diff --git a/arch/x86/include/asm/ps4.h b/arch/x86/include/asm/ps4.h index 60ee1c4f4f1841..4b95b38295d059 100644 --- a/arch/x86/include/asm/ps4.h +++ b/arch/x86/include/asm/ps4.h @@ -12,6 +12,7 @@ #ifdef CONFIG_X86_PS4 #include +#include #define PS4_DEFAULT_TSC_FREQ 1594000000 diff --git a/config b/config index 11eb9fae18d4de..8e66ec3ad0f6c1 100644 --- a/config +++ b/config @@ -1414,7 +1414,7 @@ CONFIG_SYSFB=y # CONFIG_FWCTL is not set # CONFIG_GNSS is not set # CONFIG_MTD is not set -# CONFIG_OF is not set +CONFIG_OF=y CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y # CONFIG_PARPORT is not set CONFIG_PNP=y diff --git a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c index 617a98f2c4ed41..160ef0c07d84d6 100644 --- a/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c +++ b/drivers/gpu/drm/amd/amdkfd/cik_event_interrupt.c @@ -44,7 +44,7 @@ static bool cik_event_interrupt_isr(struct kfd_node *dev, if ((ihre->source_id == CIK_INTSRC_GFX_PAGE_INV_FAULT || ihre->source_id == CIK_INTSRC_GFX_MEM_PROT_FAULT) && ((dev->adev->asic_type == CHIP_HAWAII) || - (dev->adev->asic_type == CHIP_LIVERPOOL)) { + (dev->adev->asic_type == CHIP_LIVERPOOL))) { struct cik_ih_ring_entry *tmp_ihre = (struct cik_ih_ring_entry *)patched_ihre; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 6b37d61150ee58..bcca761df585f4 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -648,4 +648,5 @@ source "drivers/misc/uacce/Kconfig" source "drivers/misc/pvpanic/Kconfig" source "drivers/misc/mchp_pci1xxxx/Kconfig" source "drivers/misc/keba/Kconfig" +source "drivers/misc/mediatek/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index d6c917229c4585..2d0841e569dbac 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -74,3 +74,4 @@ lan966x-pci-objs := lan966x_pci.o lan966x-pci-objs += lan966x_pci.dtbo.o obj-$(CONFIG_MCHP_LAN966X_PCI) += lan966x-pci.o obj-y += keba/ +obj-y += mediatek/ \ No newline at end of file diff --git a/drivers/misc/mediatek/Kconfig b/drivers/misc/mediatek/Kconfig new file mode 100644 index 00000000000000..3e5f8303e2959b --- /dev/null +++ b/drivers/misc/mediatek/Kconfig @@ -0,0 +1,6 @@ +menu "Mediatek Connectivity" + +source "drivers/misc/mediatek/connectivity/Kconfig" +source "drivers/misc/mediatek/btif/Kconfig" +endmenu # only USB + diff --git a/drivers/misc/mediatek/Makefile b/drivers/misc/mediatek/Makefile new file mode 100644 index 00000000000000..d1d9a57ec621f2 --- /dev/null +++ b/drivers/misc/mediatek/Makefile @@ -0,0 +1,22 @@ +# +# Copyright (C) 2015 MediaTek Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +#$(call all-subdir-src-or-makefile) +subdir-ccflags-y += -Werror +subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include +subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include +subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(CONFIG_MTK_PLATFORM)/include +subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/ + +obj-$(CONFIG_MTK_COMBO) += connectivity/ +obj-$(CONFIG_MTK_BTIF) += btif/ \ No newline at end of file diff --git a/drivers/misc/mediatek/btif/Kconfig b/drivers/misc/mediatek/btif/Kconfig new file mode 100644 index 00000000000000..24f293af43d7bb --- /dev/null +++ b/drivers/misc/mediatek/btif/Kconfig @@ -0,0 +1,4 @@ +config MTK_BTIF + tristate "MediaTek BTIF Driver" + help + MTK connectivity BTIF driver for A/D die diff --git a/drivers/misc/mediatek/btif/Makefile b/drivers/misc/mediatek/btif/Makefile new file mode 100644 index 00000000000000..b4d50f55e08187 --- /dev/null +++ b/drivers/misc/mediatek/btif/Makefile @@ -0,0 +1,33 @@ +# +# Copyright (C) 2015 MediaTek Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +# BTIF driver for AD DIE +# If KERNELRELEASE is defined, we've been invoked from the +# kernel build system and can use its language. +ifneq ($(KERNELRELEASE),) + #subdir-ccflags-y can be used in 2.6.34 in the future + MTK_PLATFORM := $(subst ",,$(CONFIG_MTK_PLATFORM)) + subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include + subdir-ccflags-y += -I$(srctree)/arch/arm/mach-$(MTK_PLATFORM)/include/mach + subdir-ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat + + obj-$(CONFIG_MTK_BTIF) += common/ + +# Otherwise we were called directly from the command +# line; invoke the kernel build system. +else + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) PLATFORM_FLAGS="$(subdir-ccflags-y)" modules +endif diff --git a/drivers/misc/mediatek/btif/common/Makefile b/drivers/misc/mediatek/btif/common/Makefile new file mode 100644 index 00000000000000..a726affed96278 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/Makefile @@ -0,0 +1,31 @@ +# +# Copyright (C) 2015 MediaTek Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +# BTIF driver for AD DIE +# If KERNELRELEASE is defined, we've been invoked from the +# kernel build system and can use its language. +ifneq ($(KERNELRELEASE),) + ccflags-y += -I$(src)/inc + ccflags-y += -I$(src)/plat_inc + + obj-$(CONFIG_MTK_BTIF) += btif.o + btif-objs := mtk_btif.o mtk_btif_exp.o btif_dma_plat.o btif_plat.o + +# Otherwise we were called directly from the command +# line; invoke the kernel build system. +else + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +endif diff --git a/drivers/misc/mediatek/btif/common/btif_dma_plat.c b/drivers/misc/mediatek/btif/common/btif_dma_plat.c new file mode 100644 index 00000000000000..406b7e53d47d33 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/btif_dma_plat.c @@ -0,0 +1,1436 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "MTK-BTIF-DMA" + +#include "btif_dma_priv.h" + +#define DMA_USER_ID "btif_driver" + +/************************************Global variable***********************************/ + +static MTK_BTIF_DMA_VFIFO mtk_tx_dma_vfifo = { + .vfifo = { + .p_vir_addr = NULL, + .phy_addr = 0, + .vfifo_size = TX_DMA_VFF_SIZE, + .thre = DMA_TX_THRE(TX_DMA_VFF_SIZE), + }, + .wpt = 0, + .last_wpt_wrap = 0, + .rpt = 0, + .last_rpt_wrap = 0, +}; + +static MTK_BTIF_IRQ_STR mtk_btif_tx_dma_irq = { + .name = "mtk btif tx dma irq", + .is_irq_sup = true, + .reg_flag = false, +#ifdef CONFIG_OF + .irq_flags = IRQF_TRIGGER_NONE, +#else + .irq_id = MT_DMA_BTIF_TX_IRQ_ID, + .sens_type = IRQ_SENS_LVL, + .lvl_type = IRQ_LVL_LOW, +#endif + .p_irq_handler = NULL, +}; + +static MTK_BTIF_DMA_VFIFO mtk_rx_dma_vfifo = { + .vfifo = { + .p_vir_addr = NULL, + .phy_addr = 0, + .vfifo_size = RX_DMA_VFF_SIZE, + .thre = DMA_RX_THRE(RX_DMA_VFF_SIZE), + }, + + .wpt = 0, + .last_wpt_wrap = 0, + .rpt = 0, + .last_rpt_wrap = 0, +}; + +static MTK_BTIF_IRQ_STR mtk_btif_rx_dma_irq = { + .name = "mtk btif rx dma irq", + .is_irq_sup = true, + .reg_flag = false, +#ifdef CONFIG_OF + .irq_flags = IRQF_TRIGGER_NONE, +#else + .irq_id = MT_DMA_BTIF_RX_IRQ_ID, + .sens_type = IRQ_SENS_LVL, + .lvl_type = IRQ_LVL_LOW, +#endif + .p_irq_handler = NULL, +}; + +static MTK_DMA_INFO_STR mtk_btif_tx_dma = { +#ifndef CONFIG_OF + .base = AP_DMA_BASE + BTIF_TX_DMA_OFFSET, +#endif + .dir = DMA_DIR_TX, + .p_irq = &mtk_btif_tx_dma_irq, + .p_vfifo = &(mtk_tx_dma_vfifo.vfifo), +}; + +static MTK_DMA_INFO_STR mtk_btif_rx_dma = { +#ifndef CONFIG_OF + .base = AP_DMA_BASE + BTIF_RX_DMA_OFFSET, +#endif + .dir = DMA_DIR_RX, + .p_irq = &mtk_btif_rx_dma_irq, + .p_vfifo = &(mtk_rx_dma_vfifo.vfifo), +}; + +static spinlock_t g_clk_cg_spinlock; /*dma clock's spinlock */ + +/************************************Function declearation***********************************/ +static int _is_tx_dma_in_flush(P_MTK_DMA_INFO_STR p_dma_info); +static int _tx_dma_flush(P_MTK_DMA_INFO_STR p_dma_info); +static int btif_rx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, + ENUM_DMA_CTRL ctrl_id); +static int btif_tx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, + ENUM_DMA_CTRL ctrl_id); +static int btif_rx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en); +static int btif_tx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en); +static int hal_rx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, + ENUM_BTIF_REG_ID flag); +static int hal_tx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, + ENUM_BTIF_REG_ID flag); +static int is_tx_dma_irq_finish_done(P_MTK_DMA_INFO_STR p_dma_info); +static int _btif_dma_dump_dbg_reg(void); +static void hal_btif_tx_dma_vff_set_for_4g(void); +static void hal_btif_rx_dma_vff_set_for_4g(void); + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_ier_ctrl +* DESCRIPTION +* BTIF Tx DMA's interrupt enable/disable +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* enable [IN] control if tx interrupt enabled or not +* dma_dir [IN] DMA's direction +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +static int hal_btif_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en); + +/***************************************************************************** +* FUNCTION +* hal_dma_receive_data +* DESCRIPTION +* receive data from btif module in DMA polling mode +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* positive means data is available, 0 means no data available +*****************************************************************************/ +#ifndef MTK_BTIF_MARK_UNUSED_API +static int hal_dma_receive_data(P_MTK_DMA_INFO_STR p_dma_info, + unsigned char *p_buf, + const unsigned int max_len); + +/************************************Function***********************************/ +#endif + +#ifdef CONFIG_OF +static void hal_dma_set_default_setting(ENUM_DMA_DIR dma_dir) +{ + struct device_node *node = NULL; + unsigned int irq_info[3] = {0, 0, 0}; + unsigned int phy_base; + + if (dma_dir == DMA_DIR_RX) { + node = of_find_compatible_node(NULL, NULL, "mediatek,btif_rx"); + if (node) { + mtk_btif_rx_dma.p_irq->irq_id = irq_of_parse_and_map(node, 0); + /*fixme, be compitable arch 64bits*/ + mtk_btif_rx_dma.base = (unsigned long)of_iomap(node, 0); + BTIF_INFO_FUNC("get rx_dma irq(%d),register base(0x%lx)\n", + mtk_btif_rx_dma.p_irq->irq_id, mtk_btif_rx_dma.base); + } else { + BTIF_ERR_FUNC("get rx_dma device node fail\n"); + } + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + BTIF_ERR_FUNC("get interrupt flag from DTS fail\n"); + } else { + mtk_btif_rx_dma.p_irq->irq_flags = irq_info[2]; + BTIF_INFO_FUNC("get interrupt flag(0x%x)\n", + mtk_btif_rx_dma.p_irq->irq_flags); + } + if (of_property_read_u32_index(node, "reg", 1, &phy_base)) { + BTIF_ERR_FUNC("get register phy base from DTS fail,dma_dir(%d)\n", + dma_dir); + } else { + BTIF_INFO_FUNC("get register phy base dma_dir(%d)(0x%x)\n", + dma_dir, (unsigned int)phy_base); + } + } else if (dma_dir == DMA_DIR_TX) { + node = of_find_compatible_node(NULL, NULL, "mediatek,btif_tx"); + if (node) { + mtk_btif_tx_dma.p_irq->irq_id = irq_of_parse_and_map(node, 0); + /*fixme, be compitable arch 64bits*/ + mtk_btif_tx_dma.base = (unsigned long)of_iomap(node, 0); + BTIF_INFO_FUNC("get tx_dma irq(%d),register base(0x%lx)\n", + mtk_btif_tx_dma.p_irq->irq_id, mtk_btif_tx_dma.base); + } else { + BTIF_ERR_FUNC("get tx_dma device node fail\n"); + } + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + BTIF_ERR_FUNC("get interrupt flag from DTS fail\n"); + } else { + mtk_btif_tx_dma.p_irq->irq_flags = irq_info[2]; + BTIF_INFO_FUNC("get interrupt flag(0x%x)\n", + mtk_btif_tx_dma.p_irq->irq_flags); + } + + if (of_property_read_u32_index(node, "reg", 1, &phy_base)) { + BTIF_ERR_FUNC("get register phy base from DTS fail,dma_dir(%d)\n", + dma_dir); + } else { + BTIF_INFO_FUNC("get register phy base dma_dir(%d)(0x%x)\n", + dma_dir, (unsigned int)phy_base); + } + } + +} +#endif + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_info_get +* DESCRIPTION +* get btif tx dma channel's information +* PARAMETERS +* dma_dir [IN] DMA's direction +* RETURNS +* pointer to btif dma's information structure +*****************************************************************************/ +P_MTK_DMA_INFO_STR hal_btif_dma_info_get(ENUM_DMA_DIR dma_dir) +{ + P_MTK_DMA_INFO_STR p_dma_info = NULL; + + BTIF_TRC_FUNC(); +#ifdef CONFIG_OF + hal_dma_set_default_setting(dma_dir); +#endif + if (dma_dir == DMA_DIR_RX) + /*Rx DMA*/ + p_dma_info = &mtk_btif_rx_dma; + else if (dma_dir == DMA_DIR_TX) + /*Tx DMA*/ + p_dma_info = &mtk_btif_tx_dma; + else + /*print error log*/ + BTIF_ERR_FUNC("invalid DMA dir (%d)\n", dma_dir); + spin_lock_init(&g_clk_cg_spinlock); + BTIF_TRC_FUNC(); + return p_dma_info; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_clk_ctrl +* DESCRIPTION +* control clock output enable/disable of DMA module +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_dma_clk_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_CLOCK_CTRL flag) +{ +/*In MTK DMA BTIF channel, there's only one global CG on AP_DMA, no sub channel's CG bit*/ +/*according to Artis's comment, clock of DMA and BTIF is default off, so we assume it to be off by default*/ + int i_ret = 0; + unsigned long irq_flag = 0; + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + static atomic_t s_clk_ref = ATOMIC_INIT(0); +#else + static ENUM_CLOCK_CTRL status = CLK_OUT_DISABLE; +#endif + + spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); + +#if MTK_BTIF_ENABLE_CLK_CTL + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + + if (flag == CLK_OUT_ENABLE) { + if (atomic_inc_return(&s_clk_ref) == 1) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = enable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); +#else + BTIF_DBG_FUNC("[CCF]enable clk_btif_apdma\n"); + i_ret = clk_enable(clk_btif_apdma); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + if (i_ret) { + BTIF_WARN_FUNC + ("enable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", + i_ret); + } + } + } else if (flag == CLK_OUT_DISABLE) { + if (atomic_dec_return(&s_clk_ref) == 0) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = disable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); + if (i_ret) { + BTIF_WARN_FUNC + ("disable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", + i_ret); + } +#else + BTIF_DBG_FUNC("[CCF] clk_disable(clk_btif_apdma) calling\n"); + clk_disable(clk_btif_apdma); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + } + } else { + i_ret = ERR_INVALID_PAR; + BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); + } + +#else + + if (status == flag) { + i_ret = 0; + BTIF_DBG_FUNC("dma clock already %s\n", + CLK_OUT_ENABLE == + status ? "enabled" : "disabled"); + } else { + if (flag == CLK_OUT_ENABLE) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = enable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); +#else + BTIF_DBG_FUNC("[CCF]enable clk_btif_apdma\n"); + i_ret = clk_enable(clk_btif_apdma); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + status = (i_ret == 0) ? flag : status; + if (i_ret) { + BTIF_WARN_FUNC + ("enable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", + i_ret); + } + } else if (flag == CLK_OUT_DISABLE) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = disable_clock(MTK_BTIF_APDMA_CLK_CG, DMA_USER_ID); + status = (i_ret == 0) ? flag : status; + if (i_ret) { + BTIF_WARN_FUNC + ("disable_clock for MTK_BTIF_APDMA_CLK_CG failed, ret:%d", + i_ret); + } +#else + BTIF_DBG_FUNC("[CCF] clk_disable_unprepare(clk_btif_apdma) calling\n"); + clk_disable(clk_btif_apdma); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + } else { + i_ret = ERR_INVALID_PAR; + BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); + } + } +#endif + +#else + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + +#else + + status = flag; +#endif + + i_ret = 0; +#endif + + spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + if (i_ret == 0) { + BTIF_DBG_FUNC("dma clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); + } else { + BTIF_ERR_FUNC("%s dma clock failed, ret(%d)\n", + flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); + } +#else + + if (i_ret == 0) { + BTIF_DBG_FUNC("dma clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); + } else { + BTIF_ERR_FUNC("%s dma clock failed, ret(%d)\n", + flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); + } +#endif +#if defined(CONFIG_MTK_CLKMGR) + BTIF_DBG_FUNC("DMA's clock is %s\n", (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) ? "off" : "on"); +#endif + return i_ret; +} + +int hal_btif_dma_hw_init(P_MTK_DMA_INFO_STR p_dma_info) +{ + int i_ret = 0; + unsigned int dat = 0; + unsigned long base = p_dma_info->base; + unsigned long addr_h = 0; + P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; + P_MTK_BTIF_DMA_VFIFO p_mtk_dma_vfifo = container_of(p_vfifo, + MTK_BTIF_DMA_VFIFO, + vfifo); + + if (p_dma_info->dir == DMA_DIR_RX) { + /*Rx DMA*/ + /*do hardware reset*/ + /* BTIF_SET_BIT(RX_DMA_RST(base), DMA_HARD_RST);*/ + /* BTIF_CLR_BIT(RX_DMA_RST(base), DMA_HARD_RST);*/ + BTIF_SET_BIT(RX_DMA_RST(base), DMA_WARM_RST); + do { + dat = BTIF_READ32(RX_DMA_EN(base)); + } while (0x01 & dat); + /*write vfifo base address to VFF_ADDR*/ + btif_reg_sync_writel(p_vfifo->phy_addr, RX_DMA_VFF_ADDR(base)); + if (enable_4G()) + hal_btif_rx_dma_vff_set_for_4g(); + else { + addr_h = p_vfifo->phy_addr >> 16; + addr_h = addr_h >> 16; + btif_reg_sync_writel(addr_h, RX_DMA_VFF_ADDR_H(base)); + } + /*write vfifo length to VFF_LEN*/ + btif_reg_sync_writel(p_vfifo->vfifo_size, RX_DMA_VFF_LEN(base)); + /*write wpt to VFF_WPT*/ + btif_reg_sync_writel(p_mtk_dma_vfifo->wpt, + RX_DMA_VFF_WPT(base)); + btif_reg_sync_writel(p_mtk_dma_vfifo->rpt, + RX_DMA_VFF_RPT(base)); + /*write vff_thre to VFF_THRESHOLD*/ + btif_reg_sync_writel(p_vfifo->thre, RX_DMA_VFF_THRE(base)); + /*clear Rx DMA's interrupt status*/ + BTIF_SET_BIT(RX_DMA_INT_FLAG(base), + RX_DMA_INT_DONE | RX_DMA_INT_THRE); + + /*enable Rx IER by default*/ + btif_rx_dma_ier_ctrl(p_dma_info, true); + } else { +/*Tx DMA*/ +/*do hardware reset*/ +/* BTIF_SET_BIT(TX_DMA_RST(base), DMA_HARD_RST);*/ +/* BTIF_CLR_BIT(TX_DMA_RST(base), DMA_HARD_RST);*/ + BTIF_SET_BIT(TX_DMA_RST(base), DMA_WARM_RST); + do { + dat = BTIF_READ32(TX_DMA_EN(base)); + } while (0x01 & dat); +/*write vfifo base address to VFF_ADDR*/ + btif_reg_sync_writel(p_vfifo->phy_addr, TX_DMA_VFF_ADDR(base)); + if (enable_4G()) + hal_btif_tx_dma_vff_set_for_4g(); + else { + addr_h = p_vfifo->phy_addr >> 16; + addr_h = addr_h >> 16; + btif_reg_sync_writel(addr_h, TX_DMA_VFF_ADDR_H(base)); + } +/*write vfifo length to VFF_LEN*/ + btif_reg_sync_writel(p_vfifo->vfifo_size, TX_DMA_VFF_LEN(base)); +/*write wpt to VFF_WPT*/ + btif_reg_sync_writel(p_mtk_dma_vfifo->wpt, + TX_DMA_VFF_WPT(base)); + btif_reg_sync_writel(p_mtk_dma_vfifo->rpt, + TX_DMA_VFF_RPT(base)); +/*write vff_thre to VFF_THRESHOLD*/ + btif_reg_sync_writel(p_vfifo->thre, TX_DMA_VFF_THRE(base)); + + BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), TX_DMA_INT_FLAG_MASK); + + hal_btif_dma_ier_ctrl(p_dma_info, false); + } + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_ctrl +* DESCRIPTION +* enable/disable Tx DMA channel +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* ctrl_id [IN] enable/disable ID +* RETURNS +* 0 means success; negative means fail +*****************************************************************************/ +int hal_btif_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) +{ + unsigned int i_ret = -1; + ENUM_DMA_DIR dir = p_dma_info->dir; + + if (dir == DMA_DIR_RX) + i_ret = btif_rx_dma_ctrl(p_dma_info, ctrl_id); + else if (dir == DMA_DIR_TX) + i_ret = btif_tx_dma_ctrl(p_dma_info, ctrl_id); + else { + /*TODO: print error log*/ + BTIF_ERR_FUNC("invalid dma ctrl id (%d)\n", ctrl_id); + i_ret = ERR_INVALID_PAR; + } + return i_ret; +} + +int hal_btif_dma_rx_cb_reg(P_MTK_DMA_INFO_STR p_dma_info, + dma_rx_buf_write rx_cb) +{ + if (p_dma_info->rx_cb != NULL) { + BTIF_DBG_FUNC + ("rx_cb already registered, replace (0x%p) with (0x%p)\n", + p_dma_info->rx_cb, rx_cb); + } + p_dma_info->rx_cb = rx_cb; + return 0; +} + +int btif_tx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) +{ + unsigned int i_ret = -1; + unsigned long base = p_dma_info->base; + unsigned int dat; + + BTIF_TRC_FUNC(); + if (ctrl_id == DMA_CTRL_DISABLE) { + /*if write 0 to EN bit, DMA will be stopped imediately*/ + /*if write 1 to STOP bit, DMA will be stopped after current transaction finished*/ + /*BTIF_CLR_BIT(TX_DMA_EN(base), DMA_EN_BIT);*/ + BTIF_SET_BIT(TX_DMA_STOP(base), DMA_STOP_BIT); + do { + dat = BTIF_READ32(TX_DMA_STOP(base)); + } while (0x1 & dat); + BTIF_DBG_FUNC("BTIF Tx DMA disabled,EN(0x%x),STOP(0x%x)\n", + BTIF_READ32(TX_DMA_EN(base)), BTIF_READ32(TX_DMA_STOP(base))); + i_ret = 0; + } else if (ctrl_id == DMA_CTRL_ENABLE) { + BTIF_SET_BIT(TX_DMA_EN(base), DMA_EN_BIT); + BTIF_DBG_FUNC("BTIF Tx DMA enabled\n"); + i_ret = 0; + } else { +/*TODO: print error log*/ + BTIF_ERR_FUNC("invalid DMA ctrl_id (%d)\n", ctrl_id); + i_ret = ERR_INVALID_PAR; + } + BTIF_TRC_FUNC(); + return i_ret; +} + +int btif_rx_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id) +{ + unsigned int i_ret = -1; + unsigned long base = p_dma_info->base; + unsigned int dat; + + BTIF_TRC_FUNC(); + + if (ctrl_id == DMA_CTRL_DISABLE) { + /*if write 0 to EN bit, DMA will be stopped imediately*/ + /*if write 1 to STOP bit, DMA will be stopped after current transaction finished*/ + /*BTIF_CLR_BIT(RX_DMA_EN(base), DMA_EN_BIT);*/ + BTIF_SET_BIT(RX_DMA_STOP(base), DMA_STOP_BIT); + do { + dat = BTIF_READ32(RX_DMA_STOP(base)); + } while (0x1 & dat); + BTIF_DBG_FUNC("BTIF Rx DMA disabled,EN(0x%x),STOP(0x%x)\n", + BTIF_READ32(RX_DMA_EN(base)), BTIF_READ32(RX_DMA_STOP(base))); + i_ret = 0; + } else if (ctrl_id == DMA_CTRL_ENABLE) { + BTIF_SET_BIT(RX_DMA_EN(base), DMA_EN_BIT); + BTIF_DBG_FUNC("BTIF Rx DMA enabled\n"); + i_ret = 0; + } else { +/*TODO: print error log*/ + BTIF_ERR_FUNC("invalid DMA ctrl_id (%d)\n", ctrl_id); + i_ret = ERR_INVALID_PAR; + } + BTIF_TRC_FUNC(); + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_tx_vfifo_reset +* DESCRIPTION +* reset tx virtual fifo information, except memory information +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_vfifo_reset(P_MTK_DMA_INFO_STR p_dma_info) +{ + unsigned int i_ret = -1; + P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; + P_MTK_BTIF_DMA_VFIFO p_mtk_dma_vfifo = container_of(p_vfifo, + MTK_BTIF_DMA_VFIFO, + vfifo); + + BTIF_TRC_FUNC(); + p_mtk_dma_vfifo->rpt = 0; + p_mtk_dma_vfifo->last_rpt_wrap = 0; + p_mtk_dma_vfifo->wpt = 0; + p_mtk_dma_vfifo->last_wpt_wrap = 0; + BTIF_TRC_FUNC(); + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_ier_ctrl +* DESCRIPTION +* BTIF Tx DMA's interrupt enable/disable +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* enable [IN] control if tx interrupt enabled or not +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) +{ + unsigned int i_ret = -1; + ENUM_DMA_DIR dir = p_dma_info->dir; + + if (dir == DMA_DIR_RX) { + i_ret = btif_rx_dma_ier_ctrl(p_dma_info, en); + } else if (dir == DMA_DIR_TX) { + i_ret = btif_tx_dma_ier_ctrl(p_dma_info, en); + } else { +/*TODO: print error log*/ + BTIF_ERR_FUNC("invalid DMA dma dir (%d)\n", dir); + i_ret = ERR_INVALID_PAR; + } + + return i_ret; +} + +int btif_rx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) +{ + unsigned int i_ret = -1; + unsigned long base = p_dma_info->base; + + BTIF_TRC_FUNC(); + if (!en) { + BTIF_CLR_BIT(RX_DMA_INT_EN(base), + (RX_DMA_INT_THRE_EN | RX_DMA_INT_DONE_EN)); + } else { + BTIF_SET_BIT(RX_DMA_INT_EN(base), + (RX_DMA_INT_THRE_EN | RX_DMA_INT_DONE_EN)); + } + i_ret = 0; + BTIF_TRC_FUNC(); + + return i_ret; +} + +int btif_tx_dma_ier_ctrl(P_MTK_DMA_INFO_STR p_dma_info, bool en) +{ + unsigned int i_ret = -1; + unsigned long base = p_dma_info->base; + + BTIF_TRC_FUNC(); + if (!en) + BTIF_CLR_BIT(TX_DMA_INT_EN(base), TX_DMA_INTEN_BIT); + else + BTIF_SET_BIT(TX_DMA_INT_EN(base), TX_DMA_INTEN_BIT); + i_ret = 0; + BTIF_TRC_FUNC(); + + return i_ret; +} + +static int is_tx_dma_irq_finish_done(P_MTK_DMA_INFO_STR p_dma_info) +{ + int tx_irq_done = 0; +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER +/*if we enable this clock reference couner, just return , because when enter IRQ handler, DMA's clock will be opened*/ + tx_irq_done = 1; +#else + unsigned long flag = 0; + unsigned long base = p_dma_info->base; + + spin_lock_irqsave(&(g_clk_cg_spinlock), flag); + tx_irq_done = ((BTIF_READ32(TX_DMA_INT_FLAG(base)) & TX_DMA_INT_FLAG_MASK) == 0) ? 1 : 0; + spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); +#endif + return tx_irq_done; +} + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_irq_handler +* DESCRIPTION +* lower level tx interrupt handler +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_tx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info) +{ +#define MAX_CONTINIOUS_TIMES 512 + unsigned int i_ret = -1; + unsigned int valid_size = 0; + unsigned int vff_len = 0; + unsigned int left_len = 0; + unsigned long base = p_dma_info->base; + static int flush_irq_counter; + static struct timespec64 start_timer; + static struct timespec64 end_timer; + unsigned long flag = 0; + + spin_lock_irqsave(&(g_clk_cg_spinlock), flag); + +#if defined(CONFIG_MTK_CLKMGR) + if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { + spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); + BTIF_ERR_FUNC + ("%s: clock is off before irq status clear done!!!\n", + __FILE__); + return i_ret; + } +#endif +/*check if Tx VFF Left Size equal to VFIFO size or not*/ + vff_len = BTIF_READ32(TX_DMA_VFF_LEN(base)); + valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); + left_len = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); + if (flush_irq_counter == 0) + ktime_get_ts64(&start_timer); + if ((valid_size > 0) && (valid_size < 8)) { + i_ret = _tx_dma_flush(p_dma_info); + flush_irq_counter++; + if (flush_irq_counter >= MAX_CONTINIOUS_TIMES) { + ktime_get_ts64(&end_timer); +/* + * when btif tx fifo cannot accept any data and counts of bytes left in tx vfifo < 8 for a while + * we assume that btif cannot send data for a long time + * in order not to generate interrupt continiously, which may effect system's performance. + * we clear tx flag and disable btif tx interrupt + */ +/*clear interrupt flag*/ + BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), + TX_DMA_INT_FLAG_MASK); +/*vFIFO data has been read by DMA controller, just disable tx dma's irq*/ + i_ret = hal_btif_dma_ier_ctrl(p_dma_info, false); + BTIF_ERR_FUNC + ("**********************ERROR, ERROR, ERROR**************************\n"); + BTIF_ERR_FUNC + ("BTIF Tx IRQ happened %d times (continiously), between %d.%d and %d.%d\n", + MAX_CONTINIOUS_TIMES, start_timer.tv_sec, + start_timer.tv_nsec / NSEC_PER_USEC, end_timer.tv_sec, + end_timer.tv_nsec / NSEC_PER_USEC); + } + } else if (vff_len == left_len) { + flush_irq_counter = 0; +/*clear interrupt flag*/ + BTIF_CLR_BIT(TX_DMA_INT_FLAG(base), TX_DMA_INT_FLAG_MASK); +/*vFIFO data has been read by DMA controller, just disable tx dma's irq*/ + i_ret = hal_btif_dma_ier_ctrl(p_dma_info, false); + } else { +#if 0 + BTIF_ERR_FUNC + ("**********************WARNING**************************\n"); + BTIF_ERR_FUNC("invalid irq condition, dump register\n"); + hal_dma_dump_reg(p_dma_info, REG_TX_DMA_ALL); +#endif + BTIF_DBG_FUNC + ("superious IRQ occurs, vff_len(%d), valid_size(%d), left_len(%d)\n", + vff_len, valid_size, left_len); + } + + spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_dma_send_data +* DESCRIPTION +* send data through btif in DMA mode +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* p_buf [IN] pointer to rx data buffer +* max_len [IN] tx buffer length +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_dma_send_data(P_MTK_DMA_INFO_STR p_dma_info, + const unsigned char *p_buf, const unsigned int buf_len) +{ + unsigned int i_ret = -1; + unsigned long base = p_dma_info->base; + P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; + unsigned int len_to_send = buf_len; + unsigned int ava_len = 0; + unsigned int wpt = 0; + unsigned int last_wpt_wrap = 0; + unsigned int vff_size = 0; + unsigned char *p_data = (unsigned char *)p_buf; + P_MTK_BTIF_DMA_VFIFO p_mtk_vfifo = container_of(p_vfifo, + MTK_BTIF_DMA_VFIFO, + vfifo); + + BTIF_TRC_FUNC(); + if ((p_buf == NULL) || (buf_len == 0)) { + i_ret = ERR_INVALID_PAR; + BTIF_ERR_FUNC("invalid parameters, p_buf:0x%p, buf_len:%d\n", + p_buf, buf_len); + return i_ret; + } +/*check if tx dma in flush operation? if yes, should wait until DMA finish flush operation*/ +/*currently uplayer logic will make sure this pre-condition*/ +/*disable Tx IER, in case Tx irq happens, flush bit may be set in irq handler*/ + btif_tx_dma_ier_ctrl(p_dma_info, false); + + vff_size = p_mtk_vfifo->vfifo.vfifo_size; + ava_len = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); + wpt = BTIF_READ32(TX_DMA_VFF_WPT(base)) & DMA_WPT_MASK; + last_wpt_wrap = BTIF_READ32(TX_DMA_VFF_WPT(base)) & DMA_WPT_WRAP; + +/* + * copy data to vFIFO, Note: ava_len should always large than buf_len, + * otherwise common logic layer will not call hal_dma_send_data + */ + if (buf_len > ava_len) { + BTIF_ERR_FUNC + ("length to send:(%d) < length available(%d), abnormal!!!---!!!\n", + buf_len, ava_len); + WARN_ON(buf_len > ava_len); /* this will cause kernel panic */ + } + + len_to_send = buf_len < ava_len ? buf_len : ava_len; + if (len_to_send + wpt >= vff_size) { + unsigned int tail_len = vff_size - wpt; + + memcpy((p_mtk_vfifo->vfifo.p_vir_addr + wpt), p_data, tail_len); + p_data += tail_len; + memcpy(p_mtk_vfifo->vfifo.p_vir_addr, + p_data, len_to_send - tail_len); +/*make sure all data write to memory area tx vfifo locates*/ + mb(); + +/*calculate WPT*/ + wpt = wpt + len_to_send - vff_size; + last_wpt_wrap ^= DMA_WPT_WRAP; + } else { + memcpy((p_mtk_vfifo->vfifo.p_vir_addr + wpt), + p_data, len_to_send); +/*make sure all data write to memory area tx vfifo locates*/ + mb(); + +/*calculate WPT*/ + wpt += len_to_send; + } + p_mtk_vfifo->wpt = wpt; + p_mtk_vfifo->last_wpt_wrap = last_wpt_wrap; + +/*make sure tx dma is allowed(tx flush bit is not set) to use before update WPT*/ + if (hal_dma_is_tx_allow(p_dma_info)) { + /*make sure tx dma enabled*/ + hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_ENABLE); + + /*update WTP to Tx DMA controller's control register*/ + btif_reg_sync_writel(wpt | last_wpt_wrap, TX_DMA_VFF_WPT(base)); + + if ((BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)) < 8) && + (BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)) > 0)) { + /* + * 0 < valid size in Tx vFIFO < 8 && TX Flush is not in process? + * if yes, set flush bit to DMA + */ + _tx_dma_flush(p_dma_info); + } + i_ret = len_to_send; + } else { +/*TODO: print error log*/ + BTIF_ERR_FUNC("Tx DMA flush operation is in process, this case should never happen,", + "please check if tx operation is allowed before call this API\n"); +/*if flush operation is in process , we will return 0*/ + i_ret = 0; + } + +/*Enable Tx IER*/ + btif_tx_dma_ier_ctrl(p_dma_info, true); + + BTIF_TRC_FUNC(); + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_dma_is_tx_complete +* DESCRIPTION +* get tx complete flag +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* true means tx complete, false means tx in process +*****************************************************************************/ +bool hal_dma_is_tx_complete(P_MTK_DMA_INFO_STR p_dma_info) +{ + bool b_ret = -1; + unsigned long base = p_dma_info->base; + unsigned int valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); + unsigned int inter_size = BTIF_READ32(TX_DMA_INT_BUF_SIZE(base)); + unsigned int tx_done = is_tx_dma_irq_finish_done(p_dma_info); + +/* + * only when virtual FIFO valid size and Tx channel internal buffer size are both becomes to be 0, + * we can identify tx operation finished + * confirmed with DE. + */ + if ((valid_size == 0) && (inter_size == 0) && (tx_done == 1)) { + b_ret = true; + BTIF_DBG_FUNC("DMA tx finished.\n"); + } else { + BTIF_DBG_FUNC + ("DMA tx is in process. vfifo valid size(%d), dma internal size (%d), tx_done(%d)\n", + valid_size, inter_size, tx_done); + b_ret = false; + } + + return b_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_dma_get_ava_room +* DESCRIPTION +* get tx available room +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* available room size +*****************************************************************************/ +int hal_dma_get_ava_room(P_MTK_DMA_INFO_STR p_dma_info) +{ + int i_ret = -1; + unsigned long base = p_dma_info->base; + +/*read vFIFO's left size*/ + i_ret = BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base)); + BTIF_DBG_FUNC("DMA tx ava room (%d).\n", i_ret); + if (i_ret == 0) + BTIF_INFO_FUNC("DMA tx vfifo is full.\n"); + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_dma_is_tx_allow +* DESCRIPTION +* is tx operation allowed by DMA +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* true if tx operation is allowed; false if tx is not allowed +*****************************************************************************/ +bool hal_dma_is_tx_allow(P_MTK_DMA_INFO_STR p_dma_info) +{ +#define MIN_TX_MB ((26 * 1000000 / 13) / 1000000) +#define AVE_TX_MB ((26 * 1000000 / 8) / 1000000) + + bool b_ret = false; + unsigned int wait_us = 8 / MIN_TX_MB; /*only ava length */ +/*see if flush operation is in process*/ + b_ret = _is_tx_dma_in_flush(p_dma_info) ? false : true; + if (!b_ret) { + usleep_range(wait_us, 2 * wait_us); + b_ret = _is_tx_dma_in_flush(p_dma_info) ? false : true; + } + if (!b_ret) + BTIF_WARN_FUNC("btif tx dma is not allowed\n"); +/*after Tx flush operation finished, HW will set DMA_EN back to 0 and stop DMA*/ + return b_ret; +} + + +/***************************************************************************** +* FUNCTION +* hal_rx_dma_irq_handler +* DESCRIPTION +* lower level rx interrupt handler +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_rx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info, + unsigned char *p_buf, const unsigned int max_len) +{ + int i_ret = -1; + unsigned int valid_len = 0; + unsigned int wpt_wrap = 0; + unsigned int rpt_wrap = 0; + unsigned int wpt = 0; + unsigned int rpt = 0; + unsigned int tail_len = 0; + unsigned int real_len = 0; + unsigned long base = p_dma_info->base; + P_DMA_VFIFO p_vfifo = p_dma_info->p_vfifo; + dma_rx_buf_write rx_cb = p_dma_info->rx_cb; + unsigned char *p_vff_buf = NULL; + unsigned char *vff_base = p_vfifo->p_vir_addr; + unsigned int vff_size = p_vfifo->vfifo_size; + P_MTK_BTIF_DMA_VFIFO p_mtk_vfifo = container_of(p_vfifo, + MTK_BTIF_DMA_VFIFO, + vfifo); + unsigned long flag = 0; + + spin_lock_irqsave(&(g_clk_cg_spinlock), flag); +#if defined(CONFIG_MTK_CLKMGR) + if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { + spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); + BTIF_ERR_FUNC("%s: clock is off before irq handle done!!!\n", + __FILE__); + return i_ret; + } +#endif +/*disable DMA Rx IER*/ + hal_btif_dma_ier_ctrl(p_dma_info, false); + +/*clear Rx DMA's interrupt status*/ + BTIF_SET_BIT(RX_DMA_INT_FLAG(base), RX_DMA_INT_DONE | RX_DMA_INT_THRE); + + valid_len = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); + rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); + wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); + if ((valid_len == 0) && (rpt == wpt)) { + BTIF_DBG_FUNC + ("rx interrupt, no data available in Rx DMA, wpt(0x%08x), rpt(0x%08x)\n", + rpt, wpt); + } + + i_ret = 0; + + while ((valid_len > 0) || (rpt != wpt)) { + rpt_wrap = rpt & DMA_RPT_WRAP; + wpt_wrap = wpt & DMA_WPT_WRAP; + rpt &= DMA_RPT_MASK; + wpt &= DMA_WPT_MASK; + +/*calcaute length of available data in vFIFO*/ + if (wpt_wrap != p_mtk_vfifo->last_wpt_wrap) + real_len = wpt + vff_size - rpt; + else + real_len = wpt - rpt; + + if (rx_cb != NULL) { + tail_len = vff_size - rpt; + p_vff_buf = vff_base + rpt; + if (tail_len >= real_len) { + (*rx_cb) (p_dma_info, p_vff_buf, real_len); + } else { + (*rx_cb) (p_dma_info, p_vff_buf, tail_len); + p_vff_buf = vff_base; + (*rx_cb) (p_dma_info, p_vff_buf, real_len - + tail_len); + } + i_ret += real_len; + } else + BTIF_ERR_FUNC("no rx_cb found, please check your init process\n"); + mb(); + rpt += real_len; + if (rpt >= vff_size) { + /*read wrap bit should be revert*/ + rpt_wrap ^= DMA_RPT_WRAP; + rpt %= vff_size; + } + rpt |= rpt_wrap; +/*record wpt, last_wpt_wrap, rpt, last_rpt_wrap*/ + p_mtk_vfifo->wpt = wpt; + p_mtk_vfifo->last_wpt_wrap = wpt_wrap; + + p_mtk_vfifo->rpt = rpt; + p_mtk_vfifo->last_rpt_wrap = rpt_wrap; + +/*update rpt information to DMA controller*/ + btif_reg_sync_writel(rpt, RX_DMA_VFF_RPT(base)); + +/*get vff valid size again and check if rx data is processed completely*/ + valid_len = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); + + rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); + wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); + } + +/*enable DMA Rx IER*/ + hal_btif_dma_ier_ctrl(p_dma_info, true); + + spin_unlock_irqrestore(&(g_clk_cg_spinlock), flag); + + return i_ret; +} + +static int hal_tx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, + ENUM_BTIF_REG_ID flag) +{ + int i_ret = -1; + unsigned long base = p_dma_info->base; + unsigned int int_flag = 0; + unsigned int enable = 0; + unsigned int stop = 0; + unsigned int flush = 0; + unsigned int wpt = 0; + unsigned int rpt = 0; + unsigned int int_buf = 0; + unsigned int valid_size = 0; + /*unsigned long irq_flag = 0;*/ + +#if defined(CONFIG_MTK_CLKMGR) + /*spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);*/ + if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { + /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ + BTIF_ERR_FUNC("%s: clock is off, this should never happen!!!\n", + __FILE__); + return i_ret; + } +#endif + int_flag = BTIF_READ32(TX_DMA_INT_FLAG(base)); + enable = BTIF_READ32(TX_DMA_EN(base)); + stop = BTIF_READ32(TX_DMA_STOP(base)); + flush = BTIF_READ32(TX_DMA_FLUSH(base)); + wpt = BTIF_READ32(TX_DMA_VFF_WPT(base)); + rpt = BTIF_READ32(TX_DMA_VFF_RPT(base)); + int_buf = BTIF_READ32(TX_DMA_INT_BUF_SIZE(base)); + valid_size = BTIF_READ32(TX_DMA_VFF_VALID_SIZE(base)); + /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ + + BTIF_INFO_FUNC("DMA's clock is on\n"); + BTIF_INFO_FUNC("Tx DMA's base address: 0x%lx\n", base); + + if (flag == REG_TX_DMA_ALL) { + BTIF_INFO_FUNC("TX_EN(:0x%x\n", enable); + BTIF_INFO_FUNC("INT_FLAG:0x%x\n", int_flag); + BTIF_INFO_FUNC("TX_STOP:0x%x\n", stop); + BTIF_INFO_FUNC("TX_FLUSH:0x%x\n", flush); + BTIF_INFO_FUNC("TX_WPT:0x%x\n", wpt); + BTIF_INFO_FUNC("TX_RPT:0x%x\n", rpt); + BTIF_INFO_FUNC("INT_BUF_SIZE:0x%x\n", int_buf); + BTIF_INFO_FUNC("VALID_SIZE:0x%x\n", valid_size); + BTIF_INFO_FUNC("INT_EN:0x%x\n", + BTIF_READ32(TX_DMA_INT_EN(base))); + BTIF_INFO_FUNC("TX_RST:0x%x\n", BTIF_READ32(TX_DMA_RST(base))); + BTIF_INFO_FUNC("VFF_ADDR:0x%x\n", + BTIF_READ32(TX_DMA_VFF_ADDR(base))); + BTIF_INFO_FUNC("VFF_LEN:0x%x\n", + BTIF_READ32(TX_DMA_VFF_LEN(base))); + BTIF_INFO_FUNC("TX_THRE:0x%x\n", + BTIF_READ32(TX_DMA_VFF_THRE(base))); + BTIF_INFO_FUNC("W_INT_BUF_SIZE:0x%x\n", + BTIF_READ32(TX_DMA_W_INT_BUF_SIZE(base))); + BTIF_INFO_FUNC("LEFT_SIZE:0x%x\n", + BTIF_READ32(TX_DMA_VFF_LEFT_SIZE(base))); + BTIF_INFO_FUNC("DBG_STATUS:0x%x\n", + BTIF_READ32(TX_DMA_DEBUG_STATUS(base))); + i_ret = 0; + } else { + BTIF_WARN_FUNC("unknown flag:%d\n", flag); + } + BTIF_INFO_FUNC("tx dma %s\n", (enable & DMA_EN_BIT) && + (!(stop && DMA_STOP_BIT)) ? "enabled" : "stopped"); + BTIF_INFO_FUNC("data in tx dma is %s sent by HW\n", + ((wpt == rpt) && + (int_buf == 0)) ? "completely" : "not completely"); + + return i_ret; +} + +static int hal_rx_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, + ENUM_BTIF_REG_ID flag) +{ + int i_ret = -1; + unsigned long base = p_dma_info->base; + unsigned int int_flag = 0; + unsigned int enable = 0; + unsigned int stop = 0; + unsigned int flush = 0; + unsigned int wpt = 0; + unsigned int rpt = 0; + unsigned int int_buf = 0; + unsigned int valid_size = 0; + /*unsigned long irq_flag = 0;*/ +#if defined(CONFIG_MTK_CLKMGR) + /*spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);*/ + if (clock_is_on(MTK_BTIF_APDMA_CLK_CG) == 0) { + /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ + BTIF_ERR_FUNC("%s: clock is off, this should never happen!!!\n", + __FILE__); + return i_ret; + } +#endif + BTIF_INFO_FUNC("dump DMA status register\n"); + _btif_dma_dump_dbg_reg(); + + int_flag = BTIF_READ32(RX_DMA_INT_FLAG(base)); + enable = BTIF_READ32(RX_DMA_EN(base)); + stop = BTIF_READ32(RX_DMA_STOP(base)); + flush = BTIF_READ32(RX_DMA_FLUSH(base)); + wpt = BTIF_READ32(RX_DMA_VFF_WPT(base)); + rpt = BTIF_READ32(RX_DMA_VFF_RPT(base)); + int_buf = BTIF_READ32(RX_DMA_INT_BUF_SIZE(base)); + valid_size = BTIF_READ32(RX_DMA_VFF_VALID_SIZE(base)); + /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ + + BTIF_INFO_FUNC("DMA's clock is on\n"); + BTIF_INFO_FUNC("Rx DMA's base address: 0x%lx\n", base); + + if (flag == REG_RX_DMA_ALL) { + BTIF_INFO_FUNC("RX_EN(:0x%x\n", enable); + BTIF_INFO_FUNC("RX_STOP:0x%x\n", stop); + BTIF_INFO_FUNC("RX_FLUSH:0x%x\n", flush); + BTIF_INFO_FUNC("INT_FLAG:0x%x\n", int_flag); + BTIF_INFO_FUNC("RX_WPT:0x%x\n", wpt); + BTIF_INFO_FUNC("RX_RPT:0x%x\n", rpt); + BTIF_INFO_FUNC("INT_BUF_SIZE:0x%x\n", int_buf); + BTIF_INFO_FUNC("VALID_SIZE:0x%x\n", valid_size); + BTIF_INFO_FUNC("INT_EN:0x%x\n", + BTIF_READ32(RX_DMA_INT_EN(base))); + BTIF_INFO_FUNC("RX_RST:0x%x\n", BTIF_READ32(RX_DMA_RST(base))); + BTIF_INFO_FUNC("VFF_ADDR:0x%x\n", + BTIF_READ32(RX_DMA_VFF_ADDR(base))); + BTIF_INFO_FUNC("VFF_LEN:0x%x\n", + BTIF_READ32(RX_DMA_VFF_LEN(base))); + BTIF_INFO_FUNC("RX_THRE:0x%x\n", + BTIF_READ32(RX_DMA_VFF_THRE(base))); + BTIF_INFO_FUNC("RX_FLOW_CTRL_THRE:0x%x\n", + BTIF_READ32(RX_DMA_FLOW_CTRL_THRE(base))); + BTIF_INFO_FUNC("LEFT_SIZE:0x%x\n", + BTIF_READ32(RX_DMA_VFF_LEFT_SIZE(base))); + BTIF_INFO_FUNC("DBG_STATUS:0x%x\n", + BTIF_READ32(RX_DMA_DEBUG_STATUS(base))); + i_ret = 0; + } else { + BTIF_WARN_FUNC("unknown flag:%d\n", flag); + } + BTIF_INFO_FUNC("rx dma %s\n", (enable & DMA_EN_BIT) && + (!(stop && DMA_STOP_BIT)) ? "enabled" : "stopped"); + BTIF_INFO_FUNC("data in rx dma is %s by driver\n", + ((wpt == rpt) && + (int_buf == 0)) ? "received" : "not received"); + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_dma_dump_reg +* DESCRIPTION +* dump BTIF module's information when needed +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* flag [IN] register id flag +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ENUM_BTIF_REG_ID flag) +{ + unsigned int i_ret = -1; + + if (p_dma_info->dir == DMA_DIR_TX) + i_ret = hal_tx_dma_dump_reg(p_dma_info, flag); + else if (p_dma_info->dir == DMA_DIR_RX) + i_ret = hal_rx_dma_dump_reg(p_dma_info, flag); + else + BTIF_WARN_FUNC("unknown dir:%d\n", p_dma_info->dir); + + return i_ret; +} + +static int _tx_dma_flush(P_MTK_DMA_INFO_STR p_dma_info) +{ + unsigned int i_ret = -1; + unsigned long base = p_dma_info->base; + unsigned int stop = BTIF_READ32(TX_DMA_STOP(base)); + +/*in MTK DMA BTIF channel we cannot set STOP and FLUSH bit at the same time*/ + if ((stop && DMA_STOP_BIT) != 0) + BTIF_ERR_FUNC("BTIF's DMA in stop state, omit flush operation\n"); + else { + BTIF_DBG_FUNC("flush tx dma\n"); + BTIF_SET_BIT(TX_DMA_FLUSH(base), DMA_FLUSH_BIT); + i_ret = 0; + } + return i_ret; +} + +static int _is_tx_dma_in_flush(P_MTK_DMA_INFO_STR p_dma_info) +{ + bool b_ret = true; + unsigned long base = p_dma_info->base; + +/*see if flush operation is in process*/ + b_ret = ((DMA_FLUSH_BIT & BTIF_READ32(TX_DMA_FLUSH(base))) != 0) ? true : false; + + return b_ret; +} + +int hal_dma_pm_ops(P_MTK_DMA_INFO_STR p_dma_info, MTK_BTIF_PM_OPID opid) +{ + int i_ret = -1; + + BTIF_INFO_FUNC("op id: %d\n", opid); + switch (opid) { + case BTIF_PM_DPIDLE_EN: + i_ret = 0; + break; + case BTIF_PM_DPIDLE_DIS: + i_ret = 0; + break; + case BTIF_PM_SUSPEND: + i_ret = 0; + break; + case BTIF_PM_RESUME: + i_ret = 0; + break; + case BTIF_PM_RESTORE_NOIRQ:{ + unsigned int flag = 0; + P_MTK_BTIF_IRQ_STR p_irq = p_dma_info->p_irq; + +#ifdef CONFIG_OF + flag = p_irq->irq_flags; +#else + switch (p_irq->sens_type) { + case IRQ_SENS_EDGE: + if (p_irq->edge_type == IRQ_EDGE_FALL) + flag = IRQF_TRIGGER_FALLING; + else if (p_irq->edge_type == IRQ_EDGE_RAISE) + flag = IRQF_TRIGGER_RISING; + else if (p_irq->edge_type == IRQ_EDGE_BOTH) + flag = IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING; + else + flag = IRQF_TRIGGER_FALLING; /*make this as default type */ + break; + case IRQ_SENS_LVL: + if (p_irq->lvl_type == IRQ_LVL_LOW) + flag = IRQF_TRIGGER_LOW; + else if (p_irq->lvl_type == IRQ_LVL_HIGH) + flag = IRQF_TRIGGER_HIGH; + else + flag = IRQF_TRIGGER_LOW; /*make this as default type */ + break; + default: + flag = IRQF_TRIGGER_LOW; /*make this as default type */ + break; + } +#endif +/* irq_set_irq_type(p_irq->irq_id, flag); */ + i_ret = 0; + } + i_ret = 0; + break; + default: + i_ret = ERR_INVALID_PAR; + break; + } + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_dma_receive_data +* DESCRIPTION +* receive data from btif module in DMA polling mode +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* positive means data is available, 0 means no data available +*****************************************************************************/ +#ifndef MTK_BTIF_MARK_UNUSED_API +int hal_dma_receive_data(P_MTK_DMA_INFO_STR p_dma_info, + unsigned char *p_buf, const unsigned int max_len) +{ + unsigned int i_ret = -1; + + return i_ret; +} +#endif + +int _btif_dma_dump_dbg_reg(void) +{ +#if 0 + static MTK_BTIF_DMA_REG_DMP_DBG g_dma_dbg_regs[] = { + {0x10201180, 0x0}, + {0x10201184, 0x0}, + {0x10201188, 0x0}, + {0x1020118C, 0x0}, + {0x10201190, 0x0}, + {0x1000320C, 0x0}, + {0x10003210, 0x0}, + {0x10003214, 0x0}, + }; + + int i = 0; + char *addr1 = NULL; + char *addr2 = NULL; + + int array_num = ARRAY_SIZE(g_dma_dbg_regs) + + addr1 = ioremap(g_dma_dbg_regs[0].reg_addr, 0x20); + if (addr1) { + for (i = 0; i < 5; i++) + g_dma_dbg_regs[i].reg_val = *(volatile unsigned int*)(addr1 + i*4); + iounmap(addr1); + } + + addr2 = ioremap(g_dma_dbg_regs[5].reg_addr, 0x10); + if (addr2) { + g_dma_dbg_regs[5].reg_val = *(volatile unsigned int*)(addr2); + g_dma_dbg_regs[6].reg_val = *(volatile unsigned int*)(addr2+4); + g_dma_dbg_regs[7].reg_val = *(volatile unsigned int*)(addr2+8); + iounmap(addr2); + } + + for (i = 0; i < array_num; i++) + BTIF_INFO_FUNC("-<0x%lx, 0x%08x>\n", g_dma_dbg_regs[i].reg_addr, g_dma_dbg_regs[i].reg_val); +#endif + return 0; +} + +static void hal_btif_tx_dma_vff_set_for_4g(void) +{ + BTIF_DBG_FUNC("Set btif tx_vff_addr bit29\n"); + BTIF_SET_BIT(TX_DMA_VFF_ADDR_H(mtk_btif_tx_dma.base), DMA_VFF_BIT29_OFFSET); + BTIF_DBG_FUNC("Dump value of bit29 0x%x:(0x%x)\n", TX_DMA_VFF_ADDR_H(mtk_btif_tx_dma.base), + BTIF_READ32(TX_DMA_VFF_ADDR_H(mtk_btif_tx_dma.base))); +} +static void hal_btif_rx_dma_vff_set_for_4g(void) +{ + BTIF_DBG_FUNC("Set btif rx_vff_addr bit29\n"); + BTIF_SET_BIT(RX_DMA_VFF_ADDR_H(mtk_btif_rx_dma.base), DMA_VFF_BIT29_OFFSET); + BTIF_DBG_FUNC("Dump value of bit29 0x%x:(0x%x)\n", RX_DMA_VFF_ADDR_H(mtk_btif_rx_dma.base), + BTIF_READ32(RX_DMA_VFF_ADDR_H(mtk_btif_rx_dma.base))); +} + diff --git a/drivers/misc/mediatek/btif/common/btif_plat.c b/drivers/misc/mediatek/btif/common/btif_plat.c new file mode 100644 index 00000000000000..11eb2ec9bf94af --- /dev/null +++ b/drivers/misc/mediatek/btif/common/btif_plat.c @@ -0,0 +1,1396 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "MTK-BTIF" + +#define NEW_TX_HANDLING_SUPPORT 1 + +#include "btif_pub.h" +#include "btif_priv.h" + +#define BTIF_USER_ID "btif_driver" + +static spinlock_t g_clk_cg_spinlock; /*BTIF clock's spinlock */ + +/*-----------------------------BTIF Module Clock and Power Control Defination------------------*/ + +MTK_BTIF_IRQ_STR mtk_btif_irq = { + .name = "mtk btif irq", + .is_irq_sup = true, + .reg_flag = false, +#ifdef CONFIG_OF + .irq_flags = IRQF_TRIGGER_NONE, +#else + .irq_id = MT_BTIF_IRQ_ID, + .sens_type = IRQ_SENS_LVL, + .lvl_type = IRQ_LVL_LOW, +#endif + .p_irq_handler = NULL, +}; + +/* + * will call clock manager's API export by WCP to control BTIF's clock, + * but we may need to access these registers in case of btif clock control logic is wrong in clock manager + */ + +MTK_BTIF_INFO_STR mtk_btif = { +#ifndef CONFIG_OF + .base = MTK_BTIF_REG_BASE, +#endif + .p_irq = &mtk_btif_irq, + .tx_fifo_size = BTIF_TX_FIFO_SIZE, + .rx_fifo_size = BTIF_RX_FIFO_SIZE, + .tx_tri_lvl = BTIF_TX_FIFO_THRE, + .rx_tri_lvl = BTIF_RX_FIFO_THRE, + .rx_data_len = 0, + .p_tx_fifo = NULL, +}; +#if !(NEW_TX_HANDLING_SUPPORT) +static bool _btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif); +#endif + +static int btif_rx_irq_handler(P_MTK_BTIF_INFO_STR p_btif_info, + unsigned char *p_buf, + const unsigned int max_len); +static int btif_tx_irq_handler(P_MTK_BTIF_INFO_STR p_btif); + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_ier_ctrl +* DESCRIPTION +* BTIF Rx interrupt enable/disable +* PARAMETERS +* p_base [IN] BTIF module's base address +* enable [IN] control if rx interrupt enabled or not +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +static int hal_btif_rx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); + +/***************************************************************************** +* FUNCTION +* hal_btif_tx_ier_ctrl +* DESCRIPTION +* BTIF Tx interrupt enable/disable +* PARAMETERS +* p_base [IN] BTIF module's base address +* enable [IN] control if tx interrupt enabled or not +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +static int hal_btif_tx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); + +#ifndef MTK_BTIF_MARK_UNUSED_API +static int btif_sleep_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); + +/***************************************************************************** +* FUNCTION +* _btif_receive_data +* DESCRIPTION +* receive data from btif module in FIFO polling mode +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* positive means data is available, 0 means no data available +*****************************************************************************/ +static int _btif_receive_data(P_MTK_BTIF_INFO_STR p_btif, + unsigned char *p_buf, const unsigned int max_len); +static int btif_tx_thr_set(P_MTK_BTIF_INFO_STR p_btif, unsigned int thr_count); +#endif + +static int btif_dump_array(char *string, char *p_buf, int len) +{ + unsigned int idx = 0; + unsigned char str[30]; + unsigned char *p_str; + + pr_debug("========dump %s start ========\n", string, len); + p_str = &str[0]; + for (idx = 0; idx < len; idx++, p_buf++) { + sprintf(p_str, "%02x ", *p_buf); + p_str += 3; + if (7 == (idx % 8)) { + *p_str++ = '\n'; + *p_str = '\0'; + pr_debug("%s", str); + p_str = &str[0]; + } + } + if (len % 8) { + *p_str++ = '\n'; + *p_str = '\0'; + pr_debug("%s", str); + } + pr_debug("========dump %s end========\n", string); + return 0; +} + +#if NEW_TX_HANDLING_SUPPORT +static int _btif_tx_fifo_init(P_MTK_BTIF_INFO_STR p_btif_info) +{ + int i_ret = -1; + + spin_lock_init(&(p_btif_info->tx_fifo_spinlock)); + + if (p_btif_info->p_tx_fifo == NULL) { + p_btif_info->p_tx_fifo = kzalloc(sizeof(struct kfifo), + GFP_ATOMIC); + if (p_btif_info->p_tx_fifo == NULL) { + i_ret = -ENOMEM; + BTIF_ERR_FUNC("kzalloc for p_btif->p_tx_fifo failed\n"); + goto ret; + } + + i_ret = kfifo_alloc(p_btif_info->p_tx_fifo, + BTIF_HAL_TX_FIFO_SIZE, GFP_ATOMIC); + if (i_ret != 0) { + BTIF_ERR_FUNC("kfifo_alloc failed, errno(%d)\n", i_ret); + i_ret = -ENOMEM; + goto ret; + } + i_ret = 0; + } else { + BTIF_WARN_FUNC + ("p_btif_info->p_tx_fifo is already init p_btif_info->p_tx_fifo(0x%p)\n", + p_btif_info->p_tx_fifo); + i_ret = 0; + } +ret: + return i_ret; +} + +static int _get_btif_tx_fifo_room(P_MTK_BTIF_INFO_STR p_btif_info) +{ + int i_ret = 0; + unsigned long flag = 0; + + spin_lock_irqsave(&(p_btif_info->tx_fifo_spinlock), flag); + if (p_btif_info->p_tx_fifo == NULL) + i_ret = 0; + else + i_ret = kfifo_avail(p_btif_info->p_tx_fifo); + spin_unlock_irqrestore(&(p_btif_info->tx_fifo_spinlock), flag); + BTIF_DBG_FUNC("tx kfifo:0x%p, available room:%d\n", p_btif_info->p_tx_fifo, i_ret); + return i_ret; +} + +static int _btif_tx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif_info) +{ + int i_ret = 0; + + if (p_btif_info->p_tx_fifo != NULL) + kfifo_reset(p_btif_info->p_tx_fifo); + return i_ret; +} + +#endif + +#ifdef CONFIG_OF +static void _btif_set_default_setting(void) +{ + struct device_node *node = NULL; + unsigned int irq_info[3] = {0, 0, 0}; + unsigned int phy_base; + + node = of_find_compatible_node(NULL, NULL, "mediatek,btif"); + if (node) { + mtk_btif.p_irq->irq_id = irq_of_parse_and_map(node, 0); + /*fixme, be compitable arch 64bits*/ + mtk_btif.base = (unsigned long)of_iomap(node, 0); + BTIF_INFO_FUNC("get btif irq(%d),register base(0x%lx)\n", + mtk_btif.p_irq->irq_id, mtk_btif.base); + } else { + BTIF_ERR_FUNC("get btif device node fail\n"); + } + + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + BTIF_ERR_FUNC("get interrupt flag from DTS fail\n"); + } else { + mtk_btif.p_irq->irq_flags = irq_info[2]; + BTIF_INFO_FUNC("get interrupt flag(0x%x)\n", mtk_btif.p_irq->irq_flags); + } + + if (of_property_read_u32_index(node, "reg", 1, &phy_base)) + BTIF_ERR_FUNC("get register phy base from DTS fail\n"); + else + BTIF_INFO_FUNC("get register phy base(0x%x)\n", (unsigned int)phy_base); +} +#endif + +/***************************************************************************** +* FUNCTION +* hal_btif_info_get +* DESCRIPTION +* get btif's information included base address , irq related information +* PARAMETERS +* RETURNS +* BTIF's information +*****************************************************************************/ +P_MTK_BTIF_INFO_STR hal_btif_info_get(void) +{ +#if NEW_TX_HANDLING_SUPPORT + int i_ret = 0; +/*tx fifo and fifo lock init*/ + i_ret = _btif_tx_fifo_init(&mtk_btif); + if (i_ret == 0) + BTIF_INFO_FUNC("_btif_tx_fifo_init succeed\n"); + else + BTIF_ERR_FUNC("_btif_tx_fifo_init failed, i_ret:%d\n", i_ret); + +#endif + +#ifdef CONFIG_OF + _btif_set_default_setting(); +#endif + + spin_lock_init(&g_clk_cg_spinlock); + + return &mtk_btif; +} +/***************************************************************************** +* FUNCTION +* hal_btif_clk_get_and_prepare +* DESCRIPTION +* get clock from device tree and prepare for enable/disable control +* PARAMETERS +* pdev device pointer +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +#if !defined(CONFIG_MTK_CLKMGR) +int hal_btif_clk_get_and_prepare(struct platform_device *pdev) +{ + int i_ret = -1; + + clk_btif = devm_clk_get(&pdev->dev, "btifc"); + if (IS_ERR(clk_btif)) { + BTIF_ERR_FUNC("[CCF]cannot get clk_btif clock.\n"); + return PTR_ERR(clk_btif); + } + BTIF_ERR_FUNC("[CCF]clk_btif=%p\n", clk_btif); + clk_btif_apdma = devm_clk_get(&pdev->dev, "apdmac"); + if (IS_ERR(clk_btif_apdma)) { + BTIF_ERR_FUNC("[CCF]cannot get clk_btif_apdma clock.\n"); + return PTR_ERR(clk_btif_apdma); + } + BTIF_ERR_FUNC("[CCF]clk_btif_apdma=%p\n", clk_btif_apdma); + + i_ret = clk_prepare(clk_btif); + if (i_ret != 0) { + BTIF_ERR_FUNC("clk_prepare clk_btif failed! ret:%d\n", i_ret); + return i_ret; + } + + i_ret = clk_prepare(clk_btif_apdma); + if (i_ret != 0) { + BTIF_ERR_FUNC("clk_prepare clk_btif_apdma failed! ret:%d\n", i_ret); + return i_ret; + } + return i_ret; +} +/***************************************************************************** +* FUNCTION +* hal_btif_clk_unprepare +* DESCRIPTION +* unprepare btif clock and apdma clock +* PARAMETERS +* none +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_clk_unprepare(void) +{ + clk_unprepare(clk_btif); + clk_unprepare(clk_btif_apdma); + return 0; +} +#endif +/***************************************************************************** +* FUNCTION +* hal_btif_clk_ctrl +* DESCRIPTION +* control clock output enable/disable of BTIF module +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_clk_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_CLOCK_CTRL flag) +{ +/*In MTK BTIF, there's only one global CG on AP_DMA, no sub channel's CG bit*/ +/*according to Artis's comment, clock of DMA and BTIF is default off, so we assume it to be off by default*/ + int i_ret = 0; + unsigned long irq_flag = 0; + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + static atomic_t s_clk_ref = ATOMIC_INIT(0); +#else + static ENUM_CLOCK_CTRL status = CLK_OUT_DISABLE; +#endif + + spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); + +#if MTK_BTIF_ENABLE_CLK_CTL + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + + if (flag == CLK_OUT_ENABLE) { + if (atomic_inc_return(&s_clk_ref) == 1) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = enable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); +#else + BTIF_DBG_FUNC("[CCF]enable clk_btif\n"); + i_ret = clk_enable(clk_btif); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + if (i_ret) { + BTIF_WARN_FUNC + ("enable_clock for MTK_BTIF_CG_BIT failed, ret:%d", + i_ret); + } + } + } else if (flag == CLK_OUT_DISABLE) { + if (atomic_dec_return(&s_clk_ref) == 0) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = disable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); + if (i_ret) { + BTIF_WARN_FUNC + ("disable_clock for MTK_BTIF_CG_BIT failed, ret:%d", + i_ret); + } +#else + BTIF_DBG_FUNC("[CCF] clk_disable(clk_btif) calling\n"); + clk_disable(clk_btif); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + } + } else { + i_ret = ERR_INVALID_PAR; + BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); + } + +#else + + if (status == flag) { + i_ret = 0; + BTIF_DBG_FUNC("btif clock already %s\n", + CLK_OUT_ENABLE == + status ? "enabled" : "disabled"); + } else { + if (flag == CLK_OUT_ENABLE) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = enable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); +#else + BTIF_DBG_FUNC("[CCF]enable clk_btif\n"); + i_ret = clk_enable(clk_btif); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + status = (i_ret == 0) ? flag : status; + if (i_ret) { + BTIF_WARN_FUNC + ("enable_clock for MTK_BTIF_CG_BIT failed, ret:%d", + i_ret); + } + } else if (flag == CLK_OUT_DISABLE) { +#if defined(CONFIG_MTK_CLKMGR) + i_ret = disable_clock(MTK_BTIF_CG_BIT, BTIF_USER_ID); + status = (i_ret == 0) ? flag : status; + if (i_ret) { + BTIF_WARN_FUNC + ("disable_clock for MTK_BTIF_CG_BIT failed, ret:%d", + i_ret); + } +#else + BTIF_DBG_FUNC("[CCF] clk_disable(clk_btif) calling\n"); + clk_disable(clk_btif); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + } else { + i_ret = ERR_INVALID_PAR; + BTIF_ERR_FUNC("invalid clock ctrl flag (%d)\n", flag); + } + } +#endif + +#else + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + +#else + + status = flag; +#endif + + i_ret = 0; +#endif + + spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + if (i_ret == 0) { + BTIF_DBG_FUNC("btif clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); + } else { + BTIF_ERR_FUNC("%s btif clock failed, ret(%d)\n", + flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); + } +#else + + if (i_ret == 0) { + BTIF_DBG_FUNC("btif clock %s\n", flag == CLK_OUT_ENABLE ? "enabled" : "disabled"); + } else { + BTIF_ERR_FUNC("%s btif clock failed, ret(%d)\n", + flag == CLK_OUT_ENABLE ? "enable" : "disable", i_ret); + } +#endif +#if defined(CONFIG_MTK_CLKMGR) + BTIF_DBG_FUNC("BTIF's clock is %s\n", (clock_is_on(MTK_BTIF_CG_BIT) == 0) ? "off" : "on"); +#endif + return i_ret; +} + +static int btif_new_handshake_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool enable) +{ + unsigned long base = p_btif->base; + + if (enable == true) + BTIF_SET_BIT(BTIF_HANDSHAKE(base), BTIF_HANDSHAKE_EN_HANDSHAKE); + else + BTIF_CLR_BIT(BTIF_HANDSHAKE(base), BTIF_HANDSHAKE_EN_HANDSHAKE); + return true; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_hw_init +* DESCRIPTION +* BTIF hardware init +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_hw_init(P_MTK_BTIF_INFO_STR p_btif) +{ +/*Chaozhong: To be implement*/ + int i_ret = -1; + unsigned long base = p_btif->base; + +#if NEW_TX_HANDLING_SUPPORT + _btif_tx_fifo_reset(p_btif); +#endif + +/*set to normal mode*/ + btif_reg_sync_writel(BTIF_FAKELCR_NORMAL_MODE, BTIF_FAKELCR(base)); +/*set to newhandshake mode*/ + btif_new_handshake_ctrl(p_btif, true); +/*No need to access: enable sleep mode*/ +/*No need to access: set Rx timeout count*/ +/*set Tx threshold*/ +/*set Rx threshold*/ +/*disable internal loopback test*/ + +/*set Rx FIFO clear bit to 1*/ + BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); +/*clear Rx FIFO clear bit to 0*/ + BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); +/*set Tx FIFO clear bit to 1*/ + BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); +/*clear Tx FIFO clear bit to 0*/ + BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); + + btif_reg_sync_writel(BTIF_TRI_LVL_TX(p_btif->tx_tri_lvl) + | BTIF_TRI_LVL_RX(p_btif->rx_tri_lvl) + | BTIF_TRI_LOOP_DIS, BTIF_TRI_LVL(base)); + hal_btif_loopback_ctrl(p_btif, false); +/*disable BTIF Tx DMA mode*/ + hal_btif_tx_mode_ctrl(p_btif, BTIF_MODE_PIO); +/*disable BTIF Rx DMA mode*/ + hal_btif_rx_mode_ctrl(p_btif, BTIF_MODE_PIO); +/*auto reset*/ + BTIF_SET_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_AUTORST_EN); +/*disable Tx IER*/ + hal_btif_tx_ier_ctrl(p_btif, false); +/*enable Rx IER by default*/ + hal_btif_rx_ier_ctrl(p_btif, true); + + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_ier_ctrl +* DESCRIPTION +* BTIF Rx interrupt enable/disable +* PARAMETERS +* p_base [IN] BTIF module's base address +* enable [IN] control if rx interrupt enabled or not +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_rx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + + if (en == false) + BTIF_CLR_BIT(BTIF_IER(base), BTIF_IER_RXFEN); + else + BTIF_SET_BIT(BTIF_IER(base), BTIF_IER_RXFEN); + +/*TODO:do we need to read back ? Answer: no*/ + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_tx_ier_ctrl +* DESCRIPTION +* BTIF Tx interrupt enable/disable +* PARAMETERS +* p_base [IN] BTIF module's base address +* enable [IN] control if tx interrupt enabled or not +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_tx_ier_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + + if (en == false) + BTIF_CLR_BIT(BTIF_IER(base), BTIF_IER_TXEEN); + else + BTIF_SET_BIT(BTIF_IER(base), BTIF_IER_TXEEN); + +/*TODO:do we need to read back ? Answer: no*/ + i_ret = 0; + + return i_ret; +} + +#ifndef MTK_BTIF_MARK_UNUSED_API + +/***************************************************************************** +* FUNCTION +* _btif_receive_data +* DESCRIPTION +* receive data from btif module in FIFO polling mode +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* positive means data is available, 0 means no data available +*****************************************************************************/ +int _btif_receive_data(P_MTK_BTIF_INFO_STR p_btif, + unsigned char *p_buf, const unsigned int max_len) +{ +/*Chaozhong: To be implement*/ + int i_ret = -1; + +/*check parameter valid or not*/ + if ((p_buf == NULL) || (max_len == 0)) { + i_ret = ERR_INVALID_PAR; + return i_ret; + } + i_ret = btif_rx_irq_handler(p_btif, p_buf, max_len); + + return i_ret; +} + +int btif_sleep_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + + if (en == false) + BTIF_CLR_BIT(BTIF_SLEEP_EN(base), BTIF_SLEEP_EN_BIT); + else + BTIF_SET_BIT(BTIF_SLEEP_EN(base), BTIF_SLEEP_EN_BIT); + +/*TODO:do we need to read back ? Answer: no*/ +/*TODO:do we need to dsb?*/ + i_ret = 0; + return i_ret; +} + +static int btif_tx_thr_set(P_MTK_BTIF_INFO_STR p_btif, unsigned int thr_count) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + unsigned int value = 0; + +/*read BTIF_TRI_LVL*/ + value = BTIF_READ32(BTIF_TRI_LVL(base)); +/*clear Tx threshold bits*/ + value &= (~BTIF_TRI_LVL_TX_MASK); +/*set tx threshold bits*/ + value |= BTIF_TRI_LVL_TX(BTIF_TX_FIFO_THRE); +/*write back to BTIF_TRI_LVL*/ + btif_reg_sync_writel(value, BTIF_TRI_LVL(base)); + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* btif_rx_fifo_reset +* DESCRIPTION +* reset BTIF's rx fifo +* PARAMETERS +* p_base [IN] BTIF module's base address +* ec [IN] control if loopback mode is enabled or not +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +static int btif_rx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif) +{ +/*Chaozhong: To be implement*/ + int i_ret = -1; + unsigned long base = p_btif->base; + +/*set Rx FIFO clear bit to 1*/ + BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); + +/*clear Rx FIFO clear bit to 0*/ + BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_RX); + +/*TODO:do we need to read back ? Answer: no*/ +/*TODO:do we need to dsb?*/ + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* btif_tx_fifo_reset +* DESCRIPTION +* reset BTIF's tx fifo +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +static int btif_tx_fifo_reset(P_MTK_BTIF_INFO_STR p_btif) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + +/*set Tx FIFO clear bit to 1*/ + BTIF_SET_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); + +/*clear Tx FIFO clear bit to 0*/ + BTIF_CLR_BIT(BTIF_FIFOCTRL(base), BTIF_FIFOCTRL_CLR_TX); + +/*TODO:do we need to read back ? Answer: no*/ +/*TODO:do we need to dsb?*/ + i_ret = 0; + return i_ret; +} + +#endif + +/***************************************************************************** +* FUNCTION +* hal_btif_loopback_ctrl +* DESCRIPTION +* BTIF Tx/Rx loopback mode set, this operation can only be done after set BTIF to normal mode +* PARAMETERS +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_loopback_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + + if (en == false) + BTIF_CLR_BIT(BTIF_TRI_LVL(base), BTIF_TRI_LOOP_EN); + else + BTIF_SET_BIT(BTIF_TRI_LVL(base), BTIF_TRI_LOOP_EN); + +/*TODO:do we need to read back ? Answer: no*/ +/*TODO:do we need to dsb?*/ + i_ret = 0; + return i_ret; +} + + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_handler +* DESCRIPTION +* lower level interrupt handler +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* 0 means success; negative means fail; positive means rx data length +*****************************************************************************/ +int hal_btif_irq_handler(P_MTK_BTIF_INFO_STR p_btif, + unsigned char *p_buf, const unsigned int max_len) +{ +/*Chaozhong: To be implement*/ + int i_ret = -1; + unsigned int iir = 0; + unsigned int rx_len = 0; + unsigned long base = p_btif->base; + +#if 0 +/*check parameter valid or not*/ + if ((p_buf == NULL) || (max_len == 0)) { + i_ret = ERR_INVALID_PAR; + return i_ret; + } +#endif + unsigned long irq_flag = 0; + + spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag); + +#if defined(CONFIG_MTK_CLKMGR) + if (clock_is_on(MTK_BTIF_CG_BIT) == 0) { + spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); + BTIF_ERR_FUNC("%s: clock is off before irq handle done!!!\n", + __FILE__); + return i_ret; + } +#endif +/*read interrupt identifier register*/ + iir = BTIF_READ32(BTIF_IIR(base)); + +/*is rx interrupt exist?*/ +#if 0 + while ((iir & BTIF_IIR_RX) && (rx_len < max_len)) { + rx_len += + btif_rx_irq_handler(p_btif, (p_buf + rx_len), + (max_len - rx_len)); + +/*update IIR*/ + iir = BTIF_READ32(BTIF_IIR(base)); + } +#endif + + while (iir & (BTIF_IIR_RX | BTIF_IIR_RX_TIMEOUT)) { + rx_len += btif_rx_irq_handler(p_btif, p_buf, max_len); + +/*update IIR*/ + iir = BTIF_READ32(BTIF_IIR(base)); + } + +/*is tx interrupt exist?*/ + if (iir & BTIF_IIR_TX_EMPTY) + i_ret = btif_tx_irq_handler(p_btif); + spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag); + + i_ret = rx_len != 0 ? rx_len : i_ret; + return i_ret; +} + +int hal_btif_rx_cb_reg(P_MTK_BTIF_INFO_STR p_btif_info, btif_rx_buf_write rx_cb) +{ + if (p_btif_info->rx_cb != NULL) + BTIF_DBG_FUNC("rx_cb already registered, replace (0x%p) with (0x%p)\n", + p_btif_info->rx_cb, rx_cb); + p_btif_info->rx_cb = rx_cb; + + return 0; +} + +/***************************************************************************** +* FUNCTION +* btif_rx_irq_handler +* DESCRIPTION +* lower level rx interrupt handler +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* positive means length of rx data , negative means fail +*****************************************************************************/ +static int btif_rx_irq_handler(P_MTK_BTIF_INFO_STR p_btif_info, + unsigned char *p_buf, const unsigned int max_len) +{ +/*Chaozhong: To be implement*/ + int i_ret = 0; + unsigned int iir = 0; + unsigned int rx_len = 0; + unsigned long base = p_btif_info->base; + unsigned char rx_buf[256]; + unsigned int local_buf_len = 256; + btif_rx_buf_write rx_cb = p_btif_info->rx_cb; + unsigned int total_len = 0; + +/*read interrupt identifier register*/ + iir = BTIF_READ32(BTIF_IIR(base)); + while ((iir & (BTIF_IIR_RX | BTIF_IIR_RX_TIMEOUT)) && + (rx_len < local_buf_len)) { + rx_buf[rx_len] = BTIF_READ8(base); + rx_len++; +/*need to consult CC Hwang for advice */ +/* + * whether we need to do memory barrier here + * Ans: no + */ +/* + * whether we need to d memory barrier when call BTIF_SET_BIT or BTIF_CLR_BIT + * Ans: no + */ + if (rx_len == local_buf_len) { + if (rx_cb) + (*rx_cb) (p_btif_info, rx_buf, rx_len); + rx_len = 0; + total_len += rx_len; + } + iir = BTIF_READ32(BTIF_IIR(base)); + } + total_len += rx_len; + if (rx_len && rx_cb) + (*rx_cb) (p_btif_info, rx_buf, rx_len); + +/* + * make sure all data write back to memory, mb or dsb? + * need to consult CC Hwang for advice + * Ans: no need here + */ + i_ret = total_len; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* btif_tx_irq_handler +* DESCRIPTION +* lower level tx interrupt handler +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +static int btif_tx_irq_handler(P_MTK_BTIF_INFO_STR p_btif) +{ + int i_ret = -1; + +#if NEW_TX_HANDLING_SUPPORT + int how_many = 0; + unsigned int lsr; + unsigned int ava_len = 0; + unsigned long base = p_btif->base; + char local_buf[BTIF_TX_FIFO_SIZE]; + char *p_data = local_buf; + unsigned long flag = 0; + + struct kfifo *p_tx_fifo = p_btif->p_tx_fifo; + +/*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ + lsr = BTIF_READ32(BTIF_LSR(base)); + + if (lsr & BTIF_LSR_TEMT_BIT) + /*Tx Holding Register if empty, which means we can write tx FIFO count to BTIF*/ + ava_len = BTIF_TX_FIFO_SIZE; + else if (lsr & BTIF_LSR_THRE_BIT) + /*Tx Holding Register if empty, which means we can write (Tx FIFO count - Tx threshold)to BTIF*/ + ava_len = BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE; + else { + /*this means data size in tx FIFO is more than Tx threshold, we will not write data to THR*/ + ava_len = 0; + goto ret; + } + spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); + how_many = kfifo_out(p_tx_fifo, local_buf, ava_len); + spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); + BTIF_DBG_FUNC("BTIF tx size %d done, left:%d\n", how_many, + kfifo_avail(p_tx_fifo)); + while (how_many--) + btif_reg_sync_writeb(*(p_data++), BTIF_THR(base)); + + spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); +/*clear Tx enable flag if necessary*/ + if (kfifo_is_empty(p_tx_fifo)) { + hal_btif_tx_ier_ctrl(p_btif, false); + BTIF_DBG_FUNC("BTIF tx FIFO is empty\n"); + } + spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); +ret: +#else +/*clear Tx enable flag*/ + hal_btif_tx_ier_ctrl(p_btif, false); +#endif + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_tx_mode_ctrl +* DESCRIPTION +* set BTIF tx to corresponding mode (PIO/DMA) +* PARAMETERS +* p_base [IN] BTIF module's base address +* mode [IN] rx mode +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_tx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + + if (mode == BTIF_MODE_DMA) + /*set to DMA mode*/ + BTIF_SET_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_TX); + else + /*set to PIO mode*/ + BTIF_CLR_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_TX); + + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_mode_ctrl +* DESCRIPTION +* set BTIF rx to corresponding mode (PIO/DMA) +* PARAMETERS +* p_base [IN] BTIF module's base address +* mode [IN] rx mode +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_rx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode) +{ + int i_ret = -1; + unsigned long base = p_btif->base; + + if (mode == BTIF_MODE_DMA) + /*set to DMA mode*/ + BTIF_SET_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_RX); + else + /*set to PIO mode*/ + BTIF_CLR_BIT(BTIF_DMA_EN(base), BTIF_DMA_EN_RX); + + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_send_data +* DESCRIPTION +* send data through btif in FIFO mode +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN] pointer to rx data buffer +* max_len [IN] tx buffer length +* RETURNS +* positive means number of data sent; 0 means no data put to FIFO; negative means error happens +*****************************************************************************/ +int hal_btif_send_data(P_MTK_BTIF_INFO_STR p_btif, + const unsigned char *p_buf, const unsigned int buf_len) +{ +/*Chaozhong: To be implement*/ + int i_ret = -1; + + unsigned int ava_len = 0; + unsigned int sent_len = 0; + +#if !(NEW_TX_HANDLING_SUPPORT) + unsigned long base = p_btif->base; + unsigned int lsr = 0; + unsigned int left_len = 0; + unsigned char *p_data = (unsigned char *)p_buf; +#endif + +/*check parameter valid or not*/ + if ((p_buf == NULL) || (buf_len == 0)) { + i_ret = ERR_INVALID_PAR; + return i_ret; + } +#if NEW_TX_HANDLING_SUPPORT + ava_len = _get_btif_tx_fifo_room(p_btif); + sent_len = buf_len <= ava_len ? buf_len : ava_len; + if (sent_len > 0) { + int enqueue_len = 0; + unsigned long flag = 0; + + spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flag); + enqueue_len = kfifo_in(p_btif->p_tx_fifo, + (unsigned char *)p_buf, sent_len); + if (sent_len != enqueue_len) { + BTIF_ERR_FUNC("target tx len:%d, len sent:%d\n", + sent_len, enqueue_len); + } + i_ret = enqueue_len; + mb(); +/*enable BTIF Tx IRQ*/ + hal_btif_tx_ier_ctrl(p_btif, true); + spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flag); + BTIF_DBG_FUNC("enqueue len:%d\n", enqueue_len); + } else { + i_ret = 0; + } +#else + while ((_btif_is_tx_allow(p_btif)) && (sent_len < buf_len)) { + /*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ + lsr = BTIF_READ32(BTIF_LSR(base)); + + if (lsr & BTIF_LSR_TEMT_BIT) + /*Tx Holding Register if empty, which means we can write tx FIFO count to BTIF*/ + ava_len = BTIF_TX_FIFO_SIZE; + else if (lsr & BTIF_LSR_THRE_BIT) + /*Tx Holding Register if empty, which means we can write (Tx FIFO count - Tx threshold)to BTIF*/ + ava_len = BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE; + else { + /*this means data size in tx FIFO is more than Tx threshold, we will not write data to THR*/ + ava_len = 0; + break; + } + + left_len = buf_len - sent_len; +/*ava_len will be real length will write to BTIF THR*/ + ava_len = ava_len > left_len ? left_len : ava_len; +/*update sent length valud after this operation*/ + sent_len += ava_len; +/* + * whether we need memory barrier here? + * Ans: No, no memory ordering issue exist, + * CPU will make sure logically right + */ + while (ava_len--) + btif_reg_sync_writeb(*(p_data++), BTIF_THR(base)); + + } +/* while ((hal_btif_is_tx_allow()) && (sent_len < buf_len)); */ + + i_ret = sent_len; + +/*enable BTIF Tx IRQ*/ + hal_btif_tx_ier_ctrl(p_btif, true); +#endif + return i_ret; +} + + +/***************************************************************************** +* FUNCTION +* hal_btif_raise_wak_sig +* DESCRIPTION +* raise wakeup signal to counterpart +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_raise_wak_sig(P_MTK_BTIF_INFO_STR p_btif) +{ + int i_ret = -1; + unsigned long base = p_btif->base; +#if defined(CONFIG_MTK_CLKMGR) + if (clock_is_on(MTK_BTIF_CG_BIT) == 0) { + BTIF_ERR_FUNC("%s: clock is off before send wakeup signal!!!\n", + __FILE__); + return i_ret; + } +#endif +/*write 0 to BTIF_WAK to pull ap_wakeup_consyss low */ + BTIF_CLR_BIT(BTIF_WAK(base), BTIF_WAK_BIT); + +/*wait for a period for longer than 1/32k period, here we use 40us*/ + set_current_state(TASK_UNINTERRUPTIBLE); + usleep_range(128, 160); +/* + * according to linux/documentation/timers/timers-how-to, we choose usleep_range + * SLEEPING FOR ~USECS OR SMALL MSECS ( 10us - 20ms): * Use usleep_range + */ +/*write 1 to pull ap_wakeup_consyss high*/ + BTIF_SET_BIT(BTIF_WAK(base), BTIF_WAK_BIT); + i_ret = 0; + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_dump_reg +* DESCRIPTION +* dump BTIF module's information when needed +* PARAMETERS +* p_base [IN] BTIF module's base address +* flag [IN] register id flag +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_dump_reg(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_REG_ID flag) +{ +/*Chaozhong: To be implement*/ + int i_ret = -1; + int idx = 0; + /*unsigned long irq_flag = 0;*/ + unsigned long base = p_btif->base; + unsigned char reg_map[0xE0 / 4] = { 0 }; + unsigned int lsr = 0x0; + unsigned int dma_en = 0; + + /*spin_lock_irqsave(&(g_clk_cg_spinlock), irq_flag);*/ +#if defined(CONFIG_MTK_CLKMGR) + if (clock_is_on(MTK_BTIF_CG_BIT) == 0) { + /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ + BTIF_ERR_FUNC("%s: clock is off, this should never happen!!!\n", + __FILE__); + return i_ret; + } +#endif + lsr = BTIF_READ32(BTIF_LSR(base)); + dma_en = BTIF_READ32(BTIF_DMA_EN(base)); + /* + * here we omit 1st register which is THR/RBR register to avoid + * Rx data read by this debug information accidently + */ + for (idx = 1; idx < sizeof(reg_map); idx++) + reg_map[idx] = BTIF_READ8(p_btif->base + (4 * idx)); + /*spin_unlock_irqrestore(&(g_clk_cg_spinlock), irq_flag);*/ + BTIF_INFO_FUNC("BTIF's clock is on\n"); + BTIF_INFO_FUNC("base address: 0x%lx\n", base); + switch (flag) { + case REG_BTIF_ALL: +#if 0 + BTIF_INFO_FUNC("BTIF_IER:0x%x\n", BTIF_READ32(BTIF_IER(base))); + BTIF_INFO_FUNC("BTIF_IIR:0x%x\n", BTIF_READ32(BTIF_IIR(base))); + BTIF_INFO_FUNC("BTIF_FAKELCR:0x%x\n", + BTIF_READ32(BTIF_FAKELCR(base))); + BTIF_INFO_FUNC("BTIF_LSR:0x%x\n", BTIF_READ32(BTIF_LSR(base))); + BTIF_INFO_FUNC("BTIF_SLEEP_EN:0x%x\n", + BTIF_READ32(BTIF_SLEEP_EN(base))); + BTIF_INFO_FUNC("BTIF_DMA_EN:0x%x\n", + BTIF_READ32(BTIF_DMA_EN(base))); + BTIF_INFO_FUNC("BTIF_RTOCNT:0x%x\n", + BTIF_READ32(BTIF_RTOCNT(base))); + BTIF_INFO_FUNC("BTIF_TRI_LVL:0x%x\n", + BTIF_READ32(BTIF_TRI_LVL(base))); + BTIF_INFO_FUNC("BTIF_WAT_TIME:0x%x\n", + BTIF_READ32(BTIF_WAT_TIME(base))); + BTIF_INFO_FUNC("BTIF_HANDSHAKE:0x%x\n", + BTIF_READ32(BTIF_HANDSHAKE(base))); +#endif + btif_dump_array("BTIF register", reg_map, sizeof(reg_map)); + break; + default: + break; + } + + BTIF_INFO_FUNC("Tx DMA %s\n", + (dma_en & BTIF_DMA_EN_TX) ? "enabled" : "disabled"); + BTIF_INFO_FUNC("Rx DMA %s\n", + (dma_en & BTIF_DMA_EN_RX) ? "enabled" : "disabled"); + + BTIF_INFO_FUNC("Rx data is %s\n", + (lsr & BTIF_LSR_DR_BIT) ? "not empty" : "empty"); + BTIF_INFO_FUNC("Tx data is %s\n", + (lsr & BTIF_LSR_TEMT_BIT) ? "empty" : "not empty"); + + return i_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_is_tx_complete +* DESCRIPTION +* get tx complete flag +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* true means tx complete, false means tx in process +*****************************************************************************/ +bool hal_btif_is_tx_complete(P_MTK_BTIF_INFO_STR p_btif) +{ +/*Chaozhong: To be implement*/ + bool b_ret = false; + unsigned int lsr = 0; + unsigned long flags = 0; + unsigned long base = p_btif->base; + unsigned int tx_empty = 0; + unsigned int rx_dr = 0; + unsigned int tx_irq_disable = 0; + +/* + * 3 conditions allow clock to be disable + * 1. if TEMT is set or not + * 2. if DR is set or not + * 3. Tx IRQ is disabled or not + */ + lsr = BTIF_READ32(BTIF_LSR(base)); + tx_empty = lsr & BTIF_LSR_TEMT_BIT; + rx_dr = lsr & BTIF_LSR_DR_BIT; + tx_irq_disable = BTIF_READ32(BTIF_IER(base)) & BTIF_IER_TXEEN; + + b_ret = + (tx_empty && (tx_irq_disable == 0) && (rx_dr == 0)) ? true : false; + if (!b_ret) { + BTIF_DBG_FUNC + ("BTIF flag, tx_empty:%d, rx_dr:%d, tx_irq_disable:%d\n", + tx_empty, rx_dr, tx_irq_disable); + } +#if NEW_TX_HANDLING_SUPPORT + spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flags); +/*clear Tx enable flag if necessary*/ + if (!(kfifo_is_empty(p_btif->p_tx_fifo))) { + BTIF_DBG_FUNC("BTIF tx FIFO is not empty\n"); + b_ret = false; + } + spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flags); +#endif + return b_ret; +} + +/***************************************************************************** +* FUNCTION +* hal_btif_is_tx_allow +* DESCRIPTION +* whether tx is allowed +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* true if tx operation is allowed; false if tx is not allowed +*****************************************************************************/ +bool hal_btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif) +{ +#define MIN_TX_MB ((26 * 1000000 / 13) / 1000000) +#define AVE_TX_MB ((26 * 1000000 / 8) / 1000000) + +/*Chaozhong: To be implement*/ + bool b_ret = false; + +#if NEW_TX_HANDLING_SUPPORT + unsigned long flags = 0; + + spin_lock_irqsave(&(p_btif->tx_fifo_spinlock), flags); +/*clear Tx enable flag if necessary*/ + if (kfifo_is_full(p_btif->p_tx_fifo)) { + BTIF_WARN_FUNC("BTIF tx FIFO is full\n"); + b_ret = false; + } else { + b_ret = true; + } + spin_unlock_irqrestore(&(p_btif->tx_fifo_spinlock), flags); +#else + unsigned int lsr = 0; + unsigned long base = p_btif->base; + unsigned int wait_us = (BTIF_TX_FIFO_SIZE - BTIF_TX_FIFO_THRE) / MIN_TX_MB; /*only ava length */ + +/*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ + lsr = BTIF_READ32(BTIF_LSR(base)); + + if (!(lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT))) { + BTIF_DBG_FUNC("wait for %d ~ %d us\n", wait_us, 3 * wait_us); +/* usleep_range(wait_us, 3 * 10 * wait_us); */ + usleep_range(wait_us, 3 * wait_us); + } + lsr = BTIF_READ32(BTIF_LSR(base)); + b_ret = (lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT)) ? true : false; + if (!b_ret) + BTIF_DBG_FUNC(" tx is not allowed for the moment\n"); + else + BTIF_DBG_FUNC(" tx is allowed\n"); +#endif + return b_ret; +} + +#if !(NEW_TX_HANDLING_SUPPORT) + +static bool _btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif) +{ +/*Chaozhong: To be implement*/ + bool b_ret = false; + unsigned long base = p_btif->base; + unsigned int lsr = 0; + +/*read LSR and check THER or TEMT, either one is 1 means can accept tx data*/ + lsr = BTIF_READ32(BTIF_LSR(base)); + b_ret = (lsr & (BTIF_LSR_TEMT_BIT | BTIF_LSR_THRE_BIT)) ? true : false; + return b_ret; +} +#endif + +int hal_btif_pm_ops(P_MTK_BTIF_INFO_STR p_btif_info, MTK_BTIF_PM_OPID opid) +{ + int i_ret = -1; + + BTIF_DBG_FUNC("op id: %d\n", opid); + switch (opid) { + case BTIF_PM_DPIDLE_EN: + i_ret = 0; + break; + case BTIF_PM_DPIDLE_DIS: + i_ret = 0; + break; + case BTIF_PM_SUSPEND: + i_ret = 0; + break; + case BTIF_PM_RESUME: + i_ret = 0; + break; + case BTIF_PM_RESTORE_NOIRQ:{ + unsigned int flag = 0; + P_MTK_BTIF_IRQ_STR p_irq = p_btif_info->p_irq; + +#ifdef CONFIG_OF + flag = p_irq->irq_flags; +#else + switch (p_irq->sens_type) { + case IRQ_SENS_EDGE: + if (p_irq->edge_type == IRQ_EDGE_FALL) + flag = IRQF_TRIGGER_FALLING; + else if (p_irq->edge_type == IRQ_EDGE_RAISE) + flag = IRQF_TRIGGER_RISING; + else if (p_irq->edge_type == IRQ_EDGE_BOTH) + flag = IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING; + else + flag = IRQF_TRIGGER_FALLING; /*make this as default type */ + break; + case IRQ_SENS_LVL: + if (p_irq->lvl_type == IRQ_LVL_LOW) + flag = IRQF_TRIGGER_LOW; + else if (p_irq->lvl_type == IRQ_LVL_HIGH) + flag = IRQF_TRIGGER_HIGH; + else + flag = IRQF_TRIGGER_LOW; /*make this as default type */ + break; + default: + flag = IRQF_TRIGGER_LOW; /*make this as default type */ + break; + } +#endif +/* irq_set_irq_type(p_irq->irq_id, flag); */ + i_ret = 0; + } + break; + default: + i_ret = ERR_INVALID_PAR; + break; + } + + return i_ret; +} +void mtk_btif_read_cpu_sw_rst_debug_plat(void) +{ +#define CONSYS_AP2CONN_WAKEUP_OFFSET 0x00000064 + BTIF_WARN_FUNC("+CONSYS_AP2CONN_WAKEUP_OFFSET(0x%x)\n", + BTIF_READ32(mtk_btif.base + CONSYS_AP2CONN_WAKEUP_OFFSET)); +} + diff --git a/drivers/misc/mediatek/btif/common/inc/mtk_btif.h b/drivers/misc/mediatek/btif/common/inc/mtk_btif.h new file mode 100644 index 00000000000000..def2ba4c5b647a --- /dev/null +++ b/drivers/misc/mediatek/btif/common/inc/mtk_btif.h @@ -0,0 +1,370 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_BTIF_H_ +#define __MTK_BTIF_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* gettimeofday */ +#include + +#include "btif_pub.h" +#include "btif_dma_pub.h" +#include "mtk_btif_exp.h" + +#define BTIF_PORT_NR 1 +#define BTIF_USER_NAME_MAX_LEN 32 + +/*-------------Register Defination Start ---------------*/ +#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD)) +#define BTIF_RX_BUFFER_SIZE (1024 * 32) +#else +#define BTIF_RX_BUFFER_SIZE (1024 * 64) +#endif +#define BTIF_TX_FIFO_SIZE (1024 * 4) + +/*------------Register Defination End ----------------*/ + +/*------------BTIF Module Clock and Power Control Defination---------------*/ +typedef enum _ENUM_BTIF_RX_TYPE_ { + BTIF_IRQ_CTX = 0, + BTIF_TASKLET_CTX = BTIF_IRQ_CTX + 1, + BTIF_THREAD_CTX = BTIF_TASKLET_CTX + 1, + BTIF_WQ_CTX = BTIF_THREAD_CTX + 1, + BTIF_RX_TYPE_MAX, +} ENUM_BTIF_RX_TYPE; + +typedef enum _ENUM_BTIF_TX_TYPE_ { + BTIF_TX_USER_CTX = 0, + BTIF_TX_SINGLE_CTX = BTIF_TX_USER_CTX + 1, + BTIF_TX_TYPE_MAX, +} ENUM_BTIF_TX_TYPE; + +typedef enum _ENUM_BTIF_STATE_ { + B_S_OFF = 0, + B_S_SUSPEND = B_S_OFF + 1, + B_S_DPIDLE = B_S_SUSPEND + 1, + B_S_ON = B_S_DPIDLE + 1, + B_S_MAX, +} ENUM_BTIF_STATE; + +#define ENABLE_BTIF_RX_DMA 1 +#define ENABLE_BTIF_TX_DMA 1 + +#if ENABLE_BTIF_TX_DMA +#define BTIF_TX_MODE BTIF_MODE_DMA +#else +#define BTIF_TX_MODE BTIF_MODE_PIO +#endif + +#if ENABLE_BTIF_RX_DMA +#define BTIF_RX_MODE BTIF_MODE_DMA +#else +#define BTIF_RX_MODE BTIF_MODE_PIO +#endif + +#define BTIF_RX_BTM_CTX BTIF_THREAD_CTX/*BTIF_WQ_CTX*//* BTIF_TASKLET_CTX */ +/* + * -- cannot be used because , + * mtk_wcn_stp_parser data will call *(stp_if_tx) to send ack, + * in which context sleepable lock or usleep operation may be used, + * these operation is not allowed in tasklet, may cause schedule_bug + */ + +#define BTIF_TX_CTX BTIF_TX_USER_CTX /* BTIF_TX_SINGLE_CTX */ + +#define ENABLE_BTIF_RX_THREAD_RT_SCHED 0 +#define MAX_BTIF_RXD_TIME_REC 3 + +/*Structure Defination*/ + +/*-----------------BTIF setting--------------*/ +typedef struct _mtk_btif_setting_ { + ENUM_BTIF_MODE tx_mode; /*BTIF Tx Mode Setting */ + ENUM_BTIF_MODE rx_mode; /*BTIF Tx Mode Setting */ + ENUM_BTIF_RX_TYPE rx_type; /*rx handle type */ + ENUM_BTIF_TX_TYPE tx_type; /*tx type */ +} mtk_btif_setting, *p_mtk_btif_setting; +/*---------------------------------------------------------------------------*/ + +#if 0 +/*---------------------------------------------------------------------------*/ +typedef struct _mtk_btif_register_ { + unsigned int iir; /*Interrupt Identification Register */ + unsigned int lsr; /*Line Status Register */ + unsigned int fake_lcr; /*Fake Lcr Regiseter */ + unsigned int fifo_ctrl; /*FIFO Control Register */ + unsigned int ier; /*Interrupt Enable Register */ + unsigned int sleep_en; /*Sleep Enable Register */ + unsigned int rto_counter; /*Rx Timeout Counter Register */ + unsigned int dma_en; /*DMA Enalbe Register */ + unsigned int tri_lvl; /*Tx/Rx Trigger Level Register */ + unsigned int wat_time; /*Async Wait Time Register */ + unsigned int handshake; /*New HandShake Mode Register */ + unsigned int sleep_wak; /*Sleep Wakeup Reigster */ +} mtk_btif_register, *p_mtk_btif_register; +/*---------------------------------------------------------------------------*/ + +#endif + +typedef struct _btif_buf_str_ { + unsigned int size; + unsigned char *p_buf; + /* + * For Tx: next Tx data pointer to FIFO; + * For Rx: next read data pointer from BTIF user + */ + unsigned int rd_idx; + /* + * For Tx: next Tx data pointer from BTIF user; + * For Rx: next write data(from FIFO) pointer + */ + unsigned int wr_idx; +} btif_buf_str, *p_btif_buf_str; + +/*---------------------------------------------------------------------------*/ +typedef struct _mtk_btif_dma_ { + /*p_mtk_btif*/ void *p_btif; + /*BTIF pointer to which DMA belongs */ + +#if 0 + unsigned int channel; /*DMA's channel */ +#endif + + ENUM_BTIF_DIR dir; /*DMA's direction: */ + bool enable; /*DMA enable or disable flag */ + + P_MTK_DMA_INFO_STR p_dma_info; /*DMA's IRQ information */ + +#if 0 + mtk_dma_register register; /*DMA's register */ +#endif + + spinlock_t iolock; /*io lock for DMA channel */ + atomic_t entry; /* entry count */ +} mtk_btif_dma, *p_mtk_btif_dma; + +#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD)) +#define BTIF_LOG_ENTRY_NUM 10 +#else +#define BTIF_LOG_ENTRY_NUM 30 +#endif + +#define BTIF_LOG_SZ 1536 + +typedef void (*MTK_BTIF_RX_NOTIFY) (void); + +typedef struct _btif_log_buf_t_ { + unsigned int len; + struct timespec64 timer; + unsigned char buffer[BTIF_LOG_SZ]; +} BTIF_LOG_BUF_T, *P_BTIF_LOG_BUF_T; + +typedef struct _btif_log_queue_t_ { + ENUM_BTIF_DIR dir; + bool enable; + bool output_flag; + unsigned int in; + unsigned int out; + unsigned int size; + spinlock_t lock; + P_BTIF_LOG_BUF_T p_queue[BTIF_LOG_ENTRY_NUM]; +} BTIF_LOG_QUEUE_T, *P_BTIF_LOG_QUEUE_T; + +/*---------------------------------------------------------------------------*/ +typedef struct _mtk_btif_ { + unsigned int open_counter; /*open counter */ + bool enable; /*BTIF module enable flag */ + bool lpbk_flag; /*BTIF module enable flag */ +#if 0 + unsigned long base; /* BTIF controller base address */ +#endif + + ENUM_BTIF_STATE state; /*BTIF state mechanism */ + struct mutex state_mtx; /*lock to BTIF state mechanism's state change */ + struct mutex ops_mtx; /*lock to BTIF's open and close */ + +#if 0 + mtk_btif_register register; /*BTIF registers */ +#endif + + ENUM_BTIF_MODE tx_mode; /* BTIF Tx channel mode */ + ENUM_BTIF_MODE rx_mode; /* BTIF Rx channel mode */ + struct mutex tx_mtx; /*lock to BTIF's tx process */ +/*rx handling */ + ENUM_BTIF_RX_TYPE btm_type; /*BTIF Rx bottom half context */ +/*tx handling*/ + ENUM_BTIF_TX_TYPE tx_ctx; /*BTIF tx context */ +/* unsigned char rx_buf[BTIF_RX_BUFFER_SIZE]; */ + btif_buf_str btif_buf; + spinlock_t rx_irq_spinlock; /*lock for rx irq handling */ + +/*rx workqueue information*/ + /*lock to BTIF's rx bottom half when kernel thread is used */ + struct mutex rx_mtx; + struct workqueue_struct *p_rx_wq; + struct work_struct rx_work; + + struct workqueue_struct *p_tx_wq; + struct work_struct tx_work; + struct kfifo *p_tx_fifo; + +/*rx tasklet information*/ + struct tasklet_struct rx_tasklet; + /*lock to BTIF's rx bottom half when tasklet is used */ + spinlock_t rx_tasklet_spinlock; + +/*rx thread information*/ + struct task_struct *p_task; + struct completion rx_comp; + + mtk_btif_setting *setting; /*BTIF setting */ + + p_mtk_btif_dma p_tx_dma; /*BTIF Tx channel DMA */ + p_mtk_btif_dma p_rx_dma; /*BTIF Rx channel DMA */ + + MTK_WCN_BTIF_RX_CB rx_cb; /*Rx callback function */ + MTK_BTIF_RX_NOTIFY rx_notify; + + P_MTK_BTIF_INFO_STR p_btif_info; /*BTIF's information */ + +/*Log Tx data to buffer*/ + BTIF_LOG_QUEUE_T tx_log; + +/*Log Rx data to buffer*/ + BTIF_LOG_QUEUE_T rx_log; + +/* struct list_head *p_user_list; */ + struct list_head user_list; +/* get btif dev pointer*/ + void *private_data; +} mtk_btif, *p_mtk_btif; +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +#if 0 +/*---------------------------------------------------------------------------*/ +typedef struct _mtk_dma_register_ { + unsigned int int_flag; /*Tx offset:0x0 Rx offset:0x0 */ + unsigned int int_enable; /*Tx offset:0x4 Rx offset:0x4 */ + unsigned int dma_enable; /*Tx offset:0x8 Rx offset:0x8 */ + unsigned int dma_reset; /*Tx offset:0xc Rx offset:0xc */ + unsigned int dma_stop; /*Tx offset:0x10 Rx offset:0x10 */ + unsigned int dma_flush; /*Tx offset:0x14 Rx offset:0x14 */ + unsigned int vff_addr; /*Tx offset:0x1c Rx offset:0x1c */ + unsigned int vff_len; /*Tx offset:0x24 Rx offset:0x24 */ + unsigned int vff_thr; /*Tx offset:0x28 Rx offset:0x28 */ + unsigned int vff_wpt; /*Tx offset:0x2c Rx offset:0x2c */ + unsigned int vff_rpt; /*Tx offset:0x30 Rx offset:0x30 */ + unsigned int rx_fc_thr; /*Tx:No this register Rx offset:0x34 */ + unsigned int int_buf_size; /*Tx offset:0x38 Rx offset:0x38 */ + unsigned int vff_valid_size; /*Tx offset:0x3c Rx offset:0x3c */ + unsigned int vff_left_size; /*Tx offset:0x40 Rx offset:0x40 */ + unsigned int debug_status; /*Tx offset:0x50 Rx offset:0x50 */ +} mtk_dma_register, *p_mtk_dma_register; +/*---------------------------------------------------------------------------*/ +#endif + +/*---------------------------------------------------------------------------*/ +typedef struct _mtk_btif_user_ { + bool enable; /*register its state */ + struct list_head entry; /*btif_user's bi-direction list table */ + /*BTIF's user, static allocation */ + char u_name[BTIF_USER_NAME_MAX_LEN]; + unsigned long u_id; + p_mtk_btif p_btif; +} mtk_btif_user, *p_mtk_btif_user; + +/*---------------------------------------------------------------------------*/ +#define BBS_PTR(ptr, idx) ((ptr->p_buf) + idx) + +#define BBS_SIZE(ptr) ((ptr)->size) +#define BBS_MASK(ptr) (BBS_SIZE(ptr) - 1) +#define BBS_COUNT(ptr) ((ptr)->wr_idx >= (ptr)->rd_idx ? (ptr)->wr_idx - \ +(ptr)->rd_idx : BBS_SIZE(ptr) - \ +((ptr)->rd_idx - (ptr)->wr_idx)) +#define BBS_COUNT_CUR(ptr, wr_idx) (wr_idx >= (ptr)->rd_idx ? wr_idx - \ +(ptr)->rd_idx : BBS_SIZE(ptr) - \ +((ptr)->rd_idx - wr_idx)) + +#define BBS_LEFT(ptr) (BBS_SIZE(ptr) - BBS_COUNT(ptr)) + +#define BBS_AVL_SIZE(ptr) (BBS_SIZE(ptr) - BBS_COUNT(ptr)) +#define BBS_FULL(ptr) (BBS_COUNT(ptr) - BBS_SIZE(ptr)) +#define BBS_EMPTY(ptr) ((ptr)->wr_idx == (ptr)->rd_idx) +#define BBS_WRITE_MOVE_NEXT(ptr) ((ptr)->wr_idx = \ +((ptr)->wr_idx + 1) & BBS_MASK(ptr)) +#define BBS_READ_MOVE_NEXT(ptr) ((ptr)->rd_idx = \ +((ptr)->rd_idx + 1) & BBS_MASK(ptr)) + +#define BBS_INIT(ptr) \ +{ \ +(ptr)->rd_idx = (ptr)->wr_idx = 0; \ +(ptr)->size = BTIF_RX_BUFFER_SIZE; \ +} + + +#define BTIF_MUTEX_UNLOCK(x) mutex_unlock(x) + +extern mtk_btif g_btif[]; + +int btif_open(p_mtk_btif p_btif); +int btif_close(p_mtk_btif p_btif); +int btif_send_data(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len); +int btif_enter_dpidle(p_mtk_btif p_btif); +int btif_exit_dpidle(p_mtk_btif p_btif); +int btif_rx_cb_reg(p_mtk_btif p_btif, MTK_WCN_BTIF_RX_CB rx_cb); + +/*for test purpose*/ +int _btif_suspend(p_mtk_btif p_btif); +int _btif_resume(p_mtk_btif p_btif); +int _btif_restore_noirq(p_mtk_btif p_btif); + +int btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag); +int btif_log_buf_dmp_in(P_BTIF_LOG_QUEUE_T p_log_que, const char *p_buf, + int len); +int btif_dump_data(char *p_buf, int len); +int btif_log_buf_dmp_out(P_BTIF_LOG_QUEUE_T p_log_que); +int btif_log_buf_enable(P_BTIF_LOG_QUEUE_T p_log_que); +int btif_log_buf_disable(P_BTIF_LOG_QUEUE_T p_log_que); +int btif_log_output_enable(P_BTIF_LOG_QUEUE_T p_log_que); +int btif_log_output_disable(P_BTIF_LOG_QUEUE_T p_log_que); +int btif_log_buf_reset(P_BTIF_LOG_QUEUE_T p_log_que); +int btif_log_buf_init(p_mtk_btif p_btif); +int btif_dump_reg(p_mtk_btif p_btif); +int btif_rx_notify_reg(p_mtk_btif p_btif, MTK_BTIF_RX_NOTIFY rx_notify); +int btif_raise_wak_signal(p_mtk_btif p_btif); +int btif_clock_ctrl(p_mtk_btif p_btif, int en); +bool btif_parser_wmt_evt(p_mtk_btif p_btif, + const char *sub_str, + unsigned int sub_len); +void mtk_btif_read_cpu_sw_rst_debug(void); + +#endif /*__MTK_BTIF_H_*/ diff --git a/drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h b/drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h new file mode 100644 index 00000000000000..1d43419b8ba707 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/inc/mtk_btif_exp.h @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MTK_BTIF_EXP_H_ +#define _MTK_BTIF_EXP_H_ + +/*--------------marco defination---------------*/ +#define BTIF_MAX_LEN_PER_PKT 2048 +#define BTIF_RXD_BE_BLOCKED_DETECT 1 +/*--------------Enum Defination---------------*/ +typedef enum _ENUM_BTIF_DPIDLE_ { + BTIF_DPIDLE_DISABLE = 0, + BTIF_DPIDLE_ENABLE = BTIF_DPIDLE_DISABLE + 1, + BTIF_DPIDLE_MAX, +} ENUM_BTIF_DPIDLE_CTRL; + +typedef enum _ENUM_BTIF_LPBK_MODE_ { + BTIF_LPBK_DISABLE = 0, + BTIF_LPBK_ENABLE = BTIF_LPBK_DISABLE + 1, + BTIF_LPBK_MAX, +} ENUM_BTIF_LPBK_MODE; + +typedef enum _ENUM_BTIF_DBG_ID_ { + BTIF_DISABLE_LOGGER = 0, + BTIF_ENABLE_LOGGER = BTIF_DISABLE_LOGGER + 1, + BTIF_DUMP_LOG = BTIF_ENABLE_LOGGER + 1, + BTIF_CLR_LOG = BTIF_DUMP_LOG + 1, + BTIF_DUMP_BTIF_REG = BTIF_CLR_LOG + 1, + BTIF_ENABLE_RT_LOG = BTIF_DUMP_BTIF_REG + 1, + BTIF_DISABLE_RT_LOG = BTIF_ENABLE_RT_LOG + 1, + BTIF_DUMP_BTIF_IRQ = BTIF_DISABLE_RT_LOG + 1, + BTIF_DBG_MAX, +} ENUM_BTIF_DBG_ID; + +typedef enum _ENUM_BTIF_OP_ERROR_CODE_ { + E_BTIF_AGAIN = 0, + E_BTIF_FAIL = -1, + E_BTIF_BAD_POINTER = -2, + E_BTIF_NO_SPACE = -3, + E_BTIF_INTR = -4, + E_BTIF_INVAL_PARAM = -5, + E_BTIF_ALREADY_OPEN = -6, + E_BTIF_NOT_OPEN = -7, + E_BTIF_INVAL_STATE = -8, +} ENUM_BTIF_OP_ERROR_CODE; + +/*--------------End of Enum Defination---------------*/ + +/*--------------Type Definition---------------*/ + +typedef int (*MTK_WCN_BTIF_RX_CB) (const unsigned char *p_buf, + unsigned int len); + +/*--------------End of Type Definition---------------*/ + +/*--------------Normal Mode API declearation---------------*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_open +* DESCRIPTION +* open BTIF interface, will do BTIF module HW and SW initialization +* PARAMETERS +* p_owner [IN] pointer to owner who call this API, +* currently there are 2 owner ("stp" or "btif_tester") +* may use this module +* user's id string must be less than 32 bytes +* for "stp", BTIF will call rx callback function to route rx data to STP module +* for "stp_tester", BTIF will save rx data +* and wait for native process to access +* p_id [IN] BTIF's user id will be put to this address +* RETURNS +* int 0 = succeed; others = fail, for detailed information, +* please see ENUM_BTIF_OP_ERROR_CODE +* if open success, value p_id will be the only identifier for +* user to access BTIF's other operations +* including read/write/dpidle_ctrl/rx_cb_retister +* this user id is only an identifier used for owner identification +*****************************************************************************/ +int mtk_wcn_btif_open(char *p_owner, unsigned long *p_id); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_close +* DESCRIPTION +* close BTIF interface, will do BTIF module HW and SW de-initialization +* once this API is called, p_btif should never be used by BTIF's user again +* PARAMETERS +* u_id [IN] BTIF's user id +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_close(unsigned long u_id); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_write +* DESCRIPTION +* send data throuth BTIF module +* there's no internal buffer to cache STP data in BTIF driver, +* if in DMA mode +* btif driver will check if there's enough space +* in vFIFO for data to send in DMA mode +* if yes, put data to vFIFO and return corresponding data length to caller +* if no, corresponding error code will be returned to called +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* p_buf [IN] pointer to target data to send +* len [IN] data length (should be less than 2014 bytes per STP package) +* +* if in non-DMA mode, BTIF driver will try to write to THR of BTIF controller +* if btif driver detected that no space is available in Tx FIFO, +* will return E_BTIF_NO_SPACE, +* mostly something is wrong with BTIF or consys when this +* return value is returned +* RETURNS +* int positive: data length send through BTIF; +* negative: please see ENUM_BTIF_OP_ERROR_CODE +* E_BTIF_AGAIN (0) will be returned to caller if btif does not have +* enough vFIFO to send data, when caller get 0, +* he should wait for a moment (5~10ms maybe) and +* try a few times (maybe 10~20) +* if still get E_BTIF_AGAIN, should call BTIF's debug API and +* dump BTIF driver and BTIF/DMA register information to kernel log +* for debug +* E_BTIF_BAD_POINTER will be returned to caller if btif is not +* opened successfully before call this API +* E_BTIF_INVAL_PARAM will be returned if parameter is not valid + +*****************************************************************************/ +int mtk_wcn_btif_write(unsigned long u_id, + const unsigned char *p_buf, unsigned int len); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_read +* DESCRIPTION +* read data from BTIF module +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* p_buf [IN/OUT] pointer to buffer where rx data will be put +* max_len [IN] max buffer length +* RETURNS +* int positive: data length read from BTIF; +* negative: please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_read(unsigned long u_id, + unsigned char *p_buf, unsigned int max_len); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_dpidle_ctrl +* DESCRIPTION +* control if BTIF module allow system enter deepidle state or not +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* en_flag [IN] one of ENUM_BTIF_DPIDLE_CTRL +* RETURNS +* int always return 0 +*****************************************************************************/ +int mtk_wcn_btif_dpidle_ctrl(unsigned long u_id, ENUM_BTIF_DPIDLE_CTRL en_flag); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_rx_cb_register +* DESCRIPTION +* register rx callback function to BTIF module by btif user +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* rx_cb [IN] pointer to stp rx handler callback function, +* should be comply with MTK_WCN_BTIF_RX_CB +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_rx_cb_register(unsigned long u_id, MTK_WCN_BTIF_RX_CB rx_cb); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_wakeup_consys +* DESCRIPTION +* once sleep command is sent to con sys, +* should call this API before send wakeup command to +* make con sys aware host want to send data to consys +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_wakeup_consys(unsigned long u_id); + +/*--------------End of Normal Mode API declearation----------------*/ + +/*--------------Debug Purpose API declearation----------------*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_loopback_ctrl +* DESCRIPTION +* enable/disable BTIF internal loopback function, +* when this function is enabled, +* data send to btif will be received by btif itself +* only for debug purpose, should never use this function in normal mode +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* enable [IN] loopback mode control flag, enable or disable, +* shou be one of ENUM_BTIF_LPBK_MODE +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_loopback_ctrl(unsigned long u_id, ENUM_BTIF_LPBK_MODE enable); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_logger_ctrl +* DESCRIPTION +* control BTIF logger function's behavior +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* flag [IN] should be one of ENUM_BTIF_DBG_ID +* BTIF_DISABLE_LOGGER - disable btif logger +* BTIF_ENABLE_LOGGER - enable btif logger +* BTIF_DUMP_LOG - dump log logged by btif +* BTIF_CLR_LOG - clear btif log buffer +* BTIF_DUMP_BTIF_REG - dump btif controller's register +* BTIF_DUMP_DMA_REG - dump DMA controller's register +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, +* please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_dbg_ctrl(unsigned long u_id, ENUM_BTIF_DBG_ID flag); +/*-----------End of Debug Purpose API declearation------------*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_parser_wmt_evt +* DESCRIPTION +* parser wmt sleep/wakeup evt in btif bbs buffer for debug +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* sub_str [IN] the str to be parsered +* str_len [IN] the length of sub_str +* RETURNS +* bool true = succeed; +* false = fail; +*****************************************************************************/ +bool mtk_wcn_btif_parser_wmt_evt(unsigned long u_id, + const char *sub_str, unsigned int str_len); + +int mtk_btif_exp_open_test(void); +int mtk_btif_exp_close_test(void); +int mtk_btif_exp_write_test(void); +int mtk_btif_exp_suspend_test(void); +int mtk_btif_exp_resume_test(void); +int mtk_btif_exp_enter_dpidle_test(void); +int mtk_btif_exp_exit_dpidle_test(void); +int mtk_btif_exp_write_stress_test(unsigned int length, unsigned int loop); +int mtk_btif_exp_log_debug_test(int flag); +int mtk_btif_exp_restore_noirq_test(void); +int btif_wakeup_consys_no_id(void); +int mtk_btif_exp_clock_ctrl(int en); +#if BTIF_RXD_BE_BLOCKED_DETECT +int mtk_btif_rxd_be_blocked_flag_get(void); +#endif +void mtk_btif_read_cpu_sw_rst_debug_exp(void); +#endif /*_MTK_BTIF_EXP_H_*/ diff --git a/drivers/misc/mediatek/btif/common/mtk_btif.c b/drivers/misc/mediatek/btif/common/mtk_btif.c new file mode 100644 index 00000000000000..bf1a4840762de3 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/mtk_btif.c @@ -0,0 +1,3468 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/*-----------linux system header files----------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/*#include */ +/*-----------driver own header files----------------*/ +#ifdef CONFIG_COMPAT +#include +#endif +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "MTK-BTIF" + +#define BTIF_CDEV_SUPPORT 1 + +#include "btif_pub.h" +#include "btif_dma_pub.h" +#include "mtk_btif_exp.h" +#include "mtk_btif.h" + +/*-----------static function declearation----------------*/ +static int mtk_btif_probe(struct platform_device *pdev); +static int mtk_btif_remove(struct platform_device *pdev); +static int mtk_btif_suspend(struct platform_device *pdev, pm_message_t state); +static int mtk_btif_resume(struct platform_device *pdev); +static int mtk_btif_drv_resume(struct device *dev); +static int mtk_btif_drv_suspend(struct device *pdev); + +static int mtk_btif_restore_noirq(struct device *device); +static int btif_file_open(struct inode *pinode, struct file *pfile); +static int btif_file_release(struct inode *pinode, struct file *pfile); +static ssize_t btif_file_read(struct file *pfile, + char __user *buf, size_t count, loff_t *f_ops); +static unsigned int btif_poll(struct file *filp, poll_table *wait); +static int _btif_irq_reg(P_MTK_BTIF_IRQ_STR p_irq, + mtk_btif_irq_handler irq_handler, void *data); +static int _btif_irq_free(P_MTK_BTIF_IRQ_STR p_irq, void *data); +static int _btif_irq_ctrl(P_MTK_BTIF_IRQ_STR p_irq, bool en); +static int _btif_irq_ctrl_sync(P_MTK_BTIF_IRQ_STR p_irq, bool en); +static irqreturn_t btif_irq_handler(int irq, void *data); +static unsigned int btif_pio_rx_data_receiver(P_MTK_BTIF_INFO_STR p_btif_info, + unsigned char *p_buf, + unsigned int buf_len); + +static irqreturn_t btif_tx_dma_irq_handler(int irq, void *data); +static irqreturn_t btif_rx_dma_irq_handler(int irq, void *data); + +static unsigned int btif_dma_rx_data_receiver(P_MTK_DMA_INFO_STR p_dma_info, + unsigned char *p_buf, + unsigned int buf_len); +static int _btif_controller_tx_setup(p_mtk_btif p_btif); +static int _btif_controller_tx_free(p_mtk_btif p_btif); +static int _btif_controller_rx_setup(p_mtk_btif p_btif); +static int _btif_controller_rx_free(p_mtk_btif p_btif); +static int _btif_tx_pio_setup(p_mtk_btif p_btif); +static int _btif_rx_pio_setup(p_mtk_btif p_btif); +static int _btif_rx_dma_setup(p_mtk_btif p_btif); +static int _btif_rx_dma_free(p_mtk_btif p_btif); +static int _btif_tx_dma_setup(p_mtk_btif p_btif); +static int _btif_tx_dma_free(p_mtk_btif p_btif); +static int _btif_controller_setup(p_mtk_btif p_btif); +static int _btif_controller_free(p_mtk_btif p_btif); + +static int _btif_pio_write(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len); +static int _btif_dma_write(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len); + +static unsigned int btif_bbs_wr_direct(p_btif_buf_str p_bbs, + unsigned char *p_buf, unsigned int buf_len); +static unsigned int btif_bbs_read(p_btif_buf_str p_bbs, + unsigned char *p_buf, unsigned int buf_len); +static unsigned int btif_bbs_write(p_btif_buf_str p_bbs, + unsigned char *p_buf, unsigned int buf_len); +static void btif_dump_bbs_str(unsigned char *p_str, p_btif_buf_str p_bbs); +static int _btif_dump_memory(char *str, unsigned char *p_buf, unsigned int buf_len); +static int _btif_rx_btm_deinit(p_mtk_btif p_btif); +static int _btif_rx_btm_sched(p_mtk_btif p_btif); +static int _btif_rx_btm_init(p_mtk_btif p_btif); +static void btif_rx_tasklet(unsigned long func_data); +static void btif_rx_worker(struct work_struct *p_work); +static int btif_rx_thread(void *p_data); +static int btif_rx_data_consummer(p_mtk_btif p_btif); + +static int _btif_tx_ctx_init(p_mtk_btif p_btif); +static int _btif_tx_ctx_deinit(p_mtk_btif p_btif); +static void btif_tx_worker(struct work_struct *p_work); + +static int _btif_state_deinit(p_mtk_btif p_btif); +static int _btif_state_release(p_mtk_btif p_btif); +static ENUM_BTIF_STATE _btif_state_get(p_mtk_btif p_btif); +static int _btif_state_set(p_mtk_btif p_btif, ENUM_BTIF_STATE state); +static int _btif_state_hold(p_mtk_btif p_btif); +static int _btif_state_init(p_mtk_btif p_btif); + +static int _btif_dpidle_notify_ctrl(p_mtk_btif p_btif, + ENUM_BTIF_DPIDLE_CTRL en_flag); +static int _btif_enter_dpidle(p_mtk_btif p_btif); +static int _btif_exit_dpidle(p_mtk_btif p_btif); +static int _btif_exit_dpidle_from_sus(p_mtk_btif p_btif); +static int _btif_exit_dpidle_from_dpidle(p_mtk_btif p_btif); +static int _btif_enter_dpidle_from_on(p_mtk_btif p_btif); +static int _btif_enter_dpidle_from_sus(p_mtk_btif p_btif); + +#if ENABLE_BTIF_TX_DMA +static int _btif_vfifo_deinit(p_mtk_btif_dma p_dma); +static int _btif_vfifo_init(p_mtk_btif_dma p_dma); +#endif + +static bool _btif_is_tx_complete(p_mtk_btif p_btif); +static int _btif_init(p_mtk_btif p_btif); +static int _btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag); +static int btif_rx_dma_mode_set(int en); +static int btif_tx_dma_mode_set(int en); + +static int _btif_send_data(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len); + +/*-----------end of static function declearation----------------*/ + +static const char *g_state[B_S_MAX] = { + "OFF", + "SUSPEND", + "DPIDLE", + "ON", +}; + +/*-----------BTIF setting--------------*/ +mtk_btif_setting g_btif_setting[BTIF_PORT_NR] = { + { + .tx_mode = BTIF_TX_MODE, + .rx_mode = BTIF_RX_MODE, + .rx_type = BTIF_RX_BTM_CTX, + .tx_type = BTIF_TX_CTX, + }, +}; + +mtk_btif g_btif[BTIF_PORT_NR] = { + { + .open_counter = 0, + .state = B_S_OFF, + .setting = &g_btif_setting[0], + .p_tx_dma = NULL, + .p_rx_dma = NULL, + .rx_cb = NULL, + .p_btif_info = NULL, + }, +}; + +mtk_btif_dma g_dma[BTIF_PORT_NR][BTIF_DIR_MAX] = { + { + { + .p_btif = NULL, + .dir = BTIF_TX, + .p_dma_info = NULL, + .entry = ATOMIC_INIT(0), + }, + { + .p_btif = NULL, + .dir = BTIF_RX, + .p_dma_info = NULL, + .entry = ATOMIC_INIT(0), + }, + }, +}; + +#define G_MAX_PKG_LEN (7 * 1024) +static int g_max_pkg_len = G_MAX_PKG_LEN; /*DMA vFIFO is set to 8 * 1024, we set this to 7/8 * vFIFO size*/ +static int g_max_pding_data_size = BTIF_RX_BUFFER_SIZE * 3 / 4; + + +static int mtk_btif_dbg_lvl = BTIF_LOG_ERR; + +#if BTIF_RXD_BE_BLOCKED_DETECT +static struct timespec64 btif_rxd_time_stamp[MAX_BTIF_RXD_TIME_REC]; +#endif +/*-----------Platform bus related structures----------------*/ +#define DRV_NAME "mtk_btif" + +#ifdef CONFIG_OF +const struct of_device_id apbtif_of_ids[] = { + { .compatible = "mediatek,btif", }, + {} +}; +#endif + +const struct dev_pm_ops mtk_btif_drv_pm_ops = { + .restore_noirq = mtk_btif_restore_noirq, + .suspend = mtk_btif_drv_suspend, + .resume = mtk_btif_drv_resume, +}; + +struct platform_driver mtk_btif_dev_drv = { + .probe = mtk_btif_probe, + .remove = mtk_btif_remove, +#ifdef CONFIG_PM + .suspend = mtk_btif_suspend, + .resume = mtk_btif_resume, +#endif + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &mtk_btif_drv_pm_ops, +#endif +#ifdef CONFIG_OF + .of_match_table = apbtif_of_ids, +#endif + } +}; + +#define BTIF_STATE_RELEASE(x) _btif_state_release(x) + +/*-----------End of Platform bus related structures----------------*/ + +/*-----------platform bus related operation APIs----------------*/ + +static int mtk_btif_probe(struct platform_device *pdev) +{ +/*Chaozhong: ToDo: to be implement*/ +/*register IRQ for BTIF and Tx Rx DMA and disable them by default*/ + BTIF_INFO_FUNC("DO BTIF PROBE\n"); + platform_set_drvdata(pdev, &g_btif[0]); + g_btif[0].private_data = (struct device *)&pdev->dev; + +#if !defined(CONFIG_MTK_CLKMGR) + hal_btif_clk_get_and_prepare(pdev); +#endif + + return 0; +} + +static int mtk_btif_remove(struct platform_device *pdev) +{ +/*Chaozhong: ToDo: to be implement*/ + BTIF_INFO_FUNC("DO BTIF REMOVE\n"); + platform_set_drvdata(pdev, NULL); + g_btif[0].private_data = NULL; + return 0; +} + +int _btif_suspend(p_mtk_btif p_btif) +{ + int i_ret; + + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + if (p_btif != NULL) { + if (!(p_btif->enable)) + i_ret = 0; + else { + if (_btif_state_get(p_btif) == B_S_ON) { + BTIF_ERR_FUNC("BTIF in ON state,", + "there are data need to be send or recev,suspend fail\n"); + i_ret = -1; + } else { + /* + * before disable BTIF controller and DMA controller + * we need to set BTIF to ON state + */ + i_ret = _btif_exit_dpidle(p_btif); + if (i_ret == 0) { + i_ret += _btif_controller_free(p_btif); + i_ret = _btif_controller_tx_free(p_btif); + i_ret += _btif_controller_rx_free(p_btif); + } + if (i_ret != 0) { + BTIF_INFO_FUNC("failed\n"); + /*Chaozhong: what if failed*/ + } else { + BTIF_INFO_FUNC("succeed\n"); + i_ret = _btif_state_set(p_btif, B_S_SUSPEND); + if (i_ret && _btif_init(p_btif)) { + /*Chaozhong:BTIF re-init failed? what to do*/ + i_ret = _btif_state_set(p_btif, B_S_OFF); + } + } + } + } + } else + i_ret = -1; + BTIF_STATE_RELEASE(p_btif); + + return i_ret; +} + + +static int mtk_btif_drv_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + pm_message_t state = PMSG_SUSPEND; + + return mtk_btif_suspend(pdev, state); +} + +static int mtk_btif_drv_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + return mtk_btif_resume(pdev); +} + +static int mtk_btif_suspend(struct platform_device *pdev, pm_message_t state) +{ + int i_ret = 0; + p_mtk_btif p_btif = NULL; + +/*Chaozhong: ToDo: to be implement*/ + BTIF_DBG_FUNC("++\n"); + p_btif = platform_get_drvdata(pdev); + i_ret = _btif_suspend(p_btif); + BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); + return i_ret; +} + +int _btif_restore_noirq(p_mtk_btif p_btif) +{ + int i_ret = 0; + +/*BTIF IRQ restore no irq*/ + i_ret = hal_btif_pm_ops(p_btif->p_btif_info, BTIF_PM_RESTORE_NOIRQ); + if (i_ret == 0) { + BTIF_INFO_FUNC("BTIF HW IRQ restore succeed\n"); + } else { + BTIF_INFO_FUNC("BTIF HW IRQ restore failed, i_ret:%d\n", i_ret); + return i_ret; + } +/*BTIF DMA restore no irq*/ + if (p_btif->tx_mode & BTIF_MODE_DMA) { + i_ret = hal_dma_pm_ops(p_btif->p_tx_dma->p_dma_info, + BTIF_PM_RESTORE_NOIRQ); + if (i_ret == 0) { + BTIF_INFO_FUNC("BTIF Tx DMA IRQ restore succeed\n"); + } else { + BTIF_INFO_FUNC + ("BTIF Tx DMA IRQ restore failed, i_ret:%d\n", + i_ret); + return i_ret; + } + } + if (p_btif->rx_mode & BTIF_MODE_DMA) { + i_ret = hal_dma_pm_ops(p_btif->p_rx_dma->p_dma_info, + BTIF_PM_RESTORE_NOIRQ); + if (i_ret == 0) { + BTIF_INFO_FUNC("BTIF Rx DMA IRQ restore succeed\n"); + } else { + BTIF_INFO_FUNC + ("BTIF Rx DMA IRQ restore failed, i_ret:%d\n", + i_ret); + return i_ret; + } + } + return i_ret; +} + +static int mtk_btif_restore_noirq(struct device *dev) +{ + int i_ret = 0; + struct platform_device *pdev = to_platform_device(dev); + p_mtk_btif p_btif = platform_get_drvdata(pdev); + + BTIF_INFO_FUNC("++\n"); + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + if (p_btif->enable) + BTIF_ERR_FUNC("!!!-----------------!BTIF is not closed before IPOH shutdown!!!---------------!\n"); + WARN_ON(p_btif->enable); + + i_ret = _btif_restore_noirq(p_btif); + BTIF_STATE_RELEASE(p_btif); + BTIF_INFO_FUNC("--\n"); + return 0; +} + +int _btif_resume(p_mtk_btif p_btif) +{ + int i_ret = 0; + ENUM_BTIF_STATE state = B_S_MAX; + + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + if (p_btif != NULL) { + state = _btif_state_get(p_btif); + if (!(p_btif->enable)) + i_ret = 0; + else if (state == B_S_SUSPEND) + i_ret = _btif_enter_dpidle(p_btif); + else + BTIF_INFO_FUNC + ("BTIF state: %s before resume, do nothing\n", g_state[state]); + } else + i_ret = -1; + BTIF_STATE_RELEASE(p_btif); + + return i_ret; +} + +static int mtk_btif_resume(struct platform_device *pdev) +{ + int i_ret = 0; + p_mtk_btif p_btif = NULL; +/*Chaozhong: ToDo: to be implement*/ + BTIF_DBG_FUNC("++\n"); + p_btif = platform_get_drvdata(pdev); + i_ret = _btif_resume(p_btif); + BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); + return 0; +} + +/*-----------device node----------------*/ +#if BTIF_CDEV_SUPPORT + +dev_t btif_dev; +struct class *p_btif_class; +struct device *p_btif_dev; +const char *p_btif_dev_name = "btif"; +static struct semaphore wr_mtx; +static struct semaphore rd_mtx; +unsigned char wr_buf[2048]; +unsigned char rd_buf[2048]; +static int rx_notify_flag; +static DECLARE_WAIT_QUEUE_HEAD(btif_wq); +static int btif_file_open(struct inode *pinode, struct file *pfile); +static int btif_file_release(struct inode *pinode, struct file *pfile); +static ssize_t btif_file_read(struct file *pfile, + char __user *buf, size_t count, loff_t *f_ops); + +static ssize_t btif_file_write(struct file *filp, + const char __user *buf, size_t count, loff_t *f_pos); +static long btif_unlocked_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); +#ifdef CONFIG_COMPAT +static long btif_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#endif +static struct cdev btif_dev_c; +static wait_queue_head_t btif_read_inq; /* read queues */ + +const struct file_operations mtk_btif_fops = { + .owner = THIS_MODULE, + .open = btif_file_open, + .release = btif_file_release, + .read = btif_file_read, + .write = btif_file_write, + .unlocked_ioctl = btif_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = btif_compat_ioctl, +#endif + .poll = btif_poll, +}; + +static int btif_chrdev_init(void) +{ + int i_ret; + + int i_err; + + /* alloc device number dynamically */ + i_ret = alloc_chrdev_region(&btif_dev, 0, 1, p_btif_dev_name); + if (i_ret) { + BTIF_ERR_FUNC("devuce number allocation failed, i_ret:%d\n", + i_ret); + } else { + BTIF_INFO_FUNC("devuce number allocation succeed\n"); + } + cdev_init(&btif_dev_c, &mtk_btif_fops); + btif_dev_c.owner = THIS_MODULE; + i_err = cdev_add(&btif_dev_c, btif_dev, 1); + if (i_err) { + BTIF_ERR_FUNC("error add btif dev to kernel, error code:%d\n", + i_err); + unregister_chrdev_region(btif_dev, 1); + btif_dev = 0; + return -1; + } + BTIF_INFO_FUNC("add btif dev to kernel succeed\n"); + + p_btif_class = class_create(/*THIS_MODULE, */p_btif_dev_name); + if (IS_ERR(p_btif_class)) { + BTIF_ERR_FUNC("error happened when doing class_create\n"); + unregister_chrdev_region(btif_dev, 1); + btif_dev = 0; + return -2; + } + BTIF_INFO_FUNC("create class for btif succeed\n"); + + p_btif_dev = device_create(p_btif_class, + NULL, btif_dev, 0, p_btif_dev_name); + if (IS_ERR(p_btif_dev)) { + BTIF_ERR_FUNC("error happened when doing device_create\n"); + class_destroy(p_btif_class); + p_btif_class = NULL; + unregister_chrdev_region(btif_dev, 1); + btif_dev = 0; + return -3; + } + BTIF_INFO_FUNC("create device for btif succeed\n"); + + return 0; +} + +void btif_rx_notify_cb(void) +{ + BTIF_DBG_FUNC("++\n"); + rx_notify_flag = 1; + wake_up(&btif_wq); + wake_up_interruptible(&btif_read_inq); + BTIF_DBG_FUNC("--\n"); +} + +unsigned int btif_poll(struct file *filp, poll_table *wait) +{ + unsigned int mask = 0; + unsigned int ava_len = 0; +/* btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, sizeof(rd_buf)); */ + unsigned int wr_idx = g_btif[0].btif_buf.wr_idx; + +/* BTIF_Rx_IRQ_Disable(); */ + ava_len = BBS_COUNT_CUR(&(g_btif[0].btif_buf), wr_idx); + BTIF_INFO_FUNC("++\n"); + if (ava_len == 0) { + poll_wait(filp, &btif_read_inq, wait); + wr_idx = g_btif[0].btif_buf.wr_idx; + ava_len = BBS_COUNT_CUR(&(g_btif[0].btif_buf), wr_idx); +/* btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, sizeof(rd_buf)); */ + if (ava_len) + mask |= POLLIN | POLLRDNORM; /* readable */ + } else { + mask |= POLLIN | POLLRDNORM; /* readable */ + } +/*make for writable*/ + mask |= POLLOUT | POLLWRNORM; /* writable */ + BTIF_INFO_FUNC("--, mask:%d\n", mask); + return mask; +} + +static int _btif_file_open(void) +{ + int i_ret = -1; + p_mtk_btif p_btif = &g_btif[0]; + + BTIF_INFO_FUNC("++\n"); + +/*Chaozhong: ToDo: to be implement*/ + i_ret = btif_open(p_btif); + if ((i_ret != 0) && (i_ret != E_BTIF_ALREADY_OPEN)) { + BTIF_ERR_FUNC("btif_open failed, error code:%d\n", i_ret); + } else { + BTIF_INFO_FUNC("btif_open succeed\n"); + i_ret = 0; + } +/*semaphore for read and write operation init*/ + sema_init(&wr_mtx, 1); + sema_init(&rd_mtx, 1); + +/*buffer for read and write init*/ + memset(wr_buf, 0, sizeof(wr_buf)); + memset(rd_buf, 0, sizeof(rd_buf)); + init_waitqueue_head(&(btif_read_inq)); + btif_rx_notify_reg(p_btif, btif_rx_notify_cb); + BTIF_INFO_FUNC("--\n"); + return i_ret; +} + +static int _btif_file_close(void) +{ + int i_ret = -1; + + BTIF_INFO_FUNC("++\n"); +/*Chaozhong: ToDo: to be implement*/ + i_ret = btif_close(&g_btif[0]); + if (i_ret != 0) + BTIF_ERR_FUNC("btif_close failed, error code:%d\n", i_ret); + else + BTIF_INFO_FUNC("btif_close succeed\n"); + + BTIF_INFO_FUNC("--\n"); + return i_ret; +} + +static int btif_file_open(struct inode *pinode, struct file *pfile) +{ + int i_ret = -1; + + BTIF_INFO_FUNC("pid:%d\n", current->pid); + i_ret = 0; + return i_ret; +} + +static int btif_file_release(struct inode *pinode, struct file *pfile) +{ + int i_ret = -1; + + BTIF_INFO_FUNC("pid:%d\n", current->pid); + i_ret = 0; + return i_ret; +} + +static ssize_t btif_file_read(struct file *pfile, + char __user *buf, size_t count, loff_t *f_ops) +{ + int i_ret = 0; + int rd_len = 0; + + BTIF_INFO_FUNC("++\n"); + down(&rd_mtx); + rd_len = btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, sizeof(rd_buf)); + while (rd_len == 0) { + if (pfile->f_flags & O_NONBLOCK) + break; + + wait_event(btif_wq, rx_notify_flag != 0); + rx_notify_flag = 0; + rd_len = + btif_bbs_read(&(g_btif[0].btif_buf), rd_buf, + sizeof(rd_buf)); + } + + if (rd_len == 0) + i_ret = 0; + else if ((rd_len > 0) && (copy_to_user(buf, rd_buf, rd_len) == 0)) + i_ret = rd_len; + else + i_ret = -EFAULT; + + up(&rd_mtx); + BTIF_INFO_FUNC("--, i_ret:%d\n", i_ret); + return i_ret; +} + +ssize_t btif_file_write(struct file *filp, + const char __user *buf, size_t count, loff_t *f_pos) +{ + int i_ret = 0; + int copy_size = 0; + + copy_size = count > sizeof(wr_buf) ? sizeof(wr_buf) : count; + + BTIF_INFO_FUNC("++\n"); + down(&wr_mtx); + if (copy_from_user(&wr_buf[0], &buf[0], copy_size)) + i_ret = -EFAULT; + else + i_ret = btif_send_data(&g_btif[0], wr_buf, copy_size); + + up(&wr_mtx); + BTIF_INFO_FUNC("--, i_ret:%d\n", i_ret); + + return i_ret; +} +#ifdef CONFIG_COMPAT +long btif_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret; + + BTIF_INFO_FUNC("cmd[0x%x]\n", cmd); + ret = btif_unlocked_ioctl(filp, cmd, arg); + return ret; +} +#endif +long btif_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ +#define BTIF_IOC_MAGIC 0xb0 +#define BTIF_IOCTL_OPEN _IOW(BTIF_IOC_MAGIC, 1, int) +#define BTIF_IOCTL_CLOSE _IOW(BTIF_IOC_MAGIC, 2, int) +#define BTIF_IOCTL_LPBK_CTRL _IOWR(BTIF_IOC_MAGIC, 3, int) +#define BTIF_IOCTL_LOG_FUNC_CTRL _IOWR(BTIF_IOC_MAGIC, 4, int) +#define BTIF_IOCTL_RT_LOG_CTRL _IOWR(BTIF_IOC_MAGIC, 5, int) +#define BTIF_IOCTL_LOG_DUMP _IOWR(BTIF_IOC_MAGIC, 6, int) +#define BTIF_IOCTL_REG_DUMP _IOWR(BTIF_IOC_MAGIC, 7, int) +#define BTIF_IOCTL_DMA_CTRL _IOWR(BTIF_IOC_MAGIC, 8, int) + + long ret = 0; +/* unsigned char p_buf[NAME_MAX + 1]; */ + p_mtk_btif p_btif = &g_btif[0]; + + BTIF_INFO_FUNC("++\n"); + BTIF_DBG_FUNC("cmd (%u), arg (0x%lx)\n", cmd, arg); + + switch (cmd) { + case BTIF_IOCTL_OPEN: + ret = _btif_file_open(); + break; + case BTIF_IOCTL_CLOSE: + ret = _btif_file_close(); + break; + case BTIF_IOCTL_LPBK_CTRL: + ret = btif_lpbk_ctrl(p_btif, arg == 0 ? 0 : 1); + break; + case BTIF_IOCTL_LOG_FUNC_CTRL: + if (arg == 0) { + ret += btif_log_buf_disable(&p_btif->tx_log); + ret += btif_log_buf_disable(&p_btif->rx_log); + } else { + ret += btif_log_buf_enable(&p_btif->tx_log); + ret += btif_log_buf_enable(&p_btif->rx_log); + } + break; + case BTIF_IOCTL_RT_LOG_CTRL: + if (arg == 0) { + ret += btif_log_output_disable(&p_btif->tx_log); + ret += btif_log_output_disable(&p_btif->rx_log); + } else { + ret += btif_log_output_enable(&p_btif->tx_log); + ret += btif_log_output_enable(&p_btif->rx_log); + } + break; + case BTIF_IOCTL_LOG_DUMP: + + ret += btif_log_buf_dmp_out(&p_btif->tx_log); + ret += btif_log_buf_dmp_out(&p_btif->rx_log); + break; + case BTIF_IOCTL_REG_DUMP: + ret += btif_dump_reg(p_btif); + break; + case BTIF_IOCTL_DMA_CTRL: + if (arg == 0) { + ret += btif_tx_dma_mode_set(0); + ret += btif_rx_dma_mode_set(0); + } else { + ret += btif_tx_dma_mode_set(1); + ret += btif_rx_dma_mode_set(1); + } + break; + default: + BTIF_INFO_FUNC("unknown cmd(%d)\n", cmd); + ret = -2; + break; + } + BTIF_INFO_FUNC("--\n"); + return ret; +} + +#endif + +/*-----------device property----------------*/ +static ssize_t driver_flag_read(struct device_driver *drv, char *buf) +{ + return sprintf(buf, "btif driver debug level:%d\n", mtk_btif_dbg_lvl); +} + +static ssize_t driver_flag_set(struct device_driver *drv, + const char *buffer, size_t count) +{ + char buf[256]; + char *p_buf; + unsigned long len = count; + long x = 0; + long y = 0; + long z = 0; + int result = 0; + char *p_token = NULL; + char *p_delimiter = " \t"; + + BTIF_INFO_FUNC("buffer = %s, count = %zd\n", buffer, count); + if (len >= sizeof(buf)) { + BTIF_ERR_FUNC("input handling fail!\n"); + len = sizeof(buf) - 1; + return -1; + } + + memcpy(buf, buffer, sizeof(buf)); + p_buf = buf; + + p_token = strsep(&p_buf, p_delimiter); + if (p_token != NULL) { + result = kstrtol(p_token, 16, &x); + BTIF_INFO_FUNC("x = 0x%08x\n\r", x); + } else + x = 0; +/* x = (NULL != p_token) ? kstrtol(p_token, 16, NULL) : 0;*/ + + p_token = strsep(&p_buf, "\t\n "); + if (p_token != NULL) { + result = kstrtol(p_token, 16, &y); + BTIF_INFO_FUNC("y = 0x%08x\n\r", y); + } else + y = 0; + + p_token = strsep(&p_buf, "\t\n "); + if (p_token != NULL) + result = kstrtol(p_token, 16, &z); + else + z = 0; + + BTIF_INFO_FUNC("x(0x%08x), y(0x%08x), z(0x%08x)\n\r", x, y, z); + + switch (x) { + case 1: + mtk_btif_exp_open_test(); + break; + case 2: + mtk_btif_exp_close_test(); + break; + case 3: + mtk_btif_exp_write_test(); + break; + case 4: + mtk_btif_exp_enter_dpidle_test(); + break; + case 5: + mtk_btif_exp_exit_dpidle_test(); + break; + case 6: + mtk_btif_exp_suspend_test(); + break; + case 7: + mtk_btif_exp_resume_test(); + break; + case 8: + if (y > BTIF_LOG_LOUD) + mtk_btif_dbg_lvl = BTIF_LOG_LOUD; + else if (y < BTIF_LOG_ERR) + mtk_btif_dbg_lvl = BTIF_LOG_WARN; + else + mtk_btif_dbg_lvl = y; + BTIF_ERR_FUNC("mtk_btif_dbg_lvl set to %d\n", mtk_btif_dbg_lvl); + break; + case 9: + mtk_btif_exp_open_test(); + mtk_btif_exp_write_test(); + mtk_btif_exp_close_test(); + break; + case 0xa: + mtk_btif_exp_log_debug_test(y); + break; + case 0xb: + btif_tx_dma_mode_set(1); + btif_rx_dma_mode_set(1); + break; + case 0xc: + btif_tx_dma_mode_set(0); + btif_rx_dma_mode_set(0); + break; + case 0xd: + mtk_btif_exp_restore_noirq_test(); + break; + case 0xe: + btif_wakeup_consys_no_id(); + break; + case 0xf: + mtk_btif_exp_clock_ctrl(y); + break; + case 0x10: + y = y > G_MAX_PKG_LEN ? G_MAX_PKG_LEN : y; + y = y < 1024 ? 1024 : y; + BTIF_INFO_FUNC("g_max_pkg_len is set to %d\n", y); + g_max_pkg_len = y; + break; + case 0x11: + y = y > BTIF_RX_BUFFER_SIZE ? BTIF_RX_BUFFER_SIZE : y; + y = y < 1024 ? 1024 : y; + BTIF_INFO_FUNC("g_max_pding_data_size is set to %d\n", y); + g_max_pding_data_size = y; + break; + default: + mtk_btif_exp_open_test(); + mtk_btif_exp_write_stress_test(3030, 1); + mtk_btif_exp_close_test(); + BTIF_WARN_FUNC("not supported.\n"); + break; + } + + return count; +} + +static DEVICE_ATTR(flag, S_IRUGO | S_IWUSR, driver_flag_read, driver_flag_set); + +/*-----------End of platform bus related operation APIs------------*/ + +/*-----------------------platform driver ----------------*/ + +int _btif_irq_reg(P_MTK_BTIF_IRQ_STR p_irq, + mtk_btif_irq_handler irq_handler, void *data) +{ + int i_ret = -1; + unsigned int irq_id; + unsigned int flag; + + if ((p_irq == NULL) || (irq_handler == NULL)) + return E_BTIF_INVAL_PARAM; + + if (!(p_irq->is_irq_sup)) { + BTIF_WARN_FUNC("%s is not supported\n", p_irq->name); + return 0; + } + + irq_id = p_irq->irq_id; + +#ifdef CONFIG_OF + flag = p_irq->irq_flags; +#else + switch (p_irq->sens_type) { + case IRQ_SENS_EDGE: + if (p_irq->edge_type == IRQ_EDGE_FALL) + flag = IRQF_TRIGGER_FALLING; + else if (p_irq->edge_type == IRQ_EDGE_RAISE) + flag = IRQF_TRIGGER_RISING; + else if (p_irq->edge_type == IRQ_EDGE_BOTH) + flag = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; + else + /*make this as default type */ + flag = IRQF_TRIGGER_FALLING; + break; + case IRQ_SENS_LVL: + if (p_irq->lvl_type == IRQ_LVL_LOW) + flag = IRQF_TRIGGER_LOW; + else if (p_irq->lvl_type == IRQ_LVL_HIGH) + flag = IRQF_TRIGGER_HIGH; + else + /*make this as default type */ + flag = IRQF_TRIGGER_LOW; + break; + default: + /*make this as default type */ + flag = IRQF_TRIGGER_LOW; + break; + } +#endif + + p_irq->p_irq_handler = irq_handler; + i_ret = request_irq(irq_id, + (irq_handler_t) irq_handler, + flag, p_irq->name, data); + if (i_ret) + return i_ret; + + p_irq->reg_flag = true; + return 0; +} + +int _btif_irq_free(P_MTK_BTIF_IRQ_STR p_irq, void *data) +{ + int i_ret = 0; + unsigned int eint_num = p_irq->irq_id; + + if ((p_irq->is_irq_sup) && (p_irq->reg_flag)) { + _btif_irq_ctrl(p_irq, false); + free_irq(eint_num, data); + p_irq->reg_flag = false; + } +/*do nothing for this operation*/ + return i_ret; +} + +int _btif_irq_ctrl(P_MTK_BTIF_IRQ_STR p_irq, bool en) +{ + unsigned int eint_num = p_irq->irq_id; + + if (en) + enable_irq(eint_num); + else + disable_irq_nosync(eint_num); + + return 0; +} + +int _btif_irq_ctrl_sync(P_MTK_BTIF_IRQ_STR p_irq, bool en) +{ + unsigned int eint_num = p_irq->irq_id; + + if (en) + enable_irq(eint_num); + else + disable_irq(eint_num); + + return 0; +} + + +irqreturn_t btif_irq_handler(int irq, void *data) +{ +/*search BTIF? just use index 0*/ +/*Chaozhong: do we need lock here?*/ + + p_mtk_btif p_btif = (p_mtk_btif) data; /*&(g_btif[index]); */ + + BTIF_DBG_FUNC("++, p_btif(0x%p)\n", data); + + _btif_irq_ctrl(p_btif->p_btif_info->p_irq, false); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); +#endif + + hal_btif_irq_handler(p_btif->p_btif_info, NULL, 0); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); +#endif + + _btif_irq_ctrl(p_btif->p_btif_info->p_irq, true); + _btif_rx_btm_sched(p_btif); + + BTIF_DBG_FUNC("--\n"); + return IRQ_HANDLED; +} + +irqreturn_t btif_tx_dma_irq_handler(int irq, void *data) +{ +/*search BTIF? just use index 0*/ + + p_mtk_btif p_btif = (p_mtk_btif) data; /*&(g_btif[index]); */ + p_mtk_btif_dma p_tx_dma = p_btif->p_tx_dma; + P_MTK_DMA_INFO_STR p_dma_info = p_tx_dma->p_dma_info; + + BTIF_DBG_FUNC("++, p_btif(0x%p)\n", data); + _btif_irq_ctrl(p_dma_info->p_irq, false); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_ENABLE); +#endif + + hal_tx_dma_irq_handler(p_dma_info); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); +#endif + _btif_irq_ctrl(p_dma_info->p_irq, true); + BTIF_DBG_FUNC("--\n"); + return IRQ_HANDLED; +} + +irqreturn_t btif_rx_dma_irq_handler(int irq, void *data) +{ +/*search BTIF? just use index 0*/ + + p_mtk_btif p_btif = (p_mtk_btif) data; /*&(g_btif[index]); */ + p_mtk_btif_dma p_rx_dma = p_btif->p_rx_dma; + P_MTK_DMA_INFO_STR p_rx_dma_info = p_rx_dma->p_dma_info; + + BTIF_DBG_FUNC("++, p_btif(0x%p)\n", data); + + _btif_irq_ctrl(p_rx_dma_info->p_irq, false); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); + hal_btif_dma_clk_ctrl(p_rx_dma_info, CLK_OUT_ENABLE); +#endif + + hal_rx_dma_irq_handler(p_rx_dma_info, NULL, 0); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_dma_clk_ctrl(p_rx_dma_info, CLK_OUT_DISABLE); + hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); +#endif + + _btif_irq_ctrl(p_rx_dma_info->p_irq, true); + + _btif_rx_btm_sched(p_btif); + + BTIF_DBG_FUNC("--\n"); + + return IRQ_HANDLED; +} + +unsigned int btif_dma_rx_data_receiver(P_MTK_DMA_INFO_STR p_dma_info, + unsigned char *p_buf, + unsigned int buf_len) +{ + unsigned int index = 0; + p_mtk_btif p_btif = &(g_btif[index]); + +#if 0 + _btif_dump_memory("", p_buf, buf_len); +#endif + + btif_bbs_write(&(p_btif->btif_buf), p_buf, buf_len); +/*save DMA Rx packet here*/ + if (buf_len > 0) + btif_log_buf_dmp_in(&p_btif->rx_log, p_buf, buf_len); + + return 0; +} + +unsigned int btif_pio_rx_data_receiver(P_MTK_BTIF_INFO_STR p_btif_info, + unsigned char *p_buf, + unsigned int buf_len) +{ + unsigned int index = 0; + p_mtk_btif p_btif = &(g_btif[index]); + +#if 0 + _btif_dump_memory("", p_buf, buf_len); +#endif + btif_bbs_write(&(p_btif->btif_buf), p_buf, buf_len); + +/*save PIO Rx packet here*/ + if (buf_len > 0) + btif_log_buf_dmp_in(&p_btif->rx_log, p_buf, buf_len); + + return 0; +} + +bool btif_parser_wmt_evt(p_mtk_btif p_btif, + const char *sub_str, + unsigned int str_len) +{ + unsigned int data_cnt = 0; + unsigned int copy_cnt = 0; + char *local_buf = NULL; + bool b_ret = false; + p_btif_buf_str p_bbs = &(p_btif->btif_buf); + unsigned int wr_idx = p_bbs->wr_idx; + unsigned int rd_idx = p_bbs->rd_idx; + + data_cnt = copy_cnt = BBS_COUNT(p_bbs); + + if (data_cnt < str_len) { + BTIF_WARN_FUNC("there is not enough data for parser,need(%d),have(%d)\n", str_len, data_cnt); + return false; + } + BTIF_INFO_FUNC("data count in bbs buffer:%d,wr_idx(%d),rd_idx(%d)\n", data_cnt, wr_idx, rd_idx); + local_buf = vmalloc((data_cnt + 3) & ~0x3UL); + if (!local_buf) { + BTIF_WARN_FUNC("vmalloc memory fail\n"); + return false; + } + + if (wr_idx >= rd_idx) { + memcpy(local_buf, BBS_PTR(p_bbs, rd_idx), copy_cnt); + } else { + unsigned int tail_len = BBS_SIZE(p_bbs) - rd_idx; + + BTIF_INFO_FUNC("tail_Len(%d)\n", tail_len); + memcpy(local_buf, BBS_PTR(p_bbs, rd_idx), tail_len); + memcpy(local_buf + tail_len, BBS_PTR(p_bbs, 0), copy_cnt - tail_len); + } + + do { + int i = 0; + int j = 0; + int k = 0; + int d = 0; + + BTIF_INFO_FUNC("sub_str_len:%d\n", str_len); + for (i = 0; i < copy_cnt; i++) { + BTIF_DBG_FUNC("i:%d\n", i); + k = i; + while (1) { + if ((j >= str_len) || (k >= copy_cnt) || (sub_str[j++] != local_buf[k++])) + break; + } + + if (j == str_len) { + for (d = i; d < (str_len + i); d++) + BTIF_INFO_FUNC("0x%2x", local_buf[d]); + BTIF_INFO_FUNC("find sub str index:%d\n", i); + b_ret = true; + break; + } + if (j < str_len) + j = 0; + } + + } while (0); + + vfree(local_buf); + return b_ret; +} +int _btif_controller_tx_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif->tx_mode == BTIF_MODE_DMA) { + i_ret = _btif_tx_dma_setup(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_tx_dma_setup failed,i_ret(%d),", + "set tx to PIO mode\n", i_ret); + i_ret = _btif_tx_pio_setup(p_btif); + } + } else +/*enable Tx PIO mode*/ + i_ret = _btif_tx_pio_setup(p_btif); + + return i_ret; +} + +int _btif_controller_tx_free(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif->tx_mode == BTIF_MODE_DMA) { + i_ret = _btif_tx_dma_free(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_tx_dma_free failed, i_ret(%d)\n", + i_ret); + } + } else { +/*do nothing for Tx PIO mode*/ + } + return i_ret; +} + +int _btif_controller_rx_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif->rx_mode == BTIF_MODE_DMA) { + i_ret = _btif_rx_dma_setup(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_tx_dma_setup failed, i_ret(%d),", + "set tx to PIO mode\n", i_ret); + i_ret = _btif_rx_pio_setup(p_btif); + } + } else { +/*enable Tx PIO mode*/ + i_ret = _btif_rx_pio_setup(p_btif); + } + return i_ret; +} + +int _btif_controller_rx_free(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif->rx_mode == BTIF_MODE_DMA) { + i_ret = _btif_rx_dma_free(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_rx_dma_free failed, i_ret(%d)\n", + i_ret); + } + } else { +/*do nothing for Rx PIO mode*/ + } + return i_ret; +} + +int _btif_tx_pio_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + +/*set Tx to PIO mode*/ + p_btif->tx_mode = BTIF_MODE_PIO; +/*enable Tx PIO mode*/ + i_ret = hal_btif_tx_mode_ctrl(p_btif_info, BTIF_MODE_PIO); + return i_ret; +} + +int _btif_rx_pio_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + P_MTK_BTIF_IRQ_STR p_btif_irq = p_btif_info->p_irq; + + p_btif->rx_mode = BTIF_MODE_PIO; +/*Enable Rx IRQ*/ + _btif_irq_ctrl(p_btif_irq, true); +/*enable Rx PIO mode*/ + i_ret = hal_btif_rx_mode_ctrl(p_btif_info, BTIF_MODE_PIO); + return i_ret; +} + +int _btif_rx_dma_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + P_MTK_BTIF_INFO_STR p_btif_info = NULL; + P_MTK_BTIF_IRQ_STR p_btif_irq = NULL; + P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_rx_dma->p_dma_info; + + p_btif_info = p_btif->p_btif_info; + p_btif_irq = p_dma_info->p_irq; + +/*vFIFO reset*/ + hal_btif_vfifo_reset(p_dma_info); + + i_ret = hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_ENABLE); + if (i_ret) { + BTIF_ERR_FUNC("hal_btif_dma_clk_ctrl failed, i_ret(%d),", + "set rx to pio mode\n", i_ret); +/*DMA control failed set Rx to PIO mode*/ + return _btif_rx_pio_setup(p_btif); + } +/*hardware init*/ + hal_btif_dma_hw_init(p_dma_info); + + hal_btif_dma_rx_cb_reg(p_dma_info, + (dma_rx_buf_write) btif_dma_rx_data_receiver); + +/*DMA controller enable*/ + i_ret = hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_ENABLE); + if (i_ret) { + BTIF_ERR_FUNC("hal_btif_dma_ctrl failed, i_ret(%d),", + "set rx to pio mode\n", i_ret); + hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); +/*DMA control failed set Rx to PIO mode*/ + i_ret = _btif_rx_pio_setup(p_btif); + } else { +/*enable Rx DMA mode*/ + hal_btif_rx_mode_ctrl(p_btif_info, BTIF_MODE_DMA); + +/*DMA Rx IRQ register*/ + _btif_irq_reg(p_btif_irq, btif_rx_dma_irq_handler, p_btif); +#if 0 +/*Enable DMA Rx IRQ*/ + _btif_irq_ctrl(p_btif_irq, true); +#endif + BTIF_DBG_FUNC("succeed\n"); + } + return i_ret; +} + +int _btif_rx_dma_free(p_mtk_btif p_btif) +{ + P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_rx_dma->p_dma_info; + P_MTK_BTIF_IRQ_STR p_irq = p_btif->p_rx_dma->p_dma_info->p_irq; + + hal_btif_dma_rx_cb_reg(p_dma_info, (dma_rx_buf_write) NULL); + _btif_irq_free(p_irq, p_btif); +/*disable BTIF Rx DMA channel*/ + hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_DISABLE); +/*disable clock output*/ + return hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); +} + +int _btif_tx_dma_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_tx_dma->p_dma_info; + P_MTK_BTIF_IRQ_STR p_btif_irq = p_dma_info->p_irq; + +/*vFIFO reset*/ + hal_btif_vfifo_reset(p_dma_info); + + i_ret = hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_ENABLE); + if (i_ret) { + BTIF_ERR_FUNC("hal_btif_dma_clk_ctrl failed, i_ret(%d)\n", + i_ret); + return i_ret; + } +/*DMA controller setup*/ + hal_btif_dma_hw_init(p_dma_info); + +/*DMA HW Enable*/ + i_ret = hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_ENABLE); + if (i_ret) { + BTIF_ERR_FUNC("hal_btif_dma_ctrl failed, i_ret(%d),", + "set tx to pio mode\n", i_ret); + +#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) + hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); +#endif + + _btif_tx_pio_setup(p_btif); + } else { + hal_btif_tx_mode_ctrl(p_btif_info, BTIF_MODE_DMA); +/*DMA Tx IRQ register*/ + _btif_irq_reg(p_btif_irq, btif_tx_dma_irq_handler, p_btif); +#if 0 +/*disable DMA Tx IRQ*/ + _btif_irq_ctrl(p_btif_irq, false); +#endif + + BTIF_DBG_FUNC("succeed\n"); + } + return i_ret; +} + +int _btif_tx_dma_free(p_mtk_btif p_btif) +{ + P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_tx_dma->p_dma_info; + P_MTK_BTIF_IRQ_STR p_irq = p_btif->p_tx_dma->p_dma_info->p_irq; + + _btif_irq_free(p_irq, p_btif); +/*disable BTIF Tx DMA channel*/ + hal_btif_dma_ctrl(p_dma_info, DMA_CTRL_DISABLE); +/*disable clock output*/ + return hal_btif_dma_clk_ctrl(p_dma_info, CLK_OUT_DISABLE); +} + +int btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag) +{ + int i_ret = -1; + +/*hold state mechine lock*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; +#if 0 + state = _btif_state_get(p_btif); + if (p_btif->enable && B_S_ON == state) + i_ret = _btif_lpbk_ctrl(p_btif, flag); + else + i_ret = E_BTIF_INVAL_STATE; +#endif + i_ret = _btif_exit_dpidle(p_btif); + if (i_ret == 0) + i_ret = _btif_lpbk_ctrl(p_btif, flag); + else + i_ret = E_BTIF_INVAL_STATE; + + BTIF_STATE_RELEASE(p_btif); + return i_ret; +} + +int _btif_lpbk_ctrl(p_mtk_btif p_btif, bool flag) +{ + int i_ret = -1; + + if (flag) { + i_ret = hal_btif_loopback_ctrl(p_btif->p_btif_info, true); + BTIF_DBG_FUNC("loopback function enabled\n"); + } else { + i_ret = hal_btif_loopback_ctrl(p_btif->p_btif_info, false); + BTIF_DBG_FUNC("loopback function disabled\n"); + } + if (i_ret == 0) + p_btif->lpbk_flag = flag; + + return i_ret; +} + +int btif_clock_ctrl(p_mtk_btif p_btif, int en) +{ + int i_ret = 0; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + ENUM_CLOCK_CTRL ctrl_flag = en == 0 ? CLK_OUT_DISABLE : CLK_OUT_ENABLE; + + i_ret = hal_btif_clk_ctrl(p_btif_info, ctrl_flag); + + if (p_btif->rx_mode == BTIF_MODE_DMA) + i_ret += hal_btif_dma_clk_ctrl(p_btif->p_rx_dma->p_dma_info, ctrl_flag); + + if (p_btif->tx_mode == BTIF_MODE_DMA) + i_ret += hal_btif_dma_clk_ctrl(p_btif->p_tx_dma->p_dma_info, ctrl_flag); + + return i_ret; +} + +int _btif_controller_setup(p_mtk_btif p_btif) +{ + int i_ret = -1; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + P_MTK_BTIF_IRQ_STR p_btif_irq = p_btif_info->p_irq; + +/*BTIF rx buffer init*/ +/* memset(p_btif->rx_buf, 0, BTIF_RX_BUFFER_SIZE); */ + BBS_INIT(&(p_btif->btif_buf)); +/************************************************/ + hal_btif_rx_cb_reg(p_btif_info, + (btif_rx_buf_write) btif_pio_rx_data_receiver); + + i_ret = hal_btif_clk_ctrl(p_btif_info, CLK_OUT_ENABLE); + if (i_ret) { + BTIF_ERR_FUNC("hal_btif_clk_ctrl failed, i_ret(%d)\n", i_ret); + return i_ret; + } +/*BTIF controller init*/ + i_ret = hal_btif_hw_init(p_btif_info); + if (i_ret) { + hal_btif_clk_ctrl(p_btif_info, CLK_OUT_DISABLE); + BTIF_ERR_FUNC("hal_btif_hw_init failed, i_ret(%d)\n", i_ret); + return i_ret; + } + _btif_lpbk_ctrl(p_btif, p_btif->lpbk_flag); +/*BTIF IRQ register*/ + i_ret = _btif_irq_reg(p_btif_irq, btif_irq_handler, p_btif); + if (i_ret) { + hal_btif_clk_ctrl(p_btif_info, CLK_OUT_DISABLE); + + BTIF_ERR_FUNC("_btif_irq_reg failed, i_ret(%d)\n", i_ret); + return i_ret; + } + +/*disable IRQ*/ + _btif_irq_ctrl(p_btif_irq, false); + i_ret = 0; + BTIF_DBG_FUNC("succeed\n"); + return i_ret; +} + +int _btif_controller_free(p_mtk_btif p_btif) +{ +/*No need to set BTIF to PIO mode, only enable BTIF CG*/ + hal_btif_rx_cb_reg(p_btif->p_btif_info, (btif_rx_buf_write) NULL); + _btif_irq_free(p_btif->p_btif_info->p_irq, p_btif); + return hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); +} + +int _btif_init(p_mtk_btif p_btif) +{ + int i_ret = 0; + + i_ret = _btif_controller_setup(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_controller_init failed, i_ret(%d)\n", + i_ret); + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); + BTIF_STATE_RELEASE(p_btif); + return i_ret; + } + + i_ret = _btif_controller_tx_setup(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_controller_tx_setup failed, i_ret(%d)\n", + i_ret); + _btif_controller_free(p_btif); + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); + BTIF_STATE_RELEASE(p_btif); + return i_ret; + } + + i_ret = _btif_controller_rx_setup(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("_btif_controller_tx_setup failed, i_ret(%d)\n", + i_ret); + _btif_controller_tx_free(p_btif); + _btif_controller_free(p_btif); + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); + BTIF_STATE_RELEASE(p_btif); + return i_ret; + } + return i_ret; +} + +int btif_open(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif->enable) + return E_BTIF_ALREADY_OPEN; + +/*hold state mechine lock*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; +/*disable deepidle*/ + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_DISABLE); + + i_ret = _btif_init(p_btif); + if (i_ret == 0) { + /*set BTIF's enable flag*/ + p_btif->enable = true; + _btif_state_set(p_btif, B_S_ON); + } else { + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); + } + btif_log_buf_reset(&p_btif->tx_log); + btif_log_buf_reset(&p_btif->rx_log); + + BTIF_STATE_RELEASE(p_btif); + + BTIF_DBG_FUNC("BTIF's Tx Mode:%d, Rx Mode(%d)\n", + p_btif->tx_mode, p_btif->rx_mode); + return i_ret; +} + +int btif_close(p_mtk_btif p_btif) +{ + int i_ret = 0; + + if (!(p_btif->enable)) + return E_BTIF_NOT_OPEN; + +/*hold state mechine lock*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; +/*always set state back to B_S_ON before do close operation*/ + _btif_exit_dpidle(p_btif); +/*set BTIF's state to disable state*/ + p_btif->enable = false; + + _btif_controller_free(p_btif); + _btif_controller_tx_free(p_btif); + _btif_controller_rx_free(p_btif); + +/*reset BTIF's rx_cb function*/ + p_btif->rx_cb = NULL; + p_btif->rx_notify = NULL; + p_btif->lpbk_flag = false; + +/*set state mechine to B_S_OFF*/ + _btif_state_set(p_btif, B_S_OFF); + + btif_log_buf_disable(&p_btif->tx_log); + btif_log_buf_disable(&p_btif->rx_log); + + BTIF_STATE_RELEASE(p_btif); + + return i_ret; +} + +int _btif_exit_dpidle(p_mtk_btif p_btif) +{ + int i_ret = -1; + ENUM_BTIF_STATE state = B_S_MAX; + + state = _btif_state_get(p_btif); + switch (state) { + case B_S_DPIDLE: + i_ret = _btif_exit_dpidle_from_dpidle(p_btif); + break; + case B_S_SUSPEND: +/*in suspend state, need to do reinit of btif*/ + i_ret = _btif_exit_dpidle_from_sus(p_btif); + break; + case B_S_OFF: + i_ret = _btif_init(p_btif); + break; + case B_S_ON: + i_ret = 0; /* for btif_close case */ + break; + default: + i_ret = E_BTIF_INVAL_PARAM; + BTIF_INFO_FUNC("invalid state change:%d->\n", state, B_S_ON); + break; + } + + if (i_ret == 0) + i_ret = _btif_state_set(p_btif, B_S_ON); + return i_ret; +} + +int btif_exit_dpidle(p_mtk_btif p_btif) +{ + int i_ret = 0; + +/*hold state mechine lock*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + i_ret = _btif_exit_dpidle(p_btif); + BTIF_STATE_RELEASE(p_btif); + return i_ret; +} + +int _btif_enter_dpidle(p_mtk_btif p_btif) +{ + int i_ret = 0; + ENUM_BTIF_STATE state = B_S_MAX; + + state = _btif_state_get(p_btif); + if (state == B_S_ON) { + i_ret = _btif_enter_dpidle_from_on(p_btif); + } else if (state == B_S_SUSPEND) { + /*do reinit and enter deepidle*/ + i_ret = _btif_enter_dpidle_from_sus(p_btif); + } else if (state == B_S_DPIDLE) { + /*do nothing*/ + i_ret = 0; + } else { + BTIF_WARN_FUNC("operation is not allowed, current state:%d\n", + state); + i_ret = E_BTIF_INVAL_STATE; + } +/*anyway, set to B_S_DPIDLE state*/ + if (i_ret == 0) + i_ret = _btif_state_set(p_btif, B_S_DPIDLE); + return i_ret; +} + +int btif_enter_dpidle(p_mtk_btif p_btif) +{ + int i_ret = 0; + +/*hold state mechine lock*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + i_ret = _btif_enter_dpidle(p_btif); + BTIF_STATE_RELEASE(p_btif); + return i_ret; +} + +int _btif_exit_dpidle_from_dpidle(p_mtk_btif p_btif) +{ + int i_ret = 0; + +/*in dpidle state, only need to open related clock*/ + if (p_btif->tx_mode == BTIF_MODE_DMA) { + /*enable BTIF Tx DMA's clock*/ + i_ret += hal_btif_dma_clk_ctrl(p_btif->p_tx_dma->p_dma_info, + CLK_OUT_ENABLE); + } + if (p_btif->rx_mode == BTIF_MODE_DMA) { + /*enable BTIF Rx DMA's clock*/ + i_ret += hal_btif_dma_clk_ctrl(p_btif->p_rx_dma->p_dma_info, + CLK_OUT_ENABLE); + } +/*enable BTIF's clock*/ + i_ret += hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); + + if (i_ret != 0) + BTIF_WARN_FUNC("failed, i_ret:%d\n", i_ret); + return i_ret; +} + +int _btif_exit_dpidle_from_sus(p_mtk_btif p_btif) +{ +/*in suspend state, need to do driver re-init*/ + + int i_ret = _btif_init(p_btif); + + return i_ret; +} + +int _btif_enter_dpidle_from_sus(p_mtk_btif p_btif) +{ +/*do driiver reinit*/ + int i_ret = _btif_init(p_btif); + + if (i_ret == 0) + i_ret = _btif_enter_dpidle_from_on(p_btif); + return i_ret; +} + +int _btif_enter_dpidle_from_on(p_mtk_btif p_btif) +{ +#define MAX_WAIT_TIME_MS 5000 +/* + * this max wait time cannot exceed 12s, + * because dpm will monitor each device's + * resume/suspend process by start up a watch dog timer of 12s + * incase of one driver's suspend/resume process block other device's suspend/resume + */ + int i_ret = 0; + unsigned int retry = 0; + unsigned int wait_period = 1; + unsigned int max_retry = MAX_WAIT_TIME_MS / wait_period; + struct timespec64 timer_start; + struct timespec64 timer_now; + + ktime_get_ts64(&timer_start); + + while ((!_btif_is_tx_complete(p_btif)) && (retry < max_retry)) { + ktime_get_ts64(&timer_now); + if ((MAX_WAIT_TIME_MS/1000) <= (timer_now.tv_sec - timer_start.tv_sec)) { + BTIF_WARN_FUNC("max retry timer expired, timer_start.tv_sec:%d, timer_now.tv_sec:%d,", + "retry:%d\n", timer_start.tv_sec, timer_now.tv_sec, retry); + break; + } + msleep(wait_period); + retry++; + } + + if (retry < max_retry) { + if (p_btif->tx_mode == BTIF_MODE_DMA) { + /*disable BTIF Tx DMA's clock*/ + i_ret += + hal_btif_dma_clk_ctrl(p_btif->p_tx_dma->p_dma_info, + CLK_OUT_DISABLE); + } + if (p_btif->rx_mode == BTIF_MODE_DMA) { + /*disable BTIF Rx DMA's clock*/ + i_ret += + hal_btif_dma_clk_ctrl(p_btif->p_rx_dma->p_dma_info, + CLK_OUT_DISABLE); + } +/*disable BTIF's clock*/ + i_ret += + hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_DISABLE); + + if (i_ret) + BTIF_WARN_FUNC("failed, i_ret:%d\n", i_ret); + } else + i_ret = -1; + + return i_ret; +} + +int _btif_dpidle_notify_ctrl(p_mtk_btif p_btif, ENUM_BTIF_DPIDLE_CTRL en_flag) +{ +/*call WCP's API to control deepidle's enable/disable*/ + if (en_flag == BTIF_DPIDLE_DISABLE) + hal_btif_pm_ops(p_btif->p_btif_info, BTIF_PM_DPIDLE_DIS); + else + hal_btif_pm_ops(p_btif->p_btif_info, BTIF_PM_DPIDLE_EN); + + return 0; +} + +int btif_rx_cb_reg(p_mtk_btif p_btif, MTK_WCN_BTIF_RX_CB rx_cb) +{ + if (p_btif->rx_cb) { + BTIF_WARN_FUNC + ("rx cb already exist, rewrite from (0x%p) to (0x%p)\n", + p_btif->rx_cb, rx_cb); + } + p_btif->rx_cb = rx_cb; + + return 0; +} + +int btif_raise_wak_signal(p_mtk_btif p_btif) +{ + int i_ret = 0; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_clk_ctrl(p_btif->p_btif_info, CLK_OUT_ENABLE); +#endif + + i_ret = hal_btif_raise_wak_sig(p_btif_info); + +#if MTK_BTIF_ENABLE_CLK_REF_COUNTER + hal_btif_clk_ctrl(p_btif_info, CLK_OUT_DISABLE); +#endif + return i_ret; +} + +bool _btif_is_tx_complete(p_mtk_btif p_btif) +{ + bool b_ret = false; + ENUM_BTIF_MODE tx_mode = p_btif->tx_mode; + +/* + * make sure BTIF tx finished in PIO mode + * make sure BTIF tx finished and DMA tx finished in DMA mode + */ + if (tx_mode == BTIF_MODE_DMA) { + b_ret = hal_dma_is_tx_complete(p_btif->p_tx_dma->p_dma_info); + if (b_ret == false) { + BTIF_DBG_FUNC("Tx DMA is not finished\n"); + return b_ret; + } + } + + b_ret = hal_btif_is_tx_complete(p_btif->p_btif_info); + if (b_ret == false) { + BTIF_DBG_FUNC("BTIF Tx is not finished\n"); + return b_ret; + } + b_ret = true; + return b_ret; +} + +/*--------------------------------Functions-------------------------------------------*/ + +#if ENABLE_BTIF_TX_DMA +static int _btif_vfifo_init(p_mtk_btif_dma p_dma) +{ + P_DMA_VFIFO p_vfifo = NULL; + struct device *dev = NULL; + p_mtk_btif p_btif = NULL; + + if (p_dma == NULL) { + BTIF_ERR_FUNC("p_dma is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + + p_btif = (p_mtk_btif)p_dma->p_btif; + + if (p_btif == NULL) { + BTIF_ERR_FUNC("invalid parameter: p_btif(0x%p)\n", p_btif); + return E_BTIF_INVAL_PARAM; + } + + dev = (struct device *)p_btif->private_data; + if (dev == NULL) + BTIF_WARN_FUNC("Null dev pointer!!!!\n"); + + p_vfifo = p_dma->p_dma_info->p_vfifo; + if (p_vfifo->p_vir_addr != NULL) { + BTIF_ERR_FUNC + ("BTIF vFIFO memory already allocated, do nothing\n"); + return E_BTIF_BAD_POINTER; + } + +/*vFIFO memory allocation*/ + p_vfifo->p_vir_addr = dma_alloc_coherent(dev, + p_vfifo->vfifo_size, + &p_vfifo->phy_addr, GFP_DMA | GFP_DMA32); + if (p_vfifo->p_vir_addr == NULL) { + BTIF_ERR_FUNC("alloc vFIFO memory for BTIF failed\n"); + return E_BTIF_FAIL; + } + + if (sizeof(dma_addr_t) == sizeof(unsigned long long)) + BTIF_INFO_FUNC("alloc vFIFO for BTIF succeed in arch64,vir addr:0x%p,", + "phy addr:0x%llx\n", p_vfifo->p_vir_addr, p_vfifo->phy_addr); + else + BTIF_INFO_FUNC("alloc vFIFO for BTIF succeed in arch32,vir addr:0x%p,", + "phy addr:0x%08x\n", p_vfifo->p_vir_addr, p_vfifo->phy_addr); + + return 0; +} +#endif +#if ENABLE_BTIF_TX_DMA +static int _btif_vfifo_deinit(p_mtk_btif_dma p_dma) +{ + P_DMA_VFIFO p_vfifo = NULL; + struct device *dev = NULL; + p_mtk_btif p_btif = NULL; + + if (p_dma == NULL) { + BTIF_ERR_FUNC("p_dma is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + + + p_btif = (p_mtk_btif)p_dma->p_btif; + if (p_btif == NULL) { + BTIF_ERR_FUNC("invalid parameter: p_btif(0x%p)\n", p_btif); + return E_BTIF_INVAL_PARAM; + } + + dev = (struct device *)p_btif->private_data; + if (dev == NULL) + BTIF_WARN_FUNC("Null dev pointer!!!!\n"); + + p_vfifo = p_dma->p_dma_info->p_vfifo; + +/*free DMA memory if allocated successfully before*/ + if (p_vfifo->p_vir_addr != NULL) { + dma_free_coherent(dev, + p_vfifo->vfifo_size, + p_vfifo->p_vir_addr, p_vfifo->phy_addr); + p_vfifo->p_vir_addr = NULL; + } + + return 0; +} +#endif + +static int _btif_state_init(p_mtk_btif p_btif) +{ + if (p_btif == NULL) { + BTIF_ERR_FUNC("p_btif is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + p_btif->state = B_S_OFF; + mutex_init(&(p_btif->state_mtx)); + + return 0; +} + +static int _btif_state_hold(p_mtk_btif p_btif) +{ + return mutex_lock_killable(&(p_btif->state_mtx)); +} + +static int _btif_state_set(p_mtk_btif p_btif, ENUM_BTIF_STATE state) +{ +/*chaozhong: To do: need to finished state mechine here*/ + int i_ret = 0; + int ori_state = p_btif->state; + + if (ori_state == state) { + BTIF_INFO_FUNC("already in %s state\n", g_state[state]); + return i_ret; + } + if ((state >= B_S_OFF) && (state < B_S_MAX)) { + BTIF_DBG_FUNC("%s->%s request\n", g_state[ori_state], + g_state[state]); + if (state == B_S_ON) + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_DISABLE); + switch (ori_state) { + case B_S_ON: +/*B_S_ON can only be switched to B_S_OFF, B_S_SUSPEND and B_S_DPIDLE*/ +/*B_S_ON->B_S_OFF : do nothing here*/ +/* + * B_S_ON->B_S_DPLE : disable clock backup + * BTIF and DMA controller's register if necessary + */ + if (state == B_S_DPIDLE) { + /*clock controlled id done in _btif_enter_dpidle*/ + p_btif->state = state; + i_ret = 0; + } else if (state == B_S_OFF) { + /*clock controlled is done in btif_close*/ + p_btif->state = state; + i_ret = 0; + } else if (state == B_S_SUSPEND) { + /*clock controlled is done in btif_close*/ + p_btif->state = state; + i_ret = 0; + } else { + BTIF_ERR_FUNC("%s->%s is not allowed\n", + g_state[ori_state], + g_state[state]); + i_ret = E_BTIF_INVAL_STATE; + } + break; + case B_S_DPIDLE: +/*B_S_DPIDLE can only be switched to B_S_ON and B_S_SUSPEND*/ +/*B_S_DPIDLE-> B_S_ON: do nothing for this moment*/ +/* + * B_S_DPIDLE-> B_S_SUSPEND: + * disable clock backup BTIF and DMA controller's register if necessary + */ + if (state == B_S_ON) { + /*clock controlled id done in _btif_exit_dpidle*/ + p_btif->state = state; + i_ret = 0; + } else if (state == B_S_SUSPEND) { + /*clock controlled is done in _btif_exit_dpidle*/ + p_btif->state = state; + i_ret = 0; + } else { + BTIF_ERR_FUNC("%s->%s is not allowed\n", + g_state[ori_state], + g_state[state]); + i_ret = E_BTIF_INVAL_STATE; + } + break; + + case B_S_SUSPEND: +/*B_S_SUSPEND can be switched to B_S_IDLE and B_S_ON*/ +/*reinit BTIF controller and DMA controller*/ + if (state == B_S_DPIDLE) { + /* + * system call resume API, do resume operation, + * change to deepidle state + */ + p_btif->state = state; + i_ret = 0; + } else if (state == B_S_ON) { + /* + * when stp want to send data before + * system do resume operation + */ + p_btif->state = state; + i_ret = 0; + } else { + BTIF_ERR_FUNC("%s->%s is not allowed\n", + g_state[ori_state], + g_state[state]); + i_ret = E_BTIF_INVAL_STATE; + } + break; + + case B_S_OFF:{ +/*B_S_OFF can only be switched to B_S_ON*/ + if (state == B_S_ON) { + /*clock controlled is done in btif_open*/ + p_btif->state = state; + i_ret = 0; + } else { + BTIF_ERR_FUNC("%s->%s is not allowed\n", + g_state[ori_state], + g_state[state]); + i_ret = E_BTIF_INVAL_STATE; + } + } + break; + default: +/*no this possibility*/ + BTIF_ERR_FUNC + ("state change request is not allowed, this should never happen\n"); + break; + } + + if (state != B_S_ON) + _btif_dpidle_notify_ctrl(p_btif, BTIF_DPIDLE_ENABLE); + + } else { + i_ret = E_BTIF_INVAL_PARAM; + BTIF_ERR_FUNC("invalid state:%d, do nothing\n", state); + } + return i_ret; +} + +static ENUM_BTIF_STATE _btif_state_get(p_mtk_btif p_btif) +{ + return p_btif->state; +} + +static int _btif_state_release(p_mtk_btif p_btif) +{ + int i_ret = 0; + + BTIF_MUTEX_UNLOCK(&(p_btif->state_mtx)); + return i_ret; +} + +static int _btif_state_deinit(p_mtk_btif p_btif) +{ + if (p_btif == NULL) { + BTIF_ERR_FUNC("p_btif is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + p_btif->state = B_S_OFF; + mutex_destroy(&(p_btif->state_mtx)); + + return 0; +} + +static int btif_rx_data_consummer(p_mtk_btif p_btif) +{ + unsigned int length = 0; + unsigned char *p_buf = NULL; +/*get BTIF rx buffer's information*/ + p_btif_buf_str p_bbs = &(p_btif->btif_buf); +/* + * wr_idx of btif_buf may be modified in IRQ handler, + * in order not to be effected by case in which irq interrupt this operation, + * we record wr_idx here + */ + unsigned int wr_idx = p_bbs->wr_idx; + + length = BBS_COUNT_CUR(p_bbs, wr_idx); + +/*make sure length of rx buffer data > 0*/ + do { + if (length > 0) { + /* + * check if rx_cb empty or not, if registered , + * call user's rx callback to handle these data + */ + if (p_btif->rx_cb) { + if (p_bbs->rd_idx <= wr_idx) { + p_buf = BBS_PTR(p_bbs, p_bbs->rd_idx); + /* p_buf = &(p_bbs->buf[p_bbs->rd_idx]); */ + /* length = BBS_COUNT(p_bbs); */ + length = (wr_idx >= (p_bbs)->rd_idx) ? + (wr_idx - (p_bbs)->rd_idx) : + BBS_SIZE(p_bbs) - + ((p_bbs)->rd_idx - wr_idx); + if (p_btif->rx_cb) + (*(p_btif->rx_cb)) (p_buf, length); + else + BTIF_ERR_FUNC("p_btif->rx_cb is NULL\n"); + /*update rx data read index*/ + p_bbs->rd_idx = wr_idx; + } else { + unsigned int len_tail = + BBS_SIZE(p_bbs) - (p_bbs)->rd_idx; + /*p_buf = &(p_bbs->buf[p_bbs->->rd_idx]);*/ + p_buf = BBS_PTR(p_bbs, p_bbs->rd_idx); + if (p_btif->rx_cb) + (*(p_btif->rx_cb)) (p_buf, len_tail); + else + BTIF_ERR_FUNC("p_btif->rx_cb is NULL\n"); + length = BBS_COUNT_CUR(p_bbs, wr_idx); + length -= len_tail; + /*p_buf = &(p_bbs->buf[0]);*/ + p_buf = BBS_PTR(p_bbs, 0); + if (p_btif->rx_cb) + (*(p_btif->rx_cb)) (p_buf, length); + else + BTIF_ERR_FUNC("p_btif->rx_cb is NULL\n"); + /*update rx data read index*/ + p_bbs->rd_idx = wr_idx; + } + } else if (p_btif->rx_notify != NULL) { + (*p_btif->rx_notify) (); + } else { + BTIF_WARN_FUNC + ("p_btif:0x%p, both rx_notify and rx_cb are NULL\n", + p_btif); + break; + } + } else { + BTIF_DBG_FUNC("length:%d\n", length); + break; + } + wr_idx = p_bbs->wr_idx; + length = BBS_COUNT_CUR(p_bbs, wr_idx); + } while (1); + return length; +} + +#if BTIF_RXD_BE_BLOCKED_DETECT +static int mtk_btif_rxd_be_blocked_by_timer(void) +{ + int ret = 0; + int counter = 0; + unsigned int i; + struct timespec64 now; + int time_gap[MAX_BTIF_RXD_TIME_REC]; + + ktime_get_ts64(&now); + + for (i = 0; i < MAX_BTIF_RXD_TIME_REC; i++) { + BTIF_INFO_FUNC("btif_rxd_time_stamp[%d]=%d.%d\n", i, + btif_rxd_time_stamp[i].tv_sec, btif_rxd_time_stamp[i].tv_nsec / NSEC_PER_USEC); + if (now.tv_sec >= btif_rxd_time_stamp[i].tv_sec) { + time_gap[i] = now.tv_sec - btif_rxd_time_stamp[i].tv_sec; + time_gap[i] *= 1000000; /*second*/ + if (now.tv_nsec >= btif_rxd_time_stamp[i].tv_nsec) + time_gap[i] += (now.tv_nsec - btif_rxd_time_stamp[i].tv_nsec) / NSEC_PER_USEC; + else + time_gap[i] += 1000000 - (now.tv_nsec - btif_rxd_time_stamp[i].tv_nsec) / NSEC_PER_USEC; + + if (time_gap[i] > 1000000) + counter++; + BTIF_INFO_FUNC("time_gap[%d]=%d,counter:%d\n", i, time_gap[i], counter); + } else { + time_gap[i] = 0; + BTIF_ERR_FUNC("abnormal case now:%d < time_stamp[%d]:%d\n", now.tv_sec, + i, btif_rxd_time_stamp[i].tv_nsec / NSEC_PER_USEC); + } + } + if (counter > (MAX_BTIF_RXD_TIME_REC - 2)) + ret = 1; + return ret; +} +static int mtk_btif_rxd_be_blocked_by_data(void) +{ + unsigned int out_index = 0; + unsigned int in_index = 0; + unsigned int dump_size = 0; + unsigned int len = 0; + unsigned long flags; + unsigned int sync_pkt_n = 0; + P_BTIF_LOG_BUF_T p_log_buf = NULL; + P_BTIF_LOG_QUEUE_T p_log_que = NULL; + p_mtk_btif p_btif = &(g_btif[0]); + + p_log_que = &p_btif->rx_log; + spin_lock_irqsave(&p_log_que->lock, flags); + in_index = p_log_que->in; + dump_size = p_log_que->size; + out_index = p_log_que->size >= + BTIF_LOG_ENTRY_NUM ? in_index : (BTIF_LOG_ENTRY_NUM - + p_log_que->size + + in_index) % BTIF_LOG_ENTRY_NUM; + if (dump_size != 0) { + while (dump_size--) { + p_log_buf = p_log_que->p_queue[0] + out_index; + len = p_log_buf->len; + if (len > BTIF_LOG_SZ) + len = BTIF_LOG_SZ; + if ((0x7f == *(p_log_buf->buffer)) && (0x7f == *(p_log_buf->buffer + 1))) { + sync_pkt_n++; + BTIF_INFO_FUNC("tx pkt_count:%d is sync pkt\n", out_index); + } + out_index++; + out_index %= BTIF_LOG_ENTRY_NUM; + } + } + if (sync_pkt_n == 0) + BTIF_ERR_FUNC("there is no sync pkt in BTIF buffer\n"); + else + BTIF_ERR_FUNC("there are %d sync pkt in BTIF buffer\n", sync_pkt_n); + spin_unlock_irqrestore(&p_log_que->lock, flags); + return sync_pkt_n; +} + +int mtk_btif_rxd_be_blocked_flag_get(void) +{ + int ret = 0; + int condition1 = 0, condition2 = 0; + + condition1 = mtk_btif_rxd_be_blocked_by_timer(); + condition2 = mtk_btif_rxd_be_blocked_by_data(); + if (condition1 && condition2) { + BTIF_ERR_FUNC("btif_rxd thread be blocked too long!\n"); + ret = 1; + } + return ret; +} +#endif +static int btif_rx_thread(void *p_data) +{ +#if BTIF_RXD_BE_BLOCKED_DETECT + unsigned int i = 0; +#endif + p_mtk_btif p_btif = (p_mtk_btif)p_data; + + + while (1) { + wait_for_completion_interruptible(&p_btif->rx_comp); + + if (kthread_should_stop()) { + BTIF_WARN_FUNC("btif rx thread stoping ...\n"); + break; + } +#ifdef BTIF_RXD_BE_BLOCKED_DETECT + ktime_get_ts64(&btif_rxd_time_stamp[i]); + i++; + if (i >= MAX_BTIF_RXD_TIME_REC) + i = 0; +#endif + btif_rx_data_consummer(p_btif); + } + return 0; +} + +static void btif_rx_worker(struct work_struct *p_work) +{ +/*get mtk_btif's pointer*/ + p_mtk_btif p_btif = container_of(p_work, mtk_btif, rx_work); + + BTIF_DBG_FUNC("p_btif:0x%p\n", p_btif); +/*lock rx_mutex*/ + + if (mutex_lock_killable(&(p_btif->rx_mtx))) { + BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); + return; + } + btif_rx_data_consummer(p_btif); + BTIF_MUTEX_UNLOCK(&(p_btif->rx_mtx)); +} + +static void btif_tx_worker(struct work_struct *p_work) +{ + int i_ret = 0; + int leng_sent = 0; +/*tx fifo out*/ + int how_much_get = 0; + unsigned char local_buf[384]; + +/*get mtk_btif's pointer*/ + p_mtk_btif p_btif = container_of(p_work, mtk_btif, tx_work); + + BTIF_DBG_FUNC("p_btif:0x%p\n", p_btif); + + if (mutex_lock_killable(&(p_btif->tx_mtx))) { + BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); + return; + } + how_much_get = + kfifo_out(p_btif->p_tx_fifo, local_buf, sizeof(local_buf)); + do { + while (leng_sent < how_much_get) { + i_ret = _btif_send_data(p_btif, + local_buf + leng_sent, + how_much_get - leng_sent); + if (i_ret > 0) { + leng_sent += i_ret; + } else if (i_ret == 0) { + BTIF_WARN_FUNC + ("_btif_send_data return 0, retry\n"); + } else { + BTIF_WARN_FUNC + ("btif send data fail,reset tx fifo, i_ret(%d)\n", + i_ret); + kfifo_reset(p_btif->p_tx_fifo); + break; + } + } + how_much_get = + kfifo_out(p_btif->p_tx_fifo, local_buf, sizeof(local_buf)); + leng_sent = 0; + } while (how_much_get > 0); + BTIF_MUTEX_UNLOCK(&(p_btif->tx_mtx)); +} + +static void btif_rx_tasklet(unsigned long func_data) +{ + unsigned long flags; +/*get mtk_btif's pointer*/ + p_mtk_btif p_btif = (p_mtk_btif) func_data; + + BTIF_DBG_FUNC("p_btif:0x%p\n", p_btif); +/*lock rx_spinlock*/ + spin_lock_irqsave(&p_btif->rx_tasklet_spinlock, flags); + btif_rx_data_consummer(p_btif); + spin_unlock_irqrestore(&p_btif->rx_tasklet_spinlock, flags); +} + +static int _btif_tx_ctx_init(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif == NULL) { + BTIF_ERR_FUNC("p_btif is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + + if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { + p_btif->p_tx_wq = create_singlethread_workqueue("btif_txd"); + + if (!(p_btif->p_tx_wq)) { + BTIF_ERR_FUNC + ("create_singlethread_workqueue for tx thread fail\n"); + i_ret = -ENOMEM; + goto btm_init_err; + } + mutex_init(&(p_btif->tx_mtx)); +/* init btif tx work */ + INIT_WORK(&(p_btif->tx_work), btif_tx_worker); + BTIF_INFO_FUNC("btif_tx_worker init succeed\n"); + + p_btif->p_tx_fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC); + if (p_btif->p_tx_fifo == NULL) { + i_ret = -ENOMEM; + BTIF_ERR_FUNC("kzalloc for p_btif->p_tx_fifo failed\n"); + goto btm_init_err; + } + + i_ret = kfifo_alloc(p_btif->p_tx_fifo, + BTIF_TX_FIFO_SIZE, GFP_ATOMIC); + if (i_ret != 0) { + BTIF_ERR_FUNC("kfifo_alloc failed, errno(%d)\n", i_ret); + i_ret = -ENOMEM; + goto btm_init_err; + } + } else if (p_btif->tx_ctx == BTIF_TX_USER_CTX) { + BTIF_INFO_FUNC + ("nothing is done when btif tx in user's thread\n"); + } else { + BTIF_ERR_FUNC("unsupported tx context type:%d\n", + p_btif->tx_ctx); + goto btm_init_err; + } + + BTIF_INFO_FUNC("succeed\n"); + + i_ret = 0; + return i_ret; +btm_init_err: + if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { + if (p_btif->p_tx_wq) { + destroy_workqueue(p_btif->p_tx_wq); + p_btif->p_tx_wq = NULL; + BTIF_INFO_FUNC("btif_tx_workqueue destroyed\n"); + } + kfree(p_btif->p_tx_fifo); + } + return i_ret; +} + +static int _btif_tx_ctx_deinit(p_mtk_btif p_btif) +{ + int i_ret = 0; + + if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { + if (p_btif->p_tx_wq) { + destroy_workqueue(p_btif->p_tx_wq); + p_btif->p_tx_wq = NULL; + BTIF_INFO_FUNC("btif_tx_workqueue destroyed\n"); + } + if (p_btif->p_tx_fifo) { + kfifo_free(p_btif->p_tx_fifo); + kfree(p_btif->p_tx_fifo); + p_btif->p_tx_fifo = NULL; + } + } + return i_ret; +} + +static int _btif_rx_btm_init(p_mtk_btif p_btif) +{ + int i_ret = -1; + + if (p_btif == NULL) { + BTIF_ERR_FUNC("p_btif is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + + if (p_btif->btm_type == BTIF_THREAD_CTX) { + init_completion(&p_btif->rx_comp); + + /*create kernel thread for later rx data handle*/ + p_btif->p_task = kthread_create(btif_rx_thread, p_btif, "btif_rxd"); + if (p_btif->p_task == NULL) { + BTIF_ERR_FUNC("kthread_create fail\n"); + i_ret = -ENOMEM; + goto btm_init_err; + } + +#if ENABLE_BTIF_RX_THREAD_RT_SCHED + { + int i_ret = -1; + int policy = SCHED_FIFO; + struct sched_param param; + + param.sched_priority = MAX_RT_PRIO - 20; + i_ret = sched_setscheduler(p_btif->p_task, policy, ¶m); + if (i_ret != 0) + BTIF_WARN_FUNC("set RT to btif_rxd workqueue failed\n"); + else + BTIF_INFO_FUNC("set RT to btif_rxd workqueue succeed\n"); + } +#endif + + wake_up_process(p_btif->p_task); + BTIF_INFO_FUNC("btif_rxd start to work!\n"); + } else if (p_btif->btm_type == BTIF_WQ_CTX) { + p_btif->p_rx_wq = create_singlethread_workqueue("btif_rxwq"); + if (!(p_btif->p_rx_wq)) { + BTIF_ERR_FUNC("create_singlethread_workqueue fail\n"); + i_ret = -ENOMEM; + goto btm_init_err; + } + mutex_init(&(p_btif->rx_mtx)); + /* init btif rx work */ + INIT_WORK(&(p_btif->rx_work), btif_rx_worker); + BTIF_INFO_FUNC("btif_rx_worker init succeed\n"); + } else if (p_btif->btm_type == BTIF_TASKLET_CTX) { + /*init rx tasklet*/ + tasklet_init(&(p_btif->rx_tasklet), btif_rx_tasklet, + (unsigned long)p_btif); + spin_lock_init(&(p_btif->rx_tasklet_spinlock)); + BTIF_INFO_FUNC("btif_rx_tasklet init succeed\n"); + } else { + BTIF_ERR_FUNC("unsupported rx context type:%d\n", + p_btif->btm_type); + } + +/*spinlock init*/ + spin_lock_init(&(p_btif->rx_irq_spinlock)); + BTIF_INFO_FUNC("rx_spin_lock init succeed\n"); + + i_ret = 0; + return i_ret; +btm_init_err: + if (p_btif->btm_type == BTIF_THREAD_CTX) { + /*do nothing*/ + BTIF_INFO_FUNC("failed\n"); + } else if (p_btif->btm_type == BTIF_WQ_CTX) { + if (p_btif->p_rx_wq) { + destroy_workqueue(p_btif->p_rx_wq); + p_btif->p_rx_wq = NULL; + BTIF_INFO_FUNC("btif_rx_workqueue destroyed\n"); + } + } + return i_ret; +} + +static int _btif_rx_btm_sched(p_mtk_btif p_btif) +{ + if (p_btif == NULL) { + BTIF_ERR_FUNC("p_btif is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + + if (p_btif->btm_type == BTIF_THREAD_CTX) { + complete(&p_btif->rx_comp); + BTIF_DBG_FUNC("schedule btif_rx_thread\n"); + } else if (p_btif->btm_type == BTIF_WQ_CTX) { + queue_work(p_btif->p_rx_wq, &(p_btif->rx_work)); + BTIF_DBG_FUNC("schedule btif_rx_worker\n"); + } else if (p_btif->btm_type == BTIF_TASKLET_CTX) { + /*schedule it!*/ + tasklet_schedule(&(p_btif->rx_tasklet)); + BTIF_DBG_FUNC("schedule btif_rx_tasklet\n"); + } else { + BTIF_ERR_FUNC("unsupported rx context type:%d\n", + p_btif->btm_type); + } + + return 0; +} + +static int _btif_rx_btm_deinit(p_mtk_btif p_btif) +{ + if (p_btif == NULL) { + BTIF_ERR_FUNC("p_btif is NULL\n"); + return E_BTIF_INVAL_PARAM; + } + if (p_btif->btm_type == BTIF_THREAD_CTX) { + if (p_btif->p_task != NULL) { + BTIF_INFO_FUNC("signaling btif rx thread to stop ...\n"); + kthread_stop(p_btif->p_task); + } + } else if (p_btif->btm_type == BTIF_WQ_CTX) { + if (p_btif->p_rx_wq) { + cancel_work_sync(&(p_btif->rx_work)); + BTIF_INFO_FUNC("btif_rx_worker cancelled\n"); + destroy_workqueue(p_btif->p_rx_wq); + p_btif->p_rx_wq = NULL; + BTIF_INFO_FUNC("btif_rx_workqueue destroyed\n"); + } + mutex_destroy(&(p_btif->rx_mtx)); + } else if (p_btif->btm_type == BTIF_TASKLET_CTX) { + tasklet_kill(&(p_btif->rx_tasklet)); + BTIF_INFO_FUNC("rx_tasklet killed\n"); + } else { + BTIF_ERR_FUNC("unsupported rx context type:%d\n", + p_btif->btm_type); + } + + spin_lock_init(&(p_btif->rx_irq_spinlock)); + + return 0; +} + + +void btif_dump_bbs_str(unsigned char *p_str, p_btif_buf_str p_bbs) +{ + BTIF_INFO_FUNC + ("%s UBS:0x%p\n Size:0x%p\n read:0x%08x\n write:0x%08x\n", + p_str, p_bbs, p_bbs->size, p_bbs->rd_idx, p_bbs->wr_idx); +} + +unsigned int btif_bbs_write(p_btif_buf_str p_bbs, + unsigned char *p_buf, unsigned int buf_len) +{ +/*in IRQ context, so read operation won't interrupt this operation*/ + + unsigned int wr_len = 0; + + unsigned int emp_len = BBS_LEFT(p_bbs); + unsigned int ava_len = emp_len - 1; + p_mtk_btif p_btif = container_of(p_bbs, mtk_btif, btif_buf); + + if (ava_len <= 0) { + BTIF_ERR_FUNC + ("no empty space left for write, (%d)ava_len, (%d)to write\n", + ava_len, buf_len); + hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); + hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); + return 0; + } + + if (ava_len < buf_len) { + BTIF_ERR_FUNC("BTIF overrun, (%d)empty, (%d)needed\n", + emp_len, buf_len); + hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); + hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); + _btif_dump_memory("", p_buf, buf_len); + } + + if (buf_len >= g_max_pkg_len) { + BTIF_WARN_FUNC("buf_len too long, (%d)ava_len, (%d)to write\n", + ava_len, buf_len); + hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); + hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); + _btif_dump_memory("", p_buf, buf_len); + } + + wr_len = min(buf_len, ava_len); + btif_bbs_wr_direct(p_bbs, p_buf, wr_len); + + if (BBS_COUNT(p_bbs) >= g_max_pding_data_size) { + BTIF_WARN_FUNC("Rx buf_len too long, size(%d)\n", + BBS_COUNT(p_bbs)); + btif_dump_bbs_str("Rx buffer tooo long", p_bbs); + hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); + hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); + _btif_dump_memory("", p_buf, buf_len); + BBS_INIT(p_bbs); + } + + return wr_len; +} + +unsigned int btif_bbs_read(p_btif_buf_str p_bbs, + unsigned char *p_buf, unsigned int buf_len) +{ + unsigned int rd_len = 0; + unsigned int ava_len = 0; + unsigned int wr_idx = p_bbs->wr_idx; + + ava_len = BBS_COUNT_CUR(p_bbs, wr_idx); + if (ava_len >= 4096) { + BTIF_WARN_FUNC("ava_len too long, size(%d)\n", ava_len); + btif_dump_bbs_str("Rx buffer tooo long", p_bbs); + } + if (ava_len != 0) { + if (buf_len >= ava_len) { + rd_len = ava_len; + if (wr_idx >= (p_bbs)->rd_idx) { + memcpy(p_buf, BBS_PTR(p_bbs, + p_bbs->rd_idx), + ava_len); + (p_bbs)->rd_idx = wr_idx; + } else { + unsigned int tail_len = BBS_SIZE(p_bbs) - + (p_bbs)->rd_idx; + memcpy(p_buf, BBS_PTR(p_bbs, + p_bbs->rd_idx), + tail_len); + memcpy(p_buf + tail_len, BBS_PTR(p_bbs, + 0), ava_len - tail_len); + (p_bbs)->rd_idx = wr_idx; + } + } else { + rd_len = buf_len; + if (wr_idx >= (p_bbs)->rd_idx) { + memcpy(p_buf, BBS_PTR(p_bbs, + p_bbs->rd_idx), + rd_len); + (p_bbs)->rd_idx = (p_bbs)->rd_idx + rd_len; + } else { + unsigned int tail_len = BBS_SIZE(p_bbs) - + (p_bbs)->rd_idx; + if (tail_len >= rd_len) { + memcpy(p_buf, BBS_PTR(p_bbs, p_bbs->rd_idx), + rd_len); + (p_bbs)->rd_idx = + ((p_bbs)->rd_idx + rd_len) & (BBS_MASK(p_bbs)); + } else { + memcpy(p_buf, BBS_PTR(p_bbs, p_bbs->rd_idx), tail_len); + memcpy(p_buf + tail_len, + (p_bbs)->p_buf, rd_len - tail_len); + (p_bbs)->rd_idx = rd_len - tail_len; + } + } + } + } + mb(); + return rd_len; +} + +unsigned int btif_bbs_wr_direct(p_btif_buf_str p_bbs, + unsigned char *p_buf, unsigned int buf_len) +{ + unsigned int tail_len = 0; + unsigned int l = 0; + unsigned int tmp_wr_idx = p_bbs->wr_idx; + + tail_len = BBS_SIZE(p_bbs) - (tmp_wr_idx & BBS_MASK(p_bbs)); + + l = min(tail_len, buf_len); + + memcpy((p_bbs->p_buf) + (tmp_wr_idx & BBS_MASK(p_bbs)), p_buf, l); + memcpy(p_bbs->p_buf, p_buf + l, buf_len - l); + + mb(); + + tmp_wr_idx += buf_len; + tmp_wr_idx &= BBS_MASK(p_bbs); + p_bbs->wr_idx = tmp_wr_idx; + + mb(); + return buf_len; +} + +int _btif_dma_write(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len) +{ + unsigned int i_ret = 0; + unsigned int retry = 0; + unsigned int max_tx_retry = 10; + + P_MTK_DMA_INFO_STR p_dma_info = p_btif->p_tx_dma->p_dma_info; + + _btif_irq_ctrl_sync(p_dma_info->p_irq, false); + do { + /*wait until tx is allowed*/ + while (!hal_dma_is_tx_allow(p_dma_info) && + (retry < max_tx_retry)) { + retry++; + if (retry >= max_tx_retry) { + BTIF_ERR_FUNC("wait for tx allowed timeout\n"); + break; + } + } + if (retry >= max_tx_retry) + break; + + if (buf_len <= hal_dma_get_ava_room(p_dma_info)) + i_ret = hal_dma_send_data(p_dma_info, p_buf, buf_len); + else + i_ret = 0; + } while (0); + _btif_irq_ctrl_sync(p_dma_info->p_irq, true); + return i_ret; +} + +int _btif_pio_write(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len) +{ + unsigned int i_ret = 0; + unsigned int sent_len = 0; + unsigned int retry = 0; + unsigned int max_tx_retry = 10; + P_MTK_BTIF_INFO_STR p_btif_info = p_btif->p_btif_info; + + while ((sent_len < buf_len)) { + if (hal_btif_is_tx_allow(p_btif_info)) { + i_ret = hal_btif_send_data(p_btif_info, + p_buf + sent_len, + buf_len - sent_len); + if (i_ret > 0) { + sent_len += i_ret; + BTIF_DBG_FUNC("lent sent:%d, total sent:%d\n", + i_ret, sent_len); + retry = 0; + } + } + if ((++retry > max_tx_retry) || (i_ret < 0)) { + BTIF_INFO_FUNC("exceed retry times limit :%d\n", retry); + break; + } + } + i_ret = sent_len; + return i_ret; +} + +int _btif_dump_memory(char *str, unsigned char *p_buf, unsigned int buf_len) +{ + unsigned int idx = 0; + + pr_debug("%s:, length:%d\n", str, buf_len); + for (idx = 0; idx < buf_len;) { + pr_debug("%02x ", p_buf[idx]); + idx++; + if (idx % 8 == 0) + pr_debug("\n"); + } + return 0; +} + +int btif_send_data(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len) +{ + int i_ret = 0; + + if (p_btif->tx_ctx == BTIF_TX_USER_CTX) { + i_ret = _btif_send_data(p_btif, p_buf, buf_len); + } else if (p_btif->tx_ctx == BTIF_TX_SINGLE_CTX) { + int length = 0; +/*tx fifo in*/ + length = kfifo_in(p_btif->p_tx_fifo, + (unsigned char *)p_buf, buf_len); + if (length == buf_len) { + queue_work(p_btif->p_tx_wq, &(p_btif->tx_work)); + BTIF_DBG_FUNC("schedule btif_tx_worker\n"); + i_ret = length; + } else { + i_ret = 0; + BTIF_ERR_FUNC("fifo in failed, target len(%d),in len(%d),", + "don't schedule btif_tx_worker\n", buf_len, length); + } + } else { + BTIF_ERR_FUNC("invalid btif tx context:%d\n", p_btif->tx_ctx); + i_ret = 0; + } + + return i_ret; +} + +int _btif_send_data(p_mtk_btif p_btif, + const unsigned char *p_buf, unsigned int buf_len) +{ + int i_ret = 0; + unsigned int state = 0; + +/*make sure BTIF in ON state before doing tx operation*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + state = _btif_state_get(p_btif); + + if (state != B_S_ON) + i_ret = _btif_exit_dpidle(p_btif); + + if (i_ret != 0) { + i_ret = E_BTIF_INVAL_STATE; + } else if (p_btif->tx_mode == BTIF_MODE_DMA) { + /*_btif_dump_memory("tx data:", p_buf, buf_len);*/ + i_ret = _btif_dma_write(p_btif, p_buf, buf_len); + } else if (p_btif->tx_mode == BTIF_MODE_PIO) { + /*_btif_dump_memory("tx data:", p_buf, buf_len);*/ + i_ret = _btif_pio_write(p_btif, p_buf, buf_len); + } else { + BTIF_ERR_FUNC("invalid tx mode:%d\n", p_btif->tx_mode); + i_ret = 0; + } + +/*save Tx packet here*/ + if (i_ret > 0) + btif_log_buf_dmp_in(&p_btif->tx_log, p_buf, i_ret); + + BTIF_STATE_RELEASE(p_btif); + return i_ret; +} + +int btif_dump_reg(p_mtk_btif p_btif) +{ + int i_ret = 0; + unsigned int ori_state = 0; + +/*make sure BTIF in ON state before doing tx operation*/ + if (_btif_state_hold(p_btif)) + return E_BTIF_INTR; + ori_state = _btif_state_get(p_btif); + + if (ori_state == B_S_OFF) { + i_ret = E_BTIF_INVAL_STATE; + BTIF_ERR_FUNC + ("BTIF in OFF state, ", + "should no need to dump register, ", + "please check wmt's operation is okay or not.\n"); + goto dmp_reg_err; + } + + if ((ori_state != B_S_ON) && (ori_state < B_S_MAX)) { + BTIF_ERR_FUNC("BTIF's original state is %s, not B_S_ON\n", g_state[ori_state]); + BTIF_ERR_FUNC("!!!!---<<>>---!!!"); + i_ret = _btif_exit_dpidle(p_btif); + } + + if (i_ret != 0) { + i_ret = E_BTIF_INVAL_STATE; + BTIF_ERR_FUNC("switch to B_S_ON failed\n"); + goto dmp_reg_err; + } + +/*dump BTIF register*/ + hal_btif_dump_reg(p_btif->p_btif_info, REG_BTIF_ALL); + +/*dump BTIF Tx DMA channel register if in DMA mode*/ + if (p_btif->tx_mode == BTIF_MODE_DMA) + hal_dma_dump_reg(p_btif->p_tx_dma->p_dma_info, REG_TX_DMA_ALL); + else + BTIF_INFO_FUNC("BTIF Tx in PIO mode,no need to dump Tx DMA's register\n"); + +/*dump BTIF Rx DMA channel register if in DMA mode*/ + if (p_btif->rx_mode == BTIF_MODE_DMA) + hal_dma_dump_reg(p_btif->p_rx_dma->p_dma_info, REG_RX_DMA_ALL); + else + BTIF_INFO_FUNC("BTIF Rx in PIO mode,no need to dump Rx DMA's register\n"); + + switch (ori_state) { + case B_S_SUSPEND: +/*return to dpidle state*/ +/* break; */ + case B_S_DPIDLE: +/*return to dpidle state*/ + _btif_enter_dpidle(p_btif); + break; + case B_S_ON: +/*nothing needs to be done*/ + break; + default: + break; + } + +dmp_reg_err: + + BTIF_STATE_RELEASE(p_btif); + return i_ret; +} + +int btif_rx_notify_reg(p_mtk_btif p_btif, MTK_BTIF_RX_NOTIFY rx_notify) +{ + if (p_btif->rx_notify) { + BTIF_WARN_FUNC + ("rx cb already exist, rewrite from (0x%p) to (0x%p)\n", + p_btif->rx_notify, rx_notify); + } + p_btif->rx_notify = rx_notify; + + return 0; +} + +int btif_dump_data(char *p_buf, int len) +{ + unsigned int idx = 0; + unsigned char str[30]; + unsigned char *p_str; + + p_str = &str[0]; + for (idx = 0; idx < len; idx++, p_buf++) { + sprintf(p_str, "%02x ", *p_buf); + p_str += 3; + if (7 == (idx % 8)) { + *p_str++ = '\n'; + *p_str = '\0'; + pr_debug("%s", str); + p_str = &str[0]; + } + } + if (len % 8) { + *p_str++ = '\n'; + *p_str = '\0'; + pr_debug("%s", str); + } + return 0; +} + +int btif_log_buf_dmp_in(P_BTIF_LOG_QUEUE_T p_log_que, const char *p_buf, + int len) +{ + P_BTIF_LOG_BUF_T p_log_buf = NULL; + char *dir = NULL; + struct timespec64 *p_timer = NULL; + unsigned long flags; + bool output_flag = false; + + BTIF_DBG_FUNC("++\n"); + + if ((p_log_que == NULL) || (p_buf == NULL) || (len == 0)) { + BTIF_ERR_FUNC("invalid parameter, p_log_que(0x%x), buf(0x%x), ", + "len(%d)\n", p_log_que, p_buf, len); + return 0; + } + if (!(p_log_que->enable)) + return 0; + + dir = p_log_que->dir == BTIF_TX ? "Tx" : "Rx"; + output_flag = p_log_que->output_flag; + + spin_lock_irqsave(&(p_log_que->lock), flags); + +/*get next log buffer for record usage*/ + p_log_buf = p_log_que->p_queue[0] + p_log_que->in; + p_timer = &p_log_buf->timer; + +/*log time stamp*/ + ktime_get_ts64(p_timer); + +/*record data information including length and content*/ + p_log_buf->len = len; + memcpy(p_log_buf->buffer, p_buf, len > BTIF_LOG_SZ ? BTIF_LOG_SZ : len); + +/*update log queue size information*/ + p_log_que->size++; + p_log_que->size = p_log_que->size > + BTIF_LOG_ENTRY_NUM ? BTIF_LOG_ENTRY_NUM : p_log_que->size; + +/*update log queue index information*/ + p_log_que->in++; + p_log_que->in %= BTIF_LOG_ENTRY_NUM; + + spin_unlock_irqrestore(&p_log_que->lock, flags); + +/*check if log dynamic output function is enabled or not*/ + if (output_flag) { + pr_debug("BTIF-DBG, dir:%s, %d.%ds len:%d\n", + dir, (int)p_timer->tv_sec, (int)(p_timer->tv_nsec / NSEC_PER_USEC), len); +/*output buffer content*/ + btif_dump_data((char *)p_buf, len); + } + BTIF_DBG_FUNC("--\n"); + + return 0; +} + +int btif_log_buf_dmp_out(P_BTIF_LOG_QUEUE_T p_log_que) +{ + P_BTIF_LOG_BUF_T p_log_buf = NULL; + unsigned int out_index = 0; + unsigned int in_index = 0; + unsigned int dump_size = 0; + unsigned char *p_buf = NULL; + unsigned int len = 0; + unsigned int pkt_count = 0; + unsigned char *p_dir = NULL; + struct timespec64 *p_timer = NULL; + unsigned long flags; + +#if 0 /* no matter enable or not, we allowed output */ + if (!(p_log_que->enable)) + return; +#endif + BTIF_DBG_FUNC("++\n"); + + spin_lock_irqsave(&p_log_que->lock, flags); + in_index = p_log_que->in; + dump_size = p_log_que->size; + out_index = p_log_que->size >= + BTIF_LOG_ENTRY_NUM ? in_index : (BTIF_LOG_ENTRY_NUM - + p_log_que->size + + in_index) % BTIF_LOG_ENTRY_NUM; + p_dir = p_log_que->dir == BTIF_TX ? "Tx" : "Rx"; + + BTIF_INFO_FUNC("btif %s log buffer size:%d\n", p_dir, dump_size); + + if (dump_size != 0) { + while (dump_size--) { + p_log_buf = p_log_que->p_queue[0] + out_index; + + len = p_log_buf->len; + p_buf = p_log_buf->buffer; + p_timer = &p_log_buf->timer; + + len = len > BTIF_LOG_SZ ? BTIF_LOG_SZ : len; + + BTIF_INFO_FUNC("dir:%s, pkt_count:%d, %d.%ds len:%d\n", + p_dir, + pkt_count++, + (int)p_timer->tv_sec, + (int)(p_timer->tv_nsec / NSEC_PER_USEC), len); +/*output buffer content*/ + btif_dump_data(p_log_buf->buffer, len); + out_index++; + out_index %= BTIF_LOG_ENTRY_NUM; + } + } + spin_unlock_irqrestore(&p_log_que->lock, flags); + BTIF_DBG_FUNC("--\n"); + + return 0; +} + +int btif_log_buf_enable(P_BTIF_LOG_QUEUE_T p_log_que) +{ + unsigned long flags; + + spin_lock_irqsave(&p_log_que->lock, flags); + p_log_que->enable = true; + spin_unlock_irqrestore(&p_log_que->lock, flags); + BTIF_INFO_FUNC("enable %s log function\n", + p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); + return 0; +} + +int btif_log_buf_disable(P_BTIF_LOG_QUEUE_T p_log_que) +{ + unsigned long flags; + + spin_lock_irqsave(&p_log_que->lock, flags); + p_log_que->enable = false; + spin_unlock_irqrestore(&p_log_que->lock, flags); + BTIF_INFO_FUNC("disable %s log function\n", + p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); + return 0; +} + +int btif_log_output_enable(P_BTIF_LOG_QUEUE_T p_log_que) +{ + unsigned long flags; + + spin_lock_irqsave(&p_log_que->lock, flags); + p_log_que->output_flag = true; + spin_unlock_irqrestore(&p_log_que->lock, flags); + BTIF_INFO_FUNC("%s log rt output enabled\n", + p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); + return 0; +} + +int btif_log_output_disable(P_BTIF_LOG_QUEUE_T p_log_que) +{ + unsigned long flags; + + spin_lock_irqsave(&p_log_que->lock, flags); + p_log_que->output_flag = false; + spin_unlock_irqrestore(&p_log_que->lock, flags); + BTIF_INFO_FUNC("%s log rt output disabled\n", + p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); + return 0; +} + +int btif_log_buf_reset(P_BTIF_LOG_QUEUE_T p_log_que) +{ + unsigned long flags; + + spin_lock_irqsave(&p_log_que->lock, flags); + +/*tx log buffer init*/ + p_log_que->in = 0; + p_log_que->out = 0; + p_log_que->size = 0; + p_log_que->enable = true; + memset((p_log_que->p_queue[0]), 0, sizeof(BTIF_LOG_BUF_T)); + + spin_unlock_irqrestore(&p_log_que->lock, flags); + BTIF_DBG_FUNC("reset %s log buffer\n", + p_log_que->dir == BTIF_TX ? "Tx" : "Rx"); + return 0; +} + +int btif_log_buf_init(p_mtk_btif p_btif) +{ +/*tx log buffer init*/ + p_btif->tx_log.dir = BTIF_TX; + p_btif->tx_log.in = 0; + p_btif->tx_log.out = 0; + p_btif->tx_log.size = 0; + p_btif->tx_log.output_flag = false; + p_btif->tx_log.enable = true; + spin_lock_init(&(p_btif->tx_log.lock)); + BTIF_DBG_FUNC("tx_log.p_queue:0x%p\n", p_btif->tx_log.p_queue[0]); + memset((p_btif->tx_log.p_queue[0]), 0, sizeof(BTIF_LOG_BUF_T)); + +/*rx log buffer init*/ + p_btif->rx_log.dir = BTIF_RX; + p_btif->rx_log.in = 0; + p_btif->rx_log.out = 0; + p_btif->rx_log.size = 0; + p_btif->rx_log.output_flag = false; + p_btif->rx_log.enable = true; + spin_lock_init(&(p_btif->rx_log.lock)); + BTIF_DBG_FUNC("rx_log.p_queue:0x%p\n", p_btif->rx_log.p_queue[0]); + memset((p_btif->rx_log.p_queue[0]), 0, sizeof(BTIF_LOG_BUF_T)); + + return 0; +} + +int btif_tx_dma_mode_set(int en) +{ + int index = 0; + ENUM_BTIF_MODE mode = (en == 1) ? BTIF_MODE_DMA : BTIF_MODE_PIO; + + for (index = 0; index < BTIF_PORT_NR; index++) + g_btif[index].tx_mode = mode; + + return 0; +} + +int btif_rx_dma_mode_set(int en) +{ + int index = 0; + ENUM_BTIF_MODE mode = (en == 1) ? BTIF_MODE_DMA : BTIF_MODE_PIO; + + for (index = 0; index < BTIF_PORT_NR; index++) + g_btif[index].rx_mode = mode; + + return 0; +} + +static int BTIF_init(void) +{ + int i_ret = -1; + int index = 0; + p_mtk_btif_dma p_tx_dma = NULL; + p_mtk_btif_dma p_rx_dma = NULL; + unsigned char *p_btif_buffer = NULL; + unsigned char *p_tx_queue = NULL; + unsigned char *p_rx_queue = NULL; + + BTIF_DBG_FUNC("++\n"); + +/*Platform Driver initialization*/ + i_ret = platform_driver_register(&mtk_btif_dev_drv); + if (i_ret) { + BTIF_ERR_FUNC("BTIF platform driver registered failed, ret(%d)\n", i_ret); + goto err_exit1; + } + + i_ret = driver_create_file(&mtk_btif_dev_drv.driver, &dev_attr_flag); + if (i_ret) + BTIF_ERR_FUNC("BTIF pdriver_create_file failed, ret(%d)\n", i_ret); + +/*SW init*/ + for (index = 0; index < BTIF_PORT_NR; index++) { + p_btif_buffer = kmalloc(BTIF_RX_BUFFER_SIZE, GFP_ATOMIC); + if (!p_btif_buffer) { + BTIF_ERR_FUNC("p_btif_buffer kmalloc memory fail\n"); + return -1; + } + BTIF_INFO_FUNC("p_btif_buffer get memory 0x%p\n", p_btif_buffer); + p_tx_queue = kmalloc_array(BTIF_LOG_ENTRY_NUM, sizeof(BTIF_LOG_BUF_T), GFP_ATOMIC); + if (!p_tx_queue) { + BTIF_ERR_FUNC("p_tx_queue kmalloc memory fail\n"); + kfree(p_btif_buffer); + return -1; + } + BTIF_INFO_FUNC("p_tx_queue get memory 0x%p\n", p_tx_queue); + p_rx_queue = kmalloc_array(BTIF_LOG_ENTRY_NUM, sizeof(BTIF_LOG_BUF_T), GFP_ATOMIC); + if (!p_rx_queue) { + BTIF_ERR_FUNC("p_rx_queue kmalloc memory fail\n"); + kfree(p_btif_buffer); + kfree(p_tx_queue); + return -1; + } + BTIF_INFO_FUNC("p_rx_queue get memory 0x%p\n", p_rx_queue); + + INIT_LIST_HEAD(&(g_btif[index].user_list)); + BBS_INIT(&(g_btif[index].btif_buf)); + g_btif[index].enable = false; + g_btif[index].open_counter = 0; + g_btif[index].setting = &g_btif_setting[index]; + g_btif[index].p_btif_info = hal_btif_info_get(); + g_btif[index].tx_mode = g_btif_setting[index].tx_mode; + g_btif[index].rx_mode = g_btif_setting[index].rx_mode; + g_btif[index].btm_type = g_btif_setting[index].rx_type; + g_btif[index].tx_ctx = g_btif_setting[index].tx_type; + g_btif[index].lpbk_flag = false; + g_btif[index].rx_cb = NULL; + g_btif[index].rx_notify = NULL; + g_btif[index].btif_buf.p_buf = p_btif_buffer; + g_btif[index].tx_log.p_queue[0] = (P_BTIF_LOG_BUF_T) p_tx_queue; + g_btif[index].rx_log.p_queue[0] = (P_BTIF_LOG_BUF_T) p_rx_queue; + btif_log_buf_init(&g_btif[index]); + +#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) +/*enable BTIF clock gating by default*/ + i_ret = hal_btif_clk_ctrl(g_btif[index].p_btif_info, + CLK_OUT_DISABLE); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF controller CG failed\n"); + goto err_exit2; + } +#endif + +/* + * viftual FIFO memory must be physical continious, + * because DMA will access it directly without MMU + */ +#if ENABLE_BTIF_TX_DMA + p_tx_dma = &g_dma[index][BTIF_TX]; + g_btif[index].p_tx_dma = p_tx_dma; + p_tx_dma->dir = BTIF_TX; + p_tx_dma->p_btif = &(g_btif[index]); + +/*DMA Tx vFIFO initialization*/ + p_tx_dma->p_dma_info = hal_btif_dma_info_get(DMA_DIR_TX); +/*spinlock init*/ + spin_lock_init(&(p_tx_dma->iolock)); +/*entry setup*/ + atomic_set(&(p_tx_dma->entry), 0); +/*vFIFO initialization*/ + i_ret = _btif_vfifo_init(p_tx_dma); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF Tx vFIFO allocation failed\n"); + goto err_exit2; + } + +#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) +/*enable BTIF Tx DMA channel's clock gating by default*/ + i_ret = hal_btif_dma_clk_ctrl(p_tx_dma->p_dma_info, + CLK_OUT_DISABLE); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF Tx DMA's CG failed\n"); + goto err_exit2; + } +#endif + +#else + g_btif[index].p_tx_dma = NULL; +/*force tx mode to DMA no matter what it is in default setting*/ + g_btif[index].tx_mode = BTIF_MODE_PIO; +#endif + +#if ENABLE_BTIF_RX_DMA + p_rx_dma = &g_dma[index][BTIF_RX]; + g_btif[index].p_rx_dma = p_rx_dma; + p_rx_dma->p_btif = &(g_btif[index]); + p_rx_dma->dir = BTIF_RX; + +/*DMA Tx vFIFO initialization*/ + p_rx_dma->p_dma_info = hal_btif_dma_info_get(DMA_DIR_RX); +/*spinlock init*/ + spin_lock_init(&(p_rx_dma->iolock)); +/*entry setup*/ + atomic_set(&(p_rx_dma->entry), 0); +/*vFIFO initialization*/ + i_ret = _btif_vfifo_init(p_rx_dma); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF Rx vFIFO allocation failed\n"); + goto err_exit2; + } + +#if !(MTK_BTIF_ENABLE_CLK_REF_COUNTER) +/*enable BTIF Tx DMA channel's clock gating by default*/ + i_ret = hal_btif_dma_clk_ctrl(p_rx_dma->p_dma_info, + CLK_OUT_DISABLE); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF Rx DMA's CG failed\n"); + goto err_exit2; + } +#endif + +#else + g_btif[index].p_rx_dma = NULL; +/*force rx mode to DMA no matter what it is in default setting*/ + g_btif[index].rx_mode = BTIF_MODE_PIO; + +#endif +/*PM state mechine initialization*/ + i_ret = _btif_state_init(&(g_btif[index])); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF state mechanism init failed\n"); + goto err_exit2; + } + +/*Rx bottom half initialization*/ + i_ret = _btif_rx_btm_init(&(g_btif[index])); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF Rx btm init failed\n"); + goto err_exit3; + } + i_ret = _btif_tx_ctx_init(&(g_btif[index])); + if (i_ret != 0) { + BTIF_ERR_FUNC("BTIF Tx context init failed\n"); + goto err_exit4; + } +/*Character Device initialization*/ +/*Chaozhong: ToDo: to be initialized*/ + + mutex_init(&g_btif[index].ops_mtx); + } + +/*Debug purpose initialization*/ + +#if BTIF_CDEV_SUPPORT + btif_chrdev_init(); +#endif + + return 0; + +err_exit4: + for (index = 0; index < BTIF_PORT_NR; index++) + _btif_tx_ctx_deinit(&(g_btif[index])); + +err_exit3: + for (index = 0; index < BTIF_PORT_NR; index++) { + _btif_rx_btm_deinit(&(g_btif[index])); + + _btif_state_deinit(&(g_btif[index])); + } + +err_exit2: + for (index = 0; index < BTIF_PORT_NR; index++) { + p_tx_dma = &g_dma[index][BTIF_TX]; + p_rx_dma = &g_dma[index][BTIF_RX]; +#if ENABLE_BTIF_TX_DMA + _btif_vfifo_deinit(p_tx_dma); +#endif + +#if ENABLE_BTIF_RX_DMA + _btif_vfifo_deinit(p_rx_dma); +#endif + g_btif[index].open_counter = 0; + g_btif[index].enable = false; + } + driver_remove_file(&mtk_btif_dev_drv.driver, &dev_attr_flag); + platform_driver_unregister(&mtk_btif_dev_drv); + +err_exit1: + i_ret = -1; + BTIF_DBG_FUNC("--\n"); + return i_ret; +} + +static void BTIF_exit(void) +{ + unsigned int index = 0; + p_mtk_btif_dma p_tx_dma = NULL; + p_mtk_btif_dma p_rx_dma = NULL; + + BTIF_DBG_FUNC("++\n"); + + for (index = 0; index < BTIF_PORT_NR; index++) { + g_btif[index].open_counter = 0; + g_btif[index].enable = false; + p_tx_dma = &g_dma[index][BTIF_TX]; + p_rx_dma = &g_dma[index][BTIF_RX]; +#if ENABLE_BTIF_TX_DMA + _btif_vfifo_deinit(p_tx_dma); +#endif + +#if ENABLE_BTIF_RX_DMA + _btif_vfifo_deinit(p_rx_dma); +#endif + _btif_state_deinit(&(g_btif[index])); + + _btif_rx_btm_deinit(&(g_btif[index])); + + mutex_destroy(&g_btif[index].ops_mtx); + } + +#if !defined(CONFIG_MTK_CLKMGR) + hal_btif_clk_unprepare(); +#endif + + driver_remove_file(&mtk_btif_dev_drv.driver, &dev_attr_flag); + platform_driver_unregister(&mtk_btif_dev_drv); + BTIF_DBG_FUNC("--\n"); +} + +int mtk_btif_hal_get_log_lvl(void) +{ + return mtk_btif_dbg_lvl; +} + +void mtk_btif_read_cpu_sw_rst_debug(void) +{ + mtk_btif_read_cpu_sw_rst_debug_plat(); +} + +/*---------------------------------------------------------------------------*/ + +module_init(BTIF_init); +module_exit(BTIF_exit); + +/*---------------------------------------------------------------------------*/ + +MODULE_AUTHOR("MBJ/WCN/SE/SS1/Chaozhong.Liang"); +MODULE_DESCRIPTION("MTK BTIF Driver$1.0$"); +MODULE_LICENSE("GPL"); + +/*---------------------------------------------------------------------------*/ diff --git a/drivers/misc/mediatek/btif/common/mtk_btif_exp.c b/drivers/misc/mediatek/btif/common/mtk_btif_exp.c new file mode 100644 index 00000000000000..c0df44558357b4 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/mtk_btif_exp.c @@ -0,0 +1,786 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "MTK-BTIF-EXP" + +/*#include "mtk_btif_exp.h"*/ +#include "mtk_btif.h" + +/*---------------------------------Function----------------------------------*/ + +p_mtk_btif btif_exp_srh_id(unsigned long u_id) +{ + int index = 0; + p_mtk_btif p_btif = NULL; + struct list_head *p_list = NULL; + struct list_head *tmp = NULL; + p_mtk_btif_user p_user = NULL; + + for (index = 0; (index < BTIF_PORT_NR) && (p_btif == NULL); index++) { + p_list = &(g_btif[index].user_list); + list_for_each(tmp, p_list) { + p_user = container_of(tmp, mtk_btif_user, entry); + if (u_id == p_user->u_id) { + p_btif = p_user->p_btif; + BTIF_DBG_FUNC + ("BTIF's user id(0x%p), p_btif(0x%p)\n", + p_user->u_id, p_btif); + break; + } + } + } + if (p_btif == NULL) { + BTIF_INFO_FUNC + ("no btif structure found for BTIF's user id(0x%lx)\n", + u_id); + } + return p_btif; +} + +/*-----Normal Mode API declearation-------*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_open +* DESCRIPTION +* open BTIF interface, will do BTIF module HW and SW initialization +* PARAMETERS +* p_owner [IN] pointer to owner who call this API, +* currently there are 2 owner ("stp" or "btif_tester") +* may use this module +* for "stp", BTIF will call rx callback function to route rx data to STP module +* for "stp_tester", BTIF will save rx data and wait for native process to access +* p_id [IN] BTIF's user id will be put to this address +* RETURNS +* int 0 = BTIF module initialization fail; negative = BTIF module initialization success +* if open success, value p_id will be the only identifier +* for user to access BTIF's other operations +* including read/write/dpidle_ctrl/rx_cb_retister +* this user id is only an identifier used for owner identification +*****************************************************************************/ +int mtk_wcn_btif_open(char *p_owner, unsigned long *p_id) +{ + int i_ret = -1; + unsigned int index = 0; + p_mtk_btif_user p_new_user = NULL; + p_mtk_btif p_btif = &g_btif[index]; + struct list_head *p_user_list = &(p_btif->user_list); + + BTIF_DBG_FUNC("++"); + BTIF_DBG_FUNC("p_btif(0x%p)\n", p_btif); + + if (mutex_lock_killable(&(p_btif->ops_mtx))) { + BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); + return E_BTIF_INTR; + } + if ((p_owner == NULL) || (p_id == NULL)) { + if (p_id) + *p_id = 0; + BTIF_ERR_FUNC("parameter invalid, p_owner(0x%p), p_id(0x%p)\n", + p_owner, p_id); + BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); + return E_BTIF_INVAL_PARAM; + } + +/*check if btif is already opened or not, if yes, just return fail*/ + if (!list_empty(p_user_list)) { + struct list_head *pos; + p_mtk_btif_user p_user; + + BTIF_ERR_FUNC("BTIF's user list is not empty\n"); + list_for_each(pos, p_user_list) { + p_user = container_of(pos, mtk_btif_user, entry); + BTIF_INFO_FUNC("BTIF's user id(0x%lx), name(%s)\n", + p_user->u_id, p_user->u_name); + } +/*leave p_id alone*/ + BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); + return E_BTIF_ALREADY_OPEN; + } + p_new_user = vmalloc(sizeof(mtk_btif_user)); + + if (p_new_user != NULL) { + INIT_LIST_HEAD(&(p_new_user->entry)); + p_new_user->enable = false; + p_new_user->p_btif = p_btif; + p_new_user->u_id = (unsigned long)p_new_user; + strncpy(p_new_user->u_name, p_owner, sizeof(p_new_user->u_name) - 1); + p_new_user->u_name[sizeof(p_new_user->u_name) - 1] = '\0'; + BTIF_DBG_FUNC("owner name:%s, recorded name:%s\n", + p_owner, p_new_user->u_name); + + i_ret = btif_open(p_btif); + if (i_ret) { + BTIF_ERR_FUNC("btif_open failed, i_ret(%d)\n", i_ret); + *p_id = 0; +/*free btif new user's structure*/ + vfree(p_new_user); + p_new_user = NULL; + } else { + BTIF_INFO_FUNC("btif_open succeed\n"); + *p_id = p_new_user->u_id; +/*mark enable flag to true*/ + p_new_user->enable = true; +/*add to uer lsit*/ + list_add_tail(&(p_new_user->entry), p_user_list); + } + } else { + *p_id = 0; + i_ret = -ENOMEM; + BTIF_ERR_FUNC("allocate memory for mtk_btif_user failed\n"); + } + BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); + BTIF_DBG_FUNC("--"); + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_open); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_close +* DESCRIPTION +* close BTIF interface, will do BTIF module HW and SW de-initialization +* once this API is called, p_btif should never be used by BTIF's user again +* PARAMETERS +* u_id [IN] BTIF's user id +* RETURNS +* int 0 = succeed; +* others = fail, +* for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_close(unsigned long u_id) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + struct list_head *pos = NULL; + struct list_head *p_user_list = NULL; + + BTIF_DBG_FUNC("++"); + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + + if (mutex_lock_killable(&(p_btif->ops_mtx))) { + BTIF_ERR_FUNC("mutex_lock_killable return failed\n"); + return E_BTIF_INTR; + } + p_user_list = &(p_btif->user_list); + list_for_each(pos, p_user_list) { + p_mtk_btif_user p_user = + container_of(pos, mtk_btif_user, entry); + + if (p_user->u_id == u_id) { + BTIF_INFO_FUNC + ("user who's id is 0x%lx deleted from user list\n", + u_id); + list_del(pos); + vfree(p_user); + i_ret = btif_close(p_btif); + if (i_ret) + BTIF_WARN_FUNC("BTIF close failed"); + break; + } + } + BTIF_MUTEX_UNLOCK(&(p_btif->ops_mtx)); + BTIF_DBG_FUNC("--"); + return 0; +} +EXPORT_SYMBOL(mtk_wcn_btif_close); + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_write +* DESCRIPTION +* send data throuth BTIF module +* there's no internal buffer to cache STP data in BTIF driver, +* if in DMA mode +* btif driver will check if there's enough space in vFIFO for data to send in DMA mode +* if yes, put data to vFIFO and return corresponding data length to caller +* if no, corresponding error code will be returned to called +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* p_buf [IN] pointer to target data to send +* len [IN] data length (should be less than 2014 bytes per STP package) +* +* if in non-DMA mode, BTIF driver will try to write to THR of BTIF controller +* if btif driver detected that no space is available in Tx FIFO, +* will return E_BTIF_NO_SPACE, mostly something is wrong with BTIF or +* consys when this return value is returned +* RETURNS +* int positive: data length send through BTIF; +* negative: please see ENUM_BTIF_OP_ERROR_CODE +* E_BTIF_AGAIN (0) will be returned to caller +* if btif does not have enough vFIFO to send data, +* when caller get 0, he should wait for a moment +* (5~10ms maybe) and try a few times (maybe 10~20) +* if still get E_BTIF_AGAIN, +* should call BTIF's debug API and dump BTIF driver +* and BTIF/DMA register information to kernel log for debug +* E_BTIF_BAD_POINTER will be returned to caller +* if btif is not opened successfully before call this API +* E_BTIF_INVAL_PARAM will be returned if parameter is not valid + +*****************************************************************************/ +int mtk_wcn_btif_write(unsigned long u_id, + const unsigned char *p_buf, unsigned int len) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + + BTIF_DBG_FUNC("++"); + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + if (p_buf == NULL) { + BTIF_ERR_FUNC("invalid p_buf (0x%p)\n", p_buf); + return E_BTIF_INVAL_PARAM; + } + if ((len == 0) || (len > BTIF_MAX_LEN_PER_PKT)) { + BTIF_ERR_FUNC("invalid buffer length(%d)\n", len); + return E_BTIF_INVAL_PARAM; + } + + i_ret = btif_send_data(p_btif, p_buf, len); + BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_write); + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_read +* DESCRIPTION +* read data from BTIF module +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* p_buf [IN/OUT] pointer to buffer where rx data will be put +* max_len [IN] max buffer length +* RETURNS +* int positive: data length read from BTIF; +* negative: please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_read(unsigned long u_id, + unsigned char *p_buf, unsigned int max_len) +{ + return 0; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_dpidle_ctrl +* DESCRIPTION +* control if BTIF module allow system enter deepidle state or not +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* en_flag [IN] one of ENUM_BTIF_DPIDLE_CTRL +* RETURNS +* int always return 0 +*****************************************************************************/ +int mtk_wcn_btif_dpidle_ctrl(unsigned long u_id, ENUM_BTIF_DPIDLE_CTRL en_flag) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + + if (en_flag == BTIF_DPIDLE_DISABLE) + i_ret = btif_exit_dpidle(p_btif); + else + i_ret = btif_enter_dpidle(p_btif); + + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_dpidle_ctrl); + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_rx_cb_register +* DESCRIPTION +* register rx callback function to BTIF module by btif user +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* rx_cb [IN] pointer to stp rx handler callback function, +* should be comply with MTK_WCN_BTIF_RX_CB +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, +* please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_rx_cb_register(unsigned long u_id, MTK_WCN_BTIF_RX_CB rx_cb) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + + i_ret = btif_rx_cb_reg(p_btif, rx_cb); + + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_rx_cb_register); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_wakeup_consys +* DESCRIPTION +* once sleep command is sent to con sys, +* should call this API before send wakeup command +* to make con sys aware host want to send data to consys +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* RETURNS +* int 0 = succeed; others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_wakeup_consys(unsigned long u_id) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + +/*i_ret = hal_btif_raise_wak_sig(p_btif->p_btif_info);*/ + i_ret = btif_raise_wak_signal(p_btif); + + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_wakeup_consys); + + +/***************End of Normal Mode API declearation**********/ + +/***************Debug Purpose API declearation**********/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_loopback_ctrl +* DESCRIPTION +* enable/disable BTIF internal loopback function, +* when this function is enabled data send to btif +* will be received by btif itself +* only for debug purpose, should never use this function in normal mode +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* enable [IN] loopback mode control flag, enable or disable, +* shou be one of ENUM_BTIF_LPBK_MODE +* RETURNS +* int 0 = succeed; +* others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_loopback_ctrl(unsigned long u_id, ENUM_BTIF_LPBK_MODE enable) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + i_ret = + btif_lpbk_ctrl(p_btif, enable == BTIF_LPBK_ENABLE ? true : false); + + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_loopback_ctrl); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_btif_logger_ctrl +* DESCRIPTION +* control BTIF logger function's behavior +* PARAMETERS +* p_btif [IN] pointer returned by mtk_wcn_btif_open +* flag [IN] should be one of ENUM_BTIF_DBG_ID +* BTIF_DISABLE_LOGGER - disable btif logger +* BTIF_ENABLE_LOGGER - enable btif logger +* BTIF_DUMP_LOG - dump log logged by btif +* BTIF_CLR_LOG - clear btif log buffer +* BTIF_DUMP_BTIF_REG - dump btif controller's register +* BTIF_DUMP_DMA_REG - dump DMA controller's register +* RETURNS +* int 0 = succeed; others = fail, for detailed information, please see ENUM_BTIF_OP_ERROR_CODE +*****************************************************************************/ +int mtk_wcn_btif_dbg_ctrl(unsigned long u_id, ENUM_BTIF_DBG_ID flag) +{ + int i_ret = -1; + p_mtk_btif p_btif = NULL; + + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + + i_ret = 0; + switch (flag) { + case BTIF_DISABLE_LOGGER:{ + BTIF_INFO_FUNC + ("disable btif log function for both Tx and Rx\n"); + btif_log_buf_disable(&p_btif->tx_log); + btif_log_buf_disable(&p_btif->rx_log); + } + break; + case BTIF_ENABLE_LOGGER:{ + BTIF_INFO_FUNC + ("enable btif log function for both Tx and Rx\n"); + btif_log_buf_enable(&p_btif->tx_log); + btif_log_buf_enable(&p_btif->rx_log); + } + break; + case BTIF_DUMP_LOG:{ + BTIF_INFO_FUNC("dump btif log for both Tx and Rx\n"); + btif_log_buf_dmp_out(&p_btif->tx_log); + btif_log_buf_dmp_out(&p_btif->rx_log); + } + break; + + case BTIF_CLR_LOG:{ + BTIF_INFO_FUNC("clear btif log for both Tx and Rx\n"); + btif_log_buf_reset(&p_btif->tx_log); + btif_log_buf_reset(&p_btif->rx_log); + } + break; + case BTIF_DUMP_BTIF_REG: + /*TBD*/ btif_dump_reg(p_btif); + break; + case BTIF_ENABLE_RT_LOG: + BTIF_INFO_FUNC + ("enable btif real time log for both Tx and Rx\n"); + btif_log_output_enable(&p_btif->tx_log); + btif_log_output_enable(&p_btif->rx_log); + break; + case BTIF_DISABLE_RT_LOG: + BTIF_INFO_FUNC + ("disable btif real time log for both Tx and Rx\n"); + btif_log_output_disable(&p_btif->tx_log); + btif_log_output_disable(&p_btif->rx_log); + break; + default: + BTIF_INFO_FUNC("not supported flag:%d\n", flag); + i_ret = -2; + break; + } + + return i_ret; +} +EXPORT_SYMBOL(mtk_wcn_btif_dbg_ctrl); + +bool mtk_wcn_btif_parser_wmt_evt(unsigned long u_id, + const char *sub_str, unsigned int str_len) +{ + bool b_ret = false; + p_mtk_btif p_btif = NULL; + + p_btif = btif_exp_srh_id(u_id); + + if (p_btif == NULL) + return E_BTIF_INVAL_PARAM; + b_ret = btif_parser_wmt_evt(p_btif, sub_str, str_len); + BTIF_INFO_FUNC("parser wmt evt %s\n", b_ret ? "ok" : "fail"); + + return b_ret; +} + +/**********End of Debug Purpose API declearation**********/ + +int btif_open_no_id(void) +{ + int i_ret = 0; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = btif_open(p_btif); + + if (i_ret) + BTIF_ERR_FUNC("btif_open failed, i_ret(%d)\n", i_ret); + else + BTIF_INFO_FUNC("btif_open succeed\n"); + + return i_ret; +} + +int btif_close_no_id(void) +{ + int i_ret = 0; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = btif_close(p_btif); + + if (i_ret) + BTIF_ERR_FUNC("btif_close failed, i_ret(%d)\n", i_ret); + else + BTIF_INFO_FUNC("btif_close succeed\n"); + return i_ret; +} + +int btif_write_no_id(const unsigned char *p_buf, unsigned int len) +{ + int i_ret = -1; + p_mtk_btif p_btif = &g_btif[0]; + + BTIF_DBG_FUNC("++"); + + if (p_buf == NULL) { + BTIF_ERR_FUNC("invalid p_buf (0x%p)\n", p_buf); + return E_BTIF_INVAL_PARAM; + } + if ((len == 0) || (len > BTIF_MAX_LEN_PER_PKT)) { + BTIF_ERR_FUNC("invalid buffer length(%d)\n", len); + return E_BTIF_INVAL_PARAM; + } + + i_ret = btif_send_data(p_btif, p_buf, len); + BTIF_DBG_FUNC("--, i_ret:%d\n", i_ret); + return i_ret; +} + +int btif_dpidle_ctrl_no_id(ENUM_BTIF_DPIDLE_CTRL en_flag) +{ + int i_ret = -1; + p_mtk_btif p_btif = &g_btif[0]; + + if (en_flag == BTIF_DPIDLE_DISABLE) + i_ret = btif_exit_dpidle(p_btif); + else + i_ret = btif_enter_dpidle(p_btif); + + return i_ret; +} + +int btif_wakeup_consys_no_id(void) +{ + int i_ret = -1; + p_mtk_btif p_btif = &g_btif[0]; + +/*i_ret = hal_btif_raise_wak_sig(p_btif->p_btif_info);*/ + i_ret = btif_raise_wak_signal(p_btif); + + return i_ret; +} + +int btif_loopback_ctrl_no_id(ENUM_BTIF_LPBK_MODE enable) +{ + int i_ret = -1; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = + btif_lpbk_ctrl(p_btif, enable == BTIF_LPBK_ENABLE ? true : false); + + return i_ret; +} + +int btif_dbg_ctrl_no_id(ENUM_BTIF_DBG_ID flag) +{ + int i_ret = -1; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = 0; + switch (flag) { + case BTIF_DISABLE_LOGGER:{ + BTIF_INFO_FUNC + ("disable btif log function for both Tx and Rx\n"); + btif_log_buf_disable(&p_btif->tx_log); + btif_log_buf_disable(&p_btif->rx_log); + } + break; + case BTIF_ENABLE_LOGGER:{ + BTIF_INFO_FUNC + ("enable btif log function for both Tx and Rx\n"); + btif_log_buf_enable(&p_btif->tx_log); + btif_log_buf_enable(&p_btif->rx_log); + } + break; + case BTIF_DUMP_LOG:{ + BTIF_INFO_FUNC("dump btif log for both Tx and Rx\n"); + btif_log_buf_dmp_out(&p_btif->tx_log); + btif_log_buf_dmp_out(&p_btif->rx_log); + } + break; + + case BTIF_CLR_LOG:{ + BTIF_INFO_FUNC("clear btif log for both Tx and Rx\n"); + btif_log_buf_reset(&p_btif->tx_log); + btif_log_buf_reset(&p_btif->rx_log); + } + break; + case BTIF_DUMP_BTIF_REG: + /*TBD*/ btif_dump_reg(p_btif); + break; + case BTIF_ENABLE_RT_LOG: + BTIF_INFO_FUNC + ("enable btif real time log for both Tx and Rx\n"); + btif_log_output_enable(&p_btif->tx_log); + btif_log_output_enable(&p_btif->rx_log); + break; + case BTIF_DISABLE_RT_LOG: + BTIF_INFO_FUNC + ("disable btif real time log for both Tx and Rx\n"); + btif_log_output_disable(&p_btif->tx_log); + btif_log_output_disable(&p_btif->rx_log); + break; + default: + BTIF_INFO_FUNC("not supported flag:%d\n", flag); + i_ret = -2; + break; + } + + return i_ret; +} + +int mtk_btif_exp_open_test(void) +{ + int i_ret = 0; + + i_ret = btif_open_no_id(); + if (i_ret < 0) { + BTIF_INFO_FUNC("mtk_wcn_btif_open failed\n"); + return -1; + } + + BTIF_INFO_FUNC("mtk_wcn_btif_open succeed\n"); + + return i_ret; +} + +int mtk_btif_exp_close_test(void) +{ + int i_ret = 0; + + i_ret = btif_close_no_id(); + if (i_ret < 0) { + BTIF_INFO_FUNC("mtk_wcn_btif_close failed\n"); + return -1; + } + + BTIF_INFO_FUNC("mtk_wcn_btif_close succeed\n"); + + return i_ret; +} + +int mtk_btif_exp_write_test(void) +{ + return mtk_btif_exp_write_stress_test(100, 10); +} + +int mtk_btif_exp_write_stress_test(unsigned int length, unsigned int max_loop) +{ +#define BUF_LEN 1024 + int i_ret = 0; + int idx = 0; + int buf_len = length > BUF_LEN ? BUF_LEN : length; + int loop = max_loop > 1000000 ? 1000000 : max_loop; + unsigned char *buffer; + + buffer = kmalloc(BUF_LEN, GFP_KERNEL); + if (!buffer) { + BTIF_ERR_FUNC("btif tester kmalloc failed\n"); + return -1; + } + + for (idx = 0; idx < buf_len; idx++) + /* btif_stress_test_buf[idx] = BUF_LEN -idx; */ + *(buffer + idx) = idx % 255; + i_ret = btif_loopback_ctrl_no_id(BTIF_LPBK_ENABLE); + BTIF_INFO_FUNC("mtk_wcn_btif_loopback_ctrl returned %d\n", i_ret); + while (loop--) { + i_ret = btif_write_no_id(buffer, buf_len); + BTIF_INFO_FUNC("mtk_wcn_btif_write left loop:%d, i_ret:%d\n", + loop, i_ret); + if (i_ret != buf_len) { + BTIF_INFO_FUNC + ("mtk_wcn_btif_write failed, target len %d, sent len: %d\n", + buf_len, i_ret); + break; + } + buf_len--; + if (buf_len <= 0) + buf_len = length > BUF_LEN ? BUF_LEN : length; + } + kfree(buffer); + return i_ret; +} + +int mtk_btif_exp_suspend_test(void) +{ + int i_ret = 0; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = _btif_suspend(p_btif); + return i_ret; +} + +int mtk_btif_exp_restore_noirq_test(void) +{ + int i_ret = 0; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = _btif_restore_noirq(p_btif); + return i_ret; +} + +int mtk_btif_exp_clock_ctrl(int en) +{ + int i_ret = 0; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = btif_clock_ctrl(p_btif, en); + return i_ret; +} + +int mtk_btif_exp_resume_test(void) +{ + int i_ret = 0; + p_mtk_btif p_btif = &g_btif[0]; + + i_ret = _btif_resume(p_btif); + return i_ret; +} + +int mtk_btif_exp_enter_dpidle_test(void) +{ + return btif_dpidle_ctrl_no_id(BTIF_DPIDLE_ENABLE); +} + +int mtk_btif_exp_exit_dpidle_test(void) +{ + return btif_dpidle_ctrl_no_id(BTIF_DPIDLE_DISABLE); +} + +int mtk_btif_exp_log_debug_test(int flag) +{ + int i_ret = 0; + + i_ret = btif_dbg_ctrl_no_id(flag); + return i_ret; +} + +void mtk_btif_read_cpu_sw_rst_debug_exp(void) +{ + mtk_btif_read_cpu_sw_rst_debug(); +} + +/************End of Function**********/ diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h new file mode 100644 index 00000000000000..97756f684ab401 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_priv.h @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __HAL_BTIF_DMA_H_ +#define __HAL_BTIF_DMA_H_ + +#include +#include "btif_dma_pub.h" + +#if defined(CONFIG_MTK_CLKMGR) +#if defined(CONFIG_ARCH_MT6580) +#define MTK_BTIF_APDMA_CLK_CG MT_CG_APDMA_SW_CG +#elif defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || defined(CONFIG_ARCH_MT6753) +#define MTK_BTIF_APDMA_CLK_CG MT_CG_PERI_APDMA +#endif +#else +extern struct clk *clk_btif_apdma; /*btif apdma clock*/ +#endif /* !defined(CONFIG_MTK_CLKMGR) */ + +#define TX_DMA_VFF_SIZE (1024 * 8) /*Tx vFIFO Len must be 8 Byte allignment */ +#define RX_DMA_VFF_SIZE (1024 * 8) /*Rx vFIFO Len must be 8 Byte allignment */ + +#define DMA_TX_THRE(n) (n - 7) /*Tx Trigger Level */ +#define DMA_RX_THRE(n) ((n) * 3 / 4) /*Rx Trigger Level */ + +/**********************************Hardware related defination**************************/ +#ifndef CONFIG_OF +/*DMA channel's offset refer to AP_DMA's base address*/ +#define BTIF_TX_DMA_OFFSET 0x880 +#define BTIF_RX_DMA_OFFSET 0x900 +#endif + +/*Register Address Mapping*/ +#define DMA_INT_FLAG_OFFSET 0x00 +#define DMA_INT_EN_OFFSET 0x04 +#define DMA_EN_OFFSET 0x08 +#define DMA_RST_OFFSET 0x0C +#define DMA_STOP_OFFSET 0x10 +#define DMA_FLUSH_OFFSET 0x14 + +#define DMA_BASE_OFFSET 0x1C +#define DMA_LEN_OFFSET 0x24 + +#define DMA_THRE_OFFSET 0x28 +#define DMA_WPT_OFFSET 0x2C +#define DMA_RPT_OFFSET 0x30 +#define DMA_VALID_OFFSET 0x3C +#define DMA_LEFT_OFFSET 0x40 +#define DMA_VFF_BIT29_OFFSET 0x01 + +#define TX_DMA_INT_FLAG(base) (unsigned long)(base + 0x0) /*BTIF Tx Virtual FIFO Interrupt Flag Register */ +#define TX_DMA_INT_EN(base) (unsigned long)(base + 0x4) /*BTIF Tx Virtual FIFO Interrupt Enable Register */ +#define TX_DMA_EN(base) (unsigned long)(base + DMA_EN_OFFSET)/*BTIF Tx Virtual FIFO Enable Register */ +#define TX_DMA_RST(base) (unsigned long)(base + DMA_RST_OFFSET)/*BTIF Tx Virtual FIFO Reset Register */ +#define TX_DMA_STOP(base) (unsigned long)(base + DMA_STOP_OFFSET)/*BTIF Tx Virtual FIFO STOP Register */ +#define TX_DMA_FLUSH(base) (unsigned long)(base + DMA_FLUSH_OFFSET)/*BTIF Tx Virtual FIFO Flush Register */ +#define TX_DMA_VFF_ADDR(base) (unsigned long)(base + 0x1C) /*BTIF Tx Virtual FIFO Base Address Register */ +#define TX_DMA_VFF_LEN(base) (unsigned long)(base + 0x24) /*BTIF Tx Virtual FIFO Length Register */ +#define TX_DMA_VFF_THRE(base) (unsigned long)(base + 0x28) /*BTIF Tx Virtual FIFO Threshold Register */ +#define TX_DMA_VFF_WPT(base) (unsigned long)(base + 0x2C) /*BTIF Tx Virtual FIFO Write Pointer Register */ +#define TX_DMA_VFF_RPT(base) (unsigned long)(base + 0x30) /*BTIF Tx Virtual FIFO Read Pointer Register */ +#define TX_DMA_W_INT_BUF_SIZE(base) (unsigned long)(base + 0x34) +/*BTIF Tx Virtual FIFO Internal Tx Write Buffer Size Register */ +#define TX_DMA_INT_BUF_SIZE(base) (unsigned long)(base + 0x38) +/*BTIF Tx Virtual FIFO Internal Tx Buffer Size Register */ + +#define TX_DMA_VFF_VALID_SIZE(base) (unsigned long)(base + 0x3C) /*BTIF Tx Virtual FIFO Valid Size Register */ +#define TX_DMA_VFF_LEFT_SIZE(base) (unsigned long)(base + 0x40) /*BTIF Tx Virtual FIFO Left Size Register */ +#define TX_DMA_DEBUG_STATUS(base) (unsigned long)(base + 0x50) /*BTIF Tx Virtual FIFO Debug Status Register */ +#define TX_DMA_VFF_ADDR_H(base) (unsigned long)(base + 0x54) /*BTIF Tx Virtual FIFO Base High Address Register */ + +/*Rx Register Address Mapping*/ +#define RX_DMA_INT_FLAG(base) (unsigned long)(base + 0x0) /*BTIF Rx Virtual FIFO Interrupt Flag Register */ +#define RX_DMA_INT_EN(base) (unsigned long)(base + 0x4) /*BTIF Rx Virtual FIFO Interrupt Enable Register */ +#define RX_DMA_EN(base) (unsigned long)(base + DMA_EN_OFFSET) /*BTIF Rx Virtual FIFO Enable Register */ +#define RX_DMA_RST(base) (unsigned long)(base + DMA_RST_OFFSET) /*BTIF Rx Virtual FIFO Reset Register */ +#define RX_DMA_STOP(base) (unsigned long)(base + DMA_STOP_OFFSET) /*BTIF Rx Virtual FIFO Stop Register */ +#define RX_DMA_FLUSH(base) (unsigned long)(base + DMA_FLUSH_OFFSET) /*BTIF Rx Virtual FIFO Flush Register */ +#define RX_DMA_VFF_ADDR(base) (unsigned long)(base + 0x1C) /*BTIF Rx Virtual FIFO Base Address Register */ +#define RX_DMA_VFF_LEN(base) (unsigned long)(base + 0x24) /*BTIF Rx Virtual FIFO Length Register */ +#define RX_DMA_VFF_THRE(base) (unsigned long)(base + 0x28) /*BTIF Rx Virtual FIFO Threshold Register */ +#define RX_DMA_VFF_WPT(base) (unsigned long)(base + 0x2C) /*BTIF Rx Virtual FIFO Write Pointer Register */ +#define RX_DMA_VFF_RPT(base) (unsigned long)(base + 0x30) /*BTIF Rx Virtual FIFO Read Pointer Register */ +#define RX_DMA_FLOW_CTRL_THRE(base) (unsigned long)(base + 0x34) /*BTIF Rx Virtual FIFO Flow Control Register */ +#define RX_DMA_INT_BUF_SIZE(base) (unsigned long)(base + 0x38) /*BTIF Rx Virtual FIFO Internal Buffer Register */ +#define RX_DMA_VFF_VALID_SIZE(base) (unsigned long)(base + 0x3C) /*BTIF Rx Virtual FIFO Valid Size Register */ +#define RX_DMA_VFF_LEFT_SIZE(base) (unsigned long)(base + 0x40) /*BTIF Rx Virtual FIFO Left Size Register */ +#define RX_DMA_DEBUG_STATUS(base) (unsigned long)(base + 0x50) /*BTIF Rx Virtual FIFO Debug Status Register */ +#define RX_DMA_VFF_ADDR_H(base) (unsigned long)(base + 0x54) /*BTIF Rx Virtual FIFO Base High Address Register */ + +#define DMA_EN_BIT (0x1) +#define DMA_STOP_BIT (0x1) +#define DMA_RST_BIT (0x1) +#define DMA_FLUSH_BIT (0x1) + +#define DMA_WARM_RST (0x1 << 0) +#define DMA_HARD_RST (0x1 << 1) + +#define DMA_WPT_MASK (0x0000FFFF) +#define DMA_WPT_WRAP (0x00010000) + +#define DMA_RPT_MASK (0x0000FFFF) +#define DMA_RPT_WRAP (0x00010000) + +/*APDMA BTIF Tx Reg Ctrl Bit*/ +#define TX_DMA_INT_FLAG_MASK (0x1) + +#define TX_DMA_INTEN_BIT (0x1) + +#define TX_DMA_ADDR_MASK (0xFFFFFFF8) +#define TX_DMA_LEN_MASK (0x0000FFF8) + +#define TX_DMA_THRE_MASK (0x0000FFFF) + +#define TX_DMA_W_INT_BUF_MASK (0x000000FF) + +#define TX_DMA_VFF_VALID_MASK (0x0000FFFF) +#define TX_DMA_VFF_LEFT_MASK (0x0000FFFF) + +/*APDMA BTIF Rx Reg Ctrl Bit*/ +#define RX_DMA_INT_THRE (0x1 << 0) +#define RX_DMA_INT_DONE (0x1 << 1) + +#define RX_DMA_INT_THRE_EN (0x1 << 0) +#define RX_DMA_INT_DONE_EN (0x1 << 1) + +#define RX_DMA_ADDR_MASK (0xFFFFFFF8) +#define RX_DMA_LEN_MASK (0x0000FFF8) + +#define RX_DMA_THRE_MASK (0x0000FFFF) + +#define RX_DMA_FLOW_CTRL_THRE_MASK (0x000000FF) + +#define RX_DMA_INT_BUF_SIZE_MASK (0x0000001F) + +#define RX_DMA_VFF_VALID_MASK (0x0000001F) + +#define RX_DMA_VFF_LEFT_MASK (0x0000FFFF) + +typedef struct _MTK_BTIF_DMA_VFIFO_ { + DMA_VFIFO vfifo; + unsigned int wpt; /*DMA's write pointer, which is maintained by SW for Tx DMA and HW for Rx DMA */ + unsigned int last_wpt_wrap; /*last wrap bit for wpt */ + unsigned int rpt; /*DMA's read pointer, which is maintained by HW for Tx DMA and SW for Rx DMA */ + unsigned int last_rpt_wrap; /*last wrap bit for rpt */ +} MTK_BTIF_DMA_VFIFO, *P_MTK_BTIF_DMA_VFIFO; + +/*for DMA debug purpose*/ +typedef struct _MTK_BTIF_DMA_REG_DMP_DBG_ { + unsigned long reg_addr; + unsigned int reg_val; +} MTK_BTIF_DMA_REG_DMP_DBG, *P_MTK_BTIF_DMA_REG_DMP_DBG; + +#endif /*__HAL_BTIF_DMA_H_*/ diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h new file mode 100644 index 00000000000000..0773f2ce387ac8 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_dma_pub.h @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __HAL_BTIFD_DMA_PUB_H_ +#define __HAL_BTIFD_DMA_PUB_H_ + +#include + +#include "plat_common.h" + +typedef enum _ENUM_DMA_CTRL_ { + DMA_CTRL_DISABLE = 0, + DMA_CTRL_ENABLE = DMA_CTRL_DISABLE + 1, + DMA_CTRL_BOTH, +} ENUM_DMA_CTRL; + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_info_get +* DESCRIPTION +* get btif tx dma channel's information +* PARAMETERS +* dma_dir [IN] DMA's direction +* RETURNS +* pointer to btif dma's information structure +*****************************************************************************/ +P_MTK_DMA_INFO_STR hal_btif_dma_info_get(ENUM_DMA_DIR dma_dir); + +/***************************************************************************** +* FUNCTION +* hal_btif_dma_hw_init +* DESCRIPTION +* control clock output enable/disable of DMA module +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_dma_hw_init(P_MTK_DMA_INFO_STR p_dma_info); + +/***************************************************************************** +* FUNCTION +* hal_btif_clk_ctrl +* DESCRIPTION +* control clock output enable/disable of DMA module +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_dma_clk_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_CLOCK_CTRL flag); + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_ctrl +* DESCRIPTION +* enable/disable Tx DMA channel +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* ctrl_id [IN] enable/disable ID +* dma_dir [IN] DMA's direction +* RETURNS +* 0 means success; negative means fail +*****************************************************************************/ +int hal_btif_dma_ctrl(P_MTK_DMA_INFO_STR p_dma_info, ENUM_DMA_CTRL ctrl_id); + +/***************************************************************************** +* FUNCTION +* hal_btif_dma_rx_cb_reg +* DESCRIPTION +* register rx callback function to dma module +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* rx_cb [IN] function pointer to btif +* RETURNS +* 0 means success; negative means fail +*****************************************************************************/ +int hal_btif_dma_rx_cb_reg(P_MTK_DMA_INFO_STR p_dma_info, + dma_rx_buf_write rx_cb); + +/***************************************************************************** +* FUNCTION +* hal_tx_vfifo_reset +* DESCRIPTION +* reset tx virtual fifo information, except memory information +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* dma_dir [IN] DMA's direction +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_vfifo_reset(P_MTK_DMA_INFO_STR p_dma_info); + +/***************************************************************************** +* FUNCTION +* hal_tx_dma_irq_handler +* DESCRIPTION +* lower level tx interrupt handler +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_tx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info); + +/***************************************************************************** +* FUNCTION +* hal_dma_send_data +* DESCRIPTION +* send data through btif in DMA mode +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* p_buf [IN] pointer to rx data buffer +* max_len [IN] tx buffer length +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_dma_send_data(P_MTK_DMA_INFO_STR p_dma_info, + const unsigned char *p_buf, const unsigned int buf_len); + +/***************************************************************************** +* FUNCTION +* hal_dma_is_tx_complete +* DESCRIPTION +* get tx complete flag +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* true means tx complete, false means tx in process +*****************************************************************************/ +bool hal_dma_is_tx_complete(P_MTK_DMA_INFO_STR p_dma_info); + +/***************************************************************************** +* FUNCTION +* hal_dma_get_ava_room +* DESCRIPTION +* get tx available room +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* available room size +*****************************************************************************/ +int hal_dma_get_ava_room(P_MTK_DMA_INFO_STR p_dma_info); + +/***************************************************************************** +* FUNCTION +* hal_dma_is_tx_allow +* DESCRIPTION +* is tx operation allowed by DMA +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* RETURNS +* true if tx operation is allowed; false if tx is not allowed +*****************************************************************************/ +bool hal_dma_is_tx_allow(P_MTK_DMA_INFO_STR p_dma_info); + +/***************************************************************************** +* FUNCTION +* hal_rx_dma_irq_handler +* DESCRIPTION +* lower level rx interrupt handler +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_rx_dma_irq_handler(P_MTK_DMA_INFO_STR p_dma_info, + unsigned char *p_buf, const unsigned int max_len); + +/***************************************************************************** +* FUNCTION +* hal_dma_dump_reg +* DESCRIPTION +* dump BTIF module's information when needed +* PARAMETERS +* p_dma_info [IN] pointer to BTIF dma channel's information +* flag [IN] register id flag +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_dma_dump_reg(P_MTK_DMA_INFO_STR p_dma_info, ENUM_BTIF_REG_ID flag); + +int hal_dma_pm_ops(P_MTK_DMA_INFO_STR p_dma_info, MTK_BTIF_PM_OPID opid); + +#endif /*__HAL_BTIFD_DMA_PUB_H_*/ diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h new file mode 100644 index 00000000000000..51fe58a82b49c2 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_priv.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __HAL_BTIF_H_ +#define __HAL_BTIF_H_ + +#ifndef CONFIG_OF +#define MTK_BTIF_REG_BASE BTIF_BASE +#endif + +#if defined(CONFIG_MTK_CLKMGR) +#if defined(CONFIG_ARCH_MT6580) +#define MTK_BTIF_CG_BIT MT_CG_BTIF_SW_CG +#elif defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || defined(CONFIG_ARCH_MT6753) +#define MTK_BTIF_CG_BIT MT_CG_PERI_BTIF +#endif +#else +struct clk *clk_btif_apdma; /*btif apdma clock*/ +struct clk *clk_btif; /*btif clock*/ +#endif /* !defined(CONFIG_MTK_CLKMGR) */ + +#define BTIF_RBR(base) (unsigned long)(base + 0x0) /*RX Buffer Register: read only */ +#define BTIF_THR(base) (unsigned long)(base + 0x0) /*Rx Holding Register: write only */ +#define BTIF_IER(base) (unsigned long)(base + 0x4) /*Interrupt Enable Register: read/write */ +#define BTIF_IIR(base) (unsigned long)(base + 0x8) /*Interrupt Identification Register: read only */ +#define BTIF_FIFOCTRL(base) (unsigned long)(base + 0x8) /*FIFO Control Register: write only */ +#define BTIF_FAKELCR(base) (unsigned long)(base + 0xC) /*FAKE LCR Register: read/write */ +#define BTIF_LSR(base) (unsigned long)(base + 0x14) /*Line Status Register: read only */ +#define BTIF_SLEEP_EN(base) (unsigned long)(base + 0x48) /*Sleep Enable Register: read/write */ +#define BTIF_DMA_EN(base) (unsigned long)(base + 0x4C) /*DMA Enable Register: read/write */ +#define BTIF_RTOCNT(base) (unsigned long)(base + 0x54) /*Rx Timeout Count Register: read/write */ +#define BTIF_TRI_LVL(base) (unsigned long)(base + 0x60) /*Tx/Rx Trigger Level Control Register: read/write */ +#define BTIF_WAK(base) (unsigned long)(base + 0x64) /*BTIF module wakeup Register: write only */ +#define BTIF_WAT_TIME(base) (unsigned long)(base + 0x68) /*BTIF ASYNC Wait Time Control Register: read/write */ +#define BTIF_HANDSHAKE(base) (unsigned long)(base + 0x6C) /*BTIF New Handshake Control Register: read/write */ + +/*BTIF_IER bits*/ +#define BTIF_IER_TXEEN (0x1 << 1) /*1: Tx holding register is empty */ +#define BTIF_IER_RXFEN (0x1 << 0) /*1: Rx buffer contains data */ + +/*BTIF_IIR bits*/ +#define BTIF_IIR_NINT (0x1 << 0) /*No INT Pending */ +#define BTIF_IIR_TX_EMPTY (0x1 << 1) /*Tx Holding Register empty */ +#define BTIF_IIR_RX (0x1 << 2) /*Rx data received */ +#define BTIF_IIR_RX_TIMEOUT (0x11 << 2) /*Rx data received */ + +/*BTIF_LSR bits*/ +#define BTIF_LSR_DR_BIT (0x1 << 0) +#define BTIF_LSR_THRE_BIT (0x1 << 5) +#define BTIF_LSR_TEMT_BIT (0x1 << 6) + +/*BTIF_FIFOCTRL bits*/ +#define BTIF_FIFOCTRL_CLR_TX (0x1 << 2) /*Clear Tx FIRO */ +#define BTIF_FIFOCTRL_CLR_RX (0x1 << 1) /*Clear Rx FIRO */ + +/*BTIF_FAKELCR bits*/ +#define BTIF_FAKELCR_NORMAL_MODE 0x0 + +/*BTIF_SLEEP_EN bits*/ +#define BTIF_SLEEP_EN_BIT (0x1 << 0) /*enable Sleep mode */ +#define BTIF_SLEEP_DIS_BIT (0x0) /*disable sleep mode */ + +/*BTIF_DMA_EN bits*/ +#define BTIF_DMA_EN_RX (0x1 << 0) /*Enable Rx DMA */ +#define BTIF_DMA_EN_TX (0x1 << 1) /*Enable Tx DMA */ +#define BTIF_DMA_EN_AUTORST_EN (0x1 << 2) /*1: timeout counter will be auto reset */ +#define BTIF_DMA_EN_AUTORST_DIS (0x0 << 2) /* + * 0: after Rx timeout happens, + * SW shall reset the interrupt by reading BTIF 0x4C + */ + +/*BTIF_TRI_LVL bits*/ +#define BTIF_TRI_LVL_TX_MASK ((0xf) << 0) +#define BTIF_TRI_LVL_RX_MASK ((0x7) << 4) + +#define BTIF_TRI_LVL_TX(x) ((x & 0xf) << 0) +#define BTIF_TRI_LVL_RX(x) ((x & 0x7) << 4) + +#define BTIF_TRI_LOOP_EN (0x1 << 7) +#define BTIF_TRI_LOOP_DIS (0x0 << 7) + +/*BTIF_WAK bits*/ +#define BTIF_WAK_BIT (0x1 << 0) + +/*BTIF_HANDSHAKE bits*/ +#define BTIF_HANDSHAKE_EN_HANDSHAKE 1 +#define BTIF_HANDSHAKE_DIS_HANDSHAKE 0 + +#define BTIF_TX_FIFO_SIZE 16 +#define BTIF_RX_FIFO_SIZE 8 + +#define BTIF_TX_FIFO_THRE (BTIF_TX_FIFO_SIZE / 2) +#define BTIF_RX_FIFO_THRE 0x1 /* 0x5 */ + +#endif /*__HAL_BTIF_H_*/ diff --git a/drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h b/drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h new file mode 100644 index 00000000000000..1555d5a50c384d --- /dev/null +++ b/drivers/misc/mediatek/btif/common/plat_inc/btif_pub.h @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __HAL_BTIF_PUB_H_ +#define __HAL_BTIF_PUB_H_ + +#include "plat_common.h" + +/*Enum Defination*/ +/*BTIF Mode Enum */ +typedef enum _ENUM_BTIF_MODE_ { + BTIF_MODE_PIO = 0, + BTIF_MODE_DMA = BTIF_MODE_PIO + 1, + BTIF_MODE_MAX, +} ENUM_BTIF_MODE; + +/***************************************************************************** +* FUNCTION +* hal_btif_info_get +* DESCRIPTION +* get btif's information included base address , irq related information +* PARAMETERS +* RETURNS +* BTIF's information +*****************************************************************************/ +P_MTK_BTIF_INFO_STR hal_btif_info_get(void); + +#if 0 /*included in hal_btif_info_get */ +/***************************************************************************** +* FUNCTION +* hal_btif_get_irq +* DESCRIPTION +* get BTIF module's IRQ information +* PARAMETERS +* RETURNS +* pointer to BTIF's irq structure +*****************************************************************************/ +P_MTK_BTIF_IRQ_STR hal_btif_get_irq(void); +#endif + +#if !defined(CONFIG_MTK_CLKMGR) +/***************************************************************************** +* FUNCTION +* hal_btif_clk_get_and_prepare +* DESCRIPTION +* get clock from device tree and prepare for enable/disable control +* PARAMETERS +* pdev device pointer +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_clk_get_and_prepare(struct platform_device *pdev); +/***************************************************************************** +* FUNCTION +* hal_btif_clk_unprepare +* DESCRIPTION +* unprepare btif clock and apdma clock +* PARAMETERS +* none +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_clk_unprepare(void); +#endif +/***************************************************************************** +* FUNCTION +* hal_btif_clk_ctrl +* DESCRIPTION +* control clock output enable/disable of BTIF module +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_clk_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_CLOCK_CTRL flag); + +/***************************************************************************** +* FUNCTION +* hal_btif_hw_init +* DESCRIPTION +* BTIF module init, after this step, BTIF should enable to do tx/rx with PIO +* mode +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_hw_init(P_MTK_BTIF_INFO_STR p_btif); + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_cb_reg +* DESCRIPTION +* BTIF rx callback register API +* PARAMETERS +* p_btif_info [IN] pointer to BTIF's information +* rx_cb [IN] rx callback function +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_rx_cb_reg(P_MTK_BTIF_INFO_STR p_btif_info, + btif_rx_buf_write rx_cb); + +/***************************************************************************** +* FUNCTION +* hal_btif_loopback_ctrl +* DESCRIPTION +* BTIF Tx/Rx loopback mode set, this operation can only be done +* after set BTIF to normal mode +* PARAMETERS +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_loopback_ctrl(P_MTK_BTIF_INFO_STR p_btif, bool en); + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_handler +* DESCRIPTION +* lower level interrupt handler +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN/OUT] pointer to rx data buffer +* max_len [IN] max length of rx buffer +* RETURNS +* 0 means success; negative means fail; positive means rx data length +*****************************************************************************/ +int hal_btif_irq_handler(P_MTK_BTIF_INFO_STR p_btif, + unsigned char *p_buf, const unsigned int max_len); + +/***************************************************************************** +* FUNCTION +* hal_btif_tx_mode_ctrl +* DESCRIPTION +* set BTIF tx to corresponding mode (PIO/DMA) +* PARAMETERS +* p_base [IN] BTIF module's base address +* mode [IN] rx mode +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_tx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode); + +/***************************************************************************** +* FUNCTION +* hal_btif_rx_mode_ctrl +* DESCRIPTION +* set BTIF rx to corresponding mode (PIO/DMA) +* PARAMETERS +* p_base [IN] BTIF module's base address +* mode [IN] rx mode +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_rx_mode_ctrl(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_MODE mode); + +/***************************************************************************** +* FUNCTION +* hal_btif_send_data +* DESCRIPTION +* send data through btif in FIFO mode +* PARAMETERS +* p_base [IN] BTIF module's base address +* p_buf [IN] pointer to rx data buffer +* max_len [IN] tx buffer length +* RETURNS +* positive means number of data sent; +* 0 means no data put to FIFO; +* negative means error happens +*****************************************************************************/ +int hal_btif_send_data(P_MTK_BTIF_INFO_STR p_btif, + const unsigned char *p_buf, const unsigned int buf_len); + +/***************************************************************************** +* FUNCTION +* hal_btif_raise_wak_sig +* DESCRIPTION +* raise wakeup signal to counterpart +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_raise_wak_sig(P_MTK_BTIF_INFO_STR p_btif); + +/***************************************************************************** +* FUNCTION +* hal_btif_dump_reg +* DESCRIPTION +* dump BTIF module's information when needed +* PARAMETERS +* p_base [IN] BTIF module's base address +* flag [IN] register id flag +* RETURNS +* 0 means success, negative means fail +*****************************************************************************/ +int hal_btif_dump_reg(P_MTK_BTIF_INFO_STR p_btif, ENUM_BTIF_REG_ID flag); + +/***************************************************************************** +* FUNCTION +* hal_btif_is_tx_complete +* DESCRIPTION +* get tx complete flag +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* true means tx complete, false means tx in process +*****************************************************************************/ +bool hal_btif_is_tx_complete(P_MTK_BTIF_INFO_STR p_btif); + +/***************************************************************************** +* FUNCTION +* hal_btif_is_tx_allow +* DESCRIPTION +* whether tx is allowed +* PARAMETERS +* p_base [IN] BTIF module's base address +* RETURNS +* true if tx operation is allowed; false if tx is not allowed +*****************************************************************************/ +bool hal_btif_is_tx_allow(P_MTK_BTIF_INFO_STR p_btif); + +int hal_btif_pm_ops(P_MTK_BTIF_INFO_STR p_btif, MTK_BTIF_PM_OPID opid); + +void mtk_btif_read_cpu_sw_rst_debug_plat(void); + +#endif /*__HAL_BTIF_PUB_H_*/ diff --git a/drivers/misc/mediatek/btif/common/plat_inc/plat_common.h b/drivers/misc/mediatek/btif/common/plat_inc/plat_common.h new file mode 100644 index 00000000000000..2a1462cb32ff46 --- /dev/null +++ b/drivers/misc/mediatek/btif/common/plat_inc/plat_common.h @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __HAL_PUB_H_ +#define __HAL_PUB_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_OF +#include +#include +#include +#else +#include +#include +#endif +#if defined(CONFIG_MTK_CLKMGR) +#include +#else +#include +#include +#endif /* defined(CONFIG_MTK_CLKMGR) */ +#include + +extern int mtk_btif_hal_get_log_lvl(void); + +#define MTK_BTIF_MARK_UNUSED_API + +typedef irq_handler_t mtk_btif_irq_handler; + +#define MTK_BTIF_ENABLE_CLK_CTL 1 +#define MTK_BTIF_ENABLE_CLK_REF_COUNTER 1 + +#define DBG_LOG_STR_SIZE 256 + +/*Log defination*/ +static int hal_log_print(const char *str, ...) +{ + va_list args; + char temp_sring[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(temp_sring, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + pr_err("%s", temp_sring); + + return 0; +} + +#define BTIF_LOG_LOUD 4 +#define BTIF_LOG_DBG 3 +#define BTIF_LOG_INFO 2 +#define BTIF_LOG_WARN 1 +#define BTIF_LOG_ERR 0 + +#ifndef DFT_TAG +#define DFT_TAG "[BTIF-DFT]" +#endif + +#define BTIF_LOUD_FUNC(fmt, arg ...) \ +do { \ + if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_LOUD) \ + hal_log_print(DFT_TAG "[L]%s:" fmt, \ + __func__, ## arg); \ +} while (0) + +#define BTIF_INFO_FUNC(fmt, arg ...) \ +do { \ + if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_INFO)\ + hal_log_print(DFT_TAG "[I]%s:" fmt, \ + __func__, ## arg); \ +} while (0) + +#define BTIF_WARN_FUNC(fmt, arg ...) \ +do { \ + if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_WARN)\ + hal_log_print(DFT_TAG "[W]%s:" fmt, \ + __func__, ## arg); \ +} while (0) + +#define BTIF_ERR_FUNC(fmt, arg ...)\ +do {\ + if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_ERR)\ + hal_log_print(DFT_TAG "[E]%s(%d):" fmt,\ + __func__, __LINE__, ## arg);\ +} while (0) + +#define BTIF_DBG_FUNC(fmt, arg ...) \ +do { \ + if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_DBG) \ + hal_log_print(DFT_TAG "[D]%s:" fmt, \ + __func__, ## arg); \ +} while (0) + +#define BTIF_TRC_FUNC(f) \ +do { \ + if (mtk_btif_hal_get_log_lvl() >= BTIF_LOG_DBG) \ + hal_log_print(DFT_TAG "<%s> <%d>\n", \ + __func__, __LINE__); \ +} while (0) + +/*-----------------------------------Enum Defination--------------------------------*/ +/*IRQ sensetive type */ +typedef enum _ENUM_IRQ_SENS_TYPE_ { + IRQ_SENS_EDGE = 0, + IRQ_SENS_LVL = IRQ_SENS_EDGE + 1, + IRQ_SENS_TYPE_MAX +} ENUM_IRQ_SENS_TYPE; + +/*IRQ level trigger type */ +typedef enum _ENUM_IRQ_LVL_TYPE_ { + IRQ_LVL_LOW = 0, + IRQ_LVL_HIGH = IRQ_LVL_LOW + 1, + IRQ_LVL_MAX +} ENUM_IRQ_LVL; + +/*IRQ edge trigger type */ +typedef enum _ENUM_IRQ_EDGE_TYPE_ { + IRQ_EDGE_FALL = 0, + IRQ_EDGE_RAISE = IRQ_EDGE_FALL + 1, + IRQ_EDGE_BOTH = IRQ_EDGE_RAISE + 1, + IRQ_EDGE_MAX +} ENUM_IRQ_EDGE; + +typedef enum _ENUM_CLOCK_CTRL_ { + CLK_OUT_DISABLE = 0, + CLK_OUT_ENABLE = CLK_OUT_DISABLE + 1, + CLK_OUT_MAX +} ENUM_CLOCK_CTRL; + +/*Error No. table */ +typedef enum _ENUM_ERROR_CODE_ { + ERR_NO_ERROR = 0, + ERR_INVALID_PAR = ERR_NO_ERROR - 1, + ERR_MAX = ERR_INVALID_PAR - 1, +} ENUM_ERROR_CODE; + +typedef enum _ENUM_BTIF_DIR_ { + BTIF_TX = 0, + BTIF_RX = BTIF_TX + 1, + BTIF_DIR_MAX, +} ENUM_BTIF_DIR; + +typedef enum _ENUM_DMA_DIR_ { + DMA_DIR_RX = 0, + DMA_DIR_TX = DMA_DIR_RX + 1, + DMA_DIR_BOTH, +} ENUM_DMA_DIR; + +typedef enum _ENUM_BTIF_REG_ID_ { + REG_IIR = 0, /*Interrupt Identification Register */ + REG_LSR = 1, /*Line Status Register */ + REG_FAKE_LCR = 2, /*Fake Lcr Regiseter */ + REG_FIFO_CTRL = 3, /*FIFO Control Register */ + REG_IER = 4, /*Interrupt Enable Register */ + REG_SLEEP_EN = 5, /*Sleep Enable Register */ + REG_RTO_COUNTER = 6, /*Rx Timeout Counter Register */ + REG_DMA_EN = 7, /*DMA Enalbe Register */ + REG_TRIG_LVL = 8, /*Tx/Rx Trigger Level Register */ + REG_WAT_TIME = 9, /*Async Wait Time Register */ + REG_HANDSHAKE = 10, /*New HandShake Mode Register */ + REG_SLP_WAK = 11, /*Sleep Wakeup Reigster */ + REG_BTIF_ALL = 12, /*all btif controller's registers */ + REG_TX_DMA_ALL = 13, + REG_RX_DMA_ALL = 14, + REG_MAX +} ENUM_BTIF_REG_ID; + +typedef enum _MTK_BTIF_PM_OPID_ { + BTIF_PM_DPIDLE_EN, + BTIF_PM_DPIDLE_DIS, + BTIF_PM_SUSPEND, + BTIF_PM_RESUME, + BTIF_PM_RESTORE_NOIRQ, +} MTK_BTIF_PM_OPID; + +#define BTIF_HAL_TX_FIFO_SIZE (1024 * 4) + +/*-----------------------------------Enum Defination End--------------------------------*/ + +/*****************************structure definition***************************/ +/*IRQ related information*/ +typedef struct _MTK_BTIF_IRQ_STR_ { + const char *name; + bool is_irq_sup; + unsigned int irq_id; +#ifdef CONFIG_OF + unsigned int irq_flags; +#else + ENUM_IRQ_SENS_TYPE sens_type; + union { + ENUM_IRQ_LVL lvl_type; + ENUM_IRQ_EDGE edge_type; + }; +#endif + bool reg_flag; + irq_handler_t p_irq_handler; +} MTK_BTIF_IRQ_STR, *P_MTK_BTIF_IRQ_STR; + +typedef struct _DMA_VFIFO_ { + /*[Driver Access] vFIFO memory'svirtual address */ + unsigned char *p_vir_addr; + /*[HW Access] dma handle , physically address, set to DMA's HW Register */ + dma_addr_t phy_addr; + /*DMA's vFIFO size */ + unsigned int vfifo_size; + /*DMA's threshold value */ + unsigned int thre; +} DMA_VFIFO, *P_DMA_VFIFO; + +typedef unsigned int (*dma_rx_buf_write) (void *p_dma_info, + unsigned char *p_buf, + unsigned int buf_len); +typedef unsigned int (*btif_rx_buf_write) (void *p_btif_info, + unsigned char *p_buf, + unsigned int buf_len); + +/*DMA related information*/ +typedef struct _MTK_DMA_INFO_STR_ { + unsigned long base; + ENUM_DMA_DIR dir; + P_MTK_BTIF_IRQ_STR p_irq; + dma_rx_buf_write rx_cb; + P_DMA_VFIFO p_vfifo; +} MTK_DMA_INFO_STR, *P_MTK_DMA_INFO_STR; + +/*DMA related information*/ +typedef struct _MTK_BTIF_INFO_STR_ { + unsigned long base; /*base address */ + P_MTK_BTIF_IRQ_STR p_irq; /*irq related information */ + + unsigned int tx_fifo_size; /*BTIF tx FIFO size */ + unsigned int rx_fifo_size; /*BTIF rx FIFO size */ + + unsigned int tx_tri_lvl; /*BTIFtx trigger level in FIFO mode */ + unsigned int rx_tri_lvl; /*BTIFrx trigger level in FIFO mode */ + + unsigned int clk_gat_addr; /*clock gating address */ + unsigned int set_bit; /*enable clock gating bit */ + unsigned int clr_bit; /*clear clock gating bit */ + + unsigned int rx_data_len; /*rx data length */ + + btif_rx_buf_write rx_cb; + + struct kfifo *p_tx_fifo; /*tx fifo */ + spinlock_t tx_fifo_spinlock; /*tx fifo spinlock */ +} MTK_BTIF_INFO_STR, *P_MTK_BTIF_INFO_STR; + +/**********End of Structure Definition***********/ + +/***********register operation***********/ +#ifdef __KERNEL__ +/*byte write <1 byte> */ +#define btif_reg_sync_writeb(v, a) mt_reg_sync_writeb(v, a) +/*word write <2 byte> */ +#define btif_reg_sync_writew(v, a) mt_reg_sync_writew(v, a) +/*long write <4 byte> */ +#define btif_reg_sync_writel(v, a) mt_reg_sync_writel(v, a) +#else +/*byte write <1 byte> */ +#define btif_reg_sync_writeb(v, a) mt65xx_reg_sync_writeb(v, a) +/*word write <2 byte> */ +#define btif_reg_sync_writew(v, a) mt65xx_reg_sync_writew(v, a) +/*long write <4 byte> */ +#define btif_reg_sync_writel(v, a) mt65xx_reg_sync_writel(v, a) +#endif +#define BTIF_READ8(REG) __raw_readb((unsigned char *)(REG)) +#define BTIF_READ16(REG) __raw_readw((unsigned short *)(REG)) +#define BTIF_READ32(REG) __raw_readl((unsigned int *)(REG)) + +#define BTIF_SET_BIT(REG, BITVAL) do { \ +*((volatile unsigned int *)(REG)) |= ((unsigned int)(BITVAL)); \ +mb(); /**/ \ +} \ +while (0) +#define BTIF_CLR_BIT(REG, BITVAL) do { \ +(*(volatile unsigned int *)(REG)) &= ~((unsigned int)(BITVAL)); \ +mb(); /**/\ +} \ +while (0) + +/***********end of register operation *********/ + +#endif /*__HAL_PUB_H_*/ diff --git a/drivers/misc/mediatek/conn_md/include/conn_md.h b/drivers/misc/mediatek/conn_md/include/conn_md.h new file mode 100644 index 00000000000000..e26341b7d1bd12 --- /dev/null +++ b/drivers/misc/mediatek/conn_md/include/conn_md.h @@ -0,0 +1,69 @@ +#ifndef __CONN_MD_H_ +#define __CONN_MD_H_ + + + +#include "conn_md_exp.h" +#include "conn_md_dump.h" + + +/*-----------------------Data Structure Definition-----------------------*/ + +typedef enum { + USER_MIN, + USER_REGED, + USER_ENABLED, + USER_DISABLED, + USER_UNREGED, + USER_MAX, +} USER_STATE; + +typedef struct _CONN_MD_USER_ { + uint32 u_id; + USER_STATE state; + CONN_MD_BRIDGE_OPS ops; + struct list_head entry; +} CONN_MD_USER, *P_CONN_MD_USER; + + +typedef struct _CONN_MD_MSG_ { + ipc_ilm_t ilm; + struct list_head entry; + local_para_struct local_para; +} CONN_MD_MSG, *P_CONN_MD_MSG; + + +typedef struct _CONN_MD_QUEUE_ { + struct list_head list; + struct mutex lock; + uint32 counter; +} CONN_MD_QUEUE, *P_CONN_MD_QUEUE; + + +typedef struct _CONN_MD_USER_LIST_ { + uint32 counter; + struct list_head list; + struct mutex lock; /*lock for user add/delete/check */ +} CONN_MD_USER_LIST, *P_CONN_MD_USER_LIST; + +typedef struct _CONN_MD_STRUCT_ { + /*con-md-thread used for tx queue handle */ + struct task_struct *p_task; + struct completion tx_comp; + + CONN_MD_USER_LIST user_list; + CONN_MD_QUEUE act_queue; + CONN_MD_QUEUE msg_queue; + P_CONN_MD_DMP_MSG_LOG p_msg_dmp_sys; + +} CONN_MD_STRUCT, *P_CONN_MD_STRUCT; + +extern int conn_md_send_msg(ipc_ilm_t *ilm); +extern int conn_md_del_user(uint32 u_id); +extern int conn_md_add_user(uint32 u_id, CONN_MD_BRIDGE_OPS *p_ops); +extern int conn_md_dmp_msg_logged(uint32 src_id, uint32 dst_id); +extern int conn_md_dmp_msg_active(uint32 src_id, uint32 dst_id); +extern int conn_md_dmp_msg_queued(uint32 src_id, uint32 dst_id); + + +#endif diff --git a/drivers/misc/mediatek/conn_md/include/conn_md_dbg.h b/drivers/misc/mediatek/conn_md/include/conn_md_dbg.h new file mode 100644 index 00000000000000..922a80dc0580f6 --- /dev/null +++ b/drivers/misc/mediatek/conn_md/include/conn_md_dbg.h @@ -0,0 +1,15 @@ +#ifndef __CONN_MD_DBG_H_ +#define __CONN_MD_DBG_H_ + +#ifdef ARRAY_SIZE +#undef ARRAY_SIZE +#define ARRAY_SIZE(x) sizeof(x)/sizeof(x[0]) +#endif + +typedef int (*CONN_MD_DEV_DBG_FUNC) (int par1, int par2, int par3); + +extern int conn_md_dbg_init(void); + +extern int conn_md_test(void); + +#endif/*__CONN_MD_DBG_H_*/ diff --git a/drivers/misc/mediatek/conn_md/include/conn_md_dump.h b/drivers/misc/mediatek/conn_md/include/conn_md_dump.h new file mode 100644 index 00000000000000..9c3b783bb8339c --- /dev/null +++ b/drivers/misc/mediatek/conn_md/include/conn_md_dump.h @@ -0,0 +1,47 @@ +#ifndef __CONN_MD_DUMP_H_ +#define __CONN_MD_DUMP_H_ + +#include "conn_md_log.h" +#include "conn_md_exp.h" + +#define LENGTH_PER_PACKAGE 8 +#define NUMBER_OF_MSG_LOGGED 16 + + +typedef enum { + MSG_ENQUEUE = 1, + MSG_DEQUEUE = 2, + MSG_EN_DE_QUEUE = 3, +} CONN_MD_MSG_TYPE; + + +typedef struct _CONN_MD_DMP_MSG_STR_ { + unsigned int sec; + unsigned int usec; + CONN_MD_MSG_TYPE type; + ipc_ilm_t ilm; + uint16 msg_len; + uint8 data[LENGTH_PER_PACKAGE]; +} CONN_MD_DMP_MSG_STR, *P_CONN_MD_DMP_MSG_STR; + + +typedef struct _CONN_MD_DMP_MSG_LOG_ { + + CONN_MD_DMP_MSG_STR msg[NUMBER_OF_MSG_LOGGED]; + uint16 in; + uint16 out; + uint32 size; + struct mutex lock; + +} CONN_MD_DMP_MSG_LOG, *P_CONN_MD_DMP_MSG_LOG; + + +extern P_CONN_MD_DMP_MSG_LOG conn_md_dmp_init(void); +extern int conn_md_dmp_deinit(P_CONN_MD_DMP_MSG_LOG p_log); + + +extern int conn_md_dmp_in(ipc_ilm_t *p_ilm, CONN_MD_MSG_TYPE msg_type, + P_CONN_MD_DMP_MSG_LOG p_msg_log); +extern int conn_md_dmp_out(P_CONN_MD_DMP_MSG_LOG p_msg_log, uint32 src_id, uint32 dst_id); + +#endif diff --git a/drivers/misc/mediatek/conn_md/include/conn_md_exp.h b/drivers/misc/mediatek/conn_md/include/conn_md_exp.h new file mode 100644 index 00000000000000..7832db720e5160 --- /dev/null +++ b/drivers/misc/mediatek/conn_md/include/conn_md_exp.h @@ -0,0 +1,63 @@ +#ifndef __CONN_MD_EXP_H_ +#define __CONN_MD_EXP_H_ + + +#if defined(CONFIG_MTK_ECCCI_DRIVER) || defined(CONFIG_MTK_ECCCI_DRIVER_MODULE) +#include "port_ipc.h" /*data structure is defined here, mediatek/kernel/drivers/eccci */ +#include "ccci_ipc_task_ID.h" /*IPC task id is defined here, mediatek/kernel/drivers/eccci */ +typedef unsigned int uint32; +typedef unsigned char uint8; +typedef unsigned short uint16; +#ifdef CHAR +#undef CHAR +#endif +#define IPC_HEADER_FILE_INCLUDED 1 +#endif + +#ifndef IPC_HEADER_FILE_INCLUDED +/* #if defined(CONFIG_MTK_EEMCS_DEVICES) || defined(CONFIG_MTK_EEMCS_DEVICES_MODULE) */ +#include "eemcs_ipc.h" /*data structure is defined here, mediatek/kernel/drivers/eemcs */ +#include "eemcs_ipc_task_ID.h" /*IPC task id is defined here, mediatek/kernel/drivers/eemcs */ +/* #endif */ +#endif +typedef enum { + CONN_MD_ERR_NO_ERR = 0, + CONN_MD_ERR_DEF_ERR = -1, + CONN_MD_ERR_INVALID_PARAM = -2, + CONN_MD_ERR_OTHERS = -4, + +} CONN_MD_ERR_CODE; + + +/*For IDC test*/ +typedef int (*CONN_MD_MSG_RX_CB) (conn_md_ipc_ilm_t *ilm); + +typedef struct { + CONN_MD_MSG_RX_CB rx_cb; +} CONN_MD_BRIDGE_OPS, *P_CONN_MD_BRIDGE_OPS; + +//extern int mtk_conn_md_bridge_reg(uint32 u_id, CONN_MD_BRIDGE_OPS *p_ops); +//extern int mtk_conn_md_bridge_unreg(uint32 u_id); +//extern int mtk_conn_md_bridge_send_msg(conn_md_ipc_ilm_t *ilm); + +#if 1 +extern int __weak mtk_conn_md_bridge_reg(uint32 u_id, CONN_MD_BRIDGE_OPS *p_ops) +{ + pr_err(KERN_ERR "MTK_CONN Weak FUNCTION~~~\n"); + return 0; +} + +extern int __weak mtk_conn_md_bridge_unreg(uint32 u_id) +{ + pr_err(KERN_ERR "MTK_CONN Weak FUNCTION~~~\n"); + return 0; +} + +extern int __weak mtk_conn_md_bridge_send_msg(conn_md_ipc_ilm_t *ilm) +{ + pr_err(KERN_ERR "MTK_CONN Weak FUNCTION~~~\n"); + return 0; +} +#endif + +#endif /*__CONN_MD_EXP_H_*/ diff --git a/drivers/misc/mediatek/conn_md/include/conn_md_log.h b/drivers/misc/mediatek/conn_md/include/conn_md_log.h new file mode 100644 index 00000000000000..f9a3e12ee54f40 --- /dev/null +++ b/drivers/misc/mediatek/conn_md/include/conn_md_log.h @@ -0,0 +1,94 @@ +#ifndef __CONN_MD_LOG_H_ +#define __CONN_MD_LOG_H_ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* gettimeofday */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +#define DBG_LOG_STR_SIZE 512 + +extern int g_conn_md_dbg_lvl; + +extern int __conn_md_get_log_lvl(void); +extern int conn_md_log_set_lvl(int log_lvl); +extern int __conn_md_log_print(const char *str, ...); + +#define CONN_MD_LOG_LOUD 4 +#define CONN_MD_LOG_DBG 3 +#define CONN_MD_LOG_INFO 2 +#define CONN_MD_LOG_WARN 1 +#define CONN_MD_LOG_ERR 0 + +#ifndef DFT_TAG +#define DFT_TAG "[CONN-MD-DFT]" +#endif + +#define CONN_MD_LOUD_FUNC(fmt, arg ...) \ +do { \ + if (__conn_md_get_log_lvl() >= CONN_MD_LOG_LOUD) \ + __conn_md_log_print(DFT_TAG "[L]%s:" fmt, \ + __func__, ## arg); \ +} while (0) + +#define CONN_MD_INFO_FUNC(fmt, arg ...) \ +do { \ + if (__conn_md_get_log_lvl() >= CONN_MD_LOG_INFO)\ + __conn_md_log_print(DFT_TAG "[I]%s:" fmt, \ + __func__, ## arg); \ +} while (0) + +#define CONN_MD_WARN_FUNC(fmt, arg ...) \ +do { \ + if (__conn_md_get_log_lvl() >= CONN_MD_LOG_WARN)\ + __conn_md_log_print(DFT_TAG "[W]%s:" fmt, \ + __func__, ## arg); \ +} while (0) + +#define CONN_MD_ERR_FUNC(fmt, arg ...)\ +do {\ + if (__conn_md_get_log_lvl() >= CONN_MD_LOG_ERR)\ + __conn_md_log_print(DFT_TAG "[E]%s(%d):" fmt,\ + __func__, __LINE__, ## arg);\ +} while (0) + +#define CONN_MD_DBG_FUNC(fmt, arg ...) \ +do { \ + if (__conn_md_get_log_lvl() >= CONN_MD_LOG_DBG) \ + __conn_md_log_print(DFT_TAG "[D]%s:" fmt, \ + __func__, ## arg); \ +} while (0) + +#define CONN_MD_TRC_FUNC(f) \ +do { \ + if (__conn_md_get_log_lvl() >= CONN_MD_LOG_DBG) \ + __conn_md_log_print(DFT_TAG "<%s> <%d>\n", \ + __func__, __LINE__); \ +} while (0) + + +#endif diff --git a/drivers/misc/mediatek/connectivity/Kconfig b/drivers/misc/mediatek/connectivity/Kconfig new file mode 100644 index 00000000000000..c0799a469a65dd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/Kconfig @@ -0,0 +1,341 @@ +config MTK_COMBO + tristate "MediaTek Connectivity Combo Chip Support" + help + MTK connectivity combo chip driver for MT66xx + +# +# MTK Combo Chip Selection +# + +choice + prompt "Select Chip" + depends on MTK_COMBO + +config MTK_COMBO_CHIP_MT6620 + bool "MT6620" + help + this config is used to decided combo chip version + in current platform + is + MT6620 + +config MTK_COMBO_CHIP_MT6628 + bool "MT6628" + help + this config is used to decided combo chip version + in current platform + is + MT6628 + +config MTK_COMBO_CHIP_MT7668 + bool "MT7668" + help + this config is used to decided combo chip version + in current platform + is + MT7668 + +config MTK_COMBO_CHIP_MT6630 + bool "MT6630" + help + this config is used to decided combo chip version + in current platform + is + MT6630 + +config MTK_COMBO_CHIP_MT6632 + bool "Mediatek MT6632 device driver support" + help + This driver supports the built-in smart phone found in the Mediatek MT6632 chipset. + If you want to use MT6632 driver supprt, say Y. + If unsure, say N. + Mediatek MT6632 module includes BT, FM, GPS, WIFI. + +config MTK_COMBO_CHIP_CONSYS_6757 + bool "MTK MT6757 combo chip support" + help + this config is used to decided SOC consys version + in current platform + is + MT6757(BT/WIFI/GPS/FM combo chip) + +config MTK_COMBO_CHIP_CONSYS_6763 + bool "MTK MT6763 combo chip support" + help + this config is used to decided SOC consys version + in current platform + is + MT6763(BT/WIFI/GPS/FM combo chip) + +config MTK_COMBO_CHIP_CONSYS_6759 + bool "MTK MT6759 combo chip support" + help + this config is used to decided SOC consys version + in current platform + is + MT6759(BT/WIFI/GPS/FM combo chip) + +config MTK_COMBO_CHIP_CONSYS_8167 + bool "MTK MT8167 combo chip support" + help + this config is used to decided SOC consys version + in current platform + is + MT8167(BT/WIFI/GPS/FM combo chip) + +endchoice + +config MTK_COMBO_CHIP + string + default "MT6620" if MTK_COMBO_CHIP_MT6620 + default "MT6628" if MTK_COMBO_CHIP_MT6628 + default "MT6630" if MTK_COMBO_CHIP_MT6630 + default "MT6632" if MTK_COMBO_CHIP_MT6632 + default "MT7668" if MTK_COMBO_CHIP_MT7668 + default "CONSYS_6757" if MTK_COMBO_CHIP_CONSYS_6757 + default "CONSYS_6763" if MTK_COMBO_CHIP_CONSYS_6763 + default "CONSYS_6759" if MTK_COMBO_CHIP_CONSYS_6759 + default "CONSYS_8167" if MTK_COMBO_CHIP_CONSYS_8167 + help + this feature is used to identify combo chip version or SOC chip + consys version. + +# +# Target Platform Selection +# +config MTK_COMBO_PLAT_PATH + string "Platform folder name" + depends on MTK_COMBO + default "sample" if MTK_COMBO_PLAT_SAMPLE + help + Specify platform folder under common driver platform folder: + mtk_wcn_combo/common/platform/* + +# +# MTK COMBO Chip Configuration +# +config MTK_COMBO_COMM + depends on MTK_COMBO + tristate "MediaTek Combo Chip Common part driver" + help + MediaTek combo chip common part driver + +config MTK_COMBO_COMM_UART + depends on MTK_COMBO_COMM + tristate "Common interface UART" + help + Use UART for common part interface type + +config MTK_COMBO_COMM_PS + depends on MTK_COMBO_COMM_UART + bool "Enable PS support" + default n + help + Enable PS support of common UART interface + +config MTK_COMBO_COMM_SDIO + depends on MTK_COMBO_COMM + tristate "Common interface SDIO" + help + Use SDIO for common part interface type + +config MTK_COMBO_COMM_NPWR + depends on MTK_COMBO_COMM + bool "Enable NPWR support" + default n + help + Enable NPWR support of new power on swquence + +config MTK_COMBO_COMM_APO + depends on MTK_COMBO_COMM + bool "Enable always power on support" + default n + help + Enable chip will always power on + +choice + prompt "Select Combo driver for BT" + default MTK_COMBO_BT_HCI + depends on MTK_COMBO + + config MTK_COMBO_BT_BDROID + bool "MediaTek Combo Chip Bluedroid driver" + help + MTK BT /dev/stpbt driver for Bluedroid + + config MTK_COMBO_BT_HCI + bool "MediaTek Combo Chip BlueZ driver" + help + MTK BT driver for BlueZ +endchoice + +config MTK_FMRADIO + tristate "MediaTek Combo Chip FM Radio driver" + depends on MTK_COMBO + help + This config is used to choose + if need to compile fmradio folder. + Will compile fmradio folder if set to 'y', + otherwise will not compile fmradio folder. + +config MTK_FM_CHIP + string "MTK_FM_CHIP" + depends on MTK_FMRADIO + help + This config is used to choose + which FM radio chip to use: + e.g. MT6627_FM, MT6580_FM, MT6630_FM, + for control to use which platform code. + +config MTK_FM_50KHZ_SUPPORT + bool "Enable FM 50KHz support" + depends on MTK_FMRADIO + help + This config is used to choose + if need to support FM 50KHz step or not + for tune/seek/scan functions. + Will support 50KHz step if set to 'y', + otherwise will not support 50KHz step. + +config MTK_MERGE_INTERFACE_SUPPORT + bool "Enable PCM/I2S merge interface support" + depends on MTK_FMRADIO + help + This config is used to control FM Audio + path. FM audio path will use PCM/I2S merge + interface is set to 'y', + otherwise merge interface is not used. + +config MTK_COMBO_ANT + tristate "MediaTek Combo Chip ANT driver" + depends on MTK_COMBO + help + MTK ANT /dev/stpant driver for ANT + +config MTK_COMBO_GPS + tristate "MediaTek Combo Chip GPS driver" + depends on MTK_COMBO + help + MTK GPS /dev/stpgps driver + +config MTK_COMBO_WIFI + tristate "MediaTek Combo Chip Wi-Fi driver" + depends on MTK_COMBO + select WIRELESS_EXT + select WEXT_PRIV + +config MTK_WAPI_SUPPORT + bool "Enable WAPI support" + depends on MTK_COMBO_WIFI + default y + help + if it is set to TRUE: Support WAPI (WLAN Authentication and + Privacy Infrastructure) + +config MTK_PASSPOINT_R1_SUPPORT + bool "Enable Hotspot 2.0 R1 support" + depends on MTK_COMBO_WIFI + help + Support Passpoint R1 (Hotspot 2.0 R1) + +config MTK_PASSPOINT_R2_SUPPORT + bool "Enable Hotspot 2.0 R2 support" + depends on MTK_COMBO_WIFI + help + Support Passpoint R2 + +config MTK_WIFI_MCC_SUPPORT + bool "Enable Multi-Chanel Concurency" + depends on MTK_COMBO_WIFI + default y + help + if it is set to TRUE, wlan will support Multi-Channel Concurrency, + otherwise, only support Single Channel Concurrency + +config MTK_COMBO_BT_MT7668_SDIO + tristate "MediaTek MT7668s Bluetooth driver" + depends on MTK_COMBO_CHIP_MT7668 + help + This driver is required if you want to use MT7668 + with SDIO interface. + + Set "yes" to turn on and set "no" to turn off. + +config MTK_WIFI_DEVICE + tristate "MediaTek Wi-Fi driver" + select WIRELESS_EXT + select WEXT_PRIV + help + This option enables Wi-Fi support + +config MTK_DHCPV6C_WIFI + bool "MediaTek Wi-Fi DHCPv6 client support" + depends on MTK_WIFI_DEVICE + help + no: disable this feature + +config MTK_CONN_LTE_IDC_SUPPORT + bool "MediaTek CONN LTE IDC support" + depends on MTK_WIFI_DEVICE + select MTK_CONN_MD + default y if MTK_ECCCI_DRIVER + help + This option enables CONN LTE IDC support + +config MTK_GPS_SUPPORT + tristate "MediaTek GPS driver" + select MTK_GPS + help + to switch GPS feature on the platform. + Set "yes" to turn on and set "no" + (with MTK_AGPS_APP=no at the same time) + to turn off. + +config MTK_CONN_MT3337_CHIP_SUPPORT + bool "Mediatek MT3337 device driver" + depends on MTK_GPS_SUPPORT + help + This config is used to enable or disble chip 3337's gps driver. + MT3337 is gps only chip without BT and wifi, + it is powered on by new gps driver. + Otherwise we must close this config. + +menuconfig GPS + tristate "GPS drivers" + default y + help + Say Y here for supporting GPS. + +if GPS +config MTK_GPS + tristate "MediaTek GPS NMEA port driver" + default y if GPS + help + MTK GPS driver + To switch gps nmea port driver. + Set "yes" to turn on. + Set "no" to turn off. +endif + +config MTK_GPS_REGISTER_SETTING + tristate "MediaTek GPS Register Setting" + depends on MTK_COMBO_GPS + help + GPS register settings. + +config MTK_GPS_EMI + tristate "MediaTek GPS EMI Driver" + depends on MTK_COMBO_GPS + help + GPS EMI driver is for MNL OFFLOAD feature. + +config MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT + depends on MTK_COMBO_CHIP_MT6632 + default y + tristate "Mediatek combo chip deep sleep feature setting" + help + this config is used to enable or disable chip deep sleep feature, + if the project is no deep sleep design, + host can`t wake up chip form deep sleep, + we must close this config. + diff --git a/drivers/misc/mediatek/connectivity/Makefile b/drivers/misc/mediatek/connectivity/Makefile new file mode 100644 index 00000000000000..2ad42e04ddc75b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/Makefile @@ -0,0 +1,63 @@ +# +# Copyright (C) 2015 MediaTek Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +# Connectivity combo driver +# If KERNELRELEASE is defined, we've been invoked from the +# kernel build system and can use its language. +ifneq ($(KERNELRELEASE),) +subdir-ccflags-y += -D MTK_WCN_REMOVE_KERNEL_MODULE +ifeq ($(CONFIG_ARM64), y) +subdir-ccflags-y += -D CONFIG_MTK_WCN_ARM64 +endif + +subdir-ccflags-y += -D CFG_SUPPORT_AEE=0 + +# Do build-in for Makefile checking +#export CONFIG_WLAN_DRV_BUILD_IN=y + +ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y) + subdir-ccflags-y += -D WMT_IDC_SUPPORT=1 +else + subdir-ccflags-y += -D WMT_IDC_SUPPORT=0 +endif + subdir-ccflags-y += -D MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + obj-$(CONFIG_MTK_COMBO_COMM) += common/ + obj-$(CONFIG_MTK_COMBO) += conninfra/ + +ifeq ($(CONFIG_MTK_COMBO),$(filter $(CONFIG_MTK_COMBO),m y)) + subdir-ccflags-y += -D MTK_BT_HCI -D REMOVE_MK_NODE=1 + obj-$(CONFIG_MTK_COMBO) += bt/ +endif + +ifeq ($(CONFIG_MTK_COMBO_BT_MT7668_SDIO),$(filter $(CONFIG_MTK_COMBO_BT_MT7668_SDIO),m y)) + obj-$(CONFIG_MTK_COMBO_BT_MT7668_SDIO) += bt_mt7668_sdio/ +endif + +ifeq ($(CONFIG_MTK_WIFI_DEVICE),$(filter $(CONFIG_MTK_WIFI_DEVICE),m y)) + obj-$(CONFIG_MTK_WIFI_DEVICE) += wlan/core/gen4-mt7668/ +endif + +ifeq ($(CONFIG_MTK_COMBO_WIFI),$(filter $(CONFIG_MTK_COMBO_WIFI),m y)) + obj-$(CONFIG_MTK_COMBO_WIFI) += wlan/adaptor/ +endif + obj-$(CONFIG_MTK_COMBO_GPS) += gps/ + obj-n := dummy.o + +# Otherwise we were called directly from the command line; +# invoke the kernel build system. +else + KERNELDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) PLATFORM_FLAGS="$(subdir-ccflags-y)" modules KBUILD_VERBOSE=1 +endif diff --git a/drivers/misc/mediatek/connectivity/bt/Makefile b/drivers/misc/mediatek/connectivity/bt/Makefile new file mode 100644 index 00000000000000..d3ff86d9febdbd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt/Makefile @@ -0,0 +1,21 @@ +######################################################### +# Bluetooth character device driver + +ccflags-y += -D CREATE_NODE_DYNAMIC=1 #1 +ccflags-y += -D MTK_KERNEL_DEBUG + +ccflags-y += \ + -I$(src)/../common/common_main/include \ + -I$(src)/../../include/mt-plat \ + -I$(src)/../common/common_main/core/include \ + -I$(src)/../common/common_detect \ + -I$(src)/../conninfra/base/include \ + -I$(src)/../common/common_main/linux/include + +ifeq ($(CONFIG_MTK_COMBO_BT_BDROID),y) + obj-$(CONFIG_MTK_COMBO) += stp_chrdev_bt.o +else ifeq ($(CONFIG_MTK_COMBO_BT_HCI),y) + stpbt-objs := stp_chrdev_bt_hci.o + obj-$(CONFIG_MTK_COMBO) += stpbt.o +endif + diff --git a/drivers/misc/mediatek/connectivity/bt/stp_chrdev_bt.c b/drivers/misc/mediatek/connectivity/bt/stp_chrdev_bt.c new file mode 100644 index 00000000000000..789d7ef9f2a9ad --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt/stp_chrdev_bt.c @@ -0,0 +1,488 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wmt_exp.h" +#include "stp_exp.h" + +MODULE_LICENSE("Dual BSD/GPL"); + +#define BT_DRIVER_NAME "mtk_stp_bt_chrdev" +#define BT_DEV_MAJOR 192 + +#define PFX "[MTK-BT] " +#define BT_LOG_DBG 3 +#define BT_LOG_INFO 2 +#define BT_LOG_WARN 1 +#define BT_LOG_ERR 0 + +static UINT32 gDbgLevel = BT_LOG_INFO; + +#define BT_DBG_FUNC(fmt, arg...) \ + do { if (gDbgLevel >= BT_LOG_DBG) pr_debug(PFX "%s: " fmt, __func__, ##arg); } while (0) +#define BT_INFO_FUNC(fmt, arg...) \ + do { if (gDbgLevel >= BT_LOG_INFO) pr_debug(PFX "%s: " fmt, __func__, ##arg); } while (0) +#define BT_WARN_FUNC(fmt, arg...) \ + do { if (gDbgLevel >= BT_LOG_WARN) pr_warn(PFX "%s: " fmt, __func__, ##arg); } while (0) +#define BT_ERR_FUNC(fmt, arg...) \ + do { if (gDbgLevel >= BT_LOG_ERR) pr_err(PFX "%s: " fmt, __func__, ##arg); } while (0) + +#define VERSION "2.0" + +#define COMBO_IOC_MAGIC 0xb0 +#define COMBO_IOCTL_FW_ASSERT _IOWR(COMBO_IOC_MAGIC, 0, int) +#define COMBO_IOCTL_BT_SET_PSM _IOWR(COMBO_IOC_MAGIC, 1, bool) +#define COMBO_IOCTL_BT_IC_HW_VER _IOR(COMBO_IOC_MAGIC, 2, void*) +#define COMBO_IOCTL_BT_IC_FW_VER _IOR(COMBO_IOC_MAGIC, 3, void*) + +static INT32 BT_devs = 1; +static INT32 BT_major = BT_DEV_MAJOR; +module_param(BT_major, uint, 0); +static struct cdev BT_cdev; +#if CREATE_NODE_DYNAMIC +static struct class *stpbt_class; +static struct device *stpbt_dev; +#endif + +#define BT_BUFFER_SIZE 2048 +static UINT8 i_buf[BT_BUFFER_SIZE]; /* Input buffer for read */ +static UINT8 o_buf[BT_BUFFER_SIZE]; /* Output buffer for write */ + +static struct semaphore wr_mtx, rd_mtx; +/* Wait queue for poll and read */ +static wait_queue_head_t inq; +static DECLARE_WAIT_QUEUE_HEAD(BT_wq); +static INT32 flag; +/* Reset flag for whole chip reset senario */ +static volatile INT32 rstflag; + +/******************************************************************* + * WHOLE CHIP RESET message handler + ******************************************************************* +*/ +static VOID bt_cdev_rst_cb(ENUM_WMTDRV_TYPE_T src, + ENUM_WMTDRV_TYPE_T dst, ENUM_WMTMSG_TYPE_T type, PVOID buf, UINT32 sz) +{ + ENUM_WMTRSTMSG_TYPE_T rst_msg; + + if (sz <= sizeof(ENUM_WMTRSTMSG_TYPE_T)) { + memcpy((PINT8)&rst_msg, (PINT8)buf, sz); + BT_DBG_FUNC("src = %d, dst = %d, type = %d, buf = 0x%x sz = %d, max = %d\n", src, + dst, type, rst_msg, sz, WMTRSTMSG_RESET_MAX); + if ((src == WMTDRV_TYPE_WMT) && (dst == WMTDRV_TYPE_BT) + && (type == WMTMSG_TYPE_RESET)) { + if (rst_msg == WMTRSTMSG_RESET_START) { + BT_INFO_FUNC("BT reset start!\n"); + rstflag = 1; + wake_up_interruptible(&inq); + + } else if (rst_msg == WMTRSTMSG_RESET_END) { + BT_INFO_FUNC("BT reset end!\n"); + rstflag = 2; + wake_up_interruptible(&inq); + } + } + } else + BT_WARN_FUNC("Invalid message format!\n"); +} + +VOID BT_event_cb(VOID) +{ + BT_DBG_FUNC("BT_event_cb\n"); + + flag = 1; + + /* + * Finally, wake up any reader blocked in poll or read + */ + wake_up_interruptible(&inq); + wake_up(&BT_wq); +} + +unsigned int BT_poll(struct file *filp, poll_table *wait) +{ + UINT32 mask = 0; + +/* down(&wr_mtx); */ + /* + * The buffer is circular; it is considered full + * if "wp" is right behind "rp". "left" is 0 if the + * buffer is empty, and it is "1" if it is completely full. + */ + if (mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX)) { + poll_wait(filp, &inq, wait); + + if (!mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX) || rstflag) + /* BT Rx queue has valid data, or whole chip reset occurs */ + mask |= POLLIN | POLLRDNORM; /* Readable */ + } else { + mask |= POLLIN | POLLRDNORM; /* Readable */ + } + + /* Do we need condition here? */ + mask |= POLLOUT | POLLWRNORM; /* Writable */ +/* up(&wr_mtx); */ + return mask; +} + +ssize_t BT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + INT32 retval = 0; + + down(&wr_mtx); + + BT_DBG_FUNC("count %zd pos %lld\n", count, *f_pos); + + if (rstflag) { + if (rstflag == 1) { /* Reset start */ + retval = -88; + BT_INFO_FUNC("detect whole chip reset start\n"); + } else if (rstflag == 2) { /* Reset end */ + retval = -99; + BT_INFO_FUNC("detect whole chip reset end\n"); + } + goto OUT; + } + + if (count > 0) { + if (count > BT_BUFFER_SIZE) { + count = BT_BUFFER_SIZE; + BT_WARN_FUNC("Shorten count %zd to BT_BUFFER_SIZE\n", count); + } + + if (copy_from_user(o_buf, buf, count)) { + retval = -EFAULT; + goto OUT; + } + + retval = mtk_wcn_stp_send_data(o_buf, count, BT_TASK_INDX); + if (retval < 0) + BT_ERR_FUNC("mtk_wcn_stp_send_data fail, retval %d\n", retval); + else if (retval == 0) { + /* Device cannot process data in time, BT queue is full and no space is available for write, + * native program should not call BT_write with no delay. + */ + BT_ERR_FUNC("Packet length %zd, sent bytes %d, no space is available!\n", count, retval); + retval = -EAGAIN; + } else + BT_DBG_FUNC("Packet length %zd, sent bytes %d\n", count, retval); + + } else { + BT_ERR_FUNC("Packet length %zd is not allowed\n", count); + retval = -EINVAL; + } + +OUT: + up(&wr_mtx); + return retval; +} + +ssize_t BT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + static int chip_reset_count; + INT32 retval = 0; + + down(&rd_mtx); + + BT_DBG_FUNC("count %zd pos %lld\n", count, *f_pos); + + if (rstflag) { + if (rstflag == 1) { /* Reset start */ + retval = -88; + if ((chip_reset_count%500) == 0) + BT_INFO_FUNC("detect whole chip reset start, %d\n", chip_reset_count); + chip_reset_count++; + } else if (rstflag == 2) { /* Reset end */ + retval = -99; + BT_INFO_FUNC("detect whole chip reset end\n"); + chip_reset_count = 0; + } + goto OUT; + } + + if (count > BT_BUFFER_SIZE) { + count = BT_BUFFER_SIZE; + BT_WARN_FUNC("Shorten count %zd to BT_BUFFER_SIZE\n", count); + } + + retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX); + if (retval < 0) { + BT_ERR_FUNC("mtk_wcn_stp_receive_data fail, retval %d\n", retval); + goto OUT; + } + + while (retval == 0) { /* Got nothing, wait for STP's signal */ + /* + * If nonblocking mode, return directly. + * O_NONBLOCK is specified during open() + */ + if (filp->f_flags & O_NONBLOCK) { + BT_DBG_FUNC("Non-blocking read, return directly\n"); + retval = -EAGAIN; + goto OUT; + } + + wait_event(BT_wq, flag != 0); + flag = 0; + + retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX); + if (retval < 0) { + BT_ERR_FUNC("mtk_wcn_stp_receive_data fail, retval %d\n", retval); + goto OUT; + } + } + + /* Got something from STP driver */ + BT_DBG_FUNC("Read bytes %d\n", retval); + if (copy_to_user(buf, i_buf, retval)) { + retval = -EFAULT; + goto OUT; + } + +OUT: + up(&rd_mtx); + return retval; +} + +/* int BT_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) */ +long BT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + INT32 retval = 0; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_TRUE; + UINT32 ver = 0; + + BT_DBG_FUNC("cmd: 0x%08x\n", cmd); + + switch (cmd) { + case COMBO_IOCTL_FW_ASSERT: + /* Trigger FW assert for debug */ + BT_INFO_FUNC("Host trigger FW assert......, reason: %lu\n", arg); + bRet = mtk_wcn_wmt_assert(WMTDRV_TYPE_BT, (UINT32)arg); + if (bRet == MTK_WCN_BOOL_TRUE) + BT_INFO_FUNC("Host trigger FW assert succeed\n"); + else { + BT_ERR_FUNC("Host trigger FW assert failed\n"); + retval = -EIO; + } + break; + case COMBO_IOCTL_BT_SET_PSM: + /* BT stack may need to dynamically enable/disable Power Saving Mode + * in some scenarios for performance, e.g. A2DP chopping. + */ + BT_INFO_FUNC("BT stack change PSM setting: %lu\n", arg); + retval = mtk_wcn_wmt_psm_ctrl((MTK_WCN_BOOL)arg); + break; + case COMBO_IOCTL_BT_IC_HW_VER: + ver = mtk_wcn_wmt_ic_info_get(WMTCHIN_HWVER); + BT_INFO_FUNC("HW ver: 0x%x\n", ver); + if (copy_to_user((UINT32 __user *)arg, &ver, sizeof(ver))) + retval = -EFAULT; + break; + case COMBO_IOCTL_BT_IC_FW_VER: + ver = mtk_wcn_wmt_ic_info_get(WMTCHIN_FWVER); + BT_INFO_FUNC("FW ver: 0x%x\n", ver); + if (copy_to_user((UINT32 __user *)arg, &ver, sizeof(ver))) + retval = -EFAULT; + break; + default: + BT_ERR_FUNC("Unknown cmd: 0x%08x\n", cmd); + retval = -EINVAL; + break; + } + + return retval; +} + +long BT_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + return BT_unlocked_ioctl(filp, cmd, arg); +} + +static int BT_open(struct inode *inode, struct file *file) +{ + BT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + + /* Turn on BT */ + if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT) == MTK_WCN_BOOL_FALSE) { + BT_WARN_FUNC("WMT turn on BT fail!\n"); + return -EIO; + } + + BT_INFO_FUNC("WMT turn on BT OK!\n"); + rstflag = 0; + + if (mtk_wcn_stp_is_ready()) { + + mtk_wcn_stp_set_bluez(0); + + BT_INFO_FUNC("Now it's in MTK Bluetooth Mode\n"); + BT_INFO_FUNC("STP is ready!\n"); + + BT_DBG_FUNC("Register BT event callback!\n"); + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, BT_event_cb); + } else { + BT_ERR_FUNC("STP is not ready!\n"); + mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT); + return -EIO; + } + + BT_DBG_FUNC("Register BT reset callback!\n"); + mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_BT, bt_cdev_rst_cb); + + sema_init(&wr_mtx, 1); + sema_init(&rd_mtx, 1); + + return 0; +} + +static int BT_close(struct inode *inode, struct file *file) +{ + BT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + rstflag = 0; + mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_BT); + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); + + if (mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT) == MTK_WCN_BOOL_FALSE) { + BT_ERR_FUNC("WMT turn off BT fail!\n"); + return -EIO; /* Mostly, native program will not check this return value. */ + } + + BT_INFO_FUNC("WMT turn off BT OK!\n"); + return 0; +} + +const struct file_operations BT_fops = { + .open = BT_open, + .release = BT_close, + .read = BT_read, + .write = BT_write, + /* .ioctl = BT_ioctl, */ + .unlocked_ioctl = BT_unlocked_ioctl, + .compat_ioctl = BT_compat_ioctl, + .poll = BT_poll +}; + +static int BT_init(void) +{ + dev_t dev = MKDEV(BT_major, 0); + INT32 alloc_ret = 0; + INT32 cdev_err = 0; + + /* Allocate char device */ + alloc_ret = register_chrdev_region(dev, BT_devs, BT_DRIVER_NAME); + if (alloc_ret) { + BT_ERR_FUNC("Failed to register device numbers\n"); + return alloc_ret; + } + + cdev_init(&BT_cdev, &BT_fops); + BT_cdev.owner = THIS_MODULE; + + cdev_err = cdev_add(&BT_cdev, dev, BT_devs); + if (cdev_err) + goto error; + +#if CREATE_NODE_DYNAMIC /* mknod replace */ + stpbt_class = class_create(THIS_MODULE/*, "stpbt"*/); + if (IS_ERR(stpbt_class)) + goto error; + stpbt_dev = device_create(stpbt_class, NULL, dev, NULL, "stpbt"); + if (IS_ERR(stpbt_dev)) + goto error; +#endif + + BT_INFO_FUNC("%s driver(major %d) installed\n", BT_DRIVER_NAME, BT_major); + + /* Initialize wait queue */ + init_waitqueue_head(&(inq)); + + return 0; + +error: +#if CREATE_NODE_DYNAMIC + if (stpbt_dev && !IS_ERR(stpbt_dev)) { + device_destroy(stpbt_class, dev); + stpbt_dev = NULL; + } + if (stpbt_class && !IS_ERR(stpbt_class)) { + class_destroy(stpbt_class); + stpbt_class = NULL; + } +#endif + if (cdev_err == 0) + cdev_del(&BT_cdev); + + if (alloc_ret == 0) + unregister_chrdev_region(dev, BT_devs); + + return -1; +} + +static void BT_exit(void) +{ + dev_t dev = MKDEV(BT_major, 0); + +#if CREATE_NODE_DYNAMIC + if (stpbt_dev && !IS_ERR(stpbt_dev)) { + device_destroy(stpbt_class, dev); + stpbt_dev = NULL; + } + if (stpbt_class && !IS_ERR(stpbt_class)) { + class_destroy(stpbt_class); + stpbt_class = NULL; + } +#endif + + cdev_del(&BT_cdev); + unregister_chrdev_region(dev, BT_devs); + + BT_INFO_FUNC("%s driver removed\n", BT_DRIVER_NAME); +} + +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE + +int mtk_wcn_stpbt_drv_init(void) +{ + return BT_init(); +} +EXPORT_SYMBOL(mtk_wcn_stpbt_drv_init); + +void mtk_wcn_stpbt_drv_exit(void) +{ + return BT_exit(); +} +EXPORT_SYMBOL(mtk_wcn_stpbt_drv_exit); + +#else + +module_init(BT_init); +module_exit(BT_exit); + +#endif + diff --git a/drivers/misc/mediatek/connectivity/bt/stp_chrdev_bt_hci.c b/drivers/misc/mediatek/connectivity/bt/stp_chrdev_bt_hci.c new file mode 100644 index 00000000000000..00074d46fc8aba --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt/stp_chrdev_bt_hci.c @@ -0,0 +1,964 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "osal_typedef.h" +#include "stp_exp.h" +#include "wmt_exp.h" + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("MediaTek STP Bluetooth driver"); + +#ifdef MTK_BT_HCI +#define MTK_BT_DEBUG 0 +#include +#include +#endif + +#define BT_DRIVER_NAME "mtk_stp_BT_chrdev" +#define BT_DEV_MAJOR 192 /* Never used number */ + +#define PFX "[MTK-BT] " +#define BT_LOG_DBG 3 +#define BT_LOG_INFO 2 +#define BT_LOG_WARN 1 +#define BT_LOG_ERR 0 + +#define COMBO_IOC_MAGIC 0xb0 +#define COMBO_IOCTL_FW_ASSERT _IOWR(COMBO_IOC_MAGIC, 0, int) +#define COMBO_IOCTL_BT_IC_HW_VER _IOWR(COMBO_IOC_MAGIC, 1, void*) +#define COMBO_IOCTL_BT_IC_FW_VER _IOWR(COMBO_IOC_MAGIC, 2, void*) +#define COMBO_IOC_BT_HWVER _IOWR(COMBO_IOC_MAGIC, 3, void*) + +#define NUM_REASSEMBLY 4 +#define HCI_STP_SAFE_RESET (1) +#define hci_stp_init_entry(c) \ + {.hci_cmd=c, .cmdSz=sizeof(c), .hci_evt=c##_evt, .evtSz=sizeof(c##_evt), .str=#c} + +static UINT32 gDbgLevel = BT_LOG_INFO; + +#define BT_DBG_FUNC(fmt, arg...) \ + do { if (gDbgLevel >= BT_LOG_DBG) \ + pr_debug(PFX "%s: " fmt, __func__ , ##arg); \ + } while (0) +#define BT_INFO_FUNC(fmt, arg...) \ +do { if (gDbgLevel >= BT_LOG_INFO) \ + pr_warn(PFX "%s: " fmt, __func__ , ##arg); \ + } while (0) +#define BT_WARN_FUNC(fmt, arg...) \ + do { if (gDbgLevel >= BT_LOG_WARN) \ + pr_err(PFX "%s: " fmt, __func__ , ##arg); \ + } while (0) +#define BT_ERR_FUNC(fmt, arg...) \ + do { if (gDbgLevel >= BT_LOG_ERR) \ + pr_err(PFX "%s: " fmt, __func__ , ##arg); \ + } while (0) + +#define VERSION "1.0" + +static INT32 BT_devs = 1; /* Device count */ +static INT32 BT_major = BT_DEV_MAJOR; /* Dynamic allocation */ +module_param(BT_major, uint, 0); +static struct cdev BT_cdev; + +#define BT_BUFFER_SIZE 2048 +static UINT8 i_buf[BT_BUFFER_SIZE]; /* Input buffer of read() */ +static UINT8 o_buf[BT_BUFFER_SIZE]; /* Output buffer of write() */ + +static struct semaphore wr_mtx, rd_mtx; +/* Wait queue for poll and read */ +static wait_queue_head_t inq; +static DECLARE_WAIT_QUEUE_HEAD(BT_wq); +static INT32 flag; +/* Reset flag for whole chip reset senario */ +static volatile INT32 rstflag; + +ssize_t BT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); +ssize_t BT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); +long BT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +long BT_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#if REMOVE_MK_NODE +int mtk_wcn_stpbt_drv_init(void); +void mtk_wcn_stpbt_drv_exit(void); +#endif + +#ifdef MTK_BT_HCI +/*static int hci_reassembly(struct hci_dev *hdev, int type, void *data, + int count, __u8 index) +{ + int len = 0; + int hlen = 0; + int remain = count; + struct sk_buff *skb; + struct bt_skb_cb *scb; + + if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) || + index >= NUM_REASSEMBLY) + return -EILSEQ; + + skb = hdev->reassembly[index]; + + if (!skb) { + switch (type) { + case HCI_ACLDATA_PKT: + len = HCI_MAX_FRAME_SIZE; + hlen = HCI_ACL_HDR_SIZE; + break; + case HCI_EVENT_PKT: + len = HCI_MAX_EVENT_SIZE; + hlen = HCI_EVENT_HDR_SIZE; + break; + case HCI_SCODATA_PKT: + len = HCI_MAX_SCO_SIZE; + hlen = HCI_SCO_HDR_SIZE; + break; + } + + skb = bt_skb_alloc(len, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + scb = (void *) skb->cb; + scb->expect = hlen; + scb->pkt_type = type; + + hdev->reassembly[index] = skb; + } + + while (count) { + scb = (void *) skb->cb; + len = min_t(uint, scb->expect, count); + + memcpy(skb_put(skb, len), data, len); + + count -= len; + data += len; + scb->expect -= len; + remain = count; + + switch (type) { + case HCI_EVENT_PKT: + if (skb->len == HCI_EVENT_HDR_SIZE) { + struct hci_event_hdr *h = hci_event_hdr(skb); + + scb->expect = h->plen; + + if (skb_tailroom(skb) < scb->expect) { + kfree_skb(skb); + hdev->reassembly[index] = NULL; + return -ENOMEM; + } + } + break; + + case HCI_ACLDATA_PKT: + if (skb->len == HCI_ACL_HDR_SIZE) { + struct hci_acl_hdr *h = hci_acl_hdr(skb); + + scb->expect = __le16_to_cpu(h->dlen); + + if (skb_tailroom(skb) < scb->expect) { + kfree_skb(skb); + hdev->reassembly[index] = NULL; + return -ENOMEM; + } + } + break; + + case HCI_SCODATA_PKT: + if (skb->len == HCI_SCO_HDR_SIZE) { + struct hci_sco_hdr *h = hci_sco_hdr(skb); + + scb->expect = h->dlen; + + if (skb_tailroom(skb) < scb->expect) { + kfree_skb(skb); + hdev->reassembly[index] = NULL; + return -ENOMEM; + } + } + break; + } + + if (scb->expect == 0) { + // Complete frame + + bt_cb(skb)->pkt_type = type; + hci_recv_frame(hdev, skb); + + hdev->reassembly[index] = NULL; + return remain; + } + } + + return remain; +} + +int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) +{ + int rem = 0; + + if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) + return -EILSEQ; + + while (count) { + rem = hci_reassembly(hdev, type, data, count, type - 1); + if (rem < 0) + return rem; + + data += (count - rem); + count = rem; + } + + return rem; +} */ +struct hci_stp { + struct hci_dev *hdev; + unsigned long flags; + + struct sk_buff_head txq; /* used to queue TX packets */ + unsigned long tx_state; + + struct work_struct init_work; + struct completion *p_init_comp; + wait_queue_head_t *p_init_evt_wq; + spinlock_t init_lock; /* protect init variables: comp and wq */ + unsigned int init_cmd_idx; + int init_evt_rx_flag; /* init result of last sent cmd */ + +#if HCI_STP_SAFE_RESET + wait_queue_head_t reset_wq; + atomic_t reset_count; /* !0: reset in progress */ +#endif + //void *priv; /* unused? */ + //struct sk_buff *tx_skb; /* unused? */ + //spinlock_t rx_lock; /* unused? */ +}; +#endif + +#ifdef MTK_BT_HCI +static struct mtk_hci { + struct hci_dev *hdev; + struct work_struct work; + struct sk_buff_head txq; +} mtk_hci; + +struct hci_stp_init_cmd { + unsigned char *hci_cmd; + unsigned int cmdSz; + unsigned char *hci_evt; + unsigned int evtSz; + char *str; +}; + +//static unsigned char bt_get_bd_addr[4] = {0x01, 0x09, 0x10, 0x00}; +static unsigned char bt_get_bd_addr_evt[] = {0x04, 0x0E, 0x0A, 0x01, 0x09, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static unsigned char bt_set_bd_addr[10] = {0x01, 0x1A, 0xFC, 0x06, 0x01, 0x20, 0x66, 0x46, 0x00, 0x00}; +static unsigned char bt_set_bd_addr_evt[] = {0x04, 0x0E, 0x04, 0x01, 0x1A, 0xFC, 0x00}; +static unsigned char bt_set_codec[8] = {0x01, 0x72, 0xFC, 0x04, 0x23, 0x10, 0x00, 0x00}; +static unsigned char bt_set_codec_evt[] = {0x04, 0x0E, 0x04, 0x01, 0x72, 0xFC, 0x00}; +static unsigned char bt_set_radio[10] = {0x01, 0x79, 0xFC, 0x06, 0x06, 0x80, 0x00, 0x06, 0x03, 0x06}; +static unsigned char bt_set_radio_evt[] = {0x04, 0x0E, 0x04, 0x01, 0x79, 0xFC, 0x00}; +static unsigned char bt_set_tx_pwr_offset[7] = {0x01, 0x93, 0xFC, 0x03, 0xFF, 0xFF, 0xFF}; +static unsigned char bt_set_tx_pwr_offset_evt[] = {0x04, 0x0E, 0x04, 0x01, 0x93, 0xFC, 0x00}; +static unsigned char bt_set_sleep[11] = {0x01, 0x7A, 0xFC, 0x07, 0x03, 0x40, 0x1F, 0x40, 0x1F, 0x00, 0x04}; +static unsigned char bt_set_sleep_evt[] = {0x04, 0x0E, 0x04, 0x01, 0x7A, 0xFC, 0x00}; +static unsigned char bt_set_coex_adjust[10] = {0x01, 0x22, 0xFC, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static unsigned char bt_set_coex_adjust_evt[] = {0x04, 0x0E, 0x04, 0x01, 0x22, 0xFC, 0x00}; + +static struct hci_stp_init_cmd init_table[] = +{ + /* refer to mediatek/external/bluetooth/driver/combo/radiomod.c: bt_init_script_6630[] */ + hci_stp_init_entry(bt_set_bd_addr), + hci_stp_init_entry(bt_set_codec), + hci_stp_init_entry(bt_set_radio), + hci_stp_init_entry(bt_set_tx_pwr_offset), + hci_stp_init_entry(bt_set_sleep), + hci_stp_init_entry(bt_set_coex_adjust), +}; + +static void hci_stp_dev_init_rx_cb(UINT8 * const data, INT32 count) +{ + struct hci_stp *hu; + unsigned int idx; + + if (unlikely(!mtk_hci.hdev)) { + BT_ERR_FUNC("null hdev!\n"); + return; + } + if (unlikely(!hci_get_drvdata(mtk_hci.hdev))) { + BT_ERR_FUNC("null hci_get_drvdata(hdev)!\n"); + return; + } + + /* get hci_stp from global variable */ + hu = hci_get_drvdata(mtk_hci.hdev); + idx = hu->init_cmd_idx; + + if (unlikely(count != init_table[idx].evtSz)){ + hu->init_evt_rx_flag = -1; /* size mismatch */ + } + else if (unlikely(memcmp(data, init_table[idx].hci_evt, 7))){ + hu->init_evt_rx_flag = -2; /* content mismatch */ + } + else{ + hu->init_evt_rx_flag = 1; /* ok */ + BT_DBG_FUNC("EVT(%d) len(%d) ok\n", idx, count); + if (idx == 0) { + /* store the returned eFUSE address */ + memcpy(&bt_get_bd_addr_evt[7], &data[7], 6); + } + } + + if (unlikely(1 != hu->init_evt_rx_flag)) { + int i; + BT_WARN_FUNC("EVT(%d) len(%d) buf:[", idx, count); + for (i = 0; i < count; ++i) { + printk("0x%02x ", data[i]); + } + printk("]\n"); + BT_WARN_FUNC("EVT(%d) exp(%d) buf:[", idx, init_table[idx].evtSz); + for (i = 0; i < count; ++i) { + printk("0x%02x ", init_table[idx].hci_evt[i]); + } + printk("]\n"); + + } + + smp_wmb(); /* sync shared data */ + + spin_lock(&hu->init_lock); + if (likely(hu->p_init_evt_wq)) { + wake_up(hu->p_init_evt_wq); /* wake up dev_init_work */ + } + else { + int i; + BT_WARN_FUNC("late EVT(%d) len(%d) buf:[", idx, count); + for (i = 0; i < count; ++i) { + printk("0x%02x ", data[i]); + } + printk("]\n"); + BT_WARN_FUNC("Please check if uart rx data is returned or processed in time for BT init!\n"); + BT_WARN_FUNC("Possibly caused by a very busy system, or stp_uart rx priority too low...\n"); + BT_WARN_FUNC("Check which one is the real case and try to raise stp_uart rx priority.\n"); + } + spin_unlock(&hu->init_lock); +} + +/* +static void +hex_dump(char *prefix, char *p, int len) +{ + int i; + + pr_err("%s ", prefix); + for (i = 0; i < len; i++) + pr_err("%02x ", (*p++ & 0xff)); + pr_err("\n"); +} +*/ + +static int +mtk_bt_hci_open(struct hci_dev *hdev) +{ + int err = 0; + +#if MTK_BT_DEBUG == 1 + pr_err("# %s\n", __func__); +#endif + + err = mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT); + if (err != MTK_WCN_BOOL_TRUE) { + pr_err("%s func on failed with %d\n", __func__, err); + return -ENODEV; + } + + set_bit(HCI_RUNNING, &hdev->flags); + + mtk_wcn_stp_set_bluez(1); + + return 0; +} + +static int +mtk_bt_hci_close(struct hci_dev *hdev) +{ + int err = 0; + +#if MTK_BT_DEBUG == 1 + pr_err("# %s\n", __func__); +#endif + + mtk_wcn_stp_set_bluez(0); + + clear_bit(HCI_RUNNING, &hdev->flags); + + err = mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT); + if (err != MTK_WCN_BOOL_TRUE) { + pr_err("%s func off failed with %d\n", __func__, err); + return -EIO; + } + + return 0; +} + +static void +mtk_bt_hci_work(struct work_struct *work) +{ + int err; + struct sk_buff *skb; + +#if MTK_BT_DEBUG == 1 + pr_err("# %s\n", __func__); +#endif + + while ((skb = skb_dequeue(&mtk_hci.txq))) { + skb_push(skb, 1); + skb->data[0] = bt_cb(skb)->pkt_type; + +#if MTK_BT_DEBUG == 1 + hex_dump(">>", skb->data, skb->len); +#endif + + err = mtk_wcn_stp_send_data(skb->data, skb->len, BT_TASK_INDX); + if (err < 0) { + pr_err("%s err=%d\n", __func__, err); + mtk_hci.hdev->stat.err_tx++; + skb_queue_head(&mtk_hci.txq, skb); + break; + } + + mtk_hci.hdev->stat.byte_tx += skb->len; + kfree_skb(skb); + } +} + +static int +mtk_bt_hci_send(struct hci_dev *hdev, struct sk_buff *skb) +{ +#if MTK_BT_DEBUG == 1 + pr_err("# %s\n", __func__); +#endif + + if (mtk_hci.hdev && !test_bit(HCI_RUNNING, &mtk_hci.hdev->flags)) + return -EBUSY; + + switch (bt_cb(skb)->pkt_type) { + case HCI_COMMAND_PKT: + mtk_hci.hdev->stat.cmd_tx++; + break; + + case HCI_ACLDATA_PKT: + mtk_hci.hdev->stat.acl_tx++; + break; + + case HCI_SCODATA_PKT: + mtk_hci.hdev->stat.sco_tx++; + break; + + default: + return -EILSEQ; + } + + skb_queue_tail(&mtk_hci.txq, skb); + schedule_work(&mtk_hci.work); + + return 0; +} + +static int +mtk_bt_hci_flush(struct hci_dev *hdev) +{ + pr_err("%s: todo\n", __func__); + + return 0; +} + +/* static void +mtk_bt_hci_receive(const PUINT8 data, INT32 size) +{ + int err; + +#if MTK_BT_DEBUG == 1 + pr_err("# %s\n", __func__); + hex_dump("<<", data, size); +#endif + + err = hci_recv_fragment(mtk_hci.hdev, data[0], (void *)&data[1], size - 1); + if (err < 0) + pr_err("%s: hci_recv_fragment failed with %d\n", __func__, err); + + if (mtk_hci.hdev) + mtk_hci.hdev->stat.byte_rx += size - 1; +} */ + +static void +mtk_bt_hci_notify(struct hci_dev *hdev, unsigned int evt) +{ + static const char * const notify_str[] = { + "null", + "HCI_NOTIFY_CONN_ADD", + "HCI_NOTIFY_CONN_DEL", + "HCI_NOTIFY_VOICE_SETTING" + }; + + if (evt > HCI_NOTIFY_VOICE_SETTING) + pr_info("%s event=0x%x\n", __func__, evt); + else + pr_info("%s event(%d)=%s\n", __func__, evt, notify_str[evt]); +} +#endif + +static VOID bt_cdev_rst_cb(ENUM_WMTDRV_TYPE_T src, + ENUM_WMTDRV_TYPE_T dst, ENUM_WMTMSG_TYPE_T type, PVOID buf, UINT32 sz) +{ + /* + Handle whole chip reset messages + */ + ENUM_WMTRSTMSG_TYPE_T rst_msg; + + if (sz <= sizeof(ENUM_WMTRSTMSG_TYPE_T)) { + memcpy((PINT8)&rst_msg, (PINT8)buf, sz); + BT_DBG_FUNC("src = %d, dst = %d, type = %d, buf = 0x%x sz = %d, max = %d\n", src, + dst, type, rst_msg, sz, WMTRSTMSG_RESET_MAX); + if ((src == WMTDRV_TYPE_WMT) && (dst == WMTDRV_TYPE_BT) + && (type == WMTMSG_TYPE_RESET)) { + if (rst_msg == WMTRSTMSG_RESET_START) { + BT_INFO_FUNC("BT reset start!\n"); + rstflag = 1; + wake_up_interruptible(&inq); + + } else if (rst_msg == WMTRSTMSG_RESET_END) { + BT_INFO_FUNC("BT reset end!\n"); + rstflag = 2; + wake_up_interruptible(&inq); + } + } + } else { + /* Invalid message format */ + BT_WARN_FUNC("Invalid message format!\n"); + } +} + +static VOID BT_event_cb(VOID) +{ + BT_DBG_FUNC("BT_event_cb()\n"); + + flag = 1; + + /* + * Finally, wake up any reader blocked in poll or read + */ + wake_up_interruptible(&inq); + wake_up(&BT_wq); +} + +static unsigned int BT_poll(struct file *filp, poll_table *wait) +{ + UINT32 mask = 0; + +/* down(&wr_mtx); */ + + if (mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX)) { + poll_wait(filp, &inq, wait); + + if (!mtk_wcn_stp_is_rxqueue_empty(BT_TASK_INDX) || rstflag) + /* BT Rx queue has valid data, or whole chip reset occurs */ + mask |= POLLIN | POLLRDNORM; /* Readable */ + } else { + mask |= POLLIN | POLLRDNORM; /* Readable */ + } + + /* Do we need condition here? */ + mask |= POLLOUT | POLLWRNORM; /* Writable */ +/* up(&wr_mtx); */ + return mask; +} + +ssize_t BT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + INT32 retval = 0; + INT32 write_size; + INT32 written = 0; + + down(&wr_mtx); + + BT_DBG_FUNC("%s: count %zd pos %lld\n", __func__, count, *f_pos); + if (rstflag) { + if (rstflag == 1) { /* Reset start */ + retval = -88; + BT_INFO_FUNC("%s: detect whole chip reset start\n", __func__); + } else if (rstflag == 2) { /* Reset end */ + retval = -99; + BT_INFO_FUNC("%s: detect whole chip reset end\n", __func__); + } + goto OUT; + } + + if (count > 0) { + if (count < BT_BUFFER_SIZE) { + write_size = count; + } else { + write_size = BT_BUFFER_SIZE; + BT_ERR_FUNC("%s: count > BT_BUFFER_SIZE\n", __func__); + } + + if (copy_from_user(&o_buf[0], &buf[0], write_size)) { + retval = -EFAULT; + goto OUT; + } + + written = mtk_wcn_stp_send_data(&o_buf[0], write_size, BT_TASK_INDX); + if (0 == written) { + retval = -ENOSPC; + /* No space is available, native program should not call BT_write with no delay */ + BT_ERR_FUNC + ("Packet length %zd, sent length %d, retval = %d\n", + count, written, retval); + } else { + retval = written; + } + + } else { + retval = -EFAULT; + BT_ERR_FUNC("Packet length %zd is not allowed, retval = %d\n", count, retval); + } + +OUT: + up(&wr_mtx); + return retval; +} + +ssize_t BT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + static int chip_reset_count; + INT32 retval = 0; + + down(&rd_mtx); + + BT_DBG_FUNC("%s: count %zd pos %lld\n", __func__, count, *f_pos); + if (rstflag) { + if (rstflag == 1) { /* Reset start */ + retval = -88; + if ((chip_reset_count%500) == 0) + BT_INFO_FUNC("%s: detect whole chip reset start, %d\n", __func__, chip_reset_count); + chip_reset_count++; + } else if (rstflag == 2) { /* Reset end */ + retval = -99; + BT_INFO_FUNC("%s: detect whole chip reset end\n", __func__); + chip_reset_count = 0; + } + goto OUT; + } + + if (count > BT_BUFFER_SIZE) { + count = BT_BUFFER_SIZE; + BT_ERR_FUNC("%s: count > BT_BUFFER_SIZE\n", __func__); + } + + retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX); + + while (retval == 0) { /* Got nothing, wait for STP's signal */ + /* + * If nonblocking mode, return directly. + * O_NONBLOCK is specified during open() + */ + if (filp->f_flags & O_NONBLOCK) { + BT_DBG_FUNC("Non-blocking BT_read\n"); + retval = -EAGAIN; + goto OUT; + } + + BT_DBG_FUNC("%s: wait_event 1\n", __func__); + wait_event(BT_wq, flag != 0); + BT_DBG_FUNC("%s: wait_event 2\n", __func__); + flag = 0; + retval = mtk_wcn_stp_receive_data(i_buf, count, BT_TASK_INDX); + BT_DBG_FUNC("%s: mtk_wcn_stp_receive_data returns %d\n", __func__, retval); + } + + /* Got something from STP driver */ + if (copy_to_user(buf, i_buf, retval)) { + retval = -EFAULT; + goto OUT; + } + +OUT: + up(&rd_mtx); + BT_DBG_FUNC("%s: retval = %d\n", __func__, retval); + return retval; +} + +/* int BT_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) */ +long BT_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + INT32 retval = 0; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_TRUE; + ENUM_WMTHWVER_TYPE_T hw_ver_sym = WMTHWVER_INVALID; + + BT_DBG_FUNC("%s: cmd: 0x%x\n", __func__, cmd); + + switch (cmd) { + case COMBO_IOC_BT_HWVER: + /* Get combo HW version */ + hw_ver_sym = mtk_wcn_wmt_hwver_get(); + BT_INFO_FUNC("%s: HW version = %d, sizeof(hw_ver_sym) = %zd\n", + __func__, hw_ver_sym, sizeof(hw_ver_sym)); + if (copy_to_user((int __user *)arg, &hw_ver_sym, sizeof(hw_ver_sym))) + retval = -EFAULT; + break; + + case COMBO_IOCTL_FW_ASSERT: + /* Trigger FW assert for debug */ + BT_INFO_FUNC("%s: Host trigger FW assert......, reason:%lu\n", __func__, arg); + bRet = mtk_wcn_wmt_assert(WMTDRV_TYPE_BT, arg); + if (bRet == MTK_WCN_BOOL_TRUE) { + BT_INFO_FUNC("Host trigger FW assert succeed\n"); + retval = 0; + } else { + BT_ERR_FUNC("Host trigger FW assert Failed\n"); + retval = (-EBUSY); + } + break; + case COMBO_IOCTL_BT_IC_HW_VER: + retval = mtk_wcn_wmt_ic_info_get(WMTCHIN_HWVER); + break; + case COMBO_IOCTL_BT_IC_FW_VER: + retval = mtk_wcn_wmt_ic_info_get(WMTCHIN_FWVER); + break; + default: + retval = -EFAULT; + BT_ERR_FUNC("Unknown cmd (%d)\n", cmd); + break; + } + + return retval; +} + +long BT_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + return BT_unlocked_ioctl(filp, cmd, arg); +} + +static int BT_open(struct inode *inode, struct file *file) +{ + BT_INFO_FUNC("%s: major %d minor %d pid %d\n", __func__, imajor(inode), iminor(inode), current->pid); + if (current->pid == 1) + return 0; + + /* Turn on BT */ + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT)) { + BT_WARN_FUNC("WMT turn on BT fail!\n"); + return -ENODEV; + } + + BT_INFO_FUNC("WMT turn on BT OK!\n"); + rstflag = 0; + + if (mtk_wcn_stp_is_ready()) { + + mtk_wcn_stp_set_bluez(0); + + BT_INFO_FUNC("Now it's in MTK Bluetooth Mode\n"); + BT_INFO_FUNC("STP is ready!\n"); + + BT_DBG_FUNC("Register BT event callback!\n"); + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, BT_event_cb); + } else { + BT_ERR_FUNC("STP is not ready\n"); + mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT); + return -ENODEV; + } + + BT_DBG_FUNC("Register BT reset callback!\n"); + mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_BT, bt_cdev_rst_cb); + + /* init_MUTEX(&wr_mtx); */ + sema_init(&wr_mtx, 1); + /* init_MUTEX(&rd_mtx); */ + sema_init(&rd_mtx, 1); + BT_INFO_FUNC("%s: finish\n", __func__); + + return 0; +} + +static int BT_close(struct inode *inode, struct file *file) +{ + BT_INFO_FUNC("%s: major %d minor %d pid %d\n", __func__, imajor(inode), iminor(inode), current->pid); + if (current->pid == 1) + return 0; + + rstflag = 0; + mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_BT); + mtk_wcn_stp_register_event_cb(BT_TASK_INDX, NULL); + + if (MTK_WCN_BOOL_FALSE == mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT)) { + BT_ERR_FUNC("WMT turn off BT fail!\n"); + return -EIO; /* Mostly, native program will not check this return value. */ + } + + BT_INFO_FUNC("WMT turn off BT OK!\n"); + return 0; +} + +const struct file_operations BT_fops = { + .open = BT_open, + .release = BT_close, + .read = BT_read, + .write = BT_write, + /* .ioctl = BT_ioctl, */ + .unlocked_ioctl = BT_unlocked_ioctl, + .compat_ioctl = BT_compat_ioctl, + .poll = BT_poll +}; + +#if REMOVE_MK_NODE +struct class *stpbt_class = NULL; +#endif + +static int BT_init(void) +{ + dev_t dev = MKDEV(BT_major, 0); + INT32 alloc_ret = 0; + INT32 cdev_err = 0; +#if REMOVE_MK_NODE + struct device *stpbt_dev = NULL; +#endif +#ifdef MTK_BT_HCI + INT32 hci_err = 0; +#endif + + /* Static allocate char device */ + alloc_ret = register_chrdev_region(dev, 1, BT_DRIVER_NAME); + if (alloc_ret) { + BT_ERR_FUNC("%s: Failed to register char device\n", __func__); + return alloc_ret; + } + + cdev_init(&BT_cdev, &BT_fops); + BT_cdev.owner = THIS_MODULE; + + cdev_err = cdev_add(&BT_cdev, dev, BT_devs); + if (cdev_err) + goto error; + +#if REMOVE_MK_NODE + stpbt_class = class_create(/*THIS_MODULE,*/ "stpbt"); + if (IS_ERR(stpbt_class)) + goto error; + stpbt_dev = device_create(stpbt_class, NULL, dev, NULL, "stpbt"); + if (IS_ERR(stpbt_dev)) + goto error; +#endif + + BT_INFO_FUNC("%s driver(major %d) installed\n", BT_DRIVER_NAME, BT_major); + + /* Init wait queue */ + init_waitqueue_head(&(inq)); + +#ifdef MTK_BT_HCI + mtk_hci.hdev = hci_alloc_dev(); + if (!(mtk_hci.hdev)) { + BT_ERR_FUNC("%s hci_alloc_dev failed\n", __func__); + goto error; + } + + mtk_hci.hdev->bus = HCI_SDIO; + mtk_hci.hdev->open = mtk_bt_hci_open; + mtk_hci.hdev->close = mtk_bt_hci_close; + mtk_hci.hdev->send = mtk_bt_hci_send; + mtk_hci.hdev->flush = mtk_bt_hci_flush; + mtk_hci.hdev->notify = mtk_bt_hci_notify; + SET_HCIDEV_DEV(mtk_hci.hdev, stpbt_dev); + + mtk_wcn_stp_register_if_rx(/*mtk_bt_hci_receive*/ hci_stp_dev_init_rx_cb); + + hci_err = hci_register_dev(mtk_hci.hdev); + if (hci_err) { + BT_ERR_FUNC("%s hci_register_dev failed with %d\n", __func__, hci_err); + hci_free_dev(mtk_hci.hdev); + goto error; + } + + skb_queue_head_init(&mtk_hci.txq); + INIT_WORK(&mtk_hci.work, mtk_bt_hci_work); +#endif + + return 0; + +error: + +#if REMOVE_MK_NODE + if (!IS_ERR(stpbt_dev)) + device_destroy(stpbt_class, dev); + if (!IS_ERR(stpbt_class)) { + class_destroy(stpbt_class); + stpbt_class = NULL; + } +#endif + if (cdev_err == 0) + cdev_del(&BT_cdev); + + if (alloc_ret == 0) + unregister_chrdev_region(dev, BT_devs); + + return -1; +} + +static void BT_exit(void) +{ + dev_t dev = MKDEV(BT_major, 0); + +#ifdef MTK_BT_HCI + if (mtk_hci.hdev) { + hci_unregister_dev(mtk_hci.hdev); + hci_free_dev(mtk_hci.hdev); + mtk_hci.hdev = NULL; + } +#endif + +#if REMOVE_MK_NODE + device_destroy(stpbt_class, dev); + class_destroy(stpbt_class); + stpbt_class = NULL; +#endif + + cdev_del(&BT_cdev); + unregister_chrdev_region(dev, BT_devs); + + BT_INFO_FUNC("%s driver removed\n", BT_DRIVER_NAME); +} + +#if REMOVE_MK_NODE + +int mtk_wcn_stpbt_drv_init(void) +{ + return BT_init(); +} +EXPORT_SYMBOL(mtk_wcn_stpbt_drv_init); + +void mtk_wcn_stpbt_drv_exit(void) +{ + return BT_exit(); +} +EXPORT_SYMBOL(mtk_wcn_stpbt_drv_exit); + +#else + +module_init(BT_init); +module_exit(BT_exit); + +#endif diff --git a/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/Android.mk b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/Android.mk new file mode 100644 index 00000000000000..f4eb39af8c2727 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/Android.mk @@ -0,0 +1,44 @@ +# Copyright Statement: +# + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +local_path_full := $(shell pwd)/$(LOCAL_PATH) +btsdio_module_out_path := $(ANDROID_PRODUCT_OUT)$(BT_DRIVER_MODULE_PATH) +btsdio_module_target := $(btsdio_module_out_path) + +#current parameter name for target arch on VSB is $(TARGET_ARCH) +ifeq ($(TARGET_KERNEL_ARCH),) +TARGET_KERNEL_ARCH := $(TARGET_ARCH) +endif + +#avoid $(KERNEL_OUT)is not defined +ifeq ($(KERNEL_OUT),) +KERNEL_OUT := $(ANDROID_PRODUCT_OUT)/obj/KERNEL_OBJ +endif + +LOCAL_MODULE := $(BT_DRIVER_MODULE_NAME) +LOCAL_MODULE_TAGS := optional +LOCAL_ADDITIONAL_DEPENDENCIES := $(btsdio_module_target) + +include $(BUILD_PHONY_PACKAGE) + +$(LOCAL_ADDITIONAL_DEPENDENCIES): PRIVATE_DRIVER_LOCAL_DIR := $(local_path_full) +$(LOCAL_ADDITIONAL_DEPENDENCIES): PRIVATE_DRIVER_OUT := $(btsdio_module_out_path) +$(LOCAL_ADDITIONAL_DEPENDENCIES): $(INSTALLED_KERNEL_TARGET) + $(hide) rm -rf $(PRIVATE_DRIVER_OUT) +ifeq ($(MTK_I2S_PCM), true) + $(MAKE) -C $(KERNEL_OUT) MTK_CHIP_PCM=TRUE M=$(PRIVATE_DRIVER_LOCAL_DIR) ARCH=$(TARGET_KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules + $(MAKE) -C $(KERNEL_OUT) MTK_CHIP_PCM=TRUE M=$(PRIVATE_DRIVER_LOCAL_DIR) ARCH=$(TARGET_KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules INSTALL_MOD_PATH=$(ANDROID_PRODUCT_OUT)/obj/KERNEL_OBJ modules_install +else + $(MAKE) -C $(KERNEL_OUT) M=$(PRIVATE_DRIVER_LOCAL_DIR) ARCH=$(TARGET_KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules + $(MAKE) -C $(KERNEL_OUT) M=$(PRIVATE_DRIVER_LOCAL_DIR) ARCH=$(TARGET_KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) modules INSTALL_MOD_PATH=$(ANDROID_PRODUCT_OUT)/obj/KERNEL_OBJ modules_install +endif + $(KERNEL_CROSS_COMPILE)strip -g $(PRIVATE_DRIVER_LOCAL_DIR)/$(BT_DRIVER_MODULE_NAME).ko + $(hide) cp -f $(PRIVATE_DRIVER_LOCAL_DIR)/$(BT_DRIVER_MODULE_NAME).ko $(PRIVATE_DRIVER_OUT) + $(MAKE) -C $(KERNEL_OUT) M=$(PRIVATE_DRIVER_LOCAL_DIR) ARCH=$(TARGET_KERNEL_ARCH) CROSS_COMPILE=$(KERNEL_CROSS_COMPILE) clean + +local_path_full := +btsdio_module_out_path := +btsdio_module_target := diff --git a/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/Makefile b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/Makefile new file mode 100644 index 00000000000000..40b5f9c1eaf4e5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/Makefile @@ -0,0 +1,65 @@ +export KBUILD_VERBOSE=1 +export LINUX_SRC := $(srctree) #/lib/modules/$(shell uname -r)/build + +############################################################################### +# SDIO +############################################################################### +ifneq ($(KERNELRELEASE),) +ccflags-y += -DDBG=0 +ccflags-y += -I$(src)/../wlan/os +ccflags-y += -I$(src)/../wlan/core/gen4-mt7668/os/linux/include +ccflags-y += -I$(src)/../common/common_main/linux/include +ccflags-y += -I$(src)/../conninfra/base/include +ccflags-y += -I$(src)/../common/common_main/include + +ifeq ($(MTK_CHIP_PCM), TRUE) + ccflags-y += -DMTK_CHIP_PCM +endif + +SDIO_MOD_NAME := btmtksdio +SDIO_CFILES := \ + btmtk_sdio.c \ + btmtk_main.c +export CONFIG_AMAZON_A2DP_TS_SDIO=y + +ifeq ($(CONFIG_AMAZON_A2DP_TS_SDIO),y) + SDIO_CFILES += btif_audio_ts.c +endif + +ifneq ($(TARGET_BUILD_VARIANT), user) + ccflags-y += -DMTK_KERNEL_DEBUG +endif + +$(SDIO_MOD_NAME)-objs := $(SDIO_CFILES:.c=.o) + +############################################################################### +# Common +############################################################################### +obj-$(CONFIG_MTK_COMBO_BT_MT7668_SDIO) := $(SDIO_MOD_NAME).o + +else +PWD := $(shell pwd) + +all: + make -C $(LINUX_SRC) M=$(PWD) PLATFORM_FLAGS="$(ccflags-y)" modules + +sdio: + make -C $(LINUX_SRC) M=$(PWD) $(SDIO_MOD_NAME).ko +modules_install: + make -C $(LINUX_SRC) M=`pwd` modules_install INSTALL_MOD_PATH=$(LINUX_SRC)-build +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions bin2h + rm -f Module.markers + rm -f Module.symvers + rm -f modules.order + +# Check coding style +export IGNORE_CODING_STYLE_RULES := NEW_TYPEDEFS,LEADING_SPACE,CODE_INDENT,SUSPECT_CODE_INDENT +ccs: + ./util/checkpatch.pl --no-tree --show-types --max-line-length=120 --ignore $(IGNORE_CODING_STYLE_RULES) -f btmtk_main.c + ./util/checkpatch.pl --no-tree --show-types --max-line-length=120 --ignore $(IGNORE_CODING_STYLE_RULES) -f btmtk_sdio.c + ./util/checkpatch.pl --no-tree --show-types --max-line-length=120 --ignore $(IGNORE_CODING_STYLE_RULES) -f btmtk_sdio.h + ./util/checkpatch.pl --no-tree --show-types --max-line-length=120 --ignore $(IGNORE_CODING_STYLE_RULES) -f btmtk_config.h + ./util/checkpatch.pl --no-tree --show-types --max-line-length=120 --ignore $(IGNORE_CODING_STYLE_RULES) -f btmtk_define.h + ./util/checkpatch.pl --no-tree --show-types --max-line-length=120 --ignore $(IGNORE_CODING_STYLE_RULES) -f btmtk_drv.h +endif \ No newline at end of file diff --git a/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btif_audio_ts.c b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btif_audio_ts.c new file mode 100644 index 00000000000000..2180aa240c450f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btif_audio_ts.c @@ -0,0 +1,226 @@ +#include "btif_audio_ts.h" + +#include +#include +#include +#include +#include + +struct BtifAudioTs { + unsigned long long local_time; + unsigned int audio_time; +}; + +/* Device driver-related */ +#define DEVICE_NAME "btts" +#define CLASS_NAME "bttscl" +#define STPBT_GET_TS _IOR('w', 10, struct BtifAudioTs) +static int g_major_num; +static struct class *g_dev_class; +static struct device *g_device; + +/* Timestamp for sample 0 */ +static DEFINE_SPINLOCK(g_ts0_lock); +static struct BtifAudioTs g_ts0; + +/* Timestamp ring buffer */ +#define TS_BUFFER_SIZE 128 +#define TS_READ_MIN (TS_BUFFER_SIZE / 4) +static DEFINE_SPINLOCK(g_ts_buffer_lock); +static struct BtifAudioTs g_ts_buffer[TS_BUFFER_SIZE]; +static int g_rptr, g_wptr, g_buf_size; + +/** + Add timestamp and GPT value to the storage. + If ringbuffer is full we do not wait for more space available, + we overwrite the oldest value. +*/ +void btif_update_audio_ts(unsigned int audio_ts, u64 ts) +{ + if (audio_ts == 0) { + spin_lock(&g_ts0_lock); + g_ts0.audio_time = audio_ts; + g_ts0.local_time = ts; + spin_unlock(&g_ts0_lock); + } + + spin_lock(&g_ts_buffer_lock); + /* clean the buffer if stream is restarted */ + if (audio_ts == 0) { + g_rptr = g_wptr = g_buf_size = 0; + } + /* put data into the buffer */ + g_ts_buffer[g_wptr].audio_time = audio_ts; + g_ts_buffer[g_wptr].local_time = ts; + /* update pointers and size */ + if (++g_wptr >= TS_BUFFER_SIZE) { + g_wptr = 0; + } + if (g_buf_size < TS_BUFFER_SIZE) { + ++g_buf_size; + } else { + g_rptr = g_wptr; + } + spin_unlock(&g_ts_buffer_lock); +} + +/**** Driver ****/ + +static int dev_open(struct inode *inodep, struct file *filep) +{ + pr_debug("BTTS: flags %x\n", filep->f_flags); + if ((filep->f_flags & O_NONBLOCK) == 0) { + pr_err("BTTS: blocking operations are not supported"); + return -EINVAL; + } + return 0; +} + +/** + Read API. + Reads at least TS_READ_MIN BtifAudioTs structs from timestamp ringbuffer. + If no data is available, the call does not block and returns -EAGAIN, + user space should retry at a later point. +*/ +static ssize_t dev_read(struct file *filep, + char *buffer, size_t len, loff_t *offset) +{ + size_t entries_to_read = len / sizeof(struct BtifAudioTs); + size_t tail_size = 0, size = 0; + ssize_t retval = -EACCES; + + spin_lock(&g_ts_buffer_lock); + + if (entries_to_read > g_buf_size) { + if (g_buf_size < TS_READ_MIN) { + retval = -EAGAIN; + goto fail; + } + entries_to_read = g_buf_size; + } + + if (g_rptr + entries_to_read > TS_BUFFER_SIZE) { + tail_size = (TS_BUFFER_SIZE - g_rptr) * + sizeof(struct BtifAudioTs); + if (copy_to_user(buffer, + g_ts_buffer + g_rptr, tail_size)) { + goto fail; + } + g_buf_size -= (TS_BUFFER_SIZE - g_rptr); + entries_to_read -= (TS_BUFFER_SIZE - g_rptr); + g_rptr = 0; + *offset += tail_size; + buffer += tail_size; + retval = tail_size; + } + + size = entries_to_read * sizeof(struct BtifAudioTs); + if (copy_to_user(buffer, g_ts_buffer + g_rptr, size)) { + goto fail; + } + g_buf_size -= entries_to_read; + g_rptr += entries_to_read; + *offset += size; + retval += size; + +fail: + spin_unlock(&g_ts_buffer_lock); + + return retval; +} + +/** + ioctl API. + Handles STPBT_GET_TS command. Returns a BtifAudioTs struct + which corresponds to the beginning of a stream. + If called before the first stream playback, will return {0,0}. +*/ +static long dev_unlocked_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + long retval = 0; + + switch (cmd) { + case STPBT_GET_TS: { + struct BtifAudioTs ts; + + spin_lock(&g_ts0_lock); + ts = g_ts0; + spin_unlock(&g_ts0_lock); + + if (copy_to_user((struct BtifAudioTs __user *)arg, + &ts, sizeof(ts))) { + retval = -EACCES; + } + break; + } + default: + retval = -EFAULT; + pr_err("BTTS: unknown cmd (%x)\n", cmd); + break; + } + + return retval; +} + +static long dev_compat_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + return dev_unlocked_ioctl(filp, cmd, arg); +} + +static int dev_release(struct inode *inodep, struct file *filep) +{ + pr_debug("BTTS: release\n"); + return 0; +} + +static const struct file_operations fops = { + .open = dev_open, + .read = dev_read, + .unlocked_ioctl = dev_unlocked_ioctl, + .compat_ioctl = dev_compat_ioctl, + .release = dev_release, +}; + +int btif_ts_init(void) +{ + pr_debug("BTTS: initializing\n"); + + /* Try to dynamically allocate a major number for the device */ + g_major_num = register_chrdev(0, DEVICE_NAME, &fops); + if (g_major_num < 0) { + pr_alert("BTTS: failed to register a major number\n"); + return g_major_num; + } + + /* Register the device class */ + g_dev_class = class_create(/*THIS_MODULE,*/ CLASS_NAME); + if (IS_ERR(g_dev_class)) { + unregister_chrdev(g_major_num, DEVICE_NAME); + pr_alert("BTTS: failed to register device class\n"); + return PTR_ERR(g_dev_class); + } + + /* Register the device driver */ + g_device = device_create(g_dev_class, + NULL, MKDEV(g_major_num, 0), NULL, DEVICE_NAME); + if (IS_ERR(g_device)) { + class_destroy(g_dev_class); + unregister_chrdev(g_major_num, DEVICE_NAME); + pr_alert("BTTS: failed to create the device\n"); + return PTR_ERR(g_device); + } + pr_debug("BTTS: initialized\n"); + return 0; +} + +void btif_ts_exit(void) +{ + device_destroy(g_dev_class, MKDEV(g_major_num, 0)); + class_unregister(g_dev_class); + class_destroy(g_dev_class); + unregister_chrdev(g_major_num, DEVICE_NAME); + pr_debug("BTTS: exit\n"); +} + diff --git a/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btif_audio_ts.h b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btif_audio_ts.h new file mode 100644 index 00000000000000..845e4338b94074 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btif_audio_ts.h @@ -0,0 +1,16 @@ +#ifndef _BTIF_AUDIO_TS_H_ +#define _BTIF_AUDIO_TS_H_ + +#include + +extern u64 mtk_timer_get_cnt(u8 timer); + +/* Report audio timestamp and timer value corresponding to it */ +void btif_update_audio_ts(unsigned int audio_ts, u64 ts); + +/* Driver registration/deregistration */ +int btif_ts_init(void); +void btif_ts_exit(void); + +#endif /* _BTIF_AUDIO_TS_H_ */ + diff --git a/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_config.h b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_config.h new file mode 100644 index 00000000000000..5e0883d9c9fcb4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_config.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016,2017 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef __BTMTK_CONFIG_H__ +#define __BTMTK_CONFIG_H__ + +#include +#include + +/* It's for reset procedure */ +#include +#include + +/** + * Kernel configuration check + */ +#ifndef CONFIG_PM + //#error "ERROR : CONFIG_PM should be turn on." +#endif + +/** + * Support IC configuration + */ +#define SUPPORT_MT7662 1 +#define SUPPORT_MT7668 1 +#define SUPPORT_MT7663 1 + +/** + * Debug Level Configureation + */ +#define ENABLE_BT_FIFO_THREAD 1 + +/** + * BTMTK LOG location, last char must be '/' + */ +/* #define BTMTK_LOG_PATH "/data/misc/bluedroid/" */ + + + +/** + * Fixed STPBT Major Device Id + */ +#define FIXED_STPBT_MAJOR_DEV_ID 111 + +/** + * GPIO PIN configureation + */ +#ifndef BT_DONGLE_RESET_GPIO_PIN + #define BT_DONGLE_RESET_GPIO_PIN 220 +#endif /* BT_DONGLE_RESET_GPIO_PIN */ + + +/** + * WoBLE by BLE RC + */ +#define SUPPORT_ANDROID 0 /*Linux build fail due to wake_lock, please set SUPPORT_ANDROID 0 for Linux*/ +#define SUPPORT_UNIFY_WOBLE 0 +#define SUPPORT_LEGACY_WOBLE 0 +#define BT_RC_VENDOR_DEFAULT 1 +#define BT_RC_VENDOR_S0 0 +#define SUPPORT_EINT 0 + +#if SUPPORT_EINT +#define WAIT_POWERKEY_TIMEOUT 5000 +#endif + +/** + * Support toggle GPIO + */ +#define MT76x8_PMU_EN_PIN_NAME "mt76x8_pmu_en_gpio" +#define MT76x8_PMU_EN_DELAY_NAME "mt76x8_pmu_en_delay" +#define MT76x8_PMU_EN_DEFAULT_DELAY (5) /* Default delay 5ms */ + +#endif /* __BTMTK_CONFIG_H__ */ diff --git a/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_define.h b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_define.h new file mode 100644 index 00000000000000..61bdb5ab8a4a23 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_define.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2016,2017 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef __BTMTK_DEFINE_H__ +#define __BTMTK_DEFINE_H__ + +#include "btmtk_config.h" + +/** + * Type definition + */ +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + +#ifndef UNUSED + #define UNUSED(x) (void)(x) +#endif + +//#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +//#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +/** + * Log level definition + */ +#define BTMTK_LOG_LEVEL_ERROR 1 +#define BTMTK_LOG_LEVEL_WARNING 2 +#define BTMTK_LOG_LEVEL_INFO 3 +#define BTMTK_LOG_LEVEL_DEBUG 4 +#define BTMTK_LOG_LEVEL_DEFAULT BTMTK_LOG_LEVEL_INFO /* default setting */ + +#define BTSDIO_INFO_RAW(p, l, fmt, ...) \ + do { \ + int raw_count = 0; \ + const unsigned char *ptr = p; \ + pr_info("[btmtk_info] "fmt, ##__VA_ARGS__); \ + for (raw_count = 0; raw_count <= l; ++raw_count) \ + pr_info(" %02X", ptr[raw_count]); \ + pr_info("\n"); \ + } while (0) + +#define BTSDIO_DEBUG_RAW(p, l, fmt, ...) \ + do { \ + int raw_count = 0; \ + const unsigned char *ptr = p; \ + pr_debug("[btmtk_info] "fmt, ##__VA_ARGS__); \ + for (raw_count = 0; raw_count <= l; ++raw_count) \ + pr_debug(" %02X", ptr[raw_count]); \ + pr_debug("\n"); \ + } while (0) + +/** + * HCI packet type + */ +#define MTK_HCI_COMMAND_PKT 0x01 +#define MTK_HCI_ACLDATA_PKT 0x02 +#define MTK_HCI_SCODATA_PKT 0x03 +#define MTK_HCI_EVENT_PKT 0x04 + +#define MTK_HCI_WRITE_CR_PKT 0x07 +#define MTK_HCI_READ_CR_PKT 0x08 + +#define MTK_HCI_READ_CR_PKT_LENGTH 0x05 +#define MTK_HCI_WRITE_CR_PKT_LENGTH 0x09 + +#define MTK_HCI_CMD_HEADER_LEN (4) +#define MTK_HCI_ACL_HEADER_LEN (5) +#define MTK_HCI_SCO_HEADER_LEN (4) + +/** + * Log file path & name, the default path is /sdcard + */ +#define PRINT_DUMP_COUNT 20 +#define SYSLOG_FNAME "bt_sys_log" +#define FWDUMP_FNAME "bt_fw_dump" + +char *COREDUMP_FILE_NAME[] = { + "/data/misc/bluedroid/"FWDUMP_FNAME, "/sdcard/"FWDUMP_FNAME, "/tmp/"FWDUMP_FNAME +}; + +/** + * WLAN + */ +#define WLAN 0x410000 + +/** + * MCUCTL + */ +#define CLOCK_CTL 0x0708 +#define INT_LEVEL 0x0718 +#define COM_REG0 0x0730 +#define SEMAPHORE_00 0x07B0 +#define SEMAPHORE_01 0x07B4 +#define SEMAPHORE_02 0x07B8 +#define SEMAPHORE_03 0x07BC + +/** + * Timeout setting, mescs + */ +#define USB_CTRL_IO_TIMO 100 +#define USB_INTR_MSG_TIMO 2000 + + +/** + * USB request type definition + */ +#define DEVICE_VENDOR_REQUEST_OUT 0x40 +#define DEVICE_VENDOR_REQUEST_IN 0xc0 +#define DEVICE_CLASS_REQUEST_OUT 0x20 +#define DEVICE_CLASS_REQUEST_IN 0xa0 + +#define BTUSB_MAX_ISOC_FRAMES 10 +#define BTUSB_INTR_RUNNING 0 +#define BTUSB_BULK_RUNNING 1 +#define BTUSB_ISOC_RUNNING 2 +#define BTUSB_SUSPENDING 3 +#define BTUSB_DID_ISO_RESUME 4 + +/** + * ROM patch related + */ +#define PATCH_HCI_HEADER_SIZE 4 +#define PATCH_WMT_HEADER_SIZE 5 +#define PATCH_HEADER_SIZE (PATCH_HCI_HEADER_SIZE + PATCH_WMT_HEADER_SIZE) +#define UPLOAD_PATCH_UNIT 2048 +#define PATCH_INFO_SIZE 30 +#define PATCH_PHASE1 1 +#define PATCH_PHASE2 2 +#define PATCH_PHASE3 3 +#define PATCH_LEN_ILM (192 * 1024) + + +#define USB_IO_BUF_SIZE (HCI_MAX_EVENT_SIZE > 256 ? HCI_MAX_EVENT_SIZE : 256) +#define HCI_SNOOP_ENTRY_NUM 30 +#define HCI_SNOOP_BUF_SIZE 32 + +/** + * stpbt device node + */ +#define BUFFER_SIZE (1024 * 4) /* Size of RX Queue */ +#define IOC_MAGIC 0xb0 +#define IOCTL_FW_ASSERT _IOWR(IOC_MAGIC, 0, void *) + +/** + * fw log queue count + */ +#define FWLOG_QUEUE_COUNT 200 +#define FWLOG_ASSERT_QUEUE_COUNT 6000 +#define FWLOG_BLUETOOTH_KPI_QUEUE_COUNT 200 + +/** + * Maximum rom patch file name length + */ +#define MAX_BIN_FILE_NAME_LEN 32 + +/** + * Firmware version size + */ +#define FW_VERSION_BUF_SIZE 32 /* 14 bytes for firmware version + 1 bytes for '0' */ +#define FW_VERSION_SIZE 15 /* 14 bytes for firmware version + 1 bytes for '0' */ + +#endif /* __BTMTK_DEFINE_H__ */ diff --git a/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_drv.h b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_drv.h new file mode 100644 index 00000000000000..ee104365be6860 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_drv.h @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2016,2017 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _BTMTK_DRV_H_ +#define _BTMTK_DRV_H_ + +#include +#include +#include +#include + +#define SAVE_FW_DUMP_IN_KERNEL 1 + +#define SUPPORT_FW_DUMP 1 +#define BTM_HEADER_LEN 5 + +#define MTK_TXDATA_SIZE 2000 +#define MTK_RXDATA_SIZE 2000 + +/* Time to wait until Host Sleep state change in millisecond */ +#define WAIT_UNTIL_HS_STATE_CHANGED msecs_to_jiffies(5000) +/* Time to wait for command response in millisecond */ +#define WAIT_UNTIL_CMD_RESP msecs_to_jiffies(5000) + +#define BTMTK_BIN_FILE_MODE 1 +#if BTMTK_BIN_FILE_MODE +/** For 7668 please storage cfg/bin file in ${firmware} */ +#define E2P_ACCESS_MODE_SWITCHER "wifi.cfg" +#define E2P_BIN_FILE "EEPROM_MT%X.bin" + +#define E2P_MODE "EfuseBufferModeCal" +#define BIN_FILE_MODE '1' +#define AUTO_MODE '2' +#endif + +enum rdwr_status { + RDWR_STATUS_SUCCESS = 0, + RDWR_STATUS_FAILURE = 1, + RDWR_STATUS_DONE = 2 +}; + +#define FW_DUMP_MAX_NAME_LEN 8 +#define FW_DUMP_HOST_READY 0xEE +#define FW_DUMP_DONE 0xFF +#define FW_DUMP_READ_DONE 0xFE + +struct memory_type_mapping { + u8 mem_name[FW_DUMP_MAX_NAME_LEN]; + u8 *mem_ptr; + u32 mem_size; + u8 done_flag; +}; + +struct btmtk_thread { + struct task_struct *task; + wait_queue_head_t wait_q; + void *priv; + u8 thread_status; +}; + +struct btmtk_device { + void *card; + /* struct hci_dev *hcidev; */ + + u8 dev_type; + u8 reset_progress; + u8 reset_dongle; + u8 tx_dnld_rdy; + + u8 psmode; + u8 pscmd; + u8 hsmode; + u8 hscmd; + + /* Low byte is gap, high byte is GPIO */ + u16 gpio_gap; + + u8 hscfgcmd; + u8 sendcmdflag; +}; + +struct btmtk_adapter { + void *hw_regs_buf; + u8 *hw_regs; + u32 int_count; + struct sk_buff_head tx_queue; + struct sk_buff_head fops_queue; + struct sk_buff_head fwlog_fops_queue; + struct sk_buff_head fwlog_tx_queue; + u8 fops_mode; + u8 psmode; + u8 ps_state; + u8 hs_state; + u8 wakeup_tries; + wait_queue_head_t cmd_wait_q; + wait_queue_head_t event_hs_wait_q; + u8 cmd_complete; + bool is_suspended; +}; + +struct btmtk_private { + struct btmtk_device btmtk_dev; + struct btmtk_adapter *adapter; + struct btmtk_thread main_thread; + int (*hw_host_to_card)(struct btmtk_private *priv, + u8 *payload, u16 nb); + + void (*start_reset_dongle_progress)(void); + int (*hw_sdio_reset_dongle)(void); + int (*hw_set_own_back)(int owntype); + int (*hw_process_int_status)(struct btmtk_private *priv); + void (*firmware_dump)(struct btmtk_private *priv); + spinlock_t driver_lock; /* spinlock used by driver */ +#ifdef CONFIG_DEBUG_FS + void *debugfs_data; +#endif + bool surprise_removed; +#if SUPPORT_FW_DUMP + struct semaphore fw_dump_semaphore; + struct task_struct *fw_dump_tsk; + struct task_struct *fw_dump_end_check_tsk; +#endif + struct semaphore wr_mtx; + struct semaphore rd_mtx; + struct semaphore wr_fwlog_mtx; + bool no_fw_own; +}; + +#define MTK_VENDOR_PKT 0xFE + +/* Vendor specific Bluetooth commands */ +#define BT_CMD_PSCAN_WIN_REPORT_ENABLE 0xFC03 +#define BT_CMD_ROUTE_SCO_TO_HOST 0xFC1D +#define BT_CMD_SET_BDADDR 0xFC22 +#define BT_CMD_AUTO_SLEEP_MODE 0xFC23 +#define BT_CMD_HOST_SLEEP_CONFIG 0xFC59 +#define BT_CMD_HOST_SLEEP_ENABLE 0xFC5A +#define BT_CMD_MODULE_CFG_REQ 0xFC5B +#define BT_CMD_LOAD_CONFIG_DATA 0xFC61 + +/* Sub-commands: Module Bringup/Shutdown Request/Response */ +#define MODULE_BRINGUP_REQ 0xF1 +#define MODULE_BROUGHT_UP 0x00 +#define MODULE_ALREADY_UP 0x0C + +#define MODULE_SHUTDOWN_REQ 0xF2 + +/* Vendor specific Bluetooth events */ +#define BT_EVENT_AUTO_SLEEP_MODE 0x23 +#define BT_EVENT_HOST_SLEEP_CONFIG 0x59 +#define BT_EVENT_HOST_SLEEP_ENABLE 0x5A +#define BT_EVENT_MODULE_CFG_REQ 0x5B +#define BT_EVENT_POWER_STATE 0x20 + +/* Bluetooth Power States */ +#define BT_PS_ENABLE 0x02 +#define BT_PS_DISABLE 0x03 +#define BT_PS_SLEEP 0x01 + +/* Host Sleep states */ +#define HS_ACTIVATED 0x01 +#define HS_DEACTIVATED 0x00 + +/* Power Save modes */ +#define PS_SLEEP 0x01 +#define PS_AWAKE 0x00 + +#define BT_CAL_HDR_LEN 4 +#define BT_CAL_DATA_SIZE 28 + +#define FW_DUMP_BUF_SIZE (1024*512) + +#define FW_DUMP_FILE_NAME_SIZE 64 + +#define EVENT_COMPARE_SIZE 64 + + +/* #define SAVE_FW_DUMP_IN_KERNEL 1 */ + +/* stpbt device node */ +#define BT_NODE "stpbt" +#define BT_DRIVER_NAME "BT_chrdev" + +struct btmtk_event { + u8 ec; /* event counter */ + u8 length; + u8 data[4]; +} __packed; + +/* Prototype of global function */ + +struct btmtk_private *btmtk_add_card(void *card); +int btmtk_remove_card(struct btmtk_private *priv); + +void btmtk_interrupt(struct btmtk_private *priv); + +bool btmtk_check_evtpkt(struct btmtk_private *priv, struct sk_buff *skb); +int btmtk_process_event(struct btmtk_private *priv, struct sk_buff *skb); + +int btmtk_send_module_cfg_cmd(struct btmtk_private *priv, u8 subcmd); +int btmtk_pscan_window_reporting(struct btmtk_private *priv, u8 subcmd); +int btmtk_send_hscfg_cmd(struct btmtk_private *priv); +int btmtk_enable_ps(struct btmtk_private *priv); +int btmtk_prepare_command(struct btmtk_private *priv); +int btmtk_enable_hs(struct btmtk_private *priv); +void btmtk_firmware_dump(struct btmtk_private *priv); + +ssize_t btmtk_fops_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); +ssize_t btmtk_fops_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); +unsigned int btmtk_fops_poll(struct file *filp, poll_table *wait); +long btmtk_fops_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#define META_BUFFER_SIZE (1024*50) + +struct _OSAL_UNSLEEPABLE_LOCK_ { + spinlock_t lock; + unsigned long flag; +}; + +struct ring_buffer { + struct _OSAL_UNSLEEPABLE_LOCK_ spin_lock; + u8 buffer[META_BUFFER_SIZE]; /* MTKSTP_BUFFER_SIZE:1024 */ + u32 read_p; /* indicate the current read index */ + u32 write_p; /* indicate the current write index */ +}; + +#ifdef CONFIG_DEBUG_FS + +#define FIXED_STPBT_MAJOR_DEV_ID 111 + + + +#define FW_DUMP_END_EVENT "coredump end" + +#endif + +#endif + diff --git a/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_main.c b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_main.c new file mode 100644 index 00000000000000..81296161a5c399 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_main.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2016,2017 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "btmtk_drv.h" +#include "btmtk_sdio.h" + +/* + * This function is called by interface specific interrupt handler. + * It updates Power Save & Host Sleep states, and wakes up the main + * thread. + */ +void btmtk_interrupt(struct btmtk_private *priv) +{ + priv->adapter->ps_state = PS_AWAKE; + + priv->adapter->wakeup_tries = 0; + + priv->adapter->int_count++; + + wake_up_interruptible(&priv->main_thread.wait_q); +} +EXPORT_SYMBOL_GPL(btmtk_interrupt); + +int btmtk_enable_hs(struct btmtk_private *priv) +{ + struct btmtk_adapter *adapter = priv->adapter; + int ret = 0; + + pr_info("%s begin\n", __func__); + + ret = wait_event_interruptible_timeout(adapter->event_hs_wait_q, + adapter->hs_state, + msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED)); + if (ret < 0) { + pr_err("event_hs_wait_q terminated (%d): %d,%d,%d\n", + ret, adapter->hs_state, adapter->ps_state, + adapter->wakeup_tries); + + } else { + pr_debug("host sleep enabled: %d,%d,%d\n", adapter->hs_state, + adapter->ps_state, adapter->wakeup_tries); + ret = 0; + } + + return ret; +} +EXPORT_SYMBOL_GPL(btmtk_enable_hs); + +static int btmtk_tx_pkt(struct btmtk_private *priv, struct sk_buff *skb) +{ + int ret = 0; + u32 sdio_header_len = 0; + + if (!skb) { + pr_warn("%s skb is NULL return -EINVAL\n", __func__); + return -EINVAL; + } + + pr_debug("%s skb->len %d\n", __func__, skb->len); + + if (!skb->data) { + pr_warn("%s skb->data is NULL return -EINVAL\n", __func__); + return -EINVAL; + } + + if (!skb->len || ((skb->len + BTM_HEADER_LEN) > MTK_TXDATA_SIZE)) { + pr_warn("Tx Error: Bad skb length %d : %d\n", + skb->len, MTK_TXDATA_SIZE); + return -EINVAL; + } + + sdio_header_len = skb->len + BTM_HEADER_LEN; + memset(txbuf, 0, MTK_TXDATA_SIZE); + txbuf[0] = (sdio_header_len & 0x0000ff); + txbuf[1] = (sdio_header_len & 0x00ff00) >> 8; + txbuf[2] = 0; + txbuf[3] = 0; + txbuf[4] = bt_cb(skb)->pkt_type; + memcpy(&txbuf[5], &skb->data[0], skb->len); + if (priv->hw_host_to_card) + ret = priv->hw_host_to_card(priv, txbuf, sdio_header_len); + + pr_debug("%s end\n", __func__); + return ret; +} + +static void btmtk_init_adapter(struct btmtk_private *priv) +{ + int buf_size; + + skb_queue_head_init(&priv->adapter->tx_queue); + skb_queue_head_init(&priv->adapter->fops_queue); + skb_queue_head_init(&priv->adapter->fwlog_fops_queue); + priv->adapter->ps_state = PS_AWAKE; + + buf_size = ALIGN_SZ(SDIO_BLOCK_SIZE, BTSDIO_DMA_ALIGN); + priv->adapter->hw_regs_buf = kzalloc(buf_size, GFP_KERNEL); + if (!priv->adapter->hw_regs_buf) { + priv->adapter->hw_regs = NULL; + pr_err("Unable to allocate buffer for hw_regs.\n"); + } else { + priv->adapter->hw_regs = + (u8 *)ALIGN_ADDR(priv->adapter->hw_regs_buf, + BTSDIO_DMA_ALIGN); + pr_debug("hw_regs_buf=%p hw_regs=%p\n", + priv->adapter->hw_regs_buf, priv->adapter->hw_regs); + } + + init_waitqueue_head(&priv->adapter->cmd_wait_q); + init_waitqueue_head(&priv->adapter->event_hs_wait_q); +} + +static void btmtk_free_adapter(struct btmtk_private *priv) +{ + skb_queue_purge(&priv->adapter->tx_queue); + + kfree(priv->adapter->hw_regs_buf); + kfree(priv->adapter); + + priv->adapter = NULL; +} + +/* + * This function handles the event generated by firmware, rx data + * received from firmware, and tx data sent from kernel. + */ +static int btmtk_service_main_thread(void *data) +{ + struct btmtk_thread *thread = data; + struct btmtk_private *priv = thread->priv; + struct btmtk_adapter *adapter = NULL; + wait_queue_entry_t wait; + struct sk_buff *skb; + int ret = 0; + int i = 0; + ulong flags; + struct sched_param param = { .sched_priority = 90 }; + + sched_setscheduler(current, SCHED_RR, ¶m); + + pr_notice("main_thread begin 50\n"); + /* mdelay(50); */ + + for (i = 0; i <= 1000; i++) { + if (kthread_should_stop()) { + pr_notice("main_thread: break from main thread for probe_ready\n"); + break; + } + + if (probe_ready) + break; + + pr_notice("%s probe_ready %d delay 10ms~15ms\n", + __func__, probe_ready); + usleep_range(10*1000, 15*1000); + + if (i == 1000) { + pr_warn("%s probe_ready %d i = %d try too many times return\n", + __func__, probe_ready, i); + return 0; + } + } + + if (priv->adapter) + adapter = priv->adapter; + else { + pr_err("%s priv->adapter is NULL return\n", __func__); + return 0; + } + thread->thread_status = 1; + init_waitqueue_entry(&wait, current); + for (;;) { + add_wait_queue(&thread->wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + if (kthread_should_stop()) { + pr_warn("main_thread: break from main thread\n"); + break; + } + + if ((adapter->wakeup_tries || + ((!adapter->int_count) && + (!priv->btmtk_dev.tx_dnld_rdy || + skb_queue_empty(&adapter->tx_queue)))) && (!priv->btmtk_dev.reset_dongle)) { + pr_debug("%s main_thread is sleeping...\n", __func__); + schedule(); + } + + set_current_state(TASK_RUNNING); + + remove_wait_queue(&thread->wait_q, &wait); + + if (kthread_should_stop()) { + pr_warn("main_thread: break after wake up\n"); + break; + } + + if (priv->btmtk_dev.reset_dongle) + priv->hw_sdio_reset_dongle(); + + if (priv->btmtk_dev.reset_progress) + continue; + + ret = priv->hw_set_own_back(DRIVER_OWN); + if (ret) { + pr_err("%s set driver own return fail\n", __func__); + priv->start_reset_dongle_progress(); + continue; + } + + spin_lock_irqsave(&priv->driver_lock, flags); + if (adapter->int_count) { + pr_debug("%s go int\n", __func__); + adapter->int_count = 0; + spin_unlock_irqrestore(&priv->driver_lock, flags); + if (priv->hw_process_int_status(priv)) + priv->start_reset_dongle_progress(); + } else if (adapter->ps_state == PS_SLEEP && + !skb_queue_empty(&adapter->tx_queue)) { + pr_debug("%s go vender, todo\n", __func__); + spin_unlock_irqrestore(&priv->driver_lock, flags); + adapter->wakeup_tries++; + continue; + } else { + pr_debug("%s go tx\n", __func__); + spin_unlock_irqrestore(&priv->driver_lock, flags); + } + + if (adapter->ps_state == PS_SLEEP) { + pr_debug("%s ps_state == PS_SLEEP, continue\n", + __func__); + continue; + } + + if (!priv->btmtk_dev.tx_dnld_rdy) { + pr_debug("%s tx_dnld_rdy == 0, continue\n", __func__); + continue; + } + + spin_lock_irqsave(&priv->driver_lock, flags); + skb = skb_dequeue(&adapter->tx_queue); + spin_unlock_irqrestore(&priv->driver_lock, flags); + + if (skb) { + if (skb->len < 16) + btmtk_print_buffer_conent(skb->data, skb->len); + else + btmtk_print_buffer_conent(skb->data, 16); + + ret = btmtk_tx_pkt(priv, skb); + if (ret && (ret != (-EINVAL))) { + pr_err("%s tx pkt return fail %d\n", __func__, ret); + priv->start_reset_dongle_progress(); + } + + if (skb) { + pr_debug("%s after btmtk_tx_pkt kfree_skb\n", + __func__); + kfree_skb(skb); + } + } + + if (skb_queue_empty(&adapter->tx_queue)) { + ret = priv->hw_set_own_back(FW_OWN); + if (ret) { + pr_err("%s set fw own return fail\n", + __func__); + priv->start_reset_dongle_progress(); + } + } + } + pr_warn("%s end\n", __func__); + thread->thread_status = 0; + return 0; +} + +struct btmtk_private *btmtk_add_card(void *card) +{ + struct btmtk_private *priv; + + pr_info("%s begin\n", __func__); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + goto err_priv; + + priv->adapter = kzalloc(sizeof(*priv->adapter), GFP_KERNEL); + if (!priv->adapter) + goto err_adapter; + + btmtk_init_adapter(priv); + + pr_info("Starting kthread...\n"); + priv->main_thread.priv = priv; + spin_lock_init(&priv->driver_lock); + + init_waitqueue_head(&priv->main_thread.wait_q); + priv->main_thread.task = kthread_run(btmtk_service_main_thread, + &priv->main_thread, "btmtk_main_service"); + if (IS_ERR(priv->main_thread.task)) + goto err_thread; + + priv->btmtk_dev.card = card; + priv->btmtk_dev.tx_dnld_rdy = true; + + return priv; + +err_thread: + btmtk_free_adapter(priv); + +err_adapter: + kfree(priv); + +err_priv: + return NULL; +} +EXPORT_SYMBOL_GPL(btmtk_add_card); + +int btmtk_remove_card(struct btmtk_private *priv) +{ + pr_info("%s begin\n", __func__); + + pr_info("%s stop main_thread\n", __func__); + if (!PTR_ERR(priv->main_thread.task) && (priv->main_thread.thread_status)) + kthread_stop(priv->main_thread.task); + pr_info("%s stop main_thread done\n", __func__); +#ifdef CONFIG_DEBUG_FS + /*btmtk_debugfs_remove(hdev);*/ +#endif + + btmtk_free_adapter(priv); + + kfree(priv); + + return 0; +} +EXPORT_SYMBOL_GPL(btmtk_remove_card); + +MODULE_AUTHOR("Mediatek Ltd."); +MODULE_DESCRIPTION("Mediatek Bluetooth driver ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_sdio.c b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_sdio.c new file mode 100644 index 00000000000000..4137ccf90cb186 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_sdio.c @@ -0,0 +1,5663 @@ +/* + * Copyright (c) 2016,2017 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Define for proce node */ +#include +#include + +#include "btmtk_config.h" +#include "btmtk_define.h" +#include "btmtk_drv.h" +#include "btmtk_sdio.h" + +#if SUPPORT_EINT +/* Used for WoBLE on EINT */ +#include +#include +#include +#endif + +#ifdef CONFIG_AMAZON_A2DP_TS_SDIO +#include "btif_audio_ts.h" +#endif + +#define MTK_BT_DEBUG 0 + +/* HCI controller types */ +#define HCI_PRIMARY 0x00 +#define HCI_AMP 0x01 + +static dev_t g_devIDfwlog; +static struct class *pBTClass; +static struct device *pBTDev; +struct device *pBTDevfwlog; +static wait_queue_head_t inq; +static wait_queue_head_t fw_log_inq; +static struct fasync_struct *fasync; +static struct hci_dev *hdev; + +static int need_reset_stack; +static int need_reopen; +static int wlan_remove_done; + +static u8 user_rmmod; + +struct completion g_done; +unsigned char probe_counter; +unsigned char current_fwdump_file_number; +struct btmtk_private *g_priv; +#define STR_COREDUMP_END "coredump end\n\n" +const u8 READ_ADDRESS_EVENT[] = { 0x0e, 0x0a, 0x01, 0x09, 0x10, 0x00 }; + +static struct ring_buffer metabuffer; +static struct ring_buffer fwlog_metabuffer; +u8 probe_ready; +/* record firmware version */ +static char fw_version_str[FW_VERSION_BUF_SIZE]; +static struct proc_dir_entry *g_proc_dir; +/* bluetooth KPI feautre, bperf */ +u8 btmtk_bluetooth_kpi = 0; + +/** read_write for proc */ +static int btmtk_proc_show(struct seq_file *m, void *v); +static int btmtk_proc_open(struct inode *inode, struct file *file); +static void btmtk_proc_create_new_entry(void); +#if SUPPORT_EINT +static int btmtk_sdio_RegisterBTIrq(struct btmtk_sdio_card *data); +static int btmtk_sdio_woble_input_init(struct btmtk_sdio_card *data); +#endif + +static char fw_dump_file_name[FW_DUMP_FILE_NAME_SIZE] = {0}; +static char event_need_compare[EVENT_COMPARE_SIZE] = {0}; +static char event_need_compare_len; +static char event_compare_status; +/*add special header in the beginning of even, stack won't recognize these event*/ + + +/* timer for coredump end */ +struct task_struct *wait_dump_complete_tsk; +struct task_struct *wait_wlan_remove_tsk; +int wlan_status; + +int fw_is_doing_coredump; +int fw_is_coredump_end_packet; +static int print_dump_data_counter; + +#if SAVE_FW_DUMP_IN_KERNEL + static struct file *fw_dump_file; +#else + static int fw_dump_file; +#endif + +const struct proc_ops BT_proc_fops = { + .proc_open = btmtk_proc_open, + .proc_read = seq_read, + .proc_release = single_release, +}; + +static const struct btmtk_sdio_card_reg btmtk_reg_6630 = { + .cfg = 0x03, + .host_int_mask = 0x04, + .host_intstatus = 0x05, + .card_status = 0x20, + .sq_read_base_addr_a0 = 0x10, + .sq_read_base_addr_a1 = 0x11, + .card_fw_status0 = 0x40, + .card_fw_status1 = 0x41, + .card_rx_len = 0x42, + .card_rx_unit = 0x43, + .io_port_0 = 0x00, + .io_port_1 = 0x01, + .io_port_2 = 0x02, + .int_read_to_clear = false, + .func_num = 2, + .chip_id = 0x6630, +}; + +static const struct btmtk_sdio_card_reg btmtk_reg_6632 = { + .cfg = 0x03, + .host_int_mask = 0x04, + .host_intstatus = 0x05, + .card_status = 0x20, + .sq_read_base_addr_a0 = 0x10, + .sq_read_base_addr_a1 = 0x11, + .card_fw_status0 = 0x40, + .card_fw_status1 = 0x41, + .card_rx_len = 0x42, + .card_rx_unit = 0x43, + .io_port_0 = 0x00, + .io_port_1 = 0x01, + .io_port_2 = 0x02, + .int_read_to_clear = false, + .func_num = 2, + .chip_id = 0x6632, +}; + +static const struct btmtk_sdio_card_reg btmtk_reg_7668 = { + .cfg = 0x03, + .host_int_mask = 0x04, + .host_intstatus = 0x05, + .card_status = 0x20, + .sq_read_base_addr_a0 = 0x10, + .sq_read_base_addr_a1 = 0x11, + .card_fw_status0 = 0x40, + .card_fw_status1 = 0x41, + .card_rx_len = 0x42, + .card_rx_unit = 0x43, + .io_port_0 = 0x00, + .io_port_1 = 0x01, + .io_port_2 = 0x02, + .int_read_to_clear = false, + .func_num = 2, + .chip_id = 0x7668, +}; + +static const struct btmtk_sdio_card_reg btmtk_reg_7663 = { + .cfg = 0x03, + .host_int_mask = 0x04, + .host_intstatus = 0x05, + .card_status = 0x20, + .sq_read_base_addr_a0 = 0x10, + .sq_read_base_addr_a1 = 0x11, + .card_fw_status0 = 0x40, + .card_fw_status1 = 0x41, + .card_rx_len = 0x42, + .card_rx_unit = 0x43, + .io_port_0 = 0x00, + .io_port_1 = 0x01, + .io_port_2 = 0x02, + .int_read_to_clear = false, + .func_num = 2, + .chip_id = 0x7663, +}; + +static const struct btmtk_sdio_card_reg btmtk_reg_7666 = { + .cfg = 0x03, + .host_int_mask = 0x04, + .host_intstatus = 0x05, + .card_status = 0x20, + .sq_read_base_addr_a0 = 0x10, + .sq_read_base_addr_a1 = 0x11, + .card_fw_status0 = 0x40, + .card_fw_status1 = 0x41, + .card_rx_len = 0x42, + .card_rx_unit = 0x43, + .io_port_0 = 0x00, + .io_port_1 = 0x01, + .io_port_2 = 0x02, + .int_read_to_clear = false, + .func_num = 2, + .chip_id = 0x7666, +}; + +static const struct btmtk_sdio_device btmtk_sdio_6630 = { + .helper = "mtmk/sd8688_helper.bin", + .firmware = "mt6632_patch_e1_hdr.bin", + .reg = &btmtk_reg_6630, + .support_pscan_win_report = false, + .sd_blksz_fw_dl = 64, + .supports_fw_dump = false, +}; + +static const struct btmtk_sdio_device btmtk_sdio_6632 = { + .helper = "mtmk/sd8688_helper.bin", + .firmware = "mt6632_patch_e1_hdr.bin", + .reg = &btmtk_reg_6632, + .support_pscan_win_report = false, + .sd_blksz_fw_dl = 64, + .supports_fw_dump = false, +}; + +static const struct btmtk_sdio_device btmtk_sdio_7668 = { + .helper = "mtmk/sd8688_helper.bin", +#if CFG_THREE_IN_ONE_FIRMWARE + .firmware = "MT7668_FW", +#else + .firmware = "mt7668_patch_e1_hdr.bin", + .firmware1 = "mt7668_patch_e2_hdr.bin", +#endif + .reg = &btmtk_reg_7668, + .support_pscan_win_report = false, + .sd_blksz_fw_dl = 64, + .supports_fw_dump = false, +}; + +static const struct btmtk_sdio_device btmtk_sdio_7663 = { + .helper = "mtmk/sd8688_helper.bin", + .firmware = "mt7663_patch_e1_hdr.bin", + .firmware1 = "mt7663_patch_e2_hdr.bin", + .reg = &btmtk_reg_7663, + .support_pscan_win_report = false, + .sd_blksz_fw_dl = 64, + .supports_fw_dump = false, +}; + +static const struct btmtk_sdio_device btmtk_sdio_7666 = { + .helper = "mtmk/sd8688_helper.bin", + .firmware = "mt7668_patch_e1_hdr.bin", + .reg = &btmtk_reg_7666, + .support_pscan_win_report = false, + .sd_blksz_fw_dl = 64, + .supports_fw_dump = false, +}; + +struct btmtksdio_dev { + struct hci_dev *hdev; + struct sdio_func *func; + struct device *dev; + + struct work_struct tx_work; + unsigned long tx_state; + struct sk_buff_head txq; + + struct sk_buff *evt_skb; + + const struct btmtksdio_data *data; +}; + +unsigned char *txbuf; +static unsigned char *rxbuf; +static unsigned char *userbuf; +static unsigned char *userbuf_fwlog; +static u32 rx_length; +static struct btmtk_sdio_card *g_card; + +//#define SDIO_VENDOR_ID_MEDIATEK 0x037A +static const struct sdio_device_id btmtk_sdio_ids[] = { + /* Mediatek SD8688 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x6630), + .driver_data = (unsigned long) &btmtk_sdio_6630 }, + + { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x6632), + .driver_data = (unsigned long) &btmtk_sdio_6632 }, + + { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7668), + .driver_data = (unsigned long) &btmtk_sdio_7668 }, + + { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7663), + .driver_data = (unsigned long) &btmtk_sdio_7663 }, + + { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7666), + .driver_data = (unsigned long) &btmtk_sdio_7666 }, + + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(sdio, btmtk_sdio_ids); + +static int btmtk_clean_queue(void); +#ifndef MTK_KERNEL_DEBUG +static void btmtk_sdio_do_reset_or_wait_wlan_remove_done(void); +#endif + +void btmtk_sdio_stop_wait_wlan_remove_tsk(void) +{ + if (wait_wlan_remove_tsk == NULL) + pr_info("%s wait_wlan_remove_tsk is NULL\n", __func__); + else if (IS_ERR(wait_wlan_remove_tsk)) + pr_info("%s wait_wlan_remove_tsk is error\n", __func__); + else { + pr_info("%s call kthread_stop wait_wlan_remove_tsk\n", + __func__); + kthread_stop(wait_wlan_remove_tsk); + wait_wlan_remove_tsk = NULL; + } +} + +int btmtk_sdio_notify_wlan_remove_start(void) +{ + /* notify_wlan_remove_start */ + int ret = 0; + typedef void (*pnotify_wlan_remove_start) (int reserved); + char *notify_wlan_remove_start_func_name = "notify_wlan_remove_start"; + pnotify_wlan_remove_start pnotify_wlan_remove_start_func = + (pnotify_wlan_remove_start)kallsyms_lookup_name(notify_wlan_remove_start_func_name); + + pr_info("%s: wlan_status %d\n", __func__, wlan_status); + if (wlan_status == WLAN_STATUS_CALL_REMOVE_START) { + /* do notify before, just return */ + return ret; + } + + btmtk_sdio_stop_wait_wlan_remove_tsk(); + /* void notify_wlan_remove_start(void) */ + if (pnotify_wlan_remove_start_func) { + pr_info("%s: do notify %s\n", __func__, notify_wlan_remove_start_func_name); + wlan_remove_done = 0; + pnotify_wlan_remove_start_func(1); + wlan_status = WLAN_STATUS_CALL_REMOVE_START; + } else { + ret = -1; + pr_err("%s: do not get %s\n", __func__, notify_wlan_remove_start_func_name); + wlan_status = WLAN_STATUS_IS_NOT_LOAD; + wlan_remove_done = 1; + } + return ret; +} + +/*============================================================================*/ +/* Interface Functions : timer for coredump inform wifi */ +/*============================================================================*/ +static void btmtk_sdio_wakeup_mainthread_do_reset(void) +{ + if (g_priv) { + g_priv->btmtk_dev.reset_dongle = 1; + pr_info("%s: set reset_dongle %d", __func__, g_priv->btmtk_dev.reset_dongle); + wake_up_interruptible(&g_priv->main_thread.wait_q); + } else + pr_err("%s: g_priv is NULL", __func__); +} + +static int btmtk_sdio_wait_wlan_remove_thread(void *ptr) +{ + int i; + + pr_info("%s: begin", __func__); + if (g_priv == NULL) { + pr_err("%s: g_priv is NULL, return", __func__); + return 0; + } + + g_priv->btmtk_dev.reset_progress = 1; + for (i = 0; i < 30; i++) { + if ((wait_wlan_remove_tsk && kthread_should_stop()) || wlan_remove_done) { + pr_warn("%s: break wlan_remove_done %d\n", __func__, wlan_remove_done); + break; + } + msleep(500); + } + + btmtk_sdio_wakeup_mainthread_do_reset(); + + while (!kthread_should_stop()) { + pr_info("%s: no one call %s stop", __func__, __func__); + msleep(500); + } + + pr_info("%s: end", __func__); + return 0; +} + +static void btmtk_sdio_start_reset_dongle_progress(void) +{ +#if defined(MTK_KERNEL_DEBUG) + pr_warn("%s: debug mode do not do reset", __func__); +#else + pr_warn("%s: user mode do reset", __func__); + btmtk_sdio_notify_wlan_remove_start(); + btmtk_sdio_do_reset_or_wait_wlan_remove_done(); +#endif +} + +/*============================================================================*/ +/* Interface Functions : timer for uncomplete coredump */ +/*============================================================================*/ +#ifndef MTK_KERNEL_DEBUG +static void btmtk_sdio_do_reset_or_wait_wlan_remove_done(void) +{ + pr_info("%s: wlan_remove_done %d\n", __func__, wlan_remove_done); + if (wlan_remove_done || (wlan_status == WLAN_STATUS_IS_NOT_LOAD)) + /* wifi inform bt already, reset chip */ + btmtk_sdio_wakeup_mainthread_do_reset(); + else { + /* create thread wait wifi inform bt */ + pr_info("%s: create btmtk_sdio_wait_wlan_remove_thread\n", __func__); + wait_wlan_remove_tsk = kthread_run( + btmtk_sdio_wait_wlan_remove_thread, NULL, + "btmtk_sdio_wait_wlan_remove_thread"); + if (wait_wlan_remove_tsk == NULL) + pr_err("%s: btmtk_sdio_wait_wlan_remove_thread create fail\n", __func__); + } +} +#endif + +static int btmtk_sdio_wait_dump_complete_thread(void *ptr) +{ + int i; + + pr_info("%s: begin", __func__); + for (i = 0; i < 60; i++) { + if (wait_dump_complete_tsk && kthread_should_stop()) { + pr_warn("%s: thread is stopped, break\n", __func__); + break; + } + msleep(500); + } + +#if defined(MTK_KERNEL_DEBUG) + pr_info("%s: debug mode don't do reset\n", __func__); +#else + pr_info("%s: user mode call do reset\n", __func__); + btmtk_sdio_do_reset_or_wait_wlan_remove_done(); +#endif + + pr_info("%s: end", __func__); + return 0; +} + +static void btmtk_sdio_woble_free_setting_struct(struct woble_setting_struct *woble_struct, int count) +{ + int i = 0; + + for (i = 0; i < count; i++) { + if (woble_struct[i].content) { + pr_info("%s:kfree %d", __func__, i); + kfree(woble_struct[i].content); + woble_struct[i].content = NULL; + woble_struct[i].length = 0; + } else + woble_struct[i].length = 0; + } +} + +static void btmtk_sdio_woble_free_setting(void) +{ + pr_info("%s begin", __func__); + if (g_card == NULL) { + pr_err("%s: g_data == NULL", __func__); + return; + } + + btmtk_sdio_woble_free_setting_struct(g_card->woble_setting_apcf, WOBLE_SETTING_COUNT); + btmtk_sdio_woble_free_setting_struct(g_card->woble_setting_apcf_fill_mac, WOBLE_SETTING_COUNT); + btmtk_sdio_woble_free_setting_struct(g_card->woble_setting_apcf_fill_mac_location, WOBLE_SETTING_COUNT); + btmtk_sdio_woble_free_setting_struct(g_card->woble_setting_radio_off, WOBLE_SETTING_COUNT); + btmtk_sdio_woble_free_setting_struct(g_card->woble_setting_radio_off_status_event, WOBLE_SETTING_COUNT); + btmtk_sdio_woble_free_setting_struct(g_card->woble_setting_radio_off_comp_event, WOBLE_SETTING_COUNT); + btmtk_sdio_woble_free_setting_struct(g_card->woble_setting_radio_on, WOBLE_SETTING_COUNT); + btmtk_sdio_woble_free_setting_struct(g_card->woble_setting_radio_on_status_event, WOBLE_SETTING_COUNT); + btmtk_sdio_woble_free_setting_struct(g_card->woble_setting_radio_on_comp_event, WOBLE_SETTING_COUNT); + + if (g_card->woble_setting_len) { + kfree(g_card->woble_setting); + g_card->woble_setting_len = 0; + g_card->woble_setting = NULL; + } + pr_info("%s end", __func__); +} + +static int btmtk_sdio_load_woble_block_setting(char *block_name, struct woble_setting_struct *save_content, + int save_content_count, u8 *searchconetnt) +{ + int ret = 0; + int i = 0; + long parsing_result = 0; + u8 *search_result = NULL; + u8 *search_end = NULL; + u8 search[32]; + u8 temp[260]; /* save for total hex number */ + u8 *next_number = NULL; + u8 *next_block = NULL; + u8 number[8]; + int temp_len; + + memset(search, 0, sizeof(search)); + memset(temp, 0, sizeof(temp)); + memset(number, 0, sizeof(number)); + + /* search block name */ + for (i = 0; i < WOBLE_SETTING_COUNT; i++) { + temp_len = 0; + snprintf(search, sizeof(search), "%s%02d:", block_name, i); /* ex APCF01 */ + search_result = strstr(searchconetnt, search); + if (search_result) { + memset(temp, 0, sizeof(temp)); + temp_len = 0; + search_result += strlen(search); /* move to first number */ + + do { + next_number = NULL; + search_end = strstr(search_result, ","); + if ((search_end - search_result) <= 0) { + pr_info("%s can not find search end, break", __func__); + break; + } + + if ((search_end - search_result) > sizeof(number)) + break; + + memset(number, 0, sizeof(number)); + memcpy(number, search_result, search_end - search_result); + + if (number[0] == 0x20) /* space */ + ret = kstrtol(number + 1, 0, &parsing_result); + else + ret = kstrtol(number, 0, &parsing_result); + + if (ret == 0) { + if (temp_len >= sizeof(temp)) { + pr_err("%s: %s data over %zu", __func__, search, sizeof(temp)); + break; + } + temp[temp_len] = parsing_result; + temp_len++; + /* find next number */ + next_number = strstr(search_end, "0x"); + + /* find next block */ + next_block = strstr(search_end, ":"); + } else { + pr_debug("%s:kstrtol ret = %d, search %s", __func__, ret, search); + break; + } + + if (next_number == NULL) { + pr_debug("%s: not find next apcf number temp_len %d, break, search %s", + __func__, temp_len, search); + break; + } + + if ((next_number > next_block) && (next_block != 0)) { + pr_debug("%s: find next apcf number is over to next block ", __func__); + pr_debug("%s: temp_len %d, break, search %s", + __func__, temp_len, search); + break; + } + + search_result = search_end + 1; + } while (1); + } else + pr_debug("%s: %s is not found", __func__, search); + + if (temp_len) { + pr_info("%s: %s found", __func__, search); + pr_debug("%s: kzalloc i=%d temp_len=%d", __func__, i, temp_len); + save_content[i].content = kzalloc(temp_len, GFP_KERNEL); + memcpy(save_content[i].content, temp, temp_len); + save_content[i].length = temp_len; + pr_debug("%s:x save_content[%d].length %d temp_len=%d", + __func__, i, save_content[i].length, temp_len); + } + + } + return ret; +} + +static int btmtk_sdio_load_woble_setting(u8 *image, char *bin_name, + struct device *dev, u32 *code_len, struct btmtk_sdio_card *data) +{ + int err; + const struct firmware *fw_entry = NULL; + + pr_info("%s: begin woble_setting_file_name = %s", __func__, bin_name); + err = request_firmware(&fw_entry, bin_name, dev); + if (err != 0) { + kfree(image); + image = NULL; + pr_err("%s: request_firmware function for woble setting fail!! error code = %d", __func__, err); + return err; + } + + if (fw_entry) { + image = kzalloc(fw_entry->size + 1, GFP_KERNEL); /* w:move to btmtk_sdio_free_memory */ + pr_info("%s: woble_setting request_firmware size %zu success", __func__, fw_entry->size); + } else { + pr_err("%s: fw_entry is NULL request_firmware may fail!! error code = %d", __func__, err); + return err; + } + if (image == NULL) { + pr_err("%s: kzalloc size %zu failed!!", __func__, fw_entry->size); + *code_len = 0; + return err; + } + + memcpy(image, fw_entry->data, fw_entry->size); + image[fw_entry->size] = '\0'; + + *code_len = fw_entry->size; + pr_info("%s: code_len (%d) assign done", __func__, *code_len); + + err = btmtk_sdio_load_woble_block_setting("APCF", + data->woble_setting_apcf, WOBLE_SETTING_COUNT, image); + if (err) + goto LOAD_END; + + err = btmtk_sdio_load_woble_block_setting("APCF_ADD_MAC", + data->woble_setting_apcf_fill_mac, WOBLE_SETTING_COUNT, image); + if (err) + goto LOAD_END; + + err = btmtk_sdio_load_woble_block_setting("APCF_ADD_MAC_LOCATION", + data->woble_setting_apcf_fill_mac_location, WOBLE_SETTING_COUNT, image); + if (err) + goto LOAD_END; + + err = btmtk_sdio_load_woble_block_setting("RADIOOFF", + data->woble_setting_radio_off, WOBLE_SETTING_COUNT, image); + if (err) + goto LOAD_END; + + err = btmtk_sdio_load_woble_block_setting("RADIOOFF_STATUS_EVENT", + data->woble_setting_radio_off_status_event, WOBLE_SETTING_COUNT, image); + if (err) + goto LOAD_END; + + err = btmtk_sdio_load_woble_block_setting("RADIOOFF_COMPLETE_EVENT", + data->woble_setting_radio_off_comp_event, WOBLE_SETTING_COUNT, image); + if (err) + goto LOAD_END; + + err = btmtk_sdio_load_woble_block_setting("RADIOON", + data->woble_setting_radio_on, WOBLE_SETTING_COUNT, image); + if (err) + goto LOAD_END; + + err = btmtk_sdio_load_woble_block_setting("RADIOON_STATUS_EVENT", + data->woble_setting_radio_on_status_event, WOBLE_SETTING_COUNT, image); + if (err) + goto LOAD_END; + + err = btmtk_sdio_load_woble_block_setting("RADIOON_COMPLETE_EVENT", + data->woble_setting_radio_on_comp_event, WOBLE_SETTING_COUNT, image); + if (err) + goto LOAD_END; + + err = btmtk_sdio_load_woble_block_setting("APCF_RESMUE", + data->woble_setting_apcf_resume, WOBLE_SETTING_COUNT, image); + if (err) + goto LOAD_END; + + err = btmtk_sdio_load_woble_block_setting("APCF_COMPLETE_EVENT", + data->woble_setting_apcf_resume, WOBLE_SETTING_COUNT, image); + +LOAD_END: + if (err) + pr_info("%s: error return %d", __func__, err); + + return err; +} + +static inline void btmtk_sdio_woble_wake_lock(struct btmtk_sdio_card *data) +{ +#if (SUPPORT_UNIFY_WOBLE & SUPPORT_ANDROID) + pr_info("%s:", __func__); + wake_lock(&data->woble_wlock); +#endif +} + +static inline void btmtk_sdio_woble_wake_unlock(struct btmtk_sdio_card *data) +{ +#if (SUPPORT_UNIFY_WOBLE & SUPPORT_ANDROID) + pr_info("%s:", __func__); + wake_unlock(&data->woble_wlock); +#endif +} + +u32 LOCK_UNSLEEPABLE_LOCK(struct _OSAL_UNSLEEPABLE_LOCK_ *pUSL) +{ + spin_lock_irqsave(&(pUSL->lock), pUSL->flag); + return 0; +} + +u32 UNLOCK_UNSLEEPABLE_LOCK(struct _OSAL_UNSLEEPABLE_LOCK_ *pUSL) +{ + spin_unlock_irqrestore(&(pUSL->lock), pUSL->flag); + return 0; +} + +static int btmtk_sdio_readb(u32 offset, u32 *val) +{ + u32 ret = 0; + + if (g_card->func == NULL) { + pr_err("%s g_card->func is NULL\n", __func__); + return -EIO; + } + sdio_claim_host(g_card->func); + *val = sdio_readb(g_card->func, offset, &ret); + sdio_release_host(g_card->func); + return ret; +} + +static int btmtk_sdio_writel(u32 offset, u32 val) +{ + u32 ret = 0; + + if (g_card->func == NULL) { + pr_err("%s g_card->func is NULL\n", __func__); + return -EIO; + } + sdio_claim_host(g_card->func); + sdio_writel(g_card->func, val, offset, &ret); + sdio_release_host(g_card->func); + return ret; +} + +static int btmtk_sdio_readl(u32 offset, u32 *val) +{ + u32 ret = 0; + + if (g_card->func == NULL) { + pr_err("g_card->func is NULL\n"); + return -EIO; + } + sdio_claim_host(g_card->func); + *val = sdio_readl(g_card->func, offset, &ret); + sdio_release_host(g_card->func); + return ret; +} + +static void btmtk_sdio_set_no_fw_own(struct btmtk_private *priv, bool no_fw_own) +{ + if (priv) { + priv->no_fw_own = no_fw_own; + pr_warn("%s set no_fw_own %d\n", __func__, priv->no_fw_own); + } else + pr_warn("%s priv is NULL\n", __func__); +} + +static int btmtk_sdio_set_own_back(int owntype) +{ + /*Set driver own*/ + int ret = 0, retry_ret = 0; + u32 u32LoopCount = 0; + u32 u32ReadCRValue = 0; + u32 ownValue = 0; + u32 set_checkretry = 30; + int i = 0; + + pr_debug("%s owntype %d\n", __func__, owntype); + + if (user_rmmod) + set_checkretry = 1; + + + if (owntype == FW_OWN && (g_priv)) { + if (g_priv->no_fw_own) { + printk_ratelimited(KERN_WARNING + "%s no_fw_own is on, just return\n", __func__); + + return ret; + } + } + + ret = btmtk_sdio_readl(CHLPCR, &u32ReadCRValue); + + pr_debug("%s btmtk_sdio_readl CHLPCR done\n", __func__); + if (owntype == DRIVER_OWN) { + if ((u32ReadCRValue&0x100) == 0x100) { + pr_debug("%s already driver own 0x%0x, return\n", + __func__, u32ReadCRValue); + goto set_own_end; + } + } else if (owntype == FW_OWN) { + if ((u32ReadCRValue&0x100) == 0) { + pr_debug("%s already FW own 0x%0x, return\n", + __func__, u32ReadCRValue); + goto set_own_end; + } + } + +setretry: + + if (owntype == DRIVER_OWN) + ownValue = 0x00000200; + else + ownValue = 0x00000100; + + pr_debug("%s write CHLPCR 0x%x\n", __func__, ownValue); + ret = btmtk_sdio_writel(CHLPCR, ownValue); + if (ret) { + ret = -EINVAL; + goto done; + } + pr_debug("%s write CHLPCR 0x%x done\n", __func__, ownValue); + + u32LoopCount = 1000; + + if (owntype == DRIVER_OWN) { + do { + udelay(1); + ret = btmtk_sdio_readl(CHLPCR, &u32ReadCRValue); + u32LoopCount--; + pr_debug("%s DRIVER_OWN btmtk_sdio_readl CHLPCR 0x%x\n", + __func__, u32ReadCRValue); + } while ((u32LoopCount > 0) && + ((u32ReadCRValue&0x100) != 0x100)); + + if ((u32LoopCount == 0) && (0x100 != (u32ReadCRValue&0x100)) + && (set_checkretry > 0)) { + pr_warn("%s retry set_check driver own, CHLPCR 0x%x\n", + __func__, u32ReadCRValue); + set_checkretry--; + mdelay(20); + goto setretry; + } + } else { + do { + udelay(1); + ret = btmtk_sdio_readl(CHLPCR, &u32ReadCRValue); + u32LoopCount--; + pr_debug("%s FW_OWN btmtk_sdio_readl CHLPCR 0x%x\n", + __func__, u32ReadCRValue); + } while ((u32LoopCount > 0) && ((u32ReadCRValue&0x100) != 0)); + + if ((u32LoopCount == 0) && + ((u32ReadCRValue&0x100) != 0) && + (set_checkretry > 0)) { + pr_warn("%s retry set_check FW own, CHLPCR 0x%x\n", + __func__, u32ReadCRValue); + set_checkretry--; + goto setretry; + } + } + + pr_debug("%s CHLPCR(0x%x), is 0x%x\n", + __func__, CHLPCR, u32ReadCRValue); + + if (owntype == DRIVER_OWN) { + if ((u32ReadCRValue&0x100) == 0x100) + pr_debug("%s check %04x, is 0x100 driver own success\n", + __func__, CHLPCR); + else { + pr_debug("%s check %04x, is %x shuld be 0x100\n", + __func__, CHLPCR, u32ReadCRValue); + ret = -EINVAL; + goto done; + } + } else { + if (0x0 == (u32ReadCRValue&0x100)) + pr_debug("%s check %04x, bit 8 is 0 FW own success\n", + __func__, CHLPCR); + else{ + pr_debug("%s bit 8 should be 0, %04x bit 8 is %04x\n", + __func__, u32ReadCRValue, + (u32ReadCRValue&0x100)); + ret = -EINVAL; + goto done; + } + } + +done: + if (owntype == DRIVER_OWN) { + if (ret) { + pr_err("%s set driver own fail\n", __func__); + for (i = 0; i < 8; i++) { + retry_ret = btmtk_sdio_readl(SWPCDBGR, &u32ReadCRValue); + pr_err("%s ret %d,SWPCDBGR 0x%x, then sleep 200ms\n", + __func__, retry_ret, u32ReadCRValue); + msleep(200); + } + } else + pr_debug("%s set driver own success\n", __func__); + } else if (owntype == FW_OWN) { + if (ret) + pr_err("%s set FW own fail\n", __func__); + else + pr_debug("%s set FW own success\n", __func__); + } else + pr_err("%s unknown type %d\n", __func__, owntype); + +set_own_end: + + return ret; +} + +static int btmtk_sdio_enable_interrupt(int enable) +{ + u32 ret = 0; + u32 cr_value = 0; + + if (enable) + cr_value |= C_FW_INT_EN_SET; + else + cr_value |= C_FW_INT_EN_CLEAR; + + ret = btmtk_sdio_writel(CHLPCR, cr_value); + pr_debug("%s enable %d write CHLPCR 0x%08x\n", + __func__, enable, cr_value); + + return ret; +} + +static int btmtk_sdio_get_rx_unit(struct btmtk_sdio_card *card) +{ + u8 reg; + int ret; + + reg = sdio_readb(card->func, card->reg->card_rx_unit, &ret); + if (!ret) + card->rx_unit = reg; + + return ret; +} + +static int btmtk_sdio_enable_host_int_mask( + struct btmtk_sdio_card *card, + u8 mask) +{ + int ret; + + sdio_writeb(card->func, mask, card->reg->host_int_mask, &ret); + if (ret) { + pr_err("Unable to enable the host interrupt!\n"); + ret = -EIO; + } + + return ret; +} + +static int btmtk_sdio_disable_host_int_mask( + struct btmtk_sdio_card *card, + u8 mask) +{ + u8 host_int_mask; + int ret; + + host_int_mask = sdio_readb(card->func, card->reg->host_int_mask, &ret); + if (ret) + return -EIO; + + host_int_mask &= ~mask; + + sdio_writeb(card->func, host_int_mask, card->reg->host_int_mask, &ret); + if (ret < 0) { + pr_err("Unable to disable the host interrupt!\n"); + return -EIO; + } + + return 0; +} + +/*for debug*/ +int btmtk_print_buffer_conent(u8 *buf, u32 Datalen) +{ + int i = 0; + int print_finish = 0; + //Print out txbuf data for debug + for (i = 0; i <= (Datalen-1); i += 16) { + if ((i+16) <= Datalen) { + pr_debug("%s: %02X%02X%02X%02X%02X %02X%02X%02X%02X%02X %02X%02X%02X%02X%02X %02X\n", + __func__, + buf[i], buf[i+1], buf[i+2], buf[i+3], + buf[i+4], buf[i+5], buf[i+6], buf[i+7], + buf[i+8], buf[i+9], buf[i+10], buf[i+11], + buf[i+12], buf[i+13], buf[i+14], buf[i+15]); + } else { + for (; i < (Datalen); i++) + pr_debug("%s: %02X\n", __func__, buf[i]); + + print_finish = 1; + } + + if (print_finish) + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(btmtk_print_buffer_conent); + +static int btmtk_sdio_send_tx_data(u8 *buffer, int tx_data_len) +{ + int ret = 0; + u8 MultiBluckCount = 0; + u8 redundant = 0; + + MultiBluckCount = tx_data_len/SDIO_BLOCK_SIZE; + redundant = tx_data_len % SDIO_BLOCK_SIZE; + + if (redundant) + tx_data_len = (MultiBluckCount+1)*SDIO_BLOCK_SIZE; + + sdio_claim_host(g_card->func); + ret = sdio_writesb(g_card->func, CTDR, buffer, tx_data_len); + sdio_release_host(g_card->func); + + return ret; +} + +static int btmtk_sdio_recv_rx_data(void) +{ + int ret = 0; + u32 u32ReadCRValue = 0; + int retry_count = 500; + u32 sdio_header_length = 0; + + memset(rxbuf, 0, MTK_RXDATA_SIZE); + + do { + ret = btmtk_sdio_readl(CHISR, &u32ReadCRValue); + pr_debug("%s: loop Get CHISR 0x%08X\n", + __func__, u32ReadCRValue); + rx_length = (u32ReadCRValue & RX_PKT_LEN) >> 16; + if (rx_length == 0xFFFF) { + pr_warn("%s: 0xFFFF==rx_length, error return -EIO\n", + __func__); + ret = -EIO; + break; + } + + if ((RX_DONE&u32ReadCRValue) && rx_length) { + if (rx_length > MTK_RXDATA_SIZE) { + pr_err("%s rx_length %d is bigger than MTK_RXDATA_SIZE %d\n", + __func__, rx_length, MTK_RXDATA_SIZE); + ret = -EIO; + break; + } + + pr_debug("%s: u32ReadCRValue = %08X\n", + __func__, u32ReadCRValue); + u32ReadCRValue &= 0xFFFB; + ret = btmtk_sdio_writel(CHISR, u32ReadCRValue); + pr_debug("%s: write = %08X\n", + __func__, u32ReadCRValue); + + sdio_claim_host(g_card->func); + ret = sdio_readsb(g_card->func, rxbuf, CRDR, rx_length); + sdio_release_host(g_card->func); + sdio_header_length = (rxbuf[1] << 8); + sdio_header_length |= rxbuf[0]; + + if (sdio_header_length != rx_length) { + pr_err("%s sdio header length %d, rx_length %d mismatch\n", + __func__, sdio_header_length, + rx_length); + break; + } + + if (sdio_header_length == 0) { + pr_warn("%s: get sdio_header_length = %d\n", + __func__, sdio_header_length); + continue; + } + + break; + } + + retry_count--; + if (retry_count <= 0) { + pr_warn("%s: retry_count = %d,timeout\n", + __func__, retry_count); + ret = -EIO; + break; + } + + /* msleep(1); */ + mdelay(3); + pr_debug("%s: retry_count = %d,wait\n", __func__, retry_count); + + if (ret) + break; + } while (1); + + if (ret) + return -EIO; + + return ret; +} + +static int btmtk_sdio_send_tci_power_on_wifi_memory(void) +{ + int ret = 0; + int retry = 3; + u8 wmt_event[8] = {0x04, 0xE4, 0x05, 0x02, 0x06, 0x01, 0x00, 0x00}; + u8 mtksdio_packet_header[MTK_SDIO_PACKET_HEADER_SIZE] = {0}; + u8 mtksdio_wmt_power_on_wifi_memory[10] = {0x01, 0x6F, 0xFC, 0x06, 0x01, 0x06, 0x02, 0x00, 0x03, 0x01}; + + pr_info("%s:\n", __func__); + mtksdio_packet_header[0] = sizeof(mtksdio_packet_header) + + sizeof(mtksdio_wmt_power_on_wifi_memory); + + memcpy(txbuf, mtksdio_packet_header, MTK_SDIO_PACKET_HEADER_SIZE); + memcpy(txbuf + MTK_SDIO_PACKET_HEADER_SIZE, mtksdio_wmt_power_on_wifi_memory, + sizeof(mtksdio_wmt_power_on_wifi_memory)); + + do { + btmtk_sdio_send_tx_data(txbuf, + MTK_SDIO_PACKET_HEADER_SIZE + sizeof(mtksdio_wmt_power_on_wifi_memory)); + btmtk_sdio_recv_rx_data(); + + /*compare rx data is wmt reset correct response or not*/ + if (memcmp(wmt_event, rxbuf + MTK_SDIO_PACKET_HEADER_SIZE, + sizeof(wmt_event)) != 0) { + ret = -EIO; + retry -- ; + pr_warn("%s: fail (retry=%d)\n", __func__, retry); + } + } while (ret < 0 && retry > 0); + + return ret; +} + +static int btmtk_sdio_send_wmt_reset(void) +{ + int ret = 0; + u8 wmt_event[8] = {4, 0xE4, 5, 2, 7, 1, 0, 0}; + u8 mtksdio_packet_header[MTK_SDIO_PACKET_HEADER_SIZE] = {0}; + u8 mtksdio_wmt_reset[9] = {1, 0x6F, 0xFC, 5, 1, 7, 1, 0, 4}; + + pr_info("%s:\n", __func__); + mtksdio_packet_header[0] = sizeof(mtksdio_packet_header) + + sizeof(mtksdio_wmt_reset); + + memcpy(txbuf, mtksdio_packet_header, MTK_SDIO_PACKET_HEADER_SIZE); + memcpy(txbuf+MTK_SDIO_PACKET_HEADER_SIZE, mtksdio_wmt_reset, + sizeof(mtksdio_wmt_reset)); + + btmtk_sdio_send_tx_data(txbuf, + MTK_SDIO_PACKET_HEADER_SIZE+sizeof(mtksdio_wmt_reset)); + btmtk_sdio_recv_rx_data(); + + /*compare rx data is wmt reset correct response or not*/ + if (memcmp(wmt_event, rxbuf+MTK_SDIO_PACKET_HEADER_SIZE, + sizeof(wmt_event)) != 0) { + ret = -EIO; + pr_warn("%s: fail\n", __func__); + } + + return ret; +} + +static u32 btmtk_sdio_bt_memRegister_read(u32 cr) +{ + int retrytime = 3; + u32 result = 0; + u8 wmt_event[15] = {0x04, 0xE4, 0x10, 0x02, + 0x08, 0x0C/*0x1C*/, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x80}; + /* msleep(1000); */ + u8 mtksdio_packet_header[MTK_SDIO_PACKET_HEADER_SIZE] = {0}; + u8 mtksdio_wmt_cmd[16] = {0x1, 0x6F, 0xFC, 0x0C, + 0x01, 0x08, 0x08, 0x00, + 0x02, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00}; + mtksdio_packet_header[0] = sizeof(mtksdio_packet_header) + + sizeof(mtksdio_wmt_cmd); + pr_info("%s: read cr %x\n", __func__, cr); + + memcpy(&mtksdio_wmt_cmd[12], &cr, sizeof(cr)); + + memcpy(txbuf, mtksdio_packet_header, MTK_SDIO_PACKET_HEADER_SIZE); + memcpy(txbuf + MTK_SDIO_PACKET_HEADER_SIZE, mtksdio_wmt_cmd, + sizeof(mtksdio_wmt_cmd)); + + btmtk_sdio_send_tx_data(txbuf, + MTK_SDIO_PACKET_HEADER_SIZE + sizeof(mtksdio_wmt_cmd)); + btmtk_print_buffer_conent(txbuf, + MTK_SDIO_PACKET_HEADER_SIZE + sizeof(mtksdio_wmt_cmd)); + + do { + usleep_range(10*1000, 15*1000); + btmtk_sdio_recv_rx_data(); + retrytime--; + if (retrytime <= 0) + break; + + pr_info("%s: retrytime %d\n", __func__, retrytime); + } while (!rxbuf[0]); + + btmtk_print_buffer_conent(rxbuf, rx_length); + /* compare rx data is wmt reset correct response or not */ +#if 0 + if (memcmp(wmt_event, + rxbuf+MTK_SDIO_PACKET_HEADER_SIZE, + sizeof(wmt_event)) != 0) { + ret = -EIO; + pr_info("%s: fail\n", __func__); + } +#endif + memcpy(&result, rxbuf+MTK_SDIO_PACKET_HEADER_SIZE + sizeof(wmt_event), + sizeof(result)); + pr_info("%s: ger cr 0x%x value 0x%x\n", __func__, cr, result); + return result; +} + +/* 1:on , 0:off */ +static int btmtk_sdio_bt_set_power(u8 onoff) +{ + int ret = 0; + int retrytime = 60; + u8 wmt_event[8] = {4, 0xE4, 5, 2, 6, 1, 0, 0}; + u8 mtksdio_packet_header[MTK_SDIO_PACKET_HEADER_SIZE] = {0}; + u8 mtksdio_wmt_cmd[10] = {1, 0x6F, 0xFC, 6, 1, 6, 2, 0, 0, 1}; + + if (onoff == 0) + retrytime = 3; + + mtksdio_packet_header[0] = + sizeof(mtksdio_packet_header) + sizeof(mtksdio_wmt_cmd); + pr_info("%s: onoff %d\n", __func__, onoff); + + mtksdio_wmt_cmd[9] = onoff; + + memcpy(txbuf, mtksdio_packet_header, MTK_SDIO_PACKET_HEADER_SIZE); + memcpy(txbuf+MTK_SDIO_PACKET_HEADER_SIZE, mtksdio_wmt_cmd, + sizeof(mtksdio_wmt_cmd)); + + btmtk_sdio_send_tx_data(txbuf, + MTK_SDIO_PACKET_HEADER_SIZE+sizeof(mtksdio_wmt_cmd)); + + do { + msleep(100); + btmtk_sdio_recv_rx_data(); + retrytime--; + if (retrytime <= 0) + break; + + if (retrytime < 40) + pr_warn("%s: retry over 2s, retrytime %d\n", + __func__, retrytime); + + pr_debug("%s: retrytime %d\n", __func__, retrytime); + } while (!rxbuf[0]); + + + /*compare rx data is wmt reset correct response or not*/ + if (memcmp(wmt_event, rxbuf+MTK_SDIO_PACKET_HEADER_SIZE, + sizeof(wmt_event)) != 0) { + ret = -EIO; + pr_info("%s: fail\n", __func__); + } + + return ret; +} + +#if BTMTK_BIN_FILE_MODE +static void GetRandomValue(u8 string[6], bool is7668) +{ + int iRandom = 0; + pr_info("Enable random generation\n"); + /* first random */ + get_random_bytes(&iRandom, sizeof(int)); + pr_info("iRandom = [%d]", iRandom); + string[0] = (((iRandom>>24|iRandom>>16) & (0xFE)) | (0x02)); /* Must use private bit(1) and no BCMC bit(0) */ + /* second random */ + get_random_bytes(&iRandom, sizeof(int)); + pr_info("iRandom = [%d]", iRandom); + string[1] = ((iRandom>>8) & 0xFF); + /* third random */ + get_random_bytes(&iRandom, sizeof(int)); + pr_info("iRandom = [%d]", iRandom); + string[5] = (iRandom & 0xFF); + /* */ + string[2] = 0x46; + if (is7668) + string[3] = 0x68; + else + string[3] = 0x62; + string[4] = 0x76; + return; +} + +static int btmtk_sdio_send_and_check(u8 *cmd, u16 cmd_len, + u8 *event, u16 event_len) +{ + int ret = 0; + int retrytime = 60; + int len = 0; + u8 mtksdio_packet_header[MTK_SDIO_PACKET_HEADER_SIZE] = {0}; + + len = MTK_SDIO_PACKET_HEADER_SIZE + cmd_len; + + mtksdio_packet_header[0] = (len & 0x0000ff); + mtksdio_packet_header[1] = (len & 0x00ff00) >> 8; + + memcpy(txbuf, mtksdio_packet_header, MTK_SDIO_PACKET_HEADER_SIZE); + memcpy(txbuf + MTK_SDIO_PACKET_HEADER_SIZE, cmd, cmd_len); + + btmtk_sdio_send_tx_data(txbuf, len); + + if (event && (event_len != 0)) { + do { + msleep(100); + btmtk_sdio_recv_rx_data(); + retrytime--; + if (retrytime <= 0) + break; + + if (retrytime < 40) + pr_warn("%s: retry over 2s, retrytime %d\n", + __func__, retrytime); + } while (!rxbuf[0]); + + if (memcmp(event, rxbuf + MTK_SDIO_PACKET_HEADER_SIZE, + event_len) != 0) { + ret = -EIO; + pr_warn("%s: fail\n", __func__); + } + } + + return ret; +} +/*get 1 byte only*/ +static int btmtk_efuse_read(u16 addr, u8 *value) +{ + uint8_t efuse_r[] = {0x01, 0x6F, 0xFC, 0x0E, + 0x01, 0x0D, 0x0A, 0x00, 0x02, 0x04, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00};/*4 sub block number(sub block 0~3)*/ + + uint8_t efuse_r_event[] = {0x04, 0xE4, 0x1E, 0x02, 0x0D, 0x1A, 0x00, 02, 04}; + /*check event + *04 E4 LEN(1B) 02 0D LEN(2Byte) 02 04 ADDR(2Byte) VALUE(4B) ADDR(2Byte) VALUE(4Byte) + *ADDR(2Byte) VALUE(4B) ADDR(2Byte) VALUE(4Byte) + */ + int ret = 0; + uint8_t sub_block_addr_in_event = 0; + uint8_t sub_block = (addr / 16)*4; + uint8_t temp = 0; + + efuse_r[10] = sub_block & 0xFF; + efuse_r[11] = (sub_block & 0xFF00) >> 8; + efuse_r[12] = (sub_block + 1) & 0xFF; + efuse_r[13] = ((sub_block + 1) & 0xFF00) >> 8; + efuse_r[14] = (sub_block + 2) & 0xFF; + efuse_r[15] = ((sub_block + 2) & 0xFF00) >> 8; + efuse_r[16] = (sub_block + 3) & 0xFF; + efuse_r[17] = ((sub_block + 3) & 0xFF00) >> 8; + + ret = btmtk_sdio_send_and_check(efuse_r, sizeof(efuse_r), efuse_r_event, sizeof(efuse_r_event)); + if (ret) { + pr_warn("%s: btmtk_sdio_send_and_check error\n", __func__); + pr_warn("%s: rx_length %d\n", __func__, rx_length); + return ret; + } + + if (memcmp(rxbuf + MTK_SDIO_PACKET_HEADER_SIZE, efuse_r_event, sizeof(efuse_r_event)) == 0) { + /*compare rxbuf format ok, compare addr*/ + pr_debug("%s: compare rxbuf format ok\n", __func__); + if (efuse_r[10] == rxbuf[9 + MTK_SDIO_PACKET_HEADER_SIZE] && + efuse_r[11] == rxbuf[10 + MTK_SDIO_PACKET_HEADER_SIZE] && + efuse_r[12] == rxbuf[15 + MTK_SDIO_PACKET_HEADER_SIZE] && + efuse_r[13] == rxbuf[16 + MTK_SDIO_PACKET_HEADER_SIZE] && + efuse_r[14] == rxbuf[21 + MTK_SDIO_PACKET_HEADER_SIZE] && + efuse_r[15] == rxbuf[22 + MTK_SDIO_PACKET_HEADER_SIZE] && + efuse_r[16] == rxbuf[27 + MTK_SDIO_PACKET_HEADER_SIZE] && + efuse_r[17] == rxbuf[28 + MTK_SDIO_PACKET_HEADER_SIZE]) { + + pr_debug("%s: address compare ok\n", __func__); + /*Get value*/ + sub_block_addr_in_event = ((addr / 16) / 4);/*cal block num*/ + temp = addr % 16; + pr_debug("%s: address in block %d\n", __func__, temp); + switch (temp) { + case 0: + case 1: + case 2: + case 3: + *value = rxbuf[11 + temp + MTK_SDIO_PACKET_HEADER_SIZE]; + break; + case 4: + case 5: + case 6: + case 7: + *value = rxbuf[17 + temp + MTK_SDIO_PACKET_HEADER_SIZE]; + break; + case 8: + case 9: + case 10: + case 11: + *value = rxbuf[22 + temp + MTK_SDIO_PACKET_HEADER_SIZE]; + break; + + case 12: + case 13: + case 14: + case 15: + *value = rxbuf[34 + temp + MTK_SDIO_PACKET_HEADER_SIZE]; + break; + } + + + } else { + pr_warn("%s: address compare fail\n", __func__); + ret = -1; + } + + + } else { + pr_warn("%s: compare rxbuf format fail\n", __func__); + ret = -1; + } + + return ret; +} + + +static bool btmtk_is_bin_file_mode(uint8_t *buf, size_t buf_size) +{ + char *p_buf = NULL; + char *ptr = NULL, *p = NULL; + bool ret = true; + u16 addr = 1; + u8 value = 0; + + if (!buf) { + pr_warn("%s: buf is null\n", __func__); + return false; + } else if (buf_size < (strlen(E2P_MODE) + 2)) { + pr_warn("%s: incorrect buf size(%d)\n", + __func__, (int)buf_size); + return false; + } + + p_buf = kmalloc(buf_size + 1, GFP_KERNEL); + if (!p_buf) + return false; + memcpy(p_buf, buf, buf_size); + p_buf[buf_size] = '\0'; + + /* find string */ + p = ptr = strstr(p_buf, E2P_MODE); + if (!ptr) { + pr_notice("%s: Can't find %s\n", __func__, E2P_MODE); + ret = false; + goto out; + } + + if (p > p_buf) { + p--; + while ((*p == ' ') && (p != p_buf)) + p--; + if (*p == '#') { + pr_notice("%s: It's not EEPROM - Bin file mode\n", __func__); + ret = false; + goto out; + } + } + + /* check access mode */ + ptr += (strlen(E2P_MODE) + 1); + + if (*ptr == AUTO_MODE) { + pr_notice("%s: It's Auto mode: %c\n", __func__, *ptr); + ret = btmtk_efuse_read(addr, &value); + if (ret) { + pr_notice("%s: btmtk_efuse_read fail\n", __func__); + pr_notice("%s: Use EEPROM Bin file mode\n", __func__); + ret = true; + } else if (value == 0x76) { + pr_notice("%s: get efuse[1]: 0x%02x\n", __func__, value); + pr_notice("%s: use efuse mode", __func__); + ret = false; + } else { + pr_notice("%s: get efuse[1]: 0x%02x\n", __func__, value); + pr_notice("%s: Use EEPROM Bin file mode\n", __func__); + ret = true; + } + goto out; + } else if (*ptr == BIN_FILE_MODE) + pr_notice("%s: It's EEPROM bin mode: %c\n", __func__, *ptr); + else { + pr_warn("%s: It's not Auto/EEPROM mode %c\n", __func__, *ptr); + ret = false; + } + +out: + kfree(p_buf); + return ret; +} + +static void btmtk_set_eeprom2ctrler(uint8_t *buf, + size_t buf_size, + int device) +{ + int ret = -1; + uint8_t set_bdaddr[] = {0x01, 0x1A, 0xFC, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t set_bdaddr_e[] = {0x04, 0x0E, 0x04, 0x01, + 0x1A, 0xFC, 0x00}; + uint8_t set_radio[] = {0x01, 0x79, 0xFC, 0x08, + 0x07, 0x80, 0x00, 0x06, 0x07, 0x07, 0x00, 0x00}; + uint8_t set_radio_e[] = {0x04, 0x0E, 0x04, 0x01, + 0x79, 0xFC, 0x00}; + uint8_t set_pwr_offset[] = {0x01, 0x93, 0xFC, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t set_pwr_offset_e[] = {0x04, 0x0E, 0x04, 0x01, + 0x93, 0xFC, 0x00}; + uint8_t set_xtal[] = {0x01, 0x0E, 0xFC, 0x02, 0x00, 0x00}; + uint8_t set_xtal_e[] = {0x04, 0x0E, 0x04, 0x01, + 0x0E, 0xFC, 0x00}; + uint16_t offset = 0; + uint8_t i = 0; + + pr_notice("%s start, device: 0x%x\n", __func__, device); + + if (!buf) { + pr_warn("%s: buf is null\n", __func__); + return; + } else if (device == 0x7668 && buf_size < 0x389) { + pr_warn("%s: incorrect buf size(%d)\n", + __func__, (int)buf_size); + return; + } else if (device == 0x7663 && buf_size < 0x389) { + pr_warn("%s: incorrect buf size(%d)\n", + __func__, (int)buf_size); + return; + } else if ( buf_size < 0x133) { + pr_warn("%s: incorrect buf size(%d)\n", + __func__, (int)buf_size); + return; + } + + /* set BD address */ + if (device == 0x7668) + offset = 0x384; + else if (device == 0x7663) + offset = 0x131; + else + offset = 0x1A; + + set_bdaddr[4] = *(buf + offset); + set_bdaddr[5] = *(buf + offset + 1); + set_bdaddr[6] = *(buf + offset + 2); + set_bdaddr[7] = *(buf + offset + 3); + set_bdaddr[8] = *(buf + offset + 4); + set_bdaddr[9] = *(buf + offset + 5); + if (0x0 == set_bdaddr[4] && 0x0 == set_bdaddr[5] + && 0x0 == set_bdaddr[6] && 0x0 == set_bdaddr[7] + && 0x0 == set_bdaddr[8] && 0x0 == set_bdaddr[9]) { + //pr_notice("%s: BDAddr is Zero, not set\n", __func__); + GetRandomValue(&set_bdaddr[4], true); + } else { + ret = btmtk_sdio_send_and_check(set_bdaddr, set_bdaddr[3] + 4, set_bdaddr_e, sizeof(set_bdaddr_e)); + pr_notice("%s: set BDAddress(%02X-%02X-%02X-%02X-%02X-%02X) %s\n", + __func__, + set_bdaddr[9], set_bdaddr[8], set_bdaddr[7], + set_bdaddr[6], set_bdaddr[5], set_bdaddr[4], + ret < 0 ? "fail" : "OK"); + } + /* radio setting - BT power */ + if (device == 0x7668) { + offset = 0x382; + /* BT default power */ + set_radio[4] = (*(buf + offset) & 0x07); + /* BLE default power */ + set_radio[8] = (*(buf + offset + 1) & 0x07); + /* TX MAX power */ + set_radio[9] = (*(buf + offset) & 0x70) >> 4; + /* TX power sub level */ + set_radio[10] = (*(buf + offset + 1) & 0x30) >> 4; + /* BR/EDR power diff mode */ + set_radio[11] = (*(buf + offset + 1) & 0xc0) >> 6; + } else if (device == 0x7663) { + offset = 0x137; + /* BT default power */ + set_radio[4] = (*(buf + offset) & 0x07); + /* BLE default power */ + set_radio[8] = (*(buf + offset + 1) & 0x07); + /* TX MAX power */ + set_radio[9] = (*(buf + offset) & 0x70) >> 4; + /* TX power sub level */ + set_radio[10] = (*(buf + offset + 1) & 0x30) >> 4; + /* BR/EDR power diff mode */ + set_radio[11] = (*(buf + offset + 1) & 0xc0) >> 6; + } else { + offset = 0x132; + /* BT default power */ + set_radio[4] = *(buf + offset); + /* BLE default power(no this for 7662 in table) */ + set_radio[8] = *(buf + offset); + /* TX MAX power */ + set_radio[9] = *(buf + offset + 1); + } + ret = btmtk_sdio_send_and_check(set_radio, set_radio[3] + 4, + set_radio_e, sizeof(set_radio_e)); + pr_notice("%s: set radio(BT/BLE default power: %d/%d MAX power: %d) %s\n", + __func__, + set_radio[4], set_radio[8], set_radio[9], + ret < 0 ? "fail" : "OK"); + + /* + * BT TX power compensation for low, middle and high + * channel + */ + if (device == 0x7668) { + offset = 0x36D; + /* length */ + set_pwr_offset[3] = 6; + /* Group 0 CH 0 ~ CH14 */ + set_pwr_offset[4] = *(buf + offset); + /* Group 1 CH15 ~ CH27 */ + set_pwr_offset[5] = *(buf + offset + 1); + /* Group 2 CH28 ~ CH40 */ + set_pwr_offset[6] = *(buf + offset + 2); + /* Group 3 CH41 ~ CH53 */ + set_pwr_offset[7] = *(buf + offset + 3); + /* Group 4 CH54 ~ CH66 */ + set_pwr_offset[8] = *(buf + offset + 4); + /* Group 5 CH67 ~ CH84 */ + set_pwr_offset[9] = *(buf + offset + 5); + } else if (device == 0x7663) { + offset = 0x180; + /* length */ + set_pwr_offset[3] = 16; + /* Group 0 CH 0 ~ CH6 */ + set_pwr_offset[4] = *(buf + offset); + /* Group 1 CH7 ~ CH11 */ + set_pwr_offset[5] = *(buf + offset + 1); + /* Group 2 CH12 ~ CH16 */ + set_pwr_offset[6] = *(buf + offset + 2); + /* Group 3 CH17 ~ CH21 */ + set_pwr_offset[7] = *(buf + offset + 3); + /* Group 4 CH22 ~ CH26 */ + set_pwr_offset[8] = *(buf + offset + 4); + /* Group 5 CH27 ~ CH31 */ + set_pwr_offset[9] = *(buf + offset + 5); + /* Group 6 CH32 ~ CH36 */ + set_pwr_offset[10] = *(buf + offset + 6); + /* Group 7 CH37 ~ CH41 */ + set_pwr_offset[11] = *(buf + offset + 7); + /* Group 8 CH42 ~ CH46 */ + set_pwr_offset[12] = *(buf + offset + 8); + /* Group 9 CH47 ~ CH51 */ + set_pwr_offset[13] = *(buf + offset + 9); + /* Group 10 CH52 ~ CH56 */ + set_pwr_offset[14] = *(buf + offset + 10); + /* Group 11 CH57 ~ CH61 */ + set_pwr_offset[15] = *(buf + offset + 11); + /* Group 12 CH62 ~ CH66 */ + set_pwr_offset[16] = *(buf + offset + 12); + /* Group 13 CH67 ~ CH71 */ + set_pwr_offset[17] = *(buf + offset + 13); + /* Group 14 CH72 ~ CH76 */ + set_pwr_offset[18] = *(buf + offset + 14); + /* Group 15 CH77 ~ CH78 */ + set_pwr_offset[19] = *(buf + offset + 15); + } else { + offset = 0x139; + /* length */ + set_pwr_offset[3] = 3; + /* low channel */ + set_pwr_offset[4] = *(buf + offset); + /* middle channel */ + set_pwr_offset[5] = *(buf + offset + 1); + /* high channel */ + set_pwr_offset[6] = *(buf + offset + 2); + } + ret = btmtk_sdio_send_and_check(set_pwr_offset, set_pwr_offset[3] + 4, + set_pwr_offset_e, sizeof(set_pwr_offset_e)); + for (i = 0; i < 16; ++i) { + pr_notice("%s: set power offset[%d] = %02X\n", __func__, i, set_pwr_offset[4 + i]); + } + pr_notice("%s: set power offset %s\n", __func__, ret < 0 ? "fail" : "OK"); + + /* XTAL setting */ + if (device == 0x7668) { + offset = 0xF4; + /* BT default power */ + set_xtal[4] = *(buf + offset); + set_xtal[5] = *(buf + offset + 1); + ret = btmtk_sdio_send_and_check(set_xtal, set_xtal[3] + 4, + set_xtal_e, sizeof(set_xtal_e)); + pr_notice("%s: set XTAL(0x%02X %02X) %s\n", + __func__, + set_xtal[4], set_xtal[5], + ret < 0 ? "fail" : "OK"); + } + pr_notice("%s end\n", __func__); +} + +static void btmtk_eeprom_bin_file(struct btmtk_sdio_card *card) +{ + char *cfg_file = NULL; + char bin_file[32]; + + const struct firmware *cfg_fw = NULL; + const struct firmware *bin_fw = NULL; + + int ret = -1; + int chipid = card->func->device; + + pr_notice("%s: %X series\n", __func__, chipid); + cfg_file = E2P_ACCESS_MODE_SWITCHER; + sprintf(bin_file, E2P_BIN_FILE, chipid); + + usleep_range(10*1000, 15*1000); + + /* request configure file */ + ret = request_firmware(&cfg_fw, cfg_file, &card->func->dev); + if (ret < 0) { + if (ret == -ENOENT) + pr_notice("%s: Configure file not found, ignore EEPROM bin file\n", + __func__); + else + pr_notice("%s: request configure file fail(%d)\n", + __func__, ret); + return; + } + + if (btmtk_is_bin_file_mode((uint8_t *)cfg_fw->data, cfg_fw->size) == false) + goto exit2; + + usleep_range(10*1000, 15*1000); + + /* open bin file for EEPROM */ + ret = request_firmware(&bin_fw, bin_file, &card->func->dev); + if (ret < 0) { + pr_notice("%s: request bin file fail(%d)\n", + __func__, ret); + goto exit2; + } + + /* set parameters to controller */ + btmtk_set_eeprom2ctrler((uint8_t *)bin_fw->data, + bin_fw->size, + card->func->device); + +exit2: + if (cfg_fw) + release_firmware(cfg_fw); + if (bin_fw) + release_firmware(bin_fw); +} +#endif +/* 1:on , 0:off */ +static int btmtk_sdio_set_sleep(void) +{ + int ret = 0; + int i = 0; + u8 wmt_event[] = {4, 0xE, 4, 1, 0x7A, 0xFC, 0}; + u8 mtksdio_packet_header[MTK_SDIO_PACKET_HEADER_SIZE] = {0}; + u8 mtksdio_wmt_cmd[11] = {1, 0x7A, 0xFC, 7, + /*3:sdio, 5:usb*/03, + /*host non sleep duration*/0x80, 0x02, + /*host non sleep duration*/0x80, 0x02, 0x0, 0x00}; + + mtksdio_packet_header[0] = + sizeof(mtksdio_packet_header) + sizeof(mtksdio_wmt_cmd); + pr_info("%s begin\n", __func__); + + memcpy(txbuf, mtksdio_packet_header, MTK_SDIO_PACKET_HEADER_SIZE); + memcpy(txbuf+MTK_SDIO_PACKET_HEADER_SIZE, mtksdio_wmt_cmd, + sizeof(mtksdio_wmt_cmd)); + + btmtk_sdio_send_tx_data(txbuf, + MTK_SDIO_PACKET_HEADER_SIZE + sizeof(mtksdio_wmt_cmd)); + + btmtk_sdio_recv_rx_data(); + + btmtk_print_buffer_conent(rxbuf, rx_length); + + if(rx_length < sizeof(wmt_event)) { + pr_err("%s: rx_length(%d) < WMT_event(7 bytes)\n", __func__, rx_length); + ret = -EINVAL; + return ret; + } + + /*compare rx data is wmt reset correct response or not*/ + for (i = 0; i < (rx_length - sizeof(wmt_event)); i++) { + if (memcmp(wmt_event, rxbuf + MTK_SDIO_PACKET_HEADER_SIZE + i, + sizeof(wmt_event)) != 0) { + ret = -EIO; + pr_err("%s: fail compare move %d\n", __func__, i); + } else { + pr_info("%s compare event success\n", __func__); + ret = 0; + break; + } + } + + return ret; +} + +static int btmtk_sdio_skb_enq_fwlog(void *src, u32 len, u8 type, struct sk_buff_head *queue) +{ + struct sk_buff *skb_tmp = NULL; + int retry = 10; + + if (src == NULL || len == 0) { + pr_err("%s: Incorrect parameters, src:%p, len:%d", + __func__, src, len); + return -EINVAL; + } + + do { + /* If we need hci type, len + 1 */ + skb_tmp = alloc_skb(type ? len + 1 : len, GFP_ATOMIC); + if (skb_tmp != NULL) + break; + else if (retry <= 0) { + pr_err("%s: alloc_skb return 0, error", __func__); + return -ENOMEM; + } + pr_err("%s: alloc_skb return 0, error, retry = %d", __func__, retry); + } while (retry-- > 0); + + if (type) { + memcpy(&skb_tmp->data[0], &type, 1); + memcpy(&skb_tmp->data[1], src, len); + skb_tmp->len = len + 1; + } else { + memcpy(skb_tmp->data, src, len); + skb_tmp->len = len; + } + + LOCK_UNSLEEPABLE_LOCK(&(fwlog_metabuffer.spin_lock)); + skb_queue_tail(queue, skb_tmp); + UNLOCK_UNSLEEPABLE_LOCK(&(fwlog_metabuffer.spin_lock)); + return 0; +} + +static int btmtk_usb_dispatch_data_bluetooth_kpi(u8 *buf, int len, u8 type) +{ + static u8 fwlog_blocking_warn; + + if (btmtk_bluetooth_kpi && + skb_queue_len(&g_priv->adapter->fwlog_fops_queue) < FWLOG_BLUETOOTH_KPI_QUEUE_COUNT) { + /* sent event to queue, picus tool will log it for bluetooth KPI feature */ + if (btmtk_sdio_skb_enq_fwlog(buf, len, type, &g_priv->adapter->fwlog_fops_queue) == 0) { + wake_up_interruptible(&fw_log_inq); + fwlog_blocking_warn = 0; + } + } else { + if (fwlog_blocking_warn == 0) { + fwlog_blocking_warn = 1; + pr_warn("%s fwlog queue size is full(bluetooth_kpi)\n", __func__); + } + } + return 0; +} + +#ifdef CONFIG_AMAZON_A2DP_TS_SDIO +static inline unsigned int get_audio_ts( + const unsigned char *p_buf, unsigned int buf_len) +{ + if (buf_len > 20 && p_buf[4] == 0x2 && p_buf[14] == 0x60) { + unsigned int pkt_ts; + + pkt_ts = p_buf[17] << 24; + pkt_ts |= p_buf[18] << 16; + pkt_ts |= p_buf[19] << 8; + pkt_ts |= p_buf[20]; + return pkt_ts; + } + return UINT_MAX; +} +#endif + +static int btmtk_sdio_host_to_card(struct btmtk_private *priv, + u8 *payload, u16 nb) +{ + struct btmtk_sdio_card *card = priv->btmtk_dev.card; + int ret = 0; + int i = 0; + u8 MultiBluckCount = 0; + u8 redundant = 0; + int len = 0; +#ifdef CONFIG_AMAZON_A2DP_TS_SDIO + unsigned int audio_ts; +#endif + + if (payload != txbuf) { + memset(txbuf, 0, MTK_TXDATA_SIZE); + memcpy(txbuf, payload, nb); + } + + if (!card || !card->func) { + pr_err("card or function is NULL!\n"); + return -EINVAL; + } + len = nb - MTK_SDIO_PACKET_HEADER_SIZE; + + btmtk_usb_dispatch_data_bluetooth_kpi(&txbuf[MTK_SDIO_PACKET_HEADER_SIZE], len, 0); + + MultiBluckCount = nb/SDIO_BLOCK_SIZE; + redundant = nb % SDIO_BLOCK_SIZE; + + if (redundant) + nb = (MultiBluckCount+1)*SDIO_BLOCK_SIZE; + + if (nb < 16) + btmtk_print_buffer_conent(txbuf, nb); + else + btmtk_print_buffer_conent(txbuf, 16); + +#ifdef CONFIG_AMAZON_A2DP_TS_SDIO + audio_ts = get_audio_ts(txbuf, nb); +#endif + + do { + /* Transfer data to card */ + sdio_claim_host(card->func); + ret = sdio_writesb(card->func, CTDR, txbuf, nb); + sdio_release_host(card->func); + if (ret < 0) { + i++; + pr_err("i=%d writesb failed: %d\n", i, ret); + ret = -EIO; + if (i > MAX_WRITE_IOMEM_RETRY) + goto exit; + } + } while (ret); + +#ifdef CONFIG_AMAZON_A2DP_TS_SDIO + if (audio_ts != UINT_MAX) { + u64 ts = mtk_timer_get_cnt(6); + btif_update_audio_ts(audio_ts, ts); + } +#endif + + priv->btmtk_dev.tx_dnld_rdy = false; + +exit: + + return ret; +} + +static int btmtk_sdio_set_i2s_slave(void) +{ + int ret = 0; + u8 wmt_event[7] = { 0x04, 0x0E, 0x04, 0x01, 0x72, 0xFC, 0x00 }; + +#ifdef MTK_CHIP_PCM /* For PCM setting */ + u8 cmd_pcm[] = { 0x01, 0x72, 0xFC, 0x04, 0x03, 0x10, 0x00, 0x4A }; +#if SUPPORT_MT7668 + u8 cmd_7668[] = { 0x01, 0x72, 0xFC, 0x04, 0x03, 0x10, 0x00, 0x4A }; +#endif +#if SUPPORT_MT7663 + u8 cmd_7663[] = { 0x01, 0x72, 0xFC, 0x04, 0x49, 0x00, 0x80, 0x00 }; +#endif +#else /* For I2S setting */ +#if SUPPORT_MT7668 + u8 cmd_7668[] = { 0x01, 0x72, 0xFC, 0x04, 0x03, 0x10, 0x00, 0x02 }; +#endif +#if SUPPORT_MT7663 + u8 cmd_7663[] = { 0x01, 0x72, 0xFC, 0x04, 0x49, 0x00, 0x80, 0x00 }; +#endif +#endif + u8 *cmd = NULL; + int cmd_len = 0; + u8 mtksdio_packet_header[MTK_SDIO_PACKET_HEADER_SIZE] = { 0 }; + u8 mode = 0; + + pr_info("%s\n", __func__); +#if SUPPORT_MT7668 + if (is_mt7668(g_card)) { + cmd = cmd_7668; + cmd_len = sizeof(cmd_7668); + mode = 0x08; + } +#endif +#if SUPPORT_MT7663 + if (is_mt7663(g_card)) { + cmd = cmd_7663; + cmd_len = sizeof(cmd_7663); + mode = 0x03; + } +#endif +#ifdef MTK_CHIP_PCM + if (!cmd) { + pr_info("%s cmd == null, set default PCM setting\n", __func__); + cmd = cmd_pcm; + cmd_len = sizeof(cmd_pcm); + mode |= 0x20; + } else + mode |= 0x10; +#endif + + pr_info("%s set mode = 0x%x\n", __func__, mode); + + mtksdio_packet_header[0] = sizeof(mtksdio_packet_header) + cmd_len; + memcpy(txbuf, mtksdio_packet_header, MTK_SDIO_PACKET_HEADER_SIZE); + memcpy(txbuf + MTK_SDIO_PACKET_HEADER_SIZE, cmd, cmd_len); + btmtk_sdio_send_tx_data(txbuf, MTK_SDIO_PACKET_HEADER_SIZE + cmd_len); + + btmtk_sdio_recv_rx_data(); + + pr_debug("%s rx_length %d\n", __func__, rx_length); + pr_debug("%s rx_length %d %02x%02x%02x%02x%02x\%02x%02x%02x%02x%02x%02x%02x\n", __func__, + rx_length, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4] + , rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9] + , rxbuf[10], rxbuf[11]); + + /* compare rx data is wmt reset correct response or not */ + if (memcmp(wmt_event, rxbuf + MTK_SDIO_PACKET_HEADER_SIZE, sizeof(wmt_event)) != 0) { + ret = -EIO; + pr_err("%s: fail\n", __func__); + } + return ret; +} + +static int btmtk_sdio_read_pin_mux_setting(u32 *value) +{ + int ret = 0; + u8 cmd[] = { 1, 0xD1, 0xFC, 4, 0x54, 0x30, 0x02, 0x81 }; + u8 tempvalue = 0; + u8 mtksdio_packet_header[MTK_SDIO_PACKET_HEADER_SIZE] = { 0 }; + + pr_info("%s\n", __func__); + mtksdio_packet_header[0] = sizeof(mtksdio_packet_header) + sizeof(cmd); + memcpy(txbuf, mtksdio_packet_header, MTK_SDIO_PACKET_HEADER_SIZE); + memcpy(txbuf + MTK_SDIO_PACKET_HEADER_SIZE, cmd, sizeof(cmd)); + pr_debug("%s tx buf %02x%02x%02x%02x%02x\%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + __func__, txbuf[0], txbuf[1], txbuf[2], txbuf[3], txbuf[4] + , txbuf[5], txbuf[6], txbuf[7], txbuf[8], txbuf[9] + , txbuf[10], txbuf[11], txbuf[12], txbuf[13], txbuf[14]); + btmtk_sdio_send_tx_data(txbuf, MTK_SDIO_PACKET_HEADER_SIZE + sizeof(cmd)); + + btmtk_sdio_recv_rx_data(); + + pr_debug("%s rx_length %d\n", __func__, rx_length); + pr_debug + ("%s rx_length %d %02x%02x%02x%02x%02x\%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + __func__, rx_length, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4] + , rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9] + , rxbuf[10], rxbuf[11], rxbuf[12], rxbuf[13], rxbuf[14]); + + if (rx_length >= 15) { + tempvalue = rxbuf[14]; + *value = (rxbuf[14] << 24) + (rxbuf[13] << 16) + (rxbuf[12] << 8) + rxbuf[11]; + pr_debug("%s value=%08x\n", __func__, *value); + } else { + ret = -EIO; + pr_err("%s get event error rx_length %d\n", __func__, rx_length); + } + + return ret; +} + +static int btmtk_sdio_write_pin_mux_setting(u32 value) +{ + int ret = 0; + u8 event[7] = { 4, 0xE, 4, 1, 0xD0, 0xFC, 0 }; + u8 cmd[12] = { 1, 0xD0, 0xFC, 8, 0x54, 0x30, 0x02, 0x81, 0, 0, 0, 0 }; + u8 mtksdio_packet_header[MTK_SDIO_PACKET_HEADER_SIZE] = { 0 }; + + pr_info("%s begin\n", __func__); + cmd[8] = (value & 0x000000FF); + cmd[9] = ((value & 0x0000FF00) >> 8); + cmd[10] = ((value & 0x00FF0000) >> 16); + cmd[11] = ((value & 0xFF000000) >> 24); + + pr_debug("%s value=%08x begin\n", __func__, value); + mtksdio_packet_header[0] = sizeof(mtksdio_packet_header) + sizeof(cmd); + memcpy(txbuf, mtksdio_packet_header, MTK_SDIO_PACKET_HEADER_SIZE); + memcpy(txbuf + MTK_SDIO_PACKET_HEADER_SIZE, cmd, sizeof(cmd)); + + pr_debug("%s tx buf %02x%02x%02x%02x%02x\%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + __func__, txbuf[0], txbuf[1], txbuf[2], txbuf[3], txbuf[4], + txbuf[5], txbuf[6], txbuf[7], txbuf[8], txbuf[9], + txbuf[10], txbuf[11], txbuf[12], txbuf[13], txbuf[14], txbuf[15]); + + btmtk_sdio_send_tx_data(txbuf, MTK_SDIO_PACKET_HEADER_SIZE + sizeof(cmd)); + + btmtk_sdio_recv_rx_data(); + + pr_debug("%s rx_length %d\n", __func__, rx_length); + pr_debug + ("%s rx_length %d %02x%02x%02x%02x%02x\%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + __func__, rx_length, rxbuf[0], rxbuf[1], rxbuf[2], rxbuf[3], rxbuf[4] + , rxbuf[5], rxbuf[6], rxbuf[7], rxbuf[8], rxbuf[9] + , rxbuf[10], rxbuf[11], rxbuf[12], rxbuf[13], rxbuf[14]); + + /* compare rx data is wmt reset correct response or not */ + if (memcmp(event, rxbuf + MTK_SDIO_PACKET_HEADER_SIZE, sizeof(event)) != 0) { + ret = -EIO; + pr_err("%s: fail\n", __func__); + } + return ret; + +} + +static int btmtk_send_rom_patch(u8 *fwbuf, u32 fwlen, int mode) +{ + int ret = 0; + u8 mtksdio_packet_header[MTK_SDIO_PACKET_HEADER_SIZE] = {0}; + int stp_len = 0; + u8 mtkdata_header[MTKDATA_HEADER_SIZE] = {0}; + + int copy_len = 0; + int Datalen = fwlen; + u32 u32ReadCRValue = 0; + + + pr_debug("%s fwlen %d, mode = %d\n", __func__, fwlen, mode); + if (fwlen < Datalen) { + pr_err("%s file size = %d,is not corect\n", __func__, fwlen); + return -ENOENT; + } + + stp_len = Datalen + MTKDATA_HEADER_SIZE; + + + mtkdata_header[0] = 0x2;/*ACL data*/ + mtkdata_header[1] = 0x6F; + mtkdata_header[2] = 0xFC; + + mtkdata_header[3] = ((Datalen+4+1)&0x00FF); + mtkdata_header[4] = ((Datalen+4+1)&0xFF00)>>8; + + mtkdata_header[5] = 0x1; + mtkdata_header[6] = 0x1; + + mtkdata_header[7] = ((Datalen+1)&0x00FF); + mtkdata_header[8] = ((Datalen+1)&0xFF00)>>8; + + mtkdata_header[9] = mode; + +/* 0 and 1 is packet length, include MTKSTP_HEADER_SIZE */ + mtksdio_packet_header[0] = + (Datalen+4+MTKSTP_HEADER_SIZE+6)&0xFF; + mtksdio_packet_header[1] = + ((Datalen+4+MTKSTP_HEADER_SIZE+6)&0xFF00)>>8; + mtksdio_packet_header[2] = 0; + mtksdio_packet_header[3] = 0; + +/* + * mtksdio_packet_header[2] and mtksdio_packet_header[3] + * are reserved + */ + pr_debug("%s result %02x %02x\n", __func__, + ((Datalen+4+MTKSTP_HEADER_SIZE+6)&0xFF00)>>8, + (Datalen+4+MTKSTP_HEADER_SIZE+6)); + + memcpy(txbuf+copy_len, mtksdio_packet_header, + MTK_SDIO_PACKET_HEADER_SIZE); + copy_len += MTK_SDIO_PACKET_HEADER_SIZE; + + memcpy(txbuf+copy_len, mtkdata_header, MTKDATA_HEADER_SIZE); + copy_len += MTKDATA_HEADER_SIZE; + + memcpy(txbuf+copy_len, fwbuf, Datalen); + copy_len += Datalen; + + pr_debug("%s txbuf %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", + __func__, + txbuf[0], txbuf[1], txbuf[2], txbuf[3], txbuf[4], + txbuf[5], txbuf[6], txbuf[7], txbuf[8], txbuf[9]); + + + ret = btmtk_sdio_readl(CHIER, &u32ReadCRValue); + pr_debug("%s: CHIER u32ReadCRValue %x, ret %d\n", + __func__, u32ReadCRValue, ret); + + ret = btmtk_sdio_readl(CHLPCR, &u32ReadCRValue); + pr_debug("%s: CHLPCR u32ReadCRValue %x, ret %d\n", + __func__, u32ReadCRValue, ret); + + ret = btmtk_sdio_readl(CHISR, &u32ReadCRValue); + pr_debug("%s: 0CHISR u32ReadCRValue %x, ret %d\n", + __func__, u32ReadCRValue, ret); + ret = btmtk_sdio_readl(CHISR, &u32ReadCRValue); + pr_debug("%s: 00CHISR u32ReadCRValue %x, ret %d\n", + __func__, u32ReadCRValue, ret); + + btmtk_sdio_send_tx_data(txbuf, copy_len); + + ret = btmtk_sdio_recv_rx_data(); + + return ret; +} + + + +/* + * type: cmd:1, ACL:2 + * ------------------------------------------------- + * mtksdio hedaer 4 byte| wmt header | + * + * + * data len should less than 512-4-4 + */ +static int btmtk_sdio_send_wohci(u8 type, u32 len, u8 *data) +{ + u32 ret = 0; + u32 push_in_data_len = 0; + u32 MultiBluckCount = 0; + u32 redundant = 0; + u8 mtk_wmt_header[MTKWMT_HEADER_SIZE] = {0}; + u8 mtksdio_packet_header[MTK_SDIO_PACKET_HEADER_SIZE] = {0}; + u8 mtk_tx_data[512] = {0}; + + mtk_wmt_header[0] = type; + mtk_wmt_header[1] = 0x6F; + mtk_wmt_header[2] = 0xFC; + mtk_wmt_header[3] = len; + + mtksdio_packet_header[0] = + (len+MTKWMT_HEADER_SIZE+MTK_SDIO_PACKET_HEADER_SIZE)&0xFF; + mtksdio_packet_header[1] = + ((len+MTKWMT_HEADER_SIZE+MTK_SDIO_PACKET_HEADER_SIZE)&0xFF00) + >>8; + mtksdio_packet_header[2] = 0; + mtksdio_packet_header[3] = 0; +/* + * mtksdio_packet_header[2] and mtksdio_packet_header[3] + * are reserved + */ + + memcpy(mtk_tx_data, mtksdio_packet_header, + sizeof(mtksdio_packet_header)); + push_in_data_len += sizeof(mtksdio_packet_header); + + memcpy(mtk_tx_data+push_in_data_len, mtk_wmt_header, + sizeof(mtk_wmt_header)); + push_in_data_len += sizeof(mtk_wmt_header); + + memcpy(mtk_tx_data+push_in_data_len, data, len); + push_in_data_len += len; + memcpy(txbuf, mtk_tx_data, push_in_data_len); + + MultiBluckCount = push_in_data_len/4; + redundant = push_in_data_len % 4; + if (redundant) + push_in_data_len = (MultiBluckCount+1)*4; + + sdio_claim_host(g_card->func); + ret = sdio_writesb(g_card->func, CTDR, txbuf, push_in_data_len); + sdio_release_host(g_card->func); + + pr_info("%s retrun 0x%0x\n", __func__, ret); + return ret; +} + +/* + * data event: + * return + * 0: + * patch download is not complete/get patch semaphore fail + * 1: + * patch download is complete by others + * 2 + * patch download is not coplete + * 3:(for debug) + * release patch semaphore success + */ +static int btmtk_sdio_need_load_rom_patch(void) +{ + u32 ret = -1; + u8 cmd[] = {0x1, 0x17, 0x1, 0x0, 0x1}; + u8 event[] = {0x2, 0x17, 0x1, 0x0}; + + do { + ret = btmtk_sdio_send_wohci(HCI_COMMAND_PKT, sizeof(cmd), cmd); + + if (ret) { + pr_err("%s btmtk_sdio_send_wohci return fail ret %d\n", + __func__, ret); + break; + } + + ret = btmtk_sdio_recv_rx_data(); + if (ret) + break; + + if (rx_length == 12) { + if (memcmp(rxbuf+7, event, sizeof(event)) == 0) + return rxbuf[11]; + + pr_err("%s receive event content is not correct, print receive data\n", + __func__); + btmtk_print_buffer_conent(rxbuf, rx_length); + } + } while (0); + pr_err("%s return ret %d\n", __func__, ret); + return ret; +} +static int btmtk_sdio_set_write_clear(void) +{ + u32 u32ReadCRValue = 0; + u32 ret = 0; + + ret = btmtk_sdio_readl(CHCR, &u32ReadCRValue); + if (ret) { + pr_err("%s read CHCR error\n", __func__); + ret = EINVAL; + return ret; + } + + u32ReadCRValue |= 0x00000002; + btmtk_sdio_writel(CHCR, u32ReadCRValue); + pr_info("%s write CHCR 0x%08X\n", __func__, u32ReadCRValue); + ret = btmtk_sdio_readl(CHCR, &u32ReadCRValue); + pr_info("%s read CHCR 0x%08X\n", __func__, u32ReadCRValue); + if (u32ReadCRValue&0x00000002) + pr_info("%s write clear\n", __func__); + else + pr_info("%s read clear\n", __func__); + + return ret; +} + +static int btmtk_sdio_set_i2s(void) +{ + int ret = 0; + u32 pinmux = 0; + + ret = btmtk_sdio_set_i2s_slave(); + if (ret) { + pr_err("btmtk_sdio_set_i2s_slave error(%d)\n", ret); + return ret; + } + ret = btmtk_sdio_read_pin_mux_setting(&pinmux); + if (ret) { + pr_err("btmtk_sdio_read_pin_mux_setting error(%d)\n", ret); + return ret; + } + + pinmux &= 0x0000FFFF; + pinmux |= 0x22220000; + ret = btmtk_sdio_write_pin_mux_setting(pinmux); + + if (ret) { + pr_err("btmtk_sdio_write_pin_mux_setting error(%d)\n", ret); + return ret; + } + + pinmux = 0; + ret = btmtk_sdio_read_pin_mux_setting(&pinmux); + if (ret) { + pr_err("btmtk_sdio_read_pin_mux_setting error(%d)\n", ret); + return ret; + } + pr_info("confirm pinmux %04x\n", pinmux); + + return ret; +} + +static int btmtk_sdio_download_partial_rom_patch(u8 *fwbuf, int firmwarelen) +{ + int ret = 0; + int RedundantSize = 0; + u32 bufferOffset = 0; + + pr_info("Downloading FW image (%d bytes)\n", firmwarelen); + + fwbuf += PATCH_INFO_SIZE; + pr_debug("%s PATCH_HEADER size %d\n", + __func__, PATCH_INFO_SIZE); + + RedundantSize = firmwarelen; + pr_debug("%s firmwarelen %d\n", __func__, firmwarelen); + + do { + bufferOffset = firmwarelen - RedundantSize; + + if (RedundantSize == firmwarelen && + RedundantSize >= PATCH_DOWNLOAD_SIZE) + ret = btmtk_send_rom_patch(fwbuf + bufferOffset, + PATCH_DOWNLOAD_SIZE, + SDIO_PATCH_DOWNLOAD_FIRST); + else if (RedundantSize == firmwarelen) + ret = btmtk_send_rom_patch(fwbuf + bufferOffset, + RedundantSize, + SDIO_PATCH_DOWNLOAD_FIRST); + else if (RedundantSize < PATCH_DOWNLOAD_SIZE) { + ret = btmtk_send_rom_patch(fwbuf + bufferOffset, + RedundantSize, + SDIO_PATCH_DOWNLOAD_END); + pr_debug("%s patch downoad last patch part\n", + __func__); + } else + ret = btmtk_send_rom_patch(fwbuf + bufferOffset, + PATCH_DOWNLOAD_SIZE, + SDIO_PATCH_DOWNLOAD_CON); + + RedundantSize -= PATCH_DOWNLOAD_SIZE; + + if (ret) { + pr_err("%s btmtk_send_rom_patch fail\n", __func__); + return ret; + } + pr_debug("%s RedundantSize %d\n", __func__, RedundantSize); + if (RedundantSize <= 0) { + pr_debug("%s patch downoad finish\n", __func__); + break; + } + } while (1); + + return ret; +} + +static int btmtk_sdio_download_rom_patch(struct btmtk_sdio_card *card) +{ + const struct firmware *fw_firmware = NULL; + int firmwarelen, ret = 0; + u8 *fwbuf; + struct _PATCH_HEADER *patchHdr; + u16 u2HwVer = 0; + u16 u2SwVer = 0; + u32 u4PatchVer = 0; + u32 u4FwVersion = 0; + u32 u4ChipId = 0; + u32 u32ReadCRValue = 0; + u8 patch_status = 0; + char strDateTime[17]; + bool load_sysram3 = false; + int retry = 20; + + ret = btmtk_sdio_set_own_back(DRIVER_OWN); + if (ret) + return ret; + + u4FwVersion = btmtk_sdio_bt_memRegister_read(FW_VERSION); + pr_info("%s Fw Version 0x%x\n", __func__, u4FwVersion); + u4ChipId = btmtk_sdio_bt_memRegister_read(CHIP_ID); + pr_info("%s Chip Id 0x%x\n", __func__, u4ChipId); + + if ((u4FwVersion & 0xff) == 0xff) { + pr_err("%s failed ! wrong fw version : 0x%x\n", __func__, u4FwVersion); + return -1; + + } else { + u8 uFirmwareName[MAX_BIN_FILE_NAME_LEN] = {0}; + + /* Bin filename format : "mt$$$$_patch_e%.bin" */ + /* $$$$ : chip id */ + /* % : fw version + 1 (in HEX) */ + snprintf(uFirmwareName, MAX_BIN_FILE_NAME_LEN, "mt%04x_patch_e%x_hdr.bin", + u4ChipId & 0xffff, (u4FwVersion & 0x0ff) + 1); + pr_info("%s request_firmware(firmware name %s)\n", + __func__, uFirmwareName); + ret = request_firmware(&fw_firmware, uFirmwareName, + &card->func->dev); + + if ((ret < 0) || !fw_firmware) { + pr_err("request_firmware(firmware name %s) failed, error code = %d\n", + uFirmwareName, + ret); + ret = -ENOENT; + goto done; + } + } + memset(fw_version_str, 0, FW_VERSION_BUF_SIZE); + if ((fw_firmware->data[8] >= '0') && (fw_firmware->data[8] <= '9')) + memcpy(fw_version_str, fw_firmware->data, FW_VERSION_SIZE - 1); + else + sprintf(fw_version_str, "%.4s-%.2s-%.2s.%.1s.%.2s.%.1s.%.1s.%.2s", + fw_firmware->data, fw_firmware->data + 4, fw_firmware->data + 6, + fw_firmware->data + 8, fw_firmware->data + 9, + fw_firmware->data + 11, fw_firmware->data + 12, + fw_firmware->data + 13); +#if SUPPORT_MT7663 + if (is_mt7663(g_card)) { + ret = btmtk_sdio_send_tci_power_on_wifi_memory(); + if (ret < 0) { + pr_err("Send tci power on wifi memory fail(%d)\n", ret); + goto done; + } + } + +#endif + +#if SUPPORT_MT7668 + if (is_mt7668(g_card)) { + load_sysram3 = + (fw_firmware->size > (PATCH_INFO_SIZE + PATCH_LEN_ILM)) + ? true : false; + pr_info("%s patch size is %zu bytes\n", __func__, fw_firmware->size); + } +#endif + + do { + patch_status = btmtk_sdio_need_load_rom_patch(); + pr_debug("%s patch_status %d\n", __func__, patch_status); + + if (patch_status > PATCH_NEED_DOWNLOAD || patch_status < 0) { + pr_err("%s patch_status error\n", __func__); + return -1; + } else if (patch_status == PATCH_READY) { + pr_info("%s patch is ready no need load patch again\n", + __func__); + if (!load_sysram3) + goto patch_end; + else + goto sysram3; + } else if (patch_status == PATCH_IS_DOWNLOAD_BY_OTHER) { + msleep(100); + retry--; + } else if (patch_status == PATCH_NEED_DOWNLOAD) { + break; /* Download ROM patch directly */ + } + } while (retry > 0); + + if (patch_status == PATCH_IS_DOWNLOAD_BY_OTHER) { + pr_warn("%s Hold by another fun more than 2 seconds\n", + __func__); + return -1; + } + + fwbuf = (u8 *)fw_firmware->data; + + /*Display rom patch info*/ + patchHdr = (struct _PATCH_HEADER *)fwbuf; + memcpy(strDateTime, patchHdr->ucDateTime, sizeof(patchHdr->ucDateTime)); + strDateTime[16] = '\0'; + u2HwVer = patchHdr->u2HwVer; + u2SwVer = patchHdr->u2SwVer; + u4PatchVer = patchHdr->u4PatchVer; + + pr_info("[btmtk] =============== Patch Info ==============\n"); + pr_info("[btmtk] Built Time = %s\n", strDateTime); + pr_info("[btmtk] Hw Ver = 0x%x\n", + ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8)); + pr_info("[btmtk] Sw Ver = 0x%x\n", + ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8)); + pr_info("[btmtk] Patch Ver = 0x%04x\n", + ((u4PatchVer & 0xff000000) >> 24) | + ((u4PatchVer & 0x00ff0000) >> 16)); + + pr_info("[btmtk] Platform = %c%c%c%c\n", + patchHdr->ucPlatform[0], + patchHdr->ucPlatform[1], + patchHdr->ucPlatform[2], + patchHdr->ucPlatform[3]); + pr_info("[btmtk] Patch start addr = %02x\n", patchHdr->u2PatchStartAddr); + pr_info("[btmtk] =========================================\n"); + + + firmwarelen = load_sysram3 ? + PATCH_LEN_ILM : (fw_firmware->size - PATCH_INFO_SIZE); + + ret = btmtk_sdio_readl(0, &u32ReadCRValue); + pr_info("%s read chipid = %x\n", __func__, u32ReadCRValue); + + pr_info("%s loading ILM rom patch...\n", __func__); + ret = btmtk_sdio_download_partial_rom_patch(fwbuf, firmwarelen); + pr_info("%s loading ILM rom patch... Done\n", __func__); + + if (btmtk_sdio_need_load_rom_patch() == PATCH_READY) { + pr_info("%s patchdownload is done by BT\n", __func__); + } else { + /* TODO: Need error handling here*/ + pr_warn("%s patchdownload download by BT, not ready\n", + __func__); + } + + /* CHIP_RESET, ROM patch would be reactivated. + * Currently, wmt reset is only for ILM rom patch, and there are also + * some preparations need to be done in FW for loading sysram3 patch... + */ + ret = btmtk_sdio_send_wmt_reset(); + if (ret) + goto done; + +sysram3: + if (load_sysram3) { + firmwarelen = fw_firmware->size - PATCH_INFO_SIZE + - PATCH_LEN_ILM - PATCH_INFO_SIZE; + fwbuf = (u8 *)fw_firmware->data + PATCH_INFO_SIZE + + PATCH_LEN_ILM; + pr_info("%s loading sysram3 rom patch...\n", __func__); + ret = btmtk_sdio_download_partial_rom_patch(fwbuf, firmwarelen); + pr_info("%s loading sysram3 rom patch... Done\n", __func__); + } + +patch_end: + + ret = btmtk_sdio_readl(0, &u32ReadCRValue); + pr_info("%s read chipid = %x\n", __func__, u32ReadCRValue); + + /*Set interrupt output*/ + ret = btmtk_sdio_writel(CHIER, FIRMWARE_INT|TX_FIFO_OVERFLOW | + FW_INT_IND_INDICATOR | TX_COMPLETE_COUNT | + TX_UNDER_THOLD | TX_EMPTY | RX_DONE); + if (ret) { + pr_err("Set interrupt output fail(%d)\n", ret); + ret = -EIO; + goto done; + } + + /*enable interrupt output*/ + ret = btmtk_sdio_writel(CHLPCR, C_FW_INT_EN_SET); + if (ret) { + pr_err("enable interrupt output fail(%d)\n", ret); + ret = -EIO; + goto done; + } + + btmtk_sdio_set_write_clear(); + + ret = btmtk_sdio_bt_set_power(1); + + if (ret) { + ret = -EINVAL; + goto done; + } + +#if BTMTK_BIN_FILE_MODE + /* Send hci cmd before sleep */ + btmtk_eeprom_bin_file(card); +#endif + + ret = btmtk_sdio_set_sleep(); + if (ret) { + ret = -EINVAL; + goto done; + } + + ret = btmtk_sdio_set_i2s(); + +done: + + release_firmware(fw_firmware); + + if (!ret) + pr_info("%s success\n", __func__); + else + pr_info("%s fail\n", __func__); + + return ret; +} + +static void btmtk_sdio_close_coredump_file(void) +{ + pr_debug("%s vfs_fsync\n", __func__); + +#if SAVE_FW_DUMP_IN_KERNEL + if (fw_dump_file) + vfs_fsync(fw_dump_file, 0); +#endif + fw_is_doing_coredump = false; + fw_is_coredump_end_packet = true; + + if (fw_dump_file) { + pr_info("%s : close file %s\n", + __func__, fw_dump_file_name); +#if SAVE_FW_DUMP_IN_KERNEL + filp_close(fw_dump_file, NULL); +/* #endif */ + fw_dump_file = NULL; +#endif + + } else { + printk_ratelimited(KERN_WARNING + "%s : fw_dump_file is NULL can't close file %s\n", + __func__, fw_dump_file_name); + } +} + +static void btmtk_sdio_stop_wait_dump_complete_thread(void) +{ + if (IS_ERR(wait_dump_complete_tsk) || wait_dump_complete_tsk == NULL) + printk_ratelimited(KERN_WARNING "%s wait_dump_complete_tsk is error", __func__); + else { + kthread_stop(wait_dump_complete_tsk); + wait_dump_complete_tsk = NULL; + } +} + +static int btmtk_sdio_dispatch_fwlog(u8 *buf, int len) +{ + static u8 fwlog_picus_blocking_warn; + static u8 fwlog_fwdump_blocking_warn; + int ret = 0; + + if ((buf[0] == 0xFF && buf[2] == 0x50) || + (buf[0] == 0xFF && buf[1] == 0x05)) { + if (skb_queue_len(&g_priv->adapter->fwlog_fops_queue) < FWLOG_QUEUE_COUNT) { + pr_debug("%s : This is picus data", __func__); + if (btmtk_sdio_skb_enq_fwlog(buf, len, 0, &g_priv->adapter->fwlog_fops_queue) == 0) + wake_up_interruptible(&fw_log_inq); + + fwlog_picus_blocking_warn = 0; + } else { + if (fwlog_picus_blocking_warn == 0) { + fwlog_picus_blocking_warn = 1; + pr_warn("%s picus queue is full\n", __func__); + } + } + } else if (buf[0] == 0x6f && buf[1] == 0xfc) { + /* Coredump */ + if (skb_queue_len(&g_priv->adapter->fwlog_fops_queue) < FWLOG_ASSERT_QUEUE_COUNT) { + pr_debug("%s : Receive coredump, move data to fwlogqueue for picus", __func__); + if (btmtk_sdio_skb_enq_fwlog(buf, len, 0, &g_priv->adapter->fwlog_fops_queue) == 0) + wake_up_interruptible(&fw_log_inq); + + fwlog_fwdump_blocking_warn = 0; + } else { + if (fwlog_fwdump_blocking_warn == 0) { + fwlog_fwdump_blocking_warn = 1; + pr_warn("%s FW dump queue size is full\n", __func__); + } + } + } + return ret; +} + +static int btmtk_sdio_card_to_host(struct btmtk_private *priv, const u8 *event, const int event_len, + int add_spec_header) +{ + /** + * event: check event which want to compare + * return value: -x fail, 0 success + */ + u16 buf_len = 0; + int ret = 0; + struct sk_buff *skb = NULL; + struct sk_buff *fops_skb = NULL; + u32 type = 0; + u32 fourbalignment_len = 0; + u32 dump_len = 0; + char *core_dump_end = NULL; + int i = 0; + int fw_dump_pkt = 0; + static u8 picus_blocking_warn; + static u8 fwdump_blocking_warn; + char *dump_file_name; + + struct sk_buff *skb_hci; + + if (rx_length > (MTK_SDIO_PACKET_HEADER_SIZE + 1)) + buf_len = rx_length - (MTK_SDIO_PACKET_HEADER_SIZE + 1); + else { + pr_err("%s, rx_length error(%d)\n", __func__, rx_length); + return -EINVAL; + } + +#if SUPPORT_FW_DUMP + fw_is_coredump_end_packet = false; + if (rx_length > (SDIO_HEADER_LEN + 8) && rxbuf[SDIO_HEADER_LEN] == 0x80 && + rxbuf[SDIO_HEADER_LEN + 5] == 0x6F && rxbuf[SDIO_HEADER_LEN + 6] == 0xFC) { + dump_len = (rxbuf[SDIO_HEADER_LEN + 1] & 0x0F) * 256 + + rxbuf[SDIO_HEADER_LEN + 2]; + pr_debug("%s: get dump length %d\n", __func__, dump_len); + + if (print_dump_data_counter < PRINT_DUMP_COUNT) { + print_dump_data_counter++; + pr_warn("%s : dump %d %s\n", __func__, print_dump_data_counter, + &rxbuf[SDIO_HEADER_LEN + 9]); +#ifndef MTK_KERNEL_DEBUG + /* release mode do reset dongle if print dump finish */ + } else { + if (print_dump_data_counter == PRINT_DUMP_COUNT) { + /* create dump file fail and is user mode */ + pr_info("%s: user mode, do reset after print dump done %d, disable interrupt\n", + __func__, print_dump_data_counter); + print_dump_data_counter++; + picus_blocking_warn = 0; + fwdump_blocking_warn = 0; + btmtk_sdio_close_coredump_file(); + btmtk_sdio_stop_wait_dump_complete_thread(); + } + fw_is_doing_coredump = true; + goto SKIP_DUMP; +#endif + } + fw_is_doing_coredump = true; + +#if SAVE_FW_DUMP_IN_KERNEL + if (fw_dump_file == NULL && print_dump_data_counter == 1) { + /* #if SAVE_FW_DUMP_IN_KERNEL */ + pr_info("%s: create btmtk_sdio_wait_dump_complete_thread\n", __func__); + wait_dump_complete_tsk = kthread_run(btmtk_sdio_wait_dump_complete_thread, + NULL, "btmtk_sdio_wait_dump_complete_thread"); + msleep(100); + if (!wait_dump_complete_tsk) + pr_err("%s: wait_dump_complete_tsk is NULL\n", __func__); + + btmtk_sdio_notify_wlan_remove_start(); + btmtk_sdio_set_no_fw_own(g_priv, TRUE); + + for (i = 0; i < ARRAY_SIZE(COREDUMP_FILE_NAME); i++) { + memset(fw_dump_file_name, 0, sizeof(fw_dump_file_name)); + dump_file_name = COREDUMP_FILE_NAME[i]; + snprintf(fw_dump_file_name, sizeof(fw_dump_file_name), + "%s_%d", dump_file_name, current_fwdump_file_number); + pr_warn("%s : open file %s\n", __func__, fw_dump_file_name); + fw_dump_file = filp_open(fw_dump_file_name, O_RDWR | O_CREAT, 0644); + + if (!(IS_ERR(fw_dump_file))) { + pr_warn("%s : open file %s success\n", __func__, + fw_dump_file_name); + } else { + pr_warn("%s : open file %s fail\n", __func__, + fw_dump_file_name); + fw_dump_file = NULL; + continue; + } + + if (fw_dump_file && fw_dump_file->f_op == NULL) { + pr_warn("%s : %s fw_dump_file->f_op is NULL, close\n", + fw_dump_file_name, __func__); + filp_close(fw_dump_file, NULL); + fw_dump_file = NULL; + continue; + } + + if (fw_dump_file && fw_dump_file->f_op->write == NULL) { + pr_warn("%s : %s fw_dump_file->f_op->write is NULL, close\n", + fw_dump_file_name, __func__); + filp_close(fw_dump_file, NULL); + fw_dump_file = NULL; + continue; + } + /* open file success */ + current_fwdump_file_number++; + break; + } + } + + if ((dump_len > 0) && fw_dump_file && fw_dump_file->f_op + && fw_dump_file->f_op->write) + fw_dump_file->f_op->write(fw_dump_file, &rxbuf[SDIO_HEADER_LEN + 9], + dump_len, &fw_dump_file->f_pos); +#endif /* SAVE_FW_DUMP_IN_KERNEL */ + + btmtk_sdio_dispatch_fwlog(&rxbuf[MTK_SDIO_PACKET_HEADER_SIZE + 5], buf_len); + if (dump_len >= strlen(FW_DUMP_END_EVENT)) { + core_dump_end = strstr(&rxbuf[SDIO_HEADER_LEN + 10], FW_DUMP_END_EVENT); + if (core_dump_end) { + pr_warn("%s : core_dump_end %s, rxbuf = %02x %02x %02x\n", + __func__, core_dump_end, rxbuf[4], rxbuf[5], rxbuf[6]); + pr_warn("%s : get core_dump_end %s\n", __func__, core_dump_end); + sdio_claim_host(g_card->func); + sdio_release_irq(g_card->func); + sdio_release_host(g_card->func); + print_dump_data_counter = 0; + picus_blocking_warn = 0; + fwdump_blocking_warn = 0; + btmtk_sdio_close_coredump_file(); + btmtk_sdio_stop_wait_dump_complete_thread(); + } + } + /** Modify header to ACL format, handle is 0xFFF0 + * Core dump header: + * 80 AA BB CC DD 6F FC XX XX XX ...... + * 80 -> 02 (ACL TYPE) + * AA BB -> FF F0 + * CC DD -> Data length + */ + rxbuf[SDIO_HEADER_LEN] = HCI_ACLDATA_PKT; + rxbuf[SDIO_HEADER_LEN + 3] = (buf_len - 4) & 0xFF; + rxbuf[SDIO_HEADER_LEN + 4] = ((buf_len - 4) >> 8) & 0xFF; + rxbuf[SDIO_HEADER_LEN + 1] = 0xFF; + rxbuf[SDIO_HEADER_LEN + 2] = 0xF0; + fw_dump_pkt = 1; + } +#endif /* SUPPORT_FW_DUMP */ + +#ifndef MTK_KERNEL_DEBUG +SKIP_DUMP: +#endif + if (rx_length > (SDIO_HEADER_LEN + 4) && + ((rxbuf[SDIO_HEADER_LEN] == 0x04 && + rxbuf[SDIO_HEADER_LEN + 1] == 0xFF && + rxbuf[SDIO_HEADER_LEN + 3] == 0x50) || + (rxbuf[SDIO_HEADER_LEN] == 0x02 && + rxbuf[SDIO_HEADER_LEN + 1] == 0xFF && + rxbuf[SDIO_HEADER_LEN + 2] == 0x05))) { + /* receive picus data to fwlog_queue */ + if (rxbuf[SDIO_HEADER_LEN] == 0x04) { + dump_len = rxbuf[SDIO_HEADER_LEN + 2] - 1; + buf_len = dump_len + 3; + } else { + dump_len = ((rxbuf[SDIO_HEADER_LEN + 4] & 0x0F) << 8) + rxbuf[SDIO_HEADER_LEN + 3]; + buf_len = dump_len + 4; + } + pr_debug("%s This is debug log data, length = %d", __func__, dump_len); + if (rx_length < (buf_len + MTK_SDIO_PACKET_HEADER_SIZE + 1)) + goto data_err; + btmtk_sdio_dispatch_fwlog(&rxbuf[MTK_SDIO_PACKET_HEADER_SIZE + 1], buf_len); + goto exit; + } + + type = rxbuf[MTK_SDIO_PACKET_HEADER_SIZE]; + + btmtk_print_buffer_conent(rxbuf, rx_length); + + pr_debug("%s buf_len : %d\n", __func__, buf_len); + if (rx_length <= SDIO_HEADER_LEN) { + pr_warn("invalid packet length: %d\n", buf_len); + ret = -EINVAL; + goto exit; + } + + /* Allocate buffer */ + /* rx_length = num_blocks * blksz + BTSDIO_DMA_ALIGN*/ + skb = bt_skb_alloc(rx_length, GFP_ATOMIC); + if (skb == NULL) { + pr_err("No free skb\n"); + ret = -ENOMEM; + goto exit; + } + + pr_debug("%s rx_length %d,buf_len %d\n", __func__, rx_length, buf_len); + + memcpy(skb->data, &rxbuf[MTK_SDIO_PACKET_HEADER_SIZE + 1], buf_len); + + switch (type) { + case HCI_ACLDATA_PKT: + pr_debug("%s data[2] 0x%02x, data[3] 0x%02x\n", + __func__, skb->data[2], skb->data[3]); + buf_len = skb->data[2] + skb->data[3] * 256 + 4; + pr_debug("%s acl buf_len %d\n", __func__, buf_len); + break; + case HCI_SCODATA_PKT: + buf_len = skb->data[3] + 3; + break; + case HCI_EVENT_PKT: + buf_len = skb->data[1] + 2; + break; + } + + if (buf_len > MTK_RXDATA_SIZE) { + pr_err("%s buf_len %d is invalid, more than %d\n", __func__, buf_len, MTK_RXDATA_SIZE); + ret = -EINVAL; + goto exit; + } + + if (event_compare_status == BTMTK_SDIO_EVENT_COMPARE_STATE_NEED_COMPARE) + BTSDIO_DEBUG_RAW(skb->data, buf_len, "%s: skb->data :", __func__); + + if ((buf_len >= sizeof(READ_ADDRESS_EVENT)) + && (event_compare_status == BTMTK_SDIO_EVENT_COMPARE_STATE_NEED_COMPARE)) { + if ((memcmp(skb->data, READ_ADDRESS_EVENT, sizeof(READ_ADDRESS_EVENT)) == 0) && (buf_len == 12)) { + for (i = 0; i < BD_ADDRESS_SIZE; i++) + g_card->bdaddr[i] = skb->data[6 + i]; + + pr_debug("%s: GET TV BDADDR = %02X:%02X:%02X:%02X:%02X:%02X", __func__, + g_card->bdaddr[0], g_card->bdaddr[1], g_card->bdaddr[2], + g_card->bdaddr[3], g_card->bdaddr[4], g_card->bdaddr[5]); + + /* + * event_compare_status = + * BTMTK_SDIO_EVENT_COMPARE_STATE_COMPARE_SUCCESS; + */ + } else + pr_debug("%s READ_ADDRESS_EVENT compare fail buf_len %d\n", __func__, buf_len); + } + + if ((fw_is_doing_coredump == false && fw_is_coredump_end_packet == false) + || fw_dump_pkt == 1) { + if (event_compare_status == BTMTK_SDIO_EVENT_COMPARE_STATE_NEED_COMPARE) { + /*compare with tx hci cmd*/ + pr_debug("%s buf_len %d, event_need_compare_len %d\n", + __func__, buf_len, event_need_compare_len); + if (buf_len >= event_need_compare_len) { + if (memcmp(skb->data, event_need_compare, event_need_compare_len) == 0) { + event_compare_status = BTMTK_SDIO_EVENT_COMPARE_STATE_COMPARE_SUCCESS; + pr_debug("%s compare success\n", __func__); + } else { + pr_debug("%s compare fail\n", __func__); + BTSDIO_DEBUG_RAW(event_need_compare, event_need_compare_len, + "%s: event_need_compare :", __func__); + } + } + } + + if (type == 0x80) { + /* To avoid invalid 0x80 packet */ + if (buf_len > 7) { + pr_info("%s drop the packet, packet type: %02x, len: %d, Rawdata: %02x%02x %02x%02x%02x%02x\n", + __func__, type, buf_len, skb->data[0], skb->data[1], skb->data[2], + skb->data[3], skb->data[4], skb->data[5]); + } else { + pr_info("%s drop the packet, packet type: %02x, len: %d\n", __func__, type, buf_len); + } + kfree_skb(skb); + skb = NULL; + goto exit; + } + btmtk_usb_dispatch_data_bluetooth_kpi(&rxbuf[MTK_SDIO_PACKET_HEADER_SIZE], buf_len + 1, 0); + + fops_skb = bt_skb_alloc(buf_len, GFP_ATOMIC); + if (fops_skb == NULL) { + pr_err("No memory for fops_skb\n"); + ret = -ENOMEM; + goto exit; + } + bt_cb(fops_skb)->pkt_type = type; + memcpy(fops_skb->data, skb->data, buf_len); + + skb_hci = bt_skb_alloc(buf_len, GFP_KERNEL); + skb_put(skb_hci, buf_len); + memcpy(skb_hci->data, fops_skb->data, buf_len); +#if KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE + bt_cb((skb_hci))->pkt_type = type; +#else + hci_skb_pkt_type(skb_hci) = type; +#endif + ret = hci_recv_frame(hdev, skb_hci); + if (ret < 0) + printk(KERN_ERR "XXX: error recv frame: %d\n", ret); + + fops_skb->len = buf_len; + LOCK_UNSLEEPABLE_LOCK(&(metabuffer.spin_lock)); + skb_queue_tail(&g_priv->adapter->fops_queue, fops_skb); + if (skb_queue_empty(&g_priv->adapter->fops_queue)) + pr_info("%s fops_queue is empty\n", __func__); + UNLOCK_UNSLEEPABLE_LOCK(&(metabuffer.spin_lock)); + + kfree_skb(skb); + skb = NULL; + + wake_up_interruptible(&inq); + goto exit; + } else { + kfree_skb(skb); + skb = NULL; + } + +exit: + if (ret) { + pr_debug("%s fail free skb\n", __func__); + if (skb) { + kfree_skb(skb); + skb = NULL; + } + } + + buf_len += 1; + if (buf_len % 4) + fourbalignment_len = buf_len + 4 - (buf_len % 4); + else + fourbalignment_len = buf_len; + + rx_length -= fourbalignment_len; + + if (rx_length > (MTK_SDIO_PACKET_HEADER_SIZE)) { + memcpy(&rxbuf[MTK_SDIO_PACKET_HEADER_SIZE], + &rxbuf[MTK_SDIO_PACKET_HEADER_SIZE + fourbalignment_len], + rx_length - MTK_SDIO_PACKET_HEADER_SIZE); + } + + pr_debug("%s ret %d, rx_length, %d,fourbalignment_len %d <--\n", + __func__, ret, rx_length, fourbalignment_len); + + return ret; + +data_err: + pr_err("%s, data error!!! discard rxbuf:\n", __func__); + BTSDIO_INFO_RAW(rxbuf, rx_length, "rxbuf"); + rx_length = MTK_SDIO_PACKET_HEADER_SIZE; + return -EINVAL; + +} + +static int btmtk_sdio_process_int_status( + struct btmtk_private *priv) +{ + int ret = 0; + u32 u32rxdatacount = 0; + u32 u32ReadCRValue = 0; + + ret = btmtk_sdio_readl(CHISR, &u32ReadCRValue); + pr_debug("%s CHISR 0x%08x\n", __func__, u32ReadCRValue); + if (u32ReadCRValue & FIRMWARE_INT_BIT15) { + btmtk_sdio_set_no_fw_own(g_priv, TRUE); + btmtk_sdio_writel(CHISR, FIRMWARE_INT_BIT15); + } + + pr_debug("%s check TX_EMPTY CHISR 0x%08x\n", __func__, u32ReadCRValue); + if (TX_EMPTY&u32ReadCRValue) { + ret = btmtk_sdio_writel(CHISR, (TX_EMPTY | TX_COMPLETE_COUNT)); + priv->btmtk_dev.tx_dnld_rdy = true; + pr_debug("%s set tx_dnld_rdy 1\n", __func__); + } + + if (RX_DONE&u32ReadCRValue) + ret = btmtk_sdio_recv_rx_data(); + + if (ret == 0) { + while (rx_length > (MTK_SDIO_PACKET_HEADER_SIZE)) { + btmtk_sdio_card_to_host(priv, NULL, -1, 0); + u32rxdatacount++; + pr_debug("%s u32rxdatacount %d, rx_length %d\n", + __func__, u32rxdatacount, rx_length); + } + } + + ret = btmtk_sdio_enable_interrupt(1); + + return ret; +} + +static void btmtk_sdio_interrupt(struct sdio_func *func) +{ + struct btmtk_private *priv; + struct btmtk_sdio_card *card; + + card = sdio_get_drvdata(func); + + if (!card) + return; + + + if (!card->priv) + return; + + priv = card->priv; + btmtk_sdio_enable_interrupt(0); + + btmtk_interrupt(priv); +} + +static int btmtk_sdio_register_dev(struct btmtk_sdio_card *card) +{ + struct sdio_func *func; + u32 u32ReadCRValue = 0; + u8 reg; + int ret = 0; + + if (!card || !card->func) { + pr_err("Error: card or function is NULL!\n"); + ret = -EINVAL; + goto failed; + } + + func = card->func; + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret) { + pr_err("sdio_enable_func() failed: ret=%d\n", ret); + ret = -EIO; + goto release_host; + } + + btmtk_sdio_readb(SDIO_CCCR_IENx, &u32ReadCRValue); + pr_info("before claim irq read SDIO_CCCR_IENx %x, func num %d\n", + u32ReadCRValue, func->num); + + ret = sdio_claim_irq(func, btmtk_sdio_interrupt); + if (ret) { + pr_err("sdio_claim_irq failed: ret=%d\n", ret); + ret = -EIO; + goto disable_func; + } + pr_info("sdio_claim_irq success: ret=%d\n", ret); + + btmtk_sdio_readb(SDIO_CCCR_IENx, &u32ReadCRValue); + pr_info("after claim irq read SDIO_CCCR_IENx %x\n", u32ReadCRValue); + + ret = sdio_set_block_size(card->func, SDIO_BLOCK_SIZE); + if (ret) { + pr_err("cannot set SDIO block size\n"); + ret = -EIO; + goto release_irq; + } + + reg = sdio_readb(func, card->reg->io_port_0, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + + card->ioport = reg; + + reg = sdio_readb(func, card->reg->io_port_1, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + + card->ioport |= (reg << 8); + + reg = sdio_readb(func, card->reg->io_port_2, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + + card->ioport |= (reg << 16); + + pr_info("SDIO FUNC%d IO port: 0x%x\n", func->num, card->ioport); + + if (card->reg->int_read_to_clear) { + reg = sdio_readb(func, card->reg->host_int_rsr, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + sdio_writeb(func, reg | 0x3f, card->reg->host_int_rsr, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + + reg = sdio_readb(func, card->reg->card_misc_cfg, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + sdio_writeb(func, reg | 0x10, card->reg->card_misc_cfg, &ret); + if (ret < 0) { + ret = -EIO; + goto release_irq; + } + } + + sdio_set_drvdata(func, card); + + sdio_release_host(func); + + return 0; + +release_irq: + sdio_release_irq(func); + +disable_func: + sdio_disable_func(func); + +release_host: + sdio_release_host(func); + +failed: + pr_info("%s fail\n", __func__); + return ret; +} + +static int btmtk_sdio_unregister_dev(struct btmtk_sdio_card *card) +{ + if (card && card->func) { + sdio_claim_host(card->func); + sdio_release_irq(card->func); + sdio_disable_func(card->func); + sdio_release_host(card->func); + sdio_set_drvdata(card->func, NULL); + } + + return 0; +} + +static int btmtk_sdio_enable_host_int(struct btmtk_sdio_card *card) +{ + int ret; + u32 read_data = 0; + + if (!card || !card->func) + return -EINVAL; + + sdio_claim_host(card->func); + + ret = btmtk_sdio_enable_host_int_mask(card, HIM_ENABLE); + + btmtk_sdio_get_rx_unit(card); + + if (0) { + typedef int (*fp_sdio_hook)(struct mmc_host *host, + unsigned int width); + fp_sdio_hook func_sdio_hook = + (fp_sdio_hook)kallsyms_lookup_name("mmc_set_bus_width"); + unsigned char data = 0; + + data = sdio_f0_readb(card->func, SDIO_CCCR_IF, &ret); + if (ret) + pr_info("%s sdio_f0_readb ret %d\n", __func__, ret); + + pr_info("%s sdio_f0_readb data 0x%X!\n", __func__, data); + + data &= ~SDIO_BUS_WIDTH_MASK; + data |= SDIO_BUS_ASYNC_INT; + card->func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + + sdio_f0_writeb(card->func, data, SDIO_CCCR_IF, &ret); + if (ret) + pr_info("%s sdio_f0_writeb ret %d\n", __func__, ret); + + pr_info("%s func_sdio_hook at 0x%p!\n", + __func__, func_sdio_hook); + if (func_sdio_hook) + func_sdio_hook(card->func->card->host, MMC_BUS_WIDTH_1); + + data = sdio_f0_readb(card->func, SDIO_CCCR_IF, &ret); + if (ret) + pr_info("%s sdio_f0_readb 2 ret %d\n", + __func__, ret); + + pr_info("%s sdio_f0_readb2 data 0x%X\n", __func__, data); + } + + sdio_release_host(card->func); + +/* workaround for some platform no host clock sometimes */ + + btmtk_sdio_readl(CSDIOCSR, &read_data); + pr_info("%s read CSDIOCSR is 0x%X\n", __func__, read_data); + read_data |= 0x4; + btmtk_sdio_writel(CSDIOCSR, read_data); + pr_info("%s write CSDIOCSR is 0x%X\n", __func__, read_data); + + return ret; +} + +static int btmtk_sdio_disable_host_int(struct btmtk_sdio_card *card) +{ + int ret; + + if (!card || !card->func) + return -EINVAL; + + sdio_claim_host(card->func); + + ret = btmtk_sdio_disable_host_int_mask(card, HIM_DISABLE); + + sdio_release_host(card->func); + + return ret; +} + +static int btmtk_sdio_download_fw(struct btmtk_sdio_card *card) +{ + int ret = 0; + + pr_info("%s begin\n", __func__); + if (!card || !card->func) { + pr_err("card or function is NULL!\n"); + return -EINVAL; + } + + sdio_claim_host(card->func); + + if (btmtk_sdio_download_rom_patch(card)) { + pr_err("Failed to download firmware!\n"); + ret = -EIO; + } + sdio_release_host(card->func); + + /** + * winner or not, with this test the FW synchronizes + * when the module can continue its initialization. + */ + return ret; +} + +static int btmtk_sdio_push_data_to_metabuffer( + struct ring_buffer *metabuffer, + char *data, + int len, + u8 type, + bool use_type) +{ + int remainLen = 0; + + if (metabuffer->write_p >= metabuffer->read_p) + remainLen = metabuffer->write_p - metabuffer->read_p; + else + remainLen = META_BUFFER_SIZE - + (metabuffer->read_p - metabuffer->write_p); + + if ((remainLen + 1 + len) >= META_BUFFER_SIZE) { + pr_warn("%s copy copyLen %d > META_BUFFER_SIZE(%d), push back to queue\n", + __func__, + (remainLen + 1 + len), + META_BUFFER_SIZE); + return -1; + } + + if (use_type) { + metabuffer->buffer[metabuffer->write_p] = type; + metabuffer->write_p++; + } + if (metabuffer->write_p >= META_BUFFER_SIZE) + metabuffer->write_p = 0; + + if (metabuffer->write_p + len <= META_BUFFER_SIZE) + memcpy(&metabuffer->buffer[metabuffer->write_p], + data, + len); + else { + memcpy(&metabuffer->buffer[metabuffer->write_p], + data, + META_BUFFER_SIZE - metabuffer->write_p); + memcpy(metabuffer->buffer, + &data[META_BUFFER_SIZE - metabuffer->write_p], + len - (META_BUFFER_SIZE - metabuffer->write_p)); + } + + metabuffer->write_p += len; + if (metabuffer->write_p >= META_BUFFER_SIZE) + metabuffer->write_p -= META_BUFFER_SIZE; + + remainLen += (1 + len); + return 0; +} + +static int btmtk_sdio_pull_data_from_metabuffer( + struct ring_buffer *metabuffer, + char __user *buf, + size_t count) +{ + int copyLen = 0; + unsigned long ret = 0; + + if (metabuffer->write_p >= metabuffer->read_p) + copyLen = metabuffer->write_p - metabuffer->read_p; + else + copyLen = META_BUFFER_SIZE - + (metabuffer->read_p - metabuffer->write_p); + + if (copyLen > count) + copyLen = count; + + if (metabuffer->read_p + copyLen <= META_BUFFER_SIZE) + ret = copy_to_user(buf, + &metabuffer->buffer[metabuffer->read_p], + copyLen); + else { + ret = copy_to_user(buf, + &metabuffer->buffer[metabuffer->read_p], + META_BUFFER_SIZE - metabuffer->read_p); + if (!ret) + ret = copy_to_user( + &buf[META_BUFFER_SIZE - metabuffer->read_p], + metabuffer->buffer, + copyLen - (META_BUFFER_SIZE-metabuffer->read_p)); + } + + if (ret) + pr_warn("%s copy to user fail, ret %d\n", __func__, (int)ret); + + metabuffer->read_p += (copyLen - ret); + if (metabuffer->read_p >= META_BUFFER_SIZE) + metabuffer->read_p -= META_BUFFER_SIZE; + + return (copyLen - ret); +} + +static int btmtk_sdio_reset_dev(struct btmtk_sdio_card *card) +{ + struct sdio_func *func; + u8 reg; + int ret = 0; + + if (!card || !card->func) + pr_err("Error: card or function is NULL!\n"); + + func = card->func; + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret) + pr_err("sdio_enable_func() failed: ret=%d\n", ret); + + reg = sdio_f0_readb(func, SDIO_CCCR_IENx, &ret); + if (ret) + pr_err("f0 read SDIO_CCCR_IENx %x, func num %d, ret %d\n", + reg, func->num, ret); + + ret = sdio_claim_irq(func, btmtk_sdio_interrupt); + pr_info("%s: sdio_claim_irq return %d\n", __func__, ret); + + reg |= 1 << func->num; + reg |= 1; + + /* for bt driver can write SDIO_CCCR_IENx */ + func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + sdio_f0_writeb(func, reg, SDIO_CCCR_IENx, &ret); + pr_info("f0 write ret %d SDIO_CCCR_IENx %x, func num %d\n", + ret, reg, func->num); + + reg = sdio_f0_readb(func, SDIO_CCCR_IENx, &ret); + pr_info("f0 read SDIO_CCCR_IENx %x, func num %d, ret %d\n", + reg, func->num, ret); + + ret = sdio_set_block_size(card->func, SDIO_BLOCK_SIZE); + if (ret) + pr_err("cannot set SDIO block size\n"); + pr_err("after set block size\n"); + + reg = sdio_readb(func, card->reg->io_port_0, &ret); + if (ret < 0) + pr_err("read io port0 fail\n"); + + card->ioport = reg; + + reg = sdio_readb(func, card->reg->io_port_1, &ret); + if (ret < 0) + pr_err("read io port1 fail\n"); + + card->ioport |= (reg << 8); + + reg = sdio_readb(func, card->reg->io_port_2, &ret); + if (ret < 0) + pr_err("read io port2 fail\n"); + + card->ioport |= (reg << 16); + + pr_info("SDIO FUNC%d IO port: 0x%x\n", func->num, card->ioport); + + if (card->reg->int_read_to_clear) { + reg = sdio_readb(func, card->reg->host_int_rsr, &ret); + if (ret < 0) + pr_err("read init rsr fail\n"); + sdio_writeb(func, reg | 0x3f, card->reg->host_int_rsr, &ret); + if (ret < 0) + pr_err("write init rsr fail\n"); + + reg = sdio_readb(func, card->reg->card_misc_cfg, &ret); + if (ret < 0) + pr_err("read misc cfg fail\n"); + sdio_writeb(func, reg | 0x10, card->reg->card_misc_cfg, &ret); + if (ret < 0) + pr_err("write misc cfg fail\n"); + } + + sdio_set_drvdata(func, card); + + sdio_release_host(func); + + return 0; +} + +static int btmtk_sdio_reset_fw(struct btmtk_sdio_card *card) +{ + int ret = 0; + + pr_info("%s Mediatek Bluetooth driver Version=%s\n", + __func__, VERSION); + +#if SUPPORT_EINT + btmtk_sdio_RegisterBTIrq(card); + btmtk_sdio_woble_input_init(card); +#endif + pr_debug("%s func device %X\n", __func__, card->func->device); + pr_debug("%s Call btmtk_sdio_register_dev\n", __func__); + btmtk_sdio_reset_dev(card); + + pr_debug("%s btmtk_sdio_register_dev success\n", __func__); + btmtk_sdio_enable_host_int(card); + if (btmtk_sdio_download_fw(card)) { + pr_err("%s Downloading firmware failed!\n", __func__); + ret = -ENODEV; + } + + return ret; +} + +static int btmtk_sdio_set_card_clkpd(int on) +{ + int ret = -1; + /* call sdio_set_card_clkpd in sdio host driver */ + typedef void (*psdio_set_card_clkpd) (int on, struct sdio_func *func); + char *sdio_set_card_clkpd_func_name = "sdio_set_card_clkpd"; + psdio_set_card_clkpd psdio_set_card_clkpd_func = + (psdio_set_card_clkpd)kallsyms_lookup_name(sdio_set_card_clkpd_func_name); + + if (!g_card) { + pr_err("%s: g_card is NULL\n", __func__); + return ret; + } + if (psdio_set_card_clkpd_func) { + pr_info("%s: get %s\n", __func__, + sdio_set_card_clkpd_func_name); + psdio_set_card_clkpd_func(on, g_card->func); + ret = 0; + } else + pr_err("%s: do not get %s\n", __func__, sdio_set_card_clkpd_func_name); + return ret; +} + + +/*toggle PMU enable*/ +static int btmtk_sdio_toggle_rst_pin(void) +{ + uint32_t pmu_en_delay = MT76x8_PMU_EN_DEFAULT_DELAY; + int pmu_en; + struct device *prDev; + + if (g_card == NULL) { + pr_err("g_card is NULL return\n"); + return -1; + } + sdio_claim_host(g_card->func); + btmtk_sdio_set_card_clkpd(0); + sdio_release_host(g_card->func); + prDev = mmc_dev(g_card->func->card->host); + if (!prDev) { + pr_err("unable to get struct dev for BT\n"); + return -1; + } + pmu_en = of_get_named_gpio(prDev->of_node, MT76x8_PMU_EN_PIN_NAME, 0); + pr_info("%s pmu_en %d\n", __func__, pmu_en); + if (gpio_is_valid(pmu_en)) { + gpio_direction_output(pmu_en, 0); + mdelay(pmu_en_delay); + gpio_direction_output(pmu_en, 1); + pr_info("%s: %s pull low/high done\n", __func__, + MT76x8_PMU_EN_PIN_NAME); + } else { + pr_err("%s: *** Invalid GPIO %s ***\n", __func__, + MT76x8_PMU_EN_PIN_NAME); + return -1; + } + return 0; +} + +int btmtk_sdio_notify_wlan_remove_end(void) +{ + pr_info("%s begin\n", __func__); + wlan_remove_done = 1; + btmtk_sdio_stop_wait_wlan_remove_tsk(); + + pr_info("%s done\n", __func__); + return 0; +} +EXPORT_SYMBOL(btmtk_sdio_notify_wlan_remove_end); + +int btmtk_sdio_bt_trigger_core_dump(int trigger_dump) +{ + struct sk_buff *skb = NULL; + u8 coredump_cmd[] = {0x6F, 0xFC, 0x05, 0x00, 0x01, 0x02, 0x01, 0x00, 0x08}; + + if (g_priv == NULL) { + pr_err("%s g_priv is NULL return\n", __func__); + return 0; + } + + if (wait_dump_complete_tsk) { + pr_warn("%s wait_dump_complete_tsk is working, return\n", __func__); + return 0; + } + + if (wait_wlan_remove_tsk) { + pr_warn("%s wait_wlan_remove_tsk is working, return\n", __func__); + return 0; + } + + if (g_priv->btmtk_dev.reset_dongle) { + pr_warn("%s reset_dongle is true, return\n", __func__); + return 0; + } + + if (!probe_ready) { + pr_info("%s probe_ready %d, return -1\n", __func__, probe_ready); + return -1;/*BT driver is not ready, ask wifi do coredump*/ + } + + pr_info("%s: trigger_dump %d\n", __func__, trigger_dump); + if (trigger_dump) { + skb = bt_skb_alloc(sizeof(coredump_cmd), GFP_ATOMIC); + if (skb == NULL) { + pr_err("No memory for skb\n"); + return -ENOMEM; + } + bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; + memcpy(&skb->data[0], &coredump_cmd[0], sizeof(coredump_cmd)); + skb->len = sizeof(coredump_cmd); + skb_queue_tail(&g_priv->adapter->tx_queue, skb); + wake_up_interruptible(&g_priv->main_thread.wait_q); + } else { + wait_wlan_remove_tsk = kthread_run(btmtk_sdio_wait_wlan_remove_thread, + NULL, "btmtk_sdio_wait_dump_complete_thread"); + + btmtk_sdio_notify_wlan_remove_start(); + } + + return 0; +} +EXPORT_SYMBOL(btmtk_sdio_bt_trigger_core_dump); + +void btmtk_sdio_notify_wlan_toggle_rst_end(void) +{ + typedef void (*pnotify_wlan_toggle_rst_end) (int reserved); + char *notify_wlan_toggle_rst_end_func_name = "notify_wlan_toggle_rst_end"; + /*void notify_wlan_toggle_rst_end(void)*/ + pnotify_wlan_toggle_rst_end pnotify_wlan_toggle_rst_end_func = + (pnotify_wlan_toggle_rst_end) kallsyms_lookup_name(notify_wlan_toggle_rst_end_func_name); + + if (pnotify_wlan_toggle_rst_end_func) { + pr_info("%s: do notify %s\n", __func__, notify_wlan_toggle_rst_end_func_name); + pnotify_wlan_toggle_rst_end_func(1); + } else + pr_err("%s: do not get %s\n", __func__, notify_wlan_toggle_rst_end_func_name); +} + +int btmtk_sdio_reset_dongle(void) +{ + int ret = 0; + int retry = 3; + + pr_info("%s: begin\n", __func__); + if (g_priv == NULL) { + pr_info("%s: g_priv = NULL, return\n", __func__); + return -1; + } + + if (need_reset_stack == HW_ERR_NONE) + need_reset_stack = HW_ERR_CODE_CHIP_RESET; + wlan_remove_done = 0; + +retry_reset: + retry--; + if (retry < 0) { + pr_err("%s retry overtime fail\n", __func__); + goto rst_dongle_err; + } + pr_info("%s run %d\n", __func__, retry); + ret = 0; + if (btmtk_sdio_toggle_rst_pin()) { + ret = -1; + goto rst_dongle_err; + } + + btmtk_sdio_set_no_fw_own(g_priv, FALSE); + msleep(100); + sdio_claim_host(g_card->func); + ret = sdio_reset_comm(g_card->func->card); + sdio_release_host(g_card->func); + if (ret) { + pr_warn("%s: sdio_reset_comm error %d\n", __func__, ret); + goto retry_reset; + } + pr_warn("%s: sdio_reset_comm done\n", __func__); + msleep(100); + ret = btmtk_sdio_reset_fw(g_card); + if (ret) { + pr_info("%s reset fw fail\n", __func__); + goto retry_reset; + } + else + pr_info("%s reset fw done\n", __func__); + +rst_dongle_err: + btmtk_sdio_notify_wlan_toggle_rst_end(); + + if (g_priv) { + g_priv->btmtk_dev.tx_dnld_rdy = 1; + g_priv->btmtk_dev.reset_dongle = 0; + } else + pr_err("%s g_priv is NULL no set tx_dnld_rdy = 1\n", __func__); + + wlan_status = WLAN_STATUS_DEFAULT; + btmtk_clean_queue(); + g_priv->btmtk_dev.reset_progress = 0; + print_dump_data_counter = 0; + fw_is_doing_coredump = false; + pr_info("%s return ret = %d\n", __func__, ret); + return ret; +} + +#if SUPPORT_EINT +static irqreturn_t btmtk_sdio_woble_isr(int irq, void *dev) +{ + struct btmtk_sdio_card *data = (struct btmtk_sdio_card *)dev; + unsigned long wait_powerkey_time = 0; + + pr_info("%s begin\n", __func__); + disable_irq_nosync(data->wobt_irq); + atomic_dec(&(data->irq_enable_count)); + pr_info("%s:disable BT IRQ\n", __func__); + pr_info("%s:call wake lock\n", __func__); + wait_powerkey_time = msecs_to_jiffies(WAIT_POWERKEY_TIMEOUT); + wake_lock_timeout(&data->eint_wlock, wait_powerkey_time);/*10s*/ + pr_info("%s end\n", __func__); + return IRQ_HANDLED; +} + +static int btmtk_sdio_RegisterBTIrq(struct btmtk_sdio_card *data) +{ + struct device_node *eint_node = NULL; + int interrupts[2]; + + eint_node = of_find_compatible_node(NULL, NULL, "mediatek,mt7668_bt_ctrl"); + pr_info("%s begin\n", __func__); + if (eint_node) { + pr_info("%s Get mt76xx_bt_ctrl compatible node\n", __func__); + data->wobt_irq = irq_of_parse_and_map(eint_node, 0); + pr_info("%s wobt_irq number:%d", __func__, data->wobt_irq); + if (data->wobt_irq) { + of_property_read_u32_array(eint_node, "interrupts", + interrupts, ARRAY_SIZE(interrupts)); + data->wobt_irqlevel = interrupts[1]; + if (request_irq(data->wobt_irq, btmtk_sdio_woble_isr, + data->wobt_irqlevel, "mt7668_bt_ctrl-eint", data)) + pr_info("%s WOBTIRQ LINE NOT AVAILABLE!!\n", __func__); + else { + pr_info("%s disable BT IRQ\n", __func__); + disable_irq_nosync(data->wobt_irq); + } + + } else + pr_info("%s can't find mt76xx_bt_ctrl irq\n", __func__); + + } else { + data->wobt_irq = 0; + pr_info("%s can't find mt76xx_bt_ctrl compatible node\n", __func__); + } + + + pr_info("btmtk:%s: end\n", __func__); + return 0; +} +#endif + +static int btsdio_open(struct hci_dev *hdev) +{ + return 0; +} +static int btsdio_close(struct hci_dev *hdev) +{ + return 0; +} +static int btsdio_flush(struct hci_dev *hdev) +{ + return 0; +} +static int btsdio_send_frame(struct hci_dev *hdev, struct sk_buff *skb) +{ + skb_queue_tail(&g_priv->adapter->tx_queue, skb); + wake_up_interruptible(&g_priv->main_thread.wait_q); + return 0; +} + +static int btmtk_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int ret = 0; + struct btmtk_private *priv = NULL; + struct btmtk_sdio_card *card = NULL; + struct btmtk_sdio_device *data = (void *) id->driver_data; + u32 u32ReadCRValue = 0; + u8 fw_download_fail = 0; + + probe_counter++; + pr_info("%s Mediatek Bluetooth driver Version=%s\n", + __func__, VERSION); + pr_info("vendor=0x%x, device=0x%x, class=%d, fn=%d, support func_num %d\n", + id->vendor, id->device, id->class, + func->num, data->reg->func_num); + + if (func->num != data->reg->func_num) { + pr_info("func num is not match\n"); + return -ENODEV; + } + + card = devm_kzalloc(&func->dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->func = func; + g_card = card; + +#if SUPPORT_EINT + btmtk_sdio_RegisterBTIrq(card); +#endif + + if (id->driver_data) { + card->helper = data->helper; + card->firmware = data->firmware; + card->firmware1 = data->firmware1; + card->reg = data->reg; + card->sd_blksz_fw_dl = data->sd_blksz_fw_dl; + card->support_pscan_win_report = data->support_pscan_win_report; + card->supports_fw_dump = data->supports_fw_dump; + card->chip_id = data->reg->chip_id; + card->suspend_count = 0; + pr_info("%s chip_id is %x\n", __func__, data->reg->chip_id); + /*allocate memory for woble_setting_file*/ + g_card->woble_setting_file_name = kzalloc(MAX_BIN_FILE_NAME_LEN, GFP_KERNEL); + if (!g_card->woble_setting_file_name) + return -1; + + memcpy(g_card->woble_setting_file_name, + WOBLE_SETTING_FILE_NAME, + sizeof(WOBLE_SETTING_FILE_NAME)); + } + + pr_debug("%s func device %X\n", __func__, card->func->device); + pr_debug("%s Call btmtk_sdio_register_dev\n", __func__); + if (btmtk_sdio_register_dev(card) < 0) { + pr_err("Failed to register BT device!\n"); + return -ENODEV; + } + + pr_debug("%s btmtk_sdio_register_dev success\n", __func__); + + /* Disable the interrupts on the card */ + btmtk_sdio_enable_host_int(card); + pr_debug("call btmtk_sdio_enable_host_int done\n"); + if (btmtk_sdio_download_fw(card)) { + pr_err("Downloading firmware failed!\n"); + fw_download_fail = 1; + } + + btmtk_sdio_set_i2s(); + /* Move from btmtk_fops_open() */ + spin_lock_init(&(metabuffer.spin_lock.lock)); + spin_lock_init(&(fwlog_metabuffer.spin_lock.lock)); + pr_debug("%s spin_lock_init end\n", __func__); + + priv = btmtk_add_card(card); + if (!priv) { + pr_err("Initializing card failed!\n"); + ret = -ENODEV; + goto unreg_dev; + } + pr_debug("btmtk_add_card success\n"); + card->priv = priv; + pr_debug("assign priv done\n"); + /* Initialize the interface specific function pointers */ + priv->hw_host_to_card = btmtk_sdio_host_to_card; + priv->hw_process_int_status = btmtk_sdio_process_int_status; + priv->hw_set_own_back = btmtk_sdio_set_own_back; + priv->hw_sdio_reset_dongle = btmtk_sdio_reset_dongle; + priv->start_reset_dongle_progress = btmtk_sdio_start_reset_dongle_progress; + g_priv = priv; + + memset(&metabuffer.buffer, 0, META_BUFFER_SIZE); + +#if SAVE_FW_DUMP_IN_KERNEL + fw_dump_file = NULL; +#endif + + ret = btmtk_sdio_readl(CHLPCR, &u32ReadCRValue); + pr_debug("%s read CHLPCR (0x%08X)\n", __func__, u32ReadCRValue); + pr_debug("%s chipid is (0x%X)\n", __func__, g_card->chip_id); + if (is_support_unify_woble(g_card)) { + memset(g_card->bdaddr, 0, BD_ADDRESS_SIZE); + btmtk_sdio_load_woble_setting(g_card->woble_setting, + g_card->woble_setting_file_name, + &g_card->func->dev, + &g_card->woble_setting_len, + g_card); + } + +#if (SUPPORT_UNIFY_WOBLE & SUPPORT_ANDROID) + wake_lock_init(&g_card->woble_wlock, WAKE_LOCK_SUSPEND, "btevent_woble"); +#endif + +#if SUPPORT_EINT + wake_lock_init(&g_card->eint_wlock, WAKE_LOCK_SUSPEND, "btevent_eint"); +#endif + + hdev = hci_alloc_dev(); + if (!hdev) + return -ENOMEM; + hdev->bus = HCI_SDIO; + if (id->class == SDIO_CLASS_BT_AMP) { + //hdev->dev_type = HCI_AMP; + } else { +#if KERNEL_VERSION(4, 8, 0) > LINUX_VERSION_CODE + hdev->dev_type = HCI_BREDR; +#else + //hdev->dev_type = HCI_PRIMARY; +#endif + } + SET_HCIDEV_DEV(hdev, &func->dev); + hdev->open = btsdio_open; + hdev->close = btsdio_close; + hdev->flush = btsdio_flush; + hdev->send = btsdio_send_frame; + ret = hci_register_dev(hdev); + if (ret < 0) { + pr_err("XXX: Failed to register HCI: %d\n", ret); + hci_free_dev(hdev); + return ret; + } + + pr_info("%s normal end\n", __func__); + probe_ready = true; + if (fw_download_fail) + btmtk_sdio_start_reset_dongle_progress(); + + return 0; + +unreg_dev: + btmtk_sdio_unregister_dev(card); + + pr_err("%s fail end\n", __func__); + return ret; +} + +/* The btmtk_sdio_remove() callback function is called + * when user removes this module from kernel space or ejects + * the card from the slot. The driver handles these 2 cases + * differently. + * If the user is removing the module, a MODULE_SHUTDOWN_REQ + * command is sent to firmware and interrupt will be disabled. + * If the card is removed, there is no need to send command + * or disable interrupt. + * + * The variable 'user_rmmod' is used to distinguish these two + * scenarios. This flag is initialized as FALSE in case the card + * is removed, and will be set to TRUE for module removal when + * module_exit function is called. + */ +static void btmtk_sdio_remove(struct sdio_func *func) +{ + struct btmtk_sdio_card *card; + + pr_info("%s begin user_rmmod %d\n", __func__, user_rmmod); + probe_ready = false; + + hci_unregister_dev(hdev); + hci_free_dev(hdev); + + btmtk_sdio_set_no_fw_own(g_priv, FALSE); + if (func) { + card = sdio_get_drvdata(func); + if (card) { + /* Send SHUTDOWN command & disable interrupt + * if user removes the module. + */ + if (user_rmmod) { + pr_info("%s begin user_rmmod %d in user mode\n", + __func__, user_rmmod); + btmtk_sdio_set_own_back(DRIVER_OWN); + btmtk_sdio_enable_interrupt(0); + btmtk_sdio_bt_set_power(0); + btmtk_sdio_set_own_back(FW_OWN); + + btmtk_sdio_disable_host_int(card); + } + btmtk_sdio_woble_free_setting(); + pr_debug("unregester dev\n"); + card->priv->surprise_removed = true; + btmtk_sdio_unregister_dev(card); + btmtk_remove_card(card->priv); + if (need_reset_stack == HW_ERR_NONE) + need_reset_stack = HW_ERR_CODE_CARD_DISC; + } + } + pr_info("%s end\n", __func__); +} + +/* + * cmd_type: + * #define HCI_COMMAND_PKT 0x01 + * #define HCI_ACLDATA_PKT 0x02 + * #define HCI_SCODATA_PKT 0x03 + * #define HCI_EVENT_PKT 0x04 + * #define HCI_VENDOR_PKT 0xff + */ +static int btmtk_sdio_send_hci_cmd(u8 cmd_type, u8 *cmd, int cmd_len, + const u8 *event, const int event_len, + int total_timeout, bool wait_until) + /*cmd: if cmd is null, don't compare event, just return 0 if send cmd success*/ + /* total_timeout: -1 */ + /* add_spec_header:0 hci event, 1 use vend specic event header*/ + /* return 0 if compare successfully and no need to compare */ + /* return < 0 if error*/ + /*wait_until: 0:need compare with first event after cmd*/ + /*return value: 0 or positive success, -x fail*/ +{ + int ret = -1; + unsigned long comp_event_timo = 0, start_time = 0; + struct sk_buff *skb = NULL; + + if (cmd_len == 0) { + pr_err("%s cmd_len (%d) error return\n", __func__, cmd_len); + return -EINVAL; + } + + + skb = bt_skb_alloc(cmd_len, GFP_ATOMIC); + if (skb == NULL) { + pr_err("%s: No memory for skb\n", __func__); + return -ENOMEM; + } + bt_cb(skb)->pkt_type = cmd_type; + memcpy(&skb->data[0], cmd, cmd_len); + skb->len = cmd_len; + if (event) { + event_compare_status = BTMTK_SDIO_EVENT_COMPARE_STATE_NEED_COMPARE; + memcpy(event_need_compare, event, event_len); + event_need_compare_len = event_len; + } + skb_queue_tail(&g_priv->adapter->tx_queue, skb); + wake_up_interruptible(&g_priv->main_thread.wait_q); + + + if (event == NULL) + return 0; + + if (event_len > EVENT_COMPARE_SIZE) { + pr_err("%s event_len (%d) > EVENT_COMPARE_SIZE(%d), error\n", __func__, event_len, EVENT_COMPARE_SIZE); + return -1; + } + + start_time = jiffies; + /* check HCI event */ + comp_event_timo = jiffies + msecs_to_jiffies(total_timeout); + ret = -1; + pr_debug("%s event_need_compare_len %d\n", __func__, event_need_compare_len); + pr_debug("%s event_compare_status %d\n", __func__, event_compare_status); + do { + /* check if event_compare_success */ + if (event_compare_status == BTMTK_SDIO_EVENT_COMPARE_STATE_COMPARE_SUCCESS) { + pr_debug("%s compare success\n", __func__); + ret = 0; + break; + } + + msleep(100); + } while (time_before(jiffies, comp_event_timo)); + event_compare_status = BTMTK_SDIO_EVENT_COMPARE_STATE_NOTHING_NEED_COMPARE; + pr_debug("%s ret %d\n", __func__, ret); + return ret; +} + +static int btmtk_sdio_send_get_vendor_cap(void) +{ + int ret = -1; + u8 get_vendor_cap_cmd[] = { 0x53, 0xFD, 0x00 }; + u8 get_vendor_cap_event[] = { 0x0e, 0x12, 0x01, 0x53, 0xFD, 0x00}; + + pr_debug("%s: begin", __func__); + BTSDIO_DEBUG_RAW(get_vendor_cap_cmd, sizeof(get_vendor_cap_cmd), "%s: send vendor_cap_cmd is:", __func__); + ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, get_vendor_cap_cmd, sizeof(get_vendor_cap_cmd), + get_vendor_cap_event, sizeof(get_vendor_cap_event), + WOBLE_COMP_EVENT_TIMO, 1); + + pr_debug("%s: ret %d", __func__, ret); + return ret; +} + +static int btmtk_sdio_send_read_BDADDR_cmd(void) +{ + u8 cmd[] = { 0x09, 0x10, 0x00 }; + int ret = -1; + unsigned char zero[BD_ADDRESS_SIZE]; + + pr_debug("%s: begin", __func__); + if (g_card == NULL) { + pr_err("%s: g_card == NULL!", __func__); + return -1; + } + + memset(zero, 0, sizeof(zero)); + if (memcmp(g_card->bdaddr, zero, BD_ADDRESS_SIZE) != 0) { + pr_debug("%s: already got bdaddr %02x%02x%02x%02x%02x%02x, return 0", __func__, + g_card->bdaddr[0], g_card->bdaddr[1], g_card->bdaddr[2], + g_card->bdaddr[3], g_card->bdaddr[4], g_card->bdaddr[5]); + return 0; + } + BTSDIO_DEBUG_RAW(cmd, sizeof(cmd), "%s: send read bd address cmd is:", __func__); + ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, cmd, sizeof(cmd), + READ_ADDRESS_EVENT, sizeof(READ_ADDRESS_EVENT), WOBLE_COMP_EVENT_TIMO, 1); + /*BD address will get in btmtk_sdio_host_to_card*/ + pr_debug("%s: ret = %d", __func__, ret); + + return ret; +} + +static int btmtk_sdio_set_Woble_APCF_filter_parameter(void) +{ + int ret = -1; + u8 cmd[] = { 0x57, 0xfd, 0x0a, 0x01, 0x00, 0x5a, 0x20, 0x00, 0x20, 0x00, 0x01, 0x80, 0x00 }; + u8 event_complete[] = { 0x0e, 0x07, 0x01, 0x57, 0xfd, 0x00, 0x01/*, 00, 63*/ }; + + pr_debug("%s: begin", __func__); + ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, cmd, sizeof(cmd), + event_complete, sizeof(event_complete), + WOBLE_COMP_EVENT_TIMO, 1); + if (ret < 0) + pr_err("%s: end ret %d", __func__, ret); + else + ret = 0; + + pr_info("%s: end ret=%d", __func__, ret); + return ret; +} + + +/** + * Set APCF manufacturer data and filter parameter + */ +static int btmtk_sdio_set_Woble_APCF(void) +{ + int ret = -1; + int i = 0; + u8 manufactur_data[] = { 0x57, 0xfd, 0x27, 0x06, 0x00, 0x5a, + 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x43, 0x52, 0x4B, 0x54, 0x4D, + 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + u8 event_complete[] = { 0x0e, 0x07, 0x01, 0x57, 0xfd}; + + pr_debug("%s: begin", __func__); + if (!g_card) { + pr_info("%s: g_card is NULL, return -1", __func__); + return -1; + } + + pr_debug("%s: g_card->woble_setting_apcf[0].length %d", + __func__, g_card->woble_setting_apcf[0].length); + + /* start to send apcf cmd from woble setting file */ + if (g_card->woble_setting_apcf[0].length) { + for (i = 0; i < WOBLE_SETTING_COUNT; i++) { + if (!g_card->woble_setting_apcf[i].length) + continue; + + pr_info("%s: g_data->woble_setting_apcf_fill_mac[%d].content[0] = 0x%02x", + __func__, i, + g_card->woble_setting_apcf_fill_mac[i].content[0]); + pr_info("%s: g_data->woble_setting_apcf_fill_mac_location[%d].length = %d", + __func__, i, + g_card->woble_setting_apcf_fill_mac_location[i].length); + + if ((g_card->woble_setting_apcf_fill_mac[i].content[0] == 1) && + g_card->woble_setting_apcf_fill_mac_location[i].length) { + /* need add BD addr to apcf cmd */ + memcpy(g_card->woble_setting_apcf[i].content + + (*g_card->woble_setting_apcf_fill_mac_location[i].content), + g_card->bdaddr, BD_ADDRESS_SIZE); + pr_info("%s: apcf %d ,add mac to location %d", + __func__, i, + (*g_card->woble_setting_apcf_fill_mac_location[i].content)); + } + + pr_info("%s: send APCF %d", __func__, i); + BTSDIO_INFO_RAW(g_card->woble_setting_apcf[i].content, g_card->woble_setting_apcf[i].length, + "woble_setting_apcf"); + + ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, g_card->woble_setting_apcf[i].content, + g_card->woble_setting_apcf[i].length, + event_complete, sizeof(event_complete), WOBLE_COMP_EVENT_TIMO, 1); + + if (ret < 0) { + pr_err("%s: apcf %d error ret %d", __func__, i, ret); + return ret; + } + + } + } else { /* use default */ + pr_info("%s: use default manufactur data", __func__); + memcpy(manufactur_data + 9, g_card->bdaddr, BD_ADDRESS_SIZE); + BTSDIO_DEBUG_RAW(manufactur_data, sizeof(manufactur_data), + "send manufactur_data "); + + ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, manufactur_data, + sizeof(manufactur_data), + event_complete, sizeof(event_complete), WOBLE_COMP_EVENT_TIMO, 1); + if (ret < 0) { + pr_err("%s: manufactur_data error ret %d", __func__, ret); + return ret; + } + + ret = btmtk_sdio_set_Woble_APCF_filter_parameter(); + } + + pr_info("%s: end ret=%d", __func__, ret); + return ret; +} + + + +static int btmtk_sdio_send_woble_settings(struct woble_setting_struct *settings_cmd, + struct woble_setting_struct *settings_event, char *message) +{ + int ret = -1; + int i = 0; + + pr_info("%s: %s length %d", + __func__, message, settings_cmd->length); + if (g_card->woble_setting_radio_on[0].length) { + for (i = 0; i < WOBLE_SETTING_COUNT; i++) { + if (settings_cmd[i].length) { + pr_info("%s: send %s %d", __func__, message, i); + BTSDIO_INFO_RAW(settings_cmd[i].content, + settings_cmd[i].length, "Raw"); + + ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, settings_cmd[i].content, + settings_cmd[i].length, + settings_event[i].content, + settings_event[i].length, WOBLE_COMP_EVENT_TIMO, 1); + + if (ret) { + pr_err("%s: %s %d return error", + __func__, message, i); + return ret; + } + } + } + } + return ret; +} +static int btmtk_sdio_send_unify_woble_suspend_default_cmd(void) +{ + int ret = 0; /* if successful, 0 */ + u8 cmd[] = { 0xC9, 0xFC, 0x14, 0x01, 0x20, 0x02, 0x00, 0x01, + 0x02, 0x01, 0x00, 0x05, 0x10, 0x01, 0x00, 0x40, 0x06, + 0x02, 0x40, 0x5A, 0x02, 0x41, 0x0F }; + /*u8 status[] = { 0x0F, 0x04, 0x00, 0x01, 0xC9, 0xFC };*/ + u8 comp_event[] = { 0xE6, 0x02, 0x08, 0x00 }; + + pr_debug("%s: begin", __func__); + + ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, cmd, + sizeof(cmd), + comp_event, sizeof(comp_event), WOBLE_COMP_EVENT_TIMO, 1); + if (ret) + pr_err("%s: comp_event return error(%d)", __func__, ret); + + return ret; +} +/** + * Set APCF manufacturer data and filter parameter + */ +static int btmtk_sdio_set_Woble_radio_off(void) +{ + int ret = -1; + + pr_debug("%s: g_data->woble_setting_radio_off[0].length %d", + __func__, g_card->woble_setting_radio_off[0].length); + pr_debug("%s: g_card->woble_setting_radio_off_comp_event[0].length %d", + __func__, g_card->woble_setting_radio_off_comp_event[0].length); + + if (g_card->woble_setting_radio_off[0].length) { + if (g_card->woble_setting_radio_off_comp_event[0].length && + is_support_unify_woble(g_card)) { + ret = btmtk_sdio_send_woble_settings(g_card->woble_setting_radio_off, + g_card->woble_setting_radio_off_comp_event, "radio off"); + if (ret) { + pr_err("%s: radio off error", __func__); + return ret; + } + } else + pr_info("%s: woble_setting_radio_off length is %d", __func__, + g_card->woble_setting_radio_off[0].length); + } else {/* use default */ + pr_info("%s: use default radio off cmd", __func__); + ret = btmtk_sdio_send_unify_woble_suspend_default_cmd(); + } + + pr_info("%s: end ret=%d", __func__, ret); + return ret; +} + +static int btmtk_sdio_handle_entering_WoBLE_state(void) +{ + int ret = -1; + + pr_debug("%s: begin", __func__); + if (is_support_unify_woble(g_card)) { + ret = btmtk_sdio_send_get_vendor_cap(); + if (ret < 0) { + pr_err("%s: btmtk_sdio_send_get_vendor_cap return fail ret = %d", __func__, ret); + goto Finish; + } + + ret = btmtk_sdio_send_read_BDADDR_cmd(); + if (ret < 0) { + pr_err("%s: btmtk_sdio_send_read_BDADDR_cmd return fail ret = %d", __func__, ret); + goto Finish; + } + + ret = btmtk_sdio_set_Woble_APCF(); + if (ret < 0) { + pr_err("%s: btmtk_sdio_set_Woble_APCF return fail %d", __func__, ret); + goto Finish; + } + + ret = btmtk_sdio_set_Woble_radio_off(); + if (ret < 0) { + pr_err("%s: btmtk_sdio_set_Woble_radio_off return fail %d", __func__, ret); + goto Finish; + } + } + +Finish: + if (ret) + btmtk_sdio_woble_wake_lock(g_card); + + pr_info("%s: end", __func__); + return ret; +} + +static int btmtk_sdio_send_leave_woble_suspend_cmd(void) +{ + int ret = 0; /* if successful, 0 */ + u8 cmd[] = { 0xC9, 0xFC, 0x05, 0x01, 0x21, 0x02, 0x00, 0x00 }; + u8 comp_event[] = { 0xe6, 0x02, 0x08, 0x01 }; + + BTSDIO_DEBUG_RAW(cmd, sizeof(cmd), "cmd "); + ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, cmd, sizeof(cmd), + comp_event, sizeof(comp_event), WOBLE_COMP_EVENT_TIMO, 1); + + if (ret < 0) { + pr_err("%s: failed(%d)", __func__, ret); + } else { + pr_info("%s: OK", __func__); + ret = 0; + } + return ret; +} +static int btmtk_sdio_del_Woble_APCF_inde(void) +{ + int ret = -1; + u8 cmd[] = { 0x57, 0xfd, 0x03, 0x01, 0x01, 0x5a }; + u8 event[] = { 0x0e, 0x07, 0x01, 0x57, 0xfd, 0x00, 0x01, /* 00, 63 */ }; + + pr_debug("%s", __func__); + ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, cmd, sizeof(cmd), + event, sizeof(event), WOBLE_COMP_EVENT_TIMO, 1); + + if (ret < 0) + pr_err("%s: Got error %d", __func__, ret); + + pr_info("%s end ret = %d", __func__, ret); + return ret; +} + +static int btmtk_sdio_handle_leaving_WoBLE_state(void) +{ + int ret = -1; + + if (g_card == NULL) { + pr_err("%s: g_card is NULL return", __func__); + return 0; + } + + if (!is_support_unify_woble(g_card)) { + pr_err("%s: do nothing", __func__); + return 0; + } + + if (g_card->woble_setting_radio_on[0].length && + g_card->woble_setting_radio_on_comp_event[0].length && + g_card->woble_setting_apcf_resume[0].length && + g_card->woble_setting_apcf_resume_event[0].length) { + /* start to send radio off cmd from woble setting file */ + ret = btmtk_sdio_send_woble_settings(g_card->woble_setting_radio_on, + g_card->woble_setting_radio_on_comp_event, "radio on"); + if (ret) { + pr_err("%s: wradio on error", __func__); + return ret; + } + + ret = btmtk_sdio_send_woble_settings(g_card->woble_setting_apcf_resume, + g_card->woble_setting_apcf_resume_event, "apcf resume"); + if (ret) { + pr_err("%s: apcf resume error", __func__); + return ret; + } + + } else { /* use default */ + ret = btmtk_sdio_send_leave_woble_suspend_cmd(); + if (ret) { + pr_err("%s: radio on error", __func__); + return ret; + } + + ret = btmtk_sdio_del_Woble_APCF_inde(); + if (ret) { + pr_err("%s: del apcf index error", __func__); + return ret; + } + } + + if (ret) { + pr_err("%s: woble_setting_radio_on return error", __func__); + return ret; + } + + + + return ret; +} + +static int btmtk_sdio_send_apcf_reserved(void) +{ + int ret = -1; + /* 76x8 APCF Cmd formate: [Header(0xFC5C), Len, Groups of APCF (Max. reserved 10)] + * 76x3 APCF Cmd Formate: [Header(0xFC85), Len, Groups of APCF (Max. reserved 2)] + */ + if (g_card->func->device == 0x7668) { + u8 reserve_apcf_cmd_7668[] = { 0x5C, 0xFC, 0x01, 0x0A }; + u8 reserve_apcf_event_7668[] = { 0x0e, 0x06, 0x01, 0x5C, 0xFC, 0x00 }; + + ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, + reserve_apcf_cmd_7668, sizeof(reserve_apcf_cmd_7668), + reserve_apcf_event_7668, sizeof(reserve_apcf_event_7668), + WOBLE_COMP_EVENT_TIMO, 1); + } else if (g_card->func->device == 0x7663) { + u8 reserve_apcf_cmd_7663[] = { 0x85, 0xFC, 0x01, 0x02 }; + u8 reserve_apcf_event_7663[] = { 0x0e, 0x06, 0x01, 0x85, 0xFC, 0x00, 0x0A, 0x08}; + + ret = btmtk_sdio_send_hci_cmd(HCI_COMMAND_PKT, + reserve_apcf_cmd_7663, sizeof(reserve_apcf_cmd_7663), + reserve_apcf_event_7663, sizeof(reserve_apcf_event_7663), + WOBLE_COMP_EVENT_TIMO, 1); + } else + pr_warn("%s: not support for 0x%x\n", __func__, g_card->func->device); + + pr_info("%s: ret %d\n", __func__, ret); + return ret; +} + +static int btmtk_sdio_suspend(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + u8 ret = 0; + mmc_pm_flag_t pm_flags; + + pr_info("%s begin\n", __func__); + + if (g_card == NULL) { + pr_err("%s: g_card is NULL return", __func__); + return 0; + } + + if ((g_card->suspend_count++)) { + pr_warn("%s: Has suspended. suspend_count: %d", __func__, g_card->suspend_count); + pr_info("%s: end", __func__); + return 0; + } + pr_debug("%s start to send DRIVER_OWN\n", __func__); + ret = btmtk_sdio_set_own_back(DRIVER_OWN); + + if (ret) + pr_err("%s set driver own fail\n", __func__); + + if (!is_support_unify_woble(g_card)) + pr_warn("%s: no support", __func__); + else + btmtk_sdio_handle_entering_WoBLE_state(); + +#if SUPPORT_EINT + if (g_card->wobt_irq != 0 && atomic_read(&(g_card->irq_enable_count)) == 0) { + pr_info("%s:enable BT IRQ:%d\n", __func__, g_card->wobt_irq); + irq_set_irq_wake(g_card->wobt_irq, 1); + enable_irq(g_card->wobt_irq); + atomic_inc(&(g_card->irq_enable_count)); + } else + pr_info("%s:irq_enable count:%d\n", __func__, atomic_read(&(g_card->irq_enable_count))); +#endif + + + if (func) { + pm_flags = sdio_get_host_pm_caps(func); + pr_debug("%s: suspend: PM flags = 0x%x\n", + sdio_func_id(func), pm_flags); + if (!(pm_flags & MMC_PM_KEEP_POWER)) { + pr_err("%s: cannot remain alive while suspended\n", + sdio_func_id(func)); + return -EINVAL; + } + } else { + pr_err("sdio_func is not specified\n"); + return 0; + } + + ret = btmtk_sdio_set_own_back(FW_OWN); + if (ret) + pr_err("%s set fw own fail\n", __func__); + + return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); +} + +static int btmtk_sdio_resume(struct device *dev) +{ + u8 ret = 0; + + if (g_card == NULL) { + pr_err("%s: g_card is NULL return", __func__); + return 0; + } + + g_card->suspend_count--; + if (g_card->suspend_count) { + pr_info("%s: data->suspend_count %d, return 0", __func__, g_card->suspend_count); + return 0; + } +#if SUPPORT_EINT + if (g_card->wobt_irq != 0 && atomic_read(&(g_card->irq_enable_count)) == 1) { + pr_info("%s:disable BT IRQ:%d\n", __func__, g_card->wobt_irq); + atomic_dec(&(g_card->irq_enable_count)); + disable_irq_nosync(g_card->wobt_irq); + } else + pr_info("%s:irq_enable count:%d\n", __func__, atomic_read(&(g_card->irq_enable_count))); +#endif + ret = btmtk_sdio_handle_leaving_WoBLE_state(); + + if (ret) + pr_err("%s: btmtk_sdio_handle_leaving_WoBLE_state return fail %d", __func__, ret); + + pr_info("%s end\n", __func__); + return 0; +} + +static const struct dev_pm_ops btmtk_sdio_pm_ops = { + .suspend = btmtk_sdio_suspend, + .resume = btmtk_sdio_resume, +}; + +static struct sdio_driver bt_mtk_sdio = { + .name = "btmtk_sdio", + .id_table = btmtk_sdio_ids, + .probe = btmtk_sdio_probe, + .remove = btmtk_sdio_remove, + .drv = { + .owner = THIS_MODULE, + .pm = &btmtk_sdio_pm_ops, + } +}; + +static int btmtk_clean_queue(void) +{ + struct sk_buff *skb = NULL; + + LOCK_UNSLEEPABLE_LOCK(&(metabuffer.spin_lock)); + if (!skb_queue_empty(&g_priv->adapter->fops_queue)) { + pr_info("%s clean data in fops_queue\n", __func__); + do { + skb = skb_dequeue(&g_priv->adapter->fops_queue); + if (skb == NULL) { + pr_info("%s skb=NULL error break\n", __func__); + break; + } + + kfree_skb(skb); + } while (!skb_queue_empty(&g_priv->adapter->fops_queue)); + } + UNLOCK_UNSLEEPABLE_LOCK(&(metabuffer.spin_lock)); + return 0; +} + +static int btmtk_fops_open(struct inode *inode, struct file *file) +{ + pr_info("%s begin\n", __func__); + + if (!probe_ready) { + pr_err("%s probe_ready is %d return\n", + __func__, probe_ready); + return -EFAULT; + } + + metabuffer.read_p = 0; + metabuffer.write_p = 0; +#if 0 /* Move to btmtk_sdio_probe() */ + spin_lock_init(&(metabuffer.spin_lock.lock)); + pr_info("%s spin_lock_init end\n", __func__); +#endif + if (g_priv == NULL) { + pr_err("%s g_priv is NULL\n", __func__); + return -ENOENT; + } + + if (g_priv->adapter == NULL) { + pr_err("%s g_priv->adapter is NULL\n", __func__); + return -ENOENT; + } + + if (g_card) { + if (is_support_unify_woble(g_card)) + btmtk_sdio_send_apcf_reserved(); + } else + pr_err("%s g_card is NULL\n", __func__); + + btmtk_clean_queue(); + + if (g_priv) + g_priv->adapter->fops_mode = true; + + sema_init(&g_priv->wr_mtx, 1); + sema_init(&g_priv->rd_mtx, 1); + need_reset_stack = HW_ERR_NONE; + need_reopen = 0; + pr_info("%s fops_mode=%d end\n", __func__, g_priv->adapter->fops_mode); + return 0; +} + +static int btmtk_fops_close(struct inode *inode, struct file *file) +{ + pr_info("%s begin\n", __func__); + + if (!probe_ready) { + pr_err("%s probe_ready is %d return\n", + __func__, probe_ready); + return -EFAULT; + } + + if (g_priv) + g_priv->adapter->fops_mode = false; + + btmtk_clean_queue(); + need_reopen = 0; + pr_info("%s fops_mode=%d end\n", __func__, g_priv->adapter->fops_mode); + return 0; +} + +ssize_t btmtk_fops_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + int retval = 0; + struct sk_buff *skb = NULL; + static u8 waiting_for_hci_without_packet_type; /* INITIALISED_STATIC: do not initialise statics to 0 */ + static u8 hci_packet_type = 0xff; + u32 copy_size = 0; + unsigned long c_result = 0; + u8 pkt_type = 0xff; + u32 pkt_len = 0; + unsigned char *pkt_data = NULL; + + if (!probe_ready) { + pr_err("%s probe_ready is %d return\n", + __func__, probe_ready); + return -EFAULT; + } + + if (g_priv == NULL) { + pr_info("%s g_priv is NULL\n", __func__); + return -EFAULT; + } + + if (g_priv->adapter->fops_mode == 0) { + pr_info("%s fops_mode is 0\n", __func__); + return -EFAULT; + } + + if (need_reopen) { + pr_info("%s: need_reopen (%d)!", __func__, need_reopen); + return -EFAULT; + } +#if 0 + pr_info("%s : (%d) %02X %02X %02X %02X " + %"02X %02X %02X %02X\n", + __func__, (int)count, + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + + pr_info("%s print write data", __func__); + if (count > 10) + pr_info(" %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + buf[0], buf[1], buf[2], buf[3], buf[4], + buf[5], buf[6], buf[7], buf[8], buf[9]); + else { + for (i = 0; i < count; i++) + pr_info("%d %02X", i, buf[i]); + } +#endif + down(&g_priv->wr_mtx); + + if (count > 0 && count < MTK_TXDATA_SIZE) { + c_result = copy_from_user(userbuf, buf, count); + } else { + pr_err("%s: target packet length:%zu is not allowed", __func__, count); + up(&g_priv->wr_mtx); + return -EFAULT; + } + + if (c_result != 0) { + pr_err("%s copy_from_user failed!\n", __func__); + up(&g_priv->wr_mtx); + return -EFAULT; + } + + if (count == 1) { + if (waiting_for_hci_without_packet_type == 1) { + pr_warn("%s: Waiting for hci_without_packet_type, but receive data count is 1!", __func__); + pr_warn("%s: Treat this packet as packet_type", __func__); + } + memcpy(&hci_packet_type, &userbuf[0], 1); + waiting_for_hci_without_packet_type = 1; + retval = 1; + goto OUT; + } + + if (waiting_for_hci_without_packet_type) { + copy_size = count + 1; + pkt_type = hci_packet_type; + pkt_data = &userbuf[0]; + } else { + copy_size = count; + pkt_type = userbuf[0]; + pkt_data = &userbuf[1]; + } + + /* Check input length which must follow the BT spec.*/ + switch (pkt_type) { + case MTK_HCI_COMMAND_PKT: + /* HCI command : Type(8b) OpCode(16b) length(8b) + * Header length = 1 + 2 + 1 + */ + pkt_len = pkt_data[2] + MTK_HCI_CMD_HEADER_LEN; + break; + case MTK_HCI_ACLDATA_PKT: + /* ACL data : Type(8b) handle+flag(16b) length(16b) + * Header length = 1 + 2 + 2 + */ + pkt_len = (pkt_data[2] | (pkt_data[3] << 8)) + MTK_HCI_ACL_HEADER_LEN; + break; + case MTK_HCI_SCODATA_PKT: + /* SCO data : Type(8b) handle+flag(16b) length(8b) + * Header length = 1 + 2 + 1 + */ + pkt_len = pkt_data[2] + MTK_HCI_SCO_HEADER_LEN; + break; + default: + pr_err("%s: type is 0x%x\n", __func__, pkt_type); + retval = -EFAULT; + goto OUT; + } + + /* check frame length is valid */ + if (pkt_len != copy_size) { + pr_err("%s: input len(%d) error (expect %d)\n", __func__, copy_size, pkt_type); + retval = -EFAULT; + goto OUT; + } + + + skb = bt_skb_alloc(copy_size - 1, GFP_ATOMIC); + if (skb == NULL) { + pr_err("%s: No meory for skb\n", __func__); + up(&g_priv->wr_mtx); + return -ENOMEM; + } + bt_cb(skb)->pkt_type = pkt_type; + memcpy(&skb->data[0], pkt_data, copy_size-1); + + skb->len = copy_size-1; + skb_queue_tail(&g_priv->adapter->tx_queue, skb); + + if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) { + u8 fw_assert_cmd[] = { 0x6F, 0xFC, 0x05, 0x01, 0x02, 0x01, 0x00, 0x08 }; + u8 reset_cmd[] = { 0x03, 0x0C, 0x00 }; + u8 read_ver_cmd[] = { 0x01, 0x10, 0x00 }; + + if (skb->len == sizeof(fw_assert_cmd) && + !memcmp(&skb->data[0], fw_assert_cmd, sizeof(fw_assert_cmd))) + pr_info("%s: Donge FW Assert Triggered by upper layer\n", __func__); + else if (skb->len == sizeof(reset_cmd) && + !memcmp(&skb->data[0], reset_cmd, sizeof(reset_cmd))) + pr_info("%s: got command: 0x03 0C 00 (HCI_RESET)\n", __func__); + else if (skb->len == sizeof(read_ver_cmd) && + !memcmp(&skb->data[0], read_ver_cmd, sizeof(read_ver_cmd))) + pr_info("%s: got command: 0x01 10 00 (READ_LOCAL_VERSION)\n", __func__); + } + + wake_up_interruptible(&g_priv->main_thread.wait_q); + + retval = copy_size; + + if (waiting_for_hci_without_packet_type) { + hci_packet_type = 0xff; + waiting_for_hci_without_packet_type = 0; + if (retval > 0) + retval -= 1; + } + +OUT: + + pr_debug("%s end\n", __func__); + up(&g_priv->wr_mtx); + return retval; +} + +ssize_t btmtk_fops_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + struct sk_buff *skb = NULL; + int copyLen = 0; + u8 hwerr_event[] = { 0x04, 0x10, 0x01, 0xff }; + static int send_hw_err_event_count; + + if (!probe_ready) { + pr_err("%s probe_ready is %d return\n", + __func__, probe_ready); + return -EFAULT; + } + + if (g_priv == NULL) { + pr_info("%s g_priv is NULL\n", __func__); + return -EFAULT; + } + + if (g_priv->adapter->fops_mode == 0) { + pr_info("%s fops_mode is 0\n", __func__); + return -EFAULT; + } + + down(&g_priv->rd_mtx); + + if (need_reset_stack != HW_ERR_NONE) { + pr_warn("%s: Reset BT stack", __func__); + pr_warn("%s: go if send_hw_err_event_count %d", __func__, send_hw_err_event_count); + hwerr_event[3] = need_reset_stack; + if (send_hw_err_event_count < sizeof(hwerr_event)) { + if (count < (sizeof(hwerr_event) - send_hw_err_event_count)) { + copyLen = count; + pr_info("call wake_up_interruptible"); + wake_up_interruptible(&inq); + } else + copyLen = (sizeof(hwerr_event) - send_hw_err_event_count); + pr_warn("%s: in if copyLen = %d", __func__, copyLen); + if (copy_to_user(buf, hwerr_event + send_hw_err_event_count, copyLen)) { + pr_err("send_hw_err_event_count %d copy to user fail, count = %d, go out", + send_hw_err_event_count, copyLen); + copyLen = -EFAULT; + goto OUT; + } + send_hw_err_event_count += copyLen; + pr_warn("%s: in if send_hw_err_event_count = %d", __func__, send_hw_err_event_count); + if (send_hw_err_event_count >= sizeof(hwerr_event)) { + send_hw_err_event_count = 0; + pr_warn("%s: set need_reset_stack=0", __func__); + need_reset_stack = HW_ERR_NONE; + need_reopen = 1; + } + pr_warn("%s: set call up", __func__); + goto OUT; + } else { + pr_warn("%s: xx set copyLen = -EFAULT", __func__); + copyLen = -EFAULT; + goto OUT; + } + } + + LOCK_UNSLEEPABLE_LOCK(&(metabuffer.spin_lock)); + if (skb_queue_empty(&g_priv->adapter->fops_queue)) { + /* if (filp->f_flags & O_NONBLOCK) { */ + if (metabuffer.write_p == metabuffer.read_p) { + UNLOCK_UNSLEEPABLE_LOCK(&(metabuffer.spin_lock)); + up(&g_priv->rd_mtx); + return 0; + } + } + + do { + skb = skb_dequeue(&g_priv->adapter->fops_queue); + if (skb == NULL) { + pr_debug("%s skb=NULL break\n", __func__); + break; + } + +#if 0 + pr_debug("%s pkt_type %d metabuffer.buffer %d", + __func__, bt_cb(skb)->pkt_type, + metabuffer.buffer[copyLen]); +#endif + btmtk_print_buffer_conent(skb->data, skb->len); + + if (btmtk_sdio_push_data_to_metabuffer(&metabuffer, skb->data, + skb->len, bt_cb(skb)->pkt_type, true) < 0) { + skb_queue_head(&g_priv->adapter->fops_queue, skb); + break; + } + kfree_skb(skb); + } while (!skb_queue_empty(&g_priv->adapter->fops_queue)); + UNLOCK_UNSLEEPABLE_LOCK(&(metabuffer.spin_lock)); + + up(&g_priv->rd_mtx); + + return btmtk_sdio_pull_data_from_metabuffer(&metabuffer, buf, count); + +OUT: + up(&g_priv->rd_mtx); + return copyLen; +} + +static int btmtk_fops_fasync(int fd, struct file *file, int on) +{ + pr_info("%s: fd = 0x%X, flag = 0x%X\n", __func__, fd, on); + return fasync_helper(fd, file, on, &fasync); +} + +unsigned int btmtk_fops_poll(struct file *filp, poll_table *wait) +{ + unsigned int mask = 0; + + if (!probe_ready) { + pr_err("%s probe_ready is %d return\n", + __func__, probe_ready); + return mask; + } + + if (g_priv == NULL) { + pr_err("%s g_priv is NULL\n", __func__); + return -ENODEV; + } + + if (metabuffer.write_p != metabuffer.read_p) + mask |= (POLLIN | POLLRDNORM); + + if (skb_queue_empty(&g_priv->adapter->fops_queue)) { + poll_wait(filp, &inq, wait); + + if (!skb_queue_empty(&g_priv->adapter->fops_queue)) { + mask |= (POLLIN | POLLRDNORM); + /* pr_info("%s poll done\n", __func__); */ + } + } else + mask |= (POLLIN | POLLRDNORM); + + mask |= (POLLOUT | POLLWRNORM); + + /* pr_info("%s poll mask 0x%x\n", __func__,mask); */ + return mask; +} + +long btmtk_fops_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + u32 retval = 0; + + return retval; +} + +static int btmtk_fops_openfwlog(struct inode *inode, + struct file *file) +{ + if (g_priv == NULL) { + pr_err("%s: ERROR, g_data is NULL!\n", __func__); + return -ENODEV; + } + + sema_init(&g_priv->wr_fwlog_mtx, 1); + pr_info("%s: OK\n", __func__); + return 0; +} + +static int btmtk_fops_closefwlog(struct inode *inode, + struct file *file) +{ + if (g_priv == NULL) { + pr_err("%s: ERROR, g_data is NULL!\n", __func__); + return -ENODEV; + } + + pr_info("%s: OK\n", __func__); + return 0; +} + +static ssize_t btmtk_fops_readfwlog(struct file *filp, + char __user *buf, + size_t count, + loff_t *f_pos) +{ + struct sk_buff *skb = NULL; + int copyLen = 0; + + if (!probe_ready) { + pr_err("%s probe_ready is %d return\n", + __func__, probe_ready); + return -EFAULT; + } + + if (g_priv == NULL) { + pr_info("%s g_priv is NULL\n", __func__); + return -EFAULT; + } + + /* picus read a queue, it may occur performace issue */ + LOCK_UNSLEEPABLE_LOCK(&(fwlog_metabuffer.spin_lock)); + if (skb_queue_len(&g_priv->adapter->fwlog_fops_queue)) + skb = skb_dequeue(&g_priv->adapter->fwlog_fops_queue); + UNLOCK_UNSLEEPABLE_LOCK(&(fwlog_metabuffer.spin_lock)); + + if (skb == NULL) + return 0; + + if (skb->len <= count) { + if (copy_to_user(buf, skb->data, skb->len)) { + pr_err("%s: copy_to_user failed!", __func__); + /* copy_to_user failed, add skb to fwlog_fops_queue */ + skb_queue_head(&g_priv->adapter->fwlog_fops_queue, skb); + copyLen = -EFAULT; + goto OUT; + } + copyLen = skb->len; + } else { + pr_err("%s: Drop data!! skb->len err(count: %d, skb.len: %d)", __func__, (int)count, skb->len); + copyLen = -EFAULT; + } + kfree_skb(skb); +OUT: + return copyLen; +} + +static ssize_t btmtk_fops_writefwlog(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + struct sk_buff *skb = NULL; + int i = 0, len = 0, ret = -1; + u32 crAddr = 0, crValue = 0; + u8 *i_fwlog_buf; + u8 *o_fwlog_buf; + + if (g_priv == NULL) { + pr_info("%s g_priv is NULL\n", __func__); + ret = -EINVAL; + return ret; + } + + i_fwlog_buf = kmalloc(HCI_MAX_COMMAND_BUF_SIZE, GFP_KERNEL); + if (i_fwlog_buf == NULL) + return -ENOMEM; + + o_fwlog_buf = kmalloc(HCI_MAX_COMMAND_SIZE, GFP_KERNEL); + if (o_fwlog_buf == NULL) { + kfree(i_fwlog_buf); + return -ENOMEM; + } + + down(&g_priv->wr_fwlog_mtx); + + if (count > HCI_MAX_COMMAND_BUF_SIZE) { + pr_err("%s: your command is larger than maximum length, count = %zd\n", + __func__, count); + ret = -ENOMEM; + goto exit; + } + + memset(i_fwlog_buf, 0, HCI_MAX_COMMAND_BUF_SIZE); + memset(o_fwlog_buf, 0, HCI_MAX_COMMAND_SIZE); + + if (copy_from_user(i_fwlog_buf, buf, count) != 0) { + pr_err("%s copy_from_user failed!\n", __func__); + ret = -EPERM; + goto exit; + } + + i_fwlog_buf[count] = '\0'; + + if (strstr(i_fwlog_buf, FW_OWN_OFF)) { + pr_warn("%s set %s\n", __func__, FW_OWN_OFF); + btmtk_sdio_set_no_fw_own(g_priv, true); + len = count; + wake_up_interruptible(&g_priv->main_thread.wait_q); + ret = count; + goto exit; + + } else if (strstr(i_fwlog_buf, FW_OWN_ON)) { + pr_warn("%s set %s\n", __func__, FW_OWN_ON); + btmtk_sdio_set_no_fw_own(g_priv, false); + len = count; + wake_up_interruptible(&g_priv->main_thread.wait_q); + ret = count; + goto exit; + } + + /* For btmtk_bluetooth_kpi, EX: echo bperf=1 > /dev/stpbtfwlog */ + if (strcmp(i_fwlog_buf, "bperf=") >= 0) { + u8 val = *(i_fwlog_buf + strlen("bperf=")) - 48; + + btmtk_bluetooth_kpi = val; + pr_info("%s: set bluetooth KPI feature(bperf) to %d", __func__, btmtk_bluetooth_kpi); + ret = count; + goto exit; + } + + /* hci input command format : echo 01 be fc 01 05 > /dev/stpbtfwlog */ + /* We take the data from index three to end. */ + for (i = 0; i < count; i++) { + char *pos = i_fwlog_buf + i; + char temp_str[3] = {'\0'}; + long res = 0; + + if (*pos == ' ' || *pos == '\t' || *pos == '\r' || *pos == '\n') { + continue; + } else if (*pos == '0' && (*(pos + 1) == 'x' || *(pos + 1) == 'X')) { + i++; + continue; + } else if (!(*pos >= '0' && *pos <= '9') && !(*pos >= 'A' && *pos <= 'F') + && !(*pos >= 'a' && *pos <= 'f')) { + pr_err("%s: There is an invalid input(%c)", __func__, *pos); + ret = -EINVAL; + goto exit; + } + temp_str[0] = *pos; + temp_str[1] = *(pos + 1); + i++; + ret = kstrtol(temp_str, 16, &res); + if (ret == 0) { + o_fwlog_buf[len++] = (u8)res; + } else { + pr_err("%s: Convert %s failed(%d)", __func__, temp_str, ret); + goto exit; + } + } + + /* + * Receive command from stpbtfwlog, then Sent hci command + * to controller + */ + pr_debug("%s: hci buff is %02x%02x%02x%02x%02x, length %d\n", + __func__, o_fwlog_buf[0], o_fwlog_buf[1], o_fwlog_buf[2], + o_fwlog_buf[3], o_fwlog_buf[4], len); + + /* check HCI command length */ + if (len > HCI_MAX_COMMAND_SIZE) { + pr_err("%s: your command is larger than maximum length, length = %d\n", + __func__, len); + ret = -ENOMEM; + goto exit; + } + + switch (o_fwlog_buf[0]) { + case MTK_HCI_READ_CR_PKT: + if (len == MTK_HCI_READ_CR_PKT_LENGTH) { + crAddr = (o_fwlog_buf[1] << 24) + (o_fwlog_buf[2] << 16) + + (o_fwlog_buf[3] << 8) + (o_fwlog_buf[4]); + btmtk_sdio_readl(crAddr, &crValue); + pr_info("%s read crAddr=0x%08x crValue=0x%08x\n", + __func__, crAddr, crValue); + } else { + pr_info("%s read length=%d is incorrect, should be %d\n", + __func__, len, MTK_HCI_READ_CR_PKT_LENGTH); + ret = -EINVAL; + goto exit; + } + break; + case MTK_HCI_WRITE_CR_PKT: + if (len == MTK_HCI_WRITE_CR_PKT_LENGTH) { + crAddr = (o_fwlog_buf[1] << 24) + (o_fwlog_buf[2] << 16) + + (o_fwlog_buf[3] << 8) + (o_fwlog_buf[4]); + crValue = (o_fwlog_buf[5] << 24) + (o_fwlog_buf[6] << 16) + + (o_fwlog_buf[7] << 8) + (o_fwlog_buf[8]); + pr_info("%s write crAddr=0x%08x crValue=0x%08x\n", + __func__, crAddr, crValue); + btmtk_sdio_writel(crAddr, crValue); + } else { + pr_info("%s write length=%d is incorrect, should be %d\n", + __func__, len, MTK_HCI_WRITE_CR_PKT_LENGTH); + ret = -EINVAL; + goto exit; + } + break; + default: + /* + * Receive command from stpbtfwlog, then Sent hci command + * to Stack + */ + skb = bt_skb_alloc(len - 1, GFP_ATOMIC); + if (skb == NULL) { + pr_err("%s: No meory for skb\n", __func__); + ret = -ENOMEM; + goto exit; + } + bt_cb(skb)->pkt_type = o_fwlog_buf[0]; + memcpy(&skb->data[0], &o_fwlog_buf[1], len - 1); + skb->len = len - 1; + skb_queue_tail(&g_priv->adapter->tx_queue, skb); + wake_up_interruptible(&g_priv->main_thread.wait_q); + break; + } + ret = count; + pr_info("%s write end\n", __func__); +exit: + pr_info("%s exit, length = %d\n", __func__, len); + kfree(i_fwlog_buf); + kfree(o_fwlog_buf); + up(&g_priv->wr_fwlog_mtx); + return ret; +} + +static unsigned int btmtk_fops_pollfwlog( + struct file *file, poll_table *wait) +{ + unsigned int mask = 0; + + if (!probe_ready) { + pr_err("%s probe_ready is %d return\n", + __func__, probe_ready); + return mask; + } + + if (g_priv == NULL) { + pr_err("%s g_priv is NULL\n", __func__); + return -ENODEV; + } + + if (fwlog_metabuffer.write_p != fwlog_metabuffer.read_p) + mask |= (POLLIN | POLLRDNORM); + + if (skb_queue_empty(&g_priv->adapter->fwlog_fops_queue)) { + poll_wait(file, &fw_log_inq, wait); + + if (!skb_queue_empty(&g_priv->adapter->fwlog_fops_queue)) { + mask |= (POLLIN | POLLRDNORM); + /* pr_info("%s poll done\n", __func__); */ + } + } else + mask |= (POLLIN | POLLRDNORM); + + mask |= (POLLOUT | POLLWRNORM); + + /* pr_info("%s poll mask 0x%x\n", __func__,mask); */ + return mask; +} + +static long btmtk_fops_unlocked_ioctlfwlog( + struct file *filp, unsigned int cmd, + unsigned long arg) +{ + int retval = 0; + + pr_info("%s: ->\n", __func__); + if (g_priv == NULL) { + pr_err("%s: ERROR, g_data is NULL!\n", __func__); + return -ENODEV; + } + + return retval; +} + +/*============================================================================*/ +/* Interface Functions : Proc */ +/*============================================================================*/ +static int btmtk_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%s\n", fw_version_str); + return 0; +} + +static int btmtk_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, btmtk_proc_show, NULL); +} + +void btmtk_proc_create_new_entry(void) +{ + struct proc_dir_entry *proc_show_entry; + + pr_info("proc initialized"); + + g_proc_dir = proc_mkdir("stpbt", 0); + if (g_proc_dir == 0) { + pr_info("Unable to creat dir"); + return; + } + proc_show_entry = proc_create("bt_fw_version", 0644, g_proc_dir, &BT_proc_fops); +} + + +static int BTMTK_major; +static int BT_majorfwlog; +static struct cdev BTMTK_cdev; +static struct cdev BT_cdevfwlog; +static int BTMTK_devs = 1; + +static wait_queue_head_t inq; +const struct file_operations BTMTK_fops = { + .open = btmtk_fops_open, + .release = btmtk_fops_close, + .read = btmtk_fops_read, + .write = btmtk_fops_write, + .poll = btmtk_fops_poll, + .unlocked_ioctl = btmtk_fops_unlocked_ioctl, + .fasync = btmtk_fops_fasync +}; + +const struct file_operations BT_fopsfwlog = { + .open = btmtk_fops_openfwlog, + .release = btmtk_fops_closefwlog, + .read = btmtk_fops_readfwlog, + .write = btmtk_fops_writefwlog, + .poll = btmtk_fops_pollfwlog, + .unlocked_ioctl = btmtk_fops_unlocked_ioctlfwlog + +}; + +static int BTMTK_init(void) +{ + dev_t devID = MKDEV(BTMTK_major, 0); + dev_t devIDfwlog = MKDEV(BT_majorfwlog, 1); + int ret = 0; + int cdevErr = 0; + int major = 0; + int majorfwlog = 0; + + pr_info("BTMTK_init\n"); + + g_card = NULL; + txbuf = NULL; + rxbuf = NULL; + userbuf = NULL; + rx_length = 0; + +#if SAVE_FW_DUMP_IN_KERNEL + fw_dump_file = NULL; +#else + fw_dump_file = 0; +#endif + g_priv = NULL; + + probe_counter = 0; + fw_is_doing_coredump = 0; + + btmtk_proc_create_new_entry(); + + ret = alloc_chrdev_region(&devID, 0, 1, "BT_chrdev"); + if (ret) { + pr_err("fail to allocate chrdev\n"); + return ret; + } + + ret = alloc_chrdev_region(&devIDfwlog, 0, 1, "BT_chrdevfwlog"); + if (ret) { + pr_err("fail to allocate chrdev\n"); + return ret; + } + + BTMTK_major = major = MAJOR(devID); + pr_info("major number:%d\n", BTMTK_major); + BT_majorfwlog = majorfwlog = MAJOR(devIDfwlog); + pr_info("BT_majorfwlog number: %d\n", BT_majorfwlog); + + cdev_init(&BTMTK_cdev, &BTMTK_fops); + BTMTK_cdev.owner = THIS_MODULE; + + cdev_init(&BT_cdevfwlog, &BT_fopsfwlog); + BT_cdevfwlog.owner = THIS_MODULE; + + cdevErr = cdev_add(&BTMTK_cdev, devID, BTMTK_devs); + if (cdevErr) + goto error; + + cdevErr = cdev_add(&BT_cdevfwlog, devIDfwlog, 1); + if (cdevErr) + goto error; + + pr_info("%s driver(major %d) installed.\n", + "BT_chrdev", BTMTK_major); + pr_info("%s driver(major %d) installed.\n", + "BT_chrdevfwlog", BT_majorfwlog); + + pBTClass = class_create(/*THIS_MODULE,*/ "BT_chrdev"); + if (IS_ERR(pBTClass)) { + pr_err("class create fail, error code(%ld)\n", + PTR_ERR(pBTClass)); + goto err1; + } + + pBTDev = device_create(pBTClass, NULL, devID, NULL, BT_NODE); + if (IS_ERR(pBTDev)) { + pr_err("device create fail, error code(%ld)\n", + PTR_ERR(pBTDev)); + goto err2; + } + + pBTDevfwlog = device_create(pBTClass, NULL, + devIDfwlog, NULL, "stpbtfwlog"); + if (IS_ERR(pBTDevfwlog)) { + pr_err("device(stpbtfwlog) create fail, error code(%ld)\n", + PTR_ERR(pBTDevfwlog)); + goto err2; + } + + pr_info("%s: BT_major %d, BT_majorfwlog %d\n", + __func__, BTMTK_major, BT_majorfwlog); + pr_info("%s: devID %d, devIDfwlog %d\n", __func__, devID, devIDfwlog); + + /* init wait queue */ + g_devIDfwlog = devIDfwlog; + init_waitqueue_head(&(fw_log_inq)); + init_waitqueue_head(&(inq)); + + return 0; + + err2: + if (pBTClass) { + class_destroy(pBTClass); + pBTClass = NULL; + } + + err1: + + error: + if (cdevErr == 0) + cdev_del(&BTMTK_cdev); + + if (ret == 0) + unregister_chrdev_region(devID, BTMTK_devs); + + return -1; +} + +static void BTMTK_exit(void) +{ + dev_t dev = MKDEV(BTMTK_major, 0); + dev_t devIDfwlog = g_devIDfwlog; + + pr_info("%s\n", __func__); + + if (g_proc_dir != NULL) { + remove_proc_entry("bt_fw_version", g_proc_dir); + remove_proc_entry("stpbt", NULL); + g_proc_dir = NULL; + pr_info("proc device node and folder removed!!"); + } + + if (g_card) { + pr_info("%s 1\n", __func__); + if (g_card->woble_setting_file_name) { + pr_info("%s 2\n", __func__); + kfree(g_card->woble_setting_file_name); + pr_info("%s 3\n", __func__); + pr_info("free woble_setting_file_name done\n"); + } else { + pr_err("%s no free woble_setting_file_name, g_card is not null\n", __func__); + pr_err("%s woble_setting_file_name is null\n", __func__); + } + } else + pr_err("no free woble_setting_file_name, g_card is null\n"); + +#if (SUPPORT_UNIFY_WOBLE & SUPPORT_ANDROID) + pr_info("%s 4\n", __func__); + if (g_card) + wake_lock_destroy(&g_card->woble_wlock); + else + pr_err("%s:g_data is NULL, no destroy woble_wlock", __func__); +#endif + + pr_info("%s 5\n", __func__); + if (pBTDevfwlog) { + pr_info("%s 6\n", __func__); + device_destroy(pBTClass, devIDfwlog); + pBTDevfwlog = NULL; + } + pr_info("%s 7\n", __func__); + if (pBTDev) { + device_destroy(pBTClass, dev); + pBTDev = NULL; + } + pr_info("%s 8\n", __func__); + if (pBTClass) { + class_destroy(pBTClass); + pBTClass = NULL; + } + pr_info("%s 9\n", __func__); + cdev_del(&BTMTK_cdev); + pr_info("%s 10\n", __func__); + unregister_chrdev_region(dev, 1); + + cdev_del(&BT_cdevfwlog); + unregister_chrdev_region(devIDfwlog, 1); + pr_info("%s driver removed.\n", BT_DRIVER_NAME); +} + +static int btmtk_sdio_allocate_memory(void) +{ + if (txbuf == NULL) { + txbuf = kmalloc(MTK_TXDATA_SIZE, GFP_ATOMIC); + memset(txbuf, 0, MTK_TXDATA_SIZE); + } + + if (rxbuf == NULL) { + rxbuf = kmalloc(MTK_RXDATA_SIZE, GFP_ATOMIC); + memset(rxbuf, 0, MTK_RXDATA_SIZE); + } + + if (userbuf == NULL) { + userbuf = kmalloc(MTK_TXDATA_SIZE, GFP_ATOMIC); + memset(userbuf, 0, MTK_TXDATA_SIZE); + } + + if (userbuf_fwlog == NULL) { + userbuf_fwlog = kmalloc(MTK_TXDATA_SIZE, GFP_ATOMIC); + memset(userbuf_fwlog, 0, MTK_TXDATA_SIZE); + } + + return 0; +} + +static int btmtk_sdio_free_memory(void) +{ + kfree(txbuf); + + kfree(rxbuf); + + kfree(userbuf); + + kfree(userbuf_fwlog); + + return 0; +} + +static int __init btmtk_sdio_init_module(void) +{ + int ret = 0; + +#ifdef CONFIG_AMAZON_A2DP_TS_SDIO + ret = btif_ts_init(); + if (ret) { + pr_err("%s: btif_ts_init failed!", __func__); + return ret; + } +#endif + + ret = BTMTK_init(); + if (ret) { + pr_err("%s: BTMTK_init failed!", __func__); + return ret; + } + + if (btmtk_sdio_allocate_memory() < 0) { + pr_err("%s: allocate memory failed!", __func__); + return -ENOMEM; + } + + if (sdio_register_driver(&bt_mtk_sdio) != 0) { + pr_err("SDIO Driver Registration Failed\n"); + return -ENODEV; + } + + pr_info("SDIO Driver Registration Success\n"); + + /* Clear the flag in case user removes the card. */ + user_rmmod = 0; + + return 0; +} + +static void __exit btmtk_sdio_exit_module(void) +{ + /* Set the flag as user is removing this module. */ + user_rmmod = 1; + BTMTK_exit(); + sdio_unregister_driver(&bt_mtk_sdio); + btmtk_sdio_free_memory(); +#ifdef CONFIG_AMAZON_A2DP_TS_SDIO + btif_ts_exit(); +#endif +} + +module_init(btmtk_sdio_init_module); +module_exit(btmtk_sdio_exit_module); diff --git a/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_sdio.h b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_sdio.h new file mode 100644 index 00000000000000..c35f0043effc0d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/btmtk_sdio.h @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2016,2017 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _BTMTK_SDIO_H_ +#define _BTMTK_SDIO_H_ +#include "btmtk_config.h" +#if ((SUPPORT_UNIFY_WOBLE & SUPPORT_ANDROID) || SUPPORT_EINT) +#include +#endif +#include +#include "osal_typedef.h" + +#define VERSION "v0.0.1.00_2019111401" + +#define SDIO_HEADER_LEN 4 + +#define BD_ADDRESS_SIZE 6 + +#define DUMP_HCI_LOG_FILE_NAME "/sys/hcilog" +/* SD block size can not bigger than 64 due to buf size limit in firmware */ +/* define SD block size for data Tx/Rx */ +#define SDIO_BLOCK_SIZE 256 + +#define SDIO_PATCH_DOWNLOAD_FIRST 1/*first packet*/ +#define SDIO_PATCH_DOWNLOAD_CON 2/*continue*/ +#define SDIO_PATCH_DOWNLOAD_END 3/*end*/ + +/* Number of blocks for firmware transfer */ +#define FIRMWARE_TRANSFER_NBLOCK 2 + +/* This is for firmware specific length */ +#define FW_EXTRA_LEN 36 + +#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024) + +#define MRVDRV_BT_RX_PACKET_BUFFER_SIZE \ + (HCI_MAX_FRAME_SIZE + FW_EXTRA_LEN) + +#define ALLOC_BUF_SIZE (((max_t (int, MRVDRV_BT_RX_PACKET_BUFFER_SIZE, \ + MRVDRV_SIZE_OF_CMD_BUFFER) + SDIO_HEADER_LEN \ + + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE) \ + * SDIO_BLOCK_SIZE) + +/* The number of times to try when polling for status */ +#define MAX_POLL_TRIES 100 + +/* Max retry number of CMD53 write */ +#define MAX_WRITE_IOMEM_RETRY 2 + +/* register bitmasks */ +#define HOST_POWER_UP BIT(1) +#define HOST_CMD53_FIN BIT(2) + +#define HIM_DISABLE 0xff +#define HIM_ENABLE (BIT(0) | BIT(1)) + +#define UP_LD_HOST_INT_STATUS BIT(0) +#define DN_LD_HOST_INT_STATUS BIT(1) + +#define DN_LD_CARD_RDY BIT(0) +#define CARD_IO_READY BIT(3) + +#define FIRMWARE_READY 0xfedc +#define CFG_THREE_IN_ONE_FIRMWARE 0 + + +#if CFG_THREE_IN_ONE_FIRMWARE +#define BUILD_SIGN(ch0, ch1, ch2, ch3) \ + ((unsigned int)(unsigned char)(ch0) | \ + ((unsigned int)(unsigned char)(ch1) << 8) | \ + ((unsigned int)(unsigned char)(ch2) << 16) | \ + ((unsigned int)(unsigned char)(ch3) << 24)) + +#define MTK_WIFI_SIGNATURE BUILD_SIGN('M', 'T', 'K', 'W') +#define FW_TYPE_PATCH 2 +struct _FW_SECTION_T { + unsigned int u4FwType; + unsigned int u4Offset; + unsigned int u4Length; +}; + +struct _FIRMWARE_HEADER_T { + unsigned int u4Signature; + unsigned int u4CRC; + unsigned int u4NumOfEntries; + unsigned int u4Reserved; + struct _FW_SECTION_T arSection[]; +}; +#endif + +struct btmtk_sdio_card_reg { + u8 cfg; + u8 host_int_mask; + u8 host_intstatus; + u8 card_status; + u8 sq_read_base_addr_a0; + u8 sq_read_base_addr_a1; + u8 card_revision; + u8 card_fw_status0; + u8 card_fw_status1; + u8 card_rx_len; + u8 card_rx_unit; + u8 io_port_0; + u8 io_port_1; + u8 io_port_2; + bool int_read_to_clear; + u8 host_int_rsr; + u8 card_misc_cfg; + u8 fw_dump_ctrl; + u8 fw_dump_start; + u8 fw_dump_end; + u8 func_num; + u32 chip_id; +}; + +#define WOBLE_SETTING_FILE_NAME "woble_setting.bin" +#define WOBLE_SETTING_COUNT 10 + +#define WOBLE_FAIL -10 + + +struct woble_setting_struct { + char *content; /* APCF conecnt or radio off content */ + int length; /* APCF conecnt or radio off content of length */ +}; + +struct btmtk_sdio_card { + struct sdio_func *func; + u32 ioport; + const char *helper; + const char *firmware; + const char *firmware1; + const struct btmtk_sdio_card_reg *reg; + bool support_pscan_win_report; + bool supports_fw_dump; + u16 sd_blksz_fw_dl; + u8 rx_unit; + struct btmtk_private *priv; + + + unsigned char *woble_setting; + unsigned char *woble_setting_file_name; + unsigned int woble_setting_len; + + unsigned int chip_id; + struct woble_setting_struct woble_setting_apcf[WOBLE_SETTING_COUNT]; + struct woble_setting_struct woble_setting_apcf_fill_mac[WOBLE_SETTING_COUNT]; + struct woble_setting_struct woble_setting_apcf_fill_mac_location[WOBLE_SETTING_COUNT]; + + struct woble_setting_struct woble_setting_radio_off[WOBLE_SETTING_COUNT]; + struct woble_setting_struct woble_setting_radio_off_status_event[WOBLE_SETTING_COUNT]; + /* complete event */ + struct woble_setting_struct woble_setting_radio_off_comp_event[WOBLE_SETTING_COUNT]; + + struct woble_setting_struct woble_setting_radio_on[WOBLE_SETTING_COUNT]; + struct woble_setting_struct woble_setting_radio_on_status_event[WOBLE_SETTING_COUNT]; + struct woble_setting_struct woble_setting_radio_on_comp_event[WOBLE_SETTING_COUNT]; + + int suspend_count; + /* set apcf after resume(radio on) */ + struct woble_setting_struct woble_setting_apcf_resume[WOBLE_SETTING_COUNT]; + struct woble_setting_struct woble_setting_apcf_resume_event[WOBLE_SETTING_COUNT]; + unsigned char bdaddr[BD_ADDRESS_SIZE]; + unsigned int woble_need_trigger_coredump; +#if (SUPPORT_UNIFY_WOBLE & SUPPORT_ANDROID) + struct wake_lock woble_wlock; +#endif + +#if SUPPORT_EINT + struct wake_lock eint_wlock; +#endif + +#if SUPPORT_EINT + /* WoBLE */ + unsigned int wobt_irq; + int wobt_irqlevel; + atomic_t irq_enable_count; +#endif +}; +struct btmtk_sdio_device { + const char *helper; + const char *firmware; + const char *firmware1; + const struct btmtk_sdio_card_reg *reg; + const bool support_pscan_win_report; + u16 sd_blksz_fw_dl; + bool supports_fw_dump; +}; +#pragma pack(1) +struct _PATCH_HEADER { + u8 ucDateTime[16]; + u8 ucPlatform[4]; + u16 u2HwVer; + u16 u2SwVer; + u32 u4PatchVer; + u16 u2PatchStartAddr;/*Patch ram start address*/ +}; +#pragma pack() + +#define HW_VERSION 0x80000000 +#define FW_VERSION 0x80000004 +#define CHIP_ID 0x80000008 + +/*common register address*/ +#define CHLPCR 0x0004 +#define CSDIOCSR 0x0008 +#define CHCR 0x000C +#define CHISR 0x0010 +#define CHIER 0x0014 +#define CTDR 0x0018 +#define CRDR 0x001C +#define SWPCDBGR 0x0154 +/*CHLPCR*/ +#define C_FW_INT_EN_SET 0x00000001 +#define C_FW_INT_EN_CLEAR 0x00000002 +/*CHISR*/ +#define RX_PKT_LEN 0xFFFF0000 +#define FIRMWARE_INT 0x0000FE00 +#define FIRMWARE_INT_BIT15 0x00008000 /*FW inform driver don't change to fw own for core dump*/ +#define TX_FIFO_OVERFLOW 0x00000100 +#define FW_INT_IND_INDICATOR 0x00000080 +#define TX_COMPLETE_COUNT 0x00000070 +#define TX_UNDER_THOLD 0x00000008 +#define TX_EMPTY 0x00000004 +#define RX_DONE 0x00000002 +#define FW_OWN_BACK_INT 0x00000001 + + +#define MTKSTP_HEADER_SIZE 0x0004 + +#define MTK_SDIO_PACKET_HEADER_SIZE 4 +#define MTKDATA_HEADER_SIZE 10 +#define MTKWMT_HEADER_SIZE 4 + +#define PATCH_DOWNLOAD_SIZE 1970 + +#define DRIVER_OWN 0 +#define FW_OWN 1 + +#define MTK_WMT_HEADER_LEN 4 + +#define DEFAULE_PATCH_FRAG_SIZE 1000 + +#define PATCH_IS_DOWNLOAD_BY_OTHER 0 +#define PATCH_READY 1 +#define PATCH_NEED_DOWNLOAD 2 + +//#ifdef MTK_BT_HCI +#define BT_TASK_INDX (0) +typedef VOID(*MTK_WCN_STP_IF_RX)(const unsigned char * data, INT32 size); +typedef int MTK_WCN_BOOL; +typedef enum _ENUM_WMTDRV_TYPE_T { + WMTDRV_TYPE_BT = 0, + WMTDRV_TYPE_FM = 1, + WMTDRV_TYPE_GPS = 2, + WMTDRV_TYPE_WIFI = 3, + WMTDRV_TYPE_WMT = 4, + WMTDRV_TYPE_ANT = 5, + WMTDRV_TYPE_STP = 6, + WMTDRV_TYPE_SDIO1 = 7, + WMTDRV_TYPE_SDIO2 = 8, + WMTDRV_TYPE_LPBK = 9, + WMTDRV_TYPE_COREDUMP = 10, + WMTDRV_TYPE_MAX +} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; + +//#endif + +/** + * stpbtfwlog device node + */ +#define HCI_MAX_COMMAND_SIZE 255 +/* Write a char to buffer. + * ex : echo 01 be > /dev/stpbtfwlog + * "01 " need three bytes. + */ +#define HCI_MAX_COMMAND_BUF_SIZE (HCI_MAX_COMMAND_SIZE * 3) + +/* + * data event: + * return + * 0: + * patch download is not complete/get patch semaphore fail + * 1: + * patch download is complete by others + * 2 + * patch download is not coplete + * 3:(for debug) + * release patch semaphore success + */ + +/* Platform specific DMA alignment */ +#define BTSDIO_DMA_ALIGN 8 + +/* Macros for Data Alignment : size */ +#define ALIGN_SZ(p, a) \ + (((p) + ((a) - 1)) & ~((a) - 1)) + +/* Macros for Data Alignment : address */ +#define ALIGN_ADDR(p, a) \ + ((((unsigned long)(p)) + (((unsigned long)(a)) - 1)) & \ + ~(((unsigned long)(a)) - 1)) + +/*int btmtk_print_buffer_conent(u8 *buf, u32 Datalen) +{ + int i = 0; + int print_finish = 0; + //Print out txbuf data for debug + for (i = 0; i <= (Datalen-1); i += 16) { + if ((i+16) <= Datalen) { + pr_debug("%s: %02X%02X%02X%02X%02X %02X%02X%02X%02X%02X %02X%02X%02X%02X%02X %02X\n", + __func__, + buf[i], buf[i+1], buf[i+2], buf[i+3], + buf[i+4], buf[i+5], buf[i+6], buf[i+7], + buf[i+8], buf[i+9], buf[i+10], buf[i+11], + buf[i+12], buf[i+13], buf[i+14], buf[i+15]); + } else { + for (; i < (Datalen); i++) + pr_debug("%s: %02X\n", __func__, buf[i]); + + print_finish = 1; + } + + if (print_finish) + break; + } + return 0; +}*/ + +u32 LOCK_UNSLEEPABLE_LOCK(struct _OSAL_UNSLEEPABLE_LOCK_ *pUSL); +u32 UNLOCK_UNSLEEPABLE_LOCK(struct _OSAL_UNSLEEPABLE_LOCK_ *pUSL); + +extern unsigned char probe_counter; +extern unsigned char *txbuf; +extern u8 probe_ready; + +enum { + BTMTK_WOBLE_STATE_UNKNOWN, + BTMTK_WOBLE_STATE_SUSPEND, + BTMTK_WOBLE_STATE_RESUME, + BTMTK_WOBLE_STATE_DUMPING, + BTMTK_WOBLE_STATE_DUMPEND, + BTMTK_WOBLE_STATE_NEEDRESET_STACK, +}; + +enum { + BTMTK_SDIO_EVENT_COMPARE_STATE_UNKNOWN, + BTMTK_SDIO_EVENT_COMPARE_STATE_NOTHING_NEED_COMPARE, + BTMTK_SDIO_EVENT_COMPARE_STATE_NEED_COMPARE, + BTMTK_SDIO_EVENT_COMPARE_STATE_COMPARE_SUCCESS, +}; + +enum { + HW_ERR_NONE = 0, + HW_ERR_CODE_CHIP_RESET, + HW_ERR_CODE_LEGACY_WOBLE, + HW_ERR_CODE_CARD_DISC, + HW_ERR_CODE_CORE_DUMP, + HW_ERR_CODE_POWER_ON, + HW_ERR_CODE_POWER_OFF, + HW_ERR_CODE_WOBLE, + HW_ERR_CODE_SET_SLEEP_CMD, +}; + +/** + * Maximum rom patch file name length + */ +#define MAX_BIN_FILE_NAME_LEN 32 + +#define COMPARE_FAIL -1 +#define COMPARE_SUCCESS 1 +#define WOBLE_COMP_EVENT_TIMO 5000 +#define WLAN_STATUS_IS_NOT_LOAD -1 +#define WLAN_STATUS_DEFAULT 0 +#define WLAN_STATUS_CALL_REMOVE_START 1 /* WIFI driver is inserted */ + +/** + * Inline functions + */ +static inline int is_support_unify_woble(struct btmtk_sdio_card *data) +{ +#if SUPPORT_UNIFY_WOBLE + if (((data->chip_id & 0xffff) == 0x7668) || + ((data->chip_id & 0xffff) == 0x7663)) + return 1; + else + return 0; +#else + return 0; +#endif +} + +static inline int is_mt7668(struct btmtk_sdio_card *data) +{ +#if SUPPORT_MT7668 + return ((data->chip_id & 0xffff) == 0x7668); +#else + return 0; +#endif +} + +static inline int is_mt7663(struct btmtk_sdio_card *data) +{ +#if SUPPORT_MT7663 + return ((data->chip_id & 0xffff) == 0x7663); +#else + return 0; +#endif +} + +#define FW_OWN_OFF "fw own off" +#define FW_OWN_ON "fw own on" + +extern int sdio_reset_comm(struct mmc_card *card); +extern int btmtk_print_buffer_conent(u8 *buf, u32 Datalen); +int btmtk_sdio_reset_dongle(void); +void btmtk_sdio_stop_wait_wlan_remove_tsk(void); +int btmtk_sdio_notify_wlan_remove_start(void); +int btmtk_sdio_notify_wlan_remove_end(void); +int btmtk_sdio_bt_trigger_core_dump(int trigger_dump); +void btmtk_sdio_notify_wlan_toggle_rst_end(void); +#endif + diff --git a/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/util/checkpatch.pl b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/util/checkpatch.pl new file mode 100644 index 00000000000000..a8368d1c4348ce --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/util/checkpatch.pl @@ -0,0 +1,6285 @@ +#!/usr/bin/perl -w +# (c) 2001, Dave Jones. (the file handling bit) +# (c) 2005, Joel Schopp (the ugly bit) +# (c) 2007,2008, Andy Whitcroft (new conditions, test suite) +# (c) 2008-2010 Andy Whitcroft +# Licensed under the terms of the GNU GPL License version 2 + +use strict; +use POSIX; +use File::Basename; +use Cwd 'abs_path'; +use Term::ANSIColor qw(:constants); + +my $P = $0; +my $D = dirname(abs_path($P)); + +my $V = '0.32'; + +use Getopt::Long qw(:config no_auto_abbrev); + +my $quiet = 0; +my $tree = 1; +my $chk_signoff = 1; +my $chk_patch = 1; +my $tst_only; +my $emacs = 0; +my $terse = 0; +my $showfile = 0; +my $file = 0; +my $git = 0; +my %git_commits = (); +my $check = 0; +my $check_orig = 0; +my $summary = 1; +my $mailback = 0; +my $summary_file = 0; +my $show_types = 0; +my $list_types = 0; +my $fix = 0; +my $fix_inplace = 0; +my $root; +my %debug; +my %camelcase = (); +my %use_type = (); +my @use = (); +my %ignore_type = (); +my @ignore = (); +my $help = 0; +my $configuration_file = ".checkpatch.conf"; +my $max_line_length = 80; +my $ignore_perl_version = 0; +my $minimum_perl_version = 5.10.0; +my $min_conf_desc_length = 4; +my $spelling_file = "$D/spelling.txt"; +my $codespell = 0; +my $codespellfile = "/usr/share/codespell/dictionary.txt"; +my $conststructsfile = "$D/const_structs.checkpatch"; +my $color = 1; +my $allow_c99_comments = 1; + +sub help { + my ($exitcode) = @_; + + print << "EOM"; +Usage: $P [OPTION]... [FILE]... +Version: $V + +Options: + -q, --quiet quiet + --no-tree run without a kernel tree + --no-signoff do not check for 'Signed-off-by' line + --patch treat FILE as patchfile (default) + --emacs emacs compile window format + --terse one line per report + --showfile emit diffed file position, not input file position + -g, --git treat FILE as a single commit or git revision range + single git commit with: + + ^ + ~n + multiple git commits with: + .. + ... + - + git merges are ignored + -f, --file treat FILE as regular source file + --subjective, --strict enable more subjective tests + --list-types list the possible message types + --types TYPE(,TYPE2...) show only these comma separated message types + --ignore TYPE(,TYPE2...) ignore various comma separated message types + --show-types show the specific message type in the output + --max-line-length=n set the maximum line length, if exceeded, warn + --min-conf-desc-length=n set the min description length, if shorter, warn + --root=PATH PATH to the kernel tree root + --no-summary suppress the per-file summary + --mailback only produce a report in case of warnings/errors + --summary-file include the filename in summary + --debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of + 'values', 'possible', 'type', and 'attr' (default + is all off) + --test-only=WORD report only warnings/errors containing WORD + literally + --fix EXPERIMENTAL - may create horrible results + If correctable single-line errors exist, create + ".EXPERIMENTAL-checkpatch-fixes" + with potential errors corrected to the preferred + checkpatch style + --fix-inplace EXPERIMENTAL - may create horrible results + Is the same as --fix, but overwrites the input + file. It's your fault if there's no backup or git + --ignore-perl-version override checking of perl version. expect + runtime errors. + --codespell Use the codespell dictionary for spelling/typos + (default:/usr/share/codespell/dictionary.txt) + --codespellfile Use this codespell dictionary + --color Use colors when output is STDOUT (default: on) + -h, --help, --version display this help and exit + +When FILE is - read standard input. +EOM + + exit($exitcode); +} + +sub uniq { + my %seen; + return grep { !$seen{$_}++ } @_; +} + +sub list_types { + my ($exitcode) = @_; + + my $count = 0; + + local $/ = undef; + + open(my $script, '<', abs_path($P)) or + die "$P: Can't read '$P' $!\n"; + + my $text = <$script>; + close($script); + + my @types = (); + for ($text =~ /\b(?:(?:CHK|WARN|ERROR)\s*\(\s*"([^"]+)")/g) { + push (@types, $_); + } + @types = sort(uniq(@types)); + print("#\tMessage type\n\n"); + foreach my $type (@types) { + print(++$count . "\t" . $type . "\n"); + } + + exit($exitcode); +} + +my $conf = which_conf($configuration_file); +if (-f $conf) { + my @conf_args; + open(my $conffile, '<', "$conf") + or warn "$P: Can't find a readable $configuration_file file $!\n"; + + while (<$conffile>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + $line =~ s/\s+/ /g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + + my @words = split(" ", $line); + foreach my $word (@words) { + last if ($word =~ m/^#/); + push (@conf_args, $word); + } + } + close($conffile); + unshift(@ARGV, @conf_args) if @conf_args; +} + +GetOptions( + 'q|quiet+' => \$quiet, + 'tree!' => \$tree, + 'signoff!' => \$chk_signoff, + 'patch!' => \$chk_patch, + 'emacs!' => \$emacs, + 'terse!' => \$terse, + 'showfile!' => \$showfile, + 'f|file!' => \$file, + 'g|git!' => \$git, + 'subjective!' => \$check, + 'strict!' => \$check, + 'ignore=s' => \@ignore, + 'types=s' => \@use, + 'show-types!' => \$show_types, + 'list-types!' => \$list_types, + 'max-line-length=i' => \$max_line_length, + 'min-conf-desc-length=i' => \$min_conf_desc_length, + 'root=s' => \$root, + 'summary!' => \$summary, + 'mailback!' => \$mailback, + 'summary-file!' => \$summary_file, + 'fix!' => \$fix, + 'fix-inplace!' => \$fix_inplace, + 'ignore-perl-version!' => \$ignore_perl_version, + 'debug=s' => \%debug, + 'test-only=s' => \$tst_only, + 'codespell!' => \$codespell, + 'codespellfile=s' => \$codespellfile, + 'color!' => \$color, + 'h|help' => \$help, + 'version' => \$help +) or help(1); + +help(0) if ($help); + +list_types(0) if ($list_types); + +$fix = 1 if ($fix_inplace); +$check_orig = $check; + +my $exit = 0; + +if ($^V && $^V lt $minimum_perl_version) { + printf "$P: requires at least perl version %vd\n", $minimum_perl_version; + if (!$ignore_perl_version) { + exit(1); + } +} + +#if no filenames are given, push '-' to read patch from stdin +if ($#ARGV < 0) { + push(@ARGV, '-'); +} + +sub hash_save_array_words { + my ($hashRef, $arrayRef) = @_; + + my @array = split(/,/, join(',', @$arrayRef)); + foreach my $word (@array) { + $word =~ s/\s*\n?$//g; + $word =~ s/^\s*//g; + $word =~ s/\s+/ /g; + $word =~ tr/[a-z]/[A-Z]/; + + next if ($word =~ m/^\s*#/); + next if ($word =~ m/^\s*$/); + + $hashRef->{$word}++; + } +} + +sub hash_show_words { + my ($hashRef, $prefix) = @_; + + if (keys %$hashRef) { + print "\nNOTE: $prefix message types:"; + foreach my $word (sort keys %$hashRef) { + print " $word"; + } + print "\n"; + } +} + +hash_save_array_words(\%ignore_type, \@ignore); +hash_save_array_words(\%use_type, \@use); + +my $dbg_values = 0; +my $dbg_possible = 0; +my $dbg_type = 0; +my $dbg_attr = 0; +for my $key (keys %debug) { + ## no critic + eval "\${dbg_$key} = '$debug{$key}';"; + die "$@" if ($@); +} + +my $rpt_cleaners = 0; + +if ($terse) { + $emacs = 1; + $quiet++; +} + +if ($tree) { + if (defined $root) { + if (!top_of_kernel_tree($root)) { + die "$P: $root: --root does not point at a valid tree\n"; + } + } else { + if (top_of_kernel_tree('.')) { + $root = '.'; + } elsif ($0 =~ m@(.*)/scripts/[^/]*$@ && + top_of_kernel_tree($1)) { + $root = $1; + } + } + + if (!defined $root) { + print "Must be run from the top-level dir. of a kernel tree\n"; + exit(2); + } +} + +my $emitted_corrupt = 0; + +our $Ident = qr{ + [A-Za-z_][A-Za-z\d_]* + (?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)* + }x; +our $Storage = qr{extern|static|asmlinkage}; +our $Sparse = qr{ + __user| + __kernel| + __force| + __iomem| + __must_check| + __init_refok| + __kprobes| + __ref| + __rcu| + __private + }x; +our $InitAttributePrefix = qr{__(?:mem|cpu|dev|net_|)}; +our $InitAttributeData = qr{$InitAttributePrefix(?:initdata\b)}; +our $InitAttributeConst = qr{$InitAttributePrefix(?:initconst\b)}; +our $InitAttributeInit = qr{$InitAttributePrefix(?:init\b)}; +our $InitAttribute = qr{$InitAttributeData|$InitAttributeConst|$InitAttributeInit}; + +# Notes to $Attribute: +# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check +our $Attribute = qr{ + const| + __percpu| + __nocast| + __safe| + __bitwise__| + __packed__| + __packed2__| + __naked| + __maybe_unused| + __always_unused| + __noreturn| + __used| + __cold| + __pure| + __noclone| + __deprecated| + __read_mostly| + __kprobes| + $InitAttribute| + ____cacheline_aligned| + ____cacheline_aligned_in_smp| + ____cacheline_internodealigned_in_smp| + __weak + }x; +our $Modifier; +our $Inline = qr{inline|__always_inline|noinline|__inline|__inline__}; +our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]}; +our $Lval = qr{$Ident(?:$Member)*}; + +our $Int_type = qr{(?i)llu|ull|ll|lu|ul|l|u}; +our $Binary = qr{(?i)0b[01]+$Int_type?}; +our $Hex = qr{(?i)0x[0-9a-f]+$Int_type?}; +our $Int = qr{[0-9]+$Int_type?}; +our $Octal = qr{0[0-7]+$Int_type?}; +our $String = qr{"[X\t]*"}; +our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?}; +our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?}; +our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?}; +our $Float = qr{$Float_hex|$Float_dec|$Float_int}; +our $Constant = qr{$Float|$Binary|$Octal|$Hex|$Int}; +our $Assignment = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=}; +our $Compare = qr{<=|>=|==|!=|<|(?}; +our $Arithmetic = qr{\+|-|\*|\/|%}; +our $Operators = qr{ + <=|>=|==|!=| + =>|->|<<|>>|<|>|!|~| + &&|\|\||,|\^|\+\+|--|&|\||$Arithmetic + }x; + +our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x; + +our $BasicType; +our $NonptrType; +our $NonptrTypeMisordered; +our $NonptrTypeWithAttr; +our $Type; +our $TypeMisordered; +our $Declare; +our $DeclareMisordered; + +our $NON_ASCII_UTF8 = qr{ + [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte + | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs + | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte + | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates + | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 + | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 + | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 +}x; + +our $UTF8 = qr{ + [\x09\x0A\x0D\x20-\x7E] # ASCII + | $NON_ASCII_UTF8 +}x; + +our $typeC99Typedefs = qr{(?:__)?(?:[us]_?)?int_?(?:8|16|32|64)_t}; +our $typeOtherOSTypedefs = qr{(?x: + u_(?:char|short|int|long) | # bsd + u(?:nchar|short|int|long) # sysv +)}; +our $typeKernelTypedefs = qr{(?x: + (?:__)?(?:u|s|be|le)(?:8|16|32|64)| + atomic_t +)}; +our $typeTypedefs = qr{(?x: + $typeC99Typedefs\b| + $typeOtherOSTypedefs\b| + $typeKernelTypedefs\b +)}; + +our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b}; + +our $logFunctions = qr{(?x: + printk(?:_ratelimited|_once|)| + (?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)| + WARN(?:_RATELIMIT|_ONCE|)| + panic| + MODULE_[A-Z_]+| + seq_vprintf|seq_printf|seq_puts +)}; + +our $signature_tags = qr{(?xi: + Signed-off-by:| + Acked-by:| + Tested-by:| + Reviewed-by:| + Reported-by:| + Suggested-by:| + To:| + Cc: +)}; + +our @typeListMisordered = ( + qr{char\s+(?:un)?signed}, + qr{int\s+(?:(?:un)?signed\s+)?short\s}, + qr{int\s+short(?:\s+(?:un)?signed)}, + qr{short\s+int(?:\s+(?:un)?signed)}, + qr{(?:un)?signed\s+int\s+short}, + qr{short\s+(?:un)?signed}, + qr{long\s+int\s+(?:un)?signed}, + qr{int\s+long\s+(?:un)?signed}, + qr{long\s+(?:un)?signed\s+int}, + qr{int\s+(?:un)?signed\s+long}, + qr{int\s+(?:un)?signed}, + qr{int\s+long\s+long\s+(?:un)?signed}, + qr{long\s+long\s+int\s+(?:un)?signed}, + qr{long\s+long\s+(?:un)?signed\s+int}, + qr{long\s+long\s+(?:un)?signed}, + qr{long\s+(?:un)?signed}, +); + +our @typeList = ( + qr{void}, + qr{(?:(?:un)?signed\s+)?char}, + qr{(?:(?:un)?signed\s+)?short\s+int}, + qr{(?:(?:un)?signed\s+)?short}, + qr{(?:(?:un)?signed\s+)?int}, + qr{(?:(?:un)?signed\s+)?long\s+int}, + qr{(?:(?:un)?signed\s+)?long\s+long\s+int}, + qr{(?:(?:un)?signed\s+)?long\s+long}, + qr{(?:(?:un)?signed\s+)?long}, + qr{(?:un)?signed}, + qr{float}, + qr{double}, + qr{bool}, + qr{struct\s+$Ident}, + qr{union\s+$Ident}, + qr{enum\s+$Ident}, + qr{${Ident}_t}, + qr{${Ident}_handler}, + qr{${Ident}_handler_fn}, + @typeListMisordered, +); + +our $C90_int_types = qr{(?x: + long\s+long\s+int\s+(?:un)?signed| + long\s+long\s+(?:un)?signed\s+int| + long\s+long\s+(?:un)?signed| + (?:(?:un)?signed\s+)?long\s+long\s+int| + (?:(?:un)?signed\s+)?long\s+long| + int\s+long\s+long\s+(?:un)?signed| + int\s+(?:(?:un)?signed\s+)?long\s+long| + + long\s+int\s+(?:un)?signed| + long\s+(?:un)?signed\s+int| + long\s+(?:un)?signed| + (?:(?:un)?signed\s+)?long\s+int| + (?:(?:un)?signed\s+)?long| + int\s+long\s+(?:un)?signed| + int\s+(?:(?:un)?signed\s+)?long| + + int\s+(?:un)?signed| + (?:(?:un)?signed\s+)?int +)}; + +our @typeListFile = (); +our @typeListWithAttr = ( + @typeList, + qr{struct\s+$InitAttribute\s+$Ident}, + qr{union\s+$InitAttribute\s+$Ident}, +); + +our @modifierList = ( + qr{fastcall}, +); +our @modifierListFile = (); + +our @mode_permission_funcs = ( + ["module_param", 3], + ["module_param_(?:array|named|string)", 4], + ["module_param_array_named", 5], + ["debugfs_create_(?:file|u8|u16|u32|u64|x8|x16|x32|x64|size_t|atomic_t|bool|blob|regset32|u32_array)", 2], + ["proc_create(?:_data|)", 2], + ["(?:CLASS|DEVICE|SENSOR|SENSOR_DEVICE|IIO_DEVICE)_ATTR", 2], + ["IIO_DEV_ATTR_[A-Z_]+", 1], + ["SENSOR_(?:DEVICE_|)ATTR_2", 2], + ["SENSOR_TEMPLATE(?:_2|)", 3], + ["__ATTR", 2], +); + +#Create a search pattern for all these functions to speed up a loop below +our $mode_perms_search = ""; +foreach my $entry (@mode_permission_funcs) { + $mode_perms_search .= '|' if ($mode_perms_search ne ""); + $mode_perms_search .= $entry->[0]; +} + +our $mode_perms_world_writable = qr{ + S_IWUGO | + S_IWOTH | + S_IRWXUGO | + S_IALLUGO | + 0[0-7][0-7][2367] +}x; + +our %mode_permission_string_types = ( + "S_IRWXU" => 0700, + "S_IRUSR" => 0400, + "S_IWUSR" => 0200, + "S_IXUSR" => 0100, + "S_IRWXG" => 0070, + "S_IRGRP" => 0040, + "S_IWGRP" => 0020, + "S_IXGRP" => 0010, + "S_IRWXO" => 0007, + "S_IROTH" => 0004, + "S_IWOTH" => 0002, + "S_IXOTH" => 0001, + "S_IRWXUGO" => 0777, + "S_IRUGO" => 0444, + "S_IWUGO" => 0222, + "S_IXUGO" => 0111, +); + +#Create a search pattern for all these strings to speed up a loop below +our $mode_perms_string_search = ""; +foreach my $entry (keys %mode_permission_string_types) { + $mode_perms_string_search .= '|' if ($mode_perms_string_search ne ""); + $mode_perms_string_search .= $entry; +} + +our $allowed_asm_includes = qr{(?x: + irq| + memory| + time| + reboot +)}; +# memory.h: ARM has a custom one + +# Load common spelling mistakes and build regular expression list. +my $misspellings; +my %spelling_fix; + +if (open(my $spelling, '<', $spelling_file)) { + while (<$spelling>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + + my ($suspect, $fix) = split(/\|\|/, $line); + + $spelling_fix{$suspect} = $fix; + } + close($spelling); +} else { + warn "No typos will be found - file '$spelling_file': $!\n"; +} + +if ($codespell) { + if (open(my $spelling, '<', $codespellfile)) { + while (<$spelling>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + next if ($line =~ m/, disabled/i); + + $line =~ s/,.*$//; + + my ($suspect, $fix) = split(/->/, $line); + + $spelling_fix{$suspect} = $fix; + } + close($spelling); + } else { + warn "No codespell typos will be found - file '$codespellfile': $!\n"; + } +} + +$misspellings = join("|", sort keys %spelling_fix) if keys %spelling_fix; + +my $const_structs = ""; +if (open(my $conststructs, '<', $conststructsfile)) { + while (<$conststructs>) { + my $line = $_; + + $line =~ s/\s*\n?$//g; + $line =~ s/^\s*//g; + + next if ($line =~ m/^\s*#/); + next if ($line =~ m/^\s*$/); + if ($line =~ /\s/) { + print("$conststructsfile: '$line' invalid - ignored\n"); + next; + } + + $const_structs .= '|' if ($const_structs ne ""); + $const_structs .= $line; + } + close($conststructsfile); +} else { + warn "No structs that should be const will be found - file '$conststructsfile': $!\n"; +} + +sub build_types { + my $mods = "(?x: \n" . join("|\n ", (@modifierList, @modifierListFile)) . "\n)"; + my $all = "(?x: \n" . join("|\n ", (@typeList, @typeListFile)) . "\n)"; + my $Misordered = "(?x: \n" . join("|\n ", @typeListMisordered) . "\n)"; + my $allWithAttr = "(?x: \n" . join("|\n ", @typeListWithAttr) . "\n)"; + $Modifier = qr{(?:$Attribute|$Sparse|$mods)}; + $BasicType = qr{ + (?:$typeTypedefs\b)| + (?:${all}\b) + }x; + $NonptrType = qr{ + (?:$Modifier\s+|const\s+)* + (?: + (?:typeof|__typeof__)\s*\([^\)]*\)| + (?:$typeTypedefs\b)| + (?:${all}\b) + ) + (?:\s+$Modifier|\s+const)* + }x; + $NonptrTypeMisordered = qr{ + (?:$Modifier\s+|const\s+)* + (?: + (?:${Misordered}\b) + ) + (?:\s+$Modifier|\s+const)* + }x; + $NonptrTypeWithAttr = qr{ + (?:$Modifier\s+|const\s+)* + (?: + (?:typeof|__typeof__)\s*\([^\)]*\)| + (?:$typeTypedefs\b)| + (?:${allWithAttr}\b) + ) + (?:\s+$Modifier|\s+const)* + }x; + $Type = qr{ + $NonptrType + (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+)? + (?:\s+$Inline|\s+$Modifier)* + }x; + $TypeMisordered = qr{ + $NonptrTypeMisordered + (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+)? + (?:\s+$Inline|\s+$Modifier)* + }x; + $Declare = qr{(?:$Storage\s+(?:$Inline\s+)?)?$Type}; + $DeclareMisordered = qr{(?:$Storage\s+(?:$Inline\s+)?)?$TypeMisordered}; +} +build_types(); + +our $Typecast = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*}; + +# Using $balanced_parens, $LvalOrFunc, or $FuncArg +# requires at least perl version v5.10.0 +# Any use must be runtime checked with $^V + +our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/; +our $LvalOrFunc = qr{((?:[\&\*]\s*)?$Lval)\s*($balanced_parens{0,1})\s*}; +our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)}; + +our $declaration_macros = qr{(?x: + (?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(| + (?:$Storage\s+)?LIST_HEAD\s*\(| + (?:$Storage\s+)?${Type}\s+uninitialized_var\s*\( +)}; + +sub deparenthesize { + my ($string) = @_; + return "" if (!defined($string)); + + while ($string =~ /^\s*\(.*\)\s*$/) { + $string =~ s@^\s*\(\s*@@; + $string =~ s@\s*\)\s*$@@; + } + + $string =~ s@\s+@ @g; + + return $string; +} + +sub seed_camelcase_file { + my ($file) = @_; + + return if (!(-f $file)); + + local $/; + + open(my $include_file, '<', "$file") + or warn "$P: Can't read '$file' $!\n"; + my $text = <$include_file>; + close($include_file); + + my @lines = split('\n', $text); + + foreach my $line (@lines) { + next if ($line !~ /(?:[A-Z][a-z]|[a-z][A-Z])/); + if ($line =~ /^[ \t]*(?:#[ \t]*define|typedef\s+$Type)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)/) { + $camelcase{$1} = 1; + } elsif ($line =~ /^\s*$Declare\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[\(\[,;]/) { + $camelcase{$1} = 1; + } elsif ($line =~ /^\s*(?:union|struct|enum)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[;\{]/) { + $camelcase{$1} = 1; + } + } +} + +sub is_maintained_obsolete { + my ($filename) = @_; + + return 0 if (!(-e "$root/scripts/get_maintainer.pl")); + + my $status = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`; + + return $status =~ /obsolete/i; +} + +my $camelcase_seeded = 0; +sub seed_camelcase_includes { + return if ($camelcase_seeded); + + my $files; + my $camelcase_cache = ""; + my @include_files = (); + + $camelcase_seeded = 1; + + if (-e ".git") { + my $git_last_include_commit = `git log --no-merges --pretty=format:"%h%n" -1 -- include`; + chomp $git_last_include_commit; + $camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit"; + } else { + my $last_mod_date = 0; + $files = `find $root/include -name "*.h"`; + @include_files = split('\n', $files); + foreach my $file (@include_files) { + my $date = POSIX::strftime("%Y%m%d%H%M", + localtime((stat $file)[9])); + $last_mod_date = $date if ($last_mod_date < $date); + } + $camelcase_cache = ".checkpatch-camelcase.date.$last_mod_date"; + } + + if ($camelcase_cache ne "" && -f $camelcase_cache) { + open(my $camelcase_file, '<', "$camelcase_cache") + or warn "$P: Can't read '$camelcase_cache' $!\n"; + while (<$camelcase_file>) { + chomp; + $camelcase{$_} = 1; + } + close($camelcase_file); + + return; + } + + if (-e ".git") { + $files = `git ls-files "include/*.h"`; + @include_files = split('\n', $files); + } + + foreach my $file (@include_files) { + seed_camelcase_file($file); + } + + if ($camelcase_cache ne "") { + unlink glob ".checkpatch-camelcase.*"; + open(my $camelcase_file, '>', "$camelcase_cache") + or warn "$P: Can't write '$camelcase_cache' $!\n"; + foreach (sort { lc($a) cmp lc($b) } keys(%camelcase)) { + print $camelcase_file ("$_\n"); + } + close($camelcase_file); + } +} + +sub git_commit_info { + my ($commit, $id, $desc) = @_; + + return ($id, $desc) if ((which("git") eq "") || !(-e ".git")); + + my $output = `git log --no-color --format='%H %s' -1 $commit 2>&1`; + $output =~ s/^\s*//gm; + my @lines = split("\n", $output); + + return ($id, $desc) if ($#lines < 0); + + if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous\./) { +# Maybe one day convert this block of bash into something that returns +# all matching commit ids, but it's very slow... +# +# echo "checking commits $1..." +# git rev-list --remotes | grep -i "^$1" | +# while read line ; do +# git log --format='%H %s' -1 $line | +# echo "commit $(cut -c 1-12,41-)" +# done + } elsif ($lines[0] =~ /^fatal: ambiguous argument '$commit': unknown revision or path not in the working tree\./) { + } else { + $id = substr($lines[0], 0, 12); + $desc = substr($lines[0], 41); + } + + return ($id, $desc); +} + +$chk_signoff = 0 if ($file); + +my @rawlines = (); +my @lines = (); +my @fixed = (); +my @fixed_inserted = (); +my @fixed_deleted = (); +my $fixlinenr = -1; + +# If input is git commits, extract all commits from the commit expressions. +# For example, HEAD-3 means we need check 'HEAD, HEAD~1, HEAD~2'. +die "$P: No git repository found\n" if ($git && !-e ".git"); + +if ($git) { + my @commits = (); + foreach my $commit_expr (@ARGV) { + my $git_range; + if ($commit_expr =~ m/^(.*)-(\d+)$/) { + $git_range = "-$2 $1"; + } elsif ($commit_expr =~ m/\.\./) { + $git_range = "$commit_expr"; + } else { + $git_range = "-1 $commit_expr"; + } + my $lines = `git log --no-color --no-merges --pretty=format:'%H %s' $git_range`; + foreach my $line (split(/\n/, $lines)) { + $line =~ /^([0-9a-fA-F]{40,40}) (.*)$/; + next if (!defined($1) || !defined($2)); + my $sha1 = $1; + my $subject = $2; + unshift(@commits, $sha1); + $git_commits{$sha1} = $subject; + } + } + die "$P: no git commits after extraction!\n" if (@commits == 0); + @ARGV = @commits; +} + +my $vname; +for my $filename (@ARGV) { + my $FILE; + if ($git) { + open($FILE, '-|', "git format-patch -M --stdout -1 $filename") || + die "$P: $filename: git format-patch failed - $!\n"; + } elsif ($file) { + open($FILE, '-|', "diff -u /dev/null $filename") || + die "$P: $filename: diff failed - $!\n"; + } elsif ($filename eq '-') { + open($FILE, '<&STDIN'); + } else { + open($FILE, '<', "$filename") || + die "$P: $filename: open failed - $!\n"; + } + if ($filename eq '-') { + $vname = 'Your patch'; + } elsif ($git) { + $vname = "Commit " . substr($filename, 0, 12) . ' ("' . $git_commits{$filename} . '")'; + } else { + $vname = $filename; + } + while (<$FILE>) { + chomp; + push(@rawlines, $_); + } + close($FILE); + + if ($#ARGV > 0 && $quiet == 0) { + print '-' x length($vname) . "\n"; + print "$vname\n"; + print '-' x length($vname) . "\n"; + } + + if (!process($filename)) { + $exit = 1; + } + @rawlines = (); + @lines = (); + @fixed = (); + @fixed_inserted = (); + @fixed_deleted = (); + $fixlinenr = -1; + @modifierListFile = (); + @typeListFile = (); + build_types(); +} + +if (!$quiet) { + hash_show_words(\%use_type, "Used"); + hash_show_words(\%ignore_type, "Ignored"); + + if ($^V lt 5.10.0) { + print << "EOM" + +NOTE: perl $^V is not modern enough to detect all possible issues. + An upgrade to at least perl v5.10.0 is suggested. +EOM + } + if ($exit) { + print << "EOM" + +NOTE: If any of the errors are false positives, please report + them to the maintainer, see CHECKPATCH in MAINTAINERS. +EOM + } +} + +exit($exit); + +sub top_of_kernel_tree { + my ($root) = @_; + + my @tree_check = ( + "COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile", + "README", "Documentation", "arch", "include", "drivers", + "fs", "init", "ipc", "kernel", "lib", "scripts", + ); + + foreach my $check (@tree_check) { + if (! -e $root . '/' . $check) { + return 0; + } + } + return 1; +} + +sub parse_email { + my ($formatted_email) = @_; + + my $name = ""; + my $address = ""; + my $comment = ""; + + if ($formatted_email =~ /^(.*)<(\S+\@\S+)>(.*)$/) { + $name = $1; + $address = $2; + $comment = $3 if defined $3; + } elsif ($formatted_email =~ /^\s*<(\S+\@\S+)>(.*)$/) { + $address = $1; + $comment = $2 if defined $2; + } elsif ($formatted_email =~ /(\S+\@\S+)(.*)$/) { + $address = $1; + $comment = $2 if defined $2; + $formatted_email =~ s/$address.*$//; + $name = $formatted_email; + $name = trim($name); + $name =~ s/^\"|\"$//g; + # If there's a name left after stripping spaces and + # leading quotes, and the address doesn't have both + # leading and trailing angle brackets, the address + # is invalid. ie: + # "joe smith joe@smith.com" bad + # "joe smith ]+>$/) { + $name = ""; + $address = ""; + $comment = ""; + } + } + + $name = trim($name); + $name =~ s/^\"|\"$//g; + $address = trim($address); + $address =~ s/^\<|\>$//g; + + if ($name =~ /[^\w \-]/i) { ##has "must quote" chars + $name =~ s/(?"; + } + + return $formatted_email; +} + +sub which { + my ($bin) = @_; + + foreach my $path (split(/:/, $ENV{PATH})) { + if (-e "$path/$bin") { + return "$path/$bin"; + } + } + + return ""; +} + +sub which_conf { + my ($conf) = @_; + + foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) { + if (-e "$path/$conf") { + return "$path/$conf"; + } + } + + return ""; +} + +sub expand_tabs { + my ($str) = @_; + + my $res = ''; + my $n = 0; + for my $c (split(//, $str)) { + if ($c eq "\t") { + $res .= ' '; + $n++; + for (; ($n % 8) != 0; $n++) { + $res .= ' '; + } + next; + } + $res .= $c; + $n++; + } + + return $res; +} +sub copy_spacing { + (my $res = shift) =~ tr/\t/ /c; + return $res; +} + +sub line_stats { + my ($line) = @_; + + # Drop the diff line leader and expand tabs + $line =~ s/^.//; + $line = expand_tabs($line); + + # Pick the indent from the front of the line. + my ($white) = ($line =~ /^(\s*)/); + + return (length($line), length($white)); +} + +my $sanitise_quote = ''; + +sub sanitise_line_reset { + my ($in_comment) = @_; + + if ($in_comment) { + $sanitise_quote = '*/'; + } else { + $sanitise_quote = ''; + } +} +sub sanitise_line { + my ($line) = @_; + + my $res = ''; + my $l = ''; + + my $qlen = 0; + my $off = 0; + my $c; + + # Always copy over the diff marker. + $res = substr($line, 0, 1); + + for ($off = 1; $off < length($line); $off++) { + $c = substr($line, $off, 1); + + # Comments we are wacking completly including the begin + # and end, all to $;. + if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') { + $sanitise_quote = '*/'; + + substr($res, $off, 2, "$;$;"); + $off++; + next; + } + if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') { + $sanitise_quote = ''; + substr($res, $off, 2, "$;$;"); + $off++; + next; + } + if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') { + $sanitise_quote = '//'; + + substr($res, $off, 2, $sanitise_quote); + $off++; + next; + } + + # A \ in a string means ignore the next character. + if (($sanitise_quote eq "'" || $sanitise_quote eq '"') && + $c eq "\\") { + substr($res, $off, 2, 'XX'); + $off++; + next; + } + # Regular quotes. + if ($c eq "'" || $c eq '"') { + if ($sanitise_quote eq '') { + $sanitise_quote = $c; + + substr($res, $off, 1, $c); + next; + } elsif ($sanitise_quote eq $c) { + $sanitise_quote = ''; + } + } + + #print "c<$c> SQ<$sanitise_quote>\n"; + if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") { + substr($res, $off, 1, $;); + } elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") { + substr($res, $off, 1, $;); + } elsif ($off != 0 && $sanitise_quote && $c ne "\t") { + substr($res, $off, 1, 'X'); + } else { + substr($res, $off, 1, $c); + } + } + + if ($sanitise_quote eq '//') { + $sanitise_quote = ''; + } + + # The pathname on a #include may be surrounded by '<' and '>'. + if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) { + my $clean = 'X' x length($1); + $res =~ s@\<.*\>@<$clean>@; + + # The whole of a #error is a string. + } elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) { + my $clean = 'X' x length($1); + $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@; + } + + if ($allow_c99_comments && $res =~ m@(//.*$)@) { + my $match = $1; + $res =~ s/\Q$match\E/"$;" x length($match)/e; + } + + return $res; +} + +sub get_quoted_string { + my ($line, $rawline) = @_; + + return "" if ($line !~ m/($String)/g); + return substr($rawline, $-[0], $+[0] - $-[0]); +} + +sub ctx_statement_block { + my ($linenr, $remain, $off) = @_; + my $line = $linenr - 1; + my $blk = ''; + my $soff = $off; + my $coff = $off - 1; + my $coff_set = 0; + + my $loff = 0; + + my $type = ''; + my $level = 0; + my @stack = (); + my $p; + my $c; + my $len = 0; + + my $remainder; + while (1) { + @stack = (['', 0]) if ($#stack == -1); + + #warn "CSB: blk<$blk> remain<$remain>\n"; + # If we are about to drop off the end, pull in more + # context. + if ($off >= $len) { + for (; $remain > 0; $line++) { + last if (!defined $lines[$line]); + next if ($lines[$line] =~ /^-/); + $remain--; + $loff = $len; + $blk .= $lines[$line] . "\n"; + $len = length($blk); + $line++; + last; + } + # Bail if there is no further context. + #warn "CSB: blk<$blk> off<$off> len<$len>\n"; + if ($off >= $len) { + last; + } + if ($level == 0 && substr($blk, $off) =~ /^.\s*#\s*define/) { + $level++; + $type = '#'; + } + } + $p = $c; + $c = substr($blk, $off, 1); + $remainder = substr($blk, $off); + + #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n"; + + # Handle nested #if/#else. + if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) { + push(@stack, [ $type, $level ]); + } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) { + ($type, $level) = @{$stack[$#stack - 1]}; + } elsif ($remainder =~ /^#\s*endif\b/) { + ($type, $level) = @{pop(@stack)}; + } + + # Statement ends at the ';' or a close '}' at the + # outermost level. + if ($level == 0 && $c eq ';') { + last; + } + + # An else is really a conditional as long as its not else if + if ($level == 0 && $coff_set == 0 && + (!defined($p) || $p =~ /(?:\s|\}|\+)/) && + $remainder =~ /^(else)(?:\s|{)/ && + $remainder !~ /^else\s+if\b/) { + $coff = $off + length($1) - 1; + $coff_set = 1; + #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n"; + #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n"; + } + + if (($type eq '' || $type eq '(') && $c eq '(') { + $level++; + $type = '('; + } + if ($type eq '(' && $c eq ')') { + $level--; + $type = ($level != 0)? '(' : ''; + + if ($level == 0 && $coff < $soff) { + $coff = $off; + $coff_set = 1; + #warn "CSB: mark coff<$coff>\n"; + } + } + if (($type eq '' || $type eq '{') && $c eq '{') { + $level++; + $type = '{'; + } + if ($type eq '{' && $c eq '}') { + $level--; + $type = ($level != 0)? '{' : ''; + + if ($level == 0) { + if (substr($blk, $off + 1, 1) eq ';') { + $off++; + } + last; + } + } + # Preprocessor commands end at the newline unless escaped. + if ($type eq '#' && $c eq "\n" && $p ne "\\") { + $level--; + $type = ''; + $off++; + last; + } + $off++; + } + # We are truly at the end, so shuffle to the next line. + if ($off == $len) { + $loff = $len + 1; + $line++; + $remain--; + } + + my $statement = substr($blk, $soff, $off - $soff + 1); + my $condition = substr($blk, $soff, $coff - $soff + 1); + + #warn "STATEMENT<$statement>\n"; + #warn "CONDITION<$condition>\n"; + + #print "coff<$coff> soff<$off> loff<$loff>\n"; + + return ($statement, $condition, + $line, $remain + 1, $off - $loff + 1, $level); +} + +sub statement_lines { + my ($stmt) = @_; + + # Strip the diff line prefixes and rip blank lines at start and end. + $stmt =~ s/(^|\n)./$1/g; + $stmt =~ s/^\s*//; + $stmt =~ s/\s*$//; + + my @stmt_lines = ($stmt =~ /\n/g); + + return $#stmt_lines + 2; +} + +sub statement_rawlines { + my ($stmt) = @_; + + my @stmt_lines = ($stmt =~ /\n/g); + + return $#stmt_lines + 2; +} + +sub statement_block_size { + my ($stmt) = @_; + + $stmt =~ s/(^|\n)./$1/g; + $stmt =~ s/^\s*{//; + $stmt =~ s/}\s*$//; + $stmt =~ s/^\s*//; + $stmt =~ s/\s*$//; + + my @stmt_lines = ($stmt =~ /\n/g); + my @stmt_statements = ($stmt =~ /;/g); + + my $stmt_lines = $#stmt_lines + 2; + my $stmt_statements = $#stmt_statements + 1; + + if ($stmt_lines > $stmt_statements) { + return $stmt_lines; + } else { + return $stmt_statements; + } +} + +sub ctx_statement_full { + my ($linenr, $remain, $off) = @_; + my ($statement, $condition, $level); + + my (@chunks); + + # Grab the first conditional/block pair. + ($statement, $condition, $linenr, $remain, $off, $level) = + ctx_statement_block($linenr, $remain, $off); + #print "F: c<$condition> s<$statement> remain<$remain>\n"; + push(@chunks, [ $condition, $statement ]); + if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) { + return ($level, $linenr, @chunks); + } + + # Pull in the following conditional/block pairs and see if they + # could continue the statement. + for (;;) { + ($statement, $condition, $linenr, $remain, $off, $level) = + ctx_statement_block($linenr, $remain, $off); + #print "C: c<$condition> s<$statement> remain<$remain>\n"; + last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s)); + #print "C: push\n"; + push(@chunks, [ $condition, $statement ]); + } + + return ($level, $linenr, @chunks); +} + +sub ctx_block_get { + my ($linenr, $remain, $outer, $open, $close, $off) = @_; + my $line; + my $start = $linenr - 1; + my $blk = ''; + my @o; + my @c; + my @res = (); + + my $level = 0; + my @stack = ($level); + for ($line = $start; $remain > 0; $line++) { + next if ($rawlines[$line] =~ /^-/); + $remain--; + + $blk .= $rawlines[$line]; + + # Handle nested #if/#else. + if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) { + push(@stack, $level); + } elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) { + $level = $stack[$#stack - 1]; + } elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) { + $level = pop(@stack); + } + + foreach my $c (split(//, $lines[$line])) { + ##print "C<$c>L<$level><$open$close>O<$off>\n"; + if ($off > 0) { + $off--; + next; + } + + if ($c eq $close && $level > 0) { + $level--; + last if ($level == 0); + } elsif ($c eq $open) { + $level++; + } + } + + if (!$outer || $level <= 1) { + push(@res, $rawlines[$line]); + } + + last if ($level == 0); + } + + return ($level, @res); +} +sub ctx_block_outer { + my ($linenr, $remain) = @_; + + my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0); + return @r; +} +sub ctx_block { + my ($linenr, $remain) = @_; + + my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0); + return @r; +} +sub ctx_statement { + my ($linenr, $remain, $off) = @_; + + my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off); + return @r; +} +sub ctx_block_level { + my ($linenr, $remain) = @_; + + return ctx_block_get($linenr, $remain, 0, '{', '}', 0); +} +sub ctx_statement_level { + my ($linenr, $remain, $off) = @_; + + return ctx_block_get($linenr, $remain, 0, '(', ')', $off); +} + +sub ctx_locate_comment { + my ($first_line, $end_line) = @_; + + # Catch a comment on the end of the line itself. + my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@); + return $current_comment if (defined $current_comment); + + # Look through the context and try and figure out if there is a + # comment. + my $in_comment = 0; + $current_comment = ''; + for (my $linenr = $first_line; $linenr < $end_line; $linenr++) { + my $line = $rawlines[$linenr - 1]; + #warn " $line\n"; + if ($linenr == $first_line and $line =~ m@^.\s*\*@) { + $in_comment = 1; + } + if ($line =~ m@/\*@) { + $in_comment = 1; + } + if (!$in_comment && $current_comment ne '') { + $current_comment = ''; + } + $current_comment .= $line . "\n" if ($in_comment); + if ($line =~ m@\*/@) { + $in_comment = 0; + } + } + + chomp($current_comment); + return($current_comment); +} +sub ctx_has_comment { + my ($first_line, $end_line) = @_; + my $cmt = ctx_locate_comment($first_line, $end_line); + + ##print "LINE: $rawlines[$end_line - 1 ]\n"; + ##print "CMMT: $cmt\n"; + + return ($cmt ne ''); +} + +sub raw_line { + my ($linenr, $cnt) = @_; + + my $offset = $linenr - 1; + $cnt++; + + my $line; + while ($cnt) { + $line = $rawlines[$offset++]; + next if (defined($line) && $line =~ /^-/); + $cnt--; + } + + return $line; +} + +sub cat_vet { + my ($vet) = @_; + my ($res, $coded); + + $res = ''; + while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) { + $res .= $1; + if ($2 ne '') { + $coded = sprintf("^%c", unpack('C', $2) + 64); + $res .= $coded; + } + } + $res =~ s/$/\$/; + + return $res; +} + +my $av_preprocessor = 0; +my $av_pending; +my @av_paren_type; +my $av_pend_colon; + +sub annotate_reset { + $av_preprocessor = 0; + $av_pending = '_'; + @av_paren_type = ('E'); + $av_pend_colon = 'O'; +} + +sub annotate_values { + my ($stream, $type) = @_; + + my $res; + my $var = '_' x length($stream); + my $cur = $stream; + + print "$stream\n" if ($dbg_values > 1); + + while (length($cur)) { + @av_paren_type = ('E') if ($#av_paren_type < 0); + print " <" . join('', @av_paren_type) . + "> <$type> <$av_pending>" if ($dbg_values > 1); + if ($cur =~ /^(\s+)/o) { + print "WS($1)\n" if ($dbg_values > 1); + if ($1 =~ /\n/ && $av_preprocessor) { + $type = pop(@av_paren_type); + $av_preprocessor = 0; + } + + } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') { + print "CAST($1)\n" if ($dbg_values > 1); + push(@av_paren_type, $type); + $type = 'c'; + + } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) { + print "DECLARE($1)\n" if ($dbg_values > 1); + $type = 'T'; + + } elsif ($cur =~ /^($Modifier)\s*/) { + print "MODIFIER($1)\n" if ($dbg_values > 1); + $type = 'T'; + + } elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) { + print "DEFINE($1,$2)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + push(@av_paren_type, $type); + if ($2 ne '') { + $av_pending = 'N'; + } + $type = 'E'; + + } elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) { + print "UNDEF($1)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + push(@av_paren_type, $type); + + } elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) { + print "PRE_START($1)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + + push(@av_paren_type, $type); + push(@av_paren_type, $type); + $type = 'E'; + + } elsif ($cur =~ /^(\#\s*(?:else|elif))/o) { + print "PRE_RESTART($1)\n" if ($dbg_values > 1); + $av_preprocessor = 1; + + push(@av_paren_type, $av_paren_type[$#av_paren_type]); + + $type = 'E'; + + } elsif ($cur =~ /^(\#\s*(?:endif))/o) { + print "PRE_END($1)\n" if ($dbg_values > 1); + + $av_preprocessor = 1; + + # Assume all arms of the conditional end as this + # one does, and continue as if the #endif was not here. + pop(@av_paren_type); + push(@av_paren_type, $type); + $type = 'E'; + + } elsif ($cur =~ /^(\\\n)/o) { + print "PRECONT($1)\n" if ($dbg_values > 1); + + } elsif ($cur =~ /^(__attribute__)\s*\(?/o) { + print "ATTR($1)\n" if ($dbg_values > 1); + $av_pending = $type; + $type = 'N'; + + } elsif ($cur =~ /^(sizeof)\s*(\()?/o) { + print "SIZEOF($1)\n" if ($dbg_values > 1); + if (defined $2) { + $av_pending = 'V'; + } + $type = 'N'; + + } elsif ($cur =~ /^(if|while|for)\b/o) { + print "COND($1)\n" if ($dbg_values > 1); + $av_pending = 'E'; + $type = 'N'; + + } elsif ($cur =~/^(case)/o) { + print "CASE($1)\n" if ($dbg_values > 1); + $av_pend_colon = 'C'; + $type = 'N'; + + } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) { + print "KEYWORD($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~ /^(\()/o) { + print "PAREN('$1')\n" if ($dbg_values > 1); + push(@av_paren_type, $av_pending); + $av_pending = '_'; + $type = 'N'; + + } elsif ($cur =~ /^(\))/o) { + my $new_type = pop(@av_paren_type); + if ($new_type ne '_') { + $type = $new_type; + print "PAREN('$1') -> $type\n" + if ($dbg_values > 1); + } else { + print "PAREN('$1')\n" if ($dbg_values > 1); + } + + } elsif ($cur =~ /^($Ident)\s*\(/o) { + print "FUNC($1)\n" if ($dbg_values > 1); + $type = 'V'; + $av_pending = 'V'; + + } elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) { + if (defined $2 && $type eq 'C' || $type eq 'T') { + $av_pend_colon = 'B'; + } elsif ($type eq 'E') { + $av_pend_colon = 'L'; + } + print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1); + $type = 'V'; + + } elsif ($cur =~ /^($Ident|$Constant)/o) { + print "IDENT($1)\n" if ($dbg_values > 1); + $type = 'V'; + + } elsif ($cur =~ /^($Assignment)/o) { + print "ASSIGN($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~/^(;|{|})/) { + print "END($1)\n" if ($dbg_values > 1); + $type = 'E'; + $av_pend_colon = 'O'; + + } elsif ($cur =~/^(,)/) { + print "COMMA($1)\n" if ($dbg_values > 1); + $type = 'C'; + + } elsif ($cur =~ /^(\?)/o) { + print "QUESTION($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~ /^(:)/o) { + print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1); + + substr($var, length($res), 1, $av_pend_colon); + if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') { + $type = 'E'; + } else { + $type = 'N'; + } + $av_pend_colon = 'O'; + + } elsif ($cur =~ /^(\[)/o) { + print "CLOSE($1)\n" if ($dbg_values > 1); + $type = 'N'; + + } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) { + my $variant; + + print "OPV($1)\n" if ($dbg_values > 1); + if ($type eq 'V') { + $variant = 'B'; + } else { + $variant = 'U'; + } + + substr($var, length($res), 1, $variant); + $type = 'N'; + + } elsif ($cur =~ /^($Operators)/o) { + print "OP($1)\n" if ($dbg_values > 1); + if ($1 ne '++' && $1 ne '--') { + $type = 'N'; + } + + } elsif ($cur =~ /(^.)/o) { + print "C($1)\n" if ($dbg_values > 1); + } + if (defined $1) { + $cur = substr($cur, length($1)); + $res .= $type x length($1); + } + } + + return ($res, $var); +} + +sub possible { + my ($possible, $line) = @_; + my $notPermitted = qr{(?: + ^(?: + $Modifier| + $Storage| + $Type| + DEFINE_\S+ + )$| + ^(?: + goto| + return| + case| + else| + asm|__asm__| + do| + \#| + \#\#| + )(?:\s|$)| + ^(?:typedef|struct|enum)\b + )}x; + warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2); + if ($possible !~ $notPermitted) { + # Check for modifiers. + $possible =~ s/\s*$Storage\s*//g; + $possible =~ s/\s*$Sparse\s*//g; + if ($possible =~ /^\s*$/) { + + } elsif ($possible =~ /\s/) { + $possible =~ s/\s*$Type\s*//g; + for my $modifier (split(' ', $possible)) { + if ($modifier !~ $notPermitted) { + warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible); + push(@modifierListFile, $modifier); + } + } + + } else { + warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible); + push(@typeListFile, $possible); + } + build_types(); + } else { + warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1); + } +} + +my $prefix = ''; + +sub show_type { + my ($type) = @_; + + return defined $use_type{$type} if (scalar keys %use_type > 0); + + return !defined $ignore_type{$type}; +} + +sub report { + my ($level, $type, $msg) = @_; + + if (!show_type($type) || + (defined $tst_only && $msg !~ /\Q$tst_only\E/)) { + return 0; + } + my $output = ''; + if (-t STDOUT && $color) { + if ($level eq 'ERROR') { + $output .= RED; + } elsif ($level eq 'WARNING') { + $output .= YELLOW; + } else { + $output .= GREEN; + } + } + $output .= $prefix . $level . ':'; + if ($show_types) { + $output .= BLUE if (-t STDOUT && $color); + $output .= "$type:"; + } + $output .= RESET if (-t STDOUT && $color); + $output .= ' ' . $msg . "\n"; + + if ($showfile) { + my @lines = split("\n", $output, -1); + splice(@lines, 1, 1); + $output = join("\n", @lines); + } + $output = (split('\n', $output))[0] . "\n" if ($terse); + + push(our @report, $output); + + return 1; +} + +sub report_dump { + our @report; +} + +sub fixup_current_range { + my ($lineRef, $offset, $length) = @_; + + if ($$lineRef =~ /^\@\@ -\d+,\d+ \+(\d+),(\d+) \@\@/) { + my $o = $1; + my $l = $2; + my $no = $o + $offset; + my $nl = $l + $length; + $$lineRef =~ s/\+$o,$l \@\@/\+$no,$nl \@\@/; + } +} + +sub fix_inserted_deleted_lines { + my ($linesRef, $insertedRef, $deletedRef) = @_; + + my $range_last_linenr = 0; + my $delta_offset = 0; + + my $old_linenr = 0; + my $new_linenr = 0; + + my $next_insert = 0; + my $next_delete = 0; + + my @lines = (); + + my $inserted = @{$insertedRef}[$next_insert++]; + my $deleted = @{$deletedRef}[$next_delete++]; + + foreach my $old_line (@{$linesRef}) { + my $save_line = 1; + my $line = $old_line; #don't modify the array + if ($line =~ /^(?:\+\+\+|\-\-\-)\s+\S+/) { #new filename + $delta_offset = 0; + } elsif ($line =~ /^\@\@ -\d+,\d+ \+\d+,\d+ \@\@/) { #new hunk + $range_last_linenr = $new_linenr; + fixup_current_range(\$line, $delta_offset, 0); + } + + while (defined($deleted) && ${$deleted}{'LINENR'} == $old_linenr) { + $deleted = @{$deletedRef}[$next_delete++]; + $save_line = 0; + fixup_current_range(\$lines[$range_last_linenr], $delta_offset--, -1); + } + + while (defined($inserted) && ${$inserted}{'LINENR'} == $old_linenr) { + push(@lines, ${$inserted}{'LINE'}); + $inserted = @{$insertedRef}[$next_insert++]; + $new_linenr++; + fixup_current_range(\$lines[$range_last_linenr], $delta_offset++, 1); + } + + if ($save_line) { + push(@lines, $line); + $new_linenr++; + } + + $old_linenr++; + } + + return @lines; +} + +sub fix_insert_line { + my ($linenr, $line) = @_; + + my $inserted = { + LINENR => $linenr, + LINE => $line, + }; + push(@fixed_inserted, $inserted); +} + +sub fix_delete_line { + my ($linenr, $line) = @_; + + my $deleted = { + LINENR => $linenr, + LINE => $line, + }; + + push(@fixed_deleted, $deleted); +} + +sub ERROR { + my ($type, $msg) = @_; + + if (report("ERROR", $type, $msg)) { + our $clean = 0; + our $cnt_error++; + return 1; + } + return 0; +} +sub WARN { + my ($type, $msg) = @_; + + if (report("WARNING", $type, $msg)) { + our $clean = 0; + our $cnt_warn++; + return 1; + } + return 0; +} +sub CHK { + my ($type, $msg) = @_; + + if ($check && report("CHECK", $type, $msg)) { + our $clean = 0; + our $cnt_chk++; + return 1; + } + return 0; +} + +sub check_absolute_file { + my ($absolute, $herecurr) = @_; + my $file = $absolute; + + ##print "absolute<$absolute>\n"; + + # See if any suffix of this path is a path within the tree. + while ($file =~ s@^[^/]*/@@) { + if (-f "$root/$file") { + ##print "file<$file>\n"; + last; + } + } + if (! -f _) { + return 0; + } + + # It is, so see if the prefix is acceptable. + my $prefix = $absolute; + substr($prefix, -length($file)) = ''; + + ##print "prefix<$prefix>\n"; + if ($prefix ne ".../") { + WARN("USE_RELATIVE_PATH", + "use relative pathname instead of absolute in changelog text\n" . $herecurr); + } +} + +sub trim { + my ($string) = @_; + + $string =~ s/^\s+|\s+$//g; + + return $string; +} + +sub ltrim { + my ($string) = @_; + + $string =~ s/^\s+//; + + return $string; +} + +sub rtrim { + my ($string) = @_; + + $string =~ s/\s+$//; + + return $string; +} + +sub string_find_replace { + my ($string, $find, $replace) = @_; + + $string =~ s/$find/$replace/g; + + return $string; +} + +sub tabify { + my ($leading) = @_; + + my $source_indent = 8; + my $max_spaces_before_tab = $source_indent - 1; + my $spaces_to_tab = " " x $source_indent; + + #convert leading spaces to tabs + 1 while $leading =~ s@^([\t]*)$spaces_to_tab@$1\t@g; + #Remove spaces before a tab + 1 while $leading =~ s@^([\t]*)( {1,$max_spaces_before_tab})\t@$1\t@g; + + return "$leading"; +} + +sub pos_last_openparen { + my ($line) = @_; + + my $pos = 0; + + my $opens = $line =~ tr/\(/\(/; + my $closes = $line =~ tr/\)/\)/; + + my $last_openparen = 0; + + if (($opens == 0) || ($closes >= $opens)) { + return -1; + } + + my $len = length($line); + + for ($pos = 0; $pos < $len; $pos++) { + my $string = substr($line, $pos); + if ($string =~ /^($FuncArg|$balanced_parens)/) { + $pos += length($1) - 1; + } elsif (substr($line, $pos, 1) eq '(') { + $last_openparen = $pos; + } elsif (index($string, '(') == -1) { + last; + } + } + + return length(expand_tabs(substr($line, 0, $last_openparen))) + 1; +} + +sub process { + my $filename = shift; + + my $linenr=0; + my $prevline=""; + my $prevrawline=""; + my $stashline=""; + my $stashrawline=""; + + my $length; + my $indent; + my $previndent=0; + my $stashindent=0; + + our $clean = 1; + my $signoff = 0; + my $is_patch = 0; + my $in_header_lines = $file ? 0 : 1; + my $in_commit_log = 0; #Scanning lines before patch + my $has_commit_log = 0; #Encountered lines before patch + my $commit_log_possible_stack_dump = 0; + my $commit_log_long_line = 0; + my $commit_log_has_diff = 0; + my $reported_maintainer_file = 0; + my $non_utf8_charset = 0; + + my $last_blank_line = 0; + my $last_coalesced_string_linenr = -1; + + our @report = (); + our $cnt_lines = 0; + our $cnt_error = 0; + our $cnt_warn = 0; + our $cnt_chk = 0; + + # Trace the real file/line as we go. + my $realfile = ''; + my $realline = 0; + my $realcnt = 0; + my $here = ''; + my $in_comment = 0; + my $comment_edge = 0; + my $first_line = 0; + my $p1_prefix = ''; + + my $prev_values = 'E'; + + # suppression flags + my %suppress_ifbraces; + my %suppress_whiletrailers; + my %suppress_export; + my $suppress_statement = 0; + + my %signatures = (); + + # Pre-scan the patch sanitizing the lines. + # Pre-scan the patch looking for any __setup documentation. + # + my @setup_docs = (); + my $setup_docs = 0; + + my $camelcase_file_seeded = 0; + + sanitise_line_reset(); + my $line; + foreach my $rawline (@rawlines) { + $linenr++; + $line = $rawline; + + push(@fixed, $rawline) if ($fix); + + if ($rawline=~/^\+\+\+\s+(\S+)/) { + $setup_docs = 0; + if ($1 =~ m@Documentation/kernel-parameters.txt$@) { + $setup_docs = 1; + } + #next; + } + if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { + $realline=$1-1; + if (defined $2) { + $realcnt=$3+1; + } else { + $realcnt=1+1; + } + $in_comment = 0; + + # Guestimate if this is a continuing comment. Run + # the context looking for a comment "edge". If this + # edge is a close comment then we must be in a comment + # at context start. + my $edge; + my $cnt = $realcnt; + for (my $ln = $linenr + 1; $cnt > 0; $ln++) { + next if (defined $rawlines[$ln - 1] && + $rawlines[$ln - 1] =~ /^-/); + $cnt--; + #print "RAW<$rawlines[$ln - 1]>\n"; + last if (!defined $rawlines[$ln - 1]); + if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ && + $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) { + ($edge) = $1; + last; + } + } + if (defined $edge && $edge eq '*/') { + $in_comment = 1; + } + + # Guestimate if this is a continuing comment. If this + # is the start of a diff block and this line starts + # ' *' then it is very likely a comment. + if (!defined $edge && + $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@) + { + $in_comment = 1; + } + + ##print "COMMENT:$in_comment edge<$edge> $rawline\n"; + sanitise_line_reset($in_comment); + + } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) { + # Standardise the strings and chars within the input to + # simplify matching -- only bother with positive lines. + $line = sanitise_line($rawline); + } + push(@lines, $line); + + if ($realcnt > 1) { + $realcnt-- if ($line =~ /^(?:\+| |$)/); + } else { + $realcnt = 0; + } + + #print "==>$rawline\n"; + #print "-->$line\n"; + + if ($setup_docs && $line =~ /^\+/) { + push(@setup_docs, $line); + } + } + + $prefix = ''; + + $realcnt = 0; + $linenr = 0; + $fixlinenr = -1; + foreach my $line (@lines) { + $linenr++; + $fixlinenr++; + my $sline = $line; #copy of $line + $sline =~ s/$;/ /g; #with comments as spaces + + my $rawline = $rawlines[$linenr - 1]; + +#extract the line range in the file after the patch is applied + if (!$in_commit_log && + $line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { + $is_patch = 1; + $first_line = $linenr + 1; + $realline=$1-1; + if (defined $2) { + $realcnt=$3+1; + } else { + $realcnt=1+1; + } + annotate_reset(); + $prev_values = 'E'; + + %suppress_ifbraces = (); + %suppress_whiletrailers = (); + %suppress_export = (); + $suppress_statement = 0; + next; + +# track the line number as we move through the hunk, note that +# new versions of GNU diff omit the leading space on completely +# blank context lines so we need to count that too. + } elsif ($line =~ /^( |\+|$)/) { + $realline++; + $realcnt-- if ($realcnt != 0); + + # Measure the line length and indent. + ($length, $indent) = line_stats($rawline); + + # Track the previous line. + ($prevline, $stashline) = ($stashline, $line); + ($previndent, $stashindent) = ($stashindent, $indent); + ($prevrawline, $stashrawline) = ($stashrawline, $rawline); + + #warn "line<$line>\n"; + + } elsif ($realcnt == 1) { + $realcnt--; + } + + my $hunk_line = ($realcnt != 0); + + $here = "#$linenr: " if (!$file); + $here = "#$realline: " if ($file); + + my $found_file = 0; + # extract the filename as it passes + if ($line =~ /^diff --git.*?(\S+)$/) { + $realfile = $1; + $realfile =~ s@^([^/]*)/@@ if (!$file); + $in_commit_log = 0; + $found_file = 1; + } elsif ($line =~ /^\+\+\+\s+(\S+)/) { + $realfile = $1; + $realfile =~ s@^([^/]*)/@@ if (!$file); + $in_commit_log = 0; + + $p1_prefix = $1; + if (!$file && $tree && $p1_prefix ne '' && + -e "$root/$p1_prefix") { + WARN("PATCH_PREFIX", + "patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n"); + } + + if ($realfile =~ m@^include/asm/@) { + ERROR("MODIFIED_INCLUDE_ASM", + "do not modify files in include/asm, change architecture specific files in include/asm-\n" . "$here$rawline\n"); + } + $found_file = 1; + } + +#make up the handle for any error we report on this line + if ($showfile) { + $prefix = "$realfile:$realline: " + } elsif ($emacs) { + if ($file) { + $prefix = "$filename:$realline: "; + } else { + $prefix = "$filename:$linenr: "; + } + } + + if ($found_file) { + if (is_maintained_obsolete($realfile)) { + WARN("OBSOLETE", + "$realfile is marked as 'obsolete' in the MAINTAINERS hierarchy. No unnecessary modifications please.\n"); + } + if ($realfile =~ m@^(?:drivers/net/|net/|drivers/staging/)@) { + $check = 1; + } else { + $check = $check_orig; + } + next; + } + + $here .= "FILE: $realfile:$realline:" if ($realcnt != 0); + + my $hereline = "$here\n$rawline\n"; + my $herecurr = "$here\n$rawline\n"; + my $hereprev = "$here\n$prevrawline\n$rawline\n"; + + $cnt_lines++ if ($realcnt != 0); + +# Check if the commit log has what seems like a diff which can confuse patch + if ($in_commit_log && !$commit_log_has_diff && + (($line =~ m@^\s+diff\b.*a/[\w/]+@ && + $line =~ m@^\s+diff\b.*a/([\w/]+)\s+b/$1\b@) || + $line =~ m@^\s*(?:\-\-\-\s+a/|\+\+\+\s+b/)@ || + $line =~ m/^\s*\@\@ \-\d+,\d+ \+\d+,\d+ \@\@/)) { + ERROR("DIFF_IN_COMMIT_MSG", + "Avoid using diff content in the commit message - patch(1) might not work\n" . $herecurr); + $commit_log_has_diff = 1; + } + +# Check for incorrect file permissions + if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) { + my $permhere = $here . "FILE: $realfile\n"; + if ($realfile !~ m@scripts/@ && + $realfile !~ /\.(py|pl|awk|sh)$/) { + ERROR("EXECUTE_PERMISSIONS", + "do not set execute permissions for source files\n" . $permhere); + } + } + +# Check the patch for a signoff: + if ($line =~ /^\s*signed-off-by:/i) { + $signoff++; + $in_commit_log = 0; + } + +# Check if MAINTAINERS is being updated. If so, there's probably no need to +# emit the "does MAINTAINERS need updating?" message on file add/move/delete + if ($line =~ /^\s*MAINTAINERS\s*\|/) { + $reported_maintainer_file = 1; + } + +# Check signature styles + if (!$in_header_lines && + $line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) { + my $space_before = $1; + my $sign_off = $2; + my $space_after = $3; + my $email = $4; + my $ucfirst_sign_off = ucfirst(lc($sign_off)); + + if ($sign_off !~ /$signature_tags/) { + WARN("BAD_SIGN_OFF", + "Non-standard signature: $sign_off\n" . $herecurr); + } + if (defined $space_before && $space_before ne "") { + if (WARN("BAD_SIGN_OFF", + "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = + "$ucfirst_sign_off $email"; + } + } + if ($sign_off =~ /-by:$/i && $sign_off ne $ucfirst_sign_off) { + if (WARN("BAD_SIGN_OFF", + "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = + "$ucfirst_sign_off $email"; + } + + } + if (!defined $space_after || $space_after ne " ") { + if (WARN("BAD_SIGN_OFF", + "Use a single space after $ucfirst_sign_off\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = + "$ucfirst_sign_off $email"; + } + } + + my ($email_name, $email_address, $comment) = parse_email($email); + my $suggested_email = format_email(($email_name, $email_address)); + if ($suggested_email eq "") { + ERROR("BAD_SIGN_OFF", + "Unrecognized email address: '$email'\n" . $herecurr); + } else { + my $dequoted = $suggested_email; + $dequoted =~ s/^"//; + $dequoted =~ s/" $comment" ne $email && + "$suggested_email$comment" ne $email) { + WARN("BAD_SIGN_OFF", + "email address '$email' might be better as '$suggested_email$comment'\n" . $herecurr); + } + } + +# Check for duplicate signatures + my $sig_nospace = $line; + $sig_nospace =~ s/\s//g; + $sig_nospace = lc($sig_nospace); + if (defined $signatures{$sig_nospace}) { + WARN("BAD_SIGN_OFF", + "Duplicate signature\n" . $herecurr); + } else { + $signatures{$sig_nospace} = 1; + } + } + +# Check email subject for common tools that don't need to be mentioned + if ($in_header_lines && + $line =~ /^Subject:.*\b(?:checkpatch|sparse|smatch)\b[^:]/i) { + WARN("EMAIL_SUBJECT", + "A patch subject line should describe the change not the tool that found it\n" . $herecurr); + } + +# Check for old stable address + if ($line =~ /^\s*cc:\s*.*?.*$/i) { + ERROR("STABLE_ADDRESS", + "The 'stable' address should be 'stable\@vger.kernel.org'\n" . $herecurr); + } + +# Check for unwanted Gerrit info + if ($in_commit_log && $line =~ /^\s*change-id:/i) { + ERROR("GERRIT_CHANGE_ID", + "Remove Gerrit Change-Id's before submitting upstream.\n" . $herecurr); + } + +# Check if the commit log is in a possible stack dump + if ($in_commit_log && !$commit_log_possible_stack_dump && + ($line =~ /^\s*(?:WARNING:|BUG:)/ || + $line =~ /^\s*\[\s*\d+\.\d{6,6}\s*\]/ || + # timestamp + $line =~ /^\s*\[\<[0-9a-fA-F]{8,}\>\]/)) { + # stack dump address + $commit_log_possible_stack_dump = 1; + } + +# Check for line lengths > 75 in commit log, warn once + if ($in_commit_log && !$commit_log_long_line && + length($line) > 75 && + !($line =~ /^\s*[a-zA-Z0-9_\/\.]+\s+\|\s+\d+/ || + # file delta changes + $line =~ /^\s*(?:[\w\.\-]+\/)++[\w\.\-]+:/ || + # filename then : + $line =~ /^\s*(?:Fixes:|Link:)/i || + # A Fixes: or Link: line + $commit_log_possible_stack_dump)) { + WARN("COMMIT_LOG_LONG_LINE", + "Possible unwrapped commit description (prefer a maximum 75 chars per line)\n" . $herecurr); + $commit_log_long_line = 1; + } + +# Reset possible stack dump if a blank line is found + if ($in_commit_log && $commit_log_possible_stack_dump && + $line =~ /^\s*$/) { + $commit_log_possible_stack_dump = 0; + } + +# Check for git id commit length and improperly formed commit descriptions + if ($in_commit_log && !$commit_log_possible_stack_dump && + $line !~ /^\s*(?:Link|Patchwork|http|https|BugLink):/i && + ($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i || + ($line =~ /(?:\s|^)[0-9a-f]{12,40}(?:[\s"'\(\[]|$)/i && + $line !~ /[\<\[][0-9a-f]{12,40}[\>\]]/i && + $line !~ /\bfixes:\s*[0-9a-f]{12,40}/i))) { + my $init_char = "c"; + my $orig_commit = ""; + my $short = 1; + my $long = 0; + my $case = 1; + my $space = 1; + my $hasdesc = 0; + my $hasparens = 0; + my $id = '0123456789ab'; + my $orig_desc = "commit description"; + my $description = ""; + + if ($line =~ /\b(c)ommit\s+([0-9a-f]{5,})\b/i) { + $init_char = $1; + $orig_commit = lc($2); + } elsif ($line =~ /\b([0-9a-f]{12,40})\b/i) { + $orig_commit = lc($1); + } + + $short = 0 if ($line =~ /\bcommit\s+[0-9a-f]{12,40}/i); + $long = 1 if ($line =~ /\bcommit\s+[0-9a-f]{41,}/i); + $space = 0 if ($line =~ /\bcommit [0-9a-f]/i); + $case = 0 if ($line =~ /\b[Cc]ommit\s+[0-9a-f]{5,40}[^A-F]/); + if ($line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("([^"]+)"\)/i) { + $orig_desc = $1; + $hasparens = 1; + } elsif ($line =~ /\bcommit\s+[0-9a-f]{5,}\s*$/i && + defined $rawlines[$linenr] && + $rawlines[$linenr] =~ /^\s*\("([^"]+)"\)/) { + $orig_desc = $1; + $hasparens = 1; + } elsif ($line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("[^"]+$/i && + defined $rawlines[$linenr] && + $rawlines[$linenr] =~ /^\s*[^"]+"\)/) { + $line =~ /\bcommit\s+[0-9a-f]{5,}\s+\("([^"]+)$/i; + $orig_desc = $1; + $rawlines[$linenr] =~ /^\s*([^"]+)"\)/; + $orig_desc .= " " . $1; + $hasparens = 1; + } + + ($id, $description) = git_commit_info($orig_commit, + $id, $orig_desc); + + if ($short || $long || $space || $case || ($orig_desc ne $description) || !$hasparens) { + ERROR("GIT_COMMIT_ID", + "Please use git commit description style 'commit <12+ chars of sha1> (\"\")' - ie: '${init_char}ommit $id (\"$description\")'\n" . $herecurr); + } + } + +# Check for added, moved or deleted files + if (!$reported_maintainer_file && !$in_commit_log && + ($line =~ /^(?:new|deleted) file mode\s*\d+\s*$/ || + $line =~ /^rename (?:from|to) [\w\/\.\-]+\s*$/ || + ($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ && + (defined($1) || defined($2))))) { + $reported_maintainer_file = 1; + WARN("FILE_PATH_CHANGES", + "added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr); + } + +# Check for wrappage within a valid hunk of the file + if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { + ERROR("CORRUPTED_PATCH", + "patch seems to be corrupt (line wrapped?)\n" . + $herecurr) if (!$emitted_corrupt++); + } + +# Check for absolute kernel paths. + if ($tree) { + while ($line =~ m{(?:^|\s)(/\S*)}g) { + my $file = $1; + + if ($file =~ m{^(.*?)(?::\d+)+:?$} && + check_absolute_file($1, $herecurr)) { + # + } else { + check_absolute_file($file, $herecurr); + } + } + } + +# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php + if (($realfile =~ /^$/ || $line =~ /^\+/) && + $rawline !~ m/^$UTF8*$/) { + my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/); + + my $blank = copy_spacing($rawline); + my $ptr = substr($blank, 0, length($utf8_prefix)) . "^"; + my $hereptr = "$hereline$ptr\n"; + + CHK("INVALID_UTF8", + "Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr); + } + +# Check if it's the start of a commit log +# (not a header line and we haven't seen the patch filename) + if ($in_header_lines && $realfile =~ /^$/ && + !($rawline =~ /^\s+\S/ || + $rawline =~ /^(commit\b|from\b|[\w-]+:).*$/i)) { + $in_header_lines = 0; + $in_commit_log = 1; + $has_commit_log = 1; + } + +# Check if there is UTF-8 in a commit log when a mail header has explicitly +# declined it, i.e defined some charset where it is missing. + if ($in_header_lines && + $rawline =~ /^Content-Type:.+charset="(.+)".*$/ && + $1 !~ /utf-8/i) { + $non_utf8_charset = 1; + } + + if ($in_commit_log && $non_utf8_charset && $realfile =~ /^$/ && + $rawline =~ /$NON_ASCII_UTF8/) { + WARN("UTF8_BEFORE_PATCH", + "8-bit UTF-8 used in possible commit log\n" . $herecurr); + } + +# Check for various typo / spelling mistakes + if (defined($misspellings) && + ($in_commit_log || $line =~ /^(?:\+|Subject:)/i)) { + while ($rawline =~ /(?:^|[^a-z@])($misspellings)(?:\b|$|[^a-z@])/gi) { + my $typo = $1; + my $typo_fix = $spelling_fix{lc($typo)}; + $typo_fix = ucfirst($typo_fix) if ($typo =~ /^[A-Z]/); + $typo_fix = uc($typo_fix) if ($typo =~ /^[A-Z]+$/); + my $msg_type = \&WARN; + $msg_type = \&CHK if ($file); + if (&{$msg_type}("TYPO_SPELLING", + "'$typo' may be misspelled - perhaps '$typo_fix'?\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(^|[^A-Za-z@])($typo)($|[^A-Za-z@])/$1$typo_fix$3/; + } + } + } + +# ignore non-hunk lines and lines being removed + next if (!$hunk_line || $line =~ /^-/); + +#trailing whitespace + if ($line =~ /^\+.*\015/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + if (ERROR("DOS_LINE_ENDINGS", + "DOS line endings\n" . $herevet) && + $fix) { + $fixed[$fixlinenr] =~ s/[\s\015]+$//; + } + } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + if (ERROR("TRAILING_WHITESPACE", + "trailing whitespace\n" . $herevet) && + $fix) { + $fixed[$fixlinenr] =~ s/\s+$//; + } + + $rpt_cleaners = 1; + } + +# Check for FSF mailing addresses. + if ($rawline =~ /\bwrite to the Free/i || + $rawline =~ /\b59\s+Temple\s+Pl/i || + $rawline =~ /\b51\s+Franklin\s+St/i) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + my $msg_type = \&ERROR; + $msg_type = \&CHK if ($file); + &{$msg_type}("FSF_MAILING_ADDRESS", + "Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.\n" . $herevet) + } + +# check for Kconfig help text having a real description +# Only applies when adding the entry originally, after that we do not have +# sufficient context to determine whether it is indeed long enough. + if ($realfile =~ /Kconfig/ && + $line =~ /^\+\s*config\s+/) { + my $length = 0; + my $cnt = $realcnt; + my $ln = $linenr + 1; + my $f; + my $is_start = 0; + my $is_end = 0; + for (; $cnt > 0 && defined $lines[$ln - 1]; $ln++) { + $f = $lines[$ln - 1]; + $cnt-- if ($lines[$ln - 1] !~ /^-/); + $is_end = $lines[$ln - 1] =~ /^\+/; + + next if ($f =~ /^-/); + last if (!$file && $f =~ /^\@\@/); + + if ($lines[$ln - 1] =~ /^\+\s*(?:bool|tristate)\s*\"/) { + $is_start = 1; + } elsif ($lines[$ln - 1] =~ /^\+\s*(?:---)?help(?:---)?$/) { + $length = -1; + } + + $f =~ s/^.//; + $f =~ s/#.*//; + $f =~ s/^\s+//; + next if ($f =~ /^$/); + if ($f =~ /^\s*config\s/) { + $is_end = 1; + last; + } + $length++; + } + if ($is_start && $is_end && $length < $min_conf_desc_length) { + WARN("CONFIG_DESCRIPTION", + "please write a paragraph that describes the config symbol fully\n" . $herecurr); + } + #print "is_start<$is_start> is_end<$is_end> length<$length>\n"; + } + +# discourage the addition of CONFIG_EXPERIMENTAL in Kconfig. + if ($realfile =~ /Kconfig/ && + $line =~ /.\s*depends on\s+.*\bEXPERIMENTAL\b/) { + WARN("CONFIG_EXPERIMENTAL", + "Use of CONFIG_EXPERIMENTAL is deprecated. For alternatives, see https://lkml.org/lkml/2012/10/23/580\n"); + } + +# discourage the use of boolean for type definition attributes of Kconfig options + if ($realfile =~ /Kconfig/ && + $line =~ /^\+\s*\bboolean\b/) { + WARN("CONFIG_TYPE_BOOLEAN", + "Use of boolean is deprecated, please use bool instead.\n" . $herecurr); + } + + if (($realfile =~ /Makefile.*/ || $realfile =~ /Kbuild.*/) && + ($line =~ /\+(EXTRA_[A-Z]+FLAGS).*/)) { + my $flag = $1; + my $replacement = { + 'EXTRA_AFLAGS' => 'asflags-y', + 'EXTRA_CFLAGS' => 'ccflags-y', + 'EXTRA_CPPFLAGS' => 'cppflags-y', + 'EXTRA_LDFLAGS' => 'ldflags-y', + }; + + WARN("DEPRECATED_VARIABLE", + "Use of $flag is deprecated, please use \`$replacement->{$flag} instead.\n" . $herecurr) if ($replacement->{$flag}); + } + +# check for DT compatible documentation + if (defined $root && + (($realfile =~ /\.dtsi?$/ && $line =~ /^\+\s*compatible\s*=\s*\"/) || + ($realfile =~ /\.[ch]$/ && $line =~ /^\+.*\.compatible\s*=\s*\"/))) { + + my @compats = $rawline =~ /\"([a-zA-Z0-9\-\,\.\+_]+)\"/g; + + my $dt_path = $root . "/Documentation/devicetree/bindings/"; + my $vp_file = $dt_path . "vendor-prefixes.txt"; + + foreach my $compat (@compats) { + my $compat2 = $compat; + $compat2 =~ s/\,[a-zA-Z0-9]*\-/\,<\.\*>\-/; + my $compat3 = $compat; + $compat3 =~ s/\,([a-z]*)[0-9]*\-/\,$1<\.\*>\-/; + `grep -Erq "$compat|$compat2|$compat3" $dt_path`; + if ( $? >> 8 ) { + WARN("UNDOCUMENTED_DT_STRING", + "DT compatible string \"$compat\" appears un-documented -- check $dt_path\n" . $herecurr); + } + + next if $compat !~ /^([a-zA-Z0-9\-]+)\,/; + my $vendor = $1; + `grep -Eq "^$vendor\\b" $vp_file`; + if ( $? >> 8 ) { + WARN("UNDOCUMENTED_DT_STRING", + "DT compatible string vendor \"$vendor\" appears un-documented -- check $vp_file\n" . $herecurr); + } + } + } + +# check we are in a valid source file if not then ignore this hunk + next if ($realfile !~ /\.(h|c|s|S|pl|sh|dtsi|dts)$/); + +# line length limit (with some exclusions) +# +# There are a few types of lines that may extend beyond $max_line_length: +# logging functions like pr_info that end in a string +# lines with a single string +# #defines that are a single string +# +# There are 3 different line length message types: +# LONG_LINE_COMMENT a comment starts before but extends beyond $max_linelength +# LONG_LINE_STRING a string starts before but extends beyond $max_line_length +# LONG_LINE all other lines longer than $max_line_length +# +# if LONG_LINE is ignored, the other 2 types are also ignored +# + + if ($line =~ /^\+/ && $length > $max_line_length) { + my $msg_type = "LONG_LINE"; + + # Check the allowed long line types first + + # logging functions that end in a string that starts + # before $max_line_length + if ($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(?:KERN_\S+\s*|[^"]*))?($String\s*(?:|,|\)\s*;)\s*)$/ && + length(expand_tabs(substr($line, 1, length($line) - length($1) - 1))) <= $max_line_length) { + $msg_type = ""; + + # lines with only strings (w/ possible termination) + # #defines with only strings + } elsif ($line =~ /^\+\s*$String\s*(?:\s*|,|\)\s*;)\s*$/ || + $line =~ /^\+\s*#\s*define\s+\w+\s+$String$/) { + $msg_type = ""; + + # EFI_GUID is another special case + } elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/) { + $msg_type = ""; + + # Otherwise set the alternate message types + + # a comment starts before $max_line_length + } elsif ($line =~ /($;[\s$;]*)$/ && + length(expand_tabs(substr($line, 1, length($line) - length($1) - 1))) <= $max_line_length) { + $msg_type = "LONG_LINE_COMMENT" + + # a quoted string starts before $max_line_length + } elsif ($sline =~ /\s*($String(?:\s*(?:\\|,\s*|\)\s*;\s*))?)$/ && + length(expand_tabs(substr($line, 1, length($line) - length($1) - 1))) <= $max_line_length) { + $msg_type = "LONG_LINE_STRING" + } + + if ($msg_type ne "" && + (show_type("LONG_LINE") || show_type($msg_type))) { + WARN($msg_type, + "line over $max_line_length characters\n" . $herecurr); + } + } + +# check for adding lines without a newline. + if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) { + WARN("MISSING_EOF_NEWLINE", + "adding a line without newline at end of file\n" . $herecurr); + } + +# Blackfin: use hi/lo macros + if ($realfile =~ m@arch/blackfin/.*\.S$@) { + if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) { + my $herevet = "$here\n" . cat_vet($line) . "\n"; + ERROR("LO_MACRO", + "use the LO() macro, not (... & 0xFFFF)\n" . $herevet); + } + if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) { + my $herevet = "$here\n" . cat_vet($line) . "\n"; + ERROR("HI_MACRO", + "use the HI() macro, not (... >> 16)\n" . $herevet); + } + } + +# check we are in a valid source file C or perl if not then ignore this hunk + next if ($realfile !~ /\.(h|c|pl|dtsi|dts)$/); + +# at the beginning of a line any tabs must come first and anything +# more than 8 must use tabs. + if ($rawline =~ /^\+\s* \t\s*\S/ || + $rawline =~ /^\+\s* \s*/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + $rpt_cleaners = 1; + if (ERROR("CODE_INDENT", + "code indent should use tabs where possible\n" . $herevet) && + $fix) { + $fixed[$fixlinenr] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e; + } + } + +# check for space before tabs. + if ($rawline =~ /^\+/ && $rawline =~ / \t/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + if (WARN("SPACE_BEFORE_TAB", + "please, no space before tabs\n" . $herevet) && + $fix) { + while ($fixed[$fixlinenr] =~ + s/(^\+.*) {8,8}\t/$1\t\t/) {} + while ($fixed[$fixlinenr] =~ + s/(^\+.*) +\t/$1\t/) {} + } + } + +# check for && or || at the start of a line + if ($rawline =~ /^\+\s*(&&|\|\|)/) { + CHK("LOGICAL_CONTINUATIONS", + "Logical continuations should be on the previous line\n" . $hereprev); + } + +# check indentation starts on a tab stop + if ($^V && $^V ge 5.10.0 && + $sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$))/) { + my $indent = length($1); + if ($indent % 8) { + if (WARN("TABSTOP", + "Statements should start on a tabstop\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s@(^\+\t+) +@$1 . "\t" x ($indent/8)@e; + } + } + } + +# check multi-line statement indentation matches previous line + if ($^V && $^V ge 5.10.0 && + $prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|$Ident\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) { + $prevline =~ /^\+(\t*)(.*)$/; + my $oldindent = $1; + my $rest = $2; + + my $pos = pos_last_openparen($rest); + if ($pos >= 0) { + $line =~ /^(\+| )([ \t]*)/; + my $newindent = $2; + + my $goodtabindent = $oldindent . + "\t" x ($pos / 8) . + " " x ($pos % 8); + my $goodspaceindent = $oldindent . " " x $pos; + + if ($newindent ne $goodtabindent && + $newindent ne $goodspaceindent) { + + if (CHK("PARENTHESIS_ALIGNMENT", + "Alignment should match open parenthesis\n" . $hereprev) && + $fix && $line =~ /^\+/) { + $fixed[$fixlinenr] =~ + s/^\+[ \t]*/\+$goodtabindent/; + } + } + } + } + +# check for space after cast like "(int) foo" or "(struct foo) bar" +# avoid checking a few false positives: +# "sizeof(<type>)" or "__alignof__(<type>)" +# function pointer declarations like "(*foo)(int) = bar;" +# structure definitions like "(struct foo) { 0 };" +# multiline macros that define functions +# known attributes or the __attribute__ keyword + if ($line =~ /^\+(.*)\(\s*$Type\s*\)([ \t]++)((?![={]|\\$|$Attribute|__attribute__))/ && + (!defined($1) || $1 !~ /\b(?:sizeof|__alignof__)\s*$/)) { + if (CHK("SPACING", + "No space is necessary after a cast\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/(\(\s*$Type\s*\))[ \t]+/$1/; + } + } + +# Block comment styles +# Networking with an initial /* + if ($realfile =~ m@^(drivers/net/|net/)@ && + $prevrawline =~ /^\+[ \t]*\/\*[ \t]*$/ && + $rawline =~ /^\+[ \t]*\*/ && + $realline > 2) { + WARN("NETWORKING_BLOCK_COMMENT_STYLE", + "networking block comments don't use an empty /* line, use /* Comment...\n" . $hereprev); + } + +# Block comments use * on subsequent lines + if ($prevline =~ /$;[ \t]*$/ && #ends in comment + $prevrawline =~ /^\+.*?\/\*/ && #starting /* + $prevrawline !~ /\*\/[ \t]*$/ && #no trailing */ + $rawline =~ /^\+/ && #line is new + $rawline !~ /^\+[ \t]*\*/) { #no leading * + WARN("BLOCK_COMMENT_STYLE", + "Block comments use * on subsequent lines\n" . $hereprev); + } + +# Block comments use */ on trailing lines + if ($rawline !~ m@^\+[ \t]*\*/[ \t]*$@ && #trailing */ + $rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/ + $rawline !~ m@^\+.*\*{2,}/[ \t]*$@ && #trailing **/ + $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { #non blank */ + WARN("BLOCK_COMMENT_STYLE", + "Block comments use a trailing */ on a separate line\n" . $herecurr); + } + +# Block comment * alignment + if ($prevline =~ /$;[ \t]*$/ && #ends in comment + $line =~ /^\+[ \t]*$;/ && #leading comment + $rawline =~ /^\+[ \t]*\*/ && #leading * + (($prevrawline =~ /^\+.*?\/\*/ && #leading /* + $prevrawline !~ /\*\/[ \t]*$/) || #no trailing */ + $prevrawline =~ /^\+[ \t]*\*/)) { #leading * + my $oldindent; + $prevrawline =~ m@^\+([ \t]*/?)\*@; + if (defined($1)) { + $oldindent = expand_tabs($1); + } else { + $prevrawline =~ m@^\+(.*/?)\*@; + $oldindent = expand_tabs($1); + } + $rawline =~ m@^\+([ \t]*)\*@; + my $newindent = $1; + $newindent = expand_tabs($newindent); + if (length($oldindent) ne length($newindent)) { + WARN("BLOCK_COMMENT_STYLE", + "Block comments should align the * on each line\n" . $hereprev); + } + } + +# check for missing blank lines after struct/union declarations +# with exceptions for various attributes and macros + if ($prevline =~ /^[\+ ]};?\s*$/ && + $line =~ /^\+/ && + !($line =~ /^\+\s*$/ || + $line =~ /^\+\s*EXPORT_SYMBOL/ || + $line =~ /^\+\s*MODULE_/i || + $line =~ /^\+\s*\#\s*(?:end|elif|else)/ || + $line =~ /^\+[a-z_]*init/ || + $line =~ /^\+\s*(?:static\s+)?[A-Z_]*ATTR/ || + $line =~ /^\+\s*DECLARE/ || + $line =~ /^\+\s*__setup/)) { + if (CHK("LINE_SPACING", + "Please use a blank line after function/struct/union/enum declarations\n" . $hereprev) && + $fix) { + fix_insert_line($fixlinenr, "\+"); + } + } + +# check for multiple consecutive blank lines + if ($prevline =~ /^[\+ ]\s*$/ && + $line =~ /^\+\s*$/ && + $last_blank_line != ($linenr - 1)) { + if (CHK("LINE_SPACING", + "Please don't use multiple blank lines\n" . $hereprev) && + $fix) { + fix_delete_line($fixlinenr, $rawline); + } + + $last_blank_line = $linenr; + } + +# check for missing blank lines after declarations + if ($sline =~ /^\+\s+\S/ && #Not at char 1 + # actual declarations + ($prevline =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ || + # function pointer declarations + $prevline =~ /^\+\s+$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(]/ || + # foo bar; where foo is some local typedef or #define + $prevline =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || + # known declaration macros + $prevline =~ /^\+\s+$declaration_macros/) && + # for "else if" which can look like "$Ident $Ident" + !($prevline =~ /^\+\s+$c90_Keywords\b/ || + # other possible extensions of declaration lines + $prevline =~ /(?:$Compare|$Assignment|$Operators)\s*$/ || + # not starting a section or a macro "\" extended line + $prevline =~ /(?:\{\s*|\\)$/) && + # looks like a declaration + !($sline =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ || + # function pointer declarations + $sline =~ /^\+\s+$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(]/ || + # foo bar; where foo is some local typedef or #define + $sline =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || + # known declaration macros + $sline =~ /^\+\s+$declaration_macros/ || + # start of struct or union or enum + $sline =~ /^\+\s+(?:union|struct|enum|typedef)\b/ || + # start or end of block or continuation of declaration + $sline =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(\[])/ || + # bitfield continuation + $sline =~ /^\+\s+$Ident\s*:\s*\d+\s*[,;]/ || + # other possible extensions of declaration lines + $sline =~ /^\+\s+\(?\s*(?:$Compare|$Assignment|$Operators)/) && + # indentation of previous and current line are the same + (($prevline =~ /\+(\s+)\S/) && $sline =~ /^\+$1\S/)) { + if (WARN("LINE_SPACING", + "Missing a blank line after declarations\n" . $hereprev) && + $fix) { + fix_insert_line($fixlinenr, "\+"); + } + } + +# check for spaces at the beginning of a line. +# Exceptions: +# 1) within comments +# 2) indented preprocessor commands +# 3) hanging labels + if ($rawline =~ /^\+ / && $line !~ /^\+ *(?:$;|#|$Ident:)/) { + my $herevet = "$here\n" . cat_vet($rawline) . "\n"; + if (WARN("LEADING_SPACE", + "please, no spaces at the start of a line\n" . $herevet) && + $fix) { + $fixed[$fixlinenr] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e; + } + } + +# check we are in a valid C source file if not then ignore this hunk + next if ($realfile !~ /\.(h|c)$/); + +# check indentation of any line with a bare else +# (but not if it is a multiple line "if (foo) return bar; else return baz;") +# if the previous line is a break or return and is indented 1 tab more... + if ($sline =~ /^\+([\t]+)(?:}[ \t]*)?else(?:[ \t]*{)?\s*$/) { + my $tabs = length($1) + 1; + if ($prevline =~ /^\+\t{$tabs,$tabs}break\b/ || + ($prevline =~ /^\+\t{$tabs,$tabs}return\b/ && + defined $lines[$linenr] && + $lines[$linenr] !~ /^[ \+]\t{$tabs,$tabs}return/)) { + WARN("UNNECESSARY_ELSE", + "else is not generally useful after a break or return\n" . $hereprev); + } + } + +# check indentation of a line with a break; +# if the previous line is a goto or return and is indented the same # of tabs + if ($sline =~ /^\+([\t]+)break\s*;\s*$/) { + my $tabs = $1; + if ($prevline =~ /^\+$tabs(?:goto|return)\b/) { + WARN("UNNECESSARY_BREAK", + "break is not useful after a goto or return\n" . $hereprev); + } + } + +# discourage the addition of CONFIG_EXPERIMENTAL in #if(def). + if ($line =~ /^\+\s*\#\s*if.*\bCONFIG_EXPERIMENTAL\b/) { + WARN("CONFIG_EXPERIMENTAL", + "Use of CONFIG_EXPERIMENTAL is deprecated. For alternatives, see https://lkml.org/lkml/2012/10/23/580\n"); + } + +# check for RCS/CVS revision markers + if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) { + WARN("CVS_KEYWORD", + "CVS style keyword markers, these will _not_ be updated\n". $herecurr); + } + +# Blackfin: don't use __builtin_bfin_[cs]sync + if ($line =~ /__builtin_bfin_csync/) { + my $herevet = "$here\n" . cat_vet($line) . "\n"; + ERROR("CSYNC", + "use the CSYNC() macro in asm/blackfin.h\n" . $herevet); + } + if ($line =~ /__builtin_bfin_ssync/) { + my $herevet = "$here\n" . cat_vet($line) . "\n"; + ERROR("SSYNC", + "use the SSYNC() macro in asm/blackfin.h\n" . $herevet); + } + +# check for old HOTPLUG __dev<foo> section markings + if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) { + WARN("HOTPLUG_SECTION", + "Using $1 is unnecessary\n" . $herecurr); + } + +# Check for potential 'bare' types + my ($stat, $cond, $line_nr_next, $remain_next, $off_next, + $realline_next); +#print "LINE<$line>\n"; + if ($linenr >= $suppress_statement && + $realcnt && $sline =~ /.\s*\S/) { + ($stat, $cond, $line_nr_next, $remain_next, $off_next) = + ctx_statement_block($linenr, $realcnt, 0); + $stat =~ s/\n./\n /g; + $cond =~ s/\n./\n /g; + +#print "linenr<$linenr> <$stat>\n"; + # If this statement has no statement boundaries within + # it there is no point in retrying a statement scan + # until we hit end of it. + my $frag = $stat; $frag =~ s/;+\s*$//; + if ($frag !~ /(?:{|;)/) { +#print "skip<$line_nr_next>\n"; + $suppress_statement = $line_nr_next; + } + + # Find the real next line. + $realline_next = $line_nr_next; + if (defined $realline_next && + (!defined $lines[$realline_next - 1] || + substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) { + $realline_next++; + } + + my $s = $stat; + $s =~ s/{.*$//s; + + # Ignore goto labels. + if ($s =~ /$Ident:\*$/s) { + + # Ignore functions being called + } elsif ($s =~ /^.\s*$Ident\s*\(/s) { + + } elsif ($s =~ /^.\s*else\b/s) { + + # declarations always start with types + } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) { + my $type = $1; + $type =~ s/\s+/ /g; + possible($type, "A:" . $s); + + # definitions in global scope can only start with types + } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) { + possible($1, "B:" . $s); + } + + # any (foo ... *) is a pointer cast, and foo is a type + while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) { + possible($1, "C:" . $s); + } + + # Check for any sort of function declaration. + # int foo(something bar, other baz); + # void (*store_gdt)(x86_descr_ptr *); + if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) { + my ($name_len) = length($1); + + my $ctx = $s; + substr($ctx, 0, $name_len + 1, ''); + $ctx =~ s/\)[^\)]*$//; + + for my $arg (split(/\s*,\s*/, $ctx)) { + if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) { + + possible($1, "D:" . $s); + } + } + } + + } + +# +# Checks which may be anchored in the context. +# + +# Check for switch () and associated case and default +# statements should be at the same indent. + if ($line=~/\bswitch\s*\(.*\)/) { + my $err = ''; + my $sep = ''; + my @ctx = ctx_block_outer($linenr, $realcnt); + shift(@ctx); + for my $ctx (@ctx) { + my ($clen, $cindent) = line_stats($ctx); + if ($ctx =~ /^\+\s*(case\s+|default:)/ && + $indent != $cindent) { + $err .= "$sep$ctx\n"; + $sep = ''; + } else { + $sep = "[...]\n"; + } + } + if ($err ne '') { + ERROR("SWITCH_CASE_INDENT_LEVEL", + "switch and case should be at the same indent\n$hereline$err"); + } + } + +# if/while/etc brace do not go on next line, unless defining a do while loop, +# or if that brace on the next line is for something else + if ($line =~ /(.*)\b((?:if|while|for|switch|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { + my $pre_ctx = "$1$2"; + + my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0); + + if ($line =~ /^\+\t{6,}/) { + WARN("DEEP_INDENTATION", + "Too many leading tabs - consider code refactoring\n" . $herecurr); + } + + my $ctx_cnt = $realcnt - $#ctx - 1; + my $ctx = join("\n", @ctx); + + my $ctx_ln = $linenr; + my $ctx_skip = $realcnt; + + while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt && + defined $lines[$ctx_ln - 1] && + $lines[$ctx_ln - 1] =~ /^-/)) { + ##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n"; + $ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/); + $ctx_ln++; + } + + #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n"; + #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n"; + + if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln - 1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) { + ERROR("OPEN_BRACE", + "that open brace { should be on the previous line\n" . + "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); + } + if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ && + $ctx =~ /\)\s*\;\s*$/ && + defined $lines[$ctx_ln - 1]) + { + my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]); + if ($nindent > $indent) { + WARN("TRAILING_SEMICOLON", + "trailing semicolon indicates no statements, indent implies otherwise\n" . + "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); + } + } + } + +# Check relative indent for conditionals and blocks. + if ($line =~ /\b(?:(?:if|while|for|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { + ($stat, $cond, $line_nr_next, $remain_next, $off_next) = + ctx_statement_block($linenr, $realcnt, 0) + if (!defined $stat); + my ($s, $c) = ($stat, $cond); + + substr($s, 0, length($c), ''); + + # remove inline comments + $s =~ s/$;/ /g; + $c =~ s/$;/ /g; + + # Find out how long the conditional actually is. + my @newlines = ($c =~ /\n/gs); + my $cond_lines = 1 + $#newlines; + + # Make sure we remove the line prefixes as we have + # none on the first line, and are going to readd them + # where necessary. + $s =~ s/\n./\n/gs; + while ($s =~ /\n\s+\\\n/) { + $cond_lines += $s =~ s/\n\s+\\\n/\n/g; + } + + # We want to check the first line inside the block + # starting at the end of the conditional, so remove: + # 1) any blank line termination + # 2) any opening brace { on end of the line + # 3) any do (...) { + my $continuation = 0; + my $check = 0; + $s =~ s/^.*\bdo\b//; + $s =~ s/^\s*{//; + if ($s =~ s/^\s*\\//) { + $continuation = 1; + } + if ($s =~ s/^\s*?\n//) { + $check = 1; + $cond_lines++; + } + + # Also ignore a loop construct at the end of a + # preprocessor statement. + if (($prevline =~ /^.\s*#\s*define\s/ || + $prevline =~ /\\\s*$/) && $continuation == 0) { + $check = 0; + } + + my $cond_ptr = -1; + $continuation = 0; + while ($cond_ptr != $cond_lines) { + $cond_ptr = $cond_lines; + + # If we see an #else/#elif then the code + # is not linear. + if ($s =~ /^\s*\#\s*(?:else|elif)/) { + $check = 0; + } + + # Ignore: + # 1) blank lines, they should be at 0, + # 2) preprocessor lines, and + # 3) labels. + if ($continuation || + $s =~ /^\s*?\n/ || + $s =~ /^\s*#\s*?/ || + $s =~ /^\s*$Ident\s*:/) { + $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0; + if ($s =~ s/^.*?\n//) { + $cond_lines++; + } + } + } + + my (undef, $sindent) = line_stats("+" . $s); + my $stat_real = raw_line($linenr, $cond_lines); + + # Check if either of these lines are modified, else + # this is not this patch's fault. + if (!defined($stat_real) || + $stat !~ /^\+/ && $stat_real !~ /^\+/) { + $check = 0; + } + if (defined($stat_real) && $cond_lines > 1) { + $stat_real = "[...]\n$stat_real"; + } + + #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n"; + + if ($check && $s ne '' && + (($sindent % 8) != 0 || + ($sindent < $indent) || + ($sindent > $indent + 8))) { + WARN("SUSPECT_CODE_INDENT", + "suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n"); + } + } + + # Track the 'values' across context and added lines. + my $opline = $line; $opline =~ s/^./ /; + my ($curr_values, $curr_vars) = + annotate_values($opline . "\n", $prev_values); + $curr_values = $prev_values . $curr_values; + if ($dbg_values) { + my $outline = $opline; $outline =~ s/\t/ /g; + print "$linenr > .$outline\n"; + print "$linenr > $curr_values\n"; + print "$linenr > $curr_vars\n"; + } + $prev_values = substr($curr_values, -1); + +#ignore lines not being added + next if ($line =~ /^[^\+]/); + +# check for declarations of signed or unsigned without int + while ($line =~ m{\b($Declare)\s*(?!char\b|short\b|int\b|long\b)\s*($Ident)?\s*[=,;\[\)\(]}g) { + my $type = $1; + my $var = $2; + $var = "" if (!defined $var); + if ($type =~ /^(?:(?:$Storage|$Inline|$Attribute)\s+)*((?:un)?signed)((?:\s*\*)*)\s*$/) { + my $sign = $1; + my $pointer = $2; + + $pointer = "" if (!defined $pointer); + + if (WARN("UNSPECIFIED_INT", + "Prefer '" . trim($sign) . " int" . rtrim($pointer) . "' to bare use of '$sign" . rtrim($pointer) . "'\n" . $herecurr) && + $fix) { + my $decl = trim($sign) . " int "; + my $comp_pointer = $pointer; + $comp_pointer =~ s/\s//g; + $decl .= $comp_pointer; + $decl = rtrim($decl) if ($var eq ""); + $fixed[$fixlinenr] =~ s@\b$sign\s*\Q$pointer\E\s*$var\b@$decl$var@; + } + } + } + +# TEST: allow direct testing of the type matcher. + if ($dbg_type) { + if ($line =~ /^.\s*$Declare\s*$/) { + ERROR("TEST_TYPE", + "TEST: is type\n" . $herecurr); + } elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) { + ERROR("TEST_NOT_TYPE", + "TEST: is not type ($1 is)\n". $herecurr); + } + next; + } +# TEST: allow direct testing of the attribute matcher. + if ($dbg_attr) { + if ($line =~ /^.\s*$Modifier\s*$/) { + ERROR("TEST_ATTR", + "TEST: is attr\n" . $herecurr); + } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) { + ERROR("TEST_NOT_ATTR", + "TEST: is not attr ($1 is)\n". $herecurr); + } + next; + } + +# check for initialisation to aggregates open brace on the next line + if ($line =~ /^.\s*{/ && + $prevline =~ /(?:^|[^=])=\s*$/) { + if (ERROR("OPEN_BRACE", + "that open brace { should be on the previous line\n" . $hereprev) && + $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = $prevrawline; + $fixedline =~ s/\s*=\s*$/ = {/; + fix_insert_line($fixlinenr, $fixedline); + $fixedline = $line; + $fixedline =~ s/^(.\s*){\s*/$1/; + fix_insert_line($fixlinenr, $fixedline); + } + } + +# +# Checks which are anchored on the added line. +# + +# check for malformed paths in #include statements (uses RAW line) + if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) { + my $path = $1; + if ($path =~ m{//}) { + ERROR("MALFORMED_INCLUDE", + "malformed #include filename\n" . $herecurr); + } + if ($path =~ "^uapi/" && $realfile =~ m@\binclude/uapi/@) { + ERROR("UAPI_INCLUDE", + "No #include in ...include/uapi/... should use a uapi/ path prefix\n" . $herecurr); + } + } + +# no C99 // comments + if ($line =~ m{//}) { + if (ERROR("C99_COMMENTS", + "do not use C99 // comments\n" . $herecurr) && + $fix) { + my $line = $fixed[$fixlinenr]; + if ($line =~ /\/\/(.*)$/) { + my $comment = trim($1); + $fixed[$fixlinenr] =~ s@\/\/(.*)$@/\* $comment \*/@; + } + } + } + # Remove C99 comments. + $line =~ s@//.*@@; + $opline =~ s@//.*@@; + +# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider +# the whole statement. +#print "APW <$lines[$realline_next - 1]>\n"; + if (defined $realline_next && + exists $lines[$realline_next - 1] && + !defined $suppress_export{$realline_next} && + ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ || + $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { + # Handle definitions which produce identifiers with + # a prefix: + # XXX(foo); + # EXPORT_SYMBOL(something_foo); + my $name = $1; + if ($stat =~ /^(?:.\s*}\s*\n)?.([A-Z_]+)\s*\(\s*($Ident)/ && + $name =~ /^${Ident}_$2/) { +#print "FOO C name<$name>\n"; + $suppress_export{$realline_next} = 1; + + } elsif ($stat !~ /(?: + \n.}\s*$| + ^.DEFINE_$Ident\(\Q$name\E\)| + ^.DECLARE_$Ident\(\Q$name\E\)| + ^.LIST_HEAD\(\Q$name\E\)| + ^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(| + \b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\() + )/x) { +#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n"; + $suppress_export{$realline_next} = 2; + } else { + $suppress_export{$realline_next} = 1; + } + } + if (!defined $suppress_export{$linenr} && + $prevline =~ /^.\s*$/ && + ($line =~ /EXPORT_SYMBOL.*\((.*)\)/ || + $line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) { +#print "FOO B <$lines[$linenr - 1]>\n"; + $suppress_export{$linenr} = 2; + } + if (defined $suppress_export{$linenr} && + $suppress_export{$linenr} == 2) { + WARN("EXPORT_SYMBOL", + "EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr); + } + +# check for global initialisers. + if ($line =~ /^\+$Type\s*$Ident(?:\s+$Modifier)*\s*=\s*($zero_initializer)\s*;/) { + if (ERROR("GLOBAL_INITIALISERS", + "do not initialise globals to $1\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(^.$Type\s*$Ident(?:\s+$Modifier)*)\s*=\s*$zero_initializer\s*;/$1;/; + } + } +# check for static initialisers. + if ($line =~ /^\+.*\bstatic\s.*=\s*($zero_initializer)\s*;/) { + if (ERROR("INITIALISED_STATIC", + "do not initialise statics to $1\n" . + $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(\bstatic\s.*?)\s*=\s*$zero_initializer\s*;/$1;/; + } + } + +# check for misordered declarations of char/short/int/long with signed/unsigned + while ($sline =~ m{(\b$TypeMisordered\b)}g) { + my $tmp = trim($1); + WARN("MISORDERED_TYPE", + "type '$tmp' should be specified in [[un]signed] [short|int|long|long long] order\n" . $herecurr); + } + +# check for static const char * arrays. + if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) { + WARN("STATIC_CONST_CHAR_ARRAY", + "static const char * array should probably be static const char * const\n" . + $herecurr); + } + +# check for static char foo[] = "bar" declarations. + if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) { + WARN("STATIC_CONST_CHAR_ARRAY", + "static char array declaration should probably be static const char\n" . + $herecurr); + } + +# check for const <foo> const where <foo> is not a pointer or array type + if ($sline =~ /\bconst\s+($BasicType)\s+const\b/) { + my $found = $1; + if ($sline =~ /\bconst\s+\Q$found\E\s+const\b\s*\*/) { + WARN("CONST_CONST", + "'const $found const *' should probably be 'const $found * const'\n" . $herecurr); + } elsif ($sline !~ /\bconst\s+\Q$found\E\s+const\s+\w+\s*\[/) { + WARN("CONST_CONST", + "'const $found const' should probably be 'const $found'\n" . $herecurr); + } + } + +# check for non-global char *foo[] = {"bar", ...} declarations. + if ($line =~ /^.\s+(?:static\s+|const\s+)?char\s+\*\s*\w+\s*\[\s*\]\s*=\s*\{/) { + WARN("STATIC_CONST_CHAR_ARRAY", + "char * array declaration might be better as static const\n" . + $herecurr); + } + +# check for sizeof(foo)/sizeof(foo[0]) that could be ARRAY_SIZE(foo) + if ($line =~ m@\bsizeof\s*\(\s*($Lval)\s*\)@) { + my $array = $1; + if ($line =~ m@\b(sizeof\s*\(\s*\Q$array\E\s*\)\s*/\s*sizeof\s*\(\s*\Q$array\E\s*\[\s*0\s*\]\s*\))@) { + my $array_div = $1; + if (WARN("ARRAY_SIZE", + "Prefer ARRAY_SIZE($array)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\Q$array_div\E/ARRAY_SIZE($array)/; + } + } + } + +# check for function declarations without arguments like "int foo()" + if ($line =~ /(\b$Type\s+$Ident)\s*\(\s*\)/) { + if (ERROR("FUNCTION_WITHOUT_ARGS", + "Bad function definition - $1() should probably be $1(void)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(\b($Type)\s+($Ident))\s*\(\s*\)/$2 $3(void)/; + } + } + +# check for new typedefs, only function parameters and sparse annotations +# make sense. + if ($line =~ /\btypedef\s/ && + $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && + $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && + $line !~ /\b$typeTypedefs\b/ && + $line !~ /\b__bitwise(?:__|)\b/) { + WARN("NEW_TYPEDEFS", + "do not add new typedefs\n" . $herecurr); + } + +# * goes on variable not on type + # (char*[ const]) + while ($line =~ m{(\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\))}g) { + #print "AA<$1>\n"; + my ($ident, $from, $to) = ($1, $2, $2); + + # Should start with a space. + $to =~ s/^(\S)/ $1/; + # Should not end with a space. + $to =~ s/\s+$//; + # '*'s should not have spaces between. + while ($to =~ s/\*\s+\*/\*\*/) { + } + +## print "1: from<$from> to<$to> ident<$ident>\n"; + if ($from ne $to) { + if (ERROR("POINTER_LOCATION", + "\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr) && + $fix) { + my $sub_from = $ident; + my $sub_to = $ident; + $sub_to =~ s/\Q$from\E/$to/; + $fixed[$fixlinenr] =~ + s@\Q$sub_from\E@$sub_to@; + } + } + } + while ($line =~ m{(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g) { + #print "BB<$1>\n"; + my ($match, $from, $to, $ident) = ($1, $2, $2, $3); + + # Should start with a space. + $to =~ s/^(\S)/ $1/; + # Should not end with a space. + $to =~ s/\s+$//; + # '*'s should not have spaces between. + while ($to =~ s/\*\s+\*/\*\*/) { + } + # Modifiers should have spaces. + $to =~ s/(\b$Modifier$)/$1 /; + +## print "2: from<$from> to<$to> ident<$ident>\n"; + if ($from ne $to && $ident !~ /^$Modifier$/) { + if (ERROR("POINTER_LOCATION", + "\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr) && + $fix) { + + my $sub_from = $match; + my $sub_to = $match; + $sub_to =~ s/\Q$from\E/$to/; + $fixed[$fixlinenr] =~ + s@\Q$sub_from\E@$sub_to@; + } + } + } + +# avoid BUG() or BUG_ON() + if ($line =~ /\b(?:BUG|BUG_ON)\b/) { + my $msg_type = \&WARN; + $msg_type = \&CHK if ($file); + &{$msg_type}("AVOID_BUG", + "Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()\n" . $herecurr); + } + +# avoid LINUX_VERSION_CODE + if ($line =~ /\bLINUX_VERSION_CODE\b/) { + WARN("LINUX_VERSION_CODE", + "LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr); + } + +# check for uses of printk_ratelimit + if ($line =~ /\bprintk_ratelimit\s*\(/) { + WARN("PRINTK_RATELIMITED", + "Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr); + } + +# printk should use KERN_* levels. Note that follow on printk's on the +# same line do not need a level, so we use the current block context +# to try and find and validate the current printk. In summary the current +# printk includes all preceding printk's which have no newline on the end. +# we assume the first bad printk is the one to report. + if ($line =~ /\bprintk\((?!KERN_)\s*"/) { + my $ok = 0; + for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) { + #print "CHECK<$lines[$ln - 1]\n"; + # we have a preceding printk if it ends + # with "\n" ignore it, else it is to blame + if ($lines[$ln - 1] =~ m{\bprintk\(}) { + if ($rawlines[$ln - 1] !~ m{\\n"}) { + $ok = 1; + } + last; + } + } + if ($ok == 0) { + WARN("PRINTK_WITHOUT_KERN_LEVEL", + "printk() should include KERN_ facility level\n" . $herecurr); + } + } + + if ($line =~ /\bprintk\s*\(\s*KERN_([A-Z]+)/) { + my $orig = $1; + my $level = lc($orig); + $level = "warn" if ($level eq "warning"); + my $level2 = $level; + $level2 = "dbg" if ($level eq "debug"); + WARN("PREFER_PR_LEVEL", + "Prefer [subsystem eg: netdev]_$level2([subsystem]dev, ... then dev_$level2(dev, ... then pr_$level(... to printk(KERN_$orig ...\n" . $herecurr); + } + + if ($line =~ /\bpr_warning\s*\(/) { + if (WARN("PREFER_PR_LEVEL", + "Prefer pr_warn(... to pr_warning(...\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\bpr_warning\b/pr_warn/; + } + } + + if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) { + my $orig = $1; + my $level = lc($orig); + $level = "warn" if ($level eq "warning"); + $level = "dbg" if ($level eq "debug"); + WARN("PREFER_DEV_LEVEL", + "Prefer dev_$level(... to dev_printk(KERN_$orig, ...\n" . $herecurr); + } + +# ENOSYS means "bad syscall nr" and nothing else. This will have a small +# number of false positives, but assembly files are not checked, so at +# least the arch entry code will not trigger this warning. + if ($line =~ /\bENOSYS\b/) { + WARN("ENOSYS", + "ENOSYS means 'invalid syscall nr' and nothing else\n" . $herecurr); + } + +# function brace can't be on same line, except for #defines of do while, +# or if closed on same line + if (($line=~/$Type\s*$Ident\(.*\).*\s*{/) and + !($line=~/\#\s*define.*do\s\{/) and !($line=~/}/)) { + if (ERROR("OPEN_BRACE", + "open brace '{' following function declarations go on the next line\n" . $herecurr) && + $fix) { + fix_delete_line($fixlinenr, $rawline); + my $fixed_line = $rawline; + $fixed_line =~ /(^..*$Type\s*$Ident\(.*\)\s*){(.*)$/; + my $line1 = $1; + my $line2 = $2; + fix_insert_line($fixlinenr, ltrim($line1)); + fix_insert_line($fixlinenr, "\+{"); + if ($line2 !~ /^\s*$/) { + fix_insert_line($fixlinenr, "\+\t" . trim($line2)); + } + } + } + +# open braces for enum, union and struct go on the same line. + if ($line =~ /^.\s*{/ && + $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) { + if (ERROR("OPEN_BRACE", + "open brace '{' following $1 go on the same line\n" . $hereprev) && + $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = rtrim($prevrawline) . " {"; + fix_insert_line($fixlinenr, $fixedline); + $fixedline = $rawline; + $fixedline =~ s/^(.\s*){\s*/$1\t/; + if ($fixedline !~ /^\+\s*$/) { + fix_insert_line($fixlinenr, $fixedline); + } + } + } + +# missing space after union, struct or enum definition + if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident){1,2}[=\{]/) { + if (WARN("SPACING", + "missing space after $1 definition\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/^(.\s*(?:typedef\s+)?(?:enum|union|struct)(?:\s+$Ident){1,2})([=\{])/$1 $2/; + } + } + +# Function pointer declarations +# check spacing between type, funcptr, and args +# canonical declaration is "type (*funcptr)(args...)" + if ($line =~ /^.\s*($Declare)\((\s*)\*(\s*)($Ident)(\s*)\)(\s*)\(/) { + my $declare = $1; + my $pre_pointer_space = $2; + my $post_pointer_space = $3; + my $funcname = $4; + my $post_funcname_space = $5; + my $pre_args_space = $6; + +# the $Declare variable will capture all spaces after the type +# so check it for a missing trailing missing space but pointer return types +# don't need a space so don't warn for those. + my $post_declare_space = ""; + if ($declare =~ /(\s+)$/) { + $post_declare_space = $1; + $declare = rtrim($declare); + } + if ($declare !~ /\*$/ && $post_declare_space =~ /^$/) { + WARN("SPACING", + "missing space after return type\n" . $herecurr); + $post_declare_space = " "; + } + +# unnecessary space "type (*funcptr)(args...)" +# This test is not currently implemented because these declarations are +# equivalent to +# int foo(int bar, ...) +# and this is form shouldn't/doesn't generate a checkpatch warning. +# +# elsif ($declare =~ /\s{2,}$/) { +# WARN("SPACING", +# "Multiple spaces after return type\n" . $herecurr); +# } + +# unnecessary space "type ( *funcptr)(args...)" + if (defined $pre_pointer_space && + $pre_pointer_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space after function pointer open parenthesis\n" . $herecurr); + } + +# unnecessary space "type (* funcptr)(args...)" + if (defined $post_pointer_space && + $post_pointer_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space before function pointer name\n" . $herecurr); + } + +# unnecessary space "type (*funcptr )(args...)" + if (defined $post_funcname_space && + $post_funcname_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space after function pointer name\n" . $herecurr); + } + +# unnecessary space "type (*funcptr) (args...)" + if (defined $pre_args_space && + $pre_args_space =~ /^\s/) { + WARN("SPACING", + "Unnecessary space before function pointer arguments\n" . $herecurr); + } + + if (show_type("SPACING") && $fix) { + $fixed[$fixlinenr] =~ + s/^(.\s*)$Declare\s*\(\s*\*\s*$Ident\s*\)\s*\(/$1 . $declare . $post_declare_space . '(*' . $funcname . ')('/ex; + } + } + +# check for spacing round square brackets; allowed: +# 1. with a type on the left -- int [] a; +# 2. at the beginning of a line for slice initialisers -- [0...10] = 5, +# 3. inside a curly brace -- = { [0...10] = 5 } + while ($line =~ /(.*?\s)\[/g) { + my ($where, $prefix) = ($-[1], $1); + if ($prefix !~ /$Type\s+$/ && + ($where != 0 || $prefix !~ /^.\s+$/) && + $prefix !~ /[{,]\s+$/) { + if (ERROR("BRACKET_SPACE", + "space prohibited before open square bracket '['\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/^(\+.*?)\s+\[/$1\[/; + } + } + } + +# check for spaces between functions and their parentheses. + while ($line =~ /($Ident)\s+\(/g) { + my $name = $1; + my $ctx_before = substr($line, 0, $-[1]); + my $ctx = "$ctx_before$name"; + + # Ignore those directives where spaces _are_ permitted. + if ($name =~ /^(?: + if|for|while|switch|return|case| + volatile|__volatile__| + __attribute__|format|__extension__| + asm|__asm__)$/x) + { + # cpp #define statements have non-optional spaces, ie + # if there is a space between the name and the open + # parenthesis it is simply not a parameter group. + } elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) { + + # cpp #elif statement condition may start with a ( + } elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) { + + # If this whole things ends with a type its most + # likely a typedef for a function. + } elsif ($ctx =~ /$Type$/) { + + } else { + if (WARN("SPACING", + "space prohibited between function name and open parenthesis '('\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\b$name\s+\(/$name\(/; + } + } + } + +# Check operator spacing. + if (!($line=~/\#\s*include/)) { + my $fixed_line = ""; + my $line_fixed = 0; + + my $ops = qr{ + <<=|>>=|<=|>=|==|!=| + \+=|-=|\*=|\/=|%=|\^=|\|=|&=| + =>|->|<<|>>|<|>|=|!|~| + &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%| + \?:|\?|: + }x; + my @elements = split(/($ops|;)/, $opline); + +## print("element count: <" . $#elements . ">\n"); +## foreach my $el (@elements) { +## print("el: <$el>\n"); +## } + + my @fix_elements = (); + my $off = 0; + + foreach my $el (@elements) { + push(@fix_elements, substr($rawline, $off, length($el))); + $off += length($el); + } + + $off = 0; + + my $blank = copy_spacing($opline); + my $last_after = -1; + + for (my $n = 0; $n < $#elements; $n += 2) { + + my $good = $fix_elements[$n] . $fix_elements[$n + 1]; + +## print("n: <$n> good: <$good>\n"); + + $off += length($elements[$n]); + + # Pick up the preceding and succeeding characters. + my $ca = substr($opline, 0, $off); + my $cc = ''; + if (length($opline) >= ($off + length($elements[$n + 1]))) { + $cc = substr($opline, $off + length($elements[$n + 1])); + } + my $cb = "$ca$;$cc"; + + my $a = ''; + $a = 'V' if ($elements[$n] ne ''); + $a = 'W' if ($elements[$n] =~ /\s$/); + $a = 'C' if ($elements[$n] =~ /$;$/); + $a = 'B' if ($elements[$n] =~ /(\[|\()$/); + $a = 'O' if ($elements[$n] eq ''); + $a = 'E' if ($ca =~ /^\s*$/); + + my $op = $elements[$n + 1]; + + my $c = ''; + if (defined $elements[$n + 2]) { + $c = 'V' if ($elements[$n + 2] ne ''); + $c = 'W' if ($elements[$n + 2] =~ /^\s/); + $c = 'C' if ($elements[$n + 2] =~ /^$;/); + $c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/); + $c = 'O' if ($elements[$n + 2] eq ''); + $c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/); + } else { + $c = 'E'; + } + + my $ctx = "${a}x${c}"; + + my $at = "(ctx:$ctx)"; + + my $ptr = substr($blank, 0, $off) . "^"; + my $hereptr = "$hereline$ptr\n"; + + # Pull out the value of this operator. + my $op_type = substr($curr_values, $off + 1, 1); + + # Get the full operator variant. + my $opv = $op . substr($curr_vars, $off, 1); + + # Ignore operators passed as parameters. + if ($op_type ne 'V' && + $ca =~ /\s$/ && $cc =~ /^\s*[,\)]/) { + +# # Ignore comments +# } elsif ($op =~ /^$;+$/) { + + # ; should have either the end of line or a space or \ after it + } elsif ($op eq ';') { + if ($ctx !~ /.x[WEBC]/ && + $cc !~ /^\\/ && $cc !~ /^;/) { + if (ERROR("SPACING", + "space required after that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " "; + $line_fixed = 1; + } + } + + # // is a comment + } elsif ($op eq '//') { + + # : when part of a bitfield + } elsif ($opv eq ':B') { + # skip the bitfield test for now + + # No spaces for: + # -> + } elsif ($op eq '->') { + if ($ctx =~ /Wx.|.xW/) { + if (ERROR("SPACING", + "spaces prohibited around that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } + } + + # , must not have a space before and must have a space on the right. + } elsif ($op eq ',') { + my $rtrim_before = 0; + my $space_after = 0; + if ($ctx =~ /Wx./) { + if (ERROR("SPACING", + "space prohibited before that '$op' $at\n" . $hereptr)) { + $line_fixed = 1; + $rtrim_before = 1; + } + } + if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) { + if (ERROR("SPACING", + "space required after that '$op' $at\n" . $hereptr)) { + $line_fixed = 1; + $last_after = $n; + $space_after = 1; + } + } + if ($rtrim_before || $space_after) { + if ($rtrim_before) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + } else { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]); + } + if ($space_after) { + $good .= " "; + } + } + + # '*' as part of a type definition -- reported already. + } elsif ($opv eq '*_') { + #warn "'*' is part of type\n"; + + # unary operators should have a space before and + # none after. May be left adjacent to another + # unary operator, or a cast + } elsif ($op eq '!' || $op eq '~' || + $opv eq '*U' || $opv eq '-U' || + $opv eq '&U' || $opv eq '&&U') { + if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { + if (ERROR("SPACING", + "space required before that '$op' $at\n" . $hereptr)) { + if ($n != $last_after + 2) { + $good = $fix_elements[$n] . " " . ltrim($fix_elements[$n + 1]); + $line_fixed = 1; + } + } + } + if ($op eq '*' && $cc =~/\s*$Modifier\b/) { + # A unary '*' may be const + + } elsif ($ctx =~ /.xW/) { + if (ERROR("SPACING", + "space prohibited after that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . rtrim($fix_elements[$n + 1]); + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } + } + + # unary ++ and unary -- are allowed no space on one side. + } elsif ($op eq '++' or $op eq '--') { + if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) { + if (ERROR("SPACING", + "space required one side of that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " "; + $line_fixed = 1; + } + } + if ($ctx =~ /Wx[BE]/ || + ($ctx =~ /Wx./ && $cc =~ /^;/)) { + if (ERROR("SPACING", + "space prohibited before that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + $line_fixed = 1; + } + } + if ($ctx =~ /ExW/) { + if (ERROR("SPACING", + "space prohibited after that '$op' $at\n" . $hereptr)) { + $good = $fix_elements[$n] . trim($fix_elements[$n + 1]); + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } + } + + # << and >> may either have or not have spaces both sides + } elsif ($op eq '<<' or $op eq '>>' or + $op eq '&' or $op eq '^' or $op eq '|' or + $op eq '+' or $op eq '-' or + $op eq '*' or $op eq '/' or + $op eq '%') + { + if ($check) { + if (defined $fix_elements[$n + 2] && $ctx !~ /[EW]x[EW]/) { + if (CHK("SPACING", + "spaces preferred around that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; + $fix_elements[$n + 2] =~ s/^\s+//; + $line_fixed = 1; + } + } elsif (!defined $fix_elements[$n + 2] && $ctx !~ /Wx[OE]/) { + if (CHK("SPACING", + "space preferred before that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]); + $line_fixed = 1; + } + } + } elsif ($ctx =~ /Wx[^WCE]|[^WCE]xW/) { + if (ERROR("SPACING", + "need consistent spacing around '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } + } + + # A colon needs no spaces before when it is + # terminating a case value or a label. + } elsif ($opv eq ':C' || $opv eq ':L') { + if ($ctx =~ /Wx./) { + if (ERROR("SPACING", + "space prohibited before that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); + $line_fixed = 1; + } + } + + # All the others need spaces both sides. + } elsif ($ctx !~ /[EWC]x[CWE]/) { + my $ok = 0; + + # Ignore email addresses <foo@bar> + if (($op eq '<' && + $cc =~ /^\S+\@\S+>/) || + ($op eq '>' && + $ca =~ /<\S+\@\S+$/)) + { + $ok = 1; + } + + # for asm volatile statements + # ignore a colon with another + # colon immediately before or after + if (($op eq ':') && + ($ca =~ /:$/ || $cc =~ /^:/)) { + $ok = 1; + } + + # messages are ERROR, but ?: are CHK + if ($ok == 0) { + my $msg_type = \&ERROR; + $msg_type = \&CHK if (($op eq '?:' || $op eq '?' || $op eq ':') && $ctx =~ /VxV/); + + if (&{$msg_type}("SPACING", + "spaces required around that '$op' $at\n" . $hereptr)) { + $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; + if (defined $fix_elements[$n + 2]) { + $fix_elements[$n + 2] =~ s/^\s+//; + } + $line_fixed = 1; + } + } + } + $off += length($elements[$n + 1]); + +## print("n: <$n> GOOD: <$good>\n"); + + $fixed_line = $fixed_line . $good; + } + + if (($#elements % 2) == 0) { + $fixed_line = $fixed_line . $fix_elements[$#elements]; + } + + if ($fix && $line_fixed && $fixed_line ne $fixed[$fixlinenr]) { + $fixed[$fixlinenr] = $fixed_line; + } + + + } + +# check for whitespace before a non-naked semicolon + if ($line =~ /^\+.*\S\s+;\s*$/) { + if (WARN("SPACING", + "space prohibited before semicolon\n" . $herecurr) && + $fix) { + 1 while $fixed[$fixlinenr] =~ + s/^(\+.*\S)\s+;/$1;/; + } + } + +# check for multiple assignments + if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) { + CHK("MULTIPLE_ASSIGNMENTS", + "multiple assignments should be avoided\n" . $herecurr); + } + +## # check for multiple declarations, allowing for a function declaration +## # continuation. +## if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ && +## $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) { +## +## # Remove any bracketed sections to ensure we do not +## # falsly report the parameters of functions. +## my $ln = $line; +## while ($ln =~ s/\([^\(\)]*\)//g) { +## } +## if ($ln =~ /,/) { +## WARN("MULTIPLE_DECLARATION", +## "declaring multiple variables together should be avoided\n" . $herecurr); +## } +## } + +#need space before brace following if, while, etc + if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) || + $line =~ /do\{/) { + if (ERROR("SPACING", + "space required before the open brace '{'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/^(\+.*(?:do|\))){/$1 {/; + } + } + +## # check for blank lines before declarations +## if ($line =~ /^.\t+$Type\s+$Ident(?:\s*=.*)?;/ && +## $prevrawline =~ /^.\s*$/) { +## WARN("SPACING", +## "No blank lines before declarations\n" . $hereprev); +## } +## + +# closing brace should have a space following it when it has anything +# on the line + if ($line =~ /}(?!(?:,|;|\)))\S/) { + if (ERROR("SPACING", + "space required after that close brace '}'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/}((?!(?:,|;|\)))\S)/} $1/; + } + } + +# check spacing on square brackets + if ($line =~ /\[\s/ && $line !~ /\[\s*$/) { + if (ERROR("SPACING", + "space prohibited after that open square bracket '['\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\[\s+/\[/; + } + } + if ($line =~ /\s\]/) { + if (ERROR("SPACING", + "space prohibited before that close square bracket ']'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\s+\]/\]/; + } + } + +# check spacing on parentheses + if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ && + $line !~ /for\s*\(\s+;/) { + if (ERROR("SPACING", + "space prohibited after that open parenthesis '('\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\(\s+/\(/; + } + } + if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ && + $line !~ /for\s*\(.*;\s+\)/ && + $line !~ /:\s+\)/) { + if (ERROR("SPACING", + "space prohibited before that close parenthesis ')'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\s+\)/\)/; + } + } + +# check unnecessary parentheses around addressof/dereference single $Lvals +# ie: &(foo->bar) should be &foo->bar and *(foo->bar) should be *foo->bar + + while ($line =~ /(?:[^&]&\s*|\*)\(\s*($Ident\s*(?:$Member\s*)+)\s*\)/g) { + my $var = $1; + if (CHK("UNNECESSARY_PARENTHESES", + "Unnecessary parentheses around $var\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\(\s*\Q$var\E\s*\)/$var/; + } + } + +# check for unnecessary parentheses around function pointer uses +# ie: (foo->bar)(); should be foo->bar(); +# but not "if (foo->bar) (" to avoid some false positives + if ($line =~ /(\bif\s*|)(\(\s*$Ident\s*(?:$Member\s*)+\))[ \t]*\(/ && $1 !~ /^if/) { + my $var = $2; + if (CHK("UNNECESSARY_PARENTHESES", + "Unnecessary parentheses around function pointer $var\n" . $herecurr) && + $fix) { + my $var2 = deparenthesize($var); + $var2 =~ s/\s//g; + $fixed[$fixlinenr] =~ s/\Q$var\E/$var2/; + } + } + +#goto labels aren't indented, allow a single space however + if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and + !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) { + if (WARN("INDENTED_LABEL", + "labels should not be indented\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/^(.)\s+/$1/; + } + } + +# return is not a function + if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) { + my $spacing = $1; + if ($^V && $^V ge 5.10.0 && + $stat =~ /^.\s*return\s*($balanced_parens)\s*;\s*$/) { + my $value = $1; + $value = deparenthesize($value); + if ($value =~ m/^\s*$FuncArg\s*(?:\?|$)/) { + ERROR("RETURN_PARENTHESES", + "return is not a function, parentheses are not required\n" . $herecurr); + } + } elsif ($spacing !~ /\s+/) { + ERROR("SPACING", + "space required before the open parenthesis '('\n" . $herecurr); + } + } + +# unnecessary return in a void function +# at end-of-function, with the previous line a single leading tab, then return; +# and the line before that not a goto label target like "out:" + if ($sline =~ /^[ \+]}\s*$/ && + $prevline =~ /^\+\treturn\s*;\s*$/ && + $linenr >= 3 && + $lines[$linenr - 3] =~ /^[ +]/ && + $lines[$linenr - 3] !~ /^[ +]\s*$Ident\s*:/) { + WARN("RETURN_VOID", + "void function return statements are not generally useful\n" . $hereprev); + } + +# if statements using unnecessary parentheses - ie: if ((foo == bar)) + if ($^V && $^V ge 5.10.0 && + $line =~ /\bif\s*((?:\(\s*){2,})/) { + my $openparens = $1; + my $count = $openparens =~ tr@\(@\(@; + my $msg = ""; + if ($line =~ /\bif\s*(?:\(\s*){$count,$count}$LvalOrFunc\s*($Compare)\s*$LvalOrFunc(?:\s*\)){$count,$count}/) { + my $comp = $4; #Not $1 because of $LvalOrFunc + $msg = " - maybe == should be = ?" if ($comp eq "=="); + WARN("UNNECESSARY_PARENTHESES", + "Unnecessary parentheses$msg\n" . $herecurr); + } + } + +# comparisons with a constant or upper case identifier on the left +# avoid cases like "foo + BAR < baz" +# only fix matches surrounded by parentheses to avoid incorrect +# conversions like "FOO < baz() + 5" being "misfixed" to "baz() > FOO + 5" + if ($^V && $^V ge 5.10.0 && + $line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) { + my $lead = $1; + my $const = $2; + my $comp = $3; + my $to = $4; + my $newcomp = $comp; + if ($lead !~ /(?:$Operators|\.)\s*$/ && + $to !~ /^(?:Constant|[A-Z_][A-Z0-9_]*)$/ && + WARN("CONSTANT_COMPARISON", + "Comparisons should place the constant on the right side of the test\n" . $herecurr) && + $fix) { + if ($comp eq "<") { + $newcomp = ">"; + } elsif ($comp eq "<=") { + $newcomp = ">="; + } elsif ($comp eq ">") { + $newcomp = "<"; + } elsif ($comp eq ">=") { + $newcomp = "<="; + } + $fixed[$fixlinenr] =~ s/\(\s*\Q$const\E\s*$Compare\s*\Q$to\E\s*\)/($to $newcomp $const)/; + } + } + +# Return of what appears to be an errno should normally be negative + if ($sline =~ /\breturn(?:\s*\(+\s*|\s+)(E[A-Z]+)(?:\s*\)+\s*|\s*)[;:,]/) { + my $name = $1; + if ($name ne 'EOF' && $name ne 'ERROR') { + WARN("USE_NEGATIVE_ERRNO", + "return of an errno should typically be negative (ie: return -$1)\n" . $herecurr); + } + } + +# Need a space before open parenthesis after if, while etc + if ($line =~ /\b(if|while|for|switch)\(/) { + if (ERROR("SPACING", + "space required before the open parenthesis '('\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/\b(if|while|for|switch)\(/$1 \(/; + } + } + +# Check for illegal assignment in if conditional -- and check for trailing +# statements after the conditional. + if ($line =~ /do\s*(?!{)/) { + ($stat, $cond, $line_nr_next, $remain_next, $off_next) = + ctx_statement_block($linenr, $realcnt, 0) + if (!defined $stat); + my ($stat_next) = ctx_statement_block($line_nr_next, + $remain_next, $off_next); + $stat_next =~ s/\n./\n /g; + ##print "stat<$stat> stat_next<$stat_next>\n"; + + if ($stat_next =~ /^\s*while\b/) { + # If the statement carries leading newlines, + # then count those as offsets. + my ($whitespace) = + ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s); + my $offset = + statement_rawlines($whitespace) - 1; + + $suppress_whiletrailers{$line_nr_next + + $offset} = 1; + } + } + if (!defined $suppress_whiletrailers{$linenr} && + defined($stat) && defined($cond) && + $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) { + my ($s, $c) = ($stat, $cond); + + if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) { + ERROR("ASSIGN_IN_IF", + "do not use assignment in if condition\n" . $herecurr); + } + + # Find out what is on the end of the line after the + # conditional. + substr($s, 0, length($c), ''); + $s =~ s/\n.*//g; + $s =~ s/$;//g; # Remove any comments + if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ && + $c !~ /}\s*while\s*/) + { + # Find out how long the conditional actually is. + my @newlines = ($c =~ /\n/gs); + my $cond_lines = 1 + $#newlines; + my $stat_real = ''; + + $stat_real = raw_line($linenr, $cond_lines) + . "\n" if ($cond_lines); + if (defined($stat_real) && $cond_lines > 1) { + $stat_real = "[...]\n$stat_real"; + } + + ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line\n" . $herecurr . $stat_real); + } + } + +# Check for bitwise tests written as boolean + if ($line =~ / + (?: + (?:\[|\(|\&\&|\|\|) + \s*0[xX][0-9]+\s* + (?:\&\&|\|\|) + | + (?:\&\&|\|\|) + \s*0[xX][0-9]+\s* + (?:\&\&|\|\||\)|\]) + )/x) + { + WARN("HEXADECIMAL_BOOLEAN_TEST", + "boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr); + } + +# if and else should not have general statements after it + if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) { + my $s = $1; + $s =~ s/$;//g; # Remove any comments + if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) { + ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line\n" . $herecurr); + } + } +# if should not continue a brace + if ($line =~ /}\s*if\b/) { + ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line (or did you mean 'else if'?)\n" . + $herecurr); + } +# case and default should not have general statements after them + if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g && + $line !~ /\G(?: + (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$| + \s*return\s+ + )/xg) + { + ERROR("TRAILING_STATEMENTS", + "trailing statements should be on next line\n" . $herecurr); + } + + # Check for }<nl>else {, these must be at the same + # indent level to be relevant to each other. + if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ && + $previndent == $indent) { + if (ERROR("ELSE_AFTER_BRACE", + "else should follow close brace '}'\n" . $hereprev) && + $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = $prevrawline; + $fixedline =~ s/}\s*$//; + if ($fixedline !~ /^\+\s*$/) { + fix_insert_line($fixlinenr, $fixedline); + } + $fixedline = $rawline; + $fixedline =~ s/^(.\s*)else/$1} else/; + fix_insert_line($fixlinenr, $fixedline); + } + } + + if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ && + $previndent == $indent) { + my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0); + + # Find out what is on the end of the line after the + # conditional. + substr($s, 0, length($c), ''); + $s =~ s/\n.*//g; + + if ($s =~ /^\s*;/) { + if (ERROR("WHILE_AFTER_BRACE", + "while should follow close brace '}'\n" . $hereprev) && + $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = $prevrawline; + my $trailing = $rawline; + $trailing =~ s/^\+//; + $trailing = trim($trailing); + $fixedline =~ s/}\s*$/} $trailing/; + fix_insert_line($fixlinenr, $fixedline); + } + } + } + +#Specific variable tests + while ($line =~ m{($Constant|$Lval)}g) { + my $var = $1; + +#gcc binary extension + if ($var =~ /^$Binary$/) { + if (WARN("GCC_BINARY_CONSTANT", + "Avoid gcc v4.3+ binary constant extension: <$var>\n" . $herecurr) && + $fix) { + my $hexval = sprintf("0x%x", oct($var)); + $fixed[$fixlinenr] =~ + s/\b$var\b/$hexval/; + } + } + +#CamelCase + if ($var !~ /^$Constant$/ && + $var =~ /[A-Z][a-z]|[a-z][A-Z]/ && +#Ignore Page<foo> variants + $var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ && +#Ignore SI style variants like nS, mV and dB (ie: max_uV, regulator_min_uA_show) + $var !~ /^(?:[a-z_]*?)_?[a-z][A-Z](?:_[a-z_]+)?$/ && +#Ignore some three character SI units explicitly, like MiB and KHz + $var !~ /^(?:[a-z_]*?)_?(?:[KMGT]iB|[KMGT]?Hz)(?:_[a-z_]+)?$/) { + while ($var =~ m{($Ident)}g) { + my $word = $1; + next if ($word !~ /[A-Z][a-z]|[a-z][A-Z]/); + if ($check) { + seed_camelcase_includes(); + if (!$file && !$camelcase_file_seeded) { + seed_camelcase_file($realfile); + $camelcase_file_seeded = 1; + } + } + if (!defined $camelcase{$word}) { + $camelcase{$word} = 1; + CHK("CAMELCASE", + "Avoid CamelCase: <$word>\n" . $herecurr); + } + } + } + } + +#no spaces allowed after \ in define + if ($line =~ /\#\s*define.*\\\s+$/) { + if (WARN("WHITESPACE_AFTER_LINE_CONTINUATION", + "Whitespace after \\ makes next lines useless\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\s+$//; + } + } + +# warn if <asm/foo.h> is #included and <linux/foo.h> is available and includes +# itself <asm/foo.h> (uses RAW line) + if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) { + my $file = "$1.h"; + my $checkfile = "include/linux/$file"; + if (-f "$root/$checkfile" && + $realfile ne $checkfile && + $1 !~ /$allowed_asm_includes/) + { + my $asminclude = `grep -Ec "#include\\s+<asm/$file>" $root/$checkfile`; + if ($asminclude > 0) { + if ($realfile =~ m{^arch/}) { + CHK("ARCH_INCLUDE_LINUX", + "Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr); + } else { + WARN("INCLUDE_LINUX", + "Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr); + } + } + } + } + +# multi-statement macros should be enclosed in a do while loop, grab the +# first statement and ensure its the whole macro if its not enclosed +# in a known good container + if ($realfile !~ m@/vmlinux.lds.h$@ && + $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) { + my $ln = $linenr; + my $cnt = $realcnt; + my ($off, $dstat, $dcond, $rest); + my $ctx = ''; + my $has_flow_statement = 0; + my $has_arg_concat = 0; + ($dstat, $dcond, $ln, $cnt, $off) = + ctx_statement_block($linenr, $realcnt, 0); + $ctx = $dstat; + #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n"; + #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n"; + + $has_flow_statement = 1 if ($ctx =~ /\b(goto|return)\b/); + $has_arg_concat = 1 if ($ctx =~ /\#\#/ && $ctx !~ /\#\#\s*(?:__VA_ARGS__|args)\b/); + + $dstat =~ s/^.\s*\#\s*define\s+$Ident(\([^\)]*\))?\s*//; + my $define_args = $1; + my $define_stmt = $dstat; + my @def_args = (); + + if (defined $define_args && $define_args ne "") { + $define_args = substr($define_args, 1, length($define_args) - 2); + $define_args =~ s/\s*//g; + @def_args = split(",", $define_args); + } + + $dstat =~ s/$;//g; + $dstat =~ s/\\\n.//g; + $dstat =~ s/^\s*//s; + $dstat =~ s/\s*$//s; + + # Flatten any parentheses and braces + while ($dstat =~ s/\([^\(\)]*\)/1/ || + $dstat =~ s/\{[^\{\}]*\}/1/ || + $dstat =~ s/.\[[^\[\]]*\]/1/) + { + } + + # Flatten any obvious string concatentation. + while ($dstat =~ s/($String)\s*$Ident/$1/ || + $dstat =~ s/$Ident\s*($String)/$1/) + { + } + + # Make asm volatile uses seem like a generic function + $dstat =~ s/\b_*asm_*\s+_*volatile_*\b/asm_volatile/g; + + my $exceptions = qr{ + $Declare| + module_param_named| + MODULE_PARM_DESC| + DECLARE_PER_CPU| + DEFINE_PER_CPU| + __typeof__\(| + union| + struct| + \.$Ident\s*=\s*| + ^\"|\"$| + ^\[ + }x; + #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n"; + + $ctx =~ s/\n*$//; + my $herectx = $here . "\n"; + my $stmt_cnt = statement_rawlines($ctx); + + for (my $n = 0; $n < $stmt_cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n"; + } + + if ($dstat ne '' && + $dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(), + $dstat !~ /^(?:$Ident|-?$Constant);$/ && # foo(); + $dstat !~ /^[!~-]?(?:$Lval|$Constant)$/ && # 10 // foo() // !foo // ~foo // -foo // foo->bar // foo.bar->baz + $dstat !~ /^'X'$/ && $dstat !~ /^'XX'$/ && # character constants + $dstat !~ /$exceptions/ && + $dstat !~ /^\.$Ident\s*=/ && # .foo = + $dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ && # stringification #foo + $dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...) + $dstat !~ /^for\s*$Constant$/ && # for (...) + $dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ && # for (...) bar() + $dstat !~ /^do\s*{/ && # do {... + $dstat !~ /^\(\{/ && # ({... + $ctx !~ /^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/) + { + + if ($dstat =~ /;/) { + ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE", + "Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx"); + } else { + ERROR("COMPLEX_MACRO", + "Macros with complex values should be enclosed in parentheses\n" . "$herectx"); + } + + } + + # Make $define_stmt single line, comment-free, etc + my @stmt_array = split('\n', $define_stmt); + my $first = 1; + $define_stmt = ""; + foreach my $l (@stmt_array) { + $l =~ s/\\$//; + if ($first) { + $define_stmt = $l; + $first = 0; + } elsif ($l =~ /^[\+ ]/) { + $define_stmt .= substr($l, 1); + } + } + $define_stmt =~ s/$;//g; + $define_stmt =~ s/\s+/ /g; + $define_stmt = trim($define_stmt); + +# check if any macro arguments are reused (ignore '...' and 'type') + foreach my $arg (@def_args) { + next if ($arg =~ /\.\.\./); + next if ($arg =~ /^type$/i); + my $tmp = $define_stmt; + $tmp =~ s/\b(typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g; + $tmp =~ s/\#+\s*$arg\b//g; + $tmp =~ s/\b$arg\s*\#\#//g; + my $use_cnt = $tmp =~ s/\b$arg\b//g; + if ($use_cnt > 1) { + CHK("MACRO_ARG_REUSE", + "Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx"); + } +# check if any macro arguments may have other precedence issues + if ($define_stmt =~ m/($Operators)?\s*\b$arg\b\s*($Operators)?/m && + ((defined($1) && $1 ne ',') || + (defined($2) && $2 ne ','))) { + CHK("MACRO_ARG_PRECEDENCE", + "Macro argument '$arg' may be better as '($arg)' to avoid precedence issues\n" . "$herectx"); + } + } + +# check for macros with flow control, but without ## concatenation +# ## concatenation is commonly a macro that defines a function so ignore those + if ($has_flow_statement && !$has_arg_concat) { + my $herectx = $here . "\n"; + my $cnt = statement_rawlines($ctx); + + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n"; + } + WARN("MACRO_WITH_FLOW_CONTROL", + "Macros with flow control statements should be avoided\n" . "$herectx"); + } + +# check for line continuations outside of #defines, preprocessor #, and asm + + } else { + if ($prevline !~ /^..*\\$/ && + $line !~ /^\+\s*\#.*\\$/ && # preprocessor + $line !~ /^\+.*\b(__asm__|asm)\b.*\\$/ && # asm + $line =~ /^\+.*\\$/) { + WARN("LINE_CONTINUATIONS", + "Avoid unnecessary line continuations\n" . $herecurr); + } + } + +# do {} while (0) macro tests: +# single-statement macros do not need to be enclosed in do while (0) loop, +# macro should not end with a semicolon + if ($^V && $^V ge 5.10.0 && + $realfile !~ m@/vmlinux.lds.h$@ && + $line =~ /^.\s*\#\s*define\s+$Ident(\()?/) { + my $ln = $linenr; + my $cnt = $realcnt; + my ($off, $dstat, $dcond, $rest); + my $ctx = ''; + ($dstat, $dcond, $ln, $cnt, $off) = + ctx_statement_block($linenr, $realcnt, 0); + $ctx = $dstat; + + $dstat =~ s/\\\n.//g; + $dstat =~ s/$;/ /g; + + if ($dstat =~ /^\+\s*#\s*define\s+$Ident\s*${balanced_parens}\s*do\s*{(.*)\s*}\s*while\s*\(\s*0\s*\)\s*([;\s]*)\s*$/) { + my $stmts = $2; + my $semis = $3; + + $ctx =~ s/\n*$//; + my $cnt = statement_rawlines($ctx); + my $herectx = $here . "\n"; + + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n"; + } + + if (($stmts =~ tr/;/;/) == 1 && + $stmts !~ /^\s*(if|while|for|switch)\b/) { + WARN("SINGLE_STATEMENT_DO_WHILE_MACRO", + "Single statement macros should not use a do {} while (0) loop\n" . "$herectx"); + } + if (defined $semis && $semis ne "") { + WARN("DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON", + "do {} while (0) macros should not be semicolon terminated\n" . "$herectx"); + } + } elsif ($dstat =~ /^\+\s*#\s*define\s+$Ident.*;\s*$/) { + $ctx =~ s/\n*$//; + my $cnt = statement_rawlines($ctx); + my $herectx = $here . "\n"; + + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n"; + } + + WARN("TRAILING_SEMICOLON", + "macros should not use a trailing semicolon\n" . "$herectx"); + } + } + +# make sure symbols are always wrapped with VMLINUX_SYMBOL() ... +# all assignments may have only one of the following with an assignment: +# . +# ALIGN(...) +# VMLINUX_SYMBOL(...) + if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) { + WARN("MISSING_VMLINUX_SYMBOL", + "vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr); + } + +# check for redundant bracing round if etc + if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) { + my ($level, $endln, @chunks) = + ctx_statement_full($linenr, $realcnt, 1); + #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; + #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n"; + if ($#chunks > 0 && $level == 0) { + my @allowed = (); + my $allow = 0; + my $seen = 0; + my $herectx = $here . "\n"; + my $ln = $linenr - 1; + for my $chunk (@chunks) { + my ($cond, $block) = @{$chunk}; + + # If the condition carries leading newlines, then count those as offsets. + my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s); + my $offset = statement_rawlines($whitespace) - 1; + + $allowed[$allow] = 0; + #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n"; + + # We have looked at and allowed this specific line. + $suppress_ifbraces{$ln + $offset} = 1; + + $herectx .= "$rawlines[$ln + $offset]\n[...]\n"; + $ln += statement_rawlines($block) - 1; + + substr($block, 0, length($cond), ''); + + $seen++ if ($block =~ /^\s*{/); + + #print "cond<$cond> block<$block> allowed<$allowed[$allow]>\n"; + if (statement_lines($cond) > 1) { + #print "APW: ALLOWED: cond<$cond>\n"; + $allowed[$allow] = 1; + } + if ($block =~/\b(?:if|for|while)\b/) { + #print "APW: ALLOWED: block<$block>\n"; + $allowed[$allow] = 1; + } + if (statement_block_size($block) > 1) { + #print "APW: ALLOWED: lines block<$block>\n"; + $allowed[$allow] = 1; + } + $allow++; + } + if ($seen) { + my $sum_allowed = 0; + foreach (@allowed) { + $sum_allowed += $_; + } + if ($sum_allowed == 0) { + WARN("BRACES", + "braces {} are not necessary for any arm of this statement\n" . $herectx); + } elsif ($sum_allowed != $allow && + $seen != $allow) { + CHK("BRACES", + "braces {} should be used on all arms of this statement\n" . $herectx); + } + } + } + } + if (!defined $suppress_ifbraces{$linenr - 1} && + $line =~ /\b(if|while|for|else)\b/) { + my $allowed = 0; + + # Check the pre-context. + if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { + #print "APW: ALLOWED: pre<$1>\n"; + $allowed = 1; + } + + my ($level, $endln, @chunks) = + ctx_statement_full($linenr, $realcnt, $-[0]); + + # Check the condition. + my ($cond, $block) = @{$chunks[0]}; + #print "CHECKING<$linenr> cond<$cond> block<$block>\n"; + if (defined $cond) { + substr($block, 0, length($cond), ''); + } + if (statement_lines($cond) > 1) { + #print "APW: ALLOWED: cond<$cond>\n"; + $allowed = 1; + } + if ($block =~/\b(?:if|for|while)\b/) { + #print "APW: ALLOWED: block<$block>\n"; + $allowed = 1; + } + if (statement_block_size($block) > 1) { + #print "APW: ALLOWED: lines block<$block>\n"; + $allowed = 1; + } + # Check the post-context. + if (defined $chunks[1]) { + my ($cond, $block) = @{$chunks[1]}; + if (defined $cond) { + substr($block, 0, length($cond), ''); + } + if ($block =~ /^\s*\{/) { + #print "APW: ALLOWED: chunk-1 block<$block>\n"; + $allowed = 1; + } + } + if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) { + my $herectx = $here . "\n"; + my $cnt = statement_rawlines($block); + + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n"; + } + + WARN("BRACES", + "braces {} are not necessary for single statement blocks\n" . $herectx); + } + } + +# check for unnecessary blank lines around braces + if (($line =~ /^.\s*}\s*$/ && $prevrawline =~ /^.\s*$/)) { + if (CHK("BRACES", + "Blank lines aren't necessary before a close brace '}'\n" . $hereprev) && + $fix && $prevrawline =~ /^\+/) { + fix_delete_line($fixlinenr - 1, $prevrawline); + } + } + if (($rawline =~ /^.\s*$/ && $prevline =~ /^..*{\s*$/)) { + if (CHK("BRACES", + "Blank lines aren't necessary after an open brace '{'\n" . $hereprev) && + $fix) { + fix_delete_line($fixlinenr, $rawline); + } + } + +# no volatiles please + my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b}; + if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) { + WARN("VOLATILE", + "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr); + } + +# Check for user-visible strings broken across lines, which breaks the ability +# to grep for the string. Make exceptions when the previous string ends in a +# newline (multiple lines in one string constant) or '\t', '\r', ';', or '{' +# (common in inline assembly) or is a octal \123 or hexadecimal \xaf value + if ($line =~ /^\+\s*$String/ && + $prevline =~ /"\s*$/ && + $prevrawline !~ /(?:\\(?:[ntr]|[0-7]{1,3}|x[0-9a-fA-F]{1,2})|;\s*|\{\s*)"\s*$/) { + if (WARN("SPLIT_STRING", + "quoted string split across lines\n" . $hereprev) && + $fix && + $prevrawline =~ /^\+.*"\s*$/ && + $last_coalesced_string_linenr != $linenr - 1) { + my $extracted_string = get_quoted_string($line, $rawline); + my $comma_close = ""; + if ($rawline =~ /\Q$extracted_string\E(\s*\)\s*;\s*$|\s*,\s*)/) { + $comma_close = $1; + } + + fix_delete_line($fixlinenr - 1, $prevrawline); + fix_delete_line($fixlinenr, $rawline); + my $fixedline = $prevrawline; + $fixedline =~ s/"\s*$//; + $fixedline .= substr($extracted_string, 1) . trim($comma_close); + fix_insert_line($fixlinenr - 1, $fixedline); + $fixedline = $rawline; + $fixedline =~ s/\Q$extracted_string\E\Q$comma_close\E//; + if ($fixedline !~ /\+\s*$/) { + fix_insert_line($fixlinenr, $fixedline); + } + $last_coalesced_string_linenr = $linenr; + } + } + +# check for missing a space in a string concatenation + if ($prevrawline =~ /[^\\]\w"$/ && $rawline =~ /^\+[\t ]+"\w/) { + WARN('MISSING_SPACE', + "break quoted strings at a space character\n" . $hereprev); + } + +# check for spaces before a quoted newline + if ($rawline =~ /^.*\".*\s\\n/) { + if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE", + "unnecessary whitespace before a quoted newline\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/^(\+.*\".*)\s+\\n/$1\\n/; + } + + } + +# concatenated string without spaces between elements + if ($line =~ /$String[A-Z_]/ || $line =~ /[A-Za-z0-9_]$String/) { + CHK("CONCATENATED_STRING", + "Concatenated strings should use spaces between elements\n" . $herecurr); + } + +# uncoalesced string fragments + if ($line =~ /$String\s*"/) { + WARN("STRING_FRAGMENTS", + "Consecutive strings are generally better as a single string\n" . $herecurr); + } + +# check for %L{u,d,i} and 0x%[udi] in strings + my $string; + while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { + $string = substr($rawline, $-[1], $+[1] - $-[1]); + $string =~ s/%%/__/g; + if ($string =~ /(?<!%)%[\*\d\.\$]*L[udi]/) { + WARN("PRINTF_L", + "\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr); + last; + } + if ($string =~ /0x%[\*\d\.\$\Llzth]*[udi]/) { + ERROR("PRINTF_0xDECIMAL", + "Prefixing 0x with decimal output is defective\n" . $herecurr); + } + } + +# check for line continuations in quoted strings with odd counts of " + if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) { + WARN("LINE_CONTINUATIONS", + "Avoid line continuations in quoted strings\n" . $herecurr); + } + +# warn about #if 0 + if ($line =~ /^.\s*\#\s*if\s+0\b/) { + CHK("REDUNDANT_CODE", + "if this code is redundant consider removing it\n" . + $herecurr); + } + +# check for needless "if (<foo>) fn(<foo>)" uses + if ($prevline =~ /\bif\s*\(\s*($Lval)\s*\)/) { + my $tested = quotemeta($1); + my $expr = '\s*\(\s*' . $tested . '\s*\)\s*;'; + if ($line =~ /\b(kfree|usb_free_urb|debugfs_remove(?:_recursive)?|(?:kmem_cache|mempool|dma_pool)_destroy)$expr/) { + my $func = $1; + if (WARN('NEEDLESS_IF', + "$func(NULL) is safe and this check is probably not required\n" . $hereprev) && + $fix) { + my $do_fix = 1; + my $leading_tabs = ""; + my $new_leading_tabs = ""; + if ($lines[$linenr - 2] =~ /^\+(\t*)if\s*\(\s*$tested\s*\)\s*$/) { + $leading_tabs = $1; + } else { + $do_fix = 0; + } + if ($lines[$linenr - 1] =~ /^\+(\t+)$func\s*\(\s*$tested\s*\)\s*;\s*$/) { + $new_leading_tabs = $1; + if (length($leading_tabs) + 1 ne length($new_leading_tabs)) { + $do_fix = 0; + } + } else { + $do_fix = 0; + } + if ($do_fix) { + fix_delete_line($fixlinenr - 1, $prevrawline); + $fixed[$fixlinenr] =~ s/^\+$new_leading_tabs/\+$leading_tabs/; + } + } + } + } + +# check for unnecessary "Out of Memory" messages + if ($line =~ /^\+.*\b$logFunctions\s*\(/ && + $prevline =~ /^[ \+]\s*if\s*\(\s*(\!\s*|NULL\s*==\s*)?($Lval)(\s*==\s*NULL\s*)?\s*\)/ && + (defined $1 || defined $3) && + $linenr > 3) { + my $testval = $2; + my $testline = $lines[$linenr - 3]; + + my ($s, $c) = ctx_statement_block($linenr - 3, $realcnt, 0); +# print("line: <$line>\nprevline: <$prevline>\ns: <$s>\nc: <$c>\n\n\n"); + + if ($c =~ /(?:^|\n)[ \+]\s*(?:$Type\s*)?\Q$testval\E\s*=\s*(?:\([^\)]*\)\s*)?\s*(?:devm_)?(?:[kv][czm]alloc(?:_node|_array)?\b|kstrdup|(?:dev_)?alloc_skb)/) { + WARN("OOM_MESSAGE", + "Possible unnecessary 'out of memory' message\n" . $hereprev); + } + } + +# check for logging functions with KERN_<LEVEL> + if ($line !~ /printk(?:_ratelimited|_once)?\s*\(/ && + $line =~ /\b$logFunctions\s*\(.*\b(KERN_[A-Z]+)\b/) { + my $level = $1; + if (WARN("UNNECESSARY_KERN_LEVEL", + "Possible unnecessary $level\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\s*$level\s*//; + } + } + +# check for mask then right shift without a parentheses + if ($^V && $^V ge 5.10.0 && + $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ && + $4 !~ /^\&/) { # $LvalOrFunc may be &foo, ignore if so + WARN("MASK_THEN_SHIFT", + "Possible precedence defect with mask then right shift - may need parentheses\n" . $herecurr); + } + +# check for pointer comparisons to NULL + if ($^V && $^V ge 5.10.0) { + while ($line =~ /\b$LvalOrFunc\s*(==|\!=)\s*NULL\b/g) { + my $val = $1; + my $equal = "!"; + $equal = "" if ($4 eq "!="); + if (CHK("COMPARISON_TO_NULL", + "Comparison to NULL could be written \"${equal}${val}\"\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b\Q$val\E\s*(?:==|\!=)\s*NULL\b/$equal$val/; + } + } + } + +# check for bad placement of section $InitAttribute (e.g.: __initdata) + if ($line =~ /(\b$InitAttribute\b)/) { + my $attr = $1; + if ($line =~ /^\+\s*static\s+(?:const\s+)?(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*[=;]/) { + my $ptr = $1; + my $var = $2; + if ((($ptr =~ /\b(union|struct)\s+$attr\b/ && + ERROR("MISPLACED_INIT", + "$attr should be placed after $var\n" . $herecurr)) || + ($ptr !~ /\b(union|struct)\s+$attr\b/ && + WARN("MISPLACED_INIT", + "$attr should be placed after $var\n" . $herecurr))) && + $fix) { + $fixed[$fixlinenr] =~ s/(\bstatic\s+(?:const\s+)?)(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*([=;])\s*/"$1" . trim(string_find_replace($2, "\\s*$attr\\s*", " ")) . " " . trim(string_find_replace($3, "\\s*$attr\\s*", "")) . " $attr" . ("$4" eq ";" ? ";" : " = ")/e; + } + } + } + +# check for $InitAttributeData (ie: __initdata) with const + if ($line =~ /\bconst\b/ && $line =~ /($InitAttributeData)/) { + my $attr = $1; + $attr =~ /($InitAttributePrefix)(.*)/; + my $attr_prefix = $1; + my $attr_type = $2; + if (ERROR("INIT_ATTRIBUTE", + "Use of const init definition must use ${attr_prefix}initconst\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/$InitAttributeData/${attr_prefix}initconst/; + } + } + +# check for $InitAttributeConst (ie: __initconst) without const + if ($line !~ /\bconst\b/ && $line =~ /($InitAttributeConst)/) { + my $attr = $1; + if (ERROR("INIT_ATTRIBUTE", + "Use of $attr requires a separate use of const\n" . $herecurr) && + $fix) { + my $lead = $fixed[$fixlinenr] =~ + /(^\+\s*(?:static\s+))/; + $lead = rtrim($1); + $lead = "$lead " if ($lead !~ /^\+$/); + $lead = "${lead}const "; + $fixed[$fixlinenr] =~ s/(^\+\s*(?:static\s+))/$lead/; + } + } + +# check for __read_mostly with const non-pointer (should just be const) + if ($line =~ /\b__read_mostly\b/ && + $line =~ /($Type)\s*$Ident/ && $1 !~ /\*\s*$/ && $1 =~ /\bconst\b/) { + if (ERROR("CONST_READ_MOSTLY", + "Invalid use of __read_mostly with const type\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\s+__read_mostly\b//; + } + } + +# don't use __constant_<foo> functions outside of include/uapi/ + if ($realfile !~ m@^include/uapi/@ && + $line =~ /(__constant_(?:htons|ntohs|[bl]e(?:16|32|64)_to_cpu|cpu_to_[bl]e(?:16|32|64)))\s*\(/) { + my $constant_func = $1; + my $func = $constant_func; + $func =~ s/^__constant_//; + if (WARN("CONSTANT_CONVERSION", + "$constant_func should be $func\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b$constant_func\b/$func/g; + } + } + +# prefer usleep_range over udelay + if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) { + my $delay = $1; + # ignore udelay's < 10, however + if (! ($delay < 10) ) { + CHK("USLEEP_RANGE", + "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $herecurr); + } + if ($delay > 2000) { + WARN("LONG_UDELAY", + "long udelay - prefer mdelay; see arch/arm/include/asm/delay.h\n" . $herecurr); + } + } + +# warn about unexpectedly long msleep's + if ($line =~ /\bmsleep\s*\((\d+)\);/) { + if ($1 < 20) { + WARN("MSLEEP", + "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $herecurr); + } + } + +# check for comparisons of jiffies + if ($line =~ /\bjiffies\s*$Compare|$Compare\s*jiffies\b/) { + WARN("JIFFIES_COMPARISON", + "Comparing jiffies is almost always wrong; prefer time_after, time_before and friends\n" . $herecurr); + } + +# check for comparisons of get_jiffies_64() + if ($line =~ /\bget_jiffies_64\s*\(\s*\)\s*$Compare|$Compare\s*get_jiffies_64\s*\(\s*\)/) { + WARN("JIFFIES_COMPARISON", + "Comparing get_jiffies_64() is almost always wrong; prefer time_after64, time_before64 and friends\n" . $herecurr); + } + +# warn about #ifdefs in C files +# if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) { +# print "#ifdef in C files should be avoided\n"; +# print "$herecurr"; +# $clean = 0; +# } + +# warn about spacing in #ifdefs + if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) { + if (ERROR("SPACING", + "exactly one space required after that #$1\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ + s/^(.\s*\#\s*(ifdef|ifndef|elif))\s{2,}/$1 /; + } + + } + +# check for spinlock_t definitions without a comment. + if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ || + $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) { + my $which = $1; + if (!ctx_has_comment($first_line, $linenr)) { + CHK("UNCOMMENTED_DEFINITION", + "$1 definition without comment\n" . $herecurr); + } + } +# check for memory barriers without a comment. + + my $barriers = qr{ + mb| + rmb| + wmb| + read_barrier_depends + }x; + my $barrier_stems = qr{ + mb__before_atomic| + mb__after_atomic| + store_release| + load_acquire| + store_mb| + (?:$barriers) + }x; + my $all_barriers = qr{ + (?:$barriers)| + smp_(?:$barrier_stems)| + virt_(?:$barrier_stems) + }x; + + if ($line =~ /\b(?:$all_barriers)\s*\(/) { + if (!ctx_has_comment($first_line, $linenr)) { + WARN("MEMORY_BARRIER", + "memory barrier without comment\n" . $herecurr); + } + } + + my $underscore_smp_barriers = qr{__smp_(?:$barrier_stems)}x; + + if ($realfile !~ m@^include/asm-generic/@ && + $realfile !~ m@/barrier\.h$@ && + $line =~ m/\b(?:$underscore_smp_barriers)\s*\(/ && + $line !~ m/^.\s*\#\s*define\s+(?:$underscore_smp_barriers)\s*\(/) { + WARN("MEMORY_BARRIER", + "__smp memory barriers shouldn't be used outside barrier.h and asm-generic\n" . $herecurr); + } + +# check for waitqueue_active without a comment. + if ($line =~ /\bwaitqueue_active\s*\(/) { + if (!ctx_has_comment($first_line, $linenr)) { + WARN("WAITQUEUE_ACTIVE", + "waitqueue_active without comment\n" . $herecurr); + } + } + +# Check for expedited grace periods that interrupt non-idle non-nohz +# online CPUs. These expedited can therefore degrade real-time response +# if used carelessly, and should be avoided where not absolutely +# needed. It is always OK to use synchronize_rcu_expedited() and +# synchronize_sched_expedited() at boot time (before real-time applications +# start) and in error situations where real-time response is compromised in +# any case. Note that synchronize_srcu_expedited() does -not- interrupt +# other CPUs, so don't warn on uses of synchronize_srcu_expedited(). +# Of course, nothing comes for free, and srcu_read_lock() and +# srcu_read_unlock() do contain full memory barriers in payment for +# synchronize_srcu_expedited() non-interruption properties. + if ($line =~ /\b(synchronize_rcu_expedited|synchronize_sched_expedited)\(/) { + WARN("EXPEDITED_RCU_GRACE_PERIOD", + "expedited RCU grace periods should be avoided where they can degrade real-time response\n" . $herecurr); + + } + +# check of hardware specific defines + if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) { + CHK("ARCH_DEFINES", + "architecture specific defines should be avoided\n" . $herecurr); + } + +# Check that the storage class is at the beginning of a declaration + if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) { + WARN("STORAGE_CLASS", + "storage class should be at the beginning of the declaration\n" . $herecurr) + } + +# check the location of the inline attribute, that it is between +# storage class and type. + if ($line =~ /\b$Type\s+$Inline\b/ || + $line =~ /\b$Inline\s+$Storage\b/) { + ERROR("INLINE_LOCATION", + "inline keyword should sit between storage class and type\n" . $herecurr); + } + +# Check for __inline__ and __inline, prefer inline + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b(__inline__|__inline)\b/) { + if (WARN("INLINE", + "plain inline is preferred over $1\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b(__inline__|__inline)\b/inline/; + + } + } + +# Check for __attribute__ packed, prefer __packed + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) { + WARN("PREFER_PACKED", + "__packed is preferred over __attribute__((packed))\n" . $herecurr); + } + +# Check for __attribute__ aligned, prefer __aligned + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(.*aligned/) { + WARN("PREFER_ALIGNED", + "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr); + } + +# Check for __attribute__ format(printf, prefer __printf + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) { + if (WARN("PREFER_PRINTF", + "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf\s*,\s*(.*)\)\s*\)\s*\)/"__printf(" . trim($1) . ")"/ex; + + } + } + +# Check for __attribute__ format(scanf, prefer __scanf + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) { + if (WARN("PREFER_SCANF", + "__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\s*,\s*(.*)\)\s*\)\s*\)/"__scanf(" . trim($1) . ")"/ex; + } + } + +# Check for __attribute__ weak, or __weak declarations (may have link issues) + if ($^V && $^V ge 5.10.0 && + $line =~ /(?:$Declare|$DeclareMisordered)\s*$Ident\s*$balanced_parens\s*(?:$Attribute)?\s*;/ && + ($line =~ /\b__attribute__\s*\(\s*\(.*\bweak\b/ || + $line =~ /\b__weak\b/)) { + ERROR("WEAK_DECLARATION", + "Using weak declarations can have unintended link defects\n" . $herecurr); + } + +# check for c99 types like uint8_t used outside of uapi/ + if ($realfile !~ m@\binclude/uapi/@ && + $line =~ /\b($Declare)\s*$Ident\s*[=;,\[]/) { + my $type = $1; + if ($type =~ /\b($typeC99Typedefs)\b/) { + $type = $1; + my $kernel_type = 'u'; + $kernel_type = 's' if ($type =~ /^_*[si]/); + $type =~ /(\d+)/; + $kernel_type .= $1; + if (CHK("PREFER_KERNEL_TYPES", + "Prefer kernel type '$kernel_type' over '$type'\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b$type\b/$kernel_type/; + } + } + } + +# check for cast of C90 native int or longer types constants + if ($line =~ /(\(\s*$C90_int_types\s*\)\s*)($Constant)\b/) { + my $cast = $1; + my $const = $2; + if (WARN("TYPECAST_INT_CONSTANT", + "Unnecessary typecast of c90 int constant\n" . $herecurr) && + $fix) { + my $suffix = ""; + my $newconst = $const; + $newconst =~ s/${Int_type}$//; + $suffix .= 'U' if ($cast =~ /\bunsigned\b/); + if ($cast =~ /\blong\s+long\b/) { + $suffix .= 'LL'; + } elsif ($cast =~ /\blong\b/) { + $suffix .= 'L'; + } + $fixed[$fixlinenr] =~ s/\Q$cast\E$const\b/$newconst$suffix/; + } + } + +# check for sizeof(&) + if ($line =~ /\bsizeof\s*\(\s*\&/) { + WARN("SIZEOF_ADDRESS", + "sizeof(& should be avoided\n" . $herecurr); + } + +# check for sizeof without parenthesis + if ($line =~ /\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/) { + if (WARN("SIZEOF_PARENTHESIS", + "sizeof $1 should be sizeof($1)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/"sizeof(" . trim($1) . ")"/ex; + } + } + +# check for struct spinlock declarations + if ($line =~ /^.\s*\bstruct\s+spinlock\s+\w+\s*;/) { + WARN("USE_SPINLOCK_T", + "struct spinlock should be spinlock_t\n" . $herecurr); + } + +# check for seq_printf uses that could be seq_puts + if ($sline =~ /\bseq_printf\s*\(.*"\s*\)\s*;\s*$/) { + my $fmt = get_quoted_string($line, $rawline); + $fmt =~ s/%%//g; + if ($fmt !~ /%/) { + if (WARN("PREFER_SEQ_PUTS", + "Prefer seq_puts to seq_printf\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bseq_printf\b/seq_puts/; + } + } + } + +# Check for misused memsets + if ($^V && $^V ge 5.10.0 && + defined $stat && + $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/) { + + my $ms_addr = $2; + my $ms_val = $7; + my $ms_size = $12; + + if ($ms_size =~ /^(0x|)0$/i) { + ERROR("MEMSET", + "memset to 0's uses 0 as the 2nd argument, not the 3rd\n" . "$here\n$stat\n"); + } elsif ($ms_size =~ /^(0x|)1$/i) { + WARN("MEMSET", + "single byte memset is suspicious. Swapped 2nd/3rd argument?\n" . "$here\n$stat\n"); + } + } + +# Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar) +# if ($^V && $^V ge 5.10.0 && +# defined $stat && +# $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { +# if (WARN("PREFER_ETHER_ADDR_COPY", +# "Prefer ether_addr_copy() over memcpy() if the Ethernet addresses are __aligned(2)\n" . "$here\n$stat\n") && +# $fix) { +# $fixed[$fixlinenr] =~ s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2, $7)/; +# } +# } + +# Check for memcmp(foo, bar, ETH_ALEN) that could be ether_addr_equal*(foo, bar) +# if ($^V && $^V ge 5.10.0 && +# defined $stat && +# $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { +# WARN("PREFER_ETHER_ADDR_EQUAL", +# "Prefer ether_addr_equal() or ether_addr_equal_unaligned() over memcmp()\n" . "$here\n$stat\n") +# } + +# check for memset(foo, 0x0, ETH_ALEN) that could be eth_zero_addr +# check for memset(foo, 0xFF, ETH_ALEN) that could be eth_broadcast_addr +# if ($^V && $^V ge 5.10.0 && +# defined $stat && +# $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { +# +# my $ms_val = $7; +# +# if ($ms_val =~ /^(?:0x|)0+$/i) { +# if (WARN("PREFER_ETH_ZERO_ADDR", +# "Prefer eth_zero_addr over memset()\n" . "$here\n$stat\n") && +# $fix) { +# $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_zero_addr($2)/; +# } +# } elsif ($ms_val =~ /^(?:0xff|255)$/i) { +# if (WARN("PREFER_ETH_BROADCAST_ADDR", +# "Prefer eth_broadcast_addr() over memset()\n" . "$here\n$stat\n") && +# $fix) { +# $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_broadcast_addr($2)/; +# } +# } +# } + +# typecasts on min/max could be min_t/max_t + if ($^V && $^V ge 5.10.0 && + defined $stat && + $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) { + if (defined $2 || defined $7) { + my $call = $1; + my $cast1 = deparenthesize($2); + my $arg1 = $3; + my $cast2 = deparenthesize($7); + my $arg2 = $8; + my $cast; + + if ($cast1 ne "" && $cast2 ne "" && $cast1 ne $cast2) { + $cast = "$cast1 or $cast2"; + } elsif ($cast1 ne "") { + $cast = $cast1; + } else { + $cast = $cast2; + } + WARN("MINMAX", + "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . "$here\n$stat\n"); + } + } + +# check usleep_range arguments + if ($^V && $^V ge 5.10.0 && + defined $stat && + $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) { + my $min = $1; + my $max = $7; + if ($min eq $max) { + WARN("USLEEP_RANGE", + "usleep_range should not use min == max args; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n"); + } elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ && + $min > $max) { + WARN("USLEEP_RANGE", + "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n"); + } + } + +# check for naked sscanf + if ($^V && $^V ge 5.10.0 && + defined $stat && + $line =~ /\bsscanf\b/ && + ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ && + $stat !~ /\bsscanf\s*$balanced_parens\s*(?:$Compare)/ && + $stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/)) { + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = raw_line($linenr, 0); + for (my $count = $linenr + 1; $count <= $lc; $count++) { + $stat_real = $stat_real . "\n" . raw_line($count, 0); + } + WARN("NAKED_SSCANF", + "unchecked sscanf return value\n" . "$here\n$stat_real\n"); + } + +# check for simple sscanf that should be kstrto<foo> + if ($^V && $^V ge 5.10.0 && + defined $stat && + $line =~ /\bsscanf\b/) { + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = raw_line($linenr, 0); + for (my $count = $linenr + 1; $count <= $lc; $count++) { + $stat_real = $stat_real . "\n" . raw_line($count, 0); + } + if ($stat_real =~ /\bsscanf\b\s*\(\s*$FuncArg\s*,\s*("[^"]+")/) { + my $format = $6; + my $count = $format =~ tr@%@%@; + if ($count == 1 && + $format =~ /^"\%(?i:ll[udxi]|[udxi]ll|ll|[hl]h?[udxi]|[udxi][hl]h?|[hl]h?|[udxi])"$/) { + WARN("SSCANF_TO_KSTRTO", + "Prefer kstrto<type> to single variable sscanf\n" . "$here\n$stat_real\n"); + } + } + } + +# check for new externs in .h files. + if ($realfile =~ /\.h$/ && + $line =~ /^\+\s*(extern\s+)$Type\s*$Ident\s*\(/s) { + if (CHK("AVOID_EXTERNS", + "extern prototypes should be avoided in .h files\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(.*)\bextern\b\s*(.*)/$1$2/; + } + } + +# check for new externs in .c files. + if ($realfile =~ /\.c$/ && defined $stat && + $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s) + { + my $function_name = $1; + my $paren_space = $2; + + my $s = $stat; + if (defined $cond) { + substr($s, 0, length($cond), ''); + } + if ($s =~ /^\s*;/ && + $function_name ne 'uninitialized_var') + { + WARN("AVOID_EXTERNS", + "externs should be avoided in .c files\n" . $herecurr); + } + + if ($paren_space =~ /\n/) { + WARN("FUNCTION_ARGUMENTS", + "arguments for function declarations should follow identifier\n" . $herecurr); + } + + } elsif ($realfile =~ /\.c$/ && defined $stat && + $stat =~ /^.\s*extern\s+/) + { + WARN("AVOID_EXTERNS", + "externs should be avoided in .c files\n" . $herecurr); + } + + if ($realfile =~ /\.[ch]$/ && defined $stat && + $stat =~ /^.\s*(?:extern\s+)?$Type\s*$Ident\s*\(\s*([^{]+)\s*\)\s*;/s && + $1 ne "void") { + my $args = trim($1); + while ($args =~ m/\s*($Type\s*(?:$Ident|\(\s*\*\s*$Ident?\s*\)\s*$balanced_parens)?)/g) { + my $arg = trim($1); + if ($arg =~ /^$Type$/ && $arg !~ /enum\s+$Ident$/) { + WARN("FUNCTION_ARGUMENTS", + "function definition argument '$arg' should also have an identifier name\n" . $herecurr); + } + } + } + +# checks for new __setup's + if ($rawline =~ /\b__setup\("([^"]*)"/) { + my $name = $1; + + if (!grep(/$name/, @setup_docs)) { + CHK("UNDOCUMENTED_SETUP", + "__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr); + } + } + +# check for pointless casting of kmalloc return + if ($line =~ /\*\s*\)\s*[kv][czm]alloc(_node){0,1}\b/) { + WARN("UNNECESSARY_CASTS", + "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr); + } + +# alloc style +# p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...) + if ($^V && $^V ge 5.10.0 && + $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*([kv][mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) { + CHK("ALLOC_SIZEOF_STRUCT", + "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr); + } + +# check for k[mz]alloc with multiplies that could be kmalloc_array/kcalloc + if ($^V && $^V ge 5.10.0 && + $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) { + my $oldfunc = $3; + my $a1 = $4; + my $a2 = $10; + my $newfunc = "kmalloc_array"; + $newfunc = "kcalloc" if ($oldfunc eq "kzalloc"); + my $r1 = $a1; + my $r2 = $a2; + if ($a1 =~ /^sizeof\s*\S/) { + $r1 = $a2; + $r2 = $a1; + } + if ($r1 !~ /^sizeof\b/ && $r2 =~ /^sizeof\s*\S/ && + !($r1 =~ /^$Constant$/ || $r1 =~ /^[A-Z_][A-Z0-9_]*$/)) { + if (WARN("ALLOC_WITH_MULTIPLY", + "Prefer $newfunc over $oldfunc with multiply\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*(k[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . trim($r1) . ', ' . trim($r2)/e; + + } + } + } + +# check for krealloc arg reuse + if ($^V && $^V ge 5.10.0 && + $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*\1\s*,/) { + WARN("KREALLOC_ARG_REUSE", + "Reusing the krealloc arg is almost always a bug\n" . $herecurr); + } + +# check for alloc argument mismatch + if ($line =~ /\b(kcalloc|kmalloc_array)\s*\(\s*sizeof\b/) { + WARN("ALLOC_ARRAY_ARGS", + "$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr); + } + +# check for multiple semicolons + if ($line =~ /;\s*;\s*$/) { + if (WARN("ONE_SEMICOLON", + "Statements terminations use 1 semicolon\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/(\s*;\s*){2,}$/;/g; + } + } + +# check for #defines like: 1 << <digit> that could be BIT(digit), it is not exported to uapi + if ($realfile !~ m@^include/uapi/@ && + $line =~ /#\s*define\s+\w+\s+\(?\s*1\s*([ulUL]*)\s*\<\<\s*(?:\d+|$Ident)\s*\)?/) { + my $ull = ""; + $ull = "_ULL" if (defined($1) && $1 =~ /ll/i); + if (CHK("BIT_MACRO", + "Prefer using the BIT$ull macro\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\(?\s*1\s*[ulUL]*\s*<<\s*(\d+|$Ident)\s*\)?/BIT${ull}($1)/; + } + } + +# check for #if defined CONFIG_<FOO> || defined CONFIG_<FOO>_MODULE + if ($line =~ /^\+\s*#\s*if\s+defined(?:\s*\(?\s*|\s+)(CONFIG_[A-Z_]+)\s*\)?\s*\|\|\s*defined(?:\s*\(?\s*|\s+)\1_MODULE\s*\)?\s*$/) { + my $config = $1; + if (WARN("PREFER_IS_ENABLED", + "Prefer IS_ENABLED(<FOO>) to CONFIG_<FOO> || CONFIG_<FOO>_MODULE\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] = "\+#if IS_ENABLED($config)"; + } + } + +# check for case / default statements not preceded by break/fallthrough/switch + if ($line =~ /^.\s*(?:case\s+(?:$Ident|$Constant)\s*|default):/) { + my $has_break = 0; + my $has_statement = 0; + my $count = 0; + my $prevline = $linenr; + while ($prevline > 1 && ($file || $count < 3) && !$has_break) { + $prevline--; + my $rline = $rawlines[$prevline - 1]; + my $fline = $lines[$prevline - 1]; + last if ($fline =~ /^\@\@/); + next if ($fline =~ /^\-/); + next if ($fline =~ /^.(?:\s*(?:case\s+(?:$Ident|$Constant)[\s$;]*|default):[\s$;]*)*$/); + $has_break = 1 if ($rline =~ /fall[\s_-]*(through|thru)/i); + next if ($fline =~ /^.[\s$;]*$/); + $has_statement = 1; + $count++; + $has_break = 1 if ($fline =~ /\bswitch\b|\b(?:break\s*;[\s$;]*$|return\b|goto\b|continue\b)/); + } + if (!$has_break && $has_statement) { + WARN("MISSING_BREAK", + "Possible switch case/default not preceeded by break or fallthrough comment\n" . $herecurr); + } + } + +# check for switch/default statements without a break; + if ($^V && $^V ge 5.10.0 && + defined $stat && + $stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) { + my $ctx = ''; + my $herectx = $here . "\n"; + my $cnt = statement_rawlines($stat); + for (my $n = 0; $n < $cnt; $n++) { + $herectx .= raw_line($linenr, $n) . "\n"; + } + WARN("DEFAULT_NO_BREAK", + "switch default: should use break\n" . $herectx); + } + +# check for gcc specific __FUNCTION__ + if ($line =~ /\b__FUNCTION__\b/) { + if (WARN("USE_FUNC", + "__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\b__FUNCTION__\b/__func__/g; + } + } + +# check for uses of __DATE__, __TIME__, __TIMESTAMP__ + while ($line =~ /\b(__(?:DATE|TIME|TIMESTAMP)__)\b/g) { + ERROR("DATE_TIME", + "Use of the '$1' macro makes the build non-deterministic\n" . $herecurr); + } + +# check for use of yield() + if ($line =~ /\byield\s*\(\s*\)/) { + WARN("YIELD", + "Using yield() is generally wrong. See yield() kernel-doc (sched/core.c)\n" . $herecurr); + } + +# check for comparisons against true and false + if ($line =~ /\+\s*(.*?)\b(true|false|$Lval)\s*(==|\!=)\s*(true|false|$Lval)\b(.*)$/i) { + my $lead = $1; + my $arg = $2; + my $test = $3; + my $otype = $4; + my $trail = $5; + my $op = "!"; + + ($arg, $otype) = ($otype, $arg) if ($arg =~ /^(?:true|false)$/i); + + my $type = lc($otype); + if ($type =~ /^(?:true|false)$/) { + if (("$test" eq "==" && "$type" eq "true") || + ("$test" eq "!=" && "$type" eq "false")) { + $op = ""; + } + + CHK("BOOL_COMPARISON", + "Using comparison to $otype is error prone\n" . $herecurr); + +## maybe suggesting a correct construct would better +## "Using comparison to $otype is error prone. Perhaps use '${lead}${op}${arg}${trail}'\n" . $herecurr); + + } + } + +# check for semaphores initialized locked + if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) { + WARN("CONSIDER_COMPLETION", + "consider using a completion\n" . $herecurr); + } + +# recommend kstrto* over simple_strto* and strict_strto* + if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) { + WARN("CONSIDER_KSTRTO", + "$1 is obsolete, use k$3 instead\n" . $herecurr); + } + +# check for __initcall(), use device_initcall() explicitly or more appropriate function please + if ($line =~ /^.\s*__initcall\s*\(/) { + WARN("USE_DEVICE_INITCALL", + "please use device_initcall() or more appropriate function instead of __initcall() (see include/linux/init.h)\n" . $herecurr); + } + +# check for various structs that are normally const (ops, kgdb, device_tree) + if ($line !~ /\bconst\b/ && + $line =~ /\bstruct\s+($const_structs)\b/) { + WARN("CONST_STRUCT", + "struct $1 should normally be const\n" . + $herecurr); + } + +# use of NR_CPUS is usually wrong +# ignore definitions of NR_CPUS and usage to define arrays as likely right + if ($line =~ /\bNR_CPUS\b/ && + $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ && + $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ && + $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ && + $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ && + $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/) + { + WARN("NR_CPUS", + "usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr); + } + +# Use of __ARCH_HAS_<FOO> or ARCH_HAVE_<BAR> is wrong. + if ($line =~ /\+\s*#\s*define\s+((?:__)?ARCH_(?:HAS|HAVE)\w*)\b/) { + ERROR("DEFINE_ARCH_HAS", + "#define of '$1' is wrong - use Kconfig variables or standard guards instead\n" . $herecurr); + } + +# likely/unlikely comparisons similar to "(likely(foo) > 0)" + if ($^V && $^V ge 5.10.0 && + $line =~ /\b((?:un)?likely)\s*\(\s*$FuncArg\s*\)\s*$Compare/) { + WARN("LIKELY_MISUSE", + "Using $1 should generally have parentheses around the comparison\n" . $herecurr); + } + +# whine mightly about in_atomic + if ($line =~ /\bin_atomic\s*\(/) { + if ($realfile =~ m@^drivers/@) { + ERROR("IN_ATOMIC", + "do not use in_atomic in drivers\n" . $herecurr); + } elsif ($realfile !~ m@^kernel/@) { + WARN("IN_ATOMIC", + "use of in_atomic() is incorrect outside core kernel code\n" . $herecurr); + } + } + +# whine about ACCESS_ONCE + if ($^V && $^V ge 5.10.0 && + $line =~ /\bACCESS_ONCE\s*$balanced_parens\s*(=(?!=))?\s*($FuncArg)?/) { + my $par = $1; + my $eq = $2; + my $fun = $3; + $par =~ s/^\(\s*(.*)\s*\)$/$1/; + if (defined($eq)) { + if (WARN("PREFER_WRITE_ONCE", + "Prefer WRITE_ONCE(<FOO>, <BAR>) over ACCESS_ONCE(<FOO>) = <BAR>\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bACCESS_ONCE\s*\(\s*\Q$par\E\s*\)\s*$eq\s*\Q$fun\E/WRITE_ONCE($par, $fun)/; + } + } else { + if (WARN("PREFER_READ_ONCE", + "Prefer READ_ONCE(<FOO>) over ACCESS_ONCE(<FOO>)\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/\bACCESS_ONCE\s*\(\s*\Q$par\E\s*\)/READ_ONCE($par)/; + } + } + } + +# check for lockdep_set_novalidate_class + if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ || + $line =~ /__lockdep_no_validate__\s*\)/ ) { + if ($realfile !~ m@^kernel/lockdep@ && + $realfile !~ m@^include/linux/lockdep@ && + $realfile !~ m@^drivers/base/core@) { + ERROR("LOCKDEP", + "lockdep_no_validate class is reserved for device->mutex.\n" . $herecurr); + } + } + + if ($line =~ /debugfs_create_\w+.*\b$mode_perms_world_writable\b/ || + $line =~ /DEVICE_ATTR.*\b$mode_perms_world_writable\b/) { + WARN("EXPORTED_WORLD_WRITABLE", + "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr); + } + +# Mode permission misuses where it seems decimal should be octal +# This uses a shortcut match to avoid unnecessary uses of a slow foreach loop + if ($^V && $^V ge 5.10.0 && + defined $stat && + $line =~ /$mode_perms_search/) { + foreach my $entry (@mode_permission_funcs) { + my $func = $entry->[0]; + my $arg_pos = $entry->[1]; + + my $lc = $stat =~ tr@\n@@; + $lc = $lc + $linenr; + my $stat_real = raw_line($linenr, 0); + for (my $count = $linenr + 1; $count <= $lc; $count++) { + $stat_real = $stat_real . "\n" . raw_line($count, 0); + } + + my $skip_args = ""; + if ($arg_pos > 1) { + $arg_pos--; + $skip_args = "(?:\\s*$FuncArg\\s*,\\s*){$arg_pos,$arg_pos}"; + } + my $test = "\\b$func\\s*\\(${skip_args}($FuncArg(?:\\|\\s*$FuncArg)*)\\s*[,\\)]"; + if ($stat =~ /$test/) { + my $val = $1; + $val = $6 if ($skip_args ne ""); + if (($val =~ /^$Int$/ && $val !~ /^$Octal$/) || + ($val =~ /^$Octal$/ && length($val) ne 4)) { + ERROR("NON_OCTAL_PERMISSIONS", + "Use 4 digit octal (0777) not decimal permissions\n" . "$here\n" . $stat_real); + } + if ($val =~ /^$Octal$/ && (oct($val) & 02)) { + ERROR("EXPORTED_WORLD_WRITABLE", + "Exporting writable files is usually an error. Consider more restrictive permissions.\n" . "$here\n" . $stat_real); + } + } + } + } + +# check for uses of S_<PERMS> that could be octal for readability + if ($line =~ /\b$mode_perms_string_search\b/) { + my $val = ""; + my $oval = ""; + my $to = 0; + my $curpos = 0; + my $lastpos = 0; + while ($line =~ /\b(($mode_perms_string_search)\b(?:\s*\|\s*)?\s*)/g) { + $curpos = pos($line); + my $match = $2; + my $omatch = $1; + last if ($lastpos > 0 && ($curpos - length($omatch) != $lastpos)); + $lastpos = $curpos; + $to |= $mode_permission_string_types{$match}; + $val .= '\s*\|\s*' if ($val ne ""); + $val .= $match; + $oval .= $omatch; + } + $oval =~ s/^\s*\|\s*//; + $oval =~ s/\s*\|\s*$//; + my $octal = sprintf("%04o", $to); + if (WARN("SYMBOLIC_PERMS", + "Symbolic permissions '$oval' are not preferred. Consider using octal permissions '$octal'.\n" . $herecurr) && + $fix) { + $fixed[$fixlinenr] =~ s/$val/$octal/; + } + } + +# validate content of MODULE_LICENSE against list from include/linux/module.h + if ($line =~ /\bMODULE_LICENSE\s*\(\s*($String)\s*\)/) { + my $extracted_string = get_quoted_string($line, $rawline); + my $valid_licenses = qr{ + GPL| + GPL\ v2| + GPL\ and\ additional\ rights| + Dual\ BSD/GPL| + Dual\ MIT/GPL| + Dual\ MPL/GPL| + Proprietary + }x; + if ($extracted_string !~ /^"(?:$valid_licenses)"$/x) { + WARN("MODULE_LICENSE", + "unknown module license " . $extracted_string . "\n" . $herecurr); + } + } + } + + # If we have no input at all, then there is nothing to report on + # so just keep quiet. + if ($#rawlines == -1) { + exit(0); + } + + # In mailback mode only produce a report in the negative, for + # things that appear to be patches. + if ($mailback && ($clean == 1 || !$is_patch)) { + exit(0); + } + + # This is not a patch, and we are are in 'no-patch' mode so + # just keep quiet. + if (!$chk_patch && !$is_patch) { + exit(0); + } + + if (!$is_patch && $file !~ /cover-letter\.patch$/) { + ERROR("NOT_UNIFIED_DIFF", + "Does not appear to be a unified-diff format patch\n"); + } + if ($is_patch && $has_commit_log && $chk_signoff && $signoff == 0) { + ERROR("MISSING_SIGN_OFF", + "Missing Signed-off-by: line(s)\n"); + } + + print report_dump(); + if ($summary && !($clean == 1 && $quiet == 1)) { + print "$filename " if ($summary_file); + print "total: $cnt_error errors, $cnt_warn warnings, " . + (($check)? "$cnt_chk checks, " : "") . + "$cnt_lines lines checked\n"; + } + + if ($quiet == 0) { + # If there were any defects found and not already fixing them + if (!$clean and !$fix) { + print << "EOM" + +NOTE: For some of the reported defects, checkpatch may be able to + mechanically convert to the typical style using --fix or --fix-inplace. +EOM + } + # If there were whitespace errors which cleanpatch can fix + # then suggest that. + if ($rpt_cleaners) { + $rpt_cleaners = 0; + print << "EOM" + +NOTE: Whitespace errors detected. + You may wish to use scripts/cleanpatch or scripts/cleanfile +EOM + } + } + + if ($clean == 0 && $fix && + ("@rawlines" ne "@fixed" || + $#fixed_inserted >= 0 || $#fixed_deleted >= 0)) { + my $newfile = $filename; + $newfile .= ".EXPERIMENTAL-checkpatch-fixes" if (!$fix_inplace); + my $linecount = 0; + my $f; + + @fixed = fix_inserted_deleted_lines(\@fixed, \@fixed_inserted, \@fixed_deleted); + + open($f, '>', $newfile) + or die "$P: Can't open $newfile for write\n"; + foreach my $fixed_line (@fixed) { + $linecount++; + if ($file) { + if ($linecount > 3) { + $fixed_line =~ s/^\+//; + print $f $fixed_line . "\n"; + } + } else { + print $f $fixed_line . "\n"; + } + } + close($f); + + if (!$quiet) { + print << "EOM"; + +Wrote EXPERIMENTAL --fix correction(s) to '$newfile' + +Do _NOT_ trust the results written to this file. +Do _NOT_ submit these changes without inspecting them for correctness. + +This EXPERIMENTAL file is simply a convenience to help rewrite patches. +No warranties, expressed or implied... +EOM + } + } + + if ($quiet == 0) { + print "\n"; + if ($clean == 1) { + print "$vname has no obvious style problems and is ready for submission.\n"; + } else { + print "$vname has style problems, please review.\n"; + } + } + return $clean; +} diff --git a/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/util/const_structs.checkpatch b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/util/const_structs.checkpatch new file mode 100644 index 00000000000000..ac5f1267151dfe --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/util/const_structs.checkpatch @@ -0,0 +1,64 @@ +acpi_dock_ops +address_space_operations +backlight_ops +block_device_operations +clk_ops +comedi_lrange +component_ops +dentry_operations +dev_pm_ops +dma_map_ops +driver_info +drm_connector_funcs +drm_encoder_funcs +drm_encoder_helper_funcs +ethtool_ops +extent_io_ops +file_lock_operations +file_operations +hv_ops +ide_dma_ops +ide_port_ops +inode_operations +intel_dvo_dev_ops +irq_domain_ops +item_operations +iwl_cfg +iwl_ops +kgdb_arch +kgdb_io +kset_uevent_ops +lock_manager_operations +machine_desc +microcode_ops +mlxsw_reg_info +mtrr_ops +neigh_ops +net_device_ops +nlmsvc_binding +nvkm_device_chip +of_device_id +pci_raw_ops +pipe_buf_operations +platform_hibernation_ops +platform_suspend_ops +proto_ops +regmap_access_table +rpc_pipe_ops +rtc_class_ops +sd_desc +seq_operations +sirfsoc_padmux +snd_ac97_build_ops +snd_soc_component_driver +soc_pcmcia_socket_ops +stacktrace_ops +sysfs_ops +tty_operations +uart_ops +usb_mon_operations +v4l2_ctrl_ops +v4l2_ioctl_ops +vm_operations_struct +wacom_features +wd_ops diff --git a/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/util/spelling.txt b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/util/spelling.txt new file mode 100644 index 00000000000000..163c720d3f2bb8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/bt_mt7668_sdio/util/spelling.txt @@ -0,0 +1,1072 @@ +# Originally from Debian's Lintian tool. Various false positives have been +# removed, and various additions have been made as they've been discovered +# in the kernel source. +# +# License: GPLv2 +# +# The format of each line is: +# mistake||correction +# +abandonning||abandoning +abigious||ambiguous +abitrate||arbitrate +abov||above +abreviated||abbreviated +absense||absence +absolut||absolute +absoulte||absolute +acccess||access +acceleratoin||acceleration +accelleration||acceleration +accesing||accessing +accesnt||accent +accessable||accessible +accesss||access +accidentaly||accidentally +accidentually||accidentally +accoding||according +accomodate||accommodate +accomodates||accommodates +accordign||according +accoring||according +accout||account +accquire||acquire +accquired||acquired +accross||across +acessable||accessible +acess||access +achitecture||architecture +acient||ancient +acitions||actions +acitve||active +acknowldegement||acknowldegement +acknowledgement||acknowledgment +ackowledge||acknowledge +ackowledged||acknowledged +acording||according +activete||activate +acumulating||accumulating +adapater||adapter +addional||additional +additionaly||additionally +addres||address +addreses||addresses +addresss||address +aditional||additional +aditionally||additionally +aditionaly||additionally +adminstrative||administrative +adress||address +adresses||addresses +adviced||advised +afecting||affecting +agaist||against +albumns||albums +alegorical||allegorical +algorith||algorithm +algorithmical||algorithmically +algoritm||algorithm +algoritms||algorithms +algorrithm||algorithm +algorritm||algorithm +allign||align +allocatrd||allocated +allocte||allocate +allpication||application +alocate||allocate +alogirhtms||algorithms +alogrithm||algorithm +alot||a lot +alow||allow +alows||allows +altough||although +alue||value +ambigious||ambiguous +amoung||among +amout||amount +analysator||analyzer +ang||and +anniversery||anniversary +annoucement||announcement +anomolies||anomalies +anomoly||anomaly +anway||anyway +aplication||application +appearence||appearance +applicaion||application +appliction||application +applictions||applications +appplications||applications +appropiate||appropriate +appropriatly||appropriately +approriate||appropriate +approriately||appropriately +apropriate||appropriate +aquainted||acquainted +aquired||acquired +aquisition||acquisition +arbitary||arbitrary +architechture||architecture +arguement||argument +arguements||arguments +aritmetic||arithmetic +arne't||aren't +arraival||arrival +artifical||artificial +artillary||artillery +asign||assign +assertation||assertion +assiged||assigned +assigment||assignment +assigments||assignments +assistent||assistant +assocation||association +associcated||associated +assotiated||associated +assum||assume +assumtpion||assumption +asuming||assuming +asycronous||asynchronous +asynchnous||asynchronous +atomatically||automatically +atomicly||atomically +attachement||attachment +attched||attached +attemps||attempts +attruibutes||attributes +authentification||authentication +automaticaly||automatically +automaticly||automatically +automatize||automate +automatized||automated +automatizes||automates +autonymous||autonomous +auxillary||auxiliary +auxilliary||auxiliary +avaiable||available +avaible||available +availabe||available +availabled||available +availablity||availability +availale||available +availavility||availability +availble||available +availiable||available +avalable||available +avaliable||available +aysnc||async +backgroud||background +backword||backward +backwords||backwards +bahavior||behavior +bakup||backup +baloon||balloon +baloons||balloons +bandwith||bandwidth +batery||battery +beacuse||because +becasue||because +becomming||becoming +becuase||because +beeing||being +befor||before +begining||beginning +beter||better +betweeen||between +bianries||binaries +bitmast||bitmask +boardcast||broadcast +borad||board +boundry||boundary +brievely||briefly +broadcat||broadcast +cacluated||calculated +caculation||calculation +calender||calendar +calle||called +calucate||calculate +calulate||calculate +cancelation||cancellation +capabilites||capabilities +capabitilies||capabilities +capatibilities||capabilities +carefuly||carefully +cariage||carriage +catagory||category +cehck||check +challange||challenge +challanges||challenges +chanell||channel +changable||changeable +channle||channel +channnel||channel +charachter||character +charachters||characters +charactor||character +charater||character +charaters||characters +charcter||character +chcek||check +chck||check +checksuming||checksumming +childern||children +childs||children +chiled||child +chked||checked +chnage||change +chnages||changes +chnnel||channel +choosen||chosen +chouse||chose +circumvernt||circumvent +claread||cleared +clared||cleared +closeing||closing +clustred||clustered +collapsable||collapsible +colorfull||colorful +comand||command +comit||commit +commerical||commercial +comming||coming +comminucation||communication +commited||committed +commiting||committing +committ||commit +commoditiy||commodity +compability||compatibility +compaibility||compatibility +compatability||compatibility +compatable||compatible +compatibiliy||compatibility +compatibilty||compatibility +compatiblity||compatibility +competion||completion +compilant||compliant +compleatly||completely +completly||completely +complient||compliant +componnents||components +compres||compress +compresion||compression +comression||compression +comunication||communication +conbination||combination +conditionaly||conditionally +conected||connected +configuratoin||configuration +configuraton||configuration +configuretion||configuration +conider||consider +conjuction||conjunction +connectinos||connections +connnection||connection +connnections||connections +consistancy||consistency +consistant||consistent +containes||contains +containts||contains +contaisn||contains +contant||contact +contence||contents +continous||continuous +continously||continuously +continueing||continuing +contraints||constraints +controled||controlled +controler||controller +controll||control +contruction||construction +contry||country +convertion||conversion +convertor||converter +convienient||convenient +convinient||convenient +corected||corrected +correponding||corresponding +correponds||corresponds +correspoding||corresponding +cotrol||control +couter||counter +coutner||counter +cryptocraphic||cryptographic +cunter||counter +curently||currently +dafault||default +deafult||default +deamon||daemon +decompres||decompress +decription||description +defailt||default +defferred||deferred +definate||definite +definately||definitely +defintion||definition +defintions||definitions +defualt||default +defult||default +deivce||device +delared||declared +delare||declare +delares||declares +delaring||declaring +delemiter||delimiter +dependancies||dependencies +dependancy||dependency +dependant||dependent +depreacted||deprecated +depreacte||deprecate +desactivate||deactivate +desciptors||descriptors +descripton||description +descrition||description +descritptor||descriptor +desctiptor||descriptor +desriptor||descriptor +desriptors||descriptors +destory||destroy +destoryed||destroyed +destorys||destroys +destroied||destroyed +detabase||database +develope||develop +developement||development +developped||developed +developpement||development +developper||developer +developpment||development +deveolpment||development +devided||divided +deviece||device +diable||disable +dictionnary||dictionary +didnt||didn't +diferent||different +differrence||difference +difinition||definition +diplay||display +direectly||directly +disapear||disappear +disapeared||disappeared +disappared||disappeared +disconnet||disconnect +discontinous||discontinuous +dispertion||dispersion +dissapears||disappears +distiction||distinction +docuentation||documentation +documantation||documentation +documentaion||documentation +documment||document +doesnt||doesn't +dorp||drop +dosen||doesn +downlad||download +downlads||downloads +druing||during +dynmaic||dynamic +easilly||easily +ecspecially||especially +edditable||editable +editting||editing +efficently||efficiently +ehther||ether +eigth||eight +eletronic||electronic +enabledi||enabled +enchanced||enhanced +encorporating||incorporating +encrupted||encrypted +encrypiton||encryption +endianess||endianness +enhaced||enhanced +enlightnment||enlightenment +enocded||encoded +enterily||entirely +enviroiment||environment +enviroment||environment +environement||environment +environent||environment +eqivalent||equivalent +equiped||equipped +equivelant||equivalent +equivilant||equivalent +eror||error +estbalishment||establishment +etsablishment||establishment +etsbalishment||establishment +excecutable||executable +exceded||exceeded +excellant||excellent +existance||existence +existant||existent +exixt||exist +exlcude||exclude +exlcusive||exclusive +exmaple||example +expecially||especially +explicite||explicit +explicitely||explicitly +explict||explicit +explictly||explicitly +expresion||expression +exprimental||experimental +extened||extended +extensability||extensibility +extention||extension +extracter||extractor +faild||failed +faill||fail +failue||failure +failuer||failure +faireness||fairness +faliure||failure +familar||familiar +fatser||faster +feauture||feature +feautures||features +fetaure||feature +fetaures||features +fileystem||filesystem +fimware||firmware +finanize||finalize +findn||find +finilizes||finalizes +finsih||finish +flusing||flushing +folloing||following +followign||following +follwing||following +forseeable||foreseeable +forse||force +fortan||fortran +forwardig||forwarding +framwork||framework +frequncy||frequency +frome||from +fucntion||function +fuction||function +fuctions||functions +funcion||function +functionallity||functionality +functionaly||functionally +functionnality||functionality +functonality||functionality +funtion||function +funtions||functions +furthur||further +futhermore||furthermore +futrue||future +gaurenteed||guaranteed +generiously||generously +genric||generic +globel||global +grabing||grabbing +grahical||graphical +grahpical||graphical +grapic||graphic +guage||gauge +guarenteed||guaranteed +guarentee||guarantee +halfs||halves +hander||handler +handfull||handful +hanled||handled +happend||happened +harware||hardware +heirarchically||hierarchically +helpfull||helpful +hierachy||hierarchy +hierarchie||hierarchy +howver||however +hsould||should +hypter||hyper +identidier||identifier +imblance||imbalance +immeadiately||immediately +immedaite||immediate +immediatelly||immediately +immediatly||immediately +immidiate||immediate +impelentation||implementation +impementated||implemented +implemantation||implementation +implemenation||implementation +implementaiton||implementation +implementated||implemented +implemention||implementation +implemetation||implementation +implemntation||implementation +implentation||implementation +implmentation||implementation +implmenting||implementing +incomming||incoming +incompatabilities||incompatibilities +incompatable||incompatible +inconsistant||inconsistent +increas||increase +incrment||increment +indendation||indentation +indended||intended +independant||independent +independantly||independently +independed||independent +indiate||indicate +inexpect||inexpected +infomation||information +informatiom||information +informations||information +informtion||information +infromation||information +ingore||ignore +inital||initial +initalised||initialized +initalise||initialize +initalize||initialize +initation||initiation +initators||initiators +initializiation||initialization +initialzed||initialized +initilization||initialization +initilize||initialize +inofficial||unofficial +insititute||institute +instal||install +inteface||interface +integreated||integrated +integrety||integrity +integrey||integrity +intendet||intended +intented||intended +interanl||internal +interchangable||interchangeable +interferring||interfering +interger||integer +intermittant||intermittent +internel||internal +interoprability||interoperability +interrface||interface +interrrupt||interrupt +interrup||interrupt +interrups||interrupts +interruptted||interrupted +interupted||interrupted +interupt||interrupt +intial||initial +intialized||initialized +intialize||initialize +intregral||integral +intrrupt||interrupt +intuative||intuitive +invaid||invalid +invalde||invald +invalide||invalid +invididual||individual +invokation||invocation +invokations||invocations +irrelevent||irrelevant +isnt||isn't +isssue||issue +itslef||itself +jave||java +jeffies||jiffies +juse||just +jus||just +kown||known +langage||language +langauage||language +langauge||language +langugage||language +lauch||launch +layed||laid +leightweight||lightweight +lengh||length +lenght||length +lenth||length +lesstiff||lesstif +libaries||libraries +libary||library +librairies||libraries +libraris||libraries +licenceing||licencing +loggging||logging +loggin||login +logile||logfile +loosing||losing +losted||lost +machinary||machinery +maintainance||maintenance +maintainence||maintenance +maintan||maintain +makeing||making +malplaced||misplaced +malplace||misplace +managable||manageable +managment||management +mangement||management +manoeuvering||maneuvering +mappping||mapping +mathimatical||mathematical +mathimatic||mathematic +mathimatics||mathematics +maxium||maximum +mechamism||mechanism +meetign||meeting +ment||meant +mergable||mergeable +mesage||message +messags||messages +messgaes||messages +messsage||message +messsages||messages +microprocesspr||microprocessor +milliseonds||milliseconds +minumum||minimum +miscelleneous||miscellaneous +misformed||malformed +mispelled||misspelled +mispelt||misspelt +miximum||maximum +mmnemonic||mnemonic +mnay||many +modulues||modules +monochorome||monochrome +monochromo||monochrome +monocrome||monochrome +mopdule||module +mroe||more +mulitplied||multiplied +multidimensionnal||multidimensional +multple||multiple +mumber||number +muticast||multicast +mutiple||multiple +mutli||multi +nams||names +navagating||navigating +nead||need +neccecary||necessary +neccesary||necessary +neccessary||necessary +necesary||necessary +negaive||negative +negoitation||negotiation +negotation||negotiation +nerver||never +nescessary||necessary +nessessary||necessary +noticable||noticeable +notications||notifications +notifed||notified +numebr||number +numner||number +obtaion||obtain +occassionally||occasionally +occationally||occasionally +occurance||occurrence +occurances||occurrences +occured||occurred +occurence||occurrence +occure||occurred +occuring||occurring +offet||offset +omitt||omit +ommiting||omitting +ommitted||omitted +onself||oneself +ony||only +operatione||operation +opertaions||operations +optionnal||optional +optmizations||optimizations +orientatied||orientated +orientied||oriented +otherise||otherwise +ouput||output +overaall||overall +overhread||overhead +overlaping||overlapping +overriden||overridden +overun||overrun +pacakge||package +pachage||package +packacge||package +packege||package +packge||package +packtes||packets +pakage||package +pallette||palette +paln||plan +paramameters||parameters +paramater||parameter +parametes||parameters +parametised||parametrised +paramter||parameter +paramters||parameters +particuarly||particularly +particularily||particularly +pased||passed +passin||passing +pathes||paths +pecularities||peculiarities +peformance||performance +peice||piece +pendantic||pedantic +peprocessor||preprocessor +perfoming||performing +permissons||permissions +peroid||period +persistance||persistence +persistant||persistent +platfrom||platform +plattform||platform +pleaes||please +ploting||plotting +plugable||pluggable +poinnter||pointer +poiter||pointer +posible||possible +positon||position +possibilites||possibilities +powerfull||powerful +preceeded||preceded +preceeding||preceding +preceed||precede +precendence||precedence +precission||precision +preemptable||preemptible +prefered||preferred +prefferably||preferably +premption||preemption +prepaired||prepared +pressre||pressure +primative||primitive +princliple||principle +priorty||priority +privilaged||privileged +privilage||privilege +priviledge||privilege +priviledges||privileges +probaly||probably +procceed||proceed +proccesors||processors +procesed||processed +proces||process +processessing||processing +processess||processes +processpr||processor +processsed||processed +processsing||processing +procteted||protected +prodecure||procedure +progams||programs +progess||progress +programers||programmers +programm||program +programms||programs +progresss||progress +promiscous||promiscuous +promps||prompts +pronnounced||pronounced +prononciation||pronunciation +pronouce||pronounce +pronunce||pronounce +propery||property +propigate||propagate +propigation||propagation +propogate||propagate +prosess||process +protable||portable +protcol||protocol +protecion||protection +protocoll||protocol +psudo||pseudo +psuedo||pseudo +psychadelic||psychedelic +pwoer||power +quering||querying +raoming||roaming +reasearcher||researcher +reasearchers||researchers +reasearch||research +recepient||recipient +receving||receiving +recieved||received +recieve||receive +reciever||receiver +recieves||receives +recogniced||recognised +recognizeable||recognizable +recommanded||recommended +recyle||recycle +redircet||redirect +redirectrion||redirection +refcounf||refcount +refence||reference +refered||referred +referenace||reference +refering||referring +refernces||references +refernnce||reference +refrence||reference +registerd||registered +registeresd||registered +registes||registers +registraration||registration +regster||register +regualar||regular +reguator||regulator +regulamentations||regulations +reigstration||registration +releated||related +relevent||relevant +remoote||remote +remore||remote +removeable||removable +repectively||respectively +replacable||replaceable +replacments||replacements +replys||replies +reponse||response +representaion||representation +reqeust||request +requiere||require +requirment||requirement +requred||required +requried||required +requst||request +reseting||resetting +resizeable||resizable +resouces||resources +resoures||resources +responce||response +ressizes||resizes +ressource||resource +ressources||resources +retransmited||retransmitted +retreived||retrieved +retreive||retrieve +retrive||retrieve +retuned||returned +reudce||reduce +reuest||request +reuqest||request +reutnred||returned +rmeoved||removed +rmeove||remove +rmeoves||removes +rountine||routine +routins||routines +rquest||request +runing||running +runned||ran +runnning||running +runtine||runtime +sacrifying||sacrificing +safly||safely +safty||safety +savable||saveable +scaned||scanned +scaning||scanning +scarch||search +seach||search +searchs||searches +secquence||sequence +secund||second +segement||segment +senarios||scenarios +sentivite||sensitive +separatly||separately +sepcify||specify +sepc||spec +seperated||separated +seperately||separately +seperate||separate +seperatly||separately +seperator||separator +sepperate||separate +sequece||sequence +sequencial||sequential +serveral||several +setts||sets +settting||setting +shotdown||shutdown +shoud||should +shouldnt||shouldn't +shoule||should +shrinked||shrunk +siginificantly||significantly +signabl||signal +similary||similarly +similiar||similar +simlar||similar +simliar||similar +simpified||simplified +singaled||signaled +singal||signal +singed||signed +sleeped||slept +softwares||software +speach||speech +specfic||specific +speciefied||specified +specifc||specific +specifed||specified +specificatin||specification +specificaton||specification +specifing||specifying +specifiying||specifying +speficied||specified +speicify||specify +speling||spelling +spinlcok||spinlock +spinock||spinlock +splitted||split +spreaded||spread +sructure||structure +stablilization||stabilization +staically||statically +staion||station +standardss||standards +standartization||standardization +standart||standard +staticly||statically +stoped||stopped +stoppped||stopped +straming||streaming +struc||struct +structres||structures +stuct||struct +stucture||structure +sturcture||structure +subdirectoires||subdirectories +suble||subtle +substract||subtract +succesfully||successfully +succesful||successful +successfull||successful +sucessfully||successfully +sucess||success +superflous||superfluous +superseeded||superseded +suplied||supplied +suported||supported +suport||support +suppored||supported +supportin||supporting +suppoted||supported +suppported||supported +suppport||support +supress||suppress +surpresses||suppresses +susbsystem||subsystem +suspicously||suspiciously +swaping||swapping +switchs||switches +symetric||symmetric +synax||syntax +synchonized||synchronized +syncronize||synchronize +syncronizing||synchronizing +syncronus||synchronous +syste||system +sytem||system +sythesis||synthesis +taht||that +targetted||targeted +targetting||targeting +teh||the +temorary||temporary +temproarily||temporarily +thier||their +threds||threads +threshhold||threshold +throught||through +thses||these +tiggered||triggered +tipically||typically +tmis||this +torerable||tolerable +tramsmitted||transmitted +tramsmit||transmit +tranfer||transfer +transciever||transceiver +transferd||transferrd +transfered||transferred +transfering||transferring +transision||transition +transmittd||transmitted +transormed||transformed +trasmission||transmission +treshold||threshold +trigerring||triggering +trun||turn +ture||true +tyep||type +udpate||update +uesd||used +unconditionaly||unconditionally +underun||underrun +unecessary||unnecessary +unexecpted||unexpected +unexpectd||unexpected +unexpeted||unexpected +unfortunatelly||unfortunately +unifiy||unify +unintialized||uninitialized +unknonw||unknown +unknow||unknown +unkown||unknown +unneedingly||unnecessarily +unresgister||unregister +unsinged||unsigned +unstabel||unstable +unsuccessfull||unsuccessful +unsuported||unsupported +untill||until +unuseful||useless +upate||update +usefule||useful +usefull||useful +usege||usage +usera||users +usualy||usually +utilites||utilities +utillities||utilities +utilties||utilities +utiltity||utility +utitity||utility +utitlty||utility +vaid||valid +vaild||valid +valide||valid +variantions||variations +varient||variant +vaule||value +verbse||verbose +verisons||versions +verison||version +verson||version +vicefersa||vice-versa +virtal||virtual +virtaul||virtual +virtiual||virtual +visiters||visitors +vitual||virtual +wating||waiting +wether||whether +whataver||whatever +whcih||which +whenver||whenever +wheter||whether +whe||when +wierd||weird +wiil||will +wirte||write +withing||within +wnat||want +workarould||workaround +writeing||writing +writting||writing +zombe||zombie +zomebie||zombie diff --git a/drivers/misc/mediatek/connectivity/common/Android.mk b/drivers/misc/mediatek/connectivity/common/Android.mk new file mode 100644 index 00000000000000..7d053ab8e2b4a9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/Android.mk @@ -0,0 +1,28 @@ +LOCAL_PATH := $(call my-dir) + +ifneq ($(filter yes,$(sort $(MTK_WLAN_SUPPORT) $(MTK_BT_SUPPORT) $(MTK_GPS_SUPPORT) $(MTK_FM_SUPPORT))),) + +ifneq (true,$(strip $(TARGET_NO_KERNEL))) +ifneq ($(filter yes,$(MTK_COMBO_SUPPORT)),) + +include $(CLEAR_VARS) +LOCAL_MODULE := wmt_drv.ko +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_OWNER := mtk + +LOCAL_INIT_RC := init.wmt_drv.rc +LOCAL_SRC_FILES := $(patsubst $(LOCAL_PATH)/%,%,$(shell find $(LOCAL_PATH) -type f -name '*.[cho]')) Makefile +LOCAL_REQUIRED_MODULES := + +include $(MTK_KERNEL_MODULE) + +WMT_OPTS := MTK_CONSYS_ADIE=$(MTK_CONSYS_ADIE) + +$(linked_module): OPTS += $(WMT_OPTS) + +else + $(warning wmt_drv-MTK_COMBO_SUPPORT: [$(MTK_COMBO_SUPPORT)]) +endif +endif + +endif diff --git a/drivers/misc/mediatek/connectivity/common/Makefile b/drivers/misc/mediatek/connectivity/common/Makefile new file mode 100644 index 00000000000000..0eba198e217c3c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/Makefile @@ -0,0 +1,296 @@ +############################################################################### +# Necessary Check + +ifeq ($(AUTOCONF_H),) + AUTOCONF_H := $(srctree)/include/generated/autoconf.h +endif + +ifneq ($(CONFIG_MTK_COMBO),) + +ccflags-y += -imacros $(AUTOCONF_H) + +ifeq ($(CONFIG_MTK_COMBO_CHIP),) + $(error CONFIG_MTK_COMBO_CHIP not defined) +endif + +ifeq ($(TARGET_BUILD_VARIANT),$(filter $(TARGET_BUILD_VARIANT),userdebug user)) + #ldflags-y += -s +endif + +# Force build fail on modpost warning +KBUILD_MODPOST_FAIL_ON_WARNINGS := y +############################################################################### + +#ccflags-y += -D MTK_WCN_REMOVE_KERNEL_MODULE +ifeq ($(CONFIG_ARM64), y) + ccflags-y += -D CONFIG_MTK_WCN_ARM64 +endif + +ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y) + ccflags-y += -D WMT_IDC_SUPPORT=1 +else + ccflags-y += -D WMT_IDC_SUPPORT=0 +endif + +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/btif/common/plat_inc +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat +ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/$(MTK_PLATFORM) +ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include/clkbuf_v1 +ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include/clkbuf_v1/$(MTK_PLATFORM) +ccflags-y += -I$(srctree)/drivers/misc/mediatek/btif/common/inc +ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci +ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci/$(MTK_PLATFORM) +ccflags-y += -I$(srctree)/drivers/misc/mediatek/eemcs +ccflags-y += -I$(srctree)/drivers/misc/mediatek/conn_md/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/connectivity/conninfra/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/connectivity/conninfra/base/include +ccflags-y += -I$(srctree)/drivers/mmc/core +ccflags-y += -I$(srctree)/drivers/misc/mediatek/mach/$(MTK_PLATFORM)/include/mach +ccflags-y += -I$(srctree)/drivers/misc/mediatek/emi/submodule +ccflags-y += -I$(srctree)/drivers/misc/mediatek/emi/$(MTK_PLATFORM) +ifeq ($(CONFIG_MTK_PMIC_CHIP_MT6359),y) +ccflags-y += -I$(srctree)/drivers/misc/mediatek/pmic/include/mt6359 +endif +ccflags-y += -I$(srctree)/drivers/mmc/core +############################################################################### + + +ccflags-y += -Werror + +ifneq ($(filter "MT6628",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -D MT6628 + ccflags-y += -D MERGE_INTERFACE_SUPPORT +endif + +ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -D MT6630 +ifneq ($(CONFIG_ARCH_MT2601),y) + ccflags-y += -D MERGE_INTERFACE_SUPPORT +endif +endif + +ifneq ($(filter MT7668,$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -D MT7668 +else + ccflags-y += -D MERGE_INTERFACE_SUPPORT +endif + +ifneq ($(filter "MT6632",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -D MT6632 + ccflags-y += -D MERGE_INTERFACE_SUPPORT +endif + +#obj-y += common_main/ +#obj-y += common_detect/ + +ifneq ($(filter MT6631,$(MTK_CONSYS_ADIE)),) + ccflags-y += -D CONSYS_PMIC_CTRL_6635=0 +else + ccflags-y += -D CONSYS_PMIC_CTRL_6635=1 +endif + +ifneq ($(filter MT7668,$(MTK_CONSYS_ADIE)),) + ccflags-y += -D CONSYS_PMIC_CTRL_7668=0 +else + ccflags-y += -D CONSYS_PMIC_CTRL_7668=1 +endif + +############################################################################### +MODULE_NAME := wmt_drv +ifeq ($(CONFIG_MTK_COMBO_COMM),y) +$(warning $(MODULE_NAME) build-in boot.img) +obj-y += $(MODULE_NAME).o +else +$(warning $(MODULE_NAME) is kernel module) +obj-m += $(MODULE_NAME).o +endif + +############################################################################### +# common_detect +############################################################################### +#ccflags-y += -I$(srctree)/arch/arm/mach-$(MTK_PLATFORM)/$(ARCH_MTK_PROJECT)/dct/dct +#ccflags-y += -DWMT_PLAT_ALPS=1 + +COMBO_CHIP_SUPPORT := false +ifneq ($(filter "MT6620E3",$(CONFIG_MTK_COMBO_CHIP)),) + COMBO_CHIP_SUPPORT := true +endif +ifneq ($(filter "MT6628",$(CONFIG_MTK_COMBO_CHIP)),) + COMBO_CHIP_SUPPORT := true +endif +ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),) + COMBO_CHIP_SUPPORT := true +endif +ifneq ($(filter "MT6632",$(CONFIG_MTK_COMBO_CHIP)),) + COMBO_CHIP_SUPPORT := true +endif +ifneq ($(filter "MT7668",$(CONFIG_MTK_COMBO_CHIP)),) + COMBO_CHIP_SUPPORT := true +endif + +ifeq ($(COMBO_CHIP_SUPPORT), true) + ccflags-y += -D MTK_WCN_COMBO_CHIP_SUPPORT +endif + +ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -D MTK_WCN_SOC_CHIP_SUPPORT +endif + +ccflags-y += -I$(src)/common_main/linux/include +ccflags-y += -I$(src)/common_detect/drv_init/inc +ccflags-y += -I$(src)/common_detect +ccflags-y += -I$(src)/debug_utility + +$(MODULE_NAME)-objs += common_detect/wmt_detect_pwr.o +$(MODULE_NAME)-objs += common_detect/wmt_detect.o +$(MODULE_NAME)-objs += common_detect/sdio_detect.o +$(MODULE_NAME)-objs += common_detect/mtk_wcn_stub_alps.o +$(MODULE_NAME)-objs += common_detect/wmt_gpio.o +#$(MODULE_NAME)-objs += common_detect/wmt_stp_exp.o + + +ifneq ($(filter "MT6630",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -D MTK_WCN_WLAN_GEN3 +endif + +ifneq ($(filter "MT7668",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -D MTK_WCN_WLAN_GEN4 +endif + +ifneq ($(filter "MT6632",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -D MTK_WCN_WLAN_GEN4 +endif + +ifneq ($(filter "CONSYS_6797" "CONSYS_6759" "CONSYS_6758" "CONSYS_6771" "CONSYS_6775",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -D MTK_WCN_WLAN_GEN3 +else ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -D MTK_WCN_WLAN_GEN2 +endif + +$(MODULE_NAME)-objs += common_detect/drv_init/fm_drv_init.o +$(MODULE_NAME)-objs += common_detect/drv_init/conn_drv_init.o +$(MODULE_NAME)-objs += common_detect/drv_init/bluetooth_drv_init.o +$(MODULE_NAME)-objs += common_detect/drv_init/wlan_drv_init.o +$(MODULE_NAME)-objs += common_detect/drv_init/common_drv_init.o +$(MODULE_NAME)-objs += common_detect/drv_init/gps_drv_init.o + + +############################################################################### +# common_main +############################################################################### +ccflags-y += -I$(src)/common_main/linux/pri/include +ccflags-y += -I$(src)/common_main/platform/include +ccflags-y += -I$(src)/common_main/core/include +ccflags-y += -I$(src)/common_main/include + +ccflags-y += -D WMT_PLAT_ALPS=1 +ccflags-y += -D WMT_UART_RX_MODE_WORK=1 # 1. work thread 0. tasklet +ccflags-y += -D WMT_SDIO_MODE=1 +ccflags-y += -D WMT_CREATE_NODE_DYNAMIC=1 + +ifneq ($(TARGET_BUILD_VARIANT),eng) +#ifeq ($(CONFIG_EXTREME_LOW_RAM), y) + ccflags-y += -D LOG_STP_DEBUG_DISABLE +#endif +endif + +ifneq ($(TARGET_BUILD_VARIANT), user) + ccflags-y += -D WMT_DBG_SUPPORT=1 +else + ccflags-y += -D WMT_DBG_SUPPORT=0 +endif + +ifeq ($(CONFIG_MTK_DEVAPC),y) + ccflags-y += -D WMT_DEVAPC_DBG_SUPPORT=1 +else + ccflags-y += -D WMT_DEVAPC_DBG_SUPPORT=0 +endif + +ifeq ($(CONFIG_ARCH_MT6580), y) +ccflags-y += -D CFG_WMT_READ_EFUSE_VCN33 +endif + +# STEP: (Support Connac) +# MTK eng/userdebug/user load: Support +# Customer eng/userdebug load: Support +# Customer user load: Not support + +ifeq ($(wildcard vendor/mediatek/proprietary/external/aee_config_internal/init.aee.mtk.system.rc),) + ccflags-y += -D CFG_WMT_STEP +else + ifneq ($(TARGET_BUILD_VARIANT),user) + ccflags-y += -D CFG_WMT_STEP + endif +endif + +ifeq ($(findstring evb, $(MTK_PROJECT)), evb) +ccflags-y += -D CFG_WMT_EVB +endif + +ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) +$(MODULE_NAME)-objs += common_main/platform/$(MTK_PLATFORM).o +endif + +#$(MODULE_NAME)-objs += common_main/platform/wmt_plat_stub.o +$(MODULE_NAME)-objs += common_main/platform/wmt_plat_alps.o +$(MODULE_NAME)-objs += common_main/platform/mtk_wcn_consys_hw.o +$(MODULE_NAME)-objs += common_main/platform/mtk_wcn_cmb_hw.o +$(MODULE_NAME)-objs += common_main/platform/wmt_build_in_adapter.o + +$(MODULE_NAME)-objs += common_main/core/wmt_ic_6628.o +$(MODULE_NAME)-objs += common_main/core/wmt_conf.o +$(MODULE_NAME)-objs += common_main/core/stp_core.o +#$(MODULE_NAME)-objs += common_main/core/hci_stp.o +$(MODULE_NAME)-objs += common_main/core/wmt_ctrl.o +$(MODULE_NAME)-objs += common_main/core/wmt_func.o +$(MODULE_NAME)-objs += common_main/core/wmt_core.o +$(MODULE_NAME)-objs += common_main/core/psm_core.o +$(MODULE_NAME)-objs += common_main/core/wmt_ic_soc.o +$(MODULE_NAME)-objs += common_main/core/wmt_lib.o +$(MODULE_NAME)-objs += common_main/core/wmt_ic_6620.o +$(MODULE_NAME)-objs += common_main/core/stp_exp.o +$(MODULE_NAME)-objs += common_main/core/wmt_ic_6632.o +$(MODULE_NAME)-objs += common_main/core/wmt_exp.o +$(MODULE_NAME)-objs += common_main/core/btm_core.o +$(MODULE_NAME)-objs += common_main/core/wmt_ic_6630.o + +$(MODULE_NAME)-objs += common_main/linux/hif_sdio.o +$(MODULE_NAME)-objs += common_main/linux/stp_dbg_soc.o +$(MODULE_NAME)-objs += common_main/linux/stp_dbg_combo.o +$(MODULE_NAME)-objs += common_main/linux/wmt_dev.o +$(MODULE_NAME)-objs += common_main/linux/stp_sdio.o +$(MODULE_NAME)-objs += common_main/linux/bgw_desense.o +$(MODULE_NAME)-objs += common_main/linux/wmt_idc.o +$(MODULE_NAME)-objs += common_main/linux/stp_uart.o +$(MODULE_NAME)-objs += common_main/linux/wmt_dbg.o +$(MODULE_NAME)-objs += common_main/linux/stp_dbg.o + +ifneq ($(CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH),) +$(MODULE_NAME)-objs += common_main/linux/fw_log_wmt.o +endif +$(MODULE_NAME)-objs += common_main/linux/wmt_step.o + +ifneq ($(CONFIG_MTK_BTIF),) +$(warning stp_btif build-in boot.img) +$(MODULE_NAME)-objs += common_main/linux/stp_btif.o +endif + +#$(MODULE_NAME)-objs += debug_utility/ring.o +$(MODULE_NAME)-objs += debug_utility/ring_emi.o +$(MODULE_NAME)-objs += debug_utility/connsys_debug_utility.o +############################################################################### +# test +############################################################################### +ifeq ($(TARGET_BUILD_VARIANT),eng) +ccflags-y += -I$(src)/test/include +endif + +ifeq ($(TARGET_BUILD_VARIANT),eng) +$(MODULE_NAME)-objs += test/wmt_step_test.o +endif + +endif diff --git a/drivers/misc/mediatek/connectivity/common/README b/drivers/misc/mediatek/connectivity/common/README new file mode 100644 index 00000000000000..8b3fbca848d9dc --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/README @@ -0,0 +1,2 @@ +WMT driver - kernel modules move out of kernel tree + diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c new file mode 100644 index 00000000000000..52eb5541a7ea11 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/bluetooth_drv_init.c @@ -0,0 +1,47 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[BT-MOD-INIT]" + +#include "wmt_detect.h" +#include "bluetooth_drv_init.h" + +#ifndef CONFIG_MTK_COMBO_BT_HCI +int __attribute__((weak)) mtk_wcn_stpbt_drv_init() +{ + WMT_DETECT_PR_INFO("Not implement mtk_wcn_stpbt_drv_init\n"); + return 0; +} +#endif + +int do_bluetooth_drv_init(int chip_id) +{ + int i_ret = -1; + +#ifdef CONFIG_MTK_COMBO_BT_HCI + WMT_DETECT_PR_INFO("start to do bluetooth driver init\n"); +#ifdef CONFIG_BT_HCISTP + i_ret = mtk_hci_init(); +#else + i_ret = mtk_wcn_stpbt_drv_init(); +#endif + WMT_DETECT_PR_INFO("finish bluetooth driver init, i_ret:%d\n", i_ret); +#else + WMT_DETECT_PR_INFO("CONFIG_MTK_COMBO_BT_HCI is not defined\n"); +#endif + return i_ret; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c new file mode 100644 index 00000000000000..e6c64529eaff71 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/common_drv_init.c @@ -0,0 +1,59 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-MOD-INIT]" + +#include "wmt_detect.h" +#include "common_drv_init.h" + + +#if (MTK_WCN_REMOVE_KO) +int do_common_drv_init(int chip_id) +{ + int i_ret = 0; + int i_ret_tmp = 0; + + WMT_DETECT_PR_INFO("start to do common driver init, chipid:0x%08x\n", chip_id); + + wmt_detect_set_chip_type(chip_id); + + /* HIF-SDIO driver init */ + i_ret_tmp = mtk_wcn_hif_sdio_drv_init(); + i_ret += i_ret_tmp; + WMT_DETECT_PR_DBG("HIF-SDIO driver init, i_ret:%d\n", i_ret); + + /* WMT driver init */ + i_ret_tmp = mtk_wcn_common_drv_init(); + i_ret += i_ret_tmp; + WMT_DETECT_PR_DBG("COMBO COMMON driver init, i_ret:%d\n", i_ret); + + /* STP-UART driver init */ + i_ret_tmp = mtk_wcn_stp_uart_drv_init(); + i_ret += i_ret_tmp; + WMT_DETECT_PR_DBG("STP-UART driver init, i_ret:%d\n", i_ret); + + /* STP-SDIO driver init */ + i_ret_tmp = mtk_wcn_stp_sdio_drv_init(); + i_ret += i_ret_tmp; + WMT_DETECT_PR_DBG("STP-SDIO driver init, i_ret:%d\n", i_ret); + + WMT_DETECT_PR_INFO("common driver init finish:%d\n", i_ret); + return i_ret; + +} +#endif + diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c new file mode 100644 index 00000000000000..ab03a5b14fe788 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/conn_drv_init.c @@ -0,0 +1,70 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WCN-MOD-INIT]" + +#include "wmt_detect.h" +#include "conn_drv_init.h" +#include "common_drv_init.h" +#include "fm_drv_init.h" +#include "wlan_drv_init.h" +#include "bluetooth_drv_init.h" +#include "gps_drv_init.h" + +#if (MTK_WCN_REMOVE_KO) +int do_connectivity_driver_init(int chip_id) +{ + int i_ret = 0; + int tmp_ret = 0; + static int init_before; + + /* To avoid invoking more than once.*/ + if (init_before) + return 0; + init_before = 1; + + tmp_ret = do_common_drv_init(chip_id); + i_ret += tmp_ret; + if (tmp_ret) { + WMT_DETECT_PR_ERR("do common driver not ready, ret:%d\n abort!\n", tmp_ret); + return i_ret; + } + + tmp_ret = do_bluetooth_drv_init(chip_id); + i_ret += tmp_ret; + if (tmp_ret) + WMT_DETECT_PR_ERR("do common driver init failed, ret:%d\n", tmp_ret); + + tmp_ret = do_gps_drv_init(chip_id); + i_ret += tmp_ret; + if (tmp_ret) + WMT_DETECT_PR_ERR("do common driver init failed, ret:%d\n", tmp_ret); + + tmp_ret = do_fm_drv_init(chip_id); + i_ret += tmp_ret; + if (tmp_ret) + WMT_DETECT_PR_ERR("do fm module init failed, ret:%d\n", tmp_ret); + + tmp_ret = do_wlan_drv_init(chip_id); + i_ret += tmp_ret; + if (tmp_ret) + WMT_DETECT_PR_ERR("do wlan module init failed, ret:%d\n", tmp_ret); + + return i_ret; +} +#endif + diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c new file mode 100644 index 00000000000000..4ec149e77046a6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/fm_drv_init.c @@ -0,0 +1,41 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[FM-MOD-INIT]" + +#include "wmt_detect.h" +#include "fm_drv_init.h" + +#ifdef CONFIG_MTK_FMRADIO +int __attribute__((weak)) mtk_wcn_fm_init() +{ + WMT_DETECT_PR_INFO("no impl. mtk_wcn_fm_init\n"); + return 0; +} +#endif + +int do_fm_drv_init(int chip_id) +{ + WMT_DETECT_PR_INFO("start to do fm module init\n"); + +#ifdef CONFIG_MTK_FMRADIO + mtk_wcn_fm_init(); +#endif + + WMT_DETECT_PR_INFO("finish fm module init\n"); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c new file mode 100644 index 00000000000000..ac48b231a3d0e8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/gps_drv_init.c @@ -0,0 +1,43 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[GPS-MOD-INIT]" + +#include "wmt_detect.h" +#include "gps_drv_init.h" + +#ifdef CONFIG_MTK_COMBO_GPS +int __attribute__((weak)) mtk_wcn_stpgps_drv_init() +{ + WMT_DETECT_PR_INFO("no impl. mtk_wcn_stpgps_drv_init\n"); + return 0; +} +#endif + +int do_gps_drv_init(int chip_id) +{ + int i_ret = -1; +#ifdef CONFIG_MTK_COMBO_GPS + WMT_DETECT_PR_INFO("start to do gps driver init\n"); + i_ret = mtk_wcn_stpgps_drv_init(); + WMT_DETECT_PR_INFO("finish gps driver init, i_ret:%d\n", i_ret); +#else + WMT_DETECT_PR_INFO("CONFIG_MTK_COMBO_GPS is not defined\n"); +#endif + return i_ret; + +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h new file mode 100644 index 00000000000000..10c02fb95d99ee --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/bluetooth_drv_init.h @@ -0,0 +1,25 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _BLUETOOTH_DRIVER_INIT_H_ +#define _BLUETOOTH_DRIVER_INIT_H_ + +extern int do_bluetooth_drv_init(int chip_id); +extern int mtk_wcn_stpbt_drv_init(void); + +#ifdef CONFIG_BT_HCISTP +extern int mtk_hci_init(void); +#endif + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h new file mode 100644 index 00000000000000..dae155e1d4039c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/common_drv_init.h @@ -0,0 +1,25 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _COMMON_DRV_INIT_H_ +#define _COMMON_DRV_INIT_H_ +extern int do_common_drv_init(int chip_id); + +extern int mtk_wcn_common_drv_init(void); +extern int mtk_wcn_hif_sdio_drv_init(void); +extern int mtk_wcn_stp_uart_drv_init(void); +extern int mtk_wcn_stp_sdio_drv_init(void); + + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h new file mode 100644 index 00000000000000..971193eade9e9b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/conn_drv_init.h @@ -0,0 +1,18 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _CONNECTIVITY_DRV_INIT_H_ +#define _CONNECTIVITY_DRV_INIT_H_ +extern int do_connectivity_driver_init(int chip_id); +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h new file mode 100644 index 00000000000000..f6ea30addc5da1 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/fm_drv_init.h @@ -0,0 +1,20 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _FM_DRV_INIT_H_ +#define _FM_DRV_INIT_H_ +extern int do_fm_drv_init(int chip_id); +extern int mtk_wcn_fm_init(void); +extern void mtk_wcn_fm_exit(void); +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h new file mode 100644 index 00000000000000..006ce072c53b66 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/gps_drv_init.h @@ -0,0 +1,19 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _GPS_DRIVER_INIT_H_ +#define _GPS_DRIVER_INIT_H_ +extern int do_gps_drv_init(int chip_id); +extern int mtk_wcn_stpgps_drv_init(void); +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h new file mode 100644 index 00000000000000..6ed7d4e458d1e8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/inc/wlan_drv_init.h @@ -0,0 +1,29 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _WLAN_DRV_INIT_H_ +#define _WLAN_DRV_INIT_H_ + + +extern int do_wlan_drv_init(int chip_id); + +extern int mtk_wcn_wmt_wifi_init(void); + +extern int mtk_wcn_wlan_gen2_init(void); + +extern int mtk_wcn_wlan_gen3_init(void); + +extern int mtk_wcn_wlan_gen4_init(void); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c new file mode 100644 index 00000000000000..335766817723c1 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/drv_init/wlan_drv_init.c @@ -0,0 +1,90 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WLAN-MOD-INIT]" + +#include "wmt_detect.h" +#include "wlan_drv_init.h" + +int __attribute__((weak)) mtk_wcn_wlan_gen4_init() +{ + WMT_DETECT_PR_INFO("no impl. mtk_wcn_wlan_gen4_init\n"); + return 0; +} + +int __attribute__((weak)) mtk_wcn_wlan_gen3_init() +{ + WMT_DETECT_PR_INFO("no impl. mtk_wcn_wlan_gen3_init\n"); + return 0; +} + +int __attribute__((weak)) mtk_wcn_wlan_gen2_init() +{ + WMT_DETECT_PR_INFO("no impl. mtk_wcn_wlan_gen2_init\n"); + return 0; +} + +int __attribute__((weak)) mtk_wcn_wmt_wifi_init() +{ + WMT_DETECT_PR_INFO("no impl. mtk_wcn_wmt_wifi_init\n"); + return 0; +} + +int do_wlan_drv_init(int chip_id) +{ + int i_ret = 0; + int ret = 0; + + WMT_DETECT_PR_INFO("start to do wlan module init 0x%x\n", chip_id); + + /* WMT-WIFI char dev init */ + ret = mtk_wcn_wmt_wifi_init(); + WMT_DETECT_PR_INFO("WMT-WIFI char dev init, ret:%d\n", ret); + i_ret += ret; + + switch (chip_id) { + case 0x6765: + case 0x6632: + /* WLAN driver init */ + ret = mtk_wcn_wlan_gen4_init(); + WMT_DETECT_PR_INFO("WLAN-GEN4 driver init, ret:%d\n", ret); + break; + + case 0x6630: + case 0x6797: + case 0x6758: + case 0x6759: + case 0x6775: + case 0x6771: + /* WLAN driver init */ + ret = mtk_wcn_wlan_gen3_init(); + WMT_DETECT_PR_INFO("WLAN-GEN3 driver init, ret:%d\n", ret); + break; + + default: + /* WLAN driver init */ + ret = mtk_wcn_wlan_gen2_init(); + WMT_DETECT_PR_INFO("WLAN-GEN2 driver init, ret:%d\n", ret); + break; + } + + i_ret += ret; + + WMT_DETECT_PR_INFO("finish wlan module init\n"); + + return i_ret; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c b/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c new file mode 100644 index 00000000000000..a217d368f4197f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/mtk_wcn_stub_alps.c @@ -0,0 +1,627 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * ! \file + * \brief Declaration of library functions + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. + */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + + +/* kernel wmt_build_in_adapter.c already has these, so always ignored */ +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE +#undef MTK_WCN_REMOVE_KERNEL_MODULE +#endif + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define CMB_STUB_DBG_LOG 3 +#define CMB_STUB_INFO_LOG 2 +#define CMB_STUB_WARN_LOG 1 + +int gCmbStubLogLevel = CMB_STUB_INFO_LOG; + +#define CMB_STUB_LOG_PR_INFO(fmt, arg...) \ +do { \ + if (gCmbStubLogLevel >= CMB_STUB_INFO_LOG) \ + pr_info(fmt, ##arg); \ +} while (0) +#define CMB_STUB_LOG_PR_WARN(fmt, arg...) \ +do { \ + if (gCmbStubLogLevel >= CMB_STUB_WARN_LOG) \ + pr_warn(fmt, ##arg); \ +} while (0) +#define CMB_STUB_LOG_PR_DBG(fmt, arg...) \ +do { \ + if (gCmbStubLogLevel >= CMB_STUB_DBG_LOG) \ + pr_info(fmt, ##arg); \ +} while (0) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/vmalloc.h> +#include <linux/workqueue.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/interrupt.h> +#include <osal_typedef.h> +#include <mtk_wcn_cmb_stub.h> +#include <wmt_build_in_adapter.h> +#include "wmt_detect.h" + +typedef INT32(*wmt_plat_trigger_assert_cb) (UINT32 type, UINT32 reason); + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +int gConnectivityChipId = -1; + +/* +* current used uart port name, default is "ttyMT2", +* will be changed when wmt driver init +*/ +char *wmt_uart_port_desc = "ttyMT2"; +EXPORT_SYMBOL(wmt_uart_port_desc); + +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE +static void mtk_wcn_cmb_sdio_request_eirq(msdc_sdio_irq_handler_t irq_handler, void *data); +static void mtk_wcn_cmb_sdio_enable_eirq(void); +static void mtk_wcn_cmb_sdio_disable_eirq(void); +static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data); + +struct sdio_ops mt_sdio_ops[4] = { + {NULL, NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL}, + {mtk_wcn_cmb_sdio_request_eirq, mtk_wcn_cmb_sdio_enable_eirq, + mtk_wcn_cmb_sdio_disable_eirq, mtk_wcn_cmb_sdio_register_pm}, + {mtk_wcn_cmb_sdio_request_eirq, mtk_wcn_cmb_sdio_enable_eirq, + mtk_wcn_cmb_sdio_disable_eirq, mtk_wcn_cmb_sdio_register_pm} +}; +#endif + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +//static wmt_aif_ctrl_cb cmb_stub_aif_ctrl_cb; +//static wmt_func_ctrl_cb cmb_stub_func_ctrl_cb; +//static wmt_thermal_query_cb cmb_stub_thermal_ctrl_cb; +//static wmt_plat_trigger_assert_cb cmb_stub_trigger_assert_cb; +//static CMB_STUB_AIF_X cmb_stub_aif_stat = CMB_STUB_AIF_0; +//static wmt_deep_idle_ctrl_cb cmb_stub_deep_idle_ctrl_cb; +//static wmt_func_do_reset cmb_stub_do_reset_cb; +//static wmt_clock_fail_dump_cb cmb_stub_clock_fail_dump_cb; +/* A temp translation table between COMBO_AUDIO_STATE_X and CMB_STUB_AIF_X. + * This is used for ALPS backward compatible ONLY!!! Remove this table, related + * functions, and type definition after modifying other kernel built-in modules, + * such as AUDIO. [FixMe][GeorgeKuo] + */ +#if 0 +static enum CMB_STUB_AIF_X audio2aif[] = { + [COMBO_AUDIO_STATE_0] = CMB_STUB_AIF_0, + [COMBO_AUDIO_STATE_1] = CMB_STUB_AIF_1, + [COMBO_AUDIO_STATE_2] = CMB_STUB_AIF_2, + [COMBO_AUDIO_STATE_3] = CMB_STUB_AIF_3, +}; +#endif + +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE +static msdc_sdio_irq_handler_t mtk_wcn_cmb_sdio_eirq_handler; +static atomic_t sdio_claim_irq_enable_flag; +static atomic_t irq_enable_flag; +static pm_callback_t mtk_wcn_cmb_sdio_pm_cb; +static void *mtk_wcn_cmb_sdio_pm_data; +static void *mtk_wcn_cmb_sdio_eirq_data; + +static u32 wifi_irq = 0xffffffff; +#endif +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +#ifndef MTK_WCN_REMOVE_KERNEL_MODULE +static int _mtk_wcn_cmb_stub_query_ctrl(void); +static int _mtk_wcn_cmb_stub_trigger_assert(void); +static void _mtk_wcn_cmb_stub_clock_fail_dump(void); +#endif /* MTK_WCN_REMOVE_KERNEL_MODULE */ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +/*! + * \brief A registration function for WMT-PLAT to register itself to CMB-STUB. + * + * An MTK-WCN-CMB-STUB registration function provided to WMT-PLAT to register + * itself and related callback functions when driver being loaded into kernel. + * + * \param p_stub_cb a pointer carrying CMB_STUB_CB information + * + * \retval 0 operation success + * \retval -1 invalid parameters + */ +int mtk_wcn_cmb_stub_reg(struct _CMB_STUB_CB_ *p_stub_cb) +{ +#ifndef MTK_WCN_REMOVE_KERNEL_MODULE + struct wmt_platform_bridge pbridge; + + memset(&pbridge, 0, sizeof(struct wmt_platform_bridge)); +#endif + + if ((!p_stub_cb) + || (p_stub_cb->size != sizeof(struct _CMB_STUB_CB_))) { + CMB_STUB_LOG_PR_WARN("[cmb_stub] invalid p_stub_cb:0x%p size(%d)\n", + p_stub_cb, (p_stub_cb) ? p_stub_cb->size : 0); + return -1; + } + + CMB_STUB_LOG_PR_DBG("[cmb_stub] registered, p_stub_cb:0x%p size(%d)\n", + p_stub_cb, p_stub_cb->size); + + //cmb_stub_aif_ctrl_cb = p_stub_cb->aif_ctrl_cb; + //cmb_stub_func_ctrl_cb = p_stub_cb->func_ctrl_cb; + //cmb_stub_thermal_ctrl_cb = p_stub_cb->thermal_query_cb; + //cmb_stub_trigger_assert_cb = p_stub_cb->trigger_assert_cb; + //cmb_stub_deep_idle_ctrl_cb = p_stub_cb->deep_idle_ctrl_cb; + //cmb_stub_do_reset_cb = p_stub_cb->wmt_do_reset_cb; + //cmb_stub_clock_fail_dump_cb = p_stub_cb->clock_fail_dump_cb; + +#ifndef MTK_WCN_REMOVE_KERNEL_MODULE + pbridge.thermal_query_cb = _mtk_wcn_cmb_stub_query_ctrl; + //pbridge.trigger_assert_cb = _mtk_wcn_cmb_stub_trigger_assert; + pbridge.clock_fail_dump_cb = _mtk_wcn_cmb_stub_clock_fail_dump; + wmt_export_platform_bridge_register(&pbridge); +#endif + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_reg); +/*! + * \brief A unregistration function for WMT-PLAT to unregister from CMB-STUB. + * + * An MTK-WCN-CMB-STUB unregistration function provided to WMT-PLAT to + * unregister itself and clear callback function references. + * + * \retval 0 operation success + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wint-conversion" +int mtk_wcn_cmb_stub_unreg(void) +{ +#ifndef MTK_WCN_REMOVE_KERNEL_MODULE + wmt_export_platform_bridge_unregister(); +#endif + + //cmb_stub_aif_ctrl_cb = NULL; + //cmb_stub_func_ctrl_cb = NULL; + //cmb_stub_thermal_ctrl_cb = NULL; + //cmb_stub_deep_idle_ctrl_cb = NULL; + //cmb_stub_do_reset_cb = NULL; + //cmb_stub_clock_fail_dump_cb = NULL; + CMB_STUB_LOG_PR_INFO("[cmb_stub] unregistered\n"); /* KERN_DEBUG */ + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_unreg); +#pragma GCC diagnostic pop +/* stub functions for kernel to control audio path pin mux */ +int mtk_wcn_cmb_stub_aif_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl) +{ + int ret; + + if ((state >= CMB_STUB_AIF_MAX) + || (ctrl >= CMB_STUB_AIF_CTRL_MAX)) { + + CMB_STUB_LOG_PR_WARN("[cmb_stub] aif_ctrl invalid (%d, %d)\n", + state, ctrl); + return -1; + } + + /* avoid the early interrupt before we register the eirq_handler */ + //if (cmb_stub_aif_ctrl_cb) { + // ret = (*cmb_stub_aif_ctrl_cb) (state, ctrl); + //CMB_STUB_LOG_PR_INFO("aif state(%d->%d) ctrl(%d) ret(%d)\n", cmb_stub_aif_stat, state, ctrl, ret); /* KERN_DEBUG */ + + //cmb_stub_aif_stat = state; + //} else { + CMB_STUB_LOG_PR_WARN("[cmb_stub] aif_ctrl_cb null\n"); + ret = -2; + //} + return ret; +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_aif_ctrl); + +/* Use a temp translation table between COMBO_AUDIO_STATE_X and CMB_STUB_AIF_X + * for ALPS backward compatible ONLY!!! Remove this table, related functions, + * and type definition after modifying other kernel built-in modules, such as + * AUDIO. [FixMe][GeorgeKuo] + */ + +void mtk_wcn_cmb_stub_func_ctrl(unsigned int type, unsigned int on) +{ + //if (cmb_stub_func_ctrl_cb) + // (*cmb_stub_func_ctrl_cb) (type, on); + //else + CMB_STUB_LOG_PR_WARN("[cmb_stub] func_ctrl_cb null\n"); +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_func_ctrl); + +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE +int mtk_wcn_cmb_stub_query_ctrl(void) +#else +static int _mtk_wcn_cmb_stub_query_ctrl(void) +#endif +{ + signed long temp = 0; + + //if (cmb_stub_thermal_ctrl_cb) + // temp = (*cmb_stub_thermal_ctrl_cb) (); + //else + CMB_STUB_LOG_PR_WARN("[cmb_stub] thermal_ctrl_cb null\n"); + + return temp; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE +int mtk_wcn_cmb_stub_trigger_assert(void) +#else +static int _mtk_wcn_cmb_stub_trigger_assert(void) +#endif +{ + int ret = 0; + + //if (cmb_stub_trigger_assert_cb) + // ret = (*cmb_stub_trigger_assert_cb) (); + //else + CMB_STUB_LOG_PR_WARN("[cmb_stub] trigger_assert_cb null\n"); + + return ret; +} +#pragma GCC diagnostic pop + +#ifndef MTK_WCN_REMOVE_KERNEL_MODULE +void _mtk_wcn_cmb_stub_clock_fail_dump(void) +{ + //if (cmb_stub_clock_fail_dump_cb) + // (*cmb_stub_clock_fail_dump_cb) (); + //else + CMB_STUB_LOG_PR_WARN("[cmb_stub] clock_fail_dump_cb null\n"); +} +#endif + +/*platform-related APIs*/ +/* void clr_device_working_ability(UINT32 clockId, MT6573_STATE state); */ +/* void set_device_working_ability(UINT32 clockId, MT6573_STATE state); */ + +static int _mt_combo_plt_do_deep_idle(COMBO_IF src, int enter) +{ + int ret = -1; + +#if 0 + if (src != COMBO_IF_UART && src != COMBO_IF_MSDC && src != COMBO_IF_BTIF) { + CMB_STUB_LOG_PR_WARN("src = %d is error\n", src); + return ret; + } + if (src >= 0 && src < COMBO_IF_MAX) + CMB_STUB_LOG_PR_INFO("src = %s, to enter deep idle? %d\n", + combo_if_name[src], enter); +#endif + /* + * TODO: For Common SDIO configuration, we need to do some judgement between STP and WIFI + * to decide if the msdc will enter deep idle safely + */ + + switch (src) { + case COMBO_IF_UART: + if (enter == 0) { + /* clr_device_working_ability(MT65XX_PDN_PERI_UART3, DEEP_IDLE_STATE); */ + /* disable_dpidle_by_bit(MT65XX_PDN_PERI_UART2); */ +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT +#if 0 + ret = mtk_uart_pdn_enable(wmt_uart_port_desc, 0); + if (ret < 0) + CMB_STUB_LOG_PR_WARN("%s exit deepidle failed", + wmt_uart_port_desc); +#endif +#endif + } else { + /* set_device_working_ability(MT65XX_PDN_PERI_UART3, DEEP_IDLE_STATE); */ + /* enable_dpidle_by_bit(MT65XX_PDN_PERI_UART2); */ +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT +#if 0 + ret = mtk_uart_pdn_enable(wmt_uart_port_desc, 1); + if (ret < 0) + CMB_STUB_LOG_PR_WARN("%s enter deepidle failed", + wmt_uart_port_desc); +#endif +#endif + } + ret = 0; + break; + + case COMBO_IF_MSDC: + if (enter == 0) { + /* for common sdio hif */ + /* clr_device_working_ability(MT65XX_PDN_PERI_MSDC2, DEEP_IDLE_STATE); */ + } else { + /* for common sdio hif */ + /* set_device_working_ability(MT65XX_PDN_PERI_MSDC2, DEEP_IDLE_STATE); */ + } + ret = 0; + break; + + case COMBO_IF_BTIF: + //if (cmb_stub_deep_idle_ctrl_cb) + // ret = (*cmb_stub_deep_idle_ctrl_cb) (enter); + //else + CMB_STUB_LOG_PR_WARN("NULL function pointer\n"); + + if (ret) + CMB_STUB_LOG_PR_WARN("%s deep idle fail(%d)\n", + enter == 1 ? "enter" : "exit", ret); + else + CMB_STUB_LOG_PR_DBG("%s deep idle ok(%d)\n", + enter == 1 ? "enter" : "exit", ret); + break; + default: + break; + } + + return ret; +} + +int mt_combo_plt_enter_deep_idle(COMBO_IF src) +{ + /* return 0; */ + /* TODO: [FixMe][GeorgeKuo] handling this depends on common UART or common SDIO */ + return _mt_combo_plt_do_deep_idle(src, 1); +} +EXPORT_SYMBOL(mt_combo_plt_enter_deep_idle); + +int mt_combo_plt_exit_deep_idle(COMBO_IF src) +{ + /* return 0; */ + /* TODO: [FixMe][GeorgeKuo] handling this depends on common UART or common SDIO */ + return _mt_combo_plt_do_deep_idle(src, 0); +} +EXPORT_SYMBOL(mt_combo_plt_exit_deep_idle); + +int mtk_wcn_wmt_chipid_query(void) +{ + CMB_STUB_LOG_PR_INFO("query current consys chipid (0x%x)\n", + gConnectivityChipId); + return gConnectivityChipId; +} +EXPORT_SYMBOL(mtk_wcn_wmt_chipid_query); + +void mtk_wcn_wmt_set_chipid(int chipid) +{ + CMB_STUB_LOG_PR_INFO("set current consys chipid (0x%x)\n", chipid); + gConnectivityChipId = chipid; +} +EXPORT_SYMBOL(mtk_wcn_wmt_set_chipid); + +int mtk_wcn_cmb_stub_do_reset(unsigned int type) +{ + //if (cmb_stub_do_reset_cb) + // return (*cmb_stub_do_reset_cb) (type); + //else + return -1; +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_do_reset); + +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE +static void mtk_wcn_cmb_sdio_enable_eirq(void) +{ + if (atomic_read(&irq_enable_flag)) + CMB_STUB_LOG_PR_DBG("wifi eint has been enabled\n"); + else { + atomic_set(&irq_enable_flag, 1); + if (wifi_irq != 0xffffffff) { + enable_irq(wifi_irq); + CMB_STUB_LOG_PR_DBG(" enable WIFI EINT irq %d !!\n", + wifi_irq); + } + } +} + +static void mtk_wcn_cmb_sdio_disable_eirq(void) +{ + if (!atomic_read(&irq_enable_flag)) + CMB_STUB_LOG_PR_DBG("wifi eint has been disabled!\n"); + else { + if (wifi_irq != 0xffffffff) { + disable_irq_nosync(wifi_irq); + CMB_STUB_LOG_PR_DBG("disable WIFI EINT irq %d !!\n", + wifi_irq); + } + atomic_set(&irq_enable_flag, 0); + } +} + +irqreturn_t mtk_wcn_cmb_sdio_eirq_handler_stub(int irq, void *data) +{ + if ((mtk_wcn_cmb_sdio_eirq_handler != NULL) && (atomic_read(&sdio_claim_irq_enable_flag) != 0)) + mtk_wcn_cmb_sdio_eirq_handler(mtk_wcn_cmb_sdio_eirq_data); + return IRQ_HANDLED; +} + +static void mtk_wcn_cmb_sdio_request_eirq(msdc_sdio_irq_handler_t irq_handler, void *data) +{ + struct device_node *node; + int ret = -EINVAL; +#if 0 + unsigned int gpio_wifi_eint_pin; +#endif + + CMB_STUB_LOG_PR_INFO("enter %s\n", __func__); + mtk_wcn_sdio_irq_flag_set(0); + atomic_set(&irq_enable_flag, 1); + mtk_wcn_cmb_sdio_eirq_data = data; + mtk_wcn_cmb_sdio_eirq_handler = irq_handler; + + node = (struct device_node *)of_find_compatible_node(NULL, NULL, "mediatek,connectivity-combo"); + if (node) { +#if 0 + gpio_wifi_eint_pin = of_get_gpio(node, 5); + CMB_STUB_LOG_PR_INFO("WIFI EINT pin %d !!\n", + gpio_wifi_eint_pin); + wifi_irq = gpio_to_irq(gpio_wifi_eint_pin); +#else + wifi_irq = irq_of_parse_and_map(node, 0);/* get wifi eint num */ +#endif +#if 1 + ret = request_irq(wifi_irq, mtk_wcn_cmb_sdio_eirq_handler_stub, IRQF_TRIGGER_LOW, + "WIFI-eint", NULL); + CMB_STUB_LOG_PR_DBG("WIFI EINT irq %d !!\n", wifi_irq); +#endif + + if (ret) + CMB_STUB_LOG_PR_WARN("EINT IRQ LINE NOT AVAILABLE!!\n"); + else + mtk_wcn_cmb_sdio_disable_eirq();/*not ,chip state is power off*/ + } else + CMB_STUB_LOG_PR_WARN("[%s] can't find device node\n", __func__); + + CMB_STUB_LOG_PR_INFO("exit %s\n", __func__); +} + +static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data) +{ + CMB_STUB_LOG_PR_DBG("mtk_wcn_cmb_sdio_register_pm (0x%p, 0x%p)\n", + pm_cb, data); + /* register pm change callback */ + mtk_wcn_cmb_sdio_pm_cb = pm_cb; + mtk_wcn_cmb_sdio_pm_data = data; +} +#endif /* MTK_WCN_REMOVE_KERNEL_MODULE */ + +static void mtk_wcn_cmb_sdio_on(int sdio_port_num) +{ + pm_message_t state = {.event = PM_EVENT_USER_RESUME }; + + CMB_STUB_LOG_PR_INFO("mtk_wcn_cmb_sdio_on (%d)\n", sdio_port_num); + + /* 1. disable sdio eirq */ +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE + mtk_wcn_cmb_sdio_disable_eirq(); +#else + wmt_export_mtk_wcn_cmb_sdio_disable_eirq(); +#endif + + /* 2. call sd callback */ + if (mtk_wcn_cmb_sdio_pm_cb) { + /* pr_warn("mtk_wcn_cmb_sdio_pm_cb(PM_EVENT_USER_RESUME, 0x%p, 0x%p)\n", + * mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data); + */ + mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data); + } else + CMB_STUB_LOG_PR_WARN("mtk_wcn_cmb_sdio_on no sd callback!!\n"); +} + +static void mtk_wcn_cmb_sdio_off(int sdio_port_num) +{ + pm_message_t state = {.event = PM_EVENT_USER_SUSPEND }; + + CMB_STUB_LOG_PR_INFO("mtk_wcn_cmb_sdio_off (%d)\n", sdio_port_num); + + /* 1. call sd callback */ + if (mtk_wcn_cmb_sdio_pm_cb) { + /* pr_warn("mtk_wcn_cmb_sdio_off(PM_EVENT_USER_SUSPEND, 0x%p, 0x%p)\n", + * mtk_wcn_cmb_sdio_pm_cb, mtk_wcn_cmb_sdio_pm_data); + */ + mtk_wcn_cmb_sdio_pm_cb(state, mtk_wcn_cmb_sdio_pm_data); + } else + CMB_STUB_LOG_PR_WARN("mtk_wcn_cmb_sdio_off no sd callback!!\n"); + + /* 2. disable sdio eirq */ +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE + mtk_wcn_cmb_sdio_disable_eirq(); +#else + wmt_export_mtk_wcn_cmb_sdio_disable_eirq(); +#endif +} + +int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on) +{ + CMB_STUB_LOG_PR_DBG("mt_mtk_wcn_cmb_sdio_ctrl (%d, %d)\n", + sdio_port_num, on); + if (on) { +#if 1 + CMB_STUB_LOG_PR_DBG("board_sdio_ctrl force off before on\n"); + mtk_wcn_cmb_sdio_off(sdio_port_num); +#else + CMB_STUB_LOG_PR_WARN("skip sdio off before on\n"); +#endif + /* off -> on */ + mtk_wcn_cmb_sdio_on(sdio_port_num); + if (wifi_irq != 0xffffffff) + irq_set_irq_wake(wifi_irq, 1); + else + CMB_STUB_LOG_PR_WARN("wifi_irq is not available\n"); + } else { + if (wifi_irq != 0xffffffff) + irq_set_irq_wake(wifi_irq, 0); + else + CMB_STUB_LOG_PR_WARN("wifi_irq is not available\n"); + /* on -> off */ + mtk_wcn_cmb_sdio_off(sdio_port_num); + } + + return 0; +} +EXPORT_SYMBOL(board_sdio_ctrl); + +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE +int mtk_wcn_sdio_irq_flag_set(int flag) +{ + if (flag != 0) + atomic_set(&sdio_claim_irq_enable_flag, 1); + else + atomic_set(&sdio_claim_irq_enable_flag, 0); + + CMB_STUB_LOG_PR_DBG("sdio_claim_irq_enable_flag:%d\n", + atomic_read(&sdio_claim_irq_enable_flag)); + + return atomic_read(&sdio_claim_irq_enable_flag); +} +EXPORT_SYMBOL(mtk_wcn_sdio_irq_flag_set); +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c new file mode 100644 index 00000000000000..42dbafecd265d0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.c @@ -0,0 +1,249 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[SDIO-DETECT]" + +#include "wmt_detect.h" + +unsigned int gComboChipId = -1; +struct sdio_func *g_func; +unsigned int gDrvRegistered; + +MTK_WCN_HIF_SDIO_CHIP_INFO gChipInfoArray[] = { + /* MT6620 *//* Not an SDIO standard class device */ + {{SDIO_DEVICE(0x037A, 0x020A)}, 0x6620}, /* SDIO1:FUNC1:WIFI */ + {{SDIO_DEVICE(0x037A, 0x020B)}, 0x6620}, /* SDIO2:FUNC1:BT+FM+GPS */ + {{SDIO_DEVICE(0x037A, 0x020C)}, 0x6620}, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */ + + /* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */ + {{SDIO_DEVICE(0x037A, 0x6628)}, 0x6628}, + + /* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */ + {{SDIO_DEVICE(0x037A, 0x6630)}, 0x6630}, + + /* MT6632 *//* SDIO1: Wi-Fi */ + {{SDIO_DEVICE(0x037A, 0x6602)}, 0x6632}, + + /* MT6632 *//* SDIO2: BGF */ + {{SDIO_DEVICE(0x037A, 0x6632)}, 0x6632}, + +}; + +/* Supported SDIO device table */ +static const struct sdio_device_id mtk_sdio_id_tbl[] = { + /* MT6618 *//* Not an SDIO standard class device */ + {SDIO_DEVICE(0x037A, 0x018A)}, /* SDIO1:WIFI */ + {SDIO_DEVICE(0x037A, 0x018B)}, /* SDIO2:FUNC1:BT+FM */ + {SDIO_DEVICE(0x037A, 0x018C)}, /* 2-function (SDIO2:FUNC1:BT+FM, FUNC2:WIFI) */ + + /* MT6619 *//* Not an SDIO standard class device */ + {SDIO_DEVICE(0x037A, 0x6619)}, /* SDIO2:FUNC1:BT+FM+GPS */ + + /* MT6620 *//* Not an SDIO standard class device */ + {SDIO_DEVICE(0x037A, 0x020A)}, /* SDIO1:FUNC1:WIFI */ + {SDIO_DEVICE(0x037A, 0x020B)}, /* SDIO2:FUNC1:BT+FM+GPS */ + {SDIO_DEVICE(0x037A, 0x020C)}, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */ + + /* MT5921 *//* Not an SDIO standard class device */ + {SDIO_DEVICE(0x037A, 0x5921)}, + + /* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */ + {SDIO_DEVICE(0x037A, 0x6628)}, + + /* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */ + {SDIO_DEVICE(0x037A, 0x6630)}, + + /* MT6632 *//* SDIO1: Wi-Fi */ + {SDIO_DEVICE(0x037A, 0x6602)}, + + /* MT6632 *//* SDIO2: BGF */ + {SDIO_DEVICE(0x037A, 0x6632)}, + { /* end: all zeroes */ }, +}; + +static int sdio_detect_probe(struct sdio_func *func, const struct sdio_device_id *id); + +static void sdio_detect_remove(struct sdio_func *func); + +static struct sdio_driver mtk_sdio_client_drv = { + .name = "mtk_sdio_client", /* MTK SDIO Client Driver */ + .id_table = mtk_sdio_id_tbl, /* all supported struct sdio_device_id table */ + .probe = sdio_detect_probe, + .remove = sdio_detect_remove, +}; + +static int hif_sdio_match_chipid_by_dev_id(const struct sdio_device_id *id); + +int hif_sdio_is_chipid_valid(int chipId) +{ + int index = -1; + + int left = 0; + int middle = 0; + int right = ARRAY_SIZE(gChipInfoArray) - 1; + + if ((chipId < gChipInfoArray[left].chipId) || (chipId > gChipInfoArray[right].chipId)) + return index; + + middle = (left + right) / 2; + + while (left <= right) { + if (chipId > gChipInfoArray[middle].chipId) { + left = middle + 1; + } else if (chipId < gChipInfoArray[middle].chipId) { + right = middle - 1; + } else { + index = middle; + break; + } + middle = (left + right) / 2; + } + + if (index < 0) + WMT_DETECT_PR_ERR("no supported chipid found\n"); + else + WMT_DETECT_PR_INFO("index:%d, chipId:0x%x\n", index, gChipInfoArray[index].chipId); + + return index; +} + +int hif_sdio_match_chipid_by_dev_id(const struct sdio_device_id *id) +{ + int maxIndex = ARRAY_SIZE(gChipInfoArray); + int index = 0; + struct sdio_device_id *localId = NULL; + int chipId = -1; + + for (index = 0; index < maxIndex; index++) { + localId = &(gChipInfoArray[index].deviceId); + if ((localId->vendor == id->vendor) && (localId->device == id->device)) { + chipId = gChipInfoArray[index].chipId; + WMT_DETECT_PR_INFO + ("valid chipId found, index(%d), vendor id(0x%x), device id(0x%x), chip id(0x%x)\n", index, + localId->vendor, localId->device, chipId); + mtk_wcn_wmt_set_chipid(chipId); + gComboChipId = chipId; + break; + } + } + if (chipId < 0) { + WMT_DETECT_PR_ERR("No valid chipId found, vendor id(0x%x), device id(0x%x)\n", id->vendor, + id->device); + } + + return chipId; +} + +int sdio_detect_query_chipid(int waitFlag) +{ + unsigned int timeSlotMs = 200; + unsigned int maxTimeSlot = 30; + unsigned int counter = 0; + /* gComboChipId = 0x6628; */ + if (waitFlag == 0) + return gComboChipId; + if (hif_sdio_is_chipid_valid(gComboChipId) >= 0) + return gComboChipId; + + while (counter < maxTimeSlot) { + if (hif_sdio_is_chipid_valid(gComboChipId) >= 0) + break; + msleep(timeSlotMs); + counter++; + } + + return gComboChipId; +} + +int sdio_detect_do_autok(int chipId) +{ + int i_ret = 0; + + WMT_DETECT_PR_INFO("autok was move to sdio driver\n"); + return i_ret; +} + +/*! + * \brief hif_sdio probe function + * + * hif_sdio probe function called by mmc driver when any matched SDIO function + * is detected by it. + * + * \param func + * \param id + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +static int sdio_detect_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + int chipId = 0; + + WMT_DETECT_PR_INFO("vendor(0x%x) device(0x%x) num(0x%x)\n", func->vendor, func->device, func->num); + chipId = hif_sdio_match_chipid_by_dev_id(id); + + if ((chipId == 0x6630 || chipId == 0x6632) && (func->num == 1)) { + int ret = 0; + + g_func = func; + WMT_DETECT_PR_INFO("autok function detected, func:0x%p\n", g_func); + + sdio_claim_host(func); + ret = sdio_enable_func(func); + sdio_release_host(func); + if (ret) + WMT_DETECT_PR_ERR("sdio_enable_func failed!\n"); + } + + return 0; +} + +static void sdio_detect_remove(struct sdio_func *func) +{ + if (g_func == func) { + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + g_func = NULL; + } + WMT_DETECT_PR_INFO("do sdio remove\n"); +} + +int sdio_detect_init(void) +{ + int ret = 0; + /* register to mmc driver */ + if (gDrvRegistered == 0) { + ret = sdio_register_driver(&mtk_sdio_client_drv); + if (ret == 0) + gDrvRegistered = 1; + } + WMT_DETECT_PR_INFO("sdio_register_driver() ret=%d\n", ret); + return ret; +} + +int sdio_detect_exit(void) +{ + g_func = NULL; + /* unregister to mmc driver */ + if (gDrvRegistered == 1) { + sdio_unregister_driver(&mtk_sdio_client_drv); + gDrvRegistered = 0; + } + WMT_DETECT_PR_INFO("sdio_unregister_driver\n"); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h new file mode 100644 index 00000000000000..274261d6075d1c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/sdio_detect.h @@ -0,0 +1,36 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _SDIO_DETECT_H_ +#define _SDIO_DETECT_H_ + +#include <linux/mmc/card.h> +#include <linux/mmc/host.h> +#include <linux/mmc/sdio_func.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/module.h> + +typedef struct _MTK_WCN_HIF_SDIO_CHIP_INFO_ { + struct sdio_device_id deviceId; + unsigned int chipId; +} MTK_WCN_HIF_SDIO_CHIP_INFO, *P_MTK_WCN_HIF_SDIO_CHIP_INFO; + +extern int sdio_detect_exit(void); +extern int sdio_detect_init(void); +extern int sdio_detect_query_chipid(int waitFlag); +extern int hif_sdio_is_chipid_valid(int chipId); + +extern int sdio_detect_do_autok(int chipId); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c new file mode 100644 index 00000000000000..bccfea8f6e16ef --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.c @@ -0,0 +1,408 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <mtk_wcn_cmb_stub.h> +#include <linux/platform_device.h> + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-DETECT]" + +#include "wmt_detect.h" +#include "wmt_gpio.h" +#include "wmt_dev.h" + +#if (MTK_WCN_REMOVE_KO) +#include "conn_drv_init.h" +#endif +#ifdef CONFIG_COMPAT +#include <linux/compat.h> +#endif + +#define WMT_DETECT_MAJOR 154 +#define WMT_DETECT_DEV_NUM 1 +#define WMT_DETECT_DRVIER_NAME "mtk_wcn_detect" +#define WMT_DETECT_DEVICE_NAME "wmtdetect" + +struct class *pDetectClass; +struct device *pDetectDev; +static int gWmtDetectMajor = WMT_DETECT_MAJOR; +static struct cdev gWmtDetectCdev; +int gWmtDetectDbgLvl = WMT_DETECT_LOG_INFO; +static ENUM_WMT_CHIP_TYPE g_chip_type = WMT_CHIP_TYPE_INVALID; + +static int wmt_detect_open(struct inode *inode, struct file *file) +{ + WMT_DETECT_PR_INFO("open major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + + return 0; +} + +static int wmt_detect_close(struct inode *inode, struct file *file) +{ + WMT_DETECT_PR_INFO("close major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + + return 0; +} + +static ssize_t wmt_detect_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + WMT_DETECT_PR_INFO(" ++\n"); + WMT_DETECT_PR_INFO(" --\n"); + + return 0; +} + +ssize_t wmt_detect_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + WMT_DETECT_PR_INFO(" ++\n"); + WMT_DETECT_PR_INFO(" --\n"); + + return 0; +} +EXPORT_SYMBOL(wmt_detect_write); + +long wmt_detect_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + + WMT_DETECT_PR_INFO("cmd (%d),arg(%ld)\n", cmd, arg); + + switch (cmd) { + case COMBO_IOCTL_GET_CHIP_ID: + /*just get chipid from sdio-detect module */ + /*check if external combo chip exists or not */ + /*if yes, just return combo chip id */ + /*if no, get soc chipid */ + retval = mtk_wcn_wmt_chipid_query(); + break; + + case COMBO_IOCTL_SET_CHIP_ID: + WMT_DETECT_PR_INFO("chipid(%ld)\n", arg); + mtk_wcn_wmt_set_chipid(arg); + wmt_detect_set_chip_type(arg); + break; + + case COMBO_IOCTL_EXT_CHIP_PWR_ON: + retval = wmt_detect_ext_chip_pwr_on(); + break; + + case COMBO_IOCTL_EXT_CHIP_DETECT: + retval = wmt_detect_ext_chip_detect(); + break; + + case COMBO_IOCTL_EXT_CHIP_PWR_OFF: + retval = wmt_detect_ext_chip_pwr_off(); + break; + + case COMBO_IOCTL_DO_SDIO_AUDOK: + retval = sdio_detect_do_autok(arg); + break; + + case COMBO_IOCTL_GET_SOC_CHIP_ID: + retval = wmt_plat_get_soc_chipid(); + /*get soc chipid by HAL interface */ + break; + + case COMBO_IOCTL_MODULE_CLEANUP: + retval = sdio_detect_exit(); + break; + + case COMBO_IOCTL_DO_MODULE_INIT: +#if (MTK_WCN_REMOVE_KO) + /*deinit SDIO-DETECT module */ + WMT_DETECT_PR_INFO("built-in mode\n"); + retval = do_connectivity_driver_init(arg); +#else + WMT_DETECT_PR_INFO("kernel object mode\n"); + retval = mtk_wcn_common_drv_init(); +#endif + break; + + default: + WMT_DETECT_PR_WARN("unknown cmd (%d)\n", cmd); + retval = 0; + break; + } + return retval; +} +EXPORT_SYMBOL(wmt_detect_unlocked_ioctl); + +#ifdef CONFIG_COMPAT +long WMT_compat_detect_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret; + + WMT_DETECT_PR_INFO("cmd (%d)\n", cmd); + ret = wmt_detect_unlocked_ioctl(filp, cmd, arg); + return ret; +} +EXPORT_SYMBOL(WMT_compat_detect_ioctl); +#endif + +const struct file_operations gWmtDetectFops = { + .open = wmt_detect_open, + .release = wmt_detect_close, + .read = wmt_detect_read, + .write = wmt_detect_write, + .unlocked_ioctl = wmt_detect_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = WMT_compat_detect_ioctl, +#endif +}; + +int wmt_detect_ext_chip_pwr_on(void) +{ + /*pre power on external chip */ + /* wmt_plat_pwr_ctrl(FUNC_ON); */ +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT + WMT_DETECT_PR_INFO("++\n"); + if (wmt_detect_chip_pwr_ctrl(1) != 0) + return -2; + if (wmt_detect_sdio_pwr_ctrl(1) != 0) + return -3; + return 0; +#else + WMT_DETECT_PR_INFO("combo chip is not supported\n"); + return -1; +#endif +} + +int wmt_detect_ext_chip_pwr_off(void) +{ + /*pre power off external chip */ + /* wmt_plat_pwr_ctrl(FUNC_OFF); */ +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT + WMT_DETECT_PR_INFO("--\n"); + wmt_detect_sdio_pwr_ctrl(0); + return wmt_detect_chip_pwr_ctrl(0); +#else + WMT_DETECT_PR_INFO("combo chip is not supported\n"); + return 0; +#endif +} + +int wmt_detect_ext_chip_detect(void) +{ + int iRet = -1; +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT + unsigned int chipId = -1; + /*if there is no external combo chip, return -1 */ + int bgfEintStatus = -1; + + WMT_DETECT_PR_INFO("++\n"); + /*wait for a stable time */ + msleep(20); + + /*read BGF_EINT_PIN status */ + bgfEintStatus = wmt_detect_read_ext_cmb_status(); + + if (bgfEintStatus == 0) { + /*external chip does not exist */ + WMT_DETECT_PR_INFO("external combo chip not detected\n"); + iRet = -2; + } else if (bgfEintStatus == 1) { + /*combo chip exists */ + WMT_DETECT_PR_INFO("external combo chip detected\n"); + + /*detect chipid by sdio_detect module */ + chipId = sdio_detect_query_chipid(1); + if (hif_sdio_is_chipid_valid(chipId) >= 0) + WMT_DETECT_PR_INFO("valid external combo chip id (0x%x)\n", chipId); + else + WMT_DETECT_PR_INFO("invalid external combo chip id (0x%x)\n", chipId); + iRet = 0; + } else { + /*Error exists */ + WMT_DETECT_PR_ERR("error happens when detecting combo chip\n"); + iRet = -3; + } + WMT_DETECT_PR_INFO("--\n"); + /*return 0 */ +#endif + return iRet; + /*todo: if there is external combo chip, power on chip return 0 */ +} + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT +static int wmt_detect_probe(struct platform_device *pdev) +{ + int ret = 0; + + WMT_DETECT_PR_INFO("platform name: %s\n", pdev->name); + ret = wmt_gpio_init(pdev); + if (-1 == ret) + WMT_DETECT_PR_ERR("gpio init fail ret:%d\n", ret); + return ret; +} + +static int wmt_detect_remove(struct platform_device *pdev) +{ + wmt_gpio_deinit(); + return 0; +} +#endif + +int wmt_detect_set_chip_type(int chip_id) +{ + switch (chip_id) { + case 0x6620: + case 0x6628: + case 0x6630: + case 0x6632: + g_chip_type = WMT_CHIP_TYPE_COMBO; + break; + case -1: + break; + default: + g_chip_type = WMT_CHIP_TYPE_SOC; + break; + } + return 0; +} +ENUM_WMT_CHIP_TYPE wmt_detect_get_chip_type(void) +{ + return g_chip_type; +} + + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT +static const struct of_device_id wmt_detect_match[] = { + { .compatible = "mediatek,connectivity-combo", }, + {} +}; +MODULE_DEVICE_TABLE(of, wmt_detect_match); + +static struct platform_driver wmt_detect_driver = { + .probe = wmt_detect_probe, + .remove = wmt_detect_remove, + .driver = { + .owner = THIS_MODULE, + .name = "mediatek,connectivity-combo", + .of_match_table = wmt_detect_match, + }, +}; +#endif + +/*module_platform_driver(wmt_detect_driver);*/ +static int wmt_detect_driver_init(void) +{ + dev_t devID = MKDEV(gWmtDetectMajor, 0); + int cdevErr = -1; + int ret = -1; + + /*init SDIO-DETECT module */ + sdio_detect_init(); + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT + ret = platform_driver_register(&wmt_detect_driver); + if (ret) + WMT_DETECT_PR_ERR("platform driver register fail ret:%d\n", ret); +#endif + + ret = register_chrdev_region(devID, WMT_DETECT_DEV_NUM, WMT_DETECT_DRVIER_NAME); + if (ret) { + WMT_DETECT_PR_ERR("fail to register chrdev\n"); + goto err0; + } + + cdev_init(&gWmtDetectCdev, &gWmtDetectFops); + gWmtDetectCdev.owner = THIS_MODULE; + + cdevErr = cdev_add(&gWmtDetectCdev, devID, WMT_DETECT_DEV_NUM); + if (cdevErr) { + WMT_DETECT_PR_ERR("cdev_add() fails (%d)\n", cdevErr); + goto err1; + } + + pDetectClass = class_create(/*THIS_MODULE,*/ WMT_DETECT_DEVICE_NAME); + if (IS_ERR(pDetectClass)) { + WMT_DETECT_PR_ERR("class create fail, error code(%ld)\n", PTR_ERR(pDetectClass)); + goto err1; + } + + pDetectDev = device_create(pDetectClass, NULL, devID, NULL, WMT_DETECT_DEVICE_NAME); + if (IS_ERR(pDetectDev)) { + WMT_DETECT_PR_ERR("device create fail, error code(%ld)\n", PTR_ERR(pDetectDev)); + goto err2; + } + + WMT_DETECT_PR_INFO("driver(major %d) installed success\n", gWmtDetectMajor); + + return 0; + +err2: + + if (pDetectClass) { + class_destroy(pDetectClass); + pDetectClass = NULL; + } + +err1: + + if (cdevErr == 0) + cdev_del(&gWmtDetectCdev); + + if (ret == 0) { + unregister_chrdev_region(devID, WMT_DETECT_DEV_NUM); + gWmtDetectMajor = -1; + } + +err0: + sdio_detect_exit(); + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT + platform_driver_unregister(&wmt_detect_driver); +#endif + + return ret ? ret : -1; +} + +static void wmt_detect_driver_exit(void) +{ + dev_t dev = MKDEV(gWmtDetectMajor, 0); + + mtk_wcn_common_drv_exit(); + + if (pDetectDev) { + device_destroy(pDetectClass, dev); + pDetectDev = NULL; + } + + if (pDetectClass) { + class_destroy(pDetectClass); + pDetectClass = NULL; + } + + cdev_del(&gWmtDetectCdev); + unregister_chrdev_region(dev, WMT_DETECT_DEV_NUM); + + sdio_detect_exit(); + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT + if (wmt_detect_driver.driver.p) + platform_driver_unregister(&wmt_detect_driver); +#endif + + WMT_DETECT_PR_INFO("done\n"); +} + +module_init(wmt_detect_driver_init); +module_exit(wmt_detect_driver_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Zhiguo.Niu & Chaozhong.Liang @ MBJ/WCNSE/SS1"); + +module_param(gWmtDetectMajor, uint, 0); diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h new file mode 100644 index 00000000000000..75fd03821afa90 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect.h @@ -0,0 +1,123 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _WMT_DETECT_H_ +#define _WMT_DETECT_H_ + +#include <linux/version.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/sched.h> +#include <linux/poll.h> +#include <asm/current.h> +#include <linux/uaccess.h> +#include <linux/proc_fs.h> +#include <linux/wait.h> +#include <linux/time.h> +#include <linux/delay.h> +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE +#define MTK_WCN_REMOVE_KO 1 +#else +#define MTK_WCN_REMOVE_KO 0 +#endif + +#include "sdio_detect.h" +#include "wmt_detect_pwr.h" +#include <mtk_wcn_cmb_stub.h> + +#define WMT_DETECT_LOG_LOUD 4 +#define WMT_DETECT_LOG_DBG 3 +#define WMT_DETECT_LOG_INFO 2 +#define WMT_DETECT_LOG_WARN 1 +#define WMT_DETECT_LOG_ERR 0 + +extern int gWmtDetectDbgLvl; + +#define WMT_DETECT_PR_LOUD(fmt, arg...) \ +do { \ + if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_LOUD) \ + pr_info(DFT_TAG"[L]%s:" fmt, __func__, ##arg); \ +} while (0) +#define WMT_DETECT_PR_DBG(fmt, arg...) \ +do { \ + if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_DBG) \ + pr_info(DFT_TAG"[D]%s:" fmt, __func__, ##arg); \ +} while (0) +#define WMT_DETECT_PR_INFO(fmt, arg...) \ +do { \ + if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_INFO) \ + pr_info(DFT_TAG"[I]%s:" fmt, __func__, ##arg); \ +} while (0) +#define WMT_DETECT_PR_WARN(fmt, arg...) \ +do { \ + if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_WARN) \ + pr_warn(DFT_TAG"[W]%s(%d):" fmt, __func__, __LINE__, ##arg); \ +} while (0) +#define WMT_DETECT_PR_ERR(fmt, arg...) \ +do { \ + if (gWmtDetectDbgLvl >= WMT_DETECT_LOG_ERR) \ + pr_err(DFT_TAG"[E]%s(%d):" fmt, __func__, __LINE__, ##arg); \ +} while (0) + +#define WMT_DETECT_IOC_MAGIC 'w' +#define COMBO_IOCTL_GET_CHIP_ID _IOR(WMT_DETECT_IOC_MAGIC, 0, int) +#define COMBO_IOCTL_SET_CHIP_ID _IOW(WMT_DETECT_IOC_MAGIC, 1, int) +#define COMBO_IOCTL_EXT_CHIP_DETECT _IOR(WMT_DETECT_IOC_MAGIC, 2, int) +#define COMBO_IOCTL_GET_SOC_CHIP_ID _IOR(WMT_DETECT_IOC_MAGIC, 3, int) +#define COMBO_IOCTL_DO_MODULE_INIT _IOR(WMT_DETECT_IOC_MAGIC, 4, int) +#define COMBO_IOCTL_MODULE_CLEANUP _IOR(WMT_DETECT_IOC_MAGIC, 5, int) +#define COMBO_IOCTL_EXT_CHIP_PWR_ON _IOR(WMT_DETECT_IOC_MAGIC, 6, int) +#define COMBO_IOCTL_EXT_CHIP_PWR_OFF _IOR(WMT_DETECT_IOC_MAGIC, 7, int) +#define COMBO_IOCTL_DO_SDIO_AUDOK _IOR(WMT_DETECT_IOC_MAGIC, 8, int) + +typedef enum _ENUM_WMT_CHIP_TYPE_T { + WMT_CHIP_TYPE_COMBO, + WMT_CHIP_TYPE_SOC, + WMT_CHIP_TYPE_INVALID +} ENUM_WMT_CHIP_TYPE; +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +********************************************************************************/ +extern int wmt_detect_ext_chip_detect(void); +extern int wmt_detect_ext_chip_pwr_on(void); +extern int wmt_detect_ext_chip_pwr_off(void); + +extern unsigned int wmt_plat_get_soc_chipid(void); + +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT +/* mtk_uart_pdn_enable -- request uart port enter/exit deep idle mode, this API is defined in uart driver + * + * @ port - uart port name, Eg: "ttyMT0", "ttyMT1", "ttyMT2" + * @ enable - "1", enable deep idle; "0", disable deep idle + * + * Return 0 if success, else -1 + */ +extern unsigned int mtk_uart_pdn_enable(char *port, int enable); +#endif +#ifdef CONFIG_COMPAT +extern long WMT_compat_detect_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#endif +extern int wmt_detect_set_chip_type(int chip_id); +extern ENUM_WMT_CHIP_TYPE wmt_detect_get_chip_type(void); +extern long wmt_detect_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +extern ssize_t wmt_detect_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c new file mode 100644 index 00000000000000..4c6dd60e935af3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.c @@ -0,0 +1,256 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +/* ALPS header files */ +#ifndef CONFIG_RTC_DRV_MT6397 +#include <mtk_rtc.h> +#else +#include <linux/mfd/mt6397/rtc_misc.h> +#endif + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-DETECT]" + +#include "wmt_detect.h" +#include "wmt_gpio.h" + +#define INVALID_PIN_ID (0xFFFFFFFF) + +/*copied form WMT module*/ +static int wmt_detect_dump_pin_conf(void) +{ + WMT_DETECT_PR_DBG("[WMT-DETECT]=>dump wmt pin configuration start<=\n"); + + WMT_DETECT_PR_INFO("LDO(GPIO%d), PMU(GPIO%d), PMUV28(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num); + + WMT_DETECT_PR_INFO("RST(GPIO%d), BGF_EINT(GPIO%d), BGF_EINT_NUM(%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num, + gpio_to_irq(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num)); + + WMT_DETECT_PR_INFO("WIFI_EINT(GPIO%d), WIFI_EINT_NUM(%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num, + gpio_to_irq(gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num)); + + WMT_DETECT_PR_DBG("[WMT-PLAT]=>dump wmt pin configuration ends<=\n"); + + return 0; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +int _wmt_detect_output_low(unsigned int id) +{ + if (gpio_ctrl_info.gpio_ctrl_state[id].gpio_num != INVALID_PIN_ID) { + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, 0); + WMT_DETECT_PR_INFO("WMT-DETECT: set GPIO%d to output %d\n", + gpio_ctrl_info.gpio_ctrl_state[id].gpio_num-280, + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num)); + } + + return 0; +} + +int _wmt_detect_output_high(unsigned int id) +{ + if (gpio_ctrl_info.gpio_ctrl_state[id].gpio_num != INVALID_PIN_ID) { + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, 1); + WMT_DETECT_PR_INFO("WMT-DETECT: set GPIO%d to output %d\n", + gpio_ctrl_info.gpio_ctrl_state[id].gpio_num-280, + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num)); + } + + return 0; +} + +int _wmt_detect_read_gpio_input(unsigned int id) +{ + int retval = 0; + + if (gpio_ctrl_info.gpio_ctrl_state[id].gpio_num != INVALID_PIN_ID) { + retval = gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[id].gpio_num); + WMT_DETECT_PR_DBG("WMT-DETECT: get GPIO%d val%d\n", + gpio_ctrl_info.gpio_ctrl_state[id].gpio_num, retval); + } else + WMT_DETECT_PR_ERR("WMT-DETECT: GPIO%d invalid\n", + gpio_ctrl_info.gpio_ctrl_state[id].gpio_num); + + return retval; +} +#pragma GCC diagnostic pop + +/*This power on sequence must support all combo chip's basic power on sequence + * 1. LDO control is a must, if external LDO exist + * 2. PMU control is a must + * 3. RST control is a must + * 4. WIFI_EINT pin control is a must, used for GPIO mode for EINT status checkup + * 5. RTC32k clock control is a must + * + */ +static int wmt_detect_chip_pwr_on(void) +{ + int retval = -1; + + /*setting validiation check*/ + if ((gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num == INVALID_PIN_ID) || + (gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num == INVALID_PIN_ID)) { + WMT_DETECT_PR_ERR("WMT-DETECT: either PMU(%d) or WIFI_EINT(%d) is not set\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, + gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num); + + return retval; + } + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num == INVALID_PIN_ID) { + WMT_DETECT_PR_WARN("WMT-DETECT: RST(%d) is not set, if it`s not 6632 project, please check it\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num); + + } + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN]. + gpio_state[GPIO_PULL_DIS]); + } else + pr_err("wmt_gpio:set GPIO_COMBO_URXD_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + WMT_DETECT_PR_DBG("WMT-DETECT: GPIO_COMBO_URXD_PIN out 0\n"); + _wmt_detect_output_low(GPIO_COMBO_URXD_PIN); + + /*set LDO/PMU/RST to output 0, no pull*/ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num != INVALID_PIN_ID) + _wmt_detect_output_low(GPIO_COMBO_LDO_EN_PIN); + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]); + WMT_DETECT_PR_INFO("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS done!\n"); + } else + WMT_DETECT_PR_ERR("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + _wmt_detect_output_low(GPIO_COMBO_PMU_EN_PIN); + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]); + WMT_DETECT_PR_INFO("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS done!\n"); + } else + WMT_DETECT_PR_ERR("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + _wmt_detect_output_low(GPIO_COMBO_RST_PIN); + +#if 0 + _wmt_detect_output_high(GPIO_WIFI_EINT_PIN); +#endif + + /*pull high LDO*/ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num != INVALID_PIN_ID) + _wmt_detect_output_high(GPIO_COMBO_LDO_EN_PIN); + /*sleep for LDO stable time*/ + msleep(MAX_LDO_STABLE_TIME); + + /*export RTC clock, sleep for RTC stable time*/ + rtc_gpio_enable_32k(RTC_GPIO_USER_GPS); + msleep(MAX_RTC_STABLE_TIME); + /*PMU output low, RST output low, to make chip power off completely*/ + /*always done*/ + /*sleep for power off stable time*/ + msleep(MAX_OFF_STABLE_TIME); + /*PMU output high, and sleep for reset stable time*/ + _wmt_detect_output_high(GPIO_COMBO_PMU_EN_PIN); +#ifdef CONFIG_MTK_COMBO_COMM_NPWR + if ((gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_DAT_PIN].gpio_num != INVALID_PIN_ID) && + (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_num != INVALID_PIN_ID)) { + msleep(20); + _wmt_detect_output_high(GPIO_PCM_DAISYNC_PIN); + + msleep(20); + _wmt_detect_output_high(GPIO_COMBO_I2S_DAT_PIN); + + msleep(20); + _wmt_detect_output_low(GPIO_COMBO_I2S_DAT_PIN); + + msleep(20); + _wmt_detect_output_low(GPIO_PCM_DAISYNC_PIN); + + msleep(20); + } +#endif + msleep(MAX_RST_STABLE_TIME); + /*RST output high, and sleep for power on stable time */ + _wmt_detect_output_high(GPIO_COMBO_RST_PIN); + msleep(MAX_ON_STABLE_TIME); + retval = 0; + return retval; +} + +static int wmt_detect_chip_pwr_off(void) +{ + + /*set RST pin to input low status*/ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num != INVALID_PIN_ID) + _wmt_detect_output_low(GPIO_COMBO_LDO_EN_PIN); + /*set RST pin to input low status*/ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num != INVALID_PIN_ID) + _wmt_detect_output_low(GPIO_COMBO_RST_PIN); + /*set PMU pin to input low status*/ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num != INVALID_PIN_ID) + _wmt_detect_output_low(GPIO_COMBO_PMU_EN_PIN); + return 0; +} + +int wmt_detect_read_ext_cmb_status(void) +{ + int retval = 0; + /*read WIFI_EINT pin status*/ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num == INVALID_PIN_ID) { + retval = 0; + WMT_DETECT_PR_ERR("WMT-DETECT: no WIFI_EINT pin set\n"); + } else { + retval = _wmt_detect_read_gpio_input(GPIO_WIFI_EINT_PIN); + WMT_DETECT_PR_INFO("WMT-DETECT: WIFI_EINT input status:%d\n", retval); + } + return retval; +} + +int wmt_detect_chip_pwr_ctrl(int on) +{ + int retval = -1; + + if (on == 0) { + /*power off combo chip */ + retval = wmt_detect_chip_pwr_off(); + } else { + wmt_detect_dump_pin_conf(); + /*power on combo chip */ + retval = wmt_detect_chip_pwr_on(); + } + return retval; +} + +int wmt_detect_sdio_pwr_ctrl(int on) +{ + int retval = -1; +#ifdef MTK_WCN_COMBO_CHIP_SUPPORT + if (on == 0) { + /*power off SDIO slot */ + retval = board_sdio_ctrl(1, 0); + } else { + /*power on SDIO slot */ + retval = board_sdio_ctrl(1, 1); + } +#else + WMT_DETECT_PR_WARN("WMT-DETECT: MTK_WCN_COMBO_CHIP_SUPPORT is not set\n"); +#endif + return retval; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h new file mode 100644 index 00000000000000..32e661520fd0d0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_detect_pwr.h @@ -0,0 +1,29 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __WMT_DETECT_PWR_H_ +#define __WMT_DETECT_PWR_H_ + +#define MAX_RTC_STABLE_TIME 100 +#define MAX_LDO_STABLE_TIME 100 +#define MAX_RST_STABLE_TIME 30 +#define MAX_OFF_STABLE_TIME 10 +#define MAX_ON_STABLE_TIME 30 + +extern int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on); +extern int wmt_detect_chip_pwr_ctrl(int on); +extern int wmt_detect_sdio_pwr_ctrl(int on); +extern int wmt_detect_read_ext_cmb_status(void); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c new file mode 100644 index 00000000000000..55a483895f8faa --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.c @@ -0,0 +1,496 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "wmt_gpio.h" +#if (LINUX_VERSION_CODE >> 8) == 0x40E +#include <wmt_build_in_adapter.h> +#endif + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +const PUINT8 gpio_state_name[GPIO_PIN_ID_MAX][GPIO_STATE_MAX] = {{"gpio_ldo_en_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "gpio_ldo_en_in_pulldown", + ""}, + {"gpio_pmuv28_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "gpio_pmuv28_in_pulldown", + ""}, + {"gpio_pmu_en_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "gpio_pmu_en_in_pulldown", + ""}, + {"gpio_rst_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "gpio_rst_in_pulldown", + ""}, + {"", + "", + "", + "", + "", + "", + "", + "gpio_bgf_eint_in_pull_dis", + "gpio_bgf_eint_in_pulldown", + "gpio_bgf_eint_in_pullup"}, + {"", + "", + "", + "", + "", + "", + "", + "gpio_wifi_eint_in_pull_dis", + "", + "gpio_wifi_eint_in_pullup"}, + {"", + "", + "", + "", + "", + "", + "", + "", + "gpio_all_eint_in_pulldown", + "gpio_all_eint_in_pullup"}, + {"gpio_urxd_uart_pull_dis", + "", + "", + "gpio_urxd_uart_out_low", + "", + "", + "", + "gpio_urxd_gpio_in_pull_dis", + "", + "gpio_urxd_gpio_in_pullup"}, + {"gpio_utxd_uart_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_pcm_daiclk_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_pcm_daipcmin_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_pcm_daipcmout_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_pcm_daisync_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_i2s_ck_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_i2s_ws_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_i2s_dat_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_gps_sync_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"gpio_gps_lna_pull_dis", + "", + "", + "", + "", + "", + "", + "", + "", + ""}, + {"", + "", + "", + "", + "", + "gpio_chip_deep_sleep_in_pull_dis", + "", + "", + "", + ""}, + {"", + "", + "gpio_chip_wake_up_pullup", + "", + "", + "", + "", + "", + "", + ""} +}; + +const PUINT8 gpio_pin_name[GPIO_PIN_ID_MAX] = {"gpio_combo_ldo_en_pin", + "gpio_combo_pmuv28_en_pin", + "gpio_combo_pmu_en_pin", + "gpio_combo_rst_pin", + "gpio_combo_bgf_eint_pin", + "gpio_wifi_eint_pin", + "gpio_all_eint_pin", + "gpio_combo_urxd_pin", + "gpio_combo_utxd_pin", + "gpio_pcm_daiclk_pin", + "gpio_pcm_daipcmin_pin", + "gpio_pcm_daipcmout_pin", + "gpio_pcm_daisync_pin", + "gpio_combo_i2s_ck_pin", + "gpio_combo_i2s_ws_pin", + "gpio_combo_i2s_dat_pin", + "gpio_gps_sync_pin", + "gpio_gps_lna_pin", + "gpio_chip_deep_sleep_pin", + "gpio_chip_wake_up_pin" + }; + +GPIO_CTRL_INFO gpio_ctrl_info; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +int __weak mt_get_gpio_mode_base(unsigned long pin) +{ + return 0; +} + +int __weak mt_get_gpio_pull_select_base(unsigned long pin) +{ + return 0; +} + +int __weak mt_get_gpio_in_base(unsigned long pin) +{ + return 0; +} + +int __weak mt_get_gpio_out_base(unsigned long pin) +{ + return 0; +} + +int __weak mt_get_gpio_pull_enable_base(unsigned long pin) +{ + return 0; +} + +int __weak mt_get_gpio_dir_base(unsigned long pin) +{ + return 0; +} + +int __weak mt_get_gpio_ies_base(unsigned long pin) +{ + return 0; +} + +INT32 wmt_gpio_init(struct platform_device *pdev) +{ + INT32 iret = 0; + UINT32 i, j; + struct device_node *node; + + node = of_find_compatible_node(NULL, NULL, "mediatek,connectivity-combo"); + if (!node) { + for (i = 0; i < GPIO_PIN_ID_MAX; i++) + gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID; + pr_err("wmt_gpio:can't find device tree node!\n"); + iret = -1; + goto err; + } + + gpio_ctrl_info.pinctrl_info = devm_pinctrl_get(&pdev->dev); + if (gpio_ctrl_info.pinctrl_info) { + for (i = 0; i < GPIO_PIN_ID_MAX; i++) { + gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = of_get_named_gpio(node, + gpio_pin_name[i], 0); + if (gpio_ctrl_info.gpio_ctrl_state[i].gpio_num < 0) + gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID; + if (gpio_ctrl_info.gpio_ctrl_state[i].gpio_num != DEFAULT_PIN_ID) { + for (j = 0; j < GPIO_STATE_MAX; j++) { + if (strlen(gpio_state_name[i][j]) != 0) { + gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = + pinctrl_lookup_state(gpio_ctrl_info.pinctrl_info, + gpio_state_name[i][j]); + } else + gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = NULL; + } + } else { + for (j = 0; j < GPIO_STATE_MAX; j++) + gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = NULL; + } + } + + pr_info("wmt_gpio: gpio init start!\n"); + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN]. + gpio_state[GPIO_PULL_DIS]); + } else + pr_err("wmt_gpio:set GPIO_COMBO_URXD_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_UTXD_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_UTXD_PIN]. + gpio_state[GPIO_PULL_DIS]); + } else + pr_err("wmt_gpio:set GPIO_COMBO_UTXD_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN]. + gpio_state[GPIO_PULL_DIS]); + } else + pr_err("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num != DEFAULT_PIN_ID) { + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, + 0); + pr_err("wmt_gpio:set GPIO_COMBO_PMU_EN_PIN out to 0: %d!\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num)); + } + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]); + } else + pr_err("wmt_gpio:set GPIO_COMBO_RST_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num != DEFAULT_PIN_ID) { + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, + 0); + pr_err("wmt_gpio:set GPIO_COMBO_RST_PIN out to 0: %d!\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num)); + } + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_state[GPIO_IN_PULLUP]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_state[GPIO_IN_PULLUP]); + } else + pr_err("wmt_gpio:set GPIO_WIFI_EINT_PIN to GPIO_IN_PULLUP fail, is NULL!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]); + } else + pr_err("wmt_gpio:set GPIO_PCM_DAICLK_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN]. + gpio_state[GPIO_PULL_DIS]); + } else + pr_err("wmt_gpio:set GPIO_PCM_DAIPCMIN_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN]. + gpio_state[GPIO_PULL_DIS]); + } else + pr_err("wmt_gpio:set GPIO_PCM_DAIPCMOUT_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_state[GPIO_PULL_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN]. + gpio_state[GPIO_PULL_DIS]); + } else + pr_err("wmt_gpio:set GPIO_PCM_DAISYNC_PIN to GPIO_PULL_DIS fail, is NULL!\n"); + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_DEEP_SLEEP_PIN].gpio_state[GPIO_IN_DIS]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_DEEP_SLEEP_PIN]. + gpio_state[GPIO_IN_DIS]); + } else + pr_warn("wmt_gpio:it may not be 6632 project, GPIO_CHIP_DEEP_SLEEP_PIN no need config!\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_state[GPIO_PULL_UP]) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN]. + gpio_state[GPIO_PULL_UP]); + } else + pr_warn("wmt_gpio:it may not be 6632 project, GPIO_CHIP_WAKE_UP_PIN no need config!\n"); + + pr_info("wmt_gpio: gpio init done!\n"); + } else { + pr_err("wmt_gpio:can't find pinctrl dev!\n"); + iret = -1; + } + +#if (LINUX_VERSION_CODE >> 8) == 0x40E + KERNEL_mtk_wcn_cmb_sdio_request_eirq(); +#endif +err: + return iret; +} + +INT32 wmt_gpio_deinit(VOID) +{ + INT32 iret = 0; + UINT32 i; + UINT32 j; + + for (i = 0; i < GPIO_PIN_ID_MAX; i++) { + gpio_ctrl_info.gpio_ctrl_state[i].gpio_num = DEFAULT_PIN_ID; + if (gpio_ctrl_info.gpio_ctrl_state[i].gpio_num != DEFAULT_PIN_ID) { + for (j = 0; j < GPIO_STATE_MAX; j++) { + if (strlen(gpio_state_name[i][j]) != 0) + gpio_ctrl_info.gpio_ctrl_state[i].gpio_state[j] = NULL; + } + } + } + if (gpio_ctrl_info.pinctrl_info) { + devm_pinctrl_put(gpio_ctrl_info.pinctrl_info); + gpio_ctrl_info.pinctrl_info = NULL; + } + + return iret; +} + +VOID _wmt_dump_gpio_regs(INT32 idx) +{ + ULONG idxl = (ULONG)idx; + + pr_info("PIN: [MODE] [PULL_SEL] [DIN] [DOUT] [PULL EN] [DIR] [IES]\n"); + pr_info("idx = %3d: %d %d %d %d %d %d %d\n", + idx, mt_get_gpio_mode_base(idxl), + mt_get_gpio_pull_select_base(idxl), + mt_get_gpio_in_base(idxl), + mt_get_gpio_out_base(idxl), + mt_get_gpio_pull_enable_base(idxl), + mt_get_gpio_dir_base(idxl), + mt_get_gpio_ies_base(idxl)); +} + +VOID _wmt_gpio_pre_regs(INT32 num, WMT_GPIO_STATE_INFO *gpio_state) +{ + gpio_state->gpio_num = num; + gpio_state->mode = mt_get_gpio_mode_base(num); + gpio_state->pull_sel = mt_get_gpio_pull_select_base(num); + gpio_state->in = mt_get_gpio_in_base(num); + gpio_state->out = mt_get_gpio_out_base(num); + gpio_state->pull_en = mt_get_gpio_pull_enable_base(num); + gpio_state->dir = mt_get_gpio_dir_base(num); + gpio_state->ies = mt_get_gpio_ies_base(num); + +} + +VOID _wmt_dump_gpio_pre_regs(WMT_GPIO_STATE_INFO gpio_state) +{ + pr_info("PIN: [MODE] [PULL_SEL] [DIN] [DOUT] [PULL EN] [DIR] [IES]\n"); + pr_info("idx = %3d: %d %d %d %d %d %d %d\n", + gpio_state.gpio_num, gpio_state.mode, + gpio_state.pull_sel, gpio_state.in, + gpio_state.out, gpio_state.pull_en, + gpio_state.dir, gpio_state.ies); +} diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h new file mode 100644 index 00000000000000..4d906f25fab379 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_gpio.h @@ -0,0 +1,127 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _WMT_GPIO_H_ +#define _WMT_GPIO_H_ + +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include "osal.h" +#include "osal_typedef.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define DEFAULT_PIN_ID (0xffffffff) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_GPIO_PIN_ID { + GPIO_COMBO_LDO_EN_PIN = 0, + GPIO_COMBO_PMUV28_EN_PIN, + GPIO_COMBO_PMU_EN_PIN, + GPIO_COMBO_RST_PIN, + GPIO_COMBO_BGF_EINT_PIN, + GPIO_WIFI_EINT_PIN, + GPIO_COMBO_ALL_EINT_PIN, + GPIO_COMBO_URXD_PIN, + GPIO_COMBO_UTXD_PIN, + GPIO_PCM_DAICLK_PIN, + GPIO_PCM_DAIPCMIN_PIN, + GPIO_PCM_DAIPCMOUT_PIN, + GPIO_PCM_DAISYNC_PIN, + GPIO_COMBO_I2S_CK_PIN, + GPIO_COMBO_I2S_WS_PIN, + GPIO_COMBO_I2S_DAT_PIN, + GPIO_GPS_SYNC_PIN, + GPIO_GPS_LNA_PIN, + GPIO_CHIP_DEEP_SLEEP_PIN, + GPIO_CHIP_WAKE_UP_PIN, + GPIO_PIN_ID_MAX +} ENUM_GPIO_PIN_ID, *P_ENUM_GPIO_PIN_ID; + +typedef enum _ENUM_GPIO_STATE_ID { + GPIO_PULL_DIS = 0, + GPIO_PULL_DOWN, + GPIO_PULL_UP, + GPIO_OUT_LOW, + GPIO_OUT_HIGH, + GPIO_IN_DIS, + GPIO_IN_EN, + GPIO_IN_PULL_DIS, + GPIO_IN_PULLDOWN, + GPIO_IN_PULLUP, + GPIO_STATE_MAX, +} ENUM_GPIO_STATE_ID, *P_ENUM_GPIO_STATE_ID; + +typedef struct _GPIO_CTRL_STATE { + INT32 gpio_num; + struct pinctrl_state *gpio_state[GPIO_STATE_MAX]; +} GPIO_CTRL_STATE, *P_GPIO_CTRL_STATE; + +typedef struct _WMT_GPIO_STATE_INFO { + INT32 gpio_num; + INT32 mode; + INT32 pull_sel; + INT32 in; + INT32 out; + INT32 pull_en; + INT32 dir; + INT32 ies; +} WMT_GPIO_STATE_INFO; + +typedef struct _GPIO_CTRL_INFO { + struct pinctrl *pinctrl_info; + GPIO_CTRL_STATE gpio_ctrl_state[GPIO_PIN_ID_MAX]; +} GPIO_CTRL_INFO, *P_GPIO_CTRL_INFO; + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +extern const PUINT8 gpio_state_name[GPIO_PIN_ID_MAX][GPIO_STATE_MAX]; +extern const PUINT8 gpio_pin_name[GPIO_PIN_ID_MAX]; +extern GPIO_CTRL_INFO gpio_ctrl_info; + +extern int mt_get_gpio_mode_base(unsigned long pin); +extern int mt_get_gpio_pull_select_base(unsigned long pin); +extern int mt_get_gpio_in_base(unsigned long pin); +extern int mt_get_gpio_out_base(unsigned long pin); +extern int mt_get_gpio_pull_enable_base(unsigned long pin); +extern int mt_get_gpio_dir_base(unsigned long pin); +extern int mt_get_gpio_ies_base(unsigned long pin); + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +INT32 wmt_gpio_init(struct platform_device *pdev); +VOID _wmt_dump_gpio_regs(INT32 idx); +VOID _wmt_gpio_pre_regs(INT32 num, WMT_GPIO_STATE_INFO *gpio_state); +VOID _wmt_dump_gpio_pre_regs(WMT_GPIO_STATE_INFO gpio_state); +INT32 wmt_gpio_deinit(VOID); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c new file mode 100644 index 00000000000000..211898a9c6562c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.c @@ -0,0 +1,553 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ +#include "osal_typedef.h" +#include "wmt_stp_exp.h" + + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-STP-EXP]" + +#define WMT_STP_EXP_INFO_FUNC(fmt, arg...) printk(DFT_TAG "[I]%s: " fmt, __FUNCTION__ ,##arg) +#define WMT_STP_EXP_WARN_FUNC(fmt, arg...) printk(DFT_TAG "[W]%s: " fmt, __FUNCTION__ ,##arg) +#define WMT_STP_EXP_ERR_FUNC(fmt, arg...) printk(DFT_TAG "[E]%s(%d):ERROR! " fmt, __FUNCTION__ , __LINE__, ##arg) + +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +MTK_WCN_STP_SEND_DATA mtk_wcn_stp_send_data_f = NULL; +MTK_WCN_STP_SEND_DATA mtk_wcn_stp_send_data_raw_f = NULL; +MTK_WCN_STP_PARSER_DATA mtk_wcn_stp_parser_data_f = NULL; +MTK_WCN_STP_RECV_DATA mtk_wcn_stp_receive_data_f = NULL; +MTK_WCN_STP_IS_RXQ_EMPTY mtk_wcn_stp_is_rxqueue_empty_f = NULL; +MTK_WCN_STP_IS_RDY mtk_wcn_stp_is_ready_f = NULL; +MTK_WCN_STP_SET_BLUEZ mtk_wcn_stp_set_bluez_f = NULL; +MTK_WCN_STP_REG_IF_TX mtk_wcn_stp_if_tx_f = NULL; +MTK_WCN_STP_REG_IF_RX mtk_wcn_stp_if_rx_f = NULL; +MTK_WCN_STP_REG_EVENT_CB mtk_wcn_stp_reg_event_cb_f = NULL; +MTK_WCN_STP_RGE_TX_EVENT_CB mtk_wcn_stp_reg_tx_event_cb_f = NULL; +MTK_WCN_STP_COREDUMP_START_GET mtk_wcn_stp_coredump_start_get_f = NULL; + +MTK_WCN_WMT_FUNC_CTRL mtk_wcn_wmt_func_on_f = NULL; +MTK_WCN_WMT_FUNC_CTRL mtk_wcn_wmt_func_off_f = NULL; +MTK_WCN_WMT_THERM_CTRL mtk_wcn_wmt_therm_ctrl_f = NULL; +MTK_WCN_WMT_HWVER_GET mtk_wcn_wmt_hwver_get_f = NULL; +MTK_WCN_WMT_DSNS_CTRL mtk_wcn_wmt_dsns_ctrl_f = NULL; +MTK_WCN_WMT_MSGCB_REG mtk_wcn_wmt_msgcb_reg_f = NULL; +MTK_WCN_WMT_MSGCB_UNREG mtk_wcn_wmt_msgcb_unreg_f = NULL; +MTK_WCN_WMT_SDIO_OP_REG mtk_wcn_wmt_sdio_op_reg_f = NULL; +MTK_WCN_WMT_SDIO_HOST_AWAKE mtk_wcn_wmt_sdio_host_awake_f = NULL; +MTK_WCN_WMT_ASSERT mtk_wcn_wmt_assert_f = NULL; +MTK_WCN_WMT_IC_INFO_GET mtk_wcn_wmt_ic_info_get_f = NULL; +MTK_WCN_WMT_PSM_CTRL mtk_wcn_wmt_psm_ctrl_f = NULL; + + + +UINT32 mtk_wcn_stp_exp_cb_reg(P_MTK_WCN_STP_EXP_CB_INFO pStpExpCb) +{ + WMT_STP_EXP_INFO_FUNC("call stp exp cb reg\n"); + + mtk_wcn_stp_send_data_f = pStpExpCb->stp_send_data_cb; + mtk_wcn_stp_send_data_raw_f = pStpExpCb->stp_send_data_raw_cb; + mtk_wcn_stp_parser_data_f = pStpExpCb->stp_parser_data_cb; + mtk_wcn_stp_receive_data_f = pStpExpCb->stp_receive_data_cb; + mtk_wcn_stp_is_rxqueue_empty_f = pStpExpCb->stp_is_rxqueue_empty_cb; + mtk_wcn_stp_is_ready_f = pStpExpCb->stp_is_ready_cb; + mtk_wcn_stp_set_bluez_f = pStpExpCb->stp_set_bluez_cb; + mtk_wcn_stp_if_tx_f = pStpExpCb->stp_if_tx_cb; + mtk_wcn_stp_if_rx_f = pStpExpCb->stp_if_rx_cb; + mtk_wcn_stp_reg_event_cb_f = pStpExpCb->stp_reg_event_cb; + mtk_wcn_stp_reg_tx_event_cb_f = pStpExpCb->stp_reg_tx_event_cb; + mtk_wcn_stp_coredump_start_get_f = pStpExpCb->stp_coredump_start_get_cb; + + return 0; +} + +EXPORT_SYMBOL(mtk_wcn_stp_exp_cb_reg); + +UINT32 mtk_wcn_stp_exp_cb_unreg(VOID) +{ + WMT_STP_EXP_INFO_FUNC("call stp exp cb unreg\n"); + + mtk_wcn_stp_send_data_f = NULL; + mtk_wcn_stp_send_data_raw_f = NULL; + mtk_wcn_stp_parser_data_f = NULL; + mtk_wcn_stp_receive_data_f = NULL; + mtk_wcn_stp_is_rxqueue_empty_f = NULL; + mtk_wcn_stp_is_ready_f = NULL; + mtk_wcn_stp_set_bluez_f = NULL; + mtk_wcn_stp_if_tx_f = NULL; + mtk_wcn_stp_if_rx_f = NULL; + mtk_wcn_stp_reg_event_cb_f = NULL; + mtk_wcn_stp_reg_tx_event_cb_f = NULL; + mtk_wcn_stp_coredump_start_get_f= NULL; + + return 0; +} + +EXPORT_SYMBOL(mtk_wcn_stp_exp_cb_unreg); + +INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type) +{ + INT32 ret = -1; + + if(mtk_wcn_stp_send_data_f) + { + ret = (*mtk_wcn_stp_send_data_f)(buffer,length,type); + + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_send_data_f cb is null\n"); + } + + return ret; + +} + +EXPORT_SYMBOL(mtk_wcn_stp_send_data); + +INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type) +{ + INT32 ret = -1; + + if(mtk_wcn_stp_send_data_raw_f) + { + ret = (*mtk_wcn_stp_send_data_raw_f)(buffer,length,type); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_send_data_raw_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_stp_send_data_raw); + +INT32 mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length) +{ + INT32 ret = -1; + + if(mtk_wcn_stp_parser_data_f) + { + ret = (*mtk_wcn_stp_parser_data_f)(buffer,length); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_parser_data_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_stp_parser_data); + +INT32 mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type) +{ + INT32 ret = -1; + + if(mtk_wcn_stp_receive_data_f) + { + ret = (*mtk_wcn_stp_receive_data_f)(buffer,length,type); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_receive_data_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_stp_receive_data); + +MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if(mtk_wcn_stp_is_rxqueue_empty_f) + { + ret = (*mtk_wcn_stp_is_rxqueue_empty_f)(type); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_is_rxqueue_empty_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_stp_is_rxqueue_empty); + +MTK_WCN_BOOL mtk_wcn_stp_is_ready(void) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if(mtk_wcn_stp_is_ready_f) + { + ret = (*mtk_wcn_stp_is_ready_f)(); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_is_ready_f cb is null\n"); + } + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_is_ready); + +void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL flags) +{ + + if(mtk_wcn_stp_set_bluez_f) + { + (*mtk_wcn_stp_set_bluez_f)(flags); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_set_bluez_f cb is null\n"); + } + + return; +} + +EXPORT_SYMBOL(mtk_wcn_stp_set_bluez); + +INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func) +{ + INT32 ret = -1; + + if(mtk_wcn_stp_if_tx_f) + { + ret = (*mtk_wcn_stp_if_tx_f)(stp_if,func); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_if_tx_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_stp_register_if_tx); + +INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func) +{ + INT32 ret = -1; + + if(mtk_wcn_stp_if_rx_f) + { + ret = (*mtk_wcn_stp_if_rx_f)(func); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_if_rx_f cb is null\n"); + } + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_stp_register_if_rx); + +INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +{ + INT32 ret = -1; + + if(mtk_wcn_stp_reg_event_cb_f) + { + ret = (*mtk_wcn_stp_reg_event_cb_f)(type,func); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_reg_event_cb_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_stp_register_event_cb); + +INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +{ + INT32 ret = -1; + + if(mtk_wcn_stp_reg_tx_event_cb_f) + { + ret = (*mtk_wcn_stp_reg_tx_event_cb_f)(type,func); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_reg_tx_event_cb_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_stp_register_tx_event_cb); + +INT32 mtk_wcn_stp_coredump_start_get(VOID) +{ + INT32 ret = -1; + + if(mtk_wcn_stp_coredump_start_get_f) + { + ret = (*mtk_wcn_stp_coredump_start_get_f)(); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_stp_coredump_start_get_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_stp_coredump_start_get); + + +UINT32 mtk_wcn_wmt_exp_cb_reg(P_MTK_WCN_WMT_EXP_CB_INFO pWmtExpCb) +{ + WMT_STP_EXP_INFO_FUNC("call wmt exp cb reg\n"); + + mtk_wcn_wmt_func_on_f = pWmtExpCb->wmt_func_on_cb; + mtk_wcn_wmt_func_off_f = pWmtExpCb->wmt_func_off_cb; + mtk_wcn_wmt_therm_ctrl_f = pWmtExpCb->wmt_therm_ctrl_cb; + mtk_wcn_wmt_hwver_get_f = pWmtExpCb->wmt_hwver_get_cb; + mtk_wcn_wmt_dsns_ctrl_f = pWmtExpCb->wmt_dsns_ctrl_cb; + mtk_wcn_wmt_msgcb_reg_f = pWmtExpCb->wmt_msgcb_reg_cb; + mtk_wcn_wmt_msgcb_unreg_f = pWmtExpCb->wmt_msgcb_unreg_cb; + mtk_wcn_wmt_sdio_op_reg_f = pWmtExpCb->wmt_sdio_op_reg_cb; + mtk_wcn_wmt_sdio_host_awake_f = pWmtExpCb->wmt_sdio_host_awake_cb; + mtk_wcn_wmt_assert_f = pWmtExpCb->wmt_assert_cb; + mtk_wcn_wmt_ic_info_get_f = pWmtExpCb->wmt_ic_info_get_cb; + mtk_wcn_wmt_psm_ctrl_f = pWmtExpCb->wmt_psm_ctrl_cb; + + return 0; +} + +EXPORT_SYMBOL(mtk_wcn_wmt_exp_cb_reg); + +UINT32 mtk_wcn_wmt_exp_cb_unreg(VOID) +{ + WMT_STP_EXP_INFO_FUNC("call wmt exp cb unreg\n"); + + mtk_wcn_wmt_func_on_f = NULL; + mtk_wcn_wmt_func_off_f = NULL; + mtk_wcn_wmt_therm_ctrl_f = NULL; + mtk_wcn_wmt_hwver_get_f = NULL; + mtk_wcn_wmt_dsns_ctrl_f = NULL; + mtk_wcn_wmt_msgcb_reg_f = NULL; + mtk_wcn_wmt_msgcb_unreg_f = NULL; + mtk_wcn_wmt_sdio_op_reg_f = NULL; + mtk_wcn_wmt_sdio_host_awake_f = NULL; + mtk_wcn_wmt_assert_f = NULL; + mtk_wcn_wmt_ic_info_get_f = NULL; + mtk_wcn_wmt_psm_ctrl_f = NULL; + + return 0; +} + +EXPORT_SYMBOL(mtk_wcn_wmt_exp_cb_unreg); + +MTK_WCN_BOOL mtk_wcn_wmt_func_off (ENUM_WMTDRV_TYPE_T type) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if(mtk_wcn_wmt_func_off_f) + { + ret = (*mtk_wcn_wmt_func_off_f)(type); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_func_off_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_wmt_func_off); + +MTK_WCN_BOOL mtk_wcn_wmt_func_on (ENUM_WMTDRV_TYPE_T type) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if(mtk_wcn_wmt_func_on_f) + { + ret = (*mtk_wcn_wmt_func_on_f)(type); + WMT_STP_EXP_INFO_FUNC("mtk_wcn_wmt_func_on_f type(%d)\n",type); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_func_on_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_wmt_func_on); + +INT8 mtk_wcn_wmt_therm_ctrl (ENUM_WMTTHERM_TYPE_T eType) +{ + INT32 ret = -1; + + if(mtk_wcn_wmt_therm_ctrl_f) + { + ret = (*mtk_wcn_wmt_therm_ctrl_f)(eType); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_therm_ctrl_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_wmt_therm_ctrl); + +ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get (VOID) +{ + ENUM_WMTHWVER_TYPE_T ret = WMTHWVER_INVALID; + + if(mtk_wcn_wmt_hwver_get_f) + { + ret = (*mtk_wcn_wmt_hwver_get_f)(); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_hwver_get_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_wmt_hwver_get); + +MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl (ENUM_WMTDSNS_TYPE_T eType) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if(mtk_wcn_wmt_dsns_ctrl_f) + { + ret = (*mtk_wcn_wmt_dsns_ctrl_f)(eType); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_dsns_ctrl_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_wmt_dsns_ctrl); + +INT32 mtk_wcn_wmt_msgcb_reg (ENUM_WMTDRV_TYPE_T eType,PF_WMT_CB pCb) +{ + INT32 ret = 0; + + if(mtk_wcn_wmt_msgcb_reg_f) + { + ret = (*mtk_wcn_wmt_msgcb_reg_f)(eType,pCb); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_msgcb_reg_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_reg); + +INT32 mtk_wcn_wmt_msgcb_unreg (ENUM_WMTDRV_TYPE_T eType) +{ + INT32 ret = 0; + + if(mtk_wcn_wmt_msgcb_unreg_f) + { + ret = (*mtk_wcn_wmt_msgcb_unreg_f)(eType); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_msgcb_unreg_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_unreg); + +INT32 mtk_wcn_stp_wmt_sdio_op_reg (PF_WMT_SDIO_PSOP own_cb) +{ + INT32 ret = -1; + + if(mtk_wcn_wmt_sdio_op_reg_f) + { + ret = (*mtk_wcn_wmt_sdio_op_reg_f)(own_cb); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_sdio_op_reg_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_op_reg); + +INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID) +{ + INT32 ret = -1; + + if(mtk_wcn_wmt_sdio_host_awake_f) + { + ret = (*mtk_wcn_wmt_sdio_host_awake_f)(); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_sdio_host_awake_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_host_awake); + +MTK_WCN_BOOL mtk_wcn_wmt_assert (ENUM_WMTDRV_TYPE_T type,UINT32 reason) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if(mtk_wcn_wmt_assert_f) + { + ret = (*mtk_wcn_wmt_assert_f)(type,reason); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_assert_f cb is null\n"); + } + + return ret; +} + +EXPORT_SYMBOL(mtk_wcn_wmt_assert); + +UINT32 +mtk_wcn_wmt_ic_info_get (ENUM_WMT_CHIPINFO_TYPE_T type) +{ + UINT32 ret = 0; + + if(mtk_wcn_wmt_ic_info_get_f) + { + ret = (*mtk_wcn_wmt_ic_info_get_f)(type); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_ic_info_get_f cb is null\n"); + } + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_ic_info_get); + +INT32 mtk_wcn_wmt_psm_ctrl(MTK_WCN_BOOL flag) +{ + UINT32 ret = 0; + + if(mtk_wcn_wmt_psm_ctrl_f) + { + ret = (*mtk_wcn_wmt_psm_ctrl_f)(flag); + }else + { + WMT_STP_EXP_ERR_FUNC("mtk_wcn_wmt_psm_ctrl_f cb is null\n"); + } + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_psm_ctrl); + +#endif + diff --git a/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h new file mode 100644 index 00000000000000..c2920a590f7425 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_detect/wmt_stp_exp.h @@ -0,0 +1,300 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _WMT_STP_EXP_H_ +#define _WMT_STP_EXP_H_ +#include <linux/version.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/sched.h> +#include <linux/poll.h> +#include <asm/current.h> +#include <asm/uaccess.h> +#include <linux/proc_fs.h> +#include <linux/workqueue.h> +#include <linux/wait.h> +#include <linux/time.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/vmalloc.h> +#include <linux/firmware.h> +#include <linux/kthread.h> +#include <linux/jiffies.h> +#include <linux/slab.h> +#include <mt-plat/mtk_wcn_cmb_stub.h> +#include "stp_exp.h" +#include "wmt_exp.h" + +#ifndef MTK_WCN_CMB_FOR_SDIO_1V_AUTOK +#define MTK_WCN_CMB_FOR_SDIO_1V_AUTOK 0 +#endif + +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +#ifdef WMT_IDC_SUPPORT +#if WMT_IDC_SUPPORT +#define CFG_WMT_LTE_COEX_HANDLING 1 +#define CFG_WMT_LTE_ENABLE_MSGID_MAPPING 0 +#else +#define CFG_WMT_LTE_COEX_HANDLING 0 +#endif +#endif + +#define BT_TASK_INDX (0) +#define FM_TASK_INDX (1) +#define GPS_TASK_INDX (2) +#define WIFI_TASK_INDX (3) +#define WMT_TASK_INDX (4) +#define STP_TASK_INDX (5) +#define INFO_TASK_INDX (6) +#define ANT_TASK_INDX (7) +#if CFG_WMT_LTE_COEX_HANDLING +#define COEX_TASK_INDX (8) +#define MTKSTP_MAX_TASK_NUM (9) +#else +#define MTKSTP_MAX_TASK_NUM (8) +#endif + +#define MTKSTP_BUFFER_SIZE (16384) + + +typedef void (*MTK_WCN_STP_EVENT_CB)(void); +typedef INT32 (*MTK_WCN_STP_IF_TX)(const PUINT8 data, const UINT32 size, PUINT32 written_size); +typedef void (*MTK_WCN_STP_IF_RX)(const PUINT8 data, INT32 size); + +/* +typedef enum { + STP_UART_IF_TX = 0, + STP_SDIO_IF_TX = 1, + STP_BTIF_IF_TX = 2, + STP_MAX_IF_TX +} ENUM_STP_TX_IF_TYPE; +*/ + +typedef INT32 (*MTK_WCN_STP_SEND_DATA) (const PUINT8 buffer, const UINT32 length, const UINT8 type); +typedef INT32 (*MTK_WCN_STP_PARSER_DATA)(PUINT8 buffer, UINT32 length); +typedef INT32 (*MTK_WCN_STP_RECV_DATA)(PUINT8 buffer, UINT32 length, UINT8 type); +typedef MTK_WCN_BOOL (*MTK_WCN_STP_IS_RXQ_EMPTY)(UINT8 type); +typedef MTK_WCN_BOOL (*MTK_WCN_STP_IS_RDY)(VOID); +typedef VOID (*MTK_WCN_STP_SET_BLUEZ)(MTK_WCN_BOOL flags); +typedef INT32 (*MTK_WCN_STP_REG_IF_TX)(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); +typedef INT32 (*MTK_WCN_STP_REG_IF_RX)(MTK_WCN_STP_IF_RX func); +typedef INT32 (*MTK_WCN_STP_REG_EVENT_CB)(INT32 type, MTK_WCN_STP_EVENT_CB func); +typedef INT32 (*MTK_WCN_STP_RGE_TX_EVENT_CB)(INT32 type, MTK_WCN_STP_EVENT_CB func); +typedef INT32 (*MTK_WCN_STP_COREDUMP_START_GET)(VOID); + +typedef struct _MTK_WCN_STP_EXP_CB_INFO_{ + MTK_WCN_STP_SEND_DATA stp_send_data_cb; + MTK_WCN_STP_SEND_DATA stp_send_data_raw_cb; + MTK_WCN_STP_PARSER_DATA stp_parser_data_cb; + MTK_WCN_STP_RECV_DATA stp_receive_data_cb; + MTK_WCN_STP_IS_RXQ_EMPTY stp_is_rxqueue_empty_cb; + MTK_WCN_STP_IS_RDY stp_is_ready_cb; + MTK_WCN_STP_SET_BLUEZ stp_set_bluez_cb; + MTK_WCN_STP_REG_IF_TX stp_if_tx_cb; + MTK_WCN_STP_REG_IF_RX stp_if_rx_cb; + MTK_WCN_STP_REG_EVENT_CB stp_reg_event_cb; + MTK_WCN_STP_RGE_TX_EVENT_CB stp_reg_tx_event_cb; + MTK_WCN_STP_COREDUMP_START_GET stp_coredump_start_get_cb; +}MTK_WCN_STP_EXP_CB_INFO,*P_MTK_WCN_STP_EXP_CB_INFO; + +/* +typedef enum _ENUM_WMTDRV_TYPE_T { + WMTDRV_TYPE_BT = 0, + WMTDRV_TYPE_FM = 1, + WMTDRV_TYPE_GPS = 2, + WMTDRV_TYPE_WIFI = 3, + WMTDRV_TYPE_WMT = 4, + WMTDRV_TYPE_ANT = 5, + WMTDRV_TYPE_STP = 6, + WMTDRV_TYPE_SDIO1 = 7, + WMTDRV_TYPE_SDIO2 = 8, + WMTDRV_TYPE_LPBK = 9, + WMTDRV_TYPE_COREDUMP = 10, +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK + WMTDRV_TYPE_AUTOK = 11, +#endif + WMTDRV_TYPE_MAX +} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; +*/ + +/*typedef enum _ENUM_WMTDSNS_TYPE_T{ + WMTDSNS_FM_DISABLE = 0, + WMTDSNS_FM_ENABLE = 1, + WMTDSNS_FM_GPS_DISABLE = 2, + WMTDSNS_FM_GPS_ENABLE = 3, + WMTDSNS_MAX +} ENUM_WMTDSNS_TYPE_T, *P_ENUM_WMTDSNS_TYPE_T;*/ + +/*typedef enum _ENUM_WMTHWVER_TYPE_T{ + WMTHWVER_E1 = 0x0, + WMTHWVER_E2 = 0x1, + WMTHWVER_E3 = 0x2, + WMTHWVER_E4 = 0x3, + WMTHWVER_E5 = 0x4, + WMTHWVER_E6 = 0x5, + WMTHWVER_E7 = 0x6, + WMTHWVER_MAX, + WMTHWVER_INVALID = 0xff +} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T;*/ + +/*typedef enum _ENUM_WMTTHERM_TYPE_T{ + WMTTHERM_ZERO = 0, + WMTTHERM_ENABLE = WMTTHERM_ZERO + 1, + WMTTHERM_READ = WMTTHERM_ENABLE + 1, + WMTTHERM_DISABLE = WMTTHERM_READ + 1, + WMTTHERM_MAX +}ENUM_WMTTHERM_TYPE_T, *P_ENUM_WMTTHERM_TYPE_T;*/ + +/*typedef enum _ENUM_WMTMSG_TYPE_T { + WMTMSG_TYPE_POWER_ON = 0, + WMTMSG_TYPE_POWER_OFF = 1, + WMTMSG_TYPE_RESET = 2, + WMTMSG_TYPE_STP_RDY= 3, + WMTMSG_TYPE_HW_FUNC_ON= 4, + WMTMSG_TYPE_MAX +} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T;*/ + +//typedef void (*PF_WMT_CB)(ENUM_WMTDRV_TYPE_T, ENUM_WMTDRV_TYPE_T, ENUM_WMTMSG_TYPE_T, VOID *, UINT32); + +/* +typedef enum _SDIO_PS_OP{ + OWN_SET = 0, + OWN_CLR = 1, + OWN_STATE = 2, +} SDIO_PS_OP; +*/ + +//typedef INT32 (*PF_WMT_SDIO_PSOP)(SDIO_PS_OP); + + +/*typedef enum _ENUM_WMTCHIN_TYPE_T{ + WMTCHIN_CHIPID = 0x0, + WMTCHIN_HWVER = WMTCHIN_CHIPID + 1, + WMTCHIN_MAPPINGHWVER = WMTCHIN_HWVER + 1, + WMTCHIN_FWVER = WMTCHIN_MAPPINGHWVER + 1, + WMTCHIN_MAX, + +}ENUM_WMT_CHIPINFO_TYPE_T, *P_ENUM_WMT_CHIPINFO_TYPE_T;*/ + + +typedef MTK_WCN_BOOL (*MTK_WCN_WMT_FUNC_CTRL)(ENUM_WMTDRV_TYPE_T type); +typedef INT8(*MTK_WCN_WMT_THERM_CTRL)(ENUM_WMTTHERM_TYPE_T eType); +typedef ENUM_WMTHWVER_TYPE_T(*MTK_WCN_WMT_HWVER_GET)(VOID); +typedef MTK_WCN_BOOL (*MTK_WCN_WMT_DSNS_CTRL)(ENUM_WMTDSNS_TYPE_T eType); +typedef INT32 (*MTK_WCN_WMT_MSGCB_REG)(ENUM_WMTDRV_TYPE_T eType,PF_WMT_CB pCb); +typedef INT32 (*MTK_WCN_WMT_MSGCB_UNREG) (ENUM_WMTDRV_TYPE_T eType); +typedef INT32 (*MTK_WCN_WMT_SDIO_OP_REG)(PF_WMT_SDIO_PSOP own_cb); +typedef INT32 (*MTK_WCN_WMT_SDIO_HOST_AWAKE)(VOID); +typedef MTK_WCN_BOOL(*MTK_WCN_WMT_ASSERT)(ENUM_WMTDRV_TYPE_T type,UINT32 reason); +typedef UINT32 (*MTK_WCN_WMT_IC_INFO_GET) (ENUM_WMT_CHIPINFO_TYPE_T type); +typedef INT32 (*MTK_WCN_WMT_PSM_CTRL)(MTK_WCN_BOOL flag); + + +/*typedef struct _MTK_WCN_WMT_EXP_CB_INFO_{ + MTK_WCN_WMT_FUNC_CTRL wmt_func_on_cb; + MTK_WCN_WMT_FUNC_CTRL wmt_func_off_cb; + MTK_WCN_WMT_THERM_CTRL wmt_therm_ctrl_cb; + MTK_WCN_WMT_HWVER_GET wmt_hwver_get_cb; + MTK_WCN_WMT_DSNS_CTRL wmt_dsns_ctrl_cb; + MTK_WCN_WMT_MSGCB_REG wmt_msgcb_reg_cb; + MTK_WCN_WMT_MSGCB_UNREG wmt_msgcb_unreg_cb; + MTK_WCN_WMT_SDIO_OP_REG wmt_sdio_op_reg_cb; + MTK_WCN_WMT_SDIO_HOST_AWAKE wmt_sdio_host_awake_cb; + MTK_WCN_WMT_ASSERT wmt_assert_cb; + MTK_WCN_WMT_IC_INFO_GET wmt_ic_info_get_cb; + MTK_WCN_WMT_PSM_CTRL wmt_psm_ctrl_cb; +}MTK_WCN_WMT_EXP_CB_INFO,*P_MTK_WCN_WMT_EXP_CB_INFO;*/ + + + +UINT32 mtk_wcn_stp_exp_cb_reg(P_MTK_WCN_STP_EXP_CB_INFO pStpExpCb); + +UINT32 mtk_wcn_stp_exp_cb_unreg(VOID); + +UINT32 mtk_wcn_wmt_exp_cb_reg(P_MTK_WCN_WMT_EXP_CB_INFO pWmtExpCb); + +UINT32 mtk_wcn_wmt_exp_cb_unreg(VOID); + + +extern INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type); + + +extern INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type); + + +extern INT32 mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length); + + +extern INT32 mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type); + + +extern MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type); + + +extern MTK_WCN_BOOL mtk_wcn_stp_is_ready(void); + + +extern void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL flags); + + +extern INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); + + +extern INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func); + + +extern INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); + + +extern INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); + + +extern INT32 mtk_wcn_stp_coredump_start_get(VOID); + + + +extern MTK_WCN_BOOL mtk_wcn_wmt_func_off (ENUM_WMTDRV_TYPE_T type); + +extern MTK_WCN_BOOL mtk_wcn_wmt_func_on (ENUM_WMTDRV_TYPE_T type); + +extern INT8 mtk_wcn_wmt_therm_ctrl (ENUM_WMTTHERM_TYPE_T eType); + +extern ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get (VOID); + +extern UINT32 +mtk_wcn_wmt_ic_info_get (ENUM_WMT_CHIPINFO_TYPE_T type); + + +extern MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl (ENUM_WMTDSNS_TYPE_T eType); + +extern INT32 mtk_wcn_wmt_msgcb_reg (ENUM_WMTDRV_TYPE_T eType,PF_WMT_CB pCb); + +extern INT32 mtk_wcn_wmt_msgcb_unreg (ENUM_WMTDRV_TYPE_T eType); + +extern INT32 mtk_wcn_stp_wmt_sdio_op_reg (PF_WMT_SDIO_PSOP own_cb); + +extern INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID); + +extern MTK_WCN_BOOL mtk_wcn_wmt_assert (ENUM_WMTDRV_TYPE_T type,UINT32 reason); + +extern INT32 mtk_wcn_wmt_psm_ctrl(MTK_WCN_BOOL flag); + +#endif + +#endif + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/btm_core.c b/drivers/misc/mediatek/connectivity/common/common_main/core/btm_core.c new file mode 100644 index 00000000000000..ac3ef8ce6c6927 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/btm_core.c @@ -0,0 +1,777 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <linux/atomic.h> +#include "osal_typedef.h" +#include "osal.h" +#include "stp_dbg.h" +#include "stp_core.h" +#include "btm_core.h" +#include "wmt_plat.h" +#include "wmt_step.h" +#include "wmt_detect.h" +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +#include "connsys_debug_utility.h" +#endif +#include <linux/kthread.h> + +#define PFX_BTM "[STP-BTM] " +#define STP_BTM_LOG_LOUD 4 +#define STP_BTM_LOG_DBG 3 +#define STP_BTM_LOG_INFO 2 +#define STP_BTM_LOG_WARN 1 +#define STP_BTM_LOG_ERR 0 + +INT32 gBtmDbgLevel = STP_BTM_LOG_INFO; + +#define STP_BTM_PR_LOUD(fmt, arg...) \ +do { \ + if (gBtmDbgLevel >= STP_BTM_LOG_LOUD) \ + pr_info(PFX_BTM "%s: " fmt, __func__, ##arg); \ +} while (0) +#define STP_BTM_PR_DBG(fmt, arg...) \ +do { \ + if (gBtmDbgLevel >= STP_BTM_LOG_DBG) \ + pr_info(PFX_BTM "%s: " fmt, __func__, ##arg); \ +} while (0) +#define STP_BTM_PR_INFO(fmt, arg...) \ +do { \ + if (gBtmDbgLevel >= STP_BTM_LOG_INFO) \ + pr_info(PFX_BTM "[I]%s: " fmt, __func__, ##arg); \ +} while (0) +#define STP_BTM_PR_WARN(fmt, arg...) \ +do { \ + if (gBtmDbgLevel >= STP_BTM_LOG_WARN) \ + pr_warn(PFX_BTM "[W]%s: " fmt, __func__, ##arg); \ +} while (0) +#define STP_BTM_PR_ERR(fmt, arg...) \ +do { \ + if (gBtmDbgLevel >= STP_BTM_LOG_ERR) \ + pr_err(PFX_BTM "[E]%s(%d):ERROR! " fmt, __func__, __LINE__, ##arg); \ +} while (0) + +#define ASSERT(expr) + +MTKSTP_BTM_T stp_btm_i; +MTKSTP_BTM_T *stp_btm = &stp_btm_i; + +const PINT8 g_btm_op_name[] = { + "STP_OPID_BTM_RETRY", + "STP_OPID_BTM_RST", + "STP_OPID_BTM_DBG_DUMP", + "STP_OPID_BTM_DUMP_TIMEOUT", + "STP_OPID_BTM_POLL_CPUPCR", + "STP_OPID_BTM_PAGED_DUMP", + "STP_OPID_BTM_FULL_DUMP", + "STP_OPID_BTM_PAGED_TRACE", + "STP_OPID_BTM_FORCE_FW_ASSERT", +#if CFG_WMT_LTE_COEX_HANDLING + "STP_OPID_BTM_WMT_LTE_COEX", +#endif + "STP_OPID_BTM_ASSERT_TIMEOUT", + "STP_OPID_BTM_EMI_DUMP_END", + "STP_OPID_BTM_EXIT" +}; + +static VOID stp_btm_trigger_assert_timeout_handler(ULONG data) +{ + if (mtk_wcn_stp_coredump_start_get() == 0) + stp_btm_notify_assert_timeout_wq((MTKSTP_BTM_T *)data); +} + +static INT32 _stp_btm_handler(MTKSTP_BTM_T *stp_btm, P_STP_BTM_OP pStpOp) +{ + INT32 ret = -1; + /* core dump target, 0: aee; 1: netlink */ + INT32 dump_sink = mtk_wcn_stp_coredump_flag_get(); + + if (pStpOp == NULL) + return -1; + + switch (pStpOp->opId) { + case STP_OPID_BTM_EXIT: + /* TODO: clean all up? */ + ret = 0; + break; + + /*tx timeout retry */ + case STP_OPID_BTM_RETRY: + if (mtk_wcn_stp_coredump_start_get() == 0) + stp_do_tx_timeout(); + ret = 0; + break; + + /*whole chip reset */ + case STP_OPID_BTM_RST: + STP_BTM_PR_INFO("whole chip reset start!\n"); + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC && + mtk_wcn_stp_coredump_flag_get() != 0 && chip_reset_only == 0) { +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + connsys_dedicated_log_flush_emi(); +#endif + stp_dbg_core_dump_flush(0, MTK_WCN_BOOL_FALSE); + } + STP_BTM_PR_INFO("....+\n"); + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_BEFORE_CHIP_RESET); + if (stp_btm->wmt_notify) { + stp_btm->wmt_notify(BTM_RST_OP); + ret = 0; + } else { + STP_BTM_PR_ERR("stp_btm->wmt_notify is NULL."); + ret = -1; + } + + STP_BTM_PR_INFO("whole chip reset end!\n"); + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_AFTER_CHIP_RESET); + break; + + case STP_OPID_BTM_DBG_DUMP: + /*Notify the wmt to get dump data */ + STP_BTM_PR_DBG("wmt dmp notification\n"); + set_user_nice(stp_btm->BTMd.pThread, -20); + ret = stp_dbg_core_dump(dump_sink); + set_user_nice(stp_btm->BTMd.pThread, 0); + break; + + case STP_OPID_BTM_DUMP_TIMEOUT: + /* append fake coredump end message */ + if (dump_sink == 2 && wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) { + stp_dbg_set_coredump_timer_state(CORE_DUMP_DOING); + STP_BTM_PR_WARN("generate fake coredump message\n"); + stp_dbg_nl_send_data(FAKECOREDUMPEND, osal_sizeof(FAKECOREDUMPEND)); + } + stp_dbg_poll_cpupcr(5, 1, 1); + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) { + /* Flush dump data, and reset compressor */ + STP_BTM_PR_INFO("Flush dump data\n"); + stp_dbg_core_dump_flush(0, MTK_WCN_BOOL_TRUE); + } + ret = mtk_wcn_stp_coredump_timeout_handle(); + break; +#if CFG_WMT_LTE_COEX_HANDLING + case STP_OPID_BTM_WMT_LTE_COEX: + ret = wmt_idc_msg_to_lte_handing(); + break; +#endif + case STP_OPID_BTM_ASSERT_TIMEOUT: + mtk_wcn_stp_assert_timeout_handle(); + ret = 0; + break; + case STP_OPID_BTM_EMI_DUMP_END: + STP_BTM_PR_INFO("emi dump end notification.\n"); + stp_dbg_stop_emi_dump(); + mtk_wcn_stp_ctx_restore(); + ret = 0; + break; + default: + ret = -1; + break; + } + + return ret; +} + +static P_OSAL_OP _stp_btm_get_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ) +{ + P_OSAL_OP pOp; + /* INT32 ret = 0; */ + + if (!pOpQ) { + STP_BTM_PR_WARN("!pOpQ\n"); + return NULL; + } + + osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); + /* acquire lock success */ + RB_GET(pOpQ, pOp); + osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); + + if (!pOp) + STP_BTM_PR_DBG("RB_GET fail\n"); + return pOp; +} + +static INT32 _stp_btm_put_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) +{ + INT32 ret; + P_OSAL_OP pOp_latest = NULL; + P_OSAL_OP pOp_current = NULL; + INT32 flag_latest = 1; + INT32 flag_current = 1; + + if (!pOpQ || !pOp) { + STP_BTM_PR_WARN("invalid input param: 0x%p, 0x%p\n", pOpQ, pOp); + return 0; /* ;MTK_WCN_BOOL_FALSE; */ + } + ret = 0; + + osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); + /* acquire lock success */ + if (&stp_btm->rFreeOpQ == pOpQ) { + if (!RB_FULL(pOpQ)) + RB_PUT(pOpQ, pOp); + else + ret = -1; + } else if (pOp->op.opId == STP_OPID_BTM_RST || + pOp->op.opId == STP_OPID_BTM_ASSERT_TIMEOUT || + pOp->op.opId == STP_OPID_BTM_DUMP_TIMEOUT || + pOp->op.opId == STP_OPID_BTM_EMI_DUMP_END) { + if (!RB_FULL(pOpQ)) { + RB_PUT(pOpQ, pOp); + STP_BTM_PR_DBG("RB_PUT: 0x%x\n", pOp->op.opId); + } else + ret = -1; + } else { + pOp_current = stp_btm_get_current_op(stp_btm); + if (pOp_current) { + if (pOp_current->op.opId == STP_OPID_BTM_RST || + pOp_current->op.opId == STP_OPID_BTM_DUMP_TIMEOUT || + (pOp_current->op.opId == STP_OPID_BTM_ASSERT_TIMEOUT && + pOp->op.opId != STP_OPID_BTM_DBG_DUMP)) { + STP_BTM_PR_DBG("current: 0x%x\n", pOp_current->op.opId); + flag_current = 0; + } + } + + RB_GET_LATEST(pOpQ, pOp_latest); + if (pOp_latest) { + if (pOp_latest->op.opId == STP_OPID_BTM_RST || + pOp_latest->op.opId == STP_OPID_BTM_ASSERT_TIMEOUT || + pOp_latest->op.opId == STP_OPID_BTM_DUMP_TIMEOUT) { + STP_BTM_PR_DBG("latest: 0x%x\n", pOp_latest->op.opId); + flag_latest = 0; + } + if (pOp_latest->op.opId == pOp->op.opId +#if CFG_WMT_LTE_COEX_HANDLING + && pOp->op.opId != STP_OPID_BTM_WMT_LTE_COEX +#endif + ) { + flag_latest = 0; + STP_BTM_PR_DBG("With the latest a command repeat: latest 0x%x,current 0x%x\n", + pOp_latest->op.opId, pOp->op.opId); + } + } + if (flag_current && flag_latest) { + if (!RB_FULL(pOpQ)) { + RB_PUT(pOpQ, pOp); + STP_BTM_PR_DBG("RB_PUT: 0x%x\n", pOp->op.opId); + } else + ret = -1; + } else + ret = 0; + + } + + if (ret) { + STP_BTM_PR_DBG("RB_FULL(0x%p) %d ,rFreeOpQ = %p, rActiveOpQ = %p\n", + pOpQ, RB_COUNT(pOpQ), &stp_btm->rFreeOpQ, &stp_btm->rActiveOpQ); + osal_opq_dump_locked("FreeOpQ", &stp_btm->rFreeOpQ); + osal_opq_dump_locked("ActiveOpQ", &stp_btm->rActiveOpQ); + } + + osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); + return ret ? 0 : 1; +} + +static P_OSAL_OP _stp_btm_get_free_op(MTKSTP_BTM_T *stp_btm) +{ + P_OSAL_OP pOp; + + if (stp_btm) { + pOp = _stp_btm_get_op(stp_btm, &stp_btm->rFreeOpQ); + if (pOp) { + osal_memset(pOp, 0, osal_sizeof(OSAL_OP)); + } + + return pOp; + } else + return NULL; +} + +static INT32 _stp_btm_put_act_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP pOp) +{ + INT32 bRet = 0; + INT32 wait_ret = -1; + + P_OSAL_SIGNAL pSignal = NULL; + + if (!stp_btm || !pOp) { + STP_BTM_PR_ERR("Input NULL pointer\n"); + return bRet; + } + do { + pSignal = &pOp->signal; + + if (pSignal->timeoutValue) { + pOp->result = -9; + osal_signal_init(&pOp->signal); + } + + /* Init ref_count to 2, as one is held by current thread, the second by btm thread */ + atomic_set(&pOp->ref_count, 2); + + /* put to active Q */ + bRet = _stp_btm_put_op(stp_btm, &stp_btm->rActiveOpQ, pOp); + if (bRet == 0) { + STP_BTM_PR_DBG("put active queue fail\n"); + atomic_dec(&pOp->ref_count); + break; + } + /* wake up wmtd */ + osal_trigger_event(&stp_btm->STPd_event); + + if (pSignal->timeoutValue == 0) { + bRet = 1; /* MTK_WCN_BOOL_TRUE; */ + break; + } + + /* check result */ + wait_ret = osal_wait_for_signal_timeout(&pOp->signal, &stp_btm->BTMd); + + STP_BTM_PR_DBG("wait completion:%d\n", wait_ret); + if (!wait_ret) { + STP_BTM_PR_ERR("wait completion timeout\n"); + /* TODO: how to handle it? retry? */ + } else { + if (pOp->result) + STP_BTM_PR_WARN("op(%d) result:%d\n", pOp->op.opId, pOp->result); + bRet = (pOp->result) ? 0 : 1; + } + } while (0); + + if (pOp && atomic_dec_and_test(&pOp->ref_count)) { + /* put Op back to freeQ */ + _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, pOp); + } + + return bRet; +} + +static INT32 _stp_btm_wait_for_msg(PVOID pvData) +{ + MTKSTP_BTM_T *stp_btm = (MTKSTP_BTM_T *) pvData; + + return (!RB_EMPTY(&stp_btm->rActiveOpQ)) || osal_thread_should_stop(&stp_btm->BTMd); +} + +static INT32 _stp_btm_proc(PVOID pvData) +{ + MTKSTP_BTM_T *stp_btm = (MTKSTP_BTM_T *) pvData; + P_OSAL_OP pOp; + INT32 id; + INT32 result; + + if (!stp_btm) { + STP_BTM_PR_WARN("!stp_btm\n"); + return -1; + } + + for (;;) { + pOp = NULL; + + osal_wait_for_event(&stp_btm->STPd_event, _stp_btm_wait_for_msg, (PVOID) stp_btm); + + if (osal_thread_should_stop(&stp_btm->BTMd)) { + STP_BTM_PR_INFO("should stop now...\n"); + /* TODO: clean up active opQ */ + break; + } + + if (stp_btm->gDumplogflag) { + /* pr_warn("enter place1\n"); */ + stp_btm->gDumplogflag = 0; + continue; + } + + /* get Op from activeQ */ + pOp = _stp_btm_get_op(stp_btm, &stp_btm->rActiveOpQ); + + if (!pOp) { + STP_BTM_PR_WARN("get_lxop activeQ fail\n"); + continue; + } + osal_op_history_save(&stp_btm->op_history, pOp); + + id = osal_op_get_id(pOp); + + STP_BTM_PR_DBG("======> lxop_get_opid = %d, %s, remaining count = *%d*\n", + id, (id >= osal_array_size(g_btm_op_name)) ? ("???") : (g_btm_op_name[id]), + RB_COUNT(&stp_btm->rActiveOpQ)); + + if (id >= STP_OPID_BTM_NUM) { + STP_BTM_PR_WARN("abnormal opid id: 0x%x\n", id); + result = -1; + goto handler_done; + } + + osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); + stp_btm_set_current_op(stp_btm, pOp); + osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); + result = _stp_btm_handler(stp_btm, &pOp->op); + osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); + stp_btm_set_current_op(stp_btm, NULL); + osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); + +handler_done: + + if (result) { + STP_BTM_PR_WARN("opid id(0x%x)(%s) error(%d)\n", id, + (id >= osal_array_size(g_btm_op_name)) ? ("???") : (g_btm_op_name[id]), result); + } + + if (atomic_dec_and_test(&pOp->ref_count)) { + _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, pOp); + } else if (osal_op_is_wait_for_signal(pOp)) { + osal_op_raise_signal(pOp, result); + } + + if (id == STP_OPID_BTM_EXIT) { + break; + } else if (id == STP_OPID_BTM_RST) { + /* prevent multi reset case */ + stp_btm_reset_btm_wq(stp_btm); + } + } + + STP_BTM_PR_INFO("exits\n"); + + return 0; +} + +static inline INT32 _stp_btm_dump_type(MTKSTP_BTM_T *stp_btm, ENUM_STP_BTM_OPID_T opid) +{ + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + pOp = _stp_btm_get_free_op(stp_btm); + if (!pOp) { + STP_BTM_PR_WARN("get_free_lxop fail\n"); + return -1; /* break; */ + } + + pOp->op.opId = opid; + pOp->signal.timeoutValue = 0; + bRet = _stp_btm_put_act_op(stp_btm, pOp); + STP_BTM_PR_DBG("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); + retval = (bRet == 0) ? STP_BTM_OPERATION_FAIL : STP_BTM_OPERATION_SUCCESS; + + return retval; +} + +static inline INT32 _stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm) +{ + INT32 retval; + + if (stp_btm == NULL) + return STP_BTM_OPERATION_FAIL; + + retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_RST); + return retval; +} + +static inline INT32 _stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm) +{ + INT32 retval; + + if (stp_btm == NULL) + return STP_BTM_OPERATION_FAIL; + + retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_RETRY); + return retval; +} + + +static inline INT32 _stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm) +{ + INT32 retval; + + if (!stp_btm) + return STP_BTM_OPERATION_FAIL; + + stp_btm_reset_btm_wq(stp_btm); + retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_DUMP_TIMEOUT); + return retval; +} + +static inline INT32 _stp_btm_notify_assert_timeout_wq(MTKSTP_BTM_T *stp_btm) +{ + INT32 retval; + + if (!stp_btm) + return STP_BTM_OPERATION_FAIL; + + retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_ASSERT_TIMEOUT); + return retval; +} + +static inline INT32 _stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm) +{ + + INT32 retval; + + if (stp_btm == NULL) + return STP_BTM_OPERATION_FAIL; + + /* Paged dump */ + retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_DBG_DUMP); + + return retval; +} + +static inline INT32 _stp_btm_notify_emi_dump_end_wq(MTKSTP_BTM_T *stp_btm) +{ + INT32 retval; + + if (!stp_btm) + return STP_BTM_OPERATION_FAIL; + + retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_EMI_DUMP_END); + return retval; +} + +INT32 stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm) +{ + return _stp_btm_notify_wmt_rst_wq(stp_btm); +} + +INT32 stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm) +{ + return _stp_btm_notify_stp_retry_wq(stp_btm); +} + +INT32 stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm) +{ + return _stp_btm_notify_coredump_timeout_wq(stp_btm); +} + +INT32 stp_btm_notify_assert_timeout_wq(MTKSTP_BTM_T *stp_btm) +{ + return _stp_btm_notify_assert_timeout_wq(stp_btm); +} + +INT32 stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm) +{ + return _stp_btm_notify_wmt_dmp_wq(stp_btm); +} + +INT32 stp_btm_notify_emi_dump_end(MTKSTP_BTM_T *stp_btm) +{ + return _stp_btm_notify_emi_dump_end_wq(stp_btm); +} + +INT32 stp_notify_btm_poll_cpupcr_ctrl(UINT32 en) +{ + return stp_dbg_poll_cpupcr_ctrl(en); +} + + +#if CFG_WMT_LTE_COEX_HANDLING + +static inline INT32 _stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm) +{ + INT32 retval; + + if (stp_btm == NULL) + return STP_BTM_OPERATION_FAIL; + + retval = _stp_btm_dump_type(stp_btm, STP_OPID_BTM_WMT_LTE_COEX); + return retval; +} + +INT32 stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm) +{ + return _stp_notify_btm_handle_wmt_lte_coex(stp_btm); +} + +#endif +MTKSTP_BTM_T *stp_btm_init(VOID) +{ + INT32 i = 0x0; + INT32 ret = -1; + + osal_unsleepable_lock_init(&stp_btm->wq_spinlock); + osal_event_init(&stp_btm->STPd_event); + stp_btm->wmt_notify = wmt_lib_btm_cb; + + RB_INIT(&stp_btm->rFreeOpQ, STP_BTM_OP_BUF_SIZE); + RB_INIT(&stp_btm->rActiveOpQ, STP_BTM_OP_BUF_SIZE); + + /* Put all to free Q */ + for (i = 0; i < STP_BTM_OP_BUF_SIZE; i++) { + osal_signal_init(&(stp_btm->arQue[i].signal)); + _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, &(stp_btm->arQue[i])); + } + + stp_btm_init_trigger_assert_timer(stp_btm); + osal_op_history_init(&stp_btm->op_history, 16); + + /*Generate PSM thread, to servie STP-CORE for packet retrying and core dump receiving */ + stp_btm->BTMd.pThreadData = (PVOID) stp_btm; + stp_btm->BTMd.pThreadFunc = (PVOID) _stp_btm_proc; + osal_memcpy(stp_btm->BTMd.threadName, BTM_THREAD_NAME, osal_strlen(BTM_THREAD_NAME)); + + ret = osal_thread_create(&stp_btm->BTMd); + if (ret < 0) { + STP_BTM_PR_ERR("osal_thread_create fail...\n"); + goto ERR_EXIT1; + } + + /* Start STPd thread */ + ret = osal_thread_run(&stp_btm->BTMd); + if (ret < 0) { + STP_BTM_PR_ERR("osal_thread_run FAILS\n"); + goto ERR_EXIT1; + } + + return stp_btm; + +ERR_EXIT1: + + return NULL; + +} + +INT32 stp_btm_deinit(MTKSTP_BTM_T *stp_btm) +{ + + INT32 ret = -1; + + STP_BTM_PR_INFO("btm deinit\n"); + + if (!stp_btm) + return STP_BTM_OPERATION_FAIL; + + ret = osal_thread_destroy(&stp_btm->BTMd); + if (ret < 0) { + STP_BTM_PR_ERR("osal_thread_destroy FAILS\n"); + return STP_BTM_OPERATION_FAIL; + } + + return STP_BTM_OPERATION_SUCCESS; +} + + +INT32 stp_btm_reset_btm_wq(MTKSTP_BTM_T *stp_btm) +{ + UINT32 i = 0; + + osal_lock_unsleepable_lock(&(stp_btm->wq_spinlock)); + RB_INIT(&stp_btm->rFreeOpQ, STP_BTM_OP_BUF_SIZE); + RB_INIT(&stp_btm->rActiveOpQ, STP_BTM_OP_BUF_SIZE); + osal_unlock_unsleepable_lock(&(stp_btm->wq_spinlock)); + /* Put all to free Q */ + for (i = 0; i < STP_BTM_OP_BUF_SIZE; i++) { + osal_signal_init(&(stp_btm->arQue[i].signal)); + _stp_btm_put_op(stp_btm, &stp_btm->rFreeOpQ, &(stp_btm->arQue[i])); + } + + return 0; +} + + +INT32 stp_notify_btm_dump(MTKSTP_BTM_T *stp_btm) +{ + /* pr_warn("%s:enter++\n",__func__); */ + if (stp_btm == NULL) { + osal_dbg_print("%s: NULL POINTER\n", __func__); + return -1; + } + stp_btm->gDumplogflag = 1; + osal_trigger_event(&stp_btm->STPd_event); + return 0; +} + +static inline INT32 _stp_btm_do_fw_assert(MTKSTP_BTM_T *stp_btm) +{ + INT32 status = -1; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + + /* send assert command */ + STP_BTM_PR_INFO("trigger stp assert process\n"); + if (mtk_wcn_stp_is_sdio_mode()) { + bRet = stp_btm->wmt_notify(BTM_TRIGGER_STP_ASSERT_OP); + if (bRet == MTK_WCN_BOOL_FALSE) { + STP_BTM_PR_INFO("trigger stp assert failed\n"); + return status; + } + status = 0; + } else if (mtk_wcn_stp_is_btif_fullset_mode()) { +#if BTIF_RXD_BE_BLOCKED_DETECT + stp_dbg_is_btif_rxd_be_blocked(); +#endif + status = wmt_plat_force_trigger_assert(STP_FORCE_TRG_ASSERT_DEBUG_PIN); + } + + stp_btm_start_trigger_assert_timer(stp_btm); + + if (status == 0) + STP_BTM_PR_INFO("trigger stp assert succeed\n"); + + return status; +} + + +INT32 stp_notify_btm_do_fw_assert(MTKSTP_BTM_T *stp_btm) +{ + return _stp_btm_do_fw_assert(stp_btm); +} + +INT32 wmt_btm_trigger_reset(VOID) +{ + return stp_btm_notify_wmt_rst_wq(stp_btm); +} + +INT32 stp_btm_set_current_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP pOp) +{ + if (stp_btm) { + stp_btm->pCurOP = pOp; + STP_BTM_PR_DBG("pOp=0x%p\n", pOp); + return 0; + } + STP_BTM_PR_ERR("Invalid pointer\n"); + return -1; +} + +P_OSAL_OP stp_btm_get_current_op(MTKSTP_BTM_T *stp_btm) +{ + if (stp_btm) + return stp_btm->pCurOP; + STP_BTM_PR_ERR("Invalid pointer\n"); + return NULL; +} + +INT32 stp_btm_init_trigger_assert_timer(MTKSTP_BTM_T *stp_btm) +{ + stp_btm->trigger_assert_timer.timeoutHandler = stp_btm_trigger_assert_timeout_handler; + stp_btm->trigger_assert_timer.timeroutHandlerData = (ULONG)stp_btm; + stp_btm->timeout = 1000; + + return osal_timer_create(&stp_btm->trigger_assert_timer); +} + +INT32 stp_btm_start_trigger_assert_timer(MTKSTP_BTM_T *stp_btm) +{ + return osal_timer_start(&stp_btm->trigger_assert_timer, stp_btm->timeout); +} + +INT32 stp_btm_stop_trigger_assert_timer(MTKSTP_BTM_T *stp_btm) +{ + return osal_timer_stop(&stp_btm->trigger_assert_timer); +} + +VOID stp_btm_print_op_history(VOID) +{ + osal_op_history_print(&stp_btm->op_history, "_stp_btm_proc"); +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/btm_core.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/btm_core.h new file mode 100644 index 00000000000000..2b79f269485318 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/btm_core.h @@ -0,0 +1,154 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + + +#ifndef _BTM_CORE_H +#define _BTM_CORE_H + +#include "osal_typedef.h" +#include "osal.h" +#include "stp_wmt.h" +#include "wmt_plat.h" +#include "wmt_idc.h" +#include "osal.h" +#include "mtk_btif_exp.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define STP_BTM_OPERATION_FAIL (-1) +#define STP_BTM_OPERATION_SUCCESS (0) + +#define STP_BTM_OP_BUF_SIZE (64) + +#define BTM_THREAD_NAME "mtk_stp_btm" +#define STP_PAGED_DUMP_TIME_LIMIT 3500 +#define STP_FULL_DUMP_TIME 3 +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_STP_BTM_OPID_T { + STP_OPID_BTM_RETRY = 0x0, + STP_OPID_BTM_RST = 0x1, + STP_OPID_BTM_DBG_DUMP = 0x2, + STP_OPID_BTM_DUMP_TIMEOUT = 0x3, + STP_OPID_BTM_POLL_CPUPCR = 0x4, + STP_OPID_BTM_PAGED_DUMP = 0x5, + STP_OPID_BTM_FULL_DUMP = 0x6, + STP_OPID_BTM_PAGED_TRACE = 0x7, + STP_OPID_BTM_FORCE_FW_ASSERT = 0x8, +#if CFG_WMT_LTE_COEX_HANDLING + STP_OPID_BTM_WMT_LTE_COEX = 0x9, +#endif + STP_OPID_BTM_ASSERT_TIMEOUT = 0xa, + STP_OPID_BTM_EMI_DUMP_END = 0xb, + STP_OPID_BTM_EXIT, + STP_OPID_BTM_NUM +} ENUM_STP_BTM_OPID_T, *P_ENUM_STP_BTM_OPID_T; + +typedef OSAL_OP_DAT STP_BTM_OP; +typedef P_OSAL_OP_DAT P_STP_BTM_OP; + +typedef struct mtk_stp_btm { + OSAL_THREAD BTMd; /* main thread (wmtd) handle */ + OSAL_EVENT STPd_event; + OSAL_UNSLEEPABLE_LOCK wq_spinlock; + + OSAL_OP_Q rFreeOpQ; /* free op queue */ + OSAL_OP_Q rActiveOpQ; /* active op queue */ + OSAL_OP arQue[STP_BTM_OP_BUF_SIZE]; /* real op instances */ + P_OSAL_OP pCurOP; /* current op */ + INT32 gDumplogflag; + + /*wmt_notify */ + INT32 (*wmt_notify)(MTKSTP_BTM_WMT_OP_T); + + OSAL_TIMER trigger_assert_timer; + UINT32 timeout; + struct osal_op_history op_history; +} MTKSTP_BTM_T; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +INT32 stp_btm_notify_wmt_rst_wq(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_notify_stp_retry_wq(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_notify_coredump_timeout_wq(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_notify_assert_timeout_wq(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_notify_wmt_dmp_wq(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_notify_emi_dump_end(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_deinit(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_reset_btm_wq(MTKSTP_BTM_T *stp_btm); +INT32 stp_notify_btm_poll_cpupcr(MTKSTP_BTM_T *stp_btm, UINT32 times, UINT32 sleep); +INT32 stp_notify_btm_poll_cpupcr_ctrl(UINT32 en); +INT32 stp_btm_sort_btm_wq(MTKSTP_BTM_T *stp_btm); +INT32 stp_notify_btm_dump(MTKSTP_BTM_T *stp_btm); +INT32 stp_notify_btm_do_fw_assert(MTKSTP_BTM_T *stp_btm); +INT32 stp_notify_btm_handle_wmt_lte_coex(MTKSTP_BTM_T *stp_btm); +INT32 wcn_psm_flag_trigger_collect_ftrace(void); +#if BTIF_RXD_BE_BLOCKED_DETECT +INT32 wcn_btif_rxd_blocked_collect_ftrace(void); +MTK_WCN_BOOL is_btif_rxd_be_blocked(void); +#endif + +INT32 wmt_btm_trigger_reset(VOID); +INT32 stp_btm_init_trigger_assert_timer(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_start_trigger_assert_timer(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_stop_trigger_assert_timer(MTKSTP_BTM_T *stp_btm); +INT32 stp_btm_set_current_op(MTKSTP_BTM_T *stp_btm, P_OSAL_OP pOp); +P_OSAL_OP stp_btm_get_current_op(MTKSTP_BTM_T *stp_btm); + +MTKSTP_BTM_T *stp_btm_init(VOID); +extern unsigned int chip_reset_only; + +VOID stp_btm_print_op_history(VOID); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/dbg_core.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/dbg_core.h new file mode 100644 index 00000000000000..d57740edfeae69 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/dbg_core.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + + +#ifndef _DBG_CORE_H +#define _DBG_CORE_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/psm_core.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/psm_core.h new file mode 100644 index 00000000000000..393d0f41227dd9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/psm_core.h @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + + +#ifndef _PSM_CORE_H +#define _PSM_CORE_H + +#include "osal_typedef.h" +#include "stp_wmt.h" +#include "osal.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define PFX_PSM "[STP-PSM] " +#define STP_PSM_LOG_LOUD 4 +#define STP_PSM_LOG_DBG 3 +#define STP_PSM_LOG_INFO 2 +#define STP_PSM_LOG_WARN 1 +#define STP_PSM_LOG_ERR 0 + +#define ASSERT(expr) +#define STP_PSM_FIFO_SIZE 0x2000 /* 8kbytes */ +#define STP_PSM_TX_SIZE 0x800 /* 2kbytes */ + +#define STP_PSM_OPERATION_FAIL (-1) +#define STP_PSM_OPERATION_SUCCESS (0) + +#define STP_PSM_PACKET_SIZE_MAX (2000) +#if (WMT_UART_RX_MODE_WORK || WMT_SDIO_MODE) +#define CFG_PSM_CORE_FIFO_SPIN_LOCK 0 +#else +#define CFG_PSM_CORE_FIFO_SPIN_LOCK 1 +#endif + + +#define PSM_HANDLING 127 + +#define STP_PSM_WMT_PS_TASK_HANDLING_TIME 30 /* 20 milli-seconds */ +#define STP_PSM_IDLE_TIME_SLEEP 30 /* temporary for stress testing */ +#define STP_PSM_IDLE_TIME_SLEEP_1000 1000 /* for high speed transmission e.g. BT OPP*/ +#define STP_PSM_SDIO_IDLE_TIME_SLEEP 100 /* temporary for SDIO stress testing */ +#define STP_PSM_WAIT_EVENT_TIMEOUT 18500 /* set same as MAX_FUNC_ON_TIME */ + +#if 0 +#define STP_PSM_WMT_EVENT_SLEEP_EN (0x1UL << 0) +#define STP_PSM_WMT_EVENT_WAKEUP_EN (0x1UL << 1) +#define STP_PSM_BLOCK_DATA_EN (0x1UL << 2) +#define STP_PSM_WMT_EVENT_DISABLE_MONITOR (0x1UL << 3) +#define STP_PSM_WMT_EVENT_ROLL_BACK_EN (0x1UL << 4) +#define STP_PSM_RESET_EN (0x1UL << 5) +#define STP_PSM_WMT_EVENT_HOST_WAKEUP_EN (0x1UL << 6) +#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY (0x1UL << 7) +#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY (0x1UL << 8) +#endif + +#define STP_PSM_WMT_EVENT_SLEEP_EN (0) +#define STP_PSM_WMT_EVENT_WAKEUP_EN (1) +#define STP_PSM_BLOCK_DATA_EN (2) +#define STP_PSM_WMT_EVENT_DISABLE_MONITOR (3) +#define STP_PSM_WMT_EVENT_ROLL_BACK_EN (4) +#define STP_PSM_RESET_EN (5) +#define STP_PSM_WMT_EVENT_HOST_WAKEUP_EN (6) +#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY (7) +#define STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY (8) + +#define STP_PSM_DBG_SIZE (48) + +/* OP command ring buffer : must be power of 2 */ +#define STP_OP_BUF_SIZE (16) + +#define PSM_THREAD_NAME "mtk_stp_psm" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum { + ACT = 0, + ACT_INACT = 1, + INACT = 2, + INACT_ACT = 3, + STP_PSM_MAX_STATE = 4, +} MTKSTP_PSM_STATE_T; + +typedef enum _ENUM_STP_OPID_T { + STP_OPID_PSM_SLEEP = 0, + STP_OPID_PSM_WAKEUP, + STP_OPID_PSM_HOST_AWAKE, + STP_OPID_PSM_EXIT, + STP_OPID_PSM_NUM, + STP_OPID_PSM_INALID = STP_OPID_PSM_NUM, +} ENUM_STP_OPID_T, *P_ENUM_STP_OPID_T; + +typedef enum { + MON = 0, + UNMON, +} MTKSTP_PSM_MONSTATE_T; + +typedef INT32(*wmt_notify_t) (MTKSTP_PSM_ACTION_T action); +typedef INT32(*stp_tx_cb_t) (PUINT8 buffer, UINT32 length, UINT8 type); + +typedef OSAL_OP_DAT STP_OP; +typedef P_OSAL_OP_DAT P_STP_OP; +#if 0 +#if CFG_PSM_CORE_FIFO_SPIN_LOCK +typedef OSAL_UNSLEEPABLE_LOCK PSM_FIFO_LOCK, *PPSM_FIFO_LOCK; +#else +typedef OSAL_SLEEPABLE_LOCK PSM_FIFO_LOCK, *PPSM_FIFO_LOCK; +#endif +#endif +typedef struct mtk_stp_psm { + OSAL_THREAD PSMd; /* main thread (wmtd) handle */ + OSAL_EVENT STPd_event; + + OSAL_OP_Q rFreeOpQ; /* free op queue */ + OSAL_OP_Q rActiveOpQ; /* active op queue */ + OSAL_OP arQue[STP_OP_BUF_SIZE]; /* real op instances */ + + /* OSAL_OP current_active_op; */ + /* P_OSAL_OP current_active_op; */ + UINT32 last_active_opId; + MTKSTP_PSM_STATE_T work_state; /*working state */ + OSAL_BIT_OP_VAR flag; + + /* in normal cases, sleep op is always enabled; but in error cases, we can't execute sleep cmd, + * Eg: FW assert, core dump + */ + INT32 sleep_en; + +/* OSAL_UNSLEEPABLE_LOCK flagSpinlock; */ + INT32 idle_time_to_sleep; + OSAL_WAKE_LOCK wake_lock; + OSAL_TIMER psm_timer; /*monitor if active */ + OSAL_EVENT wait_wmt_q; + OSAL_FIFO hold_fifo; + + /* PSM_FIFO_LOCK hold_fifo_lock; */ + OSAL_SLEEPABLE_LOCK hold_fifo_spinlock_global; + + OSAL_UNSLEEPABLE_LOCK wq_spinlock; + OSAL_SLEEPABLE_LOCK user_lock; + OSAL_SLEEPABLE_LOCK stp_psm_lock; + INT32 (*wmt_notify)(MTKSTP_PSM_ACTION_T action); + INT32 (*stp_tx_cb)(PUINT8 buffer, UINT32 length, UINT8 type); + MTK_WCN_BOOL (*is_wmt_quick_ps_support)(VOID); + INT32 (*update_wmt_fw_patch_chip_rst)(VOID); + UINT8 out_buf[STP_PSM_TX_SIZE]; + struct osal_op_history op_history; +} MTKSTP_PSM_T; + +typedef struct { + UINT32 prev_flag; + UINT32 cur_flag; + UINT32 line_num; + UINT32 package_no; + UINT32 sec; + UINT32 usec; + UINT32 pid; + UINT64 l_sec; + ULONG l_nsec; +} STP_PSM_ENTRY_T; + +typedef struct stp_psm_record { + STP_PSM_ENTRY_T queue[STP_PSM_DBG_SIZE]; + UINT32 in; + UINT32 out; + UINT32 size; + OSAL_UNSLEEPABLE_LOCK lock; +} STP_PSM_RECORD_T; + +typedef struct stp_psm_opid_record { + STP_PSM_ENTRY_T queue[STP_PSM_DBG_SIZE]; + UINT32 in; + UINT32 out; + UINT32 size; + OSAL_UNSLEEPABLE_LOCK lock; +} STP_PSM_OPID_RECORD, *P_STP_PSM_OPID_RECORD; +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#define PSM_USE_COUNT_PACKAGE 0 + +#if PSM_USE_COUNT_PACKAGE +#define MTK_COMBO_PSM_RX_TH_DEFAULT (1600) +#define MTK_COMBO_PSM_TX_TH_DEFAULT (300) +INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir); +#else +#define SAMPLE_DURATION 1 /*1 second */ +#define RTX_SPEED_THRESHOLD 50000 /*50KB/s */ +INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir, INT32 length); +#endif + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*stp-psm external function*/ +INT32 stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action); +INT32 stp_psm_notify_wmt_wakeup(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_notify_wmt_sleep(MTKSTP_PSM_T *stp_psm); + +INT32 stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_is_disable(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_release_data(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, + const PUINT8 buffer, const UINT32 len, const UINT8 type); +INT32 stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_reset(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_disable(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep); +struct mtk_stp_psm *stp_psm_init(void); +INT32 stp_psm_deinit(MTKSTP_PSM_T *stp_psm); +MTK_WCN_BOOL mtk_wcn_stp_psm_dbg_level(INT32 dbglevel); +INT32 stp_psm_sleep_for_thermal(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_set_state(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state); +MTK_WCN_BOOL stp_psm_is_quick_ps_support(VOID); + +INT32 stp_psm_set_sleep_enable(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_set_sleep_disable(MTKSTP_PSM_T *stp_psm); +INT32 stp_psm_check_sleep_enable(MTKSTP_PSM_T *stp_psm); + +VOID stp_psm_print_op_history(VOID); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/stp_core.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/stp_core.h new file mode 100644 index 00000000000000..af09d9517597f0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/stp_core.h @@ -0,0 +1,693 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + +#ifndef _STP_CORE_H +#define _STP_CORE_H +//#include "osal_typedef.h" +//#include "osal.h" +#include "wmt_stp_exp.h" +#include "stp_exp.h" +#include "psm_core.h" +#include "btm_core.h" +#include "stp_btif.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define WMT_LTE_COEX_FLAG (0x16) +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define CONFIG_POWER_SAVING_SUPPORT +#if (WMT_UART_RX_MODE_WORK || WMT_SDIO_MODE) +#define CFG_STP_CORE_CTX_SPIN_LOCK 0 +#else +#define CFG_STP_CORE_CTX_SPIN_LOCK 1 +#endif + + + +#define PFX "[STP] " +#define STP_LOG_DBG 4 +#define STP_LOG_PKHEAD 3 +#define STP_LOG_INFO 2 +#define STP_LOG_WARN 1 +#define STP_LOG_ERR 0 + +extern INT32 gStpDbgLvl; + +#define STP_DBG_FUNC(fmt, arg...) do {\ + if (gStpDbgLvl >= STP_LOG_DBG)\ + osal_warn_print(PFX "%s: " fmt, __func__, ##arg);\ +} while (0) + +#define STP_INFO_FUNC(fmt, arg...) do {\ + if (gStpDbgLvl >= STP_LOG_INFO)\ + osal_warn_print(PFX "%s:[I] " fmt, __func__, ##arg);\ +} while (0) + +#define STP_WARN_RATELIMITED_FUNC(fmt, arg...) do {\ + static DEFINE_RATELIMIT_STATE(_rs, HZ, 5);\ + if (gStpDbgLvl >= STP_LOG_WARN && __ratelimit(&_rs))\ + osal_warn_print(PFX "%s:[W] " fmt, __func__, ##arg);\ +} while (0) + +#define STP_WARN_FUNC(fmt, arg...) do {\ + if (gStpDbgLvl >= STP_LOG_WARN)\ + osal_warn_print(PFX "%s:[W] " fmt, __func__, ##arg);\ +} while (0) + +#define STP_ERR_FUNC(fmt, arg...) do {\ + if (gStpDbgLvl >= STP_LOG_ERR)\ + osal_err_print(PFX "%s:[E] " fmt, __func__, ##arg);\ +} while (0) + +#define STP_TRC_FUNC(f) do {\ + if (gStpDbgLvl >= STP_LOG_DBG)\ + osal_warn_print(PFX "<%s> <%d>\n", __func__, __LINE__);\ +} while (0) + +#define STP_DUMP_PACKET_HEAD(a, b, c) do {\ + if (gStpDbgLvl >= STP_LOG_PKHEAD)\ + stp_dump_data(a, b, c);\ +} while (0) + +#define STP_TRACE_FUNC(fmt, arg...) do {\ + if (gStpDbgLvl >= STP_LOG_DBG)\ + osal_warn_print(PFX "%s: " fmt, __func__, ##arg);\ +} while (0) + +#define STP_MODE_BIT(x) (0x1UL << x) +#define MTKSTP_UART_FULL_MODE STP_MODE_BIT(0) +#define MTKSTP_UART_MAND_MODE STP_MODE_BIT(1) +#define MTKSTP_BTIF_FULL_MODE STP_MODE_BIT(2) +#define MTKSTP_BTIF_MAND_MODE STP_MODE_BIT(3) +#define MTKSTP_SDIO_MODE STP_MODE_BIT(4) + +#define MTKSTP_BUFFER_SIZE (16384) +#define PARSER_CORE_DUMP_NUM 200 +#define CORE_DUMP_NUM 100 +/*To check function driver's status by the the interface*/ +/*Operation definition*/ +#define OP_FUNCTION_ACTIVE 0 + +/*Driver's status*/ +#define STATUS_OP_INVALID 0 +#define STATUS_FUNCTION_INVALID 1 + +#define STATUS_FUNCTION_ACTIVE 31 +#define STATUS_FUNCTION_INACTIVE 32 + +#define MTKSTP_CRC_SIZE (2) +#define MTKSTP_HEADER_SIZE (4) +#define MTKSTP_SEQ_SIZE (8) + +/*#define MTKSTP_WINSIZE (4)*/ +#define MTKSTP_WINSIZE (7) +#define MTKSTP_TX_TIMEOUT (180) /*TODO: Baudrate to decide this */ +#define MTKSTP_RETRY_LIMIT (10) + +#define INDEX_INC(idx) \ +{ \ + idx++; \ + idx &= 0x7; \ +} + +#define INDEX_DEC(idx) \ +{ \ + idx--; \ + idx &= 0x7; \ +} + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef INT32(*IF_TX) (const PUINT8 data, const UINT32 size, PUINT32 written_size); +typedef INT32(*RX_HAS_PENDING_DATA) (VOID); +typedef INT32(*TX_HAS_PENDING_DATA) (VOID); +typedef P_OSAL_THREAD(*RX_THREAD_GET) (VOID); +/* event/signal */ +typedef INT32(*EVENT_SET) (UINT8 function_type); +typedef INT32(*EVENT_TX_RESUME) (UINT8 winspace); +typedef INT32(*FUNCTION_STATUS) (UINT8 type, UINT8 op); +typedef INT32(*WMT_NOTIFY_FUNC_T) (UINT32 action); +typedef INT32(*BTM_NOTIFY_WMT_FUNC_T) (INT32); + +#if CFG_STP_CORE_CTX_SPIN_LOCK +typedef OSAL_UNSLEEPABLE_LOCK STP_CTX_LOCK, *PSTP_CTX_LOCK; +#else +typedef OSAL_SLEEPABLE_LOCK STP_CTX_LOCK, *PSTP_CTX_LOCK; +#endif + +typedef struct { + /* common interface */ + IF_TX cb_if_tx; + RX_HAS_PENDING_DATA cb_rx_has_pending_data; + TX_HAS_PENDING_DATA cb_tx_has_pending_data; + RX_THREAD_GET cb_rx_thread_get; + /* event/signal */ + EVENT_SET cb_event_set; + EVENT_TX_RESUME cb_event_tx_resume; + FUNCTION_STATUS cb_check_funciton_status; +} mtkstp_callback; + +typedef enum { + MTKSTP_SYNC = 0, + MTKSTP_SEQ, + MTKSTP_ACK, + MTKSTP_NAK, + MTKSTP_TYPE, + MTKSTP_LENGTH, + MTKSTP_CHECKSUM, + MTKSTP_DATA, + MTKSTP_CRC1, + MTKSTP_CRC2, + MTKSTP_RESYNC1, + MTKSTP_RESYNC2, + MTKSTP_RESYNC3, + MTKSTP_RESYNC4, + MTKSTP_FW_MSG, +} mtkstp_parser_state; + +typedef struct { + mtkstp_parser_state state; + UINT8 seq; + UINT8 ack; + UINT8 nak; + UINT8 type; + UINT16 length; + UINT8 checksum; + UINT16 crc; +} mtkstp_parser_context_struct; + +typedef struct { + UINT8 txseq; /* last tx pkt's seq + 1 */ + UINT8 txack; /* last tx pkt's ack */ + UINT8 rxack; /* last rx pkt's ack */ + UINT8 winspace; /* current sliding window size */ + UINT8 expected_rxseq; /* last rx pkt's seq + 1 */ + UINT8 retry_times; + UINT8 tx_timeout_loop; /* for extend tx timeout */ + UINT8 rx_resync; /* num of 7f7f7f7f before expected_rxseq pkt, indicates if recv series of resync pkt */ + UINT8 rx_resync_seq; /* last resync pkg's seq (0xFF if not set), only valid if rx_resync != 0 */ +} mtkstp_sequence_context_struct; + +typedef struct { + /* MTK_WCN_MUTEX mtx; */ + OSAL_UNSLEEPABLE_LOCK mtx; + UINT8 buffer[MTKSTP_BUFFER_SIZE]; + UINT32 read_p; + UINT32 write_p; +} mtkstp_ring_buffer_struct; + +typedef struct { + UINT8 inband_rst_set; + UINT32 assert_info_cnt; + UINT32 rx_counter; /* size of current processing pkt in rx_buf[] */ + UINT8 rx_buf[MTKSTP_BUFFER_SIZE]; /* input buffer of STP, room for current processing pkt */ + UINT32 tx_read; /* read ptr of tx_buf[] */ + UINT32 tx_write; /* write ptr of tx_buf[] */ + UINT8 tx_buf[MTKSTP_BUFFER_SIZE]; /* output buffer of STP */ + UINT32 tx_start_addr[MTKSTP_SEQ_SIZE]; /* ptr of each pkt in tx_buf[] */ + UINT32 tx_length[MTKSTP_SEQ_SIZE]; /* length of each pkt in tx_buf[] */ + mtkstp_ring_buffer_struct ring[MTKSTP_MAX_TASK_NUM]; /* ring buffers for each function driver */ + mtkstp_parser_context_struct parser; /* current rx pkt's content */ + mtkstp_sequence_context_struct sequence; /* state machine's current status */ + /* MTK_WCN_MUTEX stp_mutex; */ +#if CFG_STP_CORE_CTX_SPIN_LOCK + OSAL_UNSLEEPABLE_LOCK stp_mutex; +#else + OSAL_SLEEPABLE_LOCK stp_mutex; +#endif + /* MTK_WCN_TIMER tx_timer; // timer for tx timeout handling */ + OSAL_TIMER tx_timer; + + MTKSTP_PSM_T *psm; + MTKSTP_BTM_T *btm; + UINT8 f_enable; /* default disabled */ + UINT8 f_ready; /* default non-ready */ + UINT8 f_pending_type; + UINT8 f_coredump; /*block tx flag, for now, only when f/w assert happens, we will set this bit on */ + UINT8 en_coredump; + UINT8 f_emidump; + /* Flag to identify Blueztooth is Bluez/or MTK Stack */ + MTK_WCN_BOOL f_bluez; + MTK_WCN_BOOL f_dbg_en; + MTK_WCN_BOOL f_autorst_en; + + + + /* Flag to identify STP by SDIO or UART */ + UINT32 f_mode; + + /* Flag to indicate the last WMT CLOSE */ + UINT32 f_wmt_last_close; + /* Flag to indicate evt err has triggered assert or not */ + UINT32 f_evt_err_assert; + /* Flag to indicate assert process is ongoing or not */ + UINT32 f_assert_in_progress; +} mtkstp_context_struct; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +INT32 stp_send_data_no_ps(PUINT8 buffer, UINT32 length, UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_init +* DESCRIPTION +* init STP kernel +* PARAMETERS +* cb_func [IN] function pointers of system APIs +* RETURNS +* INT32 0 = success, others = failure +*****************************************************************************/ +extern INT32 mtk_wcn_stp_init(const mtkstp_callback * const cb_func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_deinit +* DESCRIPTION +* deinit STP kernel +* PARAMETERS +* void +* RETURNS +* INT32 0 = success, others = failure +*****************************************************************************/ +extern INT32 mtk_wcn_stp_deinit(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_enable +* DESCRIPTION +* enable/disable STP +* PARAMETERS +* value [IN] 0 = disable, others = enable +* RETURNS +* INT32 0 = success, others = error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_enable(INT32 value); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_enable +* DESCRIPTION +* get STP enable/disable status +* PARAMETERS +* none. +* RETURNS +* INT32 0 = disable, 1 = enable +*****************************************************************************/ +extern INT32 mtk_wcn_stp_is_enable(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_ready +* DESCRIPTION +* ready/non-ready STP +* PARAMETERS +* value [IN] 0 = non-ready, others = ready +* RETURNS +* INT32 0 = success, others = error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_ready(INT32 value); + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_coredump_start_ctrl +* DESCRIPTION +* set f/w assert flag in STP context +* PARAMETERS +* value [IN] 0=assert end, others=assert begins +* RETURNS +* INT32 0=success, others=error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_coredump_start_ctrl(UINT32 value); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_coredump_start_get +* DESCRIPTION +* get f/w assert flag in STP context +* PARAMETERS +* VOID +* RETURNS +* INT32 0= f/w assert flag is not set, others=f/w assert flag is set +*****************************************************************************/ +extern INT32 mtk_wcn_stp_coredump_start_get(VOID); + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_send_data_raw +* DESCRIPTION +* send raw data to common interface, bypass STP +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] subfunction type +* RETURNS +* INT32 length transmitted +*****************************************************************************/ +extern INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_set_sdio_mode +* DESCRIPTION +* Set stp for SDIO mode +* PARAMETERS +* sdio_flag [IN] sdio mode flag (TRUE:SDIO mode, FALSE:UART mode) +* RETURNS +* void +*****************************************************************************/ +extern VOID mtk_wcn_stp_set_mode(UINT32 sdio_flag); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_uart_fullset_mode +* DESCRIPTION +* Is stp use UART Fullset mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:UART Fullset, FALSE:UART Fullset +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_uart_fullset_mode(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_uart_mand_mode +* DESCRIPTION +* Is stp use UART Mandatory mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:UART Mandatory, FALSE:UART Mandatory +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_uart_mand_mode(VOID); + +extern MTK_WCN_BOOL mtk_wcn_stp_is_uart_mand_mode(VOID); +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_btif_fullset_mode +* DESCRIPTION +* Is stp use BTIF Fullset mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:BTIF Fullset, FALSE:BTIF Fullset +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_btif_fullset_mode(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_btif_mand_mode +* DESCRIPTION +* Is stp use BTIF Mandatory mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:BTIF Mandatory, FALSE:BTIF Mandatory +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_btif_mand_mode(void); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_sdio_mode +* DESCRIPTION +* Is stp use SDIO mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:SDIO mode, FALSE:UART mode +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_sdio_mode(VOID); + + +/***************************************************************************** +* FUNCTION +* stp_send_inband_reset +* DESCRIPTION +* To sync to oringnal stp state with f/w stp +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +extern VOID mtk_wcn_stp_inband_reset(VOID); + +/***************************************************************************** +* FUNCTION +* stp_send_inband_reset +* DESCRIPTION +* To send testing command to chip +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +extern VOID mtk_wcn_stp_test_cmd(INT32 no); + +/***************************************************************************** +* FUNCTION +* stp_send_inband_reset +* DESCRIPTION +* To control STP debugging mechanism +* PARAMETERS +* func_no: function control, func_op: dumpping filer, func_param: dumpping parameter +* RETURNS +* none +*****************************************************************************/ +extern VOID mtk_wcn_stp_debug_ctrl(INT32 func_no, INT32 func_op, INT32 func_param); +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_flush +* DESCRIPTION +* flush all stp context +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +extern VOID mtk_wcn_stp_flush_context(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_rx_queue +* DESCRIPTION +* flush all stp rx queue +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +extern VOID mtk_wcn_stp_flush_rx_queue(UINT32 type); + +/***************************************************************************** +* FUNCTION +* set stp debugging mdoe +* DESCRIPTION +* set stp debugging mdoe +* PARAMETERS +* dbg_mode: switch to dbg mode ? +* RETURNS +* void +*****************************************************************************/ +extern VOID mtk_wcn_stp_set_dbg_mode(MTK_WCN_BOOL dbg_mode); + +/***************************************************************************** +* FUNCTION +* set stp auto reset mdoe +* DESCRIPTION +* set stp auto reset mdoe +* PARAMETERS +* auto_rst: switch to auto reset mode ? +* RETURNS +* void +*****************************************************************************/ +extern VOID mtk_wcn_stp_set_auto_rst(MTK_WCN_BOOL auto_rst); + +/*stp_psm support*/ + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_notify_stp +* DESCRIPTION +* WMT notification to STP that power saving job is done or not +* PARAMETERS +* +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_psm_notify_stp(const MTKSTP_PSM_ACTION_T action); + +extern INT32 mtk_wcn_stp_set_psm_state(MTKSTP_PSM_STATE_T state); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_enabla +* DESCRIPTION +* enable STP PSM +* PARAMETERS +* int idle_time_to_sleep: IDLE time to sleep +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_psm_enable(INT32 idle_time_to_sleep); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_disable +* DESCRIPTION +* disable STP PSM +* PARAMETERS +* void +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_psm_disable(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_reset +* DESCRIPTION +* reset STP PSM (used on whole chip reset) +* PARAMETERS +* void +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_psm_reset(VOID); +extern VOID stp_do_tx_timeout(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_btm_get_dmp +* DESCRIPTION +* get stp dump related information +* PARAMETERS +* buffer: dump placement, len: dump size +* RETURNS +* 0: Success Negative Value: Fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_btm_get_dmp(PINT8 buf, PINT32 len); + +extern INT32 mtk_wcn_stp_dbg_enable(VOID); + +extern INT32 mtk_wcn_stp_dbg_disable(VOID); + +extern VOID mtk_wcn_stp_set_if_tx_type(ENUM_STP_TX_IF_TYPE stp_if_type); + +extern INT32 mtk_wcn_sys_if_rx(PUINT8 data, INT32 size); + +extern MTK_WCN_BOOL mtk_wcn_stp_dbg_level(INT32 dbglevel); + +extern INT32 mtk_wcn_stp_dbg_dump_package(VOID); + +extern INT32 stp_drv_init(VOID); + +extern VOID stp_drv_exit(VOID); + +extern INT32 mtk_wcn_stp_dbg_log_ctrl(UINT32 on); + +extern INT32 mtk_wcn_stp_coredump_flag_ctrl(UINT32 on); + +extern INT32 mtk_wcn_stp_coredump_flag_get(VOID); +extern INT32 mtk_wcn_stp_notify_sleep_for_thermal(VOID); +extern INT32 mtk_wcn_stp_emi_dump_flag_ctrl(UINT32 on); +extern INT32 mtk_wcn_stp_emi_dump_flag_get(VOID); + +extern INT32 mtk_wcn_stp_set_wmt_last_close(UINT32 value); +extern INT32 mtk_wcn_stp_is_wmt_last_close(VOID); + +/*stp btif API declared*/ +extern INT32 mtk_wcn_stp_open_btif(VOID); +extern INT32 mtk_wcn_stp_close_btif(VOID); +extern INT32 mtk_wcn_stp_rxcb_register(MTK_WCN_BTIF_RX_CB rx_cb); +extern INT32 mtk_wcn_stp_tx(UINT8 *pBuf, UINT32 len, UINT32 *written_len); +extern INT32 mtk_wcn_stp_wakeup_consys(VOID); +extern INT32 mtk_wcn_stp_dpidle_ctrl(enum _ENUM_BTIF_DPIDLE_ en_flag); +extern INT32 mtk_wcn_stp_lpbk_ctrl(enum _ENUM_BTIF_LPBK_MODE_ mode); +extern INT32 mtk_wcn_stp_logger_ctrl(enum _ENUM_BTIF_DBG_ID_ flag); +extern VOID mtk_wcn_stp_ctx_save(VOID); +extern VOID mtk_wcn_stp_ctx_restore(VOID); + +extern INT32 mtk_wcn_stp_wmt_trg_assert(VOID); +extern UINT32 mtk_wcn_stp_get_wmt_trg_assert(VOID); +extern VOID mtk_wcn_stp_set_wmt_trg_assert(UINT32 value); +extern INT32 mtk_wcn_stp_assert_timeout_handle(VOID); +extern INT32 mtk_wcn_stp_coredump_timeout_handle(VOID); +extern VOID mtk_wcn_stp_dbg_pkt_log(INT32 type, INT32 dir); + +extern INT32 mtk_wcn_sys_if_rx(UINT8 *data, INT32 size); + +/* + * API to get/set assert process is ongoing. + * It includes assert, coredump and chip reset process. + */ +extern VOID mtk_wcn_stp_assert_flow_ctrl(UINT32 on); +extern UINT32 mtk_wcn_stp_assert_flow_get(VOID); + +VOID mtk_stp_sdio_retry_flag_ctrl(INT32 flag); +VOID mtk_stp_dbg_sdio_retry_flag_ctrl(INT32 flag); +INT32 mtk_stp_sdio_retry_flag_get(VOID); +VOID mtk_stp_dump_sdio_register(VOID); +VOID mtk_stp_notify_emi_dump_end(VOID); +INT32 mtk_stp_check_rx_has_pending_data(VOID); +INT32 mtk_stp_dbg_dmp_append(PUINT8 buf, INT32 max_len); +P_OSAL_THREAD mtk_stp_rx_thread_get(VOID); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _STP_CORE_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/stp_wmt.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/stp_wmt.h new file mode 100644 index 00000000000000..63d237a058b228 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/stp_wmt.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + +#ifndef _STP_WMT_H +#define _STP_WMT_H + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum { + BTM_RST_OP = 0, + BTM_DMP_OP = 1, + BTM_GET_AEE_SUPPORT_FLAG = 2, + BTM_TRIGGER_STP_ASSERT_OP = 3, + BTM_MAX_OP, +} MTKSTP_BTM_WMT_OP_T; + +typedef enum { + SLEEP = 0, + HOST_AWAKE, + WAKEUP, + EIRQ, + ROLL_BACK, + STP_PSM_MAX_ACTION +} MTKSTP_PSM_ACTION_T; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +extern MTK_WCN_BOOL wmt_lib_btm_cb(MTKSTP_BTM_WMT_OP_T op); + +extern INT32 wmt_lib_ps_stp_cb(MTKSTP_PSM_ACTION_T action); +extern MTK_WCN_BOOL wmt_lib_is_quick_ps_support(VOID); + +extern INT32 wmt_lib_ps_set_idle_time(UINT32 psIdleTime); + +extern INT32 wmt_lib_update_fw_patch_chip_rst(VOID); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _STP_WMT_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_conf.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_conf.h new file mode 100644 index 00000000000000..99788d3d2c63ac --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_conf.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + +#ifndef _WMT_CONF_H_ +#define _WMT_CONF_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define CUST_CFG_WMT "WMT.cfg" +#define CUST_CFG_WMT_SOC "WMT_SOC.cfg" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 wmt_conf_read_file(VOID); +P_WMT_GEN_CONF wmt_conf_get_cfg(VOID); +INT32 wmt_conf_set_cfg_file(const PINT8 name); +INT32 wmt_conf_deinit(VOID); + +#endif /* _WMT_CONF_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_core.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_core.h new file mode 100644 index 00000000000000..31d083a8393bb8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_core.h @@ -0,0 +1,566 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + + +#ifndef _WMT_CORE_H_ +#define _WMT_CORE_H_ + +#include "wmt_plat.h" +#include "wmt_ctrl.h" +#include "wmt_exp.h" +//#include "wmt_stp_exp.h" +//#include "wmt_plat.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#if defined(MT6620E3) || defined(MT6620E6) /* need modify this part */ +#define CFG_CORE_MT6620_SUPPORT 1 /* whether MT6620 is supported or not */ +#else +#define CFG_CORE_MT6620_SUPPORT 1 /* whether MT6620 is supported or not */ +#endif + +#if defined(MT6628) +#define CFG_CORE_MT6628_SUPPORT 1 /* whether MT6628 is supported or not */ +#else +#define CFG_CORE_MT6628_SUPPORT 1 /* whether MT6628 is supported or not */ +#endif + +#if defined(MT6630) +#define CFG_CORE_MT6630_SUPPORT 1 /* whether MT6630 is supported or not */ +#else +#define CFG_CORE_MT6630_SUPPORT 1 /* whether MT6630 is supported or not */ +#endif + +#if defined(MT6632) +#define CFG_CORE_MT6632_SUPPORT 1 /* whether MT6632 is supported or not */ +#else +#define CFG_CORE_MT6632_SUPPORT 1 /* whether MT6632 is supported or not */ +#endif + +#define CFG_CORE_SOC_SUPPORT 1 +/* TODO:[ChangeFeature][George] move this definition outside so that wmt_dev can remove wmt_core.h inclusion. */ +#define defaultPatchName "mt66xx_patch_hdr.bin" + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define BCNT_PATCH_BUF_HEADROOM (8) + +#define BCNT_PATCH_BUF_CHECKSUM (2) + +#define DWCNT_HIF_CONF (4) +#define DWCNT_STRAP_CONF (4) +#define DWCNT_RESERVED (8) +#define DWCNT_CTRL_DATA (16) + + +#if 0 /* TODO: [obsolete][GeorgeKuo]: remove ubsolete definitions */ +#define WMT_SET (1) +#define WMT_QUERY (0) +#define WMT_PKT_FMT_RAW (1) +#define WMT_PKT_FMT_STP (0) +#endif + +#define WMT_FUNC_CTRL_ON (MTK_WCN_BOOL_TRUE) +#define WMT_FUNC_CTRL_OFF (MTK_WCN_BOOL_FALSE) + +#define WMT_HDR_LEN (4) /* header length */ +#define WMT_STS_LEN (1) /* status length */ +#define WMT_FLAG_LEN (1) +#define WMT_HIF_UART_INFO_LEN (4) +#define WMT_FUNC_CTRL_PARAM_LEN (1) +#define WMT_LPBK_CMD_LEN (5) +#define WMT_LPBK_BUF_LEN (1024+WMT_LPBK_CMD_LEN) +#define WMT_DEFAULT_BAUD_RATE (115200) + +#define INIT_CMD(c, e, s) {.cmd = c, .cmdSz = sizeof(c), .evt = e, .evtSz = sizeof(e), .str = s} + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef enum _ENUM_WMT_FM_T { + WMT_FM_INVALID = 0, + WMT_FM_I2C = 1, + WMT_FM_COMM = 2, + WMT_FM_MAX +} ENUM_WMT_FM_T, *P_ENUM_WMT_FM_T; + +typedef enum _ENUM_WMT_HIF_T { + WMT_HIF_UART = 0, + WMT_HIF_SDIO = 1, + WMT_HIF_BTIF = 2, + WMT_HIF_MAX +} ENUM_WMT_HIF_T, *P_ENUM_WMT_HIF_T; + +#if 0 /* [George] moved to wmt_exp.h for hif_sdio's use */ +typedef enum { + WMT_SDIO_SLOT_INVALID = 0, + WMT_SDIO_SLOT_SDIO1 = 1, /* Wi-Fi dedicated SDIO1 */ + WMT_SDIO_SLOT_SDIO2 = 2, + WMT_SDIO_SLOT_MAX +} WMT_SDIO_SLOT_NUM; + +typedef enum { + WMT_SDIO_FUNC_STP = 0, + WMT_SDIO_FUNC_WIFI = 1, + WMT_SDIO_FUNC_MAX +} WMT_SDIO_FUNC_TYPE; +#endif + +typedef enum _ENUM_WMT_OPID_T { + WMT_OPID_HIF_CONF = 0, + WMT_OPID_PWR_ON = 1, + WMT_OPID_PWR_OFF = 2, + WMT_OPID_FUNC_ON = 3, + WMT_OPID_FUNC_OFF = 4, + WMT_OPID_REG_RW = 5, /* TODO:[ChangeFeature][George] is this OP obsoleted? */ + WMT_OPID_EXIT = 6, + WMT_OPID_PWR_SV = 7, + WMT_OPID_DSNS = 8, + WMT_OPID_LPBK = 9, + WMT_OPID_CMD_TEST = 10, + WMT_OPID_HW_RST = 11, + WMT_OPID_SW_RST = 12, + WMT_OPID_BAUD_RST = 13, + WMT_OPID_STP_RST = 14, + WMT_OPID_THERM_CTRL = 15, + WMT_OPID_EFUSE_RW = 16, + WMT_OPID_GPIO_CTRL = 17, + WMT_OPID_SDIO_CTRL = 18, + WMT_OPID_FW_COREDMP = 19, + WMT_OPID_GPIO_STATE = 20, + WMT_OPID_BGW_DS = 21, + WMT_OPID_SET_MCU_CLK = 22, + WMT_OPID_ADIE_LPBK_TEST = 23, +#ifdef CONFIG_MTK_COMBO_ANT + WMT_OPID_ANT_RAM_DOWN = 24, + WMT_OPID_ANT_RAM_STA_GET = 25, +#endif +#if CFG_WMT_LTE_COEX_HANDLING + WMT_OPID_IDC_MSG_HANDLING = 26, +#endif + WMT_OPID_TRIGGER_STP_ASSERT = 27, + WMT_OPID_FLASH_PATCH_DOWN = 28, + WMT_OPID_FLASH_PATCH_VER_GET = 29, + WMT_OPID_UTC_TIME_SYNC = 30, + WMT_OPID_FW_LOG_CTRL = 31, + WMT_OPID_WLAN_PROBE = 32, + WMT_OPID_WLAN_REMOVE = 33, + WMT_OPID_GPS_MCU_CTRL = 34, + WMT_OPID_TRY_PWR_OFF = 35, + WMT_OPID_BLANK_STATUS_CTRL = 36, + WMT_OPID_MET_CTRL = 37, + WMT_OPID_GPS_SUSPEND = 38, + WMT_OPID_RESUME_DUMP_INFO = 39, + WMT_OPID_MAX +} ENUM_WMT_OPID_T, *P_ENUM_WMT_OPID_T; + +typedef OSAL_OP_DAT WMT_OP; +typedef P_OSAL_OP_DAT P_WMT_OP; + +typedef enum _ENUM_WMT_UART_FC_T { + WMT_UART_NO_FC = 0, + WMT_UART_MTK_SW_FC = 1, + WMT_UART_LUX_SW_FC = 2, + WMT_UART_HW_FC = 3, + WMT_UART_MAX +} ENUM_WMT_UART_FC_T, *P_ENUM_UART_FC_T; + + +typedef struct _WMT_HIF_CONF { + UINT32 hifType; /* HIF Type */ + UINT32 uartFcCtrl; /* UART FC config */ + UINT32 au4HifConf[DWCNT_HIF_CONF]; /* HIF Config */ + UINT32 au4StrapConf[DWCNT_STRAP_CONF]; /* Strap Config */ +} WMT_HIF_CONF, *P_WMT_HIF_CONF; + +typedef INT32(*WMT_OPID_FUNC) (P_WMT_OP); + +struct WMT_BYTE_ARRAY { + UINT32 size; + PUINT8 data; +}; + +typedef struct _WMT_GEN_CONF { + UINT8 cfgExist; + + UINT8 coex_wmt_ant_mode; + UINT8 coex_wmt_ant_mode_ex; + UINT8 coex_wmt_ext_component; + UINT8 coex_wmt_wifi_time_ctl; + UINT8 coex_wmt_ext_pta_dev_on; + /*combo chip and LTE coex filter mode setting */ + UINT8 coex_wmt_filter_mode; + + UINT8 coex_bt_rssi_upper_limit; + UINT8 coex_bt_rssi_mid_limit; + UINT8 coex_bt_rssi_lower_limit; + UINT8 coex_bt_pwr_high; + UINT8 coex_bt_pwr_mid; + UINT8 coex_bt_pwr_low; + + UINT8 coex_wifi_rssi_upper_limit; + UINT8 coex_wifi_rssi_mid_limit; + UINT8 coex_wifi_rssi_lower_limit; + UINT8 coex_wifi_pwr_high; + UINT8 coex_wifi_pwr_mid; + UINT8 coex_wifi_pwr_low; + + UINT8 coex_ext_pta_hi_tx_tag; + UINT8 coex_ext_pta_hi_rx_tag; + UINT8 coex_ext_pta_lo_tx_tag; + UINT8 coex_ext_pta_lo_rx_tag; + UINT16 coex_ext_pta_sample_t1; + UINT16 coex_ext_pta_sample_t2; + UINT8 coex_ext_pta_wifi_bt_con_trx; + + UINT32 coex_misc_ext_pta_on; + UINT32 coex_misc_ext_feature_set; + /*GPS LNA setting */ + UINT8 wmt_gps_lna_pin; + UINT8 wmt_gps_lna_enable; + /*GPS HW suspend setting */ + UINT8 wmt_gps_suspend_ctrl; + /*Power on sequence */ + UINT8 pwr_on_rtc_slot; + UINT8 pwr_on_ldo_slot; + UINT8 pwr_on_rst_slot; + UINT8 pwr_on_off_slot; + UINT8 pwr_on_on_slot; + UINT8 co_clock_flag; + + /*deep sleep feature flag*/ + UINT8 disable_deep_sleep_cfg; + + /* Combo chip side SDIO driving setting */ + UINT32 sdio_driving_cfg; + + /* Combo chip WiFi path setting */ + UINT16 coex_wmt_wifi_path; + /* Combo chip WiFi eLAN gain setting */ + UINT8 coex_wmt_ext_elna_gain_p1_support; + UINT32 coex_wmt_ext_elna_gain_p1_D0; + UINT32 coex_wmt_ext_elna_gain_p1_D1; + UINT32 coex_wmt_ext_elna_gain_p1_D2; + UINT32 coex_wmt_ext_elna_gain_p1_D3; + PINT8 coex_wmt_antsel_invert_support; + UINT8 coex_wmt_ext_epa_mode; + + struct WMT_BYTE_ARRAY *coex_wmt_epa_elna; + + UINT8 bt_tssi_from_wifi; + UINT16 bt_tssi_target; + + UINT8 coex_config_bt_ctrl; + UINT8 coex_config_bt_ctrl_mode; + UINT8 coex_config_bt_ctrl_rw; + + UINT8 coex_config_addjust_opp_time_ratio; + UINT8 coex_config_addjust_opp_time_ratio_bt_slot; + UINT8 coex_config_addjust_opp_time_ratio_wifi_slot; + + UINT8 coex_config_addjust_ble_scan_time_ratio; + UINT8 coex_config_addjust_ble_scan_time_ratio_bt_slot; + UINT8 coex_config_addjust_ble_scan_time_ratio_wifi_slot; + + /* wifi ant swap feature */ + UINT8 wifi_ant_swap_mode; + UINT8 wifi_main_ant_polarity; + UINT8 wifi_ant_swap_ant_sel_gpio; +} WMT_GEN_CONF, *P_WMT_GEN_CONF; + +typedef enum _ENUM_DRV_STS_ { +#if 0 + DRV_STS_INVALID = 0, + DRV_STS_UNREG = 1, /* Initial State */ +#endif + DRV_STS_POWER_OFF = 0, /* initial state */ + DRV_STS_POWER_ON = 1, /* powered on, only WMT */ + DRV_STS_FUNC_ON = 2, /* FUNC ON */ + DRV_STS_MAX +} ENUM_DRV_STS, *P_ENUM_DRV_STS; + +typedef enum _WMT_IC_PIN_ID_ { + WMT_IC_PIN_AUDIO = 0, + WMT_IC_PIN_EEDI = 1, + WMT_IC_PIN_EEDO = 2, + WMT_IC_PIN_GSYNC = 3, + WMT_IC_PIN_MAX +} WMT_IC_PIN_ID, *P_WMT_IC_PIN_ID; + + +typedef enum _WMT_IC_PIN_STATE_ { + WMT_IC_PIN_EN = 0, + WMT_IC_PIN_DIS = 1, + WMT_IC_AIF_0 = 2, /* = CMB_STUB_AIF_0, */ + WMT_IC_AIF_1 = 3, /* = CMB_STUB_AIF_1, */ + WMT_IC_AIF_2 = 4, /* = CMB_STUB_AIF_2, */ + WMT_IC_AIF_3 = 5, /* = CMB_STUB_AIF_3, */ + WMT_IC_PIN_MUX = 6, + WMT_IC_PIN_GPIO = 7, + WMT_IC_PIN_GPIO_HIGH = 8, + WMT_IC_PIN_GPIO_LOW = 9, + WMT_IC_PIN_STATE_MAX +} WMT_IC_PIN_STATE, *P_WMT_IC_PIN_STATE; + +typedef enum _WMT_CO_CLOCK_ { + WMT_CO_CLOCK_DIS = 0, + WMT_CO_CLOCK_EN = 1, + WMT_CO_CLOCK_DCXO = 2, + WMT_CO_CLOCK_MAX +} WMT_CO_CLOCK, *P_WMT_CO_CLOCK; + + +typedef INT32(*SW_INIT) (P_WMT_HIF_CONF pWmtHifConf); +typedef INT32(*SW_DEINIT) (P_WMT_HIF_CONF pWmtHifConf); +typedef INT32(*IC_PIN_CTRL) (WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag); +typedef INT32(*IC_VER_CHECK) (VOID); +typedef INT32(*CO_CLOCK_CTRL) (WMT_CO_CLOCK on); +typedef MTK_WCN_BOOL(*IS_QUICK_SLEEP_SUPPORT) (VOID); +typedef MTK_WCN_BOOL(*IS_AEE_DUMP_SUPPORT) (VOID); +typedef MTK_WCN_BOOL(*TRIGGER_STP_ASSERT) (VOID); +typedef MTK_WCN_BOOL(*DEEP_SLEEP_CONTROL) (INT32 value); + + +typedef struct _WMT_IC_OPS_ { + UINT32 icId; + SW_INIT sw_init; + SW_DEINIT sw_deinit; + IC_PIN_CTRL ic_pin_ctrl; + IC_VER_CHECK ic_ver_check; + CO_CLOCK_CTRL co_clock_ctrl; + IS_QUICK_SLEEP_SUPPORT is_quick_sleep; + IS_AEE_DUMP_SUPPORT is_aee_dump_support; + TRIGGER_STP_ASSERT trigger_stp_assert; + DEEP_SLEEP_CONTROL deep_sleep_ctrl; +} WMT_IC_OPS, *P_WMT_IC_OPS; + +typedef struct _WMT_CTX_ { + ENUM_DRV_STS eDrvStatus[WMTDRV_TYPE_MAX]; /* Controlled driver status */ + UINT32 wmtInfoBit; /* valid info bit */ + WMT_HIF_CONF wmtHifConf; /* HIF information */ + + /* Pointer to WMT_IC_OPS. Shall be assigned to a correct table in stp_init + * if and only if getting chip id successfully. hwver and fwver are kept in + * WMT-IC module only. + */ + P_WMT_IC_OPS p_ic_ops; + UINT32 wmtBlankStatus; /* Controlled blank status */ +} WMT_CTX, *P_WMT_CTX; + +/* TODO:[ChangeFeature][George] remove WMT_PKT. replace it with hardcoded arrays. */ +/* Using this struct relies on compiler's implementation and pack() settings */ +typedef struct _WMT_PKT_ { + UINT8 eType; /* WMT_PKT_TYPE_* */ + UINT8 eOpCode; /* OPCODE_* */ + UINT16 u2SduLen; /* 2 bytes length, little endian */ + UINT8 aucParam[32]; +} WMT_PKT, *P_WMT_PKT; + +/* WMT Packet Format */ +typedef enum _ENUM_WMT_PKT_TYPE { + WMT_PKT_TYPE_INVALID = 0, + WMT_PKT_TYPE_CMD = 1, + WMT_PKT_TYPE_EVENT = 2, + WMT_PKT_TYPE_MAX +} ENUM_WMT_PKT_TYPE, *P_ENUM_WMT_PKT_TYPE; + +typedef enum _ENUM_OPCODE { + OPCODE_INVALID = 0, + OPCODE_PATCH = 1, + OPCODE_TEST = 2, + OPCODE_WAKEUP = 3, + OPCODE_HIF = 4, + OPCODE_STRAP_CONF = 5, + OPCODE_FUNC_CTRL = 6, + OPCODE_RESET = 7, + OPCODE_INT = 8, + OPCODE_MAX +} ENUM_OPCODE, *P_ENUM_OPCODE; + +typedef enum { + WMT_STP_CONF_EN = 0, + WMT_STP_CONF_RDY = 1, + WMT_STP_CONF_MODE = 2, + WMT_STP_CONF_MAX +} WMT_STP_CONF_TYPE; + +struct init_script { + PUINT8 cmd; + UINT32 cmdSz; + PUINT8 evt; + UINT32 evtSz; + PUINT8 str; +}; + +typedef struct _WMT_PATCH { + UINT8 ucDateTime[16]; + UINT8 ucPLat[4]; + UINT16 u2HwVer; + UINT16 u2SwVer; + UINT32 u4PatchVer; +} WMT_PATCH, *P_WMT_PATCH; + +struct wmt_rom_patch { + UINT8 ucDateTime[16]; + UINT8 ucPLat[4]; + UINT16 u2HwVer; + UINT16 u2SwVer; + UINT32 u4PatchAddr; + UINT32 u4PatchType; + UINT32 u4CRC[4]; +}; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern INT32 wmt_core_init(VOID); +extern INT32 wmt_core_deinit(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_wmtd +* DESCRIPTION +* deinit STP kernel +* PARAMETERS +* void +* RETURNS +* INT32 0 = success, others = failure +*****************************************************************************/ +extern INT32 wmt_core_opid(P_WMT_OP pWmtOp); + +extern INT32 wmt_core_ctrl(ENUM_WMT_CTRL_T ctrId, PULONG pPa1, PULONG pPa2); + +extern INT32 wmt_core_func_ctrl_cmd(ENUM_WMTDRV_TYPE_T type, MTK_WCN_BOOL fgEn); + +extern INT32 wmt_core_reg_rw_raw(UINT32 isWrite, UINT32 offset, PUINT32 pVal, UINT32 mask); + +extern VOID wmt_core_dump_data(PUINT8 pData, PUINT8 pTitle, UINT32 len); + +extern MTK_WCN_BOOL wmt_core_patch_check(UINT32 u4PatchVer, UINT32 u4HwVer); + +extern INT32 wmt_core_init_script_retry(struct init_script *script, INT32 count, INT32 retry, INT32 dump_err_log); + +extern INT32 wmt_core_init_script(struct init_script *script, INT32 count); + +extern INT32 wmt_core_rx(PUINT8 pBuf, UINT32 bufLen, PUINT32 readSize); + +extern INT32 wmt_core_rx_flush(UINT32 type); + +extern INT32 wmt_core_opid_handler(P_WMT_OP pWmtOp); + +extern INT32 +wmt_core_tx(const PUINT8 pData, UINT32 size, PUINT32 writtenSize, MTK_WCN_BOOL bRawFlag); +extern MTK_WCN_BOOL wmt_core_is_quick_ps_support(VOID); + +extern MTK_WCN_BOOL wmt_core_get_aee_dump_flag(VOID); +extern MTK_WCN_BOOL wmt_core_trigger_stp_assert(VOID); +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +extern MTK_WCN_BOOL wmt_core_deep_sleep_ctrl(INT32 value); +#endif +extern VOID wmt_core_set_coredump_state(ENUM_DRV_STS state); + +#if CFG_CORE_INTERNAL_TXRX +extern INT32 wmt_core_lpbk_do_stp_init(void); +extern INT32 wmt_core_lpbk_do_stp_deinit(void); +#endif + +extern VOID wmt_core_set_coredump_state(ENUM_DRV_STS state); +extern ENUM_DRV_STS wmt_core_get_drv_status(ENUM_WMTDRV_TYPE_T type); +#if CFG_WMT_LTE_COEX_HANDLING +extern VOID wmt_core_set_flag_for_test(UINT32 enable); +extern UINT32 wmt_core_get_flag_for_test(VOID); +#endif + +#if CFG_CORE_MT6620_SUPPORT +extern WMT_IC_OPS wmt_ic_ops_mt6620; +#endif + +#if CFG_CORE_MT6628_SUPPORT +extern WMT_IC_OPS wmt_ic_ops_mt6628; +#endif + +#if CFG_CORE_MT6630_SUPPORT +extern WMT_IC_OPS wmt_ic_ops_mt6630; +#endif + +#if CFG_CORE_MT6632_SUPPORT +extern WMT_IC_OPS wmt_ic_ops_mt6632; +#endif + +#if CFG_CORE_SOC_SUPPORT +extern WMT_IC_OPS wmt_ic_ops_soc; +#endif + +extern P_WMT_GEN_CONF wmt_get_gen_conf_pointer(VOID); + +VOID wmt_core_set_blank_status(UINT32 on_off_flag); +extern UINT32 wmt_core_get_blank_status(VOID); + +INT32 wmt_blank_status_ctrl(UINT32 on_off_flag); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static _osal_inline_ MTK_WCN_BOOL wmt_core_ic_ops_check(P_WMT_IC_OPS p_ops) +{ + if (!p_ops) + return MTK_WCN_BOOL_FALSE; + if ((p_ops->sw_init == NULL) + || (p_ops->sw_deinit == NULL) + || (p_ops->ic_ver_check == NULL) + || (p_ops->ic_pin_ctrl == NULL)) { + return MTK_WCN_BOOL_FALSE; + } + return MTK_WCN_BOOL_TRUE; +} + +#endif /* _WMT_CORE_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_ctrl.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_ctrl.h new file mode 100644 index 00000000000000..24328583a51746 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_ctrl.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + +#ifndef _WMT_CTRL_H_ +#define _WMT_CTRL_H_ + +//#include "osal.h" +#include "wmt_stp_exp.h" +#include "stp_exp.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define DWCNT_CTRL_DATA (16) + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + + + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef struct _WMT_CTRL_DATA_ { + UINT32 ctrlId; + SIZE_T au4CtrlData[DWCNT_CTRL_DATA]; +} WMT_CTRL_DATA, *P_WMT_CTRL_DATA; + +typedef enum _ENUM_WMT_CTRL_T { + WMT_CTRL_HW_PWR_OFF = 0, /* whole chip power off */ + WMT_CTRL_HW_PWR_ON = 1, /* whole chip power on */ + WMT_CTRL_HW_RST = 2, /* whole chip reset */ + WMT_CTRL_STP_CLOSE = 3, + WMT_CTRL_STP_OPEN = 4, + WMT_CTRL_STP_CONF = 5, + WMT_CTRL_FREE_PATCH = 6, + WMT_CTRL_GET_PATCH = 7, + WMT_CTRL_GET_PATCH_NAME = 8, + WMT_CTRL_HOST_BAUDRATE_SET = 9, + WMT_CTRL_SDIO_HW = 10, /* enable/disable SDIO1/2 of combo chip */ + WMT_CTRL_SDIO_FUNC = 11, /* probe/remove STP/Wi-Fi driver in SDIO1/2 of combo chip */ + WMT_CTRL_HWIDVER_SET = 12, /* TODO: rename this and add chip id information in addition to chip version */ + WMT_CTRL_HWVER_GET = 13, /* TODO: [FixMe][GeorgeKuo] remove unused functions */ + WMT_CTRL_STP_RST = 14, + WMT_CTRL_GET_WMT_CONF = 15, + WMT_CTRL_TX = 16, /* [FixMe][GeorgeKuo]: to be removed by Sean's stp integration */ + WMT_CTRL_RX = 17, /* [FixMe][GeorgeKuo]: to be removed by Sean's stp integration */ + WMT_CTRL_RX_FLUSH = 18, /* [FixMe][SeanWang]: to be removed by Sean's stp integration */ + WMT_CTRL_GPS_SYNC_SET = 19, + WMT_CTRL_GPS_LNA_SET = 20, + WMT_CTRL_PATCH_SEARCH = 21, + WMT_CTRL_CRYSTAL_TRIMING_GET = 22, + WMT_CTRL_CRYSTAL_TRIMING_PUT = 23, + WMT_CTRL_HW_STATE_DUMP = 24, + WMT_CTRL_GET_PATCH_NUM = 25, + WMT_CTRL_GET_PATCH_INFO = 26, + WMT_CTRL_SOC_PALDO_CTRL = 27, + WMT_CTRL_SOC_WAKEUP_CONSYS = 28, + WMT_CTRL_SET_STP_DBG_INFO = 29, + WMT_CTRL_BGW_DESENSE_CTRL = 30, + WMT_CTRL_TRG_ASSERT = 31, +#if CFG_WMT_LTE_COEX_HANDLING + WMT_CTRL_GET_TDM_REQ_ANTSEL = 32, +#endif + WMT_CTRL_EVT_PARSER = 33, + WMT_CTRL_GET_ROM_PATCH_INFO = 34, + WMT_CTRL_UPDATE_PATCH_VERSION = 35, + WMT_CTRL_MAX +} ENUM_WMT_CTRL_T, *P_ENUM_WMT_CTRL_T; + +typedef INT32(*WMT_CTRL_FUNC) (P_WMT_CTRL_DATA); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern INT32 wmt_ctrl(P_WMT_CTRL_DATA pWmtCtrlData); + +extern INT32 +wmt_ctrl_tx_ex(const PUINT8 pData, + const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag); + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + + +#endif /* _WMT_CTRL_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_func.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_func.h new file mode 100644 index 00000000000000..8a5b62d0c60759 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_func.h @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + +#ifndef _WMT_FUNC_H_ +#define _WMT_FUNC_H_ + +#include "wmt_core.h" +#include "wmt_plat.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#if defined(CONFIG_MTK_COMBO_BT_HCI) || defined(CONFIG_MTK_COMBO_BT) +#define CFG_FUNC_BT_SUPPORT 1 +#else +#define CFG_FUNC_BT_SUPPORT 0 +#endif + + +#if defined(CONFIG_MTK_FMRADIO) +#define CFG_FUNC_FM_SUPPORT 1 +#else +#define CFG_FUNC_FM_SUPPORT 0 +#endif + +#if defined(CONFIG_MTK_COMBO_GPS) +#define CFG_FUNC_GPS_SUPPORT 1 +#else +#define CFG_FUNC_GPS_SUPPORT 0 +#endif + +#if 1 /* defined(CONFIG_MTK_COMBO_WIFI) */ +#define CFG_FUNC_WIFI_SUPPORT 1 +#else +#define CFG_FUNC_WIFI_SUPPORT 0 +#endif + +#if 1 +#define CFG_FUNC_ANT_SUPPORT 1 +#else +#define CFG_FUNC_ANT_SUPPORT 0 +#endif + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef INT32 (*SUBSYS_FUNC_ON)(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); +typedef INT32 (*SUBSYS_FUNC_OFF)(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); + +typedef struct _WMT_FUNC_OPS_ { + SUBSYS_FUNC_ON func_on; + SUBSYS_FUNC_OFF func_off; +} WMT_FUNC_OPS, *P_WMT_FUNC_OPS; + +typedef struct _CMB_PIN_CTRL_REG_ { + UINT32 regAddr; + UINT32 regValue; + UINT32 regMask; + +} CMB_PIN_CTRL_REG, *P_CMB_PIN_CTRL_REG; + +typedef struct _CMB_PIN_CTRL_ { + UINT32 pinId; + UINT32 regNum; + P_CMB_PIN_CTRL_REG pFuncOnArray; + P_CMB_PIN_CTRL_REG pFuncOffArray; + +} CMB_PIN_CTRL, *P_CMB_PIN_CTRL; + +typedef enum _ENUM_CMP_PIN_ID_ { + CMB_PIN_EEDI_ID = 0, + CMB_PIN_EEDO_ID = 1, + CMB_PIN_GSYNC_ID = 2, +} ENUM_CMP_PIN_ID, *P_ENUM_CMP_PIN_ID; + + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +#if CFG_FUNC_BT_SUPPORT +extern WMT_FUNC_OPS wmt_func_bt_ops; +#endif + +#if CFG_FUNC_FM_SUPPORT +extern WMT_FUNC_OPS wmt_func_fm_ops; +#endif + +#if CFG_FUNC_GPS_SUPPORT +extern WMT_FUNC_OPS wmt_func_gps_ops; +#endif + +#if CFG_FUNC_WIFI_SUPPORT +extern WMT_FUNC_OPS wmt_func_wifi_ops; +#endif + +#if CFG_FUNC_ANT_SUPPORT +extern WMT_FUNC_OPS wmt_func_ant_ops; +#endif + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + + + + + + +#endif /* _WMT_FUNC_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_ic.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_ic.h new file mode 100644 index 00000000000000..0e59671678527e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_ic.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + +#ifndef _WMT_IC_H_ +#define _WMT_IC_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "wmt_core.h" +//#include "wmt_exp.h" + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define WMT_IC_NAME_MT6620 "MT6620" +#define WMT_IC_NAME_MT6628 "MT6628" +#define WMT_IC_NAME_MT6630 "MT6630" +#define WMT_IC_NAME_MT6632 "MT6632" +#define WMT_IC_NAME_DEFAULT "SOC_CONSYS" + +#define WMT_IC_VER_E1 "E1" +#define WMT_IC_VER_E2 "E2" +#define WMT_IC_VER_E3 "E3" +#define WMT_IC_VER_E4 "E4" +#define WMT_IC_VER_E5 "E5" +#define WMT_IC_VER_E6 "E6" +#define WMT_IC_VER_E7 "E7" + +#define WMT_IC_PATCH_DUMMY_EXT "_ex" +#define WMT_IC_PATCH_NO_EXT "" +#define WMT_IC_PATCH_E1_EXT "_e1" +#define WMT_IC_PATCH_E2_EXT "_e2" +#define WMT_IC_PATCH_E3_EXT "_e3" +#define WMT_IC_PATCH_E4_EXT "_e4" +#define WMT_IC_PATCH_E5_EXT "_e5" +#define WMT_IC_PATCH_E6_EXT "_e6" + +#define WMT_IC_PATCH_TAIL "_hdr.bin" + +#define WMT_IC_INVALID_CHIP_ID 0xFFFF + +#define MAJORNUM(x) (x & 0x00F0) +#define MINORNUM(x) (x & 0x000F) + +/******************************************************************************* +* R E G I S T E R M A P +******************************************************************************** +*/ +/* General definition used for ALL/UNKNOWN CHIPS */ +/* Now MT6620 uses these definitions */ +#define GEN_CONFG_BASE (0x80000000UL) +#define GEN_HVR (GEN_CONFG_BASE + 0x0UL) /* HW_VER */ +#define GEN_FVR (GEN_CONFG_BASE + 0x4UL) /* FW_VER */ +#define GEN_VER_MASK (0x0000FFFFUL) /* HW_VER and FW_VER valid bits mask */ +#define GEN_HCR (GEN_CONFG_BASE + 0x8UL) /* HW_CODE, chip id */ +#define GEN_HCR_MASK (0x0000FFFFUL) /* HW_CODE valid bits mask */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef struct _WMT_IC_INFO_S { + UINT32 u4HwVer; /* u4HwId */ + PUINT8 cChipName; + PUINT8 cChipVersion; + PUINT8 cPatchNameExt; + MTK_WCN_BOOL bPsmSupport; + MTK_WCN_BOOL bWorkWithoutPatch; +} WMT_IC_INFO_S, *P_WMT_IC_INFO_S; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +INT32 mtk_wcn_soc_rom_patch_dwn(UINT32 ip_ver, UINT32 fw_ver); +VOID mtk_wcn_soc_restore_wifi_cal_result(VOID); + +#endif /* _WMT_IC_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_lib.h b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_lib.h new file mode 100644 index 00000000000000..305a53f4caeeaf --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/include/wmt_lib.h @@ -0,0 +1,478 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + +#ifndef _WMT_LIB_H_ +#define _WMT_LIB_H_ + + +#include "wmt_core.h" +#include "wmt_exp.h" +#include <mtk_wcn_cmb_stub.h> +#include "stp_wmt.h" +#include "wmt_plat.h" +#include "wmt_idc.h" +#include "mtk_wcn_consys_hw.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define USE_NEW_PROC_FS_FLAG 1 + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define WMT_OP_BUF_SIZE (16) +#if 0 /* moved to wmt_exp.h */ +#define WMT_LOG_LOUD 4 +#define WMT_LOG_DBG 3 +#define WMT_LOG_INFO 2 +#define WMT_LOG_WARN 1 +#define WMT_LOG_ERR 0 +#endif +typedef enum _ENUM_WMTRSTRET_TYPE_T { + WMTRSTRET_SUCCESS = 0x0, + WMTRSTRET_FAIL = 0x1, + WMTRSTRET_ONGOING = 0x2, + WMTRSTRET_RETRY = 0x3, + WMTRSTRET_MAX +} ENUM_WMTRSTRET_TYPE_T, *P_ENUM_WMTRSTRET_TYPE_T; + +#define MAX_ANT_RAM_CODE_DOWN_TIME 3000 +/* +*3(retry times) * 180 (STP retry time out) +*+ 10 (firmware process time) + +*10 (transmit time) + +*10 (uart process -> WMT response pool) + +*230 (others) +*/ +#define WMT_LIB_RX_TIMEOUT 2000 /*800-->cover v1.2phone BT function on time (~830ms) */ +/* Since GPS timeout is 6 seconds */ +#define WMT_LIB_RX_EXTEND_TIMEOUT 4000 +/* +*open wifi during wifi power on procedure +*(because wlan is insert to system after mtk_hif_sdio module, +*so wifi card is not registered to hif module +*when mtk_wcn_wmt_func_on is called by wifi through rfkill) +*/ +#define MAX_WIFI_ON_TIME 5500 + +#define WMT_PWRON_RTY_DFT 2 +#define MAX_RETRY_TIME_DUE_TO_RX_TIMEOUT (WMT_PWRON_RTY_DFT * WMT_LIB_RX_TIMEOUT) +#define MAX_EACH_FUNC_ON_WHEN_CHIP_POWER_ON_ALREADY WMT_LIB_RX_TIMEOUT /*each WMT command */ +#define MAX_FUNC_ON_TIME (MAX_WIFI_ON_TIME + MAX_RETRY_TIME_DUE_TO_RX_TIMEOUT +\ + MAX_EACH_FUNC_ON_WHEN_CHIP_POWER_ON_ALREADY * 3 + MAX_ANT_RAM_CODE_DOWN_TIME) + +/*1000->WMT_LIB_RX_TIMEOUT + 1000, logical judgement */ +#define MAX_EACH_FUNC_OFF (WMT_LIB_RX_TIMEOUT + 1000) +#define MAX_FUNC_OFF_TIME (MAX_EACH_FUNC_OFF * 4) + +/*1000->WMT_LIB_RX_TIMEOUT + 1000, logical judgement */ +#define MAX_EACH_WMT_CMD (WMT_LIB_RX_TIMEOUT + 1000) + +#define MAX_GPIO_CTRL_TIME (2000) /* [FixMe][GeorgeKuo] a temp value */ + +#define UTC_SYNC_TIME (60 * 60 * 1000) + +#define WMT_IDC_MSG_BUFFER 2048 +#define WMT_IDC_MSG_MAX_SIZE (WMT_IDC_MSG_BUFFER - 7) /* Subtract STP payload cmd size */ + +#define MAX_PATCH_NUM (10) + +#define WMT_FIRMWARE_VERSION_LENGTH (14) +#define WMT_FIRMWARE_MAX_FILE_NAME_LENGTH (50) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/* AIF FLAG definition */ +/* bit(0): share pin or not */ +#define WMT_LIB_AIF_FLAG_MASK (0x1UL) +#define WMT_LIB_AIF_FLAG_SHARE (0x1UL << 0) +#define WMT_LIB_AIF_FLAG_SEPARATE (0x0UL << 0) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* bit field offset definition */ +typedef enum { + WMT_STAT_PWR = 0, /* is powered on */ + WMT_STAT_STP_REG = 1, /* is STP driver registered: */ + WMT_STAT_STP_OPEN = 2, /* is STP opened: default FALSE */ + WMT_STAT_STP_EN = 3, /* is STP enabled: default FALSE */ + WMT_STAT_STP_RDY = 4, /* is STP ready for client: default FALSE */ + WMT_STAT_RX = 5, /* is rx data available */ + WMT_STAT_CMD = 6, /* is cmd string to be read */ + WMT_STAT_SDIO1_ON = 7, /* is SDIO1 on */ + WMT_STAT_SDIO2_ON = 8, /* is SDIO2 on */ + WMT_STAT_SDIO_WIFI_ON = 9, /* is Wi-Fi SDIO function on */ + WMT_STAT_SDIO_STP_ON = 10, /* is STP SDIO function on */ + WMT_STAT_RST_ON = 11, + WMT_STAT_MAX +} WMT_STAT; + +typedef enum _ENUM_WMTRSTSRC_TYPE_T { + WMTRSTSRC_RESET_BT = 0x0, + WMTRSTSRC_RESET_FM = 0x1, + WMTRSTSRC_RESET_GPS = 0x2, + WMTRSTSRC_RESET_WIFI = 0x3, + WMTRSTSRC_RESET_STP = 0x4, + WMTRSTSRC_RESET_TEST = 0x5, + WMTRSTSRC_RESET_MAX +} ENUM_WMTRSTSRC_TYPE_T, *P_ENUM_WMTRSTSRC_TYPE_T; + +enum wmt_fw_log_type { + WMT_FWLOG_MCU = 0, + WMT_FWLOG_MAX +}; + +typedef struct { + PF_WMT_CB fDrvRst[WMTDRV_TYPE_MAX]; +} WMT_FDRV_CB, *P_WMT_FDRV_CB; + + +typedef struct { + UINT32 dowloadSeq; + UINT8 addRess[4]; + UINT8 patchName[256]; +} WMT_PATCH_INFO, *P_WMT_PATCH_INFO; + +struct wmt_rom_patch_info { + UINT32 type; + UINT8 addRess[4]; + UINT8 patchName[256]; +}; + +struct wmt_vendor_patch { + union { + INT32 id; + INT32 type; + }; + UINT8 file_name[WMT_FIRMWARE_MAX_FILE_NAME_LENGTH + 1]; + UINT8 version[WMT_FIRMWARE_VERSION_LENGTH + 1]; +}; + +struct vendor_patch_table { + UINT32 capacity; + UINT32 num; + INT8 status; + INT8 need_update; + PUINT8 *active_version; + struct wmt_vendor_patch *patch; +}; + +enum wmt_patch_type { + WMT_PATCH_TYPE_ROM = 0, + WMT_PATCH_TYPE_RAM, + WMT_PATCH_TYPE_WIFI +}; + +enum wmt_cp_status { + WMT_CP_INIT = 0, + WMT_CP_READY_TO_CHECK, + WMT_CP_CHECK_DONE +}; + + +/* OS independent wrapper for WMT_OP */ +typedef struct _DEV_WMT_ { + + OSAL_SLEEPABLE_LOCK psm_lock; + OSAL_SLEEPABLE_LOCK idc_lock; + OSAL_SLEEPABLE_LOCK wlan_lock; + OSAL_SLEEPABLE_LOCK assert_lock; + OSAL_SLEEPABLE_LOCK mpu_lock; + /* WMTd thread information */ + /* struct task_struct *pWmtd; *//* main thread (wmtd) handle */ + OSAL_THREAD thread; + /* wait_queue_head_t rWmtdWq; *//*WMTd command wait queue */ + OSAL_EVENT rWmtdWq; /* rename */ + OSAL_THREAD worker_thread; + OSAL_EVENT rWmtdWorkerWq; + /* ULONG state; *//* bit field of WMT_STAT */ + OSAL_BIT_OP_VAR state; + + /* STP context information */ + /* wait_queue_head_t rWmtRxWq; *//* STP Rx wait queue */ + OSAL_EVENT rWmtRxWq; /* rename */ + /* WMT_STP_FUNC rStpFunc; *//* STP functions */ + WMT_FDRV_CB rFdrvCb; + + /* WMT Configurations */ + WMT_HIF_CONF rWmtHifConf; + WMT_GEN_CONF rWmtGenConf; + + /* Patch information */ + UINT8 cPatchName[NAME_MAX + 1]; + UINT8 cFullPatchName[NAME_MAX + 1]; + UINT32 patchNum; + + const osal_firmware *pPatch; + + UINT8 cWmtcfgName[NAME_MAX + 1]; + + const osal_firmware *pWmtCfg; + + const osal_firmware *pNvram; + + /* Current used UART port description */ + INT8 cUartName[NAME_MAX + 1]; + + OSAL_OP_Q rFreeOpQ; /* free op queue */ + OSAL_OP_Q rActiveOpQ; /* active op queue */ + OSAL_OP_Q rWorkerOpQ; + OSAL_OP arQue[WMT_OP_BUF_SIZE]; /* real op instances */ + P_OSAL_OP pCurOP; /* current op */ + P_OSAL_OP pWorkerOP; /* current op on worker thread */ + + /* cmd str buffer */ + UINT8 cCmd[NAME_MAX + 1]; + INT32 cmdResult; +/* struct completion cmd_comp; */ + /* wait_queue_head_t cmd_wq; *//* read command queues */ + OSAL_SIGNAL cmdResp; + OSAL_EVENT cmdReq; + + /* WMT loopback Thread Information */ +/* WMT_CMB_VER combo_ver; */ + /* P_WMT_CMB_CHIP_INFO_S pChipInfo; */ + UINT32 chip_id; + UINT32 hw_ver; + UINT32 fw_ver; + UINT32 ip_ver; + + UINT32 ext_ldo_flag; + P_WMT_PATCH_INFO pWmtPatchInfo; + struct wmt_rom_patch_info *pWmtRomPatchInfo[WMTDRV_TYPE_ANT]; + /* MET thread information */ + OSAL_THREAD met_thread; + INT32 met_log_ctrl; + /* Timer to sync UTC time with connsys */ + OSAL_TIMER utc_sync_timer; + struct work_struct utcSyncWorker; + /* Timer for wmt_worker_thread */ + OSAL_TIMER worker_timer; + struct work_struct wmtd_worker_thread_work; + struct osal_op_history wmtd_op_history; + struct osal_op_history worker_op_history; + UINT8 msg_local_buffer[WMT_IDC_MSG_BUFFER]; + struct vendor_patch_table patch_table; + +} DEV_WMT, *P_DEV_WMT; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern DEV_WMT gDevWmt; +extern INT32 wmt_lib_init(VOID); +extern INT32 wmt_lib_deinit(VOID); +extern INT32 wmt_lib_tx(PUINT8 data, UINT32 size, PUINT32 writtenSize); +extern INT32 wmt_lib_tx_raw(PUINT8 data, UINT32 size, PUINT32 writtenSize); +extern INT32 wmt_lib_rx(PUINT8 buff, UINT32 buffLen, PUINT32 readSize); +extern VOID wmt_lib_flush_rx(VOID); +extern UINT32 wmt_lib_co_clock_flag_get(VOID); +extern INT32 wmt_lib_sdio_reg_rw(INT32 func_num, INT32 direction, UINT32 offset, UINT32 value); + + +#if WMT_PLAT_ALPS +extern PINT8 wmt_uart_port_desc; /* defined in mtk_wcn_cmb_stub_alps.cpp */ +#endif + +#if CFG_WMT_PS_SUPPORT +extern INT32 wmt_lib_ps_set_idle_time(UINT32 psIdleTime); +extern INT32 wmt_lib_ps_init(VOID); +extern INT32 wmt_lib_ps_deinit(VOID); +extern INT32 wmt_lib_ps_enable(VOID); +extern INT32 wmt_lib_ps_ctrl(UINT32 state); + +extern INT32 wmt_lib_ps_disable(VOID); +extern VOID wmt_lib_ps_irq_cb(VOID); +#endif +extern VOID wmt_lib_ps_set_sdio_psop(PF_WMT_SDIO_PSOP own_cb); +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +extern VOID wmt_lib_sdio_deep_sleep_flag_set_cb_reg(PF_WMT_SDIO_DEEP_SLEEP flag_cb); +#endif +extern VOID wmt_lib_sdio_reg_rw_cb(PF_WMT_SDIO_DEBUG reg_rw_cb); +extern UINT32 wmt_lib_wait_event_checker(P_OSAL_THREAD pThread); +extern UINT32 wmt_lib_worker_wait_event_checker(P_OSAL_THREAD pThread); +extern INT32 wmt_lib_register_thermal_ctrl_cb(thermal_query_ctrl_cb thermal_ctrl); +extern INT32 wmt_lib_register_trigger_assert_cb(trigger_assert_cb trigger_assert); + +/* LXOP functions: */ +extern P_OSAL_OP wmt_lib_get_free_op(VOID); +extern INT32 wmt_lib_put_op_to_free_queue(P_OSAL_OP pOp); +extern MTK_WCN_BOOL wmt_lib_put_act_op(P_OSAL_OP pOp); +extern MTK_WCN_BOOL wmt_lib_put_worker_op(P_OSAL_OP pOp); + +/* extern ENUM_WMTHWVER_TYPE_T wmt_lib_get_hwver (VOID); */ +extern UINT32 wmt_lib_get_icinfo(ENUM_WMT_CHIPINFO_TYPE_T type); +extern PUINT8 wmt_lib_def_patch_name(VOID); +extern INT32 wmt_lib_utc_time_sync(VOID); + +extern MTK_WCN_BOOL wmt_lib_is_therm_ctrl_support(ENUM_WMTTHERM_TYPE_T eType); +extern MTK_WCN_BOOL wmt_lib_is_dsns_ctrl_support(VOID); +extern INT32 wmt_lib_trigger_cmd_signal(INT32 result); +extern PUINT8 wmt_lib_get_cmd(VOID); +extern P_OSAL_EVENT wmt_lib_get_cmd_event(VOID); +extern INT32 wmt_lib_set_patch_name(PUINT8 cPatchName); +extern INT32 wmt_lib_set_uart_name(PINT8 cUartName); +extern INT32 wmt_lib_set_hif(ULONG hifconf); +extern P_WMT_HIF_CONF wmt_lib_get_hif(VOID); +extern MTK_WCN_BOOL wmt_lib_get_cmd_status(VOID); + +/* GeorgeKuo: replace set_chip_gpio() with more specific ones */ +#if 0 /* moved to wmt_exp.h */ +extern INT32 wmt_lib_set_aif(enum CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); /* set AUDIO interface options */ +#endif +extern INT32 wmt_lib_host_awake_get(VOID); +extern INT32 wmt_lib_host_awake_put(VOID); +extern UINT32 wmt_lib_dbg_level_set(UINT32 level); +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +extern INT32 wmt_lib_deep_sleep_ctrl(INT32 value); +extern MTK_WCN_BOOL wmt_lib_deep_sleep_flag_set(MTK_WCN_BOOL flag); +#endif +extern INT32 wmt_lib_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); + +extern INT32 wmt_lib_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); +ENUM_WMTRSTRET_TYPE_T wmt_lib_cmb_rst(ENUM_WMTRSTSRC_TYPE_T src); +MTK_WCN_BOOL wmt_lib_sw_rst(INT32 baudRst); +MTK_WCN_BOOL wmt_lib_hw_rst(VOID); +INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask); +INT32 wmt_lib_efuse_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask); +VOID wmt_lib_state_init(VOID); +INT32 wmt_lib_sdio_ctrl(UINT32 on); +MTK_WCN_BOOL wmt_lib_rstmsg_snd(ENUM_WMTRSTMSG_TYPE_T msg); +INT32 wmt_lib_met_ctrl(INT32 met_ctrl, INT32 log_ctrl); +INT32 wmt_lib_gps_mcu_ctrl(PUINT8 p_tx_data_buf, UINT32 tx_data_len, PUINT8 p_rx_data_buf, + UINT32 rx_data_buf_len, PUINT32 p_rx_data_len); +VOID wmt_lib_set_ext_ldo(UINT32 flag); +UINT32 wmt_lib_get_ext_ldo(VOID); +INT32 wmt_lib_try_pwr_off(VOID); +P_WMT_PATCH_INFO wmt_lib_get_patch_info(VOID); +INT32 wmt_lib_met_cmd(UINT32 value); + +INT32 wmt_lib_blank_status_ctrl(UINT32 on_off_flag); +VOID wmt_lib_set_blank_status(UINT32 on_off_flag); +extern UINT32 wmt_lib_get_blank_status(VOID); + +extern INT32 DISABLE_PSM_MONITOR(VOID); +extern VOID ENABLE_PSM_MONITOR(VOID); +extern INT32 wmt_lib_notify_stp_sleep(VOID); +extern VOID wmt_lib_psm_lock_release(VOID); +extern INT32 wmt_lib_psm_lock_aquire(VOID); +extern INT32 wmt_lib_psm_lock_trylock(VOID); +extern VOID wmt_lib_idc_lock_release(VOID); +extern INT32 wmt_lib_idc_lock_aquire(VOID); +extern VOID wmt_lib_wlan_lock_release(VOID); +extern INT32 wmt_lib_wlan_lock_trylock(VOID); +extern INT32 wmt_lib_wlan_lock_aquire(VOID); +extern VOID wmt_lib_assert_lock_release(VOID); +extern INT32 wmt_lib_assert_lock_trylock(VOID); +extern INT32 wmt_lib_assert_lock_aquire(VOID); +extern VOID wmt_lib_mpu_lock_release(VOID); +extern INT32 wmt_lib_mpu_lock_aquire(VOID); +extern INT32 wmt_lib_set_stp_wmt_last_close(UINT32 value); + +extern VOID wmt_lib_set_patch_num(UINT32 num); +extern VOID wmt_lib_set_patch_info(P_WMT_PATCH_INFO pPatchinfo); +extern VOID wmt_lib_set_rom_patch_info(struct wmt_rom_patch_info *PatchInfo, ENUM_WMTDRV_TYPE_T type); +extern MTK_WCN_BOOL wmt_lib_stp_is_btif_fullset_mode(VOID); + +extern INT32 wmt_lib_set_current_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp); +extern P_OSAL_OP wmt_lib_get_current_op(P_DEV_WMT pWmtDev); +extern INT32 wmt_lib_set_worker_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp); +extern P_OSAL_OP wmt_lib_get_worker_op(P_DEV_WMT pWmtDev); +extern PUINT8 wmt_lib_get_fwinfor_from_emi(UINT8 section, UINT32 offset, PUINT8 buff, UINT32 len); +extern INT32 wmt_lib_merge_if_flag_ctrl(UINT32 enable); +extern INT32 wmt_lib_merge_if_flag_get(UINT32 enable); + +extern PUINT8 wmt_lib_get_cpupcr_xml_format(PUINT32 len); +extern PUINT8 wmt_lib_get_cpupcr_reg_info(PUINT32 len, PUINT32 consys_reg); +extern UINT32 wmt_lib_set_host_assert_info(UINT32 type, UINT32 reason, UINT32 en); +extern INT8 wmt_lib_co_clock_get(VOID); +extern UINT32 wmt_lib_soc_set_wifiver(UINT32 wifiver); +extern VOID wmt_lib_dump_wmtd_backtrace(VOID); + +#if CFG_WMT_LTE_COEX_HANDLING +extern MTK_WCN_BOOL wmt_lib_handle_idc_msg(conn_md_ipc_ilm_t *idc_infor); +#endif +extern UINT32 wmt_lib_get_drv_status(UINT32 type); +extern INT32 wmt_lib_tm_temp_query(VOID); +extern INT32 wmt_lib_trigger_reset(VOID); +extern INT32 wmt_lib_trigger_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); +extern INT32 wmt_lib_trigger_assert_keyword(ENUM_WMTDRV_TYPE_T type, UINT32 reason, PUINT8 keyword); +extern VOID wmt_lib_trigger_assert_keyword_delay(ENUM_WMTDRV_TYPE_T type, UINT32 reason, PUINT8 keyword); +extern INT32 wmt_lib_wifi_fem_cfg_report(PVOID pvInfoBuf); +#if CFG_WMT_PS_SUPPORT +extern UINT32 wmt_lib_quick_sleep_ctrl(UINT32 en); +#endif +extern UINT32 wmt_lib_fw_patch_update_rst_ctrl(UINT32 en); +#if CONSYS_ENALBE_SET_JTAG +extern UINT32 wmt_lib_jtag_flag_set(UINT32 en); +#endif + +UINT32 wmt_lib_get_gps_lna_pin_num(VOID); +extern INT32 wmt_lib_fw_log_ctrl(enum wmt_fw_log_type type, UINT8 onoff, UINT8 level); +VOID wmt_lib_print_wmtd_op_history(VOID); +VOID wmt_lib_print_worker_op_history(VOID); +extern INT32 wmt_lib_get_vendor_patch_num(VOID); +extern INT32 wmt_lib_set_vendor_patch_version(struct wmt_vendor_patch *p); +extern INT32 wmt_lib_get_vendor_patch_version(struct wmt_vendor_patch *p); +extern INT32 wmt_lib_set_check_patch_status(INT32 status); +extern INT32 wmt_lib_get_check_patch_status(VOID); +extern INT32 wmt_lib_set_active_patch_version(struct wmt_vendor_patch *p); +extern INT32 wmt_lib_get_active_patch_version(struct wmt_vendor_patch *p); +extern INT32 wmt_lib_get_need_update_patch_version(VOID); +extern INT32 wmt_lib_set_need_update_patch_version(INT32 need); +extern VOID wmt_lib_set_bt_link_status(INT32 type, INT32 value); +VOID mtk_lib_set_mcif_mpu_protection(MTK_WCN_BOOL enable); +INT32 wmt_lib_resume_dump_info(VOID); +VOID wmt_lib_set_wlan_mpu_protection(MTK_WCN_BOOL enable); +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WMT_LIB_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/psm_core.c b/drivers/misc/mediatek/connectivity/common/common_main/core/psm_core.c new file mode 100644 index 00000000000000..debb4cb117dcd0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/psm_core.c @@ -0,0 +1,2077 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include "osal_typedef.h" +#include "osal.h" +#include "psm_core.h" +#include "stp_core.h" +#include "stp_dbg.h" +#include "wmt_detect.h" +#include "wmt_exp.h" +#include <mtk_wcn_cmb_stub.h> +#include <linux/timer.h> + +INT32 gPsmDbgLevel = STP_PSM_LOG_INFO; +MTKSTP_PSM_T stp_psm_i; +MTKSTP_PSM_T *stp_psm = &stp_psm_i; + +STP_PSM_RECORD_T *g_stp_psm_dbg; +static UINT32 g_record_num; + +P_STP_PSM_OPID_RECORD g_stp_psm_opid_dbg; +static UINT32 g_opid_record_num; + +static UINT32 stp_traffic_start; +static UINT32 stp_traffic_current; + +#define STP_PSM_PR_LOUD(fmt, arg...) \ +do { \ + if (gPsmDbgLevel >= STP_PSM_LOG_LOUD) \ + pr_info(PFX_PSM "%s: " fmt, __func__, ##arg); \ +} while (0) +#define STP_PSM_PR_DBG(fmt, arg...) \ +do { \ + if (gPsmDbgLevel >= STP_PSM_LOG_DBG) \ + pr_info(PFX_PSM "%s: " fmt, __func__, ##arg); \ +} while (0) +#define STP_PSM_PR_INFO(fmt, arg...) \ +do { \ + if (gPsmDbgLevel >= STP_PSM_LOG_INFO) \ + pr_info(PFX_PSM "[I]%s: " fmt, __func__, ##arg); \ +} while (0) +#define STP_PSM_PR_WARN(fmt, arg...) \ +do { \ + if (gPsmDbgLevel >= STP_PSM_LOG_WARN) \ + pr_warn(PFX_PSM "[W]%s: " fmt, __func__, ##arg); \ +} while (0) +#define STP_PSM_PR_ERR(fmt, arg...) \ +do { \ + if (gPsmDbgLevel >= STP_PSM_LOG_ERR) \ + pr_err(PFX_PSM "[E]%s(%d):ERROR! " fmt, __func__, __LINE__, ##arg); \ +} while (0) + + +static inline INT32 _stp_psm_notify_wmt(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action); +static INT32 _stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm); +static INT32 _stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm); +static INT32 _stp_psm_dbg_dmp_in(STP_PSM_RECORD_T *stp_psm_dbg, UINT32 flag, UINT32 line_num); +static INT32 _stp_psm_dbg_out_printk(STP_PSM_RECORD_T *stp_psm_dbg); +static INT32 _stp_psm_opid_dbg_dmp_in(P_STP_PSM_OPID_RECORD p_opid_dbg, UINT32 opid, UINT32 line_num); +static INT32 _stp_psm_opid_dbg_out_printk(P_STP_PSM_OPID_RECORD p_opid_dbg); +static P_OSAL_OP _stp_psm_get_free_op(MTKSTP_PSM_T *stp_psm); +static INT32 _stp_psm_put_act_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP pOp); +static INT32 _stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const PUINT8 buffer, const UINT32 len, const UINT8 type); +static INT32 _stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm); + + +static const PINT8 g_psm_state[STP_PSM_MAX_STATE] = { + "ACT", + "ACT_INACT", + "INACT", + "INACT_ACT" +}; + +static const PINT8 g_psm_action[STP_PSM_MAX_ACTION] = { + "SLEEP", + "HOST_AWAKE", + "WAKEUP", + "EIRQ", + "ROLL_BACK" +}; + +static const PINT8 g_psm_op_name[STP_OPID_PSM_NUM] = { + "STP_OPID_PSM_SLEEP", + "STP_OPID_PSM_WAKEUP", + "STP_OPID_PSM_HOST_AWAKE", + "STP_OPID_PSM_EXIT" +}; + +static INT32 _stp_psm_release_data(MTKSTP_PSM_T *stp_psm); + +static inline INT32 _stp_psm_get_state(MTKSTP_PSM_T *stp_psm); + +static INT32 _stp_psm_is_redundant_active_op(P_OSAL_OP pOp, P_OSAL_OP_Q pOpQ); + +static INT32 _stp_psm_clean_up_redundant_active_op(P_OSAL_OP_Q pOpQ); +static MTK_WCN_BOOL _stp_psm_is_quick_ps_support(VOID); + +ENUM_STP_TX_IF_TYPE __weak wmt_plat_get_comm_if_type(VOID) +{ + return STP_MAX_IF_TX; +} + +MTK_WCN_BOOL mtk_wcn_stp_psm_dbg_level(INT32 dbglevel) +{ + if (dbglevel >= 0 && dbglevel <= 4) { + gPsmDbgLevel = dbglevel; + STP_PSM_PR_INFO("gPsmDbgLevel = %d\n", gPsmDbgLevel); + return true; + } + STP_PSM_PR_INFO("invalid psm debug level. gPsmDbgLevel = %d\n", gPsmDbgLevel); + return false; +} +#if 0 +/* change from macro to static function to enforce type checking on parameters. */ +static INT32 psm_fifo_lock_init(MTKSTP_PSM_T *psm) +{ + + +#if CFG_PSM_CORE_FIFO_SPIN_LOCK +#if defined(CONFIG_PROVE_LOCKING) + osal_unsleepable_lock_init(&(psm->hold_fifo_lock)); + return 0; +#else + return osal_unsleepable_lock_init(&(psm->hold_fifo_lock)); +#endif +#else +#if defined(CONFIG_PROVE_LOCKING) + osal_sleepable_lock_init(&(psm->hold_fifo_lock)); + return 0; +#else + return osal_sleepable_lock_init(&(psm->hold_fifo_lock)); +#endif +#endif +} + +static INT32 psm_fifo_lock_deinit(MTKSTP_PSM_T *psm) +{ +#if CFG_PSM_CORE_FIFO_SPIN_LOCK + return osal_unsleepable_lock_deinit(&(psm->hold_fifo_lock)); +#else + return osal_sleepable_lock_deinit(&(psm->hold_fifo_lock)); +#endif +} + +static INT32 psm_fifo_lock(MTKSTP_PSM_T *psm) +{ + + +#if CFG_PSM_CORE_FIFO_SPIN_LOCK + return osal_lock_unsleepable_lock(&(psm->hold_fifo_lock)); +#else + return osal_lock_sleepable_lock(&(psm->hold_fifo_lock)); +#endif +} + +static INT32 psm_fifo_unlock(MTKSTP_PSM_T *psm) +{ + + +#if CFG_PSM_CORE_FIFO_SPIN_LOCK + return osal_unlock_unsleepable_lock(&(psm->hold_fifo_lock)); +#else + return osal_unlock_sleepable_lock(&(psm->hold_fifo_lock)); +#endif +} +#endif +static INT32 _stp_psm_handler(MTKSTP_PSM_T *stp_psm, P_STP_OP pStpOp) +{ + INT32 ret = -1; + + /* if (NULL == pStpOp) */ + /* { */ + /* return -1; */ + /* } */ + ret = _stp_psm_thread_lock_aquire(stp_psm); + if (ret) { + STP_PSM_PR_ERR("--->lock psm_thread_lock failed ret=%d\n", ret); + return ret; + } + + switch (pStpOp->opId) { + case STP_OPID_PSM_EXIT: + /* TODO: clean all up? */ + ret = 0; + break; + + case STP_OPID_PSM_SLEEP: + if (stp_psm_check_sleep_enable(stp_psm) > 0) + ret = _stp_psm_notify_wmt(stp_psm, SLEEP); + else + STP_PSM_PR_INFO("cancel sleep request\n"); + break; + + case STP_OPID_PSM_WAKEUP: + ret = _stp_psm_notify_wmt(stp_psm, WAKEUP); + break; + + case STP_OPID_PSM_HOST_AWAKE: + ret = _stp_psm_notify_wmt(stp_psm, HOST_AWAKE); + break; + + default: + STP_PSM_PR_ERR("invalid operation id (%d)\n", pStpOp->opId); + ret = -1; + break; + } + _stp_psm_thread_lock_release(stp_psm); + return ret; +} + +static P_OSAL_OP _stp_psm_get_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP_Q pOpQ) +{ + P_OSAL_OP pOp; + + if (!pOpQ) { + STP_PSM_PR_WARN("pOpQ == NULL\n"); + return NULL; + } + + osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); + /* acquire lock success */ + RB_GET(pOpQ, pOp); + + if ((pOpQ == &stp_psm->rActiveOpQ) && (pOp != NULL)) { + /* stp_psm->current_active_op = pOp; */ + stp_psm->last_active_opId = pOp->op.opId; + } + osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); + + if ((pOpQ == &stp_psm->rActiveOpQ) && (pOp != NULL)) + STP_PSM_PR_DBG("last_active_opId(%d)\n", stp_psm->last_active_opId); + + if (!pOp) + STP_PSM_PR_WARN("RB_GET fail\n"); + + return pOp; +} + +static INT32 _stp_psm_dump_active_q(P_OSAL_OP_Q pOpQ) +{ + UINT32 read_idx; + UINT32 write_idx; + UINT32 opId; + + if (pOpQ == &stp_psm->rActiveOpQ) { + read_idx = stp_psm->rActiveOpQ.read; + write_idx = stp_psm->rActiveOpQ.write; + + STP_PSM_PR_DBG("Active op list:++\n"); + while ((read_idx & RB_MASK(pOpQ)) != (write_idx & RB_MASK(pOpQ))) { + opId = pOpQ->queue[read_idx & RB_MASK(pOpQ)]->op.opId; + if (opId < STP_OPID_PSM_NUM) + STP_PSM_PR_DBG("%s\n", g_psm_op_name[opId]); + else + STP_PSM_PR_WARN("Unknown OP Id\n"); + ++read_idx; + } + STP_PSM_PR_DBG("Active op list:--\n"); + } else + STP_PSM_PR_DBG("%s: not active queue, dont dump\n", __func__); + + return 0; +} + +static INT32 _stp_psm_is_redundant_active_op(P_OSAL_OP pOp, P_OSAL_OP_Q pOpQ) +{ + UINT32 opId = 0; + UINT32 prev_opId = 0; + + /* if((pOpQ == &stp_psm->rActiveOpQ) && (NULL != stp_psm->current_active_op)) */ + if ((pOpQ == &stp_psm->rActiveOpQ) && (stp_psm->last_active_opId != STP_OPID_PSM_INALID)) { + opId = pOp->op.opId; + + if (opId == STP_OPID_PSM_SLEEP) { + if (RB_EMPTY(pOpQ)) { + /* prev_opId = stp_psm->current_active_op->op.opId; */ + prev_opId = stp_psm->last_active_opId; + } else { + prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId; + } + + if (prev_opId == STP_OPID_PSM_SLEEP) { + STP_PSM_PR_DBG("redundant sleep opId found\n"); + return 1; + } else { + return 0; + } + } else { + if (RB_EMPTY(pOpQ)) { + /* prev_opId = stp_psm->current_active_op->op.opId; */ + prev_opId = stp_psm->last_active_opId; + } else { + prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId; + } + + if (((opId == STP_OPID_PSM_WAKEUP) && (prev_opId == STP_OPID_PSM_WAKEUP)) || + ((opId == STP_OPID_PSM_HOST_AWAKE) + && (prev_opId == STP_OPID_PSM_WAKEUP)) + || ((opId == STP_OPID_PSM_HOST_AWAKE) + && (prev_opId == STP_OPID_PSM_HOST_AWAKE)) + || ((opId == STP_OPID_PSM_WAKEUP) + && (prev_opId == STP_OPID_PSM_HOST_AWAKE)) + ) { + STP_PSM_PR_DBG("redundant opId found, opId(%d), preOpid(%d)\n", + opId, prev_opId); + return 1; + } else { + return 0; + } + } + } else { + return 0; + } + +} + +static INT32 _stp_psm_clean_up_redundant_active_op(P_OSAL_OP_Q pOpQ) +{ + UINT32 prev_opId = 0; + UINT32 prev_prev_opId = 0; + + P_OSAL_OP pOp; + P_OSAL_OP_Q pFreeOpQ = &stp_psm->rFreeOpQ; + + if (pOpQ == &stp_psm->rActiveOpQ) { + /* sleep , wakeup | sleep, --> null | sleep (x) */ + /* wakeup , sleep , wakeup | sleep --> wakeup | sleep (v) */ + /* sleep , wakeup , sleep | wakeup --> sleep | wakeup (v) */ + /* xxx, sleep | sleep --> xxx, sleep (v) */ + /* xxx, wakeup | wakeup --> xxx, wakeup (v) */ + /* xxx, awake | awake --> xxx, awake (v) --> should never happen */ + while (RB_COUNT(pOpQ) > 2) { + prev_opId = pOpQ->queue[(pOpQ->write - 1) & RB_MASK(pOpQ)]->op.opId; + prev_prev_opId = pOpQ->queue[(pOpQ->write - 2) & RB_MASK(pOpQ)]->op.opId; + + if ((prev_opId == STP_OPID_PSM_SLEEP + && prev_prev_opId == STP_OPID_PSM_WAKEUP) + || (prev_opId == STP_OPID_PSM_SLEEP + && prev_prev_opId == STP_OPID_PSM_HOST_AWAKE) + || (prev_opId == STP_OPID_PSM_WAKEUP + && prev_prev_opId == STP_OPID_PSM_SLEEP) + || (prev_opId == STP_OPID_PSM_HOST_AWAKE + && prev_prev_opId == STP_OPID_PSM_SLEEP) + ) { + RB_GET(pOpQ, pOp); + RB_PUT(pFreeOpQ, pOp); + RB_GET(pOpQ, pOp); + RB_PUT(pFreeOpQ, pOp); + } else if (prev_opId == prev_prev_opId) { + RB_GET(pOpQ, pOp); + if (!pOp) { + STP_PSM_PR_DBG("RB_GET pOp == NULL\n"); + } else { + STP_PSM_PR_DBG("redundant opId(%d) found, remove it\n", + pOp->op.opId); + } + RB_PUT(pFreeOpQ, pOp); + } else + if ((prev_opId == STP_OPID_PSM_WAKEUP + && prev_prev_opId == STP_OPID_PSM_HOST_AWAKE) + || (prev_opId == STP_OPID_PSM_HOST_AWAKE + && prev_prev_opId == STP_OPID_PSM_WAKEUP)) { + STP_PSM_PR_WARN("prev_opId(%d), prev_prev_opId(%d)\n", prev_opId, + prev_prev_opId); + RB_GET(pOpQ, pOp); + RB_PUT(pFreeOpQ, pOp); + } else { + STP_PSM_PR_ERR + ("prev_opId(%d), prev_prev_opId(%d), this should never happen!!!\n", + prev_opId, prev_prev_opId); + break; + } + } + } + + return 0; +} + +static INT32 _stp_psm_put_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) +{ + INT32 ret; + + /* if (!pOpQ || !pOp) */ + /* { */ + /* STP_PSM_PR_WARN("pOpQ = 0x%p, pLxOp = 0x%p\n", pOpQ, pOp); */ + /* return 0; */ + /* } */ + ret = 0; + + osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); + /* acquire lock success */ + if (pOpQ == &stp_psm->rActiveOpQ) { + if (!_stp_psm_is_redundant_active_op(pOp, pOpQ)) { + /* acquire lock success */ + if (!RB_FULL(pOpQ)) { + RB_PUT(pOpQ, pOp); + STP_PSM_PR_DBG("opId(%d) enqueue\n", pOp->op.opId); + } else { + STP_PSM_PR_INFO("************ Active Queue Full ************\n"); + ret = -1; + } + + _stp_psm_clean_up_redundant_active_op(pOpQ); + } else { + /*redundant opId, mark ret as success */ + P_OSAL_OP_Q pFreeOpQ = &stp_psm->rFreeOpQ; + + if (!RB_FULL(pFreeOpQ)) + RB_PUT(pFreeOpQ, pOp); + else + osal_assert(!RB_FULL(pFreeOpQ)); + ret = 0; + } + } else { + if (!RB_FULL(pOpQ)) + RB_PUT(pOpQ, pOp); + else + ret = -1; + } + + if (pOpQ == &stp_psm->rActiveOpQ) + _stp_psm_dump_active_q(&stp_psm->rActiveOpQ); + + + if (ret) { + STP_PSM_PR_WARN("RB_FULL, RB_COUNT=%d , RB_SIZE=%d\n", RB_COUNT(pOpQ), + RB_SIZE(pOpQ)); + osal_opq_dump_locked("FreeOpQ", &stp_psm->rFreeOpQ); + osal_opq_dump_locked("ActiveOpQ", &stp_psm->rActiveOpQ); + } + + osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); + return ret ? 0 : 1; +} + +P_OSAL_OP _stp_psm_get_free_op(MTKSTP_PSM_T *stp_psm) +{ + P_OSAL_OP pOp; + + if (stp_psm) { + pOp = _stp_psm_get_op(stp_psm, &stp_psm->rFreeOpQ); + if (pOp) { + osal_memset(pOp, 0, osal_sizeof(OSAL_OP)); + } + return pOp; + } + return NULL; +} + +INT32 _stp_psm_put_act_op(MTKSTP_PSM_T *stp_psm, P_OSAL_OP pOp) +{ + INT32 bRet = 0; /* MTK_WCN_BOOL_FALSE; */ + INT32 wait_ret = -1; + P_OSAL_SIGNAL pSignal = NULL; + INT32 ret = 0; + + do { + if (!stp_psm || !pOp) { + STP_PSM_PR_ERR("stp_psm = %p, pOp = %p\n", stp_psm, pOp); + break; + } + + pSignal = &pOp->signal; + + if (pSignal->timeoutValue) { + pOp->result = -9; + osal_signal_init(&pOp->signal); + } + + /* Init ref_count to 2, as one is held by current thread, the second by psm thread */ + atomic_set(&pOp->ref_count, 2); + + /* put to active Q */ + bRet = _stp_psm_put_op(stp_psm, &stp_psm->rActiveOpQ, pOp); + + if (bRet == 0) { + STP_PSM_PR_WARN("+++++++++++ Put op Active queue Fail\n"); + atomic_dec(&pOp->ref_count); + break; + } + _stp_psm_opid_dbg_dmp_in(g_stp_psm_opid_dbg, pOp->op.opId, __LINE__); + /* wake up wmtd */ + ret = osal_trigger_event(&stp_psm->STPd_event); + + if (pSignal->timeoutValue == 0) { + bRet = 1; /* MTK_WCN_BOOL_TRUE; */ + break; + } + + /* check result */ + wait_ret = osal_wait_for_signal_timeout(&pOp->signal, &stp_psm->PSMd); + STP_PSM_PR_DBG("wait completion:%d\n", wait_ret); + if (!wait_ret) { + STP_PSM_PR_ERR("wait completion timeout\n"); + /* TODO: how to handle it? retry? */ + } else { + if (pOp->result) + STP_PSM_PR_WARN("op(%d) result:%d\n", pOp->op.opId, pOp->result); + /* op completes, check result */ + bRet = (pOp->result) ? 0 : 1; + } + } while (0); + + if (pOp && atomic_dec_and_test(&pOp->ref_count)) { + /* put Op back to freeQ */ + bRet = _stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, pOp); + if (bRet == 0) + STP_PSM_PR_WARN("+++++++++++ Put op active free fail, maybe disable/enable psm\n"); + } + + return bRet; +} + +static INT32 _stp_psm_wait_for_msg(PVOID pvData) +{ + MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *)pvData; + + STP_PSM_PR_DBG("%s: stp_psm->rActiveOpQ = %d\n", __func__, + RB_COUNT(&stp_psm->rActiveOpQ)); + + return (!RB_EMPTY(&stp_psm->rActiveOpQ)) || osal_thread_should_stop(&stp_psm->PSMd); +} + +static INT32 _stp_psm_proc(PVOID pvData) +{ + MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) pvData; + P_OSAL_OP pOp; + UINT32 id; + INT32 result; + + if (!stp_psm) { + STP_PSM_PR_WARN("!stp_psm\n"); + return -1; + } +/* STP_PSM_PR_INFO("wmtd starts running: pWmtDev(0x%p) [pol, rt_pri, n_pri, pri]=[%d, %d, %d, %d]\n", */ +/* stp_psm, current->policy, current->rt_priority, current->normal_prio, current->prio); */ + + for (;;) { + + pOp = NULL; + osal_wait_for_event(&stp_psm->STPd_event, _stp_psm_wait_for_msg, (PVOID) stp_psm); + + /* we set reset flag when calling stp_reset after cleanup all op. */ + if (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)) { + osal_clear_bit(STP_PSM_RESET_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + } + if (osal_thread_should_stop(&stp_psm->PSMd)) { + STP_PSM_PR_INFO("should stop now...\n"); + /* TODO: clean up active opQ */ + break; + } + + /* get Op from activeQ */ + pOp = _stp_psm_get_op(stp_psm, &stp_psm->rActiveOpQ); + if (!pOp) { + STP_PSM_PR_WARN + ("+++++++++++ Get op from activeQ fail, maybe disable/enable psm\n"); + continue; + } + osal_op_history_save(&stp_psm->op_history, pOp); + + id = osal_op_get_id(pOp); + + if (id >= STP_OPID_PSM_NUM) { + STP_PSM_PR_WARN("abnormal opid id: 0x%x\n", id); + result = -1; + goto handler_done; + } + + result = _stp_psm_handler(stp_psm, &pOp->op); + + +handler_done: + + if (result) + STP_PSM_PR_WARN("opid id(0x%x)(%s) error(%d)\n", id, + (id >= 4) ? ("???") : (g_psm_op_name[id]), result); + + if (atomic_dec_and_test(&pOp->ref_count)) { + /* put Op back to freeQ */ + if (_stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, pOp) == 0) + STP_PSM_PR_WARN + ("+++++++++++ Put op to FreeOpQ fail, maybe disable/enable psm\n"); + } else if (osal_op_is_wait_for_signal(pOp)) { + osal_op_raise_signal(pOp, result); + } + + if (id == STP_OPID_PSM_EXIT) + break; + } + STP_PSM_PR_INFO("exits\n"); + + return 0; +}; + +static inline INT32 _stp_psm_get_time(VOID) +{ + if (gPsmDbgLevel >= STP_PSM_LOG_LOUD) + osal_printtimeofday("<psm time>>>>"); + + return 0; +} + +static inline INT32 _stp_psm_get_state(MTKSTP_PSM_T *stp_psm) +{ + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + if (stp_psm->work_state < STP_PSM_MAX_STATE) + return stp_psm->work_state; + STP_PSM_PR_ERR("work_state = %d, invalid\n", stp_psm->work_state); + return -STP_PSM_OPERATION_FAIL; +} + +static inline INT32 _stp_psm_set_state(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_STATE_T state) +{ + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + if (stp_psm->work_state < STP_PSM_MAX_STATE) { + _stp_psm_get_time(); + /* STP_PSM_PR_INFO("work_state = %s --> %s\n", + * g_psm_state[stp_psm->work_state], g_psm_state[state]); + */ + stp_psm->work_state = state; + if (stp_psm->work_state != ACT) { + /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ + osal_set_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag); + /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ + } + } else + STP_PSM_PR_ERR("work_state = %d, invalid\n", stp_psm->work_state); + + return STP_PSM_OPERATION_SUCCESS; +} + +static inline INT32 _stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm) +{ + + if (!stp_psm) + return STP_PSM_OPERATION_FAIL; + + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) { + STP_PSM_PR_DBG("STP-PSM DISABLE, DONT restart monitor!\n\r"); + return STP_PSM_OPERATION_SUCCESS; + } + + + STP_PSM_PR_LOUD("start monitor\n"); + stp_traffic_start = stp_traffic_current; + osal_timer_modify(&stp_psm->psm_timer, stp_psm->idle_time_to_sleep); + + return STP_PSM_OPERATION_SUCCESS; +} + +static inline INT32 _stp_psm_stop_monitor(MTKSTP_PSM_T *stp_psm) +{ + if (!stp_psm) + return STP_PSM_OPERATION_FAIL; + STP_PSM_PR_DBG("stop monitor\n"); + osal_timer_stop_sync(&stp_psm->psm_timer); + return STP_PSM_OPERATION_SUCCESS; +} + +INT32 +_stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const PUINT8 buffer, const UINT32 len, const UINT8 type) +{ + INT32 available_space = 0; + INT32 needed_space = 0; + UINT8 delimiter[] = { 0xbb, 0xbb }; + + if (!stp_psm) + return STP_PSM_OPERATION_FAIL; + /*psm_fifo_lock(stp_psm);*/ + osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); + available_space = STP_PSM_FIFO_SIZE - osal_fifo_len(&stp_psm->hold_fifo); + needed_space = len + sizeof(UINT8) + sizeof(UINT32) + 2; + /* STP_PSM_PR_INFO("*******FIFO Available(%d), Need(%d)\n", + * available_space, needed_space); + */ + if (available_space < needed_space) { + STP_PSM_PR_ERR("FIFO Available!! Reset FIFO\n"); + osal_fifo_reset(&stp_psm->hold_fifo); + } + /* type */ + osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) &type, sizeof(UINT8)); + /* length */ + osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) &len, sizeof(UINT32)); + /* buffer */ + osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) buffer, len); + /* delimiter */ + osal_fifo_in(&stp_psm->hold_fifo, (PUINT8) delimiter, 2); + /*psm_fifo_unlock(stp_psm);*/ + osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); + return len; +} + +INT32 _stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm) +{ + return osal_fifo_len(&stp_psm->hold_fifo); +} + +INT32 _stp_psm_release_data(MTKSTP_PSM_T *stp_psm) +{ + + INT32 i = 20; /*Max buffered packet number */ + INT32 ret = 0; + UINT8 type = 0; + UINT32 len = 0; + UINT8 delimiter[2] = {0}; + INT32 winspace_flag = 0; + + /* STP_PSM_PR_ERR("++++++++++release data++len=%d\n", osal_fifo_len(&stp_psm->hold_fifo)); */ + while ((osal_fifo_len(&stp_psm->hold_fifo) && i > 0) || winspace_flag > 0) { + /* acquire spinlock */ + /* psm_fifo_lock(stp_psm); */ + osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); + + if (winspace_flag == 0) { + ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8)&type, sizeof(UINT8)); + ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8)&len, sizeof(UINT32)); + + if (len > STP_PSM_PACKET_SIZE_MAX) { + STP_PSM_PR_ERR("***psm packet's length too Long!****\n"); + STP_PSM_PR_INFO("***reset psm's fifo***\n"); + } else { + osal_memset(stp_psm->out_buf, 0, STP_PSM_TX_SIZE); + ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8) stp_psm->out_buf, len); + } + + ret = osal_fifo_out(&stp_psm->hold_fifo, (PUINT8)delimiter, 2); + } + + if (delimiter[0] == 0xbb && delimiter[1] == 0xbb) { + /* osal_buffer_dump(stp_psm->out_buf, "psm->out_buf", len, 32); */ + ret = stp_send_data_no_ps(stp_psm->out_buf, len, type); + if (ret == 0) + winspace_flag++; + else + winspace_flag = 0; + } else { + STP_PSM_PR_ERR("***psm packet fifo parsing fail****\n"); + STP_PSM_PR_INFO("***reset psm's fifo***\n"); + + osal_fifo_reset(&stp_psm->hold_fifo); + } + + if (winspace_flag == 0) + i--; + /* psm_fifo_unlock(stp_psm); */ + osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); + + if (winspace_flag > 0 && winspace_flag < 10) + osal_sleep_ms(2); + else if (winspace_flag >= 10) { + STP_PSM_PR_ERR("***More than 20ms no winspace available***\n"); + break; + } + } + return STP_PSM_OPERATION_SUCCESS; +} + +static inline INT32 _stp_psm_notify_wmt_host_awake_wq(MTKSTP_PSM_T *stp_psm) +{ + + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + pOp = _stp_psm_get_free_op(stp_psm); + if (!pOp) { + STP_PSM_PR_DBG("get_free_lxop fail\n"); + return -1; /* break; */ + } + pOp->op.opId = STP_OPID_PSM_HOST_AWAKE; + pOp->signal.timeoutValue = 0; + bRet = _stp_psm_put_act_op(stp_psm, pOp); + STP_PSM_PR_DBG("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); + retval = (bRet == 0) ? (STP_PSM_OPERATION_FAIL) : 0; + return retval; +} + +static inline INT32 _stp_psm_notify_wmt_wakeup_wq(MTKSTP_PSM_T *stp_psm) +{ + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + pOp = _stp_psm_get_free_op(stp_psm); + if (!pOp) { + STP_PSM_PR_DBG("get_free_lxop fail\n"); + return -1; /* break; */ + } + pOp->op.opId = STP_OPID_PSM_WAKEUP; + pOp->signal.timeoutValue = 0; + bRet = _stp_psm_put_act_op(stp_psm, pOp); + if (bRet == 0) { + STP_PSM_PR_WARN("OPID(%d) type(%zd) bRet(%s)\n\n", + pOp->op.opId, pOp->op.au4OpData[0], "fail"); + } + retval = (bRet == 0) ? (STP_PSM_OPERATION_FAIL) : (STP_PSM_OPERATION_SUCCESS); + return retval; +} + +static inline INT32 _stp_psm_notify_wmt_sleep_wq(MTKSTP_PSM_T *stp_psm) +{ + P_OSAL_OP pOp; + INT32 bRet; + INT32 retval; + + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag)) + return 0; +#if PSM_USE_COUNT_PACKAGE + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag)) + return 0; +#endif + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) + return 0; + pOp = _stp_psm_get_free_op(stp_psm); + if (!pOp) { + STP_PSM_PR_DBG("get_free_lxop fail\n"); + return -1; /* break; */ + } + pOp->op.opId = STP_OPID_PSM_SLEEP; + pOp->signal.timeoutValue = 0; + bRet = _stp_psm_put_act_op(stp_psm, pOp); + STP_PSM_PR_DBG("OPID(%d) type(%zd) bRet(%d)\n\n", pOp->op.opId, pOp->op.au4OpData[0], bRet); + retval = (bRet == 0) ? (STP_PSM_OPERATION_FAIL) : 1; + return retval; +} + +/*internal function*/ + +static inline INT32 _stp_psm_reset(MTKSTP_PSM_T *stp_psm) +{ + INT32 i = 0; + P_OSAL_OP_Q pOpQ; + P_OSAL_OP pOp; + INT32 ret = 0; + + STP_PSM_PR_DBG("PSM MODE RESET=============================>\n\r"); + STP_PSM_PR_DBG("_stp_psm_reset\n"); + STP_PSM_PR_DBG("reset-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); + osal_wake_unlock(&stp_psm->wake_lock); + STP_PSM_PR_DBG("reset-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); + /* --> serialized the request from wmt <--// */ + ret = osal_lock_sleepable_lock(&stp_psm->user_lock); + if (ret) { + STP_PSM_PR_ERR("--->lock stp_psm->user_lock failed, ret=%d\n", ret); + return ret; + } + /* --> disable psm <--// */ + stp_psm->flag.data = 0; + osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + _stp_psm_stop_monitor(stp_psm); + /* --> prepare the op list <--// */ + osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); + RB_INIT(&stp_psm->rFreeOpQ, STP_OP_BUF_SIZE); + RB_INIT(&stp_psm->rActiveOpQ, STP_OP_BUF_SIZE); + /* stp_psm->current_active_op = NULL; */ + stp_psm->last_active_opId = STP_OPID_PSM_INALID; + pOpQ = &stp_psm->rFreeOpQ; + for (i = 0; i < STP_OP_BUF_SIZE; i++) { + if (!RB_FULL(pOpQ)) { + pOp = &stp_psm->arQue[i]; + RB_PUT(pOpQ, pOp); + } + } + osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); + /* --> clean up interal data structure<--// */ + _stp_psm_set_state(stp_psm, ACT); + /*psm_fifo_lock(stp_psm);*/ + osal_lock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); + osal_fifo_reset(&stp_psm->hold_fifo); + /*psm_fifo_unlock(stp_psm);*/ + osal_unlock_sleepable_lock(&stp_psm->hold_fifo_spinlock_global); + /* --> stop psm thread wait <--*/ + osal_set_bit(STP_PSM_RESET_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + osal_trigger_event(&stp_psm->wait_wmt_q); + osal_unlock_sleepable_lock(&stp_psm->user_lock); + STP_PSM_PR_DBG("PSM MODE RESET<============================\n\r"); + return STP_PSM_OPERATION_SUCCESS; +} + +static INT32 _stp_psm_wait_wmt_event(PVOID pvData) +{ + MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) pvData; + + STP_PSM_PR_DBG("%s, stp_psm->flag= %ld\n", __func__, stp_psm->flag.data); + osal_ftrace_print("%s, stp_psm->flag= %ld\n", __func__, stp_psm->flag.data); + + return (osal_test_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag)) || + (osal_test_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag)) || + (osal_test_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag)) || + (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)); + +} + + +static inline INT32 _stp_psm_wait_wmt_event_wq(MTKSTP_PSM_T *stp_psm) +{ + + INT32 retval = 0; + PUINT8 pbuf = NULL; + INT32 len = 0; + + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + osal_wait_for_event_timeout(&stp_psm->wait_wmt_q, _stp_psm_wait_wmt_event, (PVOID) stp_psm); + + if (mtk_wcn_stp_get_wmt_trg_assert() == 1 || mtk_wcn_stp_coredump_start_get() == 1) { + STP_PSM_PR_INFO("Host/Fw already triggered assert. Skip psm operation.\n"); + return STP_PSM_OPERATION_FAIL; + } + + if (osal_test_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag)) { + osal_clear_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ + /* STP send data here: STP enqueue data to psm buffer. */ + _stp_psm_release_data(stp_psm); + /* STP send data here: STP enqueue data to psm buffer. We release packet by the next one. */ + osal_clear_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* STP send data here: STP sends data directly without PSM. */ + _stp_psm_set_state(stp_psm, ACT); + /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ + if (stp_psm_is_quick_ps_support()) + stp_psm_notify_wmt_sleep(stp_psm); + else + _stp_psm_start_monitor(stp_psm); + } else if (osal_test_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag)) { + osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + _stp_psm_set_state(stp_psm, INACT); + STP_PSM_PR_DBG("mt_combo_plt_enter_deep_idle++\n"); + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + mt_combo_plt_enter_deep_idle(COMBO_IF_BTIF); + else { + switch (wmt_plat_get_comm_if_type()) { + case STP_UART_IF_TX: + mt_combo_plt_enter_deep_idle(COMBO_IF_UART); + break; + case STP_SDIO_IF_TX: + mt_combo_plt_enter_deep_idle(COMBO_IF_MSDC); + break; + default: + break; + } + } + STP_PSM_PR_DBG("mt_combo_plt_enter_deep_idle--\n"); + STP_PSM_PR_DBG("sleep-wake_lock(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); + osal_wake_unlock(&stp_psm->wake_lock); + STP_PSM_PR_DBG("sleep-wake_lock#(%d)\n", osal_wake_lock_count(&stp_psm->wake_lock)); + + if (osal_wake_lock_count(&stp_psm->wake_lock) == 0 && stp_psm->update_wmt_fw_patch_chip_rst != NULL) + stp_psm->update_wmt_fw_patch_chip_rst(); + } else if (osal_test_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag)) { + osal_clear_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + if (_stp_psm_get_state(stp_psm) == ACT_INACT) { + /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ + _stp_psm_release_data(stp_psm); + osal_clear_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + _stp_psm_set_state(stp_psm, ACT); + /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ + } else if (_stp_psm_get_state(stp_psm) == INACT_ACT) { + _stp_psm_set_state(stp_psm, INACT); + STP_PSM_PR_INFO("[WARNING]PSM state rollback due too wakeup fail\n"); + } + } else if (osal_test_bit(STP_PSM_RESET_EN, &stp_psm->flag)) { + osal_clear_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + } else { + STP_PSM_PR_ERR("state = %d, flag = %ld<== Abnormal flag be set!!\n\r", + stp_psm->work_state, stp_psm->flag.data); + mtk_wcn_wmt_dump_wmtd_backtrace(); + /* wcn_psm_flag_trigger_collect_ftrace(); */ /* trigger collect SYS_FTRACE */ + pbuf = "Abnormal PSM flag be set, just collect SYS_FTRACE to DB"; + len = osal_strlen(pbuf); + stp_dbg_trigger_collect_ftrace(pbuf, len); + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + } + retval = STP_PSM_OPERATION_SUCCESS; + return retval; +} + +static inline INT32 _stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action) +{ + + INT32 retval = STP_PSM_OPERATION_SUCCESS; + + if (action == EIRQ) { + STP_PSM_PR_DBG("Call _stp_psm_notify_wmt_host_awake_wq\n\r"); + _stp_psm_notify_wmt_host_awake_wq(stp_psm); + return STP_PSM_OPERATION_FAIL; + } + if ((_stp_psm_get_state(stp_psm) < STP_PSM_MAX_STATE) && (_stp_psm_get_state(stp_psm) >= 0)) { + STP_PSM_PR_DBG("state = %s, action=%s\n\r", + g_psm_state[_stp_psm_get_state(stp_psm)], g_psm_action[action]); + } + /* If STP trigger WAKEUP and SLEEP, to do the job below */ + switch (_stp_psm_get_state(stp_psm)) { + /* stp trigger */ + case ACT_INACT: + if (action == SLEEP) { + STP_PSM_PR_LOUD("Action = %s, ACT_INACT state, ready to INACT\n\r", + g_psm_action[action]); + osal_clear_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + osal_set_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* wake_up(&stp_psm->wait_wmt_q); */ + osal_trigger_event(&stp_psm->wait_wmt_q); + } else if (action == ROLL_BACK) { + STP_PSM_PR_LOUD("Action = %s, ACT_INACT state, back to ACT\n\r", + g_psm_action[action]); + /* stp_psm->flag &= ~STP_PSM_WMT_EVENT_ROLL_BACK_EN; */ + osal_set_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* wake_up(&stp_psm->wait_wmt_q); */ + osal_trigger_event(&stp_psm->wait_wmt_q); + } else { + if (action < STP_PSM_MAX_ACTION) { + STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n", + g_psm_action[action], + stp_psm->work_state, stp_psm->flag.data); + } else { + STP_PSM_PR_ERR("Invalid Action!!\n\r"); + } + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + + retval = STP_PSM_OPERATION_FAIL; + } + break; + /* stp trigger */ + case INACT_ACT: + if (action == WAKEUP) { + STP_PSM_PR_LOUD("Action = %s, INACT_ACT state, ready to ACT\n\r", + g_psm_action[action]); + osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + osal_set_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* wake_up(&stp_psm->wait_wmt_q); */ + osal_trigger_event(&stp_psm->wait_wmt_q); + } else if (action == HOST_AWAKE) { + STP_PSM_PR_LOUD("Action = %s, INACT_ACT state, ready to ACT\n\r", + g_psm_action[action]); + osal_clear_bit(STP_PSM_WMT_EVENT_SLEEP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + osal_set_bit(STP_PSM_WMT_EVENT_WAKEUP_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* wake_up(&stp_psm->wait_wmt_q); */ + osal_trigger_event(&stp_psm->wait_wmt_q); + } else if (action == ROLL_BACK) { + STP_PSM_PR_LOUD("Action = %s, INACT_ACT state, back to INACT\n\r", + g_psm_action[action]); + /* stp_psm->flag &= ~STP_PSM_WMT_EVENT_ROLL_BACK_EN; */ + osal_set_bit(STP_PSM_WMT_EVENT_ROLL_BACK_EN, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + /* wake_up(&stp_psm->wait_wmt_q); */ + osal_trigger_event(&stp_psm->wait_wmt_q); + } else { + if (action < STP_PSM_MAX_ACTION) { + STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n", + g_psm_action[action], + stp_psm->work_state, stp_psm->flag.data); + } else { + STP_PSM_PR_ERR("Invalid Action!!\n\r"); + } + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + retval = STP_PSM_OPERATION_FAIL; + } + break; + case INACT: + if (action < STP_PSM_MAX_ACTION) { + STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n", + g_psm_action[action], + stp_psm->work_state, stp_psm->flag.data); + } else { + STP_PSM_PR_ERR("Invalid Action!!\n\r"); + } + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + retval = -1; + break; + case ACT: + if (action < STP_PSM_MAX_ACTION) { + STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n", + g_psm_action[action], + stp_psm->work_state, stp_psm->flag.data); + } else { + STP_PSM_PR_ERR("Invalid Action!!\n\r"); + } + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + + retval = STP_PSM_OPERATION_FAIL; + break; + default: + /*invalid */ + if (action < STP_PSM_MAX_ACTION) { + STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n", + g_psm_action[action], + stp_psm->work_state, stp_psm->flag.data); + } else { + STP_PSM_PR_ERR("Invalid Action!!\n\r"); + } + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + + retval = STP_PSM_OPERATION_FAIL; + break; + } + return retval; +} + +static inline INT32 _stp_psm_notify_wmt(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action) +{ + INT32 ret = STP_PSM_OPERATION_SUCCESS; + + if (stp_psm == NULL) + return STP_PSM_OPERATION_FAIL; + + switch (_stp_psm_get_state(stp_psm)) { + case ACT: + + if (action == SLEEP) { + osal_lock_sleepable_lock(&stp_psm->user_lock); + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) { + STP_PSM_PR_ERR("psm monitor disabled, can't do sleep op\n"); + osal_unlock_sleepable_lock(&stp_psm->user_lock); + return STP_PSM_OPERATION_FAIL; + } + + _stp_psm_set_state(stp_psm, ACT_INACT); + osal_unlock_sleepable_lock(&stp_psm->user_lock); + _stp_psm_release_data(stp_psm); + + if (stp_psm->wmt_notify) { + ret = stp_psm->wmt_notify(SLEEP); + if (!ret) + _stp_psm_wait_wmt_event_wq(stp_psm); + else + STP_PSM_PR_ERR("stp_psm->wmt_notify return fail\n"); + + } else { + STP_PSM_PR_ERR("stp_psm->wmt_notify = NULL\n"); + ret = STP_PSM_OPERATION_FAIL; + } + } else if (action == WAKEUP || action == HOST_AWAKE) { + STP_PSM_PR_DBG("In ACT state, dont do WAKEUP/HOST_AWAKE again\n"); + _stp_psm_release_data(stp_psm); + } else { + STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n", + g_psm_action[action], + stp_psm->work_state, stp_psm->flag.data); + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + ret = STP_PSM_OPERATION_FAIL; + + } + + break; + + case INACT: + + if (action == WAKEUP) { + _stp_psm_set_state(stp_psm, INACT_ACT); + + if (stp_psm->wmt_notify) { + STP_PSM_PR_DBG("wakeup +wake_lock(%d)\n", + osal_wake_lock_count(&stp_psm->wake_lock)); + osal_wake_lock(&stp_psm->wake_lock); + STP_PSM_PR_DBG("wakeup +wake_lock(%d)#\n", + osal_wake_lock_count(&stp_psm->wake_lock)); + + STP_PSM_PR_DBG("mt_combo_plt_exit_deep_idle++\n"); + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + mt_combo_plt_exit_deep_idle(COMBO_IF_BTIF); + else { + switch (wmt_plat_get_comm_if_type()) { + case STP_UART_IF_TX: + mt_combo_plt_exit_deep_idle(COMBO_IF_UART); + break; + case STP_SDIO_IF_TX: + mt_combo_plt_exit_deep_idle(COMBO_IF_MSDC); + break; + default: + break; + } + } + STP_PSM_PR_DBG("mt_combo_plt_exit_deep_idle--\n"); + + ret = stp_psm->wmt_notify(WAKEUP); + if (!ret) + _stp_psm_wait_wmt_event_wq(stp_psm); + else + STP_PSM_PR_ERR("stp_psm->wmt_notify return fail\n"); + } else { + STP_PSM_PR_ERR("stp_psm->wmt_notify = NULL\n"); + ret = STP_PSM_OPERATION_FAIL; + } + } else if (action == HOST_AWAKE) { + _stp_psm_set_state(stp_psm, INACT_ACT); + + if (stp_psm->wmt_notify) { + STP_PSM_PR_DBG("host awake +wake_lock(%d)\n", + osal_wake_lock_count(&stp_psm->wake_lock)); + osal_wake_lock(&stp_psm->wake_lock); + STP_PSM_PR_DBG("host awake +wake_lock(%d)#\n", + osal_wake_lock_count(&stp_psm->wake_lock)); + + STP_PSM_PR_DBG("mt_combo_plt_exit_deep_idle++\n"); + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + mt_combo_plt_exit_deep_idle(COMBO_IF_BTIF); + else { + switch (wmt_plat_get_comm_if_type()) { + case STP_UART_IF_TX: + mt_combo_plt_exit_deep_idle(COMBO_IF_UART); + break; + case STP_SDIO_IF_TX: + mt_combo_plt_exit_deep_idle(COMBO_IF_MSDC); + break; + default: + break; + } + } + STP_PSM_PR_DBG("mt_combo_plt_exit_deep_idle--\n"); + + ret = stp_psm->wmt_notify(HOST_AWAKE); + if (!ret) + _stp_psm_wait_wmt_event_wq(stp_psm); + else + STP_PSM_PR_ERR("stp_psm->wmt_notify return fail\n"); + } else { + STP_PSM_PR_ERR("stp_psm->wmt_notify = NULL\n"); + ret = STP_PSM_OPERATION_FAIL; + } + } else if (action == SLEEP) { + STP_PSM_PR_INFO("In INACT state, dont do SLEEP again\n"); + } else { + STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n", + g_psm_action[action], + stp_psm->work_state, stp_psm->flag.data); + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + ret = STP_PSM_OPERATION_FAIL; + } + + break; + + default: + + /*invalid */ + STP_PSM_PR_ERR("Action = %s, state = %d, flag = %ld, abnormal!\n", + g_psm_action[action], + stp_psm->work_state, stp_psm->flag.data); + _stp_psm_dbg_out_printk(g_stp_psm_dbg); + ret = STP_PSM_OPERATION_FAIL; + + break; + } + return ret; +} + +static inline VOID _stp_psm_stp_is_idle(ULONG data) +{ + MTKSTP_PSM_T *stp_psm = (MTKSTP_PSM_T *) data; + + osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) { + STP_PSM_PR_DBG("STP-PSM DISABLE!\n"); + return; + } + + if (stp_traffic_start != stp_traffic_current) { + STP_PSM_PR_DBG("Timer extension due to ongoing traffic (%d, %d)\n", + stp_traffic_start, stp_traffic_current); + stp_psm_start_monitor(stp_psm); + return; + } + + STP_PSM_PR_DBG("**IDLE is over %d msec, go to sleep!!!**\n", stp_psm->idle_time_to_sleep); + osal_ftrace_print("**IDLE is over %d msec, go to sleep!!!**\n", stp_psm->idle_time_to_sleep); + _stp_psm_notify_wmt_sleep_wq(stp_psm); +} + +static inline INT32 _stp_psm_init_monitor(MTKSTP_PSM_T *stp_psm) +{ + if (!stp_psm) + return STP_PSM_OPERATION_FAIL; + STP_PSM_PR_DBG("init monitor\n"); + stp_psm->psm_timer.timeoutHandler = _stp_psm_stp_is_idle; + stp_psm->psm_timer.timeroutHandlerData = (ULONG)stp_psm; + osal_timer_create(&stp_psm->psm_timer); + return STP_PSM_OPERATION_SUCCESS; +} + +static inline INT32 _stp_psm_deinit_monitor(MTKSTP_PSM_T *stp_psm) +{ + if (!stp_psm) + return STP_PSM_OPERATION_FAIL; + STP_PSM_PR_INFO("deinit monitor\n"); + osal_timer_stop_sync(&stp_psm->psm_timer); + return 0; +} +static inline INT32 _stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm) +{ + INT32 iRet = -1; + /* osal_lock_unsleepable_lock(&stp_psm->flagSpinlock); */ + if (osal_test_bit(STP_PSM_BLOCK_DATA_EN, &stp_psm->flag)) + iRet = 1; + else + iRet = 0; + /* osal_unlock_unsleepable_lock(&stp_psm->flagSpinlock); */ + return iRet; +} + +static inline INT32 _stp_psm_is_disable(MTKSTP_PSM_T *stp_psm) +{ + if (osal_test_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag)) + return 1; + return 0; +} + +static inline INT32 _stp_psm_do_wait(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state) +{ +#define POLL_WAIT 20 /* 200 */ +#define POLL_WAIT_TIME 2000 + INT32 i = 0; + INT32 limit = POLL_WAIT_TIME / POLL_WAIT; + UINT64 sec = 0; + ULONG usec = 0; + + osal_get_local_time(&sec, &usec); + while (_stp_psm_get_state(stp_psm) != state && i < limit && mtk_wcn_stp_is_enable()) { + i++; + if (i < 3) + STP_PSM_PR_INFO("STP is waiting state for %s, i=%d, state = %d\n", + g_psm_state[state], i, _stp_psm_get_state(stp_psm)); + osal_sleep_ms(POLL_WAIT); + if (i == 10) { + STP_PSM_PR_WARN("-Wait for %s takes %d msec\n", g_psm_state[state], i * POLL_WAIT); + _stp_psm_opid_dbg_out_printk(g_stp_psm_opid_dbg); + } + } + if (mtk_wcn_stp_is_enable() == 0) { + STP_PSM_PR_INFO("STP disable, maybe do chip reset"); + return STP_PSM_OPERATION_FAIL; + } + + if (i == limit) { + STP_PSM_PR_WARN("-Wait for %s takes %llu usec\n", g_psm_state[state], osal_elapsed_us(sec, usec)); + mtk_wcn_wmt_dump_wmtd_backtrace(); + _stp_psm_opid_dbg_out_printk(g_stp_psm_opid_dbg); + return STP_PSM_OPERATION_FAIL; + } + if (i > 0) + STP_PSM_PR_INFO("+Total waits for %s takes %llu usec\n", + g_psm_state[state], osal_elapsed_us(sec, usec)); + return STP_PSM_OPERATION_SUCCESS; +} + +static inline INT32 _stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm) +{ + INT32 ret = 0; + INT32 retry = 10; + P_OSAL_OP_Q pOpQ; + P_OSAL_OP pOp; + + STP_PSM_PR_LOUD("*** Do Force Wakeup!***\n\r"); + /* <1>If timer is active, we will stop it. */ + _stp_psm_stop_monitor(stp_psm); + osal_lock_unsleepable_lock(&(stp_psm->wq_spinlock)); + pOpQ = &stp_psm->rFreeOpQ; + while (!RB_EMPTY(&stp_psm->rActiveOpQ)) { + RB_GET(&stp_psm->rActiveOpQ, pOp); + if (pOp != NULL && !RB_FULL(pOpQ)) + RB_PUT(pOpQ, pOp); + else + STP_PSM_PR_ERR("clear up active queue fail, freeQ full\n"); + } + osal_unlock_unsleepable_lock(&(stp_psm->wq_spinlock)); + /* <5>We issue wakeup request into op queue. and wait for active. */ + do { + ret = _stp_psm_notify_wmt_wakeup_wq(stp_psm); + if (ret == STP_PSM_OPERATION_SUCCESS) { + ret = _stp_psm_do_wait(stp_psm, ACT); + /* STP_PSM_PR_INFO("<< wait ret = %d, num of activeQ = %d\n", ret, + * RB_COUNT(&stp_psm->rActiveOpQ)); + */ + if (ret == STP_PSM_OPERATION_SUCCESS) + break; + } else + STP_PSM_PR_ERR("_stp_psm_notify_wmt_wakeup_wq fail, retry = %d !!\n", retry); + /* STP_PSM_PR_INFO("retry = %d\n", retry); */ + retry--; + if (retry == 0) + break; + } while (1); + if (retry == 0) + return STP_PSM_OPERATION_FAIL; + return STP_PSM_OPERATION_SUCCESS; +} + +static inline INT32 _stp_psm_disable(MTKSTP_PSM_T *stp_psm) +{ + INT32 ret = STP_PSM_OPERATION_FAIL; + P_OSAL_THREAD psm_thread; + + STP_PSM_PR_DBG("PSM Disable start\n\r"); + ret = osal_lock_sleepable_lock(&stp_psm->user_lock); + if (ret) { + STP_PSM_PR_ERR("--->lock stp_psm->user_lock failed, ret=%d\n", ret); + return ret; + } + osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + ret = _stp_psm_do_wakeup(stp_psm); + osal_unlock_sleepable_lock(&stp_psm->user_lock); + if (ret == STP_PSM_OPERATION_SUCCESS) + STP_PSM_PR_DBG("PSM Disable Success\n"); + else { + STP_PSM_PR_ERR("***PSM Disable Fail***\n"); + psm_thread = &stp_psm_i.PSMd; + osal_thread_show_stack(psm_thread); + } + return ret; +} + +static inline INT32 _stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep) +{ + INT32 ret = STP_PSM_OPERATION_FAIL; + + STP_PSM_PR_LOUD("PSM Enable start\n\r"); + ret = osal_lock_sleepable_lock(&stp_psm->user_lock); + if (ret) { + STP_PSM_PR_ERR("--->lock stp_psm->user_lock failed, ret=%d\n", ret); + return ret; + } + osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + ret = _stp_psm_do_wakeup(stp_psm); + if (ret == STP_PSM_OPERATION_SUCCESS) { + osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR, &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + stp_psm->idle_time_to_sleep = idle_time_to_sleep; + if (osal_wake_lock_count(&stp_psm->wake_lock) == 0) { + STP_PSM_PR_DBG("psm_en+wake_lock(%d)\n", + osal_wake_lock_count(&stp_psm->wake_lock)); + osal_wake_lock(&stp_psm->wake_lock); + STP_PSM_PR_DBG("psm_en+wake_lock(%d)#\n", + osal_wake_lock_count(&stp_psm->wake_lock)); + } + _stp_psm_start_monitor(stp_psm); + STP_PSM_PR_DBG("PSM Enable succeed\n\r"); + } else + STP_PSM_PR_ERR("***PSM Enable Fail***\n"); + osal_unlock_sleepable_lock(&stp_psm->user_lock); + return ret; +} + +INT32 _stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm) +{ + return osal_lock_sleepable_lock(&stp_psm->stp_psm_lock); +} + +INT32 _stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm) +{ + osal_unlock_sleepable_lock(&stp_psm->stp_psm_lock); + return 0; +} + +MTK_WCN_BOOL _stp_psm_is_quick_ps_support(VOID) +{ + if (stp_psm->is_wmt_quick_ps_support) + return (*(stp_psm->is_wmt_quick_ps_support)) (); + STP_PSM_PR_DBG("stp_psm->is_wmt_quick_ps_support is NULL, return false\n\r"); + return MTK_WCN_BOOL_FALSE; +} + + +MTK_WCN_BOOL stp_psm_is_quick_ps_support(VOID) +{ + return _stp_psm_is_quick_ps_support(); +} + +#if PSM_USE_COUNT_PACKAGE +INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir) +{ + /* easy the variable maintain beween stp tx, rx thread. */ + /* so we create variable for tx, rx respectively. */ + static INT32 tx_cnt; + static INT32 rx_cnt; + INT32 tx_cnt_th = MTK_COMBO_PSM_TX_TH_DEFAULT; + INT32 rx_cnt_th = MTK_COMBO_PSM_RX_TH_DEFAULT; + static INT32 is_tx_first = 1; + static INT32 is_rx_first = 1; + static ULONG tx_end_time; + static ULONG rx_end_time; + long res; + + /* */ + /* BT A2DP TX CNT = 220, RX CNT = 843 */ + /* BT FTP Transferring TX CNT = 574, RX CNT = 2233 (1228~1588) */ + /* BT FTP Receiving TX CNT = 204, RX CNT = 3301 (2072~2515) */ + /* BT OPP Tx TX_CNT= 330, RX CNT = 1300~1800 */ + /* BT OPP Rx TX_CNT= (109~157), RX CNT = 1681~2436 */ +/* #if defined(MTK_COMBO_PSM_RX_TH) +* osal_strtol(MTK_COMBO_PSM_RX_TH, 10, &res); +* rx_cnt_th = (INT32)res; +* #endif +* #if defined(MTK_COMBO_PSM_TX_TH) +* osal_strtol(MTK_COMBO_PSM_TX_TH, 10, &res); +* tx_cnt_th = (INT32)res; +* #endif +*/ + STP_PSM_PR_DBG("RX TH:%d; TX TH:%d\n\r", rx_cnt_th, tx_cnt_th); + stp_traffic_current++; + if (dir == 0) { /* tx */ + tx_cnt++; + if (((long)jiffies - (long)tx_end_time >= 0) || (is_tx_first)) { + tx_end_time = jiffies + (3 * HZ); + STP_PSM_PR_INFO("tx cnt = %d in the previous 3 sec,tx_th = %d\n", tx_cnt, + tx_cnt_th); + /* if(tx_cnt > 400)//for high traffic , not to do sleep. */ + if (tx_cnt > tx_cnt_th) { + osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, + &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + stp_psm_start_monitor(stp_psm); + } else { + osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, + &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + } + tx_cnt = 0; + if (is_tx_first) + is_tx_first = 0; + } + } else { + rx_cnt++; + + if (((long)jiffies - (long)rx_end_time >= 0) || (is_rx_first)) { + rx_end_time = jiffies + (3 * HZ); + STP_PSM_PR_INFO("rx cnt = %d in the previous 3 sec, rx_th = %d\n", rx_cnt, + rx_cnt_th); + + /* if(rx_cnt > 2000)//for high traffic , not to do sleep. */ + if (rx_cnt > rx_cnt_th) { /* for high traffic , not to do sleep. */ + osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, + &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + stp_psm_start_monitor(stp_psm); + } else { + osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_RX_HIGH_DENSITY, + &stp_psm->flag); + _stp_psm_dbg_dmp_in(g_stp_psm_dbg, stp_psm->flag.data, __LINE__); + } + rx_cnt = 0; + if (is_rx_first) + is_rx_first = 0; + } + } + + return 0; +} +#else +static struct timespec64 tv_now, tv_end; +static INT32 sample_start; +static INT32 tx_sum_len; +static INT32 rx_sum_len; + +INT32 stp_psm_disable_by_tx_rx_density(MTKSTP_PSM_T *stp_psm, INT32 dir, INT32 length) +{ + stp_traffic_current++; + if (sample_start) { + if (dir) + rx_sum_len += length; + else + tx_sum_len += length; + + //do_gettimeofday(&tv_now); + ktime_get_ts64(&tv_now); + /* STP_PSM_PR_INFO("tv_now:%d.%d tv_end:%d.%d\n", tv_now.tv_sec, tv_now.tv_usec, + * tv_end.tv_sec,tv_end.tv_usec); + */ + if (((tv_now.tv_sec == tv_end.tv_sec) && (tv_now.tv_nsec > tv_end.tv_nsec)) || + (tv_now.tv_sec > tv_end.tv_sec)) { + STP_PSM_PR_INFO("STP speed rx:%d tx:%d\n", rx_sum_len, tx_sum_len); + if ((rx_sum_len + tx_sum_len) > RTX_SPEED_THRESHOLD) { + STP_PSM_PR_INFO("High speed,Disable monitor\n"); + osal_set_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); + stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP_1000; + stp_psm_start_monitor(stp_psm); + } else { + STP_PSM_PR_INFO("Low speed,Enable monitor\n"); + stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP; + osal_clear_bit(STP_PSM_WMT_EVENT_DISABLE_MONITOR_TX_HIGH_DENSITY, &stp_psm->flag); + } + wmt_lib_ps_set_idle_time(stp_psm->idle_time_to_sleep); + sample_start = 0; + rx_sum_len = 0; + tx_sum_len = 0; + } + } else { + sample_start = 1; + //do_gettimeofday(&tv_now); + ktime_get_ts64(&tv_now); + tv_end = tv_now; + tv_end.tv_sec += SAMPLE_DURATION; + } + + return 0; +} +#endif + +/*external function for WMT module to do sleep/wakeup*/ +INT32 stp_psm_set_state(MTKSTP_PSM_T *stp_psm, MTKSTP_PSM_STATE_T state) +{ + return _stp_psm_set_state(stp_psm, state); +} + + +INT32 stp_psm_thread_lock_aquire(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_thread_lock_aquire(stp_psm); +} + + +INT32 stp_psm_thread_lock_release(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_thread_lock_release(stp_psm); +} + + + +INT32 stp_psm_do_wakeup(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_do_wakeup(stp_psm); +} + +INT32 stp_psm_notify_stp(MTKSTP_PSM_T *stp_psm, const MTKSTP_PSM_ACTION_T action) +{ + + return _stp_psm_notify_stp(stp_psm, action); +} + +INT32 stp_psm_notify_wmt_wakeup(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_notify_wmt_wakeup_wq(stp_psm); +} + +INT32 stp_psm_notify_wmt_sleep(MTKSTP_PSM_T *stp_psm) +{ + + return _stp_psm_notify_wmt_sleep_wq(stp_psm); +} + +INT32 stp_psm_start_monitor(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_start_monitor(stp_psm); +} + +INT32 stp_psm_is_to_block_traffic(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_is_to_block_traffic(stp_psm); +} + +INT32 stp_psm_is_disable(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_is_disable(stp_psm); +} + +INT32 stp_psm_has_pending_data(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_has_pending_data(stp_psm); +} + +INT32 stp_psm_release_data(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_release_data(stp_psm); +} + +INT32 +stp_psm_hold_data(MTKSTP_PSM_T *stp_psm, const PUINT8 buffer, const UINT32 len, const UINT8 type) +{ + return _stp_psm_hold_data(stp_psm, buffer, len, type); +} + +INT32 stp_psm_disable(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_disable(stp_psm); +} + +INT32 stp_psm_enable(MTKSTP_PSM_T *stp_psm, INT32 idle_time_to_sleep) +{ + return _stp_psm_enable(stp_psm, idle_time_to_sleep); +} + +INT32 stp_psm_reset(MTKSTP_PSM_T *stp_psm) +{ + stp_psm_set_sleep_enable(stp_psm); + + return _stp_psm_reset(stp_psm); +} + +INT32 stp_psm_sleep_for_thermal(MTKSTP_PSM_T *stp_psm) +{ + return _stp_psm_notify_wmt_sleep_wq(stp_psm); +} + + +INT32 stp_psm_set_sleep_enable(MTKSTP_PSM_T *stp_psm) +{ + INT32 ret = 0; + + if (stp_psm) { + stp_psm->sleep_en = 1; + STP_PSM_PR_DBG("\n"); + ret = 0; + } else { + STP_PSM_PR_INFO("Null pointer\n"); + ret = -1; + } + + return ret; +} + + +INT32 stp_psm_set_sleep_disable(MTKSTP_PSM_T *stp_psm) +{ + INT32 ret = 0; + + if (stp_psm) { + stp_psm->sleep_en = 0; + STP_PSM_PR_DBG("\n"); + ret = 0; + } else { + STP_PSM_PR_INFO("Null pointer\n"); + ret = -1; + } + + return ret; +} + + +/* stp_psm_check_sleep_enable - to check if sleep cmd is enabled or not + * @ stp_psm - pointer of psm + * + * return 1 if sleep is enabled; else return 0 if disabled; else error code + */ +INT32 stp_psm_check_sleep_enable(MTKSTP_PSM_T *stp_psm) +{ + INT32 ret = 0; + + if (stp_psm) { + ret = stp_psm->sleep_en; + STP_PSM_PR_DBG("%s\n", ret ? "enabled" : "disabled"); + } else { + STP_PSM_PR_INFO("Null pointer\n"); + ret = -1; + } + + return ret; +} + +static INT32 _stp_psm_dbg_dmp_in(STP_PSM_RECORD_T *stp_psm_dbg, UINT32 flag, UINT32 line_num) +{ + INT32 index = 0; + struct timespec64 now; + + if (stp_psm_dbg) { + osal_lock_unsleepable_lock(&stp_psm_dbg->lock); + ktime_get_ts64(&now); + index = stp_psm_dbg->in - 1; + index = (index + STP_PSM_DBG_SIZE) % STP_PSM_DBG_SIZE; + STP_PSM_PR_DBG("index(%d)\n", index); + stp_psm_dbg->queue[stp_psm_dbg->in].prev_flag = stp_psm_dbg->queue[index].cur_flag; + stp_psm_dbg->queue[stp_psm_dbg->in].cur_flag = flag; + stp_psm_dbg->queue[stp_psm_dbg->in].line_num = line_num; + stp_psm_dbg->queue[stp_psm_dbg->in].package_no = g_record_num++; + stp_psm_dbg->queue[stp_psm_dbg->in].sec = now.tv_sec; + stp_psm_dbg->queue[stp_psm_dbg->in].usec = now.tv_nsec / NSEC_PER_USEC; + stp_psm_dbg->size++; + STP_PSM_PR_DBG("pre_Flag = %d, cur_flag = %d\n", stp_psm_dbg->queue[stp_psm_dbg->in].prev_flag, + stp_psm_dbg->queue[stp_psm_dbg->in].cur_flag); + stp_psm_dbg->size = (stp_psm_dbg->size > STP_PSM_DBG_SIZE) ? STP_PSM_DBG_SIZE : stp_psm_dbg->size; + stp_psm_dbg->in = (stp_psm_dbg->in >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (stp_psm_dbg->in + 1); + STP_PSM_PR_DBG("record size = %d, in = %d num = %d\n", stp_psm_dbg->size, stp_psm_dbg->in, line_num); + + osal_unlock_unsleepable_lock(&stp_psm_dbg->lock); + } + return 0; +} + +static INT32 _stp_psm_dbg_out_printk(STP_PSM_RECORD_T *stp_psm_dbg) +{ + + UINT32 dumpSize = 0; + UINT32 inIndex = 0; + UINT32 outIndex = 0; + + if (!stp_psm_dbg) { + STP_PSM_PR_ERR("NULL g_stp_psm_dbg reference\n"); + return -1; + } + osal_lock_unsleepable_lock(&stp_psm_dbg->lock); + + inIndex = stp_psm_dbg->in; + dumpSize = stp_psm_dbg->size; + if (dumpSize == STP_PSM_DBG_SIZE) + outIndex = inIndex; + else + outIndex = ((inIndex + STP_PSM_DBG_SIZE) - dumpSize) % STP_PSM_DBG_SIZE; + + STP_PSM_PR_INFO("loged record size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex); + while (dumpSize > 0) { + + pr_info("STP-PSM:%d.%ds, n(%d)pre_flag(%d)cur_flag(%d)line_no(%d)\n", + stp_psm_dbg->queue[outIndex].sec, + stp_psm_dbg->queue[outIndex].usec, + stp_psm_dbg->queue[outIndex].package_no, + stp_psm_dbg->queue[outIndex].prev_flag, + stp_psm_dbg->queue[outIndex].cur_flag, stp_psm_dbg->queue[outIndex].line_num); + + outIndex = (outIndex >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (outIndex + 1); + dumpSize--; + + } + + osal_unlock_unsleepable_lock(&stp_psm_dbg->lock); + + return 0; +} + +static INT32 _stp_psm_opid_dbg_dmp_in(P_STP_PSM_OPID_RECORD p_opid_dbg, UINT32 opid, UINT32 line_num) +{ + INT32 index = 0; + struct timespec64 now; + UINT64 ts; + ULONG nsec; + + osal_get_local_time(&ts, &nsec); + if (p_opid_dbg) { + osal_lock_unsleepable_lock(&p_opid_dbg->lock); + ktime_get_ts64(&now); + index = p_opid_dbg->in - 1; + index = (index + STP_PSM_DBG_SIZE) % STP_PSM_DBG_SIZE; + STP_PSM_PR_DBG("index(%d)\n", index); + p_opid_dbg->queue[p_opid_dbg->in].prev_flag = p_opid_dbg->queue[index].cur_flag; + p_opid_dbg->queue[p_opid_dbg->in].cur_flag = opid; + p_opid_dbg->queue[p_opid_dbg->in].line_num = line_num; + p_opid_dbg->queue[p_opid_dbg->in].package_no = g_opid_record_num++; + p_opid_dbg->queue[p_opid_dbg->in].sec = now.tv_sec; + p_opid_dbg->queue[p_opid_dbg->in].usec = now.tv_nsec / NSEC_PER_USEC; + p_opid_dbg->queue[p_opid_dbg->in].pid = current->pid; + p_opid_dbg->queue[p_opid_dbg->in].l_sec = ts; + p_opid_dbg->queue[p_opid_dbg->in].l_nsec = nsec; + p_opid_dbg->size++; + STP_PSM_PR_DBG("pre_opid = %d, cur_opid = %d\n", p_opid_dbg->queue[p_opid_dbg->in].prev_flag, + p_opid_dbg->queue[p_opid_dbg->in].cur_flag); + p_opid_dbg->size = (p_opid_dbg->size > STP_PSM_DBG_SIZE) ? STP_PSM_DBG_SIZE : p_opid_dbg->size; + p_opid_dbg->in = (p_opid_dbg->in >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (p_opid_dbg->in + 1); + STP_PSM_PR_DBG("opid record size = %d, in = %d num = %d\n", p_opid_dbg->size, p_opid_dbg->in, + line_num); + + osal_unlock_unsleepable_lock(&p_opid_dbg->lock); + } + return 0; + +} + +static INT32 _stp_psm_opid_dbg_out_printk(P_STP_PSM_OPID_RECORD p_opid_dbg) +{ + UINT32 dumpSize = 0; + UINT32 inIndex = 0; + UINT32 outIndex = 0; + + if (!p_opid_dbg) { + STP_PSM_PR_ERR("NULL p_opid_dbg reference\n"); + return -1; + } + osal_lock_unsleepable_lock(&p_opid_dbg->lock); + + inIndex = p_opid_dbg->in; + dumpSize = p_opid_dbg->size; + if (dumpSize == STP_PSM_DBG_SIZE) + outIndex = inIndex; + else + outIndex = ((inIndex + STP_PSM_DBG_SIZE) - dumpSize) % STP_PSM_DBG_SIZE; + + STP_PSM_PR_INFO("loged record size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex); + while (dumpSize > 0) { + + pr_info("STP-PSM:%d.%ds, time[%llu.%06lu], n(%d)pre_flag(%d)cur_flag(%d)line_no(%d) pid(%d)\n", + p_opid_dbg->queue[outIndex].sec, + p_opid_dbg->queue[outIndex].usec, + p_opid_dbg->queue[outIndex].l_sec, + p_opid_dbg->queue[outIndex].l_nsec, + p_opid_dbg->queue[outIndex].package_no, + p_opid_dbg->queue[outIndex].prev_flag, + p_opid_dbg->queue[outIndex].cur_flag, + p_opid_dbg->queue[outIndex].line_num, p_opid_dbg->queue[outIndex].pid); + + outIndex = (outIndex >= (STP_PSM_DBG_SIZE - 1)) ? (0) : (outIndex + 1); + dumpSize--; + + } + + osal_unlock_unsleepable_lock(&p_opid_dbg->lock); + + return 0; + +} + +VOID stp_psm_print_op_history(VOID) +{ + osal_op_history_print(&stp_psm->op_history, "_stp_psm_proc"); +} + +MTKSTP_PSM_T *stp_psm_init(VOID) +{ + INT32 err = 0; + INT32 i = 0; + INT32 ret = -1; + + STP_PSM_PR_DBG("psm init\n"); + + stp_psm->work_state = ACT; + stp_psm->wmt_notify = wmt_lib_ps_stp_cb; + stp_psm->is_wmt_quick_ps_support = wmt_lib_is_quick_ps_support; + stp_psm->idle_time_to_sleep = STP_PSM_IDLE_TIME_SLEEP; + stp_psm->update_wmt_fw_patch_chip_rst = wmt_lib_update_fw_patch_chip_rst; + stp_psm->flag.data = 0; + stp_psm->stp_tx_cb = NULL; + stp_psm_set_sleep_enable(stp_psm); + + ret = osal_fifo_init(&stp_psm->hold_fifo, NULL, STP_PSM_FIFO_SIZE); + if (ret < 0) { + STP_PSM_PR_ERR("FIFO INIT FAILS\n"); + goto ERR_EXIT4; + } + + osal_fifo_reset(&stp_psm->hold_fifo); + osal_sleepable_lock_init(&stp_psm->user_lock); + /*psm_fifo_lock_init(stp_psm);*/ + osal_sleepable_lock_init(&stp_psm->hold_fifo_spinlock_global); + osal_unsleepable_lock_init(&stp_psm->wq_spinlock); + osal_sleepable_lock_init(&stp_psm->stp_psm_lock); + +/* osal_unsleepable_lock_init(&stp_psm->flagSpinlock); */ + + osal_memcpy(stp_psm->wake_lock.name, "MT662x", 6); + stp_psm->wake_lock.init_flag = 0; + osal_wake_lock_init(&stp_psm->wake_lock); + osal_event_init(&stp_psm->STPd_event); + RB_INIT(&stp_psm->rFreeOpQ, STP_OP_BUF_SIZE); + RB_INIT(&stp_psm->rActiveOpQ, STP_OP_BUF_SIZE); + /* Put all to free Q */ + for (i = 0; i < STP_OP_BUF_SIZE; i++) { + osal_signal_init(&(stp_psm->arQue[i].signal)); + _stp_psm_put_op(stp_psm, &stp_psm->rFreeOpQ, &(stp_psm->arQue[i])); + } + /* stp_psm->current_active_op = NULL; */ + stp_psm->last_active_opId = STP_OPID_PSM_INALID; + osal_op_history_init(&stp_psm->op_history, 16); + /*Generate PSM thread, to servie STP-CORE and WMT-CORE for sleeping, waking up and host awake */ + stp_psm->PSMd.pThreadData = (PVOID) stp_psm; + stp_psm->PSMd.pThreadFunc = (PVOID) _stp_psm_proc; + osal_memcpy(stp_psm->PSMd.threadName, PSM_THREAD_NAME, osal_strlen(PSM_THREAD_NAME)); + + ret = osal_thread_create(&stp_psm->PSMd); + if (ret < 0) { + STP_PSM_PR_ERR("osal_thread_create fail...\n"); + goto ERR_EXIT5; + } + /* init_waitqueue_head(&stp_psm->wait_wmt_q); */ + stp_psm->wait_wmt_q.timeoutValue = STP_PSM_WAIT_EVENT_TIMEOUT; + osal_event_init(&stp_psm->wait_wmt_q); + + err = _stp_psm_init_monitor(stp_psm); + if (err) { + STP_PSM_PR_ERR("__stp_psm_init ERROR\n"); + goto ERR_EXIT6; + } + /* Start STPd thread */ + ret = osal_thread_run(&stp_psm->PSMd); + if (ret < 0) { + STP_PSM_PR_ERR("osal_thread_run FAILS\n"); + goto ERR_EXIT6; + } + + g_stp_psm_dbg = (STP_PSM_RECORD_T *) osal_malloc(osal_sizeof(STP_PSM_RECORD_T)); + if (!g_stp_psm_dbg) { + STP_PSM_PR_ERR("stp psm dbg allocate memory fail!\n"); + return NULL; + } + osal_memset(g_stp_psm_dbg, 0, osal_sizeof(STP_PSM_RECORD_T)); + osal_unsleepable_lock_init(&g_stp_psm_dbg->lock); + + g_stp_psm_opid_dbg = (STP_PSM_OPID_RECORD *) osal_malloc(osal_sizeof(STP_PSM_OPID_RECORD)); + if (!g_stp_psm_opid_dbg) { + STP_PSM_PR_ERR("stp psm dbg allocate memory fail!\n"); + return NULL; + } + osal_memset(g_stp_psm_opid_dbg, 0, osal_sizeof(STP_PSM_OPID_RECORD)); + osal_unsleepable_lock_init(&g_stp_psm_opid_dbg->lock); + + return stp_psm; + +ERR_EXIT6: + + ret = osal_thread_destroy(&stp_psm->PSMd); + if (ret < 0) { + STP_PSM_PR_ERR("osal_thread_destroy FAILS\n"); + goto ERR_EXIT5; + } +ERR_EXIT5: + osal_fifo_deinit(&stp_psm->hold_fifo); +ERR_EXIT4: + + return NULL; +} + +INT32 stp_psm_deinit(MTKSTP_PSM_T *stp_psm) +{ + INT32 ret = -1; + + STP_PSM_PR_INFO("psm deinit\n"); + if (g_stp_psm_dbg) { + osal_unsleepable_lock_deinit(&g_stp_psm_dbg->lock); + osal_free(g_stp_psm_dbg); + g_stp_psm_dbg = NULL; + } + + if (!stp_psm) + return STP_PSM_OPERATION_FAIL; + + ret = osal_thread_destroy(&stp_psm->PSMd); + if (ret < 0) + STP_PSM_PR_ERR("osal_thread_destroy FAILS\n"); + + ret = _stp_psm_deinit_monitor(stp_psm); + if (ret < 0) + STP_PSM_PR_ERR("_stp_psm_deinit_monitor ERROR\n"); + + osal_wake_lock_deinit(&stp_psm->wake_lock); + osal_fifo_deinit(&stp_psm->hold_fifo); + osal_sleepable_lock_deinit(&stp_psm->user_lock); + /*psm_fifo_lock_deinit(stp_psm);*/ + osal_sleepable_lock_deinit(&stp_psm->hold_fifo_spinlock_global); + osal_unsleepable_lock_deinit(&stp_psm->wq_spinlock); + osal_sleepable_lock_deinit(&stp_psm->stp_psm_lock); +/* osal_unsleepable_lock_deinit(&stp_psm->flagSpinlock); */ + + return STP_PSM_OPERATION_SUCCESS; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/stp_core.c b/drivers/misc/mediatek/connectivity/common/common_main/core/stp_core.c new file mode 100644 index 00000000000000..b6e76a78e437f8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/stp_core.c @@ -0,0 +1,3562 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include "osal_typedef.h" +#include "stp_core.h" +#include "psm_core.h" +#include "btm_core.h" +#include "stp_dbg.h" +#include "stp_sdio.h" +#include "stp_btif.h" +#include "wmt_lib.h" +#include "wmt_step.h" +#include "wmt_detect.h" + +#define PFX "[STP] " +#define STP_LOG_DBG 4 +#define STP_LOG_PKHEAD 3 +#define STP_LOG_INFO 2 +#define STP_LOG_WARN 1 +#define STP_LOG_ERR 0 + +#define STP_DEL_SIZE 2 /* STP delimiter length */ +#define STP_MAX_TX_TIMEOUT_LOOP 3 + +INT32 gStpDbgLvl = STP_LOG_INFO; +unsigned int chip_reset_only; +INT32 wmt_dbg_sdio_retry_ctrl = 1; + +#define STP_POLL_CPUPCR_NUM 5 +#define STP_POLL_CPUPCR_DELAY 1 + +/* global variables */ +static const UINT8 stp_delimiter[STP_DEL_SIZE] = { 0x55, 0x55 }; + +static INT32 fgEnableNak; /* 0=enable NAK; 1=disable NAK */ +static INT32 fgEnableDelimiter; /* 0=disable Delimiter; 1=enable Delimiter */ +/* common interface */ +static IF_TX sys_if_tx; +static RX_HAS_PENDING_DATA sys_rx_has_pending_data; +static TX_HAS_PENDING_DATA sys_tx_has_pending_data; +static RX_THREAD_GET sys_rx_thread_get; +/* event/signal */ +static EVENT_SET sys_event_set; +static EVENT_TX_RESUME sys_event_tx_resume; +static FUNCTION_STATUS sys_check_function_status; +/* kernel lib */ +/* INT32 g_block_tx = 0; */ +static mtkstp_context_struct stp_core_ctx = { 0 }; + +#define STP_PSM_CORE(x) ((x).psm) +#define STP_SET_PSM_CORE(x, v) ((x).psm = (v)) + +#define STP_BTM_CORE(x) ((x).btm) +#define STP_SET_BTM_CORE(x, v) ((x).btm = (v)) + +#define STP_IS_ENABLE(x) ((x).f_enable != 0) +#define STP_NOT_ENABLE(x) ((x).f_enable == 0) +#define STP_SET_ENABLE(x, v) ((x).f_enable = (v)) + +#define STP_IS_READY(x) ((x).f_ready != 0) +#define STP_NOT_READY(x) ((x).f_ready == 0) +#define STP_SET_READY(x, v) ((x).f_ready = (v)) + +#define STP_PENDING_TYPE(x) ((x).f_pending_type) +#define STP_SET_PENDING_TYPE(x, v) ((x).f_pending_type = (v)) + +#define STP_BLUE_ANGEL (0) +#define STP_BLUE_Z (1) +#define STP_BT_STK(x) ((x).f_bluez) +#define STP_BT_STK_IS_BLUEZ(x) ((x).f_bluez == (STP_BLUE_Z)) +#define STP_SET_BT_STK(x, v) ((x).f_bluez = (v)) + +#define STP_IS_ENABLE_DBG(x) ((x).f_dbg_en != 0) +#define STP_NOT_ENABLE_DBG(x) ((x).f_dbg_en == 0) +#define STP_SET_ENABLE_DBG(x, v) ((x).f_dbg_en = (v)) + +#define STP_IS_ENABLE_RST(x) ((x).f_autorst_en != 0) +#define STP_NOT_ENABLE_RST(x) ((x).f_autorst_en == 0) +#define STP_SET_ENABLE_RST(x, v) ((x).f_autorst_en = (v)) + +#define STP_SUPPORT_PROTOCOL(x) ((x).f_mode) +#define STP_SET_SUPPORT_PROTOCOL(x, v) ((x).f_mode = (v)) + +#define STP_FW_COREDUMP_FLAG(x) ((x).f_coredump) +#define STP_SET_FW_COREDUMP_FLAG(x, v) ((x).f_coredump = (v)) +#define STP_ENABLE_FW_COREDUMP(x, v) ((x).en_coredump = (v)) +#define STP_ENABLE_FW_COREDUMP_FLAG(x) ((x).en_coredump) +#define STP_EMI_DUMP_FLAG(x) ((x).f_emidump) +#define STP_SET_EMI_DUMP_FLAG(x, v) ((x).f_emidump = (v)) + +#define STP_WMT_LAST_CLOSE(x) ((x).f_wmt_last_close) +#define STP_SET_WMT_LAST_CLOSE(x, v) ((x).f_wmt_last_close = (v)) + +#define STP_ASSERT(x) ((x).f_evt_err_assert) +#define STP_SET_ASSERT(x, v) ((x).f_evt_err_assert = (v)) + +#define STP_ASSERT_IN_PROGRESS(x) ((x).f_assert_in_progress) +#define STP_SET_ASSERT_IN_PROGRESS(x, v) ((x).f_assert_in_progress = (v)) + + +/*[PatchNeed]Need to calculate the timeout value*/ +static UINT32 mtkstp_tx_timeout = MTKSTP_TX_TIMEOUT; +static mtkstp_parser_state prev_state = -1; + + +#define CONFIG_DEBUG_STP_TRAFFIC_SUPPORT +#ifdef CONFIG_DEBUG_STP_TRAFFIC_SUPPORT +static MTKSTP_DBG_T *g_mtkstp_dbg; +#endif +static VOID stp_dbg_pkt_log(INT32 type, INT32 txAck, INT32 seq, INT32 crc, INT32 dir, + const PUINT8 pBuf, INT32 len); +static MTK_WCN_BOOL stp_check_crc(PUINT8 buffer, UINT32 length, UINT16 crc); +static VOID stp_update_tx_queue(UINT32 txseq); +static VOID stp_rest_ctx_state(VOID); +static VOID stp_change_rx_state(mtkstp_parser_state next); +static void stp_tx_timeout_handler(ULONG data); +static VOID stp_dump_data(const PUINT8 buf, const PUINT8 title, const UINT32 len); +static VOID stp_dump_tx_queue(UINT32 txseq); +static INT32 stp_is_apply_powersaving(VOID); +#if 0 +static INT32 stp_is_privileges_cmd(const UINT8 *buffer, const UINT32 length, const UINT8 type); +#endif +static MTK_WCN_BOOL stp_is_tx_res_available(UINT32 length); +static VOID stp_add_to_tx_queue(const PUINT8 buffer, UINT32 length); +static INT32 stp_add_to_rx_queue(PUINT8 buffer, UINT32 length, UINT8 type); +static VOID stp_send_tx_queue(UINT32 txseq); +static VOID stp_send_ack(UINT8 txAck, UINT8 nak); +static INT32 stp_process_rxack(VOID); +static VOID stp_process_packet(VOID); +static VOID stp_process_header_only_packet(VOID); +static VOID stp_sdio_process_packet(VOID); +static VOID stp_trace32_dump(VOID); +static VOID stp_sdio_trace32_dump(VOID); +static LONG stp_parser_dmp_num(PUINT8 str); +static INT32 wmt_parser_data(PUINT8 buffer, UINT32 length, UINT8 type); + +INT32 __weak mtk_wcn_consys_stp_btif_logger_ctrl(enum _ENUM_BTIF_DBG_ID_ flag) +{ + STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_logger_ctrl is not define!!\n"); + return 0; +} +INT32 __weak mtk_wcn_consys_stp_btif_open(VOID) +{ + STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_open is not define!!\n"); + + return 0; +} + +INT32 __weak mtk_wcn_consys_stp_btif_close(VOID) +{ + STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_close is not define!!\n"); + + return 0; +} + +INT32 __weak mtk_wcn_consys_stp_btif_rx_cb_register(MTK_WCN_BTIF_RX_CB rx_cb) +{ + STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_rx_cb_register is not define!!\n"); + return 0; +} + +INT32 __weak mtk_wcn_consys_stp_btif_tx(const PUINT8 pBuf, const UINT32 len, PUINT32 written_len) +{ + STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_tx is not define!!\n"); + + return 0; +} + +INT32 __weak mtk_wcn_consys_stp_btif_wakeup(VOID) +{ + STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_wakeup is not define!!\n"); + + return 0; +} + +INT32 __weak mtk_wcn_consys_stp_btif_lpbk_ctrl(enum _ENUM_BTIF_LPBK_MODE_ mode) +{ + STP_INFO_FUNC("in combo flow, mtk_wcn_consys_stp_btif_lpbk_ctrl is not define!!\n"); + + return 0; +} + +static INT32 stp_ctx_lock_init(mtkstp_context_struct *pctx) +{ +#if CFG_STP_CORE_CTX_SPIN_LOCK +#if defined(CONFIG_PROVE_LOCKING) + osal_unsleepable_lock_init(&((pctx)->stp_mutex)); + return 0; +#else + return osal_unsleepable_lock_init(&((pctx)->stp_mutex)); +#endif +#else +#if defined(CONFIG_PROVE_LOCKING) + osal_sleepable_lock_init(&((pctx)->stp_mutex)); + return 0; +#else + return osal_sleepable_lock_init(&((pctx)->stp_mutex)); +#endif +#endif +} + +static INT32 stp_ctx_lock_deinit(mtkstp_context_struct *pctx) +{ +#if CFG_STP_CORE_CTX_SPIN_LOCK + return osal_unsleepable_lock_deinit(&((pctx)->stp_mutex)); +#else + return osal_sleepable_lock_deinit(&((pctx)->stp_mutex)); +#endif +} + +static INT32 stp_ctx_lock(mtkstp_context_struct *pctx) +{ + /* dump_stack(); */ + /* pr_debug("stp_lock\n\r"); */ +#if CFG_STP_CORE_CTX_SPIN_LOCK + return osal_lock_unsleepable_lock(&((pctx)->stp_mutex)); +#else + return osal_lock_sleepable_lock(&((pctx)->stp_mutex)); +#endif +} + +static INT32 stp_ctx_unlock(mtkstp_context_struct *pctx) +{ + /* dump_stack(); */ + /* pr_debug("stp_unlock\n\r"); */ + +#if CFG_STP_CORE_CTX_SPIN_LOCK + return osal_unlock_unsleepable_lock(&((pctx)->stp_mutex)); +#else + return osal_unlock_sleepable_lock(&((pctx)->stp_mutex)); +#endif +} + + +MTK_WCN_BOOL mtk_wcn_stp_dbg_level(INT32 dbglevel) +{ + if (dbglevel >= 0 && dbglevel <= 4) { + gStpDbgLvl = dbglevel; + STP_INFO_FUNC("gStpDbgLvl = %d\n", gStpDbgLvl); + return MTK_WCN_BOOL_TRUE; + } + STP_INFO_FUNC("invalid stp debug level. gStpDbgLvl = %d\n", gStpDbgLvl); + return MTK_WCN_BOOL_FALSE; +} + +static VOID stp_sdio_process_packet(VOID) +{ + MTK_WCN_BOOL is_function_active = 0; + + if ((stp_core_ctx.parser.type == BT_TASK_INDX) && STP_BT_STK_IS_BLUEZ(stp_core_ctx)) { + INT32 b; + /*Indicate packet to hci_stp */ + if (gStpDbgLvl >= STP_LOG_DBG) + stp_dump_data(stp_core_ctx.rx_buf, "indicate_to_bt_core", stp_core_ctx.rx_counter); + b = mtk_wcn_sys_if_rx(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); + if (b) + STP_ERR_FUNC("mtk_wcn_sys_if_rx is NULL\n"); + } else { + is_function_active = ((*sys_check_function_status)(stp_core_ctx.parser.type, + OP_FUNCTION_ACTIVE) == STATUS_FUNCTION_ACTIVE); + /*check type and function if active? */ + if ((stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) && + (is_function_active == MTK_WCN_BOOL_TRUE)) { + if (stp_core_ctx.parser.type == WMT_TASK_INDX) + wmt_parser_data(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, + stp_core_ctx.parser.type); + else { + stp_add_to_rx_queue(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, + stp_core_ctx.parser.type); + + /*notify corresponding subfunction of incoming data */ + (*sys_event_set)(stp_core_ctx.parser.type); + } + } else { + if (is_function_active == MTK_WCN_BOOL_FALSE) { + STP_ERR_FUNC("function type = %d is inactive, so no en-queue to rx\n", + stp_core_ctx.parser.type); + } else { + STP_ERR_FUNC("mtkstp_process_packet: type = %x, the type is invalid\n", + stp_core_ctx.parser.type); + } + } + } +} + + +static VOID stp_trace32_dump(VOID) +{ + if (STP_IS_ENABLE_DBG(stp_core_ctx) && (stp_core_ctx.parser.type == STP_TASK_INDX)) { + STP_INFO_FUNC("[len=%d][type=%d]%s\n", stp_core_ctx.rx_counter, + stp_core_ctx.parser.type, stp_core_ctx.rx_buf); + } + /*Runtime FW Log */ + else if (STP_IS_ENABLE_DBG(stp_core_ctx) && + (stp_core_ctx.parser.type == INFO_TASK_INDX)) { + stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_FW_LOG, STP_TASK_INDX, 5, 0, 0, 0, + (stp_core_ctx.rx_counter + 1), stp_core_ctx.rx_buf); + mtk_wcn_stp_dbg_dump_package(); + } + /*Normal mode: whole chip reset */ + else { + /*Aee Kernel Warning Message Shown First */ + /* (*sys_dbg_assert_aee)("[MT662x]f/w Assert", stp_core_ctx.rx_buf); */ + mtk_wcn_stp_dbg_dump_package(); + + osal_dbg_assert_aee(stp_core_ctx.rx_buf, stp_core_ctx.rx_buf); + /*Whole Chip Reset Procedure Invoke */ + if (STP_IS_ENABLE_RST(stp_core_ctx)) { + STP_SET_READY(stp_core_ctx, 0); + stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); + } else + STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); + } +} + +static LONG stp_parser_dmp_num(PUINT8 str) +{ + PUINT8 pParserDmpStr = "Dump="; + PUINT8 pStr = NULL; + PUINT8 pDtr = NULL; + PUINT8 pTemp = NULL; + INT32 ret = -1; + UINT32 len = 0; + UINT8 tempBuf[64] = {0}; + LONG res; + + + if (!str) { + STP_DBG_PR_ERR("NULL string source\n"); + return -1; + } + + pStr = str; + pDtr = osal_strstr(pStr, pParserDmpStr); + if (pDtr != NULL) { + pDtr += osal_strlen(pParserDmpStr); + pTemp = pDtr; + while (*pTemp >= '0' && *pTemp <= '9') + pTemp++; + } else { + STP_DBG_PR_WARN("parser string 'Dump=' is not found\n"); + return -2; + } + len = pTemp - pDtr; + osal_memcpy(&tempBuf[0], pDtr, len); + tempBuf[len] = '\0'; + ret = osal_strtol(tempBuf, 10, &res); + if (ret) { + STP_DBG_PR_ERR(" get 'Dump=' from firmware failed (%d)", ret); + return -4; + } + + return res; +} + +static VOID stp_sdio_trace32_dump(VOID) +{ + LONG dmp_num = 0; + int coredump_end_str_len = osal_strlen("coredump end"); + int len; + + if (STP_IS_ENABLE_DBG(stp_core_ctx) && (stp_core_ctx.parser.type == STP_TASK_INDX) && + (mtk_wcn_stp_coredump_flag_get() != 0)) { + if (stp_core_ctx.rx_counter != 0) { + STP_SET_READY(stp_core_ctx, 0); + mtk_wcn_stp_ctx_save(); + if (stp_core_ctx.assert_info_cnt == 0) { + dmp_num = stp_parser_dmp_num(stp_core_ctx.rx_buf); + if (dmp_num > 0 && dmp_num < PARSER_CORE_DUMP_NUM) { + STP_INFO_FUNC("parser dmp_num is %ld\n", dmp_num); + stp_dbg_dump_num(dmp_num); + } else if (dmp_num > PARSER_CORE_DUMP_NUM) { + STP_INFO_FUNC("parser dmp_num is out of range %ld\n", + dmp_num); + stp_dbg_dump_num(PARSER_CORE_DUMP_NUM); + } else { + STP_INFO_FUNC("parser dmp_num not found %ld\n", dmp_num); + stp_dbg_dump_num(CORE_DUMP_NUM); + } + } + /*STP_DBG_FW_ASSERT */ + stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_FW_DMP, STP_TASK_INDX, 0, 0, 0, 0, + (stp_core_ctx.rx_counter + 1), stp_core_ctx.rx_buf); + } + stp_core_ctx.assert_info_cnt++; + if (stp_core_ctx.assert_info_cnt == 20) + STP_INFO_FUNC("only dump 20 packages from the beginning\n"); + else if (stp_core_ctx.assert_info_cnt < 20) + osal_err_print("[len=%d][type=%d]counter[%d]\n%s\n", stp_core_ctx.rx_counter, + stp_core_ctx.parser.type, stp_core_ctx.assert_info_cnt, stp_core_ctx.rx_buf); + + len = stp_core_ctx.rx_counter - coredump_end_str_len - 2; + if ((len >= 0) && + (stp_core_ctx.rx_counter < MTKSTP_BUFFER_SIZE) && + (osal_strncmp("coredump end", stp_core_ctx.rx_buf + + len, coredump_end_str_len) == 0)) { + STP_INFO_FUNC("%d coredump packets received\n", stp_core_ctx.assert_info_cnt); + STP_ERR_FUNC("coredump end\n"); + mtk_wcn_stp_ctx_restore(); + } + } + /*Runtime FW Log */ + else if (STP_IS_ENABLE_DBG(stp_core_ctx) && (stp_core_ctx.parser.type == INFO_TASK_INDX)) { + stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_FW_LOG, STP_TASK_INDX, 5, 0, 0, 0, + (stp_core_ctx.rx_counter + 1), stp_core_ctx.rx_buf); + mtk_wcn_stp_dbg_dump_package(); + } + /*Normal mode: whole chip reset */ + else { + /*Aee Kernel Warning Message Shown First */ + /* (*sys_dbg_assert_aee)("[MT662x]f/w Assert", stp_core_ctx.rx_buf); */ + mtk_wcn_stp_dbg_dump_package(); + if (mtk_wcn_stp_coredump_flag_get() == 0) { + osal_err_print("[len=%d][type=%d]\n%s\n", stp_core_ctx.rx_counter, + stp_core_ctx.parser.type, stp_core_ctx.rx_buf); + STP_ERR_FUNC("fw error happened but coredump disabled\n"); + } else + osal_dbg_assert_aee(stp_core_ctx.rx_buf, stp_core_ctx.rx_buf); + /*Whole Chip Reset Procedure Invoke */ + if (STP_IS_ENABLE_RST(stp_core_ctx)) { + STP_SET_READY(stp_core_ctx, 0); + stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); + } else + STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); + } +} + +static VOID stp_process_header_only_packet(VOID) +{ + if (stp_core_ctx.parser.length == 0) { + INT32 fgTriggerResume = (-1); + /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_lock(&stp_core_ctx); + if (stp_core_ctx.inband_rst_set == 0) { + stp_dbg_pkt_log(STP_TASK_INDX, + stp_core_ctx.parser.ack, + stp_core_ctx.parser.seq, + 5, /* STP type id */ + PKT_DIR_RX, + NULL, + 0); + fgTriggerResume = stp_process_rxack(); + } else { + STP_WARN_FUNC + ("Now it's inband reset process and drop ACK packet.\n"); + } + if (fgTriggerResume == 0) { + /* notify adaptation layer for + * possible tx resume mechanism + */ + (*sys_event_tx_resume) (stp_core_ctx.sequence.winspace); + } + stp_ctx_unlock(&stp_core_ctx); + /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_change_rx_state(MTKSTP_SYNC); + stp_core_ctx.rx_counter = 0; + } else { + stp_change_rx_state(MTKSTP_DATA); + stp_core_ctx.rx_counter = 0; + } +} + +#if 0 +/***************************************************************************** +* FUNCTION +* crc16 +* DESCRIPTION +* Compute the CRC-16 for the data buffer +* PARAMETERS +* crc [IN] previous CRC value +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* the updated CRC value +*****************************************************************************/ +static UINT16 crc16(const UINT8 *buffer, const UINT32 length) +{ + UINT32 crc, i; + + /* FIXME: Add STP checksum feature */ + crc = 0; + for (i = 0; i < length; i++, buffer++) + crc = (crc >> 8) ^ crc16_table[(crc ^ (*buffer)) & 0xff]; + return crc; +} + +#endif + + +VOID stp_dbg_pkt_log(INT32 type, INT32 txAck, INT32 seq, INT32 crc, INT32 dir, const PUINT8 pBuf, + INT32 len) +{ + +#ifndef CONFIG_LOG_STP_INTERNAL + return; +#endif + + if (STP_IS_ENABLE_DBG(stp_core_ctx)) { + if (STP_IS_READY(stp_core_ctx) || + (!STP_IS_READY(stp_core_ctx) && (type > WIFI_TASK_INDX) + && (type != ANT_TASK_INDX) && (len != 0))) + stp_dbg_log_pkt(g_mtkstp_dbg, STP_DBG_PKT, type, /* type */ + txAck, /* ack */ + seq, /* seq */ + crc, /* crc */ + dir, /* dir */ + len, /* len */ + pBuf); /* body */ + } else { + STP_DBG_FUNC("stp_dbg not enabled or not ready or len is 0\n"); + } +} + +/***************************************************************************** +* FUNCTION +* stp_check_crc +* DESCRIPTION +* check the check sum of packet payload +* PARAMETERS +* pdata [IN] the data want to check +* length [IN] the length of pdata +* crc [IN] the crc of pdata +* RETURNS +* KAL_TRUE crc is ok +* KAL_FALSE crc is wrong +*****************************************************************************/ +static MTK_WCN_BOOL stp_check_crc(PUINT8 buffer, UINT32 length, UINT16 crc) +{ + /*----------------------------------------------------------------*/ + /* Local Variables */ + /*----------------------------------------------------------------*/ + UINT16 checksum; + + /*----------------------------------------------------------------*/ + /* Code Body */ + /*----------------------------------------------------------------*/ + + /* FIXME: Add STP feature: check or skip crc */ + + checksum = osal_crc16(buffer, length); + if (checksum == crc) + return MTK_WCN_BOOL_TRUE; + STP_ERR_FUNC("CRC fail, length = %d, rx = %x, calc = %x \r\n", length, crc, checksum); + return MTK_WCN_BOOL_FALSE; +} + +/***************************************************************************** +* FUNCTION +* stp_update_tx_queue +* DESCRIPTION +* update packet's ACK field +* PARAMETERS +* txseq [IN] index of the tx packet which we want to update +* RETURNS +* void +*****************************************************************************/ +static void stp_update_tx_queue(UINT32 txseq) +{ + INT32 tx_read, i; + UINT8 checksum = 0; + + tx_read = stp_core_ctx.tx_start_addr[txseq]; + stp_core_ctx.tx_buf[tx_read] &= 0xf8; + stp_core_ctx.tx_buf[tx_read] |= stp_core_ctx.sequence.txack; + + for (i = 0; i < 3; i++) { + checksum += stp_core_ctx.tx_buf[tx_read]; + tx_read++; + if (tx_read >= MTKSTP_BUFFER_SIZE) + tx_read -= MTKSTP_BUFFER_SIZE; + } + + stp_core_ctx.tx_buf[tx_read] = checksum; +} + +/***************************************************************************** +* FUNCTION +* stp_rest_ctx_state +* DESCRIPTION +* Reset stp context state variables only. Mutex and timer resources are not touched. +* +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static VOID stp_rest_ctx_state(VOID) +{ + INT32 i; + + stp_ctx_lock(&stp_core_ctx); + stp_core_ctx.rx_counter = 0; + + /*reset rx buffer pointer */ + for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++) { + stp_core_ctx.ring[i].read_p = 0; + stp_core_ctx.ring[i].write_p = 0; + } + + /*reset tx buffer pointer */ + stp_core_ctx.tx_write = 0; + stp_core_ctx.tx_read = 0; + + /*reset STP protocol context */ + stp_core_ctx.parser.state = MTKSTP_SYNC; + stp_core_ctx.sequence.txseq = 0; + stp_core_ctx.sequence.txack = 7; + stp_core_ctx.sequence.rxack = 7; + stp_core_ctx.sequence.winspace = MTKSTP_WINSIZE; + stp_core_ctx.sequence.expected_rxseq = 0; + stp_core_ctx.sequence.retry_times = 0; + stp_core_ctx.sequence.tx_timeout_loop = 0; + stp_core_ctx.sequence.rx_resync = 0; + stp_core_ctx.sequence.rx_resync_seq = 0xFF; + stp_core_ctx.inband_rst_set = 0; + + stp_ctx_unlock(&stp_core_ctx); +} + +/***************************************************************************** +* FUNCTION +* stp_change_rx_state +* DESCRIPTION +* change the rx fsm of STP to "next" +* PARAMETERS +* next [IN] the next state of rx fsm +* RETURNS +* void +*****************************************************************************/ +static VOID stp_change_rx_state(mtkstp_parser_state next) +{ + prev_state = stp_core_ctx.parser.state; + stp_core_ctx.parser.state = next; +} + +/* static void stp_tx_timeout_handler(void){ */ +static void stp_tx_timeout_handler(ULONG data) +{ + if (mtk_wcn_stp_coredump_start_get() == 1) { + STP_WARN_FUNC("Starting coredump, skip tx retry.\n"); + return; + } + STP_WARN_FUNC("call retry btm retry wq ...\n"); + /*shorten the softirq lattency */ + stp_btm_notify_stp_retry_wq(STP_BTM_CORE(stp_core_ctx)); +} + +VOID stp_do_tx_timeout(VOID) +{ + UINT32 seq; + UINT32 ret; + UINT8 resync[4]; + INT32 tx_pending_state; + INT32 rx_pending_state; + + STP_WARN_FUNC + ("==============================================================================\n"); + osal_dump_thread_state("btif_rxd"); + if (!mtk_wcn_stp_is_sdio_mode()) mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_BTIF_IRQ); + + tx_pending_state = sys_tx_has_pending_data(); + /* Sys_rx_has_pending_data cannot be called after stp_ctx_lock(&stp_core_ctx), + * there will be a deadlock problem, because sys_rx_has_pending_data will take + * the mutex of btif_rxd, and btif_rxd may need to return TX ack during parsing + * data process. This will take stp_ctx_lock(&stp_core_ctx), causing deadlock + */ + rx_pending_state = sys_rx_has_pending_data(); + STP_INFO_FUNC("check tx/rx has pending data(%d/%d).\n", tx_pending_state, rx_pending_state); + stp_ctx_lock(&stp_core_ctx); + + if (stp_core_ctx.sequence.retry_times > (MTKSTP_RETRY_LIMIT)) { + STP_INFO_FUNC("STP retry times(%d) have reached retry limit,stop it\n", + stp_core_ctx.sequence.retry_times); + stp_ctx_unlock(&stp_core_ctx); + return; + } + + seq = stp_core_ctx.sequence.rxack; + INDEX_INC(seq); + + if (seq != stp_core_ctx.sequence.txseq) { + osal_memset(&resync[0], 0x7f, 4); + (*sys_if_tx) (&resync[0], 4, &ret); + if (ret != 4) { + STP_ERR_FUNC("mtkstp_tx_timeout_handler: send resync fail\n"); + osal_assert(0); + } + + do { + /* rxack (=last rx ack), txack (=last rx seq), txseq (=next tx seq) */ + STP_WARN_FUNC("[stp.ctx]rxack/txack/txseq=%d/%d/%d(Resend from%d->%d)\n", + stp_core_ctx.sequence.rxack, + stp_core_ctx.sequence.txack, + stp_core_ctx.sequence.txseq, + seq, + (stp_core_ctx.sequence.txseq <= 0) ? (7) : + (stp_core_ctx.sequence.txseq - 1)); + stp_dump_tx_queue(seq); + + stp_send_tx_queue(seq); + INDEX_INC(seq); + } while (seq != stp_core_ctx.sequence.txseq); + + } + + osal_timer_stop(&stp_core_ctx.tx_timer); + osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); + + if (stp_core_ctx.sequence.winspace == MTKSTP_WINSIZE) { + osal_timer_stop(&stp_core_ctx.tx_timer); + STP_ERR_FUNC("mtkstp_tx_timeout_handler: wmt_stop_timer\n"); + } else { + stp_core_ctx.sequence.retry_times++; + STP_ERR_FUNC("mtkstp_tx_timeout_handler, retry = %d\n", + stp_core_ctx.sequence.retry_times); + + /*If retry too much, try to recover STP by return back to initializatin state */ + /*And not to retry again */ + if (stp_core_ctx.sequence.retry_times > MTKSTP_RETRY_LIMIT) { + do { + int reason = 42; + + if (tx_pending_state > 0 || (tx_pending_state == 0 && rx_pending_state > 0)) { + if (stp_core_ctx.sequence.tx_timeout_loop < STP_MAX_TX_TIMEOUT_LOOP) { + stp_core_ctx.sequence.retry_times = 0; + stp_core_ctx.sequence.tx_timeout_loop++; + STP_INFO_FUNC("extend tx retry only.\n"); + break; + } + + STP_ERR_FUNC("there are still some data in tx/rx buffer.\n"); + /* Reason number 45 means that stp data path still has data, + * possibly a driver problem + */ + reason = 45; + } + + WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC("STP TX no ack timeout"); + osal_timer_stop(&stp_core_ctx.tx_timer); + stp_ctx_unlock(&stp_core_ctx); + + STP_ERR_FUNC("mtkstp_tx_timeout_handler: wmt_stop_timer\n"); + + STP_ERR_FUNC("TX retry limit = %d\n", MTKSTP_RETRY_LIMIT); + osal_assert(0); + stp_notify_btm_dump(STP_BTM_CORE(stp_core_ctx)); + + /*Whole Chip Reset Procedure Invoke */ + stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); + STP_INFO_FUNC("**STP NoAck trigger firmware assert**\n"); + wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 42); + return; + } while (0); + } + } + + stp_ctx_unlock(&stp_core_ctx); + /*polling cpupcr when no ack occurs at first retry */ + stp_dbg_poll_cpupcr(STP_POLL_CPUPCR_NUM, STP_POLL_CPUPCR_DELAY, 1); + STP_WARN_FUNC + ("==============================================================================#\n"); +} + +static VOID stp_dump_data(const PUINT8 buf, const PUINT8 title, const UINT32 len) +{ + osal_buffer_dump(buf, title, len, 32); +} + +/***************************************************************************** + * FUNCTION + * stp_tx_timeout_handler + * DESCRIPTION + * tx timeout handler, send resync & retransmitt + * PARAMETERS + * void + * RETURNS + * void + *****************************************************************************/ +static VOID stp_dump_tx_queue(UINT32 txseq) +{ + INT32 tx_read, tx_length, last_len; + + tx_read = stp_core_ctx.tx_start_addr[txseq]; + tx_length = stp_core_ctx.tx_length[txseq]; + + STP_ERR_FUNC("tx_seq=%d ..", txseq); + + if (tx_read + tx_length < MTKSTP_BUFFER_SIZE) + stp_dump_data(&stp_core_ctx.tx_buf[tx_read], "tx_q", (tx_length >= 8) ? (8) : (tx_length)); + else { + last_len = MTKSTP_BUFFER_SIZE - tx_read; + stp_dump_data(&stp_core_ctx.tx_buf[tx_read], "tx_q_0", (last_len >= 8) ? (8) : (last_len)); + stp_dump_data(&stp_core_ctx.tx_buf[0], "tx_q_0", + ((tx_length - last_len) ? (8) : (tx_length - last_len))); + } +} + +/***************************************************************************** +* FUNCTION +* stp_is_apply_powersaving +* DESCRIPTION +* Check if STP support power saving mode. +* PARAMETERS +* +* RETURNS +* True: support power saving False: not support power saving +*****************************************************************************/ +static INT32 stp_is_apply_powersaving(VOID) +{ + + if (STP_IS_READY(stp_core_ctx) && !stp_psm_is_disable(STP_PSM_CORE(stp_core_ctx))) { + /* osal_dbg_print("apply power saving\n"); */ + return MTK_WCN_BOOL_TRUE; + } + if (mtk_wcn_stp_is_sdio_mode()) + return MTK_WCN_BOOL_FALSE; + STP_DBG_FUNC("not apply power saving\n"); + return MTK_WCN_BOOL_FALSE; +} + +#if 0 +/***************************************************************************** +* FUNCTION +* stp_is_privileges_cmd +* DESCRIPTION +* Check if the data is privilege command +* PARAMETERS +* +* RETURNS +* True/False +*****************************************************************************/ + +static INT32 stp_is_privileges_cmd(const UINT8 *buffer, const UINT32 length, const UINT8 type) +{ + typedef struct privileges_cmd { + UINT32 length; + UINT8 type; + UINT8 buf[7]; /* MAX length of target command is only 5 currently */ + } p_cmd_t; + + p_cmd_t p_cmd_table[] = { + {0x05, WMT_TASK_INDX, {0x01, 0x03, 0x01, 0x00, 0x01} }, /* sleep command */ + {0x05, WMT_TASK_INDX, {0x01, 0x03, 0x01, 0x00, 0x02} }, /* host_awake command */ + }; + + UINT32 i; + UINT32 size = ARRAY_SIZE(p_cmd_table)); + + for (i = 0; i < size; i++) { + if (type != p_cmd_table[i].type) + continue; + + if (length != p_cmd_table[i].length) + continue; + + if (osal_memcmp(p_cmd_table[i].buf, buffer, length)) + continue; + /* matched entry is found */ + STP_DBG_FUNC("It's p_cmd_t\n"); + return MTK_WCN_BOOL_TRUE; + } + + return MTK_WCN_BOOL_FALSE; +} +#endif +/***************************************************************************** +* FUNCTION +* tx_queue_room_available +* DESCRIPTION +* check room if available, +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* void +*****************************************************************************/ +static MTK_WCN_BOOL stp_is_tx_res_available(UINT32 length) +{ + UINT32 roomLeft; + + /* + * Get available space of TX Queue + */ + if (stp_core_ctx.tx_read <= stp_core_ctx.tx_write) + roomLeft = MTKSTP_BUFFER_SIZE - stp_core_ctx.tx_write + stp_core_ctx.tx_read - 1; + else + roomLeft = stp_core_ctx.tx_read - stp_core_ctx.tx_write - 1; + if (roomLeft < length) { + STP_ERR_FUNC("%s: tx queue room shortage\n", __func__); + return MTK_WCN_BOOL_FALSE; + } + return MTK_WCN_BOOL_TRUE; +} + +/***************************************************************************** +* FUNCTION +* stp_add_to_tx_queue +* DESCRIPTION +* put data to tx queue +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* void +*****************************************************************************/ +static VOID stp_add_to_tx_queue(const PUINT8 buffer, UINT32 length) +{ + UINT32 last_len; + + /* Get available space of TX Queue */ + if (length + stp_core_ctx.tx_write < MTKSTP_BUFFER_SIZE) { + osal_memcpy(stp_core_ctx.tx_buf + stp_core_ctx.tx_write, buffer, length); + stp_core_ctx.tx_write += length; + } else { + last_len = MTKSTP_BUFFER_SIZE - stp_core_ctx.tx_write; + osal_memcpy(stp_core_ctx.tx_buf + stp_core_ctx.tx_write, buffer, last_len); + osal_memcpy(stp_core_ctx.tx_buf, buffer + last_len, length - last_len); + stp_core_ctx.tx_write = length - last_len; + } +} + +/***************************************************************************** +* FUNCTION +* stp_add_to_rx_queue +* DESCRIPTION +* put data to corresponding task's rx queue and notify corresponding task +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] corresponding task index +* RETURNS +* INT32 0=success, others=error +*****************************************************************************/ +static INT32 stp_add_to_rx_queue(UINT8 *buffer, UINT32 length, UINT8 type) +{ + UINT32 roomLeft, last_len; + + osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + + if (stp_core_ctx.ring[type].read_p <= stp_core_ctx.ring[type].write_p) + roomLeft = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].write_p + stp_core_ctx.ring[type].read_p - 1; + else + roomLeft = stp_core_ctx.ring[type].read_p - stp_core_ctx.ring[type].write_p - 1; + + if (roomLeft < length) { + osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + STP_WARN_RATELIMITED_FUNC( + "Queue full, type(%d), remain buf(%d), len(%d), w_p(%d), r_p(%d)\n", + type, roomLeft, length, + stp_core_ctx.ring[type].write_p, + stp_core_ctx.ring[type].read_p); + osal_assert(0); + return -1; + } + + if (length + stp_core_ctx.ring[type].write_p < MTKSTP_BUFFER_SIZE) { + osal_memcpy(stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].write_p, buffer, length); + stp_core_ctx.ring[type].write_p += length; + } else { + last_len = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].write_p; + osal_memcpy(stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].write_p, buffer, last_len); + osal_memcpy(stp_core_ctx.ring[type].buffer, buffer + last_len, length - last_len); + stp_core_ctx.ring[type].write_p = length - last_len; + } + + osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + + return 0; +} + +/***************************************************************************** +* FUNCTION +* wmt_parser_data +* DESCRIPTION +* push data to wmt parser engine +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] corresponding task index +* RETURNS +* INT32 0=success, others=error +*****************************************************************************/ +static INT32 wmt_parser_data(PUINT8 buffer, UINT32 length, UINT8 type) +{ + UINT8 wmtsubtype; + INT32 fgRxOk = -1; + UINT32 parser_length = 0; + UINT32 packet_length = 0; + + while (parser_length < length) { + wmtsubtype = buffer[parser_length + 1]; + packet_length = buffer[parser_length + 3] << 8; + packet_length += buffer[parser_length + 2]; + STP_DBG_FUNC("wmt sub type (%d)\n", wmtsubtype); + if (wmtsubtype == WMT_LTE_COEX_FLAG) { +#if CFG_WMT_LTE_COEX_HANDLING + fgRxOk = stp_add_to_rx_queue(buffer + parser_length, packet_length + 4, COEX_TASK_INDX); + if (fgRxOk == 0) { + STP_DBG_FUNC("wmt/lte coex package!\n"); + stp_notify_btm_handle_wmt_lte_coex(STP_BTM_CORE(stp_core_ctx)); + } else + osal_buffer_dump(buffer, "coex_packet_print", length, 128); +#else + STP_WARN_FUNC("BT/WIFI & LTE coex in non-LTE projects,drop it...\n"); +#endif + } else { + fgRxOk = stp_add_to_rx_queue(buffer + parser_length, packet_length + 4, type); + if (fgRxOk == 0) { + STP_DBG_FUNC("wmt package!\n"); + (*sys_event_set)(type); + } else + osal_buffer_dump(buffer, "wmt_packet_print", length, 128); + } + parser_length += packet_length + 4; + } + + return fgRxOk; +} + +/***************************************************************************** +* FUNCTION +* stp_send_tx_queue +* DESCRIPTION +* send data in tx buffer to common interface +* PARAMETERS +* txseq [IN] sequence number of outgoing packet in tx buffer +* RETURNS +* void +*****************************************************************************/ +static VOID stp_send_tx_queue(UINT32 txseq) +{ + UINT32 ret; + INT32 tx_read, tx_length, last_len; + + tx_read = stp_core_ctx.tx_start_addr[txseq]; + tx_length = stp_core_ctx.tx_length[txseq]; + + stp_update_tx_queue(txseq); + + if (tx_read + tx_length < MTKSTP_BUFFER_SIZE) { + + (*sys_if_tx) (&stp_core_ctx.tx_buf[tx_read], tx_length, &ret); + + if (ret != tx_length) { + STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", tx_length, ret); + osal_assert(0); + } + } else { + last_len = MTKSTP_BUFFER_SIZE - tx_read; + (*sys_if_tx) (&stp_core_ctx.tx_buf[tx_read], last_len, &ret); + + if (ret != last_len) { + STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", last_len, ret); + osal_assert(0); + } + + (*sys_if_tx) (&stp_core_ctx.tx_buf[0], tx_length - last_len, &ret); + + if (ret != tx_length - last_len) { + STP_ERR_FUNC("stp_send_tx_queue, %d/%d\n", tx_length - last_len, ret); + osal_assert(0); + } + } +} + + +/***************************************************************************** +* FUNCTION +* stp_send_ack +* DESCRIPTION +* send ack packet to the peer +* PARAMETERS +* txAck [IN] Ack number +* nak [IN] 0 = ack; !0 = NAK +* RETURNS +* void +*****************************************************************************/ +static VOID stp_send_ack(UINT8 txAck, UINT8 nak) +{ + UINT8 mtkstp_header[MTKSTP_HEADER_SIZE]; + UINT32 ret; + INT32 iStatus; + + mtkstp_header[0] = 0x80 + (0 << 3) + txAck; /* stp_core_ctx.sequence.txack; */ + + if (fgEnableNak == 0) + mtkstp_header[1] = 0x00; /* disable NAK */ + else + mtkstp_header[1] = ((nak == 0) ? 0x00 : 0x80); + + mtkstp_header[2] = 0; + mtkstp_header[3] = (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff; + + stp_dbg_pkt_log(STP_TASK_INDX, txAck, 0, 0, PKT_DIR_TX, NULL, 0); + + if (fgEnableDelimiter == 1) { + iStatus = (*sys_if_tx) ((const PUINT8)(&stp_delimiter[0]), STP_DEL_SIZE, &ret); + STP_DUMP_PACKET_HEAD((PUINT8)(&stp_delimiter[0]), "tx del", STP_DEL_SIZE); + if (ret != STP_DEL_SIZE) { + STP_ERR_FUNC("stp_send_ack, %d/%d status %d\n", STP_DEL_SIZE, ret, iStatus); + osal_assert(0); + } + } + + iStatus = (*sys_if_tx) (&mtkstp_header[0], MTKSTP_HEADER_SIZE, &ret); + + if (ret != MTKSTP_HEADER_SIZE) { + STP_ERR_FUNC("stp_send_ack, %d/%d status %d\n", MTKSTP_HEADER_SIZE, ret, iStatus); + osal_assert(0); + } +} + + + +INT32 stp_send_data_no_ps(PUINT8 buffer, UINT32 length, UINT8 type) +{ + UINT8 mtkstp_header[MTKSTP_HEADER_SIZE], temp[2]; + PUINT8 p_tx_buf = NULL; + UINT16 crc; + INT32 ret = 0; + + stp_ctx_lock(&stp_core_ctx); + + /*Only WMT can set raw data */ + if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX != type) { + /* no op */ + } else if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == type) { + /* ret = mtk_wcn_stp_send_data_raw(buffer, length, type); */ + } else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_uart_mand_mode() || + mtk_wcn_stp_is_btif_mand_mode()) && STP_IS_ENABLE(stp_core_ctx)) { + /* STP over SDIO */ + /* osal_printtimeofday("[ STP][SDIO][ B][W]"); */ + + mtkstp_header[0] = 0x80; + mtkstp_header[1] = (type << 4) + (((length) >> 8) & 0x0f); + mtkstp_header[2] = (length) & 0xff; + mtkstp_header[3] = 0x00; + + p_tx_buf = &stp_core_ctx.tx_buf[0]; + osal_memcpy(p_tx_buf, mtkstp_header, MTKSTP_HEADER_SIZE); + p_tx_buf += MTKSTP_HEADER_SIZE; + + osal_memcpy(p_tx_buf, buffer, length); + p_tx_buf += length; + + temp[0] = 0x00; + temp[1] = 0x00; + osal_memcpy(p_tx_buf, temp, 2); + stp_dbg_pkt_log(type, + stp_core_ctx.sequence.txack, + stp_core_ctx.sequence.txseq, 0, PKT_DIR_TX, buffer, length); + (*sys_if_tx) (&stp_core_ctx.tx_buf[0], (MTKSTP_HEADER_SIZE + length + 2), &ret); + if ((MTKSTP_HEADER_SIZE + length + 2) != ret) { + STP_ERR_FUNC("stp send tx packet: %d, maybe stp_if_tx == NULL\n", ret); + osal_assert(0); + ret = 0; + } else + ret = (INT32) length; + /* osal_printtimeofday("[ STP][SDIO][ E][W]"); */ + } else if ((mtk_wcn_stp_is_uart_fullset_mode() || mtk_wcn_stp_is_btif_fullset_mode()) + && STP_IS_ENABLE(stp_core_ctx)) { + /* STP over UART OR BTIF*/ + if ((stp_core_ctx.sequence.winspace > 0) && + (stp_is_tx_res_available(MTKSTP_HEADER_SIZE + length + MTKSTP_CRC_SIZE))) { + mtkstp_header[0] = + 0x80 + (stp_core_ctx.sequence.txseq << 3) + stp_core_ctx.sequence.txack; + mtkstp_header[1] = (type << 4) + ((length & 0xf00) >> 8); + mtkstp_header[2] = length & 0xff; + mtkstp_header[3] = + (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff; + + stp_core_ctx.tx_start_addr[stp_core_ctx.sequence.txseq] = + stp_core_ctx.tx_write; + stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] = + MTKSTP_HEADER_SIZE + length + 2; + + if (fgEnableDelimiter == 1) { + stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] += STP_DEL_SIZE; + stp_add_to_tx_queue((const PUINT8)(&stp_delimiter[0]), + STP_DEL_SIZE); + } + + stp_add_to_tx_queue(mtkstp_header, MTKSTP_HEADER_SIZE); + + /*Make Payload */ + stp_add_to_tx_queue(buffer, length); + + /*Make CRC */ + crc = osal_crc16(buffer, length); + temp[0] = crc & 0xff; + temp[1] = (crc & 0xff00) >> 8; + stp_add_to_tx_queue(temp, 2); + + stp_dbg_pkt_log(type, + stp_core_ctx.sequence.txack, + stp_core_ctx.sequence.txseq, + crc, PKT_DIR_TX, buffer, length); + + /*Kick to UART */ + stp_send_tx_queue(stp_core_ctx.sequence.txseq); + INDEX_INC(stp_core_ctx.sequence.txseq); + stp_core_ctx.sequence.winspace--; + + /*Setup the Retry Timer */ + osal_timer_stop(&stp_core_ctx.tx_timer); + if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE) + osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); + else + STP_ERR_FUNC("mtk_wcn_stp_send_data: wmt_stop_timer\n"); + ret = (INT32) length; + } else { + /* No winspace to send. Let caller retry */ + STP_ERR_FUNC("%s: There is no winspace/txqueue to send !!!\n", + __func__); + ret = 0; + } + } + + stp_ctx_unlock(&stp_core_ctx); + + return ret; +} + +/***************************************************************************** +* FUNCTION +* stp_process_rxack +* DESCRIPTION +* process ack packet +* PARAMETERS +* void +* RETURNS +* INT32 0=success, others=error +*****************************************************************************/ +static INT32 stp_process_rxack(VOID) +{ + INT32 j, k; + UINT8 rxack; + INT32 fgResult = -1; + + if (stp_core_ctx.sequence.rxack != stp_core_ctx.parser.ack) { + j = k = 0; + rxack = stp_core_ctx.sequence.rxack; + INDEX_INC(rxack); + while (rxack != stp_core_ctx.sequence.txseq) { + j++; + if (rxack == stp_core_ctx.parser.ack) { + k = 1; + break; + } + INDEX_INC(rxack); + } + if (k == 1) { + stp_core_ctx.sequence.rxack = stp_core_ctx.parser.ack; + stp_core_ctx.tx_read = + stp_core_ctx.tx_start_addr[rxack] + stp_core_ctx.tx_length[rxack]; + if (stp_core_ctx.tx_read >= MTKSTP_BUFFER_SIZE) + stp_core_ctx.tx_read -= MTKSTP_BUFFER_SIZE; + stp_core_ctx.sequence.winspace += j; + stp_core_ctx.sequence.retry_times = 0; + stp_core_ctx.sequence.tx_timeout_loop = 0; + + osal_timer_stop(&stp_core_ctx.tx_timer); + if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE) + osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); + fgResult = 0; + } + } + + return fgResult; +} + +/***************************************************************************** +* FUNCTION +* stp_process_packet +* DESCRIPTION +* process STP packet +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static VOID stp_process_packet(VOID) +{ + INT32 fgTriggerResume = (-1); + UINT8 txAck = 0; + static INT32 fgRxOk; + MTK_WCN_BOOL b; + MTK_WCN_BOOL is_function_active = 0; + static INT32 stp_process_packet_fail_count; + + stp_dbg_pkt_log(stp_core_ctx.parser.type, + stp_core_ctx.parser.ack, + stp_core_ctx.parser.seq, + stp_core_ctx.parser.crc, PKT_DIR_RX, stp_core_ctx.rx_buf, stp_core_ctx.parser.length); + /*Optimization */ + /*If bluez, direct send packet to hci_core not through RX buffer! */ + if ((stp_core_ctx.sequence.expected_rxseq == stp_core_ctx.parser.seq) && + (stp_core_ctx.parser.type == BT_TASK_INDX) && STP_BT_STK_IS_BLUEZ(stp_core_ctx)) { + stp_core_ctx.sequence.rx_resync = 0; + + /*Indicate packet to hci_stp */ + STP_DBG_FUNC("Send Packet to BT_SUBFUCTION, len = %d\n", stp_core_ctx.rx_counter); + + b = mtk_wcn_sys_if_rx(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); + if (b) + STP_ERR_FUNC("mtk_wcn_sys_if_rx is NULL\n"); + + /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_lock(&stp_core_ctx); + /*Process rx ack */ + fgTriggerResume = stp_process_rxack(); + stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq; + INDEX_INC(stp_core_ctx.sequence.expected_rxseq); + txAck = stp_core_ctx.sequence.txack; + + /*Send ack back */ + stp_send_ack(txAck, 0); + + /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + stp_ctx_unlock(&stp_core_ctx); + fgRxOk = 0; + } + /* sequence matches expected, enqueue packet */ + else if (stp_core_ctx.sequence.expected_rxseq == stp_core_ctx.parser.seq) { + stp_core_ctx.sequence.rx_resync = 0; + + is_function_active = + ((*sys_check_function_status) (stp_core_ctx.parser.type, OP_FUNCTION_ACTIVE) == + STATUS_FUNCTION_ACTIVE); + /*If type is valid and function works, then try to enqueue */ + if ((stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) && (is_function_active == MTK_WCN_BOOL_TRUE)) { + + stp_ctx_lock(&stp_core_ctx); + + fgTriggerResume = stp_process_rxack(); + stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq; + INDEX_INC(stp_core_ctx.sequence.expected_rxseq); + + /*Send tx ack */ + txAck = stp_core_ctx.sequence.txack; + stp_send_ack(txAck, 0); + + stp_ctx_unlock(&stp_core_ctx); + + if (stp_core_ctx.parser.type == WMT_TASK_INDX) + fgRxOk = + wmt_parser_data(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, + stp_core_ctx.parser.type); + else + fgRxOk = + stp_add_to_rx_queue(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, + stp_core_ctx.parser.type); + } else { + if (is_function_active == MTK_WCN_BOOL_FALSE) { + STP_ERR_FUNC("function type = %d is inactive, so no en-queue to rx\n", + stp_core_ctx.parser.type); + fgRxOk = 0; /*drop packet */ + } else { + STP_ERR_FUNC("mtkstp_process_packet: type = %x, the type is invalid\n", + stp_core_ctx.parser.type); + fgRxOk = 0; /*drop packet */ + } + stp_ctx_lock(&stp_core_ctx); + + fgTriggerResume = stp_process_rxack(); + stp_core_ctx.sequence.txack = stp_core_ctx.parser.seq; + INDEX_INC(stp_core_ctx.sequence.expected_rxseq); + + /*Send tx ack */ + txAck = stp_core_ctx.sequence.txack; + stp_send_ack(txAck, 0); + + stp_ctx_unlock(&stp_core_ctx); + } + + /* enqueue successfully */ + if (fgRxOk == 0) { + stp_process_packet_fail_count = 0; + /*notify corresponding subfunction of incoming data */ + if (stp_core_ctx.parser.type != WMT_TASK_INDX) + (*sys_event_set) (stp_core_ctx.parser.type); + } else { + /*Queue is full */ + switch (stp_core_ctx.parser.type) { + case GPS_TASK_INDX: + /*Clear Rx Queue if GPS */ + mtk_wcn_stp_flush_rx_queue(GPS_TASK_INDX); + break; + case BT_TASK_INDX: + /* just ignore this case */ + /*notify corresponding subfunction of incoming data */ + (*sys_event_set) (stp_core_ctx.parser.type); + break; + default: + stp_process_packet_fail_count++; + /*notify corresponding subfunction of incoming data */ + (*sys_event_set) (stp_core_ctx.parser.type); + break; + } + /*enqueue fail, don't send ack and wait for peer retry */ + STP_WARN_RATELIMITED_FUNC("%s %d queue is full\n", + "Enqueue to Rx queue fail, maybe function", + stp_core_ctx.parser.type); + } + } + /*sequence not match && previous packet enqueue successfully, send the previous ACK */ + else if (fgRxOk == 0) { + STP_ERR_FUNC("mtkstp_process_packet: expected_rxseq = %d, parser.seq = %d, rx_resync = %d\n", + stp_core_ctx.sequence.expected_rxseq, + stp_core_ctx.parser.seq, + stp_core_ctx.sequence.rx_resync); + + stp_ctx_lock(&stp_core_ctx); + /* osal_lock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + txAck = stp_core_ctx.sequence.txack; + stp_send_ack(txAck, 1); + stp_ctx_unlock(&stp_core_ctx); + /* osal_unlock_unsleepable_lock(&stp_core_ctx.stp_mutex); */ + + if (stp_core_ctx.sequence.rx_resync) { + STP_ERR_FUNC("resync'd packets, discard and send the previous (ack no =%d)\n", txAck); + if (stp_core_ctx.sequence.rx_resync_seq == 0xFF) + stp_core_ctx.sequence.rx_resync_seq = stp_core_ctx.parser.seq; + else { + INDEX_INC(stp_core_ctx.sequence.rx_resync_seq); + if (stp_core_ctx.sequence.rx_resync_seq != stp_core_ctx.parser.seq) { + STP_ERR_FUNC("resync'd packet seq not match, %d expected\n", + stp_core_ctx.sequence.rx_resync_seq); + stp_process_packet_fail_count++; + stp_core_ctx.sequence.rx_resync = 0; + } + } + } else { + stp_process_packet_fail_count++; + STP_ERR_FUNC + ("seq not match && previous packet enqueue success, send the previous (ack no =%d)\n", + txAck); + } + } + /*sequence not match && previous packet enqueue failed, do nothing, make the other side timeout */ + else { + stp_process_packet_fail_count++; + STP_ERR_FUNC + ("seq not match && previous packet enqueue failed, make the other side timeout\n"); + } + + if (fgTriggerResume == 0) { + /*[PatchNeed]Just Notificaiton, not blocking call */ + /* notify adaptation layer for possible tx resume mechanism */ + (*sys_event_tx_resume) (stp_core_ctx.sequence.winspace); + } + + if (stp_process_packet_fail_count > MTKSTP_RETRY_LIMIT) { + stp_process_packet_fail_count = 0; + STP_ERR_FUNC("The process packet fail count > 10 lastly, host trigger assert\n"); + /*Whole Chip Reset Procedure Invoke */ + wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 43); + } +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_init +* DESCRIPTION +* init STP kernel +* PARAMETERS +* cb_func [IN] function pointers of system APIs +* RETURNS +* INT32 0 = success, others = failure +*****************************************************************************/ +INT32 mtk_wcn_stp_init(const mtkstp_callback * const cb_func) +{ + INT32 ret = 0; + INT32 i = 0; + + /* Function pointer to point to the currently used transmission interface + */ + sys_if_tx = cb_func->cb_if_tx; + + /* Used to check tx/rx has pending data*/ + sys_rx_has_pending_data = cb_func->cb_rx_has_pending_data; + sys_tx_has_pending_data = cb_func->cb_tx_has_pending_data; + + /* Used to get rx thread */ + sys_rx_thread_get = cb_func->cb_rx_thread_get; + + /* Used to inform the function driver has received the corresponding type of information */ + sys_event_set = cb_func->cb_event_set; + + /* Used to inform the function driver can continue to send information and + * STP has resources to deal with + */ + sys_event_tx_resume = cb_func->cb_event_tx_resume; + + /* STP driver determines whether the function is enable. If not enable and + * STP has received the kind of information, and STP have the right to put it away. + */ + sys_check_function_status = cb_func->cb_check_funciton_status; + + stp_ctx_lock_init(&stp_core_ctx); + + /* Setup timer to be used to check if f/w receive the data in the specific time + * interval after being sent + */ + for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++) + osal_unsleepable_lock_init(&stp_core_ctx.ring[i].mtx); + stp_core_ctx.tx_timer.timeoutHandler = stp_tx_timeout_handler; + stp_core_ctx.tx_timer.timeroutHandlerData = 0; + osal_timer_create(&stp_core_ctx.tx_timer); + + STP_SET_BT_STK(stp_core_ctx, 0); + STP_SET_ENABLE(stp_core_ctx, 0); + STP_SET_ENABLE_DBG(stp_core_ctx, 0); + STP_SET_ENABLE_RST(stp_core_ctx, 0); + STP_SET_PENDING_TYPE(stp_core_ctx, 0); + STP_SET_READY(stp_core_ctx, 0); + STP_SET_SUPPORT_PROTOCOL(stp_core_ctx, 0); + STP_SET_PSM_CORE(stp_core_ctx, stp_psm_init()); + STP_SET_FW_COREDUMP_FLAG(stp_core_ctx, 0); + STP_ENABLE_FW_COREDUMP(stp_core_ctx, 0); + STP_SET_WMT_LAST_CLOSE(stp_core_ctx, 0); + STP_SET_EMI_DUMP_FLAG(stp_core_ctx, 0); + STP_SET_ASSERT(stp_core_ctx, 0); + STP_SET_ASSERT_IN_PROGRESS(stp_core_ctx, 0); + + if (!STP_PSM_CORE(stp_core_ctx)) { + ret = (-3); + goto ERROR; + } + + STP_SET_BTM_CORE(stp_core_ctx, stp_btm_init()); + if (!STP_BTM_CORE(stp_core_ctx)) { + STP_ERR_FUNC("STP_BTM_CORE(stp_core_ctx) initialization fail!\n"); + ret = (-3); + goto ERROR; + } + + if (STP_BTM_CORE(stp_core_ctx) != NULL) + g_mtkstp_dbg = stp_dbg_init(STP_BTM_CORE(stp_core_ctx)); + else + g_mtkstp_dbg = stp_dbg_init(NULL); + + if (!g_mtkstp_dbg) { + STP_ERR_FUNC("g_mtkstp_dbg initialization fail!\n"); + ret = (-3); + goto ERROR; + } + STP_SET_ENABLE_RST(stp_core_ctx, 1); + + mtk_wcn_stp_dbg_enable(); + + goto RETURN; + +ERROR: + stp_psm_deinit(STP_PSM_CORE(stp_core_ctx)); + +RETURN: + return ret; + +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_deinit +* DESCRIPTION +* deinit STP kernel +* PARAMETERS +* void +* RETURNS +* INT32 0 = success, others = failure +*****************************************************************************/ +INT32 mtk_wcn_stp_deinit(VOID) +{ + INT32 i = 0; + + sys_if_tx = NULL; + sys_event_set = NULL; + sys_event_tx_resume = NULL; + sys_check_function_status = NULL; + + stp_dbg_deinit(g_mtkstp_dbg); + stp_btm_deinit(STP_BTM_CORE(stp_core_ctx)); + stp_psm_deinit(STP_PSM_CORE(stp_core_ctx)); + + for (i = 0; i < MTKSTP_MAX_TASK_NUM; i++) + osal_unsleepable_lock_deinit(&stp_core_ctx.ring[i].mtx); + + stp_ctx_lock_deinit(&stp_core_ctx); + return 0; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_btm_get_dmp +* DESCRIPTION +* get stp dump related information +* PARAMETERS +* buffer: dump placement, len: dump size +* RETURNS +* 0: Success Negative Value: Fail +*****************************************************************************/ + +INT32 mtk_wcn_stp_btm_get_dmp(PINT8 buf, PINT32 len) +{ + return stp_dbg_dmp_out(g_mtkstp_dbg, buf, len); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_notify_stp +* DESCRIPTION +* WMT notification to STP that power saving job is done or not +* PARAMETERS +* +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +INT32 mtk_wcn_stp_psm_notify_stp(const MTKSTP_PSM_ACTION_T action) +{ + return stp_psm_notify_stp(STP_PSM_CORE(stp_core_ctx), action); +} + +INT32 mtk_wcn_stp_set_psm_state(MTKSTP_PSM_STATE_T state) +{ + return stp_psm_set_state(STP_PSM_CORE(stp_core_ctx), state); +} + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_enable +* DESCRIPTION +* enable STP sleep/wakeup support +* PARAMETERS +* void +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +INT32 mtk_wcn_stp_psm_enable(INT32 idle_time_to_sleep) +{ + if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_enable() && (mtk_wcn_stp_is_uart_fullset_mode() + || mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_btif_fullset_mode())) + return stp_psm_enable(STP_PSM_CORE(stp_core_ctx), idle_time_to_sleep); + + STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); + return -1; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_psm_disable +* DESCRIPTION +* disable STP sleep/wakeup support +* PARAMETERS +* void +* RETURNS +* 0: Sccuess Negative value: Fail +*****************************************************************************/ +INT32 mtk_wcn_stp_psm_disable(VOID) +{ + if (mtk_wcn_stp_is_ready() && mtk_wcn_stp_is_enable() && (mtk_wcn_stp_is_uart_fullset_mode() + || mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_btif_fullset_mode())) + return stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); + + STP_WARN_FUNC("STP Not Ready, Dont do Sleep/Wakeup\n"); + return 0; +} + +INT32 mtk_wcn_stp_psm_reset(VOID) +{ + return stp_psm_reset(STP_PSM_CORE(stp_core_ctx)); +} + +INT32 mtk_wcn_stp_dbg_disable(VOID) +{ + if (STP_IS_ENABLE_DBG(stp_core_ctx)) { + STP_INFO_FUNC("STP dbg mode is turned off\n"); + STP_SET_ENABLE_DBG(stp_core_ctx, 0); + stp_dbg_disable(g_mtkstp_dbg); + } else + STP_WARN_FUNC("STP dbg mode has been turned off\n"); + + return 0; +} + +INT32 mtk_wcn_stp_dbg_enable(VOID) +{ + if (STP_NOT_ENABLE_DBG(stp_core_ctx)) { + STP_DBG_FUNC("STP dbg mode is turned on\n"); + STP_SET_ENABLE_DBG(stp_core_ctx, 1); + stp_dbg_enable(g_mtkstp_dbg); + } else + STP_WARN_FUNC("STP dbg mode has been turned on\n"); + + return 0; +} + +INT32 mtk_wcn_stp_dbg_log_ctrl(UINT32 on) +{ + stp_dbg_log_ctrl(on); + return 0; +} + +INT32 mtk_wcn_stp_coredump_flag_ctrl(UINT32 on) +{ + static INT32 pre_coredump_mode; + + STP_ENABLE_FW_COREDUMP(stp_core_ctx, on); + STP_INFO_FUNC("%s coredump function.\n", 0 == on ? "disable" : "enable"); + if (pre_coredump_mode != on) { + if (on == 1 || on == 2) + stp_dbg_nl_init(); + else + stp_dbg_nl_deinit(); + } + pre_coredump_mode = on; + return 0; +} + +INT32 mtk_wcn_stp_coredump_flag_get(VOID) +{ + return STP_ENABLE_FW_COREDUMP_FLAG(stp_core_ctx); +} + +INT32 mtk_wcn_stp_emi_dump_flag_ctrl(UINT32 on) +{ + STP_SET_EMI_DUMP_FLAG(stp_core_ctx, on); + return 0; +} + +INT32 mtk_wcn_stp_emi_dump_flag_get(VOID) +{ + return STP_EMI_DUMP_FLAG(stp_core_ctx); +} + +static INT32 stp_parser_data_in_mand_mode(UINT32 length, UINT8 *p_data) +{ + UINT8 padding_len = 0; + INT32 remain_length = 0; + INT32 i = 0; + INT32 i_ret = 0; + + i = length; + while (i > 0) { + switch (stp_core_ctx.parser.state) { + case MTKSTP_SYNC: /* b'10 */ + /* Must be 0x80 */ + if (*p_data == 0x80) { + stp_change_rx_state(MTKSTP_NAK); + stp_core_ctx.rx_counter++; + } else { + STP_WARN_FUNC("non-0x80 (0x%x) detected, discard %d bytes\n", + *p_data, i); + osal_buffer_dump(p_data, "mandatory mode abnormal data", i, 0); + i = 0; + /* Drop them and keep at MTKSTP_SYNC state */ + continue; + } + break; + + case MTKSTP_NAK: + stp_change_rx_state(MTKSTP_LENGTH); + stp_core_ctx.parser.type = (*p_data & 0x70) >> 4; + if (stp_core_ctx.parser.type <= MTKSTP_MAX_TASK_NUM) { + stp_core_ctx.parser.length = (*p_data & 0x0f) << 8; + stp_core_ctx.rx_counter++; + } else { + STP_WARN_FUNC("abnormal type (0x%x) detected, discard %d bytes\n", + stp_core_ctx.parser.type, i); + osal_buffer_dump(p_data, "mandatory mode abnormal data", i, 0); + + /* Drop them and back to MTKSTP_SYNC state */ + i = 0; + STP_WARN_FUNC("nak to sync\n"); + stp_change_rx_state(MTKSTP_SYNC); + continue; + } + break; + + case MTKSTP_LENGTH: + stp_change_rx_state(MTKSTP_CHECKSUM); + stp_core_ctx.parser.length += *p_data; + + /*Valid length checking */ + if (stp_core_ctx.parser.length < 2000) + stp_core_ctx.rx_counter++; + else { + STP_WARN_FUNC("abnormal length (0x%x) detected, discard %d bytes\n", + stp_core_ctx.parser.length, i); + osal_buffer_dump(p_data, "mandatory mode abnormal data", i, 0); + + /* Drop them and back to MTKSTP_SYNC state */ + i = 0; + stp_change_rx_state(MTKSTP_SYNC); + stp_core_ctx.rx_counter = 0; + continue; + } + break; + + case MTKSTP_CHECKSUM: + if ((stp_core_ctx.parser.type == STP_TASK_INDX) || + (stp_core_ctx.parser.type == INFO_TASK_INDX)) { + stp_change_rx_state(MTKSTP_FW_MSG); + stp_core_ctx.rx_counter = 0; + i -= 1; + if (i != 0) + p_data += 1; + continue; + } + if (stp_core_ctx.parser.length == 0) { + STP_WARN_FUNC("checksum to sync\n"); + stp_change_rx_state(MTKSTP_SYNC); + stp_core_ctx.rx_counter = 0; + } else { + stp_change_rx_state(MTKSTP_DATA); + stp_core_ctx.rx_counter = 0; + } + break; + + case MTKSTP_DATA: + /* block copy instead of byte copy */ + if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { + STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", + stp_core_ctx.parser.length, stp_core_ctx.rx_counter); + osal_assert(0); + } + remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; + if (i >= remain_length) { + /*boundary checking */ + if (stp_core_ctx.rx_counter + remain_length >= MTKSTP_BUFFER_SIZE) { + STP_ERR_FUNC("Abnormal!! Memory operation over boundary!!\n"); + stp_change_rx_state(MTKSTP_SYNC); + stp_core_ctx.rx_counter = 0; + return -1; + } + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, remain_length); + i -= remain_length; + p_data += remain_length; + stp_core_ctx.rx_counter = stp_core_ctx.parser.length; + stp_core_ctx.parser.state = MTKSTP_CRC1; + continue; + + } else { /* only copy by data length */ + /*fixed klocwork insight issue */ + /*boundary checking */ + if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) { + STP_ERR_FUNC("Abnormal!! Memory operation over boundary 2!!\n"); + stp_core_ctx.rx_counter = 0; + return -1; + } + + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i); + stp_core_ctx.rx_counter += i; /* all remain buffer are data */ + i = 0; + p_data += i; + continue; + } + break; + + case MTKSTP_CRC1: + stp_change_rx_state(MTKSTP_CRC2); + stp_core_ctx.parser.crc = *p_data; + break; + + case MTKSTP_CRC2: + stp_core_ctx.parser.crc += (*p_data) << 8; + if (stp_core_ctx.parser.crc != 0x00) + STP_ERR_FUNC + ("CRC (0x%x) is not 0 under SDIO/MAND mode, maybe something is wrong.\n", + stp_core_ctx.parser.crc); + /*SDIO mode do it. */ + if (mtk_wcn_stp_is_sdio_mode()) { + /*STP packet 4-bytes alignment */ + /*Discard padding bytes , otherwise make parser state machine disorder */ + if (i <= 4) { + p_data += (i - 1); + i -= (i - 1); + } else { + padding_len = (0x04 - ((stp_core_ctx.parser.length + 6) & 0x03)) & 0x03; + p_data += padding_len; + i -= padding_len; + } + } + stp_dbg_pkt_log(stp_core_ctx.parser.type, + 0, + 0, + 0, + PKT_DIR_RX, + stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); + stp_sdio_process_packet(); + + stp_core_ctx.rx_counter = 0; + stp_change_rx_state(MTKSTP_SYNC); + + break; + + case MTKSTP_FW_MSG: + i_ret = -2; + if (stp_core_ctx.parser.length == 0) { + STP_INFO_FUNC("FW Assert len = 0, ignore this pkg\n"); + /*discard CRC */ + if (i > 2) { + STP_DBG_FUNC("crc discard.. i = %d\n", i); + i -= 2; + p_data += 2; + } else if (i == 2) { + STP_DBG_FUNC("crc discard.. i = %d\n", i); + i -= 2; + } + /*STP packet 4-bytes alignment */ + /*Discard padding bytes , otherwise make parser state machine disorder */ + if (i == 0) { + /*STP_DBG_FUNC("\n[STP]FW_EVENT======= no padding byte =======\n"); */ + /*do nothing */ + } else if (i <= 4) { + STP_INFO_FUNC + ("\n[STP]FW_EVENT========= block padding %d bytes =========\n", i); + p_data += i; + i -= i; + } else { + padding_len = (0x04 - ((stp_core_ctx.parser.length + 6) & 0x03)) & 0x03; + p_data += padding_len; + i -= padding_len; + STP_INFO_FUNC + ("\n[STP]FW_EVENT========= STP Agg padding %d bytes =========\n", + padding_len); + } + continue; + } + mtk_wcn_stp_assert_flow_ctrl(1); + mtk_wcn_stp_coredump_start_ctrl(1); + if (mtk_wcn_stp_get_wmt_trg_assert() == 1) + stp_btm_stop_trigger_assert_timer(STP_BTM_CORE(stp_core_ctx)); + if (STP_IS_READY(stp_core_ctx)) { + mtk_wcn_stp_dbg_dump_package(); + stp_notify_btm_dump(STP_BTM_CORE(stp_core_ctx)); + } + STP_SET_READY(stp_core_ctx, 0); + /*stp inband reset */ + if (stp_core_ctx.parser.type == STP_TASK_INDX && + stp_core_ctx.parser.seq == 0 && + stp_core_ctx.parser.ack == 0 && + stp_core_ctx.parser.length == 0 && + stp_core_ctx.inband_rst_set == 1) { + STP_INFO_FUNC("Inband reset event get! Resync STP with firmware!\n\r"); + stp_rest_ctx_state(); + stp_change_rx_state(MTKSTP_RESYNC1); + stp_core_ctx.inband_rst_set = 0; + STP_TRACE_FUNC("--\n"); + return 0; + } + /*f/w assert and exception information */ + if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { + STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", + stp_core_ctx.parser.length, stp_core_ctx.rx_counter); + osal_assert(0); + } + + remain_length = + stp_core_ctx.parser.length - stp_core_ctx.rx_counter; + if (i >= remain_length) { + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, remain_length); + i -= remain_length; + p_data += remain_length; + stp_core_ctx.rx_counter = stp_core_ctx.parser.length; + stp_change_rx_state(MTKSTP_SYNC); + *(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter) = '\0'; + /* STP_ERR_FUNC("%s [%d]\n", stp_core_ctx.rx_buf, stp_core_ctx.rx_counter); */ + + /*Trace32 Dump */ + stp_sdio_trace32_dump(); + + /*discard CRC */ + if (i > 2) { + STP_DBG_FUNC("crc discard.. i = %d\n", i); + i -= 2; + p_data += 2; + } else if (i == 2) { + STP_DBG_FUNC("crc discard.. i = %d\n", i); + i -= 2; + } + /*STP packet 4-bytes alignment */ + /*Discard padding bytes , otherwise make parser state machine disorder */ + if (i == 0) + STP_DBG_FUNC + ("\n[STP]FW_EVENT========= no padding byte =========\n"); + else if (i <= 4) { + STP_DBG_FUNC + ("\n[STP]FW_EVENT========= block padding %d bytes =========\n", i); + p_data += i; + i -= i; + } else { + padding_len = (0x04 - ((stp_core_ctx.parser.length + 6) & 0x03)) & 0x03; + p_data += padding_len; + i -= padding_len; + STP_DBG_FUNC + ("\n[STP]FW_EVENT========= STP Agg padding %d bytes =========\n", + padding_len); + } + continue; + } else { /* only copy by data length */ + + /*fixed klocwork insight issue */ + if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) { + STP_ERR_FUNC + ("Fail to handle Packet, maybe it doesn't follow STP protocol.\n"); + stp_change_rx_state(MTKSTP_RESYNC1); + stp_core_ctx.rx_counter = 0; + return -1; + } + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i); + stp_core_ctx.rx_counter += i; /* all remain buffer are data */ + i = 0; + p_data += i; + continue; + } + break; + default: + break; + } + p_data++; + i--; + } + return 0; +} + +static INT32 stp_parser_data_in_full_mode(UINT32 length, UINT8 *p_data) +{ + INT32 remain_length; /* GeorgeKuo: sync from MAUI, change to unsigned */ + INT32 i = length; + static DEFINE_RATELIMIT_STATE(_rs, 2 * HZ, 1); + + while (i > 0) { + switch (stp_core_ctx.parser.state) { + + case MTKSTP_RESYNC1: /* RESYNC must be 4 _continuous_ 0x7f */ + if (*p_data == 0x7f) + stp_change_rx_state(MTKSTP_RESYNC2); + else + stp_change_rx_state(MTKSTP_RESYNC1); + break; + case MTKSTP_RESYNC2: + if (*p_data == 0x7f) + stp_change_rx_state(MTKSTP_RESYNC3); + else + stp_change_rx_state(MTKSTP_RESYNC1); + break; + case MTKSTP_RESYNC3: + if (*p_data == 0x7f) + stp_change_rx_state(MTKSTP_RESYNC4); + else + stp_change_rx_state(MTKSTP_RESYNC1); + break; + case MTKSTP_RESYNC4: + if (*p_data == 0x7f) { + stp_change_rx_state(MTKSTP_SYNC); + if (stp_core_ctx.sequence.rx_resync < 0xFF) + stp_core_ctx.sequence.rx_resync++; + stp_core_ctx.sequence.rx_resync_seq = 0xFF; + } else + stp_change_rx_state(MTKSTP_RESYNC1); + break; + case MTKSTP_SYNC: /* b'10 */ + STP_DUMP_PACKET_HEAD(p_data, "rx (uart):", length > 4 ? 4 : length); + if (((*p_data & 0x80) == 0x80) && ((*p_data & 0x40) == 0x00)) { + stp_change_rx_state(MTKSTP_NAK); + stp_core_ctx.parser.seq = (*p_data & 0x38) >> 3; + stp_core_ctx.parser.ack = *p_data & 0x07; + stp_core_ctx.rx_buf[0] = *p_data; + } else if ((*p_data == 0x7f) && (prev_state == MTKSTP_RESYNC4)) { + /* if this 0x7f is continuous to resync pattern */ + /* skip this continuous 0x7f, remain current & prev state */ + STP_ERR_FUNC("MTKSTP_SYNC: continuous resync pattern, buff = %x\n", *p_data); + } else if (*p_data == 0x7f) { /* a start of 0x7f, maybe this is resync pattern */ + stp_change_rx_state(MTKSTP_RESYNC2); + STP_ERR_FUNC("MTKSTP_SYNC: go to MTKSTP_RESYNC2, buff = %x\n", *p_data); + } else if (*p_data == 0x55) { /* STP delimiter */ + /* do nothing for delimiter */ + } else { /* unexpected, drop them */ + osal_assert(0); + if (__ratelimit(&_rs)) { + STP_WARN_FUNC("error header(0x%x) detected, discard %d bytes\n", + *p_data, i); + osal_buffer_dump(p_data, "full mode unexpected header", i, 0); + } + i = 0; + continue; + } + break; + + case MTKSTP_NAK: + if (fgEnableNak == 0) + stp_core_ctx.parser.nak = 0; /* disable NAK */ + else + stp_core_ctx.parser.nak = (*p_data & 0x80) >> 7; + stp_core_ctx.parser.type = (*p_data & 0x70) >> 4; + stp_core_ctx.parser.length = (*p_data & 0x0f) << 8; + stp_core_ctx.rx_buf[1] = *p_data; + if (stp_core_ctx.parser.nak) + STP_ERR_FUNC("MTKSTP_NAK TRUE: buff = %x\n", *p_data); + + if (stp_core_ctx.parser.type < MTKSTP_MAX_TASK_NUM) + stp_change_rx_state(MTKSTP_LENGTH); + else + stp_change_rx_state(MTKSTP_SYNC); + break; + + case MTKSTP_LENGTH: + stp_change_rx_state(MTKSTP_CHECKSUM); + stp_core_ctx.parser.length += *p_data; + /* Valid length checking */ + if (stp_core_ctx.parser.length > 2048) { + STP_ERR_FUNC("The length of STP packet is not valid !!! length = %d\n", + stp_core_ctx.parser.length); + stp_change_rx_state(MTKSTP_RESYNC1); + stp_core_ctx.rx_counter = 0; + STP_WARN_FUNC("error length(0x%x) detected, discard %d bytes\n", + stp_core_ctx.parser.length, i); + osal_buffer_dump(p_data, "full mode unexpected length", i, 0); + i = 0; + continue; + } + stp_core_ctx.rx_buf[2] = *p_data; + break; + + case MTKSTP_CHECKSUM: + if ((stp_core_ctx.parser.type == STP_TASK_INDX) || + (stp_core_ctx.parser.type == INFO_TASK_INDX)) { + stp_change_rx_state(MTKSTP_FW_MSG); + stp_core_ctx.rx_counter = 0; + i -= 1; + if (i != 0) + p_data += 1; + + continue; + } + if (((stp_core_ctx.rx_buf[0] + + stp_core_ctx.rx_buf[1] + stp_core_ctx.rx_buf[2]) & 0xff) == *p_data) { + /* header only packet */ + stp_process_header_only_packet(); + } else { + STP_ERR_FUNC("The checksum of header is error !!! %02x %02x %02x %02x\n", + stp_core_ctx.rx_buf[0], stp_core_ctx.rx_buf[1], + stp_core_ctx.rx_buf[2], *p_data); + stp_change_rx_state(MTKSTP_RESYNC1); + stp_core_ctx.rx_counter = 0; + /* since checksum error is usually related to interface + * buffer overflow, so we just let timeout mechanism to + * handle such error. + */ + /*stp_send_ack(1); NAK mechanism is removed */ + osal_buffer_dump(p_data, "full mode unexpected checksum", i, 0); + i = 0; + continue; + } + break; + + case MTKSTP_DATA: + /* block copy instead of byte copy */ + if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { + STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", + stp_core_ctx.parser.length, stp_core_ctx.rx_counter); + osal_assert(0); + } + remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; + if (i >= remain_length) { + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, remain_length); + i -= remain_length; + p_data += remain_length; + stp_core_ctx.rx_counter = stp_core_ctx.parser.length; + stp_core_ctx.parser.state = MTKSTP_CRC1; + continue; + } else { /* only copy by data length */ + /*fixed klocwork insight issue */ + if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) { + STP_ERR_FUNC + ("Fail to handle Packet, maybe it doesn't follow STP protocol.\n"); + stp_change_rx_state(MTKSTP_RESYNC1); + stp_core_ctx.rx_counter = 0; + STP_TRACE_FUNC("--\n"); + return -1; + } + + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i); + stp_core_ctx.rx_counter += i; /* all remain buffer are data */ + i = 0; + p_data += i; + continue; + } + break; + + case MTKSTP_CRC1: + stp_change_rx_state(MTKSTP_CRC2); + stp_core_ctx.parser.crc = *p_data; + break; + case MTKSTP_CRC2: + stp_change_rx_state(MTKSTP_SYNC); + stp_core_ctx.parser.crc += (*p_data) << 8; + if (stp_check_crc(stp_core_ctx.rx_buf, stp_core_ctx.rx_counter, stp_core_ctx.parser.crc) + == MTK_WCN_BOOL_TRUE) { + if (stp_core_ctx.inband_rst_set == 0) + stp_process_packet(); + else + STP_WARN_FUNC("inband reset state,drop the packet\n"); + } else { + STP_ERR_FUNC("CRC error, drop the packet\n"); + osal_buffer_dump(&stp_core_ctx.rx_buf[0], "CRC data", stp_core_ctx.rx_counter, 0); + stp_change_rx_state(MTKSTP_SYNC); + stp_core_ctx.rx_counter = 0; + + /* since checksum error is usually related to interface + * buffer overflow, so we just let timeout mechanism to + * handle such error. + */ + STP_TRACE_FUNC("--\n"); + /* return and purge COMM port */ + return -1; + /*stp_send_ack(1); NAK mechanism is removed */ + } + break; + + case MTKSTP_FW_MSG: + if (((length > 11) && (osal_strncmp(p_data, "{reset}", 7) == 0)) || + (stp_core_ctx.parser.length == 7)) { + STP_INFO_FUNC("MCU need chip reset only! len=%d,pkt_len=%d!\n", + length, stp_core_ctx.parser.length); + chip_reset_only = 1; + } +#if CFG_WMT_DUMP_INT_STATUS + if (wmt_plat_dump_BGF_irq_status() == MTK_WCN_BOOL_TRUE) + wmt_plat_BGF_irq_dump_status(); +#endif + + if (mtk_wcn_stp_get_wmt_trg_assert() == 1) + stp_btm_stop_trigger_assert_timer(STP_BTM_CORE(stp_core_ctx)); + if (STP_IS_READY(stp_core_ctx)) + mtk_wcn_stp_dbg_dump_package(); + + STP_SET_READY(stp_core_ctx, 0); + /*stp inband reset */ + if (stp_core_ctx.parser.type == STP_TASK_INDX && + stp_core_ctx.parser.seq == 0 && + stp_core_ctx.parser.ack == 0 && + stp_core_ctx.parser.length == 0 && stp_core_ctx.inband_rst_set == 1) { + STP_INFO_FUNC("Inband reset event get! Resync STP with firmware!\n\r"); + stp_rest_ctx_state(); + stp_change_rx_state(MTKSTP_RESYNC1); + stp_core_ctx.inband_rst_set = 0; + STP_TRACE_FUNC("--\n"); + return 0; + } + + /*f/w assert and exception information */ + if (stp_core_ctx.parser.length < stp_core_ctx.rx_counter) { + STP_ERR_FUNC("Abnormal length in STP_DATA phase 0x%x, 0x%x\n", + stp_core_ctx.parser.length, stp_core_ctx.rx_counter); + osal_assert(0); + } + + mtk_wcn_stp_assert_flow_ctrl(1); + if (mtk_wcn_stp_coredump_start_get() == 0 && stp_core_ctx.rx_counter == 0 && + STP_IS_ENABLE_DBG(stp_core_ctx) && (stp_core_ctx.parser.type == STP_TASK_INDX)) { + mtk_wcn_stp_coredump_start_ctrl(1); + mtk_wcn_stp_ctx_save(); + STP_INFO_FUNC("++ start to read paged dump and paged trace ++\n"); + stp_btm_notify_wmt_dmp_wq(stp_core_ctx.btm); + STP_INFO_FUNC("++ start to read paged dump and paged trace --\n"); + } + + remain_length = stp_core_ctx.parser.length - stp_core_ctx.rx_counter; + if (i >= remain_length) { + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, + remain_length); + i -= remain_length; + p_data += remain_length; + stp_core_ctx.rx_counter = stp_core_ctx.parser.length; + stp_change_rx_state(MTKSTP_SYNC); + *(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter) = '\0'; + /*Trace32 Dump */ + stp_trace32_dump(); + /*discard CRC */ + if (i >= 2) { + STP_DBG_FUNC("crc discard.. i = %d\n", i); + i -= 2; + if (i > 0) + p_data += 2; + } + continue; + } else { /* only copy by data length */ + + /*fixed klocwork insight issue */ + if (i + stp_core_ctx.rx_counter >= MTKSTP_BUFFER_SIZE) { + STP_ERR_FUNC + ("Fail to handle Packet, it doesn't follow STP protocol.\n"); + stp_change_rx_state(MTKSTP_RESYNC1); + stp_core_ctx.rx_counter = 0; + return -1; + } + osal_memcpy(stp_core_ctx.rx_buf + stp_core_ctx.rx_counter, p_data, i); + stp_core_ctx.rx_counter += i; /* all remain buffer are data */ + i = 0; + p_data += i; + continue; + } + + break; + default: + break; + } + p_data++; + i--; + } + + return 0; +} + + + + + + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_parser_data +* DESCRIPTION +* push data to serial transport protocol parser engine +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* INT32 0 = success; -1 = crc/checksum error +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length) +#else +INT32 mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length) +#endif +{ + /*----------------------------------------------------------------*/ + /* Local Variables */ + /*----------------------------------------------------------------*/ + INT32 i; + PUINT8 p_data; + INT32 ret = 0; +#ifdef DEBUG_DUMP_PACKET_HEAD + static UINT32 counter; + + STP_TRACE_FUNC("++, rx (cnt=%d,len=%d)\n", ++counter, length); +#endif + + i = length; + p_data = (PUINT8) buffer; + + /* STP is not enabled and only WMT can use Raw data path */ + if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == STP_PENDING_TYPE(stp_core_ctx)) { + stp_add_to_rx_queue(buffer, i, STP_PENDING_TYPE(stp_core_ctx)); + + /* mike: notify corresponding subfunction of incoming data */ + (*sys_event_set) (STP_PENDING_TYPE(stp_core_ctx)); + } + /* Mandatory or SDIO mode */ + else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_uart_mand_mode() || + mtk_wcn_stp_is_btif_mand_mode()) && STP_IS_ENABLE(stp_core_ctx)) { + ret = stp_parser_data_in_mand_mode(i, p_data); + } + /* Full mode */ + else if ((mtk_wcn_stp_is_btif_fullset_mode() || mtk_wcn_stp_is_uart_fullset_mode()) + && STP_IS_ENABLE(stp_core_ctx)) { + ret = stp_parser_data_in_full_mode(i, p_data); + } + STP_TRACE_FUNC("--\n"); + return ret; +} +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +EXPORT_SYMBOL(mtk_wcn_stp_parser_data); +#endif + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_enable +* DESCRIPTION +* enable/disable STP +* PARAMETERS +* value [IN] 0=disable, others=enable +* RETURNS +* INT32 0=success, others=error +*****************************************************************************/ +INT32 mtk_wcn_stp_enable(INT32 value) +{ + STP_DBG_FUNC("%s: set the current enable = (%d)\n", __func__, value); + + stp_rest_ctx_state(); + STP_SET_ENABLE(stp_core_ctx, value); + if (!value) + mtk_wcn_stp_psm_reset(); + else { +/* g_block_tx = 0; */ + mtk_wcn_stp_coredump_start_ctrl(0); + mtk_wcn_stp_set_wmt_trg_assert(0); + } + return 0; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_enable +* DESCRIPTION +* get STP enable/disable status +* PARAMETERS +* none. +* RETURNS +* INT32 0 = disable, 1 = enable +*****************************************************************************/ +INT32 mtk_wcn_stp_is_enable(VOID) +{ + return STP_IS_ENABLE(stp_core_ctx); +} + +INT32 mtk_wcn_stp_dbg_dump_package(VOID) +{ + if (STP_NOT_ENABLE(stp_core_ctx)) + STP_INFO_FUNC("STP dbg mode is off\n"); + else { + STP_INFO_FUNC("STP dbg mode is on\n"); + wmt_lib_print_wmtd_op_history(); + wmt_lib_print_worker_op_history(); + stp_psm_print_op_history(); + stp_btm_print_op_history(); + + if (mtk_wcn_stp_coredump_start_get() == 0 && + mtk_wcn_stp_get_wmt_trg_assert() == 0) { + if (mtk_wcn_stp_is_sdio_mode()) { + stp_dbg_dmp_print(g_mtkstp_dbg); + STP_INFO_FUNC("STP_SDIO TX data dump start\n"); + stp_sdio_txdbg_dump(); + } else { + mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_BTIF_REG); + mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_LOG); + stp_dbg_dmp_print(g_mtkstp_dbg); + } + } else + STP_INFO_FUNC("assert start flag is set, disable packet dump function\n"); + } + return 0; +} + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_ready +* DESCRIPTION +* ready/un-ready STP +* PARAMETERS +* value [IN] 0=un-ready, others=ready +* RETURNS +* INT32 0=success, others=error +*****************************************************************************/ +INT32 mtk_wcn_stp_ready(INT32 value) +{ + STP_DBG_FUNC("set ready (%d)\n", value); + + STP_SET_READY(stp_core_ctx, value); + /*if whole chip reset, reset the debuggine mode */ +#ifndef CONFIG_LOG_STP_INTERNAL + /* mtk_wcn_stp_dbg_disable(); */ +#endif + + if (stp_is_apply_powersaving()) { + STP_INFO_FUNC("Restart the stp-psm monitor !!\n"); + stp_psm_disable(STP_PSM_CORE(stp_core_ctx)); + } + + return 0; +} + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_coredump_start_ctrl +* DESCRIPTION +* set f/w assert flag in STP context +* PARAMETERS +* value [IN] 0=assert end, others=assert begins +* RETURNS +* INT32 0=success, others=error +*****************************************************************************/ +INT32 mtk_wcn_stp_coredump_start_ctrl(UINT32 value) +{ + if (value != STP_FW_COREDUMP_FLAG(stp_core_ctx)) { + STP_INFO_FUNC("set f/w assert (%d)\n", value); + STP_SET_FW_COREDUMP_FLAG(stp_core_ctx, value); + } + return 0; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_coredump_start_get +* DESCRIPTION +* get f/w assert flag in STP context +* PARAMETERS +* VOID +* RETURNS +* INT32 0= f/w assert flag is not set, others=f/w assert flag is set +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_coredump_start_get(VOID) +#else +INT32 mtk_wcn_stp_coredump_start_get(VOID) +#endif +{ + return STP_FW_COREDUMP_FLAG(stp_core_ctx); +} +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +EXPORT_SYMBOL(mtk_wcn_stp_coredump_start_get); +#endif + +/* mtk_wcn_stp_set_wmt_last_close -- set the state of link(UART or SDIO) + * @ value - 1, link already be closed; 0, link is open + * + * Return 0 if success; else error code + */ +INT32 mtk_wcn_stp_set_wmt_last_close(UINT32 value) +{ + STP_INFO_FUNC("set wmt_last_close flag (%d)\n", value); + + /* test whether last_close can be removed safely */ + /* STP_SET_WMT_LAST_CLOSE(stp_core_ctx, value); */ + + return 0; +} + +INT32 mtk_wcn_stp_is_wmt_last_close(VOID) +{ + return STP_WMT_LAST_CLOSE(stp_core_ctx); +} + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_send_data +* DESCRIPTION +* subfunction send data through STP +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] subfunction type +* RETURNS +* INT32 > 0: length transmitted; = 0: error +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type) +#else +INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type) +#endif +{ + UINT8 mtkstp_header[MTKSTP_HEADER_SIZE], temp[2]; + PUINT8 p_tx_buf = NULL; + UINT16 crc; + INT32 ret = 0; + + /* osal_buffer_dump(buffer,"tx", length, 32); */ + osal_ftrace_print("%s|S|T%d|L%d\n", __func__, type, length); + + if (STP_WMT_LAST_CLOSE(stp_core_ctx) != 0) { + STP_ERR_FUNC("WMT lats close,should not have tx request!\n"); + return length; + } + /* if(g_block_tx) */ + if (mtk_wcn_stp_coredump_start_get() != 0) { + STP_WARN_RATELIMITED_FUNC("STP fw coredump start flag set...\n"); + return length; + } +#ifdef CONFIG_POWER_SAVING_SUPPORT + if (type != WMT_TASK_INDX) { +#if PSM_USE_COUNT_PACKAGE + stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 0); +#else + stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 0, length); +#endif + } + + if (type == WMT_TASK_INDX) + goto DONT_MONITOR; + if ((type == BT_TASK_INDX) && (wmt_plat_get_comm_if_type() == STP_SDIO_IF_TX)) { + if (stp_psm_is_to_block_traffic(STP_PSM_CORE(stp_core_ctx))) + stp_psm_notify_wmt_wakeup(STP_PSM_CORE(stp_core_ctx)); + goto DONT_MONITOR; + } + /*-----------------------------STP_PSM_Lock----------------------------------------*/ + ret = stp_psm_thread_lock_aquire(STP_PSM_CORE(stp_core_ctx)); + if (ret) { + STP_ERR_FUNC("--->lock psm_thread_lock failed ret=%d\n", ret); + return ret; + } + + if (!stp_psm_is_to_block_traffic(STP_PSM_CORE(stp_core_ctx))) { + if (stp_psm_has_pending_data(STP_PSM_CORE(stp_core_ctx))) { + STP_WARN_FUNC("***** Release psm hold data before send normal data *****\n"); + stp_psm_release_data(STP_PSM_CORE(stp_core_ctx)); + } + } else { + ret = stp_psm_hold_data(STP_PSM_CORE(stp_core_ctx), buffer, length, type); + stp_psm_notify_wmt_wakeup(STP_PSM_CORE(stp_core_ctx)); + /*-----------------------------STP_PSM_UnLock-----------------------------------*/ + stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); + return ret; + } +DONT_MONITOR: +#endif + + ret = stp_ctx_lock(&stp_core_ctx); + if (ret) { + STP_ERR_FUNC("stp context lock failed, ret=%d\n", ret); + ret = 0; + goto STP_LOCK_FAIL; + } + /*Only WMT can set raw data */ + if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX != type) { + /* no-op */ + } else if (STP_NOT_ENABLE(stp_core_ctx) && WMT_TASK_INDX == type) { + /* ret = mtk_wcn_stp_send_data_raw(buffer, length, type); */ + } else if ((mtk_wcn_stp_is_sdio_mode() || mtk_wcn_stp_is_uart_mand_mode() || mtk_wcn_stp_is_btif_mand_mode()) + && STP_IS_ENABLE(stp_core_ctx)) { + + /*mtkstp_header[0] = 0x80;*/ + mtkstp_header[0] = 0x80 + (stp_core_ctx.sequence.txseq << 3); /* for debug purpose */ + mtkstp_header[1] = (type << 4) + (((length) >> 8) & 0x0f); + mtkstp_header[2] = (length) & 0xff; + mtkstp_header[3] = 0x00; + + /* HEADER */ + p_tx_buf = &stp_core_ctx.tx_buf[0]; + osal_memcpy(p_tx_buf, mtkstp_header, MTKSTP_HEADER_SIZE); + p_tx_buf += MTKSTP_HEADER_SIZE; + + /* PAYLOAD */ + osal_memcpy(p_tx_buf, buffer, length); + p_tx_buf += length; + + /* CRC */ + temp[0] = 0x00; + temp[1] = 0x00; + osal_memcpy(p_tx_buf, temp, 2); + stp_dbg_pkt_log(type, 0, 0, 0, PKT_DIR_TX, buffer, length); + (*sys_if_tx) (&stp_core_ctx.tx_buf[0], (MTKSTP_HEADER_SIZE + length + 2), &ret); + + if ((MTKSTP_HEADER_SIZE + length + 2) != ret) { + STP_ERR_FUNC("stp send tx packet: %d, maybe stp_if_tx == NULL\n", ret); + osal_assert(0); + ret = 0; + } else + ret = (INT32) length; + } + else if ((mtk_wcn_stp_is_uart_fullset_mode() || mtk_wcn_stp_is_btif_fullset_mode()) + && STP_IS_ENABLE(stp_core_ctx)) { + + if ((stp_core_ctx.sequence.winspace > 0) && + (stp_core_ctx.inband_rst_set == 0) && + (stp_is_tx_res_available(MTKSTP_HEADER_SIZE + length + MTKSTP_CRC_SIZE))) { + /*Make Header */ + mtkstp_header[0] = + 0x80 + (stp_core_ctx.sequence.txseq << 3) + stp_core_ctx.sequence.txack; + mtkstp_header[1] = (type << 4) + ((length & 0xf00) >> 8); + mtkstp_header[2] = length & 0xff; + mtkstp_header[3] = + (mtkstp_header[0] + mtkstp_header[1] + mtkstp_header[2]) & 0xff; + stp_core_ctx.tx_start_addr[stp_core_ctx.sequence.txseq] = + stp_core_ctx.tx_write; + stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] = + MTKSTP_HEADER_SIZE + length + 2; + if (fgEnableDelimiter == 1) { + stp_core_ctx.tx_length[stp_core_ctx.sequence.txseq] += STP_DEL_SIZE; + stp_add_to_tx_queue((const PUINT8)(&stp_delimiter[0]), + STP_DEL_SIZE); + } + stp_add_to_tx_queue(mtkstp_header, MTKSTP_HEADER_SIZE); + + /*Make Payload */ + stp_add_to_tx_queue(buffer, length); + + /*Make CRC */ + crc = osal_crc16(buffer, length); + temp[0] = crc & 0xff; + temp[1] = (crc & 0xff00) >> 8; + stp_add_to_tx_queue(temp, 2); + stp_dbg_pkt_log(type, + stp_core_ctx.sequence.txack, + stp_core_ctx.sequence.txseq, + crc, PKT_DIR_TX, buffer, length); + + /*Kick to BUS */ + stp_send_tx_queue(stp_core_ctx.sequence.txseq); + + INDEX_INC(stp_core_ctx.sequence.txseq); + stp_core_ctx.sequence.winspace--; + + /*Setup the Retry Timer */ + osal_timer_stop(&stp_core_ctx.tx_timer); + if (stp_core_ctx.sequence.winspace != MTKSTP_WINSIZE) + osal_timer_start(&stp_core_ctx.tx_timer, mtkstp_tx_timeout); + else + STP_ERR_FUNC("mtk_wcn_stp_send_data: wmt_stop_timer\n"); + ret = (INT32) length; + } else { + /* + * No winspace to send. Let caller retry + */ + if (stp_core_ctx.inband_rst_set == 1) + STP_WARN_RATELIMITED_FUNC + ("Now it's inband reset process and drop sent packet.\n"); + else + STP_WARN_RATELIMITED_FUNC("%s: There is no winspace/txqueue to send !!!\n", + __func__); + ret = 0; + } + } + stp_ctx_unlock(&stp_core_ctx); +STP_LOCK_FAIL: +#ifdef CONFIG_POWER_SAVING_SUPPORT + + if (stp_psm_is_quick_ps_support() == MTK_WCN_BOOL_TRUE) { + stp_psm_notify_wmt_sleep(STP_PSM_CORE(stp_core_ctx)); + } + /*-----------------------------STP_PSM_UnLock----------------------------------------*/ + if (type != WMT_TASK_INDX) { + if (!((type == BT_TASK_INDX) && (wmt_plat_get_comm_if_type() == STP_SDIO_IF_TX))) + stp_psm_thread_lock_release(STP_PSM_CORE(stp_core_ctx)); + } +#endif + + osal_ftrace_print("%s|E|T|%d|L|%d\n", __func__, type, length); + return ret; +} +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +EXPORT_SYMBOL(mtk_wcn_stp_send_data); +#endif + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_send_data_raw +* DESCRIPTION +* send raw data to common interface, bypass STP +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] subfunction type +* RETURNS +* INT32 >= 0: length transmitted; < 0: error +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type) +#else +INT32 mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type) +#endif +{ + UINT32 written = 0; + INT32 ret = 0; + + if (STP_WMT_LAST_CLOSE(stp_core_ctx) != 0) { + STP_ERR_FUNC("WMT lats close, should not have tx request!"); + return length; + } + + if (length >= 6) + STP_DBG_FUNC("mtk_wcn_stp_send_data_raw, type = %d data = %x %x %x %x %x %x ", type, + buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); + else if (length > 0) + STP_DBG_FUNC("mtk_wcn_stp_send_data_raw, type = %d data = %x", type, buffer[0]); + + /* remember tx type, forward following rx to this type */ + STP_SET_PENDING_TYPE(stp_core_ctx, type); + + stp_ctx_lock(&stp_core_ctx); + stp_dbg_pkt_log(type, 0, 0, 0, PKT_DIR_TX, buffer, length); + (*sys_if_tx) (&buffer[0], length, &written); + stp_ctx_unlock(&stp_core_ctx); + + if (written == 0) + stp_dump_data(&buffer[0], "tx raw failed:", length); + + if (written == length) + ret = (INT32) written; + else + ret = (-1); + + return ret; +} +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +EXPORT_SYMBOL(mtk_wcn_stp_send_data_raw); +#endif + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_receive_data +* DESCRIPTION +* receive data from serial protocol engine +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] subfunction type +* RETURNS +* INT32 >= 0: size of data received; < 0: error +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type) +#else +INT32 mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type) +#endif +{ + /* GeorgeKuo modify: reduce "if" branch */ + UINT16 copyLen = 0; + UINT16 tailLen = 0; + + osal_ftrace_print("%s|S|T|%d|L|%d\n", __func__, type, length); + osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + while (stp_core_ctx.ring[type].read_p != stp_core_ctx.ring[type].write_p) { + /* GeorgeKuo modify: reduce if branch */ + if (stp_core_ctx.ring[type].write_p > stp_core_ctx.ring[type].read_p) { + copyLen = stp_core_ctx.ring[type].write_p - stp_core_ctx.ring[type].read_p; + if (copyLen > length) + copyLen = length; + osal_memcpy(buffer, + stp_core_ctx.ring[type].buffer + stp_core_ctx.ring[type].read_p, + copyLen); + stp_core_ctx.ring[type].read_p += copyLen; + break; + } + tailLen = MTKSTP_BUFFER_SIZE - stp_core_ctx.ring[type].read_p; + if (tailLen > length) { /* exclude equal case to skip wrap check */ + copyLen = length; + osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + + stp_core_ctx.ring[type].read_p, copyLen); + stp_core_ctx.ring[type].read_p += copyLen; + } else { + /* part 1: copy tailLen */ + osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + + stp_core_ctx.ring[type].read_p, tailLen); + buffer += tailLen; /* update buffer offset */ + /* part 2: check if head length is enough */ + copyLen = length - tailLen; + copyLen = (stp_core_ctx.ring[type].write_p < + copyLen) ? stp_core_ctx.ring[type].write_p : copyLen; + if (copyLen) + osal_memcpy(buffer, stp_core_ctx.ring[type].buffer + 0, copyLen); + /* Update read_p final position */ + stp_core_ctx.ring[type].read_p = copyLen; + /* update return length: head + tail */ + copyLen += tailLen; + } + break; + } + + osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + + if ((stp_psm_is_quick_ps_support() == MTK_WCN_BOOL_TRUE) && (type != WMT_TASK_INDX)) { +#if PSM_USE_COUNT_PACKAGE + stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 1); +#else + stp_psm_disable_by_tx_rx_density(STP_PSM_CORE(stp_core_ctx), 1, copyLen); +#endif + } + + osal_ftrace_print("%s|E|T|%d|L|%d\n", __func__, type, copyLen); + return copyLen; +} +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +EXPORT_SYMBOL(mtk_wcn_stp_receive_data); +#endif + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_rxqueue_empty +* DESCRIPTION +* Is certain rx queue empty? +* PARAMETERS +* type [IN] subfunction type +* RETURNS +* INT32 0: queue is NOT empyt; !0: queue is empty +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_is_rxqueue_empty(UINT8 type) +#else +INT32 mtk_wcn_stp_is_rxqueue_empty(UINT8 type) +#endif +{ + INT32 ret; + + osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + + if (stp_core_ctx.ring[type].read_p == stp_core_ctx.ring[type].write_p) + ret = 1; /* queue is empty */ + else + ret = 0; /* queue is not empty */ + + osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + + return ret; +} +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +EXPORT_SYMBOL(mtk_wcn_stp_is_rxqueue_empty); +#endif + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_set_sdio_mode +* DESCRIPTION +* Set stp for SDIO mode +* PARAMETERS +* sdio_flag [IN] sdio mode flag (TRUE:SDIO mode, FALSE:UART mode) +* RETURNS +* void +*****************************************************************************/ + +void mtk_wcn_stp_set_mode(UINT32 mode) +{ + STP_SET_SUPPORT_PROTOCOL(stp_core_ctx, mode); + STP_DBG_FUNC("STP_SUPPORT_PROTOCOL = %08x\n", STP_SUPPORT_PROTOCOL(stp_core_ctx)); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_uart_fullset_mode +* DESCRIPTION +* Is stp use UART fullset mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:Uart Fullset mode, FALSE:Not UART Fullset mode +*****************************************************************************/ +MTK_WCN_BOOL mtk_wcn_stp_is_uart_fullset_mode(VOID) +{ + /* + * bit 0: uart fullset mode + * bit 1: uart mandatory mode + * bit 2: sdio mode + */ + if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_UART_FULL_MODE) + return MTK_WCN_BOOL_TRUE; + else + return MTK_WCN_BOOL_FALSE; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_uart_mand_mode +* DESCRIPTION +* Is stp use UART mandatory mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:Uart Mandatory mode, FALSE:Not UART Mandotary mode +*****************************************************************************/ +MTK_WCN_BOOL mtk_wcn_stp_is_uart_mand_mode(VOID) +{ + /* + * bit 0: uart fullset mode + * bit 1: uart mandatory mode + * bit 2: sdio mode + */ + if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_UART_MAND_MODE) + return MTK_WCN_BOOL_TRUE; + else + return MTK_WCN_BOOL_FALSE; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_sdio_mode +* DESCRIPTION +* Is stp use SDIO mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:SDIO mode, FALSE:UART mode +*****************************************************************************/ +MTK_WCN_BOOL mtk_wcn_stp_is_sdio_mode(VOID) +{ + /* + * bit 0: uart fullset mode + * bit 1: uart mandatory mode + * bit 2: sdio mode + */ + if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_SDIO_MODE) + return MTK_WCN_BOOL_TRUE; + else + return MTK_WCN_BOOL_FALSE; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_btif_fullset_mode +* DESCRIPTION +* Is stp use BTIF fullset mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:BTIF Fullset mode, FALSE:Not BTIF Fullset mode +*****************************************************************************/ +MTK_WCN_BOOL mtk_wcn_stp_is_btif_fullset_mode(VOID) +{ + + if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_BTIF_FULL_MODE) + return MTK_WCN_BOOL_TRUE; + else + return MTK_WCN_BOOL_FALSE; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_btif_mand_mode +* DESCRIPTION +* Is stp use BTIF mandatory mode? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:BTIF Mandatory mode, FALSE:Not BTIF Mandotary mode +*****************************************************************************/ + +MTK_WCN_BOOL mtk_wcn_stp_is_btif_mand_mode(void) +{ + + if (STP_SUPPORT_PROTOCOL(stp_core_ctx) & MTKSTP_BTIF_MAND_MODE) + return MTK_WCN_BOOL_TRUE; + else + return MTK_WCN_BOOL_FALSE; +} + +/***************************************************************************** +* FUNCTION +* stp_send_inband_reset +* DESCRIPTION +* To sync to oringnal stp state with f/w stp +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +VOID mtk_wcn_stp_inband_reset(VOID) +{ + UINT8 inband_reset_packet[64]; + UINT32 txseq = 0; + UINT32 txack = 0; + UINT32 crc = 0; + UINT32 ret = 0; + UINT32 reset_payload_len = 0; + + /*512 bytes */ + UINT8 reset_payload[] = { + 0xc0, 0x01, 0xc0, 0xde, 0x3e, 0xd1, 0xa7, 0xef + }; + + stp_ctx_lock(&stp_core_ctx); + + /*RESYNC*/ inband_reset_packet[0] = 0x7f; + inband_reset_packet[1] = 0x7f; + inband_reset_packet[2] = 0x7f; + inband_reset_packet[3] = 0x7f; + inband_reset_packet[4] = 0x7f; + inband_reset_packet[5] = 0x7f; + inband_reset_packet[6] = 0x7f; + inband_reset_packet[7] = 0x7f; + + /*header */ + reset_payload_len = ARRAY_SIZE(reset_payload); + inband_reset_packet[8] = 0x80 + (txseq << 3) + txack; + inband_reset_packet[9] = (STP_TASK_INDX << 4) + ((reset_payload_len & 0xf00) >> 8); + inband_reset_packet[10] = reset_payload_len & 0xff; + inband_reset_packet[11] = + (inband_reset_packet[8] + inband_reset_packet[9] + inband_reset_packet[10]) & 0xff; + + /*payload */ + osal_memcpy(&inband_reset_packet[12], reset_payload, reset_payload_len); + + /*crc */ + crc = osal_crc16(&reset_payload[0], reset_payload_len); + inband_reset_packet[12 + reset_payload_len] = crc & 0xff; + inband_reset_packet[12 + reset_payload_len + 1] = (crc & 0xff00) >> 8; + + (*sys_if_tx)(&inband_reset_packet[0], 14 + reset_payload_len, &ret); + + if (ret != (14 + reset_payload_len)) + STP_ERR_FUNC("Inband sending error, sending %d , but ret = %d\n", + 10 + reset_payload_len, ret); + + stp_core_ctx.inband_rst_set = 1; + stp_ctx_unlock(&stp_core_ctx); +} + +void mtk_wcn_stp_debug_ctrl(INT32 op, INT32 filter, INT32 filter_param) +{ +} + +void mtk_wcn_stp_test_cmd(INT32 cmd_no) +{ + UINT8 test_packet[64]; + UINT32 txseq = 0; + UINT32 txack = 0; + UINT32 crc = 0; + UINT32 ret = 0; + UINT32 reset_payload_len = 0; + + UINT8 test_payload[] = { + 0xAA, 0xAA, 0xC0, 0xDE, 0x3E, 0xD1, 0xA7, 0xEF + }; +/* */ +/* select your test command by cmd_no */ +/* */ + if (cmd_no == 0) { + /* to test new command to chip */ + stp_ctx_lock(&stp_core_ctx); + + /*RESYNC*/ test_packet[0] = 0x7f; + test_packet[1] = 0x7f; + test_packet[2] = 0x7f; + test_packet[3] = 0x7f; + test_packet[4] = 0x7f; + test_packet[5] = 0x7f; + test_packet[6] = 0x7f; + test_packet[7] = 0x7f; + + /*header */ + reset_payload_len = ARRAY_SIZE(test_payload); + test_packet[8] = 0x80 + (txseq << 3) + txack; + test_packet[9] = (STP_TASK_INDX << 4) + ((reset_payload_len & 0xf00) >> 8); + test_packet[10] = reset_payload_len & 0xff; + test_packet[11] = (test_packet[8] + test_packet[9] + test_packet[10]) & 0xff; + + /*payload */ + osal_memcpy(&test_packet[12], test_payload, reset_payload_len); + + /*crc */ + crc = osal_crc16(&test_payload[0], reset_payload_len); + test_packet[12 + reset_payload_len] = crc & 0xff; + test_packet[12 + reset_payload_len + 1] = (crc & 0xff00) >> 8; + + (*sys_if_tx)(&test_packet[0], 14 + reset_payload_len, &ret); + if (ret != (14 + reset_payload_len)) + STP_ERR_FUNC("stp test sending error, sending %d , but ret = %d\n", + 10 + reset_payload_len, ret); + + stp_ctx_unlock(&stp_core_ctx); + } + +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_flush_context +* DESCRIPTION +* Flush STP Context +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +VOID mtk_wcn_stp_flush_context(VOID) +{ + stp_rest_ctx_state(); +} + + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_flush_rx_queue +* DESCRIPTION +* Flush STP Rx Queue +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ + +VOID mtk_wcn_stp_flush_rx_queue(UINT32 type) +{ + INT32 ret = 0; + + if (type < MTKSTP_MAX_TASK_NUM) { + ret = osal_lock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + if (ret != 0) { + STP_WARN_FUNC("stp context lock failed, ret=%d\n", ret); + return; + } + stp_core_ctx.ring[type].read_p = 0; + stp_core_ctx.ring[type].write_p = 0; + osal_unlock_unsleepable_lock(&stp_core_ctx.ring[type].mtx); + } +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_enable +* DESCRIPTION +* STP is ready? +* PARAMETERS +* none. +* RETURNS +* none +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +MTK_WCN_BOOL _mtk_wcn_stp_is_ready(VOID) +#else +MTK_WCN_BOOL mtk_wcn_stp_is_ready(VOID) +#endif +{ + return STP_IS_READY(stp_core_ctx); +} +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +EXPORT_SYMBOL(mtk_wcn_stp_is_ready); +#endif + +/***************************************************************************** +* FUNCTION +* set_bluetooth_rx_interface +* DESCRIPTION +* Set bluetooth rx interface +* PARAMETERS +* rx interface type +* RETURNS +* void +*****************************************************************************/ +#if STP_EXP_HID_API_EXPORT +VOID _mtk_wcn_stp_set_bluez(MTK_WCN_BOOL bluez_flag) +#else +VOID mtk_wcn_stp_set_bluez(MTK_WCN_BOOL bluez_flag) +#endif +{ + /* g_mtkstp_bluez_flag = bluez_flag; */ + STP_SET_BT_STK(stp_core_ctx, bluez_flag); +} +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +EXPORT_SYMBOL(mtk_wcn_stp_set_bluez); +#endif + +/***************************************************************************** +* FUNCTION +* set stp debugging mdoe +* DESCRIPTION +* set stp debugging mdoe +* PARAMETERS +* dbg_mode: switch to dbg mode ? +* RETURNS +* void +*****************************************************************************/ +VOID mtk_wcn_stp_set_dbg_mode(MTK_WCN_BOOL dbg_mode) +{ + STP_SET_ENABLE_DBG(stp_core_ctx, dbg_mode); +} + +/***************************************************************************** +* FUNCTION +* set stp auto reset mdoe +* DESCRIPTION +* set stp auto reset mdoe +* PARAMETERS +* auto_rst: switch to auto reset mode ? +* RETURNS +* void +*****************************************************************************/ +VOID mtk_wcn_stp_set_auto_rst(MTK_WCN_BOOL auto_rst) +{ + STP_SET_ENABLE_RST(stp_core_ctx, auto_rst); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_open_btif +* DESCRIPTION +* init btif hw & sw by owner stp +* PARAMETERS +* VOID +* RETURNS +* INT32 0-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_open_btif(VOID) +{ + return mtk_wcn_consys_stp_btif_open(); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_open_close +* DESCRIPTION +* close btif hw & sw by owner stp +* PARAMETERS +* VOID +* RETURNS +* INT32 0-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_close_btif(VOID) +{ + return mtk_wcn_consys_stp_btif_close(); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_rx_cb_register +* DESCRIPTION +* register stp rx cb to btif +* PARAMETERS +* MTK_WCN_BTIF_RX_CB stp rx handle function +* RETURNS +* INT32 0-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_rxcb_register(MTK_WCN_BTIF_RX_CB rx_cb) +{ + return mtk_wcn_consys_stp_btif_rx_cb_register(rx_cb); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_tx +* DESCRIPTION +* send stp package by btif +* PARAMETERS +* pBuf:package buffer pointer,len:package length +* written_len:package written length +* RETURNS +* INT32 package length-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_tx(UINT8 *pBuf, UINT32 len, UINT32 *written_len) +{ + INT32 iRet = -1; + + iRet = mtk_wcn_consys_stp_btif_tx(pBuf, len, written_len); + return iRet; +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_wakeup_consys +* DESCRIPTION +* STP wakeup consys by btif +* PARAMETERS +* VOID +* RETURNS +* INT32 0-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_wakeup_consys(VOID) +{ + /*log wakeup int for debug */ + stp_dbg_pkt_log(7, 0, 0, 0, PKT_DIR_TX, NULL, 0); + return mtk_wcn_consys_stp_btif_wakeup(); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_dpidle_ctrl +* DESCRIPTION +* decide AP enter or exit deep idle +* PARAMETERS +* en_flag:1,enter,0,exit +* RETURNS +* always 0 +*****************************************************************************/ +INT32 mtk_wcn_stp_dpidle_ctrl(enum _ENUM_BTIF_DPIDLE_ en_flag) +{ + mtk_wcn_consys_stp_btif_dpidle_ctrl(en_flag); + + return 0; +} + +INT32 mtk_wcn_stp_notify_sleep_for_thermal(VOID) +{ + return stp_psm_sleep_for_thermal(STP_PSM_CORE(stp_core_ctx)); +} + +VOID mtk_wcn_stp_set_wmt_trg_assert(UINT32 value) +{ + STP_DBG_FUNC("set evt err tigger assert flag to %d\n", value); + STP_SET_ASSERT(stp_core_ctx, value); +} + +UINT32 mtk_wcn_stp_get_wmt_trg_assert(VOID) +{ + return STP_ASSERT(stp_core_ctx); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_lpbk_ctrl +* DESCRIPTION +* enable stp internal lpbk test or not +* PARAMETERS +* mode:1,enable,0,disabel +* RETURNS +* INT32 0-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_lpbk_ctrl(enum _ENUM_BTIF_LPBK_MODE_ mode) +{ + return mtk_wcn_consys_stp_btif_lpbk_ctrl(mode); +} + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_logger_ctrl +* DESCRIPTION +* dump btif buffer or register status when No ACK or assert occurs +* PARAMETERS +* flag:see enum value in enum _ENUM_BTIF_DBG_ID_ +* RETURNS +* INT32 0-success,other fail. +*****************************************************************************/ +INT32 mtk_wcn_stp_logger_ctrl(enum _ENUM_BTIF_DBG_ID_ flag) +{ + return mtk_wcn_consys_stp_btif_logger_ctrl(flag); +} + +VOID mtk_wcn_stp_ctx_save(void) +{ + STP_DBG_FUNC("start ++\n"); + stp_psm_set_sleep_disable(stp_core_ctx.psm); + STP_DBG_FUNC("exit --\n"); +} + +VOID mtk_wcn_stp_ctx_restore(void) +{ + stp_core_ctx.assert_info_cnt = 0; + + stp_psm_set_sleep_enable(stp_core_ctx.psm); + stp_btm_reset_btm_wq(STP_BTM_CORE(stp_core_ctx)); + + if (STP_IS_ENABLE_RST(stp_core_ctx)) + stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); + else + STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); +} + +INT32 mtk_wcn_stp_wmt_trg_assert(VOID) +{ + INT32 ret = -1; + + if (mtk_wcn_stp_coredump_start_get() != 0) { + STP_INFO_FUNC("firmware assert has been triggered\n"); + return 1; + } + ret = stp_notify_btm_do_fw_assert(STP_BTM_CORE(stp_core_ctx)); + + if (ret) { + STP_ERR_FUNC("trigger assert fail,do chip reset to recovery\n"); + if (STP_IS_ENABLE_RST(stp_core_ctx)) + stp_btm_notify_wmt_rst_wq(STP_BTM_CORE(stp_core_ctx)); + else + STP_INFO_FUNC("No to launch whole chip reset! for debugging purpose\n"); + } + + return ret; +} + +INT32 mtk_wcn_stp_assert_timeout_handle(VOID) +{ + INT32 ret = 0; + P_CONSYS_EMI_ADDR_INFO p_ecsi; + + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) { + mtk_wcn_stp_ctx_restore(); + return ret; + } + + p_ecsi = wmt_plat_get_emi_phy_add(); + /* dump btif data */ + mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_BTIF_REG); + mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_LOG); + mtk_wcn_stp_coredump_start_ctrl(1); + if (p_ecsi != NULL && wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_assert_flag)) { + STP_INFO_FUNC("EMI assert flag was set. To do coredump.\n"); + mtk_wcn_stp_ctx_save(); + ret = stp_btm_notify_wmt_dmp_wq(STP_BTM_CORE(stp_core_ctx)); + } else { + /*host trigger assert timeout and no coredump packet. To dump EMI data*/ + STP_INFO_FUNC("host trigger fw assert timeout!\n"); + WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC("Trigger assert timeout"); + if (mtk_wcn_stp_coredump_flag_get() != 0) + ret = stp_dbg_start_emi_dump(); + else + mtk_wcn_stp_ctx_restore(); + } + return ret; +} + +INT32 mtk_wcn_stp_coredump_timeout_handle(VOID) +{ + /* dump btif data */ + mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_BTIF_REG); + mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_LOG); + + WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC("Coredump timeout"); + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) + mtk_wcn_stp_ctx_restore(); + return 0; +} + +VOID mtk_wcn_stp_dbg_pkt_log(INT32 type, INT32 dir) +{ + stp_dbg_pkt_log(type, 0, 0, 0, dir, NULL, 0); +} + +VOID mtk_stp_sdio_retry_flag_ctrl(INT32 flag) +{ + if (flag) { + if (flag != wmt_dbg_sdio_retry_ctrl) + flag = wmt_dbg_sdio_retry_ctrl; + } + stp_sdio_retry_flag_ctrl(flag == 0 ? 0 : 1); +} + +VOID mtk_stp_dbg_sdio_retry_flag_ctrl(INT32 flag) +{ + wmt_dbg_sdio_retry_ctrl = flag == 0 ? 0 : 1; +} + +INT32 mtk_stp_sdio_retry_flag_get(VOID) +{ + return stp_sdio_retry_flag_get(); +} + +VOID mtk_stp_dump_sdio_register(VOID) +{ + stp_sdio_dump_register(); +} + +INT32 mtk_stp_dbg_dmp_append(PUINT8 buf, INT32 max_len) +{ + return stp_dbg_dmp_append(g_mtkstp_dbg, buf, max_len); +} + +VOID mtk_stp_notify_emi_dump_end(VOID) +{ + stp_btm_notify_emi_dump_end(STP_BTM_CORE(stp_core_ctx)); +} + +INT32 mtk_stp_check_rx_has_pending_data(VOID) +{ + return sys_rx_has_pending_data(); +} + +P_OSAL_THREAD mtk_stp_rx_thread_get(VOID) +{ + return sys_rx_thread_get(); +} + +VOID mtk_wcn_stp_assert_flow_ctrl(UINT32 on) +{ + STP_DBG_FUNC("Set assert progress flag to %d\n", on); + STP_SET_ASSERT_IN_PROGRESS(stp_core_ctx, on); +} + +UINT32 mtk_wcn_stp_assert_flow_get(VOID) +{ + return STP_ASSERT_IN_PROGRESS(stp_core_ctx); +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/stp_exp.c b/drivers/misc/mediatek/connectivity/common/common_main/core/stp_exp.c new file mode 100644 index 00000000000000..1c1770fb2b8fee --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/stp_exp.c @@ -0,0 +1,442 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#if 0 /* to do---- need check why need this header file */ +#include <linux/types.h> +#include <linux/major.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/fcntl.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/timer.h> +#include <linux/ctype.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/poll.h> +#include <linux/bitops.h> +#include <linux/audit.h> +#include <linux/file.h> +#include <linux/module.h> + +#include <linux/spinlock.h> +#include <linux/delay.h> /* udelay() */ + +#include <linux/uaccess.h> +#include <asm/system.h> +#endif +#include "osal_typedef.h" +#include "stp_core.h" +#include "stp_exp.h" +#include "hif_sdio.h" +#include "stp_sdio.h" +#include "stp_dbg.h" +#include "wmt_stp_exp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static MTK_WCN_STP_IF_TX stp_uart_if_tx; +static MTK_WCN_STP_IF_TX stp_sdio_if_tx; +static MTK_WCN_STP_IF_TX stp_btif_if_tx; +static MTK_WCN_STP_RX_HAS_PENDING_DATA stp_btif_rx_has_pending_data; +static MTK_WCN_STP_TX_HAS_PENDING_DATA stp_btif_tx_has_pending_data; +static MTK_WCN_STP_RX_THREAD_GET stp_btif_rx_thread_get; +static ENUM_STP_TX_IF_TYPE g_stp_if_type = STP_MAX_IF_TX; +static MTK_WCN_STP_IF_RX stp_if_rx; +static MTK_WCN_STP_EVENT_CB event_callback_tbl[MTKSTP_MAX_TASK_NUM] = { 0x0 }; +static MTK_WCN_STP_EVENT_CB tx_event_callback_tbl[MTKSTP_MAX_TASK_NUM] = { 0x0 }; + +/****************************************************************************** +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************* +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +INT32 mtk_wcn_sys_if_rx(PUINT8 data, INT32 size) +{ + if (stp_if_rx == 0x0) + return -1; + (*stp_if_rx)(data, size); + return 0; +} + +static INT32 mtk_wcn_sys_if_tx(const PUINT8 data, const UINT32 size, PUINT32 written_size) +{ + if (g_stp_if_type == STP_UART_IF_TX) + return stp_uart_if_tx != NULL ? (*stp_uart_if_tx)(data, size, written_size) : -1; + else if (g_stp_if_type == STP_SDIO_IF_TX) + return stp_sdio_if_tx != NULL ? (*stp_sdio_if_tx)(data, size, written_size) : -1; + else if (g_stp_if_type == STP_BTIF_IF_TX) + return stp_btif_if_tx != NULL ? (*stp_btif_if_tx) (data, size, written_size) : -1; + /*if (g_stp_if_type >= STP_MAX_IF_TX) *//* George: remove ALWAYS TRUE condition */ + return -1; +} + +static INT32 mtk_wcn_sys_rx_has_pending_data(VOID) +{ + if (g_stp_if_type == STP_BTIF_IF_TX) + return stp_btif_rx_has_pending_data != NULL ? (*stp_btif_rx_has_pending_data) () : -1; + return -1; +} + +static INT32 mtk_wcn_sys_tx_has_pending_data(VOID) +{ + if (g_stp_if_type == STP_BTIF_IF_TX) + return stp_btif_tx_has_pending_data != NULL ? (*stp_btif_tx_has_pending_data) () : -1; + return -1; +} + +static P_OSAL_THREAD mtk_wcn_sys_rx_thread_get(VOID) +{ + if (g_stp_if_type == STP_BTIF_IF_TX) + return stp_btif_rx_thread_get != NULL ? (*stp_btif_rx_thread_get) () : NULL; + return NULL; +} + +static INT32 mtk_wcn_sys_event_set(UINT8 function_type) +{ + if ((function_type < MTKSTP_MAX_TASK_NUM) && (event_callback_tbl[function_type] != 0x0)) + (*event_callback_tbl[function_type])(); + else { + /* FIXME: error handling */ + osal_dbg_print("[%s] STP set event fail. It seems the function is not active.\n", + __func__); + } + + return 0; +} + +static INT32 mtk_wcn_sys_event_tx_resume(UINT8 winspace) +{ + int type = 0; + + for (type = 0; type < MTKSTP_MAX_TASK_NUM; type++) { + if (tx_event_callback_tbl[type]) + tx_event_callback_tbl[type](); + } + + return 0; +} + +static INT32 mtk_wcn_sys_check_function_status(UINT8 type, UINT8 op) +{ + + /*op == FUNCTION_ACTIVE, to check if funciton[type] is active ? */ + if (type >= MTKSTP_MAX_TASK_NUM) + return STATUS_FUNCTION_INVALID; + + if (op == OP_FUNCTION_ACTIVE) { + if (event_callback_tbl[type] != 0x0) + return STATUS_FUNCTION_ACTIVE; + return STATUS_FUNCTION_INACTIVE; + } + /*you can define more operation here ..., to queury function's status/information */ + + return STATUS_OP_INVALID; +} + +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func) +{ + stp_if_rx = func; + + return 0; +} +#endif + +VOID mtk_wcn_stp_set_if_tx_type(ENUM_STP_TX_IF_TYPE stp_if_type) +{ + g_stp_if_type = stp_if_type; + osal_dbg_print("[%s] set STP_IF_TX to %s.\n", + __func__, + (STP_UART_IF_TX == + stp_if_type) ? "UART" : ((STP_SDIO_IF_TX == + stp_if_type) ? "SDIO" : "NULL")); +} + +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func) +#else +INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func) +#endif +{ + if (stp_if == STP_UART_IF_TX) + stp_uart_if_tx = func; + else if (stp_if == STP_SDIO_IF_TX) + stp_sdio_if_tx = func; + else if (stp_if == STP_BTIF_IF_TX) + stp_btif_if_tx = func; + else { + osal_dbg_print("[%s] STP_IF_TX(%d) out of boundary.\n", __func__, stp_if); + return -1; + } + + return 0; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_register_if_tx); +#endif + +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +#else +INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +#endif +{ + if (type < MTKSTP_MAX_TASK_NUM) { + event_callback_tbl[type] = func; + + /*clear rx queue */ + mtk_wcn_stp_flush_rx_queue(type); + } + + return 0; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_register_event_cb); +#endif + +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +#else +INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func) +#endif +{ + if (type < MTKSTP_MAX_TASK_NUM) + tx_event_callback_tbl[type] = func; + else + osal_bug_on(0); + + return 0; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_register_tx_event_cb); +#endif + +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_register_rx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_HAS_PENDING_DATA func) +#else +INT32 mtk_wcn_stp_register_rx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_HAS_PENDING_DATA func) +#endif +{ + if (stp_if == STP_BTIF_IF_TX) + stp_btif_rx_has_pending_data = func; + else { + osal_dbg_print("[%s] STP_IF_TX(%d) out of boundary.\n", __func__, stp_if); + return -1; + } + + return 0; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_register_rx_has_pending_data); +#endif + +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_register_tx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_TX_HAS_PENDING_DATA func) +#else +INT32 mtk_wcn_stp_register_tx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_TX_HAS_PENDING_DATA func) +#endif +{ + if (stp_if == STP_BTIF_IF_TX) + stp_btif_tx_has_pending_data = func; + else { + osal_dbg_print("[%s] STP_IF_TX(%d) out of boundary.\n", __func__, stp_if); + return -1; + } + + return 0; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_register_tx_has_pending_data); +#endif + +#if STP_EXP_HID_API_EXPORT +INT32 _mtk_wcn_stp_register_rx_thread_get(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_THREAD_GET func) +#else +INT32 mtk_wcn_stp_register_rx_thread_get(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_THREAD_GET func) +#endif +{ + if (stp_if == STP_BTIF_IF_TX) + stp_btif_rx_thread_get = func; + else { + osal_dbg_print("[%s] STP_IF_TX(%d) out of boundary.\n", __func__, stp_if); + return -1; + } + + return 0; +} +#if !STP_EXP_HID_API_EXPORT +EXPORT_SYMBOL(mtk_wcn_stp_register_rx_thread_get); +#endif + +#define WMT_STP_EXP_INFO_FUNC(fmt, arg...) printk(DFT_TAG "[I]%s: " fmt, __FUNCTION__ ,##arg) + +MTK_WCN_STP_SEND_DATA mtk_wcn_stp_send_data_f = NULL; +MTK_WCN_STP_SEND_DATA mtk_wcn_stp_send_data_raw_f = NULL; +MTK_WCN_STP_PARSER_DATA mtk_wcn_stp_parser_data_f = NULL; +MTK_WCN_STP_RECV_DATA mtk_wcn_stp_receive_data_f = NULL; +MTK_WCN_STP_IS_RXQ_EMPTY mtk_wcn_stp_is_rxqueue_empty_f = NULL; +MTK_WCN_STP_IS_RDY mtk_wcn_stp_is_ready_f = NULL; +MTK_WCN_STP_SET_BLUEZ mtk_wcn_stp_set_bluez_f = NULL; +MTK_WCN_STP_REG_IF_TX mtk_wcn_stp_if_tx_f = NULL; +MTK_WCN_STP_REG_IF_RX mtk_wcn_stp_if_rx_f = NULL; +MTK_WCN_STP_REG_EVENT_CB mtk_wcn_stp_reg_event_cb_f = NULL; +MTK_WCN_STP_RGE_TX_EVENT_CB mtk_wcn_stp_reg_tx_event_cb_f = NULL; +MTK_WCN_STP_COREDUMP_START_GET mtk_wcn_stp_coredump_start_get_f = NULL; + +MTK_WCN_WMT_FUNC_CTRL mtk_wcn_wmt_func_on_f = NULL; +MTK_WCN_WMT_FUNC_CTRL mtk_wcn_wmt_func_off_f = NULL; +MTK_WCN_WMT_THERM_CTRL mtk_wcn_wmt_therm_ctrl_f = NULL; +MTK_WCN_WMT_HWVER_GET mtk_wcn_wmt_hwver_get_f = NULL; +MTK_WCN_WMT_DSNS_CTRL mtk_wcn_wmt_dsns_ctrl_f = NULL; +MTK_WCN_WMT_MSGCB_REG mtk_wcn_wmt_msgcb_reg_f = NULL; +MTK_WCN_WMT_MSGCB_UNREG mtk_wcn_wmt_msgcb_unreg_f = NULL; +MTK_WCN_WMT_SDIO_OP_REG mtk_wcn_wmt_sdio_op_reg_f = NULL; +MTK_WCN_WMT_SDIO_HOST_AWAKE mtk_wcn_wmt_sdio_host_awake_f = NULL; +MTK_WCN_WMT_ASSERT mtk_wcn_wmt_assert_f = NULL; +MTK_WCN_WMT_IC_INFO_GET mtk_wcn_wmt_ic_info_get_f = NULL; +MTK_WCN_WMT_PSM_CTRL mtk_wcn_wmt_psm_ctrl_f = NULL; + +UINT32 mtk_wcn_stp_exp_cb_reg(P_MTK_WCN_STP_EXP_CB_INFO pStpExpCb) +{ + WMT_STP_EXP_INFO_FUNC("call stp exp cb reg\n"); + + mtk_wcn_stp_send_data_f = pStpExpCb->stp_send_data_cb; + mtk_wcn_stp_send_data_raw_f = pStpExpCb->stp_send_data_raw_cb; + mtk_wcn_stp_parser_data_f = pStpExpCb->stp_parser_data_cb; + mtk_wcn_stp_receive_data_f = pStpExpCb->stp_receive_data_cb; + mtk_wcn_stp_is_rxqueue_empty_f = pStpExpCb->stp_is_rxqueue_empty_cb; + mtk_wcn_stp_is_ready_f = pStpExpCb->stp_is_ready_cb; + mtk_wcn_stp_set_bluez_f = pStpExpCb->stp_set_bluez_cb; + mtk_wcn_stp_if_tx_f = pStpExpCb->stp_if_tx_cb; + mtk_wcn_stp_if_rx_f = pStpExpCb->stp_if_rx_cb; + mtk_wcn_stp_reg_event_cb_f = pStpExpCb->stp_reg_event_cb; + mtk_wcn_stp_reg_tx_event_cb_f = pStpExpCb->stp_reg_tx_event_cb; + mtk_wcn_stp_coredump_start_get_f = pStpExpCb->stp_coredump_start_get_cb; + + return 0; +} + +EXPORT_SYMBOL(mtk_wcn_stp_exp_cb_reg); + +UINT32 mtk_wcn_stp_exp_cb_unreg(VOID) +{ + WMT_STP_EXP_INFO_FUNC("call stp exp cb unreg\n"); + + mtk_wcn_stp_send_data_f = NULL; + mtk_wcn_stp_send_data_raw_f = NULL; + mtk_wcn_stp_parser_data_f = NULL; + mtk_wcn_stp_receive_data_f = NULL; + mtk_wcn_stp_is_rxqueue_empty_f = NULL; + mtk_wcn_stp_is_ready_f = NULL; + mtk_wcn_stp_set_bluez_f = NULL; + mtk_wcn_stp_if_tx_f = NULL; + mtk_wcn_stp_if_rx_f = NULL; + mtk_wcn_stp_reg_event_cb_f = NULL; + mtk_wcn_stp_reg_tx_event_cb_f = NULL; + mtk_wcn_stp_coredump_start_get_f= NULL; + + return 0; +} + +EXPORT_SYMBOL(mtk_wcn_stp_exp_cb_unreg); + +INT32 stp_drv_init(VOID) +{ + INT32 ret = 0; + + mtkstp_callback cb = { + .cb_if_tx = mtk_wcn_sys_if_tx, + .cb_rx_has_pending_data = mtk_wcn_sys_rx_has_pending_data, + .cb_tx_has_pending_data = mtk_wcn_sys_tx_has_pending_data, + .cb_rx_thread_get = mtk_wcn_sys_rx_thread_get, + .cb_event_set = mtk_wcn_sys_event_set, + .cb_event_tx_resume = mtk_wcn_sys_event_tx_resume, + .cb_check_funciton_status = mtk_wcn_sys_check_function_status + }; +//#if 0 +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + MTK_WCN_STP_EXP_CB_INFO stpExpCb = { + .stp_send_data_cb = mtk_wcn_stp_send_data, + .stp_send_data_raw_cb = mtk_wcn_stp_send_data_raw, + .stp_parser_data_cb = mtk_wcn_stp_parser_data, + .stp_receive_data_cb = mtk_wcn_stp_receive_data, + .stp_is_rxqueue_empty_cb = mtk_wcn_stp_is_rxqueue_empty, + .stp_is_ready_cb = mtk_wcn_stp_is_ready, + .stp_set_bluez_cb = mtk_wcn_stp_set_bluez, + .stp_if_tx_cb = mtk_wcn_stp_register_if_tx, + .stp_if_rx_cb = mtk_wcn_stp_register_if_rx, + .stp_reg_event_cb = mtk_wcn_stp_register_event_cb, + .stp_reg_tx_event_cb = mtk_wcn_stp_register_tx_event_cb, + .stp_coredump_start_get_cb = mtk_wcn_stp_coredump_start_get + }; + mtk_wcn_stp_exp_cb_reg(&stpExpCb); + +#endif +//#endif + ret = mtk_wcn_stp_init(&cb); + + return ret; +} + +VOID stp_drv_exit(VOID) +{ + mtk_wcn_stp_deinit(); +//#if 0 +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + mtk_wcn_stp_exp_cb_unreg(); +#endif +//#endif +} + +INT32 mtk_wcn_stp_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx) +{ + stp_sdio_wake_up_ctrl(ctx); + return 0; +} +EXPORT_SYMBOL(mtk_wcn_stp_sdio_wake_up_ctrl); + +INT32 mtk_stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd) +{ + return stp_dbg_poll_cpupcr(times, sleep, cmd); +} +EXPORT_SYMBOL(mtk_stp_dbg_poll_cpupcr); diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_conf.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_conf.c new file mode 100644 index 00000000000000..20e283922ed3d8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_conf.c @@ -0,0 +1,683 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONF]" + + +#include "osal_typedef.h" +/* #include "osal.h" */ +#include "wmt_lib.h" +#include "wmt_dev.h" +#include "wmt_conf.h" +#include "wmt_detect.h" + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +struct parse_data { + PINT8 name; + INT32 (*parser)(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 value); + PINT8 (*writer)(P_DEV_WMT pWmtDev, const struct parse_data *data); + /*PCHAR param1, *param2, *param3; */ + /* TODO:[FixMe][George] CLARIFY WHAT SHOULD BE USED HERE!!! */ + PINT8 param1; + PINT8 param2; + PINT8 param3; +}; + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/****************************************************************************** +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************* +*/ +static INT32 wmt_conf_parse_char(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos); + +static PINT8 wmt_conf_write_char(P_DEV_WMT pWmtDev, const struct parse_data *data); + +static INT32 wmt_conf_parse_short(P_DEV_WMT pWmtDev, + const struct parse_data *data, const PINT8 pos); + +static PINT8 wmt_conf_write_short(P_DEV_WMT pWmtDev, const struct parse_data *data); + +static INT32 wmt_conf_parse_int(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos); + +static PINT8 wmt_conf_write_int(P_DEV_WMT pWmtDev, const struct parse_data *data); + +static INT32 wmt_conf_parse_byte_array(P_DEV_WMT pWmtDev, const struct parse_data *data, + const PINT8 pos); + +static PINT8 wmt_conf_write_byte_array(P_DEV_WMT pWmtDev, const struct parse_data *data); + +static INT32 wmt_conf_parse_string(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos); + +static PINT8 wmt_conf_write_string(P_DEV_WMT pWmtDev, const struct parse_data *data); + +static INT32 wmt_conf_parse_pair(P_DEV_WMT pWmtDev, const PINT8 pKey, const PINT8 pVal); + +static INT32 wmt_conf_parse(P_DEV_WMT pWmtDev, const PINT8 pInBuf, UINT32 size); + +#define OFFSET(v) ((void *) &((P_DEV_WMT) 0)->v) + +#define CHAR(f) {#f, wmt_conf_parse_char, wmt_conf_write_char, OFFSET(rWmtGenConf.f), NULL, NULL} + +#define SHORT(f) {#f, wmt_conf_parse_short, wmt_conf_write_short, OFFSET(rWmtGenConf.f), NULL, NULL} + +#define INT(f) {#f, wmt_conf_parse_int, wmt_conf_write_int, OFFSET(rWmtGenConf.f), NULL, NULL} + +#define BYTE_ARRAY(f) {#f, wmt_conf_parse_byte_array, wmt_conf_write_byte_array, \ + OFFSET(rWmtGenConf.f), NULL, NULL} + +#define STRING(f) {#f, wmt_conf_parse_string, wmt_conf_write_string, OFFSET(rWmtGenConf.f), NULL, NULL} + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static const struct parse_data wmtcfg_fields[] = { + CHAR(coex_wmt_ant_mode), + CHAR(coex_wmt_ant_mode_ex), + CHAR(coex_wmt_ext_component), + CHAR(coex_wmt_wifi_time_ctl), + CHAR(coex_wmt_ext_pta_dev_on), + CHAR(coex_wmt_filter_mode), + + CHAR(coex_bt_rssi_upper_limit), + CHAR(coex_bt_rssi_mid_limit), + CHAR(coex_bt_rssi_lower_limit), + CHAR(coex_bt_pwr_high), + CHAR(coex_bt_pwr_mid), + CHAR(coex_bt_pwr_low), + + CHAR(coex_wifi_rssi_upper_limit), + CHAR(coex_wifi_rssi_mid_limit), + CHAR(coex_wifi_rssi_lower_limit), + CHAR(coex_wifi_pwr_high), + CHAR(coex_wifi_pwr_mid), + CHAR(coex_wifi_pwr_low), + + CHAR(coex_ext_pta_hi_tx_tag), + CHAR(coex_ext_pta_hi_rx_tag), + CHAR(coex_ext_pta_lo_tx_tag), + CHAR(coex_ext_pta_lo_rx_tag), + SHORT(coex_ext_pta_sample_t1), + SHORT(coex_ext_pta_sample_t2), + CHAR(coex_ext_pta_wifi_bt_con_trx), + + INT(coex_misc_ext_pta_on), + INT(coex_misc_ext_feature_set), + + CHAR(wmt_gps_lna_pin), + CHAR(wmt_gps_lna_enable), + + CHAR(pwr_on_rtc_slot), + CHAR(pwr_on_ldo_slot), + CHAR(pwr_on_rst_slot), + CHAR(pwr_on_off_slot), + CHAR(pwr_on_on_slot), + CHAR(co_clock_flag), + + CHAR(disable_deep_sleep_cfg), + + INT(sdio_driving_cfg), + + SHORT(coex_wmt_wifi_path), + + CHAR(coex_wmt_ext_elna_gain_p1_support), + INT(coex_wmt_ext_elna_gain_p1_D0), + INT(coex_wmt_ext_elna_gain_p1_D1), + INT(coex_wmt_ext_elna_gain_p1_D2), + INT(coex_wmt_ext_elna_gain_p1_D3), + STRING(coex_wmt_antsel_invert_support), + CHAR(coex_wmt_ext_epa_mode), + + BYTE_ARRAY(coex_wmt_epa_elna), + + CHAR(bt_tssi_from_wifi), + SHORT(bt_tssi_target), + + CHAR(coex_config_bt_ctrl), + CHAR(coex_config_bt_ctrl_mode), + CHAR(coex_config_bt_ctrl_rw), + + CHAR(coex_config_addjust_opp_time_ratio), + CHAR(coex_config_addjust_opp_time_ratio_bt_slot), + CHAR(coex_config_addjust_opp_time_ratio_wifi_slot), + + CHAR(coex_config_addjust_ble_scan_time_ratio), + CHAR(coex_config_addjust_ble_scan_time_ratio_bt_slot), + CHAR(coex_config_addjust_ble_scan_time_ratio_wifi_slot), + + CHAR(wifi_ant_swap_mode), + CHAR(wifi_main_ant_polarity), + CHAR(wifi_ant_swap_ant_sel_gpio), +}; + +#define NUM_WMTCFG_FIELDS (osal_sizeof(wmtcfg_fields) / osal_sizeof(wmtcfg_fields[0])) + +static INT32 wmt_conf_parse_char(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos) +{ + PUINT8 dst; + long res = 0; + + dst = (PINT8)(((PUINT8) pWmtDev) + (long)data->param1); + + if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { + osal_strtol(pos + 2, 16, &res); + *dst = (UINT8)res; + WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst); + } else { + osal_strtol(pos, 10, &res); + *dst = (UINT8)res; + WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst); + } + return 0; +} + +static PINT8 wmt_conf_write_char(P_DEV_WMT pWmtDev, const struct parse_data *data) +{ + PINT8 src; + INT32 res; + PINT8 value; + + src = (PINT8) (((PUINT8) pWmtDev) + (long)data->param1); + + value = osal_malloc(20); + if (value == NULL) + return NULL; + res = osal_snprintf(value, 20, "0x%x", *src); + if (res < 0 || res >= 20) { + osal_free(value); + return NULL; + } + value[20 - 1] = '\0'; + return value; +} + +static INT32 wmt_conf_parse_short(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos) +{ + PUINT16 dst; + long res = 0; + + dst = (PINT16)(((PUINT8) pWmtDev) + (long)data->param1); + + /* WMT_INFO_FUNC(">strlen(pos)=%d\n", strlen(pos)); */ + + if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { + osal_strtol(pos + 2, 16, &res); + *dst = (UINT16)res; + WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst); + } else { + osal_strtol(pos, 10, &res); + *dst = (UINT16)res; + WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst); + } + + return 0; +} + +static PINT8 wmt_conf_write_short(P_DEV_WMT pWmtDev, const struct parse_data *data) +{ + PINT16 src; + INT32 res; + PINT8 value; + + /* TODO: [FixMe][George] FIX COMPILE WARNING HERE! */ + src = (PINT16) (((PUINT8) pWmtDev) + (long)data->param1); + + value = osal_malloc(20); + if (value == NULL) + return NULL; + res = osal_snprintf(value, 20, "0x%x", *src); + if (res < 0 || res >= 20) { + osal_free(value); + return NULL; + } + value[20 - 1] = '\0'; + return value; +} + +static INT32 wmt_conf_parse_int(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos) +{ + PUINT32 dst; + long res = 0; + + dst = (PINT32)(((PUINT8) pWmtDev) + (long)data->param1); + + /* WMT_INFO_FUNC(">strlen(pos)=%d\n", strlen(pos)); */ + + if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { + osal_strtol(pos + 2, 16, &res); + *dst = (UINT32)res; + WMT_DBG_FUNC("wmtcfg==> %s=0x%x\n", data->name, *dst); + } else { + osal_strtol(pos, 10, &res); + *dst = (UINT32)res; + WMT_DBG_FUNC("wmtcfg==> %s=%d\n", data->name, *dst); + } + + return 0; +} + +static PINT8 wmt_conf_write_int(P_DEV_WMT pWmtDev, const struct parse_data *data) +{ + PINT32 src; + INT32 res; + PINT8 value; + + src = (PUINT32) (((PUINT8) pWmtDev) + (long) data->param1); + + value = osal_malloc(20); + if (value == NULL) + return NULL; + res = osal_snprintf(value, 20, "0x%x", *src); + if (res < 0 || res >= 20) { + osal_free(value); + return NULL; + } + value[20 - 1] = '\0'; + return value; +} + +static INT32 wmt_conf_parse_string(P_DEV_WMT pWmtDev, const struct parse_data *data, const PINT8 pos) +{ + PUINT8 *dst; + PUINT8 buffer; + + buffer = osal_malloc(osal_strlen(pos)+1); + if (buffer == NULL) { + WMT_ERR_FUNC("wmtcfg==> %s malloc fail, size %d\n", data->name, osal_strlen(pos)+1); + return -1; + } + + osal_strcpy(buffer, pos); + dst = (PUINT8 *)(((PUINT8) pWmtDev) + (long)data->param1); + *dst = (PUINT8)buffer; + WMT_DBG_FUNC("wmtcfg==> %s=%s\n", data->name, *dst); + + return 0; +} + +static PINT8 wmt_conf_write_string(P_DEV_WMT pWmtDev, const struct parse_data *data) +{ + PUINT8 *src; + INT32 res; + PINT8 value; + UINT32 str_size; + + src = (PUINT8 *)(((PUINT8) pWmtDev) + (long)data->param1); + if (*src == NULL) + return NULL; + + str_size = osal_strlen(*src) + 1; + value = osal_malloc(str_size); + if (value == NULL) + return NULL; + + res = osal_snprintf(value, str_size, "%s", *src); + if (res < 0 || res >= str_size) { + osal_free(value); + return NULL; + } + + value[str_size - 1] = '\0'; + return value; +} + +static INT32 wmt_conf_parse_byte_array(P_DEV_WMT pWmtDev, + const struct parse_data *data, const PINT8 pos) +{ + PUINT8 *dst; + struct WMT_BYTE_ARRAY *ba; + PUINT8 buffer; + INT32 size = osal_strlen(pos) / 2; + UINT8 temp[3]; + INT32 i; + long value; + + if (size <= 1) { + WMT_ERR_FUNC("wmtcfg==> %s has no value assigned\n", + data->name); + return -1; + } else if (size & 0x1) { + WMT_ERR_FUNC("wmtcfg==> %s, length should be even\n", data->name); + return -1; + } + + ba = (struct WMT_BYTE_ARRAY *)osal_malloc(sizeof(struct WMT_BYTE_ARRAY)); + if (ba == NULL) { + WMT_ERR_FUNC("wmtcfg==> %s malloc fail\n", data->name); + return -1; + } + + buffer = osal_malloc(size); + if (buffer == NULL) { + osal_free(ba); + WMT_ERR_FUNC("wmtcfg==> %s malloc fail, size %d\n", data->name, size); + return -1; + } + + temp[2] = '\0'; + for (i = 0; i < size; i++) { + osal_memcpy(temp, &pos[i * 2], 2); + if (osal_strtol(temp, 16, &value) < 0) { + WMT_ERR_FUNC("wmtcfg==> %s should be hexadecimal format\n", data->name); + osal_free(ba); + osal_free(buffer); + return -1; + } + buffer[i] = (UINT8)value; + } + ba->data = buffer; + ba->size = size; + + dst = (PUINT8 *)(((PUINT8) pWmtDev) + (long)data->param1); + *dst = (PUINT8)ba; + + return 0; +} + +static PINT8 wmt_conf_write_byte_array(P_DEV_WMT pWmtDev, const struct parse_data *data) +{ + PUINT8 *src; + PINT8 value; + struct WMT_BYTE_ARRAY *ba; + INT32 i; + + src = (PUINT8 *) (((PUINT8) pWmtDev) + (long)data->param1); + if (*src == NULL) + return NULL; + + ba = (struct WMT_BYTE_ARRAY *)*src; + + value = osal_malloc(ba->size * 2 + 1); + if (value == NULL) + return NULL; + + for (i = 0; i < ba->size; i++) + osal_snprintf(&value[i * 2], 3, "%x", ba->data[i]); + + return value; +} + +static INT32 wmt_conf_parse_pair(P_DEV_WMT pWmtDev, const PINT8 pKey, const PINT8 pVal) +{ + INT32 i = 0; + INT32 ret = 0; + + /* WMT_INFO_FUNC( DBG_NAME "cfg(%s) val(%s)\n", pKey, pVal); */ + + for (i = 0; i < NUM_WMTCFG_FIELDS; i++) { + const struct parse_data *field = &wmtcfg_fields[i]; + + if (osal_strcmp(pKey, field->name) != 0) + continue; + if (field->parser(pWmtDev, field, pVal)) { + WMT_ERR_FUNC("failed to parse %s '%s'.\n", pKey, pVal); + ret = -1; + } + break; + } + if (i == NUM_WMTCFG_FIELDS) { + WMT_ERR_FUNC("unknown field '%s'.\n", pKey); + ret = -1; + } + + return ret; +} + +static INT32 wmt_conf_parse(P_DEV_WMT pWmtDev, const PINT8 pInBuf, UINT32 size) +{ + PINT8 pch; + PINT8 pBuf; + PINT8 pLine; + PINT8 pKey; + PINT8 pVal; + PINT8 pPos; + INT32 ret = 0; + INT32 i = 0; + PINT8 pa = NULL; + + pBuf = osal_malloc(size+1); + if (!pBuf) + return -1; + + osal_memcpy(pBuf, pInBuf, size); + pBuf[size] = '\0'; + + pch = pBuf; + /* pch is to be updated by strsep(). Keep pBuf unchanged!! */ + +#if 0 + { + PINT8 buf_ptr = pBuf; + INT32 k = 0; + + WMT_INFO_FUNC("%s len=%d", "wmcfg.content:", size); + for (k = 0; k < size; k++) { + /* if(k%16 == 0) WMT_INFO_FUNC("\n"); */ + WMT_INFO_FUNC("%c", buf_ptr[k]); + } + WMT_INFO_FUNC("--end\n"); + } +#endif + + while ((pLine = osal_strsep(&pch, "\r\n")) != NULL) { + /* pch is updated to the end of pLine by strsep() and updated to '\0' */ + /*WMT_INFO_FUNC("strsep offset(%d), char(%d, '%c' )\n", pLine-pBuf, *pLine, *pLine); */ + /* parse each line */ + + /* WMT_INFO_FUNC("==> Line = (%s)\n", pLine); */ + + if (!*pLine) + continue; + + pVal = osal_strchr(pLine, '='); + if (!pVal) { + WMT_WARN_FUNC("mal-format cfg string(%s)\n", pLine); + continue; + } + + /* |<-pLine->|'='<-pVal->|'\n' ('\0')| */ + *pVal = '\0'; /* replace '=' with '\0' to get key */ + /* |<-pKey->|'\0'|<-pVal->|'\n' ('\0')| */ + pKey = pLine; + + if ((pVal - pBuf) < size) + pVal++; + + /*key handling */ + pPos = pKey; + /*skip space characeter */ + while (((*pPos) == ' ') || ((*pPos) == '\t') || ((*pPos) == '\n')) { + if ((pPos - pBuf) >= size) + break; + pPos++; + } + /*key head */ + pKey = pPos; + while (((*pPos) != ' ') && ((*pPos) != '\t') && ((*pPos) != '\0') + && ((*pPos) != '\n')) { + if ((pPos - pBuf) >= size) + break; + pPos++; + } + /*key tail */ + (*pPos) = '\0'; + + /*value handling */ + pPos = pVal; + /*skip space characeter */ + while (((*pPos) == ' ') || ((*pPos) == '\t') || ((*pPos) == '\n')) { + if ((pPos - pBuf) >= size) + break; + pPos++; + } + /*value head */ + pVal = pPos; + while (((*pPos) != ' ') && ((*pPos) != '\t') && ((*pPos) != '\0') + && ((*pPos) != '\n')) { + if ((pPos - pBuf) >= size) + break; + pPos++; + } + /*value tail */ + (*pPos) = '\0'; + + /* WMT_DBG_FUNC("parse (key: #%s#, value: #%s#)\n", pKey, pVal); */ + ret = wmt_conf_parse_pair(pWmtDev, pKey, pVal); + WMT_DBG_FUNC("parse (%s, %s, %d)\n", pKey, pVal, ret); + if (ret) + WMT_WARN_FUNC("parse fail (%s, %s, %d)\n", pKey, pVal, ret); + } + + for (i = 0; i < NUM_WMTCFG_FIELDS; i++) { + const struct parse_data *field = &wmtcfg_fields[i]; + + pa = field->writer(pWmtDev, field); + if (pa) { + WMT_DBG_FUNC("#%d(%s)=>%s\n", i, field->name, pa); + osal_free(pa); + } else + WMT_ERR_FUNC("failed to parse '%s'.\n", field->name); + } + osal_free(pBuf); + return 0; +} + + +INT32 wmt_conf_set_cfg_file(const PINT8 name) +{ + if (name == NULL) { + WMT_ERR_FUNC("name is NULL\n"); + return -1; + } + if (osal_strlen(name) >= osal_sizeof(gDevWmt.cWmtcfgName)) { + WMT_ERR_FUNC("name is too long, length=%d, expect to < %zu\n", osal_strlen(name), + osal_sizeof(gDevWmt.cWmtcfgName)); + return -2; + } + osal_memset(&gDevWmt.cWmtcfgName[0], 0, osal_sizeof(gDevWmt.cWmtcfgName)); + osal_strcpy(&(gDevWmt.cWmtcfgName[0]), name); + WMT_ERR_FUNC("WMT config file is set to (%s)\n", &(gDevWmt.cWmtcfgName[0])); + + return 0; +} + + +INT32 wmt_conf_read_file(VOID) +{ + INT32 ret = -1; + ENUM_WMT_CHIP_TYPE chip_type; + + osal_memset(&gDevWmt.rWmtGenConf, 0, osal_sizeof(gDevWmt.rWmtGenConf)); + osal_memset(&gDevWmt.pWmtCfg, 0, osal_sizeof(gDevWmt.pWmtCfg)); + chip_type = wmt_detect_get_chip_type(); + if (chip_type == WMT_CHIP_TYPE_SOC) { + osal_memset(&gDevWmt.cWmtcfgName[0], 0, osal_sizeof(gDevWmt.cWmtcfgName)); + + osal_strncat(&(gDevWmt.cWmtcfgName[0]), CUST_CFG_WMT_SOC, osal_sizeof(CUST_CFG_WMT_SOC)); + } + + if (!osal_strlen(&(gDevWmt.cWmtcfgName[0]))) { + WMT_ERR_FUNC("empty Wmtcfg name\n"); + osal_assert(0); + return ret; + } + WMT_DBG_FUNC("WMT config file:%s\n", &(gDevWmt.cWmtcfgName[0])); + if (0 == + wmt_dev_patch_get(&gDevWmt.cWmtcfgName[0], (osal_firmware **) &gDevWmt.pWmtCfg)) { + /*get full name patch success */ + WMT_DBG_FUNC("get full file name(%s) buf(0x%p) size(%zu)\n", + &gDevWmt.cWmtcfgName[0], gDevWmt.pWmtCfg->data, + gDevWmt.pWmtCfg->size); + if (0 == + wmt_conf_parse(&gDevWmt, (const PINT8)gDevWmt.pWmtCfg->data, + gDevWmt.pWmtCfg->size)) { + /*config file exists */ + gDevWmt.rWmtGenConf.cfgExist = 1; + WMT_DBG_FUNC("&gDevWmt.rWmtGenConf=%p\n", &gDevWmt.rWmtGenConf); + ret = 0; + } else { + WMT_ERR_FUNC("wmt conf parsing fail\n"); + osal_assert(0); + ret = -1; + } + wmt_dev_patch_put((osal_firmware **) &gDevWmt.pWmtCfg); +/* +* if (gDevWmt.pWmtCfg) +* { +* if (gDevWmt.pWmtCfg->data) +* { +* osal_free(gDevWmt.pWmtCfg->data); +* } +* osal_free(gDevWmt.pWmtCfg); +* gDevWmt.pWmtCfg = 0; +* } +*/ + return ret; + } + WMT_ERR_FUNC("read %s file fails\n", &(gDevWmt.cWmtcfgName[0])); + osal_assert(0); + gDevWmt.rWmtGenConf.cfgExist = 0; + return ret; +} + +P_WMT_GEN_CONF wmt_conf_get_cfg(VOID) +{ + if (gDevWmt.rWmtGenConf.cfgExist == 0) + return NULL; + + return &gDevWmt.rWmtGenConf; +} + +INT32 wmt_conf_deinit(VOID) +{ + P_WMT_GEN_CONF pWmtGenConf = wmt_conf_get_cfg(); + + if (pWmtGenConf == NULL) + return -1; + + if (pWmtGenConf->coex_wmt_epa_elna != NULL) { + if (pWmtGenConf->coex_wmt_epa_elna->data != NULL) { + osal_free(pWmtGenConf->coex_wmt_epa_elna->data); + pWmtGenConf->coex_wmt_epa_elna->data = NULL; + } + osal_free(pWmtGenConf->coex_wmt_epa_elna); + pWmtGenConf->coex_wmt_epa_elna = NULL; + } + + if (pWmtGenConf->coex_wmt_antsel_invert_support != NULL) { + osal_free(pWmtGenConf->coex_wmt_antsel_invert_support); + pWmtGenConf->coex_wmt_antsel_invert_support = NULL; + } + + return 0; +} + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_core.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_core.c new file mode 100644 index 00000000000000..349fe3a5c65c61 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_core.c @@ -0,0 +1,3700 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CORE]" + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "connsys_debug_utility.h" +#include "wmt_lib.h" +#include "wmt_core.h" +#include "wmt_ctrl.h" +#include "wmt_ic.h" +#include "wmt_conf.h" + +#include "wmt_func.h" +#include "stp_core.h" +#include "psm_core.h" +#include "wmt_exp.h" +#include "wmt_detect.h" +#include "wmt_plat.h" +#include "wmt_dev.h" + +P_WMT_FUNC_OPS gpWmtFuncOps[WMTDRV_TYPE_MAX] = { +#if CFG_FUNC_BT_SUPPORT + [WMTDRV_TYPE_BT] = &wmt_func_bt_ops, +#else + [WMTDRV_TYPE_BT] = NULL, +#endif + +#if CFG_FUNC_FM_SUPPORT + [WMTDRV_TYPE_FM] = &wmt_func_fm_ops, +#else + [WMTDRV_TYPE_FM] = NULL, +#endif + +#if CFG_FUNC_GPS_SUPPORT + [WMTDRV_TYPE_GPS] = &wmt_func_gps_ops, +#else + [WMTDRV_TYPE_GPS] = NULL, +#endif + +#if CFG_FUNC_WIFI_SUPPORT + [WMTDRV_TYPE_WIFI] = &wmt_func_wifi_ops, +#else + [WMTDRV_TYPE_WIFI] = NULL, +#endif + +#if CFG_FUNC_ANT_SUPPORT + [WMTDRV_TYPE_ANT] = &wmt_func_ant_ops, +#else + [WMTDRV_TYPE_ANT] = NULL, +#endif + + +}; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* TODO:[FixMe][GeorgeKuo]: is it an MT6620 only or general general setting? + * move to wmt_ic_6620 temporarily. + */ +/* #define CFG_WMT_BT_PORT2 (1) *//* BT Port 2 Feature. */ +#define CFG_CHECK_WMT_RESULT (1) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +static WMT_CTX gMtkWmtCtx; +static UINT8 gLpbkBuf[WMT_LPBK_BUF_LEN] = { 0 }; +#ifdef CONFIG_MTK_COMBO_ANT +static UINT8 gAntBuf[1024] = { 0 }; +#endif +#if CFG_WMT_LTE_COEX_HANDLING +static UINT32 g_open_wmt_lte_flag; +#endif +static UINT8 gFlashBuf[1024] = { 0 }; +#if CFG_WMT_LTE_COEX_HANDLING +static UINT8 msg_local_buffer[WMT_IDC_MSG_BUFFER] = { 0 }; +#endif +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static INT32 opfunc_hif_conf(P_WMT_OP pWmtOp); +static INT32 opfunc_pwr_on(P_WMT_OP pWmtOp); +static INT32 opfunc_pwr_off(P_WMT_OP pWmtOp); +static INT32 opfunc_func_on(P_WMT_OP pWmtOp); +static INT32 opfunc_func_off(P_WMT_OP pWmtOp); +static INT32 opfunc_reg_rw(P_WMT_OP pWmtOp); +static INT32 opfunc_exit(P_WMT_OP pWmtOp); +static INT32 opfunc_pwr_sv(P_WMT_OP pWmtOp); +static INT32 opfunc_dsns(P_WMT_OP pWmtOp); +static INT32 opfunc_lpbk(P_WMT_OP pWmtOp); +static INT32 opfunc_cmd_test(P_WMT_OP pWmtOp); +static INT32 opfunc_hw_rst(P_WMT_OP pWmtOp); +static INT32 opfunc_sw_rst(P_WMT_OP pWmtOp); +static INT32 opfunc_stp_rst(P_WMT_OP pWmtOp); +static INT32 opfunc_efuse_rw(P_WMT_OP pWmtOp); +static INT32 opfunc_therm_ctrl(P_WMT_OP pWmtOp); +static INT32 opfunc_gpio_ctrl(P_WMT_OP pWmtOp); +static INT32 opfunc_sdio_ctrl(P_WMT_OP pWmtOp); +static INT32 opfunc_pin_state(P_WMT_OP pWmtOp); +static INT32 opfunc_bgw_ds(P_WMT_OP pWmtOp); +static INT32 opfunc_set_mcu_clk(P_WMT_OP pWmtOp); +static INT32 opfunc_adie_lpbk_test(P_WMT_OP pWmtOp); +static INT32 wmt_core_gen2_set_mcu_clk(UINT32 kind); +static INT32 wmt_core_gen3_set_mcu_clk(UINT32 kind); +static INT32 wmt_core_set_mcu_clk(UINT32 kind); +static VOID wmt_core_dump_func_state(PINT8 pSource); +static INT32 wmt_core_stp_init(VOID); +static INT32 wmt_core_trigger_assert(VOID); +static INT32 wmt_core_stp_deinit(VOID); +static INT32 wmt_core_hw_check(VOID); +#ifdef CONFIG_MTK_COMBO_ANT +static INT32 opfunc_ant_ram_down(P_WMT_OP pWmtOp); +static INT32 opfunc_ant_ram_stat_get(P_WMT_OP pWmtOp); +#endif +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 opfunc_idc_msg_handling(P_WMT_OP pWmtOp); +#endif +static INT32 opfunc_trigger_stp_assert(P_WMT_OP pWmtOp); +static INT32 opfunc_flash_patch_down(P_WMT_OP pWmtOp); +static INT32 opfunc_flash_patch_ver_get(P_WMT_OP pWmtOp); +static INT32 opfunc_utc_time_sync(P_WMT_OP pWmtOp); +static INT32 opfunc_fw_log_ctrl(P_WMT_OP pWmtOp); +static INT32 opfunc_wlan_probe(P_WMT_OP pWmtOp); +static INT32 opfunc_wlan_remove(P_WMT_OP pWmtOp); +static INT32 opfunc_try_pwr_off(P_WMT_OP pWmtOp); +static INT32 opfunc_gps_mcu_ctrl(P_WMT_OP pWmtOp); +static INT32 opfunc_blank_status_ctrl(P_WMT_OP pWmtOp); +static INT32 opfunc_met_ctrl(P_WMT_OP pWmtOp); +static INT32 opfunc_gps_suspend(P_WMT_OP pWmtOp); +static INT32 opfunc_resume_dump_info(P_WMT_OP pWmtOp); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +static const UINT8 WMT_SLEEP_CMD[] = { 0x01, 0x03, 0x01, 0x00, 0x01 }; +static const UINT8 WMT_SLEEP_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x01 }; + +static const UINT8 WMT_HOST_AWAKE_CMD[] = { 0x01, 0x03, 0x01, 0x00, 0x02 }; +static const UINT8 WMT_HOST_AWAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x02 }; + +static const UINT8 WMT_WAKEUP_CMD[] = { 0xFF }; +static const UINT8 WMT_WAKEUP_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; + +static UINT8 WMT_THERM_CMD[] = { 0x01, 0x11, 0x01, 0x00, + 0x00 /*thermal sensor operation */ +}; +static UINT8 WMT_THERM_CTRL_EVT[] = { 0x02, 0x11, 0x01, 0x00, 0x00 }; +static UINT8 WMT_THERM_READ_EVT[] = { 0x02, 0x11, 0x02, 0x00, 0x00, 0x00 }; + +static UINT8 WMT_EFUSE_CMD[] = { 0x01, 0x0D, 0x08, 0x00, + 0x01, /*[4]operation, 0:init, 1:write 2:read */ + 0x01, /*[5]Number of register setting */ + 0xAA, 0xAA, /*[6-7]Address */ + 0xBB, 0xBB, 0xBB, 0xBB /*[8-11] Value */ +}; + +static UINT8 WMT_EFUSE_EVT[] = { 0x02, 0x0D, 0x08, 0x00, + 0xAA, /*[4]operation, 0:init, 1:write 2:read */ + 0xBB, /*[5]Number of register setting */ + 0xCC, 0xCC, /*[6-7]Address */ + 0xDD, 0xDD, 0xDD, 0xDD /*[8-11] Value */ +}; + +static UINT8 WMT_DSNS_CMD[] = { 0x01, 0x0E, 0x02, 0x00, 0x01, + 0x00 /*desnse type */ +}; +static UINT8 WMT_DSNS_EVT[] = { 0x02, 0x0E, 0x01, 0x00, 0x00 }; + +/* TODO:[NewFeature][GeorgeKuo] Update register group in ONE CMD/EVT */ +static UINT8 WMT_SET_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x00 /*op: w(1) & r(2) */ + , 0x01 /*type: reg */ + , 0x00 /*res */ + , 0x01 /*1 register */ + , 0x00, 0x00, 0x00, 0x00 /* addr */ + , 0x00, 0x00, 0x00, 0x00 /* value */ + , 0xFF, 0xFF, 0xFF, 0xFF /*mask */ +}; + +static UINT8 WMT_SET_REG_WR_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 register */ + /* , 0x00, 0x00, 0x00, 0x00 *//* addr */ + /* , 0x00, 0x00, 0x00, 0x00 *//* value */ +}; + +static UINT8 WMT_SET_REG_RD_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 register */ + , 0x00, 0x00, 0x00, 0x00 /* addr */ + , 0x00, 0x00, 0x00, 0x00 /* value */ +}; + +#ifdef CONFIG_MTK_COMBO_ANT +static UINT8 WMT_ANT_RAM_STA_GET_CMD[] = { 0x01, 0x06, 0x02, 0x00, 0x05, 0x02 +}; +static UINT8 WMT_ANT_RAM_STA_GET_EVT[] = { 0x02, 0x06, 0x03, 0x00 /*length */ + , 0x05, 0x02, 0x00 /*S: result */ +}; +static UINT8 WMT_ANT_RAM_DWN_CMD[] = { 0x01, 0x15, 0x00, 0x00, 0x01 +}; +static UINT8 WMT_ANT_RAM_DWN_EVT[] = { 0x02, 0x15, 0x01, 0x00 /*length */ + , 0x00 +}; +#endif + +static UINT8 WMT_FLASH_PATCH_VER_GET_CMD[] = { 0x01, 0x01, 0x05, 0x00 /*length*/ + , 0x06, 0x00, 0x00, 0x00, 0x00 /*flash patch type*/ +}; + +static UINT8 WMT_FLASH_PATCH_VER_GET_EVT[] = { 0x02, 0x01, 0x09, 0x00 /*length */ + , 0x06, 0x00, 0x00, 0x00, 0x00 /*flash patch type*/ + , 0x00, 0x00, 0x00, 0x00 /*flash patch version*/ +}; + +static UINT8 WMT_FLASH_PATCH_DWN_CMD[] = { 0x01, 0x01, 0x0d, 0x00, 0x05 +}; + +static UINT8 WMT_FLASH_PATCH_DWN_EVT[] = { 0x02, 0x01, 0x01, 0x00 /*length */ + , 0x00 +}; + +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +static UINT8 WMT_UTC_SYNC_CMD[] = { 0x01, 0xF0, 0x09, 0x00, 0x02 + , 0x00, 0x00, 0x00, 0x00 /*UTC time second unit*/ + , 0x00, 0x00, 0x00, 0x00 /*UTC time microsecond unit*/ +}; +static UINT8 WMT_UTC_SYNC_EVT[] = { 0x02, 0xF0, 0x02, 0x00, 0x02, 0x00 +}; + +static UINT8 WMT_BLANK_STATUS_CMD[] = { 0x01, 0xF0, 0x02, 0x00, 0x03, 0x00 }; +static UINT8 WMT_BLANK_STATUS_EVT[] = { 0x02, 0xF0, 0x02, 0x00, 0x03, 0x00 }; +#endif + +static UINT8 WMT_FW_LOG_CTRL_CMD[] = { 0x01, 0xF0, 0x04, 0x00, 0x01 + , 0x00 /* subsys type */ + , 0x00 /* on/off */ + , 0x00 /* level (subsys-specific) */ +}; +static UINT8 WMT_FW_LOG_CTRL_EVT[] = { 0x02, 0xF0, 0x02, 0x00, 0x01, 0x00 }; + +/* GeorgeKuo: Use designated initializers described in + * http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Designated-Inits.html + */ + +static const WMT_OPID_FUNC wmt_core_opfunc[] = { + [WMT_OPID_HIF_CONF] = opfunc_hif_conf, + [WMT_OPID_PWR_ON] = opfunc_pwr_on, + [WMT_OPID_PWR_OFF] = opfunc_pwr_off, + [WMT_OPID_FUNC_ON] = opfunc_func_on, + [WMT_OPID_FUNC_OFF] = opfunc_func_off, + [WMT_OPID_REG_RW] = opfunc_reg_rw, /* TODO:[ChangeFeature][George] is this OP obsoleted? */ + [WMT_OPID_EXIT] = opfunc_exit, + [WMT_OPID_PWR_SV] = opfunc_pwr_sv, + [WMT_OPID_DSNS] = opfunc_dsns, + [WMT_OPID_LPBK] = opfunc_lpbk, + [WMT_OPID_CMD_TEST] = opfunc_cmd_test, + [WMT_OPID_HW_RST] = opfunc_hw_rst, + [WMT_OPID_SW_RST] = opfunc_sw_rst, + [WMT_OPID_STP_RST] = opfunc_stp_rst, + [WMT_OPID_THERM_CTRL] = opfunc_therm_ctrl, + [WMT_OPID_EFUSE_RW] = opfunc_efuse_rw, + [WMT_OPID_GPIO_CTRL] = opfunc_gpio_ctrl, + [WMT_OPID_SDIO_CTRL] = opfunc_sdio_ctrl, + [WMT_OPID_GPIO_STATE] = opfunc_pin_state, + [WMT_OPID_BGW_DS] = opfunc_bgw_ds, + [WMT_OPID_SET_MCU_CLK] = opfunc_set_mcu_clk, + [WMT_OPID_ADIE_LPBK_TEST] = opfunc_adie_lpbk_test, +#ifdef CONFIG_MTK_COMBO_ANT + [WMT_OPID_ANT_RAM_DOWN] = opfunc_ant_ram_down, + [WMT_OPID_ANT_RAM_STA_GET] = opfunc_ant_ram_stat_get, +#endif +#if CFG_WMT_LTE_COEX_HANDLING + [WMT_OPID_IDC_MSG_HANDLING] = opfunc_idc_msg_handling, +#endif + [WMT_OPID_TRIGGER_STP_ASSERT] = opfunc_trigger_stp_assert, + [WMT_OPID_FLASH_PATCH_DOWN] = opfunc_flash_patch_down, + [WMT_OPID_FLASH_PATCH_VER_GET] = opfunc_flash_patch_ver_get, + [WMT_OPID_UTC_TIME_SYNC] = opfunc_utc_time_sync, + [WMT_OPID_FW_LOG_CTRL] = opfunc_fw_log_ctrl, + [WMT_OPID_WLAN_PROBE] = opfunc_wlan_probe, + [WMT_OPID_WLAN_REMOVE] = opfunc_wlan_remove, + [WMT_OPID_GPS_MCU_CTRL] = opfunc_gps_mcu_ctrl, + [WMT_OPID_TRY_PWR_OFF] = opfunc_try_pwr_off, + [WMT_OPID_BLANK_STATUS_CTRL] = opfunc_blank_status_ctrl, + [WMT_OPID_MET_CTRL] = opfunc_met_ctrl, + [WMT_OPID_GPS_SUSPEND] = opfunc_gps_suspend, + [WMT_OPID_RESUME_DUMP_INFO] = opfunc_resume_dump_info, +}; + +atomic_t g_wifi_on_off_ready; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 wmt_core_init(VOID) +{ + INT32 i = 0; + + osal_memset(&gMtkWmtCtx, 0, osal_sizeof(gMtkWmtCtx)); + /* gMtkWmtCtx.p_ops is cleared to NULL */ + + /* default FUNC_OFF state */ + for (i = 0; i < WMTDRV_TYPE_MAX; ++i) { + /* WinMo is default to DRV_STS_UNREG; */ + gMtkWmtCtx.eDrvStatus[i] = DRV_STS_POWER_OFF; + } + + atomic_set(&g_wifi_on_off_ready, 0); + + return 0; +} + +INT32 wmt_core_deinit(VOID) +{ + /* return to init state */ + osal_memset(&gMtkWmtCtx, 0, osal_sizeof(gMtkWmtCtx)); + /* gMtkWmtCtx.p_ops is cleared to NULL */ + return 0; +} + +/* TODO: [ChangeFeature][George] Is wmt_ctrl a good interface? maybe not...... */ +/* parameters shall be copied in/from ctrl buffer, which is also a size-wasting buffer. */ +INT32 +wmt_core_tx(const PUINT8 pData, const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag) +{ + INT32 iRet = 0; + INT32 retry_times = 0; + INT32 max_retry_times = 0; + INT32 retry_delay_ms = 0; + ENUM_WMT_CHIP_TYPE chip_type; + + chip_type = wmt_detect_get_chip_type(); + iRet = wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag); + if (*writtenSize == 0 && (chip_type == WMT_CHIP_TYPE_SOC)) { + retry_times = 0; + max_retry_times = 3; + retry_delay_ms = 360; + WMT_WARN_FUNC("WMT-CORE: wmt_ctrl_tx_ex failed and written ret:%d, maybe no winspace in STP layer\n", + *writtenSize); + while ((*writtenSize == 0) && (retry_times < max_retry_times)) { + WMT_ERR_FUNC("WMT-CORE: retrying, wait for %d ms\n", retry_delay_ms); + osal_sleep_ms(retry_delay_ms); + + iRet = wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag); + retry_times++; + } + } + return iRet; +} + +INT32 wmt_core_rx(PUINT8 pBuf, UINT32 bufLen, PUINT32 readSize) +{ + INT32 iRet; + WMT_CTRL_DATA ctrlData; + + ctrlData.ctrlId = WMT_CTRL_RX; + ctrlData.au4CtrlData[0] = (SIZE_T) pBuf; + ctrlData.au4CtrlData[1] = bufLen; + ctrlData.au4CtrlData[2] = (SIZE_T) readSize; + + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + /* ERROR */ + WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: WMT_CTRL_RX, iRet:%d\n", iRet); + osal_assert(0); + } + return iRet; +} + +INT32 wmt_core_rx_flush(UINT32 type) +{ + INT32 iRet; + WMT_CTRL_DATA ctrlData; + + ctrlData.ctrlId = WMT_CTRL_RX_FLUSH; + ctrlData.au4CtrlData[0] = (UINT32) type; + + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + /* ERROR */ + WMT_ERR_FUNC("WMT-CORE: wmt_core_ctrl failed: WMT_CTRL_RX_FLUSH, iRet:%d\n", iRet); + osal_assert(0); + } + return iRet; +} + +INT32 wmt_core_func_ctrl_cmd(ENUM_WMTDRV_TYPE_T type, MTK_WCN_BOOL fgEn) +{ + INT32 iRet = 0; + UINT32 u4WmtCmdPduLen; + UINT32 u4WmtEventPduLen; + UINT32 u4ReadSize; + UINT32 u4WrittenSize; + WMT_PKT rWmtPktCmd; + WMT_PKT rWmtPktEvent; + MTK_WCN_BOOL fgFail; + + /* TODO:[ChangeFeature][George] remove WMT_PKT. replace it with hardcoded arrays. */ + /* Using this struct relies on compiler's implementation and pack() settings */ + osal_memset(&rWmtPktCmd, 0, osal_sizeof(rWmtPktCmd)); + osal_memset(&rWmtPktEvent, 0, osal_sizeof(rWmtPktEvent)); + + rWmtPktCmd.eType = (UINT8) WMT_PKT_TYPE_CMD; + rWmtPktCmd.eOpCode = (UINT8) OPCODE_FUNC_CTRL; + + /* Flag field: driver type */ + rWmtPktCmd.aucParam[0] = (UINT8) type; + /* Parameter field: ON/OFF */ + rWmtPktCmd.aucParam[1] = (fgEn == WMT_FUNC_CTRL_ON) ? 1 : 0; + rWmtPktCmd.u2SduLen = WMT_FLAG_LEN + WMT_FUNC_CTRL_PARAM_LEN; /* (2) */ + + /* WMT Header + WMT SDU */ + u4WmtCmdPduLen = WMT_HDR_LEN + rWmtPktCmd.u2SduLen; /* (6) */ + u4WmtEventPduLen = WMT_HDR_LEN + WMT_STS_LEN; /* (5) */ + + do { + fgFail = MTK_WCN_BOOL_TRUE; +/* iRet = (*kal_stp_tx)((PUINT8)&rWmtPktCmd, u4WmtCmdPduLen, &u4WrittenSize); */ + iRet = + wmt_core_tx((PUINT8) &rWmtPktCmd, u4WmtCmdPduLen, &u4WrittenSize, + MTK_WCN_BOOL_FALSE); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd kal_stp_tx failed\n"); + break; + } + + iRet = wmt_core_rx((PUINT8) &rWmtPktEvent, u4WmtEventPduLen, &u4ReadSize); + if (iRet) { + WMT_ERR_FUNC + ("WMT firwmare no rx event, trigger f/w assert. sub-driver type:%d, state(%d)\n", + type, fgEn); + wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 32); + break; + } + + /* Error Checking */ + if (rWmtPktEvent.eType != WMT_PKT_TYPE_EVENT) { + WMT_ERR_FUNC + ("WMT-CORE: wmt_func_ctrl_cmd WMT_PKT_TYPE_EVENT != rWmtPktEvent.eType %d\n", + rWmtPktEvent.eType); + break; + } + + if (rWmtPktCmd.eOpCode != rWmtPktEvent.eOpCode) { + WMT_ERR_FUNC + ("WMT-CORE: wmt_func_ctrl_cmd rWmtPktCmd.eOpCode(0x%x) != rWmtPktEvent.eType(0x%x)\n", + rWmtPktCmd.eOpCode, rWmtPktEvent.eOpCode); + break; + } + + if (u4WmtEventPduLen != (rWmtPktEvent.u2SduLen + WMT_HDR_LEN)) { + WMT_ERR_FUNC + ("WMT-CORE: wmt_func_ctrl_cmd u4WmtEventPduLen(0x%x) != rWmtPktEvent.u2SduLen(0x%x)+4\n", + u4WmtEventPduLen, rWmtPktEvent.u2SduLen); + break; + } + /* Status field of event check */ + if (rWmtPktEvent.aucParam[0] != 0) { + WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd, 0 != status(%d)\n", + rWmtPktEvent.aucParam[0]); + break; + } + + fgFail = MTK_WCN_BOOL_FALSE; + } while (0); + + if (fgFail == MTK_WCN_BOOL_FALSE) { + /* WMT_INFO_FUNC("WMT-CORE: wmt_func_ctrl_cmd OK!\n"); */ + return 0; + } + WMT_ERR_FUNC("WMT-CORE: wmt_func_ctrl_cmd 0x%x FAIL\n", rWmtPktCmd.aucParam[0]); + return -2; +} + +INT32 wmt_core_opid_handler(P_WMT_OP pWmtOp) +{ + UINT32 opId; + INT32 ret; + + opId = pWmtOp->opId; + + if (wmt_core_opfunc[opId]) { + ret = (*(wmt_core_opfunc[opId])) (pWmtOp); /*wmtCoreOpidHandlerPack[].opHandler */ + return ret; + } + WMT_ERR_FUNC("WMT-CORE: null handler (%d)\n", pWmtOp->opId); + return -2; +} + +INT32 wmt_core_opid(P_WMT_OP pWmtOp) +{ + + /*sanity check */ + if (pWmtOp == NULL) { + WMT_ERR_FUNC("null pWmtOP\n"); + /*print some message with error info */ + return -1; + } + + if (pWmtOp->opId >= WMT_OPID_MAX) { + WMT_ERR_FUNC("WMT-CORE: invalid OPID(%d)\n", pWmtOp->opId); + return -2; + } + /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */ + return wmt_core_opid_handler(pWmtOp); +} + +INT32 wmt_core_ctrl(ENUM_WMT_CTRL_T ctrId, PULONG pPa1, PULONG pPa2) +{ + INT32 iRet = -1; + WMT_CTRL_DATA ctrlData; + SIZE_T val1 = (pPa1) ? *pPa1 : 0; + SIZE_T val2 = (pPa2) ? *pPa2 : 0; + + ctrlData.ctrlId = (SIZE_T) ctrId; + ctrlData.au4CtrlData[0] = val1; + ctrlData.au4CtrlData[1] = val2; + + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + /* ERROR */ + WMT_ERR_FUNC + ("WMT-CORE: wmt_core_ctrl failed: id(%d), type(%zu), value(%zu) iRet:(%d)\n", + ctrId, val1, val2, iRet); + osal_assert(0); + } else { + if (pPa1) + *pPa1 = ctrlData.au4CtrlData[0]; + if (pPa2) + *pPa2 = ctrlData.au4CtrlData[1]; + } + return iRet; +} + + +VOID wmt_core_dump_data(PUINT8 pData, PUINT8 pTitle, UINT32 len) +{ + PUINT8 ptr = pData; + INT32 k = 0; + + WMT_INFO_FUNC("%s len=%d\n", pTitle, len); + for (k = 0; k < len; k++) { + if (k % 16 == 0) + WMT_INFO_FUNC("\n"); + WMT_INFO_FUNC("0x%02x ", *ptr); + ptr++; + } + WMT_INFO_FUNC("--end\n"); +} + +/*! + * \brief An WMT-CORE function to support read, write, and read after write to + * an internal register. + * + * Detailed description. + * + * \param isWrite 1 for write, 0 for read + * \param offset of register to be written or read + * \param pVal a pointer to the 32-bit value to be writtern or read + * \param mask a 32-bit mask to be applied for the read or write operation + * + * \retval 0 operation success + * \retval -1 invalid parameters + * \retval -2 tx cmd fail + * \retval -3 rx event fail + * \retval -4 read check error + */ +INT32 wmt_core_reg_rw_raw(UINT32 isWrite, UINT32 offset, PUINT32 pVal, UINT32 mask) +{ + INT32 iRet; + UINT32 u4Res; + UINT32 evtLen; + UINT8 evtBuf[16] = { 0 }; + + WMT_SET_REG_CMD[4] = (isWrite) ? 0x1 : 0x2; /* w:1, r:2 */ + osal_memcpy(&WMT_SET_REG_CMD[8], &offset, 4); /* offset */ + osal_memcpy(&WMT_SET_REG_CMD[12], pVal, 4); /* [2] is var addr */ + osal_memcpy(&WMT_SET_REG_CMD[16], &mask, 4); /* mask */ + + /* send command */ + iRet = wmt_core_tx(WMT_SET_REG_CMD, sizeof(WMT_SET_REG_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + if ((iRet) || (u4Res != sizeof(WMT_SET_REG_CMD))) { + WMT_ERR_FUNC("Tx REG_CMD fail!(%d) len (%d, %zu)\n", iRet, u4Res, + sizeof(WMT_SET_REG_CMD)); + return -2; + } + + /* receive event */ + evtLen = (isWrite) ? sizeof(WMT_SET_REG_WR_EVT) : sizeof(WMT_SET_REG_RD_EVT); + iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); + if ((iRet) || (u4Res != evtLen)) { + WMT_ERR_FUNC("Rx REG_EVT fail!(%d) len(%d, %d)\n", iRet, u4Res, evtLen); + if (isWrite) + WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n", + evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + WMT_SET_REG_WR_EVT[0], WMT_SET_REG_WR_EVT[1], + WMT_SET_REG_WR_EVT[2], WMT_SET_REG_WR_EVT[3], + WMT_SET_REG_WR_EVT[4]); + else + WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n", + evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + WMT_SET_REG_RD_EVT[0], WMT_SET_REG_RD_EVT[1], + WMT_SET_REG_RD_EVT[2], WMT_SET_REG_RD_EVT[3], + WMT_SET_REG_RD_EVT[4]); + mtk_wcn_stp_dbg_dump_package(); + wmt_core_trigger_assert(); + return -3; + } + + if (!isWrite) { + UINT32 rxEvtAddr; + UINT32 txCmdAddr; + + osal_memcpy(&txCmdAddr, &WMT_SET_REG_CMD[8], 4); + osal_memcpy(&rxEvtAddr, &evtBuf[8], 4); + + /* check read result */ + if (txCmdAddr != rxEvtAddr) { + WMT_ERR_FUNC("Check read addr fail (0x%08x, 0x%08x)\n", rxEvtAddr, + txCmdAddr); + return -4; + } + WMT_DBG_FUNC("Check read addr(0x%08x) ok\n", rxEvtAddr); + osal_memcpy(pVal, &evtBuf[12], 4); + } + + /* no error here just return 0 */ + return 0; +} + +INT32 wmt_core_init_script_retry(struct init_script *script, INT32 count, INT32 retry, INT32 dump_err_log) +{ + UINT8 evtBuf[256]; + UINT32 u4Res; + INT32 i = 0; + INT32 iRet; + INT32 err = 0; + + do { + err = 0; + for (i = 0; i < count; i++) { + WMT_DBG_FUNC("WMT-CORE: init_script operation %s start\n", script[i].str); + /* CMD */ + /* iRet = (*kal_stp_tx)(script[i].cmd, script[i].cmdSz, &u4Res); */ + iRet = wmt_core_tx(script[i].cmd, script[i].cmdSz, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != script[i].cmdSz)) { + WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", + script[i].str, iRet, u4Res, script[i].cmdSz); + + err = -1; + break; + } + /* EVENT BUF */ + + osal_memset(evtBuf, 0, sizeof(evtBuf)); + iRet = wmt_core_rx(evtBuf, script[i].evtSz, &u4Res); + if (iRet || (u4Res != script[i].evtSz)) { + WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", + script[i].str, iRet, u4Res, script[i].evtSz); + if (dump_err_log == 1) + mtk_wcn_stp_dbg_dump_package(); + + err = -1; + break; + } + /* RESULT */ + if (evtBuf[1] != 0x14) { /*workaround RF calibration data EVT, do not care this EVT*/ + if (osal_memcmp(evtBuf, script[i].evt, script[i].evtSz) != 0) { + WMT_ERR_FUNC("WMT-CORE:compare %s result error\n", script[i].str); + WMT_ERR_FUNC + ("WMT-CORE:rx(%d):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4]); + WMT_ERR_FUNC + ("WMT-CORE:exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", + script[i].evtSz, script[i].evt[0], script[i].evt[1], script[i].evt[2], + script[i].evt[3], script[i].evt[4]); + if (dump_err_log == 1) + mtk_wcn_stp_dbg_dump_package(); + + err = -1; + break; + } + } + WMT_DBG_FUNC("init_script operation %s ok\n", script[i].str); + } + retry--; + } while (retry >= 0 && err < 0); + + return (i == count) ? 0 : -1; +} + + +INT32 wmt_core_init_script(struct init_script *script, INT32 count) +{ + return wmt_core_init_script_retry(script, count, 0, 1); +} + +static INT32 wmt_core_trigger_assert(VOID) +{ + INT32 ret = 0; + UINT32 u4Res; + UINT32 tstCmdSz = 0; + UINT32 tstEvtSz = 0; + UINT8 tstCmd[64]; + UINT8 tstEvt[64]; + UINT8 WMT_ASSERT_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x08 }; + UINT8 WMT_ASSERT_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; + + WMT_INFO_FUNC("Send Assert command !\n"); + tstCmdSz = osal_sizeof(WMT_ASSERT_CMD); + tstEvtSz = osal_sizeof(WMT_ASSERT_EVT); + osal_memcpy(tstCmd, WMT_ASSERT_CMD, tstCmdSz); + osal_memcpy(tstEvt, WMT_ASSERT_EVT, tstEvtSz); + + ret = wmt_core_tx((PUINT8) tstCmd, tstCmdSz, &u4Res, MTK_WCN_BOOL_FALSE); + if (ret || (u4Res != tstCmdSz)) { + WMT_ERR_FUNC("WMT-CORE: wmt_cmd_test iRet(%d) cmd len err(%d, %d)\n", ret, u4Res, + tstCmdSz); + ret = -1; + } + return ret; +} + +static INT32 wmt_core_stp_init(VOID) +{ + INT32 iRet = -1; + ULONG ctrlPa1; + ULONG ctrlPa2; + UINT8 co_clock_type; + P_WMT_CTX pctx = &gMtkWmtCtx; + P_WMT_GEN_CONF pWmtGenConf = NULL; + + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) + wmt_conf_read_file(); + gDevWmt.rWmtGenConf.co_clock_flag = wmt_lib_co_clock_flag_get(); + + pWmtGenConf = wmt_conf_get_cfg(); + if (pWmtGenConf == NULL) + WMT_ERR_FUNC("WMT-CORE: wmt_conf_get_cfg return NULL!!\n"); + if (!(pctx->wmtInfoBit & WMT_OP_HIF_BIT)) { + WMT_ERR_FUNC("WMT-CORE: no hif info!\n"); + osal_assert(0); + return -1; + } + + + /* 4 <0> turn on SDIO2 for common SDIO */ + if (pctx->wmtHifConf.hifType == WMT_HIF_SDIO) { + ctrlPa1 = WMT_SDIO_SLOT_SDIO2; + ctrlPa2 = 1; /* turn on SDIO2 slot */ + iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: turn on SLOT_SDIO2 fail (%d)\n", iRet); + osal_assert(0); + + return -2; + } + pctx->eDrvStatus[WMTDRV_TYPE_SDIO2] = DRV_STS_FUNC_ON; + + ctrlPa1 = WMT_SDIO_FUNC_STP; + ctrlPa2 = 1; /* turn on STP driver */ + iRet = wmt_core_ctrl(WMT_CTRL_SDIO_FUNC, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: turn on SDIO_FUNC_STP func fail (%d)\n", iRet); + + /* check all sub-func and do power off */ + return -3; + } + } + /* 4 <1> open stp */ + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_STP_OPEN, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt open stp\n"); + return -4; + } + + if (pctx->wmtHifConf.hifType == WMT_HIF_UART) { + ctrlPa1 = WMT_DEFAULT_BAUD_RATE; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HOST_BAUDRATE_SET, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: change host baudrate(%d) fails\n", + pctx->wmtHifConf.au4HifConf[0]); + return -5; + } + } + /* WMT_DBG_FUNC("WMT-CORE: change host baudrate(%d) ok\n", gMtkWmtCtx.wmtHifConf.au4HifConf[0]); */ + + /* 4 <1.5> disable and un-ready stp */ + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 0; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WMT_STP_CONF_RDY; + ctrlPa2 = 0; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + + /* 4 <2> set mode and enable */ + if (pctx->wmtHifConf.hifType == WMT_HIF_UART) { + ctrlPa1 = WMT_STP_CONF_MODE; + ctrlPa2 = MTKSTP_UART_MAND_MODE; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + } else if (pctx->wmtHifConf.hifType == WMT_HIF_SDIO) { + + ctrlPa1 = WMT_STP_CONF_MODE; + ctrlPa2 = MTKSTP_SDIO_MODE; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + if (iRet) + WMT_ERR_FUNC(" confif SDIO_MODE fail!!!!\n"); + } + if (pctx->wmtHifConf.hifType == WMT_HIF_BTIF) { + ctrlPa1 = WMT_STP_CONF_MODE; + ctrlPa2 = MTKSTP_BTIF_MAND_MODE; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + } + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 1; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: stp_init <1><2> fail:%d\n", iRet); + return -7; + } + /* TODO: [ChangeFeature][GeorgeKuo] can we apply raise UART baud rate firstly for ALL supported chips??? */ + +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT + WMT_DBG_FUNC("disable deep sleep featrue before the first command to firmware\n"); + wmt_lib_deep_sleep_flag_set(MTK_WCN_BOOL_FALSE); +#endif + + iRet = wmt_core_hw_check(); + if (iRet) { + WMT_ERR_FUNC("hw_check fail:%d\n", iRet); + return -8; + } + /* mtkWmtCtx.p_ic_ops is identified and checked ok */ + if ((pctx->p_ic_ops->co_clock_ctrl != NULL) && (pWmtGenConf != NULL)) { + co_clock_type = (pWmtGenConf->co_clock_flag & 0x0f); + (*(pctx->p_ic_ops->co_clock_ctrl)) (co_clock_type == 0 ? WMT_CO_CLOCK_DIS : WMT_CO_CLOCK_EN); + } else { + WMT_WARN_FUNC("pctx->p_ic_ops->co_clock_ctrl(%p), pWmtGenConf(%p)\n", pctx->p_ic_ops->co_clock_ctrl, + pWmtGenConf); + } + osal_assert(pctx->p_ic_ops->sw_init != NULL); + if (pctx->p_ic_ops->sw_init != NULL) { + iRet = (*(pctx->p_ic_ops->sw_init)) (&pctx->wmtHifConf); + } else { + WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init is NULL\n"); + return -9; + } + if (iRet) { + WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init fail:%d\n", iRet); + return -10; + } + + /* send UTC time sync command after connsys power on or chip reset */ + opfunc_utc_time_sync(NULL); + + /* 4 <10> set stp ready */ + ctrlPa1 = WMT_STP_CONF_RDY; + ctrlPa2 = 1; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + return iRet; +} + +static INT32 wmt_core_stp_deinit(VOID) +{ + INT32 iRet; + ULONG ctrlPa1; + ULONG ctrlPa2; + + WMT_DBG_FUNC(" start\n"); + + if (gMtkWmtCtx.p_ic_ops == NULL) { + WMT_WARN_FUNC("gMtkWmtCtx.p_ic_ops is NULL\n"); + goto deinit_ic_ops_done; + } + if (gMtkWmtCtx.p_ic_ops->sw_deinit != NULL) { + iRet = (*(gMtkWmtCtx.p_ic_ops->sw_deinit)) (&gMtkWmtCtx.wmtHifConf); + /* unbind WMT-IC */ + gMtkWmtCtx.p_ic_ops = NULL; + } else { + WMT_ERR_FUNC("gMtkWmtCtx.p_ic_ops->sw_init is NULL\n"); + } + +deinit_ic_ops_done: + + /* 4 <1> un-ready, disable, and close stp. */ + ctrlPa1 = WMT_STP_CONF_RDY; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 0; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2); + + /* 4 <1.1> turn off SDIO2 for common SDIO */ + if (gMtkWmtCtx.wmtHifConf.hifType == WMT_HIF_SDIO) { + ctrlPa1 = WMT_SDIO_FUNC_STP; + ctrlPa2 = 0; /* turn off STP driver */ + iRet = wmt_core_ctrl(WMT_CTRL_SDIO_FUNC, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_WARN_FUNC("turn off SDIO_FUNC_STP fail (%d)\n", iRet); + /* Anyway, continue turning SDIO HW off */ + } else { + WMT_DBG_FUNC("turn off SDIO_FUNC_STP ok\n"); + } + + ctrlPa1 = WMT_SDIO_SLOT_SDIO2; + ctrlPa2 = 0; /* turn off SDIO2 slot */ + iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_WARN_FUNC("turn off SDIO2 HW fail (%d)\n", iRet); + /* Anyway, continue turning STP SDIO to POWER OFF state */ + } else + WMT_DBG_FUNC("turn off SDIO2 HW ok\n"); + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO2] = DRV_STS_POWER_OFF; + } + + if (iRet) + WMT_WARN_FUNC("end with fail:%d\n", iRet); + + return iRet; +} + +static VOID wmt_core_dump_func_state(PINT8 pSource) +{ + WMT_INFO_FUNC + ("[%s]status(b:%d f:%d g:%d w:%d lpbk:%d coredump:%d wmt:%d ant:%d sd1:%d sd2:%d stp:%d)\n", + (pSource == NULL ? (PINT8) "CORE" : pSource), gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT], + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM], gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS], + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI], gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK], + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP], gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT], + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_ANT], gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO1], + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO2], gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_STP] + ); + return; + +} + +ENUM_DRV_STS wmt_core_get_drv_status(ENUM_WMTDRV_TYPE_T type) +{ + return gMtkWmtCtx.eDrvStatus[type]; +} + +MTK_WCN_BOOL wmt_core_patch_check(UINT32 u4PatchVer, UINT32 u4HwVer) +{ + if (MAJORNUM(u4HwVer) != MAJORNUM(u4PatchVer)) { + /*major no. does not match */ + WMT_ERR_FUNC("WMT-CORE: chip version(0x%x) does not match patch version(0x%x)\n", + u4HwVer, u4PatchVer); + return MTK_WCN_BOOL_FALSE; + } + return MTK_WCN_BOOL_TRUE; +} + +static INT32 wmt_core_hw_check(VOID) +{ + UINT32 chipid; + P_WMT_IC_OPS p_ops; + INT32 iret; + + /* 1. get chip id */ + chipid = 0; + WMT_LOUD_FUNC("before read hwcode (chip id)\n"); + iret = wmt_core_reg_rw_raw(0, GEN_HCR, &chipid, GEN_HCR_MASK); /* read 0x80000008 */ + if (iret) { + WMT_ERR_FUNC("get hwcode (chip id) fail (%d)\n", iret); + return -2; + } + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) { + if (wmt_lib_get_icinfo(WMTCHIN_IPVER)) + chipid = wmt_plat_get_soc_chipid(); + } + WMT_INFO_FUNC("get hwcode (chip id) (0x%x)\n", chipid); + + /* TODO:[ChangeFeature][George]: use a better way to select a correct ops table based on chip id */ + switch (chipid) { +#if CFG_CORE_MT6620_SUPPORT + case 0x6620: + p_ops = &wmt_ic_ops_mt6620; + break; +#endif +#if CFG_CORE_MT6628_SUPPORT + case 0x6628: + p_ops = &wmt_ic_ops_mt6628; + break; +#endif + +#if CFG_CORE_MT6630_SUPPORT + case 0x6630: + p_ops = &wmt_ic_ops_mt6630; + break; +#endif + +#if CFG_CORE_MT6632_SUPPORT + case 0x6632: + p_ops = &wmt_ic_ops_mt6632; + break; +#endif +#if CFG_CORE_SOC_SUPPORT + case 0x0690: + case 0x6572: + case 0x6582: + case 0x6592: + case 0x8127: + case 0x6571: + case 0x6752: + case 0x0279: + case 0x0326: + case 0x0321: + case 0x0335: + case 0x0337: + case 0x8163: + case 0x6580: + case 0x0551: + case 0x8167: + case 0x0507: + case 0x0688: + case 0x0699: + case 0x0633: + case 0x0713: + case 0x0788: + case 0x6765: + case 0x3967: + case 0x6761: + case 0x6779: + case 0x6768: + case 0x6785: + case 0x8168: + p_ops = &wmt_ic_ops_soc; + break; +#endif + + default: + p_ops = (P_WMT_IC_OPS) NULL; +#if CFG_CORE_SOC_SUPPORT + if (chipid - 0x600 == 0x7f90) { + p_ops = &wmt_ic_ops_soc; + chipid -= 0xf6d; + } +#endif + break; + } + + if (p_ops == NULL) { + WMT_ERR_FUNC("unsupported chip id (hw_code): 0x%x\n", chipid); + return -3; + } else if (wmt_core_ic_ops_check(p_ops) == MTK_WCN_BOOL_FALSE) { + WMT_ERR_FUNC + ("chip id(0x%x) with null operation fp: init(0x%p), deinit(0x%p), pin_ctrl(0x%p), ver_chk(0x%p)\n", + chipid, p_ops->sw_init, p_ops->sw_deinit, p_ops->ic_pin_ctrl, + p_ops->ic_ver_check); + return -4; + } + WMT_DBG_FUNC("chip id(0x%x) fp: init(0x%p), deinit(0x%p), pin_ctrl(0x%p), ver_chk(0x%p)\n", + chipid, p_ops->sw_init, p_ops->sw_deinit, p_ops->ic_pin_ctrl, + p_ops->ic_ver_check); + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + wmt_ic_ops_soc.icId = chipid; + iret = p_ops->ic_ver_check(); + if (iret) { + WMT_ERR_FUNC("chip id(0x%x) ver_check error:%d\n", chipid, iret); + return -5; + } + + WMT_DBG_FUNC("chip id(0x%x) ver_check ok\n", chipid); + gMtkWmtCtx.p_ic_ops = p_ops; + return 0; +} + +static INT32 opfunc_hif_conf(P_WMT_OP pWmtOp) +{ + if (!(pWmtOp->u4InfoBit & WMT_OP_HIF_BIT)) { + WMT_ERR_FUNC("WMT-CORE: no HIF_BIT in WMT_OP!\n"); + return -1; + } + + if (gMtkWmtCtx.wmtInfoBit & WMT_OP_HIF_BIT) { + WMT_ERR_FUNC("WMT-CORE: WMT HIF already exist. Just return\n"); + return 0; + } else { + gMtkWmtCtx.wmtInfoBit |= WMT_OP_HIF_BIT; + WMT_ERR_FUNC("WMT-CORE: WMT HIF info added\n"); + } + + osal_memcpy(&gMtkWmtCtx.wmtHifConf, + &pWmtOp->au4OpData[0], osal_sizeof(gMtkWmtCtx.wmtHifConf)); + return 0; + +} + +static INT32 opfunc_pwr_on(P_WMT_OP pWmtOp) +{ + + INT32 iRet; + ULONG ctrlPa1; + ULONG ctrlPa2; + INT32 retry = WMT_PWRON_RTY_DFT; + + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] != DRV_STS_POWER_OFF) { + WMT_ERR_FUNC("WMT-CORE: already powered on, WMT DRV_STS_[0x%x]\n", + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]); + osal_assert(0); + return -1; + } + +pwr_on_rty: + /* power on control */ + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_ON, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: WMT_CTRL_HW_PWR_ON fail iRet(%d)\n", iRet); + if (retry-- == 0) { + WMT_INFO_FUNC("WMT-CORE: retry (%d)\n", retry); + goto pwr_on_rty; + } + return -2; + } + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; + + /* init stp */ + iRet = wmt_core_stp_init(); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt_core_stp_init fail (%d)\n", iRet); + osal_assert(0); + + /* deinit stp */ + iRet = wmt_core_stp_deinit(); + if (iRet) + WMT_ERR_FUNC("WMT-CORE: wmt_core_stp_deinit() failed.\n"); + iRet = opfunc_pwr_off(pWmtOp); + if (iRet) + WMT_ERR_FUNC("WMT-CORE: opfunc_pwr_off fail during pwr_on retry\n"); + + if (retry-- > 0) { + WMT_INFO_FUNC("WMT-CORE: retry (%d)\n", retry); + goto pwr_on_rty; + } + return -3; + } + + WMT_DBG_FUNC("WMT-CORE: WMT [FUNC_ON]\n"); + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_FUNC_ON; + + /* update blank status when ConnSys power on */ + wmt_blank_status_ctrl(wmt_dev_get_blank_state()); + + /* What to do when state is changed from POWER_OFF to POWER_ON? + * 1. STP driver does s/w reset + * 2. UART does 0xFF wake up + * 3. SDIO does re-init command(changed to trigger by host) + */ + return iRet; + +} + +static INT32 opfunc_pwr_off(P_WMT_OP pWmtOp) +{ + + INT32 iRet; + ULONG ctrlPa1; + ULONG ctrlPa2; + + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] == DRV_STS_POWER_OFF) { + WMT_WARN_FUNC("WMT-CORE: WMT already off, WMT DRV_STS_[0x%x]\n", + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT]); + osal_assert(0); + return -1; + } + if (g_pwr_off_flag == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("CONNSYS power off be disabled, maybe need trigger core dump!\n"); + osal_assert(0); + return -2; + } + /* wmt and stp are initialized successfully */ + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] == DRV_STS_FUNC_ON) { + iRet = wmt_core_stp_deinit(); + if (iRet) { + WMT_WARN_FUNC("wmt_core_stp_deinit fail (%d)\n", iRet); + /*should let run to power down chip */ + } + } + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; + + /* power off control */ + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_OFF, &ctrlPa1, &ctrlPa2); + if (iRet) + WMT_WARN_FUNC("HW_PWR_OFF fail (%d)\n", iRet); + else + WMT_DBG_FUNC("HW_PWR_OFF ok\n"); + + /*anyway, set to POWER_OFF state */ + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_OFF; + return iRet; + +} + +static INT32 opfunc_func_on(P_WMT_OP pWmtOp) +{ + INT32 iRet = -1; + UINT32 drvType = pWmtOp->au4OpData[0]; + + /* Check abnormal type */ + if (drvType > WMTDRV_TYPE_COREDUMP) { + WMT_ERR_FUNC("abnormal Fun(%d)\n", drvType); + osal_assert(0); + return -1; + } + + /* Check abnormal state */ + if ((gMtkWmtCtx.eDrvStatus[drvType] < DRV_STS_POWER_OFF) + || (gMtkWmtCtx.eDrvStatus[drvType] >= DRV_STS_MAX)) { + WMT_ERR_FUNC("func(%d) status[0x%x] abnormal\n", + drvType, gMtkWmtCtx.eDrvStatus[drvType]); + osal_assert(0); + return -2; + } + + /* check if func already on */ + if (gMtkWmtCtx.eDrvStatus[drvType] == DRV_STS_FUNC_ON) { + WMT_WARN_FUNC("func(%d) already on\n", drvType); + return 0; + } + /*enable power off flag, if flag=0, power off connsys will not be executed */ + mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL_TRUE); + /* check if chip power on is needed */ + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] != DRV_STS_FUNC_ON) { + iRet = opfunc_pwr_on(pWmtOp); + if (iRet) { + WMT_ERR_FUNC("func(%d) pwr_on fail(%d)\n", drvType, iRet); + osal_assert(0); + + /* check all sub-func and do power off */ + return -3; + } + } + + if (WMTDRV_TYPE_WMT > drvType || WMTDRV_TYPE_ANT == drvType) { + if (gpWmtFuncOps[drvType] && gpWmtFuncOps[drvType]->func_on) { + + /* special handling for Wi-Fi */ + if (drvType == WMTDRV_TYPE_WIFI) { + P_OSAL_OP pOp = wmt_lib_get_current_op(&gDevWmt); + atomic_set(&g_wifi_on_off_ready, 1); + + pOp->op.opId = WMT_OPID_WLAN_PROBE; + if (wmt_lib_put_worker_op(pOp) == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("put to activeWorker queue fail\n"); + atomic_set(&g_wifi_on_off_ready, 0); + return -4; + } + return 0; + } + + iRet = (*(gpWmtFuncOps[drvType]->func_on)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); + if (iRet != 0) + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; + else + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON; + } else { + WMT_WARN_FUNC("WMT-CORE: ops for type(%d) not found\n", drvType); + iRet = -5; + } + } else { + if (drvType == WMTDRV_TYPE_LPBK) + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON; + else if (drvType == WMTDRV_TYPE_COREDUMP) + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON; + iRet = 0; + } + + if (iRet) { + WMT_ERR_FUNC("WMT-CORE:type(0x%x) function on failed, ret(%d)\n", drvType, iRet); + opfunc_try_pwr_off(pWmtOp); + return iRet; + } + + /* send UTC time sync command after function on */ + opfunc_utc_time_sync(NULL); + wmt_core_dump_func_state("AF FUNC ON"); + + return 0; +} + +static INT32 opfunc_func_off(P_WMT_OP pWmtOp) +{ + INT32 iRet = -1; + UINT32 drvType = pWmtOp->au4OpData[0]; + + /* Check abnormal type */ + if (drvType > WMTDRV_TYPE_COREDUMP) { + WMT_ERR_FUNC("WMT-CORE: abnormal Fun(%d) in wmt_func_off\n", drvType); + osal_assert(0); + return -1; + } + + /* Check abnormal state */ + if (gMtkWmtCtx.eDrvStatus[drvType] >= DRV_STS_MAX) { + WMT_ERR_FUNC("WMT-CORE: Fun(%d) DRV_STS_[0x%x] abnormal in wmt_func_off\n", + drvType, gMtkWmtCtx.eDrvStatus[drvType]); + osal_assert(0); + return -2; + } + + if (gMtkWmtCtx.eDrvStatus[drvType] != DRV_STS_FUNC_ON) { + WMT_WARN_FUNC + ("WMT-CORE: Fun(%d) DRV_STS_[0x%x] already non-FUN_ON in wmt_func_off\n", + drvType, gMtkWmtCtx.eDrvStatus[drvType]); + /* needs to check 4 subsystem's state? */ + return 0; + } else if (WMTDRV_TYPE_WMT > drvType || WMTDRV_TYPE_ANT == drvType) { + if (gpWmtFuncOps[drvType] && gpWmtFuncOps[drvType]->func_off) { + /* special handling for Wi-Fi */ + if (drvType == WMTDRV_TYPE_WIFI) { + P_OSAL_OP pOp = wmt_lib_get_current_op(&gDevWmt); + atomic_set(&g_wifi_on_off_ready, 1); + + pOp->op.opId = WMT_OPID_WLAN_REMOVE; + if (wmt_lib_put_worker_op(pOp) == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("put to activeWorker queue fail\n"); + atomic_set(&g_wifi_on_off_ready, 0); + return -4; + } + return 0; + } + iRet = (*(gpWmtFuncOps[drvType]->func_off)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); + } else { + WMT_WARN_FUNC("WMT-CORE: ops for type(%d) not found\n", drvType); + iRet = -3; + } + } else { + if (drvType == WMTDRV_TYPE_LPBK) + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; + else if (drvType == WMTDRV_TYPE_COREDUMP) + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; + iRet = 0; + } + + if (drvType != WMTDRV_TYPE_WMT) + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; + + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: type(0x%x) function off failed, ret(%d)\n", drvType, iRet); + osal_assert(0); + /* no matter subsystem function control fail or not, chip should be powered off + * when no subsystem is active + * return iRet; + */ + } + + /* check all sub-func and do power off */ + opfunc_try_pwr_off(pWmtOp); + wmt_core_dump_func_state("AF FUNC OFF"); + return iRet; +} + +static INT32 opfunc_gps_suspend(P_WMT_OP pWmtOp) +{ + INT32 iRet = -1; + P_WMT_GEN_CONF pWmtGenConf = NULL; + MTK_WCN_BOOL suspend = (pWmtOp->au4OpData[0] != 0); + + pWmtGenConf = wmt_conf_get_cfg(); + + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS] != DRV_STS_FUNC_ON) { + WMT_WARN_FUNC("WMT-CORE: GPS driver non-FUN_ON in opfunc_gps_suspend\n"); + return 0; + } + + if (MTK_WCN_BOOL_TRUE == suspend) { + if (osal_test_bit(WMT_GPS_SUSPEND, &gGpsFmState)) { + WMT_WARN_FUNC("WMT-CORE: gps already suspend\n"); + return 0; + } + } else { + if (!osal_test_bit(WMT_GPS_SUSPEND, &gGpsFmState)) { + WMT_WARN_FUNC("WMT-CORE: gps already resume on\n"); + return 0; + } + } + + if (MTK_WCN_BOOL_TRUE == suspend) { + if (gpWmtFuncOps[WMTDRV_TYPE_GPS] && gpWmtFuncOps[WMTDRV_TYPE_GPS]->func_off) { + if (pWmtGenConf != NULL) + pWmtGenConf->wmt_gps_suspend_ctrl = 1; + iRet = (*(gpWmtFuncOps[WMTDRV_TYPE_GPS]->func_off)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); + if (pWmtGenConf != NULL) + pWmtGenConf->wmt_gps_suspend_ctrl = 0; + } else { + WMT_WARN_FUNC("WMT-CORE: gps suspend ops not found\n"); + iRet = -3; + } + } else { + /*enable power off flag, if flag=0, power off connsys will not be executed */ + mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL_TRUE); + /* check if chip power on is needed */ + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] != DRV_STS_FUNC_ON) { + iRet = opfunc_pwr_on(pWmtOp); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: func(WMTDRV_TYPE_GPS) hw resume fail(%d)\n", iRet); + osal_assert(0); + + /* check all sub-func and do power off */ + return -5; + } + } + + if (gpWmtFuncOps[WMTDRV_TYPE_GPS] && gpWmtFuncOps[WMTDRV_TYPE_GPS]->func_on) { + if (pWmtGenConf != NULL) + pWmtGenConf->wmt_gps_suspend_ctrl = 1; + iRet = (*(gpWmtFuncOps[WMTDRV_TYPE_GPS]->func_on)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); + if (pWmtGenConf != NULL) + pWmtGenConf->wmt_gps_suspend_ctrl = 0; + } else { + WMT_WARN_FUNC("WMT-CORE: gps resume ops not found\n"); + iRet = -7; + } + } + + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: gps %s function failed, ret(%d)\n", + ((pWmtOp->au4OpData[0] != 0) ? "suspend" : "resume"), iRet); + osal_assert(0); + } + + if (MTK_WCN_BOOL_FALSE == suspend) + opfunc_utc_time_sync(NULL); + + return iRet; +} + +/* TODO:[ChangeFeature][George] is this OP obsoleted? */ +static INT32 opfunc_reg_rw(P_WMT_OP pWmtOp) +{ + INT32 iret; + + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] != DRV_STS_FUNC_ON) { + WMT_ERR_FUNC("reg_rw when WMT is powered off\n"); + return -1; + } + iret = wmt_core_reg_rw_raw(pWmtOp->au4OpData[0], + pWmtOp->au4OpData[1], + (PUINT32) pWmtOp->au4OpData[2], pWmtOp->au4OpData[3]); + + return iret; +} + +static INT32 opfunc_exit(P_WMT_OP pWmtOp) +{ + /* TODO: [FixMe][George] is ok to leave this function empty??? */ + WMT_WARN_FUNC("EMPTY FUNCTION\n"); + return 0; +} + +static INT32 opfunc_pwr_sv(P_WMT_OP pWmtOp) +{ + INT32 ret = -1; + UINT32 u4_result = 0; + UINT32 evt_len; + UINT8 evt_buf[16] = { 0 }; + ULONG ctrlPa1 = 0; + ULONG ctrlPa2 = 0; + + typedef INT32(*STP_PSM_CB) (INT32); + STP_PSM_CB psm_cb = NULL; + + if (pWmtOp->au4OpData[0] == SLEEP) { + WMT_DBG_FUNC("**** Send sleep command\n"); + /* mtk_wcn_stp_set_psm_state(ACT_INACT); */ + /* (*kal_stp_flush_rx)(WMT_TASK_INDX); */ + ret = + wmt_core_tx((const PUINT8)(&WMT_SLEEP_CMD[0]), sizeof(WMT_SLEEP_CMD), + &u4_result, 0); + if (ret || (u4_result != sizeof(WMT_SLEEP_CMD))) { + WMT_ERR_FUNC("wmt_core: SLEEP_CMD ret(%d) cmd len err(%d, %zu) ", ret, + u4_result, sizeof(WMT_SLEEP_CMD)); + goto pwr_sv_done; + } + + evt_len = sizeof(WMT_SLEEP_EVT); + ret = wmt_core_rx(evt_buf, evt_len, &u4_result); + if (ret || (u4_result != evt_len)) { + wmt_core_rx_flush(WMT_TASK_INDX); + WMT_ERR_FUNC + ("wmt_core: read SLEEP_EVT fail(%d) len(%d, %d), host trigger firmware assert\n", + ret, u4_result, evt_len); + + wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 33); + goto pwr_sv_done; + } + + if (osal_memcmp(evt_buf, (const PVOID)WMT_SLEEP_EVT, sizeof(WMT_SLEEP_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_SLEEP_EVT error\n"); + wmt_core_rx_flush(WMT_TASK_INDX); + WMT_ERR_FUNC("rx(%d):[%2X,%2X,%2X,%2X,%2X,%2X] exp(%zu):[%2X,%2X,%2X,%2X,%2X,%2X]\n", + u4_result, evt_buf[0], evt_buf[1], evt_buf[2], evt_buf[3], evt_buf[4], + evt_buf[5], sizeof(WMT_SLEEP_EVT), WMT_SLEEP_EVT[0], WMT_SLEEP_EVT[1], + WMT_SLEEP_EVT[2], WMT_SLEEP_EVT[3], WMT_SLEEP_EVT[4], + WMT_SLEEP_EVT[5]); + mtk_wcn_stp_dbg_dump_package(); + goto pwr_sv_done; + } + WMT_DBG_FUNC("Send sleep command OK!\n"); + } else if (pWmtOp->au4OpData[0] == WAKEUP) { + if (mtk_wcn_stp_is_btif_fullset_mode()) { + WMT_DBG_FUNC("wakeup connsys by btif"); + ret = wmt_core_ctrl(WMT_CTRL_SOC_WAKEUP_CONSYS, &ctrlPa1, &ctrlPa2); + if (ret) { + WMT_ERR_FUNC("wmt-core:WAKEUP_CONSYS by BTIF fail(%d)", ret); + goto pwr_sv_done; + } + } else if (mtk_wcn_stp_is_sdio_mode()) { + WMT_DBG_FUNC("**** Send wakeup command\n"); + ret = + wmt_core_tx((const PUINT8)WMT_WAKEUP_CMD, sizeof(WMT_WAKEUP_CMD), &u4_result, 1); + if (ret || (u4_result != sizeof(WMT_WAKEUP_CMD))) { + wmt_core_rx_flush(WMT_TASK_INDX); + WMT_ERR_FUNC("wmt_core: WAKEUP_CMD ret(%d) cmd len err(%d, %zu)\n", + ret, u4_result, sizeof(WMT_WAKEUP_CMD)); + goto pwr_sv_done; + } + } + evt_len = sizeof(WMT_WAKEUP_EVT); + ret = wmt_core_rx(evt_buf, evt_len, &u4_result); + if (ret || (u4_result != evt_len)) { + WMT_ERR_FUNC + ("wmt_core: read WAKEUP_EVT fail(%d) len(%d, %d), host grigger firmaware assert\n", + ret, u4_result, evt_len); + + wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 34); + goto pwr_sv_done; + } + + if (osal_memcmp(evt_buf, (const PVOID)WMT_WAKEUP_EVT, sizeof(WMT_WAKEUP_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_WAKEUP_EVT error\n"); + wmt_core_rx_flush(WMT_TASK_INDX); + WMT_ERR_FUNC("rx(%d):[%2X,%2X,%2X,%2X,%2X,%2X] exp(%zu):[%2X,%2X,%2X,%2X,%2X,%2X]\n", + u4_result, evt_buf[0], evt_buf[1], evt_buf[2], evt_buf[3], evt_buf[4], + evt_buf[5], sizeof(WMT_WAKEUP_EVT), WMT_WAKEUP_EVT[0], + WMT_WAKEUP_EVT[1], WMT_WAKEUP_EVT[2], WMT_WAKEUP_EVT[3], + WMT_WAKEUP_EVT[4], WMT_WAKEUP_EVT[5]); + mtk_wcn_stp_dbg_dump_package(); + goto pwr_sv_done; + } + WMT_DBG_FUNC("Send wakeup command OK!\n"); + } else if (pWmtOp->au4OpData[0] == HOST_AWAKE) { + + WMT_DBG_FUNC("**** Send host awake command\n"); + + psm_cb = (STP_PSM_CB) pWmtOp->au4OpData[1]; + /* (*kal_stp_flush_rx)(WMT_TASK_INDX); */ + ret = + wmt_core_tx((const PUINT8)WMT_HOST_AWAKE_CMD, sizeof(WMT_HOST_AWAKE_CMD), + &u4_result, 0); + if (ret || (u4_result != sizeof(WMT_HOST_AWAKE_CMD))) { + WMT_ERR_FUNC("wmt_core: HOST_AWAKE_CMD ret(%d) cmd len err(%d, %zu) ", ret, + u4_result, sizeof(WMT_HOST_AWAKE_CMD)); + goto pwr_sv_done; + } + + evt_len = sizeof(WMT_HOST_AWAKE_EVT); + ret = wmt_core_rx(evt_buf, evt_len, &u4_result); + if (ret || (u4_result != evt_len)) { + wmt_core_rx_flush(WMT_TASK_INDX); + WMT_ERR_FUNC + ("wmt_core:read HOST_AWAKE_EVT fail(%d) len(%d, %d), host trigger f/w assert\n", + ret, u4_result, evt_len); + + wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 35); + goto pwr_sv_done; + } + + if (osal_memcmp + (evt_buf, (const PVOID)WMT_HOST_AWAKE_EVT, sizeof(WMT_HOST_AWAKE_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_HOST_AWAKE_EVT error\n"); + wmt_core_rx_flush(WMT_TASK_INDX); + WMT_ERR_FUNC("rx(%d):[%2X,%2X,%2X,%2X,%2X,%2X] exp(%zu):[%2X,%2X,%2X,%2X,%2X,%2X]\n", + u4_result, evt_buf[0], evt_buf[1], evt_buf[2], evt_buf[3], evt_buf[4], + evt_buf[5], sizeof(WMT_HOST_AWAKE_EVT), WMT_HOST_AWAKE_EVT[0], + WMT_HOST_AWAKE_EVT[1], WMT_HOST_AWAKE_EVT[2], WMT_HOST_AWAKE_EVT[3], + WMT_HOST_AWAKE_EVT[4], WMT_HOST_AWAKE_EVT[5]); + mtk_wcn_stp_dbg_dump_package(); + /* goto pwr_sv_done; */ + } else { + WMT_DBG_FUNC("Send host awake command OK!\n"); + } + } +pwr_sv_done: + + if (pWmtOp->au4OpData[0] < STP_PSM_MAX_ACTION) { + psm_cb = (STP_PSM_CB) pWmtOp->au4OpData[1]; + WMT_DBG_FUNC("Do STP-CB! %zu %p\n", pWmtOp->au4OpData[0], + (PVOID) pWmtOp->au4OpData[1]); + if (psm_cb != NULL) { + psm_cb(pWmtOp->au4OpData[0]); + } else { + WMT_ERR_FUNC + ("fatal error !!!, psm_cb = %p, god, someone must have corrupted our memory.\n", + psm_cb); + } + } + + return ret; +} + +static INT32 opfunc_dsns(P_WMT_OP pWmtOp) +{ + + INT32 iRet = -1; + UINT32 u4Res; + UINT32 evtLen; + UINT8 evtBuf[16] = { 0 }; + + WMT_DSNS_CMD[4] = pWmtOp->au4OpData[0]; + WMT_DSNS_CMD[5] = pWmtOp->au4OpData[1]; + + /* send command */ + /* iRet = (*kal_stp_tx)(WMT_DSNS_CMD, osal_sizeof(WMT_DSNS_CMD), &u4Res); */ + iRet = + wmt_core_tx((PUINT8) WMT_DSNS_CMD, osal_sizeof(WMT_DSNS_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != osal_sizeof(WMT_DSNS_CMD))) { + WMT_ERR_FUNC("WMT-CORE: DSNS_CMD iRet(%d) cmd len err(%d, %zu)\n", iRet, u4Res, + osal_sizeof(WMT_DSNS_CMD)); + return iRet; + } + + evtLen = osal_sizeof(WMT_DSNS_EVT); + + iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); + if (iRet || (u4Res != evtLen)) { + WMT_ERR_FUNC("WMT-CORE: read DSNS_EVT fail(%d) len(%d, %d)\n", iRet, u4Res, evtLen); + mtk_wcn_stp_dbg_dump_package(); + return iRet; + } + + if (osal_memcmp(evtBuf, WMT_DSNS_EVT, osal_sizeof(WMT_DSNS_EVT)) != 0) { + WMT_ERR_FUNC("WMT-CORE: compare WMT_DSNS_EVT error\n"); + WMT_ERR_FUNC + ("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + osal_sizeof(WMT_DSNS_EVT), WMT_DSNS_EVT[0], WMT_DSNS_EVT[1], WMT_DSNS_EVT[2], + WMT_DSNS_EVT[3], WMT_DSNS_EVT[4]); + } else { + WMT_INFO_FUNC("Send WMT_DSNS_CMD command OK!\n"); + } + + return iRet; +} + +#if CFG_CORE_INTERNAL_TXRX +INT32 wmt_core_lpbk_do_stp_init(void) +{ + INT32 iRet = 0; + ULONG ctrlPa1 = 0; + ULONG ctrlPa2 = 0; + + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_STP_OPEN, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt open stp\n"); + return -1; + } + + ctrlPa1 = WMT_STP_CONF_MODE; + ctrlPa2 = MTKSTP_BTIF_MAND_MODE; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 1; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: stp_init <1><2> fail:%d\n", iRet); + return -2; + } +} + +INT32 wmt_core_lpbk_do_stp_deinit(void) +{ + INT32 iRet = 0; + ULONG ctrlPa1 = 0; + ULONG ctrlPa2 = 0; + + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt open stp\n"); + return -1; + } + + return 0; +} +#endif + + +static INT32 opfunc_lpbk(P_WMT_OP pWmtOp) +{ + + INT32 iRet; + UINT32 u4WrittenSize = 0; + UINT32 u4ReadSize = 0; + UINT32 buf_length = 0; + PUINT32 pbuffer = NULL; + UINT16 len_in_cmd; + /* UINT32 offset; */ + UINT8 WMT_TEST_LPBK_CMD[] = { 0x1, 0x2, 0x0, 0x0, 0x7 }; + UINT8 WMT_TEST_LPBK_EVT[] = { 0x2, 0x2, 0x0, 0x0, 0x0 }; + /* UINT8 lpbk_buf[1024 + 5] = {0}; */ + MTK_WCN_BOOL fgFail; + + buf_length = pWmtOp->au4OpData[0]; /* packet length */ + pbuffer = (PUINT32) pWmtOp->au4OpData[1]; /* packet buffer pointer */ + WMT_DBG_FUNC("WMT-CORE: -->wmt_do_lpbk\n"); + /*check if WMTDRV_TYPE_LPBK function is already on */ + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK] != DRV_STS_FUNC_ON + || buf_length + osal_sizeof(WMT_TEST_LPBK_CMD) > osal_sizeof(gLpbkBuf)) { + WMT_ERR_FUNC("WMT-CORE: abnormal LPBK in wmt_do_lpbk\n"); + osal_assert(0); + return -2; + } + /*package loopback for STP */ + + /* init buffer */ + osal_memset(gLpbkBuf, 0, osal_sizeof(gLpbkBuf)); + + len_in_cmd = buf_length + 1; /* add flag field */ + + osal_memcpy(&WMT_TEST_LPBK_CMD[2], &len_in_cmd, 2); + osal_memcpy(&WMT_TEST_LPBK_EVT[2], &len_in_cmd, 2); + + /* wmt cmd */ + osal_memcpy(gLpbkBuf, WMT_TEST_LPBK_CMD, osal_sizeof(WMT_TEST_LPBK_CMD)); + osal_memcpy(gLpbkBuf + osal_sizeof(WMT_TEST_LPBK_CMD), pbuffer, buf_length); + + do { + fgFail = MTK_WCN_BOOL_TRUE; + /*send packet through STP */ + /* iRet = (*kal_stp_tx)((PUINT8)gLpbkBuf, osal_sizeof(WMT_TEST_LPBK_CMD) + + * buf_length, &u4WrittenSize); + */ + iRet = + wmt_core_tx((PUINT8) gLpbkBuf, (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length), + &u4WrittenSize, MTK_WCN_BOOL_FALSE); + if (iRet) { + WMT_ERR_FUNC("opfunc_lpbk wmt_core_tx failed\n"); + break; + } + /*receive firmware response from STP */ + iRet = + wmt_core_rx((PUINT8) gLpbkBuf, (osal_sizeof(WMT_TEST_LPBK_EVT) + buf_length), + &u4ReadSize); + if (iRet) { + WMT_ERR_FUNC("opfunc_lpbk wmt_core_rx failed\n"); + break; + } + /*check if loopback response ok or not */ + if (u4ReadSize != (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length)) { + WMT_ERR_FUNC("lpbk event read size wrong(%d, %zu)\n", u4ReadSize, + (osal_sizeof(WMT_TEST_LPBK_CMD) + buf_length)); + break; + } + if (osal_memcmp(WMT_TEST_LPBK_EVT, gLpbkBuf, osal_sizeof(WMT_TEST_LPBK_EVT))) { + WMT_ERR_FUNC + ("WMT-CORE WMT_TEST_LPBK_EVT error! read len %d [%02x,%02x,%02x,%02x,%02x]\n", + (INT32) u4ReadSize, gLpbkBuf[0], gLpbkBuf[1], gLpbkBuf[2], gLpbkBuf[3], + gLpbkBuf[4] + ); + break; + } + pWmtOp->au4OpData[0] = u4ReadSize - osal_sizeof(WMT_TEST_LPBK_EVT); + osal_memcpy((PVOID) pWmtOp->au4OpData[1], + gLpbkBuf + osal_sizeof(WMT_TEST_LPBK_CMD), buf_length); + fgFail = MTK_WCN_BOOL_FALSE; + } while (0); + /*return result */ + /* WMT_DBG_FUNC("WMT-CORE: <--wmt_do_lpbk, fgFail = %d\n", fgFail); */ + if (fgFail == MTK_WCN_BOOL_TRUE) { + WMT_ERR_FUNC("LPBK fail and trigger assert\n"); + wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 37); + } + return fgFail; + +} + +static INT32 opfunc_cmd_test(P_WMT_OP pWmtOp) +{ + + INT32 iRet = 0; + UINT32 cmdNo = 0; + UINT32 cmdNoPa = 0; + + UINT8 tstCmd[64]; + UINT8 tstEvt[64]; + UINT8 tstEvtTmp[64]; + UINT32 u4Res; + UINT32 tstCmdSz = 0; + UINT32 tstEvtSz = 0; + + PUINT8 pRes = NULL; + UINT32 resBufRoom = 0; + /*test command list */ + /*1 */ + UINT8 WMT_ASSERT_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x08 }; + UINT8 WMT_ASSERT_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; + UINT8 WMT_NOACK_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0A }; + UINT8 WMT_NOACK_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; + UINT8 WMT_WARNRST_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0B }; + UINT8 WMT_WARNRST_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; + UINT8 WMT_FWLOGTST_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x0C }; + UINT8 WMT_FWLOGTST_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; + + UINT8 WMT_EXCEPTION_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x09 }; + UINT8 WMT_EXCEPTION_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; + /*2 */ + UINT8 WMT_COEXDBG_CMD[] = { 0x01, 0x10, 0x02, 0x00, + 0x08, + 0xAA /*Debugging Parameter */ + }; + UINT8 WMT_COEXDBG_1_EVT[] = { 0x02, 0x10, 0x05, 0x00, + 0x00, + 0xAA, 0xAA, 0xAA, 0xAA /*event content */ + }; + UINT8 WMT_COEXDBG_2_EVT[] = { 0x02, 0x10, 0x07, 0x00, + 0x00, + 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB /*event content */ + }; + UINT8 WMT_COEXDBG_3_EVT[] = { 0x02, 0x10, 0x0B, 0x00, + 0x00, + 0xAA, 0xAA, 0xAA, 0xAA, 0xBB, 0xBB, 0xBB, 0xBB /*event content */ + }; + /*test command list -end */ + + cmdNo = pWmtOp->au4OpData[0]; + + WMT_INFO_FUNC("Send Test command %d!\n", cmdNo); + if (cmdNo == 0) { + /*dead command */ + WMT_INFO_FUNC("Send Assert command !\n"); + tstCmdSz = osal_sizeof(WMT_ASSERT_CMD); + tstEvtSz = osal_sizeof(WMT_ASSERT_EVT); + osal_memcpy(tstCmd, WMT_ASSERT_CMD, tstCmdSz); + osal_memcpy(tstEvt, WMT_ASSERT_EVT, tstEvtSz); + } else if (cmdNo == 1) { + /*dead command */ + WMT_INFO_FUNC("Send Exception command !\n"); + tstCmdSz = osal_sizeof(WMT_EXCEPTION_CMD); + tstEvtSz = osal_sizeof(WMT_EXCEPTION_EVT); + osal_memcpy(tstCmd, WMT_EXCEPTION_CMD, tstCmdSz); + osal_memcpy(tstEvt, WMT_EXCEPTION_EVT, tstEvtSz); + } else if (cmdNo == 2) { + cmdNoPa = pWmtOp->au4OpData[1]; + pRes = (PUINT8) pWmtOp->au4OpData[2]; + resBufRoom = pWmtOp->au4OpData[3]; + if (cmdNoPa <= 0xf) { + WMT_INFO_FUNC("Send Coexistence Debug command [0x%x]!\n", cmdNoPa); + tstCmdSz = osal_sizeof(WMT_COEXDBG_CMD); + osal_memcpy(tstCmd, WMT_COEXDBG_CMD, tstCmdSz); + if (tstCmdSz > 5) + tstCmd[5] = cmdNoPa; + + /*setup the expected event length */ + if (cmdNoPa <= 0x4) { + tstEvtSz = osal_sizeof(WMT_COEXDBG_1_EVT); + osal_memcpy(tstEvt, WMT_COEXDBG_1_EVT, tstEvtSz); + } else if (cmdNoPa == 0x5) { + tstEvtSz = osal_sizeof(WMT_COEXDBG_2_EVT); + osal_memcpy(tstEvt, WMT_COEXDBG_2_EVT, tstEvtSz); + } else if (cmdNoPa >= 0x6 && cmdNoPa <= 0xf) { + tstEvtSz = osal_sizeof(WMT_COEXDBG_3_EVT); + osal_memcpy(tstEvt, WMT_COEXDBG_3_EVT, tstEvtSz); + } else { + + } + } else { + WMT_ERR_FUNC("cmdNoPa is wrong\n"); + return iRet; + } + } else if (cmdNo == 3) { + /*dead command */ + WMT_INFO_FUNC("Send No Ack command !\n"); + tstCmdSz = osal_sizeof(WMT_NOACK_CMD); + tstEvtSz = osal_sizeof(WMT_NOACK_EVT); + osal_memcpy(tstCmd, WMT_NOACK_CMD, tstCmdSz); + osal_memcpy(tstEvt, WMT_NOACK_EVT, tstEvtSz); + } else if (cmdNo == 4) { + /*dead command */ + WMT_INFO_FUNC("Send Warm reset command !\n"); + tstCmdSz = osal_sizeof(WMT_WARNRST_CMD); + tstEvtSz = osal_sizeof(WMT_WARNRST_EVT); + osal_memcpy(tstCmd, WMT_WARNRST_CMD, tstCmdSz); + osal_memcpy(tstEvt, WMT_WARNRST_EVT, tstEvtSz); + } else if (cmdNo == 5) { + /*dead command */ + WMT_INFO_FUNC("Send f/w log test command !\n"); + tstCmdSz = osal_sizeof(WMT_FWLOGTST_CMD); + tstEvtSz = osal_sizeof(WMT_FWLOGTST_EVT); + osal_memcpy(tstCmd, WMT_FWLOGTST_CMD, tstCmdSz); + osal_memcpy(tstEvt, WMT_FWLOGTST_EVT, tstEvtSz); + } + + /* send command */ + /* iRet = (*kal_stp_tx)(tstCmd, tstCmdSz, &u4Res); */ + iRet = wmt_core_tx((PUINT8) tstCmd, tstCmdSz, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != tstCmdSz)) { + WMT_ERR_FUNC("WMT-CORE: wmt_cmd_test iRet(%d) cmd len err(%d, %d)\n", iRet, u4Res, + tstCmdSz); + return -1; + } + + if ((cmdNo == 0) || (cmdNo == 1) || cmdNo == 3) { + WMT_INFO_FUNC("WMT-CORE: not to rx event for assert command\n"); + return 0; + } + + iRet = wmt_core_rx(tstEvtTmp, tstEvtSz, &u4Res); + + /*Event Post Handling */ + if (cmdNo == 2) { + WMT_INFO_FUNC("#=========================================================#\n"); + WMT_INFO_FUNC("coext debugging id = %d", cmdNoPa); + if (tstEvtSz > 5) + wmt_core_dump_data(&tstEvtTmp[5], "coex debugging ", tstEvtSz - 5); + else + WMT_ERR_FUNC("error coex debugging event\n"); + /*put response to buffer for shell to read */ + if (pRes != NULL && resBufRoom > 0) { + pWmtOp->au4OpData[3] = + resBufRoom < tstEvtSz - 5 ? resBufRoom : tstEvtSz - 5; + osal_memcpy(pRes, &tstEvtTmp[5], pWmtOp->au4OpData[3]); + } else + pWmtOp->au4OpData[3] = 0; + WMT_INFO_FUNC("#=========================================================#\n"); + } + + return iRet; + +} + +static INT32 opfunc_hw_rst(P_WMT_OP pWmtOp) +{ + + INT32 iRet = -1; + ULONG ctrlPa1 = 0; + ULONG ctrlPa2 = 0; + + wmt_core_dump_func_state("BE HW RST"); + /*-->Reset WMT data structure*/ + /*gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] = DRV_STS_POWER_OFF;*/ + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM] = DRV_STS_POWER_OFF; + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS] = DRV_STS_POWER_OFF; + /* gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] = DRV_STS_POWER_OFF; */ + /*gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK] = DRV_STS_POWER_OFF;*/ + /* gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO1]= DRV_STS_POWER_OFF; */ + /* gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO2]= DRV_STS_POWER_OFF; */ + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_STP] = DRV_STS_POWER_OFF; + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_ANT] = DRV_STS_POWER_OFF; + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP] = DRV_STS_POWER_OFF; + /*enable power off flag, if flag=0, power off connsys will not be executed */ + mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL_TRUE); + + /* if wmt is poweroff, we need poweron chip first */ + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] == DRV_STS_POWER_OFF) { + WMT_WARN_FUNC("WMT-CORE: WMT is off, need re-poweron\n"); + /* power on control */ + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HW_PWR_ON, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: WMT_CTRL_HW_PWR_ON fail iRet(%d)\n", iRet); + return -1; + } + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_ON; + } + + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] == DRV_STS_FUNC_ON) { + if (mtk_wcn_stp_is_btif_fullset_mode()) { + ctrlPa1 = BT_PALDO; + ctrlPa2 = PALDO_OFF; + iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + if (iRet) + WMT_ERR_FUNC("WMT-CORE: wmt_ctrl_soc_paldo_ctrl failed(%d)(%lu)(%lu)\n", + iRet, ctrlPa1, ctrlPa2); + } + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] = DRV_STS_POWER_OFF; + } + + iRet = wmt_lib_wlan_lock_aquire(); + if (iRet) { + WMT_ERR_FUNC("--->lock wlan_lock failed, iRet=%d\n", iRet); + return iRet; + } + + /*--> reset SDIO function/slot additionally if wifi ON*/ + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] == DRV_STS_FUNC_ON) { + if (mtk_wcn_stp_is_sdio_mode()) { + ctrlPa1 = WMT_SDIO_FUNC_WIFI; + ctrlPa2 = 0; /* turn off Wi-Fi driver */ + iRet = wmt_core_ctrl(WMT_CTRL_SDIO_FUNC, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: turn off SDIO_WIFI func fail (%d)\n", iRet); + /* check all sub-func and do power off */ + } else + WMT_INFO_FUNC("wmt core: turn off SDIO WIFI func ok!!\n"); + /* Anyway, turn off Wi-Fi Function */ + } else if (mtk_wcn_stp_is_btif_fullset_mode()) { + if (gpWmtFuncOps[WMTDRV_TYPE_WIFI] != NULL && + gpWmtFuncOps[WMTDRV_TYPE_WIFI]->func_off != NULL) { + iRet = gpWmtFuncOps[WMTDRV_TYPE_WIFI]->func_off(gMtkWmtCtx.p_ic_ops, + wmt_conf_get_cfg()); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: turn off WIFI func fail (%d)\n", iRet); + + /* check all sub-func and do power off */ + } else { + WMT_INFO_FUNC("wmt core: turn off WIFI func ok!!\n"); + } + } + } + /* Anyway, turn off Wi-Fi Function */ + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] = DRV_STS_POWER_OFF; + + if (gMtkWmtCtx.wmtHifConf.hifType == WMT_HIF_UART) { + ctrlPa1 = WMT_SDIO_SLOT_SDIO1; + ctrlPa2 = 0; /* turn off SDIO1 slot */ + iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: turn off SLOT_SDIO1 fail (%d)\n", iRet); + osal_assert(0); + + /* check all sub-func and do power off */ + } else + WMT_INFO_FUNC("WMT-CORE: turn off SLOT_SDIO1 successfully (%d)\n", iRet); + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO1] = DRV_STS_POWER_OFF; + } + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] = DRV_STS_POWER_OFF; + } + wmt_lib_wlan_lock_release(); + + if (gMtkWmtCtx.wmtHifConf.hifType == WMT_HIF_SDIO) { + ctrlPa1 = WMT_SDIO_FUNC_STP; + ctrlPa2 = 0; /* turn off STP driver */ + iRet = wmt_core_ctrl(WMT_CTRL_SDIO_FUNC, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: turn off SDIO_FUNC_STP func fail (%d)\n", iRet); + + /* check all sub-func and do power off */ + /* goto stp_deinit_done; */ + } else + WMT_INFO_FUNC("WMT-CORE: turn off SDIO_FUNC_STP func successfully (%d)\n", iRet); + + ctrlPa1 = WMT_SDIO_SLOT_SDIO2; + ctrlPa2 = 0; /* turn off SDIO2 slot */ + iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: turn off SLOT_SDIO2 fail (%d)\n", iRet); + osal_assert(0); + + /* check all sub-func and do power off */ + /* goto stp_deinit_done; */ + } else + WMT_INFO_FUNC("WMT-CORE: turn off SLOT_SDIO2 successfully (%d)\n", iRet); + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO2] = DRV_STS_POWER_OFF; + } +#if 0 + /*<4>Power off Combo chip */ + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HW_RST, &ctrlPa1, &ctrlPa2); + if (iRet) + WMT_ERR_FUNC("WMT-CORE: [HW RST] WMT_CTRL_POWER_OFF fail (%d)", iRet); + else + WMT_INFO_FUNC("WMT-CORE: [HW RST] WMT_CTRL_POWER_OFF ok (%d)", iRet); +#endif + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_OFF; + + /*-->PesetCombo chip*/ + iRet = wmt_core_ctrl(WMT_CTRL_HW_RST, &ctrlPa1, &ctrlPa2); + if (iRet) + WMT_ERR_FUNC("WMT-CORE: -->[HW RST] fail iRet(%d)\n", iRet); + else + WMT_INFO_FUNC("WMT-CORE: -->[HW RST] ok\n"); + + /* 4 close stp */ + ctrlPa1 = 0; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CLOSE, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt close stp failed\n"); + return -1; + } + + wmt_core_dump_func_state("AF HW RST"); + return iRet; +} + +static INT32 opfunc_sw_rst(P_WMT_OP pWmtOp) +{ + INT32 iRet = -1; + + iRet = wmt_core_stp_init(); + if (iRet == 0) { + WMT_INFO_FUNC("WMT-CORE: SW Rst succeed\n"); + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_FUNC_ON; + } else { + WMT_ERR_FUNC("WMT-CORE: SW Rst failed\n"); + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] = DRV_STS_POWER_OFF; + } + + return iRet; +} + +static INT32 opfunc_stp_rst(P_WMT_OP pWmtOp) +{ + + return 0; +} + +static INT32 opfunc_therm_ctrl(P_WMT_OP pWmtOp) +{ + + INT32 iRet = -1; + UINT32 u4Res; + UINT32 evtLen; + UINT8 evtBuf[16] = { 0 }; + + WMT_THERM_CMD[4] = pWmtOp->au4OpData[0]; /*CMD type, refer to ENUM_WMTTHERM_TYPE_T */ + + /* send command */ + /* iRet = (*kal_stp_tx)(WMT_THERM_CMD, osal_sizeof(WMT_THERM_CMD), &u4Res); */ + iRet = + wmt_core_tx((PUINT8) WMT_THERM_CMD, osal_sizeof(WMT_THERM_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != osal_sizeof(WMT_THERM_CMD))) { + WMT_ERR_FUNC("WMT-CORE: THERM_CTRL_CMD iRet(%d) cmd len err(%d, %zu)\n", iRet, + u4Res, osal_sizeof(WMT_THERM_CMD)); + return iRet; + } + + evtLen = 16; + + iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); + if (iRet || ((u4Res != osal_sizeof(WMT_THERM_CTRL_EVT)) && (u4Res != osal_sizeof(WMT_THERM_READ_EVT)))) { + WMT_ERR_FUNC("WMT-CORE: read THERM_CTRL_EVT/THERM_READ_EVENT fail(%d) len(%d)\n", iRet, u4Res); + wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 36); + return iRet; + } + if (u4Res == osal_sizeof(WMT_THERM_CTRL_EVT)) { + if (osal_memcmp(evtBuf, WMT_THERM_CTRL_EVT, osal_sizeof(WMT_THERM_CTRL_EVT)) != 0) { + WMT_ERR_FUNC("WMT-CORE: compare WMT_THERM_CTRL_EVT error\n"); + WMT_ERR_FUNC + ("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + osal_sizeof(WMT_THERM_CTRL_EVT), WMT_THERM_CTRL_EVT[0], + WMT_THERM_CTRL_EVT[1], WMT_THERM_CTRL_EVT[2], WMT_THERM_CTRL_EVT[3], + WMT_THERM_CTRL_EVT[4]); + pWmtOp->au4OpData[1] = MTK_WCN_BOOL_FALSE; /*will return to function driver */ + mtk_wcn_stp_dbg_dump_package(); + } else { + WMT_DBG_FUNC("Send WMT_THERM_CTRL_CMD command OK!\n"); + pWmtOp->au4OpData[1] = MTK_WCN_BOOL_TRUE; /*will return to function driver */ + } + } else { + /*no need to judge the real thermal value */ + if (osal_memcmp(evtBuf, WMT_THERM_READ_EVT, osal_sizeof(WMT_THERM_READ_EVT) - 1) != + 0) { + WMT_ERR_FUNC("WMT-CORE: compare WMT_THERM_READ_EVT error\n"); + WMT_ERR_FUNC + ("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + evtBuf[5], osal_sizeof(WMT_THERM_READ_EVT), WMT_THERM_READ_EVT[0], + WMT_THERM_READ_EVT[1], WMT_THERM_READ_EVT[2], WMT_THERM_READ_EVT[3]); + pWmtOp->au4OpData[1] = 0xFF; /*will return to function driver */ + mtk_wcn_stp_dbg_dump_package(); + } else { + WMT_DBG_FUNC("Send WMT_THERM_READ_CMD command OK!\n"); + pWmtOp->au4OpData[1] = evtBuf[5]; /*will return to function driver */ + } + } + + return iRet; + +} + +static INT32 opfunc_efuse_rw(P_WMT_OP pWmtOp) +{ + + INT32 iRet = -1; + UINT32 u4Res; + UINT32 evtLen; + UINT8 evtBuf[16] = { 0 }; + + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] != DRV_STS_FUNC_ON) { + WMT_ERR_FUNC("WMT-CORE: wmt_efuse_rw fail: chip is powered off\n"); + return -1; + } + + WMT_EFUSE_CMD[4] = (pWmtOp->au4OpData[0]) ? 0x1 : 0x2; /* w:2, r:1 */ + osal_memcpy(&WMT_EFUSE_CMD[6], (PUINT8) &pWmtOp->au4OpData[1], 2); /* address */ + osal_memcpy(&WMT_EFUSE_CMD[8], (PUINT32) pWmtOp->au4OpData[2], 4); /* value */ + + wmt_core_dump_data(&WMT_EFUSE_CMD[0], "efuse_cmd", osal_sizeof(WMT_EFUSE_CMD)); + + /* send command */ + /* iRet = (*kal_stp_tx)(WMT_EFUSE_CMD, osal_sizeof(WMT_EFUSE_CMD), &u4Res); */ + iRet = + wmt_core_tx((PUINT8) WMT_EFUSE_CMD, osal_sizeof(WMT_EFUSE_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != osal_sizeof(WMT_EFUSE_CMD))) { + WMT_ERR_FUNC("WMT-CORE: EFUSE_CMD iRet(%d) cmd len err(%d, %zu)\n", iRet, u4Res, + osal_sizeof(WMT_EFUSE_CMD)); + return iRet; + } + + evtLen = osal_sizeof(WMT_EFUSE_EVT); + iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); + if (iRet || (u4Res != evtLen)) { + WMT_ERR_FUNC("WMT-CORE: read REG_EVB fail(%d) len(%d, %d)\n", iRet, u4Res, evtLen); + WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n", + evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + WMT_EFUSE_EVT[0], WMT_EFUSE_EVT[1], WMT_EFUSE_EVT[2], + WMT_EFUSE_EVT[3], WMT_EFUSE_EVT[4]); + } + wmt_core_dump_data(&evtBuf[0], "efuse_evt", osal_sizeof(evtBuf)); + + return iRet; +} + +static INT32 opfunc_gpio_ctrl(P_WMT_OP pWmtOp) +{ + INT32 iRet = -1; + WMT_IC_PIN_ID id; + WMT_IC_PIN_STATE stat; + UINT32 flag; + + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WMT] != DRV_STS_FUNC_ON) { + WMT_ERR_FUNC("WMT-CORE: wmt_gpio_ctrl fail: chip is powered off\n"); + return -1; + } + + if (!gMtkWmtCtx.p_ic_ops->ic_pin_ctrl) { + WMT_ERR_FUNC("WMT-CORE: error, gMtkWmtCtx.p_ic_ops->ic_pin_ctrl(NULL)\n"); + return -1; + } + + id = pWmtOp->au4OpData[0]; + stat = pWmtOp->au4OpData[1]; + flag = pWmtOp->au4OpData[2]; + + WMT_INFO_FUNC("ic pin id:%d, stat:%d, flag:0x%x\n", id, stat, flag); + + iRet = (*(gMtkWmtCtx.p_ic_ops->ic_pin_ctrl)) (id, stat, flag); + + return iRet; +} + +/* turn on/off sdio function */ +INT32 opfunc_sdio_ctrl(P_WMT_OP pWmtOp) +{ + ULONG ctrlPa1 = 0; + ULONG ctrlPa2 = 0; + UINT32 iRet = 0; + + ctrlPa1 = + WMT_HIF_SDIO == + gMtkWmtCtx.wmtHifConf.hifType ? WMT_SDIO_SLOT_SDIO2 : WMT_SDIO_SLOT_SDIO1; + ctrlPa2 = pWmtOp->au4OpData[0]; /* turn off/on SDIO slot */ + iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_WARN_FUNC("SDIO hw ctrl fail ret(%d)\n", iRet); + /* Anyway, continue turning STP SDIO to POWER OFF/ON state */ + gMtkWmtCtx.eDrvStatus[ctrlPa1] = DRV_STS_POWER_OFF; + } else { + WMT_INFO_FUNC("SDIO hw ctrl succeed\n"); + gMtkWmtCtx.eDrvStatus[ctrlPa1] = + ctrlPa2 == 0 ? DRV_STS_POWER_OFF : DRV_STS_POWER_ON; + } + + return 0; + +} + +INT32 opfunc_trigger_stp_assert(P_WMT_OP pWmtOp) +{ + if (wmt_core_trigger_stp_assert() == MTK_WCN_BOOL_TRUE) { + WMT_INFO_FUNC("trigger STP assert succeed\n"); + return 0; + } + WMT_WARN_FUNC("trigger STP assert failed\n"); + return -1; +} + +MTK_WCN_BOOL wmt_core_is_quick_ps_support(VOID) +{ + P_WMT_CTX pctx = &gMtkWmtCtx; + + if ((pctx->p_ic_ops != NULL) && (pctx->p_ic_ops->is_quick_sleep != NULL)) + return (*(pctx->p_ic_ops->is_quick_sleep))(); + return MTK_WCN_BOOL_FALSE; +} + +MTK_WCN_BOOL wmt_core_get_aee_dump_flag(VOID) +{ + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_WMT_CTX pctx = &gMtkWmtCtx; + + if ((pctx->p_ic_ops != NULL) && (pctx->p_ic_ops->is_aee_dump_support != NULL)) + bRet = (*(pctx->p_ic_ops->is_aee_dump_support))(); + else + bRet = MTK_WCN_BOOL_FALSE; + + return bRet; +} + +static INT32 opfunc_bgw_ds(P_WMT_OP pWmtOp) +{ + INT32 iRet = -1; + UINT32 u4WrittenSize = 0; + UINT32 u4ReadSize = 0; + UINT32 buf_len = 0; + UINT8 *buffer = NULL; + UINT8 evt_buffer[8] = { 0 }; + MTK_WCN_BOOL fgFail; + + UINT8 WMT_BGW_DESENSE_CMD[] = { + 0x01, 0x0e, 0x0f, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 + }; + UINT8 WMT_BGW_DESENSE_EVT[] = { 0x02, 0x0e, 0x01, 0x00, 0x00 }; + + buf_len = pWmtOp->au4OpData[0]; + buffer = (PUINT8) pWmtOp->au4OpData[1]; + + osal_memcpy(&WMT_BGW_DESENSE_CMD[5], buffer, buf_len); + + do { + fgFail = MTK_WCN_BOOL_TRUE; + + iRet = + wmt_core_tx(&WMT_BGW_DESENSE_CMD[0], osal_sizeof(WMT_BGW_DESENSE_CMD), &u4WrittenSize, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4WrittenSize != osal_sizeof(WMT_BGW_DESENSE_CMD))) { + WMT_ERR_FUNC("bgw desense tx CMD fail(%d),size(%d)\n", iRet, u4WrittenSize); + break; + } + + iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_BGW_DESENSE_EVT), &u4ReadSize); + if (iRet || (u4ReadSize != osal_sizeof(WMT_BGW_DESENSE_EVT))) { + WMT_ERR_FUNC("bgw desense rx EVT fail(%d),size(%d)\n", iRet, u4ReadSize); + break; + } + + if (osal_memcmp(evt_buffer, WMT_BGW_DESENSE_EVT, osal_sizeof(WMT_BGW_DESENSE_EVT)) != 0) { + WMT_ERR_FUNC + ("bgw desense WMT_BGW_DESENSE_EVT compare fail:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n", + evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3], evt_buffer[4]); + break; + } + + fgFail = MTK_WCN_BOOL_FALSE; + + } while (0); + + return fgFail; +} + +static INT32 wmt_core_gen2_set_mcu_clk(UINT32 kind) +{ + INT32 iRet = -1; + UINT32 u4WrittenSize = 0; + UINT32 u4ReadSize = 0; + UINT8 evt_buffer[12] = { 0 }; + MTK_WCN_BOOL fgFail; + PUINT8 set_mcu_clk_str[] = { + "Enable GEN2 MCU PLL", + "SET GEN2 MCU CLK to 26M", + "SET GEN2 MCU CLK to 37M", + "SET GEN2 MCU CLK to 64M", + "SET GEN2 MCU CLK to 69M", + "SET GEN2 MCU CLK to 104M", + "SET GEN2 MCU CLK to 118.857M", + "SET GEN2 MCU CLK to 138.67M", + "Disable GEN2 MCU PLL" + }; + UINT8 WMT_SET_MCU_CLK_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff + }; + UINT8 WMT_SET_MCU_CLK_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + + UINT8 WMT_EN_MCU_CLK_CMD[] = { 0x34, 0x03, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00 }; /* enable pll clk */ + UINT8 WMT_26_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x00, 0x4d, 0x84, 0x00 }; /* set 26M */ + UINT8 WMT_37_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1e, 0x4d, 0x84, 0x00 }; /* set 37.8M */ + UINT8 WMT_64_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1d, 0x4d, 0x84, 0x00 }; /* set 64M */ + UINT8 WMT_69_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x1c, 0x4d, 0x84, 0x00 }; /* set 69M */ + UINT8 WMT_104_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x5b, 0x4d, 0x84, 0x00 }; /* set 104M */ + UINT8 WMT_108_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x5a, 0x4d, 0x84, 0x00 }; /* set 118.857M */ + UINT8 WMT_138_MCU_CLK_CMD[] = { 0x0c, 0x01, 0x00, 0x80, 0x59, 0x4d, 0x84, 0x00 }; /* set 138.67M */ + UINT8 WMT_DIS_MCU_CLK_CMD[] = { 0x34, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 }; /* disable pll clk */ + + WMT_INFO_FUNC("do %s\n", set_mcu_clk_str[kind]); + + switch (kind) { + case 0: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_EN_MCU_CLK_CMD[0], osal_sizeof(WMT_EN_MCU_CLK_CMD)); + break; + case 1: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_26_MCU_CLK_CMD[0], osal_sizeof(WMT_26_MCU_CLK_CMD)); + break; + case 2: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_37_MCU_CLK_CMD[0], osal_sizeof(WMT_37_MCU_CLK_CMD)); + break; + case 3: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_64_MCU_CLK_CMD[0], osal_sizeof(WMT_64_MCU_CLK_CMD)); + break; + case 4: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_69_MCU_CLK_CMD[0], osal_sizeof(WMT_69_MCU_CLK_CMD)); + break; + case 5: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_104_MCU_CLK_CMD[0], osal_sizeof(WMT_104_MCU_CLK_CMD)); + break; + case 6: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_108_MCU_CLK_CMD[0], osal_sizeof(WMT_108_MCU_CLK_CMD)); + break; + case 7: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_138_MCU_CLK_CMD[0], osal_sizeof(WMT_138_MCU_CLK_CMD)); + break; + case 8: + osal_memcpy(&WMT_SET_MCU_CLK_CMD[8], &WMT_DIS_MCU_CLK_CMD[0], osal_sizeof(WMT_DIS_MCU_CLK_CMD)); + break; + default: + WMT_ERR_FUNC("unknown kind\n"); + break; + } + + do { + fgFail = MTK_WCN_BOOL_TRUE; + + iRet = + wmt_core_tx(&WMT_SET_MCU_CLK_CMD[0], osal_sizeof(WMT_SET_MCU_CLK_CMD), &u4WrittenSize, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4WrittenSize != osal_sizeof(WMT_SET_MCU_CLK_CMD))) { + WMT_ERR_FUNC("WMT_SET_MCU_CLK_CMD fail(%d),size(%d)\n", iRet, u4WrittenSize); + break; + } + + iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_SET_MCU_CLK_EVT), &u4ReadSize); + if (iRet || (u4ReadSize != osal_sizeof(WMT_SET_MCU_CLK_EVT))) { + WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT fail(%d),size(%d)\n", iRet, u4ReadSize); + mtk_wcn_stp_dbg_dump_package(); + break; + } + + if (osal_memcmp(evt_buffer, WMT_SET_MCU_CLK_EVT, osal_sizeof(WMT_SET_MCU_CLK_EVT)) != 0) { + WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail, [0-3]:0x%02x,0x%02x,0x%02x,0x%02x\n", + evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3]); + WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail, [4-7]:0x%02x,0x%02x,0x%02x,0x%02x\n", + evt_buffer[4], evt_buffer[5], evt_buffer[6], evt_buffer[7]); + break; + } + + fgFail = MTK_WCN_BOOL_FALSE; + + } while (0); + + if (fgFail == MTK_WCN_BOOL_FALSE) + WMT_INFO_FUNC("wmt-core:%s: ok!\n", set_mcu_clk_str[kind]); + else + WMT_INFO_FUNC("wmt-core:%s: fail!\n", set_mcu_clk_str[kind]); + + return fgFail; +} + +static INT32 wmt_core_gen3_set_mcu_clk(UINT32 kind) +{ + INT32 iRet = -1; + UINT32 u4WrittenSize = 0; + UINT32 u4ReadSize = 0; + UINT8 evt_buffer[12] = { 0 }; + MTK_WCN_BOOL fgFail; + PUINT8 set_mcu_clk_str[] = { + "SET GEN3 MCU CLK to 26M", + "SET GEN3 MCU CLK to 46M", + "SET GEN3 MCU CLK to 97M", + "SET GEN3 MCU CLK to 104M", + "SET GEN3 MCU CLK to 184M", + "SET GEN3 MCU CLK to 208M", + }; + UINT8 set_mcu_clk_vel[] = { + 0x1a, /* set 26M*/ + 0x2e, /* set 46M*/ + 0x61, /* set 97M*/ + 0x68, /* set 104M */ + 0xb8, /* set 184M */ + 0xd0, /* set 208M */ + }; + UINT8 WMT_SET_MCU_CLK_CMD[] = { 0x01, 0x0a, 0x04, 0x00, 0x09, 0x03, 0x00, 0x00 }; + UINT8 WMT_SET_MCU_CLK_EVT[] = { 0x02, 0x0a, 0x01, 0x00, 0x00 }; + + + if (kind < osal_sizeof(set_mcu_clk_vel)) { + WMT_INFO_FUNC("do %s\n", set_mcu_clk_str[kind]); + WMT_SET_MCU_CLK_CMD[6] = set_mcu_clk_vel[kind]; + } else { + WMT_ERR_FUNC("unknown kind(%d)!\n", kind); + return MTK_WCN_BOOL_TRUE; + } + + do { + fgFail = MTK_WCN_BOOL_TRUE; + + iRet = wmt_core_tx(&WMT_SET_MCU_CLK_CMD[0], osal_sizeof(WMT_SET_MCU_CLK_CMD), &u4WrittenSize, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4WrittenSize != osal_sizeof(WMT_SET_MCU_CLK_CMD))) { + WMT_ERR_FUNC("WMT_SET_MCU_CLK_CMD fail(%d),size(%d)\n", iRet, u4WrittenSize); + break; + } + + iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_SET_MCU_CLK_EVT), &u4ReadSize); + if (iRet || (u4ReadSize != osal_sizeof(WMT_SET_MCU_CLK_EVT))) { + WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT fail(%d),size(%d)\n", iRet, u4ReadSize); + mtk_wcn_stp_dbg_dump_package(); + break; + } + + if (osal_memcmp(evt_buffer, WMT_SET_MCU_CLK_EVT, osal_sizeof(WMT_SET_MCU_CLK_EVT)) != 0) { + WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail, [0-3]:0x%02x,0x%02x,0x%02x,0x%02x\n", + evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3]); + WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail, [4-7]:0x%02x,0x%02x,0x%02x,0x%02x\n", + evt_buffer[4], evt_buffer[5], evt_buffer[6], evt_buffer[7]); + break; + } + + fgFail = MTK_WCN_BOOL_FALSE; + + } while (0); + + if (fgFail == MTK_WCN_BOOL_FALSE) + WMT_INFO_FUNC("wmt-core:%s: ok!\n", set_mcu_clk_str[kind]); + else + WMT_INFO_FUNC("wmt-core:%s: fail!\n", set_mcu_clk_str[kind]); + + return fgFail; +} + +static INT32 wmt_core_set_mcu_clk(UINT32 kind) +{ + INT32 iRet = -1; + UINT32 u4WrittenSize = 0; + UINT32 u4ReadSize = 0; + UINT8 evt_buffer[12] = { 0 }; + MTK_WCN_BOOL fgFail; + + UINT8 WMT_SET_MCU_CLK_CMD[] = { 0x01, 0x0a, 0x04, 0x00, 0x09, 0x01, 0x00, 0x00 }; + UINT8 WMT_SET_MCU_CLK_EVT[] = { 0x02, 0x0a, 0x01, 0x00, 0x00 }; + + + WMT_INFO_FUNC("clock frequency 0x%x\n", kind); + WMT_SET_MCU_CLK_CMD[6] = (kind & 0xff); + + do { + fgFail = MTK_WCN_BOOL_TRUE; + + iRet = wmt_core_tx(&WMT_SET_MCU_CLK_CMD[0], osal_sizeof(WMT_SET_MCU_CLK_CMD), &u4WrittenSize, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4WrittenSize != osal_sizeof(WMT_SET_MCU_CLK_CMD))) { + WMT_ERR_FUNC("WMT_SET_MCU_CLK_CMD fail(%d),size(%d)\n", iRet, u4WrittenSize); + break; + } + + iRet = wmt_core_rx(evt_buffer, osal_sizeof(WMT_SET_MCU_CLK_EVT), &u4ReadSize); + if (iRet || (u4ReadSize != osal_sizeof(WMT_SET_MCU_CLK_EVT))) { + WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT fail(%d),size(%d)\n", iRet, u4ReadSize); + mtk_wcn_stp_dbg_dump_package(); + break; + } + + if (osal_memcmp(evt_buffer, WMT_SET_MCU_CLK_EVT, osal_sizeof(WMT_SET_MCU_CLK_EVT)) != 0) { + WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail, [0-3]:0x%02x,0x%02x,0x%02x,0x%02x\n", + evt_buffer[0], evt_buffer[1], evt_buffer[2], evt_buffer[3]); + WMT_ERR_FUNC("WMT_SET_MCU_CLK_EVT compare fail, [4-7]:0x%02x,0x%02x,0x%02x,0x%02x\n", + evt_buffer[4], evt_buffer[5], evt_buffer[6], evt_buffer[7]); + break; + } + + fgFail = MTK_WCN_BOOL_FALSE; + + } while (0); + + if (fgFail == MTK_WCN_BOOL_FALSE) + WMT_INFO_FUNC("wmt-core:set mcu clock ok!\n"); + else + WMT_INFO_FUNC("wmt-core:set mcu clock fail!\n"); + + return fgFail; +} + +static INT32 opfunc_set_mcu_clk(P_WMT_OP pWmtOp) +{ + UINT32 kind = 0; + UINT32 version = 0; + MTK_WCN_BOOL ret; + + kind = pWmtOp->au4OpData[0]; + version = pWmtOp->au4OpData[1]; + + switch (version) { + case 0: + ret = wmt_core_gen2_set_mcu_clk(kind); + break; + case 1: + ret = wmt_core_gen3_set_mcu_clk(kind); + break; + case 2: + ret = wmt_core_set_mcu_clk(kind); + break; + default: + WMT_ERR_FUNC("wmt-core: version(%d) is not support!\n", version); + ret = MTK_WCN_BOOL_TRUE; + } + + return ret; +} + +static INT32 opfunc_adie_lpbk_test(P_WMT_OP pWmtOp) +{ + UINT8 *buffer = NULL; + MTK_WCN_BOOL fgFail; + UINT32 u4Res; + UINT32 aDieChipid = 0; + UINT8 soc_adie_chipid_cmd[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x24, 0x00 }; + UINT8 soc_adie_chipid_evt[] = { 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00 }; + UINT8 evtbuf[20]; + INT32 iRet = -1; + + buffer = (PUINT8) pWmtOp->au4OpData[1]; + + do { + fgFail = MTK_WCN_BOOL_TRUE; + + /* read A die chipid by wmt cmd */ + iRet = + wmt_core_tx((PUINT8) &soc_adie_chipid_cmd[0], osal_sizeof(soc_adie_chipid_cmd), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != osal_sizeof(soc_adie_chipid_cmd))) { + WMT_ERR_FUNC("wmt_core:read A die chipid CMD fail(%d),size(%d)\n", iRet, u4Res); + break; + } + osal_memset(evtbuf, 0, osal_sizeof(evtbuf)); + iRet = wmt_core_rx(evtbuf, osal_sizeof(soc_adie_chipid_evt), &u4Res); + if (iRet || (u4Res != osal_sizeof(soc_adie_chipid_evt))) { + WMT_ERR_FUNC("wmt_core:read A die chipid EVT fail(%d),size(%d)\n", iRet, u4Res); + break; + } + osal_memcpy(&aDieChipid, &evtbuf[u4Res - 2], 2); + osal_memcpy(buffer, &evtbuf[u4Res - 2], 2); + pWmtOp->au4OpData[0] = 2; + WMT_INFO_FUNC("get SOC A die chipid(0x%x)\n", aDieChipid); + + fgFail = MTK_WCN_BOOL_FALSE; + + } while (0); + + return fgFail; +} + +MTK_WCN_BOOL wmt_core_trigger_stp_assert(VOID) +{ + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_WMT_CTX pctx = &gMtkWmtCtx; + + if (mtk_wcn_stp_coredump_flag_get() == 0) { + WMT_INFO_FUNC("coredump is disabled, omit trigger STP assert\n"); + wmt_lib_trigger_reset(); + return MTK_WCN_BOOL_FALSE; + } + + if ((pctx->p_ic_ops != NULL) && (pctx->p_ic_ops->trigger_stp_assert != NULL)) { + WMT_INFO_FUNC("trigger stp assert function is supported by 0x%X\n", + pctx->p_ic_ops->icId); + bRet = (*(pctx->p_ic_ops->trigger_stp_assert)) (); + } else { + if (pctx->p_ic_ops != NULL) + WMT_INFO_FUNC("trigger stp assert function is not supported by 0x%X\n", + pctx->p_ic_ops->icId); + bRet = MTK_WCN_BOOL_FALSE; + } + + return bRet; +} +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +MTK_WCN_BOOL wmt_core_deep_sleep_ctrl(INT32 value) +{ + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_WMT_CTX pctx = &gMtkWmtCtx; + + if ((pctx->p_ic_ops != NULL) && (pctx->p_ic_ops->deep_sleep_ctrl != NULL)) { + bRet = (*(pctx->p_ic_ops->deep_sleep_ctrl)) (value); + } else { + if (pctx->p_ic_ops != NULL) + WMT_INFO_FUNC("deep sleep function is not supported by 0x%x\n", + pctx->p_ic_ops->icId); + bRet = MTK_WCN_BOOL_FALSE; + } + return bRet; +} +#endif +INT32 opfunc_pin_state(P_WMT_OP pWmtOp) +{ + ULONG ctrlPa1 = 0; + ULONG ctrlPa2 = 0; + INT32 iRet = 0; + + iRet = wmt_core_ctrl(WMT_CTRL_HW_STATE_DUMP, &ctrlPa1, &ctrlPa2); + return iRet; +} + +#ifdef CONFIG_MTK_COMBO_ANT +INT32 opfunc_ant_ram_down(P_WMT_OP pWmtOp) +{ + INT32 iRet = 0; + size_t ctrlPa1 = pWmtOp->au4OpData[0]; + UINT32 ctrlPa2 = pWmtOp->au4OpData[1]; + PUINT8 pbuf = (PUINT8) ctrlPa1; + UINT32 fragSeq = 0; + UINT16 fragSize = 0; + UINT16 wmtCmdLen; + UINT16 wmtPktLen; + UINT32 u4Res = 0; + UINT8 antEvtBuf[osal_sizeof(WMT_ANT_RAM_DWN_EVT)]; +#if 1 + UINT32 ctrlPa3 = pWmtOp->au4OpData[2]; + + do { + fragSize = ctrlPa2; + fragSeq = ctrlPa3; + gAntBuf[5] = fragSeq; + + + wmtPktLen = fragSize + sizeof(WMT_ANT_RAM_DWN_CMD) + 1; + + /*WMT command length cal */ + wmtCmdLen = wmtPktLen - 4; +#if 0 + WMT_ANT_RAM_DWN_CMD[2] = wmtCmdLen & 0xFF; + WMT_ANT_RAM_DWN_CMD[3] = (wmtCmdLen & 0xFF00) >> 16; +#else + osal_memcpy(&WMT_ANT_RAM_DWN_CMD[2], &wmtCmdLen, 2); +#endif + + + + WMT_ANT_RAM_DWN_CMD[4] = 1; /*RAM CODE download */ + + osal_memcpy(gAntBuf, WMT_ANT_RAM_DWN_CMD, sizeof(WMT_ANT_RAM_DWN_CMD)); + + /*copy ram code content to global buffer */ + osal_memcpy(&gAntBuf[osal_sizeof(WMT_ANT_RAM_DWN_CMD) + 1], pbuf, fragSize); + + iRet = wmt_core_tx(gAntBuf, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != wmtPktLen)) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, + wmtPktLen, u4Res, iRet); + iRet = -4; + break; + } + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", + fragSeq, wmtPktLen, u4Res); + + osal_memset(antEvtBuf, 0, sizeof(antEvtBuf)); + + WMT_ANT_RAM_DWN_EVT[4] = 0; /*download result; 0 */ + + iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_ANT_RAM_DWN_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_ANT_RAM_DWN_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_ANT_RAM_DWN_EVT length(%zu, %d) fail(%d)\n", + sizeof(WMT_ANT_RAM_DWN_EVT), u4Res, iRet); + iRet = -5; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(antEvtBuf, WMT_ANT_RAM_DWN_EVT, sizeof(WMT_ANT_RAM_DWN_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_ANT_RAM_DWN_EVT result error\n"); + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3], + antEvtBuf[4], sizeof(WMT_ANT_RAM_DWN_EVT), WMT_ANT_RAM_DWN_EVT[0], + WMT_ANT_RAM_DWN_EVT[1], WMT_ANT_RAM_DWN_EVT[2], WMT_ANT_RAM_DWN_EVT[3], + WMT_ANT_RAM_DWN_EVT[4]); + iRet = -6; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_ANT_RAM_DWN_EVT length(%zu, %d) ok\n", + sizeof(WMT_ANT_RAM_DWN_EVT), u4Res); + + } while (0); +#else + UINT32 patchSize = ctrlPa2; + UINT32 patchSizePerFrag = 1000; + UINT32 offset; + UINT32 fragNum = 0; + /*cal patch fragNum */ + fragNum = (patchSize + patchSizePerFrag - 1) / patchSizePerFrag; + if (fragNum <= 2) { + WMT_WARN_FUNC("ANT ramcode size(%d) too short\n", patchSize); + return -1; + } + + while (fragSeq < fragNum) { + /*update fragNum */ + fragSeq++; + + if (fragSeq == 1) { + fragSize = patchSizePerFrag; + /*first package */ + gAntBuf[5] = 1; /*RAM CODE start */ + } else if (fragNum == fragSeq) { + /*last package */ + fragSize = patchSizePerFrag; + gAntBuf[5] = 3; /*RAM CODE end */ + } else { + /*middle package */ + fragSize = patchSize - ((fragNum - 1) * patchSizePerFrag); + gAntBuf[5] = 2; /*RAM CODE confinue */ + } + wmtPktLen = fragSize + sizeof(WMT_ANT_RAM_OP_CMD) + 1; + + /*WMT command length cal */ + wmtCmdLen = wmtPktLen - 4; + + WMT_ANT_RAM_OP_CMD[2] = wmtCmdLen & 0xFF; + WMT_ANT_RAM_OP_CMD[3] = (wmtCmdLen & 0xFF00) >> 16; + + WMT_ANT_RAM_OP_CMD[4] = 1; /*RAM CODE download */ + + osal_memcpy(gAntBuf, WMT_ANT_RAM_OP_CMD, sizeof(WMT_ANT_RAM_OP_CMD)); + + /*copy ram code content to global buffer */ + osal_memcpy(&gAntBuf[6], pbuf, fragSize); + + /*update offset */ + offset += fragSize; + pbuf += offset; + + iRet = wmt_core_tx(gAntBuf, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != wmtPktLen)) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, + wmtPktLen, u4Res, iRet); + iRet = -4; + break; + } + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", + fragSeq, wmtPktLen, u4Res); + + osal_memset(antEvtBuf, 0, sizeof(antEvtBuf)); + + WMT_SET_RAM_OP_EVT[4] = 0; /*download result; 0 */ + + iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_SET_RAM_OP_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_SET_RAM_OP_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_SET_RAM_OP_EVT length(%d, %d) fail(%d)\n", + sizeof(WMT_SET_RAM_OP_EVT), u4Res, iRet); + iRet = -5; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(antEvtBuf, WMT_SET_RAM_OP_EVT, sizeof(WMT_SET_RAM_OP_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_SET_RAM_OP_EVT result error\n"); + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3], + antEvtBuf[4], sizeof(WMT_SET_RAM_OP_EVT), WMT_SET_RAM_OP_EVT[0], + WMT_SET_RAM_OP_EVT[1], WMT_SET_RAM_OP_EVT[2], WMT_SET_RAM_OP_EVT[3], + WMT_SET_RAM_OP_EVT[4]); + iRet = -6; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_SET_RAM_OP_EVT length(%d, %d) ok\n", + sizeof(WMT_SET_RAM_OP_EVT), u4Res); + + + } + if (fragSeq != fragNum) + iRet = -7; +#endif + return iRet; +} + + +INT32 opfunc_ant_ram_stat_get(P_WMT_OP pWmtOp) +{ + INT32 iRet = 0; + UINT32 u4Res = 0; + UINT32 wmtPktLen = osal_sizeof(WMT_ANT_RAM_STA_GET_CMD); + UINT32 u4AntRamStatus = 0; + UINT8 antEvtBuf[osal_sizeof(WMT_ANT_RAM_STA_GET_EVT)]; + + + iRet = wmt_core_tx(WMT_ANT_RAM_STA_GET_CMD, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != wmtPktLen)) { + WMT_ERR_FUNC + ("wmt_core: write wmt and ramcode status query command failed, (%d, %d), iRet(%d)\n", + wmtPktLen, u4Res, iRet); + iRet = -4; + return iRet; + } + + + iRet = wmt_core_rx(antEvtBuf, sizeof(WMT_ANT_RAM_STA_GET_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_ANT_RAM_STA_GET_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_ANT_RAM_STA_GET_EVT length(%zu, %d) fail(%d)\n", + sizeof(WMT_ANT_RAM_STA_GET_EVT), u4Res, iRet); + iRet = -5; + return iRet; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(antEvtBuf, WMT_ANT_RAM_STA_GET_EVT, sizeof(WMT_ANT_RAM_STA_GET_EVT) - 1) != + 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_ANT_RAM_STA_GET_EVT result error\n"); + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, antEvtBuf[0], antEvtBuf[1], antEvtBuf[2], antEvtBuf[3], antEvtBuf[4], + sizeof(WMT_ANT_RAM_STA_GET_EVT), WMT_ANT_RAM_STA_GET_EVT[0], + WMT_ANT_RAM_STA_GET_EVT[1], WMT_ANT_RAM_STA_GET_EVT[2], + WMT_ANT_RAM_STA_GET_EVT[3], WMT_ANT_RAM_STA_GET_EVT[4]); + iRet = -6; + return iRet; + } +#endif + if (iRet == 0) { + u4AntRamStatus = antEvtBuf[sizeof(WMT_ANT_RAM_STA_GET_EVT) - 1]; + pWmtOp->au4OpData[2] = u4AntRamStatus; + WMT_INFO_FUNC("ANT ram code %s\n", + u4AntRamStatus == 1 ? "exist already" : "not exist"); + } + return iRet; +} +#endif +VOID wmt_core_set_coredump_state(ENUM_DRV_STS state) +{ + WMT_INFO_FUNC("wmt-core: set coredump state(%d)\n", state); + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP] = state; +} + +INT32 opfunc_flash_patch_down(P_WMT_OP pWmtOp) +{ + INT32 iRet = 0; + PUINT8 u4pbuf = (PUINT8)pWmtOp->au4OpData[0]; + UINT16 u4PatchSize = pWmtOp->au4OpData[1]; + UINT32 u4PatchSeq = pWmtOp->au4OpData[2]; + UINT32 u4PatchType = pWmtOp->au4OpData[3]; + UINT32 u4PatchVersion = pWmtOp->au4OpData[4]; + UINT32 u4PatchChecksum = pWmtOp->au4OpData[5]; + UINT16 wmtCmdLen; + UINT16 wmtPktLen = 0; + UINT32 u4Res = 0; + UINT8 evtBuf[osal_sizeof(WMT_FLASH_PATCH_DWN_EVT)]; + UINT32 i = 0; + + do { + osal_memcpy(gFlashBuf, WMT_FLASH_PATCH_DWN_CMD, sizeof(WMT_FLASH_PATCH_DWN_CMD)); + + switch (u4PatchSeq) { + case WMT_FLASH_PATCH_HEAD_PKT: + /*WMT command length cal */ + wmtPktLen = sizeof(WMT_FLASH_PATCH_DWN_CMD) + WMT_FLASH_PATCH_DWN_CMD[2] - 1; + osal_memcpy(&gFlashBuf[5], &u4PatchType, sizeof(u4PatchType)); + osal_memcpy(&gFlashBuf[9], &u4PatchVersion, sizeof(u4PatchVersion)); + osal_memcpy(&gFlashBuf[13], &u4PatchChecksum, sizeof(u4PatchChecksum)); + break; + case WMT_FLASH_PATCH_START_PKT: + case WMT_FLASH_PATCH_CONTINUE_PKT: + case WMT_FLASH_PATCH_END_PKT: + gFlashBuf[4] = u4PatchSeq; + /*WMT command length cal */ + wmtCmdLen = u4PatchSize + 1; + wmtPktLen = u4PatchSize + sizeof(WMT_FLASH_PATCH_DWN_CMD); + gFlashBuf[2] = wmtCmdLen & 0xFF; + gFlashBuf[3] = (wmtCmdLen & 0xFF00) >> 8; + /*copy ram code content to global buffer */ + osal_memcpy(&gFlashBuf[osal_sizeof(WMT_FLASH_PATCH_DWN_CMD)], u4pbuf, u4PatchSize); + break; + default: + break; + } + + iRet = wmt_core_tx(gFlashBuf, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != wmtPktLen)) { + WMT_ERR_FUNC("wmt_core: write PatchSeq(%d) size(%d, %d) fail(%d)\n", u4PatchSeq, + wmtPktLen, u4Res, iRet); + iRet = -4; + u4Res = -1; + break; + } + WMT_DBG_FUNC("wmt_core: write PatchSeq(%d) size(%d, %d) ok\n", + u4PatchSeq, wmtPktLen, u4Res); + + osal_memset(evtBuf, 0, sizeof(evtBuf)); + + /* flash patch download time longer than WMT command timeout */ + for (i = 0; i < 3; i++) { + iRet = wmt_core_rx(evtBuf, sizeof(WMT_FLASH_PATCH_DWN_EVT), &u4Res); + if (!iRet) + break; + } + if (iRet || (u4Res != sizeof(WMT_FLASH_PATCH_DWN_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_FLASH_PATCH_DWN_EVT length(%zu, %d) fail(%d)\n", + sizeof(WMT_FLASH_PATCH_DWN_EVT), u4Res, iRet); + wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 39); + + iRet = -5; + u4Res = -2; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(evtBuf, WMT_FLASH_PATCH_DWN_EVT, sizeof(WMT_FLASH_PATCH_DWN_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_FLASH_PATCH_DWN_EVT result error\n"); + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + sizeof(WMT_FLASH_PATCH_DWN_EVT), WMT_FLASH_PATCH_DWN_EVT[0], + WMT_FLASH_PATCH_DWN_EVT[1], WMT_FLASH_PATCH_DWN_EVT[2], + WMT_FLASH_PATCH_DWN_EVT[3], WMT_FLASH_PATCH_DWN_EVT[4]); + iRet = -6; + u4Res = -3; + break; + } +#endif + u4Res = 0; + WMT_DBG_FUNC("wmt_core: read WMT_FLASH_PATCH_DWN_EVT length(%zu, %d) ok\n", + sizeof(WMT_FLASH_PATCH_DWN_EVT), u4Res); + + } while (0); + + pWmtOp->au4OpData[6] = u4Res; + return iRet; +} + +INT32 opfunc_flash_patch_ver_get(P_WMT_OP pWmtOp) +{ + INT32 iRet = 0; + UINT32 u4Res = 0; + UINT32 wmtPktLen = osal_sizeof(WMT_FLASH_PATCH_VER_GET_CMD); + UINT32 u4PatchType = pWmtOp->au4OpData[3]; + UINT32 u4PatchVer = 0; + UINT8 evtBuf[osal_sizeof(WMT_FLASH_PATCH_VER_GET_EVT)]; + + do { + osal_memcpy(&WMT_FLASH_PATCH_VER_GET_CMD[5], &u4PatchType, sizeof(u4PatchType)); + + iRet = wmt_core_tx(WMT_FLASH_PATCH_VER_GET_CMD, wmtPktLen, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != wmtPktLen)) { + WMT_ERR_FUNC + ("wmt_core: write wmt and flash patch query command failed, (%d, %d), iRet(%d)\n", + wmtPktLen, u4Res, iRet); + iRet = -4; + u4Res = -1; + break; + } + + iRet = wmt_core_rx(evtBuf, sizeof(WMT_FLASH_PATCH_VER_GET_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_FLASH_PATCH_VER_GET_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_FLASH_PATCH_VER_GET_EVT length(%zu, %d) fail(%d)\n", + sizeof(WMT_FLASH_PATCH_VER_GET_EVT), u4Res, iRet); + wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 38); + + iRet = -5; + u4Res = -2; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(evtBuf, WMT_FLASH_PATCH_VER_GET_EVT, + sizeof(WMT_FLASH_PATCH_VER_GET_EVT) - 8) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_FLASH_PATCH_VER_GET_EVT result error\n"); + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + sizeof(WMT_FLASH_PATCH_VER_GET_EVT), WMT_FLASH_PATCH_VER_GET_EVT[0], + WMT_FLASH_PATCH_VER_GET_EVT[1], WMT_FLASH_PATCH_VER_GET_EVT[2], + WMT_FLASH_PATCH_VER_GET_EVT[3], WMT_FLASH_PATCH_VER_GET_EVT[4]); + iRet = -6; + u4Res = -3; + break; + } +#endif + if (iRet == 0) { + osal_memcpy(&u4PatchVer, &evtBuf[9], sizeof(u4PatchVer)); + pWmtOp->au4OpData[4] = u4PatchVer; + u4Res = 0; + WMT_INFO_FUNC("flash patch type: %x, flash patch version %x\n", + u4PatchType, u4PatchVer); + } + } while (0); + + pWmtOp->au4OpData[6] = u4Res; + return iRet; +} + +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 opfunc_idc_msg_handling(P_WMT_OP pWmtOp) +{ + MTK_WCN_BOOL fgFail; + UINT32 u4Res; + UINT8 host_lte_btwf_coex_cmd[] = { 0x01, 0x10, 0x00, 0x00, 0x00 }; + UINT8 host_lte_btwf_coex_evt[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + UINT8 *pTxBuf = NULL; + UINT8 evtbuf[8] = { 0 }; + INT32 iRet = -1; + UINT16 msg_len = 0; + UINT32 total_len = 0; + UINT32 index = 0; + UINT32 evtLen; + + pTxBuf = (UINT8 *) pWmtOp->au4OpData[0]; + if (pTxBuf == NULL) { + WMT_ERR_FUNC("idc msg buffer is NULL\n"); + return -1; + } + iRet = wmt_lib_idc_lock_aquire(); + if (iRet) { + WMT_ERR_FUNC("--->lock idc_lock failed, ret=%d\n", iRet); + return iRet; + } + osal_memcpy(&msg_len, &pTxBuf[0], osal_sizeof(msg_len)); + if (msg_len > WMT_IDC_MSG_MAX_SIZE) { + wmt_lib_idc_lock_release(); + WMT_ERR_FUNC("abnormal idc msg len:%d\n", msg_len); + return -2; + } + msg_len += 1; /*flag byte */ + osal_memcpy(&host_lte_btwf_coex_cmd[2], &msg_len, 2); + host_lte_btwf_coex_cmd[4] = (pWmtOp->au4OpData[1] & 0x00ff); + osal_memcpy(&msg_local_buffer[0], &host_lte_btwf_coex_cmd[0], + osal_sizeof(host_lte_btwf_coex_cmd)); + osal_memcpy(&msg_local_buffer[osal_sizeof(host_lte_btwf_coex_cmd)], + &pTxBuf[osal_sizeof(msg_len)], msg_len - 1); + wmt_lib_idc_lock_release(); + total_len = osal_sizeof(host_lte_btwf_coex_cmd) + msg_len - 1; + WMT_DBG_FUNC("wmt_core:idc msg payload len form lte(%d),wmt msg total len(%d)\n", + msg_len - 1, total_len); + WMT_DBG_FUNC("wmt_core:idc msg payload:\n"); + for (index = 0; index < total_len; index++) + WMT_DBG_FUNC("0x%02x ", msg_local_buffer[index]); + do { + fgFail = MTK_WCN_BOOL_TRUE; + + /* read A die chipid by wmt cmd */ + iRet = + wmt_core_tx((PUINT8) &msg_local_buffer[0], total_len, &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != total_len)) { + WMT_ERR_FUNC("wmt_core:send lte idc msg to connsys fail(%d),size(%d)\n", + iRet, u4Res); + break; + } + osal_memset(evtbuf, 0, osal_sizeof(evtbuf)); + evtLen = osal_sizeof(host_lte_btwf_coex_evt); + iRet = wmt_core_rx(evtbuf, evtLen, &u4Res); + if (iRet || (u4Res != evtLen)) { + WMT_ERR_FUNC("wmt_core:recv host_lte_btwf_coex_evt fail(%d) len(%d, %d)\n", + iRet, u4Res, evtLen); + wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 41); + break; + } + + fgFail = MTK_WCN_BOOL_FALSE; + + } while (0); + + return fgFail; +} + +/*TEST CODE*/ +VOID wmt_core_set_flag_for_test(UINT32 enable) +{ + WMT_INFO_FUNC("%s wmt_lte_flag\n", enable ? "enable" : "disable"); + g_open_wmt_lte_flag = enable; +} + +UINT32 wmt_core_get_flag_for_test(VOID) +{ + return g_open_wmt_lte_flag; +} + +#endif + +static INT32 opfunc_utc_time_sync(P_WMT_OP pWmtOp) +{ +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + INT32 iRet; + UINT32 u4Res; + UINT32 evtLen; + UINT8 evtBuf[16] = { 0 }; + UINT32 tsec; + UINT32 tusec; + + connsys_dedicated_log_get_utc_time(&tsec, &tusec); + /* UTC time second unit */ + osal_memcpy(&WMT_UTC_SYNC_CMD[5], &tsec, 4); + /* UTC time microsecond unit */ + osal_memcpy(&WMT_UTC_SYNC_CMD[9], &tusec, 4); + + /* send command */ + iRet = wmt_core_tx(WMT_UTC_SYNC_CMD, sizeof(WMT_UTC_SYNC_CMD), + &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet) { + WMT_ERR_FUNC("Tx WMT_UTC_SYNC_CMD fail!(%d) len (%d, %zu)\n", + iRet, u4Res, sizeof(WMT_UTC_SYNC_CMD)); + return -1; + } + + /* receive event */ + evtLen = osal_sizeof(WMT_UTC_SYNC_EVT); + iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); + if (iRet || (u4Res != evtLen)) { + WMT_ERR_FUNC("WMT-CORE: read WMT_UTC_SYNC_EVT fail(%d) len(%d, %d)\n", + iRet, u4Res, evtLen); + osal_assert(0); + return iRet; + } + + if (osal_memcmp(evtBuf, WMT_UTC_SYNC_EVT, + osal_sizeof(WMT_UTC_SYNC_EVT)) != 0) { + WMT_ERR_FUNC("WMT-CORE: compare WMT_UTC_SYNC_EVT error\n"); + WMT_ERR_FUNC("WMT-CORE: rx(%d):[%02X,%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], evtBuf[5]); + WMT_ERR_FUNC("WMT-CORE: exp(%zu):[%02X,%02X,%02X,%02X,%02X,%02X]\n", + osal_sizeof(WMT_UTC_SYNC_EVT), WMT_UTC_SYNC_EVT[0], + WMT_UTC_SYNC_EVT[1], WMT_UTC_SYNC_EVT[2], WMT_UTC_SYNC_EVT[3], + WMT_UTC_SYNC_EVT[4], WMT_UTC_SYNC_EVT[5]); + } else { + WMT_INFO_FUNC("Send WMT_UTC_SYNC_CMD command OK!\n"); + } + return 0; +#else + return -1; +#endif +} + +static INT32 opfunc_fw_log_ctrl(P_WMT_OP pWmtOp) +{ + INT32 iRet; + UINT32 u4Res; + UINT32 evtLen; + UINT8 evtBuf[osal_sizeof(WMT_FW_LOG_CTRL_EVT)]; + + /* fill command parameters */ + WMT_FW_LOG_CTRL_CMD[5] = (UINT8)pWmtOp->au4OpData[0]; /* type */ + WMT_FW_LOG_CTRL_CMD[6] = (UINT8)pWmtOp->au4OpData[1]; /* on/off */ + WMT_FW_LOG_CTRL_CMD[7] = (UINT8)pWmtOp->au4OpData[2]; /* log level */ + + /* send command */ + iRet = wmt_core_tx(WMT_FW_LOG_CTRL_CMD, sizeof(WMT_FW_LOG_CTRL_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet) { + WMT_ERR_FUNC("Tx WMT_FW_LOG_CTRL_CMD fail!(%d) len (%d, %zu)\n", iRet, u4Res, + sizeof(WMT_FW_LOG_CTRL_CMD)); + return -1; + } + + /* receive event */ + evtLen = osal_sizeof(WMT_FW_LOG_CTRL_EVT); + iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); + if (iRet || (u4Res != evtLen)) { + WMT_ERR_FUNC("WMT-CORE: read WMT_FW_LOG_CTRL_EVT fail(%d) len(%d, %d)\n", iRet, u4Res, evtLen); + osal_assert(0); + return iRet; + } + + if (osal_memcmp(evtBuf, WMT_FW_LOG_CTRL_EVT, evtLen) != 0) { + WMT_ERR_FUNC("WMT-CORE: compare WMT_FW_LOG_CTRL_EVT error\n"); + WMT_ERR_FUNC("WMT-CORE: tx(%zu):[%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x]\n", + osal_sizeof(WMT_FW_LOG_CTRL_CMD), WMT_FW_LOG_CTRL_CMD[0], WMT_FW_LOG_CTRL_CMD[1], + WMT_FW_LOG_CTRL_CMD[2], WMT_FW_LOG_CTRL_CMD[3], WMT_FW_LOG_CTRL_CMD[4], + WMT_FW_LOG_CTRL_CMD[5], WMT_FW_LOG_CTRL_CMD[6], WMT_FW_LOG_CTRL_CMD[7]); + WMT_ERR_FUNC("WMT-CORE: rx(%u):[%02x,%02x,%02x,%02x,%02x]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4]); + } else { + WMT_INFO_FUNC("Send WMT_FW_LOG_CTRL_EVT command OK!\n"); + } + return 0; +} + +static INT32 opfunc_wlan_probe(P_WMT_OP pWmtOp) +{ + ULONG ctrlPa1; + ULONG ctrlPa2; + INT32 iRet; + UINT32 drvType = pWmtOp->au4OpData[0]; + + + iRet = wmt_lib_wlan_lock_aquire(); + atomic_set(&g_wifi_on_off_ready, 0); + if (iRet) { + WMT_ERR_FUNC("--->lock wlan_lock failed, iRet=%d\n", iRet); + return iRet; + } + + if (gMtkWmtCtx.eDrvStatus[drvType] == DRV_STS_FUNC_ON) { + WMT_WARN_FUNC("func(%d) already on\n", drvType); + iRet = 0; + wmt_lib_wlan_lock_release(); + goto done; + } + + if (gMtkWmtCtx.wmtHifConf.hifType == WMT_HIF_UART) { + ctrlPa1 = WMT_SDIO_SLOT_SDIO1; + ctrlPa2 = 1; /* turn on SDIO1 slot */ + iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("turn on SLOT_SDIO1 fail (%d)\n", + iRet); + osal_assert(0); + } else { + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO1] = + DRV_STS_FUNC_ON; + } + } else if (gMtkWmtCtx.wmtHifConf.hifType == WMT_HIF_SDIO) { + if (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO2] == DRV_STS_FUNC_ON) { + WMT_DBG_FUNC("SLOT_SDIO2 ready for WIFI\n"); + } else { + /* SDIO2 slot power shall be either turned on in STP init + * procedures already, or failed in STP init before. Here is + * the assert condition. + **/ + WMT_ERR_FUNC("turn on Wi-Fi SDIO2 but SDIO in FUNC_OFF state(0x%x)\n", + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO2]); + osal_assert(0); + iRet = -4; + wmt_lib_wlan_lock_release(); + goto done; + } + } else { + WMT_ERR_FUNC("not implemented yet hifType: 0x%x, unspecified wifi_hif\n", + gMtkWmtCtx.wmtHifConf.hifType); + /* TODO: Wi-Fi/WMT uses other interfaces. NOT IMPLEMENTED YET! */ + } + + iRet = (*(gpWmtFuncOps[drvType]->func_on)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); + if (iRet != 0) { + if (WMT_HIF_UART == gMtkWmtCtx.wmtHifConf.hifType) { + /*need to power SDIO off when Power on Wi-Fi fail, in case of power leakage and + * right SDIO power status maintain + */ + ctrlPa1 = WMT_SDIO_SLOT_SDIO1; + ctrlPa2 = 0; /* turn off SDIO1 slot */ + wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2); + /* does not need to check turn off result */ + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO1] = DRV_STS_POWER_OFF; + } + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; + } else + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_FUNC_ON; + + /* wlan_lock must release before try_pwr_off */ + wmt_lib_wlan_lock_release(); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE:type(0x%x) function on failed, ret(%d)\n", drvType, iRet); + /* FIX-ME:[Chaozhong Liang], Error handling? check subsystem state and do pwr off if necessary? */ + /* check all sub-func and do power off */ + wmt_lib_try_pwr_off(); + } + +done: + wmt_core_dump_func_state("AF FUNC ON"); + return iRet; +} + +static INT32 opfunc_wlan_remove(P_WMT_OP pWmtOp) +{ + ULONG ctrlPa1; + ULONG ctrlPa2; + INT32 iRet; + UINT32 drvType = pWmtOp->au4OpData[0]; + + iRet = wmt_lib_wlan_lock_aquire(); + atomic_set(&g_wifi_on_off_ready, 0); + if (iRet) { + WMT_ERR_FUNC("--->lock wlan_lock failed, iRet=%d\n", iRet); + return iRet; + } + + if (gMtkWmtCtx.eDrvStatus[drvType] != DRV_STS_FUNC_ON) { + WMT_WARN_FUNC("WMT-CORE: Fun(%d) DRV_STS_[0x%x] already non-FUN_ON in wmt_func_off\n", + drvType, gMtkWmtCtx.eDrvStatus[drvType]); + iRet = 0; + wmt_lib_wlan_lock_release(); + goto done; + } + + iRet = (*(gpWmtFuncOps[drvType]->func_off)) (gMtkWmtCtx.p_ic_ops, wmt_conf_get_cfg()); + + if (WMT_HIF_UART == gMtkWmtCtx.wmtHifConf.hifType) { + UINT32 iRet = 0; + + ctrlPa1 = WMT_SDIO_SLOT_SDIO1; + ctrlPa2 = 0; /* turn off SDIO1 slot */ + iRet = wmt_core_ctrl(WMT_CTRL_SDIO_HW, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: turn on SLOT_SDIO1 fail (%d)\n", + iRet); + osal_assert(0); + } + /* Anyway, turn SDIO1 state to POWER_OFF state */ + gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_SDIO1] = DRV_STS_POWER_OFF; + } + + gMtkWmtCtx.eDrvStatus[drvType] = DRV_STS_POWER_OFF; + + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: type(0x%x) function off failed, ret(%d)\n", drvType, iRet); + osal_assert(0); + /* no matter subsystem function control fail or not, chip should be powered off + * when no subsystem is active + * return iRet; + */ + } + + /* wlan_lock must release before try_pwr_off */ + wmt_lib_wlan_lock_release(); + /* check all sub-func and do power off */ + wmt_lib_try_pwr_off(); + +done: + wmt_core_dump_func_state("AF FUNC OFF"); + return iRet; +} + +static INT32 opfunc_try_pwr_off(P_WMT_OP pWmtOp) +{ + INT32 iRet = 0; + UINT32 drvType = pWmtOp->au4OpData[0]; + + if (atomic_read(&g_wifi_on_off_ready) == 1) { + WMT_INFO_FUNC("wlan on/off procedure will be started, do not power off now.\n"); + return iRet; + } + + /* Why it can use try lock? + * Because only wmtd_worker_thread get wlan lock for wifi on/off in current design. + * It means it can decide whether to do Connsys power off after Wifi function on/off complete. + */ + if (wmt_lib_wlan_lock_trylock() == 0) { + WMT_INFO_FUNC("Can't lock wlan mutex which might be held by wlan on/off procedure.\n"); + return iRet; + } + + if ((gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_BT] == DRV_STS_POWER_OFF) && + (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_GPS] == DRV_STS_POWER_OFF) && + (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_FM] == DRV_STS_POWER_OFF) && + (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_WIFI] == DRV_STS_POWER_OFF) && + (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_LPBK] == DRV_STS_POWER_OFF) && + (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_ANT] == DRV_STS_POWER_OFF) && + (gMtkWmtCtx.eDrvStatus[WMTDRV_TYPE_COREDUMP] == DRV_STS_POWER_OFF)) { + WMT_INFO_FUNC("WMT-CORE:Fun(%d) [POWER_OFF] and power down chip\n", drvType); + mtk_wcn_wmt_system_state_reset(); + iRet = opfunc_pwr_off(pWmtOp); + if (iRet) { + WMT_ERR_FUNC("WMT-CORE: wmt_pwr_off fail(%d) when turn off func(%d)\n", + iRet, drvType); + osal_assert(0); + } + } + wmt_lib_wlan_lock_release(); + return iRet; +} + +static INT32 opfunc_gps_mcu_ctrl(P_WMT_OP pWmtOp) +{ + INT32 iRet = -1; + UINT32 u4WrittenSize = 0; + UINT32 u4ReadSize = 0; + INT32 fgFail = -1; + PUINT8 p_tx_data_buf; + UINT32 tx_data_len; + PUINT8 p_rx_data_buf; + UINT32 rx_data_buf_len; + PUINT32 p_rx_data_len; + UINT8 WMT_GPS_MCU_CTRL_CMD[] = {0x01, 0x32, 0x00, 0x00}; + PUINT8 p_tx_buf = NULL; + PUINT8 p_rx_buf = NULL; + + p_tx_data_buf = (PUINT8)pWmtOp->au4OpData[0]; + tx_data_len = pWmtOp->au4OpData[1]; + p_rx_data_buf = (PUINT8)pWmtOp->au4OpData[2]; + rx_data_buf_len = pWmtOp->au4OpData[3]; + p_rx_data_len = (PINT32)(pWmtOp->au4OpData[4]); + + if ((!p_tx_data_buf) || (tx_data_len == 0) || (!p_rx_data_buf) || (rx_data_buf_len == 0)) { + pWmtOp->au4OpData[5] = -1; + WMT_ERR_FUNC("Parameter error!\n"); + return fgFail; + } + + p_tx_buf = osal_malloc(tx_data_len + osal_sizeof(WMT_GPS_MCU_CTRL_CMD)); + if (!p_tx_buf) { + pWmtOp->au4OpData[5] = -2; + WMT_ERR_FUNC("p_tx_buf alloc fail!\n"); + return fgFail; + } + + p_rx_buf = osal_malloc(rx_data_buf_len + osal_sizeof(WMT_GPS_MCU_CTRL_CMD)); + if (!p_rx_buf) { + osal_free(p_tx_buf); + pWmtOp->au4OpData[5] = -3; + WMT_ERR_FUNC("p_rx_buf alloc fail!\n"); + return fgFail; + } + + WMT_GPS_MCU_CTRL_CMD[2] = (tx_data_len & 0x000000ff); + WMT_GPS_MCU_CTRL_CMD[3] = ((tx_data_len & 0x0000ff00) >> 8); + osal_memcpy(p_tx_buf, WMT_GPS_MCU_CTRL_CMD, osal_sizeof(WMT_GPS_MCU_CTRL_CMD)); + osal_memcpy(p_tx_buf + osal_sizeof(WMT_GPS_MCU_CTRL_CMD), p_tx_data_buf, tx_data_len); + + do { + + iRet = wmt_core_tx(p_tx_buf, tx_data_len + osal_sizeof(WMT_GPS_MCU_CTRL_CMD), &u4WrittenSize, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4WrittenSize != (tx_data_len + osal_sizeof(WMT_GPS_MCU_CTRL_CMD)))) { + WMT_ERR_FUNC("gps mcu ctrl tx CMD fail(%d),size(%d)\n", iRet, u4WrittenSize); + break; + } + + iRet = wmt_core_rx(p_rx_buf, rx_data_buf_len + osal_sizeof(WMT_GPS_MCU_CTRL_CMD), + &u4ReadSize); + if (iRet || (p_rx_buf[1] != WMT_GPS_MCU_CTRL_CMD[1])) { + WMT_ERR_FUNC("gps mcu ctrl rx EVT fail(%d),size(%d)\n", iRet, u4ReadSize); + break; + } + *p_rx_data_len = (p_rx_buf[2] | (p_rx_buf[3] << 8)); + osal_memcpy(p_rx_data_buf, p_rx_buf + osal_sizeof(WMT_GPS_MCU_CTRL_CMD), + *p_rx_data_len > rx_data_buf_len ? rx_data_buf_len : *p_rx_data_len); + + fgFail = 0; + } while (0); + + osal_free(p_tx_buf); + osal_free(p_rx_buf); + + return fgFail; +} + +P_WMT_GEN_CONF wmt_get_gen_conf_pointer(VOID) +{ + P_WMT_GEN_CONF pWmtGenConf = NULL; + + pWmtGenConf = wmt_conf_get_cfg(); + return pWmtGenConf; +} + +VOID wmt_core_set_blank_status(UINT32 on_off_flag) +{ + gMtkWmtCtx.wmtBlankStatus = on_off_flag; +} + +UINT32 wmt_core_get_blank_status(VOID) +{ + return gMtkWmtCtx.wmtBlankStatus; +} + +INT32 wmt_blank_status_ctrl(UINT32 on_off_flag) +{ + INT32 iRet = 0; +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + UINT32 u4Res; + UINT32 evtLen; + UINT8 evtBuf[16] = { 0 }; + + WMT_BLANK_STATUS_CMD[5] = (on_off_flag) ? 0x1 : 0x0; + + /* send command */ + iRet = wmt_core_tx((PUINT8)WMT_BLANK_STATUS_CMD, osal_sizeof(WMT_BLANK_STATUS_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + + if (iRet || (u4Res != osal_sizeof(WMT_BLANK_STATUS_CMD))) { + WMT_ERR_FUNC("WMT-CORE: WMT_BLANK_STATUS_CMD iRet(%d) cmd len err(%d, %zu)\n", + (iRet == 0 ? -1 : iRet), u4Res, osal_sizeof(WMT_BLANK_STATUS_CMD)); + return iRet; + } + + evtLen = osal_sizeof(WMT_BLANK_STATUS_EVT); + iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); + if (iRet || (u4Res != evtLen)) { + WMT_ERR_FUNC("WMT-CORE: read WMT_BLANK_STATUS_EVT fail(%d) len(%d, %d)\n", + iRet, u4Res, evtLen); + WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n", + evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + WMT_BLANK_STATUS_EVT[0], WMT_BLANK_STATUS_EVT[1], + WMT_BLANK_STATUS_EVT[2], WMT_BLANK_STATUS_EVT[3], + WMT_BLANK_STATUS_EVT[4]); + } + else + wmt_lib_set_blank_status(WMT_BLANK_STATUS_CMD[5]); +#endif + return iRet; +} + +static INT32 opfunc_blank_status_ctrl(P_WMT_OP pWmtOp) +{ + return wmt_blank_status_ctrl(pWmtOp->au4OpData[0]); +} + +static INT32 opfunc_met_ctrl(P_WMT_OP pWmtOp) +{ + INT32 iRet; + UINT32 u4Res; + UINT32 evtLen; + UINT8 evtBuf[16] = { 0 }; + UINT32 value; + UINT8 WMT_MET_CTRL_CMD[] = { 0x01, 0x31, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00}; + UINT8 WMT_MET_CTRL_EVT[] = { 0x02, 0x31, 0x01, 0x00, 0x00 }; + + value = pWmtOp->au4OpData[0]; + WMT_MET_CTRL_CMD[5] = (value & 0x000000ff); + WMT_MET_CTRL_CMD[6] = (value & 0x0000ff00) >> 8; + WMT_MET_CTRL_CMD[7] = (value & 0x00ff0000) >> 16; + WMT_MET_CTRL_CMD[8] = (value & 0xff000000) >> 24; + + /* send command */ + iRet = wmt_core_tx(WMT_MET_CTRL_CMD, sizeof(WMT_MET_CTRL_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + if ((iRet) || (u4Res != sizeof(WMT_MET_CTRL_CMD))) { + WMT_ERR_FUNC("Tx MET_CTRL_CMD fail!(%d) len (%d, %zu)\n", iRet, u4Res, + sizeof(WMT_MET_CTRL_CMD)); + return -2; + } + + /* receive event */ + evtLen = sizeof(WMT_MET_CTRL_EVT); + iRet = wmt_core_rx(evtBuf, evtLen, &u4Res); + if ((iRet) || (u4Res != evtLen)) { + WMT_ERR_FUNC("Rx MET_CTRL_EVT fail!(%d) len(%d, %d)\n", iRet, u4Res, evtLen); + mtk_wcn_stp_dbg_dump_package(); + wmt_core_trigger_assert(); + return -3; + } + + return 0; +} + +static INT32 opfunc_resume_dump_info(P_WMT_OP pWmtOp) +{ + return mtk_consys_resume_dump_info(); +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ctrl.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ctrl.c new file mode 100644 index 00000000000000..c1f7cd62330c83 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ctrl.c @@ -0,0 +1,1197 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CTRL]" + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "osal.h" + +#include "wmt_ctrl.h" +#include "wmt_core.h" +#include "wmt_lib.h" +#include "wmt_dev.h" +#include "wmt_plat.h" +#include "hif_sdio.h" +#include "stp_core.h" +#include "stp_dbg.h" +#include "wmt_ic.h" +#include "wmt_step.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/* moved to wmt_ctrl.h */ +/*static INT32 wmt_ctrl_tx_ex (UINT8 *pData, UINT32 size, UINT32 *writtenSize, MTK_WCN_BOOL bRawFlag);*/ + +static INT32 wmt_ctrl_stp_conf_ex(WMT_STP_CONF_TYPE type, UINT32 value); + +static INT32 wmt_ctrl_hw_pwr_off(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_hw_pwr_on(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_ul_cmd(P_DEV_WMT pWmtDev, const PUINT8 pCmdStr); +static INT32 wmt_ctrl_hw_rst(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_stp_close(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_stp_open(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_stp_conf(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_free_patch(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_get_patch(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_host_baudrate_set(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_sdio_hw(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_sdio_func(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_hwidver_set(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_stp_rst(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_get_wmt_conf(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_others(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_tx(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_rx(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_patch_search(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_crystal_triming_put(P_WMT_CTRL_DATA pWmtCtrlData); +static INT32 wmt_ctrl_crystal_triming_get(P_WMT_CTRL_DATA pWmtCtrlData); +static INT32 wmt_ctrl_hw_state_show(P_WMT_CTRL_DATA pWmtCtrlData); +static INT32 wmt_ctrl_get_patch_num(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_get_patch_info(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_rx_flush(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_soc_paldo_ctrl(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_soc_wakeup_consys(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_set_stp_dbg_info(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_bgw_desense_ctrl(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_trg_assert(P_WMT_CTRL_DATA); +static INT32 wmt_ctrl_evt_parser(P_WMT_CTRL_DATA pWmtCtrlData); +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 wmt_ctrl_get_tdm_req_antsel(P_WMT_CTRL_DATA); +#endif + +static INT32 wmt_ctrl_gps_sync_set(P_WMT_CTRL_DATA pData); + +static INT32 wmt_ctrl_gps_lna_set(P_WMT_CTRL_DATA pData); + +static INT32 wmt_ctrl_get_patch_name(P_WMT_CTRL_DATA pWmtCtrlData); + +static INT32 wmt_ctrl_get_rom_patch_info(P_WMT_CTRL_DATA pWmtCtrlData); + +static INT32 wmt_ctrl_update_patch_version(P_WMT_CTRL_DATA); + +/* TODO: [FixMe][GeorgeKuo]: remove unused function */ +/*static INT32 wmt_ctrl_hwver_get(P_WMT_CTRL_DATA);*/ + + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/* GeorgeKuo: Use designated initializers described in + * http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Designated-Inits.html + */ +static const WMT_CTRL_FUNC wmt_ctrl_func[] = { + [WMT_CTRL_HW_PWR_OFF] = wmt_ctrl_hw_pwr_off, + [WMT_CTRL_HW_PWR_ON] = wmt_ctrl_hw_pwr_on, + [WMT_CTRL_HW_RST] = wmt_ctrl_hw_rst, + [WMT_CTRL_STP_CLOSE] = wmt_ctrl_stp_close, + [WMT_CTRL_STP_OPEN] = wmt_ctrl_stp_open, + [WMT_CTRL_STP_CONF] = wmt_ctrl_stp_conf, + [WMT_CTRL_FREE_PATCH] = wmt_ctrl_free_patch, + [WMT_CTRL_GET_PATCH] = wmt_ctrl_get_patch, + [WMT_CTRL_GET_PATCH_NAME] = wmt_ctrl_get_patch_name, + [WMT_CTRL_HOST_BAUDRATE_SET] = wmt_ctrl_host_baudrate_set, + [WMT_CTRL_SDIO_HW] = wmt_ctrl_sdio_hw, + [WMT_CTRL_SDIO_FUNC] = wmt_ctrl_sdio_func, + [WMT_CTRL_HWIDVER_SET] = wmt_ctrl_hwidver_set, + [WMT_CTRL_HWVER_GET] = NULL, /* TODO: [FixMe][GeorgeKuo]: remove unused function. */ + [WMT_CTRL_STP_RST] = wmt_ctrl_stp_rst, + [WMT_CTRL_GET_WMT_CONF] = wmt_ctrl_get_wmt_conf, + [WMT_CTRL_TX] = wmt_ctrl_tx, + [WMT_CTRL_RX] = wmt_ctrl_rx, + [WMT_CTRL_RX_FLUSH] = wmt_ctrl_rx_flush, + [WMT_CTRL_GPS_SYNC_SET] = wmt_ctrl_gps_sync_set, + [WMT_CTRL_GPS_LNA_SET] = wmt_ctrl_gps_lna_set, + [WMT_CTRL_PATCH_SEARCH] = wmt_ctrl_patch_search, + [WMT_CTRL_CRYSTAL_TRIMING_GET] = wmt_ctrl_crystal_triming_get, + [WMT_CTRL_CRYSTAL_TRIMING_PUT] = wmt_ctrl_crystal_triming_put, + [WMT_CTRL_HW_STATE_DUMP] = wmt_ctrl_hw_state_show, + [WMT_CTRL_GET_PATCH_NUM] = wmt_ctrl_get_patch_num, + [WMT_CTRL_GET_PATCH_INFO] = wmt_ctrl_get_patch_info, + [WMT_CTRL_SOC_PALDO_CTRL] = wmt_ctrl_soc_paldo_ctrl, + [WMT_CTRL_SOC_WAKEUP_CONSYS] = wmt_ctrl_soc_wakeup_consys, + [WMT_CTRL_SET_STP_DBG_INFO] = wmt_ctrl_set_stp_dbg_info, + [WMT_CTRL_BGW_DESENSE_CTRL] = wmt_ctrl_bgw_desense_ctrl, + [WMT_CTRL_TRG_ASSERT] = wmt_ctrl_trg_assert, + #if CFG_WMT_LTE_COEX_HANDLING + [WMT_CTRL_GET_TDM_REQ_ANTSEL] = wmt_ctrl_get_tdm_req_antsel, +#endif + [WMT_CTRL_EVT_PARSER] = wmt_ctrl_evt_parser, + [WMT_CTRL_GET_ROM_PATCH_INFO] = wmt_ctrl_get_rom_patch_info, + [WMT_CTRL_UPDATE_PATCH_VERSION] = wmt_ctrl_update_patch_version, + [WMT_CTRL_MAX] = wmt_ctrl_others, +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 __weak mtk_wcn_consys_stp_btif_parser_wmt_evt(const PUINT8 str, UINT32 len) +{ + return 0; +} + +INT32 wmt_ctrl(P_WMT_CTRL_DATA pWmtCtrlData) +{ + UINT32 ctrlId = 0; + + if (pWmtCtrlData == NULL) { + osal_assert(0); + return -1; + } + + ctrlId = pWmtCtrlData->ctrlId; + /*1sanity check, including wmtCtrlId */ + if ((pWmtCtrlData == NULL) + || (ctrlId >= WMT_CTRL_MAX)) + /* || (ctrlId < WMT_CTRL_HW_PWR_OFF) ) [FixMe][GeorgeKuo]: useless comparison */ + { + osal_assert(pWmtCtrlData != NULL); + osal_assert(ctrlId < WMT_CTRL_MAX); + /* osal_assert(ctrlId >= WMT_CTRL_HW_PWR_OFF); [FixMe][GeorgeKuo]: useless comparison */ + return -2; + } + /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */ + if (wmt_ctrl_func[ctrlId]) { + /*call servicd handling API */ + return (*(wmt_ctrl_func[ctrlId])) (pWmtCtrlData); /* serviceHandlerPack[ctrlId].serviceHandler */ + } + osal_assert(wmt_ctrl_func[ctrlId] != NULL); + return -3; +} + +INT32 wmt_ctrl_tx(P_WMT_CTRL_DATA pWmtCtrlData /*UINT8 *pData, UINT32 size, UINT32 *writtenSize */) +{ + PUINT8 pData = (PUINT8) pWmtCtrlData->au4CtrlData[0]; + UINT32 size = pWmtCtrlData->au4CtrlData[1]; + PUINT32 writtenSize = (PUINT32) pWmtCtrlData->au4CtrlData[2]; + MTK_WCN_BOOL bRawFlag = pWmtCtrlData->au4CtrlData[3]; + + return wmt_ctrl_tx_ex(pData, size, writtenSize, bRawFlag); +} + +static VOID wmt_ctrl_show_sched_stats_log(P_OSAL_THREAD pThread, P_OSAL_THREAD_SCHEDSTATS pSchedstats) +{ + if ((pThread) && (pThread->pThread) && (pSchedstats)) + WMT_ERR_FUNC("WMT rx_timeout, pid[%d/%s] stats duration:%llums, sched(x%llu/r%llu/i%llu)\n", + pThread->pThread->pid, + pThread->threadName, + pSchedstats->time, + pSchedstats->exec, + pSchedstats->runnable, + pSchedstats->iowait); +} + +INT32 wmt_ctrl_rx(P_WMT_CTRL_DATA pWmtCtrlData /*UINT8 *pBuff, UINT32 buffLen, UINT32 *readSize */) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + INT32 readLen; + INT32 waitRet = -1; + INT32 loopCnt = 1; + INT32 leftCnt; + PUINT8 pBuff = (PUINT8) pWmtCtrlData->au4CtrlData[0]; + UINT32 buffLen = pWmtCtrlData->au4CtrlData[1]; + PUINT32 readSize = (PUINT32) pWmtCtrlData->au4CtrlData[2]; + INT32 stpRxState; + INT32 extended = 0; + P_OSAL_THREAD p_rx_thread = NULL; + OSAL_THREAD_SCHEDSTATS schedstats; + + if (readSize) + *readSize = 0; + + /* sanity check */ + if (!buffLen) { + WMT_WARN_FUNC("buffLen = 0\n"); + osal_assert(buffLen); + return 0; + } + + if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)) { + WMT_WARN_FUNC("state(0x%lx)\n", pDev->state.data); + osal_assert(osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)); + return -2; + } + if (wmt_lib_get_drv_status(WMTDRV_TYPE_WMT) == DRV_STS_FUNC_ON) + loopCnt = 4; + leftCnt = loopCnt; + + /* sanity ok, proceeding rx operation */ + readLen = mtk_wcn_stp_receive_data(pBuff, buffLen, WMT_TASK_INDX); + p_rx_thread = mtk_stp_rx_thread_get(); + osal_thread_sched_mark(p_rx_thread, &schedstats); + + while (readLen == 0 && leftCnt > 0) { /* got nothing, wait for STP's signal */ + /* if assert happen, do not wait for any signal again */ + if (mtk_wcn_stp_get_wmt_trg_assert() == 1 + && mtk_wcn_stp_is_wmt_last_close() == 0) + break; + pDev->rWmtRxWq.timeoutValue = WMT_LIB_RX_TIMEOUT/loopCnt; + waitRet = wmt_dev_rx_timeout(&pDev->rWmtRxWq); + if (waitRet == 0) { + leftCnt--; + /* dump btif_rxd's backtrace to check whether it is blocked or not */ + osal_dump_thread_state("btif_rxd"); + stp_dbg_poll_cpupcr(5, 1, 1); + if (!mtk_wcn_stp_is_sdio_mode()) mtk_wcn_consys_stp_btif_logger_ctrl(BTIF_DUMP_BTIF_IRQ); + + if (leftCnt <= 0) { + if (extended == 0) { + stpRxState = mtk_stp_check_rx_has_pending_data(); + WMT_INFO_FUNC("check rx pending data(%d)\n", stpRxState); + readLen = mtk_wcn_stp_receive_data(pBuff, buffLen, WMT_TASK_INDX); + if (readLen > 0) { + WMT_INFO_FUNC("rx data received, rx done.\n"); + break; + } else if (stpRxState > 0) { + osal_thread_sched_unmark(p_rx_thread, &schedstats); + wmt_ctrl_show_sched_stats_log(p_rx_thread, &schedstats); + WMT_INFO_FUNC("stp has pending data, extend ~4 seconds\n"); + leftCnt = WMT_LIB_RX_EXTEND_TIMEOUT/pDev->rWmtRxWq.timeoutValue; + extended = 1; + osal_thread_sched_mark(p_rx_thread, &schedstats); + continue; + } + /* wmt is closed, device is shuting down */ + if (wmt_dev_is_close() || mtk_wcn_stp_is_wmt_last_close() == 1) { + leftCnt = 10; + continue; + } + } + + osal_thread_sched_unmark(p_rx_thread, &schedstats); + wmt_ctrl_show_sched_stats_log(p_rx_thread, &schedstats); + stp_dbg_poll_cpupcr(5, 1, 1); + WMT_ERR_FUNC("wmt_dev_rx_timeout: timeout,jiffies(%lu),timeoutvalue(%d)\n", + jiffies, pDev->rWmtRxWq.timeoutValue); + WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC("STP RX timeout"); + + /* Reason number 44 means that stp data path still has data, + * possibly a driver problem + */ + if (stpRxState != 0) + wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 44); + return -1; + } + } else if (waitRet < 0) { + WMT_WARN_FUNC("wmt_dev_rx_timeout: interrupted by signal (%d)\n", waitRet); + WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC("STP RX timeout"); + return waitRet; + } + readLen = mtk_wcn_stp_receive_data(pBuff, buffLen, WMT_TASK_INDX); + + if (readLen == 0) + WMT_DBG_FUNC("wmt_ctrl_rx be signaled, but no rx data(%d)\n", waitRet); + WMT_DBG_FUNC("stp_receive_data: readLen(%d)\n", readLen); + } + + if (readSize) + *readSize = readLen; + + return 0; +} + + +INT32 +wmt_ctrl_tx_ex(const PUINT8 pData, + const UINT32 size, PUINT32 writtenSize, const MTK_WCN_BOOL bRawFlag) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + INT32 iRet; + + if (writtenSize != NULL) + *writtenSize = 0; + + /* sanity check */ + if (size == 0) { + WMT_WARN_FUNC("size to tx is 0\n"); + osal_assert(size); + return -1; + } + + /* if STP is not enabled yet, can't use this function. Use tx_raw instead */ + if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state) || + !osal_test_bit(WMT_STAT_STP_EN, &pDev->state)) { + WMT_ERR_FUNC("wmt state(0x%lx)\n", pDev->state.data); + osal_assert(osal_test_bit(WMT_STAT_STP_EN, &pDev->state)); + osal_assert(osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)); + iRet = -2; + if (writtenSize) + *writtenSize = iRet; + return iRet; + } + + /* sanity ok, proceeding tx operation */ + /*retval = mtk_wcn_stp_send_data(data, size, WMTDRV_TYPE_WMT); */ + mtk_wcn_stp_flush_rx_queue(WMT_TASK_INDX); + if (bRawFlag) + iRet = mtk_wcn_stp_send_data_raw(pData, size, WMT_TASK_INDX); + else + iRet = mtk_wcn_stp_send_data(pData, size, WMT_TASK_INDX); + + if (iRet != size) { + WMT_WARN_FUNC("write(%d) written(%d)\n", size, iRet); + osal_assert(iRet == size); + } + + if (writtenSize) + *writtenSize = iRet; + + return 0; + +} + +INT32 wmt_ctrl_rx_flush(P_WMT_CTRL_DATA pWmtCtrlData) +{ + UINT32 type = pWmtCtrlData->au4CtrlData[0]; + + WMT_INFO_FUNC("flush rx %d queue\n", type); + mtk_wcn_stp_flush_rx_queue(type); + + return 0; +} + + +INT32 wmt_ctrl_hw_pwr_off(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iret; + /*psm should be disabled before wmt_ic_deinit*/ + P_DEV_WMT pDev = &gDevWmt; + + if (osal_test_and_clear_bit(WMT_STAT_PWR, &pDev->state)) { + WMT_DBG_FUNC("on->off\n"); + iret = wmt_plat_pwr_ctrl(FUNC_OFF); + } else { + WMT_WARN_FUNC("already off\n"); + iret = 0; + } + + return iret; +} + +INT32 wmt_ctrl_hw_pwr_on(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iret; + /*psm should be enabled right after wmt_ic_init */ + P_DEV_WMT pDev = &gDevWmt; + + if (osal_test_and_set_bit(WMT_STAT_PWR, &pDev->state)) { + WMT_WARN_FUNC("already on\n"); + iret = 0; + } else { + WMT_DBG_FUNC("off->on\n"); + iret = wmt_plat_pwr_ctrl(FUNC_ON); + } + + return iret; +} + +INT32 wmt_ctrl_ul_cmd(P_DEV_WMT pWmtDev, const PUINT8 pCmdStr) +{ + INT32 waitRet = -1; + P_OSAL_SIGNAL pCmdSignal; + P_OSAL_EVENT pCmdReq; + + if (osal_test_and_set_bit(WMT_STAT_CMD, &pWmtDev->state)) { + WMT_WARN_FUNC("cmd buf is occupied by (%s)\n", pWmtDev->cCmd); + return -1; + } + + /* indicate baud rate change to user space app */ +#if 0 + INIT_COMPLETION(pWmtDev->cmd_comp); + pWmtDev->cmd_result = -1; + strncpy(pWmtDev->cCmd, pCmdStr, NAME_MAX); + pWmtDev->cCmd[NAME_MAX] = '\0'; + wake_up_interruptible(&pWmtDev->cmd_wq); +#endif + + pCmdSignal = &pWmtDev->cmdResp; + osal_signal_init(pCmdSignal); + pCmdSignal->timeoutValue = 6000; + osal_strncpy(pWmtDev->cCmd, pCmdStr, NAME_MAX); + pWmtDev->cCmd[NAME_MAX] = '\0'; + + pCmdReq = &pWmtDev->cmdReq; + + osal_trigger_event(&pWmtDev->cmdReq); + WMT_DBG_FUNC("str(%s) request ok\n", pCmdStr); + +/* waitRet = wait_for_completion_interruptible_timeout(&pWmtDev->cmd_comp, msecs_to_jiffies(2000)); */ + waitRet = osal_wait_for_signal_timeout(pCmdSignal, NULL); + WMT_LOUD_FUNC("wait signal iRet:%d\n", waitRet); + if (waitRet == 0) { + WMT_ERR_FUNC("wait signal timeout\n"); + return -2; + } + + WMT_DBG_FUNC("str(%s) result(%d)\n", pCmdStr, pWmtDev->cmdResult); + + return pWmtDev->cmdResult; +} + +INT32 wmt_ctrl_hw_rst(P_WMT_CTRL_DATA pWmtCtrlData) +{ + wmt_plat_pwr_ctrl(FUNC_RST); + return 0; +} + +INT32 wmt_ctrl_hw_state_show(P_WMT_CTRL_DATA pWmtCtrlData) +{ + wmt_plat_pwr_ctrl(FUNC_STAT); + return 0; +} + +INT32 wmt_ctrl_stp_close(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + INT32 iRet = 0; + UINT8 cmdStr[NAME_MAX + 1] = { 0 }; + /* un-register to STP-core for rx */ + + iRet = mtk_wcn_stp_register_event_cb(WMT_TASK_INDX, NULL); /* mtk_wcn_stp_register_event_cb */ + if (iRet) { + WMT_WARN_FUNC("stp_reg cb unregister fail(%d)\n", iRet); + return -1; + } + + if (pDev->rWmtHifConf.hifType == WMT_HIF_UART) { + + osal_snprintf(cmdStr, NAME_MAX, "close_stp"); + + iRet = wmt_ctrl_ul_cmd(pDev, cmdStr); + if (iRet) { + WMT_WARN_FUNC("wmt_ctrl_ul_cmd fail(%d)\n", iRet); + return -2; + } + } + if (pDev->rWmtHifConf.hifType == WMT_HIF_BTIF) { + /*un-register rxcb to btif */ + iRet = mtk_wcn_stp_rxcb_register(NULL); + if (iRet) { + WMT_WARN_FUNC("mtk_wcn_stp_rxcb_unregister fail(%d)\n", iRet); + return -2; + } + + iRet = mtk_wcn_stp_close_btif(); + if (iRet) { + WMT_WARN_FUNC("mtk_wcn_stp_close_btif fail(%d)\n", iRet); + return -3; + } + } + + osal_clear_bit(WMT_STAT_STP_OPEN, &pDev->state); + + return 0; +} + +INT32 wmt_ctrl_stp_open(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + INT32 iRet; + UINT8 cmdStr[NAME_MAX + 1] = { 0 }; + + if (pDev->rWmtHifConf.hifType == WMT_HIF_UART) { + osal_snprintf(cmdStr, NAME_MAX, "open_stp"); + iRet = wmt_ctrl_ul_cmd(pDev, cmdStr); + if (iRet) { + WMT_WARN_FUNC("wmt_ctrl_ul_cmd fail(%d)\n", iRet); + return -1; + } + } + if (pDev->rWmtHifConf.hifType == WMT_HIF_BTIF) { + iRet = mtk_wcn_stp_open_btif(); + if (iRet) { + WMT_WARN_FUNC("mtk_wcn_stp_open_btif fail(%d)\n", iRet); + return -1; + } + + /*register stp rx call back to btif */ + iRet = mtk_wcn_stp_rxcb_register((MTK_WCN_BTIF_RX_CB) mtk_wcn_stp_parser_data); + if (iRet) { + WMT_WARN_FUNC("mtk_wcn_stp_rxcb_register fail(%d)\n", iRet); + return -2; + } + } + /* register to STP-core for rx */ + /* mtk_wcn_stp_register_event_cb */ + iRet = mtk_wcn_stp_register_event_cb(WMT_TASK_INDX, wmt_dev_rx_event_cb); + if (iRet) { + WMT_WARN_FUNC("stp_reg cb fail(%d)\n", iRet); + return -2; + } + + osal_set_bit(WMT_STAT_STP_OPEN, &pDev->state); +#if 0 + iRet = mtk_wcn_stp_lpbk_ctrl(1); +#endif + + return 0; +} + + +INT32 wmt_ctrl_patch_search(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + INT32 iRet; + UINT8 cmdStr[NAME_MAX + 1] = { 0 }; + + osal_snprintf(cmdStr, NAME_MAX, "srh_patch"); + iRet = wmt_ctrl_ul_cmd(pDev, cmdStr); + if (iRet) { + WMT_WARN_FUNC("wmt_ctrl_ul_cmd fail(%d)\n", iRet); + return -1; + } + return 0; +} + + +INT32 wmt_ctrl_get_patch_num(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + + pWmtCtrlData->au4CtrlData[0] = pDev->patchNum; + return 0; +} + + +INT32 wmt_ctrl_get_patch_info(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + UINT32 downLoadSeq = 0; + P_WMT_PATCH_INFO pPatchinfo = NULL; + PUINT8 pNbuf = NULL; + PUINT8 pAbuf = NULL; + + if (pDev->pWmtPatchInfo == NULL) { + WMT_ERR_FUNC("pWmtPatchInfo is NULL\n"); + return -1; + } + + downLoadSeq = pWmtCtrlData->au4CtrlData[0]; + WMT_DBG_FUNC("download seq is %d\n", downLoadSeq); + + pPatchinfo = pDev->pWmtPatchInfo + downLoadSeq - 1; + pNbuf = (PUINT8) pWmtCtrlData->au4CtrlData[1]; + pAbuf = (PUINT8) pWmtCtrlData->au4CtrlData[2]; + if (pPatchinfo) { + osal_memcpy(pNbuf, pPatchinfo->patchName, osal_sizeof(pPatchinfo->patchName)); + osal_memcpy(pAbuf, pPatchinfo->addRess, osal_sizeof(pPatchinfo->addRess)); + WMT_DBG_FUNC("get 4 address bytes is 0x%2x,0x%2x,0x%2x,0x%2x", pAbuf[0], pAbuf[1], + pAbuf[2], pAbuf[3]); + } else + WMT_ERR_FUNC("NULL patchinfo pointer\n"); + + return 0; +} + +INT32 wmt_ctrl_get_rom_patch_info(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + UINT32 type = 0; + struct wmt_rom_patch_info *pPatchinfo = NULL; + PUINT8 pNbuf = NULL; + PUINT8 pAbuf = NULL; + INT32 ret = 0; + UINT8 cmdStr[NAME_MAX + 1] = { 0 }; + + type = pWmtCtrlData->au4CtrlData[0]; + WMT_DBG_FUNC("rom patch type is %d\n", type); + pDev->ip_ver = pWmtCtrlData->au4CtrlData[3]; + pDev->fw_ver = pWmtCtrlData->au4CtrlData[4]; + WMT_DBG_FUNC("ip version is [%x] [%x]\n", pDev->ip_ver, pDev->fw_ver); + + if (!pDev->pWmtRomPatchInfo[WMTDRV_TYPE_WMT]) { + osal_snprintf(cmdStr, NAME_MAX, "srh_rom_patch"); + ret = wmt_ctrl_ul_cmd(pDev, cmdStr); + if (ret) { + WMT_WARN_FUNC("wmt_ctrl_ul_cmd fail(%d)\n", ret); + return -1; + } + } + + if (type < WMTDRV_TYPE_ANT) { + pPatchinfo = pDev->pWmtRomPatchInfo[type]; + pNbuf = (PUINT8) pWmtCtrlData->au4CtrlData[1]; + pAbuf = (PUINT8) pWmtCtrlData->au4CtrlData[2]; + if (pPatchinfo) { + osal_memcpy(pNbuf, pPatchinfo->patchName, osal_sizeof(pPatchinfo->patchName)); + osal_memcpy(pAbuf, pPatchinfo->addRess, osal_sizeof(pPatchinfo->addRess)); + WMT_DBG_FUNC("get 4 address bytes is 0x%2x,0x%2x,0x%2x,0x%2x", + pAbuf[0], pAbuf[1], pAbuf[2], pAbuf[3]); + } else { + WMT_ERR_FUNC("NULL patchinfo pointer\n"); + ret = 1; + } + } else { + WMT_ERR_FUNC("rom patch type %d is error!\n", type); + ret = -1; + } + + return ret; +} + +INT32 wmt_ctrl_update_patch_version(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + INT32 iRet; + UINT8 cmdStr[NAME_MAX + 1] = { 0 }; + + osal_snprintf(cmdStr, NAME_MAX, "update_patch_version"); + iRet = wmt_ctrl_ul_cmd(pDev, cmdStr); + if (iRet) { + WMT_WARN_FUNC("wmt_ctrl_ul_cmd fail(%d)\n", iRet); + return -1; + } + return 0; +} + +INT32 wmt_ctrl_soc_paldo_ctrl(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = 0; + ENUM_PALDO_TYPE ept = pWmtCtrlData->au4CtrlData[0]; + ENUM_PALDO_OP epo = pWmtCtrlData->au4CtrlData[1]; + + WMT_DBG_FUNC("ept(%d),epo(%d)\n", ept, epo); + iRet = wmt_plat_soc_paldo_ctrl(ept, epo); + if (iRet) { + if (ept == PMIC_CHIPID_PALDO) { + /* special handling for PMIC CHIPID */ + pWmtCtrlData->au4CtrlData[2] = iRet; + } else { + /* for other PA handling */ + WMT_ERR_FUNC("soc palod ctrl fail(%d)\n", iRet); + } + } + + return iRet; +} + +INT32 wmt_ctrl_soc_wakeup_consys(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = 0; + + iRet = mtk_wcn_stp_wakeup_consys(); + if (iRet) + WMT_ERR_FUNC("soc palod ctrl fail(%d)\n", iRet); + + return iRet; +} + +static INT32 wmt_ctrl_bgw_desense_ctrl(P_WMT_CTRL_DATA pWmtCtrlData) +{ + UINT32 cmd = pWmtCtrlData->au4CtrlData[0]; + + WMT_INFO_FUNC("wmt-ctrl:send native cmd(%d)\n", cmd); + wmt_dev_send_cmd_to_daemon(cmd); + + return 0; +} + +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 wmt_ctrl_get_tdm_req_antsel(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 antsel_index = wmt_plat_get_tdm_antsel_index(); + + if (antsel_index >= 0) + pWmtCtrlData->au4CtrlData[0] = antsel_index; + else + pWmtCtrlData->au4CtrlData[0] = 0xff; + + WMT_INFO_FUNC("get tdm req antsel index is %d\n", antsel_index); + + return 0; +} +#endif + +static INT32 wmt_ctrl_evt_parser(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 ret = -1; + UINT32 evt_idx = (UINT32) pWmtCtrlData->au4CtrlData[0]; + UINT8 *p_buf = NULL; + + static UINT8 sleep_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x01 }; + static UINT8 wakeup_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; + static UINT8 hostawake_evt[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x02 }; + static UINT8 *evt_array[] = { sleep_evt, wakeup_evt, hostawake_evt }; + + p_buf = evt_array[evt_idx - 1]; + + WMT_INFO_FUNC("evt index:%d,p_buf:%p\n", evt_idx, p_buf); + + ret = mtk_wcn_consys_stp_btif_parser_wmt_evt(p_buf, 6); + if (ret == 1) { + WMT_INFO_FUNC("parser wmt evt from BTIF buf is OK\n"); + return 0; + } + WMT_ERR_FUNC("parser wmt evt from BTIF buf fail(%d)\n", ret); + return -1; +} + +INT32 wmt_ctrl_stp_conf_ex(WMT_STP_CONF_TYPE type, UINT32 value) +{ + INT32 iRet = -1; + + switch (type) { + case WMT_STP_CONF_EN: + iRet = mtk_wcn_stp_enable(value); + break; + + case WMT_STP_CONF_RDY: + iRet = mtk_wcn_stp_ready(value); + break; + + case WMT_STP_CONF_MODE: + mtk_wcn_stp_set_mode(value); + iRet = 0; + break; + + default: + WMT_WARN_FUNC("invalid type(%d) value(%d)\n", type, value); + break; + } + return iRet; +} + + +INT32 wmt_ctrl_stp_conf(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = -1; + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + UINT32 type; + UINT32 value; + + if (!osal_test_bit(WMT_STAT_STP_OPEN, &pDev->state)) { + WMT_WARN_FUNC("CTRL_STP_ENABLE but invalid Handle of WmtStp\n"); + return -1; + } + + type = pWmtCtrlData->au4CtrlData[0]; + value = pWmtCtrlData->au4CtrlData[1]; + iRet = wmt_ctrl_stp_conf_ex(type, value); + + if (!iRet) { + if (type == WMT_STP_CONF_EN) { + if (value) { + osal_set_bit(WMT_STAT_STP_EN, &pDev->state); + WMT_DBG_FUNC("enable STP\n"); + } else { + osal_clear_bit(WMT_STAT_STP_EN, &pDev->state); + WMT_DBG_FUNC("disable STP\n"); + } + } + if (type == WMT_STP_CONF_RDY) { + if (value) { + osal_set_bit(WMT_STAT_STP_RDY, &pDev->state); + WMT_DBG_FUNC("STP ready\n"); + } else { + osal_clear_bit(WMT_STAT_STP_RDY, &pDev->state); + WMT_DBG_FUNC("STP not ready\n"); + } + } + } + + return iRet; +} + + +INT32 wmt_ctrl_free_patch(P_WMT_CTRL_DATA pWmtCtrlData) +{ + UINT32 patchSeq = pWmtCtrlData->au4CtrlData[0]; + + WMT_DBG_FUNC("BF free patch, gDevWmt.pPatch(%p)\n", gDevWmt.pPatch); + if (gDevWmt.pPatch != NULL) + wmt_dev_patch_put((osal_firmware **) &(gDevWmt.pPatch)); + WMT_DBG_FUNC("AF free patch, gDevWmt.pPatch(%p)\n", gDevWmt.pPatch); + if (patchSeq == gDevWmt.patchNum) + WMT_DBG_FUNC("the %d patch has been download\n", patchSeq); + return 0; +} + +INT32 wmt_ctrl_get_patch_name(P_WMT_CTRL_DATA pWmtCtrlData) +{ + PUINT8 pBuf = (PUINT8) pWmtCtrlData->au4CtrlData[0]; + + osal_memcpy(pBuf, gDevWmt.cPatchName, osal_sizeof(gDevWmt.cPatchName)); + return 0; +} + +INT32 wmt_ctrl_crystal_triming_put(P_WMT_CTRL_DATA pWmtCtrlData) +{ + WMT_DBG_FUNC("BF free patch, gDevWmt.pPatch(%p)\n", gDevWmt.pPatch); + if (gDevWmt.pNvram != NULL) + wmt_dev_patch_put((osal_firmware **) &(gDevWmt.pNvram)); + WMT_DBG_FUNC("AF free patch, gDevWmt.pNvram(%p)\n", gDevWmt.pNvram); + return 0; +} + + +INT32 wmt_ctrl_crystal_triming_get(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = 0x0; + PUINT8 pFileName = (PUINT8) pWmtCtrlData->au4CtrlData[0]; + PPUINT8 ppBuf = (PPUINT8) pWmtCtrlData->au4CtrlData[1]; + PUINT32 pSize = (PUINT32) pWmtCtrlData->au4CtrlData[2]; + osal_firmware *pNvram = NULL; + + if ((pFileName == NULL) || (pSize == NULL)) { + WMT_ERR_FUNC("parameter error, pFileName(%p), pSize(%p)\n", pFileName, pSize); + iRet = -1; + return iRet; + } + if (wmt_dev_patch_get(pFileName, &pNvram) == 0) { + *ppBuf = (PUINT8)(pNvram)->data; + *pSize = (pNvram)->size; + gDevWmt.pNvram = pNvram; + return 0; + } + return -1; +} + + +INT32 wmt_ctrl_get_patch(P_WMT_CTRL_DATA pWmtCtrlData) +{ + PUINT8 pFullPatchName = NULL; + PUINT8 pDefPatchName = NULL; + PPUINT8 ppBuf = (PPUINT8) pWmtCtrlData->au4CtrlData[2]; + PUINT32 pSize = (PUINT32) pWmtCtrlData->au4CtrlData[3]; + osal_firmware *pPatch = NULL; + + pFullPatchName = (PUINT8) pWmtCtrlData->au4CtrlData[1]; + WMT_DBG_FUNC("BF get patch, pPatch(%p)\n", pPatch); + if ((pFullPatchName != NULL) + && (wmt_dev_patch_get(pFullPatchName, &pPatch) == 0)) { + /*get full name patch success */ + WMT_DBG_FUNC("get full patch name(%s) buf(0x%p) size(%zu)\n", + pFullPatchName, (pPatch)->data, (pPatch)->size); + WMT_DBG_FUNC("AF get patch, pPatch(%p)\n", pPatch); + *ppBuf = (PUINT8)(pPatch)->data; + *pSize = (pPatch)->size; + gDevWmt.pPatch = pPatch; + return 0; + } + + pDefPatchName = (PUINT8) pWmtCtrlData->au4CtrlData[0]; + if ((pDefPatchName != NULL) + && (wmt_dev_patch_get(pDefPatchName, &pPatch) == 0)) { + WMT_DBG_FUNC("get def patch name(%s) buf(0x%p) size(%zu)\n", + pDefPatchName, (pPatch)->data, (pPatch)->size); + WMT_DBG_FUNC("AF get patch, pPatch(%p)\n", pPatch); + /*get full name patch success */ + *ppBuf = (PUINT8)(pPatch)->data; + *pSize = (pPatch)->size; + gDevWmt.pPatch = pPatch; + return 0; + } + return -1; + +} + +INT32 wmt_ctrl_host_baudrate_set(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = -1; + INT8 cmdStr[NAME_MAX + 1] = { 0 }; + UINT32 u4Baudrate = pWmtCtrlData->au4CtrlData[0]; + UINT32 u4FlowCtrl = pWmtCtrlData->au4CtrlData[1]; + + WMT_DBG_FUNC("baud(%d), flowctrl(%d)\n", u4Baudrate, u4FlowCtrl); + + if (osal_test_bit(WMT_STAT_STP_OPEN, &gDevWmt.state)) { + osal_snprintf(cmdStr, NAME_MAX, "baud_%d_%d", u4Baudrate, u4FlowCtrl); + iRet = wmt_ctrl_ul_cmd(&gDevWmt, cmdStr); + if (iRet) + WMT_WARN_FUNC("CTRL_BAUDRATE baud(%d), flowctrl(%zu) fail(%d)\n", + u4Baudrate, pWmtCtrlData->au4CtrlData[1], iRet); + else + WMT_DBG_FUNC("CTRL_BAUDRATE baud(%d), flowctrl(%d) ok\n", + u4Baudrate, u4FlowCtrl); + } else + WMT_INFO_FUNC("CTRL_BAUDRATE but invalid Handle of WmtStp\n"); + return iRet; +} + +INT32 wmt_ctrl_sdio_hw(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = 0; + UINT32 statBit = WMT_STAT_SDIO1_ON; + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + + WMT_SDIO_SLOT_NUM sdioSlotNum = pWmtCtrlData->au4CtrlData[0]; + ENUM_FUNC_STATE funcState = pWmtCtrlData->au4CtrlData[1]; + + if ((sdioSlotNum == WMT_SDIO_SLOT_INVALID) + || (sdioSlotNum >= WMT_SDIO_SLOT_MAX)) { + WMT_WARN_FUNC("CTRL_SDIO_SLOT(%d) but invalid slot num\n", sdioSlotNum); + return -1; + } + + WMT_DBG_FUNC("WMT_CTRL_SDIO_HW (0x%x, %d)\n", sdioSlotNum, funcState); + + if (sdioSlotNum == WMT_SDIO_SLOT_SDIO2) + statBit = WMT_STAT_SDIO2_ON; + + if (funcState) { + if (osal_test_and_set_bit(statBit, &pDev->state)) { + WMT_WARN_FUNC("CTRL_SDIO_SLOT slotNum(%d) already ON\n", sdioSlotNum); + /* still return 0 */ + iRet = 0; + } else + iRet = wmt_plat_sdio_ctrl(sdioSlotNum, FUNC_ON); + } else { + if (osal_test_and_clear_bit(statBit, &pDev->state)) + iRet = wmt_plat_sdio_ctrl(sdioSlotNum, FUNC_OFF); + else { + WMT_WARN_FUNC("CTRL_SDIO_SLOT slotNum(%d) already OFF\n", sdioSlotNum); + /* still return 0 */ + iRet = 0; + } + } + + return iRet; +} + +INT32 wmt_ctrl_sdio_func(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = -1; + UINT32 statBit = WMT_STAT_SDIO_WIFI_ON; + INT32 retry = 10; + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + WMT_SDIO_FUNC_TYPE sdioFuncType = pWmtCtrlData->au4CtrlData[0]; + UINT32 u4On = pWmtCtrlData->au4CtrlData[1]; + + if (sdioFuncType >= WMT_SDIO_FUNC_MAX) { + WMT_ERR_FUNC("CTRL_SDIO_FUNC, invalid func type (%d)\n", sdioFuncType); + return -1; + } + + if (sdioFuncType == WMT_SDIO_FUNC_STP) + statBit = WMT_STAT_SDIO_STP_ON; + + if (u4On) { + if (osal_test_bit(statBit, &pDev->state)) { + WMT_WARN_FUNC("CTRL_SDIO_FUNC(%d) but already ON\n", sdioFuncType); + iRet = 0; + } else { + while (retry-- > 0 && iRet != 0) { + if (iRet) { + /* sleep 150ms before sdio slot ON ready */ + osal_sleep_ms(150); + } + iRet = + mtk_wcn_hif_sdio_wmt_control(sdioFuncType, MTK_WCN_BOOL_TRUE); + if (iRet == HIF_SDIO_ERR_NOT_PROBED) { + /* not probed case, retry */ + continue; + } else if (iRet == HIF_SDIO_ERR_CLT_NOT_REG) { + /* For WiFi, client not reg yet, no need to retry, + * WiFi function can work any time when wlan.ko is insert into system + */ + iRet = 0; + } else { + /* other fail cases, stop */ + break; + } + } + if (iRet) + WMT_ERR_FUNC + ("mtk_wcn_hif_sdio_wmt_control(%d, TRUE) fail(%d) retry(%d)\n", + sdioFuncType, iRet, retry); + else + osal_set_bit(statBit, &pDev->state); + } + } else { + if (osal_test_bit(statBit, &pDev->state)) { + iRet = mtk_wcn_hif_sdio_wmt_control(sdioFuncType, MTK_WCN_BOOL_FALSE); + if (iRet) + WMT_ERR_FUNC("mtk_wcn_hif_sdio_wmt_control(%d, FALSE) fail(%d)\n", + sdioFuncType, iRet); + /*any way, set to OFF state */ + osal_clear_bit(statBit, &pDev->state); + } else { + WMT_WARN_FUNC("CTRL_SDIO_FUNC(%d) but already OFF\n", sdioFuncType); + iRet = 0; + } + } + + return iRet; +} + +#if 0 +/* TODO: [FixMe][GeorgeKuo]: remove unused function. get hwver from core is not needed. */ +INT32 wmt_ctrl_hwver_get(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + + return 0; +} +#endif + +INT32 wmt_ctrl_hwidver_set(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + + /* input sanity check is done in wmt_ctrl() */ + pDev->chip_id = (pWmtCtrlData->au4CtrlData[0] & 0xFFFF0000) >> 16; + pDev->hw_ver = pWmtCtrlData->au4CtrlData[0] & 0x0000FFFF; + pDev->fw_ver = pWmtCtrlData->au4CtrlData[1] & 0x0000FFFF; + + return 0; +} + +static INT32 wmt_ctrl_gps_sync_set(P_WMT_CTRL_DATA pData) +{ + INT32 iret; + + WMT_DBG_FUNC("ctrl GPS_SYNC(%d)\n", + (pData->au4CtrlData[0] == 0) ? PIN_STA_DEINIT : PIN_STA_MUX); + iret = + wmt_plat_gpio_ctrl(PIN_GPS_SYNC, + (pData->au4CtrlData[0] == 0) ? PIN_STA_DEINIT : PIN_STA_MUX); + + if (iret) + WMT_WARN_FUNC("ctrl GPS_SYNC(%d) fail!(%d) ignore it...\n", + (pData->au4CtrlData[0] == 0) ? PIN_STA_DEINIT : PIN_STA_MUX, iret); + + return 0; +} + + +static INT32 wmt_ctrl_gps_lna_set(P_WMT_CTRL_DATA pData) +{ + INT32 iret; + + WMT_DBG_FUNC("ctrl GPS_LNA(%d)\n", + (pData->au4CtrlData[0] == 0) ? PIN_STA_DEINIT : PIN_STA_OUT_H); + iret = + wmt_plat_gpio_ctrl(PIN_GPS_LNA, + (pData->au4CtrlData[0] == 0) ? PIN_STA_DEINIT : PIN_STA_OUT_H); + + if (iret) + WMT_WARN_FUNC("ctrl GPS_SYNC(%d) fail!(%d) ignore it...\n", + (pData->au4CtrlData[0] == 0) ? PIN_STA_DEINIT : PIN_STA_OUT_H, iret); + + return 0; +} + + +INT32 wmt_ctrl_stp_rst(P_WMT_CTRL_DATA pWmtCtrlData) +{ + return 0; +} + +INT32 wmt_ctrl_get_wmt_conf(P_WMT_CTRL_DATA pWmtCtrlData) +{ + P_DEV_WMT pDev = &gDevWmt; /* single instance */ + + pWmtCtrlData->au4CtrlData[0] = (size_t) &pDev->rWmtGenConf; + + return 0; +} + +INT32 wmt_ctrl_others(P_WMT_CTRL_DATA pWmtCtrlData) +{ + WMT_ERR_FUNC("wmt_ctrl_others, invalid CTRL ID (%d)\n", pWmtCtrlData->ctrlId); + return -1; +} + + +INT32 wmt_ctrl_set_stp_dbg_info(P_WMT_CTRL_DATA pWmtCtrlData) +{ + PUINT8 pRomVer = NULL; + P_WMT_PATCH pPatch = NULL; + UINT32 chipID = 0; + + chipID = pWmtCtrlData->au4CtrlData[0]; + pRomVer = (PUINT8) (pWmtCtrlData->au4CtrlData[1]); + pPatch = (P_WMT_PATCH)(pWmtCtrlData->au4CtrlData[2]); + if (!pRomVer) { + WMT_ERR_FUNC("pRomVer null pointer\n"); + return -1; + } + + if (!pPatch) { + WMT_ERR_FUNC("pPatch null pointer\n"); + return -2; + } + WMT_DBG_FUNC("chipid(0x%x),rom(%s),patch date(%s),patch plat(%s)\n", chipID, pRomVer, + pPatch->ucDateTime, pPatch->ucPLat); + return stp_dbg_set_version_info(chipID, pRomVer, &(pPatch->ucDateTime[0]), + &(pPatch->ucPLat[0])); +} + +static INT32 wmt_ctrl_trg_assert(P_WMT_CTRL_DATA pWmtCtrlData) +{ + INT32 iRet = -1; + + ENUM_WMTDRV_TYPE_T drv_type; + UINT32 reason = 0; + PUINT8 keyword; + + drv_type = pWmtCtrlData->au4CtrlData[0]; + reason = pWmtCtrlData->au4CtrlData[1]; + keyword = (PUINT8) pWmtCtrlData->au4CtrlData[2]; + WMT_INFO_FUNC("wmt-ctrl:drv_type(%d),reason(%d),keyword(%s)\n", drv_type, reason, keyword); + + if (wmt_dev_is_close()) + WMT_INFO_FUNC("WMT is closing, don't trigger assert\n"); + else if (chip_reset_only == 1) + WMT_INFO_FUNC("Do chip reset only, don't trigger assert\n"); + else if (mtk_wcn_stp_get_wmt_trg_assert() == 0) { + mtk_wcn_stp_dbg_dump_package(); + mtk_wcn_stp_set_wmt_trg_assert(1); + mtk_wcn_stp_assert_flow_ctrl(1); + + iRet = mtk_wcn_stp_wmt_trg_assert(); + if (iRet == 0) { + wmt_lib_set_host_assert_info(drv_type, reason, 1); + stp_dbg_set_keyword(keyword); + } + } else + WMT_INFO_FUNC("do trigger assert & chip reset in stp noack\n"); + + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_exp.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_exp.c new file mode 100644 index 00000000000000..0070a59dec03a3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_exp.c @@ -0,0 +1,836 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-EXP]" + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "wmt_step.h" + +#include <wmt_exp.h> +#include <wmt_lib.h> +#include <wmt_detect.h> +#include <psm_core.h> +#include <hif_sdio.h> +#include <stp_dbg.h> +#include <stp_core.h> + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +wmt_wlan_probe_cb mtk_wcn_wlan_probe; +wmt_wlan_remove_cb mtk_wcn_wlan_remove; +wmt_wlan_bus_cnt_get_cb mtk_wcn_wlan_bus_tx_cnt; +wmt_wlan_bus_cnt_clr_cb mtk_wcn_wlan_bus_tx_cnt_clr; +wmt_wlan_emi_mpu_set_protection_cb mtk_wcn_wlan_emi_mpu_set_protection; +wmt_wlan_is_wifi_drv_own_cb mtk_wcn_wlan_is_wifi_drv_own; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +OSAL_BIT_OP_VAR gBtWifiGpsState; +OSAL_BIT_OP_VAR gGpsFmState; +UINT32 gWifiProbed; +INT32 gWmtDbgLvl = WMT_LOG_INFO; +MTK_WCN_BOOL g_pwr_off_flag = MTK_WCN_BOOL_TRUE; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static MTK_WCN_BOOL mtk_wcn_wmt_pwr_on(VOID); +static MTK_WCN_BOOL mtk_wcn_wmt_func_ctrl(ENUM_WMTDRV_TYPE_T type, ENUM_WMT_OPID_T opId); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static MTK_WCN_BOOL mtk_wcn_wmt_pwr_on(VOID) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + pSignal = &pOp->signal; + + pOp->op.opId = WMT_OPID_PWR_ON; + pSignal->timeoutValue = MAX_FUNC_ON_TIME; + pOp->op.au4OpData[0] = WMTDRV_TYPE_WMT; + + wmt_lib_host_awake_get(); + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) type(%zu) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + wmt_lib_host_awake_put(); + return MTK_WCN_BOOL_FALSE; + } + + bRet = wmt_lib_put_act_op(pOp); + + ENABLE_PSM_MONITOR(); + wmt_lib_host_awake_put(); + + if (bRet == MTK_WCN_BOOL_FALSE) + WMT_WARN_FUNC("OPID(%d) type(%zu) fail\n", pOp->op.opId, pOp->op.au4OpData[0]); + + return bRet; +} + +static MTK_WCN_BOOL mtk_wcn_wmt_func_ctrl(ENUM_WMTDRV_TYPE_T type, ENUM_WMT_OPID_T opId) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + MTK_WCN_BOOL bOffload; + MTK_WCN_BOOL bExplicitPwrOn; + + bOffload = (type == WMTDRV_TYPE_WIFI); + bExplicitPwrOn = (bOffload && opId == WMT_OPID_FUNC_ON && + wmt_lib_get_drv_status(WMTDRV_TYPE_WMT) != DRV_STS_FUNC_ON); + + /* WIFI on no need to disable psm and prevent WIFI on blocked by psm lock. */ + /* So we power on connsys separately from function on flow. */ + if (bExplicitPwrOn) + mtk_wcn_wmt_pwr_on(); + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + + pOp->op.opId = opId; + pOp->op.au4OpData[0] = type; + if (type == WMTDRV_TYPE_WIFI) + pSignal->timeoutValue = 4000; + else + pSignal->timeoutValue = (pOp->op.opId == WMT_OPID_FUNC_ON) ? MAX_FUNC_ON_TIME : MAX_FUNC_OFF_TIME; + + WMT_INFO_FUNC("wmt-exp: OPID(%d) type(%zu) start\n", pOp->op.opId, pOp->op.au4OpData[0]); + WMT_STEP_FUNC_CTRL_DO_ACTIONS_FUNC(type, opId); + + /*do not check return value, we will do this either way */ + wmt_lib_host_awake_get(); + /* wake up chip first */ + if (!bOffload) { + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) type(%zu) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + wmt_lib_host_awake_put(); + return MTK_WCN_BOOL_FALSE; + } + } + + bRet = wmt_lib_put_act_op(pOp); + if (!bOffload) + ENABLE_PSM_MONITOR(); + wmt_lib_host_awake_put(); + + if (bRet == MTK_WCN_BOOL_FALSE) + WMT_WARN_FUNC("OPID(%d) type(%zu) fail\n", pOp->op.opId, pOp->op.au4OpData[0]); + else + WMT_INFO_FUNC("OPID(%d) type(%zu) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + + return bRet; +} + +/* +INT32 mtk_wcn_wmt_psm_ctrl(MTK_WCN_BOOL flag) +{ + return -EFAULT; +} +EXPORT_SYMBOL(mtk_wcn_wmt_psm_ctrl); +*/ + +MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type) +{ + MTK_WCN_BOOL ret; + + if (type == WMTDRV_TYPE_BT) { + osal_printtimeofday("############ BT OFF ====>"); + } + + ret = mtk_wcn_wmt_func_ctrl(type, WMT_OPID_FUNC_OFF); + + if (type == WMTDRV_TYPE_BT) + osal_printtimeofday("############ BT OFF <===="); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_func_off); + +MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type) +{ + MTK_WCN_BOOL ret; + + if (type == WMTDRV_TYPE_BT) + osal_printtimeofday("############ BT ON ====>"); + + ret = mtk_wcn_wmt_func_ctrl(type, WMT_OPID_FUNC_ON); + + if (type == WMTDRV_TYPE_BT) + osal_printtimeofday(" ############BT ON <===="); + + return ret; +} +EXPORT_SYMBOL(mtk_wcn_wmt_func_on); + +/* +*return value: +*enable/disable thermal sensor function: true(1)/false(0) +*read thermal sensor function:thermal value +*/ +VOID mtk_wcn_wmt_func_ctrl_for_plat(UINT32 on, ENUM_WMTDRV_TYPE_T type) +{ + MTK_WCN_BOOL ret; + + if (on) + ret = mtk_wcn_wmt_func_on(type); + else + ret = mtk_wcn_wmt_func_off(type); + + WMT_INFO_FUNC("on=%d type=%d ret=%d\n", on, type, ret); +} +EXPORT_SYMBOL(mtk_wcn_wmt_func_ctrl_for_plat); + +INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType) +{ + P_OSAL_OP pOp; + P_WMT_OP pOpData; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + /*parameter validation check */ + if (eType > WMTTHERM_MAX || eType < WMTTHERM_ENABLE) { + WMT_ERR_FUNC("invalid thermal control command (%d)\n", eType); + return MTK_WCN_BOOL_FALSE; + } + + /*check if chip support thermal control function or not */ + bRet = wmt_lib_is_therm_ctrl_support(eType); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_DBG_FUNC("thermal ctrl function not supported\n"); + return MTK_WCN_BOOL_FALSE; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + pOpData = &pOp->op; + pOpData->opId = WMT_OPID_THERM_CTRL; + /*parameter fill */ + pOpData->au4OpData[0] = eType; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + + WMT_DBG_FUNC("OPID(%d) type(%zu) start\n", pOp->op.opId, pOp->op.au4OpData[0]); + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_BEFORE_READ_THERMAL); + + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) type(%zu) abort!\n", pOp->op.opId, pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("OPID(%d) type(%zu) fail\n\n", pOpData->opId, pOpData->au4OpData[0]); + /*0xFF means read error occurs */ + /*will return to function driver */ + pOpData->au4OpData[1] = (eType == WMTTHERM_READ) ? 0xFF : MTK_WCN_BOOL_FALSE; + } else + WMT_DBG_FUNC("OPID(%d) type(%zu) return(%zu) ok\n\n", + pOpData->opId, pOpData->au4OpData[0], pOpData->au4OpData[1]); + /*return value will be put to lxop->op.au4OpData[1] */ + WMT_DBG_FUNC("therm ctrl type(%d), iRet(0x%08zx)\n", eType, pOpData->au4OpData[1]); + + return (INT8) pOpData->au4OpData[1]; +} +EXPORT_SYMBOL(mtk_wcn_wmt_therm_ctrl); + +ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID) +{ + /* TODO: [ChangeFeature][GeorgeKuo] Reconsider usage of this type */ + /* TODO: how do we extend for new chip and newer revision? */ + /* TODO: This way is hard to extend */ + return wmt_lib_get_icinfo(WMTCHIN_MAPPINGHWVER); +} +EXPORT_SYMBOL(mtk_wcn_wmt_hwver_get); + +UINT32 mtk_wcn_wmt_ic_info_get(ENUM_WMT_CHIPINFO_TYPE_T type) +{ + return wmt_lib_get_icinfo(type); +} +EXPORT_SYMBOL(mtk_wcn_wmt_ic_info_get); + +MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType) +{ + P_OSAL_OP pOp; + P_WMT_OP pOpData; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + if (eType >= WMTDSNS_MAX) { + WMT_ERR_FUNC("invalid desense control command (%d)\n", eType); + return MTK_WCN_BOOL_FALSE; + } + + /*check if chip support thermal control function or not */ + bRet = wmt_lib_is_dsns_ctrl_support(); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_ERR_FUNC("thermal ctrl function not supported\n"); + return MTK_WCN_BOOL_FALSE; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + pOpData = &pOp->op; + pOpData->opId = WMT_OPID_DSNS; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + /*parameter fill */ + if ((eType >= WMTDSNS_FM_DISABLE) && (eType <= WMTDSNS_FM_GPS_ENABLE)) { + pOpData->au4OpData[0] = WMTDRV_TYPE_FM; + pOpData->au4OpData[1] = eType; + } + + WMT_INFO_FUNC("OPID(%d) type(%zu) start\n", pOp->op.opId, pOp->op.au4OpData[0]); + + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) type(%zu) abort!\n", pOp->op.opId, pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + return MTK_WCN_BOOL_FALSE; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + + if (bRet == MTK_WCN_BOOL_FALSE) + WMT_WARN_FUNC("OPID(%d) type(%zu) fail\n\n", pOpData->opId, pOpData->au4OpData[0]); + else + WMT_INFO_FUNC("OPID(%d) type(%zu) ok\n\n", pOpData->opId, pOpData->au4OpData[0]); + + return bRet; +} +EXPORT_SYMBOL(mtk_wcn_wmt_dsns_ctrl); + +INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) +{ + return (INT32) wmt_lib_msgcb_reg(eType, pCb); +} +EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_reg); + +INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) +{ + return (INT32) wmt_lib_msgcb_unreg(eType); +} +EXPORT_SYMBOL(mtk_wcn_wmt_msgcb_unreg); + +INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb) +{ + wmt_lib_ps_set_sdio_psop(own_cb); + return 0; +} +EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_op_reg); + +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +INT32 mtk_wcn_wmt_sdio_deep_sleep_flag_cb_reg(PF_WMT_SDIO_DEEP_SLEEP flag_cb) +{ + wmt_lib_sdio_deep_sleep_flag_set_cb_reg(flag_cb); + return 0; +} +EXPORT_SYMBOL(mtk_wcn_wmt_sdio_deep_sleep_flag_cb_reg); +#endif + +INT32 mtk_wcn_wmt_sdio_rw_cb_reg(PF_WMT_SDIO_DEBUG reg_rw_cb) +{ + wmt_lib_sdio_reg_rw_cb(reg_rw_cb); + return 0; +} + +INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID) +{ + wmt_lib_ps_irq_cb(); + return 0; +} +EXPORT_SYMBOL(mtk_wcn_stp_wmt_sdio_host_awake); + +MTK_WCN_BOOL mtk_wcn_wmt_assert_timeout(ENUM_WMTDRV_TYPE_T type, UINT32 reason, INT32 timeout) +{ + MTK_WCN_BOOL bRet; + + bRet = wmt_lib_trigger_assert(type, reason); + + return bRet == 0 ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE; +} +EXPORT_SYMBOL(mtk_wcn_wmt_assert_timeout); + +MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason) +{ + return mtk_wcn_wmt_assert_timeout(type, reason, MAX_EACH_WMT_CMD); +} +EXPORT_SYMBOL(mtk_wcn_wmt_assert); + +MTK_WCN_BOOL mtk_wcn_wmt_assert_keyword(ENUM_WMTDRV_TYPE_T type, PUINT8 keyword) +{ + MTK_WCN_BOOL bRet; + + bRet = wmt_lib_trigger_assert_keyword(type, 0, keyword); + + return bRet == 0 ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE; +} +EXPORT_SYMBOL(mtk_wcn_wmt_assert_keyword); + +/* +* ctrlId: get flash patch version opId or flash patch download opId +* pBuf: pointer to flash patch +* length: total length of flash patch +* type: flash patch type +* version: flash patch version +* checksum: flash patch checksum +*/ +ENUM_WMT_FLASH_PATCH_STATUS mtk_wcn_wmt_flash_patch_ctrl(ENUM_WMT_FLASH_PATCH_CTRL ctrlId, + PUINT8 pBuf, UINT32 length, ENUM_WMT_FLASH_PATCH_SEQ seq, ENUM_WMT_FLASH_PATCH_TYPE type, + PUINT32 version, UINT32 checksum) +{ + ENUM_WMT_FLASH_PATCH_STATUS eRet = 0; + P_OSAL_OP pOp = NULL; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_OSAL_SIGNAL pSignal; + + /*1. parameter validation check */ + /*for WMT_FLASH_PATCH_VERSION_GET, ignore pBuf and length */ + /*for WMT_ANT_RAM_DOWNLOAD, + * pBuf must not be NULL, kernel space memory pointer + * length must be large than 0 + */ + switch (ctrlId) { + case WMT_FLASH_PATCH_VERSION_GET: + break; + case WMT_FLASH_PATCH_DOWNLOAD: + if ((pBuf == NULL) || (length <= 0) || (length > 1000)) { + WMT_ERR_FUNC("error parameter detected, ctrlId:%d, pBuf:%p,length(0x%x).\n", + ctrlId, pBuf, length); + eRet = WMT_FLASH_PATCH_PARA_ERR; + goto exit; + } else + break; + default: + WMT_ERR_FUNC("error ctrlId:%d detected.\n", ctrlId); + eRet = WMT_FLASH_PATCH_PARA_ERR; + goto exit; + } + + /*get WMT opId */ + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + eRet = WMT_FLASH_PATCH_OP_ERR; + goto exit; + } + + pSignal = &pOp->signal; + pSignal->timeoutValue = + (ctrlId == WMT_FLASH_PATCH_DOWNLOAD) ? MAX_FUNC_ON_TIME : MAX_EACH_WMT_CMD; + + pOp->op.opId = (ctrlId == WMT_FLASH_PATCH_DOWNLOAD) ? + WMT_OPID_FLASH_PATCH_DOWN : WMT_OPID_FLASH_PATCH_VER_GET; + pOp->op.au4OpData[0] = (size_t) pBuf; + pOp->op.au4OpData[1] = length; + pOp->op.au4OpData[2] = seq; + pOp->op.au4OpData[3] = type; + pOp->op.au4OpData[4] = *version; + pOp->op.au4OpData[5] = checksum; + + /*disable PSM monitor */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + eRet = WMT_FLASH_PATCH_OP_ERR; + goto exit; + } + /*wakeup wmtd thread */ + bRet = wmt_lib_put_act_op(pOp); + + /*enable PSM monitor */ + ENABLE_PSM_MONITOR(); + + WMT_INFO_FUNC("CMD_TEST, opid (%d), ret(%d),retVal(%zu) result(%s)\n", + pOp->op.opId, + bRet, + pOp->op.au4OpData[6], MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed"); + + /*check return value and return result */ + if (bRet == MTK_WCN_BOOL_FALSE) { + eRet = WMT_FLASH_PATCH_OP_ERR; + } else { + switch (ctrlId) { + case WMT_FLASH_PATCH_VERSION_GET: + if (pOp->op.au4OpData[6] == 0) { + *version = pOp->op.au4OpData[4]; + eRet = WMT_FLASH_PATCH_VERSION_GET_OK; + } else + eRet = WMT_FLASH_PATCH_VERSION_GET_FAIL; + break; + case WMT_FLASH_PATCH_DOWNLOAD: + eRet = (pOp->op.au4OpData[6] == 0) ? + WMT_FLASH_PATCH_DOWNLOAD_OK : WMT_FLASH_PATCH_DOWNLOAD_FAIL; + break; + default: + WMT_ERR_FUNC("error ctrlId:%d detected.\n", ctrlId); + eRet = WMT_FLASH_PATCH_PARA_ERR; + break; + } + } + +exit: + return eRet; +} +EXPORT_SYMBOL(mtk_wcn_wmt_flash_patch_ctrl); + +#if !(DELETE_HIF_SDIO_CHRDEV) +extern INT32 mtk_wcn_wmt_chipid_query(VOID) +{ + return mtk_wcn_hif_sdio_query_chipid(0); +} +EXPORT_SYMBOL(mtk_wcn_wmt_chipid_query); +#endif + +INT8 mtk_wcn_wmt_co_clock_flag_get(void) +{ + return wmt_lib_co_clock_get(); +} +EXPORT_SYMBOL(mtk_wcn_wmt_co_clock_flag_get); + +INT32 mtk_wcn_wmt_system_state_reset(void) +{ + osal_memset(&gBtWifiGpsState, 0, osal_sizeof(gBtWifiGpsState)); + osal_memset(&gGpsFmState, 0, osal_sizeof(gGpsFmState)); + + return 0; +} + +INT32 mtk_wcn_wmt_wlan_reg(P_MTK_WCN_WMT_WLAN_CB_INFO pWmtWlanCbInfo) +{ + INT32 iRet = -1; + + if (!pWmtWlanCbInfo) { + WMT_ERR_FUNC("wlan cb info in null!\n"); + return -1; + } + + WMT_INFO_FUNC("wmt wlan cb register\n"); + mtk_wcn_wlan_probe = pWmtWlanCbInfo->wlan_probe_cb; + mtk_wcn_wlan_remove = pWmtWlanCbInfo->wlan_remove_cb; + mtk_wcn_wlan_bus_tx_cnt = pWmtWlanCbInfo->wlan_bus_cnt_get_cb; + mtk_wcn_wlan_bus_tx_cnt_clr = pWmtWlanCbInfo->wlan_bus_cnt_clr_cb; + mtk_wcn_wlan_emi_mpu_set_protection = pWmtWlanCbInfo->wlan_emi_mpu_set_protection_cb; + mtk_wcn_wlan_is_wifi_drv_own = pWmtWlanCbInfo->wlan_is_wifi_drv_own_cb; + + if (gWifiProbed) { + WMT_INFO_FUNC("wlan has been done power on,call probe directly\n"); + iRet = (*mtk_wcn_wlan_probe) (); + if (!iRet) { + WMT_INFO_FUNC("call wlan probe OK when do wlan register to wmt\n"); + gWifiProbed = 0; + } else { + WMT_ERR_FUNC("call wlan probe fail(%d) when do wlan register to wmt\n", iRet); + return -2; + } + } + return 0; +} +EXPORT_SYMBOL(mtk_wcn_wmt_wlan_reg); + +INT32 mtk_wcn_wmt_wlan_unreg(void) +{ + WMT_INFO_FUNC("wmt wlan cb unregister\n"); + mtk_wcn_wlan_probe = NULL; + mtk_wcn_wlan_remove = NULL; + mtk_wcn_wlan_bus_tx_cnt = NULL; + mtk_wcn_wlan_bus_tx_cnt_clr = NULL; + mtk_wcn_wlan_emi_mpu_set_protection = NULL; + mtk_wcn_wlan_is_wifi_drv_own = NULL; + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_wmt_wlan_unreg); + +MTK_WCN_BOOL mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL value) +{ + g_pwr_off_flag = value; + if (g_pwr_off_flag) + WMT_DBG_FUNC("enable connsys power off flag\n"); + else + WMT_INFO_FUNC("disable connsys power off, maybe need trigger coredump!\n"); + return g_pwr_off_flag; +} +EXPORT_SYMBOL(mtk_wcn_set_connsys_power_off_flag); + +#ifdef CONFIG_MTK_COMBO_ANT +/* +* ctrlId: get ram code status opId or ram code download opId +* pBuf: pointer to ANT ram code +* length: total length of ANT ram code +*/ +ENUM_WMT_ANT_RAM_STATUS mtk_wcn_wmt_ant_ram_ctrl(ENUM_WMT_ANT_RAM_CTRL ctrlId, PUINT8 pBuf, + UINT32 length, ENUM_WMT_ANT_RAM_SEQ seq) +{ + ENUM_WMT_ANT_RAM_STATUS eRet = 0; + P_OSAL_OP pOp = NULL; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_OSAL_SIGNAL pSignal; + + /*1. parameter validation check */ + /*for WMT_ANT_RAM_GET_STATUS, ignore pBuf and length */ + /*for WMT_ANT_RAM_DOWNLOAD, + * pBuf must not be NULL, kernel space memory pointer + * length must be large than 0 + */ + if ((ctrlId < WMT_ANT_RAM_GET_STATUS) || (ctrlId >= WMT_ANT_RAM_CTRL_MAX)) { + WMT_ERR_FUNC("error ctrlId:%d detected.\n", ctrlId); + eRet = WMT_ANT_RAM_PARA_ERR; + return eRet; + } + + if ((ctrlId == WMT_ANT_RAM_DOWNLOAD) && ((pBuf == NULL) || (length <= 0) || + (length > 1000) || (seq >= WMT_ANT_RAM_SEQ_MAX) || (seq < WMT_ANT_RAM_START_PKT))) { + eRet = WMT_ANT_RAM_PARA_ERR; + WMT_ERR_FUNC + ("error parameter detected, ctrlId:%d, pBuf:%p,length(0x%x),seq(%d) .\n", + ctrlId, pBuf, length, seq); + return eRet; + } + /*get WMT opId */ + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + pSignal->timeoutValue = + (ctrlId == WMT_ANT_RAM_DOWNLOAD) ? MAX_FUNC_ON_TIME : MAX_EACH_WMT_CMD; + + pOp->op.opId = + (ctrlId == WMT_ANT_RAM_DOWNLOAD) ? WMT_OPID_ANT_RAM_DOWN : WMT_OPID_ANT_RAM_STA_GET; + pOp->op.au4OpData[0] = (size_t) pBuf; + pOp->op.au4OpData[1] = length; + pOp->op.au4OpData[2] = seq; + + + /*disable PSM monitor */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return MTK_WCN_BOOL_FALSE; + } + /*wakeup wmtd thread */ + bRet = wmt_lib_put_act_op(pOp); + + /*enable PSM monitor */ + ENABLE_PSM_MONITOR(); + + WMT_INFO_FUNC("CMD_TEST, opid (%d), ret(%d),retVal(%zu) result(%s)\n", + pOp->op.opId, + bRet, + pOp->op.au4OpData[2], MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed"); + + /*check return value and return result */ + if (bRet == MTK_WCN_BOOL_FALSE) { + eRet = WMT_ANT_RAM_OP_ERR; + } else { + eRet = (ctrlId == WMT_ANT_RAM_DOWNLOAD) ? + WMT_ANT_RAM_DOWN_OK : + ((pOp->op.au4OpData[2] == 1) ? WMT_ANT_RAM_EXIST : WMT_ANT_RAM_NOT_EXIST); + } + + return eRet; + +} +EXPORT_SYMBOL(mtk_wcn_wmt_ant_ram_ctrl); +#endif +MTK_WCN_BOOL mtk_wcn_wmt_do_reset(ENUM_WMTDRV_TYPE_T type) +{ + INT32 iRet = -1; + UINT8 *drv_name[] = { + "DRV_TYPE_BT", + "DRV_TYPE_FM", + "DRV_TYPE_GPS", + "DRV_TYPE_WIFI", + "DRV_TYPE_WMT", + "DRV_TYPE_ANT" + }; + + WMT_INFO_FUNC("Subsystem trigger whole chip reset, reset source: %s\n", drv_name[type]); + if (mtk_wcn_stp_get_wmt_trg_assert() == 0) + iRet = wmt_lib_trigger_reset(); + else { + WMT_INFO_FUNC("assert has been triggered that no chip reset is required\n"); + iRet = 0; + } + + return iRet == 0 ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE; +} +EXPORT_SYMBOL(mtk_wcn_wmt_do_reset); + +VOID mtk_wcn_wmt_set_wifi_ver(UINT32 Value) +{ + wmt_lib_soc_set_wifiver(Value); +} +EXPORT_SYMBOL(mtk_wcn_wmt_set_wifi_ver); + +INT32 mtk_wcn_wmt_wifi_fem_cfg_report(PVOID pvInfoBuf) +{ + INT32 iRet = -1; + + iRet = wmt_lib_wifi_fem_cfg_report(pvInfoBuf); + return iRet; +} +EXPORT_SYMBOL(mtk_wcn_wmt_wifi_fem_cfg_report); + +VOID mtk_wcn_wmt_dump_wmtd_backtrace(VOID) +{ + wmt_lib_dump_wmtd_backtrace(); +} +EXPORT_SYMBOL(mtk_wcn_wmt_dump_wmtd_backtrace); + +UINT32 mtk_wmt_get_gps_lna_pin_num(VOID) +{ + return wmt_lib_get_gps_lna_pin_num(); +} +EXPORT_SYMBOL(mtk_wmt_get_gps_lna_pin_num); + +VOID mtk_wmt_set_ext_ldo(UINT32 flag) +{ + wmt_lib_set_ext_ldo(flag); +} +EXPORT_SYMBOL(mtk_wmt_set_ext_ldo); + +INT32 mtk_wmt_gps_mcu_ctrl(PUINT8 p_tx_data_buf, UINT32 tx_data_len, PUINT8 p_rx_data_buf, + UINT32 rx_data_buf_len, PUINT32 p_rx_data_len) +{ + return wmt_lib_gps_mcu_ctrl(p_tx_data_buf, tx_data_len, p_rx_data_buf, rx_data_buf_len, + p_rx_data_len); +} +EXPORT_SYMBOL(mtk_wmt_gps_mcu_ctrl); + +VOID mtk_wcn_wmt_set_mcif_mpu_protection(MTK_WCN_BOOL enable) +{ + mtk_consys_set_mcif_mpu_protection(enable); +} +EXPORT_SYMBOL(mtk_wcn_wmt_set_mcif_mpu_protection); + +MTK_WCN_BOOL mtk_wmt_gps_suspend_ctrl(MTK_WCN_BOOL suspend) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + + pOp->op.opId = WMT_OPID_GPS_SUSPEND; + pOp->op.au4OpData[0] = (MTK_WCN_BOOL_FALSE == suspend ? 0 : 1); + pSignal->timeoutValue = (MTK_WCN_BOOL_FALSE == suspend) ? MAX_FUNC_ON_TIME : MAX_FUNC_OFF_TIME; + + WMT_INFO_FUNC("wmt-exp: OPID(%d) type(%zu) start\n", pOp->op.opId, pOp->op.au4OpData[0]); + + /*do not check return value, we will do this either way */ + wmt_lib_host_awake_get(); + /* wake up chip first */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) type(%zu) abort\n", pOp->op.opId, pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + wmt_lib_host_awake_put(); + return MTK_WCN_BOOL_FALSE; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + wmt_lib_host_awake_put(); + + if (bRet == MTK_WCN_BOOL_FALSE) + WMT_WARN_FUNC("OPID(%d) type(%zu) fail\n", pOp->op.opId, pOp->op.au4OpData[0]); + else + WMT_INFO_FUNC("OPID(%d) type(%zu) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + + return bRet; +} +EXPORT_SYMBOL(mtk_wmt_gps_suspend_ctrl); + +INT32 mtk_wcn_wmt_mpu_lock_aquire(VOID) +{ + return wmt_lib_mpu_lock_aquire(); +} +EXPORT_SYMBOL(mtk_wcn_wmt_mpu_lock_aquire); + +VOID mtk_wcn_wmt_mpu_lock_release(VOID) +{ + wmt_lib_mpu_lock_release(); +} +EXPORT_SYMBOL(mtk_wcn_wmt_mpu_lock_release); + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_func.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_func.c new file mode 100644 index 00000000000000..9cff928054bb9f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_func.c @@ -0,0 +1,755 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-FUNC]" + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" + +#include "wmt_func.h" +#include "wmt_lib.h" +#include "wmt_core.h" +#include "wmt_exp.h" +#include "wmt_detect.h" + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CFG_FUNC_BT_SUPPORT + +static INT32 wmt_func_bt_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); +static INT32 wmt_func_bt_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); + +WMT_FUNC_OPS wmt_func_bt_ops = { + /* BT subsystem function on/off */ + .func_on = wmt_func_bt_on, + .func_off = wmt_func_bt_off +}; +#endif + +#if CFG_FUNC_FM_SUPPORT + +static INT32 wmt_func_fm_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); +static INT32 wmt_func_fm_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); + +WMT_FUNC_OPS wmt_func_fm_ops = { + /* FM subsystem function on/off */ + .func_on = wmt_func_fm_on, + .func_off = wmt_func_fm_off +}; +#endif + +#if CFG_FUNC_GPS_SUPPORT + +static INT32 wmt_func_gps_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); +static INT32 wmt_func_gps_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); + +WMT_FUNC_OPS wmt_func_gps_ops = { + /* GPS subsystem function on/off */ + .func_on = wmt_func_gps_on, + .func_off = wmt_func_gps_off +}; + +#endif + +#if CFG_FUNC_WIFI_SUPPORT +static INT32 wmt_func_wifi_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); +static INT32 wmt_func_wifi_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); +static INT32 wmt_func_wifi_ctrl(ENUM_FUNC_STATE funcState); + +WMT_FUNC_OPS wmt_func_wifi_ops = { + /* Wi-Fi subsystem function on/off */ + .func_on = wmt_func_wifi_on, + .func_off = wmt_func_wifi_off +}; +#endif + + +#if CFG_FUNC_ANT_SUPPORT + +static INT32 wmt_func_ant_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); +static INT32 wmt_func_ant_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf); + +WMT_FUNC_OPS wmt_func_ant_ops = { + /* BT subsystem function on/off */ + .func_on = wmt_func_ant_on, + .func_off = wmt_func_ant_off +}; +#endif + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if CFG_FUNC_GPS_SUPPORT +CMB_PIN_CTRL_REG eediPinOhRegs[] = { + { + /* pull down ctrl register */ + .regAddr = 0x80050020, + .regValue = ~(0x1L << 5), + .regMask = 0x00000020L, + }, + { + /* pull up ctrl register */ + .regAddr = 0x80050000, + .regValue = 0x1L << 5, + .regMask = 0x00000020L, + }, + { + /* iomode ctrl register */ + .regAddr = 0x80050110, + .regValue = 0x1L << 0, + .regMask = 0x00000007L, + }, + { + /* output high/low ctrl register */ + .regAddr = 0x80050040, + .regValue = 0x1L << 5, + .regMask = 0x00000020L, + } + +}; + +CMB_PIN_CTRL_REG eediPinOlRegs[] = { + { + .regAddr = 0x80050020, + .regValue = 0x1L << 5, + .regMask = 0x00000020L, + }, + { + .regAddr = 0x80050000, + .regValue = ~(0x1L << 5), + .regMask = 0x00000020L, + }, + { + .regAddr = 0x80050110, + .regValue = 0x1L << 0, + .regMask = 0x00000007L, + }, + { + .regAddr = 0x80050040, + .regValue = ~(0x1L << 5), + .regMask = 0x00000020L, + } +}; + +CMB_PIN_CTRL_REG eedoPinOhRegs[] = { + { + .regAddr = 0x80050020, + .regValue = ~(0x1L << 7), + .regMask = 0x00000080L, + }, + { + .regAddr = 0x80050000, + .regValue = 0x1L << 7, + .regMask = 0x00000080L, + }, + { + .regAddr = 0x80050110, + .regValue = 0x1L << 12, + .regMask = 0x00007000L, + }, + { + .regAddr = 0x80050040, + .regValue = 0x1L << 7, + .regMask = 0x00000080L, + } +}; + + +CMB_PIN_CTRL_REG eedoPinOlRegs[] = { + { + .regAddr = 0x80050020, + .regValue = 0x1L << 7, + .regMask = 0x00000080L, + }, + { + .regAddr = 0x80050000, + .regValue = ~(0x1L << 7), + .regMask = 0x00000080L, + }, + { + .regAddr = 0x80050110, + .regValue = 0x1L << 12, + .regMask = 0x00007000L, + }, + { + .regAddr = 0x80050040, + .regValue = ~(0x1L << 7), + .regMask = 0x00000080L, + } + +}; + +CMB_PIN_CTRL_REG gsyncPinOnRegs[] = { + { + .regAddr = 0x80050110, + .regValue = 0x3L << 20, + .regMask = 0x7L << 20, + } + +}; + +CMB_PIN_CTRL_REG gsyncPinOffRegs[] = { + { + .regAddr = 0x80050110, + .regValue = 0x0L << 20, + .regMask = 0x7L << 20, + } +}; + +/* templete usage for GPIO control */ +CMB_PIN_CTRL gCmbPinCtrl[3] = { + { + .pinId = CMB_PIN_EEDI_ID, + .regNum = 4, + .pFuncOnArray = eediPinOhRegs, + .pFuncOffArray = eediPinOlRegs, + }, + { + .pinId = CMB_PIN_EEDO_ID, + .regNum = 4, + .pFuncOnArray = eedoPinOhRegs, + .pFuncOffArray = eedoPinOlRegs, + }, + { + .pinId = CMB_PIN_GSYNC_ID, + .regNum = 1, + .pFuncOnArray = gsyncPinOnRegs, + .pFuncOffArray = gsyncPinOffRegs, + } +}; +#endif + + + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#if CFG_FUNC_BT_SUPPORT + + _osal_inline_ INT32 wmt_func_bt_ctrl(ENUM_FUNC_STATE funcState) +{ + /*only need to send turn BT subsystem wmt command */ + return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, + (FUNC_ON == + funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); +} + +INT32 wmt_func_bt_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + INT32 iRet = -1; + ULONG ctrlPa1; + ULONG ctrlPa2; + + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) + return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_TRUE); + + ctrlPa1 = BT_PALDO; + ctrlPa2 = PALDO_ON; + iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("wmt-func: wmt_ctrl_soc_paldo_ctrl failed(%d)(%lu)(%lu)\n", + iRet, ctrlPa1, ctrlPa2); + return -1; + } + iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_TRUE); + if (iRet) { + WMT_ERR_FUNC("wmt-func: wmt_core_func_ctrl_cmd(bt_on) failed(%d)\n", iRet); + ctrlPa1 = BT_PALDO; + ctrlPa2 = PALDO_OFF; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + + return -2; + } + osal_set_bit(WMT_BT_ON, &gBtWifiGpsState); + if (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState)) { + /* send msg to GPS native for sending de-sense CMD */ + ctrlPa1 = 1; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); + } + return 0; +} + +INT32 wmt_func_bt_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + INT32 iRet1 = -1; + INT32 iRet2 = -1; + ULONG ctrlPa1; + ULONG ctrlPa2; + + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) + return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_FALSE); + + iRet1 = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT, MTK_WCN_BOOL_FALSE); + if (iRet1) + WMT_ERR_FUNC("wmt-func: wmt_core_func_ctrl_cmd(bt_off) failed(%d)\n", iRet1); + + ctrlPa1 = BT_PALDO; + ctrlPa2 = PALDO_OFF; + iRet2 = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + if (iRet2) + WMT_ERR_FUNC("wmt-func: wmt_ctrl_soc_paldo_ctrl(bt_off) failed(%d)\n", iRet2); + + if (iRet1 + iRet2) + return -1; + + osal_clear_bit(WMT_BT_ON, &gBtWifiGpsState); + if ((!osal_test_bit(WMT_WIFI_ON, &gBtWifiGpsState)) && (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState))) { + /* send msg to GPS native for stopping send de-sense CMD */ + ctrlPa1 = 0; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); + } + return 0; +} + +#endif +#if CFG_FUNC_ANT_SUPPORT + + _osal_inline_ INT32 wmt_func_ant_ctrl(ENUM_FUNC_STATE funcState) +{ + /*only need to send turn BT subsystem wmt command */ + return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_ANT, + (FUNC_ON == + funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); +} + +INT32 wmt_func_ant_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_ANT, MTK_WCN_BOOL_TRUE); +} + +INT32 wmt_func_ant_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_ANT, MTK_WCN_BOOL_FALSE); +} + +#endif + +#if CFG_FUNC_GPS_SUPPORT + +_osal_inline_ INT32 wmt_func_gps_ctrl(ENUM_FUNC_STATE funcState) +{ + /*send turn GPS subsystem wmt command */ + return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_GPS, + (FUNC_ON == + funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); +} + +INT32 wmt_func_gps_pre_ctrl(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf, ENUM_FUNC_STATE funcStatus) +{ + UINT32 i = 0; + UINT32 iRet = 0; + UINT32 regAddr = 0; + UINT32 regValue = 0; + UINT32 regMask = 0; + UINT32 regNum = 0; + P_CMB_PIN_CTRL_REG pReg; + P_CMB_PIN_CTRL pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_GSYNC_ID]; + WMT_CTRL_DATA ctrlData; + WMT_IC_PIN_ID wmtIcPinId = WMT_IC_PIN_MAX; + /* sanity check */ + if (FUNC_ON != funcStatus && FUNC_OFF != funcStatus) { + WMT_ERR_FUNC("invalid funcStatus(%d)\n", funcStatus); + return -1; + } + /* turn on GPS sync function on both side */ + ctrlData.ctrlId = WMT_CTRL_GPS_SYNC_SET; + ctrlData.au4CtrlData[0] = (funcStatus == FUNC_ON) ? 1 : 0; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + /*we suppose this would never print */ + WMT_ERR_FUNC("ctrl GPS_SYNC_SET(%d) fail, ret(%d)\n", funcStatus, iRet); + /* TODO:[FixMe][George] error handling? */ + return -2; + } + WMT_DBG_FUNC("ctrl GPS_SYNC_SET(%d) ok\n", funcStatus); + + if ((pOps->ic_pin_ctrl == NULL) || (pOps->ic_pin_ctrl(WMT_IC_PIN_GSYNC, FUNC_ON == + funcStatus ? WMT_IC_PIN_MUX : WMT_IC_PIN_GPIO, 1) < 0)) { + /*WMT_IC_PIN_GSYNC */ + pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_GSYNC_ID]; + regNum = pCmbPinCtrl->regNum; + for (i = 0; i < regNum; i++) { + pReg = + FUNC_ON == + funcStatus ? &pCmbPinCtrl-> + pFuncOnArray[i] : &pCmbPinCtrl->pFuncOffArray[i]; + regAddr = pReg->regAddr; + regValue = pReg->regValue; + regMask = pReg->regMask; + + iRet = wmt_core_reg_rw_raw(1, regAddr, ®Value, regMask); + if (iRet) { + WMT_ERR_FUNC("set reg for GPS_SYNC function fail(%d)\n", iRet); + /* TODO:[FixMe][Chaozhong] error handling? */ + return -2; + } + + } + } else { + WMT_DBG_FUNC("set reg for GPS_SYNC function okay by chip ic_pin_ctrl\n"); + } + WMT_DBG_FUNC("ctrl combo chip gps sync function succeed\n"); + /* turn on GPS lna ctrl function */ + if (pConf != NULL) { + if (pConf->wmt_gps_lna_enable == 0) { + + WMT_INFO_FUNC("host pin used for gps lna\n"); + /* host LNA ctrl pin needed */ + ctrlData.ctrlId = WMT_CTRL_GPS_LNA_SET; + ctrlData.au4CtrlData[0] = funcStatus == FUNC_ON ? 1 : 0; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + /*we suppose this would never print */ + WMT_ERR_FUNC("ctrl host GPS_LNA output high fail, ret(%d)\n", iRet); + /* TODO:[FixMe][Chaozhong] error handling? */ + return -3; + } + WMT_INFO_FUNC("GPS LNA pin number(%d)\n", mtk_wmt_get_gps_lna_pin_num()); + WMT_DBG_FUNC("ctrl host gps lna function succeed\n"); + } else { + WMT_INFO_FUNC("combo chip pin(%s) used for gps lna\n", + pConf->wmt_gps_lna_pin == 0 ? "EEDI" : "EEDO"); + wmtIcPinId = + pConf->wmt_gps_lna_pin == 0 ? WMT_IC_PIN_EEDI : WMT_IC_PIN_EEDO; + if ((pOps->ic_pin_ctrl == NULL) || (pOps->ic_pin_ctrl(wmtIcPinId, FUNC_ON == + funcStatus ? WMT_IC_PIN_GPIO_HIGH : WMT_IC_PIN_GPIO_LOW, 1) < 0)) { + /*WMT_IC_PIN_GSYNC */ + if (pConf->wmt_gps_lna_pin == 0) { + /* EEDI needed */ + pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_EEDI_ID]; + } else if (pConf->wmt_gps_lna_pin == 1) { + /* EEDO needed */ + pCmbPinCtrl = &gCmbPinCtrl[CMB_PIN_EEDO_ID]; + } + regNum = pCmbPinCtrl->regNum; + for (i = 0; i < regNum; i++) { + pReg = + funcStatus == FUNC_ON ? &pCmbPinCtrl->pFuncOnArray[i] : + &pCmbPinCtrl->pFuncOffArray[i]; + regAddr = pReg->regAddr; + regValue = pReg->regValue; + regMask = pReg->regMask; + + iRet = wmt_core_reg_rw_raw(1, regAddr, ®Value, regMask); + if (iRet) { + WMT_ERR_FUNC + ("set reg for GPS_LNA function fail(%d)\n", + iRet); + /* TODO:[FixMe][Chaozhong] error handling? */ + return -3; + } + } + WMT_INFO_FUNC("ctrl combo chip gps lna succeed\n"); + } else { + WMT_INFO_FUNC + ("set reg for GPS_LNA function okay by chip ic_pin_ctrl\n"); + } + } + } + return 0; + +} + +INT32 wmt_func_gps_pre_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + return wmt_func_gps_pre_ctrl(pOps, pConf, FUNC_ON); +} + +INT32 wmt_func_gps_pre_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + + return wmt_func_gps_pre_ctrl(pOps, pConf, FUNC_OFF); +} + + +INT32 wmt_func_gps_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + INT32 iRet = 0; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); + + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) { + if ((co_clock_type) && (pConf->wmt_gps_lna_enable == 0)) { /* use SOC external LNA */ + if (!osal_test_bit(WMT_FM_ON, &gGpsFmState)) { + ctrlPa1 = GPS_PALDO; + ctrlPa2 = PALDO_ON; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + } else { + WMT_INFO_FUNC("LDO VCN28 has been turn on by FM\n"); + } + } + } + iRet = wmt_func_gps_pre_on(pOps, pConf); + if (iRet == 0) { + if (pConf->wmt_gps_suspend_ctrl == 0) + iRet = wmt_func_gps_ctrl(FUNC_ON); + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) { + if (!iRet) { + osal_set_bit(WMT_GPS_ON, &gBtWifiGpsState); + if ((osal_test_bit(WMT_BT_ON, &gBtWifiGpsState)) + || (osal_test_bit(WMT_WIFI_ON, &gBtWifiGpsState))) { + /* send msg to GPS native for sending de-sense CMD */ + ctrlPa1 = 1; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); + } + if ((co_clock_type) && (pConf->wmt_gps_lna_enable == 0)) /* use SOC external LNA */ + osal_set_bit(WMT_GPS_ON, &gGpsFmState); + osal_clear_bit(WMT_GPS_SUSPEND, &gGpsFmState); + } + } + } + return iRet; +} + +INT32 wmt_func_gps_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + INT32 iRet = 0; + unsigned long ctrlPa1 = 0; + unsigned long ctrlPa2 = 0; + UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); + + if (!osal_test_bit(WMT_GPS_SUSPEND, &gGpsFmState)) + iRet = wmt_func_gps_pre_off(pOps, pConf); + if (iRet == 0) { + if (pConf->wmt_gps_suspend_ctrl == 0) + iRet = wmt_func_gps_ctrl(FUNC_OFF); + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) { + if (!iRet) { + osal_clear_bit(WMT_GPS_ON, &gBtWifiGpsState); + if ((osal_test_bit(WMT_BT_ON, &gBtWifiGpsState)) + || (osal_test_bit(WMT_WIFI_ON, &gBtWifiGpsState))) { + /* send msg to GPS native for stop sending de-sense CMD */ + ctrlPa1 = 0; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); + } + } + } + } + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) { + if ((co_clock_type) && (pConf->wmt_gps_lna_enable == 0)) { /* use SOC external LNA */ + if (osal_test_bit(WMT_FM_ON, &gGpsFmState)) + WMT_INFO_FUNC("FM is still on, do not turn off LDO VCN28\n"); + else if (osal_test_bit(WMT_GPS_SUSPEND, &gGpsFmState)) + WMT_INFO_FUNC("It's GPS suspend mode, LDO VCN28 has been turned off\n"); + else { + ctrlPa1 = GPS_PALDO; + ctrlPa2 = PALDO_OFF; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + } + osal_clear_bit(WMT_GPS_ON, &gGpsFmState); + if (pConf->wmt_gps_suspend_ctrl == 1) + osal_set_bit(WMT_GPS_SUSPEND, &gGpsFmState); + } + } + return iRet; + +} +#endif + +#if CFG_FUNC_FM_SUPPORT + +_osal_inline_ INT32 wmt_func_fm_ctrl(ENUM_FUNC_STATE funcState) +{ + /*only need to send turn FM subsystem wmt command */ + return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, + (FUNC_ON == + funcState) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE); +} + + +INT32 wmt_func_fm_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + ULONG ctrlPa1 = 0; + ULONG ctrlPa2 = 0; + INT32 iRet = -1; + UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); + + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) { + if (co_clock_type) { + if (!osal_test_bit(WMT_GPS_ON, &gGpsFmState)) { + ctrlPa1 = FM_PALDO; + ctrlPa2 = PALDO_ON; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + } else { + WMT_INFO_FUNC("LDO VCN28 has been turn on by GPS\n"); + } + } else + WMT_ERR_FUNC("wmt-func: co_clock_type is not 1!\n"); + iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_TRUE); + if (!iRet) { + if (co_clock_type) + osal_set_bit(WMT_FM_ON, &gGpsFmState); + } + return iRet; + } + return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_TRUE); +} + +INT32 wmt_func_fm_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + ULONG ctrlPa1 = 0; + ULONG ctrlPa2 = 0; + INT32 iRet = -1; + UINT8 co_clock_type = (pConf->co_clock_flag & 0x0f); + + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) { + iRet = wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_FALSE); + if (co_clock_type) { + if (osal_test_bit(WMT_GPS_ON, &gGpsFmState)) { + WMT_INFO_FUNC("GPS is still on, do not turn off LDO VCN28\n"); + } else { + ctrlPa1 = FM_PALDO; + ctrlPa2 = PALDO_OFF; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + } + osal_clear_bit(WMT_FM_ON, &gGpsFmState); + } + return iRet; + } + return wmt_core_func_ctrl_cmd(WMTDRV_TYPE_FM, MTK_WCN_BOOL_FALSE); +} + +#endif + +#if CFG_FUNC_WIFI_SUPPORT + +INT32 wmt_func_wifi_ctrl(ENUM_FUNC_STATE funcState) +{ + INT32 iRet = 0; + ULONG ctrlPa1 = WMT_SDIO_FUNC_WIFI; + ULONG ctrlPa2 = (funcState == FUNC_ON) ? 1 : 0; /* turn on Wi-Fi driver */ + + iRet = wmt_core_ctrl(WMT_CTRL_SDIO_FUNC, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("WMT-FUNC: turn on WIFI function fail (%d)", iRet); + return -1; + } + return 0; +} + + +INT32 wmt_func_wifi_on(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + INT32 iRet = 0; + ULONG ctrlPa1; + ULONG ctrlPa2; + + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) + return wmt_func_wifi_ctrl(FUNC_ON); + + if (mtk_wcn_wlan_probe != NULL) { + WMT_WARN_FUNC("WMT-FUNC: wmt wlan func on before wlan probe\n"); + iRet = (*mtk_wcn_wlan_probe) (); + if (iRet) { + WMT_ERR_FUNC("WMT-FUNC: wmt call wlan probe fail(%d)\n", iRet); + iRet = -1; + } else { + WMT_WARN_FUNC("WMT-FUNC: wmt call wlan probe ok\n"); + } + } else { + WMT_ERR_FUNC("WMT-FUNC: null pointer mtk_wcn_wlan_probe\n"); + gWifiProbed = 1; + iRet = -2; + } + if (!iRet) { + osal_set_bit(WMT_WIFI_ON, &gBtWifiGpsState); + if (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState)) { + /* send msg to GPS native for sending de-sense CMD */ + ctrlPa1 = 1; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); + } + } + return iRet; +} + +INT32 wmt_func_wifi_off(P_WMT_IC_OPS pOps, P_WMT_GEN_CONF pConf) +{ + INT32 iRet = 0; + ULONG ctrlPa1 = 0; + ULONG ctrlPa2 = 0; + + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) + return wmt_func_wifi_ctrl(FUNC_OFF); + + if (mtk_wcn_wlan_remove != NULL) { + WMT_WARN_FUNC("WMT-FUNC: wmt wlan func on before wlan remove\n"); + iRet = (*mtk_wcn_wlan_remove) (); + if (iRet) { + WMT_ERR_FUNC("WMT-FUNC: wmt call wlan remove fail(%d)\n", iRet); + iRet = -1; + } else { + WMT_WARN_FUNC("WMT-FUNC: wmt call wlan remove ok\n"); + } + } else { + WMT_ERR_FUNC("WMT-FUNC: null pointer mtk_wcn_wlan_remove\n"); + iRet = -2; + } + if (!iRet) { + osal_clear_bit(WMT_WIFI_ON, &gBtWifiGpsState); + if ((!osal_test_bit(WMT_BT_ON, &gBtWifiGpsState)) && (osal_test_bit(WMT_GPS_ON, &gBtWifiGpsState))) { + /* send msg to GPS native for stopping send de-sense CMD */ + ctrlPa1 = 0; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_BGW_DESENSE_CTRL, &ctrlPa1, &ctrlPa2); + } + } + return iRet; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6620.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6620.c new file mode 100644 index 00000000000000..d9e99e1858d6e9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6620.c @@ -0,0 +1,1909 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-IC]" + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "osal.h" +#include "wmt_ic.h" +#include "wmt_core.h" +#include "wmt_lib.h" +#include "stp_core.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define DEFAULT_PATCH_FRAG_SIZE (1000) +#define MT6620E2_PATCH_FRAG_SIZE (900) +#define WMT_PATCH_FRAG_1ST (0x1) +#define WMT_PATCH_FRAG_MID (0x2) +#define WMT_PATCH_FRAG_LAST (0x3) + +#define CFG_CHECK_WMT_RESULT (1) +/* BT Port 2 Feature. this command does not need after coex command is downconfirmed by LC, */ +#define CFG_WMT_BT_PORT2 (0) + +#define CFG_SET_OPT_REG (0) +#define CFG_WMT_I2S_DBGUART_SUPPORT (0) +#define CFG_SET_OPT_REG_SWLA (0) +#define CFG_SET_OPT_REG_MCUCLK (0) +#define CFG_SET_OPT_REG_MCUIRQ (0) + +#define CFG_WMT_COREDUMP_ENABLE 0 + +#define CFG_WMT_MULTI_PATCH (1) +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +#if !(CFG_WMT_MULTI_PATCH) +static UINT8 gDefPatchName[NAME_MAX + 1]; +#endif +static UINT8 gFullPatchName[NAME_MAX + 1]; +static const WMT_IC_INFO_S *gp_mt6620_info; +static WMT_PATCH gp_mt6620_patch_info; + +static UINT8 WMT_WAKEUP_DIS_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x04 }; +static UINT8 WMT_WAKEUP_DIS_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x04 }; + +#if 0 +static UINT8 WMT_WAKEUP_EN_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x05 }; +static UINT8 WMT_WAKEUP_EN_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x05 }; +#endif +static UINT8 WMT_QUERY_BAUD_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x02 }; +static UINT8 WMT_QUERY_BAUD_EVT_115200[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x01, 0x00 }; +static UINT8 WMT_QUERY_BAUD_EVT_X[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0xAA, 0xAA, 0xAA, 0xBB }; +static UINT8 WMT_QUERY_STP_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x04 }; +static UINT8 WMT_QUERY_STP_EVT_DEFAULT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 }; +static UINT8 WMT_QUERY_STP_EVT_UART[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0xDF, 0x0E, 0x68, 0x01 }; +static UINT8 WMT_SET_BAUD_CMD_X[] = { 0x01, 0x04, 0x05, 0x00, 0x01, 0xAA, 0xAA, 0xAA, 0xBB }; +static UINT8 WMT_SET_BAUD_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x01 }; +static UINT8 WMT_SET_WAKEUP_WAKE_CMD_RAW[] = { 0xFF }; +static UINT8 WMT_SET_WAKEUP_WAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; + +#if CFG_WMT_MULTI_PATCH +static UINT8 WMT_PATCH_ADDRESS_CMD[] = { 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x64, 0x0E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_PATCH_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +static UINT8 WMT_PATCH_P_ADDRESS_CMD[] = { 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x38, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_PATCH_P_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; +#endif + +static UINT8 WMT_PATCH_CMD[] = { 0x01, 0x01, 0x00, 0x00, 0x00 }; +static UINT8 WMT_PATCH_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00 }; +static UINT8 WMT_RESET_CMD[] = { 0x01, 0x07, 0x01, 0x00, 0x04 }; +static UINT8 WMT_RESET_EVT[] = { 0x02, 0x07, 0x01, 0x00, 0x00 }; + +#if CFG_WMT_BT_PORT2 +static UINT8 WMT_BTP2_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x01, 0x03, 0x01 }; +static UINT8 WMT_BTP2_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#endif +/*coex cmd/evt++*/ +static UINT8 WMT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x04, 0x00, 0x01, 0xAA, 0xBB, 0xCC }; +static UINT8 WMT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_BT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0B, + 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, + 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA +}; +static UINT8 WMT_BT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0C, + 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA +}; +static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_PTA_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0A, + 0x00, 0x04, + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF, 0xFE +}; +static UINT8 WMT_PTA_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_MISC_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x09, + 0x00, 0x05, + 0xAA, 0xAA, 0xAA, 0xAA, + 0xBB, 0xBB, 0xBB, 0xBB +}; +static UINT8 WMT_MISC_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +/*coex cmd/evt--*/ +static UINT8 WMT_SET_STP_CMD[] = { 0x01, 0x04, 0x05, 0x00, 0x03, 0xDF, 0x0E, 0x68, 0x01 }; +static UINT8 WMT_SET_STP_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x03 }; +static UINT8 WMT_STRAP_CONF_CMD_FM_COMM[] = { 0x01, 0x05, 0x02, 0x00, 0x02, 0x02 }; +static UINT8 WMT_STRAP_CONF_EVT[] = { 0x02, 0x05, 0x02, 0x00, 0x00, 0x02 }; + +#if 0 +static UINT8 WMT_SET_OSC32K_BYPASS_CMD[] = { 0x01, 0x0A, 0x01, 0x00, 0x05 }; +static UINT8 WMT_SET_OSC32K_BYPASS_EVT[] = { 0x02, 0x0A, 0x01, 0x00, 0x00 }; +#endif + +static UINT8 WMT_CORE_DUMP_LEVEL_04_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UINT8 WMT_CORE_DUMP_LEVEL_04_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; + +/* enable all interrupt */ +static UINT8 WMT_SET_ALLINT_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x00, 0x03, 0x05, 0x80 /*addr:0x80050300 */ + , 0x00, 0xC4, 0x00, 0x00 /*value:0x0000C400 */ + , 0x00, 0xC4, 0x00, 0x00 /*mask:0x0000C400 */ +}; + +static UINT8 WMT_SET_ALLINT_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; + +#if CFG_SET_OPT_REG_SWLA /* enable swla: eesk(7) eecs(8) oscen(19) sck0(24) scs0(25) */ +static UINT8 WMT_SET_SWLA_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ + , 0x10, 0x01, 0x05, 0x80 /*addr:0x80050110 */ + , 0x10, 0x10, 0x01, 0x00 /*value:0x00011010 */ + , 0xF0, 0xF0, 0x0F, 0x00 /*mask:0x000FF0F0 */ + , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ + , 0x00, 0x10, 0x01, 0x00 /*value:0x00011000 */ + , 0x00, 0xF0, 0x0F, 0x00 /*mask:0x000FF000 */ +}; + +static UINT8 WMT_SET_SWLA_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ +}; +#endif + +#if CFG_SET_OPT_REG_MCUCLK /* enable mcu clk: antsel_4, eedi */ +static UINT8 WMT_SET_MCUCLK_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000 0400 */ + , 0x00, 0x14, 0x00, 0x00 /* value:0x0000 1400(osc, hclk), 0x0000 1501(PLL, en) */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005 0180 */ + , 0x12, 0x13, 0x00, 0x00 /* value:0x0000 1312(osc, hclk), 0x0000 1a19(PLL, en) */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005 0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002 0000 */ + , 0x00, 0x00, 0x0F, 0x00 /* mask:0x000F 0000 */ + , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005 0110 */ + , 0x02, 0x00, 0x00, 0x00 /* value:0x0000 0002 */ + , 0x0F, 0x00, 0x00, 0x00 /* mask:0x0000 000F */ +}; + +static UINT8 WMT_SET_MCUCLK_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ +}; +#endif + +#if CFG_WMT_I2S_DBGUART_SUPPORT /* register write for debug uart */ +static UINT8 WMT_SET_DBGUART_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ + , 0x30, 0x01, 0x05, 0x80 /*addr:0x80050130 */ + , 0x00, 0x00, 0x00, 0x00 /*value:0x00000000 */ + , 0xF0, 0x0F, 0x00, 0x00 /*mask:0x00000FF0 */ + , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ + , 0x00, 0x01, 0x00, 0x00 /*value:0x00000100 */ + , 0x00, 0x01, 0x00, 0x00 /*mask:0x00000100 */ +}; + +static UINT8 WMT_SET_DBGUART_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ +}; +#endif + +#if CFG_SET_OPT_REG_MCUIRQ /* enable mcu irq: antsel_4, wlan_act */ +#if 1 /* Ray */ +static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ + , 0x03, 0x14, 0x00, 0x00 /* value:0x0000_1403 check confg debug flag 3 low word */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000_FFFF */ + /* cirq_int_n */ + , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005_0110 */ + , 0x02, 0x00, 0x00, 0x00 /* value:0x0000_0002 set EEDI as cirq_int_n debug flag (monitor flag2) */ + , 0x07, 0x00, 0x00, 0x00 /* mask:0x0000_0007 */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0, ahb_x2_gt_ck debug flag) */ + , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ + /* 1. ARM irq_b, monitor flag 0 */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ + , 0x1F, 0x1E, 0x00, 0x00 /* value:0x0000_1E1F check mcusys debug flag */ + , 0x7F, 0x7F, 0x00, 0x00 /* mask:0x0000_7F7F */ +}; + +static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 5 registers */ +}; +#elif 0 /* KC */ +static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 5), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x05 /* 5 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ + , 0x00, 0x02, 0x00, 0x00 /* value:0x0000_0200 [15:8]=0x2 arm irq_b, 0xA irq_bus[5] bt_timcon_irq_b */ + , 0x00, 0xFF, 0x00, 0x00 /* mask:0x0000_FF00 */ + /* 1. ARM irq_b, monitor flag 0 */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ + , 0x18, 0x00, 0x00, 0x00 /* value:0x0000_0018 [6:0]=001_1000 (monitor flag 0 select, MCUSYS, SEL:8) */ + , 0x7F, 0x00, 0x00, 0x00 /* mask:0x0000_007F */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0) */ + , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ + /* 2. irq_bus[5] bt_timcon_irq_b monitor flag 15 */ + , 0xB0, 0x01, 0x05, 0x80 /* addr:0x8005_01B0 */ + , 0x00, 0x00, 0x00, 0x16 /* value:0x1600_0000 [30:24]=001_0110 (monitor flag 15 select, MCUSYS, SEL:6) */ + , 0x00, 0x00, 0x00, 0x7F /* mask:0x7F00_0000 */ + , 0x30, 0x01, 0x05, 0x80 /* addr:0x8005_0130 */ + , 0x00, 0x20, 0x00, 0x00 /* value:0x0000_2000 (WLAN_ACT=>monitor flag 15) */ + , 0x00, 0x70, 0x00, 0x00 /* mask:0x0000_7000 */ +}; + +static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x05 /* 5 registers */ +}; +#endif +#endif + +/* stp sdio init scripts */ +static struct init_script init_table_1_1[] = { + /* table_1_1 is only applied to common SDIO interface */ + INIT_CMD(WMT_SET_ALLINT_REG_CMD, WMT_SET_ALLINT_REG_EVT, "enable all interrupt"), + /* only applied to MT6620 E1/E2? */ + INIT_CMD(WMT_WAKEUP_DIS_GATE_CMD, WMT_WAKEUP_DIS_GATE_EVT, "disable gating"), +}; + + +static struct init_script init_table_1_2[] = { + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_115200, "query baud 115200"), + INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_DEFAULT, "query stp default"), + INIT_CMD(WMT_SET_BAUD_CMD_X, WMT_SET_BAUD_EVT, "set baud rate"), +}; + +static struct init_script init_table_2[] = { + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"), +}; + +static struct init_script init_table_3[] = { + INIT_CMD(WMT_RESET_CMD, WMT_RESET_EVT, "wmt reset"), +#if CFG_WMT_BT_PORT2 + INIT_CMD(WMT_BTP2_CMD, WMT_BTP2_EVT, "set bt port2"), +#endif +}; + +#if 0 +static struct init_script init_table_3_1[] = { + INIT_CMD(WMT_WAKEUP_EN_GATE_CMD, WMT_WAKEUP_EN_GATE_EVT, "ensable gating"), +}; +#endif + +static struct init_script init_table_4[] = { + INIT_CMD(WMT_SET_STP_CMD, WMT_SET_STP_EVT, "set stp"), +}; + +static struct init_script init_table_5[] = { + INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_UART, "query stp uart"), + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"), +}; + +static struct init_script init_table_5_1[] = { + INIT_CMD(WMT_STRAP_CONF_CMD_FM_COMM, WMT_STRAP_CONF_EVT, "configure FM comm"), +}; + +static struct init_script init_table_6[] = { +#if 0 + INIT_CMD(WMT_SET_OSC32K_BYPASS_CMD, WMT_SET_OSC32K_BYPASS_EVT, "set OSC32k by pass mode."), +#endif + INIT_CMD(WMT_CORE_DUMP_LEVEL_04_CMD, WMT_CORE_DUMP_LEVEL_04_EVT, "setup core dump level"), +}; + +#if defined(CFG_SET_OPT_REG) && CFG_SET_OPT_REG +static struct init_script set_registers[] = { + /* INIT_CMD(WMT_SET_GPS_REG_CMD, WMT_SET_GPS_REG_EVT, "set wmt registers"), */ + /* INIT_CMD(WMT_SET_SDIODRV_REG_CMD, WMT_SET_SDIODRV_REG_EVT, "set SDIO driving registers") */ +#if CFG_WMT_I2S_DBGUART_SUPPORT + INIT_CMD(WMT_SET_DBGUART_REG_CMD, WMT_SET_DBGUART_REG_EVT, "set debug uart registers"), +#endif +#if CFG_SET_OPT_REG_SWLA + INIT_CMD(WMT_SET_SWLA_REG_CMD, WMT_SET_SWLA_REG_EVT, "set swla registers"), +#endif +#if CFG_SET_OPT_REG_MCUCLK + INIT_CMD(WMT_SET_MCUCLK_REG_CMD, WMT_SET_MCUCLK_REG_EVT, "set mcuclk dbg registers"), +#endif +#if CFG_SET_OPT_REG_MCUIRQ + INIT_CMD(WMT_SET_MCUIRQ_REG_CMD, WMT_SET_MCUIRQ_REG_EVT, "set mcu irq dbg registers"), +#endif +}; +#endif + +static struct init_script coex_table[] = { + INIT_CMD(WMT_COEX_SETTING_CONFIG_CMD, WMT_COEX_SETTING_CONFIG_EVT, "coex_wmt"), + INIT_CMD(WMT_BT_COEX_SETTING_CONFIG_CMD, WMT_BT_COEX_SETTING_CONFIG_EVT, "coex_bt"), + INIT_CMD(WMT_WIFI_COEX_SETTING_CONFIG_CMD, WMT_WIFI_COEX_SETTING_CONFIG_EVT, "coex_wifi"), + INIT_CMD(WMT_PTA_COEX_SETTING_CONFIG_CMD, WMT_PTA_COEX_SETTING_CONFIG_EVT, "coex_ext_pta"), + INIT_CMD(WMT_MISC_COEX_SETTING_CONFIG_CMD, WMT_MISC_COEX_SETTING_CONFIG_EVT, "coex_misc"), +}; + +/* MT6620 Chip Version and Info Table */ +static const WMT_IC_INFO_S mt6620_info_table[] = { + { + .u4HwVer = 0x8A00, + .cChipName = WMT_IC_NAME_MT6620, + .cChipVersion = WMT_IC_VER_E1, + .cPatchNameExt = WMT_IC_PATCH_NO_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_FALSE, + }, + { + .u4HwVer = 0x8A01, + .cChipName = WMT_IC_NAME_MT6620, + .cChipVersion = WMT_IC_VER_E2, + .cPatchNameExt = WMT_IC_PATCH_NO_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_FALSE, + }, + { + .u4HwVer = 0x8A10, + .cChipName = WMT_IC_NAME_MT6620, + .cChipVersion = WMT_IC_VER_E3, + .cPatchNameExt = WMT_IC_PATCH_E3_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8A11, + .cChipName = WMT_IC_NAME_MT6620, + .cChipVersion = WMT_IC_VER_E4, + .cPatchNameExt = WMT_IC_PATCH_E3_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8A30, + .cChipName = WMT_IC_NAME_MT6620, + .cChipVersion = WMT_IC_VER_E6, + .cPatchNameExt = WMT_IC_PATCH_E6_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_TRUE /*MTK_WCN_BOOL_FALSE */, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8B30, + .cChipName = WMT_IC_NAME_MT6620, + .cChipVersion = WMT_IC_VER_E6, + .cPatchNameExt = WMT_IC_PATCH_E6_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_TRUE /*MTK_WCN_BOOL_FALSE */, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8B31, + .cChipName = WMT_IC_NAME_MT6620, + .cChipVersion = WMT_IC_VER_E7, + .cPatchNameExt = WMT_IC_PATCH_E6_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_TRUE /*MTK_WCN_BOOL_FALSE */, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, +}; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static INT32 mt6620_sw_init(P_WMT_HIF_CONF pWmtHifConf); + +static INT32 mt6620_sw_deinit(P_WMT_HIF_CONF pWmtHifConf); + +static INT32 mt6620_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag); + +static INT32 mt6620_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag); + +static INT32 mt6620_ver_check(VOID); + +static const WMT_IC_INFO_S *mt6620_find_wmt_ic_info(const UINT32 hw_ver); + +static INT32 wmt_stp_init_coex(VOID); + +#if CFG_WMT_MULTI_PATCH +static INT32 mt6620_patch_dwn(UINT32 index); +static INT32 mt6620_patch_info_prepare(VOID); +#else +static INT32 mt6620_update_patch_name(VOID); + +static INT32 mt6620_patch_dwn(VOID); +#endif +static MTK_WCN_BOOL mt6620_quick_sleep_flag_get(VOID); + +static MTK_WCN_BOOL mt6620_aee_dump_flag_get(VOID); + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/* MT6620 Operation Function Table */ +WMT_IC_OPS wmt_ic_ops_mt6620 = { + .icId = 0x6620, + .sw_init = mt6620_sw_init, + .sw_deinit = mt6620_sw_deinit, + .ic_pin_ctrl = mt6620_pin_ctrl, + .ic_ver_check = mt6620_ver_check, + .co_clock_ctrl = NULL, + .is_quick_sleep = mt6620_quick_sleep_flag_get, + .is_aee_dump_support = mt6620_aee_dump_flag_get, + .trigger_stp_assert = NULL, + .deep_sleep_ctrl = NULL, +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#if 0 +static INT32 mt6620_sw_init(P_WMT_HIF_CONF pWmtHifConf) +{ + INT32 iRet = -1; + UINT32 u4Res = 0; + UINT8 evtBuf[256]; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + UINT32 hw_ver; + + WMT_DBG_FUNC(" start\n"); + + osal_assert(gp_mt6620_info != NULL); + if ((gp_mt6620_info == NULL) + || (pWmtHifConf == NULL) + ) { + WMT_ERR_FUNC("null pointers: gp_mt6620_info(0x%p), pWmtHifConf(0x%p)\n", + gp_mt6620_info, pWmtHifConf); + return -1; + } + + hw_ver = gp_mt6620_info->u4HwVer; + + /* 4 <3.1> start init for sdio */ + if (pWmtHifConf->hifType == WMT_HIF_SDIO) { + /* 1. enable all INT32 */ + /* 2. disable mcu gate (only MT6620E1/E2) */ + iRet = wmt_core_init_script(init_table_1_1, osal_array_size(init_table_1_1)); + if (iRet) { + WMT_ERR_FUNC("init_table_1_1 fail:%d\n", iRet); + osal_assert(0); + return -1; + } + } + /* 4 <3.2> start init for uart */ + if (pWmtHifConf->hifType == WMT_HIF_UART) { + /* init variable fields for script execution */ + osal_memcpy(&WMT_SET_BAUD_CMD_X[5], &pWmtHifConf->au4HifConf[0], + osal_sizeof(UINT32)); + WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x00; /* 0xC0 MTK Flow Control no flow control */ + osal_memcpy(&WMT_QUERY_BAUD_EVT_X[6], &pWmtHifConf->au4HifConf[0], + osal_sizeof(UINT32)); + WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x00; /* 0xC0 MTK Flow Control no flow control */ + /* 3. Query chip baud rate (TEST-ONLY) */ + /* 4. Query chip STP options (TEST-ONLY) */ + /* 5. Change chip baud rate: t_baud */ + /* WMT_DBG_FUNC("WMT-CORE: init_table_1_2 set chip baud:%d", pWmtHifConf->au4HifConf[0]); + */ + iRet = wmt_core_init_script(init_table_1_2, osal_array_size(init_table_1_2)); + if (iRet) { + WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet); + osal_assert(0); + return -2; + } + + /* 6. Set host baudrate and flow control */ + ctrlPa1 = pWmtHifConf->au4HifConf[0]; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HOST_BAUDRATE_SET, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("change baudrate(%d) fail(%d)\n", pWmtHifConf->au4HifConf[0], + iRet); + return -3; + } + WMT_INFO_FUNC("WMT-CORE: change baudrate(%d) ok\n", pWmtHifConf->au4HifConf[0]); + + /* 7. Wake up chip and check event */ +/* iRet = (*kal_stp_tx_raw)(&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res); */ + iRet = + wmt_core_tx((PUINT8)&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res, + MTK_WCN_BOOL_TRUE); + if (iRet || (u4Res != 1)) { + WMT_ERR_FUNC("write raw iRet(%d) written(%d)\n", iRet, u4Res); + return -4; + } + + osal_memset(evtBuf, 0, osal_sizeof(evtBuf)); + iRet = wmt_core_rx(evtBuf, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT), &u4Res); +#ifdef CFG_DUMP_EVT + WMT_DBG_FUNC("WAKEUP_WAKE_EVT read len %d [%02x,%02x,%02x,%02x,%02x,%02x]\n", + (INT32) u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + evtBuf[5]); +#endif + if (iRet || (u4Res != osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT))) { + WMT_ERR_FUNC("read WAKEUP_WAKE_EVT fail(%d)\n", iRet); + return -5; + } + /* WMT_DBG_FUNC("WMT-CORE: read WMT_SET_WAKEUP_WAKE_EVT ok"); */ + +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp + (evtBuf, WMT_SET_WAKEUP_WAKE_EVT, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT)) != 0) { + WMT_ERR_FUNC("WMT-CORE: write WMT_SET_WAKEUP_WAKE_CMD_RAW status fail\n"); + return -6; + } +#endif + + /* 8. Query baud rate (TEST-ONLY) */ + iRet = wmt_core_init_script(init_table_2, osal_array_size(init_table_2)); + if (iRet) { + WMT_ERR_FUNC("init_table_2 fail(%d)\n", iRet); + return -7; + } + } + + /* 9. download patch */ + iRet = mt6620_patch_dwn(); + + WMT_INFO_FUNC("Not to check the patch validity\n"); +#if 0 + if (iRet) { + WMT_ERR_FUNC("patch dwn fail (%d)\n", iRet); + return -8; + } + WMT_INFO_FUNC("patch dwn ok\n"); +#endif + /* 10. WMT Reset command */ + iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3)); + if (iRet) { + WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); + return -9; + } + iRet = wmt_stp_init_coex(); + if (iRet) { + WMT_ERR_FUNC("init_coex fail(%d)\n", iRet); + return -10; + } + WMT_INFO_FUNC("init_coex ok\n"); + +#if 0 + /*10-2 enable 32K By Pass Mode */ + /* if hwVer = E3/E4, please enable 32K by pass mode. */ + /* does not support mt6620E1/E2, always enable 32k bypass mode */ + /* if ((hwVer == 0x8a10 || hwVer == 0x8a11)) */ + { + WMT_INFO_FUNC("WMT-CORE: init_table_6 OSC32K"); + iRet = wmt_core_init_script(init_table_6, osal_array_size(init_table_6)); + if (iRet == 0) { + WMT_DBG_FUNC("WMT-CORE: init_table_6 OSC32K, successful\n"); + } else { + WMT_WARN_FUNC("init table 6 OSC32K fail, continue init...\n"); + /*return -11; */ + } + } +#endif + + if (pWmtHifConf->hifType == WMT_HIF_UART) { + /* 11. Set chip STP options */ + iRet = wmt_core_init_script(init_table_4, osal_array_size(init_table_4)); + if (iRet) { + WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet); + return -12; + } + + /* 12. Enable host STP-UART mode */ + ctrlPa1 = WMT_STP_CONF_MODE; + ctrlPa2 = MTKSTP_UART_FULL_MODE; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 1; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("enable host STP-UART-FULL mode fail(%d)\n", iRet); + return -13; + } + WMT_INFO_FUNC("enable host STP-UART-FULL mode\n"); + /*13. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */ + osal_sleep_ms(10); + /* 14. Query chip STP options (TEST-ONLY) */ + /* 15. Query baud rate (stp, TEST-ONLY) */ + iRet = wmt_core_init_script(init_table_5, osal_array_size(init_table_5)); + if (iRet) { + WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet); + return -14; + } + } + + /* 15. Set FM strap */ + WMT_STRAP_CONF_CMD_FM_COMM[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; + WMT_STRAP_CONF_EVT[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; + iRet = wmt_core_init_script(init_table_5_1, osal_array_size(init_table_5_1)); + if (iRet) { + WMT_ERR_FUNC("init_table_5_1 fm mode(%d) fail(%d)\n", + pWmtHifConf->au4StrapConf[0], iRet); + return -15; + } + WMT_INFO_FUNC("set fm mode (%d) ok\n", pWmtHifConf->au4StrapConf[0]); + +#if CFG_SET_OPT_REG /*set registers */ + iRet = wmt_core_init_script(set_registers, osal_array_size(set_registers)); + if (iRet) { + WMT_ERR_FUNC("set_registers fail(%d)", iRet); + return -16; + } +#endif + +#if 0 + /* 16. trace32 dump when fw assert */ + { + INT32 val = 0x00000001; + + WMT_INFO_FUNC("WMT-CORE: enable assert dump"); + wmt_reg_rw_raw(1, 0x0100092c, &val, 0xFFFFFFFF); + } +#endif + +#if CFG_WMT_PS_SUPPORT + osal_assert(gp_mt6620_info != NULL); + if (gp_mt6620_info != NULL) { + if (gp_mt6620_info->bPsmSupport != MTK_WCN_BOOL_FALSE) + wmt_lib_ps_enable(); + else + wmt_lib_ps_disable(); + } +#endif + + return 0; +} +#endif + +static INT32 mt6620_sw_init(P_WMT_HIF_CONF pWmtHifConf) +{ + INT32 iRet = -1; + UINT32 u4Res = 0; + UINT8 evtBuf[256]; + ULONG ctrlPa1; + ULONG ctrlPa2; + UINT32 hw_ver; + UINT32 patch_num = 0; + UINT32 patch_index = 0; + WMT_CTRL_DATA ctrlData; + + WMT_DBG_FUNC(" start\n"); + + osal_assert(gp_mt6620_info != NULL); + if ((gp_mt6620_info == NULL) + || (pWmtHifConf == NULL) + ) { + WMT_ERR_FUNC("null pointers: gp_mt6620_info(0x%p), pWmtHifConf(0x%p)\n", + gp_mt6620_info, pWmtHifConf); + return -1; + } + + hw_ver = gp_mt6620_info->u4HwVer; + + /* 4 <3.1> start init for sdio */ + if (pWmtHifConf->hifType == WMT_HIF_SDIO) { + /* 1. enable all INT32 */ + /* 2. disable mcu gate (only MT6620E1/E2) */ + iRet = wmt_core_init_script(init_table_1_1, osal_array_size(init_table_1_1)); + if (iRet) { + WMT_ERR_FUNC("init_table_1_1 fail:%d\n", iRet); + osal_assert(0); + return -1; + } + } + /* 4 <3.2> start init for uart */ + if (pWmtHifConf->hifType == WMT_HIF_UART) { + + /* init variable fields for script execution */ + osal_memcpy(&WMT_SET_BAUD_CMD_X[5], &pWmtHifConf->au4HifConf[0], + osal_sizeof(UINT32)); + osal_memcpy(&WMT_QUERY_BAUD_EVT_X[6], &pWmtHifConf->au4HifConf[0], + osal_sizeof(UINT32)); + if (pWmtHifConf->uartFcCtrl == WMT_UART_MTK_SW_FC) { + WMT_INFO_FUNC("enable MTK SW Flow Control\n"); + WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x80; /* MTK SW flow control */ + WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x80; /* MTK SW flow control */ + } else if (pWmtHifConf->uartFcCtrl == WMT_UART_LUX_SW_FC) { + WMT_INFO_FUNC("enable Linux SW Flow Control\n"); + WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x80; /* Linux SW flow control */ + WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x80; /* Linux SW flow control */ + } else if (pWmtHifConf->uartFcCtrl == WMT_UART_HW_FC) { + WMT_INFO_FUNC("enable HW Flow Control\n"); + WMT_SET_BAUD_CMD_X[8] = (UINT8) 0xC0; /* HW flow control */ + WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0xC0; /* HW flow control */ + } else { + /* WMT_UART_NO_FC and all other cases!!! */ + WMT_INFO_FUNC("no Flow Control (uartFcCtrl:%d)\n", pWmtHifConf->uartFcCtrl); + WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x00; /* no flow control */ + WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x00; /* no flow control */ + } + + /* 3. Query chip baud rate (TEST-ONLY) */ + /* 4. Query chip STP options (TEST-ONLY) */ + /* 5. Change chip baud rate: t_baud */ + /* WMT_DBG_FUNC("WMT-CORE: init_table_1_2 set chip baud:%d", pWmtHifConf->au4HifConf[0]); */ + iRet = wmt_core_init_script(init_table_1_2, osal_array_size(init_table_1_2)); + if (iRet) { + WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet); + osal_assert(0); + return -2; + } + + /* 6. Set host baudrate and flow control */ + ctrlPa1 = pWmtHifConf->au4HifConf[0]; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HOST_BAUDRATE_SET, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("change baudrate(%d) fail(%d)\n", pWmtHifConf->au4HifConf[0], + iRet); + return -3; + } + WMT_INFO_FUNC("WMT-CORE: change baudrate(%d) ok\n", pWmtHifConf->au4HifConf[0]); + + /* 7. Wake up chip and check event */ +/* iRet = (*kal_stp_tx_raw)(&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res); */ + iRet = + wmt_core_tx((PUINT8)&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res, + MTK_WCN_BOOL_TRUE); + if (iRet || (u4Res != 1)) { + WMT_ERR_FUNC("write raw iRet(%d) written(%d)\n", iRet, u4Res); + return -4; + } + + osal_memset(evtBuf, 0, osal_sizeof(evtBuf)); + iRet = wmt_core_rx(evtBuf, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT), &u4Res); +#ifdef CFG_DUMP_EVT + WMT_DBG_FUNC("WAKEUP_WAKE_EVT read len %d [%02x,%02x,%02x,%02x,%02x,%02x]\n", + (INT32) u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + evtBuf[5]); +#endif + if (iRet || (u4Res != osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT))) { + WMT_ERR_FUNC("read WAKEUP_WAKE_EVT fail(%d)\n", iRet); + return -5; + } + /* WMT_DBG_FUNC("WMT-CORE: read WMT_SET_WAKEUP_WAKE_EVT ok"); */ + +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp + (evtBuf, WMT_SET_WAKEUP_WAKE_EVT, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT)) != 0) { + WMT_ERR_FUNC("WMT-CORE: write WMT_SET_WAKEUP_WAKE_CMD_RAW status fail\n"); + return -6; + } +#endif + + /* 8. Query baud rate (TEST-ONLY) */ + iRet = wmt_core_init_script(init_table_2, osal_array_size(init_table_2)); + if (iRet) { + WMT_ERR_FUNC("init_table_2 fail(%d)\n", iRet); + return -7; + } + } + if (pWmtHifConf->hifType == WMT_HIF_UART) { + /* 9. Set chip STP options */ + iRet = wmt_core_init_script(init_table_4, osal_array_size(init_table_4)); + if (iRet) { + WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet); + return -8; + } + + /* 10. Enable host STP-UART mode */ + ctrlPa1 = WMT_STP_CONF_MODE; + ctrlPa2 = MTKSTP_UART_FULL_MODE; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 1; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("enable host STP-UART-FULL mode fail(%d)\n", iRet); + return -9; + } + WMT_INFO_FUNC("enable host STP-UART-FULL mode\n"); + /*10. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */ + osal_sleep_ms(10); + /* 11. Query chip STP options (TEST-ONLY) */ + /* 12. Query baud rate (stp, TEST-ONLY) */ + iRet = wmt_core_init_script(init_table_5, osal_array_size(init_table_5)); + if (iRet) { + WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet); + return -10; + } + } + /* 13. download patch */ +#if CFG_WMT_MULTI_PATCH + iRet = mt6620_patch_info_prepare(); + if (iRet) { + WMT_ERR_FUNC("patch info perpare fail(%d)\n", iRet); + return -11; + } + + ctrlPa1 = 0; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_GET_PATCH_NUM, &ctrlPa1, &ctrlPa2); + patch_num = ctrlPa1; + WMT_INFO_FUNC("patch total num = [%d]\n", patch_num); + + for (patch_index = 0; patch_index < patch_num; patch_index++) { + iRet = mt6620_patch_dwn(patch_index); + if (iRet) { + WMT_ERR_FUNC("patch dwn fail (%d),patch_index(%d)\n", iRet, patch_index); + return -12; + } + iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3)); + if (iRet) { + WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); + return -13; + } + } +#else + iRet = mt6620_patch_dwn(); + + WMT_INFO_FUNC("Not to check the patch validity\n"); +#if 0 + if (iRet) { + WMT_ERR_FUNC("patch dwn fail (%d)\n", iRet); + return -11; + } + WMT_INFO_FUNC("patch dwn ok\n"); +#endif + /* 14. WMT Reset command */ + iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3)); + if (iRet) { + WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); + return -13; + } +#endif + iRet = wmt_stp_init_coex(); + if (iRet) { + WMT_ERR_FUNC("init_coex fail(%d)\n", iRet); + return -14; + } + WMT_INFO_FUNC("init_coex ok\n"); + +#if 0 + /*10-2 enable 32K By Pass Mode */ + /* if hwVer = E3/E4, please enable 32K by pass mode. */ + /* does not support mt6620E1/E2, always enable 32k bypass mode */ + /* if ((hwVer == 0x8a10 || hwVer == 0x8a11)) */ + { + WMT_INFO_FUNC("WMT-CORE: init_table_6 OSC32K"); + iRet = wmt_core_init_script(init_table_6, osal_array_size(init_table_6)); + if (iRet == 0) { + WMT_DBG_FUNC("WMT-CORE: init_table_6 OSC32K, successful\n"); + } else { + WMT_WARN_FUNC("init table 6 OSC32K fail, continue init...\n"); + /*return -14; */ + } + } +#endif + + + + /* 15. Set FM strap */ + WMT_STRAP_CONF_CMD_FM_COMM[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; + WMT_STRAP_CONF_EVT[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; + iRet = wmt_core_init_script(init_table_5_1, osal_array_size(init_table_5_1)); + if (iRet) { + WMT_ERR_FUNC("init_table_5_1 fm mode(%d) fail(%d)\n", + pWmtHifConf->au4StrapConf[0], iRet); + return -15; + } + WMT_INFO_FUNC("set fm mode (%d) ok\n", pWmtHifConf->au4StrapConf[0]); + +#if CFG_SET_OPT_REG /*set registers */ + iRet = wmt_core_init_script(set_registers, osal_array_size(set_registers)); + if (iRet) { + WMT_ERR_FUNC("set_registers fail(%d)", iRet); + return -16; + } +#endif + +#if 0 + /* 16. trace32 dump when fw assert */ + { + INT32 val = 0x00000001; + + WMT_INFO_FUNC("WMT-CORE: enable assert dump"); + wmt_reg_rw_raw(1, 0x0100092c, &val, 0xFFFFFFFF); + } +#endif + +#if CFG_WMT_COREDUMP_ENABLE + /*Open Core Dump Function @QC begin */ + mtk_wcn_stp_coredump_flag_ctrl(1); +#endif + if (mtk_wcn_stp_coredump_flag_get() != 0) { + iRet = wmt_core_init_script(init_table_6, osal_array_size(init_table_6)); + if (iRet) { + WMT_ERR_FUNC("init_table_6 core dump setting fail(%d)\n", iRet); + return -17; + } + WMT_INFO_FUNC("enable mt662x firmware coredump\n"); + } else + WMT_INFO_FUNC("disable mt662x firmware coredump\n"); + +#if 1 + ctrlData.ctrlId = WMT_CTRL_SET_STP_DBG_INFO; + ctrlData.au4CtrlData[0] = wmt_ic_ops_mt6620.icId; + ctrlData.au4CtrlData[1] = (size_t) gp_mt6620_info->cChipVersion; + ctrlData.au4CtrlData[2] = (size_t) &gp_mt6620_patch_info; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("set dump info fail(%d)\n", iRet); + return -16; + } +#endif + +#if CFG_WMT_PS_SUPPORT + osal_assert(gp_mt6620_info != NULL); + if (gp_mt6620_info != NULL) { + if (gp_mt6620_info->bPsmSupport != MTK_WCN_BOOL_FALSE) + wmt_lib_ps_enable(); + else + wmt_lib_ps_disable(); + } +#endif + + return 0; +} + + +static INT32 mt6620_sw_deinit(P_WMT_HIF_CONF pWmtHifConf) +{ + WMT_DBG_FUNC(" start\n"); + +#if CFG_WMT_PS_SUPPORT + osal_assert(gp_mt6620_info != NULL); + if ((gp_mt6620_info != NULL) + && (gp_mt6620_info->bPsmSupport != MTK_WCN_BOOL_FALSE)) { + wmt_lib_ps_disable(); + } +#endif + + gp_mt6620_info = NULL; + + return 0; +} + +static INT32 mt6620_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 ret = -1; + UINT32 val; + + if ((flag & WMT_LIB_AIF_FLAG_MASK) == WMT_LIB_AIF_FLAG_SHARE) { + WMT_INFO_FUNC("PCM & I2S PIN SHARE\n"); + switch (state) { + case WMT_IC_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + val = 0x00000770; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_1: + /* BT_PCM_ON & FM line in/out */ + val = 0x00000700; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_2: + /* BT_PCM_OFF & FM I2S */ + val = 0x00000710; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000800; /* 800:3-wire, 000: 4-wire */ + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + default: + WMT_ERR_FUNC("unsupported state (%d)\n", state); + ret = -1; + break; + } + } else { + /*PCM & I2S separate */ + WMT_INFO_FUNC("PCM & I2S PIN SEPARATE\n"); + switch (state) { + case WMT_IC_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + val = 0x00000770; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_1: + /* BT_PCM_ON & FM line in/out */ + val = 0x00000700; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_2: + /* BT_PCM_OFF & FM I2S */ + val = 0x00000070; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000800; /* 800:3-wire, 000: 4-wire */ + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + + break; + case WMT_IC_AIF_3: + val = 0x00000000; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000800; /* 800:3-wire, 000: 4-wire */ + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + default: + WMT_ERR_FUNC("unsupported state (%d)\n", state); + ret = -1; + break; + } + } + + if (!ret) + WMT_INFO_FUNC("new state(%d) ok\n", state); + else + WMT_WARN_FUNC("new state(%d) fail(%d)\n", state, ret); + + return ret; +} + +static INT32 mt6620_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 ret; + + WMT_DBG_FUNC("ic pin id:%d, state:%d, flag:0x%x\n", id, state, flag); + + ret = -1; + switch (id) { + case WMT_IC_PIN_AUDIO: + ret = mt6620_aif_ctrl(state, flag); + break; + + case WMT_IC_PIN_EEDI: + WMT_WARN_FUNC("TBD!!"); + ret = -1; + break; + + case WMT_IC_PIN_EEDO: + WMT_WARN_FUNC("TBD!!"); + ret = -1; + break; + case WMT_IC_PIN_GSYNC: + ret = -1; + WMT_WARN_FUNC("TBD!!"); + break; + default: + break; + } + WMT_INFO_FUNC("ret = (%d)\n", ret); + + return ret; +} + + +static MTK_WCN_BOOL mt6620_quick_sleep_flag_get(VOID) +{ + return MTK_WCN_BOOL_FALSE; +} + +static MTK_WCN_BOOL mt6620_aee_dump_flag_get(VOID) +{ + return MTK_WCN_BOOL_TRUE; +} + + +static INT32 mt6620_ver_check(VOID) +{ + UINT32 hw_ver = 0; + UINT32 fw_ver = 0; + INT32 iret; + const WMT_IC_INFO_S *p_info; + ULONG ctrlPa1; + ULONG ctrlPa2; + + /* 1. identify chip versions: HVR(HW_VER) and FVR(FW_VER) */ + WMT_LOUD_FUNC("MT6620: before read hw_ver (hw version)\n"); + iret = wmt_core_reg_rw_raw(0, GEN_HVR, &hw_ver, GEN_VER_MASK); + if (iret) { + WMT_ERR_FUNC("MT6620: read hw_ver fail:%d\n", iret); + return -2; + } + WMT_INFO_FUNC("MT6620: read hw_ver (hw version) (0x%x)\n", hw_ver); + + WMT_LOUD_FUNC("MT6620: before fw_ver (rom version)\n"); + wmt_core_reg_rw_raw(0, GEN_FVR, &fw_ver, GEN_VER_MASK); + if (iret) { + WMT_ERR_FUNC("MT6620: read fw_ver fail:%d\n", iret); + return -2; + } + WMT_INFO_FUNC("MT6620: read fw_ver (rom version) (0x%x)\n", fw_ver); + + p_info = mt6620_find_wmt_ic_info(hw_ver); + if (p_info == NULL) { + WMT_ERR_FUNC("MT6620: hw_ver(0x%x) find wmt ic info fail\n", hw_ver); + return -3; + } + + WMT_INFO_FUNC("MT6620: wmt ic info: %s.%s (0x%x, patch_ext:%s)\n", + p_info->cChipName, p_info->cChipVersion, + p_info->u4HwVer, p_info->cPatchNameExt); + + /* hw id & version */ + ctrlPa1 = (0x00006620UL << 16) | (hw_ver & 0x0000FFFF); + /* translated fw rom version */ + ctrlPa2 = (fw_ver & 0x0000FFFF); + + iret = wmt_core_ctrl(WMT_CTRL_HWIDVER_SET, &ctrlPa1, &ctrlPa2); + if (iret) + WMT_WARN_FUNC("MT6620: WMT_CTRL_HWIDVER_SET fail(%d)\n", iret); + + gp_mt6620_info = p_info; + return 0; +} + +static const WMT_IC_INFO_S *mt6620_find_wmt_ic_info(const UINT32 hw_ver) +{ + /* match chipversion with u4HwVer item in mt6620_info_table */ + const UINT32 size = osal_array_size(mt6620_info_table); + INT32 index; + + /* George: reverse the search order to favor newer version products */ + /* TODO:[FixMe][GeorgeKuo] Remove full match once API wmt_lib_get_hwver() + * is changed correctly in the future!! + */ + /* Leave full match here is a workaround for GPS to distinguish E3/E4 ICs. */ + index = size - 1; + /* full match */ + while ((index >= 0) + && (hw_ver != mt6620_info_table[index].u4HwVer) /* full match */ + ) { + --index; + } + if (index >= 0) { + WMT_INFO_FUNC("found ic info(0x%x) by full match! index:%d\n", hw_ver, index); + return &mt6620_info_table[index]; + } + WMT_WARN_FUNC("find no ic info for (0x%x) by full match!try major num match!\n", hw_ver); + + /* George: The ONLY CORRECT method to find supported hw table. Match MAJOR + * NUM only can help us support future minor hw ECO, or fab switch, etc. + * FULL matching eliminate such flexibility and software package have to be + * updated EACH TIME even when minor hw ECO or fab switch!!! + */ + /* George: reverse the search order to favor newer version products */ + index = size - 1; + /* major num match */ + while ((index >= 0) + && (MAJORNUM(hw_ver) != MAJORNUM(mt6620_info_table[index].u4HwVer)) + ) { + --index; + } + if (index >= 0) { + WMT_INFO_FUNC("MT6620: found ic info for hw_ver(0x%x) by major num! index:%d\n", + hw_ver, index); + return &mt6620_info_table[index]; + } + + WMT_ERR_FUNC + ("MT6620: find no ic info for hw_ver(0x%x) by full match nor major num match!\n", + hw_ver); + return NULL; +} + + +static INT32 wmt_stp_init_coex(VOID) +{ + INT32 iRet; + ULONG addr = 0; + WMT_GEN_CONF *pWmtGenConf; + +#define COEX_WMT 0 +#define COEX_BT 1 +#define COEX_WIFI 2 +#define COEX_PTA 3 +#define COEX_MISC 4 + + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + /*Dump the coex-related info */ + WMT_DBG_FUNC("coex_wmt:0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_wmt_ant_mode, + pWmtGenConf->coex_wmt_wifi_time_ctl, pWmtGenConf->coex_wmt_ext_pta_dev_on); + WMT_DBG_FUNC("coex_bt:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_bt_rssi_upper_limit, + pWmtGenConf->coex_bt_rssi_mid_limit, + pWmtGenConf->coex_bt_rssi_lower_limit, + pWmtGenConf->coex_bt_pwr_high, + pWmtGenConf->coex_bt_pwr_mid, pWmtGenConf->coex_bt_pwr_low); + WMT_DBG_FUNC("coex_wifi:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_wifi_rssi_upper_limit, + pWmtGenConf->coex_wifi_rssi_mid_limit, + pWmtGenConf->coex_wifi_rssi_lower_limit, + pWmtGenConf->coex_wifi_pwr_high, + pWmtGenConf->coex_wifi_pwr_mid, pWmtGenConf->coex_wifi_pwr_low); + WMT_DBG_FUNC("coex_ext_pta:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_ext_pta_hi_tx_tag, + pWmtGenConf->coex_ext_pta_hi_rx_tag, + pWmtGenConf->coex_ext_pta_lo_tx_tag, + pWmtGenConf->coex_ext_pta_lo_rx_tag, + pWmtGenConf->coex_ext_pta_sample_t1, + pWmtGenConf->coex_ext_pta_sample_t2, + pWmtGenConf->coex_ext_pta_wifi_bt_con_trx); + WMT_DBG_FUNC("coex_misc:0x%x 0x%x\n", + pWmtGenConf->coex_misc_ext_pta_on, pWmtGenConf->coex_misc_ext_feature_set); + + /*command adjustion due to WMT.cfg */ + coex_table[COEX_WMT].cmd[5] = pWmtGenConf->coex_wmt_ant_mode; + coex_table[COEX_WMT].cmd[6] = pWmtGenConf->coex_wmt_wifi_time_ctl; + coex_table[COEX_WMT].cmd[7] = pWmtGenConf->coex_wmt_ext_pta_dev_on; + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_WMT].cmd[0], + coex_table[COEX_WMT].str, coex_table[COEX_WMT].cmdSz); + } + + coex_table[COEX_BT].cmd[9] = pWmtGenConf->coex_bt_rssi_upper_limit; + coex_table[COEX_BT].cmd[10] = pWmtGenConf->coex_bt_rssi_mid_limit; + coex_table[COEX_BT].cmd[11] = pWmtGenConf->coex_bt_rssi_lower_limit; + coex_table[COEX_BT].cmd[12] = pWmtGenConf->coex_bt_pwr_high; + coex_table[COEX_BT].cmd[13] = pWmtGenConf->coex_bt_pwr_mid; + coex_table[COEX_BT].cmd[14] = pWmtGenConf->coex_bt_pwr_low; + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_BT].cmd[0], + coex_table[COEX_BT].str, coex_table[COEX_BT].cmdSz); + } + coex_table[COEX_WIFI].cmd[10] = pWmtGenConf->coex_wifi_rssi_upper_limit; + coex_table[COEX_WIFI].cmd[11] = pWmtGenConf->coex_wifi_rssi_mid_limit; + coex_table[COEX_WIFI].cmd[12] = pWmtGenConf->coex_wifi_rssi_lower_limit; + coex_table[COEX_WIFI].cmd[13] = pWmtGenConf->coex_wifi_pwr_high; + coex_table[COEX_WIFI].cmd[14] = pWmtGenConf->coex_wifi_pwr_mid; + coex_table[COEX_WIFI].cmd[15] = pWmtGenConf->coex_wifi_pwr_low; + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_WIFI].cmd[0], + coex_table[COEX_WIFI].str, coex_table[COEX_WIFI].cmdSz); + } + coex_table[COEX_PTA].cmd[5] = pWmtGenConf->coex_ext_pta_hi_tx_tag; + coex_table[COEX_PTA].cmd[6] = pWmtGenConf->coex_ext_pta_hi_rx_tag; + coex_table[COEX_PTA].cmd[7] = pWmtGenConf->coex_ext_pta_lo_tx_tag; + coex_table[COEX_PTA].cmd[8] = pWmtGenConf->coex_ext_pta_lo_rx_tag; + coex_table[COEX_PTA].cmd[9] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0xff00) >> 8); + coex_table[COEX_PTA].cmd[10] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0x00ff) >> 0); + coex_table[COEX_PTA].cmd[11] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0xff00) >> 8); + coex_table[COEX_PTA].cmd[12] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0x00ff) >> 0); + coex_table[COEX_PTA].cmd[13] = pWmtGenConf->coex_ext_pta_wifi_bt_con_trx; + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_PTA].cmd[0], + coex_table[COEX_PTA].str, coex_table[COEX_PTA].cmdSz); + } + + osal_memcpy(&coex_table[COEX_MISC].cmd[5], &pWmtGenConf->coex_misc_ext_pta_on, + sizeof(pWmtGenConf->coex_misc_ext_pta_on)); + osal_memcpy(&coex_table[COEX_MISC].cmd[9], &pWmtGenConf->coex_misc_ext_feature_set, + sizeof(pWmtGenConf->coex_misc_ext_feature_set)); + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_MISC].cmd[0], coex_table[COEX_MISC].str, + coex_table[COEX_MISC].cmdSz); + } + iRet = wmt_core_init_script(coex_table, ARRAY_SIZE(coex_table)); + + return iRet; +} + +#if CFG_WMT_MULTI_PATCH + +static INT32 mt6620_patch_info_prepare(VOID) +{ + INT32 iRet = -1; + WMT_CTRL_DATA ctrlData; + + ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; + iRet = wmt_ctrl(&ctrlData); + + return iRet; +} + +static INT32 mt6620_patch_dwn(UINT32 index) +{ + INT32 iRet = -1; + P_WMT_PATCH patchHdr = NULL; + PUINT8 pbuf = NULL; + UINT32 patchSize = 0; + UINT32 fragSeq = 0; + UINT32 fragNum = 0; + UINT16 fragSize = 0; + UINT16 cmdLen; + UINT32 offset; + UINT32 u4Res; + UINT8 patchevtBuf[8]; + UINT8 addressevtBuf[12]; + UINT8 addressByte[4]; + PINT8 cDataTime = NULL; + /*PINT8 cPlat = NULL; */ + UINT16 u2HwVer = 0; + UINT16 u2SwVer = 0; + UINT32 u4PatchVer = 0; + UINT32 patchSizePerFrag = 0; + WMT_CTRL_DATA ctrlData; + + /*1.check hardware information */ + if (gp_mt6620_info == NULL) { + WMT_ERR_FUNC("null gp_mt6620_info!\n"); + return -1; + } + + osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName)); + + ctrlData.ctrlId = WMT_CTRL_GET_PATCH_INFO; + ctrlData.au4CtrlData[0] = index + 1; + ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName; + ctrlData.au4CtrlData[2] = (size_t) &addressByte; + iRet = wmt_ctrl(&ctrlData); + WMT_INFO_FUNC("the %d time valid patch found: (%s)\n", index + 1, gFullPatchName); + /* <2.2> read patch content */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH; + ctrlData.au4CtrlData[0] = (size_t) NULL; + ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName; + + ctrlData.au4CtrlData[2] = (size_t) &pbuf; + ctrlData.au4CtrlData[3] = (size_t) &patchSize; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); + iRet -= 1; + goto done; + } + + /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ + pbuf += BCNT_PATCH_BUF_HEADROOM; + /* patch file with header: + * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| + */ + patchHdr = (P_WMT_PATCH) pbuf; + /* check patch file information */ + + cDataTime = patchHdr->ucDateTime; + u2HwVer = patchHdr->u2HwVer; + u2SwVer = patchHdr->u2SwVer; + u4PatchVer = patchHdr->u4PatchVer; + /*cPlat = &patchHdr->ucPLat[0]; */ + cDataTime[15] = '\0'; + + /* remove patch header: + * |<-patch body: X Bytes (X=patchSize)--->| + */ + if (patchSize < sizeof(WMT_PATCH)) { + WMT_ERR_FUNC("error patch size\n"); + iRet = -1; + goto done; + } + patchSize -= sizeof(WMT_PATCH); + pbuf += sizeof(WMT_PATCH); + + if (index == 0) { + WMT_INFO_FUNC("===========================================\n"); + WMT_INFO_FUNC("[Combo Patch] Built Time = %s\n", cDataTime); + WMT_INFO_FUNC("[Combo Patch] Hw Ver = 0x%x\n", + ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8)); + WMT_INFO_FUNC("[Combo Patch] Sw Ver = 0x%x\n", + ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8)); + WMT_INFO_FUNC("[Combo Patch] Ph Ver = 0x%04x\n", + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> + 16)); + WMT_INFO_FUNC("[Combo Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0], + patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + WMT_INFO_FUNC("[Combo Patch] Content Size = 0x%x\n", patchSize); + WMT_INFO_FUNC("[Combo Patch] Content CRC = 0x%04x\n", osal_crc16(pbuf, patchSize)); + WMT_INFO_FUNC("===========================================\n"); + } + + patchSizePerFrag = (MAJORNUM(gp_mt6620_info->u4HwVer) != 0) ? + DEFAULT_PATCH_FRAG_SIZE : MT6620E2_PATCH_FRAG_SIZE; + + /* reserve 1st patch cmd space before patch body + * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| + */ + osal_memcpy(&gp_mt6620_patch_info, patchHdr, osal_sizeof(WMT_PATCH)); + pbuf -= sizeof(WMT_PATCH_CMD); + + fragNum = patchSize / patchSizePerFrag; + fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; + + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + /*send wmt part patch address command */ + iRet = + wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD[0], sizeof(WMT_PATCH_ADDRESS_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD))) { + WMT_ERR_FUNC("wmt_core:wmt patch address CMD fail(%d),size(%d)\n", iRet, u4Res); + iRet -= 1; + goto done; + } + osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); + iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT))) { + WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res); + iRet -= 1; + goto done; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(addressevtBuf, WMT_PATCH_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) != + 0) { + WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail\n"); + iRet -= 1; + goto done; + } +#endif + + /*send part patch address command */ + osal_memcpy(&WMT_PATCH_P_ADDRESS_CMD[12], addressByte, osal_sizeof(addressByte)); + WMT_INFO_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x", + WMT_PATCH_P_ADDRESS_CMD[12], WMT_PATCH_P_ADDRESS_CMD[13], + WMT_PATCH_P_ADDRESS_CMD[14], WMT_PATCH_P_ADDRESS_CMD[15]); + iRet = + wmt_core_tx((PUINT8) &WMT_PATCH_P_ADDRESS_CMD[0], sizeof(WMT_PATCH_P_ADDRESS_CMD), + &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_CMD))) { + WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d),index(%d)\n", + iRet, u4Res, index); + iRet -= 1; + goto done; + } + osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); + iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_P_ADDRESS_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_EVT))) { + WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d),index(%d)\n", iRet, + u4Res, index); + iRet -= 1; + goto done; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(addressevtBuf, WMT_PATCH_P_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) + != 0) { + WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail,index(%d)\n", + index); + iRet -= 1; + goto done; + } +#endif + /* send all fragments */ + offset = sizeof(WMT_PATCH_CMD); + fragSeq = 0; + while (fragSeq < fragNum) { + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + if (fragSeq == (fragNum - 1)) { + /* last fragment */ + fragSize = patchSize - fragSeq * patchSizePerFrag; + WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; + } else { + fragSize = patchSizePerFrag; + WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; + } + /* update length field in CMD:flag+frag */ + cmdLen = 1 + fragSize; + osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); + /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ + osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, + sizeof(WMT_PATCH_CMD)); + /* iRet = (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), + * fragSize + sizeof(WMT_PATCH_CMD), &u4Res); + */ + iRet = + wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD), + fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) fail(%d)\n", fragSeq, + fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); + iRet = -4; + break; + } + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) ok\n", + fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); + + osal_memset(patchevtBuf, 0, sizeof(patchevtBuf)); + /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ + iRet = wmt_core_rx(patchevtBuf, sizeof(WMT_PATCH_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) fail(%d)\n", + sizeof(WMT_PATCH_EVT), u4Res, iRet); + iRet = -5; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(patchevtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, patchevtBuf[0], patchevtBuf[1], patchevtBuf[2], patchevtBuf[3], + patchevtBuf[4], sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0], + WMT_PATCH_EVT[1], WMT_PATCH_EVT[2], WMT_PATCH_EVT[3], + WMT_PATCH_EVT[4]); + iRet = -6; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) ok\n", + sizeof(WMT_PATCH_EVT), u4Res); + +#if 0 + WMT_DBG_FUNC("wmt_core: send patch frag(%d) [%02X,%02X,%02X,%02X,%02X] (%d) ok", + fragSeq, WMT_PATCH_CMD[0], WMT_PATCH_CMD[1], WMT_PATCH_CMD[2], + WMT_PATCH_CMD[3], WMT_PATCH_CMD[4], fragSize); +#endif + + offset += patchSizePerFrag; + ++fragSeq; + } + + WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", + iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); + + if (fragSeq != fragNum) + iRet = -7; +done: + /* WMT_CTRL_FREE_PATCH always return 0 */ + ctrlData.ctrlId = WMT_CTRL_FREE_PATCH; + ctrlData.au4CtrlData[0] = index + 1; + wmt_ctrl(&ctrlData); + /* wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); */ + if ((iRet == -2) || (iRet == -3)) { + /*no patch found or patch version does not match with hw version, + * we check if patch is mandatory or not, if yes, return iRet, if not return 0 + */ + if (gp_mt6620_info->bWorkWithoutPatch != MTK_WCN_BOOL_FALSE) + iRet = 0; + } + + return iRet; +} + + +#else +static INT32 mt6620_patch_dwn(VOID) +{ + INT32 iRet = -1; + P_WMT_PATCH patchHdr; + PUINT8 pbuf; + UINT32 patchSize; + UINT32 fragSeq; + UINT32 fragNum; + UINT16 fragSize = 0; + UINT16 cmdLen; + UINT32 offset; + UINT32 u4Res; + UINT8 evtBuf[8]; + PINT8 cDataTime = NULL; + /*PINT8 cPlat = NULL; */ + UINT16 u2HwVer = 0; + UINT16 u2SwVer = 0; + UINT32 u4PatchVer = 0; + UINT32 patchSizePerFrag = 0; + WMT_CTRL_DATA ctrlData; + + /*1.check hardware information */ + if (gp_mt6620_info == NULL) { + WMT_ERR_FUNC("null gp_mt6620_info!\n"); + return -1; + } +#if 0 + ctrlData.ctrlId = WMT_CTRL_GET_PATCH_NAME; + ctrlData.au4CtrlData[0] = (UINT32) &gDefPatchName; + iRet = wmt_ctrl(&ctrlData); + + if (mt6620_update_patch_name()) { + WMT_ERR_FUNC("invalid patch name, ommit patch download process.\n"); + return -1; + } + + ctrlData.ctrlId = WMT_CTRL_GET_PATCH; + ctrlData.au4CtrlData[0] = (UINT32) &gDefPatchName; + ctrlData.au4CtrlData[1] = (UINT32) &gFullPatchName; + ctrlData.au4CtrlData[2] = (UINT32) &pbuf; + ctrlData.au4CtrlData[3] = (UINT32) &patchSize; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); + iRet = -2; + goto done; + } +#else + /* <2> search patch and read patch content */ + /* <2.1> search patch */ + ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; + iRet = wmt_ctrl(&ctrlData); + if (iRet == 0) { + /* patch with correct Hw Ver Major Num found */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH_NAME; + ctrlData.au4CtrlData[0] = (size_t) &gFullPatchName; + iRet = wmt_ctrl(&ctrlData); + + WMT_INFO_FUNC("valid patch found: (%s)\n", gFullPatchName); + /* <2.2> read patch content */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH; + ctrlData.au4CtrlData[0] = (size_t) NULL; + ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName; + + } else { + iRet -= 1; + return iRet; + } + ctrlData.au4CtrlData[2] = (size_t) &pbuf; + ctrlData.au4CtrlData[3] = (size_t) &patchSize; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); + iRet -= 1; + goto done; + } +#endif + + /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ + pbuf += BCNT_PATCH_BUF_HEADROOM; + /* patch file with header: + * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| + */ + patchHdr = (P_WMT_PATCH) pbuf; + /* check patch file information */ + + cDataTime = patchHdr->ucDateTime; + u2HwVer = patchHdr->u2HwVer; + u2SwVer = patchHdr->u2SwVer; + u4PatchVer = patchHdr->u4PatchVer; + /*cPlat = &patchHdr->ucPLat[0]; */ + + cDataTime[15] = '\0'; + + /* remove patch header: + * |<-patch body: X Bytes (X=patchSize)--->| + */ + if (patchSize < sizeof(WMT_PATCH)) { + WMT_ERR_FUNC("error patch size\n"); + return -1; + } + patchSize -= sizeof(WMT_PATCH); + pbuf += sizeof(WMT_PATCH); + WMT_INFO_FUNC("===========================================\n"); + WMT_INFO_FUNC("[Combo Patch] Built Time = %s\n", cDataTime); + WMT_INFO_FUNC("[Combo Patch] Hw Ver = 0x%x\n", + ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8)); + WMT_INFO_FUNC("[Combo Patch] Sw Ver = 0x%x\n", + ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8)); + WMT_INFO_FUNC("[Combo Patch] Ph Ver = 0x%04x\n", + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16)); + WMT_INFO_FUNC("[Combo Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0], + patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + WMT_INFO_FUNC("[Combo Patch] Content Size = 0x%x\n", patchSize); + WMT_INFO_FUNC("[Combo Patch] Content CRC = 0x%04x\n", osal_crc16(pbuf, patchSize)); + WMT_INFO_FUNC("===========================================\n"); + + patchSizePerFrag = (MAJORNUM(gp_mt6620_info->u4HwVer) != 0) ? + DEFAULT_PATCH_FRAG_SIZE : MT6620E2_PATCH_FRAG_SIZE; + + /* reserve 1st patch cmd space before patch body + * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| + */ + osal_memcpy(&gp_mt6620_patch_info, patchHdr, osal_sizeof(WMT_PATCH)); + pbuf -= sizeof(WMT_PATCH_CMD); + + fragNum = patchSize / patchSizePerFrag; + fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; + + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + + /* send all fragments */ + offset = sizeof(WMT_PATCH_CMD); + fragSeq = 0; + while (fragSeq < fragNum) { + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + if (fragSeq == (fragNum - 1)) { + /* last fragment */ + fragSize = patchSize - fragSeq * patchSizePerFrag; + WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; + } else { + fragSize = patchSizePerFrag; + WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; + } + /* update length field in CMD:flag+frag */ + cmdLen = 1 + fragSize; + osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); + /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ + osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, + sizeof(WMT_PATCH_CMD)); + + /* iRet = (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), + * fragSize + sizeof(WMT_PATCH_CMD), &u4Res); + */ + iRet = + wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD), + fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, + fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); + iRet = -4; + break; + } + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", + fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); + + osal_memset(evtBuf, 0, sizeof(evtBuf)); + /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ + iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n", + sizeof(WMT_PATCH_EVT), u4Res, iRet); + iRet = -5; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0], WMT_PATCH_EVT[1], + WMT_PATCH_EVT[2], WMT_PATCH_EVT[3], WMT_PATCH_EVT[4]); + iRet = -6; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n", + sizeof(WMT_PATCH_EVT), u4Res); + +#if 0 + WMT_DBG_FUNC("wmt_core: send patch frag(%d) [%02X,%02X,%02X,%02X,%02X] (%d) ok", + fragSeq, WMT_PATCH_CMD[0], WMT_PATCH_CMD[1], WMT_PATCH_CMD[2], + WMT_PATCH_CMD[3], WMT_PATCH_CMD[4], fragSize); +#endif + + offset += patchSizePerFrag; + ++fragSeq; + } + + WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", + iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); + + if (fragSeq != fragNum) + iRet = -7; +done: + /* WMT_CTRL_FREE_PATCH always return 0 */ + wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); + if ((iRet == -2) || (iRet == -3)) { + /*no patch found or patch version does not match with hw version, + * we check if patch is mandatory or not, if yes, return iRet, if not return 0 + */ + if (gp_mt6620_info->bWorkWithoutPatch != MTK_WCN_BOOL_FALSE) + iRet = 0; + } + + return iRet; +} + +static INT32 mt6620_update_patch_name(VOID) +{ + INT32 len; + UINT8 cTmpPatchName[NAME_MAX + 1] = { 0 }; + + /*init.get hardware version */ + /* TODO:[FixMe][GeorgeKuo]: check using memcpy or strncpy??? */ + /*osal_memcpy (gFullPatchName, gDefPatchName, osal_strlen(gDefPatchName)); */ + osal_strncpy(gFullPatchName, gDefPatchName, osal_sizeof(gFullPatchName)); + + /*1.check hardware information */ + if (gp_mt6620_info == NULL) { + WMT_ERR_FUNC("null gp_mt6620_info!\n"); + osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName)); + return -1; + } + + /*2.make possible firmware patch name with original name and hardware version */ + if ((osal_strlen(gDefPatchName) > osal_strlen(WMT_IC_PATCH_TAIL)) + && ((osal_strlen(gDefPatchName) + osal_strlen(WMT_IC_PATCH_DUMMY_EXT) <= NAME_MAX)) + ) { + len = osal_strlen(gDefPatchName) - osal_strlen(WMT_IC_PATCH_TAIL); + osal_memcpy(cTmpPatchName, gDefPatchName, len > NAME_MAX ? NAME_MAX : len); + osal_memcpy(cTmpPatchName + osal_strlen(cTmpPatchName), + gp_mt6620_info->cPatchNameExt, + osal_strlen(gp_mt6620_info->cPatchNameExt)); + osal_memcpy(cTmpPatchName + osal_strlen(cTmpPatchName), WMT_IC_PATCH_TAIL, + osal_strlen(WMT_IC_PATCH_TAIL)); + cTmpPatchName[osal_strlen(cTmpPatchName)] = '\0'; + } else { + WMT_ERR_FUNC("invalid default firmware patch name (%s)\n", gDefPatchName); + osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName)); + return -2; + } + + /*patch with versioned name exist , update cFullPatchName with full named patch */ + osal_memcpy(gFullPatchName, cTmpPatchName, osal_strlen(cTmpPatchName)); + *(gFullPatchName + osal_strlen(cTmpPatchName)) = '\0'; + WMT_INFO_FUNC("full firmware patch name: %s\n", cTmpPatchName); + + return 0; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6628.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6628.c new file mode 100644 index 00000000000000..90e2d04a482c4e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6628.c @@ -0,0 +1,1981 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-IC]" +#define CFG_IC_MT6628 1 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "wmt_ic.h" +#include "wmt_core.h" +#include "wmt_lib.h" +#include "stp_core.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define DEFAULT_PATCH_FRAG_SIZE (1000) +#define WMT_PATCH_FRAG_1ST (0x1) +#define WMT_PATCH_FRAG_MID (0x2) +#define WMT_PATCH_FRAG_LAST (0x3) + +#define CFG_CHECK_WMT_RESULT (1) +/* BT Port 2 Feature. this command does not need after coex command is downconfirmed by LC, */ +#define CFG_WMT_BT_PORT2 (0) + +#define CFG_SET_OPT_REG (0) +#define CFG_WMT_I2S_DBGUART_SUPPORT (0) +#define CFG_SET_OPT_REG_SWLA (0) +#define CFG_SET_OPT_REG_MCUCLK (0) +#define CFG_SET_OPT_REG_MCUIRQ (0) + +#define CFG_SUBSYS_COEX_NEED 0 + +#define CFG_WMT_COREDUMP_ENABLE 0 + +#define CFG_WMT_MULTI_PATCH (1) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +static UINT8 gFullPatchName[NAME_MAX + 1]; +static const WMT_IC_INFO_S *gp_mt6628_info; +static WMT_PATCH gp_mt6628_patch_info; +static WMT_CO_CLOCK gCoClockEn = WMT_CO_CLOCK_DIS; +#if 0 +static UINT8 WMT_WAKEUP_DIS_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x04 }; +static UINT8 WMT_WAKEUP_DIS_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x04 }; + +static UINT8 WMT_WAKEUP_EN_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x05 }; +static UINT8 WMT_WAKEUP_EN_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x05 }; +#endif + +static UINT8 WMT_QUERY_BAUD_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x02 }; +static UINT8 WMT_QUERY_BAUD_EVT_115200[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x01, 0x00 }; +static UINT8 WMT_QUERY_BAUD_EVT_X[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0xAA, 0xAA, 0xAA, 0xBB }; +static UINT8 WMT_QUERY_STP_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x04 }; +static UINT8 WMT_QUERY_STP_EVT_DEFAULT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 }; +static UINT8 WMT_QUERY_STP_EVT_UART[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0xDF, 0x0E, 0x68, 0x01 }; +static UINT8 WMT_SET_BAUD_CMD_X[] = { 0x01, 0x04, 0x05, 0x00, 0x01, 0xAA, 0xAA, 0xAA, 0xBB }; +static UINT8 WMT_SET_BAUD_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x01 }; +static UINT8 WMT_SET_WAKEUP_WAKE_CMD_RAW[] = { 0xFF }; +static UINT8 WMT_SET_WAKEUP_WAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; +static UINT8 WMT_PATCH_CMD[] = { 0x01, 0x01, 0x00, 0x00, 0x00 }; +static UINT8 WMT_PATCH_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00 }; +static UINT8 WMT_RESET_CMD[] = { 0x01, 0x07, 0x01, 0x00, 0x04 }; +static UINT8 WMT_RESET_EVT[] = { 0x02, 0x07, 0x01, 0x00, 0x00 }; + +#if CFG_WMT_BT_PORT2 +static UINT8 WMT_BTP2_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x01, 0x03, 0x01 }; +static UINT8 WMT_BTP2_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#endif + +#if CFG_WMT_MULTI_PATCH +static UINT8 WMT_PATCH_ADDRESS_CMD[] = { 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0xD4, 0x01, 0x09, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_PATCH_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +static UINT8 WMT_PATCH_P_ADDRESS_CMD[] = { 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x48, 0x03, 0x09, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_PATCH_P_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; +#endif + +/*coex cmd/evt++*/ +static UINT8 WMT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x01, 0x00 }; +static UINT8 WMT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +#if CFG_SUBSYS_COEX_NEED +static UINT8 WMT_BT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0B, + 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, + 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA +}; +static UINT8 WMT_BT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0C, + 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA +}; +static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_PTA_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0A, + 0x00, 0x04, + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF, 0xFE +}; +static UINT8 WMT_PTA_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_MISC_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x09, + 0x00, 0x05, + 0xAA, 0xAA, 0xAA, 0xAA, + 0xBB, 0xBB, 0xBB, 0xBB +}; +static UINT8 WMT_MISC_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#endif + +/*coex cmd/evt--*/ +static UINT8 WMT_SET_STP_CMD[] = { 0x01, 0x04, 0x05, 0x00, 0x03, 0xDF, 0x0E, 0x68, 0x01 }; +static UINT8 WMT_SET_STP_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x03 }; +static UINT8 WMT_STRAP_CONF_CMD_FM_COMM[] = { 0x01, 0x05, 0x02, 0x00, 0x02, 0x02 }; +static UINT8 WMT_STRAP_CONF_EVT[] = { 0x02, 0x05, 0x02, 0x00, 0x00, 0x02 }; + +#if 0 +static UINT8 WMT_SET_OSC32K_BYPASS_CMD[] = { 0x01, 0x0A, 0x01, 0x00, 0x05 }; +static UINT8 WMT_SET_OSC32K_BYPASS_EVT[] = { 0x02, 0x0A, 0x01, 0x00, 0x00 }; +#endif + +#if 0 +/* to enable dump feature */ +static UINT8 WMT_CORE_DUMP_EN_CMD[] = { 0x01, 0x0F, 0x02, 0x00, 0x03, 0x01 }; +static UINT8 WMT_CORE_DUMP_EN_EVT[] = { 0x02, 0x0F, 0x01, 0x00, 0x00 }; + +/* to get system stack dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_01_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UINT8 WMT_CORE_DUMP_LEVEL_01_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; + +/* to get task and system stack dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_02_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UINT8 WMT_CORE_DUMP_LEVEL_02_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; + +/* to get bt related memory dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_03_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x03, 0x00, 0x00, 0x09, 0xF0, 0x00, 0x0A }; +static UINT8 WMT_CORE_DUMP_LEVEL_03_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; +#endif +/* to get full dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_04_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UINT8 WMT_CORE_DUMP_LEVEL_04_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_CORE_CO_CLOCK_CMD[] = { 0x1, 0x0A, 0x02, 0x00, 0x08, 0x03 }; +static UINT8 WMT_CORE_CO_CLOCK_EVT[] = { 0x2, 0x0A, 0x01, 0x00, 0x00 }; + + +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) +static UINT8 WMT_SET_I2S_SLAVE_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x78, 0x00, 0x05, 0x80 /*addr:0x80050078 */ + , 0x00, 0x00, 0x11, 0x01 /*value:0x11010000 */ + , 0x00, 0x00, 0x77, 0x07 /*mask:0x07770000 */ +}; + +static UINT8 WMT_SET_I2S_SLAVE_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; + +static UINT8 WMT_SET_DAI_TO_PAD_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x74, 0x00, 0x05, 0x80 /*addr:0x80050074 */ + , 0x44, 0x44, 0x00, 0x00 /*value:0x11010000 */ + , 0x77, 0x77, 0x00, 0x00 /*mask:0x07770000 */ +}; + +static UINT8 WMT_SET_DAI_TO_PAD_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; + +static UINT8 WMT_SET_DAI_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0xA0, 0x00, 0x05, 0x80 /*addr:0x80050074 */ + , 0x04, 0x00, 0x00, 0x00 /*value:0x11010000 */ + , 0x04, 0x00, 0x00, 0x00 /*mask:0x07770000 */ +}; + +static UINT8 WMT_SET_DAI_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; +#endif + + +#ifndef CFG_IC_MT6628 /* For MT6628 no need to set ALLEINT registers, done in f/w */ +/* enable all interrupt */ +static UINT8 WMT_SET_ALLINT_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x00, 0x03, 0x05, 0x80 /*addr:0x80050300 */ + , 0x00, 0xC4, 0x00, 0x00 /*value:0x0000C400 */ + , 0x00, 0xC4, 0x00, 0x00 /*mask:0x0000C400 */ +}; + +static UINT8 WMT_SET_ALLINT_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; + +#endif + +#if CFG_SET_OPT_REG_SWLA /* enable swla: eesk(7) eecs(8) oscen(19) sck0(24) scs0(25) */ +static UINT8 WMT_SET_SWLA_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ + , 0x10, 0x01, 0x05, 0x80 /*addr:0x80050110 */ + , 0x10, 0x10, 0x01, 0x00 /*value:0x00011010 */ + , 0xF0, 0xF0, 0x0F, 0x00 /*mask:0x000FF0F0 */ + , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ + , 0x00, 0x10, 0x01, 0x00 /*value:0x00011000 */ + , 0x00, 0xF0, 0x0F, 0x00 /*mask:0x000FF000 */ +}; + +static UINT8 WMT_SET_SWLA_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ +}; +#endif + +#if CFG_SET_OPT_REG_MCUCLK /* enable mcu clk: antsel_4, eedi */ +static UINT8 WMT_SET_MCUCLK_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000 0400 */ + , 0x00, 0x14, 0x00, 0x00 /* value:0x0000 1400(osc, hclk), 0x0000 1501(PLL, en) */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005 0180 */ + , 0x12, 0x13, 0x00, 0x00 /* value:0x0000 1312(osc, hclk), 0x0000 1a19(PLL, en) */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005 0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002 0000 */ + , 0x00, 0x00, 0x0F, 0x00 /* mask:0x000F 0000 */ + , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005 0110 */ + , 0x02, 0x00, 0x00, 0x00 /* value:0x0000 0002 */ + , 0x0F, 0x00, 0x00, 0x00 /* mask:0x0000 000F */ +}; + +static UINT8 WMT_SET_MCUCLK_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ +}; +#endif + +#if CFG_WMT_I2S_DBGUART_SUPPORT /* register write for debug uart */ +static UINT8 WMT_SET_DBGUART_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ + , 0x30, 0x01, 0x05, 0x80 /*addr:0x80050130 */ + , 0x00, 0x00, 0x00, 0x00 /*value:0x00000000 */ + , 0xF0, 0x0F, 0x00, 0x00 /*mask:0x00000FF0 */ + , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ + , 0x00, 0x01, 0x00, 0x00 /*value:0x00000100 */ + , 0x00, 0x01, 0x00, 0x00 /*mask:0x00000100 */ +}; + +static UINT8 WMT_SET_DBGUART_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ +}; +#endif + +#if CFG_SET_OPT_REG_MCUIRQ /* enable mcu irq: antsel_4, wlan_act */ +#if 1 /* Ray */ +static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ + , 0x03, 0x14, 0x00, 0x00 /* value:0x0000_1403 check confg debug flag 3 low word */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000_FFFF */ + /* cirq_int_n */ + , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005_0110 */ + , 0x02, 0x00, 0x00, 0x00 /* value:0x0000_0002 set EEDI as cirq_int_n debug flag (monitor flag2) */ + , 0x07, 0x00, 0x00, 0x00 /* mask:0x0000_0007 */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0, ahb_x2_gt_ck debug flag) */ + , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ + /* 1. ARM irq_b, monitor flag 0 */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ + , 0x1F, 0x1E, 0x00, 0x00 /* value:0x0000_1E1F check mcusys debug flag */ + , 0x7F, 0x7F, 0x00, 0x00 /* mask:0x0000_7F7F */ +}; + +static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 5 registers */ +}; +#elif 0 /* KC */ +static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 5), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x05 /* 5 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ + , 0x00, 0x02, 0x00, 0x00 /* value:0x0000_0200 [15:8]=0x2 arm irq_b, 0xA irq_bus[5] bt_timcon_irq_b */ + , 0x00, 0xFF, 0x00, 0x00 /* mask:0x0000_FF00 */ + /* 1. ARM irq_b, monitor flag 0 */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ + , 0x18, 0x00, 0x00, 0x00 /* value:0x0000_0018 [6:0]=001_1000 (monitor flag 0 select, MCUSYS, SEL:8) */ + , 0x7F, 0x00, 0x00, 0x00 /* mask:0x0000_007F */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0) */ + , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ + /* 2. irq_bus[5] bt_timcon_irq_b monitor flag 15 */ + , 0xB0, 0x01, 0x05, 0x80 /* addr:0x8005_01B0 */ + , 0x00, 0x00, 0x00, 0x16 /* value:0x1600_0000 [30:24]=001_0110 (monitor flag 15 select, MCUSYS, SEL:6) */ + , 0x00, 0x00, 0x00, 0x7F /* mask:0x7F00_0000 */ + , 0x30, 0x01, 0x05, 0x80 /* addr:0x8005_0130 */ + , 0x00, 0x20, 0x00, 0x00 /* value:0x0000_2000 (WLAN_ACT=>monitor flag 15) */ + , 0x00, 0x70, 0x00, 0x00 /* mask:0x0000_7000 */ +}; + +static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x05 /* 5 registers */ +}; +#endif +#endif + +static UINT8 WMT_SET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x01, 0x00 }; +static UINT8 WMT_SET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x01, 0x00 }; + +static UINT8 WMT_GET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x00, 0x00 }; +static UINT8 WMT_GET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x00, 0x00 }; + +/* set sdio driving */ +static UINT8 WMT_SET_SDIO_DRV_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x50, 0x00, 0x05, 0x80 /*addr:0x80050050 */ + , 0x44, 0x44, 0x04, 0x00 /*value:0x00044444 */ + , 0x77, 0x77, 0x07, 0x00 /*mask:0x00077777 */ +}; + +static UINT8 WMT_SET_SDIO_DRV_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; + + +#ifndef CFG_IC_MT6628 + +/* stp sdio init scripts */ +static struct init_script init_table_1_1[] = { + /* table_1_1 is only applied to common SDIO interface */ + INIT_CMD(WMT_SET_ALLINT_REG_CMD, WMT_SET_ALLINT_REG_EVT, "enable all interrupt"), + /* applied to MT6628 ? */ + INIT_CMD(WMT_WAKEUP_DIS_GATE_CMD, WMT_WAKEUP_DIS_GATE_EVT, "disable gating"), +}; + +#endif + +static struct init_script init_table_1_2[] = { + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_115200, "query baud 115200"), + INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_DEFAULT, "query stp default"), + INIT_CMD(WMT_SET_BAUD_CMD_X, WMT_SET_BAUD_EVT, "set baud rate"), +}; + + +static struct init_script init_table_2[] = { + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"), +}; + +static struct init_script init_table_3[] = { + INIT_CMD(WMT_RESET_CMD, WMT_RESET_EVT, "wmt reset"), +#if CFG_WMT_BT_PORT2 + INIT_CMD(WMT_BTP2_CMD, WMT_BTP2_EVT, "set bt port2"), +#endif +}; + +static struct init_script set_crystal_timing_script[] = { + INIT_CMD(WMT_SET_CRYSTAL_TRIMING_CMD, WMT_SET_CRYSTAL_TRIMING_EVT, + "set crystal trim value"), +}; + +static struct init_script get_crystal_timing_script[] = { + INIT_CMD(WMT_GET_CRYSTAL_TRIMING_CMD, WMT_GET_CRYSTAL_TRIMING_EVT, + "get crystal trim value"), +}; + + +#if 0 +static struct init_script init_table_3_1[] = { + INIT_CMD(WMT_WAKEUP_EN_GATE_CMD, WMT_WAKEUP_EN_GATE_EVT, "ensable gating"), +}; +#endif + +static struct init_script init_table_4[] = { + INIT_CMD(WMT_SET_STP_CMD, WMT_SET_STP_EVT, "set stp"), +}; + +static struct init_script init_table_5[] = { + INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_UART, "query stp uart"), + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"), +}; + +static struct init_script init_table_5_1[] = { + INIT_CMD(WMT_STRAP_CONF_CMD_FM_COMM, WMT_STRAP_CONF_EVT, "configure FM comm"), +}; + +static struct init_script init_table_6[] = { +#if 0 + INIT_CMD(WMT_CORE_DUMP_EN_CMD, WMT_CORE_DUMP_EN_EVT, "configure memory and core dump"), +#endif + INIT_CMD(WMT_CORE_DUMP_LEVEL_04_CMD, WMT_CORE_DUMP_LEVEL_04_EVT, "setup core dump level"), +}; + +#if 0 +static struct init_script init_table_6[] = { + INIT_CMD(WMT_SET_OSC32K_BYPASS_CMD, WMT_SET_OSC32K_BYPASS_EVT, "set OSC32k by pass mode."), +}; +#endif + +#if defined(CFG_SET_OPT_REG) && CFG_SET_OPT_REG +static struct init_script set_registers[] = { + /* INIT_CMD(WMT_SET_GPS_REG_CMD, WMT_SET_GPS_REG_EVT, "set wmt registers"), */ + /* INIT_CMD(WMT_SET_SDIODRV_REG_CMD, WMT_SET_SDIODRV_REG_EVT, "set SDIO driving registers") */ +#if CFG_WMT_I2S_DBGUART_SUPPORT + INIT_CMD(WMT_SET_DBGUART_REG_CMD, WMT_SET_DBGUART_REG_EVT, "set debug uart registers"), +#endif +#if CFG_SET_OPT_REG_SWLA + INIT_CMD(WMT_SET_SWLA_REG_CMD, WMT_SET_SWLA_REG_EVT, "set swla registers"), +#endif +#if CFG_SET_OPT_REG_MCUCLK + INIT_CMD(WMT_SET_MCUCLK_REG_CMD, WMT_SET_MCUCLK_REG_EVT, "set mcuclk dbg registers"), +#endif +#if CFG_SET_OPT_REG_MCUIRQ + INIT_CMD(WMT_SET_MCUIRQ_REG_CMD, WMT_SET_MCUIRQ_REG_EVT, "set mcu irq dbg registers"), +#endif +}; +#endif + +static struct init_script coex_table[] = { + INIT_CMD(WMT_COEX_SETTING_CONFIG_CMD, WMT_COEX_SETTING_CONFIG_EVT, "coex_wmt"), + +#if CFG_SUBSYS_COEX_NEED +/* no need in MT6628 */ + INIT_CMD(WMT_BT_COEX_SETTING_CONFIG_CMD, WMT_BT_COEX_SETTING_CONFIG_EVT, "coex_bt"), + INIT_CMD(WMT_WIFI_COEX_SETTING_CONFIG_CMD, WMT_WIFI_COEX_SETTING_CONFIG_EVT, "coex_wifi"), + INIT_CMD(WMT_PTA_COEX_SETTING_CONFIG_CMD, WMT_PTA_COEX_SETTING_CONFIG_EVT, "coex_ext_pta"), + INIT_CMD(WMT_MISC_COEX_SETTING_CONFIG_CMD, WMT_MISC_COEX_SETTING_CONFIG_EVT, "coex_misc"), +#endif +}; + +static struct init_script osc_type_table[] = { + INIT_CMD(WMT_CORE_CO_CLOCK_CMD, WMT_CORE_CO_CLOCK_EVT, "osc_type"), +}; + +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) +static struct init_script merge_pcm_table[] = { + INIT_CMD(WMT_SET_I2S_SLAVE_REG_CMD, WMT_SET_I2S_SLAVE_REG_EVT, "I2S_Slave"), + INIT_CMD(WMT_SET_DAI_TO_PAD_REG_CMD, WMT_SET_DAI_TO_PAD_REG_EVT, "DAI_PAD"), + INIT_CMD(WMT_SET_DAI_REG_CMD, WMT_SET_DAI_REG_EVT, "DAI_EVT"), +}; +#endif + + +static struct init_script sdio_driving_table[] = { + INIT_CMD(WMT_SET_SDIO_DRV_REG_CMD, WMT_SET_SDIO_DRV_REG_EVT, "sdio_driving"), +}; + + +/* MT6628 Chip Version and Info Table */ +static const WMT_IC_INFO_S mt6628_info_table[] = { + { + .u4HwVer = 0x8A00, + .cChipName = WMT_IC_NAME_MT6628, + .cChipVersion = WMT_IC_VER_E1, + .cPatchNameExt = WMT_IC_PATCH_E1_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8A10, + .cChipName = WMT_IC_NAME_MT6628, + .cChipVersion = WMT_IC_VER_E2, + .cPatchNameExt = WMT_IC_PATCH_E2_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8B10, + .cChipName = WMT_IC_NAME_MT6628, + .cChipVersion = WMT_IC_VER_E3, + .cPatchNameExt = WMT_IC_PATCH_E2_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8B11, + .cChipName = WMT_IC_NAME_MT6628, + .cChipVersion = WMT_IC_VER_E4, + .cPatchNameExt = WMT_IC_PATCH_E2_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8a11, + .cChipName = WMT_IC_NAME_MT6628, + .cChipVersion = WMT_IC_VER_E5, + .cPatchNameExt = WMT_IC_PATCH_E2_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + } +}; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static INT32 mt6628_sw_init(P_WMT_HIF_CONF pWmtHifConf); + +static INT32 mt6628_sw_deinit(P_WMT_HIF_CONF pWmtHifConf); + +static INT32 mt6628_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag); + +static INT32 mt6628_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag); + +static INT32 mt6628_ver_check(VOID); + +static const WMT_IC_INFO_S *mt6628_find_wmt_ic_info(const UINT32 hw_ver); + +static INT32 wmt_stp_init_coex(VOID); + +#if CFG_WMT_MULTI_PATCH +static INT32 mt6628_patch_dwn(UINT32 index); +static INT32 mt6628_patch_info_prepare(VOID); +#else +static INT32 mt6628_patch_dwn(VOID); +#endif + +static INT32 mt6628_co_clock_ctrl(WMT_CO_CLOCK on); +static WMT_CO_CLOCK mt6628_co_clock_get(VOID); + +static INT32 mt6628_crystal_triming_set(VOID); + + +static MTK_WCN_BOOL mt6628_quick_sleep_flag_get(VOID); + +static MTK_WCN_BOOL mt6628_aee_dump_flag_get(VOID); + +static INT32 mt6628_set_sdio_driving(VOID); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/* MT6628 Operation Function Table */ +WMT_IC_OPS wmt_ic_ops_mt6628 = { + .icId = 0x6628, + .sw_init = mt6628_sw_init, + .sw_deinit = mt6628_sw_deinit, + .ic_pin_ctrl = mt6628_pin_ctrl, + .ic_ver_check = mt6628_ver_check, + .co_clock_ctrl = mt6628_co_clock_ctrl, + .is_quick_sleep = mt6628_quick_sleep_flag_get, + .is_aee_dump_support = mt6628_aee_dump_flag_get, + .trigger_stp_assert = NULL, + .deep_sleep_ctrl = NULL, +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static INT32 mt6628_sw_init(P_WMT_HIF_CONF pWmtHifConf) +{ + INT32 iRet = -1; + UINT32 u4Res = 0; + UINT8 evtBuf[256]; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + UINT32 hw_ver; +#if CFG_WMT_MULTI_PATCH + UINT32 patch_num = 0; + UINT32 patch_index = 0; +#endif + WMT_CTRL_DATA ctrlData; + + WMT_DBG_FUNC(" start\n"); + + osal_assert(gp_mt6628_info != NULL); + if ((gp_mt6628_info == NULL) + || (pWmtHifConf == NULL) + ) { + WMT_ERR_FUNC("null pointers: gp_mt6628_info(0x%p), pWmtHifConf(0x%p)\n", + gp_mt6628_info, pWmtHifConf); + return -1; + } + + hw_ver = gp_mt6628_info->u4HwVer; + + /* 4 <3.1> start init for sdio */ +#ifndef CFG_IC_MT6628 /* For MT6628 no need to do this operation */ + if (pWmtHifConf->hifType == WMT_HIF_SDIO) { + wmt_lib_ps_set_idle_time(STP_PSM_SDIO_IDLE_TIME_SLEEP); + /* 1. enable all INT32 */ + /* 2. disable mcu gate (only MT6628E1/E2) */ + iRet = wmt_core_init_script(init_table_1_1, ARRAY_SIZE(init_table_1_1)); + if (iRet) { + WMT_ERR_FUNC("init_table_1_1 fail:%d\n", iRet); + osal_assert(0); + return -1; + } + } +#endif + /* 4 <3.2> start init for uart */ + if (pWmtHifConf->hifType == WMT_HIF_UART) { + /* init variable fields for script execution */ + osal_memcpy(&WMT_SET_BAUD_CMD_X[5], &pWmtHifConf->au4HifConf[0], + osal_sizeof(UINT32)); + WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x00; /* 0xC0 MTK Flow Control *//* no flow control */ + osal_memcpy(&WMT_QUERY_BAUD_EVT_X[6], &pWmtHifConf->au4HifConf[0], + osal_sizeof(UINT32)); + WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x00; /* 0xC0 MTK Flow Control *//* no flow control */ + + /* 3. Query chip baud rate (TEST-ONLY) */ + /* 4. Query chip STP options (TEST-ONLY) */ + /* 5. Change chip baud rate: t_baud */ + /* WMT_DBG_FUNC("WMT-CORE: init_table_1_2 set chip baud:%d", pWmtHifConf->au4HifConf[0]); */ + iRet = wmt_core_init_script(init_table_1_2, ARRAY_SIZE(init_table_1_2)); + if (iRet) { + WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet); + osal_assert(0); + return -2; + } + + /* 6. Set host baudrate and flow control */ + ctrlPa1 = pWmtHifConf->au4HifConf[0]; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HOST_BAUDRATE_SET, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("change baudrate(%d) fail(%d)\n", pWmtHifConf->au4HifConf[0], + iRet); + return -3; + } + WMT_INFO_FUNC("WMT-CORE: change baudrate(%d) ok\n", pWmtHifConf->au4HifConf[0]); + + /* 7. Wake up chip and check event */ + /* iRet = (*kal_stp_tx_raw)(&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res); */ + iRet = + wmt_core_tx((PUINT8)&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res, + MTK_WCN_BOOL_TRUE); + if (iRet || (u4Res != 1)) { + WMT_ERR_FUNC("write raw iRet(%d) written(%d)\n", iRet, u4Res); + return -4; + } + + osal_memset(evtBuf, 0, osal_sizeof(evtBuf)); + iRet = wmt_core_rx(evtBuf, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT), &u4Res); +#ifdef CFG_DUMP_EVT + WMT_DBG_FUNC("WAKEUP_WAKE_EVT read len %d [%02x,%02x,%02x,%02x,%02x,%02x]\n", + (INT32) u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + evtBuf[5]); +#endif + if (iRet || (u4Res != osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT))) { + WMT_ERR_FUNC("read WAKEUP_WAKE_EVT fail(%d)\n", iRet); + return -5; + } + /* WMT_DBG_FUNC("WMT-CORE: read WMT_SET_WAKEUP_WAKE_EVT ok"); */ + +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp + (evtBuf, WMT_SET_WAKEUP_WAKE_EVT, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT)) != 0) { + WMT_ERR_FUNC("WMT-CORE: write WMT_SET_WAKEUP_WAKE_CMD_RAW status fail\n"); + return -6; + } +#endif + + /* 8. Query baud rate (TEST-ONLY) */ + iRet = wmt_core_init_script(init_table_2, ARRAY_SIZE(init_table_2)); + if (iRet) { + WMT_ERR_FUNC("init_table_2 fail(%d)\n", iRet); + return -7; + } + } + + /* 9. download patch */ +#if CFG_WMT_MULTI_PATCH + /* 9.1 Let launcher to search patch info */ + iRet = mt6628_patch_info_prepare(); + if (iRet) { + WMT_ERR_FUNC("patch info perpare fail(%d)\n", iRet); + return -8; + } + + /* 9.2 Read patch number */ + ctrlPa1 = 0; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_GET_PATCH_NUM, &ctrlPa1, &ctrlPa2); + patch_num = ctrlPa1; + WMT_INFO_FUNC("patch total num = [%d]\n", patch_num); + + /* 9.3 Multi-patch Patch download */ + for (patch_index = 0; patch_index < patch_num; patch_index++) { + iRet = mt6628_patch_dwn(patch_index); + if (iRet) { + WMT_ERR_FUNC("patch dwn fail (%d),patch_index(%d)\n", iRet, patch_index); + return -12; + } + iRet = wmt_core_init_script(init_table_3, ARRAY_SIZE(init_table_3)); + if (iRet) { + WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); + return -13; + } + } +#else + /* 9.3 Patch download */ + iRet = mt6628_patch_dwn(); + /* If patch download fail, we just ignore this error and let chip init process goes on */ + if (iRet) + WMT_ERR_FUNC("patch dwn fail (%d), just omit\n", iRet); +#endif /* End of #if CFG_WMT_MULTI_PATCH */ + + /* 10. WMT Reset command */ + iRet = wmt_core_init_script(init_table_3, ARRAY_SIZE(init_table_3)); + if (iRet) { + WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); + return -9; + } + iRet = wmt_stp_init_coex(); + if (iRet) { + WMT_ERR_FUNC("init_coex fail(%d)\n", iRet); + return -10; + } + WMT_INFO_FUNC("init_coex ok\n"); + + mt6628_crystal_triming_set(); + + mt6628_set_sdio_driving(); + + if (pWmtHifConf->hifType == WMT_HIF_UART) { + /* 11. Set chip STP options */ + iRet = wmt_core_init_script(init_table_4, ARRAY_SIZE(init_table_4)); + if (iRet) { + WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet); + return -12; + } + + /* 12. Enable host STP-UART mode */ + ctrlPa1 = WMT_STP_CONF_MODE; + ctrlPa2 = MTKSTP_UART_FULL_MODE; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 1; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("enable host STP-UART-FULL mode fail(%d)\n", iRet); + return -13; + } + WMT_INFO_FUNC("enable host STP-UART-FULL mode\n"); + /*13. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */ + osal_sleep_ms(10); + /* 14. Query chip STP options (TEST-ONLY) */ + /* 15. Query baud rate (stp, TEST-ONLY) */ + iRet = wmt_core_init_script(init_table_5, ARRAY_SIZE(init_table_5)); + if (iRet) { + WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet); + return -14; + } + } + + if (mt6628_co_clock_get() == WMT_CO_CLOCK_EN) { + WMT_INFO_FUNC("co-clock enabled.\n"); + + iRet = wmt_core_init_script(osc_type_table, ARRAY_SIZE(osc_type_table)); + if (iRet) { + WMT_ERR_FUNC("osc_type_table fail(%d), goes on\n", iRet); + return -15; + } + } else { + WMT_INFO_FUNC("co-clock disabled.\n"); + } +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) + iRet = wmt_core_init_script(merge_pcm_table, ARRAY_SIZE(merge_pcm_table)); + if (iRet) { + WMT_ERR_FUNC("merge_pcm_table fail(%d), goes on\n", iRet); + return -15; + } +#endif + + /* 15. Set FM strap */ + WMT_STRAP_CONF_CMD_FM_COMM[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; + WMT_STRAP_CONF_EVT[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; + iRet = wmt_core_init_script(init_table_5_1, ARRAY_SIZE(init_table_5_1)); + if (iRet) { + WMT_ERR_FUNC("init_table_5_1 fm mode(%d) fail(%d)\n", + pWmtHifConf->au4StrapConf[0], iRet); + return -16; + } + WMT_INFO_FUNC("set fm mode (%d) ok\n", pWmtHifConf->au4StrapConf[0]); + +#if CFG_SET_OPT_REG /*set registers */ + iRet = wmt_core_init_script(set_registers, ARRAY_SIZE(set_registers)); + if (iRet) { + WMT_ERR_FUNC("set_registers fail(%d)", iRet); + return -17; + } +#endif + +#if CFG_WMT_COREDUMP_ENABLE + /*Open Core Dump Function @QC begin */ + mtk_wcn_stp_coredump_flag_ctrl(1); +#endif + if (mtk_wcn_stp_coredump_flag_get() != 0) { + iRet = wmt_core_init_script(init_table_6, ARRAY_SIZE(init_table_6)); + if (iRet) { + WMT_ERR_FUNC("init_table_6 core dump setting fail(%d)\n", iRet); + return -18; + } + WMT_INFO_FUNC("enable mt662x firmware coredump\n"); + } else + WMT_INFO_FUNC("disable mt662x firmware coredump. hifType: %d\n", + pWmtHifConf->hifType); + +#if 1 + ctrlData.ctrlId = WMT_CTRL_SET_STP_DBG_INFO; + ctrlData.au4CtrlData[0] = wmt_ic_ops_mt6628.icId; + ctrlData.au4CtrlData[1] = (size_t) gp_mt6628_info->cChipVersion; + ctrlData.au4CtrlData[2] = (size_t) &gp_mt6628_patch_info; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("set dump info fail(%d)\n", iRet); + return -16; + } +#endif + +#if CFG_WMT_PS_SUPPORT + if (pWmtHifConf->hifType == WMT_HIF_UART) { + osal_assert(gp_mt6628_info != NULL); + if (gp_mt6628_info != NULL) { + if (gp_mt6628_info->bPsmSupport != MTK_WCN_BOOL_FALSE) + wmt_lib_ps_enable(); + else + wmt_lib_ps_disable(); + } + } else if (pWmtHifConf->hifType == WMT_HIF_SDIO) { + /* COMMON SDIO is used different PS from UART, so disable current ps support + * Note: using wmt_lib_ps_ctrl() due to wmt_lib_ps_disable() cannot clear gPsEnable setting + */ + wmt_lib_ps_ctrl(0); + } +#endif + + return 0; +} + +static INT32 mt6628_sw_deinit(P_WMT_HIF_CONF pWmtHifConf) +{ + WMT_DBG_FUNC(" start\n"); + +#if CFG_WMT_PS_SUPPORT + if (pWmtHifConf->hifType == WMT_HIF_UART) { + osal_assert(gp_mt6628_info != NULL); + if ((gp_mt6628_info != NULL) + && (gp_mt6628_info->bPsmSupport != MTK_WCN_BOOL_FALSE)) { + wmt_lib_ps_disable(); + } + } +#endif + + gp_mt6628_info = NULL; + + return 0; +} + +static INT32 mt6628_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 ret = -1; + UINT32 val; + + if ((flag & WMT_LIB_AIF_FLAG_MASK) == WMT_LIB_AIF_FLAG_SHARE) { + WMT_INFO_FUNC("PCM & I2S PIN SHARE\n"); +#if 0 + switch (state) { + case WMT_IC_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + val = 0x00000770; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_1: + /* BT_PCM_ON & FM line in/out */ + val = 0x00000700; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_2: + /* BT_PCM_OFF & FM I2S */ + val = 0x00000710; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000800; /* 800:3-wire, 000: 4-wire */ + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + default: + WMT_ERR_FUNC("unsupported state (%d)\n", state); + ret = -1; + break; + } +#else + WMT_WARN_FUNC("TBD!!"); + ret = 0; +#endif + } else { + /*PCM & I2S separate */ + WMT_INFO_FUNC("PCM & I2S PIN SEPARATE\n"); +#if 0 + switch (state) { + case WMT_IC_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + val = 0x00000770; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_1: + /* BT_PCM_ON & FM line in/out */ + val = 0x00000700; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_2: + /* BT_PCM_OFF & FM I2S */ + val = 0x00000070; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000800; /* 800:3-wire, 000: 4-wire */ + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + + break; + case WMT_IC_AIF_3: + val = 0x00000000; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000800; /* 800:3-wire, 000: 4-wire */ + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + + break; + default: + WMT_ERR_FUNC("unsupported state (%d)\n", state); + ret = -1; + break; + } +#else + switch (state) { + case WMT_IC_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + ret = 0; + break; + case WMT_IC_AIF_1: + /* BT_PCM_ON & FM line in/out */ + ret = 0; + break; + + case WMT_IC_AIF_2: + /* BT_PCM_OFF & FM I2S */ + val = 0x01110000; + ret = wmt_core_reg_rw_raw(1, 0x80050078, &val, 0x0FFF0000); + + break; + case WMT_IC_AIF_3: + ret = 0; + break; + + default: + WMT_ERR_FUNC("unsupported state (%d)\n", state); + ret = -1; + break; + } +#endif + } + + if (!ret) + WMT_INFO_FUNC("new state(%d) ok\n", state); + else + WMT_WARN_FUNC("new state(%d) fail(%d)\n", state, ret); + + return ret; +} + +static INT32 mt6628_gps_sync_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 ret = -1; + UINT32 uVal = 0; + + if (state == WMT_IC_PIN_MUX) + uVal = 0x1 << 28; + else + uVal = 0x5 << 28; + ret = wmt_core_reg_rw_raw(1, 0x80050078, &uVal, 0x7 << 28); + if (ret != 0) + WMT_ERR_FUNC("gps_sync pin ctrl failed, ret(%d)\n", ret); + /* anyway, we return 0 */ + return 0; +} + + +static INT32 mt6628_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 ret; + + WMT_DBG_FUNC("ic pin id:%d, state:%d, flag:0x%x\n", id, state, flag); + + ret = -1; + switch (id) { + case WMT_IC_PIN_AUDIO: + ret = mt6628_aif_ctrl(state, flag); + break; + + case WMT_IC_PIN_EEDI: + WMT_WARN_FUNC("TBD!!"); + /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ + ret = 0; + break; + + case WMT_IC_PIN_EEDO: + WMT_WARN_FUNC("TBD!!"); + /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ + ret = 0; + break; + case WMT_IC_PIN_GSYNC: + ret = mt6628_gps_sync_ctrl(state, flag); + break; + default: + break; + } + WMT_INFO_FUNC("ret = (%d)\n", ret); + + return ret; +} + +INT32 mt6628_co_clock_ctrl(WMT_CO_CLOCK on) +{ + INT32 iRet = 0; + + if ((on >= WMT_CO_CLOCK_DIS) && (on < WMT_CO_CLOCK_MAX)) + gCoClockEn = on; + else { + WMT_DBG_FUNC("MT6628: error parameter:%d\n", on); + iRet = -1; + } + WMT_DBG_FUNC("MT6628: Co-clock %s\n", + (gCoClockEn == WMT_CO_CLOCK_DIS) ? "disabled" : "enabled"); + + return iRet; +} + +static MTK_WCN_BOOL mt6628_quick_sleep_flag_get(VOID) +{ + return MTK_WCN_BOOL_TRUE; +} + + +static MTK_WCN_BOOL mt6628_aee_dump_flag_get(VOID) +{ + return MTK_WCN_BOOL_TRUE; +} + + +WMT_CO_CLOCK mt6628_co_clock_get(VOID) +{ + return gCoClockEn; +} + + + +static INT32 mt6628_ver_check(VOID) +{ + UINT32 hw_ver = 0; + UINT32 fw_ver = 0; + INT32 iret; + const WMT_IC_INFO_S *p_info; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + + /* 1. identify chip versions: HVR(HW_VER) and FVR(FW_VER) */ + WMT_LOUD_FUNC("MT6628: before read hw_ver (hw version)\n"); + iret = wmt_core_reg_rw_raw(0, GEN_HVR, &hw_ver, GEN_VER_MASK); + if (iret) { + WMT_ERR_FUNC("MT6628: read hw_ver fail:%d\n", iret); + return -2; + } + WMT_INFO_FUNC("MT6628: read hw_ver (hw version) (0x%x)\n", hw_ver); + + WMT_LOUD_FUNC("MT6628: before fw_ver (rom version)\n"); + wmt_core_reg_rw_raw(0, GEN_FVR, &fw_ver, GEN_VER_MASK); + if (iret) { + WMT_ERR_FUNC("MT6628: read fw_ver fail:%d\n", iret); + return -2; + } + WMT_INFO_FUNC("MT6628: read fw_ver (rom version) (0x%x)\n", fw_ver); + + p_info = mt6628_find_wmt_ic_info(hw_ver); + if (p_info == NULL) { + WMT_ERR_FUNC("MT6628: hw_ver(0x%x) find wmt ic info fail\n", hw_ver); + return -3; + } + + WMT_INFO_FUNC("MT6628: wmt ic info: %s.%s (0x%x, patch_ext:%s)\n", + p_info->cChipName, p_info->cChipVersion, + p_info->u4HwVer, p_info->cPatchNameExt); + + /* hw id & version */ + ctrlPa1 = (0x00006628UL << 16) | (hw_ver & 0x0000FFFF); + /* translated fw rom version */ + ctrlPa2 = (fw_ver & 0x0000FFFF); + + iret = wmt_core_ctrl(WMT_CTRL_HWIDVER_SET, &ctrlPa1, &ctrlPa2); + if (iret) + WMT_WARN_FUNC("MT6628: WMT_CTRL_HWIDVER_SET fail(%d)\n", iret); + + gp_mt6628_info = p_info; + return 0; +} + +static const WMT_IC_INFO_S *mt6628_find_wmt_ic_info(const UINT32 hw_ver) +{ + /* match chipversion with u4HwVer item in mt6628_info_table */ + const UINT32 size = ARRAY_SIZE(mt6628_info_table); + INT32 index; + + /* George: reverse the search order to favor newer version products */ + /* TODO:[FixMe][GeorgeKuo] Remove full match once API wmt_lib_get_hwver() + * is changed correctly in the future!! + * Leave full match here is a workaround for GPS to distinguish E3/E4 ICs. + */ + index = size - 1; + /* full match */ + while ((index >= 0) + && (hw_ver != mt6628_info_table[index].u4HwVer) /* full match */ + ) { + --index; + } + if (index >= 0) { + WMT_INFO_FUNC("found ic info(0x%x) by full match! index:%d\n", hw_ver, index); + return &mt6628_info_table[index]; + } + + WMT_WARN_FUNC("find no ic info for (0x%x) by full match!try major num match!\n", hw_ver); + + /* George: The ONLY CORRECT method to find supported hw table. Match MAJOR + * NUM only can help us support future minor hw ECO, or fab switch, etc. + * FULL matching eliminate such flexibility and software package have to be + * updated EACH TIME even when minor hw ECO or fab switch!!! + */ + /* George: reverse the search order to favor newer version products */ + index = size - 1; + /* major num match */ + while ((index >= 0) + && (MAJORNUM(hw_ver) != MAJORNUM(mt6628_info_table[index].u4HwVer)) + ) { + --index; + } + if (index >= 0) { + WMT_INFO_FUNC("MT6628: found ic info for hw_ver(0x%x) by major num! index:%d\n", + hw_ver, index); + return &mt6628_info_table[index]; + } + + WMT_ERR_FUNC + ("MT6628: find no ic info for hw_ver(0x%x) by full match nor major num match!\n", + hw_ver); + return NULL; +} + + +static INT32 wmt_stp_init_coex(VOID) +{ + INT32 iRet; + ULONG addr = 0; + WMT_GEN_CONF *pWmtGenConf; + +#define COEX_WMT 0 + +#if CFG_SUBSYS_COEX_NEED + /* no need for MT6628 */ +#define COEX_BT 1 +#define COEX_WIFI 2 +#define COEX_PTA 3 +#define COEX_MISC 4 +#endif + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + + /*Dump the coex-related info */ + WMT_DBG_FUNC("coex_wmt:0x%x\n", pWmtGenConf->coex_wmt_ant_mode); +#if CFG_SUBSYS_COEX_NEED + WMT_DBG_FUNC("coex_bt:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_bt_rssi_upper_limit, + pWmtGenConf->coex_bt_rssi_mid_limit, + pWmtGenConf->coex_bt_rssi_lower_limit, + pWmtGenConf->coex_bt_pwr_high, + pWmtGenConf->coex_bt_pwr_mid, pWmtGenConf->coex_bt_pwr_low); + WMT_DBG_FUNC("coex_wifi:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_wifi_rssi_upper_limit, + pWmtGenConf->coex_wifi_rssi_mid_limit, + pWmtGenConf->coex_wifi_rssi_lower_limit, + pWmtGenConf->coex_wifi_pwr_high, + pWmtGenConf->coex_wifi_pwr_mid, pWmtGenConf->coex_wifi_pwr_low); + WMT_DBG_FUNC("coex_ext_pta:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_ext_pta_hi_tx_tag, + pWmtGenConf->coex_ext_pta_hi_rx_tag, + pWmtGenConf->coex_ext_pta_lo_tx_tag, + pWmtGenConf->coex_ext_pta_lo_rx_tag, + pWmtGenConf->coex_ext_pta_sample_t1, + pWmtGenConf->coex_ext_pta_sample_t2, + pWmtGenConf->coex_ext_pta_wifi_bt_con_trx); + WMT_DBG_FUNC("coex_misc:0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_misc_ext_pta_on, pWmtGenConf->coex_misc_ext_feature_set); +#endif + + /*command adjustion due to WMT.cfg */ + coex_table[COEX_WMT].cmd[5] = pWmtGenConf->coex_wmt_ant_mode; + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_WMT].cmd[0], + coex_table[COEX_WMT].str, coex_table[COEX_WMT].cmdSz); + } +#if CFG_SUBSYS_COEX_NEED + coex_table[COEX_BT].cmd[9] = pWmtGenConf->coex_bt_rssi_upper_limit; + coex_table[COEX_BT].cmd[10] = pWmtGenConf->coex_bt_rssi_mid_limit; + coex_table[COEX_BT].cmd[11] = pWmtGenConf->coex_bt_rssi_lower_limit; + coex_table[COEX_BT].cmd[12] = pWmtGenConf->coex_bt_pwr_high; + coex_table[COEX_BT].cmd[13] = pWmtGenConf->coex_bt_pwr_mid; + coex_table[COEX_BT].cmd[14] = pWmtGenConf->coex_bt_pwr_low; + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_BT].cmd[0], + coex_table[COEX_BT].str, coex_table[COEX_BT].cmdSz); + } + coex_table[COEX_WIFI].cmd[10] = pWmtGenConf->coex_wifi_rssi_upper_limit; + coex_table[COEX_WIFI].cmd[11] = pWmtGenConf->coex_wifi_rssi_mid_limit; + coex_table[COEX_WIFI].cmd[12] = pWmtGenConf->coex_wifi_rssi_lower_limit; + coex_table[COEX_WIFI].cmd[13] = pWmtGenConf->coex_wifi_pwr_high; + coex_table[COEX_WIFI].cmd[14] = pWmtGenConf->coex_wifi_pwr_mid; + coex_table[COEX_WIFI].cmd[15] = pWmtGenConf->coex_wifi_pwr_low; + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_WIFI].cmd[0], + coex_table[COEX_WIFI].str, coex_table[COEX_WIFI].cmdSz); + } + coex_table[COEX_PTA].cmd[5] = pWmtGenConf->coex_ext_pta_hi_tx_tag; + coex_table[COEX_PTA].cmd[6] = pWmtGenConf->coex_ext_pta_hi_rx_tag; + coex_table[COEX_PTA].cmd[7] = pWmtGenConf->coex_ext_pta_lo_tx_tag; + coex_table[COEX_PTA].cmd[8] = pWmtGenConf->coex_ext_pta_lo_rx_tag; + coex_table[COEX_PTA].cmd[9] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0xff00) >> 8); + coex_table[COEX_PTA].cmd[10] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0x00ff) >> 0); + coex_table[COEX_PTA].cmd[11] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0xff00) >> 8); + coex_table[COEX_PTA].cmd[12] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0x00ff) >> 0); + coex_table[COEX_PTA].cmd[13] = pWmtGenConf->coex_ext_pta_wifi_bt_con_trx; + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_PTA].cmd[0], + coex_table[COEX_PTA].str, coex_table[COEX_PTA].cmdSz); + } + + osal_memcpy(&coex_table[COEX_MISC].cmd[5], &pWmtGenConf->coex_misc_ext_pta_on, + sizeof(pWmtGenConf->coex_misc_ext_pta_on)); + osal_memcpy(&coex_table[COEX_MISC].cmd[9], &pWmtGenConf->coex_misc_ext_feature_set, + sizeof(pWmtGenConf->coex_misc_ext_feature_set)); + + wmt_core_dump_data(&coex_table[COEX_MISC].cmd[0], coex_table[COEX_MISC].str, + coex_table[COEX_MISC].cmdSz); +#endif + + iRet = wmt_core_init_script(coex_table, ARRAY_SIZE(coex_table)); + + return iRet; +} + + +static INT32 mt6628_set_sdio_driving(VOID) +{ + INT32 ret = 0; + + ULONG addr = 0; + WMT_GEN_CONF *pWmtGenConf; + UINT32 drv_val = 0; + + /*Get wmt config */ + ret = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (ret) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", ret); + return -1; + } + WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%8lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + drv_val = pWmtGenConf->sdio_driving_cfg; + + /*Dump the sdio driving related info */ + WMT_INFO_FUNC("sdio driving:0x%x\n", drv_val); + + sdio_driving_table[0].cmd[12] = (UINT8) ((drv_val & 0x00000077UL) >> 0); /* DAT0 and DAT1 */ + sdio_driving_table[0].cmd[13] = (UINT8) ((drv_val & 0x00007700UL) >> 8); /* DAT2 and DAT3 */ + sdio_driving_table[0].cmd[14] = (UINT8) ((drv_val & 0x00070000UL) >> 16); /* CMD */ + + ret = wmt_core_init_script(sdio_driving_table, ARRAY_SIZE(sdio_driving_table)); + + return ret; +} + + +static INT32 mt6628_crystal_triming_set(VOID) +{ + INT32 iRet = 0; + PUINT8 pbuf = NULL; + UINT32 bufLen = 0; + WMT_CTRL_DATA ctrlData; + UINT32 uCryTimOffset = 0x6D; + MTK_WCN_BOOL bIsNvramExist = MTK_WCN_BOOL_FALSE; + INT8 cCrystalTimingOffset = 0x0; + UINT8 cCrystalTiming = 0x0; + INT32 iCrystalTiming = 0x0; + MTK_WCN_BOOL bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + UINT32 u4Res; + + bIsNvramExist = MTK_WCN_BOOL_FALSE; + ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_GET; + ctrlData.au4CtrlData[0] = (size_t) "/data/nvram/APCFG/APRDEB/WIFI"; + ctrlData.au4CtrlData[1] = (size_t) &pbuf; + ctrlData.au4CtrlData[2] = (size_t) &bufLen; + + iRet = wmt_ctrl(&ctrlData); + if (iRet != 0) { + WMT_ERR_FUNC("MT6628: WMT_CTRL_CRYSTAL_TRIMING_GET fail:%d\n", iRet); + bIsNvramExist = MTK_WCN_BOOL_FALSE; + bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + cCrystalTimingOffset = 0x0; + cCrystalTiming = 0x0; + iRet = -1; + } else { + WMT_DBG_FUNC("MT6628: nvram pBuf(%p), bufLen(%d)\n", pbuf, bufLen); + if (bufLen < (uCryTimOffset + 1)) { + WMT_ERR_FUNC + ("MT6628: nvram len(%d) too short, crystalTimging value offset(%d)\n", + bufLen, uCryTimOffset); + bIsNvramExist = MTK_WCN_BOOL_FALSE; + bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + cCrystalTimingOffset = 0x0; + cCrystalTiming = 0x0; + } else { + bIsNvramExist = MTK_WCN_BOOL_TRUE; + cCrystalTimingOffset = *(pbuf + uCryTimOffset); + if (cCrystalTimingOffset & 0x80) { + bIsCrysTrimEnabled = MTK_WCN_BOOL_TRUE; + cCrystalTimingOffset = (UINT8) cCrystalTimingOffset & 0x7f; + } + WMT_DBG_FUNC("cCrystalTimingOffset (%d), bIsCrysTrimEnabled(%d)\n", + cCrystalTimingOffset, bIsCrysTrimEnabled); + } + ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_PUT; + ctrlData.au4CtrlData[0] = (size_t) "/data/nvram/APCFG/APRDEB/WIFI"; + iRet = wmt_ctrl(&ctrlData); + if (iRet != 0) { + WMT_ERR_FUNC("MT6628: WMT_CTRL_CRYSTAL_TRIMING_PUT fail:%d\n", iRet); + iRet = -2; + } else { + WMT_DBG_FUNC("MT6628: WMT_CTRL_CRYSTAL_TRIMING_PUT succeed\n"); + } + } + if ((bIsNvramExist == MTK_WCN_BOOL_TRUE) && (bIsCrysTrimEnabled == MTK_WCN_BOOL_TRUE)) { + /*get CrystalTiming value before set it */ + iRet = + wmt_core_tx(get_crystal_timing_script[0].cmd, + get_crystal_timing_script[0].cmdSz, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != get_crystal_timing_script[0].cmdSz)) { + WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", + get_crystal_timing_script[0].str, iRet, u4Res, + get_crystal_timing_script[0].cmdSz); + iRet = -3; + goto done; + } + /* EVENT BUF */ + osal_memset(get_crystal_timing_script[0].evt, 0, + get_crystal_timing_script[0].evtSz); + iRet = + wmt_core_rx(get_crystal_timing_script[0].evt, + get_crystal_timing_script[0].evtSz, &u4Res); + if (iRet || (u4Res != get_crystal_timing_script[0].evtSz)) { + WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", + get_crystal_timing_script[0].str, iRet, u4Res, + get_crystal_timing_script[0].evtSz); + mtk_wcn_stp_dbg_dump_package(); + iRet = -4; + goto done; + } + + iCrystalTiming = WMT_GET_CRYSTAL_TRIMING_EVT[5] & 0x7f; + if (cCrystalTimingOffset & 0x40) { + /*nagative offset value */ + iCrystalTiming = iCrystalTiming + cCrystalTimingOffset - 128; + } else { + iCrystalTiming += cCrystalTimingOffset; + } + WMT_DBG_FUNC("iCrystalTiming (0x%x)\n", iCrystalTiming); + if (iCrystalTiming > 0x7f) + cCrystalTiming = 0x7f; + else if (iCrystalTiming < 0) + cCrystalTiming = 0; + else + cCrystalTiming = iCrystalTiming; + WMT_DBG_FUNC("cCrystalTiming (0x%x)\n", cCrystalTiming); + /* set_crystal_timing_script */ + WMT_SET_CRYSTAL_TRIMING_CMD[5] = cCrystalTiming; + WMT_GET_CRYSTAL_TRIMING_EVT[5] = cCrystalTiming; + + iRet = + wmt_core_init_script(set_crystal_timing_script, + osal_array_size(set_crystal_timing_script)); + if (iRet) { + WMT_ERR_FUNC("set_crystal_timing_script fail(%d)\n", iRet); + iRet = -5; + } else { + WMT_DBG_FUNC("set crystal timing value (0x%x) succeed\n", + WMT_SET_CRYSTAL_TRIMING_CMD[5]); + iRet = + wmt_core_init_script(get_crystal_timing_script, + osal_array_size(get_crystal_timing_script)); + if (iRet) { + WMT_ERR_FUNC("get_crystal_timing_script fail(%d)\n", iRet); + iRet = -6; + } else { + WMT_INFO_FUNC("succeed, updated crystal timing value (0x%x)\n", + WMT_GET_CRYSTAL_TRIMING_EVT[5]); + iRet = 0x0; + } + } + } +done: + return iRet; +} + + +#if CFG_WMT_MULTI_PATCH +static INT32 mt6628_patch_info_prepare(VOID) +{ + INT32 iRet = -1; + WMT_CTRL_DATA ctrlData; + + ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; + iRet = wmt_ctrl(&ctrlData); + + return iRet; +} + + +static INT32 mt6628_patch_dwn(UINT32 index) +{ + INT32 iRet = -1; + P_WMT_PATCH patchHdr; + PUINT8 pbuf; + UINT32 patchSize; + UINT32 fragSeq; + UINT32 fragNum; + UINT16 fragSize = 0; + UINT16 cmdLen; + UINT32 offset; + UINT32 u4Res; + UINT8 evtBuf[8]; + UINT8 addressevtBuf[12]; + UINT8 addressByte[4]; + PINT8 cDataTime = NULL; + /*PINT8 cPlat = NULL; */ + UINT16 u2HwVer = 0; + UINT16 u2SwVer = 0; + UINT32 u4PatchVer = 0; + UINT32 patchSizePerFrag = 0; + WMT_CTRL_DATA ctrlData; + + /*1.check hardware information */ + if (gp_mt6628_info == NULL) { + WMT_ERR_FUNC("null gp_mt6628_info!\n"); + return -1; + } + + osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName)); + + ctrlData.ctrlId = WMT_CTRL_GET_PATCH_INFO; + ctrlData.au4CtrlData[0] = index + 1; + ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName; + ctrlData.au4CtrlData[2] = (size_t) &addressByte; + iRet = wmt_ctrl(&ctrlData); + WMT_INFO_FUNC("the %d time valid patch found: (%s)\n", index + 1, gFullPatchName); + + /* <2.2> read patch content */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH; + ctrlData.au4CtrlData[0] = (size_t) NULL; + ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName; + ctrlData.au4CtrlData[2] = (size_t) &pbuf; + ctrlData.au4CtrlData[3] = (size_t) &patchSize; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); + iRet -= 1; + goto done; + } + + /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ + pbuf += BCNT_PATCH_BUF_HEADROOM; + /* patch file with header: + * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| + */ + patchHdr = (P_WMT_PATCH) pbuf; + /* check patch file information */ + + cDataTime = patchHdr->ucDateTime; + u2HwVer = patchHdr->u2HwVer; + u2SwVer = patchHdr->u2SwVer; + u4PatchVer = patchHdr->u4PatchVer; + /*cPlat = &patchHdr->ucPLat[0]; */ + + cDataTime[15] = '\0'; + if (index == 0) { + WMT_INFO_FUNC("===========================================\n"); + WMT_INFO_FUNC("[Combo Patch] Built Time = %s\n", cDataTime); + WMT_INFO_FUNC("[Combo Patch] Hw Ver = 0x%x\n", + ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8)); + WMT_INFO_FUNC("[Combo Patch] Sw Ver = 0x%x\n", + ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8)); + WMT_INFO_FUNC("[Combo Patch] Ph Ver = 0x%04x\n", + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> + 16)); + WMT_INFO_FUNC("[Combo Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0], + patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + WMT_INFO_FUNC("===========================================\n"); + } + + /* remove patch header: + * |<-patch body: X Bytes (X=patchSize)--->| + */ + if (patchSize < sizeof(WMT_PATCH)) { + WMT_ERR_FUNC("error patch size\n"); + iRet = -1; + goto done; + } + patchSize -= sizeof(WMT_PATCH); + pbuf += sizeof(WMT_PATCH); + patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; + /* reserve 1st patch cmd space before patch body + * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| + */ + osal_memcpy(&gp_mt6628_patch_info, patchHdr, osal_sizeof(WMT_PATCH)); + pbuf -= sizeof(WMT_PATCH_CMD); + + fragNum = patchSize / patchSizePerFrag; + fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; + + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + + /*send wmt part patch address command */ + iRet = + wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD[0], sizeof(WMT_PATCH_ADDRESS_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD))) { + WMT_ERR_FUNC("wmt_core:wmt patch address CMD fail(%d),size(%d)\n", iRet, u4Res); + iRet -= 1; + goto done; + } + osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); + iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT))) { + WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res); + iRet -= 1; + goto done; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(addressevtBuf, WMT_PATCH_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) != + 0) { + WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail\n"); + iRet -= 1; + goto done; + } +#endif + + /*send part patch address command */ + osal_memcpy(&WMT_PATCH_P_ADDRESS_CMD[12], addressByte, osal_sizeof(addressByte)); + WMT_INFO_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x", + WMT_PATCH_P_ADDRESS_CMD[12], + WMT_PATCH_P_ADDRESS_CMD[13], + WMT_PATCH_P_ADDRESS_CMD[14], WMT_PATCH_P_ADDRESS_CMD[15]); + iRet = + wmt_core_tx((PUINT8) &WMT_PATCH_P_ADDRESS_CMD[0], sizeof(WMT_PATCH_P_ADDRESS_CMD), + &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_CMD))) { + WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d),index(%d)\n", + iRet, u4Res, index); + iRet -= 1; + goto done; + } + osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); + iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_P_ADDRESS_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_EVT))) { + WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d),index(%d)\n", iRet, + u4Res, index); + iRet -= 1; + goto done; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(addressevtBuf, WMT_PATCH_P_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) + != 0) { + WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail,index(%d)\n", + index); + iRet -= 1; + goto done; + } +#endif + + /* send all fragments */ + offset = sizeof(WMT_PATCH_CMD); + fragSeq = 0; + while (fragSeq < fragNum) { + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + if (fragSeq == (fragNum - 1)) { + /* last fragment */ + fragSize = patchSize - fragSeq * patchSizePerFrag; + WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; + } else { + fragSize = patchSizePerFrag; + WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; + } + /* update length field in CMD:flag+frag */ + cmdLen = 1 + fragSize; + osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); + /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ + osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, + sizeof(WMT_PATCH_CMD)); + /* iRet = (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), + * fragSize + sizeof(WMT_PATCH_CMD), &u4Res); + */ + iRet = + wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD), + fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) fail(%d)\n", fragSeq, + fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); + iRet -= 1; + break; + } + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) ok\n", + fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); + + osal_memset(evtBuf, 0, sizeof(evtBuf)); + /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ + iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) fail(%d)\n", + sizeof(WMT_PATCH_EVT), u4Res, iRet); + iRet -= 1; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0], WMT_PATCH_EVT[1], + WMT_PATCH_EVT[2], WMT_PATCH_EVT[3], WMT_PATCH_EVT[4]); + iRet -= 1; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) ok\n", + sizeof(WMT_PATCH_EVT), u4Res); + offset += patchSizePerFrag; + ++fragSeq; + } + + WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", + iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); + + if (fragSeq != fragNum) + iRet -= 1; +done: + /* WMT_CTRL_FREE_PATCH always return 0 */ + /* wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); */ + ctrlData.ctrlId = WMT_CTRL_FREE_PATCH; + ctrlData.au4CtrlData[0] = index + 1; + wmt_ctrl(&ctrlData); + + return iRet; +} + +#else +static INT32 mt6628_patch_dwn(VOID) +{ + INT32 iRet = -1; + P_WMT_PATCH patchHdr; + PUINT8 pbuf; + UINT32 patchSize; + UINT32 fragSeq; + UINT32 fragNum; + UINT16 fragSize = 0; + UINT16 cmdLen; + UINT32 offset; + UINT32 u4Res; + UINT8 evtBuf[8]; + PINT8 cDataTime = NULL; + /*PINT8 cPlat = NULL; */ + UINT16 u2HwVer = 0; + UINT16 u2SwVer = 0; + UINT32 u4PatchVer = 0; + UINT32 patchSizePerFrag = 0; + WMT_CTRL_DATA ctrlData; + + /*1.check hardware information */ + if (gp_mt6628_info == NULL) { + WMT_ERR_FUNC("null gp_mt6628_info!\n"); + return -1; + } + /* <2> search patch and read patch content */ + /* <2.1> search patch */ + ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; + iRet = wmt_ctrl(&ctrlData); + if (iRet == 0) { + /* patch with correct Hw Ver Major Num found */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH_NAME; + ctrlData.au4CtrlData[0] = (size_t) &gFullPatchName; + iRet = wmt_ctrl(&ctrlData); + + WMT_INFO_FUNC("valid patch found: (%s)\n", gFullPatchName); + /* <2.2> read patch content */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH; + ctrlData.au4CtrlData[0] = (size_t) NULL; + ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName; + + } else { + iRet -= 1; + return iRet; + } + ctrlData.au4CtrlData[2] = (size_t) &pbuf; + ctrlData.au4CtrlData[3] = (size_t) &patchSize; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); + iRet -= 1; + goto done; + } + + /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ + pbuf += BCNT_PATCH_BUF_HEADROOM; + /* patch file with header: + * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| + */ + patchHdr = (P_WMT_PATCH) pbuf; + /* check patch file information */ + + cDataTime = patchHdr->ucDateTime; + u2HwVer = patchHdr->u2HwVer; + u2SwVer = patchHdr->u2SwVer; + u4PatchVer = patchHdr->u4PatchVer; + /*cPlat = &patchHdr->ucPLat[0]; */ + + cDataTime[15] = '\0'; + WMT_INFO_FUNC("===========================================\n"); + WMT_INFO_FUNC("[Combo Patch] Built Time = %s\n", cDataTime); + WMT_INFO_FUNC("[Combo Patch] Hw Ver = 0x%x\n", + ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8)); + WMT_INFO_FUNC("[Combo Patch] Sw Ver = 0x%x\n", + ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8)); + WMT_INFO_FUNC("[Combo Patch] Ph Ver = 0x%04x\n", + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16)); + WMT_INFO_FUNC("[Combo Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0], + patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + WMT_INFO_FUNC("===========================================\n"); + + /* remove patch header: + * |<-patch body: X Bytes (X=patchSize)--->| + */ + if (patchSize < sizeof(WMT_PATCH)) { + WMT_ERR_FUNC("error patch size\n"); + return -1; + } + patchSize -= sizeof(WMT_PATCH); + pbuf += sizeof(WMT_PATCH); + patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; + /* reserve 1st patch cmd space before patch body + * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| + */ + osal_memcpy(&gp_mt6628_patch_info, patchHdr, osal_sizeof(WMT_PATCH)); + pbuf -= sizeof(WMT_PATCH_CMD); + + fragNum = patchSize / patchSizePerFrag; + fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; + + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + + /* send all fragments */ + offset = sizeof(WMT_PATCH_CMD); + fragSeq = 0; + while (fragSeq < fragNum) { + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + if (fragSeq == (fragNum - 1)) { + /* last fragment */ + fragSize = patchSize - fragSeq * patchSizePerFrag; + WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; + } else { + fragSize = patchSizePerFrag; + WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; + } + /* update length field in CMD:flag+frag */ + cmdLen = 1 + fragSize; + osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); + /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ + osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, + sizeof(WMT_PATCH_CMD)); + + /* iRet = (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), + * fragSize + sizeof(WMT_PATCH_CMD), &u4Res); + */ + iRet = + wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD), + fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, + fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); + iRet -= 1; + break; + } + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", + fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); + + osal_memset(evtBuf, 0, sizeof(evtBuf)); + /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ + iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n", + sizeof(WMT_PATCH_EVT), u4Res, iRet); + iRet -= 1; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0], WMT_PATCH_EVT[1], + WMT_PATCH_EVT[2], WMT_PATCH_EVT[3], WMT_PATCH_EVT[4]); + iRet -= 1; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n", + sizeof(WMT_PATCH_EVT), u4Res); + offset += patchSizePerFrag; + ++fragSeq; + } + + WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", + iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); + + if (fragSeq != fragNum) + iRet -= 1; +done: + /* WMT_CTRL_FREE_PATCH always return 0 */ + wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); + + return iRet; +} + +#endif + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6630.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6630.c new file mode 100644 index 00000000000000..8f31b5ebd9691d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6630.c @@ -0,0 +1,2043 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-IC]" +#define CFG_IC_MT6630 1 + +#define MT6630_BRINGUP 0 +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "wmt_ic.h" +#include "wmt_core.h" +#include "wmt_lib.h" +#include "stp_core.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define DEFAULT_PATCH_FRAG_SIZE (1000) +#define WMT_PATCH_FRAG_1ST (0x1) +#define WMT_PATCH_FRAG_MID (0x2) +#define WMT_PATCH_FRAG_LAST (0x3) + +#define CFG_CHECK_WMT_RESULT (1) +/* BT Port 2 Feature. this command does not need after coex command is downconfirmed by LC, */ +#define CFG_WMT_BT_PORT2 (0) + +#define CFG_SET_OPT_REG (0) +#define CFG_WMT_I2S_DBGUART_SUPPORT (0) +#define CFG_SET_OPT_REG_SWLA (0) +#define CFG_SET_OPT_REG_MCUCLK (0) +#define CFG_SET_OPT_REG_MCUIRQ (0) + +#define CFG_SUBSYS_COEX_NEED 0 + +#define CFG_WMT_COREDUMP_ENABLE 0 + +#define CFG_WMT_MULTI_PATCH (1) + +#define CFG_WMT_CRYSTAL_TIMING_SET (0) + +#if CFG_WMT_LTE_COEX_HANDLING +#define CFG_WMT_FILTER_MODE_SETTING (1) +#else +#define CFG_WMT_FILTER_MODE_SETTING (0) +#endif +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +static UINT8 gFullPatchName[NAME_MAX + 1]; +static const WMT_IC_INFO_S *gp_mt6630_info; +static WMT_PATCH gp_mt6630_patch_info; +static WMT_CO_CLOCK gCoClockEn = WMT_CO_CLOCK_DIS; + +static UINT8 WMT_QUERY_BAUD_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x02 }; +static UINT8 WMT_QUERY_BAUD_EVT_115200[] = { + 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x01, 0x00 }; +static UINT8 WMT_QUERY_BAUD_EVT_X[] = { + 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0xAA, 0xAA, 0xAA, 0xBB }; +static UINT8 WMT_QUERY_STP_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x04 }; +static UINT8 WMT_QUERY_STP_EVT_DEFAULT[] = { + 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 }; +static UINT8 WMT_QUERY_STP_EVT_UART[] = { + 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0xDF, 0x0E, 0x68, 0x01 }; +static UINT8 WMT_SET_BAUD_CMD_X[] = { 0x01, 0x04, 0x05, 0x00, 0x01, 0xAA, 0xAA, 0xAA, 0xBB }; +static UINT8 WMT_SET_BAUD_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x01 }; +static UINT8 WMT_SET_WAKEUP_WAKE_CMD_RAW[] = { 0xFF }; +static UINT8 WMT_SET_WAKEUP_WAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; +static UINT8 WMT_PATCH_CMD[] = { 0x01, 0x01, 0x00, 0x00, 0x00 }; +static UINT8 WMT_PATCH_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00 }; +static UINT8 WMT_RESET_CMD[] = { 0x01, 0x07, 0x01, 0x00, 0x04 }; +static UINT8 WMT_RESET_EVT[] = { 0x02, 0x07, 0x01, 0x00, 0x00 }; + +#if CFG_WMT_BT_PORT2 +static UINT8 WMT_BTP2_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x01, 0x03, 0x01 }; +static UINT8 WMT_BTP2_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#endif + +#if CFG_WMT_MULTI_PATCH +static UINT8 WMT_PATCH_ADDRESS_CMD[] = { 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, +0xD4, 0x03, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff }; + +static UINT8 WMT_PATCH_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +static UINT8 WMT_PATCH_P_ADDRESS_CMD[] = { 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, +0xfc, 0x08, 0x09, 0x02, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff, 0xff, 0xff }; + +static UINT8 WMT_PATCH_P_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; +#endif + +/*coex cmd/evt++*/ +static UINT8 WMT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x01, 0x00 }; +static UINT8 WMT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +#if CFG_SUBSYS_COEX_NEED +static UINT8 WMT_BT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0B, + 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, + 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA +}; +static UINT8 WMT_BT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0C, + 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA +}; +static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_PTA_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0A, + 0x00, 0x04, + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF, 0xFE +}; +static UINT8 WMT_PTA_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINt8 WMT_MISC_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x09, + 0x00, 0x05, + 0xAA, 0xAA, 0xAA, 0xAA, + 0xBB, 0xBB, 0xBB, 0xBB +}; +static UINT8 WMT_MISC_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#endif + +/*coex cmd/evt--*/ +static UINT8 WMT_SET_STP_CMD[] = { 0x01, 0x04, 0x05, 0x00, 0x03, 0xDF, 0x0E, 0x68, 0x01 }; +static UINT8 WMT_SET_STP_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x03 }; +static UINT8 WMT_STRAP_CONF_CMD_FM_COMM[] = { 0x01, 0x05, 0x02, 0x00, 0x02, 0x02 }; +static UINT8 WMT_STRAP_CONF_EVT[] = { 0x02, 0x05, 0x02, 0x00, 0x00, 0x02 }; + +/* to get full dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_04_CMD[] = { + 0x1, 0x0F, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UINT8 WMT_CORE_DUMP_LEVEL_04_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_CORE_CO_CLOCK_CMD[] = { 0x1, 0x0A, 0x02, 0x00, 0x08, 0x03 }; +static UINT8 WMT_CORE_CO_CLOCK_EVT[] = { 0x2, 0x0A, 0x01, 0x00, 0x00 }; + + +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) + + +static UINT8 WMT_SET_DAI_MODE_REG_CMD[] = { 0x01, 0x08, 0x28, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x03 /*2 registers */ + , 0x6c, 0x50, 0x02, 0x80 /*addr:0x8002506c */ + , 0x00, 0x00, 0x10, 0x11 /*value:0x11100000 */ + , 0x00, 0x00, 0xf0, 0xff /*mask:0xfff00000 */ + , 0x70, 0x50, 0x02, 0x80 /*addr:0x80025070 */ + , 0x01, 0x00, 0x00, 0x00 /*value:0x00000001 */ + , 0x0f, 0x00, 0x00, 0x00 /*mask:0x0000000f */ + , 0x00, 0x53, 0x02, 0x80 /*addr:0x80025300 */ + , 0x04, 0x00, 0x00, 0x00 /*value:0x00000004 */ + , 0x04, 0x00, 0x00, 0x00 /*mask:0x00000004 */ +}; + +static UINT8 WMT_SET_DAI_MODE_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x03 /*2 registers */ +}; + + +#endif + + +#if CFG_SET_OPT_REG_SWLA /* enable swla: eesk(7) eecs(8) oscen(19) sck0(24) scs0(25) */ +static UINT8 WMT_SET_SWLA_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ + , 0x10, 0x01, 0x05, 0x80 /*addr:0x80050110 */ + , 0x10, 0x10, 0x01, 0x00 /*value:0x00011010 */ + , 0xF0, 0xF0, 0x0F, 0x00 /*mask:0x000FF0F0 */ + , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ + , 0x00, 0x10, 0x01, 0x00 /*value:0x00011000 */ + , 0x00, 0xF0, 0x0F, 0x00 /*mask:0x000FF000 */ +}; + +static UINT8 WMT_SET_SWLA_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ +}; +#endif + +#if CFG_SET_OPT_REG_MCUCLK /* enable mcu clk: antsel_4, eedi */ +static UINT8 WMT_SET_MCUCLK_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000 0400 */ + , 0x00, 0x14, 0x00, 0x00 /* value:0x0000 1400(osc, hclk), 0x0000 1501(PLL, en) */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005 0180 */ + , 0x12, 0x13, 0x00, 0x00 /* value:0x0000 1312(osc, hclk), 0x0000 1a19(PLL, en) */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005 0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002 0000 */ + , 0x00, 0x00, 0x0F, 0x00 /* mask:0x000F 0000 */ + , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005 0110 */ + , 0x02, 0x00, 0x00, 0x00 /* value:0x0000 0002 */ + , 0x0F, 0x00, 0x00, 0x00 /* mask:0x0000 000F */ +}; + +static UINT8 WMT_SET_MCUCLK_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ +}; +#endif + +#if CFG_WMT_I2S_DBGUART_SUPPORT /* register write for debug uart */ +static UINT8 WMT_SET_DBGUART_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ + , 0x30, 0x01, 0x05, 0x80 /*addr:0x80050130 */ + , 0x00, 0x00, 0x00, 0x00 /*value:0x00000000 */ + , 0xF0, 0x0F, 0x00, 0x00 /*mask:0x00000FF0 */ + , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ + , 0x00, 0x01, 0x00, 0x00 /*value:0x00000100 */ + , 0x00, 0x01, 0x00, 0x00 /*mask:0x00000100 */ +}; + +static UINT8 WMT_SET_DBGUART_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ +}; +#endif + +#if CFG_SET_OPT_REG_MCUIRQ /* enable mcu irq: antsel_4, wlan_act */ +static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ + , 0x03, 0x14, 0x00, 0x00 /* value:0x0000_1403 check confg debug flag 3 low word */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000_FFFF */ + /* cirq_int_n */ + , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005_0110 */ + , 0x02, 0x00, 0x00, 0x00 /* value:0x0000_0002 set EEDI as cirq_int_n debug flag (monitor flag2) */ + , 0x07, 0x00, 0x00, 0x00 /* mask:0x0000_0007 */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0, ahb_x2_gt_ck debug flag) */ + , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ + /* 1. ARM irq_b, monitor flag 0 */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ + , 0x1F, 0x1E, 0x00, 0x00 /* value:0x0000_1E1F check mcusys debug flag */ + , 0x7F, 0x7F, 0x00, 0x00 /* mask:0x0000_7F7F */ +}; + +static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 5 registers */ +}; +#endif + +static UINT8 WMT_SET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x01, 0x00 }; +static UINT8 WMT_SET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x01, 0x00 }; + +#if CFG_WMT_CRYSTAL_TIMING_SET +static UINT8 WMT_GET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x00, 0x00 }; +static UINT8 WMT_GET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x00, 0x00 }; +#endif + + +#if CFG_WMT_FILTER_MODE_SETTING +static UINT8 WMT_COEX_EXT_COMPONENT_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x0d, 0x00, 0x00 }; + +static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = { 0x01, 0x10, 0x45, 0x00, 0x11, + 0x00, 0x00, 0x01, 0x00, 0x11, + 0x11, 0x16, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x63, 0x63, 0x63, + 0x00, 0x39, 0x43, 0x63, 0x63, + 0x02, 0x02, 0x03, 0x00, 0x01, + 0x01, 0x01, 0x01, 0x0e, 0x0e, + 0x0e, 0x00, 0x0a, 0x0c, 0x0e, + 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 +}; + +static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD[] = { 0x01, 0x10, 0x21, 0x00, 0x12, + 0xfc, 0x08, 0x15, 0x09, 0x2e, + 0x09, 0x47, 0x09, 0xc4, 0x09, + 0xd4, 0x09, 0xe3, 0x09, 0x5a, + 0x0a, 0x14, 0x09, 0x2d, 0x09, + 0x46, 0x09, 0x60, 0x09, 0xd3, + 0x09, 0xe2, 0x09, 0x59, 0x0a, + 0x8B, 0x0a +}; + +static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 }; + +#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING +#else +static UINT8 WMT_COEX_IS_LTE_L_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x21, 0x01 }; +#endif + +static UINT8 WMT_COEX_IS_LTE_PROJ_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x15, 0x01 }; + +static UINT8 WMT_COEX_SPLIT_MODE_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#endif + +static struct init_script init_table_1_2[] = { + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_115200, "query baud 115200"), + INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_DEFAULT, "query stp default"), + INIT_CMD(WMT_SET_BAUD_CMD_X, WMT_SET_BAUD_EVT, "set baud rate"), +}; + + +static struct init_script init_table_2[] = { + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"), +}; + +static struct init_script init_table_3[] = { + INIT_CMD(WMT_RESET_CMD, WMT_RESET_EVT, "wmt reset"), +#if CFG_WMT_BT_PORT2 + INIT_CMD(WMT_BTP2_CMD, WMT_BTP2_EVT, "set bt port2"), +#endif +}; + +static struct init_script set_crystal_timing_script[] = { + INIT_CMD(WMT_SET_CRYSTAL_TRIMING_CMD, WMT_SET_CRYSTAL_TRIMING_EVT, + "set crystal trim value"), +}; + +#if CFG_WMT_CRYSTAL_TIMING_SET +static struct init_script get_crystal_timing_script[] = { + INIT_CMD(WMT_GET_CRYSTAL_TRIMING_CMD, WMT_GET_CRYSTAL_TRIMING_EVT, + "get crystal trim value"), +}; +#endif + +static struct init_script init_table_4[] = { + INIT_CMD(WMT_SET_STP_CMD, WMT_SET_STP_EVT, "set stp"), +}; + +static struct init_script init_table_5[] = { + INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_UART, "query stp uart"), + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"), +}; + +static struct init_script init_table_5_1[] = { + INIT_CMD(WMT_STRAP_CONF_CMD_FM_COMM, WMT_STRAP_CONF_EVT, "configure FM comm"), +}; + +static struct init_script init_table_6[] = { + INIT_CMD(WMT_CORE_DUMP_LEVEL_04_CMD, WMT_CORE_DUMP_LEVEL_04_EVT, "setup core dump level"), +}; + + +#if defined(CFG_SET_OPT_REG) && CFG_SET_OPT_REG +static struct init_script set_registers[] = { + /* INIT_CMD(WMT_SET_GPS_REG_CMD, WMT_SET_GPS_REG_EVT, "set wmt registers"), */ + /* INIT_CMD(WMT_SET_SDIODRV_REG_CMD, WMT_SET_SDIODRV_REG_EVT, "set SDIO driving registers") */ +#if CFG_WMT_I2S_DBGUART_SUPPORT + INIT_CMD(WMT_SET_DBGUART_REG_CMD, WMT_SET_DBGUART_REG_EVT, "set debug uart registers"), +#endif +#if CFG_SET_OPT_REG_SWLA + INIT_CMD(WMT_SET_SWLA_REG_CMD, WMT_SET_SWLA_REG_EVT, "set swla registers"), +#endif +#if CFG_SET_OPT_REG_MCUCLK + INIT_CMD(WMT_SET_MCUCLK_REG_CMD, WMT_SET_MCUCLK_REG_EVT, "set mcuclk dbg registers"), +#endif +#if CFG_SET_OPT_REG_MCUIRQ + INIT_CMD(WMT_SET_MCUIRQ_REG_CMD, WMT_SET_MCUIRQ_REG_EVT, "set mcu irq dbg registers"), +#endif +}; +#endif + +static struct init_script coex_table[] = { + INIT_CMD(WMT_COEX_SETTING_CONFIG_CMD, WMT_COEX_SETTING_CONFIG_EVT, "coex_wmt"), + +#if CFG_SUBSYS_COEX_NEED +/* no need in MT6630 */ + INIT_CMD(WMT_BT_COEX_SETTING_CONFIG_CMD, WMT_BT_COEX_SETTING_CONFIG_EVT, "coex_bt"), + INIT_CMD(WMT_WIFI_COEX_SETTING_CONFIG_CMD, WMT_WIFI_COEX_SETTING_CONFIG_EVT, "coex_wifi"), + INIT_CMD(WMT_PTA_COEX_SETTING_CONFIG_CMD, WMT_PTA_COEX_SETTING_CONFIG_EVT, "coex_ext_pta"), + INIT_CMD(WMT_MISC_COEX_SETTING_CONFIG_CMD, WMT_MISC_COEX_SETTING_CONFIG_EVT, "coex_misc"), +#endif +}; + +static struct init_script osc_type_table[] = { + INIT_CMD(WMT_CORE_CO_CLOCK_CMD, WMT_CORE_CO_CLOCK_EVT, "osc_type"), +}; + +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) +static struct init_script merge_pcm_table[] = { + INIT_CMD(WMT_SET_DAI_MODE_REG_CMD, WMT_SET_DAI_MODE_REG_EVT, "DAI_PAD"), +}; +#endif + +#if CFG_WMT_FILTER_MODE_SETTING +#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING +static struct init_script set_wifi_lte_coex_table_0[] = { + INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte ext component"), + INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter"), + INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD, WMT_COEX_SPLIT_MODE_EVT, + "wifi lte freq id table"), + INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte unsafe channel"), + INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is lte project"), +}; +#else +static struct init_script set_wifi_lte_coex_table_0[] = { + INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte ext component"), + INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter"), + INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq id table"), + INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte unsafe channel"), + INIT_CMD(WMT_COEX_IS_LTE_L_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is L branch"), + INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is lte project"), +}; +#endif +#endif + +/* MT6630 Chip Version and Info Table */ +static const WMT_IC_INFO_S mt6630_info_table[] = { + { + .u4HwVer = 0x8A00, + .cChipName = WMT_IC_NAME_MT6630, + .cChipVersion = WMT_IC_VER_E1, + .cPatchNameExt = WMT_IC_PATCH_E1_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8A10, + .cChipName = WMT_IC_NAME_MT6630, + .cChipVersion = WMT_IC_VER_E2, + .cPatchNameExt = WMT_IC_PATCH_E2_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8A11, + .cChipName = WMT_IC_NAME_MT6630, + .cChipVersion = WMT_IC_VER_E3, + .cPatchNameExt = WMT_IC_PATCH_E2_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8B11, + .cChipName = WMT_IC_NAME_MT6630, + .cChipVersion = WMT_IC_VER_E4, + .cPatchNameExt = WMT_IC_PATCH_E2_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + } +}; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static INT32 mt6630_sw_init(P_WMT_HIF_CONF pWmtHifConf); + +static INT32 mt6630_sw_deinit(P_WMT_HIF_CONF pWmtHifConf); + +static INT32 mt6630_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag); + +static INT32 mt6630_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag); + +static INT32 mt6630_ver_check(VOID); + +static const WMT_IC_INFO_S *mt6630_find_wmt_ic_info(const UINT32 hw_ver); + +static INT32 wmt_stp_init_coex(VOID); + +#if CFG_WMT_MULTI_PATCH +static INT32 mt6630_patch_dwn(UINT32 index); +static INT32 mt6630_patch_info_prepare(VOID); +#else +static INT32 mt6630_patch_dwn(VOID); +#endif + +static INT32 mt6630_co_clock_ctrl(WMT_CO_CLOCK on); +static WMT_CO_CLOCK mt6630_co_clock_get(VOID); + +#if CFG_WMT_CRYSTAL_TIMING_SET +static INT32 mt6630_crystal_triming_set(VOID); +#endif + +static MTK_WCN_BOOL mt6630_quick_sleep_flag_get(VOID); + +static MTK_WCN_BOOL mt6630_aee_dump_flag_get(VOID); +#if 0 +/* set sdio driving */ +static UINT8 WMT_SET_SDIO_DRV_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x50, 0x00, 0x05, 0x80 /*addr:0x80050050 */ + , 0x44, 0x44, 0x04, 0x00 /*value:0x00044444 */ + , 0x77, 0x77, 0x07, 0x00 /*mask:0x00077777 */ +}; + +static UINT8 WMT_SET_SDIO_DRV_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; + +static INT32 mt6630_set_sdio_driving(void); +static struct init_script sdio_driving_table[] = { + INIT_CMD(WMT_SET_SDIO_DRV_REG_CMD, WMT_SET_SDIO_DRV_REG_EVT, "sdio_driving"), +}; + +#endif +static MTK_WCN_BOOL mt6630_trigger_stp_assert(VOID); +#if CFG_WMT_FILTER_MODE_SETTING +static INT32 wmt_stp_wifi_lte_coex(VOID); +#endif + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/* MT6630 Operation Function Table */ +WMT_IC_OPS wmt_ic_ops_mt6630 = { + .icId = 0x6630, + .sw_init = mt6630_sw_init, + .sw_deinit = mt6630_sw_deinit, + .ic_pin_ctrl = mt6630_pin_ctrl, + .ic_ver_check = mt6630_ver_check, + .co_clock_ctrl = mt6630_co_clock_ctrl, + .is_quick_sleep = mt6630_quick_sleep_flag_get, + .is_aee_dump_support = mt6630_aee_dump_flag_get, + .trigger_stp_assert = mt6630_trigger_stp_assert, + .deep_sleep_ctrl = NULL, +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static INT32 mt6630_sw_init(P_WMT_HIF_CONF pWmtHifConf) +{ + INT32 iRet = -1; + UINT32 u4Res = 0; + UINT8 evtBuf[256]; + ULONG ctrlPa1; + ULONG ctrlPa2; + UINT32 hw_ver; +#if CFG_WMT_MULTI_PATCH + UINT32 patch_num = 0; + UINT32 patch_index = 0; +#endif + WMT_CTRL_DATA ctrlData; + + WMT_DBG_FUNC(" start\n"); + + osal_assert(gp_mt6630_info != NULL); + + if ((gp_mt6630_info == NULL) + || (pWmtHifConf == NULL) + ) { + WMT_ERR_FUNC("null pointers: gp_mt6630_info(0x%p), pWmtHifConf(0x%p)\n", + gp_mt6630_info, pWmtHifConf); + return -1; + } + + hw_ver = gp_mt6630_info->u4HwVer; + + /* 4 <3.1> start init for sdio */ + + /* 4 <3.2> start init for uart */ + if (pWmtHifConf->hifType == WMT_HIF_UART) { + /* init variable fields for script execution */ + osal_memcpy(&WMT_SET_BAUD_CMD_X[5], &pWmtHifConf->au4HifConf[0], + osal_sizeof(UINT32)); + WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x00; /* 0xC0 MTK Flow Control *//* no flow control */ + osal_memcpy(&WMT_QUERY_BAUD_EVT_X[6], &pWmtHifConf->au4HifConf[0], + osal_sizeof(UINT32)); + WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x00; /* 0xC0 MTK Flow Control *//* no flow control */ + + /* 3. Query chip baud rate (TEST-ONLY) */ + /* 4. Query chip STP options (TEST-ONLY) */ + /* 5. Change chip baud rate: t_baud */ + /* WMT_DBG_FUNC("WMT-CORE: init_table_1_2 set chip baud:%d", pWmtHifConf->au4HifConf[0]); */ + iRet = wmt_core_init_script(init_table_1_2, ARRAY_SIZE(init_table_1_2)); + + if (iRet) { + WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet); + osal_assert(0); + return -2; + } + + /* 6. Set host baudrate and flow control */ + ctrlPa1 = pWmtHifConf->au4HifConf[0]; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HOST_BAUDRATE_SET, &ctrlPa1, &ctrlPa2); + + if (iRet) { + WMT_ERR_FUNC("change baudrate(%d) fail(%d)\n", pWmtHifConf->au4HifConf[0], + iRet); + return -3; + } + + WMT_DBG_FUNC("WMT-CORE: change baudrate(%d) ok\n", pWmtHifConf->au4HifConf[0]); + + /* 7. Wake up chip and check event */ +/* iRet = (*kal_stp_tx_raw)(&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res); */ + iRet = + wmt_core_tx((PUINT8)&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res, + MTK_WCN_BOOL_TRUE); + + if (iRet || (u4Res != 1)) { + WMT_ERR_FUNC("write raw iRet(%d) written(%d)\n", iRet, u4Res); + return -4; + } + + osal_memset(evtBuf, 0, osal_sizeof(evtBuf)); + iRet = wmt_core_rx(evtBuf, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT), &u4Res); +#ifdef CFG_DUMP_EVT + WMT_DBG_FUNC("WAKEUP_WAKE_EVT read len %d [%02x,%02x,%02x,%02x,%02x,%02x]\n", + (INT32) u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + evtBuf[5]); +#endif + + if (iRet || (u4Res != osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT))) { + WMT_ERR_FUNC("read WAKEUP_WAKE_EVT fail(%d)\n", iRet); + mtk_wcn_stp_dbg_dump_package(); + return -5; + } + /* WMT_DBG_FUNC("WMT-CORE: read WMT_SET_WAKEUP_WAKE_EVT ok"); */ + +#if CFG_CHECK_WMT_RESULT + + if (osal_memcmp + (evtBuf, WMT_SET_WAKEUP_WAKE_EVT, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT)) != 0) { + WMT_ERR_FUNC("WMT-CORE: write WMT_SET_WAKEUP_WAKE_CMD_RAW status fail\n"); + return -6; + } +#endif + + /* 8. Query baud rate (TEST-ONLY) */ + iRet = wmt_core_init_script(init_table_2, osal_array_size(init_table_2)); + + if (iRet) { + WMT_ERR_FUNC("init_table_2 fail(%d)\n", iRet); + return -7; + } + } + + /* 9. download patch */ +#if CFG_WMT_MULTI_PATCH + /* 9.1 Let launcher to search patch info */ + iRet = mt6630_patch_info_prepare(); + + if (iRet) { + WMT_ERR_FUNC("patch info perpare fail(%d)\n", iRet); + return -8; + } + + /* 9.2 Read patch number */ + ctrlPa1 = 0; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_GET_PATCH_NUM, &ctrlPa1, &ctrlPa2); + patch_num = ctrlPa1; + WMT_INFO_FUNC("patch total num = [%d]\n", patch_num); + + /* 9.3 Multi-patch Patch download */ + for (patch_index = 0; patch_index < patch_num; patch_index++) { + iRet = mt6630_patch_dwn(patch_index); + + if (iRet) { + WMT_ERR_FUNC("patch dwn fail (%d),patch_index(%d)\n", iRet, patch_index); + return -12; + } + + iRet = wmt_core_init_script(init_table_3, ARRAY_SIZE(init_table_3)); + + if (iRet) { + WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); + return -13; + } + } + +#else + /* 9.3 Patch download */ + iRet = mt6630_patch_dwn(); + + /* If patch download fail, we just ignore this error and let chip init process goes on */ + if (iRet) + WMT_ERR_FUNC("patch dwn fail (%d), just omit\n", iRet); +#endif /* End of #if CFG_WMT_MULTI_PATCH */ + + /* 10. WMT Reset command */ + iRet = wmt_core_init_script(init_table_3, ARRAY_SIZE(init_table_3)); + + if (iRet) { + WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); + return -9; + } + + iRet = wmt_stp_init_coex(); + + if (iRet) { + WMT_ERR_FUNC("init_coex fail(%d)\n", iRet); + return -10; + } + WMT_DBG_FUNC("init_coex ok\n"); + +#if CFG_WMT_CRYSTAL_TIMING_SET + mt6630_crystal_triming_set(); +#endif + +#if MT6630_BRINGUP + WMT_INFO_FUNC("Bring up period, skip sdio driving settings\n"); +#else + WMT_DBG_FUNC("Temp solution, skip sdio driving settings\n"); + /* 6630_set_sdio_driving(); */ +#endif + if (pWmtHifConf->hifType == WMT_HIF_UART) { + /* 11. Set chip STP options */ + iRet = wmt_core_init_script(init_table_4, ARRAY_SIZE(init_table_4)); + + if (iRet) { + WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet); + return -12; + } + + /* 12. Enable host STP-UART mode */ + ctrlPa1 = WMT_STP_CONF_MODE; + ctrlPa2 = MTKSTP_UART_FULL_MODE; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 1; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + + if (iRet) { + WMT_ERR_FUNC("enable host STP-UART-FULL mode fail(%d)\n", iRet); + return -13; + } + + WMT_INFO_FUNC("enable host STP-UART-FULL mode\n"); + /*13. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */ + osal_sleep_ms(10); + /* 14. Query chip STP options (TEST-ONLY) */ + /* 15. Query baud rate (stp, TEST-ONLY) */ + iRet = wmt_core_init_script(init_table_5, ARRAY_SIZE(init_table_5)); + + if (iRet) { + WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet); + return -14; + } + } + + if (mt6630_co_clock_get() == WMT_CO_CLOCK_EN) { + WMT_INFO_FUNC("co-clock enabled.\n"); + + iRet = wmt_core_init_script(osc_type_table, ARRAY_SIZE(osc_type_table)); + + if (iRet) { + WMT_ERR_FUNC("osc_type_table fail(%d), goes on\n", iRet); + return -15; + } + } else if (mt6630_co_clock_get() == WMT_CO_CLOCK_DCXO) { + WMT_SET_CRYSTAL_TRIMING_CMD[4] = 0x2; + WMT_SET_CRYSTAL_TRIMING_CMD[5] = 0x2; + WMT_SET_CRYSTAL_TRIMING_EVT[4] = 0x2; + WMT_SET_CRYSTAL_TRIMING_EVT[5] = 0x0; + iRet = wmt_core_init_script(set_crystal_timing_script, ARRAY_SIZE(set_crystal_timing_script)); + if (iRet == 0) + WMT_INFO_FUNC("set to Xtal mode suceed\n"); + else + WMT_INFO_FUNC("set to Xtal mode failed, iRet:%d.\n", iRet); + + + } else + WMT_DBG_FUNC("co-clock disabled.\n"); +#if MT6630_BRINGUP + WMT_INFO_FUNC("Bring up period, skip merge interface settings\n"); +#else + +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) + iRet = wmt_core_init_script(merge_pcm_table, ARRAY_SIZE(merge_pcm_table)); + + if (iRet) { + WMT_ERR_FUNC("merge_pcm_table fail(%d), goes on\n", iRet); + return -15; + } +#endif +#endif + /* 15. Set FM strap */ + WMT_STRAP_CONF_CMD_FM_COMM[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; + WMT_STRAP_CONF_EVT[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; + iRet = wmt_core_init_script(init_table_5_1, ARRAY_SIZE(init_table_5_1)); + + if (iRet) { + WMT_ERR_FUNC("init_table_5_1 fm mode(%d) fail(%d)\n", + pWmtHifConf->au4StrapConf[0], iRet); + return -16; + } + + WMT_INFO_FUNC("set fm mode (%d) ok\n", pWmtHifConf->au4StrapConf[0]); + +#if CFG_SET_OPT_REG /*set registers */ + iRet = wmt_core_init_script(set_registers, ARRAY_SIZE(set_registers)); + + if (iRet) { + WMT_ERR_FUNC("set_registers fail(%d)", iRet); + return -17; + } +#endif + +#if CFG_WMT_COREDUMP_ENABLE + /*Open Core Dump Function @QC begin */ + mtk_wcn_stp_coredump_flag_ctrl(1); +#endif + + if (mtk_wcn_stp_coredump_flag_get() != 0) { + iRet = wmt_core_init_script(init_table_6, ARRAY_SIZE(init_table_6)); + + if (iRet) { + WMT_ERR_FUNC("init_table_6 core dump setting fail(%d)\n", iRet); + return -18; + } + WMT_INFO_FUNC("enable mt662x firmware coredump\n"); + } else + WMT_INFO_FUNC("disable mt662x firmware coredump\n"); + + ctrlData.ctrlId = WMT_CTRL_SET_STP_DBG_INFO; + ctrlData.au4CtrlData[0] = wmt_ic_ops_mt6630.icId; + ctrlData.au4CtrlData[1] = (size_t) gp_mt6630_info->cChipVersion; + ctrlData.au4CtrlData[2] = (size_t) &gp_mt6630_patch_info; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("set dump info fail(%d)\n", iRet); + return -16; + } +#if CFG_WMT_FILTER_MODE_SETTING + wmt_stp_wifi_lte_coex(); +#endif + +#if CFG_WMT_PS_SUPPORT + osal_assert(gp_mt6630_info != NULL); + + if (gp_mt6630_info != NULL) { + if (gp_mt6630_info->bPsmSupport != MTK_WCN_BOOL_FALSE) + wmt_lib_ps_enable(); + else + wmt_lib_ps_disable(); + } +#endif + + return 0; +} + +static INT32 mt6630_sw_deinit(P_WMT_HIF_CONF pWmtHifConf) +{ + WMT_DBG_FUNC(" start\n"); + +#if CFG_WMT_PS_SUPPORT + osal_assert(gp_mt6630_info != NULL); + + if ((gp_mt6630_info != NULL) + && (gp_mt6630_info->bPsmSupport != MTK_WCN_BOOL_FALSE)) { + wmt_lib_ps_disable(); + } +#endif + + gp_mt6630_info = NULL; + + return 0; +} + +static INT32 mt6630_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 ret = -1; + +#if MT6630_BRINGUP + ret = 0; + WMT_INFO_FUNC("Bring up period, skip aif settings\n"); +#else + + if ((flag & WMT_LIB_AIF_FLAG_MASK) == WMT_LIB_AIF_FLAG_SHARE) { + WMT_INFO_FUNC("PCM & I2S PIN SHARE\n"); + + WMT_WARN_FUNC("TBD!!"); + ret = 0; + } else { + /*PCM & I2S separate */ + WMT_INFO_FUNC("PCM & I2S PIN SEPARATE\n"); + + switch (state) { + case WMT_IC_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + ret = 0; + break; + + case WMT_IC_AIF_1: + /* BT_PCM_ON & FM line in/out */ + ret = 0; + break; + + case WMT_IC_AIF_2: + /* BT_PCM_OFF & FM I2S */ +#if 0 + val = 0x01110000; + ret = wmt_core_reg_rw_raw(1, 0x80050078, &val, 0x0FFF0000); +#else + ret = 0; + WMT_INFO_FUNC("Bring up period, skip WMT_IC_AIF_2 settings\n"); +#endif + break; + + case WMT_IC_AIF_3: + ret = 0; + break; + + default: + WMT_ERR_FUNC("unsupported state (%d)\n", state); + ret = -1; + break; + } + } + + if (!ret) + WMT_INFO_FUNC("new state(%d) ok\n", state); + else + WMT_WARN_FUNC("new state(%d) fail(%d)\n", state, ret); +#endif + return ret; +} + +static INT32 mt6630_gps_sync_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) +{ +#if 0 + INT32 iRet = -1; + UINT32 uVal = 0; + + if (state == WMT_IC_PIN_MUX) + uVal = 0x1 << 4; + else + uVal = 0x0 << 4; + /*0x80025070[7:4]: 1-A-GPS_SYNC mode, 0-Jtag mode */ +#if MT6630_BRINGUP + iRet = 0; + WMT_INFO_FUNC("Bring up period, skip gps sync settings\n"); + +#else + iRet = wmt_core_reg_rw_raw(1, 0x80025070, &uVal, 0xf << 4); +#endif + if (iRet != 0) + WMT_ERR_FUNC("gps_sync pin ctrl failed, iRet(%d)\n", iRet); +#endif + /* anyway, we return 0 */ + return 0; +} + + +static INT32 mt6630_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 ret; + + WMT_DBG_FUNC("ic pin id:%d, state:%d, flag:0x%x\n", id, state, flag); + + ret = -1; + + switch (id) { + case WMT_IC_PIN_AUDIO: + ret = mt6630_aif_ctrl(state, flag); + break; + + case WMT_IC_PIN_EEDI: + WMT_WARN_FUNC("TBD!!"); + /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ + ret = 0; + break; + + case WMT_IC_PIN_EEDO: + WMT_WARN_FUNC("TBD!!"); + /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ + ret = 0; + break; + + case WMT_IC_PIN_GSYNC: + ret = mt6630_gps_sync_ctrl(state, flag); + break; + + default: + break; + } + + WMT_INFO_FUNC("ret = (%d)\n", ret); + + return ret; +} + +INT32 mt6630_co_clock_ctrl(WMT_CO_CLOCK on) +{ + INT32 iRet = 0; + + if ((on >= WMT_CO_CLOCK_DIS) && (on < WMT_CO_CLOCK_MAX)) { + gCoClockEn = on; + } else { + WMT_DBG_FUNC("MT6630: error parameter:%d\n", on); + iRet = -1; + } + + WMT_DBG_FUNC("MT6630: Co-clock type: %d\n", gCoClockEn); + + return iRet; +} + +static MTK_WCN_BOOL mt6630_quick_sleep_flag_get(VOID) +{ + return MTK_WCN_BOOL_TRUE; +} + + +static MTK_WCN_BOOL mt6630_aee_dump_flag_get(VOID) +{ + if (mtk_wcn_stp_coredump_flag_get() == 1) + return MTK_WCN_BOOL_TRUE; + else + return MTK_WCN_BOOL_FALSE; +} + +static MTK_WCN_BOOL mt6630_trigger_stp_assert(VOID) +{ + INT32 iRet = -1; + UINT32 u4Res = 0; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + UINT8 STP_DO_ASSERT_CMD[] = { 0x80, 0x50, 0x0a, 0x00, 'd', 'o', 'c', 'o', 'r', 'e', 'd', 'u', 'm', 'p', 0x00, + 0x00 + }; + + iRet = + wmt_core_tx((PUINT8)&STP_DO_ASSERT_CMD[0], sizeof(STP_DO_ASSERT_CMD), &u4Res, + MTK_WCN_BOOL_TRUE); + if (iRet || (u4Res != sizeof(STP_DO_ASSERT_CMD))) { + WMT_ERR_FUNC("wmt_core:send STP ASSERT COMMAND fail(%d),size(%d)\n", iRet, u4Res); + bRet = MTK_WCN_BOOL_FALSE; + } else + bRet = MTK_WCN_BOOL_TRUE; + return bRet; +} + +WMT_CO_CLOCK mt6630_co_clock_get(VOID) +{ + return gCoClockEn; +} + + + +static INT32 mt6630_ver_check(VOID) +{ + UINT32 hw_ver = 0; + UINT32 fw_ver = 0; + INT32 iret; + const WMT_IC_INFO_S *p_info; + ULONG ctrlPa1; + ULONG ctrlPa2; + + /* 1. identify chip versions: HVR(HW_VER) and FVR(FW_VER) */ + WMT_LOUD_FUNC("MT6630: before read hw_ver (hw version)\n"); + iret = wmt_core_reg_rw_raw(0, GEN_HVR, &hw_ver, GEN_VER_MASK); + + if (iret) { + WMT_ERR_FUNC("MT6630: read hw_ver fail:%d\n", iret); + return -2; + } + + WMT_LOUD_FUNC("MT6630: before fw_ver (rom version)\n"); + wmt_core_reg_rw_raw(0, GEN_FVR, &fw_ver, GEN_VER_MASK); + + if (iret) { + WMT_ERR_FUNC("MT6630: read fw_ver fail:%d\n", iret); + return -2; + } + + WMT_INFO_FUNC("MT6630: read (hw version)(0x%x), (fw version version)(0x%x)\n", hw_ver, fw_ver); + + p_info = mt6630_find_wmt_ic_info(hw_ver); + + if (p_info == NULL) { + WMT_ERR_FUNC("MT6630: hw_ver(0x%x) find wmt ic info fail\n", hw_ver); + return -3; + } + + WMT_INFO_FUNC("MT6630: wmt ic info: %s.%s (0x%x, patch_ext:%s)\n", + p_info->cChipName, p_info->cChipVersion, + p_info->u4HwVer, p_info->cPatchNameExt); + + /* hw id & version */ + ctrlPa1 = (0x00006630UL << 16) | (hw_ver & 0x0000FFFF); + /* translated fw rom version */ + ctrlPa2 = (fw_ver & 0x0000FFFF); + + iret = wmt_core_ctrl(WMT_CTRL_HWIDVER_SET, &ctrlPa1, &ctrlPa2); + + if (iret) + WMT_WARN_FUNC("MT6630: WMT_CTRL_HWIDVER_SET fail(%d)\n", iret); + + gp_mt6630_info = p_info; + return 0; +} + +static const WMT_IC_INFO_S *mt6630_find_wmt_ic_info(const UINT32 hw_ver) +{ + /* match chipversion with u4HwVer item in mt6630_info_table */ + const UINT32 size = ARRAY_SIZE(mt6630_info_table); + INT32 index; + + /* Leave full match here is a workaround for GPS to distinguish E3/E4 ICs. */ + index = size - 1; + + /* full match */ + while ((index >= 0) + && (hw_ver != mt6630_info_table[index].u4HwVer) /* full match */ + ) { + --index; + } + + if (index >= 0) { + WMT_INFO_FUNC("found ic info(0x%x) by full match! index:%d\n", hw_ver, index); + return &mt6630_info_table[index]; + } + + WMT_WARN_FUNC("find no ic info for (0x%x) by full match!try major num match!\n", hw_ver); + + /* George: The ONLY CORRECT method to find supported hw table. Match MAJOR + * NUM only can help us support future minor hw ECO, or fab switch, etc. + * FULL matching eliminate such flexibility and software package have to be + * updated EACH TIME even when minor hw ECO or fab switch!!! + */ + /* George: reverse the search order to favor newer version products */ + index = size - 1; + + /* major num match */ + while ((index >= 0) + && (MAJORNUM(hw_ver) != MAJORNUM(mt6630_info_table[index].u4HwVer)) + ) { + --index; + } + + if (index >= 0) { + WMT_INFO_FUNC("MT6630: found ic info for hw_ver(0x%x) by major num! index:%d\n", + hw_ver, index); + return &mt6630_info_table[index]; + } + + WMT_ERR_FUNC + ("MT6630: find no ic info for hw_ver(0x%x) by full match nor major num match!\n", + hw_ver); + return NULL; +} + + +static INT32 wmt_stp_init_coex(VOID) +{ + INT32 iRet; + ULONG addr = 0; + WMT_GEN_CONF *pWmtGenConf; + +#define COEX_WMT 0 + +#if CFG_SUBSYS_COEX_NEED + /* no need for MT6630 */ +#define COEX_BT 1 +#define COEX_WIFI 2 +#define COEX_PTA 3 +#define COEX_MISC 4 +#endif + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + + WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + + /*Dump the coex-related info */ + WMT_DBG_FUNC("coex_wmt:0x%x\n", pWmtGenConf->coex_wmt_ant_mode); +#if CFG_SUBSYS_COEX_NEED + WMT_DBG_FUNC("coex_bt:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_bt_rssi_upper_limit, + pWmtGenConf->coex_bt_rssi_mid_limit, + pWmtGenConf->coex_bt_rssi_lower_limit, + pWmtGenConf->coex_bt_pwr_high, + pWmtGenConf->coex_bt_pwr_mid, pWmtGenConf->coex_bt_pwr_low); + WMT_DBG_FUNC("coex_wifi:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_wifi_rssi_upper_limit, + pWmtGenConf->coex_wifi_rssi_mid_limit, + pWmtGenConf->coex_wifi_rssi_lower_limit, + pWmtGenConf->coex_wifi_pwr_high, + pWmtGenConf->coex_wifi_pwr_mid, pWmtGenConf->coex_wifi_pwr_low); + WMT_DBG_FUNC("coex_ext_pta:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_ext_pta_hi_tx_tag, + pWmtGenConf->coex_ext_pta_hi_rx_tag, + pWmtGenConf->coex_ext_pta_lo_tx_tag, + pWmtGenConf->coex_ext_pta_lo_rx_tag, + pWmtGenConf->coex_ext_pta_sample_t1, + pWmtGenConf->coex_ext_pta_sample_t2, + pWmtGenConf->coex_ext_pta_wifi_bt_con_trx); + WMT_DBG_FUNC("coex_misc:0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_misc_ext_pta_on, pWmtGenConf->coex_misc_ext_feature_set); +#endif + + /*command adjustion due to WMT.cfg */ + coex_table[COEX_WMT].cmd[5] = pWmtGenConf->coex_wmt_ant_mode; + + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_WMT].cmd[0], + coex_table[COEX_WMT].str, coex_table[COEX_WMT].cmdSz); + } +#if CFG_SUBSYS_COEX_NEED + coex_table[COEX_BT].cmd[9] = pWmtGenConf->coex_bt_rssi_upper_limit; + coex_table[COEX_BT].cmd[10] = pWmtGenConf->coex_bt_rssi_mid_limit; + coex_table[COEX_BT].cmd[11] = pWmtGenConf->coex_bt_rssi_lower_limit; + coex_table[COEX_BT].cmd[12] = pWmtGenConf->coex_bt_pwr_high; + coex_table[COEX_BT].cmd[13] = pWmtGenConf->coex_bt_pwr_mid; + coex_table[COEX_BT].cmd[14] = pWmtGenConf->coex_bt_pwr_low; + + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_BT].cmd[0], + coex_table[COEX_BT].str, coex_table[COEX_BT].cmdSz); + } + + coex_table[COEX_WIFI].cmd[10] = pWmtGenConf->coex_wifi_rssi_upper_limit; + coex_table[COEX_WIFI].cmd[11] = pWmtGenConf->coex_wifi_rssi_mid_limit; + coex_table[COEX_WIFI].cmd[12] = pWmtGenConf->coex_wifi_rssi_lower_limit; + coex_table[COEX_WIFI].cmd[13] = pWmtGenConf->coex_wifi_pwr_high; + coex_table[COEX_WIFI].cmd[14] = pWmtGenConf->coex_wifi_pwr_mid; + coex_table[COEX_WIFI].cmd[15] = pWmtGenConf->coex_wifi_pwr_low; + + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_WIFI].cmd[0], + coex_table[COEX_WIFI].str, coex_table[COEX_WIFI].cmdSz); + } + + coex_table[COEX_PTA].cmd[5] = pWmtGenConf->coex_ext_pta_hi_tx_tag; + coex_table[COEX_PTA].cmd[6] = pWmtGenConf->coex_ext_pta_hi_rx_tag; + coex_table[COEX_PTA].cmd[7] = pWmtGenConf->coex_ext_pta_lo_tx_tag; + coex_table[COEX_PTA].cmd[8] = pWmtGenConf->coex_ext_pta_lo_rx_tag; + coex_table[COEX_PTA].cmd[9] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0xff00) >> 8); + coex_table[COEX_PTA].cmd[10] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0x00ff) >> 0); + coex_table[COEX_PTA].cmd[11] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0xff00) >> 8); + coex_table[COEX_PTA].cmd[12] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0x00ff) >> 0); + coex_table[COEX_PTA].cmd[13] = pWmtGenConf->coex_ext_pta_wifi_bt_con_trx; + + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_PTA].cmd[0], + coex_table[COEX_PTA].str, coex_table[COEX_PTA].cmdSz); + } + + osal_memcpy(&coex_table[COEX_MISC].cmd[5], &pWmtGenConf->coex_misc_ext_pta_on, + sizeof(pWmtGenConf->coex_misc_ext_pta_on)); + osal_memcpy(&coex_table[COEX_MISC].cmd[9], &pWmtGenConf->coex_misc_ext_feature_set, + sizeof(pWmtGenConf->coex_misc_ext_feature_set)); + + wmt_core_dump_data(&coex_table[COEX_MISC].cmd[0], coex_table[COEX_MISC].str, + coex_table[COEX_MISC].cmdSz); +#endif + + iRet = wmt_core_init_script(coex_table, ARRAY_SIZE(coex_table)); + + return iRet; +} + +#if 0 +static INT32 mt6630_set_sdio_driving(void) +{ + INT32 ret = 0; + + UINT32 addr = 0; + WMT_GEN_CONF *pWmtGenConf; + UINT32 drv_val = 0; + + /*Get wmt config */ + ret = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + + if (ret) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", ret); + return -1; + } + + WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%x)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + drv_val = pWmtGenConf->sdio_driving_cfg; + + /*Dump the sdio driving related info */ + WMT_INFO_FUNC("sdio driving:0x%x\n", drv_val); + + sdio_driving_table[0].cmd[12] = (UINT8) ((drv_val & 0x00000077UL) >> 0); /* DAT0 and DAT1 */ + sdio_driving_table[0].cmd[13] = (UINT8) ((drv_val & 0x00007700UL) >> 8); /* DAT2 and DAT3 */ + sdio_driving_table[0].cmd[14] = (UINT8) ((drv_val & 0x00070000UL) >> 16); /* CMD */ + + ret = wmt_core_init_script(sdio_driving_table, ARRAY_SIZE(sdio_driving_table)); + + return ret; +} +#endif + +#if CFG_WMT_CRYSTAL_TIMING_SET +static INT32 mt6630_crystal_triming_set(VOID) +{ + INT32 iRet = 0; + PUINT8 pbuf = NULL; + UINT32 bufLen = 0; + WMT_CTRL_DATA ctrlData; + UINT32 uCryTimOffset = 0x6D; + MTK_WCN_BOOL bIsNvramExist = MTK_WCN_BOOL_FALSE; + INT8 cCrystalTimingOffset = 0x0; + UINT8 cCrystalTiming = 0x0; + INT32 iCrystalTiming = 0x0; + MTK_WCN_BOOL bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + UINT32 u4Res; + + bIsNvramExist = MTK_WCN_BOOL_FALSE; + ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_GET; + ctrlData.au4CtrlData[0] = (size_t) "/data/nvram/APCFG/APRDEB/WIFI"; + ctrlData.au4CtrlData[1] = (size_t) &pbuf; + ctrlData.au4CtrlData[2] = (size_t) &bufLen; + + iRet = wmt_ctrl(&ctrlData); + + if (iRet != 0) { + WMT_ERR_FUNC("MT6630: WMT_CTRL_CRYSTAL_TRIMING_GET fail:%d\n", iRet); + bIsNvramExist = MTK_WCN_BOOL_FALSE; + bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + cCrystalTimingOffset = 0x0; + cCrystalTiming = 0x0; + iRet = -1; + } else { + WMT_DBG_FUNC("MT6630: nvram pBuf(%p), bufLen(%d)\n", pbuf, bufLen); + + if (bufLen < (uCryTimOffset + 1)) { + WMT_ERR_FUNC + ("MT6630: nvram len(%d) too short, crystalTimging value offset(%d)\n", + bufLen, uCryTimOffset); + bIsNvramExist = MTK_WCN_BOOL_FALSE; + bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + cCrystalTimingOffset = 0x0; + cCrystalTiming = 0x0; + } else { + bIsNvramExist = MTK_WCN_BOOL_TRUE; + cCrystalTimingOffset = *(pbuf + uCryTimOffset); + + if (cCrystalTimingOffset & 0x80) { + bIsCrysTrimEnabled = MTK_WCN_BOOL_TRUE; + cCrystalTimingOffset = (UINT8) cCrystalTimingOffset & 0x7f; + } + + WMT_DBG_FUNC("cCrystalTimingOffset (%d), bIsCrysTrimEnabled(%d)\n", + cCrystalTimingOffset, bIsCrysTrimEnabled); + } + + ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_PUT; + ctrlData.au4CtrlData[0] = (size_t) "/data/nvram/APCFG/APRDEB/WIFI"; + iRet = wmt_ctrl(&ctrlData); + + if (iRet != 0) { + WMT_ERR_FUNC("MT6630: WMT_CTRL_CRYSTAL_TRIMING_PUT fail:%d\n", iRet); + iRet = -2; + } else { + WMT_DBG_FUNC("MT6630: WMT_CTRL_CRYSTAL_TRIMING_PUT succeed\n"); + } + } + + if ((bIsNvramExist == MTK_WCN_BOOL_TRUE) && (bIsCrysTrimEnabled == MTK_WCN_BOOL_TRUE)) { + /*get CrystalTiming value before set it */ + iRet = + wmt_core_tx(get_crystal_timing_script[0].cmd, + get_crystal_timing_script[0].cmdSz, &u4Res, MTK_WCN_BOOL_FALSE); + + if (iRet || (u4Res != get_crystal_timing_script[0].cmdSz)) { + WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", + get_crystal_timing_script[0].str, iRet, u4Res, + get_crystal_timing_script[0].cmdSz); + iRet = -3; + goto done; + } + + /* EVENT BUF */ + osal_memset(get_crystal_timing_script[0].evt, 0, + get_crystal_timing_script[0].evtSz); + iRet = + wmt_core_rx(get_crystal_timing_script[0].evt, + get_crystal_timing_script[0].evtSz, &u4Res); + + if (iRet || (u4Res != get_crystal_timing_script[0].evtSz)) { + WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", + get_crystal_timing_script[0].str, iRet, u4Res, + get_crystal_timing_script[0].evtSz); + mtk_wcn_stp_dbg_dump_package(); + iRet = -4; + goto done; + } + + iCrystalTiming = WMT_GET_CRYSTAL_TRIMING_EVT[5] & 0x7f; + + if (cCrystalTimingOffset & 0x40) { + /*nagative offset value */ + iCrystalTiming = iCrystalTiming + cCrystalTimingOffset - 128; + } else { + iCrystalTiming += cCrystalTimingOffset; + } + + WMT_DBG_FUNC("iCrystalTiming (0x%x)\n", iCrystalTiming); + if (iCrystalTiming > 0x7f) + cCrystalTiming = 0x7f; + else if (iCrystalTiming < 0) + cCrystalTiming = 0; + else + cCrystalTiming = iCrystalTiming; + WMT_DBG_FUNC("cCrystalTiming (0x%x)\n", cCrystalTiming); + /* set_crystal_timing_script */ + /*set crystal trim value command*/ + WMT_SET_CRYSTAL_TRIMING_CMD[4] = 0x1; + WMT_SET_CRYSTAL_TRIMING_EVT[4] = 0x1; + + WMT_SET_CRYSTAL_TRIMING_CMD[5] = cCrystalTiming; + WMT_GET_CRYSTAL_TRIMING_EVT[5] = cCrystalTiming; + + iRet = + wmt_core_init_script(set_crystal_timing_script, + ARRAY_SIZE(set_crystal_timing_script)); + + if (iRet) { + WMT_ERR_FUNC("set_crystal_timing_script fail(%d)\n", iRet); + iRet = -5; + } else { + WMT_DBG_FUNC("set crystal timing value (0x%x) succeed\n", + WMT_SET_CRYSTAL_TRIMING_CMD[5]); + iRet = + wmt_core_init_script(get_crystal_timing_script, + ARRAY_SIZE(get_crystal_timing_script)); + + if (iRet) { + WMT_ERR_FUNC("get_crystal_timing_script fail(%d)\n", iRet); + iRet = -6; + } else { + WMT_INFO_FUNC("succeed, updated crystal timing value (0x%x)\n", + WMT_GET_CRYSTAL_TRIMING_EVT[5]); + iRet = 0x0; + } + } + } + +done: + return iRet; +} +#endif + +#if CFG_WMT_MULTI_PATCH +static INT32 mt6630_patch_info_prepare(VOID) +{ + INT32 iRet = -1; + WMT_CTRL_DATA ctrlData; + + ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; + iRet = wmt_ctrl(&ctrlData); + + return iRet; +} + + +static INT32 mt6630_patch_dwn(UINT32 index) +{ + INT32 iRet = -1; + P_WMT_PATCH patchHdr = NULL; + PUINT8 pBuf = NULL; + PUINT8 pPatchBuf = NULL; + UINT32 patchSize; + UINT32 fragSeq; + UINT32 fragNum; + UINT16 fragSize = 0; + UINT16 cmdLen; + UINT32 offset; + UINT32 u4Res; + UINT8 evtBuf[8]; + UINT8 addressevtBuf[12]; + UINT8 addressByte[4]; + PINT8 cDataTime = NULL; + /*PINT8 cPlat = NULL; */ + UINT16 u2HwVer = 0; + UINT16 u2SwVer = 0; + UINT32 u4PatchVer = 0; + UINT32 patchSizePerFrag = 0; + WMT_CTRL_DATA ctrlData; + + /*1.check hardware information */ + if (gp_mt6630_info == NULL) { + WMT_ERR_FUNC("null gp_mt6630_info!\n"); + return -1; + } + + osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName)); + + ctrlData.ctrlId = WMT_CTRL_GET_PATCH_INFO; + ctrlData.au4CtrlData[0] = index + 1; + ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName; + ctrlData.au4CtrlData[2] = (size_t) &addressByte; + iRet = wmt_ctrl(&ctrlData); + WMT_INFO_FUNC("the %d time valid patch found: (%s)\n", index + 1, gFullPatchName); + + /* <2.2> read patch content */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH; + ctrlData.au4CtrlData[0] = (size_t) NULL; + ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName; + ctrlData.au4CtrlData[2] = (size_t) &pBuf; + ctrlData.au4CtrlData[3] = (size_t) &patchSize; + iRet = wmt_ctrl(&ctrlData); + + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); + iRet -= 1; + goto done; + } + + /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ + /* patch file with header: + * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| + */ + pPatchBuf = osal_malloc(patchSize); + if (pPatchBuf == NULL) { + WMT_ERR_FUNC("vmalloc pPatchBuf for patch download fail\n"); + return -2; + } + osal_memcpy(pPatchBuf, pBuf, patchSize); + /* check patch file information */ + + patchHdr = (P_WMT_PATCH) pPatchBuf; + + cDataTime = patchHdr->ucDateTime; + u2HwVer = patchHdr->u2HwVer; + u2SwVer = patchHdr->u2SwVer; + u4PatchVer = patchHdr->u4PatchVer; + + osal_memcpy(&gp_mt6630_patch_info, patchHdr, osal_sizeof(WMT_PATCH)); + + /*cPlat = &patchHdr->ucPLat[0]; */ + + cDataTime[15] = '\0'; + + if (index == 0) { + WMT_INFO_FUNC("Combo Patch:Build Time(%s)Hw(0x%x) Sw(0x%x) Ph(0x%04x)Platform(%c%c%c%c)\n", + cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8), + ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8), + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16), + patchHdr->ucPLat[0], patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + } + + /* remove patch header: + * |<-patch body: X Bytes (X=patchSize)--->| + */ + if (patchSize < sizeof(WMT_PATCH)) { + WMT_ERR_FUNC("error patch size\n"); + iRet = -1; + goto done; + } + patchSize -= sizeof(WMT_PATCH); + pPatchBuf += sizeof(WMT_PATCH); + patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; + /* reserve 1st patch cmd space before patch body + * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| + */ + pPatchBuf -= sizeof(WMT_PATCH_CMD); + + fragNum = patchSize / patchSizePerFrag; + fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; + + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + + /*send wmt part patch address command */ + iRet = + wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD[0], sizeof(WMT_PATCH_ADDRESS_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD))) { + WMT_ERR_FUNC("wmt_core:wmt patch address CMD fail(%d),size(%d)\n", iRet, u4Res); + iRet -= 1; + goto done; + } + + osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); + iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT), &u4Res); + + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT))) { + WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res); + mtk_wcn_stp_dbg_dump_package(); + iRet -= 1; + goto done; + } +#if CFG_CHECK_WMT_RESULT + + if (osal_memcmp(addressevtBuf, WMT_PATCH_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) != + 0) { + WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail\n"); + iRet -= 1; + goto done; + } +#endif + + /*send part patch address command */ + osal_memcpy(&WMT_PATCH_P_ADDRESS_CMD[12], addressByte, osal_sizeof(addressByte)); + WMT_INFO_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x", + WMT_PATCH_P_ADDRESS_CMD[12], + WMT_PATCH_P_ADDRESS_CMD[13], + WMT_PATCH_P_ADDRESS_CMD[14], WMT_PATCH_P_ADDRESS_CMD[15]); + iRet = + wmt_core_tx((PUINT8) &WMT_PATCH_P_ADDRESS_CMD[0], sizeof(WMT_PATCH_P_ADDRESS_CMD), + &u4Res, MTK_WCN_BOOL_FALSE); + + if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_CMD))) { + WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d),index(%d)\n", + iRet, u4Res, index); + iRet -= 1; + goto done; + } + + osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); + iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_P_ADDRESS_EVT), &u4Res); + + if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_EVT))) { + WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d),index(%d)\n", iRet, + u4Res, index); + mtk_wcn_stp_dbg_dump_package(); + iRet -= 1; + goto done; + } +#if CFG_CHECK_WMT_RESULT + + if (osal_memcmp(addressevtBuf, WMT_PATCH_P_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) + != 0) { + WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail,index(%d)\n", + index); + iRet -= 1; + goto done; + } +#endif + + /* send all fragments */ + offset = sizeof(WMT_PATCH_CMD); + fragSeq = 0; + + while (fragSeq < fragNum) { + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + if (fragSeq == (fragNum - 1)) { + /* last fragment */ + fragSize = patchSize - fragSeq * patchSizePerFrag; + WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; + } else { + fragSize = patchSizePerFrag; + WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; + } + + /* update length field in CMD:flag+frag */ + cmdLen = 1 + fragSize; + osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); + /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ + osal_memcpy(pPatchBuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, + sizeof(WMT_PATCH_CMD)); + + iRet = + wmt_core_tx(pPatchBuf + offset - sizeof(WMT_PATCH_CMD), + fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + + if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) fail(%d)\n", fragSeq, + fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); + iRet -= 1; + break; + } + + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) ok\n", + fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); + + osal_memset(evtBuf, 0, sizeof(evtBuf)); + /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ + iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); + + if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) fail(%d)\n", + sizeof(WMT_PATCH_EVT), u4Res, iRet); + mtk_wcn_stp_dbg_dump_package(); + iRet -= 1; + break; + } +#if CFG_CHECK_WMT_RESULT + + if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0], WMT_PATCH_EVT[1], + WMT_PATCH_EVT[2], WMT_PATCH_EVT[3], WMT_PATCH_EVT[4]); + iRet -= 1; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) ok\n", + sizeof(WMT_PATCH_EVT), u4Res); + offset += patchSizePerFrag; + ++fragSeq; + } + + WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", + iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); + + if (fragSeq != fragNum) + iRet -= 1; + +done: + if (patchHdr != NULL) { + osal_free(patchHdr); + pPatchBuf = NULL; + patchHdr = NULL; + } + /* WMT_CTRL_FREE_PATCH always return 0 */ + /* wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); */ + ctrlData.ctrlId = WMT_CTRL_FREE_PATCH; + ctrlData.au4CtrlData[0] = index + 1; + wmt_ctrl(&ctrlData); + + return iRet; +} + +#else +static INT32 mt6630_patch_dwn(VOID) +{ + INT32 iRet = -1; + P_WMT_PATCH patchHdr; + PUINT8 pbuf; + UINT32 patchSize; + UINT32 fragSeq; + UINT32 fragNum; + UINT16 fragSize = 0; + UINT16 cmdLen; + UINT32 offset; + UINT32 u4Res; + UINT8 evtBuf[8]; + PINT8 cDataTime = NULL; + /*PINT8 cPlat = NULL; */ + UINT16 u2HwVer = 0; + UINT16 u2SwVer = 0; + UINT32 u4PatchVer = 0; + UINT32 patchSizePerFrag = 0; + WMT_CTRL_DATA ctrlData; + + /*1.check hardware information */ + if (gp_mt6630_info == NULL) { + WMT_ERR_FUNC("null gp_mt6630_info!\n"); + return -1; + } + /* <2> search patch and read patch content */ + /* <2.1> search patch */ + ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; + iRet = wmt_ctrl(&ctrlData); + + if (iRet == 0) { + /* patch with correct Hw Ver Major Num found */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH_NAME; + ctrlData.au4CtrlData[0] = (size_t) &gFullPatchName; + iRet = wmt_ctrl(&ctrlData); + + WMT_INFO_FUNC("valid patch found: (%s)\n", gFullPatchName); + /* <2.2> read patch content */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH; + ctrlData.au4CtrlData[0] = (size_t) NULL; + ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName; + + } else { + iRet -= 1; + return iRet; + } + + ctrlData.au4CtrlData[2] = (size_t) &pbuf; + ctrlData.au4CtrlData[3] = (size_t) &patchSize; + iRet = wmt_ctrl(&ctrlData); + + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); + iRet -= 1; + goto done; + } + + /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ + pbuf += BCNT_PATCH_BUF_HEADROOM; + /* patch file with header: + * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| + */ + patchHdr = (P_WMT_PATCH) pbuf; + /* check patch file information */ + + cDataTime = patchHdr->ucDateTime; + u2HwVer = patchHdr->u2HwVer; + u2SwVer = patchHdr->u2SwVer; + u4PatchVer = patchHdr->u4PatchVer; + + osal_memcpy(&gp_mt6630_patch_info, patchHdr, osal_sizeof(WMT_PATCH)); + /*cPlat = &patchHdr->ucPLat[0]; */ + + cDataTime[15] = '\0'; + WMT_INFO_FUNC("===========================================\n"); + WMT_INFO_FUNC("[Combo Patch] Built Time = %s\n", cDataTime); + WMT_INFO_FUNC("[Combo Patch] Hw Ver = 0x%x\n", + ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8)); + WMT_INFO_FUNC("[Combo Patch] Sw Ver = 0x%x\n", + ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8)); + WMT_INFO_FUNC("[Combo Patch] Ph Ver = 0x%04x\n", + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16)); + WMT_INFO_FUNC("[Combo Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0], + patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + WMT_INFO_FUNC("===========================================\n"); + + /* remove patch header: + * |<-patch body: X Bytes (X=patchSize)--->| + */ + if (patchSize < sizeof(WMT_PATCH)) { + WMT_ERR_FUNC("error patch size\n"); + return -1; + } + patchSize -= sizeof(WMT_PATCH); + pbuf += sizeof(WMT_PATCH); + patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; + /* reserve 1st patch cmd space before patch body + * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| + */ + pbuf -= sizeof(WMT_PATCH_CMD); + + fragNum = patchSize / patchSizePerFrag; + fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; + + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + + /* send all fragments */ + offset = sizeof(WMT_PATCH_CMD); + fragSeq = 0; + + while (fragSeq < fragNum) { + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + if (fragSeq == (fragNum - 1)) { + /* last fragment */ + fragSize = patchSize - fragSeq * patchSizePerFrag; + WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; + } else { + fragSize = patchSizePerFrag; + WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; + } + + /* update length field in CMD:flag+frag */ + cmdLen = 1 + fragSize; + osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); + /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ + osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, + sizeof(WMT_PATCH_CMD)); + + /* iRet = (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), + * fragSize + sizeof(WMT_PATCH_CMD), &u4Res); + */ + iRet = + wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD), + fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + + if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, + fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); + iRet -= 1; + break; + } + + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", + fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); + + osal_memset(evtBuf, 0, sizeof(evtBuf)); + /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ + iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); + + if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n", + sizeof(WMT_PATCH_EVT), u4Res, iRet); + mtk_wcn_stp_dbg_dump_package(); + iRet -= 1; + break; + } +#if CFG_CHECK_WMT_RESULT + + if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0], WMT_PATCH_EVT[1], + WMT_PATCH_EVT[2], WMT_PATCH_EVT[3], WMT_PATCH_EVT[4]); + iRet -= 1; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n", + sizeof(WMT_PATCH_EVT), u4Res); + offset += patchSizePerFrag; + ++fragSeq; + } + + WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", + iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); + + if (fragSeq != fragNum) + iRet -= 1; + +done: + /* WMT_CTRL_FREE_PATCH always return 0 */ + wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); + + return iRet; +} + +#endif + +#if CFG_WMT_FILTER_MODE_SETTING +static INT32 wmt_stp_wifi_lte_coex(VOID) +{ + INT32 iRet; + ULONG addr = 0; + WMT_GEN_CONF *pWmtGenConf; + + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + if (pWmtGenConf->coex_wmt_filter_mode == 0) { + /*add WMT_COXE_CONFIG_EXT_COMPONENT_OPCODE command for 2G4 xLNA demand*/ + if (pWmtGenConf->coex_wmt_ext_component) { + WMT_INFO_FUNC("coex_wmt_ext_component:0x%x\n", pWmtGenConf->coex_wmt_ext_component); + set_wifi_lte_coex_table_0[0].cmd[5] = pWmtGenConf->coex_wmt_ext_component; + } + iRet = + wmt_core_init_script(set_wifi_lte_coex_table_0, + ARRAY_SIZE(set_wifi_lte_coex_table_0)); + if (iRet) + WMT_ERR_FUNC("wmt_core:set_wifi_lte_coex_table_0 fail(%d)\n", iRet); + else + WMT_INFO_FUNC("wmt_core:set_wifi_lte_coex_table_0 ok\n"); + } + + return iRet; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6632.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6632.c new file mode 100644 index 00000000000000..c7e8f7739d20f2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_6632.c @@ -0,0 +1,1989 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-IC]" +#define CFG_IC_MT6632 1 + +#define MT6632_BRINGUP 0 +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "wmt_ic.h" +#include "wmt_core.h" +#include "wmt_lib.h" +#include "stp_core.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define DEFAULT_PATCH_FRAG_SIZE (1000) +#define WMT_PATCH_FRAG_1ST (0x1) +#define WMT_PATCH_FRAG_MID (0x2) +#define WMT_PATCH_FRAG_LAST (0x3) + +#define CFG_CHECK_WMT_RESULT (1) +/* BT Port 2 Feature. this command does not need after coex command is downconfirmed by LC, */ +#define CFG_WMT_BT_PORT2 (0) + +#define CFG_SET_OPT_REG (0) +#define CFG_WMT_I2S_DBGUART_SUPPORT (0) +#define CFG_SET_OPT_REG_SWLA (0) +#define CFG_SET_OPT_REG_MCUCLK (0) +#define CFG_SET_OPT_REG_MCUIRQ (0) + +#define CFG_SUBSYS_COEX_NEED 0 + +#define CFG_WMT_COREDUMP_ENABLE 0 + +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +INT32 g_deep_sleep_flag = 1; +#else +INT32 g_deep_sleep_flag; +#endif + +#if CFG_WMT_LTE_COEX_HANDLING +#define CFG_WMT_FILTER_MODE_SETTING (1) +#else +#define CFG_WMT_FILTER_MODE_SETTING (0) +#endif +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +static UINT8 gFullPatchName[NAME_MAX + 1]; +static const WMT_IC_INFO_S *gp_mt6632_info; +static WMT_PATCH gp_mt6632_patch_info; +static WMT_CO_CLOCK gCoClockEn = WMT_CO_CLOCK_DIS; + +static UINT8 WMT_QUERY_BAUD_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x02 }; +static UINT8 WMT_QUERY_BAUD_EVT_115200[] = { + 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x01, 0x00 }; +static UINT8 WMT_QUERY_BAUD_EVT_X[] = { + 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0xAA, 0xAA, 0xAA, 0xBB }; +static UINT8 WMT_QUERY_STP_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x04 }; +static UINT8 WMT_QUERY_STP_EVT_DEFAULT[] = { + 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 }; +static UINT8 WMT_QUERY_STP_EVT_UART[] = { + 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0xDF, 0x0E, 0x68, 0x01 }; +static UINT8 WMT_SET_BAUD_CMD_X[] = { 0x01, 0x04, 0x05, 0x00, 0x01, 0xAA, 0xAA, 0xAA, 0xBB }; +static UINT8 WMT_SET_BAUD_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x01 }; +static UINT8 WMT_SET_WAKEUP_WAKE_CMD_RAW[] = { 0xFF }; +static UINT8 WMT_SET_WAKEUP_WAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; +static UINT8 WMT_PATCH_CMD[] = { 0x01, 0x01, 0x00, 0x00, 0x00 }; +static UINT8 WMT_PATCH_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00 }; + +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +UINT8 WMT_DEEP_SLEEP_CMD[] = { 0x01, 0x02, 0x02, 0x00, 0x11, 0x00 }; +UINT8 WMT_DEEP_SLEEP_EVT[] = { 0x02, 0x02, 0x01, 0x00, 0x00 }; +#endif + +UINT8 WMT_CLOCK_RATE_CMD[] = {0x01, 0x0A, 0x04, 0x00, 0x09, 0x01, 0x00, 0x00}; +UINT8 WMT_CLOCK_RATE_EVT[] = {0x02, 0x0A, 0x01, 0x00, 0x00}; +UINT8 WMT_PATCH_DWN_USE_DMA_CMD[] = {0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, + 0x01, 0xc0, 0x0a, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}; +UINT8 WMT_PATCH_DWN_USE_DMA_EVT[] = {0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01}; + +static UINT8 WMT_RESET_CMD[] = { 0x01, 0x07, 0x01, 0x00, 0x04 }; +static UINT8 WMT_RESET_EVT[] = { 0x02, 0x07, 0x01, 0x00, 0x00 }; + +#if CFG_WMT_BT_PORT2 +static UINT8 WMT_BTP2_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x01, 0x03, 0x01 }; +static UINT8 WMT_BTP2_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#endif + +static UINT8 WMT_PATCH_ADDRESS_CMD[] = { 0x01, 0x01, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}; + +static UINT8 WMT_PATCH_ADDRESS_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00}; + +/*coex cmd/evt++*/ +static UINT8 WMT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x01, 0x00 }; +static UINT8 WMT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +#if CFG_SUBSYS_COEX_NEED +static UINT8 WMT_BT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0B, + 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, + 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA +}; +static UINT8 WMT_BT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0C, + 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA +}; +static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_PTA_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0A, + 0x00, 0x04, + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF, 0xFE +}; +static UINT8 WMT_PTA_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINt8 WMT_MISC_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x09, + 0x00, 0x05, + 0xAA, 0xAA, 0xAA, 0xAA, + 0xBB, 0xBB, 0xBB, 0xBB +}; +static UINT8 WMT_MISC_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#else +static UINT8 WMT_COEX_WIFI_PATH_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x1A, 0x0F, 0x00 }; +static UINT8 WMT_COEX_WIFI_PATH_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_COEX_EXT_ELAN_GAIN_P1_CMD[] = { 0x01, 0x10, 0x12, 0x00, 0x1B, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static UINT8 WMT_COEX_EXT_ELAN_GAIN_P1_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#endif + +/*coex cmd/evt--*/ +static UINT8 WMT_SET_STP_CMD[] = { 0x01, 0x04, 0x05, 0x00, 0x03, 0xDF, 0x0E, 0x68, 0x01 }; +static UINT8 WMT_SET_STP_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x03 }; + +static UINT8 WMT_SET_SDIO_RETRY_CMD[] = { 0x01, 0x02, 0x02, 0x00, 0x18, 0x01 }; +static UINT8 WMT_SET_SDIO_RETRY_EVT[] = { 0x02, 0x02, 0x01, 0x00, 0x01 }; + +/* to get full dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_04_CMD[] = { + 0x1, 0x0F, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UINT8 WMT_CORE_DUMP_LEVEL_04_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_CORE_CO_CLOCK_CMD[] = { 0x1, 0x0A, 0x02, 0x00, 0x08, 0x03 }; +static UINT8 WMT_CORE_CO_CLOCK_EVT[] = { 0x2, 0x0A, 0x01, 0x00, 0x00 }; + + +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) + + +static UINT8 WMT_SET_DAI_MODE_REG_CMD[] = { 0x01, 0x08, 0x1c, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ + , 0x54, 0x30, 0x02, 0x81 /*addr:0x81023054 */ + , 0x00, 0x00, 0x33, 0x33 /*value:0x33330000 */ + , 0x00, 0x00, 0xff, 0xff /*mask:0xffff0000 */ + , 0x00, 0x53, 0x02, 0x80 /*addr:0x80025300 */ + , 0x04, 0x00, 0x00, 0x00 /*value:0x00000004 */ + , 0x04, 0x00, 0x00, 0x00 /*mask:0x00000004 */ +}; + +static UINT8 WMT_SET_DAI_MODE_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ +}; + + +#endif + + +#if CFG_SET_OPT_REG_SWLA /* enable swla: eesk(7) eecs(8) oscen(19) sck0(24) scs0(25) */ +static UINT8 WMT_SET_SWLA_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ + , 0x10, 0x01, 0x05, 0x80 /*addr:0x80050110 */ + , 0x10, 0x10, 0x01, 0x00 /*value:0x00011010 */ + , 0xF0, 0xF0, 0x0F, 0x00 /*mask:0x000FF0F0 */ + , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ + , 0x00, 0x10, 0x01, 0x00 /*value:0x00011000 */ + , 0x00, 0xF0, 0x0F, 0x00 /*mask:0x000FF000 */ +}; + +static UINT8 WMT_SET_SWLA_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ +}; +#endif + +#if CFG_SET_OPT_REG_MCUCLK /* enable mcu clk: antsel_4, eedi */ +static UINT8 WMT_SET_MCUCLK_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000 0400 */ + , 0x00, 0x14, 0x00, 0x00 /* value:0x0000 1400(osc, hclk), 0x0000 1501(PLL, en) */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005 0180 */ + , 0x12, 0x13, 0x00, 0x00 /* value:0x0000 1312(osc, hclk), 0x0000 1a19(PLL, en) */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005 0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002 0000 */ + , 0x00, 0x00, 0x0F, 0x00 /* mask:0x000F 0000 */ + , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005 0110 */ + , 0x02, 0x00, 0x00, 0x00 /* value:0x0000 0002 */ + , 0x0F, 0x00, 0x00, 0x00 /* mask:0x0000 000F */ +}; + +static UINT8 WMT_SET_MCUCLK_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ +}; +#endif + +#if CFG_WMT_I2S_DBGUART_SUPPORT /* register write for debug uart */ +static UINT8 WMT_SET_DBGUART_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ + , 0x30, 0x01, 0x05, 0x80 /*addr:0x80050130 */ + , 0x00, 0x00, 0x00, 0x00 /*value:0x00000000 */ + , 0xF0, 0x0F, 0x00, 0x00 /*mask:0x00000FF0 */ + , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ + , 0x00, 0x01, 0x00, 0x00 /*value:0x00000100 */ + , 0x00, 0x01, 0x00, 0x00 /*mask:0x00000100 */ +}; + +static UINT8 WMT_SET_DBGUART_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ +}; +#endif + +#if CFG_SET_OPT_REG_MCUIRQ /* enable mcu irq: antsel_4, wlan_act */ +static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ + , 0x03, 0x14, 0x00, 0x00 /* value:0x0000_1403 check confg debug flag 3 low word */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000_FFFF */ + /* cirq_int_n */ + , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005_0110 */ + , 0x02, 0x00, 0x00, 0x00 /* value:0x0000_0002 set EEDI as cirq_int_n debug flag (monitor flag2) */ + , 0x07, 0x00, 0x00, 0x00 /* mask:0x0000_0007 */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0, ahb_x2_gt_ck debug flag) */ + , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ + /* 1. ARM irq_b, monitor flag 0 */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ + , 0x1F, 0x1E, 0x00, 0x00 /* value:0x0000_1E1F check mcusys debug flag */ + , 0x7F, 0x7F, 0x00, 0x00 /* mask:0x0000_7F7F */ +}; + +static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 5 registers */ +}; +#endif + +static UINT8 WMT_SET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x01, 0x00 }; +static UINT8 WMT_SET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x01, 0x00 }; + +/* +* static UINT8 WMT_GET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x00, 0x00 }; +* static UINT8 WMT_GET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x00, 0x00 }; +*/ + + +#if CFG_WMT_FILTER_MODE_SETTING +static UINT8 WMT_COEX_EXT_COMPONENT_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x0d, 0x00, 0x00 }; + +static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = { 0x01, 0x10, 0x45, 0x00, 0x11, + 0x00, 0x00, 0x01, 0x00, 0x11, + 0x11, 0x16, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x63, 0x63, 0x63, + 0x00, 0x39, 0x43, 0x63, 0x63, + 0x02, 0x02, 0x03, 0x00, 0x01, + 0x01, 0x01, 0x01, 0x0e, 0x0e, + 0x0e, 0x00, 0x0a, 0x0c, 0x0e, + 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 +}; + +static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD[] = { 0x01, 0x10, 0x21, 0x00, 0x12, + 0xfc, 0x08, 0x15, 0x09, 0x2e, + 0x09, 0x47, 0x09, 0xc4, 0x09, + 0xd4, 0x09, 0xe3, 0x09, 0x5a, + 0x0a, 0x14, 0x09, 0x2d, 0x09, + 0x46, 0x09, 0x60, 0x09, 0xd3, + 0x09, 0xe2, 0x09, 0x59, 0x0a, + 0x8B, 0x0a +}; + +static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 }; + +#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING +#else +static UINT8 WMT_COEX_IS_LTE_L_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x21, 0x01 }; +#endif + +static UINT8 WMT_COEX_IS_LTE_PROJ_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x15, 0x01 }; + +static UINT8 WMT_COEX_SPLIT_MODE_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#endif + +static struct init_script init_table_1_2[] = { + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_115200, "query baud 115200"), + INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_DEFAULT, "query stp default"), + INIT_CMD(WMT_SET_BAUD_CMD_X, WMT_SET_BAUD_EVT, "set baud rate"), +}; + + +static struct init_script init_table_2[] = { + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"), +}; + +static struct init_script init_table_3[] = { + INIT_CMD(WMT_RESET_CMD, WMT_RESET_EVT, "wmt reset"), +#if CFG_WMT_BT_PORT2 + INIT_CMD(WMT_BTP2_CMD, WMT_BTP2_EVT, "set bt port2"), +#endif +}; + +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +static struct init_script init_deep_sleep_script[] = { + INIT_CMD(WMT_DEEP_SLEEP_CMD, WMT_DEEP_SLEEP_EVT, "chip deep sleep"), +}; +#endif + +static struct init_script clock_rate_modify[] = { + INIT_CMD(WMT_CLOCK_RATE_CMD, WMT_CLOCK_RATE_EVT, "clock rate modify"), +}; + +/* WMT_CLOCK_RATE_CMD[6] = 0xD0, promote the XTAL(26MHz) rate to 208MHz */ +static struct init_script clock_rate_pro_and_use_dma[] = { + INIT_CMD(WMT_CLOCK_RATE_CMD, WMT_CLOCK_RATE_EVT, "clock rate modify"), + INIT_CMD(WMT_PATCH_DWN_USE_DMA_CMD, WMT_PATCH_DWN_USE_DMA_EVT, "patch dwn use DMA"), +}; + + +static struct init_script set_crystal_timing_script[] = { + INIT_CMD(WMT_SET_CRYSTAL_TRIMING_CMD, WMT_SET_CRYSTAL_TRIMING_EVT, + "set crystal trim value"), +}; +/* +* static struct init_script get_crystal_timing_script[] = { +* INIT_CMD(WMT_GET_CRYSTAL_TRIMING_CMD, WMT_GET_CRYSTAL_TRIMING_EVT, +* "get crystal trim value"), +* }; +*/ + +static struct init_script init_table_4[] = { + INIT_CMD(WMT_SET_STP_CMD, WMT_SET_STP_EVT, "set stp"), +}; + +static struct init_script set_sdio_retry_script[] = { + INIT_CMD(WMT_SET_SDIO_RETRY_CMD, WMT_SET_SDIO_RETRY_EVT, "set sdio retry"), +}; + +static struct init_script init_table_5[] = { + INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_UART, "query stp uart"), + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"), +}; + +static struct init_script init_table_6[] = { + INIT_CMD(WMT_CORE_DUMP_LEVEL_04_CMD, WMT_CORE_DUMP_LEVEL_04_EVT, "setup core dump level"), +}; + + +#if defined(CFG_SET_OPT_REG) && CFG_SET_OPT_REG +static struct init_script set_registers[] = { + /* INIT_CMD(WMT_SET_GPS_REG_CMD, WMT_SET_GPS_REG_EVT, "set wmt registers"), */ + /* INIT_CMD(WMT_SET_SDIODRV_REG_CMD, WMT_SET_SDIODRV_REG_EVT, "set SDIO driving registers") */ +#if CFG_WMT_I2S_DBGUART_SUPPORT + INIT_CMD(WMT_SET_DBGUART_REG_CMD, WMT_SET_DBGUART_REG_EVT, "set debug uart registers"), +#endif +#if CFG_SET_OPT_REG_SWLA + INIT_CMD(WMT_SET_SWLA_REG_CMD, WMT_SET_SWLA_REG_EVT, "set swla registers"), +#endif +#if CFG_SET_OPT_REG_MCUCLK + INIT_CMD(WMT_SET_MCUCLK_REG_CMD, WMT_SET_MCUCLK_REG_EVT, "set mcuclk dbg registers"), +#endif +#if CFG_SET_OPT_REG_MCUIRQ + INIT_CMD(WMT_SET_MCUIRQ_REG_CMD, WMT_SET_MCUIRQ_REG_EVT, "set mcu irq dbg registers"), +#endif +}; +#endif + +static struct init_script coex_table[] = { + INIT_CMD(WMT_COEX_SETTING_CONFIG_CMD, WMT_COEX_SETTING_CONFIG_EVT, "coex_wmt"), + +#if CFG_SUBSYS_COEX_NEED +/* no need in MT6632 */ + INIT_CMD(WMT_BT_COEX_SETTING_CONFIG_CMD, WMT_BT_COEX_SETTING_CONFIG_EVT, "coex_bt"), + INIT_CMD(WMT_WIFI_COEX_SETTING_CONFIG_CMD, WMT_WIFI_COEX_SETTING_CONFIG_EVT, "coex_wifi"), + INIT_CMD(WMT_PTA_COEX_SETTING_CONFIG_CMD, WMT_PTA_COEX_SETTING_CONFIG_EVT, "coex_ext_pta"), + INIT_CMD(WMT_MISC_COEX_SETTING_CONFIG_CMD, WMT_MISC_COEX_SETTING_CONFIG_EVT, "coex_misc"), +#else + INIT_CMD(WMT_COEX_WIFI_PATH_CMD, WMT_COEX_WIFI_PATH_EVT, "wifi path"), + INIT_CMD(WMT_COEX_EXT_ELAN_GAIN_P1_CMD, WMT_COEX_EXT_ELAN_GAIN_P1_EVT, "wifi elan gain p1"), +#endif +}; + +static struct init_script osc_type_table[] = { + INIT_CMD(WMT_CORE_CO_CLOCK_CMD, WMT_CORE_CO_CLOCK_EVT, "osc_type"), +}; + +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) +static struct init_script merge_pcm_table[] = { + INIT_CMD(WMT_SET_DAI_MODE_REG_CMD, WMT_SET_DAI_MODE_REG_EVT, "DAI_PAD"), +}; +#endif + +#if CFG_WMT_FILTER_MODE_SETTING +#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING +static struct init_script set_wifi_lte_coex_table_0[] = { + INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte ext component"), + INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter"), + INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD, WMT_COEX_SPLIT_MODE_EVT, + "wifi lte freq id table"), + INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte unsafe channel"), + INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is lte project"), +}; +#else +static struct init_script set_wifi_lte_coex_table_0[] = { + INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte ext component"), + INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter"), + INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq id table"), + INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte unsafe channel"), + INIT_CMD(WMT_COEX_IS_LTE_L_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is L branch"), + INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is lte project"), +}; +#endif +#endif + +/* MT6632 Chip Version and Info Table */ +static const WMT_IC_INFO_S mt6632_info_table[] = { + { + .u4HwVer = 0x8A00, + .cChipName = WMT_IC_NAME_MT6632, + .cChipVersion = WMT_IC_VER_E1, + .cPatchNameExt = WMT_IC_PATCH_E1_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8A10, + .cChipName = WMT_IC_NAME_MT6632, + .cChipVersion = WMT_IC_VER_E2, + .cPatchNameExt = WMT_IC_PATCH_E2_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8A11, + .cChipName = WMT_IC_NAME_MT6632, + .cChipVersion = WMT_IC_VER_E3, + .cPatchNameExt = WMT_IC_PATCH_E2_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8B11, + .cChipName = WMT_IC_NAME_MT6632, + .cChipVersion = WMT_IC_VER_E4, + .cPatchNameExt = WMT_IC_PATCH_E2_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + } +}; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static INT32 mt6632_sw_init(P_WMT_HIF_CONF pWmtHifConf); + +static INT32 mt6632_sw_deinit(P_WMT_HIF_CONF pWmtHifConf); + +static INT32 mt6632_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag); + +static INT32 mt6632_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag); + +static INT32 mt6632_ver_check(VOID); + +static const WMT_IC_INFO_S *mt6632_find_wmt_ic_info(const UINT32 hw_ver); + +static INT32 wmt_stp_init_coex(VOID); + +static INT32 mt6632_patch_dwn(UINT32 index); +static INT32 mt6632_patch_info_prepare(VOID); + +static INT32 mt6632_co_clock_ctrl(WMT_CO_CLOCK on); +static WMT_CO_CLOCK mt6632_co_clock_get(VOID); + +/*static INT32 mt6632_crystal_triming_set(VOID);*/ + + +static MTK_WCN_BOOL mt6632_quick_sleep_flag_get(VOID); + +static MTK_WCN_BOOL mt6632_aee_dump_flag_get(VOID); +#if 0 +/* set sdio driving */ +static UINT8 WMT_SET_SDIO_DRV_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x50, 0x00, 0x05, 0x80 /*addr:0x80050050 */ + , 0x44, 0x44, 0x04, 0x00 /*value:0x00044444 */ + , 0x77, 0x77, 0x07, 0x00 /*mask:0x00077777 */ +}; + +static UINT8 WMT_SET_SDIO_DRV_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; + +static INT32 mt6632_set_sdio_driving(void); +static struct init_script sdio_driving_table[] = { + INIT_CMD(WMT_SET_SDIO_DRV_REG_CMD, WMT_SET_SDIO_DRV_REG_EVT, "sdio_driving"), +}; + +#endif +static MTK_WCN_BOOL mt6632_trigger_stp_assert(VOID); +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +static MTK_WCN_BOOL mt6632_deep_sleep_ctrl(INT32 value); +static INT32 wmt_stp_get_deep_sleep_flag_from_cfg(VOID); +#endif + +#if CFG_WMT_FILTER_MODE_SETTING +static INT32 wmt_stp_wifi_lte_coex(VOID); +#endif + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/* MT6632 Operation Function Table */ +WMT_IC_OPS wmt_ic_ops_mt6632 = { + .icId = 0x6632, + .sw_init = mt6632_sw_init, + .sw_deinit = mt6632_sw_deinit, + .ic_pin_ctrl = mt6632_pin_ctrl, + .ic_ver_check = mt6632_ver_check, + .co_clock_ctrl = mt6632_co_clock_ctrl, + .is_quick_sleep = mt6632_quick_sleep_flag_get, + .is_aee_dump_support = mt6632_aee_dump_flag_get, + .trigger_stp_assert = mt6632_trigger_stp_assert, +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT + .deep_sleep_ctrl = mt6632_deep_sleep_ctrl, +#else + .deep_sleep_ctrl = NULL, +#endif + +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static INT32 mt6632_sw_init(P_WMT_HIF_CONF pWmtHifConf) +{ + INT32 iRet = -1; + UINT32 u4Res = 0; + UINT8 evtBuf[256]; + ULONG ctrlPa1; + ULONG ctrlPa2; + UINT32 hw_ver; + UINT32 patch_num = 0; + UINT32 patch_index = 0; + WMT_CTRL_DATA ctrlData; +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT + INT32 deep_sleep_flag_from_cfg; +#endif + WMT_DBG_FUNC(" start\n"); + + osal_assert(gp_mt6632_info != NULL); + + if ((gp_mt6632_info == NULL) + || (pWmtHifConf == NULL) + ) { + WMT_ERR_FUNC("null pointers: gp_mt6632_info(0x%p), pWmtHifConf(0x%p)\n", + gp_mt6632_info, pWmtHifConf); + return -1; + } + + hw_ver = gp_mt6632_info->u4HwVer; + + /* 4 <3.1> start init for sdio */ + + /* 4 <3.2> start init for uart */ + if (pWmtHifConf->hifType == WMT_HIF_UART) { + /* init variable fields for script execution */ + osal_memcpy(&WMT_SET_BAUD_CMD_X[5], &pWmtHifConf->au4HifConf[0], + osal_sizeof(UINT32)); + WMT_SET_BAUD_CMD_X[8] = (UINT8) 0x00; /* 0xC0 MTK Flow Control *//* no flow control */ + osal_memcpy(&WMT_QUERY_BAUD_EVT_X[6], &pWmtHifConf->au4HifConf[0], + osal_sizeof(UINT32)); + WMT_QUERY_BAUD_EVT_X[9] = (UINT8) 0x00; /* 0xC0 MTK Flow Control *//* no flow control */ + + /* 3. Query chip baud rate (TEST-ONLY) */ + /* 4. Query chip STP options (TEST-ONLY) */ + /* 5. Change chip baud rate: t_baud */ + /* WMT_DBG_FUNC("WMT-CORE: init_table_1_2 set chip baud:%d", pWmtHifConf->au4HifConf[0]); */ + iRet = wmt_core_init_script(init_table_1_2, ARRAY_SIZE(init_table_1_2)); + + if (iRet) { + WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet); + osal_assert(0); + return -2; + } + + /* 6. Set host baudrate and flow control */ + ctrlPa1 = pWmtHifConf->au4HifConf[0]; + ctrlPa2 = 0; + iRet = wmt_core_ctrl(WMT_CTRL_HOST_BAUDRATE_SET, &ctrlPa1, &ctrlPa2); + + if (iRet) { + WMT_ERR_FUNC("change baudrate(%d) fail(%d)\n", pWmtHifConf->au4HifConf[0], + iRet); + return -3; + } + + WMT_INFO_FUNC("WMT-CORE: change baudrate(%d) ok\n", pWmtHifConf->au4HifConf[0]); + + /* 7. Wake up chip and check event */ +/* iRet = (*kal_stp_tx_raw)(&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res); */ + iRet = + wmt_core_tx((PUINT8)&WMT_SET_WAKEUP_WAKE_CMD_RAW[0], 1, &u4Res, + MTK_WCN_BOOL_TRUE); + + if (iRet || (u4Res != 1)) { + WMT_ERR_FUNC("write raw iRet(%d) written(%d)\n", iRet, u4Res); + return -4; + } + + osal_memset(evtBuf, 0, osal_sizeof(evtBuf)); + iRet = wmt_core_rx(evtBuf, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT), &u4Res); +#ifdef CFG_DUMP_EVT + WMT_DBG_FUNC("WAKEUP_WAKE_EVT read len %d [%02x,%02x,%02x,%02x,%02x,%02x]\n", + (INT32) u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + evtBuf[5]); +#endif + + if (iRet || (u4Res != osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT))) { + WMT_ERR_FUNC("read WAKEUP_WAKE_EVT fail(%d)\n", iRet); + mtk_wcn_stp_dbg_dump_package(); + return -5; + } + /* WMT_DBG_FUNC("WMT-CORE: read WMT_SET_WAKEUP_WAKE_EVT ok"); */ + +#if CFG_CHECK_WMT_RESULT + + if (osal_memcmp + (evtBuf, WMT_SET_WAKEUP_WAKE_EVT, osal_sizeof(WMT_SET_WAKEUP_WAKE_EVT)) != 0) { + WMT_ERR_FUNC("WMT-CORE: write WMT_SET_WAKEUP_WAKE_CMD_RAW status fail\n"); + return -6; + } +#endif + + /* 8. Query baud rate (TEST-ONLY) */ + iRet = wmt_core_init_script(init_table_2, osal_array_size(init_table_2)); + + if (iRet) { + WMT_ERR_FUNC("init_table_2 fail(%d)\n", iRet); + return -7; + } + } + + /* 9. download patch */ + /* 9.1 Let launcher to search patch info */ + iRet = mt6632_patch_info_prepare(); + + if (iRet) { + WMT_ERR_FUNC("patch info perpare fail(%d)\n", iRet); + return -8; + } + + /* 9.2 Read patch number */ + ctrlPa1 = 0; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_GET_PATCH_NUM, &ctrlPa1, &ctrlPa2); + patch_num = ctrlPa1; + WMT_DBG_FUNC("patch total num = [%d]\n", patch_num); + + /* improve patch down load speed */ + WMT_DBG_FUNC("improve patch dwn speed, clock rate promote, copy data use DMA at firmware side\n"); + WMT_CLOCK_RATE_CMD[6] = 0xD0; + /* If WMT_CLOCK_RATE_CMD[6] = 0xD0, promote the XTAL(26MHz) rate to 208MHz + * copy data use DMA at firmware side + */ + iRet = wmt_core_init_script(clock_rate_pro_and_use_dma, ARRAY_SIZE(clock_rate_pro_and_use_dma)); + if (iRet) { + WMT_ERR_FUNC("clock_rate_pro_and_use_dma fail(%d)\n", iRet); + return -30; + } + /* 9.3 Multi-patch Patch download */ + for (patch_index = 0; patch_index < patch_num; patch_index++) { + iRet = mt6632_patch_dwn(patch_index); + + if (iRet) { + WMT_ERR_FUNC("patch dwn fail (%d),patch_index(%d)\n", iRet, patch_index); + return -12; + } + + /* 10. WMT Reset command */ + iRet = wmt_core_init_script(init_table_3, ARRAY_SIZE(init_table_3)); + + if (iRet) { + WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); + return -13; + } + } + /*close clock rate promote*/ + WMT_CLOCK_RATE_CMD[6] = 0x00; + WMT_DBG_FUNC("close clock rate promote, made XTAL to 26MHz\n"); + iRet = wmt_core_init_script(clock_rate_modify, ARRAY_SIZE(clock_rate_modify)); + if (iRet) { + WMT_ERR_FUNC("close clock rate promote fail(%d)\n", iRet); + return -31; + } + + /* SDIO data patch retry feature enable/disable */ + mtk_stp_sdio_retry_flag_ctrl(1); + if (mtk_stp_sdio_retry_flag_get()) { + iRet = wmt_core_init_script(set_sdio_retry_script, ARRAY_SIZE(set_sdio_retry_script)); + + if (iRet) { + WMT_ERR_FUNC("set_sdio_retry_script fail(%d)\n", iRet); + mtk_stp_sdio_retry_flag_ctrl(0); + } + } + +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT + if (g_deep_sleep_flag) { + /*get flag form mt6632_ant_m1.cfg*/ + deep_sleep_flag_from_cfg = wmt_stp_get_deep_sleep_flag_from_cfg(); + if (deep_sleep_flag_from_cfg == 1) { + WMT_DEEP_SLEEP_CMD[5] = 1; + iRet = wmt_core_init_script(init_deep_sleep_script, ARRAY_SIZE(init_deep_sleep_script)); + if (iRet) { + WMT_ERR_FUNC("enalbe deep sleep feature fail\n"); + return -20; + } + WMT_DBG_FUNC("chip deep sleep feature is enable\n"); + wmt_lib_deep_sleep_flag_set(MTK_WCN_BOOL_TRUE); + } else { + WMT_DEEP_SLEEP_CMD[5] = 0; + iRet = wmt_core_init_script(init_deep_sleep_script, ARRAY_SIZE(init_deep_sleep_script)); + if (iRet) { + WMT_ERR_FUNC("disable deep sleep feature fail\n"); + return -21; + } + WMT_INFO_FUNC("chip deep sleep feature is disable\n"); + wmt_lib_deep_sleep_flag_set(MTK_WCN_BOOL_FALSE); + } + } else { + WMT_DEEP_SLEEP_CMD[5] = 0; + iRet = wmt_core_init_script(init_deep_sleep_script, ARRAY_SIZE(init_deep_sleep_script)); + if (iRet) { + WMT_ERR_FUNC("disable deep sleep feature fail\n"); + return -22; + } + WMT_INFO_FUNC("chip deep sleep feature is disable\n"); + wmt_lib_deep_sleep_flag_set(MTK_WCN_BOOL_FALSE); + } +#endif + iRet = wmt_stp_init_coex(); + + if (iRet) { + WMT_ERR_FUNC("init_coex fail(%d)\n", iRet); + return -10; + } + WMT_DBG_FUNC("init_coex ok\n"); + /*If TCXO or co-clock is applied in mt6632, remove the triming patch*/ + /*mt6632_crystal_triming_set();*/ +#if MT6632_BRINGUP + WMT_DBG_FUNC("Bring up period, skip sdio driving settings\n"); +#else + WMT_DBG_FUNC("Temp solution, skip sdio driving settings\n"); + /* 6632_set_sdio_driving(); */ +#endif + if (pWmtHifConf->hifType == WMT_HIF_UART) { + /* 11. Set chip STP options */ + iRet = wmt_core_init_script(init_table_4, ARRAY_SIZE(init_table_4)); + + if (iRet) { + WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet); + return -12; + } + + /* 12. Enable host STP-UART mode */ + ctrlPa1 = WMT_STP_CONF_MODE; + ctrlPa2 = MTKSTP_UART_FULL_MODE; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 1; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + + if (iRet) { + WMT_ERR_FUNC("enable host STP-UART-FULL mode fail(%d)\n", iRet); + return -13; + } + + WMT_INFO_FUNC("enable host STP-UART-FULL mode\n"); + /*13. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */ + osal_sleep_ms(10); + /* 14. Query chip STP options (TEST-ONLY) */ + /* 15. Query baud rate (stp, TEST-ONLY) */ + iRet = wmt_core_init_script(init_table_5, ARRAY_SIZE(init_table_5)); + + if (iRet) { + WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet); + return -14; + } + } + + if (mt6632_co_clock_get() == WMT_CO_CLOCK_EN) { + WMT_INFO_FUNC("co-clock enabled.\n"); + + iRet = wmt_core_init_script(osc_type_table, ARRAY_SIZE(osc_type_table)); + + if (iRet) { + WMT_ERR_FUNC("osc_type_table fail(%d), goes on\n", iRet); + return -15; + } + } else if (mt6632_co_clock_get() == WMT_CO_CLOCK_DCXO) { + WMT_SET_CRYSTAL_TRIMING_CMD[4] = 0x2; + WMT_SET_CRYSTAL_TRIMING_CMD[5] = 0x2; + WMT_SET_CRYSTAL_TRIMING_EVT[4] = 0x2; + WMT_SET_CRYSTAL_TRIMING_EVT[5] = 0x0; + iRet = wmt_core_init_script(set_crystal_timing_script, ARRAY_SIZE(set_crystal_timing_script)); + if (iRet == 0) + WMT_INFO_FUNC("set to Xtal mode suceed\n"); + else + WMT_INFO_FUNC("set to Xtal mode failed, iRet:%d.\n", iRet); + + + } else + WMT_INFO_FUNC("co-clock disabled.\n"); +#if MT6632_BRINGUP + WMT_INFO_FUNC("Bring up period, skip merge interface settings\n"); +#else + +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) + iRet = wmt_core_init_script(merge_pcm_table, ARRAY_SIZE(merge_pcm_table)); + + if (iRet) { + WMT_ERR_FUNC("merge_pcm_table fail(%d), goes on\n", iRet); + return -15; + } +#endif +#endif + +#if CFG_SET_OPT_REG /*set registers */ + iRet = wmt_core_init_script(set_registers, ARRAY_SIZE(set_registers)); + + if (iRet) { + WMT_ERR_FUNC("set_registers fail(%d)", iRet); + return -17; + } +#endif + +#if CFG_WMT_COREDUMP_ENABLE + /*Open Core Dump Function @QC begin */ + mtk_wcn_stp_coredump_flag_ctrl(1); +#endif + + if (mtk_wcn_stp_coredump_flag_get() != 0) { + iRet = wmt_core_init_script(init_table_6, ARRAY_SIZE(init_table_6)); + + if (iRet) { + WMT_ERR_FUNC("init_table_6 core dump setting fail(%d)\n", iRet); + return -18; + } + WMT_INFO_FUNC("enable mt662x firmware coredump\n"); + } else + WMT_INFO_FUNC("disable mt662x firmware coredump\n"); + + ctrlData.ctrlId = WMT_CTRL_SET_STP_DBG_INFO; + ctrlData.au4CtrlData[0] = wmt_ic_ops_mt6632.icId; + ctrlData.au4CtrlData[1] = (size_t) gp_mt6632_info->cChipVersion; + ctrlData.au4CtrlData[2] = (size_t) &gp_mt6632_patch_info; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("set dump info fail(%d)\n", iRet); + return -16; + } +#if CFG_WMT_FILTER_MODE_SETTING + wmt_stp_wifi_lte_coex(); +#endif + +#if CFG_WMT_PS_SUPPORT + osal_assert(gp_mt6632_info != NULL); + + if (gp_mt6632_info != NULL) { + if (gp_mt6632_info->bPsmSupport != MTK_WCN_BOOL_FALSE) + wmt_lib_ps_enable(); + else + wmt_lib_ps_disable(); + } +#endif + + return 0; +} + +static INT32 mt6632_sw_deinit(P_WMT_HIF_CONF pWmtHifConf) +{ + WMT_DBG_FUNC(" start\n"); + +#if CFG_WMT_PS_SUPPORT + osal_assert(gp_mt6632_info != NULL); + + if ((gp_mt6632_info != NULL) + && (gp_mt6632_info->bPsmSupport != MTK_WCN_BOOL_FALSE)) { + wmt_lib_ps_disable(); + } +#endif + + gp_mt6632_info = NULL; + + return 0; +} + +static INT32 mt6632_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 ret = -1; + +#if MT6632_BRINGUP + ret = 0; + WMT_INFO_FUNC("Bring up period, skip aif settings\n"); +#else + + if ((flag & WMT_LIB_AIF_FLAG_MASK) == WMT_LIB_AIF_FLAG_SHARE) { + WMT_INFO_FUNC("PCM & I2S PIN SHARE\n"); + + WMT_WARN_FUNC("TBD!!"); + ret = 0; + } else { + /*PCM & I2S separate */ + WMT_INFO_FUNC("PCM & I2S PIN SEPARATE\n"); + + switch (state) { + case WMT_IC_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + ret = 0; + break; + + case WMT_IC_AIF_1: + /* BT_PCM_ON & FM line in/out */ + ret = 0; + break; + + case WMT_IC_AIF_2: + /* BT_PCM_OFF & FM I2S */ +#if 0 + val = 0x01110000; + ret = wmt_core_reg_rw_raw(1, 0x80050078, &val, 0x0FFF0000); +#else + ret = 0; + WMT_INFO_FUNC("Bring up period, skip WMT_IC_AIF_2 settings\n"); +#endif + break; + + case WMT_IC_AIF_3: + ret = 0; + break; + + default: + WMT_ERR_FUNC("unsupported state (%d)\n", state); + ret = -1; + break; + } + } + + if (!ret) + WMT_INFO_FUNC("new state(%d) ok\n", state); + else + WMT_WARN_FUNC("new state(%d) fail(%d)\n", state, ret); +#endif + return ret; +} + +static INT32 mt6632_gps_sync_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) +{ + WMT_DBG_FUNC("MT6632 do not need gps sync settings\n"); + + /* anyway, we return 0 */ + return 0; +} + + +static INT32 mt6632_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 ret; + + WMT_DBG_FUNC("ic pin id:%d, state:%d, flag:0x%x\n", id, state, flag); + + ret = -1; + + switch (id) { + case WMT_IC_PIN_AUDIO: + ret = mt6632_aif_ctrl(state, flag); + break; + + case WMT_IC_PIN_EEDI: + WMT_WARN_FUNC("TBD!!"); + /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ + ret = 0; + break; + + case WMT_IC_PIN_EEDO: + WMT_WARN_FUNC("TBD!!"); + /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ + ret = 0; + break; + + case WMT_IC_PIN_GSYNC: + ret = mt6632_gps_sync_ctrl(state, flag); + break; + + default: + break; + } + + WMT_DBG_FUNC("ret = (%d)\n", ret); + + return ret; +} + +INT32 mt6632_co_clock_ctrl(WMT_CO_CLOCK on) +{ + INT32 iRet = 0; + + if ((on >= WMT_CO_CLOCK_DIS) && (on < WMT_CO_CLOCK_MAX)) { + gCoClockEn = on; + } else { + WMT_DBG_FUNC("MT6632: error parameter:%d\n", on); + iRet = -1; + } + + WMT_DBG_FUNC("MT6632: Co-clock type: %d\n", gCoClockEn); + + return iRet; +} + +static MTK_WCN_BOOL mt6632_quick_sleep_flag_get(VOID) +{ + return MTK_WCN_BOOL_TRUE; +} + + +static MTK_WCN_BOOL mt6632_aee_dump_flag_get(VOID) +{ + if (mtk_wcn_stp_coredump_flag_get() == 1) + return MTK_WCN_BOOL_TRUE; + else + return MTK_WCN_BOOL_FALSE; +} + +static MTK_WCN_BOOL mt6632_trigger_stp_assert(VOID) +{ + INT32 iRet = -1; + UINT32 u4Res = 0; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + UINT8 STP_DO_ASSERT_CMD[] = { 0x80, 0x50, 0x0a, 0x00, 'd', 'o', 'c', 'o', 'r', 'e', 'd', 'u', 'm', 'p', 0x00, + 0x00 + }; + + iRet = + wmt_core_tx((PUINT8)&STP_DO_ASSERT_CMD[0], sizeof(STP_DO_ASSERT_CMD), &u4Res, + MTK_WCN_BOOL_TRUE); + if (iRet || (u4Res != sizeof(STP_DO_ASSERT_CMD))) { + WMT_ERR_FUNC("wmt_core:send STP ASSERT COMMAND fail(%d),size(%d)\n", iRet, u4Res); + bRet = MTK_WCN_BOOL_FALSE; + } else + bRet = MTK_WCN_BOOL_TRUE; + return bRet; +} +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +static MTK_WCN_BOOL mt6632_deep_sleep_ctrl(INT32 value) +{ + INT32 ret = 0; + + g_deep_sleep_flag = value; + if (value) { + WMT_DEEP_SLEEP_CMD[5] = 1; + WMT_INFO_FUNC("enable chip deep sleep feature from wmt_dbg command\n"); + } else { + WMT_DEEP_SLEEP_CMD[5] = 0; + WMT_INFO_FUNC("disable chip deep sleep feature from wmt_dbg command\n"); + } + ret = wmt_core_init_script(init_deep_sleep_script, ARRAY_SIZE(init_deep_sleep_script)); + if (ret == 0) + return MTK_WCN_BOOL_TRUE; + else + return MTK_WCN_BOOL_FALSE; +} + +static INT32 wmt_stp_get_deep_sleep_flag_from_cfg(VOID) +{ + WMT_GEN_CONF *pWmtGenConf; + ULONG addr; + INT32 ret; + + /*Get wmt config */ + ret = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + + if (ret) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", ret); + return -2; + } + + WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return -1; + } + if (pWmtGenConf->disable_deep_sleep_cfg == 0) { + WMT_DBG_FUNC("disable_deep_sleep_cfg (%d) get form mt6632_ant_m1.cfg, enable deep sleep feature\n", + pWmtGenConf->disable_deep_sleep_cfg); + ret = 1; + } else { + WMT_DBG_FUNC("disable_deep_sleep_cfg (%d) get form mt6632_ant_m1.cfg, disable deep sleep feature\n", + pWmtGenConf->disable_deep_sleep_cfg); + ret = 0; + } + return ret; +} + +#endif + +WMT_CO_CLOCK mt6632_co_clock_get(VOID) +{ + return gCoClockEn; +} + + + +static INT32 mt6632_ver_check(VOID) +{ + UINT32 hw_ver = 0; + UINT32 fw_ver = 0; + INT32 iret; + const WMT_IC_INFO_S *p_info; + ULONG ctrlPa1; + ULONG ctrlPa2; + + + /* 1. identify chip versions: HVR(HW_VER) and FVR(FW_VER) */ + WMT_LOUD_FUNC("MT6632: before read hw_ver (hw version)\n"); + iret = wmt_core_reg_rw_raw(0, GEN_HVR, &hw_ver, GEN_VER_MASK); + + if (iret) { + WMT_ERR_FUNC("MT6632: read hw_ver fail:%d\n", iret); + return -2; + } + + WMT_LOUD_FUNC("MT6632: before fw_ver (rom version)\n"); + wmt_core_reg_rw_raw(0, GEN_FVR, &fw_ver, GEN_VER_MASK); + + if (iret) { + WMT_ERR_FUNC("MT6632: read fw_ver fail:%d\n", iret); + return -2; + } + WMT_INFO_FUNC("MT6632: read (hw version)(0x%x), (fw version version)(0x%x)\n", hw_ver, fw_ver); + + p_info = mt6632_find_wmt_ic_info(hw_ver); + + if (p_info == NULL) { + WMT_ERR_FUNC("MT6632: hw_ver(0x%x) find wmt ic info fail\n", hw_ver); + return -3; + } + + WMT_DBG_FUNC("MT6632: wmt ic info: %s.%s (0x%x, patch_ext:%s)\n", + p_info->cChipName, p_info->cChipVersion, + p_info->u4HwVer, p_info->cPatchNameExt); + + /* hw id & version */ + ctrlPa1 = (0x00006632UL << 16) | (hw_ver & 0x0000FFFF); + /* translated fw rom version */ + ctrlPa2 = (fw_ver & 0x0000FFFF); + + iret = wmt_core_ctrl(WMT_CTRL_HWIDVER_SET, &ctrlPa1, &ctrlPa2); + + if (iret) + WMT_WARN_FUNC("MT6632: WMT_CTRL_HWIDVER_SET fail(%d)\n", iret); + + gp_mt6632_info = p_info; + return 0; +} + +static const WMT_IC_INFO_S *mt6632_find_wmt_ic_info(const UINT32 hw_ver) +{ + /* match chipversion with u4HwVer item in mt6632_info_table */ + const UINT32 size = ARRAY_SIZE(mt6632_info_table); + INT32 index; + + /* Leave full match here is a workaround for GPS to distinguish E3/E4 ICs. */ + index = size - 1; + + /* full match */ + while ((index >= 0) + && (hw_ver != mt6632_info_table[index].u4HwVer) /* full match */ + ) { + --index; + } + + if (index >= 0) { + WMT_DBG_FUNC("found ic info(0x%x) by full match! index:%d\n", hw_ver, index); + return &mt6632_info_table[index]; + } + + WMT_WARN_FUNC("find no ic info for (0x%x) by full match!try major num match!\n", hw_ver); + + /* George: The ONLY CORRECT method to find supported hw table. Match MAJOR + * NUM only can help us support future minor hw ECO, or fab switch, etc. + * FULL matching eliminate such flexibility and software package have to be + * updated EACH TIME even when minor hw ECO or fab switch!!! + */ + /* George: reverse the search order to favor newer version products */ + index = size - 1; + + /* major num match */ + while ((index >= 0) + && (MAJORNUM(hw_ver) != MAJORNUM(mt6632_info_table[index].u4HwVer)) + ) { + --index; + } + + if (index >= 0) { + WMT_INFO_FUNC("MT6632: found ic info for hw_ver(0x%x) by major num! index:%d\n", + hw_ver, index); + return &mt6632_info_table[index]; + } + + WMT_ERR_FUNC + ("MT6632: find no ic info for hw_ver(0x%x) by full match nor major num match!\n", + hw_ver); + return NULL; +} + + +static INT32 wmt_stp_init_coex(VOID) +{ + INT32 iRet; + ULONG addr = 0; + WMT_GEN_CONF *pWmtGenConf; + +#define COEX_WMT 0 + +#if CFG_SUBSYS_COEX_NEED + /* no need for MT6632 */ +#define COEX_BT 1 +#define COEX_WIFI 2 +#define COEX_PTA 3 +#define COEX_MISC 4 +#else +#define COEX_WIFI_PATH 1 +#define COEX_EXT_ELAN_GAIN_P1 2 +#endif +#define WMT_COXE_CONFIG_ADJUST_ANTENNA_OPCODE 6 + + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + + WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + + /*Dump the coex-related info */ + WMT_DBG_FUNC("coex_wmt_ant_mode:0x%x, coex_wmt_wifi_path:0x%x\n", + pWmtGenConf->coex_wmt_ant_mode, pWmtGenConf->coex_wmt_wifi_path); +#if CFG_SUBSYS_COEX_NEED + WMT_DBG_FUNC("coex_bt:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_bt_rssi_upper_limit, + pWmtGenConf->coex_bt_rssi_mid_limit, + pWmtGenConf->coex_bt_rssi_lower_limit, + pWmtGenConf->coex_bt_pwr_high, + pWmtGenConf->coex_bt_pwr_mid, pWmtGenConf->coex_bt_pwr_low); + WMT_DBG_FUNC("coex_wifi:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_wifi_rssi_upper_limit, + pWmtGenConf->coex_wifi_rssi_mid_limit, + pWmtGenConf->coex_wifi_rssi_lower_limit, + pWmtGenConf->coex_wifi_pwr_high, + pWmtGenConf->coex_wifi_pwr_mid, pWmtGenConf->coex_wifi_pwr_low); + WMT_DBG_FUNC("coex_ext_pta:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_ext_pta_hi_tx_tag, + pWmtGenConf->coex_ext_pta_hi_rx_tag, + pWmtGenConf->coex_ext_pta_lo_tx_tag, + pWmtGenConf->coex_ext_pta_lo_rx_tag, + pWmtGenConf->coex_ext_pta_sample_t1, + pWmtGenConf->coex_ext_pta_sample_t2, + pWmtGenConf->coex_ext_pta_wifi_bt_con_trx); + WMT_DBG_FUNC("coex_misc:0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_misc_ext_pta_on, pWmtGenConf->coex_misc_ext_feature_set); +#endif + + /*command adjustion due to WMT.cfg */ + coex_table[COEX_WMT].cmd[4] = WMT_COXE_CONFIG_ADJUST_ANTENNA_OPCODE; + coex_table[COEX_WMT].cmd[5] = pWmtGenConf->coex_wmt_ant_mode; + + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_WMT].cmd[0], + coex_table[COEX_WMT].str, coex_table[COEX_WMT].cmdSz); + } + +#if CFG_SUBSYS_COEX_NEED + coex_table[COEX_BT].cmd[9] = pWmtGenConf->coex_bt_rssi_upper_limit; + coex_table[COEX_BT].cmd[10] = pWmtGenConf->coex_bt_rssi_mid_limit; + coex_table[COEX_BT].cmd[11] = pWmtGenConf->coex_bt_rssi_lower_limit; + coex_table[COEX_BT].cmd[12] = pWmtGenConf->coex_bt_pwr_high; + coex_table[COEX_BT].cmd[13] = pWmtGenConf->coex_bt_pwr_mid; + coex_table[COEX_BT].cmd[14] = pWmtGenConf->coex_bt_pwr_low; + + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_BT].cmd[0], + coex_table[COEX_BT].str, coex_table[COEX_BT].cmdSz); + } + + coex_table[COEX_WIFI].cmd[10] = pWmtGenConf->coex_wifi_rssi_upper_limit; + coex_table[COEX_WIFI].cmd[11] = pWmtGenConf->coex_wifi_rssi_mid_limit; + coex_table[COEX_WIFI].cmd[12] = pWmtGenConf->coex_wifi_rssi_lower_limit; + coex_table[COEX_WIFI].cmd[13] = pWmtGenConf->coex_wifi_pwr_high; + coex_table[COEX_WIFI].cmd[14] = pWmtGenConf->coex_wifi_pwr_mid; + coex_table[COEX_WIFI].cmd[15] = pWmtGenConf->coex_wifi_pwr_low; + + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_WIFI].cmd[0], + coex_table[COEX_WIFI].str, coex_table[COEX_WIFI].cmdSz); + } + + coex_table[COEX_PTA].cmd[5] = pWmtGenConf->coex_ext_pta_hi_tx_tag; + coex_table[COEX_PTA].cmd[6] = pWmtGenConf->coex_ext_pta_hi_rx_tag; + coex_table[COEX_PTA].cmd[7] = pWmtGenConf->coex_ext_pta_lo_tx_tag; + coex_table[COEX_PTA].cmd[8] = pWmtGenConf->coex_ext_pta_lo_rx_tag; + coex_table[COEX_PTA].cmd[9] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0xff00) >> 8); + coex_table[COEX_PTA].cmd[10] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0x00ff) >> 0); + coex_table[COEX_PTA].cmd[11] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0xff00) >> 8); + coex_table[COEX_PTA].cmd[12] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0x00ff) >> 0); + coex_table[COEX_PTA].cmd[13] = pWmtGenConf->coex_ext_pta_wifi_bt_con_trx; + + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_PTA].cmd[0], + coex_table[COEX_PTA].str, coex_table[COEX_PTA].cmdSz); + } + + osal_memcpy(&coex_table[COEX_MISC].cmd[5], &pWmtGenConf->coex_misc_ext_pta_on, + sizeof(pWmtGenConf->coex_misc_ext_pta_on)); + osal_memcpy(&coex_table[COEX_MISC].cmd[9], &pWmtGenConf->coex_misc_ext_feature_set, + sizeof(pWmtGenConf->coex_misc_ext_feature_set)); + + wmt_core_dump_data(&coex_table[COEX_MISC].cmd[0], coex_table[COEX_MISC].str, + coex_table[COEX_MISC].cmdSz); +#else + coex_table[COEX_WIFI_PATH].cmd[5] = + (UINT8)((pWmtGenConf->coex_wmt_wifi_path & 0x00FF) >> 0); + coex_table[COEX_WIFI_PATH].cmd[6] = + (UINT8)((pWmtGenConf->coex_wmt_wifi_path & 0xFF00) >> 8); + + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_WIFI_PATH].cmd[0], + coex_table[COEX_WIFI_PATH].str, coex_table[COEX_WIFI_PATH].cmdSz); + } + + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[5] = pWmtGenConf->coex_wmt_ext_elna_gain_p1_support; + /* wmt_ext_elna_gain_p1 D0*/ + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[6] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0x000000FF) >> 0); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[7] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0x0000FF00) >> 8); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[8] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0x00FF0000) >> 16); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[9] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0xFF000000) >> 24); + /* wmt_ext_elna_gain_p1 D1*/ + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[10] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0x000000FF) >> 0); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[11] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0x0000FF00) >> 8); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[12] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0x00FF0000) >> 16); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[13] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0xFF000000) >> 24); + /* wmt_ext_elna_gain_p1 D2*/ + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[14] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0x000000FF) >> 0); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[15] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0x0000FF00) >> 8); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[16] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0x00FF0000) >> 16); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[17] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0xFF000000) >> 24); + /* wmt_ext_elna_gain_p1 D3*/ + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[18] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0x000000FF) >> 0); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[19] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0x0000FF00) >> 8); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[20] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0x00FF0000) >> 16); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[21] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0xFF000000) >> 24); + + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[0], + coex_table[COEX_EXT_ELAN_GAIN_P1].str, coex_table[COEX_EXT_ELAN_GAIN_P1].cmdSz); + } + +#endif + + iRet = wmt_core_init_script(coex_table, ARRAY_SIZE(coex_table)); + + return iRet; +} + +#if 0 +static INT32 mt6632_set_sdio_driving(void) +{ + INT32 ret = 0; + + UINT32 addr = 0; + WMT_GEN_CONF *pWmtGenConf; + UINT32 drv_val = 0; + + /*Get wmt config */ + ret = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + + if (ret) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", ret); + return -1; + } + + WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%x)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + drv_val = pWmtGenConf->sdio_driving_cfg; + + /*Dump the sdio driving related info */ + WMT_INFO_FUNC("sdio driving:0x%x\n", drv_val); + + sdio_driving_table[0].cmd[12] = (UINT8) ((drv_val & 0x00000077UL) >> 0); /* DAT0 and DAT1 */ + sdio_driving_table[0].cmd[13] = (UINT8) ((drv_val & 0x00007700UL) >> 8); /* DAT2 and DAT3 */ + sdio_driving_table[0].cmd[14] = (UINT8) ((drv_val & 0x00070000UL) >> 16); /* CMD */ + + ret = wmt_core_init_script(sdio_driving_table, ARRAY_SIZE(sdio_driving_table)); + + return ret; +} + +static INT32 mt6632_crystal_triming_set(VOID) +{ + INT32 iRet = 0; + PUINT8 pbuf = NULL; + UINT32 bufLen = 0; + WMT_CTRL_DATA ctrlData; + UINT32 uCryTimOffset = 0x6D; + MTK_WCN_BOOL bIsNvramExist = MTK_WCN_BOOL_FALSE; + INT8 cCrystalTimingOffset = 0x0; + UINT8 cCrystalTiming = 0x0; + INT32 iCrystalTiming = 0x0; + MTK_WCN_BOOL bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + UINT32 u4Res; + + bIsNvramExist = MTK_WCN_BOOL_FALSE; + ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_GET; + ctrlData.au4CtrlData[0] = (size_t) "/data/nvram/APCFG/APRDEB/WIFI"; + ctrlData.au4CtrlData[1] = (size_t) &pbuf; + ctrlData.au4CtrlData[2] = (size_t) &bufLen; + + iRet = wmt_ctrl(&ctrlData); + + if (iRet != 0) { + WMT_ERR_FUNC("MT6632: WMT_CTRL_CRYSTAL_TRIMING_GET fail:%d\n", iRet); + bIsNvramExist = MTK_WCN_BOOL_FALSE; + bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + cCrystalTimingOffset = 0x0; + cCrystalTiming = 0x0; + iRet = -1; + } else { + WMT_DBG_FUNC("MT6632: nvram pBuf(%p), bufLen(%d)\n", pbuf, bufLen); + + if (bufLen < (uCryTimOffset + 1)) { + WMT_ERR_FUNC + ("MT6632: nvram len(%d) too short, crystalTimging value offset(%d)\n", + bufLen, uCryTimOffset); + bIsNvramExist = MTK_WCN_BOOL_FALSE; + bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + cCrystalTimingOffset = 0x0; + cCrystalTiming = 0x0; + } else { + bIsNvramExist = MTK_WCN_BOOL_TRUE; + cCrystalTimingOffset = *(pbuf + uCryTimOffset); + + if (cCrystalTimingOffset & 0x80) { + bIsCrysTrimEnabled = MTK_WCN_BOOL_TRUE; + cCrystalTimingOffset = (UINT8) cCrystalTimingOffset & 0x7f; + } + + WMT_DBG_FUNC("cCrystalTimingOffset (%d), bIsCrysTrimEnabled(%d)\n", + cCrystalTimingOffset, bIsCrysTrimEnabled); + } + + ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_PUT; + ctrlData.au4CtrlData[0] = (size_t) "/data/nvram/APCFG/APRDEB/WIFI"; + iRet = wmt_ctrl(&ctrlData); + + if (iRet != 0) { + WMT_ERR_FUNC("MT6632: WMT_CTRL_CRYSTAL_TRIMING_PUT fail:%d\n", iRet); + iRet = -2; + } else { + WMT_DBG_FUNC("MT6632: WMT_CTRL_CRYSTAL_TRIMING_PUT succeed\n"); + } + } + + if ((bIsNvramExist == MTK_WCN_BOOL_TRUE) && (bIsCrysTrimEnabled == MTK_WCN_BOOL_TRUE)) { + /*get CrystalTiming value before set it */ + iRet = + wmt_core_tx(get_crystal_timing_script[0].cmd, + get_crystal_timing_script[0].cmdSz, &u4Res, MTK_WCN_BOOL_FALSE); + + if (iRet || (u4Res != get_crystal_timing_script[0].cmdSz)) { + WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", + get_crystal_timing_script[0].str, iRet, u4Res, + get_crystal_timing_script[0].cmdSz); + iRet = -3; + goto done; + } + + /* EVENT BUF */ + osal_memset(get_crystal_timing_script[0].evt, 0, + get_crystal_timing_script[0].evtSz); + iRet = + wmt_core_rx(get_crystal_timing_script[0].evt, + get_crystal_timing_script[0].evtSz, &u4Res); + + if (iRet || (u4Res != get_crystal_timing_script[0].evtSz)) { + WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", + get_crystal_timing_script[0].str, iRet, u4Res, + get_crystal_timing_script[0].evtSz); + mtk_wcn_stp_dbg_dump_package(); + iRet = -4; + goto done; + } + + iCrystalTiming = WMT_GET_CRYSTAL_TRIMING_EVT[5] & 0x7f; + + if (cCrystalTimingOffset & 0x40) { + /*nagative offset value */ + iCrystalTiming = iCrystalTiming + cCrystalTimingOffset - 128; + } else { + iCrystalTiming += cCrystalTimingOffset; + } + + WMT_DBG_FUNC("iCrystalTiming (0x%x)\n", iCrystalTiming); + if (iCrystalTiming > 0x7f) + cCrystalTiming = 0x7f; + else if (iCrystalTiming < 0) + cCrystalTiming = 0; + else + cCrystalTiming = iCrystalTiming; + WMT_DBG_FUNC("cCrystalTiming (0x%x)\n", cCrystalTiming); + /* set_crystal_timing_script */ + /*set crystal trim value command*/ + WMT_SET_CRYSTAL_TRIMING_CMD[4] = 0x1; + WMT_SET_CRYSTAL_TRIMING_EVT[4] = 0x1; + + WMT_SET_CRYSTAL_TRIMING_CMD[5] = cCrystalTiming; + WMT_GET_CRYSTAL_TRIMING_EVT[5] = cCrystalTiming; + + iRet = + wmt_core_init_script(set_crystal_timing_script, + ARRAY_SIZE(set_crystal_timing_script)); + + if (iRet) { + WMT_ERR_FUNC("set_crystal_timing_script fail(%d)\n", iRet); + iRet = -5; + } else { + WMT_DBG_FUNC("set crystal timing value (0x%x) succeed\n", + WMT_SET_CRYSTAL_TRIMING_CMD[5]); + iRet = + wmt_core_init_script(get_crystal_timing_script, + ARRAY_SIZE(get_crystal_timing_script)); + + if (iRet) { + WMT_ERR_FUNC("get_crystal_timing_script fail(%d)\n", iRet); + iRet = -6; + } else { + WMT_INFO_FUNC("succeed, updated crystal timing value (0x%x)\n", + WMT_GET_CRYSTAL_TRIMING_EVT[5]); + iRet = 0x0; + } + } + } + +done: + return iRet; +} +#endif + +static INT32 mt6632_patch_info_prepare(VOID) +{ + INT32 iRet = -1; + WMT_CTRL_DATA ctrlData; + + ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; + iRet = wmt_ctrl(&ctrlData); + + return iRet; +} + + +static INT32 mt6632_patch_dwn(UINT32 index) +{ + INT32 iRet = -1; + P_WMT_PATCH patchHdr = NULL; + PUINT8 pBuf = NULL; + PUINT8 pPatchBuf = NULL; + UINT32 patchSize; + UINT32 fragSeq; + UINT32 fragNum; + UINT16 fragSize = 0; + UINT16 cmdLen; + UINT32 offset; + UINT32 u4Res; + UINT8 evtBuf[8]; + UINT8 addressevtBuf[12]; + UINT8 addressByte[4]; + PINT8 cDataTime = NULL; + /*PINT8 cPlat = NULL; */ + UINT16 u2HwVer = 0; + UINT16 u2SwVer = 0; + UINT32 u4PatchVer = 0; + UINT32 patchSizePerFrag = 0; + WMT_CTRL_DATA ctrlData; + + /*1.check hardware information */ + if (gp_mt6632_info == NULL) { + WMT_ERR_FUNC("null gp_mt6632_info!\n"); + return -1; + } + + osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName)); + + ctrlData.ctrlId = WMT_CTRL_GET_PATCH_INFO; + ctrlData.au4CtrlData[0] = index + 1; + ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName; + ctrlData.au4CtrlData[2] = (size_t) &addressByte; + iRet = wmt_ctrl(&ctrlData); + WMT_INFO_FUNC("the %d time valid patch found: (%s)\n", index + 1, gFullPatchName); + + /* <2.2> read patch content */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH; + ctrlData.au4CtrlData[0] = (size_t) NULL; + ctrlData.au4CtrlData[1] = (size_t) &gFullPatchName; + ctrlData.au4CtrlData[2] = (size_t) &pBuf; + ctrlData.au4CtrlData[3] = (size_t) &patchSize; + iRet = wmt_ctrl(&ctrlData); + + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); + iRet -= 1; + goto done; + } + + /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ + /* patch file with header: + * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| + */ + pPatchBuf = osal_malloc(patchSize); + if (pPatchBuf == NULL) { + WMT_ERR_FUNC("vmalloc pPatchBuf for patch download fail\n"); + return -2; + } + osal_memcpy(pPatchBuf, pBuf, patchSize); + patchHdr = (P_WMT_PATCH) pPatchBuf; + + /* check patch file information */ + + cDataTime = patchHdr->ucDateTime; + u2HwVer = patchHdr->u2HwVer; + u2SwVer = patchHdr->u2SwVer; + u4PatchVer = patchHdr->u4PatchVer; + + osal_memcpy(&gp_mt6632_patch_info, patchHdr, osal_sizeof(WMT_PATCH)); + + /*cPlat = &patchHdr->ucPLat[0]; */ + + cDataTime[15] = '\0'; + + if (index == 0) { + WMT_INFO_FUNC("Combo Patch:Build Time(%s)Hw(0x%x) Sw(0x%x) Ph(0x%04x)Platform(%c%c%c%c)\n", + cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8), + ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8), + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16), + patchHdr->ucPLat[0], patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + } + + /* remove patch header: + * |<-patch body: X Bytes (X=patchSize)--->| + */ + if (patchSize < sizeof(WMT_PATCH)) { + WMT_ERR_FUNC("error patch size\n"); + iRet = -1; + goto done; + } + patchSize -= sizeof(WMT_PATCH); + pPatchBuf += sizeof(WMT_PATCH); + patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; + + /* remove patch checksum, MT6632 no need: + * |<-patch checksum: 2Bytes->|<-patch body: X Bytes (X=patchSize)--->| + */ + pPatchBuf += BCNT_PATCH_BUF_CHECKSUM; + patchSize -= BCNT_PATCH_BUF_CHECKSUM; + + /* reserve 1st patch cmd space before patch body + * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| + */ + pPatchBuf -= sizeof(WMT_PATCH_CMD); + + fragNum = patchSize / patchSizePerFrag; + fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; + + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + /*send patch address command */ + osal_memcpy(&WMT_PATCH_ADDRESS_CMD[5], addressByte, osal_sizeof(addressByte)); + WMT_INFO_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x", + WMT_PATCH_ADDRESS_CMD[5], WMT_PATCH_ADDRESS_CMD[6], + WMT_PATCH_ADDRESS_CMD[7], WMT_PATCH_ADDRESS_CMD[8]); + iRet = wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD[0], sizeof(WMT_PATCH_ADDRESS_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD))) { + WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d),index(%d)\n", + iRet, u4Res, index); + iRet -= 1; + goto done; + } + + osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); + iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT), &u4Res); + + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT))) { + WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d),index(%d)\n", iRet, + u4Res, index); + mtk_wcn_stp_dbg_dump_package(); + iRet -= 1; + goto done; + } +#if CFG_CHECK_WMT_RESULT + + if (osal_memcmp(addressevtBuf, WMT_PATCH_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) + != 0) { + WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail,index(%d)\n", + index); + iRet -= 1; + goto done; + } +#endif + + /* send all fragments */ + offset = sizeof(WMT_PATCH_CMD); + fragSeq = 0; + + while (fragSeq < fragNum) { + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + if (fragSeq == (fragNum - 1)) { + /* last fragment */ + fragSize = patchSize - fragSeq * patchSizePerFrag; + WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; + } else { + fragSize = patchSizePerFrag; + WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; + } + + /* update length field in CMD:flag+frag */ + cmdLen = 1 + fragSize; + osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); + /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ + osal_memcpy(pPatchBuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, + sizeof(WMT_PATCH_CMD)); + + iRet = + wmt_core_tx(pPatchBuf + offset - sizeof(WMT_PATCH_CMD), + fragSize + sizeof(WMT_PATCH_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + + if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) fail(%d)\n", fragSeq, + fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); + iRet -= 1; + break; + } + + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%zu, %d) ok\n", + fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); + + osal_memset(evtBuf, 0, sizeof(evtBuf)); + /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ + iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); + + if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) fail(%d)\n", + sizeof(WMT_PATCH_EVT), u4Res, iRet); + mtk_wcn_stp_dbg_dump_package(); + iRet -= 1; + break; + } +#if CFG_CHECK_WMT_RESULT + + if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { + WMT_ERR_FUNC("rx(%d):[%02X,%02X,%02X,%02X,%02X] exp(%zu):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + sizeof(WMT_PATCH_EVT), WMT_PATCH_EVT[0], WMT_PATCH_EVT[1], + WMT_PATCH_EVT[2], WMT_PATCH_EVT[3], WMT_PATCH_EVT[4]); + iRet -= 1; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%zu, %d) ok\n", + sizeof(WMT_PATCH_EVT), u4Res); + offset += patchSizePerFrag; + ++fragSeq; + } + + WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", + iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); + + if (fragSeq != fragNum) + iRet -= 1; + +done: + if (patchHdr != NULL) { + osal_free(patchHdr); + pPatchBuf = NULL; + patchHdr = NULL; + } + + /* WMT_CTRL_FREE_PATCH always return 0 */ + /* wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); */ + ctrlData.ctrlId = WMT_CTRL_FREE_PATCH; + ctrlData.au4CtrlData[0] = index + 1; + wmt_ctrl(&ctrlData); + + return iRet; +} + +#if CFG_WMT_FILTER_MODE_SETTING +static INT32 wmt_stp_wifi_lte_coex(VOID) +{ + INT32 iRet; + ULONG addr = 0; + WMT_GEN_CONF *pWmtGenConf; + + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + if (pWmtGenConf->coex_wmt_filter_mode == 0) { + iRet = + wmt_core_init_script(set_wifi_lte_coex_table_0, + ARRAY_SIZE(set_wifi_lte_coex_table_0)); + if (iRet) + WMT_ERR_FUNC("wmt_core:set_wifi_lte_coex_table_0 fail(%d)\n", iRet); + else + WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_0 ok\n"); + } + + return iRet; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_soc.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_soc.c new file mode 100644 index 00000000000000..8ab25e984defd3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_ic_soc.c @@ -0,0 +1,4102 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-IC]" +#define CFG_IC_SOC 1 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "wmt_ic.h" +#include "wmt_core.h" +#include "wmt_lib.h" +#include "stp_core.h" +#include "mtk_wcn_consys_hw.h" +#include "wmt_step.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define DEFAULT_PATCH_FRAG_SIZE (1000) +#define WMT_PATCH_FRAG_1ST (0x1) +#define WMT_PATCH_FRAG_MID (0x2) +#define WMT_PATCH_FRAG_LAST (0x3) + +#define CFG_CHECK_WMT_RESULT (1) +/* BT Port 2 Feature. this command does not need + * after coex command is downconfirmed by LC, + */ +#define CFG_WMT_BT_PORT2 (0) + +#define CFG_SET_OPT_REG (0) +#define CFG_WMT_I2S_DBGUART_SUPPORT (0) +#define CFG_SET_OPT_REG_SWLA (0) +#define CFG_SET_OPT_REG_MCUCLK (0) +#define CFG_SET_OPT_REG_MCUIRQ (0) + +#define CFG_SUBSYS_COEX_NEED 0 + +#define CFG_WMT_COREDUMP_ENABLE 0 + +#define CFG_WMT_MULTI_PATCH (1) + +#define CFG_WMT_CRYSTAL_TIMING_SET (0) + +#define CFG_WMT_SDIO_DRIVING_SET (0) + +#define CFG_WMT_UART_HIF_USE (0) + +#define CFG_WMT_WIFI_5G_SUPPORT (1) + +#define CFG_WMT_PATCH_DL_OPTM (1) +#if CFG_WMT_LTE_COEX_HANDLING +#define CFG_WMT_FILTER_MODE_SETTING (1) +#else +#define CFG_WMT_FILTER_MODE_SETTING (0) +#endif +/* #define MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT (0) */ + +#define CFG_WMT_POWER_ON_DLM (1) + +/* Define local option for debug purpose */ +#define CFG_CALIBRATION_BACKUP_RESTORE (1) +#define CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE (640) + +#define PATCH_BUILD_TIME_SIZE (16) +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +static UINT8 gFullPatchName[NAME_MAX + 1]; +static const WMT_IC_INFO_S *gp_soc_info; +static WMT_PATCH gp_soc_patch_info; +static WMT_CO_CLOCK gCoClockEn = WMT_CO_CLOCK_DIS; + +#if CFG_CALIBRATION_BACKUP_RESTORE +static PUINT8 gBTCalResult; +static UINT16 gBTCalResultSize; +static UINT32 gWiFiCalAddrOffset; +static UINT32 gWiFiCalSize; +static PUINT8 gWiFiCalResult; +#endif + +#if 0 +static UINT8 WMT_WAKEUP_DIS_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x04 }; +static UINT8 WMT_WAKEUP_DIS_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x04 }; + +static UINT8 WMT_WAKEUP_EN_GATE_CMD[] = { 0x1, 0x3, 0x01, 0x00, 0x05 }; +static UINT8 WMT_WAKEUP_EN_GATE_EVT[] = { 0x2, 0x3, 0x02, 0x0, 0x0, 0x05 }; +#endif + +#if CFG_WMT_UART_HIF_USE +static UINT8 WMT_QUERY_BAUD_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x02 }; +static UINT8 WMT_QUERY_BAUD_EVT_115200[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0x00, 0xC2, 0x01, 0x00 }; +static UINT8 WMT_QUERY_BAUD_EVT_X[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x02, 0xAA, 0xAA, 0xAA, 0xBB }; +static UINT8 WMT_SET_BAUD_CMD_X[] = { 0x01, 0x04, 0x05, 0x00, 0x01, 0xAA, 0xAA, 0xAA, 0xBB }; +static UINT8 WMT_SET_BAUD_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x01 }; +static UINT8 WMT_SET_WAKEUP_WAKE_CMD_RAW[] = { 0xFF }; +static UINT8 WMT_SET_WAKEUP_WAKE_EVT[] = { 0x02, 0x03, 0x02, 0x00, 0x00, 0x03 }; +#endif +static UINT8 WMT_QUERY_STP_CMD[] = { 0x01, 0x04, 0x01, 0x00, 0x04 }; +static UINT8 WMT_QUERY_STP_EVT_DEFAULT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, 0x00 }; +static UINT8 WMT_QUERY_STP_EVT[] = { 0x02, 0x04, 0x06, 0x00, 0x00, 0x04, 0xDB, 0x0E, 0x68, 0x01 }; +static UINT8 WMT_PATCH_CMD[] = { 0x01, 0x01, 0x00, 0x00, 0x00 }; +static UINT8 WMT_PATCH_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00 }; +static UINT8 WMT_RESET_CMD[] = { 0x01, 0x07, 0x01, 0x00, 0x04 }; +static UINT8 WMT_RESET_EVT[] = { 0x02, 0x07, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_SET_CHIP_ID_CMD[] = { 0x01, 0x02, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00 }; +static UINT8 WMT_SET_CHIP_ID_EVT[] = { 0x02, 0x02, 0x01, 0x00, 0x00}; + +#if CFG_WMT_BT_PORT2 +static UINT8 WMT_BTP2_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x01, 0x03, 0x01 }; +static UINT8 WMT_BTP2_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#endif + +static UINT8 WMT_QUERY_A_DIE_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x12 }; +static UINT8 WMT_QUERY_A_DIE_EVT[] = { 0x02, 0x02, 0x05, 0x00, 0x00 }; + +/*soc patial patch address cmd & evt need firmware owner provide*/ +#if CFG_WMT_MULTI_PATCH +static UINT8 WMT_PATCH_ADDRESS_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x3c, 0x02, 0x09, 0x02, + 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_PATCH_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +static UINT8 WMT_PATCH_P_ADDRESS_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0xc4, 0x04, 0x09, 0x02, + 0x00, 0x3f, 0x00, 0x01, + 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_PATCH_P_ADDRESS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +static UINT8 WMT_PATCH_PDA_CFG_CMD[] = { + 0x01, 0x01, 0x11, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, /*Target address*/ + 0x00, 0x00, 0x00, 0x00, /*Download size*/ + 0x00, 0x00, 0x00, 0x00, /*Scramble key*/ + 0x2f, 0x02, 0x02, 0x00 /*Configuration*/ +}; +static UINT8 WMT_PATCH_PDA_CFG_EVT[] = { 0x02, 0x01, 0x01, 0x00, 0x00}; + +static UINT8 WMT_PATCH_ADDRESS_CMD_NEW[] = { 0x01, 0x01, 0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00}; + +static UINT8 WMT_PATCH_ADDRESS_EVT_NEW[] = { 0x02, 0x01, 0x01, 0x00, 0x00}; +#endif + +/*coex cmd/evt++*/ +static UINT8 WMT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x01, 0x00 }; +static UINT8 WMT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +#if CFG_SUBSYS_COEX_NEED +static UINT8 WMT_BT_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0B, + 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, + 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA +}; +static UINT8 WMT_BT_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0C, + 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xAA +}; +static UINT8 WMT_WIFI_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_PTA_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x0A, + 0x00, 0x04, + 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xEE, 0xFF, 0xFF, 0xFE +}; +static UINT8 WMT_PTA_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_MISC_COEX_SETTING_CONFIG_CMD[] = { 0x01, 0x10, 0x09, + 0x00, 0x05, + 0xAA, 0xAA, 0xAA, 0xAA, + 0xBB, 0xBB, 0xBB, 0xBB +}; +static UINT8 WMT_MISC_COEX_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#else +static UINT8 WMT_COEX_WIFI_PATH_CMD[] = { 0x01, 0x10, 0x03, 0x00, 0x1A, 0x0F, 0x00 }; +static UINT8 WMT_COEX_WIFI_PATH_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_COEX_EXT_ELAN_GAIN_P1_CMD[] = { 0x01, 0x10, 0x12, 0x00, 0x1B, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static UINT8 WMT_COEX_EXT_ELAN_GAIN_P1_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_COEX_EXT_EPA_MODE_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x1D, 0x00 }; +static UINT8 WMT_COEX_EXT_EPA_MODE_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; +#endif + +static UINT8 WMT_EPA_SETTING_CONFIG_CMD[] = { 0x01, 0x02, 0x02, 0x00, 0x0E, 0x00 }; +static UINT8 WMT_EPA_SETTING_CONFIG_EVT[] = { 0x02, 0x02, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_EPA_ELNA_SETTING_CONFIG_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +/*coex cmd/evt--*/ +static UINT8 WMT_SET_STP_CMD[] = { 0x01, 0x04, 0x05, 0x00, 0x03, 0xDB, 0x0E, 0x68, 0x01 }; +static UINT8 WMT_SET_STP_EVT[] = { 0x02, 0x04, 0x02, 0x00, 0x00, 0x03 }; +static UINT8 WMT_STRAP_CONF_CMD_FM_COMM[] = { 0x01, 0x05, 0x02, 0x00, 0x02, 0x02 }; +static UINT8 WMT_STRAP_CONF_EVT[] = { 0x02, 0x05, 0x02, 0x00, 0x00, 0x02 }; + +#if 0 +static UINT8 WMT_SET_OSC32K_BYPASS_CMD[] = { 0x01, 0x0A, 0x01, 0x00, 0x05 }; +static UINT8 WMT_SET_OSC32K_BYPASS_EVT[] = { 0x02, 0x0A, 0x01, 0x00, 0x00 }; +#endif + +#if 0 +/* to enable dump feature */ +static UINT8 WMT_CORE_DUMP_EN_CMD[] = { 0x01, 0x0F, 0x02, 0x00, 0x03, 0x01 }; +static UINT8 WMT_CORE_DUMP_EN_EVT[] = { 0x02, 0x0F, 0x01, 0x00, 0x00 }; + +/* to get system stack dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_01_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UINT8 WMT_CORE_DUMP_LEVEL_01_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; + +/* to get task and system stack dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_02_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UINT8 WMT_CORE_DUMP_LEVEL_02_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; + +/* to get bt related memory dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_03_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x03, 0x00, 0x00, 0x09, 0xF0, 0x00, 0x0A }; +static UINT8 WMT_CORE_DUMP_LEVEL_03_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; +#endif +/* to get full dump when f/w assert */ +static UINT8 WMT_CORE_DUMP_LEVEL_04_CMD[] = { 0x1, 0x0F, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static UINT8 WMT_CORE_DUMP_LEVEL_04_EVT[] = { 0x2, 0x0F, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_CORE_CO_CLOCK_CMD[] = { 0x1, 0x0A, 0x02, 0x00, 0x08, 0x03 }; +static UINT8 WMT_CORE_CO_CLOCK_EVT[] = { 0x2, 0x0A, 0x01, 0x00, 0x00 }; + +static UINT8 WMT_CORE_START_RF_CALIBRATION_CMD[] = { 0x1, 0x14, 0x1, 0x00, 0x01 }; +static UINT8 WMT_CORE_START_RF_CALIBRATION_EVT[] = { 0x2, 0x14, 0x02, 0x00, 0x00, 0x01 }; + +#if CFG_CALIBRATION_BACKUP_RESTORE +static UINT8 WMT_CORE_GET_RF_CALIBRATION_CMD[] = { 0x1, 0x14, 0x01, 0x00, 0x03 }; +/* byte[2] & byte[3] is left for length */ +static UINT8 WMT_CORE_SEND_RF_CALIBRATION_CMD[] = { 0x1, 0x14, 0x00, 0x00, 0x02, 0x00, 0x00 }; +static UINT8 WMT_CORE_SEND_RF_CALIBRATION_EVT_OK[] = { 0x2, 0x14, 0x02, 0x00, 0x00, 0x02 }; +static UINT8 WMT_CORE_SEND_RF_CALIBRATION_EVT_RECAL[] = { 0x2, 0x14, 0x02, 0x00, 0x01, 0x02 }; +#endif + +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) +static UINT8 WMT_SET_I2S_SLAVE_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x78, 0x00, 0x05, 0x80 /*addr:0x80050078 */ + , 0x00, 0x00, 0x11, 0x01 /*value:0x11010000 */ + , 0x00, 0x00, 0x77, 0x07 /*mask:0x07770000 */ +}; + +static UINT8 WMT_SET_I2S_SLAVE_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; + +static UINT8 WMT_SET_DAI_TO_PAD_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x74, 0x00, 0x05, 0x80 /*addr:0x80050074 */ + , 0x44, 0x44, 0x00, 0x00 /*value:0x11010000 */ + , 0x77, 0x77, 0x00, 0x00 /*mask:0x07770000 */ +}; + +static UINT8 WMT_SET_DAI_TO_PAD_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; + +static UINT8 WMT_SET_DAI_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0xA0, 0x00, 0x05, 0x80 /*addr:0x80050074 */ + , 0x04, 0x00, 0x00, 0x00 /*value:0x11010000 */ + , 0x04, 0x00, 0x00, 0x00 /*mask:0x07770000 */ +}; + +static UINT8 WMT_SET_DAI_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; +#endif + +#if !(CFG_IC_SOC) /* For MT6628 no need to set ALLEINT registers, done in f/w */ +/* enable all interrupt */ +static UINT8 WMT_SET_ALLINT_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x00, 0x03, 0x05, 0x80 /*addr:0x80050300 */ + , 0x00, 0xC4, 0x00, 0x00 /*value:0x0000C400 */ + , 0x00, 0xC4, 0x00, 0x00 /*mask:0x0000C400 */ +}; + +static UINT8 WMT_SET_ALLINT_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; + +#endif + +#if CFG_SET_OPT_REG_SWLA /* enable swla: eesk(7) eecs(8) oscen(19) sck0(24) scs0(25) */ +static UINT8 WMT_SET_SWLA_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ + , 0x10, 0x01, 0x05, 0x80 /*addr:0x80050110 */ + , 0x10, 0x10, 0x01, 0x00 /*value:0x00011010 */ + , 0xF0, 0xF0, 0x0F, 0x00 /*mask:0x000FF0F0 */ + , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ + , 0x00, 0x10, 0x01, 0x00 /*value:0x00011000 */ + , 0x00, 0xF0, 0x0F, 0x00 /*mask:0x000FF000 */ +}; + +static UINT8 WMT_SET_SWLA_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ +}; +#endif + +#if CFG_SET_OPT_REG_MCUCLK /* enable mcu clk: antsel_4, eedi */ +static UINT8 WMT_SET_MCUCLK_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000 0400 */ + , 0x00, 0x14, 0x00, 0x00 /* value:0x0000 1400(osc, hclk), 0x0000 1501(PLL, en) */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005 0180 */ + , 0x12, 0x13, 0x00, 0x00 /* value:0x0000 1312(osc, hclk), 0x0000 1a19(PLL, en) */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000 FFFF */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005 0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002 0000 */ + , 0x00, 0x00, 0x0F, 0x00 /* mask:0x000F 0000 */ + , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005 0110 */ + , 0x02, 0x00, 0x00, 0x00 /* value:0x0000 0002 */ + , 0x0F, 0x00, 0x00, 0x00 /* mask:0x0000 000F */ +}; + +static UINT8 WMT_SET_MCUCLK_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ +}; +#endif + +#if CFG_WMT_I2S_DBGUART_SUPPORT /* register write for debug uart */ +static UINT8 WMT_SET_DBGUART_REG_CMD[] = { 0x01, 0x08, 0x1C, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ + , 0x30, 0x01, 0x05, 0x80 /*addr:0x80050130 */ + , 0x00, 0x00, 0x00, 0x00 /*value:0x00000000 */ + , 0xF0, 0x0F, 0x00, 0x00 /*mask:0x00000FF0 */ + , 0x40, 0x01, 0x05, 0x80 /*addr:0x80050140 */ + , 0x00, 0x01, 0x00, 0x00 /*value:0x00000100 */ + , 0x00, 0x01, 0x00, 0x00 /*mask:0x00000100 */ +}; + +static UINT8 WMT_SET_DBGUART_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x02 /*2 registers */ +}; +#endif + +#if CFG_SET_OPT_REG_MCUIRQ /* enable mcu irq: antsel_4, wlan_act */ +#if 1 /* Ray */ +static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 4), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 4 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ + , 0x03, 0x14, 0x00, 0x00 /* value:0x0000_1403 check confg debug flag 3 low word */ + , 0xFF, 0xFF, 0x00, 0x00 /* mask:0x0000_FFFF */ + /* cirq_int_n */ + , 0x10, 0x01, 0x05, 0x80 /* addr:0x8005_0110 */ + , 0x02, 0x00, 0x00, 0x00 /* value:0x0000_0002 set EEDI as cirq_int_n debug flag (monitor flag2) */ + , 0x07, 0x00, 0x00, 0x00 /* mask:0x0000_0007 */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0, ahb_x2_gt_ck debug flag) */ + , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ + /* 1. ARM irq_b, monitor flag 0 */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ + , 0x1F, 0x1E, 0x00, 0x00 /* value:0x0000_1E1F check mcusys debug flag */ + , 0x7F, 0x7F, 0x00, 0x00 /* mask:0x0000_7F7F */ +}; + +static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x04 /* 5 registers */ +}; +#elif 0 /* KC */ +static UINT8 WMT_SET_MCUIRQ_REG_CMD[] = { 0x01, 0x08, (4 + 12 * 5), 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /* type: reg */ + , 0x00 /* rev */ + , 0x05 /* 5 registers */ + , 0x00, 0x04, 0x00, 0x80 /* addr:0x8000_0400 */ + , 0x00, 0x02, 0x00, 0x00 /* value:0x0000_0200 [15:8]=0x2 arm irq_b, 0xA irq_bus[5] bt_timcon_irq_b */ + , 0x00, 0xFF, 0x00, 0x00 /* mask:0x0000_FF00 */ + /* 1. ARM irq_b, monitor flag 0 */ + , 0x80, 0x01, 0x05, 0x80 /* addr:0x8005_0180 */ + , 0x18, 0x00, 0x00, 0x00 /* value:0x0000_0018 [6:0]=001_1000 (monitor flag 0 select, MCUSYS, SEL:8) */ + , 0x7F, 0x00, 0x00, 0x00 /* mask:0x0000_007F */ + , 0x00, 0x01, 0x05, 0x80 /* addr:0x8005_0100 */ + , 0x00, 0x00, 0x02, 0x00 /* value:0x0002_0000 (ANTSEL4=>monitor flag 0) */ + , 0x00, 0x00, 0x07, 0x00 /* mask:0x0007_0000 */ + /* 2. irq_bus[5] bt_timcon_irq_b monitor flag 15 */ + , 0xB0, 0x01, 0x05, 0x80 /* addr:0x8005_01B0 */ + , 0x00, 0x00, 0x00, 0x16 /* value:0x1600_0000 [30:24]=001_0110 (monitor flag 15 select, MCUSYS, SEL:6) */ + , 0x00, 0x00, 0x00, 0x7F /* mask:0x7F00_0000 */ + , 0x30, 0x01, 0x05, 0x80 /* addr:0x8005_0130 */ + , 0x00, 0x20, 0x00, 0x00 /* value:0x0000_2000 (WLAN_ACT=>monitor flag 15) */ + , 0x00, 0x70, 0x00, 0x00 /* mask:0x0000_7000 */ +}; + +static UINT8 WMT_SET_MCUIRQ_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /* S: 0 */ + , 0x00 /* type: reg */ + , 0x00 /* rev */ + , 0x05 /* 5 registers */ +}; +#endif +#endif + +#if CFG_WMT_CRYSTAL_TIMING_SET +static UINT8 WMT_SET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x01, 0x00 }; +static UINT8 WMT_SET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x01, 0x00 }; + +static UINT8 WMT_GET_CRYSTAL_TRIMING_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x00, 0x00 }; +static UINT8 WMT_GET_CRYSTAL_TRIMING_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x00, 0x00 }; +#endif + +#ifdef CFG_WMT_READ_EFUSE_VCN33 +static UINT8 WMT_GET_EFUSE_VCN33_CMD[] = { 0x01, 0x12, 0x02, 0x00, 0x04, 0x00 }; +static UINT8 WMT_GET_EFUSE_VCN33_EVT[] = { 0x02, 0x12, 0x02, 0x00, 0x04, 0x00 }; +#endif + +/* set sdio driving */ +#if CFG_WMT_SDIO_DRIVING_SET +static UINT8 WMT_SET_SDIO_DRV_REG_CMD[] = { 0x01, 0x08, 0x10, 0x00 /*length */ + , 0x01 /* op: w */ + , 0x01 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ + , 0x50, 0x00, 0x05, 0x80 /*addr:0x80050050 */ + , 0x44, 0x44, 0x04, 0x00 /*value:0x00044444 */ + , 0x77, 0x77, 0x07, 0x00 /*mask:0x00077777 */ +}; + +static UINT8 WMT_SET_SDIO_DRV_REG_EVT[] = { 0x02, 0x08, 0x04, 0x00 /*length */ + , 0x00 /*S: 0 */ + , 0x00 /*type: reg */ + , 0x00 /*rev */ + , 0x01 /*1 registers */ +}; +#endif + +#if CFG_WMT_WIFI_5G_SUPPORT +static UINT8 WMT_GET_SOC_ADIE_CHIPID_CMD[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x24, 0x00 }; +static UINT8 WMT_GET_SOC_ADIE_CHIPID_EVT[] = { + 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static UINT8 WMT_GET_SOC_6625_L_CMD[] = { 0x01, 0x13, 0x04, 0x00, 0x02, 0x04, 0x20, 0x01 }; +static UINT8 WMT_GET_SOC_6625_L_EVT[] = { + 0x02, 0x13, 0x09, 0x00, 0x00, 0x02, 0x04, 0x20, + 0x01, 0x00, 0x00, 0x00, 0x00 +}; +#endif + +#if CFG_WMT_PATCH_DL_OPTM +static UINT8 WMT_SET_MCU_CLK_EN_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x34, 0x03, 0x00, 0x80, + 0x00, 0x00, 0x01, 0x00, + 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_SET_MCU_CLK_EN_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +static UINT8 WMT_SET_MCU_CLK_138_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x0c, 0x01, 0x00, 0x80, + 0x59, 0x4d, 0x84, 0x00, + 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_SET_MCU_CLK_138_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +static UINT8 WMT_SET_MCU_CLK_26_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x0c, 0x01, 0x00, 0x80, + 0x00, 0x4d, 0x84, 0x00, + 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_SET_MCU_CLK_26_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +static UINT8 WMT_SET_MCU_CLK_DIS_CMD[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x34, 0x03, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff +}; +static UINT8 WMT_SET_MCU_CLK_DIS_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; + +/*only for 6797,enable high clock frequency*/ +/*CLK EN*/ +static UINT8 WMT_SET_MCU_CLK_EN_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x10, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x10 +}; +/*RATIO SET*/ +static UINT8 WMT_SET_MCU_RATIO_SET_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x0c, 0x01, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00 +}; +/*DIV SET*/ +static UINT8 WMT_SET_MCU_DIV_SET_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x18, 0x11, 0x02, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x3f, 0x00, 0x00, 0x00 +}; +/*HCLK SET*/ +static UINT8 WMT_SET_MCU_HCLK_SET_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x00, 0x11, 0x02, 0x81, 0x04, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00 +}; + +/*Change clock to 26MHz*/ +/*HCLK DIS*/ +static UINT8 WMT_SET_MCU_HCLK_DIS_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x00, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00 +}; +/*RATIO DIS*/ +static UINT8 WMT_SET_MCU_RATIO_DIS_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x0c, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00 +}; +/*CLK DIS*/ +static UINT8 WMT_SET_MCU_CLK_DIS_6797[] = { + 0x01, 0x08, 0x10, 0x00, 0x01, 0x01, 0x00, 0x01, + 0x10, 0x11, 0x02, 0x81, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10 +}; + +static UINT8 WMT_SET_MCU_CLK_EVT_6797[] = { + 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 +}; + +#endif + + +static UINT8 WMT_COEX_CONFIG_BT_CTRL_CMD[] = { + 0x01, 0x10, 0x04, 0x00, 0x1A, 0x00, 0x00, 0x00 }; +static UINT8 WMT_COEX_CONFIG_ADDJUST_OPP_TIME_RATIO_CMD[] = { + 0x01, 0x10, 0x04, 0x00, 0x1B, 0x00, 0x00, 0x00 }; +static UINT8 WMT_COEX_CONFIG_ADDJUST_BLE_SCAN_TIME_RATIO_CMD[] = { + 0x01, 0x10, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00 }; + +static UINT8 WMT_COEX_SPLIT_MODE_EVT[] = { 0x02, 0x10, 0x01, 0x00, 0x00 }; + +#if CFG_WMT_FILTER_MODE_SETTING +static UINT8 WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x14, 0x00 }; +static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = { + 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, + 0x00, 0x11, 0x11, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x63, 0x63, 0x63, 0x00, 0x39, 0x43, 0x63, + 0x63, 0x02, 0x02, 0x03, 0x00, 0x01, 0x01, 0x01, + 0x01, 0x0e, 0x0e, 0x0e, 0x00, 0x0a, 0x0c, 0x0e, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD[] = { + 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15, + 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xd4, + 0x09, 0xe3, 0x09, 0x5a, 0x0a, 0x14, 0x09, 0x2d, + 0x09, 0x46, 0x09, 0x60, 0x09, 0xd3, 0x09, 0xe2, + 0x09, 0x59, 0x0a, 0x8B, 0x0a}; +static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 }; +static UINT8 WMT_COEX_IS_LTE_L_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x21, 0x01 }; + +#if 0 +static UINT8 WMT_COEX_SPLIT_FILTER_CMD_TEST[] = { + 0x01, 0x10, 0x19, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x00, 0x6c, 0x09, 0x8a, 0x09, 0x8a, 0x09, 0x9e, + 0x09, 0x01, 0x07, 0x07, 0x0b, 0x07, 0x07, 0x00, + 0x32, 0x27, 0x4e, 0x27, 0x32 +}; + +static UINT8 WMT_COEX_FILTER_SPEC_CMD_TEST[] = { + 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, + 0x00, 0x07, 0x07, 0x07, 0x54, 0x54, 0x00, 0x00, + 0x00, 0x50, 0x50, 0x50, 0x54, 0x54, 0x39, 0x39, + 0x39, 0x02, 0x02, 0x02, 0x0e, 0x0e, 0x01, 0x01, + 0x01, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0a, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 +}; + +static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_TEST[] = { + 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15, + 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xdd, + 0x09, 0xf6, 0x09, 0x0f, 0xaf, 0x14, 0x09, 0x2d, + 0x09, 0x46, 0x09, 0x5f, 0x09, 0xdd, 0x09, 0xf5, + 0x09, 0x0d, 0x0a, 0x27, 0x0a +}; +static UINT8 WMT_COEX_LTE_CHAN_UNSAFE_CMD_TEST[] = { 0x01, 0x10, 0x02, 0x00, 0x13, 0x00 }; +static UINT8 WMT_COEX_EXT_COMPONENT_CMD_TEST[] = { 0x01, 0x10, 0x03, 0x00, 0x0d, 0x7f, 0x03 }; +#endif + +static UINT8 WMT_COEX_FILTER_SPEC_CMD_0[] = { + 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, + 0x00, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, + 0x00, 0x63, 0x63, 0x63, 0x63, 0x3c, 0x3c, 0x3c, + 0x3c, 0x04, 0x04, 0x04, 0x04, 0x01, 0x01, 0x01, + 0x01, 0x0e, 0x0e, 0x0e, 0x0e, 0x0b, 0x0b, 0x0b, + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 +}; + +static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_0[] = { + 0x01, 0x10, 0x21, 0x00, 0x12, 0xfc, 0x08, 0x15, + 0x09, 0x2e, 0x09, 0x47, 0x09, 0xc4, 0x09, 0xdd, + 0x09, 0xf6, 0x09, 0x0f, 0x0a, 0x14, 0x09, 0x2d, + 0x09, 0x46, 0x09, 0x5f, 0x09, 0xdd, 0x09, 0xf5, + 0x09, 0x0d, 0x0a, 0x27, 0x0a +}; +static UINT8 WMT_COEX_IS_LTE_PROJ_CMD[] = { 0x01, 0x10, 0x02, 0x00, 0x15, 0x01 }; + +static UINT8 WMT_COEX_FILTER_SPEC_CMD_6752[] = { + 0x01, 0x10, 0x45, 0x00, 0x11, 0x00, 0x00, 0x01, + 0x00, 0x11, 0x11, 0x16, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x63, 0x63, 0x63, 0x00, 0x39, 0x43, 0x63, + 0x63, 0x02, 0x02, 0x03, 0x00, 0x01, 0x01, 0x01, + 0x01, 0x0E, 0x0E, 0x0E, 0x00, 0x0A, 0x0C, 0x0E, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 +}; + +static UINT8 WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_6752[] = { + 0x01, 0x10, 0x21, 0x00, 0x12, 0xFC, 0x08, 0x15, + 0x09, 0x2E, 0x09, 0x47, 0x09, 0xC4, 0x09, 0xD4, + 0x09, 0xE3, 0x09, 0x5A, 0x0A, 0x14, 0x09, 0x2D, + 0x09, 0x46, 0x09, 0x60, 0x09, 0xD3, 0x09, 0xE2, + 0x09, 0x59, 0x0A, 0x8B, 0x0A +}; +#endif + +static UINT8 WMT_BT_TSSI_FROM_WIFI_CONFIG_CMD[] = { + 0x01, 0x02, 0x04, 0x00, 0x0D, 0x01, 0x1E, 0x00 +}; + +static UINT8 WMT_BT_TSSI_FROM_WIFI_EVENT[] = { + 0x02, 0x02, 0x01, 0x00, 0x00 +}; + +#if CFG_WMT_POWER_ON_DLM +static UINT8 WMT_POWER_CTRL_DLM_CMD1[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x60, 0x00, 0x10, 0x80, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x00, 0x00 +}; + +static UINT8 WMT_POWER_CTRL_DLM_CMD2[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x60, 0x00, 0x10, 0x80, + 0x00, 0x00, 0x00, 0x00, + 0xf0, 0x00, 0x00, 0x00 +}; + +static UINT8 WMT_POWER_CTRL_DLM_CMD3[] = { + 0x01, 0x08, 0x10, 0x00, + 0x01, 0x01, 0x00, 0x01, + 0x60, 0x00, 0x10, 0x80, + 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00 +}; +static UINT8 WMT_POWER_CTRL_DLM_EVT[] = { 0x02, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01 }; +#endif + +static UINT8 WMT_WIFI_ANT_SWAP_CMD[] = { 0x01, 0x14, 0x04, 0x00, 0x07, 0x02, 0x00, 0x00 }; +static UINT8 WMT_WIFI_ANT_SWAP_EVT[] = { 0x02, 0x14, 0x02, 0x00, 0x00, 0x07 }; + +#if (!CFG_IC_SOC) + +/* stp sdio init scripts */ +static struct init_script init_table_1_1[] = { + /* table_1_1 is only applied to common SDIO interface */ + INIT_CMD(WMT_SET_ALLINT_REG_CMD, WMT_SET_ALLINT_REG_EVT, "enable all interrupt"), + /* applied to MT6628 ? */ + INIT_CMD(WMT_WAKEUP_DIS_GATE_CMD, WMT_WAKEUP_DIS_GATE_EVT, "disable gating"), +}; + +#endif + +static struct init_script init_table_1_2[] = { + INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT_DEFAULT, "query stp default"), +}; + +#if CFG_WMT_UART_HIF_USE +static struct init_script init_table_2[] = { + INIT_CMD(WMT_QUERY_BAUD_CMD, WMT_QUERY_BAUD_EVT_X, "query baud X"), +}; +#endif + +static struct init_script init_table_3[] = { + INIT_CMD(WMT_RESET_CMD, WMT_RESET_EVT, "wmt reset"), +#if CFG_WMT_BT_PORT2 + INIT_CMD(WMT_BTP2_CMD, WMT_BTP2_EVT, "set bt port2"), +#endif +}; + +static struct init_script set_chipid_script[] = { + INIT_CMD(WMT_SET_CHIP_ID_CMD, WMT_SET_CHIP_ID_EVT, "wmt set chipid"), +}; + +#if CFG_WMT_CRYSTAL_TIMING_SET +static struct init_script set_crystal_timing_script[] = { + INIT_CMD(WMT_SET_CRYSTAL_TRIMING_CMD, WMT_SET_CRYSTAL_TRIMING_EVT, "set crystal trim value"), +}; + +static struct init_script get_crystal_timing_script[] = { + INIT_CMD(WMT_GET_CRYSTAL_TRIMING_CMD, WMT_GET_CRYSTAL_TRIMING_EVT, "get crystal trim value"), +}; +#endif +#ifdef CFG_WMT_READ_EFUSE_VCN33 +static struct init_script get_efuse_vcn33_script[] = { + INIT_CMD(WMT_GET_EFUSE_VCN33_CMD, WMT_GET_EFUSE_VCN33_EVT, "get efuse vcn33 value"), +}; +#endif + +static struct init_script get_a_die_script[] = { + INIT_CMD(WMT_QUERY_A_DIE_CMD, WMT_QUERY_A_DIE_EVT, "query A-die"), +}; + +static struct init_script init_table_4[] = { + INIT_CMD(WMT_SET_STP_CMD, WMT_SET_STP_EVT, "set stp"), +}; + +static struct init_script init_table_5[] = { + INIT_CMD(WMT_QUERY_STP_CMD, WMT_QUERY_STP_EVT, "query stp"), +}; + +static struct init_script init_table_5_1[] = { + INIT_CMD(WMT_STRAP_CONF_CMD_FM_COMM, WMT_STRAP_CONF_EVT, "configure FM comm"), +}; + +static struct init_script init_table_6[] = { + INIT_CMD(WMT_CORE_DUMP_LEVEL_04_CMD, WMT_CORE_DUMP_LEVEL_04_EVT, "setup core dump level"), +}; + +static struct init_script calibration_table[] = { + INIT_CMD(WMT_CORE_START_RF_CALIBRATION_CMD, WMT_CORE_START_RF_CALIBRATION_EVT, "start RF calibration data"), +}; + +#if CFG_WMT_PATCH_DL_OPTM +static struct init_script set_mcuclk_table_1[] = { + INIT_CMD(WMT_SET_MCU_CLK_EN_CMD, WMT_SET_MCU_CLK_EN_EVT, "enable set mcu clk"), + INIT_CMD(WMT_SET_MCU_CLK_138_CMD, WMT_SET_MCU_CLK_138_EVT, "set mcu clk to 138.67MH"), +}; + +static struct init_script set_mcuclk_table_2[] = { + INIT_CMD(WMT_SET_MCU_CLK_26_CMD, WMT_SET_MCU_CLK_26_EVT, "set mcu clk to 26MH"), + INIT_CMD(WMT_SET_MCU_CLK_DIS_CMD, WMT_SET_MCU_CLK_DIS_EVT, "disable set mcu clk"), +}; + +static struct init_script set_mcuclk_table_3[] = { + INIT_CMD(WMT_SET_MCU_CLK_EN_6797, WMT_SET_MCU_CLK_EVT_6797, "enable set mcu clk"), + INIT_CMD(WMT_SET_MCU_RATIO_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "mcu ratio set"), + INIT_CMD(WMT_SET_MCU_DIV_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "mcu div set"), + INIT_CMD(WMT_SET_MCU_HCLK_SET_6797, WMT_SET_MCU_CLK_EVT_6797, "set mcu clk to hclk"), +}; +static struct init_script set_mcuclk_table_4[] = { + INIT_CMD(WMT_SET_MCU_HCLK_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu hclk"), + INIT_CMD(WMT_SET_MCU_RATIO_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu ratio set"), + INIT_CMD(WMT_SET_MCU_CLK_DIS_6797, WMT_SET_MCU_CLK_EVT_6797, "disable mcu clk set"), +}; + +#endif + +static UINT8 WMT_COEX_EXT_COMPONENT_CMD[] = {0x01, 0x10, 0x03, 0x00, 0x0d, 0x00, 0x00}; + +static struct init_script set_wifi_ext_component_table[] = { + INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi ext component"), +}; + +#if CFG_WMT_FILTER_MODE_SETTING +static struct init_script set_wifi_lte_coex_table_1[] = { + INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_6752, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter spec"), + INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_6752, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq idx"), + INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "set LTE project"), +}; + +static struct init_script set_wifi_lte_coex_table_2[] = { + INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter"), + INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq id table"), + INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi lte unsafe channel"), + INIT_CMD(WMT_COEX_IS_LTE_L_CMD, WMT_COEX_SPLIT_MODE_EVT, "wifi coex is L branch"), +}; + +static struct init_script set_wifi_lte_coex_table_3[] = { + INIT_CMD(WMT_COEX_IS_LTE_PROJ_CMD, WMT_COEX_SPLIT_MODE_EVT, "set LTE project"), +}; + +static struct init_script set_wifi_lte_coex_table_0[] = { +#if 0 + INIT_CMD(WMT_COEX_SPLIT_FILTER_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex split filter"), + INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte coex filter spec"), + INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte freq idx"), + INIT_CMD(WMT_COEX_LTE_CHAN_UNSAFE_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi lte channel unsafe"), + INIT_CMD(WMT_COEX_EXT_COMPONENT_CMD_TEST, WMT_COEX_SPLIT_MODE_EVT, "wifi coex ext component"), +#endif + INIT_CMD(WMT_COEX_FILTER_SPEC_CMD_0, WMT_COEX_SPLIT_MODE_EVT, "def wifi lte coex filter spec"), + INIT_CMD(WMT_COEX_LTE_FREQ_IDX_TABLE_CMD_0, WMT_COEX_SPLIT_MODE_EVT, "def wifi lte freq idx"), +}; + +static struct init_script get_tdm_req_antsel_num_table[] = { + INIT_CMD(WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD, WMT_COEX_SPLIT_MODE_EVT, "get tdm req antsel num"), +}; +#endif + +static struct init_script bt_tssi_from_wifi_table[] = { + INIT_CMD(WMT_BT_TSSI_FROM_WIFI_CONFIG_CMD, WMT_BT_TSSI_FROM_WIFI_EVENT, "get bt tssi value from wifi"), +}; + +static struct init_script coex_config_addjust_table[] = { + INIT_CMD(WMT_COEX_CONFIG_BT_CTRL_CMD, WMT_COEX_SPLIT_MODE_EVT, "coex config bt ctrl"), + INIT_CMD(WMT_COEX_CONFIG_ADDJUST_OPP_TIME_RATIO_CMD, WMT_COEX_SPLIT_MODE_EVT, "opp time ratio"), + INIT_CMD(WMT_COEX_CONFIG_ADDJUST_BLE_SCAN_TIME_RATIO_CMD, WMT_COEX_SPLIT_MODE_EVT, "ble scan time ratio"), + +}; + +#if CFG_SET_OPT_REG +static struct init_script set_registers[] = { + /* INIT_CMD(WMT_SET_GPS_REG_CMD, WMT_SET_GPS_REG_EVT, "set wmt registers"), */ + /* INIT_CMD(WMT_SET_SDIODRV_REG_CMD, WMT_SET_SDIODRV_REG_EVT, "set SDIO driving registers") */ +#if CFG_WMT_I2S_DBGUART_SUPPORT + INIT_CMD(WMT_SET_DBGUART_REG_CMD, WMT_SET_DBGUART_REG_EVT, "set debug uart registers"), +#endif +#if CFG_SET_OPT_REG_SWLA + INIT_CMD(WMT_SET_SWLA_REG_CMD, WMT_SET_SWLA_REG_EVT, "set swla registers"), +#endif +#if CFG_SET_OPT_REG_MCUCLK + INIT_CMD(WMT_SET_MCUCLK_REG_CMD, WMT_SET_MCUCLK_REG_EVT, "set mcuclk dbg registers"), +#endif +#if CFG_SET_OPT_REG_MCUIRQ + INIT_CMD(WMT_SET_MCUIRQ_REG_CMD, WMT_SET_MCUIRQ_REG_EVT, "set mcu irq dbg registers"), +#endif +}; +#endif + +static struct init_script coex_table[] = { + INIT_CMD(WMT_COEX_SETTING_CONFIG_CMD, WMT_COEX_SETTING_CONFIG_EVT, "coex_wmt"), + +#if CFG_SUBSYS_COEX_NEED +/* no need in MT6628 */ + INIT_CMD(WMT_BT_COEX_SETTING_CONFIG_CMD, WMT_BT_COEX_SETTING_CONFIG_EVT, "coex_bt"), + INIT_CMD(WMT_WIFI_COEX_SETTING_CONFIG_CMD, WMT_WIFI_COEX_SETTING_CONFIG_EVT, "coex_wifi"), + INIT_CMD(WMT_PTA_COEX_SETTING_CONFIG_CMD, WMT_PTA_COEX_SETTING_CONFIG_EVT, "coex_ext_pta"), + INIT_CMD(WMT_MISC_COEX_SETTING_CONFIG_CMD, WMT_MISC_COEX_SETTING_CONFIG_EVT, "coex_misc"), +#else + INIT_CMD(WMT_COEX_WIFI_PATH_CMD, WMT_COEX_WIFI_PATH_EVT, "wifi path"), + INIT_CMD(WMT_COEX_EXT_ELAN_GAIN_P1_CMD, WMT_COEX_EXT_ELAN_GAIN_P1_EVT, "wifi elan gain p1"), + INIT_CMD(WMT_COEX_EXT_EPA_MODE_CMD, WMT_COEX_EXT_EPA_MODE_EVT, "wifi ext epa mode"), +#endif +}; + +static struct init_script epa_table[] = { + INIT_CMD(WMT_EPA_SETTING_CONFIG_CMD, WMT_EPA_SETTING_CONFIG_EVT, "coex_wmt_epa"), +}; + +static struct init_script osc_type_table[] = { + INIT_CMD(WMT_CORE_CO_CLOCK_CMD, WMT_CORE_CO_CLOCK_EVT, "osc_type"), +}; + +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) +static struct init_script merge_pcm_table[] = { + INIT_CMD(WMT_SET_I2S_SLAVE_REG_CMD, WMT_SET_I2S_SLAVE_REG_EVT, "I2S_Slave"), + INIT_CMD(WMT_SET_DAI_TO_PAD_REG_CMD, WMT_SET_DAI_TO_PAD_REG_EVT, "DAI_PAD"), + INIT_CMD(WMT_SET_DAI_REG_CMD, WMT_SET_DAI_REG_EVT, "DAI_EVT"), +}; +#endif + +#if CFG_WMT_SDIO_DRIVING_SET +static struct init_script sdio_driving_table[] = { + INIT_CMD(WMT_SET_SDIO_DRV_REG_CMD, WMT_SET_SDIO_DRV_REG_EVT, "sdio_driving"), +}; +#endif + +#if CFG_WMT_POWER_ON_DLM +static struct init_script wmt_power_on_dlm_table[] = { + INIT_CMD(WMT_POWER_CTRL_DLM_CMD1, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd1"), + INIT_CMD(WMT_POWER_CTRL_DLM_CMD2, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd2"), + INIT_CMD(WMT_POWER_CTRL_DLM_CMD3, WMT_POWER_CTRL_DLM_EVT, "power on dlm cmd3") +}; +#endif + + +static struct init_script wifi_ant_swap_table[] = { + INIT_CMD(WMT_WIFI_ANT_SWAP_CMD, WMT_WIFI_ANT_SWAP_EVT, "ant swap"), +}; + +/* SOC Chip Version and Info Table */ +static const WMT_IC_INFO_S mtk_wcn_soc_info_table[] = { + { + .u4HwVer = 0x8A00, + .cChipName = WMT_IC_NAME_DEFAULT, + .cChipVersion = WMT_IC_VER_E1, + .cPatchNameExt = WMT_IC_PATCH_E1_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8A01, + .cChipName = WMT_IC_NAME_DEFAULT, + .cChipVersion = WMT_IC_VER_E2, + .cPatchNameExt = WMT_IC_PATCH_E1_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8B00, + .cChipName = WMT_IC_NAME_DEFAULT, + .cChipVersion = WMT_IC_VER_E2, + .cPatchNameExt = WMT_IC_PATCH_E1_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8B01, + .cChipName = WMT_IC_NAME_DEFAULT, + .cChipVersion = WMT_IC_VER_E3, + .cPatchNameExt = WMT_IC_PATCH_E1_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + }, + { + .u4HwVer = 0x8C00, + .cChipName = WMT_IC_NAME_DEFAULT, + .cChipVersion = WMT_IC_VER_E2, + .cPatchNameExt = WMT_IC_PATCH_E1_EXT, + .bWorkWithoutPatch = MTK_WCN_BOOL_FALSE, + .bPsmSupport = MTK_WCN_BOOL_TRUE, + } +}; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static MTK_WCN_BOOL mtk_wcn_soc_trigger_assert(VOID); + +static INT32 mtk_wcn_soc_sw_init(P_WMT_HIF_CONF pWmtHifConf); + +static INT32 mtk_wcn_soc_sw_deinit(P_WMT_HIF_CONF pWmtHifConf); + +static INT32 mtk_wcn_soc_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag); + +static INT32 mtk_wcn_soc_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag); + +static INT32 mtk_wcn_soc_ver_check(VOID); + +static const WMT_IC_INFO_S *mtk_wcn_soc_find_wmt_ic_info(const UINT32 hw_ver); + +static INT32 wmt_stp_init_coex(VOID); + +static INT32 wmt_stp_init_epa(VOID); + +static INT32 wmt_stp_init_epa_elna(VOID); + +static INT32 wmt_stp_init_epa_elna_invert_cr(VOID); + +#if CFG_WMT_FILTER_MODE_SETTING +static INT32 wmt_stp_wifi_lte_coex(VOID); +#endif + +#if CFG_WMT_MULTI_PATCH +static INT32 mtk_wcn_soc_patch_dwn(UINT32 index); +static INT32 mtk_wcn_soc_patch_info_prepare(VOID); +static UINT32 mtk_wcn_soc_get_patch_num(VOID); +static INT32 mtk_wcn_soc_normal_patch_dwn(PUINT8 pPatchBuf, UINT32 patchSize, PUINT8 addressByte); +static INT32 mtk_wcn_soc_pda_patch_dwn(PUINT8 pPatchBuf, UINT32 patchSize, PUINT8 addressByte); +#else +static INT32 mtk_wcn_soc_patch_dwn(VOID); +#endif + +static INT32 mtk_wcn_soc_co_clock_ctrl(WMT_CO_CLOCK on); + +#if CFG_WMT_CRYSTAL_TIMING_SET +static INT32 mtk_wcn_soc_crystal_triming_set(VOID); +#endif + +static MTK_WCN_BOOL mtk_wcn_soc_quick_sleep_flag_get(VOID); + +static MTK_WCN_BOOL mtk_wcn_soc_aee_dump_flag_get(VOID); + +#if CFG_WMT_SDIO_DRIVING_SET +static INT32 mtk_wcn_soc_set_sdio_driving(void); +#endif +static UINT32 mtk_wcn_soc_update_patch_version(VOID); + +static INT32 mtk_wcn_soc_calibration(void); +static INT32 mtk_wcn_soc_do_calibration(void); +#if CFG_CALIBRATION_BACKUP_RESTORE +static INT32 mtk_wcn_soc_calibration_backup(void); +static INT32 mtk_wcn_soc_calibration_restore(void); +#endif + +static INT32 wmt_stp_init_wifi_ant_swap(VOID); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/* SOC Operation Function Table */ +WMT_IC_OPS wmt_ic_ops_soc = { + .icId = 0x0000, /* soc may have mt6572/82/71/83,but they have the same sw init flow */ + .sw_init = mtk_wcn_soc_sw_init, + .sw_deinit = mtk_wcn_soc_sw_deinit, + .ic_pin_ctrl = mtk_wcn_soc_pin_ctrl, + .ic_ver_check = mtk_wcn_soc_ver_check, + .co_clock_ctrl = mtk_wcn_soc_co_clock_ctrl, + .is_quick_sleep = mtk_wcn_soc_quick_sleep_flag_get, + .is_aee_dump_support = mtk_wcn_soc_aee_dump_flag_get, + .trigger_stp_assert = mtk_wcn_soc_trigger_assert, + .deep_sleep_ctrl = NULL, +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static INT32 _wmt_soc_mode_ctrl(UINT32 mode) +{ + INT32 iRet = -1; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + + /* only consider full mode situation for the moment */ + if (mode != MTKSTP_BTIF_FULL_MODE) + return -1; + + /* 1. Query chip STP default options */ + iRet = wmt_core_init_script(init_table_1_2, osal_array_size(init_table_1_2)); + if (iRet) { + WMT_ERR_FUNC("init_table_1_2 fail(%d)\n", iRet); + osal_assert(0); + return -2; + } + + /* 2. Set chip STP options */ + iRet = wmt_core_init_script(init_table_4, osal_array_size(init_table_4)); + if (iRet) { + WMT_ERR_FUNC("init_table_4 fail(%d)\n", iRet); + return -3; + } + + /* 3. Enable host full mode */ + ctrlPa1 = WMT_STP_CONF_MODE; + ctrlPa2 = MTKSTP_BTIF_FULL_MODE; + iRet = wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WMT_STP_CONF_EN; + ctrlPa2 = 1; + iRet += wmt_core_ctrl(WMT_CTRL_STP_CONF, &ctrlPa1, &ctrlPa2); + if (iRet) { + WMT_ERR_FUNC("enable host STP-BTIF-FULL mode fail(%d)\n", iRet); + return -4; + } + WMT_DBG_FUNC("enable host STP-BTIF-FULL mode\n"); + + /*4. wait for 10ms, enough for chip do mechanism switch.(at least 2ms is needed) */ + osal_sleep_ms(10); + + /* 5. Query chip STP options */ + iRet = wmt_core_init_script(init_table_5, osal_array_size(init_table_5)); + if (iRet) { + WMT_ERR_FUNC("init_table_5 fail(%d)\n", iRet); + return -5; + } + + return 0; +} + +static INT32 mtk_wcn_soc_sw_init(P_WMT_HIF_CONF pWmtHifConf) +{ + INT32 iRet = -1; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + UINT32 hw_ver; + WMT_CTRL_DATA ctrlData; + UINT32 chipid = 0; +#ifdef CFG_WMT_READ_EFUSE_VCN33 + UINT32 efuse_d3_vcn33 = 2; /*default voltage is 3.5V*/ +#endif +#if CFG_WMT_MULTI_PATCH + UINT32 patch_num = 0; + UINT32 patch_index = 0; +#endif +#if CFG_WMT_WIFI_5G_SUPPORT + UINT32 dDieChipid = 0; + UINT32 aDieChipid = 0; + UINT8 evtbuf[20]; + UINT32 u4Res; + UINT32 pmicChipid = 0; +#endif + P_WMT_GEN_CONF pWmtGenConf = NULL; + P_CONSYS_EMI_ADDR_INFO emiInfo = NULL; + + WMT_DBG_FUNC(" start\n"); + + osal_assert(gp_soc_info != NULL); + if ((gp_soc_info == NULL) + || (pWmtHifConf == NULL) + ) { + WMT_ERR_FUNC("null pointers: gp_soc_info(0x%p), pWmtHifConf(0x%p)\n", gp_soc_info, pWmtHifConf); + return -1; + } + + hw_ver = gp_soc_info->u4HwVer; + + /* 4 <3.2> start init for BTIF */ + if (pWmtHifConf->hifType == WMT_HIF_BTIF) { + + emiInfo = mtk_wcn_consys_soc_get_emi_phy_add(); + if (!emiInfo) { + WMT_ERR_FUNC("get emi info fail!\n"); + return -1; + } + /* non-PDA mode, enable full mode before patch download */ + if (!emiInfo->pda_dl_patch_flag) { + iRet = _wmt_soc_mode_ctrl(MTKSTP_BTIF_FULL_MODE); + if (iRet) + return iRet; + } + } + + /* Check whether need to update property of patch version. + * If yes, notify stp_launcher to update. + */ + if (wmt_lib_get_need_update_patch_version()) { + wmt_lib_set_need_update_patch_version(0); + mtk_wcn_soc_update_patch_version(); + WMT_INFO_FUNC("wmt update patch version\n"); + } + +#if CFG_WMT_POWER_ON_DLM + if (wmt_ic_ops_soc.icId != 0x6765 && + wmt_ic_ops_soc.icId != 0x3967 && + wmt_ic_ops_soc.icId != 0x6761 && + wmt_ic_ops_soc.icId != 0x6779 && + wmt_ic_ops_soc.icId != 0x6785 && + wmt_ic_ops_soc.icId != 0x8168) { + iRet = wmt_core_init_script(wmt_power_on_dlm_table, + osal_array_size(wmt_power_on_dlm_table)); + if (iRet) + WMT_ERR_FUNC("wmt_power_on_dlm_table fail(%d)\n", iRet); + WMT_DBG_FUNC("wmt_power_on_dlm_table ok\n"); + } +#endif + /* 6. download patch */ +#if CFG_WMT_MULTI_PATCH + /* 6.1 Let launcher to search patch info */ + /* 6.2 Read patch number */ + /* If patch number is 0, it's first time connys power on */ + patch_num = mtk_wcn_soc_get_patch_num(); + if (patch_num == 0 || wmt_lib_get_patch_info() == NULL) { + iRet = mtk_wcn_soc_patch_info_prepare(); + if (iRet) { + WMT_ERR_FUNC("patch info perpare fail(%d)\n", iRet); + return -6; + } + patch_num = mtk_wcn_soc_get_patch_num(); + } +#if CFG_WMT_PATCH_DL_OPTM + if (wmt_ic_ops_soc.icId != 0x6765 && + wmt_ic_ops_soc.icId != 0x3967 && + wmt_ic_ops_soc.icId != 0x6761 && + wmt_ic_ops_soc.icId != 0x6768 && + wmt_ic_ops_soc.icId != 0x6779 && + wmt_ic_ops_soc.icId != 0x6785 && + wmt_ic_ops_soc.icId != 0x8168) { + if (wmt_ic_ops_soc.icId == 0x0279 || + wmt_ic_ops_soc.icId == 0x0507 || + wmt_ic_ops_soc.icId == 0x0713 || + wmt_ic_ops_soc.icId == 0x0788 || + wmt_ic_ops_soc.icId == 0x0688) { + iRet = wmt_core_init_script(set_mcuclk_table_3, osal_array_size(set_mcuclk_table_3)); + if (iRet) + WMT_ERR_FUNC("set_mcuclk_table_3 fail(%d)\n", iRet); + } else { + iRet = wmt_core_init_script(set_mcuclk_table_1, osal_array_size(set_mcuclk_table_1)); + if (iRet) + WMT_ERR_FUNC("set_mcuclk_table_1 fail(%d)\n", iRet); + } + } +#endif + /* 6.3 Multi-patch Patch download */ + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_BEFORE_SEND_DOWNLOAD_PATCH); + for (patch_index = 0; patch_index < patch_num; patch_index++) { + iRet = mtk_wcn_soc_patch_dwn(patch_index); + if (iRet) { + WMT_ERR_FUNC("patch dwn fail (%d),patch_index(%d)\n", iRet, patch_index); + return -7; + } + if (patch_index == (patch_num - 1)) + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_BEFORE_CONNSYS_RESET); + + iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3)); + if (iRet) { + WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); + return -8; + } + } + +#if CFG_WMT_PATCH_DL_OPTM + if (wmt_ic_ops_soc.icId != 0x6765 && + wmt_ic_ops_soc.icId != 0x3967 && + wmt_ic_ops_soc.icId != 0x6761 && + wmt_ic_ops_soc.icId != 0x6768 && + wmt_ic_ops_soc.icId != 0x6779 && + wmt_ic_ops_soc.icId != 0x6785 && + wmt_ic_ops_soc.icId != 0x8168) { + if (wmt_ic_ops_soc.icId == 0x0279 || + wmt_ic_ops_soc.icId == 0x0507 || + wmt_ic_ops_soc.icId == 0x0713 || + wmt_ic_ops_soc.icId == 0x0788 || + wmt_ic_ops_soc.icId == 0x0688) { + iRet = wmt_core_init_script(set_mcuclk_table_4, osal_array_size(set_mcuclk_table_4)); + if (iRet) + WMT_ERR_FUNC("set_mcuclk_table_4 fail(%d)\n", iRet); + } else { + iRet = wmt_core_init_script(set_mcuclk_table_2, osal_array_size(set_mcuclk_table_2)); + if (iRet) + WMT_ERR_FUNC("set_mcuclk_table_2 fail(%d)\n", iRet); + } + } +#endif + +#else + /* 6.3 Patch download */ + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_BEFORE_SEND_DOWNLOAD_PATCH); + iRet = mtk_wcn_soc_patch_dwn(); + /* If patch download fail, we just ignore this error and let chip init process goes on */ + if (iRet) + WMT_ERR_FUNC("patch dwn fail (%d), just omit\n", iRet); + + /* 6.4. WMT Reset command */ + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_BEFORE_CONNSYS_RESET); + iRet = wmt_core_init_script(init_table_3, osal_array_size(init_table_3)); + if (iRet) { + WMT_ERR_FUNC("init_table_3 fail(%d)\n", iRet); + return -8; + } +#endif + + /* PDA mode, enable full mode after patch download */ + if (pWmtHifConf->hifType == WMT_HIF_BTIF && + emiInfo->pda_dl_patch_flag) { + iRet = _wmt_soc_mode_ctrl(MTKSTP_BTIF_FULL_MODE); + if (iRet) + return iRet; + } + + chipid = wmt_plat_get_soc_chipid(); + WMT_SET_CHIP_ID_CMD[5] = chipid & 0xff; + WMT_SET_CHIP_ID_CMD[6] = (chipid >> 8) & 0xff; + iRet = wmt_core_init_script(set_chipid_script, osal_array_size(set_chipid_script)); + if (iRet) + WMT_ERR_FUNC("wmt_core:set_chipid_script %s(%d)\n", iRet ? "fail" : "ok", iRet); + + if (wmt_ic_ops_soc.icId == 0x6765 || wmt_ic_ops_soc.icId == 0x3967 || + wmt_ic_ops_soc.icId == 0x6768 || wmt_ic_ops_soc.icId == 0x8168) { + iRet = wmt_core_init_script_retry(get_a_die_script, osal_array_size(get_a_die_script), 1, 0); + if (iRet) { + WMT_ERR_FUNC("get_a_die_script fail(%d)\n", iRet); +#ifndef CFG_WMT_EVB + osal_dbg_assert_aee("Connsys A-die is not exist", "Please check Connsys A-die\0"); +#endif + return -21; + } + } + +#ifdef CFG_WMT_READ_EFUSE_VCN33 + /*get CrystalTiming value before set it */ + iRet = wmt_core_tx(get_efuse_vcn33_script[0].cmd, get_efuse_vcn33_script[0].cmdSz, &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != get_efuse_vcn33_script[0].cmdSz)) { + WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", + get_efuse_vcn33_script[0].str, iRet, u4Res, get_efuse_vcn33_script[0].cmdSz); + } + /* EVENT BUF */ + osal_memset(get_efuse_vcn33_script[0].evt, 0, get_efuse_vcn33_script[0].evtSz); + iRet = wmt_core_rx(get_efuse_vcn33_script[0].evt, get_efuse_vcn33_script[0].evtSz, &u4Res); + if (iRet || (u4Res != get_efuse_vcn33_script[0].evtSz)) { + WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", + get_efuse_vcn33_script[0].str, iRet, u4Res, get_efuse_vcn33_script[0].evtSz); + mtk_wcn_stp_dbg_dump_package(); + } + efuse_d3_vcn33 = WMT_GET_EFUSE_VCN33_EVT[5] & 0x03; + WMT_INFO_FUNC("Read efuse to set PMIC voltage:(%d)\n", efuse_d3_vcn33); + wmt_set_pmic_voltage(efuse_d3_vcn33); +#endif + pWmtGenConf = wmt_get_gen_conf_pointer(); + if (wmt_ic_ops_soc.icId == 0x0279 || + wmt_ic_ops_soc.icId == 0x0507 || + wmt_ic_ops_soc.icId == 0x0713 || + wmt_ic_ops_soc.icId == 0x0788 || + wmt_ic_ops_soc.icId == 0x0688) { + /* add WMT_COXE_CONFIG_EXT_COMPONENT_OPCODE command for 2G4 eLNA demand*/ + if (pWmtGenConf->coex_wmt_ext_component) { + WMT_INFO_FUNC("coex_wmt_ext_component:0x%x\n", pWmtGenConf->coex_wmt_ext_component); + set_wifi_ext_component_table[0].cmd[5] = pWmtGenConf->coex_wmt_ext_component; + } + iRet = wmt_core_init_script(set_wifi_ext_component_table, + osal_array_size(set_wifi_ext_component_table)); + if (iRet) + WMT_ERR_FUNC("wmt_core:set_wifi_ext_component_table %s(%d)\n", + iRet ? "fail" : "ok", iRet); + } + +#if CFG_WMT_FILTER_MODE_SETTING + if ((wmt_ic_ops_soc.icId == 0x6580) || + (wmt_ic_ops_soc.icId == 0x8163) || + (wmt_ic_ops_soc.icId == 0x6752) || + (wmt_ic_ops_soc.icId == 0x6582) || + (wmt_ic_ops_soc.icId == 0x6592) || + (wmt_ic_ops_soc.icId == 0x0279) || + (wmt_ic_ops_soc.icId == 0x0507) || + (wmt_ic_ops_soc.icId == 0x0326) || + (wmt_ic_ops_soc.icId == 0x0551) || + (wmt_ic_ops_soc.icId == 0x0321) || + (wmt_ic_ops_soc.icId == 0x0335) || + (wmt_ic_ops_soc.icId == 0x0688) || + (wmt_ic_ops_soc.icId == 0x0713) || + (wmt_ic_ops_soc.icId == 0x0788) || + (wmt_ic_ops_soc.icId == 0x0699) || + (wmt_ic_ops_soc.icId == 0x0337) || + (wmt_ic_ops_soc.icId == 0x6765) || + (wmt_ic_ops_soc.icId == 0x3967) || + (wmt_ic_ops_soc.icId == 0x6761) || + (wmt_ic_ops_soc.icId == 0x6779) || + (wmt_ic_ops_soc.icId == 0x6768) || + (wmt_ic_ops_soc.icId == 0x6785) || + (wmt_ic_ops_soc.icId == 0x8168) || + (wmt_ic_ops_soc.icId == 0x0633)) { + wmt_stp_wifi_lte_coex(); + WMT_DBG_FUNC("wmt_stp_wifi_lte_coex done!\n"); + } + if ((wmt_ic_ops_soc.icId == 0x6582) || (wmt_ic_ops_soc.icId == 0x6592)) { + /*get gpio tdm req antsel number */ + ctrlPa1 = 0; + ctrlPa2 = 0; + wmt_core_ctrl(WMT_CTRL_GET_TDM_REQ_ANTSEL, &ctrlPa1, &ctrlPa2); + WMT_INFO_FUNC("get GPIO TDM REQ ANTSEL number(%lu)\n", ctrlPa1); + /*set gpio tdm req antsel number to firmware */ + WMT_COEX_TDM_REQ_ANTSEL_NUM_CMD[5] = ctrlPa1; + iRet = wmt_core_init_script(get_tdm_req_antsel_num_table, + osal_array_size(get_tdm_req_antsel_num_table)); + if (iRet) + WMT_ERR_FUNC("get_tdm_req_antsel_num_table fail(%d)\n", iRet); + } +#endif + WMT_INFO_FUNC("bt_tssi_from_wifi=%d, bt_tssi_target=%d\n", + pWmtGenConf->bt_tssi_from_wifi, pWmtGenConf->bt_tssi_target); + if (pWmtGenConf->bt_tssi_from_wifi) { + if (wmt_ic_ops_soc.icId == 0x0713 || + wmt_ic_ops_soc.icId == 0x6765 || + wmt_ic_ops_soc.icId == 0x3967 || + wmt_ic_ops_soc.icId == 0x6761 || + wmt_ic_ops_soc.icId == 0x6779 || + wmt_ic_ops_soc.icId == 0x6768 || + wmt_ic_ops_soc.icId == 0x6785 || + wmt_ic_ops_soc.icId == 0x8168 || + wmt_ic_ops_soc.icId == 0x0788) + WMT_BT_TSSI_FROM_WIFI_CONFIG_CMD[4] = 0x10; + + WMT_BT_TSSI_FROM_WIFI_CONFIG_CMD[5] = pWmtGenConf->bt_tssi_from_wifi; + WMT_BT_TSSI_FROM_WIFI_CONFIG_CMD[6] = (pWmtGenConf->bt_tssi_target & 0x00FF) >> 0; + WMT_BT_TSSI_FROM_WIFI_CONFIG_CMD[7] = (pWmtGenConf->bt_tssi_target & 0xFF00) >> 8; + iRet = wmt_core_init_script(bt_tssi_from_wifi_table, osal_array_size(bt_tssi_from_wifi_table)); + if (iRet) + WMT_ERR_FUNC("bt_tssi_from_wifi_table fail(%d)\n", iRet); + } + + /* init epa before start RF calibration */ + /* for chip 0x6739 */ + iRet = wmt_stp_init_epa(); + + if (iRet) { + WMT_ERR_FUNC("init_epa fail(%d)\n", iRet); + return -20; + } + + /* for chip 0x6779 */ + iRet = wmt_stp_init_epa_elna(); + + if (iRet) { + WMT_ERR_FUNC("init_epa_elna fail(%d)\n", iRet); + return -22; + } + + iRet = wmt_stp_init_epa_elna_invert_cr(); + if (iRet) { + WMT_ERR_FUNC("init_invert_cr fail(%d)\n", iRet); + return -23; + } + + /* init coex before start RF calibration */ + if (wmt_ic_ops_soc.icId == 0x6765 || + wmt_ic_ops_soc.icId == 0x6761 || + wmt_ic_ops_soc.icId == 0x6768 || + wmt_ic_ops_soc.icId == 0x6785) { + iRet = wmt_stp_init_coex(); + if (iRet) { + WMT_ERR_FUNC("init_coex fail(%d)\n", iRet); + return -10; + } + WMT_DBG_FUNC("init_coex ok\n"); + } + + iRet = wmt_stp_init_wifi_ant_swap(); + + if (iRet) { + WMT_ERR_FUNC("init_wifi_ant_swap fail(%d)\n", iRet); + return -23; + } + + /* 7. start RF calibration data */ + iRet = mtk_wcn_soc_calibration(); + if (iRet) { + WMT_ERR_FUNC("calibration failed\n"); + return -9; + } + + /* turn off VCN28 after reading efuse */ + ctrlPa1 = EFUSE_PALDO; + ctrlPa2 = PALDO_OFF; + iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + + if (wmt_ic_ops_soc.icId != 0x6765 && + wmt_ic_ops_soc.icId != 0x3967 && + wmt_ic_ops_soc.icId != 0x6761 && + wmt_ic_ops_soc.icId != 0x6768 && + wmt_ic_ops_soc.icId != 0x6779 && + wmt_ic_ops_soc.icId != 0x6785 && + wmt_ic_ops_soc.icId != 0x8168) { + iRet = wmt_stp_init_coex(); + if (iRet) { + WMT_ERR_FUNC("init_coex fail(%d)\n", iRet); + return -10; + } + WMT_DBG_FUNC("init_coex ok\n"); + } + + if (wmt_ic_ops_soc.icId == 0x0788 || + wmt_ic_ops_soc.icId == 0x6765 || + wmt_ic_ops_soc.icId == 0x6768 || + wmt_ic_ops_soc.icId == 0x6779 || + wmt_ic_ops_soc.icId == 0x6785) { + WMT_INFO_FUNC("coex_config_bt_ctrl:0x%x\n", pWmtGenConf->coex_config_bt_ctrl); + coex_config_addjust_table[0].cmd[5] = pWmtGenConf->coex_config_bt_ctrl; + WMT_INFO_FUNC("coex_config_bt_ctrl_mode:0x%x\n", pWmtGenConf->coex_config_bt_ctrl_mode); + coex_config_addjust_table[0].cmd[6] = pWmtGenConf->coex_config_bt_ctrl_mode; + WMT_INFO_FUNC("coex_config_bt_ctrl_rw:0x%x\n", pWmtGenConf->coex_config_bt_ctrl_rw); + coex_config_addjust_table[0].cmd[7] = pWmtGenConf->coex_config_bt_ctrl_rw; + + WMT_INFO_FUNC("coex_config_addjust_opp_time_ratio:0x%x\n", + pWmtGenConf->coex_config_addjust_opp_time_ratio); + coex_config_addjust_table[1].cmd[5] = pWmtGenConf->coex_config_addjust_opp_time_ratio; + WMT_INFO_FUNC("coex_config_addjust_opp_time_ratio_bt_slot:0x%x\n", + pWmtGenConf->coex_config_addjust_opp_time_ratio_bt_slot); + coex_config_addjust_table[1].cmd[6] = + pWmtGenConf->coex_config_addjust_opp_time_ratio_bt_slot; + WMT_INFO_FUNC("coex_config_addjust_opp_time_ratio_wifi_slot:0x%x\n", + pWmtGenConf->coex_config_addjust_opp_time_ratio_wifi_slot); + coex_config_addjust_table[1].cmd[7] = + pWmtGenConf->coex_config_addjust_opp_time_ratio_wifi_slot; + + WMT_INFO_FUNC("coex_config_addjust_ble_scan_time_ratio:0x%x\n", + pWmtGenConf->coex_config_addjust_ble_scan_time_ratio); + coex_config_addjust_table[2].cmd[5] = + pWmtGenConf->coex_config_addjust_ble_scan_time_ratio; + WMT_INFO_FUNC("coex_config_addjust_ble_scan_time_ratio_bt_slot:0x%x\n", + pWmtGenConf->coex_config_addjust_ble_scan_time_ratio_bt_slot); + coex_config_addjust_table[2].cmd[6] = + pWmtGenConf->coex_config_addjust_ble_scan_time_ratio_bt_slot; + WMT_INFO_FUNC("coex_config_addjust_ble_scan_time_ratio_wifi_slot:0x%x\n", + pWmtGenConf->coex_config_addjust_ble_scan_time_ratio_wifi_slot); + coex_config_addjust_table[2].cmd[7] = + pWmtGenConf->coex_config_addjust_ble_scan_time_ratio_wifi_slot; + + /* COEX flag is different in these project. */ + if (wmt_ic_ops_soc.icId == 0x6765 || + wmt_ic_ops_soc.icId == 0x6768 || + wmt_ic_ops_soc.icId == 0x6779 || + wmt_ic_ops_soc.icId == 0x6785) { + coex_config_addjust_table[0].cmd[4] = 0x1e; + coex_config_addjust_table[1].cmd[4] = 0x1f; + coex_config_addjust_table[2].cmd[4] = 0x20; + } + + iRet = wmt_core_init_script(coex_config_addjust_table, + osal_array_size(coex_config_addjust_table)); + if (iRet) + WMT_ERR_FUNC("wmt_core:coex_config_addjust_table %s(%d)\n", + iRet ? "fail" : "ok", iRet); + } + +#if CFG_WMT_CRYSTAL_TIMING_SET + mtk_wcn_soc_crystal_triming_set(); +#endif + +#if CFG_WMT_SDIO_DRIVING_SET + mtk_wcn_soc_set_sdio_driving(); +#endif + + if (wmt_ic_ops_soc.icId != 0x6765 && + wmt_ic_ops_soc.icId != 0x3967 && + wmt_ic_ops_soc.icId != 0x6761 && + wmt_ic_ops_soc.icId != 0x6768 && + wmt_ic_ops_soc.icId != 0x6779 && + wmt_ic_ops_soc.icId != 0x6785 && + wmt_ic_ops_soc.icId != 0x8168) { + if (wmt_plat_soc_co_clock_flag_get() == WMT_CO_CLOCK_EN) { + WMT_INFO_FUNC("co-clock enabled.\n"); + + iRet = wmt_core_init_script(osc_type_table, osal_array_size(osc_type_table)); + if (iRet) { + WMT_ERR_FUNC("osc_type_table fail(%d), goes on\n", iRet); + return -11; + } + } else { + WMT_WARN_FUNC("co-clock disabled.\n"); + } + } +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) + iRet = wmt_core_init_script(merge_pcm_table, osal_array_size(merge_pcm_table)); + if (iRet) { + WMT_ERR_FUNC("merge_pcm_table fail(%d), goes on\n", iRet); + return -12; + } +#endif + + /* 15. Set FM strap */ + WMT_STRAP_CONF_CMD_FM_COMM[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; + WMT_STRAP_CONF_EVT[5] = (UINT8) pWmtHifConf->au4StrapConf[0]; + iRet = wmt_core_init_script(init_table_5_1, osal_array_size(init_table_5_1)); + if (iRet) { + WMT_ERR_FUNC("init_table_5_1 fm mode(%d) fail(%d)\n", pWmtHifConf->au4StrapConf[0], iRet); + return -13; + } + WMT_DBG_FUNC("set fm mode (%d) ok\n", pWmtHifConf->au4StrapConf[0]); + +#if CFG_SET_OPT_REG /*set registers */ + iRet = wmt_core_init_script(set_registers, osal_array_size(set_registers)); + if (iRet) { + WMT_ERR_FUNC("set_registers fail(%d)", iRet); + return -14; + } +#endif + +#if CFG_WMT_COREDUMP_ENABLE + /*Open Core Dump Function @QC begin */ + mtk_wcn_stp_coredump_flag_ctrl(1); +#endif + if (wmt_ic_ops_soc.icId != 0x6765 && + wmt_ic_ops_soc.icId != 0x3967 && + wmt_ic_ops_soc.icId != 0x6761 && + wmt_ic_ops_soc.icId != 0x6768 && + wmt_ic_ops_soc.icId != 0x6779 && + wmt_ic_ops_soc.icId != 0x6785 && + wmt_ic_ops_soc.icId != 0x8168) { + if (mtk_wcn_stp_coredump_flag_get() != 0) { + iRet = wmt_core_init_script(init_table_6, osal_array_size(init_table_6)); + if (iRet) { + WMT_ERR_FUNC("init_table_6 core dump setting fail(%d)\n", iRet); + return -15; + } + WMT_DBG_FUNC("enable soc_consys firmware coredump\n"); + } else { + WMT_DBG_FUNC("disable soc_consys firmware coredump\n"); + } + } + +#if CFG_WMT_WIFI_5G_SUPPORT + dDieChipid = wmt_ic_ops_soc.icId; + WMT_DBG_FUNC("current SOC chipid is 0x%x\n", dDieChipid); + if (dDieChipid == 0X6592) { + /* read A die chipid by wmt cmd */ + iRet = + wmt_core_tx((PUINT8) &WMT_GET_SOC_ADIE_CHIPID_CMD[0], sizeof(WMT_GET_SOC_ADIE_CHIPID_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_GET_SOC_ADIE_CHIPID_CMD))) { + WMT_ERR_FUNC("wmt_core:read A die chipid CMD fail(%d),size(%d)\n", iRet, u4Res); + return -16; + } + osal_memset(evtbuf, 0, sizeof(evtbuf)); + iRet = wmt_core_rx(evtbuf, sizeof(WMT_GET_SOC_ADIE_CHIPID_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_GET_SOC_ADIE_CHIPID_EVT))) { + WMT_ERR_FUNC("wmt_core:read A die chipid EVT fail(%d),size(%d)\n", iRet, u4Res); + WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n", + evtbuf[0], evtbuf[1], evtbuf[2], evtbuf[3], evtbuf[4], + WMT_GET_SOC_ADIE_CHIPID_EVT[0], + WMT_GET_SOC_ADIE_CHIPID_EVT[1], + WMT_GET_SOC_ADIE_CHIPID_EVT[2], + WMT_GET_SOC_ADIE_CHIPID_EVT[3], + WMT_GET_SOC_ADIE_CHIPID_EVT[4]); + mtk_wcn_stp_dbg_dump_package(); + return -17; + } + + osal_memcpy(&aDieChipid, &evtbuf[u4Res - 2], 2); + WMT_INFO_FUNC("get SOC A die chipid(0x%x)\n", aDieChipid); + + if (aDieChipid == 0x6625) { + iRet = + wmt_core_tx((PUINT8) &WMT_GET_SOC_6625_L_CMD[0], sizeof(WMT_GET_SOC_6625_L_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_GET_SOC_6625_L_CMD))) + WMT_ERR_FUNC("wmt_core:read A die efuse CMD fail(%d),size(%d)\n", iRet, u4Res); + osal_memset(evtbuf, 0, sizeof(evtbuf)); + iRet = wmt_core_rx(evtbuf, sizeof(WMT_GET_SOC_6625_L_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_GET_SOC_6625_L_EVT))) { + WMT_ERR_FUNC("wmt_core:read A die efuse EVT fail(%d),size(%d)\n", iRet, u4Res); + WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X]\n", + evtbuf[0], evtbuf[1], evtbuf[2], evtbuf[3], + WMT_GET_SOC_6625_L_EVT[0], + WMT_GET_SOC_6625_L_EVT[1], + WMT_GET_SOC_6625_L_EVT[2], + WMT_GET_SOC_6625_L_EVT[3]); + mtk_wcn_stp_dbg_dump_package(); + } + WMT_INFO_FUNC("read SOC Adie Efuse(0x120) value:0x%2x,0x%2x,0x%2x,0x%2x -> %s\n", + evtbuf[u4Res - 4], evtbuf[u4Res - 3], evtbuf[u4Res - 2], evtbuf[u4Res - 1], + evtbuf[u4Res - 2] == 0x31 ? "MT6625L" : "MT6625"); + } + /* get PMIC chipid */ + + ctrlData.ctrlId = WMT_CTRL_SOC_PALDO_CTRL; + ctrlData.au4CtrlData[0] = PMIC_CHIPID_PALDO; + ctrlData.au4CtrlData[1] = 0; + iRet = wmt_ctrl(&ctrlData); + if (iRet < 0) { + WMT_ERR_FUNC("wmt_core: read PMIC chipid fail(%d)\n", iRet); + return -18; + } + pmicChipid = ctrlData.au4CtrlData[2]; + WMT_INFO_FUNC("current PMIC chipid(0x%x)\n", pmicChipid); + + /* MT6625 & MT6322, write 1 to 0x0414[12] */ + /* MT6625 & MT6323, assert */ + /* MT6627 & (MT6322 or MT6323),write 0 to 0x0414[12] */ + + switch (aDieChipid) { + case 0x6625: + if (pmicChipid == 0x6322 || pmicChipid == 0x6356) { + WMT_INFO_FUNC("wmt-core:enable wifi 5G support\n"); + ctrlPa1 = WIFI_5G_PALDO; + ctrlPa2 = PALDO_ON; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + } else if (pmicChipid == 0x6323) { + osal_assert(0); + } else { + WMT_WARN_FUNC("wmt-core: unknown PMIC chipid\n"); + } + break; + case 0x6627: + if ((pmicChipid == 0x6322) || (pmicChipid == 0x6323)) { + WMT_INFO_FUNC("wmt-core: disable wifi 5G support\n"); + ctrlPa1 = WIFI_5G_PALDO; + ctrlPa2 = PALDO_OFF; + wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + } else { + WMT_WARN_FUNC("wmt-core: unknown PMIC chipid\n"); + } + break; + default: + WMT_WARN_FUNC("wmt-core: unknown A die chipid(0x%x)\n", aDieChipid); + break; + } + } +#endif + +#if 1 + ctrlData.ctrlId = WMT_CTRL_SET_STP_DBG_INFO; + ctrlData.au4CtrlData[0] = wmt_ic_ops_soc.icId; + ctrlData.au4CtrlData[1] = (SIZE_T) gp_soc_info->cChipVersion; + ctrlData.au4CtrlData[2] = (SIZE_T) &gp_soc_patch_info; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("set dump info fail(%d)\n", iRet); + return -19; + } +#endif + +#if CFG_WMT_PS_SUPPORT + osal_assert(gp_soc_info != NULL); + if (gp_soc_info != NULL) { + if (gp_soc_info->bPsmSupport != MTK_WCN_BOOL_FALSE) + wmt_lib_ps_enable(); + else + wmt_lib_ps_disable(); + } +#endif + + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_END); + + return 0; +} + +static INT32 mtk_wcn_soc_sw_deinit(P_WMT_HIF_CONF pWmtHifConf) +{ + WMT_DBG_FUNC(" start\n"); + +#if CFG_WMT_PS_SUPPORT + osal_assert(gp_soc_info != NULL); + if ((gp_soc_info != NULL) + && (gp_soc_info->bPsmSupport != MTK_WCN_BOOL_FALSE)) { + wmt_lib_ps_disable(); + } +#endif + + gp_soc_info = NULL; + + return 0; +} + +static INT32 mtk_wcn_soc_aif_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 ret = -1; + UINT32 val; + + if ((flag & WMT_LIB_AIF_FLAG_MASK) == WMT_LIB_AIF_FLAG_SHARE) { + WMT_INFO_FUNC("PCM & I2S PIN SHARE\n"); +#if 0 + switch (state) { + case WMT_IC_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + val = 0x00000770; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_1: + /* BT_PCM_ON & FM line in/out */ + val = 0x00000700; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_2: + /* BT_PCM_OFF & FM I2S */ + val = 0x00000710; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000800; /* 800:3-wire, 000: 4-wire */ + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + default: + WMT_ERR_FUNC("unsupported state (%d)\n", state); + ret = -1; + break; + } +#else + WMT_WARN_FUNC("TBD!!"); + ret = 0; +#endif + } else { + /*PCM & I2S separate */ + WMT_INFO_FUNC("PCM & I2S PIN SEPARATE\n"); +#if 0 + switch (state) { + case WMT_IC_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + val = 0x00000770; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_1: + /* BT_PCM_ON & FM line in/out */ + val = 0x00000700; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000000; + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + break; + + case WMT_IC_AIF_2: + /* BT_PCM_OFF & FM I2S */ + val = 0x00000070; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000800; /* 800:3-wire, 000: 4-wire */ + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + + break; + case WMT_IC_AIF_3: + val = 0x00000000; + ret = wmt_core_reg_rw_raw(1, 0x80050140, &val, 0x00000FF0); + val = 0x00000800; /* 800:3-wire, 000: 4-wire */ + ret += wmt_core_reg_rw_raw(1, 0x80050150, &val, 0x00000800); + + break; + default: + WMT_ERR_FUNC("unsupported state (%d)\n", state); + ret = -1; + break; + } +#else + switch (state) { + case WMT_IC_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + ret = 0; + break; + case WMT_IC_AIF_1: + /* BT_PCM_ON & FM line in/out */ + ret = 0; + break; + + case WMT_IC_AIF_2: + /* BT_PCM_OFF & FM I2S */ + val = 0x01110000; + ret = wmt_core_reg_rw_raw(1, 0x80050078, &val, 0x0FFF0000); + + break; + case WMT_IC_AIF_3: + ret = 0; + break; + + default: + WMT_ERR_FUNC("unsupported state (%d)\n", state); + ret = -1; + break; + } +#endif + } + + if (!ret) + WMT_WARN_FUNC("new state(%d) fail(%d)\n", state, ret); + WMT_INFO_FUNC("new state(%d) ok\n", state); + + return ret; +} + +static INT32 mtk_wcn_soc_gps_sync_ctrl(WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 iRet = -1; + UINT32 uVal = 0; + + /* gen3(6631) CONSYS can not access reg:0x80050078 and no need to do GPS SYNC + * may cause bus hang + */ + if (wmt_ic_ops_soc.icId != 0x0279 && + wmt_ic_ops_soc.icId != 0x0507 && + wmt_ic_ops_soc.icId != 0x0713 && + wmt_ic_ops_soc.icId != 0x0788 && + wmt_ic_ops_soc.icId != 0x6765 && + wmt_ic_ops_soc.icId != 0x3967 && + wmt_ic_ops_soc.icId != 0x6761 && + wmt_ic_ops_soc.icId != 0x6768 && + wmt_ic_ops_soc.icId != 0x6779 && + wmt_ic_ops_soc.icId != 0x6785 && + wmt_ic_ops_soc.icId != 0x8168 && + wmt_ic_ops_soc.icId != 0x0688) { + if (state == WMT_IC_PIN_MUX) + uVal = 0x1 << 28; + else + uVal = 0x5 << 28; + iRet = wmt_core_reg_rw_raw(1, 0x80050078, &uVal, 0x7 << 28); + if (iRet) + WMT_ERR_FUNC("gps_sync pin ctrl failed, iRet(%d)\n", iRet); + } else + WMT_INFO_FUNC("This chip no need to sync GPS and MODEM!\n"); + + /* anyway, we return 0 */ + return 0; +} + +static INT32 mtk_wcn_soc_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE state, UINT32 flag) +{ + INT32 ret; + + WMT_DBG_FUNC("ic pin id:%d, state:%d, flag:0x%x\n", id, state, flag); + + ret = -1; + switch (id) { + case WMT_IC_PIN_AUDIO: + ret = mtk_wcn_soc_aif_ctrl(state, flag); + break; + + case WMT_IC_PIN_EEDI: + WMT_WARN_FUNC("TBD!!"); + /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ + ret = 0; + break; + + case WMT_IC_PIN_EEDO: + WMT_WARN_FUNC("TBD!!"); + /* We just return 0 here, prevent from WMT-FUNC do other register read/write */ + ret = 0; + break; + case WMT_IC_PIN_GSYNC: + ret = mtk_wcn_soc_gps_sync_ctrl(state, flag); + break; + default: + break; + } + WMT_INFO_FUNC("ret = (%d)\n", ret); + + return ret; +} + +INT32 mtk_wcn_soc_co_clock_ctrl(WMT_CO_CLOCK on) +{ + INT32 iRet = 0; + + if ((on >= WMT_CO_CLOCK_DIS) && (on < WMT_CO_CLOCK_MAX)) { + gCoClockEn = on; + } else { + WMT_DBG_FUNC("0x%x: error parameter:%d\n", wmt_ic_ops_soc.icId, on); + iRet = -1; + } + WMT_DBG_FUNC("0x%x: Co-clock %s\n", wmt_ic_ops_soc.icId, + (gCoClockEn == WMT_CO_CLOCK_DIS) ? "disabled" : "enabled"); + + return iRet; +} + +static MTK_WCN_BOOL mtk_wcn_soc_quick_sleep_flag_get(VOID) +{ + return MTK_WCN_BOOL_TRUE; +} + +static MTK_WCN_BOOL mtk_wcn_soc_aee_dump_flag_get(VOID) +{ + return MTK_WCN_BOOL_FALSE; +} +static MTK_WCN_BOOL mtk_wcn_soc_trigger_assert(VOID) +{ + INT32 ret = 0; + UINT32 u4Res; + UINT32 tstCmdSz = 0; + UINT32 tstEvtSz = 0; + UINT8 tstCmd[64]; + UINT8 tstEvt[64]; + UINT8 WMT_ASSERT_CMD[] = { 0x01, 0x02, 0x01, 0x00, 0x08 }; + UINT8 WMT_ASSERT_EVT[] = { 0x02, 0x02, 0x00, 0x00, 0x00 }; + + WMT_INFO_FUNC("Send Assert command !\n"); + tstCmdSz = osal_sizeof(WMT_ASSERT_CMD); + tstEvtSz = osal_sizeof(WMT_ASSERT_EVT); + osal_memcpy(tstCmd, WMT_ASSERT_CMD, tstCmdSz); + osal_memcpy(tstEvt, WMT_ASSERT_EVT, tstEvtSz); + + ret = wmt_core_tx((PUINT8) tstCmd, tstCmdSz, &u4Res, MTK_WCN_BOOL_FALSE); + if (ret || (u4Res != tstCmdSz)) { + WMT_ERR_FUNC("WMT-CORE: wmt_cmd_test iRet(%d) cmd len err(%d, %d)\n", ret, u4Res, + tstCmdSz); + ret = -1; + } + return (ret == 0); +} + +static INT32 mtk_wcn_soc_ver_check(VOID) +{ + UINT32 hw_ver = 0; + UINT32 fw_ver = 0; + INT32 iret; + const WMT_IC_INFO_S *p_info; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + + /* 1. identify chip versions: HVR(HW_VER) and FVR(FW_VER) */ + WMT_LOUD_FUNC("0x%x: before read hw_ver (hw version)\n", wmt_ic_ops_soc.icId); + iret = wmt_core_reg_rw_raw(0, GEN_HVR, &hw_ver, GEN_VER_MASK); + if (iret) { + WMT_ERR_FUNC("0x%x: read hw_ver fail:%d\n", wmt_ic_ops_soc.icId, iret); + return -2; + } + WMT_DBG_FUNC("0x%x: read hw_ver (hw version) (0x%x)\n", wmt_ic_ops_soc.icId, hw_ver); + + WMT_LOUD_FUNC("0x%x: before fw_ver (rom version)\n", wmt_ic_ops_soc.icId); + wmt_core_reg_rw_raw(0, GEN_FVR, &fw_ver, GEN_VER_MASK); + if (iret) { + WMT_ERR_FUNC("0x%x: read fw_ver fail:%d\n", wmt_ic_ops_soc.icId, iret); + return -2; + } + WMT_DBG_FUNC("0x%x: read fw_ver (rom version) (0x%x)\n", wmt_ic_ops_soc.icId, fw_ver); + + p_info = mtk_wcn_soc_find_wmt_ic_info(hw_ver); + if (p_info == NULL) { + WMT_ERR_FUNC("0x%x: hw_ver(0x%x) find wmt ic info fail\n", wmt_ic_ops_soc.icId, hw_ver); + return -3; + } + WMT_WARN_FUNC("0x%x: ic info: %s.%s (0x%x/0x%x, HWVER:0x%04x, patch_ext:%s)\n", + wmt_ic_ops_soc.icId, p_info->cChipName, p_info->cChipVersion, + hw_ver, fw_ver, p_info->u4HwVer, p_info->cPatchNameExt); + + /* hw id & version */ + ctrlPa1 = (wmt_ic_ops_soc.icId << 16) | (hw_ver & 0x0000FFFF); + /* translated fw rom version */ + ctrlPa2 = (fw_ver & 0x0000FFFF); + + iret = wmt_core_ctrl(WMT_CTRL_HWIDVER_SET, &ctrlPa1, &ctrlPa2); + if (iret) + WMT_WARN_FUNC("0x%x: WMT_CTRL_HWIDVER_SET fail(%d)\n", wmt_ic_ops_soc.icId, iret); + + gp_soc_info = p_info; + return 0; +} + +static const WMT_IC_INFO_S *mtk_wcn_soc_find_wmt_ic_info(const UINT32 hw_ver) +{ + /* match chipversion with u4HwVer item in mtk_wcn_soc_info_table */ + const UINT32 size = osal_array_size(mtk_wcn_soc_info_table); + INT32 index = 0; + + /* George: reverse the search order to favor newer version products + * TODO:[FixMe][GeorgeKuo] Remove full match once API wmt_lib_get_hwver() + * is changed correctly in the future!! + * Leave full match here is a workaround for GPS to distinguish E3/E4 ICs. + */ + index = size - 1; + /* full match */ + while ((index >= 0) && (hw_ver != mtk_wcn_soc_info_table[index].u4HwVer)) + --index; + if (index >= 0) { + WMT_DBG_FUNC("found ic info(0x%x) by full match! index:%d\n", hw_ver, index); + return &mtk_wcn_soc_info_table[index]; + } + + WMT_WARN_FUNC("find no ic info for (0x%x) by full match!try major num match!\n", hw_ver); + + /* George: The ONLY CORRECT method to find supported hw table. Match MAJOR + * NUM only can help us support future minor hw ECO, or fab switch, etc. + * FULL matching eliminate such flexibility and software package have to be + * updated EACH TIME even when minor hw ECO or fab switch!!! + */ + /* George: reverse the search order to favor newer version products */ + index = size - 1; + /* major num match */ + while ((index >= 0) && + (MAJORNUM(hw_ver) != MAJORNUM(mtk_wcn_soc_info_table[index].u4HwVer))) { + --index; + } + if (index >= 0) { + WMT_DBG_FUNC("0x%x: found ic info for hw_ver(0x%x) by major num! index:%d\n", + wmt_ic_ops_soc.icId, hw_ver, index); + return &mtk_wcn_soc_info_table[index]; + } + + WMT_ERR_FUNC("0x%x: find no ic info for hw_ver(0x%x) by full match nor major num match!\n", + wmt_ic_ops_soc.icId, hw_ver); + WMT_ERR_FUNC("Set default chip version: E1!\n"); + return &mtk_wcn_soc_info_table[0]; +} + +#if CFG_WMT_FILTER_MODE_SETTING +static INT32 wmt_stp_wifi_lte_coex(VOID) +{ + INT32 iRet; + unsigned long addr = 0; + WMT_GEN_CONF *pWmtGenConf; + + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + osal_sleep_ms(5); + + if (pWmtGenConf->coex_wmt_filter_mode == 0) { + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_BEFORE_SET_WIFI_LTE_COEX); + if ((wmt_ic_ops_soc.icId == 0x6752) || + (wmt_ic_ops_soc.icId == 0x6580) || + (wmt_ic_ops_soc.icId == 0x8163) || + (wmt_ic_ops_soc.icId == 0x0326) || + (wmt_ic_ops_soc.icId == 0x0551) || + (wmt_ic_ops_soc.icId == 0x0699) || + (wmt_ic_ops_soc.icId == 0x0321) || + (wmt_ic_ops_soc.icId == 0x0335) || + (wmt_ic_ops_soc.icId == 0x0337) || + (wmt_ic_ops_soc.icId == 0x0633)) { + iRet = + wmt_core_init_script(set_wifi_lte_coex_table_1, osal_array_size(set_wifi_lte_coex_table_1)); + WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_1 %s(%d)\n", iRet ? "fail" : "ok", iRet); + } else if (wmt_ic_ops_soc.icId == 0x0279 || + wmt_ic_ops_soc.icId == 0x0507 || + wmt_ic_ops_soc.icId == 0x0713 || + wmt_ic_ops_soc.icId == 0x0788 || + wmt_ic_ops_soc.icId == 0x0688) { + /* add WMT_COXE_CONFIG_EXT_COMPONENT_OPCODE command for 2G4 eLNA demand*/ + if (pWmtGenConf->coex_wmt_ext_component) { + WMT_INFO_FUNC("coex_wmt_ext_component:0x%x\n", pWmtGenConf->coex_wmt_ext_component); + set_wifi_lte_coex_table_2[0].cmd[5] = pWmtGenConf->coex_wmt_ext_component; + } + iRet = + wmt_core_init_script(set_wifi_lte_coex_table_2, osal_array_size(set_wifi_lte_coex_table_2)); + WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_2 %s(%d)\n", iRet ? "fail" : "ok", iRet); + } else if (wmt_ic_ops_soc.icId == 0x6765 || + wmt_ic_ops_soc.icId == 0x3967 || + wmt_ic_ops_soc.icId == 0x6761 || + wmt_ic_ops_soc.icId == 0x6768 || + wmt_ic_ops_soc.icId == 0x6779 || + wmt_ic_ops_soc.icId == 0x6785 || + wmt_ic_ops_soc.icId == 0x8168) { + iRet = + wmt_core_init_script(set_wifi_lte_coex_table_3, + osal_array_size(set_wifi_lte_coex_table_3)); + WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_3 %s(%d)\n", + iRet ? "fail" : "ok", iRet); + } else { + iRet = + wmt_core_init_script(set_wifi_lte_coex_table_0, osal_array_size(set_wifi_lte_coex_table_0)); + WMT_DBG_FUNC("wmt_core:set_wifi_lte_coex_table_0 %s(%d)\n", iRet ? "fail" : "ok", iRet); + } + } + + return iRet; +} +#endif + +static INT32 wmt_stp_init_coex(VOID) +{ + INT32 iRet; + unsigned long addr = 0; + WMT_GEN_CONF *pWmtGenConf; + +#define COEX_WMT 0 + +#if CFG_SUBSYS_COEX_NEED + /* no need for MT6628 */ +#define COEX_BT 1 +#define COEX_WIFI 2 +#define COEX_PTA 3 +#define COEX_MISC 4 +#else +#define COEX_WIFI_PATH 1 +#define COEX_EXT_ELAN_GAIN_P1 2 +#define COEX_EXT_EPA_MODE 3 +#endif +#define WMT_COXE_CONFIG_ADJUST_ANTENNA_OPCODE 6 + + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + if (wmt_ic_ops_soc.icId == 0x6765 || + wmt_ic_ops_soc.icId == 0x6761 || + wmt_ic_ops_soc.icId == 0x6768 || + wmt_ic_ops_soc.icId == 0x6785) { + WMT_INFO_FUNC("elna_gain_p1_support:0x%x\n", pWmtGenConf->coex_wmt_ext_elna_gain_p1_support); + if (pWmtGenConf->coex_wmt_ext_elna_gain_p1_support != 1) + return 0; + } + + /*Dump the coex-related info */ + WMT_DBG_FUNC("coex_wmt_ant_mode:0x%x, coex_wmt_wifi_path:0x%x\n", + pWmtGenConf->coex_wmt_ant_mode, pWmtGenConf->coex_wmt_wifi_path); +#if CFG_SUBSYS_COEX_NEED + WMT_DBG_FUNC("coex_bt:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_bt_rssi_upper_limit, + pWmtGenConf->coex_bt_rssi_mid_limit, + pWmtGenConf->coex_bt_rssi_lower_limit, + pWmtGenConf->coex_bt_pwr_high, pWmtGenConf->coex_bt_pwr_mid, pWmtGenConf->coex_bt_pwr_low); + WMT_DBG_FUNC("coex_wifi:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_wifi_rssi_upper_limit, + pWmtGenConf->coex_wifi_rssi_mid_limit, + pWmtGenConf->coex_wifi_rssi_lower_limit, + pWmtGenConf->coex_wifi_pwr_high, pWmtGenConf->coex_wifi_pwr_mid, pWmtGenConf->coex_wifi_pwr_low); + WMT_DBG_FUNC("coex_ext_pta:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_ext_pta_hi_tx_tag, + pWmtGenConf->coex_ext_pta_hi_rx_tag, + pWmtGenConf->coex_ext_pta_lo_tx_tag, + pWmtGenConf->coex_ext_pta_lo_rx_tag, + pWmtGenConf->coex_ext_pta_sample_t1, + pWmtGenConf->coex_ext_pta_sample_t2, pWmtGenConf->coex_ext_pta_wifi_bt_con_trx); + WMT_DBG_FUNC("coex_misc:0x%x 0x%x 0x%x\n", + pWmtGenConf->coex_misc_ext_pta_on, pWmtGenConf->coex_misc_ext_feature_set); +#endif + + /*command adjustion due to WMT.cfg */ + coex_table[COEX_WMT].cmd[4] = WMT_COXE_CONFIG_ADJUST_ANTENNA_OPCODE; + coex_table[COEX_WMT].cmd[5] = pWmtGenConf->coex_wmt_ant_mode; + if (gWmtDbgLvl >= WMT_LOG_DBG) + wmt_core_dump_data(&coex_table[COEX_WMT].cmd[0], coex_table[COEX_WMT].str, coex_table[COEX_WMT].cmdSz); + +#if CFG_SUBSYS_COEX_NEED + coex_table[COEX_BT].cmd[9] = pWmtGenConf->coex_bt_rssi_upper_limit; + coex_table[COEX_BT].cmd[10] = pWmtGenConf->coex_bt_rssi_mid_limit; + coex_table[COEX_BT].cmd[11] = pWmtGenConf->coex_bt_rssi_lower_limit; + coex_table[COEX_BT].cmd[12] = pWmtGenConf->coex_bt_pwr_high; + coex_table[COEX_BT].cmd[13] = pWmtGenConf->coex_bt_pwr_mid; + coex_table[COEX_BT].cmd[14] = pWmtGenConf->coex_bt_pwr_low; + if (gWmtDbgLvl >= WMT_LOG_DBG) + wmt_core_dump_data(&coex_table[COEX_BT].cmd[0], coex_table[COEX_BT].str, coex_table[COEX_BT].cmdSz); + + coex_table[COEX_WIFI].cmd[10] = pWmtGenConf->coex_wifi_rssi_upper_limit; + coex_table[COEX_WIFI].cmd[11] = pWmtGenConf->coex_wifi_rssi_mid_limit; + coex_table[COEX_WIFI].cmd[12] = pWmtGenConf->coex_wifi_rssi_lower_limit; + coex_table[COEX_WIFI].cmd[13] = pWmtGenConf->coex_wifi_pwr_high; + coex_table[COEX_WIFI].cmd[14] = pWmtGenConf->coex_wifi_pwr_mid; + coex_table[COEX_WIFI].cmd[15] = pWmtGenConf->coex_wifi_pwr_low; + if (gWmtDbgLvl >= WMT_LOG_DBG) + wmt_core_dump_data(&coex_table[COEX_WIFI].cmd[0], + coex_table[COEX_WIFI].str, coex_table[COEX_WIFI].cmdSz); + + coex_table[COEX_PTA].cmd[5] = pWmtGenConf->coex_ext_pta_hi_tx_tag; + coex_table[COEX_PTA].cmd[6] = pWmtGenConf->coex_ext_pta_hi_rx_tag; + coex_table[COEX_PTA].cmd[7] = pWmtGenConf->coex_ext_pta_lo_tx_tag; + coex_table[COEX_PTA].cmd[8] = pWmtGenConf->coex_ext_pta_lo_rx_tag; + coex_table[COEX_PTA].cmd[9] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0xff00) >> 8); + coex_table[COEX_PTA].cmd[10] = ((pWmtGenConf->coex_ext_pta_sample_t1 & 0x00ff) >> 0); + coex_table[COEX_PTA].cmd[11] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0xff00) >> 8); + coex_table[COEX_PTA].cmd[12] = ((pWmtGenConf->coex_ext_pta_sample_t2 & 0x00ff) >> 0); + coex_table[COEX_PTA].cmd[13] = pWmtGenConf->coex_ext_pta_wifi_bt_con_trx; + if (gWmtDbgLvl >= WMT_LOG_DBG) + wmt_core_dump_data(&coex_table[COEX_PTA].cmd[0], coex_table[COEX_PTA].str, coex_table[COEX_PTA].cmdSz); + + osal_memcpy(&coex_table[COEX_MISC].cmd[5], &pWmtGenConf->coex_misc_ext_pta_on, + sizeof(pWmtGenConf->coex_misc_ext_pta_on)); + osal_memcpy(&coex_table[COEX_MISC].cmd[9], &pWmtGenConf->coex_misc_ext_feature_set, + sizeof(pWmtGenConf->coex_misc_ext_feature_set)); + + wmt_core_dump_data(&coex_table[COEX_MISC].cmd[0], coex_table[COEX_MISC].str, coex_table[COEX_MISC].cmdSz); +#else + coex_table[COEX_WIFI_PATH].cmd[5] = + (UINT8)((pWmtGenConf->coex_wmt_wifi_path & 0x00FF) >> 0); + coex_table[COEX_WIFI_PATH].cmd[6] = + (UINT8)((pWmtGenConf->coex_wmt_wifi_path & 0xFF00) >> 8); + + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_WIFI_PATH].cmd[0], + coex_table[COEX_WIFI_PATH].str, coex_table[COEX_WIFI_PATH].cmdSz); + } + + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[5] = pWmtGenConf->coex_wmt_ext_elna_gain_p1_support; + /* wmt_ext_elna_gain_p1 D0*/ + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[6] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0x000000FF) >> 0); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[7] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0x0000FF00) >> 8); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[8] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0x00FF0000) >> 16); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[9] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D0 & 0xFF000000) >> 24); + /* wmt_ext_elna_gain_p1 D1*/ + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[10] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0x000000FF) >> 0); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[11] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0x0000FF00) >> 8); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[12] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0x00FF0000) >> 16); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[13] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D1 & 0xFF000000) >> 24); + /* wmt_ext_elna_gain_p1 D2*/ + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[14] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0x000000FF) >> 0); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[15] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0x0000FF00) >> 8); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[16] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0x00FF0000) >> 16); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[17] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D2 & 0xFF000000) >> 24); + /* wmt_ext_elna_gain_p1 D3*/ + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[18] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0x000000FF) >> 0); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[19] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0x0000FF00) >> 8); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[20] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0x00FF0000) >> 16); + coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[21] = + (UINT8)((pWmtGenConf->coex_wmt_ext_elna_gain_p1_D3 & 0xFF000000) >> 24); + + if (gWmtDbgLvl >= WMT_LOG_DBG) { + wmt_core_dump_data(&coex_table[COEX_EXT_ELAN_GAIN_P1].cmd[0], + coex_table[COEX_EXT_ELAN_GAIN_P1].str, + coex_table[COEX_EXT_ELAN_GAIN_P1].cmdSz); + } + + coex_table[COEX_EXT_EPA_MODE].cmd[5] = pWmtGenConf->coex_wmt_ext_epa_mode; +#endif + + iRet = wmt_core_init_script(coex_table, ARRAY_SIZE(coex_table)); + + return iRet; +} + +static INT32 wmt_stp_init_epa(VOID) +{ + INT32 iRet; + unsigned long addr = 0; + WMT_GEN_CONF *pWmtGenConf; + + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_DBG_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + WMT_INFO_FUNC("epa_mode:0x%x\n", pWmtGenConf->coex_wmt_ant_mode_ex); + + if (pWmtGenConf->coex_wmt_ant_mode_ex != 1) + return 0; + + epa_table[0].cmd[5] = pWmtGenConf->coex_wmt_ant_mode_ex; + if (gWmtDbgLvl >= WMT_LOG_DBG) + wmt_core_dump_data(&epa_table[0].cmd[0], epa_table[0].str, epa_table[0].cmdSz); + iRet = wmt_core_init_script(epa_table, ARRAY_SIZE(epa_table)); + + return iRet; +} + +static INT32 wmt_stp_init_epa_elna(VOID) +{ + INT32 iRet; + unsigned long addr = 0; + WMT_GEN_CONF *pWmtGenConf; + struct init_script script[1]; + struct WMT_BYTE_ARRAY *ba; + INT32 cmd_size; + INT32 data_size; + PUINT8 cmd; + UINT16 index = 0; + + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_DBG_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + if (pWmtGenConf->coex_wmt_epa_elna == NULL) + return 0; + + ba = pWmtGenConf->coex_wmt_epa_elna; + + /* cmd_size = direction(1) + op(1) + length(2) + coex op(1) + data */ + cmd_size = ba->size + 5; + cmd = (PUINT8)osal_malloc(cmd_size); + + if (cmd == NULL) { + WMT_ERR_FUNC("failed to malloc when init epa elna\n"); + return -1; + } + + /* 0x1: direction, 0x10: op code */ + cmd[index++] = 0x1; + cmd[index++] = 0x10; + + /* add 1 for coex op id */ + data_size = ba->size + 1; + /* assign data length */ + cmd[index++] = (data_size & 0x00FF) >> 0; + cmd[index++] = (data_size & 0xFF00) >> 8; + /* assign coex op id: 0x1D */ + cmd[index++] = 0x1D; + + osal_memcpy(&cmd[index], ba->data, ba->size); + + script[0].cmd = cmd; + script[0].cmdSz = cmd_size; + script[0].evt = WMT_EPA_ELNA_SETTING_CONFIG_EVT; + script[0].evtSz = sizeof(WMT_EPA_ELNA_SETTING_CONFIG_EVT); + script[0].str = "coex_wmt_epa_elna"; + + if (gWmtDbgLvl >= WMT_LOG_DBG) + wmt_core_dump_data(&(script[0].cmd[0]), script[0].str, + script[0].cmdSz); + + iRet = wmt_core_init_script(script, ARRAY_SIZE(script)); + + osal_free(cmd); + return iRet; +} + +static INT32 wmt_stp_init_epa_elna_invert_cr(VOID) +{ + INT32 iRet; + UINT32 uVal = 0; + unsigned long addr = 0; + WMT_GEN_CONF *pWmtGenConf; + UINT32 default_invert_cr[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + UINT32 default_invert_bit[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + PINT8 pbuf; + long res = 0; + PINT8 tok1, tok2; + UINT32 item1, item2, item_index; + UINT32 invert_cr, invert_bit; + + mtk_wcn_consys_ic_get_ant_sel_cr_addr(default_invert_cr, default_invert_bit); + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_DBG_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + WMT_DBG_FUNC("pWmtGenConf->coex_wmt_antsel_invert_support=[%s]\n", + pWmtGenConf->coex_wmt_antsel_invert_support); + + if (pWmtGenConf->coex_wmt_antsel_invert_support == NULL || + osal_strlen(pWmtGenConf->coex_wmt_antsel_invert_support) <= 0) + return 0; + + pbuf = osal_malloc(osal_strlen(pWmtGenConf->coex_wmt_antsel_invert_support)+1); + if (pbuf == NULL) { + WMT_ERR_FUNC("init_invert_cr, malloc fail, size %d\n", + osal_strlen(pWmtGenConf->coex_wmt_antsel_invert_support)+1); + return -1; + } + + osal_strcpy(pbuf, pWmtGenConf->coex_wmt_antsel_invert_support); + + while ((tok1 = osal_strsep(&pbuf, " /\\")) != NULL) { + if (*tok1 == '\0') + continue; + if (!*tok1) + continue; + item1 = 0; + item2 = 0; + item_index = 0; + while ((tok2 = osal_strsep(&tok1, " ,")) != NULL) { + if (*tok2 == '\0') + continue; + if (!*tok2) + continue; + if ((osal_strlen(tok2) > 2) && ((*tok2) == '0') && (*(tok2 + 1) == 'x')) + osal_strtol(tok2 + 2, 16, &res); + else + osal_strtol(tok2, 10, &res); + if (item_index == 0) + item1 = res; + else if (item_index == 1) + item2 = res; + item_index++; + } + + if (item_index != 1 && item_index != 2) + continue; + if ((item_index == 1) && (item1 > 7 || item1 < 0)) + continue; + if ((item_index == 2) && (item2 > 31 || item2 < 0)) + continue; + + if (item_index == 1) { + invert_cr = default_invert_cr[item1]; + invert_bit = default_invert_bit[item1]; + } else if (item_index == 2) { + invert_cr = item1; + invert_bit = item2; + } + + if (invert_cr == 0) + continue; + + uVal = 0; + iRet = wmt_core_reg_rw_raw(0, invert_cr, &uVal, 0xFFFFFFFF); + if (iRet) { + WMT_ERR_FUNC("init_invert_cr, read 0x%x[%d](before write) fail(%d)\n", + invert_cr, invert_bit, iRet); + continue; + } + WMT_DBG_FUNC("init_invert_cr, 0x%x[%d](before write) = 0x%x\n", + invert_cr, invert_bit, uVal); + + uVal = 0x1 << invert_bit; + iRet = wmt_core_reg_rw_raw(1, invert_cr, &uVal, 0x1 << invert_bit); + if (iRet) { + WMT_ERR_FUNC("init_invert_cr, write 0x%x[%d]=1 fail(%d)\n", + invert_cr, invert_bit, iRet); + continue; + } + + uVal = 0; + iRet = wmt_core_reg_rw_raw(0, invert_cr, &uVal, 0xFFFFFFFF); + if (iRet) { + WMT_ERR_FUNC("init_invert_cr, read 0x%x[%d](after write) fail(%d)\n", + invert_cr, invert_bit, iRet); + continue; + } + WMT_DBG_FUNC("init_invert_cr, 0x%x[%d](after write) = 0x%x\n", + invert_cr, invert_bit, uVal); + } + + if (pbuf != NULL) { + osal_free(pbuf); + pbuf = NULL; + } + + return 0; +} + +static INT32 wmt_stp_init_wifi_ant_swap(VOID) +{ + INT32 iRet; + unsigned long addr = 0; + WMT_GEN_CONF *pWmtGenConf; + UINT8 ant_swap_mode, polarity, ant_sel; + + /*Get wmt config */ + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + WMT_DBG_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_DBG_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + ant_swap_mode = pWmtGenConf->wifi_ant_swap_mode; + polarity = pWmtGenConf->wifi_main_ant_polarity; + ant_sel = pWmtGenConf->wifi_ant_swap_ant_sel_gpio; + + WMT_INFO_FUNC("ant swap mode = %d, main_polarity = %d, ant_sel = %d\n", + ant_swap_mode, polarity, ant_sel); + + if (ant_swap_mode <= 0 || ant_swap_mode > 2) + return 0; + + if (ant_swap_mode == 2 && + mtk_consys_is_ant_swap_enable_by_hwid() == 0) + return 0; + + wifi_ant_swap_table[0].cmd[6] = polarity; + + if (ant_sel > 0) + wifi_ant_swap_table[0].cmd[7] = ant_sel; + else { + /* backward compatible */ + wifi_ant_swap_table[0].cmdSz = sizeof(WMT_WIFI_ANT_SWAP_CMD) - 1; + wifi_ant_swap_table[0].cmd[2] = 3; /* length */ + wifi_ant_swap_table[0].cmd[4] = 6; /* op id */ + wifi_ant_swap_table[0].evt[5] = 6; /* op id */ + } + + iRet = wmt_core_init_script(wifi_ant_swap_table, ARRAY_SIZE(wifi_ant_swap_table)); + + return iRet; +} + +#if CFG_WMT_SDIO_DRIVING_SET +static INT32 mtk_wcn_soc_set_sdio_driving(void) +{ + INT32 ret = 0; + + unsigned long addr = 0; + WMT_GEN_CONF *pWmtGenConf; + UINT32 drv_val = 0; + + /*Get wmt config */ + ret = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + if (ret) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", ret); + return -1; + } + WMT_INFO_FUNC("ctrl GET_WMT_CONF ok(0x%08lx)\n", addr); + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + /*Check if WMT.cfg exists */ + if (pWmtGenConf->cfgExist == 0) { + WMT_INFO_FUNC("cfgExist == 0, skip config chip\n"); + /*if WMT.cfg not existed, still return success and adopt the default value */ + return 0; + } + + drv_val = pWmtGenConf->sdio_driving_cfg; + + /*Dump the sdio driving related info */ + WMT_INFO_FUNC("sdio driving:0x%x\n", drv_val); + + sdio_driving_table[0].cmd[12] = (UINT8) ((drv_val & 0x00000077UL) >> 0); /* DAT0 and DAT1 */ + sdio_driving_table[0].cmd[13] = (UINT8) ((drv_val & 0x00007700UL) >> 8); /* DAT2 and DAT3 */ + sdio_driving_table[0].cmd[14] = (UINT8) ((drv_val & 0x00070000UL) >> 16); /* CMD */ + + ret = wmt_core_init_script(sdio_driving_table, ARRAY_SIZE(sdio_driving_table)); + + return ret; +} +#endif + +#if CFG_WMT_CRYSTAL_TIMING_SET +static INT32 mtk_wcn_soc_crystal_triming_set(VOID) +{ + INT32 iRet = 0; + PUINT8 pbuf = NULL; + UINT32 bufLen = 0; + WMT_CTRL_DATA ctrlData; + UINT32 uCryTimOffset = 0x6D; + MTK_WCN_BOOL bIsNvramExist = MTK_WCN_BOOL_FALSE; + INT8 cCrystalTimingOffset = 0x0; + UINT8 cCrystalTiming = 0x0; + INT32 iCrystalTiming = 0x0; + MTK_WCN_BOOL bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + UINT32 u4Res; + + bIsNvramExist = MTK_WCN_BOOL_FALSE; + /**/ ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_GET; + ctrlData.au4CtrlData[0] = (UINT32) "/data/nvram/APCFG/APRDEB/WIFI"; + ctrlData.au4CtrlData[1] = (UINT32) &pbuf; + ctrlData.au4CtrlData[2] = (UINT32) &bufLen; + + iRet = wmt_ctrl(&ctrlData); + if (iRet != 0) { + WMT_ERR_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_GET fail:%d\n", wmt_ic_ops_soc.icId, iRet); + bIsNvramExist = MTK_WCN_BOOL_FALSE; + bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + cCrystalTimingOffset = 0x0; + cCrystalTiming = 0x0; + iRet = -1; + } else { + WMT_DBG_FUNC("0x%x: nvram pBuf(0x%08x), bufLen(%d)\n", wmt_ic_ops_soc.icId, pbuf, bufLen); + if (bufLen < (uCryTimOffset + 1)) { + WMT_ERR_FUNC("0x%x: nvram len(%d) too short, crystalTimging value offset(%d)\n", + wmt_ic_ops_soc.icId, bufLen, uCryTimOffset); + bIsNvramExist = MTK_WCN_BOOL_FALSE; + bIsCrysTrimEnabled = MTK_WCN_BOOL_FALSE; + cCrystalTimingOffset = 0x0; + cCrystalTiming = 0x0; + } else { + bIsNvramExist = MTK_WCN_BOOL_TRUE; + cCrystalTimingOffset = *(pbuf + uCryTimOffset); + if (cCrystalTimingOffset & 0x80) { + bIsCrysTrimEnabled = MTK_WCN_BOOL_TRUE; + cCrystalTimingOffset = (UINT8) cCrystalTimingOffset & 0x7f; + } + WMT_DBG_FUNC("cCrystalTimingOffset (%d), bIsCrysTrimEnabled(%d)\n", cCrystalTimingOffset, + bIsCrysTrimEnabled); + } + ctrlData.ctrlId = WMT_CTRL_CRYSTAL_TRIMING_PUT; + ctrlData.au4CtrlData[0] = (UINT32) "/data/nvram/APCFG/APRDEB/WIFI"; + iRet = wmt_ctrl(&ctrlData); + if (iRet != 0) { + WMT_ERR_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_PUT fail:%d\n", wmt_ic_ops_soc.icId, iRet); + iRet = -2; + } else { + WMT_DBG_FUNC("0x%x: WMT_CTRL_CRYSTAL_TRIMING_PUT succeed\n", wmt_ic_ops_soc.icId); + } + } + if ((bIsNvramExist == MTK_WCN_BOOL_TRUE) && (bIsCrysTrimEnabled == MTK_WCN_BOOL_TRUE)) { + /*get CrystalTiming value before set it */ + iRet = + wmt_core_tx(get_crystal_timing_script[0].cmd, get_crystal_timing_script[0].cmdSz, &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != get_crystal_timing_script[0].cmdSz)) { + WMT_ERR_FUNC("WMT-CORE: write (%s) iRet(%d) cmd len err(%d, %d)\n", + get_crystal_timing_script[0].str, iRet, u4Res, get_crystal_timing_script[0].cmdSz); + iRet = -3; + goto done; + } + /* EVENT BUF */ + osal_memset(get_crystal_timing_script[0].evt, 0, get_crystal_timing_script[0].evtSz); + iRet = wmt_core_rx(get_crystal_timing_script[0].evt, get_crystal_timing_script[0].evtSz, &u4Res); + if (iRet || (u4Res != get_crystal_timing_script[0].evtSz)) { + WMT_ERR_FUNC("WMT-CORE: read (%s) iRet(%d) evt len err(rx:%d, exp:%d)\n", + get_crystal_timing_script[0].str, iRet, u4Res, get_crystal_timing_script[0].evtSz); + mtk_wcn_stp_dbg_dump_package(); + iRet = -4; + goto done; + } + + iCrystalTiming = WMT_GET_CRYSTAL_TRIMING_EVT[5] & 0x7f; + if (cCrystalTimingOffset & 0x40) { + /*nagative offset value */ + iCrystalTiming = iCrystalTiming + cCrystalTimingOffset - 128; + } else { + iCrystalTiming += cCrystalTimingOffset; + } + WMT_DBG_FUNC("iCrystalTiming (0x%x)\n", iCrystalTiming); + if (iCrystalTiming > 0x7f) + cCrystalTiming = 0x7f; + else if (iCrystalTiming < 0) + cCrystalTiming = 0; + else + cCrystalTiming = iCrystalTiming; + WMT_DBG_FUNC("cCrystalTiming (0x%x)\n", cCrystalTiming); + /* set_crystal_timing_script */ + WMT_SET_CRYSTAL_TRIMING_CMD[5] = cCrystalTiming; + WMT_GET_CRYSTAL_TRIMING_EVT[5] = cCrystalTiming; + + iRet = wmt_core_init_script(set_crystal_timing_script, osal_array_size(set_crystal_timing_script)); + if (iRet) { + WMT_ERR_FUNC("set_crystal_timing_script fail(%d)\n", iRet); + iRet = -5; + } else { + WMT_DBG_FUNC("set crystal timing value (0x%x) succeed\n", WMT_SET_CRYSTAL_TRIMING_CMD[5]); + iRet = + wmt_core_init_script(get_crystal_timing_script, osal_array_size(get_crystal_timing_script)); + if (iRet) { + WMT_ERR_FUNC("get_crystal_timing_script fail(%d)\n", iRet); + iRet = -6; + } else { + WMT_INFO_FUNC("succeed, updated crystal timing value (0x%x)\n", + WMT_GET_CRYSTAL_TRIMING_EVT[5]); + iRet = 0x0; + } + } + } +done: + return iRet; +} +#endif + +#if CFG_WMT_MULTI_PATCH +static INT32 mtk_wcn_soc_patch_info_prepare(VOID) +{ + INT32 iRet = -1; + WMT_CTRL_DATA ctrlData; + + ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; + iRet = wmt_ctrl(&ctrlData); + + return iRet; +} + +static UINT32 mtk_wcn_soc_get_patch_num(VOID) +{ + ULONG ctrlPa1 = 0; + ULONG ctrlPa2 = 0; + + wmt_core_ctrl(WMT_CTRL_GET_PATCH_NUM, &ctrlPa1, &ctrlPa2); + WMT_DBG_FUNC("patch total num = [%lu]\n", ctrlPa1); + return ctrlPa1; +} + +static UINT32 mtk_wcn_soc_update_patch_version(VOID) +{ + return wmt_core_ctrl(WMT_CTRL_UPDATE_PATCH_VERSION, NULL, NULL); +} + +static INT32 mtk_wcn_soc_normal_patch_dwn(PUINT8 pPatchBuf, UINT32 patchSize, PUINT8 addressByte) +{ + INT32 iRet = -1; + UINT32 patchSizePerFrag = 0; + UINT32 fragSeq; + UINT32 fragNum; + UINT16 fragSize = 0; + UINT16 cmdLen; + UINT32 offset; + UINT32 u4Res; + UINT8 evtBuf[8]; + UINT8 addressevtBuf[12]; + + patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; + /* reserve 1st patch cmd space before patch body + * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| + */ + pPatchBuf -= sizeof(WMT_PATCH_CMD); + + fragNum = patchSize / patchSizePerFrag; + fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; + + WMT_INFO_FUNC("normal patch download patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + /*send wmt part patch address command */ + if (wmt_ic_ops_soc.icId == 0x6752 || + wmt_ic_ops_soc.icId == 0x8127 || + wmt_ic_ops_soc.icId == 0x7623 || + wmt_ic_ops_soc.icId == 0x6571 || + wmt_ic_ops_soc.icId == 0x0326 || + wmt_ic_ops_soc.icId == 0x0551 || + wmt_ic_ops_soc.icId == 0x0690 || + wmt_ic_ops_soc.icId == 0x0699 || + wmt_ic_ops_soc.icId == 0x0321 || + wmt_ic_ops_soc.icId == 0x0335 || + wmt_ic_ops_soc.icId == 0x0337 || + wmt_ic_ops_soc.icId == 0x8163 || + wmt_ic_ops_soc.icId == 0x6580 || + wmt_ic_ops_soc.icId == 0x8167 || + wmt_ic_ops_soc.icId == 0x0633) { + /* ROMv2 patch RAM base */ + WMT_PATCH_ADDRESS_CMD[8] = 0x40; + WMT_PATCH_P_ADDRESS_CMD[8] = 0xc8; + } + /*send wmt part patch address command */ + if (wmt_ic_ops_soc.icId == 0x0279) { + /* ROMv3 patch RAM base */ + WMT_PATCH_ADDRESS_CMD[8] = 0x08; + WMT_PATCH_ADDRESS_CMD[9] = 0x05; + WMT_PATCH_P_ADDRESS_CMD[8] = 0x2c; + WMT_PATCH_P_ADDRESS_CMD[9] = 0x0b; + } + + if (wmt_ic_ops_soc.icId == 0x0507 || + wmt_ic_ops_soc.icId == 0x0713 || + wmt_ic_ops_soc.icId == 0x0788 || + wmt_ic_ops_soc.icId == 0x0688) { + /* ROMv4 patch RAM base */ + WMT_PATCH_ADDRESS_CMD[8] = 0x18; + WMT_PATCH_ADDRESS_CMD[9] = 0x05; + WMT_PATCH_P_ADDRESS_CMD[8] = 0x7c; + WMT_PATCH_P_ADDRESS_CMD[9] = 0x0b; + } + + if (wmt_ic_ops_soc.icId == 0x6765 || + wmt_ic_ops_soc.icId == 0x3967 || + wmt_ic_ops_soc.icId == 0x6761 || + wmt_ic_ops_soc.icId == 0x6768 || + wmt_ic_ops_soc.icId == 0x6779 || + wmt_ic_ops_soc.icId == 0x6785 || + wmt_ic_ops_soc.icId == 0x8168) { + /*send part patch address command */ + WMT_PATCH_ADDRESS_CMD_NEW[5] = addressByte[0]; + WMT_PATCH_ADDRESS_CMD_NEW[6] = addressByte[1]; + WMT_PATCH_ADDRESS_CMD_NEW[7] = addressByte[2]; + WMT_PATCH_ADDRESS_CMD_NEW[8] = addressByte[3]; + WMT_DBG_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x", + WMT_PATCH_ADDRESS_CMD_NEW[5], + WMT_PATCH_ADDRESS_CMD_NEW[6], + WMT_PATCH_ADDRESS_CMD_NEW[7], + WMT_PATCH_ADDRESS_CMD_NEW[8]); + iRet = wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD_NEW[0], sizeof(WMT_PATCH_ADDRESS_CMD_NEW), + &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD_NEW))) { + WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d)\n", iRet, u4Res); + return -1; + } + osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); + iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT_NEW), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT_NEW))) { + WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res); + WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n", + addressevtBuf[0], addressevtBuf[1], addressevtBuf[2], + addressevtBuf[3], addressevtBuf[4], + WMT_PATCH_ADDRESS_EVT_NEW[0], WMT_PATCH_ADDRESS_EVT_NEW[1], + WMT_PATCH_ADDRESS_EVT_NEW[2], WMT_PATCH_ADDRESS_EVT_NEW[3], + WMT_PATCH_ADDRESS_EVT_NEW[4]); + mtk_wcn_stp_dbg_dump_package(); + return -1; + } + goto patch_download; + } + + /*send wmt part patch address command */ + iRet = + wmt_core_tx((PUINT8) &WMT_PATCH_ADDRESS_CMD[0], sizeof(WMT_PATCH_ADDRESS_CMD), &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_CMD))) { + WMT_ERR_FUNC("wmt_core:wmt patch address CMD fail(%d),size(%d)\n", iRet, u4Res); + return -1; + } + osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); + iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_ADDRESS_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_ADDRESS_EVT))) { + WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res); + mtk_wcn_stp_dbg_dump_package(); + return -1; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(addressevtBuf, WMT_PATCH_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail\n"); + return -1; + } +#endif + + /*send part patch address command */ + WMT_PATCH_P_ADDRESS_CMD[12] = addressByte[0]; + WMT_PATCH_P_ADDRESS_CMD[13] = addressByte[1]; + WMT_PATCH_P_ADDRESS_CMD[14] = addressByte[2]; + WMT_PATCH_P_ADDRESS_CMD[15] = addressByte[3]; + WMT_DBG_FUNC("4 bytes address command:0x%02x,0x%02x,0x%02x,0x%02x", + WMT_PATCH_P_ADDRESS_CMD[12], + WMT_PATCH_P_ADDRESS_CMD[13], WMT_PATCH_P_ADDRESS_CMD[14], WMT_PATCH_P_ADDRESS_CMD[15]); + iRet = + wmt_core_tx((PUINT8) &WMT_PATCH_P_ADDRESS_CMD[0], sizeof(WMT_PATCH_P_ADDRESS_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_CMD))) { + WMT_ERR_FUNC("wmt_core:wmt part patch address CMD fail(%d),size(%d)\n", iRet, u4Res); + return -1; + } + osal_memset(addressevtBuf, 0, sizeof(addressevtBuf)); + iRet = wmt_core_rx(addressevtBuf, sizeof(WMT_PATCH_P_ADDRESS_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_P_ADDRESS_EVT))) { + WMT_ERR_FUNC("wmt_core:wmt patch address EVT fail(%d),size(%d)\n", iRet, u4Res); + mtk_wcn_stp_dbg_dump_package(); + return -1; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(addressevtBuf, WMT_PATCH_P_ADDRESS_EVT, osal_sizeof(WMT_PATCH_ADDRESS_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: write WMT_PATCH_ADDRESS_CMD status fail\n"); + return -1; + } +#endif + +patch_download: + /* send all fragments */ + offset = sizeof(WMT_PATCH_CMD); + fragSeq = 0; + while (fragSeq < fragNum) { + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + if (fragSeq == (fragNum - 1)) { + /* last fragment */ + fragSize = patchSize - fragSeq * patchSizePerFrag; + WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; + } else { + fragSize = patchSizePerFrag; + WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; + } + /* update length field in CMD:flag+frag */ + cmdLen = 1 + fragSize; + osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); + /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ + osal_memcpy(pPatchBuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, sizeof(WMT_PATCH_CMD)); + + /* iRet = + *(*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), + *&u4Res); + */ + iRet = + wmt_core_tx(pPatchBuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), + &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%lu, %d) fail(%d)\n", fragSeq, + fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); + iRet = -1; + break; + } + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%lu, %d) ok\n", + fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); + + osal_memset(evtBuf, 0, sizeof(evtBuf)); + /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ + iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%lu, %d) fail(%d)\n", sizeof(WMT_PATCH_EVT), + u4Res, iRet); + mtk_wcn_stp_dbg_dump_package(); + iRet = -1; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_PATCH_EVT error rx(%d):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, + evtBuf[0], + evtBuf[1], + evtBuf[2], + evtBuf[3], + evtBuf[4]); + WMT_ERR_FUNC("wmt_core: exp(%lu):[%02X,%02X,%02X,%02X,%02X]\n", + sizeof(WMT_PATCH_EVT), + WMT_PATCH_EVT[0], + WMT_PATCH_EVT[1], + WMT_PATCH_EVT[2], + WMT_PATCH_EVT[3], + WMT_PATCH_EVT[4]); + iRet = -1; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%lu, %d) ok\n", sizeof(WMT_PATCH_EVT), u4Res); + offset += patchSizePerFrag; + ++fragSeq; + } + + WMT_WARN_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", + iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); + + if (fragSeq != fragNum) + return -1; + + return 0; +} + +static INT32 mtk_wcn_soc_pda_patch_dwn(PUINT8 pPatchBuf, UINT32 patchSize, PUINT8 addressByte) +{ +#define PDAHDRLEN 12 + UINT32 u4Res; + UINT8 evtBuf[8]; + INT32 iRet = -1; + UINT32 fragSeq; + UINT32 fragNum; + UINT16 fragSize = 0; + UINT32 patchSizePerFrag = 0; + UINT32 offset; + UINT8 pdaHdr[PDAHDRLEN]; + + /* PDA download address, LSB */ + WMT_PATCH_PDA_CFG_CMD[5] = addressByte[0]; + WMT_PATCH_PDA_CFG_CMD[6] = addressByte[1]; + WMT_PATCH_PDA_CFG_CMD[7] = addressByte[2]; + WMT_PATCH_PDA_CFG_CMD[8] = addressByte[3]; + + /* PDA download size, LSB */ + WMT_PATCH_PDA_CFG_CMD[9] = (patchSize & 0x000000FF); + WMT_PATCH_PDA_CFG_CMD[10] = (patchSize & 0x0000FF00) >> 8; + WMT_PATCH_PDA_CFG_CMD[11] = (patchSize & 0x00FF0000) >> 16; + WMT_PATCH_PDA_CFG_CMD[12] = (patchSize & 0xFF000000) >> 24; + + iRet = wmt_core_tx((PUINT8) &WMT_PATCH_PDA_CFG_CMD[0], sizeof(WMT_PATCH_PDA_CFG_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != sizeof(WMT_PATCH_PDA_CFG_CMD))) { + WMT_ERR_FUNC("wmt_core:wmt part patch PDA config CMD fail(%d),size(%d)\n", + iRet, u4Res); + return -1; + } + osal_memset(evtBuf, 0, sizeof(evtBuf)); + iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_PDA_CFG_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_PDA_CFG_EVT))) { + WMT_ERR_FUNC("wmt_core:wmt patch PDA config EVT fail(%d),size(%d)\n", + iRet, u4Res); + WMT_INFO_FUNC("buf:[%2X,%2X,%2X,%2X,%2X] evt:[%2X,%2X,%2X,%2X,%2X]\n", + evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], + WMT_PATCH_PDA_CFG_EVT[0], WMT_PATCH_PDA_CFG_EVT[1], + WMT_PATCH_PDA_CFG_EVT[2], WMT_PATCH_PDA_CFG_EVT[3], + WMT_PATCH_PDA_CFG_EVT[4]); + mtk_wcn_stp_dbg_dump_package(); + return -1; + } + + patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; + fragNum = patchSize / patchSizePerFrag; + fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; + + osal_memset(pdaHdr, 0, PDAHDRLEN); + pdaHdr[0] = (patchSize + PDAHDRLEN) & 0x000000FF; + pdaHdr[1] = ((patchSize + PDAHDRLEN) & 0x0000FF00) >> 8; + pdaHdr[2] = ((patchSize + PDAHDRLEN) & 0x00FF0000) >> 16; + pdaHdr[3] = ((patchSize + PDAHDRLEN) & 0xFF000000) >> 24; + + iRet = wmt_core_tx(pdaHdr, PDAHDRLEN, &u4Res, MTK_WCN_BOOL_TRUE); + if (iRet || (u4Res != PDAHDRLEN)) { + WMT_ERR_FUNC("wmt_core: set length:%d fails, u4Res:%d\n", PDAHDRLEN, u4Res); + return -1; + } + + /* send all fragments */ + offset = 0; + fragSeq = 0; + while (fragSeq < fragNum) { + if (fragSeq == (fragNum - 1)) { + /* last fragment */ + fragSize = patchSize - fragSeq * patchSizePerFrag; + } else + fragSize = patchSizePerFrag; + + iRet = wmt_core_tx(pPatchBuf + offset, fragSize, &u4Res, MTK_WCN_BOOL_TRUE); + if (iRet || (u4Res != fragSize)) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", + fragSeq, fragSize, u4Res, iRet); + iRet = -1; + break; + } + + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", + fragSeq, fragSize, u4Res); + + offset += patchSizePerFrag; + ++fragSeq; + } + + WMT_INFO_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", + iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); + + if (fragSeq != fragNum) + return -1; + + return 0; +} + +static INT32 mtk_wcn_soc_patch_dwn(UINT32 index) +{ + INT32 iRet = -1; + P_WMT_PATCH patchHdr = NULL; + PUINT8 pBuf = NULL; + PUINT8 pPatchBuf = NULL; + PUINT8 patchBuildTimeAddr; + UINT32 patchSize; + PINT8 cDataTime = NULL; + UINT16 u2HwVer = 0; + UINT16 u2SwVer = 0; + UINT32 u4PatchVer = 0; + WMT_CTRL_DATA ctrlData; + P_CONSYS_EMI_ADDR_INFO emiInfo; + UINT8 addressByte[4]; + + /*1.check hardware information */ + if (gp_soc_info == NULL) { + WMT_ERR_FUNC("null gp_soc_info!\n"); + return -1; + } + + osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName)); + + ctrlData.ctrlId = WMT_CTRL_GET_PATCH_INFO; + ctrlData.au4CtrlData[0] = index + 1; + ctrlData.au4CtrlData[1] = (SIZE_T)&gFullPatchName; + ctrlData.au4CtrlData[2] = (SIZE_T)&addressByte; + iRet = wmt_ctrl(&ctrlData); + WMT_DBG_FUNC("the %d time valid patch found: (%s)\n", index + 1, gFullPatchName); + + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH_INFO fail:%d\n", iRet); + goto done; + } + + /* <2.2> read patch content */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH; + ctrlData.au4CtrlData[0] = (SIZE_T)NULL; + ctrlData.au4CtrlData[1] = (SIZE_T)&gFullPatchName; + ctrlData.au4CtrlData[2] = (SIZE_T)&pBuf; + ctrlData.au4CtrlData[3] = (SIZE_T)&patchSize; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); + iRet -= 1; + goto done; + } + + /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ + /* patch file with header: + * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| + */ + pPatchBuf = osal_malloc(patchSize); + if (pPatchBuf == NULL) { + WMT_ERR_FUNC("vmalloc pPatchBuf for patch download fail\n"); + return -2; + } + osal_memcpy(pPatchBuf, pBuf, patchSize); + /* check patch file information */ + patchHdr = (P_WMT_PATCH) pPatchBuf; + + cDataTime = patchHdr->ucDateTime; + u2HwVer = patchHdr->u2HwVer; + u2SwVer = patchHdr->u2SwVer; + u4PatchVer = patchHdr->u4PatchVer; + + cDataTime[15] = '\0'; + if (index == 0) { + WMT_INFO_FUNC("[Patch]BuiltTime=%s,HVer=0x%x,SVer=0x%x,PhVer=0x%04x,Platform=%c%c%c%c\n", + cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8), + ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8), + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16), + patchHdr->ucPLat[0], patchHdr->ucPLat[1], + patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + } + osal_memcpy(&gp_soc_patch_info, patchHdr, osal_sizeof(WMT_PATCH)); + + /* remove patch header: + * |<-patch body: X Bytes (X=patchSize)--->| + */ + if (patchSize < sizeof(WMT_PATCH)) { + WMT_ERR_FUNC("error patch size\n"); + iRet = -1; + goto done; + } + patchSize -= sizeof(WMT_PATCH); + pPatchBuf += sizeof(WMT_PATCH); + + if (wmt_ic_ops_soc.icId == 0x6765 || + wmt_ic_ops_soc.icId == 0x3967 || + wmt_ic_ops_soc.icId == 0x6761 || + wmt_ic_ops_soc.icId == 0x6768 || + wmt_ic_ops_soc.icId == 0x6779 || + wmt_ic_ops_soc.icId == 0x6785 || + wmt_ic_ops_soc.icId == 0x8168) { + /* remove patch checksum: + * |<-patch checksum: 2Bytes->|<-patch body: X Bytes (X=patchSize)--->| + */ + pPatchBuf += BCNT_PATCH_BUF_CHECKSUM; + patchSize -= BCNT_PATCH_BUF_CHECKSUM; + } + + emiInfo = mtk_wcn_consys_soc_get_emi_phy_add(); + if (!emiInfo) { + WMT_ERR_FUNC("get emi info fail!\n"); + iRet = -1; + goto done; + } + + if (emiInfo->pda_dl_patch_flag) + iRet = mtk_wcn_soc_pda_patch_dwn(pPatchBuf, patchSize, addressByte); + else + iRet = mtk_wcn_soc_normal_patch_dwn(pPatchBuf, patchSize, addressByte); + + /* Set FW patch buildtime into EMI for debugging */ + if (emiInfo->emi_ram_mcu_buildtime_offset) { + patchBuildTimeAddr = ioremap(emiInfo->emi_ap_phy_addr + + emiInfo->emi_patch_mcu_buildtime_offset, PATCH_BUILD_TIME_SIZE); + if (patchBuildTimeAddr) { + osal_memcpy_toio(patchBuildTimeAddr, cDataTime, PATCH_BUILD_TIME_SIZE); + iounmap(patchBuildTimeAddr); + } else + WMT_ERR_FUNC("ioremap fail\n"); + } +done: + if (patchHdr != NULL) { + osal_free(patchHdr); + pPatchBuf = NULL; + patchHdr = NULL; + } + + /* WMT_CTRL_FREE_PATCH always return 0 */ + ctrlData.ctrlId = WMT_CTRL_FREE_PATCH; + ctrlData.au4CtrlData[0] = index + 1; + wmt_ctrl(&ctrlData); + + return iRet; +} + +#else +static INT32 mtk_wcn_soc_patch_dwn(VOID) +{ + INT32 iRet = -1; + P_WMT_PATCH patchHdr; + PUINT8 pbuf; + UINT32 patchSize; + UINT32 fragSeq; + UINT32 fragNum; + UINT16 fragSize = 0; + UINT16 cmdLen; + UINT32 offset; + UINT32 u4Res; + UINT8 evtBuf[8]; + PINT8 cDataTime = NULL; + /*PINT8 cPlat = NULL; */ + UINT16 u2HwVer = 0; + UINT16 u2SwVer = 0; + UINT32 u4PatchVer = 0; + UINT32 patchSizePerFrag = 0; + WMT_CTRL_DATA ctrlData; + + /*1.check hardware information */ + if (gp_soc_info == NULL) { + WMT_ERR_FUNC("null gp_soc_info!\n"); + return -1; + } + /* <2> search patch and read patch content */ + /* <2.1> search patch */ + ctrlData.ctrlId = WMT_CTRL_PATCH_SEARCH; + iRet = wmt_ctrl(&ctrlData); + if (iRet == 0) { + /* patch with correct Hw Ver Major Num found */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH_NAME; + ctrlData.au4CtrlData[0] = (UINT32) &gFullPatchName; + iRet = wmt_ctrl(&ctrlData); + + WMT_INFO_FUNC("valid patch found: (%s)\n", gFullPatchName); + /* <2.2> read patch content */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH; + ctrlData.au4CtrlData[0] = (UINT32) NULL; + ctrlData.au4CtrlData[1] = (UINT32) &gFullPatchName; + + } else { + iRet -= 1; + return iRet; + } + ctrlData.au4CtrlData[2] = (UINT32) &pbuf; + ctrlData.au4CtrlData[3] = (UINT32) &patchSize; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); + iRet -= 1; + goto done; + } + + /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| */ + pbuf += BCNT_PATCH_BUF_HEADROOM; + /* patch file with header: + * |<-patch header: 28 Bytes->|<-patch body: X Bytes ----->| + */ + patchHdr = (P_WMT_PATCH) pbuf; + /* check patch file information */ + + cDataTime = patchHdr->ucDateTime; + u2HwVer = patchHdr->u2HwVer; + u2SwVer = patchHdr->u2SwVer; + u4PatchVer = patchHdr->u4PatchVer; + /*cPlat = &patchHdr->ucPLat[0]; */ + + cDataTime[15] = '\0'; + WMT_DBG_FUNC("===========================================\n"); + WMT_INFO_FUNC("[ConsysPatch]BuiltTime = %s, HVer = 0x%x, SVer = 0x%x, PhVer = 0x%04x,Platform = %c%c%c%c\n", + cDataTime, ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8), + ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8), + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16), + patchHdr->ucPLat[0], patchHdr->ucPLat[1], patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + WMT_DBG_FUNC("[Consys Patch] Hw Ver = 0x%x\n", ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8)); + WMT_DBG_FUNC("[Consys Patch] Sw Ver = 0x%x\n", ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8)); + WMT_DBG_FUNC("[Consys Patch] Ph Ver = 0x%04x\n", + ((u4PatchVer & 0xff000000) >> 24) | ((u4PatchVer & 0x00ff0000) >> 16)); + WMT_DBG_FUNC("[Consys Patch] Platform = %c%c%c%c\n", patchHdr->ucPLat[0], patchHdr->ucPLat[1], + patchHdr->ucPLat[2], patchHdr->ucPLat[3]); + WMT_DBG_FUNC("===========================================\n"); + + /* remove patch header: + * |<-patch body: X Bytes (X=patchSize)--->| + */ + if (patchSize < sizeof(WMT_PATCH)) { + WMT_ERR_FUNC("error patch size\n"); + return -1; + } + patchSize -= sizeof(WMT_PATCH); + pbuf += sizeof(WMT_PATCH); + patchSizePerFrag = DEFAULT_PATCH_FRAG_SIZE; + /* reserve 1st patch cmd space before patch body + * |<-WMT_CMD: 5Bytes->|<-patch body: X Bytes (X=patchSize)----->| + */ + pbuf -= sizeof(WMT_PATCH_CMD); + + fragNum = patchSize / patchSizePerFrag; + fragNum += ((fragNum * patchSizePerFrag) == patchSize) ? 0 : 1; + + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + + /* send all fragments */ + offset = sizeof(WMT_PATCH_CMD); + fragSeq = 0; + while (fragSeq < fragNum) { + WMT_DBG_FUNC("patch size(%d) fragNum(%d)\n", patchSize, fragNum); + if (fragSeq == (fragNum - 1)) { + /* last fragment */ + fragSize = patchSize - fragSeq * patchSizePerFrag; + WMT_PATCH_CMD[4] = WMT_PATCH_FRAG_LAST; + } else { + fragSize = patchSizePerFrag; + WMT_PATCH_CMD[4] = (fragSeq == 0) ? WMT_PATCH_FRAG_1ST : WMT_PATCH_FRAG_MID; + } + /* update length field in CMD:flag+frag */ + cmdLen = 1 + fragSize; + osal_memcpy(&WMT_PATCH_CMD[2], &cmdLen, 2); + /* copy patch CMD to buf (overwrite last 5-byte in prev frag) */ + osal_memcpy(pbuf + offset - sizeof(WMT_PATCH_CMD), WMT_PATCH_CMD, sizeof(WMT_PATCH_CMD)); + + /* iRet = + * (*kal_stp_tx)(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), + * &u4Res); + */ + iRet = + wmt_core_tx(pbuf + offset - sizeof(WMT_PATCH_CMD), fragSize + sizeof(WMT_PATCH_CMD), &u4Res, + MTK_WCN_BOOL_FALSE); + if (iRet || (u4Res != fragSize + sizeof(WMT_PATCH_CMD))) { + WMT_ERR_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) fail(%d)\n", fragSeq, + fragSize + sizeof(WMT_PATCH_CMD), u4Res, iRet); + iRet -= 1; + break; + } + WMT_DBG_FUNC("wmt_core: write fragSeq(%d) size(%d, %d) ok\n", + fragSeq, fragSize + sizeof(WMT_PATCH_CMD), u4Res); + + osal_memset(evtBuf, 0, sizeof(evtBuf)); + /* iRet = (*kal_stp_rx)(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); */ + iRet = wmt_core_rx(evtBuf, sizeof(WMT_PATCH_EVT), &u4Res); + if (iRet || (u4Res != sizeof(WMT_PATCH_EVT))) { + WMT_ERR_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) fail(%d)\n", sizeof(WMT_PATCH_EVT), + u4Res, iRet); + mtk_wcn_stp_dbg_dump_package(); + iRet -= 1; + break; + } +#if CFG_CHECK_WMT_RESULT + if (osal_memcmp(evtBuf, WMT_PATCH_EVT, sizeof(WMT_PATCH_EVT)) != 0) { + WMT_ERR_FUNC("wmt_core: compare WMT_PATCH_EVT error rx(%d):[%02X,%02X,%02X,%02X,%02X]\n", + u4Res, + evtBuf[0], + evtBuf[1], + evtBuf[2], + evtBuf[3], + evtBuf[4]); + WMT_ERR_FUNC("wmt_core: exp(%d):[%02X,%02X,%02X,%02X,%02X]\n", + sizeof(WMT_PATCH_EVT), + WMT_PATCH_EVT[0], + WMT_PATCH_EVT[1], + WMT_PATCH_EVT[2], + WMT_PATCH_EVT[3], + WMT_PATCH_EVT[4]); + iRet -= 1; + break; + } +#endif + WMT_DBG_FUNC("wmt_core: read WMT_PATCH_EVT length(%d, %d) ok\n", sizeof(WMT_PATCH_EVT), u4Res); + offset += patchSizePerFrag; + ++fragSeq; + } + + WMT_WARN_FUNC("wmt_core: patch dwn:%d frag(%d, %d) %s\n", + iRet, fragSeq, fragSize, (!iRet && (fragSeq == fragNum)) ? "ok" : "fail"); + + if (fragSeq != fragNum) + iRet -= 1; +done: + /* WMT_CTRL_FREE_PATCH always return 0 */ + wmt_core_ctrl(WMT_CTRL_FREE_PATCH, NULL, NULL); + + return iRet; +} + +#endif + +INT32 mtk_wcn_soc_rom_patch_dwn(UINT32 ip_ver, UINT32 fw_ver) +{ + INT32 iRet = -1; + struct wmt_rom_patch *patchHdr = NULL; + PUINT8 pBuf = NULL; + PUINT8 pPatchBuf = NULL; + UINT32 patchSize; + UINT8 addressByte[4]; + PINT8 cDataTime = NULL; + UINT16 u2HwVer = 0; + UINT16 u2SwVer = 0; + UINT32 u4PatchType = 0; + UINT32 type; + UINT32 patchEmiOffset; + PUINT8 patchAddr; + UINT32 patchBuildTimeOffset = 0; + PUINT8 patchBuildTimeAddr; + WMT_CTRL_DATA ctrlData; + P_CONSYS_EMI_ADDR_INFO emiInfo; + + for (type = WMTDRV_TYPE_BT; type < WMTDRV_TYPE_ANT; type++) { + osal_memset(gFullPatchName, 0, osal_sizeof(gFullPatchName)); + + ctrlData.ctrlId = WMT_CTRL_GET_ROM_PATCH_INFO; + ctrlData.au4CtrlData[0] = type; + ctrlData.au4CtrlData[1] = (SIZE_T)&gFullPatchName; + ctrlData.au4CtrlData[2] = (SIZE_T)&addressByte; + ctrlData.au4CtrlData[3] = ip_ver; + ctrlData.au4CtrlData[4] = fw_ver; + iRet = wmt_ctrl(&ctrlData); + if (iRet > 0) { + WMT_INFO_FUNC("There is no need to download (%d) type patch!\n", type); + continue; + } else if (iRet < 0) { + WMT_ERR_FUNC("failed to get patch (type: %d, ret: %d)\n", type, iRet); + goto done; + } + + /* <2.2> read patch content */ + ctrlData.ctrlId = WMT_CTRL_GET_PATCH; + ctrlData.au4CtrlData[0] = (SIZE_T)NULL; + ctrlData.au4CtrlData[1] = (SIZE_T)&gFullPatchName; + ctrlData.au4CtrlData[2] = (SIZE_T)&pBuf; + ctrlData.au4CtrlData[3] = (SIZE_T)&patchSize; + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + WMT_ERR_FUNC("wmt_core: WMT_CTRL_GET_PATCH fail:%d\n", iRet); + iRet = -1; + goto done; + } + + /* |<-BCNT_PATCH_BUF_HEADROOM(8) bytes dummy allocated->|<-patch file->| + * patch file with header: + * |<-patch header: 32 Bytes->|<-patch body: X Bytes ----->| + */ + pPatchBuf = osal_malloc(patchSize); + if (pPatchBuf == NULL) { + WMT_ERR_FUNC("vmalloc pPatchBuf for patch download fail\n"); + iRet = -2; + goto done; + } + osal_memcpy(pPatchBuf, pBuf, patchSize); + /* check patch file information */ + patchHdr = (struct wmt_rom_patch *) pPatchBuf; + + cDataTime = patchHdr->ucDateTime; + u2HwVer = patchHdr->u2HwVer; + u2SwVer = patchHdr->u2SwVer; + u4PatchType = patchHdr->u4PatchType; + + cDataTime[15] = '\0'; + WMT_INFO_FUNC("[RomPatch]BTime=%s,HVer=0x%x,SVer=0x%x,Platform=%c%c%c%c\n,Type=%x\n", + cDataTime, + ((u2HwVer & 0x00ff) << 8) | ((u2HwVer & 0xff00) >> 8), + ((u2SwVer & 0x00ff) << 8) | ((u2SwVer & 0xff00) >> 8), + patchHdr->ucPLat[0], patchHdr->ucPLat[1], + patchHdr->ucPLat[2], patchHdr->ucPLat[3], + u4PatchType); + + /* remove patch header: + * |<-patch body: X Bytes (X=patchSize)--->| + */ + if (patchSize < sizeof(struct wmt_rom_patch)) { + WMT_ERR_FUNC("error patch size\n"); + iRet = -3; + goto done; + } + patchSize -= sizeof(struct wmt_rom_patch); + pPatchBuf += sizeof(struct wmt_rom_patch); + + patchEmiOffset = (addressByte[2] << 16) | (addressByte[1] << 8) | addressByte[0]; + + emiInfo = mtk_wcn_consys_soc_get_emi_phy_add(); + if (!emiInfo) { + WMT_ERR_FUNC("get emi info fail!\n"); + iRet = -4; + goto done; + } + + if (patchEmiOffset + patchSize < emiInfo->emi_size) { + WMT_INFO_FUNC("[Rom Patch] emiInfo: emi_ap_phy_addr=0x%x emi_size=%d emi_phy_addr=0x%x\n", + emiInfo->emi_ap_phy_addr, emiInfo->emi_size, emiInfo->emi_phy_addr); + WMT_INFO_FUNC("[Rom Patch]Name=%s,EmiOffset=0x%x,Size=0x%x\n", + gFullPatchName, patchEmiOffset, patchSize); + + if (type == WMTDRV_TYPE_WIFI) + wmt_lib_set_wlan_mpu_protection(false); + + patchAddr = ioremap(emiInfo->emi_ap_phy_addr + patchEmiOffset, patchSize); + WMT_INFO_FUNC("physAddr=0x%x, size=%d virAddr=0x%p\n", + emiInfo->emi_ap_phy_addr + patchEmiOffset, patchSize, patchAddr); + if (patchAddr) { + osal_memcpy_toio(patchAddr, pPatchBuf, patchSize); + iounmap(patchAddr); + } else + WMT_ERR_FUNC("ioremap fail\n"); + + if (type == WMTDRV_TYPE_BT) + patchBuildTimeOffset = emiInfo->emi_ram_bt_buildtime_offset; + else if (type == WMTDRV_TYPE_WIFI) + patchBuildTimeOffset = emiInfo->emi_ram_wifi_buildtime_offset; + else if (type == WMTDRV_TYPE_WMT) + patchBuildTimeOffset = emiInfo->emi_ram_mcu_buildtime_offset; + /* Set ROM patch buildtime into EMI for debugging */ + if (patchBuildTimeOffset) { + patchBuildTimeAddr = ioremap(emiInfo->emi_ap_phy_addr + + patchBuildTimeOffset, PATCH_BUILD_TIME_SIZE); + if (patchBuildTimeAddr) { + osal_memcpy_toio(patchBuildTimeAddr, cDataTime, + PATCH_BUILD_TIME_SIZE); + iounmap(patchBuildTimeAddr); + } else + WMT_ERR_FUNC("ioremap fail\n"); + } + + if (type == WMTDRV_TYPE_WIFI) + wmt_lib_set_wlan_mpu_protection(true); + } else + WMT_ERR_FUNC("The rom patch is too big to overflow on EMI\n"); + +done: + if (patchHdr != NULL) { + osal_free(patchHdr); + pPatchBuf = NULL; + patchHdr = NULL; + } + + /* WMT_CTRL_FREE_PATCH always return 0 */ + ctrlData.ctrlId = WMT_CTRL_FREE_PATCH; + ctrlData.au4CtrlData[0] = type; + wmt_ctrl(&ctrlData); + if (iRet) + break; + } + + return iRet; +} + + +VOID mtk_wcn_soc_restore_wifi_cal_result(VOID) +{ +#if CFG_CALIBRATION_BACKUP_RESTORE + P_CONSYS_EMI_ADDR_INFO emiInfo = mtk_wcn_consys_soc_get_emi_phy_add(); + PUINT8 wifiCalAddr = NULL; + + if (!emiInfo) { + WMT_ERR_FUNC("Get EMI info failed.\n"); + return; + } + + if (mtk_consys_is_calibration_backup_restore_support() == 0 || + mtk_wcn_stp_assert_flow_get() == 0) { + WMT_INFO_FUNC( + "Skip restore, chip id=%x mtk_wcn_stp_assert_flow_get()=%d\n", + wmt_ic_ops_soc.icId, mtk_wcn_stp_assert_flow_get()); + return; + } + /* Disable Wi-Fi MPU to touch Wi-Fi calibration data */ + wmt_lib_set_wlan_mpu_protection(false); + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_BEFORE_RESTORE_CAL_RESULT); + /* Write Wi-Fi data to EMI */ + if (gWiFiCalAddrOffset + gWiFiCalSize < emiInfo->emi_size) { + wifiCalAddr = ioremap(emiInfo->emi_ap_phy_addr + gWiFiCalAddrOffset, + gWiFiCalSize); + if (wifiCalAddr) { + osal_memcpy_toio(wifiCalAddr, gWiFiCalResult, gWiFiCalSize); + iounmap(wifiCalAddr); + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_AFTER_RESTORE_CAL_RESULT); + } else { + WMT_ERR_FUNC("ioremap fail\n"); + } + } + wmt_lib_set_wlan_mpu_protection(true); +#else + WMT_INFO_FUNC("Skip restore because it is not supported.\n"); +#endif +} + +#if CFG_CALIBRATION_BACKUP_RESTORE +/* + * To restore calibration data + * For BT, send by STP command. + * For Wi-Fi write to EMI directly. + * + * Return value: + * 0: restore success + * 1: recalibration happened. Caller need to re-get calibration data + * < 0: fail. Caller need to re-send calibration command. + */ +static INT32 mtk_wcn_soc_calibration_restore(void) +{ + INT32 iRet = 0; + PUINT8 evtBuf = NULL; + UINT32 u4Res; + UINT16 len = 0; + + /* Allocate event buffer */ + evtBuf = osal_malloc(CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE); + if (evtBuf == NULL) { + WMT_ERR_FUNC("allocate event buffer failed\n"); + return -1; + } + + if ((gBTCalResultSize != 0 && gBTCalResult != NULL && + (gBTCalResultSize + sizeof(WMT_CORE_SEND_RF_CALIBRATION_CMD)) < CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE) && + (gWiFiCalResult != NULL && gWiFiCalSize != 0 && gWiFiCalAddrOffset != 0)) { + WMT_INFO_FUNC("Send calibration data size=%d\n", gBTCalResultSize); + WMT_INFO_FUNC("Send calibration data start\n"); + /* Construct send calibration cmd for BT + * Format: 0x01 0x14 [ X+3 (2 bytes)] 0x02 + * [BT data len (2 bytes)] [BT data (X bytes)] + */ + /* clear buffer */ + osal_memset(&evtBuf[0], 0, CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE); + /* copy cmd template */ + osal_memcpy( + &evtBuf[0], + WMT_CORE_SEND_RF_CALIBRATION_CMD, + sizeof(WMT_CORE_SEND_RF_CALIBRATION_CMD)); + /* Setup length to byte 2&3 */ + len = gBTCalResultSize + 3; + osal_memcpy(&evtBuf[2], &len, 2); + osal_memcpy(&evtBuf[5], &gBTCalResultSize, 2); + osal_memcpy(&evtBuf[7], gBTCalResult, gBTCalResultSize); + len = sizeof(WMT_CORE_SEND_RF_CALIBRATION_CMD) + gBTCalResultSize; + iRet = wmt_core_tx(evtBuf, len, &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || u4Res != len) { + WMT_ERR_FUNC("Send calibration data TX failed (%d), %d bytes writes, expect %d\n", + iRet, u4Res, len); + iRet = -4; + goto restore_end; + } + /* RX: 02 14 02 00 XX 02 + * XX means status + * 0: OK + * 1: recalibration happened + */ + iRet = wmt_core_rx(evtBuf, CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE, &u4Res); + WMT_INFO_FUNC("Send calibration data end\n"); + if (iRet || u4Res != sizeof(WMT_CORE_SEND_RF_CALIBRATION_EVT_OK)) { + WMT_ERR_FUNC("Send calibration data event failed(%d), %d bytes get, expect %lu\n", + iRet, u4Res, sizeof(WMT_CORE_SEND_RF_CALIBRATION_EVT_OK)); + iRet = -5; + goto restore_end; + } + /* Check return */ + if (osal_memcmp(&evtBuf[0], WMT_CORE_SEND_RF_CALIBRATION_EVT_OK, + sizeof(WMT_CORE_SEND_RF_CALIBRATION_EVT_OK)) == 0) { + WMT_INFO_FUNC("Send calibration data OK.\n"); + iRet = 0; + } else if (osal_memcmp(&evtBuf[0], WMT_CORE_SEND_RF_CALIBRATION_EVT_RECAL, + sizeof(WMT_CORE_SEND_RF_CALIBRATION_EVT_RECAL)) == 0) { + WMT_INFO_FUNC("Recalibration happened. Re-get calibration data\n"); + iRet = 1; + goto restore_end; + } else { + /* Do calibration */ + WMT_ERR_FUNC("Send calibration event error. 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x\n", + evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], evtBuf[5]); + iRet = -5; + goto restore_end; + } + } else { + WMT_ERR_FUNC("Did not restore calibration data. Buf=0x%p, size=%d\n", + gBTCalResult, gBTCalResultSize); + iRet = -6; + goto restore_end; + } + +restore_end: + wmt_lib_set_wlan_mpu_protection(false); + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_AFTER_RESTORE_CAL_CMD); + wmt_lib_set_wlan_mpu_protection(true); + osal_free(evtBuf); + return iRet; +} + +/* + * To backup calibration data + * For BT, get data by STP command. + * For Wi-Fi, get EMI offset and length from STP command and then + * backup data from EMI + * + * Return value: + * 0: backup success + * < 0: fail + */ +static INT32 mtk_wcn_soc_calibration_backup(void) +{ + INT32 iRet = 0; + PUINT8 evtBuf; + UINT32 u4Res; + UINT16 len = 0; + P_CONSYS_EMI_ADDR_INFO emiInfo = mtk_wcn_consys_soc_get_emi_phy_add(); + UINT32 wifiOffset = 0; + UINT32 wifiLen = 0; + void __iomem *virWiFiAddrBase; + + /* Allocate RX event buffer */ + evtBuf = osal_malloc(CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE); + if (evtBuf == NULL) { + WMT_ERR_FUNC("Allocate event buffer failed\n"); + return -1; + } + /* Get calibration data TX */ + iRet = wmt_core_tx(WMT_CORE_GET_RF_CALIBRATION_CMD, + sizeof(WMT_CORE_GET_RF_CALIBRATION_CMD), + &u4Res, MTK_WCN_BOOL_FALSE); + if (iRet || u4Res != sizeof(WMT_CORE_GET_RF_CALIBRATION_CMD)) { + WMT_ERR_FUNC("Write get calibration cmd failed(%d), exp: %lu but write %d\n", + iRet, sizeof(WMT_CORE_GET_RF_CALIBRATION_CMD), u4Res); + goto get_calibration_fail; + } + osal_memset(&evtBuf[0], 0, CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE); + iRet = wmt_core_rx(evtBuf, CALIBRATION_BACKUP_RESTORE_BUFFER_SIZE, &u4Res); + /* RX expected format: + * 02 14 [X+14 (2 bytes)] 00 03 + * [BT size = X (2 bytes)] [BT Cal. Data (X bytes)] + * [WiFi Size = 8 (2 bytes)] [WiFi Offset (4 bytes)] [WiFi len(4 bytes)] + */ + if (iRet || u4Res < 8) { + WMT_ERR_FUNC("Get calibration event failed(%d), get %d bytes\n", iRet, u4Res); + goto get_calibration_fail; + } + /* Check data validaness */ + if (evtBuf[0] != 0x02 || evtBuf[1] != 0x14 || + evtBuf[4] != 0x00 || evtBuf[5] != 0x03) { + WMT_ERR_FUNC("Get calibration event error. 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x 0x%2x\n", + evtBuf[0], evtBuf[1], evtBuf[2], evtBuf[3], evtBuf[4], evtBuf[5]); + goto get_calibration_fail; + } + /* Get data success, backup it. + * Data size is not the same as previous, realloc memory + */ + osal_memcpy(&len, &evtBuf[6], 2); + if (len != gBTCalResultSize) { + gBTCalResultSize = len; + if (gBTCalResult != NULL) { + osal_free(gBTCalResult); + gBTCalResult = NULL; + } + } + if (gBTCalResult == NULL) + gBTCalResult = osal_malloc(gBTCalResultSize); + if (gBTCalResult == NULL) { + WMT_ERR_FUNC("Allocate BT calibration buffer failed.\n"); + goto get_calibration_fail; + } + osal_memcpy(gBTCalResult, &evtBuf[8], gBTCalResultSize); + /* Get Wi-Fi info */ + osal_memcpy(&wifiOffset, &evtBuf[10 + gBTCalResultSize], 4); + osal_memcpy(&wifiLen, &evtBuf[14 + gBTCalResultSize], 4); + if (wifiLen != gWiFiCalSize) { + gWiFiCalSize = wifiLen; + if (gWiFiCalResult != NULL) { + osal_free(gWiFiCalResult); + gWiFiCalResult = NULL; + } + } + if (gWiFiCalResult == NULL) + gWiFiCalResult = osal_malloc(gWiFiCalSize); + if (gWiFiCalResult == NULL) { + WMT_ERR_FUNC("Allocate Wi-Fi calibration buffer failed.\n"); + goto get_calibration_fail; + } + /* Start to backup Wi-Fi data */ + if (!emiInfo) { + WMT_ERR_FUNC("get emi info fail!\n"); + goto get_calibration_fail; + } + /* Before copy, disable Wi-Fi MPU to access EMI */ + wmt_lib_set_wlan_mpu_protection(false); + WMT_STEP_DO_ACTIONS_FUNC( + STEP_TRIGGER_POINT_POWER_ON_AFTER_BT_WIFI_CALIBRATION); + gWiFiCalAddrOffset = wifiOffset; + virWiFiAddrBase = ioremap( + emiInfo->emi_ap_phy_addr + gWiFiCalAddrOffset, + gWiFiCalSize); + if (virWiFiAddrBase) { + osal_memcpy_fromio(gWiFiCalResult, virWiFiAddrBase, gWiFiCalSize); + iounmap(virWiFiAddrBase); + } else { + WMT_ERR_FUNC("Remap Wi-Fi EMI fail: offset=%d size=%d\n", + gWiFiCalAddrOffset, gWiFiCalSize); + goto get_calibration_fail; + } + /* Enable Wi-Fi MPU after finished. */ + wmt_lib_set_wlan_mpu_protection(true); + WMT_INFO_FUNC("gBTCalResultSize=%d gWiFiCalResult=0x%p gWiFiCalSize=%d gWiFiCalAddrOffset=0x%x\n", + gBTCalResultSize, + gWiFiCalResult, + gWiFiCalSize, + gWiFiCalAddrOffset); + osal_free(evtBuf); + return 0; +get_calibration_fail: + WMT_ERR_FUNC("Get calibration failed.\n"); + if (emiInfo) { + WMT_ERR_FUNC("emiInfo: emi_ap_phy_addr=0x%x emi_size=%d emi_phy_addr=0x%x\n", + emiInfo->emi_ap_phy_addr, + emiInfo->emi_size, + emiInfo->emi_phy_addr); + } + WMT_ERR_FUNC("gBTCalResultSize=%d gWiFiCalResult=0x%p gWiFiCalSize=%d gWiFiCalAddrOffset=0x%x\n", + gBTCalResultSize, gWiFiCalResult, + gWiFiCalSize, gWiFiCalAddrOffset); + if (gBTCalResult != NULL) { + osal_free(gBTCalResult); + gBTCalResult = NULL; + } + gBTCalResultSize = 0; + if (gWiFiCalResult != NULL) { + osal_free(gWiFiCalResult); + gWiFiCalResult = NULL; + } + gWiFiCalSize = 0; + gWiFiCalAddrOffset = 0; + /* Enable Wi-Fi MPU after finished. */ + wmt_lib_set_wlan_mpu_protection(true); + osal_free(evtBuf); + return -1; +} +#endif + +static INT32 mtk_wcn_soc_do_calibration(void) +{ + INT32 iRet = 0; + +#if CFG_CALIBRATION_BACKUP_RESTORE + /* When chip reset is caused by assert, skip calibration. + * Restore old data. + */ + if (mtk_consys_is_calibration_backup_restore_support() == 0 || + mtk_wcn_stp_assert_flow_get() == 0) { + WMT_INFO_FUNC( + "Skip restore, chip id=%x mtk_wcn_stp_assert_flow_get()=%d\n", + wmt_ic_ops_soc.icId, mtk_wcn_stp_assert_flow_get()); + goto do_calibration; + } + + iRet = mtk_wcn_soc_calibration_restore(); + if (iRet == 0) { + WMT_INFO_FUNC("Restore success\n"); + return 0; + } else if (iRet == 1) { + WMT_INFO_FUNC("Recal happened. Re-get calibration data.\n"); + goto get_calibration; + } else + /* For all other case, re-cali. */ + WMT_ERR_FUNC("Re-cal because restore fail(%d)\n", iRet); + +do_calibration: +#endif /* CFG_CALIBRATION_BACKUP_RESTORE */ + /* Do calibration */ + WMT_INFO_FUNC("Calibration start\n"); + iRet = wmt_core_init_script( + calibration_table, + osal_array_size(calibration_table)); + WMT_INFO_FUNC("Calibration end\n"); + if (iRet) { + #if CFG_CALIBRATION_BACKUP_RESTORE + /* Calibration failed. Clear backup data. */ + if (gBTCalResult != NULL) { + osal_free(gBTCalResult); + gBTCalResult = NULL; + } + gBTCalResultSize = 0; + if (gWiFiCalResult != NULL) { + osal_free(gWiFiCalResult); + gWiFiCalResult = NULL; + } + gWiFiCalSize = 0; + gWiFiCalAddrOffset = 0; + #endif + WMT_ERR_FUNC("do calibration failed (%d)\n", iRet); + return -1; + } + +#if CFG_CALIBRATION_BACKUP_RESTORE + if (mtk_consys_is_calibration_backup_restore_support() == 0) + return 0; + +get_calibration: + iRet = mtk_wcn_soc_calibration_backup(); + /* Backup process should not influence power on sequence. + * Hence, even it return error, just record it and + * report calibration success. + */ + if (iRet == 0) + WMT_INFO_FUNC("Backup success\n"); + else + WMT_ERR_FUNC("Backup failed(%d)\n", iRet); +#endif + return 0; +} + +static INT32 mtk_wcn_soc_calibration(void) +{ + INT32 iRet = -1; + INT32 iCalRet = -1; + unsigned long ctrlPa1; + unsigned long ctrlPa2; + + /* Turn on BT/Wi-Fi */ + ctrlPa1 = BT_PALDO; + ctrlPa2 = PALDO_ON; + iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WIFI_PALDO; + ctrlPa2 = PALDO_ON; + iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + + WMT_INFO_FUNC("mtk_wcn_soc_do_calibration start\n"); + iCalRet = mtk_wcn_soc_do_calibration(); + WMT_INFO_FUNC("mtk_wcn_soc_do_calibration end\n"); + + /* Turn off BT/Wi-Fi */ + ctrlPa1 = BT_PALDO; + ctrlPa2 = PALDO_OFF; + iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + ctrlPa1 = WIFI_PALDO; + ctrlPa2 = PALDO_OFF; + iRet = wmt_core_ctrl(WMT_CTRL_SOC_PALDO_CTRL, &ctrlPa1, &ctrlPa2); + + if (iCalRet) { + /* pwrap_read(0x0210,&ctrlPa1); */ + /* pwrap_read(0x0212,&ctrlPa2); */ + /* WMT_ERR_FUNC("power status: 210:(%d),212:(%d)!\n", ctrlPa1, ctrlPa2); */ + WMT_ERR_FUNC("calibration_table fail(%d)\n", iCalRet); + return -1; + } + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_lib.c b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_lib.c new file mode 100644 index 00000000000000..8c4b0bbfe2f8ac --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/core/wmt_lib.c @@ -0,0 +1,3290 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-LIB]" + + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "wmt_dbg.h" + +#include "wmt_dev.h" +#include "wmt_lib.h" +#include "wmt_conf.h" +#include "wmt_core.h" +#include "wmt_plat.h" +#include "wmt_plat_stub.h" +#include "wmt_detect.h" +#include "mtk_wcn_consys_hw.h" + +#include "stp_core.h" +#include "btm_core.h" +#include "psm_core.h" +#include "stp_sdio.h" +#include "stp_dbg.h" +#include "wmt_step.h" +#include <linux/workqueue.h> +#include <linux/rtc.h> + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/* A table for translation: enum CMB_STUB_AIF_X=>WMT_IC_PIN_STATE */ +static const WMT_IC_PIN_STATE cmb_aif2pin_stat[] = { + [CMB_STUB_AIF_0] = WMT_IC_AIF_0, + [CMB_STUB_AIF_1] = WMT_IC_AIF_1, + [CMB_STUB_AIF_2] = WMT_IC_AIF_2, + [CMB_STUB_AIF_3] = WMT_IC_AIF_3, + [CMB_STUB_AIF_4] = WMT_IC_PIN_STATE_MAX, +}; + +#if CFG_WMT_PS_SUPPORT +static UINT32 gPsIdleTime = STP_PSM_IDLE_TIME_SLEEP; +static UINT32 gPsEnable = 1; +static PF_WMT_SDIO_PSOP sdio_own_ctrl; +static PF_WMT_SDIO_DEBUG sdio_reg_rw; +#endif +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +static PF_WMT_SDIO_DEEP_SLEEP sdio_deep_sleep_flag_set; +#endif + + +#define WMT_STP_CPUPCR_BUF_SIZE 73728 +static UINT8 g_cpupcr_buf[WMT_STP_CPUPCR_BUF_SIZE] = { 0 }; +static UINT32 g_quick_sleep_ctrl = 1; +static UINT32 g_fw_patch_update_rst; +static u64 fw_patch_rst_time; + +#define ASSERT_KEYWORD_LENGTH 20 +struct assert_work_st { + struct work_struct work; + ENUM_WMTDRV_TYPE_T type; + UINT32 reason; + UINT8 keyword[ASSERT_KEYWORD_LENGTH]; +}; + +static struct assert_work_st wmt_assert_work; + +static INT32 g_bt_no_acl_link; +static INT32 g_bt_no_br_acl_link; + +#define CONSYS_MET_WAIT (1000*10) /* ms */ +#define MET_DUMP_MAX_NUM (1) +#define MET_DUMP_SIZE (4*MET_DUMP_MAX_NUM) +#define EMI_MET_READ_OFFSET 0x0 +#define EMI_MET_WRITE_OFFSET 0x4 +#define EMI_MET_DATA_OFFSET 0x8 +#define FW_PATCH_UPDATE_RST_DURATION 180 /* 180 seconds */ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +DEV_WMT gDevWmt; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +#if CFG_WMT_PS_SUPPORT +static MTK_WCN_BOOL wmt_lib_ps_action(MTKSTP_PSM_ACTION_T action); +static MTK_WCN_BOOL wmt_lib_ps_do_sleep(VOID); +static MTK_WCN_BOOL wmt_lib_ps_do_wakeup(VOID); +static MTK_WCN_BOOL wmt_lib_ps_do_host_awake(VOID); +static INT32 wmt_lib_ps_handler(MTKSTP_PSM_ACTION_T action); +#endif + +static MTK_WCN_BOOL wmt_lib_put_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pLxOp); + +static P_OSAL_OP wmt_lib_get_op(P_OSAL_OP_Q pOpQ); + +static INT32 wmtd_thread(PVOID pvData); +static INT32 met_thread(PVOID pvData); +static INT32 wmtd_worker_thread(PVOID pvData); + +static INT32 wmt_lib_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE stat, UINT32 flag); +static MTK_WCN_BOOL wmt_lib_hw_state_show(VOID); +static VOID wmt_lib_utc_sync_timeout_handler(ULONG data); +static VOID wmt_lib_utc_sync_worker_handler(struct work_struct *work); +static VOID wmt_lib_wmtd_worker_thread_timeout_handler(ULONG data); +static VOID wmt_lib_wmtd_worker_thread_work_handler(struct work_struct *work); + +static VOID wmt_lib_assert_work_cb(struct work_struct *work); +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 __weak mtk_wcn_consys_stp_btif_dpidle_ctrl(enum _ENUM_BTIF_DPIDLE_ en_flag) +{ + WMT_ERR_FUNC("mtk_wcn_consys_stp_btif_dpidle_ctrl is not define!!!\n"); + + return 0; +} + +INT32 wmt_lib_wlan_lock_aquire(VOID) +{ + return osal_lock_sleepable_lock(&gDevWmt.wlan_lock); +} + +VOID wmt_lib_wlan_lock_release(VOID) +{ + osal_unlock_sleepable_lock(&gDevWmt.wlan_lock); +} + +INT32 wmt_lib_wlan_lock_trylock(VOID) +{ + return osal_trylock_sleepable_lock(&gDevWmt.wlan_lock); +} + +INT32 wmt_lib_idc_lock_aquire(VOID) +{ + return osal_lock_sleepable_lock(&gDevWmt.idc_lock); +} + +VOID wmt_lib_idc_lock_release(VOID) +{ + osal_unlock_sleepable_lock(&gDevWmt.idc_lock); +} + +INT32 wmt_lib_psm_lock_aquire(VOID) +{ + return osal_lock_sleepable_lock(&gDevWmt.psm_lock); +} + +void wmt_lib_psm_lock_release(VOID) +{ + osal_unlock_sleepable_lock(&gDevWmt.psm_lock); +} + +INT32 wmt_lib_psm_lock_trylock(VOID) +{ + return osal_trylock_sleepable_lock(&gDevWmt.psm_lock); +} + +INT32 wmt_lib_assert_lock_aquire(VOID) +{ + return osal_lock_sleepable_lock(&gDevWmt.assert_lock); +} + +VOID wmt_lib_assert_lock_release(VOID) +{ + osal_unlock_sleepable_lock(&gDevWmt.assert_lock); +} + +INT32 wmt_lib_assert_lock_trylock(VOID) +{ + return osal_trylock_sleepable_lock(&gDevWmt.assert_lock); +} + +INT32 wmt_lib_mpu_lock_aquire(VOID) +{ + return osal_lock_sleepable_lock(&gDevWmt.mpu_lock); +} + +VOID wmt_lib_mpu_lock_release(VOID) +{ + osal_unlock_sleepable_lock(&gDevWmt.mpu_lock); +} + +INT32 DISABLE_PSM_MONITOR(VOID) +{ + INT32 ret = 0; + PUINT8 pbuf = NULL; + INT32 len = 0; + + /* osal_lock_sleepable_lock(&gDevWmt.psm_lock); */ + ret = wmt_lib_psm_lock_aquire(); + if (ret) { + WMT_ERR_FUNC("--->lock psm_lock failed, ret=%d\n", ret); + return ret; + } +#if CFG_WMT_PS_SUPPORT + ret = wmt_lib_ps_disable(); + if (ret) { + WMT_ERR_FUNC("wmt_lib_ps_disable fail, ret=%d\n", ret); + wmt_lib_psm_lock_release(); + if (mtk_wcn_stp_coredump_start_get() == 0 && + chip_reset_only == 0 && + mtk_wcn_stp_get_wmt_trg_assert() == 0) { + pbuf = "wmt_lib_ps_disable fail, just collect SYS_FTRACE to DB"; + len = osal_strlen(pbuf); + stp_dbg_trigger_collect_ftrace(pbuf, len); + wmt_lib_trigger_reset(); + } + } +#endif + return ret; +} + +VOID ENABLE_PSM_MONITOR(VOID) +{ +#if CFG_WMT_PS_SUPPORT + wmt_lib_ps_enable(); +#endif + /* osal_unlock_sleepable_lock(&gDevWmt.psm_lock); */ + wmt_lib_psm_lock_release(); +} + + +INT32 wmt_lib_init(VOID) +{ + INT32 iRet; + UINT32 i; + P_DEV_WMT pDevWmt; + P_OSAL_THREAD pThread; + P_OSAL_THREAD pWorkerThread; + ENUM_WMT_CHIP_TYPE chip_type; + + /* create->init->start */ + /* 1. create: static allocation with zero initialization */ + pDevWmt = &gDevWmt; + osal_memset(&gDevWmt, 0, sizeof(gDevWmt)); + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) { + iRet = wmt_conf_read_file(); + if (iRet) { + WMT_ERR_FUNC("read wmt config file fail(%d)\n", iRet); + return -1; + } + } + osal_op_history_init(&pDevWmt->wmtd_op_history, 16); + osal_op_history_init(&pDevWmt->worker_op_history, 8); + + pThread = &gDevWmt.thread; + + /* Create mtk_wmtd thread */ + osal_strncpy(pThread->threadName, "mtk_wmtd", sizeof(pThread->threadName)); + pThread->pThreadData = (PVOID) pDevWmt; + pThread->pThreadFunc = (PVOID) wmtd_thread; + iRet = osal_thread_create(pThread); + if (iRet) { + WMT_ERR_FUNC("osal_thread_create(0x%p) fail(%d)\n", pThread, iRet); + return -2; + } + + /* create worker timer */ + gDevWmt.worker_timer.timeoutHandler = wmt_lib_wmtd_worker_thread_timeout_handler; + gDevWmt.worker_timer.timeroutHandlerData = 0; + osal_timer_create(&gDevWmt.worker_timer); + pWorkerThread = &gDevWmt.worker_thread; + INIT_WORK(&pDevWmt->wmtd_worker_thread_work, wmt_lib_wmtd_worker_thread_work_handler); + + /* Create wmtd_worker thread */ + osal_strncpy(pWorkerThread->threadName, "mtk_wmtd_worker", sizeof(pWorkerThread->threadName)); + pWorkerThread->pThreadData = (PVOID) pDevWmt; + pWorkerThread->pThreadFunc = (PVOID) wmtd_worker_thread; + iRet = osal_thread_create(pWorkerThread); + if (iRet) { + WMT_ERR_FUNC("osal_thread_create(0x%p) fail(%d)\n", pWorkerThread, iRet); + return -2; + } + + /* init timer */ + pDevWmt->utc_sync_timer.timeoutHandler = wmt_lib_utc_sync_timeout_handler; + osal_timer_create(&pDevWmt->utc_sync_timer); + osal_timer_start(&pDevWmt->utc_sync_timer, UTC_SYNC_TIME); + INIT_WORK(&pDevWmt->utcSyncWorker, wmt_lib_utc_sync_worker_handler); + + /* 2. initialize */ + /* Initialize wmt_core */ + + iRet = wmt_core_init(); + if (iRet) { + WMT_ERR_FUNC("wmt_core_init() fail(%d)\n", iRet); + return -1; + } + + /* Initialize WMTd Thread Information: Thread */ + osal_event_init(&pDevWmt->rWmtdWq); + osal_event_init(&pDevWmt->rWmtdWorkerWq); + osal_sleepable_lock_init(&pDevWmt->psm_lock); + osal_sleepable_lock_init(&pDevWmt->idc_lock); + osal_sleepable_lock_init(&pDevWmt->wlan_lock); + osal_sleepable_lock_init(&pDevWmt->assert_lock); + osal_sleepable_lock_init(&pDevWmt->mpu_lock); + osal_sleepable_lock_init(&pDevWmt->rActiveOpQ.sLock); + osal_sleepable_lock_init(&pDevWmt->rWorkerOpQ.sLock); + osal_sleepable_lock_init(&pDevWmt->rFreeOpQ.sLock); + pDevWmt->state.data = 0; + + /* Initialize op queue */ + RB_INIT(&pDevWmt->rFreeOpQ, WMT_OP_BUF_SIZE); + RB_INIT(&pDevWmt->rActiveOpQ, WMT_OP_BUF_SIZE); + RB_INIT(&pDevWmt->rWorkerOpQ, WMT_OP_BUF_SIZE); + /* Put all to free Q */ + for (i = 0; i < WMT_OP_BUF_SIZE; i++) { + osal_signal_init(&(pDevWmt->arQue[i].signal)); + wmt_lib_put_op(&pDevWmt->rFreeOpQ, &(pDevWmt->arQue[i])); + } + + /* initialize stp resources */ + osal_event_init(&pDevWmt->rWmtRxWq); + + /*function driver callback */ + for (i = 0; i < WMTDRV_TYPE_WIFI; i++) + pDevWmt->rFdrvCb.fDrvRst[i] = NULL; + + pDevWmt->hw_ver = WMTHWVER_MAX; + WMT_DBG_FUNC("***********Init, hw->ver = %x\n", pDevWmt->hw_ver); + + /* TODO:[FixMe][GeorgeKuo]: wmt_lib_conf_init */ + /* initialize default configurations */ + /* i4Result = wmt_lib_conf_init(VOID); */ + /* WMT_WARN_FUNC("wmt_drv_conf_init(%d)\n", i4Result); */ + + osal_signal_init(&pDevWmt->cmdResp); + osal_event_init(&pDevWmt->cmdReq); + /* initialize platform resources */ + + if (gDevWmt.rWmtGenConf.cfgExist != 0) { + PWR_SEQ_TIME pwrSeqTime; + + pwrSeqTime.ldoStableTime = gDevWmt.rWmtGenConf.pwr_on_ldo_slot; + pwrSeqTime.rstStableTime = gDevWmt.rWmtGenConf.pwr_on_rst_slot; + pwrSeqTime.onStableTime = gDevWmt.rWmtGenConf.pwr_on_on_slot; + pwrSeqTime.offStableTime = gDevWmt.rWmtGenConf.pwr_on_off_slot; + pwrSeqTime.rtcStableTime = gDevWmt.rWmtGenConf.pwr_on_rtc_slot; + WMT_INFO_FUNC("set pwr on seq par to hw conf\n"); + WMT_INFO_FUNC("ldo(%d)rst(%d)on(%d)off(%d)rtc(%d)\n", pwrSeqTime.ldoStableTime, + pwrSeqTime.rstStableTime, pwrSeqTime.onStableTime, + pwrSeqTime.offStableTime, pwrSeqTime.rtcStableTime); + iRet = wmt_plat_init(&pwrSeqTime, gDevWmt.rWmtGenConf.co_clock_flag & 0x0f); + } else { + WMT_ERR_FUNC("no pwr on seq and clk par found\n"); + iRet = wmt_plat_init(NULL, 0); + } + chip_type = wmt_detect_get_chip_type(); + if (chip_type == WMT_CHIP_TYPE_SOC) + gDevWmt.rWmtGenConf.co_clock_flag = wmt_plat_soc_co_clock_flag_get(); + + if (iRet) { + WMT_ERR_FUNC("wmt_plat_init() fail(%d)\n", iRet); + return -3; + } + +#if CFG_WMT_PS_SUPPORT + iRet = wmt_lib_ps_init(); + if (iRet) { + WMT_ERR_FUNC("wmt_lib_ps_init() fail(%d)\n", iRet); + return -4; + } +#endif + + /* 3. start: start running mtk_wmtd */ + iRet = osal_thread_run(pThread); + if (iRet) { + WMT_ERR_FUNC("osal_thread_run(wmtd 0x%p) fail(%d)\n", pThread, iRet); + return -5; + } + + iRet = osal_thread_run(pWorkerThread); + if (iRet) { + WMT_ERR_FUNC("osal_thread_run(worker 0x%p) fail(%d)\n", pWorkerThread, iRet); + return -5; + } + /*4. register irq callback to WMT-PLAT */ + wmt_plat_irq_cb_reg(wmt_lib_ps_irq_cb); + /*5. register audio if control callback to WMT-PLAT */ + wmt_plat_aif_cb_reg(wmt_lib_set_aif); + /*6. register function control callback to WMT-PLAT */ + wmt_plat_func_ctrl_cb_reg(mtk_wcn_wmt_func_ctrl_for_plat); + + wmt_plat_deep_idle_ctrl_cb_reg(mtk_wcn_consys_stp_btif_dpidle_ctrl); + /*7 reset gps/bt state */ + + mtk_wcn_wmt_system_state_reset(); + +#ifndef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + mtk_wcn_wmt_exp_init(); +#endif + +#if CFG_WMT_LTE_COEX_HANDLING + wmt_idc_init(); +#endif + + INIT_WORK(&(wmt_assert_work.work), wmt_lib_assert_work_cb); + + WMT_DBG_FUNC("init success\n"); + return 0; +} + + +INT32 wmt_lib_deinit(VOID) +{ + INT32 iRet; + P_DEV_WMT pDevWmt; + P_OSAL_THREAD pThread; + P_OSAL_THREAD pWorkerThread; + INT32 i; + INT32 iResult; + struct vendor_patch_table *table = &(gDevWmt.patch_table); + + pDevWmt = &gDevWmt; + pThread = &gDevWmt.thread; + pWorkerThread = &gDevWmt.worker_thread; + iResult = 0; + + /* stop->deinit->destroy */ + + /* 1. stop: stop running mtk_wmtd */ + iRet = osal_thread_stop(pThread); + if (iRet) { + WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pThread, iRet); + iResult += 1; + } + + iRet = osal_thread_stop(pWorkerThread); + if (iRet) { + WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pWorkerThread, iRet); + iResult += 1; + } + + /* 2. deinit: */ + +#if CFG_WMT_PS_SUPPORT + iRet = wmt_lib_ps_deinit(); + if (iRet) { + WMT_ERR_FUNC("wmt_lib_ps_deinit fail(%d)\n", iRet); + iResult += 2; + } +#endif + + iRet = wmt_plat_deinit(); + if (iRet) { + WMT_ERR_FUNC("wmt_plat_deinit fail(%d)\n", iRet); + iResult += 4; + } + + osal_event_deinit(&pDevWmt->cmdReq); + osal_signal_deinit(&pDevWmt->cmdResp); + + /* de-initialize stp resources */ + osal_event_deinit(&pDevWmt->rWmtRxWq); + + for (i = 0; i < WMT_OP_BUF_SIZE; i++) + osal_signal_deinit(&(pDevWmt->arQue[i].signal)); + + osal_sleepable_lock_deinit(&pDevWmt->rFreeOpQ.sLock); + osal_sleepable_lock_deinit(&pDevWmt->rActiveOpQ.sLock); + osal_sleepable_lock_deinit(&pDevWmt->rWorkerOpQ.sLock); + osal_sleepable_lock_deinit(&pDevWmt->mpu_lock); + osal_sleepable_lock_deinit(&pDevWmt->idc_lock); + osal_sleepable_lock_deinit(&pDevWmt->wlan_lock); + osal_sleepable_lock_deinit(&pDevWmt->assert_lock); + osal_sleepable_lock_deinit(&pDevWmt->psm_lock); + osal_event_deinit(&pDevWmt->rWmtdWq); + osal_event_deinit(&pDevWmt->rWmtdWorkerWq); + + for (i = 0; i < WMTDRV_TYPE_ANT; i++) { + kfree(pDevWmt->pWmtRomPatchInfo[i]); + pDevWmt->pWmtRomPatchInfo[i] = NULL; + } + + iRet = wmt_core_deinit(); + if (iRet) { + WMT_ERR_FUNC("wmt_core_deinit fail(%d)\n", iRet); + iResult += 8; + } + + /* 3. destroy */ + iRet = osal_thread_destroy(pThread); + if (iRet) { + WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pThread, iRet); + iResult += 16; + } + + iRet = osal_thread_destroy(pWorkerThread); + if (iRet) { + WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", pWorkerThread, iRet); + iResult += 32; + } + + iRet = wmt_conf_deinit(); + if (iRet) { + WMT_ERR_FUNC("wmt_conf_deinit fail(%d)\n", iRet); + iResult += 64; + } + + osal_memset(&gDevWmt, 0, sizeof(gDevWmt)); +#if 0 +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + mtk_wcn_wmt_exp_deinit(); +#endif +#endif + +#if CFG_WMT_LTE_COEX_HANDLING + wmt_idc_deinit(); +#endif + + if (table->active_version != NULL) { + for (i = 0; i < table->num; i++) { + if (table->active_version[i]) + osal_free(table->active_version[i]); + } + osal_free(table->active_version); + table->active_version = NULL; + } + + WMT_STEP_DEINIT_FUNC(); + + return iResult; +} + +VOID wmt_lib_flush_rx(VOID) +{ + mtk_wcn_stp_flush_rx_queue(WMT_TASK_INDX); +} + +INT32 wmt_lib_trigger_cmd_signal(INT32 result) +{ + P_OSAL_SIGNAL pSignal = &gDevWmt.cmdResp; + + gDevWmt.cmdResult = result; + osal_raise_signal(pSignal); + WMT_DBG_FUNC("wakeup cmdResp\n"); + return 0; +} + +P_OSAL_EVENT wmt_lib_get_cmd_event(VOID) +{ + return &gDevWmt.cmdReq; +} + +INT32 wmt_lib_set_patch_name(PUINT8 cPatchName) +{ + osal_strncpy(gDevWmt.cPatchName, cPatchName, NAME_MAX); + return 0; +} + +INT32 wmt_lib_set_uart_name(PINT8 cUartName) +{ +#if WMT_PLAT_ALPS + + WMT_DBG_FUNC("orig uart: %s\n", wmt_uart_port_desc); +#endif + osal_strncpy(gDevWmt.cUartName, cUartName, NAME_MAX); +#if WMT_PLAT_ALPS + wmt_uart_port_desc = gDevWmt.cUartName; + WMT_DBG_FUNC("new uart: %s\n", wmt_uart_port_desc); +#endif + return 0; +} + +INT32 wmt_lib_set_hif(ULONG hifconf) +{ + UINT32 val; + P_WMT_HIF_CONF pHif = &gDevWmt.rWmtHifConf; + + val = hifconf & 0xF; + switch (val) { + case STP_UART_FULL: + pHif->hifType = WMT_HIF_UART; + pHif->uartFcCtrl = ((hifconf & 0xc) >> 2); + val = (hifconf >> 8); + pHif->au4HifConf[0] = val; + pHif->au4HifConf[1] = val; + mtk_wcn_stp_set_if_tx_type(STP_UART_IF_TX); + wmt_plat_set_comm_if_type(STP_UART_IF_TX); + break; + case STP_SDIO: + pHif->hifType = WMT_HIF_SDIO; + mtk_wcn_stp_set_if_tx_type(STP_SDIO_IF_TX); + wmt_plat_set_comm_if_type(STP_SDIO_IF_TX); + break; + case STP_BTIF_FULL: + pHif->hifType = WMT_HIF_BTIF; + mtk_wcn_stp_set_if_tx_type(STP_BTIF_IF_TX); + break; + default: + WMT_WARN_FUNC("invalid stp mode: %lu %u\n", hifconf, val); + return -1; + } + + val = (hifconf & 0xF0) >> 4; + if (val == WMT_FM_COMM) { + pHif->au4StrapConf[0] = WMT_FM_COMM; + } else if (val == WMT_FM_I2C) { + pHif->au4StrapConf[0] = WMT_FM_I2C; + } else { + WMT_WARN_FUNC("invalid fm mode: %u\n", val); + return -2; + } + + WMT_DBG_FUNC("new hifType:%d, fcCtrl:%d, baud:%d, fm:%d\n", + pHif->hifType, pHif->uartFcCtrl, pHif->au4HifConf[0], pHif->au4StrapConf[0]); + return 0; +} + + +P_WMT_HIF_CONF wmt_lib_get_hif(VOID) +{ + return &gDevWmt.rWmtHifConf; +} + +PUINT8 wmt_lib_get_cmd(VOID) +{ + if (osal_test_and_clear_bit(WMT_STAT_CMD, &gDevWmt.state)) + return gDevWmt.cCmd; + + return NULL; +} + +MTK_WCN_BOOL wmt_lib_get_cmd_status(VOID) +{ + return osal_test_bit(WMT_STAT_CMD, &gDevWmt.state) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE; +} + +MTK_WCN_BOOL wmt_lib_stp_is_btif_fullset_mode(VOID) +{ + return mtk_wcn_stp_is_btif_fullset_mode(); +} + +#if CFG_WMT_PS_SUPPORT +INT32 wmt_lib_ps_set_idle_time(UINT32 psIdleTime) +{ + gPsIdleTime = psIdleTime; + return gPsIdleTime; +} + +INT32 wmt_lib_ps_ctrl(UINT32 state) +{ + if (state == 0) { + wmt_lib_ps_disable(); + gPsEnable = 0; + } else { + gPsEnable = 1; + wmt_lib_ps_enable(); + } + return 0; +} + + +INT32 wmt_lib_ps_enable(VOID) +{ + if (gPsEnable) + mtk_wcn_stp_psm_enable(gPsIdleTime); + + return 0; +} + +INT32 wmt_lib_ps_disable(VOID) +{ + if (gPsEnable) + return mtk_wcn_stp_psm_disable(); + + return 0; +} + +INT32 wmt_lib_ps_init(VOID) +{ + /* mtk_wcn_stp_psm_register_wmt_cb(wmt_lib_ps_stp_cb); */ + return 0; +} + +INT32 wmt_lib_ps_deinit(VOID) +{ + /* mtk_wcn_stp_psm_unregister_wmt_cb(); */ + return 0; +} + +static MTK_WCN_BOOL wmt_lib_ps_action(MTKSTP_PSM_ACTION_T action) +{ + P_OSAL_OP lxop; + MTK_WCN_BOOL bRet; + UINT32 u4Wait; + P_OSAL_SIGNAL pSignal; + + lxop = wmt_lib_get_free_op(); + if (!lxop) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &lxop->signal; + pSignal->timeoutValue = 0; + lxop->op.opId = WMT_OPID_PWR_SV; + lxop->op.au4OpData[0] = action; + lxop->op.au4OpData[1] = (SIZE_T) mtk_wcn_stp_psm_notify_stp; + u4Wait = 0; + bRet = wmt_lib_put_act_op(lxop); + return bRet; +} + +#if CFG_WMT_LTE_COEX_HANDLING +MTK_WCN_BOOL wmt_lib_handle_idc_msg(conn_md_ipc_ilm_t *idc_infor) +{ + P_OSAL_OP lxop; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_OSAL_SIGNAL pSignal; + INT32 ret = 0; + UINT16 msg_len = 0; + +#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING + MTK_WCN_BOOL unknown_msgid = MTK_WCN_BOOL_FALSE; +#endif + WMT_DBG_FUNC("idc_infor from conn_md is 0x%p\n", idc_infor); + + ret = wmt_lib_idc_lock_aquire(); + if (ret) { + WMT_ERR_FUNC("--->lock idc_lock failed, ret=%d\n", ret); + return MTK_WCN_BOOL_FALSE; + } + msg_len = idc_infor->local_para_ptr->msg_len - osal_sizeof(local_para); + if (msg_len > WMT_IDC_MSG_MAX_SIZE) { + wmt_lib_idc_lock_release(); + WMT_ERR_FUNC("abnormal idc msg len:%d\n", msg_len); + return -2; + } + osal_memcpy(&gDevWmt.msg_local_buffer[0], &msg_len, osal_sizeof(msg_len)); + osal_memcpy(&gDevWmt.msg_local_buffer[osal_sizeof(msg_len)], + &(idc_infor->local_para_ptr->data[0]), msg_len - 1); + wmt_lib_idc_lock_release(); + + lxop = wmt_lib_get_free_op(); + if (!lxop) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + pSignal = &lxop->signal; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + lxop->op.opId = WMT_OPID_IDC_MSG_HANDLING; + lxop->op.au4OpData[0] = (size_t) gDevWmt.msg_local_buffer; + + /*msg opcode fill rule is still not clrear,need scott comment */ + /***********************************************************/ + WMT_DBG_FUNC("ilm msg id is (0x%08x)\n", idc_infor->msg_id); + +#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING + switch (idc_infor->msg_id) { + case IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND: + lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_PARA; + break; + case IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND: + lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_FREQ; + break; + case IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND: + lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_WIFI_MAX_POWER; + break; + case IPC_MSG_ID_EL1_LTE_TX_IND: + lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_INDICATION; + break; + case IPC_MSG_ID_EL1_LTE_CONNECTION_STATUS_IND: + lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_CONNECTION_STAS; + break; + case IPC_MSG_ID_EL1_LTE_HW_INTERFACE_IND: + lxop->op.au4OpData[1] = WMT_IDC_TX_OPCODE_LTE_HW_IF_INDICATION; + break; + default: + unknown_msgid = MTK_WCN_BOOL_TRUE; + break; + } + if (unknown_msgid == MTK_WCN_BOOL_FALSE) { + /*wake up chip first */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(lxop); + return MTK_WCN_BOOL_FALSE; + } + + bRet = wmt_lib_put_act_op(lxop); + ENABLE_PSM_MONITOR(); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("WMT_OPID_IDC_MSG_HANDLING fail(%d)\n", bRet); + } else { + WMT_DBG_FUNC("OPID(%d) type(%zu) ok\n", + lxop->op.opId, lxop->op.au4OpData[1]); + } + } else { + bRet = MTK_WCN_BOOL_FALSE; + wmt_lib_put_op_to_free_queue(lxop); + WMT_ERR_FUNC("unknown msgid from LTE(%d)\n", idc_infor->msg_id); + } +#else + if ((idc_infor->msg_id >= IPC_EL1_MSG_ID_BEGIN) + && (idc_infor->msg_id <= IPC_EL1_MSG_ID_BEGIN + IPC_EL1_MSG_ID_RANGE)) { + lxop->op.au4OpData[1] = idc_infor->msg_id - IPC_EL1_MSG_ID_BEGIN + LTE_MSG_ID_OFFSET - 1; + + /*wake up chip first */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(lxop); + return MTK_WCN_BOOL_FALSE; + } + + bRet = wmt_lib_put_act_op(lxop); + ENABLE_PSM_MONITOR(); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("WMT_OPID_IDC_MSG_HANDLING fail(%d)\n", bRet); + } else { + WMT_DBG_FUNC("wmt_lib_handle_idc_msg OPID(%d) type(%zu) ok\n", + lxop->op.opId, lxop->op.au4OpData[1]); + } + } else { + wmt_lib_put_op_to_free_queue(lxop); + WMT_ERR_FUNC("msgid(%d) out of range,wmt drop it!\n", idc_infor->msg_id); + } + +#endif + return bRet; +} +#endif + +static MTK_WCN_BOOL wmt_lib_ps_do_sleep(VOID) +{ + return wmt_lib_ps_action(SLEEP); +} + +static MTK_WCN_BOOL wmt_lib_ps_do_wakeup(VOID) +{ + return wmt_lib_ps_action(WAKEUP); +} + +static MTK_WCN_BOOL wmt_lib_ps_do_host_awake(VOID) +{ + return wmt_lib_ps_action(HOST_AWAKE); +} + +/* extern int g_block_tx; */ +static INT32 wmt_lib_ps_handler(MTKSTP_PSM_ACTION_T action) +{ + INT32 ret; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + static DEFINE_RATELIMIT_STATE(_rs, 2 * HZ, 1); + + ret = 0; /* TODO:[FixMe][George] initial value or compile warning? */ + /* if(g_block_tx && (action == SLEEP)) */ + if ((mtk_wcn_stp_coredump_start_get() != 0) && (action == SLEEP)) { + ret = mtk_wcn_stp_psm_notify_stp(SLEEP); + return ret; + } + + /*MT662x Not Ready */ + if (!mtk_wcn_stp_is_ready()) { + if (!mtk_wcn_stp_is_sdio_mode()) { + WMT_DBG_FUNC("MT662x Not Ready, Dont Send Sleep/Wakeup Command\n"); + ret = mtk_wcn_stp_psm_notify_stp(ROLL_BACK); + } else { + WMT_DBG_FUNC("MT662x Not Ready, SDIO mode, skip EIRQ"); + } + return ret; + } + + if (action == SLEEP) { + WMT_DBG_FUNC("send op--------------------------------> sleep job\n"); + + if (!mtk_wcn_stp_is_sdio_mode()) { + bRet = wmt_lib_ps_do_sleep(); + ret = bRet ? 0 : -1; + WMT_DBG_FUNC("enable host eirq\n"); + wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_EN); +#if CFG_WMT_DUMP_INT_STATUS + if (wmt_plat_dump_BGF_irq_status() == MTK_WCN_BOOL_TRUE) + wmt_plat_BGF_irq_dump_status(); +#endif + } else { + /* ret = mtk_wcn_stp_sdio_do_own_set(); */ + if (sdio_own_ctrl) { + ret = (*sdio_own_ctrl) (OWN_SET); + mtk_wcn_stp_dbg_pkt_log(8, PKT_DIR_TX); + } else { + WMT_ERR_FUNC("sdio_own_ctrl is not registered\n"); + ret = -1; + } + + if (!ret) { + mtk_wcn_stp_psm_notify_stp(SLEEP); + } else if (ret == -2) { + mtk_wcn_stp_psm_notify_stp(ROLL_BACK); + WMT_WARN_FUNC + ("========[SDIO-PS] rollback due to tx busy ========%%\n"); + } else { + mtk_wcn_stp_psm_notify_stp(SLEEP); + WMT_ERR_FUNC + ("========[SDIO-PS] set own fails! ========%%\n"); + } + } + + WMT_DBG_FUNC("send op<--------------------------------- sleep job\n"); + } else if (action == WAKEUP) { + WMT_DBG_FUNC("send op --------------------------------> wake job\n"); + + if (!mtk_wcn_stp_is_sdio_mode()) { + WMT_DBG_FUNC("disable host eirq\n"); +#if CFG_WMT_DUMP_INT_STATUS + if (wmt_plat_dump_BGF_irq_status() == MTK_WCN_BOOL_TRUE) + wmt_plat_BGF_irq_dump_status(); +#endif + wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); + bRet = wmt_lib_ps_do_wakeup(); + ret = bRet ? 0 : -1; + } else { + /* ret = mtk_wcn_stp_sdio_do_own_clr(); */ + + if (sdio_own_ctrl) { + ret = (*sdio_own_ctrl) (OWN_CLR); + } else { + WMT_ERR_FUNC("sdio_own_ctrl is not registered\n"); + ret = -1; + } + + if (!ret) { + mtk_wcn_stp_psm_notify_stp(WAKEUP); + } else { + mtk_wcn_stp_psm_notify_stp(WAKEUP); + WMT_ERR_FUNC + ("========[SDIO-PS] set own back fails! ========%%\n"); + } + } + + WMT_DBG_FUNC("send op<--------------------------------- wake job\n"); + } else if (action == HOST_AWAKE) { + WMT_DBG_FUNC("send op --------------------------------> host awake job\n"); + + if (!mtk_wcn_stp_is_sdio_mode()) { + WMT_DBG_FUNC("disable host eirq\n"); + /* IRQ already disabled */ + /* wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); */ +#if 0 + if (wmt_plat_dump_BGF_irq_status() == MTK_WCN_BOOL_TRUE) + wmt_plat_BGF_irq_dump_status(); +#endif + bRet = wmt_lib_ps_do_host_awake(); + ret = bRet ? 0 : -1; + } else { + WMT_DBG_FUNC("[SDIO-PS] SDIO host awake! ####\n"); + + /* ret = mtk_wcn_stp_sdio_do_own_clr(); */ + + if (sdio_own_ctrl) { + ret = (*sdio_own_ctrl) (OWN_CLR); + } else { + WMT_ERR_FUNC("sdio_own_ctrl is not registered\n"); + ret = -1; + } + + mtk_wcn_stp_psm_notify_stp(HOST_AWAKE); + } + + WMT_DBG_FUNC("send op<--------------------------------- host awake job\n"); + } else if (action == EIRQ) { + WMT_DBG_FUNC("send op --------------------------------> eirq job\n"); + + if (!mtk_wcn_stp_is_sdio_mode()) { + if (__ratelimit(&_rs)) + pr_info("conn2ap_btif0_wakeup_out_b EIRQ handler\n"); + WMT_DBG_FUNC("disable host eirq\n"); + /* Disable interrupt */ + /*wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS);*/ + ret = mtk_wcn_stp_psm_notify_stp(EIRQ); + } else { + WMT_DBG_FUNC("[SDIO-PS]sdio own-back eirq!######\n"); + ret = mtk_wcn_stp_psm_notify_stp(EIRQ); + } + + WMT_DBG_FUNC("send op<--------------------------------- eirq job\n"); + } + + return ret; +} +#endif /* end of CFG_WMT_PS_SUPPORT */ + +INT32 wmt_lib_ps_stp_cb(MTKSTP_PSM_ACTION_T action) +{ +#if CFG_WMT_PS_SUPPORT + return wmt_lib_ps_handler(action); +#else + WMT_WARN_FUNC("CFG_WMT_PS_SUPPORT is not set\n"); + return 0; +#endif +} + +VOID wmt_lib_set_bt_link_status(INT32 type, INT32 value) +{ + WMT_INFO_FUNC("t = %d, v = %d, no_acl = %d, no_br = %d\n", + type, value, g_bt_no_acl_link, g_bt_no_br_acl_link); + + if (type == 0) + g_bt_no_acl_link = value; + else if (type == 1) + g_bt_no_br_acl_link = value; +} + +/* + * Allow BT to reset as long as one of the conditions is true. + * 1. no ACL link + * 2. no BR ACL link at 2 AM + */ +static INT32 wmt_lib_is_bt_able_to_reset(VOID) +{ + if (g_bt_no_acl_link) + return 1; + else if (g_bt_no_br_acl_link) { + struct timespec64 time; + ULONG local_time; + struct rtc_time tm; + + ktime_get_ts64(&time); + local_time = (ULONG)(time.tv_sec - (sys_tz.tz_minuteswest * 60)); + rtc_time64_to_tm(local_time, &tm); + if (tm.tm_hour == 2) + return 1; + } + return 0; +} + +INT32 wmt_lib_update_fw_patch_chip_rst(VOID) +{ + MTK_WCN_BOOL wifiDrvOwn = MTK_WCN_BOOL_FALSE; + + if (g_fw_patch_update_rst == 0) + return 0; + + if (chip_reset_only == 1) + return 0; + + if (time_before_eq64(get_jiffies_64(), fw_patch_rst_time)) + return 0; + + if (wmt_lib_get_drv_status(WMTDRV_TYPE_WIFI) == DRV_STS_FUNC_ON) { + if (wmt_lib_wlan_lock_trylock() == 0) + return 0; + + if (mtk_wcn_wlan_is_wifi_drv_own != NULL) + wifiDrvOwn = ((*mtk_wcn_wlan_is_wifi_drv_own)() == 0) ? MTK_WCN_BOOL_FALSE : MTK_WCN_BOOL_TRUE; + + wmt_lib_wlan_lock_release(); + } + + if (wmt_lib_get_drv_status(WMTDRV_TYPE_BT) == DRV_STS_FUNC_ON && + wmt_lib_is_bt_able_to_reset() == 0) + return 0; + + if (wmt_dev_get_early_suspend_state() == MTK_WCN_BOOL_FALSE + || wmt_lib_get_drv_status(WMTDRV_TYPE_FM) == DRV_STS_FUNC_ON + || mtk_wcn_stp_is_ready() == MTK_WCN_BOOL_FALSE + || wifiDrvOwn == MTK_WCN_BOOL_TRUE) + return 0; + + if (wmt_lib_psm_lock_trylock() == 0) + return 0; + wmt_lib_psm_lock_release(); + + wmt_lib_fw_patch_update_rst_ctrl(0); + chip_reset_only = 1; + fw_patch_rst_time = get_jiffies_64() + (FW_PATCH_UPDATE_RST_DURATION * HZ); + WMT_INFO_FUNC("Invoke whole chip reset from fw patch update!!!\n"); + return wmt_lib_trigger_reset(); +} + +MTK_WCN_BOOL wmt_lib_is_quick_ps_support(VOID) +{ + if ((g_quick_sleep_ctrl) && (wmt_dev_get_early_suspend_state() == MTK_WCN_BOOL_TRUE)) + return wmt_core_is_quick_ps_support(); + else + return MTK_WCN_BOOL_FALSE; +} + +VOID wmt_lib_ps_irq_cb(VOID) +{ +#if CFG_WMT_PS_SUPPORT + wmt_lib_ps_handler(EIRQ); +#else + WMT_DBG_FUNC("CFG_WMT_PS_SUPPORT is not set\n"); + return; +#endif +} + +VOID wmt_lib_ps_set_sdio_psop(PF_WMT_SDIO_PSOP own_cb) +{ +#if CFG_WMT_PS_SUPPORT + sdio_own_ctrl = own_cb; +#endif +} + +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +VOID wmt_lib_sdio_deep_sleep_flag_set_cb_reg(PF_WMT_SDIO_DEEP_SLEEP flag_cb) +{ + sdio_deep_sleep_flag_set = flag_cb; +} +#endif + +VOID wmt_lib_sdio_reg_rw_cb(PF_WMT_SDIO_DEBUG reg_rw_cb) +{ + sdio_reg_rw = reg_rw_cb; +} + +UINT32 wmt_lib_wait_event_checker(P_OSAL_THREAD pThread) +{ + P_DEV_WMT pDevWmt; + + if (pThread) { + pDevWmt = (P_DEV_WMT) (pThread->pThreadData); + return !RB_EMPTY(&pDevWmt->rActiveOpQ); + } + WMT_ERR_FUNC("pThread(NULL)\n"); + return 0; +} + +UINT32 wmt_lib_worker_wait_event_checker(P_OSAL_THREAD pThread) +{ + P_DEV_WMT pDevWmt; + + if (pThread) { + pDevWmt = (P_DEV_WMT) (pThread->pThreadData); + return !RB_EMPTY(&pDevWmt->rWorkerOpQ); + } + WMT_ERR_FUNC("pThread(NULL)\n"); + return 0; +} + +static INT32 wmtd_thread(void *pvData) +{ + P_DEV_WMT pWmtDev = (P_DEV_WMT) pvData; + P_OSAL_EVENT pEvent = NULL; + P_OSAL_OP pOp; + INT32 iResult; + + if (pWmtDev == NULL) { + WMT_ERR_FUNC("pWmtDev(NULL)\n"); + return -1; + } + WMT_INFO_FUNC("wmtd thread starts\n"); + + pEvent = &(pWmtDev->rWmtdWq); + + for (;;) { + pOp = NULL; + pEvent->timeoutValue = 0; +/* osal_thread_wait_for_event(&pWmtDev->thread, pEvent);*/ + osal_thread_wait_for_event(&pWmtDev->thread, pEvent, wmt_lib_wait_event_checker); + + if (osal_thread_should_stop(&pWmtDev->thread)) { + WMT_INFO_FUNC("wmtd thread should stop now...\n"); + /* TODO: clean up active opQ */ + break; + } + + /* get Op from activeQ */ + pOp = wmt_lib_get_op(&pWmtDev->rActiveOpQ); + if (!pOp) { + WMT_WARN_FUNC("get_lxop activeQ fail\n"); + continue; + } + + osal_op_history_save(&pWmtDev->wmtd_op_history, pOp); + +#if 0 /* wmt_core_opid_handler will do sanity check on opId, so no usage here */ + id = lxop_get_opid(pLxOp); + if (id >= WMT_OPID_MAX) { + WMT_WARN_FUNC("abnormal opid id: 0x%x\n", id); + iResult = -1; + goto handlerDone; + } +#endif + + if (osal_test_bit(WMT_STAT_RST_ON, &pWmtDev->state)) { + /* when whole chip reset, only HW RST and SW RST cmd can execute */ + if ((pOp->op.opId == WMT_OPID_HW_RST) + || (pOp->op.opId == WMT_OPID_SW_RST) + || (pOp->op.opId == WMT_OPID_GPIO_STATE)) { + iResult = wmt_core_opid(&pOp->op); + } else { + iResult = -2; + WMT_WARN_FUNC + ("Whole chip resetting, opid (0x%x) failed, iRet(%d)\n", + pOp->op.opId, iResult); + } + } else { + wmt_lib_set_current_op(pWmtDev, pOp); + iResult = wmt_core_opid(&pOp->op); + wmt_lib_set_current_op(pWmtDev, NULL); + } + + if (iResult) + WMT_WARN_FUNC("opid (0x%x) failed, iRet(%d)\n", pOp->op.opId, iResult); + + if (iResult == 0 && + (pOp->op.opId == WMT_OPID_WLAN_PROBE || pOp->op.opId == WMT_OPID_WLAN_REMOVE)) + continue; + + if (atomic_dec_and_test(&pOp->ref_count)) { + wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp); + } else if (osal_op_is_wait_for_signal(pOp)) { + osal_op_raise_signal(pOp, iResult); + } + + if (pOp->op.opId == WMT_OPID_EXIT) { + WMT_INFO_FUNC("wmtd thread received exit signal\n"); + break; + } + } + + WMT_INFO_FUNC("wmtd thread exits succeed\n"); + + return 0; +}; + +static INT32 met_thread(void *pvData) +{ + P_DEV_WMT p_wmtdev = (P_DEV_WMT) pvData; + INT32 log_ctrl; + UINT32 read_ptr = 0; + UINT32 write_ptr = 0; + UINT32 emi_met_size = 0; + UINT32 emi_met_offset = 0; + P_CONSYS_EMI_ADDR_INFO emi_info; + PUINT8 emi_met_base = NULL; + PINT32 met_dump_buf = 0; + UINT32 met_buf_offset = 0; + UINT32 value = 0; + + if (p_wmtdev == NULL) { + WMT_ERR_FUNC("pWmtDev(NULL)\n"); + return -1; + } + + WMT_INFO_FUNC("met thread starts\n"); + + emi_info = mtk_wcn_consys_soc_get_emi_phy_add(); + if (!emi_info) { + WMT_ERR_FUNC("get EMI info failed.\n"); + return -1; + } + + emi_met_size = emi_info->emi_met_size; + if (!emi_met_size) { + WMT_ERR_FUNC("get met emi size fail\n"); + return -1; + } + + emi_met_offset = emi_info->emi_met_data_offset; + if (!emi_met_offset) { + WMT_ERR_FUNC("get met emi offset fail\n"); + return -1; + } + + met_dump_buf = osal_malloc(MET_DUMP_SIZE); + if (!met_dump_buf) { + WMT_ERR_FUNC("alloc dump buffer fail\n"); + return -1; + } + osal_memset(met_dump_buf, 0, MET_DUMP_SIZE); + + emi_met_base = ioremap(emi_info->emi_ap_phy_addr + emi_met_offset, emi_met_size); + if (!emi_met_base) { + osal_free(met_dump_buf); + WMT_ERR_FUNC("met emi ioremap fail\n"); + return -1; + } + + WMT_INFO_FUNC("emi phy base:%x, emi vir base:%p, met offset:%x, size:%x\n", + emi_info->emi_ap_phy_addr, + emi_met_base, + emi_met_offset, + emi_met_size); + + + log_ctrl = p_wmtdev->met_log_ctrl; + if (log_ctrl) + osal_ftrace_print_ctrl(1); + + for (;;) { + if (osal_thread_should_stop(&p_wmtdev->met_thread)) { + WMT_INFO_FUNC("met thread should stop now...\n"); + goto met_exit; + } + + read_ptr = CONSYS_REG_READ(emi_met_base + EMI_MET_READ_OFFSET); + write_ptr = CONSYS_REG_READ(emi_met_base + EMI_MET_WRITE_OFFSET); + + if (read_ptr == write_ptr) + WMT_DBG_FUNC("read_ptr(0x%x) == write_ptr(0x%x) no met data need dump!!!\n", + read_ptr, write_ptr); + else if (write_ptr > (emi_met_size - EMI_MET_DATA_OFFSET)) { + WMT_ERR_FUNC("write_ptr(0x%x) overflow!!!\n", write_ptr); + wmt_lib_trigger_assert(WMTDRV_TYPE_WMT, 42); + goto met_exit; + } else { + if (read_ptr > write_ptr) { + for (; read_ptr < emi_met_size; read_ptr += 0x4) { + value = CONSYS_REG_READ(emi_met_base + EMI_MET_DATA_OFFSET + read_ptr); + met_dump_buf[met_buf_offset] = value; + met_buf_offset++; + if (met_buf_offset >= MET_DUMP_MAX_NUM) { + met_buf_offset = 0; + osal_buffer_dump_data(met_dump_buf, "MCU_MET_DATA:", + MET_DUMP_MAX_NUM, MET_DUMP_MAX_NUM, + log_ctrl); + } + } + read_ptr = 0; + } + + for (; read_ptr < write_ptr; read_ptr += 0x4) { + value = CONSYS_REG_READ(emi_met_base + EMI_MET_DATA_OFFSET + read_ptr); + met_dump_buf[met_buf_offset] = value; + met_buf_offset++; + if (met_buf_offset >= MET_DUMP_MAX_NUM) { + met_buf_offset = 0; + osal_buffer_dump_data(met_dump_buf, "MCU_MET_DATA:", MET_DUMP_MAX_NUM, + MET_DUMP_MAX_NUM, + log_ctrl); + } + } + CONSYS_REG_WRITE(emi_met_base, read_ptr); + } + osal_usleep_range(CONSYS_MET_WAIT, CONSYS_MET_WAIT); + } + +met_exit: + osal_free(met_dump_buf); + iounmap(emi_met_base); + WMT_INFO_FUNC("met thread exits succeed\n"); + + return 0; +}; + +static VOID wmt_lib_wmtd_worker_thread_timeout_handler(ULONG data) +{ + schedule_work(&gDevWmt.wmtd_worker_thread_work); +} + +static VOID wmt_lib_wmtd_worker_thread_work_handler(struct work_struct *work) +{ + PUINT8 pbuf = NULL; + INT32 len = 0; + P_OSAL_OP pOp; + + pOp = wmt_lib_get_worker_op(&gDevWmt); + if (pOp) { + switch (pOp->op.opId) { + case WMT_OPID_WLAN_PROBE: + pbuf = "DrvWMT turn on wifi fail, just collect SYS_FTRACE to DB"; + len = osal_strlen(pbuf); + break; + case WMT_OPID_WLAN_REMOVE: + pbuf = "DrvWMT turn off wifi fail, just collect SYS_FTRACE to DB"; + len = osal_strlen(pbuf); + break; + default: + pbuf = "DrvWMT unknown op fail, just collect SYS_FTRACE to DB"; + len = osal_strlen(pbuf); + break; + } + wmt_lib_trigger_assert_keyword(WMTDRV_TYPE_WIFI, 0, pbuf); + } +} + +static INT32 wmtd_worker_thread(void *pvData) +{ + P_DEV_WMT pWmtDev = (P_DEV_WMT) pvData; + P_OSAL_EVENT pEvent = NULL; + P_OSAL_OP pOp; + INT32 iResult = 0; + + pEvent = &(pWmtDev->rWmtdWorkerWq); + + for (;;) { + osal_thread_wait_for_event(&pWmtDev->worker_thread, pEvent, wmt_lib_worker_wait_event_checker); + + if (osal_thread_should_stop(&pWmtDev->worker_thread)) { + WMT_INFO_FUNC("wmtd worker thread should stop now...\n"); + /* TODO: clean up active opQ */ + break; + } + + /* get Op from activeWorkerQ */ + pOp = wmt_lib_get_op(&pWmtDev->rWorkerOpQ); + if (!pOp) { + WMT_WARN_FUNC("get activeWorkerQ fail\n"); + continue; + } + osal_op_history_save(&pWmtDev->worker_op_history, pOp); + + if (osal_test_bit(WMT_STAT_RST_ON, &pWmtDev->state)) { + iResult = -2; + WMT_WARN_FUNC("Whole chip resetting, opid (0x%x) failed, iRet(%d)\n", pOp->op.opId, iResult); + } else { + WMT_WARN_FUNC("opid: 0x%x", pOp->op.opId); + wmt_lib_set_worker_op(pWmtDev, pOp); + osal_timer_start(&gDevWmt.worker_timer, MAX_FUNC_ON_TIME); + iResult = wmt_core_opid(&pOp->op); + osal_timer_stop(&gDevWmt.worker_timer); + wmt_lib_set_worker_op(pWmtDev, NULL); + } + + if (iResult) + WMT_WARN_FUNC("opid (0x%x) failed, iRet(%d)\n", pOp->op.opId, iResult); + + if (atomic_dec_and_test(&pOp->ref_count)) + wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp); + else if (osal_op_is_wait_for_signal(pOp)) + osal_op_raise_signal(pOp, iResult); + } + + return 0; +} + +static MTK_WCN_BOOL wmt_lib_put_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) +{ + INT32 iRet; + + if (!pOpQ || !pOp) { + WMT_WARN_FUNC("invalid input param: pOpQ(0x%p), pLxOp(0x%p)\n", pOpQ, pOp); + osal_assert(pOpQ); + osal_assert(pOp); + return MTK_WCN_BOOL_FALSE; + } + + iRet = osal_lock_sleepable_lock(&pOpQ->sLock); + if (iRet) { + WMT_WARN_FUNC("osal_lock_sleepable_lock iRet(%d)\n", iRet); + return MTK_WCN_BOOL_FALSE; + } + +#if defined(CONFIG_MTK_ENG_BUILD) || defined(CONFIG_MT_ENG_BUILD) + if (osal_opq_has_op(pOpQ, pOp)) { + WMT_ERR_FUNC("Op(%p) already exists in queue(%p)\n", pOp, pOpQ); + iRet = -2; + } +#endif + + /* acquire lock success */ + if (!RB_FULL(pOpQ)) + RB_PUT(pOpQ, pOp); + else { + WMT_WARN_FUNC("RB_FULL(%p -> %p)\n", pOp, pOpQ); + iRet = -1; + } + + osal_unlock_sleepable_lock(&pOpQ->sLock); + + if (iRet) { + osal_opq_dump("FreeOpQ", &gDevWmt.rFreeOpQ); + osal_opq_dump("ActiveOpQ", &gDevWmt.rActiveOpQ); + return MTK_WCN_BOOL_FALSE; + } + return MTK_WCN_BOOL_TRUE; +} + + + +static P_OSAL_OP wmt_lib_get_op(P_OSAL_OP_Q pOpQ) +{ + P_OSAL_OP pOp; + INT32 iRet; + + if (pOpQ == NULL) { + WMT_ERR_FUNC("pOpQ = NULL\n"); + osal_assert(pOpQ); + return NULL; + } + + iRet = osal_lock_sleepable_lock(&pOpQ->sLock); + if (iRet) { + WMT_ERR_FUNC("osal_lock_sleepable_lock iRet(%d)\n", iRet); + return NULL; + } + + /* acquire lock success */ + RB_GET(pOpQ, pOp); + osal_unlock_sleepable_lock(&pOpQ->sLock); + + if (pOp == NULL) { + P_OSAL_OP pCurOp = wmt_lib_get_current_op(&gDevWmt); + + WMT_WARN_FUNC("RB_GET(%p) return NULL\n", pOpQ); + if (pCurOp != NULL) + WMT_WARN_FUNC("Current opId (%d)\n", pCurOp->op.opId); + + wmt_lib_print_wmtd_op_history(); + wmt_lib_print_worker_op_history(); + osal_opq_dump("FreeOpQ", &gDevWmt.rFreeOpQ); + osal_opq_dump("ActiveOpQ", &gDevWmt.rActiveOpQ); + osal_assert(pOp); + } + + return pOp; +} + + +INT32 wmt_lib_put_op_to_free_queue(P_OSAL_OP pOp) +{ + P_DEV_WMT pWmtDev = &gDevWmt; + + if (wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp) == MTK_WCN_BOOL_FALSE) + return -1; + + return 0; +} + + +P_OSAL_OP wmt_lib_get_free_op(VOID) +{ + P_OSAL_OP pOp = NULL; + P_DEV_WMT pDevWmt = &gDevWmt; + + osal_assert(pDevWmt); + pOp = wmt_lib_get_op(&pDevWmt->rFreeOpQ); + if (pOp) { + osal_memset(pOp, 0, osal_sizeof(OSAL_OP)); + } + return pOp; +} + +MTK_WCN_BOOL wmt_lib_put_act_op(P_OSAL_OP pOp) +{ + P_DEV_WMT pWmtDev = &gDevWmt; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_OSAL_SIGNAL pSignal = NULL; + INT32 waitRet = -1; + + osal_assert(pWmtDev); + osal_assert(pOp); + + do { + if (!pWmtDev || !pOp) { + WMT_ERR_FUNC("pWmtDev(0x%p), pOp(0x%p)\n", pWmtDev, pOp); + break; + } + + /* Init ref_count to 1 indicating that current thread holds a ref to it */ + atomic_set(&pOp->ref_count, 1); + + if ((mtk_wcn_stp_coredump_start_get() != 0) && + (pOp->op.opId != WMT_OPID_HW_RST) && + (pOp->op.opId != WMT_OPID_SW_RST) && (pOp->op.opId != WMT_OPID_GPIO_STATE)) { + WMT_WARN_FUNC("block tx flag is set\n"); + break; + } + pSignal = &pOp->signal; +/* pOp->u4WaitMs = u4WaitMs; */ + if (pSignal->timeoutValue) { + pOp->result = -9; + osal_signal_init(pSignal); + } + + /* Increment ref_count by 1 as wmtd thread will hold a reference also, + * this must be done here instead of on target thread, because + * target thread might not be scheduled until a much later time, + * allowing current thread to decrement ref_count at the end of function, + * putting op back to free queue before target thread has a chance to process. + */ + atomic_inc(&pOp->ref_count); + + /* put to active Q */ + bRet = wmt_lib_put_op(&pWmtDev->rActiveOpQ, pOp); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("put to active queue fail\n"); + atomic_dec(&pOp->ref_count); + break; + } + + /* wake up wmtd */ + /* wake_up_interruptible(&pWmtDev->rWmtdWq); */ + osal_trigger_event(&pWmtDev->rWmtdWq); + + if (pSignal->timeoutValue == 0) { + bRet = MTK_WCN_BOOL_TRUE; + /* clean it in wmtd */ + break; + } + + /* check result */ + /* wait_ret = wait_for_completion_interruptible_timeout(&pOp->comp, msecs_to_jiffies(u4WaitMs)); */ + /* wait_ret = wait_for_completion_timeout(&pOp->comp, msecs_to_jiffies(u4WaitMs)); */ + if (pOp->op.opId == WMT_OPID_FUNC_ON && + pOp->op.au4OpData[0] == WMTDRV_TYPE_WIFI) + waitRet = osal_wait_for_signal_timeout(pSignal, &pWmtDev->worker_thread); + else + waitRet = osal_wait_for_signal_timeout(pSignal, &pWmtDev->thread); + WMT_DBG_FUNC("osal_wait_for_signal_timeout:%d\n", waitRet); + + /* if (unlikely(!wait_ret)) { */ + if (waitRet == 0) + WMT_ERR_FUNC("opId(%d) completion timeout\n", pOp->op.opId); + else if (pOp->result) + WMT_WARN_FUNC("opId(%d) result:%d\n", pOp->op.opId, pOp->result); + + /* op completes, check result */ + bRet = (pOp->result) ? MTK_WCN_BOOL_FALSE : MTK_WCN_BOOL_TRUE; + } while (0); + + if (pOp && atomic_dec_and_test(&pOp->ref_count)) { + /* put Op back to freeQ */ + wmt_lib_put_op(&pWmtDev->rFreeOpQ, pOp); + } + + return bRet; +} + +MTK_WCN_BOOL wmt_lib_put_worker_op(P_OSAL_OP pOp) +{ + P_DEV_WMT pWmtDev = &gDevWmt; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + + osal_assert(pWmtDev); + osal_assert(pOp); + + do { + if (!pWmtDev || !pOp) { + WMT_ERR_FUNC("pWmtDev(0x%p), pOp(0x%p)\n", pWmtDev, pOp); + break; + } + + /* put to activeWorker Q */ + bRet = wmt_lib_put_op(&pWmtDev->rWorkerOpQ, pOp); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("put to ActiveWorker queue fail\n"); + break; + } + + /* wake up wmtd_worker */ + osal_trigger_event(&pWmtDev->rWmtdWorkerWq); + } while (0); + + return bRet; +} + +/* TODO:[ChangeFeature][George] is this function obsoleted? */ +#if 0 +INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask) +{ + P_WMT_LXOP lxop; + MTK_WCN_BOOL bRet; + PUINT32 plv = NULL; + UINT32 pbuf[2]; + P_OSAL_EVENT pSignal = NULL; + + if (!pvalue) { + WMT_WARN_FUNC("!pvalue\n"); + return -1; + } + lxop = wmt_lib_get_free_lxop(); + if (!lxop) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + + return -1; + } + + plv = (PUINT32) (((UINT32) pbuf + 0x3) & ~0x3UL); + *plv = *pvalue; + pSignal = &lxop->signal; + WMT_DBG_FUNC("OPID_REG_RW isWrite(%d) offset(0x%x) value(0x%x) mask(0x%x)\n", + isWrite, offset, *pvalue, mask); + + lxop->op.opId = WMT_OPID_REG_RW; + lxop->op.au4OpData[0] = isWrite; + lxop->op.au4OpData[1] = offset; + lxop->op.au4OpData[2] = (UINT32) plv; + lxop->op.au4OpData[3] = mask; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + + DISABLE_PSM_MONITOR(); + bRet = wmt_lib_put_act_lxop(lxop); + ENABLE_PSM_MONITOR(); + + if (bRet != MTK_WCN_BOOL_FALSE) { + WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n", + isWrite, offset, *plv, mask); + if (!isWrite) + *pvalue = *plv; + } else { + WMT_WARN_FUNC + ("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n", + isWrite, offset, *plv, mask, bRet); + } + + return bRet; +} +#endif + +/* TODO:[ChangeFeature][George] is this function obsoleted? */ +#if 0 +static VOID wmt_lib_clear_chip_id(VOID) +{ +/* + * gDevWmt.pChipInfo = NULL; +*/ + gDevWmt.hw_ver = WMTHWVER_INVALID; +} +#endif + +UINT32 wmt_lib_get_icinfo(ENUM_WMT_CHIPINFO_TYPE_T index) +{ + UINT32 chip_id = 0; + + if (index == WMTCHIN_CHIPID) { + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) + chip_id = gDevWmt.chip_id; + else + chip_id = mtk_wcn_consys_soc_chipid(); + WMT_INFO_FUNC("chip_id=[%x]", chip_id); + return chip_id; + } else if (index == WMTCHIN_HWVER) + return gDevWmt.hw_ver; + else if (index == WMTCHIN_FWVER) + return gDevWmt.fw_ver; + else if (index == WMTCHIN_IPVER) + return gDevWmt.ip_ver; + + return 0; + +} + + +PUINT8 wmt_lib_def_patch_name(VOID) +{ + WMT_INFO_FUNC("wmt-lib: use default patch name (%s)\n", gDevWmt.cPatchName); + return gDevWmt.cPatchName; +} + + +MTK_WCN_BOOL wmt_lib_is_therm_ctrl_support(ENUM_WMTTHERM_TYPE_T eType) +{ + MTK_WCN_BOOL bIsSupportTherm = MTK_WCN_BOOL_TRUE; + /* TODO:[FixMe][GeorgeKuo]: move IC-dependent checking to ic-implementation file */ + if ((gDevWmt.chip_id == 0x6620) && (gDevWmt.hw_ver == 0x8A00 /*E1*/ || gDevWmt.hw_ver == 0x8A01 /*E2*/)) { + WMT_ERR_FUNC("thermal command fail: chip version(HWVER:0x%04x) is not valid\n", + gDevWmt.hw_ver); + bIsSupportTherm = MTK_WCN_BOOL_FALSE; + } + if ((!osal_test_bit(WMT_STAT_STP_EN, &gDevWmt.state)) + || (!osal_test_bit(WMT_STAT_STP_RDY, &gDevWmt.state))) { + if (eType == WMTTHERM_READ) + WMT_INFO_FUNC + ("thermal command can`t send: STP is not enable(%d) or ready(%d)\n", + osal_test_bit(WMT_STAT_STP_EN, &gDevWmt.state), + osal_test_bit(WMT_STAT_STP_RDY, &gDevWmt.state)); + bIsSupportTherm = MTK_WCN_BOOL_FALSE; + } + + return bIsSupportTherm; +} + +MTK_WCN_BOOL wmt_lib_is_dsns_ctrl_support(VOID) +{ + /* TODO:[FixMe][GeorgeKuo]: move IC-dependent checking to ic-implementation file */ + if ((gDevWmt.chip_id == 0x6620) && (gDevWmt.hw_ver == 0x8A00 /*E1*/ || gDevWmt.hw_ver == 0x8A01 /*E2*/)) { + WMT_ERR_FUNC("thermal command fail: chip version(HWVER:0x%04x) is not valid\n", + gDevWmt.hw_ver); + return MTK_WCN_BOOL_FALSE; + } + + return MTK_WCN_BOOL_TRUE; +} + + +/*! + * \brief Update combo chip pin settings (GPIO) + * + * An internal library function to support various settings for chip GPIO. It is + * updated in a grouping way: configure all required pins in a single call. + * + * \param id desired pin ID to be controlled + * \param stat desired pin states to be set + * \param flag supplementary options for this operation + * + * \retval 0 operation success + * \retval -1 invalid id + * \retval -2 invalid stat + * \retval < 0 error for operation fail + */ +static INT32 wmt_lib_pin_ctrl(WMT_IC_PIN_ID id, WMT_IC_PIN_STATE stat, UINT32 flag) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + /* input sanity check */ + if (id >= WMT_IC_PIN_MAX) { + WMT_ERR_FUNC("invalid ic pin id(%d)\n", id); + return -1; + } + if (stat >= WMT_IC_PIN_STATE_MAX) { + WMT_ERR_FUNC("invalid ic pin state (%d)\n", stat); + return -2; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + WMT_DBG_FUNC("call WMT_OPID_GPIO_CTRL (ic pin id:%d, stat:%d, flag:0x%x)\n", id, stat, + flag); + + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_GPIO_CTRL; + pOp->op.au4OpData[0] = id; + pOp->op.au4OpData[1] = stat; + pOp->op.au4OpData[2] = flag; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + + /*wake up chip first */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (bRet == MTK_WCN_BOOL_FALSE) + WMT_WARN_FUNC("PIN_ID(%d) PIN_STATE(%d) flag(%d) fail\n", id, stat, flag); + else + WMT_DBG_FUNC("OPID(%d) type(%zu) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + + return 0; +} + +INT32 wmt_lib_reg_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + UINT32 value; + P_OSAL_SIGNAL pSignal; + + if (!pvalue) { + WMT_WARN_FUNC("!pvalue\n"); + return -1; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return -1; + } + + pSignal = &pOp->signal; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + value = *pvalue; + WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x)\n\n", + isWrite, offset, *pvalue, mask); + pOp->op.opId = WMT_OPID_REG_RW; + pOp->op.au4OpData[0] = isWrite; + pOp->op.au4OpData[1] = offset; + pOp->op.au4OpData[2] = (size_t) &value; + pOp->op.au4OpData[3] = mask; + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + + if (bRet != MTK_WCN_BOOL_FALSE) { + WMT_DBG_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n", + isWrite, offset, value, mask); + if (!isWrite) + *pvalue = value; + + return 0; + } + WMT_WARN_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n", + isWrite, offset, value, mask, bRet); + + return -1; +} + +INT32 wmt_lib_efuse_rw(UINT32 isWrite, UINT32 offset, PUINT32 pvalue, UINT32 mask) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + UINT32 value; + P_OSAL_SIGNAL pSignal; + + if (!pvalue) { + WMT_WARN_FUNC("!pvalue\n"); + return -1; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return -1; + } + + pSignal = &pOp->signal; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + value = *pvalue; + WMT_DBG_FUNC("OPID_EFUSE_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x)\n\n", + isWrite, offset, *pvalue, mask); + pOp->op.opId = WMT_OPID_EFUSE_RW; + pOp->op.au4OpData[0] = isWrite; + pOp->op.au4OpData[1] = offset; + pOp->op.au4OpData[2] = (size_t) &value; + pOp->op.au4OpData[3] = mask; + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + + if (bRet != MTK_WCN_BOOL_FALSE) { + WMT_DBG_FUNC("OPID_EFUSE_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) ok\n", + isWrite, offset, value, mask); + if (!isWrite) + *pvalue = value; + return 0; + } + WMT_WARN_FUNC("OPID_REG_RW isWrite(%u) offset(0x%x) value(0x%x) mask(0x%x) bRet(%d)\n", + isWrite, offset, value, mask, bRet); + return -1; +} + +INT32 wmt_lib_utc_time_sync(VOID) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return -1; + } + + pSignal = &pOp->signal; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + pOp->op.opId = WMT_OPID_UTC_TIME_SYNC; + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -2; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("WMT_OPID_UTC_TIME_SYNC fail(%d)\n", bRet); + return -3; + } + WMT_DBG_FUNC("wmt_lib_utc_time_sync OPID(%d) ok\n", pOp->op.opId); + + return 0; +} + +INT32 wmt_lib_try_pwr_off(VOID) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return -1; + } + + pSignal = &pOp->signal; + pSignal->timeoutValue = MAX_FUNC_OFF_TIME; + pOp->op.opId = WMT_OPID_TRY_PWR_OFF; + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -2; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("WMT_OPID_TRY_PWR_OFF fail(%d)\n", bRet); + return -2; + } + WMT_DBG_FUNC("wmt_lib_try_pwr_off OPID(%d) ok\n", pOp->op.opId); + + return 0; +} + +P_WMT_PATCH_INFO wmt_lib_get_patch_info(VOID) +{ + return gDevWmt.pWmtPatchInfo; +} + +/*! + * \brief update combo chip AUDIO Interface (AIF) settings + * + * A library function to support updating chip AUDIO pin settings. A group of + * pins is updated as a whole. + * + * \param aif desired audio interface state to use + * \param flag whether audio pin is shared or not + * + * \retval 0 operation success + * \retval -1 invalid aif + * \retval < 0 error for invalid parameters or operation fail + */ +INT32 wmt_lib_set_aif(CMB_STUB_AIF_X aif, MTK_WCN_BOOL share) +{ + if (aif >= CMB_STUB_AIF_MAX) { + WMT_ERR_FUNC("invalid aif (%d)\n", aif); + return -1; + } + WMT_DBG_FUNC("call pin_ctrl for aif:%d, share:%d\n", aif, + (share == MTK_WCN_BOOL_TRUE) ? 1 : 0); + /* Translate enum CMB_STUB_AIF_X into WMT_IC_PIN_STATE by array */ + return wmt_lib_pin_ctrl(WMT_IC_PIN_AUDIO, + cmb_aif2pin_stat[aif], + (MTK_WCN_BOOL_TRUE == + share) ? WMT_LIB_AIF_FLAG_SHARE : WMT_LIB_AIF_FLAG_SEPARATE); +} + +INT32 wmt_lib_host_awake_get(VOID) +{ + return wmt_plat_wake_lock_ctrl(WL_OP_GET); +} + +INT32 wmt_lib_host_awake_put(VOID) +{ + return wmt_plat_wake_lock_ctrl(WL_OP_PUT); +} + +MTK_WCN_BOOL wmt_lib_btm_cb(MTKSTP_BTM_WMT_OP_T op) +{ + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + + if (op == BTM_RST_OP) { + /* high priority, not to enqueue into the queue of wmtd */ + WMT_INFO_FUNC("Invoke whole chip reset from stp_btm!!!\n"); + wmt_lib_cmb_rst(WMTRSTSRC_RESET_STP); + bRet = MTK_WCN_BOOL_TRUE; + } else if (op == BTM_DMP_OP) { + + WMT_WARN_FUNC("TBD!!!\n"); + } else if (op == BTM_GET_AEE_SUPPORT_FLAG) { + bRet = wmt_core_get_aee_dump_flag(); + } else if (op == BTM_TRIGGER_STP_ASSERT_OP) { + bRet = wmt_core_trigger_stp_assert(); + } + return bRet; +} + +MTK_WCN_BOOL wmt_lib_rstmsg_snd(ENUM_WMTRSTMSG_TYPE_T msg) +{ + + INT32 i = 0; + P_DEV_WMT pDevWmt = &gDevWmt; + UINT8 *drv_name[] = { + "DRV_TYPE_BT", + "DRV_TYPE_FM", + "DRV_TYPE_GPS", + "DRV_TYPE_WIFI", + "DRV_TYPE_ANT", + "UNKNOWN" + }; + + for (i = 0; i <= WMTDRV_TYPE_ANT; i++) { + /* <1> check if reset callback is registered */ + if (pDevWmt->rFdrvCb.fDrvRst[i]) { + /* <2> send the msg to this subfucntion */ + /*src, dst, msg_type, msg_data, msg_size */ + pDevWmt->rFdrvCb.fDrvRst[i] (WMTDRV_TYPE_WMT, i, WMTMSG_TYPE_RESET, &msg, + sizeof(ENUM_WMTRSTMSG_TYPE_T)); + WMT_INFO_FUNC("type = %s, msg sent\n", drv_name[i]); + } else { + WMT_DBG_FUNC("type = %s, unregistered\n", drv_name[i]); + } + } + + return MTK_WCN_BOOL_TRUE; +} + +VOID wmt_lib_state_init(VOID) +{ + /* UINT32 i = 0; */ + P_DEV_WMT pDevWmt = &gDevWmt; + P_OSAL_OP pOp; + + /* Initialize op queue */ + /* RB_INIT(&pDevWmt->rFreeOpQ, WMT_OP_BUF_SIZE); */ + /* RB_INIT(&pDevWmt->rActiveOpQ, WMT_OP_BUF_SIZE); */ + + while (!RB_EMPTY(&pDevWmt->rActiveOpQ)) { + pOp = wmt_lib_get_op(&pDevWmt->rActiveOpQ); + if (pOp) { + if (atomic_dec_and_test(&pOp->ref_count)) + wmt_lib_put_op(&pDevWmt->rFreeOpQ, pOp); + else if (osal_op_is_wait_for_signal(pOp)) + osal_op_raise_signal(pOp, -1); + } + } +} + + +INT32 wmt_lib_sdio_ctrl(UINT32 on) +{ + + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + WMT_DBG_FUNC("call WMT_OPID_SDIO_CTRL\n"); + + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_SDIO_CTRL; + pOp->op.au4OpData[0] = on; + pSignal->timeoutValue = MAX_GPIO_CTRL_TIME; + + + bRet = wmt_lib_put_act_op(pOp); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("WMT_OPID_SDIO_CTRL failed\n"); + return -1; + } + WMT_DBG_FUNC("OPID(WMT_OPID_SDIO_CTRL)ok\n"); + return 0; +} + +MTK_WCN_BOOL wmt_lib_hw_state_show(VOID) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + WMT_DBG_FUNC("call WMT_OPID_HW_STATE_SHOW\n"); + + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_GPIO_STATE; + pSignal->timeoutValue = MAX_GPIO_CTRL_TIME; + + bRet = wmt_lib_put_act_op(pOp); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("WMT_OPID_HW_STATE_SHOW failed\n"); + return MTK_WCN_BOOL_FALSE; + } + WMT_DBG_FUNC("OPID(WMT_OPID_HW_STATE_SHOW)ok\n"); + + return MTK_WCN_BOOL_TRUE; +} + + +MTK_WCN_BOOL wmt_lib_hw_rst(VOID) +{ + + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + P_DEV_WMT pDevWmt = &gDevWmt; + + wmt_lib_state_init(); + + osal_clear_bit(WMT_STAT_STP_REG, &pDevWmt->state); + osal_clear_bit(WMT_STAT_STP_OPEN, &pDevWmt->state); + osal_clear_bit(WMT_STAT_STP_EN, &pDevWmt->state); + osal_clear_bit(WMT_STAT_STP_RDY, &pDevWmt->state); + osal_clear_bit(WMT_STAT_RX, &pDevWmt->state); + osal_clear_bit(WMT_STAT_CMD, &pDevWmt->state); + + /*Before do hardware reset, we show GPIO state to check if others modified our pin state accidentially */ + wmt_lib_hw_state_show(); + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + WMT_DBG_FUNC("call WMT_OPID_HW_RST\n"); + + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_HW_RST; + pSignal->timeoutValue = MAX_GPIO_CTRL_TIME; + + + bRet = wmt_lib_put_act_op(pOp); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("WMT_OPID_HW_RST failed\n"); + return MTK_WCN_BOOL_FALSE; + } + WMT_DBG_FUNC("OPID(WMT_OPID_HW_RST)ok\n"); + + return MTK_WCN_BOOL_TRUE; +} + +MTK_WCN_BOOL wmt_lib_sw_rst(INT32 baudRst) +{ + + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + /* <1> wmt state reset */ + wmt_lib_state_init(); + + /* <2> Reset STP data structure */ + WMT_DBG_FUNC("Cleanup STP context\n"); + mtk_wcn_stp_flush_context(); + stp_dbg_reset(); + + /* <3> Reset STP-PSM data structure */ + WMT_DBG_FUNC("Cleanup STP-PSM context\n"); + mtk_wcn_stp_psm_reset(); + + /* <4> do sw reset in wmt-core */ + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + WMT_DBG_FUNC("call WMT_OPID_SW_RST\n"); + + pSignal = &pOp->signal; + pSignal->timeoutValue = MAX_FUNC_ON_TIME; + + pOp->op.opId = WMT_OPID_SW_RST; + pOp->op.au4OpData[0] = baudRst; + + + + bRet = wmt_lib_put_act_op(pOp); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("WMT_OPID_SW_RST failed\n"); + return MTK_WCN_BOOL_FALSE; + } + WMT_DBG_FUNC("OPID(WMT_OPID_SW_RST)ok\n"); + + return MTK_WCN_BOOL_TRUE; +} + + +ENUM_WMTRSTRET_TYPE_T wmt_lib_cmb_rst(ENUM_WMTRSTSRC_TYPE_T src) +{ +#define RETRYTIMES 10 + MTK_WCN_BOOL bRet; + ENUM_WMTRSTRET_TYPE_T retval = WMTRSTRET_MAX; + ENUM_WMTRSTMSG_TYPE_T rstMsg = WMTRSTMSG_RESET_MAX; + INT32 retries = RETRYTIMES; + P_DEV_WMT pDevWmt = &gDevWmt; + P_OSAL_OP pOp; + UINT8 *srcName[] = { "WMTRSTSRC_RESET_BT", + "WMTRSTSRC_RESET_FM", + "WMTRSTSRC_RESET_GPS", + "WMTRSTSRC_RESET_WIFI", + "WMTRSTSRC_RESET_STP", + "WMTRSTSRC_RESET_TEST" + }; + INT32 coredump_mode = mtk_wcn_stp_coredump_flag_get(); + + WMT_INFO_FUNC("coredump mode == %d. Connsys coredump is %s.", + coredump_mode, coredump_mode ? "enabled" : "disabled"); + + if (src < WMTRSTSRC_RESET_MAX) + WMT_INFO_FUNC("reset source = %s\n", srcName[src]); + + if (src == WMTRSTSRC_RESET_TEST) { + pOp = wmt_lib_get_current_op(pDevWmt); + if (pOp && ((pOp->op.opId == WMT_OPID_FUNC_ON) + || (pOp->op.opId == WMT_OPID_FUNC_OFF))) { + WMT_INFO_FUNC("can't do reset by test src when func on/off\n"); + return -1; + } + } + /* <1> Consider the multi-context combo_rst case. */ + if (osal_test_and_set_bit(WMT_STAT_RST_ON, &pDevWmt->state)) { + retval = WMTRSTRET_ONGOING; + goto rstDone; + } + /* <2> Block all STP request */ + if (wmt_lib_psm_lock_trylock() == 0) { + if (chip_reset_only == 1) { + wmt_lib_fw_patch_update_rst_ctrl(1); + fw_patch_rst_time = 0; + retval = WMTRSTRET_RETRY; + goto rstDone; + } + mtk_wcn_stp_enable(0); + } else { + mtk_wcn_stp_enable(0); + wmt_lib_psm_lock_release(); + } + + /* <3> RESET_START notification */ + bRet = wmt_lib_rstmsg_snd(WMTRSTMSG_RESET_START); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_rstmsg_snd!\n"); + retval = WMTRSTRET_FAIL; + goto rstDone; + } + /* wakeup blocked opid */ + pOp = wmt_lib_get_current_op(pDevWmt); + if (osal_op_is_wait_for_signal(pOp)) + osal_op_raise_signal(pOp, -1); + /* wakeup blocked cmd */ + wmt_dev_rx_event_cb(); + + /* <4> retry until reset flow successful */ + while (retries > 0) { + /* <4.1> reset combo hw */ + bRet = wmt_lib_hw_rst(); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_hw_rst!\n"); + retries--; + continue; + } + /* <4.2> reset driver/combo sw */ + bRet = wmt_lib_sw_rst(1); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_sw_rst!\n"); + retries--; + continue; + } + break; + } + osal_clear_bit(WMT_STAT_RST_ON, &pDevWmt->state); + if (bRet == MTK_WCN_BOOL_FALSE) { + rstMsg = WMTRSTMSG_RESET_END_FAIL; + WMT_INFO_FUNC("[whole chip reset] fail! retries = %d\n", RETRYTIMES - retries); + } else { + rstMsg = WMTRSTMSG_RESET_END; + WMT_INFO_FUNC("[whole chip reset] ok! retries = %d\n", RETRYTIMES - retries); + } + + + /* <5> RESET_END notification */ + bRet = wmt_lib_rstmsg_snd(rstMsg); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_ERR_FUNC("[whole chip reset] fail at wmt_lib_rstmsg_snd!\n"); + retval = WMTRSTRET_FAIL; + } else { + retval = rstMsg == WMTRSTMSG_RESET_END ? WMTRSTRET_SUCCESS : WMTRSTRET_FAIL; + } + mtk_wcn_stp_assert_flow_ctrl(0); + mtk_wcn_stp_coredump_start_ctrl(0); + mtk_wcn_stp_set_wmt_trg_assert(0); + mtk_wcn_stp_emi_dump_flag_ctrl(0); +rstDone: + osal_clear_bit(WMT_STAT_RST_ON, &pDevWmt->state); + chip_reset_only = 0; + return retval; +} + + +MTK_WCN_BOOL wmt_lib_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb) +{ + + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_DEV_WMT pWmtDev = &gDevWmt; + + if (eType >= 0 && eType <= WMTDRV_TYPE_ANT) { + WMT_DBG_FUNC("reg ok!\n"); + pWmtDev->rFdrvCb.fDrvRst[eType] = pCb; + bRet = MTK_WCN_BOOL_TRUE; + } else { + WMT_WARN_FUNC("reg fail!\n"); + } + + return bRet; +} + +MTK_WCN_BOOL wmt_lib_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType) +{ + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_DEV_WMT pWmtDev = &gDevWmt; + + if (eType >= 0 && eType <= WMTDRV_TYPE_WIFI) { + WMT_DBG_FUNC("unreg ok!\n"); + pWmtDev->rFdrvCb.fDrvRst[eType] = NULL; + bRet = MTK_WCN_BOOL_TRUE; + } else { + WMT_WARN_FUNC("unreg fail!\n"); + } + + return bRet; +} + + +UINT32 wmt_lib_dbg_level_set(UINT32 level) +{ + gWmtDbgLvl = level > WMT_LOG_LOUD ? WMT_LOG_LOUD : level; + return 0; +} +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +INT32 wmt_lib_deep_sleep_ctrl(INT32 value) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + WMT_INFO_FUNC("g_deep_sleep_flag value (%d) set form wmt_dbg.\n", value); + ret = wmt_core_deep_sleep_ctrl(value); + if (sdio_deep_sleep_flag_set) { + if (value) + (*sdio_deep_sleep_flag_set)(MTK_WCN_BOOL_TRUE); + else + (*sdio_deep_sleep_flag_set)(MTK_WCN_BOOL_FALSE); + } else { + WMT_ERR_FUNC("sdio_deep_sleep_flag_set is not register"); + return -1; + } + return 0; +} + +MTK_WCN_BOOL wmt_lib_deep_sleep_flag_set(MTK_WCN_BOOL flag) +{ + if (sdio_deep_sleep_flag_set) { + (*sdio_deep_sleep_flag_set)(flag); + } else { + WMT_ERR_FUNC("sdio_deep_sleep_flag_set is not register"); + return MTK_WCN_BOOL_FALSE; + } + return MTK_WCN_BOOL_TRUE; +} +#endif +INT32 wmt_lib_set_stp_wmt_last_close(UINT32 value) +{ + return mtk_wcn_stp_set_wmt_last_close(value); +} + +INT32 wmt_lib_notify_stp_sleep(VOID) +{ + INT32 iRet = 0x0; + + iRet = wmt_lib_psm_lock_aquire(); + if (iRet) { + WMT_ERR_FUNC("--->lock psm_lock failed, iRet=%d\n", iRet); + return iRet; + } + + iRet = mtk_wcn_stp_notify_sleep_for_thermal(); + wmt_lib_psm_lock_release(); + + return iRet; +} + +VOID wmt_lib_set_patch_num(UINT32 num) +{ + P_DEV_WMT pWmtDev = &gDevWmt; + + pWmtDev->patchNum = num; +} + +VOID wmt_lib_set_patch_info(P_WMT_PATCH_INFO pPatchinfo) +{ + P_DEV_WMT pWmtDev = &gDevWmt; + + pWmtDev->pWmtPatchInfo = pPatchinfo; +} + +VOID wmt_lib_set_rom_patch_info(struct wmt_rom_patch_info *PatchInfo, ENUM_WMTDRV_TYPE_T type) +{ + P_DEV_WMT pWmtDev = &gDevWmt; + + /* Allow info of a type to be set only once, to avoid inproper usage */ + if (pWmtDev->pWmtRomPatchInfo[type]) + return; + + pWmtDev->pWmtRomPatchInfo[type] = kcalloc(1, sizeof(struct wmt_rom_patch_info), + GFP_ATOMIC); + + if (pWmtDev->pWmtRomPatchInfo[type]) + osal_memcpy(pWmtDev->pWmtRomPatchInfo[type], PatchInfo, + sizeof(struct wmt_rom_patch_info)); +} + +INT32 wmt_lib_set_current_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp) +{ + if (pWmtDev) { + pWmtDev->pCurOP = pOp; + WMT_DBG_FUNC("pOp=0x%p\n", pOp); + return 0; + } + WMT_ERR_FUNC("Invalid pointer\n"); + return -1; +} + +P_OSAL_OP wmt_lib_get_current_op(P_DEV_WMT pWmtDev) +{ + if (pWmtDev) + return pWmtDev->pCurOP; + WMT_ERR_FUNC("Invalid pointer\n"); + return NULL; +} + +INT32 wmt_lib_set_worker_op(P_DEV_WMT pWmtDev, P_OSAL_OP pOp) +{ + if (pWmtDev) { + pWmtDev->pWorkerOP = pOp; + WMT_DBG_FUNC("pOp=0x%p\n", pOp); + return 0; + } + WMT_ERR_FUNC("Invalid pointer\n"); + return -1; +} + +P_OSAL_OP wmt_lib_get_worker_op(P_DEV_WMT pWmtDev) +{ + if (pWmtDev) + return pWmtDev->pWorkerOP; + WMT_ERR_FUNC("Invalid pointer\n"); + return NULL; +} + +UINT8 *wmt_lib_get_fwinfor_from_emi(UINT8 section, UINT32 offset, UINT8 *buf, UINT32 len) +{ + UINT8 *pAddr = NULL; + UINT32 sublen1 = 0; + UINT32 sublen2 = 0; + P_CONSYS_EMI_ADDR_INFO p_consys_info; + + p_consys_info = wmt_plat_get_emi_phy_add(); + osal_assert(p_consys_info); + + if (section == 0) { + pAddr = wmt_plat_get_emi_virt_add(0x0); + if (len > 1024) + len = 1024; + if (!pAddr) { + WMT_ERR_FUNC("wmt-lib: get EMI virtual base address fail\n"); + } else { + WMT_INFO_FUNC("vir addr(0x%p)\n", pAddr); + osal_memcpy_fromio(&buf[0], pAddr, len); + } + } else { + if (p_consys_info == NULL) { + WMT_ERR_FUNC("wmt-lib: get EMI physical address fail!\n"); + return 0; + } + + if (offset >= 0x7fff) + offset = 0x0; + + if (offset + len > 32768) { + pAddr = wmt_plat_get_emi_virt_add(offset + p_consys_info->paged_trace_off); + if (!pAddr) { + WMT_ERR_FUNC("wmt-lib: get part1 EMI virtual base address fail\n"); + } else { + WMT_INFO_FUNC("part1 vir addr(0x%p)\n", pAddr); + sublen1 = 0x7fff - offset; + osal_memcpy_fromio(&buf[0], pAddr, sublen1); + } + pAddr = wmt_plat_get_emi_virt_add(p_consys_info->paged_trace_off); + if (!pAddr) { + WMT_ERR_FUNC("wmt-lib: get part2 EMI virtual base address fail\n"); + } else { + WMT_INFO_FUNC("part2 vir addr(0x%p)\n", pAddr); + sublen2 = len - sublen1; + osal_memcpy_fromio(&buf[sublen1], pAddr, sublen2); + } + } else { + pAddr = wmt_plat_get_emi_virt_add(offset + p_consys_info->paged_trace_off); + if (!pAddr) { + WMT_ERR_FUNC("wmt-lib: get EMI virtual base address fail\n"); + } else { + WMT_INFO_FUNC("vir addr(0x%p)\n", pAddr); + osal_memcpy_fromio(&buf[0], pAddr, len); + } + } + } + + return 0; +} +EXPORT_SYMBOL(wmt_lib_get_fwinfor_from_emi); + +INT32 wmt_lib_merge_if_flag_ctrl(UINT32 enable) +{ +#if WMT_PLAT_ALPS + return wmt_plat_merge_if_flag_ctrl(enable); +#endif +} + + +INT32 wmt_lib_merge_if_flag_get(UINT32 enable) +{ +#if WMT_PLAT_ALPS + return wmt_plat_merge_if_flag_get(); +#endif +} + + +PUINT8 wmt_lib_get_cpupcr_xml_format(PUINT32 pLen) +{ + PUINT8 temp; + + osal_memset(&g_cpupcr_buf[0], 0, WMT_STP_CPUPCR_BUF_SIZE); + temp = g_cpupcr_buf; + *pLen += stp_dbg_cpupcr_infor_format(temp, WMT_STP_CPUPCR_BUF_SIZE); + *pLen += mtk_stp_dbg_dmp_append(temp + *pLen, WMT_STP_CPUPCR_BUF_SIZE - *pLen); + + WMT_INFO_FUNC("print xml buffer,len(%d):\n\n", *pLen); + + WMT_INFO_FUNC("%s", g_cpupcr_buf); + + return &g_cpupcr_buf[0]; +} + +PUINT8 wmt_lib_get_cpupcr_reg_info(PUINT32 pLen, PUINT32 consys_reg) +{ + osal_memset(&g_cpupcr_buf[0], 0, WMT_STP_CPUPCR_BUF_SIZE); + if (consys_reg != NULL) + *pLen += stp_dbg_dump_cpupcr_reg_info(g_cpupcr_buf, consys_reg[1]); + else + *pLen += osal_sprintf(g_cpupcr_buf + *pLen, "0\n"); + WMT_INFO_FUNC("print buffer,len(%d):\n\n", *pLen); + WMT_INFO_FUNC("%s", g_cpupcr_buf); + return &g_cpupcr_buf[0]; +} + +INT32 wmt_lib_tm_temp_query(VOID) +{ + return wmt_dev_tm_temp_query(); +} + +INT32 wmt_lib_register_thermal_ctrl_cb(thermal_query_ctrl_cb thermal_ctrl) +{ + wmt_plat_thermal_ctrl_cb_reg(thermal_ctrl); + return 0; +} + +INT32 wmt_lib_register_trigger_assert_cb(trigger_assert_cb trigger_assert) +{ + wmt_plat_trigger_assert_cb_reg(trigger_assert); + return 0; +} + +UINT32 wmt_lib_set_host_assert_info(UINT32 type, UINT32 reason, UINT32 en) +{ + return stp_dbg_set_host_assert_info(type, reason, en); +} + +INT8 wmt_lib_co_clock_get(void) +{ + if (gDevWmt.rWmtGenConf.cfgExist) + return gDevWmt.rWmtGenConf.co_clock_flag; + else + return -1; +} + + +UINT32 wmt_lib_get_drv_status(UINT32 type) +{ + return wmt_core_get_drv_status((ENUM_WMTDRV_TYPE_T) type); +} + +INT32 wmt_lib_trigger_reset(VOID) +{ + return wmt_btm_trigger_reset(); +} + +INT32 wmt_lib_trigger_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason) +{ + return wmt_lib_trigger_assert_keyword(type, reason, NULL); +} + +INT32 wmt_lib_trigger_assert_keyword(ENUM_WMTDRV_TYPE_T type, UINT32 reason, PUINT8 keyword) +{ + INT32 iRet = -1; + WMT_CTRL_DATA ctrlData; + + if (wmt_lib_assert_lock_trylock() == 0) { + WMT_INFO_FUNC("Can't lock assert mutex which might be held by another trigger assert procedure.\n"); + return iRet; + } + + wmt_core_set_coredump_state(DRV_STS_FUNC_ON); + + ctrlData.ctrlId = (SIZE_T) WMT_CTRL_TRG_ASSERT; + ctrlData.au4CtrlData[0] = (SIZE_T) type; + ctrlData.au4CtrlData[1] = (SIZE_T) reason; + ctrlData.au4CtrlData[2] = (SIZE_T) keyword; + + iRet = wmt_ctrl(&ctrlData); + if (iRet) { + /* ERROR */ + WMT_ERR_FUNC + ("WMT-CORE: wmt_core_ctrl failed: type(%d), reason(%d), keyword(%s), iRet(%d)\n", + type, reason, keyword, iRet); + osal_assert(0); + } + wmt_lib_assert_lock_release(); + + return iRet; +} + +#if CFG_WMT_PS_SUPPORT +UINT32 wmt_lib_quick_sleep_ctrl(UINT32 en) +{ + WMT_WARN_FUNC("%s quick sleep mode\n", en ? "enable" : "disable"); + g_quick_sleep_ctrl = en; + return 0; +} +#endif + +UINT32 wmt_lib_fw_patch_update_rst_ctrl(UINT32 en) +{ + WMT_WARN_FUNC("%s fw patch update reset\n", en ? "enable" : "disable"); + g_fw_patch_update_rst = en; + return 0; +} + +#if CONSYS_ENALBE_SET_JTAG +UINT32 wmt_lib_jtag_flag_set(UINT32 en) +{ + return wmt_plat_jtag_flag_ctrl(en); +} +#endif + +UINT32 wmt_lib_soc_set_wifiver(UINT32 wifiver) +{ + return stp_dbg_set_wifiver(wifiver); +} + +UINT32 wmt_lib_co_clock_flag_get(VOID) +{ + return wmt_plat_soc_co_clock_flag_get(); +} + +INT32 wmt_lib_wifi_fem_cfg_report(PVOID pvInfoBuf) +{ + INT32 iRet = 0; + ULONG addr = 0; + WMT_GEN_CONF *pWmtGenConf; + + /* sanity check */ + ASSERT(pvInfoBuf); + + iRet = wmt_core_ctrl(WMT_CTRL_GET_WMT_CONF, &addr, 0); + + if (iRet) { + WMT_ERR_FUNC("ctrl GET_WMT_CONF fail(%d)\n", iRet); + return -2; + } + + pWmtGenConf = (P_WMT_GEN_CONF) addr; + + WMT_DBG_FUNC("pWmtGenConf->coex_wmt_wifi_path=0x%x\n", pWmtGenConf->coex_wmt_wifi_path); + + /* Memory copy */ + osal_memcpy((PUINT8)(pvInfoBuf), &pWmtGenConf->coex_wmt_wifi_path, + osal_sizeof(pWmtGenConf->coex_wmt_wifi_path)); + return iRet; +} + +INT32 wmt_lib_sdio_reg_rw(INT32 func_num, INT32 direction, UINT32 offset, UINT32 value) +{ + INT32 ret = -1; + ENUM_WMT_CHIP_TYPE chip_type; + + chip_type = wmt_detect_get_chip_type(); + + if (chip_type == WMT_CHIP_TYPE_COMBO) { + if (sdio_reg_rw) + ret = sdio_reg_rw(func_num, direction, offset, value); + else + WMT_ERR_FUNC("sdio_reg_rw callback is not set, maybe the sdio funcxx write/read not used\n"); + } else + WMT_ERR_FUNC("It`s soc project, this function is not used\n"); + return ret; +} + +VOID wmt_lib_dump_wmtd_backtrace(VOID) +{ + osal_thread_show_stack(&gDevWmt.thread); +} + +INT32 wmt_lib_met_cmd(UINT32 value) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return -1; + } + + pSignal = &pOp->signal; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + WMT_DBG_FUNC("met ctrl value(0x%x)\n", value); + pOp->op.opId = WMT_OPID_MET_CTRL; + pOp->op.au4OpData[0] = value; + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + + if (bRet != MTK_WCN_BOOL_FALSE) + return 0; + + return -1; +} + +UINT32 wmt_lib_get_gps_lna_pin_num(VOID) +{ + return mtk_consys_get_gps_lna_pin_num(); +} + +INT32 wmt_lib_met_ctrl(INT32 met_ctrl, INT32 log_ctrl) +{ + P_DEV_WMT p_devwmt; + P_OSAL_THREAD p_thread; + INT32 ret; + P_CONSYS_EMI_ADDR_INFO emi_info; + + emi_info = mtk_wcn_consys_soc_get_emi_phy_add(); + if (emi_info == NULL) { + WMT_ERR_FUNC("get EMI info failed\n"); + return -1; + } + + if (!emi_info->emi_met_size) { + WMT_ERR_FUNC("met debug function is not support\n"); + return -1; + } + + ret = wmt_lib_met_cmd(met_ctrl); + if (ret) { + WMT_ERR_FUNC("send MET ctrl command fail(%d)\n", ret); + return -1; + } + + p_devwmt = &gDevWmt; + p_thread = &gDevWmt.met_thread; + if (met_ctrl & 0x1) { + /*met enable*/ + /* Create mtk_wmt_met thread */ + osal_strncpy(p_thread->threadName, "mtk_wmt_met", sizeof(p_thread->threadName)); + p_devwmt->met_log_ctrl = log_ctrl; + p_thread->pThreadData = (PVOID) p_devwmt; + p_thread->pThreadFunc = (PVOID) met_thread; + ret = osal_thread_create(p_thread); + if (ret) { + WMT_ERR_FUNC("osal_thread_create(0x%p) fail(%d)\n", p_thread, ret); + return -1; + } + /* start running mtk_wmt_met */ + ret = osal_thread_run(p_thread); + if (ret) { + WMT_ERR_FUNC("osal_thread_run(0x%p) fail(%d)\n", p_thread, ret); + return -1; + } + } else { + /*met disable*/ + /* stop running mtk_wmt_met */ + ret = osal_thread_stop(p_thread); + if (ret) { + WMT_ERR_FUNC("osal_thread_stop(0x%p) fail(%d)\n", p_thread, ret); + return -1; + } + } + + return 0; +} + +VOID wmt_lib_set_ext_ldo(UINT32 flag) +{ + gDevWmt.ext_ldo_flag = flag; +} + +UINT32 wmt_lib_get_ext_ldo(VOID) +{ + return gDevWmt.ext_ldo_flag; +} + +static VOID wmt_lib_utc_sync_timeout_handler(ULONG data) +{ + schedule_work(&gDevWmt.utcSyncWorker); +} + +static VOID wmt_lib_utc_sync_worker_handler(struct work_struct *work) +{ + wmt_lib_utc_time_sync(); +} + +INT32 wmt_lib_fw_log_ctrl(enum wmt_fw_log_type type, UINT8 onoff, UINT8 level) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return -1; + } + + pSignal = &pOp->signal; + pSignal->timeoutValue = 0; + pOp->op.opId = WMT_OPID_FW_LOG_CTRL; + pOp->op.au4OpData[0] = type; + pOp->op.au4OpData[1] = onoff; + pOp->op.au4OpData[2] = level; + + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -2; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("OPID(%d) fail\n", pOp->op.opId); + return -3; + } + WMT_DBG_FUNC("OPID(%d) ok\n", pOp->op.opId); + + return 0; +} + +INT32 wmt_lib_gps_mcu_ctrl(PUINT8 p_tx_data_buf, UINT32 tx_data_len, PUINT8 p_rx_data_buf, + UINT32 rx_data_buf_len, PUINT32 p_rx_data_len) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return -1; + } + + pSignal = &pOp->signal; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + pOp->op.opId = WMT_OPID_GPS_MCU_CTRL; + pOp->op.au4OpData[0] = (SIZE_T)p_tx_data_buf; + pOp->op.au4OpData[1] = tx_data_len; + pOp->op.au4OpData[2] = (SIZE_T)p_rx_data_buf; + pOp->op.au4OpData[3] = rx_data_buf_len; + pOp->op.au4OpData[4] = (SIZE_T)p_rx_data_len; + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("WMT_OPID_GPS_MCU_CTRL fail(%zu)\n", pOp->op.au4OpData[5]); + return -1; + } + + return 0; +} + +VOID wmt_lib_print_wmtd_op_history(VOID) +{ + osal_op_history_print(&gDevWmt.wmtd_op_history, "wmtd_thread"); +} + +VOID wmt_lib_print_worker_op_history(VOID) +{ + osal_op_history_print(&gDevWmt.worker_op_history, "wmtd_worker_thread"); +} +VOID wmt_lib_set_blank_status(UINT32 on_off_flag) +{ + wmt_core_set_blank_status(on_off_flag); +} + +UINT32 wmt_lib_get_blank_status(VOID) +{ + return wmt_core_get_blank_status(); +} + +INT32 wmt_lib_blank_status_ctrl(UINT32 on_off_flag) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return -1; + } + + pSignal = &pOp->signal; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + WMT_DBG_FUNC("WMT_OPID_BLANK_STATUS_CTRL on_off_flag(0x%x)\n\n", on_off_flag); + pOp->op.opId = WMT_OPID_BLANK_STATUS_CTRL; + pOp->op.au4OpData[0] = on_off_flag; + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + + if (bRet != MTK_WCN_BOOL_FALSE) { + WMT_DBG_FUNC("WMT_OPID_BLANK_STATUS_CTRL on_off_flag(0x%x) ok\n", on_off_flag); + return 0; + } + WMT_WARN_FUNC("WMT_OPID_BLANK_STATUS_CTRL on_off_flag(0x%x) bRet(%d)\n", on_off_flag, bRet); + return -1; +} + +/** + * Desinged for native service to get number of patches + * resides in /vendor/firmware + */ +INT32 wmt_lib_get_vendor_patch_num(VOID) +{ + return gDevWmt.patch_table.num; +} + +INT32 wmt_lib_set_vendor_patch_version(struct wmt_vendor_patch *p) +{ + struct vendor_patch_table *table = &(gDevWmt.patch_table); + struct wmt_vendor_patch *patch = table->patch; + + if (patch == NULL) { + INT32 init_capacity = 5; + + patch = (struct wmt_vendor_patch *)osal_malloc( + sizeof(struct wmt_vendor_patch) * init_capacity); + if (patch == NULL) { + WMT_ERR_FUNC("[oom]set vendor patch version"); + return -1; + } + + table->patch = patch; + table->capacity = init_capacity; + table->num = 0; + + table->active_version = (PUINT8 *)osal_malloc(sizeof(PUINT8) * init_capacity); + if (table->active_version == NULL) { + osal_free(table->patch); + table->patch = NULL; + WMT_ERR_FUNC("[oom]alloc active patch"); + return -1; + } + osal_memset(table->active_version, 0, sizeof(PUINT8) * init_capacity); + } + + if (table->capacity == table->num) { + WMT_ERR_FUNC("reach to limit"); + return -1; + } + + /* copy patch info to table */ + patch = patch + table->num; + patch->type = p->type; + osal_strncpy(patch->file_name, p->file_name, sizeof(p->file_name)); + osal_strncpy(patch->version, p->version, sizeof(p->version)); + + table->num++; + WMT_INFO_FUNC("set version %s %s %d", + patch->file_name, patch->version, patch->type); + return 0; +} + +INT32 wmt_lib_get_vendor_patch_version(struct wmt_vendor_patch *p) +{ + struct vendor_patch_table *table = &(gDevWmt.patch_table); + + if (p->id >= table->num || p->id < 0) { + WMT_ERR_FUNC("id %d out of range", p->id); + return -1; + } + + osal_memcpy(p, &table->patch[p->id], sizeof(struct wmt_vendor_patch)); + WMT_INFO_FUNC("get version: %s %s t:%d", + p->file_name, p->version, p->type); + return 0; +} + +INT32 wmt_lib_set_check_patch_status(INT32 status) +{ + gDevWmt.patch_table.status = status; + return 0; +} + +INT32 wmt_lib_get_check_patch_status(VOID) +{ + return gDevWmt.patch_table.status; +} + +INT32 wmt_lib_set_active_patch_version(struct wmt_vendor_patch *p) +{ + struct vendor_patch_table *table = &(gDevWmt.patch_table); + + if (p->id < 0 || p->id >= table->num) { + WMT_ERR_FUNC("patch id: %d is invalid. num = %d", p->id, table->num); + return -1; + } + + if (table->active_version == NULL) { + WMT_ERR_FUNC("active version is NULL"); + return -1; + } + + if (table->active_version[p->id] == NULL) { + table->active_version[p->id] = osal_malloc(sizeof(UINT8) * (WMT_FIRMWARE_VERSION_LENGTH + 1)); + if (table->active_version[p->id] == NULL) { + WMT_ERR_FUNC("oom when alloc active_version"); + return -1; + } + } else if (osal_strcmp(p->version, table->active_version[p->id]) == 0) + return 0; + + wmt_lib_set_need_update_patch_version(1); + osal_strncpy(table->active_version[p->id], p->version, WMT_FIRMWARE_VERSION_LENGTH + 1); + return 0; +} + +INT32 wmt_lib_get_active_patch_version(struct wmt_vendor_patch *p) +{ + struct vendor_patch_table *table = &(gDevWmt.patch_table); + INT32 id = p->id; + + if (id >= table->num || id < 0) { + WMT_ERR_FUNC("id %d out of range", p->id); + return -1; + } + if (table->active_version[id] == NULL) { + WMT_ERR_FUNC("active_version is null: id = %d", id); + return -1; + } + + osal_memcpy(p, &table->patch[id], sizeof(struct wmt_vendor_patch)); + osal_strncpy(p->version, table->active_version[id], + WMT_FIRMWARE_VERSION_LENGTH + 1); + WMT_INFO_FUNC("get active version: %s %s t:%d id:%d", + p->file_name, p->version, p->type, id); + return 0; +} + +INT32 wmt_lib_get_need_update_patch_version(VOID) +{ + return gDevWmt.patch_table.need_update; +} + + +INT32 wmt_lib_set_need_update_patch_version(INT32 need) +{ + gDevWmt.patch_table.need_update = need > 0 ? 1 : 0; + return 0; +} + +VOID mtk_lib_set_mcif_mpu_protection(MTK_WCN_BOOL enable) +{ + mtk_consys_set_mcif_mpu_protection(enable); +} + +VOID wmt_lib_set_wlan_mpu_protection(MTK_WCN_BOOL enable) +{ + if (enable == false) { + wmt_lib_mpu_lock_aquire(); + if (mtk_wcn_wlan_emi_mpu_set_protection) + (*mtk_wcn_wlan_emi_mpu_set_protection)(false); + } else { + if (mtk_wcn_wlan_emi_mpu_set_protection) + (*mtk_wcn_wlan_emi_mpu_set_protection)(true); + wmt_lib_mpu_lock_release(); + } +} + +static VOID wmt_lib_assert_work_cb(struct work_struct *work) +{ + struct assert_work_st *a = &wmt_assert_work; + + wmt_lib_trigger_assert_keyword(a->type, a->reason, a->keyword); +} + +VOID wmt_lib_trigger_assert_keyword_delay(ENUM_WMTDRV_TYPE_T type, UINT32 reason, PUINT8 keyword) +{ + struct assert_work_st *a = &wmt_assert_work; + + a->type = type; + a->reason = reason; + snprintf(a->keyword, sizeof(a->keyword), "%s", keyword); + WMT_ERR_FUNC("Assert: type = %d, reason = %d, keyword = %s", type, reason, keyword); + schedule_work(&(a->work)); +} + +INT32 wmt_lib_resume_dump_info(VOID) +{ + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal; + + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_WHEN_AP_RESUME); + + if (mtk_consys_check_reg_readable() == 0) + return MTK_WCN_BOOL_TRUE; + + pOp = wmt_lib_get_free_op(); + + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_RESUME_DUMP_INFO; + pSignal->timeoutValue = 0; + + bRet = wmt_lib_put_act_op(pOp); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("WMT_OPID_RESUME_DUMP_INFO failed\n"); + return MTK_WCN_BOOL_FALSE; + } + + return MTK_WCN_BOOL_TRUE; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/include/mtk_wcn_cmb_hw.h b/drivers/misc/mediatek/connectivity/common/common_main/include/mtk_wcn_cmb_hw.h new file mode 100644 index 00000000000000..adbd4399a872e2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/include/mtk_wcn_cmb_hw.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + +#ifndef _MTK_WCN_CMB_HW_H_ +#define _MTK_WCN_CMB_HW_H_ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include <osal_typedef.h> + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef struct _PWR_SEQ_TIME_ { + UINT32 rtcStableTime; + UINT32 ldoStableTime; + UINT32 rstStableTime; + UINT32 offStableTime; + UINT32 onStableTime; +} PWR_SEQ_TIME, *P_PWR_SEQ_TIME; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +extern INT32 mtk_wcn_cmb_hw_pwr_off(VOID); +extern INT32 mtk_wcn_cmb_hw_pwr_on(VOID); +extern INT32 mtk_wcn_cmb_hw_rst(VOID); +extern INT32 mtk_wcn_cmb_hw_init(P_PWR_SEQ_TIME pPwrSeqTime); +extern INT32 mtk_wcn_cmb_hw_deinit(VOID); +extern INT32 mtk_wcn_cmb_hw_state_show(VOID); + + +#endif /* _MTK_WCN_CMB_HW_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/include/stp_exp.h b/drivers/misc/mediatek/connectivity/common/common_main/include/stp_exp.h new file mode 100644 index 00000000000000..3bdd87edfe6016 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/include/stp_exp.h @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _STP_EXP_H_ +#define _STP_EXP_H_ + +#include <osal.h> +#include <osal_typedef.h> +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + +#if (WMT_IDC_SUPPORT) +#define CFG_WMT_LTE_COEX_HANDLING 1 +#define CFG_WMT_LTE_ENABLE_MSGID_MAPPING 0 +#else +#define CFG_WMT_LTE_COEX_HANDLING 0 +#endif + +#define BT_TASK_INDX (0) +#define FM_TASK_INDX (1) +#define GPS_TASK_INDX (2) +#define WIFI_TASK_INDX (3) +#define WMT_TASK_INDX (4) +#define STP_TASK_INDX (5) +#define INFO_TASK_INDX (6) +#define ANT_TASK_INDX (7) +#if CFG_WMT_LTE_COEX_HANDLING +#define COEX_TASK_INDX (8) +#define MTKSTP_MAX_TASK_NUM (9) +#else +#define MTKSTP_MAX_TASK_NUM (8) +#endif + +#define MTKSTP_BUFFER_SIZE (16384) /* Size of RX Queue */ + +#define STP_EXP_HID_API_EXPORT 0 + +#else + +#define STP_EXP_HID_API_EXPORT 1 + +#endif + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + +typedef VOID (*MTK_WCN_STP_EVENT_CB) (VOID); +typedef INT32 (*MTK_WCN_STP_IF_TX) (const PUINT8 data, const UINT32 size, PUINT32 written_size); +/* export for HIF driver */ +typedef VOID(*MTK_WCN_STP_IF_RX)(const PUINT8 data, INT32 size); +typedef INT32 (*MTK_WCN_STP_RX_HAS_PENDING_DATA) (VOID); +typedef INT32 (*MTK_WCN_STP_TX_HAS_PENDING_DATA) (VOID); +typedef P_OSAL_THREAD (*MTK_WCN_STP_RX_THREAD_GET) (VOID); + +typedef enum { + STP_UART_IF_TX = 0, + STP_SDIO_IF_TX = 1, + STP_BTIF_IF_TX = 2, + STP_MAX_IF_TX +} ENUM_STP_TX_IF_TYPE; +#endif +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_receive_data +* DESCRIPTION +* receive data from serial protocol engine +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* INT32 >= 0: size of data received; < 0: error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_send_data +* DESCRIPTION +* subfunction send data through STP +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* type [IN] subfunction type +* RETURNS +* INT32 >= 0: length transmitted; < 0: error +*****************************************************************************/ +extern INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_rxqueue_empty +* DESCRIPTION +* Is certain rx queue empty? +* PARAMETERS +* type [IN] subfunction type +* RETURNS +* INT32 0: queue is NOT empyt; !0: queue is empty +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_rxqueue_empty(UINT8 type); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_is_enable +* DESCRIPTION +* Is STP ready? +* PARAMETERS +* none. +* RETURNS +* MTK_WCN_BOOL TRUE:ready, FALSE:not ready +*****************************************************************************/ +extern MTK_WCN_BOOL mtk_wcn_stp_is_ready(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_parser_data +* DESCRIPTION +* push data to serial transport protocol parser engine +* PARAMETERS +* buffer [IN] data buffer +* length [IN] data buffer length +* RETURNS +* void +*****************************************************************************/ +extern INT32 mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length); + +/***************************************************************************** +* FUNCTION +* set_bluetooth_rx_interface +* DESCRIPTION +* Set bluetooth rx interface +* PARAMETERS +* rx interface type +* RETURNS +* void +*****************************************************************************/ +extern void mtk_wcn_stp_set_bluez(MTK_WCN_BOOL sdio_flag); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_tx_event_cb +* DESCRIPTION +* regiter Tx event callback function +* PARAMETERS +* func +* RETURNS +* INT32: 0:successful , -1: fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_event_cb +* DESCRIPTION +* regiter Rx event callback function +* PARAMETERS +* func +* RETURNS +* INT32: 0:successful , -1: fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_if_tx +* DESCRIPTION +* regiter Tx event callback function +* PARAMETERS +* stp_if: SDIO or UART, fnnc: Call back function +* RETURNS +* INT32: 0:successful , -1: fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_if_rx +* DESCRIPTION +* regiter Rx event callback function +* PARAMETERS +* stp_if: SDIO or UART, fnnc: Call back function +* RETURNS +* int: 0:successful , -1: fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_coredump_start_get +* DESCRIPTION +* get f/w assert flag in STP context +* PARAMETERS +* VOID +* RETURNS +* INT32 0= f/w assert flag is not set, others=f/w assert flag is set +*****************************************************************************/ +extern INT32 mtk_wcn_stp_coredump_start_get(VOID); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_rx_has_pending_data +* DESCRIPTION +* regiter rx has pending data call back function +* PARAMETERS +* stp_if: SDIO or UART, fnnc: Call back function +* RETURNS +* int: 0:successful , -1: fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_register_rx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_HAS_PENDING_DATA func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_tx_has_pending_data +* DESCRIPTION +* regiter tx has pending data call back function +* PARAMETERS +* stp_if: SDIO or UART, fnnc: Call back function +* RETURNS +* int: 0:successful , -1: fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_register_tx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_TX_HAS_PENDING_DATA func); + +/***************************************************************************** +* FUNCTION +* mtk_wcn_stp_register_rx_thread_get +* DESCRIPTION +* regiter rx thread call back function +* PARAMETERS +* stp_if: SDIO or UART, fnnc: Call back function +* RETURNS +* int: 0:successful , -1: fail +*****************************************************************************/ +extern INT32 mtk_wcn_stp_register_rx_thread_get(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_THREAD_GET func); + +extern INT32 mtk_stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd); +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +extern INT32 mtk_wcn_stp_uart_drv_init(VOID); +extern VOID mtk_wcn_stp_uart_drv_exit(VOID); + +#else +#define CFG_WMT_LTE_COEX_HANDLING 0 + +#define BT_TASK_INDX (0) +#define FM_TASK_INDX (1) +#define GPS_TASK_INDX (2) +#define WIFI_TASK_INDX (3) +#define WMT_TASK_INDX (4) +#define STP_TASK_INDX (5) +#define INFO_TASK_INDX (6) +#define ANT_TASK_INDX (7) +#if CFG_WMT_LTE_COEX_HANDLING +#define COEX_TASK_INDX (8) +#define MTKSTP_MAX_TASK_NUM (9) +#else +#define MTKSTP_MAX_TASK_NUM (8) +#endif + +typedef enum _SDIO_PS_OP{ + OWN_SET = 0, + OWN_CLR = 1, + OWN_STATE = 2, +} SDIO_PS_OP; + +typedef enum _ENUM_WMTMSG_TYPE_T { + WMTMSG_TYPE_POWER_ON = 0, + WMTMSG_TYPE_POWER_OFF = 1, + WMTMSG_TYPE_RESET = 2, + WMTMSG_TYPE_STP_RDY= 3, + WMTMSG_TYPE_HW_FUNC_ON= 4, + WMTMSG_TYPE_MAX +} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T; + +typedef enum { + STP_UART_IF_TX = 0, + STP_SDIO_IF_TX = 1, + STP_BTIF_IF_TX = 2, + STP_MAX_IF_TX +} ENUM_STP_TX_IF_TYPE; + +typedef enum _ENUM_WMTDRV_TYPE_T { + WMTDRV_TYPE_BT = 0, + WMTDRV_TYPE_FM = 1, + WMTDRV_TYPE_GPS = 2, + WMTDRV_TYPE_WIFI = 3, + WMTDRV_TYPE_WMT = 4, + WMTDRV_TYPE_ANT = 5, + WMTDRV_TYPE_STP = 6, + WMTDRV_TYPE_SDIO1 = 7, + WMTDRV_TYPE_SDIO2 = 8, + WMTDRV_TYPE_LPBK = 9, + WMTDRV_TYPE_COREDUMP = 10, +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK + WMTDRV_TYPE_AUTOK = 11, +#endif + WMTDRV_TYPE_MAX +} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; + +typedef enum _ENUM_WMTCHIN_TYPE_T { + WMTCHIN_CHIPID = 0x0, + WMTCHIN_HWVER = WMTCHIN_CHIPID + 1, + WMTCHIN_MAPPINGHWVER = WMTCHIN_HWVER + 1, + WMTCHIN_FWVER = WMTCHIN_MAPPINGHWVER + 1, + WMTCHIN_IPVER = WMTCHIN_FWVER + 1, + WMTCHIN_MAX, + +} ENUM_WMT_CHIPINFO_TYPE_T, *P_ENUM_WMT_CHIPINFO_TYPE_T; + +typedef enum _ENUM_WMTTHERM_TYPE_T{ + WMTTHERM_ZERO = 0, + WMTTHERM_ENABLE = WMTTHERM_ZERO + 1, + WMTTHERM_READ = WMTTHERM_ENABLE + 1, + WMTTHERM_DISABLE = WMTTHERM_READ + 1, + WMTTHERM_MAX +}ENUM_WMTTHERM_TYPE_T, *P_ENUM_WMTTHERM_TYPE_T; + +typedef enum _ENUM_WMT_FLASH_PATCH_SEQ_T { + WMT_FLASH_PATCH_HEAD_PKT = 0, + WMT_FLASH_PATCH_START_PKT = WMT_FLASH_PATCH_HEAD_PKT + 1, + WMT_FLASH_PATCH_CONTINUE_PKT = WMT_FLASH_PATCH_START_PKT + 1, + WMT_FLASH_PATCH_END_PKT = WMT_FLASH_PATCH_CONTINUE_PKT + 1, + WMT_FLASH_PATCH_SEQ_MAX, +} ENUM_WMT_FLASH_PATCH_SEQ, *P_ENUM_WMT_FLASH_PATCH_SEQ; + +typedef enum _ENUM_WMTHWVER_TYPE_T { + WMTHWVER_E1 = 0x0, + WMTHWVER_E2 = 0x1, + WMTHWVER_E3 = 0x2, + WMTHWVER_E4 = 0x3, + WMTHWVER_E5 = 0x4, + WMTHWVER_E6 = 0x5, + WMTHWVER_E7 = 0x6, + WMTHWVER_MAX, + WMTHWVER_INVALID = 0xff +} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T; + +typedef void (*MTK_WCN_STP_EVENT_CB)(void); +typedef INT32 (*PF_WMT_SDIO_PSOP)(SDIO_PS_OP); +typedef void (*PF_WMT_CB)(ENUM_WMTDRV_TYPE_T, ENUM_WMTDRV_TYPE_T, ENUM_WMTMSG_TYPE_T, VOID *, UINT32); +typedef INT32 (*MTK_WCN_STP_IF_TX) (const PUINT8 data, const UINT32 size, PUINT32 written_size); +typedef INT32 (*MTK_WCN_STP_RX_HAS_PENDING_DATA) (VOID); +typedef INT32 (*MTK_WCN_STP_TX_HAS_PENDING_DATA) (VOID); + +extern INT32 mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type); +extern INT32 _mtk_wcn_stp_receive_data(PUINT8 buffer, UINT32 length, UINT8 type); +extern INT32 _mtk_wcn_stp_send_data_raw(const PUINT8 buffer, const UINT32 length, const UINT8 type); +extern INT32 mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type); +extern INT32 _mtk_wcn_stp_send_data(const PUINT8 buffer, const UINT32 length, const UINT8 type); +extern MTK_WCN_BOOL _mtk_wcn_stp_is_rxqueue_empty(UINT8 type); +extern MTK_WCN_BOOL mtk_wcn_stp_is_ready(VOID); +extern MTK_WCN_BOOL _mtk_wcn_stp_is_ready(VOID); +extern INT32 mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length); +extern INT32 _mtk_wcn_stp_parser_data(PUINT8 buffer, UINT32 length); +extern VOID _mtk_wcn_stp_set_bluez(MTK_WCN_BOOL sdio_flag); +//extern INT32 _mtk_wcn_stp_register_tx_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); +extern INT32 mtk_wcn_stp_register_event_cb(INT32 type, MTK_WCN_STP_EVENT_CB func); +//extern INT32 _mtk_wcn_stp_register_if_tx(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_IF_TX func); +//extern INT32 _mtk_wcn_stp_register_if_rx(MTK_WCN_STP_IF_RX func); +extern INT32 _mtk_wcn_stp_coredump_start_get(VOID); +//extern INT32 _mtk_wcn_stp_register_rx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, +// MTK_WCN_STP_RX_HAS_PENDING_DATA func); +//extern INT32 _mtk_wcn_stp_register_tx_has_pending_data(ENUM_STP_TX_IF_TYPE stp_if, +// MTK_WCN_STP_TX_HAS_PENDING_DATA func); +//extern INT32 _mtk_wcn_stp_register_rx_thread_get(ENUM_STP_TX_IF_TYPE stp_if, MTK_WCN_STP_RX_THREAD_GET func); +extern VOID mtk_wcn_wmt_func_ctrl_for_plat(UINT32 on, ENUM_WMTDRV_TYPE_T type); +extern VOID mtk_wcn_wmt_exp_init(VOID); + +#endif /* MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT */ + +#endif /* _STP_EXP_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/include/wmt.h b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt.h new file mode 100644 index 00000000000000..c65f504b48b84a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _MTKWMT_H_ +#define _MTKWMT_H_ +#include "wmt_core.h" + +#endif /*_MTKWMT_H_*/ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_build_in_adapter.h b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_build_in_adapter.h new file mode 100644 index 00000000000000..cea885aaf7d6cd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_build_in_adapter.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef WMT_BUILD_IN_ADAPTER_H +#define WMT_BUILD_IN_ADAPTER_H + +#include <mtk_wcn_cmb_stub.h> + + +/******************************************************************************* + * Bridging from platform -> wmt_drv.ko + ******************************************************************************/ +typedef int (*wmt_bridge_thermal_query_cb)(void); +typedef void (*wmt_bridge_connsys_clock_fail_dump_cb)(void); + +struct wmt_platform_bridge { + wmt_bridge_thermal_query_cb thermal_query_cb; + wmt_bridge_connsys_clock_fail_dump_cb clock_fail_dump_cb; +}; + +void wmt_export_platform_bridge_register(struct wmt_platform_bridge *cb); +void wmt_export_platform_bridge_unregister(void); + + +/******************************************************************************* + * SDIO integration with platform MMC driver + ******************************************************************************/ +extern unsigned int wifi_irq; +extern pm_callback_t mtk_wcn_cmb_sdio_pm_cb; +extern void *mtk_wcn_cmb_sdio_pm_data; + +void wmt_export_mtk_wcn_cmb_sdio_disable_eirq(void); +int wmt_export_mtk_wcn_sdio_irq_flag_set(int flag); + +#endif /* WMT_BUILD_IN_ADAPTER_H */ + + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_exp.h b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_exp.h new file mode 100644 index 00000000000000..cefc10e7706827 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_exp.h @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _WMT_EXP_H_ +#define _WMT_EXP_H_ + +#include <mtk_wcn_cmb_stub.h> +#include "wmt_plat.h" +/* not to reference to internal wmt */ +/* #include "wmt_core.h" */ +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#if 1 /* moved from wmt_lib.h */ +#ifndef DFT_TAG +#define DFT_TAG "[WMT-DFT]" +#endif + +#define WMT_LOUD_FUNC(fmt, arg...) \ +do { \ + if (gWmtDbgLvl >= WMT_LOG_LOUD) \ + osal_warn_print(DFT_TAG "[L]%s:" fmt, __func__, ##arg); \ +} while (0) +#define WMT_INFO_FUNC(fmt, arg...) \ +do { \ + if (gWmtDbgLvl >= WMT_LOG_INFO) \ + osal_warn_print(DFT_TAG "[I]%s:" fmt, __func__, ##arg); \ +} while (0) +#define WMT_WARN_FUNC(fmt, arg...) \ +do { \ + if (gWmtDbgLvl >= WMT_LOG_WARN) \ + osal_warn_print(DFT_TAG "[W]%s:" fmt, __func__, ##arg); \ +} while (0) +#define WMT_ERR_FUNC(fmt, arg...) \ +do { \ + if (gWmtDbgLvl >= WMT_LOG_ERR) \ + osal_err_print(DFT_TAG "[E]%s(%d):" fmt, __func__, __LINE__, ##arg); \ +} while (0) +#define WMT_DBG_FUNC(fmt, arg...) \ +do { \ + if (gWmtDbgLvl >= WMT_LOG_DBG) \ + osal_warn_print(DFT_TAG "[D]%s:" fmt, __func__, ##arg); \ +} while (0) +#define WMT_TRC_FUNC(f) \ +do { \ + if (gWmtDbgLvl >= WMT_LOG_DBG) \ + osal_warn_print(DFT_TAG "<%s> <%d>\n", __func__, __LINE__); \ +} while (0) + +#endif + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#if 1 /* moved from wmt_lib.h */ +extern INT32 gWmtDbgLvl; +#endif +extern OSAL_BIT_OP_VAR gBtWifiGpsState; +extern OSAL_BIT_OP_VAR gGpsFmState; +extern UINT32 gWifiProbed; +extern MTK_WCN_BOOL g_pwr_off_flag; +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#if 1 /* moved from wmt_lib.h */ +#define WMT_LOG_LOUD 4 +#define WMT_LOG_DBG 3 +#define WMT_LOG_INFO 2 +#define WMT_LOG_WARN 1 +#define WMT_LOG_ERR 0 +#endif +#define CFG_CORE_INTERNAL_TXRX 0 /*just do TX/RX in host side */ + +#define CFG_WMT_PS_SUPPORT 1 /* moved from wmt_lib.h */ +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + +typedef enum _ENUM_WMTDRV_TYPE_T { + WMTDRV_TYPE_BT = 0, + WMTDRV_TYPE_FM = 1, + WMTDRV_TYPE_GPS = 2, + WMTDRV_TYPE_WIFI = 3, + WMTDRV_TYPE_WMT = 4, + WMTDRV_TYPE_ANT = 5, + WMTDRV_TYPE_STP = 6, + WMTDRV_TYPE_SDIO1 = 7, + WMTDRV_TYPE_SDIO2 = 8, + WMTDRV_TYPE_LPBK = 9, + WMTDRV_TYPE_COREDUMP = 10, + WMTDRV_TYPE_MAX +} ENUM_WMTDRV_TYPE_T, *P_ENUM_WMTDRV_TYPE_T; + +/* TODO: [ChangeFeature][GeorgeKuo] Reconsider usage of this type */ +/* TODO: how do we extend for new chip and newer revision? */ +/* TODO: This way is hard to extend */ +typedef enum _ENUM_WMTHWVER_TYPE_T { + WMTHWVER_E1 = 0x0, + WMTHWVER_E2 = 0x1, + WMTHWVER_E3 = 0x2, + WMTHWVER_E4 = 0x3, + WMTHWVER_E5 = 0x4, + WMTHWVER_E6 = 0x5, + WMTHWVER_E7 = 0x6, + WMTHWVER_MAX, + WMTHWVER_INVALID = 0xff +} ENUM_WMTHWVER_TYPE_T, *P_ENUM_WMTHWVER_TYPE_T; + +typedef enum _ENUM_WMTDSNS_TYPE_T { + WMTDSNS_FM_DISABLE = 0, + WMTDSNS_FM_ENABLE = 1, + WMTDSNS_FM_GPS_DISABLE = 2, + WMTDSNS_FM_GPS_ENABLE = 3, + WMTDSNS_MAX +} ENUM_WMTDSNS_TYPE_T, *P_ENUM_WMTDSNS_TYPE_T; + +typedef enum _ENUM_WMTTHERM_TYPE_T { + WMTTHERM_ZERO = 0, + WMTTHERM_ENABLE = WMTTHERM_ZERO + 1, + WMTTHERM_READ = WMTTHERM_ENABLE + 1, + WMTTHERM_DISABLE = WMTTHERM_READ + 1, + WMTTHERM_MAX +} ENUM_WMTTHERM_TYPE_T, *P_ENUM_WMTTHERM_TYPE_T; + +typedef enum _ENUM_WMTMSG_TYPE_T { + WMTMSG_TYPE_POWER_ON = 0, + WMTMSG_TYPE_POWER_OFF = 1, + WMTMSG_TYPE_RESET = 2, + WMTMSG_TYPE_STP_RDY = 3, + WMTMSG_TYPE_HW_FUNC_ON = 4, + WMTMSG_TYPE_MAX +} ENUM_WMTMSG_TYPE_T, *P_ENUM_WMTMSG_TYPE_T; + +typedef VOID(*PF_WMT_CB) (ENUM_WMTDRV_TYPE_T, /* Source driver type */ + ENUM_WMTDRV_TYPE_T, /* Destination driver type */ + ENUM_WMTMSG_TYPE_T, /* Message type */ + /* READ-ONLY buffer. Buffer is allocated and freed by WMT_drv. + * Client can't touch this buffer after this function return. + */ + PVOID, + UINT32 /* Buffer size in unit of byte */ + ); + +typedef enum _SDIO_PS_OP { + OWN_SET = 0, + OWN_CLR = 1, + OWN_STATE = 2, +} SDIO_PS_OP; + +typedef INT32(*PF_WMT_SDIO_PSOP) (SDIO_PS_OP); +typedef INT32(*PF_WMT_SDIO_DEEP_SLEEP)(MTK_WCN_BOOL); +//typedef INT32(*PF_WMT_SDIO_DEBUG)(INT32, INT32, UINT32, UINT32); + +typedef enum _ENUM_WMTCHIN_TYPE_T { + WMTCHIN_CHIPID = 0x0, + WMTCHIN_HWVER = WMTCHIN_CHIPID + 1, + WMTCHIN_MAPPINGHWVER = WMTCHIN_HWVER + 1, + WMTCHIN_FWVER = WMTCHIN_MAPPINGHWVER + 1, + WMTCHIN_IPVER = WMTCHIN_FWVER + 1, + WMTCHIN_MAX, + +} ENUM_WMT_CHIPINFO_TYPE_T, *P_ENUM_WMT_CHIPINFO_TYPE_T; + +typedef enum _ENUM_WMT_FLASH_PATCH_CTRL_T { + WMT_FLASH_PATCH_VERSION_GET = 0, + WMT_FLASH_PATCH_DOWNLOAD = WMT_FLASH_PATCH_VERSION_GET + 1, + WMT_FLASH_PATCH_CTRL_MAX, +} ENUM_WMT_FLASH_PATCH_CTRL, *P_ENUM_WMT_FLASH_PATCH_CTRL; + +typedef enum _ENUM_WMT_FLASH_PATCH_SEQ_T { + WMT_FLASH_PATCH_HEAD_PKT = 0, + WMT_FLASH_PATCH_START_PKT = WMT_FLASH_PATCH_HEAD_PKT + 1, + WMT_FLASH_PATCH_CONTINUE_PKT = WMT_FLASH_PATCH_START_PKT + 1, + WMT_FLASH_PATCH_END_PKT = WMT_FLASH_PATCH_CONTINUE_PKT + 1, + WMT_FLASH_PATCH_SEQ_MAX, +} ENUM_WMT_FLASH_PATCH_SEQ, *P_ENUM_WMT_FLASH_PATCH_SEQ; + +typedef enum _ENUM_WMT_FLASH_PATCH_TYPE_T { + WMT_FLASH_PATCH_HIF_SW_EFUSE = 0, + WMT_FLASH_PATCH_GATT = WMT_FLASH_PATCH_HIF_SW_EFUSE + 1, + WMT_FLASH_PATCH_SYSROM = WMT_FLASH_PATCH_GATT + 1, + WMT_FLASH_PATCH_ILM = WMT_FLASH_PATCH_SYSROM + 1, + WMT_FLASH_PATCH_FLP1 = WMT_FLASH_PATCH_ILM + 1, + WMT_FLASH_PATCH_FLP2 = WMT_FLASH_PATCH_FLP1 + 1, + WMT_FLASH_PATCH_TYPE_MAX, +} ENUM_WMT_FLASH_PATCH_TYPE, *P_ENUM_WMT_FLASH_PATCH_TYPE; + +typedef enum _ENUM_WMT_FLASH_PATCH_STATUS_T { + WMT_FLASH_PATCH_VERSION_GET_OK = 0, + WMT_FLASH_PATCH_VERSION_GET_FAIL = WMT_FLASH_PATCH_VERSION_GET_OK + 1, + WMT_FLASH_PATCH_DOWNLOAD_OK = WMT_FLASH_PATCH_VERSION_GET_FAIL + 1, + WMT_FLASH_PATCH_DOWNLOAD_FAIL = WMT_FLASH_PATCH_DOWNLOAD_OK + 1, + WMT_FLASH_PATCH_PARA_ERR = WMT_FLASH_PATCH_DOWNLOAD_FAIL + 1, + WMT_FLASH_PATCH_OP_ERR = WMT_FLASH_PATCH_PARA_ERR + 1, + WMT_FLASH_PATCH_MAX +} ENUM_WMT_FLASH_PATCH_STATUS, *P_ENUM_WMT_FLASH_PATCH_STATUS; + +typedef MTK_WCN_BOOL(*MTK_WCN_WMT_FUNC_CTRL) (ENUM_WMTDRV_TYPE_T type); +typedef INT8(*MTK_WCN_WMT_THERM_CTRL) (ENUM_WMTTHERM_TYPE_T eType); +typedef ENUM_WMTHWVER_TYPE_T(*MTK_WCN_WMT_HWVER_GET) (VOID); +typedef MTK_WCN_BOOL(*MTK_WCN_WMT_DSNS_CTRL) (ENUM_WMTDSNS_TYPE_T eType); +typedef INT32(*MTK_WCN_WMT_MSGCB_REG) (ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); +typedef INT32(*MTK_WCN_WMT_MSGCB_UNREG) (ENUM_WMTDRV_TYPE_T eType); +typedef INT32(*MTK_WCN_WMT_SDIO_OP_REG) (PF_WMT_SDIO_PSOP own_cb); +typedef INT32(*MTK_WCN_WMT_SDIO_HOST_AWAKE) (VOID); +typedef MTK_WCN_BOOL(*MTK_WCN_WMT_ASSERT) (ENUM_WMTDRV_TYPE_T type, UINT32 reason); +typedef MTK_WCN_BOOL(*MTK_WCN_WMT_ASSERT_TIMEOUT)(ENUM_WMTDRV_TYPE_T type, + UINT32 reason, INT32 timeout); +typedef UINT32(*MTK_WCN_WMT_IC_INFO_GET) (ENUM_WMT_CHIPINFO_TYPE_T type); +typedef INT32 (*MTK_WCN_WMT_PSM_CTRL)(MTK_WCN_BOOL flag); + +typedef ENUM_WMT_FLASH_PATCH_STATUS(*MTK_WCN_WMT_FLASH_PATCH_CTRL)(ENUM_WMT_FLASH_PATCH_CTRL ctrlId, + PUINT8 pBuf, UINT32 length, ENUM_WMT_FLASH_PATCH_SEQ seq, ENUM_WMT_FLASH_PATCH_TYPE type, + PUINT32 version, UINT32 checksum); + +typedef struct _MTK_WCN_WMT_EXP_CB_INFO_ { + MTK_WCN_WMT_FUNC_CTRL wmt_func_on_cb; + MTK_WCN_WMT_FUNC_CTRL wmt_func_off_cb; + MTK_WCN_WMT_THERM_CTRL wmt_therm_ctrl_cb; + MTK_WCN_WMT_HWVER_GET wmt_hwver_get_cb; + MTK_WCN_WMT_DSNS_CTRL wmt_dsns_ctrl_cb; + MTK_WCN_WMT_MSGCB_REG wmt_msgcb_reg_cb; + MTK_WCN_WMT_MSGCB_UNREG wmt_msgcb_unreg_cb; + MTK_WCN_WMT_SDIO_OP_REG wmt_sdio_op_reg_cb; + MTK_WCN_WMT_SDIO_HOST_AWAKE wmt_sdio_host_awake_cb; + MTK_WCN_WMT_ASSERT wmt_assert_cb; + MTK_WCN_WMT_ASSERT_TIMEOUT wmt_assert_timeout_cb; + MTK_WCN_WMT_IC_INFO_GET wmt_ic_info_get_cb; + MTK_WCN_WMT_PSM_CTRL wmt_psm_ctrl_cb; + MTK_WCN_WMT_FLASH_PATCH_CTRL wmt_flash_patch_ctrl_cb; +} MTK_WCN_WMT_EXP_CB_INFO, *P_MTK_WCN_WMT_EXP_CB_INFO; + +#endif + +typedef INT32(*PF_WMT_SDIO_DEBUG)(INT32, INT32, UINT32, UINT32); + +typedef enum _ENUM_WMTRSTMSG_TYPE_T { + WMTRSTMSG_RESET_START = 0x0, + WMTRSTMSG_RESET_END = 0x1, + WMTRSTMSG_RESET_END_FAIL = 0x2, + WMTRSTMSG_RESET_MAX, + WMTRSTMSG_RESET_INVALID = 0xff +} ENUM_WMTRSTMSG_TYPE_T, *P_ENUM_WMTRSTMSG_TYPE_T; + +typedef enum _ENUM_BT_GPS_ONOFF_STATE_T { + WMT_BT_ON = 0, + WMT_GPS_ON = 1, + WMT_WIFI_ON = 2, + WMT_FM_ON = 3, + WMT_GPS_SUSPEND = 4, + WMT_BT_GPS_STATE_MAX, + WMT_BT_GPS_STATE_INVALID = 0xff +} ENUM_BT_GPS_ONOFF_STATE_T, *P_ENUM_BT_GPS_ONOFF_STATE_T; + +#if 1 /* moved from wmt_core.h */ +/*typedef enum { + WMT_SDIO_SLOT_INVALID = 0, + WMT_SDIO_SLOT_SDIO1 = 1, /\* Wi-Fi dedicated SDIO1 *\/ + WMT_SDIO_SLOT_SDIO2 = 2, + WMT_SDIO_SLOT_MAX +} WMT_SDIO_SLOT_NUM;*/ + +typedef enum { + WMT_SDIO_FUNC_STP = 0, + WMT_SDIO_FUNC_WIFI = 1, + WMT_SDIO_FUNC_MAX +} WMT_SDIO_FUNC_TYPE; +#endif + +typedef INT32(*wmt_wlan_probe_cb) (VOID); +typedef INT32(*wmt_wlan_remove_cb) (VOID); +typedef INT32(*wmt_wlan_bus_cnt_get_cb) (VOID); +typedef INT32(*wmt_wlan_bus_cnt_clr_cb) (VOID); +typedef INT32(*wmt_wlan_emi_mpu_set_protection_cb) (bool); +typedef INT32(*wmt_wlan_is_wifi_drv_own_cb) (VOID); + +typedef struct _MTK_WCN_WMT_WLAN_CB_INFO { + wmt_wlan_probe_cb wlan_probe_cb; + wmt_wlan_remove_cb wlan_remove_cb; + wmt_wlan_bus_cnt_get_cb wlan_bus_cnt_get_cb; + wmt_wlan_bus_cnt_clr_cb wlan_bus_cnt_clr_cb; + wmt_wlan_emi_mpu_set_protection_cb wlan_emi_mpu_set_protection_cb; + wmt_wlan_is_wifi_drv_own_cb wlan_is_wifi_drv_own_cb; +} MTK_WCN_WMT_WLAN_CB_INFO, *P_MTK_WCN_WMT_WLAN_CB_INFO; + +#ifdef CONFIG_MTK_COMBO_ANT +typedef enum _ENUM_WMT_ANT_RAM_CTRL_T { + WMT_ANT_RAM_GET_STATUS = 0, + WMT_ANT_RAM_DOWNLOAD = WMT_ANT_RAM_GET_STATUS + 1, + WMT_ANT_RAM_CTRL_MAX +} ENUM_WMT_ANT_RAM_CTRL, *P_ENUM_WMT_ANT_RAM_CTRL; + +typedef enum _ENUM_WMT_ANT_RAM_SEQ_T { + WMT_ANT_RAM_START_PKT = 1, + WMT_ANT_RAM_CONTINUE_PKT = WMT_ANT_RAM_START_PKT + 1, + WMT_ANT_RAM_END_PKT = WMT_ANT_RAM_CONTINUE_PKT + 1, + WMT_ANT_RAM_SEQ_MAX +} ENUM_WMT_ANT_RAM_SEQ, *P_ENUM_WMT_ANT_RAM_SEQ; + +typedef enum _ENUM_WMT_ANT_RAM_STATUS_T { + WMT_ANT_RAM_NOT_EXIST = 0, + WMT_ANT_RAM_EXIST = WMT_ANT_RAM_NOT_EXIST + 1, + WMT_ANT_RAM_DOWN_OK = WMT_ANT_RAM_EXIST + 1, + WMT_ANT_RAM_DOWN_FAIL = WMT_ANT_RAM_DOWN_OK + 1, + WMT_ANT_RAM_PARA_ERR = WMT_ANT_RAM_DOWN_FAIL + 1, + WMT_ANT_RAM_OP_ERR = WMT_ANT_RAM_PARA_ERR + 1, + WMT_ANT_RAM_MAX +} ENUM_WMT_ANT_RAM_STATUS, *P_ENUM_WMT_ANT_RAM_STATUS; +#endif + +extern INT32 mtk_wcn_wmt_wlan_reg(P_MTK_WCN_WMT_WLAN_CB_INFO pWmtWlanCbInfo); +extern INT32 mtk_wcn_wmt_wlan_unreg(VOID); +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +extern wmt_wlan_probe_cb mtk_wcn_wlan_probe; +extern wmt_wlan_remove_cb mtk_wcn_wlan_remove; +extern wmt_wlan_bus_cnt_get_cb mtk_wcn_wlan_bus_tx_cnt; +extern wmt_wlan_bus_cnt_clr_cb mtk_wcn_wlan_bus_tx_cnt_clr; +extern wmt_wlan_emi_mpu_set_protection_cb mtk_wcn_wlan_emi_mpu_set_protection; +extern wmt_wlan_is_wifi_drv_own_cb mtk_wcn_wlan_is_wifi_drv_own; +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +/*subsystem function ctrl APIs*/ +//extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); + +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + +extern MTK_WCN_BOOL mtk_wcn_wmt_func_off(ENUM_WMTDRV_TYPE_T type); + +extern MTK_WCN_BOOL mtk_wcn_wmt_func_on(ENUM_WMTDRV_TYPE_T type); + +extern MTK_WCN_BOOL mtk_wcn_wmt_dsns_ctrl(ENUM_WMTDSNS_TYPE_T eType); + +extern MTK_WCN_BOOL mtk_wcn_wmt_assert(ENUM_WMTDRV_TYPE_T type, UINT32 reason); + +extern MTK_WCN_BOOL mtk_wcn_wmt_assert_timeout(ENUM_WMTDRV_TYPE_T type, UINT32 reason, INT32 timeout); + +extern MTK_WCN_BOOL mtk_wcn_wmt_assert_keyword(ENUM_WMTDRV_TYPE_T type, PUINT8 keyword); + +extern MTK_WCN_BOOL mtk_wcn_wmt_do_reset(ENUM_WMTDRV_TYPE_T type); + +extern VOID mtk_wcn_wmt_set_wifi_ver(UINT32 Value); + +extern INT32 mtk_wcn_wmt_msgcb_reg(ENUM_WMTDRV_TYPE_T eType, PF_WMT_CB pCb); + +extern INT32 mtk_wcn_wmt_msgcb_unreg(ENUM_WMTDRV_TYPE_T eType); + +extern INT32 mtk_wcn_stp_wmt_sdio_op_reg(PF_WMT_SDIO_PSOP own_cb); + +extern INT32 mtk_wcn_stp_wmt_sdio_host_awake(VOID); +/* +*return value: +*enable/disable thermal sensor function: true(1)/false(0) +*read thermal sensor function: thermal value +*/ +extern INT8 mtk_wcn_wmt_therm_ctrl(ENUM_WMTTHERM_TYPE_T eType); + +extern ENUM_WMTHWVER_TYPE_T mtk_wcn_wmt_hwver_get(VOID); + +extern UINT32 mtk_wcn_wmt_ic_info_get(ENUM_WMT_CHIPINFO_TYPE_T type); + + +extern INT32 mtk_wcn_wmt_chipid_query(VOID); + +extern INT32 mtk_wcn_wmt_psm_ctrl(MTK_WCN_BOOL flag); +extern ENUM_WMT_FLASH_PATCH_STATUS mtk_wcn_wmt_flash_patch_ctrl(ENUM_WMT_FLASH_PATCH_CTRL ctrlId, + PUINT8 pBuf, UINT32 length, ENUM_WMT_FLASH_PATCH_SEQ seq, ENUM_WMT_FLASH_PATCH_TYPE type, + PUINT32 version, UINT32 checksum); + +#endif +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +extern INT32 mtk_wcn_wmt_sdio_deep_sleep_flag_cb_reg(PF_WMT_SDIO_DEEP_SLEEP flag_cb); +#endif +extern INT32 mtk_wcn_wmt_sdio_rw_cb_reg(PF_WMT_SDIO_DEBUG reg_rw_cb); + +#ifdef CONFIG_MTK_COMBO_ANT +extern ENUM_WMT_ANT_RAM_STATUS mtk_wcn_wmt_ant_ram_ctrl(ENUM_WMT_ANT_RAM_CTRL ctrlId, PUINT8 pBuf, + UINT32 length, ENUM_WMT_ANT_RAM_SEQ seq); +#endif +extern INT32 wmt_lib_set_aif(CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); /* set AUDIO interface options */ +extern VOID wmt_lib_ps_irq_cb(VOID); + +extern VOID mtk_wcn_wmt_func_ctrl_for_plat(UINT32 on, ENUM_WMTDRV_TYPE_T type); + +extern INT32 mtk_wcn_wmt_system_state_reset(VOID); +extern MTK_WCN_BOOL mtk_wcn_set_connsys_power_off_flag(MTK_WCN_BOOL value); +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +extern VOID mtk_wcn_wmt_exp_init(VOID); +extern VOID mtk_wcn_wmt_exp_deinit(VOID); +#endif +extern INT8 mtk_wcn_wmt_co_clock_flag_get(VOID); +extern INT32 mtk_wcn_wmt_wifi_fem_cfg_report(PVOID pvInfoBuf); +extern VOID mtk_wcn_wmt_dump_wmtd_backtrace(VOID); +extern UINT32 mtk_wmt_get_gps_lna_pin_num(VOID); +extern VOID mtk_wmt_set_ext_ldo(UINT32 flag); +extern INT32 mtk_wmt_gps_mcu_ctrl(PUINT8 p_tx_data_buf, UINT32 tx_data_len, PUINT8 p_rx_data_buf, + UINT32 rx_data_buf_len, PUINT32 p_rx_data_len); +extern VOID mtk_wcn_wmt_set_mcif_mpu_protection(MTK_WCN_BOOL enable); +extern MTK_WCN_BOOL mtk_wmt_gps_suspend_ctrl(MTK_WCN_BOOL suspend); + +extern INT32 mtk_wcn_wmt_mpu_lock_aquire(VOID); +extern VOID mtk_wcn_wmt_mpu_lock_release(VOID); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WMT_EXP_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_plat.h b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_plat.h new file mode 100644 index 00000000000000..dd95673ffd8bca --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_plat.h @@ -0,0 +1,381 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _WMT_PLAT_H_ +#define _WMT_PLAT_H_ +#include "stp_exp.h" +#include <mtk_wcn_cmb_stub.h> +#include "mtk_wcn_cmb_hw.h" + +/* #include "mtk_wcn_consys_hw.h" */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#if 1 /* moved from wmt_exp.h */ +#ifndef DFT_TAG +#define DFT_TAG "[WMT-DFT]" +#endif + +#define WMT_PLAT_LOG_LOUD 4 +#define WMT_PLAT_LOG_DBG 3 +#define WMT_PLAT_LOG_INFO 2 +#define WMT_PLAT_LOG_WARN 1 +#define WMT_PLAT_LOG_ERR 0 + +extern INT32 wmtPlatLogLvl; + +#define WMT_PLAT_PR_LOUD(fmt, arg...) \ +do { \ + if (wmtPlatLogLvl >= WMT_PLAT_LOG_LOUD) \ + pr_info(DFT_TAG "[L]%s:" fmt, __func__, ##arg); \ +} while (0) +#define WMT_PLAT_PR_INFO(fmt, arg...) \ +do { \ + if (wmtPlatLogLvl >= WMT_PLAT_LOG_INFO) \ + pr_info(DFT_TAG "[I]%s:" fmt, __func__, ##arg); \ +} while (0) +#define WMT_PLAT_PR_WARN(fmt, arg...) \ +do { \ + if (wmtPlatLogLvl >= WMT_PLAT_LOG_WARN) \ + pr_warn(DFT_TAG "[W]%s:" fmt, __func__, ##arg); \ +} while (0) +#define WMT_PLAT_PR_ERR(fmt, arg...) \ +do { \ + if (wmtPlatLogLvl >= WMT_PLAT_LOG_ERR) \ + pr_err(DFT_TAG "[E]%s(%d):" fmt, __func__, __LINE__, ##arg); \ +} while (0) +#define WMT_PLAT_PR_DBG(fmt, arg...) \ +do { \ + if (wmtPlatLogLvl >= WMT_PLAT_LOG_DBG) \ + pr_info(DFT_TAG "[D]%s:" fmt, __func__, ##arg); \ +} while (0) + +#endif + +#define CFG_WMT_PS_SUPPORT 1 /* moved from wmt_exp.h */ + +#define CFG_WMT_DUMP_INT_STATUS 0 +#define CONSYS_ENALBE_SET_JTAG 1 + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#if (defined(MT6630) || defined(MT6632)) +#define CONSYS_WMT_REG_SUSPEND_CB_ENABLE 1 +#else +#define CONSYS_WMT_REG_SUSPEND_CB_ENABLE 0 +#endif + +#if defined(MERGE_INTERFACE_SUPPORT) && (defined(MT6628) || defined(MT6630) || defined(MT6632)) +#define MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT 1 +#else +#define MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT 0 +#endif + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_PIN_ID_ { + PIN_LDO = 0, + PIN_PMU = 1, + PIN_RTC = 2, + PIN_RST = 3, + PIN_BGF_EINT = 4, + PIN_WIFI_EINT = 5, + PIN_ALL_EINT = 6, + PIN_UART_GRP = 7, + PIN_PCM_GRP = 8, + PIN_I2S_GRP = 9, + PIN_SDIO_GRP = 10, + PIN_GPS_SYNC = 11, + PIN_GPS_LNA = 12, + PIN_UART_RX = 13, +#if CFG_WMT_LTE_COEX_HANDLING + PIN_TDM_REQ = 14, +#endif + PIN_ID_MAX +} ENUM_PIN_ID, *P_ENUM_PIN_ID; +#if 0 +typedef enum _ENUM_PIN_ID_ { + PIN_BGF_EINT = 0, + PIN_I2S_GRP = 1, + PIN_GPS_SYNC = 2, + PIN_GPS_LNA = 3, +#if CFG_WMT_LTE_COEX_HANDLING + PIN_TDM_REQ = 4, +#endif + PIN_ID_MAX +} ENUM_PIN_ID, *P_ENUM_PIN_ID; +#endif + +typedef enum _ENUM_FUNC_STATE_ { + FUNC_ON = 0, + FUNC_OFF = 1, + FUNC_RST = 2, + FUNC_STAT = 3, + FUNC_CTRL_MAX, +} ENUM_FUNC_STATE, *P_ENUM_FUNC_STATE; + +typedef enum _ENUM_PIN_STATE_ { + PIN_STA_INIT = 0, + PIN_STA_OUT_L = 1, + PIN_STA_OUT_H = 2, + PIN_STA_IN_L = 3, + PIN_STA_MUX = 4, + PIN_STA_EINT_EN = 5, + PIN_STA_EINT_DIS = 6, + PIN_STA_DEINIT = 7, + PIN_STA_SHOW = 8, + PIN_STA_IN_PU = 9, + PIN_STA_IN_NP = 10, + PIN_STA_IN_H = 11, + PIN_STA_MAX +} ENUM_PIN_STATE, *P_ENUM_PIN_STATE; + +typedef enum _CMB_IF_TYPE_ { + CMB_IF_UART = 0, + CMB_IF_WIFI_SDIO = 1, + CMB_IF_BGF_SDIO = 2, + CMB_IF_BGWF_SDIO = 3, + CMB_IF_TYPE_MAX +} CMB_IF_TYPE, *P_CMB_IF_TYPE; + +typedef INT32(*fp_set_pin) (ENUM_PIN_STATE); + +typedef enum _ENUM_WL_OP_ { + WL_OP_GET = 0, + WL_OP_PUT = 1, + WL_OP_MAX +} ENUM_WL_OP, *P_ENUM_WL_OP; + +typedef enum _ENUM_PALDO_TYPE_ { + BT_PALDO = 0, + WIFI_PALDO = 1, + FM_PALDO = 2, + GPS_PALDO = 3, + PMIC_CHIPID_PALDO = 4, + WIFI_5G_PALDO = 5, + EFUSE_PALDO = 6, + PALDO_TYPE_MAX +} ENUM_PALDO_TYPE, *P_ENUM_PALDO_TYPE; + +typedef enum _ENUM_PALDO_OP_ { + PALDO_OFF = 0, + PALDO_ON = 1, + PALDO_OP_MAX +} ENUM_PALDO_OP, *P_ENUM_PALDO_OP; + +typedef enum _ENUM_HOST_DUMP_STATE_T { + STP_HOST_DUMP_NOT_START = 0, + STP_HOST_DUMP_GET = 1, + STP_HOST_DUMP_GET_DONE = 2, + STP_HOST_DUMP_END = 3, + STP_HOST_DUMP_MAX +} ENUM_HOST_DUMP_STATE, *P_ENUM_HOST_DUMP_STATE_T; + +typedef enum _ENUM_FORCE_TRG_ASSERT_T { + STP_FORCE_TRG_ASSERT_EMI = 0, + STP_FORCE_TRG_ASSERT_DEBUG_PIN = 1, + STP_FORCE_TRG_ASSERT_MAX = 2 +} ENUM_FORCE_TRG_ASSERT_T, *P_ENUM_FORCE_TRG_ASSERT_T; + +typedef enum _ENUM_CHIP_DUMP_STATE_T { + STP_CHIP_DUMP_NOT_START = 0, + STP_CHIP_DUMP_PUT = 1, + STP_CHIP_DUMP_PUT_DONE = 2, + STP_CHIP_DUMP_END = 3, + STP_CHIP_DUMP_MAX +} ENUM_CHIP_DUMP_STATE, *P_ENUM_CHIP_DUMP_STATE_T; + +#define CONSYS_BUS_CLK_STATUS_OFFSET 0x00000100 +#define CONSYS_CPU_CLK_STATUS_OFFSET 0x0000010c +#define CONSYS_DBG_CR1_OFFSET 0x00000408 +#define CONSYS_DBG_CR2_OFFSET 0x0000040c +typedef enum _ENUM_CONNSYS_DEBUG_CR { + CONNSYS_CPU_CLK = 0, + CONNSYS_BUS_CLK = 1, + CONNSYS_DEBUG_CR1 = 2, + CONNSYS_DEBUG_CR2 = 3, + CONNSYS_EMI_REMAP = 4, + CONNSYS_CR_MAX +} ENUM_CONNSYS_DEBUG_CR, *P_ENUM_CONNSYS_DEBUG_CR; + +typedef struct _EMI_CTRL_STATE_OFFSET_ { + UINT32 emi_apmem_ctrl_state; + UINT32 emi_apmem_ctrl_host_sync_state; + UINT32 emi_apmem_ctrl_host_sync_num; + UINT32 emi_apmem_ctrl_chip_sync_state; + UINT32 emi_apmem_ctrl_chip_sync_num; + UINT32 emi_apmem_ctrl_chip_sync_addr; + UINT32 emi_apmem_ctrl_chip_sync_len; + UINT32 emi_apmem_ctrl_chip_print_buff_start; + UINT32 emi_apmem_ctrl_chip_print_buff_len; + UINT32 emi_apmem_ctrl_chip_print_buff_idx; + UINT32 emi_apmem_ctrl_chip_int_status; + UINT32 emi_apmem_ctrl_chip_paded_dump_end; + UINT32 emi_apmem_ctrl_host_outband_assert_w1; + UINT32 emi_apmem_ctrl_chip_page_dump_num; + UINT32 emi_apmem_ctrl_assert_flag; + UINT32 emi_apmem_ctrl_chip_check_sleep; +} EMI_CTRL_STATE_OFFSET, *P_EMI_CTRL_STATE_OFFSET; + +typedef struct _BGF_IRQ_BALANCE_ { + UINT32 counter; + unsigned long flags; + spinlock_t lock; +} BGF_IRQ_BALANCE, *P_BGF_IRQ_BALANCE; + +typedef struct _CONSYS_EMI_ADDR_INFO_ { + UINT32 emi_phy_addr; + UINT32 emi_ap_phy_addr; + UINT32 paged_trace_off; + UINT32 paged_dump_off; + UINT32 full_dump_off; + UINT32 emi_remap_offset; + P_EMI_CTRL_STATE_OFFSET p_ecso; + UINT32 emi_size; + UINT32 pda_dl_patch_flag; + UINT32 emi_met_size; + UINT32 emi_met_data_offset; + UINT32 emi_core_dump_offset; + UINT32 emi_direct_path_ap_phy_addr; + UINT32 emi_direct_path_size; + UINT32 emi_ram_bt_buildtime_offset; + UINT32 emi_ram_wifi_buildtime_offset; + UINT32 emi_ram_mcu_buildtime_offset; + UINT32 emi_patch_mcu_buildtime_offset; +} CONSYS_EMI_ADDR_INFO, *P_CONSYS_EMI_ADDR_INFO; + +typedef struct _GPIO_TDM_REQ_INFO_ { + UINT32 ant_sel_index; + UINT32 gpio_number; + UINT32 cr_address; +} GPIO_TDM_REQ_INFO, *P_GPIO_TDM_REQ_INFO; + +typedef VOID(*irq_cb) (VOID); +typedef INT32(*device_audio_if_cb) (CMB_STUB_AIF_X aif, MTK_WCN_BOOL share); +typedef VOID(*func_ctrl_cb) (UINT32 on, UINT32 type); +typedef long (*thermal_query_ctrl_cb) (VOID); +typedef INT32(*trigger_assert_cb) (UINT32 type, UINT32 reason); +typedef INT32(*deep_idle_ctrl_cb) (UINT32); + +typedef enum { + WMT_SDIO_SLOT_INVALID = 0, + WMT_SDIO_SLOT_SDIO1 = 1, /* Wi-Fi dedicated SDIO1 */ + WMT_SDIO_SLOT_SDIO2 = 2, + WMT_SDIO_SLOT_MAX +} WMT_SDIO_SLOT_NUM; + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +extern INT32 gWmtDbgLvl; +extern struct device *wmt_dev; +#ifdef CFG_WMT_READ_EFUSE_VCN33 +extern INT32 wmt_set_pmic_voltage(UINT32 level); +#endif +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +INT32 wmt_plat_init(P_PWR_SEQ_TIME pPwrSeqTime, UINT32 co_clock_type); +INT32 wmt_plat_deinit(VOID); +INT32 wmt_plat_merge_if_flag_get(VOID); +INT32 wmt_plat_set_comm_if_type(ENUM_STP_TX_IF_TYPE type); +INT32 wmt_plat_merge_if_flag_ctrl(UINT32 enagle); +ENUM_STP_TX_IF_TYPE wmt_plat_get_comm_if_type(VOID); + +INT32 wmt_plat_pwr_ctrl(ENUM_FUNC_STATE state); + +INT32 wmt_plat_gpio_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state); + +INT32 wmt_plat_eirq_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state); + +INT32 wmt_plat_wake_lock_ctrl(ENUM_WL_OP opId); +INT32 wmt_plat_sdio_ctrl(WMT_SDIO_SLOT_NUM sdioPortNum, ENUM_FUNC_STATE on); + +INT32 wmt_plat_audio_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl); +VOID wmt_lib_plat_irq_cb_reg(irq_cb bgf_irq_cb); +VOID wmt_lib_plat_aif_cb_reg(device_audio_if_cb aif_ctrl_cb); + +VOID wmt_plat_irq_cb_reg(irq_cb bgf_irq_cb); +VOID wmt_plat_aif_cb_reg(device_audio_if_cb aif_ctrl_cb); +VOID wmt_plat_func_ctrl_cb_reg(func_ctrl_cb subsys_func_ctrl); +VOID wmt_plat_thermal_ctrl_cb_reg(thermal_query_ctrl_cb thermal_query_ctrl); +VOID wmt_plat_trigger_assert_cb_reg(trigger_assert_cb trigger_assert); +VOID wmt_plat_deep_idle_ctrl_cb_reg(deep_idle_ctrl_cb deep_idle_ctrl); + +INT32 wmt_plat_soc_paldo_ctrl(ENUM_PALDO_TYPE ePt, ENUM_PALDO_OP ePo); +UINT8 *wmt_plat_get_emi_virt_add(UINT32 offset); +#if CONSYS_ENALBE_SET_JTAG +UINT32 wmt_plat_jtag_flag_ctrl(UINT32 en); +#endif +#if CFG_WMT_DUMP_INT_STATUS +VOID wmt_plat_BGF_irq_dump_status(VOID); +MTK_WCN_BOOL wmt_plat_dump_BGF_irq_status(VOID); +#endif +P_CONSYS_EMI_ADDR_INFO wmt_plat_get_emi_phy_add(VOID); +UINT32 wmt_plat_read_cpupcr(VOID); +UINT32 wmt_plat_read_dmaregs(UINT32); +INT32 wmt_plat_set_host_dump_state(ENUM_HOST_DUMP_STATE state); +UINT32 wmt_plat_force_trigger_assert(ENUM_FORCE_TRG_ASSERT_T type); +INT32 wmt_plat_update_host_sync_num(VOID); +INT32 wmt_plat_get_dump_info(UINT32 offset); +INT32 wmt_plat_write_emi_l(UINT32 offset, UINT32 value); +UINT32 wmt_plat_get_soc_chipid(VOID); +UINT32 wmt_plat_soc_co_clock_flag_get(VOID); +INT32 wmt_plat_set_dbg_mode(UINT32 flag); +INT32 wmt_plat_set_dynamic_dumpmem(PUINT32 buf); +#if CFG_WMT_LTE_COEX_HANDLING +INT32 wmt_plat_get_tdm_antsel_index(VOID); +#endif +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _WMT_PLAT_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_plat_stub.h b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_plat_stub.h new file mode 100644 index 00000000000000..1bca1fefb1e728 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/include/wmt_plat_stub.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + + +#ifndef _WMT_PLAT_STUB_H_ +#define _WMT_PLAT_STUB_H_ + + +INT32 wmt_plat_audio_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl); + +INT32 wmt_plat_stub_init(VOID); + +#endif /*_WMT_PLAT_STUB_H_*/ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/bgw_desense.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/bgw_desense.c new file mode 100644 index 00000000000000..a18f03c0bca06f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/bgw_desense.c @@ -0,0 +1,141 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <linux/version.h> +#include <linux/netlink.h> +#include <linux/kernel.h> +#include <linux/module.h> + +#include <linux/socket.h> +#include <linux/skbuff.h> +#include <net/sock.h> +#include <net/genetlink.h> +#include "bgw_desense.h" + +static struct sock *g_nl_sk; +/* static struct sockaddr_nl src_addr, des_addr; */ +/* static struct iovec iov; */ +static int pid; +/* static struct msghdr msg; */ + +void bgw_destroy_netlink_kernel(void) +{ + if (g_nl_sk != NULL) { + /* sock_release(g_nl_sk->sk_socket); */ + netlink_kernel_release(g_nl_sk); + MSG("release socket\n"); + return; + } + ERR("no socket yet\n"); +} + +void send_command_to_daemon(const int command /*struct sk_buff *skb */) +{ + struct nlmsghdr *nlh; + struct sk_buff *nl_skb; + int res; + + MSG("here we will send command to native daemon\n"); + if (!g_nl_sk) { + ERR("invalid socket\n"); + return; + } + if (pid == 0) { + ERR("invalid native process pid\n"); + return; + } + /*alloc data buffer for sending to native */ + /*malloc data space at least 1500 bytes, which is ethernet data length */ + nl_skb = alloc_skb(NLMSG_SPACE(MAX_NL_MSG_LEN), GFP_ATOMIC); + if (nl_skb == NULL) { + ERR("malloc skb error\n"); + return; + } + MSG("malloc data space done\n"); + +/* nlh = NLMSG_PUT(nl_skb, 0, 0, 0, NLMSG_SPACE(1500)-sizeof(struct nlmsghdr)); */ + nlh = nlmsg_put(nl_skb, 0, 0, 0, MAX_NL_MSG_LEN, 0); + if (nlh == NULL) { + MSG("nlh is NULL\n"); + kfree_skb(nl_skb); + return; + } + NETLINK_CB(nl_skb).portid = 0; + +/* memcpy(NLMSG_DATA(nlh), ACK, 5); */ + *(char *)NLMSG_DATA(nlh) = command; + res = netlink_unicast(g_nl_sk, nl_skb, pid, MSG_DONTWAIT); + if (res == 0) { + MSG("send to user space process error\n"); + return; + } + ERR("send to user space process done, data length = %d\n", res); +} + +static void nl_data_handler(struct sk_buff *__skb) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + int i; + int len; + char str[128]; + + MSG("we got netlink message\n"); + len = NLMSG_SPACE(MAX_NL_MSG_LEN); + skb = skb_get(__skb); + if (skb == NULL) { + ERR("skb_get return NULL"); + return; + } + if (skb->len >= NLMSG_SPACE(0)) { /*presume there is 5byte payload at leaset */ + MSG("length is enough\n"); + nlh = nlmsg_hdr(skb); /* point to data which include in skb */ + memcpy(str, NLMSG_DATA(nlh), sizeof(str)); + for (i = 0; i < 3; i++) + MSG("str[%d = %c]", i, str[i]); + MSG("str[0] = %d, str[1] = %d, str[2] = %d\n", str[0], str[1], str[2]); + if (str[0] == 'B' && str[1] == 'G' && str[2] == 'W') { + MSG("got native daemon init command, record it's pid\n"); + pid = nlh->nlmsg_pid; /*record the native process PID */ + MSG("native daemon pid is %d\n", pid); + } else { + ERR("this is not BGW message, ignore it\n"); + return; + } + } else { + ERR("not engouth data length\n"); + return; + } + + kfree_skb(skb); + + send_command_to_daemon(ACK); +} + +int bgw_init_socket(void) +{ + struct netlink_kernel_cfg cfg; + + memset(&cfg, 0, sizeof(cfg)); + cfg.input = nl_data_handler; + + g_nl_sk = __netlink_kernel_create(&init_net, NETLINK_TEST, THIS_MODULE, &cfg); + + if (g_nl_sk == NULL) { + ERR("netlink_kernel_create error\n"); + return -1; + } + MSG("netlink_kernel_create ok\n"); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/fw_log_wmt.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/fw_log_wmt.c new file mode 100644 index 00000000000000..bf495f83f06ed2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/fw_log_wmt.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +#include "fw_log_wmt.h" +#include "connsys_debug_utility.h" +#include <linux/cdev.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/poll.h> +#include "wmt_lib.h" + +#define DRIVER_NAME "fw_log_wmt" +#define WMT_FW_LOG_IOC_MAGIC 0xfc +#define WMT_FW_LOG_IOCTL_ON_OFF _IOW(WMT_FW_LOG_IOC_MAGIC, 0, int) +#define WMT_FW_LOG_IOCTL_SET_LEVEL _IOW(WMT_FW_LOG_IOC_MAGIC, 1, int) + +static dev_t gDevId; +static struct cdev gLogCdev; +static struct class *fw_log_wmt_class; +static struct device *fw_log_wmt_dev; +static wait_queue_head_t wq; + +static int fw_log_wmt_open(struct inode *inode, struct file *file) +{ + pr_info("%s\n", __func__); + return 0; +} + +static int fw_log_wmt_close(struct inode *inode, struct file *file) +{ + pr_info("%s\n", __func__); + return 0; +} + +static ssize_t fw_log_wmt_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + ssize_t size = 0; + + pr_debug("%s\n", __func__); + size = connsys_log_read_to_user(CONNLOG_TYPE_MCU, buf, count); + return size; +} + +static ssize_t fw_log_wmt_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + pr_debug("%s\n", __func__); + return 0; +} + +static unsigned int fw_log_wmt_poll(struct file *filp, poll_table *wait) +{ + pr_debug("%s\n", __func__); + + poll_wait(filp, &wq, wait); + if (connsys_log_get_buf_size(CONNLOG_TYPE_MCU) > 0) + return POLLIN | POLLRDNORM; + + return 0; +} + +static long fw_log_wmt_unlocked_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + long ret = 0; + + switch (cmd) { + case WMT_FW_LOG_IOCTL_ON_OFF: + pr_debug("ioctl: WMT_FW_LOG_IOCTL_ON_OFF(%lu)", arg); + if (arg == 0 || arg == 1) + wmt_lib_fw_log_ctrl(WMT_FWLOG_MCU, (unsigned char)arg, 0xFF); + break; + case WMT_FW_LOG_IOCTL_SET_LEVEL: + pr_debug("ioctl: WMT_FW_LOG_IOCTL_SET_LEVEL(%lu)", arg); + if (arg <= 4) + wmt_lib_fw_log_ctrl(WMT_FWLOG_MCU, 0xFF, (unsigned char)arg); + break; + default: + /*no action*/ + break; + } + return ret; +} + +#ifdef CONFIG_COMPAT +static long fw_log_wmt_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return fw_log_wmt_unlocked_ioctl(filp, cmd, arg); +} +#endif + +const struct file_operations gLogFops = { + .open = fw_log_wmt_open, + .release = fw_log_wmt_close, + .read = fw_log_wmt_read, + .write = fw_log_wmt_write, + .poll = fw_log_wmt_poll, + .unlocked_ioctl = fw_log_wmt_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = fw_log_wmt_compat_ioctl, +#endif +}; + +static void fw_log_wmt_event_cb(void) +{ + wake_up_interruptible(&wq); +} + +int fw_log_wmt_init(void) +{ + int cdevErr = -1; + int ret = -1; + + ret = alloc_chrdev_region(&gDevId, 0, 1, DRIVER_NAME); + if (ret) + pr_err("fail to alloc_chrdev_region\n"); + + cdev_init(&gLogCdev, &gLogFops); + gLogCdev.owner = THIS_MODULE; + + cdevErr = cdev_add(&gLogCdev, gDevId, 1); + if (cdevErr) { + pr_err("cdev_add() fails (%d)\n", cdevErr); + goto error; + } + + fw_log_wmt_class = class_create(THIS_MODULE, DRIVER_NAME); + if (IS_ERR(fw_log_wmt_class)) { + pr_err("class_create fail\n"); + goto error; + } + + fw_log_wmt_dev = device_create(fw_log_wmt_class, NULL, gDevId, NULL, + DRIVER_NAME); + if (IS_ERR(fw_log_wmt_dev)) { + pr_err("device_create fail\n"); + goto error; + } + + init_waitqueue_head(&wq); + ret = connsys_log_init(CONNLOG_TYPE_MCU); + if (ret) + pr_err("fail to connsys_log_init\n"); + + ret = connsys_log_register_event_cb(CONNLOG_TYPE_MCU, + fw_log_wmt_event_cb); + if (ret) + pr_err("fail to connsys_log_register_event_cb\n"); + + return 0; + +error: + if (!(IS_ERR(fw_log_wmt_dev))) + device_destroy(fw_log_wmt_class, gDevId); + if (!(IS_ERR(fw_log_wmt_class))) { + class_destroy(fw_log_wmt_class); + fw_log_wmt_class = NULL; + } + + if (cdevErr == 0) + cdev_del(&gLogCdev); + if (ret == 0) + unregister_chrdev_region(gDevId, 1); + pr_err("fw_log_wmt_init fail\n"); + return -1; +} +EXPORT_SYMBOL(fw_log_wmt_init); + +void fw_log_wmt_deinit(void) +{ + connsys_log_deinit(CONNLOG_TYPE_MCU); + if (fw_log_wmt_dev) { + device_destroy(fw_log_wmt_class, gDevId); + fw_log_wmt_dev = NULL; + } + + if (fw_log_wmt_class) { + class_destroy(fw_log_wmt_class); + fw_log_wmt_class = NULL; + } + + cdev_del(&gLogCdev); + unregister_chrdev_region(gDevId, 1); + pr_warn("fw_log_wmt_driver_deinit done\n"); +} +EXPORT_SYMBOL(fw_log_wmt_deinit); +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/hif_sdio.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/hif_sdio.c new file mode 100644 index 00000000000000..12133ba33e144e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/hif_sdio.c @@ -0,0 +1,2920 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/* + * + * 07 25 2010 george.kuo + * + * Move hif_sdio driver to linux directory. + * + * 07 23 2010 george.kuo + * + * Add MT6620 driver source tree + * , including char device driver (wmt, bt, gps), stp driver, + * interface driver (tty ldisc and hif_sdio), and bt hci driver. +** +** +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define HIF_SDIO_UPDATE (1) +#define HIF_SDIO_SUPPORT_SUSPEND (1) +#define HIF_SDIO_SUPPORT_WAKEUP (0) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include <linux/proc_fs.h> +#include "hif_sdio.h" +#include "wmt_gpio.h" +/* #include "hif_sdio_chrdev.h" */ +#include <connectivity_build_in_adapter.h> +#include <wmt_build_in_adapter.h> + +#define mmc_power_up_ext(x) +#define mmc_power_off_ext(x) +MTK_WCN_BOOL g_hif_deep_sleep_flag = MTK_WCN_BOOL_FALSE; + +#ifndef MMC_CARD_REMOVED +#define MMC_CARD_REMOVED (1<<4) +#endif + +#ifndef mmc_card_removed +#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) +#endif +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* #define DRV_NAME "[hif_sdio]" */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +#if HIF_SDIO_SUPPORT_SUSPEND +static INT32 hif_sdio_suspend(struct device *dev); + +static INT32 hif_sdio_resume(struct device *dev); +#endif +static INT32 hif_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id); + +static VOID hif_sdio_remove(struct sdio_func *func); + +static VOID hif_sdio_irq(struct sdio_func *func); + +static _osal_inline_ INT32 hif_sdio_clt_probe_func(MTK_WCN_HIF_SDIO_REGISTINFO *registinfo_p, + INT8 probe_idx); + +static VOID hif_sdio_clt_probe_worker(struct work_struct *work); + +static _osal_inline_ INT32 hif_sdio_find_probed_list_index_by_func(struct sdio_func *func); + +#if 0 /* TODO:[ChangeFeature][George] remove obsolete function? */ +static INT32 hif_sdio_find_probed_list_index_by_clt_index(INT32 clt_index); +#endif + +static _osal_inline_ INT32 hif_sdio_find_probed_list_index_by_id_func(UINT16 vendor, UINT16 device, + UINT16 func_num); + +static _osal_inline_ VOID hif_sdio_init_clt_list(INT32 index); + +static _osal_inline_ INT32 hif_sdio_find_clt_list_index(UINT16 vendor, UINT16 device, UINT16 func_num); + +static _osal_inline_ INT32 hif_sdio_check_supported_sdio_id(UINT16 vendor, UINT16 device); + +static _osal_inline_ INT32 hif_sdio_check_duplicate_sdio_id(UINT16 vendor, UINT16 device, UINT16 func_num); + +static _osal_inline_ INT32 hif_sdio_add_clt_list(PINT32 clt_index_p, const MTK_WCN_HIF_SDIO_CLTINFO *pinfo, + UINT32 tbl_index); + +static _osal_inline_ INT32 hif_sdio_stp_on(VOID); + +static _osal_inline_ INT32 hif_sdio_stp_off(VOID); + +static _osal_inline_ INT32 hif_sdio_wifi_on(VOID); + +static _osal_inline_ INT32 hif_sdio_wifi_off(VOID); + +static _osal_inline_ INT32 hif_sdio_deep_sleep_info_init(VOID); + +static _osal_inline_ INT32 hif_sdio_deep_sleep_info_set_act(UINT32 chipid, UINT16 func_num, + MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT8 act_flag); + +static INT32 _hif_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx); + +static _osal_inline_ INT32 wmt_tra_sdio_update(VOID); + +static _osal_inline_ INT32 hif_sdio_deep_sleep_info_dmp(MTK_WCN_HIF_SDIO_DS_INFO *p_ds_info); + +static _osal_inline_ VOID hif_sdio_dump_probe_list(VOID); + +static _osal_inline_ VOID hif_sdio_init_probed_list(INT32 index); + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/* Supported SDIO device table */ +static const struct sdio_device_id mtk_sdio_id_tbl[] = { + /* MT6618 *//* Not an SDIO standard class device */ + {SDIO_DEVICE(0x037A, 0x018A)}, /* SDIO1:WIFI */ + {SDIO_DEVICE(0x037A, 0x018B)}, /* SDIO2:FUNC1:BT+FM */ + {SDIO_DEVICE(0x037A, 0x018C)}, /* 2-function (SDIO2:FUNC1:BT+FM, FUNC2:WIFI) */ + + /* MT6619 *//* Not an SDIO standard class device */ + {SDIO_DEVICE(0x037A, 0x6619)}, /* SDIO2:FUNC1:BT+FM+GPS */ + + /* MT6620 *//* Not an SDIO standard class device */ + {SDIO_DEVICE(0x037A, 0x020A)}, /* SDIO1:FUNC1:WIFI */ + {SDIO_DEVICE(0x037A, 0x020B)}, /* SDIO2:FUNC1:BT+FM+GPS */ + {SDIO_DEVICE(0x037A, 0x020C)}, /* 2-function (SDIO2:FUNC1:BT+FM+GPS, FUNC2:WIFI) */ + + /* MT5921 *//* Not an SDIO standard class device */ + {SDIO_DEVICE(0x037A, 0x5921)}, + + /* MT6628 *//* SDIO1: Wi-Fi, SDIO2: BGF */ + {SDIO_DEVICE(0x037A, 0x6628)}, + + /* MT6630 *//* SDIO1: Wi-Fi, SDIO2: BGF */ + {SDIO_DEVICE(0x037A, 0x6630)}, + + /* MT6632 *//* SDIO1: Wi-Fi */ + {SDIO_DEVICE(0x037A, 0x6602)}, + + /* MT6632 *//* SDIO2: BGF */ + {SDIO_DEVICE(0x037A, 0x6632)}, + + { /* end: all zeroes */ }, +}; + +#if HIF_SDIO_SUPPORT_SUSPEND +static const struct dev_pm_ops mtk_sdio_pmops = { + .suspend = hif_sdio_suspend, + .resume = hif_sdio_resume, +}; +#endif + +static struct sdio_driver mtk_sdio_client_drv = { + .name = "mtk_sdio_client", /* MTK SDIO Client Driver */ + .id_table = mtk_sdio_id_tbl, /* all supported struct sdio_device_id table */ + .probe = hif_sdio_probe, + .remove = hif_sdio_remove, +#if HIF_SDIO_SUPPORT_SUSPEND + .drv = { + .pm = &mtk_sdio_pmops, + }, +#endif +}; + +/* Registered client driver list */ +/* static list g_hif_sdio_clt_drv_list */ +static MTK_WCN_HIF_SDIO_REGISTINFO g_hif_sdio_clt_drv_list[CFG_CLIENT_COUNT]; + +/* MMC probed function list */ +/* static list g_hif_sdio_probed_func_list */ +static MTK_WCN_HIF_SDIO_PROBEINFO g_hif_sdio_probed_func_list[CFG_CLIENT_COUNT]; + +/* spin lock info for g_hif_sdio_clt_drv_list and g_hif_sdio_probed_func_list */ +static MTK_WCN_HIF_SDIO_LOCKINFO g_hif_sdio_lock_info; + +/* reference count, debug information? */ +static INT32 gRefCount; +static INT32 (*fp_wmt_tra_sdio_update)(VOID); +static atomic_t hif_sdio_irq_enable_flag = ATOMIC_INIT(0); + +/*deep sleep related information*/ +MTK_WCN_HIF_SDIO_DS_INFO g_hif_sdio_ds_info_list[] = { + { + .chip_id = 0x6630, + .reg_offset = 0xF1, + .value = 0x1, + }, + { + .chip_id = 0x6632, + .reg_offset = 0xF1, + .value = 0x1, + }, + { /* end: all zeroes */ } +}; + + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("MediaTek Inc WCN_SE_CS3"); +MODULE_DESCRIPTION("MediaTek MT6620 HIF SDIO Driver"); + +MODULE_DEVICE_TABLE(sdio, mtk_sdio_id_tbl); + +INT32 gHifSdioDbgLvl = HIF_SDIO_LOG_INFO; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#if 0 +INT32 __weak mtk_wcn_sdio_irq_flag_set(INT32 falg) +{ + HIF_SDIO_INFO_FUNC("mtk_wcn_sdio_irq_flag_set is not define!!!!!\n"); + + return 0; +} +#endif + +INT32 mtk_wcn_hif_sdio_irq_flag_set(INT32 flag) +{ + + if (flag == 0) { + atomic_dec(&hif_sdio_irq_enable_flag); + if (atomic_read(&hif_sdio_irq_enable_flag) == 0) + wmt_export_mtk_wcn_sdio_irq_flag_set(0); + } else { + atomic_inc(&hif_sdio_irq_enable_flag); + if (atomic_read(&hif_sdio_irq_enable_flag) == 1) + wmt_export_mtk_wcn_sdio_irq_flag_set(1); + } + + return 0; +} + + +/*! + * \brief register the callback funciton for record the timestamp of sdio access + * + * \param callback function + * + * \retval -EINVAL, when registered callback is invalid + * \retval 0, when registered callback is valid + */ +INT32 mtk_wcn_hif_sdio_update_cb_reg(INT32(*ts_update) (VOID)) +{ + if (ts_update) { + fp_wmt_tra_sdio_update = ts_update; + return 0; + } else { + return -EINVAL; + } +} +EXPORT_SYMBOL(mtk_wcn_hif_sdio_update_cb_reg); + +/*! + * \brief update the accessing time of SDIO via callback function + * + * \param void + * + * \retval -EINVAL, when callback is not registered + * \retval returned value of callback + */ +static _osal_inline_ INT32 wmt_tra_sdio_update(VOID) +{ + if (fp_wmt_tra_sdio_update) + return (*fp_wmt_tra_sdio_update) (); + /* HIF_SDIO_WARN_FUNC("wmt_tra_sdio_update == NULL\n"); */ + return -EINVAL; +} + +/*! + * \brief Translate CLTCTX into a pointer to struct sdio_func if it is valid + * + * Translate a CLTCTX into a pointer to struct sdio_func if it is + * 1) probed by mmc_core, and + * 2) client driver is registered, and + * 3) clt_idx of client driver is valid + * + * \param ctx a context provided by client driver + * + * \retval null if any condition is not valie + * \retval a pointer to a struct sdio_func mapped by provided ctx + */ +static _osal_inline_ struct sdio_func *hif_sdio_ctx_to_func(MTK_WCN_HIF_SDIO_CLTCTX ctx) +{ + UINT32 probe_index; + + /* 4 <1> check if ctx is valid, registered, and probed */ + probe_index = CLTCTX_IDX(ctx); + if (unlikely(!CLTCTX_UIDX_VALID(probe_index))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx); + return NULL; + } + /* the client has not been registered */ + if (unlikely(g_hif_sdio_probed_func_list[probe_index].clt_idx < 0)) { + HIF_SDIO_WARN_FUNC + ("can't find client idx in probed list!ctx(0x%x) prob_idx(%d) clt_idx(%d)\n", + ctx, probe_index, g_hif_sdio_probed_func_list[probe_index].clt_idx); + return NULL; + } + return g_hif_sdio_probed_func_list[probe_index].func; +} + +static _osal_inline_ INT32 hif_sdio_deep_sleep_info_dmp(MTK_WCN_HIF_SDIO_DS_INFO *p_ds_info) +{ + UINT32 i = 0; + MTK_WCN_HIF_SDIO_DS_CLT_INFO *ctl_info = NULL; + UINT32 ctl_info_array_size = ARRAY_SIZE(p_ds_info->clt_info); + + mutex_lock(&p_ds_info->lock); + HIF_SDIO_DBG_FUNC("p_ds_info: %p, chipid:0x%x, reg_offset:0x%x, value:0x%x\n", + p_ds_info, p_ds_info->chip_id, p_ds_info->reg_offset, p_ds_info->value); + + for (i = 0; i < ctl_info_array_size; i++) { + ctl_info = &p_ds_info->clt_info[i]; + + HIF_SDIO_DBG_FUNC + ("ctl_info[%d]--ctx:0x%08x, func_num:%d, act_flag:%d, en_flag:%d\n", i, + ctl_info->ctx, ctl_info->func_num, ctl_info->act_flag, ctl_info->ds_en_flag); + } + mutex_unlock(&p_ds_info->lock); + return 0; +} + +static _osal_inline_ INT32 hif_sdio_deep_sleep_info_init(VOID) +{ + UINT32 array_size = 0; + UINT32 clt_info_size = 0; + UINT32 i = 0; + UINT32 j = 0; + + array_size = ARRAY_SIZE(g_hif_sdio_ds_info_list); + + /*set clt_info segment to 0 by default, when do stp/wifi on, write real information back */ + for (i = 0; i < array_size; i++) { + mutex_init(&g_hif_sdio_ds_info_list[i].lock); + clt_info_size = ARRAY_SIZE(g_hif_sdio_ds_info_list[i].clt_info); + + mutex_lock(&g_hif_sdio_ds_info_list[i].lock); + for (j = 0; j < clt_info_size; j++) + memset(&g_hif_sdio_ds_info_list[i].clt_info[j], + 0, sizeof(MTK_WCN_HIF_SDIO_DS_CLT_INFO)); + mutex_unlock(&g_hif_sdio_ds_info_list[i].lock); + + hif_sdio_deep_sleep_info_dmp(&g_hif_sdio_ds_info_list[i]); + } + + return 0; +} + +static _osal_inline_ INT32 hif_sdio_deep_sleep_info_set_act(UINT32 chipid, UINT16 func_num, + MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT8 act_flag) +{ + UINT32 i = 0; + UINT32 array_size = 0; + UINT32 clt_info_size = 0; + UINT32 idx = 0; + MTK_WCN_HIF_SDIO_DS_CLT_INFO *p_ds_clt_info = NULL; + + array_size = ARRAY_SIZE(g_hif_sdio_ds_info_list); + + /*search write index */ + for (i = 0; i < array_size; i++) { + if (g_hif_sdio_ds_info_list[i].chip_id == chipid) + break; + } + if (i >= array_size) { + HIF_SDIO_WARN_FUNC("no valid ds info found for 0x%x\n", chipid); + return -1; + } + HIF_SDIO_DBG_FUNC("valid ds info found for 0x%x\n", chipid); + + clt_info_size = ARRAY_SIZE(g_hif_sdio_ds_info_list[i].clt_info); + + if (func_num > clt_info_size) { + HIF_SDIO_WARN_FUNC("func num <%d> exceed max clt info size <%d>\n", func_num, + clt_info_size); + return -2; + } + idx = func_num - 1; + p_ds_clt_info = &g_hif_sdio_ds_info_list[i].clt_info[idx]; + + mutex_lock(&g_hif_sdio_ds_info_list[i].lock); + p_ds_clt_info->func_num = func_num; + p_ds_clt_info->ctx = ctx; + p_ds_clt_info->act_flag = act_flag; + p_ds_clt_info->ds_en_flag = 0; + mutex_unlock(&g_hif_sdio_ds_info_list[i].lock); + + HIF_SDIO_DBG_FUNC("set act_flag to %d for ctx:0x%x whose chipid:0x%x, func_num:%d done\n", + act_flag, ctx, chipid, func_num); + /* hif_sdio_deep_sleep_info_dmp(&g_hif_sdio_ds_info_list[0]); */ + + return 0; +} + +static INT32 _hif_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx) +{ + INT32 ret = 0; + INT32 gpio_state = -1; + INT32 sec_old = 0; + INT32 usec_old = 0; + INT32 sec = 0; + INT32 usec = 0; + INT32 polling_counter = 0; + UINT8 cccr_value = 0x0; + UINT32 cpupcr_value = 0x00; + INT32 i = 0; + UINT32 delay_us = 500; + WMT_GPIO_STATE_INFO gpio_state_list[2]; + + HIF_SDIO_DBG_FUNC("wakeup chip from deep sleep!\n"); + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num != DEFAULT_PIN_ID) { + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num, 1); + HIF_SDIO_DBG_FUNC("wmt_gpio:set GPIO_CHIP_WAKE_UP_PIN out to 1: %d!\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num)); + } else { + HIF_SDIO_ERR_FUNC("wmt_gpio:get GPIO_CHIP_WAKE_UP_PIN number error!\n"); + return -2; + } + /*1.pull GPIO_CHIP_WAKE_UP_PIN out 0*/ + gpio_state_list[0].gpio_num = gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num-280; + _wmt_gpio_pre_regs(gpio_state_list[0].gpio_num, &gpio_state_list[0]); + gpio_state_list[1].gpio_num = gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_DEEP_SLEEP_PIN].gpio_num-280; + _wmt_gpio_pre_regs(gpio_state_list[1].gpio_num, &gpio_state_list[1]); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num != DEFAULT_PIN_ID) { + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num, 0); + HIF_SDIO_DBG_FUNC("wmt_gpio:set GPIO_CHIP_WAKE_UP_PIN out to 0: %d!\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num)); + } else { + HIF_SDIO_ERR_FUNC("wmt_gpio:get GPIO_CHIP_WAKE_UP_PIN number error!\n"); + return -2; + } + /*2.waiting for DEEP_SLEEP_PIN become high*/ + osal_gettimeofday(&sec_old, &usec_old); + HIF_SDIO_DBG_FUNC("wakeup flow, prepare polling DEEP_SLEEP_PIN high state, timing: %d us\n", usec_old); + while (1) { + osal_gettimeofday(&sec, &usec); + gpio_state = + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_DEEP_SLEEP_PIN].gpio_num); + if (gpio_state == 0) { + HIF_SDIO_DBG_FUNC("wmt_gpio:Polling GPIO_CHIP_DEEP_SLEEP_PIN low success!\n"); + if (polling_counter >= 20) + HIF_SDIO_WARN_FUNC + ("polling ACK_B pin low success but over 20 count, time:%dus, count:%d\n", + (usec - usec_old), polling_counter); + polling_counter = 0; + break; + } + if (polling_counter >= 60) { + HIF_SDIO_ERR_FUNC + ("wake up fail!, polling ACK_B pin low over 60 count, time:%dus, count:%d\n", + (usec - usec_old), polling_counter); + HIF_SDIO_INFO_FUNC("Dump EINT_B, ACT_B history states!\n"); + _wmt_dump_gpio_pre_regs(gpio_state_list[0]); + _wmt_dump_gpio_pre_regs(gpio_state_list[1]); + HIF_SDIO_INFO_FUNC("Dump EINT_B, ACT_B current states!\n"); + _wmt_dump_gpio_regs(gpio_state_list[0].gpio_num); + _wmt_dump_gpio_regs(gpio_state_list[1].gpio_num); + + HIF_SDIO_INFO_FUNC("read cccr info !\n"); + for (i = 0; i < 8; i++) { + ret = mtk_wcn_hif_sdio_f0_readb(ctx, CCCR_F8 + i, &cccr_value); + if (ret) HIF_SDIO_ERR_FUNC("read CCCR fail(%d), address(0x%x)\n", ret, CCCR_F8 + i); + else HIF_SDIO_INFO_FUNC("read CCCR value(0x%x), address(0x%x)\n", cccr_value, CCCR_F8 + i); + cccr_value = 0x0; + } + + HIF_SDIO_INFO_FUNC("read cpupcr info !\n"); + for (i = 0; i < 5; i++) { + ret = mtk_wcn_hif_sdio_readl(ctx, SWPCDBGR, &cpupcr_value); + if (ret) + HIF_SDIO_ERR_FUNC("read cpupcr fail, ret(%d)\n", ret); + else + HIF_SDIO_ERR_FUNC("read cpupcr value (0x%x)\n", cpupcr_value); + msleep(20); + } + _wmt_dump_gpio_regs(gpio_state_list[0].gpio_num); + _wmt_dump_gpio_regs(gpio_state_list[1].gpio_num); + ret = -11; + break; + } + polling_counter++; + osal_usleep_range(delay_us, 2 * delay_us); + } + /*3.pull GPIO_CHIP_WAKE_UP_PIN high, clear interrupt*/ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num != DEFAULT_PIN_ID) { + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num, 1); + HIF_SDIO_DBG_FUNC("wmt_gpio:set GPIO_CHIP_WAKE_UP_PIN out to 1: %d!\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_CHIP_WAKE_UP_PIN].gpio_num)); + } else { + HIF_SDIO_ERR_FUNC("wmt_gpio:get GPIO_CHIP_WAKE_UP_PIN number error!\n"); + return -3; + } + + return ret; +} +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +INT32 mtk_wcn_hif_sdio_deep_sleep_flag_set(MTK_WCN_BOOL flag) +{ + g_hif_deep_sleep_flag = flag; + return 0; +} +#endif +INT32 hif_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx) +{ + UINT32 i = 0; + UINT32 j = 0; + INT32 ret = 0; + UINT32 array_size = 0; + UINT32 clt_info_size = 0; + MTK_WCN_HIF_SDIO_DS_CLT_INFO *p_ds_clt_info = NULL; + MTK_WCN_HIF_SDIO_DS_INFO *p_ds_info = NULL; + UINT8 do_ds_op_flag = 0; + + array_size = ARRAY_SIZE(g_hif_sdio_ds_info_list); + /*search write index */ + for (i = 0; i < array_size; i++) { + mutex_lock(&(g_hif_sdio_ds_info_list[i].lock)); + clt_info_size = ARRAY_SIZE(g_hif_sdio_ds_info_list[i].clt_info); + + for (j = 0; j < clt_info_size; j++) { + if (g_hif_sdio_ds_info_list[i].clt_info[j].ctx == ctx) { + do_ds_op_flag = 1; + break; + } + } + + if (do_ds_op_flag != 0) + break; + mutex_unlock(&(g_hif_sdio_ds_info_list[i].lock)); + } + + if ((i >= array_size) || (j >= clt_info_size)) { + HIF_SDIO_ERR_FUNC("mtk_wcn_hif_sdio_wake_up_ctrl, no valid ds info found for ctx 0x%08x\n", ctx); + return -1; + } + HIF_SDIO_DBG_FUNC("mtk_wcn_hif_sdio_wake_up_ctrl, valid ds info found for ctx 0x%08x\n", ctx); + p_ds_info = &g_hif_sdio_ds_info_list[i]; + p_ds_clt_info = &p_ds_info->clt_info[j]; + HIF_SDIO_DBG_FUNC("mtk_wcn_hif_sdio_wake_up_ctrl, func_num:(%d), chid(%x)\n", + p_ds_clt_info->func_num, p_ds_info->chip_id); + if (g_hif_deep_sleep_flag) { + HIF_SDIO_DBG_FUNC("deep sleep feature is enable!\n"); + ret = _hif_sdio_wake_up_ctrl(ctx); + if (ret == -11) { + HIF_SDIO_DBG_FUNC("wake up chip from deep sleep fail, retry wake up operation\n"); + ret = _hif_sdio_wake_up_ctrl(ctx); + if (ret == 0) + HIF_SDIO_INFO_FUNC("retry wake up from deep sleep success\n"); + else if (ret == -11) + HIF_SDIO_INFO_FUNC("retry wake up from deep sleep fail!\n"); + } + } else + HIF_SDIO_DBG_FUNC("deep sleep feature is disable!\n"); + mutex_unlock(&(g_hif_sdio_ds_info_list[i].lock)); + return ret; +} + +/*! + * \brief MTK hif sdio client registration function + * + * Client uses this function to register itself to hif_sdio driver + * + * \param pinfo a pointer of client's information + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_client_reg(const MTK_WCN_HIF_SDIO_CLTINFO *pinfo) +{ + INT32 ret = -HIF_SDIO_ERR_FAIL; + INT32 clt_index = -1; + UINT32 i = 0; + UINT32 j = 0; + MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0; + + HIF_SDIO_DBG_FUNC("start!\n"); + /* 4 <1> check input pointer is valid */ + HIF_SDIO_ASSERT(pinfo); + + /* 4 <2> check if input parameters are all supported and valid */ + for (i = 0; i < pinfo->func_tbl_size; i++) { + ret = + hif_sdio_check_supported_sdio_id(pinfo->func_tbl[i].manf_id, + pinfo->func_tbl[i].card_id); + if (ret) { + HIF_SDIO_WARN_FUNC + ("vendor id(0x%x) and device id(0x%x) of sdio_func are not supported!\n", + pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id); + goto out; + } + } + HIF_SDIO_DBG_FUNC("hif_sdio_check_supported_sdio_id() done!\n"); + + /* 4 <3> check if the specific {manf id, card id, function number} tuple is */ + /* 4 already resigstered */ + for (i = 0; i < pinfo->func_tbl_size; i++) { + ret = + hif_sdio_check_duplicate_sdio_id(pinfo->func_tbl[i].manf_id, + pinfo->func_tbl[i].card_id, + pinfo->func_tbl[i].func_num); + if (ret) { + HIF_SDIO_WARN_FUNC("vendor id(0x%x), device id(0x%x), and fun_num(%d) of\n", + pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id, + pinfo->func_tbl[i].func_num); + HIF_SDIO_WARN_FUNC("sdio_func are duplicated in g_hif_sdio_clt_drv_list!\n"); + goto out; + } + } + HIF_SDIO_DBG_FUNC("hif_sdio_check_duplicate_sdio_id() done!\n"); + + /* + * 4 <4> add the specified {manf id, card id, function number} + * tuple to registered client list + */ + HIF_SDIO_DBG_FUNC("pinfo->func_tbl_size:%d\n", pinfo->func_tbl_size); + for (i = 0; i < pinfo->func_tbl_size; i++) { + ret = hif_sdio_add_clt_list(&clt_index, pinfo, i); + if (ret) { + HIF_SDIO_WARN_FUNC + ("client's info are added in registed client list failed (buffer is full)!\n"); + goto out; + } + HIF_SDIO_DBG_FUNC("hif_sdio_add_clt_list() done (gRefCount=%d)!\n", gRefCount); + + /* 4 <5> if the specific {manf id, card id, function number} tuple has already */ + /* 4 been probed by mmc, schedule another task to call client's .hif_clt_probe() */ + for (j = 0; j < CFG_CLIENT_COUNT; j++) { + /* probed spin lock */ + spin_lock_bh(&g_hif_sdio_lock_info.probed_list_lock); + if (g_hif_sdio_probed_func_list[j].func == 0) { + /* probed spin unlock */ + spin_unlock_bh(&g_hif_sdio_lock_info.probed_list_lock); + continue; + } + /* the function has been probed */ + if ((g_hif_sdio_clt_drv_list[clt_index].func_info->manf_id == + g_hif_sdio_probed_func_list[j].func->vendor) + && (g_hif_sdio_clt_drv_list[clt_index].func_info->card_id == + g_hif_sdio_probed_func_list[j].func->device) + && (g_hif_sdio_clt_drv_list[clt_index].func_info->func_num == + g_hif_sdio_probed_func_list[j].func->num)) { + g_hif_sdio_probed_func_list[j].clt_idx = clt_index; + /* probed spin unlock */ + spin_unlock_bh(&g_hif_sdio_lock_info.probed_list_lock); + if (g_hif_sdio_probed_func_list[j].func->num != 1 + || (g_hif_sdio_probed_func_list[j].on_by_wmt == MTK_WCN_BOOL_TRUE + && g_hif_sdio_probed_func_list[j].func->num == 1)) { + /* use worker thread to perform the client's .hif_clt_probe() */ + clt_probe_worker_info = + vmalloc(sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO)); + if (clt_probe_worker_info) { + INIT_WORK(&clt_probe_worker_info->probe_work, + hif_sdio_clt_probe_worker); + clt_probe_worker_info->registinfo_p = + &g_hif_sdio_clt_drv_list[clt_index]; + clt_probe_worker_info->probe_idx = j; + schedule_work(&clt_probe_worker_info->probe_work); + } + /* 4 <5.1> remember to do claim_irq for the */ + /* func if it's irq had been released. */ + if (!(g_hif_sdio_probed_func_list[j].func->irq_handler)) { + sdio_claim_host(g_hif_sdio_probed_func_list[j].func); + ret = + sdio_claim_irq(g_hif_sdio_probed_func_list[j].func, + hif_sdio_irq); + mtk_wcn_hif_sdio_irq_flag_set(1); + sdio_release_host(g_hif_sdio_probed_func_list[j].func); + HIF_SDIO_INFO_FUNC + ("sdio_claim_irq for func(0x%p) j(%d) v(0x%x) d(0x%x) ok\n", + g_hif_sdio_probed_func_list[j].func, j, + g_hif_sdio_probed_func_list[j].func->vendor, + g_hif_sdio_probed_func_list[j].func->device); + } + /* 4 <5.2> Reset the block size of the function provided by client */ + HIF_SDIO_INFO_FUNC("Reset sdio block size: %d!\n", + g_hif_sdio_clt_drv_list[clt_index]. + func_info->blk_sz); + sdio_claim_host(g_hif_sdio_probed_func_list[j].func); + ret = sdio_set_block_size(g_hif_sdio_probed_func_list[j].func, + g_hif_sdio_clt_drv_list + [clt_index].func_info->blk_sz); + sdio_release_host(g_hif_sdio_probed_func_list[j].func); + } + } else { + /* probed spin unlock */ + spin_unlock_bh(&g_hif_sdio_lock_info.probed_list_lock); + } + } + HIF_SDIO_DBG_FUNC + ("map g_hif_sdio_clt_drv_list to g_hif_sdio_probed_func_list done!\n"); + } + ret = HIF_SDIO_ERR_SUCCESS; + gRefCount++; + +out: + /* 4 <last> error handling */ + + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_client_reg() */ +EXPORT_SYMBOL(mtk_wcn_hif_sdio_client_reg); + +/*! + * \brief MTK hif sdio client un-registration function + * + * Client uses this function to un-register itself + * + * \param pinfo a pointer of client's information + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_client_unreg(const MTK_WCN_HIF_SDIO_CLTINFO *pinfo) +{ + INT32 ret = -HIF_SDIO_ERR_FAIL; + INT32 clt_list_index = 0; + UINT32 i = 0; + UINT32 j = 0; + + HIF_SDIO_INFO_FUNC("start!\n"); + + /* 4 <1> check if input pointer is valid */ + HIF_SDIO_ASSERT(pinfo); + + /* 4 <2> check if input parameters are all supported and valid */ + for (i = 0; i < pinfo->func_tbl_size; i++) { + ret = + hif_sdio_check_supported_sdio_id(pinfo->func_tbl[i].manf_id, + pinfo->func_tbl[i].card_id); + if (ret) { + HIF_SDIO_WARN_FUNC + ("vendor id(0x%x) and device id(0x%x) of sdio_func are not supported in mtk_sdio_id_tbl!\n", + pinfo->func_tbl[i].manf_id, pinfo->func_tbl[i].card_id); + goto out; + } + } + + /* 4 <3> check if the specific {manf id, card id, function number} tuple is already resigstered */ + /* 4 and find the corresponding client ctx and call client's .hif_clt_remove() in THIS context */ + for (i = 0; i < pinfo->func_tbl_size; i++) { + clt_list_index = + hif_sdio_find_clt_list_index(pinfo->func_tbl[i].manf_id, + pinfo->func_tbl[i].card_id, + pinfo->func_tbl[i].func_num); + if (clt_list_index < 0) { + HIF_SDIO_WARN_FUNC("vendor id(0x%x),", pinfo->func_tbl[i].manf_id); + HIF_SDIO_WARN_FUNC(" device id(0x%x),", pinfo->func_tbl[i].card_id); + HIF_SDIO_WARN_FUNC(" and fun_num(%d)", pinfo->func_tbl[i].func_num); + HIF_SDIO_WARN_FUNC(" client info is not in the client's registed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + /* 4 <4> mark the specified {manf id, card id, function number} tuple as */ + /* 4 un-registered and invalidate client's context */ + hif_sdio_init_clt_list(clt_list_index); + + /* un-map g_hif_sdio_clt_drv_list index in g_hif_sdio_probed_func_list */ + for (j = 0; j < CFG_CLIENT_COUNT; j++) { + if (g_hif_sdio_probed_func_list[j].clt_idx == clt_list_index) + g_hif_sdio_probed_func_list[j].clt_idx = -1; + } + } + gRefCount--; + + ret = HIF_SDIO_ERR_SUCCESS; +out: + HIF_SDIO_INFO_FUNC("end (gRefCount=%d) !\n", gRefCount); + return ret; +} /* end of mtk_wcn_hif_sdio_client_unreg() */ +EXPORT_SYMBOL(mtk_wcn_hif_sdio_client_unreg); + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_readb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, PUINT8 pvb) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func *func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + INT32 probe_index = -1; + struct sdio_func *func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_ASSERT(pvb); + + /* 4 <1> check if ctx is valid, registered, and probed */ +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx); + goto out; + } + if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */ + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } else { + if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */ + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + + /* 4 <2> */ + osal_ftrace_print("%s|S\n", __func__); + sdio_claim_host(func); + *pvb = sdio_readb(func, offset, &ret); + sdio_release_host(func); + osal_ftrace_print("%s|E\n", __func__); + + /* 4 <3> check result code and return proper error code */ + +out: + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_client_unreg() */ +EXPORT_SYMBOL(mtk_wcn_hif_sdio_readb); + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_writeb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, UINT8 vb) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func *func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + INT32 probe_index = -1; + struct sdio_func *func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + + /* 4 <1> check if ctx is valid, registered, and probed */ +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx); + goto out; + } + if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */ + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } else { + if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */ + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + + /* 4 <1.1> check if input parameters are valid */ + + /* 4 <2> */ + wmt_tra_sdio_update(); + osal_ftrace_print("%s|S\n", __func__); + sdio_claim_host(func); + sdio_writeb(func, vb, offset, &ret); + sdio_release_host(func); + osal_ftrace_print("%s|E\n", __func__); + + /* 4 <3> check result code and return proper error code */ + +out: + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_client_unreg() */ +EXPORT_SYMBOL(mtk_wcn_hif_sdio_writeb); + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_readl(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, PUINT32 pvl) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func *func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + INT32 probe_index = -1; + struct sdio_func *func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_ASSERT(pvl); + + /* 4 <1> check if ctx is valid, registered, and probed */ +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx); + goto out; + } + if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */ + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } else { + if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */ + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + /* 4 <1.1> check if input parameters are valid */ + + /* 4 <2> */ + osal_ftrace_print("%s|S\n", __func__); + sdio_claim_host(func); + *pvl = sdio_readl(func, offset, &ret); + sdio_release_host(func); + osal_ftrace_print("%s|E\n", __func__); + + /* 4 <3> check result code and return proper error code */ + +out: + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_client_unreg() */ +EXPORT_SYMBOL(mtk_wcn_hif_sdio_readl); + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_writel(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, UINT32 vl) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func *func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + INT32 probe_index = -1; + struct sdio_func *func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + + /* 4 <1> check if ctx is valid, registered, and probed */ +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx); + goto out; + } + if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */ + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } else { + if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */ + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + /* 4 <1.1> check if input parameters are valid */ + + /* 4 <2> */ + wmt_tra_sdio_update(); + osal_ftrace_print("%s|S\n", __func__); + sdio_claim_host(func); + sdio_writel(func, vl, offset, &ret); + sdio_release_host(func); + osal_ftrace_print("%s|E\n", __func__); + + /* 4 <3> check result code and return proper error code */ + +out: + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_client_unreg() */ +EXPORT_SYMBOL(mtk_wcn_hif_sdio_writel); + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_read_buf(MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, PUINT32 pbuf, UINT32 len) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func *func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + INT32 probe_index = -1; + struct sdio_func *func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_ASSERT(pbuf); + + /* 4 <1> check if ctx is valid, registered, and probed */ +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx); + goto out; + } + if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */ + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } else { + if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */ + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + /* 4 <1.1> check if input parameters are valid */ + + /* 4 <2> */ + osal_ftrace_print("%s|S|L|%d\n", __func__, len); + sdio_claim_host(func); + ret = sdio_readsb(func, pbuf, offset, len); + sdio_release_host(func); + osal_ftrace_print("%s|E|L|%d\n", __func__, len); + + /* 4 <3> check result code and return proper error code */ + +out: + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_read_buf() */ +EXPORT_SYMBOL(mtk_wcn_hif_sdio_read_buf); + + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_write_buf(MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, PUINT32 pbuf, UINT32 len) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func *func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + INT32 probe_index = -1; + struct sdio_func *func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_ASSERT(pbuf); + + /* 4 <1> check if ctx is valid, registered, and probed */ +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx); + goto out; + } + if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */ + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } else { + if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */ + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + /* 4 <1.1> check if input parameters are valid */ + + /* 4 <2> */ + wmt_tra_sdio_update(); + osal_ftrace_print("%s|S|L|%d\n", __func__, len); + sdio_claim_host(func); + ret = sdio_writesb(func, offset, pbuf, len); + sdio_release_host(func); + osal_ftrace_print("%s|E|L|%d\n", __func__, len); + + /* 4 <3> check result code and return proper error code */ + +out: + HIF_SDIO_DBG_FUNC("ret(%d) end!\n", ret); + + return ret; +} /* end of mtk_wcn_hif_sdio_write_buf() */ +EXPORT_SYMBOL(mtk_wcn_hif_sdio_write_buf); + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_abort(MTK_WCN_HIF_SDIO_CLTCTX ctx) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func *func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + INT32 probe_index = -1; + struct sdio_func *func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_ASSERT(pbuf); + + /* 4 <1> check if ctx is valid, registered, and probed */ +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx); + goto out; + } + if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */ + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } else { + if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */ + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + /* 4 <1.1> check if input parameters are valid */ + + /* 4 <2> */ + osal_ftrace_print("%s|S|L|\n", __func__); + sdio_claim_host(func); + /* SDIO Control must be switched to function 2 before the abort command send + * firmware can receive function 2 abort interrupt + * read CTMDPCR1(0xBC) to switch function 2 + */ + sdio_readl(func, 0xBC, &ret); + ret = sdio_writeb_readb(func, func->num, SDIO_CCCR_ABORT, NULL); //mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_ABORT, func->num, NULL); + sdio_release_host(func); + osal_ftrace_print("%s|E|L|\n", __func__); + + /* 4 <3> check result code and return proper error code */ + +out: + HIF_SDIO_DBG_FUNC("ret(%d) end!\n", ret); + + return ret; +} /* end of mtk_wcn_hif_sdio_write_buf() */ +EXPORT_SYMBOL(mtk_wcn_hif_sdio_abort); + +/*! + * \brief store client driver's private data function. + * + * + * \param clent's MTK_WCN_HIF_SDIO_CLTCTX. + * + * \retval none. + */ +VOID mtk_wcn_hif_sdio_set_drvdata(MTK_WCN_HIF_SDIO_CLTCTX ctx, PVOID private_data_p) +{ + UINT8 probed_idx = CLTCTX_IDX(ctx); + + if (unlikely(!CLTCTX_UIDX_VALID(probed_idx))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid idx in ctx(0x%x), private_data_p not stored!\n", ctx); + } else { + /* store client driver's private data to dev driver */ + g_hif_sdio_probed_func_list[probed_idx].private_data_p = private_data_p; + HIF_SDIO_DBG_FUNC("private_data_p(0x%p) for ctx(0x%x) probed idx(%d) stored!\n", + private_data_p, ctx, probed_idx); + } +} +EXPORT_SYMBOL(mtk_wcn_hif_sdio_set_drvdata); + +/*! + * \brief get client driver's private data function. + * + * + * \param clent's MTK_WCN_HIF_SDIO_CLTCTX. + * + * \retval private data pointer. + */ +PVOID mtk_wcn_hif_sdio_get_drvdata(MTK_WCN_HIF_SDIO_CLTCTX ctx) +{ + UINT8 probed_idx = CLTCTX_IDX(ctx); + + /* get client driver's private data to dev driver */ + if (likely(CLTCTX_UIDX_VALID(probed_idx))) + return g_hif_sdio_probed_func_list[probed_idx].private_data_p; + /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid idx in ctx(0x%x), return null!\n", ctx); + return NULL; +} +EXPORT_SYMBOL(mtk_wcn_hif_sdio_get_drvdata); + +/*! + * \brief control stp/wifi on/off from wmt. + * + * + * \param (1)control function type, (2)on/off control. + * + * \retval (1)control results ,(2)unknown type: -5. + * \retval 0:success, -11:not probed, -12:already on, -13:not registered, other errors. + */ +INT32 mtk_wcn_hif_sdio_wmt_control(WMT_SDIO_FUNC_TYPE func_type, MTK_WCN_BOOL is_on) +{ + /* TODO:[FixMe][George]: return value of this function shall distinguish */ + /* 1) not probed by mmc_core yet or */ + /* 2) probed by mmc_core but init fail... */ + switch (func_type) { + case WMT_SDIO_FUNC_STP: + if (is_on == MTK_WCN_BOOL_TRUE) + return hif_sdio_stp_on(); + else + return hif_sdio_stp_off(); + break; + + case WMT_SDIO_FUNC_WIFI: + if (is_on == MTK_WCN_BOOL_TRUE) + return hif_sdio_wifi_on(); + else + return hif_sdio_wifi_off(); + break; + + default: + HIF_SDIO_WARN_FUNC("unknown type(%d)\n", func_type); + return HIF_SDIO_ERR_INVALID_PARAM; + } +} +EXPORT_SYMBOL(mtk_wcn_hif_sdio_wmt_control); + +/*! + * \brief ??? + * + * \detail ??? + * + * \param ctx a context provided by client driver + * \param struct device ** ??? + * + * \retval none + */ +VOID mtk_wcn_hif_sdio_get_dev(MTK_WCN_HIF_SDIO_CLTCTX ctx, struct device **dev) +{ +#if HIF_SDIO_UPDATE + struct sdio_func *func; +#else + UINT8 probe_index = CLTCTX_IDX(ctx); +#endif + +#if HIF_SDIO_UPDATE + *dev = NULL; /* ensure we does not return any invalid value back. */ + func = hif_sdio_ctx_to_func(ctx); + if (unlikely(!func)) { + HIF_SDIO_WARN_FUNC("no valid *func with ctx(0x%x)\n", ctx); + return; + } + *dev = &(func->dev); + HIF_SDIO_DBG_FUNC("return *dev(0x%p) for ctx(0x%x)\n", *dev, ctx); +#else + if (probe_index < 0) { + HIF_SDIO_WARN_FUNC("func not probed, probe_index = %d", probe_index); + return; + } + *dev = &g_hif_sdio_probed_func_list[probe_index].func->dev; +#endif +} +EXPORT_SYMBOL(mtk_wcn_hif_sdio_get_dev); + +/*! + * \brief client's probe() function. + * + * + * \param work queue structure. + * + * \retval none. + */ +static _osal_inline_ INT32 hif_sdio_clt_probe_func(MTK_WCN_HIF_SDIO_REGISTINFO *registinfo_p, INT8 probe_idx) +{ + UINT16 card_id = 0; + UINT16 func_num = 0; + UINT16 blk_sz = 0; + INT32 ret; + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_ASSERT(registinfo_p); + if (!registinfo_p) { + HIF_SDIO_WARN_FUNC("registinfo_p NULL!!!\n"); + return -1; + } + + /* special case handling: if the clt's unregister is called during probe procedures */ + if (!registinfo_p->func_info || !registinfo_p->sdio_cltinfo) { + HIF_SDIO_WARN_FUNC("client's registinfo_p is cleared !!!\n"); + return -1; + } + + card_id = registinfo_p->func_info->card_id; + func_num = registinfo_p->func_info->func_num; + blk_sz = registinfo_p->func_info->blk_sz; + ret = + registinfo_p->sdio_cltinfo->hif_clt_probe(CLTCTX(card_id, func_num, blk_sz, probe_idx), + registinfo_p->func_info); + + HIF_SDIO_DBG_FUNC + ("clt_probe_func card_id(%x) func_num(%x) blk_sz(%d) prob_idx(%x) ret(%d) %s\n", + card_id, func_num, blk_sz, probe_idx, ret, (ret) ? "fail" : "ok"); + + return ret; +} + +/*! + * \brief client's probe() worker. + * + * + * \param work queue structure. + * + * \retval none. + */ +static VOID hif_sdio_clt_probe_worker(struct work_struct *work) +{ + MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_worker_info_p = 0; + UINT16 card_id = 0; + UINT16 func_num = 0; + UINT16 blk_sz = 0; + INT8 prob_idx = 0; + + HIF_SDIO_DBG_FUNC("start!\n"); + + HIF_SDIO_ASSERT(work); + + /* get client's information */ + clt_worker_info_p = container_of(work, MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO, probe_work); + HIF_SDIO_ASSERT(clt_worker_info_p); + HIF_SDIO_ASSERT(clt_worker_info_p->registinfo_p); + + /* special case handling: if the clt's unregister is called during probe procedures */ + if ((clt_worker_info_p->registinfo_p->func_info == 0) + || (clt_worker_info_p->registinfo_p->sdio_cltinfo == 0)) { + HIF_SDIO_WARN_FUNC("client's registinfo_p is cleared !!!\n"); + vfree(clt_worker_info_p); + return; + } + + card_id = clt_worker_info_p->registinfo_p->func_info->card_id; + func_num = clt_worker_info_p->registinfo_p->func_info->func_num; + blk_sz = clt_worker_info_p->registinfo_p->func_info->blk_sz; + prob_idx = clt_worker_info_p->probe_idx; + + /* Execute client's probe() func */ + clt_worker_info_p->registinfo_p-> + sdio_cltinfo->hif_clt_probe(CLTCTX(card_id, func_num, blk_sz, prob_idx), + clt_worker_info_p->registinfo_p->func_info); + + vfree(clt_worker_info_p); + + HIF_SDIO_DBG_FUNC("card_id(0x%x) func_num(0x%x) blk_sz(0x%x) prob_idx(0x%x)\n", card_id, + func_num, blk_sz, prob_idx); + HIF_SDIO_DBG_FUNC("end!\n"); +} + +/*! + * \brief client's probe() worker. + * + * + * \param work queue structure. + * + * \retval none. + */ +static _osal_inline_ VOID hif_sdio_dump_probe_list(VOID) +{ + INT32 i; + + HIF_SDIO_DBG_FUNC("== DUMP probed list start ==\n"); + + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + if (g_hif_sdio_probed_func_list[i].func) { + HIF_SDIO_DBG_FUNC("index(%d) func(0x%p) clt_idx(%d)\n", + i, g_hif_sdio_probed_func_list[i].func, + g_hif_sdio_probed_func_list[i].clt_idx); + + HIF_SDIO_DBG_FUNC("vendor(0x%x) device(0x%x) num(0x%x) state(%d)\n", + g_hif_sdio_probed_func_list[i].func->vendor, + g_hif_sdio_probed_func_list[i].func->device, + g_hif_sdio_probed_func_list[i].func->num, + g_hif_sdio_probed_func_list[i].on_by_wmt); + + } + } + + HIF_SDIO_DBG_FUNC("== DUMP probed list end ==\n"); +} + + +/*! + * \brief Initialize g_hif_sdio_probed_func_list + * + * + * \param index of g_hif_sdio_probed_func_list. + * + * \retval none. + */ +static _osal_inline_ VOID hif_sdio_init_probed_list(INT32 index) +{ + if ((index >= 0) && (index < CFG_CLIENT_COUNT)) { + /* probed spin lock */ + spin_lock_bh(&g_hif_sdio_lock_info.probed_list_lock); + g_hif_sdio_probed_func_list[index].func = 0; + g_hif_sdio_probed_func_list[index].clt_idx = -1; + g_hif_sdio_probed_func_list[index].private_data_p = 0; + g_hif_sdio_probed_func_list[index].on_by_wmt = MTK_WCN_BOOL_FALSE; + /* probed spin unlock */ + spin_unlock_bh(&g_hif_sdio_lock_info.probed_list_lock); + } else + HIF_SDIO_ERR_FUNC("index is out of g_hif_sdio_probed_func_list[] boundary!\n"); +} + + +/*! + * \brief Initialize g_hif_sdio_clt_drv_list + * + * + * \param index of g_hif_sdio_clt_drv_list. + * + * \retval none. + */ +static _osal_inline_ VOID hif_sdio_init_clt_list(INT32 index) +{ + /* client list spin lock */ + spin_lock_bh(&g_hif_sdio_lock_info.clt_list_lock); + if ((index >= 0) && (index < CFG_CLIENT_COUNT)) { + g_hif_sdio_clt_drv_list[index].sdio_cltinfo = 0; + g_hif_sdio_clt_drv_list[index].func_info = 0; + } else + HIF_SDIO_ERR_FUNC("index is out of g_hif_sdio_clt_drv_list[] boundary!\n"); + /* client list spin unlock */ + spin_unlock_bh(&g_hif_sdio_lock_info.clt_list_lock); +} + + +/*! + * \brief find matched g_hif_sdio_probed_func_list index from sdio function handler + * + * + * \param sdio function handler + * + * \retval -1 index not found + * \retval >= 0 return found index + */ +static _osal_inline_ INT32 hif_sdio_find_probed_list_index_by_func(struct sdio_func *func) +{ + INT32 i = 0; + + HIF_SDIO_ASSERT(func); + + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + if (g_hif_sdio_probed_func_list[i].func == func) + return i; + } + + return -1; +} + +/*! + * \brief find matched g_hif_sdio_probed_func_list from vendor_id, device_id, and function number + * + * + * \param vendor id, device id, and function number of the sdio card. + * + * \retval -1 index not found + * \retval >= 0 return found index + */ +static _osal_inline_ INT32 hif_sdio_find_probed_list_index_by_id_func(UINT16 vendor, UINT16 device, + UINT16 func_num) +{ + INT32 i; + + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + if (g_hif_sdio_probed_func_list[i].func) { + HIF_SDIO_DBG_FUNC("probed entry: vendor(0x%x) device(0x%x) num(0x%x)\n", + g_hif_sdio_probed_func_list[i].func->vendor, + g_hif_sdio_probed_func_list[i].func->device, + g_hif_sdio_probed_func_list[i].func->num); + } + } + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + if (!g_hif_sdio_probed_func_list[i].func) { + continue; + } else if ((g_hif_sdio_probed_func_list[i].func->vendor == vendor) && + (g_hif_sdio_probed_func_list[i].func->device == device) && + (g_hif_sdio_probed_func_list[i].func->num == func_num)) { + return i; + } + } + + if (i == CFG_CLIENT_COUNT) { + /* + * pr_warn(DRV_NAME "Cannot find vendor:0x%x, device:0x%x, func_num:0x%x, i=%d\n", + * vendor, device, func_num, i); + */ + /* client func has not been probed */ + return -1; + } + return -1; +} + +/*! + * \brief find matched g_hif_sdio_clt_drv_list index + * + * find the matched g_hif_sdio_clt_drv_list index from card_id and function number. + * + * \param vendor id, device id, and function number of the sdio card + * + * \retval -1 index not found + * \retval >= 0 return found index + */ +static _osal_inline_ INT32 hif_sdio_find_clt_list_index(UINT16 vendor, UINT16 device, UINT16 func_num) +{ + INT32 i = 0; + + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + if (g_hif_sdio_clt_drv_list[i].func_info != 0) { + if ((g_hif_sdio_clt_drv_list[i].func_info->manf_id == vendor) && + (g_hif_sdio_clt_drv_list[i].func_info->card_id == device) && + (g_hif_sdio_clt_drv_list[i].func_info->func_num == func_num)) { + return i; + } + } + } + + return -1; +} + + +/*! + * \brief check if the vendor, device ids are supported in mtk_sdio_id_tbl. + * + * + * \param vendor id and device id of the sdio card + * + * \retval (-HIF_SDIO_ERR_FAIL) vendor, device ids are not supported + * \retval HIF_SDIO_ERR_SUCCESS vendor, device ids are supported + */ +static _osal_inline_ INT32 hif_sdio_check_supported_sdio_id(UINT16 vendor, UINT16 device) +{ + INT32 i = 0; + + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + if ((mtk_sdio_id_tbl[i].vendor == vendor) && (mtk_sdio_id_tbl[i].device == device)) + return HIF_SDIO_ERR_SUCCESS; /* mtk_sdio_id is supported */ + } + return -HIF_SDIO_ERR_FAIL; /* mtk_sdio_id is not supported */ +} + + +/*! + * \brief check if the vendor, device ids are duplicated in g_hif_sdio_clt_drv_list. + * + * + * \param vendor id, device id, and function number of the sdio card + * + * \retval (-HIF_SDIO_ERR_DUPLICATED) vendor, device, func_num are duplicated + * \retval HIF_SDIO_ERR_SUCCESS vendor, device, func_num are not duplicated + */ +static _osal_inline_ INT32 hif_sdio_check_duplicate_sdio_id(UINT16 vendor, UINT16 device, UINT16 func_num) +{ + INT32 i = 0; + + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + if (g_hif_sdio_clt_drv_list[i].func_info != 0) { + if ((g_hif_sdio_clt_drv_list[i].func_info->manf_id == vendor) && + (g_hif_sdio_clt_drv_list[i].func_info->card_id == device) && + (g_hif_sdio_clt_drv_list[i].func_info->func_num == func_num)) { + return -HIF_SDIO_ERR_DUPLICATED; /* duplicated */ + } + } + } + return HIF_SDIO_ERR_SUCCESS; /* Not duplicated */ +} + + +/*! + * \brief Add the client info into g_hif_sdio_clt_drv_list. + * + * + * \param [output] client's index pointer. + * \param MTK_WCN_HIF_SDIO_CLTINFO of client's contex. + * + * \retval (-HIF_SDIO_ERR_FAIL) Add to clt_list successfully + * \retval HIF_SDIO_ERR_SUCCESS Add to clt_list failed (buffer is full) + */ +static _osal_inline_ INT32 hif_sdio_add_clt_list(PINT32 clt_index_p, + const MTK_WCN_HIF_SDIO_CLTINFO *pinfo, UINT32 tbl_index) +{ + INT32 i = 0; + + HIF_SDIO_ASSERT(clt_index_p); + HIF_SDIO_ASSERT(pinfo); + + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + /* client list spin lock */ + spin_lock_bh(&g_hif_sdio_lock_info.clt_list_lock); + if (g_hif_sdio_clt_drv_list[i].func_info == 0) { + g_hif_sdio_clt_drv_list[i].func_info = &(pinfo->func_tbl[tbl_index]); + g_hif_sdio_clt_drv_list[i].sdio_cltinfo = pinfo; + /* client list spin unlock */ + spin_unlock_bh(&g_hif_sdio_lock_info.clt_list_lock); + *clt_index_p = i; + return HIF_SDIO_ERR_SUCCESS; /* Add to client list successfully */ + } + /* client list spin unlock */ + spin_unlock_bh(&g_hif_sdio_lock_info.clt_list_lock); + } + return -HIF_SDIO_ERR_FAIL; /* Add to client list failed (buffer is full) */ +} + +#if HIF_SDIO_SUPPORT_SUSPEND +static INT32 hif_sdio_suspend(struct device *dev) +{ + struct sdio_func *func; + mmc_pm_flag_t flag; + INT32 ret; + + if (!dev) + return -EINVAL; + + func = dev_to_sdio_func(dev); + HIF_SDIO_DBG_FUNC("prepare for func(0x%p)\n", func); + flag = sdio_get_host_pm_caps(func); +#if HIF_SDIO_SUPPORT_WAKEUP + if (!(flag & MMC_PM_KEEP_POWER) || !(flag & MMC_PM_WAKE_SDIO_IRQ)) { + HIF_SDIO_WARN_FUNC + ("neither MMC_PM_KEEP_POWER or MMC_PM_WAKE_SDIO_IRQ is supported by host, return -ENOTSUPP\n"); + return -ENOTSUPP; + } + + /* set both */ + flag |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; +#else + if (!(flag & MMC_PM_KEEP_POWER)) { + HIF_SDIO_WARN_FUNC + ("neither MMC_PM_KEEP_POWER is supported by host, return -ENOTSUPP\n"); + return -ENOTSUPP; + } + flag |= MMC_PM_KEEP_POWER; +#endif + ret = sdio_set_host_pm_flags(func, flag); + if (ret) { + HIF_SDIO_INFO_FUNC + ("set MMC_PM_KEEP_POWER to host fail(%d)\n", ret); + return -EFAULT; + } +#if HIF_SDIO_SUPPORT_WAKEUP + sdio_claim_host(func); +#endif + HIF_SDIO_INFO_FUNC("set MMC_PM_KEEP_POWER ok\n"); + return 0; +} + +static INT32 hif_sdio_resume(struct device *dev) +{ +#if HIF_SDIO_SUPPORT_WAKEUP + struct sdio_func *func; +#endif + if (!dev) { + HIF_SDIO_WARN_FUNC("null dev!\n"); + return -EINVAL; + } +#if HIF_SDIO_SUPPORT_WAKEUP + func = dev_to_sdio_func(dev); + sdio_release_host(func); +#endif + HIF_SDIO_INFO_FUNC("do nothing\n"); + + return 0; +} +#endif + +/*! + * \brief hif_sdio probe function + * + * hif_sdio probe function called by mmc driver when any matched SDIO function + * is detected by it. + * + * \param func + * \param id + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +static INT32 hif_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + INT32 ret = 0; + INT32 i = 0; + MTK_WCN_HIF_SDIO_PROBEINFO *hif_sdio_probed_funcp = 0; + INT32 probe_index = -1; + INT32 idx; +#if 0 + INT32 clt_index = -1; + MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_ASSERT(func); +#if !(DELETE_HIF_SDIO_CHRDEV) + hif_sdio_match_chipid_by_dev_id(id); +#endif + /* 4 <0> display debug information */ + HIF_SDIO_INFO_FUNC("vendor(0x%x) device(0x%x) num(0x%x)\n", func->vendor, func->device, + func->num); + for (i = 0; i < func->card->num_info; i++) + HIF_SDIO_DBG_FUNC("card->info[%d]: %s\n", i, func->card->info[i]); + + /* 4 <1> Check if this is supported by us (mtk_sdio_id_tbl) */ + ret = hif_sdio_check_supported_sdio_id(func->vendor, func->device); + if (ret) { + HIF_SDIO_WARN_FUNC + ("vendor id and device id of sdio_func are not supported in mtk_sdio_id_tbl!\n"); + goto out; + } + /* 4 <2> Add this struct sdio_func *func to g_hif_sdio_probed_func_list */ + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + /* probed spin lock */ + spin_lock_bh(&g_hif_sdio_lock_info.probed_list_lock); + if (g_hif_sdio_probed_func_list[i].func == 0) { + hif_sdio_probed_funcp = &g_hif_sdio_probed_func_list[i]; + hif_sdio_probed_funcp->func = func; + hif_sdio_probed_funcp->clt_idx = + hif_sdio_find_clt_list_index(func->vendor, func->device, func->num); + hif_sdio_probed_funcp->on_by_wmt = MTK_WCN_BOOL_FALSE; + hif_sdio_probed_funcp->sdio_irq_enabled = MTK_WCN_BOOL_FALSE; + /* probed spin unlock */ + spin_unlock_bh(&g_hif_sdio_lock_info.probed_list_lock); + probe_index = i; + break; + } + /* probed spin unlock */ + spin_unlock_bh(&g_hif_sdio_lock_info.probed_list_lock); + } + if ((probe_index < 0) || (probe_index >= CFG_CLIENT_COUNT)) { + HIF_SDIO_ERR_FUNC("probe function list if full!\n"); + goto out; + } + /* 4 <3> Initialize this function */ + if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + /* client list spin lock */ + spin_lock_bh(&g_hif_sdio_lock_info.clt_list_lock); + if (g_hif_sdio_clt_drv_list[i].func_info == 0) { + /* client list spin unlock */ + spin_unlock_bh(&g_hif_sdio_lock_info.clt_list_lock); + continue; + } + HIF_SDIO_INFO_FUNC("manf_id:%x, card_id:%x, func_num:%d\n", + g_hif_sdio_clt_drv_list[i].func_info->manf_id, + g_hif_sdio_clt_drv_list[i].func_info->card_id, + g_hif_sdio_clt_drv_list[i].func_info->func_num); + if ((g_hif_sdio_clt_drv_list[i].func_info->manf_id == + g_hif_sdio_probed_func_list[probe_index].func->vendor) + && (g_hif_sdio_clt_drv_list[i].func_info->card_id == + g_hif_sdio_probed_func_list[probe_index].func->device) + && (g_hif_sdio_clt_drv_list[i].func_info->func_num == + g_hif_sdio_probed_func_list[probe_index].func->num)) { + g_hif_sdio_probed_func_list[probe_index].clt_idx = i; + /* client list spin unlock */ + spin_unlock_bh(&g_hif_sdio_lock_info.clt_list_lock); + break; + } + /* client list spin unlock */ + spin_unlock_bh(&g_hif_sdio_lock_info.clt_list_lock); + } + HIF_SDIO_INFO_FUNC("map to g_hif_sdio_clt_drv_list[] done: %d\n", + g_hif_sdio_probed_func_list[probe_index].clt_idx); + } + /* 4 <3.1> enable this function */ + sdio_claim_host(func); + ret = sdio_enable_func(func); + sdio_release_host(func); + if (ret) { + HIF_SDIO_ERR_FUNC("sdio_enable_func failed!\n"); + goto out; + } + + /* 4 <3.2> set block size according to the table storing function characteristics */ + if (hif_sdio_probed_funcp == 0) { + HIF_SDIO_ERR_FUNC("hif_sdio_probed_funcp is null!\n"); + goto out; + } + if (hif_sdio_probed_funcp->clt_idx >= 0 && + hif_sdio_probed_funcp->clt_idx < CFG_CLIENT_COUNT) { + /* The clt contex has been registed */ + sdio_claim_host(func); + idx = hif_sdio_probed_funcp->clt_idx; + ret = sdio_set_block_size(func, g_hif_sdio_clt_drv_list[idx].func_info->blk_sz); + sdio_release_host(func); + } else { /* The clt contex has not been registed */ + + sdio_claim_host(func); + ret = sdio_set_block_size(func, HIF_DEFAULT_BLK_SIZE); + sdio_release_host(func); + } + if (ret) { + HIF_SDIO_ERR_FUNC("set sdio block size failed!\n"); + goto out; + } + + HIF_SDIO_DBG_FUNC("cur_blksize(%d) max(%d), host max blk_size(%d) blk_count(%d)\n", + func->cur_blksize, func->max_blksize, + func->card->host->max_blk_size, func->card->host->max_blk_count); + + + hif_sdio_dump_probe_list(); + +out: + /* 4 <last> error handling */ + return ret; +} + + +/*! + * \brief hif_sdio remove function + * + * hif_sdio probe function called by mmc driver when the probed func should be + * removed. + * + * \param func + * + */ +static VOID hif_sdio_remove(struct sdio_func *func) +{ + INT32 probed_list_index = 0; +#if 0 + INT32 registed_list_index = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_ASSERT(func); + + /* 4 <1> check input parameter is valid and has been probed previously */ + if (func == NULL) { + HIF_SDIO_ERR_FUNC("func null(%p)\n", func); + return; + } + /* 4 <2> if this function has been initialized by any client driver, */ + /* 4 call client's .hif_clt_remove() call back in THIS context. */ + probed_list_index = hif_sdio_find_probed_list_index_by_func(func); + if (probed_list_index < 0) { + HIF_SDIO_WARN_FUNC + ("sdio function pointer is not in g_hif_sdio_probed_func_list!\n"); + return; + } +#if 0 + registed_list_index = g_hif_sdio_probed_func_list[probed_list_index].clt_idx; + if (registed_list_index >= 0) { + g_hif_sdio_clt_drv_list[registed_list_index].sdio_cltinfo->hif_clt_remove(CLTCTX + (func-> + device, + func-> + num, + func-> + cur_blksize, + probed_list_index)); + } +#endif + + /* 4 <3> mark this function as de-initialized and invalidate client's context */ + hif_sdio_init_probed_list(probed_list_index); + +#if 0 + /* 4 <4> release irq for this function */ + sdio_claim_host(func); + sdio_release_irq(func); + sdio_release_host(func); +#endif + + /* 4 <5> disable this function */ + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + + /* 4 <6> mark this function as removed */ + + HIF_SDIO_DBG_FUNC("sdio func(0x%p) is removed successfully!\n", func); +} + +/*! + * \brief hif_sdio interrupt handler + * + * detailed descriptions + * + * \param ctx client's context variable + * + */ +static VOID hif_sdio_irq(struct sdio_func *func) +{ + INT32 probed_list_index = -1; + INT32 registed_list_index = -1; + INT32 ret; + + HIF_SDIO_DBG_FUNC("start!\n"); + + osal_ftrace_print("%s|S\n", __func__); + /* 4 <1> check if func is valid */ + HIF_SDIO_ASSERT(func); + + /* 4 <2> if func has valid corresponding hif_sdio client's context, mark it */ + /* 4 host-locked, use it to call client's .hif_clt_irq() callback function in */ + /* 4 THIS context. */ + probed_list_index = hif_sdio_find_probed_list_index_by_func(func); + if ((probed_list_index < 0) || (probed_list_index >= CFG_CLIENT_COUNT)) { + HIF_SDIO_ERR_FUNC("probed_list_index not found!\n"); + return; + } + /* [George] added for sdio irq sync and mmc single_irq workaround. It's set + * enabled later by client driver call mtk_wcn_hif_sdio_enable_irq() + */ + /* skip smp_rmb() here */ + if (g_hif_sdio_probed_func_list[probed_list_index].sdio_irq_enabled == MTK_WCN_BOOL_FALSE) { + HIF_SDIO_WARN_FUNC("func(0x%p),probed_idx(%d) sdio irq not enabled yet\n", + func, probed_list_index); + return; + } + + registed_list_index = g_hif_sdio_probed_func_list[probed_list_index].clt_idx; +/* g_hif_sdio_probed_func_list[probed_list_index].interrupted = MTK_WCN_BOOL_TRUE; */ + if ((registed_list_index >= 0) + && (registed_list_index < CFG_CLIENT_COUNT)) { + HIF_SDIO_DBG_FUNC("[%d]SDIO IRQ (func:0x%p) v(0x%x) d(0x%x) n(0x%x)\n", + probed_list_index, func, func->vendor, func->device, func->num); + + g_hif_sdio_clt_drv_list[registed_list_index].sdio_cltinfo->hif_clt_irq(CLTCTX + (func-> + device, + func->num, + func-> + cur_blksize, + probed_list_index)); + } else { + /* 4 <3> if func has no VALID hif_sdio client's context, release irq for this */ + /* 4 func and mark it in g_hif_sdio_probed_func_list (remember: donnot claim host in irq contex). */ + HIF_SDIO_WARN_FUNC("release irq (func:0x%p) v(0x%x) d(0x%x) n(0x%x)\n", + func, func->vendor, func->device, func->num); + mtk_wcn_hif_sdio_irq_flag_set(0); + ret = sdio_release_irq(func); + if (ret) + HIF_SDIO_WARN_FUNC("sdio_release_irq() fail(%d)\n", ret); + } + osal_ftrace_print("%s|E\n", __func__); +} + +/*! + * \brief hif_sdio init function + * + * detailed descriptions + * + * \retval + */ +static INT32 hif_sdio_init(VOID) +{ + INT32 ret = 0; + INT32 i = 0; + + HIF_SDIO_INFO_FUNC("start!\n"); + + /* 4 <1> init all private variables */ + /* init reference count to 0 */ + gRefCount = 0; + + atomic_set(&hif_sdio_irq_enable_flag, 0); + /* init spin lock information */ + spin_lock_init(&g_hif_sdio_lock_info.probed_list_lock); + spin_lock_init(&g_hif_sdio_lock_info.clt_list_lock); + + /* init probed function list and g_hif_sdio_clt_drv_list */ + for (i = 0; i < CFG_CLIENT_COUNT; i++) { + hif_sdio_init_probed_list(i); + hif_sdio_init_clt_list(i); + } + + /* 4 <2> register to mmc driver */ + ret = sdio_register_driver(&mtk_sdio_client_drv); + if (ret != 0) + HIF_SDIO_INFO_FUNC("sdio_register_driver() fail, ret=%d\n", ret); + +#if !(DELETE_HIF_SDIO_CHRDEV) + /* 4 <3> create thread for query chip id and device node for launcher to access */ + if (hifsdiod_start() == 0) + hif_sdio_create_dev_node(); +#endif + hif_sdio_deep_sleep_info_init(); + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} + +/*! + * \brief hif_sdio init function + * + * detailed descriptions + * + * \retval + */ +static VOID hif_sdio_exit(VOID) +{ + HIF_SDIO_INFO_FUNC("start!\n"); + +#if !(DELETE_HIF_SDIO_CHRDEV) + hif_sdio_remove_dev_node(); + hifsdiod_stop(); +#endif + + /* 4 <0> if client driver is not removed yet, we shall NOT be called... */ + + /* 4 <1> check reference count */ + if (gRefCount != 0) + HIF_SDIO_WARN_FUNC("gRefCount=%d !!!\n", gRefCount); + /* 4 <2> check if there is any hif_sdio-registered clients. There should be */ + /* 4 no registered client... */ + + /* 4 <3> Reregister with mmc driver. Our remove handler hif_sdio_remove() */ + /* 4 will be called later by mmc_core. Clean up driver resources there. */ + sdio_unregister_driver(&mtk_sdio_client_drv); + atomic_set(&hif_sdio_irq_enable_flag, 0); + HIF_SDIO_DBG_FUNC("end!\n"); +} /* end of exitWlan() */ + +/*! + * \brief stp on by wmt (probe client driver). + * + * + * \param none. + * + * \retval 0:success, -11:not probed, -12:already on, -13:not registered, other errors. + */ +static _osal_inline_ INT32 hif_sdio_stp_on(VOID) +{ +#if 0 + MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0; +#endif + INT32 clt_index = -1; + INT32 probe_index = -1; + INT32 ret = -1; + INT32 ret2 = -1; + struct sdio_func *func; + UINT32 chip_id = 0; + UINT16 func_num = 0; + + const MTK_WCN_HIF_SDIO_FUNCINFO *func_info = NULL; + + HIF_SDIO_DBG_FUNC("hif_sdio_stp_on, start!\n"); + + /* 4 <1> If stp client drv has not been probed, return error code */ + /* MT6620 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020B, 1); + if (probe_index >= 0) + goto stp_on_exist; + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 1); + if (probe_index >= 0) + goto stp_on_exist; + + /* MT6628 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6628, 2); + if (probe_index >= 0) + goto stp_on_exist; + /* MT6630 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6630, 2); + if (probe_index >= 0) { + chip_id = 0x6630; + func_num = 2; + goto stp_on_exist; + } + /* MT6632 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6632, 2); + if (probe_index >= 0) { + chip_id = 0x6632; + func_num = 2; + goto stp_on_exist; + } + /* MT6619 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6619, 1); + if (probe_index >= 0) + goto stp_on_exist; + + /* MT6618 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018B, 1); + if (probe_index >= 0) + goto stp_on_exist; + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 1); + if (probe_index >= 0) + goto stp_on_exist; + else { + /* 4 <2> If stp client drv has not been probed, return error code */ + /* client func has not been probed */ + HIF_SDIO_INFO_FUNC("no supported func probed\n"); + return HIF_SDIO_ERR_NOT_PROBED; + } + +stp_on_exist: + /* 4 <3> If stp client drv has been on by wmt, return error code */ + if (g_hif_sdio_probed_func_list[probe_index].on_by_wmt != MTK_WCN_BOOL_FALSE) { + HIF_SDIO_INFO_FUNC("already on...\n"); + return HIF_SDIO_ERR_ALRDY_ON; + } + g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_TRUE; + + clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx; + if (clt_index >= 0) { /* the function has been registered */ + g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE; + /* 4 <4> claim irq for this function */ + func = g_hif_sdio_probed_func_list[probe_index].func; + if (unlikely(!(func) || !(func->card) || !(func->card->host) + || mmc_card_removed(func->card))) { + HIF_SDIO_ERR_FUNC("sdio host is missing\n"); + return HIF_SDIO_ERR_NOT_PROBED; + } + sdio_claim_host(func); + ret = sdio_claim_irq(func, hif_sdio_irq); + mtk_wcn_hif_sdio_irq_flag_set(1); + sdio_release_host(func); + if (ret) { + HIF_SDIO_WARN_FUNC("sdio_claim_irq() for stp fail(%d)\n", ret); + return ret; + } + HIF_SDIO_DBG_FUNC("sdio_claim_irq() for stp ok\n"); + + /* 4 <5> If this struct sdio_func *func is supported by any driver in */ + /* 4 g_hif_sdio_clt_drv_list, schedule another task to call client's .hif_clt_probe() */ + /* TODO: [FixMe][George] WHY probe worker is removed??? */ +#if 1 + /* Call client's .hif_clt_probe() */ + ret = hif_sdio_clt_probe_func(&g_hif_sdio_clt_drv_list[clt_index], probe_index); + if (ret) { + HIF_SDIO_WARN_FUNC("clt_probe_func() for stp fail(%d) release irq\n", ret); + sdio_claim_host(func); + mtk_wcn_hif_sdio_irq_flag_set(0); + ret2 = sdio_release_irq(func); + sdio_release_host(func); + if (ret2) + HIF_SDIO_WARN_FUNC("sdio_release_irq() for stp fail(%d)\n", ret2); + + g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE; + return ret; + } + g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_TRUE; + + /*set deep sleep information to global data struct */ + func_info = g_hif_sdio_clt_drv_list[clt_index].func_info; + hif_sdio_deep_sleep_info_set_act(chip_id, func_num, + CLTCTX(func_info->card_id, func_info->func_num, + func_info->blk_sz, probe_index), 1); + + + HIF_SDIO_DBG_FUNC("hif_sdio_stp_on, ok!\n"); + + return 0; +#else + /* use worker thread to perform the client's .hif_clt_probe() */ + clt_probe_worker_info = vmalloc(sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO)); + INIT_WORK(&clt_probe_worker_info->probe_work, hif_sdio_clt_probe_worker); + clt_probe_worker_info->registinfo_p = &g_hif_sdio_clt_drv_list[clt_index]; + clt_probe_worker_info->probe_idx = probe_index; + schedule_work(&clt_probe_worker_info->probe_work); +#endif + } else { + /* TODO: [FixMe][George] check if clt_index is cleared in client's unregister function */ + HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret); + return HIF_SDIO_ERR_CLT_NOT_REG; + } +} + +/*! + * \brief stp off by wmt (remove client driver). + * + * + * \param none. + * + * \retval 0:success, -11:not probed, -12:already off, -13:not registered, other errors. + */ +static _osal_inline_ INT32 hif_sdio_stp_off(VOID) +{ + INT32 clt_index = -1; + INT32 probe_index = -1; + INT32 ret = -1; + INT32 ret2 = -1; + struct sdio_func *func; + UINT32 chip_id = 0; + UINT16 func_num = 0; + const MTK_WCN_HIF_SDIO_FUNCINFO *func_info = NULL; + + HIF_SDIO_DBG_FUNC("hif_sdio_stp_off, start!\n"); + + /* 4 <1> If stp client drv has not been probed, return error code */ + /* MT6620 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020B, 1); + if (probe_index >= 0) + goto stp_off_exist; + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 1); + if (probe_index >= 0) + goto stp_off_exist; + + /* MT6628 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6628, 2); + if (probe_index >= 0) + goto stp_off_exist; + /* MT6630 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6630, 2); + if (probe_index >= 0) { + chip_id = 0x6630; + func_num = 2; + goto stp_off_exist; + } + /* MT6632 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6632, 2); + if (probe_index >= 0) { + chip_id = 0x6632; + func_num = 2; + goto stp_off_exist; + } + + /* MT6619 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6619, 1); + if (probe_index >= 0) + goto stp_off_exist; + + /* MT6618 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018B, 1); + if (probe_index >= 0) + goto stp_off_exist; + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 1); + if (probe_index >= 0) + goto stp_off_exist; + else { + /* 4 <2> If stp client drv has not been probed, return error code */ + /* client func has not been probed */ + return HIF_SDIO_ERR_NOT_PROBED; + } + +stp_off_exist: + /* 4 <3> If stp client drv has been off by wmt, return error code */ + if (g_hif_sdio_probed_func_list[probe_index].on_by_wmt == MTK_WCN_BOOL_FALSE) { + HIF_SDIO_WARN_FUNC("already off...\n"); + return HIF_SDIO_ERR_ALRDY_OFF; + } + g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE; + +#if 0 /* TODO: [FixMe][George] moved below as done in stp_on. */ + /* 4 <4> release irq for this function */ + func = g_hif_sdio_probed_func_list[probe_index].func; + sdio_claim_host(func); + ret = sdio_release_irq(func); + sdio_release_host(func); + if (ret) + pr_warn(DRV_NAME "sdio_release_irq for stp fail(%d)\n", ret); + else + pr_warn(DRV_NAME "sdio_release_irq for stp ok\n"); +#endif + clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx; + if (clt_index >= 0) { /* the function has been registered */ + func = g_hif_sdio_probed_func_list[probe_index].func; + + if (unlikely(!(func) || !(func->card) || !(func->card->host) + || mmc_card_removed(func->card))) { + HIF_SDIO_ERR_FUNC("sdio host is missing\n"); + return HIF_SDIO_ERR_ALRDY_OFF; + } + /* 4 <4> release irq for this function */ + sdio_claim_host(func); + mtk_wcn_hif_sdio_irq_flag_set(0); + ret2 = sdio_release_irq(func); + sdio_release_host(func); + + if (ret2) + HIF_SDIO_WARN_FUNC("sdio_release_irq() for stp fail(%d)\n", ret2); + else + HIF_SDIO_DBG_FUNC("sdio_release_irq() for stp ok\n"); + + /* 4 <5> Callback to client driver's remove() func */ + ret = + g_hif_sdio_clt_drv_list[clt_index]. + sdio_cltinfo->hif_clt_remove(CLTCTX + (func->device, func->num, func->cur_blksize, + probe_index)); + if (ret) + HIF_SDIO_WARN_FUNC("clt_remove for stp fail(%d)\n", ret); + else + HIF_SDIO_DBG_FUNC("hif_sdio_stp_off, ok!\n"); + + /*set deep sleep information to global data struct */ + func_info = g_hif_sdio_clt_drv_list[clt_index].func_info; + hif_sdio_deep_sleep_info_set_act(chip_id, func_num, + CLTCTX(func_info->card_id, func_info->func_num, + func_info->blk_sz, probe_index), 0); + return ret + ret2; + } + /* TODO: [FixMe][George] check if clt_index is cleared in client's unregister function */ + HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret); + return HIF_SDIO_ERR_CLT_NOT_REG; +} + +/*! + * \brief wifi on by wmt (probe client driver). + * + * + * \param none. + * + * \retval 0:success, -11:not probed, -12:already on, -13:not registered, other errors. + */ +static _osal_inline_ INT32 hif_sdio_wifi_on(VOID) +{ +#if 0 + MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO *clt_probe_worker_info = 0; +#endif + INT32 clt_index = -1; + INT32 probe_index = -1; + INT32 ret = 0; + INT32 ret2 = 0; + struct sdio_func *func; + UINT32 chip_id = 0; + UINT16 func_num = 0; + const MTK_WCN_HIF_SDIO_FUNCINFO *func_info = NULL; + + HIF_SDIO_DBG_FUNC("start!\n"); + + /* 4 <1> If wifi client drv has not been probed, return error code */ + /* MT6620 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020A, 1); + if (probe_index >= 0) + goto wifi_on_exist; + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 2); + if (probe_index >= 0) + goto wifi_on_exist; + /* MT6628 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6628, 1); + if (probe_index == 0) + goto wifi_on_exist; + /* MT6630 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6630, 1); + if (probe_index >= 0) { + chip_id = 0x6630; + func_num = 1; + goto wifi_on_exist; + } + /* MT6632 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6602, 1); + if (probe_index >= 0) { + chip_id = 0x6632; + func_num = 1; + goto wifi_on_exist; + } + + /* MT6618 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018A, 1); + if (probe_index == 0) + goto wifi_on_exist; + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 2); + if (probe_index >= 0) + goto wifi_on_exist; + else { + /* 4 <2> If wifi client drv has not been probed, return error code */ + /* client func has not been probed */ + return HIF_SDIO_ERR_NOT_PROBED; + } + +wifi_on_exist: + /* 4 <3> If wifi client drv has been on by wmt, return error code */ + if (g_hif_sdio_probed_func_list[probe_index].on_by_wmt) { + HIF_SDIO_INFO_FUNC("probe_index (%d), already on...\n", probe_index); + return HIF_SDIO_ERR_ALRDY_ON; + } + clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx; + if (clt_index >= 0) { /* the function has been registered */ + g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE; + /* 4 <4> claim irq for this function */ + func = g_hif_sdio_probed_func_list[probe_index].func; + if (unlikely(!(func) || !(func->card) || !(func->card->host) + || mmc_card_removed(func->card))) { + HIF_SDIO_ERR_FUNC("sdio host is missing\n"); + return HIF_SDIO_ERR_NOT_PROBED; + } + sdio_claim_host(func); + ret = sdio_claim_irq(func, hif_sdio_irq); + mtk_wcn_hif_sdio_irq_flag_set(1); + sdio_release_host(func); + if (ret) { + HIF_SDIO_WARN_FUNC("sdio_claim_irq() for wifi fail(%d)\n", ret); + return ret; + } + HIF_SDIO_INFO_FUNC("sdio_claim_irq() for wifi ok\n"); + + /* 4 <5> If this struct sdio_func *func is supported by any driver in */ + /* 4 g_hif_sdio_clt_drv_list, schedule another task to call client's .hif_clt_probe() */ + /* TODO: [FixMe][George] WHY probe worker is removed??? */ +#if 1 + /*set deep sleep information to global data struct */ + func_info = g_hif_sdio_clt_drv_list[clt_index].func_info; + hif_sdio_deep_sleep_info_set_act(chip_id, func_num, + CLTCTX(func_info->card_id, func_info->func_num, + func_info->blk_sz, probe_index), 1); + + /* Call client's .hif_clt_probe() */ + ret = hif_sdio_clt_probe_func(&g_hif_sdio_clt_drv_list[clt_index], probe_index); + if (ret) { + HIF_SDIO_WARN_FUNC("clt_probe_func() for wifi fail(%d) release irq\n", ret); + sdio_claim_host(func); + mtk_wcn_hif_sdio_irq_flag_set(0); + ret2 = sdio_release_irq(func); + sdio_release_host(func); + if (ret2) + HIF_SDIO_WARN_FUNC("sdio_release_irq() for wifi fail(%d)\n", ret2); + + hif_sdio_deep_sleep_info_set_act(chip_id, func_num, + CLTCTX(func_info->card_id, + func_info->func_num, + func_info->blk_sz, probe_index), + 0); + g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE; + return ret; + } + g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_TRUE; + + HIF_SDIO_DBG_FUNC("ok!\n"); + return 0; +#else + /* use worker thread to perform the client's .hif_clt_probe() */ + clt_probe_worker_info = vmalloc(sizeof(MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO)); + INIT_WORK(&clt_probe_worker_info->probe_work, hif_sdio_clt_probe_worker); + clt_probe_worker_info->registinfo_p = &g_hif_sdio_clt_drv_list[clt_index]; + clt_probe_worker_info->probe_idx = probe_index; + schedule_work(&clt_probe_worker_info->probe_work); +#endif + } else { + /* TODO: [FixMe][George] check if clt_index is cleared in client's unregister function */ + HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret); + g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_TRUE; + return HIF_SDIO_ERR_CLT_NOT_REG; + } +} + +/*! + * \brief wifi off by wmt (remove client driver). + * + * + * \param none. + * + * \retval 0:success, -11:not probed, -12:already off, -13:not registered, other errors. + */ +static _osal_inline_ INT32 hif_sdio_wifi_off(VOID) +{ + INT32 clt_index = -1; + INT32 probe_index = -1; + INT32 ret = -1; + INT32 ret2 = -1; + struct sdio_func *func; + UINT32 chip_id = 0; + UINT16 func_num = 0; + const MTK_WCN_HIF_SDIO_FUNCINFO *func_info = NULL; + + HIF_SDIO_INFO_FUNC("start!\n"); + + /* 4 <1> If wifi client drv has not been probed, return error code */ + /* MT6620 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020A, 1); + if (probe_index >= 0) + goto wifi_off_exist; + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x020C, 2); + if (probe_index >= 0) + goto wifi_off_exist; + + /* MT6628 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6628, 1); + if (probe_index >= 0) + goto wifi_off_exist; + /* MT6630 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6630, 1); + if (probe_index >= 0) { + chip_id = 0x6630; + func_num = 1; + goto wifi_off_exist; + } + /* MT6632 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x6602, 1); + if (probe_index >= 0) { + chip_id = 0x6632; + func_num = 1; + goto wifi_off_exist; + } + + /* MT6618 */ + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018A, 1); + if (probe_index >= 0) + goto wifi_off_exist; + probe_index = hif_sdio_find_probed_list_index_by_id_func(0x037A, 0x018C, 2); + if (probe_index >= 0) + goto wifi_off_exist; + else { + /* 4 <2> If wifi client drv has not been probed, return error code */ + /* client func has not been probed */ + return HIF_SDIO_ERR_NOT_PROBED; + } + +wifi_off_exist: + /* 4 <3> If wifi client drv has been off by wmt, return error code */ + if (g_hif_sdio_probed_func_list[probe_index].on_by_wmt == MTK_WCN_BOOL_FALSE) { + HIF_SDIO_WARN_FUNC("already off...\n"); + return HIF_SDIO_ERR_ALRDY_OFF; + } + g_hif_sdio_probed_func_list[probe_index].on_by_wmt = MTK_WCN_BOOL_FALSE; + + +#if 0 /* TODO: [FixMe][George] moved below as done in wifi_on. */ + /* 4 <4> release irq for this function */ + func = g_hif_sdio_probed_func_list[probe_index].func; + sdio_claim_host(func); + ret = sdio_release_irq(func); + sdio_release_host(func); + if (ret) + pr_warn(DRV_NAME "sdio_release_irq for wifi fail(%d)\n", ret); + else + pr_warn(DRV_NAME "sdio_release_irq for wifi ok\n"); + +#endif + clt_index = g_hif_sdio_probed_func_list[probe_index].clt_idx; + if (clt_index >= 0) { /* the function has been registered */ + func = g_hif_sdio_probed_func_list[probe_index].func; + + /* 4 <4> Callback to client driver's remove() func */ + ret = + g_hif_sdio_clt_drv_list[clt_index]. + sdio_cltinfo->hif_clt_remove(CLTCTX + (func->device, func->num, func->cur_blksize, + probe_index)); + if (ret) + HIF_SDIO_WARN_FUNC("clt_remove for wifi fail(%d)\n", ret); + else + HIF_SDIO_INFO_FUNC("ok!\n"); + + if (unlikely(!(func) || !(func->card) || !(func->card->host) + || mmc_card_removed(func->card))) { + HIF_SDIO_ERR_FUNC("sdio host is missing\n"); + return HIF_SDIO_ERR_ALRDY_OFF; + } + /* 4 <5> release irq for this function */ + sdio_claim_host(func); + mtk_wcn_hif_sdio_irq_flag_set(0); + ret2 = sdio_release_irq(func); + sdio_release_host(func); + g_hif_sdio_probed_func_list[probe_index].sdio_irq_enabled = MTK_WCN_BOOL_FALSE; + if (ret2) + HIF_SDIO_WARN_FUNC("sdio_release_irq() for wifi fail(%d)\n", ret2); + else + HIF_SDIO_INFO_FUNC("sdio_release_irq() for wifi ok\n"); + + /*set deep sleep information to global data struct */ + func_info = g_hif_sdio_clt_drv_list[clt_index].func_info; + hif_sdio_deep_sleep_info_set_act(chip_id, func_num, + CLTCTX(func_info->card_id, func_info->func_num, + func_info->blk_sz, probe_index), 0); + + return ret + ret2; + } + /* TODO: [FixMe][George] check if clt_index is cleared in client's unregister function */ + HIF_SDIO_WARN_FUNC("probed but not registered yet (%d)\n", ret); + return HIF_SDIO_ERR_CLT_NOT_REG; +} + +/*! + * \brief set mmc power up/off + * + * detailed descriptions + * + * \param: 1. ctx client's context variable, 2.power state: 1:power up, other:power off + * + * \retval 0:success, -1:fail + */ +INT32 mtk_wcn_hif_sdio_bus_set_power(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 pwrState) +{ + INT32 probe_index = -1; + struct sdio_func *func = 0; + + HIF_SDIO_INFO_FUNC("turn Bus Power to: %d\n", pwrState); + + probe_index = CLTCTX_IDX(ctx); + if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx); + return -1; + } + func = g_hif_sdio_probed_func_list[probe_index].func; + + if (!func) { + HIF_SDIO_WARN_FUNC("Cannot find sdio_func !!!\n"); + return -1; + } + + if (pwrState == 1) { + sdio_claim_host(func); + mmc_power_up_ext(func->card->host); + sdio_release_host(func); + HIF_SDIO_WARN_FUNC("SDIO BUS Power UP\n"); + } else { + sdio_claim_host(func); + mmc_power_off_ext(func->card->host); + sdio_release_host(func); + HIF_SDIO_WARN_FUNC("SDIO BUS Power OFF\n"); + } + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_hif_sdio_bus_set_power); + +VOID mtk_wcn_hif_sdio_enable_irq(MTK_WCN_HIF_SDIO_CLTCTX ctx, MTK_WCN_BOOL enable) +{ + UINT8 probed_idx = CLTCTX_IDX(ctx); + + if (unlikely(!CLTCTX_UIDX_VALID(probed_idx))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid idx in ctx(0x%x), sdio_irq no change\n", ctx); + return; + } + if (unlikely(!CLTCTX_UIDX_VALID(probed_idx))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx); + return; + } + /* store client driver's private data to dev driver */ + g_hif_sdio_probed_func_list[probed_idx].sdio_irq_enabled = enable; + smp_wmb(); + HIF_SDIO_DBG_FUNC("ctx(0x%x) sdio irq enable(%d)\n", + ctx, (enable == MTK_WCN_BOOL_FALSE) ? 0 : 1); + + +} +EXPORT_SYMBOL(mtk_wcn_hif_sdio_enable_irq); + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0 register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_f0_readb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, PUINT8 pvb) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func *func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + INT32 probe_index = -1; + struct sdio_func *func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + HIF_SDIO_ASSERT(pvb); + +/*4 <1> check if ctx is valid, registered, and probed */ +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx); + return -1; + } + if (probe_index < 0 || probe_index >= CFG_CLIENT_COUNT) { /* the function has not been probed */ + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } else { + if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */ + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + +/*4 <2>*/ + sdio_claim_host(func); + *pvb = sdio_f0_readb(func, offset, &ret); + sdio_release_host(func); + +/*4 <3> check result code and return proper error code*/ + +out: + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_f0_readb() */ + + +/*! + * \brief + * + * detailed descriptions + * + * \param ctx client's context variable + * + * \retval 0register successfully + * \retval < 0 list error code here + */ +INT32 mtk_wcn_hif_sdio_f0_writeb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, UINT8 vb) +{ +#if HIF_SDIO_UPDATE + INT32 ret; + struct sdio_func *func; +#else + INT32 ret = -HIF_SDIO_ERR_FAIL; + INT32 probe_index = -1; + struct sdio_func *func = 0; +#endif + + HIF_SDIO_DBG_FUNC("start!\n"); + +/*4 <1> check if ctx is valid, registered, and probed*/ +#if HIF_SDIO_UPDATE + ret = -HIF_SDIO_ERR_FAIL; + func = hif_sdio_ctx_to_func(ctx); + if (!func) { + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } +#else + probe_index = CLTCTX_IDX(ctx); + if (unlikely(!CLTCTX_IDX_VALID(probe_index))) { /* invalid index in CLTCTX */ + HIF_SDIO_WARN_FUNC("invalid ctx(0x%x)\n", ctx); + goto out; + } + if (probe_index < 0) { /* the function has not been probed */ + HIF_SDIO_WARN_FUNC("can't find client in probed list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } else { + if (g_hif_sdio_probed_func_list[probe_index].clt_idx < 0) { /* the client has not been registered */ + HIF_SDIO_WARN_FUNC("can't find client in registered list!\n"); + ret = -HIF_SDIO_ERR_FAIL; + goto out; + } + } + func = g_hif_sdio_probed_func_list[probe_index].func; +#endif + +/*4 <1.1> check if input parameters are valid*/ + +/*4 <2>*/ + wmt_tra_sdio_update(); + sdio_claim_host(func); + sdio_f0_writeb(func, vb, offset, &ret); + sdio_release_host(func); + +/*4 <3> check result code and return proper error code*/ + +out: + HIF_SDIO_DBG_FUNC("end!\n"); + return ret; +} /* end of mtk_wcn_hif_sdio_f0_writeb() */ + + +INT32 mtk_wcn_hif_sdio_drv_init(VOID) +{ + return hif_sdio_init(); + +} +EXPORT_SYMBOL(mtk_wcn_hif_sdio_drv_init); + +VOID mtk_wcn_hif_sdio_driver_exit(VOID) +{ + return hif_sdio_exit(); +} +EXPORT_SYMBOL(mtk_wcn_hif_sdio_driver_exit); diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/bgw_desense.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/bgw_desense.h new file mode 100644 index 00000000000000..4e9db7cbeb9338 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/bgw_desense.h @@ -0,0 +1,73 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef __BGW_DESENSE_H_ +#define __BGW_DESENSE_H_ + +#ifdef MSG +#undef MSG +#endif + +#ifdef ERR +#undef ERR +#endif + +#define PFX1 "[BWG] " +#define MSG(fmt, arg ...) pr_debug(PFX1 "[D]%s: " fmt, __func__, ##arg) +#define ERR(fmt, arg ...) pr_debug(PFX1 "[D]%s: " fmt, __func__, ##arg) + +#ifdef NETLINK_TEST +#undef NETLINK_TEST +#endif + +#define NETLINK_TEST 17 + +#ifdef MAX_NL_MSG_LEN +#undef MAX_NL_MSG_LEN +#endif + +#define MAX_NL_MSG_LEN 1024 + + +#ifdef ON +#undef ON +#endif +#ifdef OFF +#undef OFF +#endif +#ifdef ACK +#undef ACK +#endif + +#define ON 1 +#define OFF 0 +#define ACK 2 + +/* + * used send command to native process + * + * parameter: command could be macro ON: enable co-exist; OFF: disable co-exist; + * ACK: after get native process init message send ACK + */ +extern void send_command_to_daemon(const int command); + +/* + * before use kernel socket, please call init socket first + * return value: 0: ok; -1: fail + */ +extern int bgw_init_socket(void); + +extern void bgw_destroy_netlink_kernel(void); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/fw_log_wmt.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/fw_log_wmt.h new file mode 100644 index 00000000000000..7871f467e64d11 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/fw_log_wmt.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _FW_LOG_WMT_H_ +#define _FW_LOG_WMT_H_ + +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +int fw_log_wmt_init(void); +void fw_log_wmt_deinit(void); +#endif + +#endif /*_FW_LOG_WMT_H_*/ + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/hif_sdio.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/hif_sdio.h new file mode 100644 index 00000000000000..b018e1f7b8738f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/hif_sdio.h @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! + * \file "hif_sdio.h" + * \brief + */ + +/* + * + * 07 25 2010 george.kuo + * + * Move hif_sdio driver to linux directory. + * + * 07 23 2010 george.kuo + * + * Add MT6620 driver source tree + * , including char device driver (wmt, bt, gps), stp driver, + * interface driver (tty ldisc and hif_sdio), and bt hci driver. +** +** +*/ + +#ifndef _HIF_SDIO_H +#define _HIF_SDIO_H +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define HIF_SDIO_DEBUG (0) /* 0:turn off debug msg and assert, 1:turn off debug msg and assert */ +#define HIF_SDIO_API_EXTENSION (0) +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <linux/mmc/card.h> +#include <linux/mmc/host.h> +#include <linux/mmc/sdio_func.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/mmc/sdio.h> +#include <sdio_ops.h> + +#include <linux/mm.h> +#include <linux/firmware.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/vmalloc.h> +#include <linux/atomic.h> + +#include "osal_typedef.h" +#include "osal.h" +#include "wmt_exp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define CFG_CLIENT_COUNT (12) + +#define HIF_DEFAULT_BLK_SIZE (256) +#define HIF_DEFAULT_VENDOR (0x037A) + +#define HIF_SDIO_LOG_LOUD 4 +#define HIF_SDIO_LOG_DBG 3 +#define HIF_SDIO_LOG_INFO 2 +#define HIF_SDIO_LOG_WARN 1 +#define HIF_SDIO_LOG_ERR 0 + +#define CCCR_F8 (0X00F8) +#define SWPCDBGR (0x0154) + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/* Function info provided by client driver */ +typedef struct _MTK_WCN_HIF_SDIO_FUNCINFO MTK_WCN_HIF_SDIO_FUNCINFO; + +/* Client context provided by hif_sdio driver for the following function call */ +typedef UINT32 MTK_WCN_HIF_SDIO_CLTCTX; + +/* Callback functions provided by client driver */ +typedef INT32 (*MTK_WCN_HIF_SDIO_PROBE)(MTK_WCN_HIF_SDIO_CLTCTX, + const MTK_WCN_HIF_SDIO_FUNCINFO *); +typedef INT32 (*MTK_WCN_HIF_SDIO_REMOVE)(MTK_WCN_HIF_SDIO_CLTCTX); +typedef INT32 (*MTK_WCN_HIF_SDIO_IRQ)(MTK_WCN_HIF_SDIO_CLTCTX); + +/* Function info provided by client driver */ +struct _MTK_WCN_HIF_SDIO_FUNCINFO { + UINT16 manf_id; /* TPLMID_MANF: manufacturer ID */ + UINT16 card_id; /* TPLMID_CARD: card ID */ + UINT16 func_num; /* Function Number */ + UINT16 blk_sz; /* Function block size */ +}; + +/* Client info provided by client driver */ +typedef struct _MTK_WCN_HIF_SDIO_CLTINFO { + const MTK_WCN_HIF_SDIO_FUNCINFO *func_tbl; /* supported function info table */ + UINT32 func_tbl_size; /* supported function table info element number */ + MTK_WCN_HIF_SDIO_PROBE hif_clt_probe; /* callback function for probing */ + MTK_WCN_HIF_SDIO_REMOVE hif_clt_remove; /* callback function for removing */ + MTK_WCN_HIF_SDIO_IRQ hif_clt_irq; /* callback function for interrupt handling */ +} MTK_WCN_HIF_SDIO_CLTINFO; + +/* function info provided by registed function */ +typedef struct _MTK_WCN_HIF_SDIO_REGISTINFO { + const MTK_WCN_HIF_SDIO_CLTINFO *sdio_cltinfo; /* client's MTK_WCN_HIF_SDIO_CLTINFO pointer */ + const MTK_WCN_HIF_SDIO_FUNCINFO *func_info; /* supported function info pointer */ +} MTK_WCN_HIF_SDIO_REGISTINFO; + +/* Card info provided by probed function */ +typedef struct _MTK_WCN_HIF_SDIO_PROBEINFO { + struct sdio_func *func; /* probed sdio function pointer */ + PVOID private_data_p; /* clt's private data pointer */ + MTK_WCN_BOOL on_by_wmt; /* TRUE: on by wmt, FALSE: not on by wmt */ + /* added for sdio irq sync and mmc single_irq workaround */ + MTK_WCN_BOOL sdio_irq_enabled; /* TRUE: can handle sdio irq; FALSE: no sdio irq handling */ + INT32 clt_idx; /* registered function table info element number (initial value is -1) */ +} MTK_WCN_HIF_SDIO_PROBEINFO; + +/* work queue info needed by worker */ +typedef struct _MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO { + struct work_struct probe_work; /* work queue structure */ + MTK_WCN_HIF_SDIO_REGISTINFO *registinfo_p; /* MTK_WCN_HIF_SDIO_REGISTINFO pointer of the client */ + INT8 probe_idx; /* probed function table info element number (initial value is -1) */ +} MTK_WCN_HIF_SDIO_CLT_PROBE_WORKERINFO; + +/* global resource locks info of hif_sdio drv */ +typedef struct _MTK_WCN_HIF_SDIO_LOCKINFO { + spinlock_t probed_list_lock; /* spin lock for probed list */ + spinlock_t clt_list_lock; /* spin lock for client registed list */ +} MTK_WCN_HIF_SDIO_LOCKINFO; + +/* SDIO Deep Sleep Information by chip, maintained by HIF-SDIO itself */ +typedef struct _MTK_WCN_HIF_SDIO_DS_CLT_INFO { + MTK_WCN_HIF_SDIO_CLTCTX ctx; + UINT16 func_num; + UINT8 act_flag; + UINT8 ds_en_flag; +} MTK_WCN_HIF_SDIO_DS_CLT_INFO; + +typedef struct _MTK_WCN_HIF_SDIO_DS_INFO { + UINT32 chip_id; /*chipid */ + UINT32 reg_offset; /*offset in CCCR of control register of deep sleep */ + UINT8 value; /*value to set to CCCR reg_offset, when enable deep sleep */ + MTK_WCN_HIF_SDIO_DS_CLT_INFO clt_info[2]; /*currently, only BGF and WIFI function need this function */ + struct mutex lock; +} MTK_WCN_HIF_SDIO_DS_INFO; + + +/* error code returned by hif_sdio driver (use NEGATIVE number) */ +typedef enum { + HIF_SDIO_ERR_SUCCESS = 0, + HIF_SDIO_ERR_FAIL = HIF_SDIO_ERR_SUCCESS - 1, /* generic error */ + HIF_SDIO_ERR_INVALID_PARAM = HIF_SDIO_ERR_FAIL - 1, + HIF_SDIO_ERR_DUPLICATED = HIF_SDIO_ERR_INVALID_PARAM - 1, + HIF_SDIO_ERR_UNSUP_MANF_ID = HIF_SDIO_ERR_DUPLICATED - 1, + HIF_SDIO_ERR_UNSUP_CARD_ID = HIF_SDIO_ERR_UNSUP_MANF_ID - 1, + HIF_SDIO_ERR_INVALID_FUNC_NUM = HIF_SDIO_ERR_UNSUP_CARD_ID - 1, + HIF_SDIO_ERR_INVALID_BLK_SZ = HIF_SDIO_ERR_INVALID_FUNC_NUM - 1, + HIF_SDIO_ERR_NOT_PROBED = HIF_SDIO_ERR_INVALID_BLK_SZ - 1, + HIF_SDIO_ERR_ALRDY_ON = HIF_SDIO_ERR_NOT_PROBED - 1, + HIF_SDIO_ERR_ALRDY_OFF = HIF_SDIO_ERR_ALRDY_ON - 1, + HIF_SDIO_ERR_CLT_NOT_REG = HIF_SDIO_ERR_ALRDY_OFF - 1, +} MTK_WCN_HIF_SDIO_ERR; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*! + * \brief A macro used to generate hif_sdio client's context + * + * Generate a context for hif_sdio client based on the following input parameters + * |<-card id (16bits)->|<-block size in unit of 256 bytes(8 bits)->|<-function number(4bits)->|<-index(4bits)->| + * + * \param manf the 16 bit manufacturer id + * \param card the 16 bit card id + * \param func the 16 bit function number + * \param b_sz the 16 bit function block size + */ +#define CLTCTX(cid, func, blk_sz, idx) \ +(MTK_WCN_HIF_SDIO_CLTCTX)((((UINT32)(cid) & 0xFFFFUL) << 16) | \ + (((UINT32)(func) & 0xFUL) << 4) | \ + (((UINT32)(blk_sz) & 0xFF00UL) << 0) | \ + (((UINT32)idx & 0xFUL) << 0)) + +/*! + * \brief A set of macros used to get information out of an hif_sdio client context + * + * Generate a context for hif_sdio client based on the following input parameters + */ +#define CLTCTX_CID(ctx) (((ctx) >> 16) & 0xFFFF) +#define CLTCTX_FUNC(ctx) (((ctx) >> 4) & 0xF) +#define CLTCTX_BLK_SZ(ctx) (((ctx) >> 0) & 0xFF00) +#define CLTCTX_IDX(ctx) ((ctx) & 0xF) +#define CLTCTX_IDX_VALID(idx) ((idx >= 0) && (idx < CFG_CLIENT_COUNT)) +#define CLTCTX_UIDX_VALID(idx) (idx < CFG_CLIENT_COUNT) + + +/*! + * \brief A macro used to describe an SDIO function + * + * Fill an MTK_WCN_HIF_SDIO_FUNCINFO structure with function-specific information + * + * \param manf the 16 bit manufacturer id + * \param card the 16 bit card id + * \param func the 16 bit function number + * \param b_sz the 16 bit function block size + */ +#define MTK_WCN_HIF_SDIO_FUNC(manf, card, func, b_sz) \ + .manf_id = (manf), .card_id = (card), .func_num = (func), .blk_sz = (b_sz) + +#ifdef DFT_TAG +#undef DFT_TAG +#endif + +#ifndef DFT_TAG +#define DFT_TAG "[HIF-SDIO]" +#endif + +extern INT32 gHifSdioDbgLvl; + + +#define HIF_SDIO_LOUD_FUNC(fmt, arg...) \ +do { if (gHifSdioDbgLvl >= HIF_SDIO_LOG_LOUD) \ + osal_warn_print(DFT_TAG"[L]%s:" fmt, __func__, ##arg); \ +} while (0) +#define HIF_SDIO_DBG_FUNC(fmt, arg...) \ +do { if (gHifSdioDbgLvl >= HIF_SDIO_LOG_DBG) \ + osal_warn_print(DFT_TAG"[D]%s:" fmt, __func__, ##arg); \ +} while (0) +#define HIF_SDIO_INFO_FUNC(fmt, arg...) \ +do { if (gHifSdioDbgLvl >= HIF_SDIO_LOG_INFO) \ + osal_warn_print(DFT_TAG"[I]%s:" fmt, __func__, ##arg); \ +} while (0) +#define HIF_SDIO_WARN_FUNC(fmt, arg...) \ +do { if (gHifSdioDbgLvl >= HIF_SDIO_LOG_WARN) \ + osal_warn_print(DFT_TAG"[W]%s(%d):" fmt, __func__, __LINE__, ##arg); \ +} while (0) +#define HIF_SDIO_ERR_FUNC(fmt, arg...) \ +do { if (gHifSdioDbgLvl >= HIF_SDIO_LOG_ERR) \ + osal_err_print(DFT_TAG"[E]%s(%d):" fmt, __func__, __LINE__, ##arg); \ +} while (0) + +/*! + * \brief ASSERT function definition. + * + */ +#if HIF_SDIO_DEBUG +#define HIF_SDIO_ASSERT(expr) \ +{ \ + if (!(expr)) { \ + osal_warn_print("assertion failed! %s[%d]: %s\n",\ + __func__, __LINE__, #expr); \ + osal_bug_on(!(expr));\ + } \ +} +#else +#define HIF_SDIO_ASSERT(expr) do {} while (0) +#endif + +/* define function 0 CR */ +#define CCCR_06 (0x06) +#define CCCR_F0 (0xF0) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/*! + * \brief MTK hif sdio client registration function + * + * Client uses this function to do hif sdio registration + * + * \param pinfo a pointer of client's information + * + * \retval 0 register successfully + * \retval < 0 error code + */ +extern INT32 mtk_wcn_hif_sdio_client_reg(const MTK_WCN_HIF_SDIO_CLTINFO *pinfo); + +extern INT32 mtk_wcn_hif_sdio_client_unreg(const MTK_WCN_HIF_SDIO_CLTINFO *pinfo); + +extern INT32 mtk_wcn_hif_sdio_readb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, PUINT8 pvb); + +extern INT32 mtk_wcn_hif_sdio_writeb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, UINT8 vb); + +extern INT32 mtk_wcn_hif_sdio_readl(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, PUINT32 pvl); + +extern INT32 mtk_wcn_hif_sdio_writel(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, UINT32 vl); + +extern INT32 mtk_wcn_hif_sdio_read_buf(MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, PUINT32 pbuf, UINT32 len); + +extern INT32 mtk_wcn_hif_sdio_write_buf(MTK_WCN_HIF_SDIO_CLTCTX ctx, + UINT32 offset, PUINT32 pbuf, UINT32 len); + +extern INT32 mtk_wcn_hif_sdio_abort(MTK_WCN_HIF_SDIO_CLTCTX ctx); + +INT32 hif_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx); + +extern VOID mtk_wcn_hif_sdio_set_drvdata(MTK_WCN_HIF_SDIO_CLTCTX ctx, PVOID private_data_p); + +extern PVOID mtk_wcn_hif_sdio_get_drvdata(MTK_WCN_HIF_SDIO_CLTCTX ctx); + +extern INT32 mtk_wcn_hif_sdio_wmt_control(WMT_SDIO_FUNC_TYPE func_type, MTK_WCN_BOOL is_on); + +extern INT32 mtk_wcn_hif_sdio_bus_set_power(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 pwrState); + +extern VOID mtk_wcn_hif_sdio_get_dev(MTK_WCN_HIF_SDIO_CLTCTX ctx, struct device **dev); + +extern INT32 mtk_wcn_hif_sdio_update_cb_reg(INT32(*ts_update)(VOID)); + +extern INT32 mtk_wcn_hif_sdio_irq_flag_set(INT32 flag); + +extern VOID mtk_wcn_hif_sdio_enable_irq(MTK_WCN_HIF_SDIO_CLTCTX ctx, MTK_WCN_BOOL enable); + +extern INT32 mtk_wcn_hif_sdio_f0_writeb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, UINT8 vb); + +extern INT32 mtk_wcn_hif_sdio_drv_init(VOID); + +extern VOID mtk_wcn_hif_sdio_driver_exit(VOID); + +extern INT32 mtk_wcn_hif_sdio_f0_readb(MTK_WCN_HIF_SDIO_CLTCTX ctx, UINT32 offset, PUINT8 pvb); +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +INT32 mtk_wcn_hif_sdio_deep_sleep_flag_set(MTK_WCN_BOOL flag); +#endif + +#define DELETE_HIF_SDIO_CHRDEV 1 +#if !(DELETE_HIF_SDIO_CHRDEV) +INT32 mtk_wcn_hif_sdio_tell_chipid(INT32 chipId); +INT32 mtk_wcn_hif_sdio_query_chipid(INT32 waitFlag); +#endif + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +extern int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, + unsigned addr, u8 in, u8 *out); + +/******************************************************************************* +* E X T E R N A L F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#endif /* _HIF_SDIO_H */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_btif.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_btif.h new file mode 100644 index 00000000000000..7595708af57116 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_btif.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _STP_BTIF_H_ +#define _STP_BTIF_H_ + +#include "osal_typedef.h" +#include "mtk_btif_exp.h" +#include "osal.h" + +struct stp_btif { + ULONG stpBtifId; + OSAL_THREAD btif_thread; +}; + +INT32 mtk_wcn_consys_stp_btif_open(VOID); +INT32 mtk_wcn_consys_stp_btif_close(VOID); +INT32 mtk_wcn_consys_stp_btif_rx_cb_register(MTK_WCN_BTIF_RX_CB rx_cb); +INT32 mtk_wcn_consys_stp_btif_tx(const PUINT8 pBuf, const UINT32 len, PUINT32 written_len); +INT32 mtk_wcn_consys_stp_btif_wakeup(VOID); +INT32 mtk_wcn_consys_stp_btif_dpidle_ctrl(enum _ENUM_BTIF_DPIDLE_ en_flag); +INT32 mtk_wcn_consys_stp_btif_lpbk_ctrl(enum _ENUM_BTIF_LPBK_MODE_ mode); +INT32 mtk_wcn_consys_stp_btif_logger_ctrl(enum _ENUM_BTIF_DBG_ID_ flag); +INT32 mtk_wcn_consys_stp_btif_parser_wmt_evt(const PUINT8 str, UINT32 len); +INT32 mtk_wcn_consys_stp_btif_rx_has_pending_data(VOID); +INT32 mtk_wcn_consys_stp_btif_tx_has_pending_data(VOID); +P_OSAL_THREAD mtk_wcn_consys_stp_btif_rx_thread_get(VOID); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg.h new file mode 100644 index 00000000000000..0fe844d325cfcf --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg.h @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _STP_DEBUG_H_ +#define _STP_DEBUG_H_ + +#include <linux/time.h> +#include "stp_btif.h" +#include "osal.h" +#include "wmt_exp.h" + +#define CONFIG_LOG_STP_INTERNAL + +#ifndef LOG_STP_DEBUG_DISABLE /* #ifndef CONFIG_LOG_STP_INTERNAL */ +#define STP_PKT_SZ 16 +#define STP_DMP_SZ 2048 +#define STP_PKT_NO 2048 + +#define STP_DBG_LOG_ENTRY_NUM 1024 +#define STP_DBG_LOG_ENTRY_SZ 96 + +#else + +#define STP_PKT_SZ 16 +#define STP_DMP_SZ 16 +#define STP_PKT_NO 16 + +#define STP_DBG_LOG_ENTRY_NUM 28 +#define STP_DBG_LOG_ENTRY_SZ 96 + +#endif +#define EMICOREDUMP_CMD "emicoredump" +#define FAKECOREDUMPEND "coredump end - fake" + +#define MAX_DUMP_HEAD_LEN 512 +/* netlink header packet length is 5 "[M](3 bytes) + length(2 bypes)" */ +#define NL_PKT_HEADER_LEN 5 + +#define PFX_STP_DBG "[STPDbg]" +#define STP_DBG_LOG_LOUD 4 +#define STP_DBG_LOG_DBG 3 +#define STP_DBG_LOG_INFO 2 +#define STP_DBG_LOG_WARN 1 +#define STP_DBG_LOG_ERR 0 + +extern INT32 gStpDbgDbgLevel; + +#define STP_DBG_PR_LOUD(fmt, arg...) \ +do { \ + if (gStpDbgDbgLevel >= STP_DBG_LOG_LOUD) \ + pr_info(PFX_STP_DBG "%s: " fmt, __func__, ##arg); \ +} while (0) +#define STP_DBG_PR_DBG(fmt, arg...) \ +do { \ + if (gStpDbgDbgLevel >= STP_DBG_LOG_DBG) \ + pr_info(PFX_STP_DBG "%s: " fmt, __func__, ##arg); \ +} while (0) +#define STP_DBG_PR_INFO(fmt, arg...) \ +do { \ + if (gStpDbgDbgLevel >= STP_DBG_LOG_INFO) \ + pr_info(PFX_STP_DBG "%s: " fmt, __func__, ##arg); \ +} while (0) +#define STP_DBG_PR_WARN(fmt, arg...) \ +do { \ + if (gStpDbgDbgLevel >= STP_DBG_LOG_WARN) \ + pr_warn(PFX_STP_DBG "%s: " fmt, __func__, ##arg); \ +} while (0) +#define STP_DBG_PR_ERR(fmt, arg...) \ +do { \ + if (gStpDbgDbgLevel >= STP_DBG_LOG_ERR) \ + pr_err(PFX_STP_DBG "%s: " fmt, __func__, ##arg); \ +} while (0) + +typedef enum { + STP_DBG_EN = 0, + STP_DBG_PKT = 1, + STP_DBG_DR = 2, + STP_DBG_FW_ASSERT = 3, + STP_DBG_FW_LOG = 4, + STP_DBG_FW_DMP = 5, + STP_DBG_MAX +} STP_DBG_OP_T; + +typedef enum { + STP_DBG_PKT_FIL_ALL = 0, + STP_DBG_PKT_FIL_BT = 1, + STP_DBG_PKT_FIL_GPS = 2, + STP_DBG_PKT_FIL_FM = 3, + STP_DBG_PKT_FIL_WMT = 4, + STP_DBG_PKT_FIL_MAX +} STP_DBG_PKT_FIL_T; + +static PINT8 const comboStpDbgType[] = { + "< BT>", + "< FM>", + "<GPS>", + "<WiFi>", + "<WMT>", + "<STP>", + "<DBG>", + "<ANT>", + "<SDIO_OWN_SET>", + "<SDIO_OWN_CLR>", + "<WAKEINT>", + "<UNKNOWN>" +}; + +static PINT8 const socStpDbgType[] = { + "< BT>", + "< FM>", + "<GPS>", + "<WiFi>", + "<WMT>", + "<STP>", + "<DBG>", + "<WAKEINT>", + "<UNKNOWN>" +}; + +enum STP_DBG_TAKS_ID_T { + STP_DBG_TASK_WMT = 0, + STP_DBG_TASK_BT, + STP_DBG_TASK_WIFI, + STP_DBG_TASK_TST, + STP_DBG_TASK_FM, + STP_DBG_TASK_GPS, + STP_DBG_TASK_FLP, + STP_DBG_TASK_BT2, + STP_DBG_TASK_IDLE, + STP_DBG_TASK_DRVSTP, + STP_DBG_TASK_BUS, + STP_DBG_TASK_NATBT, + STP_DBG_TASK_DRVWIFI, + STP_DBG_TASK_DRVGPS, + STP_DBG_TASK_ID_MAX, +}; + +typedef enum { + STP_DBG_DR_MAX = 0, +} STP_DBG_DR_FIL_T; + +typedef enum { + STP_DBG_FW_MAX = 0, +} STP_DBG_FW_FIL_T; + +typedef enum { + PKT_DIR_RX = 0, + PKT_DIR_TX +} STP_DBG_PKT_DIR_T; + +/*simple log system ++*/ + +typedef struct { + /*type: 0. pkt trace 1. fw info + * 2. assert info 3. trace32 dump . + * -1. linked to the the previous + */ + INT32 id; + INT32 len; + INT8 buffer[STP_DBG_LOG_ENTRY_SZ]; +} MTKSTP_LOG_ENTRY_T; + +typedef struct log_sys { + MTKSTP_LOG_ENTRY_T queue[STP_DBG_LOG_ENTRY_NUM]; + UINT32 size; + UINT32 in; + UINT32 out; + spinlock_t lock; + MTKSTP_LOG_ENTRY_T *dump_queue; + UINT32 dump_size; + struct work_struct dump_work; +} MTKSTP_LOG_SYS_T; +/*--*/ + +typedef struct stp_dbg_pkt_hdr { + /* packet information */ + UINT32 sec; + UINT32 usec; + UINT32 dbg_type; + UINT32 last_dbg_type; + UINT32 dmy; + UINT32 no; + UINT32 dir; + + /* packet content */ + UINT32 type; + UINT32 len; + UINT32 ack; + UINT32 seq; + UINT32 chs; + UINT32 crc; + UINT64 l_sec; + ULONG l_nsec; +} STP_DBG_HDR_T; + +typedef struct stp_dbg_pkt { + struct stp_dbg_pkt_hdr hdr; + UINT8 raw[STP_DMP_SZ]; +} STP_PACKET_T; + +typedef struct mtkstp_dbg_t { + /*log_sys */ + INT32 pkt_trace_no; + PVOID btm; + INT32 is_enable; + MTKSTP_LOG_SYS_T *logsys; +} MTKSTP_DBG_T; + +/* extern void aed_combo_exception(const int *, int, const int *, int, const char *); */ +#if WMT_DBG_SUPPORT +#define STP_CORE_DUMP_TIMEOUT (1*60*1000) /* default 1 minutes */ +#else +#define STP_CORE_DUMP_TIMEOUT (10*1000) /* user load default 10 seconds */ +#endif +#if WMT_DBG_SUPPORT +#define STP_EMI_DUMP_TIMEOUT (30*1000) +#else +#define STP_EMI_DUMP_TIMEOUT (5*1000) +#endif +#define STP_OJB_NAME_SZ 20 +#define STP_CORE_DUMP_INFO_SZ 500 +#define STP_CORE_DUMP_INIT_SIZE 512 +typedef enum wcn_compress_algorithm_t { + GZIP = 0, + BZIP2 = 1, + RAR = 2, + LMA = 3, + MAX +} WCN_COMPRESS_ALG_T; + +typedef INT32 (*COMPRESS_HANDLER) (PVOID worker, UINT8 *in_buf, INT32 in_sz, PUINT8 out_buf, PINT32 out_sz, + INT32 finish); +typedef struct wcn_compressor_t { + /* current object name */ + UINT8 name[STP_OJB_NAME_SZ + 1]; + + /* buffer for raw data, named L1 */ + PUINT8 L1_buf; + INT32 L1_buf_sz; + INT32 L1_pos; + + /* target buffer, named L2 */ + PUINT8 L2_buf; + INT32 L2_buf_sz; + INT32 L2_pos; + + /* compress state */ + UINT8 f_done; + UINT16 reserved; + UINT32 uncomp_size; + UINT32 crc32; + + /* compress algorithm */ + UINT8 f_compress_en; + WCN_COMPRESS_ALG_T compress_type; + PVOID worker; + COMPRESS_HANDLER handler; +} WCN_COMPRESSOR_T, *P_WCN_COMPRESSOR_T; + +typedef enum core_dump_state_t { + CORE_DUMP_INIT = 0, + CORE_DUMP_DOING, + CORE_DUMP_TIMEOUT, + CORE_DUMP_DONE, + CORE_DUMP_MAX +} CORE_DUMP_STA; + +typedef struct core_dump_t { + /* compress dump data and buffered */ + P_WCN_COMPRESSOR_T compressor; + + /* timer for monitor timeout */ + OSAL_TIMER dmp_timer; + UINT32 timeout; + LONG dmp_num; + UINT32 count; + OSAL_SLEEPABLE_LOCK dmp_lock; + + /* timer for monitor emi dump */ + OSAL_TIMER dmp_emi_timer; + UINT32 emi_timeout; + + /* state machine for core dump flow */ + CORE_DUMP_STA sm; + + /* dump info */ + INT8 info[STP_CORE_DUMP_INFO_SZ + 1]; + + PUINT8 p_head; + UINT32 head_len; +} WCN_CORE_DUMP_T, *P_WCN_CORE_DUMP_T; + +typedef enum _ENUM_STP_FW_ISSUE_TYPE_ { + STP_FW_ISSUE_TYPE_INVALID = 0x0, + STP_FW_ASSERT_ISSUE = 0x1, + STP_FW_NOACK_ISSUE = 0x2, + STP_FW_WARM_RST_ISSUE = 0x3, + STP_DBG_PROC_TEST = 0x4, + STP_HOST_TRIGGER_FW_ASSERT = 0x5, + STP_HOST_TRIGGER_ASSERT_TIMEOUT = 0x6, + STP_FW_ABT = 0x7, + STP_HOST_TRIGGER_COLLECT_FTRACE = 0x8, + STP_FW_ISSUE_TYPE_MAX +} ENUM_STP_FW_ISSUE_TYPE, *P_ENUM_STP_FW_ISSUE_TYPE; + +/* this was added for support dmareg's issue */ +typedef enum _ENUM_DMA_ISSUE_TYPE_ { + CONNSYS_CLK_GATE_STATUS = 0x00, + CONSYS_EMI_STATUS, + SYSRAM1, + SYSRAM2, + SYSRAM3, + DMA_REGS_MAX +} ENUM_DMA_ISSUE_TYPE; +#define STP_PATCH_TIME_SIZE 12 +#define STP_DBG_CPUPCR_NUM 30 +#define STP_DBG_DMAREGS_NUM 16 +#define STP_PATCH_BRANCH_SZIE 8 +#define STP_ASSERT_INFO_SIZE 164 +#define STP_DBG_ROM_VER_SIZE 4 +#define STP_ASSERT_TYPE_SIZE 64 + +#define STP_DBG_KEYWORD_SIZE 256 +typedef struct stp_dbg_host_assert_t { + UINT32 drv_type; + UINT32 reason; + UINT32 assert_from_host; +} STP_DBG_HOST_ASSERT_T, *P_STP_DBG_HOST_ASSERT_T; + +typedef struct stp_dbg_cpupcr_t { + UINT32 chipId; + UINT8 romVer[STP_DBG_ROM_VER_SIZE]; + UINT8 patchVer[STP_PATCH_TIME_SIZE]; + UINT8 branchVer[STP_PATCH_BRANCH_SZIE]; + UINT32 wifiVer; + UINT32 count; + UINT32 stop_flag; + UINT32 buffer[STP_DBG_CPUPCR_NUM]; + UINT64 sec_buffer[STP_DBG_CPUPCR_NUM]; + ULONG nsec_buffer[STP_DBG_CPUPCR_NUM]; + UINT8 assert_info[STP_ASSERT_INFO_SIZE]; + UINT32 fwTaskId; + UINT32 fwRrq; + UINT32 fwIsr; + STP_DBG_HOST_ASSERT_T host_assert_info; + UINT8 assert_type[STP_ASSERT_TYPE_SIZE]; + ENUM_STP_FW_ISSUE_TYPE issue_type; + UINT8 keyword[STP_DBG_KEYWORD_SIZE]; + OSAL_SLEEPABLE_LOCK lock; +} STP_DBG_CPUPCR_T, *P_STP_DBG_CPUPCR_T; + +typedef struct stp_dbg_dmaregs_t { + UINT32 count; + UINT32 dmaIssue[DMA_REGS_MAX][STP_DBG_DMAREGS_NUM]; + OSAL_SLEEPABLE_LOCK lock; +} STP_DBG_DMAREGS_T, *P_STP_DBG_DMAREGS_T; + +typedef enum _ENUM_ASSERT_INFO_PARSER_TYPE_ { + STP_DBG_ASSERT_INFO = 0x0, + STP_DBG_FW_TASK_ID = 0x1, + STP_DBG_FW_ISR = 0x2, + STP_DBG_FW_IRQ = 0x3, + STP_DBG_ASSERT_TYPE = 0x4, + STP_DBG_PARSER_TYPE_MAX +} ENUM_ASSERT_INFO_PARSER_TYPE, *P_ENUM_ASSERT_INFO_PARSER_TYPE; + +VOID stp_dbg_nl_init(VOID); +VOID stp_dbg_nl_deinit(VOID); +INT32 stp_dbg_core_dump_deinit_gcoredump(VOID); +INT32 stp_dbg_core_dump_flush(INT32 rst, MTK_WCN_BOOL coredump_is_timeout); +INT32 stp_dbg_core_dump(INT32 dump_sink); +INT32 stp_dbg_trigger_collect_ftrace(PUINT8 pbuf, INT32 len); +#if BTIF_RXD_BE_BLOCKED_DETECT +MTK_WCN_BOOL stp_dbg_is_btif_rxd_be_blocked(VOID); +#endif +INT32 stp_dbg_enable(MTKSTP_DBG_T *stp_dbg); +INT32 stp_dbg_disable(MTKSTP_DBG_T *stp_dbg); +INT32 stp_dbg_dmp_print(MTKSTP_DBG_T *stp_dbg); +INT32 stp_dbg_dmp_out(MTKSTP_DBG_T *stp_dbg, PINT8 buf, PINT32 len); +INT32 stp_dbg_dmp_append(MTKSTP_DBG_T *stp_dbg, PUINT8 pBuf, INT32 max_len); + +INT32 stp_dbg_dmp_out_ex(PINT8 buf, PINT32 len); +INT32 stp_dbg_log_pkt(MTKSTP_DBG_T *stp_dbg, INT32 dbg_type, + INT32 type, INT32 ack_no, INT32 seq_no, INT32 crc, INT32 dir, INT32 len, + const PUINT8 body); +INT32 stp_dbg_log_ctrl(UINT32 on); +INT32 stp_dbg_aee_send(PUINT8 aucMsg, INT32 len, INT32 cmd); +INT32 stp_dbg_dump_num(LONG dmp_num); +INT32 stp_dbg_nl_send(PINT8 aucMsg, UINT8 cmd, INT32 len); +INT32 stp_dbg_dump_send_retry_handler(PINT8 tmp, INT32 len); +VOID stp_dbg_set_coredump_timer_state(CORE_DUMP_STA state); +INT32 stp_dbg_get_coredump_timer_state(VOID); +INT32 stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd); +INT32 stp_dbg_poll_dmaregs(UINT32 times, UINT32 sleep); +INT32 stp_dbg_poll_cpupcr_ctrl(UINT32 en); +INT32 stp_dbg_set_version_info(UINT32 chipid, PUINT8 pRomVer, PUINT8 pPatchVer, PUINT8 pPatchBrh); +INT32 stp_dbg_set_wifiver(UINT32 wifiver); +INT32 stp_dbg_set_host_assert_info(UINT32 drv_type, UINT32 reason, UINT32 en); +VOID stp_dbg_set_keyword(PINT8 keyword); +UINT32 stp_dbg_get_host_trigger_assert(VOID); +INT32 stp_dbg_set_fw_info(PUINT8 issue_info, UINT32 len, ENUM_STP_FW_ISSUE_TYPE issue_type); +INT32 stp_dbg_cpupcr_infor_format(PUINT8 buf, UINT32 max_len); +INT32 stp_dbg_dump_cpupcr_reg_info(PUINT8 buf, UINT32 consys_lp_reg); +VOID stp_dbg_clear_cpupcr_reg_info(VOID); +PUINT8 stp_dbg_id_to_task(UINT32 id); +VOID stp_dbg_reset(VOID); + +MTKSTP_DBG_T *stp_dbg_init(PVOID btm_half); +INT32 stp_dbg_deinit(MTKSTP_DBG_T *stp_dbg); +INT32 stp_dbg_start_coredump_timer(VOID); +INT32 stp_dbg_start_emi_dump(VOID); +INT32 stp_dbg_stop_emi_dump(VOID); +INT32 stp_dbg_nl_send_data(const PINT8 buf, INT32 len); +#endif /* end of _STP_DEBUG_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg_combo.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg_combo.h new file mode 100644 index 00000000000000..ab5a137e56cfaa --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg_combo.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _STP_DEBUG_COMBO_H_ +#define _STP_DEBUG_COMBO_H_ + +#include <linux/time.h> +#include "osal.h" + +INT32 stp_dbg_combo_core_dump(INT32 dump_sink); +PUINT8 stp_dbg_combo_id_to_task(UINT32 id); + +#endif /* end of _STP_DEBUG_COMBO_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg_soc.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg_soc.h new file mode 100644 index 00000000000000..6c070f9a88d3dd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_dbg_soc.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _STP_DEBUG_SOC_H_ +#define _STP_DEBUG_SOC_H_ + +#include <linux/time.h> +#include "osal.h" +#include "wmt_plat.h" + +#define STP_DBG_PAGED_DUMP_BUFFER_SIZE (32*1024*sizeof(char)) + +INT32 stp_dbg_soc_core_dump(INT32 dump_sink); +PUINT8 stp_dbg_soc_id_to_task(UINT32 id); +UINT32 stp_dbg_soc_read_debug_crs(ENUM_CONNSYS_DEBUG_CR cr); +INT32 stp_dbg_soc_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd); + +#endif /* end of _STP_DEBUG_SOC_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_sdio.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_sdio.h new file mode 100644 index 00000000000000..35fcacdb0a19e4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/stp_sdio.h @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/* + * Id: + */ + +/*! \file "stp_sdio.h" + * \brief + */ + +/* + * Log: + */ + +#ifndef _STP_SDIO_H +#define _STP_SDIO_H +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + + +#define KMALLOC_UPDATE 1 + +#if 0 /* NO support for multiple STP-SDIO instances (multiple MT6620) on a single host */ +#define STP_SDIO_HOST_COUNT (1) +#define STP_SDIO_ONLY_ONE_HOST (0) +#endif +#define STP_SDIO_POLL_OWNBACK_INTR (1) + +#define STP_SDIO_NEW_TXRING (0) +/* George: Keep old (0) codes for debugging only! + * Use new code (1) for SQC and MP! + */ + +#define STP_SDIO_OWN_THREAD (1) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "osal.h" +#include "hif_sdio.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +/* Common HIF register address */ +#define CCIR (0x0000) +#define CHLPCR (0x0004) +#define CSDIOCSR (0x0008) +#define CHCR (0x000c) +#define CHISR (0x0010) +#define CHIER (0x0014) +#define CTDR (0x0018) +#define CRDR (0x001c) +#define CTFSR (0x0020) +#define CRPLR (0x0024) +#define CTMDPCR0 (0x00B8) +#define CTMDPCR1 (0x00BC) +#define CSR (0x00D8) /* MT6630 & MT6632 only for the moment */ + + + +/* Common HIF register bit field address */ +/* CCCR_F0*/ +#define CCCR_F0_RX_CRC (0x1) +#define CCCR_F0_RX_INT (0x8) + +/* CHLPCR */ +#define C_FW_OWN_REQ_CLR (0x00000200) +#define C_FW_OWN_REQ_SET (0x00000100) +#define C_FW_INT_EN_CLR (0x00000002) +#define C_FW_INT_EN_SET (0x00000001) +#define C_FW_COM_DRV_OWN (0x00000100) + +/* CHIER */ +#define CHISR_EN_15_7 (0x0000ff80) +#define CHISR_EN_3_0 (0x0000000f) +/* CHISR */ +#define RX_PKT_LEN (0xffff0000) +#define FIRMWARE_INT (0x0000fe00) +#define TX_RETRY (0x00000200) +#define TX_FIFO_OVERFLOW (0x00000100) +#define FW_INT_IND_INDICATOR (0x00000080) +#define TX_COMPLETE_COUNT (0x00000070) +#define TX_UNDER_THOLD (0x00000008) +#define TX_EMPTY (0x00000004) +#define RX_DONE (0x00000002) +#define FW_OWN_BACK_INT (0x00000001) + +/* hardware settings */ +#define STP_SDIO_TX_FIFO_SIZE (2080UL) +#define STP_SDIO_RX_FIFO_SIZE (2304UL) /* 256*9 */ +#define STP_SDIO_TX_PKT_MAX_CNT (7) /* Max outstanding tx pkt count, as defined in TX_COMPLETE_COUNT */ +#define STP_SDIO_HDR_SIZE (4) /* hw,fw,sw follow the same format: 2 bytes length + 2 bytes reserved */ + +#define STP_SDIO_DBG_SUPPORT 1 +#define STP_SDIO_RXDBG 1 /* depends on STP_SDIO_DBG_SUPPORT */ +#define STP_SDIO_TXDBG 1 /* depends on STP_SDIO_DBG_SUPPORT */ +#define STP_TXDBG 1 + +/* sdio bus settings */ +#define STP_SDIO_BLK_SIZE (512UL) + +/* software driver settings */ +#define STP_SDIO_TX_BUF_CNT (16UL) /*(7) */ +#define STP_SDIO_TX_BUF_CNT_MASK (STP_SDIO_TX_BUF_CNT - 1) +#define STP_SDIO_TX_PKT_LIST_SIZE (STP_SDIO_TX_BUF_CNT) /* must be 2^x now... */ +#define STP_SDIO_TX_PKT_LIST_SIZE_MASK (STP_SDIO_TX_PKT_LIST_SIZE - 1) + +#define STP_SDIO_FW_CPUPCR_POLLING_CNT (5) + +#define STP_SDIO_RETRY_LIMIT (10) +#define STP_SDIO_MAX_RETRY_NUM (100) + +#define STP_SDIO_RETRY_NONE (0) +#define STP_SDIO_RETRY_CRC_ERROR (1) +#define STP_SDIO_RETRY_INT (2) + +/* tx buffer size for a single entry */ +/* George: SHALL BE a multiple of the used BLK_SIZE!! */ +#if 1 +/* round up: 512*5 = 2560 > 2080 */ +#define STP_SDIO_TX_ENTRY_SIZE ((STP_SDIO_TX_FIFO_SIZE + (STP_SDIO_BLK_SIZE - 1)) & ~(STP_SDIO_BLK_SIZE - 1)) +#else +/* round down: 512*4 = 2048 < 2080 */ +#define STP_SDIO_TX_MAX_BLK_CNT (STP_SDIO_TX_FIFO_SIZE / STP_SDIO_BLK_SIZE) +#define STP_SDIO_TX_ENTRY_SIZE (STP_SDIO_TX_MAX_BLK_CNT * STP_SDIO_BLK_SIZE) +#endif + +/*software rx buffer size */ +/*#define STP_SDIO_RX_BUF_SIZE (STP_SDIO_RX_FIFO_SIZE)*/ +/* George: SHALL BE a multiple of the used BLK_SIZE!! */ +#if 1 +/* round up: 512*5 = 2560 > 2304 */ +#define STP_SDIO_RX_BUF_SIZE ((STP_SDIO_RX_FIFO_SIZE + (STP_SDIO_BLK_SIZE - 1)) & ~(STP_SDIO_BLK_SIZE - 1)) +#else +/* round down: 512*4 = 2048 < 2304 */ +#define STP_SDIO_RX_MAX_BLK_CNT (STP_SDIO_RX_FIFO_SIZE / STP_SDIO_BLK_SIZE) +#define STP_SDIO_RX_BUF_SIZE (STP_SDIO_RX_MAX_BLK_CNT * STP_SDIO_BLK_SIZE) +#endif + +#define COHEC_00006052 (1) +/* #define COHEC_00006052 (0) */ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_STP_SDIO_HIF_TYPE_T { + HIF_TYPE_READB = 0, + HIF_TYPE_READL = HIF_TYPE_READB + 1, + HIF_TYPE_READ_BUF = HIF_TYPE_READL + 1, + HIF_TYPE_WRITEB = HIF_TYPE_READ_BUF + 1, + HIF_TYPE_WRITEL = HIF_TYPE_WRITEB + 1, + HIF_TYPE_WRITE_BUF = HIF_TYPE_WRITEL + 1, + HIF_TYPE_MAX +} ENUM_STP_SDIO_HIF_TYPE_T, *P_ENUM_STP_SDIO_HIF_TYPE_T; + +/* HIF's local packet buffer variables for Tx/Rx */ +typedef struct _MTK_WCN_STP_SDIO_PKT_BUF { + /* Tx entry ring buffer. Entry size is aligned to SDIO block size. */ +#if KMALLOC_UPDATE + PUINT8 tx_buf; +#else + UINT8 tx_buf[STP_SDIO_TX_BUF_CNT][STP_SDIO_TX_ENTRY_SIZE]; +#endif + + /* Tx size ring buffer. Record valid data size in tx_buf. */ + UINT32 tx_buf_sz[STP_SDIO_TX_BUF_CNT]; + /* Tx debug timestamp: 1st time when the entry is filled with data */ + UINT32 tx_buf_ts[STP_SDIO_TX_BUF_CNT]; + UINT64 tx_buf_local_ts[STP_SDIO_TX_BUF_CNT]; + ULONG tx_buf_local_nsec[STP_SDIO_TX_BUF_CNT]; + +#if KMALLOC_UPDATE + PUINT8 rx_buf; +#else + UINT8 rx_buf[STP_SDIO_RX_BUF_SIZE]; /* Rx buffer (not ring) */ +#endif +#if STP_SDIO_NEW_TXRING + atomic_t wr_cnt; /* Tx entry ring buffer write count */ + atomic_t rd_cnt; /* Tx entry ring buffer read count */ + spinlock_t rd_cnt_lock; /* Tx entry ring buffer read count spin lock */ +#else + atomic_t wr_idx; /* Tx ring buffer write index *//*George: obsolete */ + atomic_t rd_idx; /* Tx ring buffer read index *//*George: obsolete */ + spinlock_t rd_idx_lock; /* spin lock for Tx ring buffer read index */ +#endif + MTK_WCN_BOOL full_flag; /* Tx entry ring buffer full flag (TRUE: full, FALSE: not full) */ + /* save interrupt status flag for Tx entry ring buf spin lock */ + ULONG rd_irq_flag; + /* wait queue head for Tx entry ring buf full case */ + wait_queue_head_t fullwait_q; +} MTK_WCN_STP_SDIO_PKT_BUF; + +/* Tx packet list information */ +typedef struct _MTK_WCN_STP_SDIO_Tx_Pkt_LIST { + UINT32 pkt_rd_cnt; + UINT32 pkt_wr_cnt; + UINT16 pkt_size_list[STP_SDIO_TX_PKT_LIST_SIZE]; /*max length is FIFO Size */ + UINT32 out_ts[STP_SDIO_TX_PKT_LIST_SIZE]; + UINT32 in_ts[STP_SDIO_TX_PKT_LIST_SIZE]; +} MTK_WCN_STP_SDIO_Tx_Pkt_LIST; + +/* STP HIF firmware information */ +typedef struct _MTK_WCN_STP_SDIO_FIRMWARE_INFO { + UINT32 tx_fifo_size; /* Current left tx FIFO size */ + UINT32 tx_packet_num; /* Current outstanding tx packet (0~7) */ + atomic_t tx_comp_num; /* Current total tx ok but fifo size not released packet count */ +} MTK_WCN_STP_SDIO_FIRMWARE_INFO; + +/* STP SDIO private information */ +typedef struct _MTK_WCN_STP_SDIO_PRIVATE_INFO { + UINT8 stp_sdio_host_idx; +} MTK_WCN_STP_SDIO_PRIVATE_INFO; + +/* STP SDIO host information */ +typedef struct _MTK_WCN_STP_SDIO_HIF_INFO { + MTK_WCN_HIF_SDIO_CLTCTX sdio_cltctx; + MTK_WCN_STP_SDIO_PKT_BUF pkt_buf; + MTK_WCN_STP_SDIO_Tx_Pkt_LIST tx_pkt_list; + UINT32 rx_pkt_len; /* George: use 32-bit for efficiency. Correct name to pkt for packet */ + MTK_WCN_STP_SDIO_FIRMWARE_INFO firmware_info; + MTK_WCN_STP_SDIO_PRIVATE_INFO private_info; +#if STP_SDIO_OWN_THREAD + /* struct tasklet_struct tx_rx_job; */ + OSAL_THREAD tx_rx_thread; + INT32 irq_pending; + INT32 sleep_flag; + INT32 wakeup_flag; + INT32 awake_flag; + INT32 txwkr_flag; + OSAL_EVENT tx_rx_event; + OSAL_SIGNAL isr_check_complete; + INT32 dump_flag; +#endif + INT32 tx_dbg_dump_flag; + INT32 tx_retry_flag; + INT32 retry_enable_flag; + INT32 tx_retry_count; + INT32 rx_retry_count; + struct work_struct tx_work; + struct work_struct rx_work; +} MTK_WCN_STP_SDIO_HIF_INFO; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +extern MTK_WCN_STP_SDIO_HIF_INFO g_stp_sdio_host_info; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* STP_SDIO_TX_PKT_LIST_SIZE must be 2^x */ +#define STP_SDIO_GET_PKT_AR_IDX(idx) ((idx) & STP_SDIO_TX_PKT_LIST_SIZE_MASK) + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/*! + * \brief MTK hif sdio client registration function + * + * Client uses this function to do hif sdio registration + * + * \param pinfo a pointer of client's information + * + * \retval 0 register successfully + * \retval < 0 error code + */ +extern INT32 mtk_wcn_hif_sdio_client_reg(const MTK_WCN_HIF_SDIO_CLTINFO *pinfo); +extern INT32 stp_sdio_reg_rw(INT32 func_num, INT32 direction, UINT32 offset, UINT32 value); + +#if STP_SDIO_DBG_SUPPORT && (STP_SDIO_TXDBG || STP_SDIO_TXPERFDBG) +VOID stp_sdio_txdbg_dump(VOID); +#endif + +extern INT32 mtk_wcn_stp_sdio_do_own_clr(VOID); +extern INT32 mtk_wcn_stp_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx); +extern INT32 mtk_wcn_stp_sdio_drv_init(VOID); +extern VOID mtk_wcn_stp_sdio_drv_exit(VOID); +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +INT32 stp_sdio_deep_sleep_flag_set(MTK_WCN_BOOL flag); +#endif +/* extern INT32 */ +/* mtk_wcn_stp_sdio_do_own_set (void); */ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 stp_sdio_rw_retry(ENUM_STP_SDIO_HIF_TYPE_T type, UINT32 retry_limit, + MTK_WCN_HIF_SDIO_CLTCTX clt_ctx, UINT32 offset, PUINT32 pData, UINT32 len); +VOID stp_sdio_retry_flag_ctrl(INT32 flag); +INT32 stp_sdio_retry_flag_get(VOID); +INT32 stp_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx); +VOID stp_sdio_dump_register(VOID); +INT32 stp_sdio_issue_fake_coredump(UINT8 *str); +VOID stp_sdio_dump_info(MTK_WCN_STP_SDIO_HIF_INFO *p_info); +INT32 stp_sdio_own_ctrl(SDIO_PS_OP op); +INT32 stp_sdio_tx(const PUINT8 data, const UINT32 size, PUINT32 written_size); +INT32 stp_sdio_rxdbg_setup(VOID); +INT32 stp_sdio_rxdbg_remove(VOID); +INT32 stp_sdio_txdbg_setup(VOID); +INT32 stp_sdio_txdbg_remove(VOID); +INT32 stp_sdio_owndbg_setup(VOID); +INT32 stp_sdio_owndbg_remove(VOID); + +#endif /* _STP_SDIO_H */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_dbg.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_dbg.h new file mode 100644 index 00000000000000..729a8a4aa7d82a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_dbg.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _WMT_DBG_H_ +#define _WMT_DBG_H_ +#include "osal.h" + +#define STP_SDIO 0x04 +#define STP_UART_MAND 0x02 +#define STP_UART_FULL 0x01 + +#define CFG_WMT_DBG_SUPPORT 1 /* support wmt_dbg or not */ +#define CFG_WMT_PROC_FOR_AEE 1 + +#if CFG_WMT_DBG_SUPPORT +typedef struct _COEX_BUF { + UINT8 buffer[128]; + INT32 availSize; +} COEX_BUF, *P_COEX_BUF; + +typedef enum _ENUM_CMD_TYPE_T { + WMTDRV_CMD_ASSERT = 0, + WMTDRV_CMD_EXCEPTION = 1, + WMTDRV_CMD_COEXDBG_00 = 2, + WMTDRV_CMD_COEXDBG_01 = 3, + WMTDRV_CMD_COEXDBG_02 = 4, + WMTDRV_CMD_COEXDBG_03 = 5, + WMTDRV_CMD_COEXDBG_04 = 6, + WMTDRV_CMD_COEXDBG_05 = 7, + WMTDRV_CMD_COEXDBG_06 = 8, + WMTDRV_CMD_COEXDBG_07 = 9, + WMTDRV_CMD_COEXDBG_08 = 10, + WMTDRV_CMD_COEXDBG_09 = 11, + WMTDRV_CMD_COEXDBG_10 = 12, + WMTDRV_CMD_COEXDBG_11 = 13, + WMTDRV_CMD_COEXDBG_12 = 14, + WMTDRV_CMD_COEXDBG_13 = 15, + WMTDRV_CMD_COEXDBG_14 = 16, + WMTDRV_CMD_COEXDBG_15 = 17, + WMTDRV_CMD_NOACK_TEST = 18, + WMTDRV_CMD_WARNRST_TEST = 19, + WMTDRV_CMD_FWTRACE_TEST = 20, + WMTDRV_CMD_MAX +} ENUM_WMTDRV_CMD_T, *P_ENUM_WMTDRV_CMD_T; + + +typedef INT32(*WMT_DEV_DBG_FUNC) (INT32 par1, INT32 par2, INT32 par3); +INT32 wmt_dev_dbg_setup(VOID); +INT32 wmt_dev_dbg_remove(VOID); +INT32 wmt_dbg_fwinfor_from_emi(INT32 par1, INT32 par2, INT32 par3); + +#endif /* CFG_WMT_DBG_SUPPORT */ +#endif /* _WMT_DBG_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_dev.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_dev.h new file mode 100644 index 00000000000000..76c670926dd7d2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_dev.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _WMT_DEV_H_ +#define _WMT_DEV_H_ + +#include "osal.h" + +#define STP_UART_FULL 0x01 +#define STP_UART_MAND 0x02 +#define STP_BTIF_FULL 0x03 +#define STP_SDIO 0x04 + +#define CFG_WMT_PROC_FOR_AEE 1 +#define CFG_WMT_PROC_FOR_DUMP_INFO 1 + +VOID wmt_dev_rx_event_cb(VOID); +INT32 wmt_dev_rx_timeout(P_OSAL_EVENT pEvent); +INT32 wmt_dev_patch_get(PUINT8 pPatchName, osal_firmware **ppPatch); +INT32 wmt_dev_patch_put(osal_firmware **ppPatch); +MTK_WCN_BOOL wmt_dev_is_file_exist(PUINT8 pFileName); +VOID wmt_dev_patch_info_free(VOID); +VOID wmt_dev_send_cmd_to_daemon(UINT32 cmd); +MTK_WCN_BOOL wmt_dev_get_early_suspend_state(VOID); +INT32 wmt_lpbk_handler(UINT32 on_off_flag, UINT32 retry); +VOID wmt_dev_blank_handler(VOID); +UINT32 wmt_dev_get_blank_state(VOID); +INT32 wmt_dev_apo_ctrl(UINT32 enable); +VOID wmt_dev_set_temp_threshold(INT32 val); +UINT8 wmt_dev_is_close(VOID); +extern LONG wmt_dev_tm_temp_query(VOID); +extern INT32 wmt_dev_tra_bitf_update(VOID); +extern INT32 wmt_dev_tra_uart_update(VOID); + +INT32 mtk_wcn_common_drv_init(VOID); +VOID mtk_wcn_common_drv_exit(VOID); + +ssize_t WMT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); +ssize_t WMT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); +UINT32 WMT_poll(struct file *filp, poll_table *wait); +LONG WMT_unlocked_ioctl(struct file *filp, UINT32 cmd, ULONG arg); +LONG WMT_compat_ioctl(struct file *filp, UINT32 cmd, ULONG arg); + +VOID wmt_dev_bgw_desense_init(VOID); +VOID wmt_dev_bgw_desense_deinit(VOID); + +#endif /*_WMT_DEV_H_*/ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_idc.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_idc.h new file mode 100644 index 00000000000000..200e75b828a681 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_idc.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _WMT_IDC_H_ +#define _WMT_IDC_H_ + +//#include "osal.h" +#include "stp_exp.h" + +#if CFG_WMT_LTE_COEX_HANDLING + +#include <connectivity_build_in_adapter.h> +#include "conn_md_exp.h" + +#define LTE_IDC_BUFFER_MAX_SIZE 1024 +/*comment from firmware owner,max pckage num is 5,but should not happened*/ +#define WMT_IDC_RX_MAX_LEN 384 +#define LTE_MSG_ID_OFFSET 0x30 + +typedef enum { + WMT_IDC_TX_OPCODE_MIN = 0, + WMT_IDC_TX_OPCODE_LTE_PARA = 0x0a, + WMT_IDC_TX_OPCODE_LTE_FREQ = 0x0b, + WMT_IDC_TX_OPCODE_WIFI_MAX_POWER = 0x0c, + WMT_IDC_TX_OPCODE_DEBUG_MONITOR = 0x0e, + WMT_IDC_TX_OPCODE_SPLIT_FILTER = 0x0f, + WMT_IDC_TX_OPCODE_LTE_CONNECTION_STAS = 0x16, + WMT_IDC_TX_OPCODE_LTE_HW_IF_INDICATION = 0x17, + WMT_IDC_TX_OPCODE_LTE_INDICATION = 0x20, + WMT_IDC_TX_OPCODE_MAX +} WMT_IDC_TX_OPCODE; + +typedef enum { + WMT_IDC_RX_OPCODE_BTWF_DEF_PARA = 0x0, + WMT_IDC_RX_OPCODE_BTWF_CHAN_RAN = 0x1, + /* WMT_IDC_RX_OPCODE_TDM_REQ = 0x10, */ + WMT_IDC_RX_OPCODE_DEBUG_MONITOR = 0x02, + WMT_IDC_RX_OPCODE_LTE_FREQ_IDX_TABLE = 0x03, + WMT_IDC_RX_OPCODE_BTWF_PROFILE_IND = 0x04, + WMT_IDC_RX_OPCODE_UART_PIN_SEL = 0x05, + WMT_IDC_RX_OPCODE_MAX +} WMT_IDC_RX_OPCODE; + +#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING +typedef enum { + IPC_L4C_MSG_ID_INVALID = IPC_L4C_MSG_ID_BEGIN, + IPC_L4C_MSG_ID_END, + IPC_EL1_MSG_ID_INVALID = IPC_EL1_MSG_ID_BEGIN, + /* below are EL1 IPC messages sent from AP */ + IPC_MSG_ID_EL1_LTE_TX_ALLOW_IND, + IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND, + IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND, + IPC_MSG_ID_EL1_WIFIBT_FREQ_IDX_TABLE_IND, + IPC_MSG_ID_EL1_WIFIBT_PROFILE_IND, + + /* below are EL1 messages sent to AP */ + IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND, + IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND, + IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND, + IPC_MSG_ID_EL1_LTE_TX_IND, + IPC_MSG_ID_EL1_LTE_CONNECTION_STATUS_IND, + IPC_MSG_ID_EL1_PIN_TYPE_IND, + IPC_MSG_ID_EL1_LTE_HW_INTERFACE_IND, + IPC_MSG_ID_EL1_DUMMY13_IND, + IPC_MSG_ID_EL1_DUMMY14_IND, + IPC_MSG_ID_EL1_DUMMY15_IND, + IPC_MSG_ID_EL1_DUMMY16_IND, + IPC_MSG_ID_EL1_DUMMY17_IND, + IPC_MSG_ID_EL1_DUMMY18_IND, + IPC_MSG_ID_EL1_DUMMY19_IND, + IPC_MSG_ID_EL1_DUMMY20_IND, + IPC_MSG_ID_EL1_DUMMY21_IND, + IPC_MSG_ID_EL1_DUMMY22_IND, + IPC_MSG_ID_EL1_DUMMY23_IND, + IPC_MSG_ID_EL1_DUMMY24_IND, + IPC_MSG_ID_EL1_DUMMY25_IND, + IPC_MSG_ID_EL1_DUMMY26_IND, + IPC_MSG_ID_EL1_DUMMY27_IND, + IPC_MSG_ID_EL1_DUMMY28_IND, + IPC_MSG_ID_EL1_DUMMY29_IND, + IPC_MSG_ID_EL1_DUMMY30_IND, + IPC_MSG_ID_MD_CONSYS_VERIFICATION_IND, + IPC_MSG_ID_MD_CONSYS_VERIFICATION_REQ, + IPC_EL1_MSG_ID_END, +} IPC_MSG_ID_CODE; +#endif + +typedef struct _MTK_WCN_WMT_IDC_INFO_ { + conn_md_ipc_ilm_t iit; + CONN_MD_BRIDGE_OPS /*struct conn_md_bridge_ops*/ ops; + UINT8 buffer[LTE_IDC_BUFFER_MAX_SIZE]; +} MTK_WCN_WMT_IDC_INFO, *P_MTK_WCN_WMT_IDC_INFO; + +INT32 wmt_idc_init(VOID); +INT32 wmt_idc_deinit(VOID); +INT32 wmt_idc_msg_from_lte_handing(conn_md_ipc_ilm_t *ilm); +INT32 wmt_idc_msg_to_lte_handing(VOID); +UINT32 wmt_idc_msg_to_lte_handing_for_test(PUINT8 p_buf, UINT32 len); + +#endif /* endif CFG_WMT_LTE_COEX_HANDLING */ + +#endif /* _WMT_IDC_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_step.h b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_step.h new file mode 100644 index 00000000000000..1a02d6cf8343c0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/include/wmt_step.h @@ -0,0 +1,372 @@ +/* + * Copyright (C) 2016 MediaTek Inc. * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _WMT_STEP_H_ +#define _WMT_STEP_H_ + +#include <linux/list.h> + +#include "osal.h" +#include "wmt_exp.h" +#include "wmt_core.h" + +#define STEP_CONFIG_NAME "WMT_STEP.cfg" +#define STEP_VERSION 2 + +#define STEP_PERIODIC_DUMP_WORK_QUEUE "wmt_step_pd_wq" +#define STEP_PERIODIC_DUMP_THREAD "wmt_pd" + +#define STEP_ACTION_NAME_EMI "_EMI" +#define STEP_ACTION_NAME_REGISTER "_REG" +#define STEP_ACTION_NAME_GPIO "GPIO" +#define STEP_ACTION_NAME_DISABLE_RESET "DRST" +#define STEP_ACTION_NAME_CHIP_RESET "_RST" +#define STEP_ACTION_NAME_KEEP_WAKEUP "WAK+" +#define STEP_ACTION_NAME_CANCEL_WAKEUP "WAK-" +#define STEP_ACTION_NAME_SHOW_STRING "SHOW" +#define STEP_ACTION_NAME_SLEEP "_SLP" +#define STEP_ACTION_NAME_CONDITION "COND" +#define STEP_ACTION_NAME_VALUE "_VAL" +#define STEP_ACTION_NAME_CONDITION_EMI "CEMI" +#define STEP_ACTION_NAME_CONDITION_REGISTER "CREG" + +extern struct platform_device *g_pdev; + +enum step_action_id { + STEP_ACTION_INDEX_NO_DEFINE = 0, + STEP_ACTION_INDEX_EMI = 1, + STEP_ACTION_INDEX_REGISTER, + STEP_ACTION_INDEX_GPIO, + STEP_ACTION_INDEX_DISABLE_RESET, + STEP_ACTION_INDEX_CHIP_RESET, + STEP_ACTION_INDEX_KEEP_WAKEUP, + STEP_ACTION_INDEX_CANCEL_WAKEUP, + STEP_ACTION_INDEX_PERIODIC_DUMP, + STEP_ACTION_INDEX_SHOW_STRING, + STEP_ACTION_INDEX_SLEEP, + STEP_ACTION_INDEX_CONDITION, + STEP_ACTION_INDEX_VALUE, + STEP_ACTION_INDEX_CONDITION_EMI, + STEP_ACTION_INDEX_CONDITION_REGISTER, + STEP_ACTION_INDEX_MAX, +}; + +enum step_trigger_point_id { + STEP_TRIGGER_POINT_NO_DEFINE = 0, + STEP_TRIGGER_POINT_COMMAND_TIMEOUT = 1, + STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT, + STEP_TRIGGER_POINT_BEFORE_CHIP_RESET, + STEP_TRIGGER_POINT_AFTER_CHIP_RESET, + STEP_TRIGGER_POINT_BEFORE_WIFI_FUNC_ON, + STEP_TRIGGER_POINT_BEFORE_WIFI_FUNC_OFF, + STEP_TRIGGER_POINT_BEFORE_BT_FUNC_ON, + STEP_TRIGGER_POINT_BEFORE_BT_FUNC_OFF, + STEP_TRIGGER_POINT_BEFORE_FM_FUNC_ON, + STEP_TRIGGER_POINT_BEFORE_FM_FUNC_OFF, + STEP_TRIGGER_POINT_BEFORE_GPS_FUNC_ON, + STEP_TRIGGER_POINT_BEFORE_GPS_FUNC_OFF, + STEP_TRIGGER_POINT_BEFORE_READ_THERMAL, + STEP_TRIGGER_POINT_POWER_ON_START, + STEP_TRIGGER_POINT_POWER_ON_BEFORE_GET_CONNSYS_ID, + STEP_TRIGGER_POINT_POWER_ON_BEFORE_SEND_DOWNLOAD_PATCH, + STEP_TRIGGER_POINT_POWER_ON_BEFORE_CONNSYS_RESET, + STEP_TRIGGER_POINT_POWER_ON_BEFORE_SET_WIFI_LTE_COEX, + STEP_TRIGGER_POINT_POWER_ON_BEFORE_BT_WIFI_CALIBRATION, + STEP_TRIGGER_POINT_POWER_ON_END, + STEP_TRIGGER_POINT_BEFORE_POWER_OFF, + STEP_TRIGGER_POINT_WHEN_AP_SUSPEND, + STEP_TRIGGER_POINT_WHEN_AP_RESUME, + STEP_TRIGGER_POINT_POWER_OFF_HANDSHAKE, + STEP_TRIGGER_POINT_BEFORE_RESTORE_CAL_RESULT, + STEP_TRIGGER_POINT_AFTER_RESTORE_CAL_RESULT, + STEP_TRIGGER_POINT_POWER_ON_AFTER_BT_WIFI_CALIBRATION, + STEP_TRIGGER_POINT_AFTER_RESTORE_CAL_CMD, + STEP_TRIGGER_POINT_WHEN_CLOCK_FAIL, + STEP_TRIGGER_POINT_MAX, +}; + +enum step_base_address_index { + STEP_MCU_BASE_INDEX = 0, + STEP_TOP_RGU_BASE_INDEX, + STEP_INFRACFG_AO_BASE_INDEX, + STEP_SPM_BASE_INDEX, + STEP_MCU_CONN_HIF_ON_BASE_INDEX, + STEP_MCU_TOP_MISC_OFF_BASE_INDEX, + STEP_MCU_CFG_ON_BASE_INDEX, + STEP_MCU_CIRQ_BASE_INDEX, + STEP_MCU_TOP_MISC_ON_BASE_INDEX, + STEP_BASE_ADDRESS_MAX, +}; + +enum step_register_base_id { + STEP_REGISTER_PHYSICAL_ADDRESS = 0, + STEP_REGISTER_CONN_MCU_CONFIG_BASE, + STEP_REGISTER_AP_RGU_BASE, + STEP_REGISTER_TOPCKGEN_BASE, + STEP_REGISTER_SPM_BASE, + STEP_REGISTER_HIF_ON_BASE, + STEP_REGISTER_MISC_OFF_BASE, + STEP_REGISTER_CFG_ON_BASE, + STEP_CIRQ_BASE, + STEP_MCU_TOP_MISC_ON_BASE, + STEP_REGISTER_MAX, +}; + +enum step_condition_operator_id { + STEP_OPERATOR_GREATER = 0, + STEP_OPERATOR_GREATER_EQUAL, + STEP_OPERATOR_LESS, + STEP_OPERATOR_LESS_EQUAL, + STEP_OPERATOR_EQUAL, + STEP_OPERATOR_NOT_EQUAL, + STEP_OPERATOR_AND, + STEP_OPERATOR_OR, + STEP_OPERATOR_MAX, +}; + +struct step_register_base_struct { + unsigned long vir_addr; + unsigned long long size; +}; + +struct step_action_list { + struct list_head list; +}; + +struct step_pd_entry { + bool is_enable; + unsigned int expires_ms; + struct step_action_list action_list; + struct delayed_work pd_work; + struct list_head list; +}; + +struct step_pd_struct { + bool is_init; + struct workqueue_struct *step_pd_wq; + struct list_head pd_list; +}; + +struct step_action { + struct list_head list; + enum step_action_id action_id; +}; + +typedef int (*STEP_WRITE_ACT_TO_LIST) (struct step_action_list *, enum step_action_id, int, char **); +typedef void (*STEP_DO_EXTRA) (unsigned int, ...); + +#define STEP_OUTPUT_LOG 0 +#define STEP_OUTPUT_REGISTER 1 + +struct step_emi_info { + bool is_write; + unsigned int begin_offset; + unsigned int end_offset; + int value; + unsigned int temp_reg_id; + int output_mode; + int mask; +}; + +struct step_emi_action { + struct step_emi_info info; + struct step_action base; +}; + +struct step_reigster_info { + bool is_write; + enum step_register_base_id address_type; + unsigned long address; + unsigned int offset; + unsigned int times; + unsigned int delay_time; + int value; + int mask; + unsigned int temp_reg_id; + int output_mode; +}; + +struct step_register_action { + struct step_reigster_info info; + struct step_action base; +}; + +struct step_gpio_action { + bool is_write; + unsigned int pin_symbol; + struct step_action base; +}; + +struct step_disable_reset_action { + struct step_action base; +}; + +struct step_chip_reset_action { + struct step_action base; +}; + +struct step_keep_wakeup_action { + struct step_action base; +}; + +struct step_cancel_wakeup_action { + struct step_action base; +}; + +struct step_periodic_dump_action { + struct step_pd_entry *pd_entry; + struct step_action base; +}; + +struct step_show_string_action { + char *content; + struct step_action base; +}; + +struct step_sleep_action { + unsigned int ms; + struct step_action base; +}; + +#define STEP_CONDITION_RIGHT_REGISTER 0 +#define STEP_CONDITION_RIGHT_VALUE 1 +struct step_condition_action { + unsigned int result_temp_reg_id; + unsigned int l_temp_reg_id; + unsigned int r_temp_reg_id; + int value; + int mode; + enum step_condition_operator_id operator_id; + struct step_action base; +}; + +struct step_value_action { + unsigned int temp_reg_id; + int value; + struct step_action base; +}; + +struct step_condition_emi_action { + unsigned int cond_reg_id; + struct step_emi_info info; + struct step_action base; +}; + +struct step_condition_register_action { + unsigned int cond_reg_id; + struct step_reigster_info info; + struct step_action base; +}; + +#define list_entry_action(act_struct, ptr) \ + container_of(ptr, struct step_##act_struct##_action, base) + +struct step_reg_addr_info { + int address_type; + unsigned long address; +}; + +struct step_target_act_list_info { + enum step_trigger_point_id tp_id; + struct step_action_list *p_target_list; + struct step_pd_entry *p_pd_entry; +}; + +#define STEP_PARAMETER_SIZE 10 +struct step_parse_line_data_param_info { + int state; + enum step_action_id act_id; + char *act_params[STEP_PARAMETER_SIZE]; + int param_index; +}; + +typedef struct step_action *(*STEP_CREATE_ACTION) (int, char *[]); +typedef int (*STEP_DO_ACTIONS) (struct step_action *, STEP_DO_EXTRA); +typedef void (*STEP_REMOVE_ACTION) (struct step_action *); +struct step_action_contrl { + STEP_CREATE_ACTION func_create_action; + STEP_DO_ACTIONS func_do_action; + STEP_REMOVE_ACTION func_remove_action; +}; + +#define STEP_REGISTER_BASE_SYMBOL '#' +#define STEP_TEMP_REGISTER_SYMBOL '$' + +#define STEP_VALUE_INFO_UNKNOWN -1 +#define STEP_VALUE_INFO_NUMBER 0 +#define STEP_VALUE_INFO_SYMBOL_REG_BASE 1 +#define STEP_VALUE_INFO_SYMBOL_TEMP_REG 2 + +#define STEP_TEMP_REGISTER_SIZE 10 +struct step_env_struct { + bool is_enable; + bool is_keep_wakeup; + struct step_action_list actions[STEP_TRIGGER_POINT_MAX]; + unsigned char __iomem *emi_base_addr; + struct step_register_base_struct reg_base[STEP_REGISTER_MAX]; + struct step_pd_struct pd_struct; + int temp_register[STEP_TEMP_REGISTER_SIZE]; + bool is_setup; + struct rw_semaphore init_rwsem; +}; + +/******************************************************************************** + * F U N C T I O N D E C L A R A T I O N S +*********************************************************************************/ +void wmt_step_init(void); +void wmt_step_deinit(void); +void wmt_step_do_actions(enum step_trigger_point_id tp_id); +void wmt_step_func_crtl_do_actions(ENUM_WMTDRV_TYPE_T type, ENUM_WMT_OPID_T opId); +void wmt_step_command_timeout_do_actions(char *reason); +#ifdef CFG_WMT_STEP +#define WMT_STEP_INIT_FUNC() wmt_step_init() +#define WMT_STEP_DEINIT_FUNC() wmt_step_deinit() +#define WMT_STEP_DO_ACTIONS_FUNC(tp) wmt_step_do_actions(tp) +#define WMT_STEP_FUNC_CTRL_DO_ACTIONS_FUNC(type, id) wmt_step_func_crtl_do_actions(type, id) +#define WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC(reason) wmt_step_command_timeout_do_actions(reason) +#else +#define WMT_STEP_INIT_FUNC() +#define WMT_STEP_DEINIT_FUNC() +#define WMT_STEP_DO_ACTIONS_FUNC(tp) +#define WMT_STEP_FUNC_CTRL_DO_ACTIONS_FUNC(type, id) +#define WMT_STEP_COMMAND_TIMEOUT_DO_ACTIONS_FUNC(reason) +#endif + +/******************************************************************************** + * D E C L A R E F O R T E S T +*********************************************************************************/ +int wmt_step_read_file(const char *file_name); +int wmt_step_parse_data(const char *in_buf, unsigned int size, STEP_WRITE_ACT_TO_LIST func_act_to_list); +int wmt_step_init_pd_env(void); +int wmt_step_deinit_pd_env(void); +struct step_pd_entry *wmt_step_get_periodic_dump_entry(unsigned int expires); +struct step_action *wmt_step_create_action(enum step_action_id act_id, int param_num, char *params[]); +int wmt_step_do_emi_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +int wmt_step_do_register_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +int wmt_step_do_gpio_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +int wmt_step_do_disable_reset_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +int wmt_step_do_chip_reset_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +int wmt_step_do_keep_wakeup_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +int wmt_step_do_cancel_wakeup_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +int wmt_step_do_periodic_dump_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +int wmt_step_do_show_string_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +int wmt_step_do_sleep_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +int wmt_step_do_condition_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +int wmt_step_do_value_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +int wmt_step_do_condition_emi_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +int wmt_step_do_condition_register_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra); +void wmt_step_remove_action(struct step_action *p_act); +void wmt_step_print_version(void); +void wmt_step_setup(void); + +#endif /* end of _WMT_STEP_H_ */ + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_btif.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_btif.c new file mode 100644 index 00000000000000..739b52c9c8f02c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_btif.c @@ -0,0 +1,280 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +/*file: stp_btif, mainly control stp & btif interaction*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[STP-BTIF]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "wmt_exp.h" +#include "stp_exp.h" +#include "stp_btif.h" + +#include <asm/current.h> +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define BTIF_OWNER_NAME "CONSYS_STP" + +#define STP_MAX_PACKAGE_ALLOWED (2000) + +#define STP_BTIF_TX_RTY_LMT (10) +#define STP_BTIF_TX_RTY_DLY (5) +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +unsigned long stpBtifId = 0; +unsigned long *pBtifRef = &stpBtifId; +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +INT32 mtk_wcn_consys_stp_btif_open(VOID) +{ + INT32 iRet = -1; + + iRet = mtk_wcn_btif_open(BTIF_OWNER_NAME, pBtifRef); + if (iRet) { + WMT_WARN_FUNC("STP open btif fail(%d)\n", iRet); + return -1; + } + WMT_DBG_FUNC("STP open bitf OK\n"); + + mtk_wcn_stp_register_if_tx(STP_BTIF_IF_TX, (MTK_WCN_STP_IF_TX) mtk_wcn_consys_stp_btif_tx); + + return 0; +} + +INT32 mtk_wcn_consys_stp_btif_close(VOID) +{ + INT32 iRet = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + iRet = -1; + } else { + iRet = mtk_wcn_btif_close(stpBtifId); + if (iRet) { + WMT_WARN_FUNC("STP close btif fail(%d)\n", iRet); + iRet = -2; + } else { + stpBtifId = 0; + WMT_DBG_FUNC("STP close btif OK\n"); + } + } + return iRet; +} + +INT32 mtk_wcn_consys_stp_btif_rx_cb_register(MTK_WCN_BTIF_RX_CB rx_cb) +{ + INT32 iRet = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference\n!"); + iRet = -1; + } else { + iRet = mtk_wcn_btif_rx_cb_register(stpBtifId, rx_cb); + if (iRet) { + WMT_WARN_FUNC("STP register rxcb to btif fail(%d)\n", iRet); + iRet = -2; + } else { + WMT_DBG_FUNC("STP register rxcb to btif OK\n"); + } + } + return iRet; +} + +INT32 mtk_wcn_consys_stp_btif_tx(UINT8 * const pBuf, const UINT32 len, UINT32 *written_len) +{ + INT32 retry_left = STP_BTIF_TX_RTY_LMT; + INT32 wr_count = 0; + INT32 written = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + return -1; + } + + if (len == 0) { + *written_len = 0; + WMT_INFO_FUNC("special case for STP-CORE,pbuf(%p)\n", pBuf); + return 0; + } + + *written_len = 0; + + if (len > STP_MAX_PACKAGE_ALLOWED) { + WMT_WARN_FUNC("abnormal pacage length,len(%d),pid[%d/%s]\n", len, current->pid, current->comm); + return -2; + } + wr_count = mtk_wcn_btif_write(stpBtifId, pBuf, len); + + if (wr_count < 0) { + WMT_ERR_FUNC("mtk_wcn_btif_write err(%d)\n", wr_count); + *written_len = 0; + return -3; + } + if (wr_count == len) { + /*perfect case */ + *written_len = wr_count; + return wr_count; + } + + while ((retry_left--) && (wr_count < len)) { + osal_sleep_ms(STP_BTIF_TX_RTY_DLY); + written = mtk_wcn_btif_write(stpBtifId, pBuf + wr_count, len - wr_count); + if (written < 0) { + WMT_ERR_FUNC("mtk_wcn_btif_write err(%d)when do recovered\n", written); + break; + } + wr_count += written; + } + + if (wr_count == len) { + WMT_INFO_FUNC("recovered,len(%d),retry_left(%d)\n", len, retry_left); + /*recovered case */ + *written_len = wr_count; + return wr_count; + } + + WMT_ERR_FUNC("stp btif write fail,len(%d),written(%d),retry_left(%d),pid[%d/%s]\n", + len, wr_count, retry_left, current->pid, current->comm); + *written_len = 0; + return -wr_count; +} + +INT32 mtk_wcn_consys_stp_btif_rx(UINT8 *pBuf, UINT32 len) +{ + return 0; +} + +INT32 mtk_wcn_consys_stp_btif_wakeup(VOID) +{ + INT32 iRet = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + iRet = -1; + } else { + iRet = mtk_wcn_btif_wakeup_consys(stpBtifId); + if (iRet) { + WMT_WARN_FUNC("STP btif wakeup consys fail(%d)\n", iRet); + iRet = -2; + } else { + WMT_DBG_FUNC("STP btif wakeup consys ok\n"); + } + } + + return iRet; +} + +INT32 mtk_wcn_consys_stp_btif_dpidle_ctrl(ENUM_BTIF_DPIDLE_CTRL en_flag) +{ + INT32 iRet = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + iRet = -1; + } else { + mtk_wcn_btif_dpidle_ctrl(stpBtifId, en_flag); + WMT_DBG_FUNC("stp btif dpidle ctrl done,en_flag(%d)\n", en_flag); + } + + return iRet; +} + +INT32 mtk_wcn_consys_stp_btif_lpbk_ctrl(ENUM_BTIF_LPBK_MODE mode) +{ + INT32 iRet = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + iRet = -1; + } else { + iRet = mtk_wcn_btif_loopback_ctrl(stpBtifId, mode); + if (iRet) { + WMT_WARN_FUNC("STP btif lpbk ctrl fail(%d)\n", iRet); + iRet = -2; + } else { + WMT_INFO_FUNC("stp btif lpbk ctrl ok,mode(%d)\n", mode); + } + } + + return iRet; +} + +INT32 mtk_wcn_consys_stp_btif_logger_ctrl(ENUM_BTIF_DBG_ID flag) +{ + INT32 iRet = 0; + + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + iRet = -1; + } else { + iRet = mtk_wcn_btif_dbg_ctrl(stpBtifId, flag); + if (iRet) { + WMT_WARN_FUNC("STP btif log dbg ctrl fail(%d)\n", iRet); + iRet = -2; + } else { + WMT_INFO_FUNC("stp btif log dbg ctrl ok,flag(%d)\n", flag); + } + } + + return iRet; +} + +INT32 mtk_wcn_consys_stp_btif_parser_wmt_evt(UINT8 * const str, UINT32 len) +{ + if (!stpBtifId) { + WMT_WARN_FUNC("NULL BTIF ID reference!\n"); + return -1; + } else { + return (INT32) mtk_wcn_btif_parser_wmt_evt(stpBtifId, str, len); + } +} + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg.c new file mode 100644 index 00000000000000..a8170e8e163d2c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg.c @@ -0,0 +1,2850 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include <linux/kernel.h> /* GFP_KERNEL */ +#include <linux/timer.h> /* init_timer, add_time, del_timer_sync */ +#include <linux/time.h> /* gettimeofday */ +#include <linux/delay.h> +#include <linux/slab.h> /* kzalloc */ +#include <linux/sched.h> /* task's status */ +#include <linux/vmalloc.h> +#include <linux/err.h> +#include <linux/workqueue.h> +#include <linux/spinlock.h> +#include <linux/atomic.h> + +#include <net/sock.h> +#include <net/netlink.h> +#include <linux/skbuff.h> +#include <net/genetlink.h> + +#include <linux/zlib.h> +#include <linux/uaccess.h> +#include <linux/crc32.h> + +#include "osal.h" +#include "stp_dbg.h" +#include "stp_dbg_combo.h" +#include "stp_dbg_soc.h" +/* #include "stp_btm.h" */ +#include "btm_core.h" +#include "wmt_plat.h" +#include "wmt_detect.h" +#include "stp_sdio.h" +#include "stp_core.h" +#include "mtk_wcn_consys_hw.h" + + +UINT32 gStpDbgLogOut; +UINT32 gStpDbgDumpType = STP_DBG_PKT; +INT32 gStpDbgDbgLevel = STP_DBG_LOG_INFO; + +MTKSTP_DBG_T *g_stp_dbg; + +static OSAL_SLEEPABLE_LOCK g_dbg_nl_lock; + +#define STP_DBG_FAMILY_NAME "STP_DBG" +#define MAX_BIND_PROCESS (4) +#ifdef WMT_PLAT_ALPS +#ifndef LOG_STP_DEBUG_DISABLE +#define STP_DBG_AEE_EXP_API (1) +#else +#define STP_DBG_AEE_EXP_API (0) +#endif +#else +#define STP_DBG_AEE_EXP_API (0) +#endif + +#define STP_MAGIC_NUM (0xDEADFEED) + +#ifndef GENL_ID_GENERATE +#define GENL_ID_GENERATE 0 +#endif + +enum { + __STP_DBG_ATTR_INVALID, + STP_DBG_ATTR_MSG, + __STP_DBG_ATTR_MAX, +}; +#define STP_DBG_ATTR_MAX (__STP_DBG_ATTR_MAX - 1) + +enum { + __STP_DBG_COMMAND_INVALID, + STP_DBG_COMMAND_BIND, + STP_DBG_COMMAND_RESET, + __STP_DBG_COMMAND_MAX, +}; +#define MTK_WIFI_COMMAND_MAX (__STP_DBG_COMMAND_MAX - 1) + +/* attribute policy */ +static struct nla_policy stp_dbg_genl_policy[STP_DBG_ATTR_MAX + 1] = { + [STP_DBG_ATTR_MSG] = {.type = NLA_NUL_STRING}, +}; + +static UINT32 stp_dbg_seqnum; +static INT32 num_bind_process; +static pid_t bind_pid[MAX_BIND_PROCESS]; +static P_WCN_CORE_DUMP_T g_core_dump; +static P_STP_DBG_CPUPCR_T g_stp_dbg_cpupcr; +/* just show in log at present */ +static P_STP_DBG_DMAREGS_T g_stp_dbg_dmaregs; + +static VOID stp_dbg_core_dump_timeout_handler(ULONG data); +static VOID stp_dbg_dump_emi_timeout_handler(ULONG data); +static _osal_inline_ P_WCN_CORE_DUMP_T stp_dbg_core_dump_init(UINT32 timeout); +static _osal_inline_ INT32 stp_dbg_core_dump_deinit(P_WCN_CORE_DUMP_T dmp); +static _osal_inline_ INT32 stp_dbg_core_dump_check_end(PUINT8 buf, INT32 len); +static _osal_inline_ INT32 stp_dbg_core_dump_in(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len); +static _osal_inline_ INT32 stp_dbg_core_dump_post_handle(P_WCN_CORE_DUMP_T dmp); +static _osal_inline_ INT32 stp_dbg_core_dump_out(P_WCN_CORE_DUMP_T dmp, PPUINT8 pbuf, PINT32 plen); +static _osal_inline_ INT32 stp_dbg_core_dump_reset(P_WCN_CORE_DUMP_T dmp, UINT32 timeout); +static _osal_inline_ INT32 stp_dbg_core_dump_nl(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len); +static _osal_inline_ UINT32 stp_dbg_get_chip_id(VOID); +static _osal_inline_ INT32 stp_dbg_gzip_compressor(PVOID worker, PUINT8 in_buf, INT32 in_sz, PUINT8 out_buf, + PINT32 out_sz, INT32 finish); +static _osal_inline_ P_WCN_COMPRESSOR_T stp_dbg_compressor_init(PUINT8 name, INT32 L1_buf_sz, INT32 L2_buf_sz); +static _osal_inline_ INT32 stp_dbg_compressor_deinit(P_WCN_COMPRESSOR_T cprs); +static _osal_inline_ INT32 stp_dbg_compressor_in(P_WCN_COMPRESSOR_T cprs, + PUINT8 buf, INT32 len, INT32 is_iobuf, INT32 finish); +static _osal_inline_ INT32 stp_dbg_compressor_out(P_WCN_COMPRESSOR_T cprs, PPUINT8 pbuf, PINT32 plen); +static _osal_inline_ INT32 stp_dbg_compressor_reset(P_WCN_COMPRESSOR_T cprs, UINT8 enable, WCN_COMPRESS_ALG_T type); +static _osal_inline_ VOID stp_dbg_dump_data(PUINT8 pBuf, PINT8 title, INT32 len); +static _osal_inline_ INT32 stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, PINT8 buf, INT32 len); +static _osal_inline_ INT32 stp_dbg_notify_btm_dmp_wq(MTKSTP_DBG_T *stp_dbg); +static _osal_inline_ INT32 stp_dbg_get_avl_entry_num(MTKSTP_DBG_T *stp_dbg); +static _osal_inline_ INT32 stp_dbg_fill_hdr(STP_DBG_HDR_T *hdr, INT32 type, INT32 ack, INT32 seq, + INT32 crc, INT32 dir, INT32 len, INT32 dbg_type); +static _osal_inline_ INT32 stp_dbg_add_pkt(MTKSTP_DBG_T *stp_dbg, STP_DBG_HDR_T *hdr, const PUINT8 body); +static INT32 stp_dbg_nl_bind(struct sk_buff *skb, struct genl_info *info); +static INT32 stp_dbg_nl_reset(struct sk_buff *skb, struct genl_info *info); +static _osal_inline_ INT32 stp_dbg_parser_assert_str(PINT8 str, ENUM_ASSERT_INFO_PARSER_TYPE type); +static _osal_inline_ P_STP_DBG_CPUPCR_T stp_dbg_cpupcr_init(VOID); +static _osal_inline_ VOID stp_dbg_cpupcr_deinit(P_STP_DBG_CPUPCR_T pCpupcr); +static _osal_inline_ P_STP_DBG_DMAREGS_T stp_dbg_dmaregs_init(VOID); +static _osal_inline_ VOID stp_dbg_dmaregs_deinit(P_STP_DBG_DMAREGS_T pDmaRegs); + +INT32 __weak mtk_btif_rxd_be_blocked_flag_get(VOID) +{ + STP_DBG_PR_INFO("mtk_btif_rxd_be_blocked_flag_get is not define!!!\n"); + return 0; +} + +/* operation definition */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wint-conversion" +static struct genl_ops stp_dbg_gnl_ops_array[] = { + { + .cmd = STP_DBG_COMMAND_BIND, + .flags = 0, + .policy = stp_dbg_genl_policy, + .doit = stp_dbg_nl_bind, + .dumpit = NULL, + }, + { + .cmd = STP_DBG_COMMAND_RESET, + .flags = 0, + .policy = stp_dbg_genl_policy, + .doit = stp_dbg_nl_reset, + .dumpit = NULL, + }, +}; +#pragma GCC diagnostic pop + +static struct genl_family stp_dbg_gnl_family = { + .id = GENL_ID_GENERATE, + .hdrsize = 0, + .name = STP_DBG_FAMILY_NAME, + .version = 1, + .maxattr = STP_DBG_ATTR_MAX, + .ops = stp_dbg_gnl_ops_array, + .n_ops = ARRAY_SIZE(stp_dbg_gnl_ops_array), +}; +/* stp_dbg_core_dump_timeout_handler - handler of coredump timeout + * @ data - core dump object's pointer + * + * No return value + */ +static VOID stp_dbg_core_dump_timeout_handler(ULONG data) +{ + stp_dbg_set_coredump_timer_state(CORE_DUMP_TIMEOUT); + stp_btm_notify_coredump_timeout_wq(g_stp_dbg->btm); + STP_DBG_PR_WARN(" coredump timer timeout, coredump maybe not finished successfully\n"); +} + +/* stp_dbg_dump_emi_timeout_handler - handler of emi dump timeout + * @ data - core dump object's pointer + * + * No return value + */ +static VOID stp_dbg_dump_emi_timeout_handler(ULONG data) +{ + STP_DBG_PR_ERR("dump emi timeout!\n"); + mtk_stp_notify_emi_dump_end(); +} + +/* stp_dbg_core_dump_init - create core dump sys + * @ packet_num - core dump packet number unit 32k + * @ timeout - core dump time out value + * + * Return object pointer if success, else NULL + */ +static _osal_inline_ P_WCN_CORE_DUMP_T stp_dbg_core_dump_init(UINT32 timeout) +{ + P_WCN_CORE_DUMP_T core_dmp = NULL; + + core_dmp = (P_WCN_CORE_DUMP_T) osal_malloc(sizeof(WCN_CORE_DUMP_T)); + if (!core_dmp) { + STP_DBG_PR_ERR("alloc mem failed!\n"); + return NULL; + } + + osal_memset(core_dmp, 0, sizeof(WCN_CORE_DUMP_T)); + + core_dmp->dmp_timer.timeoutHandler = stp_dbg_core_dump_timeout_handler; + core_dmp->dmp_timer.timeroutHandlerData = (ULONG)core_dmp; + osal_timer_create(&core_dmp->dmp_timer); + core_dmp->timeout = timeout; + core_dmp->dmp_emi_timer.timeoutHandler = stp_dbg_dump_emi_timeout_handler; + core_dmp->dmp_emi_timer.timeroutHandlerData = (ULONG)core_dmp; + osal_timer_create(&core_dmp->dmp_emi_timer); + + osal_sleepable_lock_init(&core_dmp->dmp_lock); + + core_dmp->sm = CORE_DUMP_INIT; + STP_DBG_PR_INFO("create coredump object OK!\n"); + + return core_dmp; +} + + +/* stp_dbg_core_dump_deinit - destroy core dump object + * @ dmp - pointer of object + * + * Retunr 0 if success, else error code + */ +static _osal_inline_ INT32 stp_dbg_core_dump_deinit(P_WCN_CORE_DUMP_T dmp) +{ + if (dmp) { + if (dmp->p_head != NULL) { + osal_free(dmp->p_head); + dmp->p_head = NULL; + } + osal_sleepable_lock_deinit(&dmp->dmp_lock); + osal_timer_stop(&dmp->dmp_timer); + osal_timer_stop(&dmp->dmp_emi_timer); + osal_free(dmp); + dmp = NULL; + } + + return 0; +} + +INT32 stp_dbg_core_dump_deinit_gcoredump(VOID) +{ + stp_dbg_core_dump_deinit(g_core_dump); + return 0; +} + +static _osal_inline_ INT32 stp_dbg_core_dump_check_end(PUINT8 buf, INT32 len) +{ + if (strnstr(buf, "coredump end", len)) + return 1; + else + return 0; +} + +static UINT32 stp_dbg_core_dump_header_init(P_WCN_CORE_DUMP_T dmp) +{ + dmp->head_len = 0; + if (dmp->p_head == NULL) { + dmp->p_head = osal_malloc(MAX_DUMP_HEAD_LEN); + if (dmp->p_head == NULL) { + STP_DBG_PR_ERR("alloc memory for head information failed\n"); + return -1; + } + } + if (dmp->p_head != NULL) + osal_memset(dmp->p_head, 0, MAX_DUMP_HEAD_LEN); + + return 0; +} + +static UINT32 stp_dbg_core_dump_header_append(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len) +{ + INT32 tmp = 0; + + if ((dmp->p_head != NULL) && (dmp->head_len < (MAX_DUMP_HEAD_LEN - 1))) { + tmp = + (dmp->head_len + len) > + (MAX_DUMP_HEAD_LEN - 1) ? (MAX_DUMP_HEAD_LEN - 1 - dmp->head_len) : len; + osal_memcpy(dmp->p_head + dmp->head_len, buf, tmp); + dmp->head_len += tmp; + return tmp; + } + return 0; +} + +/* stp_dbg_core_dump_in - add a packet to compressor buffer + * @ dmp - pointer of object + * @ buf - input buffer + * @ len - data length + * + * Retunr 0 if success; return 1 if find end string; else error code + */ +static _osal_inline_ INT32 stp_dbg_core_dump_in(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len) +{ + INT32 ret = 0; + + if ((!dmp) || (!buf)) { + STP_DBG_PR_ERR("invalid pointer!\n"); + return -1; + } + + ret = osal_lock_sleepable_lock(&dmp->dmp_lock); + if (ret) { + STP_DBG_PR_ERR("--->lock dmp->dmp_lock failed, ret=%d\n", ret); + return ret; + } + + switch (dmp->sm) { + case CORE_DUMP_INIT: + stp_dbg_compressor_reset(dmp->compressor, 1, GZIP); + stp_dbg_core_dump_header_init(dmp); + /* show coredump start info on UI */ + /* osal_dbg_assert_aee("MT662x f/w coredump start", "MT662x firmware coredump start"); */ +#if STP_DBG_AEE_EXP_API + aee_kernel_dal_show("CONSYS coredump start ....\n"); +#endif + /* parsing data, and check end srting */ + ret = stp_dbg_core_dump_check_end(buf, len); + if (ret == 1) { + STP_DBG_PR_INFO("core dump end!\n"); + dmp->sm = CORE_DUMP_DONE; + stp_dbg_compressor_in(dmp->compressor, buf, len, 0, 0); + } else { + dmp->sm = CORE_DUMP_DOING; + stp_dbg_compressor_in(dmp->compressor, buf, len, 0, 0); + } + break; + + case CORE_DUMP_DOING: + /* parsing data, and check end srting */ + ret = stp_dbg_core_dump_check_end(buf, len); + if (ret == 1) { + STP_DBG_PR_INFO("core dump end!\n"); + dmp->sm = CORE_DUMP_DONE; + stp_dbg_compressor_in(dmp->compressor, buf, len, 0, 0); + } else { + dmp->sm = CORE_DUMP_DOING; + stp_dbg_compressor_in(dmp->compressor, buf, len, 0, 0); + } + break; + + case CORE_DUMP_DONE: + stp_dbg_compressor_reset(dmp->compressor, 1, GZIP); + osal_timer_stop(&dmp->dmp_timer); + stp_dbg_compressor_in(dmp->compressor, buf, len, 0, 0); + dmp->sm = CORE_DUMP_DOING; + break; + + case CORE_DUMP_TIMEOUT: + ret = -1; + break; + default: + break; + } + + stp_dbg_core_dump_header_append(dmp, buf, len); + osal_unlock_sleepable_lock(&dmp->dmp_lock); + + return ret; +} + +static _osal_inline_ INT32 stp_dbg_core_dump_post_handle(P_WCN_CORE_DUMP_T dmp) +{ +#define INFO_HEAD ";CONSYS FW CORE, " + INT32 ret = 0; + INT32 tmp = 0; + ENUM_STP_FW_ISSUE_TYPE issue_type; + + if ((dmp->p_head != NULL) + && ((osal_strnstr(dmp->p_head, "<ASSERT>", dmp->head_len)) != NULL)) { + PINT8 pStr = dmp->p_head; + PINT8 pDtr = NULL; + + STP_DBG_PR_INFO(" <ASSERT> string found\n"); + if (stp_dbg_get_host_trigger_assert()) + issue_type = STP_HOST_TRIGGER_FW_ASSERT; + else + issue_type = STP_FW_ASSERT_ISSUE; + STP_DBG_PR_INFO("dmp->head_len = %d\n", dmp->head_len); + /*parse f/w assert additional informationi for f/w's analysis */ + ret = stp_dbg_set_fw_info(dmp->p_head, dmp->head_len, issue_type); + if (ret) { + STP_DBG_PR_ERR("set fw issue infor fail(%d),maybe fw warm reset...\n", + ret); + stp_dbg_set_fw_info("Fw Warm reset", osal_strlen("Fw Warm reset"), + STP_FW_WARM_RST_ISSUE); + } + /* first package, copy to info buffer */ + osal_strcpy(&dmp->info[0], INFO_HEAD); + + /* set f/w assert information to warm reset */ + pStr = osal_strnstr(pStr, "<ASSERT>", dmp->head_len); + if (pStr != NULL) { + pDtr = osal_strchr(pStr, '-'); + if (pDtr != NULL) { + tmp = STP_CORE_DUMP_INFO_SZ - osal_strlen(INFO_HEAD); + tmp = ((pDtr - pStr) > tmp) ? tmp : (pDtr - pStr); + osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], pStr, tmp); + dmp->info[osal_strlen(dmp->info) + 1] = '\0'; + } else { + tmp = STP_CORE_DUMP_INFO_SZ - osal_strlen(INFO_HEAD); + tmp = (dmp->head_len > tmp) ? tmp : dmp->head_len; + osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], pStr, tmp); + dmp->info[STP_CORE_DUMP_INFO_SZ] = '\0'; + } + } + } else if ((dmp->p_head != NULL) + && ((osal_strnstr(dmp->p_head, "ABT", dmp->head_len)) != NULL)) { + STP_DBG_PR_ERR("fw ABT happens, set to Fw ABT Exception\n"); + stp_dbg_set_fw_info("Fw ABT Exception", osal_strlen("Fw ABT Exception"), + STP_FW_ABT); + osal_strcpy(&dmp->info[0], INFO_HEAD); + osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], "Fw ABT Exception...", + osal_strlen("Fw ABT Exception...")); + dmp->info[osal_strlen(INFO_HEAD) + osal_strlen("Fw ABT Exception...") + 1] = '\0'; + } else { + STP_DBG_PR_INFO(" <ASSERT> string not found, dmp->head_len:%d\n", dmp->head_len); + if (dmp->p_head == NULL) + STP_DBG_PR_INFO(" dmp->p_head is NULL\n"); + else + STP_DBG_PR_INFO(" dmp->p_head:%s\n", dmp->p_head); + + /* first package, copy to info buffer */ + osal_strcpy(&dmp->info[0], INFO_HEAD); + /* set f/w assert information to warm reset */ + osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], "Fw warm reset exception...", + osal_strlen("Fw warm reset exception...")); + dmp->info[osal_strlen(INFO_HEAD) + osal_strlen("Fw warm reset exception...") + 1] = + '\0'; + + } + dmp->head_len = 0; + + /*set ret value to notify upper layer do dump flush operation */ + ret = 1; + + return ret; +} + +/* stp_dbg_core_dump_out - get compressed data from compressor buffer + * @ dmp - pointer of object + * @ pbuf - target buffer's pointer + * @ len - data length + * + * Retunr 0 if success; else error code + */ +static _osal_inline_ INT32 stp_dbg_core_dump_out(P_WCN_CORE_DUMP_T dmp, PPUINT8 pbuf, PINT32 plen) +{ + INT32 ret = 0; + + if ((!dmp) || (!pbuf) || (!plen)) { + STP_DBG_PR_ERR("invalid pointer!\n"); + return -1; + } + + ret = osal_lock_sleepable_lock(&dmp->dmp_lock); + if (ret) { + STP_DBG_PR_ERR("--->lock dmp->dmp_lock failed, ret=%d\n", ret); + return ret; + } + + ret = stp_dbg_compressor_out(dmp->compressor, pbuf, plen); + + osal_unlock_sleepable_lock(&dmp->dmp_lock); + + return ret; +} + +/* stp_dbg_core_dump_reset - reset core dump sys + * @ dmp - pointer of object + * @ timeout - core dump time out value + * + * Retunr 0 if success, else error code + */ +static _osal_inline_ INT32 stp_dbg_core_dump_reset(P_WCN_CORE_DUMP_T dmp, UINT32 timeout) +{ + if (!dmp) { + STP_DBG_PR_ERR("invalid pointer!\n"); + return -1; + } + + dmp->sm = CORE_DUMP_INIT; + dmp->timeout = timeout; + osal_timer_stop(&dmp->dmp_timer); + osal_timer_stop(&dmp->dmp_emi_timer); + osal_memset(dmp->info, 0, STP_CORE_DUMP_INFO_SZ + 1); + + stp_dbg_core_dump_deinit(dmp); + g_core_dump = stp_dbg_core_dump_init(STP_CORE_DUMP_TIMEOUT); + + return 0; +} + +#define ENABLE_F_TRACE 0 +/* stp_dbg_core_dump_flush - Fulsh dump data and reset core dump sys + * + * Retunr 0 if success, else error code + */ +INT32 stp_dbg_core_dump_flush(INT32 rst, MTK_WCN_BOOL coredump_is_timeout) +{ + PUINT8 pbuf = NULL; + INT32 len = 0; + + if (!g_core_dump) { + STP_DBG_PR_ERR("invalid pointer!\n"); + return -1; + } + + osal_lock_sleepable_lock(&g_core_dump->dmp_lock); + stp_dbg_core_dump_post_handle(g_core_dump); + osal_unlock_sleepable_lock(&g_core_dump->dmp_lock); + stp_dbg_core_dump_out(g_core_dump, &pbuf, &len); + STP_DBG_PR_INFO("buf 0x%zx, len %d\n", (SIZE_T) pbuf, len); + + /* show coredump end info on UI */ + /* osal_dbg_assert_aee("MT662x f/w coredump end", "MT662x firmware coredump ends"); */ +#if STP_DBG_AEE_EXP_API + if (coredump_is_timeout) + aee_kernel_dal_show("++ CONSYS coredump tiemout or fail, pass received coredump to AEE ++\n"); + else + aee_kernel_dal_show("++ CONSYS coredump get successfully ++\n"); + /* call AEE driver API */ +#if ENABLE_F_TRACE + aed_combo_exception_api(NULL, 0, (const PINT32)pbuf, len, (const PINT8)g_core_dump->info, + DB_OPT_FTRACE); +#else + aed_combo_exception(NULL, 0, (const PINT32)pbuf, len, (const PINT8)g_core_dump->info); +#endif + +#endif + + /* reset */ + g_core_dump->count = 0; + stp_dbg_compressor_deinit(g_core_dump->compressor); + stp_dbg_core_dump_reset(g_core_dump, STP_CORE_DUMP_TIMEOUT); + + return 0; +} + +static _osal_inline_ INT32 stp_dbg_core_dump_nl(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len) +{ + INT32 ret = 0; + + if ((!dmp) || (!buf)) { + STP_DBG_PR_ERR("invalid pointer!\n"); + return -1; + } + + ret = osal_lock_sleepable_lock(&dmp->dmp_lock); + if (ret) { + STP_DBG_PR_ERR("--->lock dmp->dmp_lock failed, ret=%d\n", ret); + return ret; + } + + switch (dmp->sm) { + case CORE_DUMP_INIT: + STP_DBG_PR_WARN("CONSYS coredump start, please wait up to %d minutes.\n", + STP_CORE_DUMP_TIMEOUT/60000); + stp_dbg_core_dump_header_init(dmp); + /* check end srting */ + ret = stp_dbg_core_dump_check_end(buf, len); + if (ret == 1) { + STP_DBG_PR_INFO("core dump end!\n"); + osal_timer_stop(&dmp->dmp_timer); + dmp->sm = CORE_DUMP_INIT; + } else { + dmp->sm = CORE_DUMP_DOING; + } + break; + + case CORE_DUMP_DOING: + /* check end srting */ + ret = stp_dbg_core_dump_check_end(buf, len); + if (ret == 1) { + STP_DBG_PR_INFO("core dump end!\n"); + osal_timer_stop(&dmp->dmp_timer); + dmp->sm = CORE_DUMP_INIT; + } else { + dmp->sm = CORE_DUMP_DOING; + } + break; + + case CORE_DUMP_DONE: + osal_timer_stop(&dmp->dmp_timer); + dmp->sm = CORE_DUMP_INIT; + break; + + case CORE_DUMP_TIMEOUT: + ret = 32; + break; + default: + break; + } + + /* Skip nl packet header */ + stp_dbg_core_dump_header_append(dmp, buf + NL_PKT_HEADER_LEN, len - NL_PKT_HEADER_LEN); + osal_unlock_sleepable_lock(&dmp->dmp_lock); + + return ret; +} + +INT32 stp_dbg_core_dump(INT32 dump_sink) +{ + ENUM_WMT_CHIP_TYPE chip_type; + INT32 ret = 0; + + chip_type = wmt_detect_get_chip_type(); + switch (chip_type) { + case WMT_CHIP_TYPE_COMBO: + ret = stp_dbg_combo_core_dump(dump_sink); + break; + case WMT_CHIP_TYPE_SOC: + ret = stp_dbg_soc_core_dump(dump_sink); + break; + default: + STP_DBG_PR_ERR("error chip type(%d)\n", chip_type); + } + + return ret; +} + +static _osal_inline_ UINT32 stp_dbg_get_chip_id(VOID) +{ + ENUM_WMT_CHIP_TYPE chip_type; + UINT32 chip_id = 0; + + chip_type = wmt_detect_get_chip_type(); + switch (chip_type) { + case WMT_CHIP_TYPE_COMBO: + chip_id = mtk_wcn_wmt_chipid_query(); + break; + case WMT_CHIP_TYPE_SOC: + chip_id = wmt_plat_get_soc_chipid(); + break; + default: + STP_DBG_PR_ERR("error chip type(%d)\n", chip_type); + } + + return chip_id; +} + +/* stp_dbg_trigger_collect_ftrace - this func can collect SYS_FTRACE + * + * Retunr 0 if success + */ +INT32 stp_dbg_trigger_collect_ftrace(PUINT8 pbuf, INT32 len) +{ + if (!pbuf) { + STP_DBG_PR_ERR("Parameter error\n"); + return -1; + } + + if (mtk_wcn_stp_coredump_start_get()) { + STP_DBG_PR_ERR("assert has been triggered\n"); + return -1; + } + + stp_dbg_set_host_assert_info(WMTDRV_TYPE_WMT, 30, 1); + + if (stp_dbg_set_fw_info(pbuf, len, STP_HOST_TRIGGER_COLLECT_FTRACE)) + return -1; + + if (g_core_dump) { + osal_strncpy(&g_core_dump->info[0], pbuf, len); +#if STP_DBG_AEE_EXP_API + aed_combo_exception(NULL, 0, (const PINT32)pbuf, len, (const PINT8)g_core_dump->info); +#endif + } else { + STP_DBG_PR_INFO("g_core_dump is not initialized\n"); +#if STP_DBG_AEE_EXP_API + aed_combo_exception(NULL, 0, (const PINT32)pbuf, len, (const PINT8)pbuf); +#endif + } + + return 0; +} + +#if BTIF_RXD_BE_BLOCKED_DETECT +MTK_WCN_BOOL stp_dbg_is_btif_rxd_be_blocked(VOID) +{ + MTK_WCN_BOOL flag = MTK_WCN_BOOL_FALSE; + + if (mtk_btif_rxd_be_blocked_flag_get()) + flag = MTK_WCN_BOOL_TRUE; + return flag; +} +#endif + +static _osal_inline_ INT32 stp_dbg_gzip_compressor(PVOID worker, PUINT8 in_buf, INT32 in_sz, PUINT8 out_buf, + PINT32 out_sz, INT32 finish) +{ + INT32 ret = 0; + z_stream *stream = NULL; + INT32 tmp = *out_sz; + + STP_DBG_PR_DBG("before compressor:buf 0x%zx, size %d, avalible buf: 0x%zx, size %d\n", + (SIZE_T) in_buf, in_sz, (SIZE_T) out_buf, tmp); + + stream = (z_stream *) worker; + if (!stream) { + STP_DBG_PR_ERR("invalid workspace!\n"); + return -1; + } + + if (in_sz > 0) { +#if 0 + ret = zlib_deflateReset(stream); + if (ret != Z_OK) { + STP_DBG_PR_ERR("reset failed!\n"); + return -2; + } +#endif + stream->next_in = in_buf; + stream->avail_in = in_sz; + stream->next_out = out_buf; + stream->avail_out = tmp; + + zlib_deflate(stream, Z_FULL_FLUSH); + + if (finish) { + while (1) { + INT32 val = zlib_deflate(stream, Z_FINISH); + + if (val == Z_OK) + continue; + else if (val == Z_STREAM_END) + break; + STP_DBG_PR_ERR("finish operation failed %d\n", val); + return -3; + } + } + *out_sz = tmp - stream->avail_out; + } + + STP_DBG_PR_DBG("after compressor,avalible buf: 0x%zx, compress rate %d -> %d\n", + (SIZE_T) out_buf, in_sz, *out_sz); + + return ret; +} + +/* stp_dbg_compressor_init - create a compressor and do init + * @ name - compressor's name + * @ L1_buf_sz - L1 buffer size + * @ L2_buf_sz - L2 buffer size + * + * Retunr object's pointer if success, else NULL + */ +static _osal_inline_ P_WCN_COMPRESSOR_T stp_dbg_compressor_init(PUINT8 name, INT32 L1_buf_sz, + INT32 L2_buf_sz) +{ + z_stream *pstream = NULL; + P_WCN_COMPRESSOR_T compress = NULL; + + compress = (P_WCN_COMPRESSOR_T) osal_malloc(sizeof(WCN_COMPRESSOR_T)); + if (!compress) { + STP_DBG_PR_ERR("alloc compressor failed!\n"); + goto fail; + } + + osal_memset(compress, 0, sizeof(WCN_COMPRESSOR_T)); + osal_memcpy(compress->name, name, STP_OJB_NAME_SZ); + + compress->f_compress_en = 0; + compress->compress_type = GZIP; + + if (compress->compress_type == GZIP) { + compress->worker = osal_malloc(sizeof(z_stream)); + if (!compress->worker) { + STP_DBG_PR_ERR("alloc stream failed!\n"); + goto fail; + } + pstream = (z_stream *) compress->worker; + + pstream->workspace = osal_malloc(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL)); + if (!pstream->workspace) { + STP_DBG_PR_ERR("alloc workspace failed!\n"); + goto fail; + } + zlib_deflateInit2(pstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, + DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); + } + + compress->handler = stp_dbg_gzip_compressor; + compress->L1_buf_sz = L1_buf_sz; + compress->L2_buf_sz = L2_buf_sz; + compress->L1_pos = 0; + compress->L2_pos = 0; + compress->uncomp_size = 0; + compress->crc32 = 0xffffffffUL; + + compress->L1_buf = osal_malloc(compress->L1_buf_sz); + if (!compress->L1_buf) { + STP_DBG_PR_ERR("alloc %d bytes for L1 buf failed!\n", compress->L1_buf_sz); + goto fail; + } + + compress->L2_buf = osal_malloc(compress->L2_buf_sz); + if (!compress->L2_buf) { + STP_DBG_PR_ERR("alloc %d bytes for L2 buf failed!\n", compress->L2_buf_sz); + goto fail; + } + + STP_DBG_PR_INFO("create compressor OK! L1 %d bytes, L2 %d bytes\n", L1_buf_sz, L2_buf_sz); + return compress; + +fail: + if (compress) { + if (compress->L2_buf) { + osal_free(compress->L2_buf); + compress->L2_buf = NULL; + } + + if (compress->L1_buf) { + osal_free(compress->L1_buf); + compress->L1_buf = NULL; + } + + if (compress->worker) { + pstream = (z_stream *) compress->worker; + if ((compress->compress_type == GZIP) && pstream->workspace) { + zlib_deflateEnd(pstream); + osal_free(pstream->workspace); + } + osal_free(compress->worker); + compress->worker = NULL; + } + + if (compress->worker) { + osal_free(compress->worker); + compress->worker = NULL; + } + + osal_free(compress); + compress = NULL; + } + + STP_DBG_PR_ERR("init failed!\n"); + + return NULL; +} + +/* stp_dbg_compressor_deinit - distroy a compressor + * @ cprs - compressor's pointer + * + * Retunr 0 if success, else NULL + */ +static _osal_inline_ INT32 stp_dbg_compressor_deinit(P_WCN_COMPRESSOR_T cprs) +{ + z_stream *pstream = NULL; + + if (cprs) { + if (cprs->L2_buf) { + osal_free(cprs->L2_buf); + cprs->L2_buf = NULL; + } + + if (cprs->L1_buf) { + osal_free(cprs->L1_buf); + cprs->L1_buf = NULL; + } + + if (cprs->worker) { + pstream = (z_stream *) cprs->worker; + if ((cprs->compress_type == GZIP) && pstream->workspace) { + zlib_deflateEnd(pstream); + osal_free(pstream->workspace); + } + osal_free(cprs->worker); + cprs->worker = NULL; + } + + cprs->handler = NULL; + + osal_free(cprs); + } + + STP_DBG_PR_INFO("destroy OK\n"); + + return 0; +} + +/* stp_dbg_compressor_in - put in a raw data, and compress L1 buffer if need + * @ cprs - compressor's pointer + * @ buf - raw data buffer + * @ len - raw data length + * @ is_iobuf - is buf a pointer to EMI? 1: yes, 0: no + * @ finish - core dump finish or not, 1: finished; 0: not finish + * + * Retunr 0 if success, else NULL + */ +static _osal_inline_ INT32 stp_dbg_compressor_in(P_WCN_COMPRESSOR_T cprs, PUINT8 buf, INT32 len, + INT32 is_iobuf, INT32 finish) +{ + INT32 tmp_len = 0; + INT32 ret = 0; + + if (!cprs) { + STP_DBG_PR_ERR("invalid para!\n"); + return -1; + } + + cprs->uncomp_size += len; + + /* check L1 buf valid space */ + if (len > (cprs->L1_buf_sz - cprs->L1_pos)) { + STP_DBG_PR_DBG("L1 buffer full\n"); + + if (cprs->f_compress_en && cprs->handler) { + /* need compress */ + /* compress L1 buffer, and put result to L2 buffer */ + tmp_len = cprs->L2_buf_sz - cprs->L2_pos; + ret = + cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos, + &cprs->L2_buf[cprs->L2_pos], &tmp_len, finish); + if (!ret) { + cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos)); + cprs->L2_pos += tmp_len; + if (cprs->L2_pos >= cprs->L2_buf_sz) + STP_DBG_PR_ERR("coredump size too large(%d), L2 buf overflow\n", + cprs->L2_pos); + + if (finish) { + /* Add 8 byte suffix + * === + * 32 bits UNCOMPRESS SIZE + * 32 bits CRC + */ + *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos]) = + (cprs->crc32 ^ 0xffffffffUL); + *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos + 4]) = cprs->uncomp_size; + cprs->L2_pos += 8; + } + STP_DBG_PR_DBG("compress OK!\n"); + } else + STP_DBG_PR_ERR("compress error!\n"); + } else { + /* no need compress */ + /* Flush L1 buffer to L2 buffer */ + STP_DBG_PR_INFO("No need do compress, Put to L2 buf\n"); + + tmp_len = cprs->L2_buf_sz - cprs->L2_pos; + tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos; + osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len); + cprs->L2_pos += tmp_len; + } + + /* reset L1 buf pos */ + cprs->L1_pos = 0; + + /* put curren data to L1 buf */ + if (len > cprs->L1_buf_sz) { + STP_DBG_PR_ERR("len=%d, too long err!\n", len); + } else { + STP_DBG_PR_DBG("L1 Flushed, and Put %d bytes to L1 buf\n", len); + if (is_iobuf) + osal_memcpy_fromio(&cprs->L1_buf[cprs->L1_pos], buf, len); + else + osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len); + cprs->L1_pos += len; + } + } else { + /* put to L1 buffer */ + STP_DBG_PR_DBG("Put %d bytes to L1 buf\n", len); + if (is_iobuf) + osal_memcpy_fromio(&cprs->L1_buf[cprs->L1_pos], buf, len); + else + osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len); + cprs->L1_pos += len; + } + + return ret; +} + +/* stp_dbg_compressor_out - get the result data from L2 buffer + * @ cprs - compressor's pointer + * @ pbuf - point to L2 buffer + * @ plen - out len + * + * Retunr 0 if success, else NULL + */ +static _osal_inline_ INT32 stp_dbg_compressor_out(P_WCN_COMPRESSOR_T cprs, PPUINT8 pbuf, PINT32 plen) +{ + INT32 ret = 0; + INT32 tmp_len = 0; + + if ((!cprs) || (!pbuf) || (!plen)) { + STP_DBG_PR_ERR("invalid para!\n"); + return -1; + } + /* check if there's L1 data need flush to L2 buffer */ + if (cprs->L1_pos > 0) { + tmp_len = cprs->L2_buf_sz - cprs->L2_pos; + + if (cprs->f_compress_en && cprs->handler) { + /* need compress */ + ret = + cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos, + &cprs->L2_buf[cprs->L2_pos], &tmp_len, 1); + + if (!ret) { + cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos)); + cprs->L2_pos += tmp_len; + + /* Add 8 byte suffix + * === + * 32 bits UNCOMPRESS SIZE + * 32 bits CRC + */ + *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos]) = (cprs->crc32 ^ 0xffffffffUL); + *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos + 4]) = cprs->uncomp_size; + cprs->L2_pos += 8; + + STP_DBG_PR_INFO("compress OK!\n"); + } else { + STP_DBG_PR_ERR("compress error!\n"); + } + } else { + /* no need compress */ + tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos; + osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len); + cprs->L2_pos += tmp_len; + } + + cprs->L1_pos = 0; + } + + *pbuf = cprs->L2_buf; + *plen = cprs->L2_pos; + + STP_DBG_PR_INFO("0x%zx, len %d, l2_buf_remain %d\n", (SIZE_T)*pbuf, *plen, cprs->L2_buf_sz - cprs->L2_pos); + +#if 1 + ret = zlib_deflateReset((z_stream *) cprs->worker); + if (ret != Z_OK) { + STP_DBG_PR_ERR("reset failed!\n"); + return -2; + } +#endif + return 0; +} + +/* stp_dbg_compressor_reset - reset compressor + * @ cprs - compressor's pointer + * @ enable - enable/disable compress + * @ type - compress algorithm + * + * Retunr 0 if success, else NULL + */ +static _osal_inline_ INT32 stp_dbg_compressor_reset(P_WCN_COMPRESSOR_T cprs, UINT8 enable, + WCN_COMPRESS_ALG_T type) +{ + if (!cprs) { + STP_DBG_PR_ERR("invalid para!\n"); + return -1; + } + + cprs->f_compress_en = enable; + /* cprs->f_compress_en = 0; // disable compress for test */ + cprs->compress_type = type; + cprs->L1_pos = 0; + cprs->L2_pos = 0; + cprs->uncomp_size = 0; + cprs->crc32 = 0xffffffffUL; + + /* zlib_deflateEnd((z_stream*)cprs->worker); */ + + STP_DBG_PR_INFO("OK! compress algorithm %d\n", type); + + return 0; +} + +#if 0 +static _osal_inline_ VOID stp_dbg_dump_data(PUINT8 pBuf, PINT8 title, INT32 len) +{ + INT32 idx = 0; + UINT8 str[240]; + PUINT8 p_str; + + p_str = &str[0]; + pr_debug(" %s-len:%d\n", title, len); + for (idx = 0; idx < len; idx++, pBuf++) { + sprintf(p_str, "%02x ", *pBuf); + p_str += 3; + if (15 == (idx % 16)) { + sprintf(p_str, "--end\n"); + *(p_str + 6) = '\0'; + pr_debug("%s", str); + p_str = 0; + } + } + if (len % 16) { + sprintf(p_str, "--end\n"); + *(p_str + 6) = '\0'; + pr_debug("%s", str); + } +} +#endif +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-overflow" +static VOID stp_dbg_dump_data(PUINT8 pBuf, PINT8 title, INT32 len) +{ + INT32 k = 0; + char str[240] = {""}; + char buf_str[32] = {""}; + + pr_warn(" %s-len:%d\n", title, len); + /* pr_warn(" ", title, len); */ + for (k = 0; k < len; k++) { + if (strlen(str) < 200) { + snprintf(buf_str, sizeof(buf_str), "0x%02x ", pBuf[k]); + strncat(str, buf_str, strlen(buf_str)); + } else { + pr_warn("More than 200 of the data is too much\n"); + break; + } + } + strncat(str, "--end\n", strlen("--end\n")); + pr_warn("%s", str); +} +#pragma GCC diagnostic pop + +INT32 stp_dbg_enable(MTKSTP_DBG_T *stp_dbg) +{ + ULONG flags; + + spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); + stp_dbg->pkt_trace_no = 0; + stp_dbg->is_enable = 1; + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + + return 0; +} + +INT32 stp_dbg_disable(MTKSTP_DBG_T *stp_dbg) +{ + ULONG flags; + + spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); + stp_dbg->pkt_trace_no = 0; + memset(stp_dbg->logsys, 0, sizeof(MTKSTP_LOG_SYS_T)); + stp_dbg->is_enable = 0; + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + + return 0; +} + +static _osal_inline_ INT32 stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, PINT8 buf, INT32 len) +{ + ULONG flags; + STP_DBG_HDR_T *pHdr = NULL; + PINT8 pBuf = NULL; + UINT32 length = 0; + const PINT8 *pType = NULL; + + pType = wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO ? + comboStpDbgType : socStpDbgType; + + spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); + + stp_dbg->logsys->queue[stp_dbg->logsys->in].id = 0; + stp_dbg->logsys->queue[stp_dbg->logsys->in].len = len; + memset(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]), + 0, ((len >= STP_DBG_LOG_ENTRY_SZ) ? (STP_DBG_LOG_ENTRY_SZ) : (len))); + memcpy(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]), + buf, ((len >= STP_DBG_LOG_ENTRY_SZ) ? (STP_DBG_LOG_ENTRY_SZ) : (len))); + stp_dbg->logsys->size++; + stp_dbg->logsys->size = (stp_dbg->logsys->size > STP_DBG_LOG_ENTRY_NUM) ? + STP_DBG_LOG_ENTRY_NUM : stp_dbg->logsys->size; + if (gStpDbgLogOut != 0) { + pHdr = (STP_DBG_HDR_T *) &(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]); + pBuf = (PINT8)&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]) + + sizeof(STP_DBG_HDR_T); + length = stp_dbg->logsys->queue[stp_dbg->logsys->in].len - sizeof(STP_DBG_HDR_T); + pr_info("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d)\n", + pHdr->sec, + pHdr->usec, + pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", + pType[pHdr->type], pHdr->no, pHdr->len, pHdr->seq, pHdr->ack); + + if (length > 0) + stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", length); + } + stp_dbg->logsys->in = + (stp_dbg->logsys->in >= (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (stp_dbg->logsys->in + 1); + STP_DBG_PR_DBG("logsys size = %d, in = %d\n", stp_dbg->logsys->size, stp_dbg->logsys->in); + + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + + return 0; +} + +static _osal_inline_ INT32 stp_dbg_notify_btm_dmp_wq(MTKSTP_DBG_T *stp_dbg) +{ + INT32 retval = 0; + +/* #ifndef CONFIG_LOG_STP_INTERNAL */ + if (stp_dbg->btm != NULL) + retval += stp_btm_notify_wmt_dmp_wq((MTKSTP_BTM_T *) stp_dbg->btm); +/* #endif */ + + return retval; +} + +static VOID stp_dbg_dmp_print_work(struct work_struct *work) +{ + MTKSTP_LOG_SYS_T *logsys = container_of(work, MTKSTP_LOG_SYS_T, dump_work); + INT32 dumpSize = logsys->dump_size; + MTKSTP_LOG_ENTRY_T *queue = logsys->dump_queue; + INT32 i; + PINT8 pBuf = NULL; + INT32 len = 0; + STP_DBG_HDR_T *pHdr = NULL; + const PINT8 *pType = NULL; + + if (queue == NULL || queue == (MTKSTP_LOG_ENTRY_T *)STP_MAGIC_NUM) + return; + + pType = wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO ? + comboStpDbgType : socStpDbgType; + + for (i = 0; i < dumpSize; i++) { + pHdr = (STP_DBG_HDR_T *) &(queue[i].buffer[0]); + pBuf = &(queue[i].buffer[0]) + sizeof(STP_DBG_HDR_T); + len = queue[i].len - sizeof(STP_DBG_HDR_T); + len = len > STP_PKT_SZ ? STP_PKT_SZ : len; + pr_info("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d), time[%llu.%06lu]\n", + pHdr->sec, + pHdr->usec, + pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", + pType[pHdr->type], pHdr->no, pHdr->len, pHdr->seq, + pHdr->ack, pHdr->l_sec, pHdr->l_nsec); + + if (len > 0) + stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", len); + + } + vfree(queue); + logsys->dump_queue = NULL; +} + +INT32 stp_dbg_dmp_print(MTKSTP_DBG_T *stp_dbg) +{ +#define MAX_DMP_NUM 80 + ULONG flags; + UINT32 dumpSize = 0; + UINT32 inIndex = 0; + UINT32 outIndex = 0; + MTKSTP_LOG_ENTRY_T *dump_queue = NULL; + MTKSTP_LOG_ENTRY_T *queue = stp_dbg->logsys->queue; + + spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); + if (stp_dbg->logsys->dump_queue != NULL) { + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + return 0; + } + + stp_dbg->logsys->dump_queue = (MTKSTP_LOG_ENTRY_T *)STP_MAGIC_NUM; + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + + /* allocate memory may take long time, thus allocate it before get lock */ + dump_queue = vmalloc(sizeof(MTKSTP_LOG_ENTRY_T) * MAX_DMP_NUM); + if (dump_queue == NULL) { + stp_dbg->logsys->dump_queue = NULL; + pr_info("fail to allocate memory"); + return -1; + } + + if (spin_trylock_irqsave(&(stp_dbg->logsys->lock), flags) == 0) { + stp_dbg->logsys->dump_queue = NULL; + vfree(dump_queue); + pr_info("fail to get lock"); + return -1; + } + /* Not to dequeue from loging system */ + inIndex = stp_dbg->logsys->in; + dumpSize = stp_dbg->logsys->size; + + /* chance is little but still needs to check */ + if (dumpSize == 0) { + stp_dbg->logsys->dump_queue = NULL; + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + vfree(dump_queue); + return 0; + } + + if (dumpSize == STP_DBG_LOG_ENTRY_NUM) + outIndex = inIndex; + else + outIndex = ((inIndex + STP_DBG_LOG_ENTRY_NUM) - dumpSize) % STP_DBG_LOG_ENTRY_NUM; + + if (dumpSize > MAX_DMP_NUM) { + outIndex += (dumpSize - MAX_DMP_NUM); + outIndex %= STP_DBG_LOG_ENTRY_NUM; + dumpSize = MAX_DMP_NUM; + } + + stp_dbg->logsys->dump_queue = dump_queue; + stp_dbg->logsys->dump_size = dumpSize; + + /* copy content of stp_dbg->logsys->queue out, don't print log while holding */ + /* spinlock to prevent blocking other process */ + if (outIndex + dumpSize > STP_DBG_LOG_ENTRY_NUM) { + UINT32 tailNum = STP_DBG_LOG_ENTRY_NUM - outIndex; + + osal_memcpy(dump_queue, &(queue[outIndex]), sizeof(MTKSTP_LOG_ENTRY_T) * tailNum); + osal_memcpy(dump_queue + tailNum, &(queue[0]), sizeof(MTKSTP_LOG_ENTRY_T) * + (dumpSize - tailNum)); + } else { + osal_memcpy(dump_queue, &(queue[outIndex]), sizeof(MTKSTP_LOG_ENTRY_T) * dumpSize); + } + + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + STP_DBG_PR_INFO("loged packet size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex); + schedule_work(&(stp_dbg->logsys->dump_work)); + return 0; +} + +INT32 stp_dbg_dmp_out(MTKSTP_DBG_T *stp_dbg, PINT8 buf, PINT32 len) +{ + ULONG flags; + INT32 remaining = 0; + *len = 0; + spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); + + if (stp_dbg->logsys->size > 0) { + if (stp_dbg->logsys->queue[stp_dbg->logsys->out].len >= STP_DBG_LOG_ENTRY_SZ) + stp_dbg->logsys->queue[stp_dbg->logsys->out].len = STP_DBG_LOG_ENTRY_SZ - 1; + memcpy(buf, &(stp_dbg->logsys->queue[stp_dbg->logsys->out].buffer[0]), + stp_dbg->logsys->queue[stp_dbg->logsys->out].len); + + (*len) = stp_dbg->logsys->queue[stp_dbg->logsys->out].len; + stp_dbg->logsys->out = + (stp_dbg->logsys->out >= (STP_DBG_LOG_ENTRY_NUM - 1)) ? + (0) : (stp_dbg->logsys->out + 1); + stp_dbg->logsys->size--; + + STP_DBG_PR_DBG("logsys size = %d, out = %d\n", stp_dbg->logsys->size, + stp_dbg->logsys->out); + } else + STP_DBG_PR_LOUD("logsys EMPTY!\n"); + + remaining = (stp_dbg->logsys->size == 0) ? (0) : (1); + + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + + return remaining; +} + +INT32 stp_dbg_dmp_out_ex(PINT8 buf, PINT32 len) +{ + return stp_dbg_dmp_out(g_stp_dbg, buf, len); +} + +INT32 stp_dbg_dmp_append(MTKSTP_DBG_T *stp_dbg, PUINT8 pBuf, INT32 max_len) +{ + PUINT8 p = NULL; + UINT32 l = 0; + UINT32 i = 0; + INT32 j = 0; + ULONG flags; + UINT32 len = 0; + UINT32 dumpSize = 0; + STP_DBG_HDR_T *pHdr = NULL; + const PINT8 *pType = NULL; + + if (!pBuf || max_len < 8) { /* 8: length of "<!---->\n" */ + STP_DBG_PR_WARN("invalid param, pBuf:%p, max_len:%d\n", pBuf, max_len); + return 0; + } + + pType = wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO ? + comboStpDbgType : socStpDbgType; + spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); + /* Not to dequeue from loging system */ + dumpSize = stp_dbg->logsys->size; + j = stp_dbg->logsys->in; + + /* format <!-- XXX -->*/ + len += osal_sprintf(pBuf, "<!--\n"); + + while (dumpSize > 0) { + j--; + if (j < 0) + j += STP_DBG_LOG_ENTRY_NUM; + + l = stp_dbg->logsys->queue[j].len - sizeof(STP_DBG_HDR_T); + l = l > STP_PKT_SZ ? STP_PKT_SZ : l; + + /* format "\t9999999.999999s, Tx:<STP>n(999999)l(1024)s(7)a(7) xx yy zz\n" + * need to consider "-->\n" + */ + if ((len + 53 + 3 * l + 4) > max_len) + break; + + pHdr = (STP_DBG_HDR_T *) &(stp_dbg->logsys->queue[j].buffer[0]); + p = (PUINT8)pHdr + sizeof(STP_DBG_HDR_T); + + len += osal_sprintf(pBuf + len, "\t%llu.%06lus, %s:pT%sn(%d)l(%4d)s(%d)a(%d)\t", + pHdr->l_sec, pHdr->l_nsec, + pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", + pType[pHdr->type], pHdr->no, pHdr->len, pHdr->seq, + pHdr->ack); + + for (i = 0; i < l; i++, p++) + len += osal_sprintf(pBuf + len, " %02x", *p, 3); + + pBuf[len] = '\n'; + len += 1; + + dumpSize--; + } + + len += osal_sprintf(pBuf + len, "-->\n"); + + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + + return len; +} + +static _osal_inline_ INT32 stp_dbg_get_avl_entry_num(MTKSTP_DBG_T *stp_dbg) +{ + if (stp_dbg->logsys->size == 0) + return STP_DBG_LOG_ENTRY_NUM; + else + return (stp_dbg->logsys->in > stp_dbg->logsys->out) ? + (STP_DBG_LOG_ENTRY_NUM - stp_dbg->logsys->in + stp_dbg->logsys->out) : + (stp_dbg->logsys->out - stp_dbg->logsys->in); +} + +static _osal_inline_ INT32 stp_dbg_fill_hdr(STP_DBG_HDR_T *hdr, INT32 type, INT32 ack, INT32 seq, + INT32 crc, INT32 dir, INT32 len, INT32 dbg_type) +{ + + struct timespec64 now; + UINT64 ts; + ULONG nsec; + + if (!hdr) { + STP_DBG_PR_ERR("function invalid\n"); + return -EINVAL; + } + + ktime_get_ts64(&now); + osal_get_local_time(&ts, &nsec); + hdr->last_dbg_type = gStpDbgDumpType; + gStpDbgDumpType = dbg_type; + hdr->dbg_type = dbg_type; + hdr->ack = ack; + hdr->seq = seq; + hdr->sec = now.tv_sec; + hdr->usec = now.tv_nsec / NSEC_PER_USEC; + hdr->crc = crc; + hdr->dir = dir; /* rx */ + hdr->dmy = 0xffffffff; + hdr->len = len; + hdr->type = type; + hdr->l_sec = ts; + hdr->l_nsec = nsec; + return 0; +} + +static _osal_inline_ INT32 stp_dbg_add_pkt(MTKSTP_DBG_T *stp_dbg, STP_DBG_HDR_T *hdr, const PUINT8 body) +{ + /* fix the frame size large issues. */ + static STP_PACKET_T stp_pkt; + UINT32 hdr_sz = sizeof(struct stp_dbg_pkt_hdr); + UINT32 body_sz = 0; + ULONG flags; + UINT32 avl_num; + + if (hdr->dbg_type == STP_DBG_PKT) + body_sz = (hdr->len <= STP_PKT_SZ) ? (hdr->len) : (STP_PKT_SZ); + else + body_sz = (hdr->len <= STP_DMP_SZ) ? (hdr->len) : (STP_DMP_SZ); + + hdr->no = stp_dbg->pkt_trace_no++; + memcpy((PUINT8) &stp_pkt.hdr, (PUINT8) hdr, hdr_sz); + if (body != NULL) + memcpy((PUINT8) &stp_pkt.raw[0], body, body_sz); + + if (hdr->dbg_type == STP_DBG_FW_DMP) { + if (hdr->last_dbg_type != STP_DBG_FW_DMP) { + + STP_DBG_PR_INFO + ("reset stp_dbg logsys when queue fw coredump package(%d)\n", + hdr->last_dbg_type); + STP_DBG_PR_INFO("dump 1st fw coredump package len(%d) for confirming\n", + hdr->len); + spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); + stp_dbg->logsys->in = 0; + stp_dbg->logsys->out = 0; + stp_dbg->logsys->size = 0; + spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags); + } else { + avl_num = stp_dbg_get_avl_entry_num(stp_dbg); + + if (!avl_num) + STP_DBG_PR_ERR("there is no avl entry stp_dbg logsys!!!\n"); + } + } + stp_dbg_dmp_in(stp_dbg, (PINT8) &stp_pkt, hdr_sz + body_sz); + /* Only FW DMP MSG should inform BTM-CORE to dump packet to native process */ + if (hdr->dbg_type == STP_DBG_FW_DMP) + stp_dbg_notify_btm_dmp_wq(stp_dbg); + + return 0; +} + +INT32 stp_dbg_log_pkt(MTKSTP_DBG_T *stp_dbg, INT32 dbg_type, + INT32 type, INT32 ack_no, INT32 seq_no, INT32 crc, INT32 dir, INT32 len, + const PUINT8 body) +{ + STP_DBG_HDR_T hdr; + + osal_bug_on(!stp_dbg); + + if (!stp_dbg) + return -1; + + if (stp_dbg->is_enable == 0) { + /*dbg is disable,and not to log */ + } else { + hdr.no = 0; + hdr.chs = 0; + stp_dbg_fill_hdr(&hdr, + (INT32) type, + (INT32) ack_no, + (INT32) seq_no, (INT32) crc, (INT32) dir, (INT32) len, + (INT32) dbg_type); + + stp_dbg_add_pkt(stp_dbg, &hdr, body); + } + + return 0; +} + +INT32 stp_dbg_log_ctrl(UINT32 on) +{ + if (on != 0) { + gStpDbgLogOut = 1; + pr_warn("STP-DBG: enable pkt log dump out.\n"); + } else { + gStpDbgLogOut = 0; + pr_warn("STP-DBG: disable pkt log dump out.\n"); + } + + return 0; +} + +VOID stp_dbg_nl_init(VOID) +{ +#if 0 + if (genl_register_family(&stp_dbg_gnl_family) != 0) { + STP_DBG_PR_ERR("%s(): GE_NELINK family registration fail\n", __func__); + } else { + if (genl_register_ops(&stp_dbg_gnl_family, &stp_dbg_gnl_ops_bind) != 0) + STP_DBG_PR_ERR("%s(): BIND operation registration fail\n", __func__); + + if (genl_register_ops(&stp_dbg_gnl_family, &stp_dbg_gnl_ops_reset) != 0) + STP_DBG_PR_ERR("%s(): RESET operation registration fail\n", __func__); + + } +#endif + osal_sleepable_lock_init(&g_dbg_nl_lock); + if (genl_register_family(&stp_dbg_gnl_family) != 0) + STP_DBG_PR_ERR("%s(): GE_NELINK family registration fail\n", __func__); +} + +VOID stp_dbg_nl_deinit(VOID) +{ + int i; + + num_bind_process = 0; + for (i = 0; i < MAX_BIND_PROCESS; i++) + bind_pid[i] = 0; + genl_unregister_family(&stp_dbg_gnl_family); + osal_sleepable_lock_deinit(&g_dbg_nl_lock); +} + +static INT32 stp_dbg_nl_bind(struct sk_buff *skb, struct genl_info *info) +{ + struct nlattr *na; + PINT8 mydata; + INT32 i; + + if (info == NULL) + goto out; + + STP_DBG_PR_INFO("%s():->\n", __func__); + + na = info->attrs[STP_DBG_ATTR_MSG]; + + if (na) + mydata = (PINT8) nla_data(na); + + if (osal_lock_sleepable_lock(&g_dbg_nl_lock)) + return -1; + + for (i = 0; i < MAX_BIND_PROCESS; i++) { + if (bind_pid[i] == 0) { + bind_pid[i] = info->snd_portid; + num_bind_process++; + STP_DBG_PR_INFO("%s():-> pid = %d\n", __func__, info->snd_portid); + break; + } + } + + if (i == MAX_BIND_PROCESS) { + STP_DBG_PR_ERR("%s(): exceeding binding limit %d\n", __func__, MAX_BIND_PROCESS); + bind_pid[0] = info->snd_portid; + } + + osal_unlock_sleepable_lock(&g_dbg_nl_lock); + +out: + return 0; +} + +static INT32 stp_dbg_nl_reset(struct sk_buff *skb, struct genl_info *info) +{ + STP_DBG_PR_ERR("%s(): should not be invoked\n", __func__); + + return 0; +} + +INT32 stp_dbg_nl_send(PINT8 aucMsg, UINT8 cmd, INT32 len) +{ + struct sk_buff *skb = NULL; + PVOID msg_head = NULL; + INT32 rc = -1; + INT32 i, j; + INT32 ret = 0; + INT32 killed_num = 0; + + if (num_bind_process == 0) { + /* no listening process */ + STP_DBG_PR_ERR("%s(): the process is not invoked\n", __func__); + return 0; + } + + ret = stp_dbg_core_dump_nl(g_core_dump, aucMsg, len); + if (ret < 0) + return ret; + if (ret == 32) + return ret; + + ret = -1; + for (i = 0; i < num_bind_process; i++) { + if (bind_pid[i] == 0) { + killed_num++; + continue; + } + + skb = genlmsg_new(2048, GFP_KERNEL); + if (skb) { + msg_head = genlmsg_put(skb, 0, stp_dbg_seqnum++, &stp_dbg_gnl_family, 0, cmd); + if (msg_head == NULL) { + nlmsg_free(skb); + STP_DBG_PR_ERR("%s(): genlmsg_put fail...\n", __func__); + return -1; + } + + rc = nla_put(skb, STP_DBG_ATTR_MSG, len, aucMsg); + if (rc != 0) { + nlmsg_free(skb); + STP_DBG_PR_ERR("%s(): nla_put_string fail...: %d\n", __func__, rc); + return rc; + } + + /* finalize the message */ + genlmsg_end(skb, msg_head); + + /* sending message */ + rc = genlmsg_unicast(&init_net, skb, bind_pid[i]); + if (rc != 0) { + STP_DBG_PR_INFO("%s(): genlmsg_unicast fail...: %d pid: %d\n", + __func__, rc, bind_pid[i]); + if (rc == -ECONNREFUSED) { + bind_pid[i] = 0; + killed_num++; + } + } else { + /* don't retry as long as at least one process receives data */ + ret = 0; + } + } else { + STP_DBG_PR_ERR("%s(): genlmsg_new fail...\n", __func__); + } + } + + if (killed_num > 0) { + if (osal_lock_sleepable_lock(&g_dbg_nl_lock)) { + /* if fail to get lock, it is fine to update bind_pid[] later */ + return ret; + } + + for (i = 0; i < num_bind_process - killed_num; i++) { + if (bind_pid[i] == 0) { + for (j = num_bind_process - 1; j > i; j--) { + if (bind_pid[j] > 0) { + bind_pid[i] = bind_pid[j]; + bind_pid[j] = 0; + } + } + } + } + num_bind_process -= killed_num; + osal_unlock_sleepable_lock(&g_dbg_nl_lock); + } + + return ret; +} + +INT32 stp_dbg_dump_send_retry_handler(PINT8 tmp, INT32 len) +{ + INT32 ret = 0; + INT32 nl_retry = 0; + + if (tmp == NULL) + return -1; + + ret = stp_dbg_nl_send(tmp, 2, len+5); + while (ret) { + nl_retry++; + if (ret == 32) { + STP_DBG_PR_ERR("**dump send timeout : %d**\n", ret); + ret = 1; + break; + } + if (nl_retry > 1000) { + STP_DBG_PR_ERR("**dump send fails, and retry more than 1000: %d.**\n", ret); + ret = 2; + break; + } + STP_DBG_PR_WARN("**dump send fails, and retry again.**\n"); + osal_sleep_ms(3); + ret = stp_dbg_nl_send(tmp, 2, len+5); + if (!ret) + STP_DBG_PR_DBG("****retry again ok!**\n"); + } + + return ret; +} + +INT32 stp_dbg_aee_send(PUINT8 aucMsg, INT32 len, INT32 cmd) +{ +#define KBYTES (1024*sizeof(char)) +#ifndef LOG_STP_DEBUG_DISABLE +#define L1_BUF_SIZE (32*KBYTES) +#define PKT_MULTIPLIER 18 +#else +#define L1_BUF_SIZE (4*KBYTES) +#define PKT_MULTIPLIER 1 +#endif + INT32 ret = 0; + + if (g_core_dump->count == 0) { + g_core_dump->compressor = stp_dbg_compressor_init("core_dump_compressor", + L1_BUF_SIZE, + PKT_MULTIPLIER*g_core_dump->dmp_num*KBYTES); + g_core_dump->count++; + if (!g_core_dump->compressor) { + STP_DBG_PR_ERR("create compressor failed!\n"); + stp_dbg_compressor_deinit(g_core_dump->compressor); + return -1; + } + } + /* buffered to compressor */ + ret = stp_dbg_core_dump_in(g_core_dump, aucMsg, len); + if (ret == 1 && wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO) + stp_dbg_core_dump_flush(0, MTK_WCN_BOOL_FALSE); + + return ret; +} + +INT32 stp_dbg_dump_num(LONG dmp_num) +{ + g_core_dump->dmp_num = dmp_num; + return 0; +} + +static _osal_inline_ INT32 stp_dbg_parser_assert_str(PINT8 str, ENUM_ASSERT_INFO_PARSER_TYPE type) +{ +#define WDT_INFO_HEAD "Watch Dog Timeout" + PINT8 pStr = NULL; + PINT8 pDtr = NULL; + PINT8 pTemp = NULL; + PINT8 pTemp2 = NULL; + INT8 tempBuf[STP_ASSERT_TYPE_SIZE] = { 0 }; + UINT32 len = 0; + LONG res; + INT32 ret; + INT32 remain_array_len = 0; + + PUINT8 parser_sub_string[] = { + "<ASSERT> ", + "id=", + "isr=", + "irq=", + "rc=" + }; + + if (!str) { + STP_DBG_PR_ERR("NULL string source\n"); + return -1; + } + + if (!g_stp_dbg_cpupcr) { + STP_DBG_PR_ERR("NULL pointer\n"); + return -2; + } + + pStr = str; + STP_DBG_PR_DBG("source infor:%s\n", pStr); + switch (type) { + case STP_DBG_ASSERT_INFO: + + + pDtr = osal_strstr(pStr, parser_sub_string[type]); + if (pDtr != NULL) { + pDtr += osal_strlen(parser_sub_string[type]); + pTemp = osal_strchr(pDtr, ' '); + } else { + STP_DBG_PR_ERR("parser str is NULL,substring(%s)\n", parser_sub_string[type]); + return -3; + } + + if (pTemp == NULL) { + STP_DBG_PR_ERR("delimiter( ) is not found,substring(%s)\n", + parser_sub_string[type]); + return -4; + } + + len = pTemp - pDtr; + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], "assert@", osal_strlen("assert@")); + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@")], pDtr, len); + g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len] = '_'; + + pTemp = osal_strchr(pDtr, '#'); + if (pTemp == NULL) { + STP_DBG_PR_ERR("parser '#' is not find\n"); + return -5; + } + pTemp += 1; + + pTemp2 = osal_strchr(pTemp, ' '); + if (pTemp2 == NULL) { + STP_DBG_PR_ERR("parser ' ' is not find\n"); + pTemp2 = pTemp + 1; + } + remain_array_len = osal_array_size(g_stp_dbg_cpupcr->assert_info) - (osal_strlen("assert@") + len + 1); + if (remain_array_len - 1 > pTemp2 - pTemp) { + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1], pTemp, + pTemp2 - pTemp); + g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1 + pTemp2 - pTemp] = '\0'; + } else { + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1], pTemp, + remain_array_len - 1); + g_stp_dbg_cpupcr->assert_info[STP_ASSERT_INFO_SIZE - 1] = '\0'; + } + STP_DBG_PR_INFO("assert info:%s\n", &g_stp_dbg_cpupcr->assert_info[0]); + break; + case STP_DBG_FW_TASK_ID: + pDtr = osal_strstr(pStr, parser_sub_string[type]); + if (pDtr != NULL) { + pDtr += osal_strlen(parser_sub_string[type]); + pTemp = osal_strchr(pDtr, ' '); + } else { + STP_DBG_PR_ERR("parser str is NULL,substring(%s)\n", parser_sub_string[type]); + return -3; + } + + if (pTemp == NULL) { + STP_DBG_PR_ERR("delimiter( ) is not found,substring(%s)\n", + parser_sub_string[type]); + return -4; + } + + len = pTemp - pDtr; + len = (len >= STP_ASSERT_TYPE_SIZE) ? STP_ASSERT_TYPE_SIZE - 1 : len; + osal_memcpy(&tempBuf[0], pDtr, len); + tempBuf[len] = '\0'; + ret = osal_strtol(tempBuf, 16, &res); + if (ret) { + STP_DBG_PR_ERR("get fw task id fail(%d)\n", ret); + return -4; + } + g_stp_dbg_cpupcr->fwTaskId = (UINT32)res; + + STP_DBG_PR_INFO("fw task id :%x\n", (UINT32)res); + break; + case STP_DBG_FW_ISR: + pDtr = osal_strstr(pStr, parser_sub_string[type]); + + if (pDtr != NULL) { + pDtr += osal_strlen(parser_sub_string[type]); + pTemp = osal_strchr(pDtr, ','); + } else { + STP_DBG_PR_ERR("parser str is NULL,substring(%s)\n", + parser_sub_string[type]); + return -3; + } + + if (pTemp == NULL) { + STP_DBG_PR_ERR("delimiter(,) is not found,substring(%s)\n", + parser_sub_string[type]); + return -4; + } + + len = pTemp - pDtr; + len = (len >= STP_ASSERT_TYPE_SIZE) ? STP_ASSERT_TYPE_SIZE - 1 : len; + osal_memcpy(&tempBuf[0], pDtr, len); + tempBuf[len] = '\0'; + ret = osal_strtol(tempBuf, 16, &res); + if (ret) { + STP_DBG_PR_ERR("get fw isr id fail(%d)\n", ret); + return -4; + } + g_stp_dbg_cpupcr->fwIsr = (UINT32)res; + + STP_DBG_PR_INFO("fw isr str:%x\n", (UINT32)res); + break; + case STP_DBG_FW_IRQ: + pDtr = osal_strstr(pStr, parser_sub_string[type]); + if (pDtr != NULL) { + pDtr += osal_strlen(parser_sub_string[type]); + pTemp = osal_strchr(pDtr, ','); + } else { + STP_DBG_PR_ERR("parser str is NULL,substring(%s)\n", parser_sub_string[type]); + return -3; + } + + if (pTemp == NULL) { + STP_DBG_PR_ERR("delimiter(,) is not found,substring(%s)\n", + parser_sub_string[type]); + return -4; + } + + len = pTemp - pDtr; + len = (len >= STP_ASSERT_TYPE_SIZE) ? STP_ASSERT_TYPE_SIZE - 1 : len; + osal_memcpy(&tempBuf[0], pDtr, len); + tempBuf[len] = '\0'; + ret = osal_strtol(tempBuf, 16, &res); + if (ret) { + STP_DBG_PR_ERR("get fw irq id fail(%d)\n", ret); + return -4; + } + g_stp_dbg_cpupcr->fwRrq = (UINT32)res; + + STP_DBG_PR_INFO("fw irq value:%x\n", (UINT32)res); + break; + case STP_DBG_ASSERT_TYPE: + pDtr = osal_strstr(pStr, parser_sub_string[type]); + if (pDtr != NULL) { + pDtr += osal_strlen(parser_sub_string[type]); + pTemp = osal_strchr(pDtr, ','); + } else { + STP_DBG_PR_ERR("parser str is NULL,substring(%s)\n", parser_sub_string[type]); + return -3; + } + + if (pTemp == NULL) { + STP_DBG_PR_ERR("delimiter(,) is not found,substring(%s)\n", + parser_sub_string[type]); + return -4; + } + + len = pTemp - pDtr; + len = (len >= STP_ASSERT_TYPE_SIZE) ? STP_ASSERT_TYPE_SIZE - 1 : len; + osal_memcpy(&tempBuf[0], pDtr, len); + tempBuf[len] = '\0'; + + if (osal_memcmp(tempBuf, "*", osal_strlen("*")) == 0) + osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], "general assert", + osal_strlen("general assert")); + if (osal_memcmp(tempBuf, WDT_INFO_HEAD, osal_strlen(WDT_INFO_HEAD)) == 0) + osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], "wdt", osal_strlen("wdt")); + if (osal_memcmp(tempBuf, "RB_FULL", osal_strlen("RB_FULL")) == 0) { + osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], tempBuf, len); + + pDtr = osal_strstr(&g_stp_dbg_cpupcr->assert_type[0], "RB_FULL("); + if (pDtr != NULL) { + pDtr += osal_strlen("RB_FULL("); + pTemp = osal_strchr(pDtr, ')'); + } else { + STP_DBG_PR_ERR("parser str is NULL,substring(RB_FULL()\n"); + return -5; + } + len = pTemp - pDtr; + len = (len >= STP_ASSERT_TYPE_SIZE) ? STP_ASSERT_TYPE_SIZE - 1 : len; + osal_memcpy(&tempBuf[0], pDtr, len); + tempBuf[len] = '\0'; + ret = osal_strtol(tempBuf, 16, &res); + if (ret) { + STP_DBG_PR_ERR("get fw task id fail(%d)\n", ret); + return -5; + } + g_stp_dbg_cpupcr->fwTaskId = (UINT32)res; + + STP_DBG_PR_INFO("update fw task id :%x\n", (UINT32)res); + } + + STP_DBG_PR_INFO("fw asert type:%s\n", g_stp_dbg_cpupcr->assert_type); + break; + default: + STP_DBG_PR_ERR("unknown parser type\n"); + break; + } + + return 0; +} + +static _osal_inline_ P_STP_DBG_CPUPCR_T stp_dbg_cpupcr_init(VOID) +{ + P_STP_DBG_CPUPCR_T pSdCpupcr = NULL; + + pSdCpupcr = (P_STP_DBG_CPUPCR_T) osal_malloc(osal_sizeof(STP_DBG_CPUPCR_T)); + if (!pSdCpupcr) { + STP_DBG_PR_ERR("stp dbg cpupcr allocate memory fail!\n"); + return NULL; + } + + osal_memset(pSdCpupcr, 0, osal_sizeof(STP_DBG_CPUPCR_T)); + + osal_sleepable_lock_init(&pSdCpupcr->lock); + + return pSdCpupcr; +} + +static _osal_inline_ VOID stp_dbg_cpupcr_deinit(P_STP_DBG_CPUPCR_T pCpupcr) +{ + if (pCpupcr) { + osal_sleepable_lock_deinit(&pCpupcr->lock); + osal_free(pCpupcr); + pCpupcr = NULL; + } +} + +static _osal_inline_ P_STP_DBG_DMAREGS_T stp_dbg_dmaregs_init(VOID) +{ + P_STP_DBG_DMAREGS_T pDmaRegs = NULL; + + pDmaRegs = (P_STP_DBG_DMAREGS_T) osal_malloc(osal_sizeof(STP_DBG_DMAREGS_T)); + if (!pDmaRegs) { + STP_DBG_PR_ERR("stp dbg dmareg allocate memory fail!\n"); + return NULL; + } + + osal_memset(pDmaRegs, 0, osal_sizeof(STP_DBG_DMAREGS_T)); + + osal_sleepable_lock_init(&pDmaRegs->lock); + + return pDmaRegs; +} + +static VOID stp_dbg_dmaregs_deinit(P_STP_DBG_DMAREGS_T pDmaRegs) +{ + if (pDmaRegs) { + osal_sleepable_lock_deinit(&pDmaRegs->lock); + osal_free(pDmaRegs); + pDmaRegs = NULL; + } +} + +INT32 stp_dbg_poll_cpupcr(UINT32 times, UINT32 sleep, UINT32 cmd) +{ + INT32 i = 0; + UINT32 value = 0x0; + ENUM_WMT_CHIP_TYPE chip_type; + UINT8 cccr_value = 0x0; + INT32 chip_id = -1; + INT32 i_ret = 0; + INT32 count = 0; + + if (!g_stp_dbg_cpupcr) { + STP_DBG_PR_ERR("NULL reference pointer\n"); + return -1; + } + + chip_type = wmt_detect_get_chip_type(); + + if (times > STP_DBG_CPUPCR_NUM) + times = STP_DBG_CPUPCR_NUM; + + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + for (i = 0; i < times; i++) { + switch (chip_type) { + case WMT_CHIP_TYPE_COMBO: + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, + g_stp_sdio_host_info.sdio_cltctx, SWPCDBGR, &value, 0); + g_stp_dbg_cpupcr->buffer[g_stp_dbg_cpupcr->count] = value; + osal_get_local_time(&(g_stp_dbg_cpupcr->sec_buffer[g_stp_dbg_cpupcr->count]), + &(g_stp_dbg_cpupcr->nsec_buffer[g_stp_dbg_cpupcr->count])); + break; + case WMT_CHIP_TYPE_SOC: + g_stp_dbg_cpupcr->buffer[g_stp_dbg_cpupcr->count] = wmt_plat_read_cpupcr(); + osal_get_local_time(&(g_stp_dbg_cpupcr->sec_buffer[g_stp_dbg_cpupcr->count]), + &(g_stp_dbg_cpupcr->nsec_buffer[g_stp_dbg_cpupcr->count])); + break; + default: + STP_DBG_PR_ERR("error chip type(%d)\n", chip_type); + } + + if (sleep > 0) + osal_sleep_ms(sleep); + + g_stp_dbg_cpupcr->count++; + if (g_stp_dbg_cpupcr->count >= STP_DBG_CPUPCR_NUM) + g_stp_dbg_cpupcr->count = 0; + } + + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + if (cmd) { + UINT8 str[DBG_LOG_STR_SIZE] = {""}; + PUINT8 p = str; + INT32 str_len = 0; + + for (i = 0; i < STP_DBG_CPUPCR_NUM; i++) { + if (g_stp_dbg_cpupcr->sec_buffer[i] == 0 && + g_stp_dbg_cpupcr->nsec_buffer[i] == 0) + continue; + + count++; + if (count % 4 != 0) { + str_len = osal_sprintf(p, "%llu.%06lu/0x%08x;", + g_stp_dbg_cpupcr->sec_buffer[i], + g_stp_dbg_cpupcr->nsec_buffer[i], + g_stp_dbg_cpupcr->buffer[i]); + p += str_len; + } else { + str_len = osal_sprintf(p, "%llu.%06lu/0x%08x;", + g_stp_dbg_cpupcr->sec_buffer[i], + g_stp_dbg_cpupcr->nsec_buffer[i], + g_stp_dbg_cpupcr->buffer[i]); + STP_DBG_PR_INFO("TIME/CPUPCR: %s\n", str); + p = str; + } + } + if (count % 4 != 0) + STP_DBG_PR_INFO("TIME/CPUPCR: %s\n", str); + + if (chip_type == WMT_CHIP_TYPE_SOC && mtk_consys_check_reg_readable()) { + STP_DBG_PR_INFO("CONNSYS cpu:0x%x/bus:0x%x/dbg_cr1:0x%x/dbg_cr2:0x%x/EMIaddr:0x%x\n", + stp_dbg_soc_read_debug_crs(CONNSYS_CPU_CLK), + stp_dbg_soc_read_debug_crs(CONNSYS_BUS_CLK), + stp_dbg_soc_read_debug_crs(CONNSYS_DEBUG_CR1), + stp_dbg_soc_read_debug_crs(CONNSYS_DEBUG_CR2), + stp_dbg_soc_read_debug_crs(CONNSYS_EMI_REMAP)); + } + + chip_id = mtk_wcn_wmt_chipid_query(); + if (chip_id == 0x6632) { + for (i = 0; i < 8; i++) { + i_ret = mtk_wcn_hif_sdio_f0_readb(g_stp_sdio_host_info.sdio_cltctx, + CCCR_F8 + i, &cccr_value); + if (i_ret) + STP_DBG_PR_ERR("read CCCR fail(%d), address(0x%x)\n", + i_ret, CCCR_F8 + i); + else + STP_DBG_PR_INFO("read CCCR value(0x%x), address(0x%x)\n", + cccr_value, CCCR_F8 + i); + cccr_value = 0x0; + } + } + /* Need in platform code - mtxxxx.c to provide function implementation */ + mtk_wcn_consys_hang_debug(); + } + if (chip_type == WMT_CHIP_TYPE_COMBO) { + STP_DBG_PR_INFO("dump sdio register for debug\n"); + mtk_stp_dump_sdio_register(); + } + return 0; +} + +INT32 stp_dbg_dump_cpupcr_reg_info(PUINT8 buf, UINT32 consys_lp_reg) +{ + INT32 i = 0; + INT32 count = 0; + UINT32 len = 0; + + /* never retrun negative value */ + if (!g_stp_dbg_cpupcr || !buf) { + STP_DBG_PR_DBG("NULL pointer, g_stp_dbg_cpupcr:%p, buf:%p\n", + g_stp_dbg_cpupcr, buf); + return 0; + } + + for (i = 0; i < STP_DBG_CPUPCR_NUM; i++) { + if (g_stp_dbg_cpupcr->sec_buffer[i] == 0 && + g_stp_dbg_cpupcr->nsec_buffer[i] == 0) + continue; + count++; + if (count == 1) + len += osal_sprintf(buf + len, "0x%08x", g_stp_dbg_cpupcr->buffer[i]); + else + len += osal_sprintf(buf + len, ";0x%08x", g_stp_dbg_cpupcr->buffer[i]); + } + + if (count == 0) + len += osal_sprintf(buf + len, "0x%08x\n", consys_lp_reg); + else + len += osal_sprintf(buf + len, ";0x%08x\n", consys_lp_reg); + + stp_dbg_clear_cpupcr_reg_info(); + + return len; +} + +VOID stp_dbg_clear_cpupcr_reg_info(VOID) +{ + if (osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock)) { + STP_DBG_PR_DBG("lock failed\n"); + return; + } + + osal_memset(&g_stp_dbg_cpupcr->buffer[0], 0, STP_DBG_CPUPCR_NUM); + g_stp_dbg_cpupcr->count = 0; + g_stp_dbg_cpupcr->host_assert_info.reason = 0; + g_stp_dbg_cpupcr->host_assert_info.drv_type = 0; + g_stp_dbg_cpupcr->issue_type = STP_FW_ISSUE_TYPE_INVALID; + g_stp_dbg_cpupcr->keyword[0] = '\0'; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); +} + +INT32 stp_dbg_poll_dmaregs(UINT32 times, UINT32 sleep) +{ +#if 0 + INT32 i = 0; + + if (!g_stp_dbg_dmaregs) { + STP_DBG_PR_ERR("NULL reference pointer\n"); + return -1; + } + + osal_lock_sleepable_lock(&g_stp_dbg_dmaregs->lock); + + if (g_stp_dbg_dmaregs->count + times > STP_DBG_DMAREGS_NUM) { + if (g_stp_dbg_dmaregs->count > STP_DBG_DMAREGS_NUM) { + STP_DBG_PR_ERR("g_stp_dbg_dmaregs->count:%d must less than STP_DBG_DMAREGS_NUM:%d\n", + g_stp_dbg_dmaregs->count, STP_DBG_DMAREGS_NUM); + g_stp_dbg_dmaregs->count = 0; + STP_DBG_PR_ERR("g_stp_dbg_dmaregs->count be set default value 0\n"); + } + times = STP_DBG_DMAREGS_NUM - g_stp_dbg_dmaregs->count; + } + if (times > STP_DBG_DMAREGS_NUM) { + STP_DBG_PR_ERR("times overflow, set default value:0\n"); + times = 0; + } + + for (i = 0; i < times; i++) { + INT32 k = 0; + + for (; k < DMA_REGS_MAX; k++) { + STP_DBG_PR_INFO("times:%d,i:%d reg: %s, regs:%08x\n", times, i, dmaRegsStr[k], + wmt_plat_read_dmaregs(k)); + /* g_stp_dbg_dmaregs->dmaIssue[k][g_stp_dbg_dmaregs->count + i] = + * wmt_plat_read_dmaregs(k); + */ + } + osal_sleep_ms(sleep); + } + + g_stp_dbg_dmaregs->count += times; + + osal_unlock_sleepable_lock(&g_stp_dbg_dmaregs->lock); +#else + return 0; +#endif +} + +INT32 stp_dbg_poll_cpupcr_ctrl(UINT32 en) +{ + STP_DBG_PR_INFO("%s polling cpupcr\n", en == 0 ? "start" : "stop"); + + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + g_stp_dbg_cpupcr->stop_flag = en; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + return 0; +} + +INT32 stp_dbg_set_version_info(UINT32 chipid, PUINT8 pRomVer, PUINT8 pPatchVer, PUINT8 pPatchBrh) +{ + if (g_stp_dbg_cpupcr) { + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + g_stp_dbg_cpupcr->chipId = chipid; + + if (pRomVer) + osal_memcpy(g_stp_dbg_cpupcr->romVer, pRomVer, 2); + if (pPatchVer) + osal_memcpy(g_stp_dbg_cpupcr->patchVer, pPatchVer, 8); + if (pPatchBrh) + osal_memcpy(g_stp_dbg_cpupcr->branchVer, pPatchBrh, 4); + + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + } else { + STP_DBG_PR_ERR("NULL pointer\n"); + return -1; + } + + STP_DBG_PR_DBG("chipid(0x%x),romver(%s),patchver(%s),branchver(%s)\n", + g_stp_dbg_cpupcr->chipId, + &g_stp_dbg_cpupcr->romVer[0], + &g_stp_dbg_cpupcr->patchVer[0], + &g_stp_dbg_cpupcr->branchVer[0]); + + return 0; +} + +INT32 stp_dbg_set_wifiver(UINT32 wifiver) +{ + if (!g_stp_dbg_cpupcr) { + STP_DBG_PR_ERR("NULL pointer\n"); + return -1; + } + + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + g_stp_dbg_cpupcr->wifiVer = wifiver; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + STP_DBG_PR_INFO("wifiver(%x)\n", g_stp_dbg_cpupcr->wifiVer); + + return 0; +} + +INT32 stp_dbg_set_host_assert_info(UINT32 drv_type, UINT32 reason, UINT32 en) +{ + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + g_stp_dbg_cpupcr->host_assert_info.assert_from_host = en; + g_stp_dbg_cpupcr->host_assert_info.drv_type = drv_type; + g_stp_dbg_cpupcr->host_assert_info.reason = reason; + + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + return 0; +} + +VOID stp_dbg_set_keyword(PINT8 keyword) +{ + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + if (keyword != NULL) { + if (osal_strlen(keyword) >= STP_DBG_KEYWORD_SIZE) + STP_DBG_PR_INFO("Keyword over max size(%d)\n", STP_DBG_KEYWORD_SIZE); + else if (osal_strchr(keyword, '<') != NULL || osal_strchr(keyword, '>') != NULL) + STP_DBG_PR_INFO("Keyword has < or >, keywrod: %s\n", keyword); + else + osal_strncat(&g_stp_dbg_cpupcr->keyword[0], keyword, osal_strlen(keyword)); + } else { + g_stp_dbg_cpupcr->keyword[0] = '\0'; + } + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); +} + +UINT32 stp_dbg_get_host_trigger_assert(VOID) +{ + return g_stp_dbg_cpupcr->host_assert_info.assert_from_host; +} + +VOID stp_dbg_set_coredump_timer_state(CORE_DUMP_STA state) +{ + if (g_core_dump) + g_core_dump->sm = state; +} + +INT32 stp_dbg_get_coredump_timer_state(VOID) +{ + if (g_core_dump) + return g_core_dump->sm; + return -1; +} + +INT32 stp_dbg_set_fw_info(PUINT8 issue_info, UINT32 len, ENUM_STP_FW_ISSUE_TYPE issue_type) +{ + ENUM_ASSERT_INFO_PARSER_TYPE type_index; + PUINT8 tempbuf = NULL; + UINT32 i = 0; + INT32 iRet = 0; + + if (issue_info == NULL) { + STP_DBG_PR_ERR("null issue infor\n"); + return -1; + } + + if (g_stp_dbg_cpupcr->issue_type && + g_stp_dbg_cpupcr->issue_type != STP_HOST_TRIGGER_COLLECT_FTRACE) { + STP_DBG_PR_ERR("assert information has been set up\n"); + return -1; + } + + STP_DBG_PR_INFO("issue type(%d)\n", issue_type); + g_stp_dbg_cpupcr->issue_type = issue_type; + osal_memset(&g_stp_dbg_cpupcr->assert_info[0], 0, STP_ASSERT_INFO_SIZE); + + /*print patch version when assert happened */ + STP_DBG_PR_INFO("[consys patch]patch version:%s\n", g_stp_dbg_cpupcr->patchVer); + STP_DBG_PR_INFO("[consys patch]ALPS branch:%s\n", g_stp_dbg_cpupcr->branchVer); + + if ((issue_type == STP_FW_ASSERT_ISSUE) || + (issue_type == STP_HOST_TRIGGER_FW_ASSERT) || + (issue_type == STP_HOST_TRIGGER_ASSERT_TIMEOUT) || + (issue_type == STP_HOST_TRIGGER_COLLECT_FTRACE)) { + if ((issue_type == STP_FW_ASSERT_ISSUE) || (issue_type == STP_HOST_TRIGGER_FW_ASSERT)) { + tempbuf = osal_malloc(len + 1); + if (!tempbuf) + return -2; + + osal_memcpy(&tempbuf[0], issue_info, len); + + for (i = 0; i < len; i++) { + if (tempbuf[i] == '\0') + tempbuf[i] = '?'; + } + + tempbuf[len] = '\0'; + + for (type_index = STP_DBG_ASSERT_INFO; type_index < STP_DBG_PARSER_TYPE_MAX; + type_index++) + iRet += stp_dbg_parser_assert_str(&tempbuf[0], type_index); + + if (iRet) + STP_DBG_PR_ERR("passert assert infor fail(%d)\n", iRet); + + } + if ((issue_type == STP_HOST_TRIGGER_FW_ASSERT) || + (issue_type == STP_HOST_TRIGGER_ASSERT_TIMEOUT) || + (issue_type == STP_HOST_TRIGGER_COLLECT_FTRACE)) { + g_stp_dbg_cpupcr->fwIsr = 0; + g_stp_dbg_cpupcr->fwRrq = 0; + + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + switch (g_stp_dbg_cpupcr->host_assert_info.drv_type) { + case WMTDRV_TYPE_BT: + STP_DBG_PR_INFO("BT trigger assert\n"); + if (g_stp_dbg_cpupcr->host_assert_info.reason != 31) + g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_BT; /*BT firmware trigger assert */ + else { + /*BT stack trigger assert */ + g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_NATBT; + } + break; + case WMTDRV_TYPE_FM: + STP_DBG_PR_INFO("FM trigger assert\n"); + g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_FM; + break; + case WMTDRV_TYPE_GPS: + STP_DBG_PR_INFO("GPS trigger assert\n"); + g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_DRVGPS; + break; + case WMTDRV_TYPE_WIFI: + STP_DBG_PR_INFO("WIFI trigger assert\n"); + g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_DRVWIFI; + break; + case WMTDRV_TYPE_WMT: + STP_DBG_PR_INFO("WMT trigger assert\n"); + if (issue_type == STP_HOST_TRIGGER_ASSERT_TIMEOUT) + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); + /* 30: adb trigger assert */ + /* 43: process packet fail count > 10 */ + /* 44: rx timeout with pending data */ + /* 45: tx timeout with pending data */ + if (g_stp_dbg_cpupcr->host_assert_info.reason == 30 || + g_stp_dbg_cpupcr->host_assert_info.reason == 43 || + g_stp_dbg_cpupcr->host_assert_info.reason == 44 || + g_stp_dbg_cpupcr->host_assert_info.reason == 45) + g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_DRVSTP; + else + g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_WMT; + break; + default: + break; + } + g_stp_dbg_cpupcr->host_assert_info.assert_from_host = 0; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + } + osal_free(tempbuf); + } else if (issue_type == STP_FW_NOACK_ISSUE) { + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); + g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_DRVSTP; + g_stp_dbg_cpupcr->fwRrq = 0; + g_stp_dbg_cpupcr->fwIsr = 0; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + } else if (issue_type == STP_DBG_PROC_TEST) { + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); + g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_WMT; + g_stp_dbg_cpupcr->fwRrq = 0; + g_stp_dbg_cpupcr->fwIsr = 0; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + } else if (issue_type == STP_FW_WARM_RST_ISSUE) { + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); + g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_WMT; + g_stp_dbg_cpupcr->fwRrq = 0; + g_stp_dbg_cpupcr->fwIsr = 0; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + } else if (issue_type == STP_FW_ABT) { + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len); + g_stp_dbg_cpupcr->fwTaskId = STP_DBG_TASK_WMT; + g_stp_dbg_cpupcr->fwRrq = 0; + g_stp_dbg_cpupcr->fwIsr = 0; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + } else { + STP_DBG_PR_ERR("invalid issue type(%d)\n", issue_type); + return -3; + } + + return iRet; +} + +INT32 stp_dbg_cpupcr_infor_format(PUINT8 buf, UINT32 max_len) +{ + UINT32 len = 0; + UINT32 i = 0; + + /* never retrun negative value */ + if (!g_stp_dbg_cpupcr || !buf) { + STP_DBG_PR_ERR("NULL pointer, g_stp_dbg_cpupcr:%p, buf:%p\n", + g_stp_dbg_cpupcr, buf); + return 0; + } + + /* format common information about issue */ + /* max_len can guarantee there's enough buffer for <main> section */ + len = osal_sprintf(buf, "<main>\n\t"); + len += osal_sprintf(buf + len, "<chipid>\n\t\tMT%x\n\t</chipid>\n\t", + g_stp_dbg_cpupcr->chipId); + len += osal_sprintf(buf + len, "<version>\n\t\t"); + len += osal_sprintf(buf + len, "<rom>%s</rom>\n\t\t", g_stp_dbg_cpupcr->romVer); + if (!(osal_memcmp(g_stp_dbg_cpupcr->branchVer, "ALPS", strlen("ALPS")))) + len += osal_sprintf(buf + len, "<branch>Internal Dev</branch>\n\t\t", + g_stp_dbg_cpupcr->branchVer); + else + len += osal_sprintf(buf + len, "<branch>W%sMP</branch>\n\t\t", + g_stp_dbg_cpupcr->branchVer); + + len += osal_sprintf(buf + len, "<patch>%s</patch>\n\t\t", g_stp_dbg_cpupcr->patchVer); + + if (g_stp_dbg_cpupcr->wifiVer == 0) + len += osal_sprintf(buf + len, "<wifi>NULL</wifi>\n\t"); + else + len += osal_sprintf(buf + len, "<wifi>0x%X.%X</wifi>\n\t", + (UINT8)((g_stp_dbg_cpupcr->wifiVer & 0xFF00)>>8), + (UINT8)(g_stp_dbg_cpupcr->wifiVer & 0xFF)); + + len += osal_sprintf(buf + len, "</version>\n\t"); + + /*format issue information: no ack, assert */ + len += osal_sprintf(buf + len, "<issue>\n\t\t<classification>\n\t\t\t"); + if ((g_stp_dbg_cpupcr->issue_type == STP_FW_NOACK_ISSUE) || + (g_stp_dbg_cpupcr->issue_type == STP_DBG_PROC_TEST) || + (g_stp_dbg_cpupcr->issue_type == STP_FW_WARM_RST_ISSUE) || + (g_stp_dbg_cpupcr->issue_type == STP_FW_ABT)) { + len += osal_sprintf(buf + len, "%s\n\t\t</classification>\n\t\t<rc>\n\t\t\t", + g_stp_dbg_cpupcr->assert_info); + len += osal_sprintf(buf + len, "NULL\n\t\t</rc>\n\t</issue>\n\t"); + len += osal_sprintf(buf + len, "<hint>\n\t\t<time_align>NULL</time_align>\n\t\t"); + len += osal_sprintf(buf + len, "<host>NULL</host>\n\t\t"); + len += osal_sprintf(buf + len, "<client>\n\t\t\t<task>%s</task>\n\t\t\t", + stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId)); + len += osal_sprintf(buf + len, "<irqx>IRQ_0x%x</irqx>\n\t\t\t", g_stp_dbg_cpupcr->fwRrq); + len += osal_sprintf(buf + len, "<isr>0x%x</isr>\n\t\t\t", g_stp_dbg_cpupcr->fwIsr); + len += osal_sprintf(buf + len, "<drv_type>NULL</drv_type>\n\t\t\t"); + len += osal_sprintf(buf + len, "<reason>NULL</reason>\n\t\t\t"); + len += osal_sprintf(buf + len, "<keyword>%s</keyword>\n\t\t\t", + g_stp_dbg_cpupcr->keyword); + } else if ((g_stp_dbg_cpupcr->issue_type == STP_FW_ASSERT_ISSUE) || + (g_stp_dbg_cpupcr->issue_type == STP_HOST_TRIGGER_FW_ASSERT) || + (g_stp_dbg_cpupcr->issue_type == STP_HOST_TRIGGER_ASSERT_TIMEOUT)) { + len += osal_sprintf(buf + len, "%s\n\t\t</classification>\n\t\t<rc>\n\t\t\t", + g_stp_dbg_cpupcr->assert_info); + len += osal_sprintf(buf + len, "%s\n\t\t</rc>\n\t</issue>\n\t", + g_stp_dbg_cpupcr->assert_type); + len += osal_sprintf(buf + len, "<hint>\n\t\t<time_align>NULL</time_align>\n\t\t"); + len += osal_sprintf(buf + len, "<host>NULL</host>\n\t\t"); + len += osal_sprintf(buf + len, "<client>\n\t\t\t<task>%s</task>\n\t\t\t", + stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId)); + if (g_stp_dbg_cpupcr->host_assert_info.reason == 32 || + g_stp_dbg_cpupcr->host_assert_info.reason == 33 || + g_stp_dbg_cpupcr->host_assert_info.reason == 34 || + g_stp_dbg_cpupcr->host_assert_info.reason == 35 || + g_stp_dbg_cpupcr->host_assert_info.reason == 36 || + g_stp_dbg_cpupcr->host_assert_info.reason == 37 || + g_stp_dbg_cpupcr->host_assert_info.reason == 38 || + g_stp_dbg_cpupcr->host_assert_info.reason == 39 || + g_stp_dbg_cpupcr->host_assert_info.reason == 40) { + /*handling wmt turn on/off bt cmd has ack but no evt issue */ + /*one of both the irqx and irs is nULL, then use task to find MOF */ + len += osal_sprintf(buf + len, "<irqx>NULL</irqx>\n\t\t\t"); + } else + len += osal_sprintf(buf + len, "<irqx>IRQ_0x%x</irqx>\n\t\t\t", + g_stp_dbg_cpupcr->fwRrq); + len += osal_sprintf(buf + len, "<isr>0x%x</isr>\n\t\t\t", g_stp_dbg_cpupcr->fwIsr); + + if (g_stp_dbg_cpupcr->issue_type == STP_FW_ASSERT_ISSUE) { + len += osal_sprintf(buf + len, "<drv_type>NULL</drv_type>\n\t\t\t"); + len += osal_sprintf(buf + len, "<reason>NULL</reason>\n\t\t\t"); + } + + if ((g_stp_dbg_cpupcr->issue_type == STP_HOST_TRIGGER_FW_ASSERT) || + (g_stp_dbg_cpupcr->issue_type == STP_HOST_TRIGGER_ASSERT_TIMEOUT)) { + len += osal_sprintf(buf + len, "<drv_type>%d</drv_type>\n\t\t\t", + g_stp_dbg_cpupcr->host_assert_info.drv_type); + len += osal_sprintf(buf + len, "<reason>%d</reason>\n\t\t\t", + g_stp_dbg_cpupcr->host_assert_info.reason); + } + + len += osal_sprintf(buf + len, "<keyword>%s</keyword>\n\t\t\t", + g_stp_dbg_cpupcr->keyword); + } else { + len += osal_sprintf(buf + len, "NULL\n\t\t</classification>\n\t\t<rc>\n\t\t\t"); + len += osal_sprintf(buf + len, "NULL\n\t\t</rc>\n\t</issue>\n\t"); + len += osal_sprintf(buf + len, "<hint>\n\t\t<time_align>NULL</time_align>\n\t\t"); + len += osal_sprintf(buf + len, "<host>NULL</host>\n\t\t"); + len += osal_sprintf(buf + len, "<client>\n\t\t\t<task>%s</task>\n\t\t\t", + stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId)); + len += osal_sprintf(buf + len, "<irqx>NULL</irqx>\n\t\t\t"); + len += osal_sprintf(buf + len, "<isr>NULL</isr>\n\t\t\t"); + len += osal_sprintf(buf + len, "<drv_type>NULL</drv_type>\n\t\t\t"); + len += osal_sprintf(buf + len, "<reason>NULL</reason>\n\t\t\t"); + len += osal_sprintf(buf + len, "<keyword>%s</keyword>\n\t\t\t", + g_stp_dbg_cpupcr->keyword); + } + + len += osal_sprintf(buf + len, "<pctrace>"); + STP_DBG_PR_INFO("stp-dbg:sub len1 for debug(%d)\n", len); + + if (!g_stp_dbg_cpupcr->count) + len += osal_sprintf(buf + len, "NULL"); + else { + for (i = 0; i < g_stp_dbg_cpupcr->count; i++) + len += osal_sprintf(buf + len, "%08x,", g_stp_dbg_cpupcr->buffer[i]); + } + STP_DBG_PR_INFO("stp-dbg:sub len2 for debug(%d)\n", len); + len += osal_sprintf(buf + len, "</pctrace>\n\t\t\t"); + len += osal_sprintf(buf + len, + "<extension>NULL</extension>\n\t\t</client>\n\t</hint>\n</main>\n"); + + STP_DBG_PR_INFO("buffer len[%d]\n", len); + /* STP_DBG_PR_INFO("Format infor:\n%s\n",buf); */ + + osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + osal_memset(&g_stp_dbg_cpupcr->buffer[0], 0, STP_DBG_CPUPCR_NUM); + g_stp_dbg_cpupcr->count = 0; + g_stp_dbg_cpupcr->host_assert_info.reason = 0; + g_stp_dbg_cpupcr->host_assert_info.drv_type = 0; + g_stp_dbg_cpupcr->issue_type = STP_FW_ISSUE_TYPE_INVALID; + g_stp_dbg_cpupcr->keyword[0] = '\0'; + g_stp_dbg_cpupcr->fwRrq = 0; + g_stp_dbg_cpupcr->fwIsr = 0; + osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock); + + return len; +} + +PUINT8 stp_dbg_id_to_task(UINT32 id) +{ + ENUM_WMT_CHIP_TYPE chip_type; + PUINT8 task_id = NULL; + + chip_type = wmt_detect_get_chip_type(); + switch (chip_type) { + case WMT_CHIP_TYPE_COMBO: + task_id = stp_dbg_combo_id_to_task(id); + break; + case WMT_CHIP_TYPE_SOC: + task_id = stp_dbg_soc_id_to_task(id); + break; + default: + STP_DBG_PR_ERR("error chip type(%d)\n", chip_type); + } + + return task_id; +} + +VOID stp_dbg_reset(VOID) +{ + if (g_stp_dbg_cpupcr) { + osal_memset(g_stp_dbg_cpupcr->buffer, 0, osal_sizeof(g_stp_dbg_cpupcr->buffer)); + osal_memset(g_stp_dbg_cpupcr->sec_buffer, 0, osal_sizeof(g_stp_dbg_cpupcr->sec_buffer)); + osal_memset(g_stp_dbg_cpupcr->nsec_buffer, 0, osal_sizeof(g_stp_dbg_cpupcr->nsec_buffer)); + } + + if (g_stp_dbg_dmaregs) { + g_stp_dbg_dmaregs->count = 0; + osal_memset(g_stp_dbg_dmaregs->dmaIssue, 0, osal_sizeof(g_stp_dbg_dmaregs->dmaIssue)); + } +} + +MTKSTP_DBG_T *stp_dbg_init(PVOID btm_half) +{ + MTKSTP_DBG_T *stp_dbg = NULL; + + stp_dbg = kzalloc(sizeof(MTKSTP_DBG_T), GFP_KERNEL); + if (stp_dbg == NULL) + goto ERR_EXIT1; + if (IS_ERR(stp_dbg)) { + STP_DBG_PR_ERR("-ENOMEM\n"); + goto ERR_EXIT1; + } + + stp_dbg->logsys = vmalloc(sizeof(MTKSTP_LOG_SYS_T)); + if (stp_dbg->logsys == NULL) + goto ERR_EXIT2; + if (IS_ERR(stp_dbg->logsys)) { + STP_DBG_PR_ERR("-ENOMEM stp_gdb->logsys\n"); + goto ERR_EXIT2; + } + memset(stp_dbg->logsys, 0, sizeof(MTKSTP_LOG_SYS_T)); + spin_lock_init(&(stp_dbg->logsys->lock)); + INIT_WORK(&(stp_dbg->logsys->dump_work), stp_dbg_dmp_print_work); + stp_dbg->pkt_trace_no = 0; + stp_dbg->is_enable = 0; + g_stp_dbg = stp_dbg; + + if (btm_half != NULL) + stp_dbg->btm = btm_half; + else + stp_dbg->btm = NULL; + + g_core_dump = stp_dbg_core_dump_init(STP_CORE_DUMP_TIMEOUT); + if (!g_core_dump) { + STP_DBG_PR_ERR("-ENOMEM wcn_coer_dump_init fail!"); + goto ERR_EXIT2; + } + g_stp_dbg_cpupcr = stp_dbg_cpupcr_init(); + if (!g_stp_dbg_cpupcr) { + STP_DBG_PR_ERR("-ENOMEM stp_dbg_cpupcr_init fail!"); + goto ERR_EXIT2; + } + g_stp_dbg_dmaregs = stp_dbg_dmaregs_init(); + if (!g_stp_dbg_dmaregs) { + STP_DBG_PR_ERR("-ENOMEM stp_dbg_dmaregs_init fail!"); + goto ERR_EXIT2; + } + return stp_dbg; + +ERR_EXIT2: + stp_dbg_deinit(stp_dbg); + return NULL; + +ERR_EXIT1: + kfree(stp_dbg); + return NULL; +} + +INT32 stp_dbg_deinit(MTKSTP_DBG_T *stp_dbg) +{ + stp_dbg_core_dump_deinit(g_core_dump); + + stp_dbg_cpupcr_deinit(g_stp_dbg_cpupcr); + stp_dbg_dmaregs_deinit(g_stp_dbg_dmaregs); + /* unbind with netlink */ + stp_dbg_nl_deinit(); + + if (stp_dbg->logsys) + vfree(stp_dbg->logsys); + + kfree(stp_dbg); + + return 0; +} + +INT32 stp_dbg_start_coredump_timer(VOID) +{ + if (!g_core_dump) { + STP_DBG_PR_ERR("invalid pointer!\n"); + return -1; + } + + return osal_timer_modify(&g_core_dump->dmp_timer, STP_CORE_DUMP_TIMEOUT); +} + +INT32 stp_dbg_start_emi_dump(VOID) +{ + INT32 ret = 0; + + if (!g_core_dump) { + STP_DBG_PR_ERR("invalid pointer!\n"); + return -1; + } + + if (mtk_wcn_wlan_emi_mpu_set_protection) + (*mtk_wcn_wlan_emi_mpu_set_protection)(false); + /* Disable MCIF EMI protection */ + mtk_wcn_wmt_set_mcif_mpu_protection(false); + stp_dbg_set_coredump_timer_state(CORE_DUMP_DOING); + osal_timer_modify(&g_core_dump->dmp_emi_timer, STP_EMI_DUMP_TIMEOUT); + ret = stp_dbg_nl_send_data(EMICOREDUMP_CMD, sizeof(EMICOREDUMP_CMD)); + if (ret) + stp_dbg_stop_emi_dump(); + + return ret ? -1 : 0; +} + +INT32 stp_dbg_stop_emi_dump(VOID) +{ + if (!g_core_dump) { + STP_DBG_PR_ERR("invalid pointer!\n"); + return -1; + } + + if (mtk_wcn_stp_emi_dump_flag_get() == 1) { + STP_DBG_PR_ERR("stopping emi dump!\n"); + return -2; + } + + mtk_wcn_stp_emi_dump_flag_ctrl(1); + /* Enable MCIF EMI protection */ + mtk_wcn_wmt_set_mcif_mpu_protection(true); + if (mtk_wcn_wlan_emi_mpu_set_protection) + (*mtk_wcn_wlan_emi_mpu_set_protection)(true); + osal_timer_stop(&g_core_dump->dmp_emi_timer); + return 0; +} + +INT32 stp_dbg_nl_send_data(const PINT8 buf, INT32 len) +{ + PINT8 pdata = NULL; + INT32 ret = 0; + + pdata = kmalloc(len+5, GFP_KERNEL); + if (!pdata) + return -1; + pdata[0] = '['; + pdata[1] = 'M'; + pdata[2] = ']'; + osal_memcpy(&pdata[3], &len, 2); + osal_memcpy(&pdata[5], buf, len); + ret = stp_dbg_dump_send_retry_handler(pdata, len); + kfree(pdata); + return ret; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg_combo.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg_combo.c new file mode 100644 index 00000000000000..d9440ff6ce7f6c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg_combo.c @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include "stp_dbg.h" +#include "stp_dbg_combo.h" + +static _osal_inline_ INT32 stp_dbg_combo_put_dump_to_aee(VOID); +static _osal_inline_ INT32 stp_dbg_combo_put_dump_to_nl(VOID); + +static PUINT8 combo_task_str[STP_DBG_TASK_ID_MAX] = { + "Task_WMT", + "Task_BT", + "Task_Wifi", + "Task_Tst", + "Task_FM", + "Task_GPS", + "Task_FLP", + "Task_BAL", + "Task_Idle", + "Task_DrvStp", + "Task_DrvSdio", + "Task_NatBt", + "Task_DrvWifi", + "Task_GPS" +}; + +INT32 const combo_legacy_task_id_adapter[STP_DBG_TASK_ID_MAX] = { + STP_DBG_TASK_WMT, + STP_DBG_TASK_BT, + STP_DBG_TASK_WIFI, + STP_DBG_TASK_TST, + STP_DBG_TASK_FM, + STP_DBG_TASK_IDLE, + STP_DBG_TASK_WMT, + STP_DBG_TASK_WMT, + STP_DBG_TASK_WMT, + STP_DBG_TASK_DRVSTP, + STP_DBG_TASK_BUS, + STP_DBG_TASK_NATBT, + STP_DBG_TASK_DRVWIFI, + STP_DBG_TASK_DRVGPS +}; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +static _osal_inline_ INT32 stp_dbg_combo_put_dump_to_aee(VOID) +{ + static UINT8 buf[2048]; + static UINT8 tmp[2048]; + + UINT32 buf_len; + STP_PACKET_T *pkt; + STP_DBG_HDR_T *hdr; + INT32 remain = 0; + INT32 retry = 0; + INT32 ret = 0; + + do { + remain = stp_dbg_dmp_out_ex(&buf[0], &buf_len); + if (buf_len > 0) { + pkt = (STP_PACKET_T *) buf; + hdr = &pkt->hdr; + if (hdr->dbg_type == STP_DBG_FW_DMP) { + if (pkt->hdr.len <= 1500) { + tmp[pkt->hdr.len] = '\n'; + tmp[pkt->hdr.len + 1] = '\0'; + osal_memcpy(&tmp[0], pkt->raw, pkt->hdr.len); + + ret = stp_dbg_aee_send(tmp, pkt->hdr.len, 0); + } else { + STP_DBG_PR_INFO("dump entry length is over long\n"); + osal_bug_on(0); + } + retry = 0; + } + retry = 0; + } else { + retry++; + osal_sleep_ms(20); + } + } while ((remain > 0) || (retry < 10)); + + return ret; +} + +static _osal_inline_ INT32 stp_dbg_combo_put_dump_to_nl(VOID) +{ +#define NUM_FETCH_ENTRY 8 + + static UINT8 buf[2048]; + static UINT8 tmp[2048]; + + UINT32 buf_len; + STP_PACKET_T *pkt; + STP_DBG_HDR_T *hdr; + INT32 remain = 0; + INT32 index = 0; + INT32 retry = 0; + INT32 ret = 0; + INT32 len; + + index = 0; + tmp[index++] = '['; + tmp[index++] = 'M'; + tmp[index++] = ']'; + + do { + index = 3; + remain = stp_dbg_dmp_out_ex(&buf[0], &buf_len); + if (buf_len > 0) { + pkt = (STP_PACKET_T *) buf; + hdr = &pkt->hdr; + len = pkt->hdr.len; + osal_memcpy(&tmp[index], &len, 2); + index += 2; + if (hdr->dbg_type == STP_DBG_FW_DMP) { + osal_memcpy(&tmp[index], pkt->raw, pkt->hdr.len); + + if (pkt->hdr.len <= 1500) { + tmp[index + pkt->hdr.len] = '\n'; + tmp[index + pkt->hdr.len + 1] = '\0'; + + /* pr_warn("\n%s\n+++\n", tmp); */ + ret = stp_dbg_dump_send_retry_handler((PINT8)&tmp, len); + if (ret) + break; + + /* schedule(); */ + } else { + STP_DBG_PR_INFO("dump entry length is over long\n"); + osal_bug_on(0); + } + retry = 0; + } + } else { + retry++; + osal_sleep_ms(100); + } + } while ((remain > 0) || (retry < 2)); + + return ret; +} +#pragma GCC diagnostic pop + +INT32 stp_dbg_combo_core_dump(INT32 dump_sink) +{ + INT32 ret = 0; + + switch (dump_sink) { + case 0: + STP_DBG_PR_INFO("coredump is disabled!\n"); + break; + case 1: + ret = stp_dbg_combo_put_dump_to_aee(); + break; + case 2: + ret = stp_dbg_combo_put_dump_to_nl(); + break; + default: + ret = -1; + STP_DBG_PR_ERR("unknown sink %d\n", dump_sink); + } + + return ret; +} + +PUINT8 stp_dbg_combo_id_to_task(UINT32 id) +{ + UINT32 chip_id = mtk_wcn_wmt_chipid_query(); + UINT32 temp_id; + + if (id >= STP_DBG_TASK_ID_MAX) { + STP_DBG_PR_ERR("task id(%d) overflow(%d)\n", id, STP_DBG_TASK_ID_MAX); + return NULL; + } + + switch (chip_id) { + case 0x6632: + temp_id = id; + break; + default: + temp_id = combo_legacy_task_id_adapter[id]; + break; + } + + return combo_task_str[temp_id]; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg_soc.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg_soc.c new file mode 100644 index 00000000000000..57ee600377c249 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_dbg_soc.c @@ -0,0 +1,575 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include "stp_dbg.h" +#include "stp_dbg_soc.h" +#include "btm_core.h" +#include "stp_core.h" +#include "mtk_wcn_consys_hw.h" +#include "wmt_step.h" +#include "wmt_lib.h" +#include <linux/ratelimit.h> + +#define STP_DBG_PAGED_TRACE_SIZE (2048*sizeof(char)) +#define SUB_PKT_SIZE 1024 +#define EMI_SYNC_TIMEOUT 100 /* FW guarantee that MCU copy data time is ~20ms. We set 100ms for safety */ +#define IS_VISIBLE_CHAR(c) ((c) >= 32 && (c) <= 126) +#define DUMP_LOG_BYTES_PER_LINE (128) + +#define ROM_V2_PATCH "ROMv2" +#define ROM_V3_PATCH "ROMv3" +#define ROM_V4_PATCH "ROMv4" + +ENUM_STP_FW_ISSUE_TYPE issue_type; +UINT8 g_paged_trace_buffer[STP_DBG_PAGED_TRACE_SIZE] = { 0 }; +UINT32 g_paged_trace_len; +UINT8 g_paged_dump_buffer[STP_DBG_PAGED_DUMP_BUFFER_SIZE] = { 0 }; +UINT32 g_paged_dump_len; + +static PUINT8 soc_task_str[STP_DBG_TASK_ID_MAX] = { + "Task_WMT", + "Task_BT", + "Task_Wifi", + "Task_Tst", + "Task_FM", + "Task_GPS", + "Task_FLP", + "Task_BT2", + "Task_Idle", + "Task_DrvStp", + "Task_DrvBtif", + "Task_NatBt", + "Task_DrvWifi", + "Task_GPS" +}; + +INT32 const soc_gen_two_task_id_adapter[STP_DBG_TASK_ID_MAX] = { + STP_DBG_TASK_WMT, + STP_DBG_TASK_BT, + STP_DBG_TASK_WIFI, + STP_DBG_TASK_TST, + STP_DBG_TASK_FM, + STP_DBG_TASK_IDLE, + STP_DBG_TASK_WMT, + STP_DBG_TASK_WMT, + STP_DBG_TASK_WMT, + STP_DBG_TASK_DRVSTP, + STP_DBG_TASK_BUS, + STP_DBG_TASK_NATBT, + STP_DBG_TASK_DRVWIFI, + STP_DBG_TASK_DRVGPS +}; + +INT32 const soc_gen_three_task_id_adapter[STP_DBG_TASK_ID_MAX] = { + STP_DBG_TASK_WMT, + STP_DBG_TASK_BT, + STP_DBG_TASK_WIFI, + STP_DBG_TASK_TST, + STP_DBG_TASK_FM, + STP_DBG_TASK_GPS, + STP_DBG_TASK_FLP, + STP_DBG_TASK_IDLE, + STP_DBG_TASK_WMT, + STP_DBG_TASK_DRVSTP, + STP_DBG_TASK_BUS, + STP_DBG_TASK_NATBT, + STP_DBG_TASK_DRVWIFI, + STP_DBG_TASK_DRVGPS +}; + +static _osal_inline_ INT32 stp_dbg_soc_paged_dump(INT32 dump_sink); +static _osal_inline_ INT32 stp_dbg_soc_paged_trace(VOID); +static _osal_inline_ INT32 stp_dbg_soc_put_emi_dump_to_nl(PUINT8 data_buf, INT32 dump_len); +static _osal_inline_ VOID stp_dbg_soc_emi_dump_buffer(UINT8 *buffer, UINT32 len); + +static VOID stp_dbg_dump_log(PUINT8 buf, INT32 size) +{ + INT32 i = 0; + UINT8 line[DUMP_LOG_BYTES_PER_LINE + 1]; + + while (size--) { + if (IS_VISIBLE_CHAR(*buf)) + line[i] = *buf; + else + line[i] = '.'; + i++; + buf++; + + if (i >= DUMP_LOG_BYTES_PER_LINE || !size) { + line[i] = 0; + pr_info("page_trace: %s\n", line); + i = 0; + } + } +} + +static _osal_inline_ VOID stp_dbg_soc_emi_dump_buffer(UINT8 *buffer, UINT32 len) +{ + UINT32 i = 0; + + if (len > 16) + len = 16; + for (i = 0; i < len; i++) { + if (i % 16 == 0 && i != 0) + pr_cont("\n "); + + if (buffer[i] == ']' || buffer[i] == '[' || buffer[i] == ',') + pr_cont("%c", buffer[i]); + else + pr_cont("0x%02x ", buffer[i]); + } +} + +static _osal_inline_ INT32 stp_dbg_soc_put_emi_dump_to_nl(PUINT8 data_buf, INT32 dump_len) +{ + static UINT8 tmp[SUB_PKT_SIZE + NL_PKT_HEADER_LEN]; + INT32 remain = dump_len, index = 0; + INT32 ret = 0; + INT32 len; + INT32 offset = 0; + + if (dump_len > 0) { + index = 0; + tmp[index++] = '['; + tmp[index++] = 'M'; + tmp[index++] = ']'; + + do { + index = 3; + if (remain >= SUB_PKT_SIZE) + len = SUB_PKT_SIZE; + else + len = remain; + remain -= len; + + osal_memcpy(&tmp[index], &len, 2); + index += 2; + osal_memcpy(&tmp[index], data_buf + offset, len); + offset += len; + STP_DBG_PR_DBG("send %d remain %d\n", len, remain); + + ret = stp_dbg_dump_send_retry_handler((PINT8)&tmp, len); + if (ret) + break; + + /* schedule(); */ + } while (remain > 0); + } else + STP_DBG_PR_INFO("dump entry length is 0\n"); + + return ret; +} + +static _osal_inline_ UINT64 stp_dbg_soc_elapsed_time(UINT64 ts, ULONG nsec) +{ + UINT64 current_ts = 0; + ULONG current_nsec = 0; + + osal_get_local_time(¤t_ts, ¤t_nsec); + return (current_ts*1000 + current_nsec/1000) - (ts*1000 + nsec/1000); +} + +static _osal_inline_ INT32 stp_dbg_soc_paged_dump(INT32 dump_sink) +{ + INT32 ret = 0; + UINT32 counter = 0; + UINT32 dump_num = 0; + UINT32 packet_num = STP_PAGED_DUMP_TIME_LIMIT/100; + UINT32 page_counter = 0; + ENUM_CHIP_DUMP_STATE chip_state; + UINT32 dump_phy_addr = 0; + PUINT8 dump_vir_addr = NULL; + INT32 dump_len = 0; + P_CONSYS_EMI_ADDR_INFO p_ecsi; + UINT64 start_ts = 0; + ULONG start_nsec = 0; + UINT64 elapsed_time = 0; + INT32 abort = 0; +#if WMT_DBG_SUPPORT + static DEFINE_RATELIMIT_STATE(_rs, 10 * HZ, 1); +#endif + + g_paged_dump_len = 0; + p_ecsi = wmt_plat_get_emi_phy_add(); + osal_assert(p_ecsi); + if (p_ecsi == NULL) + return -1; + + issue_type = STP_FW_ASSERT_ISSUE; + if (chip_reset_only) { + STP_DBG_PR_WARN("is chip reset only\n"); + ret = -3; + return ret; + } + + if (dump_sink == 0) + return 0; + + /* handshake error handle: notify FW assert in abnormal case */ + if (p_ecsi->p_ecso->emi_apmem_ctrl_state == 0x0) { + mtk_wcn_force_trigger_assert_debug_pin(); + osal_sleep_ms(100); + } + + /*packet number depend on dump_num get from register:0xf0080044 ,support jade*/ + dump_num = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_page_dump_num); + if (dump_num != 0) { + packet_num = dump_num; + STP_DBG_PR_INFO("get consys dump num packet_num(%d)\n", packet_num); + } else { + dump_num = CORE_DUMP_NUM; + STP_DBG_PR_ERR("can not get consys dump num and default num is %d\n", CORE_DUMP_NUM); + } + + stp_dbg_dump_num(dump_num); + stp_dbg_start_coredump_timer(); + wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); + page_counter = 0; + if (mtk_wcn_stp_get_wmt_trg_assert() == 0) + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT); + + while (1) { + /* assert flag 2 means mcu is ready to start coredump */ + if (wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_assert_flag) == 2) { + STP_DBG_PR_INFO("coredump handshake start\n"); + break; + } else if (stp_dbg_get_coredump_timer_state() == CORE_DUMP_TIMEOUT) + goto paged_dump_end; + osal_sleep_ms(1); + } + + do { + dump_phy_addr = 0; + dump_vir_addr = NULL; + dump_len = 0; + + counter++; + osal_get_local_time(&start_ts, &start_nsec); + while (1) { + elapsed_time = stp_dbg_soc_elapsed_time(start_ts, start_nsec); + chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); + if (chip_state == STP_CHIP_DUMP_PUT_DONE) { + STP_DBG_PR_DBG("chip put done\n"); + break; + } + STP_DBG_PR_DBG("waiting chip put done, chip_state: %d\n", chip_state); +#if WMT_DBG_SUPPORT + if (chip_state == 0 && __ratelimit(&_rs)) + stp_dbg_poll_cpupcr(5, 1, 1); +#endif + + if (elapsed_time > EMI_SYNC_TIMEOUT) { +#if !WMT_DBG_SUPPORT + STP_DBG_PR_ERR("Wait Timeout: %llu > %d\n", elapsed_time, EMI_SYNC_TIMEOUT); + /* Since customer's user/userdebug load get coredump via netlink(dump_sink==2). */ + /* For UX, if get coredump timeout, skip it and do chip reset ASAP. */ + if (dump_sink == 2) + abort = 1; +#endif + goto paged_dump_end; + } + osal_sleep_ms(1); + } + + dump_phy_addr = wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_addr); + + if (!dump_phy_addr) { + STP_DBG_PR_ERR("get paged dump phy address fail\n"); + ret = -1; + break; + } + + dump_vir_addr = wmt_plat_get_emi_virt_add(dump_phy_addr - p_ecsi->emi_phy_addr); + if (!dump_vir_addr) { + STP_DBG_PR_ERR("get paged dump phy address fail\n"); + ret = -2; + break; + } + dump_len = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_len); + STP_DBG_PR_DBG("dump_phy_ddr(%08x),dump_vir_add(0x%p),dump_len(%d)\n", + dump_phy_addr, dump_vir_addr, dump_len); + + /* dump_len should not be negative */ + if (dump_len < 0) + dump_len = 0; + + /*move dump info according to dump_addr & dump_len */ + osal_memcpy_fromio(&g_paged_dump_buffer[0], dump_vir_addr, dump_len); + + if (dump_len <= 32 * 1024) { + STP_DBG_PR_DBG("coredump mode: %d!\n", dump_sink); + switch (dump_sink) { + case 1: + ret = stp_dbg_aee_send(&g_paged_dump_buffer[0], dump_len, 0); + if (ret == 0) + STP_DBG_PR_DBG("aee send ok!\n"); + else if (ret == 1) + STP_DBG_PR_DBG("aee send fisish!\n"); + else if (ret == -1) { + STP_DBG_PR_ERR("aee send timeout!\n"); + abort = 1; + goto paged_dump_end; + } else + STP_DBG_PR_ERR("aee send error!\n"); + break; + case 2: + ret = stp_dbg_soc_put_emi_dump_to_nl(&g_paged_dump_buffer[0], dump_len); + if (ret == 0) + STP_DBG_PR_DBG("dump send ok!\n"); + else if (ret == 1) { + STP_DBG_PR_ERR("dump send timeout!\n"); + abort = 1; + goto paged_dump_end; + } else + STP_DBG_PR_ERR("dump send error!\n"); + break; + default: + STP_DBG_PR_ERR("unknown sink %d\n", dump_sink); + return -1; + } + } else + STP_DBG_PR_ERR("dump len is over than 32K(%d)\n", dump_len); + + g_paged_dump_len += dump_len; + wmt_plat_update_host_sync_num(); + wmt_plat_set_host_dump_state(STP_HOST_DUMP_GET_DONE); + + STP_DBG_PR_DBG("host sync num(%d),chip sync num(%d)\n", + wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_host_sync_num), + wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_num)); + page_counter++; + STP_DBG_PR_DBG("++ paged dump counter(%d) ++\n", page_counter); + /* dump 1st 512 bytes data to kernel log for fw requirement */ + if (page_counter == 1) + stp_dbg_dump_log(&g_paged_dump_buffer[0], dump_len < 512 ? dump_len : 512); + + osal_get_local_time(&start_ts, &start_nsec); + while (1) { + elapsed_time = stp_dbg_soc_elapsed_time(start_ts, start_nsec); + chip_state = (ENUM_CHIP_DUMP_STATE)wmt_plat_get_dump_info( + p_ecsi->p_ecso->emi_apmem_ctrl_chip_sync_state); + if (chip_state == STP_CHIP_DUMP_END) { + STP_DBG_PR_DBG("chip put end\n"); + break; + } + STP_DBG_PR_DBG("waiting chip put end, chip_state: %d\n", chip_state); + if (elapsed_time > EMI_SYNC_TIMEOUT) { +#if !WMT_DBG_SUPPORT + STP_DBG_PR_ERR("Wait Timeout: %llu > %d\n", elapsed_time, EMI_SYNC_TIMEOUT); + /* Since customer's user/userdebug load get coredump via netlink(dump_sink==2). */ + /* For UX, if wait sync state timeout, skip it and do chip reset ASAP. */ + if (dump_sink == 2) + abort = 1; +#endif + goto paged_dump_end; + } + osal_sleep_ms(1); + } + +paged_dump_end: + wmt_plat_set_host_dump_state(STP_HOST_DUMP_NOT_START); + STP_DBG_PR_INFO("++ counter(%d) packet_num(%d) page_counter(%d) g_paged_dump_len(%d) fw_state(%d)++\n", + counter, packet_num, page_counter, g_paged_dump_len, + wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_state)); + if (wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_paded_dump_end) || + (wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_state) == 0x8)) { + if (stp_dbg_get_coredump_timer_state() == CORE_DUMP_DOING) { + STP_DBG_PR_INFO("paged dump end by emi flag\n"); + if (dump_sink == 1) + stp_dbg_aee_send(FAKECOREDUMPEND, osal_sizeof(FAKECOREDUMPEND), 0); + else if (dump_sink == 2) + stp_dbg_nl_send_data(FAKECOREDUMPEND, osal_sizeof(FAKECOREDUMPEND)); + } else + STP_DBG_PR_INFO("paged dump end\n"); + ret = 0; + break; + } else if (abort || stp_dbg_get_coredump_timer_state() == CORE_DUMP_TIMEOUT) { + STP_DBG_PR_ERR("paged dump fail, generate fake coredump message\n"); + stp_dbg_set_coredump_timer_state(CORE_DUMP_DOING); + if (dump_sink == 1) + stp_dbg_aee_send(FAKECOREDUMPEND, osal_sizeof(FAKECOREDUMPEND), 0); + else if (dump_sink == 2) + stp_dbg_nl_send_data(FAKECOREDUMPEND, osal_sizeof(FAKECOREDUMPEND)); + stp_dbg_set_coredump_timer_state(CORE_DUMP_TIMEOUT); + stp_dbg_poll_cpupcr(5, 5, 0); + stp_dbg_poll_dmaregs(5, 1); + ret = -1; + break; + } + } while (1); + + return ret; +} + +static _osal_inline_ INT32 stp_dbg_soc_paged_trace(VOID) +{ + INT32 ret = 0; + UINT32 ctrl_val = 0; + UINT32 loop_cnt1 = 0; + UINT32 buffer_start = 0; + UINT32 buffer_idx = 0; + PUINT8 dump_vir_addr = NULL; + P_CONSYS_EMI_ADDR_INFO p_ecsi; + INT32 dump_len = 0; + + p_ecsi = wmt_plat_get_emi_phy_add(); + if (p_ecsi == NULL) { + STP_DBG_PR_ERR("get EMI info failed.\n"); + return -1; + } + + do { + ctrl_val = 0; + loop_cnt1 = 0; + buffer_start = 0; + buffer_idx = 0; + dump_vir_addr = NULL; + + while (loop_cnt1 < 10) { + ctrl_val = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_state); + if (ctrl_val == 0x8) + break; + osal_sleep_ms(10); + loop_cnt1++; + } + if (loop_cnt1 >= 10) { + STP_DBG_PR_ERR("polling CTRL STATE fail\n"); + ret = -1; + break; + } + + buffer_start = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_print_buff_start); + buffer_idx = wmt_plat_get_dump_info(p_ecsi->p_ecso->emi_apmem_ctrl_chip_print_buff_idx); + g_paged_trace_len = buffer_idx; + STP_DBG_PR_INFO("paged trace buffer addr(%08x),buffer_len(%d)\n", buffer_start, + buffer_idx); + dump_vir_addr = wmt_plat_get_emi_virt_add(buffer_start - p_ecsi->emi_phy_addr); + if (!dump_vir_addr) { + STP_DBG_PR_ERR("get vir dump address fail\n"); + ret = -2; + break; + } + osal_memcpy_fromio(&g_paged_trace_buffer[0], dump_vir_addr, + buffer_idx < STP_DBG_PAGED_TRACE_SIZE ? buffer_idx : STP_DBG_PAGED_TRACE_SIZE); + /*moving paged trace according to buffer_start & buffer_len */ + + dump_len = + buffer_idx < STP_DBG_PAGED_TRACE_SIZE ? buffer_idx : STP_DBG_PAGED_TRACE_SIZE; + pr_info("-- paged trace ascii output --"); + stp_dbg_dump_log(&g_paged_trace_buffer[0], dump_len); + ret = 0; + } while (0); + + return ret; +} + +INT32 stp_dbg_soc_core_dump(INT32 dump_sink) +{ + INT32 ret = 0; + + if (dump_sink == 0 || chip_reset_only == 1) { + if (chip_reset_only) { + STP_DBG_PR_INFO("Chip reset only\n"); + chip_reset_only = 0; + } + mtk_wcn_stp_ctx_restore(); + } else if (dump_sink == 1 || dump_sink == 2) { + stp_dbg_soc_paged_dump(dump_sink); + ret = stp_dbg_soc_paged_trace(); + if (ret) + STP_DBG_PR_ERR("stp_dbg_soc_paged_trace fail: %d!\n", ret); + if (stp_dbg_start_emi_dump() < 0) + mtk_wcn_stp_ctx_restore(); + } + + return ret; +} + +PUINT8 stp_dbg_soc_id_to_task(UINT32 id) +{ + P_WMT_PATCH_INFO p_patch_info; + PUINT8 patch_name; + UINT32 temp_id; + + if (id >= STP_DBG_TASK_ID_MAX) { + STP_DBG_PR_ERR("task id(%d) overflow(%d)\n", id, STP_DBG_TASK_ID_MAX); + return NULL; + } + + p_patch_info = wmt_lib_get_patch_info(); + patch_name = p_patch_info->patchName; + + if (patch_name == NULL) { + STP_DBG_PR_ERR("patch_name is null\n"); + return NULL; + } + + if (osal_strncmp(patch_name, ROM_V2_PATCH, strlen(ROM_V2_PATCH)) == 0) { + temp_id = soc_gen_two_task_id_adapter[id]; + STP_DBG_PR_INFO("id = %d, gen two task_id = %d\n", id, temp_id); + } else if (osal_strncmp(patch_name, ROM_V3_PATCH, strlen(ROM_V3_PATCH)) == 0) { + temp_id = soc_gen_three_task_id_adapter[id]; + STP_DBG_PR_INFO("id = %d, gen three task_id = %d\n", id, temp_id); + } else if (osal_strncmp(patch_name, ROM_V4_PATCH, strlen(ROM_V4_PATCH)) == 0) { + temp_id = soc_gen_three_task_id_adapter[id]; + STP_DBG_PR_INFO("id = %d, gen three (ROMv4) task_id = %d\n", id, temp_id); + } else { + temp_id = id; + STP_DBG_PR_INFO("id = %d, CONNAC project task_id = %d\n", id, temp_id); + } + + return soc_task_str[temp_id]; +} + +UINT32 stp_dbg_soc_read_debug_crs(ENUM_CONNSYS_DEBUG_CR cr) +{ +#define CONSYS_REG_READ(addr) (*((volatile UINT32 *)(addr))) +#ifdef CONFIG_OF /*use DT */ + P_CONSYS_EMI_ADDR_INFO emi_phy_addr; + UINT32 chip_id = 0; + + chip_id = wmt_plat_get_soc_chipid(); + emi_phy_addr = mtk_wcn_consys_soc_get_emi_phy_add(); + + if (cr == CONNSYS_EMI_REMAP) { + if (emi_phy_addr != NULL && emi_phy_addr->emi_remap_offset) + return CONSYS_REG_READ(conn_reg.topckgen_base + + emi_phy_addr->emi_remap_offset); + else + STP_DBG_PR_INFO("EMI remap has no value\n"); + } + + if (chip_id == 0x6765 || chip_id == 0x3967 || chip_id == 0x6761 + || chip_id == 0x6779 || chip_id == 0x6768 || chip_id == 0x6785 + || chip_id == 0x8168) + return 0; + + if (conn_reg.mcu_base) { + switch (cr) { + case CONNSYS_CPU_CLK: + return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CPU_CLK_STATUS_OFFSET); + case CONNSYS_BUS_CLK: + return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_BUS_CLK_STATUS_OFFSET); + case CONNSYS_DEBUG_CR1: + return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DBG_CR1_OFFSET); + case CONNSYS_DEBUG_CR2: + return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DBG_CR2_OFFSET); + default: + return 0; + } + } +#endif + return -1; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_sdio.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_sdio.c new file mode 100644 index 00000000000000..a37decb60efbdd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_sdio.c @@ -0,0 +1,3589 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file "stp_sdio.c" + * \brief + * + * detailed description +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +#define STP_SDIO_TXPERFDBG 1 /* depends on STP_SDIO_DBG_SUPPORT */ +#define STP_SDIO_OWNBACKDBG 1 /* depends on STP_SDIO_DBG_SUPPORT */ +#define STP_SDIO_NEW_IRQ_HANDLER 1 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <linux/mm.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/completion.h> +#include <linux/time.h> + +#include "osal.h" +#include "stp_exp.h" +#include "hif_sdio.h" +#include "stp_sdio.h" +#include "stp_dbg.h" +#include "wmt_lib.h" +#include "wmt_exp.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[STP SDIO]" + +#define STPSDIO_LOG_LOUD 5 +#define STPSDIO_LOG_DBG 4 +#define STPSDIO_LOG_HINT 3 +#define STPSDIO_LOG_INFO 2 +#define STPSDIO_LOG_WARN 1 +#define STPSDIO_LOG_ERR 0 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_RXDBG +#define STP_SDIO_RXDBG_COUNT (0x10UL) +#define STP_SDIO_RXDBG_COUNT_MASK (STP_SDIO_RXDBG_COUNT - 1) +struct stp_sdio_rxdbg { + UINT32 ts; + UINT32 bus_rxlen; + UINT32 chisr_rxlen; + UINT8 rx_pkt_buf[STP_SDIO_RX_BUF_SIZE]; +}; +#endif + +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG +#define STP_SDIO_TXDBG_COUNT (0x10UL) +#define STP_SDIO_TXDBG_COUNT_MASK (STP_SDIO_TXDBG_COUNT - 1) +struct stp_sdio_txdbg { + UINT32 ts; + UINT32 bus_txlen; + UINT64 l_sec; + ULONG l_nsec; + UINT32 four_byte_align_len; + UINT8 tx_pkt_buf[STP_SDIO_TX_ENTRY_SIZE]; +}; +#define STP_SDIO_TXDBG_MAX_SIZE (0x20) +#endif +OSAL_SLEEPABLE_LOCK fake_coredump_lock; +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 stp_sdio_func0_reg_rw(INT32 direction, UINT32 offset, UINT32 value); +static INT32 stp_sdio_func_reg_rw(INT32 direction, UINT32 offset, UINT32 value); + +static INT32 stp_sdio_irq(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx); +static INT32 stp_sdio_probe(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx, + const MTK_WCN_HIF_SDIO_FUNCINFO *sdio_func_infop); +static INT32 stp_sdio_remove(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx); + +static VOID stp_sdio_rx_wkr(struct work_struct *work); +static VOID stp_sdio_tx_wkr(struct work_struct *work); +#if STP_SDIO_OWN_THREAD +static INT32 stp_sdio_wait_for_msg(PVOID pvData); +static VOID stp_sdio_tx_rx_handling(PVOID pData); +#endif +static _osal_inline_ INT32 stp_sdio_host_info_deinit(PPUINT8 ppTxBuf, PPUINT8 ppRxBuf); +static _osal_inline_ INT32 stp_sdio_host_info_init(PPUINT8 ppTxBuf, PPUINT8 ppRxBuf); +static _osal_inline_ INT32 stp_sdio_host_info_op(INT32 opId); +static _osal_inline_ SDIO_PS_OP stp_sdio_get_own_state(VOID); +static _osal_inline_ INT32 stp_sdio_do_own_set(MTK_WCN_STP_SDIO_HIF_INFO *p_info); +static _osal_inline_ INT32 stp_sdio_do_own_clr(INT32 wait); +static _osal_inline_ VOID stp_sdio_check_tx_sanity(const MTK_WCN_STP_SDIO_HIF_INFO *p_info, const UINT32 id); +static _osal_inline_ VOID stp_sdio_tx_wkr_comp(MTK_WCN_STP_SDIO_HIF_INFO * const p_info); +static _osal_inline_ INT32 stp_sdio_ownback_poll(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx, UINT32 retry, + UINT32 delay_us); +static _osal_inline_ VOID stp_sdio_txperf_dump(VOID); +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/* Supported SDIO device table */ +static const MTK_WCN_HIF_SDIO_FUNCINFO mtk_stp_sdio_id_tbl[] = { + /* MT6618 *//* Not an SDIO standard class device */ + {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x018B, 1, STP_SDIO_BLK_SIZE)}, + {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x018C, 1, STP_SDIO_BLK_SIZE)}, /* 2-function */ + + /* MT6619 *//* Not an SDIO standard class device */ + {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x6619, 1, STP_SDIO_BLK_SIZE)}, + + /* MT6620 *//* Not an SDIO standard class device */ + {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x020B, 1, STP_SDIO_BLK_SIZE)}, + {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x020C, 1, STP_SDIO_BLK_SIZE)}, /* 2-function */ + + /* MT6628 *//* Not an SDIO standard class device */ + {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x6628, 2, STP_SDIO_BLK_SIZE)}, /* 2-function */ + + /* MT6630 *//* Not an SDIO standard class device */ + {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x6630, 2, STP_SDIO_BLK_SIZE)}, /* 2-function */ + + /* MT6632 *//* Not an SDIO standard class device */ + {MTK_WCN_HIF_SDIO_FUNC(0x037A, 0x6632, 2, STP_SDIO_BLK_SIZE)}, /* 2-function */ + { /* end: all zeroes */ }, +}; + +wait_queue_head_t g_ownback_done; +INT32 is_wait_ownback; +/* static void (*cmb_bgf_eirq_cb)(void) = NULL; */ + +/* STP SDIO client information for hif sdio driver registration */ +const MTK_WCN_HIF_SDIO_CLTINFO g_stp_sdio_cltinfo = { + .func_tbl = mtk_stp_sdio_id_tbl, + .func_tbl_size = (sizeof(mtk_stp_sdio_id_tbl) / sizeof(MTK_WCN_HIF_SDIO_FUNCINFO) - 1), + .hif_clt_irq = stp_sdio_irq, + .hif_clt_probe = stp_sdio_probe, + .hif_clt_remove = stp_sdio_remove, +}; + +/* STP SDIO host array for multiple hosts maintenance */ +MTK_WCN_STP_SDIO_HIF_INFO g_stp_sdio_host_info; /*[STP_SDIO_HOST_COUNT]; */ +/* STP SDIO host information pointer (for stp if_tx() function) */ +MTK_WCN_STP_SDIO_HIF_INFO *const gp_info = &g_stp_sdio_host_info; + +/* STP-SDIO probe count (not support multiple probe and hosts) */ +UINT32 g_stp_sdio_host_count; + +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_RXDBG +#define STP_SDIO_RXDBG_PROCNAME "driver/stp_sdio_rxdbg" +static struct proc_dir_entry *gStpSdioRxDbgEntry; +static INT32 stp_sdio_rxdbg_cnt; +static struct stp_sdio_rxdbg stp_sdio_rxdbg_buffer[STP_SDIO_RXDBG_COUNT]; +static struct timespec64 old = {0}; +#define TX_NO_ACK_TIMEOUT_ASSERT 5 /* tx no ack timeout assert, unit:second*/ + +static ssize_t stp_sdio_rxdbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); +static ssize_t stp_sdio_rxdbg_write(struct file *filp, const char __user *buf, size_t count, + loff_t *f_pos); +static const struct proc_ops stp_sdio_rxdbg_fops = { + .proc_read = stp_sdio_rxdbg_read, + .proc_write = stp_sdio_rxdbg_write, +}; + +#endif + +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_OWNBACKDBG +#define STP_SDIO_OWNDBG_PROCNAME "driver/stp_sdio_own" +static struct proc_dir_entry *gStpSdioOwnEntry; +static ssize_t stp_sdio_own_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); +static ssize_t stp_sdio_own_write(struct file *filp, const char __user *buf, size_t count, + loff_t *f_pos); +static const struct proc_ops stp_sdio_own_fops = { + .proc_read = stp_sdio_own_read, + .proc_write = stp_sdio_own_write, +}; + +#endif + +#if STP_SDIO_DBG_SUPPORT && (STP_SDIO_TXDBG || STP_SDIO_TXPERFDBG) +#define STP_SDIO_TXDBG_PROCNAME "driver/stp_sdio_txdbg" +static struct proc_dir_entry *gStpSdioTxDbgEntry; + +static ssize_t stp_sdio_txdbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); +static ssize_t stp_sdio_txdbg_write(struct file *filp, const char __user *buf, size_t count, + loff_t *f_pos); +static const struct proc_ops stp_sdio_txdbg_fops = { + .proc_read = stp_sdio_txdbg_read, + .proc_write = stp_sdio_txdbg_write, +}; + +#if STP_SDIO_TXDBG +static INT32 stp_sdio_txdbg_cnt; +static struct stp_sdio_txdbg stp_sdio_txdbg_buffer[STP_SDIO_TXDBG_COUNT]; +#endif + +#if STP_SDIO_TXPERFDBG +/* a record for tx worker loop counter */ +static UINT32 stp_sdio_txperf_worker_cnt; + +/* a record for left fifo size in hw when tx wait */ +static UINT32 stp_sdio_txperf_fifo_left; +/* a record for data length when tx wait */ +static UINT32 stp_sdio_txperf_to_send; +/* a record for tx wait fifo limit counter */ +static UINT32 stp_sdio_txperf_fifo_lmt_cnt; + +/* a record for left txed pkt number in tx worker */ +static UINT32 stp_sdio_txperf_txed_pkt_num; +/* a record for tx wait pkt_num limit counter */ +static UINT32 stp_sdio_txperf_pkt_num_lmt_cnt; +#endif +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("MediaTek Inc WCN_SE_CS3"); +MODULE_DESCRIPTION("Read-Copy Update tracing for hierarchical implementation"); + +INT32 gStpSdioDbgLvl = STPSDIO_LOG_INFO; +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define STPSDIO_PR_LOUD(fmt, arg...) \ +do { \ + if (gStpSdioDbgLvl >= STPSDIO_LOG_LOUD) \ + pr_info(DFT_TAG "[L]%s:" fmt, __func__, ##arg); \ +} while (0) + +#define STPSDIO_PR_DBG(fmt, arg...) \ +do { \ + if (gStpSdioDbgLvl >= STPSDIO_LOG_DBG) \ + pr_info(DFT_TAG "[D]%s:" fmt, __func__, ##arg); \ +} while (0) + +#define STPSDIO_PR_HINT(fmt, arg...) \ +do { \ + if (gStpSdioDbgLvl >= STPSDIO_LOG_HINT) \ + pr_info(DFT_TAG "[I]%s:" fmt, __func__, ##arg); \ +} while (0) + +#define STPSDIO_PR_INFO(fmt, arg...) \ +do { \ + if (gStpSdioDbgLvl >= STPSDIO_LOG_INFO) \ + pr_info(DFT_TAG "[I]%s:" fmt, __func__, ##arg); \ +} while (0) + +#define STPSDIO_PR_WARN(fmt, arg...) \ +do { \ + if (gStpSdioDbgLvl >= STPSDIO_LOG_WARN) \ + pr_warn(DFT_TAG "[W]%s:" fmt, __func__, ##arg); \ +} while (0) + +#define STPSDIO_PR_ERR(fmt, arg...) \ +do { \ + if (gStpSdioDbgLvl >= STPSDIO_LOG_ERR) \ + pr_err(DFT_TAG "[E]%s(%d):" fmt, __func__, __LINE__, ##arg); \ +} while (0) + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +INT32 stp_sdio_deep_sleep_flag_set(MTK_WCN_BOOL flag) +{ + return mtk_wcn_hif_sdio_deep_sleep_flag_set(flag); +} +#endif + +VOID stp_sdio_retry_flag_ctrl(INT32 flag) +{ + gp_info->retry_enable_flag = flag == 0 ? 0 : 1; +} + +INT32 stp_sdio_retry_flag_get(VOID) +{ + return gp_info->retry_enable_flag; +} + +static _osal_inline_ INT32 stp_sdio_host_info_op(INT32 opId) +{ + INT32 iRet = 0; +#if KMALLOC_UPDATE + static PUINT8 p_tx_buffer; + static PUINT8 p_rx_buffer; + + if (p_tx_buffer == NULL) { + p_tx_buffer = kmalloc(STP_SDIO_TX_BUF_CNT * STP_SDIO_TX_ENTRY_SIZE, GFP_ATOMIC); + if (p_tx_buffer == NULL) { + STPSDIO_PR_ERR + ("memory allocate for g_stp_sdio_host_info.pkt_buf.tx_buf fail!\n"); + iRet = -1; + } else { + STPSDIO_PR_DBG + ("memory allocate for g_stp_sdio_host_info.pkt_buf.tx_buf succeed!\n"); + iRet = 0; + } + } else { + STPSDIO_PR_DBG + ("memory already allocated for g_stp_sdio_host_info.pkt_buf.tx_buf!\n"); + iRet = 0; + } + if (p_rx_buffer == NULL) { + p_rx_buffer = kmalloc(STP_SDIO_RX_BUF_SIZE, GFP_ATOMIC); + if (p_rx_buffer == NULL) { + STPSDIO_PR_ERR + ("memory allocate for g_stp_sdio_host_info.pkt_buf.rx_buf fail!\n"); + iRet = -1; + } else { + STPSDIO_PR_DBG + ("memory allocate for g_stp_sdio_host_info.pkt_buf.rx_buf succeed!\n"); + iRet = 0; + } + } else { + STPSDIO_PR_DBG + ("memory already allocated for g_stp_sdio_host_info.pkt_buf.rx_buf!\n"); + iRet = 0; + } +#endif /* KMALLOC_UPDATE */ + + if (iRet == 0 && opId == 0) + iRet = stp_sdio_host_info_deinit(&p_tx_buffer, &p_rx_buffer); + else if (iRet == 0) + iRet = stp_sdio_host_info_init(&p_tx_buffer, &p_rx_buffer); + else + STPSDIO_PR_ERR("iRet (%d)!\n", iRet); + + return iRet; +} + +static _osal_inline_ INT32 stp_sdio_host_info_init(PPUINT8 ppTxBuf, PPUINT8 ppRxBuf) +{ + /* Init host count */ + memset(&g_stp_sdio_host_info, 0, sizeof(g_stp_sdio_host_info)); + +#if KMALLOC_UPDATE + g_stp_sdio_host_info.pkt_buf.tx_buf = *ppTxBuf; + g_stp_sdio_host_info.pkt_buf.rx_buf = *ppRxBuf; +#endif + + return 0; +} + +static _osal_inline_ INT32 stp_sdio_host_info_deinit(PPUINT8 ppTxBuf, PPUINT8 ppRxBuf) +{ +#if KMALLOC_UPDATE + if (*ppTxBuf != NULL) { + kfree(*ppTxBuf); + *ppTxBuf = NULL; + } + if (*ppRxBuf != NULL) { + kfree(*ppRxBuf); + *ppRxBuf = NULL; + } +#endif + + return 0; +} + +INT32 stp_sdio_issue_fake_coredump(UINT8 *str) +{ +#define MAX_STRING_LENGTH 140 + UINT8 AssertStr[4 + MAX_STRING_LENGTH + 1 + 2] = { 0 }; + UINT32 length = strlen(str) >= MAX_STRING_LENGTH ? MAX_STRING_LENGTH : strlen(str); + /*pack str into STP SDIO packet format */ + osal_lock_sleepable_lock(&fake_coredump_lock); + /*STP header */ + AssertStr[0] = 0x80; + AssertStr[1] = 0x50; + AssertStr[2] = (length + 1) & 0xff; + AssertStr[3] = 0x0; + /*STP content */ + memcpy(&AssertStr[4], str, length); + /*string end character */ + AssertStr[4 + length] = '\n'; + /*STP CRC */ + AssertStr[4 + length + 1] = 0x0; + AssertStr[4 + length + 2] = 0x0; + /*send to STP layer coredump content */ + mtk_wcn_stp_parser_data(&AssertStr[0], 4 + length + 1 + 2); + + /*send coredump end content */ + length = strlen("coredump end"); + AssertStr[0] = 0x80; + AssertStr[1] = 0x50; + AssertStr[2] = (length + 2) & 0xff; + AssertStr[3] = 0x0; + memcpy(&AssertStr[4], "coredump end", length); + /*string end character */ + AssertStr[4 + length] = '\r'; + AssertStr[4 + length + 1] = '\n'; + /*STP CRC */ + AssertStr[4 + length + 2] = 0x0; + AssertStr[4 + length + 3] = 0x0; + mtk_wcn_stp_parser_data(&AssertStr[0], 4 + length + 2 + 2); + osal_unlock_sleepable_lock(&fake_coredump_lock); + + STPSDIO_PR_ERR("trigger fake coredump with str:[%s] finished\n", str); + + return 0; +} + +/*! + * \brief + * + * \details + * + * \retval 0 success + * \retval !=0 fail + */ +static _osal_inline_ SDIO_PS_OP stp_sdio_get_own_state(VOID) +{ + SDIO_PS_OP ret = OWN_SET; + INT32 i_ret = 0; + UINT32 chlcpr_value = 0x0; + MTK_WCN_HIF_SDIO_CLTCTX clt_ctx; + + clt_ctx = gp_info->sdio_cltctx; + i_ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, &chlcpr_value, + 0); + if (i_ret) { + ret = OWN_SET; + STPSDIO_PR_ERR("read CHLPCR fail(%d), return\n", ret); + return ret; + } + if ((chlcpr_value & C_FW_COM_DRV_OWN) == C_FW_COM_DRV_OWN) + ret = OWN_CLR; + else + ret = OWN_SET; + + return ret; +} + +static _osal_inline_ INT32 stp_sdio_do_own_set(MTK_WCN_STP_SDIO_HIF_INFO *p_info) +{ + UINT32 value = 0; + UINT32 iRet = 0; + + /* [COHEC_00006052] SW work-around solution: + * using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR + */ +#if COHEC_00006052 + value = (C_FW_OWN_REQ_SET >> 8); + iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx, + (UINT32)(CHLPCR + 0x01), &value, 0); +#else + value = C_FW_OWN_REQ_SET; + iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx, CHLPCR, &value, + 0); +#endif /* COHEC_00006052 */ + if (iRet) { + STPSDIO_PR_ERR("write CHLPCR, set firmware own! (sleeping) fail\n"); + } else { + iRet = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx, CHLPCR, + &value, 0); + if (iRet) + STPSDIO_PR_ERR("get firmware own! (sleeping) fail iRet:%d\n", iRet); + else { + if (!(value & C_FW_COM_DRV_OWN)) { + STPSDIO_PR_DBG("set firmware own! (sleeping) ok\n"); + osal_ftrace_print("set F own okay, sleep_flag(%d), wakeup_flag(%d), awake_falg(%d)", + p_info->sleep_flag, p_info->wakeup_flag, p_info->awake_flag); + p_info->awake_flag = 0; + p_info->sleep_flag = 0; + osal_raise_signal(&p_info->isr_check_complete); + osal_ftrace_print("set F own okay and raise signal done"); + } else { + STPSDIO_PR_WARN("set firmware own fail!, set CLR BACK\n"); + osal_ftrace_print("set F own fail, set CLR BACK\n"); + /* if set firmware own not successful(possibly pending interrupts), + * indicate an own clear event + */ + /* [COHEC_00006052] SW work-around solution: + * using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR + */ +#if COHEC_00006052 + value = (C_FW_OWN_REQ_CLR >> 8); + iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, + p_info->sdio_cltctx, (UINT32)(CHLPCR + 0x01), &value, 0); +#else + value = C_FW_OWN_REQ_CLR; + iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, + p_info->sdio_cltctx, CHLPCR, &value, 0); +#endif /* COHEC_00006052 */ + } + } + } + + return 0; +} + +/*! + * \brief + * + * \details + * + * \retval 0 success + * \retval !=0 fail + */ +static _osal_inline_ INT32 stp_sdio_do_own_clr(INT32 wait) +{ +#define CLR_OWN_RETRY 50 + INT32 ret = -1; + UINT32 time_out; + INT32 retry; + UINT32 chlcpr_value = 0x0; + UINT32 write_value = 0x0; + UINT32 delay_us = 500; + MTK_WCN_HIF_SDIO_CLTCTX clt_ctx; + + clt_ctx = gp_info->sdio_cltctx; + retry = 40; + + /* <1> request firmware-own back */ + STPSDIO_PR_DBG("Do FW-Own back!(Wakeup)\n"); + if (wait) { + /* TODO:[FixMe][George] why use both polling & interrupt methods here??? */ + init_waitqueue_head(&g_ownback_done); + + is_wait_ownback = 1; + } +/* need to wait for the ownback completion */ +/* [COHEC_00006052] SW work-around solution: + * using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR + */ + while (retry-- > 0) { +#if COHEC_00006052 + write_value = (C_FW_OWN_REQ_CLR>>8); + ret = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, clt_ctx, + (UINT32)(CHLPCR+0x1), &write_value, 0); +#else + write_value = C_FW_OWN_REQ_CLR; + ret = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, + &write_value, 0); +#endif /* COHEC_00006052 */ + if (ret) { + STPSDIO_PR_ERR("request firmware own back fail(%d)\n", ret); + osal_dbg_assert_aee("<HIF_SDIO> sdio_write ERROR", + "write CHLPCR by SDIO report error"); + if (retry == 0) + goto out; + } else + break; + } + retry = 1200;/*wait for 1200*500 = 600 000 us*/ + do { + ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, + &chlcpr_value, 0); + if (ret) { + /* 4 <1.1> get CHISR Rx error handling */ + STPSDIO_PR_ERR("get CHLPCR information rx error!(%d)\n", ret); + goto out; + } + + if ((chlcpr_value & C_FW_COM_DRV_OWN) == C_FW_COM_DRV_OWN) { + /* 4 <2> handle ownership back interrupt */ + STPSDIO_PR_DBG("firmware ownback is polled!(%d)\n", + CLR_OWN_RETRY - retry); + /*osal_usleep_range(2000, 2000);*/ + break; + } + STPSDIO_PR_DBG("firmware ownback is no polled, wait for (%d us) and retry\n", delay_us); + osal_usleep_range(delay_us, 2*delay_us); + if (0 == (retry - 1)%40) + STPSDIO_PR_ERR("own back failed in %d us, something might goes wrong\n", + 40*delay_us); + + if (0 == (retry - 1)%200) { +#if COHEC_00006052 + write_value = (C_FW_OWN_REQ_CLR>>8); + ret = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, clt_ctx, + (UINT32)(CHLPCR+0x1), &write_value, 0); +#else + write_value = C_FW_OWN_REQ_CLR; + ret = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, + &write_value, 0); +#endif /* COHEC_00006052 */ + if (ret) + STPSDIO_PR_ERR("request firmware own back fail(%d)\n", ret); + STPSDIO_PR_ERR("own back failed in %d us, write again\n", 200*delay_us); + stp_dbg_poll_cpupcr(5, 1, 1); + } + } while (retry-- > 0); + if (wait) { + /* <2> wait own_back bit is set. */ + time_out = wait_event_timeout(g_ownback_done, + is_wait_ownback == 0, (1000 / (1000 / HZ))); + + if (time_out != 0) { + STPSDIO_PR_INFO("Do FW-Own back!(Wakeup) succeed\n"); + ret = 0; + } else { + STPSDIO_PR_ERR("Do FW-Own back!(Wakeup) fail\n"); + ret = -1; + } + } else + ret = retry > 0 ? 0 : -1; + +out: + return ret; +} + +/*! + * \brief + * + * \details + * + * \param[IN] op code for SDIO PS and OWN control + * + * \retval 0 success + * \retval !=0 fail + */ +INT32 stp_sdio_own_ctrl(SDIO_PS_OP op) +{ + INT32 ret = -1; + P_OSAL_SIGNAL pOsalSignal = NULL; + + if (g_stp_sdio_host_count == 0) { + STPSDIO_PR_WARN("g_stp_sdio_host_count is 0, do nothing!\n"); + return 0; + } + pOsalSignal = &gp_info->isr_check_complete; + switch (op) { + case OWN_SET: + gp_info->wakeup_flag = 0; + gp_info->sleep_flag = 1; + osal_trigger_event(&gp_info->tx_rx_event); + STPSDIO_PR_LOUD("before op(%d)\n", op); + osal_ftrace_print("own set start, wakeup_flag(%d), sleep_flag(%d), wait signal", + gp_info->wakeup_flag, gp_info->sleep_flag); + ret = osal_wait_for_signal_timeout(pOsalSignal, NULL); + if (!ret) + STPSDIO_PR_ERR("OWN_SET fail, done(%d), sleep(%d), wakeup(%d)\n", + pOsalSignal->comp.done, gp_info->sleep_flag, gp_info->wakeup_flag); + STPSDIO_PR_LOUD("after op(%d)\n", op); + ret = 0; + break; + + case OWN_CLR: + /* ret = stp_sdio_do_own_clr(1); */ + gp_info->sleep_flag = 0; + gp_info->wakeup_flag = 1; + osal_trigger_event(&gp_info->tx_rx_event); + osal_ftrace_print("own clear start, wakeup_flag(%d), sleep_flag(%d), wait signal", + gp_info->wakeup_flag, gp_info->sleep_flag); + STPSDIO_PR_LOUD("before op(%d)\n", op); + ret = osal_wait_for_signal_timeout(pOsalSignal, NULL); + if (!ret) + STPSDIO_PR_ERR("OWN_CLER fail, done(%d), sleep(%d), wakeup(%d)\n", + pOsalSignal->comp.done, gp_info->sleep_flag, gp_info->wakeup_flag); + STPSDIO_PR_LOUD("after op(%d)\n", op); + ret = 0; + break; + case OWN_STATE: + /* ret = stp_sdio_get_own_state(); */ + STPSDIO_PR_INFO("omit op(%d)\n", op); + ret = 0; + break; + default: + STPSDIO_PR_WARN("omit op(%d)\n", op); + ret = -1; + break; + } + osal_ftrace_print("own control end, wakeup_flag(%d), sleep_flag(%d), signal done", + gp_info->wakeup_flag, gp_info->sleep_flag); + return ret; +} + +#if STP_SDIO_OWN_THREAD + +static INT32 stp_sdio_wait_for_msg(PVOID pvData) +{ + MTK_WCN_STP_SDIO_HIF_INFO *pInfo = (MTK_WCN_STP_SDIO_HIF_INFO *) pvData; +#if STP_SDIO_NEW_TXRING + STPSDIO_PR_LOUD + ("len(%u), wr_cnt(%u), rd_cnt(%u), irq_pending(%u), sleep(%u), wakeup(%u)\n", + pInfo->rx_pkt_len, atomic_read(&pInfo->pkt_buf.wr_cnt), atomic_read(&pInfo->pkt_buf.rd_cnt), + pInfo->irq_pending, pInfo->sleep_flag, pInfo->wakeup_flag); + osal_ftrace_print("len(%u), txwkr(%u), irq(%u), sleep(%u), wakeup(%u), tx_pkt_num(%u))\n", + pInfo->rx_pkt_len, pInfo->txwkr_flag, pInfo->irq_pending, pInfo->sleep_flag, pInfo->wakeup_flag, + pInfo->firmware_info.tx_packet_num); + return (pInfo->rx_pkt_len != 0) + || (pInfo->txwkr_flag != 0) + || (pInfo->irq_pending != 0) + || (pInfo->sleep_flag != 0) + || (pInfo->wakeup_flag != 0) + || (osal_thread_should_stop(&pInfo->tx_rx_thread)); +#else + STPSDIO_PR_LOUD + ("len(%u), rd_idx(%u), wr_idx(%u), irq_pending(%u), sleep(%u), wakeup(%u)\n", + pInfo->rx_pkt_len, atomic_read(&pInfo->pkt_buf.rd_idx), atomic_read(&pInfo->pkt_buf.wr_idx), + pInfo->irq_pending, pInfo->sleep_flag, pInfo->wakeup_flag); + osal_ftrace_print("len(%u), txwkr(%u), irq(%u), sleep(%u), wakeup(%u), tx_pkt_num(%u)\n", + pInfo->rx_pkt_len, pInfo->txwkr_flag, pInfo->irq_pending, pInfo->sleep_flag, pInfo->wakeup_flag, + pInfo->firmware_info.tx_packet_num); + return (pInfo->rx_pkt_len != 0) + || (pInfo->txwkr_flag != 0) + || (pInfo->irq_pending != 0) + || (pInfo->sleep_flag != 0) + || (pInfo->wakeup_flag != 0) + || (osal_thread_should_stop(&pInfo->tx_rx_thread)); +#endif /* STP_SDIO_NEW_TXRING */ +} + +static VOID stp_sdio_tx_rx_handling(PVOID pData) +{ + MTK_WCN_STP_SDIO_HIF_INFO *pInfo = (MTK_WCN_STP_SDIO_HIF_INFO *) pData; + UINT32 iRet = 0; + UINT32 chisr = 0; + UINT32 chlcpr_value = 0; + UINT32 write_value = 0; + UINT32 tx_comp = 0; + MTK_WCN_HIF_SDIO_CLTCTX clt_ctx; + UINT32 while_loop_counter = 0; + UINT32 own_fail_counter = 0; + UINT32 val = 0; + UINT32 delay_us = 10000; + UINT32 chisr_error_count = 3; + + STPSDIO_PR_INFO("stp_tx_rx_thread start running...\n"); + if (pInfo == NULL) { + STPSDIO_PR_WARN("sanity check fail, (pInfo == NULL)\n"); + return; + } + clt_ctx = pInfo->sdio_cltctx; + + while (!osal_thread_should_stop(&pInfo->tx_rx_thread)) { + while_loop_counter++; + osal_ftrace_print("loop_count:%d\n", while_loop_counter); + /* <0> get CHLPCR information */ + if (pInfo->awake_flag == 0) { + if (CLTCTX_CID(clt_ctx) == 0x6632) + stp_sdio_wake_up_ctrl(clt_ctx); + if (stp_sdio_do_own_clr(0) == 0) { + STPSDIO_PR_DBG("set OWN to driver side ok!\n"); + pInfo->awake_flag = 1; + osal_ftrace_print("set OWN D ok!, sleep_flag(%d), wakeup_flag(%d), awake_falg(%d)", + pInfo->sleep_flag, pInfo->wakeup_flag, pInfo->awake_flag); + own_fail_counter = 0; + } else { + if ((pInfo->sleep_flag != 0) || (pInfo->wakeup_flag != 0)) { + pInfo->wakeup_flag = 0; + pInfo->sleep_flag = 0; + STPSDIO_PR_WARN("clr fw own fail,signal for sleep/wakeup to return\n"); + osal_raise_signal(&pInfo->isr_check_complete); + } + if ((own_fail_counter % 50) == 0) { + STPSDIO_PR_ERR("set OWN to driver side error!\n"); + /*trigger whole chip reset by send fake coredump content */ + if (own_fail_counter == 0) + stp_sdio_issue_fake_coredump + ("ABT: STP-SDIO clear f/w own failed"); + } + own_fail_counter++; + } + } else { + STPSDIO_PR_DBG("OWN on driver side!\n"); + osal_ftrace_print("OWN D , sleep_flag(%d), wakeup_flag(%d), awake_falg(%d)", + pInfo->sleep_flag, pInfo->wakeup_flag, pInfo->awake_flag); + } + + if ((pInfo->wakeup_flag != 0) && (pInfo->awake_flag != 0)) { + while_loop_counter = 0; + STPSDIO_PR_DBG("clr firmware own! (wakeup) ok\n"); + pInfo->wakeup_flag = 0; + osal_raise_signal(&pInfo->isr_check_complete); + osal_ftrace_print("wakeup done\n"); + } + + if ((pInfo->irq_pending != 0) && (pInfo->awake_flag == 1)) { + while_loop_counter = 0; + + /* <1> get CHISR information */ + iRet = mtk_wcn_hif_sdio_readl(clt_ctx, CHISR, &chisr); + if (iRet) { + /* 4 <1.1> get CHISR Rx error handling */ + /* TODO: error handling! */ + STPSDIO_PR_ERR("get CHISR information rx error, ret:%d\n", iRet); + if (-5 == iRet) { + iRet = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_MAX_RETRY_NUM, + clt_ctx, CSR, &chisr, 0); + pInfo->irq_pending = 0; + } + } else { + pInfo->irq_pending = 0; + osal_ftrace_print("CHISR(0x%08x)\n", chisr); + } + + if (pInfo->dump_flag != 0) + STPSDIO_PR_ERR("CHISR(0x%08x)\n", chisr); + else + STPSDIO_PR_DBG("CHISR(0x%08x)\n", chisr); + + + if (chisr == 0x0) { + STPSDIO_PR_ERR("******CHISR == 0*****\n"); + while (chisr_error_count) { + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, + clt_ctx, CCIR, &val, 0); + STPSDIO_PR_ERR("******CCIR == 0x%x*****\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, + clt_ctx, CHLPCR, &val, 0); + STPSDIO_PR_ERR("******CHLPCR == 0x%x*****\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, + clt_ctx, CSDIOCSR, &val, 0); + STPSDIO_PR_ERR("******CSDIOCSR == 0x%x*****\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, + clt_ctx, CHCR, &val, 0); + STPSDIO_PR_ERR("******CHCR == 0x%x*****\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, + clt_ctx, CHISR, &chisr, 0); + STPSDIO_PR_ERR("******CHISR == 0x%x*****\n", chisr); + if (chisr) + break; + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, + clt_ctx, CHIER, &val, 0); + STPSDIO_PR_ERR("******CHIER == 0x%x*****\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, + clt_ctx, CTFSR, &val, 0); + STPSDIO_PR_ERR("******CTFSR == 0x%x*****\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, + clt_ctx, CRPLR, &val, 0); + STPSDIO_PR_ERR("******CRPLR == 0x%x*****\n", val); + chisr_error_count--; + osal_usleep_range(delay_us, 2 * delay_us); + } + } + + if (chisr & FW_OWN_BACK_INT) + STPSDIO_PR_HINT("FW_OWN_BACK_INT\n"); + + /* <4> handle Tx interrupt */ + if ((chisr & TX_EMPTY) || (chisr & TX_UNDER_THOLD) || (chisr & TX_RETRY)) { + while_loop_counter = 0; + STPSDIO_PR_DBG("Tx interrupt\n"); + /* get complete count */ + tx_comp = (chisr & TX_COMPLETE_COUNT) >> 4; + + tx_comp = + atomic_add_return(tx_comp, &pInfo->firmware_info.tx_comp_num); + if (tx_comp > STP_SDIO_TX_PKT_MAX_CNT) + STPSDIO_PR_ERR + ("Abnormal accumulated comp count(%d) chisr(0x%x)\n", + tx_comp, chisr); + if (chisr & TX_RETRY) + pInfo->tx_retry_flag = STP_SDIO_RETRY_INT; + } + if (pInfo->awake_flag == 1 && pInfo->tx_retry_flag != STP_SDIO_RETRY_CRC_ERROR) + stp_sdio_tx_wkr(&pInfo->tx_work); + + if (chisr & RX_DONE) { + /* STPSDIO_PR_INFO("RX_DONE_INT\n"); */ + if (pInfo->rx_pkt_len) + STPSDIO_PR_ERR("rx worker is not finished yet!\n"); + + /* get Rx packet length */ + pInfo->rx_pkt_len = (chisr & RX_PKT_LEN) >> 16; + STPSDIO_PR_HINT("rx_pkt_len(%d)\n", pInfo->rx_pkt_len); + /* sanity check */ + if ((pInfo->rx_pkt_len == 0) || + (pInfo->rx_pkt_len > STP_SDIO_RX_FIFO_SIZE)) { + STPSDIO_PR_ERR + ("abnormal rx_pkt_len(%d) in CHISR(0x%08x) skip rx_worker\n", + pInfo->rx_pkt_len, chisr); + pInfo->rx_pkt_len = 0; + } else { + /* Before host driver read all rx data, chip/fw will not send more + * data to host. No need to mask rx interrupt. schedule rx worker to + * get data back and handle it. + */ + if (pInfo->rx_pkt_len & 0x3) + STPSDIO_PR_WARN("rx len not 4 bytes, CHISR(0x%08x), rx len (%d).\n", + chisr, pInfo->rx_pkt_len); + } + /*Rx job */ + stp_sdio_rx_wkr(&pInfo->rx_work); + mtk_wcn_stp_wmt_sdio_host_awake(); + } + + } + + /* We schedule Tx job here without condition */ + /*Tx job */ + if (pInfo->awake_flag == 1 && pInfo->tx_retry_flag != STP_SDIO_RETRY_CRC_ERROR) + stp_sdio_tx_wkr(&pInfo->tx_work); + + /*Enable IRQ */ + /*Disable Common interrupt output in CHLPCR */ + STPSDIO_PR_DBG("enable COM IRQ\n"); + osal_ftrace_print("enable COM IRQ\n"); +/* need to wait for the ownback completion */ +/* [COHEC_00006052] SW work-around solution: + * using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR + */ +#if COHEC_00006052 + write_value = C_FW_INT_EN_SET; + iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, + &write_value, 0); +#else + write_value = C_FW_INT_EN_SET; + iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, + &write_value, 0); +#endif /* COHEC_00006052 */ + if (iRet) { + STPSDIO_PR_ERR("enable IRQ fail. iRet:%d\n", iRet); + osal_ftrace_print("enable COM IRQ fail, iRet:%d\n", iRet); + } else { + STPSDIO_PR_HINT("enable COM IRQ\n"); + iRet = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, + &chlcpr_value, 0); + if (iRet) { + STPSDIO_PR_ERR("read CHLPCR fail. iRet:%d\n", iRet); + } else { + if (chlcpr_value & C_FW_INT_EN_SET) { + STPSDIO_PR_HINT("enable COM IRQ okay (0x%x)\n", + chlcpr_value); + osal_ftrace_print("enable COM IRQ done\n"); + + /* INTR_STATUS CHECK */ +#if 0 + write_value = 0x00000002; + iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, + clt_ctx, CHCR, &write_value, 0); + + iRet = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, + clt_ctx, CHISR, &chisr, 0); + STPSDIO_PR_INFO("Query CHISR(0x%08x)\n", chisr); + + write_value = 0x00000000; + iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, + clt_ctx, CHCR, &write_value, 0); +#endif + } + } + + } + + if ((pInfo->sleep_flag != 0) + && (pInfo->wakeup_flag == 0) + && (pInfo->irq_pending == 0) + && (pInfo->rx_pkt_len == 0) + && mtk_wcn_stp_is_ready() + && !mtk_wcn_stp_coredump_start_get() /* f/w assert disable sdio sleep */ + ) { + if (pInfo->firmware_info.tx_packet_num == 0) { + /* pInfo->awake_flag = 0; */ + /* STPSDIO_PR_INFO("set firmware own! (sleeping)\n"); */ + while_loop_counter = 0; + osal_ftrace_print("|S|set F own\n"); + stp_sdio_do_own_set(pInfo); + osal_ftrace_print("|E|set F own, sleep_flag(%d), wakeup_flag(%d), awake_falg(%d)", + pInfo->sleep_flag, pInfo->wakeup_flag, pInfo->awake_flag); + } else { +#if 0 + /* debug code */ + if (while_loop_counter > 150) { + osal_ftrace_print("assert, w_l_c > %u\n", while_loop_counter); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, + CHLPCR, &val, 0); + osal_ftrace_print("CHLPCR(0x%x)\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, + CHISR, &val, 0); + osal_ftrace_print("CHISR(0x%x)\n", val); + iRet = wmt_core_trigger_stp_assert(); + if (!iRet) + STPSDIO_PR_INFO("trigger assert fail\n"); + } +#endif + /*Avoid competition for SDIO operations with ksdioirqd/mmc2 thread*/ + osal_usleep_range(300, 500); + } + } + if (while_loop_counter > 1000) { + while_loop_counter = 0; + pInfo->dump_flag = 1; + STPSDIO_PR_ERR("stp_sdio_tx_rx thread while_loop_counter over1000\n"); + stp_sdio_dump_info(pInfo); + osal_ftrace_print("stp(%d)irq(%d)tx_pkt_num(%d)rx_pkt_len(%d)", + mtk_wcn_stp_is_ready(), pInfo->irq_pending, + pInfo->firmware_info.tx_packet_num, pInfo->rx_pkt_len); + /*make fake irq flag to dump CHISR information */ + pInfo->irq_pending = 1; + + if ((pInfo->sleep_flag != 0) || (pInfo->wakeup_flag != 0)) { + osal_ftrace_print("loop_count > 1000, sleep_flag(%d), wakeup_flag(%d), awake_flag(%d)", + pInfo->sleep_flag, pInfo->wakeup_flag, pInfo->awake_flag); + /*clear wakeup/sleep pending flag, wakeup wmtd thread */ + pInfo->wakeup_flag = 0; + pInfo->sleep_flag = 0; + osal_raise_signal(&pInfo->isr_check_complete); + if (pInfo->firmware_info.tx_packet_num == STP_SDIO_TX_PKT_MAX_CNT) { + STPSDIO_PR_ERR("STP-SDIO can't handle tx request. tx_packet_num:%d\n", + pInfo->firmware_info.tx_packet_num); + osal_sleep_ms(200); + } + } + } else { + pInfo->dump_flag = 0; + } + osal_wait_for_event(&pInfo->tx_rx_event, stp_sdio_wait_for_msg, (PVOID) pInfo); + /* Read Packet from Firmware until firmware rx packet empty */ + STPSDIO_PR_DBG("stp_tx_rx_thread receive signal\n"); + } + /*make sure thread who is waiting for STP-SDIO's sleep/wakeup completion event */ + if ((pInfo->sleep_flag != 0) || (pInfo->wakeup_flag != 0)) { + osal_ftrace_print("wait for sleep/wakeup event, sleep_flag(%d), wakeup_flag(%d), awake_falg(%d)", + pInfo->sleep_flag, pInfo->wakeup_flag, pInfo->awake_flag); + pInfo->wakeup_flag = 0; + pInfo->sleep_flag = 0; + STPSDIO_PR_WARN("someone is wait for sleep/wakeup event, signal it to return\n"); + osal_raise_signal(&pInfo->isr_check_complete); + } + STPSDIO_PR_INFO("stp_tx_rx_thread exit\n"); +} +#endif /* STP_SDIO_OWN_THREAD */ + +/*! + * \brief Tx callback function for STP-CORE module + * + * \details A function registered to STP-CORE to provide STP-SDIO tx method. + * Multiple STP packet may be aggregated when available. + * + * \param[IN] data STP packet buffer to be sent through STP-SDIO + * \param[IN] size STP packet length to be sent + * \param[OUT] written_size Accepted buffer length by STP-SDIO. Shall be $size + * if success. + * + *\note Tx may do aggregation to previous entry with lock protection. If no + * aggregation is done, protection is NOT required. + * + * \retval 0 success + * \retval -1 invalid input parameters + * \todo return !0 when fail case (TBD) + */ +#if STP_SDIO_NEW_TXRING +INT32 stp_sdio_tx(const PUINT8 data, const UINT32 size, PUINT32 written_size) +{ + PUINT8 pkt_bufp; + UINT32 prev_wr_idx; + UINT32 prev_size; + MTK_WCN_STP_SDIO_PKT_BUF *pb; + UINT32 idx; + + osal_ftrace_print("%s|S|L|%d\n", __func__, size); + if (written_size) + *written_size = 0; + + /* do sanity check */ + if ((size > STP_SDIO_TX_FIFO_SIZE) + || (!data)) { + STPSDIO_PR_LOUD("invalid size(%ld) > fifo(%d) or data(0x%p)\n", + size, STP_SDIO_TX_FIFO_SIZE, data); + return -1; + } + + pb = &gp_info->pkt_buf; + /* 4 <1> enqueue the stp Tx packet */ + + spin_lock_irqsave(&pb->rd_cnt_lock, pb->rd_irq_flag); + /* Case 1: buffer is empty (No aggregation). Full flag is useless in this + * condition. + */ + if (atomic_read(&pb->rd_cnt) == atomic_read(&pb->wr_cnt)) { + spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag); + /* Set the size in SDIO packet header later in tx_worker, not here */ + idx = atomic_read(&pb->wr_cnt) & STP_SDIO_TX_BUF_CNT_MASK; + pb->tx_buf_ts[idx] = jiffies; + pb->tx_buf_sz[idx] = size + STP_SDIO_HDR_SIZE; +#if KMALLOC_UPDATE + pkt_bufp = pb->tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + STP_SDIO_HDR_SIZE; +#else + pkt_bufp = &pb->tx_buf[idx][STP_SDIO_HDR_SIZE]; +#endif + memcpy(pkt_bufp, data, size); + gp_info->txwkr_flag = 1; + atomic_inc(&pb->wr_cnt); + + if (written_size) + *written_size = size; + STPSDIO_PR_DBG("(Empty) Enqueue done\n"); + } + /* Case 2: buffer is neither empty(w != r) nor full (w-r < s) */ + else if ((atomic_read(&pb->wr_cnt) - atomic_read(&pb->rd_cnt)) < STP_SDIO_TX_BUF_CNT) { + prev_wr_idx = (atomic_read(&pb->wr_cnt) - 1) & STP_SDIO_TX_BUF_CNT_MASK; + prev_size = pb->tx_buf_sz[prev_wr_idx]; + + /* Case 2.1 Aggregate if rd_cnt+1 != wr_cnt */ + /* George: do length check using add instead of sub operation. Compare + * to FIFO size instead of sw entry size. + */ + if (((atomic_read(&pb->rd_cnt) + 1) != atomic_read(&pb->wr_cnt)) + && ((size + prev_size) <= STP_SDIO_TX_FIFO_SIZE)) { +#if KMALLOC_UPDATE + pkt_bufp = pb->tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + prev_size; +#else + pkt_bufp = &pb->tx_buf[prev_wr_idx][prev_size]; +#endif + pb->tx_buf_sz[prev_wr_idx] += size; + + memcpy(pkt_bufp, data, size); + spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag); + + STPSDIO_PR_DBG("(Not empty-aggre) Enqueue done\n"); + + if (written_size) + *written_size = size; + } + /* Case 2.2 Use next entry w/o aggregation */ + else { + /* Check the ring buf is full or not */ + if ((atomic_read(&pb->wr_cnt) - atomic_read(&pb->rd_cnt)) == 1) + pb->full_flag = MTK_WCN_BOOL_TRUE; + spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag); + + /* George: if tx_wkr preempts here and pop out all buffered entries, + * ie increase rd_idx utill wr_idx, tx_wkr will encounter buffer + * empty condition and stop, then being scheduled before end of this + * function. It's safe! + */ + idx = atomic_read(&pb->wr_cnt) & STP_SDIO_TX_BUF_CNT_MASK; + pb->tx_buf_ts[idx] = jiffies; + pb->tx_buf_sz[idx] = size + STP_SDIO_HDR_SIZE; +#if KMALLOC_UPDATE + pkt_bufp = pb->tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + STP_SDIO_HDR_SIZE; +#else + pkt_bufp = &pb->tx_buf[idx][STP_SDIO_HDR_SIZE]; +#endif + memcpy(pkt_bufp, data, size); + gp_info->txwkr_flag = 1; + atomic_inc(&pb->wr_cnt); + + STPSDIO_PR_DBG("(Not empty-no aggre) Enqueue done\n"); + if (written_size) + *written_size = size; + } + } + /* Case 3: buffer is full (w-r >= s), (try aggregation) */ + else { + if (!((atomic_read(&pb->wr_cnt) - atomic_read(&pb->rd_cnt)) >= STP_SDIO_TX_BUF_CNT)) { + STPSDIO_PR_ERR + ("abnormal condition and flow, wr_cnt(0x%x), rd_cnt(0x%x)\n", + atomic_read(&pb->wr_cnt), atomic_read(&pb->rd_cnt)); + } + prev_wr_idx = (atomic_read(&pb->wr_cnt) - 1) & STP_SDIO_TX_BUF_CNT_MASK; + prev_size = pb->tx_buf_sz[prev_wr_idx]; + + /* George: do length check using add instead of sub operation. Compare + * to FIFO size instead of sw entry size. (buf_allocation != 0) shall be + * an assert true condition, not a if () condition...... + */ + /* Case 3.1 Aggregation */ + if ((size + prev_size) <= STP_SDIO_TX_FIFO_SIZE) { + if (prev_size != 0) + STPSDIO_PR_ERR("abnormal, wr_cnt(0x%x), rd_cnt(0x%x), prev(%d), prev_size(%d)\n", + atomic_read(&pb->wr_cnt), atomic_read(&pb->rd_cnt), + prev_wr_idx, prev_size); +#if KMALLOC_UPDATE + pkt_bufp = pb->tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + prev_size; +#else + pkt_bufp = &pb->tx_buf[prev_wr_idx][prev_size]; +#endif + pb->tx_buf_sz[prev_wr_idx] += size; + + /* unlock after copying data to ring buffer done so that rd_cnt can + * move forward and may overlap to prev_wr_idx. + */ + memcpy(pkt_bufp, data, size); + spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag); + + STPSDIO_PR_DBG("(full-aggre) Enqueue done\n"); + + if (written_size) + *written_size = size; + } + /* Case 3.2 Buffer is full */ + else { + spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag); + STPSDIO_PR_WARN("Local Tx buffer is full !\n"); + + /* Wait for tx ring buffer is not full */ + /* TODO:[FixMe][George] This wait() call IS a problem if caller runs + * in interrupt context (sw or hw) !! + */ + /* TODO:[FixMe][George] should use timeout version, + * not interruptible version. Return error when timeout! + */ + wait_event_interruptible(pb->fullwait_q, + (pb->full_flag == MTK_WCN_BOOL_FALSE)); + STPSDIO_PR_INFO("wait event return\n"); + + spin_lock_irqsave(&pb->rd_cnt_lock, pb->rd_irq_flag); + /* Check if the local buf is free enough */ + if ((atomic_read(&pb->wr_cnt) - atomic_read(&pb->rd_cnt)) == 1) + pb->full_flag = MTK_WCN_BOOL_TRUE; + spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag); + + /* George: use this new entry w/o protection */ + idx = atomic(&pb->wr_cnt) & STP_SDIO_TX_BUF_CNT_MASK; + pb->tx_buf_ts[idx] = jiffies; + pb->tx_buf_sz[idx] = size + STP_SDIO_HDR_SIZE; +#if KMALLOC_UPDATE + pkt_bufp = pb->tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + STP_SDIO_HDR_SIZE; +#else + pkt_bufp = &pb->tx_buf[idx][STP_SDIO_HDR_SIZE]; +#endif + /* Copy data to ring buffer */ + memcpy(pkt_bufp, data, size); + gp_info->txwkr_flag = 1; + atomic_inc(&pb->wr_cnt); + + if (written_size) + *written_size = size; + } + } + + /* <2> schedule for Tx worker tasklet */ + osal_ftrace_print("%s|E|signal stp_sdio_tx_rx\n", __func__); +#if STP_SDIO_OWN_THREAD + /* tasklet_schedule(&gp_info->tx_rx_job); */ + STPSDIO_PR_DBG("osal_trigger_event gp_info->tx_rx_event\n"); + osal_trigger_event(&gp_info->tx_rx_event); +#else + schedule_work(&gp_info->tx_work); +#endif + osal_ftrace_print("%s|E|L|%d\n", __func__, size); + + return 0; +} + +#else +INT32 stp_sdio_tx(const PUINT8 data, const UINT32 size, PUINT32 written_size) +{ + PUINT8 pkt_bufp; + UINT32 prev_wr_idx; + UINT32 buf_allocation; + UINT32 room; + UINT64 ts; + ULONG nsec; + + osal_ftrace_print("%s|S|L|%d\n", __func__, size); + + /* 4 <1> enqueue the stp Tx packet */ + *written_size = 0; + + spin_lock_irqsave(&gp_info->pkt_buf.rd_idx_lock, gp_info->pkt_buf.rd_irq_flag); + /* Case 1: buffer is empty (Not aggregation) */ + if ((atomic_read(&gp_info->pkt_buf.rd_idx) == atomic_read(&gp_info->pkt_buf.wr_idx)) + && (gp_info->pkt_buf.full_flag == MTK_WCN_BOOL_FALSE)) { + spin_unlock_irqrestore(&gp_info->pkt_buf.rd_idx_lock, gp_info->pkt_buf.rd_irq_flag); + /* set the size in SDIO packet header */ +#if KMALLOC_UPDATE + *(gp_info->pkt_buf.tx_buf + atomic_read(&gp_info->pkt_buf.wr_idx) * + STP_SDIO_TX_ENTRY_SIZE + 0) = (UINT8)((size + STP_SDIO_HDR_SIZE) & 0xff); + *(gp_info->pkt_buf.tx_buf + atomic_read(&gp_info->pkt_buf.wr_idx) * + STP_SDIO_TX_ENTRY_SIZE + 1) = (UINT8)((size + STP_SDIO_HDR_SIZE) >> 8); +#else + gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][0] = + (UINT8) ((size + STP_SDIO_HDR_SIZE) & 0xff); + gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][1] = + (UINT8) ((size + STP_SDIO_HDR_SIZE) >> 8); +#endif + gp_info->pkt_buf.tx_buf_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = jiffies; + osal_get_local_time(&ts, &nsec); + gp_info->pkt_buf.tx_buf_local_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = ts; + gp_info->pkt_buf.tx_buf_local_nsec[atomic_read(&gp_info->pkt_buf.wr_idx)] = nsec; + + STPSDIO_PR_DBG("(Empty) Enqueue done\n"); +#if KMALLOC_UPDATE + pkt_bufp = gp_info->pkt_buf.tx_buf + atomic_read(&gp_info->pkt_buf.wr_idx) * + STP_SDIO_TX_ENTRY_SIZE + STP_SDIO_HDR_SIZE; +#else + pkt_bufp = &gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][STP_SDIO_HDR_SIZE]; +#endif + memcpy(pkt_bufp, data, size); + *written_size = size; + gp_info->txwkr_flag = 1; + atomic_set(&gp_info->pkt_buf.wr_idx, + (atomic_read(&gp_info->pkt_buf.wr_idx) + 1) % STP_SDIO_TX_BUF_CNT); + } + /* Case 2: buffer is not empty */ + else if (atomic_read(&gp_info->pkt_buf.rd_idx) != atomic_read(&gp_info->pkt_buf.wr_idx)) { + prev_wr_idx = (atomic_read(&gp_info->pkt_buf.wr_idx) - 1 + STP_SDIO_TX_BUF_CNT) % + STP_SDIO_TX_BUF_CNT; + /* set the packet size form previous SDIO packet header */ +#if KMALLOC_UPDATE + buf_allocation = + *(gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 1); + buf_allocation = + (buf_allocation << 8) | *(gp_info->pkt_buf.tx_buf + + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 0); +#else + buf_allocation = gp_info->pkt_buf.tx_buf[prev_wr_idx][1]; + buf_allocation = (buf_allocation << 8) | gp_info->pkt_buf.tx_buf[prev_wr_idx][0]; +#endif + /* Case 2.1 Aggregation */ + /* George: do length check using add instead of sub operation. Compare + * to FIFO size instead of sw entry size. + */ + if ((prev_wr_idx != atomic_read(&gp_info->pkt_buf.rd_idx)) + && ((size + buf_allocation) <= STP_SDIO_TX_FIFO_SIZE)) { +#if KMALLOC_UPDATE + pkt_bufp = + gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + + buf_allocation; + + buf_allocation += size; + *(gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 0) = + (UINT8) (buf_allocation & 0xff); + *(gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 1) = + (UINT8) (buf_allocation >> 8); +#else + pkt_bufp = &gp_info->pkt_buf.tx_buf[prev_wr_idx][buf_allocation]; + + buf_allocation += size; + gp_info->pkt_buf.tx_buf[prev_wr_idx][0] = (UINT8) (buf_allocation & 0xff); + gp_info->pkt_buf.tx_buf[prev_wr_idx][1] = (UINT8) (buf_allocation >> 8); +#endif + memcpy(pkt_bufp, data, size); + spin_unlock_irqrestore(&gp_info->pkt_buf.rd_idx_lock, + gp_info->pkt_buf.rd_irq_flag); + + STPSDIO_PR_DBG("(Not empty-aggre) Enqueue done\n"); + + *written_size = size; + } + /* Case 2.2 Not aggregation */ + else { + /* Check the ring buf is full or not */ + room = (atomic_read(&gp_info->pkt_buf.wr_idx) >= + atomic_read(&gp_info->pkt_buf.rd_idx)) ? (STP_SDIO_TX_BUF_CNT - + (atomic_read(&gp_info->pkt_buf.wr_idx) - + atomic_read(&gp_info->pkt_buf.rd_idx))) : + (atomic_read(&gp_info->pkt_buf.rd_idx) - + atomic_read(&gp_info->pkt_buf.wr_idx)); + if (room == 1) + gp_info->pkt_buf.full_flag = MTK_WCN_BOOL_TRUE; + spin_unlock_irqrestore(&gp_info->pkt_buf.rd_idx_lock, + gp_info->pkt_buf.rd_irq_flag); + + /* George: if tx_wkr preempts here and pop out all buffered entries, + * ie increase rd_idx utill wr_idx, tx_wkr will encounter buffer + * empty condition and stop, then being scheduled before end of this + * function. It's safe! + */ + + /* set the size in SDIO packet header */ +#if KMALLOC_UPDATE + *(gp_info->pkt_buf.tx_buf + + atomic_read(&gp_info->pkt_buf.wr_idx) * STP_SDIO_TX_ENTRY_SIZE + 0) = + (UINT8) ((size + STP_SDIO_HDR_SIZE) & 0xff); + *(gp_info->pkt_buf.tx_buf + + atomic_read(&gp_info->pkt_buf.wr_idx) * STP_SDIO_TX_ENTRY_SIZE + 1) = + (UINT8) ((size + STP_SDIO_HDR_SIZE) >> 8); + gp_info->pkt_buf.tx_buf_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = jiffies; + osal_get_local_time(&ts, &nsec); + gp_info->pkt_buf.tx_buf_local_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = ts; + gp_info->pkt_buf.tx_buf_local_nsec[atomic_read(&gp_info->pkt_buf.wr_idx)] = nsec; + + pkt_bufp = + gp_info->pkt_buf.tx_buf + + atomic_read(&gp_info->pkt_buf.wr_idx) * STP_SDIO_TX_ENTRY_SIZE + STP_SDIO_HDR_SIZE; +#else + gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][0] = + (UINT8) ((size + STP_SDIO_HDR_SIZE) & 0xff); + gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][1] = + (UINT8) ((size + STP_SDIO_HDR_SIZE) >> 8); + gp_info->pkt_buf.tx_buf_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = jiffies; + + pkt_bufp = &gp_info->pkt_buf. + tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][STP_SDIO_HDR_SIZE]; +#endif + memcpy(pkt_bufp, data, size); + + STPSDIO_PR_DBG("(Not empty-no aggre) Enqueue done\n"); + + *written_size = size; + gp_info->txwkr_flag = 1; + atomic_set(&gp_info->pkt_buf.wr_idx, + (atomic_read(&gp_info->pkt_buf.wr_idx) + 1) % STP_SDIO_TX_BUF_CNT); + } + } + /* Case 3: buffer is full (Aggregation) */ + else if (gp_info->pkt_buf.full_flag != MTK_WCN_BOOL_FALSE) { + prev_wr_idx = (atomic_read(&gp_info->pkt_buf.wr_idx) - 1 + STP_SDIO_TX_BUF_CNT) % + STP_SDIO_TX_BUF_CNT; +#if KMALLOC_UPDATE + buf_allocation = + *(gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 1); + buf_allocation = + (buf_allocation << 8) | *(gp_info->pkt_buf.tx_buf + + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 0); +#else + buf_allocation = gp_info->pkt_buf.tx_buf[prev_wr_idx][1]; + buf_allocation = (buf_allocation << 8) | gp_info->pkt_buf.tx_buf[prev_wr_idx][0]; +#endif + /* Case 3.1 Aggregation */ + /* George: do length check using add instead of sub operation. Compare + * to FIFO size instead of sw entry size. (buf_allocation != 0) shall be + * an assert true condition, not a if () condition...... + */ + if ((buf_allocation != 0) + && ((size + buf_allocation) <= STP_SDIO_TX_FIFO_SIZE)) { +#if KMALLOC_UPDATE + pkt_bufp = + gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + + buf_allocation; +#else + pkt_bufp = &gp_info->pkt_buf.tx_buf[prev_wr_idx][buf_allocation]; +#endif + buf_allocation += size; +#if KMALLOC_UPDATE + *(gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 0) = + (UINT8) (buf_allocation & 0xff); + *(gp_info->pkt_buf.tx_buf + prev_wr_idx * STP_SDIO_TX_ENTRY_SIZE + 1) = + (UINT8) (buf_allocation >> 8); +#else + gp_info->pkt_buf.tx_buf[prev_wr_idx][0] = (UINT8) (buf_allocation & 0xff); + gp_info->pkt_buf.tx_buf[prev_wr_idx][1] = (UINT8) (buf_allocation >> 8); +#endif + /* Copy data to ring buffer */ + memcpy(pkt_bufp, data, size); + spin_unlock_irqrestore(&gp_info->pkt_buf.rd_idx_lock, + gp_info->pkt_buf.rd_irq_flag); + + STPSDIO_PR_DBG("(full-aggre) Enqueue done\n"); + + *written_size = size; + } + /* Case 3.2 Buffer is full */ + else { + spin_unlock_irqrestore(&gp_info->pkt_buf.rd_idx_lock, + gp_info->pkt_buf.rd_irq_flag); + STPSDIO_PR_WARN("Local Tx buffer is full !!!!!\n"); + + /* Wait for tx ring buffer is not full + * TODO:[FixMe][George] This wait() call IS a problem + * if caller runs in interrupt context (sw or hw) !! + * TODO:[FixMe][George] should use timeout version, + * not interruptible version. Return error when timeout! + */ + wait_event_interruptible(gp_info->pkt_buf.fullwait_q, + (!gp_info->pkt_buf.full_flag)); + STPSDIO_PR_INFO("wait event return\n"); + + spin_lock_irqsave(&gp_info->pkt_buf.rd_idx_lock, + gp_info->pkt_buf.rd_irq_flag); + /* Check if the local buf is free enough */ + room = (atomic_read(&gp_info->pkt_buf.wr_idx) >= + atomic_read(&gp_info->pkt_buf.rd_idx)) ? + (STP_SDIO_TX_BUF_CNT - (atomic_read(&gp_info->pkt_buf.wr_idx) - + atomic_read(&gp_info->pkt_buf.rd_idx))) : + (atomic_read(&gp_info->pkt_buf.rd_idx) - + atomic_read(&gp_info->pkt_buf.wr_idx)); + if (room == 1) + gp_info->pkt_buf.full_flag = MTK_WCN_BOOL_TRUE; + spin_unlock_irqrestore(&gp_info->pkt_buf.rd_idx_lock, + gp_info->pkt_buf.rd_irq_flag); + + /* George: use this new entry w/o protection */ +#if KMALLOC_UPDATE + *(gp_info->pkt_buf.tx_buf + atomic_read(&gp_info->pkt_buf.wr_idx) * + STP_SDIO_TX_ENTRY_SIZE + 0) = + (UINT8) ((size + STP_SDIO_HDR_SIZE) & 0xff); + *(gp_info->pkt_buf.tx_buf + atomic_read(&gp_info->pkt_buf.wr_idx) * + STP_SDIO_TX_ENTRY_SIZE + 1) = + (UINT8) ((size + STP_SDIO_HDR_SIZE) >> 8); + gp_info->pkt_buf.tx_buf_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = jiffies; + osal_get_local_time(&ts, &nsec); + gp_info->pkt_buf.tx_buf_local_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = ts; + gp_info->pkt_buf.tx_buf_local_nsec[atomic_read(&gp_info->pkt_buf.wr_idx)] = nsec; + + pkt_bufp = gp_info->pkt_buf.tx_buf + atomic_read(&gp_info->pkt_buf.wr_idx) + * STP_SDIO_TX_ENTRY_SIZE + STP_SDIO_HDR_SIZE; +#else + gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][0] = + (UINT8) ((size + STP_SDIO_HDR_SIZE) & 0xff); + gp_info->pkt_buf.tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][1] = + (UINT8) ((size + STP_SDIO_HDR_SIZE) >> 8); + gp_info->pkt_buf.tx_buf_ts[atomic_read(&gp_info->pkt_buf.wr_idx)] = jiffies; + + pkt_bufp = &gp_info->pkt_buf. + tx_buf[atomic_read(&gp_info->pkt_buf.wr_idx)][STP_SDIO_HDR_SIZE]; +#endif + /* Copy data to ring buffer */ + memcpy(pkt_bufp, data, size); + *written_size = size; + gp_info->txwkr_flag = 1; + atomic_set(&gp_info->pkt_buf.wr_idx, + (atomic_read(&gp_info->pkt_buf.wr_idx) + 1) % STP_SDIO_TX_BUF_CNT); + } + } + /* <2> schedule for Tx worker tasklet */ + osal_ftrace_print("%s|E|signal stp_sdio_tx_rx\n", __func__); +#if STP_SDIO_OWN_THREAD + /* tasklet_schedule(&gp_info->tx_rx_job); */ + STPSDIO_PR_DBG("osal_trigger_event gp_info->tx_rx_event\n"); + osal_trigger_event(&gp_info->tx_rx_event); +#else + schedule_work(&gp_info->tx_work); +#endif + osal_ftrace_print("%s|E|L|%d\n", __func__, size); + + return 0; +} +#endif /* end of !STP_SDIO_NEW_TXRING */ + +/*! + * \brief Do STP-SDIO tx status, counters, debug information sanity check + * + * \details A function doing sanity checks on STP-SDIO Tx-related status, + * counters, debugging information. Used in tx_worker before and after bus + * write to check if any abnormal status happened. + * + * \param[IN] p_info The STP-SDIO HIF information structure pointer + * \param[IN] id The sanity check location ID, assigned by caller + * + * \retval none. + */ +static _osal_inline_ VOID stp_sdio_check_tx_sanity(const MTK_WCN_STP_SDIO_HIF_INFO *p_info, const UINT32 id) +{ +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG + if ((p_info) && (p_info->firmware_info.tx_packet_num == 0)) { + if (!(p_info->tx_pkt_list.pkt_rd_cnt == p_info->tx_pkt_list.pkt_wr_cnt)) { + STPSDIO_PR_ERR + ("abnormal fifo_size(%d) pkt_num(%d) pkt_rd(0x%x, %ld) pkt_wr(0x%x, %ld)!(%d)\n", + p_info->firmware_info.tx_fifo_size, + p_info->firmware_info.tx_packet_num, p_info->tx_pkt_list.pkt_rd_cnt, + STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_rd_cnt), + p_info->tx_pkt_list.pkt_wr_cnt, + STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_wr_cnt), id); + /* stp_sdio_dump_txdbg(); */ + } + if (p_info->firmware_info.tx_fifo_size != STP_SDIO_TX_FIFO_SIZE) { + STPSDIO_PR_ERR + ("abnormal fifo_size(%d) pkt_num(%d) pkt_rd(0x%x, %ld) pkt_wr(0x%x, %ld)!(%d)\n", + p_info->firmware_info.tx_fifo_size, + p_info->firmware_info.tx_packet_num, p_info->tx_pkt_list.pkt_rd_cnt, + STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_rd_cnt), + p_info->tx_pkt_list.pkt_wr_cnt, + STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_wr_cnt), id); + /* stp_sdio_dump_txdbg(); */ + } + } else { + if ((p_info) && (p_info->tx_pkt_list.pkt_rd_cnt == p_info->tx_pkt_list.pkt_wr_cnt)) { + STPSDIO_PR_ERR + ("abnormal fifo_size(%d) pkt_num(%d) pkt_rd(0x%x, %ld) pkt_wr(0x%x, %ld)!(%d)\n", + p_info->firmware_info.tx_fifo_size, + p_info->firmware_info.tx_packet_num, p_info->tx_pkt_list.pkt_rd_cnt, + STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_rd_cnt), + p_info->tx_pkt_list.pkt_wr_cnt, + STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_wr_cnt), id); + /* stp_sdio_dump_txdbg(); */ + } + } +#endif +} + +/*! + * \brief Handle STP-SDIO TX IRQ BH part and complete count + * + * \details Handle STP-SDIO TX IRQ bottom half part and reported tx complete + * coount. This function is used in tx_worker ONLY to avoid race condition. + * + * \note tx_comp_num in firmware_info structure shall be handled atomically. + * It is added in STP-SDIO Tx IRQ top half handler with the number reported + * in CHISR. It is deducted in this function. + * + * \note tx_fifo_size is deducted in tx_worker when writing data to bus and + * added back in this function when tx complete. + * + * \param[IN] p_info The STP-SDIO HIF information structure pointer + * + * \retval none. + */ +static VOID stp_sdio_tx_wkr_comp(MTK_WCN_STP_SDIO_HIF_INFO * const p_info) +{ + INT32 comp_count; + UINT32 idx; + INT32 i; + INT32 max; + INT32 ret; + UINT32 value = 0; + + comp_count = atomic_read(&p_info->firmware_info.tx_comp_num); + atomic_sub(comp_count, &p_info->firmware_info.tx_comp_num); + + /* update tx to firemware information */ + if (p_info->firmware_info.tx_packet_num >= comp_count) { + STPSDIO_PR_DBG("tx_pack_num(%d), comp_count(%d),tx_comp_num(%d), retry flag(%d)\n", + p_info->firmware_info.tx_packet_num, comp_count, + atomic_read(&p_info->firmware_info.tx_comp_num), + p_info->tx_retry_flag); + p_info->firmware_info.tx_packet_num -= comp_count; + } else { + STPSDIO_PR_INFO("abnormal complete count(%d), tx_packet_num(%d), retry flag(%d)!\n", + comp_count, p_info->firmware_info.tx_packet_num, p_info->tx_retry_flag); + /* TODO: [FixMe][George] Add error handling or bug report!! */ + STPSDIO_PR_INFO("tx_fifo_size(%d), tx_packet_num(%d)\n", + p_info->firmware_info.tx_fifo_size, + p_info->firmware_info.tx_packet_num); + } + + while (comp_count > 0) { + if (p_info->tx_pkt_list.pkt_rd_cnt == p_info->tx_pkt_list.pkt_wr_cnt) { + STPSDIO_PR_ERR("tx complete count(%d) but tx_pkt_list empty\n", + comp_count); + STPSDIO_PR_ERR("rd_cnt(%u, idx:%lx), wr_cnt(%u, idx:%lx)!\n", + p_info->tx_pkt_list.pkt_rd_cnt, + p_info->tx_pkt_list.pkt_rd_cnt & STP_SDIO_TX_PKT_LIST_SIZE_MASK, + p_info->tx_pkt_list.pkt_wr_cnt, + p_info->tx_pkt_list.pkt_wr_cnt & STP_SDIO_TX_PKT_LIST_SIZE_MASK); + break; + } + + idx = p_info->tx_pkt_list.pkt_rd_cnt++ & STP_SDIO_TX_PKT_LIST_SIZE_MASK; + p_info->firmware_info.tx_fifo_size += p_info->tx_pkt_list.pkt_size_list[idx]; + p_info->tx_pkt_list.out_ts[idx] = jiffies; + --comp_count; + } + if (p_info->retry_enable_flag) { + if (p_info->tx_retry_flag == STP_SDIO_RETRY_INT) { + for (i = 0; i < 100; i++) { + ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx, + CTMDPCR0, &value, 0); + if (value & 1) + break; + osal_sleep_ms(10); + } + if (!(value & 1)) { + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx, + CTMDPCR0, &value, 0); + STPSDIO_PR_ERR("tx retry: firmware rx buffer is disable CTMDPCR0 value(%x)!\n", + value); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx, + CTMDPCR1, &value, 0); + STPSDIO_PR_ERR("tx retry: firmware rx buffer is disable CTMDPCR1 value(%x)!\n", + value); + stp_sdio_issue_fake_coredump + ("ABT: <HIF_SDIO> tx retry ERROR: firmware rx buffer is disable"); + } + idx = p_info->tx_pkt_list.pkt_rd_cnt & STP_SDIO_TX_PKT_LIST_SIZE_MASK; + max = p_info->firmware_info.tx_packet_num; + STPSDIO_PR_ERR("tx retry idx(%d) tx retry max(%d)\n", idx, max); + for (i = 0; i < max; i++) { + /* sdio crc error tx retry */ + ret = stp_sdio_rw_retry(HIF_TYPE_WRITE_BUF, STP_SDIO_RETRY_LIMIT, + p_info->sdio_cltctx, CTDR, + (PUINT32)(p_info->pkt_buf.tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + 0), + p_info->tx_pkt_list.pkt_size_list[idx]); + if (ret) { + STPSDIO_PR_ERR("sdio tx retry get CTDR information Tx error(%d)!\n", + ret); + /* TODO: error handling! */ + p_info->tx_retry_count++; + if (p_info->tx_retry_count > STP_SDIO_RETRY_LIMIT) { + STPSDIO_PR_INFO("sdio tx retry fail complete count(%d)\n", + comp_count); + STPSDIO_PR_INFO("tx_packet_num(%d), tx_fifo_size(%d)\n", + p_info->firmware_info.tx_packet_num, + p_info->firmware_info.tx_fifo_size); + STPSDIO_PR_INFO("retry flag(%d)!\n", p_info->tx_retry_flag); + /* TODO: error handling! */ +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG + stp_sdio_txdbg_dump(); +#endif + p_info->tx_retry_count = 0; + stp_sdio_issue_fake_coredump + ("ABT: <HIF_SDIO> write_readsb retry ERROR"); + } + } else + p_info->tx_retry_count = 0; + idx++; + idx = idx & STP_SDIO_TX_PKT_LIST_SIZE_MASK; + } + p_info->tx_retry_flag = STP_SDIO_RETRY_NONE; + } + } +} + +/*! + * \brief Handle STP-SDIO Tx buffer and send to bus + * + * \details Handle STP-SDIO Tx buffer and send SDIO packet to bus if everything + * is checked ok. + * + * \note Tx count to FIFO is counted on a 4-byte aligned base. 1~3 bytes padding + * are also sent into HW FIFO and SHALL be trimmed off by firmware. + * tx_fifo_size is deducted in this bus when writing data to bus and added + * back in handle_tx_comp() function. + * + * \note Data length written to bus shall be 4-byte aligned AND block_size + * aligned if length > block_size. Padding bytes added for block_size is + * removed by HW. + * + * \note Max accumulated Tx size to FIFO is limited by STP_SDIO_TX_FIFO_SIZE and + * it is (2080) for MT6620. It is NOT limited to 256*5=1280 bytes. + * + * \note Max outstanding Tx packet count is limited by STP_SDIO_TX_PKT_MAX_CNT + * and it is (7) for MT6620. + * + * \param[IN] work Tx work struct work_struct pointer used by STP-SDIO + * + * \retval none. + */ +#if STP_SDIO_NEW_TXRING +static VOID stp_sdio_tx_wkr(struct work_struct *work) +{ + MTK_WCN_STP_SDIO_HIF_INFO *p_info; + UINT32 bus_txlen; + UINT32 four_byte_align_len; + PUINT8 buf_tx; + INT32 ret; + UINT32 idx; + MTK_WCN_STP_SDIO_PKT_BUF *pb; + struct timespec64 now; + UINT64 ts; + ULONG nsec; + + p_info = container_of(work, MTK_WCN_STP_SDIO_HIF_INFO, tx_work); + ret = HIF_SDIO_ERR_SUCCESS; + pb = &p_info->pkt_buf; + + /* 4 <0> Tx worker has been scheduled to send data */ + do { + /* handle tx complete count if any */ + stp_sdio_tx_wkr_comp(p_info); + /* check sanity of local tx information */ + stp_sdio_check_tx_sanity(p_info, 1); + + /* check if Tx ring buffer is empty */ + if (atomic_read(&p_info->pkt_buf.wr_cnt) == atomic_read(&p_info->pkt_buf.rd_cnt)) { + /* full flag is use less in this condition */ + STPSDIO_PR_DBG("Tx entry ring buffer empty\n"); + break; + } + p_info->txwkr_flag = 0; +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXPERFDBG + ++stp_sdio_txperf_worker_cnt; +#endif + + /* George: check txed packet number < limit(7) + * tx_packet_num is maintained only in tw_worker, no protection. + */ + if (p_info->firmware_info.tx_packet_num >= STP_SDIO_TX_PKT_MAX_CNT) { + STPSDIO_PR_DBG + ("tx_packet_num(%ld) limit, tx_fifo_size(%ld), four_byte_align_len(%ld)\n", + p_info->firmware_info.tx_packet_num, + p_info->firmware_info.tx_fifo_size, four_byte_align_len); +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXPERFDBG + ++stp_sdio_txperf_pkt_num_lmt_cnt; +#endif + break; + } +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXPERFDBG + stp_sdio_txperf_txed_pkt_num += p_info->firmware_info.tx_packet_num; +#endif + + /* Access content in rd_cnt is safe because it will not be aggregated + * anymore in sdio_tx(). Check current tx condition with info in rd_cnt. + */ + idx = atomic(&pb->rd_cnt) & STP_SDIO_TX_BUF_CNT_MASK; + + /* Get Tx packet size from Tx size ring buf */ + bus_txlen = pb->tx_buf_sz[idx]; + /* Update packet length in Tx entry */ +#if KMALLOC_UPDATE + buf_tx = gp_info->pkt_buf.tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + 0; +#else + buf_tx = &pb->tx_buf[idx][0]; +#endif + buf_tx[0] = (UINT8) (bus_txlen & 0xff); + buf_tx[1] = (UINT8) ((bus_txlen >> 8) & 0xff); + + /* George: hw always count fifo in 4-byte aligned length */ + bus_txlen += 0x3; + bus_txlen &= ~(0x3UL); + four_byte_align_len = bus_txlen; + + /* Sanity check: 4-byte aligned length shall not exceed HW FIFO Size */ + if (four_byte_align_len > STP_SDIO_TX_FIFO_SIZE) { + STPSDIO_PR_ERR("abnormal four_byte_align_len(%d) > TX_FIFO_SIZE(%ld)!!\n", + four_byte_align_len, STP_SDIO_TX_FIFO_SIZE); + } + + /* George: check if tx FIFO space is enough for 4-byte aligned length. + * If enough, tx this entry and increase rd_cnt. + */ + if (p_info->firmware_info.tx_fifo_size >= four_byte_align_len) { + /* George: refine block_size alignment with the assumption: block_size is 2^*x */ + if (bus_txlen > STP_SDIO_BLK_SIZE) { + bus_txlen += (STP_SDIO_BLK_SIZE - 1); + bus_txlen &= ~((UINT32) STP_SDIO_BLK_SIZE - 1); + } + + /* Sanity check: bus_txlen shall not exceed SW entry size */ + if (bus_txlen > STP_SDIO_TX_ENTRY_SIZE) { + STPSDIO_PR_ERR + ("abnormal bus_txlen(%d) > STP_SDIO_TX_ENTRY_SIZE(%ld)!!\n", + bus_txlen, STP_SDIO_TX_ENTRY_SIZE); + } + + ++(p_info->firmware_info.tx_packet_num); + /* decrease Tx FIFO size: using 4-byte aligned length! */ + p_info->firmware_info.tx_fifo_size -= four_byte_align_len; + /* record the SDIO packet size in packet size list: using 4-byte aligned length! */ + idx = p_info->tx_pkt_list.pkt_wr_cnt++ & STP_SDIO_TX_PKT_LIST_SIZE_MASK; + p_info->tx_pkt_list.pkt_size_list[idx] = four_byte_align_len; + p_info->tx_pkt_list.in_ts[idx] = jiffies; + p_info->tx_pkt_list.out_ts[idx] = 0; + + STPSDIO_PR_DBG("wr(0x%x, %ld) rd(0x%x, %ld), tx fifo(size:%d), pkt_num(%d)done\n", + p_info->tx_pkt_list.pkt_wr_cnt, + STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_wr_cnt), + p_info->tx_pkt_list.pkt_rd_cnt, + STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_rd_cnt), + p_info->firmware_info.tx_fifo_size, + p_info->firmware_info.tx_packet_num); + + /* port write the packet to CTDR */ + ret = stp_sdio_rw_retry(HIF_TYPE_WRITE_BUF, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx, + CTDR, (PUINT32) buf_tx, bus_txlen); + STPSDIO_PR_DBG("write to CTDR done\n"); + +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG + do { + osal_get_local_time(&ts, &nsec); + idx = stp_sdio_txdbg_cnt++ & STP_SDIO_TXDBG_COUNT_MASK; + /* skip clear buf */ + stp_sdio_txdbg_buffer[idx].ts = jiffies; + stp_sdio_txdbg_buffer[idx].l_sec = ts; + stp_sdio_txdbg_buffer[idx].l_nsec = nsec; + stp_sdio_txdbg_buffer[idx].bus_txlen = bus_txlen; + stp_sdio_txdbg_buffer[idx].four_byte_align_len = + four_byte_align_len; + /* store content */ + if (bus_txlen <= STP_SDIO_TX_ENTRY_SIZE) { + memcpy(&stp_sdio_txdbg_buffer[idx].tx_pkt_buf[0], buf_tx, + bus_txlen); + } else { + memcpy(&stp_sdio_txdbg_buffer[idx].tx_pkt_buf[0], buf_tx, + STP_SDIO_TX_ENTRY_SIZE); + STPSDIO_PR_ERR("abnormal bus_txlen (%d)!\n", bus_txlen); + } + } while (0); +#endif + if (ret) { + STPSDIO_PR_ERR("get CTDR information Tx error(%d)!\n", ret); + if (p_info->retry_enable_flag) { + if (ret == -EIO || ret == -EILSEQ || ret == -EBUSY) + p_info->tx_retry_flag = STP_SDIO_RETRY_CRC_ERROR; + else { + p_info->tx_retry_count = 0; + p_info->tx_retry_flag = STP_SDIO_RETRY_NONE; + stp_sdio_issue_fake_coredump + ("ABT: <HIF_SDIO> write_readsb retry ERROR"); + } + } else + stp_sdio_issue_fake_coredump("ABT: <HIF_SDIO> write_readsb retry ERROR"); + } + + /* clear rd index entry of Tx ring buffer */ + /*memset(buf_tx, 0, STP_SDIO_TX_ENTRY_SIZE); */ + /* George: clear STP-SDIO header only for debugging. */ + /*memset(buf_tx, 0, 4); */ + /* need clear??? skip it for debugging */ + + spin_lock_irqsave(&pb->rd_cnt_lock, pb->rd_irq_flag); + atomic_inc(&pb->rd_cnt); + /* TODO: [FixMe][George] check if full_flag needed? */ + if (pb->full_flag != MTK_WCN_BOOL_FALSE) { + pb->full_flag = MTK_WCN_BOOL_FALSE; + wake_up_interruptible(&pb->fullwait_q); + } + spin_unlock_irqrestore(&pb->rd_cnt_lock, pb->rd_irq_flag); + do_gettimeofday(&old); + } else { + /* tx FIFO free space < packet size, wait next time */ +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXPERFDBG + stp_sdio_txperf_fifo_left += p_info->firmware_info.tx_fifo_size; + stp_sdio_txperf_to_send += four_byte_align_len; + ++stp_sdio_txperf_fifo_lmt_cnt; +#endif + + ktime_get_ts64(&now); + if ((now.tv_sec - old.tv_sec) > TX_NO_ACK_TIMEOUT_ASSERT) { + STPSDIO_PR_INFO("tx_fifo_size(%d), four_byte_align_len(%d), tx_packet_num(%d)\n", + p_info->firmware_info.tx_fifo_size, four_byte_align_len, + p_info->firmware_info.tx_packet_num); + STPSDIO_PR_INFO("No ack trigger assert, tx %d seconds later\n", + TX_NO_ACK_TIMEOUT_ASSERT); + stp_dbg_poll_cpupcr(5, 1, 1); + p_info->firmware_info.tx_fifo_size = STP_SDIO_TX_FIFO_SIZE; + p_info->firmware_info.tx_packet_num = 0; + if (pb->full_flag != MTK_WCN_BOOL_FALSE) { + pb->full_flag = MTK_WCN_BOOL_FALSE; + wake_up_interruptible(&pb->fullwait_q); + } + ret = mtk_wcn_wmt_assert_timeout(WMTDRV_TYPE_STP, 33, 0); + if (!ret) + STPSDIO_PR_INFO("trigger assert fail\n"); + } + break; + } + + stp_sdio_check_tx_sanity(p_info, 2); + } while (1); +} + +#else + +static VOID stp_sdio_tx_wkr(struct work_struct *work) +{ + MTK_WCN_STP_SDIO_HIF_INFO *p_info; + UINT32 bus_txlen; + UINT32 four_byte_align_len; + PUINT8 buf_tx; + INT32 ret; + UINT32 idx; + MTK_WCN_STP_SDIO_PKT_BUF *pb; + struct timespec64 now; + UINT64 ts; + ULONG nsec; + + p_info = container_of(work, MTK_WCN_STP_SDIO_HIF_INFO, tx_work); + ret = HIF_SDIO_ERR_SUCCESS; + pb = &p_info->pkt_buf; + + /* 4 <0> Tx worker has been scheduled to send data */ + do { + /* handle tx complete count if any */ + stp_sdio_tx_wkr_comp(p_info); + stp_sdio_check_tx_sanity(p_info, 1); + + /* check if Tx ring buffer is empty */ + if ((atomic_read(&p_info->pkt_buf.wr_idx) == atomic_read(&p_info->pkt_buf.rd_idx)) + && (p_info->pkt_buf.full_flag == MTK_WCN_BOOL_FALSE)) { + STPSDIO_PR_DBG("Tx ring buffer is empty\n"); + break; + } + p_info->txwkr_flag = 0; + + /* George: no race condition here! Updating rd_idx content will not be + * put into more data by stp_sdio_tx + */ + /* Get Tx packet size from Tx ring buf */ +#if KMALLOC_UPDATE + buf_tx = gp_info->pkt_buf.tx_buf + + atomic_read(&p_info->pkt_buf.rd_idx) * STP_SDIO_TX_ENTRY_SIZE + 0; +#else + buf_tx = &p_info->pkt_buf.tx_buf[atomic_read(&p_info->pkt_buf.rd_idx)][0]; +#endif + bus_txlen = buf_tx[1]; + bus_txlen = (bus_txlen << 8) | buf_tx[0]; + + /* George: hw always count fifo in 4-byte aligned length */ + bus_txlen += 0x3; + bus_txlen &= ~(0x3UL); + four_byte_align_len = bus_txlen; + /* Sanity check: 4-byte aligned length shall not exceed HW FIFO Size */ + if (four_byte_align_len > STP_SDIO_TX_FIFO_SIZE) { + STPSDIO_PR_ERR("abnormal four_byte_align_len(%d) > TX_FIFO_SIZE(%ld)!!\n", + four_byte_align_len, STP_SDIO_TX_FIFO_SIZE); + } + + osal_ftrace_print("%s|S|bus_txlen(%d)\n", __func__, four_byte_align_len); + /* George: check if + * 1. tx FIFO free space is enough using 4-byte aligned length + * 2. tx max pkt count is not reached + */ + if ((p_info->firmware_info.tx_fifo_size >= four_byte_align_len) + && (p_info->firmware_info.tx_packet_num < STP_SDIO_TX_PKT_MAX_CNT)) { + /* George: refine block_size alignment with the assumption: block_size is 2^*x */ + if (bus_txlen > STP_SDIO_BLK_SIZE) { + bus_txlen += (STP_SDIO_BLK_SIZE - 1); + bus_txlen &= ~((UINT32) STP_SDIO_BLK_SIZE - 1); + } + + /* Sanity check: bus_txlen shall not exceed SW entry size */ + if (bus_txlen > STP_SDIO_TX_ENTRY_SIZE) { + STPSDIO_PR_ERR + ("abnormal bus_txlen(%d) > STP_SDIO_TX_ENTRY_SIZE(%ld)!!\n", + bus_txlen, STP_SDIO_TX_ENTRY_SIZE); + } + + ++(p_info->firmware_info.tx_packet_num); + /* decrease Tx FIFO size: using 4-byte aligned length! */ + p_info->firmware_info.tx_fifo_size -= four_byte_align_len; + /* record the SDIO packet size in packet size list: using 4-byte aligned length! */ + idx = p_info->tx_pkt_list.pkt_wr_cnt++ & STP_SDIO_TX_PKT_LIST_SIZE_MASK; + p_info->tx_pkt_list.pkt_size_list[idx] = four_byte_align_len; + p_info->tx_pkt_list.in_ts[idx] = jiffies; + p_info->tx_pkt_list.out_ts[idx] = 0; + + STPSDIO_PR_DBG("wr(0x%x, %ld) rd(0x%x, %ld), tx fifo(size:%d), pkt_num(%d)done\n", + p_info->tx_pkt_list.pkt_wr_cnt, + STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_wr_cnt), + p_info->tx_pkt_list.pkt_rd_cnt, + STP_SDIO_GET_PKT_AR_IDX(p_info->tx_pkt_list.pkt_rd_cnt), + p_info->firmware_info.tx_fifo_size, + p_info->firmware_info.tx_packet_num); + + /* port write the packet to CTDR */ + ret = stp_sdio_rw_retry(HIF_TYPE_WRITE_BUF, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx, + CTDR, (PUINT32) buf_tx, bus_txlen); + STPSDIO_PR_DBG("write to CTDR done\n"); + +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG + do { + osal_get_local_time(&ts, &nsec); + idx = stp_sdio_txdbg_cnt++ & STP_SDIO_TXDBG_COUNT_MASK; + /* skip clear buf */ + stp_sdio_txdbg_buffer[idx].ts = jiffies; + stp_sdio_txdbg_buffer[idx].l_sec = ts; + stp_sdio_txdbg_buffer[idx].l_nsec = nsec; + stp_sdio_txdbg_buffer[idx].bus_txlen = bus_txlen; + stp_sdio_txdbg_buffer[idx].four_byte_align_len = + four_byte_align_len; + /* store content */ + if (bus_txlen <= STP_SDIO_TX_ENTRY_SIZE) { + memcpy(&stp_sdio_txdbg_buffer[idx].tx_pkt_buf[0], buf_tx, + bus_txlen); + } else { + memcpy(&stp_sdio_txdbg_buffer[idx].tx_pkt_buf[0], buf_tx, + STP_SDIO_TX_ENTRY_SIZE); + STPSDIO_PR_ERR("abnormal bus_txlen(%d)!\n", bus_txlen); + } + } while (0); +#endif + + if (ret) { + STPSDIO_PR_ERR("get CTDR information Tx error(%d)!\n", ret); + if (p_info->retry_enable_flag) { + if (ret == -EIO || ret == -EILSEQ || ret == -EBUSY) + p_info->tx_retry_flag = STP_SDIO_RETRY_CRC_ERROR; + else { + p_info->tx_retry_count = 0; + p_info->tx_retry_flag = STP_SDIO_RETRY_NONE; + stp_sdio_issue_fake_coredump + ("ABT: <HIF_SDIO> write_readsb retry ERROR"); + } + } else + stp_sdio_issue_fake_coredump("ABT: <HIF_SDIO> write_readsb retry ERROR"); + } + + /* clear rd index entry of Tx ring buffer */ + /*memset(buf_tx, 0, STP_SDIO_TX_ENTRY_SIZE); */ + /* George: clear STP-SDIO header only for debugging. */ + /*memset(buf_tx, 0, 4); */ + /* need clear??? skip it for debugging */ + + spin_lock_irqsave(&p_info->pkt_buf.rd_idx_lock, + p_info->pkt_buf.rd_irq_flag); + /* release tx ring buffer */ + atomic_set(&p_info->pkt_buf.rd_idx, + (atomic_read(&p_info->pkt_buf.rd_idx) + 1) % STP_SDIO_TX_BUF_CNT); + /* Set Tx ring buffer is not full */ + if (p_info->pkt_buf.full_flag != MTK_WCN_BOOL_FALSE) { + p_info->pkt_buf.full_flag = MTK_WCN_BOOL_FALSE; + wake_up_interruptible(&p_info->pkt_buf.fullwait_q); + } + spin_unlock_irqrestore(&p_info->pkt_buf.rd_idx_lock, + p_info->pkt_buf.rd_irq_flag); + ktime_get_ts64(&old); + } else { +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXPERFDBG + stp_sdio_txperf_fifo_left += p_info->firmware_info.tx_fifo_size; + stp_sdio_txperf_to_send += four_byte_align_len; + ++stp_sdio_txperf_fifo_lmt_cnt; +#endif + /* (tx FIFO free space < packet size) or (the number of tx packets >= 7) */ + ktime_get_ts64(&now); + if ((now.tv_sec - old.tv_sec) > TX_NO_ACK_TIMEOUT_ASSERT) { + STPSDIO_PR_INFO("tx_fifo_size(%d), four_byte_align_len(%d), tx_packet_num(%d)\n", + p_info->firmware_info.tx_fifo_size, four_byte_align_len, + p_info->firmware_info.tx_packet_num); + STPSDIO_PR_INFO("No ack trigger assert, tx %d seconds later\n", + TX_NO_ACK_TIMEOUT_ASSERT); + stp_dbg_poll_cpupcr(5, 1, 1); + osal_ftrace_print("tx_fifo_size:%d, four_byte_align_len:%d, tx_packet_num(%d)\n", + p_info->firmware_info.tx_fifo_size, four_byte_align_len, + p_info->firmware_info.tx_packet_num); + p_info->firmware_info.tx_fifo_size = STP_SDIO_TX_FIFO_SIZE; + p_info->firmware_info.tx_packet_num = 0; + if (pb->full_flag != MTK_WCN_BOOL_FALSE) { + pb->full_flag = MTK_WCN_BOOL_FALSE; + wake_up_interruptible(&pb->fullwait_q); + } + ret = mtk_wcn_wmt_assert_timeout(WMTDRV_TYPE_STP, 33, 0); + if (!ret) + STPSDIO_PR_INFO("trigger assert fail\n"); + } + break; + } + + stp_sdio_check_tx_sanity(p_info, 2); + } while (1); + + osal_ftrace_print("%s|E|\n", __func__); +} +#endif /* end of stp_sdio_tx_wkr and STP_SDIO_NEW_TXRING */ + +/*! + * \brief Handle STP-SDIO Rx IRQ BH and read data from bus + * + * \details Handle STP-SDIO Rx IRQ buttom half and read data from bus according + * to the length read in Rx IRQ top half (stp_sdio_irq()) from CHISR + * + * \note rx_pkt_len read in stp_sdio_irq() from CHISR. No Rx IRQ would be + * triggered by FW before all Rx FIFO data is read by host driver. Do + * sanity check for this condition. + * + * \note HW Rx FIFO size is (2304 = 256*9) for MT6620 + * + * \param[IN] work Rx work struct work_struct pointer used by STP-SDIO + * + * \retval none. + */ +static VOID stp_sdio_rx_wkr(struct work_struct *work) +{ + PUINT8 bufp; + UINT32 bus_rxlen; + UINT32 chisr_rxlen; + INT32 ret; + INT32 ret_1; + UINT8 cccr_value = 0; + MTK_WCN_STP_SDIO_HIF_INFO *p_info; + + p_info = container_of(work, MTK_WCN_STP_SDIO_HIF_INFO, rx_work); + + /* 4 <0> receive data from CRDR */ + /* George: refine 4-byte alignment */ + chisr_rxlen = p_info->rx_pkt_len; + + + if (chisr_rxlen > STP_SDIO_RX_FIFO_SIZE) { + /* TODO: error handling! */ + STPSDIO_PR_ERR("abnormal chisr_rxlen(%d) rx_worker stop\n", chisr_rxlen); + return; + } + + bus_rxlen = chisr_rxlen; + bus_rxlen += 0x3; + bus_rxlen &= ~(0x3UL); + + /* George: refine block_size alignment with the assumption: BLK_SIZE is 2^x. */ + if (bus_rxlen > STP_SDIO_BLK_SIZE) { + bus_rxlen += (STP_SDIO_BLK_SIZE - 1); + bus_rxlen &= ~((UINT32) STP_SDIO_BLK_SIZE - 1); + } + + ret = stp_sdio_rw_retry(HIF_TYPE_READ_BUF, STP_SDIO_RETRY_LIMIT, p_info->sdio_cltctx, CRDR, + (PUINT32)(&(p_info->pkt_buf.rx_buf[0])), bus_rxlen); + if (p_info->retry_enable_flag) { + if (ret) { + if (ret == -EIO || ret == -EILSEQ || ret == -EBUSY) { + cccr_value = 0; + ret_1 = mtk_wcn_hif_sdio_f0_readb(p_info->sdio_cltctx, CCCR_F0, &cccr_value); + if (ret_1) + STPSDIO_PR_ERR("read CCCR_F0 fail(%d)\n", ret_1); + STPSDIO_PR_ERR("read CCCR_F0: (0x%x)\n", cccr_value); + cccr_value |= CCCR_F0_RX_CRC; + cccr_value |= CCCR_F0_RX_INT; + ret_1 = mtk_wcn_hif_sdio_f0_writeb(p_info->sdio_cltctx, CCCR_F0, cccr_value); + if (ret_1) + STPSDIO_PR_ERR("write CCCR_F0 fail(%d)\n", ret_1); + STPSDIO_PR_ERR("write CCCR_F0: (0x%x)\n", cccr_value); + cccr_value = 0; + ret_1 = mtk_wcn_hif_sdio_f0_readb(p_info->sdio_cltctx, CCCR_F0, &cccr_value); + if (ret_1) + STPSDIO_PR_ERR("read CCCR_F0 fail(%d)\n", ret_1); + STPSDIO_PR_ERR("read CCCR_F0: (0x%x)\n", cccr_value); + STPSDIO_PR_ERR("sdio read buffer happen crc error will be retry(%d)\n", ret); + p_info->rx_retry_count++; + if (p_info->rx_retry_count > STP_SDIO_RETRY_LIMIT) { + p_info->rx_retry_count = 0; + stp_sdio_issue_fake_coredump("ABT: <HIF_SDIO> sdio_readsb retry ERROR"); + } + } else { + p_info->rx_retry_count = 0; + stp_sdio_issue_fake_coredump("ABT: <HIF_SDIO> sdio_readsb retry ERROR"); + } + } else { + cccr_value = 0; + ret_1 = mtk_wcn_hif_sdio_f0_readb(p_info->sdio_cltctx, CCCR_F0, &cccr_value); + if (ret_1) + STPSDIO_PR_ERR("read CCCR_F0 fail(%d)\n", ret_1); + STPSDIO_PR_DBG("read CCCR_F0: (0x%x)\n", cccr_value); + cccr_value &= ~CCCR_F0_RX_CRC; + cccr_value |= CCCR_F0_RX_INT; + ret_1 = mtk_wcn_hif_sdio_f0_writeb(p_info->sdio_cltctx, CCCR_F0, cccr_value); + if (ret_1) + STPSDIO_PR_ERR("write CCCR_F0 fail(%d)\n", ret_1); + STPSDIO_PR_DBG("write CCCR_F0: (0x%x)\n", cccr_value); + cccr_value = 0; + ret_1 = mtk_wcn_hif_sdio_f0_readb(p_info->sdio_cltctx, CCCR_F0, &cccr_value); + if (ret_1) + STPSDIO_PR_ERR("read CCCR_F0 fail(%d)\n", ret_1); + STPSDIO_PR_DBG("read CCCR_F0: (0x%x)\n", cccr_value); + STPSDIO_PR_DBG("sdio read buffer success(%d)\n", ret); + + p_info->rx_retry_count = 0; + } + } else { + if (ret) { + STPSDIO_PR_HINT("set to p_info->rx_pkt_len 0\n"); + stp_sdio_issue_fake_coredump("ABT: <HIF_SDIO> sdio_readsb retry ERROR"); + } + } + if (ret) { + /* TODO: error handling! */ + STPSDIO_PR_ERR("read CRDR len(%d) rx error!(%d)\n", bus_rxlen, ret); + p_info->rx_pkt_len = 0; + return; + } + p_info->rx_pkt_len = 0; + STPSDIO_PR_HINT("set to p_info->rx_pkt_len 0\n"); +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_RXDBG + do { + UINT32 idx = stp_sdio_rxdbg_cnt++ & (STP_SDIO_RXDBG_COUNT - 1); + /* skip clear buf */ + stp_sdio_rxdbg_buffer[idx].ts = jiffies; + stp_sdio_rxdbg_buffer[idx].chisr_rxlen = chisr_rxlen; + stp_sdio_rxdbg_buffer[idx].bus_rxlen = bus_rxlen; + /* store content */ + memcpy(&stp_sdio_rxdbg_buffer[idx].rx_pkt_buf[0], &p_info->pkt_buf.rx_buf[0], + bus_rxlen); + } while (0); +#endif + + bufp = &p_info->pkt_buf.rx_buf[4]; + + /* Notice: len = SDIO_HDR(4) + (STP Packet + padding)*N */ + /* George: refine sanity check */ + bus_rxlen = p_info->pkt_buf.rx_buf[1]; + bus_rxlen = (bus_rxlen << 8) | p_info->pkt_buf.rx_buf[0]; + STPSDIO_PR_DBG("bus_rxlen(%d) rx_len in chisr(%d)\n", bus_rxlen, chisr_rxlen); + if (bus_rxlen != chisr_rxlen) { + STPSDIO_PR_ERR("abnormal bus_rxlen(%d) in SDIO packet header!in chisr(%d)\n", + bus_rxlen, chisr_rxlen); + return; + } + if (p_info->pkt_buf.rx_buf[2] || p_info->pkt_buf.rx_buf[3]) { + STPSDIO_PR_ERR("abnormal p_info->pkt_buf.rx_buf[2](0x%02x) [3](0x%02x)\n", + p_info->pkt_buf.rx_buf[2], p_info->pkt_buf.rx_buf[3]); + return; + } + + if (bus_rxlen > STP_SDIO_HDR_SIZE) { + bus_rxlen -= STP_SDIO_HDR_SIZE; + /* transmit data to stp core driver */ + osal_ftrace_print("%s|B|parser|L|%d\n", __func__, bus_rxlen); + ret = mtk_wcn_stp_parser_data(bufp, bus_rxlen); + osal_ftrace_print("%s|A|parser|L|%d\n", __func__, bus_rxlen); +#if STP_SDIO_DBG_SUPPORT && (STP_SDIO_TXDBG || STP_SDIO_TXPERFDBG) + if (ret && (p_info->tx_dbg_dump_flag == 0)) { + p_info->tx_dbg_dump_flag = 1; + stp_sdio_txdbg_dump(); + } +#endif + } else { + STPSDIO_PR_ERR("abnormal rx length(%d, %d)\n", bus_rxlen, chisr_rxlen); + } + + /* [George]: no need to mask/unmask rx interrupt. chip/fw assert next rx int + * if and only if host reads all rx data. + */ +} + +#if STP_SDIO_NEW_IRQ_HANDLER +static INT32 stp_sdio_irq(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx) +{ + INT32 iRet = 0; + UINT32 chlcpr_value = 0; + UINT32 write_value = 0; + MTK_WCN_STP_SDIO_HIF_INFO *p_info = gp_info; + + STPSDIO_PR_HINT("disable IRQ\n"); + /*Disable Common interrupt output in CHLPCR */ +/* [COHEC_00006052] SW work-around solution: + * using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR + */ +#if COHEC_00006052 + write_value = C_FW_INT_EN_CLR; + iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, + &write_value, 0); +#else + write_value = C_FW_INT_EN_CLR; + iRet = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, + &write_value, 0); +#endif /* COHEC_00006052 */ + if (iRet) + STPSDIO_PR_ERR("disalbe IRQ fail\n"); + else { + iRet = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, + &chlcpr_value, 0); + if (iRet) + STPSDIO_PR_ERR("read CHLPCR fail. iRet(%d)\n", iRet); + else { + if (!(chlcpr_value & C_FW_INT_EN_SET)) { + STPSDIO_PR_DBG("disable COM IRQ okay (0x%x)\n", chlcpr_value); + p_info->irq_pending = 1; + + /*inform stp_sdio thread to to rx/tx job */ + STPSDIO_PR_DBG("signal stp_tx_rx\n"); + osal_trigger_event(&gp_info->tx_rx_event); + osal_ftrace_print("%s|stp_tx_rx\n", __func__); + } else + STPSDIO_PR_ERR + ("**********disable COM IRQ fail, don't signal stp-sdio thread******\n"); + } + + } + return 0; + +} + +#else +/*! + * \brief Handle STP-SDIO interrupt + * + * \details Top half interrupt handler of STP-SDIO. Most of Tx/Rx jobs are put + * to bottom half workers respectively. + * + * \note Rx ok interrupt shall be asserted by hw ONLY after last data are all + * read by driver. Do sanity check on rx_pkt_len and should be 0: rx BH + * finished. + * + * \note Tx complete count shall be handled atomically TH here and BH in + * tx_worker. + * + * \param[IN] clt_ctx A HIF-SDIO client context + * + * \retval 0 success + * \retval !=0 fail + */ +static INT32 stp_sdio_irq(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx) +{ + /*MTK_WCN_STP_SDIO_PRIVATE_INFO *p_priv; */ + MTK_WCN_STP_SDIO_HIF_INFO *p_info = NULL; + UINT32 chisr = 0; + UINT32 tx_comp; + INT32 ret; + +#if 0 + p_priv = mtk_wcn_hif_sdio_get_drvdata(clt_ctx); +TODO:[FixMe][George] do sanity check ! + p_info = &g_stp_sdio_host_info[p_priv->stp_sdio_host_idx]; +#endif + p_info = gp_info; + ret = HIF_SDIO_ERR_SUCCESS; + /* 4 <0> get CHLPCR information */ + if (stp_sdio_get_own_state() == OWN_CLR) + STPSDIO_PR_DBG("OWN on driver side!\n"); + else { + STPSDIO_PR_DBG("OWN on fw side!\n"); + if (stp_sdio_do_own_clr(0) == 0) + STPSDIO_PR_DBG("set OWN to driver side ok!\n"); + else { + STPSDIO_PR_ERR("set OWN to driver side error!\n"); + return -1; + } + + } +retry: + /* 4 <1> get CHISR information */ + ret = mtk_wcn_hif_sdio_readl(clt_ctx, CHISR, &chisr); + if (ret) { + /* 4 <1.1> get CHISR Rx error handling */ + /* TODO: error handling! */ + STPSDIO_PR_ERR("get CHISR information rx error,ret:%d\n", ret); + if (ret == -5) { + STPSDIO_PR_ERR("get CHISR DAT CRC error, retry.\n"); + ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_MAX_RETRY_NUM, clt_ctx, CSR, &chisr, + 0); + } else + goto retry; + } + STPSDIO_PR_HINT("CHISR(0x%08x)\n", chisr); + if (chisr == 0x0) { + STPSDIO_PR_ERR("******CHISR == 0*****\n"); + return 0; + } + /* 4 <2> handle ownership back interrupt */ + if (chisr & FW_OWN_BACK_INT) { + STPSDIO_PR_INFO("FW_OWN_BACK_INT\n"); + + if (is_wait_ownback) { + is_wait_ownback = 0; + wake_up(&g_ownback_done); + } else { + mtk_wcn_stp_wmt_sdio_host_awake(); + /* if (cmb_bgf_eirq_cb) { */ + /* (*cmb_bgf_eirq_cb)(); */ + /* } */ + } + } + /* 4 <3> handle Rx interrupt */ + if (chisr & RX_DONE) { + /* STPSDIO_PR_INFO("RX_DONE_INT\n"); */ + + /* TODO: [FixMe][George] testing... */ + if (p_info->rx_pkt_len) + STPSDIO_PR_ERR("rx worker is not finished yet!!!(%d)\n", + p_info->rx_pkt_len); + + /* get Rx packet length */ + p_info->rx_pkt_len = (chisr & RX_PKT_LEN) >> 16; + STPSDIO_PR_HINT("rx_pkt_len(%d)\n", p_info->rx_pkt_len); + /* sanity check */ + if ((p_info->rx_pkt_len == 0) + || (p_info->rx_pkt_len > STP_SDIO_RX_FIFO_SIZE)) { + STPSDIO_PR_ERR + ("abnormal rx_pkt_len(%d) in CHISR(0x%08x) skip rx_worker\n", + p_info->rx_pkt_len, chisr); + p_info->rx_pkt_len = 0; + } else { + /* Before host driver read all rx data, chip/fw will not send more data + * to host. No need to mask rx interrupt. schedule rx worker to get data + * back and handle it. + */ + if (p_info->rx_pkt_len & 0x3) { + STPSDIO_PR_WARN + ("rx data len is not 4 bytes allignment, CHISR(0x%08x), rx len (%d).\n", + chisr, p_info->rx_pkt_len); + } +#if STP_SDIO_OWN_THREAD + /* tasklet_schedule(&p_info->tx_rx_job); */ + STPSDIO_PR_DBG("osal_trigger_event gp_info->tx_rx_event\n"); + osal_trigger_event(&gp_info->tx_rx_event); +#else + schedule_work(&p_info->rx_work); +#endif + } + } + /* 4 <4> handle Tx interrupt */ + if ((chisr & TX_EMPTY) || (chisr & TX_UNDER_THOLD)) { + STPSDIO_PR_DBG("Tx interrupt\n"); + /* get complete count */ + tx_comp = (chisr & TX_COMPLETE_COUNT) >> 4; +#if 0 + atomic_add(tx_comp, &p_info->firmware_info.tx_comp_num); + /* TODO:[FixMe][George]: debug and to be removed... */ + tx_comp = atomic_read(&p_info->firmware_info.tx_comp_num); +#else + tx_comp = atomic_add_return(tx_comp, &p_info->firmware_info.tx_comp_num); +#endif + if (tx_comp > STP_SDIO_TX_PKT_MAX_CNT) { + STPSDIO_PR_ERR("Abnormal accumulated comp count(%d) chisr(0x%x)\n", + tx_comp, chisr); + } + + /* move most of tx jobs to tx_worker */ + /* schedule tx worker for tx complete count and following tx data */ +#if STP_SDIO_OWN_THREAD + /* tasklet_schedule(&p_info->tx_rx_job); */ + STPSDIO_PR_DBG("osal_trigger_event gp_info->tx_rx_event\n"); + osal_trigger_event(&gp_info->tx_rx_event); +#else + schedule_work(&p_info->tx_work); +#endif + } + + return ret; +} +#endif /* STP_SDIO_NEW_IRQ_HANDLER */ + +#if STP_SDIO_POLL_OWNBACK_INTR +/***************************************************************************** + * FUNCTION + * stp_sdio_ownback_poll + * DESCRIPTION + * Poll ownback interrupt + * PARAMETERS + * 1. *func [IN] sdio driver function pointer + * 2. retryp [IN] polling retry times + * 3. delay_us [IN] polling delay (unit: us) + * RETURNS + * ret: Probe result + *****************************************************************************/ +static INT32 stp_sdio_ownback_poll(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx, UINT32 retry, UINT32 delay_us) +{ + INT32 ret; + UINT32 chlpcr = 0; + + do { +#if 0 + ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHISR, &chisr_value, + 0); +#endif + /* 20111020: change to poll CHLPCR instead of read-cleared CHISR */ + ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, &chlpcr, 0); + if (ret) { + /* 4 <1.1> get CHISR Rx error handling */ + STPSDIO_PR_ERR("get CHLPCR information rx error!(%d)\n", ret); + return ret; + } + + /*if (chisr_value & FW_OWN_BACK_INT) { */ + if (chlpcr & C_FW_COM_DRV_OWN) { + /* 4 <2> handle ownership back interrupt */ + STPSDIO_PR_DBG("Driver own is polled!(%d)\n", retry); + gp_info->awake_flag = 1; + break; + } + osal_usleep_range(delay_us, delay_us); + } while (retry-- > 0); + + /*return (chisr_value & FW_OWN_BACK_INT) ? 0 : -HIF_SDIO_ERR_FAIL; */ + return (chlpcr & C_FW_COM_DRV_OWN) ? 0 : -HIF_SDIO_ERR_FAIL; +} +#endif /* STP_SDIO_POLL_OWNBACK_INTR */ + +/***************************************************************************** + * FUNCTION + * stp_sdio_probe + * DESCRIPTION + * Probe function of SDIO driver + * PARAMETERS + * 1. *func [IN] sdio driver function pointer + * 2. *id [IN] sdio function id + * RETURNS + * ret: Probe result + *****************************************************************************/ +/* typedef INT32 (*MTK_WCN_HIF_SDIO_PROBE)(MTK_WCN_HIF_SDIO_CLTCTX, const MTK_WCN_HIF_SDIO_FUNCINFO *); */ +static INT32 stp_sdio_probe(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx, + const MTK_WCN_HIF_SDIO_FUNCINFO *sdio_func_infop) +{ + INT32 ret = HIF_SDIO_ERR_SUCCESS; + UINT32 i = 0, chlcpr_value = 0; + UINT32 write_value = 0; + + STPSDIO_PR_DBG("sdio_cltctx: 0x%08x\n", clt_ctx); + + if (g_stp_sdio_host_count) { + STPSDIO_PR_ERR("g_stp_sdio_host_count(%d) probed already!\n", + g_stp_sdio_host_count); + return -1; + } + /* 4 <1> check if input pointer is valid */ + if (g_stp_sdio_host_info.sdio_cltctx == clt_ctx) { + STPSDIO_PR_WARN("sdio_cltctx(%d) already probed!\n", clt_ctx); + return 0; + } + /* 4 <2> allocate host inform structure and initialize private variables */ + /* init host info private variables */ + g_stp_sdio_host_info.sdio_cltctx = clt_ctx; + + /* init Tx packet ring buffer */ + for (i = 0; i < STP_SDIO_TX_BUF_CNT; ++i) { +#if KMALLOC_UPDATE + UINT8 *pData = g_stp_sdio_host_info.pkt_buf.tx_buf + i * STP_SDIO_TX_ENTRY_SIZE + 0; + + memset(pData, 0, STP_SDIO_TX_ENTRY_SIZE); +#else + memset(&g_stp_sdio_host_info.pkt_buf.tx_buf[i][0], 0, + sizeof(g_stp_sdio_host_info.pkt_buf.tx_buf[i])); +#endif + } + osal_sleepable_lock_init(&fake_coredump_lock); + +#if STP_SDIO_NEW_TXRING + spin_lock_init(&g_stp_sdio_host_info.pkt_buf.rd_cnt_lock); + atomic_set(&g_stp_sdio_host_info.pkt_buf.wr_cnt, 0); + atomic_set(&g_stp_sdio_host_info.pkt_buf.rd_cnt, 0); +#else + /*g_stp_sdio_host_info.pkt_buf.rd_idx_lock = SPIN_LOCK_UNLOCKED; */ + spin_lock_init(&g_stp_sdio_host_info.pkt_buf.rd_idx_lock); + atomic_set(&g_stp_sdio_host_info.pkt_buf.wr_idx, 0); + atomic_set(&g_stp_sdio_host_info.pkt_buf.rd_idx, 0); +#endif + g_stp_sdio_host_info.pkt_buf.full_flag = MTK_WCN_BOOL_FALSE; + + /* init wait queue head for Tx ring buf full */ + init_waitqueue_head(&g_stp_sdio_host_info.pkt_buf.fullwait_q); + + /* init Tx packet size list information */ + memset(&g_stp_sdio_host_info.tx_pkt_list.pkt_size_list[0], 0, + sizeof(g_stp_sdio_host_info.tx_pkt_list.pkt_size_list)); + g_stp_sdio_host_info.tx_pkt_list.pkt_rd_cnt = 0; + g_stp_sdio_host_info.tx_pkt_list.pkt_wr_cnt = 0; + + /* init Rx interrupt mask */ + /* g_stp_sdio_host_info.rx_intr_mask = MTK_WCN_BOOL_FALSE; */ + + /* init firmware related information */ + g_stp_sdio_host_info.firmware_info.tx_fifo_size = STP_SDIO_TX_FIFO_SIZE; + g_stp_sdio_host_info.firmware_info.tx_packet_num = 0; + atomic_set(&g_stp_sdio_host_info.firmware_info.tx_comp_num, 0); + + /* init SDIO data path retry flag */ + g_stp_sdio_host_info.retry_enable_flag = 0; + g_stp_sdio_host_info.tx_retry_flag = STP_SDIO_RETRY_NONE; + + g_stp_sdio_host_info.isr_check_complete.timeoutValue = 1000; + osal_signal_init(&g_stp_sdio_host_info.isr_check_complete); + +#if STP_SDIO_OWN_THREAD + /* tasklet_init(&g_stp_sdio_host_info.tx_rx_job, stp_sdio_tx_rx_handling, */ + /* (unsigned long) &g_stp_sdio_host_info); */ + /* Create stp_sdio_tx_rx_thread, in suspend state */ + g_stp_sdio_host_info.irq_pending = 0; + g_stp_sdio_host_info.sleep_flag = 0; + g_stp_sdio_host_info.wakeup_flag = 0; + osal_event_init(&g_stp_sdio_host_info.tx_rx_event); + g_stp_sdio_host_info.tx_rx_thread.pThreadFunc = stp_sdio_tx_rx_handling; + g_stp_sdio_host_info.tx_rx_thread.pThreadData = (PVOID) &g_stp_sdio_host_info; + g_stp_sdio_host_info.tx_dbg_dump_flag = 0; + osal_strncpy((PINT8)&g_stp_sdio_host_info.tx_rx_thread.threadName, + "stp_sdio_tx_rx", osal_sizeof(g_stp_sdio_host_info.tx_rx_thread.threadName)); + ret = osal_thread_create(&g_stp_sdio_host_info.tx_rx_thread); + if (ret < 0) { + STPSDIO_PR_ERR("osal_thread_create fail...: %p\n", + g_stp_sdio_host_info.tx_rx_thread.pThread); + return ret; + } +#else + /* init tx_tasklet and rx work_queue */ + INIT_WORK(&g_stp_sdio_host_info.tx_work, stp_sdio_tx_wkr); + INIT_WORK(&g_stp_sdio_host_info.rx_work, stp_sdio_rx_wkr); +#endif + /* init stp sdio host private information *//* TODO: [FixMe][George] Still need this? */ + g_stp_sdio_host_info.private_info.stp_sdio_host_idx = g_stp_sdio_host_count; + mtk_wcn_hif_sdio_set_drvdata(clt_ctx, &g_stp_sdio_host_info.private_info); + + ++g_stp_sdio_host_count; + + /* 4 <3> request firmware-own back */ +/* [COHEC_00006052] SW work-around solution: */ +/* using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR */ +#if COHEC_00006052 + write_value = (C_FW_OWN_REQ_CLR >> 8); + ret = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, clt_ctx, (UINT32)(CHLPCR + 0x1), + &write_value, 0); +#else + write_value = C_FW_OWN_REQ_CLR; + ret = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, + &write_value, 0); +#endif /* COHEC_00006052 */ + if (ret) { + STPSDIO_PR_ERR("request FW-Own back fail!(%d)\n", ret); + goto out; + } + STPSDIO_PR_DBG("request FW-Own back done\n"); + +#if STP_SDIO_POLL_OWNBACK_INTR + /* 4 <3.1> polling own back bit */ + ret = stp_sdio_ownback_poll(clt_ctx, 10, 100); + if (ret) { + STPSDIO_PR_ERR("poll FW-Own back fail!(%d)\n", ret); + goto out; + } +#endif + /* 4 <4.0> enable irq flag in HIF-SDIO */ + mtk_wcn_hif_sdio_enable_irq(clt_ctx, MTK_WCN_BOOL_TRUE); + /* 4 <4> enabling all host interrupt except abnormal ones */ + /*write_value = (CHISR_EN_15_7 | CHISR_EN_3_0);*/ /* enable CHISR interrupt output */ + /*ret = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHIER, &write_value, 0);*/ + write_value = (FIRMWARE_INT | TX_FIFO_OVERFLOW | FW_INT_IND_INDICATOR | TX_COMPLETE_COUNT + | TX_UNDER_THOLD | TX_EMPTY | RX_DONE); + ret = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHIER, + &write_value, 0); + if (ret) { + STPSDIO_PR_ERR("set interrupt output fail!(%d)\n", ret); + goto out; + } + STPSDIO_PR_DBG("set interrupt output done\n"); +/* [COHEC_00006052] SW work-around solution: */ +/* using CMD52 write instead of CMD53 write for CCIR, CHLPCR, CSDIOCSR */ +#if COHEC_00006052 + write_value = C_FW_INT_EN_SET; + ret = stp_sdio_rw_retry(HIF_TYPE_WRITEB, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, &write_value, + 0); /* enable interrupt */ +#else + write_value = C_FW_INT_EN_SET; + ret = stp_sdio_rw_retry(HIF_TYPE_WRITEL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, &write_value, + 0); /* enable interrupt */ +#endif /* COHEC_00006052 */ + if (ret) { + STPSDIO_PR_ERR("enable interrupt fail!(%d)\n", ret); + goto out; + } + ret = stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, &chlcpr_value, + 0); + if (ret) { + STPSDIO_PR_ERR("Read CHLPCR fail!(%d)\n", ret); + goto out; + } else { + if (chlcpr_value & C_FW_INT_EN_SET) + STPSDIO_PR_DBG("enable interrupt okay (0x%x)\n", chlcpr_value); + } + + STPSDIO_PR_DBG("enable interrupt done\n"); + +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT + stp_sdio_deep_sleep_flag_set(MTK_WCN_BOOL_FALSE); +#endif + +#if STP_SDIO_OWN_THREAD + ret = osal_thread_run(&g_stp_sdio_host_info.tx_rx_thread); + if (ret < 0) { + STPSDIO_PR_ERR("osal_thread_run fail...\n"); + goto out; + } +#endif + + /* 4 <5> register mtk_wcn_stp_if_tx() to stp driver */ + mtk_wcn_stp_register_if_tx(STP_SDIO_IF_TX, (MTK_WCN_STP_IF_TX) stp_sdio_tx); + +#if 0 /* controlled by 6620_launcher & WMT */ + /*set STP sdio mode */ + pr_warn(DFT_TAG "%s: set stp sdio mode\n", __func__); + mtk_wcn_stp_set_sdio_mode(1); + + /*indicate the stp the sdio ready */ + pr_warn(DFT_TAG "%s: stp enable\n", __func__); + mtk_wcn_stp_enable(1); +#endif + +out: + /* 4 <6> error handling */ + /* TODO: error handling */ + if (ret) { +#if STP_SDIO_OWN_THREAD + osal_thread_destroy(&g_stp_sdio_host_info.tx_rx_thread); +#endif + if (g_stp_sdio_host_count > 0) + --g_stp_sdio_host_count; + } + + return ret; +} + +/***************************************************************************** + * FUNCTION + * stp_sdio_probe + * DESCRIPTION + * SDIO hardware remove function. + * PARAMETERS + * *func [IN] SDIO driver handler pointer. + * RETURNS + * none. + *****************************************************************************/ +static INT32 stp_sdio_remove(const MTK_WCN_HIF_SDIO_CLTCTX clt_ctx) +{ +#if 0 + MTK_WCN_STP_SDIO_PRIVATE_INFO *p_priv; + + p_priv = mtk_wcn_hif_sdio_get_drvdata(clt_ctx); +#endif + + if (g_stp_sdio_host_info.sdio_cltctx == clt_ctx) + STPSDIO_PR_DBG("sdio_cltctx(%d) found\n", clt_ctx); + else { + STPSDIO_PR_ERR("sdio_cltctx(%d) not found\n", clt_ctx); + return -1; + } + osal_sleepable_lock_deinit(&fake_coredump_lock); + if (g_stp_sdio_host_count > 0) + --g_stp_sdio_host_count; + /* 4 <0> disable irq flag in HIF-SDIO */ + mtk_wcn_hif_sdio_enable_irq(clt_ctx, MTK_WCN_BOOL_FALSE); + /* 4 <1> unregister if_tx() function */ + mtk_wcn_stp_register_if_tx(STP_SDIO_IF_TX, NULL); + + /* <2> stop Tx tasklet/Rx work queue of the host */ +#if STP_SDIO_OWN_THREAD + /* tasklet_kill(&g_stp_sdio_host_info.tx_rx_job); */ + /* STPSDIO_PR_INFO("kill tasklet finished\n"); */ + osal_thread_destroy(&g_stp_sdio_host_info.tx_rx_thread); + osal_event_deinit(&g_stp_sdio_host_info.tx_rx_event); + osal_signal_deinit(&g_stp_sdio_host_info.isr_check_complete); + STPSDIO_PR_DBG("destroy STP-SDIO tx_rx_thread\n"); +#else + //flush_scheduled_work(); + flush_work_sync(&clt_cxt->work_erase); + flush_work_sync(&clt_cxt->work_write); + iTPSDIO_PR_INFO("flush scheduled work end\n"); +#endif + + /* 4 <3> return ownership to firmware of the host */ + /* TODO: check set which register ! */ + + /* 4 <4> clear the host struct list */ + stp_sdio_host_info_op(1); + + + STPSDIO_PR_DBG("clear g_stp_sdio_host_info[p_priv->stp_sdio_host_idx] done\n"); + + return 0; +} + +INT32 stp_sdio_rw_retry(ENUM_STP_SDIO_HIF_TYPE_T type, UINT32 retry_limit, + MTK_WCN_HIF_SDIO_CLTCTX clt_ctx, UINT32 offset, PUINT32 pData, UINT32 len) +{ + INT32 ret = -1; + INT32 ret_1 = -1; + UINT32 value = 0; + INT32 retry_flag = 0; + + UINT32 card_id = CLTCTX_CID(clt_ctx); + + if (card_id != 0x6630 && card_id != 0x6632) { + STPSDIO_PR_LOUD("card_id is :0x%x, does not support CSR (Common Snapshot Register)\n", + card_id); + retry_limit = 1; + } + STPSDIO_PR_LOUD("clt_ctx:0x%x, offset:0x%x, retry_limit:%d\n", clt_ctx, offset, retry_limit); + + retry_limit = retry_limit == 0 ? 1 : retry_limit; + retry_limit = retry_limit > STP_SDIO_MAX_RETRY_NUM ? STP_SDIO_MAX_RETRY_NUM : retry_limit; + + while (retry_limit > 0) { + switch (type) { + case HIF_TYPE_READB: + if (retry_flag) + ret = mtk_wcn_hif_sdio_readb(clt_ctx, CSR, (PUINT8)pData); + else + ret = mtk_wcn_hif_sdio_readb(clt_ctx, offset, (PUINT8)pData); + break; + case HIF_TYPE_READL: + if (retry_flag) + ret = mtk_wcn_hif_sdio_readl(clt_ctx, CSR, pData); + else + ret = mtk_wcn_hif_sdio_readl(clt_ctx, offset, pData); + break; + case HIF_TYPE_READ_BUF: + ret = mtk_wcn_hif_sdio_read_buf(clt_ctx, offset, pData, len); + break; + case HIF_TYPE_WRITEB: + ret = mtk_wcn_hif_sdio_writeb(clt_ctx, offset, (UINT8)(*pData)); + break; + case HIF_TYPE_WRITEL: + ret = mtk_wcn_hif_sdio_writel(clt_ctx, offset, *pData); + break; + case HIF_TYPE_WRITE_BUF: + ret = mtk_wcn_hif_sdio_write_buf(clt_ctx, offset, pData, len); + break; + default: + STPSDIO_PR_ERR("unknown hif sdio type!\n"); + goto exit; + } + + if (ret) { + STPSDIO_PR_ERR("sdio read or write failed, ret:%d\n", ret); + if (ret == -ETIMEDOUT) { + ret_1 = mtk_wcn_hif_sdio_readl(clt_ctx, CCIR, &value); + STPSDIO_PR_ERR("sdio read or write timeout, ret:%d ret_1:%d, read chip id:%x\n", + ret, ret_1, value); + stp_sdio_dump_register(); + } + /* sdio CRC error read CSR */ + if (type == HIF_TYPE_READ_BUF || type == HIF_TYPE_WRITE_BUF) { + if (ret == -EIO || ret == -EILSEQ || ret == -EBUSY) { + ret_1 = mtk_wcn_hif_sdio_abort(clt_ctx); + if (ret_1) + STPSDIO_PR_ERR("sdio crc error send abort fail, ret_1:%d\n", + ret_1); + else + STPSDIO_PR_ERR("sdio crc error send abort success, ret_1:%d\n", + ret_1); + goto exit; + } + } else + retry_flag = 1; + } else { + STPSDIO_PR_LOUD("CR:0x:%x value:0x%x\n", offset, *pData); + break; + } + retry_limit--; + } + +exit: + return ret; +} + + +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_RXDBG + +/*! + * \brief /proc debug read interface and dump rx dbg information + * + * \details Dump all rx debug information to console. + * + * \retval 0 success + */ +ssize_t stp_sdio_rxdbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + UINT32 idx; + UINT32 i; + UINT32 j; + PUINT8 pbuf; + UINT32 len; + + if (*f_pos > 0) + return 0; + + for (i = 0; i < STP_SDIO_RXDBG_COUNT; ++i) { + idx = (stp_sdio_rxdbg_cnt - 1 - i) & STP_SDIO_TXDBG_COUNT_MASK; + len = stp_sdio_rxdbg_buffer[idx].bus_rxlen; + if (len == 0) { + pr_warn(DFT_TAG "idx(0x%x) 0 == len dump skip\n", + stp_sdio_rxdbg_cnt); + } + pr_warn(DFT_TAG "idx(0x%x) chisr_rxlen(%d) bus_rxlen(%d) ts(%d)\n", + stp_sdio_rxdbg_cnt, stp_sdio_rxdbg_buffer[idx].chisr_rxlen, len, + stp_sdio_rxdbg_buffer[idx].ts); + for (j = 0; j < STP_SDIO_RX_BUF_SIZE && j < len; j += 16) { + pbuf = &stp_sdio_rxdbg_buffer[idx].rx_pkt_buf[j]; + pr_warn(DFT_TAG "[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ", + pbuf[0], pbuf[1], pbuf[2], pbuf[3], pbuf[4], pbuf[5], pbuf[6], + pbuf[7]); + pr_warn(DFT_TAG "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n", + pbuf[8], pbuf[9], pbuf[10], pbuf[11], pbuf[12], pbuf[13], + pbuf[14], pbuf[15]); + msleep(20); + } + pr_warn(DFT_TAG "dump ok\n"); + } + + return 0; +} + +/*! + * \brief /proc debug write interface. do nothing. + * + * \details + * + * \retval 0 success + */ +ssize_t stp_sdio_rxdbg_write(struct file *filp, const char __user *buf, size_t count, + loff_t *f_pos) +{ + ULONG len = count; + + pr_warn(DFT_TAG "write parameter len = %lu\n\r", len); + + return len; +} + +/*! + * \brief /proc initial procedures. Initialize global debugging information. + * + * \details Setup entry for /proc debugging for rx + * + * \retval 0 success + */ +INT32 stp_sdio_rxdbg_setup(VOID) +{ + stp_sdio_rxdbg_cnt = 0; + + gStpSdioRxDbgEntry = proc_create(STP_SDIO_RXDBG_PROCNAME, 0644, NULL, &stp_sdio_rxdbg_fops); + if (gStpSdioRxDbgEntry == NULL) { + pr_warn(DFT_TAG "Unable to create /proc entry\n\r"); + return -1; + } + + return 0; +} + +/*! + * \brief /proc de-init procedures. + * + * \details remove entry for /proc debugging for rx + * + * \retval 0 success + */ +INT32 stp_sdio_rxdbg_remove(VOID) +{ + if (gStpSdioRxDbgEntry != NULL) + proc_remove(gStpSdioRxDbgEntry); + + return 0; +} +#endif + +#if STP_SDIO_DBG_SUPPORT && (STP_SDIO_TXDBG || STP_SDIO_TXPERFDBG) + +static VOID stp_sdio_txperf_dump(VOID) +{ +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXPERFDBG + UINT32 cnt; + UINT32 fifo; + UINT32 data; + UINT32 wkr; + UINT32 pkt_num; + UINT32 lmt_cnt; + + /* get debug counter snapshot */ + cnt = stp_sdio_txperf_fifo_lmt_cnt; + fifo = stp_sdio_txperf_fifo_left; + data = stp_sdio_txperf_to_send; + + wkr = stp_sdio_txperf_worker_cnt; + pkt_num = stp_sdio_txperf_txed_pkt_num; + lmt_cnt = stp_sdio_txperf_pkt_num_lmt_cnt; + + pr_warn(DFT_TAG "txwait_fifo_left(%d), txwait_to_send(%d), txwait_count(%d)\n", + fifo, data, cnt); + if (cnt) + pr_warn(DFT_TAG "avg left(%d), to_send(%d)\n", (fifo / cnt), (data / cnt)); + pr_warn(DFT_TAG "tx_worker_cnt(%d), pkt_num(%d), pkt_num_lmt_cnt(%d)\n", + wkr, pkt_num, lmt_cnt); + +#endif +} + +VOID stp_sdio_dump_info(MTK_WCN_STP_SDIO_HIF_INFO *p_info) +{ + STPSDIO_PR_INFO("stp_is_ready(%d) irq_pending(%d) tx_packet_num(%d) rx_pkt_len(%d)\n", + mtk_wcn_stp_is_ready(), p_info->irq_pending, + p_info->firmware_info.tx_packet_num, p_info->rx_pkt_len); + STPSDIO_PR_INFO("sleep_flag(%d) wakeup_flag(%d) awake_flag(%d) txwkr_flag(%d)\n", + p_info->sleep_flag, p_info->wakeup_flag, p_info->awake_flag, p_info->txwkr_flag); + STPSDIO_PR_INFO("wr_idx(%d), rd_idx(%d), full_flag(%d), tx_fifo_size(%d)\n", + atomic_read(&p_info->pkt_buf.wr_idx), atomic_read(&p_info->pkt_buf.rd_idx), + p_info->pkt_buf.full_flag, p_info->firmware_info.tx_fifo_size); +} + +VOID stp_sdio_txdbg_dump(VOID) +{ +#if STP_SDIO_TXDBG + UINT32 idx; + UINT32 i; + UINT32 j; + PUINT8 pbuf; + UINT32 len; + + for (i = 0; i < STP_SDIO_TXDBG_COUNT; ++i) { + idx = (stp_sdio_txdbg_cnt - 1 - i) & STP_SDIO_TXDBG_COUNT_MASK; + len = stp_sdio_txdbg_buffer[idx].bus_txlen; + if (len == 0) { + STPSDIO_PR_INFO("idx(%x) 0 == len dump skip\n", idx); + continue; + } + + len = len > STP_SDIO_TXDBG_MAX_SIZE ? STP_SDIO_TXDBG_MAX_SIZE : len; + STPSDIO_PR_INFO( + "stp_sdio_txdbg_buffer idx(%x) bus_txlen(0x%x, %d), time[%llu.%06lu]\n", + idx, len, len, stp_sdio_txdbg_buffer[idx].l_sec, stp_sdio_txdbg_buffer[idx].l_nsec); + for (j = 0; j < STP_SDIO_TX_ENTRY_SIZE && j < len; j += 16) { + pbuf = &stp_sdio_txdbg_buffer[idx].tx_pkt_buf[j]; + STPSDIO_PR_INFO("[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n", + pbuf[0], pbuf[1], pbuf[2], pbuf[3], pbuf[4], pbuf[5], pbuf[6], pbuf[7]); + STPSDIO_PR_INFO("[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n", + pbuf[8], pbuf[9], pbuf[10], pbuf[11], pbuf[12], pbuf[13], pbuf[14], + pbuf[15]); + msleep(20); + } + STPSDIO_PR_INFO("stp_sdio_txdbg_buffer dump ok\n"); + } +#if STP_TXDBG + for (i = 0; i < STP_SDIO_TXDBG_COUNT; ++i) { + idx = (stp_sdio_txdbg_cnt - 1 - i) & STP_SDIO_TXDBG_COUNT_MASK; + len = stp_sdio_txdbg_buffer[idx].bus_txlen; + STPSDIO_PR_INFO( + "stp_sdio_txdbg_buffer idx(%x) bus_txlen(0x%x, %d) ts(%d)\n", idx, len, len, + stp_sdio_txdbg_buffer[idx].ts); + } + STPSDIO_PR_INFO( + "Dump tx info: pkt_num(%d) fifo(%d) pkt_list.rd(0x%x, %ld) pkt_list.wr(0x%x, %ld)\n", + gp_info->firmware_info.tx_packet_num, gp_info->firmware_info.tx_fifo_size, + gp_info->tx_pkt_list.pkt_rd_cnt, + STP_SDIO_GET_PKT_AR_IDX(gp_info->tx_pkt_list.pkt_rd_cnt), + gp_info->tx_pkt_list.pkt_wr_cnt, + STP_SDIO_GET_PKT_AR_IDX(gp_info->tx_pkt_list.pkt_wr_cnt)); + + for (i = 0; i < STP_SDIO_TX_PKT_LIST_SIZE; ++i) { + idx = STP_SDIO_GET_PKT_AR_IDX(gp_info->tx_pkt_list.pkt_wr_cnt - 1 - i); + STPSDIO_PR_INFO( + "tx_pkt_list idx(0x%x, %d) size(0x%x, %d), in_ts(%d), out_ts(%d)\n", + (gp_info->tx_pkt_list.pkt_wr_cnt - 1 - i), idx, + gp_info->tx_pkt_list.pkt_size_list[idx], + gp_info->tx_pkt_list.pkt_size_list[idx], gp_info->tx_pkt_list.in_ts[idx], + gp_info->tx_pkt_list.out_ts[idx]); + } + +#if STP_SDIO_NEW_TXRING + STPSDIO_PR_INFO("\n\ndump pkt_buf.tx_buf: rd(%d) wr(%d) full(%d)\n", + atomic_read(&gp_info->pkt_buf.rd_cnt), atomic_read(&gp_info->pkt_buf.wr_cnt), + gp_info->pkt_buf.full_flag); +#else + STPSDIO_PR_INFO("\n\ndump pkt_buf.tx_buf: rdi(%d) wri(%d) full(%d)\n", + atomic_read(&gp_info->pkt_buf.rd_idx), atomic_read(&gp_info->pkt_buf.wr_idx), + gp_info->pkt_buf.full_flag); +#endif + + for (i = 0; i < STP_SDIO_TX_BUF_CNT; ++i) { +#if STP_SDIO_NEW_TXRING + idx = (atomic_read(&gp_info->pkt_buf.wr_cnt) - 1 - i) & STP_SDIO_TX_BUF_CNT_MASK; + len = gp_info->pkt_buf.tx_buf_sz[idx]; +#else + idx = (atomic_read(&gp_info->pkt_buf.wr_idx) - 1 - i + STP_SDIO_TX_BUF_CNT) % + STP_SDIO_TX_BUF_CNT; +#if KMALLOC_UPDATE + len = *(gp_info->pkt_buf.tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + 1); + len = (len << 8) | *(gp_info->pkt_buf.tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + 0); +#else + len = gp_info->pkt_buf.tx_buf[idx][1]; + len = (len << 8) | gp_info->pkt_buf.tx_buf[idx][0]; +#endif + +#endif + STPSDIO_PR_INFO("pkt_buf.tx_buf idx(%x) ts(%d) len(%d), time[%llu.%06lu]\n", + idx, gp_info->pkt_buf.tx_buf_ts[idx], len, + gp_info->pkt_buf.tx_buf_local_ts[idx], gp_info->pkt_buf.tx_buf_local_nsec[idx]); + if (len == 0) { + STPSDIO_PR_INFO("idx(%x) 0 == len dump skip\n", idx); + continue; + } + len = len > STP_SDIO_TXDBG_MAX_SIZE ? STP_SDIO_TXDBG_MAX_SIZE : len; + for (j = 0; j < STP_SDIO_TX_ENTRY_SIZE && j < len; j += 16) { +#if KMALLOC_UPDATE + pbuf = gp_info->pkt_buf.tx_buf + idx * STP_SDIO_TX_ENTRY_SIZE + j; +#else + pbuf = &gp_info->pkt_buf.tx_buf[idx][j]; +#endif + STPSDIO_PR_INFO("[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n", + pbuf[0], pbuf[1], pbuf[2], pbuf[3], pbuf[4], pbuf[5], pbuf[6], + pbuf[7]); + STPSDIO_PR_INFO("[0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x]\n", + pbuf[8], pbuf[9], pbuf[10], pbuf[11], pbuf[12], pbuf[13], pbuf[14], + pbuf[15]); + msleep(20); + } + STPSDIO_PR_INFO("pkt_buf.tx_buf dump ok\n"); + } +#endif /*end of STP_TXDBG*/ +#endif /* end of STP_SDIO_TXDBG */ +} + +/*! + * \brief /proc debug read interface and dump tx dbg information + * + * \details Dump all tx debug information to console. + * + * \retval 0 success + */ +ssize_t stp_sdio_txdbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + if (*f_pos > 0) + return 0; + + stp_sdio_txdbg_dump(); + stp_sdio_txperf_dump(); + + return 0; +} + +/*! + * \brief /proc debug write interface. do nothing. + * + * \details + * + * \retval 0 success + */ +ssize_t stp_sdio_txdbg_write(struct file *filp, const char __user *buf, size_t count, + loff_t *f_pos) +{ + ULONG len = count; + + pr_warn(DFT_TAG "write parameter len = %lu\n\r", len); + + return len; +} + +/*! + * \brief /proc debug read interface and dump tx dbg information + * + * \details Dump all tx debug information to console. + * + * \retval 0 success + */ +ssize_t stp_sdio_own_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + if (*f_pos > 0) + return 0; + + return 0; +} + +/*! + * \brief /proc debug write interface. do nothing. + * + * \details + * + * \retval 0 success + */ +ssize_t stp_sdio_own_write(struct file *filp, const char __user *buffer, size_t count, + loff_t *f_pos) +{ + ULONG len = count; + PINT8 pBuf = NULL; + PINT8 pToken = NULL; + PINT8 pDelimiter = " \t"; + INT32 x = 0; + INT8 buf[128] = { 0 }; + LONG res = 0; + + if (len >= osal_sizeof(buf)) { + STPSDIO_PR_ERR("input handling fail!\n"); + len = osal_sizeof(buf) - 1; + return -1; + } + + if (copy_from_user(buf, buffer, len)) { + STPSDIO_PR_ERR("copy_from_user error.\n"); + return -EFAULT; + } + + buf[len] = '\0'; + pBuf = buf; + pToken = osal_strsep(&pBuf, pDelimiter); + if (pToken != NULL) { + osal_strtol(pToken, 16, &res); + x = (INT32)res; + } else { + x = 0; + } + + if (x == 0) { + STPSDIO_PR_INFO("stp_sdio_own_ctrl(OWN_CLR)\n\r"); + stp_sdio_own_ctrl(OWN_CLR); + } else if (x == 2) { + STPSDIO_PR_INFO("stp_sdio_own_ctrl(OWN_SET) -->Sleep\n\r"); + stp_sdio_own_ctrl(OWN_SET); + } else if (x == 3) { + gStpSdioDbgLvl = STPSDIO_LOG_WARN; + STPSDIO_PR_WARN("set STP-SDIO LogLevel to STPSDIO_LOG_WARN\n\r"); + } else if (x == 4) { + gStpSdioDbgLvl = STPSDIO_LOG_INFO; + STPSDIO_PR_INFO("set STP-SDIO LogLevel to STPSDIO_LOG_INFO\n\r"); + } else if (x == 5) { + gStpSdioDbgLvl = STPSDIO_LOG_HINT; + STPSDIO_PR_INFO("set STP-SDIO LogLevel to STPSDIO_LOG_HINT\n\r"); + } else if (x == 6) { + gStpSdioDbgLvl = STPSDIO_LOG_DBG; + STPSDIO_PR_INFO("set STP-SDIO LogLevel to STPSDIO_LOG_DBG\n\r"); + } else if (x == 7) { + gStpSdioDbgLvl = STPSDIO_LOG_LOUD; + STPSDIO_PR_INFO("set STP-SDIO LogLevel to STPSDIO_LOG_LOUD\n\r"); + } + + return len; +} + + +/*! + * \brief /proc initial procedures. Initialize global debugging information. + * + * \details Setup entry for /proc debugging for tx + * + * \retval 0 success + */ +INT32 stp_sdio_txdbg_setup(VOID) +{ + gStpSdioTxDbgEntry = proc_create(STP_SDIO_TXDBG_PROCNAME, 0644, NULL, &stp_sdio_txdbg_fops); + if (gStpSdioTxDbgEntry == NULL) { + pr_warn(DFT_TAG "Unable to create /proc entry\n\r"); + return -1; + } + +#if STP_SDIO_TXPERFDBG + stp_sdio_txperf_worker_cnt = 0; + + stp_sdio_txperf_fifo_left = 0; + stp_sdio_txperf_to_send = 0; + stp_sdio_txperf_fifo_lmt_cnt = 0; + + stp_sdio_txperf_txed_pkt_num = 0; + stp_sdio_txperf_pkt_num_lmt_cnt = 0; +#endif + +#if STP_SDIO_TXDBG + stp_sdio_txdbg_cnt = 0; +#endif + + return 0; +} + +/*! + * \brief /proc de-init procedures. + * + * \details remove entry for /proc debugging for tx + * + * \retval 0 success + */ +INT32 stp_sdio_txdbg_remove(VOID) +{ + if (gStpSdioTxDbgEntry != NULL) + proc_remove(gStpSdioTxDbgEntry); + + return 0; +} + +#endif /* end of STP_SDIO_DBG_SUPPORT && (STP_SDIO_TXDBG || STP_SDIO_TXPERFDBG) */ + +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_OWNBACKDBG + +/*! + * \brief /proc initial procedures. Initialize global debugging information. + * + * \details Setup entry for /proc debugging for tx + * + * \retval 0 success + */ +INT32 stp_sdio_owndbg_setup(VOID) +{ + gStpSdioOwnEntry = proc_create(STP_SDIO_OWNDBG_PROCNAME, 0644, NULL, &stp_sdio_own_fops); + if (gStpSdioOwnEntry == NULL) { + pr_warn(DFT_TAG "Unable to create /proc entry\n\r"); + return -1; + } + + return 0; +} + + + +/*! + * \brief /proc de-init procedures. + * + * \details remove entry for /proc debugging for tx + * + * \retval 0 success + */ +INT32 stp_sdio_owndbg_remove(VOID) +{ + if (gStpSdioOwnEntry != NULL) + proc_remove(gStpSdioOwnEntry); + + return 0; +} +#endif + +/*! + * \brief hif_sdio init function + * + * detailed descriptions + * + * \retval + */ +static INT32 stp_sdio_init(VOID) +{ + INT32 ret; + INT32 i; + + /* 4 <1> initialize all private variables */ + stp_sdio_host_info_op(1); + g_stp_sdio_host_count = 0; + /* Init stp sdio client info */ +#if 0 /* George: chage to be a constant struct */ + g_stp_sdio_cltinfo.func_tbl = mtk_stp_sdio_id_tbl; + g_stp_sdio_cltinfo.func_tbl_size = + sizeof(mtk_stp_sdio_id_tbl) / sizeof(MTK_WCN_HIF_SDIO_FUNCINFO) - 1; + g_stp_sdio_cltinfo.hif_clt_irq = stp_sdio_irq; + g_stp_sdio_cltinfo.hif_clt_probe = stp_sdio_probe; + g_stp_sdio_cltinfo.hif_clt_remove = stp_sdio_remove; +#endif + + STPSDIO_PR_DBG("cltinfo func table size:%d\n", g_stp_sdio_cltinfo.func_tbl_size); + for (i = 0; i < g_stp_sdio_cltinfo.func_tbl_size; i++) { + STPSDIO_PR_DBG("manf_id:0x%x, card_id:0x%x, func_num:%d, blk_size:%d\n", + mtk_stp_sdio_id_tbl[i].manf_id, mtk_stp_sdio_id_tbl[i].card_id, + mtk_stp_sdio_id_tbl[i].func_num, mtk_stp_sdio_id_tbl[i].blk_sz); + } + + /* 4 <2> register supported functions from sdio id table to hif sdio driver */ + ret = mtk_wcn_hif_sdio_client_reg(&g_stp_sdio_cltinfo); + if (ret) + STPSDIO_PR_ERR("mtk_wcn_hif_sdio_client_reg fail(%d)!\n", ret); + + ret = mtk_wcn_stp_wmt_sdio_op_reg(stp_sdio_own_ctrl); + if (ret) + STPSDIO_PR_ERR + ("mtk_wcn_stp_wmt_sdio_op_reg(mtk_wcn_stp_sdio_own_ctrl) fail(%d)!\n", ret); +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT + mtk_wcn_wmt_sdio_deep_sleep_flag_cb_reg(stp_sdio_deep_sleep_flag_set); +#endif + mtk_wcn_wmt_sdio_rw_cb_reg(stp_sdio_reg_rw); + +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_RXDBG + stp_sdio_rxdbg_setup(); +#endif + +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG + stp_sdio_txdbg_setup(); +#endif + +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_OWNBACKDBG + stp_sdio_owndbg_setup(); +#endif + + STPSDIO_PR_DBG + ("blk_size(%ld), tx_buf_cnt(%ld), fifo tx(%ld) rx(%ld), buf tx(%ld) rx(%ld)\n", + STP_SDIO_BLK_SIZE, STP_SDIO_TX_BUF_CNT, STP_SDIO_TX_FIFO_SIZE, STP_SDIO_RX_FIFO_SIZE, + STP_SDIO_TX_ENTRY_SIZE, STP_SDIO_TX_ENTRY_SIZE); + + return ret; +} + +INT32 stp_sdio_reg_rw(INT32 func_num, INT32 direction, UINT32 offset, UINT32 value) +{ + + if (func_num == 0) + return stp_sdio_func0_reg_rw(direction, offset, value); + else if (func_num == 2) + return stp_sdio_func_reg_rw(direction, offset, value); + + STPSDIO_PR_ERR("func_num(%d) is not support!\n", func_num); + return -1; +} + +INT32 stp_sdio_func0_reg_rw(INT32 direction, UINT32 offset, UINT32 value) +{ + INT32 ret = -1; + UINT8 val = 0x00; + + val = (UINT8) value; + switch (direction) { + case 0: + ret = mtk_wcn_hif_sdio_f0_readb(g_stp_sdio_host_info.sdio_cltctx, offset, &val); + STPSDIO_PR_INFO("read func0 CR(0x%x), value(0x%x)\n", offset, val); + break; + case 1: + ret = mtk_wcn_hif_sdio_f0_writeb(g_stp_sdio_host_info.sdio_cltctx, offset, val); + STPSDIO_PR_INFO("write func0 CR(0x%x), value(0x%x)\n", offset, val); + break; + default: + break; + } + return ret; + +} + +INT32 stp_sdio_func_reg_rw(INT32 direction, UINT32 offset, UINT32 value) +{ + INT32 ret = -1; + UINT32 val = 0x00; + + val = (UINT32) value; + switch (direction) { + case 0: + ret = mtk_wcn_hif_sdio_readl(g_stp_sdio_host_info.sdio_cltctx, offset, &val); + STPSDIO_PR_INFO("read sdio CR(0x%x), value(0x%x)\n", offset, val); + break; + case 1: + ret = mtk_wcn_hif_sdio_writel(g_stp_sdio_host_info.sdio_cltctx, offset, val); + STPSDIO_PR_INFO("write sdio CR(0x%x), value(0x%x)\n", offset, val); + break; + default: + break; + } + return ret; +} + +INT32 stp_sdio_wake_up_ctrl(MTK_WCN_HIF_SDIO_CLTCTX ctx) +{ + INT32 ret; + + ret = hif_sdio_wake_up_ctrl(ctx); + if (ret == -11) { + STPSDIO_PR_ERR("wake up fail, polling [GPIO_CHIP_DEEP_SLEEP_PIN] low over 30ms\n"); + ret = stp_sdio_issue_fake_coredump + ("<ASSERT> wake up fail, polling [GPIO_CHIP_DEEP_SLEEP_PIN] low over 30ms # -"); + } else if (ret == -2 || ret == -3) + STPSDIO_PR_ERR("get wake up, sleep pin error\n"); + + return ret; +} + +VOID stp_sdio_dump_register(VOID) +{ + UINT32 count = 3; + MTK_WCN_HIF_SDIO_CLTCTX clt_ctx; + UINT32 val = 0; + UINT32 delay_us = 10000; + + clt_ctx = gp_info->sdio_cltctx; + while (count) { + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CCIR, &val, 0); + STPSDIO_PR_ERR("******CCIR == 0x%x*****\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHLPCR, &val, 0); + STPSDIO_PR_ERR("******CHLPCR == 0x%x*****\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CSDIOCSR, &val, 0); + STPSDIO_PR_ERR("******CSDIOCSR == 0x%x*****\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHCR, &val, 0); + STPSDIO_PR_ERR("******CHCR == 0x%x*****\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHISR, &val, 0); + STPSDIO_PR_ERR("******CHISR == 0x%x*****\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CHIER, &val, 0); + STPSDIO_PR_ERR("******CHIER == 0x%x*****\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CTFSR, &val, 0); + STPSDIO_PR_ERR("******CTFSR == 0x%x*****\n", val); + stp_sdio_rw_retry(HIF_TYPE_READL, STP_SDIO_RETRY_LIMIT, clt_ctx, CRPLR, &val, 0); + STPSDIO_PR_ERR("******CRPLR == 0x%x*****\n", val); + count--; + osal_usleep_range(delay_us, 2 * delay_us); + } + +} + +/*! + * \brief hif_sdio init function + * + * detailed descriptions + * + * \retval + */ +static VOID stp_sdio_exit(VOID) +{ +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_TXDBG + stp_sdio_txdbg_remove(); +#endif + +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_RXDBG + stp_sdio_rxdbg_remove(); +#endif + +#if STP_SDIO_DBG_SUPPORT && STP_SDIO_OWNBACKDBG + stp_sdio_owndbg_remove(); +#endif + + /* 4 <0> unregister if_tx() function */ + mtk_wcn_stp_register_if_tx(STP_SDIO_IF_TX, 0x0); + + /* 4 <1> for all functions that have not been unregistered */ + /* 4 <1.1> unregister stp sdio func of the host */ + mtk_wcn_hif_sdio_client_unreg(&g_stp_sdio_cltinfo); + + /* 4 <1.2> stop Tx tasklet/Rx work queue of the host */ + //flush_scheduled_work(); + flush_work(&gp_info->rx_work); + flush_work(&gp_info->tx_work); + STPSDIO_PR_DBG("flush scheduled work end\n"); + + /* 4 <1.3> return ownership to firmware of the host */ + /* TODO: check set which register ! */ + + /* 4 <1.4> clear the host struct list and free the memory allocation of the host */ + g_stp_sdio_host_count = 0; + stp_sdio_host_info_op(0); + /* 4 <1.5> Notice: while rmmod client driver, the stp_sdio_remove() */ + /* will not be called after stp_sdio_exit() ! */ +} + +INT32 mtk_wcn_stp_sdio_drv_init(VOID) +{ + return stp_sdio_init(); + +} +EXPORT_SYMBOL(mtk_wcn_stp_sdio_drv_init); + +VOID mtk_wcn_stp_sdio_drv_exit(VOID) +{ + return stp_sdio_exit(); +} +EXPORT_SYMBOL(mtk_wcn_stp_sdio_drv_exit); diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_uart.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_uart.c new file mode 100644 index 00000000000000..e0b326677f7b13 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/stp_uart.c @@ -0,0 +1,851 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include <linux/version.h> +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/interrupt.h> +#include <linux/ptrace.h> +#include <linux/poll.h> + +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/signal.h> +#include <linux/ioctl.h> +#include <linux/skbuff.h> + +#include <linux/spinlock.h> + +#include <linux/time.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/kfifo.h> + +#include "stp_exp.h" + +#define N_MTKSTP (15 + 1) /* refer to linux tty.h use N_HCI. */ + +#define HCIUARTSETPROTO _IOW('U', 200, int) + +//#define MAX(a, b) ((a) > (b) ? (a) : (b)) +//#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define PFX "[UART] " +#define UART_LOG_LOUD 4 +#define UART_LOG_DBG 3 +#define UART_LOG_INFO 2 +#define UART_LOG_WARN 1 +#define UART_LOG_ERR 0 + +#define MAX_PACKET_ALLOWED 2000 + + +static INT32 gDbgLevel = UART_LOG_INFO; + +#define UART_PR_DBG(fmt, arg...) \ +do { if (gDbgLevel >= UART_LOG_DBG) \ + pr_info(PFX "%s: " fmt, __func__, ##arg); \ +} while (0) +#define UART_PR_INFO(fmt, arg...) \ +do { if (gDbgLevel >= UART_LOG_INFO) \ + pr_info(PFX "%s: " fmt, __func__, ##arg); \ +} while (0) +#define UART_PR_WARN(fmt, arg...) \ +do { if (gDbgLevel >= UART_LOG_WARN) \ + pr_warn(PFX "%s: " fmt, __func__, ##arg); \ +} while (0) +#define UART_PR_ERR(fmt, arg...) \ +do { if (gDbgLevel >= UART_LOG_ERR) \ + pr_err(PFX "%s: " fmt, __func__, ##arg); \ +} while (0) + + +#include <linux/kfifo.h> +#define LDISC_RX_TASKLET 0 +#define LDISC_RX_WORK 1 + +#if WMT_UART_RX_MODE_WORK +#define LDISC_RX LDISC_RX_WORK +#else +#define LDISC_RX LDISC_RX_TASKLET +#endif + +#if (LDISC_RX == LDISC_RX_TASKLET) +#define LDISC_RX_FIFO_SIZE (0x20000) /*8192 bytes */ +struct kfifo *g_stp_uart_rx_fifo; +spinlock_t g_stp_uart_rx_fifo_spinlock; +struct tasklet_struct g_stp_uart_rx_fifo_tasklet; +#define RX_BUFFER_LEN 1024 +UINT8 g_rx_data[RX_BUFFER_LEN]; + +/* static DEFINE_RWLOCK(g_stp_uart_rx_handling_lock); */ +#elif (LDISC_RX == LDISC_RX_WORK) + +#define LDISC_RX_FIFO_SIZE (0x4000) /* 16K bytes shall be enough...... */ +#define LDISC_RX_BUF_SIZE (2048) /* 2K bytes in one shot is enough */ + +PUINT8 g_stp_uart_rx_buf; /* for stp rx data parsing */ +struct kfifo *g_stp_uart_rx_fifo; /* for uart tty data receiving */ +spinlock_t g_stp_uart_rx_fifo_spinlock; /* fifo spinlock */ +struct workqueue_struct *g_stp_uart_rx_wq; /* rx work queue (do not use system_wq) */ +struct work_struct *g_stp_uart_rx_work; /* rx work */ + +#endif + +struct tty_struct *stp_tty; + +UINT8 tx_buf[MTKSTP_BUFFER_SIZE] = { 0x0 }; + +INT32 rd_idx; +INT32 wr_idx; +/* struct semaphore buf_mtx; */ +spinlock_t buf_lock; +static INT32 mtk_wcn_uart_tx(const PUINT8 data, const UINT32 size, PUINT32 written_size); + + +static _osal_inline_ INT32 stp_uart_tx_wakeup(struct tty_struct *tty) +{ + INT32 len = 0; + INT32 written = 0; + INT32 written_count = 0; + static INT32 i; + /* UINT32 flags; */ + /* get data from ring buffer */ +/* down(&buf_mtx); */ +/* // spin_lock_irqsave(&buf_lock, flags); */ + +#if 0 + if ((i > 1000) && (i % 5) == 0) { + UART_PR_INFO("i=(%d), ****** drop data from uart******\n", i); + i++; + return 0; + } + UART_PR_INFO("i=(%d)at stp uart **\n", i); +#endif + + len = (wr_idx >= rd_idx) ? (wr_idx - rd_idx) : (MTKSTP_BUFFER_SIZE - rd_idx); + if (len > 0 && len < MAX_PACKET_ALLOWED) { + i++; + /* + * ops->write is called by the kernel to write a series of + * characters to the tty device. The characters may come from + * user space or kernel space. This routine will return the + * number of characters actually accepted for writing. + */ + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + written = tty->ops->write(tty, &tx_buf[rd_idx], len); + if (written != len) { + UART_PR_ERR + ("Error(i-%d):[pid(%d)(%s)]tty-ops->write FAIL!len(%d)wr(%d)wr_i(%d)rd_i(%d)\n\r", + i, current->pid, current->comm, len, written, wr_idx, rd_idx); + return -1; + } + written_count = written; + /* pr_debug("len = %d, written = %d\n", len, written); */ + rd_idx = ((rd_idx + written) % MTKSTP_BUFFER_SIZE); + /* all data is accepted by UART driver, check again in case roll over */ + len = (wr_idx >= rd_idx) ? (wr_idx - rd_idx) : (MTKSTP_BUFFER_SIZE - rd_idx); + if (len > 0 && len < MAX_PACKET_ALLOWED) { + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + written = tty->ops->write(tty, &tx_buf[rd_idx], len); + if (written != len) { + UART_PR_ERR("Error(i-%d):[pid(%d)(%s)]len(%d)wr(%d)wr_i(%d)rd_i(%d)\n\r", + i, current->pid, current->comm, len, written, wr_idx, rd_idx); + return -1; + } + rd_idx = ((rd_idx + written) % MTKSTP_BUFFER_SIZE); + written_count += written; + } else if (len < 0 || len >= MAX_PACKET_ALLOWED) { + UART_PR_ERR("Warnning(i-%d):[pid(%d)(%s)]length verfication(external)\n", + i, current->pid, current->comm); + UART_PR_ERR("warnning,len(%d), wr_idx(%d), rd_idx(%d)!\n\r", len, wr_idx, rd_idx); + return -1; + } + } else { + UART_PR_ERR("Warnning(i-%d):[pid(%d)(%s)]length verfication(external)\n", + i, current->pid, current->comm); + UART_PR_ERR("warnning,len(%d), wr_idx(%d), rd_idx(%d)!\n\r", len, wr_idx, rd_idx); + return -1; + } + /* up(&buf_mtx); */ +/* // spin_unlock_irqrestore(&buf_lock, flags); */ + return written_count; +} + +/* ------ LDISC part ------ */ +/* stp_uart_tty_open + * + * Called when line discipline changed to HCI_UART. + * + * Arguments: + * tty pointer to tty info structure + * Return Value: + * 0 if success, otherwise error code + */ +static INT32 stp_uart_tty_open(struct tty_struct *tty) +{ + UART_PR_DBG("stp_uart_tty_opentty: %p\n", tty); + + tty->receive_room = 65536; + tty->port->flags |= ASYNC_LOW_LATENCY; + + /* Flush any pending characters in the driver and line discipline. */ + + /* FIXME: why is this needed. Note don't use ldisc_ref here as the */ + /* open path is before the ldisc is referencable */ + + /* definition changed!! */ + if (tty->ldisc->ops->flush_buffer) + tty->ldisc->ops->flush_buffer(tty); + + tty_driver_flush_buffer(tty); + +/* init_MUTEX(&buf_mtx); */ +/* // spin_lock_init(&buf_lock); */ + + rd_idx = wr_idx = 0; + stp_tty = tty; + mtk_wcn_stp_register_if_tx(STP_UART_IF_TX, (MTK_WCN_STP_IF_TX) mtk_wcn_uart_tx); + + return 0; +} + +/* stp_uart_tty_close() + * + * Called when the line discipline is changed to something + * else, the tty is closed, or the tty detects a hangup. + */ +static VOID stp_uart_tty_close(struct tty_struct *tty) +{ + UART_PR_DBG("stp_uart_tty_close(): tty %p\n", tty); + mtk_wcn_stp_register_if_tx(STP_UART_IF_TX, NULL); +} + +/* stp_uart_tty_wakeup() + * + * Callback for transmit wakeup. Called when low level + * device driver can accept more send data. + * + * Arguments: tty pointer to associated tty instance data + * Return Value: None + */ +static VOID stp_uart_tty_wakeup(struct tty_struct *tty) +{ + /* pr_debug("%s: start !!\n", __FUNCTION__); */ + + /* clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); */ + + /* stp_uart_tx_wakeup(tty); */ +} + +/* stp_uart_tty_receive() + * + * Called by tty low level driver when receive data is + * available. + * + * Arguments: tty pointer to tty isntance data + * data pointer to received data + * flags pointer to flags for data + * count count of received data in bytes + * + * Return Value: None + */ +#if (LDISC_RX == LDISC_RX_TASKLET) + +static INT32 stp_uart_fifo_init(VOID) +{ + INT32 err = 0; + /*add rx fifo */ + g_stp_uart_rx_fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC); + if (g_stp_uart_rx_fifo == NULL) { + err = -2; + UART_PR_ERR("kzalloc for g_stp_uart_rx_fifo failed (kernel version > 2.6.35)\n"); + return err; + } + err = kfifo_alloc(g_stp_uart_rx_fifo, LDISC_RX_FIFO_SIZE, GFP_ATOMIC); + if (err != 0) { + UART_PR_ERR("kfifo_alloc failed, errno(%d)(kernel version > 2.6.35)\n", err); + kfree(g_stp_uart_rx_fifo); + g_stp_uart_rx_fifo = NULL; + err = -3; + return err; + } + if (err == 0) { + if (g_stp_uart_rx_fifo != NULL) { + kfifo_reset(g_stp_uart_rx_fifo); + UART_PR_DBG("stp_uart_fifo_init() success.\n"); + } else { + err = -4; + UART_PR_ERR + ("abnormal case, err = 0 but g_stp_uart_rx_fifo = NULL, set err to %d\n", + err); + } + } else + UART_PR_ERR("stp_uart_fifo_init() failed.\n"); + + return err; +} + +static INT32 stp_uart_fifo_deinit(VOID) +{ + if (g_stp_uart_rx_fifo != NULL) { + kfifo_free(g_stp_uart_rx_fifo); + kfree(g_stp_uart_rx_fifo); + g_stp_uart_rx_fifo = NULL; + } + return 0; +} + +static VOID stp_uart_rx_handling(ULONG func_data) +{ + UINT32 how_much_get = 0; + UINT32 how_much_to_get = 0; + UINT32 flag = 0; + +/* read_lock(&g_stp_uart_rx_handling_lock); */ + how_much_to_get = kfifo_len(g_stp_uart_rx_fifo); + + if (how_much_to_get >= RX_BUFFER_LEN) { + flag = 1; + UART_PR_INFO("fifolen(%d)\n", how_much_to_get); + } + + do { + how_much_get = kfifo_out(g_stp_uart_rx_fifo, g_rx_data, RX_BUFFER_LEN); + /* UART_PR_INFO ("fifoget(%d)\n", how_much_get); */ + mtk_wcn_stp_parser_data((UINT8 *) g_rx_data, how_much_get); + how_much_to_get = kfifo_len(g_stp_uart_rx_fifo); + } while (how_much_to_get > 0); + +/* read_unlock(&g_stp_uart_rx_handling_lock); */ + if (flag == 1) + UART_PR_INFO("finish, fifolen(%d)\n", kfifo_len(g_stp_uart_rx_fifo)); +} + +static VOID stp_uart_tty_receive(struct tty_struct *tty, const unsigned char *data, PINT8 flags, INT32 count) +{ + UINT32 fifo_avail_len = LDISC_RX_FIFO_SIZE - kfifo_len(g_stp_uart_rx_fifo); + UINT32 how_much_put = 0; +#if 0 + { + struct timeval now; + + do_gettimeofday(&now); + pr_warn("[+STP][ ][R] %4d --> sec = %lu, --> usec --> %lu\n", + count, now.tv_sec, now.tv_usec); + } +#endif +/* write_lock(&g_stp_uart_rx_handling_lock); */ + if (count > 2000) { + /*this is abnormal */ + UART_PR_ERR("abnormal: buffer count = %d\n", count); + } + /*How much empty seat? */ + if (fifo_avail_len > 0) { + /* UART_PR_INFO ("fifo left(%d), count(%d)\n", fifo_avail_len, count); */ + how_much_put = kfifo_in(g_stp_uart_rx_fifo, (PUINT8) data, count); + + /*schedule it! */ + tasklet_schedule(&g_stp_uart_rx_fifo_tasklet); + } else { + UART_PR_ERR("stp_uart_tty_receive rxfifo is full!!\n"); + } + +#if 0 + { + struct timeval now; + + do_gettimeofday(&now); + pr_warn("[-STP][ ][R] %4d --> sec = %lu, --> usec --> %lu\n", + count, now.tv_sec, now.tv_usec); + } +#endif + +/* write_unlock(&g_stp_uart_rx_handling_lock); */ + +} +#elif (LDISC_RX == LDISC_RX_WORK) +static INT32 stp_uart_fifo_init(VOID) +{ + INT32 err = 0; + + g_stp_uart_rx_buf = vzalloc(LDISC_RX_BUF_SIZE); + if (!g_stp_uart_rx_buf) { + UART_PR_ERR("kfifo_alloc failed (kernel version >= 2.6.37)\n"); + err = -4; + goto fifo_init_end; + } + + UART_PR_INFO("g_stp_uart_rx_buf alloc ok(0x%p, %d)\n", + g_stp_uart_rx_buf, LDISC_RX_BUF_SIZE); + + /*add rx fifo */ + /* allocate struct kfifo first */ + g_stp_uart_rx_fifo = kzalloc(sizeof(struct kfifo), GFP_KERNEL); + if (g_stp_uart_rx_fifo == NULL) { + err = -2; + UART_PR_ERR("kzalloc struct kfifo failed (kernel version > 2.6.33)\n"); + goto fifo_init_end; + } + + /* allocate kfifo data buffer then */ + err = kfifo_alloc(g_stp_uart_rx_fifo, LDISC_RX_FIFO_SIZE, GFP_KERNEL); + if (err != 0) { + UART_PR_ERR("kfifo_alloc failed, err(%d)(kernel version > 2.6.33)\n", err); + kfree(g_stp_uart_rx_fifo); + g_stp_uart_rx_fifo = NULL; + err = -3; + goto fifo_init_end; + } + UART_PR_INFO("g_stp_uart_rx_fifo alloc ok\n"); + +fifo_init_end: + + if (err == 0) { + /* kfifo init ok */ + kfifo_reset(g_stp_uart_rx_fifo); + UART_PR_DBG("g_stp_uart_rx_fifo init success\n"); + } else { + UART_PR_ERR("stp_uart_fifo_init() fail(%d)\n", err); + if (g_stp_uart_rx_buf) { + UART_PR_DBG("free g_stp_uart_rx_buf\n"); + vfree(g_stp_uart_rx_buf); + g_stp_uart_rx_buf = NULL; + } + } + + return err; +} + +static INT32 stp_uart_fifo_deinit(VOID) +{ + if (g_stp_uart_rx_buf) { + vfree(g_stp_uart_rx_buf); + g_stp_uart_rx_buf = NULL; + } + + if (g_stp_uart_rx_fifo != NULL) { + kfifo_free(g_stp_uart_rx_fifo); + kfree(g_stp_uart_rx_fifo); + g_stp_uart_rx_fifo = NULL; + } + return 0; +} + +static VOID stp_uart_rx_worker(struct work_struct *work) +{ + UINT32 read; + + if (unlikely(!g_stp_uart_rx_fifo)) { + UART_PR_ERR("NULL rx fifo!\n"); + return; + } + if (unlikely(!g_stp_uart_rx_buf)) { + UART_PR_ERR("NULL rx buf!\n"); + return; + } + + + /* run until fifo becomes empty */ + while (!kfifo_is_empty(g_stp_uart_rx_fifo)) { + read = kfifo_out(g_stp_uart_rx_fifo, g_stp_uart_rx_buf, LDISC_RX_BUF_SIZE); + /* pr_debug("rx_work:%d\n\r",read); */ + if (likely(read)) { + /* UART_LOUD_FUNC("->%d\n", read); */ + mtk_wcn_stp_parser_data((UINT8 *) g_stp_uart_rx_buf, read); + /* UART_LOUD_FUNC("<-\n", read); */ + } + } +} + +/* stp_uart_tty_receive() + * + * Called by tty low level driver when receive data is + * available. + * + * Arguments: tty pointer to tty isntance data + * data pointer to received data + * flags pointer to flags for data + * count count of received data in bytes + * + * Return Value: None + */ +static VOID stp_uart_tty_receive(struct tty_struct *tty, const PUINT8 data, PINT8 flags, INT32 count) +{ + UINT32 written; + + /* UART_LOUD_FUNC("URX:%d\n", count); */ + if (unlikely(count > 2000)) + UART_PR_WARN("abnormal: buffer count = %d\n", count); + + if (unlikely(!g_stp_uart_rx_fifo || !g_stp_uart_rx_work || !g_stp_uart_rx_wq)) { + UART_PR_ERR + ("abnormal g_stp_uart_rx_fifo(0x%p),g_stp_uart_rx_work(0x%p),g_stp_uart_rx_wq(0x%p)\n", + g_stp_uart_rx_fifo, g_stp_uart_rx_work, g_stp_uart_rx_wq); + return; + } + + /* need to check available buffer size? skip! */ + + /* need to lock fifo? skip for single writer single reader! */ + + written = kfifo_in(g_stp_uart_rx_fifo, (PUINT8) data, count); + /* pr_debug("uart_rx:%d,wr:%d\n\r",count,written); */ + + queue_work(g_stp_uart_rx_wq, g_stp_uart_rx_work); + + if (unlikely(written != count)) + UART_PR_ERR("c(%d),w(%d) bytes dropped\n", count, written); +} + +#else + +static VOID stp_uart_tty_receive(struct tty_struct *tty, const PUINT8 data, PINT8 flags, INT32 count) +{ + +#if 0 + mtk_wcn_stp_debug_gpio_assert(IDX_STP_RX_PROC, DBG_TIE_LOW); +#endif + + if (count > 2000) { + /*this is abnormal */ + UART_PR_ERR("stp_uart_tty_receive buffer count = %d\n", count); + } +#if 0 + { + struct timeval now; + + do_gettimeofday(&now); + } +#endif + + + /*There are multi-context to access here? Need to spinlock? */ + /*Only one context: flush_to_ldisc in tty_buffer.c */ + mtk_wcn_stp_parser_data((UINT8 *) data, (UINT32) count); + +#if 0 + mtk_wcn_stp_debug_gpio_assert(IDX_STP_RX_PROC, DBG_TIE_HIGH); +#endif + + tty_unthrottle(tty); + +#if 0 + { + struct timeval now; + + do_gettimeofday(&now); + } +#endif +} +#endif + +/* stp_uart_tty_ioctl() + * + * Process IOCTL system call for the tty device. + * + * Arguments: + * + * tty pointer to tty instance data + * file pointer to open file object for device + * cmd IOCTL command code + * arg argument for IOCTL call (cmd dependent) + * + * Return Value: Command dependent + */ +static INT32 stp_uart_tty_ioctl(struct tty_struct *tty, struct file *file, UINT32 cmd, ULONG arg) +{ + INT32 err = 0; + + switch (cmd) { + case HCIUARTSETPROTO: + UART_PR_DBG("<!!> Set low_latency to TRUE <!!>\n"); + tty->port->flags |= ASYNC_LOW_LATENCY; + + break; + default: + UART_PR_DBG("<!!> n_tty_ioctl_helper <!!>\n"); + err = n_tty_ioctl_helper(tty, cmd, arg); + break; + }; + + return err; +} + +/* + * We don't provide read/write/poll interface for user space. + */ +static ssize_t stp_uart_tty_read(struct tty_struct *tty, struct file *file, + unsigned char __user *buf, size_t nr) +{ + return 0; +} + +static ssize_t stp_uart_tty_write(struct tty_struct *tty, struct file *file, + const unsigned char *data, size_t count) +{ + return 0; +} + +static UINT32 stp_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) +{ + return 0; +} + +INT32 mtk_wcn_uart_tx(const PUINT8 data, const UINT32 size, PUINT32 written_size) +{ + INT32 room; + /* int idx = 0; */ + /* unsigned long flags; */ + INT32 ret = 0; + UINT32 len; + /* static int tmp=0; */ + static INT32 i; + + if (stp_tty == NULL) + return -1; + + (*written_size) = 0; + /* put data into ring buffer */ + /* down(&buf_mtx); */ + + + /* + * [PatchNeed] + * spin_lock_irqsave is redundant + */ + /* spin_lock_irqsave(&buf_lock, flags); */ + + room = + (wr_idx >= + rd_idx) ? (MTKSTP_BUFFER_SIZE - (wr_idx - rd_idx) - 1) : (rd_idx - wr_idx - 1); + UART_PR_DBG("r(%d)s(%d)wr_i(%d)rd_i(%d)\n\r", room, size, wr_idx, rd_idx); + /* + * [PatchNeed] + * Block copy instead of byte copying + */ + if (data == NULL) { + UART_PR_ERR("pid(%d)(%s): data is NULL\n", current->pid, current->comm); + (*written_size) = 0; + return -2; + } +#if 1 + if (unlikely(size > room)) { + UART_PR_ERR + ("pid(%d)(%s)room is not available, size needed(%d), wr_idx(%d), rd_idx(%d), room left(%d)\n", + current->pid, current->comm, size, wr_idx, rd_idx, room); + (*written_size) = 0; + return -3; + } + /* wr_idx : the position next to write */ + /* rd_idx : the position next to read */ + len = min(size, MTKSTP_BUFFER_SIZE - (UINT32) wr_idx); + memcpy(&tx_buf[wr_idx], &data[0], len); + memcpy(&tx_buf[0], &data[len], size - len); + wr_idx = (wr_idx + size) % MTKSTP_BUFFER_SIZE; + UART_PR_DBG("r(%d)s(%d)wr_i(%d)rd_i(%d)\n\r", room, size, wr_idx, rd_idx); + i++; + if (size == 0) { + (*written_size) = 0; + } else if (size < MAX_PACKET_ALLOWED) { + /* only size ~(0, 2000) is allowed */ + ret = stp_uart_tx_wakeup(stp_tty); + if (ret < 0) { + /* reset read and write index of tx_buffer, is there any risk? */ + wr_idx = rd_idx = 0; + *written_size = 0; + } else + *written_size = ret; + } else { + /* we filter all packet with size > 2000 */ + UART_PR_ERR("Warnning(i-%d):[pid(%d)(%s)]len(%d)size(%d)wr_i(%d)rd_i(%d)\n\r", + i, current->pid, current->comm, len, size, wr_idx, rd_idx); + (*written_size) = 0; + } +#endif + + +#if 0 + while ((room > 0) && (size > 0)) { + tx_buf[wr_idx] = data[idx]; + wr_idx = ((wr_idx + 1) % MTKSTP_BUFFER_SIZE); + idx++; + room--; + size--; + (*written_size)++; + } +#endif + /* up(&buf_mtx); */ + /* + * [PatchNeed] + * spin_lock_irqsave is redundant + */ + /* spin_lock_irqsave(&buf_lock, flags); */ + + /*[PatchNeed]To add a tasklet to shedule Uart Tx */ + + return 0; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wincompatible-pointer-types" +static INT32 mtk_wcn_stp_uart_init(VOID) +{ + static struct tty_ldisc_ops stp_uart_ldisc; + INT32 err; + INT32 fifo_init_done = 0; + + UART_PR_DBG("mtk_wcn_stp_uart_init(): MTK STP UART driver\n"); + +#if (LDISC_RX == LDISC_RX_TASKLET) + err = stp_uart_fifo_init(); + if (err != 0) + goto init_err; + + fifo_init_done = 1; + /*init rx tasklet */ + tasklet_init(&g_stp_uart_rx_fifo_tasklet, stp_uart_rx_handling, (ULONG)0); + +#elif (LDISC_RX == LDISC_RX_WORK) + err = stp_uart_fifo_init(); + if (err != 0) { + UART_PR_ERR("stp_uart_fifo_init(WORK) error(%d)\n", err); + err = -EFAULT; + goto init_err; + } + fifo_init_done = 1; + + g_stp_uart_rx_work = vmalloc(sizeof(struct work_struct)); + if (!g_stp_uart_rx_work) { + UART_PR_ERR("vmalloc work_struct(%lu) fail\n", sizeof(struct work_struct)); + err = -ENOMEM; + goto init_err; + } + + g_stp_uart_rx_wq = create_singlethread_workqueue("mtk_urxd"); + if (!g_stp_uart_rx_wq) { + UART_PR_ERR("create_singlethread_workqueue fail\n"); + err = -ENOMEM; + goto init_err; + } + + /* init rx work */ + INIT_WORK(g_stp_uart_rx_work, stp_uart_rx_worker); + +#endif + + /* Register the tty discipline */ + memset(&stp_uart_ldisc, 0, sizeof(stp_uart_ldisc)); + //stp_uart_ldisc.magic = TTY_LDISC_MAGIC; + stp_uart_ldisc.name = "n_mtkstp"; + stp_uart_ldisc.open = stp_uart_tty_open; + stp_uart_ldisc.close = stp_uart_tty_close; + stp_uart_ldisc.read = stp_uart_tty_read; + stp_uart_ldisc.write = stp_uart_tty_write; + stp_uart_ldisc.ioctl = stp_uart_tty_ioctl; + stp_uart_ldisc.poll = stp_uart_tty_poll; + stp_uart_ldisc.receive_buf = stp_uart_tty_receive; + stp_uart_ldisc.write_wakeup = stp_uart_tty_wakeup; + stp_uart_ldisc.owner = THIS_MODULE; + + err = tty_register_ldisc(&stp_uart_ldisc); + if (err) { + UART_PR_ERR("MTK STP line discipline registration failed. (%d)\n", err); + goto init_err; + } + + err = tty_set_ldisc(stp_tty, N_MTKSTP); + if (err) { + UART_PR_ERR("MTK STP line discipline set failed. (%d)\n", err); + goto init_err; + } + + /* + * mtk_wcn_stp_register_if_tx( mtk_wcn_uart_tx); + */ + + return 0; + +init_err: + +#if (LDISC_RX == LDISC_RX_TASKLET) + /* nothing */ + if (fifo_init_done) + stp_uart_fifo_deinit(); +#elif (LDISC_RX == LDISC_RX_WORK) + if (g_stp_uart_rx_wq) { + destroy_workqueue(g_stp_uart_rx_wq); + g_stp_uart_rx_wq = NULL; + } + if (g_stp_uart_rx_work) + vfree(g_stp_uart_rx_work); + + if (fifo_init_done) + stp_uart_fifo_deinit(); +#endif + UART_PR_ERR("init fail, return(%d)\n", err); + + return err; + +} + +static VOID mtk_wcn_stp_uart_exit(VOID) +{ + //INT32 err; + + mtk_wcn_stp_register_if_tx(STP_UART_IF_TX, NULL); /* unregister if_tx function */ + + /* Release tty registration of line discipline */ + tty_unregister_ldisc(stp_tty->ldisc); + /*if (err) + UART_PR_ERR("Can't unregister MTK STP line discipline (%d)\n", err);*/ + +#if (LDISC_RX == LDISC_RX_TASKLET) + tasklet_kill(&g_stp_uart_rx_fifo_tasklet); + stp_uart_fifo_deinit(); +#elif (LDISC_RX == LDISC_RX_WORK) + if (g_stp_uart_rx_work) + cancel_work_sync(g_stp_uart_rx_work); + + if (g_stp_uart_rx_wq) { + destroy_workqueue(g_stp_uart_rx_wq); + g_stp_uart_rx_wq = NULL; + } + if (g_stp_uart_rx_work) { + vfree(g_stp_uart_rx_work); + g_stp_uart_rx_work = NULL; + } + stp_uart_fifo_deinit(); + +#endif +} +#pragma GCC diagnostic pop + +INT32 mtk_wcn_stp_uart_drv_init(VOID) +{ + return mtk_wcn_stp_uart_init(); + +} +EXPORT_SYMBOL(mtk_wcn_stp_uart_drv_init); + +VOID mtk_wcn_stp_uart_drv_exit(VOID) +{ + return mtk_wcn_stp_uart_exit(); +} +EXPORT_SYMBOL(mtk_wcn_stp_uart_drv_exit); diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/wmt_dbg.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/wmt_dbg.c new file mode 100644 index 00000000000000..ad20fe760cefed --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/wmt_dbg.c @@ -0,0 +1,1592 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#include "osal_typedef.h" +#include "wmt_dbg.h" +#include "wmt_dev.h" +#include "wmt_core.h" +#include "wmt_lib.h" +#include "wmt_conf.h" +#include "psm_core.h" +#include "stp_core.h" +#include "stp_dbg.h" +#include "connsys_debug_utility.h" +#include "wmt_step.h" +#ifdef CONFIG_MTK_ENG_BUILD +#include "wmt_step_test.h" +#endif + +#ifdef DFT_TAG +#undef DFT_TAG +#define DFT_TAG "[WMT-DEV]" +#endif + +#define WMT_DBG_PROCNAME "driver/wmt_dbg" + +#define BUF_LEN_MAX 384 + +#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD)) +#define WMT_EMI_DEBUG_BUF_SIZE (8*1024) +#else +#define WMT_EMI_DEBUG_BUF_SIZE (32*1024) +#endif + +struct wmt_dbg_work { + struct work_struct work; + INT32 x; + INT32 y; + INT32 z; +}; + +static struct proc_dir_entry *gWmtDbgEntry; +COEX_BUF gCoexBuf; +static UINT8 gEmiBuf[WMT_EMI_DEBUG_BUF_SIZE]; +PUINT8 buf_emi; +static OSAL_SLEEPABLE_LOCK g_dbg_emi_lock; + +static ssize_t wmt_dbg_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); +static ssize_t wmt_dbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); + + +static INT32 wmt_dbg_psm_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_quick_sleep_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_dsns_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_hwver_get(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_inband_rst(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_chip_rst(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_func_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_raed_chipid(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_wmt_dbg_level(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_stp_dbg_level(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_reg_read(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_reg_write(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_coex_test(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_assert_test(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_cmd_test_api(ENUM_WMTDRV_CMD_T cmd); +static INT32 wmt_dbg_rst_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_ut_test(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_efuse_read(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_efuse_write(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_sdio_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_stp_dbg_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_stp_dbg_log_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_wmt_assert_ctrl(INT32 par1, INT32 par2, INT32 par3); +#if CFG_CORE_INTERNAL_TXRX +static INT32 wmt_dbg_internal_lpbk_test(INT32 par1, INT32 par2, INT32 par3); +#endif +static INT32 wmt_dbg_stp_trigger_assert(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_ap_reg_read(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_ap_reg_write(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_set_mcu_clock(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_poll_cpupcr(INT32 par1, INT32 par2, INT32 par3); +#if CONSYS_ENALBE_SET_JTAG +static INT32 wmt_dbg_jtag_flag_ctrl(INT32 par1, INT32 par2, INT32 par3); +#endif +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 wmt_dbg_lte_coex_test(INT32 par1, INT32 par2, INT32 par3); +#endif +#ifdef CONFIG_TRACING +static INT32 wmt_dbg_ftrace_dbg_log_ctrl(INT32 par1, INT32 par2, INT32 par3); +#endif +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +static INT32 wmt_dbg_deep_sleep_ctrl(INT32 par1, INT32 par2, INT32 par3); +#endif +static INT32 wmt_dbg_sdio_retry_ctrl(INT32 par1, INT32 par2, INT32 par3); + +static INT32 wmt_dbg_func0_reg_read(INT32 par1, INT32 address, INT32 value); +static INT32 wmt_dbg_func0_reg_write(INT32 par1, INT32 address, INT32 value); +static INT32 wmt_dbg_stp_sdio_reg_read(INT32 par1, INT32 address, INT32 value); +static INT32 wmt_dbg_stp_sdio_reg_write(INT32 par1, INT32 address, INT32 value); +static INT32 wmt_dbg_show_thread_debug_info(INT32 par1, INT32 address, INT32 value); +static INT32 wmt_dbg_met_ctrl(INT32 par1, INT32 met_ctrl, INT32 log_ctrl); +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +static INT32 wmt_dbg_set_fw_log_mode(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_emi_dump(INT32 par1, INT32 offset, INT32 size); +#endif +static INT32 wmt_dbg_suspend_debug(INT32 par1, INT32 offset, INT32 size); +static INT32 wmt_dbg_fw_log_ctrl(INT32 par1, INT32 onoff, INT32 level); +static INT32 wmt_dbg_pre_pwr_on_ctrl(INT32 par1, INT32 enable, INT32 par3); +#ifdef CONFIG_MTK_ENG_BUILD +static INT32 wmt_dbg_step_test(INT32 par1, INT32 address, INT32 value); +#endif + +static INT32 wmt_dbg_thermal_query(INT32 par1, INT32 count, INT32 interval); +static INT32 wmt_dbg_thermal_ctrl(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_step_ctrl(INT32 par1, INT32 par2, INT32 par3); + +static INT32 wmt_dbg_gps_suspend(INT32 par1, INT32 par2, INT32 par3); +static INT32 wmt_dbg_set_bt_link_status(INT32 par1, INT32 par2, INT32 par3); + +static const WMT_DEV_DBG_FUNC wmt_dev_dbg_func[] = { + [0x0] = wmt_dbg_psm_ctrl, + [0x1] = wmt_dbg_quick_sleep_ctrl, + [0x2] = wmt_dbg_dsns_ctrl, + [0x3] = wmt_dbg_hwver_get, + [0x4] = wmt_dbg_assert_test, + [0x5] = wmt_dbg_inband_rst, + [0x6] = wmt_dbg_chip_rst, + [0x7] = wmt_dbg_func_ctrl, + [0x8] = wmt_dbg_raed_chipid, + [0x9] = wmt_dbg_wmt_dbg_level, + [0xa] = wmt_dbg_stp_dbg_level, + [0xb] = wmt_dbg_reg_read, + [0xc] = wmt_dbg_reg_write, + [0xd] = wmt_dbg_coex_test, + [0xe] = wmt_dbg_rst_ctrl, + [0xf] = wmt_dbg_ut_test, + [0x10] = wmt_dbg_efuse_read, + [0x11] = wmt_dbg_efuse_write, + [0x12] = wmt_dbg_sdio_ctrl, + [0x13] = wmt_dbg_stp_dbg_ctrl, + [0x14] = wmt_dbg_stp_dbg_log_ctrl, + [0x15] = wmt_dbg_wmt_assert_ctrl, + [0x16] = wmt_dbg_stp_trigger_assert, + [0x17] = wmt_dbg_ap_reg_read, + [0x18] = wmt_dbg_ap_reg_write, + [0x19] = wmt_dbg_fwinfor_from_emi, + [0x1a] = wmt_dbg_set_mcu_clock, + [0x1b] = wmt_dbg_poll_cpupcr, + [0x1c] = wmt_dbg_jtag_flag_ctrl, + +#if CFG_WMT_LTE_COEX_HANDLING + [0x1d] = wmt_dbg_lte_coex_test, +#endif +#ifdef CONFIG_TRACING + [0x1e] = wmt_dbg_ftrace_dbg_log_ctrl, +#endif +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT + [0x1f] = wmt_dbg_deep_sleep_ctrl, +#endif + [0x20] = wmt_dbg_sdio_retry_ctrl, + [0x22] = wmt_dbg_func0_reg_read, + [0x23] = wmt_dbg_func0_reg_write, + [0x24] = wmt_dbg_stp_sdio_reg_read, + [0x25] = wmt_dbg_stp_sdio_reg_write, + [0x26] = wmt_dbg_met_ctrl, + [0x27] = wmt_dbg_fw_log_ctrl, + [0x28] = wmt_dbg_pre_pwr_on_ctrl, + [0x29] = wmt_dbg_thermal_query, + [0x2a] = wmt_dbg_thermal_ctrl, + [0x2b] = wmt_dbg_step_ctrl, +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + [0x2c] = wmt_dbg_set_fw_log_mode, + [0x2d] = wmt_dbg_emi_dump, +#endif + [0x2e] = wmt_dbg_suspend_debug, + [0x2f] = wmt_dbg_set_bt_link_status, + [0x30] = wmt_dbg_show_thread_debug_info, + [0x31] = wmt_dbg_gps_suspend, +#ifdef CONFIG_MTK_ENG_BUILD + [0xa0] = wmt_dbg_step_test, +#endif +}; + +static VOID wmt_dbg_fwinfor_print_buff(UINT32 len) +{ + UINT32 i = 0; + UINT32 idx = 0; + + for (i = 0; i < len; i++) { + buf_emi[idx] = gEmiBuf[i]; + if (gEmiBuf[i] == '\n') { + WMT_INFO_FUNC("%s", buf_emi); + osal_memset(buf_emi, 0, BUF_LEN_MAX); + idx = 0; + } else { + idx++; + if (idx == BUF_LEN_MAX-1) { + buf_emi[idx] = '\0'; + WMT_INFO_FUNC("%s", buf_emi); + osal_memset(buf_emi, 0, BUF_LEN_MAX); + idx = 0; + } + } + } + if ((idx != 0) && (idx < BUF_LEN_MAX)) { + buf_emi[idx] = '\0'; + WMT_INFO_FUNC("%s", buf_emi); + osal_memset(buf_emi, 0, BUF_LEN_MAX); + idx = 0; + } +} + +INT32 wmt_dbg_psm_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ +#if CFG_WMT_PS_SUPPORT + if (par2 == 0) { + wmt_lib_ps_ctrl(0); + WMT_INFO_FUNC("disable PSM\n"); + } else { + par2 = (par2 < 1 || par2 > 2000) ? STP_PSM_IDLE_TIME_SLEEP : par2; + wmt_lib_ps_set_idle_time(par2); + wmt_lib_ps_ctrl(1); + WMT_WARN_FUNC("enable PSM, idle to sleep time = %d ms\n", par2); + } +#else + WMT_INFO_FUNC("WMT PS not supported\n"); +#endif + return 0; +} + +INT32 wmt_dbg_quick_sleep_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ +#if CFG_WMT_PS_SUPPORT + UINT32 en_flag = par2; + + wmt_lib_quick_sleep_ctrl(en_flag); +#else + WMT_WARN_FUNC("WMT PS not supported\n"); +#endif + return 0; +} + +INT32 wmt_dbg_dsns_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + if (WMTDSNS_FM_DISABLE <= par2 && WMTDSNS_MAX > par2) { + WMT_INFO_FUNC("DSNS type (%d)\n", par2); + mtk_wcn_wmt_dsns_ctrl(par2); + } else { + WMT_WARN_FUNC("invalid DSNS type\n"); + } + return 0; +} + +INT32 wmt_dbg_hwver_get(INT32 par1, INT32 par2, INT32 par3) +{ + WMT_INFO_FUNC("query chip version\n"); + wmt_lib_get_icinfo(WMTCHIN_HWVER); + return 0; +} + +INT32 wmt_dbg_assert_test(INT32 par1, INT32 par2, INT32 par3) +{ + INT32 sec = 8; + INT32 times = 0; + + if (par3 == 0) { + /* par2 = 0: send assert command */ + /* par2 != 0: send exception command */ + return wmt_dbg_cmd_test_api(par2 == 0 ? 0 : 1); + } else if (par3 == 1) { + /* send noack command */ + return wmt_dbg_cmd_test_api(WMTDRV_CMD_NOACK_TEST); + } else if (par3 == 2) { + /* warn reset test */ + return wmt_dbg_cmd_test_api(WMTDRV_CMD_WARNRST_TEST); + } else if (par3 == 3) { + /* firmware trace test - for soc usage, not used in combo chip */ + return wmt_dbg_cmd_test_api(WMTDRV_CMD_FWTRACE_TEST); + } else if (par3 == 4) { + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + return -1; + } + /* driver type */ + wmt_lib_trigger_assert(par2, 30); + ENABLE_PSM_MONITOR(); + return 0; + } else if (par3 == 5) { + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + return -1; + } + /* assert reason */ + wmt_lib_trigger_assert(4, par2); + ENABLE_PSM_MONITOR(); + return 0; + } + + times = par3; + do { + WMT_INFO_FUNC("Send Assert Command per 8 secs!!\n"); + wmt_dbg_cmd_test_api(0); + osal_sleep_ms(sec * 1000); + } while (--times); + + return 0; +} + +INT32 wmt_dbg_cmd_test_api(ENUM_WMTDRV_CMD_T cmd) +{ + P_OSAL_OP pOp = NULL; + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + P_OSAL_SIGNAL pSignal; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_DBG_FUNC("get_free_lxop fail\n"); + return MTK_WCN_BOOL_FALSE; + } + + pSignal = &pOp->signal; + + pOp->op.opId = WMT_OPID_CMD_TEST; + + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + /*this test command should be run with usb cable connected, so no host awake is needed */ + /* wmt_lib_host_awake_get(); */ + + switch (cmd) { + case WMTDRV_CMD_ASSERT: + pOp->op.au4OpData[0] = 0; + break; + case WMTDRV_CMD_EXCEPTION: + pOp->op.au4OpData[0] = 1; + break; + case WMTDRV_CMD_NOACK_TEST: + pOp->op.au4OpData[0] = 3; + break; + case WMTDRV_CMD_WARNRST_TEST: + pOp->op.au4OpData[0] = 4; + break; + case WMTDRV_CMD_FWTRACE_TEST: + pOp->op.au4OpData[0] = 5; + break; + default: + if (WMTDRV_CMD_COEXDBG_00 <= cmd && WMTDRV_CMD_COEXDBG_15 >= cmd) { + pOp->op.au4OpData[0] = 2; + pOp->op.au4OpData[1] = cmd - 2; + } else { + pOp->op.au4OpData[0] = 0xff; + pOp->op.au4OpData[1] = 0xff; + } + pOp->op.au4OpData[2] = (ULONG) gCoexBuf.buffer; + pOp->op.au4OpData[3] = osal_sizeof(gCoexBuf.buffer); + break; + } + WMT_INFO_FUNC("CMD_TEST, opid(%d), par(%zu, %zu)\n", pOp->op.opId, pOp->op.au4OpData[0], + pOp->op.au4OpData[1]); + /*wake up chip first */ + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if ((cmd != WMTDRV_CMD_ASSERT) && + (cmd != WMTDRV_CMD_EXCEPTION) && + (cmd != WMTDRV_CMD_NOACK_TEST) && + (cmd != WMTDRV_CMD_WARNRST_TEST) && + (cmd != WMTDRV_CMD_FWTRACE_TEST)) { + if (bRet == MTK_WCN_BOOL_FALSE) { + gCoexBuf.availSize = 0; + } else { + gCoexBuf.availSize = pOp->op.au4OpData[3]; + WMT_INFO_FUNC("gCoexBuf.availSize = %d\n", gCoexBuf.availSize); + } + } + /* wmt_lib_host_awake_put(); */ + WMT_INFO_FUNC("CMD_TEST, opid (%d), par(%zu, %zu), ret(%d), result(%s)\n", + pOp->op.opId, + pOp->op.au4OpData[0], + pOp->op.au4OpData[1], + bRet, MTK_WCN_BOOL_FALSE == bRet ? "failed" : "succeed"); + + if (bRet == MTK_WCN_BOOL_TRUE) + wmt_lib_set_host_assert_info(WMTDRV_TYPE_WMT, 0, 1); + + return 0; +} + +INT32 wmt_dbg_inband_rst(INT32 par1, INT32 par2, INT32 par3) +{ + if (par2 == 0) { + WMT_INFO_FUNC("inband reset test!!\n"); + mtk_wcn_stp_inband_reset(); + } else { + WMT_INFO_FUNC("STP context reset in host side!!\n"); + mtk_wcn_stp_flush_context(); + } + + return 0; +} + +INT32 wmt_dbg_chip_rst(INT32 par1, INT32 par2, INT32 par3) +{ + if (par2 == 0) { + if (mtk_wcn_stp_is_ready()) { + WMT_INFO_FUNC("whole chip reset test\n"); + wmt_lib_cmb_rst(WMTRSTSRC_RESET_TEST); + } else { + WMT_INFO_FUNC("STP not ready , not to launch whole chip reset test\n"); + } + } else if (par2 == 1) { + WMT_INFO_FUNC("chip hardware reset test\n"); + wmt_lib_hw_rst(); + } else { + WMT_INFO_FUNC("chip software reset test\n"); + wmt_lib_sw_rst(1); + } + + return 0; +} + +INT32 wmt_dbg_func_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + if (par2 < WMTDRV_TYPE_WMT || par2 == WMTDRV_TYPE_LPBK) { + if (par3 == 0) { + WMT_INFO_FUNC("function off test, type(%d)\n", par2); + ret = mtk_wcn_wmt_func_off(par2); + } else { + WMT_INFO_FUNC("function on test, type(%d)\n", par2); + ret = mtk_wcn_wmt_func_on(par2); + } + WMT_INFO_FUNC("function test return %d\n", ret); + } else + WMT_INFO_FUNC("function ctrl test, invalid type(%d)\n", par2); + + return 0; +} + +INT32 wmt_dbg_raed_chipid(INT32 par1, INT32 par2, INT32 par3) +{ + WMT_INFO_FUNC("chip id = %d\n", wmt_lib_get_icinfo(WMTCHIN_CHIPID)); + + return 0; +} + +INT32 wmt_dbg_wmt_dbg_level(INT32 par1, INT32 par2, INT32 par3) +{ + par2 = (WMT_LOG_ERR <= par2 && WMT_LOG_LOUD >= par2) ? par2 : WMT_LOG_INFO; + wmt_lib_dbg_level_set(par2); + WMT_INFO_FUNC("set wmt log level to %d\n", par2); + + return 0; +} + +INT32 wmt_dbg_stp_dbg_level(INT32 par1, INT32 par2, INT32 par3) +{ + par2 = (0 <= par2 && 4 >= par2) ? par2 : 2; + mtk_wcn_stp_dbg_level(par2); + WMT_INFO_FUNC("set stp log level to %d\n", par2); + + return 0; +} + +INT32 wmt_dbg_reg_read(INT32 par1, INT32 par2, INT32 par3) +{ + /* par2-->register address */ + /* par3-->register mask */ + UINT32 value = 0x0; + UINT32 iRet = -1; +#if 0 + DISABLE_PSM_MONITOR(); + iRet = wmt_core_reg_rw_raw(0, par2, &value, par3); + ENABLE_PSM_MONITOR(); +#endif + iRet = wmt_lib_reg_rw(0, par2, &value, par3); + WMT_INFO_FUNC("read combo chip register (0x%08x) with mask (0x%08x) %s, value = 0x%08x\n", + par2, par3, iRet != 0 ? "failed" : "succeed", iRet != 0 ? -1 : value); + + return 0; +} + +INT32 wmt_dbg_reg_write(INT32 par1, INT32 par2, INT32 par3) +{ + /* par2-->register address */ + /* par3-->value to set */ + UINT32 iRet = -1; +#if 0 + DISABLE_PSM_MONITOR(); + iRet = wmt_core_reg_rw_raw(1, par2, &par3, 0xffffffff); + ENABLE_PSM_MONITOR(); +#endif + iRet = wmt_lib_reg_rw(1, par2, &par3, 0xffffffff); + WMT_INFO_FUNC("write combo chip register (0x%08x) with value (0x%08x) %s\n", + par2, par3, iRet != 0 ? "failed" : "succeed"); + + return 0; +} + +INT32 wmt_dbg_efuse_read(INT32 par1, INT32 par2, INT32 par3) +{ + /* par2-->efuse address */ + /* par3-->register mask */ + UINT32 value = 0x0; + UINT32 iRet = -1; + + iRet = wmt_lib_efuse_rw(0, par2, &value, par3); + WMT_INFO_FUNC("read combo chip efuse (0x%08x) with mask (0x%08x) %s, value = 0x%08x\n", + par2, par3, iRet != 0 ? "failed" : "succeed", iRet != 0 ? -1 : value); + + return 0; +} + +INT32 wmt_dbg_efuse_write(INT32 par1, INT32 par2, INT32 par3) +{ + /* par2-->efuse address */ + /* par3-->value to set */ + UINT32 iRet = -1; + + iRet = wmt_lib_efuse_rw(1, par2, &par3, 0xffffffff); + WMT_INFO_FUNC("write combo chip efuse (0x%08x) with value (0x%08x) %s\n", + par2, par3, iRet != 0 ? "failed" : "succeed"); + + return 0; +} + +INT32 wmt_dbg_sdio_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ +/*remove sdio card detect/remove control because of btif is used*/ +#if 0 + INT32 iRet = -1; + + iRet = wmt_lib_sdio_ctrl(par2 != 0 ? 1 : 0); + WMT_INFO_FUNC("ctrl SDIO function %s\n", 0 == iRet ? "succeed" : "failed"); +#endif + return 0; +} + +INT32 wmt_dbg_stp_dbg_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + if (par2 > 1) { + mtk_wcn_stp_dbg_dump_package(); + return 0; + } + + WMT_INFO_FUNC("%s stp debug function\n", par2 == 0 ? "disable" : "enable"); + + if (par2 == 0) + mtk_wcn_stp_dbg_disable(); + else if (par2 == 1) + mtk_wcn_stp_dbg_enable(); + + return 0; +} + +INT32 wmt_dbg_stp_dbg_log_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + mtk_wcn_stp_dbg_log_ctrl(par2 != 0 ? 1 : 0); + + return 0; +} + +INT32 wmt_dbg_wmt_assert_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + if (par2 > 2 || par2 < 0) + return -1; + + mtk_wcn_stp_coredump_flag_ctrl(par2); + + return 0; +} + +INT32 wmt_dbg_fwinfor_from_emi(INT32 par1, INT32 par2, INT32 par3) +{ + UINT32 offset = 0; + UINT32 len = 0; + UINT32 *pAddr = NULL; + UINT32 cur_idx_pagedtrace; + static UINT32 prev_idx_pagedtrace; + MTK_WCN_BOOL isBreak = MTK_WCN_BOOL_TRUE; + + offset = par2; + len = par3; + + if (osal_lock_sleepable_lock(&g_dbg_emi_lock)) { + WMT_ERR_FUNC("lock failed\n"); + return -1; + } + + buf_emi = kmalloc(sizeof(UINT8) * BUF_LEN_MAX, GFP_KERNEL); + if (!buf_emi) { + WMT_ERR_FUNC("buf kmalloc memory fail\n"); + return 0; + } + osal_memset(buf_emi, 0, BUF_LEN_MAX); + osal_memset(&gEmiBuf[0], 0, WMT_EMI_DEBUG_BUF_SIZE); + wmt_lib_get_fwinfor_from_emi(0, offset, &gEmiBuf[0], 0x100); + + if (offset == 1) { + do { + pAddr = (PUINT32) wmt_plat_get_emi_virt_add(0x24); + if (pAddr == NULL) { + WMT_ERR_FUNC("get virtual emi address 0x24 fail!\n"); + return -1; + } + cur_idx_pagedtrace = *pAddr; + + if (cur_idx_pagedtrace > prev_idx_pagedtrace) { + len = cur_idx_pagedtrace - prev_idx_pagedtrace; + wmt_lib_get_fwinfor_from_emi(1, prev_idx_pagedtrace, &gEmiBuf[0], len); + wmt_dbg_fwinfor_print_buff(len); + prev_idx_pagedtrace = cur_idx_pagedtrace; + } + + if (cur_idx_pagedtrace < prev_idx_pagedtrace) { + if (prev_idx_pagedtrace >= 0x8000) { + WMT_INFO_FUNC("++ prev_idx_pagedtrace invalid ...++\n\\n"); + prev_idx_pagedtrace = 0x8000 - 1; + continue; + } + + len = 0x8000 - prev_idx_pagedtrace - 1; + wmt_lib_get_fwinfor_from_emi(1, prev_idx_pagedtrace, &gEmiBuf[0], len); + WMT_INFO_FUNC("\n\n -- CONNSYS paged trace ascii output (cont...) --\n\n"); + wmt_dbg_fwinfor_print_buff(len); + + len = cur_idx_pagedtrace; + wmt_lib_get_fwinfor_from_emi(1, 0x0, &gEmiBuf[0], len); + WMT_INFO_FUNC("\n\n -- CONNSYS paged trace ascii output (end) --\n\n"); + wmt_dbg_fwinfor_print_buff(len); + prev_idx_pagedtrace = cur_idx_pagedtrace; + } + msleep(100); + } while (isBreak); + } + + WMT_INFO_FUNC("\n\n -- control word --\n\n"); + wmt_dbg_fwinfor_print_buff(256); + if (len > 1024 * 4) + len = 1024 * 4; + + WMT_WARN_FUNC("get fw infor from emi at offset(0x%x),len(0x%x)\n", offset, len); + osal_memset(&gEmiBuf[0], 0, WMT_EMI_DEBUG_BUF_SIZE); + wmt_lib_get_fwinfor_from_emi(1, offset, &gEmiBuf[0], len); + + WMT_INFO_FUNC("\n\n -- paged trace hex output --\n\n"); + wmt_dbg_fwinfor_print_buff(len); + WMT_INFO_FUNC("\n\n -- paged trace ascii output --\n\n"); + wmt_dbg_fwinfor_print_buff(len); + kfree(buf_emi); + osal_unlock_sleepable_lock(&g_dbg_emi_lock); + + return 0; +} + +INT32 wmt_dbg_stp_trigger_assert(INT32 par1, INT32 par2, INT32 par3) +{ + wmt_lib_btm_cb(BTM_TRIGGER_STP_ASSERT_OP); + + return 0; +} + +static INT32 wmt_dbg_ap_reg_read(INT32 par1, INT32 par2, INT32 par3) +{ + INT32 value = 0x0; + PUINT8 ap_reg_base = NULL; + + WMT_INFO_FUNC("AP register read, reg address:0x%x\n", par2); + ap_reg_base = ioremap(par2, 0x4); + if (ap_reg_base) { + value = readl(ap_reg_base); + WMT_INFO_FUNC("AP register read, reg address:0x%x, value:0x%x\n", par2, value); + iounmap(ap_reg_base); + } else + WMT_ERR_FUNC("AP register ioremap fail!\n"); + + return 0; +} + +static INT32 wmt_dbg_ap_reg_write(INT32 par1, INT32 par2, INT32 par3) +{ + INT32 value = 0x0; + PUINT8 ap_reg_base = NULL; + + WMT_INFO_FUNC("AP register write, reg address:0x%x, value:0x%x\n", par2, par3); + + ap_reg_base = ioremap(par2, 0x4); + if (ap_reg_base) { + writel(par3, ap_reg_base); + value = readl(ap_reg_base); + WMT_INFO_FUNC("AP register write done, value after write:0x%x\n", value); + iounmap(ap_reg_base); + } else + WMT_ERR_FUNC("AP register ioremap fail!\n"); + + return 0; +} + +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +static INT32 wmt_dbg_set_fw_log_mode(INT32 par1, INT32 par2, INT32 par3) +{ + connsys_dedicated_log_set_log_mode(par2); + return 0; +} + +static INT32 wmt_dbg_emi_dump(INT32 par1, INT32 offset, INT32 size) +{ + connsys_dedicated_log_dump_emi(offset, size); + return 0; +} +#endif + +/********************************************************/ +/* par2: */ +/* 0: Off */ +/* others: alarm time (seconds) */ +/********************************************************/ +static INT32 wmt_dbg_suspend_debug(INT32 par1, INT32 par2, INT32 par3) +{ + if (par2 > 0) + connsys_log_alarm_enable(par2); + else + connsys_log_alarm_disable(); + return 0; +} + +static INT32 wmt_dbg_set_bt_link_status(INT32 par1, INT32 par2, INT32 par3) +{ + if (par2 != 0 && par2 != 1) + return 0; + + wmt_lib_set_bt_link_status(par2, par3); + return 0; +} + +#ifdef CONFIG_TRACING +static INT32 wmt_dbg_ftrace_dbg_log_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + WMT_INFO_FUNC("%s ftrace print!!\n", par2 == 0 ? "disable" : "enable"); + + return osal_ftrace_print_ctrl(par2 == 0 ? 0 : 1); +} +#endif + +#ifdef CONFIG_MTK_COMBO_CHIP_DEEP_SLEEP_SUPPORT +static INT32 wmt_dbg_deep_sleep_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + WMT_INFO_FUNC("%s deep_sleep !!\n", par2 == 0 ? "disable" : "enable"); + return wmt_lib_deep_sleep_ctrl(par2); +} +#endif + +static INT32 wmt_dbg_sdio_retry_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + WMT_INFO_FUNC("%s sdio retry!!\n", par2 == 0 ? "disable" : "enable"); + + mtk_stp_dbg_sdio_retry_flag_ctrl(par2 == 0 ? 0 : 1); + + return 0; +} + +INT32 wmt_dbg_coex_test(INT32 par1, INT32 par2, INT32 par3) +{ + WMT_INFO_FUNC("coexistance test cmd!!\n"); + + return wmt_dbg_cmd_test_api(par2 + WMTDRV_CMD_COEXDBG_00); +} + +INT32 wmt_dbg_rst_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + WMT_INFO_FUNC("%s audo rst\n", par2 == 0 ? "disable" : "enable"); + mtk_wcn_stp_set_auto_rst(par2 == 0 ? 0 : 1); + + return 0; +} + +INT32 wmt_dbg_func0_reg_read(INT32 par1, INT32 address, INT32 value) +{ + INT32 ret = -1; + + ret = wmt_lib_sdio_reg_rw(0, 0, (UINT32)address, (UINT32)value); + if (ret) { + WMT_ERR_FUNC("read fucn0 SDIO register fail"); + return ret; + } + return ret; +} + +INT32 wmt_dbg_func0_reg_write(INT32 par1, INT32 address, INT32 value) +{ + INT32 ret = -1; + + ret = wmt_lib_sdio_reg_rw(0, 1, (UINT32)address, (UINT32)value); + if (ret) { + WMT_ERR_FUNC("write func0 SDIO register fail"); + return ret; + } + + return ret; +} + +INT32 wmt_dbg_stp_sdio_reg_read(INT32 par1, INT32 address, INT32 value) +{ + INT32 ret = -1; + + ret = wmt_lib_sdio_reg_rw(2, 0, (UINT32)address, (UINT32)value); + if (ret) { + WMT_ERR_FUNC("read SDIO register fail"); + return ret; + } + + return ret; +} + +INT32 wmt_dbg_stp_sdio_reg_write(INT32 par1, INT32 address, INT32 value) +{ + INT32 ret = -1; + + ret = wmt_lib_sdio_reg_rw(2, 1, (UINT32)address, (UINT32)value); + if (ret) { + WMT_ERR_FUNC("write SDIO register fail"); + return ret; + } + + return ret; +} + +static INT32 wmt_dbg_show_thread_debug_info(INT32 par1, INT32 address, INT32 value) +{ + + osal_dump_thread_state("btif_rxd"); + osal_dump_thread_state("mtk_wmtd"); + osal_dump_thread_state("mtk_stp_psm"); + osal_dump_thread_state("mtk_stp_btm"); + + return 0; +} + +INT32 wmt_dbg_met_ctrl(INT32 par1, INT32 met_ctrl, INT32 log_ctrl) +{ + UINT32 ret = -1; + + ret = wmt_lib_met_ctrl(met_ctrl, log_ctrl); + WMT_INFO_FUNC("met ctrl(0x%08x) met log print to %s, %s\n", + met_ctrl, + log_ctrl == 0 ? "kernel log" : "ftrace log", + ret != 0 ? "failed" : "succeed"); + + return ret; +} + +static INT32 wmt_dbg_fw_log_ctrl(INT32 par1, INT32 onoff, INT32 level) +{ + /* Parameter format + * onoff: + * - bit 24~31: unused + * - bit 16~23: subsys type + * - bit 8~15 : unused + * - bit 0~7 : on/off setting + * level: only lowest 8 bites will be used. + * - bit 8~31 : unused + * - bit 0~7 : log level setting + * Example: + * 1. To turn on MCU log + * onoff = 0x0001 + * 2. To turn on Subsys Z log + * onoff = 0x0z01 (z = subsys) + * 3. To turn off Subsys Z log + * onoff = 0x0z00 (z = subsys) + */ + UINT8 type = (unsigned char)(onoff >> 16); + + WMT_INFO_FUNC("Configuring firmware log: type:%d, on/off:%d, level:%d\n", + type, (unsigned char)onoff, (unsigned char)level); + wmt_lib_fw_log_ctrl(type, (unsigned char)onoff, (unsigned char)level); + + return 0; +} + +INT32 wmt_dbg_pre_pwr_on_ctrl(INT32 par1, INT32 enable, INT32 par3) +{ + MTK_WCN_BOOL ret = MTK_WCN_BOOL_FALSE; + + WMT_INFO_FUNC("%s pre power on function\n", enable ? "enable" : "disable"); + + if (enable) { + /* Turn LPBK off and set always power on flag to 1 */ + ret = mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK); + if (!ret) + WMT_WARN_FUNC("mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK) return %d\n", ret); + wmt_dev_apo_ctrl(1); + } else { + /* Just set always power on flag to 0 */ + wmt_dev_apo_ctrl(0); + } + + return 0; +} + +#ifdef CONFIG_MTK_ENG_BUILD +INT32 wmt_dbg_step_test(INT32 par1, INT32 par2, INT32 par3) +{ + wmt_step_test_all(); + + return 0; +} +#endif + +INT32 wmt_dbg_thermal_query(INT32 par1, INT32 count, INT32 interval) +{ + LONG tm; + + if (count < 0) + count = 0; + if (interval < 0) + interval = 0; + + WMT_INFO_FUNC("Performing thermal query for %d times with %dms interval\n", count, interval); + while (count--) { + mtk_wcn_wmt_therm_ctrl(WMTTHERM_ENABLE); + tm = mtk_wcn_wmt_therm_ctrl(WMTTHERM_READ); + mtk_wcn_wmt_therm_ctrl(WMTTHERM_DISABLE); + + WMT_INFO_FUNC("Temperature: %ld\n", tm); + if (count > 0) + osal_sleep_ms(interval); + } + return 0; +} + +INT32 wmt_dbg_thermal_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + if (par2 == 0) { + if (par3 >= 99) { + WMT_INFO_FUNC("Can`t set temp threshold greater or queal 99\n"); + return -1; + } + wmt_dev_set_temp_threshold(par3); + } + + return 0; +} + +static INT32 wmt_dbg_step_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + if (par2 == 0) + wmt_step_print_version(); + else if (par2 == 1) { + WMT_INFO_FUNC("STEP show: Start to change config\n"); + wmt_step_deinit(); + wmt_step_init(); + WMT_INFO_FUNC("STEP show: End to change config\n"); + } + + return 0; +} + +INT32 wmt_dbg_ut_test(INT32 par1, INT32 par2, INT32 par3) +{ + INT32 i = 0; + INT32 j = 0; + INT32 iRet = 0; + + i = 20; + while ((i--) > 0) { + WMT_INFO_FUNC("#### UT WMT and STP Function On/Off .... %d\n", i); + j = 10; + while ((j--) > 0) { + WMT_INFO_FUNC("#### BT On .... (%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + WMT_INFO_FUNC("#### GPS On .... (%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_GPS); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + WMT_INFO_FUNC("#### FM On .... (%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + WMT_INFO_FUNC("#### WIFI On .... (%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + WMT_INFO_FUNC("#### ANT On .... (%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_ANT); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + + WMT_INFO_FUNC("#### BT Off .... (%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_BT); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + + WMT_INFO_FUNC("#### GPS Off ....(%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_GPS); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + + WMT_INFO_FUNC("#### FM Off .... (%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + WMT_INFO_FUNC("#### WIFI Off ....(%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_WIFI); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + WMT_INFO_FUNC("#### ANT Off ....(%d, %d)\n", i, j); + iRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_ANT); + if (iRet == MTK_WCN_BOOL_FALSE) + break; + } + + if (iRet == MTK_WCN_BOOL_FALSE) + break; + } + if (iRet == MTK_WCN_BOOL_FALSE) + WMT_INFO_FUNC("#### UT FAIL!!\n"); + else + WMT_INFO_FUNC("#### UT PASS!!\n"); + + return iRet; +} + +#if CFG_CORE_INTERNAL_TXRX +struct lpbk_package { + UINT32 payload_length; + UINT8 out_payload[2048]; + UINT8 in_payload[2048]; +}; + +static INT32 wmt_internal_loopback(INT32 count, INT32 max) +{ + INT32 ret = 0; + INT32 loop; + INT32 offset; + struct lpbk_package lpbk_buffer; + P_OSAL_OP pOp; + P_OSAL_SIGNAL pSignal = NULL; + + for (loop = 0; loop < count; loop++) { + /* <1> init buffer */ + osal_memset((PVOID)&lpbk_buffer, 0, sizeof(struct lpbk_package)); + lpbk_buffer.payload_length = max; + for (offset = 0; offset < max; offset++) + lpbk_buffer.out_payload[offset] = (offset + 1) & 0xFF;/*for test use: begin from 1 */ + + memcpy(&gLpbkBuf[0], &lpbk_buffer.out_payload[0], max); + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + ret = -1; + break; + } + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_LPBK; + pOp->op.au4OpData[0] = lpbk_buffer.payload_length; /* packet length */ + pOp->op.au4OpData[1] = (UINT32) &gLpbkBuf[0]; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + WMT_INFO_FUNC("OPID(%d) type(%zu) start\n", pOp->op.opId, pOp->op.au4OpData[0]); + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) type(%zu) abort\n", pOp->op.opId, + pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + ret = -2; + } + + ret = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (ret == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("OPID(%d) type(%zu)fail\n", + pOp->op.opId, pOp->op.au4OpData[0]); + ret = -3; + break; + } + WMT_INFO_FUNC("OPID(%d) length(%zu) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + + memcpy(&lpbk_buffer.in_payload[0], &gLpbkBuf[0], max); + + ret = pOp->op.au4OpData[0]; + /*<3> compare result */ + if (memcmp(lpbk_buffer.in_payload, lpbk_buffer.out_payload, lpbk_buffer.payload_length)) { + WMT_INFO_FUNC("[%s] WMT_TEST_LPBK_CMD payload compare error\n", __func__); + ret = -4; + break; + } + WMT_ERR_FUNC("[%s] exec WMT_TEST_LPBK_CMD succeed(loop = %d, size = %ld)\n", __func__, loop, + lpbk_buffer.payload_length); + } + + if (loop != count) + WMT_ERR_FUNC("fail at loop(%d) buf_length(%d)\n", loop, max); + + return ret; +} + +INT32 wmt_dbg_internal_lpbk_test(INT32 par1, INT32 par2, INT32 par3) +{ + UINT32 count; + UINT32 length; + + count = par1; + length = par2; + + WMT_INFO_FUNC("count[%d],length[%d]\n", count, length); + + wmt_core_lpbk_do_stp_init(); + + wmt_internal_loopback(count, length); + + wmt_core_lpbk_do_stp_deinit(); + return 0; +} +#endif /* CFG_CORE_INTERNAL_TXRX */ + +static INT32 wmt_dbg_set_mcu_clock(INT32 par1, INT32 par2, INT32 par3) +{ + INT32 ret = 0; + P_OSAL_OP pOp; + P_OSAL_SIGNAL pSignal = NULL; + UINT32 kind = 0; + UINT32 version = 0; + + version = par2; + kind = par3; + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + return -1; + } + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_SET_MCU_CLK; + pOp->op.au4OpData[0] = kind; + pOp->op.au4OpData[1] = version; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + + WMT_INFO_FUNC("OPID(%d) kind(%zu) start\n", pOp->op.opId, pOp->op.au4OpData[0]); + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) kind(%zu) abort\n", + pOp->op.opId, pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + return -2; + } + + ret = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (ret == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("OPID(%d) kind(%zu)fail(%d)\n", + pOp->op.opId, pOp->op.au4OpData[0], ret); + return -3; + } + WMT_INFO_FUNC("OPID(%d) kind(%zu) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + + return ret; +} + +static INT32 wmt_dbg_poll_cpupcr(INT32 par1, INT32 par2, INT32 par3) +{ + UINT32 count = 0; + UINT16 sleep = 0; + UINT16 toAee = 0; + + count = par2; + sleep = (par3 & 0xF0) >> 4; + toAee = (par3 & 0x0F); + + WMT_INFO_FUNC("polling count[%d],polling sleep[%d],toaee[%d]\n", count, sleep, toAee); + stp_dbg_poll_cpupcr(count, sleep, toAee); + + return 0; +} + +#if CONSYS_ENALBE_SET_JTAG +static INT32 wmt_dbg_jtag_flag_ctrl(INT32 par1, INT32 par2, INT32 par3) +{ + UINT32 en_flag = par2; + + switch (en_flag) { + case 1: + case 2: + /* gen2 consys does not support 2-wire jtag*/ + wmt_lib_jtag_flag_set(en_flag); + WMT_INFO_FUNC("enable %s mcu jtag pinmux setting\n", en_flag == 1 ? "7-wire" : "2-wire"); + break; + default: + WMT_INFO_FUNC("enable mcu jtag does not support %d options\n", en_flag); + } + + return 0; +} +#endif + +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 wmt_dbg_lte_to_wmt_test(UINT32 opcode, UINT32 msg_len) +{ + conn_md_ipc_ilm_t ilm; + local_para *p_buf_str; + INT32 i = 0; + INT32 iRet = -1; + + WMT_INFO_FUNC("opcode(0x%02x),msg_len(%d)\n", opcode, msg_len); + p_buf_str = osal_malloc(osal_sizeof(local_para) + msg_len); + if (p_buf_str == NULL) { + WMT_ERR_FUNC("kmalloc for local para ptr structure failed.\n"); + return -1; + } + p_buf_str->msg_len = msg_len; + for (i = 0; i < msg_len; i++) + p_buf_str->data[i] = i; + + ilm.local_para_ptr = p_buf_str; + ilm.msg_id = opcode; + + iRet = wmt_lib_handle_idc_msg(&ilm); + osal_free(p_buf_str); + return iRet; + +} + +static INT32 wmt_dbg_lte_coex_test(INT32 par1, INT32 par2, INT32 par3) +{ + PUINT8 local_buffer = NULL; + UINT32 handle_len; + INT32 iRet = -1; + + static UINT8 wmt_to_lte_test_evt1[] = { 0x02, 0x16, 0x0d, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0xa, 0xb + }; + static UINT8 wmt_to_lte_test_evt2[] = { 0x02, 0x16, 0x09, 0x00, + 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + }; + static UINT8 wmt_to_lte_test_evt3[] = { 0x02, 0x16, 0x02, 0x00, + 0x02, 0xff + }; + static UINT8 wmt_to_lte_test_evt4[] = { 0x02, 0x16, 0x0d, 0x00, + 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0xa, 0xb + }; + + local_buffer = kmalloc(512, GFP_KERNEL); + if (!local_buffer) { + WMT_ERR_FUNC("local_buffer kmalloc memory fail\n"); + return 0; + } + + if (par2 == 1) { + handle_len = wmt_idc_msg_to_lte_handing_for_test(&wmt_to_lte_test_evt1[0], + osal_sizeof(wmt_to_lte_test_evt1)); + if (handle_len != osal_sizeof(wmt_to_lte_test_evt1)) { + WMT_ERR_FUNC("par2=1,wmt send to lte msg fail:handle_len(%d),buff_len(%zu)\n", + handle_len, osal_sizeof(wmt_to_lte_test_evt1)); + } else + WMT_INFO_FUNC("par2=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); + } + if (par2 == 2) { + osal_memcpy(&local_buffer[0], &wmt_to_lte_test_evt1[0], osal_sizeof(wmt_to_lte_test_evt1)); + osal_memcpy(&local_buffer[osal_sizeof(wmt_to_lte_test_evt1)], &wmt_to_lte_test_evt2[0], + osal_sizeof(wmt_to_lte_test_evt2)); + + handle_len = wmt_idc_msg_to_lte_handing_for_test(&local_buffer[0], + osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2)); + if (handle_len != osal_sizeof(wmt_to_lte_test_evt1) + osal_sizeof(wmt_to_lte_test_evt2)) { + WMT_ERR_FUNC("par2=2,wmt send to lte msg fail:handle_len(%d),buff_len(%zu)\n", + handle_len, + osal_sizeof(wmt_to_lte_test_evt1) + + osal_sizeof(wmt_to_lte_test_evt2)); + } else + WMT_INFO_FUNC("par2=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); + } + if (par2 == 3) { + osal_memcpy(&local_buffer[0], &wmt_to_lte_test_evt1[0], osal_sizeof(wmt_to_lte_test_evt1)); + osal_memcpy(&local_buffer[osal_sizeof(wmt_to_lte_test_evt1)], &wmt_to_lte_test_evt2[0], + osal_sizeof(wmt_to_lte_test_evt2)); + osal_memcpy(&local_buffer[osal_sizeof(wmt_to_lte_test_evt1) + + osal_sizeof(wmt_to_lte_test_evt2)], + &wmt_to_lte_test_evt3[0], osal_sizeof(wmt_to_lte_test_evt3)); + + handle_len = wmt_idc_msg_to_lte_handing_for_test(&local_buffer[0], + osal_sizeof(wmt_to_lte_test_evt1) + + osal_sizeof(wmt_to_lte_test_evt2) + + osal_sizeof(wmt_to_lte_test_evt3)); + if (handle_len != osal_sizeof(wmt_to_lte_test_evt1) + + osal_sizeof(wmt_to_lte_test_evt2) + + osal_sizeof(wmt_to_lte_test_evt3)) { + WMT_ERR_FUNC("par2=3,wmt send to lte msg fail:handle_len(%d),buff_len(%zu)\n", + handle_len, + osal_sizeof(wmt_to_lte_test_evt1) + + osal_sizeof(wmt_to_lte_test_evt2) + + osal_sizeof(wmt_to_lte_test_evt3)); + } else + WMT_INFO_FUNC("par3=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); + } + if (par2 == 4) { + handle_len = wmt_idc_msg_to_lte_handing_for_test(&wmt_to_lte_test_evt4[0], + osal_sizeof(wmt_to_lte_test_evt4)); + if (handle_len != osal_sizeof(wmt_to_lte_test_evt4)) { + WMT_ERR_FUNC("par2=1,wmt send to lte msg fail:handle_len(%d),buff_len(%zu)\n", + handle_len, osal_sizeof(wmt_to_lte_test_evt4)); + } else + WMT_INFO_FUNC("par2=1,wmt send to lte msg OK! send_len(%d)\n", handle_len); + } + if (par2 == 5) { + if (par3 >= 1024) + par3 = 1024; + iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND, par3); + WMT_INFO_FUNC("IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND test result(%d)\n", iRet); + } + if (par2 == 6) { + if (par3 >= 1024) + par3 = 1024; + iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND, par3); + WMT_INFO_FUNC("IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND test result(%d)\n", iRet); + } + if (par2 == 7) { + if (par3 >= 1024) + par3 = 1024; + iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND, par3); + WMT_INFO_FUNC("IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND test result(%d)\n", iRet); + } + if (par2 == 8) { + if (par3 >= 1024) + par3 = 1024; + iRet = wmt_dbg_lte_to_wmt_test(IPC_MSG_ID_EL1_LTE_TX_IND, par3); + WMT_INFO_FUNC("IPC_MSG_ID_EL1_LTE_TX_IND test result(%d)\n", iRet); + } + if (par2 == 9) { + if (par3 > 0) + wmt_core_set_flag_for_test(1); + else + wmt_core_set_flag_for_test(0); + } + + kfree(local_buffer); + + return 0; +} +#endif /* CFG_WMT_LTE_COEX_HANDLING */ + +ssize_t wmt_dbg_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + INT32 retval = 0; + INT32 i_ret = 0; + PINT8 warn_msg = "no data available, please run echo 15 xx > /proc/driver/wmt_psm first\n"; + + if (*f_pos > 0) + retval = 0; + else { + /*len = sprintf(page, "%d\n", g_psm_enable); */ + if (gCoexBuf.availSize <= 0) { + WMT_INFO_FUNC + ("no data available, please run echo 15 xx > /proc/driver/wmt_psm first\n"); + retval = osal_strlen(warn_msg) + 1; + if (count < retval) + retval = count; + i_ret = copy_to_user(buf, warn_msg, retval); + if (i_ret) { + WMT_ERR_FUNC("copy to buffer failed, ret:%d\n", retval); + retval = -EFAULT; + goto err_exit; + } + *f_pos += retval; + } else { + INT32 i = 0; + INT32 len = 0; + INT8 msg_info[512]; + INT32 max_num = 0; + + /*we do not check page buffer, because there are only 100 bytes in g_coex_buf, */ + /* no reason page buffer is not enough, */ + /* a bomb is placed here on unexpected condition */ + WMT_INFO_FUNC("%d bytes available\n", gCoexBuf.availSize); + max_num = + ((osal_sizeof(msg_info) > + count ? osal_sizeof(msg_info) : count) - 1) / 5; + + if (max_num > gCoexBuf.availSize) { + max_num = gCoexBuf.availSize; + } else { + WMT_INFO_FUNC + ("round to %d bytes due to local buffer size limitation\n", + max_num); + } + + for (i = 0; i < max_num; i++) + len += osal_sprintf(msg_info + len, "0x%02x ", gCoexBuf.buffer[i]); + + len += osal_sprintf(msg_info + len, "\n"); + retval = len; + + i_ret = copy_to_user(buf, msg_info, retval); + if (i_ret) { + WMT_ERR_FUNC("copy to buffer failed, ret:%d\n", retval); + retval = -EFAULT; + goto err_exit; + } + *f_pos += retval; + } + } + gCoexBuf.availSize = 0; + +err_exit: + return retval; +} + +static VOID delay_work_func(struct work_struct *work) +{ + struct wmt_dbg_work *dbgWork = container_of(work, struct wmt_dbg_work, work); + + if (!dbgWork) { + WMT_ERR_FUNC("fail to get dbgWork"); + return; + } + + (*wmt_dev_dbg_func[dbgWork->x]) (dbgWork->x, dbgWork->y, dbgWork->z); + + kvfree(dbgWork); +} + +static VOID wmt_dbg_delay_work(INT32 x, INT32 y, INT32 z) +{ + struct wmt_dbg_work *dbgWork; + + dbgWork = kmalloc(sizeof(struct wmt_dbg_work), GFP_KERNEL); + if (!dbgWork) { + WMT_ERR_FUNC("fail to allocate memory"); + return; + } + + dbgWork->x = x; + dbgWork->y = y; + dbgWork->z = z; + + INIT_WORK(&dbgWork->work, delay_work_func); + schedule_work(&dbgWork->work); +} + +ssize_t wmt_dbg_write(struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos) +{ + ULONG len = count; + INT8 buf[256]; + PINT8 pBuf; + INT32 x = 0, y = 0, z = 0; + PINT8 pToken = NULL; + PINT8 pDelimiter = " \t"; + LONG res = 0; + static INT8 dbgEnabled; + + WMT_INFO_FUNC("write parameter len = %d\n\r", (INT32) len); + if (len >= osal_sizeof(buf)) { + WMT_ERR_FUNC("input handling fail!\n"); + len = osal_sizeof(buf) - 1; + return -1; + } + + if (copy_from_user(buf, buffer, len)) + return -EFAULT; + + buf[len] = '\0'; + WMT_INFO_FUNC("write parameter data = %s\n\r", buf); + + pBuf = buf; + pToken = osal_strsep(&pBuf, pDelimiter); + if (pToken != NULL) { + osal_strtol(pToken, 16, &res); + x = (INT32)res; + } else { + x = 0; + } + + pToken = osal_strsep(&pBuf, "\t\n "); + if (pToken != NULL) { + osal_strtol(pToken, 16, &res); + y = (INT32)res; + WMT_INFO_FUNC("y = 0x%08x\n\r", y); + } else { + y = 3000; + /*efuse, register read write default value */ + if (0x11 == x || 0x12 == x || 0x13 == x) + y = 0x80000000; + } + + pToken = osal_strsep(&pBuf, "\t\n "); + if (pToken != NULL) { + if (0x2f == x) + z = osal_strcmp(pToken, "true") ? 0 : 1; + else { + osal_strtol(pToken, 16, &res); + z = (INT32)res; + } + } else { + z = 10; + /*efuse, register read write default value */ + if (0x11 == x || 0x12 == x || 0x13 == x) + z = 0xffffffff; + } + + WMT_INFO_FUNC("x(0x%08x), y(0x%08x), z(0x%08x)\n\r", x, y, z); + + /* For eng and userdebug load, have to enable wmt_dbg by writing 0xDB9DB9 to + * "/proc/driver/wmt_dbg" to avoid some malicious use + */ +#if (WMT_DBG_SUPPORT) + if (0xDB9DB9 == x) { + dbgEnabled = 1; + return len; + } +#endif + /* Commands allowed to execute in user load + * 0x15: assert control + * 0x2e: enable catch connsys log + * 0x2f: set bt link status + */ + if (0 == dbgEnabled && 0x15 != x && 0x2e != x && 0x2f != x && 0x7 != x) { + WMT_INFO_FUNC("please enable WMT debug first\n\r"); + return len; + } + + if (osal_array_size(wmt_dev_dbg_func) > x && NULL != wmt_dev_dbg_func[x]) + if (x == 0x7) + wmt_dbg_delay_work(x, y, z); + else + (*wmt_dev_dbg_func[x]) (x, y, z); + else + WMT_WARN_FUNC("no handler defined for command id(0x%08x)\n\r", x); + + return len; +} + +INT32 wmt_dev_dbg_setup(VOID) +{ + static const struct proc_ops wmt_dbg_fops = { + .proc_read = wmt_dbg_read, + .proc_write = wmt_dbg_write, + }; + INT32 i_ret = 0; + + gWmtDbgEntry = proc_create(WMT_DBG_PROCNAME, 0664, NULL, &wmt_dbg_fops); + if (gWmtDbgEntry == NULL) { + WMT_ERR_FUNC("Unable to create / wmt_aee proc entry\n\r"); + i_ret = -1; + } + osal_sleepable_lock_init(&g_dbg_emi_lock); + + return i_ret; +} + +INT32 wmt_dev_dbg_remove(VOID) +{ + if (gWmtDbgEntry != NULL) + proc_remove(gWmtDbgEntry); + + osal_sleepable_lock_deinit(&g_dbg_emi_lock); + +#if CFG_WMT_PS_SUPPORT + wmt_lib_ps_deinit(); +#endif + return 0; +} + +INT32 wmt_dbg_gps_suspend(INT32 par1, INT32 par2, INT32 par3) +{ + MTK_WCN_BOOL suspend = (par2 != 0) ? MTK_WCN_BOOL_TRUE : MTK_WCN_BOOL_FALSE; + + WMT_INFO_FUNC("GPS %s mode test\n", (par2 != 0) ? "suspend" : "resume"); + mtk_wmt_gps_suspend_ctrl(suspend); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/wmt_dev.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/wmt_dev.c new file mode 100644 index 00000000000000..fcbfc9871cb7c5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/wmt_dev.c @@ -0,0 +1,1997 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief brief description + * + * Detailed descriptions here. + * + */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-DEV]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#ifdef CONFIG_COMPAT +#include <linux/compat.h> +#endif +#include <linux/ctype.h> +#if WMT_CREATE_NODE_DYNAMIC +#include <linux/device.h> +#endif +#ifdef CONFIG_EARLYSUSPEND +#include <linux/earlysuspend.h> +#else +#include <linux/fb.h> +#endif +#include <linux/proc_fs.h> +#include <mtk_wcn_cmb_stub.h> +#include "osal_typedef.h" +#include "osal.h" +#include "wmt_dev.h" +#include "wmt_core.h" +#include "wmt_exp.h" +#include "wmt_lib.h" +#include "wmt_conf.h" +#include "wmt_dbg.h" +#include "psm_core.h" +#include "stp_core.h" +#include "stp_exp.h" +#include "stp_sdio.h" +#include "bgw_desense.h" +#include "wmt_idc.h" +#include "wmt_detect.h" +#include "hif_sdio.h" +#include "wmt_step.h" + +#include "connsys_debug_utility.h" + +#ifdef CONFIG_COMPAT +#define COMPAT_WMT_IOCTL_SET_PATCH_NAME _IOW(WMT_IOC_MAGIC, 4, compat_uptr_t) +#define COMPAT_WMT_IOCTL_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 8, compat_uptr_t) +#define COMPAT_WMT_IOCTL_SET_PATCH_INFO _IOW(WMT_IOC_MAGIC, 15, compat_uptr_t) +#define COMPAT_WMT_IOCTL_PORT_NAME _IOWR(WMT_IOC_MAGIC, 20, compat_uptr_t) +#define COMPAT_WMT_IOCTL_WMT_CFG_NAME _IOWR(WMT_IOC_MAGIC, 21, compat_uptr_t) +#define COMPAT_WMT_IOCTL_SEND_BGW_DS_CMD _IOW(WMT_IOC_MAGIC, 25, compat_uptr_t) +#define COMPAT_WMT_IOCTL_ADIE_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 26, compat_uptr_t) +#define COMPAT_WMT_IOCTL_DYNAMIC_DUMP_CTRL _IOR(WMT_IOC_MAGIC, 30, compat_uptr_t) +#define COMPAT_WMT_IOCTL_SET_ROM_PATCH_INFO _IOW(WMT_IOC_MAGIC, 31, compat_uptr_t) +#define COMPAT_WMT_IOCTL_GET_VENDOR_PATCH_VERSION _IOR(WMT_IOC_MAGIC, 36, compat_uptr_t) +#define COMPAT_WMT_IOCTL_SET_VENDOR_PATCH_VERSION _IOW(WMT_IOC_MAGIC, 37, compat_uptr_t) +#define COMPAT_WMT_IOCTL_SET_ACTIVE_PATCH_VERSION _IOR(WMT_IOC_MAGIC, 40, compat_uptr_t) +#define COMPAT_WMT_IOCTL_GET_ACTIVE_PATCH_VERSION _IOR(WMT_IOC_MAGIC, 41, compat_uptr_t) +#endif + +#define WMT_IOC_MAGIC 0xa0 +#define WMT_IOCTL_SET_PATCH_NAME _IOW(WMT_IOC_MAGIC, 4, char*) +#define WMT_IOCTL_SET_STP_MODE _IOW(WMT_IOC_MAGIC, 5, int) +#define WMT_IOCTL_FUNC_ONOFF_CTRL _IOW(WMT_IOC_MAGIC, 6, int) +#define WMT_IOCTL_LPBK_POWER_CTRL _IOW(WMT_IOC_MAGIC, 7, int) +#define WMT_IOCTL_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 8, char*) +#define WMT_IOCTL_GET_CHIP_INFO _IOR(WMT_IOC_MAGIC, 12, int) +#define WMT_IOCTL_SET_LAUNCHER_KILL _IOW(WMT_IOC_MAGIC, 13, int) +#define WMT_IOCTL_SET_PATCH_NUM _IOW(WMT_IOC_MAGIC, 14, int) +#define WMT_IOCTL_SET_PATCH_INFO _IOW(WMT_IOC_MAGIC, 15, char*) +#define WMT_IOCTL_PORT_NAME _IOWR(WMT_IOC_MAGIC, 20, char*) +#define WMT_IOCTL_WMT_CFG_NAME _IOWR(WMT_IOC_MAGIC, 21, char*) +#define WMT_IOCTL_WMT_QUERY_CHIPID _IOR(WMT_IOC_MAGIC, 22, int) +#define WMT_IOCTL_WMT_TELL_CHIPID _IOW(WMT_IOC_MAGIC, 23, int) +#define WMT_IOCTL_WMT_COREDUMP_CTRL _IOW(WMT_IOC_MAGIC, 24, int) +#define WMT_IOCTL_SEND_BGW_DS_CMD _IOW(WMT_IOC_MAGIC, 25, char*) +#define WMT_IOCTL_ADIE_LPBK_TEST _IOWR(WMT_IOC_MAGIC, 26, char*) +#define WMT_IOCTL_WMT_STP_ASSERT_CTRL _IOW(WMT_IOC_MAGIC, 27, int) +#define WMT_IOCTL_FW_DBGLOG_CTRL _IOR(WMT_IOC_MAGIC, 29, int) +#define WMT_IOCTL_DYNAMIC_DUMP_CTRL _IOR(WMT_IOC_MAGIC, 30, char*) +#define WMT_IOCTL_SET_ROM_PATCH_INFO _IOW(WMT_IOC_MAGIC, 31, char*) +#define WMT_IOCTL_GET_EMI_PHY_SIZE _IOR(WMT_IOC_MAGIC, 33, unsigned int) +#define WMT_IOCTL_FW_PATCH_UPDATE_RST _IOR(WMT_IOC_MAGIC, 34, int) +#define WMT_IOCTL_GET_VENDOR_PATCH_NUM _IOW(WMT_IOC_MAGIC, 35, int) +#define WMT_IOCTL_GET_VENDOR_PATCH_VERSION _IOR(WMT_IOC_MAGIC, 36, char*) +#define WMT_IOCTL_SET_VENDOR_PATCH_VERSION _IOW(WMT_IOC_MAGIC, 37, char*) +#define WMT_IOCTL_GET_CHECK_PATCH_STATUS _IOR(WMT_IOC_MAGIC, 38, int) +#define WMT_IOCTL_SET_CHECK_PATCH_STATUS _IOW(WMT_IOC_MAGIC, 39, int) +#define WMT_IOCTL_SET_ACTIVE_PATCH_VERSION _IOR(WMT_IOC_MAGIC, 40, char*) +#define WMT_IOCTL_GET_ACTIVE_PATCH_VERSION _IOR(WMT_IOC_MAGIC, 41, char*) +#define WMT_IOCTL_GET_DIRECT_PATH_EMI_SIZE _IOR(WMT_IOC_MAGIC, 42, unsigned int) + +#define MTK_WMT_VERSION "Consys WMT Driver - v1.0" +#define MTK_WMT_DATE "2013/01/20" +#define WMT_DEV_MAJOR 190 /* never used number */ +#define WMT_DEV_NUM 1 +#define WMT_DEV_INIT_TO_MS (2 * 1000) +#define DYNAMIC_DUMP_BUF 109 + +#define WMT_DRIVER_NAME "mtk_stp_wmt" + +P_OSAL_EVENT gpRxEvent; + +UINT32 u4RxFlag; +static atomic_t gRxCount = ATOMIC_INIT(0); + +/* Linux UINT8 device */ +static INT32 gWmtMajor = WMT_DEV_MAJOR; +static struct cdev gWmtCdev; +static atomic_t gWmtRefCnt = ATOMIC_INIT(0); +/* WMT driver information */ +static UINT8 gLpbkBuf[WMT_LPBK_BUF_LEN] = { 0 }; + +static UINT32 gLpbkBufLog; /* George LPBK debug */ + +enum wmt_init_status { + WMT_INIT_NOT_START, + WMT_INIT_START, + WMT_INIT_DONE, +}; +static INT32 gWmtInitStatus = WMT_INIT_NOT_START; +static wait_queue_head_t gWmtInitWq; +#ifdef CONFIG_MTK_COMBO_COMM_APO +UINT32 always_pwr_on_flag = 1; +#else +UINT32 always_pwr_on_flag; +#endif +P_WMT_PATCH_INFO pPatchInfo; +UINT32 pAtchNum; +UINT32 currentLpbkStatus; +#define TEMP_THRESHOLD 60 +static INT32 gTemperatureThreshold = TEMP_THRESHOLD; + + +#if CFG_WMT_PROC_FOR_AEE +static struct proc_dir_entry *gWmtAeeEntry; +#define WMT_AEE_PROCNAME "driver/wmt_aee" +#define WMT_PROC_AEE_SIZE 3072 +static UINT32 g_buf_len; +static PUINT8 pBuf; +#endif + +#if CFG_WMT_PROC_FOR_DUMP_INFO +static struct proc_dir_entry *gWmtdumpinfoEntry; +#define WMT_DUMP_INFO_PROCNAME "driver/wmt_dump_info" +static UINT32 g_dump_info_buf_len; +static PUINT8 dump_info_pBuf; +#endif + +#if WMT_CREATE_NODE_DYNAMIC +struct class *wmt_class; +struct device *wmt_dev; +#endif + + +/*LCM on/off ctrl for wmt varabile*/ +UINT32 hif_info; +UINT8 gWmtClose; +static struct work_struct gPwrOnOffWork; +static atomic_t g_es_lr_flag_for_quick_sleep = ATOMIC_INIT(1); /* for ctrl quick sleep flag */ +static atomic_t g_es_lr_flag_for_lpbk_onoff = ATOMIC_INIT(0); /* for ctrl lpbk on off */ + +/*BLANK on/off ctrl for wmt varabile*/ +static atomic_t g_es_lr_flag_for_blank = ATOMIC_INIT(0); /* for ctrl blank flag */ +static atomic_t g_late_pwr_on_for_blank = ATOMIC_INIT(0); /* PwrOnOff Late flag */ + +/* Prevent race condition when wmt_dev_tm_temp_query is called concurrently */ +static OSAL_UNSLEEPABLE_LOCK g_temp_query_spinlock; +static OSAL_SLEEPABLE_LOCK g_aee_read_lock; +static OSAL_SLEEPABLE_LOCK g_dump_info_read_lock; + +phys_addr_t gConEmiPhyBase; +EXPORT_SYMBOL(gConEmiPhyBase); + +unsigned long long gConEmiSize; +EXPORT_SYMBOL(gConEmiSize); + +#ifdef CONFIG_EARLYSUSPEND +static VOID wmt_dev_early_suspend(struct early_suspend *h) +{ + atomic_set(&g_es_lr_flag_for_quick_sleep, 1); + atomic_set(&g_es_lr_flag_for_lpbk_onoff, 0); + atomic_set(&g_es_lr_flag_for_blank, 0); + + WMT_WARN_FUNC("@@@@@@@@@@wmt enter early suspend@@@@@@@@@@@@@@\n"); + + schedule_work(&gPwrOnOffWork); +} + +static VOID wmt_dev_late_resume(struct early_suspend *h) +{ + atomic_set(&g_es_lr_flag_for_quick_sleep, 0); + atomic_set(&g_es_lr_flag_for_lpbk_onoff, 1); + atomic_set(&g_es_lr_flag_for_blank, 1); + + WMT_WARN_FUNC("@@@@@@@@@@wmt enter late resume@@@@@@@@@@@@@@\n"); + + schedule_work(&gPwrOnOffWork); + +} + +struct early_suspend wmt_early_suspend_handler = { + .suspend = wmt_dev_early_suspend, + .resume = wmt_dev_late_resume, +}; + +#else + +static struct notifier_block wmt_fb_notifier; +static INT32 wmt_fb_notifier_callback(struct notifier_block *self, ULONG event, PVOID data) +{ + struct fb_event *evdata = data; + INT32 blank; + + WMT_DBG_FUNC("wmt_fb_notifier_callback\n"); + + /* If we aren't interested in this event, skip it immediately ... */ + if (event != FB_EVENT_BLANK) + return 0; + + blank = *(INT32 *)evdata->data; + WMT_DBG_FUNC("fb_notify(blank=%d)\n", blank); + + switch (blank) { + case FB_BLANK_UNBLANK: + atomic_set(&g_es_lr_flag_for_quick_sleep, 0); + atomic_set(&g_es_lr_flag_for_lpbk_onoff, 1); + atomic_set(&g_es_lr_flag_for_blank, 1); + WMT_WARN_FUNC("@@@@@@@@@@wmt enter UNBLANK @@@@@@@@@@@@@@\n"); + if (hif_info == 0) { + atomic_set(&g_late_pwr_on_for_blank, 1); + break; + } + schedule_work(&gPwrOnOffWork); + break; + case FB_BLANK_POWERDOWN: + atomic_set(&g_es_lr_flag_for_quick_sleep, 1); + atomic_set(&g_es_lr_flag_for_lpbk_onoff, 0); + atomic_set(&g_es_lr_flag_for_blank, 0); + WMT_WARN_FUNC("@@@@@@@@@@wmt enter early POWERDOWN @@@@@@@@@@@@@@\n"); + schedule_work(&gPwrOnOffWork); + break; + default: + break; + } + return 0; +} +#endif /* CONFIG_EARLYSUSPEND */ +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +INT32 wmt_dev_apo_ctrl(UINT32 enable) +{ + always_pwr_on_flag = enable ? 1 : 0; + if (!always_pwr_on_flag) + schedule_work(&gPwrOnOffWork); + WMT_INFO_FUNC("always_pwr_on_flag: %d\n", always_pwr_on_flag); + + return 0; +} + +static VOID wmt_pwr_on_off_handler(struct work_struct *work) +{ + INT32 retry = 5; + INT32 desync = 0; + + WMT_DBG_FUNC("wmt_pwr_on_off_handler start to run\n"); + + /* Update blank off status before wmt power off */ + if (wmt_dev_get_blank_state() == 0) { + wmt_dev_blank_handler(); + connsys_log_blank_state_changed(0); + } + + if (always_pwr_on_flag == 0) { + while ((wmt_lib_get_drv_status(WMTDRV_TYPE_LPBK) == DRV_STS_FUNC_ON) != + atomic_read(&g_es_lr_flag_for_lpbk_onoff)) { + if (++desync > 1) + WMT_WARN_FUNC("suspend/resume not sync count:%d\n", desync); + if (wmt_lpbk_handler(atomic_read(&g_es_lr_flag_for_lpbk_onoff), retry) < 0) + break; + } + } + + /* Update blank on status after wmt power on */ + if (wmt_dev_get_blank_state() == 1) { + wmt_dev_blank_handler(); + connsys_log_blank_state_changed(1); + } +} + +INT32 wmt_lpbk_handler(UINT32 on_off_flag, UINT32 retry) +{ + UINT32 retry_count; + + retry_count = retry; + do { + if (on_off_flag) { + if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_LPBK) == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("WMT turn on LPBK fail, retrying, retryCounter left:%d!\n", + retry_count); + retry_count--; + osal_sleep_ms(1000); + } else { + WMT_DBG_FUNC("WMT turn on LPBK suceed\n"); + break; + } + } else { + if (mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK) == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("WMT turn off LPBK fail, retrying, retryCounter left:%d!\n", + retry_count); + retry_count--; + osal_sleep_ms(1000); + } else { + WMT_DBG_FUNC("WMT turn off LPBK suceed\n"); + break; + } + } + } while (retry_count > 0); + return ((wmt_lib_get_drv_status(WMTDRV_TYPE_LPBK) == DRV_STS_FUNC_ON) == on_off_flag) - 1; +} + +VOID wmt_dev_blank_handler(VOID) +{ + WMT_DBG_FUNC("wmt_dev_blank_handler start to run\n"); + + if (wmt_lib_get_blank_status() != wmt_dev_get_blank_state()) + if (wmt_lib_blank_status_ctrl(wmt_dev_get_blank_state())) + WMT_WARN_FUNC("mtk_lib_blank_status_ctrl failed\n"); +} + +UINT32 wmt_dev_get_blank_state(VOID) +{ + return atomic_read(&g_es_lr_flag_for_blank); +} + +MTK_WCN_BOOL wmt_dev_get_early_suspend_state(VOID) +{ + MTK_WCN_BOOL bRet = + (atomic_read(&g_es_lr_flag_for_quick_sleep) == 0) ? MTK_WCN_BOOL_FALSE : MTK_WCN_BOOL_TRUE; + /* WMT_INFO_FUNC("bRet:%d\n", bRet); */ + return bRet; +} + +#if CFG_WMT_PROC_FOR_AEE +static ssize_t wmt_dev_proc_for_aee_read(struct file *filp, char __user *buf, size_t count, + loff_t *f_pos) +{ + INT32 retval = 0; + UINT32 len = 0; + + WMT_INFO_FUNC("%s: count %zu pos %lld\n", __func__, count, *f_pos); + + if (osal_lock_sleepable_lock(&g_aee_read_lock)) { + WMT_ERR_FUNC("lock failed\n"); + return 0; + } + + if (*f_pos == 0) { + pBuf = wmt_lib_get_cpupcr_xml_format(&len); + g_buf_len = len; + WMT_INFO_FUNC("wmt_dev:wmt for aee buffer len(%d)\n", g_buf_len); + } + + if (g_buf_len >= count) { + retval = copy_to_user(buf, pBuf, count); + if (retval) { + WMT_ERR_FUNC("copy to aee buffer failed, ret:%d\n", retval); + retval = -EFAULT; + goto err_exit; + } + + *f_pos += count; + g_buf_len -= count; + pBuf += count; + WMT_INFO_FUNC("wmt_dev:after read,wmt for aee buffer len(%d)\n", g_buf_len); + + retval = count; + } else if (g_buf_len != 0) { + retval = copy_to_user(buf, pBuf, g_buf_len); + if (retval) { + WMT_ERR_FUNC("copy to aee buffer failed, ret:%d\n", retval); + retval = -EFAULT; + goto err_exit; + } + + *f_pos += g_buf_len; + len = g_buf_len; + g_buf_len = 0; + pBuf += len; + retval = len; + WMT_INFO_FUNC("wmt_dev:after read,wmt for aee buffer len(%d)\n", g_buf_len); + } else { + WMT_INFO_FUNC("wmt_dev: no data available for aee\n"); + retval = 0; + } + +err_exit: + osal_unlock_sleepable_lock(&g_aee_read_lock); + + return retval; +} + +static ssize_t wmt_dev_proc_for_aee_write(struct file *filp, const char __user *buf, size_t count, + loff_t *f_pos) +{ + WMT_TRC_FUNC(); + return 0; +} + +static INT32 wmt_dev_proc_for_aee_setup(VOID) +{ + static const struct proc_ops wmt_aee_fops = { + .proc_read = wmt_dev_proc_for_aee_read, + .proc_write = wmt_dev_proc_for_aee_write, + }; + + gWmtAeeEntry = proc_create(WMT_AEE_PROCNAME, 0664, NULL, &wmt_aee_fops); + if (gWmtAeeEntry == NULL) { + WMT_ERR_FUNC("Unable to create /proc entry\n\r"); + return -1; + } + + return 0; +} + +static INT32 wmt_dev_proc_for_aee_remove(VOID) +{ + if (gWmtAeeEntry != NULL) + remove_proc_entry(WMT_AEE_PROCNAME, NULL); + + return 0; +} +#endif /* CFG_WMT_PROC_FOR_AEE */ + +#if CFG_WMT_PROC_FOR_DUMP_INFO +static ssize_t wmt_dev_proc_for_dump_info_read(struct file *filp, char __user *buf, size_t count, + loff_t *f_pos) +{ + INT32 retval = 0; + UINT32 len = 0; + + WMT_INFO_FUNC("%s: count %zu pos %lld\n", __func__, count, *f_pos); + + if (osal_lock_sleepable_lock(&g_dump_info_read_lock)) { + WMT_ERR_FUNC("lock failed\n"); + return 0; + } + + if (*f_pos == 0) { + dump_info_pBuf = wmt_lib_get_cpupcr_reg_info(&len, mtk_wcn_consys_read_dump_info_reg()); + g_dump_info_buf_len = len; + WMT_INFO_FUNC("wmt_dev:wmt for dump info buffer len(%d)\n", g_dump_info_buf_len); + } + + if (g_dump_info_buf_len >= count) { + retval = copy_to_user(buf, dump_info_pBuf, count); + if (retval) { + WMT_ERR_FUNC("copy to dump info buffer failed, ret:%d\n", retval); + retval = -EFAULT; + goto dump_info_err_exit; + } + + *f_pos += count; + g_dump_info_buf_len -= count; + dump_info_pBuf += count; + WMT_INFO_FUNC("wmt_dev:after read,wmt for dump info buffer len(%d)\n", g_dump_info_buf_len); + + retval = count; + } else if (g_dump_info_buf_len != 0) { + retval = copy_to_user(buf, dump_info_pBuf, g_dump_info_buf_len); + if (retval) { + WMT_ERR_FUNC("copy to dump info buffer failed, ret:%d\n", retval); + retval = -EFAULT; + goto dump_info_err_exit; + } + + *f_pos += g_dump_info_buf_len; + len = g_dump_info_buf_len; + g_dump_info_buf_len = 0; + dump_info_pBuf += len; + retval = len; + WMT_INFO_FUNC("wmt_dev:after read,wmt for dump info buffer len(%d)\n", g_dump_info_buf_len); + } else { + WMT_INFO_FUNC("wmt_dev: no data available for dump info\n"); + retval = 0; + } + +dump_info_err_exit: + osal_unlock_sleepable_lock(&g_dump_info_read_lock); + + return retval; +} + +static ssize_t wmt_dev_proc_for_dump_info_write(struct file *filp, const char __user *buf, size_t count, + loff_t *f_pos) +{ + WMT_TRC_FUNC(); + return 0; +} + +static INT32 wmt_dev_proc_for_dump_info_setup(VOID) +{ + static const struct proc_ops wmt_dump_info_fops = { + .proc_read = wmt_dev_proc_for_dump_info_read, + .proc_write = wmt_dev_proc_for_dump_info_write, + }; + + gWmtdumpinfoEntry = proc_create(WMT_DUMP_INFO_PROCNAME, 0664, NULL, &wmt_dump_info_fops); + if (gWmtdumpinfoEntry == NULL) { + WMT_ERR_FUNC("Unable to create /proc entry\n\r"); + return -1; + } + + return 0; +} + +static INT32 wmt_dev_proc_for_dump_info_remove(VOID) +{ + if (gWmtdumpinfoEntry != NULL) + remove_proc_entry(WMT_DUMP_INFO_PROCNAME, NULL); + + return 0; +} +#endif /* CFG_WMT_PROC_FOR_DUMP_INFO */ + +VOID wmt_dev_rx_event_cb(VOID) +{ + u4RxFlag = 1; + atomic_inc(&gRxCount); + if (gpRxEvent != NULL) { + /* u4RxFlag = 1; */ + /* atomic_inc(&gRxCount); */ + wake_up_interruptible(&gpRxEvent->waitQueue); + } else { + /* WMT_ERR_FUNC("null gpRxEvent, flush rx!\n"); */ + /* wmt_lib_flush_rx(); */ + } +} + +INT32 wmt_dev_rx_timeout(P_OSAL_EVENT pEvent) +{ + UINT32 ms = pEvent->timeoutValue; + LONG lRet = 0; + + gpRxEvent = pEvent; + if (ms != 0) + lRet = wait_event_interruptible_timeout(gpRxEvent->waitQueue, 0 != u4RxFlag, + msecs_to_jiffies(ms)); + else + lRet = wait_event_interruptible(gpRxEvent->waitQueue, u4RxFlag != 0); + + u4RxFlag = 0; +/* gpRxEvent = NULL; */ + if (atomic_dec_return(&gRxCount)) { + WMT_ERR_FUNC("gRxCount != 0 (%d), reset it!\n", atomic_read(&gRxCount)); + atomic_set(&gRxCount, 0); + } + + return lRet; +} + +/* TODO: [ChangeFeature][George] refine this function name for general filesystem read operation, not patch only. */ +INT32 wmt_dev_patch_get(PUINT8 pPatchName, osal_firmware **ppPatch) +{ + INT32 iRet = -1; + osal_firmware *fw = NULL; + + if (!ppPatch) { + WMT_ERR_FUNC("invalid ppBufptr!\n"); + return -1; + } + *ppPatch = NULL; + do { + iRet = request_firmware((const struct firmware **)&fw, pPatchName, NULL); + if (iRet == -EAGAIN) { + WMT_ERR_FUNC("failed to open or read!(%s), retry again!\n", pPatchName); + osal_sleep_ms(100); + } + } while (iRet == -EAGAIN); + if (iRet != 0) { + WMT_ERR_FUNC("failed to open or read!(%s)\n", pPatchName); + release_firmware(fw); + return -1; + } + WMT_DBG_FUNC("loader firmware %s ok!!\n", pPatchName); + iRet = 0; + *ppPatch = fw; + + return iRet; +} +EXPORT_SYMBOL(wmt_dev_patch_get); + +INT32 wmt_dev_patch_put(osal_firmware **ppPatch) +{ + if (*ppPatch != NULL) { + release_firmware((const struct firmware *)*ppPatch); + *ppPatch = NULL; + } + return 0; +} + +VOID wmt_dev_patch_info_free(VOID) +{ + kfree(pPatchInfo); + pPatchInfo = NULL; + wmt_lib_set_patch_info(NULL); +} + +MTK_WCN_BOOL wmt_dev_is_file_exist(PUINT8 pFileName) +{ + INT32 iRet = 0; + osal_firmware *fw = NULL; + + if (pFileName == NULL) { + WMT_ERR_FUNC("invalid file name pointer(%p)\n", pFileName); + return MTK_WCN_BOOL_FALSE; + } + + if (osal_strlen(pFileName) < osal_strlen(defaultPatchName)) { + WMT_ERR_FUNC("invalid file name(%s)\n", pFileName); + return MTK_WCN_BOOL_FALSE; + } + + iRet = request_firmware((const struct firmware **)&fw, pFileName, NULL); + if (iRet != 0) { + WMT_ERR_FUNC("failed to open or read!(%s)\n", pFileName); + release_firmware(fw); + return MTK_WCN_BOOL_FALSE; + } + release_firmware(fw); + return true; +} + +static ULONG count_last_access_sdio; +static ULONG count_last_access_btif; +static ULONG count_last_access_uart; +static ULONG jiffies_last_poll; + +static INT32 wmt_dev_tra_sdio_update(VOID) +{ + count_last_access_sdio += 1; + /* WMT_INFO_FUNC("jiffies_last_access_sdio: jiffies = %ul\n", jiffies); */ + + return 0; +} + +INT32 wmt_dev_tra_bitf_update(VOID) +{ + count_last_access_btif += 1; + /* WMT_INFO_FUNC("jiffies_last_access_btif: jiffies = %ul\n", jiffies); */ + + return 0; +} +EXPORT_SYMBOL(wmt_dev_tra_bitf_update); + +INT32 wmt_dev_tra_uart_update(VOID) +{ + count_last_access_uart += 1; + /* WMT_INFO_FUNC("jiffies_last_access_btif: jiffies = %ul\n", jiffies); */ + + return 0; +} +EXPORT_SYMBOL(wmt_dev_tra_uart_update); + +static UINT32 wmt_dev_tra_poll(VOID) +{ +#define TIME_THRESHOLD_TO_TEMP_QUERY 3000 +#define COUNT_THRESHOLD_TO_TEMP_QUERY 200 + + ULONG during_count = 0; + ULONG poll_during_time = 0; + ENUM_WMT_CHIP_TYPE chip_type; + + chip_type = wmt_detect_get_chip_type(); + /* if (jiffies > jiffies_last_poll) */ + if (time_after(jiffies, jiffies_last_poll)) + poll_during_time = jiffies - jiffies_last_poll; + else + poll_during_time = 0xffffffff; + + WMT_DBG_FUNC("**jiffies_to_mesecs(0xffffffff) = %d\n", jiffies_to_msecs(0xffffffff)); + + if (jiffies_to_msecs(poll_during_time) < TIME_THRESHOLD_TO_TEMP_QUERY) { + WMT_DBG_FUNC("**poll_during_time = %d < %d, not to query\n", + jiffies_to_msecs(poll_during_time), TIME_THRESHOLD_TO_TEMP_QUERY); + return -1; + } + + switch (chip_type) { + case WMT_CHIP_TYPE_COMBO: + during_count = count_last_access_sdio; + break; + case WMT_CHIP_TYPE_SOC: + if (mtk_wcn_wlan_bus_tx_cnt == NULL) { + WMT_ERR_FUNC("WMT-DEV:mtk_wcn_wlan_bus_tx_cnt null pointer\n"); + return -1; + } + if (mtk_wcn_wlan_bus_tx_cnt_clr == NULL) { + WMT_ERR_FUNC("WMT-DEV:mtk_wcn_wlan_bus_tx_cnt_clr null pointer\n"); + return -3; + } + during_count = (*mtk_wcn_wlan_bus_tx_cnt)(); + break; + default: + WMT_ERR_FUNC("WMT-DEV:error chip type(%d)\n", chip_type); + } + + if (during_count < COUNT_THRESHOLD_TO_TEMP_QUERY) { + WMT_DBG_FUNC("**during_count = %lu < %d, not to query\n", during_count, + COUNT_THRESHOLD_TO_TEMP_QUERY); + return -2; + } + + jiffies_last_poll = jiffies; + if (chip_type == WMT_CHIP_TYPE_COMBO) + count_last_access_sdio = 0; + else if (chip_type == WMT_CHIP_TYPE_SOC) + (*mtk_wcn_wlan_bus_tx_cnt_clr)(); + else + WMT_ERR_FUNC("WMT-DEV:error chip type(%d)\n", chip_type); + WMT_INFO_FUNC("**poll_during_time = %d > %d, during_count = %d > %d, query\n", + jiffies_to_msecs(poll_during_time), TIME_THRESHOLD_TO_TEMP_QUERY, + jiffies_to_msecs(during_count), COUNT_THRESHOLD_TO_TEMP_QUERY); + + return 0; +} + +VOID wmt_dev_set_temp_threshold(INT32 val) +{ + gTemperatureThreshold = val; + WMT_INFO_FUNC("Set temperature threashold to %d\n", val); +} + +LONG wmt_dev_tm_temp_query(VOID) +{ +#define HISTORY_NUM 3 +#define REFRESH_TIME 300 /* sec */ + + static INT32 s_temp_table[HISTORY_NUM] = { 99 }; /* not query yet. */ + static INT32 s_idx_temp_table; + static struct timespec64 s_query_time; + + INT32 temp_table[HISTORY_NUM]; + INT32 idx_temp_table; + struct timespec64 query_time; + + struct timespec64 now_time; + INT32 current_temp = 0; + INT32 index = 0; + LONG return_temp = 0; + INT8 query_cond = 0; + + /* Let us work on the copied version of function static variables */ + osal_lock_unsleepable_lock(&g_temp_query_spinlock); + osal_memcpy(temp_table, s_temp_table, sizeof(s_temp_table)); + osal_memcpy(&query_time, &s_query_time, sizeof(struct timespec64)); + idx_temp_table = s_idx_temp_table; + osal_unlock_unsleepable_lock(&g_temp_query_spinlock); + + /* Query condition 1: */ + /* If we have the high temperature records on the past, we continue to query/monitor */ + /* the real temperature until cooling */ + for (index = 0; index < HISTORY_NUM; index++) { + if (temp_table[index] >= gTemperatureThreshold) { + query_cond = 1; + WMT_DBG_FUNC + ("temperature table is still initial value, we should query temp temperature..\n"); + } + } + + ktime_get_ts64(&now_time); +#if 1 + /* Query condition 2: */ + /* Moniter the bus activity to decide if we have the need to query temperature. */ + if (!query_cond) { + if (wmt_dev_tra_poll() == 0) { + query_cond = 1; + WMT_DBG_FUNC("traffic , we must query temperature..\n"); + } else if (temp_table[idx_temp_table] >= gTemperatureThreshold) { + WMT_INFO_FUNC("temperature maybe greater than %d, query temperature\n", gTemperatureThreshold); + query_cond = 1; + } else + WMT_DBG_FUNC("idle traffic ....\n"); + + /* only WIFI tx power might make temperature varies largely */ +#if 0 + if (!query_cond) { + last_access_time = wmt_dev_tra_uart_poll(); + if (jiffies_to_msecs(last_access_time) < TIME_THRESHOLD_TO_TEMP_QUERY) { + query_cond = 1; + WMT_DBG_FUNC("uart busy traffic , we must query temperature..\n"); + } else { + WMT_DBG_FUNC("uart still idle traffic , we don't query temp temperature..\n"); + } + } +#endif + } +#endif + /* Query condition 3: */ + /* If the query time exceeds the a certain of period, refresh temp table. */ + /* */ + if (!query_cond) { + /* time overflow, we refresh temp table again for simplicity! */ + if ((now_time.tv_sec < query_time.tv_sec) || + ((now_time.tv_sec > query_time.tv_sec) && + (now_time.tv_sec - query_time.tv_sec) > REFRESH_TIME)) { + query_cond = 1; + + WMT_INFO_FUNC + ("It is long time (prev(%lu), now(%lu), > %d sec) not to query, query temp again..\n", + query_time.tv_sec, now_time.tv_sec, REFRESH_TIME); + for (index = 0; index < HISTORY_NUM; index++) + temp_table[index] = 99; + + } + } + + if (query_cond) { + /* update the temperature record */ + mtk_wcn_wmt_therm_ctrl(WMTTHERM_ENABLE); + current_temp = mtk_wcn_wmt_therm_ctrl(WMTTHERM_READ); + mtk_wcn_wmt_therm_ctrl(WMTTHERM_DISABLE); + + /* Only update temperature if our index hasn't been modified by the concurrent thread */ + osal_lock_unsleepable_lock(&g_temp_query_spinlock); + if (idx_temp_table == s_idx_temp_table) { + osal_memcpy(s_temp_table, temp_table, sizeof(s_temp_table)); + s_idx_temp_table = (s_idx_temp_table + 1) % HISTORY_NUM; + s_temp_table[s_idx_temp_table] = current_temp; + ktime_get_ts64(&s_query_time); + index = -1; + } else { + index = s_idx_temp_table; + } + osal_unlock_unsleepable_lock(&g_temp_query_spinlock); + + if (index == -1) { + WMT_INFO_FUNC("[Thermal] current_temp = 0x%x\n", (current_temp & 0xFF)); + } else { + WMT_ERR_FUNC("Temperature(0x%x) update failed due to modified idx_temp_table(%d, %d)", + (current_temp & 0xFF), idx_temp_table, index); + } + } else { + /* Only update temperature if our index hasn't been modified by the concurrent thread */ + osal_lock_unsleepable_lock(&g_temp_query_spinlock); + if (idx_temp_table == s_idx_temp_table) { + current_temp = s_temp_table[s_idx_temp_table]; + s_idx_temp_table = (s_idx_temp_table + 1) % HISTORY_NUM; + s_temp_table[s_idx_temp_table] = current_temp; + index = -1; + } else { + /* Return the last valid temperature which has just been modified by the concurrent thread */ + current_temp = s_temp_table[s_idx_temp_table]; + index = s_idx_temp_table; + } + osal_unlock_unsleepable_lock(&g_temp_query_spinlock); + if (index != -1) { + WMT_DBG_FUNC("Use last valid temperature (0x%x) due to modified idx_temp_table(%d, %d)", + (current_temp & 0xFF), idx_temp_table, index); + } + } + + /* */ + /* Dump information */ + /* */ + if (gWmtDbgLvl >= WMT_LOG_DBG) { + osal_lock_unsleepable_lock(&g_temp_query_spinlock); + WMT_DBG_FUNC("[Thermal] s_idx_temp_table = %d, idx_temp_table = %d\n", + s_idx_temp_table, idx_temp_table); + WMT_DBG_FUNC("[Thermal] now.time = %lu, s_query.time = %lu, query.time = %lu, REFRESH_TIME = %d\n", + now_time.tv_sec, s_query_time.tv_sec, query_time.tv_sec, REFRESH_TIME); + + WMT_DBG_FUNC("[0] = %d, [1] = %d, [2] = %d\n----\n", + s_temp_table[0], s_temp_table[1], s_temp_table[2]); + osal_unlock_unsleepable_lock(&g_temp_query_spinlock); + } + + return_temp = ((current_temp & 0x80) == 0x0) ? current_temp : (-1) * (current_temp & 0x7f); + + return return_temp; +} + +ssize_t WMT_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + INT32 iRet = 0; + UINT8 wrBuf[NAME_MAX + 1] = { 0 }; + INT32 copySize = (count < NAME_MAX) ? count : NAME_MAX; + + WMT_LOUD_FUNC("count:%zu copySize:%d\n", count, copySize); + + if (copySize > 0) { + if (copy_from_user(wrBuf, buf, copySize)) { + iRet = -EFAULT; + goto write_done; + } + iRet = copySize; + wrBuf[NAME_MAX] = '\0'; + + if (!strncasecmp(wrBuf, "ok", NAME_MAX)) { + WMT_DBG_FUNC("resp str ok\n"); + /* pWmtDevCtx->cmd_result = 0; */ + wmt_lib_trigger_cmd_signal(0); + } else { + WMT_WARN_FUNC("warning resp str (%s)\n", wrBuf); + /* pWmtDevCtx->cmd_result = -1; */ + wmt_lib_trigger_cmd_signal(-1); + } + /* complete(&pWmtDevCtx->cmd_comp); */ + } + +write_done: + return iRet; +} + +ssize_t WMT_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + INT32 iRet = 0; + PUINT8 pCmd = NULL; + UINT32 cmdLen = 0; + + pCmd = wmt_lib_get_cmd(); + + if (pCmd != NULL) { + cmdLen = osal_strlen(pCmd) < NAME_MAX ? osal_strlen(pCmd) : NAME_MAX; + if (cmdLen > count) + cmdLen = count; + WMT_DBG_FUNC("cmd str(%s)\n", pCmd); + if (copy_to_user(buf, pCmd, cmdLen)) + iRet = -EFAULT; + else + iRet = cmdLen; + } +#if 0 + if (test_and_clear_bit(WMT_STAT_CMD, &pWmtDevCtx->state)) { + iRet = osal_strlen(localBuf) < NAME_MAX ? osal_strlen(localBuf) : NAME_MAX; + /* we got something from STP driver */ + WMT_DBG_FUNC("copy cmd to user by read:%s\n", localBuf); + if (copy_to_user(buf, localBuf, iRet)) { + iRet = -EFAULT; + goto read_done; + } + } +#endif + + return iRet; +} + +UINT32 WMT_poll(struct file *filp, poll_table *wait) +{ + UINT32 mask = 0; + P_OSAL_EVENT pEvent = wmt_lib_get_cmd_event(); + + poll_wait(filp, &pEvent->waitQueue, wait); + /* empty let select sleep */ + if (wmt_lib_get_cmd_status() == MTK_WCN_BOOL_TRUE) + mask |= POLLIN | POLLRDNORM; /* readable */ +#if 0 + if (test_bit(WMT_STAT_CMD, &pWmtDevCtx->state)) + mask |= POLLIN | POLLRDNORM; /* readable */ +#endif + mask |= POLLOUT | POLLWRNORM; /* writable */ + + return mask; +} + +/* INT32 WMT_ioctl(struct inode *inode, struct file *filp, UINT32 cmd, unsigned long arg) */ +LONG WMT_unlocked_ioctl(struct file *filp, UINT32 cmd, ULONG arg) +{ + INT32 iRet = 0; + UINT8 *pBuffer = NULL; + + WMT_DBG_FUNC("cmd (%u), arg (0x%lx)\n", cmd, arg); + switch (cmd) { + case WMT_IOCTL_SET_PATCH_NAME: /* patch location */ + { + pBuffer = kmalloc(NAME_MAX + 1, GFP_KERNEL); + if (!pBuffer) { + WMT_ERR_FUNC("pBuffer kmalloc memory fail\n"); + return 0; + } + if (copy_from_user(pBuffer, (PVOID)arg, NAME_MAX)) { + iRet = -EFAULT; + kfree(pBuffer); + break; + } + pBuffer[NAME_MAX] = '\0'; + wmt_lib_set_patch_name(pBuffer); + kfree(pBuffer); + } + break; + case WMT_IOCTL_SET_STP_MODE: /* stp/hif/fm mode */ + /* set hif conf */ + do { + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal = NULL; + P_WMT_HIF_CONF pHif = NULL; + + if (hif_info == 1) { + WMT_INFO_FUNC("hif_info had been set!\n"); + break; + } + + iRet = wmt_lib_set_hif(arg); + if (iRet != 0) { + WMT_INFO_FUNC("wmt_lib_set_hif fail (%lu)\n", arg); + break; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_INFO_FUNC("get_free_lxop fail\n"); + break; + } + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_HIF_CONF; + + pHif = wmt_lib_get_hif(); + + osal_memcpy(&pOp->op.au4OpData[0], pHif, sizeof(WMT_HIF_CONF)); + pOp->op.u4InfoBit = WMT_OP_HIF_BIT; + pSignal->timeoutValue = 0; + + bRet = wmt_lib_put_act_op(pOp); + WMT_DBG_FUNC("WMT_OPID_HIF_CONF result(%d)\n", bRet); + iRet = (bRet == MTK_WCN_BOOL_FALSE) ? -EFAULT : 0; + if (iRet == 0) { + WMT_INFO_FUNC("luncher set STP mode success!\n"); + hif_info = 1; + + if (atomic_read(&g_late_pwr_on_for_blank) && + atomic_read(&g_es_lr_flag_for_blank)) { + atomic_set(&g_late_pwr_on_for_blank, 0); + schedule_work(&gPwrOnOffWork); + } + } + } while (0); + break; + case WMT_IOCTL_FUNC_ONOFF_CTRL: /* test turn on/off func */ +#if WMT_DBG_SUPPORT + do { + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_FALSE; + + if (arg >> 4 == 0xBEEF000) + bRet = mtk_wcn_wmt_func_on(arg & 0xF); + else if (arg >> 4 == 0xDEAD000) + bRet = mtk_wcn_wmt_func_off(arg & 0xF); + + iRet = (bRet == MTK_WCN_BOOL_FALSE) ? -EFAULT : 0; + } while (0); +#endif + break; + case WMT_IOCTL_LPBK_POWER_CTRL: + do { + MTK_WCN_BOOL bRet = MTK_WCN_BOOL_TRUE; + + switch (arg) { + case 0: + if (always_pwr_on_flag) + bRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK); + break; + case 1: + if (always_pwr_on_flag) + bRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_LPBK); + break; + case 2: + bRet = mtk_wcn_wmt_func_on(WMTDRV_TYPE_LPBK); + break; + case 3: + bRet = mtk_wcn_wmt_func_off(WMTDRV_TYPE_LPBK); + break; + } + iRet = (bRet == MTK_WCN_BOOL_TRUE) ? 0 : -EFAULT; + } while (0); + break; + case WMT_IOCTL_LPBK_TEST: + do { + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + UINT32 u4Wait; + /* UINT8 lpbk_buf[1024] = {0}; */ + UINT32 effectiveLen = 0; + P_OSAL_SIGNAL pSignal = NULL; + + if (copy_from_user(&effectiveLen, (PVOID)arg, sizeof(effectiveLen))) { + iRet = -EFAULT; + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + break; + } + if (effectiveLen > sizeof(gLpbkBuf)) { + iRet = -EFAULT; + WMT_ERR_FUNC("length is too long\n"); + break; + } + WMT_DBG_FUNC("len = %d\n", effectiveLen); + + u4Wait = 2000; + if (copy_from_user(&gLpbkBuf[0], (PVOID)arg + sizeof(effectiveLen), effectiveLen)) { + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + iRet = -EFAULT; + break; + } + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + iRet = -EFAULT; + break; + } + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_LPBK; + pOp->op.au4OpData[0] = effectiveLen; /* packet length */ + pOp->op.au4OpData[1] = (SIZE_T)&gLpbkBuf[0]; /* packet buffer pointer */ + memcpy(&gLpbkBufLog, &gLpbkBuf[((effectiveLen >= 4) ? effectiveLen - 4 : 0)], 4); + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + WMT_INFO_FUNC("OPID(%d) type(%zu) start\n", pOp->op.opId, pOp->op.au4OpData[0]); + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d) type(%d) abort\n", + pOp->op.opId, pOp->op.au4OpData[0]); + wmt_lib_put_op_to_free_queue(pOp); + iRet = -1; + break; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("OPID(%d) type(%d) buf tail(0x%08x) fail\n", + pOp->op.opId, pOp->op.au4OpData[0], gLpbkBufLog); + iRet = -1; + break; + } + WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + iRet = pOp->op.au4OpData[0]; + if ((iRet > sizeof(gLpbkBuf)) || (iRet < 0)) { + iRet = -EFAULT; + WMT_ERR_FUNC("length is too long\n"); + break; + } + if (copy_to_user((PVOID)arg + sizeof(effectiveLen) + sizeof(UINT8[2048]), gLpbkBuf, iRet)) { + iRet = -EFAULT; + break; + } + + } while (0); + break; + case WMT_IOCTL_ADIE_LPBK_TEST: + do { + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + P_OSAL_SIGNAL pSignal = NULL; + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + iRet = -EFAULT; + break; + } + + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_ADIE_LPBK_TEST; + pOp->op.au4OpData[0] = 0; + pOp->op.au4OpData[1] = (SIZE_T)&gLpbkBuf[0]; + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + WMT_INFO_FUNC("OPID(%d) start\n", pOp->op.opId); + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,OPID(%d)abort\n", pOp->op.opId); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("OPID(%d) fail\n", pOp->op.opId); + iRet = -1; + break; + } + WMT_INFO_FUNC("OPID(%d) length(%d) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + iRet = pOp->op.au4OpData[0]; + if ((iRet > sizeof(gLpbkBuf)) || (iRet < 0)) { + iRet = -EFAULT; + WMT_ERR_FUNC("length is too long\n"); + break; + } + if (copy_to_user((PVOID)arg + sizeof(SIZE_T), gLpbkBuf, iRet)) { + iRet = -EFAULT; + break; + } + } while (0); + break; + case 10: + if (mtk_wcn_stp_coredump_start_get()) { + wmt_lib_host_awake_get(); + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + WMT_INFO_FUNC("stp dump start.\n"); + else { + WMT_INFO_FUNC("Trigger kernel api dump.\n"); + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_COMBO || + mtk_wcn_stp_coredump_flag_get() == 2) { + pBuffer = kmalloc(NAME_MAX + 1, GFP_KERNEL); + if (!pBuffer) { + WMT_ERR_FUNC("pBuffer kmalloc memory fail\n"); + return 0; + } + + osal_strcpy(pBuffer, "MT662x f/w coredump start-"); + if (copy_from_user(pBuffer + osal_strlen(pBuffer), (PVOID)arg, + NAME_MAX - osal_strlen(pBuffer))) { + /* osal_strcpy(pBuffer, "MT662x f/w assert core dump start"); */ + WMT_ERR_FUNC("copy assert string failed\n"); + } + pBuffer[NAME_MAX] = '\0'; + osal_dbg_assert_aee(pBuffer, "%s", pBuffer); + kfree(pBuffer); + } + } + } + break; + case 11: + if (mtk_wcn_stp_coredump_start_get()) { + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) { + WMT_INFO_FUNC("Dump connsys EMI done.\n"); + mtk_stp_notify_emi_dump_end(); + } + wmt_lib_host_awake_put(); + } + break; + case WMT_IOCTL_GET_CHIP_INFO: + if (arg == 0) + return wmt_lib_get_icinfo(WMTCHIN_CHIPID); + else if (arg == 1) + return wmt_lib_get_icinfo(WMTCHIN_HWVER); + else if (arg == 2) + return wmt_lib_get_icinfo(WMTCHIN_FWVER); + else if (arg == 3) + return wmt_lib_get_icinfo(WMTCHIN_IPVER); + else if (arg == 4) + return wmt_detect_get_chip_type(); + break; + case WMT_IOCTL_WMT_CFG_NAME: + { + INT8 cWmtCfgName[NAME_MAX + 1]; + + if (copy_from_user(cWmtCfgName, (void *)arg, NAME_MAX)) { + iRet = -EFAULT; + break; + } + cWmtCfgName[NAME_MAX] = '\0'; + wmt_conf_set_cfg_file(cWmtCfgName); + } + break; + case WMT_IOCTL_SET_LAUNCHER_KILL: + if (arg == 1) { + WMT_INFO_FUNC("launcher may be killed,block abnormal stp tx.\n"); + wmt_lib_set_stp_wmt_last_close(1); + } else + wmt_lib_set_stp_wmt_last_close(0); + break; + case WMT_IOCTL_SET_PATCH_NUM: + if (arg == 0 || arg > MAX_PATCH_NUM || pAtchNum > 0) { + WMT_ERR_FUNC("patch num(%lu) == 0 or > %d or has set!\n", arg, MAX_PATCH_NUM); + iRet = -1; + break; + } + + pAtchNum = arg; + + if (pPatchInfo == NULL) + pPatchInfo = kcalloc(pAtchNum, sizeof(WMT_PATCH_INFO), GFP_ATOMIC); + if (!pPatchInfo) { + WMT_ERR_FUNC("allocate memory fail!\n"); + iRet = -EFAULT; + break; + } + + WMT_DBG_FUNC(" get patch num from launcher = %d\n", pAtchNum); + wmt_lib_set_patch_num(pAtchNum); + break; + case WMT_IOCTL_SET_PATCH_INFO: + do { + WMT_PATCH_INFO wMtPatchInfo; + P_WMT_PATCH_INFO pTemp = NULL; + UINT32 dWloadSeq; + static UINT32 counter; + + if (!pPatchInfo) { + WMT_ERR_FUNC("NULL patch info pointer\n"); + break; + } + + if (copy_from_user(&wMtPatchInfo, (PVOID)arg, sizeof(WMT_PATCH_INFO))) { + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + iRet = -EFAULT; + break; + } + if (wMtPatchInfo.dowloadSeq > pAtchNum || wMtPatchInfo.dowloadSeq == 0) { + WMT_ERR_FUNC("dowloadSeq num(%u) > %u or == 0!\n", wMtPatchInfo.dowloadSeq, pAtchNum); + iRet = -EFAULT; + counter = 0; + break; + } + + dWloadSeq = wMtPatchInfo.dowloadSeq; + WMT_DBG_FUNC( + "patch dl seq %d,name %s,address info 0x%02x,0x%02x,0x%02x,0x%02x\n", + dWloadSeq, wMtPatchInfo.patchName, + wMtPatchInfo.addRess[0], + wMtPatchInfo.addRess[1], + wMtPatchInfo.addRess[2], + wMtPatchInfo.addRess[3]); + osal_memcpy(pPatchInfo + dWloadSeq - 1, &wMtPatchInfo, sizeof(WMT_PATCH_INFO)); + pTemp = pPatchInfo + dWloadSeq - 1; + if (++counter == pAtchNum) { + wmt_lib_set_patch_info(pPatchInfo); + counter = 0; + } + } while (0); + break; + case WMT_IOCTL_WMT_COREDUMP_CTRL: + mtk_wcn_stp_coredump_flag_ctrl(arg); + break; + case WMT_IOCTL_WMT_STP_ASSERT_CTRL: + if (wmt_lib_btm_cb(BTM_TRIGGER_STP_ASSERT_OP) == MTK_WCN_BOOL_TRUE) { + WMT_INFO_FUNC("trigger stp assert succeed\n"); + iRet = 0; + } else { + WMT_INFO_FUNC("trigger stp assert failed\n"); + iRet = -1; + } + break; + case WMT_IOCTL_WMT_QUERY_CHIPID: + iRet = mtk_wcn_wmt_chipid_query(); + WMT_WARN_FUNC("chipid = 0x%x\n", iRet); + break; + case WMT_IOCTL_WMT_TELL_CHIPID: + { +#if !(DELETE_HIF_SDIO_CHRDEV) + iRet = mtk_wcn_hif_sdio_tell_chipid(arg); +#endif + if (0x6628 == arg || 0x6630 == arg || 0x6632 == arg) + wmt_lib_merge_if_flag_ctrl(1); + else + wmt_lib_merge_if_flag_ctrl(0); + } + break; + case WMT_IOCTL_SEND_BGW_DS_CMD: + do { + P_OSAL_OP pOp; + MTK_WCN_BOOL bRet; + UINT8 desense_buf[14] = { 0 }; + UINT32 effectiveLen = 14; + P_OSAL_SIGNAL pSignal = NULL; + + if (!mtk_wcn_stp_is_ready()) { + iRet = -EFAULT; + break; + } + + if (copy_from_user(&desense_buf[0], (PVOID)arg, effectiveLen)) { + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + iRet = -EFAULT; + break; + } + + pOp = wmt_lib_get_free_op(); + if (!pOp) { + WMT_WARN_FUNC("get_free_lxop fail\n"); + iRet = -EFAULT; + break; + } + pSignal = &pOp->signal; + pOp->op.opId = WMT_OPID_BGW_DS; + pOp->op.au4OpData[0] = effectiveLen; /* packet length */ + pOp->op.au4OpData[1] = (SIZE_T)&desense_buf[0]; /* packet buffer pointer */ + pSignal->timeoutValue = MAX_EACH_WMT_CMD; + WMT_INFO_FUNC("OPID(%d) start\n", pOp->op.opId); + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed,opid(%d) abort\n", pOp->op.opId); + wmt_lib_put_op_to_free_queue(pOp); + return -1; + } + + bRet = wmt_lib_put_act_op(pOp); + ENABLE_PSM_MONITOR(); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_WARN_FUNC("OPID(%d) fail\n", pOp->op.opId); + iRet = -1; + break; + } + WMT_INFO_FUNC("OPID(%d) length(%zu) ok\n", pOp->op.opId, pOp->op.au4OpData[0]); + iRet = pOp->op.au4OpData[0]; + + } while (0); + break; + case WMT_IOCTL_FW_DBGLOG_CTRL: + iRet = wmt_plat_set_dbg_mode(arg); + if (iRet == 0) + wmt_dbg_fwinfor_from_emi(0, 1, 0); + break; + case WMT_IOCTL_DYNAMIC_DUMP_CTRL: + do { + UINT32 i = 0, j = 0, k = 0; + PUINT8 pBuf = NULL; + UINT32 int_buf[10] = {0}; + INT8 Buffer[10][11]; + + pBuf = kmalloc(DYNAMIC_DUMP_BUF + 1, GFP_KERNEL); + if (!pBuf) { + WMT_ERR_FUNC("pBuf kmalloc memory fail\n"); + return 0; + } + if (copy_from_user(pBuf, (PVOID)arg, DYNAMIC_DUMP_BUF)) { + iRet = -EFAULT; + kfree(pBuf); + break; + } + pBuf[DYNAMIC_DUMP_BUF] = '\0'; + WMT_INFO_FUNC("get dynamic dump data from property(%s)\n", pBuf); + memset(Buffer, 0, 10*11); + for (i = 0; i < DYNAMIC_DUMP_BUF && j <= 9; i++) { + if (pBuf[i] == '/') { + k = 0; + j++; + } else if (isascii(pBuf[i]) && k <= 10) { + Buffer[j][k] = pBuf[i]; + k++; + } + } + for (i = 0; i < (j > 10 ? 10 : j); i++) { + iRet = kstrtou32(Buffer[i], 0, &int_buf[i]); + if (iRet) { + WMT_ERR_FUNC("string convert fail(%d)\n", iRet); + break; + } + WMT_INFO_FUNC("dynamic dump data buf[%d]:(0x%x)\n", i, int_buf[i]); + } + wmt_plat_set_dynamic_dumpmem(int_buf); + kfree(pBuf); + } while (0); + break; + case WMT_IOCTL_SET_ROM_PATCH_INFO: + do { + struct wmt_rom_patch_info wmtRomPatchInfo; + + if (copy_from_user(&wmtRomPatchInfo, (PVOID)arg, sizeof(struct wmt_rom_patch_info))) { + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + iRet = -EFAULT; + break; + } + + if (wmtRomPatchInfo.type >= WMTDRV_TYPE_ANT) { + WMT_ERR_FUNC("rom patch type(%d) >= %d!\n", + wmtRomPatchInfo.type, WMTDRV_TYPE_WMT); + iRet = -EFAULT; + break; + } + + WMT_DBG_FUNC("rom patch type %d,name %s,address info 0x%02x,0x%02x,0x%02x,0x%02x\n", + wmtRomPatchInfo.type, wmtRomPatchInfo.patchName, + wmtRomPatchInfo.addRess[0], + wmtRomPatchInfo.addRess[1], + wmtRomPatchInfo.addRess[2], + wmtRomPatchInfo.addRess[3]); + wmt_lib_set_rom_patch_info(&wmtRomPatchInfo, wmtRomPatchInfo.type); + } while (0); + break; + case WMT_IOCTL_GET_EMI_PHY_SIZE: + do { + WMT_INFO_FUNC("gConEmiSize %llu\n", gConEmiSize); + return (UINT32)gConEmiSize; + } while (0); + break; + case WMT_IOCTL_FW_PATCH_UPDATE_RST: + wmt_lib_fw_patch_update_rst_ctrl(arg); + break; + case WMT_IOCTL_GET_DIRECT_PATH_EMI_SIZE: + do { + P_CONSYS_EMI_ADDR_INFO emiInfo = mtk_wcn_consys_soc_get_emi_phy_add(); + + if (emiInfo == NULL) { + WMT_INFO_FUNC("Get emi info fail. Return 0.\n"); + return 0; + } + WMT_INFO_FUNC("Direct path emi size=%d\n", emiInfo->emi_direct_path_size); + return (UINT32)emiInfo->emi_direct_path_size; + } while (0); + break; + case WMT_IOCTL_GET_VENDOR_PATCH_NUM: + iRet = wmt_lib_get_vendor_patch_num(); + break; + case WMT_IOCTL_SET_VENDOR_PATCH_VERSION: + do { + struct wmt_vendor_patch patch; + + if (copy_from_user(&patch, (PVOID)arg, + sizeof(struct wmt_vendor_patch))) { + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + iRet = -EFAULT; + break; + } + + iRet = wmt_lib_set_vendor_patch_version(&patch); + if (iRet) { + iRet = -EFAULT; + break; + } + } while (0); + break; + case WMT_IOCTL_GET_VENDOR_PATCH_VERSION: + do { + struct wmt_vendor_patch patch; + + if (copy_from_user(&patch, (PVOID)arg, sizeof(struct wmt_vendor_patch))) { + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + iRet = -EFAULT; + break; + } + + iRet = wmt_lib_get_vendor_patch_version(&patch); + if (iRet) { + iRet = -EFAULT; + break; + } + + if (copy_to_user((PVOID)arg, &patch, sizeof(struct wmt_vendor_patch))) + iRet = -EFAULT; + } while (0); + break; + case WMT_IOCTL_SET_ACTIVE_PATCH_VERSION: + do { + struct wmt_vendor_patch patch; + + if (copy_from_user(&patch, (PVOID)arg, + sizeof(struct wmt_vendor_patch))) { + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + iRet = -EFAULT; + break; + } + + iRet = wmt_lib_set_active_patch_version(&patch); + WMT_ERR_FUNC("wmt_lib_set_active_patch_version ret = %d\n", iRet); + if (iRet) { + iRet = -EFAULT; + break; + } + } while (0); + break; + case WMT_IOCTL_GET_ACTIVE_PATCH_VERSION: + do { + struct wmt_vendor_patch patch; + + if (copy_from_user(&patch, (PVOID)arg, sizeof(struct wmt_vendor_patch))) { + WMT_ERR_FUNC("copy_from_user failed at %d\n", __LINE__); + iRet = -EFAULT; + break; + } + + iRet = wmt_lib_get_active_patch_version(&patch); + if (iRet) { + iRet = -EFAULT; + break; + } + + if (copy_to_user((PVOID)arg, &patch, sizeof(struct wmt_vendor_patch))) + iRet = -EFAULT; + } while (0); + break; + case WMT_IOCTL_SET_CHECK_PATCH_STATUS: + iRet = wmt_lib_set_check_patch_status(arg); + break; + case WMT_IOCTL_GET_CHECK_PATCH_STATUS: + iRet = wmt_lib_get_check_patch_status(); + break; + default: + iRet = -EINVAL; + WMT_WARN_FUNC("unknown cmd (0x%x)\n", cmd); + break; + } + + return iRet; +} + +#ifdef CONFIG_COMPAT +LONG WMT_compat_ioctl(struct file *filp, UINT32 cmd, ULONG arg) +{ + LONG ret; + + WMT_INFO_FUNC("cmd[0x%x]\n", cmd); + switch (cmd) { + case COMPAT_WMT_IOCTL_SET_PATCH_NAME: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_SET_PATCH_NAME, (ULONG)compat_ptr(arg)); + break; + case COMPAT_WMT_IOCTL_LPBK_TEST: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_LPBK_TEST, (ULONG)compat_ptr(arg)); + break; + case COMPAT_WMT_IOCTL_SET_PATCH_INFO: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_SET_PATCH_INFO, (ULONG)compat_ptr(arg)); + break; + case COMPAT_WMT_IOCTL_PORT_NAME: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_PORT_NAME, (ULONG)compat_ptr(arg)); + break; + case COMPAT_WMT_IOCTL_WMT_CFG_NAME: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_WMT_CFG_NAME, (ULONG)compat_ptr(arg)); + break; + case COMPAT_WMT_IOCTL_SEND_BGW_DS_CMD: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_SEND_BGW_DS_CMD, (ULONG)compat_ptr(arg)); + break; + case COMPAT_WMT_IOCTL_ADIE_LPBK_TEST: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_ADIE_LPBK_TEST, (ULONG)compat_ptr(arg)); + break; + case COMPAT_WMT_IOCTL_DYNAMIC_DUMP_CTRL: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_DYNAMIC_DUMP_CTRL, (ULONG)compat_ptr(arg)); + break; + case COMPAT_WMT_IOCTL_SET_ROM_PATCH_INFO: + ret = WMT_unlocked_ioctl(filp, WMT_IOCTL_SET_ROM_PATCH_INFO, (ULONG)compat_ptr(arg)); + break; + default: { + ret = WMT_unlocked_ioctl(filp, cmd, arg); + break; + } + } + return ret; +} +#endif /* CONFIG_COMPAT */ + +static INT32 WMT_open(struct inode *inode, struct file *file) +{ + LONG ret; + + WMT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + ret = wait_event_timeout(gWmtInitWq, gWmtInitStatus == WMT_INIT_DONE, msecs_to_jiffies(WMT_DEV_INIT_TO_MS)); + if (!ret) { + WMT_WARN_FUNC("wait_event_timeout (%d)ms,(%lu)jiffies,return -EIO\n", + WMT_DEV_INIT_TO_MS, msecs_to_jiffies(WMT_DEV_INIT_TO_MS)); + return -EIO; + } + + if (atomic_inc_return(&gWmtRefCnt) == 1) { + WMT_INFO_FUNC("1st call\n"); + gWmtClose = 0; + } + + return 0; +} + +static INT32 WMT_close(struct inode *inode, struct file *file) +{ + WMT_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + + if (atomic_dec_return(&gWmtRefCnt) == 0) { + WMT_INFO_FUNC("last call\n"); + gWmtClose = 1; + } + + return 0; +} + +static INT32 WMT_mmap(struct file *pFile, struct vm_area_struct *pVma) +{ + unsigned long bufId = pVma->vm_pgoff; + P_CONSYS_EMI_ADDR_INFO emiInfo = mtk_wcn_consys_soc_get_emi_phy_add(); + + WMT_INFO_FUNC("WMT_mmap start:%lu end:%lu size: %lu buffer id=%lu\n", + pVma->vm_start, pVma->vm_end, + pVma->vm_end - pVma->vm_start, bufId); + + if (bufId == 0) { + if (pVma->vm_end - pVma->vm_start > gConEmiSize) + return -1; + WMT_INFO_FUNC("WMT_mmap size: %lu\n", pVma->vm_end - pVma->vm_start); + if (remap_pfn_range(pVma, pVma->vm_start, gConEmiPhyBase >> PAGE_SHIFT, + pVma->vm_end - pVma->vm_start, pVma->vm_page_prot)) + return -EAGAIN; + } else if (bufId == 1) { + if (emiInfo == NULL) + return -1; + if (emiInfo->emi_direct_path_size == 0 || + pVma->vm_end - pVma->vm_start > emiInfo->emi_direct_path_size) + return -1; + WMT_INFO_FUNC("MD direct path size=%d map size=%lu\n", + emiInfo->emi_direct_path_size, + pVma->vm_end - pVma->vm_start); + if (remap_pfn_range(pVma, pVma->vm_start, + emiInfo->emi_direct_path_ap_phy_addr >> PAGE_SHIFT, + pVma->vm_end - pVma->vm_start, pVma->vm_page_prot)) + return -EAGAIN; + } + return 0; +} + +const struct file_operations gWmtFops = { + .open = WMT_open, + .release = WMT_close, + .read = WMT_read, + .write = WMT_write, +/* .ioctl = WMT_ioctl, */ + .unlocked_ioctl = WMT_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = WMT_compat_ioctl, +#endif + .poll = WMT_poll, + .mmap = WMT_mmap, +}; + +VOID wmt_dev_bgw_desense_init(VOID) +{ + bgw_init_socket(); +} + +VOID wmt_dev_bgw_desense_deinit(VOID) +{ + bgw_destroy_netlink_kernel(); +} + +VOID wmt_dev_send_cmd_to_daemon(UINT32 cmd) +{ + send_command_to_daemon(cmd); +} + +UINT8 wmt_dev_is_close(VOID) +{ + return gWmtClose; +} + +static INT32 WMT_init(VOID) +{ +#ifdef CONFIG_MTK_COMBO_COMM + char *ptr = NULL; + + gConEmiSize = 0x400000; + ptr = kmalloc(gConEmiSize, GFP_KERNEL); + if (!ptr) { + WMT_PLAT_PR_DBG("initWlan try to allocate 0x%llu bytes memory error\n", + gConEmiSize); + return -EINVAL; + } + memset(ptr, 0, gConEmiSize); + gConEmiPhyBase = (phys_addr_t)ptr; +#endif + + dev_t devID = MKDEV(gWmtMajor, 0); + INT32 cdevErr = -1; + INT32 ret = -1; + ENUM_WMT_CHIP_TYPE chip_type; + + WMT_DBG_FUNC("WMT Version= %s DATE=%s\n", MTK_WMT_VERSION, MTK_WMT_DATE); + if (gWmtInitStatus != WMT_INIT_NOT_START) + return 0; + /* Prepare a UINT8 device */ + /*static allocate chrdev */ + gWmtInitStatus = WMT_INIT_START; + init_waitqueue_head((wait_queue_head_t *) &gWmtInitWq); +#if (MTK_WCN_REMOVE_KO) + /* called in do_common_drv_init() */ +#else + mtk_wcn_hif_sdio_drv_init(); +#endif + stp_drv_init(); + + ret = register_chrdev_region(devID, WMT_DEV_NUM, WMT_DRIVER_NAME); + if (ret) { + WMT_ERR_FUNC("fail to register chrdev\n"); + gWmtInitStatus = WMT_INIT_NOT_START; + return ret; + } + + cdev_init(&gWmtCdev, &gWmtFops); + gWmtCdev.owner = THIS_MODULE; + + cdevErr = cdev_add(&gWmtCdev, devID, WMT_DEV_NUM); + if (cdevErr) { + WMT_ERR_FUNC("cdev_add() fails (%d)\n", cdevErr); + goto error; + } + WMT_INFO_FUNC("driver(major %d) installed\n", gWmtMajor); + +#if WMT_CREATE_NODE_DYNAMIC + wmt_class = class_create(/*THIS_MODULE,*/ "stpwmt"); + if (IS_ERR(wmt_class)) + goto error; + wmt_dev = device_create(wmt_class, NULL, devID, NULL, "stpwmt"); + if (IS_ERR(wmt_dev)) + goto error; +#endif + +#if 0 + pWmtDevCtx = wmt_drv_create(); + if (!pWmtDevCtx) { + WMT_ERR_FUNC("wmt_drv_create() fails\n"); + goto error; + } + + ret = wmt_drv_init(pWmtDevCtx); + if (ret) { + WMT_ERR_FUNC("wmt_drv_init() fails (%d)\n", ret); + goto error; + } + + WMT_INFO_FUNC("stp_btmcb_reg\n"); + wmt_cdev_btmcb_reg(); + + ret = wmt_drv_start(pWmtDevCtx); + if (ret) { + WMT_ERR_FUNC("wmt_drv_start() fails (%d)\n", ret); + goto error; + } +#endif + ret = wmt_lib_init(); + if (ret) { + WMT_ERR_FUNC("wmt_lib_init() fails (%d)\n", ret); + goto error; + } +#if CFG_WMT_DBG_SUPPORT + wmt_dev_dbg_setup(); +#endif + +#if CFG_WMT_PROC_FOR_AEE + wmt_dev_proc_for_aee_setup(); +#endif + +#if CFG_WMT_PROC_FOR_DUMP_INFO + wmt_dev_proc_for_dump_info_setup(); +#endif + + WMT_STEP_INIT_FUNC(); + + chip_type = wmt_detect_get_chip_type(); + if (chip_type == WMT_CHIP_TYPE_COMBO) + mtk_wcn_hif_sdio_update_cb_reg(wmt_dev_tra_sdio_update); + + WMT_DBG_FUNC("wmt_dev register thermal cb\n"); + osal_unsleepable_lock_init(&g_temp_query_spinlock); + osal_sleepable_lock_init(&g_aee_read_lock); + osal_sleepable_lock_init(&g_dump_info_read_lock); + wmt_lib_register_thermal_ctrl_cb(wmt_dev_tm_temp_query); + wmt_lib_register_trigger_assert_cb(wmt_lib_trigger_assert); + + if (chip_type == WMT_CHIP_TYPE_SOC) + wmt_dev_bgw_desense_init(); + + gWmtInitStatus = WMT_INIT_DONE; + wake_up(&gWmtInitWq); + + INIT_WORK(&gPwrOnOffWork, wmt_pwr_on_off_handler); +#ifdef CONFIG_EARLYSUSPEND + register_early_suspend(&wmt_early_suspend_handler); + WMT_INFO_FUNC("register_early_suspend finished\n"); +#else + wmt_fb_notifier.notifier_call = wmt_fb_notifier_callback; + ret = fb_register_client(&wmt_fb_notifier); + if (ret) + WMT_ERR_FUNC("wmt register fb_notifier failed! ret(%d)\n", ret); + else + WMT_DBG_FUNC("wmt register fb_notifier OK!\n"); +#endif /* CONFIG_EARLYSUSPEND */ + WMT_DBG_FUNC("success\n"); + +#if (MTK_WCN_REMOVE_KO) + /* called in do_common_drv_init() */ +#else + mtk_wcn_stp_uart_drv_init(); + mtk_wcn_stp_sdio_drv_init(); +#endif + + return 0; + +error: + wmt_lib_deinit(); +#if CFG_WMT_DBG_SUPPORT + wmt_dev_dbg_remove(); +#endif +#if WMT_CREATE_NODE_DYNAMIC + if (!(IS_ERR(wmt_dev))) + device_destroy(wmt_class, devID); + if (!(IS_ERR(wmt_class))) { + class_destroy(wmt_class); + wmt_class = NULL; + } +#endif + + if (cdevErr == 0) + cdev_del(&gWmtCdev); + + if (ret == 0) { + unregister_chrdev_region(devID, WMT_DEV_NUM); + gWmtMajor = -1; + } + + gWmtInitStatus = WMT_INIT_NOT_START; + WMT_ERR_FUNC("fail\n"); + + return -1; +} + +static VOID WMT_exit(VOID) +{ + dev_t dev = MKDEV(gWmtMajor, 0); + + if (gWmtInitStatus != WMT_INIT_DONE) + return; + + osal_unsleepable_lock_deinit(&g_temp_query_spinlock); + osal_sleepable_lock_deinit(&g_aee_read_lock); + osal_sleepable_lock_deinit(&g_dump_info_read_lock); +#ifdef CONFIG_EARLYSUSPEND + unregister_early_suspend(&wmt_early_suspend_handler); + WMT_INFO_FUNC("unregister_early_suspend finished\n"); +#else + fb_unregister_client(&wmt_fb_notifier); +#endif /* CONFIG_EARLYSUSPEND */ + + wmt_dev_patch_info_free(); + mtk_wcn_stp_uart_drv_exit(); + mtk_wcn_stp_sdio_drv_exit(); + + wmt_dev_bgw_desense_deinit(); + + wmt_lib_register_thermal_ctrl_cb(NULL); + + wmt_lib_deinit(); + +#if CFG_WMT_DBG_SUPPORT + wmt_dev_dbg_remove(); +#endif + +#if CFG_WMT_PROC_FOR_AEE + wmt_dev_proc_for_aee_remove(); +#endif + +#if CFG_WMT_PROC_FOR_DUMP_INFO + wmt_dev_proc_for_dump_info_remove(); +#endif + +#if WMT_CREATE_NODE_DYNAMIC + if (wmt_dev) { + device_destroy(wmt_class, dev); + wmt_dev = NULL; + } + if (wmt_class) { + class_destroy(wmt_class); + wmt_class = NULL; + } +#endif + cdev_del(&gWmtCdev); + unregister_chrdev_region(dev, WMT_DEV_NUM); + gWmtMajor = -1; + + stp_drv_exit(); + mtk_wcn_hif_sdio_driver_exit(); + gWmtInitStatus = WMT_INIT_NOT_START; + WMT_INFO_FUNC("done\n"); +} + +INT32 mtk_wcn_common_drv_init(VOID) +{ + return WMT_init(); +} +EXPORT_SYMBOL(mtk_wcn_common_drv_init); + +VOID mtk_wcn_common_drv_exit(VOID) +{ + WMT_exit(); +} +EXPORT_SYMBOL(mtk_wcn_common_drv_exit); + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/wmt_idc.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/wmt_idc.c new file mode 100644 index 00000000000000..613569992e14cc --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/wmt_idc.c @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include "osal.h" +#include "wmt_idc.h" +#include "wmt_lib.h" + +#if CFG_WMT_LTE_COEX_HANDLING + +MTK_WCN_WMT_IDC_INFO gWmtIdcInfo; + +INT32 wmt_idc_init(VOID) +{ + INT32 iRet; + + osal_memset(&gWmtIdcInfo, 0, osal_sizeof(gWmtIdcInfo)); + gWmtIdcInfo.iit.src_mod_id = AP_MOD_WMT; + gWmtIdcInfo.iit.dest_mod_id = MD_MOD_EL1; + gWmtIdcInfo.iit.sap_id = 0; + gWmtIdcInfo.ops.rx_cb = wmt_idc_msg_from_lte_handing; + + iRet = mtk_conn_md_bridge_reg(gWmtIdcInfo.iit.src_mod_id, &gWmtIdcInfo.ops); + if (iRet) { + WMT_ERR_FUNC("mtk_conn_md_bridge_reg fail(%d)\n", iRet); + return -1; + } + /* mtk_wcn_stp_flush_rx_queue(COEX_TASK_INDX); */ + return 0; +} + +INT32 wmt_idc_deinit(VOID) +{ + INT32 iRet; + + iRet = mtk_conn_md_bridge_unreg(gWmtIdcInfo.iit.src_mod_id); + if (iRet) + WMT_ERR_FUNC("mtk_conn_md_bridge_unreg fail(%d)\n", iRet); + + osal_memset(&gWmtIdcInfo, 0, osal_sizeof(gWmtIdcInfo)); + + return 0; +} + +INT32 wmt_idc_msg_from_lte_handing(conn_md_ipc_ilm_t *ilm) +{ + MTK_WCN_BOOL bRet; + + if (ilm == NULL) { + WMT_ERR_FUNC("NULL pointer\n"); + return -1; + } + if (mtk_wcn_stp_is_ready()) { + bRet = wmt_lib_handle_idc_msg(ilm); + if (bRet == MTK_WCN_BOOL_FALSE) { + WMT_ERR_FUNC("wmt handing idc msg fail\n"); + return -2; + } + } else + WMT_INFO_FUNC("Received LTE msg,but STP is not ready,drop it!\n"); + + return 0; +} + +VOID wmt_idc_dump_debug_msg(PUINT8 str, PUINT8 p_buf, UINT32 buf_len) +{ + UINT32 idx = 0; + + WMT_DBG_FUNC("%s:, length:%d\n", str, buf_len); + + WMT_DBG_FUNC("ASCII output:\n"); + + for (idx = 0; idx < buf_len;) { + WMT_DBG_FUNC("%c", p_buf[idx]); + idx++; + if (idx % 16 == 0) + WMT_DBG_FUNC("\n"); + } + + WMT_DBG_FUNC("HEX output:\n"); + + for (idx = 0; idx < buf_len;) { + WMT_DBG_FUNC("%02x ", p_buf[idx]); + idx++; + if (idx % 16 == 0) + WMT_DBG_FUNC("\n"); + } +} + +INT32 wmt_idc_msg_to_lte_handing(VOID) +{ + UINT32 readlen = 0; + local_para *p_lps = NULL; + PUINT8 p_data = NULL; + UINT8 opcode = 0; + UINT16 msg_len = 0; +#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING + MTK_WCN_BOOL unknown_msgid = MTK_WCN_BOOL_FALSE; +#endif + + readlen = mtk_wcn_stp_receive_data(&gWmtIdcInfo.buffer[0], 4, COEX_TASK_INDX); + if (readlen == 0) { + osal_sleep_ms(5); + readlen = mtk_wcn_stp_receive_data(&gWmtIdcInfo.buffer[0], 4, COEX_TASK_INDX); + } + + if (readlen > 0) { + WMT_DBG_FUNC("read data len from fw(%d)\n", readlen); + wmt_idc_dump_debug_msg("WMT->LTE from STP buffer", &gWmtIdcInfo.buffer[0], readlen); + + while (readlen) { + p_data = &gWmtIdcInfo.buffer[0]; + p_data += 2; /*omit direction & opcode 2 bytes */ + osal_memcpy(&msg_len, p_data, 2); + WMT_DBG_FUNC("current raw data len(%d) from connsys firmware\n", msg_len); + + msg_len = msg_len > LTE_IDC_BUFFER_MAX_SIZE ? LTE_IDC_BUFFER_MAX_SIZE : msg_len; + osal_memset(&gWmtIdcInfo.buffer[0], 0, LTE_IDC_BUFFER_MAX_SIZE); + readlen = mtk_wcn_stp_receive_data(&gWmtIdcInfo.buffer[0], msg_len, COEX_TASK_INDX); + p_data = &gWmtIdcInfo.buffer[0]; + + if (msg_len > 0) + msg_len -= 1; /*flag byte */ + else + WMT_ERR_FUNC("msg_len is ERROR!"); + + /*how to handle flag(msg type) need to Scott comment */ + /************************************************/ + + if (*p_data == WMT_IDC_RX_OPCODE_DEBUG_MONITOR) + /*do not need transfer to LTE */ + { + p_data += 1; /*flag : 1 byte */ + /*need to handle these debug message */ + wmt_idc_dump_debug_msg("WIFI DEBUG MONITOR", p_data, msg_len); + } else + /*need to transfer to LTE */ + { + p_lps = + (local_para *) osal_malloc(osal_sizeof(local_para) + + osal_sizeof(UINT8) * msg_len); + if (p_lps == NULL) { + WMT_ERR_FUNC("allocate struct local_para memory fail\n"); + return -1; + } + + p_lps->msg_len = msg_len + osal_sizeof(local_para); + + opcode = *p_data; + WMT_DBG_FUNC("current opcode(%d) to LTE\n", opcode); + + p_data += 1; /*flag : 1 byte */ + osal_memcpy(p_lps->data, p_data, msg_len); + + gWmtIdcInfo.iit.local_para_ptr = p_lps; + +#if CFG_WMT_LTE_ENABLE_MSGID_MAPPING + switch (opcode) { + case WMT_IDC_RX_OPCODE_BTWF_DEF_PARA: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND; + break; + case WMT_IDC_RX_OPCODE_BTWF_CHAN_RAN: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; + break; + case WMT_IDC_RX_OPCODE_LTE_FREQ_IDX_TABLE: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_FREQ_IDX_TABLE_IND; + break; + case WMT_IDC_RX_OPCODE_BTWF_PROFILE_IND: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_PROFILE_IND; + break; + case WMT_IDC_RX_OPCODE_UART_PIN_SEL: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_PIN_TYPE_IND; + break; + /* case WMT_IDC_RX_OPCODE_TDM_REQ: */ + /* gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; */ + /* break; */ + default: + unknown_msgid = MTK_WCN_BOOL_TRUE; + WMT_ERR_FUNC("unknown opcode(%d) from connsys firmware\n", opcode); + break; + } + if (unknown_msgid == MTK_WCN_BOOL_FALSE) { + /*handling flag value in wmt cmd */ + mtk_conn_md_bridge_send_msg(&gWmtIdcInfo.iit); + } +#else + if (opcode >= LTE_MSG_ID_OFFSET) { + gWmtIdcInfo.iit.msg_id = + opcode + IPC_EL1_MSG_ID_BEGIN - LTE_MSG_ID_OFFSET + 1; + /*handling flag value in wmt cmd */ + if (gWmtIdcInfo.iit.msg_id == IPC_MSG_ID_MD_CONSYS_VERIFICATION_REQ) + gWmtIdcInfo.iit.dest_mod_id = MD_MOD_AOMGR; //MD_MOD_GMMGR; + else + gWmtIdcInfo.iit.dest_mod_id = MD_MOD_EL1; + + mtk_conn_md_bridge_send_msg(&gWmtIdcInfo.iit); + WMT_DBG_FUNC("CONN->LTE: (0x%x->0x%x)\n", opcode, + gWmtIdcInfo.iit.msg_id); + } else + WMT_ERR_FUNC("opcode(%d)from connsys fw is out of range,drop it!\n", + opcode); +#endif + osal_free(p_lps); + } + + osal_memset(&gWmtIdcInfo.buffer[0], 0, LTE_IDC_BUFFER_MAX_SIZE); + readlen = mtk_wcn_stp_receive_data(&gWmtIdcInfo.buffer[0], 4, COEX_TASK_INDX); + WMT_DBG_FUNC("read data len from fw(%d)\n", readlen); + } + + } else + WMT_ERR_FUNC("there is no coex data in stp buffer\n"); + + osal_memset(&gWmtIdcInfo.buffer[0], 0, LTE_IDC_BUFFER_MAX_SIZE); + + return 0; +} + +UINT32 wmt_idc_msg_to_lte_handing_for_test(PUINT8 p_buf, UINT32 len) +{ + UINT32 readlen = len; + local_para *p_lps = NULL; + PUINT8 p_data = NULL; + UINT8 opcode = 0; + UINT16 msg_len = 0; + MTK_WCN_BOOL unknown_msgid = MTK_WCN_BOOL_FALSE; + + osal_memcpy(&gWmtIdcInfo.buffer[0], p_buf, len); + + if (readlen > 0) { + WMT_DBG_FUNC("read data len from fw(%d)\n", readlen); + + while (readlen) { + p_data = &gWmtIdcInfo.buffer[0]; + p_data += 2; /*omit direction & opcode 2 bytes */ + osal_memcpy(&msg_len, p_data, 2); + + msg_len = msg_len > LTE_IDC_BUFFER_MAX_SIZE ? LTE_IDC_BUFFER_MAX_SIZE : msg_len; + osal_memset(&gWmtIdcInfo.buffer[0], 0, LTE_IDC_BUFFER_MAX_SIZE); + readlen = mtk_wcn_stp_receive_data(&gWmtIdcInfo.buffer[0], msg_len, COEX_TASK_INDX); + p_data = &gWmtIdcInfo.buffer[0]; + + if (msg_len > 0) + msg_len -= 1; /*flag byte */ + else + WMT_ERR_FUNC("msg_len is ERROR!"); + WMT_DBG_FUNC("current raw data len(%d) from connsys firmware\n", msg_len); + + /*how to handle flag(msg type) need to Scott comment */ + /************************************************/ + + if (*p_data == WMT_IDC_RX_OPCODE_DEBUG_MONITOR) + /*do not need transfer to LTE */ + { + p_data += 1; /*flag : 1 byte */ + /*need to handle these debug message */ + wmt_idc_dump_debug_msg("WIFI DEBUG MONITOR", p_data, msg_len); + } else { + /*need to transfer to LTE */ + p_lps = (local_para *) osal_malloc(osal_sizeof(local_para) + + osal_sizeof(UINT8) * msg_len); + if (p_lps == NULL) { + WMT_ERR_FUNC("allocate struct local_para memory fail\n"); + return -1; + } + + p_lps->msg_len = msg_len + osal_sizeof(local_para); + + opcode = *p_data; + WMT_DBG_FUNC("current opcode(%d) to LTE\n", opcode); + + p_data += 1; /*flag : 1 byte */ + osal_memcpy(p_lps->data, p_data, msg_len); + + gWmtIdcInfo.iit.local_para_ptr = p_lps; + + switch (opcode) { + case WMT_IDC_RX_OPCODE_BTWF_DEF_PARA: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND; + break; + case WMT_IDC_RX_OPCODE_BTWF_CHAN_RAN: + gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; + break; + /* case WMT_IDC_RX_OPCODE_TDM_REQ: */ + /* gWmtIdcInfo.iit.msg_id = IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND; */ + /* break; */ + default: + unknown_msgid = MTK_WCN_BOOL_TRUE; + WMT_ERR_FUNC("unknown opcode(%d) from connsys firmware\n", opcode); + } + if (unknown_msgid == MTK_WCN_BOOL_FALSE) { + /*handling flag value in wmt cmd */ + mtk_conn_md_bridge_send_msg(&gWmtIdcInfo.iit); + } + osal_free(p_lps); + } + + osal_memset(&gWmtIdcInfo.buffer[0], 0, LTE_IDC_BUFFER_MAX_SIZE); + readlen = mtk_wcn_stp_receive_data(&gWmtIdcInfo.buffer[0], 4, COEX_TASK_INDX); + } + + } else + WMT_ERR_FUNC("there is no coex data in stp buffer\n"); + + osal_memset(&gWmtIdcInfo.buffer[0], 0, LTE_IDC_BUFFER_MAX_SIZE); + + return 0; +} +#endif /* CFG_WMT_LTE_COEX_HANDLING */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/linux/wmt_step.c b/drivers/misc/mediatek/connectivity/common/common_main/linux/wmt_step.c new file mode 100644 index 00000000000000..0ec08f420c9b0a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/linux/wmt_step.c @@ -0,0 +1,2401 @@ +/* + * Copyright (C) 2016 MediaTek Inc. * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include <connectivity_build_in_adapter.h> +#include <linux/platform_device.h> + +#include "osal.h" +#include "wmt_step.h" +#include "wmt_dev.h" +#include "wmt_plat.h" +#include "mtk_wcn_consys_hw.h" +#include "stp_core.h" +#include "wmt_lib.h" + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S +********************************************************************************/ +static struct step_action *wmt_step_create_emi_action(int param_num, char *params[]); +static struct step_action *wmt_step_create_register_action(int param_num, char *params[]); +static struct step_action *wmt_step_create_gpio_action(int param_num, char *params[]); +static struct step_action *wmt_step_create_disable_reset_action(int param_num, char *params[]); +static struct step_action *wmt_step_create_chip_reset_action(int param_num, char *params[]); +static struct step_action *wmt_step_create_keep_wakeup_action(int param_num, char *params[]); +static struct step_action *wmt_step_create_cancel_wakeup_action(int param_num, char *params[]); +static struct step_action *wmt_step_create_periodic_dump_action(int param_num, char *params[]); +static struct step_action *wmt_step_create_show_string_action(int param_num, char *params[]); +static struct step_action *wmt_step_create_sleep_action(int param_num, char *params[]); +static struct step_action *wmt_step_create_condition_action(int param_num, char *params[]); +static struct step_action *wmt_step_create_value_action(int param_num, char *params[]); +static struct step_action *wmt_step_create_condition_emi_action(int param_num, char *params[]); +static struct step_action *wmt_step_create_condition_register_action(int param_num, char *params[]); + +static void wmt_step_remove_emi_action(struct step_action *p_act); +static void wmt_step_remove_register_action(struct step_action *p_act); +static void wmt_step_remove_gpio_action(struct step_action *p_act); +static void wmt_step_remove_disable_reset_action(struct step_action *p_act); +static void wmt_step_remove_chip_reset_action(struct step_action *p_act); +static void wmt_step_remove_keep_wakeup_action(struct step_action *p_act); +static void wmt_step_remove_cancel_wakeup_action(struct step_action *p_act); +static void wmt_step_remove_periodic_dump_action(struct step_action *p_act); +static void wmt_step_remove_show_string_action(struct step_action *p_act); +static void wmt_step_remove_sleep_action(struct step_action *p_act); +static void wmt_step_remove_condition_action(struct step_action *p_act); +static void wmt_step_remove_value_action(struct step_action *p_act); +static void wmt_step_remove_condition_emi_action(struct step_action *p_act); +static void wmt_step_remove_condition_register_action(struct step_action *p_act); + +static int wmt_step_access_line_state_init(char *tok, + struct step_target_act_list_info *p_parse_info, + struct step_parse_line_data_param_info *p_parse_line_info); +static int wmt_step_access_line_state_tp(char *tok, + struct step_target_act_list_info *p_parse_info, + struct step_parse_line_data_param_info *p_parse_line_info); +static int wmt_step_access_line_state_at(char *tok, + struct step_target_act_list_info *p_parse_info, + struct step_parse_line_data_param_info *p_parse_line_info); +static int wmt_step_access_line_state_at_op(char *tok, + struct step_target_act_list_info *p_parse_info, + struct step_parse_line_data_param_info *p_parse_line_info); +static int wmt_step_access_line_state_pd(char *tok, + struct step_target_act_list_info *p_parse_info, + struct step_parse_line_data_param_info *p_parse_line_info); + +static int wmt_step_operator_result_greater(int l_val, int r_val); +static int wmt_step_operator_result_greater_equal(int l_val, int r_val); +static int wmt_step_operator_result_less(int l_val, int r_val); +static int wmt_step_operator_result_less_equal(int l_val, int r_val); +static int wmt_step_operator_result_equal(int l_val, int r_val); +static int wmt_step_operator_result_not_equal(int l_val, int r_val); +static int wmt_step_operator_result_and(int l_val, int r_val); +static int wmt_step_operator_result_or(int l_val, int r_val); + +/******************************************************************************* + * D E F I N E +********************************************************************************/ +#define STEP_EMI_ACT_INT (int)(*(int *)STEP_ACTION_NAME_EMI) +#define STEP_REG_ACT_INT (int)(*(int *)STEP_ACTION_NAME_REGISTER) +#define STEP_GPIO_ACT_INT (int)(*(int *)STEP_ACTION_NAME_GPIO) +#define STEP_DISABLE_RESET_ACT_INT (int)(*(int *)STEP_ACTION_NAME_DISABLE_RESET) +#define STEP_CHIP_RESET_ACT_INT (int)(*(int *)STEP_ACTION_NAME_CHIP_RESET) +#define STEP_KEEP_WAKEUP_ACT_INT (int)(*(int *)STEP_ACTION_NAME_KEEP_WAKEUP) +#define STEP_CANCEL_KEEP_WAKEUP_ACT_INT (int)(*(int *)STEP_ACTION_NAME_CANCEL_WAKEUP) +#define STEP_SHOW_STRING_ACT_INT (int)(*(int *)STEP_ACTION_NAME_SHOW_STRING) +#define STEP_SLEEP_ACT_INT (int)(*(int *)STEP_ACTION_NAME_SLEEP) +#define STEP_CONDITION_ACT_INT (int)(*(int *)STEP_ACTION_NAME_CONDITION) +#define STEP_VALUE_ACT_INT (int)(*(int *)STEP_ACTION_NAME_VALUE) +#define STEP_CONDITION_EMI_ACT_INT (int)(*(int *)STEP_ACTION_NAME_CONDITION_EMI) +#define STEP_CONDITION_REG_ACT_INT (int)(*(int *)STEP_ACTION_NAME_CONDITION_REGISTER) + +#define STEP_PARSE_LINE_STATE_INIT 0 +#define STEP_PARSE_LINE_STATE_TP 1 +#define STEP_PARSE_LINE_STATE_AT 2 +#define STEP_PARSE_LINE_STATE_AT_OP 3 +#define STEP_PARSE_LINE_STATE_PD_START 4 +#define STEP_PARSE_LINE_STATE_PD_END 5 +/******************************************************************************* + * P R I V A T E D A T A +********************************************************************************/ +struct step_env_struct g_step_env; + +static const struct step_action_contrl wmt_step_action_map[] = { + [STEP_ACTION_INDEX_EMI] = { + wmt_step_create_emi_action, + wmt_step_do_emi_action, + wmt_step_remove_emi_action + }, + [STEP_ACTION_INDEX_REGISTER] = { + wmt_step_create_register_action, + wmt_step_do_register_action, + wmt_step_remove_register_action + }, + [STEP_ACTION_INDEX_GPIO] = { + wmt_step_create_gpio_action, + wmt_step_do_gpio_action, + wmt_step_remove_gpio_action + }, + [STEP_ACTION_INDEX_DISABLE_RESET] = { + wmt_step_create_disable_reset_action, + wmt_step_do_disable_reset_action, + wmt_step_remove_disable_reset_action + }, + [STEP_ACTION_INDEX_CHIP_RESET] = { + wmt_step_create_chip_reset_action, + wmt_step_do_chip_reset_action, + wmt_step_remove_chip_reset_action + }, + [STEP_ACTION_INDEX_KEEP_WAKEUP] = { + wmt_step_create_keep_wakeup_action, + wmt_step_do_keep_wakeup_action, + wmt_step_remove_keep_wakeup_action + }, + [STEP_ACTION_INDEX_CANCEL_WAKEUP] = { + wmt_step_create_cancel_wakeup_action, + wmt_step_do_cancel_wakeup_action, + wmt_step_remove_cancel_wakeup_action + }, + [STEP_ACTION_INDEX_PERIODIC_DUMP] = { + wmt_step_create_periodic_dump_action, + wmt_step_do_periodic_dump_action, + wmt_step_remove_periodic_dump_action, + }, + [STEP_ACTION_INDEX_SHOW_STRING] = { + wmt_step_create_show_string_action, + wmt_step_do_show_string_action, + wmt_step_remove_show_string_action + }, + [STEP_ACTION_INDEX_SLEEP] = { + wmt_step_create_sleep_action, + wmt_step_do_sleep_action, + wmt_step_remove_sleep_action + }, + [STEP_ACTION_INDEX_CONDITION] = { + wmt_step_create_condition_action, + wmt_step_do_condition_action, + wmt_step_remove_condition_action + }, + [STEP_ACTION_INDEX_VALUE] = { + wmt_step_create_value_action, + wmt_step_do_value_action, + wmt_step_remove_value_action + }, + [STEP_ACTION_INDEX_CONDITION_EMI] = { + wmt_step_create_condition_emi_action, + wmt_step_do_condition_emi_action, + wmt_step_remove_condition_emi_action + }, + [STEP_ACTION_INDEX_CONDITION_REGISTER] = { + wmt_step_create_condition_register_action, + wmt_step_do_condition_register_action, + wmt_step_remove_condition_register_action + }, +}; + +static const char * const STEP_TRIGGER_TIME_NAME[] = { + [STEP_TRIGGER_POINT_COMMAND_TIMEOUT] = + "[TP 1] When Command timeout", + [STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT] = + "[TP 2] When Firmware trigger assert", + [STEP_TRIGGER_POINT_BEFORE_CHIP_RESET] = + "[TP 3] Before Chip reset", + [STEP_TRIGGER_POINT_AFTER_CHIP_RESET] = + "[TP 4] After Chip reset", + [STEP_TRIGGER_POINT_BEFORE_WIFI_FUNC_ON] = + "[TP 5] Before Wifi function on", + [STEP_TRIGGER_POINT_BEFORE_WIFI_FUNC_OFF] = + "[TP 6] Before Wifi function off", + [STEP_TRIGGER_POINT_BEFORE_BT_FUNC_ON] = + "[TP 7] Before BT function on", + [STEP_TRIGGER_POINT_BEFORE_BT_FUNC_OFF] = + "[TP 8] Before BT function off", + [STEP_TRIGGER_POINT_BEFORE_FM_FUNC_ON] = + "[TP 9] Before FM function on", + [STEP_TRIGGER_POINT_BEFORE_FM_FUNC_OFF] = + "[TP 10] Before FM function off", + [STEP_TRIGGER_POINT_BEFORE_GPS_FUNC_ON] = + "[TP 11] Before GPS function on", + [STEP_TRIGGER_POINT_BEFORE_GPS_FUNC_OFF] = + "[TP 12] Before GPS function off", + [STEP_TRIGGER_POINT_BEFORE_READ_THERMAL] = + "[TP 13] Before read consys thermal", + [STEP_TRIGGER_POINT_POWER_ON_START] = + "[TP 14] Power on sequence(0): Start power on", + [STEP_TRIGGER_POINT_POWER_ON_BEFORE_GET_CONNSYS_ID] = + "[TP 15] Power on sequence(1): Before can get connsys id", + [STEP_TRIGGER_POINT_POWER_ON_BEFORE_SEND_DOWNLOAD_PATCH] = + "[TP 16] Power on sequence(2): Before send download patch", + [STEP_TRIGGER_POINT_POWER_ON_BEFORE_CONNSYS_RESET] = + "[TP 17] Power on sequence(3): Before connsys reset (donwload patch)", + [STEP_TRIGGER_POINT_POWER_ON_BEFORE_SET_WIFI_LTE_COEX] = + "[TP 18] Power on sequence(4): Before set wifi and lte coex", + [STEP_TRIGGER_POINT_POWER_ON_BEFORE_BT_WIFI_CALIBRATION] = + "[TP 19] Power on sequence(5): Before set BT and Wifi calibration", + [STEP_TRIGGER_POINT_POWER_ON_END] = + "[TP 20] Power on sequence(6): End power on", + [STEP_TRIGGER_POINT_BEFORE_POWER_OFF] = + "[TP 21] Before WMT power off", + [STEP_TRIGGER_POINT_WHEN_AP_SUSPEND] = + "[TP 22] When AP suspend", + [STEP_TRIGGER_POINT_WHEN_AP_RESUME] = + "[TP 23] When AP resume", + [STEP_TRIGGER_POINT_POWER_OFF_HANDSHAKE] = + "[TP 24] When power off handshake", + [STEP_TRIGGER_POINT_BEFORE_RESTORE_CAL_RESULT] = + "[TP 25] Before restore calibration result", + [STEP_TRIGGER_POINT_AFTER_RESTORE_CAL_RESULT] = + "[TP 26] After restore calibration result", + [STEP_TRIGGER_POINT_POWER_ON_AFTER_BT_WIFI_CALIBRATION] = + "[TP 27] Power on sequence(5): After BT and Wi-Fi calibration", + [STEP_TRIGGER_POINT_AFTER_RESTORE_CAL_CMD] = + "[TP 28] After send calibration restore command", + [STEP_TRIGGER_POINT_WHEN_CLOCK_FAIL] = + "[TP 29] When clock fail", +}; + +static const int wmt_step_func_ctrl_id[WMTDRV_TYPE_MAX][2] = { + [WMTDRV_TYPE_BT] = { + STEP_TRIGGER_POINT_BEFORE_BT_FUNC_OFF, + STEP_TRIGGER_POINT_BEFORE_BT_FUNC_ON + }, + [WMTDRV_TYPE_FM] = { + STEP_TRIGGER_POINT_BEFORE_FM_FUNC_OFF, + STEP_TRIGGER_POINT_BEFORE_FM_FUNC_ON + }, + [WMTDRV_TYPE_GPS] = { + STEP_TRIGGER_POINT_BEFORE_GPS_FUNC_OFF, + STEP_TRIGGER_POINT_BEFORE_GPS_FUNC_ON + }, + [WMTDRV_TYPE_WIFI] = { + STEP_TRIGGER_POINT_BEFORE_WIFI_FUNC_OFF, + STEP_TRIGGER_POINT_BEFORE_WIFI_FUNC_ON + }, +}; + +typedef int (*STEP_LINE_STATE) (char *, + struct step_target_act_list_info *, struct step_parse_line_data_param_info *); +static const STEP_LINE_STATE wmt_step_line_state_action_map[] = { + [STEP_PARSE_LINE_STATE_INIT] = wmt_step_access_line_state_init, + [STEP_PARSE_LINE_STATE_TP] = wmt_step_access_line_state_tp, + [STEP_PARSE_LINE_STATE_AT] = wmt_step_access_line_state_at, + [STEP_PARSE_LINE_STATE_AT_OP] = wmt_step_access_line_state_at_op, + [STEP_PARSE_LINE_STATE_PD_START] = wmt_step_access_line_state_pd, +}; + +typedef int (*STEP_OPERATOR_RESULT) (int, int); +static const STEP_OPERATOR_RESULT wmt_step_operator_result_map[] = { + [STEP_OPERATOR_GREATER] = wmt_step_operator_result_greater, + [STEP_OPERATOR_GREATER_EQUAL] = wmt_step_operator_result_greater_equal, + [STEP_OPERATOR_LESS] = wmt_step_operator_result_less, + [STEP_OPERATOR_LESS_EQUAL] = wmt_step_operator_result_less_equal, + [STEP_OPERATOR_EQUAL] = wmt_step_operator_result_equal, + [STEP_OPERATOR_NOT_EQUAL] = wmt_step_operator_result_not_equal, + [STEP_OPERATOR_AND] = wmt_step_operator_result_and, + [STEP_OPERATOR_OR] = wmt_step_operator_result_or, +}; + +/******************************************************************************* + * I N T E R N A L F U N C T I O N S +********************************************************************************/ +static void wmt_step_init_list(void) +{ + unsigned int i = 0; + + for (i = 0; i < STEP_TRIGGER_POINT_MAX; i++) + INIT_LIST_HEAD(&(g_step_env.actions[i].list)); +} + +static unsigned char __iomem *wmt_step_get_emi_base_address(void) +{ + if (g_step_env.emi_base_addr == NULL) { + if (gConEmiPhyBase) + g_step_env.emi_base_addr = ioremap(gConEmiPhyBase, gConEmiSize); + } + + return g_step_env.emi_base_addr; +} + +static void _wmt_step_init_register_base_size(struct device_node *node, int index, int step_index, unsigned long addr) +{ + int flag; + + g_step_env.reg_base[step_index].vir_addr = addr; + if (addr != 0) + of_get_address(node, index, &(g_step_env.reg_base[step_index].size), &flag); +} + +static void wmt_step_init_register_base_size(void) +{ + struct device_node *node = NULL; + + /* If you need to change the register index, address. Please update STEP Config comment */ + if (g_pdev != NULL) { + node = g_pdev->dev.of_node; + _wmt_step_init_register_base_size(node, STEP_MCU_BASE_INDEX, + STEP_REGISTER_CONN_MCU_CONFIG_BASE, conn_reg.mcu_base); + _wmt_step_init_register_base_size(node, STEP_TOP_RGU_BASE_INDEX, + STEP_REGISTER_AP_RGU_BASE, conn_reg.ap_rgu_base); + _wmt_step_init_register_base_size(node, STEP_INFRACFG_AO_BASE_INDEX, + STEP_REGISTER_TOPCKGEN_BASE, conn_reg.topckgen_base); + _wmt_step_init_register_base_size(node, STEP_SPM_BASE_INDEX, + STEP_REGISTER_SPM_BASE, conn_reg.spm_base); + _wmt_step_init_register_base_size(node, STEP_MCU_CONN_HIF_ON_BASE_INDEX, + STEP_REGISTER_HIF_ON_BASE, conn_reg.mcu_conn_hif_on_base); + _wmt_step_init_register_base_size(node, STEP_MCU_TOP_MISC_OFF_BASE_INDEX, + STEP_REGISTER_MISC_OFF_BASE, conn_reg.mcu_top_misc_off_base); + _wmt_step_init_register_base_size(node, STEP_MCU_CFG_ON_BASE_INDEX, + STEP_REGISTER_CFG_ON_BASE, conn_reg.mcu_cfg_on_base); + _wmt_step_init_register_base_size(node, STEP_MCU_CIRQ_BASE_INDEX, + STEP_CIRQ_BASE, conn_reg.mcu_cirq_base); + _wmt_step_init_register_base_size(node, STEP_MCU_TOP_MISC_ON_BASE_INDEX, + STEP_MCU_TOP_MISC_ON_BASE, conn_reg.mcu_top_misc_on_base); + } +} + +static void wmt_step_clear_action_list(struct step_action_list *action_list) +{ + struct step_action *p_act, *p_act_next; + + list_for_each_entry_safe(p_act, p_act_next, &(action_list->list), list) { + list_del_init(&p_act->list); + wmt_step_remove_action(p_act); + } +} + +static void wmt_step_clear_list(void) +{ + unsigned int i = 0; + + for (i = 0; i < STEP_TRIGGER_POINT_MAX; i++) + wmt_step_clear_action_list(&g_step_env.actions[i]); +} + +static void wmt_step_unioremap_emi(void) +{ + if (g_step_env.emi_base_addr != NULL) { + iounmap(g_step_env.emi_base_addr); + g_step_env.emi_base_addr = NULL; + } +} + +static unsigned char *mtk_step_get_emi_virt_addr(unsigned char *emi_base_addr, unsigned int offset) +{ + unsigned char *p_virtual_addr = NULL; + + if (offset > gConEmiSize) { + WMT_ERR_FUNC("STEP failed: offset size %d over MAX size(%llu)\n", offset, + gConEmiSize); + return NULL; + } + p_virtual_addr = emi_base_addr + offset; + + return p_virtual_addr; +} + +static int wmt_step_get_cfg(const char *p_patch_name, osal_firmware **pp_patch) +{ + osal_firmware *fw = NULL; + + *pp_patch = NULL; + if (request_firmware((const struct firmware **)&fw, p_patch_name, NULL) != 0) { + release_firmware(fw); + return -1; + } + + WMT_DBG_FUNC("Load step cfg %s ok!!\n", p_patch_name); + *pp_patch = fw; + + return 0; +} + +static void wmt_step_sleep_or_delay(int ms) +{ + /* msleep < 20ms can sleep for up to 20ms */ + if (ms < 20) + udelay(ms * 1000); + else + osal_sleep_ms(ms); +} + +static unsigned char wmt_step_to_upper(char str) +{ + if ((str >= 'a') && (str <= 'z')) + return str + ('A' - 'a'); + else + return str; +} + +static void wmt_step_string_to_upper(char *tok) +{ + for (; *tok != '\0'; tok++) + *tok = wmt_step_to_upper(*tok); +} + +static int wmt_step_get_int_from_four_char(char *str) +{ + unsigned char char_array[4]; + int i; + + for (i = 0; i < 4; i++) { + if (*(str + i) == '\0') + return -1; + + char_array[i] = wmt_step_to_upper(*(str + i)); + } + + return *(int *)char_array; +} + +static enum step_trigger_point_id wmt_step_parse_tp_id(char *str) +{ + long tp_id = STEP_TRIGGER_POINT_NO_DEFINE; + + if (osal_strtol(str, 10, &tp_id)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", str); + return STEP_TRIGGER_POINT_NO_DEFINE; + } + if (tp_id <= STEP_TRIGGER_POINT_NO_DEFINE || tp_id >= STEP_TRIGGER_POINT_MAX) + return STEP_TRIGGER_POINT_NO_DEFINE; + + return (enum step_trigger_point_id)tp_id; +} + +static int wmt_step_parse_pd_expires(PINT8 ptr) +{ + long expires_ms; + + if (osal_strtol(ptr, 0, &expires_ms)) + return -1; + + return (int)expires_ms; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpointer-compare" +static int wmt_step_parse_act_id(char *str) +{ + int str_to_int = STEP_ACTION_INDEX_NO_DEFINE; + + if (str == NULL || str == '\0') + return STEP_ACTION_INDEX_NO_DEFINE; + + str_to_int = wmt_step_get_int_from_four_char(str); + if (str_to_int == STEP_EMI_ACT_INT) + return STEP_ACTION_INDEX_EMI; + else if (str_to_int == STEP_REG_ACT_INT) + return STEP_ACTION_INDEX_REGISTER; + else if (str_to_int == STEP_GPIO_ACT_INT) + return STEP_ACTION_INDEX_GPIO; + else if (str_to_int == STEP_DISABLE_RESET_ACT_INT) + return STEP_ACTION_INDEX_DISABLE_RESET; + else if (str_to_int == STEP_CHIP_RESET_ACT_INT) + return STEP_ACTION_INDEX_CHIP_RESET; + else if (str_to_int == STEP_KEEP_WAKEUP_ACT_INT) + return STEP_ACTION_INDEX_KEEP_WAKEUP; + else if (str_to_int == STEP_CANCEL_KEEP_WAKEUP_ACT_INT) + return STEP_ACTION_INDEX_CANCEL_WAKEUP; + else if (str_to_int == STEP_SHOW_STRING_ACT_INT) + return STEP_ACTION_INDEX_SHOW_STRING; + else if (str_to_int == STEP_SLEEP_ACT_INT) + return STEP_ACTION_INDEX_SLEEP; + else if (str_to_int == STEP_CONDITION_ACT_INT) + return STEP_ACTION_INDEX_CONDITION; + else if (str_to_int == STEP_VALUE_ACT_INT) + return STEP_ACTION_INDEX_VALUE; + else if (str_to_int == STEP_CONDITION_EMI_ACT_INT) + return STEP_ACTION_INDEX_CONDITION_EMI; + else if (str_to_int == STEP_CONDITION_REG_ACT_INT) + return STEP_ACTION_INDEX_CONDITION_REGISTER; + else + return STEP_ACTION_INDEX_NO_DEFINE; + +} +#pragma GCC diagnostic pop + +static struct step_action_list *wmt_step_get_tp_list(int tp_id) +{ + if (tp_id <= STEP_TRIGGER_POINT_NO_DEFINE || tp_id >= STEP_TRIGGER_POINT_MAX) { + WMT_ERR_FUNC("STEP failed: Write action to tp_id: %d\n", tp_id); + return NULL; + } + + return &g_step_env.actions[tp_id]; +} + +#define STEP_PARSE_LINE_RET_CONTINUE 0 +#define STEP_PARSE_LINE_RET_BREAK 1 + +static void wmt_step_set_line_state(int *p_state, int value) +{ + *p_state = value; +} + +static int wmt_step_access_line_state_init(char *tok, + struct step_target_act_list_info *p_parse_info, + struct step_parse_line_data_param_info *p_parse_line_info) +{ + wmt_step_string_to_upper(tok); + if (osal_strcmp(tok, "[TP") == 0) { + wmt_step_set_line_state(&p_parse_line_info->state, STEP_PARSE_LINE_STATE_TP); + return STEP_PARSE_LINE_RET_CONTINUE; + } + + if (p_parse_info->tp_id == STEP_TRIGGER_POINT_NO_DEFINE) { + WMT_ERR_FUNC("STEP failed: Set trigger point first: %s\n", tok); + return STEP_PARSE_LINE_RET_BREAK; + } + + if (osal_strcmp(tok, "[PD+]") == 0) { + wmt_step_set_line_state(&p_parse_line_info->state, STEP_PARSE_LINE_STATE_PD_START); + return STEP_PARSE_LINE_RET_CONTINUE; + } + + if (osal_strcmp(tok, "[PD-]") == 0) { + wmt_step_set_line_state(&p_parse_line_info->state, STEP_PARSE_LINE_STATE_PD_END); + return STEP_PARSE_LINE_RET_BREAK; + } + + if (osal_strcmp(tok, "[AT]") == 0) { + wmt_step_set_line_state(&p_parse_line_info->state, STEP_PARSE_LINE_STATE_AT); + return STEP_PARSE_LINE_RET_CONTINUE; + } + + return STEP_PARSE_LINE_RET_BREAK; +} + +static int wmt_step_access_line_state_tp(char *tok, + struct step_target_act_list_info *p_parse_info, + struct step_parse_line_data_param_info *p_parse_line_info) +{ + char *pch; + + if (p_parse_info->p_pd_entry != NULL) { + WMT_ERR_FUNC("STEP failed: Please add [PD-] after [PD+], tok = %s\n", tok); + p_parse_info->p_pd_entry = NULL; + } + + pch = osal_strchr(tok, ']'); + if (pch == NULL) { + WMT_ERR_FUNC("STEP failed: Trigger point format is wrong: %s\n", tok); + } else { + *pch = '\0'; + p_parse_info->tp_id = wmt_step_parse_tp_id(tok); + p_parse_info->p_target_list = wmt_step_get_tp_list(p_parse_info->tp_id); + + if (p_parse_info->tp_id == STEP_TRIGGER_POINT_NO_DEFINE) + WMT_ERR_FUNC("STEP failed: Trigger point no define: %s\n", tok); + } + + return STEP_PARSE_LINE_RET_BREAK; +} + +static int wmt_step_access_line_state_at(char *tok, + struct step_target_act_list_info *p_parse_info, + struct step_parse_line_data_param_info *p_parse_line_info) +{ + p_parse_line_info->act_id = wmt_step_parse_act_id(tok); + if (p_parse_line_info->act_id == STEP_ACTION_INDEX_NO_DEFINE) { + WMT_ERR_FUNC("STEP failed: Action no define: %s\n", tok); + return STEP_PARSE_LINE_RET_BREAK; + } + wmt_step_set_line_state(&p_parse_line_info->state, STEP_PARSE_LINE_STATE_AT_OP); + + return STEP_PARSE_LINE_RET_CONTINUE; +} + +static int wmt_step_access_line_state_at_op(char *tok, + struct step_target_act_list_info *p_parse_info, + struct step_parse_line_data_param_info *p_parse_line_info) +{ + p_parse_line_info->act_params[p_parse_line_info->param_index] = tok; + (p_parse_line_info->param_index)++; + + if (p_parse_line_info->param_index >= STEP_PARAMETER_SIZE) { + WMT_ERR_FUNC("STEP failed: Param too much"); + return STEP_PARSE_LINE_RET_BREAK; + } + + return STEP_PARSE_LINE_RET_CONTINUE; +} + +static int wmt_step_access_line_state_pd(char *tok, + struct step_target_act_list_info *p_parse_info, + struct step_parse_line_data_param_info *p_parse_line_info) +{ + int pd_ms = -1; + + pd_ms = wmt_step_parse_pd_expires(tok); + if (pd_ms == -1) + WMT_ERR_FUNC("STEP failed: PD ms failed %s\n", tok); + + if (p_parse_info->p_pd_entry != NULL) + WMT_ERR_FUNC("STEP failed: Please add [PD-] after [PD+], tok = %s\n", tok); + + p_parse_info->p_pd_entry = wmt_step_get_periodic_dump_entry(pd_ms); + if (p_parse_info->p_pd_entry == NULL) + WMT_ERR_FUNC("STEP failed: p_pd_entry create fail\n"); + else + p_parse_info->p_target_list = &(p_parse_info->p_pd_entry->action_list); + + return STEP_PARSE_LINE_RET_BREAK; +} + +static void wmt_step_parse_line_data(char *line, struct step_target_act_list_info *p_parse_info, + STEP_WRITE_ACT_TO_LIST func_act_to_list) +{ + char *tok; + int line_ret = STEP_PARSE_LINE_RET_BREAK; + struct step_parse_line_data_param_info parse_line_info; + + parse_line_info.param_index = 0; + parse_line_info.act_id = STEP_ACTION_INDEX_NO_DEFINE; + parse_line_info.state = STEP_PARSE_LINE_STATE_INIT; + + while ((tok = osal_strsep(&line, " \t")) != NULL) { + if (*tok == '\0') + continue; + if (osal_strcmp(tok, "//") == 0) + break; + + if (wmt_step_line_state_action_map[parse_line_info.state] != NULL) { + line_ret = wmt_step_line_state_action_map[parse_line_info.state] (tok, + p_parse_info, &parse_line_info); + } + + if (line_ret == STEP_PARSE_LINE_RET_CONTINUE) + continue; + else + break; + } + + if (parse_line_info.state == STEP_PARSE_LINE_STATE_AT_OP) { + func_act_to_list(p_parse_info->p_target_list, + parse_line_info.act_id, parse_line_info.param_index, parse_line_info.act_params); + } else if (parse_line_info.state == STEP_PARSE_LINE_STATE_PD_END) { + p_parse_info->p_target_list = wmt_step_get_tp_list(p_parse_info->tp_id); + if (p_parse_info->p_pd_entry != NULL) { + parse_line_info.act_params[0] = (PINT8)p_parse_info->p_pd_entry; + func_act_to_list(p_parse_info->p_target_list, + STEP_ACTION_INDEX_PERIODIC_DUMP, parse_line_info.param_index, + parse_line_info.act_params); + p_parse_info->p_pd_entry = NULL; + } + } +} + +static void _wmt_step_do_actions(struct step_action_list *action_list) +{ + struct step_action *p_act, *p_act_next; + + list_for_each_entry_safe(p_act, p_act_next, &action_list->list, list) { + if (p_act->action_id <= STEP_ACTION_INDEX_NO_DEFINE || p_act->action_id >= STEP_ACTION_INDEX_MAX) { + WMT_ERR_FUNC("STEP failed: Wrong action id %d\n", (int)p_act->action_id); + continue; + } + + if (wmt_step_action_map[p_act->action_id].func_do_action != NULL) + wmt_step_action_map[p_act->action_id].func_do_action(p_act, NULL); + else + WMT_ERR_FUNC("STEP failed: Action is NULL\n"); + } +} + +static void wmt_step_start_work(struct step_pd_entry *p_entry) +{ + unsigned int timeout; + int result = 0; + + if (!g_step_env.pd_struct.step_pd_wq) { + WMT_ERR_FUNC("STEP failed: step wq doesn't run\n"); + result = -1; + } + + if (p_entry == NULL) { + WMT_ERR_FUNC("STEP failed: entry is null\n"); + result = -1; + } + + if (result == 0) { + timeout = p_entry->expires_ms; + queue_delayed_work(g_step_env.pd_struct.step_pd_wq, &p_entry->pd_work, timeout); + } +} + +static void wmt_step_pd_work(struct work_struct *work) +{ + struct step_pd_entry *p_entry; + struct delayed_work *delayed_work; + int result = 0; + + if (down_read_trylock(&g_step_env.init_rwsem)) { + if (!g_step_env.is_enable) { + WMT_ERR_FUNC("STEP failed: step doesn`t enable\n"); + result = -1; + } + + delayed_work = to_delayed_work(work); + if (delayed_work == NULL) { + WMT_ERR_FUNC("STEP failed: work is NULL\n"); + result = -1; + } + + if (result == 0) { + p_entry = container_of(delayed_work, struct step_pd_entry, pd_work); + + WMT_INFO_FUNC("STEP show: Periodic dump: %d ms\n", p_entry->expires_ms); + _wmt_step_do_actions(&p_entry->action_list); + wmt_step_start_work(p_entry); + } + + up_read(&g_step_env.init_rwsem); + } +} + +static struct step_pd_entry *wmt_step_create_periodic_dump_entry(unsigned int expires) +{ + struct step_pd_entry *p_pd_entry = NULL; + + p_pd_entry = kzalloc(sizeof(struct step_pd_entry), GFP_KERNEL); + if (p_pd_entry == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc fail\n"); + return NULL; + } + p_pd_entry->expires_ms = expires; + + INIT_DELAYED_WORK(&p_pd_entry->pd_work, wmt_step_pd_work); + INIT_LIST_HEAD(&(p_pd_entry->action_list.list)); + + return p_pd_entry; +} + +static void wmt_step_print_trigger_time(enum step_trigger_point_id tp_id, char *reason) +{ + const char *p_trigger_name = NULL; + + p_trigger_name = STEP_TRIGGER_TIME_NAME[tp_id]; + if (reason != NULL) + WMT_INFO_FUNC("STEP show: Trigger point: %s reason: %s\n", p_trigger_name, reason); + else + WMT_INFO_FUNC("STEP show: Trigger point: %s\n", p_trigger_name); +} + +static VOID wmt_step_do_actions_from_tp(enum step_trigger_point_id tp_id, char *reason) +{ + int result = 0; + + if (down_read_trylock(&g_step_env.init_rwsem)) { + if (g_step_env.is_enable == 0) + result = -1; + + if (tp_id <= STEP_TRIGGER_POINT_NO_DEFINE || tp_id >= STEP_TRIGGER_POINT_MAX) { + WMT_ERR_FUNC("STEP failed: Do actions from tp_id: %d\n", tp_id); + result = -1; + } else if (list_empty(&g_step_env.actions[tp_id].list)) { + result = -1; + } + + if (result == 0) { + wmt_step_print_trigger_time(tp_id, reason); + _wmt_step_do_actions(&g_step_env.actions[tp_id]); + } + + up_read(&g_step_env.init_rwsem); + } +} + +static int wmt_step_write_action(struct step_action_list *p_list, enum step_action_id act_id, + int param_num, char *params[]) +{ + struct step_action *p_action; + + if (p_list == NULL) { + WMT_ERR_FUNC("STEP failed: p_list is null\n"); + return -1; + } + + p_action = wmt_step_create_action(act_id, param_num, params); + if (p_action != NULL) { + list_add_tail(&(p_action->list), &(p_list->list)); + return 0; + } + + return -1; +} + +static int wmt_step_parse_number_with_symbol(char *ptr, long *value) +{ + int ret = STEP_VALUE_INFO_UNKNOWN; + + if (*ptr == '#') { + if (osal_strtol(ptr + 1, 10, value)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", ptr); + ret = STEP_VALUE_INFO_UNKNOWN; + } else { + ret = STEP_VALUE_INFO_SYMBOL_REG_BASE; + } + } else if (*ptr == '$') { + if (osal_strtol(ptr + 1, 10, value)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", ptr); + ret = STEP_VALUE_INFO_UNKNOWN; + } else { + ret = STEP_VALUE_INFO_SYMBOL_TEMP_REG; + } + } else { + if (osal_strtol(ptr, 0, value)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", ptr); + ret = STEP_VALUE_INFO_UNKNOWN; + } else { + ret = STEP_VALUE_INFO_NUMBER; + } + } + + return ret; +} + +static int wmt_step_parse_register_address(struct step_reg_addr_info *p_reg_addr, char *ptr, long offset) +{ + unsigned long res; + unsigned int symbol; + int num_sym; + + num_sym = wmt_step_parse_number_with_symbol(ptr, &res); + if (num_sym == STEP_VALUE_INFO_SYMBOL_REG_BASE) { + symbol = (unsigned int) res; + if (symbol <= STEP_REGISTER_PHYSICAL_ADDRESS || symbol >= STEP_REGISTER_MAX) { + WMT_ERR_FUNC("STEP failed: No support the base %s\n", ptr); + return -1; + } + res = g_step_env.reg_base[symbol].vir_addr; + + if (res == 0) { + WMT_ERR_FUNC("STEP failed: No support the base %s is 0\n", ptr); + return -1; + } + + if (offset >= g_step_env.reg_base[symbol].size) { + WMT_ERR_FUNC("STEP failed: symbol(%d), offset(%d) over max size(%llu)\n", + symbol, (int) offset, g_step_env.reg_base[symbol].size); + return -1; + } + + p_reg_addr->address = res; + p_reg_addr->address_type = symbol; + } else if (num_sym == STEP_VALUE_INFO_NUMBER) { + p_reg_addr->address = res; + p_reg_addr->address_type = STEP_REGISTER_PHYSICAL_ADDRESS; + } else { + WMT_ERR_FUNC("STEP failed: number with symbol parse fail %s\n", ptr); + return -1; + } + + return 0; +} + +static unsigned int wmt_step_parse_temp_register_id(char *ptr) +{ + unsigned long res; + int num_sym; + + num_sym = wmt_step_parse_number_with_symbol(ptr, &res); + + if (num_sym == STEP_VALUE_INFO_SYMBOL_TEMP_REG) + return res; + else + return STEP_TEMP_REGISTER_SIZE; +} + +static enum step_condition_operator_id wmt_step_parse_operator_id(char *ptr) +{ + if (osal_strcmp(ptr, ">") == 0) + return STEP_OPERATOR_GREATER; + else if (osal_strcmp(ptr, ">=") == 0) + return STEP_OPERATOR_GREATER_EQUAL; + else if (osal_strcmp(ptr, "<") == 0) + return STEP_OPERATOR_LESS; + else if (osal_strcmp(ptr, "<=") == 0) + return STEP_OPERATOR_LESS_EQUAL; + else if (osal_strcmp(ptr, "==") == 0) + return STEP_OPERATOR_EQUAL; + else if (osal_strcmp(ptr, "!=") == 0) + return STEP_OPERATOR_NOT_EQUAL; + else if (osal_strcmp(ptr, "&&") == 0) + return STEP_OPERATOR_AND; + else if (osal_strcmp(ptr, "||") == 0) + return STEP_OPERATOR_OR; + + return STEP_OPERATOR_MAX; +} + +static int wmt_step_operator_result_greater(int l_val, int r_val) +{ + return (l_val > r_val); +} + +static int wmt_step_operator_result_greater_equal(int l_val, int r_val) +{ + return (l_val >= r_val); +} + +static int wmt_step_operator_result_less(int l_val, int r_val) +{ + return (l_val < r_val); +} + +static int wmt_step_operator_result_less_equal(int l_val, int r_val) +{ + return (l_val <= r_val); +} + +static int wmt_step_operator_result_equal(int l_val, int r_val) +{ + return (l_val == r_val); +} + +static int wmt_step_operator_result_not_equal(int l_val, int r_val) +{ + return (l_val != r_val); +} + +static int wmt_step_operator_result_and(int l_val, int r_val) +{ + return (l_val && r_val); +} + +static int wmt_step_operator_result_or(int l_val, int r_val) +{ + return (l_val || r_val); +} + +static char *wmt_step_save_params_msg(int num, char *params[], char *buf, int buf_size) +{ + int i, len, temp; + + for (i = 0, len = 0; i < num; i++) { + if (params[i] == NULL) + break; + + temp = osal_strlen(params[i]) + 1; + + if ((len + temp) >= (buf_size - 1)) + break; + + len += temp; + osal_strncat(buf, params[i], temp); + osal_strncat(buf, " ", 1); + } + osal_strncat(buf, "\0", 1); + + return buf; +} + +static void wmt_step_create_emi_output_log(struct step_emi_info *p_emi_info, int write, + unsigned int begin, unsigned int end) +{ + p_emi_info->is_write = write; + p_emi_info->begin_offset = begin; + p_emi_info->end_offset = end; + p_emi_info->output_mode = STEP_OUTPUT_LOG; +} + +static void wmt_step_create_emi_output_register(struct step_emi_info *p_emi_info, int write, + unsigned int begin, unsigned int mask, unsigned int reg_id) +{ + p_emi_info->is_write = write; + p_emi_info->begin_offset = begin; + p_emi_info->end_offset = begin + 0x4; + p_emi_info->mask = mask; + p_emi_info->temp_reg_id = reg_id; + p_emi_info->output_mode = STEP_OUTPUT_REGISTER; +} + +static int _wmt_step_create_emi_action(struct step_emi_info *p_emi_info, int param_num, char *params[]) +{ + long write, begin, end; + unsigned int reg_id; + char buf[128] = ""; + long mask = 0xFFFFFFFF; + + if (param_num < 3) { + WMT_ERR_FUNC("STEP failed: Init EMI to log param(%d): %s\n", param_num, + wmt_step_save_params_msg(param_num, params, buf, 128)); + return -1; + } + + if (osal_strtol(params[0], 0, &write) || + osal_strtol(params[1], 0, &begin)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return -1; + } + + if (*params[(param_num - 1)] == STEP_TEMP_REGISTER_SYMBOL) { + reg_id = wmt_step_parse_temp_register_id(params[(param_num - 1)]); + if (reg_id >= STEP_PARAMETER_SIZE) { + WMT_ERR_FUNC("STEP failed: register id failed: %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return -1; + } + + if (param_num > 3) { + if (osal_strtol(params[2], 0, &mask)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return -1; + } + } + + wmt_step_create_emi_output_register(p_emi_info, write, begin, mask, reg_id); + } else { + if (osal_strtol(params[2], 0, &end)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return -1; + } + wmt_step_create_emi_output_log(p_emi_info, write, begin, end); + } + + return 0; +} + +/* + * Support: + * _EMI | R(0) | Begin offset | End offset + * _EMI | R(0) | Begin offset | mask | Output temp register ID ($) + * _EMI | R(0) | Begin offset | Output temp register ID ($) + */ +static struct step_action *wmt_step_create_emi_action(int param_num, char *params[]) +{ + struct step_emi_action *p_emi_act = NULL; + struct step_emi_info *p_emi_info = NULL; + int ret; + + p_emi_act = kzalloc(sizeof(struct step_emi_action), GFP_KERNEL); + if (p_emi_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc emi fail\n"); + return NULL; + } + + p_emi_info = &p_emi_act->info; + ret = _wmt_step_create_emi_action(p_emi_info, param_num, params); + + if (ret != 0) { + kfree(p_emi_act); + return NULL; + } + + return &(p_emi_act->base); +} + +/* + * Support: + * CEMI | Check temp register ID (#) | R(0) | Begin offset | End offset + * CEMI | Check temp register ID (#) | R(0) | Begin offset | mask | Output temp register ID ($) + * CEMI | Check temp register ID (#) | R(0) | Begin offset | Output temp register ID ($) + */ +static struct step_action *wmt_step_create_condition_emi_action(int param_num, char *params[]) +{ + struct step_condition_emi_action *p_cond_emi_act = NULL; + struct step_emi_info *p_emi_info = NULL; + unsigned int reg_id; + char buf[128] = ""; + int ret; + + if (param_num < 1) { + WMT_ERR_FUNC("STEP failed: EMI no params\n"); + return NULL; + } + + reg_id = wmt_step_parse_temp_register_id(params[0]); + if (reg_id >= STEP_PARAMETER_SIZE) { + WMT_ERR_FUNC("STEP failed: condition register id failed: %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + + p_cond_emi_act = kzalloc(sizeof(struct step_condition_emi_action), GFP_KERNEL); + if (p_cond_emi_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc condition emi fail\n"); + return NULL; + } + + p_emi_info = &p_cond_emi_act->info; + p_cond_emi_act->cond_reg_id = reg_id; + ret = _wmt_step_create_emi_action(p_emi_info, param_num - 1, ¶ms[1]); + + if (ret != 0) { + kfree(p_cond_emi_act); + return NULL; + } + + return &(p_cond_emi_act->base); +} + +static void wmt_step_create_read_register_output_register(struct step_reigster_info *p_reg_info, + struct step_reg_addr_info reg_addr_info, unsigned int offset, int mask, unsigned int reg_id) +{ + p_reg_info->is_write = 0; + p_reg_info->address_type = reg_addr_info.address_type; + p_reg_info->address = reg_addr_info.address; + p_reg_info->offset = offset; + p_reg_info->times = 1; + p_reg_info->delay_time = 0; + p_reg_info->mask = mask; + p_reg_info->temp_reg_id = reg_id; + p_reg_info->output_mode = STEP_OUTPUT_REGISTER; +} + +static void wmt_step_create_read_register_output_log(struct step_reigster_info *p_reg_info, + struct step_reg_addr_info reg_addr_info, unsigned int offset, unsigned int times, unsigned int delay_time) +{ + p_reg_info->is_write = 0; + p_reg_info->address_type = reg_addr_info.address_type; + p_reg_info->address = reg_addr_info.address; + p_reg_info->offset = offset; + p_reg_info->times = times; + p_reg_info->delay_time = delay_time; + p_reg_info->output_mode = STEP_OUTPUT_LOG; +} + +static void wmt_step_create_write_register_action(struct step_reigster_info *p_reg_info, + struct step_reg_addr_info reg_addr_info, unsigned int offset, int value, int mask) +{ + p_reg_info->is_write = 1; + p_reg_info->address_type = reg_addr_info.address_type; + p_reg_info->address = reg_addr_info.address; + p_reg_info->offset = offset; + p_reg_info->value = value; + p_reg_info->mask = mask; +} + +static int _wmt_step_create_register_action(struct step_reigster_info *p_reg_info, + int param_num, char *params[]) +{ + long write; + struct step_reg_addr_info reg_addr_info; + long offset, value; + unsigned int reg_id = 0; + char buf[128] = ""; + long mask = 0xFFFFFFFF; + long times = 1; + long delay_time = 0; + + if (param_num < 4) { + WMT_ERR_FUNC("STEP failed: Register no params\n"); + return -1; + } + + if (osal_strtol(params[0], 0, &write)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", + params[0]); + return -1; + } + + if (osal_strtol(params[2], 0, &offset)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return -1; + } + + if (wmt_step_parse_register_address(®_addr_info, params[1], offset) == -1) { + WMT_ERR_FUNC("STEP failed: init write register symbol: %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return -1; + } + + if (write == 0) { + if (*params[(param_num - 1)] == STEP_TEMP_REGISTER_SYMBOL) { + reg_id = wmt_step_parse_temp_register_id(params[(param_num - 1)]); + if (reg_id >= STEP_PARAMETER_SIZE) { + WMT_ERR_FUNC("STEP failed: register id failed: %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return -1; + } + + if (param_num > 4) { + if (osal_strtol(params[3], 0, &mask)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return -1; + } + } + + wmt_step_create_read_register_output_register(p_reg_info, reg_addr_info, offset, mask, reg_id); + } else { + if (param_num < 5 || + osal_strtol(params[3], 0, ×) || + osal_strtol(params[4], 0, &delay_time)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return -1; + } + + wmt_step_create_read_register_output_log(p_reg_info, reg_addr_info, offset, times, delay_time); + } + } else { + if (osal_strtol(params[3], 0, &value)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return -1; + } + + if (param_num > 4) { + if (osal_strtol(params[4], 0, &mask)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return -1; + } + } + + wmt_step_create_write_register_action(p_reg_info, reg_addr_info, offset, value, mask); + } + + return 0; +} + +/* + * Support: + * _REG | R(0) | Pre-define base address ID | offset | times | delay time(ms) + * _REG | R(0) | AP Physical address | offset | times | delay time(ms) + * _REG | R(0) | Pre-define base address ID | offset | mask | Output temp register ID ($) + * _REG | R(0) | AP Physical address | offset | mask | Output temp register ID ($) + * _REG | R(0) | Pre-define base address ID | offset | Output temp register ID ($) + * _REG | R(0) | AP Physical address | offset | Output temp register ID ($) + * _REG | W(1) | AP Physical address | offset | value + * _REG | W(1) | AP Physical address | offset | value + * _REG | W(1) | AP Physical address | offset | value | mask + * _REG | W(1) | AP Physical address | offset | value | mask + */ +static struct step_action *wmt_step_create_register_action(int param_num, char *params[]) +{ + struct step_register_action *p_reg_act = NULL; + struct step_reigster_info *p_reg_info; + int ret; + + p_reg_act = kzalloc(sizeof(struct step_register_action), GFP_KERNEL); + if (p_reg_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc register fail\n"); + return NULL; + } + + p_reg_info = &p_reg_act->info; + ret = _wmt_step_create_register_action(p_reg_info, param_num, params); + + if (ret != 0) { + kfree(p_reg_act); + return NULL; + } + + return &(p_reg_act->base); +} + +/* + * Support: + * CREG | Check temp register ID (#) | R(0) | Pre-define base address ID | offset | times | delay time(ms) + * CREG | Check temp register ID (#) | R(0) | AP Physical address | offset | times | delay time(ms) + * CREG | Check temp register ID (#) | R(0) | Pre-define base address ID | offset | mask | Output temp register ID ($) + * CREG | Check temp register ID (#) | R(0) | AP Physical address | offset | mask | Output temp register ID ($) + * CREG | Check temp register ID (#) | R(0) | Pre-define base address ID | offset | Output temp register ID ($) + * CREG | Check temp register ID (#) | R(0) | AP Physical address | offset | Output temp register ID ($) + * CREG | Check temp register ID (#) | W(1) | AP Physical address | offset | value + * CREG | Check temp register ID (#) | W(1) | AP Physical address | offset | value + * CREG | Check temp register ID (#) | W(1) | AP Physical address | offset | value | mask + * CREG | Check temp register ID (#) | W(1) | AP Physical address | offset | value | mask + */ +static struct step_action *wmt_step_create_condition_register_action(int param_num, char *params[]) +{ + struct step_condition_register_action *p_cond_reg_act = NULL; + struct step_reigster_info *p_reg_info; + unsigned int reg_id; + char buf[128] = ""; + int ret; + + if (param_num < 0) { + WMT_ERR_FUNC("STEP failed: Init EMI param(%d): %s\n", param_num, + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + + reg_id = wmt_step_parse_temp_register_id(params[0]); + if (reg_id >= STEP_PARAMETER_SIZE) { + WMT_ERR_FUNC("STEP failed: condition register id failed: %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + + p_cond_reg_act = kzalloc(sizeof(struct step_condition_register_action), GFP_KERNEL); + if (p_cond_reg_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc condition register fail\n"); + return NULL; + } + + p_reg_info = &p_cond_reg_act->info; + p_cond_reg_act->cond_reg_id = reg_id; + ret = _wmt_step_create_register_action(p_reg_info, param_num - 1, ¶ms[1]); + + if (ret != 0) { + kfree(p_cond_reg_act); + return NULL; + } + + return &(p_cond_reg_act->base); +} + +/* + * Support: + * GPIO | R(0) | Pin number + */ +static struct step_action *wmt_step_create_gpio_action(int param_num, char *params[]) +{ + struct step_gpio_action *p_gpio_act = NULL; + long write, symbol; + char buf[128] = ""; + + if (param_num != 2) { + WMT_ERR_FUNC("STEP failed: init gpio param(%d): %s\n", param_num, + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + + if (osal_strtol(params[0], 0, &write) || + osal_strtol(params[1], 0, &symbol)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + + p_gpio_act = kzalloc(sizeof(struct step_gpio_action), GFP_KERNEL); + if (p_gpio_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc gpio fail\n"); + return NULL; + } + p_gpio_act->is_write = write; + p_gpio_act->pin_symbol = symbol; + + return &(p_gpio_act->base); +} + +/* + * Support: + * DRST + */ +static struct step_action *wmt_step_create_disable_reset_action(int param_num, char *params[]) +{ + struct step_disable_reset_action *p_drst_act = NULL; + + p_drst_act = kzalloc(sizeof(struct step_disable_reset_action), GFP_KERNEL); + if (p_drst_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc disalbe reset fail\n"); + return NULL; + } + + return &(p_drst_act->base); +} + +/* + * Support: + * _RST + */ +static struct step_action *wmt_step_create_chip_reset_action(int param_num, char *params[]) +{ + struct step_chip_reset_action *p_crst_act = NULL; + + p_crst_act = kzalloc(sizeof(struct step_chip_reset_action), GFP_KERNEL); + if (p_crst_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc chip reset fail\n"); + return NULL; + } + + return &(p_crst_act->base); +} + +/* + * Support: + * WAK+ + */ +static struct step_action *wmt_step_create_keep_wakeup_action(int param_num, char *params[]) +{ + struct step_keep_wakeup_action *p_kwak_act = NULL; + + p_kwak_act = kzalloc(sizeof(struct step_keep_wakeup_action), GFP_KERNEL); + if (p_kwak_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc keep wakeup fail\n"); + return NULL; + } + + return &(p_kwak_act->base); +} + +/* + * Support: + * WAK- + */ +static struct step_action *wmt_step_create_cancel_wakeup_action(int param_num, char *params[]) +{ + struct step_cancel_wakeup_action *p_cwak_act = NULL; + + p_cwak_act = kzalloc(sizeof(struct step_cancel_wakeup_action), GFP_KERNEL); + if (p_cwak_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc cancel wakeup fail\n"); + return NULL; + } + + return &(p_cwak_act->base); +} + +/* + * Support: + * [PD+] | ms + */ +static struct step_action *wmt_step_create_periodic_dump_action(int param_num, char *params[]) +{ + struct step_periodic_dump_action *p_pd_act = NULL; + + if (params[0] == NULL) { + WMT_ERR_FUNC("STEP failed: param null\n"); + return NULL; + } + + p_pd_act = kzalloc(sizeof(struct step_periodic_dump_action), GFP_KERNEL); + if (p_pd_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc fail\n"); + return NULL; + } + + p_pd_act->pd_entry = (struct step_pd_entry *)params[0]; + return &(p_pd_act->base); +} + +/* + * Support: + * SHOW | Message (no space) + */ +static struct step_action *wmt_step_create_show_string_action(int param_num, char *params[]) +{ + struct step_show_string_action *p_show_act = NULL; + char buf[128] = ""; + + if (param_num != 1) { + WMT_ERR_FUNC("STEP failed: init show param(%d): %s\n", param_num, + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + + p_show_act = kzalloc(sizeof(struct step_show_string_action), GFP_KERNEL); + if (p_show_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc show string fail\n"); + return NULL; + } + + p_show_act->content = kzalloc((osal_strlen(params[0]) + 1), GFP_KERNEL); + if (p_show_act->content == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc show string content fail\n"); + kfree(p_show_act); + return NULL; + } + osal_memcpy(p_show_act->content, params[0], osal_strlen(params[0])); + return &(p_show_act->base); +} + +/* + * Support: + * _SLP | time (ms) + */ +static struct step_action *wmt_step_create_sleep_action(int param_num, char *params[]) +{ + struct step_sleep_action *p_sleep_act = NULL; + long ms; + char buf[128] = ""; + + if (param_num != 1) { + WMT_ERR_FUNC("STEP failed: init sleep param(%d): %s\n", param_num, + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + + if (osal_strtol(params[0], 0, &ms)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", + params[0]); + return NULL; + } + + p_sleep_act = kzalloc(sizeof(struct step_sleep_action), GFP_KERNEL); + if (p_sleep_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc sleep fail\n"); + return NULL; + } + p_sleep_act->ms = ms; + + return &(p_sleep_act->base); +} + +/* + * Support: + * COND | Check temp register ID ($) | Left temp register ID ($) | Operator | Right temp register ID ($) + * COND | Check temp register ID ($) | Left temp register ID ($) | Operator | value + */ +static struct step_action *wmt_step_create_condition_action(int param_num, char *params[]) +{ + struct step_condition_action *p_cond_act = NULL; + unsigned int res_reg_id, l_reg_id, r_reg_id = 0; + long value = 0; + int mode; + enum step_condition_operator_id op_id; + char buf[128] = ""; + + if (param_num != 4) { + WMT_ERR_FUNC("STEP failed: init sleep param(%d): %s\n", param_num, + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + + res_reg_id = wmt_step_parse_temp_register_id(params[0]); + l_reg_id = wmt_step_parse_temp_register_id(params[1]); + if (res_reg_id >= STEP_PARAMETER_SIZE || l_reg_id >= STEP_PARAMETER_SIZE) { + WMT_ERR_FUNC("STEP failed: register id failed: %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + + op_id = wmt_step_parse_operator_id(params[2]); + if (op_id >= STEP_OPERATOR_MAX) { + WMT_ERR_FUNC("STEP failed: operator id failed: %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + + if (*params[(param_num - 1)] == STEP_TEMP_REGISTER_SYMBOL) { + r_reg_id = wmt_step_parse_temp_register_id(params[3]); + mode = STEP_CONDITION_RIGHT_REGISTER; + if (r_reg_id >= STEP_PARAMETER_SIZE) { + WMT_ERR_FUNC("STEP failed: register id failed: %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + } else { + if (osal_strtol(params[3], 0, &value)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + mode = STEP_CONDITION_RIGHT_VALUE; + } + + p_cond_act = kzalloc(sizeof(struct step_condition_action), GFP_KERNEL); + if (p_cond_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc condition fail\n"); + return NULL; + } + + p_cond_act->result_temp_reg_id = res_reg_id; + p_cond_act->l_temp_reg_id = l_reg_id; + p_cond_act->operator_id = op_id; + p_cond_act->r_temp_reg_id = r_reg_id; + p_cond_act->value = value; + p_cond_act->mode = mode; + + return &(p_cond_act->base); +} + +/* + * Support: + * _VAL | Save temp register ID ($) | Value + */ +static struct step_action *wmt_step_create_value_action(int param_num, char *params[]) +{ + struct step_value_action *p_val_act = NULL; + unsigned int reg_id; + long value; + char buf[128] = ""; + + if (param_num != 2) { + WMT_ERR_FUNC("STEP failed: init sleep param(%d): %s\n", param_num, + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + + reg_id = wmt_step_parse_temp_register_id(params[0]); + if (reg_id >= STEP_PARAMETER_SIZE) { + WMT_ERR_FUNC("STEP failed: register id failed: %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + + if (osal_strtol(params[1], 0, &value)) { + WMT_ERR_FUNC("STEP failed: str to value %s\n", + wmt_step_save_params_msg(param_num, params, buf, 128)); + return NULL; + } + + p_val_act = kzalloc(sizeof(struct step_value_action), GFP_KERNEL); + if (p_val_act == NULL) { + WMT_ERR_FUNC("STEP failed: kzalloc value fail\n"); + return NULL; + } + + p_val_act->temp_reg_id = reg_id; + p_val_act->value = value; + + return &(p_val_act->base); +} + +static int wmt_step_do_write_register_action(struct step_reigster_info *p_reg_info, + STEP_DO_EXTRA func_do_extra) +{ + phys_addr_t phy_addr; + void __iomem *p_addr = NULL; + SIZE_T vir_addr; + + if (p_reg_info->address_type == STEP_REGISTER_PHYSICAL_ADDRESS) { + phy_addr = p_reg_info->address + p_reg_info->offset; + if (phy_addr & 0x3) { + WMT_ERR_FUNC("STEP failed: phy_addr(0x%08x) page failed\n", + (unsigned int)phy_addr); + return -1; + } + + p_addr = ioremap(phy_addr, 0x4); + if (p_addr) { + CONSYS_REG_WRITE_MASK((unsigned int *)p_addr, p_reg_info->value, p_reg_info->mask); + WMT_INFO_FUNC( + "STEP show: reg write Phy addr(0x%08x): 0x%08x\n", + (unsigned int)phy_addr, CONSYS_REG_READ(p_addr)); + if (func_do_extra != NULL) + func_do_extra(1, CONSYS_REG_READ(p_addr)); + iounmap(p_addr); + } else { + WMT_ERR_FUNC("STEP failed: ioremap(0x%08x) is NULL\n", + (unsigned int)phy_addr); + return -1; + } + } else { + vir_addr = p_reg_info->address + p_reg_info->offset; + if (vir_addr & 0x3) { + WMT_ERR_FUNC("STEP failed: vir_addr(0x%08x) page failed\n", + (unsigned int)vir_addr); + return -1; + } + + CONSYS_REG_WRITE_MASK((unsigned int *)vir_addr, p_reg_info->value, p_reg_info->mask); + WMT_INFO_FUNC( + "STEP show: reg write (symbol, offset)(%d, 0x%08x): 0x%08x\n", + p_reg_info->address_type, p_reg_info->offset, + CONSYS_REG_READ(vir_addr)); + if (func_do_extra != NULL) + func_do_extra(1, CONSYS_REG_READ(vir_addr)); + } + + return 0; +} + +static void _wmt_step_do_read_register_action(struct step_reigster_info *p_reg_info, + STEP_DO_EXTRA func_do_extra, char *info, int value) +{ + int i; + + for (i = 0; i < p_reg_info->times; i++) { + if (i > 0) + wmt_step_sleep_or_delay(p_reg_info->delay_time); + + if (p_reg_info->output_mode == STEP_OUTPUT_REGISTER) + g_step_env.temp_register[p_reg_info->temp_reg_id] = value & p_reg_info->mask; + else + WMT_INFO_FUNC("%s", info); + + if (func_do_extra != NULL) + func_do_extra(1, value); + } +} + +static int wmt_step_do_read_register_action(struct step_reigster_info *p_reg_info, + STEP_DO_EXTRA func_do_extra) +{ +#define WMT_STEP_REGISTER_ACTION_BUF_LEN 128 + phys_addr_t phy_addr; + void __iomem *p_addr = NULL; + SIZE_T vir_addr; + char buf[WMT_STEP_REGISTER_ACTION_BUF_LEN]; + + if (p_reg_info->address_type == STEP_REGISTER_PHYSICAL_ADDRESS) { + phy_addr = p_reg_info->address + p_reg_info->offset; + if (phy_addr & 0x3) { + WMT_ERR_FUNC("STEP failed: phy_addr(0x%08x) page failed\n", + (unsigned int)phy_addr); + return -1; + } + + p_addr = ioremap(phy_addr, 0x4); + if (p_addr) { + snprintf(buf, WMT_STEP_REGISTER_ACTION_BUF_LEN, + "STEP show: reg read Phy addr(0x%08x): 0x%08x\n", + (unsigned int)phy_addr, CONSYS_REG_READ(p_addr)); + _wmt_step_do_read_register_action(p_reg_info, func_do_extra, buf, + CONSYS_REG_READ(p_addr)); + iounmap(p_addr); + } else { + WMT_ERR_FUNC("STEP failed: ioremap(0x%08x) is NULL\n", + (unsigned int)phy_addr); + return -1; + } + } else { + vir_addr = p_reg_info->address + p_reg_info->offset; + if (vir_addr & 0x3) { + WMT_ERR_FUNC("STEP failed: vir_addr(0x%08x) page failed\n", + (unsigned int)vir_addr); + return -1; + } + + snprintf(buf, WMT_STEP_REGISTER_ACTION_BUF_LEN, + "STEP show: reg read (symbol, offset)(%d, 0x%08x): 0x%08x\n", + p_reg_info->address_type, p_reg_info->offset, + CONSYS_REG_READ(vir_addr)); + _wmt_step_do_read_register_action(p_reg_info, func_do_extra, buf, + CONSYS_REG_READ(vir_addr)); + } + + return 0; +} + +static void wmt_step_remove_emi_action(struct step_action *p_act) +{ + struct step_emi_action *p_emi_act = NULL; + + p_emi_act = list_entry_action(emi, p_act); + kfree(p_emi_act); +} + +static void wmt_step_remove_register_action(struct step_action *p_act) +{ + struct step_register_action *p_reg_act = NULL; + + p_reg_act = list_entry_action(register, p_act); + kfree(p_reg_act); +} + +static void wmt_step_remove_gpio_action(struct step_action *p_act) +{ + struct step_gpio_action *p_gpio_act = NULL; + + p_gpio_act = list_entry_action(gpio, p_act); + kfree(p_gpio_act); +} + +static void wmt_step_remove_disable_reset_action(struct step_action *p_act) +{ + struct step_disable_reset_action *p_drst = NULL; + + p_drst = list_entry_action(disable_reset, p_act); + kfree(p_drst); +} + +static void wmt_step_remove_chip_reset_action(struct step_action *p_act) +{ + struct step_chip_reset_action *p_crst = NULL; + + p_crst = list_entry_action(chip_reset, p_act); + kfree(p_crst); +} + +static void wmt_step_remove_keep_wakeup_action(struct step_action *p_act) +{ + struct step_keep_wakeup_action *p_kwak = NULL; + + p_kwak = list_entry_action(keep_wakeup, p_act); + kfree(p_kwak); +} + +static void wmt_step_remove_cancel_wakeup_action(struct step_action *p_act) +{ + struct step_cancel_wakeup_action *p_cwak = NULL; + + p_cwak = list_entry_action(cancel_wakeup, p_act); + kfree(p_cwak); +} + +static void wmt_step_remove_periodic_dump_action(struct step_action *p_act) +{ + struct step_periodic_dump_action *p_pd = NULL; + + p_pd = list_entry_action(periodic_dump, p_act); + kfree(p_pd); +} + +static void wmt_step_remove_show_string_action(struct step_action *p_act) +{ + struct step_show_string_action *p_show = NULL; + + p_show = list_entry_action(show_string, p_act); + if (p_show->content != NULL) + kfree(p_show->content); + + kfree(p_show); +} + +static void wmt_step_remove_sleep_action(struct step_action *p_act) +{ + struct step_sleep_action *p_sleep = NULL; + + p_sleep = list_entry_action(sleep, p_act); + kfree(p_sleep); +} + +static void wmt_step_remove_condition_action(struct step_action *p_act) +{ + struct step_condition_action *p_cond = NULL; + + p_cond = list_entry_action(condition, p_act); + kfree(p_cond); +} + +static void wmt_step_remove_value_action(struct step_action *p_act) +{ + struct step_value_action *p_val = NULL; + + p_val = list_entry_action(value, p_act); + kfree(p_val); +} + +static void wmt_step_remove_condition_emi_action(struct step_action *p_act) +{ + struct step_condition_emi_action *p_cond_emi_act = NULL; + + p_cond_emi_act = list_entry_action(condition_emi, p_act); + kfree(p_cond_emi_act); +} + +static void wmt_step_remove_condition_register_action(struct step_action *p_act) +{ + struct step_condition_register_action *p_cond_reg_act = NULL; + + p_cond_reg_act = list_entry_action(condition_register, p_act); + kfree(p_cond_reg_act); +} + +static int _wmt_step_do_emi_action(struct step_emi_info *p_emi_info, STEP_DO_EXTRA func_do_extra) +{ + unsigned char *p_emi_begin_addr = NULL, *p_emi_end_addr = NULL; + unsigned char __iomem *emi_base_addr = NULL; + unsigned int dis = 0, temp = 0, i = 0; + + if (p_emi_info->is_write != 0) { + WMT_ERR_FUNC("STEP failed: Only support dump EMI region\n"); + return -1; + } + + if (p_emi_info->begin_offset > p_emi_info->end_offset) { + temp = p_emi_info->begin_offset; + p_emi_info->begin_offset = p_emi_info->end_offset; + p_emi_info->end_offset = temp; + } + dis = p_emi_info->end_offset - p_emi_info->begin_offset; + + emi_base_addr = wmt_step_get_emi_base_address(); + if (emi_base_addr == NULL) { + WMT_ERR_FUNC("STEP failed: EMI base address is NULL\n"); + return -1; + } + + if (p_emi_info->begin_offset & 0x3) { + WMT_ERR_FUNC("STEP failed: begin offset(0x%08x) page failed\n", + p_emi_info->begin_offset); + return -1; + } + + p_emi_begin_addr = mtk_step_get_emi_virt_addr(emi_base_addr, p_emi_info->begin_offset); + p_emi_end_addr = mtk_step_get_emi_virt_addr(emi_base_addr, p_emi_info->end_offset); + if (!p_emi_begin_addr) { + WMT_ERR_FUNC("STEP failed: Get NULL begin virtual address 0x%08x\n", + p_emi_info->begin_offset); + return -1; + } + + if (!p_emi_end_addr) { + WMT_ERR_FUNC("STEP failed: Get NULL end virtual address 0x%08x\n", + p_emi_info->end_offset); + return -1; + } + + for (i = 0; i < dis; i += 0x4) { + if (p_emi_info->output_mode == STEP_OUTPUT_REGISTER) { + g_step_env.temp_register[p_emi_info->temp_reg_id] = + (CONSYS_REG_READ(p_emi_begin_addr + i) & p_emi_info->mask); + } else { + WMT_INFO_FUNC("STEP show: EMI action, Phy address(0x%08x): 0x%08x\n", + (unsigned int) (gConEmiPhyBase + p_emi_info->begin_offset + i), + CONSYS_REG_READ(p_emi_begin_addr + i)); + } + + if (func_do_extra != NULL) + func_do_extra(1, CONSYS_REG_READ(p_emi_begin_addr + i)); + } + + return 0; +} + +static bool wmt_step_reg_readable(struct step_reigster_info *p_reg_info) +{ + phys_addr_t phy_addr; + + if (p_reg_info->address_type == STEP_REGISTER_PHYSICAL_ADDRESS) { + phy_addr = p_reg_info->address + p_reg_info->offset; + if (mtk_consys_is_connsys_reg(phy_addr)) + return mtk_consys_check_reg_readable(); + else + return 1; + + } else { + if (p_reg_info->address_type == STEP_REGISTER_CONN_MCU_CONFIG_BASE || + p_reg_info->address_type == STEP_REGISTER_MISC_OFF_BASE || + p_reg_info->address_type == STEP_REGISTER_CFG_ON_BASE || + p_reg_info->address_type == STEP_REGISTER_HIF_ON_BASE || + p_reg_info->address_type == STEP_MCU_TOP_MISC_ON_BASE || + p_reg_info->address_type == STEP_CIRQ_BASE) + return mtk_consys_check_reg_readable(); + } + + return 1; +} + +static int _wmt_step_do_register_action(struct step_reigster_info *p_reg_info, STEP_DO_EXTRA func_do_extra) +{ + int ret = 0; + bool is_wakeup = g_step_env.is_keep_wakeup; + + if (is_wakeup == 1) { + if (DISABLE_PSM_MONITOR()) + WMT_ERR_FUNC("STEP failed: Wake up, continue to show register\n"); + } + + if (!wmt_step_reg_readable(p_reg_info)) { + WMT_ERR_FUNC("STEP failed: register cant read (No clock)\n"); + if (is_wakeup == 1) + ENABLE_PSM_MONITOR(); + + return -2; + } + + if (p_reg_info->is_write == 1) + ret = wmt_step_do_write_register_action(p_reg_info, func_do_extra); + else + ret = wmt_step_do_read_register_action(p_reg_info, func_do_extra); + + if (is_wakeup == 1) + ENABLE_PSM_MONITOR(); + + return ret; +} + +void wmt_step_setup(void) +{ + if (!g_step_env.is_setup) { + g_step_env.is_setup = true; + init_rwsem(&g_step_env.init_rwsem); + wmt_step_init_register_base_size(); + } +} + +/******************************************************************************* + * I N T E R N A L F U N C T I O N S W I T H U T +********************************************************************************/ +int wmt_step_do_emi_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + struct step_emi_action *p_emi_act = NULL; + struct step_emi_info *p_emi_info = NULL; + + p_emi_act = list_entry_action(emi, p_act); + p_emi_info = &p_emi_act->info; + return _wmt_step_do_emi_action(p_emi_info, func_do_extra); +} + +int wmt_step_do_condition_emi_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + struct step_condition_emi_action *p_cond_emi_act = NULL; + struct step_emi_info *p_emi_info = NULL; + + p_cond_emi_act = list_entry_action(condition_emi, p_act); + p_emi_info = &p_cond_emi_act->info; + + if (g_step_env.temp_register[p_cond_emi_act->cond_reg_id] == 0) { + WMT_INFO_FUNC("STEP show: Dont do emi, condition %c%d is %d\n", + STEP_TEMP_REGISTER_SYMBOL, p_emi_info->temp_reg_id, + g_step_env.temp_register[p_cond_emi_act->cond_reg_id]); + return -1; + } + + return _wmt_step_do_emi_action(p_emi_info, func_do_extra); +} + +int wmt_step_do_register_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + struct step_register_action *p_reg_act = NULL; + struct step_reigster_info *p_reg_info = NULL; + + p_reg_act = list_entry_action(register, p_act); + p_reg_info = &p_reg_act->info; + + return _wmt_step_do_register_action(p_reg_info, func_do_extra); +} + +int wmt_step_do_condition_register_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + struct step_condition_register_action *p_cond_reg_act = NULL; + struct step_reigster_info *p_reg_info = NULL; + + p_cond_reg_act = list_entry_action(condition_register, p_act); + p_reg_info = &p_cond_reg_act->info; + + if (g_step_env.temp_register[p_cond_reg_act->cond_reg_id] == 0) { + WMT_INFO_FUNC("STEP show: Dont do register, condition %c%d is %d\n", + STEP_TEMP_REGISTER_SYMBOL, p_reg_info->temp_reg_id, + g_step_env.temp_register[p_cond_reg_act->cond_reg_id]); + return -1; + } + + return _wmt_step_do_register_action(p_reg_info, func_do_extra); +} + +int wmt_step_do_gpio_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + struct step_gpio_action *p_gpio_act = NULL; + + p_gpio_act = list_entry_action(gpio, p_act); + if (p_gpio_act->is_write == 1) { + WMT_ERR_FUNC("STEP failed: Only support dump GPIO\n"); + return -1; + } + +#ifdef KERNEL_gpio_dump_regs_range + KERNEL_gpio_dump_regs_range(p_gpio_act->pin_symbol, p_gpio_act->pin_symbol); +#else + WMT_INFO_FUNC("STEP show: No support gpio dump\n"); +#endif + if (func_do_extra != NULL) + func_do_extra(0); + + return 0; +} + +int wmt_step_do_disable_reset_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + WMT_INFO_FUNC("STEP show: Do disable reset\n"); + mtk_wcn_stp_set_auto_rst(0); + if (func_do_extra != NULL) + func_do_extra(0); + + return 0; +} + +int wmt_step_do_chip_reset_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + WMT_INFO_FUNC("STEP show: Do chip reset\n"); + mtk_wcn_wmt_do_reset(WMTDRV_TYPE_WMT); + if (func_do_extra != NULL) + func_do_extra(0); + + return 0; +} + +int wmt_step_do_keep_wakeup_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + WMT_INFO_FUNC("STEP show: Do keep wake up\n"); + g_step_env.is_keep_wakeup = 1; + if (func_do_extra != NULL) + func_do_extra(0); + + return 0; +} + +int wmt_step_do_cancel_wakeup_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + WMT_INFO_FUNC("STEP show: Do cancel keep wake up\n"); + g_step_env.is_keep_wakeup = 0; + if (func_do_extra != NULL) + func_do_extra(0); + + return 0; +} + +int wmt_step_do_periodic_dump_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + struct step_periodic_dump_action *p_pd_act = NULL; + + p_pd_act = list_entry_action(periodic_dump, p_act); + if (p_pd_act->pd_entry->is_enable == 0) { + WMT_INFO_FUNC("STEP show: Start periodic dump(%d ms)\n", + p_pd_act->pd_entry->expires_ms); + wmt_step_start_work(p_pd_act->pd_entry); + p_pd_act->pd_entry->is_enable = 1; + } + + if (func_do_extra != NULL) + func_do_extra(0); + + return 0; +} + +int wmt_step_do_show_string_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + struct step_show_string_action *p_show_act = NULL; + + p_show_act = list_entry_action(show_string, p_act); + + WMT_INFO_FUNC("STEP show: %s\n", p_show_act->content); + + if (func_do_extra != NULL) + func_do_extra(1, p_show_act->content); + + return 0; +} + +int wmt_step_do_sleep_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + struct step_sleep_action *p_sleep_act = NULL; + + p_sleep_act = list_entry_action(sleep, p_act); + + wmt_step_sleep_or_delay(p_sleep_act->ms); + + if (func_do_extra != NULL) + func_do_extra(0); + + return 0; +} + +int wmt_step_do_condition_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + struct step_condition_action *p_cond_act = NULL; + int result, l_val, r_val; + + p_cond_act = list_entry_action(condition, p_act); + + l_val = g_step_env.temp_register[p_cond_act->l_temp_reg_id]; + + if (p_cond_act->mode == STEP_CONDITION_RIGHT_REGISTER) + r_val = g_step_env.temp_register[p_cond_act->r_temp_reg_id]; + else + r_val = p_cond_act->value; + + if (wmt_step_operator_result_map[p_cond_act->operator_id]) { + result = wmt_step_operator_result_map[p_cond_act->operator_id] (l_val, r_val); + g_step_env.temp_register[p_cond_act->result_temp_reg_id] = result; + + WMT_INFO_FUNC("STEP show: Condition %d(%c%d) op %d(%c%d) => %d(%c%d)\n", + l_val, STEP_TEMP_REGISTER_SYMBOL, p_cond_act->l_temp_reg_id, + r_val, STEP_TEMP_REGISTER_SYMBOL, p_cond_act->r_temp_reg_id, + result, STEP_TEMP_REGISTER_SYMBOL, p_cond_act->result_temp_reg_id); + } else { + WMT_ERR_FUNC("STEP failed: operator no define id: %d\n", p_cond_act->operator_id); + } + + if (func_do_extra != NULL) + func_do_extra(1, g_step_env.temp_register[p_cond_act->result_temp_reg_id]); + + return 0; +} + +int wmt_step_do_value_action(struct step_action *p_act, STEP_DO_EXTRA func_do_extra) +{ + struct step_value_action *p_val_act = NULL; + + p_val_act = list_entry_action(value, p_act); + + g_step_env.temp_register[p_val_act->temp_reg_id] = p_val_act->value; + + if (func_do_extra != NULL) + func_do_extra(1, g_step_env.temp_register[p_val_act->temp_reg_id]); + + return 0; +} + +struct step_action *wmt_step_create_action(enum step_action_id act_id, int param_num, char *params[]) +{ + struct step_action *p_act = NULL; + + if (act_id <= STEP_ACTION_INDEX_NO_DEFINE || act_id >= STEP_ACTION_INDEX_MAX) { + WMT_ERR_FUNC("STEP failed: Create action id: %d\n", act_id); + return NULL; + } + + if (wmt_step_action_map[act_id].func_create_action != NULL) + p_act = wmt_step_action_map[act_id].func_create_action(param_num, params); + else + WMT_ERR_FUNC("STEP failed: Create no define id: %d\n", act_id); + + if (p_act != NULL) + p_act->action_id = act_id; + + return p_act; +} + +int wmt_step_init_pd_env(void) +{ + g_step_env.pd_struct.step_pd_wq = create_workqueue(STEP_PERIODIC_DUMP_WORK_QUEUE); + if (!g_step_env.pd_struct.step_pd_wq) { + WMT_ERR_FUNC("create_workqueue fail\n"); + return -1; + } + INIT_LIST_HEAD(&g_step_env.pd_struct.pd_list); + + return 0; +} + +int wmt_step_deinit_pd_env(void) +{ + struct step_pd_entry *p_current; + struct step_pd_entry *p_next; + + if (!g_step_env.pd_struct.step_pd_wq) + return -1; + + list_for_each_entry_safe(p_current, p_next, &g_step_env.pd_struct.pd_list, list) { + cancel_delayed_work(&p_current->pd_work); + wmt_step_clear_action_list(&p_current->action_list); + } + destroy_workqueue(g_step_env.pd_struct.step_pd_wq); + + return 0; +} + +struct step_pd_entry *wmt_step_get_periodic_dump_entry(unsigned int expires) +{ + struct step_pd_entry *p_current; + + if (expires <= 0) + return NULL; + + if (!g_step_env.pd_struct.step_pd_wq) { + if (wmt_step_init_pd_env() != 0) + return NULL; + } + + p_current = wmt_step_create_periodic_dump_entry(expires); + if (p_current == NULL) + return NULL; + list_add_tail(&(p_current->list), &(g_step_env.pd_struct.pd_list)); + + return p_current; +} + +int wmt_step_parse_data(const char *in_buf, unsigned int size, + STEP_WRITE_ACT_TO_LIST func_act_to_list) +{ + struct step_target_act_list_info parse_info; + char *buf, *tmp_buf; + char *line; + + buf = osal_malloc(size + 1); + if (!buf) { + WMT_ERR_FUNC("STEP failed: Buf malloc\n"); + return -1; + } + + osal_memcpy(buf, (char *)in_buf, size); + buf[size] = '\0'; + + parse_info.tp_id = STEP_TRIGGER_POINT_NO_DEFINE; + parse_info.p_target_list = NULL; + parse_info.p_pd_entry = NULL; + + tmp_buf = buf; + while ((line = osal_strsep(&tmp_buf, "\r\n")) != NULL) + wmt_step_parse_line_data(line, &parse_info, func_act_to_list); + + osal_free(buf); + + return 0; +} + + +int wmt_step_read_file(const char *file_name) +{ + int ret = -1; + const osal_firmware *p_step_cfg = NULL; + + if (g_step_env.is_enable == 1) + return 0; + + if (0 == wmt_step_get_cfg(file_name, (osal_firmware **) &p_step_cfg)) { + if (0 == wmt_step_parse_data((const char *)p_step_cfg->data, p_step_cfg->size, + wmt_step_write_action)) { + ret = 0; + } else { + ret = -1; + } + + wmt_dev_patch_put((osal_firmware **) &p_step_cfg); + return ret; + } + + WMT_INFO_FUNC("STEP read file, %s is not exist\n", file_name); + + return ret; +} + +void wmt_step_remove_action(struct step_action *p_act) +{ + if (p_act != NULL) { + if (p_act->action_id <= STEP_ACTION_INDEX_NO_DEFINE || p_act->action_id >= STEP_ACTION_INDEX_MAX) { + WMT_ERR_FUNC("STEP failed: Wrong action id %d\n", (int)p_act->action_id); + return; + } + + if (wmt_step_action_map[p_act->action_id].func_remove_action != NULL) + wmt_step_action_map[p_act->action_id].func_remove_action(p_act); + } else { + WMT_ERR_FUNC("STEP failed: Action is NULL\n"); + } +} + +void wmt_step_print_version(void) +{ + WMT_INFO_FUNC("STEP version: %d\n", STEP_VERSION); +} + +/******************************************************************************* + * E X T E R N A L F U N C T I O N S +********************************************************************************/ +void wmt_step_init(void) +{ + wmt_step_setup(); + wmt_step_init_list(); + if (wmt_step_read_file(STEP_CONFIG_NAME) == 0) { + wmt_step_print_version(); + down_write(&g_step_env.init_rwsem); + g_step_env.is_enable = 1; + up_write(&g_step_env.init_rwsem); + } +} + +void wmt_step_deinit(void) +{ + down_write(&g_step_env.init_rwsem); + g_step_env.is_enable = 0; + up_write(&g_step_env.init_rwsem); + wmt_step_clear_list(); + wmt_step_unioremap_emi(); + wmt_step_deinit_pd_env(); +} + +void wmt_step_do_actions(enum step_trigger_point_id tp_id) +{ + wmt_step_do_actions_from_tp(tp_id, NULL); +} + +void wmt_step_func_crtl_do_actions(ENUM_WMTDRV_TYPE_T type, ENUM_WMT_OPID_T opId) +{ + enum step_trigger_point_id tp_id = STEP_TRIGGER_POINT_NO_DEFINE; + + if (type < WMTDRV_TYPE_BT || type >= WMTDRV_TYPE_MAX) { + WMT_ERR_FUNC("STEP failed: Do actions from type: %d\n", type); + return; + } + + switch (opId) { + case WMT_OPID_FUNC_OFF: + tp_id = wmt_step_func_ctrl_id[type][0]; + break; + case WMT_OPID_FUNC_ON: + tp_id = wmt_step_func_ctrl_id[type][1]; + break; + default: + break; + } + + if (tp_id != STEP_TRIGGER_POINT_NO_DEFINE) { + /* default value is 0*/ + wmt_step_do_actions(tp_id); + } +} + +void wmt_step_command_timeout_do_actions(char *reason) +{ + wmt_step_do_actions_from_tp(STEP_TRIGGER_POINT_COMMAND_TIMEOUT, reason); +} + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6580.h b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6580.h new file mode 100644 index 00000000000000..9ceee3b3942020 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6580.h @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_MT6580_H_ +#define _MTK_MT6580_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define MT6580_WORKAROUND 1 +#if MT6580_WORKAROUND +#define CONSYS_BT_WIFI_SHARE_V33 1 +#else +#define CONSYS_BT_WIFI_SHARE_V33 0 +#endif +#define CONSYS_PMIC_CTRL_ENABLE 1 +#define CONSYS_EMI_MPU_SETTING 1 +#define CONSYS_AHB_CLK_MAGEMENT 0 +#define CONSYS_USE_PLATFORM_WRITE 1 +#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 +#define CONSYS_CLOCK_BUF_CTRL 1 +#if defined(CONFIG_MTK_LEGACY) +#define CONFIG_MTK_PMIC_LEGACY 1 +#endif +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*tag start:new platform need to make sure these define */ +#define PLATFORM_SOC_CHIP 0x6580 +/*tag end*/ + +#ifdef CONFIG_OF +/*TOPCKGEN_BASE*/ +#define CONSYS_TOP_CLKCG_CLR_OFFSET 0x00000084 +#define CONSYS_TOP_CLKCG_SET_OFFSET 0x00000054 +#define CONSYS_WD_SYS_RST_OFFSET 0x00000018 +#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00001880 +#define CONSYS_EMI_MAPPING_OFFSET 0x00001320 +#define CONSYS_DA_XOBUF_OFFSET 0x0000013C +#define CONSYS_TOPAXI_PROT_EN_OFFSET 0x00001220 +#define CONSYS_TOPAXI_PROT_STA1_OFFSET 0x00001228 +#define CONSYS_PROT_MASK ((0x1<<9) | (0x1<<8))/*bit 9, 8*/ +/*AP_RGU_BASE*/ +#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 +/*SPM_BASE*/ +#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 +#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x00000280 +#define CONSYS_PWR_CONN_ACK_OFFSET 0x0000060c +#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000610 +/*CONN_MCU_CONFIG_BASE*/ +#define CONSYS_CHIP_ID_OFFSET 0x00000008 +#define CONSYS_ROM_RAM_DELSEL_OFFSET 0x00000114 +#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000110 +#define CONSYS_CPUPCR_OFFSET 0x00000160 +#endif /*END CONFIG_OF*/ + +/*tag start: connsys register base address (hard code, no use) */ +#define AP_RGU_BASE 0xF0007000 +#define TOPCKGEN_BASE 0xF0000000 +#define SPM_BASE 0xF0006000 +#define CONN_MCU_CONFIG_BASE 0xF8070000 +/*GIC Interrupt ID*/ +#define MT_CONN2AP_BTIF_WAKEUP_IRQ_ID 270 +/*tag end*/ + + +/*connsys register offset define(hard code mode)*/ +#if 1 +/*top clock gating control register*/ +#define CONSYS_TOP_CLKCG_CLR_REG (TOPCKGEN_BASE + 0x00000084) +#define CONSYS_TOP_CLKCG_SET_REG (TOPCKGEN_BASE + 0x00000054) +#define CONSYS_TOP_CLKCG_BIT (0x1 << 26) + +/*SPM clock gating control register*/ +#define CONSYS_PWRON_CONFG_EN_REG (SPM_BASE + 0x00000000) +#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) +#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) +#endif + +#define CONSYS_CPU_SW_RST_REG (AP_RGU_BASE + 0x00000018) +#define CONSYS_TOP1_PWR_CTRL_REG (SPM_BASE + 0x00000280) +#define CONSYS_PWR_CONN_ACK_REG (SPM_BASE + 0x0000060c) +#define CONSYS_PWR_CONN_ACK_S_REG (SPM_BASE + 0x00000610) + +#define CONSYS_WD_SYS_RST_REG (TOPCKGEN_BASE + 0x00000018) +#define CONSYS_CHIP_ID_REG (CONN_MCU_CONFIG_BASE + 0x00000008) +#define CONSYS_ROM_RAM_DELSEL_REG (CONN_MCU_CONFIG_BASE + 0x00000114) +#define CONSYS_MCU_CFG_ACR_REG (CONN_MCU_CONFIG_BASE + 0x00000110) +#define CONSYS_AFE_REG (CONN_TOP_CR_BASE + 0x00002000) +#define CONSYS_AFE_REG_DIG_RCK_01 (CONSYS_AFE_REG + 0x00000010) +#define CONSYS_AFE_REG_WBG_PLL_02 (CONSYS_AFE_REG + 0x00000028) +#define CONSYS_AFE_REG_WBG_WB_TX_01 (CONSYS_AFE_REG + 0x0000003c) +#define CONSYS_AFE_REG_DIG_RCK_01_VALUE (0x174b0160) +#define CONSYS_AFE_REG_WBG_PLL_02_VALUE (0x844083fe) +#define CONSYS_AFE_REG_WBG_WB_TX_01_VALUE (0x7fc39a20) + + +/*CONSYS_CPU_SW_RST_REG*/ +#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) +#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) + +/*CONSYS_TOP1_PWR_CTRL_REG*/ +#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) +#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) +#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) +#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) +#define CONSYS_CLK_CTRL_BIT (0x1 << 4) +#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) + +/*CONSYS_PWR_CONN_ACK_REG*/ +#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_ACK_S_REG*/ +#define CONSYS_PWR_CONN_ACK_S_BIT (0x1 << 1) + +/*CONSYS_WD_SYS_RST_REG*/ +#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) + +/*CONSYS_MCU_CFG_ACR_REG*/ +#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 18) + +/* EMI part mapping & ctrl*/ +#define CONSYS_EMI_COREDUMP_OFFSET (0x80000) +#define CONSYS_EMI_AP_PHY_BASE (0x80080000) +#define CONSYS_EMI_FW_PHY_BASE (0xf0080000) +#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) +#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) +#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) + +/*cpupcr*/ +#define CONSYS_CPUPCR_REG (CONN_MCU_CONFIG_BASE + 0x00000160) +/*emi mapping*/ +#define CONSYS_EMI_MAPPING (TOPCKGEN_BASE + CONSYS_EMI_MAPPING_OFFSET) + +/*control app2cnn_osc_en*/ +#define CONSYS_AP2CONN_OSC_EN_REG (TOPCKGEN_BASE + 0x00001800) +#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 16) +#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 17) + +/*paged dump address start*/ +#define CONSYS_PAGED_DUMP_START_ADDR (0xf0088400) + +/*full dump address start*/ +#define CONSYS_FULL_DUMP_START_ADDR (0xf0090400) +#define CONSYS_FULL_DUMP_DLM_LEN (0x1f000) +#define CONSYS_FULL_DUMP_SYSB2_START (CONSYS_FULL_DUMP_START_ADDR + CONSYS_FULL_DUMP_DLM_LEN) +#define CONSYS_FULL_DUMP_SYSB2_LEN (0x6800) +#define CONSYS_FULL_DUMP_SYSB3_START (CONSYS_FULL_DUMP_SYSB2_START + CONSYS_FULL_DUMP_SYSB2_LEN) +#define CONSYS_FULL_DUMP_SYSB3_LEN (0x16800) + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status { + UINT32 counter; + UINT32 flags; + spinlock_t lock; +}; + +extern struct bt_wifi_v33_status gBtWifiV33; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_MT6580_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6735.h b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6735.h new file mode 100644 index 00000000000000..a3b6463c402dff --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6735.h @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + + +#ifndef _MTK_MT6735_H_ +#define _MTK_MT6735_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define CONSYS_BT_WIFI_SHARE_V33 0 +#define CONSYS_PMIC_CTRL_ENABLE 1 +#define CONSYS_EMI_MPU_SETTING 1 +#define CONSYS_AHB_CLK_MAGEMENT 1 +#define CONSYS_USE_PLATFORM_WRITE 1 +#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 +#define CONSYS_CLOCK_BUF_CTRL 1 +#if defined(CONFIG_MTK_LEGACY) +#define CONFIG_MTK_PMIC_LEGACY 1 +#endif +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*tag start:new platform need to make sure these define */ +#if defined(CONFIG_ARCH_MT6735) || defined(CONFIG_MACH_MT6735) +#define PLATFORM_SOC_CHIP 0x0321 +#elif defined(CONFIG_ARCH_MT6735M) || defined(CONFIG_MACH_MT6735M) +#define PLATFORM_SOC_CHIP 0x0335 +#elif defined(CONFIG_ARCH_MT6753) || defined(CONFIG_MACH_MT6753) +#define PLATFORM_SOC_CHIP 0x0337 +#else +#define PLATFORM_SOC_CHIP 0x6735 +#endif +/*tag end*/ + +#ifdef CONFIG_OF +/*TOPCKGEN_BASE*/ +#define CONSYS_TOP_CLKCG_CLR_OFFSET 0x00000084 +#define CONSYS_TOP_CLKCG_SET_OFFSET 0x00000054 +#define CONSYS_WD_SYS_RST_OFFSET 0x00000018 +#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00000700 +#define CONSYS_EMI_MAPPING_OFFSET 0x00000320 +/*AP_RGU_BASE*/ +#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 +/*SPM_BASE*/ +#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 +#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x00000280 +#define CONSYS_PWR_CONN_ACK_OFFSET 0x0000060c +#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000610 +/*CONN_MCU_CONFIG_BASE*/ +#define CONSYS_CHIP_ID_OFFSET 0x00000008 +#define CONSYS_ROM_RAM_DELSEL_OFFSET 0x00000114 +#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000110 +#define CONSYS_CPUPCR_OFFSET 0x00000160 +/*AXI bus*/ +#define CONSYS_TOPAXI_PROT_EN_OFFSET 0x0220 +#define CONSYS_TOPAXI_PROT_STA1_OFFSET 0x0228 +#endif /* END CONFIG_OF*/ + +/*tag start: connsys register base address (hard code, no use) */ +#define AP_RGU_BASE 0xF0007000 +#define TOPCKGEN_BASE 0xF0000000 +#define SPM_BASE 0xF0006000 +#define CONN_MCU_CONFIG_BASE 0xF8070000 +/*GIC Interrupt ID*/ +#define MT_CONN2AP_BTIF_WAKEUP_IRQ_ID 259 +/*tag end*/ + +/*connsys register offset define(hard code mode)*/ +#if 1 + /*top clock gating control register */ +#define CONSYS_TOP_CLKCG_CLR_REG (TOPCKGEN_BASE + 0x00000084) +#define CONSYS_TOP_CLKCG_SET_REG (TOPCKGEN_BASE + 0x00000054) +#define CONSYS_TOP_CLKCG_BIT (0x1 << 26) + + /*SPM clock gating control register */ +#define CONSYS_PWRON_CONFG_EN_REG (SPM_BASE + 0x00000000) +#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) +#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) +#endif + +#define CONSYS_CPU_SW_RST_REG (AP_RGU_BASE + 0x00000018) +#define CONSYS_TOP1_PWR_CTRL_REG (SPM_BASE + 0x00000280) +#define CONSYS_PWR_CONN_ACK_REG (SPM_BASE + 0x0000060c) +#define CONSYS_PWR_CONN_ACK_S_REG (SPM_BASE + 0x00000610) + +#define CONSYS_WD_SYS_RST_REG (TOPCKGEN_BASE + 0x00000018) +#define CONSYS_CHIP_ID_REG (CONN_MCU_CONFIG_BASE + 0x00000008) +#define CONSYS_ROM_RAM_DELSEL_REG (CONN_MCU_CONFIG_BASE + 0x00000114) +#define CONSYS_MCU_CFG_ACR_REG (CONN_MCU_CONFIG_BASE + 0x00000110) +#define CONSYS_AFE_REG (CONN_TOP_CR_BASE + 0x00002000) +#define CONSYS_AFE_REG_DIG_RCK_01 (CONSYS_AFE_REG + 0x00000010) +#define CONSYS_AFE_REG_WBG_PLL_02 (CONSYS_AFE_REG + 0x00000028) +#define CONSYS_AFE_REG_WBG_WB_TX_01 (CONSYS_AFE_REG + 0x0000003c) +#define CONSYS_AFE_REG_DIG_RCK_01_VALUE (0x174b0160) +#define CONSYS_AFE_REG_WBG_PLL_02_VALUE (0x844083fe) +#define CONSYS_AFE_REG_WBG_WB_TX_01_VALUE (0x7fc39a20) + +#define CONSYS_TOPAXI_PROT_EN (TOPCKGEN_BASE + 0x0220) +#define CONSYS_TOPAXI_PROT_STA1 (TOPCKGEN_BASE + 0x0228) +#define CONSYS_PROT_MASK ((0x1<<2) | (0x1<<8)) /* bit 2, 8 */ +/*CONSYS_CPU_SW_RST_REG*/ +#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) +#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) + +/*CONSYS_TOP1_PWR_CTRL_REG*/ +#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) +#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) +#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) +#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) +#define CONSYS_CLK_CTRL_BIT (0x1 << 4) +#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) + +/*CONSYS_PWR_CONN_ACK_REG*/ +#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_ACK_S_REG*/ +#define CONSYS_PWR_CONN_ACK_S_BIT (0x1 << 1) + +/*CONSYS_WD_SYS_RST_REG*/ +#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) + +/*CONSYS_MCU_CFG_ACR_REG*/ +#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 18) + +/* EMI part mapping & ctrl*/ +#define CONSYS_EMI_COREDUMP_OFFSET (0x80000) +#define CONSYS_EMI_AP_PHY_BASE (0x80080000) +#define CONSYS_EMI_FW_PHY_BASE (0xf0080000) +#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) +#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) +#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) + +/*cpupcr*/ +#define CONSYS_CPUPCR_REG (CONN_MCU_CONFIG_BASE + 0x00000160) +/*emi mapping*/ +#define CONSYS_EMI_MAPPING (TOPCKGEN_BASE + CONSYS_EMI_MAPPING_OFFSET) + +/*control app2cnn_osc_en*/ +#define CONSYS_AP2CONN_OSC_EN_REG (TOPCKGEN_BASE + 0x00001800) +#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 10) +#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 9) + +/*paged dump address start*/ +#define CONSYS_PAGED_DUMP_START_ADDR (0xf0088400) + +/*full dump address start*/ +#define CONSYS_FULL_DUMP_START_ADDR (0xf0090400) +#define CONSYS_FULL_DUMP_DLM_LEN (0x1f000) +#define CONSYS_FULL_DUMP_SYSB2_START (CONSYS_FULL_DUMP_START_ADDR + CONSYS_FULL_DUMP_DLM_LEN) +#define CONSYS_FULL_DUMP_SYSB2_LEN (0x6800) +#define CONSYS_FULL_DUMP_SYSB3_START (CONSYS_FULL_DUMP_SYSB2_START + CONSYS_FULL_DUMP_SYSB2_LEN) +#define CONSYS_FULL_DUMP_SYSB3_LEN (0x16800) + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status { + UINT32 counter; + UINT32 flags; + spinlock_t lock; +}; + +extern struct bt_wifi_v33_status gBtWifiV33; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_MT6735_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6739.h b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6739.h new file mode 100644 index 00000000000000..684e2afdcce0d8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6739.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_MT6739_H_ +#define _MTK_MT6739_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +#define CONSYS_BT_WIFI_SHARE_V33 0 +#define CONSYS_PMIC_CTRL_ENABLE 1 +#define CONSYS_EMI_MPU_SETTING 1 +#define CONSYS_AHB_CLK_MAGEMENT 1 +#define CONSYS_USE_PLATFORM_WRITE 1 +#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 +#define CONSYS_CLOCK_BUF_CTRL 1 +#define CONSYS_AFE_REG_SETTING 0 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*tag start:new platform need to make sure these define */ +#define PLATFORM_SOC_CHIP 0x6739 +/*tag end*/ + +/*device tree mode*/ +#if CONFIG_OF +/*TOPCKGEN_BASE*/ +#define CONSYS_TOP_CLKCG_CLR_OFFSET 0x00000084 +#define CONSYS_TOP_CLKCG_SET_OFFSET 0x00000054 +#define CONSYS_WD_SYS_RST_OFFSET 0x00000018 +#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00001f00 +#define CONSYS_EMI_MAPPING_OFFSET 0x00001380 +/*AP_RGU_BASE*/ +#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 +/*SPM_BASE*/ +#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 +#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x0000032c +#define CONSYS_PWR_CONN_ACK_OFFSET 0x00000180 +#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000184 +/*CONN_MCU_CONFIG_BASE*/ +#define CONSYS_CHIP_ID_OFFSET 0x00000008 +#define CONSYS_ROM_RAM_DELSEL_OFFSET 0x00000114 +#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000110 +#define CONSYS_CPUPCR_OFFSET 0x00000160 +#endif +/*AXI bus*/ +#define CONSYS_TOPAXI_PROT_EN_OFFSET 0x1220 +#define CONSYS_TOPAXI_PROT_STA1_OFFSET 0x1228 + +/*tag start: connsys register base address (hard code, no use) */ +#define AP_RGU_BASE 0xF0007000 +#define TOPCKGEN_BASE 0xF0000000 +#define SPM_BASE 0xF0006000 +#define CONN_MCU_CONFIG_BASE 0xF8070000 +/*GIC Interrupt ID*/ +#define MT_CONN2AP_BTIF_WAKEUP_IRQ_ID 270 +/*tag end*/ + +/*connsys register offset define(hard code mode)*/ +#if 1 + /*top clock gating control register */ +#define CONSYS_TOP_CLKCG_CLR_REG (TOPCKGEN_BASE + 0x00000084) +#define CONSYS_TOP_CLKCG_SET_REG (TOPCKGEN_BASE + 0x00000054) +#define CONSYS_TOP_CLKCG_BIT (0x1 << 26) + + /*SPM clock gating control register */ +#define CONSYS_PWRON_CONFG_EN_REG (SPM_BASE + 0x00000000) +#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) +#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) +#endif + +#define CONSYS_CPU_SW_RST_REG (AP_RGU_BASE + 0x00000018) +#define CONSYS_TOP1_PWR_CTRL_REG (SPM_BASE + 0x0000032c) +#define CONSYS_PWR_CONN_ACK_REG (SPM_BASE + 0x00000180) +#define CONSYS_PWR_CONN_ACK_S_REG (SPM_BASE + 0x00000184) + +#define CONSYS_WD_SYS_RST_REG (TOPCKGEN_BASE + 0x00000018) +#define CONSYS_CHIP_ID_REG (CONN_MCU_CONFIG_BASE + 0x00000008) +#define CONSYS_ROM_RAM_DELSEL_REG (CONN_MCU_CONFIG_BASE + 0x00000114) +#define CONSYS_MCU_CFG_ACR_REG (CONN_MCU_CONFIG_BASE + 0x00000110) + +#if CONSYS_AFE_REG_SETTING +#define CONSYS_AFE_REG_BASE (0x180B2000) +#define CONSYS_AFE_REG_WBG_AFE_01_OFFSET (0x00000010) +#define CONSYS_AFE_REG_WBG_AFE_01_VALUE (0x00000000) +#define CONSYS_AFE_REG_WBG_PLL_03_OFFSET (0x00000038) +#define CONSYS_AFE_REG_WBG_PLL_03_VALUE (0x000C15F0) +#define CONSYS_AFE_REG_WBG_PLL_05_OFFSET (0x00000040) +#define CONSYS_AFE_REG_WBG_PLL_05_VALUE (0x07900020) +#define CONSYS_AFE_REG_WBG_WB_TX_01_OFFSET (0x00000088) +#define CONSYS_AFE_REG_WBG_WB_TX_01_VALUE (0x08440000) +#endif + +#define CONSYS_TOPAXI_PROT_EN (TOPCKGEN_BASE + 0x1220) +#define CONSYS_TOPAXI_PROT_STA1 (TOPCKGEN_BASE + 0x1228) +#define CONSYS_PROT_MASK ((0x1<<13) | (0x1<<14)) /* bit 13, 14 */ +/*CONSYS_CPU_SW_RST_REG*/ +#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) +#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) + +/*CONSYS_TOP1_PWR_CTRL_REG*/ +#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) +#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) +#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) +#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) +#define CONSYS_CLK_CTRL_BIT (0x1 << 4) +#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) + +/*CONSYS_PWR_CONN_ACK_REG*/ +#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_ACK_S_REG*/ +#define CONSYS_PWR_CONN_ACK_S_BIT (0x1 << 1) + +/*CONSYS_WD_SYS_RST_REG*/ +#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) + +/*CONSYS_MCU_CFG_ACR_REG*/ +#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 18) + +/* EMI part mapping & ctrl*/ +#define CONSYS_EMI_COREDUMP_OFFSET (0x80000) +#define CONSYS_EMI_AP_PHY_BASE (0x80080000) +#define CONSYS_EMI_FW_PHY_BASE (0xf0080000) +#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) +#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) +#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) + +/*cpupcr*/ +#define CONSYS_CPUPCR_REG (CONN_MCU_CONFIG_BASE + 0x00000160) +/*emi mapping*/ +#define CONSYS_EMI_MAPPING (TOPCKGEN_BASE + CONSYS_EMI_MAPPING_OFFSET) + +/*control app2cnn_osc_en*/ +#define CONSYS_AP2CONN_OSC_EN_REG (TOPCKGEN_BASE + 0x00001800) +#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 10) +#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 9) + +/*paged dump address start*/ +#define CONSYS_PAGED_DUMP_START_ADDR (0xf0088400) + +/*full dump address start*/ +#define CONSYS_FULL_DUMP_START_ADDR (0xf0090400) +#define CONSYS_FULL_DUMP_DLM_LEN (0x1f000) +#define CONSYS_FULL_DUMP_SYSB2_START (CONSYS_FULL_DUMP_START_ADDR + CONSYS_FULL_DUMP_DLM_LEN) +#define CONSYS_FULL_DUMP_SYSB2_LEN (0x6800) +#define CONSYS_FULL_DUMP_SYSB3_START (CONSYS_FULL_DUMP_SYSB2_START + CONSYS_FULL_DUMP_SYSB2_LEN) +#define CONSYS_FULL_DUMP_SYSB3_LEN (0x16800) + +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) +#define PMIC_DCXO_CW15 (0x0D46) +#define PMIC_DCXO_CW16 (0x0D48) +#define PMIC_DCXO_CW15_VAL (0x18) +#define AP_CONSYS_NOCO_CLOCK_BITA (0x1 << 11) +#define AP_CONSYS_NOCO_CLOCK_BITB (0x1 << 13) +#define AP_CONSYS_CO_CLOCK_BITA (0x1 << 10) +#define AP_CONSYS_CO_CLOCK_BITB (0x1 << 12) +#else +#define PMIC_DCXO_CW15 (0x701E) +#define PMIC_DCXO_CW16 (0x7000) +#define PMIC_DCXO_CW15_VAL (0x7) +#define AP_CONSYS_NOCO_CLOCK_BITA (0x1 << 7) +#define AP_CONSYS_NOCO_CLOCK_BITB (0x1 << 9) +#define AP_CONSYS_CO_CLOCK_BITA (0x1 << 6) +#define AP_CONSYS_CO_CLOCK_BITB (0x1 << 8) +#endif + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status { + UINT32 counter; + UINT32 flags; + spinlock_t lock; +}; + +extern struct bt_wifi_v33_status gBtWifiV33; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************* +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_MT6739_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6755.h b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6755.h new file mode 100644 index 00000000000000..896868c50a1496 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6755.h @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _MTK_MT6755_H_ +#define _MTK_MT6755_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +#define CONSYS_BT_WIFI_SHARE_V33 0 +#define CONSYS_PMIC_CTRL_ENABLE 1 +#define CONSYS_EMI_MPU_SETTING 1 +#define CONSYS_AHB_CLK_MAGEMENT 1 +#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 +#define CONSYS_CLOCK_BUF_CTRL 1 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*tag start:new platform need to make sure these define */ +#define PLATFORM_SOC_CHIP 0x6755 +/*tag end*/ + +/*device tree mode*/ +#if CONFIG_OF + +/*TOPCKGEN_BASE*/ +#define CONSYS_TOP_CLKCG_CLR_OFFSET 0x00000084 +#define CONSYS_TOP_CLKCG_SET_OFFSET 0x00000054 +#define CONSYS_WD_SYS_RST_OFFSET 0x00000018 +#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00001f00 +#define CONSYS_EMI_MAPPING_OFFSET 0x00001340 +/*AP_RGU_BASE*/ +#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 +/*SPM_BASE*/ +#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 +#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x0000032c +#define CONSYS_PWR_CONN_ACK_OFFSET 0x00000180 +#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000184 +/*CONN_MCU_CONFIG_BASE*/ +#define CONSYS_CHIP_ID_OFFSET 0x00000008 +#define CONSYS_ROM_RAM_DELSEL_OFFSET 0x00000114 +#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000110 +#define CONSYS_CPUPCR_OFFSET 0x00000160 +#endif +/*AXI bus*/ +#define CONSYS_TOPAXI_PROT_EN_OFFSET 0x1220 +#define CONSYS_TOPAXI_PROT_STA1_OFFSET 0x1228 + +/*tag start: connsys register base address (hard code, no use) */ +#define AP_RGU_BASE 0xF0007000 +#define TOPCKGEN_BASE 0xF0000000 +#define SPM_BASE 0xF0006000 +#define CONN_MCU_CONFIG_BASE 0xF8070000 +/*GIC Interrupt ID*/ +#define MT_CONN2AP_BTIF_WAKEUP_IRQ_ID 270 +/*tag end*/ + +/*connsys register offset define(hard code mode)*/ +#if 1 + /*top clock gating control register */ +#define CONSYS_TOP_CLKCG_CLR_REG (TOPCKGEN_BASE + 0x00000084) +#define CONSYS_TOP_CLKCG_SET_REG (TOPCKGEN_BASE + 0x00000054) +#define CONSYS_TOP_CLKCG_BIT (0x1 << 26) + + /*SPM clock gating control register */ +#define CONSYS_PWRON_CONFG_EN_REG (SPM_BASE + 0x00000000) +#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) +#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) +#endif + +#define CONSYS_CPU_SW_RST_REG (AP_RGU_BASE + 0x00000018) +#define CONSYS_TOP1_PWR_CTRL_REG (SPM_BASE + 0x0000032c) +#define CONSYS_PWR_CONN_ACK_REG (SPM_BASE + 0x00000180) +#define CONSYS_PWR_CONN_ACK_S_REG (SPM_BASE + 0x00000184) + +#define CONSYS_WD_SYS_RST_REG (TOPCKGEN_BASE + 0x00000018) +#define CONSYS_CHIP_ID_REG (CONN_MCU_CONFIG_BASE + 0x00000008) +#define CONSYS_ROM_RAM_DELSEL_REG (CONN_MCU_CONFIG_BASE + 0x00000114) +#define CONSYS_MCU_CFG_ACR_REG (CONN_MCU_CONFIG_BASE + 0x00000110) +#define CONSYS_AFE_REG (CONN_TOP_CR_BASE + 0x00002000) +#define CONSYS_AFE_REG_DIG_RCK_01 (CONSYS_AFE_REG + 0x00000010) +#define CONSYS_AFE_REG_WBG_PLL_02 (CONSYS_AFE_REG + 0x00000028) +#define CONSYS_AFE_REG_WBG_WB_TX_01 (CONSYS_AFE_REG + 0x0000003c) +#define CONSYS_AFE_REG_DIG_RCK_01_VALUE (0x174b0160) +#define CONSYS_AFE_REG_WBG_PLL_02_VALUE (0x844083fe) +#define CONSYS_AFE_REG_WBG_WB_TX_01_VALUE (0x7fc39a20) + +#define CONSYS_TOPAXI_PROT_EN (TOPCKGEN_BASE + 0x1220) +#define CONSYS_TOPAXI_PROT_STA1 (TOPCKGEN_BASE + 0x1228) +#define CONSYS_PROT_MASK ((0x1<<13) | (0x1<<14)) /* bit 13, 14 */ +/*CONSYS_CPU_SW_RST_REG*/ +#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) +#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) + +/*CONSYS_TOP1_PWR_CTRL_REG*/ +#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) +#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) +#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) +#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) +#define CONSYS_CLK_CTRL_BIT (0x1 << 4) +#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) + +/*CONSYS_PWR_CONN_ACK_REG*/ +#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_ACK_S_REG*/ +#define CONSYS_PWR_CONN_ACK_S_BIT (0x1 << 1) + +/*CONSYS_WD_SYS_RST_REG*/ +#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) + +/*CONSYS_MCU_CFG_ACR_REG*/ +#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 18) + +/* EMI part mapping & ctrl*/ +#define CONSYS_EMI_COREDUMP_OFFSET (0x80000) +#define CONSYS_EMI_AP_PHY_BASE (0x80080000) +#define CONSYS_EMI_FW_PHY_BASE (0xf0080000) +#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) +#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) +#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) + +/*cpupcr*/ +#define CONSYS_CPUPCR_REG (CONN_MCU_CONFIG_BASE + 0x00000160) +/*emi mapping*/ +#define CONSYS_EMI_MAPPING (TOPCKGEN_BASE + CONSYS_EMI_MAPPING_OFFSET) + +/*control app2cnn_osc_en*/ +#define CONSYS_AP2CONN_OSC_EN_REG (TOPCKGEN_BASE + 0x00001800) +#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 10) +#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 9) + +/*paged dump address start*/ +#define CONSYS_PAGED_DUMP_START_ADDR (0xf0088400) + +/*full dump address start*/ +#define CONSYS_FULL_DUMP_START_ADDR (0xf0090400) +#define CONSYS_FULL_DUMP_DLM_LEN (0x1f000) +#define CONSYS_FULL_DUMP_SYSB2_START (CONSYS_FULL_DUMP_START_ADDR + CONSYS_FULL_DUMP_DLM_LEN) +#define CONSYS_FULL_DUMP_SYSB2_LEN (0x6800) +#define CONSYS_FULL_DUMP_SYSB3_START (CONSYS_FULL_DUMP_SYSB2_START + CONSYS_FULL_DUMP_SYSB2_LEN) +#define CONSYS_FULL_DUMP_SYSB3_LEN (0x16800) + +/*clock type auto detection for jade and jade minus*/ +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) +#define PMIC_DCXO_CW15 0x0D46 +#define PMIC_DCXO_CW16 0x0D48 +#define PMIC_DCXO_CW15_VAL 0x18 +#define AP_CONSYS_NOCO_CLOCK_BITA (0x1 << 11) +#define AP_CONSYS_NOCO_CLOCK_BITB (0x1 << 13) +#define AP_CONSYS_CO_CLOCK_BITA (0x1 << 10) +#define AP_CONSYS_CO_CLOCK_BITB (0x1 << 12) +#else +#define PMIC_DCXO_CW15 0x701E +#define PMIC_DCXO_CW16 0x7000 +#define PMIC_DCXO_CW15_VAL 0x7 +#define AP_CONSYS_NOCO_CLOCK_BITA (0x1 << 7) +#define AP_CONSYS_NOCO_CLOCK_BITB (0x1 << 9) +#define AP_CONSYS_CO_CLOCK_BITA (0x1 << 6) +#define AP_CONSYS_CO_CLOCK_BITB (0x1 << 8) +#endif + +#define CLOCK_TYPE_TCXO 0 +#define CLOCK_TYPE_CO_TSX 1 +#define CLOCK_TYPE_CO_VCTCXO 3 + +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status { + UINT32 counter; + UINT32 flags; + spinlock_t lock; +}; + +extern struct bt_wifi_v33_status gBtWifiV33; +#endif + +#endif /* _MTK_MT6755_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6757.h b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6757.h new file mode 100644 index 00000000000000..51bde69365aef1 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6757.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_MT6757_H_ +#define _MTK_MT6757_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +#define CONSYS_BT_WIFI_SHARE_V33 0 +#define CONSYS_PMIC_CTRL_ENABLE 1 +#define CONSYS_EMI_MPU_SETTING 1 +#define CONSYS_AHB_CLK_MAGEMENT 1 +#define CONSYS_USE_PLATFORM_WRITE 1 +#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 +#define CONSYS_CLOCK_BUF_CTRL 1 +#define CONSYS_AFE_REG_SETTING 1 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*tag start:new platform need to make sure these define */ +#define PLATFORM_SOC_CHIP 0x6757 +/*tag end*/ + +/*device tree mode*/ +#if CONFIG_OF +/*TOPCKGEN_BASE*/ +#define CONSYS_TOP_CLKCG_CLR_OFFSET 0x00000084 +#define CONSYS_TOP_CLKCG_SET_OFFSET 0x00000054 +#define CONSYS_WD_SYS_RST_OFFSET 0x00000018 +#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00001f00 +#define CONSYS_EMI_MAPPING_OFFSET 0x00001380 +/*AP_RGU_BASE*/ +#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 +/*SPM_BASE*/ +#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 +#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x0000032c +#define CONSYS_PWR_CONN_ACK_OFFSET 0x00000180 +#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000184 +/*CONN_MCU_CONFIG_BASE*/ +#define CONSYS_CHIP_ID_OFFSET 0x00000008 +#define CONSYS_ROM_RAM_DELSEL_OFFSET 0x00000114 +#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000110 +#define CONSYS_CPUPCR_OFFSET 0x00000160 +#endif +/*AXI bus*/ +#define CONSYS_TOPAXI_PROT_EN_OFFSET 0x1220 +#define CONSYS_TOPAXI_PROT_STA1_OFFSET 0x1228 + +/*tag start: connsys register base address (hard code, no use) */ +#define AP_RGU_BASE 0xF0007000 +#define TOPCKGEN_BASE 0xF0000000 +#define SPM_BASE 0xF0006000 +#define CONN_MCU_CONFIG_BASE 0xF8070000 +/*GIC Interrupt ID*/ +#define MT_CONN2AP_BTIF_WAKEUP_IRQ_ID 270 +/*tag end*/ + +/*connsys register offset define(hard code mode)*/ +#if 1 + /*top clock gating control register */ +#define CONSYS_TOP_CLKCG_CLR_REG (TOPCKGEN_BASE + 0x00000084) +#define CONSYS_TOP_CLKCG_SET_REG (TOPCKGEN_BASE + 0x00000054) +#define CONSYS_TOP_CLKCG_BIT (0x1 << 26) + + /*SPM clock gating control register */ +#define CONSYS_PWRON_CONFG_EN_REG (SPM_BASE + 0x00000000) +#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) +#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) +#endif + +#define CONSYS_CPU_SW_RST_REG (AP_RGU_BASE + 0x00000018) +#define CONSYS_TOP1_PWR_CTRL_REG (SPM_BASE + 0x0000032c) +#define CONSYS_PWR_CONN_ACK_REG (SPM_BASE + 0x00000180) +#define CONSYS_PWR_CONN_ACK_S_REG (SPM_BASE + 0x00000184) + +#define CONSYS_WD_SYS_RST_REG (TOPCKGEN_BASE + 0x00000018) +#define CONSYS_CHIP_ID_REG (CONN_MCU_CONFIG_BASE + 0x00000008) +#define CONSYS_ROM_RAM_DELSEL_REG (CONN_MCU_CONFIG_BASE + 0x00000114) +#define CONSYS_MCU_CFG_ACR_REG (CONN_MCU_CONFIG_BASE + 0x00000110) + +#if CONSYS_AFE_REG_SETTING +#define CONSYS_AFE_REG_BASE (0x180B2000) +#define CONSYS_AFE_REG_WBG_AFE_01_OFFSET (0x00000010) +#define CONSYS_AFE_REG_WBG_AFE_01_VALUE (0x00000001) +#define CONSYS_AFE_REG_WBG_PLL_03_OFFSET (0x00000038) +#define CONSYS_AFE_REG_WBG_PLL_03_VALUE (0x000C15F0) +#define CONSYS_AFE_REG_WBG_PLL_05_OFFSET (0x00000040) +#define CONSYS_AFE_REG_WBG_PLL_05_VALUE (0x07900020) +#define CONSYS_AFE_REG_WBG_WB_TX_01_OFFSET (0x00000088) +#define CONSYS_AFE_REG_WBG_WB_TX_01_VALUE (0x08440000) +#endif + +#define CONSYS_TOPAXI_PROT_EN (TOPCKGEN_BASE + 0x1220) +#define CONSYS_TOPAXI_PROT_STA1 (TOPCKGEN_BASE + 0x1228) +#define CONSYS_PROT_MASK ((0x1<<13) | (0x1<<14)) /* bit 13, 14 */ +/*CONSYS_CPU_SW_RST_REG*/ +#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) +#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) + +/*CONSYS_TOP1_PWR_CTRL_REG*/ +#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) +#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) +#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) +#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) +#define CONSYS_CLK_CTRL_BIT (0x1 << 4) +#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) + +/*CONSYS_PWR_CONN_ACK_REG*/ +#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_ACK_S_REG*/ +#define CONSYS_PWR_CONN_ACK_S_BIT (0x1 << 1) + +/*CONSYS_WD_SYS_RST_REG*/ +#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) + +/*CONSYS_MCU_CFG_ACR_REG*/ +#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 18) + +/* EMI part mapping & ctrl*/ +#define CONSYS_EMI_COREDUMP_OFFSET (0x80000) +#define CONSYS_EMI_AP_PHY_BASE (0x80080000) +#define CONSYS_EMI_FW_PHY_BASE (0xf0080000) +#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) +#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) +#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) + +/*cpupcr*/ +#define CONSYS_CPUPCR_REG (CONN_MCU_CONFIG_BASE + 0x00000160) +/*emi mapping*/ +#define CONSYS_EMI_MAPPING (TOPCKGEN_BASE + CONSYS_EMI_MAPPING_OFFSET) + +/*control app2cnn_osc_en*/ +#define CONSYS_AP2CONN_OSC_EN_REG (TOPCKGEN_BASE + 0x00001800) +#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 10) +#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 9) + +/*paged dump address start*/ +#define CONSYS_PAGED_DUMP_START_ADDR (0xf0088400) + +/*full dump address start*/ +#define CONSYS_FULL_DUMP_START_ADDR (0xf0090400) +#define CONSYS_FULL_DUMP_DLM_LEN (0x1f000) +#define CONSYS_FULL_DUMP_SYSB2_START (CONSYS_FULL_DUMP_START_ADDR + CONSYS_FULL_DUMP_DLM_LEN) +#define CONSYS_FULL_DUMP_SYSB2_LEN (0x6800) +#define CONSYS_FULL_DUMP_SYSB3_START (CONSYS_FULL_DUMP_SYSB2_START + CONSYS_FULL_DUMP_SYSB2_LEN) +#define CONSYS_FULL_DUMP_SYSB3_LEN (0x16800) + +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) +#define PMIC_DCXO_CW15 (0x0D46) +#define PMIC_DCXO_CW16 (0x0D48) +#define PMIC_DCXO_CW15_VAL (0x18) +#define AP_CONSYS_NOCO_CLOCK_BITA (0x1 << 11) +#define AP_CONSYS_NOCO_CLOCK_BITB (0x1 << 13) +#define AP_CONSYS_CO_CLOCK_BITA (0x1 << 10) +#define AP_CONSYS_CO_CLOCK_BITB (0x1 << 12) +#else +#define PMIC_DCXO_CW15 (0x701E) +#define PMIC_DCXO_CW16 (0x7000) +#define PMIC_DCXO_CW15_VAL (0x7) +#define AP_CONSYS_NOCO_CLOCK_BITA (0x1 << 7) +#define AP_CONSYS_NOCO_CLOCK_BITB (0x1 << 9) +#define AP_CONSYS_CO_CLOCK_BITA (0x1 << 6) +#define AP_CONSYS_CO_CLOCK_BITB (0x1 << 8) +#endif + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status { + UINT32 counter; + UINT32 flags; + spinlock_t lock; +}; + +extern struct bt_wifi_v33_status gBtWifiV33; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************* +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_MT6757_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6761.h b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6761.h new file mode 100644 index 00000000000000..ced9b37a4e6ae6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6761.h @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_MT6761_H_ +#define _MTK_MT6761_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +#define CONSYS_BT_WIFI_SHARE_V33 0 +#define CONSYS_PMIC_CTRL_ENABLE 1 +#define CONSYS_AHB_CLK_MAGEMENT 1 +#define CONSYS_USE_PLATFORM_WRITE 1 +#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 +#define CONSYS_AFE_REG_SETTING 1 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*tag start:new platform need to make sure these define */ +#define PLATFORM_SOC_CHIP 0x6761 +/*tag end*/ + +/*device tree mode*/ +/* A-Die interface pinmux base */ +#define CONSYS_IF_PINMUX_REG_BASE 0x10005000 +#define CONSYS_IF_PINMUX_01_OFFSET 0x000003F0 +#define CONSYS_IF_PINMUX_01_MASK 0xFFFFFF88 +#define CONSYS_IF_PINMUX_01_VALUE 0x00000011 +#define CONSYS_IF_PINMUX_02_OFFSET 0x000003E0 +#define CONSYS_IF_PINMUX_02_MASK 0x8888888F +#define CONSYS_IF_PINMUX_02_VALUE 0x11111110 +#define CONSYS_IF_DRV_PINMUX_REG_BASE 0x10420000 +#define CONSYS_IF_DRV_PINMUX_MASK 0xF8FFFFFF + +/*TOPCKGEN_BASE*/ +#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00000f00 +#define CONSYS_EMI_MAPPING_OFFSET 0x00000380 +#define CONSYS_EMI_PERI_MAPPING_OFFSET 0x00000388 +/*AP_RGU_BASE*/ +#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 +/*SPM_BASE*/ +#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 +#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x0000032C +#define CONSYS_PWR_CONN_ACK_OFFSET 0x00000180 +#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000184 +#define CONSYS_SPM_APSRC_OFFSET 0x000006f8 +#define CONSYS_SPM_APSRC_VALUE 0x00000005 +#define CONSYS_SPM_DDR_EN_OFFSET 0x000006fc +#define CONSYS_SPM_DDR_EN_VALUE 0x00050505 +/*CONN_MCU_CONFIG_BASE*/ +#define CONSYS_IP_VER_OFFSET 0x00000010 +#define CONSYS_CONF_ID_OFFSET 0x0000001c +#define CONSYS_HW_ID_OFFSET 0x00000000 +#define CONSYS_FW_ID_OFFSET 0x00000004 +#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000140 +#define CONSYS_CPUPCR_OFFSET 0x00000104 +#define CONSYS_SW_IRQ_OFFSET 0x00000150 +#define CONSYS_CLOCK_CONTROL 0x00000100 +#define CONSYS_BUS_CONTROL 0x00000110 +#define CONSYS_DEBUG_SELECT 0x00000400 +#define CONSYS_DEBUG_STATUS 0x0000040c +#define CONSYS_EMI_CTRL_VALUE (1 << 0 | 1 << 15 | 1 << 21) +/*CONN_HIF_TOP*/ +#define CONSYS_HIF_TOP_MISC 0x00000104 +#define CONSYS_HIF_DBG_IDX 0x0000012C +#define CONSYS_HIF_DBG_PROBE 0x00000130 +#define CONSYS_HIF_BUSY_STATUS 0x00000138 +#define CONSYS_HIF_PDMA_AXI_RREADY 0x00000154 +#define CONSYS_HIF_PDMA_BUSY_STATUS 0x00000168 + +/*CONN_HIF_ON_BASE*/ +#define CONSYS_BUSY_OFFSET 0x110 +#define CONSYS_BUSY_BIT (0x1 << 27) +#define CONSYS_CLOCK_CHECK_VALUE 0x30000 +#define CONSYS_HCLK_CHECK_BIT (0x1 << 16) +#define CONSYS_OSCCLK_CHECK_BIT (0x1 << 17) +#define CONSYS_SLEEP_CHECK_BIT (0x1 << 18) + +/*CONN_TOP_MISC_ON_BASE*/ +#define CONN_ON_HOST_CSR_MISC 0x14c +#define CONN_ON_IRQ_CTL 0x170 +#define CONN_ON_IRQ_STATUS 0x174 + + +/*AXI bus*/ +#define CONSYS_AHBAXI_PROT_EN_OFFSET 0x220 +#define CONSYS_AHBAXI_PROT_STA_OFFSET 0x228 +#define CONSYS_AXI_TX_PROT_EN_OFFSET 0x250 +#define CONSYS_AXI_TX_PROT_STA_OFFSET 0x258 +#define CONSYS_PROT_MASK ((0x1<<13) | (0x1<<14)) /* bit 13, 14 */ +#define CONSYS_TX_PROT_MASK (0x1<<18) /* bit 18 */ +#define CONSYS_PDMA_AXI_RREADY_MASK (0x1 << 1) /* bit 1 */ + +/*SPM clock gating control register */ +#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) +#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) + +#if CONSYS_AFE_REG_SETTING +#define CONSYS_AFE_REG_BASE (0x180B3000) +#define CONSYS_AFE_RG_WBG_01_OFFSET (0x00000010) +#define CONSYS_AFE_RG_WBG_01_VALUE (0x00000004) +#define CONSYS_AFE_RG_WBG_GPS_01_OFFSET (0x00000040) +#define CONSYS_AFE_RG_WBG_GPS_01_VALUE (0xEF904400) +#define CONSYS_AFE_RG_WBG_BT_RX_01_OFFSET (0x00000048) +#define CONSYS_AFE_RG_WBG_BT_RX_01_VALUE (0xEFC82200) +#define CONSYS_AFE_RG_WBG_WF0_RX_01_OFFSET (0x00000068) +#define CONSYS_AFE_RG_WBG_WF0_RX_01_VALUE (0xFBF21102) +#endif + +#define CONSYS_COCLOCK_STABLE_TIME_BASE (0x180C1200) +#define CONSYS_COCLOCK_ACK_ENABLE_OFFSET (0x4) +#define CONSYS_COCLOCK_ACK_ENABLE_BIT (1 << 0) +#define CONSYS_COCLOCK_STABLE_TIME (0x2223) +#define CONSYS_COCLOCK_STABLE_TIME_MASK (0xffff0000) + +/*CONSYS_CPU_SW_RST_REG*/ +#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) +#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_SW_RST_BIT (0x1 << 9) + +/*CONSYS_TOP1_PWR_CTRL_REG*/ +#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) +#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) +#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) +#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) +#define CONSYS_CLK_CTRL_BIT (0x1 << 4) +#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) + +/*CONSYS_PWR_CONN_ACK_REG*/ +#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_ACK_S_REG*/ +#define CONSYS_PWR_ON_ACK_S_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_TOP2_ACK_REG*/ +#define CONSYS_TOP2_PWR_ON_ACK_BIT (0x1 << 30) + +/*CONSYS_PWR_CONN_TOP2_ACK_S_REG*/ +#define CONSYS_TOP2_PWR_ON_ACK_S_BIT (0x1 << 30) + +/*CONSYS_WD_SYS_RST_REG*/ +#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) + +/*CONSYS_MCU_CFG_ACR_REG*/ +#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 0 | 0x1 << 1) + +/*control app2cnn_osc_en*/ +#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 10) +#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 9) + +/* EMI part mapping & ctrl*/ +#define CONSYS_EMI_COREDUMP_OFFSET (0x68000) +#define CONSYS_EMI_AP_PHY_OFFSET (0x00000) +#define CONSYS_EMI_AP_PHY_BASE (0x80068000) +#define CONSYS_EMI_FW_PHY_BASE (0xf0068000) +#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) +#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) +#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) +#define CONSYS_EMI_MET_DATA_OFFSET (0x0) + +#define CONSYS_EMI_RAM_BT_BUILDTIME_OFFSET (0x68300) +#define CONSYS_EMI_RAM_WIFI_BUILDTIME_OFFSET (0x68310) +#define CONSYS_EMI_RAM_MCU_BUILDTIME_OFFSET (0x68320) +#define CONSYS_EMI_PATCH_MCU_BUILDTIME_OFFSET (0x68330) + +/*CONSYS_MCU_CFG_DBG_LP_INFO*/ +#define CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR (conn_reg.mcu_cfg_on_base + 0x104) +#define CONN_CFG_ON_CONN_ON_MON_CTL_ADDR (conn_reg.mcu_top_misc_on_base + 0x320) +#define CONN_CFG_ON_CONN_ON_DBGSEL_ADDR (conn_reg.mcu_top_misc_on_base + 0x310) +#define CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_ADDR (conn_reg.mcu_top_misc_on_base + 0x340) +#define CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_MAPPING_AP_ADDR (0x180c1340) + +/* default coex wmt ant_sel cr address */ +#define DEFAULT_COEX_WMT_ANTSEL_0_POLARITY_CR 0x80025310 +#define DEFAULT_COEX_WMT_ANTSEL_1_POLARITY_CR 0x80025310 +#define DEFAULT_COEX_WMT_ANTSEL_2_POLARITY_CR 0x80025314 +#define DEFAULT_COEX_WMT_ANTSEL_3_POLARITY_CR 0x80025314 +#define DEFAULT_COEX_WMT_ANTSEL_4_POLARITY_CR 0x80025318 +#define DEFAULT_COEX_WMT_ANTSEL_5_POLARITY_CR 0x80025318 +#define DEFAULT_COEX_WMT_ANTSEL_6_POLARITY_CR 0x8002531C +#define DEFAULT_COEX_WMT_ANTSEL_7_POLARITY_CR 0x8002531C + +/* default coex wmt ant_sel cr bit */ +#define DEFAULT_COEX_WMT_ANTSEL_0_POLARITY_BIT 8 +#define DEFAULT_COEX_WMT_ANTSEL_1_POLARITY_BIT 24 +#define DEFAULT_COEX_WMT_ANTSEL_2_POLARITY_BIT 8 +#define DEFAULT_COEX_WMT_ANTSEL_3_POLARITY_BIT 24 +#define DEFAULT_COEX_WMT_ANTSEL_4_POLARITY_BIT 8 +#define DEFAULT_COEX_WMT_ANTSEL_5_POLARITY_BIT 24 +#define DEFAULT_COEX_WMT_ANTSEL_6_POLARITY_BIT 8 +#define DEFAULT_COEX_WMT_ANTSEL_7_POLARITY_BIT 24 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#ifdef CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status { + UINT32 counter; + UINT32 flags; + spinlock_t lock; +}; + +extern struct bt_wifi_v33_status gBtWifiV33; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************* +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_MT6761_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6763.h b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6763.h new file mode 100644 index 00000000000000..961a64b0fd74d0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6763.h @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_MT6763_H_ +#define _MTK_MT6763_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +#define CONSYS_BT_WIFI_SHARE_V33 0 +#define CONSYS_PMIC_CTRL_ENABLE 1 +#define CONSYS_EMI_MPU_SETTING 1 +#define CONSYS_AHB_CLK_MAGEMENT 1 +#define CONSYS_USE_PLATFORM_WRITE 1 +#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 +#define CONSYS_CLOCK_BUF_CTRL 1 +#define CONSYS_AFE_REG_SETTING 1 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*tag start:new platform need to make sure these define */ +#define PLATFORM_SOC_CHIP 0x6763 +/*tag end*/ + +/*device tree mode*/ +#if CONFIG_OF +/*TOPCKGEN_BASE*/ +#define CONSYS_TOP_CLKCG_CLR_OFFSET 0x00000084 +#define CONSYS_TOP_CLKCG_SET_OFFSET 0x00000054 +#define CONSYS_WD_SYS_RST_OFFSET 0x00000018 +#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00001f00 +#define CONSYS_EMI_MAPPING_OFFSET 0x00001380 +/*AP_RGU_BASE*/ +#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 +/*SPM_BASE*/ +#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 +#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x0000032c +#define CONSYS_PWR_CONN_ACK_OFFSET 0x00000180 +#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000184 +/*CONN_MCU_CONFIG_BASE*/ +#define CONSYS_CHIP_ID_OFFSET 0x00000008 +#define CONSYS_ROM_RAM_DELSEL_OFFSET 0x00000114 +#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000110 +#define CONSYS_CPUPCR_OFFSET 0x00000160 +#endif +/*AXI bus*/ +#define CONSYS_TOPAXI_PROT_EN_OFFSET 0x1220 +#define CONSYS_TOPAXI_PROT_STA1_OFFSET 0x1228 + +/*tag start: connsys register base address (hard code, no use) */ +#define AP_RGU_BASE 0xF0007000 +#define TOPCKGEN_BASE 0xF0000000 +#define SPM_BASE 0xF0006000 +#define CONN_MCU_CONFIG_BASE 0xF8070000 +/*GIC Interrupt ID*/ +#define MT_CONN2AP_BTIF_WAKEUP_IRQ_ID 270 +/*tag end*/ + +/*connsys register offset define(hard code mode)*/ +#if 1 + /*top clock gating control register */ +#define CONSYS_TOP_CLKCG_CLR_REG (TOPCKGEN_BASE + 0x00000084) +#define CONSYS_TOP_CLKCG_SET_REG (TOPCKGEN_BASE + 0x00000054) +#define CONSYS_TOP_CLKCG_BIT (0x1 << 26) + + /*SPM clock gating control register */ +#define CONSYS_PWRON_CONFG_EN_REG (SPM_BASE + 0x00000000) +#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) +#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) +#endif + +#define CONSYS_CPU_SW_RST_REG (AP_RGU_BASE + 0x00000018) +#define CONSYS_TOP1_PWR_CTRL_REG (SPM_BASE + 0x0000032c) +#define CONSYS_PWR_CONN_ACK_REG (SPM_BASE + 0x00000180) +#define CONSYS_PWR_CONN_ACK_S_REG (SPM_BASE + 0x00000184) + +#define CONSYS_WD_SYS_RST_REG (TOPCKGEN_BASE + 0x00000018) +#define CONSYS_CHIP_ID_REG (CONN_MCU_CONFIG_BASE + 0x00000008) +#define CONSYS_ROM_RAM_DELSEL_REG (CONN_MCU_CONFIG_BASE + 0x00000114) +#define CONSYS_MCU_CFG_ACR_REG (CONN_MCU_CONFIG_BASE + 0x00000110) + +#if CONSYS_AFE_REG_SETTING +#define CONSYS_AFE_REG_BASE (0x180B2000) +#define CONSYS_AFE_REG_WBG_AFE_01_OFFSET (0x00000010) +#define CONSYS_AFE_REG_WBG_AFE_01_VALUE (0x00000000) +#define CONSYS_AFE_REG_WBG_PLL_03_OFFSET (0x00000038) +#define CONSYS_AFE_REG_WBG_PLL_03_VALUE (0x000C15F0) +#define CONSYS_AFE_REG_WBG_PLL_05_OFFSET (0x00000040) +#define CONSYS_AFE_REG_WBG_PLL_05_VALUE (0x07900020) +#define CONSYS_AFE_REG_WBG_WB_TX_01_OFFSET (0x00000088) +#define CONSYS_AFE_REG_WBG_WB_TX_01_VALUE (0x08440000) +#endif + +#define CONSYS_TOPAXI_PROT_EN (TOPCKGEN_BASE + 0x1220) +#define CONSYS_TOPAXI_PROT_STA1 (TOPCKGEN_BASE + 0x1228) +#define CONSYS_PROT_MASK ((0x1<<13) | (0x1<<14)) /* bit 13, 14 */ +/*CONSYS_CPU_SW_RST_REG*/ +#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) +#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) + +/*CONSYS_TOP1_PWR_CTRL_REG*/ +#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) +#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) +#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) +#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) +#define CONSYS_CLK_CTRL_BIT (0x1 << 4) +#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) + +/*CONSYS_PWR_CONN_ACK_REG*/ +#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_ACK_S_REG*/ +#define CONSYS_PWR_CONN_ACK_S_BIT (0x1 << 1) + +/*CONSYS_WD_SYS_RST_REG*/ +#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) + +/*CONSYS_MCU_CFG_ACR_REG*/ +#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 18) + +/* EMI part mapping & ctrl*/ +#define CONSYS_EMI_COREDUMP_OFFSET (0x80000) +#define CONSYS_EMI_AP_PHY_BASE (0x80080000) +#define CONSYS_EMI_FW_PHY_BASE (0xf0080000) +#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) +#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) +#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) + +/*cpupcr*/ +#define CONSYS_CPUPCR_REG (CONN_MCU_CONFIG_BASE + 0x00000160) +/*emi mapping*/ +#define CONSYS_EMI_MAPPING (TOPCKGEN_BASE + CONSYS_EMI_MAPPING_OFFSET) + +/*control app2cnn_osc_en*/ +#define CONSYS_AP2CONN_OSC_EN_REG (TOPCKGEN_BASE + 0x00001800) +#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 10) +#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 9) + +/*paged dump address start*/ +#define CONSYS_PAGED_DUMP_START_ADDR (0xf0088400) + +/*full dump address start*/ +#define CONSYS_FULL_DUMP_START_ADDR (0xf0090400) +#define CONSYS_FULL_DUMP_DLM_LEN (0x1f000) +#define CONSYS_FULL_DUMP_SYSB2_START (CONSYS_FULL_DUMP_START_ADDR + CONSYS_FULL_DUMP_DLM_LEN) +#define CONSYS_FULL_DUMP_SYSB2_LEN (0x6800) +#define CONSYS_FULL_DUMP_SYSB3_START (CONSYS_FULL_DUMP_SYSB2_START + CONSYS_FULL_DUMP_SYSB2_LEN) +#define CONSYS_FULL_DUMP_SYSB3_LEN (0x16800) + +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) +#define PMIC_DCXO_CW15 (0x0D46) +#define PMIC_DCXO_CW16 (0x0D48) +#define PMIC_DCXO_CW15_VAL (0x18) +#define AP_CONSYS_NOCO_CLOCK_BITA (0x1 << 11) +#define AP_CONSYS_NOCO_CLOCK_BITB (0x1 << 13) +#define AP_CONSYS_CO_CLOCK_BITA (0x1 << 10) +#define AP_CONSYS_CO_CLOCK_BITB (0x1 << 12) +#else +#define PMIC_DCXO_CW15 (0x701E) +#define PMIC_DCXO_CW16 (0x7000) +#define PMIC_DCXO_CW15_VAL (0x7) +#define AP_CONSYS_NOCO_CLOCK_BITA (0x1 << 7) +#define AP_CONSYS_NOCO_CLOCK_BITB (0x1 << 9) +#define AP_CONSYS_CO_CLOCK_BITA (0x1 << 6) +#define AP_CONSYS_CO_CLOCK_BITB (0x1 << 8) +#endif + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#ifdef CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status { + UINT32 counter; + UINT32 flags; + spinlock_t lock; +}; + +extern struct bt_wifi_v33_status gBtWifiV33; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************* +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_MT6763_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6765.h b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6765.h new file mode 100644 index 00000000000000..ed7bf447cb9f27 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6765.h @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_MT6765_H_ +#define _MTK_MT6765_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +#define CONSYS_BT_WIFI_SHARE_V33 0 +#define CONSYS_PMIC_CTRL_ENABLE 1 +#define CONSYS_AHB_CLK_MAGEMENT 1 +#define CONSYS_USE_PLATFORM_WRITE 1 +#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 +#define CONSYS_AFE_REG_SETTING 0 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*tag start:new platform need to make sure these define */ +#define PLATFORM_SOC_CHIP 0x6765 +/*tag end*/ + +/*device tree mode*/ +/* A-Die interface pinmux base */ +#define CONSYS_IF_PINMUX_REG_BASE 0x10005000 +#define CONSYS_IF_PINMUX_01_OFFSET 0x000003F0 +#define CONSYS_IF_PINMUX_01_MASK 0xFFFFFF88 +#define CONSYS_IF_PINMUX_01_VALUE 0x00000011 +#define CONSYS_IF_PINMUX_02_OFFSET 0x000003E0 +#define CONSYS_IF_PINMUX_02_MASK 0x8888888F +#define CONSYS_IF_PINMUX_02_VALUE 0x11111110 +#define CONSYS_IF_DRV_PINMUX_REG_BASE 0x10420000 +#define CONSYS_IF_DRV_PINMUX_MASK 0xF8FFFFFF + +/*TOPCKGEN_BASE*/ +#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00000f00 +#define CONSYS_EMI_MAPPING_OFFSET 0x00000380 +#define CONSYS_EMI_PERI_MAPPING_OFFSET 0x00000388 +/*AP_RGU_BASE*/ +#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 +/*SPM_BASE*/ +#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 +#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x0000032C +#define CONSYS_PWR_CONN_ACK_OFFSET 0x00000180 +#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000184 +#define CONSYS_SPM_APSRC_OFFSET 0x000006f8 +#define CONSYS_SPM_APSRC_VALUE 0x00000005 +#define CONSYS_SPM_DDR_EN_OFFSET 0x000006fc +#define CONSYS_SPM_DDR_EN_VALUE 0x00050505 +/*CONN_MCU_CONFIG_BASE*/ +#define CONSYS_IP_VER_OFFSET 0x00000010 +#define CONSYS_CONF_ID_OFFSET 0x0000001c +#define CONSYS_HW_ID_OFFSET 0x00000000 +#define CONSYS_FW_ID_OFFSET 0x00000004 +#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000140 +#define CONSYS_CPUPCR_OFFSET 0x00000104 +#define CONSYS_SW_IRQ_OFFSET 0x00000150 +#define CONSYS_MCU_ROM_DELSEL_OFFSET 0x00000114 +#define CONSYS_MCU_ROM_DELSEL_VALUE 0x00000017 +#define CONSYS_EMI_CTRL_VALUE (1 << 0 | 1 << 15 | 1 << 21) +/*CONN_HIF_TOP*/ +#define CONSYS_HIF_PDMA_AXI_RREADY 0x00000154 + +/*CONN_HIF_ON_BASE*/ +#define CONSYS_BUSY_OFFSET 0x110 +#define CONSYS_BUSY_BIT (0x1 << 27) +#define CONSYS_CLOCK_CHECK_VALUE 0x30000 +#define CONSYS_HCLK_CHECK_BIT (0x1 << 16) +#define CONSYS_OSCCLK_CHECK_BIT (0x1 << 17) +#define CONSYS_SLEEP_CHECK_BIT (0x1 << 18) + +/*AXI bus*/ +#define CONSYS_AHBAXI_PROT_EN_OFFSET 0x220 +#define CONSYS_AHBAXI_PROT_STA0_OFFSET 0x224 +#define CONSYS_AHBAXI_PROT_STA1_OFFSET 0x228 +#define CONSYS_AXI_TX_PROT_EN_OFFSET 0x250 +#define CONSYS_AXI_TX_PROT_STA_OFFSET 0x258 +#define CONSYS_PROT_MASK ((0x1<<13) | (0x1<<14)) /* bit 13, 14 */ +#define CONSYS_TX_PROT_MASK (0x1<<18) /* bit 18 */ +#define CONSYS_PDMA_AXI_RREADY_MASK (0x1 << 1) /* bit 1 */ + +/* INFRACFG_REG_BASE */ +#define INFRAGCFG_REG_TOPAXI_SI3_STA_OFFSET 0x02C +#define INFRAGCFG_REG_TOPAXI_MI_STA_OFFSET 0x008 + +/*SPM clock gating control register */ +#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) +#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) + +#if CONSYS_AFE_REG_SETTING +#define CONSYS_AFE_REG_BASE (0x180B6000) +#define CONSYS_AFE_RG_WBG_PLL_03_OFFSET (0x00000038) +#define CONSYS_AFE_RG_WBG_PLL_03_VALUE (0x000C1DF0) +#define CONSYS_AFE_RG_WBG_GPS_02_OFFSET (0x00000054) +#define CONSYS_AFE_RG_WBG_GPS_02_VALUE (0x110A2000) +#endif + +#define CONSYS_COCLOCK_STABLE_TIME_BASE (0x180C1200) +#define CONSYS_COCLOCK_ACK_ENABLE_OFFSET (0x4) +#define CONSYS_COCLOCK_ACK_ENABLE_BIT (1 << 0) +#define CONSYS_COCLOCK_STABLE_TIME (0x2223) +#define CONSYS_COCLOCK_STABLE_TIME_MASK (0xffff0000) + +/*CONSYS_CPU_SW_RST_REG*/ +#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) +#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_SW_RST_BIT (0x1 << 9) + +/*CONSYS_TOP1_PWR_CTRL_REG*/ +#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) +#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) +#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) +#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) +#define CONSYS_CLK_CTRL_BIT (0x1 << 4) +#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) + +/*CONSYS_PWR_CONN_ACK_REG*/ +#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_ACK_S_REG*/ +#define CONSYS_PWR_ON_ACK_S_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_TOP2_ACK_REG*/ +#define CONSYS_TOP2_PWR_ON_ACK_BIT (0x1 << 30) + +/*CONSYS_PWR_CONN_TOP2_ACK_S_REG*/ +#define CONSYS_TOP2_PWR_ON_ACK_S_BIT (0x1 << 30) + +/*CONSYS_WD_SYS_RST_REG*/ +#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) + +/*CONSYS_MCU_CFG_ACR_REG*/ +#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 0 | 0x1 << 1) + +/*control app2cnn_osc_en*/ +#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 10) +#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 9) + +/* EMI part mapping & ctrl*/ +#define CONSYS_EMI_COREDUMP_OFFSET (0x68000) +#define CONSYS_EMI_AP_PHY_BASE (0x80068000) +#define CONSYS_EMI_FW_PHY_BASE (0xf0068000) +#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) +#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) +#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) +#define CONSYS_EMI_MET_DATA_OFFSET (0x2e500) + +#define CONSYS_EMI_RAM_BT_BUILDTIME_OFFSET (0x68300) +#define CONSYS_EMI_RAM_WIFI_BUILDTIME_OFFSET (0x68310) +#define CONSYS_EMI_RAM_MCU_BUILDTIME_OFFSET (0x68320) +#define CONSYS_EMI_PATCH_MCU_BUILDTIME_OFFSET (0x68330) + +/*CONSYS_MCU_CFG_DBG_LP_INFO*/ +#define CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR (conn_reg.mcu_cfg_on_base + 0x104) +#define CONN_CFG_ON_CONN_ON_MON_CTL_ADDR (conn_reg.mcu_top_misc_on_base + 0x320) +#define CONN_CFG_ON_CONN_ON_DBGSEL_ADDR (conn_reg.mcu_top_misc_on_base + 0x310) +#define CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_ADDR (conn_reg.mcu_top_misc_on_base + 0x340) +#define CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_MAPPING_AP_ADDR (0x180c1340) + +/* default coex wmt ant_sel cr address */ +#define DEFAULT_COEX_WMT_ANTSEL_0_POLARITY_CR 0x80025310 +#define DEFAULT_COEX_WMT_ANTSEL_1_POLARITY_CR 0x80025310 +#define DEFAULT_COEX_WMT_ANTSEL_2_POLARITY_CR 0x80025314 +#define DEFAULT_COEX_WMT_ANTSEL_3_POLARITY_CR 0x80025314 +#define DEFAULT_COEX_WMT_ANTSEL_4_POLARITY_CR 0x80025318 +#define DEFAULT_COEX_WMT_ANTSEL_5_POLARITY_CR 0x80025318 +#define DEFAULT_COEX_WMT_ANTSEL_6_POLARITY_CR 0x8002531C +#define DEFAULT_COEX_WMT_ANTSEL_7_POLARITY_CR 0x8002531C + +/* default coex wmt ant_sel cr bit */ +#define DEFAULT_COEX_WMT_ANTSEL_0_POLARITY_BIT 8 +#define DEFAULT_COEX_WMT_ANTSEL_1_POLARITY_BIT 24 +#define DEFAULT_COEX_WMT_ANTSEL_2_POLARITY_BIT 8 +#define DEFAULT_COEX_WMT_ANTSEL_3_POLARITY_BIT 24 +#define DEFAULT_COEX_WMT_ANTSEL_4_POLARITY_BIT 8 +#define DEFAULT_COEX_WMT_ANTSEL_5_POLARITY_BIT 24 +#define DEFAULT_COEX_WMT_ANTSEL_6_POLARITY_BIT 8 +#define DEFAULT_COEX_WMT_ANTSEL_7_POLARITY_BIT 24 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#ifdef CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status { + UINT32 counter; + UINT32 flags; + spinlock_t lock; +}; + +extern struct bt_wifi_v33_status gBtWifiV33; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************* +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_MT6765_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6768.h b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6768.h new file mode 100644 index 00000000000000..a467f0547e3e6b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6768.h @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_MT6768_H_ +#define _MTK_MT6768_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +#define CONSYS_BT_WIFI_SHARE_V33 0 +#define CONSYS_PMIC_CTRL_ENABLE 1 +#define CONSYS_AHB_CLK_MAGEMENT 1 +#define CONSYS_USE_PLATFORM_WRITE 1 +#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 +#define CONSYS_AFE_REG_SETTING 1 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*tag start:new platform need to make sure these define */ +#define PLATFORM_SOC_CHIP 0x6768 +/*tag end*/ + +/*device tree mode*/ +/* A-Die interface pinmux base */ +#define CONSYS_IF_PINMUX_REG_BASE 0x10005000 +#define CONSYS_IF_PINMUX_01_OFFSET 0x000003F0 +#define CONSYS_IF_PINMUX_01_MASK 0xFFFFFF88 +#define CONSYS_IF_PINMUX_01_VALUE 0x00000011 +#define CONSYS_IF_PINMUX_02_OFFSET 0x000003E0 +#define CONSYS_IF_PINMUX_02_MASK 0x8888888F +#define CONSYS_IF_PINMUX_02_VALUE 0x11111110 +#define CONSYS_IF_DRV_PINMUX_REG_BASE 0x10420000 +#define CONSYS_IF_DRV_PINMUX_MASK 0xF8FFFFFF + +/*TOPCKGEN_BASE*/ +#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00000f00 +#define CONSYS_EMI_MAPPING_OFFSET 0x00000380 +#define CONSYS_EMI_PERI_MAPPING_OFFSET 0x00000388 +/*AP_RGU_BASE*/ +#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 +/*SPM_BASE*/ +#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 +#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x0000032C +#define CONSYS_PWR_CONN_ACK_OFFSET 0x00000180 +#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000184 +#define CONSYS_SPM_APSRC_OFFSET 0x000006f8 +#define CONSYS_SPM_APSRC_VALUE 0x00000005 +#define CONSYS_SPM_DDR_EN_OFFSET 0x000006fc +#define CONSYS_SPM_DDR_EN_VALUE 0x00050505 +/*CONN_MCU_CONFIG_BASE*/ +#define CONSYS_IP_VER_OFFSET 0x00000010 +#define CONSYS_CONF_ID_OFFSET 0x0000001c +#define CONSYS_HW_ID_OFFSET 0x00000000 +#define CONSYS_FW_ID_OFFSET 0x00000004 +#define CONSYS_IP_VER_ID 0x10020501 +#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000140 +#define CONSYS_CPUPCR_OFFSET 0x00000104 +#define EMI_CONTROL_DBG_PROBE 0x00000144 +#define CONSYS_SW_IRQ_OFFSET 0x00000150 +#define CONSYS_MCU_ROM_DELSEL_OFFSET 0x00000114 +#define CONSYS_MCU_ROM_DELSEL_VALUE 0x00000017 +#define CONSYS_EMI_CTRL_VALUE (1 << 21) +/*CONN_HIF_TOP*/ +#define CONSYS_HIF_PDMA_AXI_RREADY 0x00000154 + +#define CONSYS_HIF_TOP_MISC 0x00000104 +#define CONSYS_HIF_DBG_IDX 0x0000012C +#define CONSYS_HIF_DBG_PROBE 0x00000130 +#define CONSYS_HIF_BUSY_STATUS 0x00000138 +#define CONSYS_HIF_PDMA_AXI_RREADY 0x00000154 +#define CONSYS_HIF_PDMA_BUSY_STATUS 0x00000168 + +/*CONN_HIF_ON_BASE*/ +#define CONSYS_CLOCK_CONTROL 0x00000100 +#define CONSYS_BUS_CONTROL 0x00000110 +#define CONSYS_DEBUG_SELECT 0x00000400 +#define CONSYS_DEBUG_STATUS 0x0000040c + +#define CONSYS_BUSY_OFFSET 0x110 +#define CONSYS_BUSY_BIT (0x1 << 27) +#define CONSYS_CLOCK_CHECK_VALUE 0x30000 +#define CONSYS_HCLK_CHECK_BIT (0x1 << 16) +#define CONSYS_OSCCLK_CHECK_BIT (0x1 << 17) +#define CONSYS_SLEEP_CHECK_BIT (0x1 << 18) + +/*AXI bus*/ +#define CONSYS_AHBAXI_PROT_EN_OFFSET 0x220 +#define CONSYS_AHBAXI_PROT_STA_OFFSET 0x228 +#define CONSYS_AXI_TX_PROT_EN_OFFSET 0x250 +#define CONSYS_AXI_TX_PROT_STA_OFFSET 0x258 +#define CONSYS_PROT_MASK ((0x1<<13) | (0x1<<14)) /* bit 13, 14 */ +#define CONSYS_TX_PROT_MASK (0x1<<18) /* bit 18 */ +#define CONSYS_PDMA_AXI_RREADY_MASK (0x1 << 1) /* bit 1 */ + +/* toppose_restore_done rollback CR */ +#define CONSYS_TOPPOSE_RESTORE_OFFSET 0x600 +#define CONSYS_TOPPOSE_RESTORE_MASK 0xFF7FFFFF /* bit 23 */ +#define CONSYS_TOPPOSE_RESTORE_VALUE (0x1 << 23) + +/*SPM clock gating control register */ +#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) +#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) + +#if CONSYS_AFE_REG_SETTING +#define CONSYS_AFE_REG_BASE (0x180B3000) +#define CONSYS_AFE_RG_WBG_PLL_03_OFFSET (0x00000034) +#define CONSYS_AFE_RG_WBG_PLL_03_VALUE (0x000C1DF0) +#define CONSYS_AFE_RG_WBG_GPS_02_OFFSET (0x00000054) +#define CONSYS_AFE_RG_WBG_GPS_02_VALUE (0x110A2000) +#endif + +#define CONSYS_COCLOCK_STABLE_TIME_BASE (0x180C1200) +#define CONSYS_COCLOCK_ACK_ENABLE_OFFSET (0x4) +#define CONSYS_COCLOCK_ACK_ENABLE_BIT (1 << 0) +#define CONSYS_COCLOCK_STABLE_TIME (0x708) +#define CONSYS_COCLOCK_STABLE_TIME_MASK (0xffff0000) + +/*CONSYS_CPU_SW_RST_REG*/ +#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) +#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_SW_RST_BIT (0x1 << 9) + +/*CONSYS_TOP1_PWR_CTRL_REG*/ +#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) +#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) +#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) +#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) +#define CONSYS_CLK_CTRL_BIT (0x1 << 4) +#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) + +/*CONSYS_PWR_CONN_ACK_REG*/ +#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_ACK_S_REG*/ +#define CONSYS_PWR_ON_ACK_S_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_TOP2_ACK_REG*/ +#define CONSYS_TOP2_PWR_ON_ACK_BIT (0x1 << 30) + +/*CONSYS_PWR_CONN_TOP2_ACK_S_REG*/ +#define CONSYS_TOP2_PWR_ON_ACK_S_BIT (0x1 << 30) + +/*CONSYS_WD_SYS_RST_REG*/ +#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) + +/*CONSYS_MCU_CFG_ACR_REG*/ +#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 0 | 0x1 << 1) + +/*control app2cnn_osc_en*/ +#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 10) +#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 9) + +/* EMI part mapping & ctrl*/ +#define CONSYS_EMI_COREDUMP_OFFSET (0x68000) +#define CONSYS_EMI_AP_PHY_BASE (0x80068000) +#define CONSYS_EMI_FW_PHY_BASE (0xf0068000) +#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) +#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) +#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) +#define CONSYS_EMI_MET_DATA_OFFSET (0x2e500) + +#define CONSYS_EMI_RAM_BT_BUILDTIME_OFFSET (0x68300) +#define CONSYS_EMI_RAM_WIFI_BUILDTIME_OFFSET (0x68310) +#define CONSYS_EMI_RAM_MCU_BUILDTIME_OFFSET (0x68320) +#define CONSYS_EMI_PATCH_MCU_BUILDTIME_OFFSET (0x68330) + +/*CONSYS_MCU_CFG_DBG_LP_INFO*/ +#define CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR (conn_reg.mcu_cfg_on_base + 0x104) +#define CONN_CFG_ON_CONN_ON_MON_CTL_ADDR (conn_reg.mcu_top_misc_on_base + 0x320) +#define CONN_CFG_ON_CONN_ON_DBGSEL_ADDR (conn_reg.mcu_top_misc_on_base + 0x310) +#define CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_ADDR (conn_reg.mcu_top_misc_on_base + 0x340) +#define CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_MAPPING_AP_ADDR (0x180c1340) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#ifdef CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status { + UINT32 counter; + UINT32 flags; + spinlock_t lock; +}; + +extern struct bt_wifi_v33_status gBtWifiV33; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************* +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_MT6768_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6771.h b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6771.h new file mode 100644 index 00000000000000..74aab509f6fb65 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6771.h @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_MT6771_H_ +#define _MTK_MT6771_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +#define CONSYS_BT_WIFI_SHARE_V33 0 +#define CONSYS_PMIC_CTRL_ENABLE 1 +#define CONSYS_AHB_CLK_MAGEMENT 1 +#define CONSYS_USE_PLATFORM_WRITE 1 +#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 +#define CONSYS_AFE_REG_SETTING 1 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*tag start:new platform need to make sure these define */ +#define PLATFORM_SOC_CHIP 0x6771 +/*tag end*/ + +/*device tree mode*/ +/* A-Die interface pinmux base */ +#define CONSYS_IF_PINMUX_REG_BASE 0x10005000 +#define CONSYS_IF_PINMUX_01_OFFSET 0x000003F0 +#define CONSYS_IF_PINMUX_01_MASK 0xFFFFFF00 +#define CONSYS_IF_PINMUX_01_VALUE 0x00000011 +#define CONSYS_IF_PINMUX_02_OFFSET 0x000003E0 +#define CONSYS_IF_PINMUX_02_MASK 0x0000000F +#define CONSYS_IF_PINMUX_02_VALUE 0x11111110 +#define CONSYS_IF_DRV_PINMUX_REG_BASE 0x10420000 +#define CONSYS_IF_DRV_PINMUX_MASK 0xF8FFFFFF + +/*TOPCKGEN_BASE*/ +#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00000f00 +#define CONSYS_EMI_MAPPING_OFFSET 0x00000380 +/*AP_RGU_BASE*/ +#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 +/*SPM_BASE*/ +#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 +#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x0000032C +#define CONSYS_PWR_CONN_ACK_OFFSET 0x00000180 +#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000184 +/*CONN_MCU_CONFIG_BASE*/ +#define CONSYS_CHIP_ID_OFFSET 0x00000008 +#define CONSYS_ROM_DESEL_OFFSET 0x00000600 +#define CONSYS_HANG_DBG_OFFSET_1 0x00000400 +#define CONSYS_HANG_DBG_OFFSET_2 0x00000404 +#define CONSYS_HANG_DBG_OFFSET_3 0x0000040C +#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000140 +#define CONSYS_CPUPCR_OFFSET 0x00000160 + +/*AXI bus*/ +#define CONSYS_TOPAXI_PROT_EN_OFFSET 0x2a4 +#define CONSYS_TOPAXI_PROT_STA1_OFFSET 0x228 + +/*SPM clock gating control register */ +#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) +#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) + +#if CONSYS_AFE_REG_SETTING +#define CONSYS_AFE_REG_BASE (0x180B6000) +#define CONSYS_AFE_RG_WBG_PLL_03_OFFSET (0x00000038) +#define CONSYS_AFE_RG_WBG_PLL_03_VALUE (0x000C1DF0) +#define CONSYS_AFE_RG_WBG_GPS_02_OFFSET (0x00000054) +#define CONSYS_AFE_RG_WBG_GPS_02_VALUE (0x110A2000) +#endif + +#define CONSYS_PROT_MASK ((0x1<<13) | (0x1<<14)) /* bit 13, 14 */ +/*CONSYS_CPU_SW_RST_REG*/ +#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) +#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) + +/*CONSYS_TOP1_PWR_CTRL_REG*/ +#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) +#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) +#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) +#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) +#define CONSYS_CLK_CTRL_BIT (0x1 << 4) +#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) + +/*CONSYS_PWR_CONN_ACK_REG*/ +#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_ACK_S_REG*/ +#define CONSYS_PWR_ON_ACK_S_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_TOP2_ACK_REG*/ +#define CONSYS_TOP2_PWR_ON_ACK_BIT (0x1 << 30) + +/*CONSYS_PWR_CONN_TOP2_ACK_S_REG*/ +#define CONSYS_TOP2_PWR_ON_ACK_S_BIT (0x1 << 30) + +/*CONSYS_WD_SYS_RST_REG*/ +#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) + +/*CONSYS_MCU_CFG_ACR_REG*/ +#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 0 | 0x1 << 1) + +/*control app2cnn_osc_en*/ +#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 10) +#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 9) +#define CONSYS_ROM_DESEL_MASK ((0x17 << 16) | 0x2a4) + +/* EMI part mapping & ctrl*/ +#define CONSYS_EMI_COREDUMP_OFFSET (0x80000) +#define CONSYS_EMI_AP_PHY_BASE (0x80080000) +#define CONSYS_EMI_FW_PHY_BASE (0xf0080000) +#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) +#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) +#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#ifdef CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status { + UINT32 counter; + UINT32 flags; + spinlock_t lock; +}; + +extern struct bt_wifi_v33_status gBtWifiV33; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************* +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_MT6771_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6779.h b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6779.h new file mode 100644 index 00000000000000..f12563a43906f7 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6779.h @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_MT6779_H_ +#define _MTK_MT6779_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +#define CONSYS_BT_WIFI_SHARE_V33 0 +#define CONSYS_PMIC_CTRL_ENABLE 1 +#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 +#define CONSYS_AFE_REG_SETTING 0 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*tag start:new platform need to make sure these define */ +#define PLATFORM_SOC_CHIP 0x6779 +/*tag end*/ + +/*device tree mode*/ +/* A-Die interface pinmux base */ +#define CONSYS_IF_PINMUX_REG_BASE 0x10005000 +#define CONSYS_IF_PINMUX_01_OFFSET 0x00000430 +#define CONSYS_IF_PINMUX_01_MASK 0x0000FFFF +#define CONSYS_IF_PINMUX_01_VALUE 0x11110000 +#define CONSYS_IF_PINMUX_02_OFFSET 0x00000440 +#define CONSYS_IF_PINMUX_02_MASK 0xF0000000 +#define CONSYS_IF_PINMUX_02_VALUE 0x01111111 + +/* A-Die interface pinmux driving base */ +#define CONSYS_IF_PINMUX_DRIVING_BASE 0x11EA0000 +#define CONSYS_IF_PINMUX_DRIVING_OFFSET 0x0 +#define CONSYS_IF_PINMUX_DRIVING_MASK 0xC00001FF +#define CONSYS_IF_PINMUX_DRIVING_VALUE 0x0 + +/* CONN_WF_CTRL2 */ +#define CONSYS_WF_CTRL2_01_OFFSET 0x00000050 +#define CONSYS_WF_CTRL2_01_MASK 0xFFFFFFEF +#define CONSYS_WF_CTRL2_01_VALUE 0x00000010 +#define CONSYS_WF_CTRL2_02_OFFSET 0x00000150 +#define CONSYS_WF_CTRL2_02_MASK 0xFFFFFFEF +#define CONSYS_WF_CTRL2_02_VALUE 0x00000010 +#define CONSYS_WF_CTRL2_03_OFFSET 0x00000440 +#define CONSYS_WF_CTRL2_03_MASK 0xFFF8FFFF +#define CONSYS_WF_CTRL2_GPIO_MODE 0x00000000 +#define CONSYS_WF_CTRL2_CONN_MODE 0x00010000 + +/*TOPCKGEN_BASE*/ +#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00000f00 +#define CONSYS_EMI_MAPPING_OFFSET 0x00000380 +#define CONSYS_EMI_PERI_MAPPING_OFFSET 0x00000388 +#define CONSYS_EMI_AP_MD_OFFSET 0x0000039C +/*AP_RGU_BASE*/ +#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 +/*SPM_BASE*/ +#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 +#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x00000320 +#define CONSYS_PWR_CONN_ACK_OFFSET 0x00000160 +#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000164 +#define CONSYS_SPM_APSRC_OFFSET 0x000006f8 +#define CONSYS_SPM_APSRC_VALUE 0x00000005 +#define CONSYS_SPM_DDR_EN_OFFSET 0x000006fc +#define CONSYS_SPM_DDR_EN_VALUE 0x00050505 +/*CONN_MCU_CONFIG_BASE*/ +#define CONSYS_IP_VER_OFFSET 0x00000010 +#define CONSYS_CONF_ID_OFFSET 0x0000001c +#define CONSYS_HW_ID_OFFSET 0x00000000 +#define CONSYS_FW_ID_OFFSET 0x00000004 +#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000140 +#define CONSYS_CPUPCR_OFFSET 0x00000104 +#define EMI_CONTROL_DBG_PROBE 0x00000144 +#define CONSYS_SW_IRQ_OFFSET 0x00000148 +#define CONN_MCU_EMI_CONTROL 0x00000150 + +#define CONSYS_IP_VER_ID 0x10050000 + +#define CONSYS_HIF_TOP_MISC 0x00002104 +#define CONSYS_HIF_DBG_IDX 0x0000212C +#define CONSYS_HIF_DBG_PROBE 0x00002130 +#define CONSYS_HIF_BUSY_STATUS 0x00002138 +#define CONSYS_HIF_PDMA_BUSY_STATUS 0x00002168 +#define CONSYS_CLOCK_CONTROL 0x00000100 +#define CONSYS_BUS_CONTROL 0x00000110 +#define CONSYS_DEBUG_SELECT 0x00000400 +#define CONSYS_DEBUG_STATUS 0x0000040c +#define CONSYS_EMI_CTRL_VALUE (1 << 21) + +/*CONN_HIF_ON_BASE*/ +#define CONSYS_CLOCK_CHECK_VALUE 0x30000 +#define CONSYS_HCLK_CHECK_BIT (0x1 << 16) +#define CONSYS_OSCCLK_CHECK_BIT (0x1 << 17) +#define CONSYS_SLEEP_CHECK_BIT (0x1 << 18) + +/*AXI bus*/ +#define CONSYS_AHB_RX_PROT_EN_OFFSET 0x2AC +#define CONSYS_AHB_RX_PROT_STA_OFFSET 0x258 +#define CONSYS_AXI_RX_PROT_EN_OFFSET 0x2A4 +#define CONSYS_AXI_RX_PROT_STA_OFFSET 0x228 +#define CONSYS_AHB_RX_PROT_MASK (0x1<<10) /* bit 10 */ +#define CONSYS_AXI_RX_PROT_MASK (0x1<<14) /* bit 14 */ +#define CONSYS_AXI_TX_PROT_MASK (0x1<<18) /* bit 18 */ +#define CONSYS_AHB_TX_PROT_MASK (0x1<<13) /* bit 13 */ +#define CONSYS_AHB_TIMEOUT_EN_ADDRESS 0x18002440 +#define CONSYS_AHB_TIMEOUT_EN_VALUE 0x80000101 + +/*WPLL SETTING*/ +#define CONSYS_WPLL_SETTING_ADDRESS 0x180b3034 +#define CONSYS_WPLL_SETTING_MASK 0xFFE7FFFF /* bit 19, bit 20 */ +#define CONSYS_WPLL_SETTING_VALUE 0x00080000 /* bit 19, bit 20 */ + +/* toppose_restore_done rollback CR */ +#define CONSYS_TOPPOSE_RESTORE_ADDRESS 0x180c1130 +#define CONSYS_TOPPOSE_RESTORE_MASK 0xFBFFFFFF /* bit 26 */ +#define CONSYS_TOPPOSE_RESTORE_VALUE (0x1 << 26) + +/*SPM clock gating control register */ +#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) +#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) + +#if CONSYS_AFE_REG_SETTING +#define CONSYS_AFE_REG_BASE (0x180B6000) +#define CONSYS_AFE_RG_WBG_PLL_03_OFFSET (0x00000038) +#define CONSYS_AFE_RG_WBG_PLL_03_VALUE (0x000C1DF0) +#define CONSYS_AFE_RG_WBG_GPS_02_OFFSET (0x00000054) +#define CONSYS_AFE_RG_WBG_GPS_02_VALUE (0x110A2000) +#endif + +#define CONSYS_COCLOCK_STABLE_TIME_BASE (0x180C1200) +#define CONSYS_COCLOCK_ACK_ENABLE_OFFSET (0x4) +#define CONSYS_COCLOCK_ACK_ENABLE_BIT (1 << 0) +#define CONSYS_COCLOCK_ACK_ENABLE_MAST (0xffff00ff) +#define CONSYS_COCLOCK_ACK_ENABLE_VALUE (0x600) +#define CONSYS_COCLOCK_STABLE_TIME (0x708) +#define CONSYS_COCLOCK_STABLE_TIME_MASK (0xffff0000) + +#define CONSYS_IDENTIFY_ADIE_CR_ADDRESS (0x180C1130) +#define CONSYS_IDENTIFY_ADIE_ENABLE_BIT (1 << 8) + +/*CONSYS_CPU_SW_RST_REG*/ +#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) +#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_SW_RST_BIT (0x1 << 9) + +/*CONSYS_TOP1_PWR_CTRL_REG*/ +#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) +#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) +#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) +#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) +#define CONSYS_CLK_CTRL_BIT (0x1 << 4) +#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) + +/*CONSYS_PWR_CONN_ACK_REG*/ +#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_ACK_S_REG*/ +#define CONSYS_PWR_ON_ACK_S_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_TOP2_ACK_REG*/ +#define CONSYS_TOP2_PWR_ON_ACK_BIT (0x1 << 30) + +/*CONSYS_PWR_CONN_TOP2_ACK_S_REG*/ +#define CONSYS_TOP2_PWR_ON_ACK_S_BIT (0x1 << 30) + +/*CONSYS_WD_SYS_RST_REG*/ +#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) + +/*CONSYS_MCU_CFG_ACR_REG*/ +#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 0 | 0x1 << 1) + +/*control app2cnn_osc_en*/ +#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 10) +#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 9) + +/* EMI part mapping & ctrl*/ +#define CONSYS_EMI_COREDUMP_OFFSET (0x68000) +#define CONSYS_EMI_AP_PHY_OFFSET (0x00000) +#define CONSYS_EMI_AP_PHY_BASE (0x80068000) +#define CONSYS_EMI_FW_PHY_BASE (0xf0068000) +#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) +#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) +#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) +#define CONSYS_EMI_MET_DATA_OFFSET (0x0) + +#define CONSYS_EMI_RAM_BT_BUILDTIME_OFFSET (0x68300) +#define CONSYS_EMI_RAM_WIFI_BUILDTIME_OFFSET (0x68310) +#define CONSYS_EMI_RAM_MCU_BUILDTIME_OFFSET (0x68320) +#define CONSYS_EMI_PATCH_MCU_BUILDTIME_OFFSET (0x68330) + +/* AP_PCCIF4_BASE Register */ +#define INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG (0x438) +#define INFRASYS_COMMON_AP2MD_PCCIF4_AP_PCCIF_ACK_OFFSET (0x14) +#define INFRASYS_COMMON_AP2MD_CON_PWR_ON_CON_SW_READY_MASK (0x3 << 0) + +/* MCU Sleep handshake */ +#define MCU_GOTO_SLEEP 0x5aa5 +#define MCU_SLEEP_DONE 0x7788 + +/*CONSYS_MCU_CFG_DBG_LP_INFO*/ +#define CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR (conn_reg.mcu_cfg_on_base + 0x104) +#define CONN_CFG_ON_CONN_ON_MON_CTL_ADDR (conn_reg.mcu_top_misc_on_base + 0x320) +#define CONN_CFG_ON_CONN_ON_MON_SEL0_ADDR (conn_reg.mcu_top_misc_on_base + 0x328) +#define CONN_CFG_ON_CONN_ON_MON_SEL1_ADDR (conn_reg.mcu_top_misc_on_base + 0x32C) +#define CONN_CFG_ON_CONN_ON_MON_SEL2_ADDR (conn_reg.mcu_top_misc_on_base + 0x330) +#define CONN_CFG_ON_CONN_ON_MON_SEL3_ADDR (conn_reg.mcu_top_misc_on_base + 0x334) +#define CONN_CFG_ON_CONN_ON_DBGSEL_ADDR (conn_reg.mcu_top_misc_on_base + 0x310) +#define CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_ADDR (conn_reg.mcu_top_misc_on_base + 0x340) +#define CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_MAPPING_AP_ADDR (0x180c1340) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#ifdef CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status { + UINT32 counter; + UINT32 flags; + spinlock_t lock; +}; + +extern struct bt_wifi_v33_status gBtWifiV33; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************* +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_MT6779_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6785.h b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6785.h new file mode 100644 index 00000000000000..ce2e035d4c5ff2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mt6785.h @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_MT6785_H_ +#define _MTK_MT6785_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +#define CONSYS_BT_WIFI_SHARE_V33 0 +#define CONSYS_PMIC_CTRL_ENABLE 1 +#define CONSYS_AHB_CLK_MAGEMENT 1 +#define CONSYS_USE_PLATFORM_WRITE 1 +#define CONSYS_PWR_ON_OFF_API_AVAILABLE 1 +#define CONSYS_AFE_REG_SETTING 1 + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/*tag start:new platform need to make sure these define */ +#define PLATFORM_SOC_CHIP 0x6785 +/*tag end*/ + +/*device tree mode*/ +/* A-Die interface pinmux base */ +#define CONSYS_IF_PINMUX_REG_BASE 0x10005000 +#define CONSYS_IF_PINMUX_01_OFFSET 0x00000430 +#define CONSYS_IF_PINMUX_01_MASK 0x0000ffff +#define CONSYS_IF_PINMUX_01_VALUE 0x11110000 +#define CONSYS_IF_PINMUX_02_OFFSET 0x00000440 +#define CONSYS_IF_PINMUX_02_MASK 0xfff00000 +#define CONSYS_IF_PINMUX_02_VALUE 0x11111 + +/* A-Die interface pinmux driving base */ +#define CONSYS_IF_PINMUX_DRIVING_BASE 0x11EA0000 +#define CONSYS_IF_PINMUX_DRIVING_OFFSET 0x0 +#define CONSYS_IF_PINMUX_DRIVING_MASK 0xff000007 +#define CONSYS_IF_PINMUX_DRIVING_VALUE 0x0 + +/*TOPCKGEN_BASE*/ +#define CONSYS_AP2CONN_OSC_EN_OFFSET 0x00000f00 +#define CONSYS_EMI_MAPPING_OFFSET 0x00000380 +#define CONSYS_EMI_PERI_MAPPING_OFFSET 0x00000388 +#define CONSYS_EMI_AP_MD_OFFSET 0x0000039C +/*AP_RGU_BASE*/ +#define CONSYS_CPU_SW_RST_OFFSET 0x00000018 +/*SPM_BASE*/ +#define CONSYS_PWRON_CONFG_EN_OFFSET 0x00000000 +#define CONSYS_TOP1_PWR_CTRL_OFFSET 0x00000320 +#define CONSYS_PWR_CONN_ACK_OFFSET 0x00000160 +#define CONSYS_PWR_CONN_ACK_S_OFFSET 0x00000164 +#define CONSYS_SPM_APSRC_OFFSET 0x000006f8 +#define CONSYS_SPM_APSRC_VALUE 0x00000005 +#define CONSYS_SPM_DDR_EN_OFFSET 0x000006fc +#define CONSYS_SPM_DDR_EN_VALUE 0x00050505 +/*CONN_MCU_CONFIG_BASE*/ +#define CONSYS_IP_VER_OFFSET 0x00000010 +#define CONSYS_CONF_ID_OFFSET 0x0000001c +#define CONSYS_HW_ID_OFFSET 0x00000000 +#define CONSYS_FW_ID_OFFSET 0x00000004 +#define CONSYS_IP_VER_ID 0x10020600 +#define CONSYS_MCU_CFG_ACR_OFFSET 0x00000140 +#define CONSYS_CPUPCR_OFFSET 0x00000104 +#define EMI_CONTROL_DBG_PROBE 0x00000144 +#define CONN_MCU_EMI_CONTROL 0x00000150 +#define CONSYS_MCU_ROM_DELSEL_OFFSET 0x00000114 +#define CONSYS_MCU_ROM_DELSEL_VALUE 0x00000017 +#define CONSYS_EMI_CTRL_VALUE (1 << 21) +/*CONN_HIF_TOP*/ +#define CONSYS_HIF_PDMA_AXI_RREADY 0x00000154 + +#define CONSYS_HIF_TOP_MISC 0x00000104 +#define CONSYS_HIF_DBG_IDX 0x0000012C +#define CONSYS_HIF_DBG_PROBE 0x00000130 +#define CONSYS_HIF_BUSY_STATUS 0x00000138 +#define CONSYS_HIF_PDMA_AXI_RREADY 0x00000154 +#define CONSYS_HIF_PDMA_BUSY_STATUS 0x00000168 + +/*CONN_HIF_ON_BASE*/ +#define CONSYS_CLOCK_CONTROL 0x00000100 +#define CONSYS_BUS_CONTROL 0x00000110 +#define CONSYS_DEBUG_SELECT 0x00000400 +#define CONSYS_DEBUG_STATUS 0x0000040c + +#define CONSYS_BUSY_OFFSET 0x110 +#define CONSYS_BUSY_BIT (0x1 << 27) +#define CONSYS_CLOCK_CHECK_VALUE 0x30000 +#define CONSYS_HCLK_CHECK_BIT (0x1 << 16) +#define CONSYS_OSCCLK_CHECK_BIT (0x1 << 17) +#define CONSYS_SLEEP_CHECK_BIT (0x1 << 18) + +/*AXI bus*/ +#define CONSYS_AHB_RX_PROT_EN_OFFSET 0x2AC +#define CONSYS_AHB_RX_PROT_STA_OFFSET 0x258 +#define CONSYS_AXI_RX_PROT_EN_OFFSET 0x2A4 +#define CONSYS_AXI_RX_PROT_STA_OFFSET 0x228 +#define CONSYS_AHB_RX_PROT_MASK (0x1<<10) /* bit 10 */ +#define CONSYS_AXI_RX_PROT_MASK (0x1<<14) /* bit 14 */ +#define CONSYS_AXI_TX_PROT_MASK (0x1<<18) /* bit 18 */ +#define CONSYS_AHB_TX_PROT_MASK (0x1<<13) /* bit 13 */ +#define CONSYS_AHB_TIMEOUT_EN_ADDRESS 0x18002440 +#define CONSYS_AHB_TIMEOUT_EN_VALUE 0x80000101 +#define CONSYS_PDMA_AXI_RREADY_MASK (0x1 << 1) /* bit 1 */ + +/* CONN2EMI HW slpprot control enable */ +#define CONSYS_SLPPROT_CONTROL_OFFSET 0x160 +#define CONSYS_SLPPROT_CONTROL_MASK 0xFFFFFFEF /* bit 4 */ +#define CONSYS_SLPPROT_CONTROL_VALUE (0x1 << 4) + +/* toppose_restore_done rollback CR */ +#define CONSYS_TOPPOSE_RESTORE_ADDRESS 0x180c1600 +#define CONSYS_TOPPOSE_RESTORE_MASK 0xFF7FFFFF /* bit 23 */ +#define CONSYS_TOPPOSE_RESTORE_VALUE (0x1 << 23) + +/* WPLL SETTING */ +#define CONSYS_WPLL_SETTING_ADDRESS 0x180b3034 +#define CONSYS_WPLL_SETTING_MASK 0xFFE7FFFF /* bit 19, bit 20 */ +#define CONSYS_WPLL_SETTING_VALUE 0x00080000 /* bit 19, bit 20 */ + +/*SPM clock gating control register */ +#define CONSYS_PWRON_CONFG_EN_VALUE (0x0b160001) +#define CONSYS_PWRON_CONFG_DIS_VALUE (0x0b160000) + +#if CONSYS_AFE_REG_SETTING +#define CONSYS_AFE_REG_BASE (0x180B3000) +#define CONSYS_AFE_RG_WBG_PLL_03_OFFSET (0x00000034) +#endif + +#define CONSYS_COCLOCK_STABLE_TIME_BASE (0x180C1200) +#define CONSYS_COCLOCK_ACK_ENABLE_OFFSET (0x4) +#define CONSYS_COCLOCK_ACK_ENABLE_BIT (1 << 0) +#define CONSYS_COCLOCK_STABLE_TIME (0x708) +#define CONSYS_COCLOCK_STABLE_TIME_MASK (0xffff0000) + +/*CONSYS_CPU_SW_RST_REG*/ +#define CONSYS_CPU_SW_RST_BIT (0x1 << 12) +#define CONSYS_CPU_SW_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_SW_RST_BIT (0x1 << 9) + +/*CONSYS_TOP1_PWR_CTRL_REG*/ +#define CONSYS_SPM_PWR_RST_BIT (0x1 << 0) +#define CONSYS_SPM_PWR_ISO_S_BIT (0x1 << 1) +#define CONSYS_SPM_PWR_ON_BIT (0x1 << 2) +#define CONSYS_SPM_PWR_ON_S_BIT (0x1 << 3) +#define CONSYS_CLK_CTRL_BIT (0x1 << 4) +#define CONSYS_SRAM_CONN_PD_BIT (0x1 << 8) + +/*CONSYS_PWR_CONN_ACK_REG*/ +#define CONSYS_PWR_ON_ACK_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_ACK_S_REG*/ +#define CONSYS_PWR_ON_ACK_S_BIT (0x1 << 1) + +/*CONSYS_PWR_CONN_TOP2_ACK_REG*/ +#define CONSYS_TOP2_PWR_ON_ACK_BIT (0x1 << 30) + +/*CONSYS_PWR_CONN_TOP2_ACK_S_REG*/ +#define CONSYS_TOP2_PWR_ON_ACK_S_BIT (0x1 << 30) + +/*CONSYS_WD_SYS_RST_REG*/ +#define CONSYS_WD_SYS_RST_CTRL_KEY (0x88 << 24) +#define CONSYS_WD_SYS_RST_BIT (0x1 << 9) + +/*CONSYS_MCU_CFG_ACR_REG*/ +#define CONSYS_MCU_CFG_ACR_MBIST_BIT (0x1 << 0 | 0x1 << 1) + +/*control app2cnn_osc_en*/ +#define CONSYS_AP2CONN_OSC_EN_BIT (0x1 << 10) +#define CONSYS_AP2CONN_WAKEUP_BIT (0x1 << 9) + +/* EMI part mapping & ctrl*/ +#define CONSYS_EMI_COREDUMP_OFFSET (0x68000) +#define CONSYS_EMI_AP_PHY_BASE (0x80068000) +#define CONSYS_EMI_FW_PHY_BASE (0xf0068000) +#define CONSYS_EMI_PAGED_TRACE_OFFSET (0x400) +#define CONSYS_EMI_PAGED_DUMP_OFFSET (0x8400) +#define CONSYS_EMI_FULL_DUMP_OFFSET (0x10400) +#define CONSYS_EMI_MET_DATA_OFFSET (0x2e500) + +#define CONSYS_EMI_RAM_BT_BUILDTIME_OFFSET (0x68300) +#define CONSYS_EMI_RAM_WIFI_BUILDTIME_OFFSET (0x68310) +#define CONSYS_EMI_RAM_MCU_BUILDTIME_OFFSET (0x68320) +#define CONSYS_EMI_PATCH_MCU_BUILDTIME_OFFSET (0x68330) + +/* AP_PCCIF4_BASE Register */ +#define INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG (0x438) +#define INFRASYS_COMMON_AP2MD_PCCIF4_AP_PCCIF_ACK_OFFSET (0x14) +#define INFRASYS_COMMON_AP2MD_CON_PWR_ON_CON_SW_READY_MASK (0x3 << 0) + +/*CONSYS_MCU_CFG_DBG_LP_INFO*/ +#define CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR (conn_reg.mcu_cfg_on_base + 0x104) +#define CONN_CFG_ON_CONN_ON_MON_CTL_ADDR (conn_reg.mcu_top_misc_on_base + 0x320) +#define CONN_CFG_ON_CONN_ON_MON_SEL0_ADDR (conn_reg.mcu_top_misc_on_base + 0x328) +#define CONN_CFG_ON_CONN_ON_MON_SEL1_ADDR (conn_reg.mcu_top_misc_on_base + 0x32C) +#define CONN_CFG_ON_CONN_ON_MON_SEL2_ADDR (conn_reg.mcu_top_misc_on_base + 0x330) +#define CONN_CFG_ON_CONN_ON_MON_SEL3_ADDR (conn_reg.mcu_top_misc_on_base + 0x334) +#define CONN_CFG_ON_CONN_ON_DBGSEL_ADDR (conn_reg.mcu_top_misc_on_base + 0x310) +#define CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_ADDR (conn_reg.mcu_top_misc_on_base + 0x340) +#define CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_MAPPING_AP_ADDR (0x180c1340) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +#ifdef CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status { + UINT32 counter; + UINT32 flags; + spinlock_t lock; +}; + +extern struct bt_wifi_v33_status gBtWifiV33; +#endif + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************* +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_MT6785_H_ */ diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mtk_wcn_consys_hw.h b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mtk_wcn_consys_hw.h new file mode 100644 index 00000000000000..42ef0c2953fa8b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/include/mtk_wcn_consys_hw.h @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_WCN_CONSYS_HW_H_ +#define _MTK_WCN_CONSYS_HW_H_ + +#include <sync_write.h> +/*#include <mt_reg_base.h>*/ +#include "wmt_plat.h" + +/*device tree mode*/ +#ifdef CONFIG_OF +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/irqreturn.h> +#include <linux/of_address.h> +#endif +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#define ENABLE MTK_WCN_BOOL_TRUE +#define DISABLE MTK_WCN_BOOL_FALSE + +#define KBYTE (1024*sizeof(char)) +#define CONSYS_PAGED_DUMP_SIZE (32*KBYTE) +#define CONSYS_EMI_MEM_SIZE (96*KBYTE) /*coredump space , 96K is enough */ + +#define CONSYS_SET_BIT(REG, BITVAL) (*((volatile UINT32 *)(REG)) |= ((UINT32)(BITVAL))) +#define CONSYS_CLR_BIT(REG, BITVAL) ((*(volatile UINT32 *)(REG)) &= ~((UINT32)(BITVAL))) +#define CONSYS_CLR_BIT_WITH_KEY(REG, BITVAL, KEY) {\ + UINT32 val = (*(volatile UINT32 *)(REG)); \ + val &= ~((UINT32)(BITVAL)); \ + val |= ((UINT32)(KEY)); \ + (*(volatile UINT32 *)(REG)) = val;\ +} +#define CONSYS_REG_READ(addr) (*((volatile UINT32 *)(addr))) +#define CONSYS_REG_WRITE(addr, data) mt_reg_sync_writel(data, addr) +#define CONSYS_REG_WRITE_RANGE(reg, data, end, begin) {\ + UINT32 val = CONSYS_REG_READ(reg); \ + SET_BIT_RANGE(&val, data, end, begin); \ + CONSYS_REG_WRITE(reg, val); \ +} +#define CONSYS_REG_WRITE_MASK(reg, data, mask) {\ + UINT32 val = CONSYS_REG_READ(reg); \ + SET_BIT_MASK(&val, data, mask); \ + CONSYS_REG_WRITE(reg, val); \ +} + +/* + * Write value with value_offset bits of right shift and size bits, + * to the reg_offset-th bit of address reg + * value -----------XXXXXXXXXXXX------------------- + * |<--size-->|<--value_offset-->| + * reg -------------OOOOOOOOOOOO----------------- + * |<--size-->|<--reg_offset-->| + * result -------------XXXXXXXXXXXX----------------- + */ +#define CONSYS_REG_WRITE_OFFSET_RANGE(reg, value, reg_offset, value_offset, size) ({\ + UINT32 data = (value) >> (value_offset); \ + data = GET_BIT_RANGE(data, size, 0); \ + data = data << (reg_offset); \ + CONSYS_REG_WRITE_RANGE(reg, data, ((reg_offset) + ((size) - 1)), reg_offset); \ +}) + +#define CONSYS_REG_WRITE_BIT(reg, offset, val) CONSYS_REG_WRITE_OFFSET_RANGE(reg, ((val) & 1), offset, 0, 1) + +/*force fw assert pattern*/ +#define EXP_APMEM_HOST_OUTBAND_ASSERT_MAGIC_W1 (0x19b30bb1) + +#define DYNAMIC_DUMP_GROUP_NUM 5 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +struct CONSYS_BASE_ADDRESS { + SIZE_T mcu_base; + SIZE_T ap_rgu_base; + SIZE_T topckgen_base; + SIZE_T spm_base; + SIZE_T mcu_conn_hif_on_base; + SIZE_T mcu_top_misc_off_base; + SIZE_T mcu_cfg_on_base; + SIZE_T mcu_cirq_base; + SIZE_T da_xobuf_base; + SIZE_T mcu_top_misc_on_base; + SIZE_T mcu_conn_hif_pdma_base; + SIZE_T ap_pccif4_base; + SIZE_T infra_ao_pericfg_base; + SIZE_T infracfg_reg_base; +}; + +enum CONSYS_BASE_ADDRESS_INDEX { + MCU_BASE_INDEX = 0, + TOP_RGU_BASE_INDEX, + INFRACFG_AO_BASE_INDEX, + SPM_BASE_INDEX, + MCU_CONN_HIF_ON_BASE_INDEX, + MCU_TOP_MISC_OFF_BASE_INDEX, + MCU_CFG_ON_BASE_INDEX, + MCU_CIRQ_BASE_INDEX, + MCU_TOP_MISC_ON_BASE_INDEX, + MCU_CONN_HIF_PDMA_BASE_INDEX, + AP_PCCIF4_BASE_INDEX, + INFRA_AO_PERICFG_BASE_INDEX, + INFRACFG_REG_BASE_INDEX, +}; + +typedef enum _ENUM_EMI_CTRL_STATE_OFFSET_ { + EXP_APMEM_CTRL_STATE = 0x0, + EXP_APMEM_CTRL_HOST_SYNC_STATE = 0x4, + EXP_APMEM_CTRL_HOST_SYNC_NUM = 0x8, + EXP_APMEM_CTRL_CHIP_SYNC_STATE = 0xc, + EXP_APMEM_CTRL_CHIP_SYNC_NUM = 0x10, + EXP_APMEM_CTRL_CHIP_SYNC_ADDR = 0x14, + EXP_APMEM_CTRL_CHIP_SYNC_LEN = 0x18, + EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START = 0x1c, + EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN = 0x20, + EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX = 0x24, + EXP_APMEM_CTRL_CHIP_INT_STATUS = 0x28, + EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END = 0x2c, + EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1 = 0x30, + EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM = 0x44, + EXP_APMEM_CTRL_CHIP_FW_DBGLOG_MODE = 0x40, + EXP_APMEM_CTRL_CHIP_DYNAMIC_DUMP = 0x48, + EXP_APMEM_CTRL_CHIP_CHECK_SLEEP = 0x4c, + EXP_APMEM_CTRL_ASSERT_FLAG = 0x100, + EXP_APMEM_CTRL_MAX +} ENUM_EMI_CTRL_STATE_OFFSET, *P_ENUM_EMI_CTRL_STATE_OFFSET; + +typedef enum _CONSYS_GPS_CO_CLOCK_TYPE_ { + GPS_TCXO_TYPE = 0, + GPS_CO_TSX_TYPE = 1, + GPS_CO_DCXO_TYPE = 2, + GPS_CO_VCTCXO_TYPE = 3, + GPS_CO_CLOCK_TYPE_MAX +} CONSYS_GPS_CO_CLOCK_TYPE, *P_CONSYS_GPS_CO_CLOCK_TYPE; + +typedef INT32(*CONSYS_IC_CLOCK_BUFFER_CTRL) (MTK_WCN_BOOL enable); +typedef VOID(*CONSYS_IC_HW_RESET_BIT_SET) (MTK_WCN_BOOL enable); +typedef VOID(*CONSYS_IC_HW_SPM_CLK_GATING_ENABLE) (VOID); +typedef INT32(*CONSYS_IC_HW_POWER_CTRL) (MTK_WCN_BOOL enable); +typedef INT32(*CONSYS_IC_AHB_CLOCK_CTRL) (MTK_WCN_BOOL enable); +typedef INT32(*POLLING_CONSYS_IC_CHIPID) (VOID); +typedef VOID(*UPDATE_CONSYS_ROM_DESEL_VALUE) (VOID); +typedef VOID(*CONSYS_HANG_DEBUG)(VOID); +typedef VOID(*CONSYS_IC_ARC_REG_SETTING) (VOID); +typedef VOID(*CONSYS_IC_AFE_REG_SETTING) (VOID); +typedef INT32(*CONSYS_IC_HW_VCN18_CTRL) (MTK_WCN_BOOL enable); +typedef VOID(*CONSYS_IC_VCN28_HW_MODE_CTRL) (UINT32 enable); +typedef INT32(*CONSYS_IC_HW_VCN28_CTRL) (UINT32 enable); +typedef INT32(*CONSYS_IC_HW_WIFI_VCN33_CTRL) (UINT32 enable); +typedef INT32(*CONSYS_IC_HW_BT_VCN33_CTRL) (UINT32 enable); +typedef UINT32(*CONSYS_IC_SOC_CHIPID_GET) (VOID); +typedef INT32(*CONSYS_IC_EMI_MPU_SET_REGION_PROTECTION) (VOID); +typedef UINT32(*CONSYS_IC_EMI_SET_REMAPPING_REG) (VOID); +typedef INT32(*IC_BT_WIFI_SHARE_V33_SPIN_LOCK_INIT) (VOID); +typedef INT32(*CONSYS_IC_CLK_GET_FROM_DTS) (struct platform_device *pdev); +typedef INT32(*CONSYS_IC_PMIC_GET_FROM_DTS) (struct platform_device *pdev); +typedef INT32(*CONSYS_IC_READ_IRQ_INFO_FROM_DTS) (struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag); +typedef INT32(*CONSYS_IC_READ_REG_FROM_DTS) (struct platform_device *pdev); +typedef UINT32(*CONSYS_IC_READ_CPUPCR) (VOID); +typedef VOID(*IC_FORCE_TRIGGER_ASSERT_DEBUG_PIN) (VOID); +typedef INT32(*CONSYS_IC_CO_CLOCK_TYPE) (VOID); +typedef P_CONSYS_EMI_ADDR_INFO(*CONSYS_IC_SOC_GET_EMI_PHY_ADD) (VOID); +typedef MTK_WCN_BOOL(*CONSYS_IC_NEED_STORE_PDEV) (VOID); +typedef UINT32(*CONSYS_IC_STORE_PDEV) (struct platform_device *pdev); +typedef UINT32(*CONSYS_IC_STORE_RESET_CONTROL) (struct platform_device *pdev); +typedef MTK_WCN_BOOL(*CONSYS_IC_NEED_GPS) (VOID); +typedef VOID(*CONSYS_IC_SET_IF_PINMUX) (MTK_WCN_BOOL enable); +typedef VOID(*CONSYS_IC_SET_DL_ROM_PATCH_FLAG) (INT32 flag); +typedef INT32(*CONSYS_IC_DEDICATED_LOG_PATH_INIT) (struct platform_device *pdev); +typedef VOID(*CONSYS_IC_DEDICATED_LOG_PATH_DEINIT) (VOID); +typedef INT32(*CONSYS_IC_CHECK_REG_READABLE) (VOID); +typedef INT32(*CONSYS_IC_EMI_COREDUMP_REMAPPING) (UINT8 __iomem **addr, UINT32 enable); +typedef INT32(*CONSYS_IC_RESET_EMI_COREDUMP) (UINT8 __iomem *addr); +typedef VOID(*CONSYS_IC_CLOCK_FAIL_DUMP) (VOID); +typedef INT32(*CONSYS_IC_IS_CONNSYS_REG) (UINT32 addr); +typedef PUINT32(*CONSYS_IC_RESUME_DUMP_INFO) (VOID); +typedef VOID(*CONSYS_IC_SET_PDMA_AXI_RREADY_FORCE_HIGH) (UINT32 enable); +typedef VOID(*CONSYS_IC_SET_MCIF_EMI_MPU_PROTECTION)(MTK_WCN_BOOL enable); +typedef INT32(*CONSYS_IC_CALIBRATION_BACKUP_RESTORE) (VOID); +typedef VOID(*CONSYS_IC_REGISTER_DEVAPC_CB) (VOID); +typedef VOID(*CONSYS_IC_INFRA_REG_DUMP)(VOID); +typedef INT32(*CONSYS_IC_IS_ANT_SWAP_ENABLE_BY_HWID) (INT32 pin_num); +typedef VOID(*CONSYS_IC_GET_ANT_SEL_CR_ADDR) (PUINT32 default_invert_cr, PUINT32 default_invert_bit); + +typedef struct _WMT_CONSYS_IC_OPS_ { + CONSYS_IC_CLOCK_BUFFER_CTRL consys_ic_clock_buffer_ctrl; + CONSYS_IC_HW_RESET_BIT_SET consys_ic_hw_reset_bit_set; + CONSYS_IC_HW_SPM_CLK_GATING_ENABLE consys_ic_hw_spm_clk_gating_enable; + CONSYS_IC_HW_POWER_CTRL consys_ic_hw_power_ctrl; + CONSYS_IC_AHB_CLOCK_CTRL consys_ic_ahb_clock_ctrl; + POLLING_CONSYS_IC_CHIPID polling_consys_ic_chipid; + UPDATE_CONSYS_ROM_DESEL_VALUE update_consys_rom_desel_value; + CONSYS_HANG_DEBUG consys_hang_debug; + CONSYS_IC_ARC_REG_SETTING consys_ic_acr_reg_setting; + CONSYS_IC_AFE_REG_SETTING consys_ic_afe_reg_setting; + CONSYS_IC_HW_VCN18_CTRL consys_ic_hw_vcn18_ctrl; + CONSYS_IC_VCN28_HW_MODE_CTRL consys_ic_vcn28_hw_mode_ctrl; + CONSYS_IC_HW_VCN28_CTRL consys_ic_hw_vcn28_ctrl; + CONSYS_IC_HW_WIFI_VCN33_CTRL consys_ic_hw_wifi_vcn33_ctrl; + CONSYS_IC_HW_BT_VCN33_CTRL consys_ic_hw_bt_vcn33_ctrl; + CONSYS_IC_SOC_CHIPID_GET consys_ic_soc_chipid_get; + CONSYS_IC_EMI_MPU_SET_REGION_PROTECTION consys_ic_emi_mpu_set_region_protection; + CONSYS_IC_EMI_SET_REMAPPING_REG consys_ic_emi_set_remapping_reg; + IC_BT_WIFI_SHARE_V33_SPIN_LOCK_INIT ic_bt_wifi_share_v33_spin_lock_init; + CONSYS_IC_CLK_GET_FROM_DTS consys_ic_clk_get_from_dts; + CONSYS_IC_PMIC_GET_FROM_DTS consys_ic_pmic_get_from_dts; + CONSYS_IC_READ_IRQ_INFO_FROM_DTS consys_ic_read_irq_info_from_dts; + CONSYS_IC_READ_REG_FROM_DTS consys_ic_read_reg_from_dts; + CONSYS_IC_READ_CPUPCR consys_ic_read_cpupcr; + IC_FORCE_TRIGGER_ASSERT_DEBUG_PIN ic_force_trigger_assert_debug_pin; + CONSYS_IC_CO_CLOCK_TYPE consys_ic_co_clock_type; + CONSYS_IC_SOC_GET_EMI_PHY_ADD consys_ic_soc_get_emi_phy_add; + CONSYS_IC_NEED_STORE_PDEV consys_ic_need_store_pdev; + CONSYS_IC_STORE_PDEV consys_ic_store_pdev; + CONSYS_IC_STORE_RESET_CONTROL consys_ic_store_reset_control; + CONSYS_IC_NEED_GPS consys_ic_need_gps; + CONSYS_IC_SET_IF_PINMUX consys_ic_set_if_pinmux; + CONSYS_IC_SET_DL_ROM_PATCH_FLAG consys_ic_set_dl_rom_patch_flag; + CONSYS_IC_DEDICATED_LOG_PATH_INIT consys_ic_dedicated_log_path_init; + CONSYS_IC_DEDICATED_LOG_PATH_DEINIT consys_ic_dedicated_log_path_deinit; + CONSYS_IC_CHECK_REG_READABLE consys_ic_check_reg_readable; + CONSYS_IC_EMI_COREDUMP_REMAPPING consys_ic_emi_coredump_remapping; + CONSYS_IC_RESET_EMI_COREDUMP consys_ic_reset_emi_coredump; + CONSYS_IC_CLOCK_FAIL_DUMP consys_ic_clock_fail_dump; + CONSYS_IC_IS_CONNSYS_REG consys_ic_is_connsys_reg; + CONSYS_IC_RESUME_DUMP_INFO consys_ic_resume_dump_info; + CONSYS_IC_SET_PDMA_AXI_RREADY_FORCE_HIGH consys_ic_set_pdma_axi_rready_force_high; + CONSYS_IC_SET_MCIF_EMI_MPU_PROTECTION consys_ic_set_mcif_emi_mpu_protection; + CONSYS_IC_CALIBRATION_BACKUP_RESTORE consys_ic_calibration_backup_restore; + CONSYS_IC_REGISTER_DEVAPC_CB consys_ic_register_devapc_cb; + CONSYS_IC_INFRA_REG_DUMP consys_ic_infra_reg_dump; + CONSYS_IC_IS_ANT_SWAP_ENABLE_BY_HWID consys_ic_is_ant_swap_enable_by_hwid; + CONSYS_IC_GET_ANT_SEL_CR_ADDR consys_ic_get_ant_sel_cr_addr; +} WMT_CONSYS_IC_OPS, *P_WMT_CONSYS_IC_OPS; +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CFG_WMT_DUMP_INT_STATUS +extern void mt_irq_dump_status(int irq); +#endif +extern struct CONSYS_BASE_ADDRESS conn_reg; +extern UINT32 gCoClockFlag; +extern EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off; +extern CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info; + +extern UINT64 gConEmiSize; +extern phys_addr_t gConEmiPhyBase; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 mtk_wcn_consys_hw_init(VOID); +INT32 mtk_wcn_consys_hw_deinit(VOID); +INT32 mtk_wcn_consys_hw_pwr_off(UINT32 co_clock_type); +INT32 mtk_wcn_consys_hw_pwr_on(UINT32 co_clock_type); +INT32 mtk_wcn_consys_hw_rst(UINT32 co_clock_type); +INT32 mtk_wcn_consys_hw_bt_paldo_ctrl(UINT32 enable); +INT32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT32 enable); +INT32 mtk_wcn_consys_hw_efuse_paldo_ctrl(UINT32 enable, UINT32 co_clock_type); +INT32 mtk_wcn_consys_hw_vcn28_ctrl(UINT32 enable); +INT32 mtk_wcn_consys_hw_state_show(VOID); +PUINT8 mtk_wcn_consys_emi_virt_addr_get(UINT32 ctrl_state_offset); +P_CONSYS_EMI_ADDR_INFO mtk_wcn_consys_soc_get_emi_phy_add(VOID); +UINT32 mtk_wcn_consys_read_cpupcr(VOID); +PUINT32 mtk_wcn_consys_read_dump_info_reg(VOID); +INT32 mtk_wcn_consys_hw_reg_ctrl(UINT32 on, UINT32 co_clock_type); +INT32 mtk_wcn_consys_hw_gpio_ctrl(UINT32 on); +INT32 mtk_wcn_consys_hw_restore(struct device *device); +VOID mtk_wcn_force_trigger_assert_debug_pin(VOID); +INT32 mtk_wcn_consys_read_irq_info_from_dts(PINT32 irq_num, PUINT32 irq_flag); +INT32 mtk_wcn_consys_reg_ctrl(UINT32 is_write, enum CONSYS_BASE_ADDRESS_INDEX index, UINT32 offset, + PUINT32 value); + +P_WMT_CONSYS_IC_OPS mtk_wcn_get_consys_ic_ops(VOID); +INT32 mtk_wcn_consys_jtag_set_for_mcu(VOID); +#if CONSYS_ENALBE_SET_JTAG +UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en); +#endif +#ifdef CONSYS_WMT_REG_SUSPEND_CB_ENABLE +UINT32 mtk_wcn_consys_hw_osc_en_ctrl(UINT32 en); +#endif +UINT32 mtk_wcn_consys_soc_chipid(VOID); +#if !defined(CONFIG_MTK_GPIO_LEGACY) +struct pinctrl *mtk_wcn_consys_get_pinctrl(VOID); +#endif +INT32 mtk_wcn_consys_co_clock_type(VOID); +INT32 mtk_wcn_consys_set_dbg_mode(UINT32 flag); +INT32 mtk_wcn_consys_set_dynamic_dump(PUINT32 buf); +INT32 mtk_wdt_swsysret_config(INT32 bit, INT32 set_value); +VOID mtk_wcn_consys_hang_debug(VOID); +UINT32 mtk_consys_get_gps_lna_pin_num(VOID); +INT32 mtk_consys_check_reg_readable(VOID); +VOID mtk_wcn_consys_clock_fail_dump(VOID); +INT32 mtk_consys_is_connsys_reg(UINT32 addr); +VOID mtk_consys_set_mcif_mpu_protection(MTK_WCN_BOOL enable); +INT32 mtk_consys_is_calibration_backup_restore_support(VOID); +VOID mtk_consys_set_chip_reset_status(INT32 status); +INT32 mtk_consys_chip_reset_status(VOID); +INT32 mtk_consys_is_ant_swap_enable_by_hwid(VOID); +INT32 mtk_consys_resume_dump_info(VOID); +VOID mtk_wcn_consys_ic_get_ant_sel_cr_addr(PUINT32 default_invert_cr, PUINT32 default_invert_bit); +#endif /* _MTK_WCN_CONSYS_HW_H_ */ + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6580.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6580.c new file mode 100644 index 00000000000000..2ecbf622333c6c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6580.c @@ -0,0 +1,1135 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <connectivity_build_in_adapter.h> + +#if defined(CONFIG_MTK_CLKMGR) +#include <mt_clkmgr.h> +#else +#include <linux/clk.h> +#endif /* defined(CONFIG_MTK_CLKMGR) */ +#include <linux/delay.h> +#include <linux/memblock.h> +#include "osal_typedef.h" +#include "mt6580.h" +#include "mtk_wcn_consys_hw.h" +#include <linux/platform_device.h> + +#if CONSYS_EMI_MPU_SETTING +#include <emi_mpu.h> +#endif + +#if CONSYS_PMIC_CTRL_ENABLE +#include <upmu_common.h> +#include <linux/regulator/consumer.h> +#endif + +#ifdef CONFIG_MTK_HIBERNATION +#include <mtk_hibernate_dpm.h> +#endif + +#include <linux/of_reserved_mem.h> + +#if CONSYS_CLOCK_BUF_CTRL +#include <mt_clkbuf_ctl.h> +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable); +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable); +static VOID consys_hw_spm_clk_gating_enable(VOID); +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable); +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable); +static INT32 polling_consys_chipid(VOID); +static VOID consys_acr_reg_setting(VOID); +static VOID consys_afe_reg_setting(VOID); +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable); +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable); +static INT32 consys_hw_vcn28_ctrl(UINT32 enable); +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable); +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable); +static UINT32 consys_soc_chipid_get(VOID); +static INT32 consys_emi_mpu_set_region_protection(VOID); +static UINT32 consys_emi_set_remapping_reg(VOID); +static INT32 bt_wifi_share_v33_spin_lock_init(VOID); +static INT32 consys_clk_get_from_dts(struct platform_device *pdev); +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev); +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, INT32 *irq_num, UINT32 *irq_flag); +static INT32 consys_read_reg_from_dts(struct platform_device *pdev); +static UINT32 consys_read_cpupcr(VOID); +static VOID force_trigger_assert_debug_pin(VOID); +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID); +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable); +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status gBtWifiV33; +#endif + +/* PMIC part */ +#if CONSYS_PMIC_CTRL_ENABLE +#if !defined(CONFIG_MTK_PMIC_LEGACY) +struct regulator *reg_VCN18; +struct regulator *reg_VCN28; +struct regulator *reg_VCN33_BT; +struct regulator *reg_VCN33_WIFI; +#endif +#endif + +/* CCF part */ +#if !defined(CONFIG_MTK_CLKMGR) +struct clk *clk_scp_conn_main; /*ctrl conn_power_on/off */ +struct clk *clk_infra_conn_main; /*ctrl infra_connmcu_bus clk */ +#endif /* !defined(CONFIG_MTK_CLKMGR) */ + + +EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { + .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, + .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, + .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, + .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, + .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, + .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, + .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, + .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, + .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, + .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, + .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, + .emi_apmem_ctrl_chip_page_dump_num = EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM, + .emi_apmem_ctrl_assert_flag = EXP_APMEM_CTRL_ASSERT_FLAG, +}; + +CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { + .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, + .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, + .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, + .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, + .p_ecso = &mtk_wcn_emi_state_off, + .emi_core_dump_offset = CONSYS_EMI_COREDUMP_OFFSET, +}; + +WMT_CONSYS_IC_OPS consys_ic_ops = { + .consys_ic_clock_buffer_ctrl = consys_clock_buffer_ctrl, + .consys_ic_hw_reset_bit_set = consys_hw_reset_bit_set, + .consys_ic_hw_spm_clk_gating_enable = consys_hw_spm_clk_gating_enable, + .consys_ic_hw_power_ctrl = consys_hw_power_ctrl, + .consys_ic_ahb_clock_ctrl = consys_ahb_clock_ctrl, + .polling_consys_ic_chipid = polling_consys_chipid, + .consys_ic_acr_reg_setting = consys_acr_reg_setting, + .consys_ic_afe_reg_setting = consys_afe_reg_setting, + .consys_ic_hw_vcn18_ctrl = consys_hw_vcn18_ctrl, + .consys_ic_vcn28_hw_mode_ctrl = consys_vcn28_hw_mode_ctrl, + .consys_ic_hw_vcn28_ctrl = consys_hw_vcn28_ctrl, + .consys_ic_hw_wifi_vcn33_ctrl = consys_hw_wifi_vcn33_ctrl, + .consys_ic_hw_bt_vcn33_ctrl = consys_hw_bt_vcn33_ctrl, + .consys_ic_soc_chipid_get = consys_soc_chipid_get, + .consys_ic_emi_mpu_set_region_protection = consys_emi_mpu_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .ic_bt_wifi_share_v33_spin_lock_init = bt_wifi_share_v33_spin_lock_init, + .consys_ic_clk_get_from_dts = consys_clk_get_from_dts, + .consys_ic_pmic_get_from_dts = consys_pmic_get_from_dts, + .consys_ic_read_irq_info_from_dts = consys_read_irq_info_from_dts, + .consys_ic_read_reg_from_dts = consys_read_reg_from_dts, + .consys_ic_read_cpupcr = consys_read_cpupcr, + .ic_force_trigger_assert_debug_pin = force_trigger_assert_debug_pin, + .consys_ic_soc_get_emi_phy_add = consys_soc_get_emi_phy_add, + .consys_ic_emi_coredump_remapping = consys_emi_coredump_remapping, + .consys_ic_reset_emi_coredump = consys_reset_emi_coredump, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +UINT32 gJtagCtrl; +#if CONSYS_ENALBE_SET_JTAG +#define JTAG_ADDR1_BASE 0x10002000 +PINT8 jtag_addr1 = (PINT8)JTAG_ADDR1_BASE; +#define JTAG1_REG_WRITE(addr, value) \ + writel(value, ((PUINT32)(jtag_addr1+(addr-JTAG_ADDR1_BASE)))) +#define JTAG1_REG_READ(addr) \ + readl(((PUINT32)(jtag_addr1+(addr-JTAG_ADDR1_BASE)))) +#endif + +INT32 mtk_wcn_consys_jtag_set_for_mcu(VOID) +{ +#if CONSYS_ENALBE_SET_JTAG + + if (gJtagCtrl) { +#if 0 + INT32 iRet = -1; + + WMT_PLAT_PR_INFO("WCN jtag_set_for_mcu start...\n"); + jtag_addr1 = ioremap(JTAG_ADDR1_BASE, 0x5000); + if (jtag_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + return iRet; + } + WMT_PLAT_PR_INFO("jtag_addr1 = 0x%p\n", jtag_addr1); + + JTAG1_REG_WRITE(0x100053c4, 0x11111100); + JTAG1_REG_WRITE(0x100053d4, 0x00111111); + + /*Enable IES of all pins */ + JTAG1_REG_WRITE(0x10002014, 0x00000003); + JTAG1_REG_WRITE(0x10005334, 0x55000000); + JTAG1_REG_WRITE(0x10005344, 0x00555555); + JTAG1_REG_WRITE(0x10005008, 0xc0000000); + JTAG1_REG_WRITE(0x10005018, 0x0000000d); + JTAG1_REG_WRITE(0x10005014, 0x00000032); + JTAG1_REG_WRITE(0x100020a4, 0x000000ff); + JTAG1_REG_WRITE(0x100020d4, 0x000000b4); + JTAG1_REG_WRITE(0x100020d8, 0x0000004b); + + WMT_PLAT_PR_INFO("WCN jtag set for mcu start...\n"); + kal_uint32 tmp = 0; + kal_int32 addr = 0; + kal_int32 remap_addr1 = 0; + kal_int32 remap_addr2 = 0; + + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + return -1; + } + + remap_addr2 = ioremap(JTAG_ADDR2_BASE, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + return -1; + } + + /*Pinmux setting for MT6625 I/F */ + addr = remap_addr1 + 0x03C0; + tmp = DRV_Reg32(addr); + tmp = tmp & 0xff; + tmp = tmp | 0x11111100; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + addr = remap_addr1 + 0x03D0; + tmp = DRV_Reg32(addr); + tmp = tmp & 0xff000000; + tmp = tmp | 0x00111111; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*AP GPIO Setting 1 <default use> */ + /*Enable IES */ + /* addr = 0x10002014; */ + addr = remap_addr2 + 0x0014; + tmp = 0x00000003; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + /*GPIO mode setting */ + /* addr = 0x10005334; */ + addr = remap_addr1 + 0x0334; + tmp = 0x55000000; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005344; */ + addr = remap_addr1 + 0x0344; + tmp = 0x00555555; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + /*GPIO direction control */ + /* addr = 0x10005008; */ + addr = remap_addr1 + 0x0008; + tmp = 0xc0000000; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005018; */ + addr = remap_addr1 + 0x0018; + tmp = 0x0000000d; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005014; */ + addr = remap_addr1 + 0x0014; + tmp = 0x00000032; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*PULL Enable */ + /* addr = 0x100020a4; */ + addr = remap_addr2 + 0x00a4; + tmp = 0x000000ff; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*PULL select enable */ + /* addr = 0x100020d4; */ + addr = remap_addr2 + 0x00d4; + tmp = 0x000000b4; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x100020d8; */ + addr = remap_addr2 + 0x00d8; + tmp = 0x0000004b; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); +#endif + } +#endif + return 0; +} + +UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en) +{ + WMT_PLAT_PR_INFO("%s jtag set for MCU\n", en ? "enable" : "disable"); + gJtagCtrl = en; + return 0; +} + +#if CONSYS_PMIC_CTRL_ENABLE +#ifdef CFG_WMT_READ_EFUSE_VCN33 +INT32 wmt_set_pmic_voltage(UINT32 level) +{ + INT32 iRet = -1; + + switch (level) { + case 0: + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + regulator_set_voltage(reg_VCN33_WIFI, 3300000, 3300000); + WMT_PLAT_PR_INFO("WMT set BT/WIFI regulator voltage:3.3V!\n"); + iRet = 0; + break; + case 1: + regulator_set_voltage(reg_VCN33_BT, 3400000, 3400000); + regulator_set_voltage(reg_VCN33_WIFI, 3400000, 3400000); + WMT_PLAT_PR_INFO("WMT set BT/WIFI regulator voltage:3.4V!\n"); + iRet = 0; + break; + case 2: + regulator_set_voltage(reg_VCN33_BT, 3500000, 3500000); + regulator_set_voltage(reg_VCN33_WIFI, 3500000, 3500000); + WMT_PLAT_PR_INFO("WMT set BT/WIFI regulator voltage:3.5V!\n"); + iRet = 0; + break; + case 3: + regulator_set_voltage(reg_VCN33_BT, 3600000, 3600000); + regulator_set_voltage(reg_VCN33_WIFI, 3600000, 3600000); + WMT_PLAT_PR_INFO("WMT set BT/WIFI regulator voltage:3.6V!\n"); + iRet = 0; + break; + default: + regulator_set_voltage(reg_VCN33_BT, 3500000, 3500000); + regulator_set_voltage(reg_VCN33_WIFI, 3500000, 3500000); + WMT_PLAT_PR_INFO("WMT set BT/WIFI regulator voltage default:3.5V!\n"); + iRet = 0; + break; + } + return iRet; +} +#endif /*CFG_WMT_READ_EFUSE_VCN33 defined*/ +#endif + +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_CLOCK_BUF_CTRL + KERNEL_clk_buf_ctrl(CLK_BUF_CONNSRC, enable); +#endif + return 0; +} + +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable) +{ +#ifdef CONFIG_OF /*use DT */ + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE((conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET), + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) | + CONSYS_CPU_SW_RST_BIT | CONSYS_CPU_SW_RST_CTRL_KEY); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88 (key)" */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_CPU_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + } +#else + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE(CONSYS_CPU_SW_RST_REG, + (CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG) | CONSYS_CPU_SW_RST_BIT | + CONSYS_CPU_SW_RST_CTRL_KEY)); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88(key)" */ + CONSYS_REG_WRITE(CONSYS_CPU_SW_RST_REG, + (CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG) & ~CONSYS_CPU_SW_RST_BIT) | + CONSYS_CPU_SW_RST_CTRL_KEY); + } +#endif +} + +static VOID consys_hw_spm_clk_gating_enable(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + /*turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE((conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET), CONSYS_PWRON_CONFG_EN_VALUE); +#else + /*turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE(CONSYS_PWRON_CONFG_EN_REG, CONSYS_PWRON_CONFG_EN_VALUE); +#endif +} + +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + INT32 iRet = -1; +#endif + + if (enable) { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE +#if defined(CONFIG_MTK_CLKMGR) + iRet = conn_power_on(); /* consult clkmgr owner. */ + if (iRet) + WMT_PLAT_PR_ERR("conn_power_on fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("conn_power_on ok\n"); +#else + iRet = clk_prepare_enable(clk_scp_conn_main); + if (iRet) + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_scp_conn_main) fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_scp_conn_main) ok\n"); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + +#else + +#ifdef CONFIG_OF /*use DT */ + /*2.write conn_top1_pwr_on=1, power on conn_top1 0x10006280 [2] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_BIT); + /*3.read conn_top1_pwr_on_ack =1, power on ack ready 0x1000660C [1] */ + while (0 == (CONSYS_PWR_ON_ACK_BIT & CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET))) + NULL; + /*5.write conn_top1_pwr_on_s=1, power on conn_top1 0x10006280 [3] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_S_BIT); + /*6.write conn_clk_dis=0, enable connsys clock 0x10006280 [4] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_CLK_CTRL_BIT); + /*7.wait 1us */ + udelay(1); + /*8.read conn_top1_pwr_on_ack_s =1, power on ack ready 0x10006610 [1] */ + while (0 == (CONSYS_PWR_CONN_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET))) + NULL; + /*9.release connsys ISO, conn_top1_iso_en=0 0x10006280 [1] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_ISO_S_BIT); + /*10.release SW reset of connsys, conn_ap_sw_rst_b=1 0x10006280[0] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_RST_BIT); + /*disable AXI BUS protect */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) & + ~CONSYS_PROT_MASK); + while (CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_STA1_OFFSET) & CONSYS_PROT_MASK) + NULL; +#else /*use HADRCODE, maybe no use.. */ + /*2.write conn_top1_pwr_on=1, power on conn_top1 0x10006280 [2] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ON_BIT); + /*3.read conn_top1_pwr_on_ack =1, power on ack ready 0x1000660C [1] */ + while (0 == (CONSYS_PWR_ON_ACK_BIT & CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_REG))) + NULL; + /*5.write conn_top1_pwr_on_s=1, power on conn_top1 0x10006280 [3] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ON_S_BIT); + /*6.write conn_clk_dis=0, enable connsys clock 0x10006280 [4] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_CLK_CTRL_BIT); + /*7.wait 1us */ + udelay(1); + /*8.read conn_top1_pwr_on_ack_s =1, power on ack ready 0x10006610 [1] */ + while (0 == (CONSYS_PWR_CONN_ACK_S_BIT & CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_S_REG))) + NULL; + /*9.release connsys ISO, conn_top1_iso_en=0 0x10006280 [1] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_SPM_PWR_ISO_S_BIT); + /*10.release SW reset of connsys, conn_ap_sw_rst_b=1 0x10006280[0] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_RST_BIT); + /*disable AXI BUS protect */ + CONSYS_REG_WRITE(CONSYS_TOPAXI_PROT_EN, CONSYS_REG_READ(CONSYS_TOPAXI_PROT_EN) & ~CONSYS_PROT_MASK); + while (CONSYS_REG_READ(CONSYS_TOPAXI_PROT_STA1) & CONSYS_PROT_MASK) + NULL; +#endif +#endif + } else { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE +#if defined(CONFIG_MTK_CLKMGR) + /*power off connsys by API (MT6582, MT6572 are different) API: conn_power_off() */ + iRet = conn_power_off(); /* consult clkmgr owner */ + if (iRet) + WMT_PLAT_PR_ERR("conn_power_off fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("conn_power_off ok\n"); +#else + clk_disable_unprepare(clk_scp_conn_main); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_scp_conn_main) calling\n"); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + +#else + +#ifdef CONFIG_OF /*use DT */ + { + INT32 count = 0; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) | + CONSYS_PROT_MASK); + while ((CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_STA1_OFFSET) & + CONSYS_PROT_MASK) != CONSYS_PROT_MASK) { + count++; + if (count > 1000) + break; + } + } + /*release connsys ISO, conn_top1_iso_en=1 0x10006280 [1] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ISO_S_BIT); + /*assert SW reset of connsys, conn_ap_sw_rst_b=0 0x10006280[0] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x10006280 [4] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x10006280 [3:2] 2'b00 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#else + { + INT32 count = 0; + + CONSYS_REG_WRITE(CONSYS_TOPAXI_PROT_EN, + CONSYS_REG_READ(CONSYS_TOPAXI_PROT_EN) | CONSYS_PROT_MASK); + while ((CONSYS_REG_READ(CONSYS_TOPAXI_PROT_STA1) & CONSYS_PROT_MASK) != CONSYS_PROT_MASK) { + count++; + if (count > 1000) + break; + } + + } + /*release connsys ISO, conn_top1_iso_en=1 0x10006280 [1] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ISO_S_BIT); + /*assert SW reset of connsys, conn_ap_sw_rst_b=0 0x10006280[0] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x10006280 [4] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x10006280 [3:2] 2'b00 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#endif /* CONFIG_OF */ +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } + +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + return iRet; +#else + return 0; +#endif +} + +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_AHB_CLK_MAGEMENT + if (enable) { +#if defined(CONFIG_MTK_CLKMGR) + enable_clock(MT_CG_INFRA_CONNMCU_BUS, "WCN_MOD"); + WMT_PLAT_PR_DBG("enable MT_CG_INFRA_CONNMCU_BUS CLK\n"); +#else + INT32 iRet = -1; + + iRet = clk_prepare_enable(clk_infra_conn_main); + if (iRet) + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_infra_conn_main) fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("[CCF]enable clk_infra_conn_main\n"); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + } else { +#if defined(CONFIG_MTK_CLKMGR) + disable_clock(MT_CG_INFRA_CONNMCU_BUS, "WMT_MOD"); +#else + clk_disable_unprepare(clk_infra_conn_main); + WMT_PLAT_PR_DBG("[CCF] clk_disable_unprepare(clk_infra_conn_main) calling\n"); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + } +#endif + return 0; +} + +static INT32 polling_consys_chipid(VOID) +{ + UINT32 retry = 10; + UINT32 consysHwChipId = 0; + +#ifdef CONFIG_OF /*use DT */ + /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ + while (retry-- > 0) { + consysHwChipId = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CHIP_ID_OFFSET); + if (consysHwChipId == 0x6580) { + WMT_PLAT_PR_INFO("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + msleep(20); + } + + if ((0 == retry) || (0 == consysHwChipId)) { + WMT_PLAT_PR_ERR("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + WMT_PLAT_PR_INFO("reg dump:CONSYS_CPU_SW_RST_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_S_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_TOP1_PWR_CTRL_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET)); + } +#else + /*12.poll CONNSYS CHIP ID until 6752 is returned 0x18070008 32'h6752 */ + while (retry-- > 0) { + WMT_PLAT_PR_DBG("CONSYS_CHIP_ID_REG(0x%08x)", CONSYS_REG_READ(CONSYS_CHIP_ID_REG)); + consysHwChipId = CONSYS_REG_READ(CONSYS_CHIP_ID_REG); + if ((consysHwChipId == 0x0321) || (consysHwChipId == 0x0335) || (consysHwChipId == 0x0337)) { + WMT_PLAT_PR_INFO("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + msleep(20); + } + + if ((0 == retry) || (0 == consysHwChipId)) { + WMT_PLAT_PR_ERR("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + WMT_PLAT_PR_INFO("reg dump:CONSYS_CPU_SW_RST_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_S_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_S_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_TOP1_PWR_CTRL_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG)); + } +#endif + return 0; +} + +static VOID consys_acr_reg_setting(VOID) +{ + /* + *14.write 1 to conn_mcu_confg ACR[1] if real speed MBIST + *(default write "1") ACR 0x18070110[18] 1'b1 + *if this bit is 0, HW will do memory auto test under low CPU frequence (26M Hz) + *if this bit is 0, HW will do memory auto test under high CPU frequence(138M Hz) + *inclulding low CPU frequence + */ +#ifdef CONFIG_OF /*use DT */ + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET, + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET) | + CONSYS_MCU_CFG_ACR_MBIST_BIT); +#else + CONSYS_REG_WRITE(CONSYS_MCU_CFG_ACR_REG, + CONSYS_REG_READ(CONSYS_MCU_CFG_ACR_REG) | CONSYS_MCU_CFG_ACR_MBIST_BIT); +#endif +} + +static VOID consys_afe_reg_setting(VOID) +{ +#if 0 + /*15.default no need,update ANA_WBG(AFE) CR if needed, CONSYS_AFE_REG */ + CONSYS_REG_WRITE(CONSYS_AFE_REG_DIG_RCK_01, CONSYS_AFE_REG_DIG_RCK_01_VALUE); + CONSYS_REG_WRITE(CONSYS_AFE_REG_WBG_PLL_02, CONSYS_AFE_REG_WBG_PLL_02_VALUE); + CONSYS_REG_WRITE(CONSYS_AFE_REG_WBG_WB_TX_01, CONSYS_AFE_REG_WBG_WB_TX_01_VALUE); +#endif +} + +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*need PMIC driver provide new API protocol */ + /*1.AP power on VCN_1V8 LDO (with PMIC_WRAP API) VCN_1V8 */ +#if MT6580_WORKAROUND + KERNEL_pmic_set_register_value(MT6350_VCN_1V8_CON1, 0); +#else +#if !defined(CONFIG_MTK_PMIC_LEGACY) + KERNEL_pmic_set_register_value(PMIC_VCN_1V8_ON_CTRL, 0); + if (reg_VCN18) { + if (regulator_enable(reg_VCN18)) + WMT_PLAT_PR_INFO("wmt_dev enable VCN_1V8 fail!\n"); + else + WMT_PLAT_PR_DBG("wmt_dev enable VCN_1V8\n"); + } +#endif +#endif + } else { + /*AP power off MT6323 VCN_1V8 LDO (with PMIC_WRAP API) RG_VCN18_ON_CTRL "0x0510[1] + *"1'b0 RG_VCN18_EN" 0x0512[14]" 1'b0" + */ +#if MT6580_WORKAROUND + KERNEL_pmic_set_register_value(MT6350_VCN_1V8_CON1, 1); +#else +#if !defined(CONFIG_MTK_PMIC_LEGACY) + KERNEL_pmic_set_register_value(PMIC_VCN_1V8_ON_CTRL, 0); + if (reg_VCN18) { + regulator_disable(reg_VCN18); + WMT_PLAT_PR_INFO("wmt_dev disable VCN_1V8\n"); + } +#endif +#endif + } +#endif + return 0; +} + +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + KERNEL_pmic_set_register_value(PMIC_VCN28_ON_CTRL, 1); + /*2.2 turn on VCN28 LDO (with PMIC_WRAP API) DA_XOBUF_SEL 0x1000513C[7:6]" " 2'b11"*/ + CONSYS_REG_WRITE((conn_reg.da_xobuf_base + CONSYS_DA_XOBUF_OFFSET), + CONSYS_REG_READ(conn_reg.da_xobuf_base + CONSYS_DA_XOBUF_OFFSET) | + ((0x1 << 7) | (0x1 << 6))); + WMT_PLAT_PR_INFO("NOT co_clock mode reg dump:XO BUFFER(0x%08x)\n", + CONSYS_REG_READ(conn_reg.da_xobuf_base + CONSYS_DA_XOBUF_OFFSET)); + } else { + KERNEL_pmic_set_register_value(PMIC_VCN28_ON_CTRL, 0); + /*2.set RF XO BUF source from CellularRF DA_XOBUF_SEL 0x1000513C[7:6] 2'b10*/ + CONSYS_REG_WRITE((conn_reg.da_xobuf_base + CONSYS_DA_XOBUF_OFFSET), + CONSYS_REG_READ(conn_reg.da_xobuf_base + CONSYS_DA_XOBUF_OFFSET) & + ~(0x1 << 6)); + CONSYS_REG_WRITE((conn_reg.da_xobuf_base + CONSYS_DA_XOBUF_OFFSET), + CONSYS_REG_READ(conn_reg.da_xobuf_base + CONSYS_DA_XOBUF_OFFSET) | + (0x1 << 7)); + WMT_PLAT_PR_INFO("co_clock mode reg dump:XO BUFFER(0x%08x)\n", + CONSYS_REG_READ(conn_reg.da_xobuf_base + CONSYS_DA_XOBUF_OFFSET)); + } +#endif +} + +static INT32 consys_hw_vcn28_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { +#if defined(CONFIG_MTK_PMIC_LEGACY) + hwPowerOn(MT6328_POWER_LDO_VCN28, VOL_2800, "wcn_drv"); +#else + if (reg_VCN28) { + regulator_set_voltage(reg_VCN28, VOL_2800, VOL_2800); + if (regulator_enable(reg_VCN28)) + WMT_PLAT_PR_ERR("enable VCN_2V8 fail!\n"); + else + WMT_PLAT_PR_DBG("enable VCN_2V8 ok\n"); + } +#endif + } else { +#if defined(CONFIG_MTK_LEGACY) + hwPowerDown(MT6328_POWER_LDO_VCN28, "wcn_drv"); +#else + if (reg_VCN28) + regulator_disable(reg_VCN28); +#endif + } +#endif + return 0; +} + +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + /* spin_lock_irqsave(&gBtWifiV33.lock,gBtWifiV33.flags); */ + if (enable) { + if (1 == gBtWifiV33.counter) { + gBtWifiV33.counter++; + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else if (2 == gBtWifiV33.counter) { + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else { +#if CONSYS_PMIC_CTRL_ENABLE + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + KERNEL_pmic_set_register_value(PMIC_VCN33_LP_SET, 0); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 on\n"); + gBtWifiV33.counter++; + } + + } else { + if (1 == gBtWifiV33.counter) { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + KERNEL_pmic_set_register_value(PMIC_VCN33_LP_SET, 1); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 off\n"); + gBtWifiV33.counter--; + } else if (2 == gBtWifiV33.counter) { + gBtWifiV33.counter--; + WMT_PLAT_PR_DBG("V33 no need disabled,counter(%d)\n", gBtWifiV33.counter); + } else { + WMT_PLAT_PR_DBG("V33 has been disabled,counter(%d)\n", gBtWifiV33.counter); + } + + } + /* spin_unlock_irqrestore(&gBtWifiV33.lock,gBtWifiV33.flags); */ +#else + if (enable) { + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, VOL_3300, VOL_3300); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } +#endif + WMT_PLAT_PR_INFO("WMT do BT PMIC on\n"); + } else { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); +#endif + WMT_PLAT_PR_INFO("WMT do BT PMIC off\n"); + } +#endif + return 0; +} + +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + consys_hw_bt_vcn33_ctrl(enable); +#else + if (enable) { + /*do WIFI PMIC on,depenency PMIC API ready */ + /*switch WIFI PALDO control from SW mode to HW mode:0x418[14]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + + if (reg_VCN33_WIFI) { + regulator_set_voltage(reg_VCN33_WIFI, VOL_3300, VOL_3300); + if (regulator_enable(reg_VCN33_WIFI)) + WMT_PLAT_PR_ERR("WMT do WIFI PMIC on fail!\n"); + } +#endif + WMT_PLAT_PR_INFO("WMT do WIFI PMIC on\n"); + } else { + /*do WIFI PMIC off */ + /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + + if (reg_VCN33_WIFI) + regulator_disable(reg_VCN33_WIFI); +#endif + WMT_PLAT_PR_INFO("WMT do WIFI PMIC off\n"); + } +#endif + return 0; +} + +#if CONSYS_WMT_REG_SUSPEND_CB_ENABLE +UINT32 mtk_wcn_consys_hw_osc_en_ctrl(UINT32 en) +{ + if (en) { + WMT_PLAT_PR_INFO("enable consys sleep mode(turn off 26M)\n"); + CONSYS_REG_WRITE(CONSYS_AP2CONN_OSC_EN_REG, CONSYS_REG_READ(CONSYS_AP2CONN_OSC_EN_REG) & + ~CONSYS_AP2CONN_OSC_EN_BIT); + } else { + WMT_PLAT_PR_INFO("disable consys sleep mode\n"); + CONSYS_REG_WRITE(CONSYS_AP2CONN_OSC_EN_REG, CONSYS_REG_READ(CONSYS_AP2CONN_OSC_EN_REG) | + CONSYS_AP2CONN_OSC_EN_BIT); + } + + WMT_PLAT_PR_INFO("dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", CONSYS_REG_READ(CONSYS_AP2CONN_OSC_EN_REG)); + + return 0; +} +#endif + +static INT32 consys_emi_mpu_set_region_protection(VOID) +{ +#if CONSYS_EMI_MPU_SETTING + /*set MPU for EMI share Memory */ + WMT_PLAT_PR_INFO("setting MPU for EMI share memory\n"); + emi_mpu_set_region_protection(gConEmiPhyBase + SZ_1M/2, + gConEmiPhyBase + gConEmiSize - 1, + 6, + SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, NO_PROTECTION)); +#endif + return 0; +} + +static UINT32 consys_emi_set_remapping_reg(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + UINT32 addrPhy = 0; + + /*consys to ap emi remapping register:10000320, cal remapping address */ + addrPhy = (gConEmiPhyBase & 0xFFF00000) >> 20; + + /*enable consys to ap emi remapping bit12 */ + addrPhy = addrPhy | 0x1000; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); + + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); +#endif + return 0; +} + +static INT32 bt_wifi_share_v33_spin_lock_init(VOID) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + gBtWifiV33.counter = 0; + spin_lock_init(&gBtWifiV33.lock); +#endif + return 0; +} + +static INT32 consys_clk_get_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ +#if !defined(CONFIG_MTK_CLKMGR) + clk_scp_conn_main = devm_clk_get(&pdev->dev, "conn"); + if (IS_ERR(clk_scp_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_scp_conn_main clock.\n"); + return PTR_ERR(clk_scp_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_scp_conn_main=%p\n", clk_scp_conn_main); + + clk_infra_conn_main = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(clk_infra_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_infra_conn_main clock.\n"); + return PTR_ERR(clk_infra_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_infra_conn_main=%p\n", clk_infra_conn_main); +#endif /* !defined(CONFIG_MTK_CLKMGR) */ +#endif + return 0; +} + +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ +#if CONSYS_PMIC_CTRL_ENABLE +#if !defined(CONFIG_MTK_PMIC_LEGACY) + reg_VCN18 = regulator_get(&pdev->dev, "vcn18"); + if (!reg_VCN18) + WMT_PLAT_PR_ERR("Regulator_get VCN_1V8 fail\n"); + reg_VCN28 = regulator_get(&pdev->dev, "vcn28"); + if (!reg_VCN28) + WMT_PLAT_PR_ERR("Regulator_get VCN_2V8 fail\n"); + reg_VCN33_BT = regulator_get(&pdev->dev, "vcn33_bt"); + if (!reg_VCN33_BT) + WMT_PLAT_PR_ERR("Regulator_get VCN33_BT fail\n"); + reg_VCN33_WIFI = regulator_get(&pdev->dev, "vcn33_wifi"); + if (!reg_VCN33_WIFI) + WMT_PLAT_PR_ERR("Regulator_get VCN33_WIFI fail\n"); +#endif +#endif +#endif + return 0; +} + +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, INT32 *irq_num, UINT32 *irq_flag) +{ +#ifdef CONFIG_OF /*use DT */ + struct device_node *node; + UINT32 irq_info[3] = { 0, 0, 0 }; + + INT32 iret = -1; + + node = pdev->dev.of_node; + if (node) { + *irq_num = irq_of_parse_and_map(node, 0); + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + WMT_PLAT_PR_ERR("get irq flags from DTS fail!!\n"); + return iret; + } + *irq_flag = irq_info[2]; + WMT_PLAT_PR_INFO("get irq id(%d) and irq trigger flag(%d) from DT\n", *irq_num, + *irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iret; + } +#endif + return 0; +} + +static INT32 consys_read_reg_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ + INT32 iRet = -1; + struct device_node *node = NULL; + + node = pdev->dev.of_node; + if (node) { + /* registers base address */ + conn_reg.mcu_base = (SIZE_T) of_iomap(node, 0); + WMT_PLAT_PR_DBG("Get mcu register base(0x%zx)\n", conn_reg.mcu_base); + conn_reg.ap_rgu_base = (SIZE_T) of_iomap(node, 1); + WMT_PLAT_PR_DBG("Get ap_rgu register base(0x%zx)\n", conn_reg.ap_rgu_base); + conn_reg.topckgen_base = (SIZE_T) of_iomap(node, 2); + WMT_PLAT_PR_DBG("Get topckgen register base(0x%zx)\n", conn_reg.topckgen_base); + conn_reg.spm_base = (SIZE_T) of_iomap(node, 3); + WMT_PLAT_PR_DBG("Get spm register base(0x%zx)\n", conn_reg.spm_base); + conn_reg.da_xobuf_base = (SIZE_T)of_iomap(node, 4); + WMT_PLAT_PR_INFO("Get xo_buf register base(0x%zx)\n", conn_reg.da_xobuf_base); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iRet; + } +#endif + return 0; +} + +static VOID force_trigger_assert_debug_pin(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + usleep_range(64, 96); + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); +#endif +} + +static UINT32 consys_read_cpupcr(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CPUPCR_OFFSET); +#endif +} + +static UINT32 consys_soc_chipid_get(VOID) +{ + return PLATFORM_SOC_CHIP; +} + +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID) +{ + return &mtk_wcn_emi_addr_info; +} + +P_WMT_CONSYS_IC_OPS mtk_wcn_get_consys_ic_ops(VOID) +{ + return &consys_ic_ops; +} + +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable) +{ + if (enable) { + *addr = ioremap(gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET, CONSYS_EMI_MEM_SIZE); + if (*addr) { + WMT_PLAT_PR_INFO("COREDUMP EMI mapping OK virtual(0x%p) physical(0x%x)\n", + *addr, (UINT32) gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET); + memset_io(*addr, 0, CONSYS_EMI_MEM_SIZE); + } else { + WMT_PLAT_PR_ERR("EMI mapping fail\n"); + return -1; + } + } else { + if (*addr) { + iounmap(*addr); + *addr = NULL; + } + } + return 0; +} + +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr) +{ + if (!addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + WMT_PLAT_PR_INFO("Reset EMI(0xF0080000 ~ 0xF0080400) and (0xF0088400 ~ 0xF0090400)\n"); + /* reset 0xF0080000 ~ 0xF0080400 (1K) */ + memset_io(addr, 0, 0x400); + /* reset 0xF0088400 ~ 0xF0090400 (32K) */ + memset_io(addr + CONSYS_EMI_PAGED_DUMP_OFFSET, 0, 0x8000); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6735.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6735.c new file mode 100644 index 00000000000000..0554b48f7a15f8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6735.c @@ -0,0 +1,1110 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <connectivity_build_in_adapter.h> + +#if defined(CONFIG_MTK_CLKMGR) +#include <mt_clkmgr.h> +#else +#include <linux/clk.h> +#endif /* defined(CONFIG_MTK_CLKMGR) */ +#include <linux/delay.h> +#include <linux/memblock.h> +#include "osal_typedef.h" +#include "mt6735.h" +#include "mtk_wcn_consys_hw.h" +#include <linux/platform_device.h> + +#if CONSYS_EMI_MPU_SETTING +#include <emi_mpu.h> +#endif + +#if CONSYS_PMIC_CTRL_ENABLE +#include <upmu_common.h> +#include <linux/regulator/consumer.h> +#endif + +#ifdef CONFIG_MTK_HIBERNATION +#include <mtk_hibernate_dpm.h> +#endif + +#include <linux/of_reserved_mem.h> + +#if CONSYS_CLOCK_BUF_CTRL +#include <mt_clkbuf_ctl.h> +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable); +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable); +static VOID consys_hw_spm_clk_gating_enable(VOID); +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable); +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable); +static INT32 polling_consys_chipid(VOID); +static VOID consys_acr_reg_setting(VOID); +static VOID consys_afe_reg_setting(VOID); +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable); +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable); +static INT32 consys_hw_vcn28_ctrl(UINT32 enable); +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable); +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable); +static UINT32 consys_soc_chipid_get(VOID); +static INT32 consys_emi_mpu_set_region_protection(VOID); +static UINT32 consys_emi_set_remapping_reg(VOID); +static INT32 bt_wifi_share_v33_spin_lock_init(VOID); +static INT32 consys_clk_get_from_dts(struct platform_device *pdev); +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev); +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, INT32 *irq_num, UINT32 *irq_flag); +static INT32 consys_read_reg_from_dts(struct platform_device *pdev); +static UINT32 consys_read_cpupcr(VOID); +static VOID force_trigger_assert_debug_pin(VOID); +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID); +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable); +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status gBtWifiV33; +#endif + +/* CCF part */ +#if !defined(CONFIG_MTK_CLKMGR) +struct clk *clk_scp_conn_main; /*ctrl conn_power_on/off */ +struct clk *clk_infra_conn_main; /*ctrl infra_connmcu_bus clk */ +#endif /* !defined(CONFIG_MTK_CLKMGR) */ + + +/* PMIC part */ +#if CONSYS_PMIC_CTRL_ENABLE +#if !defined(CONFIG_MTK_PMIC_LEGACY) +struct regulator *reg_VCN18; +struct regulator *reg_VCN28; +struct regulator *reg_VCN33_BT; +struct regulator *reg_VCN33_WIFI; +#endif +#endif + +EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { + .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, + .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, + .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, + .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, + .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, + .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, + .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, + .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, + .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, + .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, + .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, + .emi_apmem_ctrl_chip_page_dump_num = EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM, + .emi_apmem_ctrl_assert_flag = EXP_APMEM_CTRL_ASSERT_FLAG, +}; + +CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { + .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, + .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, + .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, + .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, + .p_ecso = &mtk_wcn_emi_state_off, + .emi_core_dump_offset = CONSYS_EMI_COREDUMP_OFFSET, +}; + +WMT_CONSYS_IC_OPS consys_ic_ops = { + .consys_ic_clock_buffer_ctrl = consys_clock_buffer_ctrl, + .consys_ic_hw_reset_bit_set = consys_hw_reset_bit_set, + .consys_ic_hw_spm_clk_gating_enable = consys_hw_spm_clk_gating_enable, + .consys_ic_hw_power_ctrl = consys_hw_power_ctrl, + .consys_ic_ahb_clock_ctrl = consys_ahb_clock_ctrl, + .polling_consys_ic_chipid = polling_consys_chipid, + .consys_ic_acr_reg_setting = consys_acr_reg_setting, + .consys_ic_afe_reg_setting = consys_afe_reg_setting, + .consys_ic_hw_vcn18_ctrl = consys_hw_vcn18_ctrl, + .consys_ic_vcn28_hw_mode_ctrl = consys_vcn28_hw_mode_ctrl, + .consys_ic_hw_vcn28_ctrl = consys_hw_vcn28_ctrl, + .consys_ic_hw_wifi_vcn33_ctrl = consys_hw_wifi_vcn33_ctrl, + .consys_ic_hw_bt_vcn33_ctrl = consys_hw_bt_vcn33_ctrl, + .consys_ic_soc_chipid_get = consys_soc_chipid_get, + .consys_ic_emi_mpu_set_region_protection = consys_emi_mpu_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .ic_bt_wifi_share_v33_spin_lock_init = bt_wifi_share_v33_spin_lock_init, + .consys_ic_clk_get_from_dts = consys_clk_get_from_dts, + .consys_ic_pmic_get_from_dts = consys_pmic_get_from_dts, + .consys_ic_read_irq_info_from_dts = consys_read_irq_info_from_dts, + .consys_ic_read_reg_from_dts = consys_read_reg_from_dts, + .consys_ic_read_cpupcr = consys_read_cpupcr, + .ic_force_trigger_assert_debug_pin = force_trigger_assert_debug_pin, + .consys_ic_soc_get_emi_phy_add = consys_soc_get_emi_phy_add, + .consys_ic_emi_coredump_remapping = consys_emi_coredump_remapping, + .consys_ic_reset_emi_coredump = consys_reset_emi_coredump, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +UINT32 gJtagCtrl; +#if CONSYS_ENALBE_SET_JTAG +#define JTAG_ADDR1_BASE 0x10002000 +PINT8 jtag_addr1 = (PINT8)JTAG_ADDR1_BASE; +#define JTAG1_REG_WRITE(addr, value) \ + writel(value, ((PUINT32)(jtag_addr1+(addr-JTAG_ADDR1_BASE)))) +#define JTAG1_REG_READ(addr) \ + readl(((PUINT32)(jtag_addr1+(addr-JTAG_ADDR1_BASE)))) +#endif + +INT32 mtk_wcn_consys_jtag_set_for_mcu(VOID) +{ +#if CONSYS_ENALBE_SET_JTAG + + if (gJtagCtrl) { +#if 0 + INT32 iRet = -1; + + WMT_PLAT_PR_INFO("WCN jtag_set_for_mcu start...\n"); + jtag_addr1 = ioremap(JTAG_ADDR1_BASE, 0x5000); + if (jtag_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + return iRet; + } + WMT_PLAT_PR_INFO("jtag_addr1 = 0x%p\n", jtag_addr1); + + JTAG1_REG_WRITE(0x100053c4, 0x11111100); + JTAG1_REG_WRITE(0x100053d4, 0x00111111); + + /*Enable IES of all pins */ + JTAG1_REG_WRITE(0x10002014, 0x00000003); + JTAG1_REG_WRITE(0x10005334, 0x55000000); + JTAG1_REG_WRITE(0x10005344, 0x00555555); + JTAG1_REG_WRITE(0x10005008, 0xc0000000); + JTAG1_REG_WRITE(0x10005018, 0x0000000d); + JTAG1_REG_WRITE(0x10005014, 0x00000032); + JTAG1_REG_WRITE(0x100020a4, 0x000000ff); + JTAG1_REG_WRITE(0x100020d4, 0x000000b4); + JTAG1_REG_WRITE(0x100020d8, 0x0000004b); + + WMT_PLAT_PR_INFO("WCN jtag set for mcu start...\n"); + kal_int32 iRet = 0; + kal_uint32 tmp = 0; + kal_int32 addr = 0; + kal_int32 remap_addr1 = 0; + kal_int32 remap_addr2 = 0; + + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + return -1; + } + + remap_addr2 = ioremap(JTAG_ADDR2_BASE, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + return -1; + } + + /*Pinmux setting for MT6625 I/F */ + addr = remap_addr1 + 0x03C0; + tmp = DRV_Reg32(addr); + tmp = tmp & 0xff; + tmp = tmp | 0x11111100; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + addr = remap_addr1 + 0x03D0; + tmp = DRV_Reg32(addr); + tmp = tmp & 0xff000000; + tmp = tmp | 0x00111111; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*AP GPIO Setting 1 <default use> */ + /*Enable IES */ + /* addr = 0x10002014; */ + addr = remap_addr2 + 0x0014; + tmp = 0x00000003; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + /*GPIO mode setting */ + /* addr = 0x10005334; */ + addr = remap_addr1 + 0x0334; + tmp = 0x55000000; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005344; */ + addr = remap_addr1 + 0x0344; + tmp = 0x00555555; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + /*GPIO direction control */ + /* addr = 0x10005008; */ + addr = remap_addr1 + 0x0008; + tmp = 0xc0000000; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005018; */ + addr = remap_addr1 + 0x0018; + tmp = 0x0000000d; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005014; */ + addr = remap_addr1 + 0x0014; + tmp = 0x00000032; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*PULL Enable */ + /* addr = 0x100020a4; */ + addr = remap_addr2 + 0x00a4; + tmp = 0x000000ff; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*PULL select enable */ + /* addr = 0x100020d4; */ + addr = remap_addr2 + 0x00d4; + tmp = 0x000000b4; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x100020d8; */ + addr = remap_addr2 + 0x00d8; + tmp = 0x0000004b; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); +#endif + } +#endif + return 0; +} + +UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en) +{ + WMT_PLAT_PR_INFO("%s jtag set for MCU\n", en ? "enable" : "disable"); + gJtagCtrl = en; + return 0; +} + +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_CLOCK_BUF_CTRL + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, enable); +#endif + return 0; +} + +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable) +{ +#ifdef CONFIG_OF /*use DT */ + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE((conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET), + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) | + CONSYS_CPU_SW_RST_BIT | CONSYS_CPU_SW_RST_CTRL_KEY); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88 (key)" */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_CPU_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + } +#else + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE(CONSYS_CPU_SW_RST_REG, + (CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG) | CONSYS_CPU_SW_RST_BIT | + CONSYS_CPU_SW_RST_CTRL_KEY)); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88(key)" */ + CONSYS_REG_WRITE(CONSYS_CPU_SW_RST_REG, + (CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG) & ~CONSYS_CPU_SW_RST_BIT) | + CONSYS_CPU_SW_RST_CTRL_KEY); + } +#endif +} + +static VOID consys_hw_spm_clk_gating_enable(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + /*turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE((conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET), CONSYS_PWRON_CONFG_EN_VALUE); +#else + /*turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE(CONSYS_PWRON_CONFG_EN_REG, CONSYS_PWRON_CONFG_EN_VALUE); +#endif +} + +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + INT32 iRet = -1; +#endif + + if (enable) { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE +#if defined(CONFIG_MTK_CLKMGR) + iRet = conn_power_on(); /* consult clkmgr owner. */ + if (iRet) + WMT_PLAT_PR_ERR("conn_power_on fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("conn_power_on ok\n"); +#else + iRet = clk_prepare_enable(clk_scp_conn_main); + if (iRet) + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_scp_conn_main) fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_scp_conn_main) ok\n"); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + +#else + +#ifdef CONFIG_OF /*use DT */ + /*2.write conn_top1_pwr_on=1, power on conn_top1 0x10006280 [2] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_BIT); + /*3.read conn_top1_pwr_on_ack =1, power on ack ready 0x1000660C [1] */ + while (0 == (CONSYS_PWR_ON_ACK_BIT & CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET))) + NULL; + /*5.write conn_top1_pwr_on_s=1, power on conn_top1 0x10006280 [3] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_S_BIT); + /*6.write conn_clk_dis=0, enable connsys clock 0x10006280 [4] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_CLK_CTRL_BIT); + /*7.wait 1us */ + udelay(1); + /*8.read conn_top1_pwr_on_ack_s =1, power on ack ready 0x10006610 [1] */ + while (0 == (CONSYS_PWR_CONN_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET))) + NULL; + /*9.release connsys ISO, conn_top1_iso_en=0 0x10006280 [1] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_ISO_S_BIT); + /*10.release SW reset of connsys, conn_ap_sw_rst_b=1 0x10006280[0] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_RST_BIT); + /*disable AXI BUS protect */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) & + ~CONSYS_PROT_MASK); + while (CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_STA1_OFFSET) & CONSYS_PROT_MASK) + NULL; +#else + /*2.write conn_top1_pwr_on=1, power on conn_top1 0x10006280 [2] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ON_BIT); + /*3.read conn_top1_pwr_on_ack =1, power on ack ready 0x1000660C [1] */ + while (0 == (CONSYS_PWR_ON_ACK_BIT & CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_REG))) + NULL; + /*5.write conn_top1_pwr_on_s=1, power on conn_top1 0x10006280 [3] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ON_S_BIT); + /*6.write conn_clk_dis=0, enable connsys clock 0x10006280 [4] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_CLK_CTRL_BIT); + /*7.wait 1us */ + udelay(1); + /*8.read conn_top1_pwr_on_ack_s =1, power on ack ready 0x10006610 [1] */ + while (0 == (CONSYS_PWR_CONN_ACK_S_BIT & CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_S_REG))) + NULL; + /*9.release connsys ISO, conn_top1_iso_en=0 0x10006280 [1] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_SPM_PWR_ISO_S_BIT); + /*10.release SW reset of connsys, conn_ap_sw_rst_b=1 0x10006280[0] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_RST_BIT); + /*disable AXI BUS protect */ + CONSYS_REG_WRITE(CONSYS_TOPAXI_PROT_EN, CONSYS_REG_READ(CONSYS_TOPAXI_PROT_EN) & ~CONSYS_PROT_MASK); + while (CONSYS_REG_READ(CONSYS_TOPAXI_PROT_STA1) & CONSYS_PROT_MASK) + NULL; +#endif /* CONFIG_OF */ +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } else { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE +#if defined(CONFIG_MTK_CLKMGR) + /*power off connsys by API (MT6582, MT6572 are different) API: conn_power_off() */ + iRet = conn_power_off(); /* consult clkmgr owner */ + if (iRet) + WMT_PLAT_PR_ERR("conn_power_off fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("conn_power_off ok\n"); +#else + clk_disable_unprepare(clk_scp_conn_main); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_scp_conn_main) calling\n"); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + +#else + +#ifdef CONFIG_OF /*use DT */ + { + INT32 count = 0; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) | + CONSYS_PROT_MASK); + while ((CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_STA1_OFFSET) & + CONSYS_PROT_MASK) != CONSYS_PROT_MASK) { + count++; + if (count > 1000) + break; + } + } + /*release connsys ISO, conn_top1_iso_en=1 0x10006280 [1] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ISO_S_BIT); + /*assert SW reset of connsys, conn_ap_sw_rst_b=0 0x10006280[0] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x10006280 [4] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x10006280 [3:2] 2'b00 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#else + { + INT32 count = 0; + + CONSYS_REG_WRITE(CONSYS_TOPAXI_PROT_EN, + CONSYS_REG_READ(CONSYS_TOPAXI_PROT_EN) | CONSYS_PROT_MASK); + while ((CONSYS_REG_READ(CONSYS_TOPAXI_PROT_STA1) & CONSYS_PROT_MASK) != CONSYS_PROT_MASK) { + count++; + if (count > 1000) + break; + } + + } + /*release connsys ISO, conn_top1_iso_en=1 0x10006280 [1] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ISO_S_BIT); + /*assert SW reset of connsys, conn_ap_sw_rst_b=0 0x10006280[0] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x10006280 [4] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x10006280 [3:2] 2'b00 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#endif /* CONFIG_OF */ +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } + +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + return iRet; +#else + return 0; +#endif +} + +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_AHB_CLK_MAGEMENT + + if (enable) { +#if defined(CONFIG_MTK_CLKMGR) + enable_clock(MT_CG_INFRA_CONNMCU_BUS, "WCN_MOD"); + WMT_PLAT_PR_DBG("enable MT_CG_INFRA_CONNMCU_BUS CLK\n"); +#else + INT32 iRet = -1; + + iRet = clk_prepare_enable(clk_infra_conn_main); + if (iRet) + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_infra_conn_main) fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("[CCF]enable clk_infra_conn_main\n"); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + } else { +#if defined(CONFIG_MTK_CLKMGR) + disable_clock(MT_CG_INFRA_CONNMCU_BUS, "WMT_MOD"); +#else + clk_disable_unprepare(clk_infra_conn_main); + WMT_PLAT_PR_DBG("[CCF] clk_disable_unprepare(clk_infra_conn_main) calling\n"); +#endif /* defined(CONFIG_MTK_CLKMGR) */ + } +#endif + return 0; +} + +static INT32 polling_consys_chipid(VOID) +{ + UINT32 retry = 10; + UINT32 consysHwChipId = 0; + +#ifdef CONFIG_OF /*use DT */ + /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ + while (retry-- > 0) { + consysHwChipId = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CHIP_ID_OFFSET); + if ((consysHwChipId == 0x0321) || (consysHwChipId == 0x0335) || (consysHwChipId == 0x0337)) { + WMT_PLAT_PR_INFO("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + msleep(20); + } + + if ((0 == retry) || (0 == consysHwChipId)) { + WMT_PLAT_PR_ERR("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + WMT_PLAT_PR_INFO("reg dump:CONSYS_CPU_SW_RST_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_S_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_TOP1_PWR_CTRL_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET)); + } +#else + /*12.poll CONNSYS CHIP ID until 6752 is returned 0x18070008 32'h6752 */ + while (retry-- > 0) { + WMT_PLAT_PR_DBG("CONSYS_CHIP_ID_REG(0x%08x)", CONSYS_REG_READ(CONSYS_CHIP_ID_REG)); + consysHwChipId = CONSYS_REG_READ(CONSYS_CHIP_ID_REG); + if ((consysHwChipId == 0x0321) || (consysHwChipId == 0x0335) || (consysHwChipId == 0x0337)) { + WMT_PLAT_PR_INFO("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + msleep(20); + } + + if ((0 == retry) || (0 == consysHwChipId)) { + WMT_PLAT_PR_ERR("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + WMT_PLAT_PR_INFO("reg dump:CONSYS_CPU_SW_RST_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_S_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_S_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_TOP1_PWR_CTRL_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG)); + } +#endif + return 0; +} + +static VOID consys_acr_reg_setting(VOID) +{ + /* + *14.write 1 to conn_mcu_confg ACR[1] if real speed MBIST + *(default write "1") ACR 0x18070110[18] 1'b1 + *if this bit is 0, HW will do memory auto test under low CPU frequence (26M Hz) + *if this bit is 0, HW will do memory auto test under high CPU frequence(138M Hz) + *inclulding low CPU frequence + */ +#ifdef CONFIG_OF /*use DT */ + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET, + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET) | + CONSYS_MCU_CFG_ACR_MBIST_BIT); +#else + CONSYS_REG_WRITE(CONSYS_MCU_CFG_ACR_REG, + CONSYS_REG_READ(CONSYS_MCU_CFG_ACR_REG) | CONSYS_MCU_CFG_ACR_MBIST_BIT); +#endif +} + +static VOID consys_afe_reg_setting(VOID) +{ +#if 0 + /*15.default no need,update ANA_WBG(AFE) CR if needed, CONSYS_AFE_REG */ + CONSYS_REG_WRITE(CONSYS_AFE_REG_DIG_RCK_01, CONSYS_AFE_REG_DIG_RCK_01_VALUE); + CONSYS_REG_WRITE(CONSYS_AFE_REG_WBG_PLL_02, CONSYS_AFE_REG_WBG_PLL_02_VALUE); + CONSYS_REG_WRITE(CONSYS_AFE_REG_WBG_WB_TX_01, CONSYS_AFE_REG_WBG_WB_TX_01_VALUE); +#endif +} + +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*need PMIC driver provide new API protocol */ + /*1.AP power on VCN_1V8 LDO (with PMIC_WRAP API) VCN_1V8 */ + KERNEL_pmic_set_register_value(PMIC_RG_VCN18_ON_CTRL, 0); + /* VOL_DEFAULT, VOL_1200, VOL_1300, VOL_1500, VOL_1800... */ +#if defined(CONFIG_MTK_PMIC_LEGACY) + hwPowerOn(MT6328_POWER_LDO_VCN18, VOL_1800, "wcn_drv"); +#else + if (reg_VCN18) { + regulator_set_voltage(reg_VCN18, VOL_1800, VOL_1800); + if (regulator_enable(reg_VCN18)) + WMT_PLAT_PR_ERR("enable VCN18 fail\n"); + else + WMT_PLAT_PR_DBG("enable VCN18 ok\n"); + } +#endif + } else { + /*AP power off MT6625L VCN_1V8 LDO */ + KERNEL_pmic_set_register_value(PMIC_RG_VCN18_ON_CTRL, 0); +#if defined(CONFIG_MTK_PMIC_LEGACY) + hwPowerDown(MT6328_POWER_LDO_VCN18, "wcn_drv"); +#else + if (reg_VCN18) { + if (regulator_disable(reg_VCN18)) + WMT_PLAT_PR_ERR("disable VCN_1V8 fail!\n"); + else + WMT_PLAT_PR_DBG("disable VCN_1V8 ok\n"); + } +#endif + } +#endif + return 0; +} + +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*2.1.switch VCN28 to HW control mode (with PMIC_WRAP API) */ + KERNEL_pmic_set_register_value(PMIC_RG_VCN28_ON_CTRL, 1); + } else + KERNEL_pmic_set_register_value(PMIC_RG_VCN28_ON_CTRL, 0); +#endif +} + +static INT32 consys_hw_vcn28_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*in co-clock mode,need to turn on vcn28 when fm on */ +#if defined(CONFIG_MTK_PMIC_LEGACY) + hwPowerOn(MT6328_POWER_LDO_VCN28, VOL_2800, "wcn_drv"); +#else + if (reg_VCN28) { + regulator_set_voltage(reg_VCN28, VOL_2800, VOL_2800); + if (regulator_enable(reg_VCN28)) + WMT_PLAT_PR_ERR("enable VCN_2V8 fail!\n"); + else + WMT_PLAT_PR_DBG("enable VCN_2V8 ok\n"); + } +#endif + WMT_PLAT_PR_INFO("turn on vcn28 for fm/gps usage in co-clock mode\n"); + } else { + /*in co-clock mode,need to turn off vcn28 when fm off */ +#if defined(CONFIG_MTK_PMIC_LEGACY) + hwPowerDown(MT6328_POWER_LDO_VCN28, "wcn_drv"); +#else + if (reg_VCN28) { + if (regulator_disable(reg_VCN28)) + WMT_PLAT_PR_ERR("disable VCN_2V8 fail!\n"); + else + WMT_PLAT_PR_DBG("disable VCN_2V8 ok\n"); + } +#endif + WMT_PLAT_PR_INFO("turn off vcn28 for fm/gps usage in co-clock mode\n"); + } +#endif + return 0; +} + +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + /* spin_lock_irqsave(&gBtWifiV33.lock,gBtWifiV33.flags); */ + if (enable) { + if (1 == gBtWifiV33.counter) { + gBtWifiV33.counter++; + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else if (2 == gBtWifiV33.counter) { + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else { +#if CONSYS_PMIC_CTRL_ENABLE + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + hwPowerOn(MT6325_POWER_LDO_VCN33, VOL_3300, "wcn_drv"); + mt6325_upmu_set_rg_vcn33_on_ctrl(1); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 on\n"); + gBtWifiV33.counter++; + } + + } else { + if (1 == gBtWifiV33.counter) { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + mt6325_upmu_set_rg_vcn33_on_ctrl(0); + hwPowerDown(MT6325_POWER_LDO_VCN33, "wcn_drv"); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 off\n"); + gBtWifiV33.counter--; + } else if (2 == gBtWifiV33.counter) { + gBtWifiV33.counter--; + WMT_PLAT_PR_DBG("V33 no need disabled,counter(%d)\n", gBtWifiV33.counter); + } else { + WMT_PLAT_PR_DBG("V33 has been disabled,counter(%d)\n", gBtWifiV33.counter); + } + + } + /* spin_unlock_irqrestore(&gBtWifiV33.lock,gBtWifiV33.flags); */ +#else + if (enable) { + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ +#if defined(CONFIG_MTK_PMIC_LEGACY) + hwPowerOn(MT6328_POWER_LDO_VCN33_BT, VOL_3300, "wcn_drv"); +#else + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, VOL_3300, VOL_3300); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } +#endif + KERNEL_pmic_set_register_value(PMIC_RG_VCN33_ON_CTRL_BT, 1); + +#endif + WMT_PLAT_PR_INFO("WMT do BT PMIC on\n"); + } else { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + KERNEL_pmic_set_register_value(PMIC_RG_VCN33_ON_CTRL_BT, 0); +#if defined(CONFIG_MTK_PMIC_LEGACY) + hwPowerDown(MT6328_POWER_LDO_VCN33_BT, "wcn_drv"); +#else + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); +#endif +#endif + WMT_PLAT_PR_INFO("WMT do BT PMIC off\n"); + } +#endif + return 0; +} + +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + mtk_wcn_consys_hw_bt_paldo_ctrl(enable); +#else + if (enable) { + /*do WIFI PMIC on,depenency PMIC API ready */ + /*switch WIFI PALDO control from SW mode to HW mode:0x418[14]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE +#if defined(CONFIG_MTK_PMIC_LEGACY) + hwPowerOn(MT6328_POWER_LDO_VCN33_WIFI, VOL_3300, "wcn_drv"); +#else + if (reg_VCN33_WIFI) { + regulator_set_voltage(reg_VCN33_WIFI, VOL_3300, VOL_3300); + if (regulator_enable(reg_VCN33_WIFI)) + WMT_PLAT_PR_ERR("WMT do WIFI PMIC on fail!\n"); + } +#endif + KERNEL_pmic_set_register_value(PMIC_RG_VCN33_ON_CTRL_WIFI, 1); +#endif + WMT_PLAT_PR_INFO("WMT do WIFI PMIC on\n"); + } else { + /*do WIFI PMIC off */ + /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + KERNEL_pmic_set_register_value(PMIC_RG_VCN33_ON_CTRL_WIFI, 0); +#if defined(CONFIG_MTK_PMIC_LEGACY) + hwPowerDown(MT6328_POWER_LDO_VCN33_WIFI, "wcn_drv"); +#else + if (reg_VCN33_WIFI) + regulator_disable(reg_VCN33_WIFI); +#endif + +#endif + WMT_PLAT_PR_INFO("WMT do WIFI PMIC off\n"); + } + +#endif + return 0; +} + +static INT32 consys_emi_mpu_set_region_protection(VOID) +{ +#if CONSYS_EMI_MPU_SETTING + /*set MPU for EMI share Memory */ + WMT_PLAT_PR_INFO("setting MPU for EMI share memory\n"); +#if defined(CONFIG_ARCH_MT6735) + emi_mpu_set_region_protection(gConEmiPhyBase + SZ_1M / 2, + gConEmiPhyBase + gConEmiSize - 1, + 13, + SET_ACCESS_PERMISSON(FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, NO_PROTECTION, FORBIDDEN, NO_PROTECTION)); +#elif defined(CONFIG_ARCH_MT6735M) + emi_mpu_set_region_protection(gConEmiPhyBase, + gConEmiPhyBase + SZ_1M - 1, + 6, + SET_ACCESS_PERMISSON(FORBIDDEN, NO_PROTECTION, FORBIDDEN, + NO_PROTECTION)); +#elif defined(CONFIG_ARCH_MT6753) + emi_mpu_set_region_protection(gConEmiPhyBase + SZ_1M / 2, + gConEmiPhyBase + SZ_1M - 1, + 13, + SET_ACCESS_PERMISSON(FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, FORBIDDEN, NO_PROTECTION, FORBIDDEN, NO_PROTECTION)); + +#else + WMT_PLAT_PR_WARN("not define platform config\n"); +#endif +#endif + return 0; +} + +static UINT32 consys_emi_set_remapping_reg(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + UINT32 addrPhy = 0; + + /*consys to ap emi remapping register:10000320, cal remapping address */ + addrPhy = (gConEmiPhyBase & 0xFFF00000) >> 20; + + /*enable consys to ap emi remapping bit12 */ + addrPhy = addrPhy | 0x1000; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); + + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); +#endif + return 0; +} + +static INT32 bt_wifi_share_v33_spin_lock_init(VOID) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + gBtWifiV33.counter = 0; + spin_lock_init(&gBtWifiV33.lock); +#endif + return 0; +} + +static INT32 consys_clk_get_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ +#if !defined(CONFIG_MTK_CLKMGR) + clk_scp_conn_main = devm_clk_get(&pdev->dev, "conn"); + if (IS_ERR(clk_scp_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_scp_conn_main clock.\n"); + return PTR_ERR(clk_scp_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_scp_conn_main=%p\n", clk_scp_conn_main); + + clk_infra_conn_main = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(clk_infra_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_infra_conn_main clock.\n"); + return PTR_ERR(clk_infra_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_infra_conn_main=%p\n", clk_infra_conn_main); +#endif /* !defined(CONFIG_MTK_CLKMGR) */ +#endif + return 0; +} + +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ +#if CONSYS_PMIC_CTRL_ENABLE +#if !defined(CONFIG_MTK_PMIC_LEGACY) + reg_VCN18 = regulator_get(&pdev->dev, "vcn18"); + if (!reg_VCN18) + WMT_PLAT_PR_ERR("Regulator_get VCN_1V8 fail\n"); + reg_VCN28 = regulator_get(&pdev->dev, "vcn28"); + if (!reg_VCN28) + WMT_PLAT_PR_ERR("Regulator_get VCN_2V8 fail\n"); + reg_VCN33_BT = regulator_get(&pdev->dev, "vcn33_bt"); + if (!reg_VCN33_BT) + WMT_PLAT_PR_ERR("Regulator_get VCN33_BT fail\n"); + reg_VCN33_WIFI = regulator_get(&pdev->dev, "vcn33_wifi"); + if (!reg_VCN33_WIFI) + WMT_PLAT_PR_ERR("Regulator_get VCN33_WIFI fail\n"); +#endif +#endif +#endif + return 0; +} + +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, INT32 *irq_num, UINT32 *irq_flag) +{ +#ifdef CONFIG_OF /*use DT */ + struct device_node *node; + UINT32 irq_info[3] = { 0, 0, 0 }; + + INT32 iret = -1; + + node = pdev->dev.of_node; + if (node) { + *irq_num = irq_of_parse_and_map(node, 0); + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + WMT_PLAT_PR_ERR("get irq flags from DTS fail!!\n"); + return iret; + } + *irq_flag = irq_info[2]; + WMT_PLAT_PR_INFO("get irq id(%d) and irq trigger flag(%d) from DT\n", *irq_num, + *irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iret; + } +#endif + return 0; +} + +static INT32 consys_read_reg_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ + INT32 iRet = -1; + struct device_node *node = NULL; + + node = pdev->dev.of_node; + if (node) { + /* registers base address */ + conn_reg.mcu_base = (SIZE_T) of_iomap(node, 0); + WMT_PLAT_PR_DBG("Get mcu register base(0x%zx)\n", conn_reg.mcu_base); + conn_reg.ap_rgu_base = (SIZE_T) of_iomap(node, 1); + WMT_PLAT_PR_DBG("Get ap_rgu register base(0x%zx)\n", conn_reg.ap_rgu_base); + conn_reg.topckgen_base = (SIZE_T) of_iomap(node, 2); + WMT_PLAT_PR_DBG("Get topckgen register base(0x%zx)\n", conn_reg.topckgen_base); + conn_reg.spm_base = (SIZE_T) of_iomap(node, 3); + WMT_PLAT_PR_DBG("Get spm register base(0x%zx)\n", conn_reg.spm_base); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iRet; + } +#endif + return 0; +} + +static VOID force_trigger_assert_debug_pin(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + usleep_range(64, 96); + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); +#endif +} + +static UINT32 consys_read_cpupcr(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CPUPCR_OFFSET); +#endif +} + +static UINT32 consys_soc_chipid_get(VOID) +{ + return PLATFORM_SOC_CHIP; +} + +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID) +{ + return &mtk_wcn_emi_addr_info; +} + +P_WMT_CONSYS_IC_OPS mtk_wcn_get_consys_ic_ops(VOID) +{ + return &consys_ic_ops; +} + +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable) +{ + if (enable) { + *addr = ioremap(gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET, CONSYS_EMI_MEM_SIZE); + if (*addr) { + WMT_PLAT_PR_INFO("COREDUMP EMI mapping OK virtual(0x%p) physical(0x%x)\n", + *addr, (UINT32) gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET); + memset_io(*addr, 0, CONSYS_EMI_MEM_SIZE); + } else { + WMT_PLAT_PR_ERR("EMI mapping fail\n"); + return -1; + } + } else { + if (*addr) { + iounmap(*addr); + *addr = NULL; + } + } + return 0; +} + +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr) +{ + if (!addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + WMT_PLAT_PR_INFO("Reset EMI(0xF0080000 ~ 0xF0080400) and (0xF0088400 ~ 0xF0090400)\n"); + /* reset 0xF0080000 ~ 0xF0080400 (1K) */ + memset_io(addr, 0, 0x400); + /* reset 0xF0088400 ~ 0xF0090400 (32K) */ + memset_io(addr + CONSYS_EMI_PAGED_DUMP_OFFSET, 0, 0x8000); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6739.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6739.c new file mode 100644 index 00000000000000..435c4e71833144 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6739.c @@ -0,0 +1,1172 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <connectivity_build_in_adapter.h> + +#if defined(CONFIG_MTK_CLKMGR) +#include <mtk_clkmgr.h> +#else +#include <linux/clk.h> +#endif /* defined(CONFIG_MTK_LEGACY) */ +#include <linux/delay.h> +#include <linux/memblock.h> +#include <linux/platform_device.h> +#include "osal_typedef.h" +#include "mt6739.h" +#include "mtk_wcn_consys_hw.h" + +#if CONSYS_EMI_MPU_SETTING +#include <mach/emi_mpu.h> +#endif + +#if CONSYS_PMIC_CTRL_ENABLE +#include <upmu_common.h> +#include <linux/regulator/consumer.h> +#endif + +#ifdef CONFIG_MTK_HIBERNATION +#include <mtk_hibernate_dpm.h> +#endif + +#include <linux/of_reserved_mem.h> + +#if CONSYS_CLOCK_BUF_CTRL +#include <mtk_clkbuf_ctl.h> +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable); +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable); +static VOID consys_hw_spm_clk_gating_enable(VOID); +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable); +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable); +static INT32 polling_consys_chipid(VOID); +static VOID consys_acr_reg_setting(VOID); +static VOID consys_afe_reg_setting(VOID); +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable); +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable); +static INT32 consys_hw_vcn28_ctrl(UINT32 enable); +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable); +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable); +static UINT32 consys_soc_chipid_get(VOID); +static INT32 consys_emi_mpu_set_region_protection(VOID); +static UINT32 consys_emi_set_remapping_reg(VOID); +static INT32 bt_wifi_share_v33_spin_lock_init(VOID); +static INT32 consys_clk_get_from_dts(struct platform_device *pdev); +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev); +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag); +static INT32 consys_read_reg_from_dts(struct platform_device *pdev); +static UINT32 consys_read_cpupcr(VOID); +static VOID force_trigger_assert_debug_pin(VOID); +static INT32 consys_co_clock_type(VOID); +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID); +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable); +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status gBtWifiV33; +#endif + +/* CCF part */ +#if !defined(CONFIG_MTK_CLKMGR) +struct clk *clk_scp_conn_main; /*ctrl conn_power_on/off */ +/* struct clk *clk_infra_conn_main; */ /*ctrl infra_connmcu_bus clk */ +#endif /* !defined(CONFIG_MTK_LEGACY) */ + + +/* PMIC part */ +#if CONSYS_PMIC_CTRL_ENABLE +#if !defined(CONFIG_MTK_LEGACY) +struct regulator *reg_VCN18; +struct regulator *reg_VCN28; +struct regulator *reg_VCN33_BT; +struct regulator *reg_VCN33_WIFI; +#endif +#endif + +EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { + .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, + .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, + .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, + .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, + .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, + .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, + .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, + .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, + .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, + .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, + .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, + .emi_apmem_ctrl_chip_page_dump_num = EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM, + .emi_apmem_ctrl_assert_flag = EXP_APMEM_CTRL_ASSERT_FLAG, +}; + +CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { + .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, + .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, + .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, + .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, + .p_ecso = &mtk_wcn_emi_state_off, + .emi_core_dump_offset = CONSYS_EMI_COREDUMP_OFFSET, +}; + +WMT_CONSYS_IC_OPS consys_ic_ops = { + .consys_ic_clock_buffer_ctrl = consys_clock_buffer_ctrl, + .consys_ic_hw_reset_bit_set = consys_hw_reset_bit_set, + .consys_ic_hw_spm_clk_gating_enable = consys_hw_spm_clk_gating_enable, + .consys_ic_hw_power_ctrl = consys_hw_power_ctrl, + .consys_ic_ahb_clock_ctrl = consys_ahb_clock_ctrl, + .polling_consys_ic_chipid = polling_consys_chipid, + .consys_ic_acr_reg_setting = consys_acr_reg_setting, + .consys_ic_afe_reg_setting = consys_afe_reg_setting, + .consys_ic_hw_vcn18_ctrl = consys_hw_vcn18_ctrl, + .consys_ic_vcn28_hw_mode_ctrl = consys_vcn28_hw_mode_ctrl, + .consys_ic_hw_vcn28_ctrl = consys_hw_vcn28_ctrl, + .consys_ic_hw_wifi_vcn33_ctrl = consys_hw_wifi_vcn33_ctrl, + .consys_ic_hw_bt_vcn33_ctrl = consys_hw_bt_vcn33_ctrl, + .consys_ic_soc_chipid_get = consys_soc_chipid_get, + .consys_ic_emi_mpu_set_region_protection = consys_emi_mpu_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .ic_bt_wifi_share_v33_spin_lock_init = bt_wifi_share_v33_spin_lock_init, + .consys_ic_clk_get_from_dts = consys_clk_get_from_dts, + .consys_ic_pmic_get_from_dts = consys_pmic_get_from_dts, + .consys_ic_read_irq_info_from_dts = consys_read_irq_info_from_dts, + .consys_ic_read_reg_from_dts = consys_read_reg_from_dts, + .consys_ic_read_cpupcr = consys_read_cpupcr, + .ic_force_trigger_assert_debug_pin = force_trigger_assert_debug_pin, + .consys_ic_co_clock_type = consys_co_clock_type, + .consys_ic_soc_get_emi_phy_add = consys_soc_get_emi_phy_add, + .consys_ic_emi_coredump_remapping = consys_emi_coredump_remapping, + .consys_ic_reset_emi_coredump = consys_reset_emi_coredump, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +UINT32 gJtagCtrl; +#if CONSYS_ENALBE_SET_JTAG +#define JTAG_ADDR1_BASE 0x10002000 +PINT8 jtag_addr1 = (PINT8)JTAG_ADDR1_BASE; +#define JTAG1_REG_WRITE(addr, value) \ + writel(value, ((PUINT32)(jtag_addr1+(addr-JTAG_ADDR1_BASE)))) +#define JTAG1_REG_READ(addr) \ + readl(((PUINT32)(jtag_addr1+(addr-JTAG_ADDR1_BASE)))) +#endif + +INT32 mtk_wcn_consys_jtag_set_for_mcu(VOID) +{ +#if CONSYS_ENALBE_SET_JTAG + + if (gJtagCtrl) { +#if 0 + INT32 iRet = -1; + + WMT_PLAT_PR_INFO("WCN jtag_set_for_mcu start...\n"); + jtag_addr1 = ioremap(JTAG_ADDR1_BASE, 0x5000); + if (jtag_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + return iRet; + } + WMT_PLAT_PR_INFO("jtag_addr1 = 0x%p\n", jtag_addr1); + + JTAG1_REG_WRITE(0x100053c4, 0x11111100); + JTAG1_REG_WRITE(0x100053d4, 0x00111111); + + /*Enable IES of all pins */ + JTAG1_REG_WRITE(0x10002014, 0x00000003); + JTAG1_REG_WRITE(0x10005334, 0x55000000); + JTAG1_REG_WRITE(0x10005344, 0x00555555); + JTAG1_REG_WRITE(0x10005008, 0xc0000000); + JTAG1_REG_WRITE(0x10005018, 0x0000000d); + JTAG1_REG_WRITE(0x10005014, 0x00000032); + JTAG1_REG_WRITE(0x100020a4, 0x000000ff); + JTAG1_REG_WRITE(0x100020d4, 0x000000b4); + + JTAG1_REG_WRITE(0x100020d8, 0x0000004b); + + WMT_PLAT_PR_INFO("WCN jtag set for mcu start...\n"); + kal_uint32 tmp = 0; + kal_int32 addr = 0; + kal_int32 remap_addr1 = 0; + kal_int32 remap_addr2 = 0; + + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + return -1; + } + + remap_addr2 = ioremap(JTAG_ADDR2_BASE, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + return -1; + } + + /*Pinmux setting for MT6625 I/F */ + addr = remap_addr1 + 0x03C0; + tmp = DRV_Reg32(addr); + tmp = tmp & 0xff; + tmp = tmp | 0x11111100; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + addr = remap_addr1 + 0x03D0; + tmp = DRV_Reg32(addr); + tmp = tmp & 0xff000000; + tmp = tmp | 0x00111111; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*AP GPIO Setting 1 <default use> */ + /*Enable IES */ + /* addr = 0x10002014; */ + addr = remap_addr2 + 0x0014; + tmp = 0x00000003; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + /*GPIO mode setting */ + /* addr = 0x10005334; */ + addr = remap_addr1 + 0x0334; + tmp = 0x55000000; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005344; */ + addr = remap_addr1 + 0x0344; + tmp = 0x00555555; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + /*GPIO direction control */ + /* addr = 0x10005008; */ + addr = remap_addr1 + 0x0008; + tmp = 0xc0000000; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005018; */ + addr = remap_addr1 + 0x0018; + tmp = 0x0000000d; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005014; */ + addr = remap_addr1 + 0x0014; + tmp = 0x00000032; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*PULL Enable */ + /* addr = 0x100020a4; */ + addr = remap_addr2 + 0x00a4; + tmp = 0x000000ff; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*PULL select enable */ + /* addr = 0x100020d4; */ + addr = remap_addr2 + 0x00d4; + tmp = 0x000000b4; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x100020d8; */ + addr = remap_addr2 + 0x00d8; + tmp = 0x0000004b; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); +#endif + } +#endif + return 0; +} + +UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en) +{ + WMT_PLAT_PR_INFO("%s jtag set for MCU\n", en ? "enable" : "disable"); + gJtagCtrl = en; + return 0; +} + +static INT32 consys_clk_get_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ +#if !defined(CONFIG_MTK_CLKMGR) + clk_scp_conn_main = devm_clk_get(&pdev->dev, "conn"); + if (IS_ERR(clk_scp_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_scp_conn_main clock.\n"); + return PTR_ERR(clk_scp_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_scp_conn_main=%p\n", clk_scp_conn_main); +#if 0 + clk_infra_conn_main = devm_clk_get(&pdev->dev, "infra-sys-conn-main"); + if (IS_ERR(clk_infra_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_infra_conn_main clock.\n"); + return PTR_ERR(clk_infra_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_infra_conn_main=%p\n", clk_infra_conn_main); +#endif + +#endif /* !defined(CONFIG_MTK_LEGACY) */ +#endif + return 0; +} + +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ +#if CONSYS_PMIC_CTRL_ENABLE +#if !defined(CONFIG_MTK_LEGACY) + reg_VCN18 = regulator_get(&pdev->dev, "vcn18"); + if (!reg_VCN18) + WMT_PLAT_PR_ERR("Regulator_get VCN_1V8 fail\n"); + reg_VCN28 = regulator_get(&pdev->dev, "vcn28"); + if (!reg_VCN28) + WMT_PLAT_PR_ERR("Regulator_get VCN_2V8 fail\n"); + reg_VCN33_BT = regulator_get(&pdev->dev, "vcn33_bt"); + if (!reg_VCN33_BT) + WMT_PLAT_PR_ERR("Regulator_get VCN33_BT fail\n"); + reg_VCN33_WIFI = regulator_get(&pdev->dev, "vcn33_wifi"); + if (!reg_VCN33_WIFI) + WMT_PLAT_PR_ERR("Regulator_get VCN33_WIFI fail\n"); +#endif +#endif +#endif + return 0; +} + +static INT32 consys_co_clock_type(VOID) +{ + UINT32 retval = 0; + UINT32 back_up = 0; + UINT32 co_clock_type = 0; + + /* co-clock auto detection:backup cw15,write cw15,read cw16,restore cw15, */ + KERNEL_pmic_read_interface(PMIC_DCXO_CW15, &retval, 0xFFFF, 0); + back_up = retval; + KERNEL_pmic_config_interface(PMIC_DCXO_CW15, PMIC_DCXO_CW15_VAL, 0xFFFF, 0); + KERNEL_pmic_read_interface(PMIC_DCXO_CW16, &retval, 0xFFFF, 0); + KERNEL_pmic_config_interface(PMIC_DCXO_CW15, back_up, 0xFFFF, 0); + if ((retval & AP_CONSYS_NOCO_CLOCK_BITA) || (retval & AP_CONSYS_NOCO_CLOCK_BITB)) { + co_clock_type = 0; + WMT_PLAT_PR_INFO("pmic_register_val = 0x%x, co_clock_type = %d,TCXO mode\n", retval, co_clock_type); + } else if ((retval & AP_CONSYS_CO_CLOCK_BITA) || (retval & AP_CONSYS_CO_CLOCK_BITB)) { + co_clock_type = 1; + WMT_PLAT_PR_INFO("pmic_register_val = 0x%x, co_clock_type = %d,co-TSX mode\n", retval, co_clock_type); + } + return co_clock_type; +} + +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_CLOCK_BUF_CTRL + if (enable == MTK_WCN_BOOL_TRUE) + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, 1); + else if (enable == MTK_WCN_BOOL_FALSE) + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, 0); +#endif + return 0; +} + +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable) +{ +#ifdef CONFIG_OF /*use DT */ + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE((conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET), + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) | + CONSYS_CPU_SW_RST_BIT | CONSYS_CPU_SW_RST_CTRL_KEY); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88 (key)" */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_CPU_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + } +#else + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE(CONSYS_CPU_SW_RST_REG, + (CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG) | CONSYS_CPU_SW_RST_BIT | + CONSYS_CPU_SW_RST_CTRL_KEY)); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88(key)" */ + CONSYS_REG_WRITE(CONSYS_CPU_SW_RST_REG, + (CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG) & ~CONSYS_CPU_SW_RST_BIT) | + CONSYS_CPU_SW_RST_CTRL_KEY); + } +#endif +} + +static VOID consys_hw_spm_clk_gating_enable(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + /*turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + /*CONSYS_REG_WRITE((conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET), CONSYS_PWRON_CONFG_EN_VALUE);*/ +#else + /*turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE(CONSYS_PWRON_CONFG_EN_REG, CONSYS_PWRON_CONFG_EN_VALUE); +#endif +} + +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + INT32 iRet = -1; +#endif + + if (enable) { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE +#if defined(CONFIG_MTK_CLKMGR) + iRet = conn_power_on(); /* consult clkmgr owner. */ + if (iRet) + WMT_PLAT_PR_ERR("conn_power_on fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("conn_power_on ok\n"); +#else + iRet = clk_prepare_enable(clk_scp_conn_main); + if (iRet) + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_scp_conn_main) fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_scp_conn_main) ok\n"); +#endif /* defined(CONFIG_MTK_LEGACY) */ + +#else + +#ifdef CONFIG_OF /*use DT */ + /*2.write conn_top1_pwr_on=1, power on conn_top1 0x1000632c [2] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_BIT); + /*3.read conn_top1_pwr_on_ack =1, power on ack ready 0x10006180 [1] */ + while (0 == (CONSYS_PWR_ON_ACK_BIT & CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET))) + NULL; + /*5.write conn_top1_pwr_on_s=1, power on conn_top1 0x1000632c [3] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_S_BIT); + /*6.write conn_clk_dis=0, enable connsys clock 0x1000632c [4] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_CLK_CTRL_BIT); + /*7.wait 1us */ + udelay(1); + /*8.read conn_top1_pwr_on_ack_s =1, power on ack ready 0x10006184 [1] */ + while (0 == (CONSYS_PWR_CONN_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET))) + NULL; + /*9.release connsys ISO, conn_top1_iso_en=0 0x1000632c [1] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_ISO_S_BIT); + /*10.release SW reset of connsys, conn_ap_sw_rst_b=1 0x1000632c[0] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_RST_BIT); + /*disable AXI BUS protect 0x10001220[13] [14] */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) & + ~CONSYS_PROT_MASK); + while (CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_STA1_OFFSET) & CONSYS_PROT_MASK) + NULL; +#else + /*2.write conn_top1_pwr_on=1, power on conn_top1 0x10006280 [2] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ON_BIT); + /*3.read conn_top1_pwr_on_ack =1, power on ack ready 0x1000660C [1] */ + while (0 == (CONSYS_PWR_ON_ACK_BIT & CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_REG))) + NULL; + /*5.write conn_top1_pwr_on_s=1, power on conn_top1 0x10006280 [3] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ON_S_BIT); + /*6.write conn_clk_dis=0, enable connsys clock 0x10006280 [4] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_CLK_CTRL_BIT); + /*7.wait 1us */ + udelay(1); + /*8.read conn_top1_pwr_on_ack_s =1, power on ack ready 0x10006610 [1] */ + while (0 == (CONSYS_PWR_CONN_ACK_S_BIT & CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_S_REG))) + NULL; + /*9.release connsys ISO, conn_top1_iso_en=0 0x10006280 [1] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_SPM_PWR_ISO_S_BIT); + /*10.release SW reset of connsys, conn_ap_sw_rst_b=1 0x10006280[0] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_RST_BIT); + /*disable AXI BUS protect */ + CONSYS_REG_WRITE(CONSYS_TOPAXI_PROT_EN, CONSYS_REG_READ(CONSYS_TOPAXI_PROT_EN) & ~CONSYS_PROT_MASK); + while (CONSYS_REG_READ(CONSYS_TOPAXI_PROT_STA1) & CONSYS_PROT_MASK) + NULL; +#endif /* CONFIG_OF */ +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } else { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE +#if defined(CONFIG_MTK_CLKMGR) + /*power off connsys by API (MT6582, MT6572 are different) API: conn_power_off() */ + iRet = conn_power_off(); /* consult clkmgr owner */ + if (iRet) + WMT_PLAT_PR_ERR("conn_power_off fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("conn_power_off ok\n"); +#else + clk_disable_unprepare(clk_scp_conn_main); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_scp_conn_main) calling\n"); +#endif /* defined(CONFIG_MTK_LEGACY) */ + +#else + +#ifdef CONFIG_OF /*use DT */ + { + INT32 count = 0; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) | + CONSYS_PROT_MASK); + while ((CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_STA1_OFFSET) & + CONSYS_PROT_MASK) != CONSYS_PROT_MASK) { + count++; + if (count > 1000) + break; + } + } + /*release connsys ISO, conn_top1_iso_en=1 0x1000632c [1] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ISO_S_BIT); + /*assert SW reset of connsys, conn_ap_sw_rst_b=0 0x1000632c[0] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x1000632c [4] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632c [3:2] 2'b00 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#else + { + INT32 count = 0; + + CONSYS_REG_WRITE(CONSYS_TOPAXI_PROT_EN, + CONSYS_REG_READ(CONSYS_TOPAXI_PROT_EN) | CONSYS_PROT_MASK); + while ((CONSYS_REG_READ(CONSYS_TOPAXI_PROT_STA1) & CONSYS_PROT_MASK) != CONSYS_PROT_MASK) { + count++; + if (count > 1000) + break; + } + + } + /*release connsys ISO, conn_top1_iso_en=1 0x1000632c [1] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ISO_S_BIT); + /*assert SW reset of connsys, conn_ap_sw_rst_b=0 0x1000632c[0] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x1000632c [4] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632c [3:2] 2'b00 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#endif /* CONFIG_OF */ +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } + +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + return iRet; +#else + return 0; +#endif +} + +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable) +{ + return 0; +} + +static INT32 polling_consys_chipid(VOID) +{ + UINT32 retry = 10; + UINT32 consysHwChipId = 0; + +#ifdef CONFIG_OF /*use DT */ + /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ + while (retry-- > 0) { + consysHwChipId = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CHIP_ID_OFFSET); + if (consysHwChipId == 0x0699) { + WMT_PLAT_PR_INFO("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + msleep(20); + } + + if ((retry == 0) || (consysHwChipId == 0)) { + WMT_PLAT_PR_ERR("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + WMT_PLAT_PR_INFO("reg dump:CONSYS_CPU_SW_RST_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_S_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_TOP1_PWR_CTRL_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET)); + } +#else + /*12.poll CONNSYS CHIP ID until 6739 is returned 0x18070008 32'h6739 */ + while (retry-- > 0) { + WMT_PLAT_PR_DBG("CONSYS_CHIP_ID_REG(0x%08x)", CONSYS_REG_READ(CONSYS_CHIP_ID_REG)); + consysHwChipId = CONSYS_REG_READ(CONSYS_CHIP_ID_REG); + if (consysHwChipId == 0x0699) { + WMT_PLAT_PR_INFO("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + msleep(20); + } + + if ((retry == 0) || (consysHwChipId == 0)) { + WMT_PLAT_PR_ERR("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + WMT_PLAT_PR_INFO("reg dump:CONSYS_CPU_SW_RST_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_S_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_S_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_TOP1_PWR_CTRL_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG)); + } +#endif + return 0; +} + +static VOID consys_acr_reg_setting(VOID) +{ + /* + *14.write 1 to conn_mcu_confg ACR[1] if real speed MBIST + *(default write "1") ACR 0x18070110[18] 1'b1 + *if this bit is 0, HW will do memory auto test under low CPU frequence (26M Hz) + *if this bit is 0, HW will do memory auto test under high CPU frequence(138M Hz) + *inclulding low CPU frequence + */ +#ifdef CONFIG_OF /*use DT */ + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET, + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET) | + CONSYS_MCU_CFG_ACR_MBIST_BIT); +#else + CONSYS_REG_WRITE(CONSYS_MCU_CFG_ACR_REG, + CONSYS_REG_READ(CONSYS_MCU_CFG_ACR_REG) | CONSYS_MCU_CFG_ACR_MBIST_BIT); +#endif +} + +static VOID consys_afe_reg_setting(VOID) +{ +#if CONSYS_AFE_REG_SETTING + UINT8 *consys_afe_reg_base = NULL; + UINT8 i = 0; + + /*15.default no need,update ANA_WBG(AFE) CR if needed, CONSYS_AFE_REG */ + consys_afe_reg_base = ioremap(CONSYS_AFE_REG_BASE, 0x100); + if (consys_afe_reg_base) { + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_REG_WBG_AFE_01_OFFSET, + CONSYS_AFE_REG_WBG_AFE_01_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_REG_WBG_PLL_03_OFFSET, + CONSYS_AFE_REG_WBG_PLL_03_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_REG_WBG_PLL_05_OFFSET, + CONSYS_AFE_REG_WBG_PLL_05_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_REG_WBG_WB_TX_01_OFFSET, + CONSYS_AFE_REG_WBG_WB_TX_01_VALUE); + + WMT_PLAT_PR_DBG("Dump AFE register\n"); + for (i = 0; i < 64; i++) { + WMT_PLAT_PR_DBG("reg:0x%08x|val:0x%08x\n", CONSYS_AFE_REG_BASE + 4*i, + CONSYS_REG_READ(consys_afe_reg_base + 4*i)); + } + iounmap(consys_afe_reg_base); + } else + WMT_PLAT_PR_ERR("AFE base(0x%x) ioremap fail!\n", CONSYS_AFE_REG_BASE); +#endif +} + +/* Wayne Chen - This function was copied from mt6759.c */ +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*need PMIC driver provide new API protocol */ + /*1.AP power on VCN_1V8 LDO (with PMIC_WRAP API) VCN_1V8 */ +#if defined(CONFIG_MTK_PMIC_CHIP_MT6357) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_SW_OP_EN, 1); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN18_ON_CTRL, 0); +#endif + /* VOL_DEFAULT, VOL_1200, VOL_1300, VOL_1500, VOL_1800... */ +#if defined(CONFIG_MTK_LEGACY) + hwPowerOn(MT6351_POWER_LDO_VCN18, VOL_1800 * 1000, "wcn_drv"); +#else + if (reg_VCN18) { + regulator_set_voltage(reg_VCN18, 1800000, 1800000); + if (regulator_enable(reg_VCN18)) + WMT_PLAT_PR_ERR("enable VCN18 fail\n"); + else + WMT_PLAT_PR_DBG("enable VCN18 ok\n"); + } +#endif + + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } + +#if defined(CONFIG_MTK_PMIC_CHIP_MT6357) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_BT, 1); +#endif + } else { +#if defined(CONFIG_MTK_PMIC_CHIP_MT6357) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_SW_OP_EN, 1); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_BT, 0); +#endif + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); + + /*AP power off MT6351L VCN_1V8 LDO */ +#if defined(CONFIG_MTK_PMIC_CHIP_MT6357) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_SW_OP_EN, 1); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN18_ON_CTRL, 0); +#endif +#if defined(CONFIG_MTK_LEGACY) + hwPowerDown(MT6351_POWER_LDO_VCN18, "wcn_drv"); +#else + if (reg_VCN18) { + if (regulator_disable(reg_VCN18)) + WMT_PLAT_PR_ERR("disable VCN_1V8 fail!\n"); + else + WMT_PLAT_PR_DBG("disable VCN_1V8 ok\n"); + } +#endif + } +#endif + return 0; +} + +/* Wayne Chen - This function was copied from mt6759.c */ +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { +#if defined(CONFIG_MTK_PMIC_CHIP_MT6357) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN28_ON_CTRL, 1); +#endif + } else { +#if defined(CONFIG_MTK_PMIC_CHIP_MT6357) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN28_ON_CTRL, 0); +#endif + } +#endif +} + +/* Wayne Chen - This function was copied from mt6759.c */ +static INT32 consys_hw_vcn28_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*in co-clock mode,need to turn on vcn28 when fm on */ + if (reg_VCN28) { + regulator_set_voltage(reg_VCN28, 2800000, 2800000); + if (regulator_enable(reg_VCN28)) + WMT_PLAT_PR_ERR("WMT do VCN28 PMIC on fail!\n"); + } + WMT_PLAT_PR_INFO("turn on vcn28 for fm/gps usage in co-clock mode\n"); + } else { + /*in co-clock mode,need to turn off vcn28 when fm off */ + if (reg_VCN28) + regulator_disable(reg_VCN28); + WMT_PLAT_PR_INFO("turn off vcn28 for fm/gps usage in co-clock mode\n"); + } +#endif + return 0; +} + +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + /* spin_lock_irqsave(&gBtWifiV33.lock,gBtWifiV33.flags); */ + if (enable) { + if (gBtWifiV33.counter == 1) { + gBtWifiV33.counter++; + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else if (gBtWifiV33.counter == 2) { + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else { +#if CONSYS_PMIC_CTRL_ENABLE + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + hwPowerOn(MT6351_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); + mt6351_upmu_set_rg_vcn33_on_ctrl(1); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 on\n"); + gBtWifiV33.counter++; + } + + } else { + if (gBtWifiV33.counter == 1) { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + mt6351_upmu_set_rg_vcn33_on_ctrl(0); + hwPowerDown(MT6351_POWER_LDO_VCN33_BT, "wcn_drv"); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 off\n"); + gBtWifiV33.counter--; + } else if (gBtWifiV33.counter == 2) { + gBtWifiV33.counter--; + WMT_PLAT_PR_DBG("V33 no need disabled,counter(%d)\n", gBtWifiV33.counter); + } else { + WMT_PLAT_PR_DBG("V33 has been disabled,counter(%d)\n", gBtWifiV33.counter); + } + + } + /* spin_unlock_irqrestore(&gBtWifiV33.lock,gBtWifiV33.flags); */ +#else + if (enable) { + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ +#if defined(CONFIG_MTK_LEGACY) + hwPowerOn(MT6351_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); +#else + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } +#endif + +#if defined(CONFIG_MTK_PMIC_CHIP_MT6357) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_BT, 1); +#endif + +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC on\n"); + } else { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE +#if defined(CONFIG_MTK_PMIC_CHIP_MT6357) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_BT, 0); +#endif +#if defined(CONFIG_MTK_LEGACY) + hwPowerDown(MT6351_POWER_LDO_VCN33_BT, "wcn_drv"); +#else + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); +#endif +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC off\n"); + } +#endif + + return 0; +} + +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + mtk_wcn_consys_hw_bt_paldo_ctrl(enable); +#else + if (enable) { + /*do WIFI PMIC on,depenency PMIC API ready */ + /*switch WIFI PALDO control from SW mode to HW mode:0x418[14]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE +#if defined(CONFIG_MTK_LEGACY) + hwPowerOn(MT6351_POWER_LDO_VCN33_WIFI, VOL_3300 * 1000, "wcn_drv"); +#else + if (reg_VCN33_WIFI) { + regulator_set_voltage(reg_VCN33_WIFI, 3300000, 3300000); + if (regulator_enable(reg_VCN33_WIFI)) + WMT_PLAT_PR_ERR("WMT do WIFI PMIC on fail!\n"); + } +#endif +#if defined(CONFIG_MTK_PMIC_CHIP_MT6357) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_WIFI, 1); +#endif +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC on\n"); + } else { + /*do WIFI PMIC off */ + /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE +#if defined(CONFIG_MTK_PMIC_CHIP_MT6357) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_WIFI, 0); +#endif +#if defined(CONFIG_MTK_LEGACY) + hwPowerDown(MT6351_POWER_LDO_VCN33_WIFI, "wcn_drv"); +#else + if (reg_VCN33_WIFI) + regulator_disable(reg_VCN33_WIFI); +#endif + +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC off\n"); + } + +#endif + + return 0; +} + +static INT32 consys_emi_mpu_set_region_protection(VOID) +{ +#if CONSYS_EMI_MPU_SETTING + /*set MPU for EMI share Memory */ + WMT_PLAT_PR_INFO("setting MPU for EMI share memory\n"); + + /* 5 = Forbidden, 0 = No_protect */ + emi_mpu_set_region_protection(gConEmiPhyBase + SZ_1M / 2, + gConEmiPhyBase + gConEmiSize - 1, + 22, + SET_ACCESS_PERMISSON(LOCK, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, NO_PROTECTION, FORBIDDEN, NO_PROTECTION)); +#endif + return 0; +} + +static UINT32 consys_emi_set_remapping_reg(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + UINT32 addrPhy = 0; + + /*consys to ap emi remapping register:10001380, cal remapping address */ + addrPhy = (gConEmiPhyBase >> 21) & 0x1FFF; + + /*enable consys to ap emi remapping bit13 */ + addrPhy = addrPhy | 0x2000; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); + + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); +#endif + return 0; +} + +static INT32 bt_wifi_share_v33_spin_lock_init(VOID) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + gBtWifiV33.counter = 0; + spin_lock_init(&gBtWifiV33.lock); +#endif + return 0; +} + +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag) +{ +#ifdef CONFIG_OF /*use DT */ + struct device_node *node; + UINT32 irq_info[3] = { 0, 0, 0 }; + + INT32 iret = -1; + + node = pdev->dev.of_node; + if (node) { + *irq_num = irq_of_parse_and_map(node, 0); + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + WMT_PLAT_PR_ERR("get irq flags from DTS fail!!\n"); + return iret; + } + *irq_flag = irq_info[2]; + WMT_PLAT_PR_INFO("get irq id(%d) and irq trigger flag(%d) from DT\n", *irq_num, + *irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iret; + } +#endif + return 0; +} + +static INT32 consys_read_reg_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ + INT32 iRet = -1; + struct device_node *node = NULL; + + node = pdev->dev.of_node; + if (node) { + /* registers base address */ + conn_reg.mcu_base = (SIZE_T) of_iomap(node, 0); + WMT_PLAT_PR_DBG("Get mcu register base(0x%zx)\n", conn_reg.mcu_base); + conn_reg.ap_rgu_base = (SIZE_T) of_iomap(node, 1); + WMT_PLAT_PR_DBG("Get ap_rgu register base(0x%zx)\n", conn_reg.ap_rgu_base); + conn_reg.topckgen_base = (SIZE_T) of_iomap(node, 2); + WMT_PLAT_PR_DBG("Get topckgen register base(0x%zx)\n", conn_reg.topckgen_base); + conn_reg.spm_base = (SIZE_T) of_iomap(node, 3); + WMT_PLAT_PR_DBG("Get spm register base(0x%zx)\n", conn_reg.spm_base); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iRet; + } +#endif + return 0; +} + +static VOID force_trigger_assert_debug_pin(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + usleep_range(64, 96); + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); +#endif +} + +static UINT32 consys_read_cpupcr(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CPUPCR_OFFSET); +#endif +} + +static UINT32 consys_soc_chipid_get(VOID) +{ + return PLATFORM_SOC_CHIP; +} + +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID) +{ + return &mtk_wcn_emi_addr_info; +} + +P_WMT_CONSYS_IC_OPS mtk_wcn_get_consys_ic_ops(VOID) +{ + return &consys_ic_ops; +} + +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable) +{ + if (enable) { + *addr = ioremap(gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET, CONSYS_EMI_MEM_SIZE); + if (*addr) { + WMT_PLAT_PR_INFO("COREDUMP EMI mapping OK virtual(0x%p) physical(0x%x)\n", + *addr, (UINT32) gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET); + memset_io(*addr, 0, CONSYS_EMI_MEM_SIZE); + } else { + WMT_PLAT_PR_ERR("EMI mapping fail\n"); + return -1; + } + } else { + if (*addr) { + iounmap(*addr); + *addr = NULL; + } + } + return 0; +} + +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr) +{ + if (!addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + WMT_PLAT_PR_INFO("Reset EMI(0xF0080000 ~ 0xF0080400) and (0xF0088400 ~ 0xF0090400)\n"); + /* reset 0xF0080000 ~ 0xF0080400 (1K) */ + memset_io(addr, 0, 0x400); + /* reset 0xF0088400 ~ 0xF0090400 (32K) */ + memset_io(addr + CONSYS_EMI_PAGED_DUMP_OFFSET, 0, 0x8000); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6755.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6755.c new file mode 100644 index 00000000000000..9999a6ef084848 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6755.c @@ -0,0 +1,1162 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <connectivity_build_in_adapter.h> + +#if defined(CONFIG_MTK_CLKMGR) +#include <mt_clkmgr.h> +#else +#include <linux/clk.h> +#endif /* defined(CONFIG_MTK_CLKMGR) */ +#include <linux/delay.h> +#include <linux/memblock.h> +#include "osal_typedef.h" +#include "mt6755.h" +#include "mtk_wcn_consys_hw.h" +#include <linux/platform_device.h> + +#if CONSYS_EMI_MPU_SETTING +#include <emi_mpu.h> +#endif + +#if CONSYS_PMIC_CTRL_ENABLE +#include <upmu_common.h> +#include <linux/regulator/consumer.h> +#endif + +#ifdef CONFIG_MTK_HIBERNATION +#include <mtk_hibernate_dpm.h> +#endif + +#include <linux/of_reserved_mem.h> + +#if CONSYS_CLOCK_BUF_CTRL +#include <mt_clkbuf_ctl.h> +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable); +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable); +static VOID consys_hw_spm_clk_gating_enable(VOID); +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable); +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable); +static INT32 polling_consys_chipid(VOID); +static VOID consys_acr_reg_setting(VOID); +static VOID consys_afe_reg_setting(VOID); +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable); +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable); +static INT32 consys_hw_vcn28_ctrl(UINT32 enable); +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable); +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable); +static UINT32 consys_soc_chipid_get(VOID); +static INT32 consys_emi_mpu_set_region_protection(VOID); +static UINT32 consys_emi_set_remapping_reg(VOID); +static INT32 bt_wifi_share_v33_spin_lock_init(VOID); +static INT32 consys_clk_get_from_dts(struct platform_device *pdev); +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev); +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, INT32 *irq_num, UINT32 *irq_flag); +static INT32 consys_read_reg_from_dts(struct platform_device *pdev); +static UINT32 consys_read_cpupcr(VOID); +static VOID force_trigger_assert_debug_pin(VOID); +static INT32 consys_co_clock_type(VOID); +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID); +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable); +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status gBtWifiV33; +#endif + +/* PMIC part */ +#if CONSYS_PMIC_CTRL_ENABLE +#if !defined(CONFIG_MTK_PMIC_LEGACY) +struct regulator *reg_VCN18; +struct regulator *reg_VCN28; +struct regulator *reg_VCN33_BT; +struct regulator *reg_VCN33_WIFI; +#endif +#endif + +/* CCF part */ +#if !defined(CONFIG_MTK_CLKMGR) +struct clk *clk_scp_conn_main; /*ctrl conn_power_on/off */ +/*struct clk *clk_infra_conn_main;*/ /*ctrl infra_connmcu_bus clk */ +#endif /* !defined(CONFIG_MTK_CLKMGR) */ + + +EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { + .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, + .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, + .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, + .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, + .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, + .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, + .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, + .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, + .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, + .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, + .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, + .emi_apmem_ctrl_chip_page_dump_num = EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM, + .emi_apmem_ctrl_assert_flag = EXP_APMEM_CTRL_ASSERT_FLAG, +}; + +CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { + .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, + .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, + .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, + .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, + .p_ecso = &mtk_wcn_emi_state_off, + .emi_core_dump_offset = CONSYS_EMI_COREDUMP_OFFSET, +}; + +WMT_CONSYS_IC_OPS consys_ic_ops = { + .consys_ic_clock_buffer_ctrl = consys_clock_buffer_ctrl, + .consys_ic_hw_reset_bit_set = consys_hw_reset_bit_set, + .consys_ic_hw_spm_clk_gating_enable = consys_hw_spm_clk_gating_enable, + .consys_ic_hw_power_ctrl = consys_hw_power_ctrl, + .consys_ic_ahb_clock_ctrl = consys_ahb_clock_ctrl, + .polling_consys_ic_chipid = polling_consys_chipid, + .consys_ic_acr_reg_setting = consys_acr_reg_setting, + .consys_ic_afe_reg_setting = consys_afe_reg_setting, + .consys_ic_hw_vcn18_ctrl = consys_hw_vcn18_ctrl, + .consys_ic_vcn28_hw_mode_ctrl = consys_vcn28_hw_mode_ctrl, + .consys_ic_hw_vcn28_ctrl = consys_hw_vcn28_ctrl, + .consys_ic_hw_wifi_vcn33_ctrl = consys_hw_wifi_vcn33_ctrl, + .consys_ic_hw_bt_vcn33_ctrl = consys_hw_bt_vcn33_ctrl, + .consys_ic_soc_chipid_get = consys_soc_chipid_get, + .consys_ic_emi_mpu_set_region_protection = consys_emi_mpu_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .ic_bt_wifi_share_v33_spin_lock_init = bt_wifi_share_v33_spin_lock_init, + .consys_ic_clk_get_from_dts = consys_clk_get_from_dts, + .consys_ic_pmic_get_from_dts = consys_pmic_get_from_dts, + .consys_ic_read_irq_info_from_dts = consys_read_irq_info_from_dts, + .consys_ic_read_reg_from_dts = consys_read_reg_from_dts, + .consys_ic_read_cpupcr = consys_read_cpupcr, + .ic_force_trigger_assert_debug_pin = force_trigger_assert_debug_pin, + .consys_ic_co_clock_type = consys_co_clock_type, + .consys_ic_soc_get_emi_phy_add = consys_soc_get_emi_phy_add, + .consys_ic_emi_coredump_remapping = consys_emi_coredump_remapping, + .consys_ic_reset_emi_coredump = consys_reset_emi_coredump, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +UINT32 gJtagCtrl; +#if CONSYS_ENALBE_SET_JTAG +#define JTAG_ADDR1_BASE 0x10002000 +PINT8 jtag_addr1 = (PINT8)JTAG_ADDR1_BASE; +#define JTAG1_REG_WRITE(addr, value) \ + writel(value, ((PUINT32)(jtag_addr1+(addr-JTAG_ADDR1_BASE)))) +#define JTAG1_REG_READ(addr) \ + readl(((PUINT32)(jtag_addr1+(addr-JTAG_ADDR1_BASE)))) +#endif + +INT32 mtk_wcn_consys_jtag_set_for_mcu(VOID) +{ +#if CONSYS_ENALBE_SET_JTAG + + if (gJtagCtrl) { +#if 0 + INT32 iRet = -1; + + WMT_PLAT_PR_INFO("WCN jtag_set_for_mcu start...\n"); + jtag_addr1 = ioremap(JTAG_ADDR1_BASE, 0x5000); + if (jtag_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + return iRet; + } + WMT_PLAT_PR_INFO("jtag_addr1 = 0x%p\n", jtag_addr1); + + JTAG1_REG_WRITE(0x100053c4, 0x11111100); + JTAG1_REG_WRITE(0x100053d4, 0x00111111); + + /*Enable IES of all pins */ + JTAG1_REG_WRITE(0x10002014, 0x00000003); + JTAG1_REG_WRITE(0x10005334, 0x55000000); + JTAG1_REG_WRITE(0x10005344, 0x00555555); + JTAG1_REG_WRITE(0x10005008, 0xc0000000); + JTAG1_REG_WRITE(0x10005018, 0x0000000d); + JTAG1_REG_WRITE(0x10005014, 0x00000032); + JTAG1_REG_WRITE(0x100020a4, 0x000000ff); + JTAG1_REG_WRITE(0x100020d4, 0x000000b4); + JTAG1_REG_WRITE(0x100020d8, 0x0000004b); + + WMT_PLAT_PR_INFO("WCN jtag set for mcu start...\n"); + kal_uint32 tmp = 0; + kal_int32 addr = 0; + kal_int32 remap_addr1 = 0; + kal_int32 remap_addr2 = 0; + + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + return -1; + } + + remap_addr2 = ioremap(JTAG_ADDR2_BASE, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + return -1; + } + + /*Pinmux setting for MT6625 I/F */ + addr = remap_addr1 + 0x03C0; + tmp = DRV_Reg32(addr); + tmp = tmp & 0xff; + tmp = tmp | 0x11111100; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + addr = remap_addr1 + 0x03D0; + tmp = DRV_Reg32(addr); + tmp = tmp & 0xff000000; + tmp = tmp | 0x00111111; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*AP GPIO Setting 1 <default use> */ + /*Enable IES */ + /* addr = 0x10002014; */ + addr = remap_addr2 + 0x0014; + tmp = 0x00000003; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + /*GPIO mode setting */ + /* addr = 0x10005334; */ + addr = remap_addr1 + 0x0334; + tmp = 0x55000000; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005344; */ + addr = remap_addr1 + 0x0344; + tmp = 0x00555555; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + /*GPIO direction control */ + /* addr = 0x10005008; */ + addr = remap_addr1 + 0x0008; + tmp = 0xc0000000; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005018; */ + addr = remap_addr1 + 0x0018; + tmp = 0x0000000d; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005014; */ + addr = remap_addr1 + 0x0014; + tmp = 0x00000032; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*PULL Enable */ + /* addr = 0x100020a4; */ + addr = remap_addr2 + 0x00a4; + tmp = 0x000000ff; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*PULL select enable */ + /* addr = 0x100020d4; */ + addr = remap_addr2 + 0x00d4; + tmp = 0x000000b4; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x100020d8; */ + addr = remap_addr2 + 0x00d8; + tmp = 0x0000004b; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); +#endif + } +#endif + return 0; +} + +UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en) +{ + WMT_PLAT_PR_INFO("%s jtag set for MCU\n", en ? "enable" : "disable"); + gJtagCtrl = en; + return 0; +} + +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable) +{ + /* Keep XO_CONN SW default on to prevent that Connsys may wakeup to scan(wifi) + * when XO_CONN is closed due to RF suspending which will cause WMT power on failed issue + */ + if (wmt_plat_soc_co_clock_flag_get() != CLOCK_TYPE_CO_VCTCXO) { +#if CONSYS_CLOCK_BUF_CTRL + WMT_PLAT_PR_INFO("co clock type(%d),turn %s clk buf\n", + wmt_plat_soc_co_clock_flag_get(), enable ? "on" : "off"); + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, enable); +#endif + } + return 0; +} + +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable) +{ +#ifdef CONFIG_OF /*use DT */ + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE((conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET), + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) | + CONSYS_CPU_SW_RST_BIT | CONSYS_CPU_SW_RST_CTRL_KEY); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88 (key)" */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_CPU_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + } +#else + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE(CONSYS_CPU_SW_RST_REG, + (CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG) | CONSYS_CPU_SW_RST_BIT | + CONSYS_CPU_SW_RST_CTRL_KEY)); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88(key)" */ + CONSYS_REG_WRITE(CONSYS_CPU_SW_RST_REG, + (CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG) & ~CONSYS_CPU_SW_RST_BIT) | + CONSYS_CPU_SW_RST_CTRL_KEY); + } +#endif +} + +static VOID consys_hw_spm_clk_gating_enable(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + /*turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE((conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET), CONSYS_PWRON_CONFG_EN_VALUE); +#else + /*turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE(CONSYS_PWRON_CONFG_EN_REG, CONSYS_PWRON_CONFG_EN_VALUE); +#endif +} + +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + INT32 iRet = -1; +#endif + + if (enable) { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE +#if defined(CONFIG_MTK_CLKMGR) + iRet = conn_power_on(); /* consult clkmgr owner. */ + if (iRet) + WMT_PLAT_PR_ERR("conn_power_on fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("conn_power_on ok\n"); +#else + iRet = clk_prepare_enable(clk_scp_conn_main); + if (iRet) + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_scp_conn_main) fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_scp_conn_main) ok\n"); +#endif /* defined(CONFIG_MTK_LEGACY) */ + +#else + +#ifdef CONFIG_OF /*use DT */ + /*2.write conn_top1_pwr_on=1, power on conn_top1 0x1000632c [2] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_BIT); + /*3.read conn_top1_pwr_on_ack =1, power on ack ready 0x10006180 [1] */ + while (0 == (CONSYS_PWR_ON_ACK_BIT & CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET))) + NULL; + /*5.write conn_top1_pwr_on_s=1, power on conn_top1 0x1000632c [3] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_S_BIT); + /*6.write conn_clk_dis=0, enable connsys clock 0x1000632c [4] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_CLK_CTRL_BIT); + /*7.wait 1us */ + udelay(1); + /*8.read conn_top1_pwr_on_ack_s =1, power on ack ready 0x10006184 [1] */ + while (0 == (CONSYS_PWR_CONN_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET))) + NULL; + /*9.release connsys ISO, conn_top1_iso_en=0 0x1000632c [1] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_ISO_S_BIT); + /*10.release SW reset of connsys, conn_ap_sw_rst_b=1 0x1000632c[0] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_RST_BIT); + /*disable AXI BUS protect 0x10001220[13] [14] */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) & + ~CONSYS_PROT_MASK); + while (CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_STA1_OFFSET) & CONSYS_PROT_MASK) + NULL; +#else + /*2.write conn_top1_pwr_on=1, power on conn_top1 0x10006280 [2] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ON_BIT); + /*3.read conn_top1_pwr_on_ack =1, power on ack ready 0x1000660C [1] */ + while (0 == (CONSYS_PWR_ON_ACK_BIT & CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_REG))) + NULL; + /*5.write conn_top1_pwr_on_s=1, power on conn_top1 0x10006280 [3] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ON_S_BIT); + /*6.write conn_clk_dis=0, enable connsys clock 0x10006280 [4] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_CLK_CTRL_BIT); + /*7.wait 1us */ + udelay(1); + /*8.read conn_top1_pwr_on_ack_s =1, power on ack ready 0x10006610 [1] */ + while (0 == (CONSYS_PWR_CONN_ACK_S_BIT & CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_S_REG))) + NULL; + /*9.release connsys ISO, conn_top1_iso_en=0 0x10006280 [1] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_SPM_PWR_ISO_S_BIT); + /*10.release SW reset of connsys, conn_ap_sw_rst_b=1 0x10006280[0] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_RST_BIT); + /*disable AXI BUS protect */ + CONSYS_REG_WRITE(CONSYS_TOPAXI_PROT_EN, CONSYS_REG_READ(CONSYS_TOPAXI_PROT_EN) & ~CONSYS_PROT_MASK); + while (CONSYS_REG_READ(CONSYS_TOPAXI_PROT_STA1) & CONSYS_PROT_MASK) + NULL; +#endif +#endif + } else { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE +#if defined(CONFIG_MTK_CLKMGR) + /*power off connsys by API (MT6582, MT6572 are different) API: conn_power_off() */ + iRet = conn_power_off(); /* consult clkmgr owner */ + if (iRet) + WMT_PLAT_PR_ERR("conn_power_off fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("conn_power_off ok\n"); +#else + clk_disable_unprepare(clk_scp_conn_main); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_scp_conn_main) calling\n"); +#endif /* defined(CONFIG_MTK_LEGACY) */ + +#else + +#ifdef CONFIG_OF /*use DT */ + { + INT32 count = 0; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) | + CONSYS_PROT_MASK); + while ((CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_STA1_OFFSET) & + CONSYS_PROT_MASK) != CONSYS_PROT_MASK) { + count++; + if (count > 1000) + break; + } + } + /*release connsys ISO, conn_top1_iso_en=1 0x1000632c [1] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ISO_S_BIT); + /*assert SW reset of connsys, conn_ap_sw_rst_b=0 0x1000632c[0] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x1000632c [4] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632c [3:2] 2'b00 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#else + { + INT32 count = 0; + + CONSYS_REG_WRITE(CONSYS_TOPAXI_PROT_EN, + CONSYS_REG_READ(CONSYS_TOPAXI_PROT_EN) | CONSYS_PROT_MASK); + while ((CONSYS_REG_READ(CONSYS_TOPAXI_PROT_STA1) & CONSYS_PROT_MASK) != CONSYS_PROT_MASK) { + count++; + if (count > 1000) + break; + } + } + /*release connsys ISO, conn_top1_iso_en=1 0x1000632c [1] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ISO_S_BIT); + /*assert SW reset of connsys, conn_ap_sw_rst_b=0 0x1000632c[0] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x1000632c [4] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632c [3:2] 2'b00 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#endif +#endif + } + +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + return iRet; +#else + return 0; +#endif +} + +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable) +{ + return 0; +} + +static INT32 polling_consys_chipid(VOID) +{ + UINT32 retry = 10; + UINT32 consysHwChipId = 0; + +#ifdef CONFIG_OF /*use DT */ + /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ + while (retry-- > 0) { + consysHwChipId = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CHIP_ID_OFFSET); + if (consysHwChipId == 0x0326) { + WMT_PLAT_PR_INFO("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + msleep(20); + } + + if ((0 == retry) || (0 == consysHwChipId)) { + WMT_PLAT_PR_ERR("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + WMT_PLAT_PR_INFO("reg dump:CONSYS_CPU_SW_RST_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_S_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_TOP1_PWR_CTRL_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET)); + } +#else + /*12.poll CONNSYS CHIP ID until 6755 is returned 0x18070008 32'h6755 */ + while (retry-- > 0) { + WMT_PLAT_PR_DBG("CONSYS_CHIP_ID_REG(0x%08x)", CONSYS_REG_READ(CONSYS_CHIP_ID_REG)); + consysHwChipId = CONSYS_REG_READ(CONSYS_CHIP_ID_REG); + if (consysHwChipId == 0x0326) { + WMT_PLAT_PR_INFO("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + msleep(20); + } + + if ((0 == retry) || (0 == consysHwChipId)) { + WMT_PLAT_PR_ERR("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + WMT_PLAT_PR_INFO("reg dump:CONSYS_CPU_SW_RST_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_S_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_S_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_TOP1_PWR_CTRL_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG)); + } +#endif + return 0; +} + +static VOID consys_acr_reg_setting(VOID) +{ + /* + *14.write 1 to conn_mcu_confg ACR[1] if real speed MBIST + *(default write "1") ACR 0x18070110[18] 1'b1 + *if this bit is 0, HW will do memory auto test under low CPU frequence (26M Hz) + *if this bit is 0, HW will do memory auto test under high CPU frequence(138M Hz) + *inclulding low CPU frequence + */ +#ifdef CONFIG_OF /*use DT */ + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET, + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET) | + CONSYS_MCU_CFG_ACR_MBIST_BIT); +#else + CONSYS_REG_WRITE(CONSYS_MCU_CFG_ACR_REG, + CONSYS_REG_READ(CONSYS_MCU_CFG_ACR_REG) | CONSYS_MCU_CFG_ACR_MBIST_BIT); +#endif +} + +static VOID consys_afe_reg_setting(VOID) +{ +#if 0 + /*15.default no need,update ANA_WBG(AFE) CR if needed, CONSYS_AFE_REG */ + CONSYS_REG_WRITE(CONSYS_AFE_REG_DIG_RCK_01, CONSYS_AFE_REG_DIG_RCK_01_VALUE); + CONSYS_REG_WRITE(CONSYS_AFE_REG_WBG_PLL_02, CONSYS_AFE_REG_WBG_PLL_02_VALUE); + CONSYS_REG_WRITE(CONSYS_AFE_REG_WBG_WB_TX_01, CONSYS_AFE_REG_WBG_WB_TX_01_VALUE); +#endif +} + +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*need PMIC driver provide new API protocol */ + /*1.AP power on VCN_1V8 LDO (with PMIC_WRAP API) VCN_1V8 */ +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + KERNEL_pmic_set_register_value(PMIC_LDO_VCN18_EN_CTRL, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN18_ON_CTRL, 0); +#endif + /* VOL_DEFAULT, VOL_1200, VOL_1300, VOL_1500, VOL_1800... */ +#if defined(CONFIG_MTK_LEGACY) +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + hwPowerOn(MT6353_POWER_LDO_VCN18, VOL_1800 * 1000, "wcn_drv"); +#else + hwPowerOn(MT6351_POWER_LDO_VCN18, VOL_1800 * 1000, "wcn_drv"); +#endif +#else + if (reg_VCN18) { + regulator_set_voltage(reg_VCN18, VOL_1800, VOL_1800); + if (regulator_enable(reg_VCN18)) + WMT_PLAT_PR_ERR("enable VCN18 fail\n"); + else + WMT_PLAT_PR_DBG("enable VCN18 ok\n"); + } +#endif + } else { + /*AP power off MT6351L VCN_1V8 LDO */ +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + KERNEL_pmic_set_register_value(PMIC_LDO_VCN18_EN_CTRL, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN18_ON_CTRL, 0); +#endif +#if defined(CONFIG_MTK_LEGACY) +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + hwPowerDown(MT6353_POWER_LDO_VCN18, "wcn_drv"); +#else + hwPowerDown(MT6351_POWER_LDO_VCN18, "wcn_drv"); +#endif +#else + if (reg_VCN18) { + if (regulator_disable(reg_VCN18)) + WMT_PLAT_PR_ERR("disable VCN_1V8 fail!\n"); + else + WMT_PLAT_PR_DBG("disable VCN_1V8 ok\n"); + } +#endif + } +#endif + return 0; +} + +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + KERNEL_pmic_set_register_value(PMIC_LDO_VCN28_EN_CTRL, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN28_ON_CTRL, 1); +#endif + else +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + /* 2.1.for jade minus:switch VCN28 to SW control mode (with PMIC_WRAP API) */ + KERNEL_pmic_set_register_value(PMIC_LDO_VCN28_EN_CTRL, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN28_ON_CTRL, 0); +#endif +#endif +} + +static INT32 consys_hw_vcn28_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*in co-clock mode,need to turn on vcn28 when fm on */ +#if defined(CONFIG_MTK_LEGACY) +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + hwPowerOn(MT6353_POWER_LDO_VCN28, VOL_2800 * 1000, "wcn_drv"); +#else + hwPowerOn(MT6351_POWER_LDO_VCN28, VOL_2800 * 1000, "wcn_drv"); +#endif +#else + if (reg_VCN28) { + regulator_set_voltage(reg_VCN28, VOL_2800, VOL_2800); + if (regulator_enable(reg_VCN28)) + WMT_PLAT_PR_ERR("WMT do VCN28 PMIC on fail!\n"); + } +#endif + } else { + /*in co-clock mode,need to turn off vcn28 when fm off */ +#if defined(CONFIG_MTK_LEGACY) +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + hwPowerDown(MT6353_POWER_LDO_VCN28, "wcn_drv"); +#else + hwPowerDown(MT6351_POWER_LDO_VCN28, "wcn_drv"); +#endif +#else + if (reg_VCN28) + regulator_disable(reg_VCN28); +#endif + } + +#endif + return 0; +} + +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + /* spin_lock_irqsave(&gBtWifiV33.lock,gBtWifiV33.flags); */ + if (enable) { + if (1 == gBtWifiV33.counter) { + gBtWifiV33.counter++; + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else if (2 == gBtWifiV33.counter) { + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else { +#if CONSYS_PMIC_CTRL_ENABLE + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + hwPowerOn(MT6353_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); + mt6353_upmu_set_ldo_vcn33_en_ctrl_bt(1); +#else + hwPowerOn(MT6351_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); + mt6351_upmu_set_rg_vcn33_on_ctrl(1); +#endif +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 on\n"); + gBtWifiV33.counter++; + } + + } else { + if (1 == gBtWifiV33.counter) { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + mt6353_upmu_set_ldo_vcn33_en_ctrl_bt(0); + hwPowerDown(MT6353_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); +#else + mt6351_upmu_set_rg_vcn33_on_ctrl(0); + hwPowerDown(MT6351_POWER_LDO_VCN33_BT, "wcn_drv"); +#endif +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 off\n"); + gBtWifiV33.counter--; + } else if (2 == gBtWifiV33.counter) { + gBtWifiV33.counter--; + WMT_PLAT_PR_DBG("V33 no need disabled,counter(%d)\n", gBtWifiV33.counter); + } else { + WMT_PLAT_PR_DBG("V33 has been disabled,counter(%d)\n", gBtWifiV33.counter); + } + + } + /* spin_unlock_irqrestore(&gBtWifiV33.lock,gBtWifiV33.flags); */ +#else + if (enable) { + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ +#if defined(CONFIG_MTK_LEGACY) +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + hwPowerOn(MT6353_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); +#else + hwPowerOn(MT6351_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); +#endif +#else + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, VOL_3300, VOL_3300); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } +#endif +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + KERNEL_pmic_set_register_value(PMIC_LDO_VCN33_EN_CTRL_BT, 1); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_BT, 1); +#endif + +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC on\n"); + } else { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + KERNEL_pmic_set_register_value(PMIC_LDO_VCN33_EN_CTRL_BT, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_BT, 0); +#endif +#if defined(CONFIG_MTK_LEGACY) +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + hwPowerDown(MT6353_POWER_LDO_VCN33_BT, "wcn_drv"); +#else + hwPowerDown(MT6351_POWER_LDO_VCN33_BT, "wcn_drv"); +#endif +#else + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); +#endif +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC off\n"); + } +#endif + return 0; +} + +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + consys_hw_bt_vcn33_ctrl(enable); +#else + if (enable) { + /*do WIFI PMIC on,depenency PMIC API ready */ + /*switch WIFI PALDO control from SW mode to HW mode:0x418[14]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE +#if defined(CONFIG_MTK_LEGACY) +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + hwPowerOn(MT6353_POWER_LDO_VCN33_WIFI, VOL_3300 * 1000, "wcn_drv"); +#else + hwPowerOn(MT6351_POWER_LDO_VCN33_WIFI, VOL_3300 * 1000, "wcn_drv"); +#endif +#else + if (reg_VCN33_WIFI) { + regulator_set_voltage(reg_VCN33_WIFI, VOL_3300, VOL_3300); + if (regulator_enable(reg_VCN33_WIFI)) + WMT_PLAT_PR_ERR("WMT do WIFI PMIC on fail!\n"); + } +#endif +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + KERNEL_pmic_set_register_value(PMIC_LDO_VCN33_EN_CTRL_WIFI, 1); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_WIFI, 1); +#endif +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC on\n"); + } else { + /*do WIFI PMIC off */ + /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + KERNEL_pmic_set_register_value(PMIC_LDO_VCN33_EN_CTRL_WIFI, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_WIFI, 0); +#endif +#if defined(CONFIG_MTK_LEGACY) +#if defined(CONFIG_MTK_PMIC_CHIP_MT6353) + hwPowerDown(MT6353_POWER_LDO_VCN33_WIFI, "wcn_drv"); +#else + hwPowerDown(MT6351_POWER_LDO_VCN33_WIFI, "wcn_drv"); +#endif +#else + if (reg_VCN33_WIFI) + regulator_disable(reg_VCN33_WIFI); +#endif + +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC off\n"); + } +#endif + return 0; +} + +static UINT32 consys_soc_chipid_get(VOID) +{ + return PLATFORM_SOC_CHIP; +} + +static INT32 consys_emi_mpu_set_region_protection(VOID) +{ +#if CONSYS_EMI_MPU_SETTING + /*set MPU for EMI share Memory */ + WMT_PLAT_PR_INFO("setting MPU for EMI share memory\n"); + emi_mpu_set_region_protection(gConEmiPhyBase + SZ_1M / 2, + gConEmiPhyBase + SZ_1M - 1, + 13, + SET_ACCESS_PERMISSON(FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, NO_PROTECTION, FORBIDDEN, NO_PROTECTION)); +#endif + return 0; +} + +static UINT32 consys_emi_set_remapping_reg(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + UINT32 addrPhy = 0; + + /*consys to ap emi remapping register:10000320, cal remapping address */ + addrPhy = (gConEmiPhyBase & 0xFFF00000) >> 20; + + /*enable consys to ap emi remapping bit12 */ + addrPhy = addrPhy | 0x1000; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); + + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); +#endif + return 0; +} + +static INT32 bt_wifi_share_v33_spin_lock_init(VOID) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + gBtWifiV33.counter = 0; + spin_lock_init(&gBtWifiV33.lock); +#endif + return 0; +} + +static INT32 consys_clk_get_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ +#if !defined(CONFIG_MTK_CLKMGR) + clk_scp_conn_main = devm_clk_get(&pdev->dev, "conn"); + if (IS_ERR(clk_scp_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_scp_conn_main clock.\n"); + return -1; + } + WMT_PLAT_PR_DBG("[CCF]clk_scp_conn_main=%p\n", clk_scp_conn_main); +#if 0 + clk_infra_conn_main = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(clk_infra_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_infra_conn_main clock.\n"); + return PTR_ERR(clk_infra_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_infra_conn_main=%p\n", clk_infra_conn_main); +#endif + +#endif /* !defined(CONFIG_MTK_CLKMGR) */ +#endif + return 0; +} + +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ +#if CONSYS_PMIC_CTRL_ENABLE +#if !defined(CONFIG_MTK_PMIC_LEGACY) + reg_VCN18 = regulator_get(&pdev->dev, "vcn18"); + if (!reg_VCN18) + WMT_PLAT_PR_ERR("Regulator_get VCN_1V8 fail\n"); + reg_VCN28 = regulator_get(&pdev->dev, "vcn28"); + if (!reg_VCN28) + WMT_PLAT_PR_ERR("Regulator_get VCN_2V8 fail\n"); + reg_VCN33_BT = regulator_get(&pdev->dev, "vcn33_bt"); + if (!reg_VCN33_BT) + WMT_PLAT_PR_ERR("Regulator_get VCN33_BT fail\n"); + reg_VCN33_WIFI = regulator_get(&pdev->dev, "vcn33_wifi"); + if (!reg_VCN33_WIFI) + WMT_PLAT_PR_ERR("Regulator_get VCN33_WIFI fail\n"); +#endif +#endif +#endif + return 0; +} + +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, INT32 *irq_num, UINT32 *irq_flag) +{ +#ifdef CONFIG_OF /*use DT */ + struct device_node *node; + UINT32 irq_info[3] = { 0, 0, 0 }; + + INT32 iret = -1; + + node = pdev->dev.of_node; + if (node) { + *irq_num = irq_of_parse_and_map(node, 0); + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + WMT_PLAT_PR_ERR("get irq flags from DTS fail!!\n"); + return iret; + } + *irq_flag = irq_info[2]; + WMT_PLAT_PR_INFO("get irq id(%d) and irq trigger flag(%d) from DT\n", *irq_num, + *irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iret; + } +#endif + return 0; +} + +static INT32 consys_read_reg_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ + INT32 iRet = -1; + struct device_node *node = NULL; + + node = pdev->dev.of_node; + if (node) { + /* registers base address */ + conn_reg.mcu_base = (SIZE_T) of_iomap(node, 0); + WMT_PLAT_PR_DBG("Get mcu register base(0x%zx)\n", conn_reg.mcu_base); + conn_reg.ap_rgu_base = (SIZE_T) of_iomap(node, 1); + WMT_PLAT_PR_DBG("Get ap_rgu register base(0x%zx)\n", conn_reg.ap_rgu_base); + conn_reg.topckgen_base = (SIZE_T) of_iomap(node, 2); + WMT_PLAT_PR_DBG("Get topckgen register base(0x%zx)\n", conn_reg.topckgen_base); + conn_reg.spm_base = (SIZE_T) of_iomap(node, 3); + WMT_PLAT_PR_DBG("Get spm register base(0x%zx)\n", conn_reg.spm_base); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iRet; + } +#endif + return 0; +} + +static VOID force_trigger_assert_debug_pin(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + usleep_range(64, 96); + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); +#endif +} + +static INT32 consys_co_clock_type(VOID) +{ + UINT32 retval = 0; + UINT32 back_up = 0; + UINT32 co_clock_type = 0; + + /* co-clock auto detection:backup cw15,write cw15,read cw16,restore cw15, */ + KERNEL_pmic_read_interface(PMIC_DCXO_CW15, &retval, 0xFFFF, 0); + back_up = retval; + KERNEL_pmic_config_interface(PMIC_DCXO_CW15, PMIC_DCXO_CW15_VAL, 0xFFFF, 0); + KERNEL_pmic_read_interface(PMIC_DCXO_CW16, &retval, 0xFFFF, 0); + KERNEL_pmic_config_interface(PMIC_DCXO_CW15, back_up, 0xFFFF, 0); + if ((retval & AP_CONSYS_NOCO_CLOCK_BITA) || (retval & AP_CONSYS_NOCO_CLOCK_BITB)) { + co_clock_type = 0; + WMT_PLAT_PR_INFO("pmic_register_val = 0x%x, co_clock_type = %d,TCXO mode\n", retval, co_clock_type); + } else if ((retval & AP_CONSYS_CO_CLOCK_BITA) || (retval & AP_CONSYS_CO_CLOCK_BITB)) { + co_clock_type = 1; + WMT_PLAT_PR_INFO("pmic_register_val = 0x%x, co_clock_type = %d,co-TSX mode\n", retval, co_clock_type); + } + + return co_clock_type; +} + +static UINT32 consys_read_cpupcr(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CPUPCR_OFFSET); +#endif +} + +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID) +{ + return &mtk_wcn_emi_addr_info; +} + +P_WMT_CONSYS_IC_OPS mtk_wcn_get_consys_ic_ops(VOID) +{ + return &consys_ic_ops; +} + +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable) +{ + if (enable) { + *addr = ioremap(gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET, CONSYS_EMI_MEM_SIZE); + if (*addr) { + WMT_PLAT_PR_INFO("COREDUMP EMI mapping OK virtual(0x%p) physical(0x%x)\n", + *addr, (UINT32) gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET); + memset_io(*addr, 0, CONSYS_EMI_MEM_SIZE); + } else { + WMT_PLAT_PR_ERR("EMI mapping fail\n"); + return -1; + } + } else { + if (*addr) { + iounmap(*addr); + *addr = NULL; + } + } + return 0; +} + +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr) +{ + if (!addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + WMT_PLAT_PR_INFO("Reset EMI(0xF0080000 ~ 0xF0080400) and (0xF0088400 ~ 0xF0090400)\n"); + /* reset 0xF0080000 ~ 0xF0080400 (1K) */ + memset_io(addr, 0, 0x400); + /* reset 0xF0088400 ~ 0xF0090400 (32K) */ + memset_io(addr + CONSYS_EMI_PAGED_DUMP_OFFSET, 0, 0x8000); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6757.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6757.c new file mode 100644 index 00000000000000..975e8dd15e25b8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6757.c @@ -0,0 +1,1100 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <connectivity_build_in_adapter.h> + +#if defined(CONFIG_MTK_CLKMGR) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) +#include <mtk_clkmgr.h> +#else +#include <mt_clkmgr.h> +#endif +#else +#include <linux/clk.h> +#endif /* defined(CONFIG_MTK_LEGACY) */ +#include <linux/delay.h> +#include <linux/memblock.h> +#include <linux/platform_device.h> +#include "osal_typedef.h" +#include "mt6757.h" +#include "mtk_wcn_consys_hw.h" + +#if CONSYS_EMI_MPU_SETTING +#include <mach/emi_mpu.h> +#endif + +#if CONSYS_PMIC_CTRL_ENABLE +#include <upmu_common.h> +#include <linux/regulator/consumer.h> +#endif + +#ifdef CONFIG_MTK_HIBERNATION +#include <mtk_hibernate_dpm.h> +#endif + +#include <linux/of_reserved_mem.h> + +#if CONSYS_CLOCK_BUF_CTRL +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) +#include <mtk_clkbuf_ctl.h> +#else +#include <mt_clkbuf_ctl.h> +#endif +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable); +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable); +static VOID consys_hw_spm_clk_gating_enable(VOID); +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable); +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable); +static INT32 polling_consys_chipid(VOID); +static VOID consys_acr_reg_setting(VOID); +static VOID consys_afe_reg_setting(VOID); +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable); +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable); +static INT32 consys_hw_vcn28_ctrl(UINT32 enable); +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable); +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable); +static UINT32 consys_soc_chipid_get(VOID); +static INT32 consys_emi_mpu_set_region_protection(VOID); +static UINT32 consys_emi_set_remapping_reg(VOID); +static INT32 bt_wifi_share_v33_spin_lock_init(VOID); +static INT32 consys_clk_get_from_dts(struct platform_device *pdev); +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev); +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag); +static INT32 consys_read_reg_from_dts(struct platform_device *pdev); +static UINT32 consys_read_cpupcr(VOID); +static VOID force_trigger_assert_debug_pin(VOID); +static INT32 consys_co_clock_type(VOID); +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID); +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable); +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status gBtWifiV33; +#endif + +/* CCF part */ +#if !defined(CONFIG_MTK_CLKMGR) +struct clk *clk_scp_conn_main; /*ctrl conn_power_on/off */ +/* struct clk *clk_infra_conn_main; */ /*ctrl infra_connmcu_bus clk */ +#endif /* !defined(CONFIG_MTK_LEGACY) */ + + +/* PMIC part */ +#if CONSYS_PMIC_CTRL_ENABLE +#if !defined(CONFIG_MTK_LEGACY) +struct regulator *reg_VCN18; +struct regulator *reg_VCN28; +struct regulator *reg_VCN33_BT; +struct regulator *reg_VCN33_WIFI; +#endif +#endif + +EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { + .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, + .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, + .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, + .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, + .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, + .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, + .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, + .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, + .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, + .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, + .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, + .emi_apmem_ctrl_chip_page_dump_num = EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM, + .emi_apmem_ctrl_assert_flag = EXP_APMEM_CTRL_ASSERT_FLAG, +}; + +CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { + .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, + .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, + .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, + .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, + .p_ecso = &mtk_wcn_emi_state_off, + .emi_core_dump_offset = CONSYS_EMI_COREDUMP_OFFSET, +}; + +WMT_CONSYS_IC_OPS consys_ic_ops = { + .consys_ic_clock_buffer_ctrl = consys_clock_buffer_ctrl, + .consys_ic_hw_reset_bit_set = consys_hw_reset_bit_set, + .consys_ic_hw_spm_clk_gating_enable = consys_hw_spm_clk_gating_enable, + .consys_ic_hw_power_ctrl = consys_hw_power_ctrl, + .consys_ic_ahb_clock_ctrl = consys_ahb_clock_ctrl, + .polling_consys_ic_chipid = polling_consys_chipid, + .consys_ic_acr_reg_setting = consys_acr_reg_setting, + .consys_ic_afe_reg_setting = consys_afe_reg_setting, + .consys_ic_hw_vcn18_ctrl = consys_hw_vcn18_ctrl, + .consys_ic_vcn28_hw_mode_ctrl = consys_vcn28_hw_mode_ctrl, + .consys_ic_hw_vcn28_ctrl = consys_hw_vcn28_ctrl, + .consys_ic_hw_wifi_vcn33_ctrl = consys_hw_wifi_vcn33_ctrl, + .consys_ic_hw_bt_vcn33_ctrl = consys_hw_bt_vcn33_ctrl, + .consys_ic_soc_chipid_get = consys_soc_chipid_get, + .consys_ic_emi_mpu_set_region_protection = consys_emi_mpu_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .ic_bt_wifi_share_v33_spin_lock_init = bt_wifi_share_v33_spin_lock_init, + .consys_ic_clk_get_from_dts = consys_clk_get_from_dts, + .consys_ic_pmic_get_from_dts = consys_pmic_get_from_dts, + .consys_ic_read_irq_info_from_dts = consys_read_irq_info_from_dts, + .consys_ic_read_reg_from_dts = consys_read_reg_from_dts, + .consys_ic_read_cpupcr = consys_read_cpupcr, + .ic_force_trigger_assert_debug_pin = force_trigger_assert_debug_pin, + .consys_ic_co_clock_type = consys_co_clock_type, + .consys_ic_soc_get_emi_phy_add = consys_soc_get_emi_phy_add, + .consys_ic_emi_coredump_remapping = consys_emi_coredump_remapping, + .consys_ic_reset_emi_coredump = consys_reset_emi_coredump, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +UINT32 gJtagCtrl; +#if CONSYS_ENALBE_SET_JTAG +#define JTAG_ADDR1_BASE 0x10002000 +PINT8 jtag_addr1 = (PINT8)JTAG_ADDR1_BASE; +#define JTAG1_REG_WRITE(addr, value) \ + writel(value, ((PUINT32)(jtag_addr1+(addr-JTAG_ADDR1_BASE)))) +#define JTAG1_REG_READ(addr) \ + readl(((PUINT32)(jtag_addr1+(addr-JTAG_ADDR1_BASE)))) +#endif + +INT32 mtk_wcn_consys_jtag_set_for_mcu(VOID) +{ +#if CONSYS_ENALBE_SET_JTAG + + if (gJtagCtrl) { +#if 0 + INT32 iRet = -1; + + WMT_PLAT_PR_INFO("WCN jtag_set_for_mcu start...\n"); + jtag_addr1 = ioremap(JTAG_ADDR1_BASE, 0x5000); + if (jtag_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + return iRet; + } + WMT_PLAT_PR_INFO("jtag_addr1 = 0x%p\n", jtag_addr1); + + JTAG1_REG_WRITE(0x100053c4, 0x11111100); + JTAG1_REG_WRITE(0x100053d4, 0x00111111); + + /*Enable IES of all pins */ + JTAG1_REG_WRITE(0x10002014, 0x00000003); + JTAG1_REG_WRITE(0x10005334, 0x55000000); + JTAG1_REG_WRITE(0x10005344, 0x00555555); + JTAG1_REG_WRITE(0x10005008, 0xc0000000); + JTAG1_REG_WRITE(0x10005018, 0x0000000d); + JTAG1_REG_WRITE(0x10005014, 0x00000032); + JTAG1_REG_WRITE(0x100020a4, 0x000000ff); + JTAG1_REG_WRITE(0x100020d4, 0x000000b4); + + JTAG1_REG_WRITE(0x100020d8, 0x0000004b); + + WMT_PLAT_PR_INFO("WCN jtag set for mcu start...\n"); + kal_uint32 tmp = 0; + kal_int32 addr = 0; + kal_int32 remap_addr1 = 0; + kal_int32 remap_addr2 = 0; + + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + return -1; + } + + remap_addr2 = ioremap(JTAG_ADDR2_BASE, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + return -1; + } + + /*Pinmux setting for MT6625 I/F */ + addr = remap_addr1 + 0x03C0; + tmp = DRV_Reg32(addr); + tmp = tmp & 0xff; + tmp = tmp | 0x11111100; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + addr = remap_addr1 + 0x03D0; + tmp = DRV_Reg32(addr); + tmp = tmp & 0xff000000; + tmp = tmp | 0x00111111; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*AP GPIO Setting 1 <default use> */ + /*Enable IES */ + /* addr = 0x10002014; */ + addr = remap_addr2 + 0x0014; + tmp = 0x00000003; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + /*GPIO mode setting */ + /* addr = 0x10005334; */ + addr = remap_addr1 + 0x0334; + tmp = 0x55000000; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005344; */ + addr = remap_addr1 + 0x0344; + tmp = 0x00555555; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + /*GPIO direction control */ + /* addr = 0x10005008; */ + addr = remap_addr1 + 0x0008; + tmp = 0xc0000000; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005018; */ + addr = remap_addr1 + 0x0018; + tmp = 0x0000000d; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005014; */ + addr = remap_addr1 + 0x0014; + tmp = 0x00000032; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*PULL Enable */ + /* addr = 0x100020a4; */ + addr = remap_addr2 + 0x00a4; + tmp = 0x000000ff; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*PULL select enable */ + /* addr = 0x100020d4; */ + addr = remap_addr2 + 0x00d4; + tmp = 0x000000b4; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x100020d8; */ + addr = remap_addr2 + 0x00d8; + tmp = 0x0000004b; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); +#endif + } +#endif + return 0; +} + +UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en) +{ + WMT_PLAT_PR_INFO("%s jtag set for MCU\n", en ? "enable" : "disable"); + gJtagCtrl = en; + return 0; +} + +static INT32 consys_clk_get_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ +#if !defined(CONFIG_MTK_CLKMGR) + clk_scp_conn_main = devm_clk_get(&pdev->dev, "conn"); + if (IS_ERR(clk_scp_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_scp_conn_main clock.\n"); + return PTR_ERR(clk_scp_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_scp_conn_main=%p\n", clk_scp_conn_main); +#if 0 + clk_infra_conn_main = devm_clk_get(&pdev->dev, "infra-sys-conn-main"); + if (IS_ERR(clk_infra_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_infra_conn_main clock.\n"); + return PTR_ERR(clk_infra_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_infra_conn_main=%p\n", clk_infra_conn_main); +#endif + +#endif /* !defined(CONFIG_MTK_LEGACY) */ +#endif + return 0; +} + +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ +#if CONSYS_PMIC_CTRL_ENABLE +#if !defined(CONFIG_MTK_LEGACY) + reg_VCN18 = regulator_get(&pdev->dev, "vcn18"); + if (!reg_VCN18) + WMT_PLAT_PR_ERR("Regulator_get VCN_1V8 fail\n"); + reg_VCN28 = regulator_get(&pdev->dev, "vcn28"); + if (!reg_VCN28) + WMT_PLAT_PR_ERR("Regulator_get VCN_2V8 fail\n"); + reg_VCN33_BT = regulator_get(&pdev->dev, "vcn33_bt"); + if (!reg_VCN33_BT) + WMT_PLAT_PR_ERR("Regulator_get VCN33_BT fail\n"); + reg_VCN33_WIFI = regulator_get(&pdev->dev, "vcn33_wifi"); + if (!reg_VCN33_WIFI) + WMT_PLAT_PR_ERR("Regulator_get VCN33_WIFI fail\n"); +#endif +#endif +#endif + return 0; +} + +static INT32 consys_co_clock_type(VOID) +{ + UINT32 retval = 0; + UINT32 back_up = 0; + UINT32 co_clock_type = 0; + + /* co-clock auto detection:backup cw15,write cw15,read cw16,restore cw15, */ + KERNEL_pmic_read_interface(PMIC_DCXO_CW15, &retval, 0xFFFF, 0); + back_up = retval; + KERNEL_pmic_config_interface(PMIC_DCXO_CW15, PMIC_DCXO_CW15_VAL, 0xFFFF, 0); + KERNEL_pmic_read_interface(PMIC_DCXO_CW16, &retval, 0xFFFF, 0); + KERNEL_pmic_config_interface(PMIC_DCXO_CW15, back_up, 0xFFFF, 0); + if ((retval & AP_CONSYS_NOCO_CLOCK_BITA) || (retval & AP_CONSYS_NOCO_CLOCK_BITB)) { + co_clock_type = 0; + WMT_PLAT_PR_INFO("pmic_register_val = 0x%x, co_clock_type = %d,TCXO mode\n", retval, co_clock_type); + } else if ((retval & AP_CONSYS_CO_CLOCK_BITA) || (retval & AP_CONSYS_CO_CLOCK_BITB)) { + co_clock_type = 1; + WMT_PLAT_PR_INFO("pmic_register_val = 0x%x, co_clock_type = %d,co-TSX mode\n", retval, co_clock_type); + } + return co_clock_type; +} + +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable) +{ + if (!KERNEL_is_clk_buf_from_pmic()) + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, enable); + return 0; +} + +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable) +{ +#ifdef CONFIG_OF /*use DT */ + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE((conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET), + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) | + CONSYS_CPU_SW_RST_BIT | CONSYS_CPU_SW_RST_CTRL_KEY); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88 (key)" */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_CPU_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + } +#else + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE(CONSYS_CPU_SW_RST_REG, + (CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG) | CONSYS_CPU_SW_RST_BIT | + CONSYS_CPU_SW_RST_CTRL_KEY)); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88(key)" */ + CONSYS_REG_WRITE(CONSYS_CPU_SW_RST_REG, + (CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG) & ~CONSYS_CPU_SW_RST_BIT) | + CONSYS_CPU_SW_RST_CTRL_KEY); + } +#endif +} + +static VOID consys_hw_spm_clk_gating_enable(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + /*turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + /*CONSYS_REG_WRITE((conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET), CONSYS_PWRON_CONFG_EN_VALUE);*/ +#else + /*turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE(CONSYS_PWRON_CONFG_EN_REG, CONSYS_PWRON_CONFG_EN_VALUE); +#endif +} + +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + INT32 iRet = -1; +#endif + + if (enable) { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE +#if defined(CONFIG_MTK_CLKMGR) + iRet = conn_power_on(); /* consult clkmgr owner. */ + if (iRet) + WMT_PLAT_PR_ERR("conn_power_on fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("conn_power_on ok\n"); +#else + iRet = clk_prepare_enable(clk_scp_conn_main); + if (iRet) + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_scp_conn_main) fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_scp_conn_main) ok\n"); +#endif /* defined(CONFIG_MTK_LEGACY) */ + +#else + +#ifdef CONFIG_OF /*use DT */ + /*2.write conn_top1_pwr_on=1, power on conn_top1 0x1000632c [2] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_BIT); + /*3.read conn_top1_pwr_on_ack =1, power on ack ready 0x10006180 [1] */ + while (0 == (CONSYS_PWR_ON_ACK_BIT & CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET))) + NULL; + /*5.write conn_top1_pwr_on_s=1, power on conn_top1 0x1000632c [3] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_S_BIT); + /*6.write conn_clk_dis=0, enable connsys clock 0x1000632c [4] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_CLK_CTRL_BIT); + /*7.wait 1us */ + udelay(1); + /*8.read conn_top1_pwr_on_ack_s =1, power on ack ready 0x10006184 [1] */ + while (0 == (CONSYS_PWR_CONN_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET))) + NULL; + /*9.release connsys ISO, conn_top1_iso_en=0 0x1000632c [1] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_ISO_S_BIT); + /*10.release SW reset of connsys, conn_ap_sw_rst_b=1 0x1000632c[0] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_RST_BIT); + /*disable AXI BUS protect 0x10001220[13] [14] */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) & + ~CONSYS_PROT_MASK); + while (CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_STA1_OFFSET) & CONSYS_PROT_MASK) + NULL; +#else + /*2.write conn_top1_pwr_on=1, power on conn_top1 0x10006280 [2] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ON_BIT); + /*3.read conn_top1_pwr_on_ack =1, power on ack ready 0x1000660C [1] */ + while (0 == (CONSYS_PWR_ON_ACK_BIT & CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_REG))) + NULL; + /*5.write conn_top1_pwr_on_s=1, power on conn_top1 0x10006280 [3] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ON_S_BIT); + /*6.write conn_clk_dis=0, enable connsys clock 0x10006280 [4] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_CLK_CTRL_BIT); + /*7.wait 1us */ + udelay(1); + /*8.read conn_top1_pwr_on_ack_s =1, power on ack ready 0x10006610 [1] */ + while (0 == (CONSYS_PWR_CONN_ACK_S_BIT & CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_S_REG))) + NULL; + /*9.release connsys ISO, conn_top1_iso_en=0 0x10006280 [1] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_SPM_PWR_ISO_S_BIT); + /*10.release SW reset of connsys, conn_ap_sw_rst_b=1 0x10006280[0] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_RST_BIT); + /*disable AXI BUS protect */ + CONSYS_REG_WRITE(CONSYS_TOPAXI_PROT_EN, CONSYS_REG_READ(CONSYS_TOPAXI_PROT_EN) & ~CONSYS_PROT_MASK); + while (CONSYS_REG_READ(CONSYS_TOPAXI_PROT_STA1) & CONSYS_PROT_MASK) + NULL; +#endif /* CONFIG_OF */ +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } else { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE +#if defined(CONFIG_MTK_CLKMGR) + /*power off connsys by API (MT6582, MT6572 are different) API: conn_power_off() */ + iRet = conn_power_off(); /* consult clkmgr owner */ + if (iRet) + WMT_PLAT_PR_ERR("conn_power_off fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("conn_power_off ok\n"); +#else + clk_disable_unprepare(clk_scp_conn_main); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_scp_conn_main) calling\n"); +#endif /* defined(CONFIG_MTK_LEGACY) */ + +#else + +#ifdef CONFIG_OF /*use DT */ + { + INT32 count = 0; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) | + CONSYS_PROT_MASK); + while ((CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_STA1_OFFSET) & + CONSYS_PROT_MASK) != CONSYS_PROT_MASK) { + count++; + if (count > 1000) + break; + } + } + /*release connsys ISO, conn_top1_iso_en=1 0x1000632c [1] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ISO_S_BIT); + /*assert SW reset of connsys, conn_ap_sw_rst_b=0 0x1000632c[0] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x1000632c [4] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632c [3:2] 2'b00 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#else + { + INT32 count = 0; + + CONSYS_REG_WRITE(CONSYS_TOPAXI_PROT_EN, + CONSYS_REG_READ(CONSYS_TOPAXI_PROT_EN) | CONSYS_PROT_MASK); + while ((CONSYS_REG_READ(CONSYS_TOPAXI_PROT_STA1) & CONSYS_PROT_MASK) != CONSYS_PROT_MASK) { + count++; + if (count > 1000) + break; + } + + } + /*release connsys ISO, conn_top1_iso_en=1 0x1000632c [1] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ISO_S_BIT); + /*assert SW reset of connsys, conn_ap_sw_rst_b=0 0x1000632c[0] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x1000632c [4] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632c [3:2] 2'b00 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#endif /* CONFIG_OF */ +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } + +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + return iRet; +#else + return 0; +#endif +} + +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable) +{ + return 0; +} + +static INT32 polling_consys_chipid(VOID) +{ + UINT32 retry = 10; + UINT32 consysHwChipId = 0; + +#ifdef CONFIG_OF /*use DT */ + /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ + while (retry-- > 0) { + consysHwChipId = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CHIP_ID_OFFSET); + if (consysHwChipId == 0x0551) { + WMT_PLAT_PR_INFO("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + msleep(20); + } + + if ((retry == 0) || (consysHwChipId == 0)) { + WMT_PLAT_PR_ERR("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + WMT_PLAT_PR_INFO("reg dump:CONSYS_CPU_SW_RST_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_S_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_TOP1_PWR_CTRL_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET)); + } +#else + /*12.poll CONNSYS CHIP ID until 6757 is returned 0x18070008 32'h6757 */ + while (retry-- > 0) { + WMT_PLAT_PR_DBG("CONSYS_CHIP_ID_REG(0x%08x)", CONSYS_REG_READ(CONSYS_CHIP_ID_REG)); + consysHwChipId = CONSYS_REG_READ(CONSYS_CHIP_ID_REG); + if (consysHwChipId == 0x0551) { + WMT_PLAT_PR_INFO("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + msleep(20); + } + + if ((retry == 0) || (consysHwChipId == 0)) { + WMT_PLAT_PR_ERR("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + WMT_PLAT_PR_INFO("reg dump:CONSYS_CPU_SW_RST_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_S_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_S_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_TOP1_PWR_CTRL_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG)); + } +#endif + return 0; +} + +static VOID consys_acr_reg_setting(VOID) +{ + /* + *14.write 1 to conn_mcu_confg ACR[1] if real speed MBIST + *(default write "1") ACR 0x18070110[18] 1'b1 + *if this bit is 0, HW will do memory auto test under low CPU frequence (26M Hz) + *if this bit is 0, HW will do memory auto test under high CPU frequence(138M Hz) + *inclulding low CPU frequence + */ +#ifdef CONFIG_OF /*use DT */ + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET, + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET) | + CONSYS_MCU_CFG_ACR_MBIST_BIT); +#else + CONSYS_REG_WRITE(CONSYS_MCU_CFG_ACR_REG, + CONSYS_REG_READ(CONSYS_MCU_CFG_ACR_REG) | CONSYS_MCU_CFG_ACR_MBIST_BIT); +#endif +} + +static VOID consys_afe_reg_setting(VOID) +{ +#if CONSYS_AFE_REG_SETTING + UINT8 *consys_afe_reg_base = NULL; + UINT8 i = 0; + + /*15.default no need,update ANA_WBG(AFE) CR if needed, CONSYS_AFE_REG */ + consys_afe_reg_base = ioremap(CONSYS_AFE_REG_BASE, 0x100); + if (consys_afe_reg_base) { + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_REG_WBG_AFE_01_OFFSET, + CONSYS_AFE_REG_WBG_AFE_01_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_REG_WBG_PLL_03_OFFSET, + CONSYS_AFE_REG_WBG_PLL_03_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_REG_WBG_PLL_05_OFFSET, + CONSYS_AFE_REG_WBG_PLL_05_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_REG_WBG_WB_TX_01_OFFSET, + CONSYS_AFE_REG_WBG_WB_TX_01_VALUE); + + WMT_PLAT_PR_DBG("Dump AFE register\n"); + for (i = 0; i < 64; i++) { + WMT_PLAT_PR_DBG("reg:0x%08x|val:0x%08x\n", CONSYS_AFE_REG_BASE + 4*i, + CONSYS_REG_READ(consys_afe_reg_base + 4*i)); + } + iounmap(consys_afe_reg_base); + } else + WMT_PLAT_PR_ERR("AFE base(0x%x) ioremap fail!\n", CONSYS_AFE_REG_BASE); +#endif +} + +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*need PMIC driver provide new API protocol */ + /*1.AP power on VCN_1V8 LDO (with PMIC_WRAP API) VCN_1V8 */ +#if defined(CONFIG_MTK_PMIC_CHIP_MT6355) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN18_ON_CTRL, 0); +#endif + /* VOL_DEFAULT, VOL_1200, VOL_1300, VOL_1500, VOL_1800... */ +#if defined(CONFIG_MTK_LEGACY) + hwPowerOn(MT6351_POWER_LDO_VCN18, VOL_1800 * 1000, "wcn_drv"); +#else + if (reg_VCN18) { + regulator_set_voltage(reg_VCN18, 1800000, 1800000); + if (regulator_enable(reg_VCN18)) + WMT_PLAT_PR_ERR("enable VCN18 fail\n"); + else + WMT_PLAT_PR_DBG("enable VCN18 ok\n"); + } +#endif +#if defined(CONFIG_MTK_PMIC_CHIP_MT6355) + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#endif + } else { +#if defined(CONFIG_MTK_PMIC_CHIP_MT6355) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); +#endif + /*AP power off MT6351L VCN_1V8 LDO */ +#if defined(CONFIG_MTK_PMIC_CHIP_MT6355) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN18_ON_CTRL, 0); +#endif +#if defined(CONFIG_MTK_LEGACY) + hwPowerDown(MT6351_POWER_LDO_VCN18, "wcn_drv"); +#else + if (reg_VCN18) { + if (regulator_disable(reg_VCN18)) + WMT_PLAT_PR_ERR("disable VCN_1V8 fail!\n"); + else + WMT_PLAT_PR_DBG("disable VCN_1V8 ok\n"); + } +#endif + } +#endif + return 0; +} + +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { +#if defined(CONFIG_MTK_PMIC_CHIP_MT6355) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN28_ON_CTRL, 1); +#endif + } else { +#if defined(CONFIG_MTK_PMIC_CHIP_MT6355) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN28_ON_CTRL, 0); +#endif +} +#endif +} + +static INT32 consys_hw_vcn28_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*in co-clock mode,need to turn on vcn28 when fm on */ + if (reg_VCN28) { + regulator_set_voltage(reg_VCN28, 2800000, 2800000); + if (regulator_enable(reg_VCN28)) + WMT_PLAT_PR_ERR("WMT do VCN28 PMIC on fail!\n"); + } + WMT_PLAT_PR_INFO("turn on vcn28 for fm/gps usage in co-clock mode\n"); + } else { + /*in co-clock mode,need to turn off vcn28 when fm off */ + if (reg_VCN28) + regulator_disable(reg_VCN28); + WMT_PLAT_PR_INFO("turn off vcn28 for fm/gps usage in co-clock mode\n"); + } +#endif + return 0; +} + +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable) +{ +#if !defined(CONFIG_MTK_PMIC_CHIP_MT6355) + if (enable) { + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ +#if defined(CONFIG_MTK_LEGACY) + hwPowerOn(MT6351_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); +#else + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_ERR_FUNC("WMT do BT PMIC on fail!\n"); + } +#endif + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_BT, 1); +#endif + WMT_PLAT_DBG_FUNC("WMT do BT PMIC on\n"); + } else { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_BT, 0); +#if defined(CONFIG_MTK_LEGACY) + hwPowerDown(MT6351_POWER_LDO_VCN33_BT, "wcn_drv"); +#else + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); +#endif +#endif + WMT_PLAT_DBG_FUNC("WMT do BT PMIC off\n"); + } +#endif + return 0; +} + +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable) +{ +#if !defined(CONFIG_MTK_PMIC_CHIP_MT6355) + if (enable) { + /*do WIFI PMIC on,depenency PMIC API ready */ + /*switch WIFI PALDO control from SW mode to HW mode:0x418[14]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE +#if defined(CONFIG_MTK_LEGACY) + hwPowerOn(MT6351_POWER_LDO_VCN33_WIFI, VOL_3300 * 1000, "wcn_drv"); +#else + if (reg_VCN33_WIFI) { + regulator_set_voltage(reg_VCN33_WIFI, 3300000, 3300000); + if (regulator_enable(reg_VCN33_WIFI)) + WMT_PLAT_ERR_FUNC("WMT do WIFI PMIC on fail!\n"); + } +#endif + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_WIFI, 1); +#endif + WMT_PLAT_DBG_FUNC("WMT do WIFI PMIC on\n"); + } else { + /*do WIFI PMIC off */ + /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_WIFI, 0); +#if defined(CONFIG_MTK_LEGACY) + hwPowerDown(MT6351_POWER_LDO_VCN33_WIFI, "wcn_drv"); +#else + if (reg_VCN33_WIFI) + regulator_disable(reg_VCN33_WIFI); +#endif + +#endif + WMT_PLAT_DBG_FUNC("WMT do WIFI PMIC off\n"); + } + +#endif + return 0; +} + +static INT32 consys_emi_mpu_set_region_protection(VOID) +{ +#if CONSYS_EMI_MPU_SETTING + /*set MPU for EMI share Memory */ + WMT_PLAT_PR_INFO("setting MPU for EMI share memory\n"); + + emi_mpu_set_region_protection(gConEmiPhyBase + SZ_1M / 2, + gConEmiPhyBase + gConEmiSize - 1, + 13, + SET_ACCESS_PERMISSON(FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, NO_PROTECTION, FORBIDDEN, NO_PROTECTION)); +#endif + return 0; +} + +static UINT32 consys_emi_set_remapping_reg(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + UINT32 addrPhy = 0; + + /*consys to ap emi remapping register:10001380, cal remapping address */ + addrPhy = (gConEmiPhyBase >> 21) & 0x0FFF; + + /*enable consys to ap emi remapping bit12 */ + addrPhy = addrPhy | 0x1000; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); + + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); +#endif + return 0; +} + +static INT32 bt_wifi_share_v33_spin_lock_init(VOID) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + gBtWifiV33.counter = 0; + spin_lock_init(&gBtWifiV33.lock); +#endif + return 0; +} + +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag) +{ +#ifdef CONFIG_OF /*use DT */ + struct device_node *node; + UINT32 irq_info[3] = { 0, 0, 0 }; + + INT32 iret = -1; + + node = pdev->dev.of_node; + if (node) { + *irq_num = irq_of_parse_and_map(node, 0); + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + WMT_PLAT_PR_ERR("get irq flags from DTS fail!!\n"); + return iret; + } + *irq_flag = irq_info[2]; + WMT_PLAT_PR_INFO("get irq id(%d) and irq trigger flag(%d) from DT\n", *irq_num, + *irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iret; + } +#endif + return 0; +} + +static INT32 consys_read_reg_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ + INT32 iRet = -1; + struct device_node *node = NULL; + + node = pdev->dev.of_node; + if (node) { + /* registers base address */ + conn_reg.mcu_base = (SIZE_T) of_iomap(node, 0); + WMT_PLAT_PR_DBG("Get mcu register base(0x%zx)\n", conn_reg.mcu_base); + conn_reg.ap_rgu_base = (SIZE_T) of_iomap(node, 1); + WMT_PLAT_PR_DBG("Get ap_rgu register base(0x%zx)\n", conn_reg.ap_rgu_base); + conn_reg.topckgen_base = (SIZE_T) of_iomap(node, 2); + WMT_PLAT_PR_DBG("Get topckgen register base(0x%zx)\n", conn_reg.topckgen_base); + conn_reg.spm_base = (SIZE_T) of_iomap(node, 3); + WMT_PLAT_PR_DBG("Get spm register base(0x%zx)\n", conn_reg.spm_base); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iRet; + } +#endif + return 0; +} + +static VOID force_trigger_assert_debug_pin(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + usleep_range(64, 96); + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); +#endif +} + +static UINT32 consys_read_cpupcr(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CPUPCR_OFFSET); +#endif +} + +static UINT32 consys_soc_chipid_get(VOID) +{ + return PLATFORM_SOC_CHIP; +} + +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID) +{ + return &mtk_wcn_emi_addr_info; +} + +P_WMT_CONSYS_IC_OPS mtk_wcn_get_consys_ic_ops(VOID) +{ + return &consys_ic_ops; +} + +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable) +{ + if (enable) { + *addr = ioremap(gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET, CONSYS_EMI_MEM_SIZE); + if (*addr) { + WMT_PLAT_PR_INFO("COREDUMP EMI mapping OK virtual(0x%p) physical(0x%x)\n", + *addr, (UINT32) gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET); + memset_io(*addr, 0, CONSYS_EMI_MEM_SIZE); + } else { + WMT_PLAT_PR_ERR("EMI mapping fail\n"); + return -1; + } + } else { + if (*addr) { + iounmap(*addr); + *addr = NULL; + } + } + return 0; +} + +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr) +{ + if (!addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + WMT_PLAT_PR_INFO("Reset EMI(0xF0080000 ~ 0xF0080400) and (0xF0088400 ~ 0xF0090400)\n"); + /* reset 0xF0080000 ~ 0xF0080400 (1K) */ + memset_io(addr, 0, 0x400); + /* reset 0xF0088400 ~ 0xF0090400 (32K) */ + memset_io(addr + CONSYS_EMI_PAGED_DUMP_OFFSET, 0, 0x8000); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6761.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6761.c new file mode 100644 index 00000000000000..ceaa3765a87525 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6761.c @@ -0,0 +1,1341 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <connectivity_build_in_adapter.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/memblock.h> +#include <linux/platform_device.h> +#include "connsys_debug_utility.h" +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +#include "fw_log_wmt.h" +#endif +#include "osal_typedef.h" +#include "mt6761.h" +#include "mtk_wcn_consys_hw.h" +#include "wmt_ic.h" +#include "wmt_lib.h" +#include "stp_dbg.h" + +#ifdef CONFIG_MTK_EMI +#include <mt_emi_api.h> +#endif + +#if CONSYS_PMIC_CTRL_ENABLE +#include <upmu_common.h> +#include <linux/regulator/consumer.h> +#endif + +#ifdef CONFIG_MTK_HIBERNATION +#include <mtk_hibernate_dpm.h> +#endif + +#include <linux/of_reserved_mem.h> + +#include <mtk_clkbuf_ctl.h> + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable); +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable); +static VOID consys_hw_spm_clk_gating_enable(VOID); +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable); +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable); +static INT32 polling_consys_chipid(VOID); +static VOID consys_acr_reg_setting(VOID); +static VOID consys_afe_reg_setting(VOID); +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable); +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable); +static INT32 consys_hw_vcn28_ctrl(UINT32 enable); +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable); +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable); +static UINT32 consys_soc_chipid_get(VOID); +static INT32 consys_emi_mpu_set_region_protection(VOID); +static UINT32 consys_emi_set_remapping_reg(VOID); +static INT32 bt_wifi_share_v33_spin_lock_init(VOID); +static INT32 consys_clk_get_from_dts(struct platform_device *pdev); +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev); +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag); +static INT32 consys_read_reg_from_dts(struct platform_device *pdev); +static UINT32 consys_read_cpupcr(VOID); +static VOID force_trigger_assert_debug_pin(VOID); +static INT32 consys_co_clock_type(VOID); +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID); +static VOID consys_set_if_pinmux(MTK_WCN_BOOL enable); +static INT32 consys_dl_rom_patch(UINT32 ip_ver, UINT32 fw_ver); +static VOID consys_set_dl_rom_patch_flag(INT32 flag); +static INT32 consys_dedicated_log_path_init(struct platform_device *pdev); +static VOID consys_dedicated_log_path_deinit(VOID); +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable); +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr); +static INT32 consys_check_reg_readable(VOID); +static PUINT32 consys_resume_dump_info(VOID); +static VOID consys_clock_fail_dump(VOID); +static VOID consys_set_pdma_axi_rready_force_high(UINT32 enable); +static VOID consys_get_ant_sel_cr_addr(PUINT32 default_invert_cr, PUINT32 default_invert_bit); +static INT32 consys_calibration_backup_restore_support(VOID); +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status gBtWifiV33; +#endif + +/* CCF part */ +struct clk *clk_scp_conn_main; /*ctrl conn_power_on/off */ + +/* PMIC part */ +#if CONSYS_PMIC_CTRL_ENABLE +struct regulator *reg_VCN18; +struct regulator *reg_VCN28; +struct regulator *reg_VCN33_BT; +struct regulator *reg_VCN33_WIFI; +#endif + +EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { + .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, + .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, + .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, + .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, + .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, + .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, + .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, + .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, + .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, + .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, + .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, + .emi_apmem_ctrl_chip_page_dump_num = EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM, + .emi_apmem_ctrl_assert_flag = EXP_APMEM_CTRL_ASSERT_FLAG, +}; + +CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { + .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, + .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, + .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, + .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, + .emi_remap_offset = CONSYS_EMI_MAPPING_OFFSET, + .emi_core_dump_offset = CONSYS_EMI_COREDUMP_OFFSET, + .p_ecso = &mtk_wcn_emi_state_off, + .pda_dl_patch_flag = 1, + .emi_met_size = 0x50000, + .emi_met_data_offset = CONSYS_EMI_MET_DATA_OFFSET, +}; + +WMT_CONSYS_IC_OPS consys_ic_ops = { + .consys_ic_clock_buffer_ctrl = consys_clock_buffer_ctrl, + .consys_ic_hw_reset_bit_set = consys_hw_reset_bit_set, + .consys_ic_hw_spm_clk_gating_enable = consys_hw_spm_clk_gating_enable, + .consys_ic_hw_power_ctrl = consys_hw_power_ctrl, + .consys_ic_ahb_clock_ctrl = consys_ahb_clock_ctrl, + .polling_consys_ic_chipid = polling_consys_chipid, + .consys_ic_acr_reg_setting = consys_acr_reg_setting, + .consys_ic_afe_reg_setting = consys_afe_reg_setting, + .consys_ic_hw_vcn18_ctrl = consys_hw_vcn18_ctrl, + .consys_ic_vcn28_hw_mode_ctrl = consys_vcn28_hw_mode_ctrl, + .consys_ic_hw_vcn28_ctrl = consys_hw_vcn28_ctrl, + .consys_ic_hw_wifi_vcn33_ctrl = consys_hw_wifi_vcn33_ctrl, + .consys_ic_hw_bt_vcn33_ctrl = consys_hw_bt_vcn33_ctrl, + .consys_ic_soc_chipid_get = consys_soc_chipid_get, + .consys_ic_emi_mpu_set_region_protection = consys_emi_mpu_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .ic_bt_wifi_share_v33_spin_lock_init = bt_wifi_share_v33_spin_lock_init, + .consys_ic_clk_get_from_dts = consys_clk_get_from_dts, + .consys_ic_pmic_get_from_dts = consys_pmic_get_from_dts, + .consys_ic_read_irq_info_from_dts = consys_read_irq_info_from_dts, + .consys_ic_read_reg_from_dts = consys_read_reg_from_dts, + .consys_ic_read_cpupcr = consys_read_cpupcr, + .ic_force_trigger_assert_debug_pin = force_trigger_assert_debug_pin, + .consys_ic_co_clock_type = consys_co_clock_type, + .consys_ic_soc_get_emi_phy_add = consys_soc_get_emi_phy_add, + .consys_ic_set_if_pinmux = consys_set_if_pinmux, + .consys_ic_set_dl_rom_patch_flag = consys_set_dl_rom_patch_flag, + .consys_ic_dedicated_log_path_init = consys_dedicated_log_path_init, + .consys_ic_dedicated_log_path_deinit = consys_dedicated_log_path_deinit, + .consys_ic_emi_coredump_remapping = consys_emi_coredump_remapping, + .consys_ic_reset_emi_coredump = consys_reset_emi_coredump, + .consys_ic_check_reg_readable = consys_check_reg_readable, + .consys_ic_resume_dump_info = consys_resume_dump_info, + .consys_ic_clock_fail_dump = consys_clock_fail_dump, + .consys_ic_set_pdma_axi_rready_force_high = consys_set_pdma_axi_rready_force_high, + .consys_ic_get_ant_sel_cr_addr = consys_get_ant_sel_cr_addr, + .consys_ic_calibration_backup_restore = consys_calibration_backup_restore_support, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 rom_patch_dl_flag = 1; +UINT32 gJtagCtrl; +UINT32 g_connsys_lp_dump_info[2]; + +#if CONSYS_ENALBE_SET_JTAG +#define JTAG_ADDR1_BASE 0x10005000 +#define JTAG_ADDR2_BASE 0x11E80000 +#define JTAG_ADDR3_BASE 0x11D20000 +#define AP2CONN_JTAG_2WIRE_OFFSET 0xF00 +#endif + +INT32 mtk_wcn_consys_jtag_set_for_mcu(VOID) +{ +#if CONSYS_ENALBE_SET_JTAG + INT32 ret = 0; + UINT32 tmp = 0; + PVOID addr = 0; + PVOID remap_addr1 = 0; + PVOID remap_addr2 = 0; + PVOID remap_addr3 = 0; + + if (gJtagCtrl) { + + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + ret = -1; + goto error; + } + + remap_addr2 = ioremap(JTAG_ADDR2_BASE, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + ret = -1; + goto error; + } + + remap_addr3 = ioremap(JTAG_ADDR3_BASE, 0x100); + if (remap_addr3 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr3 fail!\n"); + ret = -1; + goto error; + } + + WMT_PLAT_PR_INFO("WCN jtag set for mcu start...\n"); + switch (gJtagCtrl) { + case 1: + /* 7-wire jtag pinmux setting*/ +#if 1 + /* PAD AUX Function Selection */ + addr = remap_addr1 + 0x320; + tmp = readl(addr); + tmp = tmp & 0x0000000f; + tmp = tmp | 0x33333330; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD Driving Selection */ + addr = remap_addr2 + 0xA0; + tmp = readl(addr); + tmp = tmp & 0xfff00fff; + tmp = tmp | 0x00077000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD PULL Selection */ + addr = remap_addr2 + 0x60; + tmp = readl(addr); + tmp = tmp & 0xfffe03ff; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr2 + 0x60; + tmp = readl(addr); + tmp = tmp & 0xfff80fff; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + +#else + /* backup */ + /* PAD AUX Function Selection */ + addr = remap_addr1 + 0x310; + tmp = readl(addr); + tmp = tmp & 0xfffff000; + tmp = tmp | 0x00000444; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr1 + 0x3C0; + tmp = readl(addr); + tmp = tmp & 0xf00ff00f; + tmp = tmp | 0x04400440; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD Driving Selection */ + addr = remap_addr3 + 0xA0; + tmp = readl(addr); + tmp = tmp & 0x0ffffff0; + tmp = tmp | 0x70000007; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr3 + 0xB0; + tmp = readl(addr); + tmp = tmp & 0xfff0f0ff; + tmp = tmp | 0x0007070f; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD PULL Selection */ + addr = remap_addr3 + 0x60; + tmp = readl(addr); + tmp = tmp & 0xf333fffe; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); +#endif + break; + case 2: + /* 2-wire jtag pinmux setting*/ +#if 0 + CONSYS_SET_BIT(conn_reg.topckgen_base + AP2CONN_JTAG_2WIRE_OFFSET, 1 << 8); + addr = remap_addr1 + 0x340; + tmp = readl(addr); + tmp = tmp & 0xfff88fff; + tmp = tmp | 0x00034000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); +#endif + break; + default: + WMT_PLAT_PR_INFO("unsupported options!\n"); + } + + } +#endif + +error: + + if (remap_addr1) + iounmap(remap_addr1); + if (remap_addr2) + iounmap(remap_addr2); + if (remap_addr3) + iounmap(remap_addr3); + + return ret; +} + +UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en) +{ + WMT_PLAT_PR_INFO("%s jtag set for MCU\n", en ? "enable" : "disable"); + gJtagCtrl = en; + return 0; +} + +static INT32 consys_clk_get_from_dts(struct platform_device *pdev) +{ + clk_scp_conn_main = devm_clk_get(&pdev->dev, "conn"); + if (IS_ERR(clk_scp_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_scp_conn_main clock.\n"); + return PTR_ERR(clk_scp_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_scp_conn_main=%p\n", clk_scp_conn_main); + + return 0; +} + +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev) +{ +#if CONSYS_PMIC_CTRL_ENABLE + reg_VCN18 = regulator_get(&pdev->dev, "vcn18"); + if (!reg_VCN18) + WMT_PLAT_PR_ERR("Regulator_get VCN_1V8 fail\n"); + reg_VCN28 = regulator_get(&pdev->dev, "vcn28"); + if (!reg_VCN28) + WMT_PLAT_PR_ERR("Regulator_get VCN_2V8 fail\n"); + reg_VCN33_BT = regulator_get(&pdev->dev, "vcn33_bt"); + if (!reg_VCN33_BT) + WMT_PLAT_PR_ERR("Regulator_get VCN33_BT fail\n"); + reg_VCN33_WIFI = regulator_get(&pdev->dev, "vcn33_wifi"); + if (!reg_VCN33_WIFI) + WMT_PLAT_PR_ERR("Regulator_get VCN33_WIFI fail\n"); +#endif + return 0; +} + +static INT32 consys_co_clock_type(VOID) +{ + return 0; +} + +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable) +{ + if (enable) + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, true); /*open XO_WCN*/ + else + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, false); /*close XO_WCN*/ + + return 0; +} + +static VOID consys_set_if_pinmux(MTK_WCN_BOOL enable) +{ + UINT8 *consys_if_pinmux_reg_base = NULL; + + /* Switch D die pinmux for connecting A die */ + consys_if_pinmux_reg_base = ioremap(CONSYS_IF_PINMUX_REG_BASE, 0x1000); + if (!consys_if_pinmux_reg_base) { + WMT_PLAT_PR_ERR("consys_if_pinmux_reg_base(%x) ioremap fail\n", CONSYS_IF_PINMUX_REG_BASE); + return; + } + + if (enable) { + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET) & + CONSYS_IF_PINMUX_01_MASK) | CONSYS_IF_PINMUX_01_VALUE); + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET) & + CONSYS_IF_PINMUX_02_MASK) | CONSYS_IF_PINMUX_02_VALUE); + } else { + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET, + CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET) & + CONSYS_IF_PINMUX_01_MASK); + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET, + CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET) & + CONSYS_IF_PINMUX_02_MASK); + } + + if (consys_if_pinmux_reg_base) + iounmap(consys_if_pinmux_reg_base); +} + +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable) +{ + UINT32 consys_ver_id = 0; + UINT32 cnt = 0; + UINT32 pre_ver_id = 0xFFFFFFFF; + + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE((conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET), + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) | + CONSYS_CPU_SW_RST_BIT | CONSYS_CPU_SW_RST_CTRL_KEY); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88 (key)" */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_CPU_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + 0x600); + while (consys_ver_id != 0x1D1E) { + if (cnt > 10) + break; + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + 0x600); + if (pre_ver_id != consys_ver_id) { + pre_ver_id = consys_ver_id; + WMT_PLAT_PR_INFO("0x18002600(0x%x), 0x1800216c(0x%x), 0x18007104(0x%x)\n", + consys_ver_id, CONSYS_REG_READ(conn_reg.mcu_base + 0x16c), + CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base + CONSYS_CPUPCR_OFFSET)); + } + msleep(20); + cnt++; + } + } +} + +static VOID consys_hw_spm_clk_gating_enable(VOID) +{ +} + +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + INT32 iRet = 0; +#else + INT32 value = 0; + INT32 i = 0; +#endif + + if (enable) { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + iRet = clk_prepare_enable(clk_scp_conn_main); + if (iRet) + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_scp_conn_main) fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_scp_conn_main) ok\n"); +#else + /* turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE((conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET), + (CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET) & + 0x0000FFFF) | CONSYS_PWRON_CONFG_EN_VALUE); + + /*write assert "conn_top_on" primary part power on, set "connsys_on_domain_pwr_on"=1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_BIT); + /*read check "conn_top_on" primary part power status, check "connsys_on_domain_pwr_ack"=1 */ + value = CONSYS_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + while (value == 0) + value = CONSYS_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + /*write assert "conn_top_on" secondary part power on, set "connsys_on_domain_pwr_on_s"=1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_S_BIT); + /*read check "conn_top_on" secondary part power status, check "connsys_on_domain_pwr_ack_s"=1 */ + value = CONSYS_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + while (value == 0) + value = CONSYS_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + /*write turn on AP-to-CONNSYS bus clock, set "conn_clk_dis"=0 (apply this for bus + *clock toggling) + */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_CLK_CTRL_BIT); + /*wait 1us*/ + udelay(1); + /*de-assert "conn_top_on" isolation, set "connsys_iso_en"=0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_ISO_S_BIT); + /*read check "conn_top_off" primary part power status, check + *"connsys_off_domain_pwr_ack"=1 + */ + value = CONSYS_TOP2_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + while (value == 0) + value = CONSYS_TOP2_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + /*read check "conn_top_off" secondary part power status, check + *"connsys_off_domain_pwr_ack_s"=1 + */ + value = CONSYS_TOP2_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + while (value == 0) + value = CONSYS_TOP2_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + + /*de-assert CONNSYS S/W reset, set "ap_sw_rst_b"=1 */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + + /*Turn off AHB bus sleep protect (AP2CONN AHB Bus protect) (apply this for INFRA AHB + *bus accessing when CONNSYS had been turned on) + */ + /*disable AHBAXI BUS protect 10001220 [13][14] */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET) & + ~CONSYS_PROT_MASK); + value = ~CONSYS_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i++; + } + /*Disable AXI TX bus sleep protect (CONN2AP AXI Tx Bus protect) (disable sleep + * protection when CONNSYS had been turned on) + * Note : Should turn off AXI Tx sleep protection after AXI Rx sleep protection has + * been turn off. + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_EN_OFFSET) & + ~CONSYS_TX_PROT_MASK); + value = ~CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_STA_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_STA_OFFSET); + i++; + } + /*SPM apsrc/ddr_en hardware mask disable & wait cycle setting*/ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_SPM_APSRC_OFFSET, CONSYS_SPM_APSRC_VALUE); + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_SPM_DDR_EN_OFFSET, CONSYS_SPM_DDR_EN_VALUE); +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } else { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + clk_disable_unprepare(clk_scp_conn_main); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_scp_conn_main) calling\n"); +#else + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET) & + CONSYS_PROT_MASK); + value = CONSYS_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i = 0; + while (value == CONSYS_PROT_MASK || i > 10) { + value = CONSYS_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i++; + } + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_EN_OFFSET) & + CONSYS_TX_PROT_MASK); + value = CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_STA_OFFSET); + i = 0; + while (value == CONSYS_TX_PROT_MASK || i > 10) { + value = CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_STA_OFFSET); + i++; + } + + /*release connsys ISO, conn_top1_iso_en=1 0x1000632C [1] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ISO_S_BIT); + /*de-assert CONNSYS S/W reset, set "ap_sw_rst_b"=1 */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + CONSYS_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + /*write conn_clk_dis=1, disable connsys clock 0x1000632C [4] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632C [3:2] 2'b00 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } + +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + return iRet; +#else + return 0; +#endif +} + +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable) +{ + return 0; +} + +static INT32 polling_consys_chipid(VOID) +{ + INT32 retry = 10; + UINT32 consys_ver_id = 0; + UINT32 consys_hw_ver = 0; + UINT32 consys_fw_ver = 0; + UINT8 *consys_reg_base = NULL; + UINT32 value = 0; + UINT32 pre_ver_id = 0xFFFFFFFF; + + /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ + while (retry-- > 0) { + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_top_misc_off_base + CONSYS_IP_VER_OFFSET); + if (consys_ver_id == 0x10020300) { + WMT_PLAT_PR_INFO("retry(%d)consys version id(0x%08x)\n", retry, consys_ver_id); + consys_hw_ver = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys HW version id(0x%x)\n", consys_hw_ver & 0xFFFF); + consys_fw_ver = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_FW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys FW version id(0x%x)\n", consys_fw_ver & 0xFFFF); + + if (consys_dl_rom_patch(consys_ver_id, consys_fw_ver) == 0) + break; + } else if (pre_ver_id != consys_ver_id) { + pre_ver_id = consys_ver_id; + WMT_PLAT_PR_ERR("Read CONSYS version id(0x%08x)", consys_ver_id); + } + msleep(20); + } + + if (retry <= 0) + return -1; + + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_top_misc_off_base + CONSYS_CONF_ID_OFFSET); + WMT_PLAT_PR_INFO("consys configuration id(0x%x)\n", consys_ver_id & 0xF); + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys HW version id(0x%x)\n", consys_ver_id & 0xFFFF); + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_FW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys FW version id(0x%x)\n", consys_ver_id & 0xFFFF); + if (wmt_plat_soc_co_clock_flag_get()) { + consys_reg_base = ioremap(CONSYS_COCLOCK_STABLE_TIME_BASE, 0x100); + if (consys_reg_base) { + value = CONSYS_REG_READ(consys_reg_base); + value = (value & CONSYS_COCLOCK_STABLE_TIME_MASK) | CONSYS_COCLOCK_STABLE_TIME; + CONSYS_REG_WRITE(consys_reg_base, value); + value = CONSYS_REG_READ(consys_reg_base + CONSYS_COCLOCK_ACK_ENABLE_OFFSET); + value = value & (~CONSYS_COCLOCK_ACK_ENABLE_BIT); + CONSYS_REG_WRITE(consys_reg_base + CONSYS_COCLOCK_ACK_ENABLE_OFFSET, value); + iounmap(consys_reg_base); + } else + WMT_PLAT_PR_ERR("connsys co_clock stable time base(0x%x) ioremap fail!\n", + CONSYS_COCLOCK_STABLE_TIME_BASE); + } + /* EMI control CR setting(sw mode) */ + CONSYS_SET_BIT(conn_reg.mcu_base + CONSYS_SW_IRQ_OFFSET, CONSYS_EMI_CTRL_VALUE); + return 0; +} + +static VOID consys_acr_reg_setting(VOID) +{ +} + +static VOID consys_afe_reg_setting(VOID) +{ +#if CONSYS_AFE_REG_SETTING + UINT8 *consys_afe_reg_base = NULL; + + /*15.default no need,update ANA_WBG(AFE) CR if needed, CONSYS_AFE_REG */ + consys_afe_reg_base = ioremap(CONSYS_AFE_REG_BASE, 0x100); + if (consys_afe_reg_base) { + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_RG_WBG_01_OFFSET, + CONSYS_AFE_RG_WBG_01_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_RG_WBG_GPS_01_OFFSET, + CONSYS_AFE_RG_WBG_GPS_01_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_RG_WBG_BT_RX_01_OFFSET, + CONSYS_AFE_RG_WBG_BT_RX_01_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_RG_WBG_WF0_RX_01_OFFSET, + CONSYS_AFE_RG_WBG_WF0_RX_01_VALUE); + + iounmap(consys_afe_reg_base); + } else + WMT_PLAT_PR_ERR("AFE base(0x%x) ioremap fail!\n", CONSYS_AFE_REG_BASE); +#endif +} + +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*need PMIC driver provide new API protocol */ + /*1.AP power on VCN_1V8 LDO (with PMIC_WRAP API) VCN_1V8 */ + /*set vcn18 SW mode*/ + KERNEL_upmu_set_reg_value(MT6357_LDO_VCN18_OP_EN, 0x1); + if (reg_VCN18) { + regulator_set_voltage(reg_VCN18, 1800000, 1800000); + if (regulator_enable(reg_VCN18)) + WMT_PLAT_PR_ERR("enable VCN18 fail\n"); + else + WMT_PLAT_PR_DBG("enable VCN18 ok\n"); + } + + KERNEL_upmu_set_reg_value(MT6357_LDO_VCN33_OP_EN, 0x1); + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } + + } else { + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); + + /*AP power off MT6351L VCN_1V8 LDO */ + if (reg_VCN18) { + if (regulator_disable(reg_VCN18)) + WMT_PLAT_PR_ERR("disable VCN_1V8 fail!\n"); + else + WMT_PLAT_PR_DBG("disable VCN_1V8 ok\n"); + } + } +#endif + return 0; +} + +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); + } else { + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); + } +#endif +} + +static INT32 consys_hw_vcn28_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*in co-clock mode,need to turn on vcn28 when fm on */ + if (reg_VCN28) { + regulator_set_voltage(reg_VCN28, 2800000, 2800000); + if (regulator_enable(reg_VCN28)) + WMT_PLAT_PR_ERR("WMT do VCN28 PMIC on fail!\n"); + } + WMT_PLAT_PR_INFO("turn on vcn28 for fm/gps usage in co-clock mode\n"); + } else { + /*in co-clock mode,need to turn off vcn28 when fm off */ + if (reg_VCN28) + regulator_disable(reg_VCN28); + WMT_PLAT_PR_INFO("turn off vcn28 for fm/gps usage in co-clock mode\n"); + } +#endif + return 0; +} + +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable) +{ +#if 0 +#if CONSYS_BT_WIFI_SHARE_V33 + /* spin_lock_irqsave(&gBtWifiV33.lock,gBtWifiV33.flags); */ + if (enable) { + if (gBtWifiV33.counter == 1) { + gBtWifiV33.counter++; + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else if (gBtWifiV33.counter == 2) { + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else { +#if CONSYS_PMIC_CTRL_ENABLE + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + hwPowerOn(MT6351_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); + mt6351_upmu_set_rg_vcn33_on_ctrl(1); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 on\n"); + gBtWifiV33.counter++; + } + + } else { + if (gBtWifiV33.counter == 1) { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + mt6351_upmu_set_rg_vcn33_on_ctrl(0); + hwPowerDown(MT6351_POWER_LDO_VCN33_BT, "wcn_drv"); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 off\n"); + gBtWifiV33.counter--; + } else if (gBtWifiV33.counter == 2) { + gBtWifiV33.counter--; + WMT_PLAT_PR_DBG("V33 no need disabled,counter(%d)\n", gBtWifiV33.counter); + } else { + WMT_PLAT_PR_DBG("V33 has been disabled,counter(%d)\n", gBtWifiV33.counter); + } + + } + /* spin_unlock_irqrestore(&gBtWifiV33.lock,gBtWifiV33.flags); */ +#else + if (enable) { + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } + + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC on\n"); + } else { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC off\n"); + } +#endif + +#endif + return 0; +} + +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable) +{ +#if 0 +#if CONSYS_BT_WIFI_SHARE_V33 + mtk_wcn_consys_hw_bt_paldo_ctrl(enable); +#else + if (enable) { + /*do WIFI PMIC on,depenency PMIC API ready */ + /*switch WIFI PALDO control from SW mode to HW mode:0x418[14]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + if (reg_VCN33_WIFI) { + regulator_set_voltage(reg_VCN33_WIFI, 3300000, 3300000); + if (regulator_enable(reg_VCN33_WIFI)) + WMT_PLAT_PR_ERR("WMT do WIFI PMIC on fail!\n"); + } + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC on\n"); + } else { + /*do WIFI PMIC off */ + /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); + if (reg_VCN33_WIFI) + regulator_disable(reg_VCN33_WIFI); +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC off\n"); + } + +#endif + +#endif + return 0; +} + +static INT32 consys_emi_mpu_set_region_protection(VOID) +{ +#ifdef CONFIG_MTK_EMI + struct emi_region_info_t region_info; + + /*set MPU for EMI share Memory */ + WMT_PLAT_PR_INFO("setting MPU for EMI share memory\n"); + + region_info.start = gConEmiPhyBase; + region_info.end = gConEmiPhyBase + gConEmiSize - 1; + region_info.region = 25; + SET_ACCESS_PERMISSION(region_info.apc, LOCK, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + NO_PROTECTION, FORBIDDEN, NO_PROTECTION); + emi_mpu_set_protection(®ion_info); +#endif + return 0; +} + +static UINT32 consys_emi_set_remapping_reg(VOID) +{ + UINT32 addrPhy = 0; + UINT32 value = 0; + + mtk_wcn_emi_addr_info.emi_ap_phy_addr = gConEmiPhyBase; + mtk_wcn_emi_addr_info.emi_size = gConEmiSize; + + /*consys to ap emi remapping register:10001380, cal remapping address */ + addrPhy = (gConEmiPhyBase >> 24) & 0xFFF; + value = CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET); + WMT_PLAT_PR_INFO("before CONSYS_EMI_MAPPING read:0x%zx, value:0x%x\n", + conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, value); + + value = value & 0xFFFFF000; + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, value | addrPhy); + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); + + /*Perisys Configuration Registers remapping*/ + addrPhy = ((0x10003000 >> 24) & 0xFFF) << 16; + value = CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_PERI_MAPPING_OFFSET); + value = value & 0xF000FFFF; + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_PERI_MAPPING_OFFSET, value | addrPhy); + + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_PERI_MAPPING_OFFSET)); + + mtk_wcn_emi_addr_info.emi_ram_bt_buildtime_offset = + CONSYS_EMI_RAM_BT_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_ram_wifi_buildtime_offset = + CONSYS_EMI_RAM_WIFI_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_ram_mcu_buildtime_offset = + CONSYS_EMI_RAM_MCU_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_patch_mcu_buildtime_offset = + CONSYS_EMI_PATCH_MCU_BUILDTIME_OFFSET; + + return 0; +} + +static INT32 bt_wifi_share_v33_spin_lock_init(VOID) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + gBtWifiV33.counter = 0; + spin_lock_init(&gBtWifiV33.lock); +#endif + return 0; +} + +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag) +{ + struct device_node *node; + + node = pdev->dev.of_node; + if (node) { + *irq_num = irq_of_parse_and_map(node, 0); + *irq_flag = irq_get_trigger_type(*irq_num); + WMT_PLAT_PR_INFO("get irq id(%d) and irq trigger flag(%d) from DT\n", *irq_num, + *irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return -1; + } + + return 0; +} + +static INT32 consys_read_reg_from_dts(struct platform_device *pdev) +{ + INT32 iRet = -1; + struct device_node *node = NULL; + + node = pdev->dev.of_node; + if (node) { + /* registers base address */ + conn_reg.mcu_base = (SIZE_T) of_iomap(node, MCU_BASE_INDEX); + conn_reg.ap_rgu_base = (SIZE_T) of_iomap(node, TOP_RGU_BASE_INDEX); + conn_reg.topckgen_base = (SIZE_T) of_iomap(node, INFRACFG_AO_BASE_INDEX); + conn_reg.spm_base = (SIZE_T) of_iomap(node, SPM_BASE_INDEX); + conn_reg.mcu_top_misc_off_base = (SIZE_T) of_iomap(node, MCU_TOP_MISC_OFF_BASE_INDEX); + conn_reg.mcu_conn_hif_on_base = (SIZE_T) of_iomap(node, MCU_CONN_HIF_ON_BASE_INDEX); + conn_reg.mcu_cfg_on_base = (SIZE_T) of_iomap(node, MCU_CFG_ON_BASE_INDEX); + conn_reg.mcu_cirq_base = (SIZE_T) of_iomap(node, MCU_CIRQ_BASE_INDEX); + conn_reg.mcu_top_misc_on_base = (SIZE_T) of_iomap(node, MCU_TOP_MISC_ON_BASE_INDEX); + conn_reg.mcu_conn_hif_pdma_base = (SIZE_T) of_iomap(node, MCU_CONN_HIF_PDMA_BASE_INDEX); + + WMT_PLAT_PR_DBG("Get base mcu(0x%zx), rgu(0x%zx), topckgen(0x%zx), spm(0x%zx)\n", + conn_reg.mcu_base, conn_reg.ap_rgu_base, + conn_reg.topckgen_base, conn_reg.spm_base); + WMT_PLAT_PR_DBG("Get base misc_off(0x%zx), hif_on(0x%zx), cfg_on(0x%zx), misc_on(0x%zx)\n", + conn_reg.mcu_top_misc_off_base, + conn_reg.mcu_conn_hif_on_base, + conn_reg.mcu_cfg_on_base, + conn_reg.mcu_top_misc_on_base); + WMT_PLAT_PR_DBG("Get hif_pdma(0x%zx)\n", + conn_reg.mcu_conn_hif_pdma_base); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iRet; + } + + return 0; +} + +static VOID force_trigger_assert_debug_pin(VOID) +{ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + usleep_range(64, 96); + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); +} + +static UINT32 consys_read_cpupcr(VOID) +{ + return CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base + CONSYS_CPUPCR_OFFSET); +} + +static UINT32 consys_soc_chipid_get(VOID) +{ + return PLATFORM_SOC_CHIP; +} + +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID) +{ + return &mtk_wcn_emi_addr_info; +} + +P_WMT_CONSYS_IC_OPS mtk_wcn_get_consys_ic_ops(VOID) +{ + return &consys_ic_ops; +} + +static INT32 consys_dl_rom_patch(UINT32 ip_ver, UINT32 fw_ver) +{ + if (rom_patch_dl_flag) { + if (mtk_wcn_soc_rom_patch_dwn(ip_ver, fw_ver) == 0) + rom_patch_dl_flag = 1; + else + return -1; + } + + return 0; +} + +static VOID consys_set_dl_rom_patch_flag(INT32 flag) +{ + rom_patch_dl_flag = flag; +} + +static INT32 consys_dedicated_log_path_init(struct platform_device *pdev) +{ + struct device_node *node; + UINT32 irq_num; + UINT32 irq_flag; + INT32 iret = -1; + + node = pdev->dev.of_node; + if (node) { + irq_num = irq_of_parse_and_map(node, 2); + irq_flag = irq_get_trigger_type(irq_num); + WMT_PLAT_PR_INFO("get conn2ap_sw_irq id(%d) and irq trigger flag(%d) from DT\n", irq_num, + irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iret; + } + + connsys_dedicated_log_path_apsoc_init(gConEmiPhyBase, irq_num, irq_flag); +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + fw_log_wmt_init(); +#endif + return 0; +} + +static VOID consys_dedicated_log_path_deinit(VOID) +{ +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + fw_log_wmt_deinit(); +#endif + connsys_dedicated_log_path_apsoc_deinit(); +} + +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable) +{ + if (enable) { + *addr = ioremap(gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET, CONSYS_EMI_MEM_SIZE); + if (*addr) { + WMT_PLAT_PR_INFO("COREDUMP EMI mapping OK virtual(0x%p) physical(0x%x)\n", + *addr, (UINT32) gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET); + memset_io(*addr, 0, CONSYS_EMI_MEM_SIZE); + } else { + WMT_PLAT_PR_ERR("EMI mapping fail\n"); + return -1; + } + } else { + if (*addr) { + iounmap(*addr); + *addr = NULL; + } + } + return 0; +} + +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr) +{ + if (!addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + WMT_PLAT_PR_INFO("Reset EMI(0xF0068000 ~ 0xF0068400) and (0xF0070400 ~ 0xF0078400)\n"); + /* reset 0xF0068000 ~ 0xF0068400 (1K) */ + memset_io(addr, 0, 0x400); + /* reset 0xF0070400 ~ 0xF0078400 (32K) */ + memset_io(addr + CONSYS_EMI_PAGED_DUMP_OFFSET, 0, 0x8000); + return 0; +} + +static INT32 consys_check_reg_readable(VOID) +{ + INT32 flag = 0; + UINT32 value = 0; + P_DEV_WMT pDev = &gDevWmt; + + if ((wmt_lib_get_drv_status(WMTDRV_TYPE_WMT) == DRV_STS_FUNC_ON) + && (osal_test_bit(WMT_STAT_PWR, &pDev->state))) { + /*check connsys clock and sleep status*/ + CONSYS_REG_WRITE(conn_reg.mcu_conn_hif_on_base, CONSYS_CLOCK_CHECK_VALUE); + udelay(1000); + value = CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base); + if ((value & CONSYS_HCLK_CHECK_BIT) && + (value & CONSYS_OSCCLK_CHECK_BIT) && + ((value & CONSYS_SLEEP_CHECK_BIT) == 0)) + flag = 1; + } + + if (!flag) + WMT_PLAT_PR_ERR("connsys clock check fail 0x18007000(0x%x)\n", value); + + return flag; +} + +static VOID consys_clock_fail_dump(VOID) +{ + WMT_PLAT_PR_ERR("CONN_HIF_TOP_MISC=0x%08x CONN_HIF_BUSY_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_TOP_MISC), + CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_BUSY_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_DBG_IDX, 0x3333); + WMT_PLAT_PR_ERR("Write CONSYS_HIF_DBG_IDX to 0x3333\n"); + + WMT_PLAT_PR_ERR("CONSYS_HIF_DBG_PROBE=0x%08x CONN_HIF_TOP_MISC=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_DBG_PROBE), + CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_TOP_MISC)); + WMT_PLAT_PR_ERR("CONN_HIF_BUSY_STATUS=0x%08x CONN_HIF_PDMA_BUSY_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_BUSY_STATUS), + CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_PDMA_BUSY_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_DBG_IDX, 0x2222); + WMT_PLAT_PR_ERR("Write CONSYS_HIF_DBG_IDX to 0x2222\n"); + + WMT_PLAT_PR_ERR("CONSYS_HIF_DBG_PROBE=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_DBG_PROBE)); + + CONSYS_REG_WRITE(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_DBG_IDX, 0x3333); + WMT_PLAT_PR_ERR("Write CONSYS_HIF_DBG_IDX to 0x3333\n"); + + WMT_PLAT_PR_ERR("CONSYS_HIF_DBG_PROBE=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_DBG_PROBE)); + + CONSYS_REG_WRITE(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_DBG_IDX, 0x4444); + WMT_PLAT_PR_ERR("Write CONSYS_HIF_DBG_IDX to 0x4444\n"); + + WMT_PLAT_PR_ERR("CONSYS_HIF_DBG_PROBE=0x%08x CONN_MCU_EMI_CONTROL=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_DBG_PROBE), + CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_SW_IRQ_OFFSET)); + WMT_PLAT_PR_ERR("CONN_MCU_CLOCK_CONTROL=0x%08x CONN_MCU_BUS_CONTROL=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CLOCK_CONTROL), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_BUS_CONTROL)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x003e3d00); + WMT_PLAT_PR_ERR("Write CONSYS_DEBUG_SELECT to 0x003e3d00\n"); + + WMT_PLAT_PR_ERR("CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x00403f00); + WMT_PLAT_PR_ERR("Write CONSYS_DEBUG_SELECT to 0x00403f00\n"); + + WMT_PLAT_PR_ERR("CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x00424100); + WMT_PLAT_PR_ERR("Write CONSYS_DEBUG_SELECT to 0x00424100\n"); + + WMT_PLAT_PR_ERR("CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x00444300); + WMT_PLAT_PR_ERR("Write CONSYS_DEBUG_SELECT to 0x00444300\n"); + + WMT_PLAT_PR_ERR("CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + WMT_PLAT_PR_ERR("CONN_ON_HOST_CSR_MISC=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_top_misc_on_base + CONN_ON_HOST_CSR_MISC)); + + WMT_PLAT_PR_ERR("CONN_ON_IRQ_CTL=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_top_misc_on_base + CONN_ON_IRQ_CTL)); + + WMT_PLAT_PR_ERR("CONN_ON_IRQ_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_top_misc_on_base + CONN_ON_IRQ_STATUS)); +} + +static PUINT32 consys_resume_dump_info(VOID) +{ + if (conn_reg.mcu_cfg_on_base != 0 && + conn_reg.mcu_top_misc_on_base != 0 && + mtk_consys_check_reg_readable()) { + stp_dbg_clear_cpupcr_reg_info(); + stp_dbg_poll_cpupcr(5, 0, 1); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR, 0x1); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_MON_CTL_ADDR, 0x80000001); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_DBGSEL_ADDR, 0x3); + g_connsys_lp_dump_info[0] = (UINT32)CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_MAPPING_AP_ADDR; + g_connsys_lp_dump_info[1] = CONSYS_REG_READ(CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_ADDR); + WMT_PLAT_PR_INFO("0x%08x: 0x%x\n", g_connsys_lp_dump_info[0], g_connsys_lp_dump_info[1]); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR, 0x0); + return &g_connsys_lp_dump_info[0]; + } + return NULL; +} + +static VOID consys_set_pdma_axi_rready_force_high(UINT32 enable) +{ + if (enable) + CONSYS_SET_BIT(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_PDMA_AXI_RREADY, + CONSYS_PDMA_AXI_RREADY_MASK); + else if ((CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_PDMA_AXI_RREADY) & + CONSYS_PDMA_AXI_RREADY_MASK) != 0) + CONSYS_CLR_BIT(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_PDMA_AXI_RREADY, + CONSYS_PDMA_AXI_RREADY_MASK); +} + +static VOID consys_get_ant_sel_cr_addr(PUINT32 default_invert_cr, PUINT32 default_invert_bit) +{ + if (default_invert_cr) { + default_invert_cr[0] = DEFAULT_COEX_WMT_ANTSEL_0_POLARITY_CR; + default_invert_cr[1] = DEFAULT_COEX_WMT_ANTSEL_1_POLARITY_CR; + default_invert_cr[2] = DEFAULT_COEX_WMT_ANTSEL_2_POLARITY_CR; + default_invert_cr[3] = DEFAULT_COEX_WMT_ANTSEL_3_POLARITY_CR; + default_invert_cr[4] = DEFAULT_COEX_WMT_ANTSEL_4_POLARITY_CR; + default_invert_cr[5] = DEFAULT_COEX_WMT_ANTSEL_5_POLARITY_CR; + default_invert_cr[6] = DEFAULT_COEX_WMT_ANTSEL_6_POLARITY_CR; + default_invert_cr[7] = DEFAULT_COEX_WMT_ANTSEL_7_POLARITY_CR; + } + + if (default_invert_bit) { + default_invert_bit[0] = DEFAULT_COEX_WMT_ANTSEL_0_POLARITY_BIT; + default_invert_bit[1] = DEFAULT_COEX_WMT_ANTSEL_1_POLARITY_BIT; + default_invert_bit[2] = DEFAULT_COEX_WMT_ANTSEL_2_POLARITY_BIT; + default_invert_bit[3] = DEFAULT_COEX_WMT_ANTSEL_3_POLARITY_BIT; + default_invert_bit[4] = DEFAULT_COEX_WMT_ANTSEL_4_POLARITY_BIT; + default_invert_bit[5] = DEFAULT_COEX_WMT_ANTSEL_5_POLARITY_BIT; + default_invert_bit[6] = DEFAULT_COEX_WMT_ANTSEL_6_POLARITY_BIT; + default_invert_bit[7] = DEFAULT_COEX_WMT_ANTSEL_7_POLARITY_BIT; + } +} + +static INT32 consys_calibration_backup_restore_support(VOID) +{ + return 1; +} + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6763.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6763.c new file mode 100644 index 00000000000000..d329794da6cb7f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6763.c @@ -0,0 +1,1178 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <connectivity_build_in_adapter.h> + +#if defined(CONFIG_MTK_CLKMGR) +#include <mtk_clkmgr.h> +#else +#include <linux/clk.h> +#endif /* defined(CONFIG_MTK_LEGACY) */ +#include <linux/delay.h> +#include <linux/memblock.h> +#include <linux/platform_device.h> +#include "osal_typedef.h" +#include "mt6763.h" +#include "mtk_wcn_consys_hw.h" + +#if CONSYS_EMI_MPU_SETTING +#include <mt_emi_api.h> +#endif + +#if CONSYS_PMIC_CTRL_ENABLE +#include <upmu_common.h> +#include <linux/regulator/consumer.h> +#endif + +#ifdef CONFIG_MTK_HIBERNATION +#include <mtk_hibernate_dpm.h> +#endif + +#include <linux/of_reserved_mem.h> + +#if CONSYS_CLOCK_BUF_CTRL +#include <mtk_clkbuf_ctl.h> +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable); +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable); +static VOID consys_hw_spm_clk_gating_enable(VOID); +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable); +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable); +static INT32 polling_consys_chipid(VOID); +static VOID consys_acr_reg_setting(VOID); +static VOID consys_afe_reg_setting(VOID); +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable); +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable); +static INT32 consys_hw_vcn28_ctrl(UINT32 enable); +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable); +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable); +static UINT32 consys_soc_chipid_get(VOID); +static INT32 consys_emi_mpu_set_region_protection(VOID); +static UINT32 consys_emi_set_remapping_reg(VOID); +static INT32 bt_wifi_share_v33_spin_lock_init(VOID); +static INT32 consys_clk_get_from_dts(struct platform_device *pdev); +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev); +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag); +static INT32 consys_read_reg_from_dts(struct platform_device *pdev); +static UINT32 consys_read_cpupcr(VOID); +static VOID force_trigger_assert_debug_pin(VOID); +static INT32 consys_co_clock_type(VOID); +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID); +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable); +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status gBtWifiV33; +#endif + +/* CCF part */ +#if !defined(CONFIG_MTK_CLKMGR) +struct clk *clk_scp_conn_main; /*ctrl conn_power_on/off */ +/* struct clk *clk_infra_conn_main; */ /*ctrl infra_connmcu_bus clk */ +#endif /* !defined(CONFIG_MTK_LEGACY) */ + + +/* PMIC part */ +#if CONSYS_PMIC_CTRL_ENABLE +#if !defined(CONFIG_MTK_LEGACY) +struct regulator *reg_VCN18; +struct regulator *reg_VCN28; +struct regulator *reg_VCN33_BT; +struct regulator *reg_VCN33_WIFI; +#endif +#endif + +EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { + .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, + .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, + .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, + .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, + .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, + .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, + .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, + .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, + .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, + .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, + .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, + .emi_apmem_ctrl_chip_page_dump_num = EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM, + .emi_apmem_ctrl_assert_flag = EXP_APMEM_CTRL_ASSERT_FLAG, +}; + +CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { + .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, + .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, + .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, + .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, + .p_ecso = &mtk_wcn_emi_state_off, + .emi_core_dump_offset = CONSYS_EMI_COREDUMP_OFFSET, +}; + +WMT_CONSYS_IC_OPS consys_ic_ops = { + .consys_ic_clock_buffer_ctrl = consys_clock_buffer_ctrl, + .consys_ic_hw_reset_bit_set = consys_hw_reset_bit_set, + .consys_ic_hw_spm_clk_gating_enable = consys_hw_spm_clk_gating_enable, + .consys_ic_hw_power_ctrl = consys_hw_power_ctrl, + .consys_ic_ahb_clock_ctrl = consys_ahb_clock_ctrl, + .polling_consys_ic_chipid = polling_consys_chipid, + .consys_ic_acr_reg_setting = consys_acr_reg_setting, + .consys_ic_afe_reg_setting = consys_afe_reg_setting, + .consys_ic_hw_vcn18_ctrl = consys_hw_vcn18_ctrl, + .consys_ic_vcn28_hw_mode_ctrl = consys_vcn28_hw_mode_ctrl, + .consys_ic_hw_vcn28_ctrl = consys_hw_vcn28_ctrl, + .consys_ic_hw_wifi_vcn33_ctrl = consys_hw_wifi_vcn33_ctrl, + .consys_ic_hw_bt_vcn33_ctrl = consys_hw_bt_vcn33_ctrl, + .consys_ic_soc_chipid_get = consys_soc_chipid_get, + .consys_ic_emi_mpu_set_region_protection = consys_emi_mpu_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .ic_bt_wifi_share_v33_spin_lock_init = bt_wifi_share_v33_spin_lock_init, + .consys_ic_clk_get_from_dts = consys_clk_get_from_dts, + .consys_ic_pmic_get_from_dts = consys_pmic_get_from_dts, + .consys_ic_read_irq_info_from_dts = consys_read_irq_info_from_dts, + .consys_ic_read_reg_from_dts = consys_read_reg_from_dts, + .consys_ic_read_cpupcr = consys_read_cpupcr, + .ic_force_trigger_assert_debug_pin = force_trigger_assert_debug_pin, + .consys_ic_co_clock_type = consys_co_clock_type, + .consys_ic_soc_get_emi_phy_add = consys_soc_get_emi_phy_add, + .consys_ic_emi_coredump_remapping = consys_emi_coredump_remapping, + .consys_ic_reset_emi_coredump = consys_reset_emi_coredump, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +UINT32 gJtagCtrl; +#if CONSYS_ENALBE_SET_JTAG +#define JTAG_ADDR1_BASE 0x10002000 +PINT8 jtag_addr1 = (PINT8)JTAG_ADDR1_BASE; +#define JTAG1_REG_WRITE(addr, value) \ + writel(value, ((PUINT32)(jtag_addr1+(addr-JTAG_ADDR1_BASE)))) +#define JTAG1_REG_READ(addr) \ + readl(((PUINT32)(jtag_addr1+(addr-JTAG_ADDR1_BASE)))) +#endif + +INT32 mtk_wcn_consys_jtag_set_for_mcu(VOID) +{ +#if CONSYS_ENALBE_SET_JTAG + + if (gJtagCtrl) { +#if 0 + INT32 iRet = -1; + + WMT_PLAT_PR_INFO("WCN jtag_set_for_mcu start...\n"); + jtag_addr1 = ioremap(JTAG_ADDR1_BASE, 0x5000); + if (jtag_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + return iRet; + } + WMT_PLAT_PR_INFO("jtag_addr1 = 0x%p\n", jtag_addr1); + + JTAG1_REG_WRITE(0x100053c4, 0x11111100); + JTAG1_REG_WRITE(0x100053d4, 0x00111111); + + /*Enable IES of all pins */ + JTAG1_REG_WRITE(0x10002014, 0x00000003); + JTAG1_REG_WRITE(0x10005334, 0x55000000); + JTAG1_REG_WRITE(0x10005344, 0x00555555); + JTAG1_REG_WRITE(0x10005008, 0xc0000000); + JTAG1_REG_WRITE(0x10005018, 0x0000000d); + JTAG1_REG_WRITE(0x10005014, 0x00000032); + JTAG1_REG_WRITE(0x100020a4, 0x000000ff); + JTAG1_REG_WRITE(0x100020d4, 0x000000b4); + + JTAG1_REG_WRITE(0x100020d8, 0x0000004b); + + WMT_PLAT_PR_INFO("WCN jtag set for mcu start...\n"); + kal_uint32 tmp = 0; + kal_int32 addr = 0; + kal_int32 remap_addr1 = 0; + kal_int32 remap_addr2 = 0; + + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + return -1; + } + + remap_addr2 = ioremap(JTAG_ADDR2_BASE, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + return -1; + } + + /*Pinmux setting for MT6625 I/F */ + addr = remap_addr1 + 0x03C0; + tmp = DRV_Reg32(addr); + tmp = tmp & 0xff; + tmp = tmp | 0x11111100; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + addr = remap_addr1 + 0x03D0; + tmp = DRV_Reg32(addr); + tmp = tmp & 0xff000000; + tmp = tmp | 0x00111111; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*AP GPIO Setting 1 <default use> */ + /*Enable IES */ + /* addr = 0x10002014; */ + addr = remap_addr2 + 0x0014; + tmp = 0x00000003; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + /*GPIO mode setting */ + /* addr = 0x10005334; */ + addr = remap_addr1 + 0x0334; + tmp = 0x55000000; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005344; */ + addr = remap_addr1 + 0x0344; + tmp = 0x00555555; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + /*GPIO direction control */ + /* addr = 0x10005008; */ + addr = remap_addr1 + 0x0008; + tmp = 0xc0000000; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005018; */ + addr = remap_addr1 + 0x0018; + tmp = 0x0000000d; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x10005014; */ + addr = remap_addr1 + 0x0014; + tmp = 0x00000032; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*PULL Enable */ + /* addr = 0x100020a4; */ + addr = remap_addr2 + 0x00a4; + tmp = 0x000000ff; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /*PULL select enable */ + /* addr = 0x100020d4; */ + addr = remap_addr2 + 0x00d4; + tmp = 0x000000b4; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); + + /* addr = 0x100020d8; */ + addr = remap_addr2 + 0x00d8; + tmp = 0x0000004b; + DRV_WriteReg32(addr, tmp); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%08x, 0x%08x)", addr, DRV_Reg32(addr)); +#endif + } +#endif + return 0; +} + +UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en) +{ + WMT_PLAT_PR_INFO("%s jtag set for MCU\n", en ? "enable" : "disable"); + gJtagCtrl = en; + return 0; +} + +static INT32 consys_clk_get_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ +#if !defined(CONFIG_MTK_CLKMGR) + clk_scp_conn_main = devm_clk_get(&pdev->dev, "conn"); + if (IS_ERR(clk_scp_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_scp_conn_main clock.\n"); + return PTR_ERR(clk_scp_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_scp_conn_main=%p\n", clk_scp_conn_main); +#if 0 + clk_infra_conn_main = devm_clk_get(&pdev->dev, "infra-sys-conn-main"); + if (IS_ERR(clk_infra_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_infra_conn_main clock.\n"); + return PTR_ERR(clk_infra_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_infra_conn_main=%p\n", clk_infra_conn_main); +#endif + +#endif /* !defined(CONFIG_MTK_LEGACY) */ +#endif + return 0; +} + +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ +#if CONSYS_PMIC_CTRL_ENABLE +#if !defined(CONFIG_MTK_LEGACY) + reg_VCN18 = regulator_get(&pdev->dev, "vcn18"); + if (!reg_VCN18) + WMT_PLAT_PR_ERR("Regulator_get VCN_1V8 fail\n"); + reg_VCN28 = regulator_get(&pdev->dev, "vcn28"); + if (!reg_VCN28) + WMT_PLAT_PR_ERR("Regulator_get VCN_2V8 fail\n"); + reg_VCN33_BT = regulator_get(&pdev->dev, "vcn33_bt"); + if (!reg_VCN33_BT) + WMT_PLAT_PR_ERR("Regulator_get VCN33_BT fail\n"); + reg_VCN33_WIFI = regulator_get(&pdev->dev, "vcn33_wifi"); + if (!reg_VCN33_WIFI) + WMT_PLAT_PR_ERR("Regulator_get VCN33_WIFI fail\n"); +#endif +#endif +#endif + return 0; +} + +static INT32 consys_co_clock_type(VOID) +{ + UINT32 retval = 0; + UINT32 back_up = 0; + UINT32 co_clock_type = 0; + + /* co-clock auto detection:backup cw15,write cw15,read cw16,restore cw15, */ + KERNEL_pmic_read_interface(PMIC_DCXO_CW15, &retval, 0xFFFF, 0); + back_up = retval; + KERNEL_pmic_config_interface(PMIC_DCXO_CW15, PMIC_DCXO_CW15_VAL, 0xFFFF, 0); + KERNEL_pmic_read_interface(PMIC_DCXO_CW16, &retval, 0xFFFF, 0); + KERNEL_pmic_config_interface(PMIC_DCXO_CW15, back_up, 0xFFFF, 0); + if ((retval & AP_CONSYS_NOCO_CLOCK_BITA) || (retval & AP_CONSYS_NOCO_CLOCK_BITB)) { + co_clock_type = 0; + WMT_PLAT_PR_INFO("pmic_register_val = 0x%x, co_clock_type = %d,TCXO mode\n", retval, co_clock_type); + } else if ((retval & AP_CONSYS_CO_CLOCK_BITA) || (retval & AP_CONSYS_CO_CLOCK_BITB)) { + co_clock_type = 1; + WMT_PLAT_PR_INFO("pmic_register_val = 0x%x, co_clock_type = %d,co-TSX mode\n", retval, co_clock_type); + } + return co_clock_type; +} + +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_CLOCK_BUF_CTRL + if (enable == MTK_WCN_BOOL_TRUE) + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, 1); + else if (enable == MTK_WCN_BOOL_FALSE) + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, 0); +#endif + return 0; +} + +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable) +{ +#ifdef CONFIG_OF /*use DT */ + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE((conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET), + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) | + CONSYS_CPU_SW_RST_BIT | CONSYS_CPU_SW_RST_CTRL_KEY); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88 (key)" */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_CPU_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + } +#else + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE(CONSYS_CPU_SW_RST_REG, + (CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG) | CONSYS_CPU_SW_RST_BIT | + CONSYS_CPU_SW_RST_CTRL_KEY)); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88(key)" */ + CONSYS_REG_WRITE(CONSYS_CPU_SW_RST_REG, + (CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG) & ~CONSYS_CPU_SW_RST_BIT) | + CONSYS_CPU_SW_RST_CTRL_KEY); + } +#endif +} + +static VOID consys_hw_spm_clk_gating_enable(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + /*turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + /*CONSYS_REG_WRITE((conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET), CONSYS_PWRON_CONFG_EN_VALUE);*/ +#else + /*turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE(CONSYS_PWRON_CONFG_EN_REG, CONSYS_PWRON_CONFG_EN_VALUE); +#endif +} + +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + INT32 iRet = -1; +#endif + + if (enable) { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE +#if defined(CONFIG_MTK_CLKMGR) + iRet = conn_power_on(); /* consult clkmgr owner. */ + if (iRet) + WMT_PLAT_PR_ERR("conn_power_on fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("conn_power_on ok\n"); +#else + iRet = clk_prepare_enable(clk_scp_conn_main); + if (iRet) + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_scp_conn_main) fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_scp_conn_main) ok\n"); +#endif /* defined(CONFIG_MTK_LEGACY) */ + +#else + +#ifdef CONFIG_OF /*use DT */ + /*2.write conn_top1_pwr_on=1, power on conn_top1 0x1000632c [2] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_BIT); + /*3.read conn_top1_pwr_on_ack =1, power on ack ready 0x10006180 [1] */ + while (0 == (CONSYS_PWR_ON_ACK_BIT & CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET))) + NULL; + /*5.write conn_top1_pwr_on_s=1, power on conn_top1 0x1000632c [3] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_S_BIT); + /*6.write conn_clk_dis=0, enable connsys clock 0x1000632c [4] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_CLK_CTRL_BIT); + /*7.wait 1us */ + udelay(1); + /*8.read conn_top1_pwr_on_ack_s =1, power on ack ready 0x10006184 [1] */ + while (0 == (CONSYS_PWR_CONN_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET))) + NULL; + /*9.release connsys ISO, conn_top1_iso_en=0 0x1000632c [1] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_ISO_S_BIT); + /*10.release SW reset of connsys, conn_ap_sw_rst_b=1 0x1000632c[0] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_RST_BIT); + /*disable AXI BUS protect 0x10001220[13] [14] */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) & + ~CONSYS_PROT_MASK); + while (CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_STA1_OFFSET) & CONSYS_PROT_MASK) + NULL; +#else + /*2.write conn_top1_pwr_on=1, power on conn_top1 0x10006280 [2] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ON_BIT); + /*3.read conn_top1_pwr_on_ack =1, power on ack ready 0x1000660C [1] */ + while (0 == (CONSYS_PWR_ON_ACK_BIT & CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_REG))) + NULL; + /*5.write conn_top1_pwr_on_s=1, power on conn_top1 0x10006280 [3] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ON_S_BIT); + /*6.write conn_clk_dis=0, enable connsys clock 0x10006280 [4] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_CLK_CTRL_BIT); + /*7.wait 1us */ + udelay(1); + /*8.read conn_top1_pwr_on_ack_s =1, power on ack ready 0x10006610 [1] */ + while (0 == (CONSYS_PWR_CONN_ACK_S_BIT & CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_S_REG))) + NULL; + /*9.release connsys ISO, conn_top1_iso_en=0 0x10006280 [1] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_SPM_PWR_ISO_S_BIT); + /*10.release SW reset of connsys, conn_ap_sw_rst_b=1 0x10006280[0] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_RST_BIT); + /*disable AXI BUS protect */ + CONSYS_REG_WRITE(CONSYS_TOPAXI_PROT_EN, CONSYS_REG_READ(CONSYS_TOPAXI_PROT_EN) & ~CONSYS_PROT_MASK); + while (CONSYS_REG_READ(CONSYS_TOPAXI_PROT_STA1) & CONSYS_PROT_MASK) + NULL; +#endif /* CONFIG_OF */ +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } else { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE +#if defined(CONFIG_MTK_CLKMGR) + /*power off connsys by API (MT6582, MT6572 are different) API: conn_power_off() */ + iRet = conn_power_off(); /* consult clkmgr owner */ + if (iRet) + WMT_PLAT_PR_ERR("conn_power_off fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("conn_power_off ok\n"); +#else + clk_disable_unprepare(clk_scp_conn_main); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_scp_conn_main) calling\n"); +#endif /* defined(CONFIG_MTK_LEGACY) */ + +#else + +#ifdef CONFIG_OF /*use DT */ + { + INT32 count = 0; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) | + CONSYS_PROT_MASK); + while ((CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_STA1_OFFSET) & + CONSYS_PROT_MASK) != CONSYS_PROT_MASK) { + count++; + if (count > 1000) + break; + } + } + /*release connsys ISO, conn_top1_iso_en=1 0x1000632c [1] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ISO_S_BIT); + /*assert SW reset of connsys, conn_ap_sw_rst_b=0 0x1000632c[0] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x1000632c [4] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632c [3:2] 2'b00 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#else + { + INT32 count = 0; + + CONSYS_REG_WRITE(CONSYS_TOPAXI_PROT_EN, + CONSYS_REG_READ(CONSYS_TOPAXI_PROT_EN) | CONSYS_PROT_MASK); + while ((CONSYS_REG_READ(CONSYS_TOPAXI_PROT_STA1) & CONSYS_PROT_MASK) != CONSYS_PROT_MASK) { + count++; + if (count > 1000) + break; + } + + } + /*release connsys ISO, conn_top1_iso_en=1 0x1000632c [1] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_SPM_PWR_ISO_S_BIT); + /*assert SW reset of connsys, conn_ap_sw_rst_b=0 0x1000632c[0] 1'b0 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x1000632c [4] 1'b1 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) | CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632c [3:2] 2'b00 */ + CONSYS_REG_WRITE(CONSYS_TOP1_PWR_CTRL_REG, CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#endif /* CONFIG_OF */ +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } + +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + return iRet; +#else + return 0; +#endif +} + +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable) +{ + return 0; +} + +static INT32 polling_consys_chipid(VOID) +{ + UINT32 retry = 10; + UINT32 consysHwChipId = 0; + +#ifdef CONFIG_OF /*use DT */ + /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ + while (retry-- > 0) { + consysHwChipId = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CHIP_ID_OFFSET); + if (consysHwChipId == 0x0690) { + WMT_PLAT_PR_INFO("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + msleep(20); + } + + if ((retry == 0) || (consysHwChipId == 0)) { + WMT_PLAT_PR_ERR("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + WMT_PLAT_PR_INFO("reg dump:CONSYS_CPU_SW_RST_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_S_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_TOP1_PWR_CTRL_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET)); + } +#else + /*12.poll CONNSYS CHIP ID until 6763 is returned 0x18070008 32'h6763 */ + while (retry-- > 0) { + WMT_PLAT_PR_DBG("CONSYS_CHIP_ID_REG(0x%08x)", CONSYS_REG_READ(CONSYS_CHIP_ID_REG)); + consysHwChipId = CONSYS_REG_READ(CONSYS_CHIP_ID_REG); + if (consysHwChipId == 0x0690) { + WMT_PLAT_PR_INFO("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + msleep(20); + } + + if ((retry == 0) || (consysHwChipId == 0)) { + WMT_PLAT_PR_ERR("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + WMT_PLAT_PR_INFO("reg dump:CONSYS_CPU_SW_RST_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_CPU_SW_RST_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_S_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_PWR_CONN_ACK_S_REG)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_TOP1_PWR_CTRL_REG(0x%x)\n", + CONSYS_REG_READ(CONSYS_TOP1_PWR_CTRL_REG)); + } +#endif + return 0; +} + +static VOID consys_acr_reg_setting(VOID) +{ + /* + *14.write 1 to conn_mcu_confg ACR[1] if real speed MBIST + *(default write "1") ACR 0x18070110[18] 1'b1 + *if this bit is 0, HW will do memory auto test under low CPU frequence (26M Hz) + *if this bit is 0, HW will do memory auto test under high CPU frequence(138M Hz) + *inclulding low CPU frequence + */ +#ifdef CONFIG_OF /*use DT */ + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET, + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET) | + CONSYS_MCU_CFG_ACR_MBIST_BIT); +#else + CONSYS_REG_WRITE(CONSYS_MCU_CFG_ACR_REG, + CONSYS_REG_READ(CONSYS_MCU_CFG_ACR_REG) | CONSYS_MCU_CFG_ACR_MBIST_BIT); +#endif +} + +static VOID consys_afe_reg_setting(VOID) +{ +#if CONSYS_AFE_REG_SETTING + UINT8 *consys_afe_reg_base = NULL; + UINT8 i = 0; + + /*15.default no need,update ANA_WBG(AFE) CR if needed, CONSYS_AFE_REG */ + consys_afe_reg_base = ioremap(CONSYS_AFE_REG_BASE, 0x100); + if (consys_afe_reg_base) { + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_REG_WBG_AFE_01_OFFSET, + CONSYS_AFE_REG_WBG_AFE_01_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_REG_WBG_PLL_03_OFFSET, + CONSYS_AFE_REG_WBG_PLL_03_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_REG_WBG_PLL_05_OFFSET, + CONSYS_AFE_REG_WBG_PLL_05_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_REG_WBG_WB_TX_01_OFFSET, + CONSYS_AFE_REG_WBG_WB_TX_01_VALUE); + + WMT_PLAT_PR_DBG("Dump AFE register\n"); + for (i = 0; i < 64; i++) { + WMT_PLAT_PR_DBG("reg:0x%08x|val:0x%08x\n", CONSYS_AFE_REG_BASE + 4*i, + CONSYS_REG_READ(consys_afe_reg_base + 4*i)); + } + iounmap(consys_afe_reg_base); + } else + WMT_PLAT_PR_ERR("AFE base(0x%x) ioremap fail!\n", CONSYS_AFE_REG_BASE); +#endif +} + +/* Wayne Chen - This function was copied from mt6759.c */ +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*need PMIC driver provide new API protocol */ + /*1.AP power on VCN_1V8 LDO (with PMIC_WRAP API) VCN_1V8 */ +#if defined(CONFIG_MTK_PMIC_CHIP_MT6356) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_SW_OP_EN, 1); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN18_ON_CTRL, 0); +#endif + /* VOL_DEFAULT, VOL_1200, VOL_1300, VOL_1500, VOL_1800... */ +#if defined(CONFIG_MTK_LEGACY) + hwPowerOn(MT6351_POWER_LDO_VCN18, VOL_1800 * 1000, "wcn_drv"); +#else + if (reg_VCN18) { + regulator_set_voltage(reg_VCN18, 1800000, 1800000); + if (regulator_enable(reg_VCN18)) + WMT_PLAT_PR_ERR("enable VCN18 fail\n"); + else + WMT_PLAT_PR_DBG("enable VCN18 ok\n"); + } +#endif + + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } + +#if defined(CONFIG_MTK_PMIC_CHIP_MT6356) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_BT, 1); +#endif + } else { +#if defined(CONFIG_MTK_PMIC_CHIP_MT6356) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_SW_OP_EN, 1); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_BT, 0); +#endif + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); + + /*AP power off MT6351L VCN_1V8 LDO */ +#if defined(CONFIG_MTK_PMIC_CHIP_MT6356) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_SW_OP_EN, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN18_ON_CTRL, 0); +#endif +#if defined(CONFIG_MTK_LEGACY) + hwPowerDown(MT6351_POWER_LDO_VCN18, "wcn_drv"); +#else + if (reg_VCN18) { + if (regulator_disable(reg_VCN18)) + WMT_PLAT_PR_ERR("disable VCN_1V8 fail!\n"); + else + WMT_PLAT_PR_DBG("disable VCN_1V8 ok\n"); + } +#endif + } +#endif + return 0; +} + +/* Wayne Chen - This function was copied from mt6759.c */ +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { +#if defined(CONFIG_MTK_PMIC_CHIP_MT6356) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN28_ON_CTRL, 1); +#endif + } else { +#if defined(CONFIG_MTK_PMIC_CHIP_MT6356) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN28_ON_CTRL, 0); +#endif + } +#endif +} + +/* Wayne Chen - This function was copied from mt6759.c */ +static INT32 consys_hw_vcn28_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*in co-clock mode,need to turn on vcn28 when fm on */ + if (reg_VCN28) { + regulator_set_voltage(reg_VCN28, 2800000, 2800000); + if (regulator_enable(reg_VCN28)) + WMT_PLAT_PR_ERR("WMT do VCN28 PMIC on fail!\n"); + } + WMT_PLAT_PR_INFO("turn on vcn28 for fm/gps usage in co-clock mode\n"); + } else { + /*in co-clock mode,need to turn off vcn28 when fm off */ + if (reg_VCN28) + regulator_disable(reg_VCN28); + WMT_PLAT_PR_INFO("turn off vcn28 for fm/gps usage in co-clock mode\n"); + } +#endif + return 0; +} + +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + /* spin_lock_irqsave(&gBtWifiV33.lock,gBtWifiV33.flags); */ + if (enable) { + if (gBtWifiV33.counter == 1) { + gBtWifiV33.counter++; + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else if (gBtWifiV33.counter == 2) { + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else { +#if CONSYS_PMIC_CTRL_ENABLE + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + hwPowerOn(MT6351_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); + mt6351_upmu_set_rg_vcn33_on_ctrl(1); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 on\n"); + gBtWifiV33.counter++; + } + + } else { + if (gBtWifiV33.counter == 1) { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + mt6351_upmu_set_rg_vcn33_on_ctrl(0); + hwPowerDown(MT6351_POWER_LDO_VCN33_BT, "wcn_drv"); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 off\n"); + gBtWifiV33.counter--; + } else if (gBtWifiV33.counter == 2) { + gBtWifiV33.counter--; + WMT_PLAT_PR_DBG("V33 no need disabled,counter(%d)\n", gBtWifiV33.counter); + } else { + WMT_PLAT_PR_DBG("V33 has been disabled,counter(%d)\n", gBtWifiV33.counter); + } + + } + /* spin_unlock_irqrestore(&gBtWifiV33.lock,gBtWifiV33.flags); */ +#else + if (enable) { + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ +#if defined(CONFIG_MTK_LEGACY) + hwPowerOn(MT6351_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); +#else + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } +#endif + +#if defined(CONFIG_MTK_PMIC_CHIP_MT6356) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_BT, 1); +#endif + +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC on\n"); + } else { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE +#if defined(CONFIG_MTK_PMIC_CHIP_MT6356) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_BT, 0); +#endif +#if defined(CONFIG_MTK_LEGACY) + hwPowerDown(MT6351_POWER_LDO_VCN33_BT, "wcn_drv"); +#else + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); +#endif +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC off\n"); + } +#endif + + return 0; +} + +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + mtk_wcn_consys_hw_bt_paldo_ctrl(enable); +#else + if (enable) { + /*do WIFI PMIC on,depenency PMIC API ready */ + /*switch WIFI PALDO control from SW mode to HW mode:0x418[14]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE +#if defined(CONFIG_MTK_LEGACY) + hwPowerOn(MT6351_POWER_LDO_VCN33_WIFI, VOL_3300 * 1000, "wcn_drv"); +#else + if (reg_VCN33_WIFI) { + regulator_set_voltage(reg_VCN33_WIFI, 3300000, 3300000); + if (regulator_enable(reg_VCN33_WIFI)) + WMT_PLAT_PR_ERR("WMT do WIFI PMIC on fail!\n"); + } +#endif +#if defined(CONFIG_MTK_PMIC_CHIP_MT6356) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_WIFI, 1); +#endif +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC on\n"); + } else { + /*do WIFI PMIC off */ + /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE +#if defined(CONFIG_MTK_PMIC_CHIP_MT6356) + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#else + KERNEL_pmic_set_register_value(MT6351_PMIC_RG_VCN33_ON_CTRL_WIFI, 0); +#endif +#if defined(CONFIG_MTK_LEGACY) + hwPowerDown(MT6351_POWER_LDO_VCN33_WIFI, "wcn_drv"); +#else + if (reg_VCN33_WIFI) + regulator_disable(reg_VCN33_WIFI); +#endif + +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC off\n"); + } + +#endif + + return 0; +} + +static INT32 consys_emi_mpu_set_region_protection(VOID) +{ + struct emi_region_info_t region_info; + +#if CONSYS_EMI_MPU_SETTING + /*set MPU for EMI share Memory */ + WMT_PLAT_PR_INFO("setting MPU for EMI share memory\n"); + + /* 5 = Forbidden, 0 = No_protect */ + region_info.start = gConEmiPhyBase + SZ_1M / 2; + region_info.end = gConEmiPhyBase + gConEmiSize - 1; + region_info.region = 24; + SET_ACCESS_PERMISSION(region_info.apc, LOCK, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + NO_PROTECTION, FORBIDDEN, NO_PROTECTION); + emi_mpu_set_protection(®ion_info); +#endif + return 0; +} + +static UINT32 consys_emi_set_remapping_reg(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + UINT32 addrPhy = 0; + + /*consys to ap emi remapping register:10001380, cal remapping address */ + addrPhy = (gConEmiPhyBase >> 21) & 0x1FFF; + + /*enable consys to ap emi remapping bit13 */ + addrPhy = addrPhy | 0x2000; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); + + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); +#endif + return 0; +} + +static INT32 bt_wifi_share_v33_spin_lock_init(VOID) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + gBtWifiV33.counter = 0; + spin_lock_init(&gBtWifiV33.lock); +#endif + return 0; +} + +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag) +{ +#ifdef CONFIG_OF /*use DT */ + struct device_node *node; + UINT32 irq_info[3] = { 0, 0, 0 }; + + INT32 iret = -1; + + node = pdev->dev.of_node; + if (node) { + *irq_num = irq_of_parse_and_map(node, 0); + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + WMT_PLAT_PR_ERR("get irq flags from DTS fail!!\n"); + return iret; + } + *irq_flag = irq_info[2]; + WMT_PLAT_PR_INFO("get irq id(%d) and irq trigger flag(%d) from DT\n", *irq_num, + *irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iret; + } +#endif + return 0; +} + +static INT32 consys_read_reg_from_dts(struct platform_device *pdev) +{ +#ifdef CONFIG_OF /*use DT */ + INT32 iRet = -1; + struct device_node *node = NULL; + + node = pdev->dev.of_node; + if (node) { + /* registers base address */ + conn_reg.mcu_base = (SIZE_T) of_iomap(node, 0); + WMT_PLAT_PR_DBG("Get mcu register base(0x%zx)\n", conn_reg.mcu_base); + conn_reg.ap_rgu_base = (SIZE_T) of_iomap(node, 1); + WMT_PLAT_PR_DBG("Get ap_rgu register base(0x%zx)\n", conn_reg.ap_rgu_base); + conn_reg.topckgen_base = (SIZE_T) of_iomap(node, 2); + WMT_PLAT_PR_DBG("Get topckgen register base(0x%zx)\n", conn_reg.topckgen_base); + conn_reg.spm_base = (SIZE_T) of_iomap(node, 3); + WMT_PLAT_PR_DBG("Get spm register base(0x%zx)\n", conn_reg.spm_base); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iRet; + } +#endif + return 0; +} + +static VOID force_trigger_assert_debug_pin(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + usleep_range(64, 96); + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); +#endif +} + +static UINT32 consys_read_cpupcr(VOID) +{ +#ifdef CONFIG_OF /*use DT */ + return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CPUPCR_OFFSET); +#endif +} + +static UINT32 consys_soc_chipid_get(VOID) +{ + return PLATFORM_SOC_CHIP; +} + +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID) +{ + return &mtk_wcn_emi_addr_info; +} + +P_WMT_CONSYS_IC_OPS mtk_wcn_get_consys_ic_ops(VOID) +{ + return &consys_ic_ops; +} + +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable) +{ + if (enable) { + *addr = ioremap(gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET, CONSYS_EMI_MEM_SIZE); + if (*addr) { + WMT_PLAT_PR_INFO("COREDUMP EMI mapping OK virtual(0x%p) physical(0x%x)\n", + *addr, (UINT32) gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET); + memset_io(*addr, 0, CONSYS_EMI_MEM_SIZE); + } else { + WMT_PLAT_PR_ERR("EMI mapping fail\n"); + return -1; + } + } else { + if (*addr) { + iounmap(*addr); + *addr = NULL; + } + } + return 0; +} + +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr) +{ + if (!addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + WMT_PLAT_PR_INFO("Reset EMI(0xF0080000 ~ 0xF0080400) and (0xF0088400 ~ 0xF0090400)\n"); + /* reset 0xF0080000 ~ 0xF0080400 (1K) */ + memset_io(addr, 0, 0x400); + /* reset 0xF0088400 ~ 0xF0090400 (32K) */ + memset_io(addr + CONSYS_EMI_PAGED_DUMP_OFFSET, 0, 0x8000); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6765.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6765.c new file mode 100644 index 00000000000000..8862df9cfa7958 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6765.c @@ -0,0 +1,1326 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <connectivity_build_in_adapter.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/memblock.h> +#include <linux/platform_device.h> +#include "connsys_debug_utility.h" +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +#include "fw_log_wmt.h" +#endif +#include "osal_typedef.h" +#include "mt6765.h" +#include "mtk_wcn_consys_hw.h" +#include "wmt_ic.h" +#include "wmt_lib.h" +#include "wmt_plat.h" +#include "stp_dbg.h" + +#ifdef CONFIG_MTK_EMI +#include <mt_emi_api.h> +#endif + +#if CONSYS_PMIC_CTRL_ENABLE +#include <upmu_common.h> +#include <linux/regulator/consumer.h> +#endif + +#ifdef CONFIG_MTK_HIBERNATION +#include <mtk_hibernate_dpm.h> +#endif + +#include <linux/of_reserved_mem.h> + +#include <mtk_clkbuf_ctl.h> + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable); +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable); +static VOID consys_hw_spm_clk_gating_enable(VOID); +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable); +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable); +static INT32 polling_consys_chipid(VOID); +static VOID consys_acr_reg_setting(VOID); +static VOID consys_afe_reg_setting(VOID); +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable); +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable); +static INT32 consys_hw_vcn28_ctrl(UINT32 enable); +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable); +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable); +static UINT32 consys_soc_chipid_get(VOID); +static INT32 consys_emi_mpu_set_region_protection(VOID); +static UINT32 consys_emi_set_remapping_reg(VOID); +static INT32 bt_wifi_share_v33_spin_lock_init(VOID); +static INT32 consys_clk_get_from_dts(struct platform_device *pdev); +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev); +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag); +static INT32 consys_read_reg_from_dts(struct platform_device *pdev); +static UINT32 consys_read_cpupcr(VOID); +static VOID force_trigger_assert_debug_pin(VOID); +static INT32 consys_co_clock_type(VOID); +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID); +static VOID consys_set_if_pinmux(MTK_WCN_BOOL enable); +static INT32 consys_dl_rom_patch(UINT32 ip_ver, UINT32 fw_ver); +static VOID consys_set_dl_rom_patch_flag(INT32 flag); +static INT32 consys_dedicated_log_path_init(struct platform_device *pdev); +static VOID consys_dedicated_log_path_deinit(VOID); +static INT32 consys_check_reg_readable(VOID); +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable); +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr); +static INT32 consys_is_connsys_reg(UINT32 addr); +static PUINT32 consys_resume_dump_info(VOID); +static VOID consys_set_pdma_axi_rready_force_high(UINT32 enable); +static VOID consys_infra_reg_dump(VOID); +static VOID consys_get_ant_sel_cr_addr(PUINT32 default_invert_cr, PUINT32 default_invert_bit); +static INT32 consys_calibration_backup_restore_support(VOID); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status gBtWifiV33; +#endif + +/* CCF part */ +struct clk *clk_scp_conn_main; /*ctrl conn_power_on/off */ + +/* PMIC part */ +#if CONSYS_PMIC_CTRL_ENABLE +struct regulator *reg_VCN18; +struct regulator *reg_VCN28; +struct regulator *reg_VCN33_BT; +struct regulator *reg_VCN33_WIFI; +#endif + +EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { + .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, + .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, + .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, + .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, + .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, + .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, + .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, + .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, + .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, + .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, + .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, + .emi_apmem_ctrl_chip_page_dump_num = EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM, + .emi_apmem_ctrl_assert_flag = EXP_APMEM_CTRL_ASSERT_FLAG, +}; + +CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { + .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, + .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, + .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, + .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, + .emi_remap_offset = CONSYS_EMI_MAPPING_OFFSET, + .p_ecso = &mtk_wcn_emi_state_off, + .emi_core_dump_offset = CONSYS_EMI_COREDUMP_OFFSET, + .pda_dl_patch_flag = 1, + .emi_met_size = (32*KBYTE), + .emi_met_data_offset = CONSYS_EMI_MET_DATA_OFFSET, +}; + +WMT_CONSYS_IC_OPS consys_ic_ops = { + .consys_ic_clock_buffer_ctrl = consys_clock_buffer_ctrl, + .consys_ic_hw_reset_bit_set = consys_hw_reset_bit_set, + .consys_ic_hw_spm_clk_gating_enable = consys_hw_spm_clk_gating_enable, + .consys_ic_hw_power_ctrl = consys_hw_power_ctrl, + .consys_ic_ahb_clock_ctrl = consys_ahb_clock_ctrl, + .polling_consys_ic_chipid = polling_consys_chipid, + .consys_ic_acr_reg_setting = consys_acr_reg_setting, + .consys_ic_afe_reg_setting = consys_afe_reg_setting, + .consys_ic_hw_vcn18_ctrl = consys_hw_vcn18_ctrl, + .consys_ic_vcn28_hw_mode_ctrl = consys_vcn28_hw_mode_ctrl, + .consys_ic_hw_vcn28_ctrl = consys_hw_vcn28_ctrl, + .consys_ic_hw_wifi_vcn33_ctrl = consys_hw_wifi_vcn33_ctrl, + .consys_ic_hw_bt_vcn33_ctrl = consys_hw_bt_vcn33_ctrl, + .consys_ic_soc_chipid_get = consys_soc_chipid_get, + .consys_ic_emi_mpu_set_region_protection = consys_emi_mpu_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .ic_bt_wifi_share_v33_spin_lock_init = bt_wifi_share_v33_spin_lock_init, + .consys_ic_clk_get_from_dts = consys_clk_get_from_dts, + .consys_ic_pmic_get_from_dts = consys_pmic_get_from_dts, + .consys_ic_read_irq_info_from_dts = consys_read_irq_info_from_dts, + .consys_ic_read_reg_from_dts = consys_read_reg_from_dts, + .consys_ic_read_cpupcr = consys_read_cpupcr, + .ic_force_trigger_assert_debug_pin = force_trigger_assert_debug_pin, + .consys_ic_co_clock_type = consys_co_clock_type, + .consys_ic_soc_get_emi_phy_add = consys_soc_get_emi_phy_add, + .consys_ic_set_if_pinmux = consys_set_if_pinmux, + .consys_ic_set_dl_rom_patch_flag = consys_set_dl_rom_patch_flag, + .consys_ic_dedicated_log_path_init = consys_dedicated_log_path_init, + .consys_ic_dedicated_log_path_deinit = consys_dedicated_log_path_deinit, + .consys_ic_check_reg_readable = consys_check_reg_readable, + .consys_ic_emi_coredump_remapping = consys_emi_coredump_remapping, + .consys_ic_reset_emi_coredump = consys_reset_emi_coredump, + .consys_ic_is_connsys_reg = consys_is_connsys_reg, + .consys_ic_resume_dump_info = consys_resume_dump_info, + .consys_ic_set_pdma_axi_rready_force_high = consys_set_pdma_axi_rready_force_high, + .consys_ic_infra_reg_dump = consys_infra_reg_dump, + .consys_ic_get_ant_sel_cr_addr = consys_get_ant_sel_cr_addr, + .consys_ic_calibration_backup_restore = consys_calibration_backup_restore_support, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 rom_patch_dl_flag = 1; +UINT32 gJtagCtrl; +UINT32 g_connsys_lp_dump_info[2]; + +#if CONSYS_ENALBE_SET_JTAG +#define JTAG_ADDR1_BASE 0x10005000 +#define JTAG_ADDR2_BASE 0x11E80000 +#define JTAG_ADDR3_BASE 0x11D20000 +#define AP2CONN_JTAG_2WIRE_OFFSET 0xF00 +#endif + +INT32 mtk_wcn_consys_jtag_set_for_mcu(VOID) +{ +#if CONSYS_ENALBE_SET_JTAG + INT32 ret = 0; + UINT32 tmp = 0; + PVOID addr = 0; + PVOID remap_addr1 = 0; + PVOID remap_addr2 = 0; + PVOID remap_addr3 = 0; + + if (gJtagCtrl) { + + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + ret = -1; + goto error; + } + + remap_addr2 = ioremap(JTAG_ADDR2_BASE, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + ret = -1; + goto error; + } + + remap_addr3 = ioremap(JTAG_ADDR3_BASE, 0x100); + if (remap_addr3 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr3 fail!\n"); + ret = -1; + goto error; + } + + WMT_PLAT_PR_INFO("WCN jtag set for mcu start...\n"); + switch (gJtagCtrl) { + case 1: + /* 7-wire jtag pinmux setting*/ +#if 1 + /* PAD AUX Function Selection */ + addr = remap_addr1 + 0x320; + tmp = readl(addr); + tmp = tmp & 0x0000000f; + tmp = tmp | 0x33333330; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD Driving Selection */ + addr = remap_addr2 + 0xA0; + tmp = readl(addr); + tmp = tmp & 0xfff00fff; + tmp = tmp | 0x00077000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD PULL Selection */ + addr = remap_addr2 + 0x60; + tmp = readl(addr); + tmp = tmp & 0xfffe03ff; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr2 + 0x60; + tmp = readl(addr); + tmp = tmp & 0xfff80fff; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + +#else + /* backup */ + /* PAD AUX Function Selection */ + addr = remap_addr1 + 0x310; + tmp = readl(addr); + tmp = tmp & 0xfffff000; + tmp = tmp | 0x00000444; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr1 + 0x3C0; + tmp = readl(addr); + tmp = tmp & 0xf00ff00f; + tmp = tmp | 0x04400440; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD Driving Selection */ + addr = remap_addr3 + 0xA0; + tmp = readl(addr); + tmp = tmp & 0x0ffffff0; + tmp = tmp | 0x70000007; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr3 + 0xB0; + tmp = readl(addr); + tmp = tmp & 0xfff0f0ff; + tmp = tmp | 0x0007070f; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD PULL Selection */ + addr = remap_addr3 + 0x60; + tmp = readl(addr); + tmp = tmp & 0xf333fffe; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); +#endif + break; + case 2: + /* 2-wire jtag pinmux setting*/ +#if 0 + CONSYS_SET_BIT(conn_reg.topckgen_base + AP2CONN_JTAG_2WIRE_OFFSET, 1 << 8); + addr = remap_addr1 + 0x340; + tmp = readl(addr); + tmp = tmp & 0xfff88fff; + tmp = tmp | 0x00034000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); +#endif + break; + default: + WMT_PLAT_PR_INFO("unsupported options!\n"); + } + + } +#endif + +error: + + if (remap_addr1) + iounmap(remap_addr1); + if (remap_addr2) + iounmap(remap_addr2); + if (remap_addr3) + iounmap(remap_addr3); + + return ret; +} + +UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en) +{ + WMT_PLAT_PR_INFO("%s jtag set for MCU\n", en ? "enable" : "disable"); + gJtagCtrl = en; + return 0; +} + +static INT32 consys_clk_get_from_dts(struct platform_device *pdev) +{ + clk_scp_conn_main = devm_clk_get(&pdev->dev, "conn"); + if (IS_ERR(clk_scp_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_scp_conn_main clock.\n"); + return PTR_ERR(clk_scp_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_scp_conn_main=%p\n", clk_scp_conn_main); + + return 0; +} + +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev) +{ +#if CONSYS_PMIC_CTRL_ENABLE + reg_VCN18 = regulator_get(&pdev->dev, "vcn18"); + if (!reg_VCN18) + WMT_PLAT_PR_ERR("Regulator_get VCN_1V8 fail\n"); + reg_VCN28 = regulator_get(&pdev->dev, "vcn28"); + if (!reg_VCN28) + WMT_PLAT_PR_ERR("Regulator_get VCN_2V8 fail\n"); + reg_VCN33_BT = regulator_get(&pdev->dev, "vcn33_bt"); + if (!reg_VCN33_BT) + WMT_PLAT_PR_ERR("Regulator_get VCN33_BT fail\n"); + reg_VCN33_WIFI = regulator_get(&pdev->dev, "vcn33_wifi"); + if (!reg_VCN33_WIFI) + WMT_PLAT_PR_ERR("Regulator_get VCN33_WIFI fail\n"); +#endif + return 0; +} + +static INT32 consys_co_clock_type(VOID) +{ + return 0; +} + +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable) +{ + if (enable) + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, true); /*open XO_WCN*/ + else + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, false); /*close XO_WCN*/ + + return 0; +} + +static VOID consys_set_if_pinmux(MTK_WCN_BOOL enable) +{ + UINT8 *consys_if_pinmux_reg_base = NULL; + + /* Switch D die pinmux for connecting A die */ + consys_if_pinmux_reg_base = ioremap(CONSYS_IF_PINMUX_REG_BASE, 0x1000); + if (!consys_if_pinmux_reg_base) { + WMT_PLAT_PR_ERR("consys_if_pinmux_reg_base(%x) ioremap fail\n", CONSYS_IF_PINMUX_REG_BASE); + return; + } + + if (enable) { + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET) & + CONSYS_IF_PINMUX_01_MASK) | CONSYS_IF_PINMUX_01_VALUE); + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET) & + CONSYS_IF_PINMUX_02_MASK) | CONSYS_IF_PINMUX_02_VALUE); + } else { + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET, + CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET) & + CONSYS_IF_PINMUX_01_MASK); + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET, + CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET) & + CONSYS_IF_PINMUX_02_MASK); + } + + if (consys_if_pinmux_reg_base) + iounmap(consys_if_pinmux_reg_base); +} + +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable) +{ + UINT32 consys_ver_id = 0; + UINT32 cnt = 0; + + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE((conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET), + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) | + CONSYS_CPU_SW_RST_BIT | CONSYS_CPU_SW_RST_CTRL_KEY); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88 (key)" */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_CPU_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + 0x600); + while (consys_ver_id != 0x1D1E) { + if (cnt > 10) + break; + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + 0x600); + WMT_PLAT_PR_INFO("0x18002600(0x%x)\n", consys_ver_id); + WMT_PLAT_PR_INFO("0x1800216c(0x%x)\n", + CONSYS_REG_READ(conn_reg.mcu_base + 0x16c)); + WMT_PLAT_PR_INFO("0x18007104(0x%x)\n", + CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base + CONSYS_CPUPCR_OFFSET)); + msleep(20); + cnt++; + } + } +} + +static VOID consys_hw_spm_clk_gating_enable(VOID) +{ +} + +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + INT32 iRet = 0; +#else + INT32 value = 0; + INT32 i = 0; +#endif + + if (enable) { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + iRet = clk_prepare_enable(clk_scp_conn_main); + if (iRet) + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_scp_conn_main) fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_scp_conn_main) ok\n"); +#else + /* turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE((conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET), + (CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET) & + 0x0000FFFF) | CONSYS_PWRON_CONFG_EN_VALUE); + + /*write assert "conn_top_on" primary part power on, set "connsys_on_domain_pwr_on"=1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_BIT); + /*read check "conn_top_on" primary part power status, check "connsys_on_domain_pwr_ack"=1 */ + value = CONSYS_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + while (value == 0) + value = CONSYS_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + /*write assert "conn_top_on" secondary part power on, set "connsys_on_domain_pwr_on_s"=1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_S_BIT); + /*read check "conn_top_on" secondary part power status, check "connsys_on_domain_pwr_ack_s"=1 */ + value = CONSYS_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + while (value == 0) + value = CONSYS_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + /*write turn on AP-to-CONNSYS bus clock, set "conn_clk_dis"=0 (apply this for bus + *clock toggling) + */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_CLK_CTRL_BIT); + /*wait 1us*/ + udelay(1); + /*de-assert "conn_top_on" isolation, set "connsys_iso_en"=0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_ISO_S_BIT); + /*read check "conn_top_off" primary part power status, check + *"connsys_off_domain_pwr_ack"=1 + */ + value = CONSYS_TOP2_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + while (value == 0) + value = CONSYS_TOP2_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + /*read check "conn_top_off" secondary part power status, check + *"connsys_off_domain_pwr_ack_s"=1 + */ + value = CONSYS_TOP2_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + while (value == 0) + value = CONSYS_TOP2_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + + /*de-assert CONNSYS S/W reset, set "ap_sw_rst_b"=1 */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + + /*Turn off AHB bus sleep protect (AP2CONN AHB Bus protect) (apply this for INFRA AHB + *bus accessing when CONNSYS had been turned on) + */ + /*disable AHBAXI BUS protect 10001220 [13][14] */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET) & + ~CONSYS_PROT_MASK); + value = ~CONSYS_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA1_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA1_OFFSET); + i++; + } + /*Disable AXI TX bus sleep protect (CONN2AP AXI Tx Bus protect) (disable sleep + * protection when CONNSYS had been turned on) + * Note : Should turn off AXI Tx sleep protection after AXI Rx sleep protection has + * been turn off. + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_EN_OFFSET) & + ~CONSYS_TX_PROT_MASK); + value = ~CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_STA_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_STA_OFFSET); + i++; + } + /*SPM apsrc/ddr_en hardware mask disable & wait cycle setting*/ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_SPM_APSRC_OFFSET, CONSYS_SPM_APSRC_VALUE); + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_SPM_DDR_EN_OFFSET, CONSYS_SPM_DDR_EN_VALUE); +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } else { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + clk_disable_unprepare(clk_scp_conn_main); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_scp_conn_main) calling\n"); +#else + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET) & + CONSYS_PROT_MASK); + value = CONSYS_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA1_OFFSET); + i = 0; + while (value == CONSYS_PROT_MASK || i > 10) { + value = CONSYS_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA1_OFFSET); + i++; + } + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_EN_OFFSET) & + CONSYS_TX_PROT_MASK); + value = CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_STA_OFFSET); + i = 0; + while (value == CONSYS_TX_PROT_MASK || i > 10) { + value = CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_STA_OFFSET); + i++; + } + + /*release connsys ISO, conn_top1_iso_en=1 0x1000632C [1] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ISO_S_BIT); + /*de-assert CONNSYS S/W reset, set "ap_sw_rst_b"=1 */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + CONSYS_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + /*write conn_clk_dis=1, disable connsys clock 0x1000632C [4] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632C [3:2] 2'b00 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } + +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + return iRet; +#else + return 0; +#endif +} + +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable) +{ + return 0; +} + +static INT32 polling_consys_chipid(VOID) +{ + INT32 retry = 10; + UINT32 consys_ver_id = 0; + UINT32 consys_hw_ver = 0; + UINT32 consys_fw_ver = 0; + UINT8 *consys_reg_base = NULL; + UINT32 value = 0; + + /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ + while (retry-- > 0) { + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_top_misc_off_base + CONSYS_IP_VER_OFFSET); + if (consys_ver_id == 0x10020300) { + WMT_PLAT_PR_INFO("retry(%d)consys version id(0x%08x)\n", retry, consys_ver_id); + consys_hw_ver = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys HW version id(0x%x)\n", consys_hw_ver & 0xFFFF); + consys_fw_ver = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_FW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys FW version id(0x%x)\n", consys_fw_ver & 0xFFFF); + + if (consys_dl_rom_patch(consys_ver_id, consys_fw_ver) == 0) + break; + } + WMT_PLAT_PR_ERR("Read CONSYS version id(0x%08x)", consys_ver_id); + msleep(20); + } + + if (retry <= 0) + return -1; + + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_top_misc_off_base + CONSYS_CONF_ID_OFFSET); + WMT_PLAT_PR_INFO("consys configuration id(0x%x)\n", consys_ver_id & 0xF); + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys HW version id(0x%x)\n", consys_ver_id & 0xFFFF); + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_FW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys FW version id(0x%x)\n", consys_ver_id & 0xFFFF); + + /* CONNSYS mcu rom delsel setting */ + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_MCU_ROM_DELSEL_OFFSET); + consys_ver_id &= 0xFFFF0000; + consys_ver_id |= CONSYS_MCU_ROM_DELSEL_VALUE; + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_MCU_ROM_DELSEL_OFFSET, consys_ver_id); + + if (wmt_plat_soc_co_clock_flag_get()) { + consys_reg_base = ioremap(CONSYS_COCLOCK_STABLE_TIME_BASE, 0x100); + if (consys_reg_base) { +#if 0 + /* disable XO stable time setting */ + value = CONSYS_REG_READ(consys_reg_base); + value = (value & CONSYS_COCLOCK_STABLE_TIME_MASK) | CONSYS_COCLOCK_STABLE_TIME; + CONSYS_REG_WRITE(consys_reg_base, value); +#endif + value = CONSYS_REG_READ(consys_reg_base + CONSYS_COCLOCK_ACK_ENABLE_OFFSET); + value = value & (~CONSYS_COCLOCK_ACK_ENABLE_BIT); + CONSYS_REG_WRITE(consys_reg_base + CONSYS_COCLOCK_ACK_ENABLE_OFFSET, value); + iounmap(consys_reg_base); + } else + WMT_PLAT_PR_ERR("connsys co_clock stable time base(0x%x) ioremap fail!\n", + CONSYS_COCLOCK_STABLE_TIME_BASE); + } + + CONSYS_SET_BIT(conn_reg.mcu_base + CONSYS_SW_IRQ_OFFSET, CONSYS_EMI_CTRL_VALUE); + + return 0; +} + +static VOID consys_acr_reg_setting(VOID) +{ +} + +static VOID consys_afe_reg_setting(VOID) +{ +#if CONSYS_AFE_REG_SETTING + UINT8 i = 0; + UINT8 *consys_afe_reg_base = NULL; + + /*15.default no need,update ANA_WBG(AFE) CR if needed, CONSYS_AFE_REG */ + consys_afe_reg_base = ioremap(CONSYS_AFE_REG_BASE, 0x100); + if (consys_afe_reg_base) { + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_RG_WBG_PLL_03_OFFSET, + CONSYS_AFE_RG_WBG_PLL_03_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_RG_WBG_GPS_02_OFFSET, + CONSYS_AFE_RG_WBG_GPS_02_VALUE); + + WMT_PLAT_PR_DBG("Dump AFE register\n"); + for (i = 0; i < 64; i++) { + WMT_PLAT_PR_DBG("reg:0x%08x|val:0x%08x\n", + CONSYS_AFE_REG_BASE + 4*i, + CONSYS_REG_READ(consys_afe_reg_base + 4*i)); + } + iounmap(consys_afe_reg_base); + } else + WMT_PLAT_PR_ERR("AFE base(0x%x) ioremap fail!\n", CONSYS_AFE_REG_BASE); +#endif +} + +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*need PMIC driver provide new API protocol */ + /*1.AP power on VCN_1V8 LDO (with PMIC_WRAP API) VCN_1V8 */ + /*set vcn18 SW mode*/ + KERNEL_upmu_set_reg_value(MT6357_LDO_VCN18_OP_EN, 0x1); + if (reg_VCN18) { + regulator_set_voltage(reg_VCN18, 1800000, 1800000); + if (regulator_enable(reg_VCN18)) + WMT_PLAT_PR_ERR("enable VCN18 fail\n"); + else + WMT_PLAT_PR_DBG("enable VCN18 ok\n"); + } + + if (!(wmt_lib_get_ext_ldo())) { + KERNEL_upmu_set_reg_value(MT6357_LDO_VCN33_OP_EN, 0x1); + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } + } else + WMT_PLAT_PR_INFO("VCN33 uses external LDO!\n"); + } else { + if (!(wmt_lib_get_ext_ldo())) { + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); + } + + /*AP power off MT6351L VCN_1V8 LDO */ + if (reg_VCN18) { + if (regulator_disable(reg_VCN18)) + WMT_PLAT_PR_ERR("disable VCN_1V8 fail!\n"); + else + WMT_PLAT_PR_DBG("disable VCN_1V8 ok\n"); + } + } +#endif + return 0; +} + +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); + } else { + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); + } +#endif +} + +static INT32 consys_hw_vcn28_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*in co-clock mode,need to turn on vcn28 when fm on */ + if (reg_VCN28) { + regulator_set_voltage(reg_VCN28, 2800000, 2800000); + if (regulator_enable(reg_VCN28)) + WMT_PLAT_PR_ERR("WMT do VCN28 PMIC on fail!\n"); + } + WMT_PLAT_PR_INFO("turn on vcn28 for fm/gps usage in co-clock mode\n"); + } else { + /*in co-clock mode,need to turn off vcn28 when fm off */ + if (reg_VCN28) + regulator_disable(reg_VCN28); + WMT_PLAT_PR_INFO("turn off vcn28 for fm/gps usage in co-clock mode\n"); + } +#endif + return 0; +} + +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable) +{ +#if 0 +#if CONSYS_BT_WIFI_SHARE_V33 + /* spin_lock_irqsave(&gBtWifiV33.lock,gBtWifiV33.flags); */ + if (enable) { + if (gBtWifiV33.counter == 1) { + gBtWifiV33.counter++; + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else if (gBtWifiV33.counter == 2) { + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else { +#if CONSYS_PMIC_CTRL_ENABLE + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + hwPowerOn(MT6351_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); + mt6351_upmu_set_rg_vcn33_on_ctrl(1); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 on\n"); + gBtWifiV33.counter++; + } + + } else { + if (gBtWifiV33.counter == 1) { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + mt6351_upmu_set_rg_vcn33_on_ctrl(0); + hwPowerDown(MT6351_POWER_LDO_VCN33_BT, "wcn_drv"); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 off\n"); + gBtWifiV33.counter--; + } else if (gBtWifiV33.counter == 2) { + gBtWifiV33.counter--; + WMT_PLAT_PR_DBG("V33 no need disabled,counter(%d)\n", gBtWifiV33.counter); + } else { + WMT_PLAT_PR_DBG("V33 has been disabled,counter(%d)\n", gBtWifiV33.counter); + } + + } + /* spin_unlock_irqrestore(&gBtWifiV33.lock,gBtWifiV33.flags); */ +#else + if (enable) { + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } + + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC on\n"); + } else { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC off\n"); + } +#endif + +#endif + return 0; +} + +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable) +{ +#if 0 +#if CONSYS_BT_WIFI_SHARE_V33 + mtk_wcn_consys_hw_bt_paldo_ctrl(enable); +#else + if (enable) { + /*do WIFI PMIC on,depenency PMIC API ready */ + /*switch WIFI PALDO control from SW mode to HW mode:0x418[14]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + if (reg_VCN33_WIFI) { + regulator_set_voltage(reg_VCN33_WIFI, 3300000, 3300000); + if (regulator_enable(reg_VCN33_WIFI)) + WMT_PLAT_PR_ERR("WMT do WIFI PMIC on fail!\n"); + } + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC on\n"); + } else { + /*do WIFI PMIC off */ + /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); + if (reg_VCN33_WIFI) + regulator_disable(reg_VCN33_WIFI); +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC off\n"); + } + +#endif + +#endif + return 0; +} + +static INT32 consys_emi_mpu_set_region_protection(VOID) +{ +#ifdef CONFIG_MTK_EMI + struct emi_region_info_t region_info; + + /*set MPU for EMI share Memory */ + WMT_PLAT_PR_INFO("setting MPU for EMI share memory\n"); + + region_info.start = gConEmiPhyBase; + region_info.end = gConEmiPhyBase + gConEmiSize - 1; + region_info.region = 25; + SET_ACCESS_PERMISSION(region_info.apc, LOCK, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + NO_PROTECTION, FORBIDDEN, NO_PROTECTION); + emi_mpu_set_protection(®ion_info); +#endif + return 0; +} + +static UINT32 consys_emi_set_remapping_reg(VOID) +{ + UINT32 addrPhy = 0; + UINT32 value = 0; + + mtk_wcn_emi_addr_info.emi_ap_phy_addr = gConEmiPhyBase; + mtk_wcn_emi_addr_info.emi_size = gConEmiSize; + + /*consys to ap emi remapping register:10001380, cal remapping address */ + addrPhy = (gConEmiPhyBase >> 24) & 0xFFF; + value = CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET); + WMT_PLAT_PR_INFO("before CONSYS_EMI_MAPPING read:0x%zx, value:0x%x\n", + conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, value); + + value = value & 0xFFFFF000; + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, value | addrPhy); + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); + + /*Perisys Configuration Registers remapping*/ + addrPhy = ((0x10003000 >> 24) & 0xFFF) << 16; + value = CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_PERI_MAPPING_OFFSET); + value = value & 0xF000FFFF; + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_PERI_MAPPING_OFFSET, value | addrPhy); + + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_PERI_MAPPING_OFFSET)); + + mtk_wcn_emi_addr_info.emi_ram_bt_buildtime_offset = + CONSYS_EMI_RAM_BT_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_ram_wifi_buildtime_offset = + CONSYS_EMI_RAM_WIFI_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_ram_mcu_buildtime_offset = + CONSYS_EMI_RAM_MCU_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_patch_mcu_buildtime_offset = + CONSYS_EMI_PATCH_MCU_BUILDTIME_OFFSET; + + return 0; +} + +static INT32 bt_wifi_share_v33_spin_lock_init(VOID) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + gBtWifiV33.counter = 0; + spin_lock_init(&gBtWifiV33.lock); +#endif + return 0; +} + +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag) +{ + struct device_node *node; + + node = pdev->dev.of_node; + if (node) { + *irq_num = irq_of_parse_and_map(node, 0); + *irq_flag = irq_get_trigger_type(*irq_num); + WMT_PLAT_PR_INFO("get irq id(%d) and irq trigger flag(%d) from DT\n", *irq_num, + *irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return -1; + } + + return 0; +} + +static INT32 consys_read_reg_from_dts(struct platform_device *pdev) +{ + INT32 iRet = -1; + struct device_node *node = NULL; + + node = pdev->dev.of_node; + if (node) { + /* registers base address */ + conn_reg.mcu_base = (SIZE_T) of_iomap(node, MCU_BASE_INDEX); + conn_reg.ap_rgu_base = (SIZE_T) of_iomap(node, TOP_RGU_BASE_INDEX); + conn_reg.topckgen_base = (SIZE_T) of_iomap(node, INFRACFG_AO_BASE_INDEX); + conn_reg.spm_base = (SIZE_T) of_iomap(node, SPM_BASE_INDEX); + conn_reg.mcu_top_misc_off_base = (SIZE_T) of_iomap(node, MCU_TOP_MISC_OFF_BASE_INDEX); + conn_reg.mcu_conn_hif_on_base = (SIZE_T) of_iomap(node, MCU_CONN_HIF_ON_BASE_INDEX); + conn_reg.mcu_cfg_on_base = (SIZE_T) of_iomap(node, MCU_CFG_ON_BASE_INDEX); + conn_reg.mcu_cirq_base = (SIZE_T) of_iomap(node, MCU_CIRQ_BASE_INDEX); + conn_reg.mcu_top_misc_on_base = (SIZE_T) of_iomap(node, MCU_TOP_MISC_ON_BASE_INDEX); + conn_reg.mcu_conn_hif_pdma_base = (SIZE_T) of_iomap(node, MCU_CONN_HIF_PDMA_BASE_INDEX); + conn_reg.infracfg_reg_base = (SIZE_T) of_iomap(node, INFRACFG_REG_BASE_INDEX); + + WMT_PLAT_PR_DBG("Get base mcu(0x%zx), rgu(0x%zx), topckgen(0x%zx), spm(0x%zx)\n", + conn_reg.mcu_base, conn_reg.ap_rgu_base, + conn_reg.topckgen_base, conn_reg.spm_base); + WMT_PLAT_PR_DBG("Get base misc_off(0x%zx), hif_on(0x%zx), cfg_on(0x%zx), misc_on(0x%zx)\n", + conn_reg.mcu_top_misc_off_base, + conn_reg.mcu_conn_hif_on_base, + conn_reg.mcu_cfg_on_base, + conn_reg.mcu_top_misc_on_base); + WMT_PLAT_PR_DBG("Get hif_pdma(0x%zx)\n", + conn_reg.mcu_conn_hif_pdma_base); + WMT_PLAT_PR_DBG("Get infracfg_reg(0x%zx)\n", + conn_reg.infracfg_reg_base); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iRet; + } + + return 0; +} + +static VOID force_trigger_assert_debug_pin(VOID) +{ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + usleep_range(64, 96); + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); +} + +static UINT32 consys_read_cpupcr(VOID) +{ + return CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base + CONSYS_CPUPCR_OFFSET); +} + +static UINT32 consys_soc_chipid_get(VOID) +{ + return PLATFORM_SOC_CHIP; +} + +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID) +{ + return &mtk_wcn_emi_addr_info; +} + +P_WMT_CONSYS_IC_OPS mtk_wcn_get_consys_ic_ops(VOID) +{ + return &consys_ic_ops; +} + +static INT32 consys_dl_rom_patch(UINT32 ip_ver, UINT32 fw_ver) +{ + if (rom_patch_dl_flag) { + if (mtk_wcn_soc_rom_patch_dwn(ip_ver, fw_ver) == 0) + rom_patch_dl_flag = 1; + else + return -1; + } + + return 0; +} + +static VOID consys_set_dl_rom_patch_flag(INT32 flag) +{ + rom_patch_dl_flag = flag; +} + +static INT32 consys_dedicated_log_path_init(struct platform_device *pdev) +{ + struct device_node *node; + UINT32 irq_num; + UINT32 irq_flag; + INT32 iret = -1; + + node = pdev->dev.of_node; + if (node) { + irq_num = irq_of_parse_and_map(node, 2); + irq_flag = irq_get_trigger_type(irq_num); + WMT_PLAT_PR_INFO("get conn2ap_sw_irq id(%d) and irq trigger flag(%d) from DT\n", irq_num, + irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iret; + } + + connsys_dedicated_log_path_apsoc_init(gConEmiPhyBase, irq_num, irq_flag); +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + fw_log_wmt_init(); +#endif + return 0; +} + +static VOID consys_dedicated_log_path_deinit(VOID) +{ +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + fw_log_wmt_deinit(); +#endif + connsys_dedicated_log_path_apsoc_deinit(); +} + +static INT32 consys_check_reg_readable(VOID) +{ + INT32 flag = 0; + UINT32 value = 0; + P_DEV_WMT pDev = &gDevWmt; + + if ((wmt_lib_get_drv_status(WMTDRV_TYPE_WMT) == DRV_STS_FUNC_ON) + && (osal_test_bit(WMT_STAT_PWR, &pDev->state))) { + /*check connsys clock and sleep status*/ + CONSYS_REG_WRITE(conn_reg.mcu_conn_hif_on_base, CONSYS_CLOCK_CHECK_VALUE); + udelay(1000); + value = CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base); + if ((value & CONSYS_HCLK_CHECK_BIT) && + (value & CONSYS_OSCCLK_CHECK_BIT) && + ((value & CONSYS_SLEEP_CHECK_BIT) == 0)) + flag = 1; + } + + if (!flag) + WMT_PLAT_PR_ERR("connsys clock check fail 0x18007000(0x%x)\n", value); + + return flag; +} + +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable) +{ + if (enable) { + *addr = ioremap(gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET, CONSYS_EMI_MEM_SIZE); + if (*addr) { + WMT_PLAT_PR_INFO("COREDUMP EMI mapping OK virtual(0x%p) physical(0x%x)\n", + *addr, (UINT32) gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET); + memset_io(*addr, 0, CONSYS_EMI_MEM_SIZE); + } else { + WMT_PLAT_PR_ERR("EMI mapping fail\n"); + return -1; + } + } else { + if (*addr) { + iounmap(*addr); + *addr = NULL; + } + } + return 0; +} + +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr) +{ + if (!addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + WMT_PLAT_PR_INFO("Reset EMI(0xF0068000 ~ 0xF0068400) and (0xF0070400 ~ 0xF0078400)\n"); + /* reset 0xF0068000 ~ 0xF0068400 (1K) */ + memset_io(addr, 0, 0x400); + /* reset 0xF0070400 ~ 0xF0078400 (32K) */ + memset_io(addr + CONSYS_EMI_PAGED_DUMP_OFFSET, 0, 0x8000); + return 0; +} + +static INT32 consys_is_connsys_reg(UINT32 addr) +{ + if (addr > 0x18000000 && addr < 0x180FFFFF) { + if (addr >= 0x18007000 && addr <= 0x18007FFF) + return 0; + + return 1; + } + + return 0; +} + +static PUINT32 consys_resume_dump_info(VOID) +{ + if (conn_reg.mcu_cfg_on_base != 0 && + conn_reg.mcu_top_misc_on_base != 0 && + mtk_consys_check_reg_readable()) { + stp_dbg_clear_cpupcr_reg_info(); + stp_dbg_poll_cpupcr(5, 0, 1); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR, 0x1); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_MON_CTL_ADDR, 0x80000001); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_DBGSEL_ADDR, 0x3); + g_connsys_lp_dump_info[0] = (UINT32)CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_MAPPING_AP_ADDR; + g_connsys_lp_dump_info[1] = CONSYS_REG_READ(CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_ADDR); + WMT_PLAT_PR_INFO("0x%08x: 0x%x\n", g_connsys_lp_dump_info[0], g_connsys_lp_dump_info[1]); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR, 0x0); + return &g_connsys_lp_dump_info[0]; + } + return NULL; +} + +static VOID consys_set_pdma_axi_rready_force_high(UINT32 enable) +{ + if (enable) + CONSYS_SET_BIT(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_PDMA_AXI_RREADY, + CONSYS_PDMA_AXI_RREADY_MASK); + else if ((CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_PDMA_AXI_RREADY) & + CONSYS_PDMA_AXI_RREADY_MASK) != 0) + CONSYS_CLR_BIT(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_PDMA_AXI_RREADY, + CONSYS_PDMA_AXI_RREADY_MASK); +} + +static VOID consys_infra_reg_dump(VOID) +{ + UINT32 infra_topaxi_si3_sta = + CONSYS_REG_READ(conn_reg.infracfg_reg_base + INFRAGCFG_REG_TOPAXI_SI3_STA_OFFSET); + UINT32 infra_topaxi_mi_sta = + CONSYS_REG_READ(conn_reg.infracfg_reg_base + INFRAGCFG_REG_TOPAXI_MI_STA_OFFSET); + UINT32 infra_topaxi_prot_sta0 = + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA0_OFFSET); + UINT32 infra_topaxi_prot_sta1 = + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA1_OFFSET); + + + WMT_PLAT_PR_INFO("INFRA_TOPAXI_SI3_STA(0x%zx): 0x%x\n", + conn_reg.infracfg_reg_base + INFRAGCFG_REG_TOPAXI_SI3_STA_OFFSET, + infra_topaxi_si3_sta); + WMT_PLAT_PR_INFO("INFRA_TOPAXI_MI_STA(0x%zx): 0x%x\n", + conn_reg.infracfg_reg_base + INFRAGCFG_REG_TOPAXI_MI_STA_OFFSET, + infra_topaxi_mi_sta); + WMT_PLAT_PR_INFO("INFRA_TOPAXI_PROTECTEN_STA0(0x%zx): 0x%x\n", + conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA0_OFFSET, + infra_topaxi_prot_sta0); + WMT_PLAT_PR_INFO("INFRA_TOPAXI_PROTECTEN_STA1(0x%zx): 0x%x\n", + conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA1_OFFSET, + infra_topaxi_prot_sta1); +} + +static VOID consys_get_ant_sel_cr_addr(PUINT32 default_invert_cr, PUINT32 default_invert_bit) +{ + if (default_invert_cr) { + default_invert_cr[0] = DEFAULT_COEX_WMT_ANTSEL_0_POLARITY_CR; + default_invert_cr[1] = DEFAULT_COEX_WMT_ANTSEL_1_POLARITY_CR; + default_invert_cr[2] = DEFAULT_COEX_WMT_ANTSEL_2_POLARITY_CR; + default_invert_cr[3] = DEFAULT_COEX_WMT_ANTSEL_3_POLARITY_CR; + default_invert_cr[4] = DEFAULT_COEX_WMT_ANTSEL_4_POLARITY_CR; + default_invert_cr[5] = DEFAULT_COEX_WMT_ANTSEL_5_POLARITY_CR; + default_invert_cr[6] = DEFAULT_COEX_WMT_ANTSEL_6_POLARITY_CR; + default_invert_cr[7] = DEFAULT_COEX_WMT_ANTSEL_7_POLARITY_CR; + } + + if (default_invert_bit) { + default_invert_bit[0] = DEFAULT_COEX_WMT_ANTSEL_0_POLARITY_BIT; + default_invert_bit[1] = DEFAULT_COEX_WMT_ANTSEL_1_POLARITY_BIT; + default_invert_bit[2] = DEFAULT_COEX_WMT_ANTSEL_2_POLARITY_BIT; + default_invert_bit[3] = DEFAULT_COEX_WMT_ANTSEL_3_POLARITY_BIT; + default_invert_bit[4] = DEFAULT_COEX_WMT_ANTSEL_4_POLARITY_BIT; + default_invert_bit[5] = DEFAULT_COEX_WMT_ANTSEL_5_POLARITY_BIT; + default_invert_bit[6] = DEFAULT_COEX_WMT_ANTSEL_6_POLARITY_BIT; + default_invert_bit[7] = DEFAULT_COEX_WMT_ANTSEL_7_POLARITY_BIT; + } +} + +static INT32 consys_calibration_backup_restore_support(VOID) +{ + return 1; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6768.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6768.c new file mode 100644 index 00000000000000..f6f867142d961f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6768.c @@ -0,0 +1,1416 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <connectivity_build_in_adapter.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/memblock.h> +#include <linux/platform_device.h> +#include "connsys_debug_utility.h" +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +#include "fw_log_wmt.h" +#endif +#include "osal_typedef.h" +#include "mt6768.h" +#include "mtk_wcn_consys_hw.h" +#include "wmt_ic.h" +#include "wmt_lib.h" +#include "wmt_plat.h" +#include "stp_dbg.h" + +#ifdef CONFIG_MTK_EMI +#include <mt_emi_api.h> +#endif + +#if CONSYS_PMIC_CTRL_ENABLE +#include <upmu_common.h> +#include <linux/regulator/consumer.h> +#endif + +#ifdef CONFIG_MTK_HIBERNATION +#include <mtk_hibernate_dpm.h> +#endif + +#include <linux/of_reserved_mem.h> + +#include <mtk_clkbuf_ctl.h> + +#ifdef CONFIG_MTK_DEVAPC_DRIVER +#include <devapc_public.h> +#define WMT_DEVAPC_CALLBACK +#endif + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable); +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable); +static VOID consys_hw_spm_clk_gating_enable(VOID); +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable); +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable); +static INT32 polling_consys_chipid(VOID); +static VOID consys_acr_reg_setting(VOID); +static VOID consys_afe_reg_setting(VOID); +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable); +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable); +static INT32 consys_hw_vcn28_ctrl(UINT32 enable); +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable); +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable); +static UINT32 consys_soc_chipid_get(VOID); +static INT32 consys_emi_mpu_set_region_protection(VOID); +static UINT32 consys_emi_set_remapping_reg(VOID); +static INT32 bt_wifi_share_v33_spin_lock_init(VOID); +static INT32 consys_clk_get_from_dts(struct platform_device *pdev); +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev); +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag); +static INT32 consys_read_reg_from_dts(struct platform_device *pdev); +static UINT32 consys_read_cpupcr(VOID); +static VOID force_trigger_assert_debug_pin(VOID); +static INT32 consys_co_clock_type(VOID); +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID); +static VOID consys_set_if_pinmux(MTK_WCN_BOOL enable); +static INT32 consys_dl_rom_patch(UINT32 ip_ver, UINT32 fw_ver); +static VOID consys_set_dl_rom_patch_flag(INT32 flag); +static INT32 consys_dedicated_log_path_init(struct platform_device *pdev); +static VOID consys_dedicated_log_path_deinit(VOID); +static INT32 consys_check_reg_readable(VOID); +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable); +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr); +static VOID consys_ic_clock_fail_dump(VOID); +static INT32 consys_is_connsys_reg(UINT32 addr); +static PUINT32 consys_resume_dump_info(VOID); +static VOID consys_set_pdma_axi_rready_force_high(UINT32 enable); +static INT32 consys_calibration_backup_restore_support(VOID); +#ifdef WMT_DEVAPC_CALLBACK +static VOID consys_devapc_violation_cb(VOID); +static VOID consyc_register_devapc_cb(VOID); +#endif +static INT32 consys_is_ant_swap_enable_by_hwid(INT32 pin_num); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status gBtWifiV33; +#endif + +/* CCF part */ +struct clk *clk_scp_conn_main; /*ctrl conn_power_on/off */ + +/* PMIC part */ +#if CONSYS_PMIC_CTRL_ENABLE +struct regulator *reg_VCN18; +struct regulator *reg_VCN28; +struct regulator *reg_VCN33_BT; +struct regulator *reg_VCN33_WIFI; +#endif + +EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { + .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, + .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, + .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, + .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, + .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, + .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, + .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, + .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, + .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, + .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, + .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, + .emi_apmem_ctrl_chip_page_dump_num = EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM, + .emi_apmem_ctrl_assert_flag = EXP_APMEM_CTRL_ASSERT_FLAG, +}; + +CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { + .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, + .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, + .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, + .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, + .emi_remap_offset = CONSYS_EMI_MAPPING_OFFSET, + .p_ecso = &mtk_wcn_emi_state_off, + .emi_core_dump_offset = CONSYS_EMI_COREDUMP_OFFSET, + .pda_dl_patch_flag = 1, + .emi_met_size = (32*KBYTE), + .emi_met_data_offset = CONSYS_EMI_MET_DATA_OFFSET, +}; + +WMT_CONSYS_IC_OPS consys_ic_ops = { + .consys_ic_clock_buffer_ctrl = consys_clock_buffer_ctrl, + .consys_ic_hw_reset_bit_set = consys_hw_reset_bit_set, + .consys_ic_hw_spm_clk_gating_enable = consys_hw_spm_clk_gating_enable, + .consys_ic_hw_power_ctrl = consys_hw_power_ctrl, + .consys_ic_ahb_clock_ctrl = consys_ahb_clock_ctrl, + .polling_consys_ic_chipid = polling_consys_chipid, + .consys_ic_acr_reg_setting = consys_acr_reg_setting, + .consys_ic_afe_reg_setting = consys_afe_reg_setting, + .consys_ic_hw_vcn18_ctrl = consys_hw_vcn18_ctrl, + .consys_ic_vcn28_hw_mode_ctrl = consys_vcn28_hw_mode_ctrl, + .consys_ic_hw_vcn28_ctrl = consys_hw_vcn28_ctrl, + .consys_ic_hw_wifi_vcn33_ctrl = consys_hw_wifi_vcn33_ctrl, + .consys_ic_hw_bt_vcn33_ctrl = consys_hw_bt_vcn33_ctrl, + .consys_ic_soc_chipid_get = consys_soc_chipid_get, + .consys_ic_emi_mpu_set_region_protection = consys_emi_mpu_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .ic_bt_wifi_share_v33_spin_lock_init = bt_wifi_share_v33_spin_lock_init, + .consys_ic_clk_get_from_dts = consys_clk_get_from_dts, + .consys_ic_pmic_get_from_dts = consys_pmic_get_from_dts, + .consys_ic_read_irq_info_from_dts = consys_read_irq_info_from_dts, + .consys_ic_read_reg_from_dts = consys_read_reg_from_dts, + .consys_ic_read_cpupcr = consys_read_cpupcr, + .ic_force_trigger_assert_debug_pin = force_trigger_assert_debug_pin, + .consys_ic_co_clock_type = consys_co_clock_type, + .consys_ic_soc_get_emi_phy_add = consys_soc_get_emi_phy_add, + .consys_ic_set_if_pinmux = consys_set_if_pinmux, + .consys_ic_set_dl_rom_patch_flag = consys_set_dl_rom_patch_flag, + .consys_ic_dedicated_log_path_init = consys_dedicated_log_path_init, + .consys_ic_dedicated_log_path_deinit = consys_dedicated_log_path_deinit, + .consys_ic_check_reg_readable = consys_check_reg_readable, + .consys_ic_emi_coredump_remapping = consys_emi_coredump_remapping, + .consys_ic_reset_emi_coredump = consys_reset_emi_coredump, + .consys_ic_clock_fail_dump = consys_ic_clock_fail_dump, + .consys_ic_is_connsys_reg = consys_is_connsys_reg, + .consys_ic_resume_dump_info = consys_resume_dump_info, + .consys_ic_set_pdma_axi_rready_force_high = consys_set_pdma_axi_rready_force_high, + .consys_ic_calibration_backup_restore = consys_calibration_backup_restore_support, +#ifdef WMT_DEVAPC_CALLBACK + .consys_ic_register_devapc_cb = consyc_register_devapc_cb, +#endif + .consys_ic_is_ant_swap_enable_by_hwid = consys_is_ant_swap_enable_by_hwid, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 rom_patch_dl_flag = 1; +UINT32 gJtagCtrl; +UINT32 g_connsys_lp_dump_info[2]; + +#ifdef WMT_DEVAPC_CALLBACK +static struct devapc_vio_callbacks devapc_handle = { + .id = INFRA_SUBSYS_CONN, + .debug_dump = consys_devapc_violation_cb, +}; +#endif + +#if CONSYS_ENALBE_SET_JTAG +#define JTAG_ADDR1_BASE 0x10005000 +#define JTAG_ADDR2_BASE 0x10002800 +#define JTAG_ADDR3_BASE 0x10002600 +#define AP2CONN_JTAG_2WIRE_OFFSET 0xF00 +#endif + +INT32 mtk_wcn_consys_jtag_set_for_mcu(VOID) +{ + INT32 ret = 0; +#if CONSYS_ENALBE_SET_JTAG + UINT32 tmp = 0; + PVOID addr = 0; + PVOID remap_addr1 = 0; + PVOID remap_addr2 = 0; + PVOID remap_addr3 = 0; + + if (gJtagCtrl) { + WMT_PLAT_PR_INFO("WCN jtag set for mcu start...\n"); + + switch (gJtagCtrl) { + case 1: + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + ret = -1; + goto error; + } + + remap_addr2 = ioremap(JTAG_ADDR2_BASE, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + ret = -1; + goto error; + } + + remap_addr3 = ioremap(JTAG_ADDR3_BASE, 0x100); + if (remap_addr3 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr3 fail!\n"); + ret = -1; + goto error; + } + /* 7-wire jtag pinmux setting*/ + /* PAD AUX Function Selection */ + addr = remap_addr1 + 0x310; + tmp = readl(addr); + tmp = tmp & 0xfffff00f; + tmp = tmp | 0x440; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr1 + 0x3c0; + tmp = readl(addr); + tmp = tmp & 0xf00ff00f; + tmp = tmp | 0x4400440; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr1 + 0x370; + tmp = readl(addr); + tmp = tmp & 0xfffff0ff; + tmp = tmp | 0x400; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD Driving Selection */ + addr = remap_addr2; + tmp = readl(addr); + tmp = tmp & 0xffe381ff; + tmp = tmp | 0x1c7e00; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr2 + 0x10; + tmp = readl(addr); + tmp = tmp & 0xfffc7fff; + tmp = tmp | 0x38000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr3 + 0x10; + tmp = readl(addr); + tmp = tmp & 0xf8ffffff; + tmp = tmp | 0x7000000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD PULL Selection */ + addr = remap_addr2 + 0x60; + tmp = readl(addr); + tmp = tmp & 0xfffdfd87; + tmp = tmp | 0x20278; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr3 + 0x40; + tmp = readl(addr); + tmp = tmp & 0xffbfffff; + tmp = tmp | 0x400000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + break; + case 2: + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + ret = -1; + goto error; + } + + remap_addr2 = ioremap(0x10002400, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + ret = -1; + goto error; + } + + /* 2-wire jtag pinmux setting*/ + addr = remap_addr1 + 0x450; + tmp = readl(addr); + tmp = tmp & 0xff0fffff; + tmp = tmp | 0x400000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr1 + 0x430; + tmp = readl(addr); + tmp = tmp & 0xfff0ffff; + tmp = tmp | 0x40000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* Driving Selection */ + + addr = remap_addr2; + tmp = readl(addr); + tmp = tmp & 0xffff99ff; + tmp = tmp | 0x6600; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PULL Selection */ + addr = remap_addr2 + 0x10; + tmp = readl(addr); + tmp = tmp & 0xfffff6ff; + tmp = tmp | 0x900; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + break; + default: + WMT_PLAT_PR_INFO("unsupported options!\n"); + } + + } + +error: + if (remap_addr1) + iounmap(remap_addr1); + if (remap_addr2) + iounmap(remap_addr2); + if (remap_addr3) + iounmap(remap_addr3); +#endif + return ret; +} + +UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en) +{ + WMT_PLAT_PR_INFO("%s jtag set for MCU\n", en ? "enable" : "disable"); + gJtagCtrl = en; + return 0; +} + +static INT32 consys_clk_get_from_dts(struct platform_device *pdev) +{ + clk_scp_conn_main = devm_clk_get(&pdev->dev, "conn"); + if (IS_ERR(clk_scp_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_scp_conn_main clock.\n"); + return PTR_ERR(clk_scp_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_scp_conn_main=%p\n", clk_scp_conn_main); + + return 0; +} + +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev) +{ +#if CONSYS_PMIC_CTRL_ENABLE + reg_VCN18 = regulator_get(&pdev->dev, "vcn18"); + if (!reg_VCN18) + WMT_PLAT_PR_ERR("Regulator_get VCN_1V8 fail\n"); + reg_VCN28 = regulator_get(&pdev->dev, "vcn28"); + if (!reg_VCN28) + WMT_PLAT_PR_ERR("Regulator_get VCN_2V8 fail\n"); + reg_VCN33_BT = regulator_get(&pdev->dev, "vcn33_bt"); + if (!reg_VCN33_BT) + WMT_PLAT_PR_ERR("Regulator_get VCN33_BT fail\n"); + reg_VCN33_WIFI = regulator_get(&pdev->dev, "vcn33_wifi"); + if (!reg_VCN33_WIFI) + WMT_PLAT_PR_ERR("Regulator_get VCN33_WIFI fail\n"); +#endif + return 0; +} + +static INT32 consys_co_clock_type(VOID) +{ + return 0; +} + +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable) +{ + if (enable) + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, true); /*open XO_WCN*/ + else + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, false); /*close XO_WCN*/ + + return 0; +} + +static VOID consys_set_if_pinmux(MTK_WCN_BOOL enable) +{ + UINT8 *consys_if_pinmux_reg_base = NULL; + + /* Switch D die pinmux for connecting A die */ + consys_if_pinmux_reg_base = ioremap(CONSYS_IF_PINMUX_REG_BASE, 0x1000); + if (!consys_if_pinmux_reg_base) { + WMT_PLAT_PR_ERR("consys_if_pinmux_reg_base(%x) ioremap fail\n", CONSYS_IF_PINMUX_REG_BASE); + return; + } + + if (enable) { + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET) & + CONSYS_IF_PINMUX_01_MASK) | CONSYS_IF_PINMUX_01_VALUE); + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET) & + CONSYS_IF_PINMUX_02_MASK) | CONSYS_IF_PINMUX_02_VALUE); + } else { + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET, + CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET) & + CONSYS_IF_PINMUX_01_MASK); + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET, + CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET) & + CONSYS_IF_PINMUX_02_MASK); + } + + if (consys_if_pinmux_reg_base) + iounmap(consys_if_pinmux_reg_base); +} + +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable) +{ + UINT32 consys_ver_id = 0; + UINT32 cnt = 0; + + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE((conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET), + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) | + CONSYS_CPU_SW_RST_BIT | CONSYS_CPU_SW_RST_CTRL_KEY); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88 (key)" */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_CPU_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + 0x600); + while (consys_ver_id != 0x1D1E) { + if (cnt > 10) + break; + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + 0x600); + WMT_PLAT_PR_INFO("0x18002600(0x%x)\n", consys_ver_id); + WMT_PLAT_PR_INFO("0x1800216c(0x%x)\n", + CONSYS_REG_READ(conn_reg.mcu_base + 0x16c)); + WMT_PLAT_PR_INFO("0x18007104(0x%x)\n", + CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base + CONSYS_CPUPCR_OFFSET)); + msleep(20); + cnt++; + } + } +} + +static VOID consys_hw_spm_clk_gating_enable(VOID) +{ +} + +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + INT32 iRet = 0; +#else + INT32 value = 0; + INT32 i = 0; +#endif + + if (enable) { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + iRet = clk_prepare_enable(clk_scp_conn_main); + if (iRet) + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_scp_conn_main) fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_scp_conn_main) ok\n"); +#else + /* turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE((conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET), + (CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET) & + 0x0000FFFF) | CONSYS_PWRON_CONFG_EN_VALUE); + + /*write assert "conn_top_on" primary part power on, set "connsys_on_domain_pwr_on"=1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_BIT); + /*read check "conn_top_on" primary part power status, check "connsys_on_domain_pwr_ack"=1 */ + value = CONSYS_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + while (value == 0) + value = CONSYS_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + /*write assert "conn_top_on" secondary part power on, set "connsys_on_domain_pwr_on_s"=1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_S_BIT); + /*read check "conn_top_on" secondary part power status, check "connsys_on_domain_pwr_ack_s"=1 */ + value = CONSYS_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + while (value == 0) + value = CONSYS_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + /*write turn on AP-to-CONNSYS bus clock, set "conn_clk_dis"=0 (apply this for bus + *clock toggling) + */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_CLK_CTRL_BIT); + /*wait 1us*/ + udelay(1); + /*de-assert "conn_top_on" isolation, set "connsys_iso_en"=0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_ISO_S_BIT); + /*read check "conn_top_off" primary part power status, check + *"connsys_off_domain_pwr_ack"=1 + */ + value = CONSYS_TOP2_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + while (value == 0) + value = CONSYS_TOP2_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + /*read check "conn_top_off" secondary part power status, check + *"connsys_off_domain_pwr_ack_s"=1 + */ + value = CONSYS_TOP2_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + while (value == 0) + value = CONSYS_TOP2_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + + /*de-assert CONNSYS S/W reset, set "ap_sw_rst_b"=1 */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + + /*Turn off AHB bus sleep protect (AP2CONN AHB Bus protect) (apply this for INFRA AHB + *bus accessing when CONNSYS had been turned on) + */ + /*disable AHBAXI BUS protect 10001220 [13][14] */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET) & + ~CONSYS_PROT_MASK); + value = ~CONSYS_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i++; + } + /*Disable AXI TX bus sleep protect (CONN2AP AXI Tx Bus protect) (disable sleep + * protection when CONNSYS had been turned on) + * Note : Should turn off AXI Tx sleep protection after AXI Rx sleep protection has + * been turn off. + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_EN_OFFSET) & + ~CONSYS_TX_PROT_MASK); + value = ~CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_STA_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_STA_OFFSET); + i++; + } + /*SPM apsrc/ddr_en hardware mask disable & wait cycle setting*/ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_SPM_APSRC_OFFSET, CONSYS_SPM_APSRC_VALUE); + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_SPM_DDR_EN_OFFSET, CONSYS_SPM_DDR_EN_VALUE); +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } else { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + clk_disable_unprepare(clk_scp_conn_main); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_scp_conn_main) calling\n"); +#else + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET) & + CONSYS_PROT_MASK); + value = CONSYS_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i = 0; + while (value == CONSYS_PROT_MASK || i > 10) { + value = CONSYS_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i++; + } + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_EN_OFFSET) & + CONSYS_TX_PROT_MASK); + value = CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_STA_OFFSET); + i = 0; + while (value == CONSYS_TX_PROT_MASK || i > 10) { + value = CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_TX_PROT_STA_OFFSET); + i++; + } + + /*release connsys ISO, conn_top1_iso_en=1 0x1000632C [1] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ISO_S_BIT); + /*de-assert CONNSYS S/W reset, set "ap_sw_rst_b"=1 */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + CONSYS_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + /*write conn_clk_dis=1, disable connsys clock 0x1000632C [4] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632C [3:2] 2'b00 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } + +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + return iRet; +#else + return 0; +#endif +} + +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable) +{ + return 0; +} + +static INT32 polling_consys_chipid(VOID) +{ + INT32 retry = 10; + UINT32 consys_ver_id = 0; + UINT32 consys_hw_ver = 0; + UINT32 consys_fw_ver = 0; + UINT8 *consys_reg_base = NULL; + UINT32 value = 0; + + /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ + while (retry-- > 0) { + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_top_misc_off_base + CONSYS_IP_VER_OFFSET); + if (consys_ver_id == CONSYS_IP_VER_ID) { + WMT_PLAT_PR_INFO("retry(%d)consys version id(0x%08x)\n", retry, consys_ver_id); + consys_hw_ver = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys HW version id(0x%x)\n", consys_hw_ver & 0xFFFF); + consys_fw_ver = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_FW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys FW version id(0x%x)\n", consys_fw_ver & 0xFFFF); + + if (consys_dl_rom_patch(consys_ver_id, consys_fw_ver) == 0) + break; + } + WMT_PLAT_PR_ERR("Read CONSYS version id(0x%08x)", consys_ver_id); + msleep(20); + } + + if (retry <= 0) + return -1; + + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_top_misc_off_base + CONSYS_CONF_ID_OFFSET); + WMT_PLAT_PR_INFO("consys configuration id(0x%x)\n", consys_ver_id & 0xF); + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys HW version id(0x%x)\n", consys_ver_id & 0xFFFF); + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_FW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys FW version id(0x%x)\n", consys_ver_id & 0xFFFF); + + if (wmt_plat_soc_co_clock_flag_get()) { + consys_reg_base = ioremap(CONSYS_COCLOCK_STABLE_TIME_BASE, 0x100); + if (consys_reg_base) { + /** + * 1. set CR "vcore ready stable time" "XO initial stable time" and + * "XO bg stable time" to optimize the wakeup time after sleep + * 2. clear "source clock enable ack to XO state" mask + */ + value = CONSYS_REG_READ(consys_reg_base); + value = (value & CONSYS_COCLOCK_STABLE_TIME_MASK) | CONSYS_COCLOCK_STABLE_TIME; + CONSYS_REG_WRITE(consys_reg_base, value); + + value = CONSYS_REG_READ(consys_reg_base + CONSYS_COCLOCK_ACK_ENABLE_OFFSET); + value = (value & 0xffff00fe) | 0x600; + CONSYS_REG_WRITE(consys_reg_base + CONSYS_COCLOCK_ACK_ENABLE_OFFSET, value); + iounmap(consys_reg_base); + } else + WMT_PLAT_PR_ERR("connsys co_clock stable time base(0x%x) ioremap fail!\n", + CONSYS_COCLOCK_STABLE_TIME_BASE); + } + + /* EMI control CR setting(hw mode) */ + CONSYS_CLR_BIT(conn_reg.mcu_base + CONSYS_SW_IRQ_OFFSET, CONSYS_EMI_CTRL_VALUE); + + /* toppose_restore_done rollabck */ + CONSYS_REG_WRITE(conn_reg.mcu_top_misc_on_base + CONSYS_TOPPOSE_RESTORE_OFFSET, + (CONSYS_REG_READ(conn_reg.mcu_top_misc_on_base + CONSYS_TOPPOSE_RESTORE_OFFSET) & + CONSYS_TOPPOSE_RESTORE_MASK) | CONSYS_TOPPOSE_RESTORE_VALUE); + + return 0; +} + +static VOID consys_acr_reg_setting(VOID) +{ +} + +static VOID consys_afe_reg_setting(VOID) +{ +#if CONSYS_AFE_REG_SETTING + UINT8 *consys_afe_reg_base = NULL; + + /* update WPLL setting for WPLL issue@LT */ + consys_afe_reg_base = ioremap(CONSYS_AFE_REG_BASE, 0x100); + if (consys_afe_reg_base) { + + UINT32 value = CONSYS_REG_READ(consys_afe_reg_base + CONSYS_AFE_RG_WBG_PLL_03_OFFSET); + + value = (value & 0xffe7ffff) | 0x80000; + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_RG_WBG_PLL_03_OFFSET, value); + iounmap(consys_afe_reg_base); + } else + WMT_PLAT_PR_ERR("AFE base(0x%x) ioremap fail!\n", CONSYS_AFE_REG_BASE); +#endif +} + +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*need PMIC driver provide new API protocol */ + /*1.AP power on VCN_1V8 LDO (with PMIC_WRAP API) VCN_1V8 */ + /*set vcn18 SW mode*/ + KERNEL_upmu_set_reg_value(MT6358_LDO_VCN18_OP_EN, 0x1); + if (reg_VCN18) { + regulator_set_voltage(reg_VCN18, 1800000, 1800000); + if (regulator_enable(reg_VCN18)) + WMT_PLAT_PR_ERR("enable VCN18 fail\n"); + else + WMT_PLAT_PR_DBG("enable VCN18 ok\n"); + } + + if (!(wmt_lib_get_ext_ldo())) { + KERNEL_upmu_set_reg_value(MT6358_LDO_VCN33_OP_EN, 0x1); + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } + } else + WMT_PLAT_PR_INFO("VCN33 uses external LDO!\n"); + } else { + if (!(wmt_lib_get_ext_ldo())) { + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); + } + + /*AP power off MT6358 VCN_1V8 LDO */ + if (reg_VCN18) { + if (regulator_disable(reg_VCN18)) + WMT_PLAT_PR_ERR("disable VCN_1V8 fail!\n"); + else + WMT_PLAT_PR_DBG("disable VCN_1V8 ok\n"); + } + } +#endif + return 0; +} + +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); + } else { + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); + } +#endif +} + +static INT32 consys_hw_vcn28_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*in co-clock mode,need to turn on vcn28 when fm on */ + if (reg_VCN28) { + regulator_set_voltage(reg_VCN28, 2800000, 2800000); + if (regulator_enable(reg_VCN28)) + WMT_PLAT_PR_ERR("WMT do VCN28 PMIC on fail!\n"); + } + WMT_PLAT_PR_INFO("turn on vcn28 for fm/gps usage in co-clock mode\n"); + } else { + /*in co-clock mode,need to turn off vcn28 when fm off */ + if (reg_VCN28) + regulator_disable(reg_VCN28); + WMT_PLAT_PR_INFO("turn off vcn28 for fm/gps usage in co-clock mode\n"); + } +#endif + return 0; +} + +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable) +{ +#if 0 +#if CONSYS_BT_WIFI_SHARE_V33 + /* spin_lock_irqsave(&gBtWifiV33.lock,gBtWifiV33.flags); */ + if (enable) { + if (gBtWifiV33.counter == 1) { + gBtWifiV33.counter++; + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else if (gBtWifiV33.counter == 2) { + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else { +#if CONSYS_PMIC_CTRL_ENABLE + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + hwPowerOn(MT6351_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); + mt6351_upmu_set_rg_vcn33_on_ctrl(1); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 on\n"); + gBtWifiV33.counter++; + } + + } else { + if (gBtWifiV33.counter == 1) { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + mt6351_upmu_set_rg_vcn33_on_ctrl(0); + hwPowerDown(MT6351_POWER_LDO_VCN33_BT, "wcn_drv"); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 off\n"); + gBtWifiV33.counter--; + } else if (gBtWifiV33.counter == 2) { + gBtWifiV33.counter--; + WMT_PLAT_PR_DBG("V33 no need disabled,counter(%d)\n", gBtWifiV33.counter); + } else { + WMT_PLAT_PR_DBG("V33 has been disabled,counter(%d)\n", gBtWifiV33.counter); + } + + } + /* spin_unlock_irqrestore(&gBtWifiV33.lock,gBtWifiV33.flags); */ +#else + if (enable) { + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } + + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC on\n"); + } else { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC off\n"); + } +#endif + +#endif + return 0; +} + +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable) +{ +#if 0 +#if CONSYS_BT_WIFI_SHARE_V33 + mtk_wcn_consys_hw_bt_paldo_ctrl(enable); +#else + if (enable) { + /*do WIFI PMIC on,depenency PMIC API ready */ + /*switch WIFI PALDO control from SW mode to HW mode:0x418[14]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + if (reg_VCN33_WIFI) { + regulator_set_voltage(reg_VCN33_WIFI, 3300000, 3300000); + if (regulator_enable(reg_VCN33_WIFI)) + WMT_PLAT_PR_ERR("WMT do WIFI PMIC on fail!\n"); + } + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC on\n"); + } else { + /*do WIFI PMIC off */ + /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); + if (reg_VCN33_WIFI) + regulator_disable(reg_VCN33_WIFI); +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC off\n"); + } + +#endif + +#endif + return 0; +} + +static INT32 consys_emi_mpu_set_region_protection(VOID) +{ +#ifdef CONFIG_MTK_EMI + struct emi_region_info_t region_info; + + /*set MPU for EMI share Memory */ + WMT_PLAT_PR_INFO("setting MPU for EMI share memory\n"); + + region_info.start = gConEmiPhyBase; + region_info.end = gConEmiPhyBase + gConEmiSize - 1; + region_info.region = 26; + SET_ACCESS_PERMISSION(region_info.apc, LOCK, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + NO_PROTECTION, FORBIDDEN, NO_PROTECTION); + emi_mpu_set_protection(®ion_info); +#endif + return 0; +} + +static UINT32 consys_emi_set_remapping_reg(VOID) +{ + UINT32 addrPhy = 0; + UINT32 value = 0; + + mtk_wcn_emi_addr_info.emi_ap_phy_addr = gConEmiPhyBase; + mtk_wcn_emi_addr_info.emi_size = gConEmiSize; + + /*consys to ap emi remapping register:10001380, cal remapping address */ + addrPhy = (gConEmiPhyBase >> 24) & 0xFFF; + value = CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET); + WMT_PLAT_PR_INFO("before CONSYS_EMI_MAPPING read:0x%zx, value:0x%x\n", + conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, value); + + value = value & 0xFFFFF000; + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, value | addrPhy); + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); + + /*Perisys Configuration Registers remapping*/ + addrPhy = ((0x10003000 >> 24) & 0xFFF) << 16; + value = CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_PERI_MAPPING_OFFSET); + value = value & 0xF000FFFF; + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_PERI_MAPPING_OFFSET, value | addrPhy); + + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_PERI_MAPPING_OFFSET)); + + mtk_wcn_emi_addr_info.emi_ram_bt_buildtime_offset = + CONSYS_EMI_RAM_BT_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_ram_wifi_buildtime_offset = + CONSYS_EMI_RAM_WIFI_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_ram_mcu_buildtime_offset = + CONSYS_EMI_RAM_MCU_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_patch_mcu_buildtime_offset = + CONSYS_EMI_PATCH_MCU_BUILDTIME_OFFSET; + + return 0; +} + +static INT32 bt_wifi_share_v33_spin_lock_init(VOID) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + gBtWifiV33.counter = 0; + spin_lock_init(&gBtWifiV33.lock); +#endif + return 0; +} + +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag) +{ + struct device_node *node; + + node = pdev->dev.of_node; + if (node) { + *irq_num = irq_of_parse_and_map(node, 0); + *irq_flag = irq_get_trigger_type(*irq_num); + WMT_PLAT_PR_INFO("get irq id(%d) and irq trigger flag(%d) from DT\n", *irq_num, + *irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return -1; + } + + return 0; +} + +static INT32 consys_read_reg_from_dts(struct platform_device *pdev) +{ + INT32 iRet = -1; + struct device_node *node = NULL; + + node = pdev->dev.of_node; + if (node) { + /* registers base address */ + conn_reg.mcu_base = (SIZE_T) of_iomap(node, MCU_BASE_INDEX); + conn_reg.ap_rgu_base = (SIZE_T) of_iomap(node, TOP_RGU_BASE_INDEX); + conn_reg.topckgen_base = (SIZE_T) of_iomap(node, INFRACFG_AO_BASE_INDEX); + conn_reg.spm_base = (SIZE_T) of_iomap(node, SPM_BASE_INDEX); + conn_reg.mcu_top_misc_off_base = (SIZE_T) of_iomap(node, MCU_TOP_MISC_OFF_BASE_INDEX); + conn_reg.mcu_conn_hif_on_base = (SIZE_T) of_iomap(node, MCU_CONN_HIF_ON_BASE_INDEX); + conn_reg.mcu_cfg_on_base = (SIZE_T) of_iomap(node, MCU_CFG_ON_BASE_INDEX); + conn_reg.mcu_cirq_base = (SIZE_T) of_iomap(node, MCU_CIRQ_BASE_INDEX); + conn_reg.mcu_top_misc_on_base = (SIZE_T) of_iomap(node, MCU_TOP_MISC_ON_BASE_INDEX); + conn_reg.mcu_conn_hif_pdma_base = (SIZE_T) of_iomap(node, MCU_CONN_HIF_PDMA_BASE_INDEX); + + WMT_PLAT_PR_DBG("Get base mcu(0x%zx), rgu(0x%zx), topckgen(0x%zx), spm(0x%zx)\n", + conn_reg.mcu_base, conn_reg.ap_rgu_base, + conn_reg.topckgen_base, conn_reg.spm_base); + WMT_PLAT_PR_DBG("Get base misc_off(0x%zx), hif_on(0x%zx), cfg_on(0x%zx), misc_on(0x%zx)\n", + conn_reg.mcu_top_misc_off_base, + conn_reg.mcu_conn_hif_on_base, + conn_reg.mcu_cfg_on_base, + conn_reg.mcu_top_misc_on_base); + WMT_PLAT_PR_DBG("Get hif_pdma(0x%zx)\n", + conn_reg.mcu_conn_hif_pdma_base); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iRet; + } + + return 0; +} + +static VOID force_trigger_assert_debug_pin(VOID) +{ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + usleep_range(64, 96); + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); +} + +static UINT32 consys_read_cpupcr(VOID) +{ + return CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base + CONSYS_CPUPCR_OFFSET); +} + +static UINT32 consys_soc_chipid_get(VOID) +{ + return PLATFORM_SOC_CHIP; +} + +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID) +{ + return &mtk_wcn_emi_addr_info; +} + +P_WMT_CONSYS_IC_OPS mtk_wcn_get_consys_ic_ops(VOID) +{ + return &consys_ic_ops; +} + +static INT32 consys_dl_rom_patch(UINT32 ip_ver, UINT32 fw_ver) +{ + if (rom_patch_dl_flag) { + if (mtk_wcn_soc_rom_patch_dwn(ip_ver, fw_ver) == 0) + rom_patch_dl_flag = 1; + else + return -1; + } + + return 0; +} + +static VOID consys_set_dl_rom_patch_flag(INT32 flag) +{ + rom_patch_dl_flag = flag; +} + +static INT32 consys_dedicated_log_path_init(struct platform_device *pdev) +{ + struct device_node *node; + UINT32 irq_num; + UINT32 irq_flag; + INT32 iret = -1; + + node = pdev->dev.of_node; + if (node) { + irq_num = irq_of_parse_and_map(node, 2); + irq_flag = irq_get_trigger_type(irq_num); + WMT_PLAT_PR_INFO("get conn2ap_sw_irq id(%d) and irq trigger flag(%d) from DT\n", irq_num, + irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iret; + } + + connsys_dedicated_log_path_apsoc_init(gConEmiPhyBase, irq_num, irq_flag); +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + fw_log_wmt_init(); +#endif + return 0; +} + +static VOID consys_dedicated_log_path_deinit(VOID) +{ +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + fw_log_wmt_deinit(); +#endif + connsys_dedicated_log_path_apsoc_deinit(); +} + +static INT32 consys_check_reg_readable(VOID) +{ + INT32 flag = 0; + UINT32 value = 0; + P_DEV_WMT pDev = &gDevWmt; + + if ((wmt_lib_get_drv_status(WMTDRV_TYPE_WMT) == DRV_STS_FUNC_ON) + && (osal_test_bit(WMT_STAT_PWR, &pDev->state))) { + /*check connsys clock and sleep status*/ + CONSYS_REG_WRITE(conn_reg.mcu_conn_hif_on_base, CONSYS_CLOCK_CHECK_VALUE); + udelay(1000); + value = CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base); + if ((value & CONSYS_HCLK_CHECK_BIT) && + (value & CONSYS_OSCCLK_CHECK_BIT) && + ((value & CONSYS_SLEEP_CHECK_BIT) == 0)) + flag = 1; + } + + if (!flag) + WMT_PLAT_PR_ERR("connsys clock check fail 0x18007000(0x%x)\n", value); + + return flag; +} + +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable) +{ + if (enable) { + *addr = ioremap(gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET, CONSYS_EMI_MEM_SIZE); + if (*addr) { + WMT_PLAT_PR_INFO("COREDUMP EMI mapping OK virtual(0x%p) physical(0x%x)\n", + *addr, (UINT32) gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET); + memset_io(*addr, 0, CONSYS_EMI_MEM_SIZE); + } else { + WMT_PLAT_PR_ERR("EMI mapping fail\n"); + return -1; + } + } else { + if (*addr) { + iounmap(*addr); + *addr = NULL; + } + } + return 0; +} + +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr) +{ + if (!addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + WMT_PLAT_PR_INFO("Reset EMI(0xF0068000 ~ 0xF0068400) and (0xF0070400 ~ 0xF0078400)\n"); + /* reset 0xF0068000 ~ 0xF0068400 (1K) */ + memset_io(addr, 0, 0x400); + /* reset 0xF0070400 ~ 0xF0078400 (32K) */ + memset_io(addr + CONSYS_EMI_PAGED_DUMP_OFFSET, 0, 0x8000); + return 0; +} + +static INT32 consys_is_connsys_reg(UINT32 addr) +{ + if (addr > 0x18000000 && addr < 0x180FFFFF) { + if (addr >= 0x18007000 && addr <= 0x18007FFF) + return 0; + + return 1; + } + + return 0; +} + +static VOID consys_ic_clock_fail_dump(VOID) +{ + INT8 *addr; + char *buffer, *temp; + INT32 size = 1024; + + /* make sure buffer size is big enough */ + buffer = osal_malloc(size); + if (!buffer) + return; + + temp = buffer; + temp += sprintf(temp, "CONN_HIF_TOP_MISC=0x%08x CONN_HIF_BUSY_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_TOP_MISC), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_BUSY_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_HIF_DBG_IDX, 0x3333); + temp += sprintf(temp, "Write CONSYS_HIF_DBG_IDX to 0x3333\n"); + + temp += sprintf(temp, "CONSYS_HIF_DBG_PROBE=0x%08x CONN_HIF_TOP_MISC=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_DBG_PROBE), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_TOP_MISC)); + + temp += sprintf(temp, "CONN_HIF_BUSY_STATUS=0x%08x CONN_HIF_PDMA_BUSY_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_BUSY_STATUS), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_PDMA_BUSY_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_HIF_DBG_IDX, 0x2222); + temp += sprintf(temp, "Write CONSYS_HIF_DBG_IDX to 0x2222\n"); + + temp += sprintf(temp, "CONSYS_HIF_DBG_PROBE=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_DBG_PROBE)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_HIF_DBG_IDX, 0x3333); + temp += sprintf(temp, "Write CONSYS_HIF_DBG_IDX to 0x3333\n"); + + temp += sprintf(temp, "CONSYS_HIF_DBG_PROBE=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_DBG_PROBE)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_HIF_DBG_IDX, 0x4444); + temp += sprintf(temp, "Write CONSYS_HIF_DBG_IDX to 0x4444\n"); + + temp += sprintf(temp, "CONSYS_HIF_DBG_PROBE=0x%08x CONN_MCU_EMI_CONTROL=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_DBG_PROBE), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_SW_IRQ_OFFSET)); + temp += sprintf(temp, "EMI_CONTROL_DBG_PROBE=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + EMI_CONTROL_DBG_PROBE)); + temp += sprintf(temp, "CONN_MCU_CLOCK_CONTROL=0x%08x CONN_MCU_BUS_CONTROL=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CLOCK_CONTROL), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_BUS_CONTROL)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x003e3d00); + temp += sprintf(temp, "Write CONSYS_DEBUG_SELECT to 0x003e3d00\n"); + + temp += sprintf(temp, "CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x00403f00); + temp += sprintf(temp, "Write CONSYS_DEBUG_SELECT to 0x00403f00\n"); + + temp += sprintf(temp, "CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x00424100); + temp += sprintf(temp, "Write CONSYS_DEBUG_SELECT to 0x00424100\n"); + + temp += sprintf(temp, "CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x00444300); + temp += sprintf(temp, "Write CONSYS_DEBUG_SELECT to 0x00444300\n"); + + temp += sprintf(temp, "CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + addr = ioremap(0x10001B20, 0x100); + /* 0x1020E804 */ + temp += sprintf(temp, "0x10001B20=0x%08x\n", CONSYS_REG_READ(addr)); + iounmap(addr); + + WMT_PLAT_PR_ERR("%s length = %d", buffer, osal_strlen(buffer)); + osal_free(buffer); +} + +static PUINT32 consys_resume_dump_info(VOID) +{ + if (conn_reg.mcu_cfg_on_base != 0 && + conn_reg.mcu_top_misc_on_base != 0 && + mtk_consys_check_reg_readable()) { + stp_dbg_clear_cpupcr_reg_info(); + stp_dbg_poll_cpupcr(5, 0, 1); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR, 0x1); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_MON_CTL_ADDR, 0x80000001); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_DBGSEL_ADDR, 0x3); + g_connsys_lp_dump_info[0] = (UINT32)CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_MAPPING_AP_ADDR; + g_connsys_lp_dump_info[1] = CONSYS_REG_READ(CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_ADDR); + WMT_PLAT_PR_INFO("0x%08x: 0x%x\n", g_connsys_lp_dump_info[0], g_connsys_lp_dump_info[1]); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR, 0x0); + return &g_connsys_lp_dump_info[0]; + } + return NULL; +} + +static VOID consys_set_pdma_axi_rready_force_high(UINT32 enable) +{ + if (enable) + CONSYS_SET_BIT(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_PDMA_AXI_RREADY, + CONSYS_PDMA_AXI_RREADY_MASK); + else if ((CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_PDMA_AXI_RREADY) & + CONSYS_PDMA_AXI_RREADY_MASK) != 0) + CONSYS_CLR_BIT(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_PDMA_AXI_RREADY, + CONSYS_PDMA_AXI_RREADY_MASK); +} + +static INT32 consys_calibration_backup_restore_support(VOID) +{ + return 1; +} + +#ifdef WMT_DEVAPC_CALLBACK +static VOID consys_devapc_violation_cb(VOID) +{ + /** + * Don't use wmt_lib_trigger_assert() because it will invoke vmalloc and then cause KE since + * this callback is supposed to be invoked in DEVAPC exception hanlder. + */ + wmt_lib_trigger_assert_keyword_delay(WMTDRV_TYPE_WMT, 46, "DEVAPC Violation"); +} + +static VOID consyc_register_devapc_cb(VOID) +{ + register_devapc_vio_callback(&devapc_handle); +} +#endif + +static INT32 consys_is_ant_swap_enable_by_hwid(INT32 pin_num) +{ + return !connectivity_export_gpio_get_tristate_input(pin_num); +} + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6771.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6771.c new file mode 100644 index 00000000000000..ac64123a9cda67 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6771.c @@ -0,0 +1,1067 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <connectivity_build_in_adapter.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/memblock.h> +#include <linux/platform_device.h> +#include "osal_typedef.h" +#include "mt6771.h" +#include "mtk_wcn_consys_hw.h" + +#ifdef CONFIG_MTK_EMI +#include <mt_emi_api.h> +#endif + +#if CONSYS_PMIC_CTRL_ENABLE +#include <upmu_common.h> +#include <linux/regulator/consumer.h> +#endif + +#ifdef CONFIG_MTK_HIBERNATION +#include <mtk_hibernate_dpm.h> +#endif + +#include <linux/of_reserved_mem.h> +#include <mtk_clkbuf_ctl.h> + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable); +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable); +static VOID consys_hw_spm_clk_gating_enable(VOID); +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable); +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable); +static INT32 polling_consys_chipid(VOID); +static VOID update_consys_rom_desel(VOID); +static VOID consys_hang_debug_info(VOID); +static VOID consys_acr_reg_setting(VOID); +static VOID consys_afe_reg_setting(VOID); +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable); +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable); +static INT32 consys_hw_vcn28_ctrl(UINT32 enable); +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable); +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable); +static UINT32 consys_soc_chipid_get(VOID); +static INT32 consys_emi_mpu_set_region_protection(VOID); +static UINT32 consys_emi_set_remapping_reg(VOID); +static INT32 bt_wifi_share_v33_spin_lock_init(VOID); +static INT32 consys_clk_get_from_dts(struct platform_device *pdev); +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev); +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag); +static INT32 consys_read_reg_from_dts(struct platform_device *pdev); +static UINT32 consys_read_cpupcr(VOID); +static VOID force_trigger_assert_debug_pin(VOID); +static INT32 consys_co_clock_type(VOID); +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID); +static VOID consys_set_if_pinmux(MTK_WCN_BOOL enable); +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable); +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +#if CONSYS_BT_WIFI_SHARE_V33 +struct bt_wifi_v33_status gBtWifiV33; +#endif + +/* CCF part */ +struct clk *clk_scp_conn_main; /*ctrl conn_power_on/off */ + +/* PMIC part */ +#if CONSYS_PMIC_CTRL_ENABLE +struct regulator *reg_VCN18; +struct regulator *reg_VCN28; +struct regulator *reg_VCN33_BT; +struct regulator *reg_VCN33_WIFI; +#endif + +EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { + .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, + .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, + .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, + .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, + .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, + .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, + .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, + .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, + .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, + .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, + .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, + .emi_apmem_ctrl_chip_page_dump_num = EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM, + .emi_apmem_ctrl_assert_flag = EXP_APMEM_CTRL_ASSERT_FLAG, +}; + +CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { + .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, + .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, + .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, + .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, + .emi_remap_offset = CONSYS_EMI_MAPPING_OFFSET, + .p_ecso = &mtk_wcn_emi_state_off, + .emi_core_dump_offset = CONSYS_EMI_COREDUMP_OFFSET, +}; + +WMT_CONSYS_IC_OPS consys_ic_ops = { + .consys_ic_clock_buffer_ctrl = consys_clock_buffer_ctrl, + .consys_ic_hw_reset_bit_set = consys_hw_reset_bit_set, + .consys_ic_hw_spm_clk_gating_enable = consys_hw_spm_clk_gating_enable, + .consys_ic_hw_power_ctrl = consys_hw_power_ctrl, + .consys_ic_ahb_clock_ctrl = consys_ahb_clock_ctrl, + .polling_consys_ic_chipid = polling_consys_chipid, + .update_consys_rom_desel_value = update_consys_rom_desel, + .consys_hang_debug = consys_hang_debug_info, + .consys_ic_acr_reg_setting = consys_acr_reg_setting, + .consys_ic_afe_reg_setting = consys_afe_reg_setting, + .consys_ic_hw_vcn18_ctrl = consys_hw_vcn18_ctrl, + .consys_ic_vcn28_hw_mode_ctrl = consys_vcn28_hw_mode_ctrl, + .consys_ic_hw_vcn28_ctrl = consys_hw_vcn28_ctrl, + .consys_ic_hw_wifi_vcn33_ctrl = consys_hw_wifi_vcn33_ctrl, + .consys_ic_hw_bt_vcn33_ctrl = consys_hw_bt_vcn33_ctrl, + .consys_ic_soc_chipid_get = consys_soc_chipid_get, + .consys_ic_emi_mpu_set_region_protection = consys_emi_mpu_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .ic_bt_wifi_share_v33_spin_lock_init = bt_wifi_share_v33_spin_lock_init, + .consys_ic_clk_get_from_dts = consys_clk_get_from_dts, + .consys_ic_pmic_get_from_dts = consys_pmic_get_from_dts, + .consys_ic_read_irq_info_from_dts = consys_read_irq_info_from_dts, + .consys_ic_read_reg_from_dts = consys_read_reg_from_dts, + .consys_ic_read_cpupcr = consys_read_cpupcr, + .ic_force_trigger_assert_debug_pin = force_trigger_assert_debug_pin, + .consys_ic_co_clock_type = consys_co_clock_type, + .consys_ic_soc_get_emi_phy_add = consys_soc_get_emi_phy_add, + .consys_ic_set_if_pinmux = consys_set_if_pinmux, + .consys_ic_emi_coredump_remapping = consys_emi_coredump_remapping, + .consys_ic_reset_emi_coredump = consys_reset_emi_coredump, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +UINT32 gJtagCtrl; + +#if CONSYS_ENALBE_SET_JTAG +#define JTAG_ADDR1_BASE 0x10005000 +#define JTAG_ADDR2_BASE 0x11E80000 +#define JTAG_ADDR3_BASE 0x11D20000 +#define AP2CONN_JTAG_2WIRE_OFFSET 0xF00 +#endif + +INT32 mtk_wcn_consys_jtag_set_for_mcu(VOID) +{ +#if CONSYS_ENALBE_SET_JTAG + INT32 ret = 0; + UINT32 tmp = 0; + PVOID addr = 0; + PVOID remap_addr1 = 0; + PVOID remap_addr2 = 0; + PVOID remap_addr3 = 0; + + if (gJtagCtrl) { + + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + ret = -1; + goto error; + } + + remap_addr2 = ioremap(JTAG_ADDR2_BASE, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + ret = -1; + goto error; + } + + remap_addr3 = ioremap(JTAG_ADDR3_BASE, 0x100); + if (remap_addr3 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr3 fail!\n"); + ret = -1; + goto error; + } + + WMT_PLAT_PR_INFO("WCN jtag set for mcu start...\n"); + switch (gJtagCtrl) { + case 1: + /* 7-wire jtag pinmux setting*/ +#if 1 + /* PAD AUX Function Selection */ + addr = remap_addr1 + 0x320; + tmp = readl(addr); + tmp = tmp & 0x0000000f; + tmp = tmp | 0x33333330; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD Driving Selection */ + addr = remap_addr2 + 0xA0; + tmp = readl(addr); + tmp = tmp & 0xfff00fff; + tmp = tmp | 0x00077000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD PULL Selection */ + addr = remap_addr2 + 0x60; + tmp = readl(addr); + tmp = tmp & 0xfffe03ff; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr2 + 0x60; + tmp = readl(addr); + tmp = tmp & 0xfff80fff; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + +#else + /* backup */ + /* PAD AUX Function Selection */ + addr = remap_addr1 + 0x310; + tmp = readl(addr); + tmp = tmp & 0xfffff000; + tmp = tmp | 0x00000444; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr1 + 0x3C0; + tmp = readl(addr); + tmp = tmp & 0xf00ff00f; + tmp = tmp | 0x04400440; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD Driving Selection */ + addr = remap_addr3 + 0xA0; + tmp = readl(addr); + tmp = tmp & 0x0ffffff0; + tmp = tmp | 0x70000007; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr3 + 0xB0; + tmp = readl(addr); + tmp = tmp & 0xfff0f0ff; + tmp = tmp | 0x0007070f; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD PULL Selection */ + addr = remap_addr3 + 0x60; + tmp = readl(addr); + tmp = tmp & 0xf333fffe; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); +#endif + break; + case 2: + /* 2-wire jtag pinmux setting*/ +#if 0 + CONSYS_SET_BIT(conn_reg.topckgen_base + AP2CONN_JTAG_2WIRE_OFFSET, 1 << 8); + addr = remap_addr1 + 0x340; + tmp = readl(addr); + tmp = tmp & 0xfff88fff; + tmp = tmp | 0x00034000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); +#endif + break; + default: + WMT_PLAT_PR_INFO("unsupported options!\n"); + } + + } +#endif + +error: + + if (remap_addr1) + iounmap(remap_addr1); + if (remap_addr2) + iounmap(remap_addr2); + if (remap_addr3) + iounmap(remap_addr3); + + return ret; +} + +UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en) +{ + WMT_PLAT_PR_INFO("%s jtag set for MCU\n", en ? "enable" : "disable"); + gJtagCtrl = en; + return 0; +} + +static INT32 consys_clk_get_from_dts(struct platform_device *pdev) +{ + clk_scp_conn_main = devm_clk_get(&pdev->dev, "conn"); + if (IS_ERR(clk_scp_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_scp_conn_main clock.\n"); + return PTR_ERR(clk_scp_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_scp_conn_main=%p\n", clk_scp_conn_main); + + return 0; +} + +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev) +{ +#if CONSYS_PMIC_CTRL_ENABLE + reg_VCN18 = regulator_get(&pdev->dev, "vcn18"); + if (!reg_VCN18) + WMT_PLAT_PR_ERR("Regulator_get VCN_1V8 fail\n"); + reg_VCN28 = regulator_get(&pdev->dev, "vcn28"); + if (!reg_VCN28) + WMT_PLAT_PR_ERR("Regulator_get VCN_2V8 fail\n"); + reg_VCN33_BT = regulator_get(&pdev->dev, "vcn33_bt"); + if (!reg_VCN33_BT) + WMT_PLAT_PR_ERR("Regulator_get VCN33_BT fail\n"); + reg_VCN33_WIFI = regulator_get(&pdev->dev, "vcn33_wifi"); + if (!reg_VCN33_WIFI) + WMT_PLAT_PR_ERR("Regulator_get VCN33_WIFI fail\n"); +#endif + return 0; +} + +static INT32 consys_co_clock_type(VOID) +{ + return 0; +} + +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable) +{ + if (enable) + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, true); /*open XO_WCN*/ + else + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, false); /*close XO_WCN*/ + + return 0; +} + +static VOID consys_set_if_pinmux(MTK_WCN_BOOL enable) +{ + UINT8 *consys_if_pinmux_reg_base = NULL; + + /* Switch D die pinmux for connecting A die */ + consys_if_pinmux_reg_base = ioremap(CONSYS_IF_PINMUX_REG_BASE, 0x1000); + if (!consys_if_pinmux_reg_base) { + WMT_PLAT_PR_ERR("consys_if_pinmux_reg_base(%x) ioremap fail\n", CONSYS_IF_PINMUX_REG_BASE); + return; + } + + if (enable) { + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET) & + CONSYS_IF_PINMUX_01_MASK) | CONSYS_IF_PINMUX_01_VALUE); + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET) & + CONSYS_IF_PINMUX_02_MASK) | CONSYS_IF_PINMUX_02_VALUE); + } else { + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET, + CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET) & + CONSYS_IF_PINMUX_01_MASK); + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET, + CONSYS_REG_READ(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET) & + CONSYS_IF_PINMUX_02_MASK); + } + + if (consys_if_pinmux_reg_base) + iounmap(consys_if_pinmux_reg_base); +} + +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable) +{ + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE((conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET), + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) | + CONSYS_CPU_SW_RST_BIT | CONSYS_CPU_SW_RST_CTRL_KEY); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88 (key)" */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_CPU_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + } +} + +static VOID consys_hw_spm_clk_gating_enable(VOID) +{ + /*turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ +} + +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + INT32 iRet = -1; +#else + INT32 value = 0; +#endif + + if (enable) { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + iRet = clk_prepare_enable(clk_scp_conn_main); + if (iRet) + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_scp_conn_main) fail(%d)\n", iRet); + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_scp_conn_main) ok\n"); +#else + /*2.write conn_top1_pwr_on=1, power on conn_top1 0x1000632C [2] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_BIT); + /*2.write conn_top1_pwr_on_s=1, power on conn_top1 0x1000632C [3] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_S_BIT); + /*3.read conn_top1_pwr_on_ack =1, power on ack ready 0x10006180 [1] */ + value = CONSYS_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + while (value == 0) + value = CONSYS_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + /*3.read conn_top1_pwr_on_ack_s =1, power on ack ready 0x10006184 [1] */ + value = CONSYS_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + while (value == 0) + value = CONSYS_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + /*6.write conn_clk_dis=0, enable connsys clock 0x1000632C [4] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_CLK_CTRL_BIT); + /*7.wait 1us */ + udelay(1); + /*9.release connsys ISO, conn_top1_iso_en=0 0x1000632C [1] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_ISO_S_BIT); + /*10.release SW reset of connsys, conn_ap_sw_rst_b=1 0x1000632C[0] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_RST_BIT); + /*disable AXI BUS protect 100012a4 [13][14] */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) & + ~CONSYS_PROT_MASK); + /*read conn_top2_pwr_on_ack =1, power on ack ready 0x10006180 [30] */ + value = CONSYS_TOP2_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET); + while (value == 0) + value = CONSYS_TOP2_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET); + /*read conn_top2_pwr_on_ack_s =1, power on ack ready 0x10006180 [30] */ + value = CONSYS_TOP2_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET); + while (value == 0) + value = CONSYS_TOP2_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET); +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } else { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + clk_disable_unprepare(clk_scp_conn_main); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_scp_conn_main) calling\n"); +#else + /*disable AXI BUS protect 0x100012a0 [13][14] */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_TOPAXI_PROT_EN_OFFSET) | + CONSYS_PROT_MASK); + /*assert SW reset of connsys, conn_ap_sw_rst_b=0 0x1000632C [0] 1'b0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_RST_BIT); + /*release connsys ISO, conn_top1_iso_en=1 0x1000632C [1] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ISO_S_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x1000632C [4] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632C [3:2] 2'b00 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } + +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + return iRet; +#else + return 0; +#endif +} + +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable) +{ + return 0; +} + +static INT32 polling_consys_chipid(VOID) +{ + UINT32 retry = 10; + UINT32 consysHwChipId = 0; + + /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ + while (retry-- > 0) { + consysHwChipId = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CHIP_ID_OFFSET); + if (consysHwChipId == 0x0788) { + WMT_PLAT_PR_INFO("retry(%d)consys chipId(0x%08x)\n", retry, consysHwChipId); + break; + } + msleep(20); + } + + if ((retry == 0) || (consysHwChipId == 0)) { + WMT_PLAT_PR_ERR("Maybe has a consys power on issue,(0x%08x)\n", consysHwChipId); + WMT_PLAT_PR_INFO("reg dump:CONSYS_CPU_SW_RST_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_PWR_CONN_ACK_S_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET)); + WMT_PLAT_PR_INFO("reg dump:CONSYS_TOP1_PWR_CTRL_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET)); + } + + return 0; +} + +static VOID update_consys_rom_desel(VOID) +{ + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_ROM_DESEL_OFFSET, CONSYS_ROM_DESEL_MASK); + WMT_PLAT_PR_INFO("Update consys rom desel value(0x%x)\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_ROM_DESEL_OFFSET)); +} + +static VOID consys_hang_debug_info(VOID) +{ + SIZE_T addr_1; + SIZE_T addr_2; + SIZE_T addr_3; + + UINT32 rv1, wv1[2], rv2[2], rv3, wv3 = 0; + UINT32 i = 0; + + addr_1 = conn_reg.mcu_base + CONSYS_HANG_DBG_OFFSET_1; + addr_2 = conn_reg.mcu_base + CONSYS_HANG_DBG_OFFSET_2; + addr_3 = conn_reg.mcu_base + CONSYS_HANG_DBG_OFFSET_3; + rv1 = CONSYS_REG_READ(addr_1); + rv3 = CONSYS_REG_READ(addr_3); + WMT_PLAT_PR_INFO("addr1:%zx:0x%x/addr2:%zx/addr3:%zx:0x%x\n", + addr_1, rv1, addr_2, addr_3, rv3); + + wv1[0] = (rv1 & 0xFF0000FF) | (0x0201 << 8); + CONSYS_REG_WRITE(addr_1, wv1[0]); + rv2[0] = CONSYS_REG_READ(addr_2); + + wv1[1] = (rv1 & 0xFF0000FF) | (0x0403 << 8); + CONSYS_REG_WRITE(addr_1, wv1[1]); + rv2[1] = CONSYS_REG_READ(addr_2); + WMT_PLAT_PR_INFO("0x%x->addr1, addr2:0x%x/0x%x->addr1, addr2:0x%x\n", + wv1[0], rv2[0], wv1[1], rv2[1]); + + for (i = 0; i < 9; i++) { + wv3 = (rv3 & 0xFFFFFF0F) | (i << 4); + CONSYS_REG_WRITE(addr_3, wv3); + + wv1[0] = (rv1 & 0xFF0000FF) | (0x5251 << 8); + CONSYS_REG_WRITE(addr_1, wv1[0]); + rv2[0] = CONSYS_REG_READ(addr_2); + + wv1[1] = (rv1 & 0xFF0000FF) | (0x5453 << 8); + CONSYS_REG_WRITE(addr_1, wv1[1]); + rv2[1] = CONSYS_REG_READ(addr_2); + WMT_PLAT_PR_INFO("0x%x->addr3,0x%x->addr1,addr2:0x%x/0x%x->addr1,addr2:0x%x\n", + wv3, wv1[0], rv2[0], wv1[1], rv2[1]); + } + + WMT_PLAT_PR_INFO("apb0_dbg_prob\n"); + for (i = 0; i < 10; i++) { + wv3 = (rv3 & 0xFFFF0FFF) | (i << 12); + CONSYS_REG_WRITE(addr_3, wv3); + + wv1[0] = (rv1 & 0xFF0000FF) | (0x5655 << 8); + CONSYS_REG_WRITE(addr_1, wv1[0]); + rv2[0] = CONSYS_REG_READ(addr_2); + + wv1[1] = (rv1 & 0xFF0000FF) | (0x5857 << 8); + CONSYS_REG_WRITE(addr_1, wv1[1]); + rv2[1] = CONSYS_REG_READ(addr_2); + WMT_PLAT_PR_INFO("0x%x->addr3,0x%x->addr1,addr2:0x%x/0x%x->addr1,addr2:0x%x\n", + wv3, wv1[0], rv2[0], wv1[1], rv2[1]); + } + + WMT_PLAT_PR_INFO("apb1_dbg_prob\n"); + for (i = 0; i < 10; i++) { + wv3 = (rv3 & 0xFF0FFFFF) | (i << 20); + CONSYS_REG_WRITE(addr_3, wv3); + + wv1[0] = (rv1 & 0xFF0000FF) | (0x5A59 << 8); + CONSYS_REG_WRITE(addr_1, wv1[0]); + rv2[0] = CONSYS_REG_READ(addr_2); + + wv1[1] = (rv1 & 0xFF0000FF) | (0x5C5B << 8); + CONSYS_REG_WRITE(addr_1, wv1[1]); + rv2[1] = CONSYS_REG_READ(addr_2); + WMT_PLAT_PR_INFO("0x%x->addr3,0x%x->addr1,addr2:0x%x/0x%x->addr1,addr2:0x%x\n", + wv3, wv1[0], rv2[0], wv1[1], rv2[1]); + } +} + +static VOID consys_acr_reg_setting(VOID) +{ + /* + * if bypass at-speed MBIST (default is at-speed) 0x18070140[1:0] 2'b11 + */ + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET, + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_MCU_CFG_ACR_OFFSET) | + CONSYS_MCU_CFG_ACR_MBIST_BIT); +} + +static VOID consys_afe_reg_setting(VOID) +{ +#if CONSYS_AFE_REG_SETTING + UINT8 i = 0; + UINT8 *consys_afe_reg_base = NULL; + + /*15.default no need,update ANA_WBG(AFE) CR if needed, CONSYS_AFE_REG */ + consys_afe_reg_base = ioremap(CONSYS_AFE_REG_BASE, 0x100); + if (consys_afe_reg_base) { + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_RG_WBG_PLL_03_OFFSET, + CONSYS_AFE_RG_WBG_PLL_03_VALUE); + CONSYS_REG_WRITE(consys_afe_reg_base + CONSYS_AFE_RG_WBG_GPS_02_OFFSET, + CONSYS_AFE_RG_WBG_GPS_02_VALUE); + + WMT_PLAT_PR_DBG("Dump AFE register\n"); + for (i = 0; i < 64; i++) { + WMT_PLAT_PR_DBG("reg:0x%08x|val:0x%08x\n", + CONSYS_AFE_REG_BASE + 4*i, + CONSYS_REG_READ(consys_afe_reg_base + 4*i)); + } + iounmap(consys_afe_reg_base); + } else + WMT_PLAT_PR_ERR("AFE base(0x%x) ioremap fail!\n", CONSYS_AFE_REG_BASE); +#endif +} + +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*need PMIC driver provide new API protocol */ + /*1.AP power on VCN_1V8 LDO (with PMIC_WRAP API) VCN_1V8 */ + /*set vcn18 SW mode*/ + KERNEL_upmu_set_reg_value(MT6358_LDO_VCN18_OP_EN, 0x1); + + if (reg_VCN18) { + regulator_set_voltage(reg_VCN18, 1800000, 1800000); + if (regulator_enable(reg_VCN18)) + WMT_PLAT_PR_ERR("enable VCN18 fail\n"); + else + WMT_PLAT_PR_DBG("enable VCN18 ok\n"); + } + + /*set vcn33 SW mode*/ + KERNEL_upmu_set_reg_value(MT6358_LDO_VCN33_OP_EN, 0x1); + + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3500000, 3500000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } + + } else { + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); + + /*AP power off MT6351L VCN_1V8 LDO */ + if (reg_VCN18) { + if (regulator_disable(reg_VCN18)) + WMT_PLAT_PR_ERR("disable VCN_1V8 fail!\n"); + else + WMT_PLAT_PR_DBG("disable VCN_1V8 ok\n"); + } + } +#endif + return 0; +} + +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); + } else { + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN28_HW0_OP_CFG, 0); + } +#endif +} + +static INT32 consys_hw_vcn28_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*in co-clock mode,need to turn on vcn28 when fm on */ + if (reg_VCN28) { + regulator_set_voltage(reg_VCN28, 2800000, 2800000); + if (regulator_enable(reg_VCN28)) + WMT_PLAT_PR_ERR("WMT do VCN28 PMIC on fail!\n"); + } + WMT_PLAT_PR_INFO("turn on vcn28 for fm/gps usage in co-clock mode\n"); + } else { + /*in co-clock mode,need to turn off vcn28 when fm off */ + if (reg_VCN28) + regulator_disable(reg_VCN28); + WMT_PLAT_PR_INFO("turn off vcn28 for fm/gps usage in co-clock mode\n"); + } +#endif + return 0; +} + +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable) +{ +#if 0 +#if CONSYS_BT_WIFI_SHARE_V33 + /* spin_lock_irqsave(&gBtWifiV33.lock,gBtWifiV33.flags); */ + if (enable) { + if (gBtWifiV33.counter == 1) { + gBtWifiV33.counter++; + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else if (gBtWifiV33.counter == 2) { + WMT_PLAT_PR_DBG("V33 has been enabled,counter(%d)\n", gBtWifiV33.counter); + } else { +#if CONSYS_PMIC_CTRL_ENABLE + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + hwPowerOn(MT6351_POWER_LDO_VCN33_BT, VOL_3300 * 1000, "wcn_drv"); + mt6351_upmu_set_rg_vcn33_on_ctrl(1); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 on\n"); + gBtWifiV33.counter++; + } + + } else { + if (gBtWifiV33.counter == 1) { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + mt6351_upmu_set_rg_vcn33_on_ctrl(0); + hwPowerDown(MT6351_POWER_LDO_VCN33_BT, "wcn_drv"); +#endif + WMT_PLAT_PR_INFO("WMT do BT/WIFI v3.3 off\n"); + gBtWifiV33.counter--; + } else if (gBtWifiV33.counter == 2) { + gBtWifiV33.counter--; + WMT_PLAT_PR_DBG("V33 no need disabled,counter(%d)\n", gBtWifiV33.counter); + } else { + WMT_PLAT_PR_DBG("V33 has been disabled,counter(%d)\n", gBtWifiV33.counter); + } + + } + /* spin_unlock_irqrestore(&gBtWifiV33.lock,gBtWifiV33.flags); */ +#else + if (enable) { + /*do BT PMIC on,depenency PMIC API ready */ + /*switch BT PALDO control from SW mode to HW mode:0x416[5]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + /* VOL_DEFAULT, VOL_3300, VOL_3400, VOL_3500, VOL_3600 */ + if (reg_VCN33_BT) { + regulator_set_voltage(reg_VCN33_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } + + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC on\n"); + } else { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); + if (reg_VCN33_BT) + regulator_disable(reg_VCN33_BT); +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC off\n"); + } +#endif + +#endif + return 0; +} + +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable) +{ +#if 0 +#if CONSYS_BT_WIFI_SHARE_V33 + mtk_wcn_consys_hw_bt_paldo_ctrl(enable); +#else + if (enable) { + /*do WIFI PMIC on,depenency PMIC API ready */ + /*switch WIFI PALDO control from SW mode to HW mode:0x418[14]-->0x1 */ +#if CONSYS_PMIC_CTRL_ENABLE + if (reg_VCN33_WIFI) { + regulator_set_voltage(reg_VCN33_WIFI, 3300000, 3300000); + if (regulator_enable(reg_VCN33_WIFI)) + WMT_PLAT_PR_ERR("WMT do WIFI PMIC on fail!\n"); + } + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 1); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC on\n"); + } else { + /*do WIFI PMIC off */ + /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_EN, 0); + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_HW0_OP_CFG, 0); + if (reg_VCN33_WIFI) + regulator_disable(reg_VCN33_WIFI); +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC off\n"); + } + +#endif + +#endif + return 0; +} + +static INT32 consys_emi_mpu_set_region_protection(VOID) +{ +#ifdef CONFIG_MTK_EMI + struct emi_region_info_t region_info; + + /*set MPU for EMI share Memory */ + WMT_PLAT_PR_INFO("setting MPU for EMI share memory\n"); + + region_info.start = gConEmiPhyBase + SZ_1M / 2 - SZ_64K; + region_info.end = gConEmiPhyBase + gConEmiSize - 1; + region_info.region = 26; + SET_ACCESS_PERMISSION(region_info.apc, LOCK, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + NO_PROTECTION, FORBIDDEN, NO_PROTECTION); + emi_mpu_set_protection(®ion_info); +#endif + return 0; +} + +static UINT32 consys_emi_set_remapping_reg(VOID) +{ + UINT32 addrPhy = 0; + + /*consys to ap emi remapping register:10000380, cal remapping address */ + addrPhy = (gConEmiPhyBase >> 21) & 0x1FFF; + + /*enable consys to ap emi remapping bit13 */ + addrPhy = addrPhy | 0x2000; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); + + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); + + return 0; +} + +static INT32 bt_wifi_share_v33_spin_lock_init(VOID) +{ +#if CONSYS_BT_WIFI_SHARE_V33 + gBtWifiV33.counter = 0; + spin_lock_init(&gBtWifiV33.lock); +#endif + return 0; +} + +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, PUINT32 irq_flag) +{ + struct device_node *node; + UINT32 irq_info[3] = { 0, 0, 0 }; + + INT32 iret = -1; + + node = pdev->dev.of_node; + if (node) { + *irq_num = irq_of_parse_and_map(node, 0); + /* get the interrupt line behaviour */ + if (of_property_read_u32_array(node, "interrupts", irq_info, ARRAY_SIZE(irq_info))) { + WMT_PLAT_PR_ERR("get irq flags from DTS fail!!\n"); + return iret; + } + *irq_flag = irq_info[2]; + WMT_PLAT_PR_INFO("get irq id(%d) and irq trigger flag(%d) from DT\n", *irq_num, + *irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iret; + } + + return 0; +} + +static INT32 consys_read_reg_from_dts(struct platform_device *pdev) +{ + INT32 iRet = -1; + struct device_node *node = NULL; + + node = pdev->dev.of_node; + if (node) { + /* registers base address */ + conn_reg.mcu_base = (SIZE_T) of_iomap(node, 0); + WMT_PLAT_PR_DBG("Get mcu register base(0x%zx)\n", conn_reg.mcu_base); + conn_reg.ap_rgu_base = (SIZE_T) of_iomap(node, 1); + WMT_PLAT_PR_DBG("Get ap_rgu register base(0x%zx)\n", conn_reg.ap_rgu_base); + conn_reg.topckgen_base = (SIZE_T) of_iomap(node, 2); + WMT_PLAT_PR_DBG("Get topckgen register base(0x%zx)\n", conn_reg.topckgen_base); + conn_reg.spm_base = (SIZE_T) of_iomap(node, 3); + WMT_PLAT_PR_DBG("Get spm register base(0x%zx)\n", conn_reg.spm_base); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iRet; + } + + return 0; +} + +static VOID force_trigger_assert_debug_pin(VOID) +{ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + usleep_range(64, 96); + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); +} + +static UINT32 consys_read_cpupcr(VOID) +{ + return CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CPUPCR_OFFSET); +} + +static UINT32 consys_soc_chipid_get(VOID) +{ + return PLATFORM_SOC_CHIP; +} + +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID) +{ + return &mtk_wcn_emi_addr_info; +} + +P_WMT_CONSYS_IC_OPS mtk_wcn_get_consys_ic_ops(VOID) +{ + return &consys_ic_ops; +} + +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable) +{ + if (enable) { + *addr = ioremap(gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET, CONSYS_EMI_MEM_SIZE); + if (*addr) { + WMT_PLAT_PR_INFO("COREDUMP EMI mapping OK virtual(0x%p) physical(0x%x)\n", + *addr, (UINT32) gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET); + memset_io(*addr, 0, CONSYS_EMI_MEM_SIZE); + } else { + WMT_PLAT_PR_ERR("EMI mapping fail\n"); + return -1; + } + } else { + if (*addr) { + iounmap(*addr); + *addr = NULL; + } + } + return 0; +} + +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr) +{ + if (!addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + WMT_PLAT_PR_INFO("Reset EMI(0xF0080000 ~ 0xF0080400) and (0xF0088400 ~ 0xF0090400)\n"); + /* reset 0xF0080000 ~ 0xF0080400 (1K) */ + memset_io(addr, 0, 0x400); + /* reset 0xF0088400 ~ 0xF0090400 (32K) */ + memset_io(addr + CONSYS_EMI_PAGED_DUMP_OFFSET, 0, 0x8000); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6779.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6779.c new file mode 100644 index 00000000000000..3346490ade20e7 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6779.c @@ -0,0 +1,1762 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <connectivity_build_in_adapter.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/memblock.h> +#include <linux/platform_device.h> +#include "connsys_debug_utility.h" +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +#include "fw_log_wmt.h" +#endif +#include "osal_typedef.h" +#include "mt6779.h" +#include "mtk_wcn_consys_hw.h" +#include "wmt_ic.h" +#include "wmt_lib.h" +#include "wmt_step.h" +#include "stp_dbg.h" + +#ifdef CONFIG_MTK_EMI +#include <mt_emi_api.h> +#endif + +#if CONSYS_PMIC_CTRL_ENABLE +#include <mtk_pmic_api_buck.h> +#include <upmu_common.h> +#include <linux/regulator/consumer.h> +#endif + +#ifdef CONFIG_MTK_HIBERNATION +#include <mtk_hibernate_dpm.h> +#endif + +#include <linux/of_reserved_mem.h> + +#include <mtk_clkbuf_ctl.h> + +/* Direct path */ +#include <mtk_ccci_common.h> +#include <linux/gpio.h> +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable); +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable); +static VOID consys_hw_spm_clk_gating_enable(VOID); +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable); +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable); +static INT32 polling_consys_chipid(VOID); +static VOID consys_acr_reg_setting(VOID); +static VOID consys_afe_reg_setting(VOID); +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable); +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable); +static INT32 consys_hw_vcn28_ctrl(UINT32 enable); +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable); +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable); +static UINT32 consys_soc_chipid_get(VOID); +static INT32 consys_emi_mpu_set_region_protection(VOID); +static UINT32 consys_emi_set_remapping_reg(VOID); +static INT32 bt_wifi_share_v33_spin_lock_init(VOID); +static INT32 consys_clk_get_from_dts(struct platform_device *pdev); +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev); +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, + PINT32 irq_num, PUINT32 irq_flag); +static INT32 consys_read_reg_from_dts(struct platform_device *pdev); +static UINT32 consys_read_cpupcr(VOID); +static VOID force_trigger_assert_debug_pin(VOID); +static INT32 consys_co_clock_type(VOID); +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID); +static VOID consys_set_if_pinmux(MTK_WCN_BOOL enable); +static INT32 consys_dl_rom_patch(UINT32 ip_ver, UINT32 fw_ver); +static VOID consys_set_dl_rom_patch_flag(INT32 flag); +static INT32 consys_dedicated_log_path_init(struct platform_device *pdev); +static VOID consys_dedicated_log_path_deinit(VOID); +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable); +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr); +static INT32 consys_check_reg_readable(VOID); +static VOID consys_ic_clock_fail_dump(VOID); +static INT32 consys_is_connsys_reg(UINT32 addr); +static PUINT32 consys_resume_dump_info(VOID); +static VOID consys_set_mcif_emi_mpu_protection(MTK_WCN_BOOL enable); +/* + * If 1: this platform supports calibration backup/restore. + * otherwise: 0 + */ +static INT32 consys_calibration_backup_restore_support(VOID); +static INT32 consys_is_ant_swap_enable_by_hwid(INT32 pin_num); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +/* CCF part */ +struct clk *clk_scp_conn_main; /*ctrl conn_power_on/off */ +struct clk *clk_infracfg_ao_ccif4_ap_cg; /* For direct path */ + +/* PMIC part */ +#if CONSYS_PMIC_CTRL_ENABLE +struct regulator *reg_VCN18; +#if CONSYS_PMIC_CTRL_6635 +struct regulator *reg_VCN13; +#endif +struct regulator *reg_VCN33_1_BT; +struct regulator *reg_VCN33_1_WIFI; +struct regulator *reg_VCN33_2_WIFI; +#endif + +EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { + .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, + .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, + .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, + .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, + .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, + .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, + .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, + .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, + .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, + .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, + .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, + .emi_apmem_ctrl_chip_page_dump_num = EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM, + .emi_apmem_ctrl_assert_flag = EXP_APMEM_CTRL_ASSERT_FLAG, + .emi_apmem_ctrl_chip_check_sleep = EXP_APMEM_CTRL_CHIP_CHECK_SLEEP, +}; + +CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { + .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, + .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, + .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, + .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, + .emi_remap_offset = CONSYS_EMI_MAPPING_OFFSET, + .p_ecso = &mtk_wcn_emi_state_off, + .pda_dl_patch_flag = 1, + .emi_met_size = (32*KBYTE), + .emi_met_data_offset = CONSYS_EMI_MET_DATA_OFFSET, + .emi_core_dump_offset = CONSYS_EMI_COREDUMP_OFFSET, +}; + +WMT_CONSYS_IC_OPS consys_ic_ops = { + .consys_ic_clock_buffer_ctrl = consys_clock_buffer_ctrl, + .consys_ic_hw_reset_bit_set = consys_hw_reset_bit_set, + .consys_ic_hw_spm_clk_gating_enable = consys_hw_spm_clk_gating_enable, + .consys_ic_hw_power_ctrl = consys_hw_power_ctrl, + .consys_ic_ahb_clock_ctrl = consys_ahb_clock_ctrl, + .polling_consys_ic_chipid = polling_consys_chipid, + .consys_ic_acr_reg_setting = consys_acr_reg_setting, + .consys_ic_afe_reg_setting = consys_afe_reg_setting, + .consys_ic_hw_vcn18_ctrl = consys_hw_vcn18_ctrl, + .consys_ic_vcn28_hw_mode_ctrl = consys_vcn28_hw_mode_ctrl, + .consys_ic_hw_vcn28_ctrl = consys_hw_vcn28_ctrl, + .consys_ic_hw_wifi_vcn33_ctrl = consys_hw_wifi_vcn33_ctrl, + .consys_ic_hw_bt_vcn33_ctrl = consys_hw_bt_vcn33_ctrl, + .consys_ic_soc_chipid_get = consys_soc_chipid_get, + .consys_ic_emi_mpu_set_region_protection = consys_emi_mpu_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .ic_bt_wifi_share_v33_spin_lock_init = bt_wifi_share_v33_spin_lock_init, + .consys_ic_clk_get_from_dts = consys_clk_get_from_dts, + .consys_ic_pmic_get_from_dts = consys_pmic_get_from_dts, + .consys_ic_read_irq_info_from_dts = consys_read_irq_info_from_dts, + .consys_ic_read_reg_from_dts = consys_read_reg_from_dts, + .consys_ic_read_cpupcr = consys_read_cpupcr, + .ic_force_trigger_assert_debug_pin = force_trigger_assert_debug_pin, + .consys_ic_co_clock_type = consys_co_clock_type, + .consys_ic_soc_get_emi_phy_add = consys_soc_get_emi_phy_add, + .consys_ic_set_if_pinmux = consys_set_if_pinmux, + .consys_ic_set_dl_rom_patch_flag = consys_set_dl_rom_patch_flag, + .consys_ic_dedicated_log_path_init = consys_dedicated_log_path_init, + .consys_ic_dedicated_log_path_deinit = consys_dedicated_log_path_deinit, + .consys_ic_emi_coredump_remapping = consys_emi_coredump_remapping, + .consys_ic_reset_emi_coredump = consys_reset_emi_coredump, + .consys_ic_check_reg_readable = consys_check_reg_readable, + .consys_ic_clock_fail_dump = consys_ic_clock_fail_dump, + .consys_ic_is_connsys_reg = consys_is_connsys_reg, + .consys_ic_resume_dump_info = consys_resume_dump_info, + .consys_ic_set_mcif_emi_mpu_protection = consys_set_mcif_emi_mpu_protection, + .consys_ic_calibration_backup_restore = consys_calibration_backup_restore_support, + .consys_ic_is_ant_swap_enable_by_hwid = consys_is_ant_swap_enable_by_hwid, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 rom_patch_dl_flag = 1; +UINT32 gJtagCtrl; +UINT32 g_connsys_lp_dump_info[2]; + +#if CONSYS_ENALBE_SET_JTAG +#define JTAG_ADDR1_BASE 0x10005000 +#define JTAG_ADDR2_BASE 0x11E80000 +#define JTAG_ADDR3_BASE 0x11D20000 +#define AP2CONN_JTAG_2WIRE_OFFSET 0xF00 +#endif + +INT32 mtk_wcn_consys_jtag_set_for_mcu(VOID) +{ +#if 0 +#if CONSYS_ENALBE_SET_JTAG + INT32 ret = 0; + UINT32 tmp = 0; + PVOID addr = 0; + PVOID remap_addr1 = 0; + PVOID remap_addr2 = 0; + PVOID remap_addr3 = 0; + + if (gJtagCtrl) { + + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + ret = -1; + goto error; + } + + remap_addr2 = ioremap(JTAG_ADDR2_BASE, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + ret = -1; + goto error; + } + + remap_addr3 = ioremap(JTAG_ADDR3_BASE, 0x100); + if (remap_addr3 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr3 fail!\n"); + ret = -1; + goto error; + } + + WMT_PLAT_PR_INFO("WCN jtag set for mcu start...\n"); + switch (gJtagCtrl) { + case 1: + /* 7-wire jtag pinmux setting*/ +#if 1 + /* PAD AUX Function Selection */ + addr = remap_addr1 + 0x320; + tmp = readl(addr); + tmp = tmp & 0x0000000f; + tmp = tmp | 0x33333330; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD Driving Selection */ + addr = remap_addr2 + 0xA0; + tmp = readl(addr); + tmp = tmp & 0xfff00fff; + tmp = tmp | 0x00077000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD PULL Selection */ + addr = remap_addr2 + 0x60; + tmp = readl(addr); + tmp = tmp & 0xfffe03ff; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr2 + 0x60; + tmp = readl(addr); + tmp = tmp & 0xfff80fff; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + +#else + /* backup */ + /* PAD AUX Function Selection */ + addr = remap_addr1 + 0x310; + tmp = readl(addr); + tmp = tmp & 0xfffff000; + tmp = tmp | 0x00000444; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr1 + 0x3C0; + tmp = readl(addr); + tmp = tmp & 0xf00ff00f; + tmp = tmp | 0x04400440; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD Driving Selection */ + addr = remap_addr3 + 0xA0; + tmp = readl(addr); + tmp = tmp & 0x0ffffff0; + tmp = tmp | 0x70000007; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr3 + 0xB0; + tmp = readl(addr); + tmp = tmp & 0xfff0f0ff; + tmp = tmp | 0x0007070f; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD PULL Selection */ + addr = remap_addr3 + 0x60; + tmp = readl(addr); + tmp = tmp & 0xf333fffe; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); +#endif + break; + case 2: + /* 2-wire jtag pinmux setting*/ +#if 0 + CONSYS_SET_BIT(conn_reg.topckgen_base + AP2CONN_JTAG_2WIRE_OFFSET, 1 << 8); + addr = remap_addr1 + 0x340; + tmp = readl(addr); + tmp = tmp & 0xfff88fff; + tmp = tmp | 0x00034000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); +#endif + break; + default: + WMT_PLAT_PR_INFO("unsupported options!\n"); + } + + } +#endif + +error: + + if (remap_addr1) + iounmap(remap_addr1); + if (remap_addr2) + iounmap(remap_addr2); + if (remap_addr3) + iounmap(remap_addr3); + + return ret; +#else + WMT_PLAT_PR_INFO("No support switch to JTAG!\n"); + + return 0; +#endif +} + +UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en) +{ + WMT_PLAT_PR_INFO("%s jtag set for MCU\n", en ? "enable" : "disable"); + gJtagCtrl = en; + + return 0; +} + +static INT32 consys_clk_get_from_dts(struct platform_device *pdev) +{ + clk_scp_conn_main = devm_clk_get(&pdev->dev, "conn"); + if (IS_ERR(clk_scp_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_scp_conn_main clock.\n"); + return PTR_ERR(clk_scp_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_scp_conn_main=%p\n", clk_scp_conn_main); + + clk_infracfg_ao_ccif4_ap_cg = devm_clk_get(&pdev->dev, "ccif"); + if (IS_ERR(clk_infracfg_ao_ccif4_ap_cg)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_infracfg_ao_ccif4_ap_cg clock.\n"); + return PTR_ERR(clk_infracfg_ao_ccif4_ap_cg); + } + WMT_PLAT_PR_DBG("[CCF]clk_infracfg_ao_ccif4_ap_cg=%p\n", clk_infracfg_ao_ccif4_ap_cg); + + return 0; +} + +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev) +{ +#if CONSYS_PMIC_CTRL_ENABLE + reg_VCN18 = regulator_get(&pdev->dev, "vcn18"); + if (!reg_VCN18) + WMT_PLAT_PR_ERR("Regulator_get VCN_1V8 fail\n"); +#if CONSYS_PMIC_CTRL_6635 + reg_VCN13 = regulator_get(&pdev->dev, "vcn13"); + if (!reg_VCN13) + WMT_PLAT_PR_ERR("Regulator_get VCN_1V3 fail\n"); +#endif + reg_VCN33_1_BT = regulator_get(&pdev->dev, "vcn33_1_bt"); + if (!reg_VCN33_1_BT) + WMT_PLAT_PR_ERR("Regulator_get VCN33_1_BT fail\n"); + reg_VCN33_1_WIFI = regulator_get(&pdev->dev, "vcn33_1_wifi"); + if (!reg_VCN33_1_WIFI) + WMT_PLAT_PR_ERR("Regulator_get VCN33_1_WIFI fail\n"); + reg_VCN33_2_WIFI = regulator_get(&pdev->dev, "vcn33_2_wifi"); + if (!reg_VCN33_2_WIFI) + WMT_PLAT_PR_ERR("Regulator_get VCN33_2_WIFI fail\n"); +#endif + + return 0; +} + +static INT32 consys_co_clock_type(VOID) +{ + return 0; +} + +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable) +{ + if (enable) + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, true); /*open XO_WCN*/ + else + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, false); /*close XO_WCN*/ + + return 0; +} + +static VOID consys_set_if_pinmux(MTK_WCN_BOOL enable) +{ + UINT8 *consys_if_pinmux_reg_base = NULL; + UINT8 *consys_if_pinmux_driving_base = NULL; + + /* Switch D die pinmux for connecting A die */ + consys_if_pinmux_reg_base = ioremap(CONSYS_IF_PINMUX_REG_BASE, 0x1000); + if (!consys_if_pinmux_reg_base) { + WMT_PLAT_PR_ERR("consys_if_pinmux_reg_base(%x) ioremap fail\n", + CONSYS_IF_PINMUX_REG_BASE); + return; + } + + consys_if_pinmux_driving_base = ioremap(CONSYS_IF_PINMUX_DRIVING_BASE, 0x100); + if (!consys_if_pinmux_driving_base) { + WMT_PLAT_PR_ERR("consys_if_pinmux_driving_base(%x) ioremap fail\n", + CONSYS_IF_PINMUX_DRIVING_BASE); + if (consys_if_pinmux_reg_base) + iounmap(consys_if_pinmux_reg_base); + return; + } + + if (enable) { + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_reg_base + + CONSYS_IF_PINMUX_01_OFFSET) & + CONSYS_IF_PINMUX_01_MASK) | CONSYS_IF_PINMUX_01_VALUE); + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_reg_base + + CONSYS_IF_PINMUX_02_OFFSET) & + CONSYS_IF_PINMUX_02_MASK) | CONSYS_IF_PINMUX_02_VALUE); + /* set pinmux driving to 2mA */ + CONSYS_REG_WRITE(consys_if_pinmux_driving_base + CONSYS_IF_PINMUX_DRIVING_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_driving_base + + CONSYS_IF_PINMUX_DRIVING_OFFSET) & + CONSYS_IF_PINMUX_DRIVING_MASK) | CONSYS_IF_PINMUX_DRIVING_VALUE); + } else { + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET, + CONSYS_REG_READ(consys_if_pinmux_reg_base + + CONSYS_IF_PINMUX_01_OFFSET) & CONSYS_IF_PINMUX_01_MASK); + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET, + CONSYS_REG_READ(consys_if_pinmux_reg_base + + CONSYS_IF_PINMUX_02_OFFSET) & CONSYS_IF_PINMUX_02_MASK); + } + + if (consys_if_pinmux_reg_base) + iounmap(consys_if_pinmux_reg_base); + if (consys_if_pinmux_driving_base) + iounmap(consys_if_pinmux_driving_base); +} + +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable) +{ + UINT32 consys_ver_id = 0; + UINT32 cnt = 0; +#if CONSYS_PMIC_CTRL_6635 + UINT8 *consys_reg_base = NULL; +#endif + + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE((conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET), + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) | + CONSYS_CPU_SW_RST_BIT | CONSYS_CPU_SW_RST_CTRL_KEY); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88 (key)" */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_CPU_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + /* check CONNSYS power-on completion + * (polling "0x8000_0600[31:0]" == 0x1D1E and each polling interval is "1ms") + * (apply this for guarantee that CONNSYS CPU goes to "cos_idle_loop") + */ + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + 0x600); + while (consys_ver_id != 0x1D1E) { + if (cnt > 10) + break; + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + 0x600); + WMT_PLAT_PR_INFO("0x18002600(0x%x)\n", consys_ver_id); + WMT_PLAT_PR_INFO("0x1800216c(0x%x)\n", + CONSYS_REG_READ(conn_reg.mcu_base + 0x16c)); + WMT_PLAT_PR_INFO("0x18007104(0x%x)\n", + CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base + + CONSYS_CPUPCR_OFFSET)); + msleep(20); + cnt++; + } + +#if CONSYS_PMIC_CTRL_6635 + /* if(MT6635) CONN_WF_CTRL2 swtich to CONN mode */ + consys_reg_base = ioremap(CONSYS_IF_PINMUX_REG_BASE, 0x1000); + if (!consys_reg_base) { + WMT_PLAT_PR_ERR("consys_if_pinmux_reg_base(%x) ioremap fail\n", + CONSYS_IF_PINMUX_REG_BASE); + return; + } + CONSYS_REG_WRITE(consys_reg_base + CONSYS_WF_CTRL2_03_OFFSET, + (CONSYS_REG_READ(consys_reg_base + CONSYS_WF_CTRL2_03_OFFSET) & + CONSYS_WF_CTRL2_03_MASK) | CONSYS_WF_CTRL2_CONN_MODE); + if (consys_reg_base) + iounmap(consys_reg_base); + else + WMT_PLAT_PR_ERR("consys_if_pinmux_reg_base(0x%x) ioremap fail!\n", + CONSYS_IF_PINMUX_REG_BASE); +#endif + } +} + +static VOID consys_hw_spm_clk_gating_enable(VOID) +{ +} + +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + INT32 iRet = 0; + UINT8 *check_coredump_reg = NULL; + UINT8 *check_sleep_reg = NULL; + UINT32 check_sleep = 0; + UINT32 retry = 100; + P_CONSYS_EMI_ADDR_INFO p_ecsi; +#else + INT32 value = 0; + INT32 i = 0; +#endif + + if (enable) { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + iRet = clk_prepare_enable(clk_infracfg_ao_ccif4_ap_cg); + if (iRet) { + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_infracfg_ao_ccif4_ap_cg) fail(%d)\n", iRet); + return iRet; + } + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_infracfg_ao_ccif4_ap_cg) ok\n"); + + iRet = clk_prepare_enable(clk_scp_conn_main); + if (iRet) { + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_scp_conn_main) fail(%d)\n", iRet); + return iRet; + } + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_scp_conn_main) ok\n"); + + if (conn_reg.infra_ao_pericfg_base != 0) { + WMT_PLAT_PR_DBG("CON_STA_REG = %x\n", + CONSYS_REG_READ( + conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG)); + + /* Set CON_PWR_ON bit (CON_STA_REG[0]) */ + CONSYS_REG_WRITE_RANGE((conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG), + 1, 1, 0); + + WMT_PLAT_PR_DBG("CON_STA_REG = %x\n", + CONSYS_REG_READ( + conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG)); + } +#else + /* turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE((conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET), + (CONSYS_REG_READ(conn_reg.spm_base + + CONSYS_PWRON_CONFG_EN_OFFSET) & + 0x0000FFFF) | CONSYS_PWRON_CONFG_EN_VALUE); + + /*write assert "conn_top_on" primary part power on, + *set "connsys_on_domain_pwr_on"=1 + */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_BIT); + /*read check "conn_top_on" primary part power status, + *check "connsys_on_domain_pwr_ack"=1 + */ + value = CONSYS_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + while (value == 0) + value = CONSYS_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + /*write assert "conn_top_on" secondary part power on, + *set "connsys_on_domain_pwr_on_s"=1 + */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_S_BIT); + /*read check "conn_top_on" secondary part power status, + *check "connsys_on_domain_pwr_ack_s"=1 + */ + value = CONSYS_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + while (value == 0) + value = CONSYS_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + /*write turn on AP-to-CONNSYS bus clock, set "conn_clk_dis"=0 (apply this for bus + *clock toggling) + */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_CLK_CTRL_BIT); + /*wait 1us*/ + udelay(1); + /*de-assert "conn_top_on" isolation, set "connsys_iso_en"=0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_ISO_S_BIT); + + /*de-assert CONNSYS S/W reset (TOP RGU CR), set "ap_sw_rst_b"=1 */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + + /*de-assert CONNSYS S/W reset (SPM CR), set "ap_sw_rst_b"=1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + CONSYS_SPM_PWR_RST_BIT); +#if 0 + /*read check "conn_top_off" primary part power status, check + *"connsys_off_domain_pwr_ack"=1 + */ + value = CONSYS_TOP2_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + while (value == 0) + value = CONSYS_TOP2_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + /*read check "conn_top_off" secondary part power status, check + *"connsys_off_domain_pwr_ack_s"=1 + */ + value = CONSYS_TOP2_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + while (value == 0) + value = CONSYS_TOP2_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); +#endif + /*wait 0.5ms*/ + udelay(500); + /*Turn off AHB RX bus sleep protect (AP2CONN AHB Bus protect) + *(apply this for INFRA AHB bus accessing when CONNSYS had been turned on) + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHB_RX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHB_RX_PROT_EN_OFFSET) & ~CONSYS_AHB_RX_PROT_MASK); + value = ~CONSYS_AHB_RX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHB_RX_PROT_STA_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_AP2CONN_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHB_RX_PROT_STA_OFFSET); + i++; + } + + /*Turn off AXI Rx bus sleep protect (CONN2AP AXI Rx Bus protect) + *(disable sleep protection when CONNSYS had been turned on) + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AXI_RX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AXI_RX_PROT_EN_OFFSET) & ~CONSYS_AXI_RX_PROT_MASK); + value = ~CONSYS_AXI_RX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_RX_PROT_STA_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_AXI_RX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AXI_RX_PROT_STA_OFFSET); + i++; + } + + /*Turn off AXI TX bus sleep protect (CONN2AP AXI Tx Bus protect) + *(disable sleep protection when CONNSYS had been turned on) + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AXI_RX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AXI_RX_PROT_EN_OFFSET) & ~CONSYS_AXI_TX_PROT_MASK); + value = ~CONSYS_AXI_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_RX_PROT_STA_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_AXI_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AXI_RX_PROT_STA_OFFSET); + i++; + } + + /*Turn off AHB TX bus sleep protect (AP2CONN AHB Bus protect) + *(apply this for INFRA AHB bus accessing when CONNSYS had been turned on) + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AXI_RX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AXI_RX_PROT_EN_OFFSET) & ~CONSYS_AHB_TX_PROT_MASK); + value = ~CONSYS_AHB_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_RX_PROT_STA_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_AHB_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AXI_RX_PROT_STA_OFFSET); + i++; + } +#if 0 + /*SPM apsrc/ddr_en hardware mask disable & wait cycle setting*/ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_SPM_APSRC_OFFSET, + CONSYS_SPM_APSRC_VALUE); + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_SPM_DDR_EN_OFFSET, + CONSYS_SPM_DDR_EN_VALUE); +#endif + /*wait 5ms*/ + mdelay(5); +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } else { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + p_ecsi = wmt_plat_get_emi_phy_add(); + if (!p_ecsi) + return iRet; + check_sleep_reg = wmt_plat_get_emi_virt_add + (p_ecsi->p_ecso->emi_apmem_ctrl_chip_check_sleep); + check_coredump_reg = wmt_plat_get_emi_virt_add + (p_ecsi->p_ecso->emi_apmem_ctrl_state); + + /* Handshake flow: Notify MCU goto sleep before connsys power off */ + if ((check_sleep_reg) && (check_coredump_reg)) { + /* check if chip reset flow */ + if ((CONSYS_REG_READ(check_coredump_reg) == 0) + && (mtk_consys_chip_reset_status() != 1)) { + /* 1. write pattern EMI CR: F006804C = 0x5aa5 */ + CONSYS_REG_WRITE(check_sleep_reg, MCU_GOTO_SLEEP); + + /* 2. trigger EINT */ + mtk_wcn_force_trigger_assert_debug_pin(); + + /* 3. Polling EMI CR: F006804C == 0x7788 */ + while (retry-- > 0) { + check_sleep = CONSYS_REG_READ(check_sleep_reg); + if (check_sleep == MCU_SLEEP_DONE) { + WMT_PLAT_PR_INFO("consys is ready to sleep\n"); + break; + } + WMT_STEP_DO_ACTIONS_FUNC + (STEP_TRIGGER_POINT_POWER_OFF_HANDSHAKE); + WMT_PLAT_PR_INFO("check_sleep_reg=(0x%x)\n", check_sleep); + msleep(20); + } + /* 4. Clear EMI CR: F006804C = 0 */ + CONSYS_REG_WRITE(check_sleep_reg, 0x0); + } + } + + if (conn_reg.infra_ao_pericfg_base != 0) { + WMT_PLAT_PR_DBG("CON_STA_REG = %x\n", + CONSYS_REG_READ( + conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG)); + + /* Clean CON_STA_REG + * when power off or reset connsys + */ + CONSYS_REG_WRITE((conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG), 0); + + WMT_PLAT_PR_DBG("CON_STA_REG = %x\n", + CONSYS_REG_READ( + conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG)); + } + + clk_disable_unprepare(clk_scp_conn_main); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_scp_conn_main) calling\n"); + + /* Clean CCIF4 ACK status */ + /* Wait 100us to make sure all ongoing tx interrupt could be + * reset. + * According to profiling result, the time between read + * register and send tx interrupt is less than 20 us. + */ + udelay(100); + CONSYS_REG_WRITE((conn_reg.ap_pccif4_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PCCIF_ACK_OFFSET), + 0xFF); + WMT_PLAT_PR_DBG("AP_PCCIF_ACK = %x\n", + CONSYS_REG_READ( + conn_reg.ap_pccif4_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PCCIF_ACK_OFFSET)); + + clk_disable_unprepare(clk_infracfg_ao_ccif4_ap_cg); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_infracfg_ao_ccif4_ap_cg) calling\n"); + +#else + /* Turn on AHB bus sleep protect (AP2CONN AHB Bus protect) + * (apply this for INFRA AXI bus protection to prevent bus hang + * when CONNSYS had been turned off) + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHBAXI_PROT_EN_OFFSET) & + CONSYS_AP2CONN_PROT_MASK); + value = CONSYS_AP2CONN_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i = 0; + while (value == CONSYS_AP2CONN_PROT_MASK || i > 10) { + value = CONSYS_AP2CONN_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHBAXI_PROT_STA_OFFSET); + i++; + } + /* Turn on AXI Tx bus sleep protect (CONN2AP AXI Tx Bus protect) + * (apply this for INFRA AXI bus protection to prevent bus hang + * when CONNSYS had been turned off) + * Note : Should turn on AXI Tx sleep protection first. + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHBAXI_PROT_EN_OFFSET) & + CONSYS_TX_PROT_MASK); + value = CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i = 0; + while (value == CONSYS_TX_PROT_MASK || i > 10) { + value = CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHBAXI_PROT_STA_OFFSET); + i++; + } + /* Turn on AXI Rx bus sleep protect (CONN2AP AXI RX Bus protect) + * (apply this for INFRA AXI bus protection to prevent bus hang + * when CONNSYS had been turned off) + * Note : Should turn on AXI Rx sleep protection + * after AXI Tx sleep protection has been turn on. + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHBAXI_PROT_EN_OFFSET) & + CONSYS_RX_PROT_MASK); + value = CONSYS_RX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i = 0; + while (value == CONSYS_RX_PROT_MASK || i > 10) { + value = CONSYS_RX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHBAXI_PROT_STA_OFFSET); + i++; + } + + /*assert "conn_top_on" isolation, set "connsys_iso_en"=1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ISO_S_BIT); + /*assert CONNSYS S/W reset (TOP RGU CR), set "ap_sw_rst_b"=0 */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + CONSYS_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + /*assert CONNSYS S/W reset (SPM CR), set "ap_sw_rst_b"=0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x1000632C [4] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632C [3:2] 2'b00 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } + +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + return iRet; +#else + return 0; +#endif +} + +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable) +{ + return 0; +} + +static INT32 polling_consys_chipid(VOID) +{ + INT32 retry = 10; + UINT32 consys_ver_id = 0; + UINT32 consys_hw_ver = 0; + UINT32 consys_fw_ver = 0; + UINT8 *consys_reg_base = NULL; + UINT32 value = 0; + + /*12.poll CONNSYS CHIP ID until chipid is returned 0x18070008 */ + while (retry-- > 0) { + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_top_misc_off_base + + CONSYS_IP_VER_OFFSET); + if (consys_ver_id == CONSYS_IP_VER_ID) { + WMT_PLAT_PR_INFO("retry(%d)consys version id(0x%08x)\n", + retry, consys_ver_id); + consys_hw_ver = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys HW version id(0x%x)\n", consys_hw_ver & 0xFFFF); + consys_fw_ver = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_FW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys FW version id(0x%x)\n", consys_fw_ver & 0xFFFF); + + if (consys_dl_rom_patch(consys_ver_id, consys_fw_ver) == 0) + break; + } + WMT_PLAT_PR_ERR("Read CONSYS version id(0x%08x)", consys_ver_id); + msleep(20); + } + + if (retry <= 0) + return -1; + + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_top_misc_off_base + CONSYS_CONF_ID_OFFSET); + WMT_PLAT_PR_INFO("consys configuration id(0x%x)\n", consys_ver_id & 0xF); + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys HW version id(0x%x)\n", consys_ver_id & 0xFFFF); + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_FW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys FW version id(0x%x)\n", consys_ver_id & 0xFFFF); + + /* set CR "XO initial stable time" and "XO bg stable time" + * to optimize the wakeup time after sleep + * clear "source clock enable ack to XO state" mask + */ + if (wmt_plat_soc_co_clock_flag_get()) { + consys_reg_base = ioremap(CONSYS_COCLOCK_STABLE_TIME_BASE, 0x100); + if (consys_reg_base) { + value = CONSYS_REG_READ(consys_reg_base); + value = (value & CONSYS_COCLOCK_STABLE_TIME_MASK) | + CONSYS_COCLOCK_STABLE_TIME; + CONSYS_REG_WRITE(consys_reg_base, value); + value = CONSYS_REG_READ(consys_reg_base + CONSYS_COCLOCK_ACK_ENABLE_OFFSET); + value = (value & CONSYS_COCLOCK_ACK_ENABLE_MAST) | + CONSYS_COCLOCK_ACK_ENABLE_VALUE; + value = value & (~CONSYS_COCLOCK_ACK_ENABLE_BIT); + CONSYS_REG_WRITE(consys_reg_base + CONSYS_COCLOCK_ACK_ENABLE_OFFSET, value); + iounmap(consys_reg_base); + } else + WMT_PLAT_PR_ERR("connsys co_clock stable time base(0x%x) ioremap fail!\n", + CONSYS_COCLOCK_STABLE_TIME_BASE); + } + + /* write reserverd cr for identify adie is 6635 or 6631 */ + consys_reg_base = ioremap(CONSYS_IDENTIFY_ADIE_CR_ADDRESS, 0x8); + if (consys_reg_base) { + value = CONSYS_REG_READ(consys_reg_base); +#if CONSYS_PMIC_CTRL_6635 + value = value & (~CONSYS_IDENTIFY_ADIE_ENABLE_BIT); +#else + value = value | (CONSYS_IDENTIFY_ADIE_ENABLE_BIT); +#endif + CONSYS_REG_WRITE(consys_reg_base, value); + iounmap(consys_reg_base); + } else + WMT_PLAT_PR_ERR("connsys identify adie cr address(0x%x) ioremap fail!\n", + CONSYS_IDENTIFY_ADIE_CR_ADDRESS); + +#if CONSYS_PMIC_CTRL_6635 + /* if(MT6635) + * CONN_WF_CTRL2 swtich to GPIO mode, GPIO output value + * before patch download swtich back to CONN mode. + */ + consys_reg_base = ioremap(CONSYS_IF_PINMUX_REG_BASE, 0x1000); + if (!consys_reg_base) { + WMT_PLAT_PR_ERR("consys_if_pinmux_reg_base(%x) ioremap fail\n", + CONSYS_IF_PINMUX_REG_BASE); + return 0; + } + + CONSYS_REG_WRITE(consys_reg_base + CONSYS_WF_CTRL2_01_OFFSET, + (CONSYS_REG_READ(consys_reg_base + CONSYS_WF_CTRL2_01_OFFSET) & + CONSYS_WF_CTRL2_01_MASK) | CONSYS_WF_CTRL2_01_VALUE); + CONSYS_REG_WRITE(consys_reg_base + CONSYS_WF_CTRL2_02_OFFSET, + (CONSYS_REG_READ(consys_reg_base + CONSYS_WF_CTRL2_02_OFFSET) & + CONSYS_WF_CTRL2_02_MASK) | CONSYS_WF_CTRL2_02_VALUE); + CONSYS_REG_WRITE(consys_reg_base + CONSYS_WF_CTRL2_03_OFFSET, + (CONSYS_REG_READ(consys_reg_base + CONSYS_WF_CTRL2_03_OFFSET) & + CONSYS_WF_CTRL2_03_MASK) | CONSYS_WF_CTRL2_GPIO_MODE); + if (consys_reg_base) + iounmap(consys_reg_base); + else + WMT_PLAT_PR_ERR("consys_if_pinmux_reg_base(0x%x) ioremap fail!\n", + CONSYS_IF_PINMUX_REG_BASE); +#endif + /* connsys bus time out configure, enable AHB bus timeout */ + consys_reg_base = ioremap(CONSYS_AHB_TIMEOUT_EN_ADDRESS, 0x100); + if (consys_reg_base) { + CONSYS_REG_WRITE(consys_reg_base, CONSYS_AHB_TIMEOUT_EN_VALUE); + iounmap(consys_reg_base); + } else + WMT_PLAT_PR_ERR("CONSYS_AHB_TIMEOUT_EN_ADDRESS(0x%x) ioremap fail!\n", + CONSYS_AHB_TIMEOUT_EN_ADDRESS); + + /* update WPLL setting for WPLL issue@LT */ + consys_reg_base = ioremap(CONSYS_WPLL_SETTING_ADDRESS, 0x100); + if (consys_reg_base) { + CONSYS_REG_WRITE(consys_reg_base, + (CONSYS_REG_READ(consys_reg_base) & + CONSYS_WPLL_SETTING_MASK) | CONSYS_WPLL_SETTING_VALUE); + iounmap(consys_reg_base); + } + + /* toppose_restore_done rollabck */ + consys_reg_base = ioremap(CONSYS_TOPPOSE_RESTORE_ADDRESS, 0x100); + if (consys_reg_base) { + CONSYS_REG_WRITE(consys_reg_base, + (CONSYS_REG_READ(consys_reg_base) & + CONSYS_TOPPOSE_RESTORE_MASK) | CONSYS_TOPPOSE_RESTORE_VALUE); + iounmap(consys_reg_base); + } + + return 0; +} + +static VOID consys_acr_reg_setting(VOID) +{ + WMT_PLAT_PR_INFO("No need to do acr"); +} + +static VOID consys_afe_reg_setting(VOID) +{ + WMT_PLAT_PR_INFO("No need to do afe"); +} + +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*Set VCN18_SW_OP_EN as 1*/ + KERNEL_pmic_ldo_vcn18_lp(SW, 1, 1, SW_OFF); + /*Set VCN18_SW_EN as 1 and set votage as 1V8*/ + if (reg_VCN18) { + regulator_set_voltage(reg_VCN18, 1800000, 1800000); + if (regulator_enable(reg_VCN18)) + WMT_PLAT_PR_ERR("enable VCN18 fail\n"); + else + WMT_PLAT_PR_DBG("enable VCN18 ok\n"); + } + /*Set VCN18 SW_LP as 0*/ + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_LP, 0); + /*Set VCN18 as low-power mode(1), HW0_OP_EN as 1, HW0_OP_CFG as HW_LP(1)*/ + KERNEL_pmic_ldo_vcn18_lp(SRCLKEN0, 1, 1, HW_LP); +#if CONSYS_PMIC_CTRL_6635 + /* delay 300us (VCN18 stable time) */ + udelay(300); + /*Set VCN13_SW_OP_EN as 1*/ + KERNEL_pmic_ldo_vcn13_lp(SW, 1, 1, SW_OFF); + /*Set VCN13_SW_EN as 1 and set votage as 1V3*/ + if (reg_VCN13) { + regulator_set_voltage(reg_VCN13, 1300000, 1300000); + if (regulator_enable(reg_VCN13)) + WMT_PLAT_PR_ERR("enable VCN13 fail\n"); + else + WMT_PLAT_PR_DBG("enable VCN13 ok\n"); + } + /*Set VCN13 SW_LP as 0*/ + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN13_LP, 0); + /*Set VCN13 as low-power mode(1), HW0_OP_EN as 1, HW0_OP_CFG as HW_LP(1)*/ + KERNEL_pmic_ldo_vcn13_lp(SRCLKEN0, 1, 1, HW_LP); +#else + /*1.AP power on VCN_3V3 LDO (with PMIC_WRAP API) VCN_3V3 */ + /*default vcn33_1 SW mode*/ + if (reg_VCN33_1_BT) { + regulator_set_voltage(reg_VCN33_1_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_1_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } +#endif + } else { +#if CONSYS_PMIC_CTRL_6635 + if (reg_VCN13) + regulator_disable(reg_VCN13); +#else + if (reg_VCN33_1_BT) + regulator_disable(reg_VCN33_1_BT); +#endif + /* delay 300us */ + udelay(300); + /*AP power off MT6351L VCN_1V8 LDO */ + if (reg_VCN18) { + if (regulator_disable(reg_VCN18)) + WMT_PLAT_PR_ERR("disable VCN_1V8 fail!\n"); + else + WMT_PLAT_PR_DBG("disable VCN_1V8 ok\n"); + } + } +#endif + return 0; +} + +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE +#if CONSYS_PMIC_CTRL_6635 + /* 6635 not supported */ +#else + if (enable) + /*Set VCN33_2_SW_OP_EN as 1*/ + KERNEL_pmic_ldo_vcn33_2_lp(SW, 1, 1, SW_OFF); + else + /*Set VCN33_2 as low-power mode(1), HW0_OP_EN as 0, HW0_OP_CFG as HW_OFF(0)*/ + KERNEL_pmic_ldo_vcn33_2_lp(SRCLKEN0, 1, 0, HW_OFF); +#endif +#endif +} + +static INT32 consys_hw_vcn28_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE +#if CONSYS_PMIC_CTRL_6635 + /* 6635 not supported */ +#else + if (enable) { + /*in co-clock mode,need to turn on vcn33_2 when fm on */ + /*Set VCN33_2_SW_OP_EN as 1*/ + KERNEL_pmic_ldo_vcn33_2_lp(SW, 1, 1, SW_OFF); + /*Set VCN33_1_SW_EN as 1 and set votage as 2V8*/ + if (reg_VCN33_2_WIFI) { + regulator_set_voltage(reg_VCN33_2_WIFI, 2800000, 2800000); + regulator_enable(reg_VCN33_2_WIFI); + } + /*Set VCN33_2 SW_LP as 0*/ + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_2_LP, 0); + /*Set VCN33_2 as low-power mode(1), HW0_OP_EN as 1, HW0_OP_CFG as HW_OFF(0)*/ + KERNEL_pmic_ldo_vcn33_2_lp(SRCLKEN0, 1, 1, HW_OFF); + WMT_PLAT_PR_INFO("turn on vcn33_2 for fm/gps usage in co-clock mode\n"); + } else { + /*in co-clock mode,need to turn off vcn33_2 when fm off */ + /*Set VCN33_2 as low-power mode(1), HW0_OP_EN as 0, HW0_OP_CFG as HW_OFF(0)*/ + KERNEL_pmic_ldo_vcn33_2_lp(SRCLKEN0, 1, 0, HW_OFF); + if (reg_VCN33_2_WIFI) + regulator_disable(reg_VCN33_2_WIFI); + WMT_PLAT_PR_INFO("turn off vcn33_2 for fm/gps usage in co-clock mode\n"); + } +#endif +#endif + + return 0; +} + +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_6635 + if (enable) { +#if CONSYS_PMIC_CTRL_ENABLE + /*Set VCN33_1_SW_OP_EN as 1*/ + KERNEL_pmic_ldo_vcn33_1_lp(SW, 1, 1, SW_OFF); + /*Set VCN33_1_SW_EN as 1 and set votage as 3V3*/ + if (reg_VCN33_1_BT) { + regulator_set_voltage(reg_VCN33_1_BT, 3300000, 3300000); + if (regulator_enable(reg_VCN33_1_BT)) + WMT_PLAT_PR_ERR("WMT do BT PMIC on fail!\n"); + } + /*Set VCN33_1 SW_LP as 0*/ + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_1_LP, 0); + /*Set VCN33_1 as low-power mode(1), HW0_OP_EN as 1, HW0_OP_CFG as HW_OFF(0)*/ + KERNEL_pmic_ldo_vcn33_1_lp(SRCLKEN0, 1, 1, HW_OFF); + /* request VS2 to 1.4V by VS2 VOTER (use bit 4) */ + KERNEL_pmic_set_register_value(PMIC_RG_BUCK_VS2_VOTER_EN_SET, 0x10); + /* Set VCN13 to 1.32V */ + KERNEL_pmic_set_register_value(PMIC_RG_VCN13_VOCAL, 0x2); + +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC on\n"); + } else { + /*do BT PMIC off */ + /*switch BT PALDO control from HW mode to SW mode:0x416[5]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + /*Set VCN33_1 as low-power mode(1), HW0_OP_EN as 0, HW0_OP_CFG as HW_OFF(0)*/ + KERNEL_pmic_ldo_vcn33_1_lp(SRCLKEN0, 1, 0, HW_OFF); + /* restore VCN13 to 1.3V */ + KERNEL_pmic_set_register_value(PMIC_RG_VCN13_VOCAL, 0); + /* clear bit 4 of VS2 VOTER then VS2 can restore to 1.35V */ + KERNEL_pmic_set_register_value(PMIC_RG_BUCK_VS2_VOTER_EN_CLR, 0x10); + + if (reg_VCN33_1_BT) + regulator_disable(reg_VCN33_1_BT); +#endif + WMT_PLAT_PR_DBG("WMT do BT PMIC off\n"); + } +#endif + + return 0; +} + +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_6635 + if (enable) { +#if CONSYS_PMIC_CTRL_ENABLE + /*Set VCN33_1_SW_OP_EN as 1*/ + KERNEL_pmic_ldo_vcn33_1_lp(SW, 1, 1, SW_OFF); + /*Set VCN33_1_SW_EN as 1 and set votage as 3V3*/ + if (reg_VCN33_1_WIFI) { + regulator_set_voltage(reg_VCN33_1_WIFI, 3300000, 3300000); + if (regulator_enable(reg_VCN33_1_WIFI)) + WMT_PLAT_PR_ERR("WMT do WIFI PMIC on fail!\n"); + } + /*Set VCN33_1 SW_LP as 0*/ + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_1_LP, 0); + /*Set VCN33_1 as low-power mode(1), HW0_OP_EN as 1, HW0_OP_CFG as HW_OFF(0)*/ + KERNEL_pmic_ldo_vcn33_1_lp(SRCLKEN0, 1, 1, HW_OFF); + + /*Set VCN33_2_SW_OP_EN as 1*/ + KERNEL_pmic_ldo_vcn33_2_lp(SW, 1, 1, SW_OFF); + /*Set VCN33_1_SW_EN as 1 and set votage as 3V3*/ + if (reg_VCN33_2_WIFI) { + regulator_set_voltage(reg_VCN33_2_WIFI, 3300000, 3300000); + if (regulator_enable(reg_VCN33_2_WIFI)) + WMT_PLAT_PR_ERR("WMT do WIFI PMIC on fail!\n"); + } + /*Set VCN33_2 SW_LP as 0*/ + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_2_LP, 0); + /*Set VCN33_2 as low-power mode(1), HW0_OP_EN as 1, HW0_OP_CFG as HW_OFF(0)*/ + KERNEL_pmic_ldo_vcn33_2_lp(SRCLKEN0, 1, 1, HW_OFF); +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC on\n"); + } else { + /*do WIFI PMIC off */ + /*switch WIFI PALDO control from HW mode to SW mode:0x418[14]-->0x0 */ +#if CONSYS_PMIC_CTRL_ENABLE + /*Set VCN33_1 as low-power mode(1), HW0_OP_EN as 0, HW0_OP_CFG as HW_OFF(0)*/ + KERNEL_pmic_ldo_vcn33_1_lp(SRCLKEN0, 1, 0, HW_OFF); + if (reg_VCN33_1_WIFI) + regulator_disable(reg_VCN33_1_WIFI); + + /*Set VCN33_2 as low-power mode(1), HW0_OP_EN as 0, HW0_OP_CFG as HW_OFF(0)*/ + KERNEL_pmic_ldo_vcn33_2_lp(SRCLKEN0, 1, 0, HW_OFF); + if (reg_VCN33_2_WIFI) + regulator_disable(reg_VCN33_2_WIFI); +#endif + WMT_PLAT_PR_DBG("WMT do WIFI PMIC off\n"); + } + +#endif + + return 0; +} + +static INT32 consys_emi_mpu_set_region_protection(VOID) +{ +#ifdef CONFIG_MTK_EMI + struct emi_region_info_t region_info; + + /*set MPU for EMI share Memory */ + WMT_PLAT_PR_INFO("setting MPU for EMI share memory\n"); + + region_info.start = gConEmiPhyBase; + region_info.end = gConEmiPhyBase + gConEmiSize - 1; + region_info.region = 27; + SET_ACCESS_PERMISSION(region_info.apc, LOCK, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + NO_PROTECTION, FORBIDDEN, NO_PROTECTION); + emi_mpu_set_protection(®ion_info); +#endif + + return 0; +} + +static UINT32 consys_emi_set_remapping_reg(VOID) +{ + /* For direct path */ + phys_addr_t mdPhy = 0; + INT32 size = 0; + + mtk_wcn_emi_addr_info.emi_ap_phy_addr = gConEmiPhyBase; + mtk_wcn_emi_addr_info.emi_size = gConEmiSize; + + /*EMI Registers remapping*/ + CONSYS_REG_WRITE_OFFSET_RANGE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, + gConEmiPhyBase, 0, 16, 20); + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); + + /*Perisys Configuration Registers remapping*/ + CONSYS_REG_WRITE_OFFSET_RANGE(conn_reg.topckgen_base + CONSYS_EMI_PERI_MAPPING_OFFSET, + 0x10003000, 0, 16, 20); + WMT_PLAT_PR_INFO("PERISYS_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_PERI_MAPPING_OFFSET)); + + /*Modem Configuration Registers remapping*/ + mdPhy = get_smem_phy_start_addr(MD_SYS1, SMEM_USER_RAW_MD_CONSYS, &size); + if (size == 0) + WMT_PLAT_PR_INFO("MD direct path is not supported\n"); + else { + CONSYS_REG_WRITE_OFFSET_RANGE( + conn_reg.topckgen_base + CONSYS_EMI_AP_MD_OFFSET, + mdPhy, 0, 16, 20); + WMT_PLAT_PR_INFO("MD_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_AP_MD_OFFSET)); + } + mtk_wcn_emi_addr_info.emi_direct_path_ap_phy_addr = mdPhy; + mtk_wcn_emi_addr_info.emi_direct_path_size = size; + + mtk_wcn_emi_addr_info.emi_ram_bt_buildtime_offset = + CONSYS_EMI_RAM_BT_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_ram_wifi_buildtime_offset = + CONSYS_EMI_RAM_WIFI_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_ram_mcu_buildtime_offset = + CONSYS_EMI_RAM_MCU_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_patch_mcu_buildtime_offset = + CONSYS_EMI_PATCH_MCU_BUILDTIME_OFFSET; + + return 0; +} + +static INT32 bt_wifi_share_v33_spin_lock_init(VOID) +{ + return 0; +} + +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, + PUINT32 irq_flag) +{ + struct device_node *node; + + node = pdev->dev.of_node; + if (node) { + *irq_num = irq_of_parse_and_map(node, 0); + *irq_flag = irq_get_trigger_type(*irq_num); + WMT_PLAT_PR_INFO("get irq id(%d) and irq trigger flag(%d) from DT\n", *irq_num, + *irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return -1; + } + + return 0; +} + +static INT32 consys_read_reg_from_dts(struct platform_device *pdev) +{ + INT32 iRet = -1; + struct device_node *node = NULL; + + node = pdev->dev.of_node; + if (node) { + /* registers base address */ + conn_reg.mcu_base = (SIZE_T) of_iomap(node, MCU_BASE_INDEX); + WMT_PLAT_PR_DBG("Get mcu register base(0x%zx)\n", conn_reg.mcu_base); + conn_reg.ap_rgu_base = (SIZE_T) of_iomap(node, TOP_RGU_BASE_INDEX); + WMT_PLAT_PR_DBG("Get ap_rgu register base(0x%zx)\n", conn_reg.ap_rgu_base); + conn_reg.topckgen_base = (SIZE_T) of_iomap(node, INFRACFG_AO_BASE_INDEX); + WMT_PLAT_PR_DBG("Get topckgen register base(0x%zx)\n", conn_reg.topckgen_base); + conn_reg.spm_base = (SIZE_T) of_iomap(node, SPM_BASE_INDEX); + WMT_PLAT_PR_DBG("Get spm register base(0x%zx)\n", conn_reg.spm_base); + conn_reg.mcu_conn_hif_on_base = (SIZE_T) of_iomap(node, MCU_CONN_HIF_ON_BASE_INDEX); + WMT_PLAT_PR_DBG("Get mcu_conn_hif_on register base(0x%zx)\n", + conn_reg.mcu_conn_hif_on_base); + conn_reg.mcu_top_misc_off_base = (SIZE_T) of_iomap(node, + MCU_TOP_MISC_OFF_BASE_INDEX); + WMT_PLAT_PR_DBG("Get mcu_top_misc_off register base(0x%zx)\n", + conn_reg.mcu_top_misc_off_base); + conn_reg.mcu_cfg_on_base = (SIZE_T) of_iomap(node, MCU_CFG_ON_BASE_INDEX); + WMT_PLAT_PR_DBG("Get mcu_cfg_on register base(0x%zx)\n", conn_reg.mcu_cfg_on_base); + conn_reg.mcu_cirq_base = (SIZE_T) of_iomap(node, MCU_CIRQ_BASE_INDEX); + WMT_PLAT_PR_DBG("Get mcu cirq register base(0x%zx)\n", conn_reg.mcu_cirq_base); + conn_reg.mcu_top_misc_on_base = (SIZE_T) of_iomap(node, MCU_TOP_MISC_ON_BASE_INDEX); + WMT_PLAT_PR_DBG("Get mcu_top_misc_off register base(0x%zx)\n", + conn_reg.mcu_top_misc_on_base); + conn_reg.ap_pccif4_base = (SIZE_T) of_iomap(node, AP_PCCIF4_BASE_INDEX); + WMT_PLAT_PR_DBG("Get ap_pccif4 register base(0x%zx)\n", + conn_reg.ap_pccif4_base); + conn_reg.infra_ao_pericfg_base = (SIZE_T) of_iomap(node, INFRA_AO_PERICFG_BASE_INDEX); + WMT_PLAT_PR_DBG("Get infra_ao_pericfg register base(0x%zx)\n", + conn_reg.infra_ao_pericfg_base); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iRet; + } + + return 0; +} + +static VOID force_trigger_assert_debug_pin(VOID) +{ + UINT32 value = 0; + + if (conn_reg.infra_ao_pericfg_base != 0) { + WMT_PLAT_PR_DBG("CON_STA_REG = %x\n", + CONSYS_REG_READ( + conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG)); + + /* clear CON_PWR_ON & CON_SW_READY bit (CON_STA_REG[0], CON_STA_REG[1]) */ + value = CONSYS_REG_READ(conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG); + value = value & (~INFRASYS_COMMON_AP2MD_CON_PWR_ON_CON_SW_READY_MASK); + CONSYS_REG_WRITE(conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG, + value); + + WMT_PLAT_PR_DBG("CON_STA_REG = %x\n", + CONSYS_REG_READ( + conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG)); + } + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + usleep_range(64, 96); + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); +} + +static UINT32 consys_read_cpupcr(VOID) +{ + return CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base + CONSYS_CPUPCR_OFFSET); +} + +static UINT32 consys_soc_chipid_get(VOID) +{ + return PLATFORM_SOC_CHIP; +} + +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID) +{ + return &mtk_wcn_emi_addr_info; +} + +P_WMT_CONSYS_IC_OPS mtk_wcn_get_consys_ic_ops(VOID) +{ + return &consys_ic_ops; +} + +static INT32 consys_dl_rom_patch(UINT32 ip_ver, UINT32 fw_ver) +{ + if (rom_patch_dl_flag) { + if (mtk_wcn_soc_rom_patch_dwn(ip_ver, fw_ver) == 0) + rom_patch_dl_flag = 1; + else + return -1; + } + + return 0; +} + +static VOID consys_set_dl_rom_patch_flag(INT32 flag) +{ + rom_patch_dl_flag = flag; +} + +static INT32 consys_dedicated_log_path_init(struct platform_device *pdev) +{ + struct device_node *node; + UINT32 irq_num; + UINT32 irq_flag; + INT32 iret = -1; + + node = pdev->dev.of_node; + if (node) { + irq_num = irq_of_parse_and_map(node, 2); + irq_flag = irq_get_trigger_type(irq_num); + WMT_PLAT_PR_INFO("get conn2ap_sw_irq id(%d) and irq trigger flag(%d) from DT\n", + irq_num, irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iret; + } + + connsys_dedicated_log_path_apsoc_init(gConEmiPhyBase, irq_num, irq_flag); +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + fw_log_wmt_init(); +#endif + return 0; +} + +static VOID consys_dedicated_log_path_deinit(VOID) +{ +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + fw_log_wmt_deinit(); +#endif + connsys_dedicated_log_path_apsoc_deinit(); +} + +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable) +{ + if (enable) { + *addr = ioremap(gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET, + CONSYS_EMI_MEM_SIZE); + if (*addr) { + WMT_PLAT_PR_INFO("COREDUMP EMI mapping OK virtual(0x%p) physical(0x%x)\n", + *addr, (UINT32) gConEmiPhyBase + + CONSYS_EMI_COREDUMP_OFFSET); + memset_io(*addr, 0, CONSYS_EMI_MEM_SIZE); + } else { + WMT_PLAT_PR_ERR("EMI mapping fail\n"); + return -1; + } + } else { + if (*addr) { + iounmap(*addr); + *addr = NULL; + } + } + return 0; +} + +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr) +{ + if (!addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + WMT_PLAT_PR_INFO("Reset EMI(0xF0068000 ~ 0xF0068400) and (0xF0070400 ~ 0xF0078400)\n"); + /* reset 0xF0068000 ~ 0xF0068400 (1K) */ + memset_io(addr, 0, 0x400); + /* reset 0xF0070400 ~ 0xF0078400 (32K) */ + memset_io(addr + CONSYS_EMI_PAGED_DUMP_OFFSET, 0, 0x8000); + return 0; +} + +static INT32 consys_check_reg_readable(VOID) +{ + INT32 flag = 0; + UINT32 value = 0; + P_DEV_WMT pDev = &gDevWmt; + + if (osal_test_bit(WMT_STAT_PWR, &pDev->state)) { + /*check connsys clock and sleep status*/ + CONSYS_REG_WRITE(conn_reg.mcu_conn_hif_on_base, CONSYS_CLOCK_CHECK_VALUE); + udelay(1000); + value = CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base); + if ((value & CONSYS_HCLK_CHECK_BIT) && + (value & CONSYS_OSCCLK_CHECK_BIT)) + flag = 1; + } + + if (!flag) + WMT_PLAT_PR_ERR("connsys clock check fail 0x18007000(0x%x)\n", value); + + return flag; +} + +static VOID consys_ic_clock_fail_dump(VOID) +{ + UINT8 *addr; + char *buffer, *temp; + INT32 size = 1024; + + /* make sure buffer size is big enough */ + buffer = osal_malloc(size); + if (!buffer) + return; + + temp = buffer; + temp += sprintf(temp, "CONN_HIF_TOP_MISC=0x%08x CONN_HIF_BUSY_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_TOP_MISC), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_BUSY_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_HIF_DBG_IDX, 0x3333); + temp += sprintf(temp, "Write CONSYS_HIF_DBG_IDX to 0x3333\n"); + + temp += sprintf(temp, "CONSYS_HIF_DBG_PROBE=0x%08x CONN_HIF_TOP_MISC=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_DBG_PROBE), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_TOP_MISC)); + + temp += sprintf(temp, "CONN_HIF_BUSY_STATUS=0x%08x CONN_HIF_PDMA_BUSY_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_BUSY_STATUS), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_PDMA_BUSY_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_HIF_DBG_IDX, 0x2222); + temp += sprintf(temp, "Write CONSYS_HIF_DBG_IDX to 0x2222\n"); + + temp += sprintf(temp, "CONSYS_HIF_DBG_PROBE=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_DBG_PROBE)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_HIF_DBG_IDX, 0x3333); + temp += sprintf(temp, "Write CONSYS_HIF_DBG_IDX to 0x3333\n"); + + temp += sprintf(temp, "CONSYS_HIF_DBG_PROBE=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_DBG_PROBE)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_HIF_DBG_IDX, 0x4444); + temp += sprintf(temp, "Write CONSYS_HIF_DBG_IDX to 0x4444\n"); + + temp += sprintf(temp, "CONSYS_HIF_DBG_PROBE=0x%08x CONN_MCU_EMI_CONTROL=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_DBG_PROBE), + CONSYS_REG_READ(conn_reg.mcu_base + CONN_MCU_EMI_CONTROL)); + temp += sprintf(temp, "EMI_CONTROL_DBG_PROBE=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + EMI_CONTROL_DBG_PROBE)); + temp += sprintf(temp, "CONN_MCU_CLOCK_CONTROL=0x%08x CONN_MCU_BUS_CONTROL=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CLOCK_CONTROL), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_BUS_CONTROL)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x003e3d00); + temp += sprintf(temp, "Write CONSYS_DEBUG_SELECT to 0x003e3d00\n"); + + temp += sprintf(temp, "CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x00403f00); + temp += sprintf(temp, "Write CONSYS_DEBUG_SELECT to 0x00403f00\n"); + + temp += sprintf(temp, "CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x00424100); + temp += sprintf(temp, "Write CONSYS_DEBUG_SELECT to 0x00424100\n"); + + temp += sprintf(temp, "CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x00444300); + temp += sprintf(temp, "Write CONSYS_DEBUG_SELECT to 0x00444300\n"); + + temp += sprintf(temp, "CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + WMT_PLAT_PR_ERR("%s length = %d", buffer, osal_strlen(buffer)); + + temp = buffer; + addr = ioremap(0x180bc000, 0x100); + /* conn2ap axi master sleep prot info */ + temp += sprintf(temp, "0x180bc010=0x%08x\n", CONSYS_REG_READ(addr + 0x10)); + /* conn_mcu2ap axi master sleep prot info */ + temp += sprintf(temp, "0x180bc014=0x%08x\n", CONSYS_REG_READ(addr + 0x14)); + /* conn2ap axi gals bus info */ + temp += sprintf(temp, "0x180bc018=0x%08x\n", CONSYS_REG_READ(addr + 0x18)); + /* conn2ap mux4to1 debug info */ + temp += sprintf(temp, "0x180bc01c=0x%08x\n", CONSYS_REG_READ(addr + 0x1c)); + /* conn_hif_off bus busy info */ + temp += sprintf(temp, "0x180bc020=0x%08x\n", CONSYS_REG_READ(addr + 0x20)); + iounmap(addr); + + addr = ioremap(0x1800713c, 0x100); + /* conn_hif_on misc info */ + temp += sprintf(temp, "0x1800713c=0x%08x\n", CONSYS_REG_READ(addr)); + iounmap(addr); + + addr = ioremap(0x180c1144, 0x100); + /* conn_on_host debug flag */ + temp += sprintf(temp, "0x180c1144=0x%08x\n", CONSYS_REG_READ(addr)); + iounmap(addr); + + addr = ioremap(0x1020E804, 0x100); + /* 0x1020E804 */ + temp += sprintf(temp, "0x1020E804=0x%08x\n", CONSYS_REG_READ(addr)); + iounmap(addr); + + WMT_PLAT_PR_ERR("%s length = %d", buffer, osal_strlen(buffer)); + osal_free(buffer); +} + +static INT32 consys_is_connsys_reg(UINT32 addr) +{ + if (addr > 0x18000000 && addr < 0x180FFFFF) { + if (addr >= 0x18007000 && addr <= 0x18007FFF) + return 0; + + return 1; + } + + return 0; +} + +static PUINT32 consys_resume_dump_info(VOID) +{ + if (conn_reg.mcu_cfg_on_base != 0 && + conn_reg.mcu_top_misc_on_base != 0 && + mtk_consys_check_reg_readable()) { + stp_dbg_clear_cpupcr_reg_info(); + stp_dbg_poll_cpupcr(5, 0, 1); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR, 0x1); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_MON_CTL_ADDR, 0x80000001); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_MON_SEL0_ADDR, 0x03020100); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_MON_SEL1_ADDR, 0x07060504); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_MON_SEL2_ADDR, 0x0b0a0908); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_MON_SEL3_ADDR, 0x0f0e0d0c); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_DBGSEL_ADDR, 0x3); + g_connsys_lp_dump_info[0] = (UINT32)CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_MAPPING_AP_ADDR; + g_connsys_lp_dump_info[1] = CONSYS_REG_READ(CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_ADDR); + WMT_PLAT_PR_INFO("0x%08x: 0x%x\n", g_connsys_lp_dump_info[0], g_connsys_lp_dump_info[1]); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR, 0x0); + return &g_connsys_lp_dump_info[0]; + } + return NULL; +} + +static VOID consys_set_mcif_emi_mpu_protection(MTK_WCN_BOOL enable) +{ + WMT_PLAT_PR_INFO("Setup region 23 for domain 0 as %s\n", enable ? "FORBIDDEN" : "SEC_R_NSEC_R"); + emi_mpu_set_single_permission(23, 0, enable ? FORBIDDEN : SEC_R_NSEC_R); +} + +static INT32 consys_calibration_backup_restore_support(VOID) +{ + return 1; +} + +static INT32 consys_is_ant_swap_enable_by_hwid(INT32 pin_num) +{ + return !gpio_get_value(pin_num); +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6785.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6785.c new file mode 100644 index 00000000000000..5eb76d9e4e651e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mt6785.c @@ -0,0 +1,1545 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <connectivity_build_in_adapter.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/memblock.h> +#include <linux/platform_device.h> +#include "connsys_debug_utility.h" +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +#include "fw_log_wmt.h" +#endif +#include "osal_typedef.h" +#include "mt6785.h" +#include "mtk_wcn_consys_hw.h" +#include "wmt_ic.h" +#include "wmt_lib.h" +#include "wmt_plat.h" +#include "stp_dbg.h" + +#ifdef CONFIG_MTK_EMI +#include <mt_emi_api.h> +#endif + +#if CONSYS_PMIC_CTRL_ENABLE +#include <mtk_pmic_api_buck.h> +#include <upmu_common.h> +#include <linux/regulator/consumer.h> +#endif + +#ifdef CONFIG_MTK_HIBERNATION +#include <mtk_hibernate_dpm.h> +#endif + +#include <linux/of_reserved_mem.h> + +#include <mtk_clkbuf_ctl.h> + +/* Direct path */ +#include <mtk_ccci_common.h> +#if WMT_DEVAPC_DBG_SUPPORT +#include <devapc_public.h> +#endif +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable); +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable); +static VOID consys_hw_spm_clk_gating_enable(VOID); +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable); +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable); +static INT32 polling_consys_chipid(VOID); +static VOID consys_acr_reg_setting(VOID); +static VOID consys_afe_reg_setting(VOID); +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable); +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable); +static INT32 consys_hw_vcn28_ctrl(UINT32 enable); +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable); +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable); +static UINT32 consys_soc_chipid_get(VOID); +static INT32 consys_emi_mpu_set_region_protection(VOID); +static UINT32 consys_emi_set_remapping_reg(VOID); +static INT32 bt_wifi_share_v33_spin_lock_init(VOID); +static INT32 consys_clk_get_from_dts(struct platform_device *pdev); +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev); +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, + PINT32 irq_num, PUINT32 irq_flag); +static INT32 consys_read_reg_from_dts(struct platform_device *pdev); +static UINT32 consys_read_cpupcr(VOID); +static VOID force_trigger_assert_debug_pin(VOID); +static INT32 consys_co_clock_type(VOID); +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID); +static VOID consys_set_if_pinmux(MTK_WCN_BOOL enable); +static INT32 consys_dl_rom_patch(UINT32 ip_ver, UINT32 fw_ver); +static VOID consys_set_dl_rom_patch_flag(INT32 flag); +static INT32 consys_dedicated_log_path_init(struct platform_device *pdev); +static VOID consys_dedicated_log_path_deinit(VOID); +static INT32 consys_check_reg_readable(VOID); +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable); +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr); +static VOID consys_ic_clock_fail_dump(VOID); +static INT32 consys_is_connsys_reg(UINT32 addr); +static PUINT32 consys_resume_dump_info(VOID); +static VOID consys_set_pdma_axi_rready_force_high(UINT32 enable); +static VOID consys_set_mcif_emi_mpu_protection(MTK_WCN_BOOL enable); +/* + * If 1: this platform supports calibration backup/restore. + * otherwise: 0 + */ +static INT32 consys_calibration_backup_restore_support(VOID); +#if WMT_DEVAPC_DBG_SUPPORT +static VOID consys_devapc_violation_cb(VOID); +#endif +static VOID consyc_register_devapc_cb(VOID); +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +/* CCF part */ +struct clk *clk_scp_conn_main; /*ctrl conn_power_on/off */ +struct clk *clk_infracfg_ao_ccif4_ap_cg; /* For direct path */ + +/* PMIC part */ +#if CONSYS_PMIC_CTRL_ENABLE +struct regulator *reg_VCN18; +struct regulator *reg_VCN33_1; +struct regulator *reg_VCN33_2; +#endif + +EMI_CTRL_STATE_OFFSET mtk_wcn_emi_state_off = { + .emi_apmem_ctrl_state = EXP_APMEM_CTRL_STATE, + .emi_apmem_ctrl_host_sync_state = EXP_APMEM_CTRL_HOST_SYNC_STATE, + .emi_apmem_ctrl_host_sync_num = EXP_APMEM_CTRL_HOST_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_state = EXP_APMEM_CTRL_CHIP_SYNC_STATE, + .emi_apmem_ctrl_chip_sync_num = EXP_APMEM_CTRL_CHIP_SYNC_NUM, + .emi_apmem_ctrl_chip_sync_addr = EXP_APMEM_CTRL_CHIP_SYNC_ADDR, + .emi_apmem_ctrl_chip_sync_len = EXP_APMEM_CTRL_CHIP_SYNC_LEN, + .emi_apmem_ctrl_chip_print_buff_start = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START, + .emi_apmem_ctrl_chip_print_buff_len = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN, + .emi_apmem_ctrl_chip_print_buff_idx = EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX, + .emi_apmem_ctrl_chip_int_status = EXP_APMEM_CTRL_CHIP_INT_STATUS, + .emi_apmem_ctrl_chip_paded_dump_end = EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END, + .emi_apmem_ctrl_host_outband_assert_w1 = EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1, + .emi_apmem_ctrl_chip_page_dump_num = EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM, + .emi_apmem_ctrl_assert_flag = EXP_APMEM_CTRL_ASSERT_FLAG, +}; + +CONSYS_EMI_ADDR_INFO mtk_wcn_emi_addr_info = { + .emi_phy_addr = CONSYS_EMI_FW_PHY_BASE, + .paged_trace_off = CONSYS_EMI_PAGED_TRACE_OFFSET, + .paged_dump_off = CONSYS_EMI_PAGED_DUMP_OFFSET, + .full_dump_off = CONSYS_EMI_FULL_DUMP_OFFSET, + .emi_remap_offset = CONSYS_EMI_MAPPING_OFFSET, + .p_ecso = &mtk_wcn_emi_state_off, + .emi_core_dump_offset = CONSYS_EMI_COREDUMP_OFFSET, + .pda_dl_patch_flag = 1, + .emi_met_size = (32*KBYTE), + .emi_met_data_offset = CONSYS_EMI_MET_DATA_OFFSET, +}; + +WMT_CONSYS_IC_OPS consys_ic_ops = { + .consys_ic_clock_buffer_ctrl = consys_clock_buffer_ctrl, + .consys_ic_hw_reset_bit_set = consys_hw_reset_bit_set, + .consys_ic_hw_spm_clk_gating_enable = consys_hw_spm_clk_gating_enable, + .consys_ic_hw_power_ctrl = consys_hw_power_ctrl, + .consys_ic_ahb_clock_ctrl = consys_ahb_clock_ctrl, + .polling_consys_ic_chipid = polling_consys_chipid, + .consys_ic_acr_reg_setting = consys_acr_reg_setting, + .consys_ic_afe_reg_setting = consys_afe_reg_setting, + .consys_ic_hw_vcn18_ctrl = consys_hw_vcn18_ctrl, + .consys_ic_vcn28_hw_mode_ctrl = consys_vcn28_hw_mode_ctrl, + .consys_ic_hw_vcn28_ctrl = consys_hw_vcn28_ctrl, + .consys_ic_hw_wifi_vcn33_ctrl = consys_hw_wifi_vcn33_ctrl, + .consys_ic_hw_bt_vcn33_ctrl = consys_hw_bt_vcn33_ctrl, + .consys_ic_soc_chipid_get = consys_soc_chipid_get, + .consys_ic_emi_mpu_set_region_protection = consys_emi_mpu_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .ic_bt_wifi_share_v33_spin_lock_init = bt_wifi_share_v33_spin_lock_init, + .consys_ic_clk_get_from_dts = consys_clk_get_from_dts, + .consys_ic_pmic_get_from_dts = consys_pmic_get_from_dts, + .consys_ic_read_irq_info_from_dts = consys_read_irq_info_from_dts, + .consys_ic_read_reg_from_dts = consys_read_reg_from_dts, + .consys_ic_read_cpupcr = consys_read_cpupcr, + .ic_force_trigger_assert_debug_pin = force_trigger_assert_debug_pin, + .consys_ic_co_clock_type = consys_co_clock_type, + .consys_ic_soc_get_emi_phy_add = consys_soc_get_emi_phy_add, + .consys_ic_set_if_pinmux = consys_set_if_pinmux, + .consys_ic_set_dl_rom_patch_flag = consys_set_dl_rom_patch_flag, + .consys_ic_dedicated_log_path_init = consys_dedicated_log_path_init, + .consys_ic_dedicated_log_path_deinit = consys_dedicated_log_path_deinit, + .consys_ic_check_reg_readable = consys_check_reg_readable, + .consys_ic_emi_coredump_remapping = consys_emi_coredump_remapping, + .consys_ic_reset_emi_coredump = consys_reset_emi_coredump, + .consys_ic_clock_fail_dump = consys_ic_clock_fail_dump, + .consys_ic_is_connsys_reg = consys_is_connsys_reg, + .consys_ic_resume_dump_info = consys_resume_dump_info, + .consys_ic_set_pdma_axi_rready_force_high = consys_set_pdma_axi_rready_force_high, + .consys_ic_set_mcif_emi_mpu_protection = consys_set_mcif_emi_mpu_protection, + .consys_ic_calibration_backup_restore = consys_calibration_backup_restore_support, + .consys_ic_register_devapc_cb = consyc_register_devapc_cb, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 rom_patch_dl_flag = 1; +UINT32 gJtagCtrl; +UINT32 g_connsys_lp_dump_info[2]; + +#if WMT_DEVAPC_DBG_SUPPORT +static struct devapc_vio_callbacks devapc_handle = { + .id = INFRA_SUBSYS_CONN, + .debug_dump = consys_devapc_violation_cb, +}; +#endif + +#if CONSYS_ENALBE_SET_JTAG +#define JTAG_ADDR1_BASE 0x10005000 +#define JTAG_ADDR2_BASE 0x11F20000 +#define AP2CONN_JTAG_2WIRE_OFFSET 0xF00 +#endif + +INT32 mtk_wcn_consys_jtag_set_for_mcu(VOID) +{ + INT32 ret = 0; +#if CONSYS_ENALBE_SET_JTAG + UINT32 tmp = 0; + PVOID addr = 0; + PVOID remap_addr1 = 0; + PVOID remap_addr2 = 0; + + if (gJtagCtrl) { + WMT_PLAT_PR_INFO("WCN jtag set for mcu start...\n"); + + switch (gJtagCtrl) { + case 1: + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + ret = -1; + goto error; + } + + remap_addr2 = ioremap(JTAG_ADDR2_BASE, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + ret = -1; + goto error; + } + + /* 7-wire jtag pinmux setting*/ + /* PAD AUX Function Selection */ + addr = remap_addr1 + 0x310; + tmp = readl(addr); + tmp = tmp & 0xffffff00; + tmp = tmp | 0x66; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr1 + 0x330; + tmp = readl(addr); + tmp = tmp & 0x00ffffff; + tmp = tmp | 0x66000000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr1 + 0x340; + tmp = readl(addr); + tmp = tmp & 0xfffff000; + tmp = tmp | 0x666; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD Driving Selection */ + addr = remap_addr2; + tmp = readl(addr); + tmp = tmp & 0xfffc01ff; + tmp = tmp | 0x3fe00; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PAD PULL Selection */ + addr = remap_addr2 + 0x40; + tmp = readl(addr); + tmp = tmp & 0xfffc07ff; + tmp = tmp | 0x3f800; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + break; + case 2: + remap_addr1 = ioremap(JTAG_ADDR1_BASE, 0x1000); + if (remap_addr1 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr1 fail!\n"); + ret = -1; + goto error; + } + + remap_addr2 = ioremap(0x11C20000, 0x100); + if (remap_addr2 == 0) { + WMT_PLAT_PR_ERR("remap jtag_addr2 fail!\n"); + ret = -1; + goto error; + } + + /* 2-wire jtag pinmux setting*/ + addr = remap_addr1 + 0x3F0; + tmp = readl(addr); + tmp = tmp & 0x0fffffff; + tmp = tmp | 0x60000000; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + addr = remap_addr1 + 0x400; + tmp = readl(addr); + tmp = tmp & 0xfffffff0; + tmp = tmp | 0x6; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* Driving Selection */ + + addr = remap_addr2; + tmp = readl(addr); + tmp = tmp & 0xfffff1ff; + tmp = tmp | 0x600; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + + /* PULL Selection */ + addr = remap_addr2 + 0x30; + tmp = readl(addr); + tmp = tmp & 0xffffff3f; + tmp = tmp | 0xc0; + writel(tmp, addr); + tmp = readl(addr); + WMT_PLAT_PR_INFO("(RegAddr, RegVal):(0x%p, 0x%x)\n", addr, tmp); + break; + default: + WMT_PLAT_PR_INFO("unsupported options!\n"); + } + + } + +error: + if (remap_addr1) + iounmap(remap_addr1); + if (remap_addr2) + iounmap(remap_addr2); +#endif + return ret; +} + +UINT32 mtk_wcn_consys_jtag_flag_ctrl(UINT32 en) +{ + WMT_PLAT_PR_INFO("%s jtag set for MCU\n", en ? "enable" : "disable"); + gJtagCtrl = en; + return 0; +} + +static INT32 consys_clk_get_from_dts(struct platform_device *pdev) +{ + clk_scp_conn_main = devm_clk_get(&pdev->dev, "conn"); + if (IS_ERR(clk_scp_conn_main)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_scp_conn_main clock.\n"); + return PTR_ERR(clk_scp_conn_main); + } + WMT_PLAT_PR_DBG("[CCF]clk_scp_conn_main=%p\n", clk_scp_conn_main); + + clk_infracfg_ao_ccif4_ap_cg = devm_clk_get(&pdev->dev, "ccif"); + if (IS_ERR(clk_infracfg_ao_ccif4_ap_cg)) { + WMT_PLAT_PR_ERR("[CCF]cannot get clk_infracfg_ao_ccif4_ap_cg clock.\n"); + return PTR_ERR(clk_infracfg_ao_ccif4_ap_cg); + } + WMT_PLAT_PR_DBG("[CCF]clk_infracfg_ao_ccif4_ap_cg=%p\n", clk_infracfg_ao_ccif4_ap_cg); + + return 0; +} + +static INT32 consys_pmic_get_from_dts(struct platform_device *pdev) +{ +#if CONSYS_PMIC_CTRL_ENABLE + reg_VCN18 = regulator_get(&pdev->dev, "vcn18"); + if (!reg_VCN18) + WMT_PLAT_PR_ERR("Regulator_get VCN_1V8 fail\n"); + reg_VCN33_1 = regulator_get(&pdev->dev, "vcn33_1_wifi"); + if (!reg_VCN33_1) + WMT_PLAT_PR_ERR("Regulator_get VCN33_1 fail\n"); + reg_VCN33_2 = regulator_get(&pdev->dev, "vcn33_2_wifi"); + if (!reg_VCN33_2) + WMT_PLAT_PR_ERR("Regulator_get VCN33_2 fail\n"); +#endif + return 0; +} + +static INT32 consys_co_clock_type(VOID) +{ + return 0; +} + +static INT32 consys_clock_buffer_ctrl(MTK_WCN_BOOL enable) +{ + if (enable) + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, true); /*open XO_WCN*/ + else + KERNEL_clk_buf_ctrl(CLK_BUF_CONN, false); /*close XO_WCN*/ + + return 0; +} + +static VOID consys_set_if_pinmux(MTK_WCN_BOOL enable) +{ + UINT8 *consys_if_pinmux_reg_base = NULL; + UINT8 *consys_if_pinmux_driving_base = NULL; + + /* Switch D die pinmux for connecting A die */ + consys_if_pinmux_reg_base = ioremap(CONSYS_IF_PINMUX_REG_BASE, 0x1000); + if (!consys_if_pinmux_reg_base) { + WMT_PLAT_PR_ERR("consys_if_pinmux_reg_base(%x) ioremap fail\n", + CONSYS_IF_PINMUX_REG_BASE); + return; + } + + consys_if_pinmux_driving_base = ioremap(CONSYS_IF_PINMUX_DRIVING_BASE, 0x100); + if (!consys_if_pinmux_driving_base) { + WMT_PLAT_PR_ERR("consys_if_pinmux_driving_base(%x) ioremap fail\n", + CONSYS_IF_PINMUX_DRIVING_BASE); + if (consys_if_pinmux_reg_base) + iounmap(consys_if_pinmux_reg_base); + return; + } + + if (enable) { + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_reg_base + + CONSYS_IF_PINMUX_01_OFFSET) & + CONSYS_IF_PINMUX_01_MASK) | CONSYS_IF_PINMUX_01_VALUE); + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_reg_base + + CONSYS_IF_PINMUX_02_OFFSET) & + CONSYS_IF_PINMUX_02_MASK) | CONSYS_IF_PINMUX_02_VALUE); + /* set pinmux driving to 2mA */ + CONSYS_REG_WRITE(consys_if_pinmux_driving_base + CONSYS_IF_PINMUX_DRIVING_OFFSET, + (CONSYS_REG_READ(consys_if_pinmux_driving_base + + CONSYS_IF_PINMUX_DRIVING_OFFSET) & + CONSYS_IF_PINMUX_DRIVING_MASK) | CONSYS_IF_PINMUX_DRIVING_VALUE); + } else { + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_01_OFFSET, + CONSYS_REG_READ(consys_if_pinmux_reg_base + + CONSYS_IF_PINMUX_01_OFFSET) & CONSYS_IF_PINMUX_01_MASK); + CONSYS_REG_WRITE(consys_if_pinmux_reg_base + CONSYS_IF_PINMUX_02_OFFSET, + CONSYS_REG_READ(consys_if_pinmux_reg_base + + CONSYS_IF_PINMUX_02_OFFSET) & CONSYS_IF_PINMUX_02_MASK); + } + + if (consys_if_pinmux_reg_base) + iounmap(consys_if_pinmux_reg_base); + if (consys_if_pinmux_driving_base) + iounmap(consys_if_pinmux_driving_base); +} + +static VOID consys_hw_reset_bit_set(MTK_WCN_BOOL enable) +{ + UINT32 consys_ver_id = 0; + UINT32 cnt = 0; + + if ((conn_reg.ap_rgu_base == 0) || (conn_reg.mcu_base == 0) || + (conn_reg.mcu_conn_hif_on_base == 0)) + return; + + if (enable) { + /*3.assert CONNSYS CPU SW reset 0x10007018 "[12]=1'b1 [31:24]=8'h88 (key)" */ + CONSYS_REG_WRITE((conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET), + CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) | + CONSYS_CPU_SW_RST_BIT | CONSYS_CPU_SW_RST_CTRL_KEY); + } else { + /*16.deassert CONNSYS CPU SW reset 0x10007018 "[12]=1'b0 [31:24] =8'h88 (key)" */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_CPU_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + 0x600); + while (consys_ver_id != 0x1D1E) { + if (cnt > 10) + break; + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + 0x600); + WMT_PLAT_PR_INFO("0x18002600(0x%x)\n", consys_ver_id); + WMT_PLAT_PR_INFO("0x1800216c(0x%x)\n", + CONSYS_REG_READ(conn_reg.mcu_base + 0x16c)); + WMT_PLAT_PR_INFO("0x18007104(0x%x)\n", + CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base + + CONSYS_CPUPCR_OFFSET)); + msleep(20); + cnt++; + } + } +} + +static VOID consys_hw_spm_clk_gating_enable(VOID) +{ +} + +static INT32 consys_hw_power_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + INT32 iRet = 0; +#else + INT32 value = 0; + INT32 i = 0; +#endif + + if (enable) { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + iRet = clk_prepare_enable(clk_infracfg_ao_ccif4_ap_cg); + if (iRet) { + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_infracfg_ao_ccif4_ap_cg) fail(%d)\n", iRet); + return iRet; + } + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_infracfg_ao_ccif4_ap_cg) ok\n"); + + iRet = clk_prepare_enable(clk_scp_conn_main); + if (iRet) { + WMT_PLAT_PR_ERR("clk_prepare_enable(clk_scp_conn_main) fail(%d)\n", iRet); + return iRet; + } + WMT_PLAT_PR_DBG("clk_prepare_enable(clk_scp_conn_main) ok\n"); + + if (conn_reg.infra_ao_pericfg_base != 0) { + WMT_PLAT_PR_DBG("CON_STA_REG = %x\n", + CONSYS_REG_READ( + conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG)); + + /* Set CON_PWR_ON bit (CON_STA_REG[0]) */ + CONSYS_REG_WRITE_RANGE((conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG), + 1, 1, 0); + + WMT_PLAT_PR_DBG("CON_STA_REG = %x\n", + CONSYS_REG_READ( + conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG)); + } +#else + /* turn on SPM clock gating enable PWRON_CONFG_EN 0x10006000 32'h0b160001 */ + CONSYS_REG_WRITE((conn_reg.spm_base + CONSYS_PWRON_CONFG_EN_OFFSET), + (CONSYS_REG_READ(conn_reg.spm_base + + CONSYS_PWRON_CONFG_EN_OFFSET) & + 0x0000FFFF) | CONSYS_PWRON_CONFG_EN_VALUE); + + /*write assert "conn_top_on" primary part power on, + *set "connsys_on_domain_pwr_on"=1 + */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_BIT); + /*read check "conn_top_on" primary part power status, + *check "connsys_on_domain_pwr_ack"=1 + */ + value = CONSYS_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + while (value == 0) + value = CONSYS_PWR_ON_ACK_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_OFFSET); + /*write assert "conn_top_on" secondary part power on, + *set "connsys_on_domain_pwr_on_s"=1 + */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ON_S_BIT); + /*read check "conn_top_on" secondary part power status, + *check "connsys_on_domain_pwr_ack_s"=1 + */ + value = CONSYS_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + while (value == 0) + value = CONSYS_PWR_ON_ACK_S_BIT & + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_PWR_CONN_ACK_S_OFFSET); + /*write turn on AP-to-CONNSYS bus clock, set "conn_clk_dis"=0 (apply this for bus + *clock toggling) + */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_CLK_CTRL_BIT); + /*wait 1us*/ + udelay(1); + /*de-assert "conn_top_on" isolation, set "connsys_iso_en"=0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~CONSYS_SPM_PWR_ISO_S_BIT); + + /*de-assert CONNSYS S/W reset (TOP RGU CR), set "ap_sw_rst_b"=1 */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + ~CONSYS_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + + /*de-assert CONNSYS S/W reset (SPM CR), set "ap_sw_rst_b"=1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + CONSYS_SPM_PWR_RST_BIT); + + /*wait 0.5ms*/ + udelay(500); + /*Turn off AHB RX bus sleep protect (AP2CONN AHB Bus protect) + *(apply this for INFRA AHB bus accessing when CONNSYS had been turned on) + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHB_RX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHB_RX_PROT_EN_OFFSET) & ~CONSYS_AHB_RX_PROT_MASK); + value = ~CONSYS_AHB_RX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHB_RX_PROT_STA_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_AP2CONN_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHB_RX_PROT_STA_OFFSET); + i++; + } + + /*Turn off AXI Rx bus sleep protect (CONN2AP AXI Rx Bus protect) + *(disable sleep protection when CONNSYS had been turned on) + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AXI_RX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AXI_RX_PROT_EN_OFFSET) & ~CONSYS_AXI_RX_PROT_MASK); + value = ~CONSYS_AXI_RX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_RX_PROT_STA_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_AXI_RX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AXI_RX_PROT_STA_OFFSET); + i++; + } + + /*Turn off AXI TX bus sleep protect (CONN2AP AXI Tx Bus protect) + *(disable sleep protection when CONNSYS had been turned on) + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AXI_RX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AXI_RX_PROT_EN_OFFSET) & ~CONSYS_AXI_TX_PROT_MASK); + value = ~CONSYS_AXI_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_RX_PROT_STA_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_AXI_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AXI_RX_PROT_STA_OFFSET); + i++; + } + + /*Turn off AHB TX bus sleep protect (AP2CONN AHB Bus protect) + *(apply this for INFRA AHB bus accessing when CONNSYS had been turned on) + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AXI_RX_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AXI_RX_PROT_EN_OFFSET) & ~CONSYS_AHB_TX_PROT_MASK); + value = ~CONSYS_AHB_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AXI_RX_PROT_STA_OFFSET); + i = 0; + while (value == 0 || i > 10) { + value = ~CONSYS_AHB_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AXI_RX_PROT_STA_OFFSET); + i++; + } + /*wait 5ms*/ + mdelay(5); +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } else { +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + if (conn_reg.infra_ao_pericfg_base != 0) { + WMT_PLAT_PR_DBG("CON_STA_REG = %x\n", + CONSYS_REG_READ( + conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG)); + + /* Clean CON_STA_REG + * when power off or reset connsys + */ + CONSYS_REG_WRITE((conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG), 0); + + WMT_PLAT_PR_DBG("CON_STA_REG = %x\n", + CONSYS_REG_READ( + conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG)); + } + + clk_disable_unprepare(clk_scp_conn_main); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_scp_conn_main) calling\n"); + + /* Clean CCIF4 ACK status */ + /* Wait 100us to make sure all ongoing tx interrupt could be + * reset. + * According to profiling result, the time between read + * register and send tx interrupt is less than 20 us. + */ + udelay(100); + if (conn_reg.ap_pccif4_base != 0) { + CONSYS_REG_WRITE((conn_reg.ap_pccif4_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PCCIF_ACK_OFFSET), + 0xFF); + WMT_PLAT_PR_DBG("AP_PCCIF_ACK = %x\n", + CONSYS_REG_READ( + conn_reg.ap_pccif4_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PCCIF_ACK_OFFSET)); + } + + clk_disable_unprepare(clk_infracfg_ao_ccif4_ap_cg); + WMT_PLAT_PR_DBG("clk_disable_unprepare(clk_infracfg_ao_ccif4_ap_cg) calling\n"); + +#else + /* Turn on AHB bus sleep protect (AP2CONN AHB Bus protect) + * (apply this for INFRA AXI bus protection to prevent bus hang + * when CONNSYS had been turned off) + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHBAXI_PROT_EN_OFFSET) & + CONSYS_AP2CONN_PROT_MASK); + value = CONSYS_AP2CONN_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i = 0; + while (value == CONSYS_AP2CONN_PROT_MASK || i > 10) { + value = CONSYS_AP2CONN_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHBAXI_PROT_STA_OFFSET); + i++; + } + /* Turn on AXI Tx bus sleep protect (CONN2AP AXI Tx Bus protect) + * (apply this for INFRA AXI bus protection to prevent bus hang + * when CONNSYS had been turned off) + * Note : Should turn on AXI Tx sleep protection first. + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHBAXI_PROT_EN_OFFSET) & + CONSYS_TX_PROT_MASK); + value = CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i = 0; + while (value == CONSYS_TX_PROT_MASK || i > 10) { + value = CONSYS_TX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHBAXI_PROT_STA_OFFSET); + i++; + } + /* Turn on AXI Rx bus sleep protect (CONN2AP AXI RX Bus protect) + * (apply this for INFRA AXI bus protection to prevent bus hang + * when CONNSYS had been turned off) + * Note : Should turn on AXI Rx sleep protection + * after AXI Tx sleep protection has been turn on. + */ + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHBAXI_PROT_EN_OFFSET) & + CONSYS_RX_PROT_MASK); + value = CONSYS_RX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AHBAXI_PROT_STA_OFFSET); + i = 0; + while (value == CONSYS_RX_PROT_MASK || i > 10) { + value = CONSYS_RX_PROT_MASK & + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AHBAXI_PROT_STA_OFFSET); + i++; + } + + /*assert "conn_top_on" isolation, set "connsys_iso_en"=1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_SPM_PWR_ISO_S_BIT); + /*assert CONNSYS S/W reset (TOP RGU CR), set "ap_sw_rst_b"=0 */ + CONSYS_REG_WRITE(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET, + (CONSYS_REG_READ(conn_reg.ap_rgu_base + CONSYS_CPU_SW_RST_OFFSET) & + CONSYS_SW_RST_BIT) | CONSYS_CPU_SW_RST_CTRL_KEY); + /*assert CONNSYS S/W reset (SPM CR), set "ap_sw_rst_b"=0 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + ~CONSYS_SPM_PWR_RST_BIT); + /*write conn_clk_dis=1, disable connsys clock 0x1000632C [4] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) | + CONSYS_CLK_CTRL_BIT); + /*wait 1us */ + udelay(1); + /*write conn_top1_pwr_on=0, power off conn_top1 0x1000632C [3:2] 2'b00 */ + CONSYS_REG_WRITE(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET, + CONSYS_REG_READ(conn_reg.spm_base + CONSYS_TOP1_PWR_CTRL_OFFSET) & + ~(CONSYS_SPM_PWR_ON_BIT | CONSYS_SPM_PWR_ON_S_BIT)); +#endif /* CONSYS_PWR_ON_OFF_API_AVAILABLE */ + } + +#if CONSYS_PWR_ON_OFF_API_AVAILABLE + return iRet; +#else + return 0; +#endif +} + +static INT32 consys_ahb_clock_ctrl(MTK_WCN_BOOL enable) +{ + return 0; +} + +static INT32 polling_consys_chipid(VOID) +{ + UINT32 retry = 10; + UINT32 consys_ver_id = 0; + UINT32 consys_hw_ver = 0; + UINT32 consys_fw_ver = 0; + UINT8 *consys_reg_base = NULL; + UINT32 value = 0; + + if ((conn_reg.mcu_top_misc_off_base == 0) || (conn_reg.mcu_base == 0) || + (conn_reg.mcu_conn_hif_pdma_base == 0)) + return 0; + + /*12.poll CONNSYS CHIP ID until chipid is returned */ + while (retry-- > 0) { + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_top_misc_off_base + + CONSYS_IP_VER_OFFSET); + if (consys_ver_id == CONSYS_IP_VER_ID) { + WMT_PLAT_PR_INFO("retry(%d)consys version id(0x%08x)\n", + retry, consys_ver_id); + consys_hw_ver = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys HW version id(0x%x)\n", consys_hw_ver & 0xFFFF); + consys_fw_ver = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_FW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys FW version id(0x%x)\n", consys_fw_ver & 0xFFFF); + + consys_dl_rom_patch(consys_ver_id, consys_fw_ver); + break; + } + WMT_PLAT_PR_ERR("Read CONSYS version id(0x%08x)", consys_ver_id); + msleep(20); + } + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_top_misc_off_base + CONSYS_CONF_ID_OFFSET); + WMT_PLAT_PR_INFO("consys configuration id(0x%x)\n", consys_ver_id & 0xF); + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys HW version id(0x%x)\n", consys_ver_id & 0xFFFF); + consys_ver_id = CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_FW_ID_OFFSET); + WMT_PLAT_PR_INFO("consys FW version id(0x%x)\n", consys_ver_id & 0xFFFF); + + if (wmt_plat_soc_co_clock_flag_get()) { + consys_reg_base = ioremap(CONSYS_COCLOCK_STABLE_TIME_BASE, 0x100); + if (consys_reg_base) { + /** + * 1. set CR "vcore ready stable time" "XO initial stable time" and + * "XO bg stable time" to optimize the wakeup time after sleep + * 2. clear "source clock enable ack to XO state" mask + */ + value = CONSYS_REG_READ(consys_reg_base); + value = (value & CONSYS_COCLOCK_STABLE_TIME_MASK) | + CONSYS_COCLOCK_STABLE_TIME; + CONSYS_REG_WRITE(consys_reg_base, value); + value = CONSYS_REG_READ(consys_reg_base + CONSYS_COCLOCK_ACK_ENABLE_OFFSET); + value = (value & 0xffff00fe) | 0x600; + CONSYS_REG_WRITE(consys_reg_base + CONSYS_COCLOCK_ACK_ENABLE_OFFSET, value); + iounmap(consys_reg_base); + } else + WMT_PLAT_PR_ERR("connsys co_clock stable time base(0x%x) ioremap fail!\n", + CONSYS_COCLOCK_STABLE_TIME_BASE); + } + + /* CONN2EMI HW slpprot control enable: 0x18004160[4] 1'b1 */ + CONSYS_REG_WRITE(conn_reg.mcu_conn_hif_pdma_base + CONSYS_SLPPROT_CONTROL_OFFSET, + (CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + + CONSYS_SLPPROT_CONTROL_OFFSET) & + CONSYS_SLPPROT_CONTROL_MASK) | CONSYS_SLPPROT_CONTROL_VALUE); + + /* toppose_restore_done rollback */ + consys_reg_base = ioremap(CONSYS_TOPPOSE_RESTORE_ADDRESS, 0x100); + if (consys_reg_base) { + CONSYS_REG_WRITE(consys_reg_base, + (CONSYS_REG_READ(consys_reg_base) & + CONSYS_TOPPOSE_RESTORE_MASK) | CONSYS_TOPPOSE_RESTORE_VALUE); + iounmap(consys_reg_base); + } + + /* update WPLL setting for WPLL issue@LT */ + consys_reg_base = ioremap(CONSYS_WPLL_SETTING_ADDRESS, 0x100); + if (consys_reg_base) { + CONSYS_REG_WRITE(consys_reg_base, + (CONSYS_REG_READ(consys_reg_base) & + CONSYS_WPLL_SETTING_MASK) | CONSYS_WPLL_SETTING_VALUE); + iounmap(consys_reg_base); + } + + return 0; +} + +static VOID consys_acr_reg_setting(VOID) +{ + WMT_PLAT_PR_INFO("No need to do acr"); +} + +static VOID consys_afe_reg_setting(VOID) +{ + WMT_PLAT_PR_INFO("No need to do afe"); +} + +static INT32 consys_hw_vcn18_ctrl(MTK_WCN_BOOL enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) { + /*Set VCN18_SW_OP_EN as 1*/ + KERNEL_pmic_ldo_vcn18_lp(SW, 1, 1, SW_OFF); + /*Set VCN18_SW_EN as 1 and set votage as 1V8*/ + if (reg_VCN18) { + regulator_set_voltage(reg_VCN18, 1800000, 1800000); + if (regulator_enable(reg_VCN18)) + WMT_PLAT_PR_ERR("enable VCN18 fail\n"); + else + WMT_PLAT_PR_DBG("enable VCN18 ok\n"); + } + /*Set VCN18 SW_LP as 0*/ + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN18_LP, 0); + /*Set VCN18 as low-power mode(1), HW0_OP_EN as 1, HW0_OP_CFG as HW_LP(1)*/ + KERNEL_pmic_ldo_vcn18_lp(SRCLKEN0, 1, 1, HW_LP); + + /*1.AP power on VCN_3V3 LDO (with PMIC_WRAP API) VCN_3V3 */ + /*default vcn33_1 SW mode*/ + if (reg_VCN33_1) { + regulator_set_voltage(reg_VCN33_1, 3300000, 3300000); + if (regulator_enable(reg_VCN33_1)) + WMT_PLAT_PR_ERR("WMT do VCN33_1 PMIC on fail!\n"); + } + + } else { + if (reg_VCN33_1) + regulator_disable(reg_VCN33_1); + /* delay 300us */ + udelay(300); + /*AP power off MT6359 VCN_1V8 LDO */ + if (reg_VCN18) { + if (regulator_disable(reg_VCN18)) + WMT_PLAT_PR_ERR("disable VCN_1V8 fail!\n"); + else + WMT_PLAT_PR_DBG("disable VCN_1V8 ok\n"); + } + } +#endif + return 0; +} + +static VOID consys_vcn28_hw_mode_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + if (enable) + /*Set VCN33_2_SW_OP_EN as 1*/ + KERNEL_pmic_ldo_vcn33_2_lp(SW, 1, 1, SW_OFF); + else + /*Set VCN33_2 as low-power mode(1), HW0_OP_EN as 0, HW0_OP_CFG as HW_OFF(0)*/ + KERNEL_pmic_ldo_vcn33_2_lp(SRCLKEN0, 1, 0, HW_OFF); +#endif +} + +static INT32 consys_hw_vcn28_ctrl(UINT32 enable) +{ +#if CONSYS_PMIC_CTRL_ENABLE + INT32 result; + + if (enable) { + /*in co-clock mode,need to turn on vcn33_2 when fm on */ + /*Set VCN33_2_SW_OP_EN as 1*/ + KERNEL_pmic_ldo_vcn33_2_lp(SW, 1, 1, SW_OFF); + /*Set VCN33_2_SW_EN as 1 and set votage as 2V8*/ + if (reg_VCN33_2) { + regulator_set_voltage(reg_VCN33_2, 2800000, 2800000); + result = regulator_enable(reg_VCN33_2); + } + /*Set VCN33_2 SW_LP as 0*/ + KERNEL_pmic_set_register_value(PMIC_RG_LDO_VCN33_2_LP, 0); + /*Set VCN33_2 as low-power mode(1), HW0_OP_EN as 1, HW0_OP_CFG as HW_OFF(0)*/ + KERNEL_pmic_ldo_vcn33_2_lp(SRCLKEN0, 1, 1, HW_OFF); + WMT_PLAT_PR_INFO("turn on vcn33_2 for fm/gps usage in co-clock mode\n"); + } else { + /*in co-clock mode,need to turn off vcn33_2 when fm off */ + /*Set VCN33_2 as low-power mode(1), HW0_OP_EN as 0, HW0_OP_CFG as HW_OFF(0)*/ + KERNEL_pmic_ldo_vcn33_2_lp(SRCLKEN0, 1, 0, HW_OFF); + if (reg_VCN33_2) + regulator_disable(reg_VCN33_2); + WMT_PLAT_PR_INFO("turn off vcn33_2 for fm/gps usage in co-clock mode\n"); + } +#endif + return 0; +} + +static INT32 consys_hw_bt_vcn33_ctrl(UINT32 enable) +{ + return 0; +} + +static INT32 consys_hw_wifi_vcn33_ctrl(UINT32 enable) +{ + return 0; +} + +static INT32 consys_emi_mpu_set_region_protection(VOID) +{ +#ifdef CONFIG_MTK_EMI + struct emi_region_info_t region_info; + + /*set MPU for EMI share Memory */ + WMT_PLAT_PR_INFO("setting MPU for EMI share memory\n"); + + region_info.start = gConEmiPhyBase; + region_info.end = gConEmiPhyBase + gConEmiSize - 1; + region_info.region = 27; + SET_ACCESS_PERMISSION(region_info.apc, LOCK, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + NO_PROTECTION, FORBIDDEN, NO_PROTECTION); + emi_mpu_set_protection(®ion_info); +#endif + return 0; +} + +static UINT32 consys_emi_set_remapping_reg(VOID) +{ + /* For direct path */ + phys_addr_t mdPhy = 0; + INT32 size = 0; + + mtk_wcn_emi_addr_info.emi_ap_phy_addr = gConEmiPhyBase; + mtk_wcn_emi_addr_info.emi_size = gConEmiSize; + + if (conn_reg.topckgen_base == 0) + return 0; + + /*EMI Registers remapping*/ + CONSYS_REG_WRITE_OFFSET_RANGE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, + gConEmiPhyBase, 0, 16, 20); + WMT_PLAT_PR_INFO("CONSYS_EMI_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); + + /*Perisys Configuration Registers remapping*/ + CONSYS_REG_WRITE_OFFSET_RANGE(conn_reg.topckgen_base + CONSYS_EMI_PERI_MAPPING_OFFSET, + 0x10003000, 0, 16, 20); + WMT_PLAT_PR_INFO("PERISYS_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_PERI_MAPPING_OFFSET)); + + /*Modem Configuration Registers remapping*/ + mdPhy = get_smem_phy_start_addr(MD_SYS1, SMEM_USER_RAW_MD_CONSYS, &size); + if (size == 0) + WMT_PLAT_PR_INFO("MD direct path is not supported\n"); + else { + CONSYS_REG_WRITE_OFFSET_RANGE( + conn_reg.topckgen_base + CONSYS_EMI_AP_MD_OFFSET, + mdPhy, 0, 16, 20); + WMT_PLAT_PR_INFO("MD_MAPPING dump in restore cb(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_AP_MD_OFFSET)); + } + mtk_wcn_emi_addr_info.emi_direct_path_ap_phy_addr = mdPhy; + mtk_wcn_emi_addr_info.emi_direct_path_size = size; + + mtk_wcn_emi_addr_info.emi_ram_bt_buildtime_offset = + CONSYS_EMI_RAM_BT_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_ram_wifi_buildtime_offset = + CONSYS_EMI_RAM_WIFI_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_ram_mcu_buildtime_offset = + CONSYS_EMI_RAM_MCU_BUILDTIME_OFFSET; + mtk_wcn_emi_addr_info.emi_patch_mcu_buildtime_offset = + CONSYS_EMI_PATCH_MCU_BUILDTIME_OFFSET; + + return 0; +} + +static INT32 bt_wifi_share_v33_spin_lock_init(VOID) +{ + return 0; +} + +static INT32 consys_read_irq_info_from_dts(struct platform_device *pdev, PINT32 irq_num, + PUINT32 irq_flag) +{ + struct device_node *node; + + node = pdev->dev.of_node; + if (node) { + *irq_num = irq_of_parse_and_map(node, 0); + *irq_flag = irq_get_trigger_type(*irq_num); + WMT_PLAT_PR_INFO("get irq id(%d) and irq trigger flag(%d) from DT\n", *irq_num, + *irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return -1; + } + + return 0; +} + +static INT32 consys_read_reg_from_dts(struct platform_device *pdev) +{ + INT32 iRet = -1; + struct device_node *node = NULL; + + node = pdev->dev.of_node; + if (node) { + /* registers base address */ + conn_reg.mcu_base = (SIZE_T) of_iomap(node, MCU_BASE_INDEX); + conn_reg.ap_rgu_base = (SIZE_T) of_iomap(node, TOP_RGU_BASE_INDEX); + conn_reg.topckgen_base = (SIZE_T) of_iomap(node, INFRACFG_AO_BASE_INDEX); + conn_reg.spm_base = (SIZE_T) of_iomap(node, SPM_BASE_INDEX); + conn_reg.mcu_conn_hif_on_base = (SIZE_T) of_iomap(node, MCU_CONN_HIF_ON_BASE_INDEX); + conn_reg.mcu_top_misc_off_base = (SIZE_T) of_iomap(node, + MCU_TOP_MISC_OFF_BASE_INDEX); + conn_reg.mcu_cfg_on_base = (SIZE_T) of_iomap(node, MCU_CFG_ON_BASE_INDEX); + conn_reg.mcu_cirq_base = (SIZE_T) of_iomap(node, MCU_CIRQ_BASE_INDEX); + conn_reg.mcu_top_misc_on_base = (SIZE_T) of_iomap(node, MCU_TOP_MISC_ON_BASE_INDEX); + conn_reg.mcu_conn_hif_pdma_base = (SIZE_T) of_iomap(node, + MCU_CONN_HIF_PDMA_BASE_INDEX); + conn_reg.ap_pccif4_base = (SIZE_T) of_iomap(node, AP_PCCIF4_BASE_INDEX); + conn_reg.infra_ao_pericfg_base = (SIZE_T) of_iomap(node, + INFRA_AO_PERICFG_BASE_INDEX); + + WMT_PLAT_PR_DBG("Get base mcu(0x%zx), rgu(0x%zx), topckgen(0x%zx), spm(0x%zx)\n", + conn_reg.mcu_base, conn_reg.ap_rgu_base, + conn_reg.topckgen_base, conn_reg.spm_base); + WMT_PLAT_PR_DBG("Get base hif_on(0x%zx), misc_off(0x%zx), cfg_on(0x%zx)\n", + conn_reg.mcu_top_misc_off_base, + conn_reg.mcu_conn_hif_on_base, + conn_reg.mcu_cfg_on_base); + WMT_PLAT_PR_DBG("Get base cirq(0x%zx), top_misc_on(0x%zx), hif_pdma(0x%zx)\n", + conn_reg.mcu_top_misc_on_base, + conn_reg.mcu_cirq_base, + conn_reg.mcu_conn_hif_pdma_base); + WMT_PLAT_PR_DBG("Get base ap_pccif4(0x%zx), infra_ao_pericfg(0x%zx)\n", + conn_reg.ap_pccif4_base, + conn_reg.infra_ao_pericfg_base); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iRet; + } + + return 0; +} + +static VOID force_trigger_assert_debug_pin(VOID) +{ + UINT32 value = 0; + + if (conn_reg.infra_ao_pericfg_base != 0) { + WMT_PLAT_PR_DBG("CON_STA_REG = %x\n", + CONSYS_REG_READ( + conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG)); + + /* clear CON_PWR_ON & CON_SW_READY bit (CON_STA_REG[0], CON_STA_REG[1]) */ + value = CONSYS_REG_READ(conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG); + value = value & (~INFRASYS_COMMON_AP2MD_CON_PWR_ON_CON_SW_READY_MASK); + CONSYS_REG_WRITE(conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG, + value); + + WMT_PLAT_PR_DBG("CON_STA_REG = %x\n", + CONSYS_REG_READ( + conn_reg.infra_ao_pericfg_base + + INFRASYS_COMMON_AP2MD_PCCIF4_AP_PERI_AP_CCU_CONFIG)); + } + + if (conn_reg.topckgen_base == 0) + return; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) & ~CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("enable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); + usleep_range(64, 96); + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + + CONSYS_AP2CONN_OSC_EN_OFFSET) | CONSYS_AP2CONN_WAKEUP_BIT); + WMT_PLAT_PR_INFO("disable:dump CONSYS_AP2CONN_OSC_EN_REG(0x%x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_AP2CONN_OSC_EN_OFFSET)); +} + +static UINT32 consys_read_cpupcr(VOID) +{ + if (conn_reg.mcu_conn_hif_on_base == 0) + return 0; + + return CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base + CONSYS_CPUPCR_OFFSET); +} + +static UINT32 consys_soc_chipid_get(VOID) +{ + return PLATFORM_SOC_CHIP; +} + +static P_CONSYS_EMI_ADDR_INFO consys_soc_get_emi_phy_add(VOID) +{ + return &mtk_wcn_emi_addr_info; +} + +P_WMT_CONSYS_IC_OPS mtk_wcn_get_consys_ic_ops(VOID) +{ + return &consys_ic_ops; +} + +static INT32 consys_dl_rom_patch(UINT32 ip_ver, UINT32 fw_ver) +{ + if (rom_patch_dl_flag) { + if (mtk_wcn_soc_rom_patch_dwn(ip_ver, fw_ver) == 0) + rom_patch_dl_flag = 1; + } + + return 0; +} + +static VOID consys_set_dl_rom_patch_flag(INT32 flag) +{ + rom_patch_dl_flag = flag; +} + +static INT32 consys_dedicated_log_path_init(struct platform_device *pdev) +{ + struct device_node *node; + UINT32 irq_num; + UINT32 irq_flag; + INT32 iret = -1; + + node = pdev->dev.of_node; + if (node) { + irq_num = irq_of_parse_and_map(node, 2); + irq_flag = irq_get_trigger_type(irq_num); + WMT_PLAT_PR_INFO("get conn2ap_sw_irq id(%d) and irq trigger flag(%d) from DT\n", + irq_num, irq_flag); + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return iret; + } + + connsys_dedicated_log_path_apsoc_init(gConEmiPhyBase, irq_num, irq_flag); +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + fw_log_wmt_init(); +#endif + return 0; +} + +static VOID consys_dedicated_log_path_deinit(VOID) +{ +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + fw_log_wmt_deinit(); +#endif + connsys_dedicated_log_path_apsoc_deinit(); +} + +static INT32 consys_check_reg_readable(VOID) +{ + INT32 flag = 0; + UINT32 value = 0; + P_DEV_WMT pDev = &gDevWmt; + + if (conn_reg.mcu_conn_hif_on_base == 0) + return flag; + + if ((wmt_lib_get_drv_status(WMTDRV_TYPE_WMT) == DRV_STS_FUNC_ON) + && (osal_test_bit(WMT_STAT_PWR, &pDev->state))) { + /*check connsys clock and sleep status*/ + CONSYS_REG_WRITE(conn_reg.mcu_conn_hif_on_base, CONSYS_CLOCK_CHECK_VALUE); + udelay(1000); + value = CONSYS_REG_READ(conn_reg.mcu_conn_hif_on_base); + if ((value & CONSYS_HCLK_CHECK_BIT) && + (value & CONSYS_OSCCLK_CHECK_BIT) && + ((value & CONSYS_SLEEP_CHECK_BIT) == 0)) + flag = 1; + } + + if (!flag) { + KERNEL_clk_buf_show_status_info(); + WMT_PLAT_PR_ERR("connsys clock check fail 0x18007000(0x%x)\n", value); + } + + return flag; +} + +static INT32 consys_emi_coredump_remapping(UINT8 __iomem **addr, UINT32 enable) +{ + if (enable) { + *addr = ioremap(gConEmiPhyBase + CONSYS_EMI_COREDUMP_OFFSET, + CONSYS_EMI_MEM_SIZE); + if (*addr) { + WMT_PLAT_PR_INFO("COREDUMP EMI mapping OK virtual(0x%p) physical(0x%x)\n", + *addr, (UINT32) gConEmiPhyBase + + CONSYS_EMI_COREDUMP_OFFSET); + memset_io(*addr, 0, CONSYS_EMI_MEM_SIZE); + } else { + WMT_PLAT_PR_ERR("EMI mapping fail\n"); + return -1; + } + } else { + if (*addr) { + iounmap(*addr); + *addr = NULL; + } + } + return 0; +} + +static INT32 consys_reset_emi_coredump(UINT8 __iomem *addr) +{ + if (!addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + WMT_PLAT_PR_INFO("Reset EMI(0xF0068000 ~ 0xF0068400) and (0xF0070400 ~ 0xF0078400)\n"); + /* reset 0xF0068000 ~ 0xF0068400 (1K) */ + memset_io(addr, 0, 0x400); + /* reset 0xF0070400 ~ 0xF0078400 (32K) */ + memset_io(addr + CONSYS_EMI_PAGED_DUMP_OFFSET, 0, 0x8000); + return 0; +} + +static INT32 consys_is_connsys_reg(UINT32 addr) +{ + if (addr > 0x18000000 && addr < 0x180FFFFF) { + if (addr >= 0x18007000 && addr <= 0x18007FFF) + return 0; + + return 1; + } + + return 0; +} + +static VOID consys_ic_clock_fail_dump(VOID) +{ + UINT8 *addr; + char *buffer, *temp; + INT32 size = 1024; + + if (conn_reg.mcu_base == 0) + return; + + /* make sure buffer size is big enough */ + buffer = osal_malloc(size); + if (!buffer) + return; + + temp = buffer; + temp += sprintf(temp, "CONN_HIF_TOP_MISC=0x%08x CONN_HIF_BUSY_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_TOP_MISC), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_BUSY_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_HIF_DBG_IDX, 0x3333); + temp += sprintf(temp, "Write CONSYS_HIF_DBG_IDX to 0x3333\n"); + + temp += sprintf(temp, "CONSYS_HIF_DBG_PROBE=0x%08x CONN_HIF_TOP_MISC=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_DBG_PROBE), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_TOP_MISC)); + + temp += sprintf(temp, "CONN_HIF_BUSY_STATUS=0x%08x CONN_HIF_PDMA_BUSY_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_BUSY_STATUS), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_PDMA_BUSY_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_HIF_DBG_IDX, 0x2222); + temp += sprintf(temp, "Write CONSYS_HIF_DBG_IDX to 0x2222\n"); + + temp += sprintf(temp, "CONSYS_HIF_DBG_PROBE=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_DBG_PROBE)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_HIF_DBG_IDX, 0x3333); + temp += sprintf(temp, "Write CONSYS_HIF_DBG_IDX to 0x3333\n"); + + temp += sprintf(temp, "CONSYS_HIF_DBG_PROBE=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_DBG_PROBE)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_HIF_DBG_IDX, 0x4444); + temp += sprintf(temp, "Write CONSYS_HIF_DBG_IDX to 0x4444\n"); + + temp += sprintf(temp, "CONSYS_HIF_DBG_PROBE=0x%08x CONN_MCU_EMI_CONTROL=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_HIF_DBG_PROBE), + CONSYS_REG_READ(conn_reg.mcu_base + CONN_MCU_EMI_CONTROL)); + temp += sprintf(temp, "EMI_CONTROL_DBG_PROBE=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + EMI_CONTROL_DBG_PROBE)); + temp += sprintf(temp, "CONN_MCU_CLOCK_CONTROL=0x%08x CONN_MCU_BUS_CONTROL=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_CLOCK_CONTROL), + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_BUS_CONTROL)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x003e3d00); + temp += sprintf(temp, "Write CONSYS_DEBUG_SELECT to 0x003e3d00\n"); + + temp += sprintf(temp, "CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x00403f00); + temp += sprintf(temp, "Write CONSYS_DEBUG_SELECT to 0x00403f00\n"); + + temp += sprintf(temp, "CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x00424100); + temp += sprintf(temp, "Write CONSYS_DEBUG_SELECT to 0x00424100\n"); + + temp += sprintf(temp, "CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + + CONSYS_REG_WRITE(conn_reg.mcu_base + CONSYS_DEBUG_SELECT, 0x00444300); + temp += sprintf(temp, "Write CONSYS_DEBUG_SELECT to 0x00444300\n"); + + temp += sprintf(temp, "CONN_MCU_DEBUG_STATUS=0x%08x\n", + CONSYS_REG_READ(conn_reg.mcu_base + CONSYS_DEBUG_STATUS)); + WMT_PLAT_PR_ERR("%s length = %d", buffer, osal_strlen(buffer)); + + temp = buffer; + addr = ioremap(0x180bc000, 0x100); + /* conn2ap axi master sleep prot info */ + temp += sprintf(temp, "0x180bc010=0x%08x\n", CONSYS_REG_READ(addr + 0x10)); + /* conn_mcu2ap axi master sleep prot info */ + temp += sprintf(temp, "0x180bc014=0x%08x\n", CONSYS_REG_READ(addr + 0x14)); + /* conn2ap axi gals bus info */ + temp += sprintf(temp, "0x180bc018=0x%08x\n", CONSYS_REG_READ(addr + 0x18)); + /* conn2ap mux4to1 debug info */ + temp += sprintf(temp, "0x180bc01c=0x%08x\n", CONSYS_REG_READ(addr + 0x1c)); + /* conn_hif_off bus busy info */ + temp += sprintf(temp, "0x180bc020=0x%08x\n", CONSYS_REG_READ(addr + 0x20)); + iounmap(addr); + + addr = ioremap(0x10001B20, 0x100); + /* 0x1020E804 */ + temp += sprintf(temp, "0x10001B20=0x%08x\n", CONSYS_REG_READ(addr)); + + addr = ioremap(0x1800713c, 0x100); + /* conn_hif_on misc info */ + temp += sprintf(temp, "0x1800713c=0x%08x\n", CONSYS_REG_READ(addr)); + iounmap(addr); + + addr = ioremap(0x180c1144, 0x100); + /* conn_on_host debug flag */ + temp += sprintf(temp, "0x180c1144=0x%08x\n", CONSYS_REG_READ(addr)); + iounmap(addr); + + addr = ioremap(0x1020E804, 0x100); + /* 0x1020E804 */ + temp += sprintf(temp, "0x1020E804=0x%08x\n", CONSYS_REG_READ(addr)); + iounmap(addr); + + WMT_PLAT_PR_ERR("%s length = %d", buffer, osal_strlen(buffer)); + osal_free(buffer); +} + +static PUINT32 consys_resume_dump_info(VOID) +{ + if (conn_reg.mcu_cfg_on_base != 0 && + conn_reg.mcu_top_misc_on_base != 0 && + mtk_consys_check_reg_readable()) { + stp_dbg_clear_cpupcr_reg_info(); + stp_dbg_poll_cpupcr(5, 0, 1); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR, 0x1); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_MON_CTL_ADDR, 0x80000001); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_MON_SEL0_ADDR, 0x03020100); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_MON_SEL1_ADDR, 0x07060504); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_MON_SEL2_ADDR, 0x0b0a0908); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_MON_SEL3_ADDR, 0x0f0e0d0c); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_DBGSEL_ADDR, 0x3); + g_connsys_lp_dump_info[0] = (UINT32)CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_MAPPING_AP_ADDR; + g_connsys_lp_dump_info[1] = CONSYS_REG_READ(CONN_CFG_ON_CONN_ON_MON_FLAG_RECORD_ADDR); + WMT_PLAT_PR_INFO("0x%08x: 0x%x\n", g_connsys_lp_dump_info[0], g_connsys_lp_dump_info[1]); + CONSYS_REG_WRITE(CONN_CFG_ON_CONN_ON_HOST_MAILBOX_MCU_ADDR, 0x0); + return &g_connsys_lp_dump_info[0]; + } + return NULL; +} + +static VOID consys_set_pdma_axi_rready_force_high(UINT32 enable) +{ + if (conn_reg.mcu_conn_hif_pdma_base == 0) + return; + + if (enable) + CONSYS_SET_BIT(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_PDMA_AXI_RREADY, + CONSYS_PDMA_AXI_RREADY_MASK); + else if ((CONSYS_REG_READ(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_PDMA_AXI_RREADY) & + CONSYS_PDMA_AXI_RREADY_MASK) != 0) + CONSYS_CLR_BIT(conn_reg.mcu_conn_hif_pdma_base + CONSYS_HIF_PDMA_AXI_RREADY, + CONSYS_PDMA_AXI_RREADY_MASK); +} + +static VOID consys_set_mcif_emi_mpu_protection(MTK_WCN_BOOL enable) +{ + WMT_PLAT_PR_INFO("No need setup region 23 for this project.\n"); +} + +static INT32 consys_calibration_backup_restore_support(VOID) +{ + return 1; +} + +#if WMT_DEVAPC_DBG_SUPPORT +static VOID consys_devapc_violation_cb(VOID) +{ + /** + * Don't use wmt_lib_trigger_assert() because it will invoke vmalloc and then cause KE since + * this callback is supposed to be invoked in DEVAPC exception hanlder. + */ + wmt_lib_trigger_assert_keyword_delay(WMTDRV_TYPE_WMT, 46, "DEVAPC Violation"); +} +#endif + +static VOID consyc_register_devapc_cb(VOID) +{ +#if WMT_DEVAPC_DBG_SUPPORT + register_devapc_vio_callback(&devapc_handle); +#endif +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mtk_wcn_cmb_hw.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mtk_wcn_cmb_hw.c new file mode 100644 index 00000000000000..b2fd526e632f1d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mtk_wcn_cmb_hw.c @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CMB-HW]" + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +#include "wmt_plat.h" +#include "wmt_lib.h" +#include "mtk_wcn_cmb_hw.h" +#include "osal_typedef.h" + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +#define DFT_RTC_STABLE_TIME 100 +#define DFT_LDO_STABLE_TIME 100 +#define DFT_RST_STABLE_TIME 30 +#define DFT_OFF_STABLE_TIME 10 +#define DFT_ON_STABLE_TIME 30 + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +PWR_SEQ_TIME gPwrSeqTime; + + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +INT32 mtk_wcn_cmb_hw_pwr_off(VOID) +{ + INT32 iRet = 0; + UINT32 chip_id = 0x0; + + WMT_DBG_FUNC("CMB-HW, hw_pwr_off start\n"); + + /*1. disable irq --> should be done when do wmt-ic swDeinit period */ + /* TODO:[FixMe][GeorgeKuo] clarify this */ + + /*2. set bgf eint/all eint to deinit state, namely input low state */ + chip_id = mtk_wcn_wmt_chipid_query(); + if (!((chip_id == 0x6630 || chip_id == 0x6632) + && (wmt_plat_get_comm_if_type() == STP_SDIO_IF_TX))) { + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); + WMT_INFO_FUNC("CMB-HW, BGF_EINT IRQ unregistered and disabled\n"); + iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_DEINIT); + } + /* 2.1 set ALL_EINT pin to correct state even it is not used currently */ + iRet += wmt_plat_eirq_ctrl(PIN_ALL_EINT, PIN_STA_DEINIT); + WMT_DBG_FUNC("CMB-HW, ALL_EINT IRQ unregistered and disabled\n"); + iRet += wmt_plat_gpio_ctrl(PIN_ALL_EINT, PIN_STA_DEINIT); + /* 2.2 deinit gps sync */ + iRet += wmt_plat_gpio_ctrl(PIN_GPS_SYNC, PIN_STA_DEINIT); + + /*3. set audio interface to CMB_STUB_AIF_0, BT PCM OFF, I2S OFF */ + iRet += wmt_plat_audio_ctrl(CMB_STUB_AIF_0, CMB_STUB_AIF_CTRL_DIS); + + /*4. set control gpio into deinit state, namely input low state */ + iRet += wmt_plat_gpio_ctrl(PIN_SDIO_GRP, PIN_STA_DEINIT); + if (chip_id != 0x6632) + iRet += wmt_plat_gpio_ctrl(PIN_RST, PIN_STA_OUT_L); + iRet += wmt_plat_gpio_ctrl(PIN_PMU, PIN_STA_OUT_L); + + /*5. set uart tx/rx into deinit state, namely input low state */ + iRet += wmt_plat_gpio_ctrl(PIN_UART_GRP, PIN_STA_DEINIT); + + /* 6. Last, LDO output low */ + iRet += wmt_plat_gpio_ctrl(PIN_LDO, PIN_STA_OUT_L); + + /*7. deinit gps_lna */ + iRet += wmt_plat_gpio_ctrl(PIN_GPS_LNA, PIN_STA_DEINIT); + + WMT_DBG_FUNC("CMB-HW, hw_pwr_off finish\n"); + return iRet; +} + +INT32 mtk_wcn_cmb_hw_pwr_on(VOID) +{ + static UINT32 _pwr_first_time = 1; + INT32 iRet = 0; + UINT32 chip_id = 0x0; + + WMT_DBG_FUNC("CMB-HW, hw_pwr_on start\n"); + + /* disable interrupt firstly */ + chip_id = mtk_wcn_wmt_chipid_query(); + if (!((chip_id == 0x6630 || chip_id == 0x6632) + && (wmt_plat_get_comm_if_type() == STP_SDIO_IF_TX))) + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); + iRet += wmt_plat_eirq_ctrl(PIN_ALL_EINT, PIN_STA_EINT_DIS); + + /*set all control and eint gpio to init state, namely input low mode */ + iRet += wmt_plat_gpio_ctrl(PIN_LDO, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_PMU, PIN_STA_INIT); + if (chip_id != 0x6632) + iRet += wmt_plat_gpio_ctrl(PIN_RST, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_SDIO_GRP, PIN_STA_INIT); + if (!((chip_id == 0X6630 || chip_id == 0X6632) + && (wmt_plat_get_comm_if_type() == STP_SDIO_IF_TX))) + iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_ALL_EINT, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_GPS_SYNC, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_GPS_LNA, PIN_STA_INIT); + /* wmt_plat_gpio_ctrl(PIN_WIFI_EINT, PIN_STA_INIT); *//* WIFI_EINT is controlled by SDIO host driver */ + /* TODO: [FixMe][George]:WIFI_EINT is used in common SDIO */ + + /*1. pull high LDO to supply power to chip */ + iRet += wmt_plat_gpio_ctrl(PIN_LDO, PIN_STA_OUT_H); + osal_sleep_ms(gPwrSeqTime.ldoStableTime); + + /* 2. export RTC clock to chip */ + if (_pwr_first_time) { + /* rtc clock should be output all the time, so no need to enable output again */ + iRet += wmt_plat_gpio_ctrl(PIN_RTC, PIN_STA_INIT); + osal_sleep_ms(gPwrSeqTime.rtcStableTime); + WMT_INFO_FUNC("CMB-HW, rtc clock exported\n"); + } + + /*3. set UART Tx/Rx to UART mode */ + iRet += wmt_plat_gpio_ctrl(PIN_UART_GRP, PIN_STA_INIT); + + if (0x6630 == chip_id || 0x6632 == chip_id) { + switch (wmt_plat_get_comm_if_type()) { + case STP_UART_IF_TX: + iRet += wmt_plat_gpio_ctrl(PIN_UART_RX, PIN_STA_OUT_H); + break; + case STP_SDIO_IF_TX: + iRet += wmt_plat_gpio_ctrl(PIN_UART_RX, PIN_STA_OUT_L); + break; + default: + WMT_ERR_FUNC("not supported common interface\n"); + break; + } + } + /*4. PMU->output low, RST->output low, sleep off stable time */ + iRet += wmt_plat_gpio_ctrl(PIN_PMU, PIN_STA_OUT_L); + if (chip_id != 0x6632) + iRet += wmt_plat_gpio_ctrl(PIN_RST, PIN_STA_OUT_L); + osal_sleep_ms(gPwrSeqTime.offStableTime); + + /*5. PMU->output high, sleep rst stable time */ + iRet += wmt_plat_gpio_ctrl(PIN_PMU, PIN_STA_OUT_H); + osal_sleep_ms(gPwrSeqTime.rstStableTime); + + /*6. RST->output high, sleep on stable time */ + if (chip_id != 0x6632) + iRet += wmt_plat_gpio_ctrl(PIN_RST, PIN_STA_OUT_H); + osal_sleep_ms(gPwrSeqTime.onStableTime); + + /*set UART Tx/Rx to UART mode */ + if (0x6630 == chip_id || 0x6632 == chip_id) + iRet += wmt_plat_gpio_ctrl(PIN_UART_RX, PIN_STA_IN_NP); + + + /*7. set audio interface to CMB_STUB_AIF_1, BT PCM ON, I2S OFF */ + /* BT PCM bus default mode. Real control is done by audio */ + iRet += wmt_plat_audio_ctrl(CMB_STUB_AIF_1, CMB_STUB_AIF_CTRL_DIS); + + /*8. set EINT< -ommited-> move this to WMT-IC module, + * where common sdio interface will be identified and do proper operation + */ + /* TODO: [FixMe][GeorgeKuo] double check if BGF_INT is implemented ok */ + if (!((chip_id == 0x6630 || chip_id == 0x6632) + && (wmt_plat_get_comm_if_type() == STP_SDIO_IF_TX))) { + iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_MUX); + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_INIT); + WMT_INFO_FUNC("CMB-HW, BGF_EINT IRQ registered and disabled\n"); + } else { + WMT_DBG_FUNC("CMB-HW, no need to register BGF_EINT for MT6630 & MT6632 SDIO mode\n"); + } + + /* 8.1 set ALL_EINT pin to correct state even it is not used currently */ + iRet += wmt_plat_gpio_ctrl(PIN_ALL_EINT, PIN_STA_MUX); + iRet += wmt_plat_eirq_ctrl(PIN_ALL_EINT, PIN_STA_INIT); + WMT_DBG_FUNC("CMB-HW, hw_pwr_on finish (%d)\n", iRet); + + _pwr_first_time = 0; + return iRet; + +} + +INT32 mtk_wcn_cmb_hw_rst(VOID) +{ + INT32 iRet = 0; + UINT32 chip_id = 0x0; + + WMT_INFO_FUNC("CMB-HW, hw_rst start, eirq should be disabled before this step\n"); + chip_id = mtk_wcn_wmt_chipid_query(); + iRet += wmt_plat_gpio_ctrl(PIN_UART_GRP, PIN_STA_INIT); + if (0x6630 == chip_id || 0x6632 == chip_id) { + switch (wmt_plat_get_comm_if_type()) { + case STP_UART_IF_TX: + iRet += wmt_plat_gpio_ctrl(PIN_UART_RX, PIN_STA_OUT_H); + break; + case STP_SDIO_IF_TX: + iRet += wmt_plat_gpio_ctrl(PIN_UART_RX, PIN_STA_OUT_L); + break; + default: + WMT_ERR_FUNC("not supported common interface\n"); + break; + } + } + + /*1. PMU->output low, RST->output low, sleep off stable time */ + iRet += wmt_plat_gpio_ctrl(PIN_PMU, PIN_STA_OUT_L); + if (chip_id != 0x6632) + iRet += wmt_plat_gpio_ctrl(PIN_RST, PIN_STA_OUT_L); + osal_sleep_ms(gPwrSeqTime.offStableTime); + + /*2. PMU->output high, sleep rst stable time */ + iRet += wmt_plat_gpio_ctrl(PIN_PMU, PIN_STA_OUT_H); + osal_sleep_ms(gPwrSeqTime.rstStableTime); + + /*3. RST->output high, sleep on stable time */ + if (chip_id != 0x6632) + iRet += wmt_plat_gpio_ctrl(PIN_RST, PIN_STA_OUT_H); + osal_sleep_ms(gPwrSeqTime.onStableTime); + + /*set UART Tx/Rx to UART mode */ + if (0x6630 == chip_id || 0x6632 == chip_id) + iRet += wmt_plat_gpio_ctrl(PIN_UART_RX, PIN_STA_IN_NP); + + WMT_INFO_FUNC("CMB-HW, hw_rst finish, eirq should be enabled after this step\n"); + return 0; +} + +static VOID mtk_wcn_cmb_hw_dmp_seq(VOID) +{ + PUINT32 pTimeSlot = (PUINT32) &gPwrSeqTime; + + WMT_INFO_FUNC + ("combo chip power on sequence time, RTC (%d), LDO (%d), RST(%d), OFF(%d), ON(%d)\n", + pTimeSlot[0], + /**pTimeSlot++,*/ + pTimeSlot[1], pTimeSlot[2], pTimeSlot[3], pTimeSlot[4] + ); +} + +INT32 mtk_wcn_cmb_hw_state_show(VOID) +{ + wmt_plat_gpio_ctrl(PIN_PMU, PIN_STA_SHOW); + wmt_plat_gpio_ctrl(PIN_RST, PIN_STA_SHOW); + wmt_plat_gpio_ctrl(PIN_RTC, PIN_STA_SHOW); + return 0; +} + + + +INT32 mtk_wcn_cmb_hw_init(P_PWR_SEQ_TIME pPwrSeqTime) +{ + if (pPwrSeqTime != NULL && + pPwrSeqTime->ldoStableTime > 0 && + pPwrSeqTime->rtcStableTime > 0 && + pPwrSeqTime->offStableTime > DFT_OFF_STABLE_TIME && + pPwrSeqTime->onStableTime > DFT_ON_STABLE_TIME && + pPwrSeqTime->rstStableTime > DFT_RST_STABLE_TIME) { + /*memcpy may be more performance */ + WMT_DBG_FUNC("setting hw init sequence parameters\n"); + osal_memcpy(&gPwrSeqTime, pPwrSeqTime, osal_sizeof(gPwrSeqTime)); + } else { + WMT_DBG_FUNC + ("invalid pPwrSeqTime parameter, use default hw init sequence parameters\n"); + gPwrSeqTime.ldoStableTime = DFT_LDO_STABLE_TIME; + gPwrSeqTime.offStableTime = DFT_OFF_STABLE_TIME; + gPwrSeqTime.onStableTime = DFT_ON_STABLE_TIME; + gPwrSeqTime.rstStableTime = DFT_RST_STABLE_TIME; + gPwrSeqTime.rtcStableTime = DFT_RTC_STABLE_TIME; + } + mtk_wcn_cmb_hw_dmp_seq(); + return 0; +} + +INT32 mtk_wcn_cmb_hw_deinit(VOID) +{ + + WMT_WARN_FUNC("mtk_wcn_cmb_hw_deinit start, set to default hw init sequence parameters\n"); + gPwrSeqTime.ldoStableTime = DFT_LDO_STABLE_TIME; + gPwrSeqTime.offStableTime = DFT_OFF_STABLE_TIME; + gPwrSeqTime.onStableTime = DFT_ON_STABLE_TIME; + gPwrSeqTime.rstStableTime = DFT_RST_STABLE_TIME; + gPwrSeqTime.rtcStableTime = DFT_RTC_STABLE_TIME; + WMT_WARN_FUNC("mtk_wcn_cmb_hw_deinit finish\n"); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/mtk_wcn_consys_hw.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/mtk_wcn_consys_hw.c new file mode 100644 index 00000000000000..d438486d542b5e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/mtk_wcn_consys_hw.c @@ -0,0 +1,859 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-CONSYS-HW]" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include "mtk_wcn_consys_hw.h" +#include "osal_typedef.h" +#include "wmt_step.h" +#include "wmt_ic.h" +#include <linux/of_reserved_mem.h> +#include <linux/pinctrl/consumer.h> +#include <linux/of_gpio.h> +#include <connectivity_build_in_adapter.h> +#include "wmt_lib.h" +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static INT32 mtk_wmt_probe(struct platform_device *pdev); +static void mtk_wmt_remove(struct platform_device *pdev); +static INT32 mtk_wmt_suspend(struct platform_device *pdev, pm_message_t state); +static INT32 mtk_wmt_resume(struct platform_device *pdev); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +UINT8 __iomem *pEmibaseaddr; + +P_WMT_CONSYS_IC_OPS wmt_consys_ic_ops; + +//struct platform_device *g_pdev; + +UINT32 gps_lna_pin_num = 0xffffffff; + +INT32 chip_reset_status = -1; +static INT32 wifi_ant_swap_gpio_pin_num; + +#ifdef CONFIG_OF +const struct of_device_id apwmt_of_ids[] = { + {.compatible = "mediatek,mt3967-consys",}, + {.compatible = "mediatek,mt6570-consys",}, + {.compatible = "mediatek,mt6580-consys",}, + {.compatible = "mediatek,mt6735-consys",}, + {.compatible = "mediatek,mt6739-consys",}, + {.compatible = "mediatek,mt6755-consys",}, + {.compatible = "mediatek,mt6757-consys",}, + {.compatible = "mediatek,mt6758-consys",}, + {.compatible = "mediatek,mt6759-consys",}, + {.compatible = "mediatek,mt6763-consys",}, + {.compatible = "mediatek,mt6797-consys",}, + {.compatible = "mediatek,mt8127-consys",}, + {.compatible = "mediatek,mt8163-consys",}, + {.compatible = "mediatek,mt8167-consys",}, + {.compatible = "mediatek,mt6775-consys",}, + {.compatible = "mediatek,mt6771-consys",}, + {.compatible = "mediatek,mt6765-consys",}, + {.compatible = "mediatek,mt6761-consys",}, + {.compatible = "mediatek,mt6779-consys",}, + {.compatible = "mediatek,mt6768-consys",}, + {.compatible = "mediatek,mt6785-consys",}, + {.compatible = "mediatek,mt8168-consys",}, + {} +}; +struct CONSYS_BASE_ADDRESS conn_reg; +#endif + +static struct platform_driver mtk_wmt_dev_drv = { + .probe = mtk_wmt_probe, + .remove = mtk_wmt_remove, + .suspend = mtk_wmt_suspend, + .resume = mtk_wmt_resume, + .driver = { + .name = "mtk_wmt", + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = apwmt_of_ids, +#endif + }, +}; + +/* GPIO part */ +struct pinctrl *consys_pinctrl; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +INT32 __weak mtk_wcn_consys_jtag_set_for_mcu(VOID) +{ + WMT_PLAT_PR_WARN("Does not support on combo\n"); + return 0; +} + +#if CONSYS_ENALBE_SET_JTAG +UINT32 __weak mtk_wcn_consys_jtag_flag_ctrl(UINT32 en) +{ + WMT_PLAT_PR_WARN("Does not support on combo\n"); + return 0; +} +#endif + +#ifdef CONSYS_WMT_REG_SUSPEND_CB_ENABLE +UINT32 __weak mtk_wcn_consys_hw_osc_en_ctrl(UINT32 en) +{ + WMT_PLAT_PR_WARN("Does not support on combo\n"); + return 0; +} +#endif + +P_WMT_CONSYS_IC_OPS __weak mtk_wcn_get_consys_ic_ops(VOID) +{ + WMT_PLAT_PR_WARN("Does not support on combo\n"); + return NULL; +} + +static INT32 mtk_wmt_probe(struct platform_device *pdev) +{ + INT32 iRet = -1; + INT32 pin_ret = 0; + UINT32 pinmux = 0; + struct device_node *pinctl_node, *pins_node; + UINT8 __iomem *pConnsysEmiStart; + + if (pdev) + g_pdev = pdev; + else { + WMT_PLAT_PR_ERR("pdev is NULL\n"); + return -1; + } + + if (wmt_consys_ic_ops->consys_ic_need_store_pdev) { + if (wmt_consys_ic_ops->consys_ic_need_store_pdev() == MTK_WCN_BOOL_TRUE) { + if (wmt_consys_ic_ops->consys_ic_store_pdev) + wmt_consys_ic_ops->consys_ic_store_pdev(pdev); + pm_runtime_enable(&pdev->dev); + } + } + + if (wmt_consys_ic_ops->consys_ic_read_reg_from_dts) + iRet = wmt_consys_ic_ops->consys_ic_read_reg_from_dts(pdev); + else + iRet = -1; + + if (iRet) + return iRet; + + if (wmt_consys_ic_ops->consys_ic_clk_get_from_dts) + iRet = wmt_consys_ic_ops->consys_ic_clk_get_from_dts(pdev); + else + iRet = -1; + + if (iRet) + return iRet; + + if (gConEmiPhyBase) { + pConnsysEmiStart = ioremap(gConEmiPhyBase, gConEmiSize); + WMT_PLAT_PR_INFO("Clearing Connsys EMI (virtual(0x%p) physical(0x%pa)) %llu bytes\n", + pConnsysEmiStart, &gConEmiPhyBase, gConEmiSize); + memset_io(pConnsysEmiStart, 0, gConEmiSize); + iounmap(pConnsysEmiStart); + pConnsysEmiStart = NULL; + + if (wmt_consys_ic_ops->consys_ic_emi_mpu_set_region_protection) + wmt_consys_ic_ops->consys_ic_emi_mpu_set_region_protection(); + if (wmt_consys_ic_ops->consys_ic_emi_set_remapping_reg) + wmt_consys_ic_ops->consys_ic_emi_set_remapping_reg(); + if (wmt_consys_ic_ops->consys_ic_emi_coredump_remapping) + wmt_consys_ic_ops->consys_ic_emi_coredump_remapping(&pEmibaseaddr, 1); + if (wmt_consys_ic_ops->consys_ic_dedicated_log_path_init) + wmt_consys_ic_ops->consys_ic_dedicated_log_path_init(pdev); + } else { + WMT_PLAT_PR_ERR("consys emi memory address gConEmiPhyBase invalid\n"); + } + +#ifdef CONFIG_MTK_HIBERNATION + WMT_PLAT_PR_INFO("register connsys restore cb for complying with IPOH function\n"); + register_swsusp_restore_noirq_func(ID_M_CONNSYS, mtk_wcn_consys_hw_restore, NULL); +#endif + + if (wmt_consys_ic_ops->ic_bt_wifi_share_v33_spin_lock_init) + wmt_consys_ic_ops->ic_bt_wifi_share_v33_spin_lock_init(); + + + if (wmt_consys_ic_ops->consys_ic_pmic_get_from_dts) + wmt_consys_ic_ops->consys_ic_pmic_get_from_dts(pdev); + + consys_pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(consys_pinctrl)) { + WMT_PLAT_PR_ERR("cannot find consys pinctrl.\n"); + consys_pinctrl = NULL; + } + + /* find gps lna gpio number */ + if (consys_pinctrl) { + pinctl_node = of_parse_phandle(pdev->dev.of_node, "pinctrl-1", 0); + if (pinctl_node) { + pins_node = of_get_child_by_name(pinctl_node, "pins_cmd_dat"); + if (pins_node) { + pin_ret = of_property_read_u32(pins_node, "pinmux", &pinmux); + if (pin_ret) + pin_ret = of_property_read_u32(pins_node, "pins", &pinmux); + gps_lna_pin_num = (pinmux >> 8) & 0xff; + WMT_PLAT_PR_INFO("GPS LNA gpio pin number:%d, pinmux:0x%08x.\n", + gps_lna_pin_num, pinmux); + } + } + } + + wifi_ant_swap_gpio_pin_num = of_get_named_gpio(pdev->dev.of_node, "wifi_ant_swap_gpio", 0); + WMT_PLAT_PR_INFO("ant swap pin number:%d\n", wifi_ant_swap_gpio_pin_num); + + if (wmt_consys_ic_ops->consys_ic_store_reset_control) + wmt_consys_ic_ops->consys_ic_store_reset_control(pdev); + + if (wmt_consys_ic_ops->consys_ic_register_devapc_cb) + wmt_consys_ic_ops->consys_ic_register_devapc_cb(); + + return 0; +} + +static void mtk_wmt_remove(struct platform_device *pdev) +{ + if (wmt_consys_ic_ops->consys_ic_need_store_pdev) { + if (wmt_consys_ic_ops->consys_ic_need_store_pdev() == MTK_WCN_BOOL_TRUE) + pm_runtime_disable(&pdev->dev); + } + + if (wmt_consys_ic_ops->consys_ic_dedicated_log_path_deinit) + wmt_consys_ic_ops->consys_ic_dedicated_log_path_deinit(); + if (wmt_consys_ic_ops->consys_ic_emi_coredump_remapping) + wmt_consys_ic_ops->consys_ic_emi_coredump_remapping(&pEmibaseaddr, 0); + + if (g_pdev) + g_pdev = NULL; +} + +static INT32 mtk_wmt_suspend(struct platform_device *pdev, pm_message_t state) +{ + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_WHEN_AP_SUSPEND); + + return 0; +} + +static INT32 mtk_wmt_resume(struct platform_device *pdev) +{ + wmt_lib_resume_dump_info(); + + return 0; +} + +PUINT32 mtk_wcn_consys_read_dump_info_reg(VOID) +{ + if (wmt_consys_ic_ops->consys_ic_resume_dump_info) + return wmt_consys_ic_ops->consys_ic_resume_dump_info(); + else + return NULL; +} + +INT32 mtk_wcn_consys_hw_reg_ctrl(UINT32 on, UINT32 co_clock_type) +{ + INT32 iRet = 0; + + WMT_PLAT_PR_INFO("CONSYS-HW-REG-CTRL(0x%08x),start\n", on); + + if (on) { + WMT_PLAT_PR_DBG("++\n"); + if (wmt_consys_ic_ops->consys_ic_reset_emi_coredump) + wmt_consys_ic_ops->consys_ic_reset_emi_coredump(pEmibaseaddr); + + if (wmt_consys_ic_ops->consys_ic_hw_vcn18_ctrl) + wmt_consys_ic_ops->consys_ic_hw_vcn18_ctrl(ENABLE); + + if (wmt_consys_ic_ops->consys_ic_set_if_pinmux) + wmt_consys_ic_ops->consys_ic_set_if_pinmux(ENABLE); + + udelay(150); + + if (co_clock_type) { + WMT_PLAT_PR_INFO("co clock type(%d),turn on clk buf\n", co_clock_type); + if (wmt_consys_ic_ops->consys_ic_clock_buffer_ctrl) + wmt_consys_ic_ops->consys_ic_clock_buffer_ctrl(ENABLE); + } + + if (co_clock_type) { + /*if co-clock mode: */ + /*1.set VCN28 to SW control mode (with PMIC_WRAP API) */ + if (wmt_consys_ic_ops->consys_ic_vcn28_hw_mode_ctrl) + wmt_consys_ic_ops->consys_ic_vcn28_hw_mode_ctrl(DISABLE); + } else { + /*if NOT co-clock: */ + /*1.set VCN28 to HW control mode (with PMIC_WRAP API) */ + /*2.turn on VCN28 LDO (with PMIC_WRAP API)" */ + if (wmt_consys_ic_ops->consys_ic_vcn28_hw_mode_ctrl) + wmt_consys_ic_ops->consys_ic_vcn28_hw_mode_ctrl(ENABLE); + if (wmt_consys_ic_ops->consys_ic_hw_vcn28_ctrl) + wmt_consys_ic_ops->consys_ic_hw_vcn28_ctrl(ENABLE); + } + + /* turn on VCN28 LDO for reading efuse usage */ + mtk_wcn_consys_hw_efuse_paldo_ctrl(ENABLE, co_clock_type); + + if (wmt_consys_ic_ops->consys_ic_hw_reset_bit_set) + wmt_consys_ic_ops->consys_ic_hw_reset_bit_set(ENABLE); + if (wmt_consys_ic_ops->consys_ic_hw_spm_clk_gating_enable) + wmt_consys_ic_ops->consys_ic_hw_spm_clk_gating_enable(); + if (wmt_consys_ic_ops->consys_ic_hw_power_ctrl) + wmt_consys_ic_ops->consys_ic_hw_power_ctrl(ENABLE); + + udelay(10); + + if (wmt_consys_ic_ops->consys_ic_ahb_clock_ctrl) + wmt_consys_ic_ops->consys_ic_ahb_clock_ctrl(ENABLE); + + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_BEFORE_GET_CONNSYS_ID); + + if (wmt_consys_ic_ops->polling_consys_ic_chipid && + wmt_consys_ic_ops->polling_consys_ic_chipid() < 0) + return -1; + if (wmt_consys_ic_ops->update_consys_rom_desel_value) + wmt_consys_ic_ops->update_consys_rom_desel_value(); + if (wmt_consys_ic_ops->consys_ic_acr_reg_setting) + wmt_consys_ic_ops->consys_ic_acr_reg_setting(); + if (wmt_consys_ic_ops->consys_ic_afe_reg_setting) + wmt_consys_ic_ops->consys_ic_afe_reg_setting(); + if (wmt_consys_ic_ops->consys_ic_hw_reset_bit_set) + wmt_consys_ic_ops->consys_ic_hw_reset_bit_set(DISABLE); + + msleep(20); + + } else { + if (wmt_consys_ic_ops->consys_ic_ahb_clock_ctrl) + wmt_consys_ic_ops->consys_ic_ahb_clock_ctrl(DISABLE); + if (wmt_consys_ic_ops->consys_ic_hw_power_ctrl) + wmt_consys_ic_ops->consys_ic_hw_power_ctrl(DISABLE); + if (co_clock_type) { + if (wmt_consys_ic_ops->consys_ic_clock_buffer_ctrl) + wmt_consys_ic_ops->consys_ic_clock_buffer_ctrl(DISABLE); + } + + if (co_clock_type == 0) { + if (wmt_consys_ic_ops->consys_ic_vcn28_hw_mode_ctrl) + wmt_consys_ic_ops->consys_ic_vcn28_hw_mode_ctrl(DISABLE); + /*turn off VCN28 LDO (with PMIC_WRAP API)" */ + if (wmt_consys_ic_ops->consys_ic_hw_vcn28_ctrl) + wmt_consys_ic_ops->consys_ic_hw_vcn28_ctrl(DISABLE); + } + + if (wmt_consys_ic_ops->consys_ic_set_if_pinmux) + wmt_consys_ic_ops->consys_ic_set_if_pinmux(DISABLE); + + if (wmt_consys_ic_ops->consys_ic_hw_vcn18_ctrl) + wmt_consys_ic_ops->consys_ic_hw_vcn18_ctrl(DISABLE); + } + WMT_PLAT_PR_INFO("CONSYS-HW-REG-CTRL(0x%08x),finish\n", on); + return iRet; +} +/*tag4 wujun api big difference end*/ + +INT32 mtk_wcn_consys_hw_bt_paldo_ctrl(UINT32 enable) +{ + if (wmt_consys_ic_ops->consys_ic_hw_bt_vcn33_ctrl) + wmt_consys_ic_ops->consys_ic_hw_bt_vcn33_ctrl(enable); + return 0; +} + +INT32 mtk_wcn_consys_hw_wifi_paldo_ctrl(UINT32 enable) +{ + if (wmt_consys_ic_ops->consys_ic_hw_wifi_vcn33_ctrl) + wmt_consys_ic_ops->consys_ic_hw_wifi_vcn33_ctrl(enable); + return 0; +} +EXPORT_SYMBOL(mtk_wcn_consys_hw_wifi_paldo_ctrl); + +INT32 mtk_wcn_consys_hw_efuse_paldo_ctrl(UINT32 enable, UINT32 co_clock_type) +{ + if (co_clock_type) { + if (wmt_consys_ic_ops->consys_ic_hw_vcn28_ctrl) + wmt_consys_ic_ops->consys_ic_hw_vcn28_ctrl(enable); + if (enable) + WMT_PLAT_PR_INFO("turn on vcn28 for efuse usage in co-clock mode\n"); + else + WMT_PLAT_PR_INFO("turn off vcn28 for efuse usage in co-clock mode\n"); + } + return 0; +} +EXPORT_SYMBOL(mtk_wcn_consys_hw_efuse_paldo_ctrl); + +INT32 mtk_wcn_consys_hw_vcn28_ctrl(UINT32 enable) +{ + if (wmt_consys_ic_ops->consys_ic_hw_vcn28_ctrl) + wmt_consys_ic_ops->consys_ic_hw_vcn28_ctrl(enable); + if (enable) + WMT_PLAT_PR_INFO("turn on vcn28 for fm/gps usage in co-clock mode\n"); + else + WMT_PLAT_PR_INFO("turn off vcn28 for fm/gps usage in co-clock mode\n"); + return 0; +} + +UINT32 mtk_wcn_consys_soc_chipid(VOID) +{ + if (wmt_consys_ic_ops == NULL) + wmt_consys_ic_ops = mtk_wcn_get_consys_ic_ops(); + + if (wmt_consys_ic_ops && wmt_consys_ic_ops->consys_ic_soc_chipid_get) + return wmt_consys_ic_ops->consys_ic_soc_chipid_get(); + else + return 0; +} + +struct pinctrl *mtk_wcn_consys_get_pinctrl() +{ + return consys_pinctrl; +} + +INT32 mtk_wcn_consys_hw_gpio_ctrl(UINT32 on) +{ + INT32 iRet = 0; + + WMT_PLAT_PR_DBG("CONSYS-HW-GPIO-CTRL(0x%08x), start\n", on); + + if (on) { + + if (wmt_consys_ic_ops->consys_ic_need_gps) { + if (wmt_consys_ic_ops->consys_ic_need_gps() == MTK_WCN_BOOL_TRUE) { + /*if external modem used,GPS_SYNC still needed to control */ + iRet += wmt_plat_gpio_ctrl(PIN_GPS_SYNC, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_GPS_LNA, PIN_STA_INIT); + + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_INIT); + } + } else { + iRet += wmt_plat_gpio_ctrl(PIN_GPS_SYNC, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_GPS_LNA, PIN_STA_INIT); + + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_INIT); + } + /* TODO: [FixMe][GeorgeKuo] double check if BGF_INT is implemented ok */ + /* iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_MUX); */ + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_INIT); + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); + WMT_PLAT_PR_DBG("CONSYS-HW, BGF IRQ registered and disabled\n"); + + } else { + + /* set bgf eint/all eint to deinit state, namely input low state */ + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); + iRet += wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_DEINIT); + WMT_PLAT_PR_DBG("CONSYS-HW, BGF IRQ unregistered and disabled\n"); + /* iRet += wmt_plat_gpio_ctrl(PIN_BGF_EINT, PIN_STA_DEINIT); */ + if (wmt_consys_ic_ops->consys_ic_need_gps) { + if (wmt_consys_ic_ops->consys_ic_need_gps() == MTK_WCN_BOOL_TRUE) { + /*if external modem used,GPS_SYNC still needed to control */ + iRet += wmt_plat_gpio_ctrl(PIN_GPS_SYNC, PIN_STA_DEINIT); + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_DEINIT); + /* deinit gps_lna */ + iRet += wmt_plat_gpio_ctrl(PIN_GPS_LNA, PIN_STA_DEINIT); + } + } else { + iRet += wmt_plat_gpio_ctrl(PIN_GPS_SYNC, PIN_STA_DEINIT); + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_DEINIT); + iRet += wmt_plat_gpio_ctrl(PIN_GPS_LNA, PIN_STA_DEINIT); + } + } + WMT_PLAT_PR_DBG("CONSYS-HW-GPIO-CTRL(0x%08x), finish\n", on); + return iRet; + +} + +INT32 mtk_wcn_consys_hw_pwr_on(UINT32 co_clock_type) +{ + INT32 iRet = 0; + + WMT_PLAT_PR_INFO("CONSYS-HW-PWR-ON, start\n"); + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_POWER_ON_START); + if (!gConEmiPhyBase) { + WMT_PLAT_PR_ERR("EMI base address is invalid, CONNSYS can not be powered on!"); + return -1; + } + iRet += mtk_wcn_consys_hw_reg_ctrl(1, co_clock_type); + iRet += mtk_wcn_consys_hw_gpio_ctrl(1); + mtk_wcn_consys_jtag_set_for_mcu(); + + WMT_PLAT_PR_INFO("CONSYS-HW-PWR-ON, finish(%d)\n", iRet); + return iRet; +} + +INT32 mtk_wcn_consys_hw_pwr_off(UINT32 co_clock_type) +{ + INT32 iRet = 0; + + WMT_PLAT_PR_INFO("CONSYS-HW-PWR-OFF, start\n"); + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_BEFORE_POWER_OFF); + + iRet += mtk_wcn_consys_hw_reg_ctrl(0, co_clock_type); + iRet += mtk_wcn_consys_hw_gpio_ctrl(0); + + WMT_PLAT_PR_INFO("CONSYS-HW-PWR-OFF, finish(%d)\n", iRet); + return iRet; +} + +INT32 mtk_wcn_consys_hw_rst(UINT32 co_clock_type) +{ + INT32 iRet = 0; + + WMT_PLAT_PR_INFO("CONSYS-HW, hw_rst start, eirq should be disabled before this step\n"); + + mtk_consys_set_chip_reset_status(1); + + if (wmt_consys_ic_ops->consys_ic_set_dl_rom_patch_flag) + wmt_consys_ic_ops->consys_ic_set_dl_rom_patch_flag(1); + + /* Dump infra register for debug purpose */ + if (wmt_consys_ic_ops->consys_ic_infra_reg_dump) + wmt_consys_ic_ops->consys_ic_infra_reg_dump(); + + /* write 0x5000_0154.Bit[1] = 1 (pdma_axi_rready_force_high) to prevent pdma block slpprot */ + if (wmt_consys_ic_ops->consys_ic_set_pdma_axi_rready_force_high) + wmt_consys_ic_ops->consys_ic_set_pdma_axi_rready_force_high(1); + + /*1. do whole hw power off flow */ + iRet += mtk_wcn_consys_hw_reg_ctrl(0, co_clock_type); + + /* Write Wi-Fi calibration data back to EMI */ + mtk_wcn_soc_restore_wifi_cal_result(); + + /*2. do whole hw power on flow */ + iRet += mtk_wcn_consys_hw_reg_ctrl(1, co_clock_type); + + /* Make sure pdma_axi_rready_force_high set to 0 after reset */ + if (wmt_consys_ic_ops->consys_ic_set_pdma_axi_rready_force_high) + wmt_consys_ic_ops->consys_ic_set_pdma_axi_rready_force_high(0); + + mtk_consys_set_chip_reset_status(0); + + WMT_PLAT_PR_INFO("CONSYS-HW, hw_rst finish, eirq should be enabled after this step\n"); + return iRet; +} + +INT32 mtk_wcn_consys_hw_state_show(VOID) +{ + return 0; +} + +INT32 mtk_wcn_consys_hw_restore(struct device *device) +{ + if (gConEmiPhyBase) { + if (wmt_consys_ic_ops->consys_ic_emi_mpu_set_region_protection) + wmt_consys_ic_ops->consys_ic_emi_mpu_set_region_protection(); + if (wmt_consys_ic_ops->consys_ic_emi_set_remapping_reg) + wmt_consys_ic_ops->consys_ic_emi_set_remapping_reg(); + if (wmt_consys_ic_ops->consys_ic_emi_coredump_remapping) + wmt_consys_ic_ops->consys_ic_emi_coredump_remapping(&pEmibaseaddr, 1); + } else { + WMT_PLAT_PR_ERR("consys emi memory address gConEmiPhyBase invalid\n"); + } + + return 0; +} + +INT32 mtk_wcn_consys_hw_init(VOID) +{ + INT32 iRet = -1; + + if (wmt_consys_ic_ops == NULL) + wmt_consys_ic_ops = mtk_wcn_get_consys_ic_ops(); + + iRet = platform_driver_register(&mtk_wmt_dev_drv); + if (iRet) + WMT_PLAT_PR_ERR("WMT platform driver registered failed(%d)\n", iRet); + + + return iRet; + +} + +INT32 mtk_wcn_consys_hw_deinit(VOID) +{ + + if (pEmibaseaddr) { + if (wmt_consys_ic_ops->consys_ic_emi_coredump_remapping) + wmt_consys_ic_ops->consys_ic_emi_coredump_remapping(&pEmibaseaddr, 0); + } +#ifdef CONFIG_MTK_HIBERNATION + unregister_swsusp_restore_noirq_func(ID_M_CONNSYS); +#endif + + platform_driver_unregister(&mtk_wmt_dev_drv); + + if (wmt_consys_ic_ops) + wmt_consys_ic_ops = NULL; + + return 0; +} + +PUINT8 mtk_wcn_consys_emi_virt_addr_get(UINT32 ctrl_state_offset) +{ + UINT8 *p_virtual_addr = NULL; + + if (!pEmibaseaddr) { + WMT_PLAT_PR_ERR("EMI base address is NULL\n"); + return NULL; + } + WMT_PLAT_PR_DBG("ctrl_state_offset(%08x)\n", ctrl_state_offset); + p_virtual_addr = pEmibaseaddr + ctrl_state_offset; + + return p_virtual_addr; +} + +INT32 mtk_wcn_consys_set_dbg_mode(UINT32 flag) +{ + INT32 ret = -1; + PUINT8 vir_addr = NULL; + + vir_addr = mtk_wcn_consys_emi_virt_addr_get(EXP_APMEM_CTRL_CHIP_FW_DBGLOG_MODE); + if (!vir_addr) { + WMT_PLAT_PR_ERR("get vir address fail\n"); + return -2; + } + if (flag) { + ret = 0; + CONSYS_REG_WRITE(vir_addr, 0x1); + } else { + CONSYS_REG_WRITE(vir_addr, 0x0); + } + WMT_PLAT_PR_INFO("fw dbg mode register value(0x%08x)\n", CONSYS_REG_READ(vir_addr)); + return ret; +} + +INT32 mtk_wcn_consys_set_dynamic_dump(PUINT32 str_buf) +{ + PUINT8 vir_addr = NULL; + + vir_addr = mtk_wcn_consys_emi_virt_addr_get(EXP_APMEM_CTRL_CHIP_DYNAMIC_DUMP); + if (!vir_addr) { + WMT_PLAT_PR_ERR("get vir address fail\n"); + return -2; + } + memcpy(vir_addr, str_buf, DYNAMIC_DUMP_GROUP_NUM*8); + WMT_PLAT_PR_INFO("dynamic dump register value(0x%08x)\n", CONSYS_REG_READ(vir_addr)); + return 0; +} + +INT32 mtk_wcn_consys_co_clock_type(VOID) +{ + if (wmt_consys_ic_ops == NULL) + wmt_consys_ic_ops = mtk_wcn_get_consys_ic_ops(); + + if (wmt_consys_ic_ops && wmt_consys_ic_ops->consys_ic_co_clock_type) + return wmt_consys_ic_ops->consys_ic_co_clock_type(); + else + return -1; +} + +P_CONSYS_EMI_ADDR_INFO mtk_wcn_consys_soc_get_emi_phy_add(VOID) +{ + if (wmt_consys_ic_ops->consys_ic_soc_get_emi_phy_add) + return wmt_consys_ic_ops->consys_ic_soc_get_emi_phy_add(); + else + return NULL; +} + +UINT32 mtk_wcn_consys_read_cpupcr(VOID) +{ + if (wmt_consys_ic_ops->consys_ic_read_cpupcr && + mtk_consys_check_reg_readable()) + return wmt_consys_ic_ops->consys_ic_read_cpupcr(); + else + return 0; +} + +VOID mtk_wcn_force_trigger_assert_debug_pin(VOID) +{ + if (wmt_consys_ic_ops->ic_force_trigger_assert_debug_pin) + wmt_consys_ic_ops->ic_force_trigger_assert_debug_pin(); +} + +INT32 mtk_wcn_consys_read_irq_info_from_dts(PINT32 irq_num, PUINT32 irq_flag) +{ + if (wmt_consys_ic_ops->consys_ic_read_irq_info_from_dts) + return wmt_consys_ic_ops->consys_ic_read_irq_info_from_dts(g_pdev, irq_num, irq_flag); + else + return 0; +} + +VOID mtk_wcn_consys_hang_debug(VOID) +{ + if (wmt_consys_ic_ops && wmt_consys_ic_ops->consys_hang_debug) + wmt_consys_ic_ops->consys_hang_debug(); +} + +UINT32 mtk_consys_get_gps_lna_pin_num(VOID) +{ + return gps_lna_pin_num; +} + + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvla" +INT32 mtk_wcn_consys_reg_ctrl(UINT32 is_write, enum CONSYS_BASE_ADDRESS_INDEX index, UINT32 offset, + PUINT32 value) +{ + UINT32 reg_info[index*4 + 4]; + struct device_node *node; + PVOID remap_addr = NULL; + + + node = g_pdev->dev.of_node; + if (node) { + if (of_property_read_u32_array(node, "reg", reg_info, ARRAY_SIZE(reg_info))) { + WMT_PLAT_PR_ERR("get reg from DTS fail!!\n"); + return -1; + } + } else { + WMT_PLAT_PR_ERR("[%s] can't find CONSYS compatible node\n", __func__); + return -1; + } + + if (reg_info[index*4 + 3] < offset) { + WMT_PLAT_PR_ERR("Access overflow of address(0x%x), offset(0x%x)!\n", + reg_info[index*4 + 1], reg_info[index*4 + 3]); + return -1; + } + + remap_addr = ioremap(reg_info[index*4 + 1] + offset, 0x4); + if (remap_addr == NULL) { + WMT_PLAT_PR_ERR("ioremap fail!\n"); + return -1; + } + + if (is_write) + CONSYS_REG_WRITE(remap_addr, *value); + else + *value = CONSYS_REG_READ(remap_addr); + + if (remap_addr) + iounmap(remap_addr); + + return 0; +} +#pragma GCC diagnostic pop + +INT32 mtk_consys_check_reg_readable(VOID) +{ + if (wmt_consys_ic_ops->consys_ic_check_reg_readable) + return wmt_consys_ic_ops->consys_ic_check_reg_readable(); + else + return 1; +} + +VOID mtk_wcn_consys_clock_fail_dump(VOID) +{ + if (wmt_consys_ic_ops->consys_ic_clock_fail_dump) + wmt_consys_ic_ops->consys_ic_clock_fail_dump(); + WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_WHEN_CLOCK_FAIL); +} + +INT32 mtk_consys_is_connsys_reg(UINT32 addr) +{ + if (wmt_consys_ic_ops->consys_ic_is_connsys_reg) + return wmt_consys_ic_ops->consys_ic_is_connsys_reg(addr); + else + return 0; +} + +VOID mtk_consys_set_mcif_mpu_protection(MTK_WCN_BOOL enable) +{ + if (wmt_consys_ic_ops->consys_ic_set_mcif_emi_mpu_protection) + wmt_consys_ic_ops->consys_ic_set_mcif_emi_mpu_protection(enable); +} + +INT32 mtk_consys_is_calibration_backup_restore_support(VOID) +{ + if (wmt_consys_ic_ops->consys_ic_calibration_backup_restore) + return wmt_consys_ic_ops->consys_ic_calibration_backup_restore(); + else + return 0; + +} + +VOID mtk_consys_set_chip_reset_status(INT32 status) +{ + chip_reset_status = status; +} + +INT32 mtk_consys_chip_reset_status(VOID) +{ + return chip_reset_status; +} + +INT32 mtk_consys_is_ant_swap_enable_by_hwid(VOID) +{ + if (wmt_consys_ic_ops->consys_ic_is_ant_swap_enable_by_hwid) + return wmt_consys_ic_ops->consys_ic_is_ant_swap_enable_by_hwid(wifi_ant_swap_gpio_pin_num); + else + return 0; +} + +INT32 mtk_consys_resume_dump_info(VOID) +{ + if (wmt_consys_ic_ops->consys_ic_resume_dump_info) + wmt_consys_ic_ops->consys_ic_resume_dump_info(); + + return 0; +} + +VOID mtk_wcn_consys_ic_get_ant_sel_cr_addr(PUINT32 default_invert_cr, PUINT32 default_invert_bit) +{ + if (wmt_consys_ic_ops->consys_ic_get_ant_sel_cr_addr) + wmt_consys_ic_ops->consys_ic_get_ant_sel_cr_addr(default_invert_cr, default_invert_bit); +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/wmt_build_in_adapter.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/wmt_build_in_adapter.c new file mode 100644 index 00000000000000..bfab519cc9831d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/wmt_build_in_adapter.c @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__*/ +#include <linux/kernel.h> + +#include "wmt_build_in_adapter.h" + +/*device tree mode*/ +#ifdef CONFIG_OF +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/irqreturn.h> +#include <linux/of_address.h> +#endif + +#include <linux/interrupt.h> + +#define CONNADP_LOG_LOUD 4 +#define CONNADP_LOG_DBG 3 +#define CONNADP_LOG_INFO 2 +#define CONNADP_LOG_WARN 1 +#define CONNADP_LOG_ERR 0 + +/******************************************************************************* + * Connsys adaptation layer logging utility + ******************************************************************************/ +static unsigned int gConnAdpDbgLvl = CONNADP_LOG_INFO; + +#define CONNADP_LOUD_FUNC(fmt, arg...) \ +do { \ + if (gConnAdpDbgLvl >= CONNADP_LOG_LOUD) \ + pr_info("[L]%s:" fmt, __func__, ##arg); \ +} while (0) +#define CONNADP_DBG_FUNC(fmt, arg...) \ +do { \ + if (gConnAdpDbgLvl >= CONNADP_LOG_DBG) \ + pr_info("[D]%s:" fmt, __func__, ##arg); \ +} while (0) +#define CONNADP_INFO_FUNC(fmt, arg...) \ +do { \ + if (gConnAdpDbgLvl >= CONNADP_LOG_INFO) \ + pr_info("[I]%s:" fmt, __func__, ##arg); \ +} while (0) +#define CONNADP_WARN_FUNC(fmt, arg...) \ +do { \ + if (gConnAdpDbgLvl >= CONNADP_LOG_WARN) \ + pr_info("[W]%s:" fmt, __func__, ##arg); \ +} while (0) +#define CONNADP_ERR_FUNC(fmt, arg...) \ +do { \ + if (gConnAdpDbgLvl >= CONNADP_LOG_ERR) \ + pr_info("[E]%s(%d):" fmt, __func__, __LINE__, ##arg); \ +} while (0) + + +/******************************************************************************* + * Bridging from platform -> wmt_drv.ko + ******************************************************************************/ +static struct wmt_platform_bridge bridge; + +void wmt_export_platform_bridge_register(struct wmt_platform_bridge *cb) +{ + if (unlikely(!cb)) + return; + bridge.thermal_query_cb = cb->thermal_query_cb; + bridge.clock_fail_dump_cb = cb->clock_fail_dump_cb; + CONNADP_INFO_FUNC("\n"); +} +EXPORT_SYMBOL(wmt_export_platform_bridge_register); + +void wmt_export_platform_bridge_unregister(void) +{ + memset(&bridge, 0, sizeof(struct wmt_platform_bridge)); + CONNADP_INFO_FUNC("\n"); +} +EXPORT_SYMBOL(wmt_export_platform_bridge_unregister); + +int mtk_wcn_cmb_stub_query_ctrl(void) +{ + CONNADP_DBG_FUNC("\n"); + if (unlikely(!bridge.thermal_query_cb)) { + CONNADP_WARN_FUNC("Thermal query not registered\n"); + return -1; + } else + return bridge.thermal_query_cb(); +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_query_ctrl); + +void mtk_wcn_cmb_stub_clock_fail_dump(void) +{ + CONNADP_DBG_FUNC("\n"); + if (unlikely(!bridge.clock_fail_dump_cb)) + CONNADP_WARN_FUNC("Clock fail dump not registered\n"); + else + bridge.clock_fail_dump_cb(); +} +EXPORT_SYMBOL(mtk_wcn_cmb_stub_clock_fail_dump); + +/******************************************************************************* + * SDIO integration with platform MMC driver + ******************************************************************************/ +static void mtk_wcn_cmb_sdio_request_eirq(msdc_sdio_irq_handler_t irq_handler, + void *data); +static void mtk_wcn_cmb_sdio_enable_eirq(void); +static void mtk_wcn_cmb_sdio_disable_eirq(void); +static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data); + +struct sdio_ops mt_sdio_ops[4] = { + {NULL, NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL}, + {mtk_wcn_cmb_sdio_request_eirq, mtk_wcn_cmb_sdio_enable_eirq, + mtk_wcn_cmb_sdio_disable_eirq, mtk_wcn_cmb_sdio_register_pm}, + {mtk_wcn_cmb_sdio_request_eirq, mtk_wcn_cmb_sdio_enable_eirq, + mtk_wcn_cmb_sdio_disable_eirq, mtk_wcn_cmb_sdio_register_pm} +}; + +static atomic_t sdio_claim_irq_enable_flag; +static atomic_t irq_enable_flag; + +static msdc_sdio_irq_handler_t mtk_wcn_cmb_sdio_eirq_handler; +static void *mtk_wcn_cmb_sdio_eirq_data; + +unsigned int wifi_irq = 0xffffffff; +EXPORT_SYMBOL(wifi_irq); + +pm_callback_t mtk_wcn_cmb_sdio_pm_cb; +EXPORT_SYMBOL(mtk_wcn_cmb_sdio_pm_cb); + +void *mtk_wcn_cmb_sdio_pm_data; +EXPORT_SYMBOL(mtk_wcn_cmb_sdio_pm_data); + +static int _mtk_wcn_sdio_irq_flag_set(int flag) +{ + if (flag != 0) + atomic_set(&sdio_claim_irq_enable_flag, 1); + else + atomic_set(&sdio_claim_irq_enable_flag, 0); + + CONNADP_DBG_FUNC("sdio_claim_irq_enable_flag:%d\n", + atomic_read(&sdio_claim_irq_enable_flag)); + + return atomic_read(&sdio_claim_irq_enable_flag); +} + +int wmt_export_mtk_wcn_sdio_irq_flag_set(int flag) +{ + return _mtk_wcn_sdio_irq_flag_set(flag); +} +EXPORT_SYMBOL(wmt_export_mtk_wcn_sdio_irq_flag_set); + +static irqreturn_t mtk_wcn_cmb_sdio_eirq_handler_stub(int irq, void *data) +{ + if ((mtk_wcn_cmb_sdio_eirq_handler != NULL) && + (atomic_read(&sdio_claim_irq_enable_flag) != 0)) + mtk_wcn_cmb_sdio_eirq_handler(mtk_wcn_cmb_sdio_eirq_data); + return IRQ_HANDLED; +} + +static void mtk_wcn_cmb_sdio_request_eirq(msdc_sdio_irq_handler_t irq_handler, + void *data) +{ +#ifdef CONFIG_OF + struct device_node *node; + int ret = -EINVAL; + + CONNADP_INFO_FUNC("enter\n"); + _mtk_wcn_sdio_irq_flag_set(0); + atomic_set(&irq_enable_flag, 1); + mtk_wcn_cmb_sdio_eirq_data = data; + mtk_wcn_cmb_sdio_eirq_handler = irq_handler; + + node = (struct device_node *)of_find_compatible_node(NULL, NULL, + "mediatek,connectivity-combo"); + if (node) { + wifi_irq = irq_of_parse_and_map(node, 0);/* get wifi eint num */ + ret = request_irq(wifi_irq, mtk_wcn_cmb_sdio_eirq_handler_stub, + IRQF_TRIGGER_LOW, "WIFI-eint", NULL); + CONNADP_DBG_FUNC("WIFI EINT irq %d !!\n", wifi_irq); + + if (ret) + CONNADP_WARN_FUNC("WIFI EINT LINE NOT AVAILABLE!!\n"); + else + mtk_wcn_cmb_sdio_disable_eirq();/*state:power off*/ + } else + CONNADP_WARN_FUNC("can't find connectivity compatible node\n"); + + CONNADP_INFO_FUNC("exit\n"); +#else + CONNADP_ERR_FUNC("not implemented\n"); +#endif +} + +static void mtk_wcn_cmb_sdio_register_pm(pm_callback_t pm_cb, void *data) +{ + CONNADP_DBG_FUNC("cmb_sdio_register_pm (0x%p, 0x%p)\n", pm_cb, data); + /* register pm change callback */ + mtk_wcn_cmb_sdio_pm_cb = pm_cb; + mtk_wcn_cmb_sdio_pm_data = data; +} + +static void mtk_wcn_cmb_sdio_enable_eirq(void) +{ + if (atomic_read(&irq_enable_flag)) + CONNADP_DBG_FUNC("wifi eint has been enabled\n"); + else { + atomic_set(&irq_enable_flag, 1); + if (wifi_irq != 0xfffffff) { + enable_irq(wifi_irq); + CONNADP_DBG_FUNC(" enable WIFI EINT %d!\n", wifi_irq); + } + } +} + +static void mtk_wcn_cmb_sdio_disable_eirq(void) +{ + if (!atomic_read(&irq_enable_flag)) + CONNADP_DBG_FUNC("wifi eint has been disabled!\n"); + else { + if (wifi_irq != 0xfffffff) { + disable_irq_nosync(wifi_irq); + CONNADP_DBG_FUNC("disable WIFI EINT %d!\n", wifi_irq); + } + atomic_set(&irq_enable_flag, 0); + } +} + +void wmt_export_mtk_wcn_cmb_sdio_disable_eirq(void) +{ + mtk_wcn_cmb_sdio_disable_eirq(); +} +EXPORT_SYMBOL(wmt_export_mtk_wcn_cmb_sdio_disable_eirq); + + diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/wmt_plat_alps.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/wmt_plat_alps.c new file mode 100644 index 00000000000000..a7f811c88531f8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/wmt_plat_alps.c @@ -0,0 +1,1850 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +//#ifdef CONFIG_PM_WAKELOCKS +//#else +//#include <linux/wakelock.h> +//#endif +#define CFG_WMT_WAKELOCK_SUPPORT 1 + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-PLAT]" + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <linux/delay.h> + +/* ALPS header files */ +#ifndef CONFIG_RTC_DRV_MT6397 +#include <mtk_rtc.h> +#else +#include <linux/mfd/mt6397/rtc_misc.h> +#endif +#ifdef CONFIG_MTK_MT6306_GPIO_SUPPORT +#include <mtk_6306_gpio.h> +#endif + +/* ALPS and COMBO header files */ +#include <mtk_wcn_cmb_stub.h> +/* MTK_WCN_COMBO header files */ +#include "wmt_plat.h" +#include "wmt_dev.h" +#include "wmt_lib.h" +#include "mtk_wcn_cmb_hw.h" +#include "mtk_wcn_consys_hw.h" +#include "stp_dbg.h" +#include "wmt_gpio.h" +#include "wmt_detect.h" +#include "stp_exp.h" +#include <connectivity_build_in_adapter.h> + +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/irqreturn.h> + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +#if CFG_WMT_PS_SUPPORT +static VOID wmt_plat_bgf_eirq_cb(VOID); +#endif +static INT32 wmt_plat_ldo_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_pmu_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_rtc_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_rst_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_bgf_eint_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_wifi_eint_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_all_eint_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_uart_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_pcm_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_i2s_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_sdio_pin_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_gps_sync_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_gps_lna_ctrl(ENUM_PIN_STATE state); +static INT32 wmt_plat_uart_rx_ctrl(ENUM_PIN_STATE state); +static irqreturn_t wmt_plat_bgf_irq_isr(INT32 irq, PVOID arg); +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 wmt_plat_tdm_req_ctrl(ENUM_PIN_STATE state); +#endif +static INT32 wmt_plat_dump_pin_conf(VOID); + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +INT32 gWmtMergeIfSupport; +UINT32 gCoClockFlag; +BGF_IRQ_BALANCE g_bgf_irq_lock; +INT32 wmtPlatLogLvl = WMT_PLAT_LOG_INFO; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +static ENUM_STP_TX_IF_TYPE gCommIfType = STP_MAX_IF_TX; +#if CFG_WMT_WAKELOCK_SUPPORT +static OSAL_SLEEPABLE_LOCK gOsSLock; +static OSAL_WAKE_LOCK wmt_wake_lock; +#endif + +irq_cb wmt_plat_bgf_irq_cb; +device_audio_if_cb wmt_plat_audio_if_cb; +func_ctrl_cb wmt_plat_func_ctrl_cb; +thermal_query_ctrl_cb wmt_plat_thermal_query_ctrl_cb; +trigger_assert_cb wmt_plat_trigger_assert_cb; +deep_idle_ctrl_cb wmt_plat_deep_idle_ctrl_cb; + +static const fp_set_pin gfp_set_pin_table[] = { + [PIN_LDO] = wmt_plat_ldo_ctrl, + [PIN_PMU] = wmt_plat_pmu_ctrl, + [PIN_RTC] = wmt_plat_rtc_ctrl, + [PIN_RST] = wmt_plat_rst_ctrl, + [PIN_BGF_EINT] = wmt_plat_bgf_eint_ctrl, + [PIN_WIFI_EINT] = wmt_plat_wifi_eint_ctrl, + [PIN_ALL_EINT] = wmt_plat_all_eint_ctrl, + [PIN_UART_GRP] = wmt_plat_uart_ctrl, + [PIN_PCM_GRP] = wmt_plat_pcm_ctrl, + [PIN_I2S_GRP] = wmt_plat_i2s_ctrl, + [PIN_SDIO_GRP] = wmt_plat_sdio_pin_ctrl, + [PIN_GPS_SYNC] = wmt_plat_gps_sync_ctrl, + [PIN_GPS_LNA] = wmt_plat_gps_lna_ctrl, + [PIN_UART_RX] = wmt_plat_uart_rx_ctrl, +#if CFG_WMT_LTE_COEX_HANDLING + [PIN_TDM_REQ] = wmt_plat_tdm_req_ctrl, +#endif +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*! + * \brief audio control callback function for CMB_STUB on ALPS + * + * A platform function required for dynamic binding with CMB_STUB on ALPS. + * + * \param state desired audio interface state to use + * \param flag audio interface control options + * + * \retval 0 operation success + * \retval -1 invalid parameters + * \retval < 0 error for operation fail + */ +INT32 wmt_plat_audio_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl) +{ + INT32 iRet = 0; + UINT32 mergeIfSupport = 0; + + /* input sanity check */ + if ((state >= CMB_STUB_AIF_MAX) || (ctrl >= CMB_STUB_AIF_CTRL_MAX)) + return -1; + + iRet = 0; + + /* set host side first */ + switch (state) { + case CMB_STUB_AIF_0: + /* BT_PCM_OFF & FM line in/out */ + iRet += wmt_plat_gpio_ctrl(PIN_PCM_GRP, PIN_STA_DEINIT); + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_DEINIT); + break; + + case CMB_STUB_AIF_1: + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_DEINIT); + iRet += wmt_plat_gpio_ctrl(PIN_PCM_GRP, PIN_STA_INIT); + break; + + case CMB_STUB_AIF_2: + iRet += wmt_plat_gpio_ctrl(PIN_PCM_GRP, PIN_STA_DEINIT); + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_INIT); + break; + + case CMB_STUB_AIF_3: + iRet += wmt_plat_gpio_ctrl(PIN_PCM_GRP, PIN_STA_INIT); + iRet += wmt_plat_gpio_ctrl(PIN_I2S_GRP, PIN_STA_INIT); + break; + + default: + /* FIXME: move to cust folder? */ + WMT_ERR_FUNC("invalid state [%d]\n", state); + return -1; + } + + if (wmt_plat_merge_if_flag_get() != 0) { +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) + WMT_DBG_FUNC("[MT6628]<Merge IF> no need to ctrl combo chip side GPIO\n"); +#else + mergeIfSupport = 1; +#endif + } else + mergeIfSupport = 1; + + if (mergeIfSupport != 0) { + if (ctrl == CMB_STUB_AIF_CTRL_EN) { + WMT_INFO_FUNC("call chip aif setting\n"); + /* need to control chip side GPIO */ + if (wmt_plat_audio_if_cb != NULL) + iRet += (*wmt_plat_audio_if_cb)(state, MTK_WCN_BOOL_FALSE); + else { + WMT_WARN_FUNC("wmt_plat_audio_if_cb is not registered\n"); + iRet -= 1; + } + + + } else + WMT_INFO_FUNC("skip chip aif setting\n"); + } + + return iRet; +} + +static VOID wmt_plat_func_ctrl(UINT32 type, UINT32 on) +{ + if (wmt_plat_func_ctrl_cb) + (*wmt_plat_func_ctrl_cb)(on, type); +} + +static long wmt_plat_thermal_ctrl(VOID) +{ + long temp = 0; + + if (wmt_plat_thermal_query_ctrl_cb) + temp = (*wmt_plat_thermal_query_ctrl_cb)(); + + return temp; +} + +#pragma GCC diagnostic pop +#pragma GCC diagnostic ignored "-Wunused-function" +static INT32 wmt_plat_assert_ctrl(VOID) +{ + INT32 ret = 0; + + if (wmt_plat_trigger_assert_cb) + ret = (*wmt_plat_trigger_assert_cb)(WMTDRV_TYPE_WMT, 45); + + return ret; +} +#pragma GCC diagnostic pop + +static INT32 wmt_plat_deep_idle_ctrl(UINT32 dpilde_ctrl) +{ + INT32 iRet = -1; + + if (wmt_plat_deep_idle_ctrl_cb) + iRet = (*wmt_plat_deep_idle_ctrl_cb)(dpilde_ctrl); + + return iRet; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +static VOID wmt_plat_clock_fail_dump(VOID) +{ + mtk_wcn_consys_clock_fail_dump(); +} +#pragma GCC diagnostic pop + +#if CFG_WMT_PS_SUPPORT +static VOID wmt_plat_bgf_eirq_cb(VOID) +{ +/* #error "need to disable EINT here" */ + /* wmt_lib_ps_irq_cb(); */ + if (wmt_plat_bgf_irq_cb != NULL) + (*(wmt_plat_bgf_irq_cb))(); + else + WMT_PLAT_PR_WARN("WMT-PLAT: wmt_plat_bgf_irq_cb not registered\n"); +} +#endif + +irqreturn_t wmt_plat_bgf_irq_isr(INT32 irq, PVOID arg) +{ +#if CFG_WMT_PS_SUPPORT + wmt_plat_eirq_ctrl(PIN_BGF_EINT, PIN_STA_EINT_DIS); + wmt_plat_bgf_eirq_cb(); +#else + WMT_PLAT_PR_INFO("skip irq handing because psm is disable"); +#endif + + return IRQ_HANDLED; +} + +VOID wmt_plat_irq_cb_reg(irq_cb bgf_irq_cb) +{ + wmt_plat_bgf_irq_cb = bgf_irq_cb; +} + +VOID wmt_plat_aif_cb_reg(device_audio_if_cb aif_ctrl_cb) +{ + wmt_plat_audio_if_cb = aif_ctrl_cb; +} + +VOID wmt_plat_func_ctrl_cb_reg(func_ctrl_cb subsys_func_ctrl) +{ + wmt_plat_func_ctrl_cb = subsys_func_ctrl; +} + +VOID wmt_plat_thermal_ctrl_cb_reg(thermal_query_ctrl_cb thermal_query_ctrl) +{ + wmt_plat_thermal_query_ctrl_cb = thermal_query_ctrl; +} + +VOID wmt_plat_trigger_assert_cb_reg(trigger_assert_cb trigger_assert) +{ + wmt_plat_trigger_assert_cb = trigger_assert; +} + +VOID wmt_plat_deep_idle_ctrl_cb_reg(deep_idle_ctrl_cb deep_idle_ctrl) +{ + wmt_plat_deep_idle_ctrl_cb = deep_idle_ctrl; +} + +UINT32 wmt_plat_soc_co_clock_flag_get(VOID) +{ + return gCoClockFlag; +} + +static UINT32 wmt_plat_soc_co_clock_flag_set(UINT32 flag) +{ + gCoClockFlag = flag; + return 0; +} + +INT32 wmt_plat_init(P_PWR_SEQ_TIME pPwrSeqTime, UINT32 co_clock_type) +{ + struct _CMB_STUB_CB_ stub_cb; + INT32 iret = -1; + + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) { + iret = mtk_wcn_consys_co_clock_type(); + if ((co_clock_type == 0) && (iret >= 0)) + co_clock_type = iret; + wmt_plat_soc_co_clock_flag_set(co_clock_type); + } + + stub_cb.aif_ctrl_cb = wmt_plat_audio_ctrl; + stub_cb.func_ctrl_cb = wmt_plat_func_ctrl; + stub_cb.thermal_query_cb = wmt_plat_thermal_ctrl; + //stub_cb.trigger_assert_cb = wmt_plat_assert_ctrl; + stub_cb.deep_idle_ctrl_cb = wmt_plat_deep_idle_ctrl; + stub_cb.wmt_do_reset_cb = NULL; + //stub_cb.clock_fail_dump_cb = wmt_plat_clock_fail_dump; + stub_cb.size = sizeof(stub_cb); + + /* register to cmb_stub */ + iret = mtk_wcn_cmb_stub_reg(&stub_cb); + + /*init wmt function ctrl wakelock if wake lock is supported by host platform */ +#ifdef CFG_WMT_WAKELOCK_SUPPORT + osal_strcpy(wmt_wake_lock.name, "wmtFuncCtrl"); + wmt_wake_lock.init_flag = 0; + osal_wake_lock_init(&wmt_wake_lock); + osal_sleepable_lock_init(&gOsSLock); +#endif + /* init hw */ + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + iret += mtk_wcn_consys_hw_init(); + else + iret += mtk_wcn_cmb_hw_init(pPwrSeqTime); + + spin_lock_init(&g_bgf_irq_lock.lock); + + WMT_DBG_FUNC("WMT-PLAT: ALPS platform init (%d)\n", iret); + + return 0; +} + +INT32 wmt_plat_deinit(VOID) +{ + INT32 iret = 0; + + /* 1. de-init hw */ + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + iret += mtk_wcn_consys_hw_deinit(); + else + iret = mtk_wcn_cmb_hw_deinit(); + /* 2. unreg to cmb_stub */ + iret += mtk_wcn_cmb_stub_unreg(); + /*3. wmt wakelock deinit */ +#ifdef CFG_WMT_WAKELOCK_SUPPORT + osal_wake_lock_deinit(&wmt_wake_lock); + osal_sleepable_lock_deinit(&gOsSLock); + WMT_DBG_FUNC("destroy wmt_wake_lock\n"); +#endif + WMT_DBG_FUNC("WMT-PLAT: ALPS platform init (%d)\n", iret); + + return 0; +} + +INT32 wmt_plat_sdio_ctrl(WMT_SDIO_SLOT_NUM sdioPortType, ENUM_FUNC_STATE on) +{ + return board_sdio_ctrl(sdioPortType, (on == FUNC_OFF) ? 0 : 1); +} + +static INT32 wmt_plat_dump_pin_conf(VOID) +{ + WMT_DBG_FUNC("[WMT-PLAT]=>dump wmt pin configuration start<=\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("LDO(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num); + } else + WMT_DBG_FUNC("LDO(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("PMU(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num); + } else + WMT_DBG_FUNC("PMU(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("PMUV28(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num); + } else + WMT_DBG_FUNC("PMUV28(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("RST(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num); + } else + WMT_DBG_FUNC("RST(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("BGF_EINT(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num); + } else + WMT_DBG_FUNC("BGF_EINT(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("BGF_EINT_NUM(%d)\n", + gpio_to_irq(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num)); + } else + WMT_DBG_FUNC("BGF_EINT_NUM(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("WIFI_EINT(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num); + } else + WMT_DBG_FUNC("WIFI_EINT(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("WIFI_EINT_NUM(%d)\n", + gpio_to_irq(gpio_ctrl_info.gpio_ctrl_state[GPIO_WIFI_EINT_PIN].gpio_num)); + } else + WMT_DBG_FUNC("WIFI_EINT_NUM(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("UART_RX(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_num); + } else + WMT_DBG_FUNC("UART_RX(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_UTXD_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("UART_TX(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_UTXD_PIN].gpio_num); + } else + WMT_DBG_FUNC("UART_TX(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("DAICLK(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_num); + } else + WMT_DBG_FUNC("DAICLK(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("PCMOUT(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN].gpio_num); + } else + WMT_DBG_FUNC("PCMOUT(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("PCMIN(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN].gpio_num); + } else + WMT_DBG_FUNC("PCMIN(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("PCMSYNC(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_num); + } else + WMT_DBG_FUNC("PCMSYNC(not defined)\n"); +#if defined(FM_DIGITAL_INPUT) || defined(FM_DIGITAL_OUTPUT) + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_CK_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("I2S_CK(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_CK_PIN].gpio_num); + } else + WMT_DBG_FUNC("I2S_CK(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_WS_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("I2S_WS(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_WS_PIN].gpio_num); + } else + WMT_DBG_FUNC("I2S_WS(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_DAT_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("I2S_DAT(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_DAT_PIN].gpio_num); + } else + WMT_DBG_FUNC("I2S_DAT(not defined)\n"); + +#else /* FM_ANALOG_INPUT || FM_ANALOG_OUTPUT */ + WMT_DBG_FUNC("FM digital mode is not set, no need for I2S GPIOs\n"); +#endif + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_GPS_SYNC_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("GPS_SYNC(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_GPS_SYNC_PIN].gpio_num); + } else + WMT_DBG_FUNC("GPS_SYNC(not defined)\n"); + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_GPS_LNA_PIN].gpio_num != DEFAULT_PIN_ID) { + WMT_DBG_FUNC("GPS_LNA(GPIO%d)\n", + gpio_ctrl_info.gpio_ctrl_state[GPIO_GPS_LNA_PIN].gpio_num); + } else + WMT_DBG_FUNC("GPS_LNA(not defined)\n"); + + WMT_DBG_FUNC("[WMT-PLAT]=>dump wmt pin configuration emds<=\n"); + + return 0; +} + +INT32 wmt_plat_pwr_ctrl(ENUM_FUNC_STATE state) +{ + INT32 ret = -1; + + switch (state) { + case FUNC_ON: + /* TODO:[ChangeFeature][George] always output this or by request throuth /proc or sysfs? */ + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + ret = mtk_wcn_consys_hw_pwr_on(gCoClockFlag); + else { + wmt_plat_dump_pin_conf(); + ret = mtk_wcn_cmb_hw_pwr_on(); + } + break; + + case FUNC_OFF: + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + ret = mtk_wcn_consys_hw_pwr_off(gCoClockFlag); + else + ret = mtk_wcn_cmb_hw_pwr_off(); + break; + + case FUNC_RST: + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + ret = mtk_wcn_consys_hw_rst(gCoClockFlag); + else + ret = mtk_wcn_cmb_hw_rst(); + break; + case FUNC_STAT: + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + ret = mtk_wcn_consys_hw_state_show(); + else + ret = mtk_wcn_cmb_hw_state_show(); + break; + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) in pwr_ctrl\n", state); + break; + } + + return ret; +} + +INT32 wmt_plat_eirq_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state) +{ + INT32 iret; + static UINT32 bgf_irq_num = -1; + static UINT32 bgf_irq_flag; + + /* TODO: [ChangeFeature][GeorgeKuo]: use another function to handle this, as done in gpio_ctrls */ + + if ((state != PIN_STA_INIT) && (state != PIN_STA_DEINIT) && (state != PIN_STA_EINT_EN) + && (state != PIN_STA_EINT_DIS)) { + WMT_WARN_FUNC("WMT-PLAT:invalid PIN_STATE(%d) in eirq_ctrl for PIN(%d)\n", state, id); + return -1; + } + + iret = -2; + switch (id) { + case PIN_BGF_EINT: + if (state == PIN_STA_INIT) { + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) { +#ifdef CONFIG_OF + iret = mtk_wcn_consys_read_irq_info_from_dts(&bgf_irq_num, &bgf_irq_flag); + if (iret) + return iret; +#else + bgf_irq_num = MT_CONN2AP_BTIF_WAKEUP_IRQ_ID; + bgf_irq_flag = IRQF_TRIGGER_LOW; +#endif + iret = request_irq(bgf_irq_num, wmt_plat_bgf_irq_isr, bgf_irq_flag, + "BTIF_WAKEUP_IRQ", NULL); + if (iret) { + WMT_PLAT_PR_ERR("request_irq fail,irq_no(%d),iret(%d)\n", + bgf_irq_num, iret); + return iret; + } + } else { + struct device_node *node; + INT32 ret = -EINVAL; + + node = of_find_compatible_node(NULL, NULL, "mediatek,connectivity-combo"); + if (node) { + /*BGF-eint name maybe wrong*/ + bgf_irq_num = irq_of_parse_and_map(node, 1); + ret = request_irq(bgf_irq_num, wmt_plat_bgf_irq_isr, + IRQF_TRIGGER_LOW, "BGF-eint", NULL); + if (ret) + WMT_ERR_FUNC("BGF EINT IRQ LINE NOT AVAILABLE!!\n"); + else + WMT_INFO_FUNC("BGF EINT request_irq success!!\n"); + } else + WMT_ERR_FUNC("[%s] can't find BGF eint compatible node\n", + __func__); + } + g_bgf_irq_lock.counter = 1; + } else if (state == PIN_STA_EINT_EN) { + spin_lock_irqsave(&g_bgf_irq_lock.lock, g_bgf_irq_lock.flags); + if (g_bgf_irq_lock.counter) { + WMT_PLAT_PR_DBG("BGF INT has been enabled,counter(%d)\n", + g_bgf_irq_lock.counter); + } else { + enable_irq(bgf_irq_num); + g_bgf_irq_lock.counter++; + WMT_DBG_FUNC("WMT-PLAT:BGFInt (en)\n"); + } + spin_unlock_irqrestore(&g_bgf_irq_lock.lock, g_bgf_irq_lock.flags); + } else if (state == PIN_STA_EINT_DIS) { + spin_lock_irqsave(&g_bgf_irq_lock.lock, g_bgf_irq_lock.flags); + if (!g_bgf_irq_lock.counter) { + WMT_PLAT_PR_DBG("BGF INT has been disabled,counter(%d)\n", + g_bgf_irq_lock.counter); + } else { + disable_irq_nosync(bgf_irq_num); + g_bgf_irq_lock.counter--; + WMT_DBG_FUNC("WMT-PLAT:BGFInt (dis)\n"); + } + spin_unlock_irqrestore(&g_bgf_irq_lock.lock, g_bgf_irq_lock.flags); + } else { + free_irq(bgf_irq_num, NULL); + WMT_DBG_FUNC("WMT-PLAT:BGFInt (free)\n"); + /* de-init: nothing to do in ALPS, such as un-registration... */ + } + + iret = 0; + break; + case PIN_ALL_EINT: + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_ALL_EINT_PIN].gpio_num != DEFAULT_PIN_ID) { + if (state == PIN_STA_INIT) { + disable_irq_nosync(gpio_to_irq(gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_ALL_EINT_PIN].gpio_num)); + WMT_DBG_FUNC("WMT-PLAT:ALLInt (INIT but not used yet)\n"); + } else if (state == PIN_STA_EINT_EN) { + enable_irq(gpio_to_irq(gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_ALL_EINT_PIN].gpio_num)); + WMT_DBG_FUNC("WMT-PLAT:ALLInt (EN but not used yet)\n"); + } else if (state == PIN_STA_EINT_DIS) { + disable_irq_nosync(gpio_to_irq(gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_ALL_EINT_PIN].gpio_num)); + WMT_DBG_FUNC("WMT-PLAT:ALLInt (DIS but not used yet)\n"); + } else { + disable_irq_nosync(gpio_to_irq(gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_ALL_EINT_PIN].gpio_num)); + WMT_DBG_FUNC("WMT-PLAT:ALLInt (DEINIT but not used yet)\n"); + /* de-init: nothing to do in ALPS, such as un-registration... */ + } + } else + WMT_DBG_FUNC("WMT-PLAT:ALL EINT not defined\n"); + + iret = 0; + break; + + default: + WMT_WARN_FUNC("WMT-PLAT:unsupported EIRQ(PIN_ID:%d) in eirq_ctrl\n", id); + iret = -1; + break; + } + + return iret; +} + +INT32 wmt_plat_gpio_ctrl(ENUM_PIN_ID id, ENUM_PIN_STATE state) +{ + INT32 iret = -1; + + if ((id < PIN_ID_MAX) && (state < PIN_STA_MAX)) { + /* TODO: [FixMe][GeorgeKuo] do sanity check to const function table when init and skip checking here */ + if (gfp_set_pin_table[id]) + iret = (*(gfp_set_pin_table[id]))(state); /* .handler */ + else { + WMT_WARN_FUNC("WMT-PLAT: null fp for gpio_ctrl(%d)\n", id); + iret = -2; + } + } + + return iret; +} + +static INT32 wmt_plat_ldo_ctrl(ENUM_PIN_STATE state) +{ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_DBG_FUNC("WMT-PLAT:LDO is not used\n"); + return 0; + } + + switch (state) { + case PIN_STA_INIT: + /*set to gpio output low, disable pull */ + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_state[GPIO_PULL_DIS]); + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num, 0); + WMT_DBG_FUNC("WMT-PLAT:LDO init (out 0)\n"); + break; + case PIN_STA_OUT_H: + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num, 1); + WMT_DBG_FUNC("WMT-PLAT:LDO (out 1)\n"); + break; + case PIN_STA_OUT_L: + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_num, 0); + WMT_DBG_FUNC("WMT-PLAT:LDO (out 0)\n"); + break; + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable */ + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_LDO_EN_PIN].gpio_state[GPIO_IN_PULLDOWN]); + WMT_DBG_FUNC("WMT-PLAT:LDO deinit (in pd)\n"); + break; + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on LDO\n", state); + break; + } + + return 0; +} + +static INT32 wmt_plat_pmu_ctrl(ENUM_PIN_STATE state) +{ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_ERR_FUNC("WMT-PLAT:PMU not define\n"); + return -1; + } + + switch (state) { + case PIN_STA_INIT: + /*set to gpio output low, disable pull */ + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_PULL_DIS]); + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, 0); + WMT_DBG_FUNC("WMT-PLAT:PMU init (out %d)\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num)); + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num != DEFAULT_PIN_ID) { + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_state[GPIO_PULL_DIS]); + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num, + 0); + } + WMT_DBG_FUNC("WMT-PLAT:PMU init (out 0)\n"); + break; + + case PIN_STA_OUT_H: + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, 1); + WMT_DBG_FUNC("WMT-PLAT:PMU (out 1): %d\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num)); + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num != DEFAULT_PIN_ID) + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num, + 1); + WMT_DBG_FUNC("WMT-PLAT:PMU (out 1)\n"); + break; + + case PIN_STA_OUT_L: + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num, 0); + WMT_DBG_FUNC("WMT-PLAT:PMU (out 0): %d\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_num)); + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num != DEFAULT_PIN_ID) + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num, + 0); + WMT_DBG_FUNC("WMT-PLAT:PMU (out 0)\n"); + break; + + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable */ + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_PMU_EN_PIN].gpio_state[GPIO_IN_PULLDOWN]); + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num != DEFAULT_PIN_ID) + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_state[GPIO_IN_PULLDOWN]); + WMT_DBG_FUNC("WMT-PLAT:PMU deinit (in pd)\n"); + break; + case PIN_STA_SHOW: + WMT_INFO_FUNC("WMT-PLAT:PMU PIN_STA_SHOW start\n"); + WMT_INFO_FUNC("WMT-PLAT:PMU out(%d)\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_PMUV28_EN_PIN].gpio_num)); + WMT_INFO_FUNC("WMT-PLAT:PMU PIN_STA_SHOW end\n"); + break; + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on PMU\n", state); + break; + } + + return 0; +} + +static INT32 wmt_plat_rtc_ctrl(ENUM_PIN_STATE state) +{ + switch (state) { + case PIN_STA_INIT: + rtc_gpio_enable_32k(RTC_GPIO_USER_GPS); + WMT_DBG_FUNC("WMT-PLAT:RTC init\n"); + break; + case PIN_STA_SHOW: + WMT_INFO_FUNC("WMT-PLAT:RTC PIN_STA_SHOW start\n"); + /* WMT_INFO_FUNC("WMT-PLAT:RTC Status(%d)\n", rtc_gpio_32k_status()); */ + WMT_INFO_FUNC("WMT-PLAT:RTC PIN_STA_SHOW end\n"); + break; + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on RTC\n", state); + break; + } + + return 0; +} + +static INT32 wmt_plat_rst_ctrl(ENUM_PIN_STATE state) +{ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_ERR_FUNC("WMT-PLAT:RST not define\n"); + return -1; + } + + switch (state) { + case PIN_STA_INIT: + /*set to gpio output low, disable pull */ + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_PULL_DIS]); + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, 0); + WMT_DBG_FUNC("WMT-PLAT:RST init (out 0)\n"); + break; + + case PIN_STA_OUT_H: + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, 1); + WMT_DBG_FUNC("WMT-PLAT:RST (out 1): %d\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num)); + break; + + case PIN_STA_OUT_L: + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num, 0); + WMT_DBG_FUNC("WMT-PLAT:RST (out 0): %d\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num)); + break; + + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable */ + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_state[GPIO_IN_PULLDOWN]); + WMT_DBG_FUNC("WMT-PLAT:RST deinit (in pd)\n"); + break; + case PIN_STA_SHOW: + WMT_INFO_FUNC("WMT-PLAT:RST PIN_STA_SHOW start\n"); + WMT_INFO_FUNC("WMT-PLAT:RST out(%d)\n", + gpio_get_value(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_RST_PIN].gpio_num)); + WMT_INFO_FUNC("WMT-PLAT:RST PIN_STA_SHOW end\n"); + break; + + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on RST\n", state); + break; + } + + return 0; +} + +static INT32 wmt_plat_bgf_eint_ctrl(ENUM_PIN_STATE state) +{ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_INFO_FUNC("WMT-PLAT:BGF EINT not defined\n"); + return 0; + } + + switch (state) { + case PIN_STA_INIT: + /*set to gpio input low, pull down enable */ + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_state[GPIO_IN_PULLDOWN]); + WMT_DBG_FUNC("WMT-PLAT:BGFInt init(in pd)\n"); + break; + case PIN_STA_MUX: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_state[GPIO_IN_PULLUP]); + WMT_DBG_FUNC("WMT-PLAT:BGFInt mux (eint)\n"); + break; + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable */ + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_BGF_EINT_PIN].gpio_state[GPIO_IN_PULLDOWN]); + WMT_DBG_FUNC("WMT-PLAT:BGFInt deinit(in pd)\n"); + break; + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on BGF EINT\n", state); + break; + } + + return 0; +} + + +static INT32 wmt_plat_wifi_eint_ctrl(ENUM_PIN_STATE state) +{ +#if 0 /*def GPIO_WIFI_EINT_PIN */ + switch (state) { + case PIN_STA_INIT: + mt_set_gpio_pull_enable(GPIO_WIFI_EINT_PIN, GPIO_PULL_DISABLE); + mt_set_gpio_dir(GPIO_WIFI_EINT_PIN, GPIO_DIR_OUT); + mt_set_gpio_mode(GPIO_WIFI_EINT_PIN, GPIO_MODE_GPIO); + mt_set_gpio_out(GPIO_WIFI_EINT_PIN, GPIO_OUT_ONE); + break; + case PIN_STA_MUX: + mt_set_gpio_mode(GPIO_WIFI_EINT_PIN, GPIO_WIFI_EINT_PIN_M_GPIO); + mt_set_gpio_pull_enable(GPIO_WIFI_EINT_PIN, GPIO_PULL_ENABLE); + mt_set_gpio_pull_select(GPIO_WIFI_EINT_PIN, GPIO_PULL_UP); + mt_set_gpio_mode(GPIO_WIFI_EINT_PIN, GPIO_WIFI_EINT_PIN_M_EINT); + + break; + case PIN_STA_EINT_EN: + mt_eint_unmask(CUST_EINT_WIFI_NUM); + break; + case PIN_STA_EINT_DIS: + mt_eint_mask(CUST_EINT_WIFI_NUM); + break; + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable */ + mt_set_gpio_mode(GPIO_WIFI_EINT_PIN, GPIO_COMBO_BGF_EINT_PIN_M_GPIO); + mt_set_gpio_dir(GPIO_WIFI_EINT_PIN, GPIO_DIR_IN); + mt_set_gpio_pull_select(GPIO_WIFI_EINT_PIN, GPIO_PULL_DOWN); + mt_set_gpio_pull_enable(GPIO_WIFI_EINT_PIN, GPIO_PULL_ENABLE); + break; + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on WIFI EINT\n", state); + break; + } +#else + WMT_INFO_FUNC("WMT-PLAT:WIFI EINT is controlled by MSDC driver\n"); +#endif + return 0; +} + + +static INT32 wmt_plat_all_eint_ctrl(ENUM_PIN_STATE state) +{ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_ALL_EINT_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_DBG_FUNC("WMT-PLAT:ALL EINT not defined\n"); + return 0; + } + + switch (state) { + case PIN_STA_INIT: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_ALL_EINT_PIN].gpio_state[GPIO_IN_PULLDOWN]); + WMT_DBG_FUNC("WMT-PLAT:ALLInt init(in pd)\n"); + break; + case PIN_STA_MUX: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_ALL_EINT_PIN].gpio_state[GPIO_IN_PULLUP]); + break; + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + /*set to gpio input low, pull down enable */ + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_ALL_EINT_PIN].gpio_state[GPIO_IN_PULLDOWN]); + break; + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on ALL EINT\n", state); + break; + } + + return 0; +} + +static INT32 wmt_plat_uart_ctrl(ENUM_PIN_STATE state) +{ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_UTXD_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_DBG_FUNC("WMT-PLAT:UART TX not defined\n"); + return 0; + } + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_DBG_FUNC("WMT-PLAT:UART RX not defined\n"); + return 0; + } + + switch (state) { + case PIN_STA_MUX: + case PIN_STA_INIT: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_UTXD_PIN].gpio_state[GPIO_PULL_DIS]); + WMT_DBG_FUNC("WMT-PLAT:UART init (mode_01, uart)\n"); + break; + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_num, 0); + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_UTXD_PIN].gpio_num, 0); + WMT_DBG_FUNC("WMT-PLAT:UART deinit (out 0)\n"); + break; + case PIN_STA_IN_PU: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_state[GPIO_IN_PULLUP]); + break; + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on UART Group\n", state); + break; + } + + return 0; +} + +static INT32 wmt_plat_pcm_ctrl(ENUM_PIN_STATE state) +{ + UINT32 normalPCMFlag = 0; + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_INFO_FUNC("WMT-PLAT:PCM DAICLK not defined\n"); + return 0; + } + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_INFO_FUNC("WMT-PLAT:PCM DAIPCMOUT not defined\n"); + return 0; + } + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_INFO_FUNC("WMT-PLAT:PCM DAIPCMIN not defined\n"); + return 0; + } + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_INFO_FUNC("WMT-PLAT:PCM DAISYNC not defined\n"); + return 0; + } + /*check if combo chip support merge if or not */ + if (wmt_plat_merge_if_flag_get() != 0) { +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) + /* Hardware support Merge IF function */ + WMT_DBG_FUNC("WMT-PLAT:<Merge IF>set to Merge PCM function\n"); + /*merge PCM function define */ + switch (state) { + case PIN_STA_MUX: + case PIN_STA_INIT: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_state[GPIO_PULL_DIS]); + WMT_DBG_FUNC("WMT-PLAT:<Merge IF>PCM init (pcm)\n"); + break; + + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_state[GPIO_PULL_DIS]); + WMT_DBG_FUNC("WMT-PLAT:<Merge IF>PCM deinit (out 0)\n"); + break; + + default: + WMT_WARN_FUNC + ("WMT-PLAT:<Merge IF>Warnning, invalid state(%d) on PCM Group\n", + state); + break; + } + +#else + /* Hardware does not support Merge IF function */ + normalPCMFlag = 1; + WMT_DBG_FUNC("WMT-PLAT:set to normal PCM function\n"); +#endif + + } else { + normalPCMFlag = 1; + } + + if (normalPCMFlag != 0) { + /*normal PCM function define */ + switch (state) { + case PIN_STA_MUX: + case PIN_STA_INIT: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_state[GPIO_PULL_DIS]); + WMT_DBG_FUNC("WMT-PLAT:MT6589 PCM init (pcm)\n"); + break; + + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_PCM_DAICLK_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_PCM_DAIPCMOUT_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_PCM_DAIPCMIN_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_PCM_DAISYNC_PIN].gpio_state[GPIO_PULL_DIS]); + WMT_DBG_FUNC("WMT-PLAT:MT6589 PCM deinit (out 0)\n"); + break; + + default: + WMT_WARN_FUNC("WMT-PLAT:MT6589 Warnning, invalid state(%d) on PCM Group\n", + state); + break; + } + } + + return 0; +} + +static INT32 wmt_plat_cmb_i2s_ctrl(ENUM_PIN_STATE state) +{ + UINT32 normalI2SFlag = 0; + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_CK_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_DBG_FUNC("WMT-PLAT:I2S CK not defined\n"); + return 0; + } + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_WS_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_DBG_FUNC("WMT-PLAT:I2S WS not defined\n"); + return 0; + } + + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_DAT_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_DBG_FUNC("WMT-PLAT:DAT CK not defined\n"); + return 0; + } + /*check if combo chip support merge if or not */ + if (wmt_plat_merge_if_flag_get() != 0) { +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) + /* Hardware support Merge IF function */ +#if defined(FM_DIGITAL_INPUT) || defined(FM_DIGITAL_OUTPUT) + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_CK_PIN].gpio_num != DEFAULT_PIN_ID) { + switch (state) { + case PIN_STA_INIT: + case PIN_STA_MUX: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_I2S_CK_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_I2S_WS_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_I2S_DAT_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_PCM_DAIPMCOUT_PIN]. + gpio_state[GPIO_PULL_DIS]); + WMT_DBG_FUNC("WMT-PLAT:<Merge IF>I2S init (I2S0 system)\n"); + break; + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + gpio_direction_output(gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_I2S_CK_PIN].gpio_num, 0); + gpio_direction_output(gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_I2S_WS_PIN].gpio_num, 0); + gpio_direction_output(gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_I2S_DAT_PIN].gpio_num, 0); + WMT_DBG_FUNC("WMT-PLAT:<Merge IF>I2S deinit (out 0)\n"); + break; + default: + WMT_WARN_FUNC("WMT-PLAT:<Merge IF>Warnning, invalid state(%d) on I2S Group\n", + state); + break; + } + } else + WMT_ERR_FUNC("[MT662x]<Merge IF>Error:FM digital mode set, no I2S GPIOs defined\n"); +#else + WMT_INFO_FUNC("[MT662x]<Merge IF>warnning:FM digital mode is not set\n"); + WMT_INFO_FUNC("no I2S GPIO settings should be modified by combo driver\n"); +#endif +#else + /* Hardware does support Merge IF function */ + normalI2SFlag = 1; +#endif + } else + normalI2SFlag = 1; + + if (normalI2SFlag != 0) { +#if defined(FM_DIGITAL_INPUT) || defined(FM_DIGITAL_OUTPUT) + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_I2S_CK_PIN].gpio_num != DEFAULT_PIN_ID) { + switch (state) { + case PIN_STA_INIT: + case PIN_STA_MUX: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_I2S_CK_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_I2S_WS_PIN].gpio_state[GPIO_PULL_DIS]); + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_I2S_DAT_PIN].gpio_state[GPIO_PULL_DIS]); + WMT_DBG_FUNC("WMT-PLAT:<I2S IF>I2S init (I2S0 system)\n"); + break; + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + gpio_direction_output(gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_I2S_CK_PIN].gpio_num, 0); + gpio_direction_output(gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_I2S_WS_PIN].gpio_num, 0); + gpio_direction_output(gpio_ctrl_info. + gpio_ctrl_state[GPIO_COMBO_I2S_DAT_PIN].gpio_num, 0); + WMT_DBG_FUNC("WMT-PLAT:<I2S IF>I2S deinit (out 0)\n"); + break; + default: + WMT_WARN_FUNC("WMT-PLAT:<I2S IF>Warnning, invalid state(%d) on I2S Group\n", + state); + break; + } + } else + WMT_ERR_FUNC("[MT662x]<I2S IF>Error:FM digital mode set, but no I2S GPIOs defined\n"); +#else + WMT_INFO_FUNC("[MT662x]<I2S IF>warnning:FM digital mode is not set\n"); + WMT_INFO_FUNC("no I2S GPIO settings should be modified by combo driver\n"); +#endif + } + + return 0; +} + +static INT32 wmt_plat_soc_i2s_ctrl(ENUM_PIN_STATE state) +{ + WMT_PLAT_PR_WARN("host i2s pin not defined!!!\n"); + + return 0; +} + +static INT32 wmt_plat_i2s_ctrl(ENUM_PIN_STATE state) +{ + INT32 ret = -1; + + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + ret = wmt_plat_soc_i2s_ctrl(state); + else + ret = wmt_plat_cmb_i2s_ctrl(state); + + return ret; +} + +static INT32 wmt_plat_sdio_pin_ctrl(ENUM_PIN_STATE state) +{ + return 0; +} + +static INT32 wmt_plat_cmb_gps_sync_ctrl(ENUM_PIN_STATE state) +{ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_GPS_SYNC_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_INFO_FUNC("WMT-PLAT:GPS SYNC not defined\n"); + return 0; + } + + switch (state) { + case PIN_STA_INIT: + case PIN_STA_DEINIT: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_GPS_SYNC_PIN].gpio_state[GPIO_PULL_DIS]); + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_GPS_SYNC_PIN].gpio_num, 0); + break; + case PIN_STA_MUX: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_GPS_SYNC_PIN].gpio_state[GPIO_PULL_DIS]); + break; + default: + break; + } + + return 0; +} + +static INT32 wmt_plat_soc_gps_sync_ctrl(ENUM_PIN_STATE state) +{ + WMT_PLAT_PR_WARN("host gps sync pin not defined!!!\n"); + + return 0; +} + +static INT32 wmt_plat_gps_sync_ctrl(ENUM_PIN_STATE state) +{ + INT32 ret = -1; + + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + ret = wmt_plat_soc_gps_sync_ctrl(state); + else + ret = wmt_plat_cmb_gps_sync_ctrl(state); + + return ret; +} + +static INT32 wmt_plat_soc_gps_lna_ctrl(ENUM_PIN_STATE state) +{ +#ifdef CONFIG_MTK_MT6306_GPIO_SUPPORT + switch (state) { + case PIN_STA_INIT: + case PIN_STA_DEINIT: + KERNEL_mt6306_set_gpio_dir(MT6306_GPIO_01, MT6306_GPIO_DIR_OUT); + KERNEL_mt6306_set_gpio_out(MT6306_GPIO_01, MT6306_GPIO_OUT_LOW); + WMT_PLAT_PR_DBG("set gps lna to init\n"); + break; + case PIN_STA_OUT_H: + KERNEL_mt6306_set_gpio_out(MT6306_GPIO_01, MT6306_GPIO_OUT_HIGH); + WMT_PLAT_PR_DBG("set gps lna to oh\n"); + break; + case PIN_STA_OUT_L: + KERNEL_mt6306_set_gpio_out(MT6306_GPIO_01, MT6306_GPIO_OUT_LOW); + WMT_PLAT_PR_DBG("set gps lna to ol\n"); + break; + default: + WMT_PLAT_PR_WARN("%d mode not defined for gps lna pin !!!\n", state); + break; + } +#else + struct pinctrl_state *gps_lna_init; + struct pinctrl_state *gps_lna_oh; + struct pinctrl_state *gps_lna_ol; + struct pinctrl *consys_pinctrl; + + WMT_PLAT_PR_DBG("ENTER++\n"); + consys_pinctrl = mtk_wcn_consys_get_pinctrl(); + if (!consys_pinctrl) { + WMT_PLAT_PR_ERR("get consys pinctrl fail\n"); + return 0; + } + + gps_lna_init = pinctrl_lookup_state(consys_pinctrl, "gps_lna_state_init"); + if (IS_ERR(gps_lna_init)) { + WMT_PLAT_PR_ERR("Cannot find gps lna pin init state!\n"); + return 0; + } + + gps_lna_oh = pinctrl_lookup_state(consys_pinctrl, "gps_lna_state_oh"); + if (IS_ERR(gps_lna_oh)) { + WMT_PLAT_PR_ERR("Cannot find gps lna pin oh state!\n"); + return 0; + } + + gps_lna_ol = pinctrl_lookup_state(consys_pinctrl, "gps_lna_state_ol"); + if (IS_ERR(gps_lna_ol)) { + WMT_PLAT_PR_ERR("Cannot find gps lna pin ol state!\n"); + return 0; + } + + switch (state) { + case PIN_STA_INIT: + case PIN_STA_DEINIT: + pinctrl_select_state(consys_pinctrl, gps_lna_init); + WMT_PLAT_PR_DBG("set gps lna to init\n"); + break; + case PIN_STA_OUT_H: + pinctrl_select_state(consys_pinctrl, gps_lna_oh); + WMT_PLAT_PR_DBG("set gps lna to oh\n"); + break; + case PIN_STA_OUT_L: + pinctrl_select_state(consys_pinctrl, gps_lna_ol); + WMT_PLAT_PR_DBG("set gps lna to ol\n"); + break; + default: + WMT_PLAT_PR_WARN("%d mode not defined for gps lna pin !!!\n", state); + break; + } +#endif + + return 0; +} + +static INT32 wmt_plat_cmb_gps_lna_ctrl(ENUM_PIN_STATE state) +{ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_GPS_LNA_PIN].gpio_num != DEFAULT_PIN_ID) { + switch (state) { + case PIN_STA_INIT: + case PIN_STA_DEINIT: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_GPS_LNA_PIN].gpio_state[GPIO_PULL_DIS]); + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_GPS_LNA_PIN].gpio_num, 0); + break; + case PIN_STA_OUT_H: + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_GPS_LNA_PIN].gpio_num, 1); + break; + case PIN_STA_OUT_L: + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_GPS_LNA_PIN].gpio_num, 0); + break; + default: + WMT_WARN_FUNC("%d mode not defined for gps lna pin !!!\n", state); + break; + } + } else { +#ifdef CONFIG_MTK_MT6306_GPIO_SUPPORT + WMT_WARN_FUNC("/******************************************************************/\n"); + WMT_WARN_FUNC("use MT6306 GPIO7 for gps lna pin.\n this HARD CODE may hurt other\n"); + WMT_WARN_FUNC("system module, if GPIO7 of MT6306 is not defined as GPS_LNA function\n"); + WMT_WARN_FUNC("/******************************************************************/\n"); + + switch (state) { + case PIN_STA_INIT: + case PIN_STA_DEINIT: + /* KERNEL_mt6306_set_gpio_dir(GPIO7, GPIO_DIR_OUT); */ + /* KERNEL_mt6306_set_gpio_out(GPIO7, GPIO_OUT_ZERO); */ + break; + case PIN_STA_OUT_H: + /* KERNEL_mt6306_set_gpio_out(GPIO7, GPIO_OUT_ONE); */ + break; + case PIN_STA_OUT_L: + /* KERNEL_mt6306_set_gpio_out(GPIO7, GPIO_OUT_ZERO); */ + break; + default: + WMT_WARN_FUNC("%d mode not defined for gps lna pin !!!\n", state); + break; + } +#else + WMT_WARN_FUNC("host gps lna pin not defined!!!\n"); + WMT_WARN_FUNC("if you donot use eighter AP or MT6306's pin as GPS_LNA\n"); + WMT_WARN_FUNC("please customize your own GPS_LNA related code here\n"); +#endif + } + + return 0; +} + +static INT32 wmt_plat_gps_lna_ctrl(ENUM_PIN_STATE state) +{ + INT32 ret = -1; + + if (wmt_detect_get_chip_type() == WMT_CHIP_TYPE_SOC) + ret = wmt_plat_soc_gps_lna_ctrl(state); + else + ret = wmt_plat_cmb_gps_lna_ctrl(state); + + return ret; +} + +static INT32 wmt_plat_uart_rx_ctrl(ENUM_PIN_STATE state) +{ + if (gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_num == DEFAULT_PIN_ID) { + WMT_DBG_FUNC("WMT-PLAT:UART RX not defined\n"); + return 0; + } + + switch (state) { + case PIN_STA_MUX: + case PIN_STA_INIT: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_state[GPIO_PULL_DIS]); + WMT_DBG_FUNC("WMT-PLAT:UART Rx init\n"); + break; + case PIN_STA_IN_L: + case PIN_STA_DEINIT: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_state[GPIO_PULL_DIS]); + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_num, 0); + WMT_DBG_FUNC("WMT-PLAT:UART Rx deinit (out 0)\n"); + break; + case PIN_STA_IN_NP: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_state[GPIO_IN_PULL_DIS]); + WMT_DBG_FUNC("WMT-PLAT:UART Rx input pull none\n"); + break; + case PIN_STA_IN_H: + pinctrl_select_state(gpio_ctrl_info.pinctrl_info, + gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_state[GPIO_IN_PULLUP]); + WMT_DBG_FUNC("WMT-PLAT:UART Rx input pull high\n"); + break; + case PIN_STA_OUT_H: + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_num, 1); + WMT_DBG_FUNC("WMT-PLAT:UART Rx output high\n"); + break; + case PIN_STA_OUT_L: + gpio_direction_output(gpio_ctrl_info.gpio_ctrl_state[GPIO_COMBO_URXD_PIN].gpio_num, 0); + WMT_DBG_FUNC("WMT-PLAT:UART Rx deinit (out 0)\n"); + break; + default: + WMT_WARN_FUNC("WMT-PLAT:Warnning, invalid state(%d) on UART Rx\n", state); + break; + } + + return 0; +} + +#if CFG_WMT_LTE_COEX_HANDLING +static INT32 wmt_plat_tdm_req_ctrl(ENUM_PIN_STATE state) +{ + return 0; +} +#endif + +INT32 wmt_plat_wake_lock_ctrl(ENUM_WL_OP opId) +{ +#ifdef CFG_WMT_WAKELOCK_SUPPORT + static INT32 counter; + INT32 ret = 0; + + ret = osal_lock_sleepable_lock(&gOsSLock); + if (ret) { + WMT_ERR_FUNC("--->lock gOsSLock failed, ret=%d\n", ret); + return ret; + } + + if (opId == WL_OP_GET) + ++counter; + else if (opId == WL_OP_PUT) + --counter; + + osal_unlock_sleepable_lock(&gOsSLock); + if (opId == WL_OP_GET && counter == 1) { + osal_wake_lock(&wmt_wake_lock); + WMT_DBG_FUNC("WMT-PLAT: after wake_lock(%d), counter(%d)\n", + osal_wake_lock_count(&wmt_wake_lock), counter); + + } else if (opId == WL_OP_PUT && counter == 0) { + osal_wake_unlock(&wmt_wake_lock); + WMT_DBG_FUNC("WMT-PLAT: after wake_unlock(%d), counter(%d)\n", + osal_wake_lock_count(&wmt_wake_lock), counter); + } else { + WMT_WARN_FUNC("WMT-PLAT: wakelock status(%d), counter(%d)\n", + osal_wake_lock_count(&wmt_wake_lock), counter); + } + + return 0; +#else + WMT_WARN_FUNC("WMT-PLAT: host awake function is not supported."); + + return 0; +#endif +} + + +INT32 wmt_plat_merge_if_flag_ctrl(UINT32 enable) +{ + if (enable) { +#if (MTK_WCN_CMB_MERGE_INTERFACE_SUPPORT) + gWmtMergeIfSupport = 1; +#else + gWmtMergeIfSupport = 0; + WMT_WARN_FUNC("neither MT6589, MTK_MERGE_INTERFACE_SUPPORT nor MT6628 is not set to 1\n"); + WMT_WARN_FUNC("so set gWmtMergeIfSupport to %d\n", gWmtMergeIfSupport); +#endif + } else + gWmtMergeIfSupport = 0; + + WMT_INFO_FUNC("set gWmtMergeIfSupport to %d\n", gWmtMergeIfSupport); + + return gWmtMergeIfSupport; +} + +INT32 wmt_plat_set_comm_if_type(ENUM_STP_TX_IF_TYPE type) +{ + gCommIfType = type; + + return 0; +} + +#ifdef MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +INT32 wmt_plat_merge_if_flag_get(VOID) +{ + return gWmtMergeIfSupport; +} + + +ENUM_STP_TX_IF_TYPE wmt_plat_get_comm_if_type(VOID) +{ + return gCommIfType; +} +#endif + +INT32 wmt_plat_soc_paldo_ctrl(ENUM_PALDO_TYPE ePt, ENUM_PALDO_OP ePo) +{ + INT32 iRet = 0; + + switch (ePt) { + case BT_PALDO: + iRet = mtk_wcn_consys_hw_bt_paldo_ctrl(ePo); + break; + case WIFI_PALDO: + iRet = mtk_wcn_consys_hw_wifi_paldo_ctrl(ePo); + break; + case FM_PALDO: + case GPS_PALDO: + iRet = mtk_wcn_consys_hw_vcn28_ctrl(ePo); + break; + case EFUSE_PALDO: + iRet = mtk_wcn_consys_hw_efuse_paldo_ctrl(ePo, wmt_plat_soc_co_clock_flag_get()); + break; + default: + WMT_PLAT_PR_WARN("WMT-PLAT:Warnning, invalid type(%d) in palod_ctrl\n", ePt); + break; + } + + return iRet; +} + +#if CONSYS_WMT_REG_SUSPEND_CB_ENABLE +UINT32 wmt_plat_soc_osc_en_ctrl(UINT32 en) +{ + return mtk_wcn_consys_hw_osc_en_ctrl(en); +} +#endif + +UINT8 *wmt_plat_get_emi_virt_add(UINT32 offset) +{ + return mtk_wcn_consys_emi_virt_addr_get(offset); +} + +P_CONSYS_EMI_ADDR_INFO wmt_plat_get_emi_phy_add(VOID) +{ + return mtk_wcn_consys_soc_get_emi_phy_add(); +} + +#if CONSYS_ENALBE_SET_JTAG +UINT32 wmt_plat_jtag_flag_ctrl(UINT32 en) +{ + return mtk_wcn_consys_jtag_flag_ctrl(en); +} +#endif + +#if CFG_WMT_DUMP_INT_STATUS +VOID wmt_plat_BGF_irq_dump_status(VOID) +{ + mt_irq_dump_status(269);/*tag3 wujun rainier is enabled */ + + WMT_PLAT_PR_INFO("this function is null in MT6735\n"); +} + +MTK_WCN_BOOL wmt_plat_dump_BGF_irq_status(VOID) +{ + return MTK_WCN_BOOL_FALSE;/*tag4 wujun rainier is enabled */ +} +#endif + +UINT32 wmt_plat_read_cpupcr(VOID) +{ + return mtk_wcn_consys_read_cpupcr(); +} +EXPORT_SYMBOL(wmt_plat_read_cpupcr); + +UINT32 wmt_plat_read_dmaregs(UINT32 type) +{ + return 0; +#if 0 + switch (type) { + case CONNSYS_CLK_GATE_STATUS: + return CONSYS_REG_READ(CONNSYS_CLK_GATE_STATUS_REG); + case CONSYS_EMI_STATUS: + return CONSYS_REG_READ(CONSYS_EMI_STATUS_REG); + case SYSRAM1: + return CONSYS_REG_READ(SYSRAM1_REG); + case SYSRAM2: + return CONSYS_REG_READ(SYSRAM2_REG); + case SYSRAM3: + return CONSYS_REG_READ(SYSRAM3_REG); + default: + return 0; + } +#endif +} + +INT32 wmt_plat_set_host_dump_state(ENUM_HOST_DUMP_STATE state) +{ + PUINT8 p_virtual_addr = NULL; + + p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_SYNC_STATE); + if (!p_virtual_addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + + CONSYS_REG_WRITE(p_virtual_addr, state); + + return 0; +} + +UINT32 wmt_plat_force_trigger_assert(ENUM_FORCE_TRG_ASSERT_T type) +{ + PUINT8 p_virtual_addr = NULL; + + switch (type) { + case STP_FORCE_TRG_ASSERT_EMI: + + WMT_PLAT_PR_INFO("[Force Assert] stp_trigger_firmware_assert_via_emi -->\n"); + p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1); + if (!p_virtual_addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + + CONSYS_REG_WRITE(p_virtual_addr, EXP_APMEM_HOST_OUTBAND_ASSERT_MAGIC_W1); + WMT_PLAT_PR_INFO("[Force Assert] stp_trigger_firmware_assert_via_emi <--\n"); + break; + case STP_FORCE_TRG_ASSERT_DEBUG_PIN: + mtk_wcn_force_trigger_assert_debug_pin(); + break; + default: + WMT_PLAT_PR_ERR("unknown force trigger assert type\n"); + break; + } + + return 0; +} + +INT32 wmt_plat_update_host_sync_num(VOID) +{ + PUINT8 p_virtual_addr = NULL; + UINT32 sync_num = 0; + + p_virtual_addr = wmt_plat_get_emi_virt_add(EXP_APMEM_CTRL_HOST_SYNC_NUM); + if (!p_virtual_addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + + sync_num = CONSYS_REG_READ(p_virtual_addr); + CONSYS_REG_WRITE(p_virtual_addr, sync_num + 1); + + return 0; +} + +INT32 wmt_plat_get_dump_info(UINT32 offset) +{ + PUINT8 p_virtual_addr = NULL; + + p_virtual_addr = wmt_plat_get_emi_virt_add(offset); + if (!p_virtual_addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + WMT_PLAT_PR_DBG("connsys_reg_read (0x%x), (0x%p), (0x%x)\n", CONSYS_REG_READ(p_virtual_addr), p_virtual_addr, + offset); + return CONSYS_REG_READ(p_virtual_addr); +} + +INT32 wmt_plat_write_emi_l(UINT32 offset, UINT32 value) +{ + PUINT8 p_virtual_addr = NULL; + + p_virtual_addr = wmt_plat_get_emi_virt_add(offset); + if (!p_virtual_addr) { + WMT_PLAT_PR_ERR("get virtual address fail\n"); + return -1; + } + + CONSYS_REG_WRITE(p_virtual_addr, value); + return 0; +} + +UINT32 wmt_plat_get_soc_chipid(VOID) +{ + UINT32 chipId = mtk_wcn_consys_soc_chipid(); + + return chipId; +} +EXPORT_SYMBOL(wmt_plat_get_soc_chipid); + +#if CFG_WMT_LTE_COEX_HANDLING +INT32 wmt_plat_get_tdm_antsel_index(VOID) +{ + WMT_PLAT_PR_INFO("not support LTE in this platform\n"); + return 0; +} +#endif + +INT32 wmt_plat_set_dbg_mode(UINT32 flag) +{ + INT32 ret = -1; + PUINT8 vir_addr = NULL; + + vir_addr = mtk_wcn_consys_emi_virt_addr_get(EXP_APMEM_CTRL_CHIP_FW_DBGLOG_MODE); + if (!vir_addr) { + WMT_PLAT_PR_ERR("get vir address fail\n"); + return ret; + } + if (flag) { + CONSYS_REG_WRITE(vir_addr, 0x1); + ret = 0; + } else { + CONSYS_REG_WRITE(vir_addr, 0x0); + ret = 1; + } + WMT_PLAT_PR_INFO("fw dbg mode register value(0x%08x)\n", CONSYS_REG_READ(vir_addr)); + + return ret; +} + +INT32 wmt_plat_set_dynamic_dumpmem(PUINT32 str_buf) +{ + PUINT8 vir_addr = NULL; + + vir_addr = mtk_wcn_consys_emi_virt_addr_get(EXP_APMEM_CTRL_CHIP_DYNAMIC_DUMP); + if (!vir_addr) { + WMT_PLAT_PR_ERR("get vir address fail\n"); + return -1; + } + memcpy(vir_addr, str_buf, DYNAMIC_DUMP_GROUP_NUM*8); + WMT_PLAT_PR_INFO("dynamic dump register value(0x%08x)\n", CONSYS_REG_READ(vir_addr)); + + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/common/common_main/platform/wmt_plat_stub.c b/drivers/misc/mediatek/connectivity/common/common_main/platform/wmt_plat_stub.c new file mode 100644 index 00000000000000..c5f52d1024203a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/common_main/platform/wmt_plat_stub.c @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +#ifdef CONFIG_PM_WAKELOCKS +/* #include <linux/pm_wakeup.h> */ +#else +#include <linux/wakelock.h> +#endif +#define CFG_WMT_WAKELOCK_SUPPORT 1 + +#ifdef DFT_TAG +#undef DFT_TAG +#endif +#define DFT_TAG "[WMT-PLAT]" + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/* ALPS and COMBO header files */ +#include <mtk_wcn_cmb_stub.h> + +/* MTK_WCN_COMBO header files */ +#include "wmt_plat.h" +#include "wmt_plat_stub.h" +#include "wmt_exp.h" +#include "wmt_lib.h" +#include "osal.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static VOID wmt_plat_func_ctrl(UINT32 type, UINT32 on); + + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static void wmt_plat_func_ctrl(unsigned int type, unsigned int on) +{ + if (on) + mtk_wcn_wmt_func_on((ENUM_WMTDRV_TYPE_T) type); + else + mtk_wcn_wmt_func_off((ENUM_WMTDRV_TYPE_T) type); +} + +static signed long wmt_plat_thremal_query(void) +{ + return wmt_lib_tm_temp_query(); +} + +INT32 wmt_plat_stub_init(VOID) +{ + INT32 iRet = -1; + struct _CMB_STUB_CB_ stub_cb = {0}; + + stub_cb.aif_ctrl_cb = wmt_plat_audio_ctrl; + stub_cb.func_ctrl_cb = wmt_plat_func_ctrl; + stub_cb.thermal_query_cb = wmt_plat_thremal_query; + stub_cb.size = sizeof(stub_cb); + + /* register to cmb_stub */ + iRet = mtk_wcn_cmb_stub_reg(&stub_cb); + return iRet; +} diff --git a/drivers/misc/mediatek/connectivity/common/debug_utility/connsys_debug_utility.c b/drivers/misc/mediatek/connectivity/common/debug_utility/connsys_debug_utility.c new file mode 100644 index 00000000000000..5ce29a5b760428 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/debug_utility/connsys_debug_utility.c @@ -0,0 +1,1259 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/workqueue.h> +#include <linux/ratelimit.h> +#include "connsys_debug_utility.h" +#include "ring_emi.h" +#include "ring.h" +#include "wmt_exp.h" +#include <linux/alarmtimer.h> +#include <linux/suspend.h> +#include <linux/rtc.h> + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +enum FW_LOG_MODE { + PRINT_TO_KERNEL_LOG = 0, + LOG_TO_FILE = 1, +}; + +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +static atomic_t log_mode = ATOMIC_INIT(LOG_TO_FILE); +#else +static atomic_t log_mode = ATOMIC_INIT(PRINT_TO_KERNEL_LOG); +#endif + +#define CONNLOG_ALARM_STATE_DISABLE 0x0 +#define CONNLOG_ALARM_STATE_ENABLE 0x01 +#define CONNLOG_ALARM_STATE_RUNNING 0x03 + +struct connlog_alarm { + struct alarm alarm_timer; + unsigned int alarm_state; + unsigned int blank_state; + unsigned int alarm_sec; + spinlock_t alarm_lock; + unsigned long flags; +}; + +struct connlog_dev { + phys_addr_t phyAddrEmiBase; + void __iomem *virAddrEmiLogBase; + int conn2ApIrqId; + bool eirqOn; + spinlock_t irq_lock; + unsigned long flags; + unsigned int irq_counter; + struct timer_list workTimer; + struct work_struct logDataWorker; + /* alarm timer for suspend */ + struct connlog_alarm log_alarm; + void *log_data; +}; +static struct connlog_dev gDev = { 0 }; + +static CONNLOG_EVENT_CB event_callback_table[CONNLOG_TYPE_END] = { 0x0 }; + +struct connlog_buffer { + struct ring_emi ring_emi; + struct ring ring_cache; + void *cache_base; +}; +static struct connlog_buffer connlog_buffer_table[CONNLOG_TYPE_END]; + +struct connlog_offset { + unsigned int emi_base_offset; + unsigned int emi_size; + unsigned int emi_read; + unsigned int emi_write; + unsigned int emi_buf; +}; + +#define INIT_EMI_OFFSET(base, size, read, write, buf) {\ + .emi_base_offset = base, \ + .emi_size = size, \ + .emi_read = read, \ + .emi_write = write, \ + .emi_buf = buf} +static struct connlog_offset emi_offset_table[CONNLOG_TYPE_END] = { + INIT_EMI_OFFSET(CONNLOG_EMI_WIFI_BASE_OFFESET, CONNLOG_EMI_WIFI_SIZE, + CONNLOG_EMI_WIFI_READ, CONNLOG_EMI_WIFI_WRITE, + CONNLOG_EMI_WIFI_BUF), + INIT_EMI_OFFSET(CONNLOG_EMI_BT_BASE_OFFESET, CONNLOG_EMI_BT_SIZE, + CONNLOG_EMI_BT_READ, CONNLOG_EMI_BT_WRITE, + CONNLOG_EMI_BT_BUF), + INIT_EMI_OFFSET(CONNLOG_EMI_GPS_BASE_OFFESET, CONNLOG_EMI_GPS_SIZE, + CONNLOG_EMI_GPS_READ, CONNLOG_EMI_GPS_WRITE, + CONNLOG_EMI_GPS_BUF), + INIT_EMI_OFFSET(CONNLOG_EMI_MCU_BASE_OFFESET, CONNLOG_EMI_MCU_SIZE, + CONNLOG_EMI_MCU_READ, CONNLOG_EMI_MCU_WRITE, + CONNLOG_EMI_MCU_BUF), +}; + + +static char *type_to_title[CONNLOG_TYPE_END] = { + "wifi_fw", "bt_fw", "gps_fw", "mcu_fw" +}; + +static size_t cache_size_table[CONNLOG_TYPE_END] = { + CONNLOG_EMI_WIFI_SIZE * 2, CONNLOG_EMI_BT_SIZE * 2, + CONNLOG_EMI_GPS_SIZE, CONNLOG_EMI_MCU_SIZE +}; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static int connlog_eirq_init(unsigned int irq_id, unsigned int irq_flag); +static void connlog_eirq_deinit(void); +static int connlog_emi_init(phys_addr_t emiaddr); +static void connlog_emi_deinit(void); +static int connlog_ring_buffer_init(void); +static void connlog_ring_buffer_deinit(void); +static int connlog_set_ring_buffer_base_addr(void); +static irqreturn_t connlog_eirq_isr(int irq, void *arg); +static void connlog_set_ring_ready(void); +static void connlog_buffer_init(int conn_type); +static void connlog_ring_emi_to_cache(int conn_type); +static void connlog_dump_buf(const char *title, const char *buf, ssize_t sz); +static void connlog_ring_print(int conn_type); +static void connlog_event_set(int conn_type); +static void connlog_log_data_handler(struct work_struct *work); +static void work_timer_handler(unsigned long data); +static void connlog_do_schedule_work(bool count); + +/* connlog when suspend */ +static int connlog_alarm_init(void); +static void alarm_timer_handler(struct alarm *alarm, ktime_t); +static inline bool connlog_is_alarm_enable(void); +static int connlog_set_alarm_timer(void); +static int connlog_cancel_alarm_timer(void); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +static void connlog_set_ring_ready(void); + +/***************************************************************************** +* FUNCTION +* connlog_cache_allocate +* DESCRIPTION +* Allocate memroy for cache . +* PARAMETERS +* size [IN] data buffer length +* RETURNS +* void* buffer pointer +*****************************************************************************/ +static void *connlog_cache_allocate(size_t size) +{ + void *pBuffer = NULL; + + pBuffer = vmalloc(size); + if (!pBuffer) + return NULL; + return pBuffer; +} + +/* */ +/***************************************************************************** +* FUNCTION +* connlog_set_ring_ready +* DESCRIPTION +* set reserved bit be EMIFWLOG to indicate that init is ready. +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static void connlog_set_ring_ready(void) +{ + const char ready_str[] = "EMIFWLOG"; + + memcpy_toio(gDev.virAddrEmiLogBase + CONNLOG_READY_PATTERN_BASE, + ready_str, CONNLOG_READY_PATTERN_BASE_SIZE); +} + +/***************************************************************************** +* FUNCTION +* connlog_buffer_init +* DESCRIPTION +* Initialize ring and cache buffer +* PARAMETERS +* conn_type [IN] subsys type +* RETURNS +* void +*****************************************************************************/ +static void connlog_buffer_init(int conn_type) +{ + /* init ring emi */ + ring_emi_init( + gDev.virAddrEmiLogBase + emi_offset_table[conn_type].emi_buf, + emi_offset_table[conn_type].emi_size, + gDev.virAddrEmiLogBase + emi_offset_table[conn_type].emi_read, + gDev.virAddrEmiLogBase + emi_offset_table[conn_type].emi_write, + &connlog_buffer_table[conn_type].ring_emi + ); + + /* init ring cache */ + connlog_buffer_table[conn_type].cache_base = connlog_cache_allocate(cache_size_table[conn_type]); + memset(connlog_buffer_table[conn_type].cache_base, 0, cache_size_table[conn_type]); + ring_init( + connlog_buffer_table[conn_type].cache_base, + cache_size_table[conn_type], + 0, + 0, + &connlog_buffer_table[conn_type].ring_cache + ); +} + +/***************************************************************************** +* FUNCTION +* connlog_ring_emi_to_cache +* DESCRIPTION +* copy data from emi ring buffer to cache +* PARAMETERS +* conn_type [IN] subsys type +* RETURNS +* int 0=failed, others=buffer length +*****************************************************************************/ +static void connlog_ring_emi_to_cache(int conn_type) +{ + struct ring_emi_segment ring_emi_seg; + struct ring_emi *ring_emi = &connlog_buffer_table[conn_type].ring_emi; + struct ring *ring_cache = &connlog_buffer_table[conn_type].ring_cache; + int total_size = 0; + int count = 0; + unsigned int cache_max_size = 0; + static DEFINE_RATELIMIT_STATE(_rs, 10 * HZ, 1); + static DEFINE_RATELIMIT_STATE(_rs2, HZ, 1); + + if (RING_FULL(ring_cache)) { + if (__ratelimit(&_rs)) + pr_warn("%s cache is full.\n", type_to_title[conn_type]); + return; + } + + cache_max_size = RING_WRITE_REMAIN_SIZE(ring_cache); + if (RING_EMI_EMPTY(ring_emi) || !ring_emi_read_prepare(cache_max_size, &ring_emi_seg, ring_emi)) { + if (__ratelimit(&_rs)) + pr_err("%s no data, possibly taken by concurrent reader.\n", type_to_title[conn_type]); + return; + } + + /* Check ring_emi buffer memory. Dump EMI data if it's corruption. */ + if (EMI_READ32(ring_emi->read) > emi_offset_table[conn_type].emi_size || + EMI_READ32(ring_emi->write) > emi_offset_table[conn_type].emi_size) { + if (__ratelimit(&_rs)) + pr_err("%s read/write pointer out-of-bounds.\n", type_to_title[conn_type]); + /* 64 byte ring_emi buffer setting & 32 byte mcu read/write pointer */ + connsys_dedicated_log_dump_emi(0x0, 0x60); + /* 32 byte wifi read/write pointer */ + connsys_dedicated_log_dump_emi(CONNLOG_EMI_WIFI_BASE_OFFESET, 0x20); + /* 32 byte bt read/write pointer */ + connsys_dedicated_log_dump_emi(CONNLOG_EMI_BT_BASE_OFFESET, 0x20); + /* 32 byte gps read/write pointer */ + connsys_dedicated_log_dump_emi(CONNLOG_EMI_GPS_BASE_OFFESET, 0x20); + /* Trigger Connsys Assert */ + mtk_wcn_wmt_assert(WMTDRV_TYPE_WMT, 46); + return; + } + + RING_EMI_READ_ALL_FOR_EACH(ring_emi_seg, ring_emi) { + struct ring_segment ring_cache_seg; + unsigned int emi_buf_size = ring_emi_seg.sz; + unsigned int written = 0; + +#ifdef DEBUG_RING + ring_emi_dump(__func__, ring_emi); + ring_emi_dump_segment(__func__, &ring_emi_seg); +#endif + RING_WRITE_FOR_EACH(ring_emi_seg.sz, ring_cache_seg, &connlog_buffer_table[conn_type].ring_cache) { +#ifdef DEBUG_RING + ring_dump(__func__, &connlog_buffer_table[conn_type].ring_cache); + ring_dump_segment(__func__, &ring_cache_seg); +#endif + if (__ratelimit(&_rs2)) + pr_info("%s: ring_emi_seg.sz=%d, ring_cache_pt=%p, ring_cache_seg.sz=%d\n", + type_to_title[conn_type], ring_emi_seg.sz, ring_cache_seg.ring_pt, + ring_cache_seg.sz); + memcpy_fromio(ring_cache_seg.ring_pt, ring_emi_seg.ring_emi_pt + ring_cache_seg.data_pos, + ring_cache_seg.sz); + emi_buf_size -= ring_cache_seg.sz; + written += ring_cache_seg.sz; + } + + total_size += ring_emi_seg.sz; + count++; + } +} + +/* output format + * xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx ................ + * 3 digits hex * 16 + 16 single char + 1 NULL terminate = 64+1 bytes + */ +#define BYETES_PER_LINE 16 +#define LOG_LINE_SIZE (3*BYETES_PER_LINE + BYETES_PER_LINE + 1) +#define IS_VISIBLE_CHAR(c) ((c) >= 32 && (c) <= 126) +static void connlog_dump_buf(const char *title, const char *buf, ssize_t sz) +{ + int i; + char line[LOG_LINE_SIZE]; + + i = 0; + line[LOG_LINE_SIZE-1] = 0; + while (sz--) { + snprintf(line + i*3, 3, "%02x", *buf); + line[i*3 + 2] = ' '; + + if (IS_VISIBLE_CHAR(*buf)) + line[3*BYETES_PER_LINE + i] = *buf; + else + line[3*BYETES_PER_LINE + i] = '`'; + + i++; + buf++; + + if (i >= BYETES_PER_LINE || !sz) { + if (i < BYETES_PER_LINE) { + memset(line+i*3, ' ', (BYETES_PER_LINE-i)*3); + memset(line+3*BYETES_PER_LINE+i, '.', BYETES_PER_LINE-i); + } + pr_info("%s: %s\n", title, line); + i = 0; + } + } +} + +#define LOG_MAX_LEN 1024 +#define LOG_HEAD_LENG 16 +#define TIMESYNC_LENG 40 +const char log_head[] = {0x55, 0x00, 0x00, 0x62}; +const char timesync_head[] = {0x55, 0x00, 0x25, 0x62}; +static char log_line[LOG_MAX_LEN]; +static void connlog_fw_log_parser(int conn_type, const char *buf, ssize_t sz) +{ + unsigned int systime = 0; + unsigned int utc_s = 0; + unsigned int utc_us = 0; + unsigned int buf_len = 0; + unsigned int print_len = 0; + + while (sz > LOG_HEAD_LENG) { + if (*buf == log_head[0]) { + if (!memcmp(buf, log_head, sizeof(log_head))) { + buf_len = buf[14] + (buf[15] << 8); + print_len = buf_len >= LOG_MAX_LEN ? LOG_MAX_LEN - 1 : buf_len; + memcpy(log_line, buf + LOG_HEAD_LENG, print_len); + log_line[print_len] = 0; + pr_info("%s: %s\n", type_to_title[conn_type], log_line); + sz -= (LOG_HEAD_LENG + buf_len); + buf += (LOG_HEAD_LENG + buf_len); + continue; + } else if (sz >= TIMESYNC_LENG && + !memcmp(buf, timesync_head, sizeof(timesync_head))) { + memcpy(&systime, buf + 28, sizeof(systime)); + memcpy(&utc_s, buf + 32, sizeof(utc_s)); + memcpy(&utc_us, buf + 36, sizeof(utc_us)); + pr_info("%s: timesync : (%u) %u.%06u\n", + type_to_title[conn_type], systime, utc_s, utc_us); + sz -= TIMESYNC_LENG; + buf += TIMESYNC_LENG; + continue; + } + } + sz--; + buf++; + } +} +/***************************************************************************** +* FUNCTION +* connlog_ring_print +* DESCRIPTION +* print log data on kernel log +* PARAMETERS +* conn_type [IN] subsys type +* RETURNS +* void +*****************************************************************************/ +static void connlog_ring_print(int conn_type) +{ + unsigned int written = 0; + unsigned int buf_size; + struct ring_emi_segment ring_emi_seg; + struct ring_emi *ring_emi; + + ring_emi = &connlog_buffer_table[conn_type].ring_emi; + if (RING_EMI_EMPTY(ring_emi) || !ring_emi_read_all_prepare(&ring_emi_seg, ring_emi)) { + pr_err("type(%s) no data, possibly taken by concurrent reader.\n", type_to_title[conn_type]); + return; + } + buf_size = ring_emi_seg.remain; + memset(gDev.log_data, 0, CONNLOG_EMI_BT_SIZE); + + /* Check ring_emi buffer memory. Dump EMI data if it's corruption. */ + if (EMI_READ32(ring_emi->read) > emi_offset_table[conn_type].emi_size || + EMI_READ32(ring_emi->write) > emi_offset_table[conn_type].emi_size) { + pr_err("%s read/write pointer out-of-bounds.\n", type_to_title[conn_type]); + /* 64 byte ring_emi buffer setting & 32 byte mcu read/write pointer */ + connsys_dedicated_log_dump_emi(0x0, 0x60); + /* 32 byte wifi read/write pointer */ + connsys_dedicated_log_dump_emi(CONNLOG_EMI_WIFI_BASE_OFFESET, 0x20); + /* 32 byte bt read/write pointer */ + connsys_dedicated_log_dump_emi(CONNLOG_EMI_BT_BASE_OFFESET, 0x20); + /* 32 byte gps read/write pointer */ + connsys_dedicated_log_dump_emi(CONNLOG_EMI_GPS_BASE_OFFESET, 0x20); + /* Trigger Connsys Assert */ + mtk_wcn_wmt_assert(WMTDRV_TYPE_WMT, 46); + return; + } + + RING_EMI_READ_ALL_FOR_EACH(ring_emi_seg, ring_emi) { + memcpy_fromio(gDev.log_data + written, ring_emi_seg.ring_emi_pt, ring_emi_seg.sz); + /* connlog_dump_buf("fw_log", gDev.log_data + written, ring_emi_seg.sz); */ + buf_size -= ring_emi_seg.sz; + written += ring_emi_seg.sz; + } + if (conn_type != CONNLOG_TYPE_BT) + connlog_fw_log_parser(conn_type, gDev.log_data, written); +} + +/***************************************************************************** +* FUNCTION +* connlog_event_set +* DESCRIPTION +* Trigger event call back to wakeup waitqueue +* PARAMETERS +* conn_type [IN] subsys type +* RETURNS +* void +*****************************************************************************/ +static void connlog_event_set(int conn_type) +{ + if ((conn_type < CONNLOG_TYPE_END) && (event_callback_table[conn_type] != 0x0)) + (*event_callback_table[conn_type])(); +} + +/***************************************************************************** +* FUNCTION +* connlog_do_schedule_work +* DESCRIPTION +* schedule work to read emi log data +* PARAMETERS +* count [IN] write irq counter to EMI +* RETURNS +* void +*****************************************************************************/ +static void connlog_do_schedule_work(bool count) +{ + spin_lock_irqsave(&gDev.irq_lock, gDev.flags); + if (count) { + gDev.irq_counter++; + EMI_WRITE32(gDev.virAddrEmiLogBase + CONNLOG_IRQ_COUNTER_BASE, gDev.irq_counter); + } + gDev.eirqOn = !schedule_work(&gDev.logDataWorker); + spin_unlock_irqrestore(&gDev.irq_lock, gDev.flags); +} + +/***************************************************************************** +* FUNCTION +* work_timer_handler +* DESCRIPTION +* IRQ is still on, do schedule_work again +* PARAMETERS +* data [IN] input data +* RETURNS +* void +*****************************************************************************/ +static void work_timer_handler(unsigned long data) +{ + connlog_do_schedule_work(false); +} + +/***************************************************************************** +* FUNCTION +* connlog_alarm_init +* DESCRIPTION +* init alarm timer +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static int connlog_alarm_init(void) +{ + alarm_init(&gDev.log_alarm.alarm_timer, ALARM_REALTIME, alarm_timer_handler); + gDev.log_alarm.alarm_state = CONNLOG_ALARM_STATE_DISABLE; + spin_lock_init(&gDev.log_alarm.alarm_lock); + return 0; +} + +/***************************************************************************** +* FUNCTION +* connlog_is_alarm_enable +* DESCRIPTION +* is alarm timer enable +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static inline bool connlog_is_alarm_enable(void) +{ + if ((gDev.log_alarm.alarm_state & CONNLOG_ALARM_STATE_ENABLE) > 0) + return true; + return false; +} + +/***************************************************************************** +* FUNCTION +* connlog_set_alarm_timer +* DESCRIPTION +* setup alarm timer +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static int connlog_set_alarm_timer(void) +{ + ktime_t kt; + + kt = ktime_set(gDev.log_alarm.alarm_sec, 0); + alarm_start_relative(&gDev.log_alarm.alarm_timer, kt); + + pr_info("[connsys_log_alarm] alarm timer enabled timeout=[%d]", gDev.log_alarm.alarm_sec); + return 0; +} + +/***************************************************************************** +* FUNCTION +* connlog_cancel_alarm_timer +* DESCRIPTION +* cancel alarm timer +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static int connlog_cancel_alarm_timer(void) +{ + pr_info("[connsys_log_alarm] alarm timer cancel"); + return alarm_cancel(&gDev.log_alarm.alarm_timer); +} + +/***************************************************************************** +* FUNCTION +* connsys_log_alarm_enable +* DESCRIPTION +* enable screen off alarm timer mechanism +* PARAMETERS +* sec [IN] alarm timeout in seconds +* RETURNS +* void +*****************************************************************************/ +int connsys_log_alarm_enable(unsigned int sec) +{ + if (!gDev.virAddrEmiLogBase) + return -1; + + spin_lock_irqsave(&gDev.log_alarm.alarm_lock, gDev.log_alarm.flags); + + gDev.log_alarm.alarm_sec = sec; + if (!connlog_is_alarm_enable()) { + gDev.log_alarm.alarm_state = CONNLOG_ALARM_STATE_ENABLE; + pr_info("[connsys_log_alarm] alarm timer enabled timeout=[%d]", sec); + } + if (gDev.log_alarm.blank_state == 0) + connlog_set_alarm_timer(); + + spin_unlock_irqrestore(&gDev.log_alarm.alarm_lock, gDev.log_alarm.flags); + return 0; +} +EXPORT_SYMBOL(connsys_log_alarm_enable); + +/***************************************************************************** +* FUNCTION +* connsys_log_alarm_disable +* DESCRIPTION +* disable screen off alarm timer mechanism +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +int connsys_log_alarm_disable(void) +{ + int ret = 0; + + if (!gDev.virAddrEmiLogBase) + return -1; + + spin_lock_irqsave(&gDev.log_alarm.alarm_lock, gDev.log_alarm.flags); + if (connlog_is_alarm_enable()) { + ret = connlog_cancel_alarm_timer(); + gDev.log_alarm.alarm_state = CONNLOG_ALARM_STATE_DISABLE; + pr_info("[connsys_log_alarm] alarm timer disable"); + } + + spin_unlock_irqrestore(&gDev.log_alarm.alarm_lock, gDev.log_alarm.flags); + return ret; +} +EXPORT_SYMBOL(connsys_log_alarm_disable); + +/***************************************************************************** +* FUNCTION +* connsys_log_blank_state_changed +* DESCRIPTION +* listen blank on/off to suspend/reusme alarm timer +* PARAMETERS +* int [IN] blank state +* RETURNS +* void +*****************************************************************************/ +int connsys_log_blank_state_changed(int blank_state) +{ + int ret = 0; + + if (!gDev.virAddrEmiLogBase) + return -1; + + spin_lock_irqsave(&gDev.log_alarm.alarm_lock, gDev.log_alarm.flags); + gDev.log_alarm.blank_state = blank_state; + if (connlog_is_alarm_enable()) { + if (blank_state == 0) + ret = connlog_set_alarm_timer(); + else + ret = connlog_cancel_alarm_timer(); + } + spin_unlock_irqrestore(&gDev.log_alarm.alarm_lock, gDev.log_alarm.flags); + + return ret; +} +EXPORT_SYMBOL(connsys_log_blank_state_changed); + +/***************************************************************************** +* FUNCTION +* alarm_timer_handler +* DESCRIPTION +* handler for alarm timer +* PARAMETERS +* int [IN] blank state +* RETURNS +* void +*****************************************************************************/ +static void alarm_timer_handler(struct alarm *alarm, + ktime_t now) +{ + ktime_t kt; + struct rtc_time tm; + unsigned int tsec, tusec; + + connsys_dedicated_log_get_utc_time(&tsec, &tusec); + rtc_time64_to_tm(tsec, &tm); + pr_info("[connsys_log_alarm] alarm_timer triggered [%d-%02d-%02d %02d:%02d:%02d.%09u]" + , tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday + , tm.tm_hour, tm.tm_min, tm.tm_sec, tusec); + + connlog_do_schedule_work(false); + + spin_lock_irqsave(&gDev.log_alarm.alarm_lock, gDev.log_alarm.flags); + kt = ktime_set(gDev.log_alarm.alarm_sec, 0); + alarm_start_relative(&gDev.log_alarm.alarm_timer, kt); + spin_unlock_irqrestore(&gDev.log_alarm.alarm_lock, gDev.log_alarm.flags); +} + +/***************************************************************************** +* FUNCTION +* connlog_print_log +* DESCRIPTION +* Print FW log to kernel log +* PARAMETERS +* conn_type [IN] subsys type +* RETURNS +* void +*****************************************************************************/ +static void connlog_log_data_handler(struct work_struct *work) +{ + int ret = 0; + int i; + int module = 0; + static DEFINE_RATELIMIT_STATE(_rs, 10 * HZ, 1); + static DEFINE_RATELIMIT_STATE(_rs2, 2 * HZ, 1); + + do { + ret = 0; + for (i = 0; i < CONNLOG_TYPE_END; i++) { + if (!RING_EMI_EMPTY(&connlog_buffer_table[i].ring_emi)) { + if (atomic_read(&log_mode) == LOG_TO_FILE) + connlog_ring_emi_to_cache(i); + else + connlog_ring_print(i); + + connlog_event_set(i); + /* Set module bit */ + module |= (1 << i); + /* ret++; */ + } else { + if (__ratelimit(&_rs)) + pr_info("[connlog] %s emi ring is empty!!\n", type_to_title[i]); + } + } + } while (ret); + + if (__ratelimit(&_rs2)) + pr_info("[connlog] irq counter=%d module=0x%04x\n", + EMI_READ32(gDev.virAddrEmiLogBase + CONNLOG_IRQ_COUNTER_BASE), module); + spin_lock_irqsave(&gDev.irq_lock, gDev.flags); + if (gDev.eirqOn) + mod_timer(&gDev.workTimer, jiffies + 1); + spin_unlock_irqrestore(&gDev.irq_lock, gDev.flags); +} + +/***************************************************************************** +* FUNCTION +* connlog_eirq_isr +* DESCRIPTION +* IRQ handler to notify subsys that EMI has logs. +* PARAMETERS +* irq [IN] irq number +* art [IN] other argument +* RETURNS +* irqreturn_t irq status +* @IRQ_HANDLED interrupt was handled by this device +*****************************************************************************/ +static irqreturn_t connlog_eirq_isr(int irq, void *arg) +{ + connlog_do_schedule_work(true); + return IRQ_HANDLED; +} + +/***************************************************************************** +* FUNCTION +* connlog_eirq_init +* DESCRIPTION +* To register IRQ +* PARAMETERS +* irq_id [IN] irq number +* irq_flag [IN] irq type +* RETURNS +* int 0=success, others=error +*****************************************************************************/ +static int connlog_eirq_init(unsigned int irq_id, unsigned int irq_flag) +{ + int iret = 0; + + if (gDev.conn2ApIrqId == 0) + gDev.conn2ApIrqId = irq_id; + else { + pr_warn("IRQ has been initialized\n"); + return -1; + } + pr_info("EINT CONN_LOG_IRQ(%d, %d)\n", irq_id, irq_flag); + + iret = request_irq(gDev.conn2ApIrqId, connlog_eirq_isr, irq_flag, "CONN_LOG_IRQ", NULL); + if (iret) + pr_err("EINT IRQ(%d) NOT AVAILABLE!!\n", gDev.conn2ApIrqId); + return iret; +} + +/***************************************************************************** +* FUNCTION +* connlog_eirq_deinit +* DESCRIPTION +* unrigester irq +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static void connlog_eirq_deinit(void) +{ + free_irq(gDev.conn2ApIrqId, NULL); +} + +/***************************************************************************** +* FUNCTION +* connlog_set_ring_buffer_base_addr +* DESCRIPTION +* Set subsys log base address on EMI for FW +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static int connlog_set_ring_buffer_base_addr(void) +{ + if (!gDev.virAddrEmiLogBase) + return -1; + + /* set up subsys base address */ + EMI_WRITE32(gDev.virAddrEmiLogBase + 0, CONNLOG_EMI_MCU_BASE_OFFESET); + EMI_WRITE32(gDev.virAddrEmiLogBase + 4, CONNLOG_EMI_MCU_SIZE); + EMI_WRITE32(gDev.virAddrEmiLogBase + 8, CONNLOG_EMI_WIFI_BASE_OFFESET); + EMI_WRITE32(gDev.virAddrEmiLogBase + 12, CONNLOG_EMI_WIFI_SIZE); + EMI_WRITE32(gDev.virAddrEmiLogBase + 16, CONNLOG_EMI_BT_BASE_OFFESET); + EMI_WRITE32(gDev.virAddrEmiLogBase + 20, CONNLOG_EMI_BT_SIZE); + EMI_WRITE32(gDev.virAddrEmiLogBase + 24, CONNLOG_EMI_GPS_BASE_OFFESET); + EMI_WRITE32(gDev.virAddrEmiLogBase + 28, CONNLOG_EMI_GPS_SIZE); + return 0; +} + +/***************************************************************************** +* FUNCTION +* connlog_emi_init +* DESCRIPTION +* Do ioremap for log buffer on EMI +* PARAMETERS +* emiaddr [IN] physical EMI base address +* RETURNS +* void +*****************************************************************************/ +static int connlog_emi_init(phys_addr_t emiaddr) +{ + if (emiaddr == 0) { + pr_err("consys emi memory address gPhyAddrEmiBase invalid\n"); + return -1; + } + + if (gDev.phyAddrEmiBase) { + pr_warn("emi base address has been initialized\n"); + return -2; + } + + gDev.phyAddrEmiBase = emiaddr; + gDev.virAddrEmiLogBase = ioremap(gDev.phyAddrEmiBase + + CONNLOG_EMI_LOG_BASE_OFFSET, CONNLOG_EMI_SIZE); + if (gDev.virAddrEmiLogBase) { + pr_info("EMI mapping OK virtual(0x%p) physical(0x%x)\n", + gDev.virAddrEmiLogBase, (unsigned int) gDev.phyAddrEmiBase + + CONNLOG_EMI_LOG_BASE_OFFSET); + memset_io(gDev.virAddrEmiLogBase, 0, CONNLOG_EMI_SIZE); + } else + pr_err("EMI mapping fail\n"); + + return 0; +} + +/***************************************************************************** +* FUNCTION +* connlog_emi_init +* DESCRIPTION +* Do iounmap for log buffer on EMI +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static void connlog_emi_deinit(void) +{ + iounmap(gDev.virAddrEmiLogBase); +} + +/***************************************************************************** +* FUNCTION +* connlog_ring_buffer_init +* DESCRIPTION +* Initialize ring buffer setting for subsys +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static int connlog_ring_buffer_init(void) +{ + if (!gDev.virAddrEmiLogBase) { + pr_err("consys emi memory address phyAddrEmiBase invalid\n"); + return -1; + } + + connlog_set_ring_buffer_base_addr(); + connlog_buffer_init(CONNLOG_TYPE_WIFI); + connlog_buffer_init(CONNLOG_TYPE_BT); + connlog_buffer_init(CONNLOG_TYPE_GPS); + connlog_buffer_init(CONNLOG_TYPE_MCU); + gDev.log_data = connlog_cache_allocate(CONNLOG_EMI_BT_SIZE); + connlog_set_ring_ready(); + + return 0; +} + +/***************************************************************************** +* FUNCTION +* connlog_ring_buffer_deinit +* DESCRIPTION +* Initialize ring buffer setting for subsys +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +static void connlog_ring_buffer_deinit(void) +{ + int i = 0; + + for (i = 0; i < CONNLOG_TYPE_END; i++) { + kvfree(connlog_buffer_table[i].cache_base); + connlog_buffer_table[i].cache_base = NULL; + } + kvfree(gDev.log_data); + gDev.log_data = NULL; +} + +/***************************************************************************** +* FUNCTION +* connsys_dedicated_log_path_apsoc_init +* DESCRIPTION +* Initialize API for common driver to initialize connsys dedicated log +* for APSOC platform +* PARAMETERS +* emiaddr [IN] EMI physical base address +* irq_num [IN] IRQ id from device tree +* irq_flag [IN] IRQ flag from device tree +* RETURNS +* void +*****************************************************************************/ + +void (*workingTimerHandlerHack)(unsigned long); + +static void workingTimerHandlerWrapper(struct timer_list *t) +{ + struct connlog_dev* pOsalTimer = container_of(t, struct connlog_dev, workTimer); + + workingTimerHandlerHack((unsigned long) pOsalTimer); +} + +int connsys_dedicated_log_path_apsoc_init(phys_addr_t emiaddr, unsigned int irq_num, unsigned int irq_flag) +{ + gDev.phyAddrEmiBase = 0; + gDev.virAddrEmiLogBase = 0; + gDev.conn2ApIrqId = 0; + gDev.eirqOn = false; + gDev.irq_counter = 0; + + if (connlog_emi_init(emiaddr)) { + pr_err("EMI init failed\n"); + return -1; + } + + if (connlog_ring_buffer_init()) { + pr_err("Ring buffer init failed\n"); + return -2; + } + + //init_timer(&gDev.workTimer); + //gDev.workTimer.function = work_timer_handler; + + workingTimerHandlerHack = work_timer_handler; + timer_setup(&gDev.workTimer, workingTimerHandlerWrapper, 0); + + spin_lock_init(&gDev.irq_lock); + INIT_WORK(&gDev.logDataWorker, connlog_log_data_handler); + if (connlog_eirq_init(irq_num, irq_flag)) { + pr_err("EIRQ init failed\n"); + return -3; + } + + /* alarm_timer */ + connlog_alarm_init(); + return 0; +} +EXPORT_SYMBOL(connsys_dedicated_log_path_apsoc_init); + +/***************************************************************************** +* FUNCTION +* connsys_dedicated_log_path_apsoc_deinit +* DESCRIPTION +* De-Initialize API for common driver to release cache, un-remap emi and free +* irq for APSOC platform +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +void connsys_dedicated_log_path_apsoc_deinit(void) +{ + connlog_emi_deinit(); + connlog_eirq_deinit(); + connlog_ring_buffer_deinit(); +} +EXPORT_SYMBOL(connsys_dedicated_log_path_apsoc_deinit); + +/***************************************************************************** +* FUNCTION +* connsys_log_init +* DESCRIPTION +* Init API for subsys driver. +* PARAMETERS +* conn_type [IN] subsys type +* RETURNS +* int 0=success, others=error +*****************************************************************************/ +int connsys_log_init(int conn_type) +{ + return 0; +} +EXPORT_SYMBOL(connsys_log_init); + +/***************************************************************************** +* FUNCTION +* connsys_log_deinit +* DESCRIPTION +* De-init API for subsys driver. +* PARAMETERS +* conn_type [IN] subsys type +* RETURNS +* int 0=success, others=error +*****************************************************************************/ +int connsys_log_deinit(int conn_type) +{ + if (conn_type >= CONNLOG_TYPE_END || conn_type < 0) + return -1; + event_callback_table[conn_type] = 0x0; + return 0; +} +EXPORT_SYMBOL(connsys_log_deinit); + +/***************************************************************************** +* FUNCTION +* connsys_log_get_buf_size +* DESCRIPTION +* Get ring buffer unread size on EMI. +* PARAMETERS +* conn_type [IN] subsys type +* RETURNS +* unsigned int Ring buffer unread size +*****************************************************************************/ +unsigned int connsys_log_get_buf_size(int conn_type) +{ + if (conn_type >= CONNLOG_TYPE_END || conn_type < 0) + return -1; + return RING_SIZE(&connlog_buffer_table[conn_type].ring_cache); +} +EXPORT_SYMBOL(connsys_log_get_buf_size); + +/***************************************************************************** +* FUNCTION +* connsys_log_register_event_cb +* DESCRIPTION +* Register callback function. It'll be trigger while receive conn2ap IRQ. +* PARAMETERS +* conn_type [IN] subsys type +* func [IN] callback function pointer +* RETURNS +* int 0=success, others=error +*****************************************************************************/ +int connsys_log_register_event_cb(int conn_type, CONNLOG_EVENT_CB func) +{ + if (conn_type >= CONNLOG_TYPE_END || conn_type < 0) + return -1; + event_callback_table[conn_type] = func; + return 0; +} +EXPORT_SYMBOL(connsys_log_register_event_cb); + +/***************************************************************************** +* FUNCTION +* connsys_log_read +* DESCRIPTION +* Copy EMI ring buffer data to the buffer that provided by sub-module. +* PARAMETERS +* conn_type [IN] subsys type +* buf [IN] buffer from driver +* count [IN] buffer length +* RETURNS +* ssize_t read buffer size +*****************************************************************************/ +ssize_t connsys_log_read(int conn_type, char *buf, size_t count) +{ + unsigned int written = 0; + unsigned int cache_buf_size; + struct ring_segment ring_seg; + struct ring *ring = &connlog_buffer_table[conn_type].ring_cache; + unsigned int size = 0; + + if (atomic_read(&log_mode) != LOG_TO_FILE) + goto done; + + size = count < RING_SIZE(ring) ? count : RING_SIZE(ring); + if (RING_EMPTY(ring) || !ring_read_prepare(size, &ring_seg, ring)) { + pr_err("type(%d) no data, possibly taken by concurrent reader.\n", conn_type); + goto done; + } + cache_buf_size = ring_seg.remain; + + RING_READ_FOR_EACH(size, ring_seg, ring) { + memcpy(buf + written, ring_seg.ring_pt, ring_seg.sz); + cache_buf_size -= ring_seg.sz; + written += ring_seg.sz; + } +done: + return written; +} +EXPORT_SYMBOL(connsys_log_read); + +/***************************************************************************** +* FUNCTION +* connsys_log_read_to_user +* DESCRIPTION +* Copy EMI ring buffer data to the user buffer. +* PARAMETERS +* conn_type [IN] subsys type +* buf [IN] user buffer +* count [IN] buffer length +* RETURNS +* ssize_t read buffer size +*****************************************************************************/ +ssize_t connsys_log_read_to_user(int conn_type, char __user *buf, size_t count) +{ + int retval; + unsigned int written = 0; + static DEFINE_RATELIMIT_STATE(_rs, 10 * HZ, 1); + unsigned int cache_buf_size; + struct ring_segment ring_seg; + struct ring *ring = &connlog_buffer_table[conn_type].ring_cache; + unsigned int size = 0; + + if (atomic_read(&log_mode) != LOG_TO_FILE) + goto done; + + size = count < RING_SIZE(ring) ? count : RING_SIZE(ring); + if (RING_EMPTY(ring) || !ring_read_prepare(size, &ring_seg, ring)) { + pr_err("type(%d) no data, possibly taken by concurrent reader.\n", conn_type); + goto done; + } + cache_buf_size = ring_seg.remain; + + RING_READ_FOR_EACH(size, ring_seg, ring) { + retval = copy_to_user(buf + written, ring_seg.ring_pt, ring_seg.sz); + if (retval) { + if (__ratelimit(&_rs)) + pr_err("copy to user buffer failed, ret:%d\n", retval); + goto done; + } + cache_buf_size -= ring_seg.sz; + written += ring_seg.sz; + } +done: + return written; +} +EXPORT_SYMBOL(connsys_log_read_to_user); + +/***************************************************************************** +* FUNCTION +* connsys_log_get_emi_log_base_vir_addr +* DESCRIPTION +* return EMI log base address whitch has done ioremap. +* PARAMETERS +* void +* RETURNS +* void __iomem * ioremap EMI log base address +*****************************************************************************/ +void __iomem *connsys_log_get_emi_log_base_vir_addr(void) +{ + return gDev.virAddrEmiLogBase; +} +EXPORT_SYMBOL(connsys_log_get_emi_log_base_vir_addr); + +/***************************************************************************** +* FUNCTION +* connsys_dedicated_log_get_utc_time +* DESCRIPTION +* return EMI log base address whitch has done ioremap. +* PARAMETERS +* second [IN] UTC seconds +* usecond [IN] UTC usecons +* RETURNS +* void +*****************************************************************************/ +void connsys_dedicated_log_get_utc_time(unsigned int *second, unsigned int *usecond) +{ + struct timespec64 time; + + ktime_get_ts64(&time); + *second = (unsigned int)time.tv_sec; /* UTC time second unit */ + *usecond = (unsigned int)(time.tv_nsec / NSEC_PER_USEC); /* UTC time microsecond unit */ +} +EXPORT_SYMBOL(connsys_dedicated_log_get_utc_time); + +/***************************************************************************** +* FUNCTION +* connsys_dedicated_log_flush_emi +* DESCRIPTION +* flush EMI buffer to log cache. +* PARAMETERS +* void +* RETURNS +* void +*****************************************************************************/ +void connsys_dedicated_log_flush_emi(void) +{ + connlog_do_schedule_work(false); +} + +/***************************************************************************** +* FUNCTION +* connsys_dedicated_log_dump_emi +* DESCRIPTION +* dump EMI buffer for debug. +* PARAMETERS +* offset [IN] buffer offset +* size [IN] dump buffer size +* RETURNS +* void +*****************************************************************************/ +void connsys_dedicated_log_dump_emi(int offset, int size) +{ + connlog_dump_buf("emi", gDev.virAddrEmiLogBase + offset, size); +} + +/***************************************************************************** +* FUNCTION +* connsys_dedicated_log_set_log_to_file +* DESCRIPTION +* set log mode. +* PARAMETERS +* mode [IN] log mode +* RETURNS +* void +*****************************************************************************/ +void connsys_dedicated_log_set_log_mode(int mode) +{ + atomic_set(&log_mode, (mode > 0 ? LOG_TO_FILE : PRINT_TO_KERNEL_LOG)); +} + +/***************************************************************************** +* FUNCTION +* connsys_dedicated_log_get_log_mode +* DESCRIPTION +* get log mode. +* PARAMETERS +* void +* RETURNS +* int log mode +*****************************************************************************/ +int connsys_dedicated_log_get_log_mode(void) +{ + return atomic_read(&log_mode); +} diff --git a/drivers/misc/mediatek/connectivity/common/debug_utility/connsys_debug_utility.h b/drivers/misc/mediatek/connectivity/common/debug_utility/connsys_debug_utility.h new file mode 100644 index 00000000000000..5ba3f62350a7bd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/debug_utility/connsys_debug_utility.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _CONNSYS_DEBUG_UTILITY_H_ +#define _CONNSYS_DEBUG_UTILITY_H_ + +#include "connsys_debug_utility_emi.h" +#include <linux/types.h> +#include <linux/compiler.h> + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +enum CONNLOG_TYPE { + CONNLOG_TYPE_WIFI = 0, + CONNLOG_TYPE_BT = 1, + CONNLOG_TYPE_GPS = 2, + CONNLOG_TYPE_MCU = 3, + CONNLOG_TYPE_END, +}; + +typedef void (*CONNLOG_EVENT_CB) (void); + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/* Common Driver API */ +int connsys_dedicated_log_path_apsoc_init(phys_addr_t emiaddr, unsigned int irq_num, unsigned int irq_flag); +void connsys_dedicated_log_path_apsoc_deinit(void); +void __iomem *connsys_log_get_emi_log_base_vir_addr(void); +void connsys_dedicated_log_get_utc_time(unsigned int *second, unsigned int *usecond); +void connsys_dedicated_log_flush_emi(void); +void connsys_dedicated_log_set_log_mode(int mode); +int connsys_dedicated_log_get_log_mode(void); +void connsys_dedicated_log_dump_emi(int offset, int size); + +/* Debug Utility API */ +int connsys_log_init(int conn_type); +int connsys_log_deinit(int conn_type); +unsigned int connsys_log_get_buf_size(int conn_type); +int connsys_log_register_event_cb(int conn_type, CONNLOG_EVENT_CB func); +ssize_t connsys_log_read_to_user(int conn_type, char __user *buf, size_t count); +ssize_t connsys_log_read(int conn_type, char *buf, size_t count); + +int connsys_log_alarm_enable(unsigned int sec); +int connsys_log_alarm_disable(void); +int connsys_log_blank_state_changed(int blank_state); + +#endif /*_CONNSYS_DEBUG_UTILITY_H_*/ diff --git a/drivers/misc/mediatek/connectivity/common/debug_utility/connsys_debug_utility_emi.h b/drivers/misc/mediatek/connectivity/common/debug_utility/connsys_debug_utility_emi.h new file mode 100644 index 00000000000000..e1c3280674805a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/debug_utility/connsys_debug_utility_emi.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +#ifndef _CONN_DEDICATED_LOG_EMI_H_ +#define _CONN_DEDICATED_LOG_EMI_H_ + +#define CONNLOG_EMI_SIZE (192*1024) /* 192KB */ +#define CONNLOG_EMI_LOG_BASE_OFFSET 0x36500 +#define CONNLOG_EMI_32_BYTE_ALIGNED 32 /* connsys EMI cache is 32-byte aligned */ +#define CONNLOG_CONTROL_RING_BUFFER_BASE_SIZE 64 /* Reserve for setup ring buffer base address */ +#define CONNLOG_CONTROL_RING_BUFFER_RESERVE_SIZE 32 +#define CONNLOG_IRQ_COUNTER_BASE 48 +#define CONNLOG_READY_PATTERN_BASE 56 +#define CONNLOG_READY_PATTERN_BASE_SIZE 8 + +/* define subsys EMI log buffer size */ +#define CONNLOG_EMI_MCU_SIZE (16*1024) +#define CONNLOG_EMI_WIFI_SIZE (64*1024) +#define CONNLOG_EMI_BT_SIZE (64*1024) +#define CONNLOG_EMI_GPS_SIZE (32*1024) + +#define CONNLOG_EMI_MCU_BASE_OFFESET CONNLOG_CONTROL_RING_BUFFER_BASE_SIZE +#define CONNLOG_EMI_MCU_READ (CONNLOG_EMI_MCU_BASE_OFFESET + 0) +#define CONNLOG_EMI_MCU_WRITE (CONNLOG_EMI_MCU_BASE_OFFESET + 4) +#define CONNLOG_EMI_MCU_BUF (CONNLOG_EMI_MCU_BASE_OFFESET + \ + CONNLOG_EMI_32_BYTE_ALIGNED) + +#define CONNLOG_EMI_WIFI_BASE_OFFESET (CONNLOG_EMI_MCU_BASE_OFFESET + \ + CONNLOG_EMI_MCU_SIZE + \ + CONNLOG_EMI_32_BYTE_ALIGNED + \ + CONNLOG_CONTROL_RING_BUFFER_RESERVE_SIZE) +#define CONNLOG_EMI_WIFI_READ (CONNLOG_EMI_WIFI_BASE_OFFESET + 0) +#define CONNLOG_EMI_WIFI_WRITE (CONNLOG_EMI_WIFI_BASE_OFFESET + 4) +#define CONNLOG_EMI_WIFI_BUF (CONNLOG_EMI_WIFI_BASE_OFFESET + \ + CONNLOG_EMI_32_BYTE_ALIGNED) + +#define CONNLOG_EMI_BT_BASE_OFFESET (CONNLOG_EMI_WIFI_BASE_OFFESET + \ + CONNLOG_EMI_WIFI_SIZE + \ + CONNLOG_EMI_32_BYTE_ALIGNED + \ + CONNLOG_CONTROL_RING_BUFFER_RESERVE_SIZE) +#define CONNLOG_EMI_BT_READ (CONNLOG_EMI_BT_BASE_OFFESET + 0) +#define CONNLOG_EMI_BT_WRITE (CONNLOG_EMI_BT_BASE_OFFESET + 4) +#define CONNLOG_EMI_BT_BUF (CONNLOG_EMI_BT_BASE_OFFESET + \ + CONNLOG_EMI_32_BYTE_ALIGNED) + +#define CONNLOG_EMI_GPS_BASE_OFFESET (CONNLOG_EMI_BT_BASE_OFFESET + \ + CONNLOG_EMI_BT_SIZE + \ + CONNLOG_EMI_32_BYTE_ALIGNED + \ + CONNLOG_CONTROL_RING_BUFFER_RESERVE_SIZE) +#define CONNLOG_EMI_GPS_READ (CONNLOG_EMI_GPS_BASE_OFFESET + 0) +#define CONNLOG_EMI_GPS_WRITE (CONNLOG_EMI_GPS_BASE_OFFESET + 4) +#define CONNLOG_EMI_GPS_BUF (CONNLOG_EMI_GPS_BASE_OFFESET + \ + CONNLOG_EMI_32_BYTE_ALIGNED) + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/debug_utility/ring.h b/drivers/misc/mediatek/connectivity/common/debug_utility/ring.h new file mode 100644 index 00000000000000..81168ce8661515 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/debug_utility/ring.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +#ifndef _RING_H_ +#define _RING_H_ + +struct ring { + /* addr where ring buffer starts */ + void *base; + /* addr storing the next writable pos, guaranteed to be >= read except when write overflow, but it's ok. */ + unsigned int write; + /* addr storing the next readable pos, except when read == write as buffer empty */ + unsigned int read; + /* must be power of 2 */ + unsigned int max_size; +}; + +struct ring_segment { + /* addr points into ring buffer for read/write */ + void *ring_pt; + /* size to read/write */ + unsigned int sz; + /* pos in external data buffer to read/write */ + unsigned int data_pos; + /* the size to be read/write after this segment completed */ + unsigned int remain; +}; + +void ring_init(void *base, unsigned int max_size, unsigned int read, + unsigned int write, struct ring *ring); +unsigned int ring_read_prepare(unsigned int sz, struct ring_segment *seg, struct ring *ring); +#define ring_read_all_prepare(seg, ring) ring_read_prepare((ring)->max_size, seg, ring) +unsigned int ring_write_prepare(unsigned int sz, struct ring_segment *seg, struct ring *ring); +unsigned int ring_overwrite_prepare(unsigned int sz, + struct ring_segment *seg, struct ring *ring); + +/* making sure max_size is power of 2 */ +#define RING_VALIDATE_SIZE(max_size) WARN_ON(!max_size || (max_size & (max_size - 1))) + +#define RING_EMPTY(ring) ((ring)->read == (ring)->write) +/* equation works even when write overflow */ +#define RING_SIZE(ring) ((ring)->write - (ring)->read) +#define RING_FULL(ring) (RING_SIZE(ring) == (ring)->max_size) +#define RING_WRITE_REMAIN_SIZE(ring) ((ring)->max_size - RING_SIZE(ring)) + +#define RING_READ_FOR_EACH(_sz, _seg, _ring) \ + for (ring_read_prepare(_sz, &(_seg), _ring), \ + _ring_segment_prepare((_ring)->read, &(_seg), (_ring)); \ + (_seg).sz > 0; \ + _ring_read_commit(&(_seg), (_ring)), _ring_segment_prepare((_ring)->read, \ + &(_seg), (_ring))) + +#define RING_READ_ALL_FOR_EACH(seg, ring) RING_READ_FOR_EACH((ring)->max_size, seg, ring) + +#define RING_READ_FOR_EACH_ITEM(_sz, _seg, _ring) \ + for (ring_read_prepare(_sz, &(_seg), _ring), \ + _ring_segment_prepare_item((_ring)->read, &(_seg), (_ring)); \ + (_seg).sz > 0; \ + _ring_read_commit(&(_seg), (_ring)), _ring_segment_prepare_item((_ring)->read, \ + &(_seg), (_ring))) + +#define RING_WRITE_FOR_EACH(_sz, _seg, _ring) \ + for (ring_write_prepare(_sz, &(_seg), _ring),\ + _ring_segment_prepare((_ring)->write, &(_seg), (_ring)); \ + (_seg).sz > 0; \ + _ring_write_commit(&(_seg), (_ring)), _ring_segment_prepare((_ring)->write, \ + &(_seg), (_ring))) + +#define RING_OVERWRITE_FOR_EACH(_sz, _seg, _ring) \ + for (ring_overwrite_prepare(_sz, &(_seg), _ring), \ + _ring_segment_prepare((_ring)->write, &(_seg), (_ring)); \ + (_seg).sz > 0; \ + _ring_write_commit(&(_seg), (_ring)), _ring_segment_prepare((_ring)->write, \ + &(_seg), (_ring))) + +void ring_dump(const char *title, struct ring *ring); +void ring_dump_segment(const char *title, struct ring_segment *seg); + + +/* ring Buffer Internal API */ +void _ring_segment_prepare(unsigned int from, struct ring_segment *seg, struct ring *ring); +void _ring_segment_prepare_item(unsigned int from, struct ring_segment *seg, struct ring *ring); +void _ring_read_commit(struct ring_segment *seg, struct ring *ring); +void _ring_write_commit(struct ring_segment *seg, struct ring *ring); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/debug_utility/ring_emi.c b/drivers/misc/mediatek/connectivity/common/debug_utility/ring_emi.c new file mode 100644 index 00000000000000..9b34eab566734e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/debug_utility/ring_emi.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +#include "ring_emi.h" +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/bug.h> + +void ring_emi_init(void *base, unsigned int max_size, void *read, void *write, struct ring_emi *ring_emi) +{ + WARN_ON(!base || !read || !write); + + /* making sure max_size is power of 2 */ + WARN_ON(!max_size || (max_size & (max_size - 1))); + + /* making sure read & write pointers are 4 bytes aligned */ + WARN_ON(((long)read & 0x3) != 0 || ((long)write & 0x3) != 0); + + ring_emi->base = base; + ring_emi->read = read; + ring_emi->write = write; + EMI_WRITE32(ring_emi->write, 0); + EMI_WRITE32(ring_emi->read, 0); + ring_emi->max_size = max_size; + pr_info("base: %p, read: %p, write: %p, max_size: %d\n", base, read, write, max_size); +} + +void ring_emi_dump(const char *title, struct ring_emi *ring_emi) +{ + pr_info("[%s] ring_emi:{base=0x%p, write=%d, read=%d, max_size=%d}\n", + title, ring_emi->base, EMI_READ32(ring_emi->write), + EMI_READ32(ring_emi->read), ring_emi->max_size); +} + +void ring_emi_dump_segment(const char *title, struct ring_emi_segment *seg) +{ + pr_info("[%s] seg:{ring_emi_pt=0x%p, data_pos=%d, sz=%d, remain=%d}\n", + title, seg->ring_emi_pt, seg->data_pos, seg->sz, seg->remain); +} + +/* + * Function prepares the ring_emi_segment and returns the number of valid bytes for read. + */ +unsigned int ring_emi_read_prepare(unsigned int sz, struct ring_emi_segment *seg, struct ring_emi *ring_emi) +{ + unsigned int wt = EMI_READ32(ring_emi->write); + unsigned int rd = EMI_READ32(ring_emi->read); + + memset(seg, 0, sizeof(struct ring_emi_segment)); +#ifdef ROUND_REPEAT + if (wt >= rd) { + if (sz > wt - rd) + sz = wt - rd; + seg->remain = sz; + } else { + if (sz > ring_emi->max_size - (rd - wt)) + sz = ring_emi->max_size - (rd - wt); + seg->remain = sz; + } +#else + if (sz > wt - rd) + sz = wt - rd; + seg->remain = sz; +#endif + /* ring_emi_dump(__func__, ring_emi); */ + /* ring_emi_dump_segment(__func__, seg); */ + return seg->remain; +} + +/* + * Function prepares the ring_emi_segment and returns the number of bytes available for write. + */ +unsigned int ring_emi_write_prepare(unsigned int sz, struct ring_emi_segment *seg, struct ring_emi *ring_emi) +{ + unsigned int wt = EMI_READ32(ring_emi->write); + unsigned int rd = EMI_READ32(ring_emi->read); + + memset(seg, 0, sizeof(struct ring_emi_segment)); +#ifdef ROUND_REPEAT + if (wt >= rd) + seg->remain = ring_emi->max_size - (wt - rd + 1); + else + seg->remain = ring_emi->max_size - (rd - wt + 1); + + if (sz <= seg->remain) + seg->remain = sz; +#else + if (sz > ring_emi->max_size - (wt - rd)) + sz = ring_emi->max_size - (wt - rd); + seg->remain = sz; +#endif + /* ring_emi_dump(__func__, ring_emi); */ + /* ring_emi_dump_segment(__func__, seg); */ + return seg->remain; +} + +void _ring_emi_segment_prepare(unsigned int from, struct ring_emi_segment *seg, struct ring_emi *ring_emi) +{ +#ifndef ROUND_REPEAT + unsigned int ring_emi_pos = from & (ring_emi->max_size - 1); + + seg->ring_emi_pt = ring_emi->base + ring_emi_pos; +#else + seg->ring_emi_pt = ring_emi->base + from; +#endif + seg->data_pos = (seg->sz ? seg->data_pos + seg->sz : 0); + if (from + seg->remain <= ring_emi->max_size) + seg->sz = seg->remain; + else + seg->sz = ring_emi->max_size - from; + seg->remain -= seg->sz; + /* ring_emi_dump(__func__, ring_emi); */ + /* ring_emi_dump_segment(__func__, seg); */ +} + +void _ring_emi_read_commit(struct ring_emi_segment *seg, struct ring_emi *ring_emi) +{ +#ifdef ROUND_REPEAT + EMI_WRITE32(ring_emi->read, (EMI_READ32(ring_emi->read) + seg->sz) & (ring_emi->max_size - 1)); +#else + EMI_WRITE32(ring_emi->read, EMI_READ32(ring_emi->read) + seg->sz); +#endif + /* *(ring_emi->read) += seg->sz; */ + /* ring_emi_dump(__func__, ring_emi); */ + /* ring_emi_dump_segment(__func__, seg); */ +} +void _ring_emi_write_commit(struct ring_emi_segment *seg, struct ring_emi *ring_emi) +{ +#ifdef ROUND_REPEAT + EMI_WRITE32(ring_emi->write, (EMI_READ32(ring_emi->write) + seg->sz) & (ring_emi->max_size - 1)); +#else + EMI_WRITE32(ring_emi->write, EMI_READ32(ring_emi->write) + seg->sz); +#endif + /* ring_emi_dump(__func__, ring_emi); */ + /* ring_emi_dump_segment(__func__, seg); */ +} + diff --git a/drivers/misc/mediatek/connectivity/common/debug_utility/ring_emi.h b/drivers/misc/mediatek/connectivity/common/debug_utility/ring_emi.h new file mode 100644 index 00000000000000..30e9e475e7c0f8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/debug_utility/ring_emi.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +#ifndef _RING_EMI_H_ +#define _RING_EMI_H_ + +#include <linux/io.h> +#define ROUND_REPEAT +#define EMI_READ32(addr) (readl(addr)) +#define EMI_WRITE32(addr, data) (writel(data, addr)) + +struct ring_emi { + /* addr where ring buffer starts */ + void *base; + /* addr storing the next writable pos, guaranteed to be >= read except when write overflow, but it's ok. */ + void *write; + /* addr storing the next readable pos, except when read == write as buffer empty */ + void *read; + /* must be power of 2 */ + unsigned int max_size; +}; + +struct ring_emi_segment { + /* addr points into ring buffer for read/write */ + void *ring_emi_pt; + /* size to read/write */ + unsigned int sz; + /* pos in external data buffer to read/write */ + unsigned int data_pos; + /* the size to be read/write after this segment completed */ + unsigned int remain; +}; + +void ring_emi_init(void *base, unsigned int max_size, void *read, void *write, struct ring_emi *ring_emi); +unsigned int ring_emi_read_prepare(unsigned int sz, struct ring_emi_segment *seg, struct ring_emi *ring_emi); +#define ring_emi_read_all_prepare(seg, ring_emi) ring_emi_read_prepare((ring_emi)->max_size, seg, ring_emi) +unsigned int ring_emi_write_prepare(unsigned int sz, struct ring_emi_segment *seg, struct ring_emi *ring_emi); + +/* making sure max_size is power of 2 */ +#define RING_EMI_VALIDATE_SIZE(max_size) WARN_ON(!max_size || (max_size & (max_size - 1))) + +#define RING_EMI_EMPTY(ring_emi) (EMI_READ32((ring_emi)->read) == EMI_READ32((ring_emi)->write)) +/* equation works even when write overflow */ +#define RING_EMI_SIZE(ring_emi) (EMI_READ32((ring_emi)->write) - EMI_READ32((ring_emi)->read)) +#ifdef ROUND_REPEAT +#define RING_EMI_FULL(ring_emi) (((EMI_READ32((ring_emi)->write) + 1) & ((ring_emi)->max_size - 1)) \ + == EMI_READ32((ring_emi)->read)) +#else +#define RING_EMI_FULL(ring_emi) (RING_EMI_SIZE(ring_emi) == (ring_emi)->max_size) +#endif + +#define RING_EMI_READ_FOR_EACH(_sz, _seg, _ring_emi) \ + for (_ring_emi_segment_prepare(EMI_READ32((_ring_emi)->read), &(_seg), (_ring_emi)); \ + (_seg).sz > 0; \ + _ring_emi_read_commit(&(_seg), (_ring_emi)), \ + _ring_emi_segment_prepare(EMI_READ32((_ring_emi)->read), &(_seg), (_ring_emi))) + +#define RING_EMI_READ_ALL_FOR_EACH(seg, ring_emi) RING_EMI_READ_FOR_EACH((ring_emi)->max_size, seg, ring_emi) + +#define RING_EMI_WRITE_FOR_EACH(_sz, _seg, _ring_emi) \ + for (_ring_emi_segment_prepare(EMI_READ32((_ring_emi)->write), &(_seg), (_ring_emi)); \ + (_seg).sz > 0; \ + _ring_emi_write_commit(&(_seg), (_ring_emi)), \ + _ring_emi_segment_prepare(EMI_READ32((_ring_emi)->write), &(_seg), (_ring_emi))) + +void ring_emi_dump(const char *title, struct ring_emi *ring_emi); +void ring_emi_dump_segment(const char *title, struct ring_emi_segment *seg); + + +/* Ring Buffer Internal API */ +void _ring_emi_segment_prepare(unsigned int from, struct ring_emi_segment *seg, struct ring_emi *ring_emi); +void _ring_emi_read_commit(struct ring_emi_segment *seg, struct ring_emi *ring_emi); +void _ring_emi_write_commit(struct ring_emi_segment *seg, struct ring_emi *ring_emi); + +#endif diff --git a/drivers/misc/mediatek/connectivity/common/debug_utility/tool/connsys_log_AT/connsys_debut_utility_tester.bat b/drivers/misc/mediatek/connectivity/common/debug_utility/tool/connsys_log_AT/connsys_debut_utility_tester.bat new file mode 100644 index 00000000000000..ad6610c04477f0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/debug_utility/tool/connsys_log_AT/connsys_debut_utility_tester.bat @@ -0,0 +1,5 @@ +SET log_path=output + +python dedicated_log_path_test.py %log_path% + +PAUSE \ No newline at end of file diff --git a/drivers/misc/mediatek/connectivity/common/debug_utility/tool/connsys_log_AT/dedicated_log_path_test.py b/drivers/misc/mediatek/connectivity/common/debug_utility/tool/connsys_log_AT/dedicated_log_path_test.py new file mode 100644 index 00000000000000..7ce453428120e9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/debug_utility/tool/connsys_log_AT/dedicated_log_path_test.py @@ -0,0 +1,134 @@ +# +# Copyright (C) 2016 MediaTek Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See http://www.gnu.org/licenses/gpl-2.0.html for more details. +# + +import sys, os, time +import subprocess +import re +import optparse + +emi_log = 'emi.log' +out_path = '' +MCU_INDEX = 0 +WIFI_INDEX = 1 +BT_INDEX =2 +GPS_INDEX = 3 +WMTDRV_TYPE_BT = 0 +WMTDRV_TYPE_GPS = 2 +WMTDRV_TYPE_WIFI = 3 + +def get_last_emi_log(log_fd, num_line): + log_list = [] + for line in log_fd: + if line.find('emi:') > 0: + log_list.append(line) + num_line *= -1 + return log_list[num_line:] + +def dump_emi(offset, size): + global out_path + dump_emi_init_cmd = "adb shell \"echo 0x2d " + hex(offset) + " " + hex(size) + " " + "> /proc/driver/wmt_dbg\"" + get_emi_log_cmd = "adb shell \"dmesg | grep emi\" > " + os.path.join(out_path, emi_log) + subprocess.call(dump_emi_init_cmd, shell=True) + subprocess.call(get_emi_log_cmd, shell=True) + log_fd = open(os.path.join(out_path, emi_log), 'rb') + log_list = get_last_emi_log(log_fd, 4) + log_fd.close + return log_list + +def find_base_addr(line_list): + base_addr_list = [] + count = 0 + for line in line_list: + # print line + base_addr = '' + pos = line.find('emi:') + digit_list = line[pos+4:].split(' ') + for no, dig in enumerate(digit_list, start=1): + if len(dig) == 2: + base_addr = dig + base_addr + if no % 4 == 1: + count+=1 + if count % 2 == 1: + base_addr_list.append(int(base_addr, 16)) + base_addr = '' + if count >= 8: + break + return base_addr_list + +def subsys_test(line_list, subsys_name): + for line in line_list: + base_addr = '' + count = 0 + pos = line.find('emi:') + digit_list = line[pos+4:].split(' ') + for no, dig in enumerate(digit_list, start=1): + if len(dig) == 2: + base_addr = dig + base_addr + if no % 4 == 1: + if int(base_addr, 16) > 0: + count += 1 + if count == 2: + print '------------------->' + subsys_name + ' connsys log Test PASS!' + return; + base_addr = '' + print '------------------->' + subsys_name + ' connsys log Test FAIL!' + +def subsys_fucn_ctrl(wmtdrv_type, on): + func_ctrl_cmd = "adb shell \"echo 0x07 " + hex(wmtdrv_type) + " " + hex(on) + " " + "> /proc/driver/wmt_dbg\"" + subprocess.call(func_ctrl_cmd, shell=True) + if on == 1: + time.sleep(5) + else: + time.sleep(1) + +def main(): + global out_path + out_folder = sys.argv[1] + out_path = os.path.join(os.getcwd(), out_folder) + print out_path + if(not os.path.exists(out_path)): + os.makedirs(out_path) + + line_list = dump_emi(0, 64) + base_addr_list = [] + + # TEST CASE1 INIT + if line_list[-1].find('EMIFWLOG'): + print '------------------->' + 'Connsys Debug Utility init Test PASS!' + else: + print 'EMIFWLOG not found.' + print '------------------->' + 'Connsys Debug Utility init Test FAIL!' + return + + base_addr_list = find_base_addr(line_list) + print 'subsys base address offset:' + print base_addr_list + + subsys_fucn_ctrl(WMTDRV_TYPE_WIFI, 1) + line_list = dump_emi(base_addr_list[WIFI_INDEX], 64) + subsys_test(line_list, 'WIFI') + + subsys_fucn_ctrl(WMTDRV_TYPE_BT, 1) + line_list = dump_emi(base_addr_list[BT_INDEX], 64) + subsys_test(line_list, 'BT') + + ygps_cmd = "adb shell \"am start -n com.mediatek.ygps/.YgpsActivity\"" + subprocess.call(ygps_cmd, shell=True) + time.sleep(30) + line_list = dump_emi(base_addr_list[GPS_INDEX], 64) + subsys_test(line_list, 'GPS') + ygps_cmd = "adb shell \"am force-stop com.mediatek.ygps\"" + time.sleep(1) + +if __name__ == '__main__': + main() diff --git a/drivers/misc/mediatek/connectivity/common/debug_utility/tool/connsys_log_tool/connsys_log_converter.py b/drivers/misc/mediatek/connectivity/common/debug_utility/tool/connsys_log_tool/connsys_log_converter.py new file mode 100644 index 00000000000000..56db892dc4228e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/debug_utility/tool/connsys_log_tool/connsys_log_converter.py @@ -0,0 +1,174 @@ + +# +# Copyright (C) 2016 MediaTek Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See http://www.gnu.org/licenses/gpl-2.0.html for more details. +# + +import sys +import re +import time +import os +import datetime +import codecs +import struct + +LogHeader = b'\x00\x00\x62' +InfoHeader = b'\x00\x25\x62' +TimeSyncLog = b'\x74\x69\x6D\x65' +LostLog = b'\x6C\x6F\x73\x74' +UTC_DIFF = 0 +UtcTime = 0 +systemTime = 0 + +# write time log +# ex: 01-01 08:34:46.372470 ( 79.231659) +def write_time_title(fh_out, utc_time, system_time): + utcTimeInt = int(utc_time) + utcTimeFrac = utc_time - utcTimeInt + systemTimeInt = int(system_time) + systemTimeFrac = system_time - systemTimeInt + fh_out.write(time.strftime("%m-%d %H:%M:%S", time.gmtime(utcTimeInt)) + ("%.6f " % utcTimeFrac)[1:] + "(%5d" % systemTimeInt + ("%.6f) " % systemTimeFrac)[1:]) + +# check time sync log +# update UTC_DIFF if utc log is chaged +def update_time_sync(fh, fh_out): + global UTC_DIFF + global UtcTime + global systemTime + fh.read(8) # skip 24 byte in header + systemTime = struct.unpack("<I",fh.read(4))[0] + systemTime /= 1.0 + systemTime /= 32768 + UtcTime = struct.unpack("<I",fh.read(4))[0] + usec = struct.unpack("<I",fh.read(4))[0] + usec /= 1.0 + usec /= 1000000 + UtcTime += usec + tmpDiff = UtcTime - systemTime + # write timesync only if UTC time changed + if(tmpDiff != UTC_DIFF): + UTC_DIFF = tmpDiff + write_time_title(fh_out, UtcTime, systemTime); + fh_out.write("timesync\n") + +def show_lost_counter(fh, fh_out): + fh_out.write("lost" + fh.read(20) + "\n") + +def find_1st_timesync_from_here(pos, fh, fh_out): + fh.seek(pos) + while True: + byte = fh.read(1) + if byte == '': + if UTC_DIFF == 0: + fh_out.write("No found timesync log in this file.\n") + break; + if byte == b'\x55': + bytes = fh.read(3) + if bytes == InfoHeader: + # skip 12 bytes header data + fh.read(12) + bytes = fh.read(4) + if bytes == TimeSyncLog: + update_time_sync(fh, fh_out) + break + +# parse all file in sub folder +def walk_all_file(folderName): + # print "walk all file - ", folderName + for path, subdirs, files in os.walk(folderName): + for name in files: + # print os.path.join(path, name) + # print "convert_file: ", os.path.abspath(name) + convert_file(os.path.join(path, name)) + +def convert_file(srcFile): + global UTC_DIFF + global UtcTime + global systemTime + + name = os.path.basename(srcFile) + # only support file name starts and ends with + # WIFI_FW_2010_0101_001720.clog or WIFI_FW_2010_0101_001720.clog.curl + # GPS_FW_2010_0101_003427.clog or GPS_FW_2010_0101_003427.clog.curl + if(not((name.startswith('GPS_FW_') or name.startswith('WIFI_FW_') or name.startswith('MCU_FW_')) and (name.endswith('.clog') or name.endswith('.curf')))): + return + + # create converted file name + fileSize = os.path.getsize(srcFile) + outputFile = os.path.abspath(srcFile) + ".txt" + print "convert_file: ", outputFile + try: + fh = open(srcFile, "rb") + fhout = open(outputFile, "w") + except IOError as err: + print err + sys.exit() + + # find 1st time sync log + find_1st_timesync_from_here(0, fh, fhout) + + # parse file + fh.seek(0) + while True: + byte = fh.read(1) + if byte == '': + break; + + if byte == b'\x55': + bytes = fh.read(3) + # parse normal log + if bytes == LogHeader: + fh.read(4); # skip 4 byte REM NUM + timeStamp = struct.unpack("<I",fh.read(4))[0] + timeStamp /= 1.0 + timeStamp /= 32768 + utc_time = UTC_DIFF + timeStamp + write_time_title(fhout, utc_time, timeStamp) + fh.read(2); # skip 2 byte TASK ID + bufLen = struct.unpack("<h",fh.read(2))[0] + log_buf = fh.read(bufLen) + fhout.write(log_buf) + # if log end has no \n, append \n + if len(log_buf) != 0 and log_buf[-1] != b'\x0a': + fhout.write('\n') + continue + + # Parse time sync log + elif bytes == InfoHeader: + # skip 12 bytes header data + fh.read(12) + bytes = fh.read(4) + if bytes == TimeSyncLog: + update_time_sync(fh, fhout) + elif bytes == LostLog: + show_lost_counter(fh, fhout) + # since lost some log, to find last time sync + find_1st_timesync_from_here(fh.tell(), fh, fhout) + fh.seek(fh.tell()) + continue + + try: + fh.close() + fhout.close() + except IOError as err: + print err + sys.exit() + +if __name__ == '__main__': + inputArg = os.path.abspath(sys.argv[1]) + if os.path.exists(inputArg): + if os.path.isdir(inputArg): + walk_all_file(inputArg) + else: + convert_file(inputArg) + sys.exit() + else: + print "file/dir not exist" diff --git a/drivers/misc/mediatek/connectivity/common/debug_utility/tool/connsys_log_tool/kernel_to_utc.py b/drivers/misc/mediatek/connectivity/common/debug_utility/tool/connsys_log_tool/kernel_to_utc.py new file mode 100644 index 00000000000000..e2d348ae1d473f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/debug_utility/tool/connsys_log_tool/kernel_to_utc.py @@ -0,0 +1,158 @@ + +# +# Copyright (C) 2016 MediaTek Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See http://www.gnu.org/licenses/gpl-2.0.html for more details. +# + +''' +Created on 2012/11/14 + +Convert kernel time stamp in each line of a kernel log, +prepend the converted local time in the beginning of each line. +The time stamp reference is from the log of the following pattern: + +...[<kernel time>] ... android time <local time> + +such as: +<4>[12175.130847] (0)[62:wdtk-0][cpu-0:thread:62] 2012-08-02 03:41:18.94083 UTC; android time 2012-08-02 11:41:18.94083 +<5>[25676.236787] (0)[313:InputReader][request_suspend_state]: wakeup (0->0) at 25665623103493 (2012-11-19 08:03:43.654473155 UTC) +<6>[ 344.427890] (0)[41:binder_watchdog]binder: 54296 exec 1354:1380 to 110:333 over 4.011 sec () dex_code 4 start_at 581.260 2012-01-02 00:06:18.728 +<6>[ 160.699284] (0)[44:binder_watchdog]binder: 15889 read 563:1223 to 1076:0 over 2.257 sec () dex_code 44 start_at 158.372 android 2013-04-26 21:57:28.624 +<6>[26064.469194].(4)[6320:kworker/u:1]PM: suspend exit 2013-10-12 06:18:48.551577654 UTC +[ 5.219499] .(2)[1:swapper/0]mt-rtc mt-rtc: setting system clock to 2018-01-25 01:24:36 UTC (1516843476) +[ 67.101501] .(1)[249:wdtk-1][name:wd_common_drv&][thread:249][RT:67101493390] 2018-01-25 01:25:38.382875 UTC;android time 2018-01-25 01:25:38.382875 + +''' + +import sys +import re +import time +import os +import datetime +from bisect import bisect_right + +def kernel_to_utc(klog, llog): + # if llog == '-', output to stdout + line = 0 + line_timestamp = [] + diff_timestamp = [] + debug_enable = False + _stdout = True if llog == '-' else False + + # first pass + try: + fh = open(klog, "rb") + if _stdout: + fhout = sys.stdout + else: + fhout = open(llog, "w") + except IOError as err: + print err + sys.exit() + + _re_utc_time = re.compile(r"[^\[]*?\[[ ]*(\d+?\.\d+)\].*?(\d+-\d+-\d+ \d+:\d+:\d+)(\.\d+) UTC") + + for linebuf in fh: + line = line + 1 + + if "UTC" not in linebuf: + continue + + m = _re_utc_time.match(linebuf) + if m: + (ktime, atime, usec) = m.group(1,2,3) + time_sec_int = time.mktime(time.strptime(atime, "%Y-%m-%d %H:%M:%S")) + time_sec = time_sec_int + float(usec) - float(ktime) + + if (debug_enable): + print "*" + print linebuf + print ktime, atime, usec + + line_timestamp.append(line) + diff_timestamp.append(time_sec) + + + # second pass + fh.seek(0, os.SEEK_SET) + + if debug_enable: + print len(line_timestamp),",",len(diff_timestamp) + print line_timestamp + print diff_timestamp + + line_ts_ref = -1 + diff_ts_ref = 0 + + # in case no timestamp exist + if line_timestamp: + line_ts_ref = line_timestamp[0] + diff_ts_ref = diff_timestamp[0] + + # _re_ktime = re.compile(r"^[ ]*?<[^>]+>\[[ ]*?(\d+?\.\d+?)\]") + _re_ktime = re.compile(r"^[^\[]*?\[[ ]*?(\d+?\.\d+?)\]") + + line = 0 + for linebuf in fh: + diff_ts = -1 + line = line + 1 + + m = _re_ktime.match(linebuf) + if m: + diff_ts = float(m.group(1)) + + if line == line_ts_ref: + line_timestamp.pop(0) + line_ts_ref = line_timestamp[0] if line_timestamp else sys.maxint + diff_ts_ref = diff_timestamp.pop(0) + + if debug_enable: print "diff_ts_ref: ", diff_ts_ref + + if diff_ts != -1: + if line_ts_ref != -1: + android_time = diff_ts + diff_ts_ref + android_time_int = int(android_time) + android_time_frac = android_time - android_time_int + + ts = time.localtime(android_time_int) + + fhout.write(time.strftime("%m-%d %H:%M:%S", ts) + ("%.6f " % android_time_frac)[1:]) + else: + fhout.write("??-?? ??:??:??.?????? ") + + fhout.write(linebuf) + + # for debug + # print linebuf, + + try: + fhout.close() + if not _stdout: + fh.close() + except IOError as err: + print err + sys.exit() + + +if __name__ == "__main__": + if (len(sys.argv) not in [2, 3]): + print "Usage: ", sys.argv[0], " <kernel log> [-]" + sys.exit() + + _stdout = False + if len(sys.argv) == 3 and sys.argv[2] == '-': + _stdout = True + + if _stdout: + kernel_to_utc(sys.argv[1],'-') + else: + kernel_to_utc(sys.argv[1],sys.argv[1]+".utc") + sys.exit() diff --git a/drivers/misc/mediatek/connectivity/common/init.wmt_drv.rc b/drivers/misc/mediatek/connectivity/common/init.wmt_drv.rc new file mode 100644 index 00000000000000..732a4cd8c3b27f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/init.wmt_drv.rc @@ -0,0 +1,2 @@ +on boot + insmod /vendor/lib/modules/wmt_drv.ko diff --git a/drivers/misc/mediatek/connectivity/common/test/include/wmt_step_test.h b/drivers/misc/mediatek/connectivity/common/test/include/wmt_step_test.h new file mode 100644 index 00000000000000..c8de0418cac776 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/test/include/wmt_step_test.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 MediaTek Inc. * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _WMT_STEP_TEST_H_ +#define _WMT_STEP_TEST_H_ + +#include "osal.h" +#include "wmt_step.h" + +#define STEP_TEST_CONSYS_EMI_WMT_OFFSET 0x68000 + +#define TEST_FAIL -1 +#define TEST_PASS 0 +#define TEST_CHECK 1 +#define STEP_TEST_ACTION_NUMBER 30 + +extern struct step_env_struct g_step_env; +extern struct platform_device *g_pdev; + +struct step_test_report { + unsigned int pass; + unsigned int fail; + unsigned int check; +}; + +struct step_test_check { + unsigned int step_check_total; + int step_check_test_tp_id[STEP_TEST_ACTION_NUMBER]; + int step_check_test_act_id[STEP_TEST_ACTION_NUMBER]; + char *step_check_params[STEP_TEST_ACTION_NUMBER][STEP_PARAMETER_SIZE]; + int step_check_params_num[STEP_TEST_ACTION_NUMBER]; + unsigned int step_check_index; + int step_check_result; + char *step_check_result_string; + int step_check_result_value; + unsigned int step_check_emi_offset[STEP_TEST_ACTION_NUMBER]; + SIZE_T step_check_register_addr; + SIZE_T step_check_write_value; + unsigned int step_test_mask; + unsigned int step_recovery_value; + int step_check_temp_register_id; +}; + +void wmt_step_test_all(void); +void wmt_step_test_read_file(struct step_test_report *p_report); +void wmt_step_test_parse_data(struct step_test_report *p_report); +void wmt_step_test_create_emi_action(struct step_test_report *p_report); +void wmt_step_test_create_cond_emi_action(struct step_test_report *p_report); +void wmt_step_test_create_register_action(struct step_test_report *p_report); +void wmt_step_test_create_cond_register_action(struct step_test_report *p_report); +void wmt_step_test_check_register_symbol(struct step_test_report *p_report); +void wmt_step_test_create_other_action(struct step_test_report *p_report); +void wmt_step_test_do_emi_action(struct step_test_report *p_report); +void wmt_step_test_do_cond_emi_action(struct step_test_report *p_report); +void wmt_step_test_do_register_action(struct step_test_report *p_report); +void wmt_step_test_do_cond_register_action(struct step_test_report *p_report); +void wmt_step_test_do_gpio_action(struct step_test_report *p_report); +void wmt_step_test_do_disable_reset_action(struct step_test_report *p_report); +void wmt_step_test_do_chip_reset_action(struct step_test_report *p_report); +void wmt_step_test_do_wakeup_action(struct step_test_report *p_report); +void wmt_step_test_create_periodic_dump(struct step_test_report *p_report); +void wmt_step_test_do_show_action(struct step_test_report *p_report); +void wmt_step_test_do_sleep_action(struct step_test_report *p_report); +void wmt_step_test_do_condition_action(struct step_test_report *p_report); +void wmt_step_test_do_value_action(struct step_test_report *p_report); + +#endif /* end of _WMT_STEP_TEST_H_ */ + diff --git a/drivers/misc/mediatek/connectivity/common/test/wmt_step_test.c b/drivers/misc/mediatek/connectivity/common/test/wmt_step_test.c new file mode 100644 index 00000000000000..dbc10fec75dff6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/common/test/wmt_step_test.c @@ -0,0 +1,4956 @@ +/* + * Copyright (C) 2016 MediaTek Inc. * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include <linux/platform_device.h> +#include "osal.h" +#include "wmt_step_test.h" +#include "wmt_step.h" +#include "wmt_exp.h" +#include "wmt_lib.h" +#include "mtk_wcn_consys_hw.h" +#include "stp_core.h" +#include "wmt_dbg.h" + +struct step_test_check g_step_test_check; + +void wmt_step_test_clear_parameter(char *params[]) +{ + int i = 0; + + for (i = 0; i < STEP_PARAMETER_SIZE; i++) + params[i] = NULL; +} + +#define index_of_array(current_addr, base_addr, type) \ + (((unsigned long)current_addr - (unsigned long)base_addr) / sizeof(type)) + +int wmt_step_test_check_write_tp(struct step_action_list *p_act_list, enum step_action_id act_id, + int param_num, char *params[]) +{ + int index = g_step_test_check.step_check_index; + int i; + int tp_id; + + if (g_step_test_check.step_check_result == TEST_FAIL) + return 0; + + g_step_test_check.step_check_index++; + + if (g_step_test_check.step_check_test_tp_id[index] != -1) { + tp_id = index_of_array(p_act_list, &g_step_env.actions, struct step_action_list); + if (tp_id != g_step_test_check.step_check_test_tp_id[index]) { + g_step_test_check.step_check_result = TEST_FAIL; + WMT_ERR_FUNC("STEP test failed: tp_id %d: expect %d(%d)\n", tp_id, + g_step_test_check.step_check_test_tp_id[index], index); + return 0; + } + } + + if (act_id != g_step_test_check.step_check_test_act_id[index]) { + g_step_test_check.step_check_result = TEST_FAIL; + WMT_ERR_FUNC("STEP test failed: act_id %d: expect %d(%d)\n", act_id, + g_step_test_check.step_check_test_tp_id[index], index); + return 0; + } + + if (param_num != g_step_test_check.step_check_params_num[index]) { + g_step_test_check.step_check_result = TEST_FAIL; + WMT_ERR_FUNC("STEP test failed: param num %d: expect %d(%d)\n", param_num, + g_step_test_check.step_check_params_num[index], index); + return 0; + } + + for (i = 0; i < STEP_PARAMETER_SIZE; i++) { + if (osal_strcmp(g_step_test_check.step_check_params[index][0], "") == 0) + break; + + if (params[0] == NULL || osal_strcmp(params[0], g_step_test_check.step_check_params[index][0]) != 0) { + g_step_test_check.step_check_result = TEST_FAIL; + WMT_ERR_FUNC("STEP test failed: params[%d] %s: expect %s(%d)\n", i, params[0], + g_step_test_check.step_check_params[index][0], index); + return 0; + } + } + + g_step_test_check.step_check_result = TEST_PASS; + + return 0; +} + +int wmt_step_test_check_create_emi(struct step_emi_action *p_emi_act, int check_params[], + char *err_result) +{ + struct step_emi_info *p_emi_info = NULL; + int result = TEST_FAIL; + + p_emi_info = &p_emi_act->info; + if (p_emi_act->base.action_id != STEP_ACTION_INDEX_EMI) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_emi_act->base.action_id); + result = TEST_FAIL; + } else if (p_emi_info->output_mode == STEP_OUTPUT_LOG) { + if (p_emi_info->is_write != check_params[0] || + p_emi_info->begin_offset != check_params[1] || + p_emi_info->end_offset != check_params[2]) { + WMT_ERR_FUNC("%s, C1 emi log params: %d, %d, %d\n", + err_result, p_emi_info->is_write, p_emi_info->begin_offset, + p_emi_info->end_offset); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + } else if (p_emi_info->output_mode == STEP_OUTPUT_REGISTER) { + if (p_emi_info->is_write != check_params[0] || + p_emi_info->begin_offset != check_params[1] || + p_emi_info->mask != check_params[2] || + p_emi_info->temp_reg_id != check_params[3]) { + WMT_ERR_FUNC("%s, C2 emi reg params: %d, %d, %d, %d\n", + err_result, p_emi_info->is_write, p_emi_info->begin_offset, + p_emi_info->mask, p_emi_info->temp_reg_id); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + } else { + result = TEST_FAIL; + } + + return result; +} + +int wmt_step_test_check_create_condition_emi(struct step_condition_emi_action *p_cond_emi_act, int check_params[], + char *err_result) +{ + struct step_emi_info *p_emi_info = NULL; + int result = TEST_FAIL; + + p_emi_info = &p_cond_emi_act->info; + if (p_cond_emi_act->base.action_id != STEP_ACTION_INDEX_CONDITION_EMI) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_cond_emi_act->base.action_id); + result = TEST_FAIL; + } else if (p_emi_info->output_mode == STEP_OUTPUT_LOG) { + if (p_cond_emi_act->cond_reg_id != check_params[0] || + p_emi_info->is_write != check_params[1] || + p_emi_info->begin_offset != check_params[2] || + p_emi_info->end_offset != check_params[3]) { + WMT_ERR_FUNC("%s, C1 emi log params: %d, %d, %d, %d\n", + err_result, p_cond_emi_act->cond_reg_id, p_emi_info->is_write, + p_emi_info->begin_offset, p_emi_info->end_offset); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + } else if (p_emi_info->output_mode == STEP_OUTPUT_REGISTER) { + if (p_cond_emi_act->cond_reg_id != check_params[0] || + p_emi_info->is_write != check_params[1] || + p_emi_info->begin_offset != check_params[2] || + p_emi_info->mask != check_params[3] || + p_emi_info->temp_reg_id != check_params[4]) { + WMT_ERR_FUNC("%s, C2 emi reg params: %d, %d, %d, %d, %d\n", + err_result, p_cond_emi_act->cond_reg_id, p_emi_info->is_write, + p_emi_info->begin_offset, p_emi_info->mask, p_emi_info->temp_reg_id); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + } else { + result = TEST_FAIL; + } + + return result; +} + +int wmt_step_test_check_create_read_reg(struct step_reigster_info *p_reg_info, + int check_params[], char *err_result, int check_index) +{ + int result = TEST_FAIL; + + if (p_reg_info->address_type == STEP_REGISTER_PHYSICAL_ADDRESS) { + if (p_reg_info->address != check_params[check_index + 1] || + p_reg_info->offset != check_params[check_index + 2]) { + WMT_ERR_FUNC( + "%s, C1 reg params: %d, 0x%08x, %d\n", + err_result, p_reg_info->is_write, (unsigned int)p_reg_info->address, + p_reg_info->offset); + return TEST_FAIL; + } + } else { + if (p_reg_info->address_type != check_params[check_index + 1] || + p_reg_info->offset != check_params[check_index + 2]) { + WMT_ERR_FUNC( + "%s, C2 reg params: %d, 0x%08x, %d\n", + err_result, p_reg_info->is_write, (unsigned int)p_reg_info->address, + p_reg_info->offset); + return TEST_FAIL; + } + } + + if (p_reg_info->output_mode == STEP_OUTPUT_LOG) { + if (p_reg_info->times != check_params[check_index + 3] || + p_reg_info->delay_time != check_params[check_index + 4]) { + WMT_ERR_FUNC( + "%s, C3 reg params: %d, 0x%08x, %d, %d, %d\n", + err_result, p_reg_info->is_write, (unsigned int)p_reg_info->address, + p_reg_info->offset, p_reg_info->times, p_reg_info->delay_time); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + } else if (p_reg_info->output_mode == STEP_OUTPUT_REGISTER) { + if (p_reg_info->mask != check_params[check_index + 3] || + p_reg_info->temp_reg_id != check_params[check_index + 4]) { + WMT_ERR_FUNC( + "%s, C4 reg params: %d, 0x%08x, %d, %d, %d\n", + err_result, p_reg_info->is_write, (unsigned int)p_reg_info->address, + p_reg_info->offset, p_reg_info->mask, p_reg_info->temp_reg_id); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + } else { + result = TEST_FAIL; + } + + return result; +} + +int wmt_step_test_check_create_write_reg(struct step_reigster_info *p_reg_info, + int check_params[], char *err_result, int check_index) +{ + int result = TEST_FAIL; + + if (p_reg_info->address_type == STEP_REGISTER_PHYSICAL_ADDRESS) { + if (p_reg_info->address != check_params[check_index + 1] || + p_reg_info->offset != check_params[check_index + 2] || + p_reg_info->value != check_params[check_index + 3]) { + WMT_ERR_FUNC( + "%s, C1 reg params: %d, 0x%08x, %d, %d\n", + err_result, p_reg_info->is_write, (unsigned int)p_reg_info->address, + p_reg_info->offset, p_reg_info->value); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + } else { + if (p_reg_info->address_type != check_params[check_index + 1] || + p_reg_info->offset != check_params[check_index + 2] || + p_reg_info->value != check_params[check_index + 3]) { + WMT_ERR_FUNC( + "%s, C2 reg params: %d, %d, %d, %d\n", + err_result, p_reg_info->is_write, p_reg_info->address_type, + p_reg_info->offset, p_reg_info->value); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + } + + return result; +} + +int wmt_step_test_check_create_reg(struct step_register_action *p_reg_act, int check_params[], + char *err_result) +{ + struct step_reigster_info *p_reg_info = NULL; + int result = TEST_FAIL; + + p_reg_info = &p_reg_act->info; + if (p_reg_act->base.action_id != STEP_ACTION_INDEX_REGISTER) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_reg_act->base.action_id); + result = TEST_FAIL; + } else if (p_reg_info->is_write != check_params[0]) { + WMT_ERR_FUNC("%s, write failed: %d expect(%d)", err_result, p_reg_info->is_write, check_params[0]); + result = TEST_FAIL; + } else { + if (p_reg_info->is_write == 0) + result = wmt_step_test_check_create_read_reg(p_reg_info, check_params, err_result, 0); + else + result = wmt_step_test_check_create_write_reg(p_reg_info, check_params, err_result, 0); + } + + return result; +} + +int wmt_step_test_check_create_condition_reg(struct step_condition_register_action *p_cond_reg_act, int check_params[], + char *err_result) +{ + struct step_reigster_info *p_reg_info = NULL; + int result = TEST_FAIL; + + p_reg_info = &p_cond_reg_act->info; + if (p_cond_reg_act->base.action_id != STEP_ACTION_INDEX_CONDITION_REGISTER) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_cond_reg_act->base.action_id); + result = TEST_FAIL; + } else if (p_cond_reg_act->cond_reg_id != check_params[0]) { + WMT_ERR_FUNC("%s, reg id failed: %d expect(%d)", err_result, + p_cond_reg_act->cond_reg_id, check_params[0]); + result = TEST_FAIL; + } else if (p_reg_info->is_write != check_params[1]) { + WMT_ERR_FUNC("%s, write failed: %d expect(%d)", err_result, + p_reg_info->is_write, check_params[1]); + result = TEST_FAIL; + } else { + if (p_reg_info->is_write == 0) + result = wmt_step_test_check_create_read_reg(p_reg_info, check_params, err_result, 1); + else + result = wmt_step_test_check_create_write_reg(p_reg_info, check_params, err_result, 1); + } + + return result; +} + +int wmt_step_test_check_create_gpio(struct step_gpio_action *p_gpio_act, int check_params[], + char *err_result) +{ + int result = TEST_FAIL; + + if (p_gpio_act->base.action_id != STEP_ACTION_INDEX_GPIO) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_gpio_act->base.action_id); + result = TEST_FAIL; + } else if (p_gpio_act->is_write != check_params[0]) { + WMT_ERR_FUNC("%s, write failed: %d", err_result, p_gpio_act->is_write); + result = TEST_FAIL; + } else { + if (p_gpio_act->pin_symbol != check_params[1]) { + WMT_ERR_FUNC("%s, gpio params: %d, %d\n", + err_result, p_gpio_act->is_write, p_gpio_act->pin_symbol); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + } + + return result; +} + +int wmt_step_test_check_create_drst(struct step_disable_reset_action *p_drst_act, int check_params[], + char *err_result) +{ + int result = TEST_FAIL; + + if (p_drst_act->base.action_id != STEP_ACTION_INDEX_DISABLE_RESET) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_drst_act->base.action_id); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + + return result; +} + +int wmt_step_test_check_create_crst(struct step_chip_reset_action *p_crst_act, int check_params[], + char *err_result) +{ + int result = TEST_FAIL; + + if (p_crst_act->base.action_id != STEP_ACTION_INDEX_CHIP_RESET) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_crst_act->base.action_id); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + + return result; +} + +int wmt_step_test_check_create_keep_wakeup(struct step_keep_wakeup_action *p_kwak_act, + int check_params[], char *err_result) +{ + int result = TEST_FAIL; + + if (p_kwak_act->base.action_id != STEP_ACTION_INDEX_KEEP_WAKEUP) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_kwak_act->base.action_id); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + + return result; +} + +int wmt_step_test_check_create_cancel_wakeup(struct step_cancel_wakeup_action *p_cwak_act, + int check_params[], char *err_result) +{ + int result = TEST_FAIL; + + if (p_cwak_act->base.action_id != STEP_ACTION_INDEX_CANCEL_WAKEUP) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_cwak_act->base.action_id); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + + return result; +} + +int wmt_step_test_check_create_periodic_dump(struct step_periodic_dump_action *p_pd_act, + int check_params[], char *err_result) +{ + int result = TEST_FAIL; + + if (p_pd_act->base.action_id != STEP_ACTION_INDEX_PERIODIC_DUMP) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_pd_act->base.action_id); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + + return result; +} + +int wmt_step_test_check_create_show_string(struct step_show_string_action *p_show_act, + int check_params[], char *err_result) +{ + int result = TEST_FAIL; + + if (p_show_act->base.action_id != STEP_ACTION_INDEX_SHOW_STRING) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_show_act->base.action_id); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + + return result; +} + +int wmt_step_test_check_create_sleep(struct step_sleep_action *p_sleep_act, + int check_params[], char *err_result) +{ + int result = TEST_FAIL; + + if (p_sleep_act->base.action_id != STEP_ACTION_INDEX_SLEEP) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_sleep_act->base.action_id); + result = TEST_FAIL; + } else if (p_sleep_act->ms != check_params[0]) { + WMT_ERR_FUNC("%s, param failed: %d expect(%d)", err_result, p_sleep_act->ms, check_params[0]); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + + return result; +} + +int wmt_step_test_check_create_condition(struct step_condition_action *p_cond_act, + int check_params[], char *err_result) +{ + int result = TEST_FAIL; + + if (p_cond_act->base.action_id != STEP_ACTION_INDEX_CONDITION) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_cond_act->base.action_id); + result = TEST_FAIL; + } else if (p_cond_act->result_temp_reg_id != check_params[0] || + p_cond_act->l_temp_reg_id != check_params[1] || + p_cond_act->operator_id != check_params[2]) { + WMT_ERR_FUNC("%s, C1 param failed: %d %d %d %d expect(%d %d %d %d)", + err_result, p_cond_act->result_temp_reg_id, p_cond_act->l_temp_reg_id, + p_cond_act->operator_id, p_cond_act->r_temp_reg_id, + check_params[0], check_params[1], check_params[2], check_params[3]); + result = TEST_FAIL; + } else { + if (p_cond_act->mode == STEP_CONDITION_RIGHT_REGISTER && p_cond_act->r_temp_reg_id != check_params[3]) { + WMT_ERR_FUNC("%s, C2 param failed: %d %d %d %d expect(%d %d %d %d)", + err_result, p_cond_act->result_temp_reg_id, p_cond_act->l_temp_reg_id, + p_cond_act->operator_id, p_cond_act->r_temp_reg_id, + check_params[0], check_params[1], check_params[2], check_params[3]); + result = TEST_FAIL; + } else if (p_cond_act->mode == STEP_CONDITION_RIGHT_VALUE && p_cond_act->value != check_params[3]) { + WMT_ERR_FUNC("%s, C3 param failed: %d %d %d %d expect(%d %d %d %d)", + err_result, p_cond_act->result_temp_reg_id, p_cond_act->l_temp_reg_id, + p_cond_act->operator_id, p_cond_act->value, + check_params[0], check_params[1], check_params[2], check_params[3]); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + } + + return result; +} + +int wmt_step_test_check_create_value(struct step_value_action *p_val_act, + int check_params[], char *err_result) +{ + int result = TEST_FAIL; + + if (p_val_act->base.action_id != STEP_ACTION_INDEX_VALUE) { + WMT_ERR_FUNC("%s, id wrong: %d\n", err_result, p_val_act->base.action_id); + result = TEST_FAIL; + } else if (p_val_act->temp_reg_id != check_params[0] || + p_val_act->value != check_params[1]) { + WMT_ERR_FUNC("%s, param failed: %d %d expect(%d %d)", + err_result, p_val_act->temp_reg_id, p_val_act->value, + check_params[0], check_params[1]); + result = TEST_FAIL; + } else { + result = TEST_PASS; + } + + return result; +} + +void wmt_step_test_check_emi_act(unsigned int len, ...) +{ + unsigned int offset; + unsigned int check_result; + unsigned int value; + PUINT8 p_virtual_addr = NULL; + va_list args; + + if (g_step_test_check.step_check_result == TEST_FAIL) + return; + + offset = g_step_test_check.step_check_emi_offset[g_step_test_check.step_check_index]; + p_virtual_addr = wmt_plat_get_emi_virt_add(offset); + if (!p_virtual_addr) { + g_step_test_check.step_check_result = TEST_FAIL; + WMT_ERR_FUNC("STEP test failed: p_virtual_addr offset(%d) is null", offset); + return; + } + check_result = CONSYS_REG_READ(p_virtual_addr); + + va_start(args, len); + value = va_arg(args, unsigned int); + va_end(args); + + if (check_result == value) { + g_step_test_check.step_check_result = TEST_PASS; + } else { + WMT_ERR_FUNC("STEP test failed: Value is %d, expect %d", value, check_result); + g_step_test_check.step_check_result = TEST_FAIL; + return; + } + + if (g_step_test_check.step_check_temp_register_id != -1) { + if (g_step_env.temp_register[g_step_test_check.step_check_temp_register_id] != + (check_result & g_step_test_check.step_test_mask)) { + WMT_ERR_FUNC("STEP test failed: Register id(%d) value is %d, expect %d mask 0x%08x", + g_step_test_check.step_check_temp_register_id, + g_step_env.temp_register[g_step_test_check.step_check_temp_register_id], + check_result, g_step_test_check.step_test_mask); + g_step_test_check.step_check_result = TEST_FAIL; + } + } + + g_step_test_check.step_check_index++; +} + +void wmt_step_test_check_reg_read_act(unsigned int len, ...) +{ + unsigned int check_result; + unsigned int value; + va_list args; + + if (g_step_test_check.step_check_result == TEST_FAIL) + return; + + va_start(args, len); + value = va_arg(args, unsigned int); + check_result = CONSYS_REG_READ(g_step_test_check.step_check_register_addr); + + if (check_result == value) { + g_step_test_check.step_check_result = TEST_PASS; + } else { + WMT_ERR_FUNC("STEP test failed: Value is %d, expect %d(0x%08x)", value, check_result, + (unsigned int)g_step_test_check.step_check_register_addr); + g_step_test_check.step_check_result = TEST_FAIL; + } + + if (g_step_test_check.step_check_temp_register_id != -1) { + if (g_step_env.temp_register[g_step_test_check.step_check_temp_register_id] != + (check_result & g_step_test_check.step_test_mask)) { + WMT_ERR_FUNC("STEP test failed: Register id(%d) value is %d, expect %d", + g_step_test_check.step_check_temp_register_id, + g_step_env.temp_register[g_step_test_check.step_check_temp_register_id], + check_result); + g_step_test_check.step_check_result = TEST_FAIL; + } + } + + va_end(args); +} + +void wmt_step_test_check_reg_write_act(unsigned int len, ...) +{ + unsigned int value; + va_list args; + unsigned int mask = g_step_test_check.step_test_mask; + + va_start(args, len); + value = va_arg(args, unsigned int); + + if (value == 0xdeadfeed) { + g_step_test_check.step_check_result = TEST_PASS; + } else if (mask == 0xFFFFFFFF) { + if (g_step_test_check.step_check_write_value == value) { + g_step_test_check.step_check_result = TEST_PASS; + } else { + WMT_ERR_FUNC("STEP test failed: Value is %d, expect %zu", value, + g_step_test_check.step_check_write_value); + g_step_test_check.step_check_result = TEST_FAIL; + } + } else { + if ((mask & value) != (mask & g_step_test_check.step_check_write_value)) { + WMT_ERR_FUNC("STEP test failed: Overrite:%d, expect:%zu origin %d mask %d", + value, + g_step_test_check.step_check_write_value, + g_step_test_check.step_recovery_value, + mask); + g_step_test_check.step_check_result = TEST_FAIL; + } else if ((~mask & value) != (~mask & g_step_test_check.step_recovery_value)) { + WMT_ERR_FUNC("STEP test failed: No change:%d, expect:%zu origin %d mask %d", + value, + g_step_test_check.step_check_write_value, + g_step_test_check.step_recovery_value, + mask); + g_step_test_check.step_check_result = TEST_FAIL; + } else { + g_step_test_check.step_check_result = TEST_PASS; + } + } + + va_end(args); +} + +void wmt_step_test_check_show_act(unsigned int len, ...) +{ + char *content; + va_list args; + + va_start(args, len); + content = va_arg(args, char*); + if (content == NULL || g_step_test_check.step_check_result_string == NULL) { + WMT_ERR_FUNC("STEP test failed: content is NULL"); + g_step_test_check.step_check_result = TEST_FAIL; + } else if (osal_strcmp(content, g_step_test_check.step_check_result_string) == 0) { + g_step_test_check.step_check_result = TEST_PASS; + } else { + WMT_ERR_FUNC("STEP test failed: content(%s), expect(%s)", + content, g_step_test_check.step_check_result_string); + g_step_test_check.step_check_result = TEST_FAIL; + } + va_end(args); +} + +void wmt_step_test_check_condition_act(unsigned int len, ...) +{ + int value; + va_list args; + + va_start(args, len); + value = va_arg(args, int); + if (value == g_step_test_check.step_check_result_value) { + g_step_test_check.step_check_result = TEST_PASS; + } else { + WMT_ERR_FUNC("STEP test failed: value(%d), expect(%d)", + value, g_step_test_check.step_check_result_value); + g_step_test_check.step_check_result = TEST_FAIL; + } + va_end(args); +} + +void wmt_step_test_check_value_act(unsigned int len, ...) +{ + int value; + va_list args; + + va_start(args, len); + value = va_arg(args, int); + if (value == g_step_test_check.step_check_result_value) { + g_step_test_check.step_check_result = TEST_PASS; + } else { + WMT_ERR_FUNC("STEP test failed: value(%d), expect(%d)", + value, g_step_test_check.step_check_result_value); + g_step_test_check.step_check_result = TEST_FAIL; + } + va_end(args); +} + +void wmt_step_test_clear_check_data(void) +{ + unsigned int i = 0, j = 0; + + for (i = 0; i < STEP_TEST_ACTION_NUMBER; i++) { + g_step_test_check.step_check_test_tp_id[i] = 0; + g_step_test_check.step_check_test_act_id[i] = 0; + g_step_test_check.step_check_params_num[i] = 0; + g_step_test_check.step_check_emi_offset[i] = 0; + for (j = 0; j < STEP_PARAMETER_SIZE; j++) + g_step_test_check.step_check_params[i][j] = ""; + } + + g_step_test_check.step_check_total = 0; + g_step_test_check.step_check_index = 0; + g_step_test_check.step_check_result = TEST_PASS; + g_step_test_check.step_check_register_addr = 0; + g_step_test_check.step_test_mask = 0xFFFFFFFF; + g_step_test_check.step_recovery_value = 0; + g_step_test_check.step_check_result_value = 0; + g_step_test_check.step_check_temp_register_id = -1; +} + +void wmt_step_test_clear_temp_register(void) +{ + int i; + + for (i = 0; i < STEP_TEMP_REGISTER_SIZE; i++) + g_step_env.temp_register[i] = 0; +} + +#define STEP_CAN_WRITE_UNKNOWN 0 +#define STEP_CAN_WRITE_YES 1 +#define STEP_CAN_WRITE_NO 2 +int wmt_step_test_is_can_write(SIZE_T addr, unsigned int mask) +{ + unsigned int before, after; + int ret = STEP_CAN_WRITE_UNKNOWN; + + before = CONSYS_REG_READ(addr); + CONSYS_REG_WRITE_MASK(addr, 0xFFFFFFFF, mask); + after = CONSYS_REG_READ(addr); + if ((after & mask) != (0xFFFFFFFF & mask)) + ret = STEP_CAN_WRITE_NO; + + CONSYS_REG_WRITE_MASK(addr, 0x0, mask); + after = CONSYS_REG_READ(addr); + if ((after & mask) != (0x0 & mask)) + ret = STEP_CAN_WRITE_NO; + + CONSYS_REG_WRITE_MASK(addr, before, mask); + if (ret != STEP_CAN_WRITE_NO) + ret = STEP_CAN_WRITE_YES; + + return ret; +} + +int wmt_step_test_find_can_write_register(SIZE_T addr, int max, unsigned int mask) +{ + int i; + int write_able; + + if (DISABLE_PSM_MONITOR()) { + WMT_ERR_FUNC("wake up failed\n"); + return -1; + } + + for (i = 0x0; i < max; i += 0x4) { + write_able = wmt_step_test_is_can_write(addr + i, mask); + if (write_able == STEP_CAN_WRITE_YES) { + ENABLE_PSM_MONITOR(); + return i; + } + } + ENABLE_PSM_MONITOR(); + + return -1; +} + +void wmt_step_test_update_result(int result, struct step_test_report *p_report, char *err_result) +{ + if (result != TEST_FAIL) { + p_report->pass++; + } else { + WMT_ERR_FUNC("%s", err_result); + p_report->fail++; + } +} + +void wmt_step_test_update_result_report(struct step_test_report *p_dest_report, + struct step_test_report *p_src_report) +{ + p_dest_report->pass += p_src_report->pass; + p_dest_report->fail += p_src_report->fail; + p_dest_report->check += p_src_report->check; +} + +void wmt_step_test_show_result_report(char *test_name, struct step_test_report *p_report, int sec_begin, int usec_begin, + int sec_end, int usec_end) +{ + unsigned int total = 0; + unsigned int pass = 0; + unsigned int fail = 0; + unsigned int check = 0; + int sec = 0; + int usec = 0; + + pass = p_report->pass; + fail = p_report->fail; + check = p_report->check; + + if (usec_end >= usec_begin) { + sec = sec_end - sec_begin; + usec = usec_end - usec_begin; + } else { + sec = sec_end - sec_begin - 1; + usec = usec_end - usec_begin + 1000000; + } + + total = pass + fail + check; + WMT_INFO_FUNC("%s Total: %d, PASS: %d, FAIL: %d, CHECK: %d, Spend Time: %d.%.6d\n", + test_name, total, pass, fail, check, sec, usec); +} + +void __wmt_step_test_parse_data(const char *buf, struct step_test_report *p_report, char *err_result) +{ + wmt_step_parse_data(buf, osal_strlen((char *)buf), wmt_step_test_check_write_tp); + if (g_step_test_check.step_check_total != g_step_test_check.step_check_index) { + WMT_ERR_FUNC("STEP test failed: index %d: expect total %d\n", g_step_test_check.step_check_index, + g_step_test_check.step_check_total); + g_step_test_check.step_check_result = TEST_FAIL; + } + wmt_step_test_update_result(g_step_test_check.step_check_result, p_report, err_result); +} + +void __wmt_step_test_create_action(enum step_action_id act_id, int param_num, char *params[], int result_of_action, + int check_params[], struct step_test_report *p_report, char *err_result) +{ + struct step_action *p_act = NULL; + int result = TEST_FAIL; + + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + switch (p_act->action_id) { + case STEP_ACTION_INDEX_EMI: + { + struct step_emi_action *p_emi_act = NULL; + + p_emi_act = list_entry_action(emi, p_act); + result = wmt_step_test_check_create_emi(p_emi_act, check_params, + err_result); + } + break; + case STEP_ACTION_INDEX_REGISTER: + { + struct step_register_action *p_reg_act = NULL; + + p_reg_act = list_entry_action(register, p_act); + result = wmt_step_test_check_create_reg(p_reg_act, check_params, + err_result); + } + break; + case STEP_ACTION_INDEX_GPIO: + { + struct step_gpio_action *p_gpio_act = NULL; + + p_gpio_act = list_entry_action(gpio, p_act); + result = wmt_step_test_check_create_gpio(p_gpio_act, check_params, + err_result); + } + break; + case STEP_ACTION_INDEX_DISABLE_RESET: + { + struct step_disable_reset_action *p_drst_act = NULL; + + p_drst_act = list_entry_action(disable_reset, p_act); + result = wmt_step_test_check_create_drst(p_drst_act, + check_params, err_result); + } + break; + case STEP_ACTION_INDEX_CHIP_RESET: + { + struct step_chip_reset_action *p_crst_act = NULL; + + p_crst_act = list_entry_action(chip_reset, p_act); + result = wmt_step_test_check_create_crst(p_crst_act, + check_params, err_result); + } + break; + case STEP_ACTION_INDEX_KEEP_WAKEUP: + { + struct step_keep_wakeup_action *p_kwak_act = NULL; + + p_kwak_act = list_entry_action(keep_wakeup, p_act); + result = wmt_step_test_check_create_keep_wakeup(p_kwak_act, + check_params, err_result); + } + break; + case STEP_ACTION_INDEX_CANCEL_WAKEUP: + { + struct step_cancel_wakeup_action *p_cwak_act = NULL; + + p_cwak_act = list_entry_action(cancel_wakeup, p_act); + result = wmt_step_test_check_create_cancel_wakeup(p_cwak_act, + check_params, err_result); + } + break; + case STEP_ACTION_INDEX_PERIODIC_DUMP: + { + struct step_periodic_dump_action *p_pd_act = NULL; + + p_pd_act = list_entry_action(periodic_dump, p_act); + result = wmt_step_test_check_create_periodic_dump(p_pd_act, + check_params, err_result); + } + break; + case STEP_ACTION_INDEX_SHOW_STRING: + { + struct step_show_string_action *p_show_act = NULL; + + p_show_act = list_entry_action(show_string, p_act); + result = wmt_step_test_check_create_show_string(p_show_act, + check_params, err_result); + } + break; + case STEP_ACTION_INDEX_SLEEP: + { + struct step_sleep_action *p_sleep_act = NULL; + + p_sleep_act = list_entry_action(sleep, p_act); + result = wmt_step_test_check_create_sleep(p_sleep_act, + check_params, err_result); + } + break; + case STEP_ACTION_INDEX_CONDITION: + { + struct step_condition_action *p_cond_act = NULL; + + p_cond_act = list_entry_action(condition, p_act); + result = wmt_step_test_check_create_condition(p_cond_act, + check_params, err_result); + } + break; + case STEP_ACTION_INDEX_VALUE: + { + struct step_value_action *p_val_act = NULL; + + p_val_act = list_entry_action(value, p_act); + result = wmt_step_test_check_create_value(p_val_act, + check_params, err_result); + } + break; + case STEP_ACTION_INDEX_CONDITION_EMI: + { + struct step_condition_emi_action *p_cond_emi_act = NULL; + + p_cond_emi_act = list_entry_action(condition_emi, p_act); + result = wmt_step_test_check_create_condition_emi(p_cond_emi_act, check_params, + err_result); + } + break; + case STEP_ACTION_INDEX_CONDITION_REGISTER: + { + struct step_condition_register_action *p_cond_reg_act = NULL; + + p_cond_reg_act = list_entry_action(condition_register, p_act); + result = wmt_step_test_check_create_condition_reg(p_cond_reg_act, check_params, + err_result); + } + break; + default: + result = TEST_FAIL; + break; + } + + if (result_of_action == -1) + result = TEST_FAIL; + + wmt_step_remove_action(p_act); + } else { + if (result_of_action == -1) + result = TEST_PASS; + else + result = TEST_FAIL; + } + wmt_step_test_update_result(result, p_report, err_result); +} + +void __wmt_step_test_do_emi_action(enum step_action_id act_id, int param_num, char *params[], int result_of_action, + struct step_test_report *p_report, char *err_result) +{ + struct step_action *p_act = NULL; + + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + if (wmt_step_do_emi_action(p_act, wmt_step_test_check_emi_act) == + result_of_action) { + if (g_step_test_check.step_check_total != g_step_test_check.step_check_index) { + p_report->fail++; + WMT_ERR_FUNC("%s, index %d: expect total %d\n", err_result, + g_step_test_check.step_check_index, g_step_test_check.step_check_total); + } else if (g_step_test_check.step_check_result == TEST_PASS) { + p_report->pass++; + } else { + p_report->fail++; + WMT_ERR_FUNC("%s\n", err_result); + } + } else { + WMT_ERR_FUNC("%s, expect result is %d\n", err_result, result_of_action); + p_report->fail++; + } + wmt_step_remove_action(p_act); + } else { + if (result_of_action == -1) { + p_report->pass++; + } else { + p_report->fail++; + WMT_ERR_FUNC("%s, Create failed\n", err_result); + } + } +} + +void __wmt_step_test_do_cond_emi_action(enum step_action_id act_id, int param_num, char *params[], int result_of_action, + struct step_test_report *p_report, char *err_result) +{ + struct step_action *p_act = NULL; + + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + if (wmt_step_do_condition_emi_action(p_act, wmt_step_test_check_emi_act) == + result_of_action) { + if (g_step_test_check.step_check_total != g_step_test_check.step_check_index) { + p_report->fail++; + WMT_ERR_FUNC("%s, index %d: expect total %d\n", err_result, + g_step_test_check.step_check_index, g_step_test_check.step_check_total); + } else if (g_step_test_check.step_check_result == TEST_PASS) { + p_report->pass++; + } else { + p_report->fail++; + WMT_ERR_FUNC("%s\n", err_result); + } + } else { + WMT_ERR_FUNC("%s, expect result is %d\n", err_result, result_of_action); + p_report->fail++; + } + wmt_step_remove_action(p_act); + } else { + if (result_of_action == -1) { + p_report->pass++; + } else { + p_report->fail++; + WMT_ERR_FUNC("%s, Create failed\n", err_result); + } + } +} + + +void __wmt_step_test_do_register_action(enum step_action_id act_id, int param_num, char *params[], int result_of_action, + struct step_test_report *p_report, char *err_result) +{ + struct step_action *p_act = NULL; + int result; + + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + if (osal_strcmp(params[0], "1") == 0) { + /* Write register test */ + if (g_step_test_check.step_check_register_addr != 0) { + g_step_test_check.step_recovery_value = + CONSYS_REG_READ(g_step_test_check.step_check_register_addr); + } + result = wmt_step_do_register_action(p_act, wmt_step_test_check_reg_write_act); + if (result == result_of_action) { + if (g_step_test_check.step_check_result == TEST_PASS) { + p_report->pass++; + } else { + p_report->fail++; + WMT_ERR_FUNC("%s\n", err_result); + } + } else if (result == -2) { + p_report->check++; + WMT_INFO_FUNC("STEP check: %s, no clock is ok?\n", err_result); + } else { + WMT_ERR_FUNC("%s, expect result is %d\n", err_result, + result_of_action); + p_report->fail++; + } + if (g_step_test_check.step_check_register_addr != 0) { + CONSYS_REG_WRITE(g_step_test_check.step_check_register_addr, + g_step_test_check.step_recovery_value); + } + } else { + /* Read register test */ + g_step_test_check.step_check_result = TEST_PASS; + result = wmt_step_do_register_action(p_act, wmt_step_test_check_reg_read_act); + if (result == result_of_action) { + if (g_step_test_check.step_check_result == TEST_PASS) { + p_report->pass++; + } else { + p_report->fail++; + WMT_ERR_FUNC("%s\n", err_result); + } + } else if (result == -2) { + p_report->check++; + WMT_INFO_FUNC("STEP check: %s, no clock is ok?\n", err_result); + } else { + WMT_ERR_FUNC("%s, expect result is %d\n", err_result, + result_of_action); + p_report->fail++; + } + } + wmt_step_remove_action(p_act); + } else { + if (result_of_action == -1) { + p_report->pass++; + } else { + p_report->fail++; + WMT_ERR_FUNC("%s, Create failed\n", err_result); + } + } +} + +void __wmt_step_test_do_cond_register_action(enum step_action_id act_id, int param_num, + char *params[], int result_of_action, + struct step_test_report *p_report, char *err_result) +{ + struct step_action *p_act = NULL; + int result; + + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + if (osal_strcmp(params[1], "1") == 0) { + /* Write register test */ + if (g_step_test_check.step_check_register_addr != 0) { + g_step_test_check.step_recovery_value = + CONSYS_REG_READ(g_step_test_check.step_check_register_addr); + } + + result = wmt_step_do_condition_register_action(p_act, wmt_step_test_check_reg_write_act); + if (result == result_of_action) { + if (g_step_test_check.step_check_result == TEST_PASS) { + p_report->pass++; + } else { + p_report->fail++; + WMT_ERR_FUNC("%s\n", err_result); + } + } else if (result == -2) { + p_report->check++; + WMT_INFO_FUNC("STEP check: %s, no clock is ok?\n", err_result); + } else { + WMT_ERR_FUNC("%s, expect result is %d\n", err_result, result_of_action); + p_report->fail++; + } + if (g_step_test_check.step_check_register_addr != 0) { + CONSYS_REG_WRITE(g_step_test_check.step_check_register_addr, + g_step_test_check.step_recovery_value); + } + } else { + /* Read register test */ + g_step_test_check.step_check_result = TEST_PASS; + result = wmt_step_do_condition_register_action(p_act, wmt_step_test_check_reg_read_act); + if (result == result_of_action) { + if (g_step_test_check.step_check_result == TEST_PASS) { + p_report->pass++; + } else { + p_report->fail++; + WMT_ERR_FUNC("%s\n", err_result); + } + } else if (result == -2) { + p_report->check++; + WMT_INFO_FUNC("STEP check: %s, no clock is ok?\n", err_result); + } else { + WMT_ERR_FUNC("%s, expect result is %d\n", err_result, result_of_action); + p_report->fail++; + } + } + wmt_step_remove_action(p_act); + } else { + if (result_of_action == -1) { + p_report->pass++; + } else { + p_report->fail++; + WMT_ERR_FUNC("%s, Create failed\n", err_result); + } + } +} + +void wmt_step_test_all(void) +{ + struct step_test_report report = {0, 0, 0}; + bool is_enable_step = g_step_env.is_enable; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + + report.pass = 0; + report.fail = 0; + report.check = 0; + + WMT_INFO_FUNC("STEP test: All start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + g_step_env.is_enable = 0; + wmt_step_test_read_file(&report); + g_step_env.is_enable = 1; + wmt_step_test_create_emi_action(&report); + wmt_step_test_create_cond_emi_action(&report); + wmt_step_test_create_register_action(&report); + wmt_step_test_create_cond_register_action(&report); + wmt_step_test_check_register_symbol(&report); + wmt_step_test_create_other_action(&report); + wmt_step_test_parse_data(&report); + wmt_step_test_do_emi_action(&report); + wmt_step_test_do_cond_emi_action(&report); + wmt_step_test_do_register_action(&report); + wmt_step_test_do_cond_register_action(&report); + wmt_step_test_do_gpio_action(&report); + wmt_step_test_do_wakeup_action(&report); + wmt_step_test_create_periodic_dump(&report); + wmt_step_test_do_show_action(&report); + wmt_step_test_do_sleep_action(&report); + wmt_step_test_do_condition_action(&report); + wmt_step_test_do_value_action(&report); + + wmt_step_test_do_chip_reset_action(&report); + g_step_env.is_enable = is_enable_step; + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: All result", + &report, sec_begin, usec_begin, sec_end, usec_end); +} + +void wmt_step_test_read_file(struct step_test_report *p_report) +{ + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + + WMT_INFO_FUNC("STEP test: Read file start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + /******************************** + ******** Test case 1 *********** + ******* Wrong file name ******** + ********************************/ + if (-1 == wmt_step_read_file("wmt_failed.cfg")) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test failed: (Read file TC-1) expect no file\n"); + temp_report.fail++; + } + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Read file result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_parse_data(struct step_test_report *p_report) +{ + char *buf = NULL; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + + WMT_INFO_FUNC("STEP test: Parse data start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + /******************************** + ******** Test case 1 *********** + ******** Normal case *********** + ********************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_check_data(); + + buf = + "// TEST NOW\r\n" + "\r\n" + "[TP 1] When Command timeout\r\n" + "[AT] _EMI 0 0x50 0x9c\r\n" + "[AT] _REG 0 0x08 5 2\r\n" + "[AT] DRST\r\n" + "[AT] _RST\r\n" + "[TP 2] When Firmware trigger assert\r\n" + "[AT] _REG 1 0x08 30\r\n" + "[AT] GPIO 0 8\r\n" + "[AT] GPIO 1 6 3\r\n" + "[AT] WAK+\r\n" + "[AT] WAK-\r\n" + "[AT] _REG 1 0x08 30 0xFF00FF00\r\n" + "[TP 3] Before Chip reset\r\n" + "[AT] SHOW Hello_World\r\n" + "[AT] _SLP 1000\r\n" + "[AT] COND $1 $2 == $3\r\n" + "[AT] COND $1 $2 == 16\r\n" + "[AT] _VAL $0 0x66\r\n" + "[TP 4] After Chip reset\r\n" + "[AT] _EMI 0 0x50 0xFFFFFFFF $1\r\n" + "[AT] _REG 0 0x08 0xFFFFFFFF $1\r\n" + "[AT] CEMI $2 0 0x50 0xFFFFFFFF $1\r\n" + "[AT] CREG $2 0 0x08 0xFFFFFFFF $1\r\n" + "\r\n"; + + g_step_test_check.step_check_total = 19; + g_step_test_check.step_check_test_tp_id[0] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[0] = STEP_ACTION_INDEX_EMI; + g_step_test_check.step_check_test_tp_id[1] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[1] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[2] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[2] = STEP_ACTION_INDEX_DISABLE_RESET; + g_step_test_check.step_check_test_tp_id[3] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[3] = STEP_ACTION_INDEX_CHIP_RESET; + g_step_test_check.step_check_test_tp_id[4] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[4] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[5] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[5] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[6] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[6] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[7] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[7] = STEP_ACTION_INDEX_KEEP_WAKEUP; + g_step_test_check.step_check_test_tp_id[8] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[8] = STEP_ACTION_INDEX_CANCEL_WAKEUP; + g_step_test_check.step_check_test_tp_id[9] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[9] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[10] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[10] = STEP_ACTION_INDEX_SHOW_STRING; + g_step_test_check.step_check_test_tp_id[11] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[11] = STEP_ACTION_INDEX_SLEEP; + g_step_test_check.step_check_test_tp_id[12] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[12] = STEP_ACTION_INDEX_CONDITION; + g_step_test_check.step_check_test_tp_id[13] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[13] = STEP_ACTION_INDEX_CONDITION; + g_step_test_check.step_check_test_tp_id[14] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[14] = STEP_ACTION_INDEX_VALUE; + g_step_test_check.step_check_test_tp_id[15] = STEP_TRIGGER_POINT_AFTER_CHIP_RESET; + g_step_test_check.step_check_test_act_id[15] = STEP_ACTION_INDEX_EMI; + g_step_test_check.step_check_test_tp_id[16] = STEP_TRIGGER_POINT_AFTER_CHIP_RESET; + g_step_test_check.step_check_test_act_id[16] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[17] = STEP_TRIGGER_POINT_AFTER_CHIP_RESET; + g_step_test_check.step_check_test_act_id[17] = STEP_ACTION_INDEX_CONDITION_EMI; + g_step_test_check.step_check_test_tp_id[18] = STEP_TRIGGER_POINT_AFTER_CHIP_RESET; + g_step_test_check.step_check_test_act_id[18] = STEP_ACTION_INDEX_CONDITION_REGISTER; + + g_step_test_check.step_check_params[0][0] = "0"; + g_step_test_check.step_check_params[0][1] = "0x50"; + g_step_test_check.step_check_params[0][2] = "0x9c"; + g_step_test_check.step_check_params_num[0] = 3; + g_step_test_check.step_check_params[1][0] = "0"; + g_step_test_check.step_check_params[1][1] = "0x08"; + g_step_test_check.step_check_params[1][2] = "5"; + g_step_test_check.step_check_params[1][3] = "2"; + g_step_test_check.step_check_params_num[1] = 4; + g_step_test_check.step_check_params[4][0] = "1"; + g_step_test_check.step_check_params[4][1] = "0x08"; + g_step_test_check.step_check_params[4][2] = "30"; + g_step_test_check.step_check_params_num[4] = 3; + g_step_test_check.step_check_params[5][0] = "0"; + g_step_test_check.step_check_params[5][1] = "8"; + g_step_test_check.step_check_params_num[5] = 2; + g_step_test_check.step_check_params[6][0] = "1"; + g_step_test_check.step_check_params[6][1] = "6"; + g_step_test_check.step_check_params[6][2] = "3"; + g_step_test_check.step_check_params_num[6] = 3; + g_step_test_check.step_check_params[9][0] = "1"; + g_step_test_check.step_check_params[9][1] = "0x08"; + g_step_test_check.step_check_params[9][2] = "30"; + g_step_test_check.step_check_params[9][3] = "0xFF00FF00"; + g_step_test_check.step_check_params_num[9] = 4; + g_step_test_check.step_check_params[10][0] = "Hello_World"; + g_step_test_check.step_check_params_num[10] = 1; + g_step_test_check.step_check_params[11][0] = "1000"; + g_step_test_check.step_check_params_num[11] = 1; + g_step_test_check.step_check_params[12][0] = "$1"; + g_step_test_check.step_check_params[12][1] = "$2"; + g_step_test_check.step_check_params[12][2] = "=="; + g_step_test_check.step_check_params[12][3] = "$3"; + g_step_test_check.step_check_params_num[12] = 4; + g_step_test_check.step_check_params[13][0] = "$1"; + g_step_test_check.step_check_params[13][1] = "$2"; + g_step_test_check.step_check_params[13][2] = "=="; + g_step_test_check.step_check_params[13][3] = "16"; + g_step_test_check.step_check_params_num[13] = 4; + g_step_test_check.step_check_params[14][0] = "$0"; + g_step_test_check.step_check_params[14][1] = "0x66"; + g_step_test_check.step_check_params_num[14] = 2; + g_step_test_check.step_check_params[15][0] = "0"; + g_step_test_check.step_check_params[15][1] = "0x50"; + g_step_test_check.step_check_params[15][2] = "0xFFFFFFFF"; + g_step_test_check.step_check_params[15][3] = "$1"; + g_step_test_check.step_check_params_num[15] = 4; + g_step_test_check.step_check_params[16][0] = "0"; + g_step_test_check.step_check_params[16][1] = "0x08"; + g_step_test_check.step_check_params[16][2] = "0xFFFFFFFF"; + g_step_test_check.step_check_params[16][3] = "$1"; + g_step_test_check.step_check_params_num[16] = 4; + g_step_test_check.step_check_params[17][0] = "$2"; + g_step_test_check.step_check_params[17][1] = "0"; + g_step_test_check.step_check_params[17][2] = "0x50"; + g_step_test_check.step_check_params[17][3] = "0xFFFFFFFF"; + g_step_test_check.step_check_params[17][4] = "$1"; + g_step_test_check.step_check_params_num[17] = 5; + g_step_test_check.step_check_params[18][0] = "$2"; + g_step_test_check.step_check_params[18][1] = "0"; + g_step_test_check.step_check_params[18][2] = "0x08"; + g_step_test_check.step_check_params[18][3] = "0xFFFFFFFF"; + g_step_test_check.step_check_params[18][4] = "$1"; + g_step_test_check.step_check_params_num[18] = 5; + __wmt_step_test_parse_data(buf, &temp_report, + "STEP test case failed: (Parse data TC-1) Normal case\n"); + + /********************************* + ******** Test case 2 ************ + ** Normal case with some space ** + *********************************/ + WMT_INFO_FUNC("STEP test: TC 2\n"); + wmt_step_test_clear_check_data(); + buf = + "// TEST NOW\r\n" + "\r\n" + "[TP 1] When Command timeout\r\n" + "[AT] _EMI 0 0x50 0x9c \r\n" + "[AT] _REG 0 0x08 5 2\r\n" + "[AT] DRST\r\n" + "[AT] _RST\r\n" + " [PD+] 2\r\n" + " [AT] _EMI 0 0x50 0x9c\r\n" + " [PD-] \r\n" + " [TP 2] When Firmware trigger assert\r\n" + "[AT] _REG 1 0x08 30\r\n" + "[AT] GPIO 0 8\r\n" + " [AT] GPIO 1 6 3\r\n" + " [AT] WAK+\r\n" + " [AT] WAK-\r\n" + " [PD+] 5\r\n" + " [AT] _EMI 0 0x50 0x9c\r\n" + " [PD-] \r\n" + "[TP 3] Before Chip reset\r\n" + " [AT] SHOW Hello\r\n" + "[AT] _SLP 1000\r\n" + " [AT] COND $1 $2 == $3\r\n" + " [AT] _VAL $0 0x66\r\n" + "[TP 4] After Chip reset\r\n" + "[AT] CEMI $2 0 0x50 0xFFFFFFFF $1\r\n" + " [AT] CREG $2 0 0x08 0xFFFFFFFF $1\r\n" + "\r\n"; + + g_step_test_check.step_check_total = 19; + g_step_test_check.step_check_test_tp_id[0] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[0] = STEP_ACTION_INDEX_EMI; + g_step_test_check.step_check_test_tp_id[1] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[1] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[2] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[2] = STEP_ACTION_INDEX_DISABLE_RESET; + g_step_test_check.step_check_test_tp_id[3] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[3] = STEP_ACTION_INDEX_CHIP_RESET; + g_step_test_check.step_check_test_tp_id[4] = -1; + g_step_test_check.step_check_test_act_id[4] = STEP_ACTION_INDEX_EMI; + g_step_test_check.step_check_test_tp_id[5] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[5] = STEP_ACTION_INDEX_PERIODIC_DUMP; + g_step_test_check.step_check_test_tp_id[6] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[6] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[7] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[7] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[8] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[8] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[9] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[9] = STEP_ACTION_INDEX_KEEP_WAKEUP; + g_step_test_check.step_check_test_tp_id[10] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[10] = STEP_ACTION_INDEX_CANCEL_WAKEUP; + g_step_test_check.step_check_test_tp_id[11] = -1; + g_step_test_check.step_check_test_act_id[11] = STEP_ACTION_INDEX_EMI; + g_step_test_check.step_check_test_tp_id[12] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[12] = STEP_ACTION_INDEX_PERIODIC_DUMP; + g_step_test_check.step_check_test_tp_id[13] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[13] = STEP_ACTION_INDEX_SHOW_STRING; + g_step_test_check.step_check_test_tp_id[14] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[14] = STEP_ACTION_INDEX_SLEEP; + g_step_test_check.step_check_test_tp_id[15] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[15] = STEP_ACTION_INDEX_CONDITION; + g_step_test_check.step_check_test_tp_id[16] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[16] = STEP_ACTION_INDEX_VALUE; + g_step_test_check.step_check_test_tp_id[17] = STEP_TRIGGER_POINT_AFTER_CHIP_RESET; + g_step_test_check.step_check_test_act_id[17] = STEP_ACTION_INDEX_CONDITION_EMI; + g_step_test_check.step_check_test_tp_id[18] = STEP_TRIGGER_POINT_AFTER_CHIP_RESET; + g_step_test_check.step_check_test_act_id[18] = STEP_ACTION_INDEX_CONDITION_REGISTER; + g_step_test_check.step_check_params[0][0] = "0"; + g_step_test_check.step_check_params[0][1] = "0x50"; + g_step_test_check.step_check_params[0][2] = "0x9c"; + g_step_test_check.step_check_params_num[0] = 3; + g_step_test_check.step_check_params[1][0] = "0"; + g_step_test_check.step_check_params[1][1] = "0x08"; + g_step_test_check.step_check_params[1][2] = "5"; + g_step_test_check.step_check_params[1][3] = "2"; + g_step_test_check.step_check_params_num[1] = 4; + g_step_test_check.step_check_params[4][0] = "0"; + g_step_test_check.step_check_params[4][1] = "0x50"; + g_step_test_check.step_check_params[4][2] = "0x9c"; + g_step_test_check.step_check_params_num[4] = 3; + g_step_test_check.step_check_params[6][0] = "1"; + g_step_test_check.step_check_params[6][1] = "0x08"; + g_step_test_check.step_check_params[6][2] = "30"; + g_step_test_check.step_check_params_num[6] = 3; + g_step_test_check.step_check_params[7][0] = "0"; + g_step_test_check.step_check_params[7][1] = "8"; + g_step_test_check.step_check_params_num[7] = 2; + g_step_test_check.step_check_params[8][0] = "1"; + g_step_test_check.step_check_params[8][1] = "6"; + g_step_test_check.step_check_params[8][2] = "3"; + g_step_test_check.step_check_params_num[8] = 3; + g_step_test_check.step_check_params[11][0] = "0"; + g_step_test_check.step_check_params[11][1] = "0x50"; + g_step_test_check.step_check_params[11][2] = "0x9c"; + g_step_test_check.step_check_params_num[11] = 3; + g_step_test_check.step_check_params[13][0] = "Hello"; + g_step_test_check.step_check_params_num[13] = 1; + g_step_test_check.step_check_params[14][0] = "1000"; + g_step_test_check.step_check_params_num[14] = 1; + g_step_test_check.step_check_params[15][0] = "$1"; + g_step_test_check.step_check_params[15][1] = "$2"; + g_step_test_check.step_check_params[15][2] = "=="; + g_step_test_check.step_check_params[15][3] = "$3"; + g_step_test_check.step_check_params_num[15] = 4; + g_step_test_check.step_check_params[16][0] = "$0"; + g_step_test_check.step_check_params[16][1] = "0x66"; + g_step_test_check.step_check_params_num[16] = 2; + g_step_test_check.step_check_params[17][0] = "$2"; + g_step_test_check.step_check_params[17][1] = "0"; + g_step_test_check.step_check_params[17][2] = "0x50"; + g_step_test_check.step_check_params[17][3] = "0xFFFFFFFF"; + g_step_test_check.step_check_params[17][4] = "$1"; + g_step_test_check.step_check_params_num[17] = 5; + g_step_test_check.step_check_params[18][0] = "$2"; + g_step_test_check.step_check_params[18][1] = "0"; + g_step_test_check.step_check_params[18][2] = "0x08"; + g_step_test_check.step_check_params[18][3] = "0xFFFFFFFF"; + g_step_test_check.step_check_params[18][4] = "$1"; + g_step_test_check.step_check_params_num[18] = 5; + __wmt_step_test_parse_data(buf, &temp_report, + "STEP test case failed: (Parse data TC-2) Normal case with some space\n"); + + /*************************************************** + ****************** Test case 3 ******************** + ** Failed case not enough parameter (Can parser) ** + ***************************************************/ + WMT_INFO_FUNC("STEP test: TC 3\n"); + wmt_step_test_clear_check_data(); + buf = + "// TEST NOW\r\n" + "\r\n" + "[TP 1] When Command timeout\r\n" + "[AT] _EMI 0x50 0x9c\r\n" + "[AT] _REG 0 5 2\r\n" + "[AT] DRST\r\n" + "[AT] _RST\r\n" + "[TP 2] When Firmware trigger assert\r\n" + "[AT] _REG 1 0x08\r\n" + "[AT] GPIO 0\r\n" + "[AT] GPIO 6 3\r\n" + "[TP 3] Before Chip reset\r\n" + "[AT] SHOW\r\n" + "[AT] _SLP\r\n" + "[AT] COND $1 $2 >\r\n" + "[AT] _VAL 0x66\r\n" + "\r\n"; + + g_step_test_check.step_check_total = 11; + g_step_test_check.step_check_test_tp_id[0] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[0] = STEP_ACTION_INDEX_EMI; + g_step_test_check.step_check_test_tp_id[1] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[1] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[2] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[2] = STEP_ACTION_INDEX_DISABLE_RESET; + g_step_test_check.step_check_test_tp_id[3] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[3] = STEP_ACTION_INDEX_CHIP_RESET; + g_step_test_check.step_check_test_tp_id[4] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[4] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[5] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[5] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[6] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[6] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[7] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[7] = STEP_ACTION_INDEX_SHOW_STRING; + g_step_test_check.step_check_test_tp_id[8] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[8] = STEP_ACTION_INDEX_SLEEP; + g_step_test_check.step_check_test_tp_id[9] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[9] = STEP_ACTION_INDEX_CONDITION; + g_step_test_check.step_check_test_tp_id[10] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[10] = STEP_ACTION_INDEX_VALUE; + + g_step_test_check.step_check_params[0][0] = "0x50"; + g_step_test_check.step_check_params[0][1] = "0x9c"; + g_step_test_check.step_check_params_num[0] = 2; + g_step_test_check.step_check_params[1][0] = "0"; + g_step_test_check.step_check_params[1][1] = "5"; + g_step_test_check.step_check_params[1][2] = "2"; + g_step_test_check.step_check_params_num[1] = 3; + g_step_test_check.step_check_params[4][0] = "1"; + g_step_test_check.step_check_params[4][1] = "0x08"; + g_step_test_check.step_check_params_num[4] = 2; + g_step_test_check.step_check_params[5][0] = "0"; + g_step_test_check.step_check_params_num[5] = 1; + g_step_test_check.step_check_params[6][0] = "6"; + g_step_test_check.step_check_params[6][1] = "3"; + g_step_test_check.step_check_params_num[6] = 2; + g_step_test_check.step_check_params[9][0] = "$1"; + g_step_test_check.step_check_params[9][1] = "$2"; + g_step_test_check.step_check_params[9][2] = ">"; + g_step_test_check.step_check_params_num[9] = 3; + g_step_test_check.step_check_params[10][0] = "0x66"; + g_step_test_check.step_check_params_num[10] = 1; + + __wmt_step_test_parse_data(buf, &temp_report, + "STEP test case failed: (Parse data TC-3) Not enough parameter\n"); + + /*************************************************** + ****************** Test case 4 ******************** + ************** Upcase and lowercase *************** + ***************************************************/ + WMT_INFO_FUNC("STEP test: TC 4\n"); + wmt_step_test_clear_check_data(); + buf = + "// TEST NOW\r\n" + "\r\n" + "[Tp 1] When Command timeout\r\n" + "[aT] _emi 0 0x50 0x9c\r\n" + "[At] _reg 0 0x08 5 2\r\n" + "[AT] drst\r\n" + "[at] _rst\r\n" + "[tP 2] When Firmware trigger assert\r\n" + "[at] _reg 1 0x08 30\r\n" + "[at] gpio 0 8\r\n" + "[AT] gpio 1 6 3\r\n" + "[AT] wak+\r\n" + "[AT] wak--\r\n" + "[AT] _reg 1 0x08 30 0xFF00FF00\r\n" + "[pd+] 5\r\n" + "[At] gpio 0 8\r\n" + "[pd-]\r\n" + "[tp 3] Before Chip reset\r\n" + "[AT] show Hello_World\r\n" + "[AT] _slp 1000\r\n" + "[AT] cond $1 $2 == $3\r\n" + "[AT] _val $0 0x66\r\n" + "[TP 4] After Chip reset\r\n" + "[AT] cemi $2 0 0x50 0xFFFFFFFF $1\r\n" + "[at] creg $2 0 0x08 0xffffffff $1\r\n" + "\r\n"; + + g_step_test_check.step_check_total = 18; + g_step_test_check.step_check_test_tp_id[0] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[0] = STEP_ACTION_INDEX_EMI; + g_step_test_check.step_check_test_tp_id[1] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[1] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[2] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[2] = STEP_ACTION_INDEX_DISABLE_RESET; + g_step_test_check.step_check_test_tp_id[3] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[3] = STEP_ACTION_INDEX_CHIP_RESET; + g_step_test_check.step_check_test_tp_id[4] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[4] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[5] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[5] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[6] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[6] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[7] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[7] = STEP_ACTION_INDEX_KEEP_WAKEUP; + g_step_test_check.step_check_test_tp_id[8] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[8] = STEP_ACTION_INDEX_CANCEL_WAKEUP; + g_step_test_check.step_check_test_tp_id[9] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[9] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[10] = -1; + g_step_test_check.step_check_test_act_id[10] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[11] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[11] = STEP_ACTION_INDEX_PERIODIC_DUMP; + g_step_test_check.step_check_test_tp_id[12] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[12] = STEP_ACTION_INDEX_SHOW_STRING; + g_step_test_check.step_check_test_tp_id[13] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[13] = STEP_ACTION_INDEX_SLEEP; + g_step_test_check.step_check_test_tp_id[14] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[14] = STEP_ACTION_INDEX_CONDITION; + g_step_test_check.step_check_test_tp_id[15] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[15] = STEP_ACTION_INDEX_VALUE; + g_step_test_check.step_check_test_tp_id[16] = STEP_TRIGGER_POINT_AFTER_CHIP_RESET; + g_step_test_check.step_check_test_act_id[16] = STEP_ACTION_INDEX_CONDITION_EMI; + g_step_test_check.step_check_test_tp_id[17] = STEP_TRIGGER_POINT_AFTER_CHIP_RESET; + g_step_test_check.step_check_test_act_id[17] = STEP_ACTION_INDEX_CONDITION_REGISTER; + + g_step_test_check.step_check_params[0][0] = "0"; + g_step_test_check.step_check_params[0][1] = "0x50"; + g_step_test_check.step_check_params[0][2] = "0x9c"; + g_step_test_check.step_check_params_num[0] = 3; + g_step_test_check.step_check_params[1][0] = "0"; + g_step_test_check.step_check_params[1][1] = "0x08"; + g_step_test_check.step_check_params[1][2] = "5"; + g_step_test_check.step_check_params[1][3] = "2"; + g_step_test_check.step_check_params_num[1] = 4; + g_step_test_check.step_check_params[4][0] = "1"; + g_step_test_check.step_check_params[4][1] = "0x08"; + g_step_test_check.step_check_params[4][2] = "30"; + g_step_test_check.step_check_params_num[4] = 3; + g_step_test_check.step_check_params[5][0] = "0"; + g_step_test_check.step_check_params[5][1] = "8"; + g_step_test_check.step_check_params_num[5] = 2; + g_step_test_check.step_check_params[6][0] = "1"; + g_step_test_check.step_check_params[6][1] = "6"; + g_step_test_check.step_check_params[6][2] = "3"; + g_step_test_check.step_check_params_num[6] = 3; + g_step_test_check.step_check_params[9][0] = "1"; + g_step_test_check.step_check_params[9][1] = "0x08"; + g_step_test_check.step_check_params[9][2] = "30"; + g_step_test_check.step_check_params[9][3] = "0xFF00FF00"; + g_step_test_check.step_check_params_num[9] = 4; + g_step_test_check.step_check_params[10][0] = "0"; + g_step_test_check.step_check_params[10][1] = "8"; + g_step_test_check.step_check_params_num[10] = 2; + g_step_test_check.step_check_params[12][0] = "Hello_World"; + g_step_test_check.step_check_params_num[12] = 1; + g_step_test_check.step_check_params[13][0] = "1000"; + g_step_test_check.step_check_params_num[13] = 1; + g_step_test_check.step_check_params[14][0] = "$1"; + g_step_test_check.step_check_params[14][1] = "$2"; + g_step_test_check.step_check_params[14][2] = "=="; + g_step_test_check.step_check_params[14][3] = "$3"; + g_step_test_check.step_check_params_num[14] = 4; + g_step_test_check.step_check_params[15][0] = "$0"; + g_step_test_check.step_check_params[15][1] = "0x66"; + g_step_test_check.step_check_params_num[15] = 2; + g_step_test_check.step_check_params[16][0] = "$2"; + g_step_test_check.step_check_params[16][1] = "0"; + g_step_test_check.step_check_params[16][2] = "0x50"; + g_step_test_check.step_check_params[16][3] = "0xFFFFFFFF"; + g_step_test_check.step_check_params[16][4] = "$1"; + g_step_test_check.step_check_params_num[16] = 5; + g_step_test_check.step_check_params[17][0] = "$2"; + g_step_test_check.step_check_params[17][1] = "0"; + g_step_test_check.step_check_params[17][2] = "0x08"; + g_step_test_check.step_check_params[17][3] = "0xFFFFFFFF"; + g_step_test_check.step_check_params[17][4] = "$1"; + g_step_test_check.step_check_params_num[17] = 5; + + __wmt_step_test_parse_data(buf, &temp_report, + "STEP test case failed: (Parse data TC-4) Upcase and lowercase\n"); + + /************************************************* + ****************** Test case 5 ****************** + ************** TP sequence switch *************** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 5\n"); + wmt_step_test_clear_check_data(); + buf = + "// TEST NOW\r\n" + "\r\n" + "[TP 2] When Firmware trigger assert\r\n" + "[AT] _REG 1 0x08 30\r\n" + "[AT] GPIO 0 8\r\n" + "[AT] GPIO 1 6 3\r\n" + "[tp 3] Before Chip reset\r\n" + "[AT] DRST\r\n" + "[AT] _RST\r\n" + "[TP 1] When Command timeout\r\n" + "[AT] _EMI 0 0x50 0x9c\r\n" + "[AT] _REG 0 0x08 5 2\r\n" + "\r\n"; + + g_step_test_check.step_check_total = 7; + g_step_test_check.step_check_test_tp_id[0] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[0] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[1] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[1] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[2] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[2] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[3] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[3] = STEP_ACTION_INDEX_DISABLE_RESET; + g_step_test_check.step_check_test_tp_id[4] = STEP_TRIGGER_POINT_BEFORE_CHIP_RESET; + g_step_test_check.step_check_test_act_id[4] = STEP_ACTION_INDEX_CHIP_RESET; + g_step_test_check.step_check_test_tp_id[5] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[5] = STEP_ACTION_INDEX_EMI; + g_step_test_check.step_check_test_tp_id[6] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[6] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_params[0][0] = "1"; + g_step_test_check.step_check_params[0][1] = "0x08"; + g_step_test_check.step_check_params[0][2] = "30"; + g_step_test_check.step_check_params_num[0] = 3; + g_step_test_check.step_check_params[1][0] = "0"; + g_step_test_check.step_check_params[1][1] = "8"; + g_step_test_check.step_check_params_num[1] = 2; + g_step_test_check.step_check_params[2][0] = "1"; + g_step_test_check.step_check_params[2][1] = "6"; + g_step_test_check.step_check_params[2][2] = "3"; + g_step_test_check.step_check_params_num[2] = 3; + g_step_test_check.step_check_params[5][0] = "0"; + g_step_test_check.step_check_params[5][1] = "0x50"; + g_step_test_check.step_check_params[5][2] = "0x9c"; + g_step_test_check.step_check_params_num[5] = 3; + g_step_test_check.step_check_params[6][0] = "0"; + g_step_test_check.step_check_params[6][1] = "0x08"; + g_step_test_check.step_check_params[6][2] = "5"; + g_step_test_check.step_check_params[6][3] = "2"; + g_step_test_check.step_check_params_num[6] = 4; + __wmt_step_test_parse_data(buf, &temp_report, + "STEP test case failed: (Parse data TC-5) TP sequence switch\n"); + + /********************************* + ********* Test case 6 *********** + ********* More comment ********** + *********************************/ + WMT_INFO_FUNC("STEP test: TC 6\n"); + wmt_step_test_clear_check_data(); + + buf = + "// TEST NOW\r\n" + "\r\n" + "[TP 1] When Command timeout\r\n" + "[AT] _EMI 0 0x50 0x9c // show emi 0x50~0x9c\r\n" + "// show cregister\r\n" + "[AT] _REG 0 0x08 5 2\r\n" + "// Do some action\r\n" + "[AT] DRST // just do it\r\n" + "[AT] _RST // is ok?\r\n" + "[TP 2] When Firmware trigger assert\r\n" + "[AT] _REG 1 0x08 30\r\n" + "[AT] GPIO 0 8\r\n" + "[AT] GPIO 1 6 3\r\n" + "[PD+] 5 // pd start\r\n" + "[AT] GPIO 0 8 // just do it\r\n" + "// Do some action\r\n" + "[PD-] // pd ned\r\n" + "\r\n"; + + g_step_test_check.step_check_total = 9; + g_step_test_check.step_check_test_tp_id[0] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[0] = STEP_ACTION_INDEX_EMI; + g_step_test_check.step_check_test_tp_id[1] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[1] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[2] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[2] = STEP_ACTION_INDEX_DISABLE_RESET; + g_step_test_check.step_check_test_tp_id[3] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[3] = STEP_ACTION_INDEX_CHIP_RESET; + g_step_test_check.step_check_test_tp_id[4] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[4] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[5] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[5] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[6] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[6] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[7] = -1; + g_step_test_check.step_check_test_act_id[7] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[8] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[8] = STEP_ACTION_INDEX_PERIODIC_DUMP; + g_step_test_check.step_check_params[0][0] = "0"; + g_step_test_check.step_check_params[0][1] = "0x50"; + g_step_test_check.step_check_params[0][2] = "0x9c"; + g_step_test_check.step_check_params_num[0] = 3; + g_step_test_check.step_check_params[1][0] = "0"; + g_step_test_check.step_check_params[1][1] = "0x08"; + g_step_test_check.step_check_params[1][2] = "5"; + g_step_test_check.step_check_params[1][3] = "2"; + g_step_test_check.step_check_params_num[1] = 4; + g_step_test_check.step_check_params[4][0] = "1"; + g_step_test_check.step_check_params[4][1] = "0x08"; + g_step_test_check.step_check_params[4][2] = "30"; + g_step_test_check.step_check_params_num[4] = 3; + g_step_test_check.step_check_params[5][0] = "0"; + g_step_test_check.step_check_params[5][1] = "8"; + g_step_test_check.step_check_params_num[5] = 2; + g_step_test_check.step_check_params[6][0] = "1"; + g_step_test_check.step_check_params[6][1] = "6"; + g_step_test_check.step_check_params[6][2] = "3"; + g_step_test_check.step_check_params_num[6] = 3; + g_step_test_check.step_check_params[7][0] = "0"; + g_step_test_check.step_check_params[7][1] = "8"; + g_step_test_check.step_check_params_num[7] = 2; + __wmt_step_test_parse_data(buf, &temp_report, + "STEP test case failed: (Parse data TC-6) More comment\n"); + + /********************************* + ********* Test case 7 *********** + ********* Wrong format ********** + *********************************/ + WMT_INFO_FUNC("STEP test: TC 7\n"); + wmt_step_test_clear_check_data(); + + buf = + "// TEST NOW\r\n" + "\r\n" + "[TP adfacdadf]When Command timeout\r\n" + "[AT] _EMI 0 0x50 0x9c\r\n" + "[TP1]When Command timeout\r\n" + "[AT] DRST\r\n" + "[TP-1]When Command timeout\r\n" + "[AT] _RST\r\n" + "[T P 2] When Firmware trigger assert\r\n" + "[AT] WAK+\r\n" + "[TP 2 When Firmware trigger assert\r\n" + "[AT] WAK+\r\n" + "[PD+]\r\n" + "[PD-]\r\n" + "[TP 2] When Firmware trigger assert\r\n" + "[AT]_REG 1 0x08 30\r\n" + "[A T] GPIO 0 8\r\n" + "[ AT ] GPIO 1 6 3\r\n" + "AT GPIO 0 8\r\n" + "[AT WAK+\r\n" + "\r\n"; + + g_step_test_check.step_check_total = 0; + __wmt_step_test_parse_data(buf, &temp_report, + "STEP test case failed: (Parse data TC-7) Wrong format\n"); + + /******************************** + ******** Test case 8 *********** + ******* Periodic dump ********** + ********************************/ + WMT_INFO_FUNC("STEP test: TC 8\n"); + wmt_step_test_clear_check_data(); + + buf = + "// TEST NOW\r\n" + "\r\n" + "[TP 1] When Command timeout\r\n" + "[PD+] 5\r\n" + "[AT] _EMI 0 0x50 0x9c\r\n" + "[AT] _REG 0 0x08 5 2\r\n" + "[PD-]\r\n" + "[AT] DRST\r\n" + "[AT] _RST\r\n" + "[TP 2] When Firmware trigger assert\r\n" + "[AT] _REG 1 0x08 30\r\n" + "[PD+] 3\r\n" + "[AT] GPIO 0 8\r\n" + "[PD-]\r\n" + "[AT] GPIO 1 6 3\r\n" + "[AT] WAK+\r\n" + "[AT] WAK-\r\n" + "\r\n"; + + g_step_test_check.step_check_total = 11; + g_step_test_check.step_check_test_tp_id[0] = -1; + g_step_test_check.step_check_test_act_id[0] = STEP_ACTION_INDEX_EMI; + g_step_test_check.step_check_test_tp_id[1] = -1; + g_step_test_check.step_check_test_act_id[1] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[2] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[2] = STEP_ACTION_INDEX_PERIODIC_DUMP; + g_step_test_check.step_check_test_tp_id[3] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[3] = STEP_ACTION_INDEX_DISABLE_RESET; + g_step_test_check.step_check_test_tp_id[4] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[4] = STEP_ACTION_INDEX_CHIP_RESET; + g_step_test_check.step_check_test_tp_id[5] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[5] = STEP_ACTION_INDEX_REGISTER; + g_step_test_check.step_check_test_tp_id[6] = -1; + g_step_test_check.step_check_test_act_id[6] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[7] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[7] = STEP_ACTION_INDEX_PERIODIC_DUMP; + g_step_test_check.step_check_test_tp_id[8] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[8] = STEP_ACTION_INDEX_GPIO; + g_step_test_check.step_check_test_tp_id[9] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[9] = STEP_ACTION_INDEX_KEEP_WAKEUP; + g_step_test_check.step_check_test_tp_id[10] = STEP_TRIGGER_POINT_FIRMWARE_TRIGGER_ASSERT; + g_step_test_check.step_check_test_act_id[10] = STEP_ACTION_INDEX_CANCEL_WAKEUP; + g_step_test_check.step_check_params[0][0] = "0"; + g_step_test_check.step_check_params[0][1] = "0x50"; + g_step_test_check.step_check_params[0][2] = "0x9c"; + g_step_test_check.step_check_params_num[0] = 3; + g_step_test_check.step_check_params[1][0] = "0"; + g_step_test_check.step_check_params[1][1] = "0x08"; + g_step_test_check.step_check_params[1][2] = "5"; + g_step_test_check.step_check_params[1][3] = "2"; + g_step_test_check.step_check_params_num[1] = 4; + g_step_test_check.step_check_params[5][0] = "1"; + g_step_test_check.step_check_params[5][1] = "0x08"; + g_step_test_check.step_check_params[5][2] = "30"; + g_step_test_check.step_check_params_num[5] = 3; + g_step_test_check.step_check_params[6][0] = "0"; + g_step_test_check.step_check_params[6][1] = "8"; + g_step_test_check.step_check_params_num[6] = 2; + g_step_test_check.step_check_params[8][0] = "1"; + g_step_test_check.step_check_params[8][1] = "6"; + g_step_test_check.step_check_params[8][2] = "3"; + g_step_test_check.step_check_params_num[8] = 3; + __wmt_step_test_parse_data(buf, &temp_report, + "STEP test case failed: (Parse data TC-8) Periodic dump\n"); + + /********************************* + ******** Test case 9 ************ + *** Boundary: Much parameter **** + *********************************/ + WMT_INFO_FUNC("STEP test: TC 9\n"); + wmt_step_test_clear_check_data(); + buf = + "// TEST NOW\r\n" + "\r\n" + "[TP 1] When Command timeout\r\n" + "[AT] _EMI 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0x10 0x11 0x12 0x13\r\n" + "\r\n"; + + g_step_test_check.step_check_total = 1; + g_step_test_check.step_check_test_tp_id[0] = STEP_TRIGGER_POINT_COMMAND_TIMEOUT; + g_step_test_check.step_check_test_act_id[0] = STEP_ACTION_INDEX_EMI; + g_step_test_check.step_check_params[0][0] = "0x1"; + g_step_test_check.step_check_params[0][1] = "0x2"; + g_step_test_check.step_check_params[0][2] = "0x3"; + g_step_test_check.step_check_params[0][3] = "0x4"; + g_step_test_check.step_check_params[0][4] = "0x5"; + g_step_test_check.step_check_params[0][5] = "0x6"; + g_step_test_check.step_check_params[0][6] = "0x7"; + g_step_test_check.step_check_params[0][7] = "0x8"; + g_step_test_check.step_check_params[0][8] = "0x9"; + g_step_test_check.step_check_params[0][9] = "0x10"; + g_step_test_check.step_check_params_num[0] = 10; + + __wmt_step_test_parse_data(buf, &temp_report, + "STEP test case failed: (Parse data TC-9) Boundary: Much parameter\n"); + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Parse data result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_create_emi_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + int check_params[STEP_PARAMETER_SIZE]; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + int param_num = 0; + + WMT_INFO_FUNC("STEP test: Create EMI action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_EMI; + + /***************************** + ******** Test case 1 ******** + **** EMI create for read **** + *****************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "0x50"; + params[2] = "0x9c"; + param_num = 3; + check_params[0] = 0; + check_params[1] = 0x50; + check_params[2] = 0x9c; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-1) EMI create"); + + /************************************ + ********** Test case 2 ************ + **** EMI create fail less param **** + ************************************/ + WMT_INFO_FUNC("STEP test: TC 2\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "0x50"; + param_num = 2; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-2) EMI create fail"); + + /************************************************* + **************** Test case 3 ******************* + ********** Save emi to temp register ************ + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 3\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "0x50"; + params[2] = "0x00000030"; + params[3] = "$3"; + param_num = 4; + check_params[0] = 0; + check_params[1] = 0x50; + check_params[2] = 0x00000030; + check_params[3] = 3; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-3) Save emi to temp register"); + + /************************************************* + **************** Test case 4 ******************* + ** Boundary: Save emi to wrong temp register **** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 4\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "0x50"; + params[2] = "0x00000030"; + params[3] = "$30"; + param_num = 4; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-4) Boundary: Save emi to wrong temp register"); + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Create EMI action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_create_cond_emi_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + int check_params[STEP_PARAMETER_SIZE]; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + int param_num = 0; + + WMT_INFO_FUNC("STEP test: Create condition EMI action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_CONDITION_EMI; + + /************************************************* + **************** Test case 1 ******************* + ************ Condition emi create *************** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$1"; + params[1] = "0"; + params[2] = "0x50"; + params[3] = "0x70"; + param_num = 4; + check_params[0] = 1; + check_params[1] = 0; + check_params[2] = 0x50; + check_params[3] = 0x70; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-1) Condition emi create"); + + /************************************************* + **************** Test case 2 ******************* + ****** Save condition emi to temp register ****** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 2\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$2"; + params[1] = "0"; + params[2] = "0x50"; + params[3] = "0x00000030"; + params[4] = "$3"; + param_num = 5; + check_params[0] = 2; + check_params[1] = 0; + check_params[2] = 0x50; + check_params[3] = 0x00000030; + check_params[4] = 3; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-2) Save condition emi to temp register"); + + /*********************************************************** + ******************** Test case 3 ************************* + ** Boundary: Save condition emi to wrong temp register **** + ***********************************************************/ + WMT_INFO_FUNC("STEP test: TC 3\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$1"; + params[1] = "0"; + params[2] = "0x50"; + params[3] = "0x00000030"; + params[4] = "$30"; + param_num = 5; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-3) Boundary: Boundary: Save condition emi to wrong temp register"); + + /*********************************************************** + ******************** Test case 4 ************************* + ** Boundary: Save condition emi is wrong temp register **** + ***********************************************************/ + WMT_INFO_FUNC("STEP test: TC 4\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$30"; + params[1] = "0"; + params[2] = "0x50"; + params[3] = "0x00000030"; + params[4] = "$1"; + param_num = 5; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-4) Boundary: Boundary: Save condition emi is wrong temp register"); + + /************************************************* + **************** Test case 5 ******************* + ******* Condition emi create less params ******** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 5\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$1"; + params[1] = "0"; + params[2] = "0x50"; + param_num = 3; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-5) Condition emi create less params"); + + /************************************************* + **************** Test case 6 ******************* + ******* Condition emi create wrong symbol ******* + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 6\n"); + wmt_step_test_clear_parameter(params); + params[0] = "1"; + params[1] = "0"; + params[2] = "0x50"; + params[3] = "0x00000030"; + params[4] = "$1"; + param_num = 5; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-6) Condition emi create wrong symbol"); + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Create condition EMI action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_create_register_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + int check_params[STEP_PARAMETER_SIZE]; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + int param_num = 0; + + WMT_INFO_FUNC("STEP test: Create Register action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_REGISTER; + + /**************************************** + ************ Test case 1 *************** + **** REGISTER(Addr) create for read **** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "0x124dfad"; + params[2] = "0x9c"; + params[3] = "2"; + params[4] = "10"; + param_num = 5; + check_params[0] = 0; + check_params[1] = 0x124dfad; + check_params[2] = 0x9c; + check_params[3] = 2; + check_params[4] = 10; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-1) REG create read"); + + /***************************************** + ************ Test case 2 **************** + **** REGISTER(Addr) create for write **** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 2\n"); + wmt_step_test_clear_parameter(params); + params[0] = "1"; + params[1] = "0x124dfad"; + params[2] = "0x9c"; + params[3] = "15"; + param_num = 4; + check_params[0] = 1; + check_params[1] = 0x124dfad; + check_params[2] = 0x9c; + check_params[3] = 15; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-2) REG create write"); + + /****************************************** + ************** Test case 3 *************** + ******* Boundary: read wrong symbol ****** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 3\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "#10000"; + params[2] = "0x204"; + params[3] = "1"; + params[4] = "0"; + param_num = 5; + check_params[0] = 0; + check_params[1] = 0x124dfad; + check_params[2] = 0x9c; + check_params[3] = 2; + check_params[4] = 10; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-3) Boundary: read wrong symbol"); + + /**************************************************** + **************** Test case 4 ********************** + **** REGISTER(Addr) create read fail less param **** + ****************************************************/ + WMT_INFO_FUNC("STEP test: TC 4\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "0x124dfad"; + params[2] = "0x9c"; + param_num = 3; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-4) REG create read fail"); + + /***************************************************** + ************ Test case 5 *************************** + **** REGISTER(Addr) create write fail less param **** + *****************************************************/ + WMT_INFO_FUNC("STEP test: TC 5\n"); + wmt_step_test_clear_parameter(params); + params[0] = "1"; + params[1] = "0x124dfad"; + params[2] = "0x9c"; + param_num = 3; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-5) REG create write fail"); + + /***************************************** + ************ Test case 6 **************** + ** REGISTER(Addr) create for write bit *** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 6\n"); + wmt_step_test_clear_parameter(params); + params[0] = "1"; + params[1] = "0x124dfad"; + params[2] = "0x9c"; + params[3] = "15"; + params[4] = "0xFF00FF00"; + param_num = 5; + check_params[0] = 1; + check_params[1] = 0x124dfad; + check_params[2] = 0x9c; + check_params[3] = 15; + check_params[4] = 0xFF00FF00; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-6) REG create write"); + + /********************************************************* + ******************** Test case 7 *********************** + **** REGISTER(Addr) create for read to temp register **** + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 7\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "0x124dfad"; + params[2] = "0x9c"; + params[3] = "0x00000030"; + params[4] = "$5"; + param_num = 5; + check_params[0] = 0; + check_params[1] = 0x124dfad; + check_params[2] = 0x9c; + check_params[3] = 0x00000030; + check_params[4] = 5; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-7) REGISTER(Addr) create for read to temp register"); + + /********************************************************* + ******************** Test case 8 *********************** + *** REGISTER(Symbol) create for read to temp register *** + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 8\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "#1"; + params[2] = "0x9c"; + params[3] = "0x00000030"; + params[4] = "$7"; + param_num = 5; + check_params[0] = 0; + check_params[1] = 1; + check_params[2] = 0x9c; + check_params[3] = 0x00000030; + check_params[4] = 7; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-8) REGISTER(Symbol) create for read to temp register"); + + /********************************************************* + ******************** Test case 9 *********************** + ********** REGISTER(Symbol) create for read ************* + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 9\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "#1"; + params[2] = "0x9c"; + params[3] = "1"; + params[4] = "10"; + param_num = 5; + check_params[0] = 0; + check_params[1] = 1; + check_params[2] = 0x9c; + check_params[3] = 1; + check_params[4] = 10; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-9) REGISTER(Symbol) create for read"); + + /********************************************************* + ******************** Test case 10 *********************** + ************ REGISTER(Addr) less parameter ************** + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 10\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "0x124dfad"; + params[2] = "0x9c"; + params[3] = "0x555"; + param_num = 4; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-10) REGISTER(Addr) less parameter"); + + /********************************************************* + ******************** Test case 11 *********************** + ************ REGISTER(Symbol) less parameter ************** + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 11\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "#1"; + params[2] = "0x9c"; + params[3] = "0x555"; + param_num = 4; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-11) REGISTER(Symbol) less parameter"); + + /********************************************************** + *********************** Test case 12 ********************* + ** Boundary: REGISTER(Addr) read to worng temp register ** + **********************************************************/ + WMT_INFO_FUNC("STEP test: TC 12\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "0x124dfad"; + params[2] = "0x9c"; + params[3] = "0x00000030"; + params[4] = "$35"; + param_num = 5; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-12) Boundary: REGISTER(Addr) read to worng temp registe"); + + /************************************************************ + *********************** Test case 13 *********************** + ** Boundary: REGISTER(Symbol) read to worng temp register ** + ************************************************************/ + WMT_INFO_FUNC("STEP test: TC 13\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "#1"; + params[2] = "0x9c"; + params[3] = "0x00000030"; + params[4] = "$35"; + param_num = 5; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-13) Boundary: REGISTER(Symbol) read to worng temp registe"); + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Create register action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_create_cond_register_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + int check_params[STEP_PARAMETER_SIZE]; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + int param_num = 0; + + WMT_INFO_FUNC("STEP test: Create condition Register action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_CONDITION_REGISTER; + + /**************************************** + ************ Test case 1 *************** + **** COND_REG(Addr) create for read **** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$5"; + params[1] = "0"; + params[2] = "0x124dfad"; + params[3] = "0x9c"; + params[4] = "2"; + params[5] = "10"; + param_num = 6; + check_params[0] = 5; + check_params[1] = 0; + check_params[2] = 0x124dfad; + check_params[3] = 0x9c; + check_params[4] = 2; + check_params[5] = 10; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-1) COND_REG(Addr) create for read"); + + /***************************************** + ************ Test case 2 **************** + **** COND_REG(Addr) create for write **** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 2\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$7"; + params[1] = "1"; + params[2] = "0x124dfad"; + params[3] = "0x9c"; + params[4] = "15"; + param_num = 5; + check_params[0] = 7; + check_params[1] = 1; + check_params[2] = 0x124dfad; + check_params[3] = 0x9c; + check_params[4] = 15; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-2) COND_REG(Addr) create write"); + + /****************************************** + ************** Test case 3 *************** + ******* Boundary: read wrong symbol ****** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 3\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$2"; + params[1] = "0"; + params[2] = "#10000"; + params[3] = "0x204"; + params[4] = "1"; + params[5] = "0"; + param_num = 6; + check_params[0] = 2; + check_params[1] = 0; + check_params[2] = 0x124dfad; + check_params[3] = 0x9c; + check_params[4] = 2; + check_params[5] = 10; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-3) Boundary: read wrong symbol"); + + /**************************************************** + **************** Test case 4 ********************** + **** COND_REG(Addr) create read fail less param **** + ****************************************************/ + WMT_INFO_FUNC("STEP test: TC 4\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$3"; + params[1] = "0"; + params[2] = "0x124dfad"; + params[3] = "0x9c"; + param_num = 4; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-4) COND_REG create read fail"); + + /***************************************************** + ************ Test case 5 *************************** + **** COND_REG(Addr) create write fail less param **** + *****************************************************/ + WMT_INFO_FUNC("STEP test: TC 5\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$4"; + params[1] = "1"; + params[2] = "0x124dfad"; + params[3] = "0x9c"; + param_num = 4; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-5) COND_REG create write fail"); + + /***************************************** + ************ Test case 6 **************** + ** COND_REG(Addr) create for write bit *** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 6\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$9"; + params[1] = "1"; + params[2] = "0x124dfad"; + params[3] = "0x9c"; + params[4] = "15"; + params[5] = "0xFF00FF00"; + param_num = 6; + check_params[0] = 9; + check_params[1] = 1; + check_params[2] = 0x124dfad; + check_params[3] = 0x9c; + check_params[4] = 15; + check_params[5] = 0xFF00FF00; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-6) COND_REG create write"); + + /********************************************************* + ******************** Test case 7 *********************** + **** COND_REG(Addr) create for read to temp register **** + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 7\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$9"; + params[1] = "0"; + params[2] = "0x124dfad"; + params[3] = "0x9c"; + params[4] = "0x00000030"; + params[5] = "$5"; + param_num = 6; + check_params[0] = 9; + check_params[1] = 0; + check_params[2] = 0x124dfad; + check_params[3] = 0x9c; + check_params[4] = 0x00000030; + check_params[5] = 5; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-7) COND_REG(Addr) create for read to temp register"); + + /********************************************************* + ******************** Test case 8 *********************** + *** COND_REG(Symbol) create for read to temp register *** + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 8\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$1"; + params[1] = "0"; + params[2] = "#1"; + params[3] = "0x9c"; + params[4] = "0x00000030"; + params[5] = "$7"; + param_num = 6; + check_params[0] = 1; + check_params[1] = 0; + check_params[2] = 1; + check_params[3] = 0x9c; + check_params[4] = 0x00000030; + check_params[5] = 7; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-8) COND_REG(Symbol) create for read to temp register"); + + /********************************************************* + ******************** Test case 9 *********************** + ********** COND_REG(Symbol) create for read ************* + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 9\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$2"; + params[1] = "0"; + params[2] = "#1"; + params[3] = "0x9c"; + params[4] = "1"; + params[5] = "10"; + param_num = 6; + check_params[0] = 2; + check_params[1] = 0; + check_params[2] = 1; + check_params[3] = 0x9c; + check_params[4] = 1; + check_params[5] = 10; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-9) COND_REG(Symbol) create for read"); + + /********************************************************* + ******************** Test case 10 *********************** + ************ COND_REG(Addr) less parameter ************** + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 10\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$3"; + params[1] = "0"; + params[2] = "0x124dfad"; + params[3] = "0x9c"; + params[4] = "0x555"; + param_num = 5; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-10) COND_REG(Addr) less parameter"); + + /********************************************************* + ******************** Test case 11 *********************** + ************ COND_REG(Symbol) less parameter ************** + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 11\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$4"; + params[1] = "0"; + params[2] = "#1"; + params[3] = "0x9c"; + params[4] = "0x555"; + param_num = 5; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-11) COND_REG(Symbol) less parameter"); + + /********************************************************** + *********************** Test case 12 ********************* + ** Boundary: COND_REG(Addr) read to worng temp register ** + **********************************************************/ + WMT_INFO_FUNC("STEP test: TC 12\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$5"; + params[1] = "0"; + params[2] = "0x124dfad"; + params[3] = "0x9c"; + params[4] = "0x00000030"; + params[5] = "$35"; + param_num = 6; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-12) Boundary: COND_REG(Addr) read to worng temp registe"); + + /************************************************************ + *********************** Test case 13 *********************** + ** Boundary: COND_REG(Symbol) read to worng temp register ** + ************************************************************/ + WMT_INFO_FUNC("STEP test: TC 13\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$6"; + params[1] = "0"; + params[2] = "#1"; + params[3] = "0x9c"; + params[4] = "0x00000030"; + params[5] = "$35"; + param_num = 6; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-13) Boundary: COND_REG(Symbol) read to worng temp registe"); + + /********************************************************* + ******************** Test case 14 *********************** + ************* COND_REG(Symbol) worng symbol ************* + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 14\n"); + wmt_step_test_clear_parameter(params); + params[0] = "8"; + params[1] = "0"; + params[2] = "#1"; + params[3] = "0x9c"; + params[4] = "1"; + params[5] = "10"; + param_num = 6; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-14) Boundary: COND_REG(Symbol) worng symbol"); + + /********************************************************* + ******************** Test case 15 *********************** + ********* COND_REG(Symbol) worng temp register id ******* + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 15\n"); + wmt_step_test_clear_parameter(params); + params[0] = "$88"; + params[1] = "0"; + params[2] = "#1"; + params[3] = "0x9c"; + params[4] = "1"; + params[5] = "10"; + param_num = 6; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-15) Boundary: COND_REG(Symbol) read to worng temp registe"); + + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Create condition register action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +int wmt_step_test_get_symbol_num(void) +{ + int len = 0; + struct device_node *node = NULL; + + if (g_pdev != NULL) { + node = g_pdev->dev.of_node; + if (node) { + of_get_property(node, "reg", &len); + len /= (of_n_addr_cells(node) + of_n_size_cells(node)); + len /= (sizeof(int)); + } else { + WMT_ERR_FUNC("STEP test failed: node null"); + return -1; + } + } else { + WMT_ERR_FUNC("STEP test failed: gdev null"); + return -1; + } + + return len; +} + +void wmt_step_test_check_register_symbol(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + int check_params[STEP_PARAMETER_SIZE]; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + int param_num = 0; + int i = 0; + int symbol_num = wmt_step_test_get_symbol_num(); + unsigned char buf[4]; + + WMT_INFO_FUNC("STEP test: Check Register symbol start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_REGISTER; + /********************************************************* + ******************** Test case 1 *********************** + ********** REGISTER(Symbol) create for read ************* + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + if (symbol_num < 0) { + temp_report.fail++; + } else { + if (symbol_num >= STEP_REGISTER_MAX) { + symbol_num = STEP_REGISTER_MAX - 1; + } + + for (i = 1; i <= symbol_num; i++) { + wmt_step_test_clear_parameter(params); + params[0] = "0"; + snprintf(buf, 4, "#%d", i); + params[1] = buf; + params[2] = "0x9c"; + params[3] = "1"; + params[4] = "10"; + param_num = 5; + check_params[0] = 0; + check_params[1] = i; + check_params[2] = 0x9c; + check_params[3] = 1; + check_params[4] = 10; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Check Register symbol TC-1) REGISTER(Symbol) create for read"); + } + } + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Check Register symbol result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_create_other_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + int check_params[STEP_PARAMETER_SIZE]; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + struct step_pd_entry fack_pd_entry; + int param_num = 0; + + WMT_INFO_FUNC("STEP test: Create other action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + /****************************************** + ************ Test case 1 ***************** + ********** GPIO create for read ********** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_GPIO; + params[0] = "0"; + params[1] = "8"; + param_num = 2; + check_params[0] = 0; + check_params[1] = 8; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-1) GPIO create read"); + + /***************************************** + ************ Test case 2 **************** + ********* DISABLE REST create *********** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 2\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_DISABLE_RESET; + param_num = 0; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-2) DISABLE REST"); + + /***************************************** + ************ Test case 3 **************** + ********** CHIP REST create ************* + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 3\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_CHIP_RESET; + param_num = 0; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-3) CHIP REST"); + + /***************************************** + ************ Test case 4 **************** + ******** Keep Wakeup create ************* + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 4\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_KEEP_WAKEUP; + param_num = 0; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-4) Keep wakeup"); + + /***************************************** + ************ Test case 5 **************** + ***** Cancel keep wakeup create ********* + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 5\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_CANCEL_WAKEUP; + param_num = 0; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-5) Cancel keep wakeup"); + + /************************************************* + **************** Test case 6 ******************* + ********** GPIO create fail less param ********** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 6\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_GPIO; + params[0] = "0"; + param_num = 1; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-6) GPIO create fail"); + + /************************************************* + **************** Test case 7 ******************* + ************** Periodic dump create ************* + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 7\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_PERIODIC_DUMP; + params[0] = (PINT8)&fack_pd_entry; + param_num = 1; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-7) Periodic dump create fail"); + + /************************************************* + **************** Test case 8 ******************* + ****** Periodic dump create fail no param ******* + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 8\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_PERIODIC_DUMP; + param_num = 0; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-8) Periodic dump create fail"); + + /************************************************* + **************** Test case 9 ******************* + **************** Show create ******************** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 9\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_SHOW_STRING; + params[0] = "Hello"; + param_num = 1; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-9) Show create"); + + /************************************************* + **************** Test case 10 ******************* + ******** Show create failed no param ************ + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 10\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_SHOW_STRING; + param_num = 0; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-10) Show create failed no param"); + + /************************************************* + **************** Test case 11 ******************* + **************** Sleep create ******************* + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 11\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_SLEEP; + params[0] = "1000"; + param_num = 1; + check_params[0] = 1000; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-11) Sleep create"); + + /************************************************* + **************** Test case 12 ******************* + ********* Sleep create failed no param ********** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 12\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_SLEEP; + param_num = 0; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-12) Sleep create failed no param"); + + /************************************************* + **************** Test case 13 ******************* + ************** Condition create ***************** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 13\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_CONDITION; + params[0] = "$0"; + params[1] = "$1"; + params[2] = "=="; + params[3] = "$2"; + param_num = 4; + check_params[0] = 0; + check_params[1] = 1; + check_params[2] = STEP_OPERATOR_EQUAL; + check_params[3] = 2; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-13) Condition create"); + + /************************************************* + **************** Test case 14 ******************* + *********** Condition create value ************** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 14\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_CONDITION; + params[0] = "$0"; + params[1] = "$1"; + params[2] = "=="; + params[3] = "16"; + param_num = 4; + check_params[0] = 0; + check_params[1] = 1; + check_params[2] = STEP_OPERATOR_EQUAL; + check_params[3] = 16; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-14) Condition create"); + + /************************************************* + **************** Test case 15 ******************* + ****** Condition create failed less param ******* + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 15\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_CONDITION; + params[0] = "$0"; + params[1] = "$1"; + params[2] = "$2"; + param_num = 3; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-15) Condition create failed less param"); + + /************************************************* + **************** Test case 16 ******************* + ******** Condition create failed no value******** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 16\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_CONDITION; + params[0] = "=="; + param_num = 1; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-16) Condition create failed no value"); + + /************************************************* + **************** Test case 17 ******************* + * Boundary: Condition create failed over reg id * + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 17\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_CONDITION; + params[0] = "$25"; + params[1] = "$1"; + params[2] = "=="; + params[3] = "$2"; + param_num = 4; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-17) Boundary: Condition create failed over reg id"); + + /************************************************* + **************** Test case 18 ******************* + * Boundary: Condition create failed over reg id * + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 18\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_CONDITION; + params[0] = "$0"; + params[1] = "$1"; + params[2] = "=="; + params[3] = "$20"; + param_num = 4; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-18) Boundary: Condition create failed over reg id"); + + /************************************************* + **************** Test case 19 ******************* + ******** Condition create failed operator******** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 19\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_CONDITION; + params[0] = "$0"; + params[1] = "$1"; + params[2] = "&"; + params[3] = "$2"; + param_num = 4; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-19) Condition create failed operator"); + + /************************************************* + **************** Test case 20 ******************* + **************** Value create ******************* + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 20\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_VALUE; + params[0] = "$0"; + params[1] = "0x123"; + param_num = 2; + check_params[0] = 0; + check_params[1] = 0x123; + __wmt_step_test_create_action(act_id, param_num, params, 0, check_params, &temp_report, + "STEP test case failed: (Create action TC-20) Condition create"); + + /************************************************* + **************** Test case 21 ******************* + ******* Value create failed wrong order ********* + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 21\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_VALUE; + params[0] = "0x123"; + params[1] = "$1"; + param_num = 2; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-21) Value create failed wrong order"); + + /************************************************* + **************** Test case 22 ******************* + ********* Value create failed no value ********** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 22\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_VALUE; + params[0] = "$1"; + param_num = 1; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-22) Value create failed no value"); + + /************************************************* + **************** Test case 23 ******************* + *** Boundary: Value create failed over reg id *** + *************************************************/ + WMT_INFO_FUNC("STEP test: TC 23\n"); + wmt_step_test_clear_parameter(params); + act_id = STEP_ACTION_INDEX_VALUE; + params[0] = "$25"; + params[1] = "0x123"; + param_num = 2; + __wmt_step_test_create_action(act_id, param_num, params, -1, check_params, &temp_report, + "STEP test case failed: (Create action TC-23) Boundary: Value create failed over reg id"); + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Create other action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +int wmt_step_test_get_emi_wmt_offset(unsigned char buf[], int offset) +{ + P_CONSYS_EMI_ADDR_INFO emi_phy_addr; + + emi_phy_addr = mtk_wcn_consys_soc_get_emi_phy_add(); + if (emi_phy_addr != NULL) { + snprintf(buf, 11, "0x%08x", ((unsigned int)emi_phy_addr->emi_core_dump_offset + offset)); + } else { + WMT_ERR_FUNC("STEP test failed: emi_phy_addr is NULL\n"); + return -1; + } + + return 0; +} + +void wmt_step_test_do_emi_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + unsigned char buf_begin[11]; + unsigned char buf_end[11]; + int param_num; + + WMT_INFO_FUNC("STEP test: Do EMI action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_EMI; + + if (wmt_step_test_get_emi_wmt_offset(buf_begin, 0x0) != 0) { + temp_report.fail++; + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Do EMI action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); + return; + } + + /***************************************** + ************ Test case 1 **************** + ********** EMI dump 32 bit ************** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x44); + params[1] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, 0x48); + params[2] = buf_end; + param_num = 3; + g_step_test_check.step_check_total = 1; + g_step_test_check.step_check_emi_offset[0] = 0x44; + __wmt_step_test_do_emi_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do EMI action TC-1) dump 32bit"); + + /***************************************** + ************ Test case 2 **************** + ****** EMI dump check for address ******* + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 2\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x24); + params[1] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, 0x44); + params[2] = buf_end; + param_num = 3; + g_step_test_check.step_check_total = 8; + g_step_test_check.step_check_emi_offset[0] = 0x24; + g_step_test_check.step_check_emi_offset[1] = 0x28; + g_step_test_check.step_check_emi_offset[2] = 0x2c; + g_step_test_check.step_check_emi_offset[3] = 0x30; + g_step_test_check.step_check_emi_offset[4] = 0x34; + g_step_test_check.step_check_emi_offset[5] = 0x38; + g_step_test_check.step_check_emi_offset[6] = 0x3c; + g_step_test_check.step_check_emi_offset[7] = 0x40; + __wmt_step_test_do_emi_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do EMI action TC-2) more address"); + + /***************************************** + ************ Test case 3 **************** + **** EMI dump begin larger than end ***** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 3\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x20); + params[1] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, 0x08); + params[2] = buf_end; + param_num = 3; + g_step_test_check.step_check_total = 6; + g_step_test_check.step_check_emi_offset[0] = 0x08; + g_step_test_check.step_check_emi_offset[1] = 0x0c; + g_step_test_check.step_check_emi_offset[2] = 0x10; + g_step_test_check.step_check_emi_offset[3] = 0x14; + g_step_test_check.step_check_emi_offset[4] = 0x18; + g_step_test_check.step_check_emi_offset[5] = 0x1c; + __wmt_step_test_do_emi_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do EMI action TC-3) begin larger than end"); + + /**************************************** + ************ Test case 4 *************** + ******** EMI only support read ********* + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 4\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "1"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x08); + params[1] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, 0x20); + params[2] = buf_end; + param_num = 3; + __wmt_step_test_do_emi_action(act_id, param_num, params, -1, &temp_report, + "STEP test case failed: (Do EMI action TC-4) only support read"); + + /**************************************** + ************ Test case 5 *************** + ********* EMI dump not 32bit *********** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 5\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x08); + params[1] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, 0x0e); + params[2] = buf_end; + param_num = 3; + g_step_test_check.step_check_total = 2; + g_step_test_check.step_check_emi_offset[0] = 0x08; + g_step_test_check.step_check_emi_offset[1] = 0x0c; + __wmt_step_test_do_emi_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do EMI action TC-5) not 32bit"); + + /***************************************** + ************ Test case 6 **************** + ***** EMI dump over emi max size ******** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 6\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, (gConEmiSize + 0x08)); + params[1] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, (gConEmiSize + 0x0e)); + params[2] = buf_end; + param_num = 3; + __wmt_step_test_do_emi_action(act_id, param_num, params, -1, &temp_report, + "STEP test case failed: (Do EMI action TC-6) over emi max size"); + + /***************************************** + ************ Test case 7 **************** + ************* page fault **************** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 7\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x02); + params[1] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, 0x08); + params[2] = buf_end; + param_num = 3; + __wmt_step_test_do_emi_action(act_id, param_num, params, -1, &temp_report, + "STEP test case failed: (Do EMI action TC-7) page fault"); + + /***************************************** + ************ Test case 8 **************** + ********** save to temp reg ************* + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 8\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x08); + params[1] = buf_begin; + params[2] = "0x0F0F0F0F"; + params[3] = "$1"; + param_num = 4; + g_step_test_check.step_check_total = 1; + g_step_test_check.step_check_emi_offset[0] = 0x08; + g_step_test_check.step_test_mask = 0x0F0F0F0F; + g_step_test_check.step_check_temp_register_id = 1; + __wmt_step_test_do_emi_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do EMI action TC-8) save to temp reg"); + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Do EMI action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_do_cond_emi_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + unsigned char buf_begin[11]; + unsigned char buf_end[11]; + int param_num; + + WMT_INFO_FUNC("STEP test: Do condition EMI action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_CONDITION_EMI; + /***************************************** + ************ Test case 1 **************** + ********** EMI dump 32 bit ************** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$0"; + params[1] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x44); + params[2] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, 0x48); + params[3] = buf_end; + param_num = 4; + g_step_env.temp_register[0] = 1; + + g_step_test_check.step_check_total = 1; + g_step_test_check.step_check_emi_offset[0] = 0x44; + __wmt_step_test_do_cond_emi_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do COND EMI action TC-1) dump 32bit"); + + /***************************************** + ************ Test case 2 **************** + ****** EMI dump check for address ******* + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 2\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$1"; + params[1] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x24); + params[2] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, 0x44); + params[3] = buf_end; + param_num = 4; + g_step_env.temp_register[1] = 1; + + g_step_test_check.step_check_total = 8; + g_step_test_check.step_check_emi_offset[0] = 0x24; + g_step_test_check.step_check_emi_offset[1] = 0x28; + g_step_test_check.step_check_emi_offset[2] = 0x2c; + g_step_test_check.step_check_emi_offset[3] = 0x30; + g_step_test_check.step_check_emi_offset[4] = 0x34; + g_step_test_check.step_check_emi_offset[5] = 0x38; + g_step_test_check.step_check_emi_offset[6] = 0x3c; + g_step_test_check.step_check_emi_offset[7] = 0x40; + __wmt_step_test_do_cond_emi_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do COND EMI action TC-2) more address"); + + /***************************************** + ************ Test case 3 **************** + **** EMI dump begin larger than end ***** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 3\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$0"; + params[1] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x20); + params[2] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, 0x08); + params[3] = buf_end; + param_num = 4; + g_step_env.temp_register[0] = 15; + + g_step_test_check.step_check_total = 6; + g_step_test_check.step_check_emi_offset[0] = 0x08; + g_step_test_check.step_check_emi_offset[1] = 0x0c; + g_step_test_check.step_check_emi_offset[2] = 0x10; + g_step_test_check.step_check_emi_offset[3] = 0x14; + g_step_test_check.step_check_emi_offset[4] = 0x18; + g_step_test_check.step_check_emi_offset[5] = 0x1c; + __wmt_step_test_do_cond_emi_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do COND EMI action TC-3) begin larger than end"); + + /**************************************** + ************ Test case 4 *************** + ******** EMI only support read ********* + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 4\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$1"; + params[1] = "1"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x08); + params[2] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, 0x20); + params[3] = buf_end; + param_num = 4; + g_step_env.temp_register[1] = 1; + + __wmt_step_test_do_cond_emi_action(act_id, param_num, params, -1, &temp_report, + "STEP test case failed: (Do COND EMI action TC-4) only support read"); + + /**************************************** + ************ Test case 5 *************** + ********* EMI dump not 32bit *********** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 5\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$0"; + params[1] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x08); + params[2] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, 0x0e); + params[3] = buf_end; + param_num = 4; + g_step_env.temp_register[0] = 1; + + g_step_test_check.step_check_total = 2; + g_step_test_check.step_check_emi_offset[0] = 0x08; + g_step_test_check.step_check_emi_offset[1] = 0x0c; + __wmt_step_test_do_cond_emi_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do COND EMI action TC-5) not 32bit"); + + /***************************************** + ************ Test case 6 **************** + ***** EMI dump over emi max size ******** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 6\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$9"; + params[1] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, (gConEmiSize + 0x08)); + params[2] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, (gConEmiSize + 0x0e)); + params[3] = buf_end; + param_num = 4; + g_step_env.temp_register[9] = 1; + + __wmt_step_test_do_cond_emi_action(act_id, param_num, params, -1, &temp_report, + "STEP test case failed: (Do COND EMI action TC-6) over emi max size"); + + /***************************************** + ************ Test case 7 **************** + ************* page fault **************** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 7\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$0"; + params[1] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x02); + params[2] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, 0x08); + params[3] = buf_end; + param_num = 4; + g_step_env.temp_register[0] = 1; + + __wmt_step_test_do_cond_emi_action(act_id, param_num, params, -1, &temp_report, + "STEP test case failed: (Do COND EMI action TC-7) page fault"); + + /***************************************** + ************ Test case 8 **************** + ********** save to temp reg ************* + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 8\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$0"; + params[1] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x08); + params[2] = buf_begin; + params[3] = "0x0F0F0F0F"; + params[4] = "$1"; + param_num = 5; + g_step_test_check.step_check_total = 1; + g_step_test_check.step_check_emi_offset[0] = 0x08; + g_step_test_check.step_test_mask = 0x0F0F0F0F; + g_step_test_check.step_check_temp_register_id = 1; + g_step_env.temp_register[0] = 1; + __wmt_step_test_do_cond_emi_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do EMI action TC-8) save to temp reg"); + + + /***************************************** + ************ Test case 9 **************** + ******** condition invalid ************** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 9\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$0"; + params[1] = "0"; + wmt_step_test_get_emi_wmt_offset(buf_begin, 0x08); + params[2] = buf_begin; + wmt_step_test_get_emi_wmt_offset(buf_end, 0x0e); + params[3] = buf_end; + param_num = 4; + g_step_env.temp_register[0] = 0; + + __wmt_step_test_do_cond_emi_action(act_id, param_num, params, -1, &temp_report, + "STEP test case failed: (Do COND EMI action TC-9) condition invalid"); + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Do condition EMI action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +int wmt_step_test_get_reg_base_phy_addr(unsigned char buf[], unsigned int index) +{ + struct device_node *node = NULL; + struct resource res; + int ret; + + if (g_pdev != NULL) { + node = g_pdev->dev.of_node; + if (node) { + ret = of_address_to_resource(node, index, &res); + if (ret) { + WMT_ERR_FUNC("STEP test failed: of_address_to_resource null"); + return ret; + } + } else { + WMT_ERR_FUNC("STEP test failed: node null"); + return -1; + } + } else { + WMT_ERR_FUNC("STEP test failed: gdev null"); + return -1; + } + snprintf(buf, 11, "0x%08x", ((unsigned int)res.start)); + + return 0; +} + +void wmt_step_test_do_register_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + unsigned char buf[11]; + int param_num; + int can_write_offset = 0; + unsigned char can_write_offset_char[11]; + + WMT_INFO_FUNC("STEP test: Do register action start\n"); + + can_write_offset = + wmt_step_test_find_can_write_register(conn_reg.mcu_base, 0x200, 0x0000000F); + if (can_write_offset == -1) { + p_report->fail++; + WMT_ERR_FUNC("STEP test: Do register action init can_write_offset failed\n"); + return; + } + snprintf(can_write_offset_char, 11, "0x%08x", can_write_offset); + + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_REGISTER; + /**************************************** + ************ Test case 1 *************** + ******** REG read MCU chip id ********** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "#1"; + params[2] = "0x08"; + params[3] = "1"; + params[4] = "0"; + param_num = 5; + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x08); + __wmt_step_test_do_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do register action TC-1) MCU chip id"); + + /**************************************** + ************ Test case 2 *************** + *** REG read cpucpr 5 times / 3ms **** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 2\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "#1"; + params[2] = "0x160"; + params[3] = "5"; + params[4] = "3"; + param_num = 5; + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x160); + __wmt_step_test_do_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do register action TC-2) cpucpr 5 times / 3ms"); + + /********************************************** + *************** Test case 3 ****************** + ** REG read MCU chip id by physical address ** + **********************************************/ + WMT_INFO_FUNC("STEP test: TC 3\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + if (wmt_step_test_get_reg_base_phy_addr(buf, 0) == 0) { + params[1] = buf; + params[2] = "0x08"; + params[3] = "1"; + params[4] = "0"; + param_num = 5; + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x08); + __wmt_step_test_do_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do register action TC-3) MCU chip id by phy"); + } else { + p_report->fail++; + WMT_ERR_FUNC("STEP test case failed: get physical address failed\n"); + } + + /********************************************************* + ********************* Test case 4 *********************** + ** REG read cpucpr 5 times / 3ms by physical address ** + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 4\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + if (wmt_step_test_get_reg_base_phy_addr(buf, 0) == 0) { + params[1] = buf; + params[2] = "0x160"; + params[3] = "5"; + params[4] = "3"; + param_num = 5; + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x160); + __wmt_step_test_do_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do register action TC-4) cpucpr 5 times / 3ms by phy"); + } else { + p_report->fail++; + WMT_ERR_FUNC("STEP test case failed: get physical address failed\n"); + } + + /***************************************** + ************* Test case 5 *************** + ******** REG read over base size ******** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 5\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "#1"; + params[2] = "0x11204"; + params[3] = "1"; + params[4] = "0"; + param_num = 5; + __wmt_step_test_do_register_action(act_id, param_num, params, -1, &temp_report, + "STEP test case failed: (Do register action TC-5) Over size"); + + /****************************************** + ************** Test case 6 *************** + ***** REG read over base size by phy ***** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 6\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + if (wmt_step_test_get_reg_base_phy_addr(buf, 0) == 0) { + params[1] = buf; + params[2] = "0x204"; + params[3] = "1"; + params[4] = "0"; + param_num = 5; + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x204); + __wmt_step_test_do_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do register action TC-6) Over size by phy"); + } else { + p_report->fail++; + WMT_ERR_FUNC("STEP test case failed: get physical address failed\n"); + } + + /****************************************** + ************** Test case 7 *************** + *************** REG write **************** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 7\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "1"; + params[1] = "#1"; + params[2] = can_write_offset_char; + params[3] = "0x2"; + param_num = 4; + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + can_write_offset); + g_step_test_check.step_check_write_value = 0x2; + __wmt_step_test_do_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do register action TC-7) REG write"); + + /****************************************** + ************** Test case 8 *************** + *********** REG write by phy ************* + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 8\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "1"; + if (wmt_step_test_get_reg_base_phy_addr(buf, 0) == 0) { + params[1] = buf; + params[2] = can_write_offset_char; + params[3] = "0x7"; + param_num = 4; + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + can_write_offset); + g_step_test_check.step_check_write_value = 0x7; + __wmt_step_test_do_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do register action TC-8) REG write by phy"); + } else { + p_report->fail++; + WMT_ERR_FUNC("STEP test case failed: get physical address failed\n"); + } + + /****************************************** + ************** Test case 9 *************** + ************* REG write bit ************** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 9\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "1"; + params[1] = "#1"; + params[2] = can_write_offset_char; + params[3] = "0x321"; + params[4] = "0x00F"; + param_num = 5; + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + can_write_offset); + g_step_test_check.step_check_write_value = 0x001; + g_step_test_check.step_test_mask = 0x00F; + __wmt_step_test_do_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do register action TC-9) REG write bit"); + + /****************************************** + ************** Test case 10 ************** + ********* REG write bit by phy *********** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 10\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "1"; + if (wmt_step_test_get_reg_base_phy_addr(buf, 0) == 0) { + params[1] = buf; + params[2] = can_write_offset_char; + params[3] = "0x32f"; + params[4] = "0x002"; + param_num = 5; + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + can_write_offset); + g_step_test_check.step_check_write_value = 0x002; + g_step_test_check.step_test_mask = 0x002; + __wmt_step_test_do_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do register action TC-10) REG write bit by phy"); + } else { + p_report->fail++; + WMT_ERR_FUNC("STEP test case failed: get physical address failed\n"); + } + + /****************************************** + ************** Test case 11 ************** + ********* REG read to temp reg *********** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 11\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "0"; + params[1] = "#1"; + params[2] = "0x08"; + params[3] = "0x0F0F0F0F"; + params[4] = "$2"; + param_num = 5; + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x08); + g_step_test_check.step_test_mask = 0x0F0F0F0F; + g_step_test_check.step_check_temp_register_id = 2; + __wmt_step_test_do_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do register action TC-11) REG read to temp reg"); + + /****************************************** + ************** Test case 12 ************** + ******* REG read phy to temp reg ********* + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 12\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "0"; + if (wmt_step_test_get_reg_base_phy_addr(buf, 0) == 0) { + params[1] = buf; + params[2] = "0x08"; + params[3] = "0x0F0F0F0F"; + params[4] = "$3"; + param_num = 5; + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x08); + g_step_test_check.step_test_mask = 0x0F0F0F0F; + g_step_test_check.step_check_temp_register_id = 3; + __wmt_step_test_do_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do register action TC-12) REG read phy to temp reg"); + } else { + p_report->fail++; + WMT_ERR_FUNC("STEP test case failed: get physical address failed\n"); + } + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Do register action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_do_cond_register_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + unsigned char buf[11]; + int param_num; + int can_write_offset = 0; + unsigned char can_write_offset_char[11]; + + WMT_INFO_FUNC("STEP test: Do condition register action start\n"); + + can_write_offset = + wmt_step_test_find_can_write_register(conn_reg.mcu_base, 0x200, 0x0000000F); + if (can_write_offset == -1) { + p_report->fail++; + WMT_ERR_FUNC("STEP test: Do register action init can_write_offset failed\n"); + return; + } + snprintf(can_write_offset_char, 11, "0x%08x", can_write_offset); + + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_CONDITION_REGISTER; + /**************************************** + ************ Test case 1 *************** + ******** REG read MCU chip id ********** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$0"; + params[1] = "0"; + params[2] = "#1"; + params[3] = "0x08"; + params[4] = "1"; + params[5] = "0"; + param_num = 6; + g_step_env.temp_register[0] = 1; + + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x08); + __wmt_step_test_do_cond_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do cond register action TC-1) MCU chip id"); + + /**************************************** + ************ Test case 2 *************** + *** REG read cpucpr 5 times / 3ms **** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 2\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$1"; + params[1] = "0"; + params[2] = "#1"; + params[3] = "0x160"; + params[4] = "5"; + params[5] = "3"; + param_num = 6; + g_step_env.temp_register[1] = 1; + + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x160); + __wmt_step_test_do_cond_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do cond register action TC-2) cpucpr 5 times / 3ms"); + + /********************************************** + *************** Test case 3 ****************** + ** REG read MCU chip id by physical address ** + **********************************************/ + WMT_INFO_FUNC("STEP test: TC 3\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$2"; + params[1] = "0"; + if (wmt_step_test_get_reg_base_phy_addr(buf, 0) == 0) { + params[2] = buf; + params[3] = "0x08"; + params[4] = "1"; + params[5] = "0"; + param_num = 6; + g_step_env.temp_register[2] = 1; + + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x08); + __wmt_step_test_do_cond_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do cond register action TC-3) MCU chip id by phy"); + } else { + p_report->fail++; + WMT_ERR_FUNC("STEP test case failed: get physical address failed\n"); + } + + /********************************************************* + ********************* Test case 4 *********************** + ** REG read cpucpr 5 times / 3ms by physical address ** + *********************************************************/ + WMT_INFO_FUNC("STEP test: TC 4\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$3"; + params[1] = "0"; + if (wmt_step_test_get_reg_base_phy_addr(buf, 0) == 0) { + params[2] = buf; + params[3] = "0x160"; + params[4] = "5"; + params[5] = "3"; + param_num = 6; + g_step_env.temp_register[3] = 11; + + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x160); + __wmt_step_test_do_cond_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do cond register action TC-4) cpucpr 5 times / 3ms by phy"); + } else { + p_report->fail++; + WMT_ERR_FUNC("STEP test case failed: get physical address failed\n"); + } + + /***************************************** + ************* Test case 5 *************** + ******** REG read over base size ******** + *****************************************/ + WMT_INFO_FUNC("STEP test: TC 5\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$4"; + params[1] = "0"; + params[2] = "#1"; + params[3] = "0x11204"; + params[4] = "1"; + params[5] = "0"; + param_num = 6; + g_step_env.temp_register[4] = 10; + + __wmt_step_test_do_cond_register_action(act_id, param_num, params, -1, &temp_report, + "STEP test case failed: (Do cond register action TC-5) Over size"); + + /****************************************** + ************** Test case 6 *************** + ***** REG read over base size by phy ***** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 6\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$5"; + params[1] = "0"; + if (wmt_step_test_get_reg_base_phy_addr(buf, 0) == 0) { + params[2] = buf; + params[3] = "0x204"; + params[4] = "1"; + params[5] = "0"; + param_num = 6; + g_step_env.temp_register[5] = 1; + + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x204); + __wmt_step_test_do_cond_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do cond register action TC-6) Over size by phy"); + } else { + p_report->fail++; + WMT_ERR_FUNC("STEP test case failed: get physical address failed\n"); + } + + /****************************************** + ************** Test case 7 *************** + *************** REG write **************** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 7\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$6"; + params[1] = "1"; + params[2] = "#1"; + params[3] = can_write_offset_char; + params[4] = "0x2"; + param_num = 5; + g_step_env.temp_register[6] = 1; + + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + can_write_offset); + g_step_test_check.step_check_write_value = 0x2; + __wmt_step_test_do_cond_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do cond register action TC-7) REG write"); + + /****************************************** + ************** Test case 8 *************** + *********** REG write by phy ************* + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 8\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$7"; + params[1] = "1"; + if (wmt_step_test_get_reg_base_phy_addr(buf, 0) == 0) { + params[2] = buf; + params[3] = can_write_offset_char; + params[4] = "0x7"; + param_num = 5; + g_step_env.temp_register[7] = 1; + + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + can_write_offset); + g_step_test_check.step_check_write_value = 0x7; + __wmt_step_test_do_cond_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do cond register action TC-8) REG write by phy"); + } else { + p_report->fail++; + WMT_ERR_FUNC("STEP test case failed: get physical address failed\n"); + } + + /****************************************** + ************** Test case 9 *************** + ************* REG write bit ************** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 9\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$8"; + params[1] = "1"; + params[2] = "#1"; + params[3] = can_write_offset_char; + params[4] = "0x321"; + params[5] = "0x00F"; + param_num = 6; + g_step_env.temp_register[8] = 1; + + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + can_write_offset); + g_step_test_check.step_check_write_value = 0x001; + g_step_test_check.step_test_mask = 0x00F; + __wmt_step_test_do_cond_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do cond register action TC-9) REG write bit"); + + /****************************************** + ************** Test case 10 ************** + ********* REG write bit by phy *********** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 10\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$9"; + params[1] = "1"; + if (wmt_step_test_get_reg_base_phy_addr(buf, 0) == 0) { + params[2] = buf; + params[3] = can_write_offset_char; + params[4] = "0x32f"; + params[5] = "0x002"; + param_num = 6; + g_step_env.temp_register[9] = 1; + + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + can_write_offset); + g_step_test_check.step_check_write_value = 0x002; + g_step_test_check.step_test_mask = 0x002; + __wmt_step_test_do_cond_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do cond register action TC-10) REG write bit by phy"); + } else { + p_report->fail++; + WMT_ERR_FUNC("STEP test case failed: get physical address failed\n"); + } + + /****************************************** + ************** Test case 11 ************** + ********* REG read to temp reg *********** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 11\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$8"; + params[1] = "0"; + params[2] = "#1"; + params[3] = "0x08"; + params[4] = "0x0F0F0F0F"; + params[5] = "$2"; + param_num = 6; + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x08); + g_step_test_check.step_test_mask = 0x0F0F0F0F; + g_step_test_check.step_check_temp_register_id = 2; + g_step_env.temp_register[8] = 1; + __wmt_step_test_do_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do register action TC-11) REG read to temp reg"); + + /****************************************** + ************** Test case 12 ************** + ******* REG read phy to temp reg ********* + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 12\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$8"; + params[1] = "0"; + if (wmt_step_test_get_reg_base_phy_addr(buf, 0) == 0) { + params[2] = buf; + params[3] = "0x08"; + params[4] = "0x0F0F0F0F"; + params[5] = "$3"; + param_num = 6; + g_step_test_check.step_check_register_addr = (conn_reg.mcu_base + 0x08); + g_step_test_check.step_test_mask = 0x0F0F0F0F; + g_step_test_check.step_check_temp_register_id = 3; + g_step_env.temp_register[8] = 1; + __wmt_step_test_do_register_action(act_id, param_num, params, 0, &temp_report, + "STEP test case failed: (Do register action TC-12) REG read phy to temp reg"); + } else { + p_report->fail++; + WMT_ERR_FUNC("STEP test case failed: get physical address failed\n"); + } + + /****************************************** + ************** Test case 13 ************** + ************* condition invalid ********** + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 13\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$8"; + params[1] = "1"; + params[2] = "#1"; + params[3] = "0x160"; + params[4] = "0x123"; + params[5] = "0xF00"; + param_num = 6; + g_step_env.temp_register[8] = 0; + + __wmt_step_test_do_cond_register_action(act_id, param_num, params, -1, &temp_report, + "STEP test case failed: (Do cond register action TC-13) condition invalid"); + + /****************************************** + ************** Test case 14 ************** + ********** condition invalid write ******* + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 14\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$6"; + params[1] = "1"; + params[2] = "#1"; + params[3] = "0x110"; + params[4] = "0x200"; + param_num = 5; + g_step_env.temp_register[6] = 0; + + __wmt_step_test_do_cond_register_action(act_id, param_num, params, -1, &temp_report, + "STEP test case failed: (Do cond register action TC-14) condition invalid write"); + + /****************************************** + ************** Test case 15 ************** + ********** condition invalid read ******* + ******************************************/ + WMT_INFO_FUNC("STEP test: TC 15\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + wmt_step_test_clear_temp_register(); + params[0] = "$0"; + params[1] = "0"; + params[2] = "#1"; + params[3] = "0x08"; + params[4] = "1"; + params[5] = "0"; + param_num = 6; + g_step_env.temp_register[0] = 0; + + __wmt_step_test_do_cond_register_action(act_id, param_num, params, -1, &temp_report, + "STEP test case failed: (Do cond register action TC-15) REG write"); + + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Do condition register action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + + +void wmt_step_test_do_gpio_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + struct step_action *p_act = NULL; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + int param_num; + + WMT_INFO_FUNC("STEP test: Do GPIO action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_GPIO; + /**************************************** + ************* Test case 1 ************** + ************* GPIO read #8 ************* + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_parameter(params); + params[0] = "0"; + params[1] = "8"; + param_num = 2; + + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + if (wmt_step_do_gpio_action(p_act, NULL) == 0) { + WMT_INFO_FUNC("STEP check: Do gpio action TC-1(Read #8): search(8: )"); + temp_report.check++; + } else { + WMT_ERR_FUNC("STEP test case failed: (Do gpio action TC-1) Read #8\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: (Do gpio action TC-1) Create failed\n"); + } + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Do GPIO action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_do_chip_reset_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + struct step_action *p_act = NULL; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + int param_num; + + WMT_INFO_FUNC("STEP test: Do chip reset action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_CHIP_RESET; + /**************************************** + ************* Test case 1 ************** + ************* chip reset *************** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + param_num = 0; + + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + if (wmt_step_do_chip_reset_action(p_act, NULL) == 0) { + WMT_INFO_FUNC("STEP check: Do chip reset TC-1(chip reset): Trigger AEE"); + temp_report.check++; + } else { + WMT_ERR_FUNC("STEP test case failed: (Do chip reset action TC-1) chip reset\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: (Do chip reset action TC-1) Create failed\n"); + } + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Do chip reset action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_do_wakeup_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + struct step_action *p_act = NULL; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + int param_num; + + WMT_INFO_FUNC("STEP test: Do wakeup action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + /**************************************** + ************* Test case 1 ************** + ***** Wakeup then read/write reg ******* + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + act_id = STEP_ACTION_INDEX_KEEP_WAKEUP; + param_num = 0; + + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_keep_wakeup_action(p_act, NULL); + wmt_step_test_do_register_action(&temp_report); + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: (Do wakeup) Create failed\n"); + } + + act_id = STEP_ACTION_INDEX_CANCEL_WAKEUP; + param_num = 0; + + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_cancel_wakeup_action(p_act, NULL); + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: (Do cancel wakeup) Create failed\n"); + } + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Do wakeup action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_do_show_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + struct step_action *p_act = NULL; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + int param_num; + + WMT_INFO_FUNC("STEP test: Do show action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_SHOW_STRING; + /**************************************** + ************* Test case 1 ************** + ********** Show Hello world ************ + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_parameter(params); + params[0] = "Hello_World"; + param_num = 1; + + g_step_test_check.step_check_result_string = "Hello_World"; + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_show_string_action(p_act, wmt_step_test_check_show_act); + if (g_step_test_check.step_check_result == TEST_PASS) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do show TC-1(Show Hello world)\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do show TC-1(Show Hello world) Create failed\n"); + } + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Do show action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_do_sleep_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + struct step_action *p_act = NULL; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + int check_sec_b, check_sec_e; + int check_usec_b, check_usec_e; + int param_num; + + WMT_INFO_FUNC("STEP test: Do sleep action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_SLEEP; + /**************************************** + ************* Test case 1 ************** + *************** Sleep 1s *************** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_parameter(params); + params[0] = "1000"; + param_num = 1; + + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + osal_gettimeofday(&check_sec_b, &check_usec_b); + wmt_step_do_sleep_action(p_act, NULL); + osal_gettimeofday(&check_sec_e, &check_usec_e); + if (check_sec_e > check_sec_b) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do show TC-1(Sleep 1s), begin(%d.%d) end(%d.%d)\n", + check_sec_b, check_usec_b, check_sec_e, check_usec_e); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do show TC-1(Sleep 1s) Create failed\n"); + } + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Do sleep action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_do_condition_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + struct step_action *p_act = NULL; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + int param_num; + + WMT_INFO_FUNC("STEP test: Do condition action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_CONDITION; + /**************************************** + ************* Test case 1 ************** + *********** Condition equal ************ + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_temp_register(); + wmt_step_test_clear_parameter(params); + params[0] = "$0"; + params[1] = "$1"; + params[2] = "=="; + params[3] = "$2"; + param_num = 4; + + g_step_test_check.step_check_result_value = 1; + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_condition_action(p_act, wmt_step_test_check_condition_act); + if (g_step_test_check.step_check_result == TEST_PASS) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do condition TC-1(equal)\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do condition TC-1(equal) Create failed\n"); + } + + /**************************************** + ************* Test case 2 ************** + ********** Condition greater *********** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 2\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_temp_register(); + wmt_step_test_clear_parameter(params); + params[0] = "$0"; + params[1] = "$1"; + params[2] = ">"; + params[3] = "$2"; + param_num = 4; + g_step_env.temp_register[1] = 0; + g_step_env.temp_register[2] = 1; + + g_step_test_check.step_check_result_value = 0; + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_condition_action(p_act, wmt_step_test_check_condition_act); + if (g_step_test_check.step_check_result == TEST_PASS) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do condition TC-2(greater)\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do condition TC-2(greater) Create failed\n"); + } + + /**************************************** + ************* Test case 3 ************** + ******* Condition greater equal ******** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 3\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_temp_register(); + wmt_step_test_clear_parameter(params); + params[0] = "$0"; + params[1] = "$1"; + params[2] = ">="; + params[3] = "$2"; + param_num = 4; + g_step_env.temp_register[1] = 2; + g_step_env.temp_register[2] = 2; + + g_step_test_check.step_check_result_value = 1; + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_condition_action(p_act, wmt_step_test_check_condition_act); + if (g_step_test_check.step_check_result == TEST_PASS) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do condition TC-3(greater equal)\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do condition TC-3(greater equal) Create failed\n"); + } + + /**************************************** + ************* Test case 4 ************** + ************ Condition less ************ + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 4\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_temp_register(); + wmt_step_test_clear_parameter(params); + params[0] = "$0"; + params[1] = "$1"; + params[2] = "<"; + params[3] = "$2"; + param_num = 4; + g_step_env.temp_register[1] = 10; + g_step_env.temp_register[2] = 0; + + g_step_test_check.step_check_result_value = 0; + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_condition_action(p_act, wmt_step_test_check_condition_act); + if (g_step_test_check.step_check_result == TEST_PASS) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do condition TC-4(less)\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do condition TC-4(less) Create failed\n"); + } + + /**************************************** + ************* Test case 5 ************** + ********* Condition less equal ********* + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 5\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_temp_register(); + wmt_step_test_clear_parameter(params); + params[0] = "$0"; + params[1] = "$1"; + params[2] = "<="; + params[3] = "$2"; + param_num = 4; + g_step_env.temp_register[1] = 0; + g_step_env.temp_register[2] = 10; + + g_step_test_check.step_check_result_value = 1; + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_condition_action(p_act, wmt_step_test_check_condition_act); + if (g_step_test_check.step_check_result == TEST_PASS) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do condition TC-5(less equal)\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do condition TC-5(less equal) Create failed\n"); + } + + /**************************************** + ************* Test case 6 ************** + ********* Condition not equal ********** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 6\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_temp_register(); + wmt_step_test_clear_parameter(params); + params[0] = "$1"; + params[1] = "$2"; + params[2] = "!="; + params[3] = "$3"; + param_num = 4; + g_step_env.temp_register[2] = 3; + g_step_env.temp_register[3] = 3; + + g_step_test_check.step_check_result_value = 0; + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_condition_action(p_act, wmt_step_test_check_condition_act); + if (g_step_test_check.step_check_result == TEST_PASS) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do condition TC-6(not equal)\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do condition TC-6(not equal) Create failed\n"); + } + + /**************************************** + ************* Test case 7 ************** + ************ Condition and ************* + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 7\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_temp_register(); + wmt_step_test_clear_parameter(params); + params[0] = "$1"; + params[1] = "$2"; + params[2] = "&&"; + params[3] = "$3"; + param_num = 4; + g_step_env.temp_register[2] = 0x10; + g_step_env.temp_register[3] = 0x00; + + g_step_test_check.step_check_result_value = 0; + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_condition_action(p_act, wmt_step_test_check_condition_act); + if (g_step_test_check.step_check_result == TEST_PASS) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do condition TC-7(and)\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do condition TC-7(and) Create failed\n"); + } + + /**************************************** + ************* Test case 8 ************** + ************* Condition or ************* + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 8\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_temp_register(); + wmt_step_test_clear_parameter(params); + params[0] = "$1"; + params[1] = "$2"; + params[2] = "||"; + params[3] = "$3"; + param_num = 4; + g_step_env.temp_register[2] = 0x10; + g_step_env.temp_register[3] = 0x00; + + g_step_test_check.step_check_result_value = 1; + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_condition_action(p_act, wmt_step_test_check_condition_act); + if (g_step_test_check.step_check_result == TEST_PASS) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do condition TC-8(or)\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do condition TC-8(or) Create failed\n"); + } + + /**************************************** + ************* Test case 9 ************** + ****** Condition not equal value ******* + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 9\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_temp_register(); + wmt_step_test_clear_parameter(params); + params[0] = "$1"; + params[1] = "$2"; + params[2] = "!="; + params[3] = "99"; + param_num = 4; + g_step_env.temp_register[2] = 99; + + g_step_test_check.step_check_result_value = 0; + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_condition_action(p_act, wmt_step_test_check_condition_act); + if (g_step_test_check.step_check_result == TEST_PASS) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do condition TC-9(not equal value)\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do condition TC-9(not equal value) Create failed\n"); + } + + /**************************************** + ************* Test case 10 ************* + ********* Condition equal value ******** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 10\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_temp_register(); + wmt_step_test_clear_parameter(params); + params[0] = "$1"; + params[1] = "$2"; + params[2] = "=="; + params[3] = "18"; + param_num = 4; + g_step_env.temp_register[2] = 18; + + g_step_test_check.step_check_result_value = 1; + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_condition_action(p_act, wmt_step_test_check_condition_act); + if (g_step_test_check.step_check_result == TEST_PASS) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do condition TC-10(equal value)\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do condition TC-10(equal value) Create failed\n"); + } + + /**************************************** + ************* Test case 11 ************* + ****** Condition equal value (HEX) ***** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 10\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_temp_register(); + wmt_step_test_clear_parameter(params); + params[0] = "$1"; + params[1] = "$2"; + params[2] = "=="; + params[3] = "0x18"; + param_num = 4; + g_step_env.temp_register[2] = 24; + + g_step_test_check.step_check_result_value = 1; + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_condition_action(p_act, wmt_step_test_check_condition_act); + if (g_step_test_check.step_check_result == TEST_PASS) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do condition TC-11(equal value HEX)\n"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do condition TC-11(equal value HEX) Create failed\n"); + } + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Do condition action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_do_value_action(struct step_test_report *p_report) +{ + enum step_action_id act_id; + char *params[STEP_PARAMETER_SIZE]; + struct step_action *p_act = NULL; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + int param_num; + + WMT_INFO_FUNC("STEP test: Do value action start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + act_id = STEP_ACTION_INDEX_VALUE; + /**************************************** + ************* Test case 1 ************** + ******* Save value to register ********* + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + wmt_step_test_clear_check_data(); + wmt_step_test_clear_temp_register(); + wmt_step_test_clear_parameter(params); + params[0] = "$2"; + params[1] = "0x66"; + param_num = 2; + + g_step_test_check.step_check_result_value = 0x66; + p_act = wmt_step_create_action(act_id, param_num, params); + if (p_act != NULL) { + wmt_step_do_value_action(p_act, wmt_step_test_check_value_act); + if (g_step_test_check.step_check_result == TEST_PASS) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: Do show TC-1(Save value to register)"); + temp_report.fail++; + } + wmt_step_remove_action(p_act); + } else { + temp_report.fail++; + WMT_ERR_FUNC("STEP test case failed: Do show TC-1(Save value to register) Create failed\n"); + } + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Do value action result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + +void wmt_step_test_create_periodic_dump(struct step_test_report *p_report) +{ + int expires_ms; + struct step_test_report temp_report = {0, 0, 0}; + int sec_begin = 0; + int usec_begin = 0; + int sec_end = 0; + int usec_end = 0; + struct step_pd_entry *p_current; + bool is_thread_run_for_test = 0; + + WMT_INFO_FUNC("STEP test: Create periodic dump start\n"); + osal_gettimeofday(&sec_begin, &usec_begin); + + if (g_step_env.pd_struct.step_pd_wq == NULL) { + if (wmt_step_init_pd_env() != 0) { + WMT_ERR_FUNC("STEP test case failed: Start thread failed\n"); + return; + } + is_thread_run_for_test = 1; + } + + /**************************************** + ************* Test case 1 ************** + *************** Normal ***************** + ****************************************/ + WMT_INFO_FUNC("STEP test: TC 1\n"); + expires_ms = 5; + p_current = wmt_step_get_periodic_dump_entry(expires_ms); + if (p_current == NULL) { + WMT_ERR_FUNC("STEP test case failed: (Create periodic dump TC-1) No entry\n"); + temp_report.fail++; + } else { + if (p_current->expires_ms == expires_ms) { + temp_report.pass++; + } else { + WMT_ERR_FUNC("STEP test case failed: (Create periodic dump TC-1) Currect %d not %d\n", + p_current->expires_ms, expires_ms); + temp_report.fail++; + } + list_del_init(&p_current->list); + kfree(p_current); + } + + if (is_thread_run_for_test == 1) + wmt_step_deinit_pd_env(); + + osal_gettimeofday(&sec_end, &usec_end); + wmt_step_test_show_result_report("STEP result: Create periodic dump result", + &temp_report, sec_begin, usec_begin, sec_end, usec_end); + wmt_step_test_update_result_report(p_report, &temp_report); +} + diff --git a/drivers/misc/mediatek/connectivity/conninfra/Android.mk b/drivers/misc/mediatek/connectivity/conninfra/Android.mk new file mode 100644 index 00000000000000..6f3f05aebddc66 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/Android.mk @@ -0,0 +1,24 @@ +LOCAL_PATH := $(call my-dir) + +ifneq ($(filter yes,$(sort $(MTK_WLAN_SUPPORT) $(MTK_BT_SUPPORT) $(MTK_GPS_SUPPORT) $(MTK_FM_SUPPORT))),) + +ifneq (true,$(strip $(TARGET_NO_KERNEL))) +ifneq ($(filter yes,$(MTK_COMBO_SUPPORT)),) + +include $(CLEAR_VARS) +LOCAL_MODULE := conninfra.ko +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_OWNER := mtk + +LOCAL_INIT_RC := init.conninfra.rc +LOCAL_SRC_FILES := $(patsubst $(LOCAL_PATH)/%,%,$(shell find $(LOCAL_PATH) -type f -name '*.[cho]')) Makefile +LOCAL_REQUIRED_MODULES := + +include $(MTK_KERNEL_MODULE) + +else + $(warning wmt_drv-MTK_COMBO_SUPPORT: [$(MTK_COMBO_SUPPORT)]) +endif +endif + +endif diff --git a/drivers/misc/mediatek/connectivity/conninfra/Makefile b/drivers/misc/mediatek/connectivity/conninfra/Makefile new file mode 100644 index 00000000000000..86c4afea13a5bd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/Makefile @@ -0,0 +1,149 @@ +############################################################################### +# Necessary Check + +#ifeq ($(AUTOCONF_H),) +# $(error AUTOCONF_H is not defined) +#endif + +AUTOCONF_H := $(srctree)/include/generated/autoconf.h + +ccflags-y += -imacros $(AUTOCONF_H) + +#ifeq ($(CONFIG_MTK_COMBO_CHIP),) +# $(error CONFIG_MTK_COMBO_CHIP not defined) +#endif + +ifeq ($(TARGET_BUILD_VARIANT),$(filter $(TARGET_BUILD_VARIANT),userdebug user)) + #ldflags-y += -s +endif + +# Force build fail on modpost warning +KBUILD_MODPOST_FAIL_ON_WARNINGS := y +############################################################################### + +#ccflags-y += -D MTK_WCN_REMOVE_KERNEL_MODULE +ifeq ($(CONFIG_ARM64), y) + ccflags-y += -D CONFIG_MTK_WCN_ARM64 +endif + +ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y) + ccflags-y += -D WMT_IDC_SUPPORT=1 +else + ccflags-y += -D WMT_IDC_SUPPORT=0 +endif + +ccflags-y += -D MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include +ccflags-y += -I$(srctree)/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat +ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/$(MTK_PLATFORM) +ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include/clkbuf_v1 +ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include/clkbuf_v1/$(MTK_PLATFORM) +ccflags-y += -I$(srctree)/drivers/misc/mediatek/btif/common/inc +ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci +ccflags-y += -I$(srctree)/drivers/misc/mediatek/eccci/$(MTK_PLATFORM) +ccflags-y += -I$(srctree)/drivers/misc/mediatek/eemcs +ccflags-y += -I$(srctree)/drivers/misc/mediatek/conn_md/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/mach/$(MTK_PLATFORM)/include/mach +ccflags-y += -I$(srctree)/drivers/misc/mediatek/emi/submodule +ccflags-y += -I$(srctree)/drivers/misc/mediatek/emi/$(MTK_PLATFORM) +ccflags-y += -I$(srctree)/drivers/mmc/core +############################################################################## + + +ccflags-y += -Werror + + +############################################################################### +MODULE_NAME := mtk_conninfra +ifeq ($(CONFIG_MTK_COMBO_COMM),y) +$(warning $(MODULE_NAME) build-in boot.img) +obj-y += $(MODULE_NAME).o +else +$(warning $(MODULE_NAME) is kernel module) +obj-m += $(MODULE_NAME).o +endif + +############################################################################### +# common_main +############################################################################### +ccflags-y += -I$(src)/include +ccflags-y += -I$(src)/base/include +ccflags-y += -I$(src)/core/include +ccflags-y += -I$(src)/conf/include +ccflags-y += -I$(src)/platform/include + +# By Plaftfrom +ccflags-y += -I$(src)/platform/$(MTK_PLATFORM)/include + + +ifneq ($(TARGET_BUILD_VARIANT), user) + ccflags-y += -D CONNINFRA_DBG_SUPPORT=1 +else + ccflags-y += -D CONNINFRA_DBG_SUPPORT=0 +endif + +# STEP: (Support Connac) +# MTK eng/userdebug/user load: Support +# Customer eng/userdebug load: Support +# Customer user load: Not support + +ifeq ($(wildcard vendor/mediatek/proprietary/external/aee_config_internal/init.aee.mtk.system.rc),) + ccflags-y += -D CFG_WMT_STEP +else + ifneq ($(TARGET_BUILD_VARIANT),user) + ccflags-y += -D CFG_WMT_STEP + endif +endif + +#ifeq ($(findstring evb, $(MTK_PROJECT)), evb) +#ccflags-y += -D CFG_WMT_EVB +#endif + +#ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) +#$(MODULE_NAME)-objs += common_main/platform/$(MTK_PLATFORM).o +#endif + +$(MODULE_NAME)-objs += base/ring.o +$(MODULE_NAME)-objs += base/osal.o +#$(MODULE_NAME)-objs += base/log.o +$(MODULE_NAME)-objs += base/msg_thread.o +$(MODULE_NAME)-objs += core/conninfra_core.o +$(MODULE_NAME)-objs += src/conninfra_dev.o +$(MODULE_NAME)-objs += src/conninfra.o +$(MODULE_NAME)-objs += conf/conninfra_conf.o +$(MODULE_NAME)-objs += platform/consys_hw.o +$(MODULE_NAME)-objs += platform/clock_mng.o +$(MODULE_NAME)-objs += platform/pmic_mng.o +$(MODULE_NAME)-objs += platform/emi_mng.o +$(MODULE_NAME)-objs += platform/consys_reg_mng.o + +# By Plaftfrom +#$(MODULE_NAME)-objs += platform/$(MTK_PLATFORM)/$(MTK_PLATFORM).o +#$(MODULE_NAME)-objs += platform/$(MTK_PLATFORM)/$(MTK_PLATFORM)_pmic.o +#$(MODULE_NAME)-objs += platform/$(MTK_PLATFORM)/$(MTK_PLATFORM)_emi.o +#$(MODULE_NAME)-objs += platform/$(MTK_PLATFORM)/$(MTK_PLATFORM)_consys_reg.o +#$(MODULE_NAME)-objs += platform/$(MTK_PLATFORM)/$(MTK_PLATFORM)_pos.o + +############################################################################### +# test +############################################################################### +#ifeq ($(TARGET_BUILD_VARIANT),eng) +ifneq ($(TARGET_BUILD_VARIANT), user) +ccflags-y += -I$(src)/test/include +endif + +#ifeq ($(TARGET_BUILD_VARIANT),eng) +ifneq ($(TARGET_BUILD_VARIANT), user) +$(MODULE_NAME)-objs += test/conninfra_core_test.o +$(MODULE_NAME)-objs += test/conf_test.o +$(MODULE_NAME)-objs += test/cal_test.o +$(MODULE_NAME)-objs += test/msg_evt_test.o +$(MODULE_NAME)-objs += test/chip_rst_test.o +$(MODULE_NAME)-objs += test/conninfra_test.o +$(MODULE_NAME)-objs += test/mailbox_test.o +endif diff --git a/drivers/misc/mediatek/connectivity/conninfra/base/include/msg_thread.h b/drivers/misc/mediatek/connectivity/conninfra/base/include/msg_thread.h new file mode 100644 index 00000000000000..767e23ce6c6cc5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/base/include/msg_thread.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _BASE_MSG_THREAD_H_ +#define _BASE_MSG_THREAD_H_ + +#include "osal.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +#define MSG_THREAD_OP_DATA_SIZE 8 +#define MSG_THREAD_OP_BUF_SIZE 64 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +struct msg_op_data { + unsigned int op_id; /* Event ID */ + unsigned int info_bit; /* Reserved */ + size_t op_data[MSG_THREAD_OP_DATA_SIZE]; /* OP Data */ +}; + +struct msg_op { + struct msg_op_data op; + OSAL_SIGNAL signal; + int result; + atomic_t ref_count; +}; + + +struct msg_op_q { + OSAL_SLEEPABLE_LOCK lock; + unsigned int write; + unsigned int read; + unsigned int size; + struct msg_op *queue[MSG_THREAD_OP_BUF_SIZE]; +}; + +typedef OSAL_OP_DAT msg_evt_op; +typedef int(*msg_opid_func) (struct msg_op_data *); + +struct msg_thread_ctx { + OSAL_THREAD thread; /* core thread */ + OSAL_EVENT evt; + + struct msg_op_q free_op_q; /* free op queue */ + struct msg_op_q active_op_q; /* active op queue */ + struct msg_op op_q_inst[MSG_THREAD_OP_BUF_SIZE]; /* real op instances */ + struct msg_op *cur_op; /* current op */ + + int op_func_size; + const msg_opid_func *op_func; + + struct osal_op_history op_history; +}; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +#define MSG_OP_TIMEOUT 3000 + +int msg_thread_init(struct msg_thread_ctx *ctx, const char *name, + const msg_opid_func *func, int op_size); +int msg_thread_deinit(struct msg_thread_ctx *ctx); + +/* timeout: + * 0: default value (by MSG_OP_TIMEOUT define) + * >0: cutom timeout (ms) + */ +int msg_thread_send(struct msg_thread_ctx *ctx, int opid); +int msg_thread_send_1(struct msg_thread_ctx *ctx, int opid, + size_t param1); +int msg_thread_send_2(struct msg_thread_ctx *ctx, int opid, + size_t param1, size_t param2); + +int msg_thread_send_wait(struct msg_thread_ctx *ctx, int opid, + int timeout); +int msg_thread_send_wait_1(struct msg_thread_ctx *ctx, int opid, + int timeout, size_t param1); +int msg_thread_send_wait_2(struct msg_thread_ctx *ctx, int opid, + int timeout, size_t param1, size_t param2); + + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +int msg_evt_put_op_to_free_queue(struct msg_thread_ctx *ctx, struct msg_op *op); +struct msg_op *msg_evt_get_free_op(struct msg_thread_ctx *ctx); +int msg_evt_put_op_to_active(struct msg_thread_ctx *ctx, struct msg_op *op); +void msg_op_history_save(struct osal_op_history *log_history, struct msg_op *op); +unsigned int msg_evt_wait_event_checker(P_OSAL_THREAD thread); +int msg_evt_set_current_op(struct msg_thread_ctx *ctx, struct msg_op *op); +int msg_evt_opid_handler(struct msg_thread_ctx *ctx, struct msg_op_data *op); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _BASE_MSG_THREAD_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/base/include/osal.h b/drivers/misc/mediatek/connectivity/conninfra/base/include/osal.h new file mode 100644 index 00000000000000..db1a5914d6a9e9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/base/include/osal.h @@ -0,0 +1,454 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + + +/*! \file + * \brief Declaration of library functions + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. + */ + +#ifndef _OSAL_H_ +#define _OSAL_H_ + +#include <linux/workqueue.h> +#include <linux/mutex.h> +#include <linux/completion.h> +#include <linux/wait.h> +#include "ring.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define OS_BIT_OPS_SUPPORT 1 + +#ifndef MTK_CONN_BOOL_TRUE +#define MTK_CONN_BOOL_FALSE ((MTK_CONN_BOOL) 0) +#define MTK_CONN_BOOL_TRUE ((MTK_CONN_BOOL) 1) +#endif + +#define _osal_inline_ inline + +#define MAX_THREAD_NAME_LEN 16 +#define MAX_WAKE_LOCK_NAME_LEN 16 +#define MAX_HISTORY_NAME_LEN 16 +#define OSAL_OP_BUF_SIZE 64 + + +#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD)) +#define OSAL_OP_DATA_SIZE 8 +#else +#define OSAL_OP_DATA_SIZE 32 +#endif + +#define DBG_LOG_STR_SIZE 256 + +#define osal_sizeof(x) sizeof(x) + +#define osal_array_size(x) ARRAY_SIZE(x) + +#ifndef NAME_MAX +#define NAME_MAX 256 +#endif + +#define WMT_OP_BIT(x) (0x1UL << x) +#define WMT_OP_HIF_BIT WMT_OP_BIT(0) + +#define GET_BIT_MASK(value, mask) ((value) & (mask)) +#define SET_BIT_MASK(pdest, value, mask) (*(pdest) = (GET_BIT_MASK(*(pdest), ~(mask)) | GET_BIT_MASK(value, mask))) +#define GET_BIT_RANGE(data, end, begin) ((data) & GENMASK(end, begin)) +#define SET_BIT_RANGE(pdest, data, end, begin) (SET_BIT_MASK(pdest, data, GENMASK(end, begin))) + +#define RB_LATEST(prb) ((prb)->write - 1) +#define RB_SIZE(prb) ((prb)->size) +#define RB_MASK(prb) (RB_SIZE(prb) - 1) +#define RB_COUNT(prb) ((prb)->write - (prb)->read) +#define RB_FULL(prb) (RB_COUNT(prb) >= RB_SIZE(prb)) +#define RB_EMPTY(prb) ((prb)->write == (prb)->read) + +#define RB_INIT(prb, qsize) \ +do { \ + (prb)->read = (prb)->write = 0; \ + (prb)->size = (qsize); \ +} while (0) + +#define RB_PUT(prb, value) \ +do { \ + if (!RB_FULL(prb)) { \ + (prb)->queue[(prb)->write & RB_MASK(prb)] = value; \ + ++((prb)->write); \ + } \ + else { \ + pr_warn("RB is full!"); \ + } \ +} while (0) + +#define RB_GET(prb, value) \ +do { \ + if (!RB_EMPTY(prb)) { \ + value = (prb)->queue[(prb)->read & RB_MASK(prb)]; \ + ++((prb)->read); \ + if (RB_EMPTY(prb)) { \ + (prb)->read = (prb)->write = 0; \ + } \ + } \ + else { \ + value = NULL; \ + pr_warn("RB is empty!"); \ + } \ +} while (0) + +#define RB_GET_LATEST(prb, value) \ +do { \ + if (!RB_EMPTY(prb)) { \ + value = (prb)->queue[RB_LATEST(prb) & RB_MASK(prb)]; \ + if (RB_EMPTY(prb)) { \ + (prb)->read = (prb)->write = 0; \ + } \ + } \ + else { \ + value = NULL; \ + } \ +} while (0) + + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef int MTK_CONN_BOOL; + +typedef void(*P_TIMEOUT_HANDLER) (unsigned long); +typedef int(*P_COND) (void *); + +typedef struct _OSAL_TIMER_ { + struct timer_list timer; + P_TIMEOUT_HANDLER timeoutHandler; + unsigned long timeroutHandlerData; +} OSAL_TIMER, *P_OSAL_TIMER; + +typedef struct _OSAL_UNSLEEPABLE_LOCK_ { + spinlock_t lock; + unsigned long flag; +} OSAL_UNSLEEPABLE_LOCK, *P_OSAL_UNSLEEPABLE_LOCK; + +typedef struct _OSAL_SLEEPABLE_LOCK_ { + struct mutex lock; +} OSAL_SLEEPABLE_LOCK, *P_OSAL_SLEEPABLE_LOCK; + +typedef struct _OSAL_SIGNAL_ { + struct completion comp; + unsigned int timeoutValue; + unsigned int timeoutExtension; /* max number of timeout caused by thread not able to acquire CPU */ +} OSAL_SIGNAL, *P_OSAL_SIGNAL; + +typedef struct _OSAL_EVENT_ { + wait_queue_head_t waitQueue; + unsigned int timeoutValue; + int waitFlag; + +} OSAL_EVENT, *P_OSAL_EVENT; + +/* Data collected from sched_entity and sched_statistics */ +typedef struct _OSAL_THREAD_SCHEDSTATS_ { + unsigned long long time; /* when marked: the profiling start time(ms), when unmarked: total duration(ms) */ + unsigned long long exec; /* time spent in exec (sum_exec_runtime) */ + unsigned long long runnable; /* time spent in run-queue while not being scheduled (wait_sum) */ + unsigned long long iowait; /* time spent waiting for I/O (iowait_sum) */ +} OSAL_THREAD_SCHEDSTATS, *P_OSAL_THREAD_SCHEDSTATS; + +typedef struct _OSAL_THREAD_ { + struct task_struct *pThread; + void *pThreadFunc; + void *pThreadData; + char threadName[MAX_THREAD_NAME_LEN]; +} OSAL_THREAD, *P_OSAL_THREAD; + + +typedef struct _OSAL_FIFO_ { + /*fifo definition */ + void *pFifoBody; + spinlock_t fifoSpinlock; + /*fifo operations */ + int (*FifoInit)(struct _OSAL_FIFO_ *pFifo, unsigned char *buf, unsigned int); + int (*FifoDeInit)(struct _OSAL_FIFO_ *pFifo); + int (*FifoReset)(struct _OSAL_FIFO_ *pFifo); + int (*FifoSz)(struct _OSAL_FIFO_ *pFifo); + int (*FifoAvailSz)(struct _OSAL_FIFO_ *pFifo); + int (*FifoLen)(struct _OSAL_FIFO_ *pFifo); + int (*FifoIsEmpty)(struct _OSAL_FIFO_ *pFifo); + int (*FifoIsFull)(struct _OSAL_FIFO_ *pFifo); + int (*FifoDataIn)(struct _OSAL_FIFO_ *pFifo, const void *buf, unsigned int len); + int (*FifoDataOut)(struct _OSAL_FIFO_ *pFifo, void *buf, unsigned int len); +} OSAL_FIFO, *P_OSAL_FIFO; + +typedef struct firmware osal_firmware; + +typedef struct _OSAL_OP_DAT { + unsigned int opId; /* Event ID */ + unsigned int u4InfoBit; /* Reserved */ + size_t au4OpData[OSAL_OP_DATA_SIZE]; /* OP Data */ +} OSAL_OP_DAT, *P_OSAL_OP_DAT; + +typedef struct _OSAL_LXOP_ { + OSAL_OP_DAT op; + OSAL_SIGNAL signal; + int result; + atomic_t ref_count; +} OSAL_OP, *P_OSAL_OP; + +typedef struct _OSAL_LXOP_Q { + OSAL_SLEEPABLE_LOCK sLock; + unsigned int write; + unsigned int read; + unsigned int size; + P_OSAL_OP queue[OSAL_OP_BUF_SIZE]; +} OSAL_OP_Q, *P_OSAL_OP_Q; + +typedef struct _OSAL_WAKE_LOCK_ { + struct wakeup_source *wake_lock; + unsigned char name[MAX_WAKE_LOCK_NAME_LEN]; + int init_flag; +} OSAL_WAKE_LOCK, *P_OSAL_WAKE_LOCK; + +typedef struct _OSAL_BIT_OP_VAR_ { + unsigned long data; + OSAL_UNSLEEPABLE_LOCK opLock; +} OSAL_BIT_OP_VAR, *P_OSAL_BIT_OP_VAR; + +typedef unsigned int (*P_OSAL_EVENT_CHECKER) (P_OSAL_THREAD pThread); + +struct osal_op_history_entry { + void *opbuf_address; + unsigned int op_id; + unsigned int opbuf_ref_count; + unsigned int op_info_bit; + size_t param_0; + size_t param_1; + size_t param_2; + size_t param_3; + unsigned long long ts; + unsigned long usec; +}; + +struct osal_op_history { + struct ring ring_buffer; + struct osal_op_history_entry *queue; + spinlock_t lock; + struct ring dump_ring_buffer; + struct work_struct dump_work; + unsigned char name[MAX_HISTORY_NAME_LEN]; +}; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +unsigned int osal_strlen(const char *str); +int osal_strcmp(const char *dst, const char *src); +int osal_strncmp(const char *dst, const char *src, unsigned int len); +char *osal_strcpy(char *dst, const char *src); +char *osal_strncpy(char *dst, const char *src, unsigned int len); +char *osal_strcat(char *dst, const char *src); +char *osal_strncat(char *dst, const char *src, unsigned int len); +char *osal_strchr(const char *str, unsigned char c); +char *osal_strsep(char **str, const char *c); +int osal_strtol(const char *str, unsigned int adecimal, long *res); +char *osal_strstr(char *str1, const char *str2); +char *osal_strnstr(char *str1, const char *str2, int n); + +void osal_bug_on(unsigned int val); + +int osal_snprintf(char *buf, unsigned int len, const char *fmt, ...); + +int osal_dbg_assert_aee(char* const module, char* const detail_description, ...); +int osal_sprintf(char *str, const char *format, ...); +int osal_err_print(char* const str, ...); +int osal_dbg_print(char* const str, ...); +int osal_warn_print(char* const str, ...); + +void *osal_malloc(unsigned int size); +void osal_free(const void *dst); +void *osal_memset(void *buf, int i, unsigned int len); +void *osal_memcpy(void *dst, const void *src, unsigned int len); +void osal_memcpy_fromio(void *dst, const void *src, unsigned int len); +void osal_memcpy_toio(void *dst, const void *src, unsigned int len); +int osal_memcmp(const void *buf1, const void *buf2, unsigned int len); + +unsigned short osal_crc16(const unsigned char *buffer, const unsigned int length); +void osal_thread_show_stack(P_OSAL_THREAD pThread); + +int osal_sleep_ms(unsigned int ms); +int osal_udelay(unsigned int us); +int osal_usleep_range(unsigned long min, unsigned long max); +int osal_timer_create(P_OSAL_TIMER); +int osal_timer_start(P_OSAL_TIMER, unsigned int); +int osal_timer_stop(P_OSAL_TIMER); +int osal_timer_stop_sync(P_OSAL_TIMER pTimer); +int osal_timer_modify(P_OSAL_TIMER, unsigned int); +int osal_timer_delete(P_OSAL_TIMER); + +int _osal_fifo_init(OSAL_FIFO *pFifo, unsigned char *buf, unsigned int size); +int _osal_fifo_deinit(OSAL_FIFO *pFifo); +int _osal_fifo_size(OSAL_FIFO *pFifo); +int _osal_fifo_avail_size(OSAL_FIFO *pFifo); +int _osal_fifo_len(OSAL_FIFO *pFifo); +int _osal_fifo_is_empty(OSAL_FIFO *pFifo); +int _osal_fifo_is_full(OSAL_FIFO *pFifo); +int _osal_fifo_data_in(OSAL_FIFO *pFifo, const void *buf, unsigned int len); +int _osal_fifo_data_out(OSAL_FIFO *pFifo, void *buf, unsigned int len); +int _osal_fifo_reset(OSAL_FIFO *pFifo); + +int osal_fifo_init(P_OSAL_FIFO pFifo, unsigned char *buffer, unsigned int size); +void osal_fifo_deinit(P_OSAL_FIFO pFifo); +int osal_fifo_reset(P_OSAL_FIFO pFifo); +unsigned int osal_fifo_in(P_OSAL_FIFO pFifo, unsigned char *buffer, + unsigned int size); +unsigned int osal_fifo_out(P_OSAL_FIFO pFifo, unsigned char *buffer, + unsigned int size); +unsigned int osal_fifo_len(P_OSAL_FIFO pFifo); +unsigned int osal_fifo_sz(P_OSAL_FIFO pFifo); +unsigned int osal_fifo_avail(P_OSAL_FIFO pFifo); +unsigned int osal_fifo_is_empty(P_OSAL_FIFO pFifo); +unsigned int osal_fifo_is_full(P_OSAL_FIFO pFifo); + +int osal_wake_lock_init(P_OSAL_WAKE_LOCK plock); +int osal_wake_lock(P_OSAL_WAKE_LOCK plock); +int osal_wake_unlock(P_OSAL_WAKE_LOCK plock); +int osal_wake_lock_count(P_OSAL_WAKE_LOCK plock); +int osal_wake_lock_deinit(P_OSAL_WAKE_LOCK plock); + +#if defined(CONFIG_PROVE_LOCKING) +#define osal_unsleepable_lock_init(l) { spin_lock_init(&((l)->lock)); } +#else +int osal_unsleepable_lock_init(P_OSAL_UNSLEEPABLE_LOCK); +#endif +int osal_lock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK); +int osal_unlock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK); +int osal_unsleepable_lock_deinit(P_OSAL_UNSLEEPABLE_LOCK); + +#if defined(CONFIG_PROVE_LOCKING) +#define osal_sleepable_lock_init(l) { mutex_init(&((l)->lock)); } +#else +int osal_sleepable_lock_init(P_OSAL_SLEEPABLE_LOCK); +#endif +int osal_lock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK); +int osal_unlock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK); +int osal_trylock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK); +int osal_sleepable_lock_deinit(P_OSAL_SLEEPABLE_LOCK); + +int osal_signal_init(P_OSAL_SIGNAL); +int osal_wait_for_signal(P_OSAL_SIGNAL); +int osal_wait_for_signal_timeout(P_OSAL_SIGNAL, P_OSAL_THREAD); +int osal_raise_signal(P_OSAL_SIGNAL); +int osal_signal_active_state(P_OSAL_SIGNAL pSignal); +int osal_signal_deinit(P_OSAL_SIGNAL); + +int osal_event_init(P_OSAL_EVENT); +int osal_wait_for_event(P_OSAL_EVENT, P_COND, void*); +int osal_wait_for_event_timeout(P_OSAL_EVENT, P_COND, void*); +extern int osal_trigger_event(P_OSAL_EVENT); + +int osal_event_deinit(P_OSAL_EVENT); +long osal_wait_for_event_bit_set(P_OSAL_EVENT pEvent, unsigned long *pState, unsigned int bitOffset); +long osal_wait_for_event_bit_clr(P_OSAL_EVENT pEvent, unsigned long *pState, unsigned int bitOffset); + +int osal_thread_create(P_OSAL_THREAD); +int osal_thread_run(P_OSAL_THREAD); +int osal_thread_should_stop(P_OSAL_THREAD); +int osal_thread_stop(P_OSAL_THREAD); +/*int osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT);*/ +int osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT, P_OSAL_EVENT_CHECKER); +/*check pOsalLxOp and OSAL_THREAD_SHOULD_STOP*/ +int osal_thread_destroy(P_OSAL_THREAD); +int osal_thread_sched_mark(P_OSAL_THREAD, P_OSAL_THREAD_SCHEDSTATS schedstats); +int osal_thread_sched_unmark(P_OSAL_THREAD pThread, P_OSAL_THREAD_SCHEDSTATS schedstats); + +int osal_clear_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData); +int osal_set_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData); +int osal_test_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData); +int osal_test_and_clear_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData); +int osal_test_and_set_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData); + +int osal_gettimeofday(int *sec, int *usec); +int osal_printtimeofday(unsigned char* const prefix); +void osal_get_local_time(unsigned long long *sec, unsigned long *nsec); +unsigned long long osal_elapsed_us(unsigned long long ts, unsigned long usec); + +void osal_buffer_dump(const unsigned char *buf, const unsigned char *title, unsigned int len, unsigned int limit); +void osal_buffer_dump_data(const unsigned int *buf, const unsigned char *title, const unsigned int len, const unsigned int limit, + const int flag); + +unsigned int osal_op_get_id(P_OSAL_OP pOp); +MTK_CONN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp); +void osal_op_raise_signal(P_OSAL_OP pOp, int result); +void osal_set_op_result(P_OSAL_OP pOp, int result); +void osal_opq_dump(const char *qName, P_OSAL_OP_Q pOpQ); +void osal_opq_dump_locked(const char *qName, P_OSAL_OP_Q pOpQ); +MTK_CONN_BOOL osal_opq_has_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp); + +int osal_ftrace_print(const char *str, ...); +int osal_ftrace_print_ctrl(int flag); + +void osal_dump_thread_state(const unsigned char *name); +void osal_op_history_init(struct osal_op_history *log_history, int queue_size); +void osal_op_history_save(struct osal_op_history *log_history, P_OSAL_OP pOp); +void osal_op_history_print(struct osal_op_history *log_history, char *name); + +void osal_systrace_major_b(const char *name, ...); +void osal_systrace_major_e(void); + +void osal_systrace_minor_b(const char *name, ...); +void osal_systrace_minor_e(void); +void osal_systrace_minor_c(int val, const char *name, ...); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#define osal_assert(condition) \ +do { \ + if (!(condition)) \ + osal_err_print("%s, %d, (%s)\n", __FILE__, __LINE__, #condition); \ +} while (0) + +#endif /* _OSAL_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/base/include/osal_typedef.h b/drivers/misc/mediatek/connectivity/conninfra/base/include/osal_typedef.h new file mode 100644 index 00000000000000..75b4953ae3b5f4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/base/include/osal_typedef.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. + */ + +#ifndef _OSAL_TYPEDEF_H_ +#define _OSAL_TYPEDEF_H_ + +#include <linux/version.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/sched.h> +#include <linux/poll.h> +#include <asm/current.h> +#include <linux/uaccess.h> +#include <linux/proc_fs.h> +#include <linux/workqueue.h> +#include <linux/wait.h> +#include <linux/time.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/vmalloc.h> +#include <linux/firmware.h> +#include <linux/kthread.h> +#include <linux/jiffies.h> +#include <linux/slab.h> +#if defined(WMT_PLAT_ALPS) && WMT_PLAT_ALPS +#include <aee.h> +#endif +#include <linux/kfifo.h> +#include <linux/device.h> +#include <linux/pm_wakeup.h> +#include <linux/log2.h> +#include <linux/atomic.h> +#include <linux/ratelimit.h> + +#ifndef _TYPEDEFS_H /*fix redifine */ +typedef signed char INT8; +#endif + +typedef void VOID, *PVOID, **PPVOID; +typedef char *PINT8, **PPINT8; +typedef short INT16, *PINT16, **PPINT16; +typedef int INT32, *PINT32, **PPINT32; +typedef long LONG, *PLONG, **PPLONG; +typedef long long INT64, *PINT64, **PPINT64; + +typedef unsigned char UINT8, *PUINT8, **PPUINT8; +typedef unsigned short UINT16, *PUINT16, **PPUINT16; +typedef unsigned int UINT32, *PUINT32, **PPUINT32; +typedef unsigned long ULONG, *PULONG, **PPULONG; +typedef unsigned long long UINT64, *PUINT64, **PPUINT64; + +typedef size_t SIZE_T; + +typedef int MTK_WCN_BOOL; +#ifndef MTK_WCN_BOOL_TRUE +#define MTK_WCN_BOOL_FALSE ((MTK_WCN_BOOL) 0) +#define MTK_WCN_BOOL_TRUE ((MTK_WCN_BOOL) 1) +#endif + +#endif /*_OSAL_TYPEDEF_H_*/ diff --git a/drivers/misc/mediatek/connectivity/conninfra/base/include/ring.h b/drivers/misc/mediatek/connectivity/conninfra/base/include/ring.h new file mode 100644 index 00000000000000..64ccbfdd959ecd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/base/include/ring.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +#ifndef _RING_H_ +#define _RING_H_ + +struct ring { + /* addr where ring buffer starts */ + void *base; + /* addr storing the next writable pos, guaranteed to be >= read except when write overflow, but it's ok. */ + unsigned int write; + /* addr storing the next readable pos, except when read == write as buffer empty */ + unsigned int read; + /* must be power of 2 */ + unsigned int max_size; +}; + +struct ring_segment { + /* addr points into ring buffer for read/write */ + void *ring_pt; + /* size to read/write */ + unsigned int sz; + /* pos in external data buffer to read/write */ + unsigned int data_pos; + /* the size to be read/write after this segment completed */ + unsigned int remain; +}; + +void ring_init(void *base, unsigned int max_size, unsigned int read, + unsigned int write, struct ring *ring); +unsigned int ring_read_prepare(unsigned int sz, struct ring_segment *seg, struct ring *ring); +#define ring_read_all_prepare(seg, ring) ring_read_prepare((ring)->max_size, seg, ring) +unsigned int ring_write_prepare(unsigned int sz, struct ring_segment *seg, struct ring *ring); +unsigned int ring_overwrite_prepare(unsigned int sz, + struct ring_segment *seg, struct ring *ring); + +/* making sure max_size is power of 2 */ +#define RING_VALIDATE_SIZE(max_size) WARN_ON(!max_size || (max_size & (max_size - 1))) + +#define RING_EMPTY(ring) ((ring)->read == (ring)->write) +/* equation works even when write overflow */ +#define RING_SIZE(ring) ((ring)->write - (ring)->read) +#define RING_FULL(ring) (RING_SIZE(ring) == (ring)->max_size) +#define RING_WRITE_REMAIN_SIZE(ring) ((ring)->max_size - RING_SIZE(ring)) + +#define RING_READ_FOR_EACH(_sz, _seg, _ring) \ + for (ring_read_prepare(_sz, &(_seg), _ring), \ + _ring_segment_prepare((_ring)->read, &(_seg), (_ring)); \ + (_seg).sz > 0; \ + _ring_read_commit(&(_seg), (_ring)), _ring_segment_prepare((_ring)->read, \ + &(_seg), (_ring))) + +#define RING_READ_ALL_FOR_EACH(seg, ring) RING_READ_FOR_EACH((ring)->max_size, seg, ring) + +#define RING_READ_FOR_EACH_ITEM(_sz, _seg, _ring) \ + for (ring_read_prepare(_sz, &(_seg), _ring), \ + _ring_segment_prepare_item((_ring)->read, &(_seg), (_ring)); \ + (_seg).sz > 0; \ + _ring_read_commit(&(_seg), (_ring)), _ring_segment_prepare_item((_ring)->read, \ + &(_seg), (_ring))) + +#define RING_WRITE_FOR_EACH(_sz, _seg, _ring) \ + for (ring_write_prepare(_sz, &(_seg), _ring),\ + _ring_segment_prepare((_ring)->write, &(_seg), (_ring)); \ + (_seg).sz > 0; \ + _ring_write_commit(&(_seg), (_ring)), _ring_segment_prepare((_ring)->write, \ + &(_seg), (_ring))) + +#define RING_OVERWRITE_FOR_EACH(_sz, _seg, _ring) \ + for (ring_overwrite_prepare(_sz, &(_seg), _ring), \ + _ring_segment_prepare((_ring)->write, &(_seg), (_ring)); \ + (_seg).sz > 0; \ + _ring_write_commit(&(_seg), (_ring)), _ring_segment_prepare((_ring)->write, \ + &(_seg), (_ring))) + +void ring_dump(const char *title, struct ring *ring); +void ring_dump_segment(const char *title, struct ring_segment *seg); + + +/* ring Buffer Internal API */ +void _ring_segment_prepare(unsigned int from, struct ring_segment *seg, struct ring *ring); +void __ring_segment_prepare(unsigned int from, unsigned int sz, struct ring_segment *seg, struct ring *ring); +void _ring_segment_prepare_item(unsigned int from, struct ring_segment *seg, struct ring *ring); +void _ring_read_commit(struct ring_segment *seg, struct ring *ring); +void _ring_write_commit(struct ring_segment *seg, struct ring *ring); + +#endif diff --git a/drivers/misc/mediatek/connectivity/conninfra/base/msg_thread.c b/drivers/misc/mediatek/connectivity/conninfra/base/msg_thread.c new file mode 100644 index 00000000000000..47e4618b85a971 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/base/msg_thread.c @@ -0,0 +1,596 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ +#include <linux/delay.h> +#include "msg_thread.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#define MSG_OP_SIZE(prb) ((prb)->size) +#define MSG_OP_MASK(prb) (MSG_OP_SIZE(prb) - 1) +#define MSG_OP_COUNT(prb) ((prb)->write - (prb)->read) +#define MSG_OP_FULL(prb) (MSG_OP_COUNT(prb) >= MSG_OP_SIZE(prb)) +#define MSG_OP_EMPTY(prb) ((prb)->write == (prb)->read) + +#define MSG_OP_INIT(prb, qsize) \ +do { \ + (prb)->read = (prb)->write = 0; \ + (prb)->size = (qsize); \ +} while (0) + +#define MSG_OP_PUT(prb, value) \ +do { \ + if (!MSG_OP_FULL(prb)) { \ + (prb)->queue[(prb)->write & MSG_OP_MASK(prb)] = value; \ + ++((prb)->write); \ + } \ + else { \ + pr_warn("Message queue is full."); \ + } \ +} while (0) + +#define MSG_OP_GET(prb, value) \ +do { \ + if (!MSG_OP_EMPTY(prb)) { \ + value = (prb)->queue[(prb)->read & MSG_OP_MASK(prb)]; \ + ++((prb)->read); \ + if (MSG_OP_EMPTY(prb)) { \ + (prb)->read = (prb)->write = 0; \ + } \ + } \ + else { \ + value = NULL; \ + pr_warn("Message queue is empty."); \ + } \ +} while (0) + + + +#if defined(CONFIG_MTK_ENG_BUILD) || defined(CONFIG_MT_ENG_BUILD) +static bool msg_evt_opq_has_op(struct msg_op_q *op_q, struct msg_op *op) +{ + unsigned int rd; + unsigned int wt; + struct msg_op *tmp_op; + + rd = op_q->read; + wt = op_q->write; + + while (rd != wt) { + tmp_op = op_q->queue[rd & MSG_OP_MASK(op_q)]; + if (op == tmp_op) + return true; + rd++; + } + return false; +} +#endif + +/* + * Utility functions + */ +static int msg_evt_put_op_to_q(struct msg_op_q *op_q, struct msg_op *op) +{ + int ret; + + if (!op_q || !op) { + pr_err("invalid input param: pOpQ(0x%p), pLxOp(0x%p)\n", op_q, op); + return -1; + } + + ret = osal_lock_sleepable_lock(&op_q->lock); + if (ret) { + pr_warn("osal_lock_sleepable_lock iRet(%d)\n", ret); + return -2; + } + +#if defined(CONFIG_MTK_ENG_BUILD) || defined(CONFIG_MT_ENG_BUILD) + if (msg_evt_opq_has_op(op_q, op)) { + pr_err("Op(%p) already exists in queue(%p)\n", op, op_q); + ret = -3; + } +#endif + + /* acquire lock success */ + if (!MSG_OP_FULL(op_q)) + MSG_OP_PUT(op_q, op); + else { + pr_warn("MSG_OP_FULL(%p -> %p)\n", op, op_q); + ret = -4; + } + + osal_unlock_sleepable_lock(&op_q->lock); + + if (ret) { + //osal_opq_dump("FreeOpQ", &g_conninfra_ctx.rFreeOpQ); + //osal_opq_dump("ActiveOpQ", &g_conninfra_ctx.rActiveOpQ); + return ret; + } + return 0; +} + + +/* + * Utility functions + */ +static struct msg_op *msg_evt_get_op_from_q(struct msg_op_q *op_q) +{ + struct msg_op *op; + int ret; + + if (op_q == NULL) { + pr_err("pOpQ = NULL\n"); + return NULL; + } + + ret = osal_lock_sleepable_lock(&op_q->lock); + if (ret) { + pr_err("osal_lock_sleepable_lock iRet(%d)\n", ret); + return NULL; + } + + /* acquire lock success */ + MSG_OP_GET(op_q, op); + osal_unlock_sleepable_lock(&op_q->lock); + + if (op == NULL) { + pr_warn("MSG_OP_GET(%p) return NULL\n", op_q); + //osal_opq_dump("FreeOpQ", &g_conninfra_ctx.rFreeOpQ); + //osal_opq_dump("ActiveOpQ", &g_conninfra_ctx.rActiveOpQ); + } + + return op; +} + +/* + * msg_evt_thread API + */ + +int msg_evt_put_op_to_free_queue(struct msg_thread_ctx *ctx, struct msg_op *op) +{ + if (msg_evt_put_op_to_q(&ctx->free_op_q, op)) + return -1; + return 0; +} + + +struct msg_op *msg_evt_get_free_op(struct msg_thread_ctx *ctx) +{ + struct msg_op *op = NULL; + + if (ctx == NULL) { + pr_warn("ctx is null."); + return op; + } + op = msg_evt_get_op_from_q(&ctx->free_op_q); + if (op) + osal_memset(op, 0, osal_sizeof(struct msg_op)); + return op; +} + +int msg_evt_put_op_to_active(struct msg_thread_ctx *ctx, struct msg_op *op) +{ + P_OSAL_SIGNAL signal = NULL; + int wait_ret = -1; + int ret = 0; + + do { + if (!ctx || !op) { + pr_err("msg_thread_ctx(0x%p), op(0x%p)\n", ctx, op); + break; + } + + signal = &op->signal; + if (signal->timeoutValue) { + op->result = -9; + osal_signal_init(signal); + atomic_set(&op->ref_count, 1); + } else + atomic_set(&op->ref_count, 0); + + /* Increment ref_count by 1 as wmtd thread will hold a reference also, + * this must be done here instead of on target thread, because + * target thread might not be scheduled until a much later time, + * allowing current thread to decrement ref_count at the end of function, + * putting op back to free queue before target thread has a chance to process. + */ + atomic_inc(&op->ref_count); + + /* put to active Q */ + ret = msg_evt_put_op_to_q(&ctx->active_op_q, op); + if (ret) { + pr_warn("put to active queue fail\n"); + atomic_dec(&op->ref_count); + break; + } + + /* wake up conninfra_cored */ + osal_trigger_event(&ctx->evt); + + if (signal->timeoutValue == 0) { + //ret = -1; + /* Not set timeout, don't wait */ + /* pr_info("[%s] timeout is zero", __func__);*/ + break; + } + + /* check result */ + wait_ret = osal_wait_for_signal_timeout(signal, &ctx->thread); + pr_info("osal_wait_for_signal_timeout:%d result=[%d]\n", + wait_ret, op->result); + + if (wait_ret == 0) + pr_warn("opId(%d) completion timeout\n", op->op.op_id); + else if (op->result) + pr_info("opId(%d) result:%d\n", + op->op.op_id, op->result); + + /* op completes, check result */ + ret = op->result; + } while (0); + + if (op != NULL && signal != NULL && signal->timeoutValue && + atomic_dec_and_test(&op->ref_count)) { + /* put Op back to freeQ */ + msg_evt_put_op_to_free_queue(ctx, op); + } + + return ret; +} + + +int msg_thread_send(struct msg_thread_ctx *ctx, int opid) +{ + return msg_thread_send_2(ctx, opid, 0, 0); +} + +int msg_thread_send_1(struct msg_thread_ctx *ctx, int opid, + size_t param1) +{ + return msg_thread_send_2(ctx, opid, param1, 0); +} + +int msg_thread_send_2(struct msg_thread_ctx *ctx, int opid, + size_t param1, size_t param2) +{ + struct msg_op *op = NULL; + P_OSAL_SIGNAL signal; + int ret; + + op = msg_evt_get_free_op(ctx); + if (!op) { + pr_err("[%s] can't get free op\n", __func__); + return -1; + } + op->op.op_id = opid; + op->op.op_data[0] = param1; + op->op.op_data[1] = param2; + + signal = &op->signal; + //signal->timeoutValue = timeout > 0 ? timeout : MSG_OP_TIMEOUT; + signal->timeoutValue = 0; + ret = msg_evt_put_op_to_active(ctx, op); + + return ret; +} + +int msg_thread_send_wait(struct msg_thread_ctx *ctx, int opid, + int timeout) +{ + return msg_thread_send_wait_2(ctx, opid, timeout, 0, 0); +} + +int msg_thread_send_wait_1(struct msg_thread_ctx *ctx, + int opid, int timeout, + size_t param1) +{ + return msg_thread_send_wait_2(ctx, opid, timeout, param1, 0); +} + + +int msg_thread_send_wait_2(struct msg_thread_ctx *ctx, + int opid, int timeout, + size_t param1, + size_t param2) +{ + struct msg_op *op = NULL; + P_OSAL_SIGNAL signal; + int ret; + + op = msg_evt_get_free_op(ctx); + if (!op) { + pr_err("[%s] can't get free op\n", __func__); + return -1; + } + op->op.op_id = opid; + op->op.op_data[0] = param1; + op->op.op_data[1] = param2; + + signal = &op->signal; + signal->timeoutValue = timeout > 0 ? timeout : MSG_OP_TIMEOUT; + ret = msg_evt_put_op_to_active(ctx, op); + return ret; + +} + + +void msg_op_history_save(struct osal_op_history *log_history, struct msg_op *op) +{ + struct osal_op_history_entry *entry = NULL; + struct ring_segment seg; + int index; + unsigned long long sec = 0; + unsigned long usec = 0; + unsigned long flags; + + if (log_history->queue == NULL) + return; + + osal_get_local_time(&sec, &usec); + + spin_lock_irqsave(&(log_history->lock), flags); + RING_OVERWRITE_FOR_EACH(1, seg, &log_history->ring_buffer) { + index = seg.ring_pt - log_history->ring_buffer.base; + entry = &log_history->queue[index]; + } + + if (entry == NULL) { + pr_info("Entry is null, size %d\n", + RING_SIZE(&log_history->ring_buffer)); + spin_unlock_irqrestore(&(log_history->lock), flags); + return; + } + + entry->opbuf_address = op; + entry->op_id = op->op.op_id; + entry->opbuf_ref_count = atomic_read(&op->ref_count); + entry->op_info_bit = op->op.info_bit; + entry->param_0 = op->op.op_data[0]; + entry->param_1 = op->op.op_data[1]; + entry->param_2 = op->op.op_data[2]; + entry->param_3 = op->op.op_data[3]; + entry->ts = sec; + entry->usec = usec; + spin_unlock_irqrestore(&(log_history->lock), flags); +} + +unsigned int msg_evt_wait_event_checker(P_OSAL_THREAD thread) +{ + struct msg_thread_ctx *ctx = NULL; + + if (thread) { + ctx = (struct msg_thread_ctx *) (thread->pThreadData); + return !MSG_OP_EMPTY(&ctx->active_op_q); + } + return 0; +} + +int msg_evt_set_current_op(struct msg_thread_ctx *ctx, struct msg_op *op) +{ + ctx->cur_op = op; + return 0; +} + +int msg_evt_opid_handler(struct msg_thread_ctx *ctx, struct msg_op_data *op) +{ + int opid, ret; + + /*sanity check */ + if (op == NULL) { + pr_warn("null op\n"); + return -1; + } + if (ctx == NULL) { + pr_warn("null evt thread ctx\n"); + return -2; + } + + opid = op->op_id; + + if (opid >= ctx->op_func_size) { + pr_err("msg_evt_thread invalid OPID(%d)\n", opid); + return -3; + } + + if (ctx->op_func[opid] == NULL) { + pr_err("null handler (%d)\n", opid); + return -4; + } + ret = (*(ctx->op_func[opid])) (op); + return ret; +} + +static int msg_evt_thread(void *pvData) +{ + struct msg_thread_ctx *ctx = (struct msg_thread_ctx *)pvData; + P_OSAL_EVENT evt = NULL; + struct msg_op *op; + int ret; + + if (ctx == NULL) { + pr_err("msg_evt_thread (NULL)\n"); + return -1; + } + + evt = &(ctx->evt); + + for (;;) { + op = NULL; + evt->timeoutValue = 0; + + osal_thread_wait_for_event(&ctx->thread, evt, msg_evt_wait_event_checker); + + if (osal_thread_should_stop(&ctx->thread)) { + pr_info("msg_evt_thread thread should stop now...\n"); + /* TODO: clean up active opQ */ + break; + } + /* get Op from activeQ */ + op = msg_evt_get_op_from_q(&ctx->active_op_q); + if (!op) { + pr_warn("get op from activeQ fail\n"); + continue; + } + + /* TODO: save op history */ + msg_op_history_save(&ctx->op_history, op); + msg_evt_set_current_op(ctx, op); + ret = msg_evt_opid_handler(ctx, &op->op); + msg_evt_set_current_op(ctx, NULL); + + if (ret) + pr_warn("opid (0x%x) failed, ret(%d)\n", + op->op.op_id, ret); + + if (atomic_dec_and_test(&op->ref_count)) { + /* msg_evt_free_op(ctx) */ + msg_evt_put_op_to_free_queue(ctx, op); + } else if (op->signal.timeoutValue) { + op->result = ret; + osal_raise_signal(&op->signal); + } + } + + pr_debug("msg evt thread exists\n"); + return 0; +} + +int msg_thread_init(struct msg_thread_ctx *ctx, + const char *thread_name, const msg_opid_func *funcs, + int op_size) +{ + int r = 0, i; + P_OSAL_THREAD p_thread; + + osal_memset(ctx, 0, sizeof(struct msg_thread_ctx)); + + ctx->op_func = funcs; + ctx->op_func_size = op_size; + + /* init thread inst */ + p_thread = &ctx->thread; + + osal_strncpy(p_thread->threadName, thread_name, + sizeof(p_thread->threadName)); + + p_thread->pThreadData = (void *) ctx; + p_thread->pThreadFunc = (void *) msg_evt_thread; + r = osal_thread_create(p_thread); + + if (r) { + pr_err("osal_thread_create(0x%p) fail(%d)\n", p_thread, r); + return -1; + } + + osal_event_init(&ctx->evt); + osal_sleepable_lock_init(&ctx->active_op_q.lock); + osal_sleepable_lock_init(&ctx->free_op_q.lock); + + /* Initialize op queue */ + MSG_OP_INIT(&ctx->free_op_q, MSG_THREAD_OP_BUF_SIZE); + MSG_OP_INIT(&ctx->active_op_q, MSG_THREAD_OP_BUF_SIZE); + + /* Put all to free Q */ + for (i = 0; i < MSG_THREAD_OP_BUF_SIZE; i++) { + osal_signal_init(&(ctx->op_q_inst[i].signal)); + msg_evt_put_op_to_free_queue(ctx, &(ctx->op_q_inst[i])); + } + + osal_op_history_init(&ctx->op_history, 16); + + r = osal_thread_run(p_thread); + if (r) { + pr_err("osal_thread_run(evt_thread 0x%p) fail(%d)\n", + p_thread, r); + return -2; + } + return r; +} + +int msg_thread_deinit(struct msg_thread_ctx *ctx) +{ + int r, i; + P_OSAL_THREAD p_thraed = &ctx->thread; + + r = osal_thread_stop(p_thraed); + if (r) { + pr_err("osal_thread_stop(0x%p) fail(%d)\n", p_thraed, r); + return -1; + } + + for (i = 0; i < MSG_THREAD_OP_BUF_SIZE; i++) + osal_signal_deinit(&(ctx->op_q_inst[i].signal)); + + osal_sleepable_lock_deinit(&ctx->free_op_q.lock); + osal_sleepable_lock_deinit(&ctx->active_op_q.lock); + + r = osal_thread_destroy(p_thraed); + if (r) { + pr_err("osal_thread_stop(0x%p) fail(%d)\n", p_thraed, r); + return -2; + } + + osal_memset(ctx, 0, sizeof(struct msg_thread_ctx)); + + pr_debug("[%s] DONE\n", __func__); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/conninfra/base/osal.c b/drivers/misc/mediatek/connectivity/conninfra/base/osal.c new file mode 100644 index 00000000000000..2ec6330d422cb5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/base/osal.c @@ -0,0 +1,1969 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. + */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/kallsyms.h> +#include <linux/trace_events.h> +#include <linux/kthread.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <asm/current.h> +#include <linux/kfifo.h> +#include <linux/io.h> +#include "connectivity_build_in_adapter.h" +#include "osal.h" +#include "osal_typedef.h" +#include <linux/sched/clock.h> + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define GPIO_ASSERT 70 +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/* CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */ +static unsigned short const crc16_table[256] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 +}; + +int ftrace_flag = 1; + +static unsigned long __read_mostly mark_addr; +static unsigned int g_pid; +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +/*string operations*/ +unsigned int osal_strlen(const char *str) +{ + return strlen(str); +} +EXPORT_SYMBOL(osal_strlen); + +int osal_strcmp(const char *dst, const char *src) +{ + return strcmp(dst, src); +} +EXPORT_SYMBOL(osal_strcmp); + +int osal_strncmp(const char *dst, const char *src, unsigned int len) +{ + return strncmp(dst, src, len); +} +EXPORT_SYMBOL(osal_strncmp); + +char *osal_strcpy(char *dst, const char *src) +{ + return strncpy(dst, src, strlen(src)+1); +} +EXPORT_SYMBOL(osal_strcpy); + +char *osal_strncpy(char *dst, const char *src, unsigned int len) +{ + return strncpy(dst, src, len); +} +EXPORT_SYMBOL(osal_strncpy); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-overflow" +char *osal_strcat(char *dst, const char *src) +{ + return strncat(dst, src, strlen(src)); +} +#pragma GCC diagnostic pop + +char *osal_strncat(char *dst, const char *src, unsigned int len) +{ + return strncat(dst, src, len); +} +EXPORT_SYMBOL(osal_strncat); + +char *osal_strchr(const char *str, unsigned char c) +{ + return strchr(str, c); +} +EXPORT_SYMBOL(osal_strchr); + +char *osal_strsep(char **str, const char *c) +{ + return strsep(str, c); +} +EXPORT_SYMBOL(osal_strsep); + +int osal_strtol(const char *str, unsigned int adecimal, long *res) +{ + if (sizeof(long) == 4) + return kstrtou32(str, adecimal, (unsigned int *) res); + else + return kstrtol(str, adecimal, res); +} +EXPORT_SYMBOL(osal_strtol); + +char *osal_strstr(char *str1, const char *str2) +{ + return strstr(str1, str2); +} +EXPORT_SYMBOL(osal_strstr); + +char *osal_strnstr(char *str1, const char *str2, int n) +{ + return strnstr(str1, str2, n); +} +EXPORT_SYMBOL(osal_strnstr); + +void osal_bug_on(unsigned int val) +{ + WARN_ON(val); +} +EXPORT_SYMBOL(osal_bug_on); + +int osal_snprintf(char *buf, unsigned int len, const char *fmt, ...) +{ + int iRet = 0; + va_list args; + + /*va_start(args, fmt); */ + va_start(args, fmt); + /*iRet = snprintf(buf, len, fmt, args); */ + iRet = vsnprintf(buf, len, fmt, args); + va_end(args); + + return iRet; +} +EXPORT_SYMBOL(osal_snprintf); + +INT32 osal_dbg_assert_aee(const PINT8 module, const PINT8 detail_description, ...) +{ + INT8 tempString[DBG_LOG_STR_SIZE]; + va_list args; + + va_start(args, detail_description); + vsnprintf(tempString, DBG_LOG_STR_SIZE, detail_description, args); + osal_err_print("[WMT-ASSERT][E][Module]:%s, [INFO]%s\n", module, tempString); +#if defined WMT_PLAT_ALPS && CFG_ENABLE_AEE_MSG + /* There exists Format-String vulnerability. For safety, we must use the %s format parameter to read data */ + aee_kernel_warning_api(__FILE__, __LINE__, DB_OPT_WCN_ISSUE_INFO, module, detail_description, "%s", tempString); +#endif + va_end(args); + return 0; +} +EXPORT_SYMBOL(osal_dbg_assert_aee); + +int osal_sprintf(char *str, const char *format, ...) +{ + int iRet = 0; + va_list args; + + va_start(args, format); + iRet = vsnprintf(str, DBG_LOG_STR_SIZE, format, args); + va_end(args); + + return iRet; +} +EXPORT_SYMBOL(osal_sprintf); + +INT32 osal_err_print(const PINT8 str, ...) +{ + va_list args; + INT8 tempString[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + pr_err("%s", tempString); + + return 0; +} +EXPORT_SYMBOL(osal_err_print); + +INT32 osal_dbg_print(const PINT8 str, ...) +{ + va_list args; + INT8 tempString[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + pr_debug("%s", tempString); + + return 0; +} +EXPORT_SYMBOL(osal_dbg_print); + +INT32 osal_warn_print(const PINT8 str, ...) +{ + va_list args; + INT8 tempString[DBG_LOG_STR_SIZE]; + + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + pr_warn("%s", tempString); + + return 0; +} +EXPORT_SYMBOL(osal_warn_print); + +void *osal_malloc(unsigned int size) +{ + return vmalloc(size); +} +EXPORT_SYMBOL(osal_malloc); + +void osal_free(const void *dst) +{ + vfree(dst); +} +EXPORT_SYMBOL(osal_free); + +void *osal_memset(void *buf, int i, unsigned int len) +{ + return memset(buf, i, len); +} +EXPORT_SYMBOL(osal_memset); + +void *osal_memcpy(void *dst, const void *src, unsigned int len) +{ + return memcpy(dst, src, len); +} +EXPORT_SYMBOL(osal_memcpy); + +void osal_memcpy_fromio(void *dst, const void *src, unsigned int len) +{ + return memcpy_fromio(dst, src, len); +} +EXPORT_SYMBOL(osal_memcpy_fromio); + +void osal_memcpy_toio(void *dst, const void *src, unsigned int len) +{ + return memcpy_toio(dst, src, len); +} +EXPORT_SYMBOL(osal_memcpy_toio); + +int osal_memcmp(const void *buf1, const void *buf2, unsigned int len) +{ + return memcmp(buf1, buf2, len); +} +EXPORT_SYMBOL(osal_memcmp); + +unsigned short osal_crc16(const unsigned char *buffer, + const unsigned int length) +{ + unsigned short crc = 0; + unsigned int i = 0; + const unsigned char *temp = buffer; + + /* FIXME: Add STP checksum feature */ + crc = 0; + for (i = 0; i < length; i++, temp++) + crc = (crc >> 8) ^ crc16_table[(crc ^ (*temp)) & 0xff]; + return crc; +} +EXPORT_SYMBOL(osal_crc16); + +void osal_dump_thread_state(const unsigned char *name) +{ + //return connectivity_export_dump_thread_state(name); +} +EXPORT_SYMBOL(osal_dump_thread_state); + +void osal_thread_show_stack(P_OSAL_THREAD pThread) +{ +#if 0 + if ((pThread) && (pThread->pThread)) + KERNEL_show_stack(pThread->pThread, NULL); +#endif +} +EXPORT_SYMBOL(osal_thread_show_stack); + +/* + * OSAL layer Thread Opeartion related APIs + * + */ +int osal_thread_create(P_OSAL_THREAD pThread) +{ + if (!pThread) + return -1; + + pThread->pThread = kthread_create(pThread->pThreadFunc, + pThread->pThreadData, pThread->threadName); + if (pThread->pThread == NULL) + return -1; + + return 0; +} +EXPORT_SYMBOL(osal_thread_create); + +int osal_thread_run(P_OSAL_THREAD pThread) +{ + if ((pThread) && (pThread->pThread)) { + wake_up_process(pThread->pThread); + return 0; + } else { + return -1; + } +} +EXPORT_SYMBOL(osal_thread_run); + +int osal_thread_stop(P_OSAL_THREAD pThread) +{ + int iRet; + + if ((pThread) && (pThread->pThread)) { + iRet = kthread_stop(pThread->pThread); + pThread->pThread = NULL; + return iRet; + } + return -1; +} +EXPORT_SYMBOL(osal_thread_stop); + +int osal_thread_should_stop(P_OSAL_THREAD pThread) +{ + if ((pThread) && (pThread->pThread)) + return kthread_should_stop(); + else + return 1; + +} +EXPORT_SYMBOL(osal_thread_should_stop); + +int osal_thread_wait_for_event(P_OSAL_THREAD pThread, + P_OSAL_EVENT pEvent, P_OSAL_EVENT_CHECKER pChecker) +{ + /* P_DEV_WMT pDevWmt;*/ + + if ((pThread) && (pThread->pThread) && (pEvent) && (pChecker)) { + return wait_event_interruptible(pEvent->waitQueue, ( + osal_thread_should_stop(pThread) + || (*pChecker) (pThread))); + } + return -1; +} +EXPORT_SYMBOL(osal_thread_wait_for_event); + +int osal_thread_destroy(P_OSAL_THREAD pThread) +{ + if (pThread && (pThread->pThread)) { + kthread_stop(pThread->pThread); + pThread->pThread = NULL; + } + return 0; +} +EXPORT_SYMBOL(osal_thread_destroy); + +/* + * osal_thread_sched_retrieve + * Retrieve thread's current scheduling statistics and stored in output "sched". + * Return value: + * 0 : Schedstats successfully retrieved + * -1 : Kernel's schedstats feature not enabled + * -2 : pThread not yet initialized or sched is a NULL pointer + */ +static int osal_thread_sched_retrieve(P_OSAL_THREAD pThread, + P_OSAL_THREAD_SCHEDSTATS sched) +{ +#ifdef CONFIG_SCHEDSTATS + struct sched_entity se; + unsigned long long sec; + unsigned long usec; + + if (!sched) + return -2; + + /* always clear sched to simplify error handling at caller side */ + memset(sched, 0, sizeof(OSAL_THREAD_SCHEDSTATS)); + + if (!pThread || !pThread->pThread) + return -2; + + memcpy(&se, &pThread->pThread->se, sizeof(struct sched_entity)); + osal_get_local_time(&sec, &usec); + + sched->time = sec*1000 + usec/1000; + sched->exec = se.sum_exec_runtime; + sched->runnable = se.statistics.wait_sum; + sched->iowait = se.statistics.iowait_sum; + + return 0; +#else + /* always clear sched to simplify error handling at caller side */ + if (sched) + memset(sched, 0, sizeof(OSAL_THREAD_SCHEDSTATS)); + return -1; +#endif +} + +/* + * osal_thread_sched_mark + * Record the thread's current schedstats and stored + * in output "schedstats" parameter for profiling at + * later time. + * Return value: + * 0 : Schedstats successfully recorded + * -1 : Kernel's schedstats feature not enabled + * -2 : pThread not yet initialized or invalid parameters + */ +int osal_thread_sched_mark(P_OSAL_THREAD pThread, + P_OSAL_THREAD_SCHEDSTATS schedstats) +{ + return osal_thread_sched_retrieve(pThread, schedstats); +} +EXPORT_SYMBOL(osal_thread_sched_mark); + +/* + * osal_thread_sched_unmark + * Calculate scheduling statistics against the previously marked point. + * The result will be filled back into the schedstats output parameter. + * Return value: + * 0 : Schedstats successfully calculated + * -1 : Kernel's schedstats feature not enabled + * -2 : pThread not yet initialized or invalid parameters + */ +int osal_thread_sched_unmark(P_OSAL_THREAD pThread, + P_OSAL_THREAD_SCHEDSTATS schedstats) +{ + int ret; + OSAL_THREAD_SCHEDSTATS sched_now; + + if (unlikely(!schedstats)) { + ret = -2; + } else { + ret = osal_thread_sched_retrieve(pThread, &sched_now); + if (ret == 0) { + schedstats->time = sched_now.time - schedstats->time; + schedstats->exec = sched_now.exec - schedstats->exec; + schedstats->runnable = + sched_now.runnable - schedstats->runnable; + schedstats->iowait = + sched_now.iowait - schedstats->iowait; + } + } + return ret; +} +EXPORT_SYMBOL(osal_thread_sched_unmark); + +/* + * OSAL layer Signal Opeartion related APIs + * initialization + * wait for signal + * wait for signal timerout + * raise signal + * destroy a signal + * + */ + +int osal_signal_init(P_OSAL_SIGNAL pSignal) +{ + if (pSignal) { + init_completion(&pSignal->comp); + return 0; + } else { + return -1; + } +} +EXPORT_SYMBOL(osal_signal_init); + +int osal_wait_for_signal(P_OSAL_SIGNAL pSignal) +{ + if (pSignal) { + wait_for_completion_interruptible(&pSignal->comp); + return 0; + } else { + return -1; + } +} + +/* + * osal_wait_for_signal_timeout + * + * Wait for a signal to be triggered by the corresponding thread, within the + * expected timeout specified by the signal's timeoutValue. + * When the pThread parameter is specified, the thread's scheduling ability is + * considered, the timeout will be extended when thread cannot acquire CPU + * resource, and will only extend for a number of times specified by the + * signal's timeoutExtension should the situation continues. + * + * Return value: + * 0 : timeout + * >0 : signal triggered + */ +int osal_wait_for_signal_timeout(P_OSAL_SIGNAL pSignal, P_OSAL_THREAD pThread) +{ + OSAL_THREAD_SCHEDSTATS schedstats; + int waitRet; + + /* [ChangeFeature][George] gps driver may be closed by -ERESTARTSYS. + * Avoid using *interruptible" version in order to complete our jobs, + * such as function off gracefully. + */ + if (!pThread || !pThread->pThread) + return wait_for_completion_timeout(&pSignal->comp, + msecs_to_jiffies(pSignal->timeoutValue)); + + do { + osal_thread_sched_mark(pThread, &schedstats); + waitRet = wait_for_completion_timeout(&pSignal->comp, + msecs_to_jiffies(pSignal->timeoutValue)); + osal_thread_sched_unmark(pThread, &schedstats); + + if (waitRet > 0) + break; + + if (schedstats.runnable > schedstats.exec) { + pr_err( + "[E]%s:wait completion timeout, %s cannot get CPU, extension(%d), show backtrace:\n", + __func__, + pThread->threadName, + pSignal->timeoutExtension); + } else { + pr_err( + "[E]%s:wait completion timeout, show %s backtrace:\n", + __func__, + pThread->threadName); + pSignal->timeoutExtension = 0; + } + pr_err( + "[E]%s:\tduration:%llums, sched(x%llu/r%llu/i%llu)\n", + __func__, + schedstats.time, + schedstats.exec, + schedstats.runnable, + schedstats.iowait); + /* + * no need to disginguish combo or A/D die projects + * osal_dump_thread_state will just return if target + * thread does not exist + */ + osal_dump_thread_state("mtk_wmtd"); + osal_dump_thread_state("mtk_wmtd_worker"); + osal_dump_thread_state("btif_rxd"); + osal_dump_thread_state("mtk_stp_psm"); + osal_dump_thread_state("mtk_stp_btm"); + osal_dump_thread_state("stp_sdio_tx_rx"); + } while (pSignal->timeoutExtension--); + return waitRet; +} +EXPORT_SYMBOL(osal_wait_for_signal_timeout); + +int osal_raise_signal(P_OSAL_SIGNAL pSignal) +{ + if (pSignal) { + complete(&pSignal->comp); + return 0; + } else + return -1; +} +EXPORT_SYMBOL(osal_raise_signal); + +int osal_signal_active_state(P_OSAL_SIGNAL pSignal) +{ + if (pSignal) + return pSignal->timeoutValue; + else + return -1; +} + +int osal_signal_deinit(P_OSAL_SIGNAL pSignal) +{ + if (pSignal) { + pSignal->timeoutValue = 0; + return 0; + } else + return -1; +} +EXPORT_SYMBOL(osal_signal_deinit); + +/* + * OSAL layer Event Opeartion related APIs + * initialization + * wait for signal + * wait for signal timerout + * raise signal + * destroy a signal + * + */ + +int osal_event_init(P_OSAL_EVENT pEvent) +{ + if (pEvent) { + init_waitqueue_head(&pEvent->waitQueue); + return 0; + } + return -1; +} +EXPORT_SYMBOL(osal_event_init); + +int osal_trigger_event(P_OSAL_EVENT pEvent) +{ + int ret = 0; + + if (pEvent) { + wake_up_interruptible(&pEvent->waitQueue); + return ret; + } + return -1; +} +EXPORT_SYMBOL(osal_trigger_event); + +int osal_wait_for_event(P_OSAL_EVENT pEvent, + int (*condition)(void *), void *cond_pa) +{ + if (pEvent) + return wait_event_interruptible(pEvent->waitQueue, + condition(cond_pa)); + else + return -1; +} +EXPORT_SYMBOL(osal_wait_for_event); + +int osal_wait_for_event_timeout(P_OSAL_EVENT pEvent, + int (*condition)(void *), void *cond_pa) +{ + if (pEvent) + return wait_event_interruptible_timeout(pEvent->waitQueue, + condition(cond_pa), + msecs_to_jiffies(pEvent->timeoutValue)); + return -1; +} +EXPORT_SYMBOL(osal_wait_for_event_timeout); + + +int osal_event_deinit(P_OSAL_EVENT pEvent) +{ + return 0; +} +EXPORT_SYMBOL(osal_event_deinit); + +long osal_wait_for_event_bit_set(P_OSAL_EVENT pEvent, + unsigned long *pState, unsigned int bitOffset) +{ + unsigned int ms = 0; + + if (pEvent) { + ms = pEvent->timeoutValue; + if (ms != 0) + return wait_event_interruptible_timeout( + pEvent->waitQueue, + test_bit(bitOffset, pState), + msecs_to_jiffies(ms)); + else + return wait_event_interruptible(pEvent->waitQueue, + test_bit(bitOffset, pState)); + } else + return -1; + +} + +long osal_wait_for_event_bit_clr(P_OSAL_EVENT pEvent, + unsigned long *pState, unsigned int bitOffset) +{ + unsigned int ms = 0; + + if (pEvent) { + ms = pEvent->timeoutValue; + if (ms != 0) + return wait_event_interruptible_timeout( + pEvent->waitQueue, + !test_bit(bitOffset, pState), + msecs_to_jiffies(ms)); + else + return wait_event_interruptible(pEvent->waitQueue, + !test_bit(bitOffset, pState)); + } else + return -1; +} + +/* + * bit test and set/clear operations APIs + */ +#if OS_BIT_OPS_SUPPORT +#define osal_bit_op_lock(x) +#define osal_bit_op_unlock(x) +#else + +int osal_bit_op_lock(P_OSAL_UNSLEEPABLE_LOCK pLock) +{ + + return 0; +} + +int osal_bit_op_unlock(P_OSAL_UNSLEEPABLE_LOCK pLock) +{ + + return 0; +} +#endif +int osal_clear_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + osal_bit_op_lock(&(pData->opLock)); + clear_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return 0; +} +EXPORT_SYMBOL(osal_clear_bit); + +int osal_set_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + osal_bit_op_lock(&(pData->opLock)); + set_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return 0; +} +EXPORT_SYMBOL(osal_set_bit); + +int osal_test_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + unsigned int iRet = 0; + + osal_bit_op_lock(&(pData->opLock)); + iRet = test_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return iRet; +} +EXPORT_SYMBOL(osal_test_bit); + +int osal_test_and_clear_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + unsigned int iRet = 0; + + osal_bit_op_lock(&(pData->opLock)); + iRet = test_and_clear_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return iRet; + +} +EXPORT_SYMBOL(osal_test_and_clear_bit); + +int osal_test_and_set_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + unsigned int iRet = 0; + + osal_bit_op_lock(&(pData->opLock)); + iRet = test_and_set_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return iRet; +} +EXPORT_SYMBOL(osal_test_and_set_bit); + +void (*timeoutHandlerHack)(unsigned long); + +static void timeoutHandlerWrapper(struct timer_list *t) +{ + P_OSAL_TIMER pOsalTimer = container_of(t, OSAL_TIMER, timer); + + timeoutHandlerHack((unsigned long) pOsalTimer); +} + +/* + * tiemr operations APIs + * create + * stop + * modify + * create + * delete + * + */ + +int osal_timer_create(P_OSAL_TIMER pTimer) +{ + struct timer_list *timer = &pTimer->timer; + + //init_timer(timer); + //timer->function = pTimer->timeoutHandler; + //timer->data = (unsigned long)pTimer->timeroutHandlerData; + + timeoutHandlerHack = pTimer->timeoutHandler; + timer_setup(timer, timeoutHandlerWrapper, 0); + return 0; +} +EXPORT_SYMBOL(osal_timer_create); + +int osal_timer_start(P_OSAL_TIMER pTimer, unsigned int ms) +{ + + struct timer_list *timer = &pTimer->timer; + + timer->expires = jiffies + (ms / (1000 / HZ)); + add_timer(timer); + return 0; +} +EXPORT_SYMBOL(osal_timer_start); + +int osal_timer_stop(P_OSAL_TIMER pTimer) +{ + struct timer_list *timer = &pTimer->timer; + + timer_shutdown(timer); + return 0; +} +EXPORT_SYMBOL(osal_timer_stop); + +int osal_timer_stop_sync(P_OSAL_TIMER pTimer) +{ + struct timer_list *timer = &pTimer->timer; + + timer_shutdown_sync(timer); + return 0; +} +EXPORT_SYMBOL(osal_timer_stop_sync); + +int osal_timer_modify(P_OSAL_TIMER pTimer, unsigned int ms) +{ + + mod_timer(&pTimer->timer, jiffies + (ms) / (1000 / HZ)); + return 0; +} +EXPORT_SYMBOL(osal_timer_modify); + +int _osal_fifo_init(OSAL_FIFO *pFifo, unsigned char *buf, unsigned int size) +{ + struct kfifo *fifo = NULL; + int ret = -1; + + if (!pFifo) { + pr_err("pFifo must be !NULL\n"); + return -1; + } + if (pFifo->pFifoBody) { + pr_err("pFifo->pFifoBody must be NULL\n"); + pr_err("pFifo(0x%p), pFifo->pFifoBody(0x%p)\n", + pFifo, pFifo->pFifoBody); + return -1; + } + fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC); + if (!buf) { + /*fifo's buffer is not ready, we allocate automatically */ + ret = kfifo_alloc(fifo, size, /*GFP_KERNEL */ GFP_ATOMIC); + } else { + if (is_power_of_2(size)) { + kfifo_init(fifo, buf, size); + ret = 0; + } else { + kfifo_free(fifo); + fifo = NULL; + ret = -1; + } + } + + pFifo->pFifoBody = fifo; + return (ret < 0) ? (-1) : (0); +} +EXPORT_SYMBOL(osal_fifo_init); + +int _osal_fifo_deinit(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + kfifo_free(fifo); + + return 0; +} + +int _osal_fifo_size(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_size(fifo); + + return ret; +} + +/*returns unused bytes in fifo*/ +int _osal_fifo_avail_size(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_avail(fifo); + + return ret; +} + +/*returns used bytes in fifo*/ +int _osal_fifo_len(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_len(fifo); + + return ret; +} +EXPORT_SYMBOL(osal_fifo_len); + +int _osal_fifo_is_empty(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_is_empty(fifo); + + return ret; +} + +int _osal_fifo_is_full(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_is_full(fifo); + + return ret; +} + +int _osal_fifo_data_in(OSAL_FIFO *pFifo, const void *buf, unsigned int len) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo && buf && (len <= _osal_fifo_avail_size(pFifo))) { + ret = kfifo_in(fifo, buf, len); + } else { + pr_err("%s: kfifo_in, error, len = %d, _osal_fifo_avail_size = %d, buf=%p\n", + __func__, len, _osal_fifo_avail_size(pFifo), buf); + + ret = 0; + } + + return ret; +} + +int _osal_fifo_data_out(OSAL_FIFO *pFifo, void *buf, unsigned int len) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n" + , __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo && buf && (len <= _osal_fifo_len(pFifo))) { + ret = kfifo_out(fifo, buf, len); + } else { + pr_err("%s: kfifo_out, error, len = %d, osal_fifo_len = %d, buf=%p\n", + __func__, len, _osal_fifo_len(pFifo), buf); + + ret = 0; + } + + return ret; +} + +int _osal_fifo_reset(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + kfifo_reset(fifo); + + return 0; +} +EXPORT_SYMBOL(osal_fifo_reset); + +int osal_fifo_init(P_OSAL_FIFO pFifo, unsigned char *buffer, unsigned int size) +{ + if (!pFifo) { + pr_err("%s:pFifo = NULL, error\n", __func__); + return -1; + } + + pFifo->FifoInit = _osal_fifo_init; + pFifo->FifoDeInit = _osal_fifo_deinit; + pFifo->FifoSz = _osal_fifo_size; + pFifo->FifoAvailSz = _osal_fifo_avail_size; + pFifo->FifoLen = _osal_fifo_len; + pFifo->FifoIsEmpty = _osal_fifo_is_empty; + pFifo->FifoIsFull = _osal_fifo_is_full; + pFifo->FifoDataIn = _osal_fifo_data_in; + pFifo->FifoDataOut = _osal_fifo_data_out; + pFifo->FifoReset = _osal_fifo_reset; + + if (pFifo->pFifoBody != NULL) { + pr_err("%s:Because pFifo room is avialable, we clear the room and allocate them again.\n", __func__); + pFifo->FifoDeInit(pFifo->pFifoBody); + pFifo->pFifoBody = NULL; + } + + pFifo->FifoInit(pFifo, buffer, size); + + return 0; +} + +void osal_fifo_deinit(P_OSAL_FIFO pFifo) +{ + if (pFifo) + pFifo->FifoDeInit(pFifo); + else { + pr_err("%s:pFifo = NULL, error\n", __func__); + return; + } + kfree(pFifo->pFifoBody); +} +EXPORT_SYMBOL(osal_fifo_deinit); + +int osal_fifo_reset(P_OSAL_FIFO pFifo) +{ + int ret = -1; + + if (pFifo) { + ret = pFifo->FifoReset(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = -1; + } + return ret; +} + +unsigned int osal_fifo_in(P_OSAL_FIFO pFifo, + unsigned char *buffer, unsigned int size) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoDataIn(pFifo, buffer, size); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} +EXPORT_SYMBOL(osal_fifo_in); + +unsigned int osal_fifo_out(P_OSAL_FIFO pFifo, + unsigned char *buffer, unsigned int size) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoDataOut(pFifo, buffer, size); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} +EXPORT_SYMBOL(osal_fifo_out); + +unsigned int osal_fifo_len(P_OSAL_FIFO pFifo) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoLen(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +unsigned int osal_fifo_sz(P_OSAL_FIFO pFifo) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoSz(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +unsigned int osal_fifo_avail(P_OSAL_FIFO pFifo) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoAvailSz(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +unsigned int osal_fifo_is_empty(P_OSAL_FIFO pFifo) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoIsEmpty(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +unsigned int osal_fifo_is_full(P_OSAL_FIFO pFifo) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoIsFull(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + return ret; +} + +int osal_wake_lock_init(P_OSAL_WAKE_LOCK pLock) +{ + if (!pLock) + return -1; + + if (pLock->init_flag == 0) { + pLock->wake_lock = wakeup_source_register(NULL, pLock->name); + pLock->init_flag = 1; + } + + return 0; +} +EXPORT_SYMBOL(osal_wake_lock_init); + +int osal_wake_lock_deinit(P_OSAL_WAKE_LOCK pLock) +{ + if (!pLock) + return -1; + + if (pLock->init_flag == 1) { + wakeup_source_unregister(pLock->wake_lock); + pLock->init_flag = 0; + } else + pr_info("%s: wake_lock is not initialized!\n", __func__); + + return 0; +} +EXPORT_SYMBOL(osal_wake_lock_deinit); + +int osal_wake_lock(P_OSAL_WAKE_LOCK pLock) +{ + if (!pLock) + return -1; + + if (pLock->init_flag == 1) + __pm_stay_awake(pLock->wake_lock); + else + pr_info("%s: wake_lock is not initialized!\n", __func__); + + return 0; +} +EXPORT_SYMBOL(osal_wake_lock); + +int osal_wake_unlock(P_OSAL_WAKE_LOCK pLock) +{ + if (!pLock) + return -1; + + if (pLock->init_flag == 1) + __pm_relax(pLock->wake_lock); + else + pr_info("%s: wake_lock is not initialized!\n", __func__); + + return 0; + +} +EXPORT_SYMBOL(osal_wake_unlock); + +int osal_wake_lock_count(P_OSAL_WAKE_LOCK pLock) +{ + int count = 0; + + if (!pLock) + return -1; + + if (pLock->init_flag == 1) + count = pLock->wake_lock->active; + else + pr_info("%s: wake_lock is not initialized!\n", __func__); + + return count; +} +EXPORT_SYMBOL(osal_wake_lock_count); + +/* + * sleepable lock operations APIs + * init + * lock + * unlock + * destroy + * + */ +#if !defined(CONFIG_PROVE_LOCKING) +int osal_unsleepable_lock_init(P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + spin_lock_init(&(pUSL->lock)); + return 0; +} +EXPORT_SYMBOL(osal_unsleepable_lock_init); +#endif + +int osal_lock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + spin_lock_irqsave(&(pUSL->lock), pUSL->flag); + return 0; +} +EXPORT_SYMBOL(osal_lock_unsleepable_lock); + +int osal_unlock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + spin_unlock_irqrestore(&(pUSL->lock), pUSL->flag); + return 0; +} +EXPORT_SYMBOL(osal_unlock_unsleepable_lock); + +int osal_unsleepable_lock_deinit(P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + return 0; +} +EXPORT_SYMBOL(osal_unsleepable_lock_deinit); + +/* + * unsleepable operations APIs + * init + * lock + * unlock + * destroy + * + */ + +#if !defined(CONFIG_PROVE_LOCKING) +int osal_sleepable_lock_init(P_OSAL_SLEEPABLE_LOCK pSL) +{ + mutex_init(&pSL->lock); + return 0; +} +EXPORT_SYMBOL(osal_sleepable_lock_init); +#endif + +int osal_lock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL) +{ + return mutex_lock_killable(&pSL->lock); +} +EXPORT_SYMBOL(osal_lock_sleepable_lock); + +int osal_unlock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL) +{ + mutex_unlock(&pSL->lock); + return 0; +} +EXPORT_SYMBOL(osal_unlock_sleepable_lock); + +int osal_trylock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL) +{ + return mutex_trylock(&pSL->lock); +} +EXPORT_SYMBOL(osal_trylock_sleepable_lock); + +int osal_sleepable_lock_deinit(P_OSAL_SLEEPABLE_LOCK pSL) +{ + mutex_destroy(&pSL->lock); + return 0; +} +EXPORT_SYMBOL(osal_sleepable_lock_deinit); + +int osal_sleep_ms(unsigned int ms) +{ + msleep(ms); + return 0; +} +EXPORT_SYMBOL(osal_sleep_ms); + +int osal_udelay(unsigned int us) +{ + udelay(us); + return 0; +} + +int osal_usleep_range(unsigned long min, unsigned long max) +{ + usleep_range(min, max); + return 0; +} +EXPORT_SYMBOL(osal_usleep_range); + +int osal_gettimeofday(int *sec, int *usec) +{ + int ret = 0; + struct timespec64 now; + + ktime_get_ts64(&now); + + if (sec != NULL) + *sec = now.tv_sec; + else + ret = -1; + + if (usec != NULL) + *usec = now.tv_nsec / NSEC_PER_USEC; + else + ret = -1; + + return ret; +} +EXPORT_SYMBOL(osal_gettimeofday); + +INT32 osal_printtimeofday(const PUINT8 prefix) +{ + INT32 ret; + INT32 sec; + INT32 usec; + + ret = osal_gettimeofday(&sec, &usec); + ret += osal_dbg_print("%s>sec=%d, usec=%d\n", prefix, sec, usec); + + return ret; +} +EXPORT_SYMBOL(osal_printtimeofday); + +void osal_get_local_time(unsigned long long *sec, unsigned long *nsec) +{ + if (sec != NULL && nsec != NULL) { + *sec = local_clock(); + *nsec = do_div(*sec, 1000000000)/1000; + } else + pr_err("The input parameters error when get local time\n"); +} +EXPORT_SYMBOL(osal_get_local_time); + +unsigned long long osal_elapsed_us(unsigned long long ts, unsigned long usec) +{ + unsigned long long current_ts = 0; + unsigned long current_usec = 0; + + osal_get_local_time(¤t_ts, ¤t_usec); + return (current_ts*1000000 + current_usec) - (ts*1000000 + usec); +} +EXPORT_SYMBOL(osal_elapsed_us); + +void osal_buffer_dump(const unsigned char *buf, + const unsigned char *title, const unsigned int len, + const unsigned int limit) +{ + int k; + unsigned int dump_len; + char str[DBG_LOG_STR_SIZE] = {""}; + int strlen = 0; + + pr_info("[%s] len=%d, limit=%d, start dump\n", title, len, limit); + + dump_len = ((limit != 0) && (len > limit)) ? limit : len; + for (k = 0; k < dump_len; k++) { + if ((k+1) % 16 != 0) { + strlen += osal_snprintf(str + strlen, DBG_LOG_STR_SIZE - strlen, + "%02x ", buf[k]); + } else { + strlen += osal_snprintf(str + strlen, DBG_LOG_STR_SIZE - strlen, + "%02x ", buf[k]); + + pr_info("%s", str); + strlen = 0; + } + } + if (k % 16 != 0) + pr_info("%s\n", str); + + pr_info("end of dump\n"); +} +EXPORT_SYMBOL(osal_buffer_dump); + +void osal_buffer_dump_data(const unsigned int *buf, + const unsigned char *title, const unsigned int len, + const unsigned int limit, + const int flag) +{ + int k; + unsigned int dump_len; + char str[DBG_LOG_STR_SIZE] = {""}; + int strlen = 0; + + dump_len = ((limit != 0) && (len > limit)) ? limit : len; + for (k = 0; k < dump_len; k++) { + if (((k+1) % 8 != 0) && (k < (dump_len - 1))) { + strlen += osal_snprintf(str + strlen, DBG_LOG_STR_SIZE - strlen, + "0x%08x,", buf[k]); + } else { + strlen += osal_snprintf(str + strlen, DBG_LOG_STR_SIZE - strlen, + "0x%08x,", buf[k]); + if (flag) + osal_ftrace_print("%s%s", title, str); + else + pr_info("%s%s", title, str); + strlen = 0; + } + } + if (k % 8 != 0) { + if (flag) + osal_ftrace_print("%s%s", title, str); + else + pr_info("%s%s", title, str); + } +} +EXPORT_SYMBOL(osal_buffer_dump_data); + +unsigned int osal_op_get_id(P_OSAL_OP pOp) +{ + return (pOp) ? pOp->op.opId : 0xFFFFFFFF; +} +EXPORT_SYMBOL(osal_op_get_id); + +MTK_CONN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp) +{ + return (pOp && pOp->signal.timeoutValue) + ? MTK_CONN_BOOL_TRUE : MTK_CONN_BOOL_FALSE; +} +EXPORT_SYMBOL(osal_op_is_wait_for_signal); + +void osal_op_raise_signal(P_OSAL_OP pOp, int result) +{ + if (pOp) { + pOp->result = result; + osal_raise_signal(&pOp->signal); + } +} +EXPORT_SYMBOL(osal_op_raise_signal); + +int osal_ftrace_print(const char *str, ...) +{ +#ifdef CONFIG_TRACING + va_list args; + char tempString[DBG_LOG_STR_SIZE]; + + if (ftrace_flag) { + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + trace_printk("%s\n", tempString); + } +#endif + return 0; +} +EXPORT_SYMBOL(osal_ftrace_print); + +int osal_ftrace_print_ctrl(int flag) +{ +#ifdef CONFIG_TRACING + if (flag) + ftrace_flag = 1; + else + ftrace_flag = 0; +#endif + return 0; +} +EXPORT_SYMBOL(osal_ftrace_print_ctrl); + +void osal_set_op_result(P_OSAL_OP pOp, int result) +{ + if (pOp) + pOp->result = result; + +} + +static void _osal_opq_dump(const char *qName, P_OSAL_OP_Q pOpQ) +{ + /* Line format: + * [LogicalIdx(PhysicalIdx)]Address:OpId(Ref)(Result)-Info-OpData0,OpData1,OpData2,OpData3,OpData5_ + * [LogicalIdx] max 10+2=12 chars (decimal) + * (PhysicalIdx) max 10+2=12 chars (decimal) + * Address: max 16+1=17 chars (hex) + * OpId max 10 chars (decimal) + * (Ref) max 2+2=4 chars (should only be 1 digit, reserve 2 in case of negative number) + * (Result) max 11+2=13 chars (signed decimal) + * -Info- max 8+2=10 chars (hex) + * OpData, max 16+1=17 chars (hex) + */ +#define OPQ_DUMP_OP_PER_LINE 1 +#define OPQ_DUMP_OPDATA_PER_OP 6 +#define OPQ_DUMP_OP_BUF_SIZE (12 + 12 + 17 + 10 + 4 + 13 + 10 + (17 * (OPQ_DUMP_OPDATA_PER_OP)) + 1) +#define OPQ_DUMP_LINE_BUF_SIZE ((OPQ_DUMP_OP_BUF_SIZE * OPQ_DUMP_OP_PER_LINE) + 1) + unsigned int rd; + unsigned int wt; + unsigned int idx = 0; + unsigned int opDataIdx; + unsigned int idxInBuf; + int printed; + P_OSAL_OP op; + char buf[OPQ_DUMP_LINE_BUF_SIZE]; + + rd = pOpQ->read; + wt = pOpQ->write; + + pr_info("%s(%p), sz:%u/%u, rd:%u, wt:%u\n", + qName, pOpQ, RB_COUNT(pOpQ), RB_SIZE(pOpQ), rd, wt); + while (rd != wt && idx < RB_SIZE(pOpQ)) { + idxInBuf = idx % OPQ_DUMP_OP_PER_LINE; + op = pOpQ->queue[rd & RB_MASK(pOpQ)]; + + if (idxInBuf == 0) { + printed = 0; + buf[0] = 0; + } + + if (op) { + printed += snprintf(buf + printed, OPQ_DUMP_LINE_BUF_SIZE - printed, + "[%u(%u)]%p:%u(%d)(%d)-%u-", + idx, + (rd & RB_MASK(pOpQ)), + op, + op->op.opId, + atomic_read(&op->ref_count), + op->result, + op->op.u4InfoBit); + for (opDataIdx = 0; opDataIdx < OPQ_DUMP_OPDATA_PER_OP; opDataIdx++) + printed += snprintf(buf + printed, OPQ_DUMP_LINE_BUF_SIZE - printed, + "%zx,", op->op.au4OpData[opDataIdx]); + buf[printed-1] = ' '; + } else { + printed += snprintf(buf + printed, OPQ_DUMP_LINE_BUF_SIZE - printed, + "[%u(%u)]%p ", idx, (rd & RB_MASK(pOpQ)), op); + } + buf[printed++] = ' '; + + if (idxInBuf == OPQ_DUMP_OP_PER_LINE - 1 || rd == wt - 1) { + buf[printed - 1] = 0; + pr_info("%s\n", buf); + } + rd++; + idx++; + } +} +EXPORT_SYMBOL(osal_opq_dump); + +void osal_opq_dump(const char *qName, P_OSAL_OP_Q pOpQ) +{ + int err; + + err = osal_lock_sleepable_lock(&pOpQ->sLock); + if (err) { + pr_info("Failed to lock queue (%d)\n", err); + return; + } + + _osal_opq_dump(qName, pOpQ); + + osal_unlock_sleepable_lock(&pOpQ->sLock); +} + +void osal_opq_dump_locked(const char *qName, P_OSAL_OP_Q pOpQ) +{ + _osal_opq_dump(qName, pOpQ); +} +EXPORT_SYMBOL(osal_opq_dump_locked); + +MTK_CONN_BOOL osal_opq_has_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) +{ + unsigned int rd; + unsigned int wt; + P_OSAL_OP op; + + rd = pOpQ->read; + wt = pOpQ->write; + + while (rd != wt) { + op = pOpQ->queue[rd & RB_MASK(pOpQ)]; + if (op == pOp) + return MTK_CONN_BOOL_TRUE; + rd++; + } + return MTK_CONN_BOOL_FALSE; +} + +static void osal_op_history_print_work(struct work_struct *work) +{ + struct osal_op_history *log_history + = container_of(work, struct osal_op_history, dump_work); + struct ring *ring_buffer = &log_history->dump_ring_buffer; + struct ring_segment seg; + struct osal_op_history_entry *queue = ring_buffer->base; + struct osal_op_history_entry *entry; + int index = 0; + + if (queue == NULL) { + pr_info("queue shouldn't be NULL, %s", log_history->name); + return; + } + + RING_READ_FOR_EACH_ITEM(RING_SIZE(ring_buffer), seg, ring_buffer) { + index = seg.ring_pt - ring_buffer->base; + entry = &queue[index]; + pr_info("(%llu.%06lu) %s: pOp(%p):%u(%d)-%x-%zx,%zx,%zx,%zx\n", + entry->ts, + entry->usec, + log_history->name, + entry->opbuf_address, + entry->op_id, + entry->opbuf_ref_count, + entry->op_info_bit, + entry->param_0, + entry->param_1, + entry->param_2, + entry->param_3); + } + kfree(queue); + ring_buffer->base = NULL; +} + +void osal_op_history_init(struct osal_op_history *log_history, int queue_size) +{ + int size = queue_size * sizeof(struct osal_op_history_entry); + + spin_lock_init(&(log_history->lock)); + + log_history->queue = kzalloc(size, GFP_ATOMIC); + if (log_history->queue == NULL) + return; + + /* queue_size must be power of 2 */ + ring_init( + &log_history->queue, + queue_size, + 0, + 0, + &log_history->ring_buffer); + + INIT_WORK(&log_history->dump_work, osal_op_history_print_work); +} +EXPORT_SYMBOL(osal_op_history_init); + +void osal_op_history_print(struct osal_op_history *log_history, char *name) +{ + struct osal_op_history_entry *queue; + struct ring *ring_buffer, *dump_ring_buffer; + int queue_size; + unsigned long flags; + struct work_struct *work = &log_history->dump_work; + spinlock_t *lock = &(log_history->lock); + + if (log_history->queue == NULL) { + pr_info("Queue is NULL, name: %s\n", name); + return; + } + + ring_buffer = &log_history->ring_buffer; + queue_size = sizeof(struct osal_op_history_entry) + * RING_SIZE(ring_buffer); + + /* Allocate memory before getting lock to save time of holding lock */ + queue = kmalloc(queue_size, GFP_KERNEL); + if (queue == NULL) + return; + + dump_ring_buffer = &log_history->dump_ring_buffer; + + spin_lock_irqsave(lock, flags); + if (dump_ring_buffer->base != NULL) { + spin_unlock_irqrestore(lock, flags); + kfree(queue); + pr_info("print is ongoing: %s\n", name); + return; + } + + osal_snprintf(log_history->name, sizeof(log_history->name), "%s", name); + osal_memcpy(queue, log_history->queue, queue_size); + osal_memcpy(dump_ring_buffer, ring_buffer, sizeof(struct ring)); + /* assign value to base after memory copy */ + dump_ring_buffer->base = queue; + spin_unlock_irqrestore(lock, flags); + schedule_work(work); +} +EXPORT_SYMBOL(osal_op_history_print); + +void osal_op_history_save(struct osal_op_history *log_history, P_OSAL_OP pOp) +{ + struct osal_op_history_entry *entry = NULL; + struct ring_segment seg; + int index; + unsigned long long sec = 0; + unsigned long usec = 0; + unsigned long flags; + + if (log_history->queue == NULL) + return; + + osal_get_local_time(&sec, &usec); + + spin_lock_irqsave(&(log_history->lock), flags); + RING_OVERWRITE_FOR_EACH(1, seg, &log_history->ring_buffer) { + index = seg.ring_pt - log_history->ring_buffer.base; + entry = &log_history->queue[index]; + } + + if (entry == NULL) { + pr_info("Entry is null, size %d\n", + RING_SIZE(&log_history->ring_buffer)); + spin_unlock_irqrestore(&(log_history->lock), flags); + return; + } + + entry->opbuf_address = pOp; + entry->op_id = pOp->op.opId; + entry->opbuf_ref_count = atomic_read(&pOp->ref_count); + entry->op_info_bit = pOp->op.u4InfoBit; + entry->param_0 = pOp->op.au4OpData[0]; + entry->param_1 = pOp->op.au4OpData[1]; + entry->param_2 = pOp->op.au4OpData[2]; + entry->param_3 = pOp->op.au4OpData[3]; + entry->ts = sec; + entry->usec = usec; + spin_unlock_irqrestore(&(log_history->lock), flags); +} +EXPORT_SYMBOL(osal_op_history_save); + +static inline void osal_systrace_prepare(void) +{ + if (unlikely(mark_addr == 0)) + mark_addr = kallsyms_lookup_name("tracing_mark_write"); + if (unlikely(g_pid == 0)) + g_pid = task_pid_nr(current); +} + +static void osal_systrace_b(const char *log) +{ + osal_systrace_prepare(); + preempt_disable(); + //event_trace_printk(mark_addr, "B|%d|%s\n", g_pid, log); + preempt_enable(); +} + + +static void osal_systrace_e(void) +{ + preempt_disable(); + //event_trace_printk(mark_addr, "E\n"); + preempt_enable(); +} + +static void osal_systrace_c(int val, const char *log) +{ + osal_systrace_prepare(); + preempt_disable(); + //event_trace_printk(mark_addr, "C|%d|%s|%d\n", g_pid, log, val); + preempt_enable(); +} + +void osal_systrace_major_b(const char *fmt, ...) +{ + char log[DBG_LOG_STR_SIZE]; + va_list args; + + memset(log, ' ', sizeof(log)); + va_start(args, fmt); + vsnprintf(log, sizeof(log), fmt, args); + va_end(args); + osal_systrace_b(log); +} + +void osal_systrace_major_e(void) +{ + osal_systrace_e(); +} + +void osal_systrace_minor_b(const char *fmt, ...) +{ + char log[DBG_LOG_STR_SIZE]; + va_list args; + + if (!ftrace_flag) + return; + + memset(log, ' ', sizeof(log)); + va_start(args, fmt); + vsnprintf(log, sizeof(log), fmt, args); + va_end(args); + osal_systrace_b(log); + +} + +void osal_systrace_minor_e(void) +{ + if (!ftrace_flag) + return; + osal_systrace_e(); +} + +void osal_systrace_minor_c(int val, const char *fmt, ...) +{ + char log[DBG_LOG_STR_SIZE]; + va_list args; + + if (!ftrace_flag) + return; + + memset(log, ' ', sizeof(log)); + va_start(args, fmt); + vsnprintf(log, sizeof(log), fmt, args); + va_end(args); + osal_systrace_c(val, log); +} + diff --git a/drivers/misc/mediatek/connectivity/conninfra/base/ring.c b/drivers/misc/mediatek/connectivity/conninfra/base/ring.c new file mode 100644 index 00000000000000..9bc5a5cbd4ef39 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/base/ring.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +#include "ring.h" +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/bug.h> + + + +void ring_init(void *base, unsigned int max_size, unsigned int read, + unsigned int write, struct ring *ring) +{ + WARN_ON(!base); + + /* making sure max_size is power of 2 */ + WARN_ON(!max_size || (max_size & (max_size - 1))); + + /* making sure write largger than read */ + WARN_ON(read > write); + + ring->base = base; + ring->read = read; + ring->write = write; + ring->max_size = max_size; +} +EXPORT_SYMBOL(ring_init); + +void ring_dump(const char *title, struct ring *ring) +{ + pr_info("[%s] ring:{write=%d, read=%d, max_size=%d}\n", + title, ring->write, ring->read, ring->max_size); +} + +void ring_dump_segment(const char *title, struct ring_segment *seg) +{ + pr_info("[%s] seg:{ring_pt=0x%p, data_pos=%d, sz=%d, remain=%d}\n", + title, seg->ring_pt, seg->data_pos, + seg->sz, seg->remain); +} + +/* + * Function prepares the ring_segment and + * returns the number of valid bytes for read. + */ +unsigned int ring_read_prepare(unsigned int sz, + struct ring_segment *seg, + struct ring *ring) +{ + unsigned int wt = ring->write; + unsigned int rd = ring->read; + + memset(seg, 0, sizeof(struct ring_segment)); + if (sz > wt - rd) + sz = wt - rd; + seg->remain = sz; + /* ring_dump(__func__, ring); */ + /* ring_dump_segment(__func__, seg); */ + return seg->remain; +} +EXPORT_SYMBOL(ring_read_prepare); + +/* + * Function prepares the ring_segment and + * returns the number of bytes available for write. + */ +unsigned int ring_write_prepare(unsigned int sz, + struct ring_segment *seg, + struct ring *ring) +{ + unsigned int wt = ring->write; + unsigned int rd = ring->read; + + memset(seg, 0, sizeof(struct ring_segment)); + if (sz > ring->max_size - (wt - rd)) + sz = ring->max_size - (wt - rd); + seg->remain = sz; + /* ring_dump(__func__, ring); */ + /* ring_dump_segment(__func__, seg); */ + return seg->remain; +} +EXPORT_SYMBOL(ring_write_prepare); + +unsigned int ring_overwrite_prepare(unsigned int sz, struct ring_segment *seg, + struct ring *ring) +{ + unsigned int wt = ring->write; + unsigned int rd = ring->read; + + memset(seg, 0, sizeof(struct ring_segment)); + if (sz > ring->max_size - (wt - rd)) + ring->read += sz - (ring->max_size - (wt - rd)); + seg->remain = sz; + /* ring_dump(__func__, ring); */ + /* ring_dump_segment(__func__, seg); */ + return seg->remain; +} + +void __ring_segment_prepare(unsigned int from, unsigned int sz, + struct ring_segment *seg, + struct ring *ring) +{ + unsigned int ring_pos = from & (ring->max_size - 1); + + seg->ring_pt = ring->base + ring_pos; + seg->data_pos = (seg->sz ? seg->data_pos + seg->sz : 0); + if (ring_pos + sz <= ring->max_size) + seg->sz = sz; + else + seg->sz = ring->max_size - ring_pos; + seg->remain -= seg->sz; + /* ring_dump(__func__, ring); */ + /* ring_dump_segment(__func__, seg); */ +} + +void _ring_segment_prepare(unsigned int from, + struct ring_segment *seg, + struct ring *ring) +{ + __ring_segment_prepare(from, seg->remain, seg, ring); +} +EXPORT_SYMBOL(_ring_segment_prepare); + +void _ring_segment_prepare_item(unsigned int from, + struct ring_segment *seg, + struct ring *ring) +{ + unsigned int size; + + size = (seg->remain ? 1 : 0); + __ring_segment_prepare(from, size, seg, ring); +} + +void _ring_read_commit(struct ring_segment *seg, struct ring *ring) +{ + ring->read += seg->sz; + /* ring_dump(__func__, ring); */ + /* ring_dump_segment(__func__, seg); */ +} +EXPORT_SYMBOL(_ring_read_commit); + +void _ring_write_commit(struct ring_segment *seg, struct ring *ring) +{ + ring->write += seg->sz; + /* ring_dump(__func__, ring); */ + /* ring_dump_segment(__func__, seg); */ +} +EXPORT_SYMBOL(_ring_write_commit); diff --git a/drivers/misc/mediatek/connectivity/conninfra/conf/conninfra_conf.c b/drivers/misc/mediatek/connectivity/conninfra/conf/conninfra_conf.c new file mode 100644 index 00000000000000..2aa0f3b3c4f078 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/conf/conninfra_conf.c @@ -0,0 +1,632 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + +#include <linux/firmware.h> +#include "conninfra_conf.h" + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +struct parse_data { + char *name; + int (*parser)(const struct parse_data *data, const char *value); + char *(*writer)(const struct parse_data *data); + void (*relase_mem)(const struct parse_data *data); + /*PCHAR param1, *param2, *param3; */ + /* TODO:[FixMe][George] CLARIFY WHAT SHOULD BE USED HERE!!! */ + char *param1; + char *param2; + char *param3; +}; + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +struct conninfra_conf g_conninfra_conf; + +/****************************************************************************** +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************* +*/ +static int conf_parse_char(const struct parse_data *data, const char *pos); + +static char *conf_write_char(const struct parse_data *data); + +static int conf_parse_short(const struct parse_data *data, const char *pos); + +static char *conf_write_short(const struct parse_data *data); + +static int conf_parse_int(const struct parse_data *data, const char *pos); + +static char *conf_write_int(const struct parse_data *data); + +static int conf_parse_byte_array(const struct parse_data *data, + const char *pos); + +static char *conf_write_byte_array(const struct parse_data *data); + +static void conf_release_byte_array(const struct parse_data *data); + +static int conf_parse_pair(const char *key, const char *pVal); + +static int conf_parse(const char *pInBuf, unsigned int size); + +//#define OFFSET(v) ((void *) &((struct conninfra_conf*) 0)->v) + +#define CHAR(f) {#f, conf_parse_char, conf_write_char, NULL, (char *)&g_conninfra_conf.f, NULL, NULL} + +#define SHORT(f) {#f, conf_parse_short, conf_write_short, NULL, (char *)&g_conninfra_conf.f, NULL, NULL} + +#define INT(f) {#f, conf_parse_int, conf_write_int, NULL, (char *)&g_conninfra_conf.f, NULL, NULL} + +#define BYTE_ARRAY(f) {#f, conf_parse_byte_array, conf_write_byte_array, conf_release_byte_array,\ + (char *)&g_conninfra_conf.f, NULL, NULL} + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static const struct parse_data cfg_fields[] = { + CHAR(coex_wmt_ant_mode), + CHAR(coex_wmt_ant_mode_ex), + CHAR(coex_wmt_ext_component), + CHAR(coex_wmt_wifi_time_ctl), + CHAR(coex_wmt_ext_pta_dev_on), + CHAR(coex_wmt_filter_mode), + + CHAR(coex_bt_rssi_upper_limit), + CHAR(coex_bt_rssi_mid_limit), + CHAR(coex_bt_rssi_lower_limit), + CHAR(coex_bt_pwr_high), + CHAR(coex_bt_pwr_mid), + CHAR(coex_bt_pwr_low), + + CHAR(coex_wifi_rssi_upper_limit), + CHAR(coex_wifi_rssi_mid_limit), + CHAR(coex_wifi_rssi_lower_limit), + CHAR(coex_wifi_pwr_high), + CHAR(coex_wifi_pwr_mid), + CHAR(coex_wifi_pwr_low), + + CHAR(coex_ext_pta_hi_tx_tag), + CHAR(coex_ext_pta_hi_rx_tag), + CHAR(coex_ext_pta_lo_tx_tag), + CHAR(coex_ext_pta_lo_rx_tag), + SHORT(coex_ext_pta_sample_t1), + SHORT(coex_ext_pta_sample_t2), + CHAR(coex_ext_pta_wifi_bt_con_trx), + + INT(coex_misc_ext_pta_on), + INT(coex_misc_ext_feature_set), + + CHAR(wmt_gps_lna_pin), + CHAR(wmt_gps_lna_enable), + + CHAR(pwr_on_rtc_slot), + CHAR(pwr_on_ldo_slot), + CHAR(pwr_on_rst_slot), + CHAR(pwr_on_off_slot), + CHAR(pwr_on_on_slot), + CHAR(co_clock_flag), + + CHAR(disable_deep_sleep_cfg), + + INT(sdio_driving_cfg), + + SHORT(coex_wmt_wifi_path), + + CHAR(coex_wmt_ext_elna_gain_p1_support), + INT(coex_wmt_ext_elna_gain_p1_D0), + INT(coex_wmt_ext_elna_gain_p1_D1), + INT(coex_wmt_ext_elna_gain_p1_D2), + INT(coex_wmt_ext_elna_gain_p1_D3), + + BYTE_ARRAY(coex_wmt_epa_elna), + + CHAR(bt_tssi_from_wifi), + SHORT(bt_tssi_target), + + CHAR(coex_config_bt_ctrl), + CHAR(coex_config_bt_ctrl_mode), + CHAR(coex_config_bt_ctrl_rw), + + CHAR(coex_config_addjust_opp_time_ratio), + CHAR(coex_config_addjust_opp_time_ratio_bt_slot), + CHAR(coex_config_addjust_opp_time_ratio_wifi_slot), + + CHAR(coex_config_addjust_ble_scan_time_ratio), + CHAR(coex_config_addjust_ble_scan_time_ratio_bt_slot), + CHAR(coex_config_addjust_ble_scan_time_ratio_wifi_slot), +}; + +#define NUM_CFG_FIELDS (osal_sizeof(cfg_fields) / osal_sizeof(cfg_fields[0])) + +static int conf_parse_char(const struct parse_data *data, const char *pos) +{ + char *dst; + long res; + + dst = (char *)(data->param1); + + if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { + osal_strtol(pos + 2, 16, &res); + *dst = (char)res; + pr_debug("cfg==> %s=0x%x\n", data->name, *dst); + } else { + osal_strtol(pos, 10, &res); + *dst = (char)res; + pr_debug("cfg==> %s=%d\n", data->name, *dst); + } + return 0; +} + +static char *conf_write_char(const struct parse_data *data) +{ + char *src; + int res; + char *value; + + src = data->param1; + + value = osal_malloc(20); + if (value == NULL) + return NULL; + res = osal_snprintf(value, 20, "0x%x", *src); + if (res < 0 || res >= 20) { + osal_free(value); + return NULL; + } + value[20 - 1] = '\0'; + return value; +} + +static int conf_parse_short(const struct parse_data *data, const char *pos) +{ + unsigned short *dst; + long res; + + dst = (unsigned short *)data->param1; + + if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { + osal_strtol(pos + 2, 16, &res); + *dst = (unsigned short)res; + pr_debug("cfg==> %s=0x%x\n", data->name, *dst); + } else { + osal_strtol(pos, 10, &res); + *dst = (unsigned short)res; + pr_debug("cfg==> %s=%d\n", data->name, *dst); + } + + return 0; +} + +static char *conf_write_short(const struct parse_data *data) +{ + short *src; + int res; + char *value; + + /* TODO: [FixMe][George] FIX COMPILE WARNING HERE! */ + src = (short *)data->param1; + + value = osal_malloc(20); + if (value == NULL) + return NULL; + res = osal_snprintf(value, 20, "0x%x", *src); + if (res < 0 || res >= 20) { + osal_free(value); + return NULL; + } + value[20 - 1] = '\0'; + return value; +} + +static int conf_parse_int(const struct parse_data *data, const char *pos) +{ + int *dst; + long res; + + dst = (int *)data->param1; + + if ((osal_strlen(pos) > 2) && ((*pos) == '0') && (*(pos + 1) == 'x')) { + osal_strtol(pos + 2, 16, &res); + *dst = (unsigned int)res; + pr_debug("cfg==> %s=0x%x\n", data->name, *dst); + } else { + osal_strtol(pos, 10, &res); + *dst = (unsigned int)res; + pr_debug("cfg==> %s=%d\n", data->name, *dst); + } + + return 0; +} + +static char *conf_write_int(const struct parse_data *data) +{ + int *src; + int res; + char *value; + + src = (unsigned int *) data->param1; + + value = osal_malloc(20); + if (value == NULL) + return NULL; + res = osal_snprintf(value, 20, "0x%x", *src); + if (res < 0 || res >= 20) { + osal_free(value); + return NULL; + } + value[20 - 1] = '\0'; + return value; +} + +static int conf_parse_byte_array(const struct parse_data *data, + const char *pos) +{ + unsigned char **dst; + struct conf_byte_ary *ba; + unsigned char *buffer; + int size = osal_strlen(pos) / 2; + unsigned char temp[3]; + int i; + long value; + + if (size <= 1) { + pr_err("cfg==> %s has no value assigned\n", + data->name); + return -1; + } else if (size & 0x1) { + pr_debug("cfg==> %s, length should be even\n", data->name); + return -1; + } + + ba = (struct conf_byte_ary *)osal_malloc(sizeof(struct conf_byte_ary)); + if (ba == NULL) { + pr_err("cfg==> %s malloc fail\n", data->name); + return -1; + } + + buffer = osal_malloc(size); + if (buffer == NULL) { + osal_free(ba); + pr_err("cfg==> %s malloc fail, size %d\n", data->name, size); + return -1; + } + + temp[2] = '\0'; + for (i = 0; i < size; i++) { + osal_memcpy(temp, &pos[i * 2], 2); + if (osal_strtol(temp, 16, &value) < 0) { + pr_err("cfg==> %s should be hexadecimal format\n", + data->name); + osal_free(ba); + osal_free(buffer); + return -1; + } + buffer[i] = (char)value; + } + ba->data = buffer; + ba->size = size; + + dst = (unsigned char **) data->param1; + *dst = (unsigned char *)ba; + + return 0; +} + +static char *conf_write_byte_array(const struct parse_data *data) +{ + unsigned char **src; + char *value; + struct conf_byte_ary *ba; + int i; + + src = (unsigned char **) data->param1; + if (*src == NULL) + return NULL; + + ba = (struct conf_byte_ary *)*src; + + value = osal_malloc(ba->size * 2 + 1); + if (value == NULL) + return NULL; + + for (i = 0; i < ba->size; i++) + osal_snprintf(&value[i * 2], 3, "%x", ba->data[i]); + + return value; +} + + +static void conf_release_byte_array(const struct parse_data *data) +{ + //unsigned char *buffer; + struct conf_byte_ary *ba; + unsigned char **src; + + if (data->param1 != NULL) { + src = (unsigned char **) data->param1; + ba = (struct conf_byte_ary *) *src; + if (ba->data != NULL) { + osal_free(ba->data); + ba->data = NULL; + } + osal_free(ba); + //data->param1 = NULL; + *src = NULL; + } +} + +static int conf_parse_pair(const char *pKey, const char *pVal) +{ + int i = 0; + int ret = 0; + + + for (i = 0; i < NUM_CFG_FIELDS; i++) { + const struct parse_data *field = &cfg_fields[i]; + + if (osal_strcmp(pKey, field->name) != 0) + continue; + if (field->parser(field, pVal)) { + pr_err("failed to parse %s '%s'.\n", pKey, pVal); + ret = -1; + } + break; + } + if (i == NUM_CFG_FIELDS) { + pr_err("unknown field '%s'.\n", pKey); + ret = -1; + } + + return ret; +} + +static int conf_parse(const char *pInBuf, unsigned int size) +{ + char *pch; + char *pBuf; + char *pLine; + char *pKey; + char *pVal; + char *pPos; + int ret = 0; + int i = 0; + char *pa = NULL; + + pBuf = osal_malloc(size+1); + if (!pBuf) + return -1; + + osal_memcpy(pBuf, pInBuf, size); + pBuf[size] = '\0'; + + pch = pBuf; + /* pch is to be updated by strsep(). Keep pBuf unchanged!! */ + + while ((pLine = osal_strsep(&pch, "\r\n")) != NULL) { + /* pch is updated to the end of pLine by + * strsep() and updated to '\0' + */ + /* parse each line */ + + if (!*pLine) + continue; + + pVal = osal_strchr(pLine, '='); + if (!pVal) { + pr_warn("mal-format cfg string(%s)\n", pLine); + continue; + } + + /* |<-pLine->|'='<-pVal->|'\n' ('\0')| */ + *pVal = '\0'; /* replace '=' with '\0' to get key */ + /* |<-pKey->|'\0'|<-pVal->|'\n' ('\0')| */ + pKey = pLine; + + if ((pVal - pBuf) < size) + pVal++; + + /*key handling */ + pPos = pKey; + /*skip space characeter */ + while (((*pPos) == ' ') || + ((*pPos) == '\t') || ((*pPos) == '\n')) { + if ((pPos - pBuf) >= size) + break; + pPos++; + } + /*key head */ + pKey = pPos; + while (((*pPos) != ' ') && + ((*pPos) != '\t') && ((*pPos) != '\0') + && ((*pPos) != '\n')) { + if ((pPos - pBuf) >= size) + break; + pPos++; + } + /*key tail */ + (*pPos) = '\0'; + + /*value handling */ + pPos = pVal; + /*skip space characeter */ + while (((*pPos) == ' ') || + ((*pPos) == '\t') || ((*pPos) == '\n')) { + if ((pPos - pBuf) >= size) + break; + pPos++; + } + /*value head */ + pVal = pPos; + while (((*pPos) != ' ') && + ((*pPos) != '\t') && ((*pPos) != '\0') + && ((*pPos) != '\n')) { + if ((pPos - pBuf) >= size) + break; + pPos++; + } + /*value tail */ + (*pPos) = '\0'; + + ret = conf_parse_pair(pKey, pVal); + pr_debug("parse (%s, %s, %d)\n", pKey, pVal, ret); + if (ret) + pr_debug("parse fail (%s, %s, %d)\n", pKey, pVal, ret); + } + + for (i = 0; i < NUM_CFG_FIELDS; i++) { + const struct parse_data *field = &cfg_fields[i]; + + pa = field->writer(field); + if (pa) { + pr_debug("#%d(%s)=>%s\n", i, field->name, pa); + osal_free(pa); + } else + pr_err("failed to parse '%s'.\n", field->name); + } + osal_free(pBuf); + return 0; +} + +static int platform_request_firmware(char *patch_name, osal_firmware **ppPatch) +{ + int ret = -1; + osal_firmware *fw = NULL; + + if (!ppPatch) { + pr_err("invalid ppBufptr!\n"); + return -1; + } + + *ppPatch = NULL; + do { + ret = request_firmware((const struct firmware **)&fw, + patch_name, NULL); + if (ret == -EAGAIN) { + pr_err("failed to open or read!(%s), retry again!\n", + patch_name); + osal_sleep_ms(100); + } + } while (ret == -EAGAIN); + if (ret != 0) { + pr_err("failed to open or read!(%s)\n", patch_name); + return -1; + } + pr_debug("loader firmware %s ok!!\n", patch_name); + ret = 0; + *ppPatch = fw; + + return ret; +} + +static int platform_release_firmware(osal_firmware **ppPatch) +{ + if (*ppPatch != NULL) { + release_firmware((const struct firmware *)*ppPatch); + *ppPatch = NULL; + } + return 0; +} + +int conninfra_conf_init(void) +{ + int ret = -1; + const osal_firmware *conf_inst; + + osal_memset(&g_conninfra_conf, 0, osal_sizeof(struct conninfra_conf)); + osal_strcpy(&(g_conninfra_conf.conf_name[0]), "conninfra.cfg"); + + pr_debug("config file:%s\n", &(g_conninfra_conf.conf_name[0])); + if (0 == + platform_request_firmware(&g_conninfra_conf.conf_name[0], + (osal_firmware **) &conf_inst)) { + /*get full name patch success */ + pr_debug("get full file name(%s) buf(0x%p) size(%zu)\n", + &g_conninfra_conf.conf_name[0], conf_inst->data, + conf_inst->size); + if (0 == + conf_parse((const char *)conf_inst->data, + conf_inst->size)) { + /*config file exists */ + g_conninfra_conf.cfg_exist = 1; + ret = 0; + } else { + pr_err("conf parsing fail\n"); + ret = -1; + } + platform_release_firmware((osal_firmware **) &conf_inst); + return ret; + } + pr_err("read %s file fails\n", &(g_conninfra_conf.conf_name[0])); + g_conninfra_conf.cfg_exist = 0; + return ret; +} + +int conninfra_conf_set_cfg_file(const char *name) +{ + if (name == NULL) { + pr_err("name is NULL\n"); + return -1; + } + if (osal_strlen(name) >= osal_sizeof(g_conninfra_conf.conf_name)) { + pr_err("name is too long, length=%d, expect to < %zu\n", + osal_strlen(name), + osal_sizeof(g_conninfra_conf.conf_name)); + return -2; + } + osal_memset(&g_conninfra_conf.conf_name[0], 0, + osal_sizeof(g_conninfra_conf.conf_name)); + osal_strcpy(&(g_conninfra_conf.conf_name[0]), name); + pr_err("WMT config file is set to (%s)\n", + &(g_conninfra_conf.conf_name[0])); + + return 0; +} + +const struct conninfra_conf *conninfra_conf_get_cfg(void) +{ + if (g_conninfra_conf.cfg_exist == 0) + return NULL; + + return &g_conninfra_conf; +} + +int conninfra_conf_deinit(void) +{ + int i; + + if (g_conninfra_conf.cfg_exist == 0) + return -1; + + for (i = 0; i < NUM_CFG_FIELDS; i++) { + const struct parse_data *field = &cfg_fields[i]; + field->relase_mem(field); + } + g_conninfra_conf.cfg_exist = 0; + return 0; +} + diff --git a/drivers/misc/mediatek/connectivity/conninfra/conf/include/conninfra_conf.h b/drivers/misc/mediatek/connectivity/conninfra/conf/include/conninfra_conf.h new file mode 100644 index 00000000000000..7a849a00bd893b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/conf/include/conninfra_conf.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + + + +#ifndef _CONNINFRA_CONF_H_ +#define _CONNINFRA_CONF_H_ + +#include "osal.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define CUST_CFG_INFRA "WMT.cfg" +#define CUST_CFG_INFRA_SOC "WMT_SOC.cfg" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + + + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + + + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +struct conf_byte_ary { + unsigned int size; + char *data; +}; + +struct conninfra_conf { + + char conf_name[NAME_MAX + 1]; + //const osal_firmware *conf_inst; + unsigned char cfg_exist; + + unsigned char coex_wmt_ant_mode; + unsigned char coex_wmt_ant_mode_ex; + unsigned char coex_wmt_ext_component; + unsigned char coex_wmt_wifi_time_ctl; + unsigned char coex_wmt_ext_pta_dev_on; + /*combo chip and LTE coex filter mode setting */ + unsigned char coex_wmt_filter_mode; + + unsigned char coex_bt_rssi_upper_limit; + unsigned char coex_bt_rssi_mid_limit; + unsigned char coex_bt_rssi_lower_limit; + unsigned char coex_bt_pwr_high; + unsigned char coex_bt_pwr_mid; + unsigned char coex_bt_pwr_low; + + unsigned char coex_wifi_rssi_upper_limit; + unsigned char coex_wifi_rssi_mid_limit; + unsigned char coex_wifi_rssi_lower_limit; + unsigned char coex_wifi_pwr_high; + unsigned char coex_wifi_pwr_mid; + unsigned char coex_wifi_pwr_low; + + unsigned char coex_ext_pta_hi_tx_tag; + unsigned char coex_ext_pta_hi_rx_tag; + unsigned char coex_ext_pta_lo_tx_tag; + unsigned char coex_ext_pta_lo_rx_tag; + unsigned short coex_ext_pta_sample_t1; + unsigned short coex_ext_pta_sample_t2; + unsigned char coex_ext_pta_wifi_bt_con_trx; + + unsigned int coex_misc_ext_pta_on; + unsigned int coex_misc_ext_feature_set; + /*GPS LNA setting */ + unsigned char wmt_gps_lna_pin; + unsigned char wmt_gps_lna_enable; + /*Power on sequence */ + unsigned char pwr_on_rtc_slot; + unsigned char pwr_on_ldo_slot; + unsigned char pwr_on_rst_slot; + unsigned char pwr_on_off_slot; + unsigned char pwr_on_on_slot; + unsigned char co_clock_flag; + + /*deep sleep feature flag*/ + unsigned char disable_deep_sleep_cfg; + + /* Combo chip side SDIO driving setting */ + unsigned int sdio_driving_cfg; + + /* Combo chip WiFi path setting */ + unsigned short coex_wmt_wifi_path; + /* Combo chip WiFi eLAN gain setting */ + unsigned char coex_wmt_ext_elna_gain_p1_support; + unsigned int coex_wmt_ext_elna_gain_p1_D0; + unsigned int coex_wmt_ext_elna_gain_p1_D1; + unsigned int coex_wmt_ext_elna_gain_p1_D2; + unsigned int coex_wmt_ext_elna_gain_p1_D3; + + struct conf_byte_ary *coex_wmt_epa_elna; + + unsigned char bt_tssi_from_wifi; + unsigned short bt_tssi_target; + + unsigned char coex_config_bt_ctrl; + unsigned char coex_config_bt_ctrl_mode; + unsigned char coex_config_bt_ctrl_rw; + + unsigned char coex_config_addjust_opp_time_ratio; + unsigned char coex_config_addjust_opp_time_ratio_bt_slot; + unsigned char coex_config_addjust_opp_time_ratio_wifi_slot; + + unsigned char coex_config_addjust_ble_scan_time_ratio; + unsigned char coex_config_addjust_ble_scan_time_ratio_bt_slot; + unsigned char coex_config_addjust_ble_scan_time_ratio_wifi_slot; + +}; + + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + + + + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +const struct conninfra_conf *conninfra_conf_get_cfg(void); +int conninfra_conf_set_cfg_file(const char *name); + +int conninfra_conf_init(void); +int conninfra_conf_deinit(void); + +#endif /* _CONNINFRA_CONF_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/core/conninfra_core.c b/drivers/misc/mediatek/connectivity/conninfra/core/conninfra_core.c new file mode 100644 index 00000000000000..70560f94bd451f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/core/conninfra_core.c @@ -0,0 +1,637 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + +#include "consys_hw.h" +#include "conninfra_core.h" +#include "msg_thread.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define CONNINFRA_EVENT_TIMEOUT 3000 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <linux/delay.h> + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static int opfunc_power_on(struct msg_op_data *op); +static int opfunc_power_off(struct msg_op_data *op); +static int opfunc_chip_rst(struct msg_op_data *op); +static int opfunc_pre_cal(struct msg_op_data *op); +static int opfunc_therm_ctrl(struct msg_op_data *op); + + +static int opfunc_subdrv_pre_reset(struct msg_op_data *op); +static int opfunc_subdrv_post_reset(struct msg_op_data *op); +static int opfunc_subdrv_cal_pwr_on(struct msg_op_data *op); +static int opfunc_subdrv_cal_do_cal(struct msg_op_data *op); +static int opfunc_subdrv_therm_ctrl(struct msg_op_data *op); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +struct conninfra_ctx g_conninfra_ctx; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static const msg_opid_func conninfra_core_opfunc[] = { + [CONNINFRA_OPID_PWR_ON] = opfunc_power_on, + [CONNINFRA_OPID_PWR_OFF] = opfunc_power_off, + [CONNINFRA_OPID_THERM_CTRL] = opfunc_therm_ctrl, +}; + +static const msg_opid_func conninfra_core_cb_opfunc[] = { + [CONNINFRA_CB_OPID_CHIP_RST] = opfunc_chip_rst, + [CONNINFRA_CB_OPID_PRE_CAL] = opfunc_pre_cal, +}; + + +/* subsys ops */ +static char *drv_thread_name[] = { + [CONNDRV_TYPE_BT] = "sub_bt_thrd", + [CONNDRV_TYPE_FM] = "sub_fm_thrd", + [CONNDRV_TYPE_GPS] = "sub_gps_thrd", + [CONNDRV_TYPE_WIFI] = "sub_wifi_thrd", +}; + +typedef enum { + INFRA_SUBDRV_OPID_PRE_RESET = 0, + INFRA_SUBDRV_OPID_POST_RESET = 1, + INFRA_SUBDRV_OPID_CAL_PWR_ON = 2, + INFRA_SUBDRV_OPID_CAL_DO_CAL = 3, + INFRA_SUBDRV_OPID_THERM_CTRL = 4, + + INFRA_SUBDRV_OPID_MAX +} infra_subdrv_op; + + +static const msg_opid_func infra_subdrv_opfunc[] = { + [INFRA_SUBDRV_OPID_PRE_RESET] = opfunc_subdrv_pre_reset, + [INFRA_SUBDRV_OPID_POST_RESET] = opfunc_subdrv_post_reset, + [INFRA_SUBDRV_OPID_CAL_PWR_ON] = opfunc_subdrv_cal_pwr_on, + [INFRA_SUBDRV_OPID_CAL_DO_CAL] = opfunc_subdrv_cal_do_cal, + [INFRA_SUBDRV_OPID_THERM_CTRL] = opfunc_subdrv_therm_ctrl, +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static int opfunc_power_on_internal(unsigned int drv_type) +{ + int ret; + + /* Check abnormal type */ + if (drv_type >= CONNDRV_TYPE_MAX) { + pr_err("abnormal Fun(%d)\n", drv_type); + return -1; + } + + /* Check abnormal state */ + if ((g_conninfra_ctx.drv_inst[drv_type].drv_status < DRV_STS_POWER_OFF) + || (g_conninfra_ctx.drv_inst[drv_type].drv_status >= DRV_STS_MAX)) { + pr_err("func(%d) status[0x%x] abnormal\n", drv_type, + g_conninfra_ctx.drv_inst[drv_type].drv_status); + return -2; + } + + /* check if func already on */ + if (g_conninfra_ctx.drv_inst[drv_type].drv_status == DRV_STS_POWER_ON) { + pr_warn("func(%d) already on\n", drv_type); + return 0; + } + + if (g_conninfra_ctx.infra_drv_status == DRV_STS_POWER_OFF) { + ret = consys_hw_pwr_on(); + if (ret) { + pr_err("Conninfra power on fail. drv(%d) ret=(%d)\n", + drv_type, ret); + return -3; + } + /* POWER ON SEQUENCE */ + g_conninfra_ctx.infra_drv_status = DRV_STS_POWER_ON; + } + + g_conninfra_ctx.drv_inst[drv_type].drv_status = DRV_STS_POWER_ON; + + /* VCNx enable */ + switch (drv_type) { + case CONNDRV_TYPE_BT: + consys_hw_bt_power_ctl(1); + break; + case CONNDRV_TYPE_FM: + consys_hw_fm_power_ctl(1); + break; + case CONNDRV_TYPE_GPS: + consys_hw_gps_power_ctl(1); + break; + case CONNDRV_TYPE_WIFI: + consys_hw_wifi_power_ctl(1); + break; + default: + break; + } + + return 0; +} + +static int opfunc_power_on(struct msg_op_data *op) +{ + unsigned int drv_type = op->op_data[0]; + + return opfunc_power_on_internal(drv_type); +} + +static int opfunc_power_off_internal(unsigned int drv_type) +{ + int i, ret; + bool try_power_off = true; + + /* Check abnormal type */ + if (drv_type >= CONNDRV_TYPE_MAX) { + pr_err("abnormal Fun(%d)\n", drv_type); + return -1; + } + + /* Check abnormal state */ + if ((g_conninfra_ctx.drv_inst[drv_type].drv_status < DRV_STS_POWER_OFF) + || (g_conninfra_ctx.drv_inst[drv_type].drv_status >= DRV_STS_MAX)) { + pr_err("func(%d) status[0x%x] abnormal\n", drv_type, + g_conninfra_ctx.drv_inst[drv_type].drv_status); + return -2; + } + + /* check if func already on */ + if (g_conninfra_ctx.drv_inst[drv_type].drv_status + == DRV_STS_POWER_OFF) { + pr_warn("func(%d) already on\n", drv_type); + return 0; + } + + /* VCNx disable */ + switch (drv_type) { + case CONNDRV_TYPE_BT: + consys_hw_bt_power_ctl(0); + break; + case CONNDRV_TYPE_FM: + consys_hw_fm_power_ctl(0); + break; + case CONNDRV_TYPE_GPS: + consys_hw_gps_power_ctl(0); + break; + case CONNDRV_TYPE_WIFI: + consys_hw_wifi_power_ctl(0); + break; + default: + break; + } + + g_conninfra_ctx.drv_inst[drv_type].drv_status = DRV_STS_POWER_OFF; + + /* is there subsys on ? */ + for (i = 0; i < CONNDRV_TYPE_MAX; i++) + if (g_conninfra_ctx.drv_inst[i].drv_status == DRV_STS_POWER_ON) + try_power_off = false; + + if (try_power_off) { + /* POWER OFF SEQUENCE */ + ret = consys_hw_pwr_off(); + if (ret) { + pr_err("Conninfra power on fail. drv(%d) ret=(%d)\n", + drv_type, ret); + return -3; + } + g_conninfra_ctx.infra_drv_status = DRV_STS_POWER_OFF; + } + + return 0; +} + +static int opfunc_power_off(struct msg_op_data *op) +{ + unsigned int drv_type = op->op_data[0]; + + return opfunc_power_off_internal(drv_type); +} + +static int opfunc_chip_rst(struct msg_op_data *op) +{ + int i, ret; + struct subsys_drv_inst *drv_inst; + unsigned int drv_pwr_state[CONNDRV_TYPE_MAX]; + + if (g_conninfra_ctx.infra_drv_status == DRV_STS_POWER_OFF) { + pr_info("No subsys on, just return"); + return 0; + } + + atomic_set(&g_conninfra_ctx.rst_state, 0); + sema_init(&g_conninfra_ctx.rst_sema, 1); + /* pre */ + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + drv_inst = &g_conninfra_ctx.drv_inst[i]; + drv_pwr_state[i] = drv_inst->drv_status; + pr_info("subsys %d is %d", i, drv_inst->drv_status); + ret = msg_thread_send_1(&drv_inst->msg_ctx, + INFRA_SUBDRV_OPID_PRE_RESET, i); + } + while (atomic_read(&g_conninfra_ctx.rst_state) < CONNDRV_TYPE_MAX) + ret = down_interruptible(&g_conninfra_ctx.rst_sema); + + /*******************************************************/ + /* reset */ + /* call consys_hw */ + /*******************************************************/ + /* Turn off subsys one-by-one */ + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + if (drv_pwr_state[i]) { + ret = opfunc_power_off_internal(i); + pr_info("Call subsys(%d) power off ret=%d", i, ret); + } + } + pr_info("conninfra status should be power off. Status=%d", g_conninfra_ctx.infra_drv_status); + /* Turn on subsys */ + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + if (drv_pwr_state[i]) { + ret = opfunc_power_on_internal(i); + pr_info("Call subsys(%d) power on ret=%d", i, ret); + } + } + pr_info("conninfra status should be power on. Status=%d", g_conninfra_ctx.infra_drv_status); + + /* post */ + atomic_set(&g_conninfra_ctx.rst_state, 0); + sema_init(&g_conninfra_ctx.rst_sema, 1); + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + drv_inst = &g_conninfra_ctx.drv_inst[i]; + ret = msg_thread_send_1(&drv_inst->msg_ctx, + INFRA_SUBDRV_OPID_POST_RESET, i); + } + while (atomic_read(&g_conninfra_ctx.rst_state) < CONNDRV_TYPE_MAX) + ret = down_interruptible(&g_conninfra_ctx.rst_sema); + + return 0; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" +static int opfunc_pre_cal(struct msg_op_data *op) +{ +#define CAL_DRV_COUNT 2 + int cal_drvs[CAL_DRV_COUNT] = {CONNDRV_TYPE_BT, CONNDRV_TYPE_WIFI}; + int i, ret; + struct subsys_drv_inst *drv_inst; + + /* power on subsys */ + atomic_set(&g_conninfra_ctx.pre_cal_state, 0); + sema_init(&g_conninfra_ctx.pre_cal_sema, 1); + + for (i = 0; i < CAL_DRV_COUNT; i++) { + drv_inst = &g_conninfra_ctx.drv_inst[cal_drvs[i]]; + ret = msg_thread_send_1(&drv_inst->msg_ctx, + INFRA_SUBDRV_OPID_CAL_PWR_ON, cal_drvs[i]); + if (ret) + pr_warn("driver [%d] power on fail\n", cal_drvs[i]); + } + while (atomic_read(&g_conninfra_ctx.pre_cal_state) < CAL_DRV_COUNT) + down_interruptible(&g_conninfra_ctx.pre_cal_sema); + pr_info(">>>>>>> power on DONE!!"); + + /* Do Calibration */ + drv_inst = &g_conninfra_ctx.drv_inst[CONNDRV_TYPE_BT]; + ret = msg_thread_send_wait_1(&drv_inst->msg_ctx, + INFRA_SUBDRV_OPID_CAL_DO_CAL, 0, CONNDRV_TYPE_BT); + if (ret) + pr_warn("driver [%d] calibration fail\n", CONNDRV_TYPE_BT); + pr_info(">>>>>>>> BT do cal done"); + drv_inst = &g_conninfra_ctx.drv_inst[CONNDRV_TYPE_WIFI]; + ret = msg_thread_send_wait_1(&drv_inst->msg_ctx, + INFRA_SUBDRV_OPID_CAL_DO_CAL, 0, CONNDRV_TYPE_WIFI); + if (ret) + pr_warn("driver [%d] calibration fail\n", CONNDRV_TYPE_WIFI); + + pr_info(">>>>>>>> WF do cal done"); + + return 0; +} +#pragma GCC diagnostic pop + +static int opfunc_therm_ctrl(struct msg_op_data *op) +{ + return 0; +} + + +static int opfunc_subdrv_pre_reset(struct msg_op_data *op) +{ + int ret; + unsigned int drv_type = op->op_data[0]; + struct subsys_drv_inst *drv_inst; + + /* TODO: should be locked, to avoid cb was reset */ + drv_inst = &g_conninfra_ctx.drv_inst[drv_type]; + if (/*drv_inst->drv_status == DRV_ST_POWER_ON &&*/ + drv_inst->ops_cb.rst_cb.pre_whole_chip_rst) { + + ret = drv_inst->ops_cb.rst_cb.pre_whole_chip_rst(); + if (ret) + pr_err("[%s] fail [%d]", __func__, ret); + } + atomic_inc(&g_conninfra_ctx.rst_state); + up(&g_conninfra_ctx.rst_sema); + return 0; +} + +static int opfunc_subdrv_post_reset(struct msg_op_data *op) +{ + int ret; + unsigned int drv_type = op->op_data[0]; + struct subsys_drv_inst *drv_inst; + + /* TODO: should be locked, to avoid cb was reset */ + drv_inst = &g_conninfra_ctx.drv_inst[drv_type]; + if (/*drv_inst->drv_status == DRV_ST_POWER_ON &&*/ + drv_inst->ops_cb.rst_cb.post_whole_chip_rst) { + ret = drv_inst->ops_cb.rst_cb.post_whole_chip_rst(); + if (ret) + pr_warn("[%s] fail [%d]", __func__, ret); + } + + atomic_inc(&g_conninfra_ctx.rst_state); + up(&g_conninfra_ctx.rst_sema); + return 0; +} + +static int opfunc_subdrv_cal_pwr_on(struct msg_op_data *op) +{ + int ret; + unsigned int drv_type = op->op_data[0]; + struct subsys_drv_inst *drv_inst; + + pr_info("[%s] drv=[%s]", __func__, drv_thread_name[drv_type]); + + /* TODO: should be locked, to avoid cb was reset */ + drv_inst = &g_conninfra_ctx.drv_inst[drv_type]; + if (/*drv_inst->drv_status == DRV_ST_POWER_ON &&*/ + drv_inst->ops_cb.pre_cal_cb.pwr_on_cb) { + ret = drv_inst->ops_cb.pre_cal_cb.pwr_on_cb(); + if (ret) + pr_warn("[%s] fail [%d]", __func__, ret); + } + + atomic_inc(&g_conninfra_ctx.pre_cal_state); + up(&g_conninfra_ctx.pre_cal_sema); + + pr_info("[%s] DONE", __func__); + return 0; +} + +static int opfunc_subdrv_cal_do_cal(struct msg_op_data *op) +{ + int ret; + unsigned int drv_type = op->op_data[0]; + struct subsys_drv_inst *drv_inst; + + pr_info("[%s] drv=[%s]", __func__, drv_thread_name[drv_type]); + + drv_inst = &g_conninfra_ctx.drv_inst[drv_type]; + if (/*drv_inst->drv_status == DRV_ST_POWER_ON &&*/ + drv_inst->ops_cb.pre_cal_cb.do_cal_cb) { + ret = drv_inst->ops_cb.pre_cal_cb.do_cal_cb(); + if (ret) + pr_warn("[%s] fail [%d]", __func__, ret); + } + + pr_info("[%s]", __func__); + return 0; +} + +static int opfunc_subdrv_therm_ctrl(struct msg_op_data *op) +{ + return 0; +} + + +/* + * CONNINFRA API + */ +int conninfra_core_power_on(enum consys_drv_type type) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = msg_thread_send_wait_1(&infra_ctx->msg_ctx, + CONNINFRA_OPID_PWR_ON, 0, type); + if (ret) { + pr_err("[%s] fail", __func__); + return -1; + } + return 0; +} + +int conninfra_core_power_off(enum consys_drv_type type) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = msg_thread_send_wait_1(&infra_ctx->msg_ctx, + CONNINFRA_OPID_PWR_OFF, 0, type); + if (ret) { + pr_err("[%s] send msg fail", __func__); + return -1; + } + return 0; +} + +int conninfra_core_pre_cal_start(void) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = msg_thread_send(&infra_ctx->cb_ctx, + CONNINFRA_CB_OPID_PRE_CAL); + if (ret) { + pr_err("[%s] send msg fail", __func__); + return -1; + } + return 0; +} + +int conninfra_core_reg_readable(void) +{ + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + if (infra_ctx->infra_drv_status == DRV_STS_POWER_ON) + return consys_hw_reg_readable(); + return 0; +} + +int conninfra_core_is_consys_reg(phys_addr_t addr) +{ + return consys_hw_is_connsys_reg(addr); +} + + +int conninfra_core_lock_rst(void) +{ + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + int ret; + + /* non-zero means lock got, zero means not */ + ret = osal_trylock_sleepable_lock(&infra_ctx->rst_lock); + pr_info("[%s] ret=[%d]", __func__, ret); + return ret; +} + +int conninfra_core_unlock_rst(void) +{ + int ret = osal_unlock_sleepable_lock(&g_conninfra_ctx.rst_lock); + + pr_info("[%s] ret=[%d]", __func__, ret); + return ret; +} + +int conninfra_core_trg_chip_rst(enum consys_drv_type drv, char *reason) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = msg_thread_send_wait_1(&infra_ctx->cb_ctx, + CONNINFRA_CB_OPID_CHIP_RST, 0, drv); + if (ret) { + pr_err("[%s] send msg fail", __func__); + return -1; + } + return 0; +} + +int conninfra_core_subsys_ops_reg(enum consys_drv_type type, + struct sub_drv_ops_cb *cb) +{ + unsigned long flag; + struct subsys_drv_inst *drv_inst; + + spin_lock_irqsave(&g_conninfra_ctx.infra_lock, flag); + drv_inst = &g_conninfra_ctx.drv_inst[type]; + memcpy(&g_conninfra_ctx.drv_inst[type].ops_cb, cb, + sizeof(struct sub_drv_ops_cb)); + spin_unlock_irqrestore(&g_conninfra_ctx.infra_lock, flag); + return 0; +} + +int conninfra_core_subsys_ops_unreg(enum consys_drv_type type) +{ + unsigned long flag; + + spin_lock_irqsave(&g_conninfra_ctx.infra_lock, flag); + memset(&g_conninfra_ctx.drv_inst[type].ops_cb, 0, + sizeof(struct sub_drv_ops_cb)); + spin_unlock_irqrestore(&g_conninfra_ctx.infra_lock, flag); + + return 0; +} + +int conninfra_core_init(void) +{ + int ret = 0, i; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + osal_memset(&g_conninfra_ctx, 0, sizeof(g_conninfra_ctx)); + + spin_lock_init(&infra_ctx->infra_lock); + osal_sleepable_lock_init(&infra_ctx->rst_lock); + + + ret = msg_thread_init(&infra_ctx->msg_ctx, "conninfra_cored", + conninfra_core_opfunc, CONNINFRA_OPID_MAX); + if (ret) { + pr_err("msg_thread init fail(%d)\n", ret); + return -1; + } + + ret = msg_thread_init(&infra_ctx->cb_ctx, "conninfra_cb", + conninfra_core_cb_opfunc, CONNINFRA_CB_OPID_MAX); + if (ret) { + pr_err("callback msg thread init fail(%d)\n", ret); + return -1; + } + /* init subsys drv state */ + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + msg_thread_init(&infra_ctx->drv_inst[i].msg_ctx, + drv_thread_name[i], infra_subdrv_opfunc, + INFRA_SUBDRV_OPID_MAX); + } + + return ret; +} + + +int conninfra_core_deinit(void) +{ + int ret, i; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + ret = msg_thread_deinit(&infra_ctx->drv_inst[i].msg_ctx); + if (ret) + pr_warn("subdrv [%d] msg_thread deinit fail (%d)\n", + i, ret); + } + + ret = msg_thread_deinit(&infra_ctx->msg_ctx); + if (ret) { + pr_err("msg_thread_deinit fail(%d)\n", ret); + return -1; + } + + osal_sleepable_lock_deinit(&infra_ctx->rst_lock); + + return 0; +} + + + diff --git a/drivers/misc/mediatek/connectivity/conninfra/core/include/conninfra_core.h b/drivers/misc/mediatek/connectivity/conninfra/core/include/conninfra_core.h new file mode 100644 index 00000000000000..21acd8e7b3a8c1 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/core/include/conninfra_core.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _CONNINFRA_CORE_H_ +#define _CONNINFRA_CORE_H_ + +#include <linux/semaphore.h> +#include <linux/platform_device.h> + +#include "osal.h" +#include "msg_thread.h" +#include "conninfra.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_DRV_STS_ { + DRV_STS_POWER_OFF = 0, /* initial state */ + DRV_STS_POWER_ON = 1, /* powered on */ + DRV_STS_RESET = 2, + DRV_STS_MAX +} ENUM_DRV_STS, *P_ENUM_DRV_STS; + +struct subsys_drv_inst { + ENUM_DRV_STS drv_status; /* Controlled driver status */ + unsigned int rst_state; + struct sub_drv_ops_cb ops_cb; + struct msg_thread_ctx msg_ctx; +}; + + +/* + * state of conninfra + * + */ +struct conninfra_ctx { + ENUM_DRV_STS infra_drv_status; + + struct subsys_drv_inst drv_inst[CONNDRV_TYPE_MAX]; + /*struct spinlock infra_lock;*/ + spinlock_t infra_lock; + + OSAL_SLEEPABLE_LOCK rst_lock; + struct semaphore rst_sema; + atomic_t rst_state; + + struct semaphore pre_cal_sema; + atomic_t pre_cal_state; + + struct msg_thread_ctx msg_ctx; + struct msg_thread_ctx cb_ctx; + + unsigned int hw_ver; + unsigned int fw_ver; + unsigned int ip_ver; + + struct osal_op_history cored_op_history; + +}; + +//typedef enum _ENUM_CONNINFRA_CORE_OPID_T { +typedef enum { + CONNINFRA_OPID_PWR_ON = 0, + CONNINFRA_OPID_PWR_OFF = 1, + CONNINFRA_OPID_THERM_CTRL = 2, + CONNINFRA_OPID_MAX +} conninfra_core_opid; + +/* For the operation which may callback subsys driver */ +typedef enum { + CONNINFRA_CB_OPID_CHIP_RST = 0, + CONNINFRA_CB_OPID_PRE_CAL = 1, + CONNINFRA_CB_OPID_MAX +} conninfra_core_cb_opid; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern int conninfra_core_init(void); +extern int conninfra_core_deinit(void); + +int conninfra_core_power_on(enum consys_drv_type type); +int conninfra_core_power_off(enum consys_drv_type type); + +int conninfra_core_lock_rst(void); +int conninfra_core_unlock_rst(void); +int conninfra_core_trg_chip_rst(enum consys_drv_type drv, char *reason); + +int conninfra_core_subsys_ops_reg(enum consys_drv_type type, + struct sub_drv_ops_cb *cb); +int conninfra_core_subsys_ops_unreg(enum consys_drv_type type); + +int conninfra_core_pre_cal_start(void); + +/* NOTE: NOT thread-safe + * return value + * 1 : Yes, 0: NO + */ +int conninfra_core_reg_readable(void); +int conninfra_core_is_consys_reg(phys_addr_t addr); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _CONNINFRA_CORE_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/include/connectivity_build_in_adapter.h b/drivers/misc/mediatek/connectivity/conninfra/include/connectivity_build_in_adapter.h new file mode 100644 index 00000000000000..1913aab7188de7 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/include/connectivity_build_in_adapter.h @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef CONNECTIVITY_BUILD_IN_ADAPTER_H +#define CONNECTIVITY_BUILD_IN_ADAPTER_H + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/trace_events.h> + +/******************************************************************************* + * Clock Buffer Control + * + * The Connsys adaptation layer must provide Clock Buffer Control support + * should it be available from the platform. + * Therefore CONNADP_HAS_CLOCK_BUF_CTRL is defined based on platform chip, and + * is used to decide if adaptation has support on Clock Buffer Control. + * + * Each WMT platform file must still define its own CONSYS_CLOCK_BUF_CTRL to + * decide if it is a co-clock'd platform. + * It is possible that the Clock Buffer Control is available on the platform, + * but is not used by Connsys. + * + * For Kernel-3.18, definition of CONNADP_HAS_CLOCK_BUF_CTRL must align with: + * drivers/misc/mediatek/base/power/include/mt_clkbuf_ctl.h + * + * Platform that wishes to use Clock Buffer Control, please be sure to #include + * the header file above. + ******************************************************************************/ +#if defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || defined(CONFIG_ARCH_MT6753) || \ + defined(CONFIG_ARCH_MT6755) || \ + defined(CONFIG_ARCH_MT6757) || \ + defined(CONFIG_ARCH_MT6797) || \ + defined(CONFIG_ARCH_MT6570) || \ + defined(CONFIG_ARCH_MT6580) +#define CONNADP_HAS_CLOCK_BUF_CTRL +#define KERNEL_clk_buf_ctrl connectivity_export_clk_buf_ctrl +void connectivity_export_clk_buf_ctrl(/*enum clk_buf_id*/ int id, bool onoff); +#endif + +/******************************************************************************* + * PMIC + * Caller please be sure to #include: + * drivers/misc/mediatek/include/mt-plat/upmu_common.h + ******************************************************************************/ +#if defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || defined(CONFIG_ARCH_MT6753) || \ + defined(CONFIG_ARCH_MT6755) || \ + defined(CONFIG_ARCH_MT6757) || \ + defined(CONFIG_ARCH_MT6797) || \ + defined(CONFIG_ARCH_MT6570) || \ + defined(CONFIG_ARCH_MT6580) +#define CONNADP_HAS_PMIC_API +#define KERNEL_pmic_config_interface connectivity_export_pmic_config_interface +#define KERNEL_pmic_read_interface connectivity_export_pmic_read_interface +#define KERNEL_pmic_set_register_value connectivity_export_pmic_set_register_value +void connectivity_export_pmic_config_interface(unsigned int RegNum, unsigned int val, + unsigned int MASK, unsigned int SHIFT); +void connectivity_export_pmic_read_interface(unsigned int RegNum, unsigned int *val, + unsigned int MASK, unsigned int SHIFT); +void connectivity_export_pmic_set_register_value(/*PMU_FLAGS_LIST_ENUM*/ int flagname, unsigned int val); +#endif +#if defined(CONFIG_ARCH_MT8127) || \ + defined(CONFIG_ARCH_MT8163) +#define CONNADP_HAS_UPMU_VCN_CTRL +#define KERNEL_upmu_set_vcn_1v8_lp_mode_set connectivity_export_upmu_set_vcn_1v8_lp_mode_set +#define KERNEL_upmu_set_vcn28_on_ctrl connectivity_export_upmu_set_vcn28_on_ctrl +#define KERNEL_upmu_set_vcn33_on_ctrl_bt connectivity_export_upmu_set_vcn33_on_ctrl_bt +#define KERNEL_upmu_set_vcn33_on_ctrl_wifi connectivity_export_upmu_set_vcn33_on_ctrl_wifi +void connectivity_export_upmu_set_vcn_1v8_lp_mode_set(unsigned int val); +void connectivity_export_upmu_set_vcn28_on_ctrl(unsigned int val); +void connectivity_export_upmu_set_vcn33_on_ctrl_bt(unsigned int val); +void connectivity_export_upmu_set_vcn33_on_ctrl_wifi(unsigned int val); +#endif + +/******************************************************************************* + * MMC + * Caller please be sure to #include: + * <linux/mmc/host.h> + * <linux/mmc/card.h> + * drivers/mmc/core/sdio_ops.h + ******************************************************************************/ +#define KERNEL_mmc_io_rw_direct connectivity_export_mmc_io_rw_direct +struct mmc_card; +int connectivity_export_mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, + unsigned addr, u8 in, u8 *out); + +/******************************************************************************* + * Watchdog + ******************************************************************************/ +#if defined(CONFIG_ARCH_MT6797) +#define KERNEL_mtk_wdt_swsysret_config connectivity_export_mtk_wdt_swsysret_config +int connectivity_export_mtk_wdt_swsysret_config(int bit, int set_value); +extern int mtk_wdt_swsysret_config(int bit, int set_value); +#endif + + +#ifdef CONFIG_ARCH_MT6755 +#define CPU_BOOST y +#endif +#ifdef CONFIG_ARCH_MT6757 +#define CPU_BOOST y +#endif +#ifdef CONFIG_ARCH_MT6797 +#define CPU_BOOST y +#endif + +#ifdef CPU_BOOST +#include "mach/mt_ppm_api.h" +#endif + +#define KERNEL_show_stack connectivity_export_show_stack +#define KERNEL_tracing_record_cmdline connectivity_export_tracing_record_cmdline + +#ifdef CPU_BOOST +#define KERNEL_mt_ppm_sysboost_freq connectivity_export_mt_ppm_sysboost_freq +#define KERNEL_mt_ppm_sysboost_core connectivity_export_mt_ppm_sysboost_core +#define KERNEL_mt_ppm_sysboost_set_core_limit connectivity_export_mt_ppm_sysboost_set_core_limit +#else +#define KERNEL_mt_ppm_sysboost_freq +#define KERNEL_mt_ppm_sysboost_core +#define KERNEL_mt_ppm_sysboost_set_core_limit +#endif + +void connectivity_export_show_stack(struct task_struct *tsk, unsigned long *sp); +void connectivity_export_tracing_record_cmdline(struct task_struct *tsk); +#ifdef CPU_BOOST +void __attribute__((weak)) mt_ppm_sysboost_freq(enum ppm_sysboost_user user, unsigned int freq); +void __attribute__((weak)) mt_ppm_sysboost_core(enum ppm_sysboost_user user, unsigned int core_num); +void __attribute__((weak)) mt_ppm_sysboost_set_core_limit(enum ppm_sysboost_user user, unsigned int cluster, + int min_core, int max_core); +void connectivity_export_mt_ppm_sysboost_freq(enum ppm_sysboost_user user, unsigned int freq); +void connectivity_export_mt_ppm_sysboost_core(enum ppm_sysboost_user user, unsigned int core_num); +void connectivity_export_mt_ppm_sysboost_set_core_limit(enum ppm_sysboost_user user, unsigned int cluster, + int min_core, int max_core); +#endif + +extern void tracing_record_cmdline(struct task_struct *tsk); +extern void show_stack(struct task_struct *tsk, unsigned long *sp); + +/********************************************* + * for CPU unified APIs + *********************************************/ +#if defined(CONFIG_ARCH_MT6735) || defined(CONFIG_ARCH_MT6735M) || defined(CONFIG_ARCH_MT6753) +#include <mach/mt_lbc.h> +void connectivity_update_userlimit_cpu_freq(int kicker, + int num_cluster, struct ppm_limit_data *freq_limit); +void connectivity_update_userlimit_cpu_core(int kicker, + int num_cluster, struct ppm_limit_data *core_limit); + +extern int +update_userlimit_cpu_freq(int kicker, int num_cluster, struct ppm_limit_data *freq_limit); +extern int +update_userlimit_cpu_core(int kicker, int num_cluster, struct ppm_limit_data *core_limit); +#endif + +/********************************************* + * copy from + * kernel-3.18/include/linux/ftrace_event.h + * kernel-4.4/include/linux/trace_events.h + * + * event_trace_printk() + *********************************************/ +/* +#define KERNEL_event_trace_printk(ip, fmt, args...) \ +do { \ + __trace_printk_check_format(fmt, ##args); \ + KERNEL_tracing_record_cmdline(current); \ + if (__builtin_constant_p(fmt)) { \ + static const char *trace_printk_fmt \ + __attribute__((section("__trace_printk_fmt"))) = \ + __builtin_constant_p(fmt) ? fmt : NULL; \ + __trace_bprintk(ip, trace_printk_fmt, ##args); \ + } else \ + __trace_printk(ip, fmt, ##args); \ +} while (0) +*/ +#endif /* CONNECTIVITY_BUILD_IN_ADAPTER_H */ + + diff --git a/drivers/misc/mediatek/connectivity/conninfra/include/conninfra.h b/drivers/misc/mediatek/connectivity/conninfra/include/conninfra.h new file mode 100644 index 00000000000000..9468dc4a1cdf76 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/include/conninfra.h @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _CONNINFRA_H_ +#define _CONNINFRA_H_ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +enum consys_drv_type { + CONNDRV_TYPE_BT = 0, + CONNDRV_TYPE_FM = 1, + CONNDRV_TYPE_GPS = 2, + CONNDRV_TYPE_WIFI = 3, + CONNDRV_TYPE_MAX +}; + +#define CONNINFRA_CB_RET_CAL_PASS_POWER_OFF 0x0 +#define CONNINFRA_CB_RET_CAL_PASS_POWER_ON 0x2 +#define CONNINFRA_CB_RET_CAL_FAIL_POWER_OFF 0x1 +#define CONNINFRA_CB_RET_CAL_FAIL_POWER_ON 0x3 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/* EMI */ +extern void conninfra_get_phy_addr(unsigned int *addr, unsigned int *size); + +/* power on/off */ +extern int conninfra_pwr_on(enum consys_drv_type drv_type); +extern int conninfra_pwr_off(enum consys_drv_type drv_type); + + +/* chip reset +* return: +* <0: error +* =0: triggered +* =1: ongoing +*/ +extern int conninfra_trigger_whole_chip_rst(enum consys_drv_type drv, char *reason); + +struct whole_chip_rst_cb { + int (*pre_whole_chip_rst)(void); + int (*post_whole_chip_rst)(void); +}; + +/* driver state query */ + +/* VCN control */ + +/* Thermal */ + +/* Config */ + +/* semaphore */ + +/* calibration */ + + + +/* subsys callback register */ +struct pre_calibration_cb { + int (*pwr_on_cb)(void); + int (*do_cal_cb)(void); +}; + +struct sub_drv_ops_cb { + /* chip reset */ + struct whole_chip_rst_cb rst_cb; + + /* calibration */ + struct pre_calibration_cb pre_cal_cb; + + /* thermal query */ + int (*thermal_qry)(void); + +}; + +extern int conninfra_sub_drv_ops_register(enum consys_drv_type drv_type, struct sub_drv_ops_cb *cb); +extern int conninfra_sub_drv_ops_unregister(enum consys_drv_type drv_type); + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _CONNINFRA_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/init.conninfra.rc b/drivers/misc/mediatek/connectivity/conninfra/init.conninfra.rc new file mode 100644 index 00000000000000..ce09cb231804d1 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/init.conninfra.rc @@ -0,0 +1,2 @@ +on boot + insmod /vendor/lib/modules/mtk_conninfra.ko diff --git a/drivers/misc/mediatek/connectivity/conninfra/platform/clock_mng.c b/drivers/misc/mediatek/connectivity/conninfra/platform/clock_mng.c new file mode 100644 index 00000000000000..9c2fd55d28ad39 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/platform/clock_mng.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include "osal.h" + +#include "clock_mng.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + diff --git a/drivers/misc/mediatek/connectivity/conninfra/platform/consys_hw.c b/drivers/misc/mediatek/connectivity/conninfra/platform/consys_hw.c new file mode 100644 index 00000000000000..8da63560441d73 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/platform/consys_hw.c @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ +#include <linux/of.h> +#include <linux/of_reserved_mem.h> +#include <linux/delay.h> +#include "osal.h" + +#include "consys_hw.h" +#include "emi_mng.h" +#include "pmic_mng.h" +#include "consys_reg_mng.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static int mtk_conninfra_probe(struct platform_device *pdev); +static void mtk_conninfra_remove(struct platform_device *pdev); +static int mtk_conninfra_suspend(struct platform_device *pdev, pm_message_t state); +static int mtk_conninfra_resume(struct platform_device *pdev); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +#ifdef CONFIG_OF +const struct of_device_id apconninfra_of_ids[] = { + {.compatible = "mediatek,mt6789-consys",}, + {} +}; +#endif + +static struct platform_driver mtk_conninfra_dev_drv = { + .probe = mtk_conninfra_probe, + .remove = mtk_conninfra_remove, + .suspend = mtk_conninfra_suspend, + .resume = mtk_conninfra_resume, + .driver = { + .name = "mtk_conninfra", + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = apconninfra_of_ids, +#endif + }, +}; + +struct consys_hw_ops_struct *consys_hw_ops; +struct platform_device *g_pdev; +EXPORT_SYMBOL(g_pdev); + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +struct consys_hw_ops_struct* __weak get_consys_platform_ops(void) +{ + pr_err("Miss platform ops !!\n"); + return NULL; +} + + +struct platform_device *get_consys_device(void) +{ + return g_pdev; +} + + +int consys_hw_pwr_off(void) +{ +#if 0 + if (wmt_consys_ic_ops->consys_ic_ahb_clock_ctrl) + wmt_consys_ic_ops->consys_ic_ahb_clock_ctrl(DISABLE); + if (wmt_consys_ic_ops->consys_ic_hw_power_ctrl) + wmt_consys_ic_ops->consys_ic_hw_power_ctrl(DISABLE); + if (co_clock_type) { + if (wmt_consys_ic_ops->consys_ic_clock_buffer_ctrl) + wmt_consys_ic_ops->consys_ic_clock_buffer_ctrl(DISABLE); + } + + if (co_clock_type == 0) { + if (wmt_consys_ic_ops->consys_ic_vcn28_hw_mode_ctrl) + wmt_consys_ic_ops->consys_ic_vcn28_hw_mode_ctrl(DISABLE); + /*turn off VCN28 LDO (with PMIC_WRAP API)" */ + if (wmt_consys_ic_ops->consys_ic_hw_vcn28_ctrl) + wmt_consys_ic_ops->consys_ic_hw_vcn28_ctrl(DISABLE); + } + + if (wmt_consys_ic_ops->consys_ic_set_if_pinmux) + wmt_consys_ic_ops->consys_ic_set_if_pinmux(DISABLE); + + if (wmt_consys_ic_ops->consys_ic_hw_vcn18_ctrl) + wmt_consys_ic_ops->consys_ic_hw_vcn18_ctrl(DISABLE); +#endif + return 0; +} + +int consys_hw_pwr_on(void) +{ + int ret; + + /* POS PART 1: + * Set PMIC to turn on the power that AFE WBG circuit in D-die, + * OSC or crystal component, and A-die need. + */ + ret = pmic_mng_common_power_ctrl(1); + if (consys_hw_ops->consys_plt_clock_buffer_ctrl) + consys_hw_ops->consys_plt_clock_buffer_ctrl(1); + + /* POS PART 2: + * 1. Pinmux setting + * 2. Turn on MTCMOS + * 3. Enable AXI bus (AP2CONN slpprot) + */ + if (consys_hw_ops->consys_plt_set_if_pinmux) + consys_hw_ops->consys_plt_set_if_pinmux(1); + + udelay(150); + if (consys_hw_ops->consys_plt_conninfra_on_power_ctrl) + consys_hw_ops->consys_plt_conninfra_on_power_ctrl(1); + + /* Wait 5ms for CONNSYS XO clock ready */ + mdelay(5); + + if (consys_hw_ops->consys_plt_polling_consys_chipid) + consys_hw_ops->consys_plt_polling_consys_chipid(); + + /* POS PART 3: + * 1. d_die_cfg + * 2. spi_master_cfg + * 3. a_die_cfg + * 4. afe_wbg_cal + * 5. patch default value + * 6. CONN_INFRA low power setting (srcclken wait time, mtcmos HW ctl...) + */ + if (consys_hw_ops->consys_plt_d_die_cfg) + consys_hw_ops->consys_plt_d_die_cfg(); + if (consys_hw_ops->consys_plt_spi_master_cfg) + consys_hw_ops->consys_plt_spi_master_cfg(); + if (consys_hw_ops->consys_plt_a_die_cfg) + consys_hw_ops->consys_plt_a_die_cfg(); + if (consys_hw_ops->consys_plt_afe_wbg_cal) + consys_hw_ops->consys_plt_afe_wbg_cal(); + if (consys_hw_ops->consys_plt_low_power_setting) + consys_hw_ops->consys_plt_low_power_setting(); + return 0; +} + +int consys_hw_wifi_power_ctl(unsigned int enable) +{ + return 0; +} + +int consys_hw_bt_power_ctl(unsigned int enable) +{ + return 0; +} + +int consys_hw_gps_power_ctl(unsigned int enable) +{ + return 0; +} + +int consys_hw_fm_power_ctl(unsigned int enable) +{ + return 0; +} + +int mtk_conninfra_probe(struct platform_device *pdev) +{ + int ret = -1; + + /* Read device node */ + + if (consys_reg_mng_init(pdev) != 0) { + pr_err("consys_plt_read_reg_from_dts fail"); + return -1; + } + + if (consys_hw_ops->consys_plt_clk_get_from_dts) + consys_hw_ops->consys_plt_clk_get_from_dts(pdev); + else { + pr_err("consys_plt_clk_get_from_dtsfail"); + return -2; + } + + /* emi mng init */ + ret = emi_mng_init(); + if (ret) { + pr_err("emi_mng init fail, %d\n", ret); + return -3; + } + + ret = pmic_mng_init(pdev); + if (ret) { + pr_err("pmic_mng init fail, %d\n", ret); + return -4; + } + + if (pdev) + g_pdev = pdev; + + return 0; +} + +void mtk_conninfra_remove(struct platform_device *pdev) +{ +#if 0 + if (wmt_consys_ic_ops->consys_ic_need_store_pdev) { + if (wmt_consys_ic_ops->consys_ic_need_store_pdev() == MTK_WCN_BOOL_TRUE) + pm_runtime_disable(&pdev->dev); + } + + if (wmt_consys_ic_ops->consys_ic_dedicated_log_path_deinit) + wmt_consys_ic_ops->consys_ic_dedicated_log_path_deinit(); + if (wmt_consys_ic_ops->consys_ic_emi_coredump_remapping) + wmt_consys_ic_ops->consys_ic_emi_coredump_remapping(&pEmibaseaddr, 0); +#endif + if (g_pdev) + g_pdev = NULL; +} + +int mtk_conninfra_suspend(struct platform_device *pdev, pm_message_t state) +{ + //WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_WHEN_AP_SUSPEND); + + return 0; +} + +int mtk_conninfra_resume(struct platform_device *pdev) +{ + //WMT_STEP_DO_ACTIONS_FUNC(STEP_TRIGGER_POINT_WHEN_AP_RESUME); + + //if (wmt_consys_ic_ops->consys_ic_resume_dump_info) + // wmt_consys_ic_ops->consys_ic_resume_dump_info(); + + return 0; +} + + +int consys_hw_init(void) +{ + int iRet = 0; + + if (consys_hw_ops == NULL) + consys_hw_ops = get_consys_platform_ops(); + + iRet = platform_driver_register(&mtk_conninfra_dev_drv); + if (iRet) + pr_err("Conninfra platform driver registered failed(%d)\n", iRet); + + pr_info("[consys_hw_init] result [%d]\n", iRet); + return iRet; +} + +int consys_hw_deinit(void) +{ + platform_driver_unregister(&mtk_conninfra_dev_drv); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/conninfra/platform/consys_reg_mng.c b/drivers/misc/mediatek/connectivity/conninfra/platform/consys_reg_mng.c new file mode 100644 index 00000000000000..aaee6b2e3f17e2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/platform/consys_reg_mng.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include "consys_reg_mng.h" + +struct consys_reg_mng_ops* g_consys_reg_ops = NULL; + +struct consys_reg_mng_ops* __weak get_consys_reg_mng_ops(void) +{ + pr_warn("No specify project\n"); + return NULL; +} + +int consys_hw_reg_readable(void) +{ + if (g_consys_reg_ops && + g_consys_reg_ops->consys_reg_mng_check_reable) + return g_consys_reg_ops->consys_reg_mng_check_reable(); + return -1; +} + +int consys_hw_is_connsys_reg(phys_addr_t addr) +{ + if (g_consys_reg_ops && + g_consys_reg_ops->consys_reg_mng_is_consys_reg) + return g_consys_reg_ops->consys_reg_mng_is_consys_reg(addr); + return -1; +} + +int consys_reg_mng_init(struct platform_device *pdev) +{ + int ret = 0; + if (g_consys_reg_ops == NULL) + g_consys_reg_ops = get_consys_reg_mng_ops(); + + if (g_consys_reg_ops && + g_consys_reg_ops->consys_reg_mng_init) + ret = g_consys_reg_ops->consys_reg_mng_init(pdev); + else + ret = EFAULT; + + return ret; +} + +int consys_reg_mng_deinit(void) +{ + if (g_consys_reg_ops&& + g_consys_reg_ops->consys_reg_mng_deinit) + g_consys_reg_ops->consys_reg_mng_deinit(); + + return 0; +} + diff --git a/drivers/misc/mediatek/connectivity/conninfra/platform/emi_mng.c b/drivers/misc/mediatek/connectivity/conninfra/platform/emi_mng.c new file mode 100644 index 00000000000000..9538d9b273b9c4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/platform/emi_mng.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include <linux/of_reserved_mem.h> +#include <linux/io.h> +#include <linux/types.h> +#include "osal.h" + +#include "emi_mng.h" + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +extern unsigned long long gConEmiSize; +extern phys_addr_t gConEmiPhyBase; + +struct consys_platform_emi_ops* consys_platform_emi_ops = NULL; + +struct consys_emi_addr_info connsys_emi_addr_info = { + .emi_ap_phy_addr = 0, + .emi_size = 0 +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + +int emi_mng_set_region_protection(void) +{ + if (consys_platform_emi_ops && + consys_platform_emi_ops->consys_ic_emi_mpu_set_region_protection) + return consys_platform_emi_ops->consys_ic_emi_mpu_set_region_protection(); + return -1; +} + +int emi_mng_set_remapping_reg(void) +{ + if (consys_platform_emi_ops && + consys_platform_emi_ops->consys_ic_emi_set_remapping_reg) + return consys_platform_emi_ops->consys_ic_emi_set_remapping_reg(gConEmiPhyBase); + return -1; +} + +struct consys_emi_addr_info* emi_mng_get_phy_addr(void) +{ + return &connsys_emi_addr_info; +} + + +struct consys_platform_emi_ops* __weak get_consys_platform_emi_ops(void) +{ + pr_warn("No specify project\n"); + return NULL; +} + +//#pragma GCC diagnostic push +//#pragma GCC diagnostic ignored "-Wincompatible-pointer-types" +int emi_mng_init(void) +{ + if (consys_platform_emi_ops == NULL) + consys_platform_emi_ops = get_consys_platform_emi_ops(); + + pr_info("[emi_mng_init] gConEmiPhyBase = [%llu] size = [%llu] ops=[%p]", + gConEmiPhyBase, gConEmiSize, consys_platform_emi_ops); + + if (gConEmiPhyBase) { + + connsys_emi_addr_info.emi_ap_phy_addr = gConEmiPhyBase; + connsys_emi_addr_info.emi_size = gConEmiSize; + + #if 0 + if (consys_platform_emi_ops->consys_ic_emi_mpu_set_region_protection) + consys_platform_emi_ops->consys_ic_emi_mpu_set_region_protection(); + #endif + if (consys_platform_emi_ops->consys_ic_emi_set_remapping_reg) + consys_platform_emi_ops->consys_ic_emi_set_remapping_reg(gConEmiPhyBase); + #if 0 + if (consys_platform_emi_ops->consys_ic_emi_coredump_remapping) + consys_platform_emi_ops->consys_ic_emi_coredump_remapping(&pEmibaseaddr, 1); + #endif + } else { + pr_err("consys emi memory address gConEmiPhyBase invalid\n"); + } + return 0; +} +#pragma GCC diagnostic pop + +int emi_mng_deinit(void) +{ + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/conninfra/platform/include/clock_mng.h b/drivers/misc/mediatek/connectivity/conninfra/platform/include/clock_mng.h new file mode 100644 index 00000000000000..ff628306c800bf --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/platform/include/clock_mng.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_CLOCK_MNG_H_ +#define _PLATFORM_CLOCK_MNG_H_ + +#include "osal.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PLATFORM_CLOCK_MNG_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/platform/include/consys_hw.h b/drivers/misc/mediatek/connectivity/conninfra/platform/include/consys_hw.h new file mode 100644 index 00000000000000..9f438739c32843 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/platform/include/consys_hw.h @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_CONSYS_HW_H_ +#define _PLATFORM_CONSYS_HW_H_ + +#include <linux/platform_device.h> + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef int(*CONSYS_PLT_CLK_GET_FROM_DTS) (struct platform_device *pdev); +typedef int(*CONSYS_PLT_READ_REG_FROM_DTS) (struct platform_device *pdev); + +typedef int(*CONSYS_PLT_CLOCK_BUFFER_CTRL) (unsigned int enable); +typedef int(*CONSYS_PLT_CONNINFRA_ON_POWER_CTRL) (unsigned int enable); +typedef void(*CONSYS_PLT_SET_IF_PINMUX) (unsigned int enable); + +typedef int(*CONSYS_PLT_POLLING_CONSYS_CHIPID) (void); +typedef int(*CONSYS_PLT_D_DIE_CFG) (void); +typedef int(*CONSYS_PLT_SPI_MASTER_CFG) (void); +typedef int(*CONSYS_PLT_A_DIE_CFG) (void); +typedef int(*CONSYS_PLT_AFE_WBG_CAL) (void); +typedef int(*CONSYS_PLT_LOW_POWER_SETTING) (void); + +typedef void(*CONSYS_PLT_AFE_REG_SETTING) (void); +typedef unsigned int(*CONSYS_PLT_SOC_CHIPID_GET) (void); + +typedef void(*CONSYS_PLT_FORCE_TRIGGER_ASSERT_DEBUG_PIN) (void); +typedef int(*CONSYS_PLT_CO_CLOCK_TYPE) (void); + +typedef int(*CONSYS_PLT_CHECK_REG_READABLE) (void); +typedef void(*CONSYS_PLT_CLOCK_FAIL_DUMP) (void); +typedef unsigned int(*CONSYS_PLT_READ_CPUPCR) (void); +typedef int(*CONSYS_PLT_IS_CONNSYS_REG) (unsigned int addr); + +typedef void(*CONSYS_PLT_RESUME_DUMP_INFO) (void); +typedef void(*CONSYS_PLT_SET_PDMA_AXI_RREADY_FORCE_HIGH) (unsigned int enable); + +struct consys_hw_ops_struct { + /* load from dts */ + CONSYS_PLT_CLK_GET_FROM_DTS consys_plt_clk_get_from_dts; + /*CONSYS_IC_PMIC_GET_FROM_DTS consys_ic_pmic_get_from_dts;*/ + //CONSYS_PLT_READ_REG_FROM_DTS consys_plt_read_reg_from_dts; + /* irq, do we need? */ + /*CONSYS_IC_READ_IRQ_INFO_FROM_DTS consys_ic_read_irq_info_from_dts;*/ + + /* clock */ + CONSYS_PLT_CLOCK_BUFFER_CTRL consys_plt_clock_buffer_ctrl; + CONSYS_PLT_CO_CLOCK_TYPE consys_plt_co_clock_type; + + /* POS */ + /*CONSYS_IC_HW_SPM_CLK_GATING_ENABLE consys_ic_hw_spm_clk_gating_enable;*/ + CONSYS_PLT_CONNINFRA_ON_POWER_CTRL consys_plt_conninfra_on_power_ctrl; + CONSYS_PLT_SET_IF_PINMUX consys_plt_set_if_pinmux; + + /*CONSYS_IC_AHB_CLOCK_CTRL consys_ic_ahb_clock_ctrl;*/ + CONSYS_PLT_POLLING_CONSYS_CHIPID consys_plt_polling_consys_chipid; + CONSYS_PLT_D_DIE_CFG consys_plt_d_die_cfg; + CONSYS_PLT_SPI_MASTER_CFG consys_plt_spi_master_cfg; + CONSYS_PLT_A_DIE_CFG consys_plt_a_die_cfg; + CONSYS_PLT_AFE_WBG_CAL consys_plt_afe_wbg_cal; + CONSYS_PLT_LOW_POWER_SETTING consys_plt_low_power_setting; + + /*UPDATE_CONSYS_ROM_DESEL_VALUE update_consys_rom_desel_value;*/ + /*CONSYS_HANG_DEBUG consys_hang_debug;*/ + /*CONSYS_IC_ARC_REG_SETTING consys_ic_acr_reg_setting;*/ + CONSYS_PLT_AFE_REG_SETTING consys_plt_afe_reg_setting; + + CONSYS_PLT_SOC_CHIPID_GET consys_plt_soc_chipid_get; + + /*IC_BT_WIFI_SHARE_V33_SPIN_LOCK_INIT ic_bt_wifi_share_v33_spin_lock_init;*/ + /*CONSYS_PLT_FORCE_TRIGGER_ASSERT_DEBUG_PIN consys_plt_force_trigger_assert_debug_pin;*/ + + /*CONSYS_IC_SET_DL_ROM_PATCH_FLAG consys_ic_set_dl_rom_patch_flag;*/ + /*CONSYS_IC_DEDICATED_LOG_PATH_INIT consys_ic_dedicated_log_path_init;*/ + /*CONSYS_IC_DEDICATED_LOG_PATH_DEINIT consys_ic_dedicated_log_path_deinit;*/ + + /* debug */ + CONSYS_PLT_CHECK_REG_READABLE consys_plt_check_reg_readable; + CONSYS_PLT_CLOCK_FAIL_DUMP consys_plt_clock_fail_dump; + CONSYS_PLT_READ_CPUPCR consys_plt_cread_cpupcr; + + /* debug, used by STEP */ + CONSYS_PLT_IS_CONNSYS_REG consys_plt_is_connsys_reg; + + CONSYS_PLT_RESUME_DUMP_INFO consys_plt_resume_dump_info; + + /* for reset */ + CONSYS_PLT_SET_PDMA_AXI_RREADY_FORCE_HIGH consys_plt_set_pdma_axi_rready_force_high; +}; + + +extern struct consys_base_addr conn_reg; +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +int consys_hw_init(void); +int consys_hw_deinit(void); + +int consys_hw_pwr_off(void); +int consys_hw_pwr_on(void); + +int consys_hw_wifi_power_ctl(unsigned int enable); +int consys_hw_bt_power_ctl(unsigned int enable); +int consys_hw_gps_power_ctl(unsigned int enable); +int consys_hw_fm_power_ctl(unsigned int enable); + +struct consys_hw_ops_struct* __weak get_consys_platform_ops(void); + +/******************************************************************************* +* tempoary for STEP +******************************************************************************** +*/ +/* + * return + * 1 : can read + * 0 : can't read + * -1: not consys register + */ +int consys_hw_reg_readable(void); +int consys_hw_is_connsys_reg(phys_addr_t addr); + + +struct platform_device *get_consys_device(void); +struct consys_base_addr *get_conn_reg_base_addr(void); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PLATFORM_CONSYS_HW_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/platform/include/consys_reg_base.h b/drivers/misc/mediatek/connectivity/conninfra/platform/include/consys_reg_base.h new file mode 100644 index 00000000000000..7c1d96a713dff0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/platform/include/consys_reg_base.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_CONSYS_REG_BASE_H_ +#define _PLATFORM_CONSYS_REG_BASE_H_ + +struct consys_reg_base_addr { + unsigned long vir_addr; + unsigned long long size; +}; + +#endif /* _PLATFORM_CONSYS_REG_BASE_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/platform/include/consys_reg_mng.h b/drivers/misc/mediatek/connectivity/conninfra/platform/include/consys_reg_mng.h new file mode 100644 index 00000000000000..c84c84929bc87f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/platform/include/consys_reg_mng.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_CONSYS_REG_MNG_H_ +#define _PLATFORM_CONSYS_REG_MNG_H_ + +#include <linux/platform_device.h> + +struct consys_reg_mng_ops { + + int(*consys_reg_mng_init) (struct platform_device *pdev); + int(*consys_reg_mng_deinit) (void); + int(*consys_reg_mng_check_reable) (void); + int(*consys_reg_mng_is_consys_reg) (unsigned int addr); + +}; + +int consys_reg_mng_init(struct platform_device *pdev); +int consys_reg_mng_deinit(void); + +int consys_hw_reg_readable(void); +int consys_hw_is_connsys_reg(phys_addr_t addr); + +struct consys_reg_mng_ops* __weak get_consys_reg_mng_ops(void); + +#endif /* _PLATFORM_CONSYS_REG_MNG_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/platform/include/consys_reg_util.h b/drivers/misc/mediatek/connectivity/conninfra/platform/include/consys_reg_util.h new file mode 100644 index 00000000000000..8dfc1439e45617 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/platform/include/consys_reg_util.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_CONSYS_REG_UTIL_H_ +#define _PLATFORM_CONSYS_REG_UTIL_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define KBYTE (1024*sizeof(char)) + +#define GENMASK(h, l) \ + (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) + +#define GET_BIT_MASK(value, mask) ((value) & (mask)) +#define SET_BIT_MASK(pdest, value, mask) (*(pdest) = (GET_BIT_MASK(*(pdest), ~(mask)) | GET_BIT_MASK(value, mask))) +#define GET_BIT_RANGE(data, end, begin) ((data) & GENMASK(end, begin)) +#define SET_BIT_RANGE(pdest, data, end, begin) (SET_BIT_MASK(pdest, data, GENMASK(end, begin))) + +#define CONSYS_SET_BIT(REG, BITVAL) (*((volatile unsigned int *)(REG)) |= ((unsigned int)(BITVAL))) +#define CONSYS_CLR_BIT(REG, BITVAL) ((*(volatile unsigned int *)(REG)) &= ~((unsigned int)(BITVAL))) +#define CONSYS_CLR_BIT_WITH_KEY(REG, BITVAL, KEY) {\ + unsigned int val = (*(volatile unsigned int *)(REG)); \ + val &= ~((unsigned int)(BITVAL)); \ + val |= ((unsigned int)(KEY)); \ + (*(volatile unsigned int *)(REG)) = val;\ +} +#define CONSYS_REG_READ(addr) (*((volatile unsigned int *)(addr))) +#define CONSYS_REG_READ_BIT(addr, BITVAL) (*((volatile unsigned int *)(addr)) & ((unsigned int)(BITVAL))) +#define CONSYS_REG_WRITE(addr, data) mt_reg_sync_writel(data, addr) +#define CONSYS_REG_WRITE_RANGE(reg, data, end, begin) {\ + unsigned int val = CONSYS_REG_READ(reg); \ + SET_BIT_RANGE(&val, data, end, begin); \ + CONSYS_REG_WRITE(reg, val); \ +} +#define CONSYS_REG_WRITE_MASK(reg, data, mask) {\ + unsigned int val = CONSYS_REG_READ(reg); \ + SET_BIT_MASK(&val, data, mask); \ + CONSYS_REG_WRITE(reg, val); \ +} + +/* + * Write value with value_offset bits of right shift and size bits, + * to the reg_offset-th bit of address reg + * value -----------XXXXXXXXXXXX------------------- + * |<--size-->|<--value_offset-->| + * reg -------------OOOOOOOOOOOO----------------- + * |<--size-->|<--reg_offset-->| + * result -------------XXXXXXXXXXXX----------------- + */ +#define CONSYS_REG_WRITE_OFFSET_RANGE(reg, value, reg_offset, value_offset, size) ({\ + unsigned int data = (value) >> (value_offset); \ + data = GET_BIT_RANGE(data, size, 0); \ + data = data << (reg_offset); \ + CONSYS_REG_WRITE_RANGE(reg, data, ((reg_offset) + ((size) - 1)), reg_offset); \ +}) + +#define CONSYS_REG_WRITE_BIT(reg, offset, val) CONSYS_REG_WRITE_OFFSET_RANGE(reg, ((val) & 1), offset, 0, 1) + +#define CONSYS_REG_BIT_POLLING(addr, bit_index, exp_val, loop, delay, success) {\ + unsigned int polling_count = 0; \ + unsigned int reg_value = 0; \ + success = 0; \ + reg_value = (CONSYS_REG_READ_BIT(addr, (0x1 << bit_index)) >> bit_index); \ + while (reg_value != exp_val) { \ + if (polling_count > loop) { \ + success = -1; \ + break; \ + } \ + reg_value = (CONSYS_REG_READ_BIT(addr, (0x1 << bit_index)) >> bit_index); \ + udelay(delay); \ + polling_count++; \ + } \ +} + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PLATFORM_CONSYS_REG_UTIL_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/platform/include/emi_mng.h b/drivers/misc/mediatek/connectivity/conninfra/platform/include/emi_mng.h new file mode 100644 index 00000000000000..5e6dd6e29113f0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/platform/include/emi_mng.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_EMI_MNG_H_ +#define _PLATFORM_EMI_MNG_H_ + +#include <linux/types.h> +#include "osal.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_EMI_CTRL_STATE_OFFSET_ { + EXP_APMEM_CTRL_STATE = 0x0, + EXP_APMEM_CTRL_HOST_SYNC_STATE = 0x4, + EXP_APMEM_CTRL_HOST_SYNC_NUM = 0x8, + EXP_APMEM_CTRL_CHIP_SYNC_STATE = 0xc, + EXP_APMEM_CTRL_CHIP_SYNC_NUM = 0x10, + EXP_APMEM_CTRL_CHIP_SYNC_ADDR = 0x14, + EXP_APMEM_CTRL_CHIP_SYNC_LEN = 0x18, + EXP_APMEM_CTRL_CHIP_PRINT_BUFF_START = 0x1c, + EXP_APMEM_CTRL_CHIP_PRINT_BUFF_LEN = 0x20, + EXP_APMEM_CTRL_CHIP_PRINT_BUFF_IDX = 0x24, + EXP_APMEM_CTRL_CHIP_INT_STATUS = 0x28, + EXP_APMEM_CTRL_CHIP_PAGED_DUMP_END = 0x2c, + EXP_APMEM_CTRL_HOST_OUTBAND_ASSERT_W1 = 0x30, + EXP_APMEM_CTRL_CHIP_PAGE_DUMP_NUM = 0x44, + EXP_APMEM_CTRL_CHIP_FW_DBGLOG_MODE = 0x40, + EXP_APMEM_CTRL_CHIP_DYNAMIC_DUMP = 0x48, + EXP_APMEM_CTRL_ASSERT_FLAG = 0x100, + EXP_APMEM_CTRL_MAX +} ENUM_EMI_CTRL_STATE_OFFSET, *P_ENUM_EMI_CTRL_STATE_OFFSET; + +typedef struct _EMI_CTRL_STATE_OFFSET_ { + unsigned int emi_apmem_ctrl_state; + unsigned int emi_apmem_ctrl_host_sync_state; + unsigned int emi_apmem_ctrl_host_sync_num; + //unsigned int emi_apmem_ctrl_chip_sync_state; + //unsigned int emi_apmem_ctrl_chip_sync_num; + //unsigned int emi_apmem_ctrl_chip_sync_addr; + //unsigned int emi_apmem_ctrl_chip_sync_len; + //unsigned int emi_apmem_ctrl_chip_print_buff_start; + //unsigned int emi_apmem_ctrl_chip_print_buff_len; + //unsigned int emi_apmem_ctrl_chip_print_buff_idx; + //unsigned int emi_apmem_ctrl_chip_int_status; + //unsigned int emi_apmem_ctrl_chip_paded_dump_end; + //unsigned int emi_apmem_ctrl_host_outband_assert_w1; + //unsigned int emi_apmem_ctrl_chip_page_dump_num; + //unsigned int emi_apmem_ctrl_assert_flag; +} EMI_CTRL_STATE_OFFSET, *P_EMI_CTRL_STATE_OFFSET; + + +struct consys_emi_addr_info { + unsigned int emi_ap_phy_addr; + unsigned int emi_size; +#if 0 + unsigned int emi_phy_addr; + unsigned int emi_ap_phy_addr; + unsigned int paged_trace_off; + unsigned int paged_dump_off; + unsigned int full_dump_off; + unsigned int emi_remap_offset; + P_EMI_CTRL_STATE_OFFSET p_ecso; + unsigned int emi_size; + unsigned int pda_dl_patch_flag; + unsigned int emi_met_size; + unsigned int emi_met_data_offset; + unsigned int emi_core_dump_offset; +#endif +}; + +typedef int(*CONSYS_IC_EMI_MPU_SET_REGION_PROTECTION) (void); +typedef unsigned int(*CONSYS_IC_EMI_SET_REMAPPING_REG) (unsigned int); +typedef int(*CONSYS_IC_EMI_COREDUMP_REMAPPING) (unsigned char __iomem **addr, unsigned int enable); +typedef int(*CONSYS_IC_EMI_COREDUMP_RESET) (unsigned char __iomem *addr); +//typedef P_CONSYS_EMI_ADDR_INFO(*CONSYS_IC_EMI_GET_PHY_ADDR) (void); + +struct consys_platform_emi_ops { + CONSYS_IC_EMI_MPU_SET_REGION_PROTECTION consys_ic_emi_mpu_set_region_protection; + CONSYS_IC_EMI_SET_REMAPPING_REG consys_ic_emi_set_remapping_reg; + //CONSYS_IC_EMI_GET_PHY_ADDR consys_ic_emi_get_phy_addr; + CONSYS_IC_EMI_COREDUMP_REMAPPING consys_ic_emi_coredump_remapping; + CONSYS_IC_EMI_COREDUMP_RESET consys_ic_reset_emi_coredump; +}; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +//extern unsigned long long gConEmiSize; +//extern phys_addr_t gConEmiPhyBase; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +int emi_mng_init(void); +int emi_mng_deinit(void); + +int emi_mng_set_region_protection(void); +int emi_mng_set_remapping_reg(void); +struct consys_emi_addr_info* emi_mng_get_phy_addr(void); + +struct consys_platform_emi_ops* __weak get_consys_platform_emi_ops(void); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PLATFORM_EMI_MNG_H_ */ + diff --git a/drivers/misc/mediatek/connectivity/conninfra/platform/include/plat_def.h b/drivers/misc/mediatek/connectivity/conninfra/platform/include/plat_def.h new file mode 100644 index 00000000000000..0d3903bd99df92 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/platform/include/plat_def.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_DEF_H_ +#define _PLATFORM_DEF_H_ + +#include <linux/delay.h> +#include <sync_write.h> + +#endif /* _PLATFORM_DEF_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/platform/include/pmic_mng.h b/drivers/misc/mediatek/connectivity/conninfra/platform/include/pmic_mng.h new file mode 100644 index 00000000000000..4231e843a90050 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/platform/include/pmic_mng.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_PMIC_MNG_H_ +#define _PLATFORM_PMIC_MNG_H_ + +#include <linux/platform_device.h> + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef int(*CONSYS_PMIC_GET_FROM_DTS) (struct platform_device *pdev); + +typedef int(*CONSYS_PMIC_COMMON_POWER_CTRL) (unsigned int enable); + +typedef int(*CONSYS_PMIC_WIFI_POWER_CTRL) (unsigned int enable); +typedef int(*CONSYS_PMIC_BT_POWER_CTRL) (unsigned int enable); +typedef int(*CONSYS_PMIC_GPS_POWER_CTRL) (unsigned int enable); +typedef int(*CONSYS_PMIC_FM_POWER_CTRL) (unsigned int enable); + +typedef struct _CONSYS_PLATFORM_PMIC_OPS_ { + CONSYS_PMIC_GET_FROM_DTS consys_pmic_get_from_dts; + /* vcn 18 */ + CONSYS_PMIC_COMMON_POWER_CTRL consys_pmic_common_power_ctrl; + CONSYS_PMIC_WIFI_POWER_CTRL consys_pmic_wifi_power_ctrl; + CONSYS_PMIC_BT_POWER_CTRL consys_pmic_bt_power_ctrl; + CONSYS_PMIC_GPS_POWER_CTRL consys_pmic_gps_power_ctrl; + CONSYS_PMIC_FM_POWER_CTRL consys_pmic_fm_power_ctrl; + +} CONSYS_PLATFORM_PMIC_OPS, *P_CONSYS_PLATFORM_PMIC_OPS; + + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +int pmic_mng_init(struct platform_device *pdev); +int pmic_mng_deinit(void); + +int pmic_mng_common_power_ctrl(unsigned int enable); +int pmic_mng_wifi_power_ctrl(unsigned int enable); +int pmic_mng_bt_power_ctrl(unsigned int enable); +int pmic_mng_gps_power_ctrl(unsigned int enable); +int pmic_mng_fm_power_ctrl(unsigned int enable); + +P_CONSYS_PLATFORM_PMIC_OPS __weak get_consys_platform_pmic_ops(void); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PLATFORM_PMIC_MNG_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/platform/pmic_mng.c b/drivers/misc/mediatek/connectivity/conninfra/platform/pmic_mng.c new file mode 100644 index 00000000000000..c528825d8bf02f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/platform/pmic_mng.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include "pmic_mng.h" + +#include "osal.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +P_CONSYS_PLATFORM_PMIC_OPS consys_platform_pmic_ops; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +P_CONSYS_PLATFORM_PMIC_OPS __weak get_consys_platform_pmic_ops(void) +{ + pr_err("No specify project\n"); + return NULL; +} + + +int pmic_mng_init(struct platform_device *pdev) +{ + if (consys_platform_pmic_ops == NULL) + consys_platform_pmic_ops = get_consys_platform_pmic_ops(); + + if (consys_platform_pmic_ops && consys_platform_pmic_ops->consys_pmic_get_from_dts) + consys_platform_pmic_ops->consys_pmic_get_from_dts(pdev); + + return 0; +} + +int pmic_mng_deinit(void) +{ + return 0; +} + +int pmic_mng_common_power_ctrl(unsigned int enable) +{ + int ret = 0; + if (consys_platform_pmic_ops && + consys_platform_pmic_ops->consys_pmic_common_power_ctrl) + ret = consys_platform_pmic_ops->consys_pmic_common_power_ctrl(enable); + return ret; +} + +int pmic_mng_wifi_power_ctrl(unsigned int enable) +{ + int ret = 0; + if (consys_platform_pmic_ops && + consys_platform_pmic_ops->consys_pmic_wifi_power_ctrl) + ret = consys_platform_pmic_ops->consys_pmic_wifi_power_ctrl(enable); + return ret; + +} + +int pmic_mng_bt_power_ctrl(unsigned int enable) +{ + int ret = 0; + if (consys_platform_pmic_ops && + consys_platform_pmic_ops->consys_pmic_bt_power_ctrl) + ret = consys_platform_pmic_ops->consys_pmic_bt_power_ctrl(enable); + return ret; +} + +int pmic_mng_gps_power_ctrl(unsigned int enable) +{ + int ret = 0; + if (consys_platform_pmic_ops && + consys_platform_pmic_ops->consys_pmic_gps_power_ctrl) + ret = consys_platform_pmic_ops->consys_pmic_gps_power_ctrl(enable); + return ret; +} + +int pmic_mng_fm_power_ctrl(unsigned int enable) +{ + int ret = 0; + if (consys_platform_pmic_ops && + consys_platform_pmic_ops->consys_pmic_fm_power_ctrl) + ret = consys_platform_pmic_ops->consys_pmic_fm_power_ctrl(enable); + return ret; +} + + + diff --git a/drivers/misc/mediatek/connectivity/conninfra/src/conninfra.c b/drivers/misc/mediatek/connectivity/conninfra/src/conninfra.c new file mode 100644 index 00000000000000..6e07297db1ce0f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/src/conninfra.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +//#include <linux/platform_device.h> +//#include <linux/cdev.h> +#include <linux/module.h> +#include <linux/fb.h> +#include <linux/workqueue.h> +#include <linux/delay.h> +#include "conninfra.h" +#include "emi_mng.h" +#include "conninfra_core.h" +#include "consys_hw.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +MODULE_DESCRIPTION("MediaTek Conninfra Driver"); + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +struct conninfra_rst_data { + struct work_struct rst_worker; + enum consys_drv_type drv; + char *reason; +}; + +struct conninfra_rst_data rst_data; + +void conninfra_get_phy_addr(unsigned int *addr, unsigned int *size) +{ + struct consys_emi_addr_info* addr_info = emi_mng_get_phy_addr(); + + if (!addr_info) { + pr_err("Get EMI info fail!"); + return; + } + + if (addr) + *addr = addr_info->emi_ap_phy_addr; + if (size) + *size = addr_info->emi_size; + return; +} + +EXPORT_SYMBOL_GPL(conninfra_get_phy_addr); + +int conninfra_pwr_on(enum consys_drv_type drv_type) +{ + return conninfra_core_power_on(drv_type); +} + +EXPORT_SYMBOL_GPL(conninfra_pwr_on); + +int conninfra_pwr_off(enum consys_drv_type drv_type) +{ + return conninfra_core_power_off(drv_type); +} + +EXPORT_SYMBOL_GPL(conninfra_pwr_off); + +static void conninfra_rst_handler(struct work_struct *work) +{ + int ret; + + pr_info("[%s] +++++++++++", __func__); + ret = conninfra_core_trg_chip_rst(rst_data.drv, rst_data.reason); + if (ret) + pr_err("[%s] trg_chip_rst fail [%d]", __func__, ret); + + osal_sleep_ms(1000); + + ret = conninfra_core_unlock_rst(); + if (ret) + pr_err("[%s] trg_chip_rst fail [%d]", __func__, ret); + pr_info("[%s] -----------", __func__); +} + +int conninfra_trigger_whole_chip_rst(enum consys_drv_type who, char *reason) +{ + /* use schedule worker to trigger ??? */ + /* so that function can be returned immediately */ + int r; + + r = conninfra_core_lock_rst(); + pr_info("[%s] rst lock [%d]", __func__, r); + if (r == 0) { + /* reset is ongoing */ + pr_warn("[%s] r=[%d]", __func__, r); + return 1; + } + + memset(&rst_data, 0, osal_sizeof(struct conninfra_rst_data)); + + pr_info("[%s] drv=[%d] reason=[%s]", __func__, who, reason); + rst_data.drv = who; + rst_data.reason = reason; + + INIT_WORK(&rst_data.rst_worker, conninfra_rst_handler); + schedule_work(&rst_data.rst_worker); + + return 0; +} +EXPORT_SYMBOL_GPL(conninfra_trigger_whole_chip_rst); + +int conninfra_sub_drv_ops_register(enum consys_drv_type type, + struct sub_drv_ops_cb *cb) +{ + /* type validation */ + if (type < 0 || type >= CONNDRV_TYPE_MAX) { + pr_err("[%s] incorrect drv type [%d]", __func__, type); + return -1; + } + pr_info("[%s] ----", __func__); + conninfra_core_subsys_ops_reg(type, cb); + return 0; +} + +EXPORT_SYMBOL_GPL(conninfra_sub_drv_ops_register); + +int conninfra_sub_drv_ops_unregister(enum consys_drv_type type) +{ + /* type validation */ + if (type < 0 || type >= CONNDRV_TYPE_MAX) { + pr_err("[%s] incorrect drv type [%d]", __func__, type); + return -1; + } + pr_info("[%s] ----", __func__); + conninfra_core_subsys_ops_unreg(type); + return 0; +} + +EXPORT_SYMBOL_GPL(conninfra_sub_drv_ops_unregister); diff --git a/drivers/misc/mediatek/connectivity/conninfra/src/conninfra_dev.c b/drivers/misc/mediatek/connectivity/conninfra/src/conninfra_dev.c new file mode 100644 index 00000000000000..497a88501f75e1 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/src/conninfra_dev.c @@ -0,0 +1,332 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include <linux/platform_device.h> +#include <linux/cdev.h> +#include <linux/module.h> +#include <linux/fb.h> +#include <linux/workqueue.h> +#include "conninfra.h" +#include "conninfra_core.h" +#include "conninfra_test.h" +#include "consys_hw.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define CONNINFRA_DEV_MAJOR 164 +//#define WMT_DETECT_MAJOR 154 +#define CONNINFRA_DEV_NUM 1 +#define CONNINFRA_DRVIER_NAME "conninfra_drv" +#define CONNINFRA_DEVICE_NAME "conninfra_dev" + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include <linux/delay.h> + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static int conninfra_dev_fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); + +static int conninfra_dev_open(struct inode *inode, struct file *file); +static int conninfra_dev_close(struct inode *inode, struct file *file); +static ssize_t conninfra_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos); +static ssize_t conninfra_dev_write(struct file *filp, + const char __user *buf, size_t count, + loff_t *f_pos); + +extern long wmt_detect_unlocked_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); +extern long WMT_compat_detect_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +MODULE_DESCRIPTION("MediaTek Conninfra Driver"); + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +struct class *pConninfraClass; +struct device *pConninfraDev; +static struct cdev gConninfraCdev; + +const struct file_operations gConninfraDevFops = { + .open = conninfra_dev_open, + .release = conninfra_dev_close, + .read = conninfra_dev_read, + .write = conninfra_dev_write, + .unlocked_ioctl = wmt_detect_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = WMT_compat_detect_ioctl, +#endif +}; + + + + +static int gConnInfraMajor = CONNINFRA_DEV_MAJOR; + +static struct notifier_block conninfra_fb_notifier; +static struct work_struct gPwrOnOffWork; +static atomic_t g_es_lr_flag_for_blank = ATOMIC_INIT(0); /* for ctrl blank flag */ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +int conninfra_dev_open(struct inode *inode, struct file *file) +{ + pr_info("open major %d minor %d (pid %d)\n", + imajor(inode), iminor(inode), current->pid); + + return 0; +} + +int conninfra_dev_close(struct inode *inode, struct file *file) +{ + pr_info("close major %d minor %d (pid %d)\n", + imajor(inode), iminor(inode), current->pid); + + return 0; +} + +ssize_t conninfra_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + return 0; +} + +ssize_t conninfra_dev_write(struct file *filp, + const char __user *buf, size_t count, loff_t *f_pos) +{ + return 0; +} +static int conninfra_dev_get_blank_state(void) +{ + return atomic_read(&g_es_lr_flag_for_blank); +} + +int conninfra_dev_fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int blank; + + pr_debug("conninfra_dev_fb_notifier_callback\n"); + + /* If we aren't interested in this event, skip it immediately ... */ + if (event != FB_EVENT_BLANK) + return 0; + + blank = *(int *)evdata->data; + pr_info("fb_notify(blank=%d)\n", blank); + + switch (blank) { + case FB_BLANK_UNBLANK: + atomic_set(&g_es_lr_flag_for_blank, 1); + pr_info("@@@@@@@@@@ Conninfra enter UNBLANK @@@@@@@@@@@@@@\n"); + schedule_work(&gPwrOnOffWork); + break; + case FB_BLANK_POWERDOWN: + atomic_set(&g_es_lr_flag_for_blank, 0); + pr_info("@@@@@@@@@@ Conninfra enter early POWERDOWN @@@@@@@@@@@@@@\n"); + schedule_work(&gPwrOnOffWork); + break; + default: + break; + } + return 0; +} + +static void conninfra_dev_pwr_on_off_handler(struct work_struct *work) +{ + pr_debug("conninfra_dev_pwr_on_off_handler start to run\n"); + + /* Update blank off status before wmt power off */ + /*if (conninfra_dev_get_blank_state() == 0) { + } + */ + + /* Update blank on status after wmt power on */ + if (conninfra_dev_get_blank_state() == 1) { + //wmt_dev_blank_handler(); + //connsys_log_blank_state_changed(1); + } +} + +/************************************************************************/ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-extra-args" +static int conninfra_dev_init(void) +{ + dev_t devID = MKDEV(gConnInfraMajor, 0); + int cdevErr = -1; + int iret = 0; + + iret = register_chrdev_region(devID, CONNINFRA_DEV_NUM, + CONNINFRA_DRVIER_NAME); + if (iret) { + pr_err("fail to register chrdev\n"); + return -1; + } + + cdev_init(&gConninfraCdev, &gConninfraDevFops); + gConninfraCdev.owner = THIS_MODULE; + + cdevErr = cdev_add(&gConninfraCdev, devID, CONNINFRA_DEV_NUM); + if (cdevErr) { + pr_err("cdev_add() fails (%d)\n", cdevErr); + goto err1; + } + + pConninfraClass = class_create(/*THIS_MODULE,*/ CONNINFRA_DEVICE_NAME); + if (IS_ERR(pConninfraClass)) { + pr_err("class create fail, error code(%ld)\n", + PTR_ERR(pConninfraClass)); + goto err1; + } + + pConninfraDev = device_create(pConninfraClass, NULL, devID, + NULL, CONNINFRA_DEVICE_NAME); + if (IS_ERR(pConninfraDev)) { + pr_err("device create fail, error code(%ld)\n", + PTR_ERR(pConninfraDev)); + goto err2; + } + + /* init power on off handler */ + INIT_WORK(&gPwrOnOffWork, conninfra_dev_pwr_on_off_handler); + conninfra_fb_notifier.notifier_call + = conninfra_dev_fb_notifier_callback; + iret = fb_register_client(&conninfra_fb_notifier); + if (iret) { + pr_err("register fb_notifier fail"); + return -3; + } else + pr_info("register fb_notifier success"); + + iret = conninfra_test_setup(); + if (iret) + pr_err("init conninfra_test fail\n", iret); + + iret = consys_hw_init(); + if (iret) { + pr_err("init consys_hw fail\n", iret); + return -4; + } + + iret = conninfra_core_init(); + if (iret) { + pr_err("conninfra init fail"); + return -5; + } + + + pr_info("ConnInfra Dev: init (%d)\n", iret); + return 0; + +err2: + + pr_err("[conninfra_dev_init] err2"); + if (pConninfraClass) { + class_destroy(pConninfraClass); + pConninfraClass = NULL; + } +err1: + pr_err("[conninfra_dev_init] err1"); + if (cdevErr == 0) + cdev_del(&gConninfraCdev); + + if (iret == 0) { + unregister_chrdev_region(devID, CONNINFRA_DEV_NUM); + gConnInfraMajor = -1; + } + + return -2; +} +#pragma GCC diagnostic pop + +static void conninfra_dev_deinit(void) +{ + dev_t dev = MKDEV(gConnInfraMajor, 0); + int iret = 0; + + fb_unregister_client(&conninfra_fb_notifier); + + iret = conninfra_test_remove(); + + iret = conninfra_core_deinit(); + + iret = consys_hw_deinit(); + + if (pConninfraDev) { + device_destroy(pConninfraClass, dev); + pConninfraDev = NULL; + } + + if (pConninfraClass) { + class_destroy(pConninfraClass); + pConninfraClass = NULL; + } + + cdev_del(&gConninfraCdev); + unregister_chrdev_region(dev, CONNINFRA_DEV_NUM); + + pr_info("ConnInfra: ALPS platform init (%d)\n", iret); +} + +module_init(conninfra_dev_init); +module_exit(conninfra_dev_deinit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Willy.Yu @ CTD/SE5/CS5"); + +module_param(gConnInfraMajor, uint, 0644); + diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/cal_test.c b/drivers/misc/mediatek/connectivity/conninfra/test/cal_test.c new file mode 100644 index 00000000000000..b0f2818105a481 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/cal_test.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include <linux/slab.h> +#include <linux/gfp.h> +#include <linux/mm.h> +#include "conninfra.h" +#include "conninfra_core.h" +#include "osal.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +int pre_cal_power_on_handler(void); +int pre_cal_do_cal_handler(void); +int calibration_test(void); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +int pre_cal_power_on_handler(void) +{ + pr_info("[%s] ===========", __func__); + osal_sleep_ms(100); + return 0; +} + +int pre_cal_do_cal_handler(void) +{ + pr_info("[%s] ===========", __func__); + return 0; +} + + +struct sub_drv_ops_cb g_cal_drv_ops_cb; + +int calibration_test(void) +{ + int ret; + + memset(&g_cal_drv_ops_cb, 0, sizeof(struct sub_drv_ops_cb)); + + g_cal_drv_ops_cb.pre_cal_cb.pwr_on_cb = pre_cal_power_on_handler; + g_cal_drv_ops_cb.pre_cal_cb.do_cal_cb = pre_cal_do_cal_handler; + + + pr_info("[%s] cb init [%p][%p]", __func__, + g_cal_drv_ops_cb.pre_cal_cb.pwr_on_cb, + g_cal_drv_ops_cb.pre_cal_cb.do_cal_cb); + + conninfra_sub_drv_ops_register(CONNDRV_TYPE_BT, &g_cal_drv_ops_cb); + conninfra_sub_drv_ops_register(CONNDRV_TYPE_WIFI, &g_cal_drv_ops_cb); + + ret = conninfra_core_pre_cal_start(); + if (ret) + pr_warn("[%s] fail [%d]", __func__, ret); + +#if 0 + pr_info("[%s] ++++++++++++++++++++++", __func__); + ret = trigger_whole_chip_rst(CONNDRV_TYPE_BT, "test reset"); + if (ret) + pr_warn("[%s] fail [%d]", __func__, ret); + osal_sleep_ms(10); + + pr_info("[%s]>>>>>>>", __func__); + ret = trigger_whole_chip_rst(CONNDRV_TYPE_BT, "test reset"); + if (ret) + pr_warn("[%s] fail [%d]", __func__, ret); + pr_info("[%s] ---------------------", __func__); +#endif + osal_sleep_ms(1000); + + conninfra_sub_drv_ops_unregister(CONNDRV_TYPE_BT); + conninfra_sub_drv_ops_unregister(CONNDRV_TYPE_WIFI); + pr_info("[%s] finish.", __func__); + return 0; +} + + diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/chip_rst_test.c b/drivers/misc/mediatek/connectivity/conninfra/test/chip_rst_test.c new file mode 100644 index 00000000000000..829c9db079ebf0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/chip_rst_test.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include <linux/slab.h> +#include <linux/gfp.h> +#include <linux/mm.h> +#include "conninfra.h" +#include "osal.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +int pre_chip_rst_handler(void); +int post_chip_rst_handler(void); +int chip_rst_test(void); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +int pre_chip_rst_handler(void) +{ + pr_info("[%s] ===========", __func__); + osal_sleep_ms(100); + return 0; +} + +int post_chip_rst_handler(void) +{ + pr_info("[%s] ===========", __func__); + return 0; +} + + +struct sub_drv_ops_cb g_drv_ops_cb; + +int chip_rst_test(void) +{ + int ret; + + memset(&g_drv_ops_cb, 0, sizeof(struct sub_drv_ops_cb)); + + g_drv_ops_cb.rst_cb.pre_whole_chip_rst = pre_chip_rst_handler; + g_drv_ops_cb.rst_cb.post_whole_chip_rst = post_chip_rst_handler; + + pr_info("[%s] cb init [%p][%p]", __func__, + g_drv_ops_cb.rst_cb.pre_whole_chip_rst, + g_drv_ops_cb.rst_cb.post_whole_chip_rst); + + conninfra_sub_drv_ops_register(CONNDRV_TYPE_BT, &g_drv_ops_cb); + conninfra_sub_drv_ops_register(CONNDRV_TYPE_WIFI, &g_drv_ops_cb); + + + pr_info("[%s] ++++++++++++++++++++++", __func__); + ret = conninfra_trigger_whole_chip_rst(CONNDRV_TYPE_BT, "test reset"); + if (ret) + pr_warn("[%s] fail [%d]", __func__, ret); + else + pr_info("Trigger chip reset success. Test pass."); + osal_sleep_ms(10); + + pr_info("Try to trigger whole chip reset when reset is ongoing. It should be fail."); + ret = conninfra_trigger_whole_chip_rst(CONNDRV_TYPE_BT, "test reset"); + pr_info("Test %s. ret = %d.", ret == 1? "pass": "fail", ret); + + osal_sleep_ms(1000); + + conninfra_sub_drv_ops_unregister(CONNDRV_TYPE_BT); + conninfra_sub_drv_ops_unregister(CONNDRV_TYPE_WIFI); + pr_info("chip_rst_test finish"); + return 0; +} + + diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/conf_test.c b/drivers/misc/mediatek/connectivity/conninfra/test/conf_test.c new file mode 100644 index 00000000000000..5c9277e3502c77 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/conf_test.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include "conninfra_conf.h" +#include "conf_test.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + +int conninfra_conf_test(void) +{ + int ret; + const struct conninfra_conf *conf; + +#if 0 + ret = conninfra_conf_set_cfg_file("WMT_SOC.cfg"); + if (ret) { + pr_err("set cfg file fail [%d]", ret); + return -1; + } +#endif + + ret = conninfra_conf_init(); + if (ret) { + pr_err("int conf fail [%d]", ret); + return -1; + } + + conf = conninfra_conf_get_cfg(); + if (NULL == conf) { + pr_err("int conf fail [%d]", ret); + return -1; + } + if (conf->co_clock_flag != 1) { + pr_err("test co_clock_flag fail [%d]", conf->co_clock_flag); + return -1; + } + + pr_info("[%s] test PASS\n", __func__); + return 0; +} + + diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/conninfra_core_test.c b/drivers/misc/mediatek/connectivity/conninfra/test/conninfra_core_test.c new file mode 100644 index 00000000000000..3f4e039cf79e85 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/conninfra_core_test.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/proc_fs.h> +#include "conninfra_core_test.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/conninfra_test.c b/drivers/misc/mediatek/connectivity/conninfra/test/conninfra_test.c new file mode 100644 index 00000000000000..ca77f6e4365ca7 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/conninfra_test.c @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) "conninfra_test@(%s:%d) " fmt, __func__, __LINE__ + +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/proc_fs.h> +#include "conninfra_test.h" +#include "osal.h" + +#include "conninfra.h" +#include "conninfra_core.h" +#include "conf_test.h" +#include "cal_test.h" +#include "msg_evt_test.h" +#include "chip_rst_test.h" +#include "mailbox_test.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define CONNINFRA_TEST_PROCNAME "driver/conninfra_test" + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static ssize_t conninfra_test_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); +static ssize_t conninfra_test_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); + +static int core_tc(int par1, int par2, int par3); +static int conf_tc(int par1, int par2, int par3); +static int cal_tc(int par1, int par2, int par3); +static int msg_evt_tc(int par1, int par2, int par3); +static int chip_rst_tc(int par1, int par2, int par3); +static int mailbox_tc(int par1, int par2, int par3); +static int emi_tc(int par1, int par2, int par3); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +static struct proc_dir_entry *gConninfraTestEntry; + +static const CONNINFRA_TEST_FUNC conninfra_test_func[] = { + [0x01] = core_tc, + [0x02] = conf_tc, + [0x03] = msg_evt_tc, + [0x04] = chip_rst_tc, + [0x05] = cal_tc, + [0x06] = mailbox_tc, + [0x07] = emi_tc, +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +int core_tc_pwr_on() +{ + int iret = 0; + + pr_info("Power on test start"); + iret = conninfra_core_power_on(CONNDRV_TYPE_BT); + pr_info("BT power on %s (result = %d)", iret? "fail" : "pass", iret); + osal_sleep_ms(100); + iret = conninfra_core_power_on(CONNDRV_TYPE_FM); + pr_info("FM power on %s (result = %d)", iret? "fail" : "pass", iret); + osal_sleep_ms(100); + iret = conninfra_core_power_on(CONNDRV_TYPE_GPS); + pr_info("GPS power on %s (result = %d)", iret? "fail" : "pass", iret); + osal_sleep_ms(100); + iret = conninfra_core_power_on(CONNDRV_TYPE_WIFI); + pr_info("Wi-Fi power on %s (result = %d)", iret? "fail" : "pass", iret); + osal_sleep_ms(200); + + return iret; +} + +int core_tc_pwr_off() +{ + int iret = 0; + + iret = conninfra_core_power_off(CONNDRV_TYPE_WIFI); + pr_info("Wi-Fi power off %s (result = %d)", iret? "fail" : "pass", iret); + osal_sleep_ms(100); + iret = conninfra_core_power_off(CONNDRV_TYPE_GPS); + pr_info("GPS power off %s (result = %d)", iret? "fail" : "pass", iret); + osal_sleep_ms(100); + iret = conninfra_core_power_off(CONNDRV_TYPE_BT); + pr_info("BT power off %s (result = %d)", iret? "fail" : "pass", iret); + osal_sleep_ms(100); + iret = conninfra_core_power_off(CONNDRV_TYPE_FM); + pr_info("FM power off %s (result = %d)", iret? "fail" : "pass", iret); + + return iret; +} +#pragma GCC diagnostic pop + +int core_tc(int par1, int par2, int par3) +{ + int iret = 0; + + if (par2 == 0) { + iret = core_tc_pwr_on(); + iret = core_tc_pwr_off(); + } else if (par2 == 1) { + iret = core_tc_pwr_on(); + } else if (par2 == 2) { + iret = core_tc_pwr_off(); + } + //pr_info("core_tc %s (result = %d)", iret? "fail" : "pass", iret); + return 0; +} + +static int conf_tc(int par1, int par2, int par3) +{ + return conninfra_conf_test(); +} + +static int msg_evt_tc(int par1, int par2, int par3) +{ + return msg_evt_test(); +} + +static int chip_rst_tc(int par1, int par2, int par3) +{ + pr_info("test start"); + return chip_rst_test(); +} + +static int cal_tc(int par1, int par2, int par3) +{ + pr_info("test start"); + return calibration_test(); +} + + +static int mailbox_tc(int par1, int par2, int par3) +{ + return mailbox_test(); +} + +static int emi_tc(int par1, int par2, int par3) +{ + unsigned int addr = 0; + unsigned int size = 0; + int ret = 0; + + pr_info("[%s] start", __func__); + conninfra_get_phy_addr(&addr, &size); + if (addr == 0 || size == 0) { + pr_err("[%s] fail! addr=[0x%x] size=[%u]", __func__, addr, size); + ret = -1; + } else + pr_info("[%s] pass. addr=[0x%x] size=[%u]", __func__, addr, size); + + pr_info("[%s] end", __func__); + + return ret; +} + +ssize_t conninfra_test_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + return 0; +} + +ssize_t conninfra_test_write(struct file *filp, const char __user *buffer, size_t count, loff_t *f_pos) +{ + size_t len = count; + char buf[256]; + char *pBuf; + char *pDelimiter = " \t"; + int x = 0, y = 0, z = 0; + char *pToken = NULL; + long res; + //static bool testEnabled; + + pr_info("write parameter len = %d\n\r", (int) len); + if (len >= osal_sizeof(buf)) { + pr_err("input handling fail!\n"); + len = osal_sizeof(buf) - 1; + return -1; + } + + if (copy_from_user(buf, buffer, len)) + return -EFAULT; + + buf[len] = '\0'; + pr_info("write parameter data = %s\n\r", buf); + + pBuf = buf; + pToken = osal_strsep(&pBuf, pDelimiter); + if (pToken != NULL) { + osal_strtol(pToken, 16, &res); + x = (int)res; + } else { + x = 0; + } + + pToken = osal_strsep(&pBuf, "\t\n "); + if (pToken != NULL) { + osal_strtol(pToken, 16, &res); + y = (int)res; + pr_info("y = 0x%08x\n\r", y); + } else { + y = 3000; + /*efuse, register read write default value */ + if (0x11 == x || 0x12 == x || 0x13 == x) + y = 0x80000000; + } + + pToken = osal_strsep(&pBuf, "\t\n "); + if (pToken != NULL) { + osal_strtol(pToken, 16, &res); + z = (int)res; + } else { + z = 10; + /*efuse, register read write default value */ + if (0x11 == x || 0x12 == x || 0x13 == x) + z = 0xffffffff; + } + + pr_info("x(0x%08x), y(0x%08x), z(0x%08x)\n\r", x, y, z); + + /* For eng and userdebug load, have to enable wmt_dbg by + * writing 0xDB9DB9 to * "/proc/driver/wmt_dbg" to avoid + * some malicious use + */ +#if 0 + if (x == 0xDB9DB9) { + dbgEnabled = 1; + return len; + } +#endif + + if (osal_array_size(conninfra_test_func) > x && + NULL != conninfra_test_func[x]) + (*conninfra_test_func[x]) (x, y, z); + else + pr_warn("no handler defined for command id(0x%08x)\n\r", x); + + return len; + +} + + +int conninfra_test_setup(void) +{ + static const struct proc_ops conninfra_test_fops = { + .proc_read = conninfra_test_read, + .proc_write = conninfra_test_write, + }; + int i_ret = 0; + + gConninfraTestEntry = proc_create(CONNINFRA_TEST_PROCNAME, + 0664, NULL, &conninfra_test_fops); + if (gConninfraTestEntry == NULL) { + pr_err("Unable to create / wmt_aee proc entry\n\r"); + i_ret = -1; + } + + return i_ret; +} + +int conninfra_test_remove(void) +{ + if (gConninfraTestEntry != NULL) + proc_remove(gConninfraTestEntry); + return 0; +} + diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/include/cal_test.h b/drivers/misc/mediatek/connectivity/conninfra/test/include/cal_test.h new file mode 100644 index 00000000000000..da917cae2e6dbb --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/include/cal_test.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _CAL_TEST_H_ +#define _CAL_TEST_H_ + +#include "osal.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +int calibration_test(void); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _CAL_TEST_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/include/chip_rst_test.h b/drivers/misc/mediatek/connectivity/conninfra/test/include/chip_rst_test.h new file mode 100644 index 00000000000000..b9b413a568b0c4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/include/chip_rst_test.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _CHIP_RST_TEST_H_ +#define _CHIP_RST_TEST_H_ + +#include "osal.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +int chip_rst_test(void); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _CHIP_RST_TEST_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/include/conf_test.h b/drivers/misc/mediatek/connectivity/conninfra/test/include/conf_test.h new file mode 100644 index 00000000000000..a5aa7bd4a02ff0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/include/conf_test.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _CONF_TEST_H_ +#define _CONF_TEST_H_ + +#include "osal.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +int conninfra_conf_test(void); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _CONF_TEST_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/include/conninfra_core_test.h b/drivers/misc/mediatek/connectivity/conninfra/test/include/conninfra_core_test.h new file mode 100644 index 00000000000000..fcc964ad032b67 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/include/conninfra_core_test.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _CONNINFRA_CORE_TEST_H_ +#define _CONNINFRA_CORE_TEST_H_ + +#include "osal.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +#define WMT_FUNC_CTRL_ON (MTK_WCN_BOOL_TRUE) +#define WMT_FUNC_CTRL_OFF (MTK_WCN_BOOL_FALSE) + +#define INIT_CMD(c, e, s) {.cmd = c, .cmdSz = sizeof(c), .evt = e, .evtSz = sizeof(e), .str = s} + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _CONNINFRA_CORE_TEST_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/include/conninfra_test.h b/drivers/misc/mediatek/connectivity/conninfra/test/include/conninfra_test.h new file mode 100644 index 00000000000000..4710e670b82d59 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/include/conninfra_test.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _CONNINFRA_TEST_H_ +#define _CONNINFRA_TEST_H_ + +#include "osal.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +#define INIT_CMD(c, e, s) {.cmd = c, .cmdSz = sizeof(c), .evt = e, .evtSz = sizeof(e), .str = s} + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +typedef int(*CONNINFRA_TEST_FUNC) (int par1, int par2, int par3); + +int conninfra_test_setup(void); +int conninfra_test_remove(void); + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _CONNINFRA_CORE_TEST_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/include/mailbox_test.h b/drivers/misc/mediatek/connectivity/conninfra/test/include/mailbox_test.h new file mode 100644 index 00000000000000..99353524c73313 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/include/mailbox_test.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MAILBOX_TEST_H_ +#define _MAILBOX_TEST_H_ + +#include "osal.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +int mailbox_test(void); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MAILBOX_TEST_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/include/msg_evt_test.h b/drivers/misc/mediatek/connectivity/conninfra/test/include/msg_evt_test.h new file mode 100644 index 00000000000000..617c6579790f84 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/include/msg_evt_test.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MSG_EVT_TEST_H_ +#define _MSG_EVT_TEST_H_ + +#include "osal.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +int msg_evt_test(void); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MSG_EVT_TEST_H_ */ diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/mailbox_test.c b/drivers/misc/mediatek/connectivity/conninfra/test/mailbox_test.c new file mode 100644 index 00000000000000..f9c44cf7902aa3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/mailbox_test.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/proc_fs.h> +#include <linux/slab.h> +#include <linux/mailbox_client.h> +#include "consys_hw.h" +#include "conninfra_core_test.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +int mailbox_test(void); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +struct demo_client { + struct mbox_client cl; + struct mbox_chan *mbox; + struct completion c; + bool async; +}; + + +static void message_from_remote(struct mbox_client *cl, void *msg) +{ + struct demo_client *dc = container_of(cl, struct demo_client, cl); + if (dc->async) { + pr_info("AAAAsync"); + } else { + pr_info("SSSSSSSync"); + } +} + +static void sample_sent(struct mbox_client *cl, void *msg, int r) +{ + struct demo_client *dc = container_of(cl, struct demo_client, cl); + complete(&dc->c); +} + +int mailbox_test(void) +{ + struct demo_client *dc_sync; + struct platform_device *pdev = get_consys_device(); + + dc_sync = kzalloc(sizeof(*dc_sync), GFP_KERNEL); + dc_sync->cl.dev = &pdev->dev; + dc_sync->cl.rx_callback = message_from_remote; + dc_sync->cl.tx_done = sample_sent; + dc_sync->cl.tx_block = true; + dc_sync->cl.tx_tout = 500; + dc_sync->cl.knows_txdone = false; + dc_sync->async = false; + + dc_sync->mbox = mbox_request_channel(&dc_sync->cl, 0); + + if (IS_ERR(dc_sync->mbox)) { + pr_err("request channel fail [%p]", dc_sync->mbox); + return -1; + } + mbox_send_message(dc_sync->mbox, 0); + + wait_for_completion(&dc_sync->c); + + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/conninfra/test/msg_evt_test.c b/drivers/misc/mediatek/connectivity/conninfra/test/msg_evt_test.c new file mode 100644 index 00000000000000..6efd310a3362ec --- /dev/null +++ b/drivers/misc/mediatek/connectivity/conninfra/test/msg_evt_test.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) "msg_evt_test@(%s:%d) " fmt, __func__, __LINE__ + +#include <linux/slab.h> +#include <linux/gfp.h> +#include <linux/mm.h> +#include "msg_thread.h" +#include "msg_evt_test.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +struct work_struct rst_worker; +struct msg_thread_ctx g_ctx; + +typedef enum { + INFRA_TEST_OPID_1 = 0, + INFRA_TEST_OPID_2 = 1, + INFRA_TEST_OPID_MAX +} test_opid; + + +static int opfunc_test_1(struct msg_op_data *op); +static int opfunc_test_2(struct msg_op_data *op); + +static const msg_opid_func test_op_func[] = { + [INFRA_TEST_OPID_1] = opfunc_test_1, + [INFRA_TEST_OPID_2] = opfunc_test_2, +}; + +int opfunc_test_1(struct msg_op_data *op) +{ + pr_info("[%s]", __func__); + return 0; +} + +int opfunc_test_2(struct msg_op_data *op) +{ + unsigned int drv_type = op->op_data[0]; + + pr_info("[%s] param=[%d]", __func__, drv_type); + return 0; +} + + +static void msg_thrd_handler(struct work_struct *work) +{ + msg_thread_send_1(&g_ctx, INFRA_TEST_OPID_2, 2011); + osal_sleep_ms(5); + msg_thread_send_wait_1(&g_ctx, INFRA_TEST_OPID_2, 0, 2022); + msg_thread_send_wait_1(&g_ctx, INFRA_TEST_OPID_2, 0, 2033); +} + +int msg_evt_test(void) +{ + int ret; + + INIT_WORK(&rst_worker, msg_thrd_handler); + + ret = msg_thread_init(&g_ctx, "TestThread", + test_op_func, INFRA_TEST_OPID_MAX); + if (ret) { + pr_err("inti msg_thread fail ret=[%d]\n", ret); + return -2; + } + + schedule_work(&rst_worker); + + msg_thread_send_wait_1(&g_ctx, INFRA_TEST_OPID_2, 0, 1011); + //osal_sleep_ms(10); + msg_thread_send_1(&g_ctx, INFRA_TEST_OPID_2, 1022); + osal_sleep_ms(10); + msg_thread_send_wait_1(&g_ctx, INFRA_TEST_OPID_2, 0, 1033); + + osal_sleep_ms(1000); + + pr_info("<<<<<>>>>>>> freeOpq=[%u][%u] ActiveQ=[%u][%u]", + g_ctx.free_op_q.write, g_ctx.free_op_q.read, + g_ctx.active_op_q.write, g_ctx.active_op_q.read); + osal_sleep_ms(500); + + ret = msg_thread_deinit(&g_ctx); + pr_info("[%s] msg_thread_deinit\n", __func__); + + pr_info("[%s] test PASS\n", __func__); + return 0; +} + + diff --git a/drivers/misc/mediatek/connectivity/fmradio/Android.mk b/drivers/misc/mediatek/connectivity/fmradio/Android.mk new file mode 100644 index 00000000000000..00367f4b66e925 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/Android.mk @@ -0,0 +1,28 @@ +LOCAL_PATH := $(call my-dir) + +ifeq ($(MTK_FM_SUPPORT),yes) + +include $(CLEAR_VARS) +LOCAL_MODULE := fmradio_drv.ko +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_OWNER := mtk +LOCAL_INIT_RC := init.fmradio_drv.rc +ifeq ($(BUILD_CONNAC2), true) +LOCAL_REQUIRED_MODULES := conninfra.ko +else +LOCAL_REQUIRED_MODULES := wmt_drv.ko +endif + +ifeq ($(TARGET_BUILD_VARIANT),user) +FM_OPTS := CONFIG_FM_USER_LOAD=1 +else +FM_OPTS := +endif + +FM_OPTS += CFG_BUILD_CONNAC2=$(BUILD_CONNAC2) CFG_FM_CHIP_ID=$(FM_CHIP_ID) + +include $(MTK_KERNEL_MODULE) + +$(linked_module): OPTS += $(FM_OPTS) + +endif diff --git a/drivers/misc/mediatek/connectivity/fmradio/Makefile b/drivers/misc/mediatek/connectivity/fmradio/Makefile new file mode 100644 index 00000000000000..246e5feb1c27aa --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/Makefile @@ -0,0 +1,134 @@ +# +# Copyright (C) 2015 MediaTek Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +############################################################################### +# Necessary Check + +ifeq ($(AUTOCONF_H),) + $(error AUTOCONF_H is not defined) +endif + +ccflags-y += -imacros $(AUTOCONF_H) + +# Force build fail on modpost warning +KBUILD_MODPOST_FAIL_ON_WARNINGS := y +############################################################################### + +# only WMT align this design flow +#ccflags-y += -D MTK_WCN_REMOVE_KERNEL_MODULE + +ifeq ($(CONFIG_ARM64), y) + ccflags-y += -D CONFIG_MTK_WCN_ARM64 +endif + +ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y) + ccflags-y += -D WMT_IDC_SUPPORT=1 +else + ccflags-y += -D WMT_IDC_SUPPORT=0 +endif +ccflags-y += -D MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT + +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include + +ifeq ($(CONFIG_FM_USER_LOAD),1) + ccflags-y += -D CONFIG_MTK_USER_BUILD +endif + +# Makefile generated by Mediatek +# fm support + +ifeq ($(CONFIG_MTK_FMRADIO), y) + +ifeq ($(CONFIG_MTK_FM_CHIP),) + $(error CONFIG_MTK_FM_CHIP not defined) +endif + +ifneq ($(CFG_FM_CHIP_ID),) + ccflags-y += -D CFG_FM_CHIP_ID=0x$(CFG_FM_CHIP_ID) +endif + + MODULE_NAME := fmradio_drv + obj-m += $(MODULE_NAME).o + + FM_CHIP_MACRO := $(subst ",,$(CONFIG_MTK_FM_CHIP)) + FM_CHIP := $(subst _FM,,$(subst MT,mt,$(subst ",,$(CONFIG_MTK_FM_CHIP)))) + +ifeq ($(FM_CHIP), mt6625) + FM_CHIP_MACRO := MT6627_FM + FM_CHIP := mt6627 + ccflags-y += -DMT6625_FM +endif + +ifeq ($(FM_CHIP), mt6580) + FM_CHIP_MACRO := soc + FM_CHIP := soc + ccflags-y += -Dsoc +endif + +ifeq ($(FM_CHIP), mt0633) + FM_CHIP_MACRO := soc + FM_CHIP := soc + ccflags-y += -Dsoc +endif + +ifeq ($(FM_CHIP), mt6631) + ccflags-y += -DMT6631_FM +endif + +ifeq ($(FM_CHIP), mt6635) + ccflags-y += -DMT6635_FM +endif + + FM_CHIP_PATH := $(FM_CHIP)/pub/$(FM_CHIP) + ccflags-y += -D$(FM_CHIP_MACRO) + ccflags-y += -I$(src)/inc \ + -I$(src)/chips/$(FM_CHIP)/inc \ + -I$(src)/plat/inc + + $(FM_CHIP)-objs := core/fm_module.o \ + core/fm_main.o \ + core/fm_config.o \ + core/fm_rds_parser.o \ + core/fm_patch.o \ + core/fm_utils.o \ + core/fm_link.o \ + core/fm_eint.o \ + core/fm_cmd.o \ + core/fm_reg_utils.o \ + chips/$(FM_CHIP_PATH)_fm_rds.o + +ifeq ($(CFG_BUILD_CONNAC2), true) + CONNINFRA_SRC_FOLDER := $(TOP)/vendor/mediatek/kernel_modules/connectivity/conninfra + + ccflags-y += -I$(CONNINFRA_SRC_FOLDER)/include + ccflags-y += -DCFG_FM_CONNAC2=1 + $(FM_CHIP)-objs += chips/$(FM_CHIP_PATH)_2_fm_lib.o + $(FM_CHIP)-objs += plat/conn_infra.o +else + WMT_SRC_FOLDER := $(TOP)/vendor/mediatek/kernel_modules/connectivity/common + WMT_INCLUDE_PATH := common_main + + ccflags-y += -I$(WMT_SRC_FOLDER)/$(WMT_INCLUDE_PATH)/include \ + -I$(WMT_SRC_FOLDER)/$(WMT_INCLUDE_PATH)/linux/include + ccflags-y += -DCFG_FM_CONNAC2=0 + $(FM_CHIP)-objs += chips/$(FM_CHIP_PATH)_fm_lib.o + $(FM_CHIP)-objs += plat/legacy_wmt.o +endif + + $(MODULE_NAME)-objs += $($(FM_CHIP)-objs) + #obj-$(CONFIG_MTK_FMRADIO) += private/ +endif + +obj-y += dummy.o diff --git a/drivers/misc/mediatek/connectivity/fmradio/README b/drivers/misc/mediatek/connectivity/fmradio/README new file mode 100644 index 00000000000000..d8eef677c95ca6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/README @@ -0,0 +1,2 @@ +FM Radio driver - kernel modules move out of kernel tree + diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/inc/mt6627_drv_dsp.h b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/inc/mt6627_drv_dsp.h new file mode 100644 index 00000000000000..957a869719bc3b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/inc/mt6627_drv_dsp.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +const unsigned char channel_parameter[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 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, 2, 0, 0, 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, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 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, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0 +}; diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/inc/mt6627_fm_lib.h b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/inc/mt6627_fm_lib.h new file mode 100644 index 00000000000000..f62c130f8b1a2e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/inc/mt6627_fm_lib.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT6627_FM_LIB_H__ +#define __MT6627_FM_LIB_H__ + +#include "fm_typedef.h" + +enum { + DSPPATCH = 0xFFF9, + USDELAY = 0xFFFA, + MSDELAY = 0xFFFB, + HW_VER = 0xFFFD, + POLL_N = 0xFFFE, /* poling check if bit(n) is '0' */ + POLL_P = 0xFFFF, /* polling check if bit(n) is '1' */ +}; + +enum { + FM_PUS_DSPPATCH = DSPPATCH, + FM_PUS_USDELAY = USDELAY, + FM_PUS_MSDELAY = MSDELAY, + FM_PUS_HW_VER = HW_VER, + FM_PUS_POLL_N = POLL_N, /* poling check if bit(n) is '0' */ + FM_PUS_POLL_P = POLL_P, /* polling check if bit(n) is '1' */ + FM_PUS_MAX +}; + +enum { + mt6627_E1 = 0, + mt6627_E2 +}; + +struct mt6627_fm_cqi { + unsigned short ch; + unsigned short rssi; + unsigned short reserve; +}; + +struct adapt_fm_cqi { + signed int ch; + signed int rssi; + signed int reserve; +}; + +struct mt6627_full_cqi { + unsigned short ch; + unsigned short rssi; + unsigned short pamd; + unsigned short pr; + unsigned short fpamd; + unsigned short mr; + unsigned short atdc; + unsigned short prx; + unsigned short atdev; + unsigned short smg; /* soft-mute gain */ + unsigned short drssi; /* delta rssi */ +}; + +#endif diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/inc/mt6627_fm_reg.h b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/inc/mt6627_fm_reg.h new file mode 100644 index 00000000000000..ba7a71d8565bf6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/inc/mt6627_fm_reg.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT6627_FM_REG_H__ +#define __MT6627_FM_REG_H__ + +/* RDS_BDGRP_ABD_CTRL_REG */ +enum { + BDGRP_ABD_EN = 0x0001, + BER_RUN = 0x2000 +}; +#define FM_DAC_CON1 0x83 +#define FM_DAC_CON2 0x84 +#define FM_FT_CON0 0x86 +enum { + FT_EN = 0x0001 +}; + +#define FM_I2S_CON0 0x90 +enum { + I2S_EN = 0x0001, + FORMAT = 0x0002, + WLEN = 0x0004, + I2S_SRC = 0x0008 +}; + +/* FM_MAIN_CTRL */ +enum { + TUNE = 0x0001, + SEEK = 0x0002, + SCAN = 0x0004, + CQI_READ = 0x0008, + RDS_MASK = 0x0010, + MUTE = 0x0020, + RDS_BRST = 0x0040, + RAMP_DOWN = 0x0100, +}; + +enum { + ANTENNA_TYPE = 0x0010, /* 0x61 D4, 0:long, 1:short */ + ANALOG_I2S = 0x0080, /* 0x61 D7, 0:lineout, 1:I2S */ + DE_EMPHASIS = 0x1000, /* 0x61 D12,0:50us, 1:75 us */ +}; + +#define OSC_FREQ_BITS 0x0070 /* 0x60 bit4~6 */ +#define OSC_FREQ_MASK (~OSC_FREQ_BITS) + +#endif /* __MT6627_FM_REG_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/pub/mt6627_fm_lib.c b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/pub/mt6627_fm_lib.c new file mode 100644 index 00000000000000..3234f63e1f9771 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/pub/mt6627_fm_lib.c @@ -0,0 +1,1843 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/slab.h> +#include <linux/vmalloc.h> + +#include "osal_typedef.h" +#include "stp_exp.h" +#include "wmt_exp.h" + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_patch.h" +#include "fm_utils.h" +#include "fm_link.h" +#include "fm_config.h" +#include "fm_cmd.h" + +#include "mt6627_fm_reg.h" +#include "mt6627_fm_lib.h" + +/* #include "mach/mt_gpio.h" */ + +/* #define MT6627_FM_PATCH_PATH "/etc/firmware/mt6627/mt6627_fm_patch.bin" */ +/* #define MT6627_FM_COEFF_PATH "/etc/firmware/mt6627/mt6627_fm_coeff.bin" */ +/* #define MT6627_FM_HWCOEFF_PATH "/etc/firmware/mt6627/mt6627_fm_hwcoeff.bin" */ +/* #define MT6627_FM_ROM_PATH "/etc/firmware/mt6627/mt6627_fm_rom.bin" */ + +static struct fm_patch_tbl mt6627_patch_tbl[5] = { + {FM_ROM_V1, "mt6627_fm_v1_patch.bin", "mt6627_fm_v1_coeff.bin", NULL, NULL}, + {FM_ROM_V2, "mt6627_fm_v2_patch.bin", "mt6627_fm_v2_coeff.bin", NULL, NULL}, + {FM_ROM_V3, "mt6627_fm_v3_patch.bin", "mt6627_fm_v3_coeff.bin", NULL, NULL}, + {FM_ROM_V4, "mt6627_fm_v4_patch.bin", "mt6627_fm_v4_coeff.bin", NULL, NULL}, + {FM_ROM_V5, "mt6627_fm_v5_patch.bin", "mt6627_fm_v5_coeff.bin", NULL, NULL} +}; + +static struct fm_hw_info mt6627_hw_info = { + .chip_id = 0x00006627, + .eco_ver = 0x00000000, + .rom_ver = 0x00000000, + .patch_ver = 0x00000000, + .reserve = 0x00000000, +}; + +unsigned char *cmd_buf; +struct fm_lock *cmd_buf_lock; +struct fm_res_ctx *fm_res; +static struct fm_callback *fm_cb_op; +/* static signed int Chip_Version = mt6627_E1; */ + +/* static bool rssi_th_set = false; */ + +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ +static struct fm_fifo *cqi_fifo; +#endif +static signed int mt6627_is_dese_chan(unsigned short freq); +static bool mt6627_I2S_hopping_check(unsigned short freq); + +#if 0 +static signed int mt6627_mcu_dese(unsigned short freq, void *arg); +static signed int mt6627_gps_dese(unsigned short freq, void *arg); +static signed int mt6627_I2s_Setting(signed int onoff, signed int mode, signed int sample); +#endif +static unsigned short mt6627_chan_para_get(unsigned short freq); +static signed int mt6627_desense_check(unsigned short freq, signed int rssi); +static bool mt6627_TDD_chan_check(unsigned short freq); +static signed int mt6627_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid); +static signed int mt6627_pwron(signed int data) +{ + if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM) == MTK_WCN_BOOL_FALSE) { + WCN_DBG(FM_ERR | CHIP, "WMT turn on FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn on FM OK!\n"); + return 0; +} + +static signed int mt6627_pwroff(signed int data) +{ + if (mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM) == MTK_WCN_BOOL_FALSE) { + WCN_DBG(FM_ERR | CHIP, "WMT turn off FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn off FM OK!\n"); + return 0; +} + +#if 0 +static signed int mt6627_top_set_bits(unsigned short addr, unsigned int bits, unsigned int mask) +{ + signed int ret = 0; + unsigned int val; + + ret = fm_top_reg_read(addr, &val); + + if (ret) + return ret; + + val = ((val & (mask)) | bits); + ret = fm_top_reg_write(addr, val); + + return ret; +} +#endif + +#if 0 +static signed int mt6627_DSP_write(unsigned short addr, unsigned short val) +{ + fm_reg_write(0xE2, addr); + fm_reg_write(0xE3, val); + fm_reg_write(0xE1, 0x0002); + return 0; +} +static signed int mt6627_DSP_read(unsigned short addr, unsigned short *val) +{ + signed int ret = -1; + + fm_reg_write(0xE2, addr); + fm_reg_write(0xE1, 0x0001); + ret = fm_reg_read(0xE4, val); + return ret; +} +#endif + +static unsigned short mt6627_get_chipid(void) +{ + return 0x6627; +} + +/* MT6627_SetAntennaType - set Antenna type + * @type - 1,Short Antenna; 0, Long Antenna + */ +static signed int mt6627_SetAntennaType(signed int type) +{ + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | CHIP, "set ana to %s\n", type ? "short" : "long"); + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + + if (type) + dataRead |= ANTENNA_TYPE; + else + dataRead &= (~ANTENNA_TYPE); + + fm_reg_write(FM_MAIN_CG2_CTRL, dataRead); + + return 0; +} + +static signed int mt6627_GetAntennaType(void) +{ + unsigned short dataRead = 0; + + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + WCN_DBG(FM_DBG | CHIP, "get ana type: %s\n", (dataRead & ANTENNA_TYPE) ? "short" : "long"); + + if (dataRead & ANTENNA_TYPE) + return FM_ANA_SHORT; /* short antenna */ + else + return FM_ANA_LONG; /* long antenna */ +} + +static signed int mt6627_Mute(bool mute) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | CHIP, "set %s\n", mute ? "mute" : "unmute"); + /* fm_reg_read(FM_MAIN_CTRL, &dataRead); */ + fm_reg_read(0x9C, &dataRead); + + /* fm_top_reg_write(0x0050,0x00000007); */ + if (mute == 1) + ret = fm_reg_write(0x9C, (dataRead & 0xFFFC) | 0x0003); + else + ret = fm_reg_write(0x9C, (dataRead & 0xFFFC)); + + /* fm_top_reg_write(0x0050,0x0000000F); */ + + return ret; +} + +#if 0 +static signed int mt6627_set_RSSITh(unsigned short TH_long, unsigned short TH_short) +{ + fm_reg_write(0xE2, 0x3072); + fm_reg_write(0xE3, TH_long); + fm_reg_write(0xE1, 0x0002); + + fm_delayms(1); + fm_reg_write(0xE2, 0x307A); + fm_reg_write(0xE3, TH_short); + fm_reg_write(0xE1, 0x0002); + + WCN_DBG(FM_DBG | CHIP, "RSSI TH, long:0x%04x, short:0x%04x", TH_long, TH_short); + return 0; +} + +static signed int mt6627_set_SMGTh(signed int ver, unsigned short TH_smg) +{ + if (mt6627_E1 == ver) { + fm_reg_write(0xE2, 0x321E); + fm_reg_write(0xE3, TH_smg); + fm_reg_write(0xE1, 0x0002); + } else { + fm_reg_write(0xE2, 0x3218); + fm_reg_write(0xE3, TH_smg); + fm_reg_write(0xE1, 0x0002); + } + + WCN_DBG(FM_DBG | CHIP, "Soft-mute gain TH %d\n", (int)TH_smg); + return 0; +} +#endif + +static signed int mt6627_pwrup_clock_on_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + unsigned short de_emphasis; + /* unsigned short osc_freq; */ + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + de_emphasis = fm_config.rx_cfg.deemphasis; + de_emphasis &= 0x0001; /* rang 0~1 */ + + /* 2,turn on top clock */ + pkt_size += fm_bop_top_write(0xA10, 0xFFFFFFFF, &buf[pkt_size], buf_size - pkt_size); /* wr a10 ffffffff */ + /* 3,enable MTCMOS */ + pkt_size += fm_bop_top_write(0x60, 0x00000030, &buf[pkt_size], buf_size - pkt_size); /* wr 60 30 */ + pkt_size += fm_bop_top_write(0x60, 0x00000035, &buf[pkt_size], buf_size - pkt_size); /* wr 60 35 */ + pkt_size += fm_bop_top_rd_until(0x60, 0x0000000A, 0xA, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x60, 0x00000015, &buf[pkt_size], buf_size - pkt_size); /* wr 60 15 */ + pkt_size += fm_bop_top_write(0x60, 0x00000005, &buf[pkt_size], buf_size - pkt_size); /* wr 60 5 */ + pkt_size += fm_bop_udelay(10, &buf[pkt_size], buf_size - pkt_size); /* delay 10us */ + pkt_size += fm_bop_top_write(0x60, 0x00000045, &buf[pkt_size], buf_size - pkt_size); /* wr 60 45 */ + /* 4,set CSPI fm slave dummy count */ + pkt_size += fm_bop_top_write(0x68, 0x0000003F, &buf[pkt_size], buf_size - pkt_size); /* wr 68 3F */ + + /* a1 enable digital OSC */ + pkt_size += fm_bop_top_write(0x50, 0x00000001, &buf[pkt_size], buf_size - pkt_size); /* wr 50 1 */ + pkt_size += fm_bop_udelay(3000, &buf[pkt_size], buf_size - pkt_size); /* delay 3ms */ + /* a3 set OSC clock output to fm */ + pkt_size += fm_bop_top_write(0x50, 0x00000003, &buf[pkt_size], buf_size - pkt_size); /* wr 50 3 */ + /* a4 release HW clock gating */ + pkt_size += fm_bop_top_write(0x50, 0x00000007, &buf[pkt_size], buf_size - pkt_size); /* wr 50 7 */ + /* set I2S current driving */ + pkt_size += fm_bop_top_write(0x000, 0x00000000, &buf[pkt_size], buf_size - pkt_size); /* wr 0 0 */ + /* a5 enable DSP auto clock gating */ + pkt_size += fm_bop_write(0x70, 0x0040, &buf[pkt_size], buf_size - pkt_size); /* wr 70 0040 */ + /* a7 deemphasis setting */ + pkt_size += fm_bop_modify(0x61, ~DE_EMPHASIS, (de_emphasis << 12), &buf[pkt_size], buf_size - pkt_size); + + /* pkt_size += fm_bop_modify(0x60, OSC_FREQ_MASK, (osc_freq << 4), &buf[pkt_size], buf_size - pkt_size); */ + + return pkt_size - 4; +} +/* + * mt6627_pwrup_clock_on - Wholechip FM Power Up: step 1, FM Digital Clock enable + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6627_pwrup_clock_on(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6627_pwrup_clock_on_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6627_pwrup_digital_init_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* FM RF&ADPLL divider setting */ + /* D2.1 set cell mode */ + /* wr 30 D3:D2 00:FDD(default),01:both.10: TDD, 11 FDD */ + /* pkt_size += fm_bop_modify(0x30, 0xFFF3, 0x0000, &buf[pkt_size], buf_size - pkt_size); */ + /* D2.2 set ADPLL divider */ + pkt_size += fm_bop_write(0x21, 0xE000, &buf[pkt_size], buf_size - pkt_size); /* wr 21 E000 */ + /* D2.3 set SDM coeff0_H */ + pkt_size += fm_bop_write(0xD8, 0x03F0, &buf[pkt_size], buf_size - pkt_size); /* wr D8 0x03F0 */ + /* D2.4 set SDM coeff0_L */ + pkt_size += fm_bop_write(0xD9, 0x3F04, &buf[pkt_size], buf_size - pkt_size); /* wr D9 0x3F04 */ + /* D2.5 set SDM coeff1_H */ + pkt_size += fm_bop_write(0xDA, 0x0014, &buf[pkt_size], buf_size - pkt_size); /* wr DA 0x0014 */ + /* D2.6 set SDM coeff1_L */ + pkt_size += fm_bop_write(0xDB, 0x2A38, &buf[pkt_size], buf_size - pkt_size); /* wr DB 0x2A38 */ + /* D2.7 set 26M clock */ + pkt_size += fm_bop_write(0x23, 0x4000, &buf[pkt_size], buf_size - pkt_size); /* wr 23 4000 */ + + /* FM Digital Init: fm_rgf_maincon */ + /* E4 */ + pkt_size += fm_bop_write(0x6A, 0x0021, &buf[pkt_size], buf_size - pkt_size); /* wr 6A 0021 */ + pkt_size += fm_bop_write(0x6B, 0x0021, &buf[pkt_size], buf_size - pkt_size); /* wr 6B 0021 */ + /* E5 */ + pkt_size += fm_bop_top_write(0x50, 0x0000000F, &buf[pkt_size], buf_size - pkt_size); /* wr 50 f */ + /* E6 */ + pkt_size += fm_bop_modify(0x61, 0xFFFD, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D1=1 */ + /* E7 */ + pkt_size += fm_bop_modify(0x61, 0xFFFE, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D0=0 */ + /* E8 */ + pkt_size += fm_bop_udelay(100000, &buf[pkt_size], buf_size - pkt_size); /* delay 100ms */ + /* E9 */ + pkt_size += fm_bop_rd_until(0x64, 0x001F, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* Poll 64[0~4] = 2 */ + + return pkt_size - 4; +} + +/* + * mt6627_pwrup_digital_init - Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6627_pwrup_digital_init(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6627_pwrup_digital_init_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6627_pwrup_fine_tune_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* F1 set host control RF register */ + pkt_size += fm_bop_top_write(0x50, 0x00000007, &buf[pkt_size], buf_size - pkt_size); + /* F2 fine tune RF setting */ + pkt_size += fm_bop_write(0x01, 0xBEE8, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x03, 0xF6ED, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x15, 0x0D80, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x16, 0x0068, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x17, 0x092A, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x34, 0x807F, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x35, 0x311E, &buf[pkt_size], buf_size - pkt_size); + /* F1 set DSP control RF register */ + pkt_size += fm_bop_top_write(0x50, 0x0000000F, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} + +/* + * mt6627_pwrup_fine_tune - Wholechip FM Power Up: step 5, FM RF fine tune setting + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6627_pwrup_fine_tune(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6627_pwrup_fine_tune_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6627_pwrdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* A1:set audio output I2S Tx mode: */ + pkt_size += fm_bop_modify(0x9B, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + + /* B0:Disable HW clock control */ + pkt_size += fm_bop_top_write(0x50, 0x330F, &buf[pkt_size], buf_size - pkt_size); + /* B1:Reset ASIP */ + pkt_size += fm_bop_write(0x61, 0x0001, &buf[pkt_size], buf_size - pkt_size); + /* B2:digital core + digital rgf reset */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* B3:Disable all clock */ + pkt_size += fm_bop_top_write(0x50, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* B4:Reset rgfrf */ + pkt_size += fm_bop_top_write(0x50, 0x4000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x50, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* MTCMOS power off */ + /* C0:disable MTCMOS */ + pkt_size += fm_bop_top_write(0x60, 0x0005, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x60, 0x0015, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x60, 0x0035, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x60, 0x0030, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_rd_until(0x60, 0x0000000A, 0x0, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6627_pwrdown - Wholechip FM Power down: Digital Modem Power Down + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6627_pwrdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6627_pwrdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6627_tune_reg_op(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 4; + + WCN_DBG(FM_ALT | CHIP, "%s enter mt6627_tune function\n", __func__); + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* Set desired channel & channel parameter */ +#ifdef FM_TUNE_USE_POLL + pkt_size += fm_bop_write(0x6A, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x6B, 0x0000, &buf[pkt_size], buf_size - pkt_size); +#endif + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF8, TUNE, &buf[pkt_size], buf_size - pkt_size); + /* Wait for STC_DONE interrupt */ +#ifdef FM_TUNE_USE_POLL + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size], + buf_size - pkt_size); + /* Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); +#endif + + WCN_DBG(FM_ALT | CHIP, "%s leave mt6627_tune function\n", __func__); + + return pkt_size - 4; +} + +/* + * mt6627_tune - execute tune action, + * @buf - target buf + * @buf_size - buffer size + * @freq - 760 ~ 1080, 100KHz unit + * return package size + */ +static signed int mt6627_tune(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 0; + + pkt_size = mt6627_tune_reg_op(buf, buf_size, freq, chan_para); + return fm_op_seq_combine_cmd(buf, FM_TUNE_OPCODE, pkt_size); +} + +static signed int mt6627_rampdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* Clear DSP state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF0, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* Set DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFFF, RAMP_DOWN, &buf[pkt_size], buf_size - pkt_size); + /* @Wait for STC_DONE interrupt@ */ + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size], + buf_size - pkt_size); + /* Clear DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, (~RAMP_DOWN), 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6627_rampdown - f/w will wait for STC_DONE interrupt + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6627_rampdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6627_rampdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_RAMPDOWN_OPCODE, pkt_size); +} + +static signed int mt6627_RampDown(void) +{ + signed int ret = 0; + unsigned short pkt_size; + /* unsigned short tmp; */ + + WCN_DBG(FM_DBG | CHIP, "ramp down\n"); + /* pwer up sequence 0425 */ + ret = fm_top_reg_write(0x0050, 0x00000007); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down wr top 0x50 failed\n"); + return ret; + } + + ret = fm_set_bits(0x0F, 0x0000, 0xF800); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down wr 0x0f failed\n"); + return ret; + } + + ret = fm_top_reg_write(0x0050, 0x0000000F); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down wr top 0x50 failed\n"); + return ret; + } + + /* fm_reg_read(FM_MAIN_INTRMASK, &tmp); */ + ret = fm_reg_write(FM_MAIN_INTRMASK, 0x0000); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down wr FM_MAIN_INTRMASK failed\n"); + return ret; + } + + ret = fm_reg_write(FM_MAIN_EXTINTRMASK, 0x0000); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down wr FM_MAIN_EXTINTRMASK failed\n"); + return ret; + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6627_rampdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_RAMPDOWN, SW_RETRY_CNT, RAMPDOWN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down failed\n"); + return ret; + } + + ret = fm_reg_write(FM_MAIN_EXTINTRMASK, 0x0021); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down wr FM_MAIN_EXTINTRMASK failed\n"); + return ret; + } + + ret = fm_reg_write(FM_MAIN_INTRMASK, 0x0021); + if (ret) + WCN_DBG(FM_ERR | CHIP, "ramp down wr FM_MAIN_INTRMASK failed\n"); + + return ret; +} + +static signed int mt6627_get_rom_version(void) +{ + unsigned short tmp = 0; + signed int ret = 0; + + /* DSP rom code version request enable --- set 0x61 b15=1 */ + fm_set_bits(0x61, 0x8000, 0x7FFF); + + /* Release ASIP reset --- set 0x61 b1=1 */ + fm_set_bits(0x61, 0x0002, 0xFFFD); + + /* Enable ASIP power --- set 0x61 b0=0 */ + fm_set_bits(0x61, 0x0000, 0xFFFE); + + /* Wait DSP code version ready --- wait 1ms */ + do { + fm_delayus(1000); + ret = fm_reg_read(0x84, &tmp); + /* ret=-4 means signal got when control FM. usually get sig 9 to kill FM process. */ + /* now cancel FM power up sequence is recommended. */ + if (ret) + return ret; + + WCN_DBG(FM_DBG | CHIP, "0x84=%x\n", tmp); + } while (tmp != 0x0001); + + /* Get FM DSP code version --- rd 0x83[15:8] */ + fm_reg_read(0x83, &tmp); + tmp = (tmp >> 8); + + /* DSP rom code version request disable --- set 0x61 b15=0 */ + fm_set_bits(0x61, 0x0000, 0x7FFF); + + /* Reset ASIP --- set 0x61[1:0] = 1 */ + fm_set_bits(0x61, 0x0001, 0xFFFC); + + /* WCN_DBG(FM_NTC | CHIP, "ROM version: v%d\n", (signed int)tmp); */ + return (signed int) tmp; +} + +/* + * mt6627_pwrup_DSP_download - execute dsp/coeff patch dl action, + * @patch_tbl - current chip patch table + * return patch dl ok or not + */ +static signed int mt6627_pwrup_DSP_download(struct fm_patch_tbl *patch_tbl) +{ +#define PATCH_BUF_SIZE (4096*6) + signed int ret = 0; + signed int patch_len = 0; + unsigned char *dsp_buf = NULL; + unsigned short tmp_reg = 0; + + mt6627_hw_info.eco_ver = (signed int) mtk_wcn_wmt_ic_info_get(1); + WCN_DBG(FM_DBG | CHIP, "ECO version:0x%08x\n", mt6627_hw_info.eco_ver); + + /* get mt6627 DSP rom version */ + ret = mt6627_get_rom_version(); + if (ret >= 0) { + mt6627_hw_info.rom_ver = ret; + WCN_DBG(FM_DBG | CHIP, "ROM version: v%d\n", mt6627_hw_info.rom_ver); + } else { + WCN_DBG(FM_ERR | CHIP, "get ROM version failed\n"); + /* ret=-4 means signal got when control FM. usually get sig 9 to kill FM process. */ + /* now cancel FM power up sequence is recommended. */ + goto out; + } + + /* Wholechip FM Power Up: step 3, download patch */ + dsp_buf = fm_vmalloc(PATCH_BUF_SIZE); + if (!dsp_buf) { + WCN_DBG(FM_ALT | CHIP, "-ENOMEM\n"); + return -ENOMEM; + } + + patch_len = fm_get_patch_path(mt6627_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_patch_path failed\n"); + ret = patch_len; + goto out; + } + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_PATCH); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " DL DSPpatch failed\n"); + goto out; + } + + patch_len = fm_get_coeff_path(mt6627_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_coeff_path failed\n"); + ret = patch_len; + goto out; + } + + mt6627_hw_info.rom_ver += 1; + + tmp_reg = dsp_buf[38] | (dsp_buf[39] << 8); /* to be confirmed */ + mt6627_hw_info.patch_ver = (signed int) tmp_reg; + WCN_DBG(FM_NTC | CHIP, "Patch version: 0x%08x\n", mt6627_hw_info.patch_ver); + + if (ret == 1) { + dsp_buf[4] = 0x00; /* if we found rom version undefined, we should disable patch */ + dsp_buf[5] = 0x00; + } + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_COEFFICIENT); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " DL DSPcoeff failed\n"); + goto out; + } + fm_reg_write(0x92, 0x0000); /* ? */ + fm_reg_write(0x90, 0x0040); + fm_reg_write(0x90, 0x0000); + +out: + if (dsp_buf) { + fm_vfree(dsp_buf); + dsp_buf = NULL; + } + return ret; +} + +static signed int mt6627_PowerUp(unsigned short *chip_id, unsigned short *device_id) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short tmp_reg = 0; +#if defined(MT6625_FM) + unsigned int host_reg = 0; +#endif + + if (chip_id == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (device_id == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + WCN_DBG(FM_DBG | CHIP, "pwr on seq......\n"); + + /* Wholechip FM Power Up: step 1, set common SPI parameter */ + ret = fm_host_reg_write(0x8013000C, 0x0000801F); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup set CSPI failed\n"); + return ret; + } +#if defined(MT6625_FM) + ret = fm_host_reg_read(0x80000224, &host_reg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup read 0x80000224 failed\n"); + return ret; + } + ret = fm_host_reg_write(0x80000224, host_reg | (1 << 0)); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup conn_srcclkena enable failed\n"); + return ret; + } + + ret = fm_host_reg_read(0x80000224, &host_reg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup read 0x80000224 failed\n"); + return ret; + } + ret = fm_host_reg_write(0x80000224, host_reg | (1 << 16)); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup conn_srcclkena switch failed\n"); + return ret; + } + + ret = fm_host_reg_read(0x80101030, &host_reg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup read 0x80100030 failed\n"); + return ret; + } + ret = fm_host_reg_write(0x80101030, host_reg | (1 << 1)); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup enable top_ck_en_adie failed\n"); + return ret; + } + + /* enable bgldo */ + ret = fm_top_reg_read(0x00c0, &host_reg); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "power up read top 0xc0 failed\n"); + return ret; + } + ret = fm_top_reg_write(0x00c0, host_reg | (0x3 << 27)); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "power up write top 0xc0 failed\n"); + return ret; + } +#endif + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6627_pwrup_clock_on(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6627_pwrup_clock_on failed\n"); + return ret; + } +/* #ifdef FM_DIGITAL_INPUT */ + /* mt6627_I2s_Setting(MT6627_I2S_ON, MT6627_I2S_MASTER, MT6627_I2S_44K); */ + /* mt_combo_audio_ctrl(COMBO_AUDIO_STATE_2); */ + /* mtk_wcn_cmb_stub_audio_ctrl((CMB_STUB_AIF_X)CMB_STUB_AIF_2); */ +/* #endif */ + + /* Wholechip FM Power Up: step 2, read HW version */ + fm_reg_read(0x62, &tmp_reg); + /* *chip_id = tmp_reg; */ + if ((tmp_reg == 0x6625) || (tmp_reg == 0x6627)) + *chip_id = 0x6627; + *device_id = tmp_reg; + mt6627_hw_info.chip_id = (signed int) tmp_reg; + WCN_DBG(FM_DBG | CHIP, "chip_id:0x%04x\n", tmp_reg); + + if ((mt6627_hw_info.chip_id != 0x6627) && (mt6627_hw_info.chip_id != 0x6625)) { + WCN_DBG(FM_NTC | CHIP, "fm sys error, reset hw\n"); + return -FM_EFW; + } + + /* Wholechip FM Power Up: step 3, patch download */ + ret = mt6627_pwrup_DSP_download(mt6627_patch_tbl); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6627_pwrup_DSP_download failed\n"); + return ret; + } + + /* Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6627_pwrup_digital_init(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6627_pwrup_digital_init failed\n"); + return ret; + } + /* Wholechip FM Power Up: step 5, FM RF fine tune setting */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6627_pwrup_fine_tune(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6627_pwrup_fine_tune failed\n"); + return ret; + } + /* enable connsys FM 2 wire RX */ + fm_reg_write(0x9B, 0xF9AB); + fm_host_reg_write(0x80101054, 0x00003f35); + + WCN_DBG(FM_DBG | CHIP, "pwr on seq ok\n"); + + return ret; +} + +static signed int mt6627_PowerDown(void) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short dataRead = 0; + unsigned int tem = 0; +#if defined(MT6625_FM) + unsigned int host_reg = 0; + + WCN_DBG(FM_DBG | CHIP, "pwr down seq, but not clear top_clk_en_adie\n"); +#endif + + WCN_DBG(FM_DBG | CHIP, "pwr down seq\n"); + /*SW work around for MCUFA issue. + *if interrupt happen before doing rampdown, DSP can't switch MCUFA back well. + * In case read interrupt, and clean if interrupt found before rampdown. + */ + fm_reg_read(FM_MAIN_INTR, &dataRead); + + if (dataRead & 0x1) + fm_reg_write(FM_MAIN_INTR, dataRead); /* clear status flag */ + + /* mt6627_RampDown(); */ + +/* #ifdef FM_DIGITAL_INPUT */ +/* mt6627_I2s_Setting(MT6627_I2S_OFF, MT6627_I2S_SLAVE, MT6627_I2S_44K); */ +/* #endif */ + /* pwer up sequence 0425 */ + /* A0:set audio output I2X Rx mode: */ + fm_host_reg_read(0x80101054, &tem); + tem = tem & 0xFFFF9FFF; + fm_host_reg_write(0x80101054, tem); + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6627_pwrdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6627_pwrdown failed\n"); + return ret; + } + /* FIX_ME, disable ext interrupt */ + fm_reg_write(FM_MAIN_EXTINTRMASK, 0x00); + +#if defined(MT6625_FM) + /* ret = fm_host_reg_read(0x80101030, &host_reg); + * if (ret) { + * WCN_DBG(FM_ALT | CHIP, " pwroff read 0x80100030 failed\n"); + * return ret; + * } + * WCN_DBG(FM_DBG | CHIP, "read host reg 0x80101030=%x\n", host_reg); + * ret = fm_host_reg_write(0x80101030, host_reg & (~(0x1 << 1))); + * if (ret) { + * WCN_DBG(FM_ALT | CHIP, " pwroff disable top_ck_en_adie failed\n"); + * return ret; + * } + */ + + ret = fm_host_reg_read(0x80000224, &host_reg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwroff read 0x80000224 failed\n"); + return ret; + } + WCN_DBG(FM_DBG | CHIP, "read host reg 0x80000224=%x\n", host_reg); + ret = fm_host_reg_write(0x80000224, host_reg & (~(1 << 16))); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwroff conn_srcclkena switch failed\n"); + return ret; + } +#endif + +/* rssi_th_set = false; */ + return ret; +} + +/* just for dgb */ +#if 0 +static void mt6627_bt_write(unsigned int addr, unsigned int val) +{ + unsigned int tem, i = 0; + + fm_host_reg_write(0x80103020, addr); + fm_host_reg_write(0x80103024, val); + fm_host_reg_read(0x80103000, &tem); + while ((tem == 4) && (i < 1000)) { + i++; + fm_host_reg_read(0x80103000, &tem); + } +} +#endif +static bool mt6627_SetFreq(unsigned short freq) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short chan_para = 0; + unsigned int reg_val = 0; + unsigned short freq_reg = 0; + + fm_cb_op->cur_freq_set(freq); + +#if 0 + /* MCU clock adjust if need */ + ret = mt6627_mcu_dese(freq, NULL); + if (ret < 0) + WCN_DBG(FM_ERR | MAIN, "mt6627_mcu_dese FAIL:%d\n", ret); + + WCN_DBG(FM_INF | MAIN, "MCU %d\n", ret); + + /* GPS clock adjust if need */ + ret = mt6627_gps_dese(freq, NULL); + if (ret < 0) + WCN_DBG(FM_ERR | MAIN, "mt6627_gps_dese FAIL:%d\n", ret); + + WCN_DBG(FM_INF | MAIN, "GPS %d\n", ret); +#endif + /* pwer up sequence 0425 */ + ret = fm_top_reg_write(0x0050, 0x00000007); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr top 0x50 failed\n"); + + ret = fm_set_bits(0x0F, 0x0455, 0xF800); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x0f failed\n"); + + if (mt6627_TDD_chan_check(freq)) { + ret = fm_set_bits(0x30, 0x0008, 0xFFF3); /* use TDD solution */ + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x30 failed\n"); + } else { + ret = fm_set_bits(0x30, 0x0000, 0xFFF3); /* default use FDD solution */ + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x30 failed\n"); + } + ret = fm_top_reg_write(0x0050, 0x0000000F); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr top 0x50 failed\n"); + +/* if (fm_cb_op->chan_para_get) { */ + chan_para = mt6627_chan_para_get(freq); + WCN_DBG(FM_DBG | CHIP, "%d chan para = %d\n", (signed int) freq, (signed int) chan_para); +/* } */ + + freq_reg = freq; + if (fm_get_channel_space(freq_reg) == 0) + freq_reg *= 10; + + freq_reg = (freq_reg - 6400) * 2 / 10; + ret = fm_set_bits(0x65, freq_reg, 0xFC00); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x65 failed\n"); + return false; + } + + ret = fm_set_bits(0x65, (chan_para << 12), 0x0FFF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x65 failed\n"); + return false; + } + + /* enable connsys FM 2 wire RX */ + fm_reg_write(0x9B, 0xF9AB); + fm_host_reg_write(0x80101054, 0x00003f35); + + if ((mt6627_hw_info.chip_id == 0x6625) + && ((mtk_wcn_wmt_chipid_query() == 0x6592) || (mtk_wcn_wmt_chipid_query() == 0x6752) + || (mtk_wcn_wmt_chipid_query() == 0x6755) || (mtk_wcn_wmt_chipid_query() == 0x6757) + || (mtk_wcn_wmt_chipid_query() == 0x6763) || (mtk_wcn_wmt_chipid_query() == 0x6739))) { + if (mt6627_I2S_hopping_check(freq)) { + /* set i2s TX desense mode */ + ret = fm_set_bits(0x9C, 0x80, 0xFFFF); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x9C failed\n"); + + /* set i2s RX desense mode */ + ret = fm_host_reg_read(0x80101054, ®_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq rd 0x80101054 failed\n"); + + reg_val |= 0x8000; + ret = fm_host_reg_write(0x80101054, reg_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x80101054 failed\n"); + } else { + ret = fm_set_bits(0x9C, 0x0, 0xFF7F); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x9C failed\n"); + + ret = fm_host_reg_read(0x80101054, ®_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq rd 0x80101054 failed\n"); + + reg_val &= 0x7FFF; + ret = fm_host_reg_write(0x80101054, reg_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x80101054 failed\n"); + } + } + + if (FM_LOCK(cmd_buf_lock)) + return false; + pkt_size = mt6627_tune(cmd_buf, TX_BUF_SIZE, freq, chan_para); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE | FLAG_TUNE_DONE, SW_RETRY_CNT, TUNE_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6627_tune failed\n"); + return false; + } + + WCN_DBG(FM_DBG | CHIP, "set freq to %d ok\n", freq); +#if 0 + /* ADPLL setting for dbg */ + fm_top_reg_write(0x0050, 0x00000007); + fm_top_reg_write(0x0A08, 0xFFFFFFFF); + mt6627_bt_write(0x82, 0x11); + mt6627_bt_write(0x83, 0x11); + mt6627_bt_write(0x84, 0x11); + fm_top_reg_write(0x0040, 0x1C1C1C1C); + fm_top_reg_write(0x0044, 0x1C1C1C1C); + fm_reg_write(0x70, 0x0010); + /*0x0806 DCO clk + *0x0802 ref clk + *0x0804 feedback clk + */ + fm_reg_write(0xE0, 0x0806); +#endif + return true; +} + +#define FM_CQI_LOG_PATH "/mnt/sdcard/fmcqilog" + +static signed int mt6627_full_cqi_get(signed int min_freq, signed int max_freq, signed int space, signed int cnt) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short freq, orig_freq; + signed int i, j, k; + signed int space_val, max, min, num; + struct mt6627_full_cqi *p_cqi; + unsigned char *cqi_log_title = "Freq, RSSI, PAMD, PR, FPAMD, MR, ATDC, PRX, ATDEV, SMGain, DltaRSSI\n"; + unsigned char cqi_log_buf[100] = { 0 }; + signed int pos; + unsigned char cqi_log_path[100] = { 0 }; + + /* for soft-mute tune, and get cqi */ + freq = fm_cb_op->cur_freq_get(); + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + /* get cqi */ + orig_freq = freq; + if (fm_get_channel_space(min_freq) == 0) + min = min_freq * 10; + else + min = min_freq; + + if (fm_get_channel_space(max_freq) == 0) + max = max_freq * 10; + else + max = max_freq; + + if (space == 0x0001) + space_val = 5; /* 50Khz */ + else if (space == 0x0002) + space_val = 10; /* 100Khz */ + else if (space == 0x0004) + space_val = 20; /* 200Khz */ + else + space_val = 10; + + num = (max - min) / space_val + 1; /* Eg, (8760 - 8750) / 10 + 1 = 2 */ + for (k = 0; (orig_freq == 10000) && (g_dbg_level == 0xffffffff) && (k < cnt); k++) { + WCN_DBG(FM_NTC | CHIP, "cqi file:%d\n", k + 1); + freq = min; + pos = 0; + fm_memcpy(cqi_log_path, FM_CQI_LOG_PATH, strlen(FM_CQI_LOG_PATH)); + sprintf(&cqi_log_path[strlen(FM_CQI_LOG_PATH)], "%d.txt", k + 1); + fm_file_write(cqi_log_path, cqi_log_title, strlen(cqi_log_title), &pos); + for (j = 0; j < num; j++) { + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = + fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, + SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + WCN_DBG(FM_NTC | CHIP, "smt cqi size %d\n", fm_res->cqi[0]); + p_cqi = (struct mt6627_full_cqi *)&fm_res->cqi[2]; + for (i = 0; i < fm_res->cqi[1]; i++) { + /* just for debug */ + WCN_DBG(FM_NTC | CHIP, + "freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* format to buffer */ + sprintf(cqi_log_buf, + "%04d,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* write back to log file */ + fm_file_write(cqi_log_path, cqi_log_buf, strlen(cqi_log_buf), &pos); + } + } else { + WCN_DBG(FM_ALT | CHIP, "smt get CQI failed\n"); + ret = -1; + } + freq += space_val; + } + fm_cb_op->cur_freq_set(0); /* avoid run too much times */ + } + + return ret; +} + +/* + * mt6627_GetCurRSSI - get current freq's RSSI value + * RS=RSSI + * If RS>511, then RSSI(dBm)= (RS-1024)/16*6 + * else RSSI(dBm)= RS/16*6 + */ +static signed int mt6627_GetCurRSSI(signed int *pRSSI) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RSSI_IND, &tmp_reg); + tmp_reg = tmp_reg & 0x03ff; + + if (pRSSI) { + *pRSSI = (tmp_reg > 511) ? (((tmp_reg - 1024) * 6) >> 4) : ((tmp_reg * 6) >> 4); + WCN_DBG(FM_DBG | CHIP, "rssi:%d, dBm:%d\n", tmp_reg, *pRSSI); + } else { + WCN_DBG(FM_ERR | CHIP, "get rssi para error\n"); + return -FM_EPARA; + } + + return 0; +} + +static unsigned short mt6627_vol_tbl[16] = { 0x0000, 0x0519, 0x066A, 0x0814, + 0x0A2B, 0x0CCD, 0x101D, 0x1449, + 0x198A, 0x2027, 0x287A, 0x32F5, + 0x4027, 0x50C3, 0x65AD, 0x7FFF +}; + +static signed int mt6627_SetVol(unsigned char vol) +{ + signed int ret = 0; + + vol = (vol > 15) ? 15 : vol; + ret = fm_reg_write(0x7D, mt6627_vol_tbl[vol]); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "Set vol=%d Failed\n", vol); + return ret; + } + + WCN_DBG(FM_DBG | CHIP, "Set vol=%d OK\n", vol); + + if (vol == 10) { + fm_print_cmd_fifo(); /* just for debug */ + fm_print_evt_fifo(); + } + return 0; +} + +static signed int mt6627_GetVol(unsigned char *pVol) +{ + int ret = 0; + unsigned short tmp = 0; + signed int i; + + if (pVol == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + ret = fm_reg_read(0x7D, &tmp); + if (ret) { + *pVol = 0; + WCN_DBG(FM_ERR | CHIP, "Get vol Failed\n"); + return ret; + } + + for (i = 0; i < 16; i++) { + if (mt6627_vol_tbl[i] == tmp) { + *pVol = i; + break; + } + } + + WCN_DBG(FM_DBG | CHIP, "Get vol=%d OK\n", *pVol); + return 0; +} + +static signed int mt6627_dump_reg(void) +{ + signed int i; + unsigned short TmpReg = 0; + + for (i = 0; i < 0xff; i++) { + fm_reg_read(i, &TmpReg); + WCN_DBG(FM_NTC | CHIP, "0x%02x=0x%04x\n", i, TmpReg); + } + return 0; +} + +/*0:mono, 1:stereo*/ +static bool mt6627_GetMonoStereo(unsigned short *pMonoStereo) +{ +#define FM_BF_STEREO 0x1000 + unsigned short TmpReg = 0; + + if (pMonoStereo) { + fm_reg_read(FM_RSSI_IND, &TmpReg); + *pMonoStereo = (TmpReg & FM_BF_STEREO) >> 12; + } else { + WCN_DBG(FM_ERR | CHIP, "MonoStero: para err\n"); + return false; + } + + WCN_DBG(FM_NTC | CHIP, "Get MonoStero:0x%04x\n", *pMonoStereo); + return true; +} + +static signed int mt6627_SetMonoStereo(signed int MonoStereo) +{ + signed int ret = 0; + + WCN_DBG(FM_NTC | CHIP, "set to %s\n", MonoStereo ? "mono" : "auto"); + fm_top_reg_write(0x50, 0x0007); + + if (MonoStereo) /*mono */ + ret = fm_set_bits(0x75, 0x0008, ~0x0008); + else + ret = fm_set_bits(0x75, 0x0000, ~0x0008); + + fm_top_reg_write(0x50, 0x000F); + return ret; +} + +static signed int mt6627_GetCapArray(signed int *ca) +{ + unsigned short dataRead = 0; + unsigned short tmp = 0; + + if (ca == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_reg_read(0x60, &tmp); + fm_reg_write(0x60, tmp & 0xFFF7); /* 0x60 D3=0 */ + + fm_reg_read(0x26, &dataRead); + *ca = dataRead; + + fm_reg_write(0x60, tmp); /* 0x60 D3=1 */ + return 0; +} + +/* + * mt6627_GetCurPamd - get current freq's PAMD value + * PA=PAMD + * If PA>511 then PAMD(dB)= (PA-1024)/16*6, + * else PAMD(dB)=PA/16*6 + */ +static bool mt6627_GetCurPamd(unsigned short *pPamdLevl) +{ + unsigned short tmp_reg = 0; + unsigned short dBvalue, valid_cnt = 0; + int i, total = 0; + + for (i = 0; i < 8; i++) { + if (fm_reg_read(FM_ADDR_PAMD, &tmp_reg)) { + *pPamdLevl = 0; + return false; + } + + tmp_reg &= 0x03FF; + dBvalue = (tmp_reg > 256) ? ((512 - tmp_reg) * 6 / 16) : 0; + if (dBvalue != 0) { + total += dBvalue; + valid_cnt++; + WCN_DBG(FM_DBG | CHIP, "[%d]PAMD=%d\n", i, dBvalue); + } + fm_delayms(3); + } + if (valid_cnt != 0) + *pPamdLevl = total / valid_cnt; + else + *pPamdLevl = 0; + + WCN_DBG(FM_NTC | CHIP, "PAMD=%d\n", *pPamdLevl); + return true; +} + +static signed int mt6627_i2s_info_get(signed int *ponoff, signed int *pmode, signed int *psample) +{ + if (ponoff == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (pmode == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (psample == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + *ponoff = fm_config.aud_cfg.i2s_info.status; + *pmode = fm_config.aud_cfg.i2s_info.mode; + *psample = fm_config.aud_cfg.i2s_info.rate; + + return 0; +} + +static signed int mt6627fm_get_audio_info(struct fm_audio_info_t *data) +{ + memcpy(data, &fm_config.aud_cfg, sizeof(struct fm_audio_info_t)); + return 0; +} + +static signed int mt6627_hw_info_get(struct fm_hw_info *req) +{ + if (req == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + req->chip_id = mt6627_hw_info.chip_id; + req->eco_ver = mt6627_hw_info.eco_ver; + req->patch_ver = mt6627_hw_info.patch_ver; + req->rom_ver = mt6627_hw_info.rom_ver; + + return 0; +} + +static signed int mt6627_pre_search(void) +{ + mt6627_RampDown(); + /* disable audio output I2S Rx mode */ + fm_host_reg_write(0x80101054, 0x00000000); + /* disable audio output I2S Tx mode */ + fm_reg_write(0x9B, 0x0000); + + return 0; +} + +static signed int mt6627_restore_search(void) +{ + mt6627_RampDown(); + /* set audio output I2S Tx mode */ + fm_reg_write(0x9B, 0xF9AB); + /* set audio output I2S Rx mode */ + fm_host_reg_write(0x80101054, 0x00003f35); + return 0; +} + +static signed int mt6627_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid) +{ + signed int ret = 0; + unsigned short pkt_size; + /* unsigned short freq;//, orig_freq; */ + struct mt6627_full_cqi *p_cqi; + signed int RSSI = 0, PAMD = 0, MR = 0, ATDC = 0; + unsigned int PRX = 0, ATDEV = 0; + unsigned short softmuteGainLvl = 0; + + ret = mt6627_chan_para_get(freq); + if (ret == 2) + ret = fm_set_bits(FM_CHANNEL_SET, 0x2000, 0x0FFF); /* mdf HiLo */ + else + ret = fm_set_bits(FM_CHANNEL_SET, 0x0000, 0x0FFF); /* clear FA/HL/ATJ */ + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + p_cqi = (struct mt6627_full_cqi *)&fm_res->cqi[2]; + + RSSI = ((p_cqi->rssi & 0x03FF) >= 512) ? ((p_cqi->rssi & 0x03FF) - 1024) : (p_cqi->rssi & 0x03FF); + PAMD = ((p_cqi->pamd & 0x1FF) >= 256) ? ((p_cqi->pamd & 0x01FF) - 512) : (p_cqi->pamd & 0x01FF); + MR = ((p_cqi->mr & 0x01FF) >= 256) ? ((p_cqi->mr & 0x01FF) - 512) : (p_cqi->mr & 0x01FF); + ATDC = (p_cqi->atdc >= 32768) ? (65536 - p_cqi->atdc) : (p_cqi->atdc); + if (ATDC < 0) + ATDC = (~(ATDC)) - 1; /* Get abs value of ATDC */ + + PRX = (p_cqi->prx & 0x00FF); + ATDEV = p_cqi->atdev; + softmuteGainLvl = p_cqi->smg; + /* check if the channel is valid according to each CQIs */ + if ((fm_config.rx_cfg.long_ana_rssi_th <= RSSI) + && (fm_config.rx_cfg.pamd_th >= PAMD) + && (fm_config.rx_cfg.atdc_th >= ATDC) + && (fm_config.rx_cfg.mr_th <= MR) + && (fm_config.rx_cfg.prx_th <= PRX) + && (ATDEV >= ATDC) /* sync scan algorithm */ + && (fm_config.rx_cfg.smg_th <= softmuteGainLvl)) { + *valid = true; + } else { + *valid = false; + } + WCN_DBG(FM_NTC | CHIP, + "valid=%d, freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", + *valid, p_cqi->ch, p_cqi->rssi, p_cqi->pamd, p_cqi->pr, p_cqi->fpamd, p_cqi->mr, + p_cqi->atdc, p_cqi->prx, p_cqi->atdev, p_cqi->smg, p_cqi->drssi); + + *rssi = RSSI; + } else { + WCN_DBG(FM_ALT | CHIP, "smt get CQI failed\n"); + return false; + } + return true; +} + +static bool mt6627_em_test(unsigned short group_idx, unsigned short item_idx, unsigned int item_value) +{ + return true; +} + +/* +*parm: +* parm.th_type: 0, RSSI. 1,desense RSSI. 2,SMG. +* parm.th_val: threshold value +*/ +static signed int mt6627_set_search_th(signed int idx, signed int val, signed int reserve) +{ + switch (idx) { + case 0: { + fm_config.rx_cfg.long_ana_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set rssi th =%d\n", val); + break; + } + case 1: { + fm_config.rx_cfg.desene_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set desense rssi th =%d\n", val); + break; + } + case 2: { + fm_config.rx_cfg.smg_th = val; + WCN_DBG(FM_NTC | CHIP, "set smg th =%d\n", val); + break; + } + default: + break; + } + return 0; +} + +static signed int MT6627fm_low_power_wa_default(signed int fmon) +{ + return 0; +} + +signed int fm_low_ops_register(struct fm_callback *cb, struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,bi invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_get == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_get invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_set == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_set invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_cb_op = cb; + + bi->pwron = mt6627_pwron; + bi->pwroff = mt6627_pwroff; + bi->chipid_get = mt6627_get_chipid; + bi->mute = mt6627_Mute; + bi->rampdown = mt6627_RampDown; + bi->pwrupseq = mt6627_PowerUp; + bi->pwrdownseq = mt6627_PowerDown; + bi->setfreq = mt6627_SetFreq; + bi->low_pwr_wa = MT6627fm_low_power_wa_default; + bi->get_aud_info = mt6627fm_get_audio_info; + bi->rssiget = mt6627_GetCurRSSI; + bi->volset = mt6627_SetVol; + bi->volget = mt6627_GetVol; + bi->dumpreg = mt6627_dump_reg; + bi->msget = mt6627_GetMonoStereo; + bi->msset = mt6627_SetMonoStereo; + bi->pamdget = mt6627_GetCurPamd; + bi->em = mt6627_em_test; + bi->anaswitch = mt6627_SetAntennaType; + bi->anaget = mt6627_GetAntennaType; + bi->caparray_get = mt6627_GetCapArray; + bi->hwinfo_get = mt6627_hw_info_get; + bi->i2s_get = mt6627_i2s_info_get; + bi->is_dese_chan = mt6627_is_dese_chan; + bi->softmute_tune = mt6627_soft_mute_tune; + bi->desense_check = mt6627_desense_check; + bi->cqi_log = mt6627_full_cqi_get; + bi->pre_search = mt6627_pre_search; + bi->restore_search = mt6627_restore_search; + bi->set_search_th = mt6627_set_search_th; + + cmd_buf_lock = fm_lock_create("27_cmd"); + ret = fm_lock_get(cmd_buf_lock); + + cmd_buf = fm_zalloc(TX_BUF_SIZE + 1); + + if (!cmd_buf) { + WCN_DBG(FM_ALT | CHIP, "6627 fm lib alloc tx buf failed\n"); + ret = -1; + } +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ + cqi_fifo = fm_fifo_create("6628_cqi_fifo", sizeof(struct adapt_fm_cqi), 640); + if (!cqi_fifo) { + WCN_DBG(FM_ALT | CHIP, "6627 fm lib create cqi fifo failed\n"); + ret = -1; + } +#endif + + return ret; +} + +signed int fm_low_ops_unregister(struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ + fm_fifo_release(cqi_fifo); +#endif + + if (cmd_buf) { + fm_free(cmd_buf); + cmd_buf = NULL; + } + + ret = fm_lock_put(cmd_buf_lock); + fm_memset(bi, 0, sizeof(struct fm_basic_interface)); + return ret; +} + +/* static struct fm_pub pub; */ +/* static struct fm_pub_cb *pub_cb = &pub.pub_tbl; */ + +static const unsigned short mt6627_mcu_dese_list[] = { + 7630, 7800, 7940, 8320, 9260, 9600, 9710, 9920, 10400, 10410 +}; + +static const unsigned short mt6627_gps_dese_list[] = { + 7850, 7860 +}; + +static const signed char mt6627_chan_para_map[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, /* 6500~6595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6600~6695 */ + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, /* 6700~6795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6800~6895 */ + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6900~6995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7000~7095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 7100~7195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, /* 7200~7295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7300~7395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7400~7495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7500~7595 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, /* 7600~7695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7700~7795 */ + 8, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7800~7895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* 7900~7995 */ + 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, /* 8000~8095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8100~8195 */ + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8200~8295 */ + 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8300~8395 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8400~8495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8500~8595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8600~8695 */ + 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8700~8795 */ + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8800~8895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8900~8995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9000~9095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9100~9195 */ + 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9200~9295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, /* 9300~9395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9400~9495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9500~9595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9600~9695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9700~9795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9800~9895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 9900~9995 */ + 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10000~10095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10100~10195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, /* 10200~10295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10300~10395 */ + 8, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10400~10495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10500~10595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10600~10695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 10700~10795 */ + 0 /* 10800 */ +}; + +static const unsigned short mt6627_scan_dese_list[] = { + 6910, 7680, 7800, 9210, 9220, 9230, 9600, 9980, 9990, 10400, 10750, 10760 +}; + +static const unsigned short mt6627_I2S_hopping_list[] = { + 6550, 6760, 6960, 6970, 7170, 7370, 7580, 7780, 7990, 8810, 9210, 9220, 10240 +}; + +static const unsigned short mt6627_TDD_list[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6500~6595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6600~6695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6700~6795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6800~6895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6900~6995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7000~7095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7100~7195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7200~7295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7300~7395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7400~7495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7500~7595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7600~7695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7700~7795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7800~7895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7900~7995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8000~8095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8100~8195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8200~8295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8300~8395 */ + 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, /* 8400~8495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8500~8595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8600~8695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8700~8795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8800~8895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8900~8995 */ + 0x0000, 0x0000, 0x0101, 0x0101, 0x0101, /* 9000~9095 */ + 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, /* 9100~9195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9200~9295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9300~9395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9400~9495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9500~9595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9600~9695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, /* 9700~9795 */ + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, /* 9800~9895 */ + 0x0101, 0x0101, 0x0001, 0x0000, 0x0000, /* 9900~9995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10000~10095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10100~10195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10200~10295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10300~10395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10400~10495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10500~10595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, /* 10600~10695 */ + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, /* 10700~10795 */ + 0x0001 /* 10800 */ +}; + +static const unsigned short mt6627_TDD_Mask[] = { + 0x0001, 0x0010, 0x0100, 0x1000 +}; + +/* return value: 0, not a de-sense channel; 1, this is a de-sense channel; else error no */ +static signed int mt6627_is_dese_chan(unsigned short freq) +{ + signed int size; + + /* return 0;//HQA only :skip desense channel check. */ + size = ARRAY_SIZE(mt6627_scan_dese_list); + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + while (size) { + if (mt6627_scan_dese_list[size - 1] == freq) + return 1; + + size--; + } + + return 0; +} + +/* return value: +*1, is desense channel and rssi is less than threshold; +*0, not desense channel or it is but rssi is more than threshold. +*/ +static signed int mt6627_desense_check(unsigned short freq, signed int rssi) +{ + if (mt6627_is_dese_chan(freq)) { + if (rssi < fm_config.rx_cfg.desene_rssi_th) + return 1; + + WCN_DBG(FM_DBG | CHIP, "desen_rssi %d th:%d\n", rssi, fm_config.rx_cfg.desene_rssi_th); + } + return 0; +} + +static bool mt6627_TDD_chan_check(unsigned short freq) +{ + unsigned int i = 0; + unsigned short freq_tmp = freq; + signed int ret = 0; + + ret = fm_get_channel_space(freq_tmp); + if (ret == 0) + freq_tmp *= 10; + else if (ret == -1) + return false; + + i = (freq_tmp - 6500) / 5; + if ((i / 4) >= ARRAY_SIZE(mt6627_TDD_list)) { + WCN_DBG(FM_ERR | CHIP, "Freq index out of range(%d),max(%zd)\n", + i / 4, ARRAY_SIZE(mt6627_TDD_list)); + return false; + } + + if (mt6627_TDD_list[i / 4] & mt6627_TDD_Mask[i % 4]) { + WCN_DBG(FM_NTC | CHIP, "Freq %d use TDD solution\n", freq); + return true; + } else + return false; +} + +/* get channel parameter, HL side/ FA / ATJ */ +static unsigned short mt6627_chan_para_get(unsigned short freq) +{ + signed int pos, size; + + /* return 0;//for HQA only: skip FA/HL/ATJ */ + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + if (freq < 6500) + return 0; + + pos = (freq - 6500) / 5; + + size = ARRAY_SIZE(mt6627_chan_para_map); + + pos = (pos > (size - 1)) ? (size - 1) : pos; + + return mt6627_chan_para_map[pos]; +} + +static bool mt6627_I2S_hopping_check(unsigned short freq) +{ + signed int size; + + size = ARRAY_SIZE(mt6627_I2S_hopping_list); + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + while (size) { + if (mt6627_I2S_hopping_list[size - 1] == freq) + return 1; + size--; + } + + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/pub/mt6627_fm_rds.c b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/pub/mt6627_fm_rds.c new file mode 100644 index 00000000000000..20bad698b319b0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6627/pub/mt6627_fm_rds.c @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_rds.h" +#include "mt6627_fm_reg.h" +#include "fm_cmd.h" + +static bool bRDS_FirstIn; /* false */ +static unsigned int gBLER_CHK_INTERVAL = 500; +static unsigned short GOOD_BLK_CNT = 0, BAD_BLK_CNT; +static unsigned char BAD_BLK_RATIO; + +static struct fm_basic_interface *fm_bi; + +static bool mt6627_RDS_support(void); +static signed int mt6627_RDS_enable(void); +static signed int mt6627_RDS_disable(void); +static unsigned short mt6627_RDS_Get_GoodBlock_Counter(void); +static unsigned short mt6627_RDS_Get_BadBlock_Counter(void); +static unsigned char mt6627_RDS_Get_BadBlock_Ratio(void); +static unsigned int mt6627_RDS_Get_BlerCheck_Interval(void); +/* static void mt6627_RDS_GetData(unsigned short *data, unsigned short datalen); */ +static void mt6627_RDS_Init_Data(struct rds_t *pstRDSData); + +static bool mt6627_RDS_support(void) +{ + return true; +} + +static signed int mt6627_RDS_enable(void) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | RDSC, "rds enable\n"); + ret = fm_reg_read(FM_RDS_CFG0, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable read 0x80 fail\n"); + return ret; + } + ret = fm_reg_write(FM_RDS_CFG0, 6); /* set buf_start_th */ + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable write 0x80 fail\n"); + return ret; + } + ret = fm_reg_read(FM_MAIN_CTRL, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable read 0x63 fail\n"); + return ret; + } + ret = fm_reg_write(FM_MAIN_CTRL, dataRead | (RDS_MASK)); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable write 0x63 fail\n"); + return ret; + } + + return ret; +} + +static signed int mt6627_RDS_disable(void) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | RDSC, "rds disable\n"); + ret = fm_reg_read(FM_MAIN_CTRL, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds disable read 0x63 fail\n"); + return ret; + } + ret = fm_reg_write(FM_MAIN_CTRL, dataRead & (~RDS_MASK)); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds disable write 0x63 fail\n"); + return ret; + } + + return ret; +} + +static unsigned short mt6627_RDS_Get_GoodBlock_Counter(void) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RDS_GOODBK_CNT, &tmp_reg); + GOOD_BLK_CNT = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get good block cnt:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static unsigned short mt6627_RDS_Get_BadBlock_Counter(void) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RDS_BADBK_CNT, &tmp_reg); + BAD_BLK_CNT = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get bad block cnt:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static unsigned char mt6627_RDS_Get_BadBlock_Ratio(void) +{ + unsigned short tmp_reg; + unsigned short gbc; + unsigned short bbc; + + gbc = mt6627_RDS_Get_GoodBlock_Counter(); + bbc = mt6627_RDS_Get_BadBlock_Counter(); + + if ((gbc + bbc) > 0) + tmp_reg = (unsigned char) (bbc * 100 / (gbc + bbc)); + else + tmp_reg = 0; + + BAD_BLK_RATIO = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get badblock ratio:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static signed int mt6627_RDS_BlockCounter_Reset(void) +{ + mt6627_RDS_disable(); + mt6627_RDS_enable(); + + return 0; +} + +static unsigned int mt6627_RDS_Get_BlerCheck_Interval(void) +{ + return gBLER_CHK_INTERVAL; +} + +static signed int mt6627_RDS_BlerCheck(struct rds_t *dst) +{ + return 0; +} + +#if 0 +static void RDS_Recovery_Handler(void) +{ + unsigned short tempData = 0; + + do { + fm_reg_read(FM_RDS_DATA_REG, &tempData); + fm_reg_read(FM_RDS_POINTER, &tempData); + } while (tempData & 0x3); +} +#endif + +#if 0 +static void mt6627_RDS_GetData(unsigned short *data, unsigned short datalen) +{ +#define RDS_GROUP_DIFF_OFS 0x007C +#define RDS_FIFO_DIFF 0x007F +#define RDS_CRC_BLK_ADJ 0x0020 +#define RDS_CRC_CORR_CNT 0x001E +#define RDS_CRC_INFO 0x0001 + + unsigned short CRC = 0, i = 0, RDS_adj = 0, RDSDataCount = 0, FM_WARorrCnt = 0; + unsigned short temp = 0, OutputPofm_s32 = 0; + + WCN_DBG(FM_DBG | RDSC, "get data\n"); + fm_reg_read(FM_RDS_FIFO_STATUS0, &temp); + RDSDataCount = ((RDS_GROUP_DIFF_OFS & temp) << 2); + + if ((temp & RDS_FIFO_DIFF) >= 4) { + /* block A data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 10; + CRC |= (temp & RDS_CRC_INFO) << 3; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 11); + fm_reg_read(FM_RDS_DATA_REG, &data[0]); + + /* block B data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 9; + CRC |= (temp & RDS_CRC_INFO) << 2; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 7); + fm_reg_read(FM_RDS_DATA_REG, &data[1]); + + /* block C data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 8; + CRC |= (temp & RDS_CRC_INFO) << 1; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 3); + fm_reg_read(FM_RDS_DATA_REG, &data[2]); + + /* block D data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 7; + CRC |= (temp & RDS_CRC_INFO); + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) >> 1); + fm_reg_read(FM_RDS_DATA_REG, &data[3]); + + data[4] = (CRC | RDS_adj | RDSDataCount); + data[5] = FM_WARorrCnt; + + fm_reg_read(FM_RDS_PWDI, &data[6]); + fm_reg_read(FM_RDS_PWDQ, &data[7]); + + fm_reg_read(FM_RDS_POINTER, &OutputPofm_s32); + + /* Go fm_s32o RDS recovery handler while RDS output pofm_s32 doesn't align to 4 in numeric */ + if (OutputPofm_s32 & 0x3) + RDS_Recovery_Handler(); + + } else { + for (; i < 8; i++) + data[i] = 0; + } +} +#endif + +static void mt6627_RDS_Init_Data(struct rds_t *pstRDSData) +{ + fm_memset(pstRDSData, 0, sizeof(struct rds_t)); + bRDS_FirstIn = true; + + pstRDSData->event_status = 0x0000; + fm_memset(pstRDSData->RT_Data.TextData, 0x20, sizeof(pstRDSData->RT_Data.TextData)); + fm_memset(pstRDSData->PS_Data.PS, '\0', sizeof(pstRDSData->PS_Data.PS)); + fm_memset(pstRDSData->PS_ON, 0x20, sizeof(pstRDSData->PS_ON)); +} + +bool mt6627_RDS_OnOff(struct rds_t *dst, bool bFlag) +{ + signed int ret = 0; + + if (mt6627_RDS_support() == false) { + WCN_DBG(FM_ALT | RDSC, "mt6627_RDS_OnOff failed, RDS not support\n"); + return false; + } + + if (bFlag) { + mt6627_RDS_Init_Data(dst); + ret = mt6627_RDS_enable(); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "mt6627_RDS_OnOff enable failed\n"); + return false; + } + } else { + mt6627_RDS_Init_Data(dst); + ret = mt6627_RDS_disable(); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "mt6627_RDS_OnOff disable failed\n"); + return false; + } + } + + return true; +} + +DEFINE_RDSLOG(mt6627_rds_log); + +/* mt6627_RDS_Efm_s32_Handler - response FM RDS interrupt + * @fm - main data structure of FM driver + * This function first get RDS raw data, then call RDS spec parser + */ +static signed int mt6627_rds_parser(struct rds_t *rds_dst, struct rds_rx_t *rds_raw, + signed int rds_size, unsigned short(*getfreq) (void)) +{ + mt6627_rds_log.log_in(&mt6627_rds_log, rds_raw, rds_size); + return rds_parser(rds_dst, rds_raw, rds_size, getfreq); +} + +static signed int mt6627_rds_log_get(struct rds_rx_t *dst, signed int *dst_len) +{ + return mt6627_rds_log.log_out(&mt6627_rds_log, dst, dst_len); +} + +static signed int mt6627_rds_gc_get(struct rds_group_cnt_t *dst, struct rds_t *rdsp) +{ + return rds_grp_counter_get(dst, &rdsp->gc); +} + +static signed int mt6627_rds_gc_reset(struct rds_t *rdsp) +{ + return rds_grp_counter_reset(&rdsp->gc); +} + +signed int fm_rds_ops_register(struct fm_basic_interface *bi, struct fm_rds_interface *ri) +{ + signed int ret = 0; + + if (ri == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,ri invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_bi = bi; + + ri->rds_blercheck = mt6627_RDS_BlerCheck; + ri->rds_onoff = mt6627_RDS_OnOff; + ri->rds_parser = mt6627_rds_parser; + ri->rds_gbc_get = mt6627_RDS_Get_GoodBlock_Counter; + ri->rds_bbc_get = mt6627_RDS_Get_BadBlock_Counter; + ri->rds_bbr_get = mt6627_RDS_Get_BadBlock_Ratio; + ri->rds_bc_reset = mt6627_RDS_BlockCounter_Reset; + ri->rds_bci_get = mt6627_RDS_Get_BlerCheck_Interval; + ri->rds_log_get = mt6627_rds_log_get; + ri->rds_gc_get = mt6627_rds_gc_get; + ri->rds_gc_reset = mt6627_rds_gc_reset; + return ret; +} + +signed int fm_rds_ops_unregister(struct fm_rds_interface *ri) +{ + signed int ret = 0; + + if (ri == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,ri invalid pointer\n", __func__); + return -FM_EPARA; + } + + fm_bi = NULL; + fm_memset(ri, 0, sizeof(struct fm_rds_interface)); + return ret; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6630/inc/mt6630_fm_lib.h b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6630/inc/mt6630_fm_lib.h new file mode 100644 index 00000000000000..55fd695b2031d5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6630/inc/mt6630_fm_lib.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT6630_FM_LIB_H__ +#define __MT6630_FM_LIB_H__ + +#include "fm_typedef.h" + +enum { + DSPPATCH = 0xFFF9, + USDELAY = 0xFFFA, + MSDELAY = 0xFFFB, + HW_VER = 0xFFFD, + POLL_N = 0xFFFE, /* poling check if bit(n) is '0' */ + POLL_P = 0xFFFF, /* polling check if bit(n) is '1' */ +}; + +enum { + FM_PUS_DSPPATCH = DSPPATCH, + FM_PUS_USDELAY = USDELAY, + FM_PUS_MSDELAY = MSDELAY, + FM_PUS_HW_VER = HW_VER, + FM_PUS_POLL_N = POLL_N, /* poling check if bit(n) is '0' */ + FM_PUS_POLL_P = POLL_P, /* polling check if bit(n) is '1' */ + FM_PUS_MAX +}; + +enum { + mt6630_E1 = 0, + mt6630_E2 +}; + +struct mt6630_fm_cqi { + unsigned short ch; + unsigned short rssi; + unsigned short reserve; +}; + +struct adapt_fm_cqi { + signed int ch; + signed int rssi; + signed int reserve; +}; + +struct mt6630_full_cqi { + unsigned short ch; + unsigned short rssi; + unsigned short pamd; + unsigned short pr; + unsigned short fpamd; + unsigned short mr; + unsigned short atdc; + unsigned short prx; + unsigned short atdev; + unsigned short smg; /* soft-mute gain */ + unsigned short drssi; /* delta rssi */ +}; + +#endif diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6630/inc/mt6630_fm_reg.h b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6630/inc/mt6630_fm_reg.h new file mode 100644 index 00000000000000..cab9c814e4ca3c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6630/inc/mt6630_fm_reg.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT6630_FM_REG_H__ +#define __MT6630_FM_REG_H__ + +/* RDS_BDGRP_ABD_CTRL_REG */ +enum { + BDGRP_ABD_EN = 0x0001, + BER_RUN = 0x2000 +}; +#define FM_DAC_CON1 0x83 +#define FM_DAC_CON2 0x84 +#define FM_FT_CON0 0x86 +enum { + FT_EN = 0x0001 +}; + +#define FM_I2S_CON0 0x90 +enum { + I2S_EN = 0x0001, + FORMAT = 0x0002, + WLEN = 0x0004, + I2S_SRC = 0x0008 +}; + +/* FM_MAIN_CTRL */ +enum { + TUNE = 0x0001, + SEEK = 0x0002, + SCAN = 0x0004, + CQI_READ = 0x0008, + RDS_MASK = 0x0010, + MUTE = 0x0020, + RDS_BRST = 0x0040, + RAMP_DOWN = 0x0100, +}; + +enum { + ANTENNA_TYPE = 0x0010, /* 0x61 D4, 0:long, 1:short */ + ANALOG_I2S = 0x0080, /* 0x61 D7, 0:lineout, 1:I2S */ + DE_EMPHASIS = 0x1000, /* 0x61 D12,0:50us, 1:75 us */ +}; + +#define OSC_FREQ_BITS 0x0070 /* 0x60 bit4~6 */ +#define OSC_FREQ_MASK (~OSC_FREQ_BITS) + +#endif /* __MT6630_FM_REG_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6630/pub/mt6630_fm_lib.c b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6630/pub/mt6630_fm_lib.c new file mode 100644 index 00000000000000..dc989d054fa0a6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6630/pub/mt6630_fm_lib.c @@ -0,0 +1,2473 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/slab.h> +#include <linux/vmalloc.h> + +#include "stp_exp.h" +#include "wmt_exp.h" + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_patch.h" +#include "fm_utils.h" +#include "fm_link.h" +#include "fm_config.h" +#include "fm_cmd.h" + +#include "mt6630_fm_reg.h" +#include "mt6630_fm_lib.h" + +static struct fm_patch_tbl mt6630_patch_tbl[5] = { + {FM_ROM_V1, "mt6630_fm_v1_patch.bin", "mt6630_fm_v1_coeff.bin", NULL, NULL}, + {FM_ROM_V2, "mt6630_fm_v2_patch.bin", "mt6630_fm_v2_coeff.bin", NULL, NULL}, + {FM_ROM_V3, "mt6630_fm_v3_patch.bin", "mt6630_fm_v3_coeff.bin", NULL, NULL}, + {FM_ROM_V4, "mt6630_fm_v4_patch.bin", "mt6630_fm_v4_coeff.bin", NULL, NULL}, + {FM_ROM_V5, "mt6630_fm_v5_patch.bin", "mt6630_fm_v5_coeff.bin", NULL, NULL}, +}; + +static struct fm_patch_tbl mt6630_patch_tbl_tx[5] = { + {FM_ROM_V1, "mt6630_fm_v1_patch_tx.bin", "mt6630_fm_v1_coeff_tx.bin", NULL, NULL}, + {FM_ROM_V2, "mt6630_fm_v2_patch_tx.bin", "mt6630_fm_v2_coeff_tx.bin", NULL, NULL}, + {FM_ROM_V3, "mt6630_fm_v3_patch_tx.bin", "mt6630_fm_v3_coeff_tx.bin", NULL, NULL}, + {FM_ROM_V4, "mt6630_fm_v4_patch_tx.bin", "mt6630_fm_v4_coeff_tx.bin", NULL, NULL}, + {FM_ROM_V5, "mt6630_fm_v5_patch_tx.bin", "mt6630_fm_v5_coeff_tx.bin", NULL, NULL}, +}; + +static struct fm_hw_info mt6630_hw_info = { + .chip_id = 0x00006630, + .eco_ver = 0x00000000, + .rom_ver = 0x00000000, + .patch_ver = 0x00000000, + .reserve = 0x00000000, +}; + +unsigned char *cmd_buf; +struct fm_lock *cmd_buf_lock; +struct fm_res_ctx *fm_res; +static struct fm_callback *fm_cb_op; +static unsigned char fm_packaging = 1; /*0:QFN,1:WLCSP */ +static unsigned int fm_sant_flag; /* 1,Short Antenna; 0, Long Antenna */ +static signed int mt6630_is_dese_chan(unsigned short freq); +#if 0 +static signed int mt6630_mcu_dese(unsigned short freq, void *arg); +#endif +static signed int mt6630_gps_dese(unsigned short freq, void *arg); + +static signed int mt6630_I2s_Setting(signed int onoff, signed int mode, signed int sample); +static unsigned short mt6630_chan_para_get(unsigned short freq); +static signed int mt6630_desense_check(unsigned short freq, signed int rssi); +static bool mt6630_TDD_chan_check(unsigned short freq); +static signed int mt6630_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid); +static signed int mt6630_pwron(signed int data) +{ + if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM) == MTK_WCN_BOOL_FALSE) { + WCN_DBG(FM_ERR | CHIP, "WMT turn on FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn on FM OK!\n"); + return 0; +} + +static signed int mt6630_pwroff(signed int data) +{ + if (mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM) == MTK_WCN_BOOL_FALSE) { + WCN_DBG(FM_ERR | CHIP, "WMT turn off FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn off FM OK!\n"); + return 0; +} + +static unsigned short mt6630_get_chipid(void) +{ + return 0x6630; +} + +/* MT6630_SetAntennaType - set Antenna type + * @type - 1,Short Antenna; 0, Long Antenna + */ +static signed int mt6630_SetAntennaType(signed int type) +{ + unsigned short dataRead = 0; + + WCN_DBG(FM_NTC | CHIP, "set ana to %s\n", type ? "short" : "long"); + if (fm_packaging == 0) { + fm_sant_flag = type; + } else { + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + + if (type) + dataRead |= ANTENNA_TYPE; + else + dataRead &= (~ANTENNA_TYPE); + + fm_reg_write(FM_MAIN_CG2_CTRL, dataRead); + } + return 0; +} + +static signed int mt6630_GetAntennaType(void) +{ + unsigned short dataRead = 0; + + if (fm_packaging == 0) + return fm_sant_flag; + + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + WCN_DBG(FM_NTC | CHIP, "get ana type: %s\n", (dataRead & ANTENNA_TYPE) ? "short" : "long"); + + if (dataRead & ANTENNA_TYPE) + return FM_ANA_SHORT; /* short antenna */ + else + return FM_ANA_LONG; /* long antenna */ +} + +static signed int mt6630_Mute(bool mute) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_NTC | CHIP, "set %s\n", mute ? "mute" : "unmute"); + fm_reg_read(FM_MAIN_CTRL, &dataRead); + + if (mute == 1) + ret = fm_reg_write(FM_MAIN_CTRL, (dataRead & 0xFFDF) | 0x0020); + else + ret = fm_reg_write(FM_MAIN_CTRL, (dataRead & 0xFFDF)); + + return ret; +} + +signed int mt6630_rampdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* Clear DSP state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF0, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* Set DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFFF, RAMP_DOWN, &buf[pkt_size], buf_size - pkt_size); + /* @Wait for STC_DONE interrupt@ */ + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size], + buf_size - pkt_size); + /* Clear DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, (~RAMP_DOWN), 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} + + +/* + * mt6630_rampdown - f/w will wait for STC_DONE interrupt + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6630_rampdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6630_rampdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_RAMPDOWN_OPCODE, pkt_size); +} + +static signed int mt6630_RampDown(void) +{ + signed int ret = 0; + unsigned short pkt_size; + /* unsigned short tmp; */ + + WCN_DBG(FM_NTC | CHIP, "ramp down\n"); + + ret = fm_reg_write(FM_MAIN_EXTINTRMASK, 0x0000); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down write FM_MAIN_EXTINTRMASK failed\n"); + return ret; + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6630_rampdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_RAMPDOWN, SW_RETRY_CNT, RAMPDOWN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down failed\n"); + return ret; + } + + ret = fm_reg_write(FM_MAIN_EXTINTRMASK, 0x0021); + if (ret) + WCN_DBG(FM_ERR | CHIP, "ramp down write FM_MAIN_EXTINTRMASK failed\n"); + + return ret; +} + +static signed int mt6630_pwrup_clock_on_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + unsigned short de_emphasis; + /* unsigned short osc_freq; */ + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + de_emphasis = fm_config.rx_cfg.deemphasis; + de_emphasis &= 0x0001; /* rang 0~1 */ + + /* B1.1 Enable digital OSC */ + pkt_size += fm_bop_write(0x60, 0x0003, &buf[pkt_size], buf_size - pkt_size); /* wr 60 3 */ + pkt_size += fm_bop_udelay(100, &buf[pkt_size], buf_size - pkt_size); /* delay 100us */ + /* B1.3 Release HW clock gating */ + pkt_size += fm_bop_write(0x60, 0x0007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 7 */ + /* B1.4 Set FM long/short antenna:1: short_antenna 0: long antenna(default) */ + pkt_size += fm_bop_modify(0x61, 0xFFEF, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* B1.5 Set audio output mode (lineout/I2S) 0:lineout, 1:I2S */ + if (fm_config.aud_cfg.aud_path == FM_AUD_ANALOG) + pkt_size += fm_bop_modify(0x61, 0xFF7F, 0x0000, &buf[pkt_size], buf_size - pkt_size); + else + pkt_size += fm_bop_modify(0x61, 0xFF7F, 0x0080, &buf[pkt_size], buf_size - pkt_size); + + /* B1.6 Set deemphasis setting */ + pkt_size += fm_bop_modify(0x61, ~DE_EMPHASIS, (de_emphasis << 12), &buf[pkt_size], buf_size - pkt_size); + + /* pkt_size += fm_bop_modify(0x60, OSC_FREQ_MASK, (osc_freq << 4), &buf[pkt_size], buf_size - pkt_size); */ + + return pkt_size - 4; +} + +/* + * mt6630_pwrup_clock_on - Wholechip FM Power Up: step 1, FM Digital Clock enable + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6630_pwrup_clock_on(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6630_pwrup_clock_on_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6630_pwrup_digital_init_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* update FM ADPLL fast tracking mode gain */ + pkt_size += fm_bop_modify(0xF, 0xF800, 0x0455, &buf[pkt_size], buf_size - pkt_size); + /* F1.4 Set appropriate interrupt mask behavior as desired(RX) */ + /* pkt_size += fm_bop_write(0x6A, 0x0021, &buf[pkt_size], buf_size - pkt_size);//wr 6A 0021 */ + pkt_size += fm_bop_write(0x6B, 0x0021, &buf[pkt_size], buf_size - pkt_size); /* wr 6B 0021 */ + /* F1.9 Enable HW auto control */ + pkt_size += fm_bop_write(0x60, 0x000F, &buf[pkt_size], buf_size - pkt_size); /* wr 60 f */ + /* F1.10 Release ASIP reset */ + pkt_size += fm_bop_modify(0x61, 0xFFFD, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D1=1 */ + /* F1.11 Enable ASIP power */ + pkt_size += fm_bop_modify(0x61, 0xFFFE, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D0=0 */ + pkt_size += fm_bop_udelay(100000, &buf[pkt_size], buf_size - pkt_size); /* delay 100ms */ + /* F1.13 Check HW intitial complete */ + pkt_size += fm_bop_rd_until(0x64, 0x001F, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* Poll 64[0~4] = 2 */ + + return pkt_size - 4; +} + +/* + * mt6630_pwrup_digital_init - Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6630_pwrup_digital_init(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6630_pwrup_digital_init_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + + +signed int mt6630_pwrdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* Disable HW clock control */ + pkt_size += fm_bop_write(0x60, 0x0107, &buf[pkt_size], buf_size - pkt_size); /* wr 60 107 */ + /* Reset ASIP */ + pkt_size += fm_bop_write(0x61, 0x0001, &buf[pkt_size], buf_size - pkt_size); /* wr 61 0001 */ + /* digital core + digital rgf reset */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */ + /* Disable all clock */ + pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 60 0000 */ + /* Reset rgfrf */ + pkt_size += fm_bop_write(0x60, 0x4000, &buf[pkt_size], buf_size - pkt_size); /* wr 60 4000 */ + pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 60 0000 */ + + return pkt_size - 4; +} + +/* + * mt6630_pwrdown - Wholechip FM Power down: Digital Modem Power Down + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6630_pwrdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6630_pwrdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +signed int mt6630_tune_reg_op(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 4; + + WCN_DBG(FM_ALT | CHIP, "%s enter mt6630_tune function\n", __func__); + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + freq = (freq - 6400) * 2 / 10; + + /* Set desired channel & channel parameter */ +#ifdef FM_TUNE_USE_POLL + pkt_size += fm_bop_write(0x6A, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x6B, 0x0000, &buf[pkt_size], buf_size - pkt_size); +#endif + pkt_size += fm_bop_modify(FM_CHANNEL_SET, 0xFC00, freq, &buf[pkt_size], buf_size - pkt_size); + /* channel para setting, D15~D12, D15: ATJ, D13: HL, D12: FA */ + pkt_size += fm_bop_modify(FM_CHANNEL_SET, 0x0FFF, (chan_para << 12), &buf[pkt_size], buf_size - pkt_size); + /* Enable hardware controlled tuning sequence */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF8, TUNE, &buf[pkt_size], buf_size - pkt_size); + /* Wait for STC_DONE interrupt */ +#ifdef FM_TUNE_USE_POLL + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size], + buf_size - pkt_size); + /* Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); +#endif + + return pkt_size - 4; +} + +/* + * mt6630_tune - execute tune action, + * @buf - target buf + * @buf_size - buffer size + * @freq - 760 ~ 1080, 100KHz unit + * return package size + */ +static signed int mt6630_tune(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 0; + + pkt_size = mt6630_tune_reg_op(buf, buf_size, freq, chan_para); + return fm_op_seq_combine_cmd(buf, FM_TUNE_OPCODE, pkt_size); +} + +static signed int mt6630_get_rom_version(void) +{ + unsigned short tmp = 0; + signed int ret = 0; + + /* DSP rom code version request enable --- set 0x61 b15=1 */ + fm_set_bits(0x61, 0x8000, 0x7FFF); + + /* Release ASIP reset --- set 0x61 b1=1 */ + fm_set_bits(0x61, 0x0002, 0xFFFD); + + /* Enable ASIP power --- set 0x61 b0=0 */ + fm_set_bits(0x61, 0x0000, 0xFFFE); + + /* Wait DSP code version ready --- wait 1ms */ + do { + fm_delayus(1000); + ret = fm_reg_read(0x84, &tmp); + /* ret=-4 means signal got when control FM. usually get sig 9 to kill FM process. */ + /* now cancel FM power up sequence is recommended. */ + if (ret) + return ret; + + WCN_DBG(FM_DBG | CHIP, "0x84=%x\n", tmp); + } while (tmp != 0x0001); + + /* Get FM DSP code version --- rd 0x83[15:8] */ + fm_reg_read(0x83, &tmp); + WCN_DBG(FM_NTC | CHIP, "DSP ver=0x%x\n", tmp); + tmp = (tmp >> 8); + + /* DSP rom code version request disable --- set 0x61 b15=0 */ + fm_set_bits(0x61, 0x0000, 0x7FFF); + + /* Reset ASIP --- set 0x61[1:0] = 1 */ + fm_set_bits(0x61, 0x0001, 0xFFFC); + + return (signed int) tmp; +} + +static signed int mt6630_pwrup_top_setting(void) +{ + signed int ret = 0, value = 0; + /* A0.1 Turn on FM buffer */ + ret = fm_host_reg_read(0x8102123c, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x8102123c rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x8102123c, value & 0xFFFFFFBF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x8102123c wr failed\n"); + return ret; + } + /* A0.2 Set xtal no off when FM on */ + ret = fm_host_reg_read(0x81021134, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81021134 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81021134, value | 0x80); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81021134 wr failed\n"); + return ret; + } + /* A0.3 Set top off always on when FM on */ + ret = fm_host_reg_read(0x81020010, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020010 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81020010, value & 0xFFFDFFFF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020010 wr failed\n"); + return ret; + } + /* A0.4 Always enable PALDO when FM on */ + ret = fm_host_reg_read(0x81021430, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81021430 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81021430, value | 0x80000000); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81021430 wr failed\n"); + return ret; + } + /* A0.5 */ + fm_delayus(240); + + /* A0.6 MTCMOS Control */ + ret = fm_host_reg_read(0x81020008, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81020008, value | 0x00000030); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 wr failed\n"); + return ret; + } + /* A0.7 */ + fm_delayus(20); + + /* A0.8 release power on reset */ + ret = fm_host_reg_read(0x81020008, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81020008, value | 0x00000001); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 wr failed\n"); + return ret; + } + /* A0.9 enable fspi_mas_bclk_ck */ + ret = fm_host_reg_read(0x80000108, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x80000108 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x80000108, value | 0x00000100); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x80000108 wr failed\n"); + return ret; + } + return ret; +} + +static signed int mt6630_pwrdown_top_setting(void) +{ + signed int ret = 0, value = 0; + /* B0.1 disable fspi_mas_bclk_ck */ + ret = fm_host_reg_read(0x80000104, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x80000104 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x80000104, value | 0x00000100); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x80000104 wr failed\n"); + return ret; + } + /* B0.2 set power off reset */ + ret = fm_host_reg_read(0x81020008, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81020008, value & 0xFFFFFFFE); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 wr failed\n"); + return ret; + } + /* B0.3 */ + fm_delayus(20); + + /* B0.4 disable MTCMOS & set Iso_en */ + ret = fm_host_reg_read(0x81020008, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81020008, value & 0xFFFFFFEF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 wr failed\n"); + return ret; + } + /* B0.5 Turn off FM buffer */ + ret = fm_host_reg_read(0x8102123c, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x8102123c rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x8102123c, value | 0x40); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x8102123c wr failed\n"); + return ret; + } + /* B0.6 Clear xtal no off when FM off */ + ret = fm_host_reg_read(0x81021134, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81021134 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81021134, value & 0xFFFFFF7F); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81021134 wr failed\n"); + return ret; + } + /* B0.7 Clear top off always on when FM off */ + ret = fm_host_reg_read(0x81020010, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020010 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81020010, value | 0x20000); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020010 wr failed\n"); + return ret; + } + /* B0.9 Disable PALDO when FM off */ + ret = fm_host_reg_read(0x81021430, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81021430 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81021430, value & 0x7FFFFFFF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81021430 wr failed\n"); + return ret; + } + + return ret; +} + +static signed int mt6630_pwrup_DSP_download(struct fm_patch_tbl *patch_tbl) +{ +#define PATCH_BUF_SIZE (4096*6) + signed int ret = 0; + signed int patch_len = 0; + unsigned char *dsp_buf = NULL; + unsigned short tmp_reg = 0; + + mt6630_hw_info.eco_ver = (signed int) mtk_wcn_wmt_ic_info_get(1); + WCN_DBG(FM_NTC | CHIP, "ECO version:0x%08x\n", mt6630_hw_info.eco_ver); + + /* FM ROM code version request */ + ret = mt6630_get_rom_version(); + if (ret >= 0) { + mt6630_hw_info.rom_ver = ret; + WCN_DBG(FM_NTC | CHIP, "ROM version: v%d\n", mt6630_hw_info.rom_ver); + } else { + WCN_DBG(FM_ERR | CHIP, "get ROM version failed\n"); + /* ret=-4 means signal got when control FM. usually get sig 9 to kill FM process. */ + /* now cancel FM power up sequence is recommended. */ + return ret; + } + + /* Wholechip FM Power Up: step 3, download patch */ + dsp_buf = fm_vmalloc(PATCH_BUF_SIZE); + if (!dsp_buf) { + WCN_DBG(FM_ERR | CHIP, "-ENOMEM\n"); + return -ENOMEM; + } + + patch_len = fm_get_patch_path(mt6630_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_patch_path failed\n"); + ret = patch_len; + goto out; + } + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_PATCH); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " DL DSPpatch failed\n"); + goto out; + } + + patch_len = fm_get_coeff_path(mt6630_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_coeff_path failed\n"); + ret = patch_len; + goto out; + } + + mt6630_hw_info.rom_ver += 1; + + tmp_reg = dsp_buf[38] | (dsp_buf[39] << 8); /* to be confirmed */ + mt6630_hw_info.patch_ver = (signed int) tmp_reg; + WCN_DBG(FM_NTC | CHIP, "Patch version: 0x%08x\n", mt6630_hw_info.patch_ver); + + if (ret == 1) { + dsp_buf[4] = 0x00; /* if we found rom version undefined, we should disable patch */ + dsp_buf[5] = 0x00; + } + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_COEFFICIENT); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " DL DSPcoeff failed\n"); + goto out; + } + fm_reg_write(0x90, 0x0040); + fm_reg_write(0x90, 0x0000); +out: + if (dsp_buf) { + fm_vfree(dsp_buf); + dsp_buf = NULL; + } + return ret; +} + +static signed int mt6630_PowerUp(unsigned short *chip_id, unsigned short *device_id) +{ + signed int ret = 0, reg = 0; + unsigned short pkt_size; + unsigned short tmp_reg = 0; + + if (chip_id == NULL) { + WCN_DBG(CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (device_id == NULL) { + WCN_DBG(CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + WCN_DBG(FM_DBG | CHIP, "pwr on seq......\n"); + + ret = fm_host_reg_read(0x80021010, ®); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "packaging rd failed\n"); + } else { + fm_packaging = (reg & 0x00008000) >> 15; + WCN_DBG(FM_NTC | CHIP, "fm_packaging: %d\n", fm_packaging); + } + ret = mt6630_pwrup_top_setting(); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6630_pwrup_top_setting failed\n"); + return ret; + } + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6630_pwrup_clock_on(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6630_pwrup_clock_on failed\n"); + return ret; + } + /* read HW version */ + fm_reg_read(0x62, &tmp_reg); + *chip_id = tmp_reg; + *device_id = tmp_reg; + mt6630_hw_info.chip_id = (signed int) tmp_reg; + WCN_DBG(FM_NTC | CHIP, "chip_id:0x%04x\n", tmp_reg); + + if (mt6630_hw_info.chip_id != 0x6630) { + WCN_DBG(FM_NTC | CHIP, "fm sys error!\n"); + return -FM_EPARA; + } + ret = mt6630_pwrup_DSP_download(mt6630_patch_tbl); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6630_pwrup_DSP_download failed\n"); + return ret; + } + + if ((fm_config.aud_cfg.aud_path == FM_AUD_MRGIF) + || (fm_config.aud_cfg.aud_path == FM_AUD_I2S)) { + mt6630_I2s_Setting(FM_I2S_ON, fm_config.aud_cfg.i2s_info.mode, + fm_config.aud_cfg.i2s_info.rate); + /* mt_combo_audio_ctrl(COMBO_AUDIO_STATE_2); */ + mtk_wcn_cmb_stub_audio_ctrl((enum CMB_STUB_AIF_X) CMB_STUB_AIF_2); + } + /* Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6630_pwrup_digital_init(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6630_pwrup_digital_init failed\n"); + return ret; + } + + WCN_DBG(FM_NTC | CHIP, "pwr on seq ok\n"); + + return ret; +} + +static signed int mt6630_PowerDown(void) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | CHIP, "pwr down seq\n"); + /*SW work around for MCUFA issue. + *if interrupt happen before doing rampdown, DSP can't switch MCUFA back well. + * In case read interrupt, and clean if interrupt found before rampdown. + */ + fm_reg_read(FM_MAIN_INTR, &dataRead); + + if (dataRead & 0x1) + fm_reg_write(FM_MAIN_INTR, dataRead); /* clear status flag */ + + /* mt6630_RampDown(); */ + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6630_pwrdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6630_pwrdown failed\n"); + return ret; + } + + ret = mt6630_pwrdown_top_setting(); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6630_pwrdown_top_setting failed\n"); + return ret; + } + + return ret; +} + +/* just for dgb */ +static bool mt6630_SetFreq(unsigned short freq) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short chan_para = 0; + + fm_cb_op->cur_freq_set(freq); + +#if 0 + /* MCU clock adjust if need */ + ret = mt6630_mcu_dese(freq, NULL); + if (ret < 0) + WCN_DBG(FM_ERR | MAIN, "mt6630_mcu_dese FAIL:%d\n", ret); + + WCN_DBG(FM_INF | MAIN, "MCU %d\n", ret); +#endif + + /* GPS clock adjust if need */ + ret = mt6630_gps_dese(freq, NULL); + if (ret < 0) + WCN_DBG(FM_ERR | MAIN, "mt6630_gps_dese FAIL:%d\n", ret); + + WCN_DBG(FM_INF | MAIN, "GPS %d\n", ret); + + ret = fm_reg_write(0x60, 0x0007); + if (ret) + WCN_DBG(FM_ALT | MAIN, "set freq write 0x60 fail\n"); + + if (mt6630_TDD_chan_check(freq)) { + ret = fm_set_bits(0x30, 0x0004, 0xFFF9); /* use TDD solution */ + if (ret) + WCN_DBG(FM_ALT | MAIN, "set freq write 0x30 fail\n"); + } else { + ret = fm_set_bits(0x30, 0x0000, 0xFFF9); /* default use FDD solution */ + if (ret) + WCN_DBG(FM_ALT | MAIN, "set freq write 0x30 fail\n"); + } + ret = fm_reg_write(0x60, 0x000F); + if (ret) + WCN_DBG(FM_ALT | MAIN, "set freq write 0x60 fail\n"); + + chan_para = mt6630_chan_para_get(freq); + WCN_DBG(FM_DBG | CHIP, "%d chan para = %d\n", (signed int) freq, (signed int) chan_para); + + if (FM_LOCK(cmd_buf_lock)) + return false; + pkt_size = mt6630_tune(cmd_buf, TX_BUF_SIZE, freq, chan_para); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE | FLAG_TUNE_DONE, SW_RETRY_CNT, TUNE_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6630_tune failed\n"); + return false; + } + + WCN_DBG(FM_DBG | CHIP, "set freq to %d ok\n", freq); + return true; +} + +#define FM_CQI_LOG_PATH "/mnt/sdcard/fmcqilog" + +static signed int mt6630_full_cqi_get(signed int min_freq, signed int max_freq, signed int space, signed int cnt) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short freq, orig_freq; + signed int i, j, k; + signed int space_val, max, min, num; + struct mt6630_full_cqi *p_cqi; + unsigned char *cqi_log_title = "Freq, RSSI, PAMD, PR, FPAMD, MR, ATDC, PRX, ATDEV, SMGain, DltaRSSI\n"; + unsigned char cqi_log_buf[100] = { 0 }; + signed int pos; + unsigned char cqi_log_path[100] = { 0 }; + + WCN_DBG(FM_DBG | CHIP, "6630 cqi log start\n"); + /* for soft-mute tune, and get cqi */ + freq = fm_cb_op->cur_freq_get(); + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + /* get cqi */ + orig_freq = freq; + if (fm_get_channel_space(min_freq) == 0) + min = min_freq * 10; + else + min = min_freq; + + if (fm_get_channel_space(max_freq) == 0) + max = max_freq * 10; + else + max = max_freq; + + if (space == 0x0001) + space_val = 5; /* 50Khz */ + else if (space == 0x0002) + space_val = 10; /* 100Khz */ + else if (space == 0x0004) + space_val = 20; /* 200Khz */ + else + space_val = 10; + + num = (max - min) / space_val + 1; /* Eg, (8760 - 8750) / 10 + 1 = 2 */ + for (k = 0; (orig_freq == 10000) && (g_dbg_level == 0xffffffff) && (k < cnt); k++) { + WCN_DBG(FM_NTC | CHIP, "cqi file:%d\n", k + 1); + freq = min; + pos = 0; + fm_memcpy(cqi_log_path, FM_CQI_LOG_PATH, strlen(FM_CQI_LOG_PATH)); + sprintf(&cqi_log_path[strlen(FM_CQI_LOG_PATH)], "%d.txt", k + 1); + fm_file_write(cqi_log_path, cqi_log_title, strlen(cqi_log_title), &pos); + for (j = 0; j < num; j++) { + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = + fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, + SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + WCN_DBG(FM_NTC | CHIP, "smt cqi size %d\n", fm_res->cqi[0]); + p_cqi = (struct mt6630_full_cqi *)&fm_res->cqi[2]; + for (i = 0; i < fm_res->cqi[1]; i++) { + /* just for debug */ + WCN_DBG(FM_NTC | CHIP, + "freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* format to buffer */ + sprintf(cqi_log_buf, + "%04d,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* write back to log file */ + fm_file_write(cqi_log_path, cqi_log_buf, strlen(cqi_log_buf), &pos); + } + } else { + WCN_DBG(FM_ERR | CHIP, "smt get CQI failed\n"); + ret = -1; + } + freq += space_val; + } + fm_cb_op->cur_freq_set(0); /* avoid run too much times */ + } + WCN_DBG(FM_DBG | CHIP, "6630 cqi log done\n"); + + return ret; +} + +/* + * mt6630_GetCurRSSI - get current freq's RSSI value + * RS=RSSI + * If RS>511, then RSSI(dBm)= (RS-1024)/16*6 + * else RSSI(dBm)= RS/16*6 + */ +static signed int mt6630_GetCurRSSI(signed int *pRSSI) +{ + unsigned short tmp_reg = 0; + + /* TODO: check reg */ + fm_reg_read(FM_RSSI_IND, &tmp_reg); + tmp_reg = tmp_reg & 0x03ff; + + if (pRSSI) { + *pRSSI = (tmp_reg > 511) ? (((tmp_reg - 1024) * 6) >> 4) : ((tmp_reg * 6) >> 4); + WCN_DBG(FM_DBG | CHIP, "rssi:%d, dBm:%d\n", tmp_reg, *pRSSI); + } else { + WCN_DBG(FM_ERR | CHIP, "get rssi para error\n"); + return -FM_EPARA; + } + + return 0; +} + +static unsigned short mt6630_vol_tbl[16] = { + 0x0000, 0x0519, 0x066A, 0x0814, + 0x0A2B, 0x0CCD, 0x101D, 0x1449, + 0x198A, 0x2027, 0x287A, 0x32F5, + 0x4027, 0x50C3, 0x65AD, 0x7FFF +}; + +static signed int mt6630_SetVol(unsigned char vol) +{ + signed int ret = 0; + + /* TODO: check reg */ + vol = (vol > 15) ? 15 : vol; + ret = fm_reg_write(0x7D, mt6630_vol_tbl[vol]); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "Set vol=%d Failed\n", vol); + return ret; + } + + WCN_DBG(FM_DBG | CHIP, "Set vol=%d OK\n", vol); + + if (vol == 10) { + fm_print_cmd_fifo(); /* just for debug */ + fm_print_evt_fifo(); + } + return 0; +} + +static signed int mt6630_GetVol(unsigned char *pVol) +{ + int ret = 0; + unsigned short tmp = 0; + signed int i; + + if (pVol == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + /* TODO: check reg */ + ret = fm_reg_read(0x7D, &tmp); + if (ret) { + *pVol = 0; + WCN_DBG(FM_ERR | CHIP, "Get vol Failed\n"); + return ret; + } + + for (i = 0; i < 16; i++) { + if (mt6630_vol_tbl[i] == tmp) { + *pVol = i; + break; + } + } + + WCN_DBG(FM_DBG | CHIP, "Get vol=%d OK\n", *pVol); + return 0; +} + +static signed int mt6630_dump_reg(void) +{ + signed int i; + unsigned short TmpReg = 0; + + for (i = 0; i < 0xff; i++) { + fm_reg_read(i, &TmpReg); + WCN_DBG(FM_NTC | CHIP, "0x%02x=0x%04x\n", i, TmpReg); + } + return 0; +} + +static bool mt6630_GetMonoStereo(unsigned short *pMonoStereo) +{ +#define FM_BF_STEREO 0x1000 + unsigned short TmpReg = 0; + + /* TODO: check reg */ + if (pMonoStereo) { + fm_reg_read(FM_RSSI_IND, &TmpReg); + *pMonoStereo = (TmpReg & FM_BF_STEREO) >> 12; + } else { + WCN_DBG(FM_ERR | CHIP, "MonoStero: para err\n"); + return false; + } + + WCN_DBG(FM_DBG | CHIP, "MonoStero:0x%04x\n", *pMonoStereo); + return true; +} + +static signed int mt6630_SetMonoStereo(signed int MonoStereo) +{ + signed int ret = 0; +#define FM_FORCE_MS 0x0008 + + WCN_DBG(FM_DBG | CHIP, "set to %s\n", MonoStereo ? "mono" : "auto"); + /* TODO: check reg */ + + fm_reg_write(0x60, 0x3007); + + if (MonoStereo) + ret = fm_set_bits(0x75, FM_FORCE_MS, ~FM_FORCE_MS); + else + ret = fm_set_bits(0x75, 0x0000, ~FM_FORCE_MS); + + return ret; +} + +static signed int mt6630_GetCapArray(signed int *ca) +{ + unsigned short dataRead = 0; + unsigned short tmp = 0; + + /* TODO: check reg */ + if (ca == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_reg_read(0x60, &tmp); + fm_reg_write(0x60, tmp & 0xFFF7); /* 0x60 D3=0 */ + + fm_reg_read(0x26, &dataRead); + *ca = dataRead; + + fm_reg_write(0x60, tmp); /* 0x60 D3=1 */ + return 0; +} + +/* + * mt6630_GetCurPamd - get current freq's PAMD value + * PA=PAMD + * If PA>511 then PAMD(dB)= (PA-1024)/16*6, + * else PAMD(dB)=PA/16*6 + */ +static bool mt6630_GetCurPamd(unsigned short *pPamdLevl) +{ + unsigned short tmp_reg = 0; + unsigned short dBvalue, valid_cnt = 0; + int i, total = 0; + + for (i = 0; i < 8; i++) { + /* TODO: check reg */ + if (fm_reg_read(FM_ADDR_PAMD, &tmp_reg)) { + *pPamdLevl = 0; + return false; + } + + tmp_reg &= 0x03FF; + dBvalue = (tmp_reg > 256) ? ((512 - tmp_reg) * 6 / 16) : 0; + if (dBvalue != 0) { + total += dBvalue; + valid_cnt++; + WCN_DBG(FM_DBG | CHIP, "[%d]PAMD=%d\n", i, dBvalue); + } + fm_delayms(3); + } + if (valid_cnt != 0) + *pPamdLevl = total / valid_cnt; + else + *pPamdLevl = 0; + + WCN_DBG(FM_NTC | CHIP, "PAMD=%d\n", *pPamdLevl); + return true; +} + +static signed int MT6630_FMOverBT(bool enable) +{ + signed int ret = 0; + + WCN_DBG(FM_NTC | CHIP, "+%s():\n", __func__); + + if (enable == true) { + /* change I2S to slave mode and 48K sample rate */ + if (mt6630_I2s_Setting(FM_I2S_ON, FM_I2S_SLAVE, FM_I2S_48K)) + goto out; + WCN_DBG(FM_NTC | CHIP, "set FM via BT controller\n"); + } else if (enable == false) { + /* change I2S to master mode and 44.1K sample rate */ + if (mt6630_I2s_Setting(FM_I2S_ON, FM_I2S_MASTER, FM_I2S_44K)) + goto out; + WCN_DBG(FM_NTC | CHIP, "set FM via Host\n"); + } else { + WCN_DBG(FM_ERR | CHIP, "%s()\n", __func__); + ret = -FM_EPARA; + goto out; + } +out: + WCN_DBG(FM_NTC | CHIP, "-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +/* + * mt6630_I2s_Setting - set the I2S state on MT6630 + * @onoff - I2S on/off + * @mode - I2S mode: Master or Slave + * + * Return:0, if success; error code, if failed + */ +static signed int mt6630_I2s_Setting(signed int onoff, signed int mode, signed int sample) +{ + unsigned short tmp_state = 0; + unsigned short tmp_mode = 0; + unsigned short tmp_sample = 0; + signed int ret = 0; + + if (onoff == FM_I2S_ON) { + tmp_state = 0x0003; /* I2S enable and standard I2S mode, 0x9B D0,D1=1 */ + fm_config.aud_cfg.i2s_info.status = FM_I2S_ON; + } else if (onoff == FM_I2S_OFF) { + tmp_state = 0x0000; /* I2S off, 0x9B D0,D1=0 */ + fm_config.aud_cfg.i2s_info.status = FM_I2S_OFF; + } else { + WCN_DBG(FM_ERR | CHIP, "%s():[onoff=%d]\n", __func__, onoff); + ret = -FM_EPARA; + goto out; + } + + if (mode == FM_I2S_MASTER) { + tmp_mode = 0x0000; /* 6630 as I2S master, set 0x9B D3=0 */ + fm_config.aud_cfg.i2s_info.mode = FM_I2S_MASTER; + } else if (mode == FM_I2S_SLAVE) { + tmp_mode = 0x0008; /* 6630 as I2S slave, set 0x9B D3=1 */ + fm_config.aud_cfg.i2s_info.mode = FM_I2S_SLAVE; + } else { + WCN_DBG(FM_ERR | CHIP, "%s():[mode=%d]\n", __func__, mode); + ret = -FM_EPARA; + goto out; + } + + if (sample == FM_I2S_32K) { + tmp_sample = 0x0000; /* 6630 I2S 32KHz sample rate, 0x5F D11~12 */ + fm_config.aud_cfg.i2s_info.rate = FM_I2S_32K; + } else if (sample == FM_I2S_44K) { + tmp_sample = 0x0800; /* 6630 I2S 44.1KHz sample rate */ + fm_config.aud_cfg.i2s_info.rate = FM_I2S_44K; + } else if (sample == FM_I2S_48K) { + tmp_sample = 0x1000; /* 6630 I2S 48KHz sample rate */ + fm_config.aud_cfg.i2s_info.rate = FM_I2S_48K; + } else { + WCN_DBG(FM_ERR | CHIP, "%s():[sample=%d]\n", __func__, sample); + ret = -FM_EPARA; + goto out; + } + + ret = fm_reg_write(0x60, 0x7); + if (ret) + goto out; + + ret = fm_set_bits(0x5F, tmp_sample, 0xE7FF); + if (ret) + goto out; + + ret = fm_set_bits(0x9B, tmp_mode, 0xFFF7); + if (ret) + goto out; + + ret = fm_set_bits(0x9B, tmp_state, 0xFFFC); + if (ret) + goto out; + + /* F0.4 enable ft */ + ret = fm_set_bits(0x56, 0x1, 0xFFFE); + if (ret) + goto out; + + ret = fm_reg_write(0x60, 0xf); + if (ret) + goto out; + + WCN_DBG(FM_NTC | CHIP, "[onoff=%s][mode=%s][sample=%d](0)33KHz,(1)44.1KHz,(2)48KHz\n", + (onoff == FM_I2S_ON) ? "On" : "Off", (mode == FM_I2S_MASTER) ? "Master" : "Slave", sample); +out: + return ret; +} + +static signed int mt6630fm_get_audio_info(struct fm_audio_info_t *data) +{ + memcpy(data, &fm_config.aud_cfg, sizeof(struct fm_audio_info_t)); + return 0; +} + +static signed int mt6630_i2s_info_get(signed int *ponoff, signed int *pmode, signed int *psample) +{ + *ponoff = fm_config.aud_cfg.i2s_info.status; + *pmode = fm_config.aud_cfg.i2s_info.mode; + *psample = fm_config.aud_cfg.i2s_info.rate; + + return 0; +} + +static signed int mt6630_hw_info_get(struct fm_hw_info *req) +{ + if (req == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + req->chip_id = mt6630_hw_info.chip_id; + req->eco_ver = mt6630_hw_info.eco_ver; + req->patch_ver = mt6630_hw_info.patch_ver; + req->rom_ver = mt6630_hw_info.rom_ver; + + return 0; +} + +static signed int mt6630_pre_search(void) +{ + mt6630_RampDown(); + return 0; +} + +static signed int mt6630_restore_search(void) +{ + mt6630_RampDown(); + return 0; +} + +/* +*freq: 8750~10800 +*valid: true-valid channel,false-invalid channel +*return: true- smt success, false-smt fail +*/ +static signed int mt6630_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid) +{ + signed int ret = 0; + unsigned short pkt_size; + /* unsigned short freq;//, orig_freq; */ + struct mt6630_full_cqi *p_cqi; + signed int RSSI = 0, PAMD = 0, MR = 0, ATDC = 0; + unsigned int PRX = 0, ATDEV = 0; + unsigned short softmuteGainLvl = 0; + + ret = mt6630_chan_para_get(freq); + if (ret == 2) + ret = fm_set_bits(FM_CHANNEL_SET, 0x2000, 0x0FFF); /* mdf HiLo */ + else + ret = fm_set_bits(FM_CHANNEL_SET, 0x0000, 0x0FFF); /* clear FA/HL/ATJ */ +#if 0 + fm_reg_write(0x60, 0x0007); + if (mt6630_TDD_chan_check(freq)) + fm_set_bits(0x30, 0x0004, 0xFFF9); /* use TDD solution */ + else + fm_set_bits(0x30, 0x0000, 0xFFF9); /* default use FDD solution */ + fm_reg_write(0x60, 0x000F); +#endif + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + WCN_DBG(FM_DBG | CHIP, "smt cqi size %d\n", fm_res->cqi[0]); + p_cqi = (struct mt6630_full_cqi *)&fm_res->cqi[2]; + + RSSI = ((p_cqi->rssi & 0x03FF) >= 512) ? ((p_cqi->rssi & 0x03FF) - 1024) : (p_cqi->rssi & 0x03FF); + PAMD = ((p_cqi->pamd & 0x1FF) >= 256) ? ((p_cqi->pamd & 0x01FF) - 512) : (p_cqi->pamd & 0x01FF); + MR = ((p_cqi->mr & 0x01FF) >= 256) ? ((p_cqi->mr & 0x01FF) - 512) : (p_cqi->mr & 0x01FF); + ATDC = (p_cqi->atdc >= 32768) ? (65536 - p_cqi->atdc) : (p_cqi->atdc); + if (ATDC < 0) + ATDC = (~(ATDC)) - 1; /* Get abs value of ATDC */ + + PRX = (p_cqi->prx & 0x00FF); + ATDEV = p_cqi->atdev; + softmuteGainLvl = p_cqi->smg; + /* check if the channel is valid according to each CQIs */ + if ((fm_config.rx_cfg.long_ana_rssi_th <= RSSI) + && (fm_config.rx_cfg.pamd_th >= PAMD) + && (fm_config.rx_cfg.atdc_th >= ATDC) + && (fm_config.rx_cfg.mr_th <= MR) + && (fm_config.rx_cfg.prx_th <= PRX) + && (ATDEV >= ATDC) /* sync scan algorithm */ + && (fm_config.rx_cfg.smg_th <= softmuteGainLvl)) { + *valid = true; + } else { + *valid = false; + } + + WCN_DBG(FM_NTC | CHIP, + "valid = %d, freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", + *valid, p_cqi->ch, p_cqi->rssi, p_cqi->pamd, p_cqi->pr, p_cqi->fpamd, p_cqi->mr, + p_cqi->atdc, p_cqi->prx, p_cqi->atdev, p_cqi->smg, p_cqi->drssi); + + *rssi = RSSI; + } else { + WCN_DBG(FM_ERR | CHIP, "smt get CQI failed\n"); + return false; + } + return true; +} + +/* +*parm: +* parm.th_type: 0, RSSI. 1,desense RSSI. 2,SMG. +* parm.th_val: threshold value +*/ +static signed int mt6630_set_search_th(signed int idx, signed int val, signed int reserve) +{ + switch (idx) { + case 0: { + fm_config.rx_cfg.long_ana_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set rssi th =%d\n", val); + break; + } + case 1: { + fm_config.rx_cfg.desene_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set desense rssi th =%d\n", val); + break; + } + case 2: { + fm_config.rx_cfg.smg_th = val; + WCN_DBG(FM_NTC | CHIP, "set smg th =%d\n", val); + break; + } + default: + break; + } + return 0; +} + +#if 0 +static const unsigned short mt6630_mcu_dese_list[] = { + 0 /* 7630, 7800, 7940, 8320, 9260, 9600, 9710, 9920, 10400, 10410 */ +}; + +static const unsigned short mt6630_gps_dese_list[] = { + 0 /* 7850, 7860 */ +}; +#endif + +static const signed char mt6630_chan_para_map[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6500~6595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6600~6695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, /* 6700~6795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6800~6895 */ + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6900~6995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7000~7095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7100~7195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7200~7295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7300~7395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7400~7495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7500~7595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, /* 7600~7695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7700~7795 */ + 8, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7800~7895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7900~7995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8000~8095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8100~8195 */ + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8200~8295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, /* 8300~8395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8400~8495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8500~8595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8600~8695 */ + 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8700~8795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8800~8895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8900~8995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9000~9095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9100~9195 */ + 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9200~9295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9300~9395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9400~9495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9500~9595 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9600~9695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9700~9795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9800~9895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 9900~9995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10000~10095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10100~10195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, /* 10200~10295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, /* 10300~10395 */ + 8, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10400~10495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, /* 10500~10595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10600~10695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, /* 10700~10795 */ + 0 /* 10800 */ +}; + +static const unsigned short mt6630_TDD_list[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6500~6595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6600~6695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6700~6795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6800~6895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6900~6995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7000~7095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7100~7195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7200~7295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7300~7395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7400~7495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7500~7595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7600~7695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7700~7795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7800~7895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7900~7995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8000~8095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8100~8195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8200~8295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8300~8395 */ + 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, /* 8400~8495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8500~8595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8600~8695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8700~8795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8800~8895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8900~8995 */ + 0x0000, 0x0000, 0x0101, 0x0101, 0x0101, /* 9000~9095 */ + 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, /* 9100~9195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9200~9295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9300~9395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9400~9495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9500~9595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9600~9695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, /* 9700~9795 */ + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, /* 9800~9895 */ + 0x0101, 0x0101, 0x0001, 0x0000, 0x0000, /* 9900~9995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10000~10095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10100~10195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10200~10295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10300~10395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10400~10495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10500~10595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, /* 10600~10695 */ + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, /* 10700~10795 */ + 0x0001 /* 10800 */ +}; + +static const unsigned short mt6630_TDD_Mask[] = { + 0x0001, 0x0010, 0x0100, 0x1000 +}; + +static const unsigned short mt6630_scan_dese_list[] = { + 7800, 9210, 9220, 9600, 9980, 10400, 10750, 10760 +}; + +/* return value: 0, not a de-sense channel; 1, this is a de-sense channel; else error no */ +static signed int mt6630_is_dese_chan(unsigned short freq) +{ + signed int size; + + /* return 0;//HQA only :skip desense channel check. */ + size = ARRAY_SIZE(mt6630_scan_dese_list); + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + while (size) { + if (mt6630_scan_dese_list[size - 1] == freq) + return 1; + + size--; + } + + return 0; +} + +static bool mt6630_TDD_chan_check(unsigned short freq) +{ + unsigned int i = 0; + unsigned short freq_tmp = freq; + signed int ret = 0; + + ret = fm_get_channel_space(freq_tmp); + if (ret == 0) + freq_tmp *= 10; + else if (ret == -1) + return false; + + i = (freq_tmp - 6500) / 5; + if ((i / 4) >= ARRAY_SIZE(mt6630_TDD_list)) { + WCN_DBG(FM_ERR | CHIP, "Freq index out of range(%d),max(%zd)\n", + i / 4, ARRAY_SIZE(mt6630_TDD_list)); + return false; + } + + if (mt6630_TDD_list[i / 4] & mt6630_TDD_Mask[i % 4]) { + WCN_DBG(FM_DBG | CHIP, "Freq %d use TDD solution\n", freq); + return true; + } else + return false; +} + +/* return value: +*1, is desense channel and rssi is less than threshold; +*0, not desense channel or it is but rssi is more than threshold. +*/ +static signed int mt6630_desense_check(unsigned short freq, signed int rssi) +{ + if (mt6630_is_dese_chan(freq)) { + if (rssi < fm_config.rx_cfg.desene_rssi_th) + return 1; + + WCN_DBG(FM_DBG | CHIP, "desen_rssi %d th:%d\n", rssi, fm_config.rx_cfg.desene_rssi_th); + } + return 0; +} + +/* get channel parameter, HL side/ FA / ATJ */ +static unsigned short mt6630_chan_para_get(unsigned short freq) +{ + signed int pos, size; + + /* return 0;//for HQA only: skip FA/HL/ATJ */ + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + if (freq < 6500) + return 0; + + pos = (freq - 6500) / 5; + + size = ARRAY_SIZE(mt6630_chan_para_map); + + pos = (pos > (size - 1)) ? (size - 1) : pos; + + return mt6630_chan_para_map[pos]; +} + +static signed int mt6630_gps_dese(unsigned short freq, void *arg) +{ + enum fm_gps_desense_t state = FM_GPS_DESE_DISABLE; + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + WCN_DBG(FM_DBG | CHIP, "%s, [freq=%d]\n", __func__, (int)freq); + + if (state != FM_GPS_DESE_ENABLE) { + if ((freq >= 7800) && (freq <= 8000)) + state = FM_GPS_DESE_ENABLE; + } + /* request 6630 GPS change clk */ + if (state == FM_GPS_DESE_DISABLE) { + if (!mtk_wcn_wmt_dsns_ctrl(WMTDSNS_FM_GPS_DISABLE)) + return -1; + + return 0; + } + + if (!mtk_wcn_wmt_dsns_ctrl(WMTDSNS_FM_GPS_ENABLE)) + return -1; + + return 1; +} + +/******************************Tx function********************************************/ + +signed int mt6630_pwrup_clock_on_tx_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* B1.0 Enable digital OSC */ + pkt_size += fm_bop_write(0x60, 0x0003, &buf[pkt_size], buf_size - pkt_size); /* wr 60 3 */ + pkt_size += fm_bop_udelay(100, &buf[pkt_size], buf_size - pkt_size); /* delay 100us */ + /* B1.2 Release HW clock gating */ + pkt_size += fm_bop_write(0x60, 0x0007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 7 */ + if (fm_config.aud_cfg.aud_path == FM_AUD_ANALOG) + pkt_size += fm_bop_modify(0x61, 0xFF7F, 0x0000, &buf[pkt_size], buf_size - pkt_size); + else + pkt_size += fm_bop_modify(0x61, 0xFF7F, 0x0080, &buf[pkt_size], buf_size - pkt_size); + + /* B1.4 set TX mode: 0909 sequence */ + pkt_size += fm_bop_write(0xC7, 0x8286, &buf[pkt_size], buf_size - pkt_size); /* wr C7 8286 */ + + return pkt_size - 4; +} + +/* + * mt6630_pwrup_clock_on_tx - FM tx Digital Clock enable + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6630_pwrup_clock_on_tx(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6630_pwrup_clock_on_tx_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +signed int mt6630_pwrup_tx_deviation_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* A1 switch to host control */ + pkt_size += fm_bop_write(0x60, 0x0007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 0007 */ + /* set rgf_tx_beta_sum */ + pkt_size += fm_bop_write(0xCD, 0x72D2, &buf[pkt_size], buf_size - pkt_size); /* wr CD 72D2 */ + /* set rgf_tx_beta_diff */ + pkt_size += fm_bop_write(0xCF, 0x787B, &buf[pkt_size], buf_size - pkt_size); /* wr CF 787B */ + /* set rgf_tx_beta_rds */ + pkt_size += fm_bop_write(0xCE, 0x0785, &buf[pkt_size], buf_size - pkt_size); /* wr CE 785 */ + /* set rgf_tx_beta_pilot */ + pkt_size += fm_bop_write(0xCC, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr CC 0 */ + /* set rgf_phase_gen_rsh */ + pkt_size += fm_bop_modify(0xAD, 0xFFE8, 0x0001, &buf[pkt_size], buf_size - pkt_size); /* wr AD D4 D2:D0=1 */ + /* set rgf_phase_gen_wb */ + pkt_size += fm_bop_modify(0xA8, 0xF000, 0x0F16, &buf[pkt_size], buf_size - pkt_size); /* wr A8 D11:D0=F16 */ + /* set agc */ + pkt_size += fm_bop_modify(0xAE, 0xFC00, 0x020B, &buf[pkt_size], buf_size - pkt_size); /* wr AE D9:D0=20B */ + /* set rgf_beta_fm */ + pkt_size += fm_bop_write(0xEE, 0x623D, &buf[pkt_size], buf_size - pkt_size); /* wr EE 623D */ + /* switch to DSP control */ + pkt_size += fm_bop_write(0x60, 0x000F, &buf[pkt_size], buf_size - pkt_size); /* wr 60 000F */ + + return pkt_size - 4; +} + +/* + * mt6630_pwrup_tx_deviation - default deviation (RDS off) + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +signed int mt6630_pwrup_tx_deviation(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6630_pwrup_tx_deviation_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +signed int mt6630_tx_rdson_deviation_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* A1 switch to host control */ + pkt_size += fm_bop_write(0x60, 0x0007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 0007 */ + /* set rgf_tx_beta_sum */ + pkt_size += fm_bop_write(0xCD, 0x70E3, &buf[pkt_size], buf_size - pkt_size); /* wr CD 70E3 */ + /* set rgf_tx_beta_diff */ + pkt_size += fm_bop_write(0xCF, 0x7675, &buf[pkt_size], buf_size - pkt_size); /* wr CF 7675 */ + /* set rgf_tx_beta_rds:0909 sequence */ + pkt_size += fm_bop_write(0xCC, 0x0227, &buf[pkt_size], buf_size - pkt_size); /* wr CC 227 */ + /* set rgf_tx_beta_pilot :0909 sequence */ + pkt_size += fm_bop_write(0xCE, 0x0764, &buf[pkt_size], buf_size - pkt_size); /* wr CE 764 */ + /* set rgf_phase_gen_rsh */ + pkt_size += fm_bop_modify(0xAD, 0xFFEF, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr AD D4 =0 */ + pkt_size += fm_bop_modify(0xAD, 0xFFF8, 0x0001, &buf[pkt_size], buf_size - pkt_size); /* wr AD D2:D0=1 */ + /* set rgf_phase_gen_wb */ + pkt_size += fm_bop_modify(0xA8, 0xF000, 0x0222, &buf[pkt_size], buf_size - pkt_size); /* wr A8 D11:D0=222 */ + /* set agc */ + pkt_size += fm_bop_modify(0xAE, 0xFC00, 0x0203, &buf[pkt_size], buf_size - pkt_size); /* wr AE D9:D0=203 */ + /* set rgf_beta_fm */ + pkt_size += fm_bop_write(0xEE, 0x63EB, &buf[pkt_size], buf_size - pkt_size); /* wr EE 63EB */ + /* switch to DSP control */ + pkt_size += fm_bop_write(0x60, 0x000F, &buf[pkt_size], buf_size - pkt_size); /* wr 60 000F */ + + return pkt_size - 4; +} +/* + * mt6630_tx_rdsoff_deviation - deviation (RDS on) + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6630_tx_rdson_deviation(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6630_tx_rdson_deviation_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, RDS_TX_OPCODE, pkt_size); +} + +signed int mt6630_tune_tx_reg_op(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + freq = (freq - 6400) * 2 / 10; + /* Set desired channel & channel parameter */ +#ifdef FM_TUNE_USE_POLL + pkt_size += fm_bop_write(0x6B, 0x0000, &buf[pkt_size], buf_size - pkt_size); +#endif + /* sequence 09/16:0x65 D12=1 for iq switch */ + pkt_size += fm_bop_modify(FM_CHANNEL_SET, 0xEC00, freq | 0x1000, &buf[pkt_size], buf_size - pkt_size); + /* set 0x65[9:0] = 0x029e, => ((97.5 - 64) * 20) */ + /* set iq switch, D12 */ + /* pkt_size += fm_bop_modify(FM_CHANNEL_SET, 0x0FFF, (chan_para << 12), &buf[pkt_size], buf_size - pkt_size); */ + /* Enable hardware controlled tuning sequence */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF8, TUNE, &buf[pkt_size], buf_size - pkt_size); + /* Wait for STC_DONE interrupt */ +#ifdef FM_TUNE_USE_POLL + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size], + buf_size - pkt_size); + /* Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); +#endif + + return pkt_size - 4; +} + + +/* + * mt6630_tune_tx - execute tx tune action, + * @buf - target buf + * @buf_size - buffer size + * @freq - 760 ~ 1080, 100KHz unit + * return package size + */ +static signed int mt6630_tune_tx(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 0; + + pkt_size = mt6630_tune_tx_reg_op(buf, buf_size, freq, chan_para); + return fm_op_seq_combine_cmd(buf, FM_TUNE_OPCODE, pkt_size); +} + +signed int mt6630_rds_tx_reg_op(unsigned char *tx_buf, signed int tx_buf_size, unsigned short pi, + unsigned short *ps, unsigned short *other_rds, unsigned char other_rds_cnt) +{ + signed int pkt_size = 4; + signed int i = 0; + + if (tx_buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (tx_buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, tx_buf_size); + return -2; + } + + /* set repeat mode */ + pkt_size += fm_bop_modify(0x88, 0xFFFE, 0x0001, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size); + /* wr 88[0] = b'1, repeat mode */ + pkt_size += fm_bop_modify(0x88, 0xFFFB, 0x0004, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size); + /* wr 88[2] = b'1, PI_reg mode */ + pkt_size += fm_bop_write(0x8A, pi, &tx_buf[pkt_size], tx_buf_size - pkt_size); + /* write PI to PI_reg */ + + pkt_size += fm_bop_modify(0x88, 0xFFFD, 0x0002, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size); + /* wr 88[1] = b'1, addr from host */ + for (i = 0; i < 12; i++) { + pkt_size += fm_bop_write(0x8B, (0x0063 + i), &tx_buf[pkt_size], tx_buf_size - pkt_size); + /* 8B = mem_addr */ + pkt_size += fm_bop_write(0x8C, ps[i], &tx_buf[pkt_size], tx_buf_size - pkt_size); + /* 8C = RDS Tx data */ + } + pkt_size += fm_bop_modify(0x88, 0xFFFD, 0x0000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size); + /* wr 88[1] = b'0, clear mem_addr */ + pkt_size += fm_bop_modify(0x88, 0xFFEF, 0x0010, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size); + /* wr 88[4] = b'1, switch to ps buf */ + /* work around: write at leat one group to normal buffer, otherwise ps buffer can be sent out. */ + pkt_size += fm_bop_write(0x8C, 0, &tx_buf[pkt_size], tx_buf_size - pkt_size); + pkt_size += fm_bop_write(0x8C, 0, &tx_buf[pkt_size], tx_buf_size - pkt_size); + pkt_size += fm_bop_write(0x8C, 0, &tx_buf[pkt_size], tx_buf_size - pkt_size); + pkt_size += fm_bop_write(0x8C, 0, &tx_buf[pkt_size], tx_buf_size - pkt_size); + pkt_size += fm_bop_modify(0x88, 0xFFDF, 0x0020, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size); + /* wr 88[5] = b'1,clear in_ptr */ + pkt_size += fm_bop_modify(0x88, 0xFFDF, 0x0000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size); + /* wr 88[5] = b'0,clear in_ptr */ + + return pkt_size - 4; +} + +/* +*pi: pi code +*ps: block B,C,D +*other_rds: unused +*other_rds_cnt: unused +*/ +static signed int mt6630_rds_tx(unsigned char *tx_buf, signed int tx_buf_size, unsigned short pi, + unsigned short *ps, unsigned short *other_rds, unsigned char other_rds_cnt) +{ + signed int pkt_size = 0; + + pkt_size = mt6630_rds_tx_reg_op(tx_buf, tx_buf_size, pi, ps, other_rds, other_rds_cnt); + return fm_op_seq_combine_cmd(tx_buf, RDS_TX_OPCODE, pkt_size); +} + +static signed int mt6630_Tx_Support(signed int *sup) +{ + *sup = 1; + return 0; +} + +/* +*pi: pi code, +*ps: block B,C,D +*other_rds: NULL now +*other_rds_cnt:0 now +*/ +static signed int MT6630_lib_Rds_Tx_adapter(unsigned short pi, unsigned short *ps, unsigned short *other_rds, + unsigned char other_rds_cnt) +{ + signed int ret = 0; + unsigned short pkt_size = 0; + + WCN_DBG(FM_NTC | RDSC, + "+%s():PI=0x%04x, PS=0x%04x/0x%04x/0x%04x/0x%04x, other_rds_cnt=%d\n", __func__, + pi, ps[0], ps[1], ps[2], ps[3], other_rds_cnt); + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6630_rds_tx(cmd_buf, TX_BUF_SIZE, pi, ps, other_rds, other_rds_cnt); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_RDS_TX, SW_RETRY_CNT, RDS_TX_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + return ret; +} + +/* +*freq: 8750~10800 +*valid: true-valid channel,false-invalid channel +*return: true- smt success, false-smt fail +*/ +static signed int mt6630_soft_mute_tune_Tx(unsigned short freq, signed int *rssi, bool *valid) +{ + signed int ret = 0; + unsigned short pkt_size; + struct mt6630_full_cqi *p_cqi; + signed int RSSI = 0, PAMD = 0, MR = 0, ATDC = 0; + unsigned int PRX = 0, ATDEV = 0; + unsigned short softmuteGainLvl = 0; + + ret = mt6630_chan_para_get(freq); + if (ret == 2) + ret = fm_set_bits(FM_CHANNEL_SET, 0x2000, 0x0FFF); /* mdf HiLo */ + else + ret = fm_set_bits(FM_CHANNEL_SET, 0x0000, 0x0FFF); /* clear FA/HL/ATJ */ + + fm_reg_write(0x60, 0x0007); + if (mt6630_TDD_chan_check(freq)) + fm_set_bits(0x30, 0x0004, 0xFFF9); /* use TDD solution */ + else + fm_set_bits(0x30, 0x0000, 0xFFF9); /* default use FDD solution */ + fm_reg_write(0x60, 0x000F); + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + WCN_DBG(FM_NTC | CHIP, "smt cqi size %d\n", fm_res->cqi[0]); + p_cqi = (struct mt6630_full_cqi *)&fm_res->cqi[2]; + /* just for debug */ + WCN_DBG(FM_NTC | CHIP, + "freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", + p_cqi->ch, p_cqi->rssi, p_cqi->pamd, p_cqi->pr, p_cqi->fpamd, p_cqi->mr, + p_cqi->atdc, p_cqi->prx, p_cqi->atdev, p_cqi->smg, p_cqi->drssi); + RSSI = ((p_cqi->rssi & 0x03FF) >= 512) ? ((p_cqi->rssi & 0x03FF) - 1024) : (p_cqi->rssi & 0x03FF); + PAMD = ((p_cqi->pamd & 0x1FF) >= 256) ? ((p_cqi->pamd & 0x01FF) - 512) : (p_cqi->pamd & 0x01FF); + MR = ((p_cqi->mr & 0x01FF) >= 256) ? ((p_cqi->mr & 0x01FF) - 512) : (p_cqi->mr & 0x01FF); + ATDC = (p_cqi->atdc >= 32768) ? (65536 - p_cqi->atdc) : (p_cqi->atdc); + if (ATDC < 0) + ATDC = (~(ATDC)) - 1; /* Get abs value of ATDC */ + + PRX = (p_cqi->prx & 0x00FF); + ATDEV = p_cqi->atdev; + softmuteGainLvl = p_cqi->smg; + /* check if the channel is valid according to each CQIs */ + if ((fm_config.tx_cfg.pamd_th < PAMD) + && (fm_config.tx_cfg.mr_th >= MR) + && (fm_config.tx_cfg.smg_th > softmuteGainLvl)) + *valid = true; + else + *valid = false; + + *rssi = RSSI; + } else { + WCN_DBG(FM_ERR | CHIP, "smt get CQI failed\n"); + return false; + } + WCN_DBG(FM_NTC | CHIP, "valid=%d\n", *valid); + return true; +} + +#define TX_ABANDON_BAND_LOW1 7320 +#define TX_ABANDON_BAND_HIGH1 7450 +#define TX_ABANDON_BAND_LOW2 9760 +#define TX_ABANDON_BAND_HIGH2 9940 +static signed int mt6630_TxScan(unsigned short min_freq, unsigned short max_freq, unsigned short *pFreq, + unsigned short *pScanTBL, unsigned short *ScanTBLsize, unsigned short scandir, + unsigned short space) +{ + signed int i = 0, ret = 0; + unsigned short freq = *pFreq; + unsigned short scan_cnt = *ScanTBLsize; + unsigned short cnt = 0; + signed int rssi = 0; + signed int step; + bool valid = false; + signed int total_no = 0; + + WCN_DBG(FM_NTC | CHIP, "+%s():\n", __func__); + + if ((!pScanTBL) || (*ScanTBLsize < FM_TX_SCAN_MIN) || (*ScanTBLsize > FM_TX_SCAN_MAX)) { + WCN_DBG(FM_ERR | CHIP, "invalid scan table\n"); + ret = -FM_EPARA; + return 1; + } + if (fm_get_channel_space(freq) == 0) + *pFreq *= 10; + + if (fm_get_channel_space(max_freq) == 0) + max_freq *= 10; + + if (fm_get_channel_space(min_freq) == 0) + min_freq *= 10; + + WCN_DBG(FM_NTC | CHIP, + "[freq=%d], [max_freq=%d],[min_freq=%d],[scan BTL size=%d],[scandir=%d],[space=%d]\n", + *pFreq, max_freq, min_freq, *ScanTBLsize, scandir, space); + + cnt = 0; + if (space == FM_SPACE_200K) + step = 20; + else if (space == FM_SPACE_50K) + step = 5; + else + step = 10; + + total_no = (max_freq - min_freq) / step + 1; + if (scandir == FM_TX_SCAN_UP) { + for (i = ((*pFreq - min_freq) / step); i < total_no; i++) { + freq = min_freq + step * i; + + /* FM desense GPS */ + if ((freq >= TX_ABANDON_BAND_LOW1) && (freq <= TX_ABANDON_BAND_HIGH1)) { + freq = TX_ABANDON_BAND_HIGH1 + 10; + i = (freq - min_freq) / step; + } + + if ((freq >= TX_ABANDON_BAND_LOW2) && (freq <= TX_ABANDON_BAND_HIGH2)) { + freq = TX_ABANDON_BAND_HIGH2 + 10; + i = (freq - min_freq) / step; + } + + ret = mt6630_soft_mute_tune_Tx(freq, &rssi, &valid); + if (ret == false) { + WCN_DBG(FM_ERR | CHIP, "mt6630_soft_mute_tune_tx failed\n"); + return 1; + } + + if (valid == true) { + *(pScanTBL + cnt) = freq; /* strore the valid empty channel */ + cnt++; + WCN_DBG(FM_NTC | CHIP, "empty channel:[freq=%d] [cnt=%d]\n", freq, cnt); + } + if (cnt >= scan_cnt) + break; + } + + if (cnt < scan_cnt) { + for (i = 0; i < ((*pFreq - min_freq) / step); i++) { + freq = min_freq + step * i; + + /* FM desense GPS */ + if ((freq >= TX_ABANDON_BAND_LOW1) && (freq <= TX_ABANDON_BAND_HIGH1)) { + freq = TX_ABANDON_BAND_HIGH1 + 10; + i = (freq - min_freq) / step; + } + + if ((freq >= TX_ABANDON_BAND_LOW2) && (freq <= TX_ABANDON_BAND_HIGH2)) { + freq = TX_ABANDON_BAND_HIGH2 + 10; + i = (freq - min_freq) / step; + } + + if (i >= ((*pFreq - min_freq) / step)) + break; + + ret = mt6630_soft_mute_tune_Tx(freq, &rssi, &valid); + if (ret == false) { + WCN_DBG(FM_ERR | CHIP, "mt6630_soft_mute_tune failed\n"); + return 1; + } + + if (valid == true) { + *(pScanTBL + cnt) = freq; /* strore the valid empty channel */ + cnt++; + WCN_DBG(FM_NTC | CHIP, "empty channel:[freq=%d] [cnt=%d]\n", freq, cnt); + } + if (cnt >= scan_cnt) + break; + } + } + } else { + for (i = ((*pFreq - min_freq) / step - 1); i >= 0; i--) { + freq = min_freq + step * i; + + /* FM desense GPS */ + if ((freq >= TX_ABANDON_BAND_LOW1) && (freq <= TX_ABANDON_BAND_HIGH1)) { + freq = TX_ABANDON_BAND_LOW1 - 10; + i = (freq - min_freq) / step; + } + + if ((freq >= TX_ABANDON_BAND_LOW2) && (freq <= TX_ABANDON_BAND_HIGH2)) { + freq = TX_ABANDON_BAND_LOW2 - 10; + i = (freq - min_freq) / step; + } + + ret = mt6630_soft_mute_tune_Tx(freq, &rssi, &valid); + if (ret == false) { + WCN_DBG(FM_ERR | CHIP, "mt6630_soft_mute_tune failed\n"); + return 1; + } + + if (valid == true) { + *(pScanTBL + cnt) = freq; /* strore the valid empty channel */ + cnt++; + WCN_DBG(FM_NTC | CHIP, "empty channel:[freq=%d] [cnt=%d]\n", freq, cnt); + } + if (cnt >= scan_cnt) + break; + } + if (cnt < scan_cnt) { + for (i = (total_no - 1); i > ((*pFreq - min_freq) / step); i--) { + freq = min_freq + step * i; + + /* FM desense GPS */ + if ((freq >= TX_ABANDON_BAND_LOW1) && (freq <= TX_ABANDON_BAND_HIGH1)) { + freq = TX_ABANDON_BAND_LOW1 - 10; + i = (freq - min_freq) / step; + } + + if ((freq >= TX_ABANDON_BAND_LOW2) && (freq <= TX_ABANDON_BAND_HIGH2)) { + freq = TX_ABANDON_BAND_LOW2 - 10; + i = (freq - min_freq) / step; + } + + if (i <= ((*pFreq - min_freq) / step)) + break; + + ret = mt6630_soft_mute_tune_Tx(freq, &rssi, &valid); + if (ret == false) { + WCN_DBG(FM_ERR | CHIP, "mt6630_soft_mute_tune failed\n"); + return 1; + } + + if (valid == true) { + *(pScanTBL + cnt) = freq; /* strore the valid empty channel */ + cnt++; + WCN_DBG(FM_NTC | CHIP, "empty channel:[freq=%d] [cnt=%d]\n", freq, cnt); + } + if (cnt >= scan_cnt) + break; + } + } + } + + *ScanTBLsize = cnt; + WCN_DBG(FM_NTC | CHIP, "completed, [cnt=%d],[freq=%d]\n", cnt, freq); + /* return 875~1080 */ + for (i = 0; i < cnt; i++) { + if (fm_get_channel_space(*(pScanTBL + i)) == 1 && space != FM_SPACE_50K) + *(pScanTBL + i) = *(pScanTBL + i) / 10; + } + WCN_DBG(FM_NTC | CHIP, "-%s():[ret=%d]\n", __func__, ret); + return 0; +} + +static signed int mt6630_PowerUpTx(void) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short dataRead = 0; + + WCN_DBG(FM_NTC | CHIP, "pwr on Tx seq......\n"); + + ret = mt6630_pwrup_top_setting(); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6630_pwrup_top_setting failed\n"); + return ret; + } + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + + pkt_size = mt6630_pwrup_clock_on_tx(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6630_pwrup_clock_on_tx failed\n"); + return ret; + } + + fm_reg_read(0x62, &dataRead); + WCN_DBG(FM_NTC | CHIP, "Tx on chipid=%x\n", dataRead); + + ret = mt6630_pwrup_DSP_download(mt6630_patch_tbl_tx); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6630_pwrup_DSP_download failed\n"); + return ret; + } + + if ((fm_config.aud_cfg.aud_path == FM_AUD_MRGIF) + || (fm_config.aud_cfg.aud_path == FM_AUD_I2S)) { + mt6630_I2s_Setting(FM_I2S_ON, fm_config.aud_cfg.i2s_info.mode, + fm_config.aud_cfg.i2s_info.rate); + /* mtk_wcn_cmb_stub_audio_ctrl((CMB_STUB_AIF_X)CMB_STUB_AIF_2);//no need to do? */ + WCN_DBG(FM_NTC | CHIP, "pwron set I2S on ok\n"); + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + + pkt_size = mt6630_pwrup_digital_init(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6630_dig_init failed\n"); + return ret; + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + + pkt_size = mt6630_tx_rdson_deviation(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_RDS_TX, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6630_tx_rdson_deviation failed\n"); + return ret; + } + + WCN_DBG(FM_DBG | CHIP, "pwr on tx seq ok\n"); + return ret; +} + +static signed int mt6630_PowerDownTx(void) +{ + signed int ret = 0; + + ret = mt6630_PowerDown(); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6630_PowerDownTx failed\n"); + return ret; + } + + return ret; +} + +static unsigned short mt6630_Hside_list_Tx[] = { 7720, 8045 }; + +static bool mt6630_HiSide_chan_check_Tx(unsigned short freq) +{ + /* signed int pos, size; */ + unsigned int i = 0, count = 0; + + /* return 0;//for HQA only: skip FA/HL/ATJ */ + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + if (freq < 6500) + return false; + + count = ARRAY_SIZE(mt6630_Hside_list_Tx); + for (i = 0; i < count; i++) { + if (freq == mt6630_Hside_list_Tx[i]) + return true; + } + + return false; +} + +static bool MT6630_SetFreq_Tx(unsigned short freq) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short chan_para = 0; + unsigned short dataRead = 0; + + /* repeat tune due to audio noise workaround */ + fm_reg_read(0x63, &dataRead); + fm_reg_read(0x61, &dataRead); + fm_reg_write(0x63, 0x0); + fm_reg_write(0x61, 0x81); + fm_reg_write(0x61, 0x83); + fm_reg_write(0x61, 0x82); + /*fm_reg_write(0x69, 0x1);*/ + do { + fm_reg_read(0x64, &dataRead); + WCN_DBG(FM_DBG | CHIP, "dataRead = %d\n", dataRead); + } while (dataRead != 2); + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + + pkt_size = mt6630_tx_rdson_deviation(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_RDS_TX, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6630_tx_rdson_deviation failed\n"); + return ret; + } + /* repeat tune due to audio noise workaround end */ + + ret = mt6630_RampDown(); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6630_RampDown failed\n"); + return ret; + } + + if (true == mt6630_HiSide_chan_check_Tx(freq)) { + WCN_DBG(FM_DBG | CHIP, "%d chan para = %d\n", (signed int) freq, (signed int) chan_para); + ret = fm_set_bits(FM_CHANNEL_SET, 0x2000, 0x0FFF); /* mdf HiLo */ + } else + ret = fm_set_bits(FM_CHANNEL_SET, 0x0000, 0xEFFF); /* clear HiLo */ + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "fm_set_bits failed\n"); + return ret; + } + /* fm_cb_op->cur_freq_set(freq); */ + /* start tune */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6630_tune_tx(cmd_buf, TX_BUF_SIZE, freq, 0); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE | FLAG_TUNE_DONE, SW_RETRY_CNT, TUNE_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6630_tune_tx failed\n"); + return ret; + } + + WCN_DBG(FM_DBG | CHIP, "mt6630_tune_tx to %d ok\n", freq); + + return true; +} + +signed int fm_low_ops_register(struct fm_callback *cb, struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,bi invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_get == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_get invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_set == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_set invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_cb_op = cb; + + bi->pwron = mt6630_pwron; + bi->pwroff = mt6630_pwroff; + bi->chipid_get = mt6630_get_chipid; + bi->mute = mt6630_Mute; + bi->rampdown = mt6630_RampDown; + bi->pwrupseq = mt6630_PowerUp; + bi->pwrdownseq = mt6630_PowerDown; + bi->setfreq = mt6630_SetFreq; + /* bi->low_pwr_wa = MT6630fm_low_power_wa_default; */ + bi->i2s_set = mt6630_I2s_Setting; + bi->rssiget = mt6630_GetCurRSSI; + bi->volset = mt6630_SetVol; + bi->volget = mt6630_GetVol; + bi->dumpreg = mt6630_dump_reg; + bi->msget = mt6630_GetMonoStereo; + bi->msset = mt6630_SetMonoStereo; + bi->pamdget = mt6630_GetCurPamd; + /* bi->em = mt6630_em_test; */ + bi->anaswitch = mt6630_SetAntennaType; + bi->anaget = mt6630_GetAntennaType; + bi->caparray_get = mt6630_GetCapArray; + bi->hwinfo_get = mt6630_hw_info_get; + bi->fm_via_bt = MT6630_FMOverBT; + bi->i2s_get = mt6630_i2s_info_get; + bi->is_dese_chan = mt6630_is_dese_chan; + bi->softmute_tune = mt6630_soft_mute_tune; + bi->desense_check = mt6630_desense_check; + bi->cqi_log = mt6630_full_cqi_get; + bi->pre_search = mt6630_pre_search; + bi->restore_search = mt6630_restore_search; + bi->set_search_th = mt6630_set_search_th; + bi->get_aud_info = mt6630fm_get_audio_info; + /*****tx function****/ + bi->tx_support = mt6630_Tx_Support; + bi->pwrupseq_tx = mt6630_PowerUpTx; + bi->tune_tx = MT6630_SetFreq_Tx; + bi->pwrdownseq_tx = mt6630_PowerDownTx; + bi->tx_scan = mt6630_TxScan; + /* need call fm link/cmd */ + bi->rds_tx_adapter = MT6630_lib_Rds_Tx_adapter; + /* bi->tx_pwr_ctrl = MT6630_TX_PWR_CTRL; */ + /* bi->rtc_drift_ctrl = MT6630_RTC_Drift_CTRL; */ + /* bi->tx_desense_wifi = MT6630_TX_DESENSE; */ + + cmd_buf_lock = fm_lock_create("30_cmd"); + ret = fm_lock_get(cmd_buf_lock); + + cmd_buf = fm_zalloc(TX_BUF_SIZE + 1); + + if (!cmd_buf) { + WCN_DBG(FM_ERR | CHIP, "6630 fm lib alloc tx buf failed\n"); + ret = -1; + } + + return ret; +} + +signed int fm_low_ops_unregister(struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (cmd_buf) { + fm_free(cmd_buf); + cmd_buf = NULL; + } + + ret = fm_lock_put(cmd_buf_lock); + fm_memset(bi, 0, sizeof(struct fm_basic_interface)); + return ret; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6630/pub/mt6630_fm_rds.c b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6630/pub/mt6630_fm_rds.c new file mode 100644 index 00000000000000..5f413c6a50de08 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6630/pub/mt6630_fm_rds.c @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_rds.h" +#include "mt6630_fm_reg.h" +#include "fm_cmd.h" + +static bool bRDS_FirstIn; /* false */ +static unsigned int gBLER_CHK_INTERVAL = 500; +static unsigned short GOOD_BLK_CNT = 0, BAD_BLK_CNT; +static unsigned char BAD_BLK_RATIO; + +static struct fm_basic_interface *fm_bi; + +static bool mt6630_RDS_support(void); +static signed int mt6630_RDS_enable(void); +static signed int mt6630_RDS_disable(void); +static unsigned short mt6630_RDS_Get_GoodBlock_Counter(void); +static unsigned short mt6630_RDS_Get_BadBlock_Counter(void); +static unsigned char mt6630_RDS_Get_BadBlock_Ratio(void); +static unsigned int mt6630_RDS_Get_BlerCheck_Interval(void); +/* static void mt6630_RDS_GetData(unsigned short *data, unsigned short datalen); */ +static void mt6630_RDS_Init_Data(struct rds_t *pstRDSData); + +static bool mt6630_RDS_support(void) +{ + return true; +} + +static signed int mt6630_RDS_enable(void) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | RDSC, "rds enable\n"); + /* ret = fm_reg_read(FM_RDS_CFG0, &dataRead); */ + ret = fm_reg_write(FM_RDS_CFG0, 6); /* set buf_start_th */ + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable write 0x80 fail\n"); + return ret; + } + ret = fm_reg_read(FM_MAIN_CTRL, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable read 0x63 fail\n"); + return ret; + } + ret = fm_reg_write(FM_MAIN_CTRL, dataRead | (RDS_MASK)); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable write 0x63 fail\n"); + return ret; + } + + return ret; +} + +static signed int mt6630_RDS_disable(void) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | RDSC, "rds disable\n"); + ret = fm_reg_read(FM_MAIN_CTRL, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds disable read 0x63 fail\n"); + return ret; + } + ret = fm_reg_write(FM_MAIN_CTRL, dataRead & (~RDS_MASK)); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds disable write 0x63 fail\n"); + return ret; + } + + return ret; +} + +static unsigned short mt6630_RDS_Get_GoodBlock_Counter(void) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RDS_GOODBK_CNT, &tmp_reg); + GOOD_BLK_CNT = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get good block cnt:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static unsigned short mt6630_RDS_Get_BadBlock_Counter(void) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RDS_BADBK_CNT, &tmp_reg); + BAD_BLK_CNT = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get bad block cnt:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static unsigned char mt6630_RDS_Get_BadBlock_Ratio(void) +{ + unsigned short tmp_reg; + unsigned short gbc; + unsigned short bbc; + + gbc = mt6630_RDS_Get_GoodBlock_Counter(); + bbc = mt6630_RDS_Get_BadBlock_Counter(); + + if ((gbc + bbc) > 0) + tmp_reg = (unsigned char) (bbc * 100 / (gbc + bbc)); + else + tmp_reg = 0; + + BAD_BLK_RATIO = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get badblock ratio:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static signed int mt6630_RDS_BlockCounter_Reset(void) +{ + mt6630_RDS_disable(); + mt6630_RDS_enable(); + + return 0; +} + +static unsigned int mt6630_RDS_Get_BlerCheck_Interval(void) +{ + return gBLER_CHK_INTERVAL; +} + +static signed int mt6630_RDS_BlerCheck(struct rds_t *dst) +{ + return 0; +} + +#if 0 +static void RDS_Recovery_Handler(void) +{ + unsigned short tempData = 0; + + do { + fm_reg_read(FM_RDS_DATA_REG, &tempData); + fm_reg_read(FM_RDS_POINTER, &tempData); + } while (tempData & 0x3); +} +#endif + +#if 0 +static void mt6630_RDS_GetData(unsigned short *data, unsigned short datalen) +{ +#define RDS_GROUP_DIFF_OFS 0x007C +#define RDS_FIFO_DIFF 0x007F +#define RDS_CRC_BLK_ADJ 0x0020 +#define RDS_CRC_CORR_CNT 0x001E +#define RDS_CRC_INFO 0x0001 + + unsigned short CRC = 0, i = 0, RDS_adj = 0, RDSDataCount = 0, FM_WARorrCnt = 0; + unsigned short temp = 0, OutputPofm_s32 = 0; + + WCN_DBG(FM_DBG | RDSC, "get data\n"); + fm_reg_read(FM_RDS_FIFO_STATUS0, &temp); + RDSDataCount = ((RDS_GROUP_DIFF_OFS & temp) << 2); + + if ((temp & RDS_FIFO_DIFF) >= 4) { + /* block A data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 10; + CRC |= (temp & RDS_CRC_INFO) << 3; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 11); + fm_reg_read(FM_RDS_DATA_REG, &data[0]); + + /* block B data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 9; + CRC |= (temp & RDS_CRC_INFO) << 2; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 7); + fm_reg_read(FM_RDS_DATA_REG, &data[1]); + + /* block C data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 8; + CRC |= (temp & RDS_CRC_INFO) << 1; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 3); + fm_reg_read(FM_RDS_DATA_REG, &data[2]); + + /* block D data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 7; + CRC |= (temp & RDS_CRC_INFO); + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) >> 1); + fm_reg_read(FM_RDS_DATA_REG, &data[3]); + + data[4] = (CRC | RDS_adj | RDSDataCount); + data[5] = FM_WARorrCnt; + + fm_reg_read(FM_RDS_PWDI, &data[6]); + fm_reg_read(FM_RDS_PWDQ, &data[7]); + + fm_reg_read(FM_RDS_POINTER, &OutputPofm_s32); + + /* Go fm_s32o RDS recovery handler while RDS output pofm_s32 doesn't align to 4 in numeric */ + if (OutputPofm_s32 & 0x3) + RDS_Recovery_Handler(); + + } else { + for (; i < 8; i++) + data[i] = 0; + } +} +#endif + +static signed int mt6630_rdsTx_Support(signed int *sup) +{ + *sup = 1; + return 0; +} + +static signed int mt6630_Rds_Tx_Enable(void) +{ + fm_set_bits(0xC7, 0x0800, 0xF7FF); + return 0; +} + +static signed int mt6630_Rds_Tx_Disable(void) +{ + fm_set_bits(0xC7, 0x0000, 0xF7FF); + return 0; +} + +/* +*pi: pi code, +*ps: block B,C,D +*other_rds: NULL now +*other_rds_cnt:0 now +*/ +static signed int mt6630_Rds_Tx(unsigned short pi, unsigned short *ps, unsigned short *other_rds, + unsigned char other_rds_cnt) +{ + return fm_bi->rds_tx_adapter(pi, ps, other_rds, other_rds_cnt); +} + +static void mt6630_RDS_Init_Data(struct rds_t *pstRDSData) +{ + fm_memset(pstRDSData, 0, sizeof(struct rds_t)); + bRDS_FirstIn = true; + + fm_memset(pstRDSData->RT_Data.TextData, 0x20, sizeof(pstRDSData->RT_Data.TextData)); + fm_memset(pstRDSData->PS_Data.PS, '\0', sizeof(pstRDSData->PS_Data.PS)); + fm_memset(pstRDSData->PS_ON, 0x20, sizeof(pstRDSData->PS_ON)); +} + +bool mt6630_RDS_OnOff(struct rds_t *dst, bool bFlag) +{ + signed int ret = 0; + + if (mt6630_RDS_support() == false) { + WCN_DBG(FM_ALT | RDSC, "mt6630_RDS_OnOff failed, RDS not support\n"); + return false; + } + + if (bFlag) { + mt6630_RDS_Init_Data(dst); + ret = mt6630_RDS_enable(); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "mt6630_RDS_OnOff enable failed\n"); + return false; + } + } else { + ret = mt6630_RDS_disable(); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "mt6630_RDS_OnOff disable failed\n"); + return false; + } + } + + return true; +} + +DEFINE_RDSLOG(mt6630_rds_log); + +/* mt6630_RDS_Efm_s32_Handler - response FM RDS interrupt + * @fm - main data structure of FM driver + * This function first get RDS raw data, then call RDS spec parser + */ +static signed int mt6630_rds_parser(struct rds_t *rds_dst, struct rds_rx_t *rds_raw, + signed int rds_size, unsigned short(*getfreq) (void)) +{ + mt6630_rds_log.log_in(&mt6630_rds_log, rds_raw, rds_size); + return rds_parser(rds_dst, rds_raw, rds_size, getfreq); +} + +static signed int mt6630_rds_log_get(struct rds_rx_t *dst, signed int *dst_len) +{ + return mt6630_rds_log.log_out(&mt6630_rds_log, dst, dst_len); +} + +static signed int mt6630_rds_gc_get(struct rds_group_cnt_t *dst, struct rds_t *rdsp) +{ + return rds_grp_counter_get(dst, &rdsp->gc); +} + +static signed int mt6630_rds_gc_reset(struct rds_t *rdsp) +{ + return rds_grp_counter_reset(&rdsp->gc); +} + +signed int fm_rds_ops_register(struct fm_basic_interface *bi, struct fm_rds_interface *ri) +{ + signed int ret = 0; + + if (ri == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,ri invalid pointer\n", __func__); + return -FM_EPARA; + } + if (bi->rds_tx_adapter == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,bi->rds_tx_adapter invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_bi = bi; + + ri->rds_blercheck = mt6630_RDS_BlerCheck; + ri->rds_onoff = mt6630_RDS_OnOff; + ri->rds_parser = mt6630_rds_parser; + ri->rds_gbc_get = mt6630_RDS_Get_GoodBlock_Counter; + ri->rds_bbc_get = mt6630_RDS_Get_BadBlock_Counter; + ri->rds_bbr_get = mt6630_RDS_Get_BadBlock_Ratio; + ri->rds_bc_reset = mt6630_RDS_BlockCounter_Reset; + ri->rds_bci_get = mt6630_RDS_Get_BlerCheck_Interval; + ri->rds_log_get = mt6630_rds_log_get; + ri->rds_gc_get = mt6630_rds_gc_get; + ri->rds_gc_reset = mt6630_rds_gc_reset; + ri->rdstx_support = mt6630_rdsTx_Support; + ri->rds_tx_enable = mt6630_Rds_Tx_Enable; + ri->rds_tx_disable = mt6630_Rds_Tx_Disable; + ri->rds_tx = mt6630_Rds_Tx; + + return ret; +} + +signed int fm_rds_ops_unregister(struct fm_rds_interface *ri) +{ + signed int ret = 0; + + if (ri == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,ri invalid pointer\n", __func__); + return -FM_EPARA; + } + + fm_bi = NULL; + fm_memset(ri, 0, sizeof(struct fm_rds_interface)); + return ret; +} + diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6631/inc/mt6631_fm_lib.h b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6631/inc/mt6631_fm_lib.h new file mode 100644 index 00000000000000..3a8839e250dcf2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6631/inc/mt6631_fm_lib.h @@ -0,0 +1,68 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ +#ifndef __MT6631_FM_LIB_H__ +#define __MT6631_FM_LIB_H__ + +#include "fm_typedef.h" + +enum { + DSPPATCH = 0xFFF9, + USDELAY = 0xFFFA, + MSDELAY = 0xFFFB, + HW_VER = 0xFFFD, + POLL_N = 0xFFFE, /* poling check if bit(n) is '0' */ + POLL_P = 0xFFFF, /* polling check if bit(n) is '1' */ +}; + +enum { + FM_PUS_DSPPATCH = DSPPATCH, + FM_PUS_USDELAY = USDELAY, + FM_PUS_MSDELAY = MSDELAY, + FM_PUS_HW_VER = HW_VER, + FM_PUS_POLL_N = POLL_N, /* poling check if bit(n) is '0' */ + FM_PUS_POLL_P = POLL_P, /* polling check if bit(n) is '1' */ + FM_PUS_MAX +}; + +enum { + mt6631_E1 = 0, + mt6631_E2 +}; + +struct mt6631_fm_cqi { + unsigned short ch; + unsigned short rssi; + unsigned short reserve; +}; + +struct adapt_fm_cqi { + signed int ch; + signed int rssi; + signed int reserve; +}; + +struct mt6631_full_cqi { + unsigned short ch; + unsigned short rssi; + unsigned short pamd; + unsigned short pr; + unsigned short fpamd; + unsigned short mr; + unsigned short atdc; + unsigned short prx; + unsigned short atdev; + unsigned short smg; /* soft-mute gain */ + unsigned short drssi; /* delta rssi */ +}; + +#endif diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6631/inc/mt6631_fm_reg.h b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6631/inc/mt6631_fm_reg.h new file mode 100644 index 00000000000000..d4ff954759f659 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6631/inc/mt6631_fm_reg.h @@ -0,0 +1,57 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ +#ifndef __MT6631_FM_REG_H__ +#define __MT6631_FM_REG_H__ + +/* RDS_BDGRP_ABD_CTRL_REG */ +enum { + BDGRP_ABD_EN = 0x0001, + BER_RUN = 0x2000 +}; +#define FM_DAC_CON1 0x83 +#define FM_DAC_CON2 0x84 +#define FM_FT_CON0 0x86 +enum { + FT_EN = 0x0001 +}; + +#define FM_I2S_CON0 0x90 +enum { + I2S_EN = 0x0001, + FORMAT = 0x0002, + WLEN = 0x0004, + I2S_SRC = 0x0008 +}; + +/* FM_MAIN_CTRL */ +enum { + TUNE = 0x0001, + SEEK = 0x0002, + SCAN = 0x0004, + CQI_READ = 0x0008, + RDS_MASK = 0x0010, + MUTE = 0x0020, + RDS_BRST = 0x0040, + RAMP_DOWN = 0x0100, +}; + +enum { + ANTENNA_TYPE = 0x0010, /* 0x61 D4, 0:long, 1:short */ + ANALOG_I2S = 0x0080, /* 0x61 D7, 0:lineout, 1:I2S */ + DE_EMPHASIS = 0x1000, /* 0x61 D12,0:50us, 1:75 us */ +}; + +#define OSC_FREQ_BITS 0x0070 /* 0x60 bit4~6 */ +#define OSC_FREQ_MASK (~OSC_FREQ_BITS) + +#endif /* __MT6631_FM_REG_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6631/pub/mt6631_fm_lib.c b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6631/pub/mt6631_fm_lib.c new file mode 100644 index 00000000000000..cd18caae716521 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6631/pub/mt6631_fm_lib.c @@ -0,0 +1,2241 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ +#include <linux/slab.h> +#include <linux/vmalloc.h> + +#include "osal_typedef.h" +#include "stp_exp.h" +#include "wmt_exp.h" + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_patch.h" +#include "fm_utils.h" +#include "fm_link.h" +#include "fm_config.h" +#include "fm_cmd.h" + +#include "mt6631_fm_reg.h" +#include "mt6631_fm_lib.h" + +#define HQA_RETURN_ZERO_MAP 0 +#define HQA_ZERO_DESENSE_MAP 0 + +/* #include "mach/mt_gpio.h" */ + +/* #define MT6631_FM_PATCH_PATH "/etc/firmware/mt6631/mt6631_fm_patch.bin" */ +/* #define MT6631_FM_COEFF_PATH "/etc/firmware/mt6631/mt6631_fm_coeff.bin" */ +/* #define MT6631_FM_HWCOEFF_PATH "/etc/firmware/mt6631/mt6631_fm_hwcoeff.bin" */ +/* #define MT6631_FM_ROM_PATH "/etc/firmware/mt6631/mt6631_fm_rom.bin" */ + +static struct fm_patch_tbl mt6631_patch_tbl[5] = { + {FM_ROM_V1, "mt6631_fm_v1_patch.bin", "mt6631_fm_v1_coeff.bin", NULL, NULL}, + {FM_ROM_V2, "mt6631_fm_v2_patch.bin", "mt6631_fm_v2_coeff.bin", NULL, NULL}, + {FM_ROM_V3, "mt6631_fm_v3_patch.bin", "mt6631_fm_v3_coeff.bin", NULL, NULL}, + {FM_ROM_V4, "mt6631_fm_v4_patch.bin", "mt6631_fm_v4_coeff.bin", NULL, NULL}, + {FM_ROM_V5, "mt6631_fm_v5_patch.bin", "mt6631_fm_v5_coeff.bin", NULL, NULL} +}; + +static struct fm_hw_info mt6631_hw_info = { + .chip_id = 0x00006631, + .eco_ver = 0x00000000, + .rom_ver = 0x00000000, + .patch_ver = 0x00000000, + .reserve = 0x00000000, +}; + +unsigned char *cmd_buf; +struct fm_lock *cmd_buf_lock; +struct fm_res_ctx *fm_res; +static struct fm_callback *fm_cb_op; + +/* static signed int Chip_Version = mt6631_E1; */ + +/* static bool rssi_th_set = false; */ + +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ +static struct fm_fifo *cqi_fifo; +#endif +static signed int mt6631_is_dese_chan(unsigned short freq); + +#if 0 +static signed int mt6631_mcu_dese(unsigned short freq, void *arg); +static signed int mt6631_gps_dese(unsigned short freq, void *arg); +static signed int mt6631_I2s_Setting(signed int onoff, signed int mode, signed int sample); +#endif +static unsigned short mt6631_chan_para_get(unsigned short freq); +static signed int mt6631_desense_check(unsigned short freq, signed int rssi); +static bool mt6631_TDD_chan_check(unsigned short freq); +static bool mt6631_SPI_hopping_check(unsigned short freq); +static signed int mt6631_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid); +static signed int mt6631_pwron(signed int data) +{ + if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM) == MTK_WCN_BOOL_FALSE) { + WCN_DBG(FM_ERR | CHIP, "WMT turn on FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn on FM OK!\n"); + return 0; +} + +static signed int mt6631_pwroff(signed int data) +{ + if (mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM) == MTK_WCN_BOOL_FALSE) { + WCN_DBG(FM_ERR | CHIP, "WMT turn off FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn off FM OK!\n"); + return 0; +} + +static unsigned short mt6631_get_chipid(void) +{ + return 0x6631; +} + +static signed int mt6631_switch_clk_64m(void) +{ + unsigned int val = 0; + int i = 0, ret = 0; + + /* switch SPI clock to 64MHz */ + ret = fm_host_reg_read(0x81026004, &val); + /* Set 0x81026004[0] = 0x1 */ + ret = fm_host_reg_write(0x81026004, val | 0x1); + if (ret) { + WCN_DBG(FM_ALT | CHIP, + "RampDown Switch SPI clock to 64MHz failed\n"); + return -1; + } + + for (i = 0; i < 100; i++) { + fm_host_reg_read(0x81026004, &val); + if ((val & 0x18) == 0x10) + break; + fm_delayus(10); + } + + if (i == 100) { + WCN_DBG(FM_ERR | CHIP, + "switch_SPI_clock_to_64MHz polling timeout\n"); + return -1; + } + + /* Capture next (with SPI Clock: 64MHz) */ + fm_host_reg_read(0x81026004, &val); + /* Set 0x81026004[2] = 0x1 */ + fm_host_reg_write(0x81026004, val | 0x4); + + return 0; +} + +static signed int mt6631_switch_clk_26m(void) +{ + unsigned int val = 0; + int i = 0, ret = 0; + + /* Capture next (with SPI Clock: 26MHz) */ + fm_host_reg_read(0x81026004, &val); + /* Set 0x81026004[2] = 0x0 */ + fm_host_reg_write(0x81026004, val & 0xFFFFFFFB); + + /* switch SPI clock to 26MHz */ + ret = fm_host_reg_read(0x81026004, &val); + /* Set 0x81026004[0] = 0x0 */ + ret = fm_host_reg_write(0x81026004, val & 0xFFFFFFFE); + if (ret) { + WCN_DBG(FM_ALT | CHIP, + "RampDown Switch SPI clock to 26MHz failed\n"); + return -1; + } + + for (i = 0; i < 100; i++) { + fm_host_reg_read(0x81026004, &val); + if ((val & 0x18) == 0x8) + break; + fm_delayus(10); + } + + if (i == 100) { + WCN_DBG(FM_ERR | CHIP, + "switch_SPI_clock_to_26MHz polling timeout\n"); + return -1; + } + + return 0; +} + +/* MT6631_SetAntennaType - set Antenna type + * @type - 1, Short Antenna; 0, Long Antenna + */ +static signed int mt6631_SetAntennaType(signed int type) +{ + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | CHIP, "set ana to %s\n", type ? "short" : "long"); + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + + if (type) + dataRead |= ANTENNA_TYPE; + else + dataRead &= (~ANTENNA_TYPE); + + fm_reg_write(FM_MAIN_CG2_CTRL, dataRead); + + return 0; +} + +static signed int mt6631_GetAntennaType(void) +{ + unsigned short dataRead = 0; + + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + WCN_DBG(FM_DBG | CHIP, "get ana type: %s\n", (dataRead & ANTENNA_TYPE) ? "short" : "long"); + + if (dataRead & ANTENNA_TYPE) + return FM_ANA_SHORT; /* short antenna */ + else + return FM_ANA_LONG; /* long antenna */ +} + +static signed int mt6631_Mute(bool mute) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | CHIP, "set %s\n", mute ? "mute" : "unmute"); + /* fm_reg_read(FM_MAIN_CTRL, &dataRead); */ + fm_reg_read(0x9C, &dataRead); + + /* fm_top_reg_write(0x0050, 0x00000007); */ + if (mute == 1) + ret = fm_reg_write(0x9C, (dataRead & 0xFFFC) | 0x0003); + else + ret = fm_reg_write(0x9C, (dataRead & 0xFFFC)); + + /* fm_top_reg_write(0x0050, 0x0000000F); */ + + return ret; +} + +static signed int mt6631_rampdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* Clear DSP state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF0, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* Set DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFFF, RAMP_DOWN, &buf[pkt_size], buf_size - pkt_size); + /* @Wait for STC_DONE interrupt@ */ + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size], + buf_size - pkt_size); + /* Clear DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, (~RAMP_DOWN), 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6631_rampdown - f/w will wait for STC_DONE interrupt + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6631_rampdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6631_rampdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_RAMPDOWN_OPCODE, pkt_size); +} + +/* FMSYS Ramp Down Sequence*/ +static signed int mt6631_RampDown(void) +{ + signed int ret = 0; + unsigned int tem = 0; + unsigned short pkt_size; + signed int projectid = fm_cb_op->projectid_get(); + /* unsigned short tmp; */ + + WCN_DBG(FM_DBG | CHIP, "ramp down\n"); + + mt6631_switch_clk_26m(); + WCN_DBG(FM_DBG | CHIP, "RampDown Switch SPI clock to 26MHz\n"); + + /* unlock 64M */ + if (projectid != 0x6768 && projectid != 0x6779 && projectid != 0x6785) { + ret = fm_host_reg_read(0x80026000, &tem); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: unlock 64M reg 0x80026000 failed\n", __func__); + ret = fm_host_reg_write(0x80026000, tem & (~(0x1 << 28))); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: unlock 64M failed\n", __func__); + + } else { + ret = fm_host_reg_read(0x80023008, &tem); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M reg 0x80023008 failed\n", __func__); + ret = fm_host_reg_write(0x80023008, tem & (~(0x1 << 21))); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M failed\n", __func__); + } + + if (projectid != 0x6779) { + /* Rlease TOP2/64M sleep */ + ret = fm_host_reg_read(0x81021138, &tem); /* Set 0x81021138[7] = 0x0 */ + tem = tem & 0xFFFFFF7F; + ret = fm_host_reg_write(0x81021138, tem); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "RampDown Rlease TOP2/64M sleep failed\n"); + return ret; + } + WCN_DBG(FM_DBG | CHIP, "RampDown Rlease TOP2/64M sleep\n"); + } + /* A0.0 Host control RF register */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /*Set 0x60 [D3:D0] = 0x7*/ + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down HOST control rf: Set 0x60 [D3:D0] = 0x7 failed\n"); + return ret; + } + + /* A0.1 Update FM ADPLL fast tracking mode gain */ + ret = fm_set_bits(0x0F, 0x0000, 0xF800); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down ADPLL gainA/B: Set 0xFH [D10:D0] = 0x000 failed\n"); + return ret; + } + + /* A0.2 Host control RF register */ + ret = fm_set_bits(0x60, 0x000F, 0xFFF0); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down Host control RF registerwr top 0x60 failed\n"); + return ret; + } + /*Clear dsp state*/ + ret = fm_set_bits(0x63, 0x0000, 0xFFF0); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down Host control RF registerwr top 0x63 failed\n"); + return ret; + } + /* Set DSP ramp down state*/ + ret = fm_set_bits(0x63, 0x0010, 0xFFEF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down Host control RF registerwr top 0x63 failed\n"); + return ret; + } + + ret = fm_reg_write(FM_MAIN_INTRMASK, 0x0000); + if (ret) + WCN_DBG(FM_ERR | CHIP, "ramp down clean FM_MAIN_INTRMASK failed\n"); + + ret = fm_reg_write(FM_MAIN_EXTINTRMASK, 0x0000); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down clean FM_MAIN_EXTINTRMASK failed\n"); + return ret; + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6631_rampdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_RAMPDOWN, SW_RETRY_CNT, RAMPDOWN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down failed\n"); + return ret; + } + + ret = fm_reg_write(FM_MAIN_EXTINTRMASK, 0x0021); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down wr FM_MAIN_EXTINTRMASK failed\n"); + return ret; + } + + ret = fm_reg_write(FM_MAIN_INTRMASK, 0x0021); + if (ret) + WCN_DBG(FM_ERR | CHIP, "ramp down wr FM_MAIN_INTRMASK failed\n"); + +#if 0 + fm_delayms(1); + WCN_DBG(FM_DBG | CHIP, "ramp down delay 1ms\n"); + + /* A1.1. Disable aon_osc_clk_cg */ + ret = fm_host_reg_write(0x81024064, 0x00000004); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Disable aon_osc_clk_cg failed\n"); + return ret; + } + /* A1.1. Disable FMAUD trigger */ + ret = fm_host_reg_write(0x81024058, 0x88800000); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "Disable FMAUD trigger failed\n"); + return ret; + } + + /* A1.1. issue fmsys memory powr down */ + ret = fm_host_reg_write(0x81024054, 0x00000180); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Issue fmsys memory powr down failed\n"); + return ret; + } +#endif + + return ret; +} + +static signed int mt6631_get_rom_version(void) +{ + unsigned short flag_Romcode = 0; + unsigned short nRomVersion = 0; +#define ROM_CODE_READY 0x0001 + signed int ret = 0; + + /* A1.1 DSP rom code version request enable --- set 0x61 b15=1 */ + fm_set_bits(0x61, 0x8000, 0x7FFF); + + /* A1.2 Release ASIP reset --- set 0x61 b1=1 */ + fm_set_bits(0x61, 0x0002, 0xFFFD); + + /* A1.3 Enable ASIP power --- set 0x61 b0=0 */ + fm_set_bits(0x61, 0x0000, 0xFFFE); + + /* A1.4 Wait until DSP code version ready --- wait loop 1ms */ + do { + fm_delayus(1000); + ret = fm_reg_read(0x84, &flag_Romcode); + /* ret=-4 means signal got when control FM. usually get sig 9 to kill FM process. */ + /* now cancel FM power up sequence is recommended. */ + if (ret) + return ret; + + WCN_DBG(FM_DBG | CHIP, "ROM_CODE_READY flag 0x84=%x\n", flag_Romcode); + } while (flag_Romcode != ROM_CODE_READY); + + + /* A1.5 Read FM DSP code version --- rd 0x83[15:8] */ + fm_reg_read(0x83, &nRomVersion); + nRomVersion = (nRomVersion >> 8); + + /* A1.6 DSP rom code version request disable --- set 0x61 b15=0 */ + fm_set_bits(0x61, 0x0000, 0x7FFF); + + /* A1.7 Reset ASIP --- set 0x61[1:0] = 1 */ + fm_set_bits(0x61, 0x0001, 0xFFFC); + + return (signed int) nRomVersion; +} + +static signed int mt6631_pwrup_clock_on_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + unsigned short de_emphasis; + signed int projectid = fm_cb_op->projectid_get(); + /* unsigned short osc_freq; */ + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + de_emphasis = fm_config.rx_cfg.deemphasis; + de_emphasis &= 0x0001; /* rang 0~1 */ + /* 2,turn on top clock */ + pkt_size += fm_bop_top_write(0xA10, 0xFFFFFFFF, &buf[pkt_size], buf_size - pkt_size); + /* wr top cr a10 ffffffff */ + + /* 3,enable MTCMOS */ + pkt_size += fm_bop_top_write(0x60, 0x00000030, &buf[pkt_size], buf_size - pkt_size); + /* wr top 60 30 */ + + pkt_size += fm_bop_top_write(0x60, 0x00000035, &buf[pkt_size], buf_size - pkt_size); + /* wr top 60 35 */ + pkt_size += fm_bop_udelay(10, &buf[pkt_size], buf_size - pkt_size); + /* delay 10us */ + pkt_size += fm_bop_top_write(0x60, 0x00000015, &buf[pkt_size], buf_size - pkt_size); + /* wr top 60 15 */ + pkt_size += fm_bop_top_write(0x60, 0x00000005, &buf[pkt_size], buf_size - pkt_size); + /* wr top 60 5 */ + + pkt_size += fm_bop_udelay(10, &buf[pkt_size], buf_size - pkt_size); + /* delay 10us */ + pkt_size += fm_bop_top_write(0x60, 0x00000045, &buf[pkt_size], buf_size - pkt_size); + /* wr top 60 45 */ + + /* 4,set comspi fm slave dumy count */ + if (projectid == 0x6779) + pkt_size += fm_bop_write(0x7f, 0x801f, &buf[pkt_size], buf_size - pkt_size); /* wr 7f 801f */ + else + pkt_size += fm_bop_write(0x7f, 0x800f, &buf[pkt_size], buf_size - pkt_size); /* wr 7f 800f */ + + /* A. FM digital clock enable */ + /* A1. Enable digital OSC */ + if (projectid != 0x6779) + pkt_size += fm_bop_write(0x60, 0x00000001, &buf[pkt_size], buf_size - pkt_size); /* wr 60 1 */ + + /* A2. Wait 3ms */ + pkt_size += fm_bop_udelay(3000, &buf[pkt_size], buf_size - pkt_size); + + /* A3. Set OSC clock output to FM */ + if (projectid != 0x6779) + pkt_size += fm_bop_write(0x60, 0x00000003, &buf[pkt_size], buf_size - pkt_size); /* wr 60 3 */ + /* A4. Release HW clock gating*/ + pkt_size += fm_bop_write(0x60, 0x00000007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 7 */ + /* Enable DSP auto clock gating */ + pkt_size += fm_bop_write(0x70, 0x0040, &buf[pkt_size], buf_size - pkt_size); /* wr 70 0040 */ + /* A7. Deemphasis setting: Set 0 for 50us, Set 1 for 75us */ + pkt_size += fm_bop_modify(0x61, ~DE_EMPHASIS, (de_emphasis << 12), &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6631_pwrup_clock_on - Wholechip FM Power Up: step 1, FM Digital Clock enable + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6631_pwrup_clock_on(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6631_pwrup_clock_on_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6631_pwrup_digital_init_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* Part D FM RF&ADPLL divider setting */ + + /* D2.1 set cell mode */ + /* wr 30 D3:D2 00:FDD(default),01:both.10: TDD, 11 FDD */ + /* pkt_size += fm_bop_modify(0x30, 0xFFF3, 0x0000, &buf[pkt_size], buf_size - pkt_size); */ + + /* D2.2 set ADPLL divider */ + pkt_size += fm_bop_write(0x21, 0xE000, &buf[pkt_size], buf_size - pkt_size); /* wr 21 E000 */ + /* D2.3 set SDM coeff0_H */ + pkt_size += fm_bop_write(0xD8, 0x03F0, &buf[pkt_size], buf_size - pkt_size); /* wr D8 0x03F0 */ + /* D2.4 set SDM coeff0_L */ + pkt_size += fm_bop_write(0xD9, 0x3F04, &buf[pkt_size], buf_size - pkt_size); /* wr D9 0x3F04 */ + /* D2.5 set SDM coeff1_H */ + pkt_size += fm_bop_write(0xDA, 0x0014, &buf[pkt_size], buf_size - pkt_size); /* wr DA 0x0014 */ + /* D2.6 set SDM coeff1_L */ + pkt_size += fm_bop_write(0xDB, 0x2A38, &buf[pkt_size], buf_size - pkt_size); /* wr DB 0x2A38 */ + /* D2.7 set 26M clock */ + pkt_size += fm_bop_write(0x23, 0x4000, &buf[pkt_size], buf_size - pkt_size); /* wr 23 4000 */ + + /* Part E: FM Digital Init: fm_rgf_maincon */ + + /* E4. Set appropriate interrupt mask behavior as desired */ + /* Enable stc_done_mask, Enable rgf_rds_mask*/ + pkt_size += fm_bop_write(0x6A, 0x0021, &buf[pkt_size], buf_size - pkt_size); /* wr 6A 0021 */ + pkt_size += fm_bop_write(0x6B, 0x0021, &buf[pkt_size], buf_size - pkt_size); /* wr 6B 0021 */ + + /* E5. Enable hw auto control */ + pkt_size += fm_bop_write(0x60, 0x0000000F, &buf[pkt_size], buf_size - pkt_size); /* wr 60 f */ + + /* E6. Release ASIP reset */ + pkt_size += fm_bop_modify(0x61, 0xFFFD, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D1=1 */ + /* E7. Enable ASIP power */ + pkt_size += fm_bop_modify(0x61, 0xFFFE, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D0=0 */ + + /* E8 */ + pkt_size += fm_bop_udelay(100000, &buf[pkt_size], buf_size - pkt_size); /* delay 100ms */ + /* E9. Check HW initial complete */ + pkt_size += fm_bop_rd_until(0x64, 0x001F, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* Poll 64[0~4] = 2 */ + + return pkt_size - 4; +} + +/* + * mt6631_pwrup_digital_init - Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6631_pwrup_digital_init(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6631_pwrup_digital_init_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6631_pwrup_fine_tune_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* F1 set host control RF register */ + pkt_size += fm_bop_write(0x60, 0x00000007, &buf[pkt_size], buf_size - pkt_size); + /* F2 fine tune RF setting */ + pkt_size += fm_bop_write(0x01, 0xBEE8, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x03, 0xF6ED, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x15, 0x0D80, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x16, 0x0068, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x17, 0x092A, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x34, 0x807F, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x35, 0x311E, &buf[pkt_size], buf_size - pkt_size); + /* F3 set DSP control RF register */ + pkt_size += fm_bop_write(0x60, 0x0000000F, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} + +/* + * mt6631_pwrup_fine_tune - Wholechip FM Power Up: step 5, FM RF fine tune setting + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6631_pwrup_fine_tune(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6631_pwrup_fine_tune_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6631_pwrdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* A1:set audio output I2S Tx mode: */ + pkt_size += fm_bop_modify(0x9B, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + + /* B0:Disable HW clock control */ + pkt_size += fm_bop_write(0x60, 0x330F, &buf[pkt_size], buf_size - pkt_size); + /* B1:Reset ASIP : Set 0x61, [D1 = 0, D0=1] */ + pkt_size += fm_bop_modify(0x61, 0xFFFD, 0x0001, &buf[pkt_size], buf_size - pkt_size); + + /* B2:digital core + digital rgf reset */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + + /* B3:Disable all clock */ + pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* B4:Reset rgfrf */ + pkt_size += fm_bop_write(0x60, 0x4000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); + + /* MTCMOS power off */ + /* C0:disable MTCMOS */ + pkt_size += fm_bop_top_write(0x60, 0x0005, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x60, 0x0015, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x60, 0x0035, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x60, 0x0030, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_rd_until(0x60, 0x0000000A, 0x0, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6631_pwrdown - Wholechip FM Power down: Digital Modem Power Down + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6631_pwrdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6631_pwrdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6631_tune_reg_op(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 4; + + WCN_DBG(FM_ALT | CHIP, "%s enter mt6631_tune function\n", __func__); + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* A2 Enable hardware controlled tuning sequence */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF8, TUNE, &buf[pkt_size], buf_size - pkt_size);/*Set 0x63 D0=1*/ + /* Wait for STC_DONE interrupt */ + +#ifdef FM_TUNE_USE_POLL + /* A3 Wait for STC_DONE interrupt */ + /* A4 Wait for STC_DONE interrupt status flag */ + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, + FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); + /* A6 Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); +#endif + + pkt_size += fm_bop_udelay(100000, &buf[pkt_size], buf_size - pkt_size); + WCN_DBG(FM_ALT | CHIP, "mt6631_tune delay 100 ms wait 0x69 to change\n"); + + WCN_DBG(FM_ALT | CHIP, "%s leave mt6631_tune function\n", __func__); + + return pkt_size - 4; +} + +/* + * mt6631_tune - execute tune action, + * @buf - target buf + * @buf_size - buffer size + * @freq - 760 ~ 1080, 100KHz unit + * return package size + */ +static signed int mt6631_tune(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 0; + + pkt_size = mt6631_tune_reg_op(buf, buf_size, freq, chan_para); + return fm_op_seq_combine_cmd(buf, FM_TUNE_OPCODE, pkt_size); +} + +/* + * mt6631_pwrup_DSP_download - execute dsp/coeff patch dl action, + * @patch_tbl - current chip patch table + * return patch dl ok or not + */ +static signed int mt6631_pwrup_DSP_download(struct fm_patch_tbl *patch_tbl) +{ +#define PATCH_BUF_SIZE (4096*6) + signed int ret = 0; + signed int patch_len = 0; + unsigned char *dsp_buf = NULL; + unsigned short tmp_reg = 0; + + mt6631_hw_info.eco_ver = (signed int) mtk_wcn_wmt_ic_info_get(1); + WCN_DBG(FM_DBG | CHIP, "ECO version:0x%08x\n", mt6631_hw_info.eco_ver); + + /* Wholechip FM Power Up: step 3, get mt6631 DSP ROM version */ + ret = mt6631_get_rom_version(); + if (ret >= 0) { + mt6631_hw_info.rom_ver = ret; + WCN_DBG(FM_NTC | CHIP, "%s ROM version: v%d\n", __func__, mt6631_hw_info.rom_ver); + } else { + WCN_DBG(FM_ERR | CHIP, "get ROM version failed\n"); + if (ret == -4) + WCN_DBG(FM_ERR | CHIP, "signal got when control FM, usually get sig 9 to kill FM process.\n"); + /* now cancel FM power up sequence is recommended. */ + goto out; + } + + /* Wholechip FM Power Up: step 4 download patch */ + dsp_buf = fm_vmalloc(PATCH_BUF_SIZE); + if (!dsp_buf) { + WCN_DBG(FM_ALT | CHIP, "-ENOMEM\n"); + return -ENOMEM; + } + + patch_len = fm_get_patch_path(mt6631_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_patch_path failed\n"); + ret = patch_len; + goto out; + } + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_PATCH); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " DL DSPpatch failed\n"); + goto out; + } + + patch_len = fm_get_coeff_path(mt6631_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_coeff_path failed\n"); + ret = patch_len; + goto out; + } + + mt6631_hw_info.rom_ver += 1; + + tmp_reg = dsp_buf[38] | (dsp_buf[39] << 8); /* to be confirmed */ + mt6631_hw_info.patch_ver = (signed int) tmp_reg; + WCN_DBG(FM_NTC | CHIP, "Patch version: 0x%08x\n", mt6631_hw_info.patch_ver); + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_COEFFICIENT); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Download DSP coefficient failed\n"); + goto out; + } + + /* Download HWACC coefficient */ + fm_reg_write(0x92, 0x0000); + fm_reg_write(0x90, 0x0040); /* Reset download control */ + fm_reg_write(0x90, 0x0000); /* Disable memory control from host*/ +out: + if (dsp_buf) { + fm_vfree(dsp_buf); + dsp_buf = NULL; + } + return ret; +} +static void mt6631_show_reg(void) +{ + unsigned int host_reg[3] = {0}; + unsigned int debug_reg1[3] = {0}; + unsigned short debug_reg2[3] = {0}; + + fm_host_reg_read(0x81024030, &host_reg[0]); + fm_host_reg_read(0x81021234, &host_reg[1]); + fm_host_reg_read(0x81021138, &host_reg[2]); + WCN_DBG(FM_ALT | CHIP, + "host read 0x81024030 = 0x%08x, 0x81021234 = 0x%08x, 0x81021138 = 0x%08x\n", + host_reg[0], host_reg[1], host_reg[2]); + + fm_top_reg_read(0x00c0, &debug_reg1[0]); + fm_top_reg_read(0x00c8, &debug_reg1[1]); + fm_top_reg_read(0x0060, &debug_reg1[2]); + fm_reg_read(0x7f, &debug_reg2[0]); + fm_reg_read(0x62, &debug_reg2[1]); + fm_reg_read(0x60, &debug_reg2[2]); + WCN_DBG(FM_ALT | CHIP, + "top cr 0xc0 = 0x%08x, 0xc8 = 0x%08x, 0x60 = 0x%08x, fmreg 0x7f = 0x%08x, 0x62 = 0x%08x, 0x60 = 0x%08x\n", + debug_reg1[0], debug_reg1[1], debug_reg1[2], debug_reg2[0], debug_reg2[1], debug_reg2[2]); +} + +static signed int mt6631_PowerUp(unsigned short *chip_id, unsigned short *device_id) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short tmp_reg = 0; + unsigned int tem = 0; + unsigned int host_reg = 0; + signed int projectid = fm_cb_op->projectid_get(); + + if (chip_id == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (device_id == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + WCN_DBG(FM_DBG | CHIP, "pwr on seq......\n"); + + /* Wholechip FM Power Up: step 1, set common SPI parameter */ + if (projectid == 0x6779) + ret = fm_host_reg_write(0x8102600C, 0x0000801F); + else + ret = fm_host_reg_write(0x8102600C, 0x0000800F); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup set CSPI failed\n"); + return ret; + } + + if (projectid == 0x6765 || projectid == 0x6761 + || projectid == 0x3967 || projectid == 0x6768 + || projectid == 0x6785 || projectid == 0x6779) { + /* Set top_clk_en_adie to trigger sleep controller before FM power on */ + if (projectid == 0x6779) { + ret = fm_host_reg_write(0x81021500, 0x00000003); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup set top_clk_en_adie failed\n"); + return ret; + } + } else { + fm_host_reg_read(0x81021500, &tem); /* Set 0x81021500[1] = 0x1 */ + tem = tem | 0x00000002; + fm_host_reg_write(0x81021500, tem); + } + + /* Disable 26M crystal sleep */ + fm_host_reg_read(0x81021200, &tem); /* Set 0x81021200[23] = 0x1 */ + tem = tem | 0x00800000; + fm_host_reg_write(0x81021200, tem); + } else { + /* Set top_clk_en_adie to trigger sleep controller before FM power on */ + fm_host_reg_read(0x81024030, &tem); /* Set 0x81024030[1] = 0x1 */ + tem = tem | 0x00000002; + fm_host_reg_write(0x81024030, tem); + + /* Disable 26M crystal sleep */ + fm_host_reg_read(0x81021234, &tem); /* Set 0x81021234[7] = 0x1 */ + tem = tem | 0x00000080; + fm_host_reg_write(0x81021234, tem); + } + + /* turn on RG_TOP_BGLDO */ + ret = fm_top_reg_read(0x00c0, &host_reg); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "power up read top 0xc0 failed\n"); + return ret; + } + ret = fm_top_reg_write(0x00c0, host_reg | (0x3 << 27)); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "power up write top 0xc0 failed\n"); + return ret; + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + + pkt_size = mt6631_pwrup_clock_on(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6631_pwrup_clock_on failed\n"); + return ret; + } + + /* Wholechip FM Power Up: step 2, read HW version */ + mt6631_show_reg(); + fm_reg_read(0x62, &tmp_reg); + /* chip_id = tmp_reg; */ + if (tmp_reg == 0x6631) + *chip_id = 0x6631; + *device_id = tmp_reg; + mt6631_hw_info.chip_id = (signed int) tmp_reg; + WCN_DBG(FM_DBG | CHIP, "chip_id:0x%04x\n", tmp_reg); + + if ((mt6631_hw_info.chip_id != 0x6631)) { + mt6631_show_reg(); + WCN_DBG(FM_NTC | CHIP, "fm sys error, reset hw, chip_id = 0x%08x\n", mt6631_hw_info.chip_id); + return -FM_EFW; + + } + /* Wholechip FM Power Up: step 3, patch download */ + ret = mt6631_pwrup_DSP_download(mt6631_patch_tbl); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6631_pwrup_DSP_download failed\n"); + return ret; + } + + /* Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6631_pwrup_digital_init(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6631_pwrup_digital_init failed\n"); + return ret; + } + + /* Wholechip FM Power Up: step 5, FM RF fine tune setting */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6631_pwrup_fine_tune(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6631_pwrup_fine_tune failed\n"); + return ret; + } + + /* Enable connsys FM 2 wire RX */ + fm_reg_write(0x9B, 0xF9AB); /* G2: Set audio output i2s TX mode */ + fm_host_reg_write(0x81024064, 0x00000014); /* G3: Enable aon_osc_clk_cg */ + /* G4: Enable FMAUD trigger, 20170119 */ + if (projectid == 0x6779) + fm_host_reg_write(0x81024058, 0x888100C3); + else + fm_host_reg_write(0x81024058, 0x888100F3); + fm_host_reg_write(0x81024054, 0x00000100); /* G5: Release fmsys memory power down*/ + + WCN_DBG(FM_NTC | CHIP, "pwr on seq ok\n"); + + return ret; +} + +static signed int mt6631_PowerDown(void) +{ + signed int ret = 0; + unsigned int tem = 0; + unsigned short pkt_size; + signed int projectid = fm_cb_op->projectid_get(); + /* unsigned int host_reg = 0; */ + + WCN_DBG(FM_DBG | CHIP, "pwr down seq\n"); + + /* A0.1. Disable aon_osc_clk_cg */ + ret = fm_host_reg_write(0x81024064, 0x00000004); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Disable aon_osc_clk_cg failed\n"); + return ret; + } + /* A0.1. Disable FMAUD trigger */ + ret = fm_host_reg_write(0x81024058, 0x88800000); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Disable FMAUD trigger failed\n"); + return ret; + } + + /* A0.1. issue fmsys memory powr down */ + ret = fm_host_reg_write(0x81024054, 0x00000180); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Issue fmsys memory powr down failed\n"); + return ret; + } + + mt6631_switch_clk_26m(); + + /* unlock 64M */ + if (projectid != 0x6768 && projectid != 0x6779 && projectid != 0x6785) { + ret = fm_host_reg_read(0x80026000, &tem); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: unlock 64M reg 0x80026000 failed\n", __func__); + ret = fm_host_reg_write(0x80026000, tem & (~(0x1 << 28))); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: unlock 64M failed\n", __func__); + + } else { + ret = fm_host_reg_read(0x80023008, &tem); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M reg 0x80023008 failed\n", __func__); + ret = fm_host_reg_write(0x80023008, tem & (~(0x1 << 21))); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M failed\n", __func__); + } + + if (projectid != 0x6779) { + /*Release TOP2/64M sleep*/ + WCN_DBG(FM_DBG | CHIP, "PowerDown: Release TOP2/64M sleep\n"); + ret = fm_host_reg_read(0x81021138, &tem); + tem = tem & 0xFFFFFF7F; + ret = fm_host_reg_write(0x81021138, tem); + if (ret) + WCN_DBG(FM_ALT | CHIP, "PowerDown: Release TOP2/64M sleep failed\n"); + } + + /* Enable 26M crystal sleep */ + if (projectid == 0x6765 || projectid == 0x6761 + || projectid == 0x3967 || projectid == 0x6768 + || projectid == 0x6785) { + WCN_DBG(FM_DBG | CHIP, "PowerDown: Enable 26M crystal sleep,Set 0x81021200[23] = 0x0\n"); + ret = fm_host_reg_read(0x81021200, &tem); /* Set 0x81021200[23] = 0x0 */ + tem = tem & 0xFF7FFFFF; + ret = fm_host_reg_write(0x81021200, tem); + } else { + WCN_DBG(FM_DBG | CHIP, "PowerDown: Enable 26M crystal sleep,Set 0x81021234[7] = 0x0\n"); + ret = fm_host_reg_read(0x81021234, &tem); /* Set 0x81021234[7] = 0x0 */ + tem = tem & 0xFFFFFF7F; + ret = fm_host_reg_write(0x81021234, tem); + } + + if (ret) + WCN_DBG(FM_ALT | CHIP, "PowerDown: Enable 26M crystal sleep,Set 0x81021234[7] = 0x0 failed\n"); + + /* A0:set audio output I2X Rx mode: */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6631_pwrdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6631_pwrdown failed\n"); + return ret; + } + /* FIX_ME, disable ext interrupt */ + /* fm_reg_write(FM_MAIN_EXTINTRMASK, 0x00); */ + + + /* D0. Clear top_clk_en_adie to indicate sleep controller after FM power off */ + /* ret = fm_host_reg_read(0x80101030, &host_reg); + * if (ret) { + * WCN_DBG(FM_ALT | CHIP, " pwroff read 0x80100030 failed\n"); + * return ret; + * } + * ret = fm_host_reg_write(0x80101030, host_reg & (~(0x1 << 1))); + * if (ret) { + * WCN_DBG(FM_ALT | CHIP, " pwroff disable top_ck_en_adie failed\n"); + * return ret; + * } + */ + return ret; +} + +/* just for dgb */ +#if 0 +static void mt6631_bt_write(unsigned int addr, unsigned int val) +{ + unsigned int tem, i = 0; + + fm_host_reg_write(0x80103020, addr); + fm_host_reg_write(0x80103024, val); + fm_host_reg_read(0x80103000, &tem); + while ((tem == 4) && (i < 1000)) { + i++; + fm_host_reg_read(0x80103000, &tem); + } +} +#endif +static bool mt6631_SetFreq(unsigned short freq) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short chan_para = 0; + unsigned short freq_reg = 0; + unsigned int reg_val = 0; + unsigned int i = 0; + bool flag_spi_hopping = false; + unsigned short tmp_reg[6] = {0}; + signed int projectid = fm_cb_op->projectid_get(); + + fm_cb_op->cur_freq_set(freq); + +#if 0 + /* MCU clock adjust if need */ + ret = mt6631_mcu_dese(freq, NULL); + if (ret < 0) + WCN_DBG(FM_ERR | MAIN, "mt6631_mcu_dese FAIL:%d\n", ret); + + WCN_DBG(FM_INF | MAIN, "MCU %d\n", ret); + + /* GPS clock adjust if need */ + ret = mt6631_gps_dese(freq, NULL); + if (ret < 0) + WCN_DBG(FM_ERR | MAIN, "mt6631_gps_dese FAIL:%d\n", ret); + + WCN_DBG(FM_INF | MAIN, "GPS %d\n", ret); +#endif + + /* A0. Host contrl RF register */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /* Set 0x60 [D3:D0] = 0x07*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Host Control RF register 0x60 = 0x7 failed\n", __func__); + + /* A0.1 Update FM ADPLL fast tracking mode gain */ + ret = fm_set_bits(0x0F, 0x0455, 0xF800); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set FM ADPLL gainA/B=0x455 failed\n", __func__); + + /* A0.2 Set FMSYS cell mode */ + if (mt6631_TDD_chan_check(freq)) { + ret = fm_set_bits(0x30, 0x0008, 0xFFF3); /* use TDD solution */ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: freq[%d]: use TDD solution failed\n", __func__, freq); + } else { + ret = fm_set_bits(0x30, 0x0000, 0xFFF3); /* default use FDD solution */ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: freq[%d]: default use FDD solution failed\n", __func__, freq); + } + + /* A0.3 Host control RF register */ + ret = fm_set_bits(0x60, 0x000F, 0xFFF0); /* Set 0x60 [D3:D0] = 0x0F*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x60 [D3:D0] = 0x0F failed\n", __func__); + + /* A1 Get Channel parameter from map list*/ + + chan_para = mt6631_chan_para_get(freq); + WCN_DBG(FM_DBG | CHIP, "%s: %d chan para = %d\n", __func__, (signed int) freq, (signed int) chan_para); + + freq_reg = freq; + if (fm_get_channel_space(freq_reg) == 0) + freq_reg *= 10; + + freq_reg = (freq_reg - 6400) * 2 / 10; + + /*A1 Set rgfrf_chan = XXX*/ + ret = fm_set_bits(0x65, freq_reg, 0xFC00); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "%s: set rgfrf_chan = xxx = %d failed\n", __func__, freq_reg); + return false; + } + + ret = fm_set_bits(0x65, (chan_para << 12), 0x0FFF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x65 failed\n"); + return false; + } + /* SPI hoppint setting*/ + if (mt6631_SPI_hopping_check(freq)) { + + WCN_DBG(FM_NTC | CHIP, "%s: freq:%d is SPI hopping channel,turn on 64M PLL\n", __func__, freq); + + if (projectid != 0x6779) { + /*Disable TOP2/64M sleep*/ + ret = fm_host_reg_read(0x81021138, ®_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: read 64M reg 0x81021138 failed\n", __func__); + reg_val |= 0x00000080; + ret = fm_host_reg_write(0x81021138, reg_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: disable 64M sleep failed\n", __func__); + } + /* lock 64M */ + if (projectid != 0x6768 && projectid != 0x6779 + && projectid != 0x6785) { + ret = fm_host_reg_read(0x80026000, ®_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M reg 0x80026000 failed\n", __func__); + ret = fm_host_reg_write(0x80026000, reg_val | (0x1 << 28)); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M failed\n", __func__); + } else { + ret = fm_host_reg_read(0x80023008, ®_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M reg 0x80023008 failed\n", __func__); + ret = fm_host_reg_write(0x80023008, reg_val | (0x1 << 21)); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M failed\n", __func__); + } + + for (i = 0; i < 100; i++) { /*rd 0x8002110C until D27 ==1*/ + + if (projectid != 0x6768 && projectid != 0x6779 + && projectid != 0x6785) + ret = fm_host_reg_read(0x8002110C, ®_val); + else + ret = fm_host_reg_read(0x80021118, ®_val); + + if (reg_val & 0x08000000) { + WCN_DBG(FM_NTC | CHIP, "%s: POLLING PLL_RDY success !\n", __func__); + flag_spi_hopping = mt6631_switch_clk_64m() == 0; + break; + } + fm_delayus(10); + } + if (false == flag_spi_hopping) + WCN_DBG(FM_ERR | CHIP, "%s: Polling to read rd 0x8002110C[27] ==0x1 failed !\n", __func__); + } + + /* A0. Host contrl RF register */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /* Set 0x60 [D3:D0] = 0x07*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Host Control RF register 0x60 = 0x7 failed\n", __func__); + + + fm_reg_read(0x62, &tmp_reg[0]); + fm_reg_read(0x64, &tmp_reg[1]); + fm_reg_read(0x69, &tmp_reg[2]); + fm_reg_read(0x6a, &tmp_reg[3]); + fm_reg_read(0x6b, &tmp_reg[4]); + fm_reg_read(0x9b, &tmp_reg[5]); + + WCN_DBG(FM_ALT | CHIP, "%s: Before tune--0x62 0x64 0x69 0x6a 0x6b 0x9b = %04x %04x %04x %04x %04x %04x\n", + __func__, + tmp_reg[0], + tmp_reg[1], + tmp_reg[2], + tmp_reg[3], + tmp_reg[4], + tmp_reg[5]); + + /* A0.3 Host control RF register */ + ret = fm_set_bits(0x60, 0x000F, 0xFF00); /* Set 0x60 [D3:D0] = 0x0F*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x60 [D3:D0] = 0x0F failed\n", __func__); + + if (FM_LOCK(cmd_buf_lock)) + return false; + pkt_size = mt6631_tune(cmd_buf, TX_BUF_SIZE, freq, chan_para); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE | FLAG_TUNE_DONE, SW_RETRY_CNT, TUNE_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + + /* A0. Host contrl RF register */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /* Set 0x60 [D3:D0] = 0x07*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Host Control RF register 0x60 = 0x7 failed\n", __func__); + + memset(tmp_reg, 0, sizeof(tmp_reg[0])*6); + + fm_reg_read(0x62, &tmp_reg[0]); + fm_reg_read(0x64, &tmp_reg[1]); + fm_reg_read(0x69, &tmp_reg[2]); + fm_reg_read(0x6a, &tmp_reg[3]); + fm_reg_read(0x6b, &tmp_reg[4]); + fm_reg_read(0x9b, &tmp_reg[5]); + + WCN_DBG(FM_ALT | CHIP, "%s: After tune--0x62 0x64 0x69 0x6a 0x6b 0x9b = %04x %04x %04x %04x %04x %04x\n", + __func__, + tmp_reg[0], + tmp_reg[1], + tmp_reg[2], + tmp_reg[3], + tmp_reg[4], + tmp_reg[5]); + + /* A0.3 Host control RF register */ + ret = fm_set_bits(0x60, 0x000F, 0xFF00); /* Set 0x60 [D3:D0] = 0x0F*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x60 [D3:D0] = 0x0F failed\n", __func__); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "%s: mt6631_tune failed\n", __func__); + return false; + } + + WCN_DBG(FM_DBG | CHIP, "%s: set freq to %d ok\n", __func__, freq); +#if 0 + /* ADPLL setting for dbg */ + fm_top_reg_write(0x0050, 0x00000007); + fm_top_reg_write(0x0A08, 0xFFFFFFFF); + mt6631_bt_write(0x82, 0x11); + mt6631_bt_write(0x83, 0x11); + mt6631_bt_write(0x84, 0x11); + fm_top_reg_write(0x0040, 0x1C1C1C1C); + fm_top_reg_write(0x0044, 0x1C1C1C1C); + fm_reg_write(0x70, 0x0010); + /*0x0806 DCO clk + *0x0802 ref clk + *0x0804 feedback clk + */ + fm_reg_write(0xE0, 0x0806); +#endif + return true; +} + +#if 0 +/* +* mt6631_Seek +* @pFreq - IN/OUT parm, IN start freq/OUT seek valid freq +* @seekdir - 0:up, 1:down +* @space - 1:50KHz, 2:100KHz, 4:200KHz +* return true:seek success; false:seek failed +*/ +static bool mt6631_Seek(unsigned short min_freq, unsigned short max_freq, unsigned short *pFreq, + unsigned short seekdir, unsigned short space) +{ + signed int ret = 0; + unsigned short pkt_size, temp; + + mt6631_RampDown(); + fm_reg_read(FM_MAIN_CTRL, &temp); + mt6631_Mute(true); + + if (FM_LOCK(cmd_buf_lock)) + return false; + pkt_size = mt6631_seek(cmd_buf, TX_BUF_SIZE, seekdir, space, max_freq, min_freq); + ret = + fm_cmd_tx(cmd_buf, pkt_size, FLAG_SEEK | FLAG_SEEK_DONE, SW_RETRY_CNT, SEEK_TIMEOUT, + fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + *pFreq = fm_res->seek_result; + /* fm_cb_op->cur_freq_set(*pFreq); */ + } else { + WCN_DBG(FM_ALT | CHIP, "mt6631_seek failed\n"); + return ret; + } + + /* get the result freq */ + WCN_DBG(FM_NTC | CHIP, "seek, result freq:%d\n", *pFreq); + mt6631_RampDown(); + if ((temp & 0x0020) == 0) + mt6631_Mute(false); + + return true; +} +#endif +#define FM_CQI_LOG_PATH "/mnt/sdcard/fmcqilog" + +static signed int mt6631_full_cqi_get(signed int min_freq, signed int max_freq, signed int space, signed int cnt) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short freq, orig_freq; + signed int i, j, k; + signed int space_val, max, min, num; + struct mt6631_full_cqi *p_cqi; + unsigned char *cqi_log_title = "Freq, RSSI, PAMD, PR, FPAMD, MR, ATDC, PRX, ATDEV, SMGain, DltaRSSI\n"; + unsigned char cqi_log_buf[100] = { 0 }; + signed int pos; + unsigned char cqi_log_path[100] = { 0 }; + + /* for soft-mute tune, and get cqi */ + freq = fm_cb_op->cur_freq_get(); + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + /* get cqi */ + orig_freq = freq; + if (fm_get_channel_space(min_freq) == 0) + min = min_freq * 10; + else + min = min_freq; + + if (fm_get_channel_space(max_freq) == 0) + max = max_freq * 10; + else + max = max_freq; + + if (space == 0x0001) + space_val = 5; /* 50Khz */ + else if (space == 0x0002) + space_val = 10; /* 100Khz */ + else if (space == 0x0004) + space_val = 20; /* 200Khz */ + else + space_val = 10; + + num = (max - min) / space_val + 1; /* Eg, (8760 - 8750) / 10 + 1 = 2 */ + for (k = 0; (orig_freq == 10000) && (g_dbg_level == 0xffffffff) && (k < cnt); k++) { + WCN_DBG(FM_NTC | CHIP, "cqi file:%d\n", k + 1); + freq = min; + pos = 0; + fm_memcpy(cqi_log_path, FM_CQI_LOG_PATH, strlen(FM_CQI_LOG_PATH)); + sprintf(&cqi_log_path[strlen(FM_CQI_LOG_PATH)], "%d.txt", k + 1); + fm_file_write(cqi_log_path, cqi_log_title, strlen(cqi_log_title), &pos); + for (j = 0; j < num; j++) { + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, + SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + WCN_DBG(FM_NTC | CHIP, "smt cqi size %d\n", fm_res->cqi[0]); + p_cqi = (struct mt6631_full_cqi *)&fm_res->cqi[2]; + for (i = 0; i < fm_res->cqi[1]; i++) { + /* just for debug */ + WCN_DBG(FM_NTC | CHIP, + "%04d, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x,\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* format to buffer */ + sprintf(cqi_log_buf, + "%04d, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x,\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* write back to log file */ + fm_file_write(cqi_log_path, cqi_log_buf, strlen(cqi_log_buf), &pos); + } + } else { + WCN_DBG(FM_ALT | CHIP, "smt get CQI failed\n"); + ret = -1; + } + freq += space_val; + } + fm_cb_op->cur_freq_set(0); /* avoid run too much times */ + } + + return ret; +} + +static unsigned short mt6631_read_dsp_reg(unsigned short addr) +{ + unsigned short regValue = 0; + + fm_reg_write(0x60, 0x07); + fm_reg_write(0xE2, addr); + fm_reg_write(0xE1, 0x01); + fm_reg_read(0xE4, ®Value); + fm_reg_write(0x60, 0x0F); + + return regValue; +} + +static bool mt6631_is_valid_freq(unsigned short freq) +{ + int i = 0; + bool valid = false; + signed int RSSI = 0, PAMD = 0, MR = 0; + unsigned int PRX = 0; + unsigned short softmuteGainLvl = 0; + unsigned short tmp_reg = 0; + + for (i = 0; i < 8; i++) { + fm_reg_read(0x6C, &tmp_reg); + RSSI += (((tmp_reg & 0x03FF) >= 512) ? ((tmp_reg & 0x03FF) - 1024) : (tmp_reg & 0x03FF)) >> 3; + fm_reg_read(0xB4, &tmp_reg); + PAMD += (((tmp_reg & 0x1FF) >= 256) ? ((tmp_reg & 0x01FF) - 512) : (tmp_reg & 0x01FF)) >> 3; + tmp_reg = mt6631_read_dsp_reg(0x4E1); + PRX += (tmp_reg & 0x00FF) >> 3; + fm_reg_read(0xBD, &tmp_reg); + MR += (((tmp_reg & 0x01FF) >= 256) ? ((tmp_reg & 0x01FF) - 512) : (tmp_reg & 0x01FF)) >> 3; + tmp_reg = mt6631_read_dsp_reg(0x2C4); + softmuteGainLvl += tmp_reg >> 3; + fm_delayus(2250); + } + + if ((fm_config.rx_cfg.long_ana_rssi_th <= RSSI) + && (fm_config.rx_cfg.pamd_th >= PAMD) + && (fm_config.rx_cfg.mr_th <= MR) + && (fm_config.rx_cfg.prx_th <= PRX) + && (fm_config.rx_cfg.smg_th <= softmuteGainLvl)) { + valid = true; + } + + WCN_DBG(FM_DBG | CHIP, + "freq %d valid=%d, %d, %d, 0x%04x, 0x%04x, 0x%04x\n", + freq, valid, RSSI, PAMD, PRX, MR, softmuteGainLvl); + + return valid; +} + +/* + * mt6631_GetCurRSSI - get current freq's RSSI value + * RS=RSSI + * If RS>511, then RSSI(dBm)= (RS-1024)/16*6 + * else RSSI(dBm)= RS/16*6 + */ +static signed int mt6631_GetCurRSSI(signed int *pRSSI) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RSSI_IND, &tmp_reg); + tmp_reg = tmp_reg & 0x03ff; + + if (pRSSI) { + *pRSSI = (tmp_reg > 511) ? (((tmp_reg - 1024) * 6) >> 4) : ((tmp_reg * 6) >> 4); + WCN_DBG(FM_DBG | CHIP, "rssi:%d, dBm:%d\n", tmp_reg, *pRSSI); + } else { + WCN_DBG(FM_ERR | CHIP, "get rssi para error\n"); + return -FM_EPARA; + } + + return 0; +} + +static unsigned short mt6631_vol_tbl[16] = { 0x0000, 0x0519, 0x066A, 0x0814, + 0x0A2B, 0x0CCD, 0x101D, 0x1449, + 0x198A, 0x2027, 0x287A, 0x32F5, + 0x4027, 0x50C3, 0x65AD, 0x7FFF +}; + +static signed int mt6631_SetVol(unsigned char vol) +{ + signed int ret = 0; + + vol = (vol > 15) ? 15 : vol; + ret = fm_reg_write(0x7D, mt6631_vol_tbl[vol]); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "Set vol=%d Failed\n", vol); + return ret; + } + WCN_DBG(FM_DBG | CHIP, "Set vol=%d OK\n", vol); + + + if (vol == 10) { + fm_print_cmd_fifo(); /* just for debug */ + fm_print_evt_fifo(); + } + return 0; +} + +static signed int mt6631_GetVol(unsigned char *pVol) +{ + int ret = 0; + unsigned short tmp = 0; + signed int i; + + if (pVol == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + ret = fm_reg_read(0x7D, &tmp); + if (ret) { + *pVol = 0; + WCN_DBG(FM_ERR | CHIP, "Get vol Failed\n"); + return ret; + } + + for (i = 0; i < 16; i++) { + if (mt6631_vol_tbl[i] == tmp) { + *pVol = i; + break; + } + } + + WCN_DBG(FM_DBG | CHIP, "Get vol=%d OK\n", *pVol); + return 0; +} + +static signed int mt6631_dump_reg(void) +{ + signed int i; + unsigned short TmpReg = 0; + + for (i = 0; i < 0xff; i++) { + fm_reg_read(i, &TmpReg); + WCN_DBG(FM_NTC | CHIP, "0x%02x=0x%04x\n", i, TmpReg); + } + return 0; +} + +/*0:mono, 1:stereo*/ +static bool mt6631_GetMonoStereo(unsigned short *pMonoStereo) +{ +#define FM_BF_STEREO 0x1000 + unsigned short TmpReg = 0; + + if (pMonoStereo) { + fm_reg_read(FM_RSSI_IND, &TmpReg); + *pMonoStereo = (TmpReg & FM_BF_STEREO) >> 12; + } else { + WCN_DBG(FM_ERR | CHIP, "MonoStero: para err\n"); + return false; + } + + WCN_DBG(FM_NTC | CHIP, "Get MonoStero:0x%04x\n", *pMonoStereo); + return true; +} + +static signed int mt6631_SetMonoStereo(signed int MonoStereo) +{ + signed int ret = 0; + + WCN_DBG(FM_NTC | CHIP, "set to %s\n", MonoStereo ? "mono" : "auto"); + fm_reg_write(0x60, 0x0007); + + if (MonoStereo) /*mono */ + ret = fm_set_bits(0x75, 0x0008, ~0x0008); + else + ret = fm_set_bits(0x75, 0x0000, ~0x0008); + + fm_reg_write(0x60, 0x000F); + return ret; +} + +static signed int mt6631_GetCapArray(signed int *ca) +{ + unsigned short dataRead = 0; + unsigned short tmp = 0; + + if (ca == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_reg_read(0x60, &tmp); + fm_reg_write(0x60, tmp & 0xFFF7); /* 0x60 D3=0 */ + + fm_reg_read(0x26, &dataRead); + *ca = dataRead; + + fm_reg_write(0x60, tmp); /* 0x60 D3=1 */ + return 0; +} + +/* + * mt6631_GetCurPamd - get current freq's PAMD value + * PA=PAMD + * If PA>511 then PAMD(dB)= (PA-1024)/16*6, + * else PAMD(dB)=PA/16*6 + */ +static bool mt6631_GetCurPamd(unsigned short *pPamdLevl) +{ + unsigned short tmp_reg = 0; + unsigned short dBvalue, valid_cnt = 0; + int i, total = 0; + + for (i = 0; i < 8; i++) { + if (fm_reg_read(FM_ADDR_PAMD, &tmp_reg)) { + *pPamdLevl = 0; + return false; + } + + tmp_reg &= 0x03FF; + dBvalue = (tmp_reg > 256) ? ((512 - tmp_reg) * 6 / 16) : 0; + if (dBvalue != 0) { + total += dBvalue; + valid_cnt++; + WCN_DBG(FM_DBG | CHIP, "[%d]PAMD=%d\n", i, dBvalue); + } + fm_delayms(3); + } + if (valid_cnt != 0) + *pPamdLevl = total / valid_cnt; + else + *pPamdLevl = 0; + + WCN_DBG(FM_NTC | CHIP, "PAMD=%d\n", *pPamdLevl); + return true; +} + +static signed int mt6631_i2s_info_get(signed int *ponoff, signed int *pmode, signed int *psample) +{ + if (ponoff == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (pmode == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (psample == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + *ponoff = fm_config.aud_cfg.i2s_info.status; + *pmode = fm_config.aud_cfg.i2s_info.mode; + *psample = fm_config.aud_cfg.i2s_info.rate; + + return 0; +} + +static signed int mt6631_get_audio_info(struct fm_audio_info_t *data) +{ + memcpy(data, &fm_config.aud_cfg, sizeof(struct fm_audio_info_t)); + return 0; +} + +static signed int mt6631_hw_info_get(struct fm_hw_info *req) +{ + if (req == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + req->chip_id = mt6631_hw_info.chip_id; + req->eco_ver = mt6631_hw_info.eco_ver; + req->patch_ver = mt6631_hw_info.patch_ver; + req->rom_ver = mt6631_hw_info.rom_ver; + + return 0; +} + +static signed int mt6631_pre_search(void) +{ + mt6631_RampDown(); + /* disable audio output I2S Rx mode */ + fm_host_reg_write(0x80101054, 0x00000000); + /* disable audio output I2S Tx mode */ + fm_reg_write(0x9B, 0x0000); + + return 0; +} + +static signed int mt6631_restore_search(void) +{ + mt6631_RampDown(); + /* set audio output I2S Tx mode */ + fm_reg_write(0x9B, 0xF9AB); + /* set audio output I2S Rx mode */ + fm_host_reg_write(0x80101054, 0x00003f35); + return 0; +} + +static signed int mt6631_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid) +{ + signed int ret = 0; + signed int i = 0; + unsigned short pkt_size; + unsigned int reg_val = 0; + bool flag_spi_hopping = false; + struct mt6631_full_cqi *p_cqi; + signed int RSSI = 0, PAMD = 0, MR = 0, ATDC = 0; + unsigned int PRX = 0, ATDEV = 0; + unsigned short softmuteGainLvl = 0; + signed int projectid = fm_cb_op->projectid_get(); + + ret = mt6631_chan_para_get(freq); + if (ret == 2) + ret = fm_set_bits(FM_CHANNEL_SET, 0x2000, 0x0FFF); /* mdf HiLo */ + else + ret = fm_set_bits(FM_CHANNEL_SET, 0x0000, 0x0FFF); /* clear FA/HL/ATJ */ + + /* SPI hoppint setting*/ + if (mt6631_SPI_hopping_check(freq)) { + WCN_DBG(FM_NTC | CHIP, "%s: freq:%d is SPI hopping channel,turn on 64M PLL\n", __func__, freq); + + if (projectid != 0x6779) { + /*Disable TOP2/64M sleep*/ + ret = fm_host_reg_read(0x81021138, ®_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: read 64M reg 0x81021138 failed\n", __func__); + reg_val |= 0x00000080; + ret = fm_host_reg_write(0x81021138, reg_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: disable 64M sleep failed\n", __func__); + } + /* lock 64M */ + if (projectid != 0x6768 && projectid != 0x6779 + && projectid != 0x6785) { + ret = fm_host_reg_read(0x80026000, ®_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M reg 0x80026000 failed\n", __func__); + ret = fm_host_reg_write(0x80026000, reg_val | (0x1 << 28)); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M failed\n", __func__); + } else { + ret = fm_host_reg_read(0x80023008, ®_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M reg 0x80023008 failed\n", __func__); + ret = fm_host_reg_write(0x80023008, reg_val | (0x1 << 21)); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M failed\n", __func__); + } + + for (i = 0; i < 100; i++) { /*rd 0x8002110C until D27 ==1*/ + + if (projectid != 0x6768 && projectid != 0x6779 + && projectid != 0x6785) + ret = fm_host_reg_read(0x8002110C, ®_val); + else + ret = fm_host_reg_read(0x80021118, ®_val); + + if (reg_val & 0x08000000) { + WCN_DBG(FM_NTC | CHIP, "%s: POLLING PLL_RDY success !\n", __func__); + flag_spi_hopping = mt6631_switch_clk_64m() == 0; + break; + } + fm_delayus(10); + } + if (false == flag_spi_hopping) + WCN_DBG(FM_ERR | CHIP, "%s: Polling to read rd 0x8002110C[27] ==0x1 failed !\n", __func__); + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + p_cqi = (struct mt6631_full_cqi *)&fm_res->cqi[2]; + /* just for debug */ + WCN_DBG(FM_NTC | CHIP, + "freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", + p_cqi->ch, p_cqi->rssi, p_cqi->pamd, p_cqi->pr, p_cqi->fpamd, p_cqi->mr, + p_cqi->atdc, p_cqi->prx, p_cqi->atdev, p_cqi->smg, p_cqi->drssi); + RSSI = ((p_cqi->rssi & 0x03FF) >= 512) ? ((p_cqi->rssi & 0x03FF) - 1024) : (p_cqi->rssi & 0x03FF); + PAMD = ((p_cqi->pamd & 0x1FF) >= 256) ? ((p_cqi->pamd & 0x01FF) - 512) : (p_cqi->pamd & 0x01FF); + MR = ((p_cqi->mr & 0x01FF) >= 256) ? ((p_cqi->mr & 0x01FF) - 512) : (p_cqi->mr & 0x01FF); + ATDC = (p_cqi->atdc >= 32768) ? (65536 - p_cqi->atdc) : (p_cqi->atdc); + if (ATDC < 0) + ATDC = (~(ATDC)) - 1; /* Get abs value of ATDC */ + + PRX = (p_cqi->prx & 0x00FF); + ATDEV = p_cqi->atdev; + softmuteGainLvl = p_cqi->smg; + /* check if the channel is valid according to each CQIs */ + if ((fm_config.rx_cfg.long_ana_rssi_th <= RSSI) + && (fm_config.rx_cfg.pamd_th >= PAMD) + && (fm_config.rx_cfg.atdc_th >= ATDC) + && (fm_config.rx_cfg.mr_th <= MR) + && (fm_config.rx_cfg.prx_th <= PRX) + && (ATDEV >= ATDC) /* sync scan algorithm */ + && (fm_config.rx_cfg.smg_th <= softmuteGainLvl)) { + *valid = true; + } else { + *valid = false; + } + *rssi = RSSI; + } else { + WCN_DBG(FM_ALT | CHIP, "smt get CQI failed\n"); + return false; + } + WCN_DBG(FM_NTC | CHIP, "valid=%d\n", *valid); + return true; +} + +static bool mt6631_em_test(unsigned short group_idx, unsigned short item_idx, unsigned int item_value) +{ + return true; +} + +/* +*parm: +* parm.th_type: 0, RSSI. 1, desense RSSI. 2, SMG. +* parm.th_val: threshold value +*/ +static signed int mt6631_set_search_th(signed int idx, signed int val, signed int reserve) +{ + switch (idx) { + case 0: { + fm_config.rx_cfg.long_ana_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set rssi th =%d\n", val); + break; + } + case 1: { + fm_config.rx_cfg.desene_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set desense rssi th =%d\n", val); + break; + } + case 2: { + fm_config.rx_cfg.smg_th = val; + WCN_DBG(FM_NTC | CHIP, "set smg th =%d\n", val); + break; + } + default: + break; + } + return 0; +} + +static signed int MT6631_low_power_wa_default(signed int fmon) +{ + return 0; +} + +signed int fm_low_ops_register(struct fm_callback *cb, struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,bi invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_get == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_get invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_set == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_set invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_cb_op = cb; + + bi->pwron = mt6631_pwron; + bi->pwroff = mt6631_pwroff; + bi->chipid_get = mt6631_get_chipid; + bi->mute = mt6631_Mute; + bi->rampdown = mt6631_RampDown; + bi->pwrupseq = mt6631_PowerUp; + bi->pwrdownseq = mt6631_PowerDown; + bi->setfreq = mt6631_SetFreq; + bi->low_pwr_wa = MT6631_low_power_wa_default; + bi->get_aud_info = mt6631_get_audio_info; + bi->rssiget = mt6631_GetCurRSSI; + bi->volset = mt6631_SetVol; + bi->volget = mt6631_GetVol; + bi->dumpreg = mt6631_dump_reg; + bi->msget = mt6631_GetMonoStereo; + bi->msset = mt6631_SetMonoStereo; + bi->pamdget = mt6631_GetCurPamd; + bi->em = mt6631_em_test; + bi->anaswitch = mt6631_SetAntennaType; + bi->anaget = mt6631_GetAntennaType; + bi->caparray_get = mt6631_GetCapArray; + bi->hwinfo_get = mt6631_hw_info_get; + bi->i2s_get = mt6631_i2s_info_get; + bi->is_dese_chan = mt6631_is_dese_chan; + bi->softmute_tune = mt6631_soft_mute_tune; + bi->desense_check = mt6631_desense_check; + bi->cqi_log = mt6631_full_cqi_get; + bi->pre_search = mt6631_pre_search; + bi->restore_search = mt6631_restore_search; + bi->set_search_th = mt6631_set_search_th; + bi->is_valid_freq = mt6631_is_valid_freq; + + cmd_buf_lock = fm_lock_create("31_cmd"); + ret = fm_lock_get(cmd_buf_lock); + + cmd_buf = fm_zalloc(TX_BUF_SIZE + 1); + + if (!cmd_buf) { + WCN_DBG(FM_ALT | CHIP, "6631 fm lib alloc tx buf failed\n"); + ret = -1; + } +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ + cqi_fifo = fm_fifo_create("6628_cqi_fifo", sizeof(struct adapt_fm_cqi), 640); + if (!cqi_fifo) { + WCN_DBG(FM_ALT | CHIP, "6631 fm lib create cqi fifo failed\n"); + ret = -1; + } +#endif + + return ret; +} + +signed int fm_low_ops_unregister(struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,bi invalid pointer\n", __func__); + return -FM_EPARA; + } + +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ + fm_fifo_release(cqi_fifo); +#endif + + if (cmd_buf) { + fm_free(cmd_buf); + cmd_buf = NULL; + } + + ret = fm_lock_put(cmd_buf_lock); + fm_memset(bi, 0, sizeof(struct fm_basic_interface)); + + fm_cb_op = NULL; + + return ret; +} + +static const signed char mt6631_chan_para_map[] = { + /* 0, X, 1, X, 2, X, 3, X, 4, X, 5, X, 6, X, 7, X, 8, X, 9, X*/ + 0, 0, 2, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6500~6595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6600~6695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, /* 6700~6795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6800~6895 */ + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6900~6995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7000~7095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7100~7195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, /* 7200~7295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, /* 7300~7395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 7400~7495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7500~7595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 7600~7695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7700~7795 */ + 8, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7800~7895 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7900~7995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8000~8095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8100~8195 */ + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8200~8295 */ + 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, /* 8300~8395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8400~8495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8500~8595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8600~8695 */ + 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8700~8795 */ + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8800~8895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8900~8995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9000~9095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9100~9195 */ + 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9200~9295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9300~9395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9400~9495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9500~9595 */ + 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9600~9695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9700~9795 */ + 0, 0, 0, 0, 0, 0, 8, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9800~9895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 9900~9995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10000~10095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10100~10195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, /* 10200~10295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* 10300~10395 */ + 8, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10400~10495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, /* 10500~10595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10600~10695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 10700~10795 */ + 0 /* 10800 */ +}; +static const unsigned short mt6631_scan_dese_list[] = { + 6910, 6920, 7680, 7800, 8450, 9210, 9220, 9230, 9590, 9600, 9830, 9900, 9980, 9990, 10400, 10750, 10760 +}; + +static const unsigned short mt6631_SPI_hopping_list[] = { + 6510, 6520, 6530, 7780, 7790, 7800, 7810, 7820, 9090, 9100, 9110, 9120, 10380, 10390, 10400, 10410, 10420 +}; + +static const unsigned short mt6631_I2S_hopping_list[] = { + 6550, 6760, 6960, 6970, 7170, 7370, 7580, 7780, 7990, 8810, 9210, 9220, 10240 +}; + +static const unsigned short mt6631_TDD_list[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6500~6595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6600~6695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6700~6795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6800~6895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6900~6995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7000~7095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7100~7195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7200~7295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7300~7395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7400~7495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7500~7595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7600~7695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7700~7795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7800~7895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7900~7995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8000~8095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8100~8195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8200~8295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8300~8395 */ + 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, /* 8400~8495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8500~8595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8600~8695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8700~8795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8800~8895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8900~8995 */ + 0x0000, 0x0000, 0x0101, 0x0101, 0x0101, /* 9000~9095 */ + 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, /* 9100~9195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9200~9295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9300~9395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9400~9495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9500~9595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9600~9695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, /* 9700~9795 */ + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, /* 9800~9895 */ + 0x0101, 0x0101, 0x0001, 0x0000, 0x0000, /* 9900~9995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10000~10095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10100~10195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10200~10295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10300~10395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10400~10495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10500~10595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, /* 10600~10695 */ + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, /* 10700~10795 */ + 0x0001 /* 10800 */ +}; + +static const unsigned short mt6631_TDD_Mask[] = { + 0x0001, 0x0010, 0x0100, 0x1000 +}; + +/* return value: 0, not a de-sense channel; 1, this is a de-sense channel; else error no */ +static signed int mt6631_is_dese_chan(unsigned short freq) +{ + signed int size; + + if (1 == HQA_ZERO_DESENSE_MAP) /*HQA only :skip desense channel check. */ + return 0; + + size = ARRAY_SIZE(mt6631_scan_dese_list); + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + while (size) { + if (mt6631_scan_dese_list[size - 1] == freq) + return 1; + + size--; + } + + return 0; +} + +/* return value: +*1, is desense channel and rssi is less than threshold; +*0, not desense channel or it is but rssi is more than threshold. +*/ +static signed int mt6631_desense_check(unsigned short freq, signed int rssi) +{ + if (mt6631_is_dese_chan(freq)) { + if (rssi < fm_config.rx_cfg.desene_rssi_th) + return 1; + + WCN_DBG(FM_DBG | CHIP, "desen_rssi %d th:%d\n", rssi, fm_config.rx_cfg.desene_rssi_th); + } + return 0; +} + +static bool mt6631_TDD_chan_check(unsigned short freq) +{ + unsigned int i = 0; + unsigned short freq_tmp = freq; + signed int ret = 0; + + ret = fm_get_channel_space(freq_tmp); + if (ret == 0) + freq_tmp *= 10; + else if (ret == -1) + return false; + + i = (freq_tmp - 6500) / 5; + if ((i / 4) >= ARRAY_SIZE(mt6631_TDD_list)) { + WCN_DBG(FM_ERR | CHIP, "Freq index out of range(%d),max(%zd)\n", + i / 4, ARRAY_SIZE(mt6631_TDD_list)); + return false; + } + + if (mt6631_TDD_list[i / 4] & mt6631_TDD_Mask[i % 4]) { + WCN_DBG(FM_DBG | CHIP, "Freq %d use TDD solution\n", freq); + return true; + } else + return false; +} + +/* get channel parameter, HL side/ FA / ATJ */ +static unsigned short mt6631_chan_para_get(unsigned short freq) +{ + signed int pos, size; + + if (1 == HQA_RETURN_ZERO_MAP) { + WCN_DBG(FM_NTC | CHIP, "HQA_RETURN_ZERO_CHAN mt6631_chan_para_map enabled!\n"); + return 0; + } + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + if (freq < 6500) + return 0; + + pos = (freq - 6500) / 5; + + size = ARRAY_SIZE(mt6631_chan_para_map); + + pos = (pos > (size - 1)) ? (size - 1) : pos; + + return mt6631_chan_para_map[pos]; +} + + +static bool mt6631_SPI_hopping_check(unsigned short freq) +{ + signed int size; + + size = ARRAY_SIZE(mt6631_SPI_hopping_list); + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + while (size) { + if (mt6631_SPI_hopping_list[size - 1] == freq) + return 1; + size--; + } + + return 0; +} + diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6631/pub/mt6631_fm_rds.c b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6631/pub/mt6631_fm_rds.c new file mode 100644 index 00000000000000..d3abcea779785b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6631/pub/mt6631_fm_rds.c @@ -0,0 +1,335 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_rds.h" +#include "mt6631_fm_reg.h" +#include "fm_cmd.h" + +static bool bRDS_FirstIn; /* false */ +static unsigned int gBLER_CHK_INTERVAL = 500; +static unsigned short GOOD_BLK_CNT = 0, BAD_BLK_CNT; +static unsigned char BAD_BLK_RATIO; + +static struct fm_basic_interface *fm_bi; + +static bool mt6631_RDS_support(void); +static signed int mt6631_RDS_enable(void); +static signed int mt6631_RDS_disable(void); +static unsigned short mt6631_RDS_Get_GoodBlock_Counter(void); +static unsigned short mt6631_RDS_Get_BadBlock_Counter(void); +static unsigned char mt6631_RDS_Get_BadBlock_Ratio(void); +static unsigned int mt6631_RDS_Get_BlerCheck_Interval(void); +/* static void mt6631_RDS_GetData(unsigned short *data, unsigned short datalen); */ +static void mt6631_RDS_Init_Data(struct rds_t *pstRDSData); + +static bool mt6631_RDS_support(void) +{ + return true; +} + +static signed int mt6631_RDS_enable(void) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | RDSC, "rds enable\n"); + ret = fm_reg_read(FM_RDS_CFG0, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable read 0x80 fail\n"); + return ret; + } + ret = fm_reg_write(FM_RDS_CFG0, 6); /* set buf_start_th */ + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable write 0x80 fail\n"); + return ret; + } + ret = fm_reg_read(FM_MAIN_CTRL, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable read 0x63 fail\n"); + return ret; + } + ret = fm_reg_write(FM_MAIN_CTRL, dataRead | (RDS_MASK)); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable write 0x63 fail\n"); + return ret; + } + + return ret; +} + +static signed int mt6631_RDS_disable(void) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | RDSC, "rds disable\n"); + ret = fm_reg_read(FM_MAIN_CTRL, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds disable read 0x63 fail\n"); + return ret; + } + ret = fm_reg_write(FM_MAIN_CTRL, dataRead & (~RDS_MASK)); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds disable write 0x63 fail\n"); + return ret; + } + + return ret; +} + +static unsigned short mt6631_RDS_Get_GoodBlock_Counter(void) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RDS_GOODBK_CNT, &tmp_reg); + GOOD_BLK_CNT = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get good block cnt:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static unsigned short mt6631_RDS_Get_BadBlock_Counter(void) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RDS_BADBK_CNT, &tmp_reg); + BAD_BLK_CNT = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get bad block cnt:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static unsigned char mt6631_RDS_Get_BadBlock_Ratio(void) +{ + unsigned short tmp_reg; + unsigned short gbc; + unsigned short bbc; + + gbc = mt6631_RDS_Get_GoodBlock_Counter(); + bbc = mt6631_RDS_Get_BadBlock_Counter(); + + if ((gbc + bbc) > 0) + tmp_reg = (unsigned char) (bbc * 100 / (gbc + bbc)); + else + tmp_reg = 0; + + BAD_BLK_RATIO = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get badblock ratio:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static signed int mt6631_RDS_BlockCounter_Reset(void) +{ + mt6631_RDS_disable(); + mt6631_RDS_enable(); + + return 0; +} + +static unsigned int mt6631_RDS_Get_BlerCheck_Interval(void) +{ + return gBLER_CHK_INTERVAL; +} + +static signed int mt6631_RDS_BlerCheck(struct rds_t *dst) +{ + return 0; +} + +#if 0 +static void RDS_Recovery_Handler(void) +{ + unsigned short tempData = 0; + + do { + fm_reg_read(FM_RDS_DATA_REG, &tempData); + fm_reg_read(FM_RDS_POINTER, &tempData); + } while (tempData & 0x3); +} +#endif + +#if 0 +static void mt6631_RDS_GetData(unsigned short *data, unsigned short datalen) +{ +#define RDS_GROUP_DIFF_OFS 0x007C +#define RDS_FIFO_DIFF 0x007F +#define RDS_CRC_BLK_ADJ 0x0020 +#define RDS_CRC_CORR_CNT 0x001E +#define RDS_CRC_INFO 0x0001 + + unsigned short CRC = 0, i = 0, RDS_adj = 0, RDSDataCount = 0, FM_WARorrCnt = 0; + unsigned short temp = 0, OutputPofm_s32 = 0; + + WCN_DBG(FM_DBG | RDSC, "get data\n"); + fm_reg_read(FM_RDS_FIFO_STATUS0, &temp); + RDSDataCount = ((RDS_GROUP_DIFF_OFS & temp) << 2); + + if ((temp & RDS_FIFO_DIFF) >= 4) { + /* block A data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 10; + CRC |= (temp & RDS_CRC_INFO) << 3; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 11); + fm_reg_read(FM_RDS_DATA_REG, &data[0]); + + /* block B data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 9; + CRC |= (temp & RDS_CRC_INFO) << 2; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 7); + fm_reg_read(FM_RDS_DATA_REG, &data[1]); + + /* block C data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 8; + CRC |= (temp & RDS_CRC_INFO) << 1; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 3); + fm_reg_read(FM_RDS_DATA_REG, &data[2]); + + /* block D data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 7; + CRC |= (temp & RDS_CRC_INFO); + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) >> 1); + fm_reg_read(FM_RDS_DATA_REG, &data[3]); + + data[4] = (CRC | RDS_adj | RDSDataCount); + data[5] = FM_WARorrCnt; + + fm_reg_read(FM_RDS_PWDI, &data[6]); + fm_reg_read(FM_RDS_PWDQ, &data[7]); + + fm_reg_read(FM_RDS_POINTER, &OutputPofm_s32); + + /* Go fm_s32o RDS recovery handler while RDS output pofm_s32 doesn't align to 4 in numeric */ + if (OutputPofm_s32 & 0x3) + RDS_Recovery_Handler(); + + } else { + for (; i < 8; i++) + data[i] = 0; + } +} +#endif + +static void mt6631_RDS_Init_Data(struct rds_t *pstRDSData) +{ + fm_memset(pstRDSData, 0, sizeof(struct rds_t)); + bRDS_FirstIn = true; + + pstRDSData->event_status = 0x0000; + fm_memset(pstRDSData->RT_Data.TextData, 0x20, sizeof(pstRDSData->RT_Data.TextData)); + fm_memset(pstRDSData->PS_Data.PS, '\0', sizeof(pstRDSData->PS_Data.PS)); + fm_memset(pstRDSData->PS_ON, 0x20, sizeof(pstRDSData->PS_ON)); +} + +bool mt6631_RDS_OnOff(struct rds_t *dst, bool bFlag) +{ + signed int ret = 0; + + if (mt6631_RDS_support() == false) { + WCN_DBG(FM_ALT | RDSC, "mt6631_RDS_OnOff failed, RDS not support\n"); + return false; + } + + if (bFlag) { + mt6631_RDS_Init_Data(dst); + ret = mt6631_RDS_enable(); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "mt6631_RDS_OnOff enable failed\n"); + return false; + } + } else { + mt6631_RDS_Init_Data(dst); + ret = mt6631_RDS_disable(); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "mt6631_RDS_OnOff disable failed\n"); + return false; + } + } + + return true; +} + +DEFINE_RDSLOG(mt6631_rds_log); + +/* mt6631_RDS_Efm_s32_Handler - response FM RDS interrupt + * @fm - main data structure of FM driver + * This function first get RDS raw data, then call RDS spec parser + */ +static signed int mt6631_rds_parser(struct rds_t *rds_dst, struct rds_rx_t *rds_raw, + signed int rds_size, unsigned short(*getfreq) (void)) +{ + mt6631_rds_log.log_in(&mt6631_rds_log, rds_raw, rds_size); + return rds_parser(rds_dst, rds_raw, rds_size, getfreq); +} + +static signed int mt6631_rds_log_get(struct rds_rx_t *dst, signed int *dst_len) +{ + return mt6631_rds_log.log_out(&mt6631_rds_log, dst, dst_len); +} + +static signed int mt6631_rds_gc_get(struct rds_group_cnt_t *dst, struct rds_t *rdsp) +{ + return rds_grp_counter_get(dst, &rdsp->gc); +} + +static signed int mt6631_rds_gc_reset(struct rds_t *rdsp) +{ + return rds_grp_counter_reset(&rdsp->gc); +} + +signed int fm_rds_ops_register(struct fm_basic_interface *bi, struct fm_rds_interface *ri) +{ + signed int ret = 0; + + if (ri == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,ri invalid pointer\n", __func__); + return -FM_EPARA; + } + + fm_bi = bi; + + ri->rds_blercheck = mt6631_RDS_BlerCheck; + ri->rds_onoff = mt6631_RDS_OnOff; + ri->rds_parser = mt6631_rds_parser; + ri->rds_gbc_get = mt6631_RDS_Get_GoodBlock_Counter; + ri->rds_bbc_get = mt6631_RDS_Get_BadBlock_Counter; + ri->rds_bbr_get = mt6631_RDS_Get_BadBlock_Ratio; + ri->rds_bc_reset = mt6631_RDS_BlockCounter_Reset; + ri->rds_bci_get = mt6631_RDS_Get_BlerCheck_Interval; + ri->rds_log_get = mt6631_rds_log_get; + ri->rds_gc_get = mt6631_rds_gc_get; + ri->rds_gc_reset = mt6631_rds_gc_reset; + + return ret; +} + +signed int fm_rds_ops_unregister(struct fm_rds_interface *ri) +{ + signed int ret = 0; + + if (ri == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,ri invalid pointer\n", __func__); + return -FM_EPARA; + } + + fm_bi = NULL; + fm_memset(ri, 0, sizeof(struct fm_rds_interface)); + return ret; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6632/inc/mt6632_fm_lib.h b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6632/inc/mt6632_fm_lib.h new file mode 100644 index 00000000000000..1c1ae7ea5056e4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6632/inc/mt6632_fm_lib.h @@ -0,0 +1,69 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ + +#ifndef __MT6632_FM_LIB_H__ +#define __MT6632_FM_LIB_H__ + +#include "fm_typedef.h" + +enum { + DSPPATCH = 0xFFF9, + USDELAY = 0xFFFA, + MSDELAY = 0xFFFB, + HW_VER = 0xFFFD, + POLL_N = 0xFFFE, /* poling check if bit(n) is '0' */ + POLL_P = 0xFFFF, /* polling check if bit(n) is '1' */ +}; + +enum { + FM_PUS_DSPPATCH = DSPPATCH, + FM_PUS_USDELAY = USDELAY, + FM_PUS_MSDELAY = MSDELAY, + FM_PUS_HW_VER = HW_VER, + FM_PUS_POLL_N = POLL_N, /* poling check if bit(n) is '0' */ + FM_PUS_POLL_P = POLL_P, /* polling check if bit(n) is '1' */ + FM_PUS_MAX +}; + +enum { + mt6632_E1 = 0, + mt6632_E2 +}; + +struct mt6632_fm_cqi { + unsigned short ch; + unsigned short rssi; + unsigned short reserve; +}; + +struct adapt_fm_cqi { + signed int ch; + signed int rssi; + signed int reserve; +}; + +struct mt6632_full_cqi { + unsigned short ch; + unsigned short rssi; + unsigned short pamd; + unsigned short pr; + unsigned short fpamd; + unsigned short mr; + unsigned short atdc; + unsigned short prx; + unsigned short atdev; + unsigned short smg; /* soft-mute gain */ + unsigned short drssi; /* delta rssi */ +}; + +#endif diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6632/inc/mt6632_fm_reg.h b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6632/inc/mt6632_fm_reg.h new file mode 100644 index 00000000000000..d1e0f62063abae --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6632/inc/mt6632_fm_reg.h @@ -0,0 +1,58 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ + +#ifndef __MT6632_FM_REG_H__ +#define __MT6632_FM_REG_H__ + +/* RDS_BDGRP_ABD_CTRL_REG */ +enum { + BDGRP_ABD_EN = 0x0001, + BER_RUN = 0x2000 +}; +#define FM_DAC_CON1 0x83 +#define FM_DAC_CON2 0x84 +#define FM_FT_CON0 0x86 +enum { + FT_EN = 0x0001 +}; + +#define FM_I2S_CON0 0x90 +enum { + I2S_EN = 0x0001, + FORMAT = 0x0002, + WLEN = 0x0004, + I2S_SRC = 0x0008 +}; + +/* FM_MAIN_CTRL */ +enum { + TUNE = 0x0001, + SEEK = 0x0002, + SCAN = 0x0004, + CQI_READ = 0x0008, + RDS_MASK = 0x0010, + MUTE = 0x0020, + RDS_BRST = 0x0040, + RAMP_DOWN = 0x0100, +}; + +enum { + ANTENNA_TYPE = 0x0010, /* 0x61 D4, 0:long, 1:short */ + ANALOG_I2S = 0x0080, /* 0x61 D7, 0:lineout, 1:I2S */ + DE_EMPHASIS = 0x1000, /* 0x61 D12,0:50us, 1:75 us */ +}; + +#define OSC_FREQ_BITS 0x0070 /* 0x60 bit4~6 */ +#define OSC_FREQ_MASK (~OSC_FREQ_BITS) + +#endif /* __MT6632_FM_REG_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6632/pub/mt6632_fm_lib.c b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6632/pub/mt6632_fm_lib.c new file mode 100644 index 00000000000000..7ae2563858c9c5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6632/pub/mt6632_fm_lib.c @@ -0,0 +1,1795 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ + +#include <linux/slab.h> +#include <linux/vmalloc.h> + +#include "stp_exp.h" +#include "wmt_exp.h" + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_patch.h" +#include "fm_utils.h" +#include "fm_link.h" +#include "fm_config.h" +#include "fm_cmd.h" + +#include "mt6632_fm_reg.h" +#include "mt6632_fm_lib.h" + +static struct fm_patch_tbl mt6632_patch_tbl[5] = { + {FM_ROM_V1, "mt6632_fm_v1_patch.bin", "mt6632_fm_v1_coeff.bin", NULL, NULL}, + {FM_ROM_V2, "mt6632_fm_v2_patch.bin", "mt6632_fm_v2_coeff.bin", NULL, NULL}, + {FM_ROM_V3, "mt6632_fm_v3_patch.bin", "mt6632_fm_v3_coeff.bin", NULL, NULL}, + {FM_ROM_V4, "mt6632_fm_v4_patch.bin", "mt6632_fm_v4_coeff.bin", NULL, NULL}, + {FM_ROM_V5, "mt6632_fm_v5_patch.bin", "mt6632_fm_v5_coeff.bin", NULL, NULL}, +}; + + +static struct fm_hw_info mt6632_hw_info = { + .chip_id = 0x00006632, + .eco_ver = 0x00000000, + .rom_ver = 0x00000000, + .patch_ver = 0x00000000, + .reserve = 0x00000000, +}; + +unsigned char *cmd_buf; +struct fm_lock *cmd_buf_lock; +struct fm_res_ctx *fm_res; +static struct fm_callback *fm_cb_op; +static unsigned char fm_packaging = 1; /*0:QFN,1:WLCSP */ +static unsigned int fm_sant_flag; /* 1,Short Antenna; 0, Long Antenna */ +static signed int mt6632_is_dese_chan(unsigned short freq); +#if 0 +static signed int mt6632_mcu_dese(unsigned short freq, void *arg); +#endif +static signed int mt6632_gps_dese(unsigned short freq, void *arg); + +static signed int mt6632_I2s_Setting(signed int onoff, signed int mode, signed int sample); +static unsigned short mt6632_chan_para_get(unsigned short freq); +static signed int mt6632_desense_check(unsigned short freq, signed int rssi); +static bool mt6632_TDD_chan_check(unsigned short freq); +static signed int mt6632_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid); +static signed int mt6632_pwron(signed int data) +{ + if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM) == MTK_WCN_BOOL_FALSE) { + WCN_DBG(FM_ERR | CHIP, "WMT turn on FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn on FM OK!\n"); + return 0; +} + +static signed int mt6632_pwroff(signed int data) +{ + if (mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM) == MTK_WCN_BOOL_FALSE) { + WCN_DBG(FM_ERR | CHIP, "WMT turn off FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn off FM OK!\n"); + return 0; +} + +static unsigned short mt6632_get_chipid(void) +{ + return 0x6632; +} + +/* MT6632_SetAntennaType - set Antenna type + * @type - 1,Short Antenna; 0, Long Antenna + */ +static signed int mt6632_SetAntennaType(signed int type) +{ + unsigned short dataRead = 0; + + WCN_DBG(FM_NTC | CHIP, "set ana to %s\n", type ? "short" : "long"); + if (fm_packaging == 0) { + fm_sant_flag = type; + } else { + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + + if (type) + dataRead |= ANTENNA_TYPE; + else + dataRead &= (~ANTENNA_TYPE); + + fm_reg_write(FM_MAIN_CG2_CTRL, dataRead); + } + return 0; +} + +static signed int mt6632_GetAntennaType(void) +{ + unsigned short dataRead = 0; + + if (fm_packaging == 0) + return fm_sant_flag; + + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + WCN_DBG(FM_NTC | CHIP, "get ana type: %s\n", (dataRead & ANTENNA_TYPE) ? "short" : "long"); + + if (dataRead & ANTENNA_TYPE) + return FM_ANA_SHORT; /* short antenna */ + else + return FM_ANA_LONG; /* long antenna */ +} + +static signed int mt6632_Mute(bool mute) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_NTC | CHIP, "set %s\n", mute ? "mute" : "unmute"); + fm_reg_read(FM_MAIN_CTRL, &dataRead); + + if (mute == 1) + ret = fm_reg_write(FM_MAIN_CTRL, (dataRead & 0xFFDF) | 0x0020); + else + ret = fm_reg_write(FM_MAIN_CTRL, (dataRead & 0xFFDF)); + + return ret; +} + +static signed int mt6632_rampdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* Clear DSP state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF0, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* Set DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFEFF, RAMP_DOWN, &buf[pkt_size], buf_size - pkt_size); + /* @Wait for STC_DONE interrupt@ */ + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size], + buf_size - pkt_size); + /* Clear DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, (~RAMP_DOWN), 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFE, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6632_rampdown - f/w will wait for STC_DONE interrupt + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6632_rampdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6632_rampdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_RAMPDOWN_OPCODE, pkt_size); +} + +static signed int mt6632_RampDown(void) +{ + signed int ret = 0; + unsigned short pkt_size; + /* unsigned short tmp; */ + + WCN_DBG(FM_NTC | CHIP, "ramp down\n"); + + ret = fm_reg_write(FM_MAIN_EXTINTRMASK, 0x0000); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down write FM_MAIN_EXTINTRMASK failed\n"); + return ret; + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6632_rampdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_RAMPDOWN, SW_RETRY_CNT, RAMPDOWN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down failed\n"); + return ret; + } + + ret = fm_reg_write(FM_MAIN_EXTINTRMASK, 0x0021); + if (ret) + WCN_DBG(FM_ERR | CHIP, "ramp down write FM_MAIN_EXTINTRMASK failed\n"); + + return ret; +} + +static signed int mt6632_get_rom_version(void) +{ + unsigned short tmp = 0; + signed int ret = 0; + + /* set download dsp coefficient mode */ + fm_reg_write(0x90, 0xe); + /* fill in coefficient data */ + fm_reg_write(0x92, 0x0); + /* reset download control */ + fm_reg_write(0x90, 0x40); + /* disable memory control from host */ + fm_reg_write(0x90, 0x0); + + /* DSP rom code version request enable --- set 0x61 b15=1 */ + fm_set_bits(0x61, 0x8000, 0x7FFF); + + /* Release ASIP reset --- set 0x61 b1=1 */ + fm_set_bits(0x61, 0x0002, 0xFFFD); + + /* Enable ASIP power --- set 0x61 b0=0 */ + fm_set_bits(0x61, 0x0000, 0xFFFE); + + /* Wait DSP code version ready --- wait 1ms */ + do { + fm_delayus(1000); + ret = fm_reg_read(0x84, &tmp); + /* ret=-4 means signal got when control FM. usually get sig 9 to kill FM process. */ + /* now cancel FM power up sequence is recommended. */ + if (ret) + return ret; + + WCN_DBG(FM_DBG | CHIP, "0x84=%x\n", tmp); + } while (tmp != 0x0001); + + /* Get FM DSP code version --- rd 0x83[15:8] */ + fm_reg_read(0x83, &tmp); + WCN_DBG(FM_NTC | CHIP, "DSP ver=0x%x\n", tmp); + tmp = (tmp >> 8); + + /* DSP rom code version request disable --- set 0x61 b15=0 */ + fm_set_bits(0x61, 0x0000, 0x7FFF); + + /* Reset ASIP --- set 0x61[1:0] = 1 */ + fm_set_bits(0x61, 0x0001, 0xFFFC); + + /* WCN_DBG(FM_NTC | CHIP, "ROM version: v%d\n", (signed int)tmp); */ + return (signed int) tmp; +} + +static signed int mt6632_pmic_read(unsigned char addr, unsigned int *val) +{ + signed int ret = 0; + unsigned char read_reslut = 0xff; + unsigned short pkt_size; + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_pmic_get_reg(cmd_buf, TX_BUF_SIZE, addr); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_PMIC_READ, SW_RETRY_CNT, PMIC_CONTROL_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + fm_memcpy(val, &fm_res->pmic_result[0], sizeof(unsigned int)); + read_reslut = fm_res->pmic_result[4]; + } else { + WCN_DBG(FM_ERR | CHIP, "mt6632_pmic_read failed,ret(%d)\n", ret); + return -1; + } + + if (read_reslut) { + WCN_DBG(FM_ERR | CHIP, "mt6632_pmic_read failed(%02x)\n", read_reslut); + return -2; + } + return ret; +} + +static signed int mt6632_pmic_write(unsigned char addr, unsigned int val) +{ + signed int ret = 0; + unsigned char read_reslut = 0xff; + unsigned short pkt_size; + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_pmic_set_reg(cmd_buf, TX_BUF_SIZE, addr, val); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_PMIC_MODIFY, SW_RETRY_CNT, + PMIC_CONTROL_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) + read_reslut = fm_res->pmic_result[0]; + else { + WCN_DBG(FM_ERR | CHIP, "mt6632_pmic_write failed,ret(%d)\n", ret); + return -1; + } + + if (read_reslut) { + WCN_DBG(FM_ERR | CHIP, "mt6632_pmic_write failed(%02x)\n", read_reslut); + return -2; + } + + return ret; +} + +static signed int mt6632_pmic_mod(unsigned char addr, unsigned int mask_and, unsigned int mask_or) +{ + signed int ret = 0; + unsigned char read_reslut = 0xff; + unsigned short pkt_size; + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_pmic_mod_reg(cmd_buf, TX_BUF_SIZE, addr, mask_and, mask_or); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_PMIC_MODIFY, SW_RETRY_CNT, + PMIC_CONTROL_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) + read_reslut = fm_res->pmic_result[0]; + else { + WCN_DBG(FM_ERR | CHIP, "mt6632_pmic_mod failed,ret(%d)\n", ret); + return -1; + } + + if (read_reslut) { + WCN_DBG(FM_ERR | CHIP, "mt6632_pmic_mod failed(%02x)\n", read_reslut); + return -2; + } + return ret; +} + +static signed int mt6632_pmic_ctrl(void) +{ + signed int ret = 0; + unsigned int val = 0; + + ret = mt6632_pmic_mod(0xa8, 0xFFFFFFF7, 0x00000008); + if (!ret) { + mt6632_pmic_read(0xa8, &val); + WCN_DBG(FM_NTC | CHIP, "0xa8 = %08x\n", val); + } else { + WCN_DBG(FM_ERR | CHIP, "mt6632_pmic_ctrl 0xa8 failed(%d)\n", ret); + return ret; + } + + ret = mt6632_pmic_mod(0xc7, 0x7FFFFFCF, 0x00000000); + if (!ret) { + mt6632_pmic_read(0xc7, &val); + WCN_DBG(FM_NTC | CHIP, "0xc7 = %08x\n", val); + } else { + WCN_DBG(FM_ERR | CHIP, "mt6632_pmic_ctrl 0xc7 failed(%d)\n", ret); + return ret; + } + + return ret; +} + +static signed int mt6632_pwrup_top_setting(void) +{ + signed int ret = 0, value = 0; + /* A0.1 Turn on FM buffer */ + ret = fm_host_reg_read(0x81020008, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81020008, value | 0x30); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 wr failed\n"); + return ret; + } + /* A0.2 Set xtal no off when FM on */ + fm_delayus(20); + /* A0.3 release power on reset */ + ret = fm_host_reg_read(0x81020008, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81020008, value | 0x1); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 wr failed\n"); + return ret; + } + /* A0.4 enable fspi_mas_bclk_ck */ + ret = fm_host_reg_read(0x80000108, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x80000108 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x80000108, value | 0x00000100); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x80000108 wr failed\n"); + return ret; + } + return ret; +} + +static signed int mt6632_pwrdown_top_setting(void) +{ + signed int ret = 0, value = 0; + /* B0.1 disable fspi_mas_bclk_ck */ + ret = fm_host_reg_read(0x80000104, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x80000104 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x80000104, value | 0x00000100); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x80000104 wr failed\n"); + return ret; + } + /* B0.2 set power off reset */ + ret = fm_host_reg_read(0x81020008, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81020008, value & 0xFFFFFFFE); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 wr failed\n"); + return ret; + } + /* B0.3 */ + fm_delayus(20); + + /* B0.4 disable MTCMOS & set Iso_en */ + ret = fm_host_reg_read(0x81020008, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81020008, value & 0xFFFFFFEF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020008 wr failed\n"); + return ret; + } +#if 0 + /* B0.5 Turn off FM buffer */ + ret = fm_host_reg_read(0x8102123c, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x8102123c rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x8102123c, value | 0x40); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x8102123c wr failed\n"); + return ret; + } + /* B0.6 Clear xtal no off when FM off */ + ret = fm_host_reg_read(0x81021134, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81021134 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81021134, value & 0xFFFFFF7F); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81021134 wr failed\n"); + return ret; + } + /* B0.7 Clear top off always on when FM off */ + ret = fm_host_reg_read(0x81020010, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020010 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81020010, value | 0x20000); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81020010 wr failed\n"); + return ret; + } + /* B0.9 Disable PALDO when FM off */ + ret = fm_host_reg_read(0x81021430, &value); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81021430 rd failed\n"); + return ret; + } + ret = fm_host_reg_write(0x81021430, value & 0x7FFFFFFF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " 0x81021430 wr failed\n"); + return ret; + } +#endif + return ret; +} + +static signed int mt6632_pwrup_DSP_download(struct fm_patch_tbl *patch_tbl) +{ +#define PATCH_BUF_SIZE (4096*6) + signed int ret = 0; + signed int patch_len = 0; + unsigned char *dsp_buf = NULL; + unsigned short tmp_reg = 0; + + mt6632_hw_info.eco_ver = (signed int) mtk_wcn_wmt_ic_info_get(1); + WCN_DBG(FM_NTC | CHIP, "ECO version:0x%08x\n", mt6632_hw_info.eco_ver); + + /* FM ROM code version request */ + ret = mt6632_get_rom_version(); + if (ret >= 0) { + mt6632_hw_info.rom_ver = ret; + WCN_DBG(FM_NTC | CHIP, "ROM version: v%d\n", mt6632_hw_info.rom_ver); + } else { + WCN_DBG(FM_ERR | CHIP, "get ROM version failed\n"); + /* ret=-4 means signal got when control FM. usually get sig 9 to kill FM process. */ + /* now cancel FM power up sequence is recommended. */ + return ret; + } + + /* Wholechip FM Power Up: step 3, download patch */ + dsp_buf = fm_vmalloc(PATCH_BUF_SIZE); + if (!dsp_buf) { + WCN_DBG(FM_ERR | CHIP, "-ENOMEM\n"); + return -ENOMEM; + } + + patch_len = fm_get_patch_path(mt6632_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_patch_path failed\n"); + ret = patch_len; + goto out; + } + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_PATCH); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " DL DSPpatch failed\n"); + goto out; + } + + patch_len = fm_get_coeff_path(mt6632_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_coeff_path failed\n"); + ret = patch_len; + goto out; + } + + mt6632_hw_info.rom_ver += 1; + + tmp_reg = dsp_buf[38] | (dsp_buf[39] << 8); /* to be confirmed */ + mt6632_hw_info.patch_ver = (signed int) tmp_reg; + WCN_DBG(FM_NTC | CHIP, "Patch version: 0x%08x\n", mt6632_hw_info.patch_ver); + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_COEFFICIENT); + if (ret) { + WCN_DBG(FM_ERR | CHIP, " DL DSPcoeff failed\n"); + goto out; + } + fm_reg_write(0x90, 0x0040); + fm_reg_write(0x90, 0x0000); +out: + if (dsp_buf) { + fm_vfree(dsp_buf); + dsp_buf = NULL; + } + return ret; +} + +static signed int mt6632_pwrup_clock_on_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + unsigned short de_emphasis; + /* unsigned short osc_freq; */ + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + de_emphasis = fm_config.rx_cfg.deemphasis; + de_emphasis &= 0x0001; /* rang 0~1 */ + + /* B1.1 Enable digital OSC */ + pkt_size += fm_bop_write(0x60, 0x0003, &buf[pkt_size], buf_size - pkt_size); /* wr 60 3 */ + pkt_size += fm_bop_udelay(100, &buf[pkt_size], buf_size - pkt_size); /* delay 100us */ + /* B1.3 Release HW clock gating */ + pkt_size += fm_bop_write(0x60, 0x0007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 7 */ + /* B1.4 Set FM long/short antenna:1: short_antenna 0: long antenna(default) */ + /* pkt_size += fm_bop_modify(0x61, 0xFFEF, 0x0000, &buf[pkt_size], buf_size - pkt_size); */ + /* B1.5 Set audio output mode (lineout/I2S) 0:lineout, 1:I2S */ + /* + *if (mt6632_fm_config.aud_cfg.aud_path == FM_AUD_ANALOG) + * pkt_size += fm_bop_modify(0x61, 0xFF7F, 0x0000, &buf[pkt_size], buf_size - pkt_size); + *else + * pkt_size += fm_bop_modify(0x61, 0xFF7F, 0x0080, &buf[pkt_size], buf_size - pkt_size); + */ + /* B1.6 Set deemphasis setting */ + pkt_size += fm_bop_modify(0x61, ~DE_EMPHASIS, (de_emphasis << 12), &buf[pkt_size], buf_size - pkt_size); + + /* pkt_size += fm_bop_modify(0x60, OSC_FREQ_MASK, (osc_freq << 4), &buf[pkt_size], buf_size - pkt_size); */ + + return pkt_size - 4; +} +/* + * mt6632_pwrup_clock_on - Wholechip FM Power Up: step 1, FM Digital Clock enable + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6632_pwrup_clock_on(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6632_pwrup_clock_on_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6632_pwrup_digital_init_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* F1.4 Set appropriate interrupt mask behavior as desired(RX) */ + /* pkt_size += fm_bop_write(0x6A, 0x0021, &buf[pkt_size], buf_size - pkt_size);//wr 6A 0021 */ + pkt_size += fm_bop_write(0x6B, 0x0021, &buf[pkt_size], buf_size - pkt_size); /* wr 6B 0021 */ + /* F1.9 Enable HW auto control */ + pkt_size += fm_bop_write(0x60, 0x000F, &buf[pkt_size], buf_size - pkt_size); /* wr 60 f */ + /* F1.10 Release ASIP reset */ + pkt_size += fm_bop_modify(0x61, 0xFFFD, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D1=1 */ + /* F1.11 Enable ASIP power */ + pkt_size += fm_bop_modify(0x61, 0xFFFE, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D0=0 */ + pkt_size += fm_bop_udelay(100000, &buf[pkt_size], buf_size - pkt_size); /* delay 100ms */ + /* F1.13 Check HW intitial complete */ + pkt_size += fm_bop_rd_until(0x64, 0x001F, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* Poll 64[0~4] = 2 */ + + return pkt_size - 4; +} + +/* + * mt6632_pwrup_digital_init - Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6632_pwrup_digital_init(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6632_pwrup_digital_init_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6632_pwrdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* Disable HW clock control */ + pkt_size += fm_bop_write(0x60, 0x0107, &buf[pkt_size], buf_size - pkt_size); /* wr 60 107 */ + /* Reset ASIP */ + pkt_size += fm_bop_write(0x61, 0x0001, &buf[pkt_size], buf_size - pkt_size); /* wr 61 0001 */ + /* digital core + digital rgf reset */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */ + /* Disable all clock */ + pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 60 0000 */ + /* Reset rgfrf */ + pkt_size += fm_bop_write(0x60, 0x4000, &buf[pkt_size], buf_size - pkt_size); /* wr 60 4000 */ + pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 60 0000 */ + + return pkt_size - 4; +} +/* + * mt6632_pwrdown - Wholechip FM Power down: Digital Modem Power Down + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6632_pwrdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6632_pwrdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6632_tune_reg_op(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 4; + + WCN_DBG(FM_ALT | CHIP, "%s enter mt6632_tune function\n", __func__); + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + freq = (freq - 6400) * 2 / 10; + + /* Set desired channel & channel parameter */ +#ifdef FM_TUNE_USE_POLL + pkt_size += fm_bop_write(0x6A, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x6B, 0x0000, &buf[pkt_size], buf_size - pkt_size); +#endif + pkt_size += fm_bop_modify(FM_CHANNEL_SET, 0xFC00, freq, &buf[pkt_size], buf_size - pkt_size); + /* channel para setting, D15~D12, D15: ATJ, D13: HL, D12: FA */ + pkt_size += fm_bop_modify(FM_CHANNEL_SET, 0x0FFF, (chan_para << 12), &buf[pkt_size], buf_size - pkt_size); + /* Enable hardware controlled tuning sequence */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF8, TUNE, &buf[pkt_size], buf_size - pkt_size); + /* Wait for STC_DONE interrupt */ +#ifdef FM_TUNE_USE_POLL + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size], + buf_size - pkt_size); + /* Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); +#endif + + WCN_DBG(FM_ALT | CHIP, "%s leave mt6632_tune function\n", __func__); + + return pkt_size - 4; +} + +/* + * mt6632_tune - execute tune action, + * @buf - target buf + * @buf_size - buffer size + * @freq - 760 ~ 1080, 100KHz unit + * return package size + */ +static signed int mt6632_tune(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 0; + + pkt_size = mt6632_tune_reg_op(buf, buf_size, freq, chan_para); + return fm_op_seq_combine_cmd(buf, FM_TUNE_OPCODE, pkt_size); +} + +static signed int mt6632_PowerUp(unsigned short *chip_id, unsigned short *device_id) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short tmp_reg = 0; + + if (chip_id == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (device_id == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + WCN_DBG(FM_DBG | CHIP, "pwr on seq......\n"); + + ret = mt6632_pmic_ctrl(); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6632_pmic_ctrl failed\n"); + return ret; + } + fm_delayus(240); + + ret = mt6632_pwrup_top_setting(); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6632_pwrup_top_setting failed\n"); + return ret; + } + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6632_pwrup_clock_on(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6632_pwrup_clock_on failed\n"); + return ret; + } + /* read HW version */ + fm_reg_read(0x62, &tmp_reg); + *chip_id = tmp_reg; + *device_id = tmp_reg; + mt6632_hw_info.chip_id = (signed int) tmp_reg; + WCN_DBG(FM_NTC | CHIP, "chip_id:0x%04x\n", tmp_reg); + + if (mt6632_hw_info.chip_id != 0x6632) { + WCN_DBG(FM_NTC | CHIP, "fm sys error!\n"); + return -FM_EPARA; + } + ret = mt6632_pwrup_DSP_download(mt6632_patch_tbl); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6632_pwrup_DSP_download failed\n"); + return ret; + } + + if ((fm_config.aud_cfg.aud_path == FM_AUD_MRGIF) + || (fm_config.aud_cfg.aud_path == FM_AUD_I2S)) { + mt6632_I2s_Setting(FM_I2S_ON, fm_config.aud_cfg.i2s_info.mode, + fm_config.aud_cfg.i2s_info.rate); + /* mt_combo_audio_ctrl(COMBO_AUDIO_STATE_2); */ + mtk_wcn_cmb_stub_audio_ctrl((CMB_STUB_AIF_X) CMB_STUB_AIF_2); + } + /* Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6632_pwrup_digital_init(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6632_pwrup_digital_init failed\n"); + return ret; + } + + /* FM RF fine tune setting */ + fm_reg_write(0x60, 0x7); + fm_reg_write(0x2d, 0x1fa); + fm_reg_write(0x60, 0xF); + + WCN_DBG(FM_NTC | CHIP, "pwr on seq ok\n"); + + return ret; +} + +static signed int mt6632_PowerDown(void) +{ + signed int ret = 0; + unsigned short pkt_size; + + WCN_DBG(FM_DBG | CHIP, "pwr down seq\n"); + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6632_pwrdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6632_pwrdown failed\n"); + return ret; + } + + ret = mt6632_pwrdown_top_setting(); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6632_pwrdown_top_setting failed\n"); + return ret; + } + + return ret; +} + +/* just for dgb */ +static bool mt6632_SetFreq(unsigned short freq) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short chan_para = 0; + unsigned short tmp_reg[4]; + + fm_cb_op->cur_freq_set(freq); + +#if 0 + /* MCU clock adjust if need */ + ret = mt6632_mcu_dese(freq, NULL); + if (ret < 0) + WCN_DBG(FM_ERR | MAIN, "mt6632_mcu_dese FAIL:%d\n", ret); + + WCN_DBG(FM_INF | MAIN, "MCU %d\n", ret); +#endif + + /* GPS clock adjust if need */ + ret = mt6632_gps_dese(freq, NULL); + if (ret < 0) + WCN_DBG(FM_ERR | MAIN, "mt6632_gps_dese FAIL:%d\n", ret); + + WCN_DBG(FM_INF | MAIN, "GPS %d\n", ret); + + ret = fm_reg_write(0x60, 0x0007); + if (ret) + WCN_DBG(FM_ALT | MAIN, "set freq write 0x60 fail\n"); + + if (mt6632_TDD_chan_check(freq)) { + ret = fm_set_bits(0x30, 0x0004, 0xFFF9); /* use TDD solution */ + if (ret) + WCN_DBG(FM_ALT | MAIN, "set freq write 0x30 fail\n"); + } else { + ret = fm_set_bits(0x30, 0x0000, 0xFFF9); /* default use FDD solution */ + if (ret) + WCN_DBG(FM_ALT | MAIN, "set freq write 0x30 fail\n"); + } + ret = fm_reg_write(0x60, 0x000F); + if (ret) + WCN_DBG(FM_ALT | MAIN, "set freq write 0x60 fail\n"); + + chan_para = mt6632_chan_para_get(freq); + WCN_DBG(FM_DBG | CHIP, "%d chan para = %d\n", (signed int) freq, (signed int) chan_para); + + if (FM_LOCK(cmd_buf_lock)) + return false; + pkt_size = mt6632_tune(cmd_buf, TX_BUF_SIZE, freq, chan_para); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE | FLAG_TUNE_DONE, SW_RETRY_CNT, TUNE_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + fm_reg_read(0x64, &tmp_reg[0]); + fm_reg_read(0x69, &tmp_reg[1]); + fm_reg_read(0x6c, &tmp_reg[2]); + WCN_DBG(FM_ERR | CHIP, "mt6632_tune failed\n"); + WCN_DBG(FM_ERR | CHIP, "0x64[0x%04x],0x69[0x%04x],0x6c[0x%04x]\n", tmp_reg[0], tmp_reg[1], tmp_reg[2]); + return false; + } + + WCN_DBG(FM_DBG | CHIP, "set freq to %d ok\n", freq); + return true; +} + +#define FM_CQI_LOG_PATH "/mnt/sdcard/fmcqilog" + +static signed int mt6632_full_cqi_get(signed int min_freq, signed int max_freq, signed int space, signed int cnt) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short freq, orig_freq; + signed int i, j, k; + signed int space_val, max, min, num; + struct mt6632_full_cqi *p_cqi; + unsigned char *cqi_log_title = "Freq, RSSI, PAMD, PR, FPAMD, MR, ATDC, PRX, ATDEV, SMGain, DltaRSSI\n"; + unsigned char cqi_log_buf[100] = { 0 }; + signed int pos; + unsigned char cqi_log_path[100] = { 0 }; + + WCN_DBG(FM_DBG | CHIP, "6632 cqi log start\n"); + /* for soft-mute tune, and get cqi */ + freq = fm_cb_op->cur_freq_get(); + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + /* get cqi */ + orig_freq = freq; + if (fm_get_channel_space(min_freq) == 0) + min = min_freq * 10; + else + min = min_freq; + + if (fm_get_channel_space(max_freq) == 0) + max = max_freq * 10; + else + max = max_freq; + + if (space == 0x0001) + space_val = 5; /* 50Khz */ + else if (space == 0x0002) + space_val = 10; /* 100Khz */ + else if (space == 0x0004) + space_val = 20; /* 200Khz */ + else + space_val = 10; + + num = (max - min) / space_val + 1; /* Eg, (8760 - 8750) / 10 + 1 = 2 */ + for (k = 0; (orig_freq == 10000) && (g_dbg_level == 0xffffffff) && (k < cnt); k++) { + WCN_DBG(FM_NTC | CHIP, "cqi file:%d\n", k + 1); + freq = min; + pos = 0; + fm_memcpy(cqi_log_path, FM_CQI_LOG_PATH, strlen(FM_CQI_LOG_PATH)); + sprintf(&cqi_log_path[strlen(FM_CQI_LOG_PATH)], "%d.txt", k + 1); + fm_file_write(cqi_log_path, cqi_log_title, strlen(cqi_log_title), &pos); + for (j = 0; j < num; j++) { + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = + fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, + SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + WCN_DBG(FM_NTC | CHIP, "smt cqi size %d\n", fm_res->cqi[0]); + p_cqi = (struct mt6632_full_cqi *)&fm_res->cqi[2]; + for (i = 0; i < fm_res->cqi[1]; i++) { + /* just for debug */ + WCN_DBG(FM_NTC | CHIP, + "freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* format to buffer */ + sprintf(cqi_log_buf, + "%04d,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* write back to log file */ + fm_file_write(cqi_log_path, cqi_log_buf, strlen(cqi_log_buf), &pos); + } + } else { + WCN_DBG(FM_ERR | CHIP, "smt get CQI failed\n"); + ret = -1; + } + freq += space_val; + } + fm_cb_op->cur_freq_set(0); /* avoid run too much times */ + } + WCN_DBG(FM_DBG | CHIP, "6632 cqi log done\n"); + + return ret; +} + +/* + * mt6632_GetCurRSSI - get current freq's RSSI value + * RS=RSSI + * If RS>511, then RSSI(dBm)= (RS-1024)/16*6 + * else RSSI(dBm)= RS/16*6 + */ +static signed int mt6632_GetCurRSSI(signed int *pRSSI) +{ + unsigned short tmp_reg = 0; + + /* TODO: check reg */ + fm_reg_read(FM_RSSI_IND, &tmp_reg); + tmp_reg = tmp_reg & 0x03ff; + + if (pRSSI) { + *pRSSI = (tmp_reg > 511) ? (((tmp_reg - 1024) * 6) >> 4) : ((tmp_reg * 6) >> 4); + WCN_DBG(FM_DBG | CHIP, "rssi:%d, dBm:%d\n", tmp_reg, *pRSSI); + } else { + WCN_DBG(FM_ERR | CHIP, "get rssi para error\n"); + return -FM_EPARA; + } + + return 0; +} + +static unsigned short mt6632_vol_tbl[16] = { + 0x0000, 0x0519, 0x066A, 0x0814, + 0x0A2B, 0x0CCD, 0x101D, 0x1449, + 0x198A, 0x2027, 0x287A, 0x32F5, + 0x4027, 0x50C3, 0x65AD, 0x7FFF +}; + +static signed int mt6632_SetVol(unsigned char vol) +{ + signed int ret = 0; + + /* TODO: check reg */ + vol = (vol > 15) ? 15 : vol; + ret = fm_reg_write(0x7D, mt6632_vol_tbl[vol]); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "Set vol=%d Failed\n", vol); + return ret; + } + + WCN_DBG(FM_DBG | CHIP, "Set vol=%d OK\n", vol); + + if (vol == 10) { + fm_print_cmd_fifo(); /* just for debug */ + fm_print_evt_fifo(); + } + return 0; +} + +static signed int mt6632_GetVol(unsigned char *pVol) +{ + int ret = 0; + unsigned short tmp = 0; + signed int i; + + if (pVol == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + /* TODO: check reg */ + ret = fm_reg_read(0x7D, &tmp); + if (ret) { + *pVol = 0; + WCN_DBG(FM_ERR | CHIP, "Get vol Failed\n"); + return ret; + } + + for (i = 0; i < 16; i++) { + if (mt6632_vol_tbl[i] == tmp) { + *pVol = i; + break; + } + } + + WCN_DBG(FM_DBG | CHIP, "Get vol=%d OK\n", *pVol); + return 0; +} + +static signed int mt6632_dump_reg(void) +{ + signed int i; + unsigned short TmpReg = 0; + + for (i = 0; i < 0xff; i++) { + fm_reg_read(i, &TmpReg); + WCN_DBG(FM_NTC | CHIP, "0x%02x=0x%04x\n", i, TmpReg); + } + return 0; +} + +static bool mt6632_GetMonoStereo(unsigned short *pMonoStereo) +{ +#define FM_BF_STEREO 0x1000 + unsigned short TmpReg = 0; + + /* TODO: check reg */ + if (pMonoStereo) { + fm_reg_read(FM_RSSI_IND, &TmpReg); + *pMonoStereo = (TmpReg & FM_BF_STEREO) >> 12; + } else { + WCN_DBG(FM_ERR | CHIP, "MonoStero: para err\n"); + return false; + } + + WCN_DBG(FM_DBG | CHIP, "MonoStero:0x%04x\n", *pMonoStereo); + return true; +} + +static signed int mt6632_SetMonoStereo(signed int MonoStereo) +{ + signed int ret = 0; +#define FM_FORCE_MS 0x0008 + + WCN_DBG(FM_DBG | CHIP, "set to %s\n", MonoStereo ? "mono" : "auto"); + /* TODO: check reg */ + + fm_reg_write(0x60, 0x3007); + + if (MonoStereo) + ret = fm_set_bits(0x75, FM_FORCE_MS, ~FM_FORCE_MS); + else + ret = fm_set_bits(0x75, 0x0000, ~FM_FORCE_MS); + + return ret; +} + +static signed int mt6632_GetCapArray(signed int *ca) +{ + unsigned short dataRead = 0; + unsigned short tmp = 0; + + /* TODO: check reg */ + if (ca == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_reg_read(0x60, &tmp); + fm_reg_write(0x60, tmp & 0xFFF7); /* 0x60 D3=0 */ + + fm_reg_read(0x26, &dataRead); + *ca = dataRead; + + fm_reg_write(0x60, tmp); /* 0x60 D3=1 */ + return 0; +} + +/* + * mt6632_GetCurPamd - get current freq's PAMD value + * PA=PAMD + * If PA>511 then PAMD(dB)= (PA-1024)/16*6, + * else PAMD(dB)=PA/16*6 + */ +static bool mt6632_GetCurPamd(unsigned short *pPamdLevl) +{ + unsigned short tmp_reg = 0; + unsigned short dBvalue, valid_cnt = 0; + int i, total = 0; + + for (i = 0; i < 8; i++) { + /* TODO: check reg */ + if (fm_reg_read(FM_ADDR_PAMD, &tmp_reg)) { + *pPamdLevl = 0; + return false; + } + + tmp_reg &= 0x03FF; + dBvalue = (tmp_reg > 256) ? ((512 - tmp_reg) * 6 / 16) : 0; + if (dBvalue != 0) { + total += dBvalue; + valid_cnt++; + WCN_DBG(FM_DBG | CHIP, "[%d]PAMD=%d\n", i, dBvalue); + } + fm_delayms(3); + } + if (valid_cnt != 0) + *pPamdLevl = total / valid_cnt; + else + *pPamdLevl = 0; + + WCN_DBG(FM_NTC | CHIP, "PAMD=%d\n", *pPamdLevl); + return true; +} + +static signed int MT6632_FMOverBT(bool enable) +{ + signed int ret = 0; + + WCN_DBG(FM_NTC | CHIP, "+%s():\n", __func__); + + if (enable == true) { + /* change I2S to slave mode and 48K sample rate */ + if (mt6632_I2s_Setting(FM_I2S_ON, FM_I2S_SLAVE, FM_I2S_48K)) + goto out; + WCN_DBG(FM_NTC | CHIP, "set FM via BT controller\n"); + } else if (enable == false) { + /* change I2S to master mode and 44.1K sample rate */ + if (mt6632_I2s_Setting(FM_I2S_ON, FM_I2S_MASTER, FM_I2S_44K)) + goto out; + WCN_DBG(FM_NTC | CHIP, "set FM via Host\n"); + } else { + WCN_DBG(FM_ERR | CHIP, "%s()\n", __func__); + ret = -FM_EPARA; + goto out; + } +out: + WCN_DBG(FM_NTC | CHIP, "-%s():[ret=%d]\n", __func__, ret); + return ret; +} + +/* + * mt6632_I2s_Setting - set the I2S state on MT6632 + * @onoff - I2S on/off + * @mode - I2S mode: Master or Slave + * + * Return:0, if success; error code, if failed + */ +static signed int mt6632_I2s_Setting(signed int onoff, signed int mode, signed int sample) +{ + unsigned short tmp_state = 0; + unsigned short tmp_mode = 0; + unsigned short tmp_sample = 0; + signed int ret = 0; + + if (onoff == FM_I2S_ON) { + tmp_state = 0x0002; /* I2S enable and standard I2S mode, 0x9B D0,D1=1 */ + fm_config.aud_cfg.i2s_info.status = FM_I2S_ON; + } else if (onoff == FM_I2S_OFF) { + tmp_state = 0x0000; /* I2S off, 0x9B D0,D1=0 */ + fm_config.aud_cfg.i2s_info.status = FM_I2S_OFF; + } else { + WCN_DBG(FM_ERR | CHIP, "%s():[onoff=%d]\n", __func__, onoff); + ret = -FM_EPARA; + goto out; + } + + if (mode == FM_I2S_MASTER) { + tmp_mode = 0x0000; /* 6632 as I2S master, set 0x9B D3=0 */ + fm_config.aud_cfg.i2s_info.mode = FM_I2S_MASTER; + } else if (mode == FM_I2S_SLAVE) { + tmp_mode = 0x0008; /* 6632 as I2S slave, set 0x9B D3=1 */ + fm_config.aud_cfg.i2s_info.mode = FM_I2S_SLAVE; + } else { + WCN_DBG(FM_ERR | CHIP, "%s():[mode=%d]\n", __func__, mode); + ret = -FM_EPARA; + goto out; + } + + if (sample == FM_I2S_32K) { + tmp_sample = 0x0000; /* 6632 I2S 32KHz sample rate, 0x5F D11~12 */ + fm_config.aud_cfg.i2s_info.rate = FM_I2S_32K; + } else if (sample == FM_I2S_44K) { + tmp_sample = 0x0800; /* 6632 I2S 44.1KHz sample rate */ + fm_config.aud_cfg.i2s_info.rate = FM_I2S_44K; + } else if (sample == FM_I2S_48K) { + tmp_sample = 0x1000; /* 6632 I2S 48KHz sample rate */ + fm_config.aud_cfg.i2s_info.rate = FM_I2S_48K; + } else { + WCN_DBG(FM_ERR | CHIP, "%s():[sample=%d]\n", __func__, sample); + ret = -FM_EPARA; + goto out; + } + + ret = fm_reg_write(0x60, 0x0007); + if (ret) + goto out; + + ret = fm_set_bits(0x5F, tmp_sample, 0xE7FF); + if (ret) + goto out; + + ret = fm_set_bits(0x9B, tmp_mode, 0xFFF7); + if (ret) + goto out; + + ret = fm_set_bits(0x9B, tmp_state, 0xFFFD); + if (ret) + goto out; + + ret = fm_reg_write(0x60, 0x000F); + if (ret) + goto out; + WCN_DBG(FM_NTC | CHIP, "[onoff=%s][mode=%s][sample=%d](0)33KHz,(1)44.1KHz,(2)48KHz\n", + (onoff == FM_I2S_ON) ? "On" : "Off", (mode == FM_I2S_MASTER) ? "Master" : "Slave", sample); +out: + return ret; +} + +static signed int mt6632fm_get_audio_info(struct fm_audio_info_t *data) +{ + fm_memcpy(data, &fm_config.aud_cfg, sizeof(struct fm_audio_info_t)); + return 0; +} + +static signed int mt6632_i2s_info_get(signed int *ponoff, signed int *pmode, signed int *psample) +{ + *ponoff = fm_config.aud_cfg.i2s_info.status; + *pmode = fm_config.aud_cfg.i2s_info.mode; + *psample = fm_config.aud_cfg.i2s_info.rate; + + return 0; +} + +static signed int mt6632_hw_info_get(struct fm_hw_info *req) +{ + if (req == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + req->chip_id = mt6632_hw_info.chip_id; + req->eco_ver = mt6632_hw_info.eco_ver; + req->patch_ver = mt6632_hw_info.patch_ver; + req->rom_ver = mt6632_hw_info.rom_ver; + + return 0; +} + +static signed int mt6632_pre_search(void) +{ + mt6632_RampDown(); + return 0; +} + +static signed int mt6632_restore_search(void) +{ + mt6632_RampDown(); + return 0; +} + +/* +*freq: 8750~10800 +*valid: true-valid channel,false-invalid channel +*return: true- smt success, false-smt fail +*/ +static signed int mt6632_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid) +{ + signed int ret = 0; + unsigned short pkt_size; + /* unsigned short freq;//, orig_freq; */ + struct mt6632_full_cqi *p_cqi; + signed int RSSI = 0, PAMD = 0, MR = 0, ATDC = 0; + unsigned int PRX = 0, ATDEV = 0; + unsigned short softmuteGainLvl = 0; + + ret = mt6632_chan_para_get(freq); + if (ret == 2) + ret = fm_set_bits(FM_CHANNEL_SET, 0x2000, 0x0FFF); /* mdf HiLo */ + else + ret = fm_set_bits(FM_CHANNEL_SET, 0x0000, 0x0FFF); /* clear FA/HL/ATJ */ +#if 0 + fm_reg_write(0x60, 0x0007); + if (mt6632_TDD_chan_check(freq)) + fm_set_bits(0x30, 0x0004, 0xFFF9); /* use TDD solution */ + else + fm_set_bits(0x30, 0x0000, 0xFFF9); /* default use FDD solution */ + fm_reg_write(0x60, 0x000F); +#endif + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + WCN_DBG(FM_DBG | CHIP, "smt cqi size %d\n", fm_res->cqi[0]); + p_cqi = (struct mt6632_full_cqi *)&fm_res->cqi[2]; + + + RSSI = ((p_cqi->rssi & 0x03FF) >= 512) ? ((p_cqi->rssi & 0x03FF) - 1024) : (p_cqi->rssi & 0x03FF); + PAMD = ((p_cqi->pamd & 0x1FF) >= 256) ? ((p_cqi->pamd & 0x01FF) - 512) : (p_cqi->pamd & 0x01FF); + MR = ((p_cqi->mr & 0x01FF) >= 256) ? ((p_cqi->mr & 0x01FF) - 512) : (p_cqi->mr & 0x01FF); + ATDC = (p_cqi->atdc >= 32768) ? (65536 - p_cqi->atdc) : (p_cqi->atdc); + if (ATDC < 0) + ATDC = (~(ATDC)) - 1; /* Get abs value of ATDC */ + + PRX = (p_cqi->prx & 0x00FF); + ATDEV = p_cqi->atdev; + softmuteGainLvl = p_cqi->smg; + /* check if the channel is valid according to each CQIs */ + if ((fm_config.rx_cfg.long_ana_rssi_th <= RSSI) + && (fm_config.rx_cfg.pamd_th >= PAMD) + && (fm_config.rx_cfg.atdc_th >= ATDC) + && (fm_config.rx_cfg.mr_th <= MR) + && (fm_config.rx_cfg.prx_th <= PRX) + && (ATDEV >= ATDC) /* sync scan algorithm */ + && (fm_config.rx_cfg.smg_th <= softmuteGainLvl)) { + *valid = true; + } else { + *valid = false; + } + WCN_DBG(FM_NTC | CHIP, + "valid=%d, freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", + *valid, p_cqi->ch, p_cqi->rssi, p_cqi->pamd, p_cqi->pr, p_cqi->fpamd, p_cqi->mr, + p_cqi->atdc, p_cqi->prx, p_cqi->atdev, p_cqi->smg, p_cqi->drssi); + *rssi = RSSI; + } else { + WCN_DBG(FM_ERR | CHIP, "smt get CQI failed\n"); + return false; + } + return true; +} + +/* +*parm: +* parm.th_type: 0, RSSI. 1,desense RSSI. 2,SMG. +* parm.th_val: threshold value +*/ +static signed int mt6632_set_search_th(signed int idx, signed int val, signed int reserve) +{ + switch (idx) { + case 0: { + fm_config.rx_cfg.long_ana_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set rssi th =%d\n", val); + break; + } + case 1: { + fm_config.rx_cfg.desene_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set desense rssi th =%d\n", val); + break; + } + case 2: { + fm_config.rx_cfg.smg_th = val; + WCN_DBG(FM_NTC | CHIP, "set smg th =%d\n", val); + break; + } + default: + break; + } + return 0; +} + +#if 0 +static const unsigned short mt6632_mcu_dese_list[] = { + 0 /* 7630, 7800, 7940, 8320, 9260, 9600, 9710, 9920, 10400, 10410 */ +}; + +static const unsigned short mt6632_gps_dese_list[] = { + 0 /* 7850, 7860 */ +}; +#endif + +static const signed char mt6632_chan_para_map[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6500~6595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6600~6695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6700~6795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6800~6895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6900~6995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7000~7095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7100~7195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7200~7295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7300~7395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7400~7495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7500~7595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7600~7695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7700~7795 */ + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7800~7895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7900~7995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8000~8095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8100~8195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8200~8295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8300~8395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8400~8495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8500~8595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8600~8695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8700~8795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8800~8895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8900~8995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9000~9095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9100~9195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9200~9295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9300~9395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9400~9495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9500~9595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9600~9695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9700~9795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9800~9895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9900~9995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10000~10095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10100~10195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10200~10295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10300~10395 */ + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10400~10495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10500~10595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10600~10695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10700~10795 */ + 0 /* 10800 */ +}; + +static const unsigned short mt6632_TDD_list[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6500~6595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6600~6695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6700~6795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6800~6895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6900~6995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7000~7095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7100~7195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7200~7295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7300~7395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7400~7495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7500~7595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7600~7695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7700~7795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7800~7895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7900~7995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8000~8095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8100~8195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8200~8295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8300~8395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8400~8495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8500~8595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8600~8695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8700~8795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8800~8895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8900~8995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9000~9095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9100~9195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9200~9295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9300~9395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9400~9495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9500~9595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9600~9695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9700~9795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9800~9895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9900~9995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10000~10095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10100~10195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10200~10295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10300~10395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10400~10495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10500~10595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10600~10695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10700~10795 */ + 0x0000 /* 10800 */ +}; + +static const unsigned short mt6632_TDD_Mask[] = { + 0x0001, 0x0010, 0x0100, 0x1000 +}; + +static const unsigned short mt6632_scan_dese_list[] = { + 7800, 9210, 9220, 9600, 9980, 10400, 10750, 10760 +}; + + +/* return value: 0, not a de-sense channel; 1, this is a de-sense channel; else error no */ +static signed int mt6632_is_dese_chan(unsigned short freq) +{ + signed int size; + + /* return 0;//HQA only :skip desense channel check. */ + size = ARRAY_SIZE(mt6632_scan_dese_list); + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + while (size) { + if (mt6632_scan_dese_list[size - 1] == freq) + return 1; + + size--; + } + + return 0; +} + +static bool mt6632_TDD_chan_check(unsigned short freq) +{ + unsigned int i = 0; + unsigned short freq_tmp = freq; + signed int ret = 0; + + ret = fm_get_channel_space(freq_tmp); + if (ret == 0) + freq_tmp *= 10; + else if (ret == -1) + return false; + + i = (freq_tmp - 6500) / 5; + if ((i / 4) >= ARRAY_SIZE(mt6632_TDD_list)) { + WCN_DBG(FM_ERR | CHIP, "Freq index out of range(%d),max(%zd)\n", + i / 4, ARRAY_SIZE(mt6632_TDD_list)); + return false; + } + + if (mt6632_TDD_list[i / 4] & mt6632_TDD_Mask[i % 4]) { + WCN_DBG(FM_DBG | CHIP, "Freq %d use TDD solution\n", freq); + return true; + } else + return false; +} + +/* return value: +*1, is desense channel and rssi is less than threshold; +*0, not desense channel or it is but rssi is more than threshold. +*/ +static signed int mt6632_desense_check(unsigned short freq, signed int rssi) +{ + if (mt6632_is_dese_chan(freq)) { + if (rssi < fm_config.rx_cfg.desene_rssi_th) + return 1; + + WCN_DBG(FM_DBG | CHIP, "desen_rssi %d th:%d\n", rssi, fm_config.rx_cfg.desene_rssi_th); + } + return 0; +} + +/* get channel parameter, HL side/ FA / ATJ */ +static unsigned short mt6632_chan_para_get(unsigned short freq) +{ + signed int pos, size; + + /* return 0;//for HQA only: skip FA/HL/ATJ */ + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + if (freq < 6500) + return 0; + + pos = (freq - 6500) / 5; + size = ARRAY_SIZE(mt6632_chan_para_map); + + pos = (pos > (size - 1)) ? (size - 1) : pos; + + return mt6632_chan_para_map[pos]; +} + +static signed int mt6632_gps_dese(unsigned short freq, void *arg) +{ + /*enum fm_gps_desense_t state = FM_GPS_DESE_DISABLE;*/ + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + WCN_DBG(FM_NTC | CHIP, "%s, [freq=%d]\n", __func__, (int)freq); + + /* request 6632 GPS change clk */ + if ((freq >= 7690) && (freq <= 8230)) { + WCN_DBG(FM_NTC | CHIP, "gps desense disable\n"); + if (!mtk_wcn_wmt_dsns_ctrl(WMTDSNS_FM_GPS_DISABLE)) + return -1; + } + + if ((freq >= 8460) && (freq <= 9120)) { + WCN_DBG(FM_NTC | CHIP, "gps desense enable\n"); + if (!mtk_wcn_wmt_dsns_ctrl(WMTDSNS_FM_GPS_ENABLE)) + return -1; + } + + return 1; +} + + +signed int fm_low_ops_register(struct fm_callback *cb, struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,bi invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_get == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_get invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_set == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_set invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_cb_op = cb; + + bi->pwron = mt6632_pwron; + bi->pwroff = mt6632_pwroff; + bi->pmic_read = mt6632_pmic_read; + bi->pmic_write = mt6632_pmic_write; + bi->chipid_get = mt6632_get_chipid; + bi->mute = mt6632_Mute; + bi->rampdown = mt6632_RampDown; + bi->pwrupseq = mt6632_PowerUp; + bi->pwrdownseq = mt6632_PowerDown; + bi->setfreq = mt6632_SetFreq; + /* bi->low_pwr_wa = MT6632fm_low_power_wa_default; */ + bi->i2s_set = mt6632_I2s_Setting; + bi->rssiget = mt6632_GetCurRSSI; + bi->volset = mt6632_SetVol; + bi->volget = mt6632_GetVol; + bi->dumpreg = mt6632_dump_reg; + bi->msget = mt6632_GetMonoStereo; + bi->msset = mt6632_SetMonoStereo; + bi->pamdget = mt6632_GetCurPamd; + /* bi->em = mt6632_em_test; */ + bi->anaswitch = mt6632_SetAntennaType; + bi->anaget = mt6632_GetAntennaType; + bi->caparray_get = mt6632_GetCapArray; + bi->hwinfo_get = mt6632_hw_info_get; + bi->fm_via_bt = MT6632_FMOverBT; + bi->i2s_get = mt6632_i2s_info_get; + bi->is_dese_chan = mt6632_is_dese_chan; + bi->softmute_tune = mt6632_soft_mute_tune; + bi->desense_check = mt6632_desense_check; + bi->cqi_log = mt6632_full_cqi_get; + bi->pre_search = mt6632_pre_search; + bi->restore_search = mt6632_restore_search; + bi->set_search_th = mt6632_set_search_th; + bi->get_aud_info = mt6632fm_get_audio_info; + + cmd_buf_lock = fm_lock_create("32_cmd"); + ret = fm_lock_get(cmd_buf_lock); + + cmd_buf = fm_zalloc(TX_BUF_SIZE + 1); + + if (!cmd_buf) { + WCN_DBG(FM_ERR | CHIP, "6632 fm lib alloc tx buf failed\n"); + ret = -1; + } + + return ret; +} + +signed int fm_low_ops_unregister(struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,bi invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (cmd_buf) { + fm_free(cmd_buf); + cmd_buf = NULL; + } + + ret = fm_lock_put(cmd_buf_lock); + fm_memset(bi, 0, sizeof(struct fm_basic_interface)); + + fm_cb_op = NULL; + + return ret; +} + diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6632/pub/mt6632_fm_rds.c b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6632/pub/mt6632_fm_rds.c new file mode 100644 index 00000000000000..f0160a48d0bf7e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6632/pub/mt6632_fm_rds.c @@ -0,0 +1,329 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_rds.h" +#include "mt6632_fm_reg.h" +#include "fm_cmd.h" + +static bool bRDS_FirstIn; /* false */ +static unsigned int gBLER_CHK_INTERVAL = 500; +static unsigned short GOOD_BLK_CNT = 0, BAD_BLK_CNT; +static unsigned char BAD_BLK_RATIO; + +static struct fm_basic_interface *fm_bi; + +static bool mt6632_RDS_support(void); +static signed int mt6632_RDS_enable(void); +static signed int mt6632_RDS_disable(void); +static unsigned short mt6632_RDS_Get_GoodBlock_Counter(void); +static unsigned short mt6632_RDS_Get_BadBlock_Counter(void); +static unsigned char mt6632_RDS_Get_BadBlock_Ratio(void); +static unsigned int mt6632_RDS_Get_BlerCheck_Interval(void); +/* static void mt6632_RDS_GetData(unsigned short *data, unsigned short datalen); */ +static void mt6632_RDS_Init_Data(struct rds_t *pstRDSData); + +static bool mt6632_RDS_support(void) +{ + return true; +} + +static signed int mt6632_RDS_enable(void) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | RDSC, "rds enable\n"); + /* ret = fm_reg_read(FM_RDS_CFG0, &dataRead); */ + ret = fm_reg_write(FM_RDS_CFG0, 6); /* set buf_start_th */ + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable write 0x80 fail\n"); + return ret; + } + ret = fm_reg_read(FM_MAIN_CTRL, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable read 0x63 fail\n"); + return ret; + } + ret = fm_reg_write(FM_MAIN_CTRL, dataRead | (RDS_MASK)); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable write 0x63 fail\n"); + return ret; + } + + return ret; +} + +static signed int mt6632_RDS_disable(void) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | RDSC, "rds disable\n"); + ret = fm_reg_read(FM_MAIN_CTRL, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds disable read 0x63 fail\n"); + return ret; + } + ret = fm_reg_write(FM_MAIN_CTRL, dataRead & (~RDS_MASK)); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds disable write 0x63 fail\n"); + return ret; + } + + return ret; +} + +static unsigned short mt6632_RDS_Get_GoodBlock_Counter(void) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RDS_GOODBK_CNT, &tmp_reg); + GOOD_BLK_CNT = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get good block cnt:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static unsigned short mt6632_RDS_Get_BadBlock_Counter(void) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RDS_BADBK_CNT, &tmp_reg); + BAD_BLK_CNT = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get bad block cnt:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static unsigned char mt6632_RDS_Get_BadBlock_Ratio(void) +{ + unsigned short tmp_reg; + unsigned short gbc; + unsigned short bbc; + + gbc = mt6632_RDS_Get_GoodBlock_Counter(); + bbc = mt6632_RDS_Get_BadBlock_Counter(); + + if ((gbc + bbc) > 0) + tmp_reg = (unsigned char) (bbc * 100 / (gbc + bbc)); + else + tmp_reg = 0; + + BAD_BLK_RATIO = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get badblock ratio:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static signed int mt6632_RDS_BlockCounter_Reset(void) +{ + mt6632_RDS_disable(); + mt6632_RDS_enable(); + + return 0; +} + +static unsigned int mt6632_RDS_Get_BlerCheck_Interval(void) +{ + return gBLER_CHK_INTERVAL; +} + +static signed int mt6632_RDS_BlerCheck(struct rds_t *dst) +{ + return 0; +} + +#if 0 +static void RDS_Recovery_Handler(void) +{ + unsigned short tempData = 0; + + do { + fm_reg_read(FM_RDS_DATA_REG, &tempData); + fm_reg_read(FM_RDS_POINTER, &tempData); + } while (tempData & 0x3); +} +#endif + +#if 0 +static void mt6632_RDS_GetData(unsigned short *data, unsigned short datalen) +{ +#define RDS_GROUP_DIFF_OFS 0x007C +#define RDS_FIFO_DIFF 0x007F +#define RDS_CRC_BLK_ADJ 0x0020 +#define RDS_CRC_CORR_CNT 0x001E +#define RDS_CRC_INFO 0x0001 + + unsigned short CRC = 0, i = 0, RDS_adj = 0, RDSDataCount = 0, FM_WARorrCnt = 0; + unsigned short temp = 0, OutputPofm_s32 = 0; + + WCN_DBG(FM_DBG | RDSC, "get data\n"); + fm_reg_read(FM_RDS_FIFO_STATUS0, &temp); + RDSDataCount = ((RDS_GROUP_DIFF_OFS & temp) << 2); + + if ((temp & RDS_FIFO_DIFF) >= 4) { + /* block A data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 10; + CRC |= (temp & RDS_CRC_INFO) << 3; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 11); + fm_reg_read(FM_RDS_DATA_REG, &data[0]); + + /* block B data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 9; + CRC |= (temp & RDS_CRC_INFO) << 2; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 7); + fm_reg_read(FM_RDS_DATA_REG, &data[1]); + + /* block C data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 8; + CRC |= (temp & RDS_CRC_INFO) << 1; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 3); + fm_reg_read(FM_RDS_DATA_REG, &data[2]); + + /* block D data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 7; + CRC |= (temp & RDS_CRC_INFO); + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) >> 1); + fm_reg_read(FM_RDS_DATA_REG, &data[3]); + + data[4] = (CRC | RDS_adj | RDSDataCount); + data[5] = FM_WARorrCnt; + + fm_reg_read(FM_RDS_PWDI, &data[6]); + fm_reg_read(FM_RDS_PWDQ, &data[7]); + + fm_reg_read(FM_RDS_POINTER, &OutputPofm_s32); + + /* Go fm_s32o RDS recovery handler while RDS output pofm_s32 doesn't align to 4 in numeric */ + if (OutputPofm_s32 & 0x3) + RDS_Recovery_Handler(); + + } else { + for (; i < 8; i++) + data[i] = 0; + } +} +#endif + +static void mt6632_RDS_Init_Data(struct rds_t *pstRDSData) +{ + fm_memset(pstRDSData, 0, sizeof(struct rds_t)); + bRDS_FirstIn = true; + + fm_memset(pstRDSData->RT_Data.TextData, 0x20, sizeof(pstRDSData->RT_Data.TextData)); + fm_memset(pstRDSData->PS_Data.PS, '\0', sizeof(pstRDSData->PS_Data.PS)); + fm_memset(pstRDSData->PS_ON, 0x20, sizeof(pstRDSData->PS_ON)); +} + +bool mt6632_RDS_OnOff(struct rds_t *dst, bool bFlag) +{ + signed int ret = 0; + + if (mt6632_RDS_support() == false) { + WCN_DBG(FM_ALT | RDSC, "mt6632_RDS_OnOff failed, RDS not support\n"); + return false; + } + + if (bFlag) { + mt6632_RDS_Init_Data(dst); + ret = mt6632_RDS_enable(); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "mt6632_RDS_OnOff enable failed\n"); + return false; + } + } else { + ret = mt6632_RDS_disable(); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "mt6632_RDS_OnOff disable failed\n"); + return false; + } + } + + return true; +} + +DEFINE_RDSLOG(mt6632_rds_log); + +/* mt6632_RDS_Efm_s32_Handler - response FM RDS interrupt + * @fm - main data structure of FM driver + * This function first get RDS raw data, then call RDS spec parser + */ +static signed int mt6632_rds_parser(struct rds_t *rds_dst, struct rds_rx_t *rds_raw, + signed int rds_size, unsigned short(*getfreq) (void)) +{ + mt6632_rds_log.log_in(&mt6632_rds_log, rds_raw, rds_size); + return rds_parser(rds_dst, rds_raw, rds_size, getfreq); +} + +static signed int mt6632_rds_log_get(struct rds_rx_t *dst, signed int *dst_len) +{ + return mt6632_rds_log.log_out(&mt6632_rds_log, dst, dst_len); +} + +static signed int mt6632_rds_gc_get(struct rds_group_cnt_t *dst, struct rds_t *rdsp) +{ + return rds_grp_counter_get(dst, &rdsp->gc); +} + +static signed int mt6632_rds_gc_reset(struct rds_t *rdsp) +{ + return rds_grp_counter_reset(&rdsp->gc); +} + +signed int fm_rds_ops_register(struct fm_basic_interface *bi, struct fm_rds_interface *ri) +{ + signed int ret = 0; + + if (ri == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,ri invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_bi = bi; + + ri->rds_blercheck = mt6632_RDS_BlerCheck; + ri->rds_onoff = mt6632_RDS_OnOff; + ri->rds_parser = mt6632_rds_parser; + ri->rds_gbc_get = mt6632_RDS_Get_GoodBlock_Counter; + ri->rds_bbc_get = mt6632_RDS_Get_BadBlock_Counter; + ri->rds_bbr_get = mt6632_RDS_Get_BadBlock_Ratio; + ri->rds_bc_reset = mt6632_RDS_BlockCounter_Reset; + ri->rds_bci_get = mt6632_RDS_Get_BlerCheck_Interval; + ri->rds_log_get = mt6632_rds_log_get; + ri->rds_gc_get = mt6632_rds_gc_get; + ri->rds_gc_reset = mt6632_rds_gc_reset; + return ret; +} + +signed int fm_rds_ops_unregister(struct fm_rds_interface *ri) +{ + signed int ret = 0; + + if (ri == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,ri invalid pointer\n", __func__); + return -FM_EPARA; + } + + fm_bi = NULL; + fm_memset(ri, 0, sizeof(struct fm_rds_interface)); + return ret; +} + diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/inc/mt6635_fm_lib.h b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/inc/mt6635_fm_lib.h new file mode 100644 index 00000000000000..6d6f195cfb4c14 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/inc/mt6635_fm_lib.h @@ -0,0 +1,68 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ +#ifndef __MT6635_FM_LIB_H__ +#define __MT6635_FM_LIB_H__ + +#include "fm_typedef.h" + +enum { + DSPPATCH = 0xFFF9, + USDELAY = 0xFFFA, + MSDELAY = 0xFFFB, + HW_VER = 0xFFFD, + POLL_N = 0xFFFE, /* poling check if bit(n) is '0' */ + POLL_P = 0xFFFF, /* polling check if bit(n) is '1' */ +}; + +enum { + FM_PUS_DSPPATCH = DSPPATCH, + FM_PUS_USDELAY = USDELAY, + FM_PUS_MSDELAY = MSDELAY, + FM_PUS_HW_VER = HW_VER, + FM_PUS_POLL_N = POLL_N, /* poling check if bit(n) is '0' */ + FM_PUS_POLL_P = POLL_P, /* polling check if bit(n) is '1' */ + FM_PUS_MAX +}; + +enum { + mt6635_E1 = 0, + mt6635_E2 +}; + +struct mt6635_fm_cqi { + unsigned short ch; + unsigned short rssi; + unsigned short reserve; +}; + +struct adapt_fm_cqi { + signed int ch; + signed int rssi; + signed int reserve; +}; + +struct mt6635_full_cqi { + unsigned short ch; + unsigned short rssi; + unsigned short pamd; + unsigned short pr; + unsigned short fpamd; + unsigned short mr; + unsigned short atdc; + unsigned short prx; + unsigned short atdev; + unsigned short smg; /* soft-mute gain */ + unsigned short drssi; /* delta rssi */ +}; + +#endif diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/inc/mt6635_fm_reg.h b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/inc/mt6635_fm_reg.h new file mode 100644 index 00000000000000..9a2c77483fb3d9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/inc/mt6635_fm_reg.h @@ -0,0 +1,57 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ +#ifndef __MT6635_FM_REG_H__ +#define __MT6635_FM_REG_H__ + +/* RDS_BDGRP_ABD_CTRL_REG */ +enum { + BDGRP_ABD_EN = 0x0001, + BER_RUN = 0x2000 +}; +#define FM_DAC_CON1 0x83 +#define FM_DAC_CON2 0x84 +#define FM_FT_CON0 0x86 +enum { + FT_EN = 0x0001 +}; + +#define FM_I2S_CON0 0x90 +enum { + I2S_EN = 0x0001, + FORMAT = 0x0002, + WLEN = 0x0004, + I2S_SRC = 0x0008 +}; + +/* FM_MAIN_CTRL */ +enum { + TUNE = 0x0001, + SEEK = 0x0002, + SCAN = 0x0004, + CQI_READ = 0x0008, + RDS_MASK = 0x0010, + MUTE = 0x0020, + RDS_BRST = 0x0040, + RAMP_DOWN = 0x0100, +}; + +enum { + ANTENNA_TYPE = 0x0010, /* 0x61 D4, 0:long, 1:short */ + ANALOG_I2S = 0x0080, /* 0x61 D7, 0:lineout, 1:I2S */ + DE_EMPHASIS = 0x1000, /* 0x61 D12,0:50us, 1:75 us */ +}; + +#define OSC_FREQ_BITS 0x0070 /* 0x60 bit4~6 */ +#define OSC_FREQ_MASK (~OSC_FREQ_BITS) + +#endif /* __MT6635_FM_REG_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/pub/mt6635_2_fm_lib.c b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/pub/mt6635_2_fm_lib.c new file mode 100644 index 00000000000000..c7c049064109f8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/pub/mt6635_2_fm_lib.c @@ -0,0 +1,2007 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ +#include <linux/slab.h> +#include <linux/vmalloc.h> + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_patch.h" +#include "fm_utils.h" +#include "fm_link.h" +#include "fm_config.h" +#include "fm_cmd.h" + +#include "mt6635_fm_reg.h" +#include "mt6635_fm_lib.h" + +#define HQA_RETURN_ZERO_MAP 0 +#define HQA_ZERO_DESENSE_MAP 0 + +/* #include "mach/mt_gpio.h" */ + +/* #define MT6635_FM_PATCH_PATH "/etc/firmware/mt6635/mt6635_fm_patch.bin" */ +/* #define MT6635_FM_COEFF_PATH "/etc/firmware/mt6635/mt6635_fm_coeff.bin" */ +/* #define MT6635_FM_HWCOEFF_PATH "/etc/firmware/mt6635/mt6635_fm_hwcoeff.bin" */ +/* #define MT6635_FM_ROM_PATH "/etc/firmware/mt6635/mt6635_fm_rom.bin" */ + +static struct fm_patch_tbl mt6635_patch_tbl[5] = { + {FM_ROM_V1, "mt6635_fm_v1_patch.bin", "mt6635_fm_v1_coeff.bin", NULL, NULL}, + {FM_ROM_V2, "mt6635_fm_v2_patch.bin", "mt6635_fm_v2_coeff.bin", NULL, NULL}, + {FM_ROM_V3, "mt6635_fm_v3_patch.bin", "mt6635_fm_v3_coeff.bin", NULL, NULL}, + {FM_ROM_V4, "mt6635_fm_v4_patch.bin", "mt6635_fm_v4_coeff.bin", NULL, NULL}, + {FM_ROM_V5, "mt6635_fm_v5_patch.bin", "mt6635_fm_v5_coeff.bin", NULL, NULL} +}; + +static struct fm_hw_info mt6635_hw_info = { + .chip_id = 0x00006635, + .eco_ver = 0x00000000, + .rom_ver = 0x00000000, + .patch_ver = 0x00000000, + .reserve = 0x00000000, +}; + +unsigned char *cmd_buf; +struct fm_lock *cmd_buf_lock; +struct fm_res_ctx *fm_res; +static struct fm_callback *fm_cb_op; + +/* static signed int Chip_Version = mt6635_E1; */ + +/* static bool rssi_th_set = false; */ + +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ +static struct fm_fifo *cqi_fifo; +#endif +static signed int mt6635_is_dese_chan(unsigned short freq); + +static unsigned short mt6635_chan_para_get(unsigned short freq); +static signed int mt6635_desense_check(unsigned short freq, signed int rssi); +static bool mt6635_TDD_chan_check(unsigned short freq); +static bool mt6635_SPI_hopping_check(unsigned short freq); +static signed int mt6635_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid); + +static signed int mt6635_pwron(signed int data) +{ + if (fm_wcn_ops.ei.wmt_func_on && !fm_wcn_ops.ei.wmt_func_on()) { + WCN_DBG(FM_ERR | CHIP, "WMT turn on FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn on FM OK!\n"); + return 0; +} + +static signed int mt6635_pwroff(signed int data) +{ + if (fm_wcn_ops.ei.wmt_func_off && !fm_wcn_ops.ei.wmt_func_off()) { + WCN_DBG(FM_ERR | CHIP, "WMT turn off FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn off FM OK!\n"); + return 0; +} + +static unsigned short mt6635_get_chipid(void) +{ + return 0x6635; +} + +/* MT6635_SetAntennaType - set Antenna type + * @type - 1, Short Antenna; 0, Long Antenna + */ +static signed int mt6635_SetAntennaType(signed int type) +{ + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | CHIP, "set ana to %s\n", type ? "short" : "long"); + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + + if (type) + dataRead |= ANTENNA_TYPE; + else + dataRead &= (~ANTENNA_TYPE); + + fm_reg_write(FM_MAIN_CG2_CTRL, dataRead); + + return 0; +} + +static signed int mt6635_GetAntennaType(void) +{ + unsigned short dataRead = 0; + + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + WCN_DBG(FM_DBG | CHIP, "get ana type: %s\n", (dataRead & ANTENNA_TYPE) ? "short" : "long"); + + if (dataRead & ANTENNA_TYPE) + return FM_ANA_SHORT; /* short antenna */ + else + return FM_ANA_LONG; /* long antenna */ +} + +static signed int mt6635_Mute(bool mute) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | CHIP, "set %s\n", mute ? "mute" : "unmute"); + /* fm_reg_read(FM_MAIN_CTRL, &dataRead); */ + fm_reg_read(0x9C, &dataRead); + + /* fm_top_reg_write(0x0050, 0x00000007); */ + if (mute == 1) + ret = fm_reg_write(0x9C, (dataRead & 0xFFFC) | 0x0003); + else + ret = fm_reg_write(0x9C, (dataRead & 0xFFFC)); + + /* fm_top_reg_write(0x0050, 0x0000000F); */ + + return ret; +} + +static signed int mt6635_rampdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + + /* A1. Clear DSP state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF0, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* A2. Set DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFFF, RAMP_DOWN, &buf[pkt_size], buf_size - pkt_size); + /* @Wait for STC_DONE interrupt@ */ + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size], + buf_size - pkt_size); + /* A6. Clear DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, (~RAMP_DOWN), 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* A7. Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6635_rampdown - f/w will wait for STC_DONE interrupt + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6635_rampdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_rampdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_RAMPDOWN_OPCODE, pkt_size); +} + +/* FMSYS Ramp Down Sequence*/ +static signed int mt6635_RampDown(void) +{ + struct fm_ext_interface *ei = &fm_wcn_ops.ei; + signed int ret = 0; + unsigned int tem = 0; + unsigned short pkt_size; + /* unsigned short tmp; */ + + WCN_DBG(FM_DBG | CHIP, "ramp down\n"); + + /* switch SPI clock to 26MHz */ + if (ei->spi_clock_switch) + ret = ei->spi_clock_switch(FM_SPI_SPEED_26M); + else { + ret = -1; + WCN_DBG(FM_ERR | CHIP, "Clock switch cb is null\n"); + } + if (ret) + WCN_DBG(FM_ERR | CHIP, + "RampDown Switch SPI clock to 26MHz failed\n"); + + /* unlock 64M */ + ret = fm_host_reg_read(0x18003004, &tem); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: unlock 64M reg 0x18003004 failed\n", __func__); + ret = fm_host_reg_write(0x18003004, tem & (~(0x1 << 15))); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: unlock 64M failed\n", __func__); + + /* disable 'rf_spi_div_en' */ + ret = fm_host_reg_read(0x18001A00, &tem); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: disable rf_spi_div_en read failed\n", __func__); + ret = fm_host_reg_write(0x18001A00, tem | (0x1 << 28)); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: disable rf_spi_div_en write failed\n", __func__); + + /* A0.0 Host control RF register */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /*Set 0x60 [D3:D0] = 0x7*/ + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down HOST control rf: Set 0x60 [D3:D0] = 0x7 failed\n"); + return ret; + } + + /* A0.1 Update FM ADPLL fast tracking mode gain */ + ret = fm_set_bits(0x0F, 0x0000, 0xF800); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down ADPLL gainA/B: Set 0xFH [D10:D0] = 0x000 failed\n"); + return ret; + } + + /* A0.2 Host control RF register */ + ret = fm_set_bits(0x60, 0x000F, 0xFFF0); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down Host control RF registerwr top 0x60 failed\n"); + return ret; + } + /* A1. Clear dsp state*/ + ret = fm_set_bits(0x63, 0x0000, 0xFFF0); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down Host control RF registerwr top 0x63 failed\n"); + return ret; + } + /* A2. Set DSP ramp down state*/ + ret = fm_set_bits(0x63, 0x0010, 0xFFEF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down Host control RF registerwr top 0x63 failed\n"); + return ret; + } + + /* A3. Clear STC_DONE interrupt */ + ret = fm_reg_write(FM_MAIN_INTRMASK, 0x0000); + if (ret) + WCN_DBG(FM_ERR | CHIP, "ramp down clean FM_MAIN_INTRMASK failed\n"); + + ret = fm_reg_write(FM_MAIN_EXTINTRMASK, 0x0000); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down clean FM_MAIN_EXTINTRMASK failed\n"); + return ret; + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6635_rampdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_RAMPDOWN, SW_RETRY_CNT, RAMPDOWN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down failed\n"); + return ret; + } + + ret = fm_reg_write(FM_MAIN_EXTINTRMASK, 0x0021); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down wr FM_MAIN_EXTINTRMASK failed\n"); + return ret; + } + + ret = fm_reg_write(FM_MAIN_INTRMASK, 0x0021); + if (ret) + WCN_DBG(FM_ERR | CHIP, "ramp down wr FM_MAIN_INTRMASK failed\n"); + + return ret; +} + +static signed int mt6635_get_rom_version(void) +{ + unsigned short flag_Romcode = 0; + unsigned short nRomVersion = 0; +#define ROM_CODE_READY 0x0001 + signed int ret = 0; + + /* A1.1 DSP rom code version request enable --- set 0x61 b15=1 */ + fm_set_bits(0x61, 0x8000, 0x7FFF); + + /* A1.2 Release ASIP reset --- set 0x61 b1=1 */ + fm_set_bits(0x61, 0x0002, 0xFFFD); + + /* A1.3 Enable ASIP power --- set 0x61 b0=0 */ + fm_set_bits(0x61, 0x0000, 0xFFFE); + + /* A1.4 Wait until DSP code version ready --- wait loop 1ms */ + do { + fm_delayus(1000); + ret = fm_reg_read(0x84, &flag_Romcode); + /* ret=-4 means signal got when control FM. usually get sig 9 to kill FM process. */ + /* now cancel FM power up sequence is recommended. */ + if (ret) + return ret; + + WCN_DBG(FM_DBG | CHIP, "ROM_CODE_READY flag 0x84=%x\n", flag_Romcode); + } while (flag_Romcode != ROM_CODE_READY); + + + /* A1.5 Read FM DSP code version --- rd 0x83[15:8] */ + fm_reg_read(0x83, &nRomVersion); + nRomVersion = (nRomVersion >> 8); + + /* A1.6 DSP rom code version request disable --- set 0x61 b15=0 */ + fm_set_bits(0x61, 0x0000, 0x7FFF); + + /* A1.7 Reset ASIP --- set 0x61[1:0] = 1 */ + fm_set_bits(0x61, 0x0001, 0xFFFC); + + return (signed int) nRomVersion; +} + +static signed int mt6635_pwrup_clock_on_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + unsigned short de_emphasis; + /* unsigned short osc_freq; */ + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + de_emphasis = fm_config.rx_cfg.deemphasis; + de_emphasis &= 0x0001; /* rang 0~1 */ + /* 2,turn on top clock */ + pkt_size += fm_bop_top_write(0xA00, 0xFFFFFFFF, &buf[pkt_size], buf_size - pkt_size); + /* wr top cr a00 ffffffff */ + + /* 3,enable MTCMOS */ + pkt_size += fm_bop_top_write(0x160, 0x00000030, &buf[pkt_size], buf_size - pkt_size); + /* wr top 160 30 */ + + pkt_size += fm_bop_top_write(0x160, 0x00000035, &buf[pkt_size], buf_size - pkt_size); + /* wr top 160 35 */ + pkt_size += fm_bop_udelay(10, &buf[pkt_size], buf_size - pkt_size); + /* delay 10us */ + pkt_size += fm_bop_top_write(0x160, 0x00000015, &buf[pkt_size], buf_size - pkt_size); + /* wr top 160 15 */ + pkt_size += fm_bop_top_write(0x160, 0x00000005, &buf[pkt_size], buf_size - pkt_size); + /* wr top 160 5 */ + + pkt_size += fm_bop_udelay(10, &buf[pkt_size], buf_size - pkt_size); + /* delay 10us */ + pkt_size += fm_bop_top_write(0x160, 0x00000045, &buf[pkt_size], buf_size - pkt_size); + /* wr top 160 45 */ + + /* 4,set comspi fm slave dumy count */ + pkt_size += fm_bop_write(0x7f, 0x801f, &buf[pkt_size], buf_size - pkt_size); /* wr 7f 801f */ + + /* A. FM digital clock enable */ + /* A1. Wait 3ms */ + pkt_size += fm_bop_udelay(3000, &buf[pkt_size], buf_size - pkt_size); + + /* A2. Release HW clock gating*/ + pkt_size += fm_bop_write(0x60, 0x0007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 7 */ + /* A3. Enable DSP auto clock gating */ + pkt_size += fm_bop_write(0x70, 0x0040, &buf[pkt_size], buf_size - pkt_size); /* wr 70 0040 */ + /* A4. Deemphasis setting: Set 0 for 50us, Set 1 for 75us */ + pkt_size += fm_bop_modify(0x61, ~DE_EMPHASIS, (de_emphasis << 12), &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6635_pwrup_clock_on - Wholechip FM Power Up: step 1, FM Digital Clock enable + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6635_pwrup_clock_on(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_pwrup_clock_on_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6635_pwrup_digital_init_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* Part D FM RF&ADPLL divider setting */ + + /* D2.1 set cell mode */ + /* wr 30 D3:D2 00:FDD(default),01:both.10: TDD, 11 FDD */ + /* pkt_size += fm_bop_modify(0x30, 0xFFF3, 0x0000, &buf[pkt_size], buf_size - pkt_size); */ + + /* D2.2 set ADPLL divider */ + pkt_size += fm_bop_write(0x21, 0xE000, &buf[pkt_size], buf_size - pkt_size); /* wr 21 E000 */ + /* D2.3 set SDM coeff0_H */ + pkt_size += fm_bop_write(0xD8, 0x03F0, &buf[pkt_size], buf_size - pkt_size); /* wr D8 0x03F0 */ + /* D2.4 set SDM coeff0_L */ + pkt_size += fm_bop_write(0xD9, 0x3F04, &buf[pkt_size], buf_size - pkt_size); /* wr D9 0x3F04 */ + /* D2.5 set SDM coeff1_H */ + pkt_size += fm_bop_write(0xDA, 0x0014, &buf[pkt_size], buf_size - pkt_size); /* wr DA 0x0014 */ + /* D2.6 set SDM coeff1_L */ + pkt_size += fm_bop_write(0xDB, 0x2A38, &buf[pkt_size], buf_size - pkt_size); /* wr DB 0x2A38 */ + /* D2.7 set 26M clock */ + pkt_size += fm_bop_write(0x23, 0x4000, &buf[pkt_size], buf_size - pkt_size); /* wr 23 4000 */ + + /* Part E: FM Digital Init: fm_rgf_maincon */ + + /* E4. Set appropriate interrupt mask behavior as desired */ + /* Enable stc_done_mask, Enable rgf_rds_mask*/ + pkt_size += fm_bop_write(0x6A, 0x0021, &buf[pkt_size], buf_size - pkt_size); /* wr 6A 0021 */ + pkt_size += fm_bop_write(0x6B, 0x0021, &buf[pkt_size], buf_size - pkt_size); /* wr 6B 0021 */ + + /* E5. Enable hw auto control */ + pkt_size += fm_bop_write(0x60, 0x0000000F, &buf[pkt_size], buf_size - pkt_size); /* wr 60 f */ + + /* E6. Release ASIP reset */ + pkt_size += fm_bop_modify(0x61, 0xFFFD, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D1=1 */ + /* E7. Enable ASIP power */ + pkt_size += fm_bop_modify(0x61, 0xFFFE, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D0=0 */ + + /* E8 */ + pkt_size += fm_bop_udelay(100000, &buf[pkt_size], buf_size - pkt_size); /* delay 100ms */ + /* E9. Check HW initial complete */ + pkt_size += fm_bop_rd_until(0x64, 0x001F, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* Poll 64[0~4] = 2 */ + + return pkt_size - 4; +} + +/* + * mt6635_pwrup_digital_init - Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6635_pwrup_digital_init(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_pwrup_digital_init_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6635_pwrup_fine_tune_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* F1 set host control RF register */ + pkt_size += fm_bop_write(0x60, 0x00000007, &buf[pkt_size], buf_size - pkt_size); + + /* F2 fine tune RF setting */ + pkt_size += fm_bop_write(0x01, 0xBEE8, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x03, 0xF6ED, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x15, 0x0D80, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x16, 0x0068, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x17, 0x092A, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x34, 0x807F, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x35, 0x311E, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x40, 0x0100, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x03, 0xFAF5, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x05, 0x7A80, &buf[pkt_size], buf_size - pkt_size); + + /* F4 set DSP control RF register */ + pkt_size += fm_bop_write(0x60, 0x0000000F, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} + +/* + * mt6635_pwrup_fine_tune - Wholechip FM Power Up: step 5, FM RF fine tune setting + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6635_pwrup_fine_tune(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_pwrup_fine_tune_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6635_pwrdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* A1:set audio output I2S Tx mode: */ + pkt_size += fm_bop_modify(0x9B, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + + /* B0:Disable HW clock control */ + pkt_size += fm_bop_write(0x60, 0x330F, &buf[pkt_size], buf_size - pkt_size); + /* B1:Reset ASIP : Set 0x61, [D1 = 0, D0=1] */ + pkt_size += fm_bop_modify(0x61, 0xFFFD, 0x0001, &buf[pkt_size], buf_size - pkt_size); + + /* B2:digital core + digital rgf reset */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + + /* B3:Disable all clock */ + pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* B4:Reset rgfrf */ + pkt_size += fm_bop_write(0x60, 0x4000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); + + /* MTCMOS power off */ + /* C0:disable MTCMOS */ + pkt_size += fm_bop_top_write(0x160, 0x0005, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x160, 0x0015, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x160, 0x0035, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x160, 0x0030, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_rd_until(0x160, 0x0000000A, 0x0, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6635_pwrdown - Wholechip FM Power down: Digital Modem Power Down + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6635_pwrdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_pwrdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6635_tune_reg_op(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 4; + + WCN_DBG(FM_ALT | CHIP, "%s enter mt6635_tune function\n", __func__); + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* A2 Enable hardware controlled tuning sequence */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF8, TUNE, &buf[pkt_size], buf_size - pkt_size);/*Set 0x63 D0=1*/ + /* Wait for STC_DONE interrupt */ + + +#ifdef FM_TUNE_USE_POLL + /* A3 Wait for STC_DONE interrupt */ + /* A4 Wait for STC_DONE interrupt status flag */ + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, + FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); + /* A6 Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); +#endif + + pkt_size += fm_bop_udelay(100000, &buf[pkt_size], buf_size - pkt_size); + WCN_DBG(FM_ALT | CHIP, "mt6635_tune delay 100 ms wait 0x69 to change\n"); + + WCN_DBG(FM_ALT | CHIP, "%s leave mt6635_tune function\n", __func__); + + return pkt_size - 4; +} + +/* + * mt6635_tune - execute tune action, + * @buf - target buf + * @buf_size - buffer size + * @freq - 760 ~ 1080, 100KHz unit + * return package size + */ +static signed int mt6635_tune(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_tune_reg_op(buf, buf_size, freq, chan_para); + return fm_op_seq_combine_cmd(buf, FM_TUNE_OPCODE, pkt_size); +} + +/* + * mt6635_pwrup_DSP_download - execute dsp/coeff patch dl action, + * @patch_tbl - current chip patch table + * return patch dl ok or not + */ +static signed int mt6635_pwrup_DSP_download(struct fm_patch_tbl *patch_tbl) +{ +#define PATCH_BUF_SIZE (4096*6) + signed int ret = 0; + signed int patch_len = 0; + unsigned char *dsp_buf = NULL; + unsigned short tmp_reg = 0; + + if (fm_wcn_ops.ei.wmt_ic_info_get) + mt6635_hw_info.eco_ver = fm_wcn_ops.ei.wmt_ic_info_get(); + WCN_DBG(FM_DBG | CHIP, "ECO version:0x%08x\n", mt6635_hw_info.eco_ver); + + /* Wholechip FM Power Up: step 3, get mt6635 DSP ROM version */ + ret = mt6635_get_rom_version(); + if (ret >= 0) { + mt6635_hw_info.rom_ver = ret; + WCN_DBG(FM_NTC | CHIP, "%s ROM version: v%d\n", __func__, mt6635_hw_info.rom_ver); + } else { + WCN_DBG(FM_ERR | CHIP, "get ROM version failed\n"); + if (ret == -4) + WCN_DBG(FM_ERR | CHIP, "signal got when control FM, usually get sig 9 to kill FM process.\n"); + /* now cancel FM power up sequence is recommended. */ + goto out; + } + + /* Wholechip FM Power Up: step 4 download patch */ + dsp_buf = fm_vmalloc(PATCH_BUF_SIZE); + if (!dsp_buf) { + WCN_DBG(FM_ALT | CHIP, "-ENOMEM\n"); + return -ENOMEM; + } + + patch_len = fm_get_patch_path(mt6635_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_patch_path failed\n"); + ret = patch_len; + goto out; + } + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_PATCH); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " DL DSPpatch failed\n"); + goto out; + } + + patch_len = fm_get_coeff_path(mt6635_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_coeff_path failed\n"); + ret = patch_len; + goto out; + } + + mt6635_hw_info.rom_ver += 1; + + tmp_reg = dsp_buf[38] | (dsp_buf[39] << 8); /* to be confirmed */ + mt6635_hw_info.patch_ver = (signed int) tmp_reg; + WCN_DBG(FM_NTC | CHIP, "Patch version: 0x%08x\n", mt6635_hw_info.patch_ver); + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_COEFFICIENT); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Download DSP coefficient failed\n"); + goto out; + } + + /* Download HWACC coefficient */ + fm_reg_write(0x92, 0x0000); + fm_reg_write(0x90, 0x0040); /* Reset download control */ + fm_reg_write(0x90, 0x0000); /* Disable memory control from host*/ +out: + if (dsp_buf) { + fm_vfree(dsp_buf); + dsp_buf = NULL; + } + return ret; +} +static void mt6635_show_reg(void) +{ + unsigned int host_reg[3] = {0}; + unsigned int debug_reg1[3] = {0}; + unsigned short debug_reg2[3] = {0}; + + fm_host_reg_read(0x1800400C, &host_reg[0]); + fm_host_reg_read(0x18001900, &host_reg[1]); + fm_host_reg_read(0x18008040, &host_reg[2]); + WCN_DBG(FM_ALT | CHIP, + "host read 0x1800400C = 0x%08x, 0x18001900 = 0x%08x, 0x18008040 = 0x%08x\n", + host_reg[0], host_reg[1], host_reg[2]); + + fm_top_reg_read(0x003c, &debug_reg1[0]); + fm_top_reg_read(0x0a18, &debug_reg1[1]); + fm_top_reg_read(0x0160, &debug_reg1[2]); + fm_reg_read(0x7f, &debug_reg2[0]); + fm_reg_read(0x62, &debug_reg2[1]); + fm_reg_read(0x60, &debug_reg2[2]); + WCN_DBG(FM_ALT | CHIP, + "top cr 0x3c = 0x%08x, 0xa18 = 0x%08x, 0x160 = 0x%08x, fmreg 0x7f = 0x%08x, 0x62 = 0x%08x, 0x60 = 0x%08x\n", + debug_reg1[0], debug_reg1[1], debug_reg1[2], debug_reg2[0], debug_reg2[1], debug_reg2[2]); +} + +static signed int mt6635_PowerUp(unsigned short *chip_id, unsigned short *device_id) +{ + signed int ret = 0, count = 0; + unsigned short pkt_size; + unsigned short tmp_reg = 0; + unsigned int tem = 0; + + if (chip_id == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (device_id == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + WCN_DBG(FM_DBG | CHIP, "pwr on seq......\n"); + + /* enable osc_en to conn_infra_cfg */ + ret = fm_host_reg_write(0x18008040, 0x00000001); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "Enable osc_en to conn_infra_cfg failed\n"); + return ret; + } + + /* polling 26M rdy, max 5 times */ + do { + fm_delayus(1000); + ret = fm_host_reg_read(0x18001830, &tem); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "read 0x18001830 failed\n"); + return ret; + } + count++; + } while ((tem & 0x80000) == 0 && count < 5); + + if (count >= 5) + WCN_DBG(FM_ERR | CHIP, "polling 26M rdy failed\n"); + + /* Wholechip FM Power Up: step 1, set common SPI parameter */ + ret = fm_host_reg_write(0x1800400C, 0x0000801F); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup set CSPI failed\n"); + return ret; + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + + pkt_size = mt6635_pwrup_clock_on(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6635_pwrup_clock_on failed\n"); + return ret; + } + + /* Wholechip FM Power Up: step 2, read HW version */ + mt6635_show_reg(); + fm_reg_read(0x62, &tmp_reg); + /* chip_id = tmp_reg; */ + if (tmp_reg == 0x6635) + *chip_id = 0x6635; + *device_id = tmp_reg; + mt6635_hw_info.chip_id = (signed int) tmp_reg; + WCN_DBG(FM_DBG | CHIP, "chip_id:0x%04x\n", tmp_reg); + + if ((mt6635_hw_info.chip_id != 0x6635)) { + mt6635_show_reg(); + WCN_DBG(FM_NTC | CHIP, "fm sys error, reset hw, chip_id = 0x%08x\n", mt6635_hw_info.chip_id); + return -FM_EFW; + + } + /* Wholechip FM Power Up: step 3, patch download */ + ret = mt6635_pwrup_DSP_download(mt6635_patch_tbl); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6635_pwrup_DSP_download failed\n"); + return ret; + } + + /* Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6635_pwrup_digital_init(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6635_pwrup_digital_init failed\n"); + return ret; + } + + /* Wholechip FM Power Up: step 5, FM RF fine tune setting */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6635_pwrup_fine_tune(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6635_pwrup_fine_tune failed\n"); + return ret; + } + + /* Enable connsys FM 2 wire RX */ + fm_reg_write(0x9B, 0xF9AB); /* G2: Set audio output i2s TX mode */ + fm_host_reg_write(0x18008064, 0x00000014); /* G4: Enable aon_osc_clk_cg */ + fm_host_reg_write(0x18008058, 0x888100C3); /* G5: Enable FMAUD trigger, 20170119 */ + fm_host_reg_write(0x18000070, 0x00000000); /* G6: Release fmsys memory power down*/ + + WCN_DBG(FM_NTC | CHIP, "pwr on seq ok\n"); + + return ret; +} + +static signed int mt6635_PowerDown(void) +{ + struct fm_ext_interface *ei = &fm_wcn_ops.ei; + signed int ret = 0; + unsigned int tem = 0; + unsigned short pkt_size; + + WCN_DBG(FM_DBG | CHIP, "pwr down seq\n"); + + /* A0.1. Disable aon_osc_clk_cg */ + ret = fm_host_reg_write(0x18008064, 0x00000004); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Disable aon_osc_clk_cg failed\n"); + return ret; + } + /* A0.1. Disable FMAUD trigger */ + ret = fm_host_reg_write(0x18008058, 0x88800000); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Disable FMAUD trigger failed\n"); + return ret; + } + + /* A0.1. issue fmsys memory powr down */ + ret = fm_host_reg_write(0x18000070, 0x00000001); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Issue fmsys memory powr down failed\n"); + return ret; + } + + /* switch SPI clock to 26M */ + WCN_DBG(FM_DBG | CHIP, "PowerDown: switch SPI clock to 26M\n"); + if (ei->spi_clock_switch) + ret = ei->spi_clock_switch(FM_SPI_SPEED_26M); + else { + ret = -1; + WCN_DBG(FM_ERR | CHIP, "Clock switch cb is null\n"); + } + if (ret) + WCN_DBG(FM_ERR | CHIP, + "PowerDown: Switch SPI clock to 26M failed\n"); + + /* unlock 64M */ + ret = fm_host_reg_read(0x18003004, &tem); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: unlock 64M reg 0x18003004 failed\n", __func__); + ret = fm_host_reg_write(0x18003004, tem & (~(0x1 << 15))); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: unlock 64M failed\n", __func__); + + /* disable 'rf_spi_div_en' */ + ret = fm_host_reg_read(0x18001A00, &tem); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: disable rf_spi_div_en read failed\n", __func__); + ret = fm_host_reg_write(0x18001A00, tem | (0x1 << 28)); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: disable rf_spi_div_en write failed\n", __func__); + + if (ret) + WCN_DBG(FM_ALT | CHIP, "PowerDown: Enable 26M crystal sleep failed\n"); + + /* A0:set audio output I2X Rx mode: */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6635_pwrdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6635_pwrdown failed\n"); + return ret; + } + + /* RF power off */ + + /* SLP_CTRL setting */ + + /* set common spi fm parameter */ + ret = fm_host_reg_read(0x1800400C, &tem); + tem = tem & 0xFFFF0000; /* D15:D0 */ + ret = fm_host_reg_write(0x1800400C, tem); + if (ret) + WCN_DBG(FM_ALT | CHIP, "set common spi fm parameter failed\n"); + + /* clear 26M crystal sleep */ + WCN_DBG(FM_DBG | CHIP, "PowerDown: Enable 26M crystal sleep,Set 0x18008040[0] = 0x0\n"); + ret = fm_host_reg_read(0x18008040, &tem); + tem = tem & 0xFFFFFFFE; + ret = fm_host_reg_write(0x18008040, tem); + + return ret; +} + +static signed int mt6635_set_freq_fine_tune_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* F3 DCOC @ LNA = 7 */ + pkt_size += fm_bop_write(0x40, 0x01AF, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x03, 0xFAF5, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x07, 0x0100, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x01, 0xEEE8, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x3F, 0x3221, &buf[pkt_size], buf_size - pkt_size); + /* wait 1ms */ + pkt_size += fm_bop_udelay(1000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_rd_until(0x3F, 0x001F, 0x0001, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x3F, 0x0220, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x40, 0x0100, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x01, 0xAEE8, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x30, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x36, 0x017A, &buf[pkt_size], buf_size - pkt_size); + + /* F4 set DSP control RF register */ + pkt_size += fm_bop_write(0x60, 0x0000000F, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} + +/* + * mt6635_set_freq_fine_tune - FM RF fine tune setting + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6635_set_freq_fine_tune(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_set_freq_fine_tune_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static bool mt6635_do_SPI_hopping(unsigned short freq) +{ + struct fm_ext_interface *ei = &fm_wcn_ops.ei; + signed int ret = 0; + signed int i = 0; + unsigned int reg_val = 0; + bool flag_spi_hopping = false; + + if (!mt6635_SPI_hopping_check(freq)) + return true; + + /* SPI hopping setting*/ + WCN_DBG(FM_NTC | CHIP, + "%s: freq:%d is SPI hopping channel,turn on 64M PLL\n", + __func__, freq); + + /* enable 'rf_spi_div_en' */ + ret = fm_host_reg_read(0x18001A00, ®_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, + "%s: rf_spi_div_en read failed\n", __func__); + ret = fm_host_reg_write(0x18001A00, reg_val | (0x1 << 28)); + if (ret) + WCN_DBG(FM_ERR | CHIP, + "%s: rf_spi_div_en write failed\n", __func__); + + /* lock 64M */ + ret = fm_host_reg_read(0x18003004, ®_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, + "%s: lock 64M reg 0x18003004 failed\n", __func__); + ret = fm_host_reg_write(0x18003004, reg_val | (0x1 << 15)); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M failed\n", __func__); + + for (i = 0; i < 100; i++) { /*rd 0x18001810 until D1 == 1*/ + + ret = fm_host_reg_read(0x18001810, ®_val); + + if (reg_val & 0x00000002) { + flag_spi_hopping = true; + WCN_DBG(FM_NTC | CHIP, + "%s: POLLING PLL_RDY success !\n", __func__); + /* switch SPI clock to 64MHz */ + if (ei->spi_clock_switch) + ret = ei->spi_clock_switch(FM_SPI_SPEED_64M); + else { + ret = -1; + WCN_DBG(FM_ERR | CHIP, + "Clock switch cb is null\n"); + } + if (ret) + WCN_DBG(FM_ERR | CHIP, + "Switch SPI clock to 64M failed\n"); + break; + } + fm_delayus(10); + } + if (false == flag_spi_hopping) + WCN_DBG(FM_ERR | CHIP, + "%s: Polling to read rd 0x18001810[1] ==0x1 failed !\n", + __func__); + + return flag_spi_hopping; +} + +static bool mt6635_SetFreq(unsigned short freq) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short chan_para = 0; + unsigned short freq_reg = 0; + unsigned short tmp_reg[6] = {0}; + + fm_cb_op->cur_freq_set(freq); + + /* FM VCO Calibration */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /* Set 0x60 [D3:D0] = 0x07*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Host Control RF register 0x60 = 0x7 failed\n", __func__); + + fm_delayus(5); + if (freq >= 750) { + fm_reg_write(0x37, 0xF68C); + fm_reg_write(0x38, 0x0B53); + ret = fm_set_bits(0x30, 0x0014 << 8, 0xC0FF); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x30 failed\n", __func__); + + } else { + fm_reg_write(0x37, 0x0675); + fm_reg_write(0x38, 0x0F54); + ret = fm_set_bits(0x30, 0x001C << 8, 0xC0FF); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x30 failed\n", __func__); + } + ret = fm_set_bits(0x30, 0x0001 << 14, 0xBFFF); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x30 failed\n", __func__); + + fm_reg_write(0x40, 0x010F); + fm_delayus(5); + fm_reg_write(0x36, 0x037A); + fm_reg_write(0x32, 0x8000); + fm_delayus(200); + ret = fm_set_bits(0x3D, 0x0001 << 2, 0xFFFB); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x3D failed\n", __func__); + + fm_reg_write(0x32, 0x0000); + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6635_set_freq_fine_tune(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6635_pwrup_fine_tune failed\n"); + return ret; + } + + if (!mt6635_do_SPI_hopping(freq)) + WCN_DBG(FM_ERR | CHIP, "%s: spi hopping fail!\n", __func__); + + /* A0. Host contrl RF register */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /* Set 0x60 [D3:D0] = 0x07*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Host Control RF register 0x60 = 0x7 failed\n", __func__); + + /* A0.1 Update FM ADPLL fast tracking mode gain */ + ret = fm_set_bits(0x0F, 0x0455, 0xF800); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set FM ADPLL gainA/B=0x455 failed\n", __func__); + + /* A0.2 Set FMSYS cell mode */ + if (mt6635_TDD_chan_check(freq)) { + ret = fm_set_bits(0x30, 0x0008, 0xFFF3); /* use TDD solution */ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: freq[%d]: use TDD solution failed\n", __func__, freq); + } else { + ret = fm_set_bits(0x30, 0x0000, 0xFFF3); /* default use FDD solution */ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: freq[%d]: default use FDD solution failed\n", __func__, freq); + } + + /* A0.3 Host control RF register */ + ret = fm_set_bits(0x60, 0x000F, 0xFFF0); /* Set 0x60 [D3:D0] = 0x0F*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x60 [D3:D0] = 0x0F failed\n", __func__); + + /* A1 Get Channel parameter from map list*/ + + chan_para = mt6635_chan_para_get(freq); + WCN_DBG(FM_DBG | CHIP, "%s: %d chan para = %d\n", __func__, (signed int) freq, (signed int) chan_para); + + freq_reg = freq; + if (fm_get_channel_space(freq_reg) == 0) + freq_reg *= 10; + + freq_reg = (freq_reg - 6400) * 2 / 10; + + /*A1 Set rgfrf_chan = XXX*/ + ret = fm_set_bits(0x65, freq_reg, 0xFC00); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "%s: set rgfrf_chan = xxx = %d failed\n", __func__, freq_reg); + return false; + } + + ret = fm_set_bits(0x65, (chan_para << 12), 0x0FFF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x65 failed\n"); + return false; + } + + /* A0. Host contrl RF register */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /* Set 0x60 [D3:D0] = 0x07*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Host Control RF register 0x60 = 0x7 failed\n", __func__); + + + fm_reg_read(0x62, &tmp_reg[0]); + fm_reg_read(0x64, &tmp_reg[1]); + fm_reg_read(0x69, &tmp_reg[2]); + fm_reg_read(0x6a, &tmp_reg[3]); + fm_reg_read(0x6b, &tmp_reg[4]); + fm_reg_read(0x9b, &tmp_reg[5]); + + WCN_DBG(FM_ALT | CHIP, "%s: Before tune--0x62 0x64 0x69 0x6a 0x6b 0x9b = %04x %04x %04x %04x %04x %04x\n", + __func__, + tmp_reg[0], + tmp_reg[1], + tmp_reg[2], + tmp_reg[3], + tmp_reg[4], + tmp_reg[5]); + + /* A0.3 Host control RF register */ + ret = fm_set_bits(0x60, 0x000F, 0xFF00); /* Set 0x60 [D3:D0] = 0x0F*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x60 [D3:D0] = 0x0F failed\n", __func__); + + if (FM_LOCK(cmd_buf_lock)) + return false; + pkt_size = mt6635_tune(cmd_buf, TX_BUF_SIZE, freq, chan_para); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE | FLAG_TUNE_DONE, SW_RETRY_CNT, TUNE_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + + /* A0. Host contrl RF register */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /* Set 0x60 [D3:D0] = 0x07*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Host Control RF register 0x60 = 0x7 failed\n", __func__); + + memset(tmp_reg, 0, sizeof(tmp_reg[0])*6); + + fm_reg_read(0x62, &tmp_reg[0]); + fm_reg_read(0x64, &tmp_reg[1]); + fm_reg_read(0x69, &tmp_reg[2]); + fm_reg_read(0x6a, &tmp_reg[3]); + fm_reg_read(0x6b, &tmp_reg[4]); + fm_reg_read(0x9b, &tmp_reg[5]); + + WCN_DBG(FM_ALT | CHIP, "%s: After tune--0x62 0x64 0x69 0x6a 0x6b 0x9b = %04x %04x %04x %04x %04x %04x\n", + __func__, + tmp_reg[0], + tmp_reg[1], + tmp_reg[2], + tmp_reg[3], + tmp_reg[4], + tmp_reg[5]); + + /* A0.3 Host control RF register */ + ret = fm_set_bits(0x60, 0x000F, 0xFF00); /* Set 0x60 [D3:D0] = 0x0F*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x60 [D3:D0] = 0x0F failed\n", __func__); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "%s: mt6635_tune failed\n", __func__); + return false; + } + + WCN_DBG(FM_DBG | CHIP, "%s: set freq to %d ok\n", __func__, freq); +#if 0 + /* ADPLL setting for dbg */ + fm_top_reg_write(0x0050, 0x00000007); + fm_top_reg_write(0x0A08, 0xFFFFFFFF); + mt6635_bt_write(0x82, 0x11); + mt6635_bt_write(0x83, 0x11); + mt6635_bt_write(0x84, 0x11); + fm_top_reg_write(0x0040, 0x1C1C1C1C); + fm_top_reg_write(0x0044, 0x1C1C1C1C); + fm_reg_write(0x70, 0x0010); + /*0x0806 DCO clk + *0x0802 ref clk + *0x0804 feedback clk + */ + fm_reg_write(0xE0, 0x0806); +#endif + return true; +} + +#define FM_CQI_LOG_PATH "/mnt/sdcard/fmcqilog" + +static signed int mt6635_full_cqi_get(signed int min_freq, signed int max_freq, signed int space, signed int cnt) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short freq, orig_freq; + signed int i, j, k; + signed int space_val, max, min, num; + struct mt6635_full_cqi *p_cqi; + unsigned char *cqi_log_title = "Freq, RSSI, PAMD, PR, FPAMD, MR, ATDC, PRX, ATDEV, SMGain, DltaRSSI\n"; + unsigned char cqi_log_buf[100] = { 0 }; + signed int pos; + unsigned char cqi_log_path[100] = { 0 }; + + /* for soft-mute tune, and get cqi */ + freq = fm_cb_op->cur_freq_get(); + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + /* get cqi */ + orig_freq = freq; + if (fm_get_channel_space(min_freq) == 0) + min = min_freq * 10; + else + min = min_freq; + + if (fm_get_channel_space(max_freq) == 0) + max = max_freq * 10; + else + max = max_freq; + + if (space == 0x0001) + space_val = 5; /* 50Khz */ + else if (space == 0x0002) + space_val = 10; /* 100Khz */ + else if (space == 0x0004) + space_val = 20; /* 200Khz */ + else + space_val = 10; + + num = (max - min) / space_val + 1; /* Eg, (8760 - 8750) / 10 + 1 = 2 */ + for (k = 0; (orig_freq == 10000) && (g_dbg_level == 0xffffffff) && (k < cnt); k++) { + WCN_DBG(FM_NTC | CHIP, "cqi file:%d\n", k + 1); + freq = min; + pos = 0; + fm_memcpy(cqi_log_path, FM_CQI_LOG_PATH, strlen(FM_CQI_LOG_PATH)); + sprintf(&cqi_log_path[strlen(FM_CQI_LOG_PATH)], "%d.txt", k + 1); + fm_file_write(cqi_log_path, cqi_log_title, strlen(cqi_log_title), &pos); + for (j = 0; j < num; j++) { + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, + SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + WCN_DBG(FM_NTC | CHIP, "smt cqi size %d\n", fm_res->cqi[0]); + p_cqi = (struct mt6635_full_cqi *)&fm_res->cqi[2]; + for (i = 0; i < fm_res->cqi[1]; i++) { + /* just for debug */ + WCN_DBG(FM_NTC | CHIP, + "%04d, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x,\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* format to buffer */ + sprintf(cqi_log_buf, + "%04d, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x,\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* write back to log file */ + fm_file_write(cqi_log_path, cqi_log_buf, strlen(cqi_log_buf), &pos); + } + } else { + WCN_DBG(FM_ALT | CHIP, "smt get CQI failed\n"); + ret = -1; + } + freq += space_val; + } + fm_cb_op->cur_freq_set(0); /* avoid run too much times */ + } + + return ret; +} + +/* + * mt6635_GetCurRSSI - get current freq's RSSI value + * RS=RSSI + * If RS>511, then RSSI(dBm)= (RS-1024)/16*6 + * else RSSI(dBm)= RS/16*6 + */ +static signed int mt6635_GetCurRSSI(signed int *pRSSI) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RSSI_IND, &tmp_reg); + tmp_reg = tmp_reg & 0x03ff; + + if (pRSSI) { + *pRSSI = (tmp_reg > 511) ? (((tmp_reg - 1024) * 6) >> 4) : ((tmp_reg * 6) >> 4); + WCN_DBG(FM_DBG | CHIP, "rssi:%d, dBm:%d\n", tmp_reg, *pRSSI); + } else { + WCN_DBG(FM_ERR | CHIP, "get rssi para error\n"); + return -FM_EPARA; + } + + return 0; +} + +static unsigned short mt6635_vol_tbl[16] = { 0x0000, 0x0519, 0x066A, 0x0814, + 0x0A2B, 0x0CCD, 0x101D, 0x1449, + 0x198A, 0x2027, 0x287A, 0x32F5, + 0x4027, 0x50C3, 0x65AD, 0x7FFF +}; + +static signed int mt6635_SetVol(unsigned char vol) +{ + signed int ret = 0; + + vol = (vol > 15) ? 15 : vol; + ret = fm_reg_write(0x7D, mt6635_vol_tbl[vol]); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "Set vol=%d Failed\n", vol); + return ret; + } + WCN_DBG(FM_DBG | CHIP, "Set vol=%d OK\n", vol); + + + if (vol == 10) { + fm_print_cmd_fifo(); /* just for debug */ + fm_print_evt_fifo(); + } + return 0; +} + +static signed int mt6635_GetVol(unsigned char *pVol) +{ + int ret = 0; + unsigned short tmp = 0; + signed int i; + + if (pVol == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + ret = fm_reg_read(0x7D, &tmp); + if (ret) { + *pVol = 0; + WCN_DBG(FM_ERR | CHIP, "Get vol Failed\n"); + return ret; + } + + for (i = 0; i < 16; i++) { + if (mt6635_vol_tbl[i] == tmp) { + *pVol = i; + break; + } + } + + WCN_DBG(FM_DBG | CHIP, "Get vol=%d OK\n", *pVol); + return 0; +} + +static signed int mt6635_dump_reg(void) +{ + signed int i; + unsigned short TmpReg = 0; + + for (i = 0; i < 0xff; i++) { + fm_reg_read(i, &TmpReg); + WCN_DBG(FM_NTC | CHIP, "0x%02x=0x%04x\n", i, TmpReg); + } + return 0; +} + +/*0:mono, 1:stereo*/ +static bool mt6635_GetMonoStereo(unsigned short *pMonoStereo) +{ +#define FM_BF_STEREO 0x1000 + unsigned short TmpReg = 0; + + if (pMonoStereo) { + fm_reg_read(FM_RSSI_IND, &TmpReg); + *pMonoStereo = (TmpReg & FM_BF_STEREO) >> 12; + } else { + WCN_DBG(FM_ERR | CHIP, "MonoStero: para err\n"); + return false; + } + + WCN_DBG(FM_NTC | CHIP, "Get MonoStero:0x%04x\n", *pMonoStereo); + return true; +} + +static signed int mt6635_SetMonoStereo(signed int MonoStereo) +{ + signed int ret = 0; + + WCN_DBG(FM_NTC | CHIP, "set to %s\n", MonoStereo ? "mono" : "auto"); + fm_reg_write(0x60, 0x0007); + + if (MonoStereo) /*mono */ + ret = fm_set_bits(0x75, 0x0008, ~0x0008); + else + ret = fm_set_bits(0x75, 0x0000, ~0x0008); + + fm_reg_write(0x60, 0x000F); + return ret; +} + +static signed int mt6635_GetCapArray(signed int *ca) +{ + unsigned short dataRead = 0; + unsigned short tmp = 0; + + if (ca == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_reg_read(0x60, &tmp); + fm_reg_write(0x60, tmp & 0xFFF7); /* 0x60 D3=0 */ + + fm_reg_read(0x26, &dataRead); + *ca = dataRead; + + fm_reg_write(0x60, tmp); /* 0x60 D3=1 */ + return 0; +} + +/* + * mt6635_GetCurPamd - get current freq's PAMD value + * PA=PAMD + * If PA>511 then PAMD(dB)= (PA-1024)/16*6, + * else PAMD(dB)=PA/16*6 + */ +static bool mt6635_GetCurPamd(unsigned short *pPamdLevl) +{ + unsigned short tmp_reg = 0; + unsigned short dBvalue, valid_cnt = 0; + int i, total = 0; + + for (i = 0; i < 8; i++) { + if (fm_reg_read(FM_ADDR_PAMD, &tmp_reg)) { + *pPamdLevl = 0; + return false; + } + + tmp_reg &= 0x03FF; + dBvalue = (tmp_reg > 256) ? ((512 - tmp_reg) * 6 / 16) : 0; + if (dBvalue != 0) { + total += dBvalue; + valid_cnt++; + WCN_DBG(FM_DBG | CHIP, "[%d]PAMD=%d\n", i, dBvalue); + } + fm_delayms(3); + } + if (valid_cnt != 0) + *pPamdLevl = total / valid_cnt; + else + *pPamdLevl = 0; + + WCN_DBG(FM_NTC | CHIP, "PAMD=%d\n", *pPamdLevl); + return true; +} + +static signed int mt6635_i2s_info_get(signed int *ponoff, signed int *pmode, signed int *psample) +{ + if (ponoff == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (pmode == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (psample == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + *ponoff = fm_config.aud_cfg.i2s_info.status; + *pmode = fm_config.aud_cfg.i2s_info.mode; + *psample = fm_config.aud_cfg.i2s_info.rate; + + return 0; +} + +static signed int mt6635_get_audio_info(struct fm_audio_info_t *data) +{ + memcpy(data, &fm_config.aud_cfg, sizeof(struct fm_audio_info_t)); + return 0; +} + +static signed int mt6635_hw_info_get(struct fm_hw_info *req) +{ + if (req == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + req->chip_id = mt6635_hw_info.chip_id; + req->eco_ver = mt6635_hw_info.eco_ver; + req->patch_ver = mt6635_hw_info.patch_ver; + req->rom_ver = mt6635_hw_info.rom_ver; + + return 0; +} + +static signed int mt6635_pre_search(void) +{ + mt6635_RampDown(); + /* disable audio output I2S Tx mode */ + fm_reg_write(0x9B, 0x0000); + + return 0; +} + +static signed int mt6635_restore_search(void) +{ + mt6635_RampDown(); + /* set audio output I2S Tx mode */ + fm_reg_write(0x9B, 0xF9AB); + return 0; +} + +static signed int mt6635_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid) +{ + signed int ret = 0; + unsigned short pkt_size; + struct mt6635_full_cqi *p_cqi; + signed int RSSI = 0, PAMD = 0, MR = 0, ATDC = 0; + unsigned int PRX = 0, ATDEV = 0; + unsigned short softmuteGainLvl = 0; + + /* Set rgf_host2dsp_reserve[2] = 1 */ + + ret = mt6635_chan_para_get(freq); + if (ret == 2) + ret = fm_set_bits(FM_CHANNEL_SET, 0x2000, 0x0FFF); /* mdf HiLo */ + else + ret = fm_set_bits(FM_CHANNEL_SET, 0x0000, 0x0FFF); /* clear FA/HL/ATJ */ + + if (!mt6635_do_SPI_hopping(freq)) + WCN_DBG(FM_ERR | CHIP, "%s: spi hopping fail!\n", __func__); + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + p_cqi = (struct mt6635_full_cqi *)&fm_res->cqi[2]; + /* just for debug */ + WCN_DBG(FM_NTC | CHIP, + "freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", + p_cqi->ch, p_cqi->rssi, p_cqi->pamd, p_cqi->pr, p_cqi->fpamd, p_cqi->mr, + p_cqi->atdc, p_cqi->prx, p_cqi->atdev, p_cqi->smg, p_cqi->drssi); + RSSI = ((p_cqi->rssi & 0x03FF) >= 512) ? ((p_cqi->rssi & 0x03FF) - 1024) : (p_cqi->rssi & 0x03FF); + PAMD = ((p_cqi->pamd & 0x1FF) >= 256) ? ((p_cqi->pamd & 0x01FF) - 512) : (p_cqi->pamd & 0x01FF); + MR = ((p_cqi->mr & 0x01FF) >= 256) ? ((p_cqi->mr & 0x01FF) - 512) : (p_cqi->mr & 0x01FF); + ATDC = (p_cqi->atdc >= 32768) ? (65536 - p_cqi->atdc) : (p_cqi->atdc); + if (ATDC < 0) + ATDC = (~(ATDC)) - 1; /* Get abs value of ATDC */ + + PRX = (p_cqi->prx & 0x00FF); + ATDEV = p_cqi->atdev; + softmuteGainLvl = p_cqi->smg; + /* check if the channel is valid according to each CQIs */ + if ((fm_config.rx_cfg.long_ana_rssi_th <= RSSI) + && (fm_config.rx_cfg.pamd_th >= PAMD) + && (fm_config.rx_cfg.atdc_th >= ATDC) + && (fm_config.rx_cfg.mr_th <= MR) + && (fm_config.rx_cfg.prx_th <= PRX) + && (ATDEV >= ATDC) /* sync scan algorithm */ + && (fm_config.rx_cfg.smg_th <= softmuteGainLvl)) { + *valid = true; + } else { + *valid = false; + } + *rssi = RSSI; + } else { + WCN_DBG(FM_ALT | CHIP, "smt get CQI failed\n"); + return false; + } + WCN_DBG(FM_NTC | CHIP, "valid=%d\n", *valid); + return true; +} + +static bool mt6635_em_test(unsigned short group_idx, unsigned short item_idx, unsigned int item_value) +{ + return true; +} + +/* +*parm: +* parm.th_type: 0, RSSI. 1, desense RSSI. 2, SMG. +* parm.th_val: threshold value +*/ +static signed int mt6635_set_search_th(signed int idx, signed int val, signed int reserve) +{ + switch (idx) { + case 0: { + fm_config.rx_cfg.long_ana_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set rssi th =%d\n", val); + break; + } + case 1: { + fm_config.rx_cfg.desene_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set desense rssi th =%d\n", val); + break; + } + case 2: { + fm_config.rx_cfg.smg_th = val; + WCN_DBG(FM_NTC | CHIP, "set smg th =%d\n", val); + break; + } + default: + break; + } + return 0; +} + +static signed int MT6635_low_power_wa_default(signed int fmon) +{ + return 0; +} + +signed int fm_low_ops_register(struct fm_callback *cb, struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,bi invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_get == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_get invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_set == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_set invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_cb_op = cb; + + bi->pwron = mt6635_pwron; + bi->pwroff = mt6635_pwroff; + bi->chipid_get = mt6635_get_chipid; + bi->mute = mt6635_Mute; + bi->rampdown = mt6635_RampDown; + bi->pwrupseq = mt6635_PowerUp; + bi->pwrdownseq = mt6635_PowerDown; + bi->setfreq = mt6635_SetFreq; + bi->low_pwr_wa = MT6635_low_power_wa_default; + bi->get_aud_info = mt6635_get_audio_info; + bi->rssiget = mt6635_GetCurRSSI; + bi->volset = mt6635_SetVol; + bi->volget = mt6635_GetVol; + bi->dumpreg = mt6635_dump_reg; + bi->msget = mt6635_GetMonoStereo; + bi->msset = mt6635_SetMonoStereo; + bi->pamdget = mt6635_GetCurPamd; + bi->em = mt6635_em_test; + bi->anaswitch = mt6635_SetAntennaType; + bi->anaget = mt6635_GetAntennaType; + bi->caparray_get = mt6635_GetCapArray; + bi->hwinfo_get = mt6635_hw_info_get; + bi->i2s_get = mt6635_i2s_info_get; + bi->is_dese_chan = mt6635_is_dese_chan; + bi->softmute_tune = mt6635_soft_mute_tune; + bi->desense_check = mt6635_desense_check; + bi->cqi_log = mt6635_full_cqi_get; + bi->pre_search = mt6635_pre_search; + bi->restore_search = mt6635_restore_search; + bi->set_search_th = mt6635_set_search_th; + + cmd_buf_lock = fm_lock_create("31_cmd"); + ret = fm_lock_get(cmd_buf_lock); + + cmd_buf = fm_zalloc(TX_BUF_SIZE + 1); + + if (!cmd_buf) { + WCN_DBG(FM_ALT | CHIP, "6635 fm lib alloc tx buf failed\n"); + ret = -1; + } +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ + cqi_fifo = fm_fifo_create("6628_cqi_fifo", sizeof(struct adapt_fm_cqi), 640); + if (!cqi_fifo) { + WCN_DBG(FM_ALT | CHIP, "6635 fm lib create cqi fifo failed\n"); + ret = -1; + } +#endif + + return ret; +} + +signed int fm_low_ops_unregister(struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,bi invalid pointer\n", __func__); + return -FM_EPARA; + } + +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ + fm_fifo_release(cqi_fifo); +#endif + + if (cmd_buf) { + fm_free(cmd_buf); + cmd_buf = NULL; + } + + ret = fm_lock_put(cmd_buf_lock); + fm_memset(bi, 0, sizeof(struct fm_basic_interface)); + + fm_cb_op = NULL; + + return ret; +} + +static const signed char mt6635_chan_para_map[] = { +/* 0, X, 1, X, 2, X, 3, X, 4, X, 5, X, 6, X, 7, X, 8, X, 9, X*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, /* 6500~6595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6600~6695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, /* 6700~6795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6800~6895 */ + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6900~6995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7000~7095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7100~7195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, /* 7200~7295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7300~7395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 7400~7495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7500~7595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, /* 7600~7695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7700~7795 */ + 8, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7800~7895 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7900~7995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8000~8095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8100~8195 */ + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8200~8295 */ + 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, /* 8300~8395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8400~8495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8500~8595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8600~8695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8700~8795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8800~8895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8900~8995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9000~9095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9100~9195 */ + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9200~9295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9300~9395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9400~9495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9500~9595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9600~9695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9700~9795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, /* 9800~9895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 9900~9995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10000~10095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10100~10195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10200~10295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10300~10395 */ + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10400~10495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, /* 10500~10595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10600~10695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, /* 10700~10795 */ + 0 /* 10800 */ +}; +static const unsigned short mt6635_scan_dese_list[] = { + 6910, 6920, 7680, 7800, 8450, 9210, 9220, 9230, 9590, 9600, 9830, 9900, 9980, 9990, 10400, 10750, 10760 +}; + +static const unsigned short mt6635_SPI_hopping_list[] = { + 6510, 6520, 6530, 7780, 7790, 7800, 7810, 7820, 9090, 9100, 9110, 9120, 10380, 10390, 10400, 10410, 10420 +}; + +static const unsigned short mt6635_I2S_hopping_list[] = { + 6550, 6760, 6960, 6970, 7170, 7370, 7580, 7780, 7990, 8810, 9210, 9220, 10240 +}; + +static const unsigned short mt6635_TDD_list[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6500~6595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6600~6695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6700~6795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6800~6895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6900~6995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7000~7095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7100~7195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7200~7295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7300~7395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7400~7495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7500~7595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7600~7695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7700~7795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7800~7895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7900~7995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8000~8095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8100~8195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8200~8295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8300~8395 */ + 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, /* 8400~8495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8500~8595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8600~8695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8700~8795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8800~8895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8900~8995 */ + 0x0000, 0x0000, 0x0101, 0x0101, 0x0101, /* 9000~9095 */ + 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, /* 9100~9195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9200~9295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9300~9395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9400~9495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9500~9595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9600~9695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, /* 9700~9795 */ + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, /* 9800~9895 */ + 0x0101, 0x0101, 0x0001, 0x0000, 0x0000, /* 9900~9995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10000~10095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10100~10195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10200~10295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10300~10395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10400~10495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10500~10595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, /* 10600~10695 */ + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, /* 10700~10795 */ + 0x0001 /* 10800 */ +}; + +static const unsigned short mt6635_TDD_Mask[] = { + 0x0001, 0x0010, 0x0100, 0x1000 +}; + +/* return value: 0, not a de-sense channel; 1, this is a de-sense channel; else error no */ +static signed int mt6635_is_dese_chan(unsigned short freq) +{ + signed int size; + + if (1 == HQA_ZERO_DESENSE_MAP) /*HQA only :skip desense channel check. */ + return 0; + + size = ARRAY_SIZE(mt6635_scan_dese_list); + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + while (size) { + if (mt6635_scan_dese_list[size - 1] == freq) + return 1; + + size--; + } + + return 0; +} + +/* return value: +*1, is desense channel and rssi is less than threshold; +*0, not desense channel or it is but rssi is more than threshold. +*/ +static signed int mt6635_desense_check(unsigned short freq, signed int rssi) +{ + if (mt6635_is_dese_chan(freq)) { + if (rssi < fm_config.rx_cfg.desene_rssi_th) + return 1; + + WCN_DBG(FM_DBG | CHIP, "desen_rssi %d th:%d\n", rssi, fm_config.rx_cfg.desene_rssi_th); + } + return 0; +} + +static bool mt6635_TDD_chan_check(unsigned short freq) +{ + unsigned int i = 0; + unsigned short freq_tmp = freq; + signed int ret = 0; + + ret = fm_get_channel_space(freq_tmp); + if (ret == 0) + freq_tmp *= 10; + else if (ret == -1) + return false; + + i = (freq_tmp - 6500) / 5; + if ((i / 4) >= ARRAY_SIZE(mt6635_TDD_list)) { + WCN_DBG(FM_ERR | CHIP, "Freq index out of range(%d),max(%zd)\n", + i / 4, ARRAY_SIZE(mt6635_TDD_list)); + return false; + } + + if (mt6635_TDD_list[i / 4] & mt6635_TDD_Mask[i % 4]) { + WCN_DBG(FM_DBG | CHIP, "Freq %d use TDD solution\n", freq); + return true; + } else + return false; +} + +/* get channel parameter, HL side/ FA / ATJ */ +static unsigned short mt6635_chan_para_get(unsigned short freq) +{ + signed int pos, size; + + if (1 == HQA_RETURN_ZERO_MAP) { + WCN_DBG(FM_NTC | CHIP, "HQA_RETURN_ZERO_CHAN mt6635_chan_para_map enabled!\n"); + return 0; + } + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + if (freq < 6500) + return 0; + + pos = (freq - 6500) / 5; + + size = ARRAY_SIZE(mt6635_chan_para_map); + + pos = (pos > (size - 1)) ? (size - 1) : pos; + + return mt6635_chan_para_map[pos]; +} + + +static bool mt6635_SPI_hopping_check(unsigned short freq) +{ + signed int size; + + size = ARRAY_SIZE(mt6635_SPI_hopping_list); + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + while (size) { + if (mt6635_SPI_hopping_list[size - 1] == freq) + return 1; + size--; + } + + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/pub/mt6635_fm_lib.c b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/pub/mt6635_fm_lib.c new file mode 100644 index 00000000000000..f7429058a9a652 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/pub/mt6635_fm_lib.c @@ -0,0 +1,2077 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ +#include <linux/slab.h> +#include <linux/vmalloc.h> + +#include "osal_typedef.h" +#include "stp_exp.h" +#include "wmt_exp.h" + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_patch.h" +#include "fm_utils.h" +#include "fm_link.h" +#include "fm_config.h" +#include "fm_cmd.h" + +#include "mt6635_fm_reg.h" +#include "mt6635_fm_lib.h" + +#define HQA_RETURN_ZERO_MAP 0 +#define HQA_ZERO_DESENSE_MAP 0 + +/* #include "mach/mt_gpio.h" */ + +/* #define MT6635_FM_PATCH_PATH "/etc/firmware/mt6635/mt6635_fm_patch.bin" */ +/* #define MT6635_FM_COEFF_PATH "/etc/firmware/mt6635/mt6635_fm_coeff.bin" */ +/* #define MT6635_FM_HWCOEFF_PATH "/etc/firmware/mt6635/mt6635_fm_hwcoeff.bin" */ +/* #define MT6635_FM_ROM_PATH "/etc/firmware/mt6635/mt6635_fm_rom.bin" */ + +static struct fm_patch_tbl mt6635_patch_tbl[5] = { + {FM_ROM_V1, "mt6635_fm_v1_patch.bin", "mt6635_fm_v1_coeff.bin", NULL, NULL}, + {FM_ROM_V2, "mt6635_fm_v2_patch.bin", "mt6635_fm_v2_coeff.bin", NULL, NULL}, + {FM_ROM_V3, "mt6635_fm_v3_patch.bin", "mt6635_fm_v3_coeff.bin", NULL, NULL}, + {FM_ROM_V4, "mt6635_fm_v4_patch.bin", "mt6635_fm_v4_coeff.bin", NULL, NULL}, + {FM_ROM_V5, "mt6635_fm_v5_patch.bin", "mt6635_fm_v5_coeff.bin", NULL, NULL} +}; + +static struct fm_hw_info mt6635_hw_info = { + .chip_id = 0x00006635, + .eco_ver = 0x00000000, + .rom_ver = 0x00000000, + .patch_ver = 0x00000000, + .reserve = 0x00000000, +}; + +unsigned char *cmd_buf; +struct fm_lock *cmd_buf_lock; +struct fm_res_ctx *fm_res; +static struct fm_callback *fm_cb_op; + +/* static signed int Chip_Version = mt6635_E1; */ + +/* static bool rssi_th_set = false; */ + +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ +static struct fm_fifo *cqi_fifo; +#endif +static signed int mt6635_is_dese_chan(unsigned short freq); + +static unsigned short mt6635_chan_para_get(unsigned short freq); +static signed int mt6635_desense_check(unsigned short freq, signed int rssi); +static bool mt6635_TDD_chan_check(unsigned short freq); +static bool mt6635_SPI_hopping_check(unsigned short freq); +static signed int mt6635_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid); + +static signed int mt6635_pwron(signed int data) +{ + if (fm_wcn_ops.ei.wmt_func_on && !fm_wcn_ops.ei.wmt_func_on()) { + WCN_DBG(FM_ERR | CHIP, "WMT turn on FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn on FM OK!\n"); + return 0; +} + +static signed int mt6635_pwroff(signed int data) +{ + if (fm_wcn_ops.ei.wmt_func_off && !fm_wcn_ops.ei.wmt_func_off()) { + WCN_DBG(FM_ERR | CHIP, "WMT turn off FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn off FM OK!\n"); + return 0; +} + +static unsigned short mt6635_get_chipid(void) +{ + return 0x6635; +} + +/* MT6635_SetAntennaType - set Antenna type + * @type - 1, Short Antenna; 0, Long Antenna + */ +static signed int mt6635_SetAntennaType(signed int type) +{ + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | CHIP, "set ana to %s\n", type ? "short" : "long"); + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + + if (type) + dataRead |= ANTENNA_TYPE; + else + dataRead &= (~ANTENNA_TYPE); + + fm_reg_write(FM_MAIN_CG2_CTRL, dataRead); + + return 0; +} + +static signed int mt6635_GetAntennaType(void) +{ + unsigned short dataRead = 0; + + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + WCN_DBG(FM_DBG | CHIP, "get ana type: %s\n", (dataRead & ANTENNA_TYPE) ? "short" : "long"); + + if (dataRead & ANTENNA_TYPE) + return FM_ANA_SHORT; /* short antenna */ + else + return FM_ANA_LONG; /* long antenna */ +} + +static signed int mt6635_Mute(bool mute) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | CHIP, "set %s\n", mute ? "mute" : "unmute"); + /* fm_reg_read(FM_MAIN_CTRL, &dataRead); */ + fm_reg_read(0x9C, &dataRead); + + /* fm_top_reg_write(0x0050, 0x00000007); */ + if (mute == 1) + ret = fm_reg_write(0x9C, (dataRead & 0xFFFC) | 0x0003); + else + ret = fm_reg_write(0x9C, (dataRead & 0xFFFC)); + + /* fm_top_reg_write(0x0050, 0x0000000F); */ + + return ret; +} + +static signed int mt6635_rampdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + + /* A1. Clear DSP state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF0, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* A2. Set DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFFF, RAMP_DOWN, &buf[pkt_size], buf_size - pkt_size); + /* @Wait for STC_DONE interrupt@ */ + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size], + buf_size - pkt_size); + /* A6. Clear DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, (~RAMP_DOWN), 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* A7. Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6635_rampdown - f/w will wait for STC_DONE interrupt + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6635_rampdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_rampdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_RAMPDOWN_OPCODE, pkt_size); +} + +/* FMSYS Ramp Down Sequence*/ +static signed int mt6635_RampDown(void) +{ + signed int ret = 0; + unsigned int tem = 0; + unsigned short pkt_size; + /* unsigned short tmp; */ + + WCN_DBG(FM_DBG | CHIP, "ramp down\n"); + + /* switch SPI clock to 26MHz */ + ret = fm_host_reg_read(0x81026004, &tem); /* Set 0x81026004[0] = 0x0 */ + tem = tem & 0xFFFFFFFE; + ret = fm_host_reg_write(0x81026004, tem); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "RampDown Switch SPI clock to 26MHz failed\n"); + return ret; + } + WCN_DBG(FM_DBG | CHIP, "RampDown Switch SPI clock to 26MHz\n"); + + /* unlock 64M */ + ret = fm_host_reg_read(0x80023008, &tem); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: unlock 64M reg 0x80026000 failed\n", __func__); + ret = fm_host_reg_write(0x80023008, tem & (~(0x1 << 21))); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: unlock 64M failed\n", __func__); + + /* A0.0 Host control RF register */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /*Set 0x60 [D3:D0] = 0x7*/ + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down HOST control rf: Set 0x60 [D3:D0] = 0x7 failed\n"); + return ret; + } + + /* A0.1 Update FM ADPLL fast tracking mode gain */ + ret = fm_set_bits(0x0F, 0x0000, 0xF800); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down ADPLL gainA/B: Set 0xFH [D10:D0] = 0x000 failed\n"); + return ret; + } + + /* A0.2 Host control RF register */ + ret = fm_set_bits(0x60, 0x000F, 0xFFF0); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down Host control RF registerwr top 0x60 failed\n"); + return ret; + } + /* A1. Clear dsp state*/ + ret = fm_set_bits(0x63, 0x0000, 0xFFF0); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down Host control RF registerwr top 0x63 failed\n"); + return ret; + } + /* A2. Set DSP ramp down state*/ + ret = fm_set_bits(0x63, 0x0010, 0xFFEF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down Host control RF registerwr top 0x63 failed\n"); + return ret; + } + + /* A3. Clear STC_DONE interrupt */ + ret = fm_reg_write(FM_MAIN_INTRMASK, 0x0000); + if (ret) + WCN_DBG(FM_ERR | CHIP, "ramp down clean FM_MAIN_INTRMASK failed\n"); + + ret = fm_reg_write(FM_MAIN_EXTINTRMASK, 0x0000); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down clean FM_MAIN_EXTINTRMASK failed\n"); + return ret; + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6635_rampdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_RAMPDOWN, SW_RETRY_CNT, RAMPDOWN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down failed\n"); + return ret; + } + + ret = fm_reg_write(FM_MAIN_EXTINTRMASK, 0x0021); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down wr FM_MAIN_EXTINTRMASK failed\n"); + return ret; + } + + ret = fm_reg_write(FM_MAIN_INTRMASK, 0x0021); + if (ret) + WCN_DBG(FM_ERR | CHIP, "ramp down wr FM_MAIN_INTRMASK failed\n"); + + return ret; +} + +static signed int mt6635_get_rom_version(void) +{ + unsigned short flag_Romcode = 0; + unsigned short nRomVersion = 0; +#define ROM_CODE_READY 0x0001 + signed int ret = 0; + + /* A1.1 DSP rom code version request enable --- set 0x61 b15=1 */ + fm_set_bits(0x61, 0x8000, 0x7FFF); + + /* A1.2 Release ASIP reset --- set 0x61 b1=1 */ + fm_set_bits(0x61, 0x0002, 0xFFFD); + + /* A1.3 Enable ASIP power --- set 0x61 b0=0 */ + fm_set_bits(0x61, 0x0000, 0xFFFE); + + /* A1.4 Wait until DSP code version ready --- wait loop 1ms */ + do { + fm_delayus(1000); + ret = fm_reg_read(0x84, &flag_Romcode); + /* ret=-4 means signal got when control FM. usually get sig 9 to kill FM process. */ + /* now cancel FM power up sequence is recommended. */ + if (ret) + return ret; + + WCN_DBG(FM_DBG | CHIP, "ROM_CODE_READY flag 0x84=%x\n", flag_Romcode); + } while (flag_Romcode != ROM_CODE_READY); + + + /* A1.5 Read FM DSP code version --- rd 0x83[15:8] */ + fm_reg_read(0x83, &nRomVersion); + nRomVersion = (nRomVersion >> 8); + + /* A1.6 DSP rom code version request disable --- set 0x61 b15=0 */ + fm_set_bits(0x61, 0x0000, 0x7FFF); + + /* A1.7 Reset ASIP --- set 0x61[1:0] = 1 */ + fm_set_bits(0x61, 0x0001, 0xFFFC); + + return (signed int) nRomVersion; +} + +static signed int mt6635_pwrup_clock_on_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + unsigned short de_emphasis; + /* unsigned short osc_freq; */ + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + de_emphasis = fm_config.rx_cfg.deemphasis; + de_emphasis &= 0x0001; /* rang 0~1 */ + /* 2,turn on top clock */ + pkt_size += fm_bop_top_write(0xA00, 0xFFFFFFFF, &buf[pkt_size], buf_size - pkt_size); + /* wr top cr a00 ffffffff */ + + /* 3,enable MTCMOS */ + pkt_size += fm_bop_top_write(0x160, 0x00000030, &buf[pkt_size], buf_size - pkt_size); + /* wr top 160 30 */ + + pkt_size += fm_bop_top_write(0x160, 0x00000035, &buf[pkt_size], buf_size - pkt_size); + /* wr top 160 35 */ + pkt_size += fm_bop_udelay(10, &buf[pkt_size], buf_size - pkt_size); + /* delay 10us */ + pkt_size += fm_bop_top_write(0x160, 0x00000015, &buf[pkt_size], buf_size - pkt_size); + /* wr top 160 15 */ + pkt_size += fm_bop_top_write(0x160, 0x00000005, &buf[pkt_size], buf_size - pkt_size); + /* wr top 160 5 */ + + pkt_size += fm_bop_udelay(10, &buf[pkt_size], buf_size - pkt_size); + /* delay 10us */ + pkt_size += fm_bop_top_write(0x160, 0x00000045, &buf[pkt_size], buf_size - pkt_size); + /* wr top 160 45 */ + + /* 4,set comspi fm slave dumy count */ + pkt_size += fm_bop_write(0x7f, 0x801f, &buf[pkt_size], buf_size - pkt_size); /* wr 7f 801f */ + + /* A. FM digital clock enable */ + /* A1. Wait 3ms */ + pkt_size += fm_bop_udelay(3000, &buf[pkt_size], buf_size - pkt_size); + + /* A2. Release HW clock gating*/ + pkt_size += fm_bop_write(0x60, 0x0007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 7 */ + /* A3. Enable DSP auto clock gating */ + pkt_size += fm_bop_write(0x70, 0x0040, &buf[pkt_size], buf_size - pkt_size); /* wr 70 0040 */ + /* A4. Deemphasis setting: Set 0 for 50us, Set 1 for 75us */ + pkt_size += fm_bop_modify(0x61, ~DE_EMPHASIS, (de_emphasis << 12), &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6635_pwrup_clock_on - Wholechip FM Power Up: step 1, FM Digital Clock enable + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6635_pwrup_clock_on(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_pwrup_clock_on_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6635_pwrup_digital_init_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* Part D FM RF&ADPLL divider setting */ + + /* D2.1 set cell mode */ + /* wr 30 D3:D2 00:FDD(default),01:both.10: TDD, 11 FDD */ + /* pkt_size += fm_bop_modify(0x30, 0xFFF3, 0x0000, &buf[pkt_size], buf_size - pkt_size); */ + + /* D2.2 set ADPLL divider */ + pkt_size += fm_bop_write(0x21, 0xE000, &buf[pkt_size], buf_size - pkt_size); /* wr 21 E000 */ + /* D2.3 set SDM coeff0_H */ + pkt_size += fm_bop_write(0xD8, 0x03F0, &buf[pkt_size], buf_size - pkt_size); /* wr D8 0x03F0 */ + /* D2.4 set SDM coeff0_L */ + pkt_size += fm_bop_write(0xD9, 0x3F04, &buf[pkt_size], buf_size - pkt_size); /* wr D9 0x3F04 */ + /* D2.5 set SDM coeff1_H */ + pkt_size += fm_bop_write(0xDA, 0x0014, &buf[pkt_size], buf_size - pkt_size); /* wr DA 0x0014 */ + /* D2.6 set SDM coeff1_L */ + pkt_size += fm_bop_write(0xDB, 0x2A38, &buf[pkt_size], buf_size - pkt_size); /* wr DB 0x2A38 */ + /* D2.7 set 26M clock */ + pkt_size += fm_bop_write(0x23, 0x4000, &buf[pkt_size], buf_size - pkt_size); /* wr 23 4000 */ + + /* Part E: FM Digital Init: fm_rgf_maincon */ + + /* E4. Set appropriate interrupt mask behavior as desired */ + /* Enable stc_done_mask, Enable rgf_rds_mask*/ + pkt_size += fm_bop_write(0x6A, 0x0021, &buf[pkt_size], buf_size - pkt_size); /* wr 6A 0021 */ + pkt_size += fm_bop_write(0x6B, 0x0021, &buf[pkt_size], buf_size - pkt_size); /* wr 6B 0021 */ + + /* E5. Enable hw auto control */ + pkt_size += fm_bop_write(0x60, 0x0000000F, &buf[pkt_size], buf_size - pkt_size); /* wr 60 f */ + + /* E6. Release ASIP reset */ + pkt_size += fm_bop_modify(0x61, 0xFFFD, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D1=1 */ + /* E7. Enable ASIP power */ + pkt_size += fm_bop_modify(0x61, 0xFFFE, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D0=0 */ + + /* E8 */ + pkt_size += fm_bop_udelay(100000, &buf[pkt_size], buf_size - pkt_size); /* delay 100ms */ + /* E9. Check HW initial complete */ + pkt_size += fm_bop_rd_until(0x64, 0x001F, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* Poll 64[0~4] = 2 */ + + return pkt_size - 4; +} + +/* + * mt6635_pwrup_digital_init - Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6635_pwrup_digital_init(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_pwrup_digital_init_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6635_pwrup_fine_tune_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* F1 set host control RF register */ + pkt_size += fm_bop_write(0x60, 0x00000007, &buf[pkt_size], buf_size - pkt_size); + + /* F2 fine tune RF setting */ + pkt_size += fm_bop_write(0x01, 0xBEE8, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x03, 0xF6ED, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x15, 0x0D80, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x16, 0x0068, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x17, 0x092A, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x34, 0x807F, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x35, 0x311E, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x40, 0x0100, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x03, 0xFAF5, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x05, 0x7A80, &buf[pkt_size], buf_size - pkt_size); + + /* F4 set DSP control RF register */ + pkt_size += fm_bop_write(0x60, 0x0000000F, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} + +/* + * mt6635_pwrup_fine_tune - Wholechip FM Power Up: step 5, FM RF fine tune setting + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6635_pwrup_fine_tune(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_pwrup_fine_tune_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6635_pwrdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* A1:set audio output I2S Tx mode: */ + pkt_size += fm_bop_modify(0x9B, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + + /* B0:Disable HW clock control */ + pkt_size += fm_bop_write(0x60, 0x330F, &buf[pkt_size], buf_size - pkt_size); + /* B1:Reset ASIP : Set 0x61, [D1 = 0, D0=1] */ + pkt_size += fm_bop_modify(0x61, 0xFFFD, 0x0001, &buf[pkt_size], buf_size - pkt_size); + + /* B2:digital core + digital rgf reset */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); + + /* B3:Disable all clock */ + pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* B4:Reset rgfrf */ + pkt_size += fm_bop_write(0x60, 0x4000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); + + /* MTCMOS power off */ + /* C0:disable MTCMOS */ + pkt_size += fm_bop_top_write(0x160, 0x0005, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x160, 0x0015, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x160, 0x0035, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_write(0x160, 0x0030, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_top_rd_until(0x160, 0x0000000A, 0x0, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6635_pwrdown - Wholechip FM Power down: Digital Modem Power Down + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6635_pwrdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_pwrdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6635_tune_reg_op(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 4; + + WCN_DBG(FM_ALT | CHIP, "%s enter mt6635_tune function\n", __func__); + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* A2 Enable hardware controlled tuning sequence */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF8, TUNE, &buf[pkt_size], buf_size - pkt_size);/*Set 0x63 D0=1*/ + /* Wait for STC_DONE interrupt */ + + +#ifdef FM_TUNE_USE_POLL + /* A3 Wait for STC_DONE interrupt */ + /* A4 Wait for STC_DONE interrupt status flag */ + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, + FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); + /* A6 Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); +#endif + + pkt_size += fm_bop_udelay(100000, &buf[pkt_size], buf_size - pkt_size); + WCN_DBG(FM_ALT | CHIP, "mt6635_tune delay 100 ms wait 0x69 to change\n"); + + WCN_DBG(FM_ALT | CHIP, "%s leave mt6635_tune function\n", __func__); + + return pkt_size - 4; +} + +/* + * mt6635_tune - execute tune action, + * @buf - target buf + * @buf_size - buffer size + * @freq - 760 ~ 1080, 100KHz unit + * return package size + */ +static signed int mt6635_tune(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_tune_reg_op(buf, buf_size, freq, chan_para); + return fm_op_seq_combine_cmd(buf, FM_TUNE_OPCODE, pkt_size); +} + +/* + * mt6635_pwrup_DSP_download - execute dsp/coeff patch dl action, + * @patch_tbl - current chip patch table + * return patch dl ok or not + */ +static signed int mt6635_pwrup_DSP_download(struct fm_patch_tbl *patch_tbl) +{ +#define PATCH_BUF_SIZE (4096*6) + signed int ret = 0; + signed int patch_len = 0; + unsigned char *dsp_buf = NULL; + unsigned short tmp_reg = 0; + + if (fm_wcn_ops.ei.wmt_ic_info_get) + mt6635_hw_info.eco_ver = fm_wcn_ops.ei.wmt_ic_info_get(); + WCN_DBG(FM_DBG | CHIP, "ECO version:0x%08x\n", mt6635_hw_info.eco_ver); + + /* Wholechip FM Power Up: step 3, get mt6635 DSP ROM version */ + ret = mt6635_get_rom_version(); + if (ret >= 0) { + mt6635_hw_info.rom_ver = ret; + WCN_DBG(FM_NTC | CHIP, "%s ROM version: v%d\n", __func__, mt6635_hw_info.rom_ver); + } else { + WCN_DBG(FM_ERR | CHIP, "get ROM version failed\n"); + if (ret == -4) + WCN_DBG(FM_ERR | CHIP, "signal got when control FM, usually get sig 9 to kill FM process.\n"); + /* now cancel FM power up sequence is recommended. */ + goto out; + } + + /* Wholechip FM Power Up: step 4 download patch */ + dsp_buf = fm_vmalloc(PATCH_BUF_SIZE); + if (!dsp_buf) { + WCN_DBG(FM_ALT | CHIP, "-ENOMEM\n"); + return -ENOMEM; + } + + patch_len = fm_get_patch_path(mt6635_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_patch_path failed\n"); + ret = patch_len; + goto out; + } + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_PATCH); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " DL DSPpatch failed\n"); + goto out; + } + + patch_len = fm_get_coeff_path(mt6635_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_coeff_path failed\n"); + ret = patch_len; + goto out; + } + + mt6635_hw_info.rom_ver += 1; + + tmp_reg = dsp_buf[38] | (dsp_buf[39] << 8); /* to be confirmed */ + mt6635_hw_info.patch_ver = (signed int) tmp_reg; + WCN_DBG(FM_NTC | CHIP, "Patch version: 0x%08x\n", mt6635_hw_info.patch_ver); + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_COEFFICIENT); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Download DSP coefficient failed\n"); + goto out; + } + + /* Download HWACC coefficient */ + fm_reg_write(0x92, 0x0000); + fm_reg_write(0x90, 0x0040); /* Reset download control */ + fm_reg_write(0x90, 0x0000); /* Disable memory control from host*/ +out: + if (dsp_buf) { + fm_vfree(dsp_buf); + dsp_buf = NULL; + } + return ret; +} +static void mt6635_show_reg(void) +{ + unsigned int host_reg[3] = {0}; + unsigned int debug_reg1[3] = {0}; + unsigned short debug_reg2[3] = {0}; + + fm_host_reg_read(0x8102600C, &host_reg[0]); + fm_host_reg_read(0x81021500, &host_reg[1]); + fm_host_reg_read(0x81021200, &host_reg[2]); + WCN_DBG(FM_ALT | CHIP, + "host read 0x8102600C = 0x%08x, 0x81021500 = 0x%08x, 0x81021200 = 0x%08x\n", + host_reg[0], host_reg[1], host_reg[2]); + + fm_top_reg_read(0x003c, &debug_reg1[0]); + fm_top_reg_read(0x0a18, &debug_reg1[1]); + fm_top_reg_read(0x0160, &debug_reg1[2]); + fm_reg_read(0x7f, &debug_reg2[0]); + fm_reg_read(0x62, &debug_reg2[1]); + fm_reg_read(0x60, &debug_reg2[2]); + WCN_DBG(FM_ALT | CHIP, + "top cr 0x3c = 0x%08x, 0xa18 = 0x%08x, 0x160 = 0x%08x, fmreg 0x7f = 0x%08x, 0x62 = 0x%08x, 0x60 = 0x%08x\n", + debug_reg1[0], debug_reg1[1], debug_reg1[2], debug_reg2[0], debug_reg2[1], debug_reg2[2]); +} + +static signed int mt6635_PowerUp(unsigned short *chip_id, unsigned short *device_id) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short tmp_reg = 0; + unsigned int tem = 0; + unsigned int host_reg = 0; + + if (chip_id == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (device_id == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + WCN_DBG(FM_DBG | CHIP, "pwr on seq......\n"); + + /* Wholechip FM Power Up: step 1, set common SPI parameter */ + ret = fm_host_reg_write(0x8102600C, 0x0000801F); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup set CSPI failed\n"); + return ret; + } + + + /* Set top_clk_en_adie to trigger sleep controller before FM power on */ + ret = fm_host_reg_write(0x81021500, 0x00000003); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup set top_clk_en_adie failed\n"); + return ret; + } + + /* Disable 26M crystal sleep */ + fm_host_reg_read(0x81021200, &tem); /* Set 0x81021200[23] = 0x1 */ + tem = tem | 0x00800000; + fm_host_reg_write(0x81021200, tem); + + /* Enable the power_RG_ready */ + ret = fm_top_reg_read(0x0a18, &host_reg); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "power up read top 0xa18 failed\n"); + return ret; + } + ret = fm_top_reg_write(0x0a18, host_reg | (0x3 << 26)); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "power up write top 0xa18 failed\n"); + return ret; + } + + /* Enable the buffer to top digital domain */ + ret = fm_top_reg_read(0x0a18, &host_reg); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "power up read top 0xa18 failed\n"); + return ret; + } + ret = fm_top_reg_write(0x0a18, host_reg | (0x1f << 25)); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "power up write top 0xa18 failed\n"); + return ret; + } + + /* Enable the buffer to FM RF domain */ + ret = fm_top_reg_read(0x0a18, &host_reg); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "power up read top 0xa18 failed\n"); + return ret; + } + ret = fm_top_reg_write(0x0a18, host_reg | (0x01 << 12)); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "power up write top 0xa18 failed\n"); + return ret; + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + + pkt_size = mt6635_pwrup_clock_on(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6635_pwrup_clock_on failed\n"); + return ret; + } + + /* Wholechip FM Power Up: step 2, read HW version */ + mt6635_show_reg(); + fm_reg_read(0x62, &tmp_reg); + /* chip_id = tmp_reg; */ + if (tmp_reg == 0x6635) + *chip_id = 0x6635; + *device_id = tmp_reg; + mt6635_hw_info.chip_id = (signed int) tmp_reg; + WCN_DBG(FM_DBG | CHIP, "chip_id:0x%04x\n", tmp_reg); + + if ((mt6635_hw_info.chip_id != 0x6635)) { + mt6635_show_reg(); + WCN_DBG(FM_NTC | CHIP, "fm sys error, reset hw, chip_id = 0x%08x\n", mt6635_hw_info.chip_id); + return -FM_EFW; + + } + /* Wholechip FM Power Up: step 3, patch download */ + ret = mt6635_pwrup_DSP_download(mt6635_patch_tbl); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6635_pwrup_DSP_download failed\n"); + return ret; + } + + /* Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6635_pwrup_digital_init(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6635_pwrup_digital_init failed\n"); + return ret; + } + + /* Wholechip FM Power Up: step 5, FM RF fine tune setting */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6635_pwrup_fine_tune(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6635_pwrup_fine_tune failed\n"); + return ret; + } + + /* Enable connsys FM 2 wire RX */ + fm_reg_write(0x9B, 0xF9AB); /* G2: Set audio output i2s TX mode */ + fm_host_reg_write(0x81024064, 0x00000014); /* G3: Enable aon_osc_clk_cg */ + fm_host_reg_write(0x81024058, 0x888100C3); /* G4: Enable FMAUD trigger, 20170119 */ + fm_host_reg_write(0x81024054, 0x00000100); /* G5: Release fmsys memory power down*/ + + WCN_DBG(FM_NTC | CHIP, "pwr on seq ok\n"); + + return ret; +} + +static signed int mt6635_PowerDown(void) +{ + signed int ret = 0; + unsigned int tem = 0; + unsigned short pkt_size; + unsigned int host_reg = 0; + /* unsigned int host_reg = 0; */ + + WCN_DBG(FM_DBG | CHIP, "pwr down seq\n"); + + /* A0.1. Disable aon_osc_clk_cg */ + ret = fm_host_reg_write(0x81024064, 0x00000004); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Disable aon_osc_clk_cg failed\n"); + return ret; + } + /* A0.1. Disable FMAUD trigger */ + ret = fm_host_reg_write(0x81024058, 0x88800000); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Disable FMAUD trigger failed\n"); + return ret; + } + + /* A0.1. issue fmsys memory powr down */ + ret = fm_host_reg_write(0x81024054, 0x00000180); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " Issue fmsys memory powr down failed\n"); + return ret; + } + + /*switch SPI clock to 26M*/ + WCN_DBG(FM_DBG | CHIP, "PowerDown: switch SPI clock to 26M\n"); + ret = fm_host_reg_read(0x81026004, &tem); + tem = tem & 0xFFFFFFFE; + ret = fm_host_reg_write(0x81026004, tem); + if (ret) + WCN_DBG(FM_ALT | CHIP, "PowerDown: switch SPI clock to 26M failed\n"); + + /* unlock 64M */ + ret = fm_host_reg_read(0x80023008, &tem); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: unlock 64M reg 0x880023008 failed\n", __func__); + ret = fm_host_reg_write(0x80023008, tem & (~(0x1 << 21))); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: unlock 64M failed\n", __func__); + + /* Enable 26M crystal sleep */ + WCN_DBG(FM_DBG | CHIP, "PowerDown: Enable 26M crystal sleep,Set 0x81021200[23] = 0x0\n"); + ret = fm_host_reg_read(0x81021200, &tem); /* Set 0x81021200[23] = 0x0 */ + tem = tem & 0xFF7FFFFF; + ret = fm_host_reg_write(0x81021200, tem); + + if (ret) + WCN_DBG(FM_ALT | CHIP, "PowerDown: Enable 26M crystal sleep,Set 0x81021200[23] = 0x0 failed\n"); + + /* A0:set audio output I2X Rx mode: */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6635_pwrdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6635_pwrdown failed\n"); + return ret; + } + + /* RF power off */ + /* Disnable the buffer to fm rf domain */ + ret = fm_top_reg_read(0x0a18, &host_reg); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "power down read top 0xa18 failed\n"); + return ret; + } + ret = fm_top_reg_write(0x0a18, host_reg & (~(0x1 << 12))); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "power down write top 0xa18 failed\n"); + return ret; + } + + return ret; +} + +static signed int mt6635_set_freq_fine_tune_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* F3 DCOC @ LNA = 7 */ + pkt_size += fm_bop_write(0x40, 0x01AF, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x03, 0xFAF5, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x07, 0x0100, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x01, 0xEEE8, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x3F, 0x3221, &buf[pkt_size], buf_size - pkt_size); + /* wait 1ms */ + pkt_size += fm_bop_udelay(1000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_rd_until(0x3F, 0x001F, 0x0001, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x3F, 0x0220, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x40, 0x0100, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x01, 0xAEE8, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x30, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x36, 0x017A, &buf[pkt_size], buf_size - pkt_size); + + /* F4 set DSP control RF register */ + pkt_size += fm_bop_write(0x60, 0x0000000F, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} + +/* + * mt6635_set_freq_fine_tune - FM RF fine tune setting + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6635_set_freq_fine_tune(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6635_set_freq_fine_tune_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} +static bool mt6635_SetFreq(unsigned short freq) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short chan_para = 0; + unsigned short freq_reg = 0; + unsigned int reg_val = 0; + unsigned int i = 0; + bool flag_spi_hopping = false; + unsigned short tmp_reg[6] = {0}; + + fm_cb_op->cur_freq_set(freq); + + /* FM VCO Calibration */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /* Set 0x60 [D3:D0] = 0x07*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Host Control RF register 0x60 = 0x7 failed\n", __func__); + + fm_delayus(5); + if (freq >= 750) { + fm_reg_write(0x37, 0xF68C); + fm_reg_write(0x38, 0x0B53); + ret = fm_set_bits(0x30, 0x0014 << 8, 0xC0FF); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x30 failed\n", __func__); + + } else { + fm_reg_write(0x37, 0x0675); + fm_reg_write(0x38, 0x0F54); + ret = fm_set_bits(0x30, 0x001C << 8, 0xC0FF); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x30 failed\n", __func__); + } + ret = fm_set_bits(0x30, 0x0001 << 14, 0xBFFF); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x30 failed\n", __func__); + + fm_reg_write(0x40, 0x010F); + fm_delayus(5); + fm_reg_write(0x36, 0x037A); + fm_reg_write(0x32, 0x8000); + fm_delayus(200); + ret = fm_set_bits(0x3D, 0x0001 << 2, 0xFFFB); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x3D failed\n", __func__); + + fm_reg_write(0x32, 0x0000); + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6635_set_freq_fine_tune(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6635_pwrup_fine_tune failed\n"); + return ret; + } + + /* A0. Host contrl RF register */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /* Set 0x60 [D3:D0] = 0x07*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Host Control RF register 0x60 = 0x7 failed\n", __func__); + + /* A0.1 Update FM ADPLL fast tracking mode gain */ + ret = fm_set_bits(0x0F, 0x0455, 0xF800); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set FM ADPLL gainA/B=0x455 failed\n", __func__); + + /* A0.2 Set FMSYS cell mode */ + if (mt6635_TDD_chan_check(freq)) { + ret = fm_set_bits(0x30, 0x0008, 0xFFF3); /* use TDD solution */ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: freq[%d]: use TDD solution failed\n", __func__, freq); + } else { + ret = fm_set_bits(0x30, 0x0000, 0xFFF3); /* default use FDD solution */ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: freq[%d]: default use FDD solution failed\n", __func__, freq); + } + + /* A0.3 Host control RF register */ + ret = fm_set_bits(0x60, 0x000F, 0xFFF0); /* Set 0x60 [D3:D0] = 0x0F*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x60 [D3:D0] = 0x0F failed\n", __func__); + + /* A1 Get Channel parameter from map list*/ + + chan_para = mt6635_chan_para_get(freq); + WCN_DBG(FM_DBG | CHIP, "%s: %d chan para = %d\n", __func__, (signed int) freq, (signed int) chan_para); + + freq_reg = freq; + if (fm_get_channel_space(freq_reg) == 0) + freq_reg *= 10; + + freq_reg = (freq_reg - 6400) * 2 / 10; + + /*A1 Set rgfrf_chan = XXX*/ + ret = fm_set_bits(0x65, freq_reg, 0xFC00); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "%s: set rgfrf_chan = xxx = %d failed\n", __func__, freq_reg); + return false; + } + + ret = fm_set_bits(0x65, (chan_para << 12), 0x0FFF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x65 failed\n"); + return false; + } + + /* SPI hopping setting*/ + if (mt6635_SPI_hopping_check(freq)) { + WCN_DBG(FM_NTC | CHIP, "%s: freq:%d is SPI hopping channel,turn on 64M PLL\n", __func__, freq); + + /* lock 64M */ + ret = fm_host_reg_read(0x80023008, ®_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M reg 0x80023008 failed\n", __func__); + ret = fm_host_reg_write(0x80023008, reg_val | (0x1 << 21)); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M failed\n", __func__); + + for (i = 0; i < 100; i++) { /*rd 0x80021118 until D27 ==1*/ + + ret = fm_host_reg_read(0x80021118, ®_val); + + if (reg_val & 0x08000000) { + flag_spi_hopping = true; + WCN_DBG(FM_NTC | CHIP, "%s: POLLING PLL_RDY success !\n", __func__); + /* switch SPI clock to 64MHz */ + ret = fm_host_reg_read(0x81026004, ®_val); /* wr 0x81026004[0] 0x1 D0 */ + reg_val |= 0x00000001; + ret = fm_host_reg_write(0x81026004, reg_val); + break; + } + fm_delayus(10); + } + if (false == flag_spi_hopping) + WCN_DBG(FM_ERR | CHIP, "%s: Polling to read rd 0x80021118[27] ==0x1 failed!\n", + __func__); + } + + /* A0. Host contrl RF register */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /* Set 0x60 [D3:D0] = 0x07*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Host Control RF register 0x60 = 0x7 failed\n", __func__); + + + fm_reg_read(0x62, &tmp_reg[0]); + fm_reg_read(0x64, &tmp_reg[1]); + fm_reg_read(0x69, &tmp_reg[2]); + fm_reg_read(0x6a, &tmp_reg[3]); + fm_reg_read(0x6b, &tmp_reg[4]); + fm_reg_read(0x9b, &tmp_reg[5]); + + WCN_DBG(FM_ALT | CHIP, "%s: Before tune--0x62 0x64 0x69 0x6a 0x6b 0x9b = %04x %04x %04x %04x %04x %04x\n", + __func__, + tmp_reg[0], + tmp_reg[1], + tmp_reg[2], + tmp_reg[3], + tmp_reg[4], + tmp_reg[5]); + + /* A0.3 Host control RF register */ + ret = fm_set_bits(0x60, 0x000F, 0xFF00); /* Set 0x60 [D3:D0] = 0x0F*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x60 [D3:D0] = 0x0F failed\n", __func__); + + if (FM_LOCK(cmd_buf_lock)) + return false; + pkt_size = mt6635_tune(cmd_buf, TX_BUF_SIZE, freq, chan_para); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE | FLAG_TUNE_DONE, SW_RETRY_CNT, TUNE_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + + /* A0. Host contrl RF register */ + ret = fm_set_bits(0x60, 0x0007, 0xFFF0); /* Set 0x60 [D3:D0] = 0x07*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Host Control RF register 0x60 = 0x7 failed\n", __func__); + + memset(tmp_reg, 0, sizeof(tmp_reg[0])*6); + + fm_reg_read(0x62, &tmp_reg[0]); + fm_reg_read(0x64, &tmp_reg[1]); + fm_reg_read(0x69, &tmp_reg[2]); + fm_reg_read(0x6a, &tmp_reg[3]); + fm_reg_read(0x6b, &tmp_reg[4]); + fm_reg_read(0x9b, &tmp_reg[5]); + + WCN_DBG(FM_ALT | CHIP, "%s: After tune--0x62 0x64 0x69 0x6a 0x6b 0x9b = %04x %04x %04x %04x %04x %04x\n", + __func__, + tmp_reg[0], + tmp_reg[1], + tmp_reg[2], + tmp_reg[3], + tmp_reg[4], + tmp_reg[5]); + + /* A0.3 Host control RF register */ + ret = fm_set_bits(0x60, 0x000F, 0xFF00); /* Set 0x60 [D3:D0] = 0x0F*/ + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: Set 0x60 [D3:D0] = 0x0F failed\n", __func__); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "%s: mt6635_tune failed\n", __func__); + return false; + } + + WCN_DBG(FM_DBG | CHIP, "%s: set freq to %d ok\n", __func__, freq); +#if 0 + /* ADPLL setting for dbg */ + fm_top_reg_write(0x0050, 0x00000007); + fm_top_reg_write(0x0A08, 0xFFFFFFFF); + mt6635_bt_write(0x82, 0x11); + mt6635_bt_write(0x83, 0x11); + mt6635_bt_write(0x84, 0x11); + fm_top_reg_write(0x0040, 0x1C1C1C1C); + fm_top_reg_write(0x0044, 0x1C1C1C1C); + fm_reg_write(0x70, 0x0010); + /*0x0806 DCO clk + *0x0802 ref clk + *0x0804 feedback clk + */ + fm_reg_write(0xE0, 0x0806); +#endif + return true; +} + +#define FM_CQI_LOG_PATH "/mnt/sdcard/fmcqilog" + +static signed int mt6635_full_cqi_get(signed int min_freq, signed int max_freq, signed int space, signed int cnt) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short freq, orig_freq; + signed int i, j, k; + signed int space_val, max, min, num; + struct mt6635_full_cqi *p_cqi; + unsigned char *cqi_log_title = "Freq, RSSI, PAMD, PR, FPAMD, MR, ATDC, PRX, ATDEV, SMGain, DltaRSSI\n"; + unsigned char cqi_log_buf[100] = { 0 }; + signed int pos; + unsigned char cqi_log_path[100] = { 0 }; + + /* for soft-mute tune, and get cqi */ + freq = fm_cb_op->cur_freq_get(); + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + /* get cqi */ + orig_freq = freq; + if (fm_get_channel_space(min_freq) == 0) + min = min_freq * 10; + else + min = min_freq; + + if (fm_get_channel_space(max_freq) == 0) + max = max_freq * 10; + else + max = max_freq; + + if (space == 0x0001) + space_val = 5; /* 50Khz */ + else if (space == 0x0002) + space_val = 10; /* 100Khz */ + else if (space == 0x0004) + space_val = 20; /* 200Khz */ + else + space_val = 10; + + num = (max - min) / space_val + 1; /* Eg, (8760 - 8750) / 10 + 1 = 2 */ + for (k = 0; (orig_freq == 10000) && (g_dbg_level == 0xffffffff) && (k < cnt); k++) { + WCN_DBG(FM_NTC | CHIP, "cqi file:%d\n", k + 1); + freq = min; + pos = 0; + fm_memcpy(cqi_log_path, FM_CQI_LOG_PATH, strlen(FM_CQI_LOG_PATH)); + sprintf(&cqi_log_path[strlen(FM_CQI_LOG_PATH)], "%d.txt", k + 1); + fm_file_write(cqi_log_path, cqi_log_title, strlen(cqi_log_title), &pos); + for (j = 0; j < num; j++) { + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, + SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + WCN_DBG(FM_NTC | CHIP, "smt cqi size %d\n", fm_res->cqi[0]); + p_cqi = (struct mt6635_full_cqi *)&fm_res->cqi[2]; + for (i = 0; i < fm_res->cqi[1]; i++) { + /* just for debug */ + WCN_DBG(FM_NTC | CHIP, + "%04d, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x,\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* format to buffer */ + sprintf(cqi_log_buf, + "%04d, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x,\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* write back to log file */ + fm_file_write(cqi_log_path, cqi_log_buf, strlen(cqi_log_buf), &pos); + } + } else { + WCN_DBG(FM_ALT | CHIP, "smt get CQI failed\n"); + ret = -1; + } + freq += space_val; + } + fm_cb_op->cur_freq_set(0); /* avoid run too much times */ + } + + return ret; +} + +static unsigned short mt6635_read_dsp_reg(unsigned short addr) +{ + unsigned short regValue = 0; + + fm_reg_write(0x60, 0x07); + fm_reg_write(0xE2, addr); + fm_reg_write(0xE1, 0x01); + fm_reg_read(0xE4, ®Value); + fm_reg_write(0x60, 0x0F); + + return regValue; +} + +static bool mt6635_is_valid_freq(unsigned short freq) +{ + int i = 0; + bool valid = false; + signed int RSSI = 0, PAMD = 0, MR = 0; + unsigned int PRX = 0; + unsigned short softmuteGainLvl = 0; + unsigned short tmp_reg = 0; + + for (i = 0; i < 8; i++) { + fm_reg_read(0x6C, &tmp_reg); + RSSI += (((tmp_reg & 0x03FF) >= 512) ? + ((tmp_reg & 0x03FF) - 1024) : (tmp_reg & 0x03FF)) >> 3; + fm_reg_read(0xB4, &tmp_reg); + PAMD += (((tmp_reg & 0x1FF) >= 256) ? + ((tmp_reg & 0x01FF) - 512) : (tmp_reg & 0x01FF)) >> 3; + tmp_reg = mt6635_read_dsp_reg(0x4E1); + PRX += (tmp_reg & 0x00FF) >> 3; + fm_reg_read(0xBD, &tmp_reg); + MR += (((tmp_reg & 0x01FF) >= 256) ? + ((tmp_reg & 0x01FF) - 512) : (tmp_reg & 0x01FF)) >> 3; + tmp_reg = mt6635_read_dsp_reg(0x2C4); + softmuteGainLvl += tmp_reg >> 3; + fm_delayus(2250); + } + + if ((fm_config.rx_cfg.long_ana_rssi_th <= RSSI) + && (fm_config.rx_cfg.pamd_th >= PAMD) + && (fm_config.rx_cfg.mr_th <= MR) + && (fm_config.rx_cfg.prx_th <= PRX) + && (fm_config.rx_cfg.smg_th <= softmuteGainLvl)) { + valid = true; + } + + WCN_DBG(FM_DBG | CHIP, + "freq %d valid=%d, %d, %d, 0x%04x, 0x%04x, 0x%04x\n", + freq, valid, RSSI, PAMD, PRX, MR, softmuteGainLvl); + + return valid; +} + +/* + * mt6635_GetCurRSSI - get current freq's RSSI value + * RS=RSSI + * If RS>511, then RSSI(dBm)= (RS-1024)/16*6 + * else RSSI(dBm)= RS/16*6 + */ +static signed int mt6635_GetCurRSSI(signed int *pRSSI) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RSSI_IND, &tmp_reg); + tmp_reg = tmp_reg & 0x03ff; + + if (pRSSI) { + *pRSSI = (tmp_reg > 511) ? (((tmp_reg - 1024) * 6) >> 4) : ((tmp_reg * 6) >> 4); + WCN_DBG(FM_DBG | CHIP, "rssi:%d, dBm:%d\n", tmp_reg, *pRSSI); + } else { + WCN_DBG(FM_ERR | CHIP, "get rssi para error\n"); + return -FM_EPARA; + } + + return 0; +} + +static unsigned short mt6635_vol_tbl[16] = { 0x0000, 0x0519, 0x066A, 0x0814, + 0x0A2B, 0x0CCD, 0x101D, 0x1449, + 0x198A, 0x2027, 0x287A, 0x32F5, + 0x4027, 0x50C3, 0x65AD, 0x7FFF +}; + +static signed int mt6635_SetVol(unsigned char vol) +{ + signed int ret = 0; + + vol = (vol > 15) ? 15 : vol; + ret = fm_reg_write(0x7D, mt6635_vol_tbl[vol]); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "Set vol=%d Failed\n", vol); + return ret; + } + WCN_DBG(FM_DBG | CHIP, "Set vol=%d OK\n", vol); + + + if (vol == 10) { + fm_print_cmd_fifo(); /* just for debug */ + fm_print_evt_fifo(); + } + return 0; +} + +static signed int mt6635_GetVol(unsigned char *pVol) +{ + int ret = 0; + unsigned short tmp = 0; + signed int i; + + if (pVol == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + ret = fm_reg_read(0x7D, &tmp); + if (ret) { + *pVol = 0; + WCN_DBG(FM_ERR | CHIP, "Get vol Failed\n"); + return ret; + } + + for (i = 0; i < 16; i++) { + if (mt6635_vol_tbl[i] == tmp) { + *pVol = i; + break; + } + } + + WCN_DBG(FM_DBG | CHIP, "Get vol=%d OK\n", *pVol); + return 0; +} + +static signed int mt6635_dump_reg(void) +{ + signed int i; + unsigned short TmpReg = 0; + + for (i = 0; i < 0xff; i++) { + fm_reg_read(i, &TmpReg); + WCN_DBG(FM_NTC | CHIP, "0x%02x=0x%04x\n", i, TmpReg); + } + return 0; +} + +/*0:mono, 1:stereo*/ +static bool mt6635_GetMonoStereo(unsigned short *pMonoStereo) +{ +#define FM_BF_STEREO 0x1000 + unsigned short TmpReg = 0; + + if (pMonoStereo) { + fm_reg_read(FM_RSSI_IND, &TmpReg); + *pMonoStereo = (TmpReg & FM_BF_STEREO) >> 12; + } else { + WCN_DBG(FM_ERR | CHIP, "MonoStero: para err\n"); + return false; + } + + WCN_DBG(FM_NTC | CHIP, "Get MonoStero:0x%04x\n", *pMonoStereo); + return true; +} + +static signed int mt6635_SetMonoStereo(signed int MonoStereo) +{ + signed int ret = 0; + + WCN_DBG(FM_NTC | CHIP, "set to %s\n", MonoStereo ? "mono" : "auto"); + fm_reg_write(0x60, 0x0007); + + if (MonoStereo) /*mono */ + ret = fm_set_bits(0x75, 0x0008, ~0x0008); + else + ret = fm_set_bits(0x75, 0x0000, ~0x0008); + + fm_reg_write(0x60, 0x000F); + return ret; +} + +static signed int mt6635_GetCapArray(signed int *ca) +{ + unsigned short dataRead = 0; + unsigned short tmp = 0; + + if (ca == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_reg_read(0x60, &tmp); + fm_reg_write(0x60, tmp & 0xFFF7); /* 0x60 D3=0 */ + + fm_reg_read(0x26, &dataRead); + *ca = dataRead; + + fm_reg_write(0x60, tmp); /* 0x60 D3=1 */ + return 0; +} + +/* + * mt6635_GetCurPamd - get current freq's PAMD value + * PA=PAMD + * If PA>511 then PAMD(dB)= (PA-1024)/16*6, + * else PAMD(dB)=PA/16*6 + */ +static bool mt6635_GetCurPamd(unsigned short *pPamdLevl) +{ + unsigned short tmp_reg = 0; + unsigned short dBvalue, valid_cnt = 0; + int i, total = 0; + + for (i = 0; i < 8; i++) { + if (fm_reg_read(FM_ADDR_PAMD, &tmp_reg)) { + *pPamdLevl = 0; + return false; + } + + tmp_reg &= 0x03FF; + dBvalue = (tmp_reg > 256) ? ((512 - tmp_reg) * 6 / 16) : 0; + if (dBvalue != 0) { + total += dBvalue; + valid_cnt++; + WCN_DBG(FM_DBG | CHIP, "[%d]PAMD=%d\n", i, dBvalue); + } + fm_delayms(3); + } + if (valid_cnt != 0) + *pPamdLevl = total / valid_cnt; + else + *pPamdLevl = 0; + + WCN_DBG(FM_NTC | CHIP, "PAMD=%d\n", *pPamdLevl); + return true; +} + +static signed int mt6635_i2s_info_get(signed int *ponoff, signed int *pmode, signed int *psample) +{ + if (ponoff == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (pmode == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (psample == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + *ponoff = fm_config.aud_cfg.i2s_info.status; + *pmode = fm_config.aud_cfg.i2s_info.mode; + *psample = fm_config.aud_cfg.i2s_info.rate; + + return 0; +} + +static signed int mt6635_get_audio_info(struct fm_audio_info_t *data) +{ + memcpy(data, &fm_config.aud_cfg, sizeof(struct fm_audio_info_t)); + return 0; +} + +static signed int mt6635_hw_info_get(struct fm_hw_info *req) +{ + if (req == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + req->chip_id = mt6635_hw_info.chip_id; + req->eco_ver = mt6635_hw_info.eco_ver; + req->patch_ver = mt6635_hw_info.patch_ver; + req->rom_ver = mt6635_hw_info.rom_ver; + + return 0; +} + +static signed int mt6635_pre_search(void) +{ + mt6635_RampDown(); + /* disable audio output I2S Rx mode */ + fm_host_reg_write(0x80101054, 0x00000000); + /* disable audio output I2S Tx mode */ + fm_reg_write(0x9B, 0x0000); + + return 0; +} + +static signed int mt6635_restore_search(void) +{ + mt6635_RampDown(); + /* set audio output I2S Tx mode */ + fm_reg_write(0x9B, 0xF9AB); + /* set audio output I2S Rx mode */ + fm_host_reg_write(0x80101054, 0x00003f35); + return 0; +} + +static signed int mt6635_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid) +{ + signed int ret = 0; + signed int i = 0; + unsigned short pkt_size; + unsigned int reg_val = 0; + bool flag_spi_hopping = false; + struct mt6635_full_cqi *p_cqi; + signed int RSSI = 0, PAMD = 0, MR = 0, ATDC = 0; + unsigned int PRX = 0, ATDEV = 0; + unsigned short softmuteGainLvl = 0; + + /* Set rgf_host2dsp_reserve[2] = 1 */ + WCN_DBG(FM_NTC | CHIP, "start %s\n", __func__); + + ret = mt6635_chan_para_get(freq); + if (ret == 2) + ret = fm_set_bits(FM_CHANNEL_SET, 0x2000, 0x0FFF); /* mdf HiLo */ + else + ret = fm_set_bits(FM_CHANNEL_SET, 0x0000, 0x0FFF); /* clear FA/HL/ATJ */ + + /* SPI hopping setting*/ + if (mt6635_SPI_hopping_check(freq)) { + WCN_DBG(FM_NTC | CHIP, "%s: freq:%d is SPI hopping channel,turn on 64M PLL\n", __func__, freq); + + /* lock 64M */ + ret = fm_host_reg_read(0x80023008, ®_val); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M reg 0x80023008 failed\n", __func__); + ret = fm_host_reg_write(0x80023008, reg_val | (0x1 << 21)); + if (ret) + WCN_DBG(FM_ERR | CHIP, "%s: lock 64M failed\n", __func__); + + for (i = 0; i < 100; i++) { /*rd 0x80021118 until D27 ==1*/ + + ret = fm_host_reg_read(0x80021118, ®_val); + + if (reg_val & 0x08000000) { + flag_spi_hopping = true; + WCN_DBG(FM_NTC | CHIP, "%s: POLLING PLL_RDY success !\n", __func__); + /* switch SPI clock to 64MHz */ + ret = fm_host_reg_read(0x81026004, ®_val); /* wr 0x81026004[0] 0x1 D0 */ + reg_val |= 0x00000001; + ret = fm_host_reg_write(0x81026004, reg_val); + break; + } + fm_delayus(100); + } + if (false == flag_spi_hopping) + WCN_DBG(FM_ERR | CHIP, "%s: Polling to read rd 0x80021118[27] ==0x1 failed !\n", __func__); + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + p_cqi = (struct mt6635_full_cqi *)&fm_res->cqi[2]; + /* just for debug */ + WCN_DBG(FM_NTC | CHIP, + "freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", + p_cqi->ch, p_cqi->rssi, p_cqi->pamd, p_cqi->pr, p_cqi->fpamd, p_cqi->mr, + p_cqi->atdc, p_cqi->prx, p_cqi->atdev, p_cqi->smg, p_cqi->drssi); + RSSI = ((p_cqi->rssi & 0x03FF) >= 512) ? ((p_cqi->rssi & 0x03FF) - 1024) : (p_cqi->rssi & 0x03FF); + PAMD = ((p_cqi->pamd & 0x1FF) >= 256) ? ((p_cqi->pamd & 0x01FF) - 512) : (p_cqi->pamd & 0x01FF); + MR = ((p_cqi->mr & 0x01FF) >= 256) ? ((p_cqi->mr & 0x01FF) - 512) : (p_cqi->mr & 0x01FF); + ATDC = (p_cqi->atdc >= 32768) ? (65536 - p_cqi->atdc) : (p_cqi->atdc); + if (ATDC < 0) + ATDC = (~(ATDC)) - 1; /* Get abs value of ATDC */ + + PRX = (p_cqi->prx & 0x00FF); + ATDEV = p_cqi->atdev; + softmuteGainLvl = p_cqi->smg; + /* check if the channel is valid according to each CQIs */ + if ((fm_config.rx_cfg.long_ana_rssi_th <= RSSI) + && (fm_config.rx_cfg.pamd_th >= PAMD) + && (fm_config.rx_cfg.atdc_th >= ATDC) + && (fm_config.rx_cfg.mr_th <= MR) + && (fm_config.rx_cfg.prx_th <= PRX) + && (ATDEV >= ATDC) /* sync scan algorithm */ + && (fm_config.rx_cfg.smg_th <= softmuteGainLvl)) { + *valid = true; + } else { + *valid = false; + } + *rssi = RSSI; + } else { + WCN_DBG(FM_ALT | CHIP, "smt get CQI failed\n"); + return false; + } + WCN_DBG(FM_NTC | CHIP, "valid=%d\n", *valid); + return true; +} + +static bool mt6635_em_test(unsigned short group_idx, unsigned short item_idx, unsigned int item_value) +{ + return true; +} + +/* +*parm: +* parm.th_type: 0, RSSI. 1, desense RSSI. 2, SMG. +* parm.th_val: threshold value +*/ +static signed int mt6635_set_search_th(signed int idx, signed int val, signed int reserve) +{ + switch (idx) { + case 0: { + fm_config.rx_cfg.long_ana_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set rssi th =%d\n", val); + break; + } + case 1: { + fm_config.rx_cfg.desene_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set desense rssi th =%d\n", val); + break; + } + case 2: { + fm_config.rx_cfg.smg_th = val; + WCN_DBG(FM_NTC | CHIP, "set smg th =%d\n", val); + break; + } + default: + break; + } + return 0; +} + +static signed int MT6635_low_power_wa_default(signed int fmon) +{ + return 0; +} + +signed int fm_low_ops_register(struct fm_callback *cb, struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,bi invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_get == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_get invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_set == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_set invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_cb_op = cb; + + bi->pwron = mt6635_pwron; + bi->pwroff = mt6635_pwroff; + bi->chipid_get = mt6635_get_chipid; + bi->mute = mt6635_Mute; + bi->rampdown = mt6635_RampDown; + bi->pwrupseq = mt6635_PowerUp; + bi->pwrdownseq = mt6635_PowerDown; + bi->setfreq = mt6635_SetFreq; + bi->low_pwr_wa = MT6635_low_power_wa_default; + bi->get_aud_info = mt6635_get_audio_info; + bi->rssiget = mt6635_GetCurRSSI; + bi->volset = mt6635_SetVol; + bi->volget = mt6635_GetVol; + bi->dumpreg = mt6635_dump_reg; + bi->msget = mt6635_GetMonoStereo; + bi->msset = mt6635_SetMonoStereo; + bi->pamdget = mt6635_GetCurPamd; + bi->em = mt6635_em_test; + bi->anaswitch = mt6635_SetAntennaType; + bi->anaget = mt6635_GetAntennaType; + bi->caparray_get = mt6635_GetCapArray; + bi->hwinfo_get = mt6635_hw_info_get; + bi->i2s_get = mt6635_i2s_info_get; + bi->is_dese_chan = mt6635_is_dese_chan; + bi->softmute_tune = mt6635_soft_mute_tune; + bi->desense_check = mt6635_desense_check; + bi->cqi_log = mt6635_full_cqi_get; + bi->pre_search = mt6635_pre_search; + bi->restore_search = mt6635_restore_search; + bi->set_search_th = mt6635_set_search_th; + bi->is_valid_freq = mt6635_is_valid_freq; + + cmd_buf_lock = fm_lock_create("31_cmd"); + ret = fm_lock_get(cmd_buf_lock); + + cmd_buf = fm_zalloc(TX_BUF_SIZE + 1); + + if (!cmd_buf) { + WCN_DBG(FM_ALT | CHIP, "6635 fm lib alloc tx buf failed\n"); + ret = -1; + } +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ + cqi_fifo = fm_fifo_create("6628_cqi_fifo", sizeof(struct adapt_fm_cqi), 640); + if (!cqi_fifo) { + WCN_DBG(FM_ALT | CHIP, "6635 fm lib create cqi fifo failed\n"); + ret = -1; + } +#endif + + return ret; +} + +signed int fm_low_ops_unregister(struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,bi invalid pointer\n", __func__); + return -FM_EPARA; + } + +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ + fm_fifo_release(cqi_fifo); +#endif + + if (cmd_buf) { + fm_free(cmd_buf); + cmd_buf = NULL; + } + + ret = fm_lock_put(cmd_buf_lock); + fm_memset(bi, 0, sizeof(struct fm_basic_interface)); + + fm_cb_op = NULL; + + return ret; +} + +static const signed char mt6635_chan_para_map[] = { +/* 0, X, 1, X, 2, X, 3, X, 4, X, 5, X, 6, X, 7, X, 8, X, 9, X*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, /* 6500~6595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6600~6695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, /* 6700~6795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6800~6895 */ + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6900~6995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7000~7095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7100~7195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, /* 7200~7295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7300~7395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 7400~7495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7500~7595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, /* 7600~7695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7700~7795 */ + 8, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7800~7895 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7900~7995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8000~8095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8100~8195 */ + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8200~8295 */ + 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, /* 8300~8395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8400~8495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8500~8595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8600~8695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8700~8795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8800~8895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8900~8995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9000~9095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9100~9195 */ + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9200~9295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9300~9395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9400~9495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9500~9595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9600~9695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9700~9795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, /* 9800~9895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 9900~9995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10000~10095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10100~10195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10200~10295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10300~10395 */ + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10400~10495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, /* 10500~10595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10600~10695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, /* 10700~10795 */ + 0 /* 10800 */ +}; +static const unsigned short mt6635_scan_dese_list[] = { + 6910, 6920, 7680, 7800, 8450, 9210, 9220, 9230, 9590, 9600, 9830, 9900, 9980, 9990, 10400, 10750, 10760 +}; + +static const unsigned short mt6635_SPI_hopping_list[] = { + 6510, 6520, 6530, 7780, 7790, 7800, 7810, 7820, 9090, 9100, 9110, 9120, 10380, 10390, 10400, 10410, 10420 +}; + +static const unsigned short mt6635_I2S_hopping_list[] = { + 6550, 6760, 6960, 6970, 7170, 7370, 7580, 7780, 7990, 8810, 9210, 9220, 10240 +}; + +static const unsigned short mt6635_TDD_list[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6500~6595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6600~6695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6700~6795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6800~6895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6900~6995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7000~7095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7100~7195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7200~7295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7300~7395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7400~7495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7500~7595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7600~7695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7700~7795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7800~7895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7900~7995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8000~8095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8100~8195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8200~8295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8300~8395 */ + 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, /* 8400~8495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8500~8595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8600~8695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8700~8795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8800~8895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8900~8995 */ + 0x0000, 0x0000, 0x0101, 0x0101, 0x0101, /* 9000~9095 */ + 0x0101, 0x0000, 0x0000, 0x0000, 0x0000, /* 9100~9195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9200~9295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9300~9395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9400~9495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9500~9595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9600~9695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, /* 9700~9795 */ + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, /* 9800~9895 */ + 0x0101, 0x0101, 0x0001, 0x0000, 0x0000, /* 9900~9995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10000~10095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10100~10195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10200~10295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10300~10395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10400~10495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10500~10595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, /* 10600~10695 */ + 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, /* 10700~10795 */ + 0x0001 /* 10800 */ +}; + +static const unsigned short mt6635_TDD_Mask[] = { + 0x0001, 0x0010, 0x0100, 0x1000 +}; + +/* return value: 0, not a de-sense channel; 1, this is a de-sense channel; else error no */ +static signed int mt6635_is_dese_chan(unsigned short freq) +{ + signed int size; + + if (1 == HQA_ZERO_DESENSE_MAP) /*HQA only :skip desense channel check. */ + return 0; + + size = ARRAY_SIZE(mt6635_scan_dese_list); + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + while (size) { + if (mt6635_scan_dese_list[size - 1] == freq) + return 1; + + size--; + } + + return 0; +} + +/* return value: +*1, is desense channel and rssi is less than threshold; +*0, not desense channel or it is but rssi is more than threshold. +*/ +static signed int mt6635_desense_check(unsigned short freq, signed int rssi) +{ + if (mt6635_is_dese_chan(freq)) { + if (rssi < fm_config.rx_cfg.desene_rssi_th) + return 1; + + WCN_DBG(FM_DBG | CHIP, "desen_rssi %d th:%d\n", rssi, fm_config.rx_cfg.desene_rssi_th); + } + return 0; +} + +static bool mt6635_TDD_chan_check(unsigned short freq) +{ + unsigned int i = 0; + unsigned short freq_tmp = freq; + signed int ret = 0; + + ret = fm_get_channel_space(freq_tmp); + if (ret == 0) + freq_tmp *= 10; + else if (ret == -1) + return false; + + i = (freq_tmp - 6500) / 5; + if ((i / 4) >= ARRAY_SIZE(mt6635_TDD_list)) { + WCN_DBG(FM_ERR | CHIP, "Freq index out of range(%d),max(%zd)\n", + i / 4, ARRAY_SIZE(mt6635_TDD_list)); + return false; + } + + if (mt6635_TDD_list[i / 4] & mt6635_TDD_Mask[i % 4]) { + WCN_DBG(FM_DBG | CHIP, "Freq %d use TDD solution\n", freq); + return true; + } else + return false; +} + +/* get channel parameter, HL side/ FA / ATJ */ +static unsigned short mt6635_chan_para_get(unsigned short freq) +{ + signed int pos, size; + + if (1 == HQA_RETURN_ZERO_MAP) { + WCN_DBG(FM_NTC | CHIP, "HQA_RETURN_ZERO_CHAN mt6635_chan_para_map enabled!\n"); + return 0; + } + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + if (freq < 6500) + return 0; + + pos = (freq - 6500) / 5; + + size = ARRAY_SIZE(mt6635_chan_para_map); + + pos = (pos > (size - 1)) ? (size - 1) : pos; + + return mt6635_chan_para_map[pos]; +} + + +static bool mt6635_SPI_hopping_check(unsigned short freq) +{ + signed int size; + + size = ARRAY_SIZE(mt6635_SPI_hopping_list); + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + while (size) { + if (mt6635_SPI_hopping_list[size - 1] == freq) + return 1; + size--; + } + + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/pub/mt6635_fm_rds.c b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/pub/mt6635_fm_rds.c new file mode 100644 index 00000000000000..0a4dd9f1e4ac03 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/mt6635/pub/mt6635_fm_rds.c @@ -0,0 +1,335 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_rds.h" +#include "mt6635_fm_reg.h" +#include "fm_cmd.h" + +static bool bRDS_FirstIn; /* false */ +static unsigned int gBLER_CHK_INTERVAL = 500; +static unsigned short GOOD_BLK_CNT = 0, BAD_BLK_CNT; +static unsigned char BAD_BLK_RATIO; + +static struct fm_basic_interface *fm_bi; + +static bool mt6635_RDS_support(void); +static signed int mt6635_RDS_enable(void); +static signed int mt6635_RDS_disable(void); +static unsigned short mt6635_RDS_Get_GoodBlock_Counter(void); +static unsigned short mt6635_RDS_Get_BadBlock_Counter(void); +static unsigned char mt6635_RDS_Get_BadBlock_Ratio(void); +static unsigned int mt6635_RDS_Get_BlerCheck_Interval(void); +/* static void mt6635_RDS_GetData(unsigned short *data, unsigned short datalen); */ +static void mt6635_RDS_Init_Data(struct rds_t *pstRDSData); + +static bool mt6635_RDS_support(void) +{ + return true; +} + +static signed int mt6635_RDS_enable(void) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | RDSC, "rds enable\n"); + ret = fm_reg_read(FM_RDS_CFG0, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable read 0x80 fail\n"); + return ret; + } + ret = fm_reg_write(FM_RDS_CFG0, 6); /* set buf_start_th */ + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable write 0x80 fail\n"); + return ret; + } + ret = fm_reg_read(FM_MAIN_CTRL, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable read 0x63 fail\n"); + return ret; + } + ret = fm_reg_write(FM_MAIN_CTRL, dataRead | (RDS_MASK)); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable write 0x63 fail\n"); + return ret; + } + + return ret; +} + +static signed int mt6635_RDS_disable(void) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | RDSC, "rds disable\n"); + ret = fm_reg_read(FM_MAIN_CTRL, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds disable read 0x63 fail\n"); + return ret; + } + ret = fm_reg_write(FM_MAIN_CTRL, dataRead & (~RDS_MASK)); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds disable write 0x63 fail\n"); + return ret; + } + + return ret; +} + +static unsigned short mt6635_RDS_Get_GoodBlock_Counter(void) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RDS_GOODBK_CNT, &tmp_reg); + GOOD_BLK_CNT = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get good block cnt:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static unsigned short mt6635_RDS_Get_BadBlock_Counter(void) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RDS_BADBK_CNT, &tmp_reg); + BAD_BLK_CNT = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get bad block cnt:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static unsigned char mt6635_RDS_Get_BadBlock_Ratio(void) +{ + unsigned short tmp_reg; + unsigned short gbc; + unsigned short bbc; + + gbc = mt6635_RDS_Get_GoodBlock_Counter(); + bbc = mt6635_RDS_Get_BadBlock_Counter(); + + if ((gbc + bbc) > 0) + tmp_reg = (unsigned char) (bbc * 100 / (gbc + bbc)); + else + tmp_reg = 0; + + BAD_BLK_RATIO = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get badblock ratio:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static signed int mt6635_RDS_BlockCounter_Reset(void) +{ + mt6635_RDS_disable(); + mt6635_RDS_enable(); + + return 0; +} + +static unsigned int mt6635_RDS_Get_BlerCheck_Interval(void) +{ + return gBLER_CHK_INTERVAL; +} + +static signed int mt6635_RDS_BlerCheck(struct rds_t *dst) +{ + return 0; +} + +#if 0 +static void RDS_Recovery_Handler(void) +{ + unsigned short tempData = 0; + + do { + fm_reg_read(FM_RDS_DATA_REG, &tempData); + fm_reg_read(FM_RDS_POINTER, &tempData); + } while (tempData & 0x3); +} +#endif + +#if 0 +static void mt6635_RDS_GetData(unsigned short *data, unsigned short datalen) +{ +#define RDS_GROUP_DIFF_OFS 0x007C +#define RDS_FIFO_DIFF 0x007F +#define RDS_CRC_BLK_ADJ 0x0020 +#define RDS_CRC_CORR_CNT 0x001E +#define RDS_CRC_INFO 0x0001 + + unsigned short CRC = 0, i = 0, RDS_adj = 0, RDSDataCount = 0, FM_WARorrCnt = 0; + unsigned short temp = 0, OutputPofm_s32 = 0; + + WCN_DBG(FM_DBG | RDSC, "get data\n"); + fm_reg_read(FM_RDS_FIFO_STATUS0, &temp); + RDSDataCount = ((RDS_GROUP_DIFF_OFS & temp) << 2); + + if ((temp & RDS_FIFO_DIFF) >= 4) { + /* block A data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 10; + CRC |= (temp & RDS_CRC_INFO) << 3; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 11); + fm_reg_read(FM_RDS_DATA_REG, &data[0]); + + /* block B data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 9; + CRC |= (temp & RDS_CRC_INFO) << 2; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 7); + fm_reg_read(FM_RDS_DATA_REG, &data[1]); + + /* block C data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 8; + CRC |= (temp & RDS_CRC_INFO) << 1; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 3); + fm_reg_read(FM_RDS_DATA_REG, &data[2]); + + /* block D data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 7; + CRC |= (temp & RDS_CRC_INFO); + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) >> 1); + fm_reg_read(FM_RDS_DATA_REG, &data[3]); + + data[4] = (CRC | RDS_adj | RDSDataCount); + data[5] = FM_WARorrCnt; + + fm_reg_read(FM_RDS_PWDI, &data[6]); + fm_reg_read(FM_RDS_PWDQ, &data[7]); + + fm_reg_read(FM_RDS_POINTER, &OutputPofm_s32); + + /* Go fm_s32o RDS recovery handler while RDS output pofm_s32 doesn't align to 4 in numeric */ + if (OutputPofm_s32 & 0x3) + RDS_Recovery_Handler(); + + } else { + for (; i < 8; i++) + data[i] = 0; + } +} +#endif + +static void mt6635_RDS_Init_Data(struct rds_t *pstRDSData) +{ + fm_memset(pstRDSData, 0, sizeof(struct rds_t)); + bRDS_FirstIn = true; + + pstRDSData->event_status = 0x0000; + fm_memset(pstRDSData->RT_Data.TextData, 0x20, sizeof(pstRDSData->RT_Data.TextData)); + fm_memset(pstRDSData->PS_Data.PS, '\0', sizeof(pstRDSData->PS_Data.PS)); + fm_memset(pstRDSData->PS_ON, 0x20, sizeof(pstRDSData->PS_ON)); +} + +bool mt6635_RDS_OnOff(struct rds_t *dst, bool bFlag) +{ + signed int ret = 0; + + if (mt6635_RDS_support() == false) { + WCN_DBG(FM_ALT | RDSC, "mt6635_RDS_OnOff failed, RDS not support\n"); + return false; + } + + if (bFlag) { + mt6635_RDS_Init_Data(dst); + ret = mt6635_RDS_enable(); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "mt6635_RDS_OnOff enable failed\n"); + return false; + } + } else { + mt6635_RDS_Init_Data(dst); + ret = mt6635_RDS_disable(); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "mt6635_RDS_OnOff disable failed\n"); + return false; + } + } + + return true; +} + +DEFINE_RDSLOG(mt6635_rds_log); + +/* mt6635_RDS_Efm_s32_Handler - response FM RDS interrupt + * @fm - main data structure of FM driver + * This function first get RDS raw data, then call RDS spec parser + */ +static signed int mt6635_rds_parser(struct rds_t *rds_dst, struct rds_rx_t *rds_raw, + signed int rds_size, unsigned short(*getfreq) (void)) +{ + mt6635_rds_log.log_in(&mt6635_rds_log, rds_raw, rds_size); + return rds_parser(rds_dst, rds_raw, rds_size, getfreq); +} + +static signed int mt6635_rds_log_get(struct rds_rx_t *dst, signed int *dst_len) +{ + return mt6635_rds_log.log_out(&mt6635_rds_log, dst, dst_len); +} + +static signed int mt6635_rds_gc_get(struct rds_group_cnt_t *dst, struct rds_t *rdsp) +{ + return rds_grp_counter_get(dst, &rdsp->gc); +} + +static signed int mt6635_rds_gc_reset(struct rds_t *rdsp) +{ + return rds_grp_counter_reset(&rdsp->gc); +} + +signed int fm_rds_ops_register(struct fm_basic_interface *bi, struct fm_rds_interface *ri) +{ + signed int ret = 0; + + if (ri == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,ri invalid pointer\n", __func__); + return -FM_EPARA; + } + + fm_bi = bi; + + ri->rds_blercheck = mt6635_RDS_BlerCheck; + ri->rds_onoff = mt6635_RDS_OnOff; + ri->rds_parser = mt6635_rds_parser; + ri->rds_gbc_get = mt6635_RDS_Get_GoodBlock_Counter; + ri->rds_bbc_get = mt6635_RDS_Get_BadBlock_Counter; + ri->rds_bbr_get = mt6635_RDS_Get_BadBlock_Ratio; + ri->rds_bc_reset = mt6635_RDS_BlockCounter_Reset; + ri->rds_bci_get = mt6635_RDS_Get_BlerCheck_Interval; + ri->rds_log_get = mt6635_rds_log_get; + ri->rds_gc_get = mt6635_rds_gc_get; + ri->rds_gc_reset = mt6635_rds_gc_reset; + + return ret; +} + +signed int fm_rds_ops_unregister(struct fm_rds_interface *ri) +{ + signed int ret = 0; + + if (ri == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,ri invalid pointer\n", __func__); + return -FM_EPARA; + } + + fm_bi = NULL; + fm_memset(ri, 0, sizeof(struct fm_rds_interface)); + return ret; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/soc/inc/soc_drv_dsp.h b/drivers/misc/mediatek/connectivity/fmradio/chips/soc/inc/soc_drv_dsp.h new file mode 100644 index 00000000000000..957a869719bc3b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/soc/inc/soc_drv_dsp.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +const unsigned char channel_parameter[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 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, 2, 0, 0, 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, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 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, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0 +}; diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/soc/inc/soc_fm_lib.h b/drivers/misc/mediatek/connectivity/fmradio/chips/soc/inc/soc_fm_lib.h new file mode 100644 index 00000000000000..7e2f049f7010ba --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/soc/inc/soc_fm_lib.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT6580_FM_LIB_H__ +#define __MT6580_FM_LIB_H__ + +#include "fm_typedef.h" + +enum { + DSPPATCH = 0xFFF9, + USDELAY = 0xFFFA, + MSDELAY = 0xFFFB, + HW_VER = 0xFFFD, + POLL_N = 0xFFFE, /* poling check if bit(n) is '0' */ + POLL_P = 0xFFFF, /* polling check if bit(n) is '1' */ +}; + +enum { + FM_PUS_DSPPATCH = DSPPATCH, + FM_PUS_USDELAY = USDELAY, + FM_PUS_MSDELAY = MSDELAY, + FM_PUS_HW_VER = HW_VER, + FM_PUS_POLL_N = POLL_N, /* poling check if bit(n) is '0' */ + FM_PUS_POLL_P = POLL_P, /* polling check if bit(n) is '1' */ + FM_PUS_MAX +}; + +enum { + mt6580_E1 = 0, + mt6580_E2 +}; + +struct mt6580_fm_cqi { + unsigned short ch; + unsigned short rssi; + unsigned short reserve; +}; + +struct adapt_fm_cqi { + signed int ch; + signed int rssi; + signed int reserve; +}; + +struct mt6580_full_cqi { + unsigned short ch; + unsigned short rssi; + unsigned short pamd; + unsigned short pr; + unsigned short fpamd; + unsigned short mr; + unsigned short atdc; + unsigned short prx; + unsigned short atdev; + unsigned short smg; /* soft-mute gain */ + unsigned short drssi; /* delta rssi */ +}; + +#endif diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/soc/inc/soc_fm_reg.h b/drivers/misc/mediatek/connectivity/fmradio/chips/soc/inc/soc_fm_reg.h new file mode 100644 index 00000000000000..5a52de14649787 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/soc/inc/soc_fm_reg.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT6580_FM_REG_H__ +#define __MT6580_FM_REG_H__ + +enum MT6580_HOSTREG { + MCUPLL_CON1 = 0x80000224, + CONN_RF_CG = 0x80102090 +}; + +/* RDS_BDGRP_ABD_CTRL_REG */ +enum { + BDGRP_ABD_EN = 0x0001, + BER_RUN = 0x2000 +}; +#define FM_DAC_CON1 0x83 +#define FM_DAC_CON2 0x84 +#define FM_FT_CON0 0x86 +enum { + FT_EN = 0x0001 +}; + +#define FM_I2S_CON0 0x90 +enum { + I2S_EN = 0x0001, + FORMAT = 0x0002, + WLEN = 0x0004, + I2S_SRC = 0x0008 +}; + +/* FM_MAIN_CTRL */ +enum { + TUNE = 0x0001, + SEEK = 0x0002, + SCAN = 0x0004, + CQI_READ = 0x0008, + RDS_MASK = 0x0010, + MUTE = 0x0020, + RDS_BRST = 0x0040, + RAMP_DOWN = 0x0100, +}; + +enum { + ANTENNA_TYPE = 0x0010, /* 0x61 D4, 0:long, 1:short */ + ANALOG_I2S = 0x0080, /* 0x61 D7, 0:lineout, 1:I2S */ + DE_EMPHASIS = 0x1000, /* 0x61 D12,0:50us, 1:75 us */ +}; + +#define OSC_FREQ_BITS 0x0070 /* 0x60 bit4~6 */ +#define OSC_FREQ_MASK (~OSC_FREQ_BITS) + +#endif /* __MT6580_FM_REG_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/soc/pub/soc_fm_lib.c b/drivers/misc/mediatek/connectivity/fmradio/chips/soc/pub/soc_fm_lib.c new file mode 100644 index 00000000000000..58f1d453b0c00b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/soc/pub/soc_fm_lib.c @@ -0,0 +1,1843 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/slab.h> +#include <linux/vmalloc.h> + +#include "osal_typedef.h" +#include "stp_exp.h" +#include "wmt_exp.h" + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_patch.h" +#include "fm_utils.h" +#include "fm_link.h" +#include "fm_config.h" +#include "fm_cmd.h" + +#include "soc_fm_reg.h" +#include "soc_fm_lib.h" + +/* #include "mach/mt_gpio.h" */ + +static struct fm_patch_tbl mt6580_patch_tbl[5] = { + {FM_ROM_V1, "soc_fm_v1_patch.bin", "soc_fm_v1_coeff.bin", NULL, NULL}, + {FM_ROM_V2, "soc_fm_v2_patch.bin", "soc_fm_v2_coeff.bin", NULL, NULL}, + {FM_ROM_V3, "soc_fm_v3_patch.bin", "soc_fm_v3_coeff.bin", NULL, NULL}, + {FM_ROM_V4, "soc_fm_v4_patch.bin", "soc_fm_v4_coeff.bin", NULL, NULL}, + {FM_ROM_V5, "soc_fm_v5_patch.bin", "soc_fm_v5_coeff.bin", NULL, NULL} +}; + +static struct fm_hw_info mt6580_hw_info = { + .chip_id = 0x00006580, + .eco_ver = 0x00000000, + .rom_ver = 0x00000000, + .patch_ver = 0x00000000, + .reserve = 0x00000000, +}; + +unsigned char *cmd_buf; +struct fm_lock *cmd_buf_lock; +struct fm_res_ctx *fm_res; +static struct fm_callback *fm_cb_op; +/* static signed int Chip_Version = mt6580_E1; */ + +/* static bool rssi_th_set = false; */ + +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ +static struct fm_fifo *cqi_fifo; +#endif +static signed int mt6580_is_dese_chan(unsigned short freq); + +#if 0 +static signed int mt6580_mcu_dese(unsigned short freq, void *arg); +static signed int mt6580_gps_dese(unsigned short freq, void *arg); +static signed int mt6580_I2s_Setting(signed int onoff, signed int mode, signed int sample); +#endif +static unsigned short mt6580_chan_para_get(unsigned short freq); +static signed int mt6580_desense_check(unsigned short freq, signed int rssi); +/*static bool mt6580_TDD_chan_check(unsigned short freq);*/ +static signed int mt6580_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid); +static signed int mt6580_pwron(signed int data) +{ + if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM) == MTK_WCN_BOOL_FALSE) { + WCN_DBG(FM_ERR | CHIP, "WMT turn on FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn on FM OK!\n"); + return 0; +} + +static signed int mt6580_pwroff(signed int data) +{ + if (mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM) == MTK_WCN_BOOL_FALSE) { + WCN_DBG(FM_ERR | CHIP, "WMT turn off FM Fail!\n"); + return -FM_ELINK; + } + + WCN_DBG(FM_NTC | CHIP, "WMT turn off FM OK!\n"); + return 0; +} + +#if 0 +static signed int mt6580_top_set_bits(unsigned short addr, unsigned int bits, unsigned int mask) +{ + signed int ret = 0; + unsigned int val; + + ret = fm_top_reg_read(addr, &val); + + if (ret) + return ret; + + val = ((val & (mask)) | bits); + ret = fm_top_reg_write(addr, val); + + return ret; +} +#endif + +#if 0 +static signed int mt6580_DSP_write(unsigned short addr, unsigned short val) +{ + fm_reg_write(0xE2, addr); + fm_reg_write(0xE3, val); + fm_reg_write(0xE1, 0x0002); + return 0; +} +static signed int mt6580_DSP_read(unsigned short addr, unsigned short *val) +{ + signed int ret = -1; + + fm_reg_write(0xE2, addr); + fm_reg_write(0xE1, 0x0001); + ret = fm_reg_read(0xE4, val); + return ret; +} +#endif + +static unsigned short mt6580_get_chipid(void) +{ + return 0x6580; +} + +/* MT6580_SetAntennaType - set Antenna type + * @type - 1,Short Antenna; 0, Long Antenna + */ +static signed int mt6580_SetAntennaType(signed int type) +{ + unsigned short dataRead; + + WCN_DBG(FM_DBG | CHIP, "set ana to %s\n", type ? "short" : "long"); + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + + if (type) + dataRead |= ANTENNA_TYPE; + else + dataRead &= (~ANTENNA_TYPE); + + fm_reg_write(FM_MAIN_CG2_CTRL, dataRead); + + return 0; +} + +static signed int mt6580_GetAntennaType(void) +{ + unsigned short dataRead = 0; + + fm_reg_read(FM_MAIN_CG2_CTRL, &dataRead); + WCN_DBG(FM_DBG | CHIP, "get ana type: %s\n", (dataRead & ANTENNA_TYPE) ? "short" : "long"); + + if (dataRead & ANTENNA_TYPE) + return FM_ANA_SHORT; /* short antenna */ + else + return FM_ANA_LONG; /* long antenna */ +} + +static signed int mt6580_Mute(bool mute) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | CHIP, "set %s\n", mute ? "mute" : "unmute"); + /* fm_reg_read(FM_MAIN_CTRL, &dataRead); */ + fm_reg_read(0x9C, &dataRead); + + /* fm_top_reg_write(0x0050,0x00000007); */ + + if (mute == 1) + ret = fm_reg_write(0x9C, (dataRead & 0xFFFC) | 0x0003); + else + ret = fm_reg_write(0x9C, (dataRead & 0xFFFC)); + + /* fm_top_reg_write(0x0050,0x0000000F); */ + + return ret; +} + +#if 0 +static signed int mt6580_set_RSSITh(unsigned short TH_long, unsigned short TH_short) +{ + fm_reg_write(0xE2, 0x3072); + fm_reg_write(0xE3, TH_long); + fm_reg_write(0xE1, 0x0002); + fm_delayms(1); + fm_reg_write(0xE2, 0x307A); + fm_reg_write(0xE3, TH_short); + fm_reg_write(0xE1, 0x0002); + + WCN_DBG(FM_DBG | CHIP, "RSSI TH, long:0x%04x, short:0x%04x", TH_long, TH_short); + return 0; +} + +static signed int mt6580_set_SMGTh(signed int ver, unsigned short TH_smg) +{ + if (mt6580_E1 == ver) { + fm_reg_write(0xE2, 0x321E); + fm_reg_write(0xE3, TH_smg); + fm_reg_write(0xE1, 0x0002); + } else { + fm_reg_write(0xE2, 0x3218); + fm_reg_write(0xE3, TH_smg); + fm_reg_write(0xE1, 0x0002); + } + + WCN_DBG(FM_DBG | CHIP, "Soft-mute gain TH %d\n", (int)TH_smg); + return 0; +} +#endif + +static signed int mt6580_rampdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* Clear DSP state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF0, 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* Set DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFFF, RAMP_DOWN, &buf[pkt_size], buf_size - pkt_size); + /* @Wait for STC_DONE interrupt@ */ + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size], + buf_size - pkt_size); + /* Clear DSP ramp down state */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, (~RAMP_DOWN), 0x0000, &buf[pkt_size], buf_size - pkt_size); + /* Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6580_rampdown - f/w will wait for STC_DONE interrupt + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6580_rampdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6580_rampdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_RAMPDOWN_OPCODE, pkt_size); +} + +static signed int mt6580_RampDown(void) +{ + signed int ret = 0; + unsigned short pkt_size; + + WCN_DBG(FM_DBG | CHIP, "ramp down\n"); + ret = fm_reg_write(0x60, 0x00000007); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down wr 0x60 failed\n"); + return ret; + } + ret = fm_reg_write(0x60, 0x0000000f); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down wr 0x60 failed\n"); + return ret; + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6580_rampdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_RAMPDOWN, SW_RETRY_CNT, RAMPDOWN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "ramp down failed\n"); + return ret; + } + + return ret; +} + +static signed int mt6580_get_rom_version(void) +{ + unsigned short tmp; + signed int ret; + + fm_reg_write(0x90, 0xe); + fm_reg_write(0x92, 0x0); + fm_reg_write(0x90, 0x40); + fm_reg_write(0x90, 0x0); + + /* DSP rom code version request enable --- set 0x61 b15=1 */ + fm_set_bits(0x61, 0x8000, 0x7FFF); + + /* Release ASIP reset --- set 0x61 b1=1 */ + fm_set_bits(0x61, 0x0002, 0xFFFD); + + /* Enable ASIP power --- set 0x61 b0=0 */ + fm_set_bits(0x61, 0x0000, 0xFFFE); + + /* Wait DSP code version ready --- wait 1ms */ + do { + fm_delayus(1000); + ret = fm_reg_read(0x84, &tmp); + /* ret=-4 means signal got when control FM. usually get sig 9 to kill FM process. */ + /* now cancel FM power up sequence is recommended. */ + if (ret) + return ret; + + WCN_DBG(FM_NTC | CHIP, "0x84=%x\n", tmp); + } while (tmp != 0x0001); + + /* Get FM DSP code version --- rd 0x83[15:8] */ + fm_reg_read(0x83, &tmp); + tmp = (tmp >> 8); + + /* DSP rom code version request disable --- set 0x61 b15=0 */ + fm_set_bits(0x61, 0x0000, 0x7FFF); + + /* Reset ASIP --- set 0x61[1:0] = 1 */ + fm_set_bits(0x61, 0x0001, 0xFFFC); + + /* WCN_DBG(FM_NTC | CHIP, "ROM version: v%d\n", (signed int)tmp); */ + return (signed int) tmp; +} + +static signed int mt6580_enable_pmic_tldo(void) +{ + signed int ret = 0; + unsigned int hostreg = 0; + + /* set 26M clock mannual on */ + ret = fm_host_reg_read(MCUPLL_CON1, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd MCUPLL_CON1 failed\n"); + return ret; + } + ret = fm_host_reg_write(MCUPLL_CON1, hostreg | (0x1 << 0)); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr MCUPLL_CON1 failed\n"); + return ret; + } + + ret = fm_host_reg_read(MCUPLL_CON1, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd MCUPLL_CON1 failed\n"); + return ret; + } + ret = fm_host_reg_write(MCUPLL_CON1, hostreg | (0x1 << 6)); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr MCUPLL_CON1 failed\n"); + return ret; + } + + ret = fm_host_reg_read(MCUPLL_CON1, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd MCUPLL_CON1 failed\n"); + return ret; + } + ret = fm_host_reg_write(MCUPLL_CON1, hostreg | (0x1 << 16)); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr MCUPLL_CON1 failed\n"); + return ret; + } + + ret = fm_host_reg_read(MCUPLL_CON1, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd MCUPLL_CON1 failed\n"); + return ret; + } + ret = fm_host_reg_write(MCUPLL_CON1, hostreg | (0x1 << 22)); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr MCUPLL_CON1 failed\n"); + return ret; + } + + /* set RX_DET_OUT Gating off */ + ret = fm_host_reg_read(CONN_RF_CG, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd CONN_RF_CG failed\n"); + return ret; + } + ret = fm_host_reg_write(CONN_RF_CG, hostreg | (0x1 << 16)); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr CONN_RF_CG failed\n"); + return ret; + } + + /* set ADC_QD Gating off */ + ret = fm_host_reg_read(CONN_RF_CG, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd CONN_RF_CG failed\n"); + return ret; + } + ret = fm_host_reg_write(CONN_RF_CG, hostreg | (0x1 << 15)); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr CONN_RF_CG failed\n"); + return ret; + } + + /* set ADC_ID Gating off */ + ret = fm_host_reg_read(CONN_RF_CG, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd CONN_RF_CG failed\n"); + return ret; + } + ret = fm_host_reg_write(CONN_RF_CG, hostreg | (0x1 << 14)); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr CONN_RF_CG failed\n"); + return ret; + } + + /* set ADC_CK Gating off */ + ret = fm_host_reg_read(CONN_RF_CG, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd CONN_RF_CG failed\n"); + return ret; + } + ret = fm_host_reg_write(CONN_RF_CG, hostreg | (0x1 << 7)); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr CONN_RF_CG failed\n"); + return ret; + } + + /* set DIG_CK Gating off */ + ret = fm_host_reg_read(CONN_RF_CG, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd CONN_RF_CG failed\n"); + return ret; + } + ret = fm_host_reg_write(CONN_RF_CG, hostreg | (0x1 << 6)); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr CONN_RF_CG failed\n"); + return ret; + } + + return ret; +} + +static signed int mt6580_disable_pmic_tldo(void) +{ + signed int ret = 0; + unsigned int hostreg = 0; + + /* set 26M clock mannual on */ + ret = fm_host_reg_read(MCUPLL_CON1, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd MCUPLL_CON1 failed\n"); + return ret; + } + ret = fm_host_reg_write(MCUPLL_CON1, hostreg & (~(0x1 << 22))); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr MCUPLL_CON1 failed\n"); + return ret; + } + + ret = fm_host_reg_read(MCUPLL_CON1, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd MCUPLL_CON1 failed\n"); + return ret; + } + ret = fm_host_reg_write(MCUPLL_CON1, hostreg & (~(0x1 << 16))); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr MCUPLL_CON1 failed\n"); + return ret; + } + + ret = fm_host_reg_read(MCUPLL_CON1, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd MCUPLL_CON1 failed\n"); + return ret; + } + ret = fm_host_reg_write(MCUPLL_CON1, hostreg & (~(0x1 << 6))); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr MCUPLL_CON1 failed\n"); + return ret; + } + + ret = fm_host_reg_read(MCUPLL_CON1, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd MCUPLL_CON1 failed\n"); + return ret; + } + ret = fm_host_reg_write(MCUPLL_CON1, hostreg & (~(0x1 << 0))); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr MCUPLL_CON1 failed\n"); + return ret; + } + + /* set RX_DET_OUT Gating off */ + ret = fm_host_reg_read(CONN_RF_CG, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd CONN_RF_CG failed\n"); + return ret; + } + ret = fm_host_reg_write(CONN_RF_CG, hostreg & (~(0x1 << 16))); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr CONN_RF_CG failed\n"); + return ret; + } + + /* set ADC_QD Gating off */ + ret = fm_host_reg_read(CONN_RF_CG, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd CONN_RF_CG failed\n"); + return ret; + } + ret = fm_host_reg_write(CONN_RF_CG, hostreg & (~(0x1 << 15))); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr CONN_RF_CG failed\n"); + return ret; + } + + /* set ADC_ID Gating off */ + ret = fm_host_reg_read(CONN_RF_CG, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd CONN_RF_CG failed\n"); + return ret; + } + ret = fm_host_reg_write(CONN_RF_CG, hostreg & (~(0x1 << 14))); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr CONN_RF_CG failed\n"); + return ret; + } + + /* set ADC_CK Gating off */ + ret = fm_host_reg_read(CONN_RF_CG, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd CONN_RF_CG failed\n"); + return ret; + } + ret = fm_host_reg_write(CONN_RF_CG, hostreg & (~(0x1 << 7))); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr CONN_RF_CG failed\n"); + return ret; + } + + /* set DIG_CK Gating off */ + ret = fm_host_reg_read(CONN_RF_CG, &hostreg); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup rd CONN_RF_CG failed\n"); + return ret; + } + ret = fm_host_reg_write(CONN_RF_CG, hostreg & (~(0x1 << 6))); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " pwrup wr CONN_RF_CG failed\n"); + return ret; + } + + return ret; +} + +static signed int mt6580_pwrup_clock_on_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + unsigned short de_emphasis; + /* unsigned short osc_freq; */ + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + de_emphasis = fm_config.rx_cfg.deemphasis; /* fm_cust_config_fetch(FM_CFG_RX_DEEMPHASIS); */ + de_emphasis &= 0x0001; /* rang 0~1 */ + + /* turn on top clock */ + pkt_size += fm_bop_top_write(0xA10, 0xFFFFFFFF, &buf[pkt_size], buf_size - pkt_size); /* wr a10 ffffffff */ + /* enable MTCMOS */ + pkt_size += fm_bop_top_write(0x60, 0x00000030, &buf[pkt_size], buf_size - pkt_size); /* wr 60 30 */ + pkt_size += fm_bop_top_write(0x60, 0x00000005, &buf[pkt_size], buf_size - pkt_size); /* wr 60 5 */ + pkt_size += fm_bop_udelay(10, &buf[pkt_size], buf_size - pkt_size); /* delay 10us */ + pkt_size += fm_bop_top_write(0x60, 0x00000045, &buf[pkt_size], buf_size - pkt_size); /* wr 60 45 */ + + /* enable digital OSC */ + pkt_size += fm_bop_write(0x60, 0x00000001, &buf[pkt_size], buf_size - pkt_size); /* wr 60 1 */ + /* set OSC clock output to fm */ + pkt_size += fm_bop_write(0x60, 0x00000003, &buf[pkt_size], buf_size - pkt_size); /* wr 60 3 */ + /* release HW clock gating */ + pkt_size += fm_bop_write(0x60, 0x00000007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 7 */ + /* enable DSP auto clock gating */ + pkt_size += fm_bop_write(0x70, 0x0040, &buf[pkt_size], buf_size - pkt_size); /* wr 70 0040 */ + /* deemphasis setting */ + pkt_size += fm_bop_modify(0x61, ~DE_EMPHASIS, (de_emphasis << 12), &buf[pkt_size], buf_size - pkt_size); + + return pkt_size - 4; +} +/* + * mt6580_pwrup_clock_on - Wholechip FM Power Up: step 1, FM Digital Clock enable + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6580_pwrup_clock_on(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6580_pwrup_clock_on_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6580_pwrup_digital_init_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* FM Digital Init: fm_rgf_maincon */ + pkt_size += fm_bop_write(0x6A, 0x0021, &buf[pkt_size], buf_size - pkt_size); + /* wr 6A 0021, set 1 to enable interrupt */ + pkt_size += fm_bop_write(0x6B, 0x0021, &buf[pkt_size], buf_size - pkt_size); /* wr 6B 0021 */ + pkt_size += fm_bop_write(0x60, 0x0000000F, &buf[pkt_size], buf_size - pkt_size); /* wr 60 f */ + pkt_size += fm_bop_modify(0x61, 0xFFFD, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D1=1 */ + pkt_size += fm_bop_modify(0x61, 0xFFFE, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D0=0 */ + pkt_size += fm_bop_udelay(100000, &buf[pkt_size], buf_size - pkt_size); /* delay 100ms */ + pkt_size += fm_bop_rd_until(0x64, 0x001F, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* Poll 64[0~4] = 2 */ + pkt_size += fm_bop_write(0x60, 0x00000007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 7 */ + pkt_size += fm_bop_write(0x2d, 0x000001fa, &buf[pkt_size], buf_size - pkt_size); /* wr 2d 1fa */ + pkt_size += fm_bop_write(0x60, 0x0000000F, &buf[pkt_size], buf_size - pkt_size); /* wr 60 f */ + + return pkt_size - 4; +} + +/* + * mt6580_pwrup_digital_init - Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6580_pwrup_digital_init(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6580_pwrup_digital_init_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6580_pwrdown_reg_op(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 4; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* A1:set audio output I2S Tx mode: */ + pkt_size += fm_bop_modify(0x9B, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 9B[0~2] 0 */ + + /* B0:Disable HW clock control */ + pkt_size += fm_bop_write(0x60, 0x330F, &buf[pkt_size], buf_size - pkt_size); /* wr 60 330F */ + /* B1:Reset ASIP */ + pkt_size += fm_bop_write(0x61, 0x0001, &buf[pkt_size], buf_size - pkt_size); /* wr 61 0001 */ + /* B2:digital core + digital rgf reset */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */ + pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */ + /* B3:Disable all clock */ + pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 60 0000 */ + /* B4:Reset rgfrf */ + pkt_size += fm_bop_write(0x60, 0x4000, &buf[pkt_size], buf_size - pkt_size); /* wr 60 4000 */ + pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 60 0000 */ + /* MTCMOS power off */ + /* C0:disable MTCMOS */ + pkt_size += fm_bop_top_write(0x60, 0x0005, &buf[pkt_size], buf_size - pkt_size); /* wr top60 0005 */ + pkt_size += fm_bop_top_write(0x60, 0x0015, &buf[pkt_size], buf_size - pkt_size); /* wr top60 0015 */ + + return pkt_size - 4; +} +/* + * mt6580_pwrdown - Wholechip FM Power down: Digital Modem Power Down + * @buf - target buf + * @buf_size - buffer size + * return package size + */ +static signed int mt6580_pwrdown(unsigned char *buf, signed int buf_size) +{ + signed int pkt_size = 0; + + pkt_size = mt6580_pwrdown_reg_op(buf, buf_size); + return fm_op_seq_combine_cmd(buf, FM_ENABLE_OPCODE, pkt_size); +} + +static signed int mt6580_tune_reg_op(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 4; + + WCN_DBG(FM_ALT | CHIP, "%s enter mt6580_tune function\n", __func__); + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s invalid pointer\n", __func__); + return -1; + } + if (buf_size < TX_BUF_SIZE) { + WCN_DBG(FM_ERR | CHIP, "%s invalid buf size(%d)\n", __func__, buf_size); + return -2; + } + + /* Set desired channel & channel parameter */ +#ifdef FM_TUNE_USE_POLL + pkt_size += fm_bop_write(0x6A, 0x0000, &buf[pkt_size], buf_size - pkt_size); + pkt_size += fm_bop_write(0x6B, 0x0000, &buf[pkt_size], buf_size - pkt_size); +#endif + /* Enable hardware controlled tuning sequence */ + pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF8, TUNE, &buf[pkt_size], buf_size - pkt_size); + /* Wait for STC_DONE interrupt */ +#ifdef FM_TUNE_USE_POLL + pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size], + buf_size - pkt_size); + /* Write 1 clear the STC_DONE interrupt status flag */ + pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size); +#endif + + WCN_DBG(FM_ALT | CHIP, "%s leave mt6580_tune function\n", __func__); + + return pkt_size - 4; +} + +/* + * mt6580_tune - execute tune action, + * @buf - target buf + * @buf_size - buffer size + * @freq - 760 ~ 1080, 100KHz unit + * return package size + */ +static signed int mt6580_tune(unsigned char *buf, signed int buf_size, unsigned short freq, + unsigned short chan_para) +{ + signed int pkt_size = 0; + + pkt_size = mt6580_tune_reg_op(buf, buf_size, freq, chan_para); + return fm_op_seq_combine_cmd(buf, FM_TUNE_OPCODE, pkt_size); +} + +/* + * mt6580_pwrup_DSP_download - execute dsp/coeff patch dl action, + * @patch_tbl - current chip patch table + * return patch dl ok or not + */ +static signed int mt6580_pwrup_DSP_download(struct fm_patch_tbl *patch_tbl) +{ +#define PATCH_BUF_SIZE (4096*6) + signed int ret = 0; + signed int patch_len = 0; + unsigned char *dsp_buf = NULL; + unsigned short tmp_reg = 0; + + mt6580_hw_info.eco_ver = (signed int) mtk_wcn_wmt_hwver_get(); + WCN_DBG(FM_NTC | CHIP, "ECO version:0x%08x\n", mt6580_hw_info.eco_ver); + mt6580_hw_info.eco_ver += 1; + + /* get mt6580 DSP rom version */ + ret = mt6580_get_rom_version(); + if (ret >= 0) { + mt6580_hw_info.rom_ver = ret; + WCN_DBG(FM_NTC | CHIP, "ROM version: v%d\n", mt6580_hw_info.rom_ver); + } else { + WCN_DBG(FM_ERR | CHIP, "get ROM version failed\n"); + /* ret=-4 means signal got when control FM. usually get sig 9 to kill FM process. */ + /* now cancel FM power up sequence is recommended. */ + goto out; + } + + dsp_buf = fm_vmalloc(PATCH_BUF_SIZE); + if (!dsp_buf) { + WCN_DBG(FM_ALT | CHIP, "-ENOMEM\n"); + return -ENOMEM; + } + + patch_len = fm_get_patch_path(mt6580_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_patch_path failed\n"); + ret = patch_len; + goto out; + } + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_PATCH); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " DL DSPpatch failed\n"); + goto out; + } + + patch_len = fm_get_coeff_path(mt6580_hw_info.rom_ver, dsp_buf, PATCH_BUF_SIZE, patch_tbl); + if (patch_len <= 0) { + WCN_DBG(FM_ALT | CHIP, " fm_get_coeff_path failed\n"); + ret = patch_len; + goto out; + } + + mt6580_hw_info.rom_ver += 1; + + tmp_reg = dsp_buf[38] | (dsp_buf[39] << 8); /* to be confirmed */ + mt6580_hw_info.patch_ver = (signed int) tmp_reg; + WCN_DBG(FM_NTC | CHIP, "Patch version: 0x%08x\n", mt6580_hw_info.patch_ver); + + if (ret == 1) { + dsp_buf[4] = 0x00; /* if we found rom version undefined, we should disable patch */ + dsp_buf[5] = 0x00; + } + + ret = fm_download_patch((const unsigned char *)dsp_buf, patch_len, IMG_COEFFICIENT); + if (ret) { + WCN_DBG(FM_ALT | CHIP, " DL DSPcoeff failed\n"); + goto out; + } + fm_reg_write(0x92, 0x0000); + fm_reg_write(0x90, 0x0040); + fm_reg_write(0x90, 0x0000); +out: + if (dsp_buf) { + fm_vfree(dsp_buf); + dsp_buf = NULL; + } + return ret; +} + + +static signed int mt6580_PowerUp(unsigned short *chip_id, unsigned short *device_id) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short tmp_reg = 0; + + if (chip_id == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (device_id == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + WCN_DBG(FM_DBG | CHIP, "pwr on seq......\n"); + + mt6580_enable_pmic_tldo(); + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6580_pwrup_clock_on(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6580_pwrup_clock_on failed\n"); + return ret; + } + + fm_reg_read(0x62, &tmp_reg); + /* *chip_id = tmp_reg; */ + if ((tmp_reg == 0x6580) || (tmp_reg == 0x0633)) + *chip_id = 0x6580; + *device_id = tmp_reg; + mt6580_hw_info.chip_id = (signed int) tmp_reg; + WCN_DBG(FM_NTC | CHIP, "chip_id:0x%04x\n", tmp_reg); + + if ((mt6580_hw_info.chip_id != 0x6580) && (mt6580_hw_info.chip_id != 0x0633)) { + WCN_DBG(FM_NTC | CHIP, "fm sys error, reset hw\n"); + return -FM_EFW; + } + + ret = mt6580_pwrup_DSP_download(mt6580_patch_tbl); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "mt6580_pwrup_DSP_download failed\n"); + return ret; + } + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6580_pwrup_digital_init(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6580_pwrup_digital_init failed\n"); + return ret; + } + + /* set audio output I2S TX mode */ + fm_reg_write(0x9B, 0x3); + + WCN_DBG(FM_NTC | CHIP, "pwr on seq ok\n"); + + return ret; +} + +static signed int mt6580_PowerDown(void) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | CHIP, "pwr down seq\n"); + + /*SW work around for MCUFA issue. + *if interrupt happen before doing rampdown, DSP can't switch MCUFA back well. + * In case read interrupt, and clean if interrupt found before rampdown. + */ + fm_reg_read(FM_MAIN_INTR, &dataRead); + + if (dataRead & 0x1) { + ret = fm_reg_write(FM_MAIN_INTR, dataRead); /* clear status flag */ + if (ret) + WCN_DBG(FM_ALT | CHIP, "mt6580_pwrdown wr FM_MAIN_INTR failed\n"); + } + /* mt6580_RampDown(); */ + + /* set audio output I2X Rx mode: */ + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = mt6580_pwrdown(cmd_buf, TX_BUF_SIZE); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_EN, SW_RETRY_CNT, EN_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6580_pwrdown failed\n"); + return ret; + } + + mt6580_disable_pmic_tldo(); + + return ret; +} + +static bool mt6580_SetFreq(unsigned short freq) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short chan_para = 0; + unsigned short freq_reg = 0; + + fm_cb_op->cur_freq_set(freq); + + chan_para = mt6580_chan_para_get(freq); + WCN_DBG(FM_DBG | CHIP, "%d chan para = %d\n", (signed int) freq, (signed int) chan_para); + freq_reg = freq; + if (fm_get_channel_space(freq_reg) == 0) + freq_reg *= 10; + WCN_DBG(FM_DBG | CHIP, "freq_reg = %d\n", freq_reg); + ret = fm_reg_write(0x60, 0x00000007); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x60 failed\n"); + /* add this paragragh to resolve FM sensitivity bad in low band issue */ +#if 0 + if (mt6580_TDD_chan_check(freq)) { + ret = fm_set_bits(0x39, 0x0008, 0xFFF3); /* use TDD solution */ + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x30 failed\n"); + } else { + ret = fm_set_bits(0x39, 0x0000, 0xFFF3); /* default use FDD solution */ + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x30 failed\n"); + } +#endif + if ((freq_reg >= 6500) && (freq_reg <= 7290)) { + ret = fm_reg_write(0x39, 0xd002); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } else if ((freq_reg >= 7295) && (freq_reg <= 8410)) { + ret = fm_reg_write(0x39, 0xce02); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } else if ((freq_reg >= 8415) && (freq_reg <= 9815)) { + ret = fm_reg_write(0x39, 0xcc02); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } else if ((freq_reg >= 9820) && (freq_reg <= 9830)) { + ret = fm_reg_write(0x39, 0xca02); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } else if ((freq_reg >= 9835) && (freq_reg <= 9940)) { + ret = fm_reg_write(0x39, 0xcc02); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } else if ((freq_reg >= 9845) && (freq_reg <= 10800)) { + ret = fm_reg_write(0x39, 0xca02); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } else { + ret = fm_reg_write(0x39, 0xca02); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } + + /* end */ + ret = fm_reg_write(0x6a, 0x00000021); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x6a failed\n"); + + ret = fm_reg_write(0x6b, 0x00000021); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x6b failed\n"); + + ret = fm_reg_write(0x60, 0x0000000F); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x60 failed\n"); + + + freq_reg = (freq_reg - 6400) * 2 / 10; + ret = fm_set_bits(0x65, freq_reg, 0xFC00); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x65 failed\n"); + return false; + } + ret = fm_set_bits(0x65, (chan_para << 12), 0x0FFF); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x65 failed\n"); + return false; + } + + if (FM_LOCK(cmd_buf_lock)) + return false; + pkt_size = mt6580_tune(cmd_buf, TX_BUF_SIZE, freq, chan_para); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_TUNE | FLAG_TUNE_DONE, SW_RETRY_CNT, TUNE_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ALT | CHIP, "mt6580_tune failed\n"); + return false; + } + + WCN_DBG(FM_DBG | CHIP, "set freq to %d ok\n", freq); + + return true; +} + +#define FM_CQI_LOG_PATH "/mnt/sdcard/fmcqilog" + +static signed int mt6580_full_cqi_get(signed int min_freq, signed int max_freq, signed int space, signed int cnt) +{ + signed int ret = 0; + unsigned short pkt_size; + unsigned short freq, orig_freq; + signed int i, j, k; + signed int space_val, max, min, num; + struct mt6580_full_cqi *p_cqi; + unsigned char *cqi_log_title = "Freq, RSSI, PAMD, PR, FPAMD, MR, ATDC, PRX, ATDEV, SMGain, DltaRSSI\n"; + unsigned char cqi_log_buf[100] = { 0 }; + signed int pos; + unsigned char cqi_log_path[100] = { 0 }; + + WCN_DBG(FM_DBG | CHIP, "6580 cqi log start\n"); + /* for soft-mute tune, and get cqi */ + freq = fm_cb_op->cur_freq_get(); + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + /* get cqi */ + orig_freq = freq; + if (fm_get_channel_space(min_freq) == 0) + min = min_freq * 10; + else + min = min_freq; + + if (fm_get_channel_space(max_freq) == 0) + max = max_freq * 10; + else + max = max_freq; + + if (space == 0x0001) + space_val = 5; /* 50Khz */ + else if (space == 0x0002) + space_val = 10; /* 100Khz */ + else if (space == 0x0004) + space_val = 20; /* 200Khz */ + else + space_val = 10; + + num = (max - min) / space_val + 1; /* Eg, (8760 - 8750) / 10 + 1 = 2 */ + for (k = 0; (orig_freq == 10000) && (g_dbg_level == 0xffffffff) && (k < cnt); k++) { + WCN_DBG(FM_NTC | CHIP, "cqi file:%d\n", k + 1); + freq = min; + pos = 0; + fm_memcpy(cqi_log_path, FM_CQI_LOG_PATH, strlen(FM_CQI_LOG_PATH)); + sprintf(&cqi_log_path[strlen(FM_CQI_LOG_PATH)], "%d.txt", k + 1); + fm_file_write(cqi_log_path, cqi_log_title, strlen(cqi_log_title), &pos); + for (j = 0; j < num; j++) { + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = + fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, + SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + WCN_DBG(FM_NTC | CHIP, "smt cqi size %d\n", fm_res->cqi[0]); + p_cqi = (struct mt6580_full_cqi *)&fm_res->cqi[2]; + for (i = 0; i < fm_res->cqi[1]; i++) { + /* just for debug */ + WCN_DBG(FM_NTC | CHIP, + "freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* format to buffer */ + sprintf(cqi_log_buf, + "%04d,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,\n", + p_cqi[i].ch, p_cqi[i].rssi, p_cqi[i].pamd, + p_cqi[i].pr, p_cqi[i].fpamd, p_cqi[i].mr, + p_cqi[i].atdc, p_cqi[i].prx, p_cqi[i].atdev, + p_cqi[i].smg, p_cqi[i].drssi); + /* write back to log file */ + fm_file_write(cqi_log_path, cqi_log_buf, strlen(cqi_log_buf), &pos); + } + } else { + WCN_DBG(FM_ALT | CHIP, "smt get CQI failed\n"); + ret = -1; + } + freq += space_val; + } + fm_cb_op->cur_freq_set(0); /* avoid run too much times */ + } + WCN_DBG(FM_DBG | CHIP, "6580 cqi log done\n"); + + return ret; +} + +/* + * mt6580_GetCurRSSI - get current freq's RSSI value + * RS=RSSI + * If RS>511, then RSSI(dBm)= (RS-1024)/16*6 + * else RSSI(dBm)= RS/16*6 + */ +static signed int mt6580_GetCurRSSI(signed int *pRSSI) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RSSI_IND, &tmp_reg); + tmp_reg = tmp_reg & 0x03ff; + + if (pRSSI) { + *pRSSI = (tmp_reg > 511) ? (((tmp_reg - 1024) * 6) >> 4) : ((tmp_reg * 6) >> 4); + WCN_DBG(FM_DBG | CHIP, "rssi:%d, dBm:%d\n", tmp_reg, *pRSSI); + } else { + WCN_DBG(FM_ERR | CHIP, "get rssi para error\n"); + return -FM_EPARA; + } + + return 0; +} + +static unsigned short mt6580_vol_tbl[16] = { 0x0000, 0x0519, 0x066A, 0x0814, + 0x0A2B, 0x0CCD, 0x101D, 0x1449, + 0x198A, 0x2027, 0x287A, 0x32F5, + 0x4027, 0x50C3, 0x65AD, 0x7FFF +}; + +static signed int mt6580_SetVol(unsigned char vol) +{ + signed int ret = 0; + + vol = (vol > 15) ? 15 : vol; + ret = fm_reg_write(0x7D, mt6580_vol_tbl[vol]); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "Set vol=%d Failed\n", vol); + return ret; + } + + WCN_DBG(FM_DBG | CHIP, "Set vol=%d OK\n", vol); + + if (vol == 10) { + fm_print_cmd_fifo(); /* just for debug */ + fm_print_evt_fifo(); + } + return 0; +} + +static signed int mt6580_GetVol(unsigned char *pVol) +{ + int ret = 0; + unsigned short tmp = 0; + signed int i; + + if (pVol == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + ret = fm_reg_read(0x7D, &tmp); + if (ret) { + *pVol = 0; + WCN_DBG(FM_ERR | CHIP, "Get vol Failed\n"); + return ret; + } + + for (i = 0; i < 16; i++) { + if (mt6580_vol_tbl[i] == tmp) { + *pVol = i; + break; + } + } + + WCN_DBG(FM_DBG | CHIP, "Get vol=%d OK\n", *pVol); + return 0; +} + +static signed int mt6580_dump_reg(void) +{ + signed int i; + unsigned short TmpReg = 0; + + for (i = 0; i < 0xff; i++) { + fm_reg_read(i, &TmpReg); + WCN_DBG(FM_NTC | CHIP, "0x%02x=0x%04x\n", i, TmpReg); + } + return 0; +} + +/*0:mono, 1:stereo*/ +static bool mt6580_GetMonoStereo(unsigned short *pMonoStereo) +{ +#define FM_BF_STEREO 0x1000 + unsigned short TmpReg = 0; + + if (pMonoStereo) { + fm_reg_read(FM_RSSI_IND, &TmpReg); + *pMonoStereo = (TmpReg & FM_BF_STEREO) >> 12; + } else { + WCN_DBG(FM_ERR | CHIP, "MonoStero: para err\n"); + return false; + } + + WCN_DBG(FM_NTC | CHIP, "Get MonoStero:0x%04x\n", *pMonoStereo); + return true; +} + +static signed int mt6580_SetMonoStereo(signed int MonoStereo) +{ + signed int ret = 0; + + WCN_DBG(FM_NTC | CHIP, "set to %s\n", MonoStereo ? "mono" : "auto"); + fm_top_reg_write(0x50, 0x0007); + + if (MonoStereo) { /*mono */ + ret = fm_set_bits(0x75, 0x0008, ~0x0008); + } else { /*auto switch */ + + ret = fm_set_bits(0x75, 0x0000, ~0x0008); + } + + fm_top_reg_write(0x50, 0x000F); + return ret; +} + +static signed int mt6580_GetCapArray(signed int *ca) +{ + unsigned short dataRead = 0; + unsigned short tmp = 0; + + if (ca == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_reg_read(0x60, &tmp); + fm_reg_write(0x60, tmp & 0xFFF7); /* 0x60 D3=0 */ + + fm_reg_read(0x26, &dataRead); + *ca = dataRead; + + fm_reg_write(0x60, tmp); /* 0x60 D3=1 */ + return 0; +} + +/* + * mt6580_GetCurPamd - get current freq's PAMD value + * PA=PAMD + * If PA>511 then PAMD(dB)= (PA-1024)/16*6, + * else PAMD(dB)=PA/16*6 + */ +static bool mt6580_GetCurPamd(unsigned short *pPamdLevl) +{ + unsigned short tmp_reg = 0; + unsigned short dBvalue, valid_cnt = 0; + int i, total = 0; + + for (i = 0; i < 8; i++) { + if (fm_reg_read(FM_ADDR_PAMD, &tmp_reg)) { + *pPamdLevl = 0; + return false; + } + + tmp_reg &= 0x03FF; + dBvalue = (tmp_reg > 256) ? ((512 - tmp_reg) * 6 / 16) : 0; + if (dBvalue != 0) { + total += dBvalue; + valid_cnt++; + WCN_DBG(FM_DBG | CHIP, "[%d]PAMD=%d\n", i, dBvalue); + } + fm_delayms(3); + } + if (valid_cnt != 0) + *pPamdLevl = total / valid_cnt; + else + *pPamdLevl = 0; + + WCN_DBG(FM_NTC | CHIP, "PAMD=%d\n", *pPamdLevl); + return true; +} + +static signed int mt6580_i2s_info_get(signed int *ponoff, signed int *pmode, signed int *psample) +{ + if (ponoff == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (pmode == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (psample == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + *ponoff = fm_config.aud_cfg.i2s_info.status; + *pmode = fm_config.aud_cfg.i2s_info.mode; + *psample = fm_config.aud_cfg.i2s_info.rate; + + return 0; +} + +static signed int mt6580fm_get_audio_info(struct fm_audio_info_t *data) +{ + memcpy(data, &fm_config.aud_cfg, sizeof(struct fm_audio_info_t)); + return 0; +} + +static signed int mt6580_hw_info_get(struct fm_hw_info *req) +{ + if (req == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + req->chip_id = mt6580_hw_info.chip_id; + req->eco_ver = mt6580_hw_info.eco_ver; + req->patch_ver = mt6580_hw_info.patch_ver; + req->rom_ver = mt6580_hw_info.rom_ver; + + return 0; +} + +static signed int mt6580_pre_search(void) +{ + mt6580_RampDown(); + /* disable audio output I2S Rx mode */ + fm_host_reg_write(0x80101054, 0x00000000); + /* disable audio output I2S Tx mode */ + fm_reg_write(0x9B, 0x0000); + + return 0; +} + +static signed int mt6580_restore_search(void) +{ + mt6580_RampDown(); + /* set audio output I2S Tx mode */ + fm_reg_write(0x9B, 0xF9AB); + /* set audio output I2S Rx mode */ + fm_host_reg_write(0x80101054, 0x00003f35); + return 0; +} + +static signed int mt6580_soft_mute_tune(unsigned short freq, signed int *rssi, signed int *valid) +{ + signed int ret = 0; + unsigned short pkt_size; + struct mt6580_full_cqi *p_cqi; + signed int RSSI = 0, PAMD = 0, MR = 0, ATDC = 0; + unsigned int PRX = 0, ATDEV = 0; + unsigned short softmuteGainLvl = 0; + unsigned short freq_reg = 0; + + /* add this paragragh to resolve FM sensitivity bad in low band issue */ +#if 0 + ret = mt6580_chan_para_get(freq); + if (ret == 2) + ret = fm_set_bits(FM_CHANNEL_SET, 0x2000, 0x0FFF); /* mdf HiLo */ + else + ret = fm_set_bits(FM_CHANNEL_SET, 0x0000, 0x0FFF); /* clear FA/HL/ATJ */ +#endif + freq_reg = freq; + if (fm_get_channel_space(freq_reg) == 0) + freq_reg *= 10; + + ret = fm_reg_write(0x60, 0x00000007); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x60 failed\n"); + + if ((freq_reg >= 6500) && (freq_reg <= 7290)) { + ret = fm_reg_write(0x39, 0xd002); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } else if ((freq_reg >= 7295) && (freq_reg <= 8410)) { + ret = fm_reg_write(0x39, 0xce02); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } else if ((freq_reg >= 8415) && (freq_reg <= 9815)) { + ret = fm_reg_write(0x39, 0xcc02); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } else if ((freq_reg >= 9820) && (freq_reg <= 9830)) { + ret = fm_reg_write(0x39, 0xca02); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } else if ((freq_reg >= 9835) && (freq_reg <= 9940)) { + ret = fm_reg_write(0x39, 0xcc02); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } else if ((freq_reg >= 9845) && (freq_reg <= 10800)) { + ret = fm_reg_write(0x39, 0xca02); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } else { + ret = fm_reg_write(0x39, 0xca02); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x39 failed\n"); + } + + ret = fm_reg_write(0x60, 0x0000000f); + if (ret) + WCN_DBG(FM_ERR | CHIP, "set freq wr 0x60 failed\n"); + /* end */ + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_full_cqi_req(cmd_buf, TX_BUF_SIZE, &freq, 1, 1); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_SM_TUNE, SW_RETRY_CNT, SM_TUNE_TIMEOUT, fm_get_read_result); + FM_UNLOCK(cmd_buf_lock); + + if (!ret && fm_res) { + WCN_DBG(FM_NTC | CHIP, "smt cqi size %d\n", fm_res->cqi[0]); + p_cqi = (struct mt6580_full_cqi *)&fm_res->cqi[2]; + /* just for debug */ + WCN_DBG(FM_NTC | CHIP, + "freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", + p_cqi->ch, p_cqi->rssi, p_cqi->pamd, p_cqi->pr, p_cqi->fpamd, p_cqi->mr, + p_cqi->atdc, p_cqi->prx, p_cqi->atdev, p_cqi->smg, p_cqi->drssi); + RSSI = ((p_cqi->rssi & 0x03FF) >= 512) ? ((p_cqi->rssi & 0x03FF) - 1024) : (p_cqi->rssi & 0x03FF); + PAMD = ((p_cqi->pamd & 0x1FF) >= 256) ? ((p_cqi->pamd & 0x01FF) - 512) : (p_cqi->pamd & 0x01FF); + MR = ((p_cqi->mr & 0x01FF) >= 256) ? ((p_cqi->mr & 0x01FF) - 512) : (p_cqi->mr & 0x01FF); + ATDC = (p_cqi->atdc >= 32768) ? (65536 - p_cqi->atdc) : (p_cqi->atdc); + if (ATDC < 0) + ATDC = (~(ATDC)) - 1; /* Get abs value of ATDC */ + + PRX = (p_cqi->prx & 0x00FF); + ATDEV = p_cqi->atdev; + softmuteGainLvl = p_cqi->smg; + /* check if the channel is valid according to each CQIs */ + if ((fm_config.rx_cfg.long_ana_rssi_th <= RSSI) + && (fm_config.rx_cfg.pamd_th >= PAMD) + && (fm_config.rx_cfg.atdc_th >= ATDC) + && (fm_config.rx_cfg.mr_th <= MR) + && (fm_config.rx_cfg.prx_th <= PRX) + && (ATDEV >= ATDC) /* sync scan algorithm */ + && (fm_config.rx_cfg.smg_th <= softmuteGainLvl)) { + *valid = true; + } else { + *valid = false; + } + *rssi = RSSI; +/* if(RSSI < -296) +* WCN_DBG(FM_NTC | CHIP, "rssi\n"); +* else if(PAMD > -12) +* WCN_DBG(FM_NTC | CHIP, "PAMD\n"); +* else if(ATDC > 3496) +* WCN_DBG(FM_NTC | CHIP, "ATDC\n"); +* else if(MR < -67) +* WCN_DBG(FM_NTC | CHIP, "MR\n"); +* else if(PRX < 80) +* WCN_DBG(FM_NTC | CHIP, "PRX\n"); +* else if(ATDEV < ATDC) +* WCN_DBG(FM_NTC | CHIP, "ATDEV\n"); +* else if(softmuteGainLvl < 16421) +* WCN_DBG(FM_NTC | CHIP, "softmuteGainLvl\n"); +*/ + } else { + WCN_DBG(FM_ALT | CHIP, "smt get CQI failed\n"); + return false; + } + WCN_DBG(FM_NTC | CHIP, "valid=%d\n", *valid); + return true; +} + +static bool mt6580_em_test(unsigned short group_idx, unsigned short item_idx, unsigned int item_value) +{ + return true; +} + +/* +*parm: +* parm.th_type: 0, RSSI. 1,desense RSSI. 2,SMG. +* parm.th_val: threshold value +*/ +static signed int mt6580_set_search_th(signed int idx, signed int val, signed int reserve) +{ + switch (idx) { + case 0: + { + fm_config.rx_cfg.long_ana_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set rssi th =%d\n", val); + break; + } + case 1: + { + fm_config.rx_cfg.desene_rssi_th = val; + WCN_DBG(FM_NTC | CHIP, "set desense rssi th =%d\n", val); + break; + } + case 2: + { + fm_config.rx_cfg.smg_th = val; + WCN_DBG(FM_NTC | CHIP, "set smg th =%d\n", val); + break; + } + default: + break; + } + return 0; +} + +static signed int MT6580fm_low_power_wa_default(signed int fmon) +{ + return 0; +} + +signed int fm_low_ops_register(struct fm_callback *cb, struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,bi invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_get == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_get invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cb->cur_freq_set == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,cb->cur_freq_set invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_cb_op = cb; + + bi->pwron = mt6580_pwron; + bi->pwroff = mt6580_pwroff; + bi->chipid_get = mt6580_get_chipid; + bi->mute = mt6580_Mute; + bi->rampdown = mt6580_RampDown; + bi->pwrupseq = mt6580_PowerUp; + bi->pwrdownseq = mt6580_PowerDown; + bi->setfreq = mt6580_SetFreq; + bi->low_pwr_wa = MT6580fm_low_power_wa_default; + bi->get_aud_info = mt6580fm_get_audio_info; + bi->rssiget = mt6580_GetCurRSSI; + bi->volset = mt6580_SetVol; + bi->volget = mt6580_GetVol; + bi->dumpreg = mt6580_dump_reg; + bi->msget = mt6580_GetMonoStereo; + bi->msset = mt6580_SetMonoStereo; + bi->pamdget = mt6580_GetCurPamd; + bi->em = mt6580_em_test; + bi->anaswitch = mt6580_SetAntennaType; + bi->anaget = mt6580_GetAntennaType; + bi->caparray_get = mt6580_GetCapArray; + bi->hwinfo_get = mt6580_hw_info_get; + bi->i2s_get = mt6580_i2s_info_get; + bi->is_dese_chan = mt6580_is_dese_chan; + bi->softmute_tune = mt6580_soft_mute_tune; + bi->desense_check = mt6580_desense_check; + bi->cqi_log = mt6580_full_cqi_get; + bi->pre_search = mt6580_pre_search; + bi->restore_search = mt6580_restore_search; + bi->set_search_th = mt6580_set_search_th; + + cmd_buf_lock = fm_lock_create("80_cmd"); + ret = fm_lock_get(cmd_buf_lock); + + cmd_buf = fm_zalloc(TX_BUF_SIZE + 1); + + if (!cmd_buf) { + WCN_DBG(FM_ALT | CHIP, "6580 fm lib alloc tx buf failed\n"); + ret = -1; + } +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ + cqi_fifo = fm_fifo_create("6628_cqi_fifo", sizeof(struct adapt_fm_cqi), 640); + if (!cqi_fifo) { + WCN_DBG(FM_ALT | CHIP, "6627 fm lib create cqi fifo failed\n"); + ret = -1; + } +#endif + + return ret; +} + +signed int fm_low_ops_unregister(struct fm_basic_interface *bi) +{ + signed int ret = 0; + /* Basic functions. */ + if (bi == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + +#if 0 /* def CONFIG_MTK_FM_50KHZ_SUPPORT */ + fm_fifo_release(cqi_fifo); +#endif + + if (cmd_buf) { + fm_free(cmd_buf); + cmd_buf = NULL; + } + + ret = fm_lock_put(cmd_buf_lock); + fm_memset(bi, 0, sizeof(struct fm_basic_interface)); + return ret; +} + +/* static struct fm_pub pub; */ +/* static struct fm_pub_cb *pub_cb = &pub.pub_tbl; */ + +static const unsigned short mt6580_mcu_dese_list[] = { + 0 +}; + +static const unsigned short mt6580_gps_dese_list[] = { + 7850, 7860 +}; + +static const signed char mt6580_chan_para_map[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6500~6595 */ + 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, /* 6600~6695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6700~6795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6800~6895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, /* 6900~6995 */ + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7000~7095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7100~7195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, /* 7200~7295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, /* 7300~7395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7400~7495 */ + 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, /* 7500~7595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7600~7695 */ + 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7700~7795 */ + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, /* 7800~7895 */ + 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7900~7995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8000~8095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, /* 8100~8195 */ + 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8200~8295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, /* 8300~8395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8400~8495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8500~8595 */ + 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, /* 8600~8695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8700~8795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8800~8895 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8900~8995 */ + 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9000~9095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9100~9195 */ + 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, /* 9200~9295 */ + 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9300~9395 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9400~9495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9500~9595 */ + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, /* 9600~9695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9700~9795 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9800~9895 */ + 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9900~9995 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10000~10095 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10100~10195 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10200~10295 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10300~10395 */ + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10400~10495 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10500~10595 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10600~10695 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10700~10795 */ + 0 /* 10800 */ +}; + +static const unsigned short mt6580_scan_dese_list[] = { + 6700, 7800, 9210, 9220, 9300, 1040, 1041 +}; + +static const unsigned short mt6580_TDD_list[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6500~6595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6600~6695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6700~6795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6800~6895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 6900~6995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7000~7095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7100~7195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7200~7295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7300~7395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7400~7495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7500~7595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7600~7695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7700~7795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7800~7895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 7900~7995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8000~8095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8100~8195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8200~8295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8300~8395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8400~8495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8500~8595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8600~8695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8700~8795 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8800~8895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 8900~8995 */ + 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, /* 9000~9095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9100~9195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9200~9295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9300~9395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9400~9495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9500~9595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9600~9695 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9700~9795 */ + 0x0000, 0x0101, 0x0000, 0x0000, 0x0000, /* 9800~9895 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 9900~9995 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10000~10095 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10100~10195 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10200~10295 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10300~10395 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10400~10495 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10500~10595 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 10600~10695 */ + 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, /* 10700~10795 */ + 0x0000 /* 10800 */ +}; + +static const unsigned short mt6580_TDD_Mask[] = { + 0x0001, 0x0010, 0x0100, 0x1000 +}; + +/* return value: 0, not a de-sense channel; 1, this is a de-sense channel; else error no */ +static signed int mt6580_is_dese_chan(unsigned short freq) +{ + signed int size; + + /* return 0;//HQA only :skip desense channel check. */ + size = ARRAY_SIZE(mt6580_scan_dese_list); + + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + while (size) { + if (mt6580_scan_dese_list[size - 1] == freq) + return 1; + + size--; + } + + return 0; +} + +/* return value: +*1, is desense channel and rssi is less than threshold; +*0, not desense channel or it is but rssi is more than threshold. +*/ +static signed int mt6580_desense_check(unsigned short freq, signed int rssi) +{ + if (mt6580_is_dese_chan(freq)) { + if (rssi < fm_config.rx_cfg.desene_rssi_th) + return 1; + + WCN_DBG(FM_DBG | CHIP, "desen_rssi %d th:%d\n", rssi, fm_config.rx_cfg.desene_rssi_th); + } + return 0; +} +#if 0 +static bool mt6580_TDD_chan_check(unsigned short freq) +{ + unsigned int i = 0; + unsigned short freq_tmp = freq; + signed int ret = 0; + + ret = fm_get_channel_space(freq_tmp); + if (ret == 0) + freq_tmp *= 10; + else if (-1 == ret) + return false; + + i = (freq_tmp - 6500) / 5; + if ((i / 4) >= ARRAY_SIZE(mt6580_TDD_list)) { + WCN_DBG(FM_ERR | CHIP, "Freq index out of range(%d),max(%zd)\n", + i / 4, ARRAY_SIZE(mt6580_TDD_list)); + return false; + } + + WCN_DBG(FM_NTC | CHIP, "Freq %d is 0x%4x, mask is 0x%4x\n", freq, (mt6580_TDD_list[i / 4]), + mt6580_TDD_Mask[i % 4]); + if (mt6580_TDD_list[i / 4] & mt6580_TDD_Mask[i % 4]) { + WCN_DBG(FM_NTC | CHIP, "Freq %d use TDD solution\n", freq); + return true; + } else + return false; +} +#endif +/* get channel parameter, HL side/ FA / ATJ */ +static unsigned short mt6580_chan_para_get(unsigned short freq) +{ + signed int pos, size; + + /* return 0;//for HQA only: skip FA/HL/ATJ */ + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + if (freq < 6500) + return 0; + + pos = (freq - 6500) / 5; + + size = ARRAY_SIZE(mt6580_chan_para_map); + + pos = (pos > (size - 1)) ? (size - 1) : pos; + + return mt6580_chan_para_map[pos]; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/chips/soc/pub/soc_fm_rds.c b/drivers/misc/mediatek/connectivity/fmradio/chips/soc/pub/soc_fm_rds.c new file mode 100644 index 00000000000000..49d9ebef5803dd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/chips/soc/pub/soc_fm_rds.c @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_rds.h" +#include "soc_fm_reg.h" +#include "fm_cmd.h" + +static bool bRDS_FirstIn; /* false */ +static unsigned int gBLER_CHK_INTERVAL = 500; +static unsigned short GOOD_BLK_CNT = 0, BAD_BLK_CNT; +static unsigned char BAD_BLK_RATIO; + +static struct fm_basic_interface *fm_bi; + +static bool mt6580_RDS_support(void); +static signed int mt6580_RDS_enable(void); +static signed int mt6580_RDS_disable(void); +static unsigned short mt6580_RDS_Get_GoodBlock_Counter(void); +static unsigned short mt6580_RDS_Get_BadBlock_Counter(void); +static unsigned char mt6580_RDS_Get_BadBlock_Ratio(void); +static unsigned int mt6580_RDS_Get_BlerCheck_Interval(void); +/* static void mt6580_RDS_GetData(unsigned short *data, unsigned short datalen); */ +static void mt6580_RDS_Init_Data(struct rds_t *pstRDSData); + +static bool mt6580_RDS_support(void) +{ + return true; +} + +static signed int mt6580_RDS_enable(void) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | RDSC, "rds enable\n"); + ret = fm_reg_read(FM_RDS_CFG0, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable read 0x80 fail\n"); + return ret; + } + ret = fm_reg_write(FM_RDS_CFG0, 6); /* set buf_start_th */ + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable write 0x80 fail\n"); + return ret; + } + ret = fm_reg_read(FM_MAIN_CTRL, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable read 0x63 fail\n"); + return ret; + } + ret = fm_reg_write(FM_MAIN_CTRL, dataRead | (RDS_MASK)); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds enable write 0x63 fail\n"); + return ret; + } + + return ret; +} + +static signed int mt6580_RDS_disable(void) +{ + signed int ret = 0; + unsigned short dataRead = 0; + + WCN_DBG(FM_DBG | RDSC, "rds disable\n"); + ret = fm_reg_read(FM_MAIN_CTRL, &dataRead); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds disable read 0x63 fail\n"); + return ret; + } + ret = fm_reg_write(FM_MAIN_CTRL, dataRead & (~RDS_MASK)); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "rds disable write 0x63 fail\n"); + return ret; + } + + return ret; +} + +static unsigned short mt6580_RDS_Get_GoodBlock_Counter(void) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RDS_GOODBK_CNT, &tmp_reg); + GOOD_BLK_CNT = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get good block cnt:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static unsigned short mt6580_RDS_Get_BadBlock_Counter(void) +{ + unsigned short tmp_reg = 0; + + fm_reg_read(FM_RDS_BADBK_CNT, &tmp_reg); + BAD_BLK_CNT = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get bad block cnt:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static unsigned char mt6580_RDS_Get_BadBlock_Ratio(void) +{ + unsigned short tmp_reg; + unsigned short gbc; + unsigned short bbc; + + gbc = mt6580_RDS_Get_GoodBlock_Counter(); + bbc = mt6580_RDS_Get_BadBlock_Counter(); + + if ((gbc + bbc) > 0) + tmp_reg = (unsigned char) (bbc * 100 / (gbc + bbc)); + else + tmp_reg = 0; + + BAD_BLK_RATIO = tmp_reg; + WCN_DBG(FM_DBG | RDSC, "get badblock ratio:%d\n", (signed int) tmp_reg); + + return tmp_reg; +} + +static signed int mt6580_RDS_BlockCounter_Reset(void) +{ + mt6580_RDS_disable(); + mt6580_RDS_enable(); + + return 0; +} + +static unsigned int mt6580_RDS_Get_BlerCheck_Interval(void) +{ + return gBLER_CHK_INTERVAL; +} + +static signed int mt6580_RDS_BlerCheck(struct rds_t *dst) +{ + return 0; +} + +#if 0 +static void RDS_Recovery_Handler(void) +{ + unsigned short tempData = 0; + + do { + fm_reg_read(FM_RDS_DATA_REG, &tempData); + fm_reg_read(FM_RDS_POINTER, &tempData); + } while (tempData & 0x3); +} +#endif + +#if 0 +static void mt6580_RDS_GetData(unsigned short *data, unsigned short datalen) +{ +#define RDS_GROUP_DIFF_OFS 0x007C +#define RDS_FIFO_DIFF 0x007F +#define RDS_CRC_BLK_ADJ 0x0020 +#define RDS_CRC_CORR_CNT 0x001E +#define RDS_CRC_INFO 0x0001 + + unsigned short CRC = 0, i = 0, RDS_adj = 0, RDSDataCount = 0, FM_WARorrCnt = 0; + unsigned short temp = 0, OutputPofm_s32 = 0; + + WCN_DBG(FM_DBG | RDSC, "get data\n"); + fm_reg_read(FM_RDS_FIFO_STATUS0, &temp); + RDSDataCount = ((RDS_GROUP_DIFF_OFS & temp) << 2); + + if ((temp & RDS_FIFO_DIFF) >= 4) { + /* block A data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 10; + CRC |= (temp & RDS_CRC_INFO) << 3; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 11); + fm_reg_read(FM_RDS_DATA_REG, &data[0]); + + /* block B data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 9; + CRC |= (temp & RDS_CRC_INFO) << 2; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 7); + fm_reg_read(FM_RDS_DATA_REG, &data[1]); + + /* block C data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 8; + CRC |= (temp & RDS_CRC_INFO) << 1; + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) << 3); + fm_reg_read(FM_RDS_DATA_REG, &data[2]); + + /* block D data and info handling */ + fm_reg_read(FM_RDS_INFO, &temp); + RDS_adj |= (temp & RDS_CRC_BLK_ADJ) << 7; + CRC |= (temp & RDS_CRC_INFO); + FM_WARorrCnt |= ((temp & RDS_CRC_CORR_CNT) >> 1); + fm_reg_read(FM_RDS_DATA_REG, &data[3]); + + data[4] = (CRC | RDS_adj | RDSDataCount); + data[5] = FM_WARorrCnt; + + fm_reg_read(FM_RDS_PWDI, &data[6]); + fm_reg_read(FM_RDS_PWDQ, &data[7]); + + fm_reg_read(FM_RDS_POINTER, &OutputPofm_s32); + + /* Go fm_s32o RDS recovery handler while RDS output pofm_s32 doesn't align to 4 in numeric */ + if (OutputPofm_s32 & 0x3) + RDS_Recovery_Handler(); + + } else { + for (; i < 8; i++) + data[i] = 0; + } +} +#endif + +static void mt6580_RDS_Init_Data(struct rds_t *pstRDSData) +{ + fm_memset(pstRDSData, 0, sizeof(struct rds_t)); + bRDS_FirstIn = true; + + pstRDSData->event_status = 0x0000; + fm_memset(pstRDSData->RT_Data.TextData, 0x20, sizeof(pstRDSData->RT_Data.TextData)); + fm_memset(pstRDSData->PS_Data.PS, '\0', sizeof(pstRDSData->PS_Data.PS)); + fm_memset(pstRDSData->PS_ON, 0x20, sizeof(pstRDSData->PS_ON)); +} + +bool mt6580_RDS_OnOff(struct rds_t *dst, bool bFlag) +{ + signed int ret = 0; + + if (mt6580_RDS_support() == false) { + WCN_DBG(FM_ALT | RDSC, "mt6580_RDS_OnOff failed, RDS not support\n"); + return false; + } + + if (bFlag) { + mt6580_RDS_Init_Data(dst); + ret = mt6580_RDS_enable(); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "mt6580_RDS_OnOff enable failed\n"); + return false; + } + } else { + mt6580_RDS_Init_Data(dst); + ret = mt6580_RDS_disable(); + if (ret) { + WCN_DBG(FM_NTC | RDSC, "mt6580_RDS_OnOff disable failed\n"); + return false; + } + } + + return true; +} + +DEFINE_RDSLOG(mt6580_rds_log); + +/* mt6580_RDS_Efm_s32_Handler - response FM RDS interrupt + * @fm - main data structure of FM driver + * This function first get RDS raw data, then call RDS spec parser + */ +static signed int mt6580_rds_parser(struct rds_t *rds_dst, struct rds_rx_t *rds_raw, + signed int rds_size, unsigned short(*getfreq) (void)) +{ + mt6580_rds_log.log_in(&mt6580_rds_log, rds_raw, rds_size); + return rds_parser(rds_dst, rds_raw, rds_size, getfreq); +} + +static signed int mt6580_rds_log_get(struct rds_rx_t *dst, signed int *dst_len) +{ + return mt6580_rds_log.log_out(&mt6580_rds_log, dst, dst_len); +} + +static signed int mt6580_rds_gc_get(struct rds_group_cnt_t *dst, struct rds_t *rdsp) +{ + return rds_grp_counter_get(dst, &rdsp->gc); +} + +static signed int mt6580_rds_gc_reset(struct rds_t *rdsp) +{ + return rds_grp_counter_reset(&rdsp->gc); +} + +signed int fm_rds_ops_register(struct fm_basic_interface *bi, struct fm_rds_interface *ri) +{ + signed int ret = 0; + + if (ri == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,ri invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_bi = bi; + + ri->rds_blercheck = mt6580_RDS_BlerCheck; + ri->rds_onoff = mt6580_RDS_OnOff; + ri->rds_parser = mt6580_rds_parser; + ri->rds_gbc_get = mt6580_RDS_Get_GoodBlock_Counter; + ri->rds_bbc_get = mt6580_RDS_Get_BadBlock_Counter; + ri->rds_bbr_get = mt6580_RDS_Get_BadBlock_Ratio; + ri->rds_bc_reset = mt6580_RDS_BlockCounter_Reset; + ri->rds_bci_get = mt6580_RDS_Get_BlerCheck_Interval; + ri->rds_log_get = mt6580_rds_log_get; + ri->rds_gc_get = mt6580_rds_gc_get; + ri->rds_gc_reset = mt6580_rds_gc_reset; + return ret; +} + +signed int fm_rds_ops_unregister(struct fm_rds_interface *ri) +{ + signed int ret = 0; + + if (ri == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,ri invalid pointer\n", __func__); + return -FM_EPARA; + } + + fm_bi = NULL; + fm_memset(ri, 0, sizeof(struct fm_rds_interface)); + return ret; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/core/fm_cmd.c b/drivers/misc/mediatek/connectivity/fmradio/core/fm_cmd.c new file mode 100644 index 00000000000000..e79d41b5200d68 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/core/fm_cmd.c @@ -0,0 +1,842 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ + +#include <linux/kernel.h> +#include <linux/types.h> + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_rds.h" +#include "fm_config.h" +#include "fm_link.h" +#include "fm_cmd.h" + +signed int fm_bop_write(unsigned char addr, unsigned short value, unsigned char *buf, signed int size) +{ + if (size < (FM_WRITE_BASIC_OP_SIZE + 2)) { + WCN_DBG(FM_ERR | CHIP, "%s : left size(%d)/need size(%d)\n", + __func__, size, FM_WRITE_BASIC_OP_SIZE + 2); + return -1; + } + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s :buf invalid pointer\n", __func__); + return -2; + } + + buf[0] = FM_WRITE_BASIC_OP; + buf[1] = FM_WRITE_BASIC_OP_SIZE; + buf[2] = addr; + buf[3] = (unsigned char) ((value) & 0x00FF); + buf[4] = (unsigned char) ((value >> 8) & 0x00FF); + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4]); + + return FM_WRITE_BASIC_OP_SIZE + 2; +} + +signed int fm_bop_udelay(unsigned int value, unsigned char *buf, signed int size) +{ + if (size < (FM_UDELAY_BASIC_OP_SIZE + 2)) { + WCN_DBG(FM_ERR | CHIP, "%s : left size(%d)/need size(%d)\n", + __func__, size, FM_UDELAY_BASIC_OP_SIZE + 2); + return -1; + } + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s :buf invalid pointer\n", __func__); + return -2; + } + + buf[0] = FM_UDELAY_BASIC_OP; + buf[1] = FM_UDELAY_BASIC_OP_SIZE; + buf[2] = (unsigned char) ((value) & 0x000000FF); + buf[3] = (unsigned char) ((value >> 8) & 0x000000FF); + buf[4] = (unsigned char) ((value >> 16) & 0x000000FF); + buf[5] = (unsigned char) ((value >> 24) & 0x000000FF); + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + + return FM_UDELAY_BASIC_OP_SIZE + 2; +} + +signed int fm_bop_rd_until(unsigned char addr, unsigned short mask, unsigned short value, + unsigned char *buf, signed int size) +{ + if (size < (FM_RD_UNTIL_BASIC_OP_SIZE + 2)) { + WCN_DBG(FM_ERR | CHIP, "%s : left size(%d)/need size(%d)\n", + __func__, size, FM_RD_UNTIL_BASIC_OP_SIZE + 2); + return -1; + } + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s :buf invalid pointer\n", __func__); + return -2; + } + + buf[0] = FM_RD_UNTIL_BASIC_OP; + buf[1] = FM_RD_UNTIL_BASIC_OP_SIZE; + buf[2] = addr; + buf[3] = (unsigned char) ((mask) & 0x00FF); + buf[4] = (unsigned char) ((mask >> 8) & 0x00FF); + buf[5] = (unsigned char) ((value) & 0x00FF); + buf[6] = (unsigned char) ((value >> 8) & 0x00FF); + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5], buf[6]); + + return FM_RD_UNTIL_BASIC_OP_SIZE + 2; +} + +signed int fm_bop_modify(unsigned char addr, unsigned short mask_and, unsigned short mask_or, + unsigned char *buf, signed int size) +{ + if (size < (FM_MODIFY_BASIC_OP_SIZE + 2)) { + WCN_DBG(FM_ERR | CHIP, "%s : left size(%d)/need size(%d)\n", + __func__, size, FM_MODIFY_BASIC_OP_SIZE + 2); + return -1; + } + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s :buf invalid pointer\n", __func__); + return -2; + } + + buf[0] = FM_MODIFY_BASIC_OP; + buf[1] = FM_MODIFY_BASIC_OP_SIZE; + buf[2] = addr; + buf[3] = (unsigned char) ((mask_and) & 0x00FF); + buf[4] = (unsigned char) ((mask_and >> 8) & 0x00FF); + buf[5] = (unsigned char) ((mask_or) & 0x00FF); + buf[6] = (unsigned char) ((mask_or >> 8) & 0x00FF); + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5], buf[6]); + + return FM_MODIFY_BASIC_OP_SIZE + 2; +} + +signed int fm_bop_top_write(unsigned short addr, unsigned int value, unsigned char *buf, signed int size) +{ + if (size < (FM_TOP_WRITE_BOP_SIZE + 2)) { + WCN_DBG(FM_ERR | CHIP, "%s : left size(%d)/need size(%d)\n", + __func__, size, FM_TOP_WRITE_BOP_SIZE + 2); + return -1; + } + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s :buf invalid pointer\n", __func__); + return -2; + } + + buf[0] = FM_WRITE_SPI_BASIC_OP; + buf[1] = FM_TOP_WRITE_BOP_SIZE; + buf[2] = top_index; + buf[3] = (unsigned char) ((addr) & 0x00FF); + buf[4] = (unsigned char) ((addr >> 8) & 0x00FF); + buf[5] = (unsigned char) ((value) & 0x00FF); + buf[6] = (unsigned char) ((value >> 8) & 0x00FF); + buf[7] = (unsigned char) ((value >> 16) & 0x00FF); + buf[8] = (unsigned char) ((value >> 24) & 0x00FF); + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], + buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]); + + return FM_TOP_WRITE_BOP_SIZE + 2; +} + +signed int fm_bop_top_rd_until(unsigned short addr, unsigned int mask, unsigned int value, + unsigned char *buf, signed int size) +{ + if (size < (FM_TOP_RD_UNTIL_BOP_SIZE + 2)) { + WCN_DBG(FM_ERR | CHIP, "%s : left size(%d)/need size(%d)\n", + __func__, size, FM_TOP_RD_UNTIL_BOP_SIZE + 2); + return -1; + } + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s :buf invalid pointer\n", __func__); + return -2; + } + + buf[0] = FM_RD_SPI_UNTIL_BASIC_OP; + buf[1] = FM_TOP_RD_UNTIL_BOP_SIZE; + buf[2] = top_index; + buf[3] = (unsigned char) ((addr) & 0x00FF); + buf[4] = (unsigned char) ((addr >> 8) & 0x00FF); + buf[5] = (unsigned char) ((mask) & 0x00FF); + buf[6] = (unsigned char) ((mask >> 8) & 0x00FF); + buf[7] = (unsigned char) ((mask >> 16) & 0x00FF); + buf[8] = (unsigned char) ((mask >> 24) & 0x00FF); + buf[9] = (unsigned char) ((value) & 0x00FF); + buf[10] = (unsigned char) ((value >> 8) & 0x00FF); + buf[11] = (unsigned char) ((value >> 16) & 0x00FF); + buf[12] = (unsigned char) ((value >> 24) & 0x00FF); + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], + buf[10], buf[11], buf[12]); + + return FM_TOP_RD_UNTIL_BOP_SIZE + 2; +} + +signed int fm_op_seq_combine_cmd(unsigned char *buf, unsigned char opcode, signed int pkt_size) +{ + signed int total_size = 0; + + if (buf == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s :buf invalid pointer\n", __func__); + return -1; + } + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = opcode; + buf[2] = (unsigned char) (pkt_size & 0x00FF); + buf[3] = (unsigned char) ((pkt_size >> 8) & 0x00FF); + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]); + + total_size = pkt_size + 4; + + return total_size; +} + +/* + * fm_patch_download - Wholechip FM Power Up: step 3, download patch to f/w, + * @buf - target buf + * @buf_size - buffer size + * @seg_num - total segments that this patch divided into + * @seg_id - No. of Segments: segment that will now be sent + * @src - patch source buffer + * @seg_len - segment size: segment that will now be sent + * return package size + */ +signed int fm_patch_download(unsigned char *buf, signed int buf_size, unsigned char seg_num, unsigned char seg_id, + const unsigned char *src, signed int seg_len) +{ + signed int pkt_size = 0; + unsigned char *dst = NULL; + + if (buf_size < TX_BUF_SIZE) + return -1; + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = FM_PATCH_DOWNLOAD_OPCODE; + pkt_size = 4; + + buf[pkt_size++] = seg_num; + buf[pkt_size++] = seg_id; + + if (seg_len > (buf_size - pkt_size)) + return -1; + + dst = &buf[pkt_size]; + pkt_size += seg_len; + + /* copy patch to tx buffer */ + while (seg_len--) { + *dst = *src; + src++; + dst++; + } + + buf[2] = (unsigned char) ((pkt_size - 4) & 0x00FF); + buf[3] = (unsigned char) (((pkt_size - 4) >> 8) & 0x00FF); + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5], buf[6]); + + return pkt_size; +} + +/* + * fm_coeff_download - Wholechip FM Power Up: step 3,download coeff to f/w, + * @buf - target buf + * @buf_size - buffer size + * @seg_num - total segments that this patch divided into + * @seg_id - No. of Segments: segment that will now be sent + * @src - patch source buffer + * @seg_len - segment size: segment that will now be sent + * return package size + */ +signed int fm_coeff_download(unsigned char *buf, signed int buf_size, unsigned char seg_num, unsigned char seg_id, + const unsigned char *src, signed int seg_len) +{ + signed int pkt_size = 0; + unsigned char *dst = NULL; + + if (buf_size < TX_BUF_SIZE) + return -1; + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = FM_COEFF_DOWNLOAD_OPCODE; + pkt_size = 4; + + buf[pkt_size++] = seg_num; + buf[pkt_size++] = seg_id; + + if (seg_len > (buf_size - pkt_size)) + return -1; + + dst = &buf[pkt_size]; + pkt_size += seg_len; + + /* copy patch to tx buffer */ + while (seg_len--) { + *dst = *src; + src++; + dst++; + } + + buf[2] = (unsigned char) ((pkt_size - 4) & 0x00FF); + buf[3] = (unsigned char) (((pkt_size - 4) >> 8) & 0x00FF); + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5], buf[6]); + + return pkt_size; +} + +/* + * fm_full_cqi_req - execute request cqi info action, + * @buf - target buf + * @buf_size - buffer size + * @freq - 7600 ~ 10800, freq array + * @cnt - channel count + * @type - request type, 1: a single channel; 2: multi channel; + * 3:multi channel with 100Khz step; 4: multi channel with 50Khz step + * + * return package size + */ +signed int fm_full_cqi_req(unsigned char *buf, signed int buf_size, unsigned short *freq, + signed int cnt, signed int type) +{ + signed int pkt_size = 0; + + if (buf_size < TX_BUF_SIZE) + return -1; + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = FM_SOFT_MUTE_TUNE_OPCODE; + pkt_size = 4; + + switch (type) { + case 1: + buf[pkt_size] = 0x0001; + pkt_size++; + buf[pkt_size] = (unsigned char) ((*freq) & 0x00FF); + pkt_size++; + buf[pkt_size] = (unsigned char) ((*freq >> 8) & 0x00FF); + pkt_size++; + break; + case 2: + buf[pkt_size] = 0x0002; + pkt_size++; + break; + case 3: + buf[pkt_size] = 0x0003; + pkt_size++; + break; + case 4: + buf[pkt_size] = 0x0004; + pkt_size++; + break; + default: + buf[pkt_size] = (unsigned short) type; + pkt_size++; + break; + } + + buf[2] = (unsigned char) ((pkt_size - 4) & 0x00FF); + buf[3] = (unsigned char) (((pkt_size - 4) >> 8) & 0x00FF); + + return pkt_size; +} + + +signed int fm_get_reg(unsigned char *buf, signed int buf_size, unsigned char addr) +{ + if (buf_size < TX_BUF_SIZE) + return -1; + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = FSPI_READ_OPCODE; + buf[2] = 0x01; + buf[3] = 0x00; + buf[4] = addr; + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4]); + return 5; +} + +signed int fm_set_reg(unsigned char *buf, signed int buf_size, unsigned char addr, unsigned short value) +{ + if (buf_size < TX_BUF_SIZE) + return -1; + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = FSPI_WRITE_OPCODE; + buf[2] = 0x03; + buf[3] = 0x00; + buf[4] = addr; + buf[5] = (unsigned char) ((value) & 0x00FF); + buf[6] = (unsigned char) ((value >> 8) & 0x00FF); + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5], buf[6]); + return 7; +} + +signed int fm_set_bits_reg(unsigned char *buf, signed int buf_size, unsigned char addr, + unsigned short bits, unsigned short mask) +{ + signed int pkt_size = 0; + + if (buf_size < TX_BUF_SIZE) + return -1; + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = 0x11; /* 0x11 this opcode won't be parsed as an opcode, so set here as spcial case. */ + pkt_size = 4; + pkt_size += fm_bop_modify(addr, mask, bits, &buf[pkt_size], buf_size - pkt_size); + + buf[2] = (unsigned char) ((pkt_size - 4) & 0x00FF); + buf[3] = (unsigned char) (((pkt_size - 4) >> 8) & 0x00FF); + + return pkt_size; +} + +/*top register read*/ +signed int fm_top_get_reg(unsigned char *buf, signed int buf_size, unsigned short addr) +{ + if (buf_size < TX_BUF_SIZE) + return -1; + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = CSPI_READ_OPCODE; + buf[2] = 0x03; + buf[3] = 0x00; + buf[4] = top_index; + buf[5] = (unsigned char) ((addr) & 0x00FF); + buf[6] = (unsigned char) ((addr >> 8) & 0x00FF); + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5], buf[6]); + return 7; +} + +signed int fm_top_set_reg(unsigned char *buf, signed int buf_size, unsigned short addr, unsigned int value) +{ + if (buf_size < TX_BUF_SIZE) + return -1; + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = CSPI_WRITE_OPCODE; + buf[2] = 0x07; + buf[3] = 0x00; + buf[4] = top_index; + buf[5] = (unsigned char) ((addr) & 0x00FF); + buf[6] = (unsigned char) ((addr >> 8) & 0x00FF); + buf[7] = (unsigned char) ((value) & 0x00FF); + buf[8] = (unsigned char) ((value >> 8) & 0x00FF); + buf[9] = (unsigned char) ((value >> 16) & 0x00FF); + buf[10] = (unsigned char) ((value >> 24) & 0x00FF); + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], + buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10]); + return 11; +} + +/*host register read*/ +signed int fm_host_get_reg(unsigned char *buf, signed int buf_size, unsigned int addr) +{ + if (buf_size < TX_BUF_SIZE) + return -1; + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = FM_HOST_READ_OPCODE; + buf[2] = 0x04; + buf[3] = 0x00; + buf[4] = (unsigned char) ((addr) & 0x00FF); + buf[5] = (unsigned char) ((addr >> 8) & 0x00FF); + buf[6] = (unsigned char) ((addr >> 16) & 0x00FF); + buf[7] = (unsigned char) ((addr >> 24) & 0x00FF); + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], + buf[3], buf[4], buf[5], buf[6], buf[7]); + return 8; +} + +signed int fm_host_set_reg(unsigned char *buf, signed int buf_size, unsigned int addr, unsigned int value) +{ + if (buf_size < TX_BUF_SIZE) + return -1; + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = FM_HOST_WRITE_OPCODE; + buf[2] = 0x08; + buf[3] = 0x00; + buf[4] = (unsigned char) ((addr) & 0x00FF); + buf[5] = (unsigned char) ((addr >> 8) & 0x00FF); + buf[6] = (unsigned char) ((addr >> 16) & 0x00FF); + buf[7] = (unsigned char) ((addr >> 24) & 0x00FF); + buf[8] = (unsigned char) ((value) & 0x00FF); + buf[9] = (unsigned char) ((value >> 8) & 0x00FF); + buf[10] = (unsigned char) ((value >> 16) & 0x00FF); + buf[11] = (unsigned char) ((value >> 24) & 0x00FF); + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]); + return 12; +} + +signed int fm_pmic_get_reg(unsigned char *buf, signed int buf_size, unsigned char addr) +{ + if (buf_size < TX_BUF_SIZE) + return -1; + + if (buf == NULL) + return -2; + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = FM_READ_PMIC_CR_OPCODE; + buf[2] = 0x01; + buf[3] = 0x00; + buf[4] = addr; + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], + buf[3], buf[4]); + return 5; +} + +signed int fm_pmic_set_reg(unsigned char *buf, signed int buf_size, unsigned char addr, unsigned int val) +{ + if (buf_size < TX_BUF_SIZE) + return -1; + + if (buf == NULL) + return -2; + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = FM_WRITE_PMIC_CR_OPCODE; + buf[2] = 0x05; + buf[3] = 0x00; + buf[4] = addr; + buf[5] = (unsigned char) ((val) & 0x00FF); + buf[6] = (unsigned char) ((val >> 8) & 0x00FF); + buf[7] = (unsigned char) ((val >> 16) & 0x00FF); + buf[8] = (unsigned char) ((val >> 24) & 0x00FF); + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8]); + return 9; +} + +signed int fm_pmic_mod_reg(unsigned char *buf, signed int buf_size, unsigned char addr, + unsigned int mask_and, unsigned int mask_or) +{ + if (buf_size < TX_BUF_SIZE) + return -1; + + if (buf == NULL) + return -2; + + buf[0] = FM_TASK_COMMAND_PKT_TYPE; + buf[1] = FM_MODIFY_PMIC_CR_OPCODE; + buf[2] = 0x09; + buf[3] = 0x00; + buf[4] = addr; + buf[5] = (unsigned char) ((mask_and) & 0x00FF); + buf[6] = (unsigned char) ((mask_and >> 8) & 0x00FF); + buf[7] = (unsigned char) ((mask_and >> 16) & 0x00FF); + buf[8] = (unsigned char) ((mask_and >> 24) & 0x00FF); + buf[9] = (unsigned char) ((mask_or) & 0x00FF); + buf[10] = (unsigned char) ((mask_or >> 8) & 0x00FF); + buf[11] = (unsigned char) ((mask_or >> 16) & 0x00FF); + buf[12] = (unsigned char) ((mask_or >> 24) & 0x00FF); + + WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], + buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12]); + + return 13; +} + +signed int fm_get_patch_path(signed int ver, unsigned char *buff, int buffsize, struct fm_patch_tbl *patch_tbl) +{ + signed int i; + signed int patch_len = 0; + signed int max = FM_ROM_MAX; + const signed char *ppath = NULL; + + /* check if the ROM version is defined or not */ + for (i = 0; i < max; i++) { + if (patch_tbl[i].idx == ver) { + ppath = patch_tbl[i].patch; + WCN_DBG(FM_NTC | CHIP, "Get ROM version OK\n"); + break; + } + } + + if (ppath == NULL) { + /* Load latest default patch */ + for (i = max; i > 0; i--) { + patch_len = fm_file_read(patch_tbl[i - 1].patch, buff, buffsize, 0); + if (patch_len >= 0) { + WCN_DBG(FM_NTC | CHIP, "undefined ROM version, load %s\n", patch_tbl[i - 1].patch); + return patch_len; + } + } + } else { + /* Load patch */ + patch_len = fm_file_read(ppath, buff, buffsize, 0); + if (patch_len >= 0) + return patch_len; + } + + /* get path failed */ + WCN_DBG(FM_ERR | CHIP, "No valid patch file\n"); + return -FM_EPATCH; +} + +signed int fm_get_coeff_path(signed int ver, unsigned char *buff, int buffsize, struct fm_patch_tbl *patch_tbl) +{ + signed int i; + signed int patch_len = 0; + const signed char *ppath = NULL; + signed int max = FM_ROM_MAX; + + /* check if the ROM version is defined or not */ + for (i = 0; i < max; i++) { + if (patch_tbl[i].idx == ver) { + ppath = patch_tbl[i].coeff; + WCN_DBG(FM_NTC | CHIP, "Get ROM version OK\n"); + break; + } + } + + if (ppath == NULL) { + /* Load default patch */ + for (i = max; i > 0; i--) { + patch_len = fm_file_read(patch_tbl[i - 1].coeff, buff, buffsize, 0); + if (patch_len >= 0) { + WCN_DBG(FM_NTC | CHIP, "undefined ROM version, load %s\n", patch_tbl[i - 1].coeff); + return patch_len; + } + } + } else { + /* Load patch by patch path*/ + patch_len = fm_file_read(ppath, buff, buffsize, 0); + if (patch_len >= 0) + return patch_len; + } + + /* get path failed */ + WCN_DBG(FM_ERR | CHIP, "No valid coeff file\n"); + return -FM_EPATCH; +} + +/* +* DspPatch - DSP download procedure +* @img - source dsp bin code +* @len - patch length in byte +* @type - rom/patch/coefficient/hw_coefficient +*/ +signed int fm_download_patch(const unsigned char *img, signed int len, enum IMG_TYPE type) +{ + unsigned char seg_num; + unsigned char seg_id = 0; + signed int seg_len; + signed int ret = 0; + unsigned short pkt_size; + + if (img == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (len <= 0) + return -1; + + seg_num = len / PATCH_SEG_LEN + 1; + WCN_DBG(FM_NTC | CHIP, "binary len:%d, seg num:%d\n", len, seg_num); + + switch (type) { + case IMG_PATCH: + + for (seg_id = 0; seg_id < seg_num; seg_id++) { + seg_len = ((seg_id + 1) < seg_num) ? PATCH_SEG_LEN : (len % PATCH_SEG_LEN); + WCN_DBG(FM_INF | CHIP, "patch,[seg_id:%d], [seg_len:%d]\n", seg_id, seg_len); + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = + fm_patch_download(cmd_buf, TX_BUF_SIZE, seg_num, seg_id, + &img[seg_id * PATCH_SEG_LEN], seg_len); + WCN_DBG(FM_INF | CHIP, "pkt_size:%d\n", (signed int) pkt_size); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_PATCH, SW_RETRY_CNT, PATCH_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ERR | CHIP, "fm_patch_download failed\n"); + return ret; + } + } + + break; + + case IMG_COEFFICIENT: + + for (seg_id = 0; seg_id < seg_num; seg_id++) { + seg_len = ((seg_id + 1) < seg_num) ? PATCH_SEG_LEN : (len % PATCH_SEG_LEN); + WCN_DBG(FM_INF | CHIP, "coeff,[seg_id:%d], [seg_len:%d]\n", seg_id, seg_len); + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = + fm_coeff_download(cmd_buf, TX_BUF_SIZE, seg_num, seg_id, + &img[seg_id * PATCH_SEG_LEN], seg_len); + WCN_DBG(FM_INF | CHIP, "pkt_size:%d\n", (signed int) pkt_size); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_COEFF, SW_RETRY_CNT, COEFF_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + if (ret) { + WCN_DBG(FM_ERR | CHIP, "fm_coeff_download failed\n"); + return ret; + } + } + + break; + default: + break; + } + + return 0; +} + +signed int fm_get_read_result(struct fm_res_ctx *result) +{ + if (result == NULL) { + WCN_DBG(FM_ERR | CHIP, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_res = result; + + return 0; +} + +signed int fm_reg_read(unsigned char addr, unsigned short *val) +{ + signed int ret = 0; + unsigned short pkt_size; + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_get_reg(cmd_buf, TX_BUF_SIZE, addr); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_FSPI_RD, SW_RETRY_CNT, FSPI_RD_TIMEOUT, fm_get_read_result); + + if (!ret && fm_res) + *val = fm_res->fspi_rd; + + FM_UNLOCK(cmd_buf_lock); + + return ret; +} + +signed int fm_reg_write(unsigned char addr, unsigned short val) +{ + signed int ret = 0; + unsigned short pkt_size; + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_set_reg(cmd_buf, TX_BUF_SIZE, addr, val); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_FSPI_WR, SW_RETRY_CNT, FSPI_WR_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + return ret; +} + +signed int fm_set_bits(unsigned char addr, unsigned short bits, unsigned short mask) +{ + signed int ret = 0; + unsigned short pkt_size; + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_set_bits_reg(cmd_buf, TX_BUF_SIZE, addr, bits, mask); + ret = fm_cmd_tx(cmd_buf, pkt_size, (1 << 0x11), SW_RETRY_CNT, FSPI_WR_TIMEOUT, NULL); + /* 0x11 this opcode won't be parsed as an opcode, so set here as spcial case. */ + FM_UNLOCK(cmd_buf_lock); + + return ret; +} + +signed int fm_top_reg_read(unsigned short addr, unsigned int *val) +{ + signed int ret = 0; + unsigned short pkt_size; + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_top_get_reg(cmd_buf, TX_BUF_SIZE, addr); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_CSPI_READ, SW_RETRY_CNT, FSPI_RD_TIMEOUT, fm_get_read_result); + + if (!ret && fm_res) + *val = fm_res->cspi_rd; + + FM_UNLOCK(cmd_buf_lock); + + return ret; +} + +signed int fm_top_reg_write(unsigned short addr, unsigned int val) +{ + signed int ret = 0; + unsigned short pkt_size; + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_top_set_reg(cmd_buf, TX_BUF_SIZE, addr, val); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_CSPI_WRITE, SW_RETRY_CNT, FSPI_WR_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + return ret; +} + +signed int fm_host_reg_read(unsigned int addr, unsigned int *val) +{ + signed int ret = 0; + unsigned short pkt_size; + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_host_get_reg(cmd_buf, TX_BUF_SIZE, addr); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_HOST_READ, SW_RETRY_CNT, FSPI_RD_TIMEOUT, fm_get_read_result); + + if (!ret && fm_res) + *val = fm_res->cspi_rd; + + FM_UNLOCK(cmd_buf_lock); + + return ret; +} + +signed int fm_host_reg_write(unsigned int addr, unsigned int val) +{ + signed int ret = 0; + unsigned short pkt_size; + + if (FM_LOCK(cmd_buf_lock)) + return -FM_ELOCK; + pkt_size = fm_host_set_reg(cmd_buf, TX_BUF_SIZE, addr, val); + ret = fm_cmd_tx(cmd_buf, pkt_size, FLAG_HOST_WRITE, SW_RETRY_CNT, FSPI_WR_TIMEOUT, NULL); + FM_UNLOCK(cmd_buf_lock); + + return ret; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/core/fm_config.c b/drivers/misc/mediatek/connectivity/fmradio/core/fm_config.c new file mode 100644 index 00000000000000..86610a6d33bd02 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/core/fm_config.c @@ -0,0 +1,624 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/string.h> +#include <linux/slab.h> + +#include "fm_typedef.h" +#include "fm_rds.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_stdlib.h" +#include "fm_patch.h" +#include "fm_config.h" + +struct fm_cust_cfg fm_config; +unsigned short g_fm_chipid; +enum fm_cfg_chip_type g_fm_chip_type = FM_CHIP_TYPE_MAX; + +#define FM_CUST_CFG_PATH "fm_cust.cfg" + +signed int to_upper_n(signed char *str, signed int len) +{ + signed int i = 0; + + for (i = 0; i < len; i++) { + if (('a' <= str[i]) && (str[i] <= 'z')) + str[i] = str[i] - ('a' - 'A'); + } + + return 0; +} + +signed int check_hex_str(signed char *str, signed int len) +{ + signed int i = 0; + + for (i = 0; i < len; i++) { + if ((('a' <= str[i]) && (str[i] <= 'z')) || (('A' <= str[i]) && (str[i] <= 'Z')) + || (('0' <= str[i]) && (str[i] <= '9'))) { + ; + } else { + return -1; + } + } + + return 0; +} + +signed int check_dec_str(signed char *str, signed int len) +{ + signed int i = 0; + + for (i = 0; i < len; i++) { + if (('0' <= str[i]) && (str[i] <= '9')) + ; + else + return -1; + } + + return 0; +} + +signed int ascii_to_hex(signed char *in_ascii, unsigned short *out_hex) +{ + signed int len = (signed int) strlen(in_ascii); + int i = 0; + unsigned short tmp; + + len = (len > 4) ? 4 : len; + + if (check_hex_str(in_ascii, len)) + return -1; + + to_upper_n(in_ascii, len); + *out_hex = 0; + + for (i = 0; i < len; i++) { + if (in_ascii[len - i - 1] < 'A') { + tmp = in_ascii[len - i - 1]; + *out_hex |= ((tmp - '0') << (4 * i)); + } else { + tmp = in_ascii[len - i - 1]; + *out_hex |= ((tmp - 'A' + 10) << (4 * i)); + } + } + + return 0; +} + +signed int ascii_to_dec(signed char *in_ascii, signed int *out_dec) +{ + signed int len = (signed int) strlen(in_ascii); + int i = 0; + int flag; + int multi = 1; + + len = (len > 10) ? 10 : len; + + if (in_ascii[0] == '-') { + flag = -1; + in_ascii += 1; + len -= 1; + } else { + flag = 1; + } + + if (check_dec_str(in_ascii, len)) + return -1; + + *out_dec = 0; + multi = 1; + + for (i = 0; i < len; i++) { + *out_dec += ((in_ascii[len - i - 1] - '0') * multi); + multi *= 10; + } + + *out_dec *= flag; + return 0; +} + +signed int trim_string(signed char **start) +{ + signed char *end = *start; + + /* Advance to non-space character */ + while (*(*start) == ' ') + (*start)++; + + /* Move to end of string */ + while (*end != '\0') + (end)++; + + /* Backup to non-space character */ + do { + end--; + } while ((end >= *start) && (*end == ' ')); + + /* Terminate string after last non-space character */ + *(++end) = '\0'; + return end - *start; +} + +signed int trim_path(signed char **start) +{ + signed char *end = *start; + + while (*(*start) == ' ') + (*start)++; + + while (*end != '\0') + (end)++; + + do { + end--; + } while ((end >= *start) && ((*end == ' ') || (*end == '\n') || (*end == '\r'))); + + *(++end) = '\0'; + return end - *start; +} + +signed int check_path(signed char *str, signed int len) +{ + signed int i = 0; + + for (i = 0; i < len; i++) { + if ((('a' <= str[i]) && (str[i] <= 'z')) || + (('A' <= str[i]) && (str[i] <= 'Z')) || + (('0' <= str[i]) && (str[i] <= '9')) || + ('/' == str[i]) || ('_' == str[i]) || + ('.' == str[i])) { + ; + } else { + return -1; + } + } + return 0; +} + +signed int cfg_parser(signed char *buffer, CFG_HANDLER handler, struct fm_cust_cfg *cfg) +{ + signed int ret = 0; + signed char *p = buffer; + signed char *group_start = NULL; + signed char *key_start = NULL; + signed char *value_start = NULL; + + enum fm_cfg_parser_state state = FM_CFG_STAT_NONE; + + if (p == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + for (p = buffer; *p != '\0'; p++) { + switch (state) { + case FM_CFG_STAT_NONE:{ + if (*p == '[') { + /* if we get char '[' in none state, it means a new group name start */ + state = FM_CFG_STAT_GROUP; + group_start = p + 1; + } else if (*p == COMMENT_CHAR) { + /* if we get char '#' in none state, it means a new comment start */ + state = FM_CFG_STAT_COMMENT; + } else if (!isspace(*p) && (*p != '\n') && (*p != '\r')) { + /* if we get an nonspace char in none state, it means a new key start */ + state = FM_CFG_STAT_KEY; + key_start = p; + } + + break; + } + case FM_CFG_STAT_GROUP:{ + if (*p == ']') { + /* if we get char ']' in group state, it means a group name complete */ + *p = '\0'; + /* FIX_ME */ + /* record group name */ + state = FM_CFG_STAT_NONE; + trim_string(&group_start); + /* WCN_DBG(FM_NTC|MAIN, "g=%s\n", group_start); */ + } + + break; + } + case FM_CFG_STAT_COMMENT:{ + if (*p == '\n') { + /* if we get char '\n' in comment state, it means new line start */ + state = FM_CFG_STAT_NONE; + group_start = p + 1; + } + + break; + } + case FM_CFG_STAT_KEY:{ + if (*p == DELIMIT_CHAR) { + /* if we get char '=' in key state, it means a key name complete */ + *p = '\0'; + /* FIX_ME */ + /* record key name */ + state = FM_CFG_STAT_VALUE; + value_start = p + 1; + trim_string(&key_start); + /* WCN_DBG(FM_NTC|MAIN, "k=%s\n", key_start); */ + } + + break; + } + case FM_CFG_STAT_VALUE:{ + if (*p == '\n' || *p == '\r') { + /* if we get char '\n' or '\r' in value state, it means a value complete */ + *p = '\0'; + /* record value */ + trim_string(&value_start); + /* WCN_DBG(FM_NTC|MAIN, "v=%s\n", value_start); */ + + if (handler) + ret = handler(group_start, key_start, value_start, cfg); + + state = FM_CFG_STAT_NONE; + } + + break; + } + default: + break; + } + } + + return ret; +} + +signed int cfg_item_match(signed char *src_key, signed char *src_val, signed char *dst_key, signed int *dst_val) +{ + signed int ret = 0; + unsigned short tmp_hex; + signed int tmp_dec; + + /* WCN_DBG(FM_NTC|MAIN,"src_key=%s,src_val=%s\n", src_key,src_val); */ + /* WCN_DBG(FM_NTC|MAIN,"dst_key=%s\n", dst_key); */ + if (strcmp(src_key, dst_key) == 0) { + if (strncmp(src_val, "0x", strlen("0x")) == 0) { + src_val += strlen("0x"); + /* WCN_DBG(FM_NTC|MAIN,"%s\n", src_val); */ + ret = ascii_to_hex(src_val, &tmp_hex); + + if (!ret) { + *dst_val = tmp_hex; + /* WCN_DBG(FM_NTC|MAIN, "%s 0x%04x\n", dst_key, tmp_hex); */ + return 0; + } + /* WCN_DBG(FM_ERR | MAIN, "%s format error\n", dst_key); */ + return 1; + } + + ret = ascii_to_dec(src_val, &tmp_dec); + + if (!ret /*&& ((0 <= tmp_dec) && (tmp_dec <= 0xFFFF)) */) { + *dst_val = tmp_dec; + /* WCN_DBG(FM_NTC|MAIN, "%s %d\n", dst_key, tmp_dec); */ + return 0; + } + /* WCN_DBG(FM_ERR | MAIN, "%s format error\n", dst_key); */ + return 1; + } + /* else */ + /* { */ + /* WCN_DBG(FM_ERR | MAIN, "src_key!=dst_key\n"); */ + /* } */ + + return -1; +} + +static signed int cfg_item_handler(signed char *grp, signed char *key, signed char *val, struct fm_cust_cfg *cfg) +{ + signed int ret = 0; + struct fm_rx_cust_cfg *rx_cfg = &cfg->rx_cfg; + struct fm_tx_cust_cfg *tx_cfg = &cfg->tx_cfg; + + + ret = cfg_item_match(key, val, "FM_RX_RSSI_TH_LONG", &rx_cfg->long_ana_rssi_th); + if (ret >= 0) + return ret; + + ret = cfg_item_match(key, val, "FM_RX_RSSI_TH_SHORT", &rx_cfg->short_ana_rssi_th); + if (ret >= 0) + return ret; + + ret = cfg_item_match(key, val, "FM_RX_DESENSE_RSSI", &rx_cfg->desene_rssi_th); + if (ret >= 0) + return ret; + + ret = cfg_item_match(key, val, "FM_RX_SMG_TH", &rx_cfg->smg_th); + if (ret >= 0) + return ret; + + ret = cfg_item_match(key, val, "FM_RX_DEEMPHASIS", &rx_cfg->deemphasis); + if (ret >= 0) + return ret; + + ret = cfg_item_match(key, val, "FM_RX_OSC_FREQ", &rx_cfg->osc_freq); + if (ret >= 0) + return ret; + + ret = cfg_item_match(key, val, "FM_RX_PAMD_TH", &rx_cfg->pamd_th); + if (ret >= 0) + return ret; + + ret = cfg_item_match(key, val, "FM_RX_MR_TH", &rx_cfg->mr_th); + if (ret >= 0) + return ret; + + ret = cfg_item_match(key, val, "FM_RX_ATDC_TH", &rx_cfg->atdc_th); + if (ret >= 0) + return ret; + + ret = cfg_item_match(key, val, "FM_RX_PRX_TH", &rx_cfg->prx_th); + if (ret >= 0) + return ret; + + ret = cfg_item_match(key, val, "FM_TX_PAMD_TH", &tx_cfg->pamd_th); + if (ret >= 0) + return ret; + + ret = cfg_item_match(key, val, "FM_TX_MR_TH", &tx_cfg->mr_th); + if (ret >= 0) + return ret; + + ret = cfg_item_match(key, val, "FM_TX_SMG_TH", &tx_cfg->smg_th); + if (ret >= 0) + return ret; + + + WCN_DBG(FM_WAR | MAIN, "invalid key\n"); + return -1; +} + +static signed int fm_cust_config_default(struct fm_cust_cfg *cfg) +{ + if (cfg == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + /*RX Threshold config*/ + cfg->rx_cfg.long_ana_rssi_th = FM_RX_RSSI_TH_LONG; + cfg->rx_cfg.short_ana_rssi_th = FM_RX_RSSI_TH_SHORT; + cfg->rx_cfg.desene_rssi_th = FM_RX_DESENSE_RSSI; + cfg->rx_cfg.pamd_th = FM_RX_PAMD_TH; + cfg->rx_cfg.mr_th = FM_RX_MR_TH; + cfg->rx_cfg.atdc_th = FM_RX_ATDC_TH; + cfg->rx_cfg.prx_th = FM_RX_PRX_TH; + cfg->rx_cfg.smg_th = FM_RX_SMG_TH; + cfg->rx_cfg.deemphasis = FM_RX_DEEMPHASIS; + cfg->rx_cfg.osc_freq = FM_RX_OSC_FREQ; + + /*TX Threshold config*/ + cfg->tx_cfg.pamd_th = FM_TX_PAMD_TH; + cfg->tx_cfg.mr_th = FM_TX_MR_TH; + cfg->tx_cfg.smg_th = FM_TX_SMG_TH; + + /*Audio path config*/ + if (g_fm_chip_type == FM_COMBO_CHIP) { + /* combo chip config MT6630,MT6632 */ +#ifdef CONFIG_MTK_MERGE_INTERFACE_SUPPORT + cfg->aud_cfg.aud_path = FM_AUD_MRGIF; + cfg->aud_cfg.i2s_info.status = FM_I2S_OFF; + cfg->aud_cfg.i2s_info.mode = FM_I2S_SLAVE; + if (g_fm_chipid == 0x6632) + cfg->aud_cfg.i2s_info.rate = FM_I2S_48K; + else + cfg->aud_cfg.i2s_info.rate = FM_I2S_44K; + cfg->aud_cfg.i2s_pad = FM_I2S_PAD_IO; +#elif defined FM_DIGITAL_INPUT + cfg->aud_cfg.aud_path = FM_AUD_I2S; + cfg->aud_cfg.i2s_info.status = FM_I2S_OFF; + cfg->aud_cfg.i2s_info.mode = FM_I2S_SLAVE; + if (g_fm_chipid == 0x6632) + cfg->aud_cfg.i2s_info.rate = FM_I2S_48K; + else + cfg->aud_cfg.i2s_info.rate = FM_I2S_44K; + cfg->aud_cfg.i2s_pad = FM_I2S_PAD_IO; +#elif defined FM_ANALOG_INPUT + cfg->aud_cfg.aud_path = FM_AUD_ANALOG; + cfg->aud_cfg.i2s_info.status = FM_I2S_STATE_ERR; + cfg->aud_cfg.i2s_info.mode = FM_I2S_MODE_ERR; + cfg->aud_cfg.i2s_info.rate = FM_I2S_SR_ERR; + cfg->aud_cfg.i2s_pad = FM_I2S_PAD_ERR; +#else + cfg->aud_cfg.aud_path = FM_AUD_ERR; + cfg->aud_cfg.i2s_info.status = FM_I2S_STATE_ERR; + cfg->aud_cfg.i2s_info.mode = FM_I2S_MODE_ERR; + cfg->aud_cfg.i2s_info.rate = FM_I2S_SR_ERR; + cfg->aud_cfg.i2s_pad = FM_I2S_PAD_ERR; +#endif + } else if ((g_fm_chip_type == FM_AD_DIE_CHIP) || (g_fm_chip_type == FM_SOC_CHIP)) { + /* MT6627 MT6580 MT6631 ?*/ + cfg->aud_cfg.aud_path = FM_AUD_I2S; + cfg->aud_cfg.i2s_info.status = FM_I2S_OFF; + cfg->aud_cfg.i2s_info.mode = FM_I2S_MASTER; + cfg->aud_cfg.i2s_info.rate = FM_I2S_32K; + cfg->aud_cfg.i2s_pad = FM_I2S_PAD_CONN; + } else { + WCN_DBG(FM_ALT | MAIN, "Invalid chip type %d\n", g_fm_chip_type); + cfg->aud_cfg.aud_path = FM_AUD_ERR; + cfg->aud_cfg.i2s_info.status = FM_I2S_STATE_ERR; + cfg->aud_cfg.i2s_info.mode = FM_I2S_MODE_ERR; + cfg->aud_cfg.i2s_info.rate = FM_I2S_SR_ERR; + cfg->aud_cfg.i2s_pad = FM_I2S_PAD_ERR; + } + return 0; +} + +static signed int fm_cust_config_file(const signed char *filename, struct fm_cust_cfg *cfg) +{ + signed int ret = 0; + signed char *buf = NULL; + signed int file_len = 0; + + buf = fm_zalloc(4096); + if (!buf) { + WCN_DBG(FM_ALT | MAIN, "-ENOMEM\n"); + return -ENOMEM; + } + + file_len = fm_file_read(filename, buf, 4096, 0); + + if (file_len <= 0) { + WCN_DBG(FM_ALT | MAIN, "fail to read config file = %s\n", filename); + ret = -1; + goto out; + } + + ret = cfg_parser(buf, cfg_item_handler, cfg); + +out: + if (buf) + fm_free(buf); + + return ret; +} + +static signed int fm_cust_config_print(struct fm_cust_cfg *cfg) +{ + WCN_DBG(FM_NTC | MAIN, "0x%x configs:\n", g_fm_chipid); + WCN_DBG(FM_NTC | MAIN, "RX->rssi_l:\t%d\n", cfg->rx_cfg.long_ana_rssi_th); + WCN_DBG(FM_NTC | MAIN, "RX->rssi_s:\t%d\n", cfg->rx_cfg.short_ana_rssi_th); + WCN_DBG(FM_NTC | MAIN, "RX->pamd_th:\t%d\n", cfg->rx_cfg.pamd_th); + WCN_DBG(FM_NTC | MAIN, "RX->mr_th:\t%d\n", cfg->rx_cfg.mr_th); + WCN_DBG(FM_NTC | MAIN, "RX->atdc_th:\t%d\n", cfg->rx_cfg.atdc_th); + WCN_DBG(FM_NTC | MAIN, "RX->prx_th:\t%d\n", cfg->rx_cfg.prx_th); + WCN_DBG(FM_NTC | MAIN, "RX->smg_th:\t%d\n", cfg->rx_cfg.smg_th); + WCN_DBG(FM_NTC | MAIN, "RX->de_emphasis:\t%d\n", cfg->rx_cfg.deemphasis); + WCN_DBG(FM_NTC | MAIN, "RX->osc_freq:\t%d\n", cfg->rx_cfg.osc_freq); + WCN_DBG(FM_NTC | MAIN, "RX->desense_rssi_th:\t%d\n", cfg->rx_cfg.desene_rssi_th); + + WCN_DBG(FM_NTC | MAIN, "TX->scan_hole_low:\t%d\n", cfg->tx_cfg.scan_hole_low); + WCN_DBG(FM_NTC | MAIN, "TX->scan_hole_high:\t%d\n", cfg->tx_cfg.scan_hole_high); + WCN_DBG(FM_NTC | MAIN, "TX->power_level:\t%d\n", cfg->tx_cfg.power_level); + + WCN_DBG(FM_NTC | MAIN, "aud path[%d]I2S state[%d]mode[%d]rate[%d]pad[%d]\n", + cfg->aud_cfg.aud_path, + cfg->aud_cfg.i2s_info.status, + cfg->aud_cfg.i2s_info.mode, + cfg->aud_cfg.i2s_info.rate, + cfg->aud_cfg.i2s_pad); + return 0; +} + +signed int fm_cust_config_setup(const signed char *filepath) +{ + signed int ret = 0; + signed char *filep = NULL; + signed char file_path[51] = { 0 }; + + fm_cust_config_default(&fm_config); + WCN_DBG(FM_NTC | MAIN, "FM default config\n"); + fm_cust_config_print(&fm_config); + + if (!filepath) { + filep = FM_CUST_CFG_PATH; + } else { + memcpy(file_path, filepath, (strlen(filepath) > 50) ? 50 : strlen(filepath)); + filep = file_path; + trim_path(&filep); + } + + if (check_path(filep, strlen(filep)) != 0) { + WCN_DBG(FM_ALT | MAIN, + "Invalid config file: %s\n", filep); + return -FM_EPATCH; + } + + ret = fm_cust_config_file(filep, &fm_config); + WCN_DBG(FM_NTC | MAIN, "FM cust config\n"); + fm_cust_config_print(&fm_config); + return ret; +} + +unsigned short fm_cust_config_fetch(enum fm_cust_cfg_op op_code) +{ + unsigned short tmp = 0; + + switch (op_code) { + /* For FM RX */ + case FM_CFG_RX_RSSI_TH_LONG: + tmp = fm_config.rx_cfg.long_ana_rssi_th; + break; + case FM_CFG_RX_RSSI_TH_SHORT: + tmp = fm_config.rx_cfg.short_ana_rssi_th; + break; + case FM_CFG_RX_DESENSE_RSSI_TH: + tmp = fm_config.rx_cfg.desene_rssi_th; + break; + case FM_CFG_RX_PAMD_TH: + tmp = fm_config.rx_cfg.pamd_th; + break; + case FM_CFG_RX_MR_TH: + tmp = fm_config.rx_cfg.mr_th; + break; + case FM_CFG_RX_ATDC_TH: + tmp = fm_config.rx_cfg.atdc_th; + break; + case FM_CFG_RX_PRX_TH: + tmp = fm_config.rx_cfg.prx_th; + break; + case FM_CFG_RX_ATDEV_TH: + tmp = fm_config.rx_cfg.atdev_th; + break; + case FM_CFG_RX_CQI_TH: + tmp = fm_config.rx_cfg.cqi_th; + break; + case FM_CFG_RX_SMG_TH: + tmp = fm_config.rx_cfg.smg_th; + break; + case FM_CFG_RX_DEEMPHASIS: + tmp = fm_config.rx_cfg.deemphasis; + break; + case FM_CFG_RX_OSC_FREQ: + tmp = fm_config.rx_cfg.osc_freq; + break; + + case FM_CFG_TX_SCAN_HOLE_LOW: + tmp = fm_config.tx_cfg.scan_hole_low; + break; + case FM_CFG_TX_SCAN_HOLE_HIGH: + tmp = fm_config.tx_cfg.scan_hole_high; + break; + case FM_CFG_TX_PWR_LEVEL: + tmp = fm_config.tx_cfg.power_level; + break; + case FM_CFG_TX_PAMD_TH: + tmp = fm_config.tx_cfg.pamd_th; + break; + case FM_CFG_TX_DEEMPHASIS: + tmp = fm_config.tx_cfg.mr_th; + break; + case FM_CFG_TX_SMG_TH: + tmp = fm_config.tx_cfg.smg_th; + break; + default: + break; + } + + WCN_DBG(FM_DBG | MAIN, "cust cfg %d: 0x%04x\n", op_code, tmp); + return tmp; +} +unsigned short fm_cust_config_chip(unsigned short chipid, enum fm_cfg_chip_type type) +{ + g_fm_chipid = chipid; + g_fm_chip_type = type; + + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/core/fm_eint.c b/drivers/misc/mediatek/connectivity/fmradio/core/fm_eint.c new file mode 100644 index 00000000000000..066ee1aae3f1a2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/core/fm_eint.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_eint.h" +#include "fm_reg_utils.h" + +signed int fm_enable_eint(void) +{ + struct fm_ext_interface *ei = &fm_wcn_ops.ei; + + if (ei->enable_eint) + ei->enable_eint(); + + return 0; +} + +signed int fm_disable_eint(void) +{ + struct fm_ext_interface *ei = &fm_wcn_ops.ei; + + if (ei->disable_eint) + ei->disable_eint(); + + return 0; +} + +signed int fm_request_eint(void (*parser) (void)) +{ + struct fm_ext_interface *ei = &fm_wcn_ops.ei; + + if (ei->stp_register_event_cb) + ei->stp_register_event_cb(parser); + + return 0; +} + +signed int fm_eint_pin_cfg(signed int mode) +{ + return 0; +} + diff --git a/drivers/misc/mediatek/connectivity/fmradio/core/fm_link.c b/drivers/misc/mediatek/connectivity/fmradio/core/fm_link.c new file mode 100644 index 00000000000000..d91359ed37516a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/core/fm_link.c @@ -0,0 +1,570 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/interrupt.h> + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_stdlib.h" +#include "fm_link.h" +#include "fm_reg_utils.h" + +static struct fm_link_event *link_event; + +static struct fm_trace_fifo_t *cmd_fifo; + +static struct fm_trace_fifo_t *evt_fifo; + +signed int fm_link_setup(void *data) +{ + signed int ret = 0; + + link_event = fm_zalloc(sizeof(struct fm_link_event)); + if (!link_event) { + WCN_DBG(FM_ALT | LINK, "fm_zalloc(fm_link_event) -ENOMEM\n"); + return -1; + } + + link_event->ln_event = fm_flag_event_create("ln_evt"); + + if (!link_event->ln_event) { + WCN_DBG(FM_ALT | LINK, "create mt6620_ln_event failed\n"); + fm_free(link_event); + return -1; + } + + fm_flag_event_get(link_event->ln_event); + + WCN_DBG(FM_NTC | LINK, "fm link setup\n"); + + cmd_fifo = fm_trace_fifo_create("cmd_fifo"); + if (!cmd_fifo) { + WCN_DBG(FM_ALT | LINK, "create cmd_fifo failed\n"); + ret = -1; + goto failed; + } + + evt_fifo = fm_trace_fifo_create("evt_fifo"); + if (!evt_fifo) { + WCN_DBG(FM_ALT | LINK, "create evt_fifo failed\n"); + ret = -1; + goto failed; + } + + if (fm_wcn_ops.ei.wmt_msgcb_reg) + fm_wcn_ops.ei.wmt_msgcb_reg(data); + + return 0; + +failed: + fm_trace_fifo_release(evt_fifo); + fm_trace_fifo_release(cmd_fifo); + if (link_event) { + fm_flag_event_put(link_event->ln_event); + fm_free(link_event); + } + + return ret; +} + +signed int fm_link_release(void) +{ + + fm_trace_fifo_release(evt_fifo); + fm_trace_fifo_release(cmd_fifo); + if (link_event) { + fm_flag_event_put(link_event->ln_event); + fm_free(link_event); + } + WCN_DBG(FM_NTC | LINK, "fm link release\n"); + return 0; +} + +/* + * fm_ctrl_rx + * the low level func to read a rigister + * @addr - rigister address + * @val - the pointer of target buf + * If success, return 0; else error code + */ +signed int fm_ctrl_rx(unsigned char addr, unsigned short *val) +{ + return 0; +} + +/* + * fm_ctrl_tx + * the low level func to write a rigister + * @addr - rigister address + * @val - value will be writed in the rigister + * If success, return 0; else error code + */ +signed int fm_ctrl_tx(unsigned char addr, unsigned short val) +{ + return 0; +} + +/* + * fm_cmd_tx() - send cmd to FM firmware and wait event + * @buf - send buffer + * @len - the length of cmd + * @mask - the event flag mask + * @ cnt - the retry conter + * @timeout - timeout per cmd + * Return 0, if success; error code, if failed + */ +signed int fm_cmd_tx(unsigned char *buf, unsigned short len, signed int mask, signed int cnt, signed int timeout, + signed int (*callback)(struct fm_res_ctx *result)) +{ + signed int ret_time = 0; + struct task_struct *task = current; + struct fm_trace_t trace; + + if ((buf == NULL) || (len < 0) || (mask == 0) + || (cnt > SW_RETRY_CNT_MAX) || (timeout > SW_WAIT_TIMEOUT_MAX)) { + WCN_DBG(FM_ERR | LINK, "cmd tx, invalid para\n"); + return -FM_EPARA; + } + + FM_EVENT_CLR(link_event->ln_event, mask); + +#ifdef FM_TRACE_ENABLE + trace.type = buf[0]; + trace.opcode = buf[1]; + trace.len = len - 4; + trace.tid = (signed int) task->pid; + fm_memset(trace.pkt, 0, FM_TRACE_PKT_SIZE); + fm_memcpy(trace.pkt, &buf[4], (trace.len > FM_TRACE_PKT_SIZE) ? FM_TRACE_PKT_SIZE : trace.len); +#endif + + +#ifdef FM_TRACE_ENABLE + if (true == FM_TRACE_FULL(cmd_fifo)) + FM_TRACE_OUT(cmd_fifo, NULL); + + FM_TRACE_IN(cmd_fifo, &trace); +#endif + + /* send cmd to FM firmware */ + if (fm_wcn_ops.ei.stp_send_data) + ret_time = fm_wcn_ops.ei.stp_send_data(buf, len); + if (ret_time <= 0) { + WCN_DBG(FM_EMG | LINK, "send data over stp failed[%d]\n", ret_time); + return -FM_ELINK; + } + /* wait the response form FM firmware */ + ret_time = FM_EVENT_WAIT_TIMEOUT(link_event->ln_event, mask, timeout); + + if (!ret_time) { + if (cnt-- > 0) { + WCN_DBG(FM_WAR | LINK, "wait event timeout, [retry_cnt=%d], pid=%d\n", cnt, task->pid); + fm_print_cmd_fifo(); + fm_print_evt_fifo(); + } else + WCN_DBG(FM_ALT | LINK, "fatal error, SW retry failed, reset HW\n"); + + return -FM_EFW; + } + + FM_EVENT_CLR(link_event->ln_event, mask); + + if (callback) + callback(&link_event->result); + + return 0; +} + +signed int fm_event_parser(signed int(*rds_parser) (struct rds_rx_t *, signed int)) +{ + signed int len; + signed int i = 0; + unsigned char opcode = 0; + unsigned short length = 0; + unsigned char ch; + unsigned char rx_buf[RX_BUF_SIZE + 10] = { 0 }; /* the 10 bytes are protect gaps */ + unsigned int rx_len = 0; + + static enum fm_task_parser_state state = FM_TASK_RX_PARSER_PKT_TYPE; + struct fm_trace_t trace; + struct task_struct *task = current; + + if (fm_wcn_ops.ei.stp_recv_data) + len = fm_wcn_ops.ei.stp_recv_data(rx_buf, RX_BUF_SIZE); + WCN_DBG_LIMITED(FM_DBG | LINK, "[len=%d],[CMD=0x%02x 0x%02x 0x%02x 0x%02x]\n", len, rx_buf[0], + rx_buf[1], rx_buf[2], rx_buf[3]); + + while (i < len) { + ch = rx_buf[i]; + + switch (state) { + case FM_TASK_RX_PARSER_PKT_TYPE: + + if (ch == FM_TASK_EVENT_PKT_TYPE) { + if ((i + 5) < RX_BUF_SIZE) { + if (i != 0) { + WCN_DBG(FM_DBG | LINK, + "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", + rx_buf[i], rx_buf[i + 1], rx_buf[i + 2], + rx_buf[i + 3], rx_buf[i + 4], rx_buf[i + 5]); + } + } else { + WCN_DBG(FM_DBG | LINK, "0x%02x 0x%02x\n", rx_buf[i], rx_buf[i + 1]); + } + + state = FM_TASK_RX_PARSER_OPCODE; + } else { + WCN_DBG(FM_ALT | LINK, "event pkt type error (rx_buf[%d] = 0x%02x)\n", i, ch); + } + + i++; + break; + + case FM_TASK_RX_PARSER_OPCODE: + i++; + opcode = ch; + state = FM_TASK_RX_PARSER_PKT_LEN_1; + break; + + case FM_TASK_RX_PARSER_PKT_LEN_1: + i++; + length = ch; + state = FM_TASK_RX_PARSER_PKT_LEN_2; + break; + + case FM_TASK_RX_PARSER_PKT_LEN_2: + i++; + length |= (unsigned short) (ch << 0x8); + +#ifdef FM_TRACE_ENABLE + trace.type = FM_TASK_EVENT_PKT_TYPE; + trace.opcode = opcode; + trace.len = length; + trace.tid = (signed int) task->pid; + fm_memset(trace.pkt, 0, FM_TRACE_PKT_SIZE); + rx_len = (length > FM_TRACE_PKT_SIZE) ? FM_TRACE_PKT_SIZE : length; + rx_len = (rx_len > (sizeof(rx_buf) - i)) ? sizeof(rx_buf) - i : rx_len; + fm_memcpy(trace.pkt, &rx_buf[i], rx_len); + + if (true == FM_TRACE_FULL(evt_fifo)) + FM_TRACE_OUT(evt_fifo, NULL); + + FM_TRACE_IN(evt_fifo, &trace); +#endif + if (length > 0) { + state = FM_TASK_RX_PARSER_PKT_PAYLOAD; + } else if (opcode == CSPI_WRITE_OPCODE) { + state = FM_TASK_RX_PARSER_PKT_TYPE; + FM_EVENT_SEND(link_event->ln_event, FLAG_CSPI_WRITE); + } else { + state = FM_TASK_RX_PARSER_PKT_TYPE; + FM_EVENT_SEND(link_event->ln_event, (1 << opcode)); + } + + break; + + case FM_TASK_RX_PARSER_PKT_PAYLOAD: + + switch (opcode) { + case FM_TUNE_OPCODE: + + if ((length == 1) && (rx_buf[i] == 1)) + FM_EVENT_SEND(link_event->ln_event, FLAG_TUNE_DONE); + + break; + + case FM_SOFT_MUTE_TUNE_OPCODE: + + if (length >= 2) { + fm_memcpy(link_event->result.cqi, &rx_buf[i], + (length > FM_CQI_BUF_SIZE) ? FM_CQI_BUF_SIZE : length); + FM_EVENT_SEND(link_event->ln_event, FLAG_SM_TUNE); + } + break; + + case FM_SEEK_OPCODE: + + if ((i + 1) < RX_BUF_SIZE) + link_event->result.seek_result = rx_buf[i] + (rx_buf[i + 1] << 8); + + FM_EVENT_SEND(link_event->ln_event, FLAG_SEEK_DONE); + break; + + case FM_SCAN_OPCODE: + + /* check if the result data is long enough */ + if ((RX_BUF_SIZE - i) < (sizeof(unsigned short) * FM_SCANTBL_SIZE)) { + WCN_DBG(FM_ALT | LINK, + "FM_SCAN_OPCODE err, [tblsize=%d],[bufsize=%d]\n", + (unsigned int)(sizeof(unsigned short) * FM_SCANTBL_SIZE), + (unsigned int)(RX_BUF_SIZE - i)); + FM_EVENT_SEND(link_event->ln_event, FLAG_SCAN_DONE); + return 0; + } else if ((length >= FM_CQI_BUF_SIZE) + && ((RX_BUF_SIZE - i) >= FM_CQI_BUF_SIZE)) { + fm_memcpy(link_event->result.cqi, &rx_buf[i], FM_CQI_BUF_SIZE); + FM_EVENT_SEND(link_event->ln_event, FLAG_CQI_DONE); + } else { + fm_memcpy(link_event->result.scan_result, &rx_buf[i], + sizeof(unsigned short) * FM_SCANTBL_SIZE); + FM_EVENT_SEND(link_event->ln_event, FLAG_SCAN_DONE); + } + + break; + + case FSPI_READ_OPCODE: + + if ((i + 1) < RX_BUF_SIZE) + link_event->result.fspi_rd = (rx_buf[i] + (rx_buf[i + 1] << 8)); + + FM_EVENT_SEND(link_event->ln_event, (1 << opcode)); + break; + case CSPI_READ_OPCODE: + { + if ((i + 1) < RX_BUF_SIZE) { + link_event->result.cspi_rd = + (rx_buf[i] + (rx_buf[i + 1] << 8) + + (rx_buf[i + 2] << 16) + (rx_buf[i + 3] << 24)); + } + + FM_EVENT_SEND(link_event->ln_event, FLAG_CSPI_READ); + break; + } + case FM_HOST_READ_OPCODE: + { + if ((i + 1) < RX_BUF_SIZE) { + link_event->result.cspi_rd = + (rx_buf[i] + (rx_buf[i + 1] << 8) + + (rx_buf[i + 2] << 16) + (rx_buf[i + 3] << 24)); + } + + FM_EVENT_SEND(link_event->ln_event, (1 << opcode)); + break; + } + case FM_WRITE_PMIC_CR_OPCODE: + case FM_MODIFY_PMIC_CR_OPCODE: + { + link_event->result.pmic_result[0] = rx_buf[i]; + + FM_EVENT_SEND(link_event->ln_event, FLAG_PMIC_MODIFY); + break; + } + case FM_READ_PMIC_CR_OPCODE: + { + fm_memcpy(&link_event->result.pmic_result[0], &rx_buf[i], length); + FM_EVENT_SEND(link_event->ln_event, FLAG_PMIC_READ); + break; + } + case RDS_RX_DATA_OPCODE: + + /* check if the rds data is long enough */ + if ((RX_BUF_SIZE - i) < length) { + WCN_DBG(FM_ALT | LINK, + "RDS RX err, [rxlen=%d],[bufsize=%d]\n", + (signed int) length, (RX_BUF_SIZE - i)); + FM_EVENT_SEND(link_event->ln_event, (1 << opcode)); + break; + } + + if (length > sizeof(struct rds_rx_t)) { + WCN_DBG(FM_ALT | LINK, + "RDS RX len out of range, [rxlen=%d],[needmaxlen=%zd]\n", + (signed int) length, (sizeof(struct rds_rx_t))); + FM_EVENT_SEND(link_event->ln_event, (1 << opcode)); + break; + } + /* copy rds data to rds buf */ + fm_memcpy(&link_event->result.rds_rx_result, &rx_buf[i], length); + + /*Handle the RDS data that we get */ + if (rds_parser) + rds_parser(&link_event->result.rds_rx_result, length); + else + WCN_DBG(FM_WAR | LINK, "no method to parse RDS data\n"); + + FM_EVENT_SEND(link_event->ln_event, (1 << opcode)); + break; + + default: + FM_EVENT_SEND(link_event->ln_event, (1 << opcode)); + break; + } + + state = FM_TASK_RX_PARSER_PKT_TYPE; + i += length; + break; + + default: + break; + } + } + + return 0; +} + +bool fm_wait_stc_done(unsigned int sec) +{ + return true; +} + +signed int fm_force_active_event(unsigned int mask) +{ + unsigned int flag; + + flag = FM_EVENT_GET(link_event->ln_event); + WCN_DBG(FM_WAR | LINK, "before force active event, [flag=0x%08x]\n", flag); + flag = FM_EVENT_SEND(link_event->ln_event, mask); + WCN_DBG(FM_WAR | LINK, "after force active event, [flag=0x%08x]\n", flag); + + return 0; +} + +extern signed int fm_print_cmd_fifo(void) +{ +#ifdef FM_TRACE_ENABLE + struct fm_trace_t trace; + signed int i = 0; + + fm_memset(&trace, 0, sizeof(struct fm_trace_t)); + + while (false == FM_TRACE_EMPTY(cmd_fifo)) { + fm_memset(trace.pkt, 0, FM_TRACE_PKT_SIZE); + FM_TRACE_OUT(cmd_fifo, &trace); + WCN_DBG_LIMITED(FM_ALT | LINK, "trace, type %d, op %d, len %d, tid %d, time %d\n", + trace.type, trace.opcode, trace.len, trace.tid, jiffies_to_msecs(abs(trace.time))); + i = 0; + while ((trace.len > 0) && (i < trace.len) && (i < (FM_TRACE_PKT_SIZE - 8))) { + WCN_DBG_LIMITED(FM_ALT | LINK, "trace, %02x %02x %02x %02x %02x %02x %02x %02x\n", + trace.pkt[i], trace.pkt[i + 1], trace.pkt[i + 2], trace.pkt[i + 3], + trace.pkt[i + 4], trace.pkt[i + 5], trace.pkt[i + 6], trace.pkt[i + 7]); + i += 8; + } + WCN_DBG_LIMITED(FM_ALT | LINK, "trace\n"); + } +#endif + + return 0; +} + +extern signed int fm_print_evt_fifo(void) +{ +#ifdef FM_TRACE_ENABLE + struct fm_trace_t trace; + signed int i = 0; + + fm_memset(&trace, 0, sizeof(struct fm_trace_t)); + + while (false == FM_TRACE_EMPTY(evt_fifo)) { + fm_memset(trace.pkt, 0, FM_TRACE_PKT_SIZE); + FM_TRACE_OUT(evt_fifo, &trace); + WCN_DBG_LIMITED(FM_ALT | LINK, "%s: op %d, len %d, %d\n", evt_fifo->name, trace.opcode, + trace.len, jiffies_to_msecs(abs(trace.time))); + i = 0; + while ((trace.len > 0) && (i < trace.len) && (i < (FM_TRACE_PKT_SIZE - 8))) { + WCN_DBG_LIMITED(FM_ALT | LINK, "%s: %02x %02x %02x %02x %02x %02x %02x %02x\n", + evt_fifo->name, trace.pkt[i], trace.pkt[i + 1], trace.pkt[i + 2], + trace.pkt[i + 3], trace.pkt[i + 4], trace.pkt[i + 5], + trace.pkt[i + 6], trace.pkt[i + 7]); + i += 8; + } + WCN_DBG_LIMITED(FM_ALT | LINK, "%s\n", evt_fifo->name); + } +#endif + + return 0; +} + +signed int fm_trace_in(struct fm_trace_fifo_t *thiz, struct fm_trace_t *new_tra) +{ + if (new_tra == NULL) { + WCN_DBG(FM_ERR | LINK, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (thiz->len < thiz->size) { + fm_memcpy(&(thiz->trace[thiz->in]), new_tra, sizeof(struct fm_trace_t)); + thiz->trace[thiz->in].time = jiffies; + thiz->in = (thiz->in + 1) % thiz->size; + thiz->len++; + /* WCN_DBG(FM_DBG | RDSC, "add a new tra[len=%d]\n", thiz->len); */ + } else { + WCN_DBG(FM_WAR | LINK, "tra buf is full\n"); + return -FM_ENOMEM; + } + + return 0; +} + +signed int fm_trace_out(struct fm_trace_fifo_t *thiz, struct fm_trace_t *dst_tra) +{ + if (thiz->len > 0) { + if (dst_tra) { + fm_memcpy(dst_tra, &(thiz->trace[thiz->out]), sizeof(struct fm_trace_t)); + fm_memset(&(thiz->trace[thiz->out]), 0, sizeof(struct fm_trace_t)); + } + thiz->out = (thiz->out + 1) % thiz->size; + thiz->len--; + /* WCN_DBG(FM_DBG | LINK, "del a tra[len=%d]\n", thiz->len); */ + } else { + WCN_DBG(FM_WAR | LINK, "tra buf is empty\n"); + } + + return 0; +} + +bool fm_trace_is_full(struct fm_trace_fifo_t *thiz) +{ + return (thiz->len == thiz->size) ? true : false; +} + +bool fm_trace_is_empty(struct fm_trace_fifo_t *thiz) +{ + return (thiz->len == 0) ? true : false; +} + +struct fm_trace_fifo_t *fm_trace_fifo_create(const signed char *name) +{ + struct fm_trace_fifo_t *tmp; + + tmp = fm_zalloc(sizeof(struct fm_trace_fifo_t)); + if (!tmp) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(fm_trace_fifo) -ENOMEM\n"); + return NULL; + } + + fm_memcpy(tmp->name, name, (strlen(name) + 1)); + tmp->size = FM_TRACE_FIFO_SIZE; + tmp->in = 0; + tmp->out = 0; + tmp->len = 0; + tmp->trace_in = fm_trace_in; + tmp->trace_out = fm_trace_out; + tmp->is_full = fm_trace_is_full; + tmp->is_empty = fm_trace_is_empty; + + WCN_DBG(FM_NTC | LINK, "%s created\n", tmp->name); + + return tmp; +} + +signed int fm_trace_fifo_release(struct fm_trace_fifo_t *fifo) +{ + if (fifo) { + WCN_DBG(FM_NTC | LINK, "%s released\n", fifo->name); + fm_free(fifo); + } + + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/core/fm_main.c b/drivers/misc/mediatek/connectivity/fmradio/core/fm_main.c new file mode 100644 index 00000000000000..a79b78587cef31 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/core/fm_main.c @@ -0,0 +1,2856 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/uaccess.h> +#include <linux/slab.h> + +#include "fm_main.h" +#include "fm_err.h" +#include "fm_reg_utils.h" +/* #include "fm_cust_cfg.h" */ +#include "fm_cmd.h" +#include "fm_reg_utils.h" + +/* fm main data structure */ +static struct fm *g_fm_struct; +/* we must get low level interface first, when add a new chip, the main effort is this interface */ +static struct fm_lowlevel_ops fm_low_ops; + +/* mutex for char device ops */ +static struct fm_lock *fm_ops_lock; +/* mutex for RDS parsing and read result */ +static struct fm_lock *fm_read_lock; +/* for get rds block counter */ +static struct fm_lock *fm_rds_cnt; +/* mutex for fm timer, RDS reset */ +static struct fm_lock *fm_timer_lock; +static struct fm_lock *fm_rxtx_lock; /* protect FM RX TX mode switch */ +static struct fm_lock *fm_rtc_mutex; /* protect FM GPS RTC drift info */ + +static struct fm_timer *fm_timer_sys; + +#if (FM_INVALID_CHAN_NOISE_REDUCING) +static struct fm_timer *fm_cqi_check_timer; +#endif + +static bool scan_stop_flag; /* false */ +static struct fm_gps_rtc_info gps_rtc_info; +static bool g_fm_stat[3] = { + false, /* RX power */ + false, /* TX power */ + false, /* TX scan */ +}; + +#if !defined(MT6631_FM) && !defined(MT6635_FM) +/* chipid porting table */ +static struct fm_chip_mapping fm_support_chip_array[] = { +{ 0x6572, 0x6627, FM_AD_DIE_CHIP }, +{ 0x6582, 0x6627, FM_AD_DIE_CHIP }, +{ 0x6592, 0x6627, FM_AD_DIE_CHIP }, +{ 0x8127, 0x6627, FM_AD_DIE_CHIP }, +{ 0x6571, 0x6627, FM_AD_DIE_CHIP }, +{ 0x6752, 0x6627, FM_AD_DIE_CHIP }, +{ 0x0321, 0x6627, FM_AD_DIE_CHIP }, +{ 0x0335, 0x6627, FM_AD_DIE_CHIP }, +{ 0x0337, 0x6627, FM_AD_DIE_CHIP }, +{ 0x6735, 0x6627, FM_AD_DIE_CHIP }, +{ 0x8163, 0x6627, FM_AD_DIE_CHIP }, +{ 0x6755, 0x6627, FM_AD_DIE_CHIP }, +{ 0x0326, 0x6627, FM_AD_DIE_CHIP }, +{ 0x6570, 0x0633, FM_SOC_CHIP }, +{ 0x6580, 0x6580, FM_SOC_CHIP }, +{ 0x6630, 0x6630, FM_COMBO_CHIP }, +{ 0x6797, 0x6631, FM_AD_DIE_CHIP }, +{ 0x6759, 0x6631, FM_AD_DIE_CHIP }, +{ 0x6758, 0x6631, FM_AD_DIE_CHIP }, +{ 0x6632, 0x6632, FM_COMBO_CHIP }, +{ 0x6757, 0x6627, FM_AD_DIE_CHIP }, +{ 0x6763, 0x6627, FM_AD_DIE_CHIP }, +{ 0x6765, 0x6631, FM_AD_DIE_CHIP }, +{ 0x6761, 0x6631, FM_AD_DIE_CHIP }, +{ 0x6739, 0x6627, FM_AD_DIE_CHIP }, +{ 0x3967, 0x6631, FM_AD_DIE_CHIP }, +{ 0x6771, 0x6631, FM_AD_DIE_CHIP }, +{ 0x6775, 0x6631, FM_AD_DIE_CHIP }, +{ 0x6768, 0x6631, FM_AD_DIE_CHIP }, +{ 0x6779, 0x6635, FM_AD_DIE_CHIP }, +}; +#endif + +unsigned char top_index; + +/* RDS reset related functions */ +static unsigned short fm_cur_freq_get(void); +static signed int fm_cur_freq_set(unsigned short new_freq); +static enum fm_op_state fm_op_state_get(struct fm *fmp); +static enum fm_op_state fm_op_state_set(struct fm *fmp, enum fm_op_state sta); +static void fm_timer_func(unsigned long data); +static void fm_enable_rds_BlerCheck(struct fm *fm); +static void fm_disable_rds_BlerCheck(void); +static void fm_rds_reset_work_func(unsigned long data); +/* when interrupt be triggered by FM chip, fm_eint_handler will first be executed */ +/* then fm_eint_handler will schedule fm_eint_work_func to run */ +static void fm_eint_handler(void); +static void fm_eint_work_func(unsigned long data); +static signed int pwrdown_flow(struct fm *fm); + +static unsigned short fm_cur_freq_get(void) +{ + return g_fm_struct ? g_fm_struct->cur_freq : 0; +} + +static signed int fm_cur_freq_set(unsigned short new_freq) +{ + if (g_fm_struct) + g_fm_struct->cur_freq = new_freq; + + return 0; +} + +static signed int fm_projectid_get(void) +{ + return g_fm_struct ? g_fm_struct->projectid : 0; +} + +static enum fm_op_state fm_op_state_get(struct fm *fmp) +{ + if (fmp) { + WCN_DBG(FM_DBG | MAIN, "op state get %d\n", fmp->op_sta); + return fmp->op_sta; + } + + WCN_DBG(FM_ERR | MAIN, "op state get para error\n"); + return FM_STA_UNKNOWN; +} + +static enum fm_op_state fm_op_state_set(struct fm *fmp, enum fm_op_state sta) +{ + if (fmp && (sta < FM_STA_MAX)) { + fmp->op_sta = sta; + WCN_DBG(FM_DBG | MAIN, "op state set to %d\n", sta); + return fmp->op_sta; + } + + WCN_DBG(FM_ERR | MAIN, "op state set para error, %d\n", sta); + return FM_STA_UNKNOWN; +} + +enum fm_pwr_state fm_pwr_state_get(struct fm *fmp) +{ + if (fmp) { + WCN_DBG(FM_DBG | MAIN, "pwr state get %d\n", fmp->pwr_sta); + return fmp->pwr_sta; + } + + WCN_DBG(FM_ERR | MAIN, "pwr state get para error\n"); + return FM_PWR_MAX; +} + +enum fm_pwr_state fm_pwr_state_set(struct fm *fmp, enum fm_pwr_state sta) +{ + if (fmp && (sta < FM_PWR_MAX)) { + fmp->pwr_sta = sta; + WCN_DBG(FM_DBG | MAIN, "pwr state set to %d\n", sta); + return fmp->pwr_sta; + } + + WCN_DBG(FM_ERR | MAIN, "pwr state set para error, %d\n", sta); + return FM_PWR_MAX; +} + +signed int fm_set_stat(struct fm *fmp, int which, bool stat) +{ + signed int ret = 0; + + if (fmp == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if (which >= 0 && which < ARRAY_SIZE(g_fm_stat)) { + g_fm_stat[which] = stat; + WCN_DBG(FM_DBG | MAIN, "fm set stat object=%d, stat=%d\n", which, stat); + } else { + ret = -1; + WCN_DBG(FM_ERR | MAIN, "fm set stat error, object=%d, stat=%d\n", which, stat); + } + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_get_stat(struct fm *fmp, int which, bool *stat) +{ + signed int ret = 0; + + if (fmp == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (stat == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if (which >= 0 && which < ARRAY_SIZE(g_fm_stat)) { + *stat = g_fm_stat[which]; + WCN_DBG(FM_DBG | MAIN, "fm get stat object=%d, stat=%d\n", which, *stat); + } else { + ret = -1; + WCN_DBG(FM_ERR | MAIN, "fm get stat error, object=%d\n", which); + } + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +static signed int subsys_rst_state = FM_SUBSYS_RST_OFF; + +signed int fm_sys_state_get(struct fm *fmp) +{ + return subsys_rst_state; +} + +signed int fm_sys_state_set(struct fm *fmp, signed int sta) +{ + if ((sta >= FM_SUBSYS_RST_OFF) && (sta < FM_SUBSYS_RST_MAX)) { + WCN_DBG(FM_NTC | MAIN, "sys state set from %d to %d\n", subsys_rst_state, sta); + subsys_rst_state = sta; + } else { + WCN_DBG(FM_ERR | MAIN, "sys state set para error, %d\n", sta); + } + + return subsys_rst_state; +} + +signed int fm_subsys_reset(struct fm *fm) +{ + /* check if we are resetting */ + if (fm_sys_state_get(fm) != FM_SUBSYS_RST_OFF) { + WCN_DBG(FM_NTC | MAIN, "subsys reset is ongoing\n"); + goto out; + } + + if (fm == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + fm->timer_wkthd->add_work(fm->timer_wkthd, fm->rst_wk); + +out: + return 0; +} + +signed int fm_wholechip_rst_cb(signed int sta) +{ + struct fm *fm = g_fm_struct; + + if (!fm) + return 0; + + if (sta == 1) { + if (fm_sys_state_get(fm) == FM_SUBSYS_RST_OFF) + fm_sys_state_set(fm, FM_SUBSYS_RST_START); + } else if (sta == 2) { + if (fm_sys_state_get(fm) == FM_SUBSYS_RST_START) + fm_sys_state_set(fm, FM_SUBSYS_RST_OFF); + } else + fm->timer_wkthd->add_work(fm->timer_wkthd, fm->rst_wk); + + return 0; +} + +static signed int fm_which_chip(unsigned short chipid, enum fm_cfg_chip_type *type) +{ + signed short fm_chip = -1; + +#if defined(MT6631_FM) + fm_chip = 0x6631; + if (type) + *type = FM_AD_DIE_CHIP; +#elif defined(MT6635_FM) + fm_chip = 0x6635; + if (type) + *type = FM_AD_DIE_CHIP; +#else + signed short i = 0; + for (i = 0; i < (sizeof(fm_support_chip_array)/sizeof(struct fm_chip_mapping)); i++) { + if (chipid == fm_support_chip_array[i].con_chip) { + fm_chip = fm_support_chip_array[i].fm_chip; + break; + } + } + + if (type) { + for (i = 0; i < (sizeof(fm_support_chip_array)/sizeof(struct fm_chip_mapping)); i++) { + if (chipid == fm_support_chip_array[i].fm_chip) { + *type = fm_support_chip_array[i].type; + break; + } + } + } +#endif + return fm_chip; +} + +signed int fm_open(struct fm *fmp) +{ + signed int ret = 0; + signed int chipid = 0; + + if (fmp == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (fmp->chipon == false) { + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if (fm_wcn_ops.ei.wmt_chipid_query) + chipid = fm_wcn_ops.ei.wmt_chipid_query(); + fmp->projectid = chipid; + WCN_DBG(FM_NTC | MAIN, "wmt chip id=0x%x\n", chipid); + + if (fm_wcn_ops.ei.get_top_index) + top_index = fm_wcn_ops.ei.get_top_index(); + else + top_index = 4; + WCN_DBG(FM_NTC | MAIN, "mcu top index = 0x%x\n", top_index); + /* what's the purpose of put chipid to fmp->chip_id ? */ + fmp->chip_id = fm_which_chip(chipid, NULL); + WCN_DBG(FM_NTC | MAIN, "fm chip id=0x%x\n", fmp->chip_id); + + fm_eint_pin_cfg(FM_EINT_PIN_EINT_MODE); + fm_request_eint(fm_eint_handler); + + FM_UNLOCK(fm_ops_lock); + } + return ret; +} + +signed int fm_close(struct fm *fmp) +{ + signed int ret = 0; + + if (fmp == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + fm_eint_pin_cfg(FM_EINT_PIN_GPIO_MODE); + + FM_UNLOCK(fm_ops_lock); + + return ret; +} + +signed int fm_rds_read(struct fm *fmp, signed char *dst, signed int len) +{ + signed int copy_len = 0, left = 0; + + copy_len = sizeof(struct rds_t); + + if (FM_EVENT_GET(fmp->rds_event) == FM_RDS_DATA_READY) { + if (FM_LOCK(fm_read_lock)) + return -FM_ELOCK; + + left = copy_to_user((void *)dst, fmp->pstRDSData, (unsigned long)copy_len); + if (left) + WCN_DBG(FM_ALT | MAIN, "fm_read copy failed\n"); + else + fmp->pstRDSData->event_status = 0x0000; + + WCN_DBG(FM_DBG | MAIN, "fm_read copy len:%d\n", (copy_len - left)); + + FM_EVENT_RESET(fmp->rds_event); + FM_UNLOCK(fm_read_lock); + } else { + /*if (FM_EVENT_WAIT(fmp->rds_event, FM_RDS_DATA_READY) == 0) { + * WCN_DBG(FM_DBG | MAIN, "fm_read wait ok\n"); + * goto RESTART; + * } else { + * WCN_DBG(FM_ALT | MAIN, "fm_read wait err\n"); + * return 0; + * } *//*event wait caused AP stop RDS thread and re-read RDS, which caused issue ALPS00595367 */ + + WCN_DBG(FM_DBG | MAIN, "fm_read no event now\n"); + return 0; + } + + return copy_len - left; +} + +signed int fm_powerup(struct fm *fm, struct fm_tune_parm *parm) +{ + signed int ret = 0; + unsigned char tmp_vol; + + if (fm_low_ops.bi.pwron == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (fm_low_ops.bi.pwrupseq == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + /* for normal case */ + if (fm_low_ops.bi.pwron == NULL) { + WCN_DBG(FM_NTC | MAIN, "get fm_low_ops fail\n"); + ret = -ENODEV; + goto out; + } + + if (fm->chipon == false) { + ret = fm_low_ops.bi.pwron(0); + if (ret) { + ret = -ENODEV; + goto out; + } + fm->chipon = true; + } + + if (fm_pwr_state_get(fm) == FM_PWR_RX_ON) { + WCN_DBG(FM_NTC | MAIN, "already pwron!\n"); + goto out; + } else if (fm_pwr_state_get(fm) == FM_PWR_TX_ON) { + /* if Tx is on, we need pwr down TX first */ + WCN_DBG(FM_NTC | MAIN, "power down TX first!\n"); + + ret = fm_powerdowntx(fm); + if (ret) { + WCN_DBG(FM_ERR | MAIN, "FM pwr down Tx fail!\n"); + return ret; + } + } + + fm_pwr_state_set(fm, FM_PWR_RX_ON); + + /* execute power on sequence */ + ret = fm_low_ops.bi.pwrupseq(&fm->chip_id, &fm->device_id); + if (ret) { + fm_pwr_state_set(fm, FM_PWR_OFF); + WCN_DBG(FM_ERR | MAIN, "powerup fail!!!\n"); + goto out; + } + + fm_enable_eint(); + fm_cur_freq_set(parm->freq); + + parm->err = FM_SUCCESS; + if (fm_low_ops.bi.low_pwr_wa) + fm_low_ops.bi.low_pwr_wa(1); + + fm_low_ops.bi.volget(&tmp_vol); + WCN_DBG(FM_INF | MAIN, "vol=%d!!!\n", tmp_vol); + + /* fm_low_ops.bi.volset(0); */ + fm->vol = 15; + if (fm_low_ops.ri.rds_bci_get) { + fm_timer_sys->init(fm_timer_sys, fm_timer_func, (unsigned long)g_fm_struct, + fm_low_ops.ri.rds_bci_get(), 0); + fm_timer_sys->start(fm_timer_sys); + } else { + WCN_DBG(FM_NTC | MAIN, "start timer fail!!!\n"); + } + +out: + FM_UNLOCK(fm_ops_lock); + return ret; +} + +/* + * fm_powerup_tx + */ +signed int fm_powerup_tx(struct fm *fm, struct fm_tune_parm *parm) +{ + signed int ret = 0; + + if (fm_low_ops.bi.pwron == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (fm_low_ops.bi.pwrupseq_tx == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (fm_pwr_state_get(fm) == FM_PWR_TX_ON) { + WCN_DBG(FM_NTC | MAIN, "already pwron!\n"); + parm->err = FM_BADSTATUS; + goto out; + } else if (fm_pwr_state_get(fm) == FM_PWR_RX_ON) { + /* if Rx is on, we need pwr down first */ + ret = fm_powerdown(fm, 0); + if (ret) { + WCN_DBG(FM_ERR | MAIN, "FM pwr down Rx fail!\n"); + goto out; + } + } + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + /* for normal case */ + if (fm->chipon == false) { + fm_low_ops.bi.pwron(0); + fm->chipon = true; + } + + fm_pwr_state_set(fm, FM_PWR_TX_ON); + ret = fm_low_ops.bi.pwrupseq_tx(); + + if (ret) { + parm->err = FM_FAILED; + fm_pwr_state_set(fm, FM_PWR_OFF); + WCN_DBG(FM_ERR | MAIN, "FM pwr up Tx fail!\n"); + } else { + parm->err = FM_SUCCESS; + } + fm_cur_freq_set(parm->freq); + +out: + FM_UNLOCK(fm_ops_lock); + return ret; +} + +static signed int pwrdown_flow(struct fm *fm) +{ + signed int ret = 0; + + if (fm_low_ops.ri.rds_onoff == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (fm_low_ops.bi.pwrdownseq == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (fm_pwr_state_get(fm) == FM_PWR_OFF) { + WCN_DBG(FM_NTC | MAIN, "FMSYS already pwroff!\n"); + goto out; + } + + if (fm_pwr_state_get(fm) == FM_PWR_RX_ON) { + /* Disable all interrupt */ + fm_disable_rds_BlerCheck(); + fm_low_ops.ri.rds_onoff(fm->pstRDSData, false); + fm_disable_eint(); + + fm_pwr_state_set(fm, FM_PWR_OFF); + + /* execute power down sequence */ + ret = fm_low_ops.bi.pwrdownseq(); + + if (fm_low_ops.bi.low_pwr_wa) + fm_low_ops.bi.low_pwr_wa(0); + + WCN_DBG(FM_ALT | MAIN, "pwrdown_flow exit\n"); + } +out: + return ret; +} + +signed int fm_powerdown(struct fm *fm, int type) +{ + signed int ret = 0; + +#if (FM_INVALID_CHAN_NOISE_REDUCING) + fm_cqi_check_timer->stop(fm_cqi_check_timer); +#endif + + if (type == 1) { /* 0: RX 1: TX */ + ret = fm_powerdowntx(fm); + } else { + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + if (FM_LOCK(fm_rxtx_lock)) + return -FM_ELOCK; + + ret = pwrdown_flow(fm); + + FM_UNLOCK(fm_rxtx_lock); + FM_UNLOCK(fm_ops_lock); + } + + if ((fm_pwr_state_get(fm) == FM_PWR_OFF) && (fm->chipon == true)) { + fm_low_ops.bi.pwroff(0); + fm->chipon = false; + } + + return ret; +} + +signed int fm_powerdowntx(struct fm *fm) +{ + signed int ret = 0; + + if (fm_low_ops.bi.pwrdownseq_tx == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_rxtx_lock)) + return -FM_ELOCK; + + if (fm_pwr_state_get(fm) == FM_PWR_TX_ON) { + /* fm_low_ops.ri.rds_onoff(fm->pstRDSData, false); */ + /* execute power down sequence */ + ret = fm_low_ops.bi.pwrdownseq_tx(); + if (ret) + WCN_DBG(FM_ERR | MAIN, "pwrdown tx fail\n"); + + fm_pwr_state_set(fm, FM_PWR_OFF); + WCN_DBG(FM_NTC | MAIN, "pwrdown tx ok\n"); + } + + FM_UNLOCK(fm_rxtx_lock); + /* FM_UNLOCK(fm_ops_lock); */ + return ret; +} + +/*********************************************************** +* Function: fm_tx_scan() +* +* Description: get the valid channels for fm tx function +* +* Para: fm--->fm driver global info +* parm--->input/output parameter +* +* Return: 0, if success; error code, if failed +***********************************************************/ +signed int fm_tx_scan(struct fm *fm, struct fm_tx_scan_parm *parm) +{ + signed int ret = 0; + unsigned short scandir = 0; + unsigned short space = parm->space; + + if (fm_low_ops.bi.tx_scan == NULL) { + pr_err("%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if (fm->chipon != true) { + parm->err = FM_BADSTATUS; + ret = -EPERM; + WCN_DBG(FM_ERR | MAIN, "tx scan chip not on\n"); + goto out; + } + switch (parm->scandir) { + case FM_TX_SCAN_UP: + scandir = 0; + break; + case FM_TX_SCAN_DOWN: + scandir = 1; + break; + default: + scandir = 0; + break; + } + + if (parm->band == FM_BAND_UE) { + fm->min_freq = FM_UE_FREQ_MIN; + fm->max_freq = FM_UE_FREQ_MAX; + } else if (parm->band == FM_BAND_JAPANW) { + fm->min_freq = FM_JP_FREQ_MIN; + fm->max_freq = FM_JP_FREQ_MAX; + } else if (parm->band == FM_BAND_SPECIAL) { + fm->min_freq = FM_FREQ_MIN; + fm->max_freq = FM_FREQ_MAX; + } else { + WCN_DBG(FM_ERR | MAIN, "band:%d out of range\n", parm->band); + parm->err = FM_EPARM; + ret = -EPERM; + goto out; + } + + if (unlikely((parm->freq < fm->min_freq) || (parm->freq > fm->max_freq))) { + parm->err = FM_EPARM; + ret = -EPERM; + WCN_DBG(FM_ERR | MAIN, "%s parm->freq:%d fm->min_freq: %d fm->max_freq:%d\n", + __func__, parm->freq, fm->min_freq, fm->max_freq); + goto out; + } + + if (unlikely(parm->ScanTBLSize < TX_SCAN_MIN || parm->ScanTBLSize > TX_SCAN_MAX)) { + parm->err = FM_EPARM; + ret = -EPERM; + WCN_DBG(FM_ERR | MAIN, "%s parm->ScanTBLSize:%d TX_SCAN_MIN:%d TX_SCAN_MAX:%d\n", + __func__, parm->ScanTBLSize, TX_SCAN_MIN, TX_SCAN_MAX); + goto out; + } + + ret = fm_low_ops.bi.anaswitch(FM_ANA_SHORT); + if (ret) { + WCN_DBG(FM_ERR | MAIN, "switch to short ana failed\n"); + goto out; + } + /* do tx scan */ + ret = fm_low_ops.bi.tx_scan(fm->min_freq, fm->max_freq, &(parm->freq), + parm->ScanTBL, &(parm->ScanTBLSize), scandir, space); + if (!ret) { + parm->err = FM_SUCCESS; + } else { + WCN_DBG(FM_ERR | MAIN, "fm_tx_scan failed\n"); + parm->err = FM_SCAN_FAILED; + } +out: + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_cqi_get(struct fm *fm, signed int ch_num, signed char *buf, signed int buf_size) +{ + signed int ret = 0; + signed int idx = 0; + + if (fm_low_ops.bi.cqi_get == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if (true == scan_stop_flag) { + WCN_DBG(FM_NTC | MAIN, "scan flow aborted, do not get CQI\n"); + ret = -1; + goto out; + } + + if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) { + ret = -EPERM; + goto out; + } + + if (ch_num * sizeof(struct fm_cqi) > buf_size) { + ret = -EPERM; + goto out; + } + + fm_op_state_set(fm, FM_STA_SCAN); + + idx = 0; + WCN_DBG(FM_NTC | MAIN, "cqi num %d\n", ch_num); + + while (ch_num > 0) { + ret = + fm_low_ops.bi.cqi_get(buf + 16 * sizeof(struct fm_cqi) * idx, + buf_size - 16 * sizeof(struct fm_cqi) * idx); + + if (ret) + goto out; + + ch_num -= 16; + idx++; + } + + fm_op_state_set(fm, FM_STA_STOP); + +out: + FM_UNLOCK(fm_ops_lock); + return ret; +} + +/* fm_is_dese_chan -- check if gived channel is a de-sense channel or not + * @pfm - fm driver global DS + * @freq - gived channel + * return value: 0, not a dese chan; 1, a dese chan; else error NO. + */ +signed int fm_is_dese_chan(struct fm *pfm, unsigned short freq) +{ + signed int ret = 0; + + if (pfm == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (fm_low_ops.bi.is_dese_chan) { + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + ret = fm_low_ops.bi.is_dese_chan(freq); + FM_UNLOCK(fm_ops_lock); + } + + return ret; +} + +/* fm_is_dese_chan -- check if gived channel is a de-sense channel or not + * @pfm - fm driver global DS + * @freq - gived channel + * return value: 0, not a dese chan; 1, a dese chan; else error NO. + */ +signed int fm_desense_check(struct fm *pfm, unsigned short freq, signed int rssi) +{ + signed int ret = 0; + + if (pfm == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (fm_low_ops.bi.desense_check) { + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + ret = fm_low_ops.bi.desense_check(freq, rssi); + FM_UNLOCK(fm_ops_lock); + } + + return ret; +} + +signed int fm_dump_reg(void) +{ + signed int ret = 0; + + if (fm_low_ops.bi.dumpreg) { + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + ret = fm_low_ops.bi.dumpreg(); + FM_UNLOCK(fm_ops_lock); + } + return ret; +} + +/* fm_get_hw_info -- hw info: chip id, ECO version, DSP ROM version, Patch version + * @pfm - fm driver global DS + * @freq - target buffer + * return value: 0, success; else error NO. + */ +signed int fm_get_hw_info(struct fm *pfm, struct fm_hw_info *req) +{ + signed int ret = 0; + + if (req == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + /* default value for all chips */ + req->chip_id = 0x000066FF; + req->eco_ver = 0x00000000; + req->rom_ver = 0x00000001; + req->patch_ver = 0x00000100; + req->reserve = 0x00000000; + + /* get actual chip hw info */ + if (fm_low_ops.bi.hwinfo_get) { + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + ret = fm_low_ops.bi.hwinfo_get(req); + FM_UNLOCK(fm_ops_lock); + } + + return ret; +} + +signed int fm_get_aud_info(struct fm_audio_info_t *data) +{ + if (fm_low_ops.bi.get_aud_info) + return fm_low_ops.bi.get_aud_info(data); + + data->aud_path = FM_AUD_ERR; + data->i2s_info.mode = FM_I2S_MODE_ERR; + data->i2s_info.status = FM_I2S_STATE_ERR; + data->i2s_info.rate = FM_I2S_SR_ERR; + data->i2s_pad = FM_I2S_PAD_ERR; + return 0; +} + +/* fm_get_i2s_info -- i2s info: on/off, master/slave, sample rate + * @pfm - fm driver global DS + * @req - target buffer + * return value: 0, success; else error NO. + */ +signed int fm_get_i2s_info(struct fm *pfm, struct fm_i2s_info *req) +{ + if (fm_low_ops.bi.i2s_get == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + return fm_low_ops.bi.i2s_get(&req->status, &req->mode, &req->rate); +} + +signed int fm_hwscan_stop(struct fm *fm) +{ + signed int ret = 0; + + if ((fm_op_state_get(fm) != FM_STA_SCAN) && (fm_op_state_get(fm) != FM_STA_SEEK)) { + WCN_DBG(FM_WAR | MAIN, "fm isn't on scan, no need stop\n"); + return ret; + } + + if (fm_low_ops.bi.scanstop == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + fm_low_ops.bi.scanstop(); + fm_low_ops.bi.seekstop(); + scan_stop_flag = true; + WCN_DBG(FM_DBG | MAIN, "fm will stop scan\n"); + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + fm_low_ops.bi.rampdown(); + fm_low_ops.bi.setfreq(fm_cur_freq_get()); + + FM_UNLOCK(fm_ops_lock); + + return ret; +} + +/* fm_ana_switch -- switch antenna to long/short + * @fm - fm driver main data structure + * @antenna - 0, long; 1, short + * If success, return 0; else error code + */ +signed int fm_ana_switch(struct fm *fm, signed int antenna) +{ + signed int ret = 0; + + if (fm_low_ops.bi.anaswitch == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + WCN_DBG(FM_DBG | MAIN, "Switching ana to %s\n", antenna ? "short" : "long"); + fm->ana_type = antenna; + + if ((fm_pwr_state_get(fm) == FM_PWR_RX_ON) || (fm_pwr_state_get(fm) == FM_PWR_TX_ON)) + ret = fm_low_ops.bi.anaswitch(antenna); + + if (ret) + WCN_DBG(FM_ALT | MAIN, "Switch ana Failed\n"); + else + WCN_DBG(FM_DBG | MAIN, "Switch ana OK!\n"); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +/* volume?[0~15] */ +signed int fm_setvol(struct fm *fm, unsigned int vol) +{ + unsigned char tmp_vol; + + if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) + return -EPERM; + + if (fm_low_ops.bi.volset == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + tmp_vol = (vol > 15) ? 15 : vol; + fm_low_ops.bi.volset(tmp_vol); + fm->vol = (signed int) tmp_vol; + + FM_UNLOCK(fm_ops_lock); + return 0; +} + +signed int fm_getvol(struct fm *fm, unsigned int *vol) +{ + unsigned char tmp_vol; + + if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) + return -EPERM; + + if (fm_low_ops.bi.volget == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + fm_low_ops.bi.volget(&tmp_vol); + *vol = (unsigned int) tmp_vol; + + FM_UNLOCK(fm_ops_lock); + return 0; +} + +signed int fm_mute(struct fm *fm, unsigned int bmute) +{ + signed int ret = 0; + + if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) { + ret = -EPERM; + return ret; + } + if (fm_low_ops.bi.mute == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if (bmute) { + ret = fm_low_ops.bi.mute(true); + fm->mute = true; + } else { + ret = fm_low_ops.bi.mute(false); + fm->mute = false; + } + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_getrssi(struct fm *fm, signed int *rssi) +{ + signed int ret = 0; + + if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) { + ret = -EPERM; + return ret; + } + if (fm_low_ops.bi.rssiget == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_low_ops.bi.rssiget(rssi); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_read(struct fm *fm, unsigned char addr, unsigned short *val) +{ + signed int ret = 0; + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_reg_read(addr, val); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_write(struct fm *fm, unsigned char addr, unsigned short val) +{ + signed int ret = 0; + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_reg_write(addr, val); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_top_read(struct fm *fm, unsigned short addr, unsigned int *val) +{ + signed int ret = 0; + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_top_reg_read(addr, val); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_top_write(struct fm *fm, unsigned short addr, unsigned int val) +{ + signed int ret = 0; + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_top_reg_write(addr, val); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_host_read(struct fm *fm, unsigned int addr, unsigned int *val) +{ + signed int ret = 0; + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_host_reg_read(addr, val); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_host_write(struct fm *fm, unsigned int addr, unsigned int val) +{ + signed int ret = 0; + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_host_reg_write(addr, val); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_pmic_read(struct fm *fm, unsigned char addr, unsigned int *val) +{ + signed int ret = 0; + + if (fm_low_ops.bi.pmic_read == NULL) { + pr_err("%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_low_ops.bi.pmic_read(addr, val); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_pmic_write(struct fm *fm, unsigned char addr, unsigned int val) +{ + signed int ret = 0; + + if (fm_low_ops.bi.pmic_write == NULL) { + pr_err("%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_low_ops.bi.pmic_write(addr, val); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_chipid_get(struct fm *fm, unsigned short *chipid) +{ + if (chipid == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + *chipid = fm->chip_id; + + FM_UNLOCK(fm_ops_lock); + return 0; +} + +signed int fm_monostereo_get(struct fm *fm, unsigned short *ms) +{ + signed int ret = 0; + + if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) { + ret = -EPERM; + return ret; + } + + if (fm_low_ops.bi.msget == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (ms == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if (fm_low_ops.bi.msget(ms) == false) + ret = -FM_EPARA; + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +/* + * Force set to stero/mono mode + * @MonoStereo -- 0, auto; 1, mono + * If success, return 0; else error code + */ +signed int fm_monostereo_set(struct fm *fm, signed int ms) +{ + signed int ret = 0; + + if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) { + ret = -EPERM; + return ret; + } + + if (fm_low_ops.bi.msset == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_low_ops.bi.msset(ms); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_pamd_get(struct fm *fm, unsigned short *pamd) +{ + signed int ret = 0; + + if (fm_low_ops.bi.pamdget == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (pamd == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if (fm_low_ops.bi.pamdget(pamd) == false) + ret = -FM_EPARA; + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_caparray_get(struct fm *fm, signed int *ca) +{ + signed int ret = 0; + + if (fm_low_ops.bi.caparray_get == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (ca == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_low_ops.bi.caparray_get(ca); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_em_test(struct fm *fm, unsigned short group, unsigned short item, unsigned int val) +{ + signed int ret = 0; + + if (fm_low_ops.bi.em == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if (false == fm_low_ops.bi.em(group, item, val)) + ret = -FM_EPARA; + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_set_search_th(struct fm *fm, struct fm_search_threshold_t parm) +{ + signed int ret = 0; + + if (fm_low_ops.bi.set_search_th == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + ret = fm_low_ops.bi.set_search_th(parm.th_type, parm.th_val, parm.reserve); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_rds_tx(struct fm *fm, struct fm_rds_tx_parm *parm) +{ + signed int ret = 0; + + if (fm_low_ops.ri.rds_tx == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (fm_pwr_state_get(fm) != FM_PWR_TX_ON) { + parm->err = FM_BADSTATUS; + ret = -FM_EPARA; + goto out; + } + if (parm->other_rds_cnt > 29) { + parm->err = FM_EPARM; + WCN_DBG(FM_ERR | MAIN, "other_rds_cnt=%d\n", parm->other_rds_cnt); + ret = -FM_EPARA; + goto out; + } + + ret = fm_low_ops.ri.rds_tx(parm->pi, parm->ps, parm->other_rds, parm->other_rds_cnt); + if (ret) { + WCN_DBG(FM_ERR | MAIN, "Rds_Tx failed!\n"); + goto out; + } +/* fm_cxt->txcxt.rdsTxOn = true; */ +/* fm_cxt->txcxt.pi = parm->pi; */ +/* memcpy(fm_cxt->txcxt.ps, parm->ps,sizeof(parm->ps)); */ +/* memcpy(fm_cxt->txcxt.other_rds, parm->other_rds,sizeof(parm->other_rds)); */ +/* fm_cxt->txcxt.other_rds_cnt = parm->other_rds_cnt; */ +out: + return ret; +} + +signed int fm_rds_onoff(struct fm *fm, unsigned short rdson_off) +{ + signed int ret = 0; + + if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) { + ret = -EPERM; + goto out; + } + if (fm_low_ops.ri.rds_onoff == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if (rdson_off) { + fm->rds_on = true; + if (fm_low_ops.ri.rds_onoff(fm->pstRDSData, true) == false) { + WCN_DBG(FM_ALT | MAIN, "FM_IOCTL_RDS_ONOFF on faield\n"); + ret = -EPERM; + goto out; + } + + fm_enable_rds_BlerCheck(fm); + } else { + fm->rds_on = false; + fm_disable_rds_BlerCheck(); + if (fm_low_ops.ri.rds_onoff(fm->pstRDSData, false) == false) { + WCN_DBG(FM_ALT | MAIN, "FM_IOCTL_RDS_ONOFF off faield\n"); + ret = -EPERM; + }; + } + +out: + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_rds_good_bc_get(struct fm *fm, unsigned short *gbc) +{ + signed int ret = 0; + + if (fm_low_ops.ri.rds_gbc_get == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (gbc == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + *gbc = fm_low_ops.ri.rds_gbc_get(); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_rds_bad_bc_get(struct fm *fm, unsigned short *bbc) +{ + signed int ret = 0; + + if (fm_low_ops.ri.rds_gbc_get == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (bbc == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + *bbc = fm_low_ops.ri.rds_bbc_get(); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_rds_bler_ratio_get(struct fm *fm, unsigned short *bbr) +{ + signed int ret = 0; + + if (fm_low_ops.ri.rds_bbr_get == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (bbr == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + *bbr = (unsigned short) fm_low_ops.ri.rds_bbr_get(); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_rds_group_cnt_get(struct fm *fm, struct rds_group_cnt_t *dst) +{ + signed int ret = 0; + + if (fm_low_ops.ri.rds_gc_get == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (dst == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_rds_cnt)) + return -FM_ELOCK; + + ret = fm_low_ops.ri.rds_gc_get(dst, fm->pstRDSData); + + FM_UNLOCK(fm_rds_cnt); + return ret; +} + +signed int fm_rds_group_cnt_reset(struct fm *fm) +{ + signed int ret = 0; + + if (fm_low_ops.ri.rds_gc_reset == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_rds_cnt)) + return -FM_ELOCK; + + ret = fm_low_ops.ri.rds_gc_reset(fm->pstRDSData); + + FM_UNLOCK(fm_rds_cnt); + return ret; +} + +signed int fm_rds_log_get(struct fm *fm, struct rds_rx_t *dst, signed int *dst_len) +{ + signed int ret = 0; + + if (fm_low_ops.ri.rds_log_get == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (dst == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (dst_len == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_read_lock)) + return -FM_ELOCK; + + ret = fm_low_ops.ri.rds_log_get(dst, dst_len); + + FM_UNLOCK(fm_read_lock); + return ret; +} + +signed int fm_rds_block_cnt_reset(struct fm *fm) +{ + signed int ret = 0; + + if (fm_low_ops.ri.rds_bc_reset == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_low_ops.ri.rds_bc_reset(); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_i2s_set(struct fm *fm, signed int onoff, signed int mode, signed int sample) +{ + signed int ret = 0; + + if (fm_low_ops.bi.i2s_set == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if ((onoff != 0) && (onoff != 1)) + onoff = 0; /* default set i2s on in case user input illegal.*/ + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if ((fm_pwr_state_get(fm) == FM_PWR_RX_ON) || (fm_pwr_state_get(fm) == FM_PWR_TX_ON)) + ret = fm_low_ops.bi.i2s_set(onoff, mode, sample); + if (ret) + WCN_DBG(FM_ALT | MAIN, "i2s setting Failed\n"); + else + WCN_DBG(FM_INF | MAIN, "i2s setting OK!\n"); + + FM_UNLOCK(fm_ops_lock); + return ret; +} + +/* + * fm_tune_tx + */ +signed int fm_tune_tx(struct fm *fm, struct fm_tune_parm *parm) +{ + signed int ret = 0; + + if (fm_low_ops.bi.tune_tx == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (fm_pwr_state_get(fm) != FM_PWR_TX_ON) { + parm->err = FM_BADSTATUS; + return -EPERM; + } + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + WCN_DBG(FM_DBG | MAIN, "%s\n", __func__); + + fm_op_state_set(fm, FM_STA_TUNE); + WCN_DBG(FM_NTC | MAIN, "Tx tune to %d\n", parm->freq); + /* tune to desired channel */ + if (true != fm_low_ops.bi.tune_tx(parm->freq)) { + parm->err = FM_TUNE_FAILED; + WCN_DBG(FM_ALT | MAIN, "Tx tune failed\n"); + ret = -EPERM; + } + fm_op_state_set(fm, FM_STA_PLAY); + FM_UNLOCK(fm_ops_lock); + + return ret; +} + +/* + * fm_tune + */ +signed int fm_tune(struct fm *fm, struct fm_tune_parm *parm) +{ + signed int ret = 0; + signed int len = 0; + struct rds_raw_t rds_log; + +#if (FM_INVALID_CHAN_NOISE_REDUCING) + fm_cqi_check_timer->stop(fm_cqi_check_timer); +#endif + + if (fm_low_ops.bi.mute == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (fm_low_ops.bi.rampdown == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (fm_low_ops.bi.setfreq == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + WCN_DBG(FM_INF | MAIN, "%s\n", __func__); + + /* clean RDS first in case RDS event report before tune success */ + /* clean RDS data */ + fm_memset(fm->pstRDSData, 0, sizeof(struct rds_t)); + + /* clean RDS log buffer */ + do { + ret = fm_rds_log_get(fm, (struct rds_rx_t *)&(rds_log.data), &len); + rds_log.dirty = true; + rds_log.len = (len < sizeof(rds_log.data)) ? len : sizeof(rds_log.data); + WCN_DBG(FM_ALT | MAIN, "clean rds log, rds_log.len =%d\n", rds_log.len); + if (ret < 0) + break; + } while (rds_log.len > 0); + + if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) { + parm->err = FM_BADSTATUS; + ret = -EPERM; + goto out; + } +/* fm_low_ops.bi.mute(true); */ + ret = fm_low_ops.bi.rampdown(); + if (ret) { + WCN_DBG(FM_ALT | MAIN, "FM ramp down failed\n"); + goto out; + } + + fm_op_state_set(fm, FM_STA_TUNE); + WCN_DBG(FM_ALT | MAIN, "tuning to %d\n", parm->freq); + + if (true != fm_low_ops.bi.setfreq(parm->freq)) { + parm->err = FM_TUNE_FAILED; + WCN_DBG(FM_ALT | MAIN, "FM tune failed\n"); + ret = -FM_EFW; + } + +#if (FM_INVALID_CHAN_NOISE_REDUCING) + if (fm_low_ops.bi.is_valid_freq) { + if (fm_low_ops.bi.is_valid_freq(parm->freq)) { + if (fm->vol != 15) { + fm_low_ops.bi.volset(15); + fm->vol = 15; + WCN_DBG(FM_NTC | MAIN, "Valid freq, volset: 15\n"); + } + WCN_DBG(FM_NTC | MAIN, "FM tune to a valid channel resume volume.\n"); + } else { + if (fm->vol != 5) { + fm_low_ops.bi.volset(5); + fm->vol = 5; + WCN_DBG(FM_NTC | MAIN, "Not a valid freq, volset: 5\n"); + } + WCN_DBG(FM_NTC | MAIN, "FM tune to an invalid channel.\n"); + fm_cqi_check_timer->start(fm_cqi_check_timer); + } + } +#endif + /* fm_low_ops.bi.mute(false);//open for dbg */ + fm_op_state_set(fm, FM_STA_PLAY); +out: + FM_UNLOCK(fm_ops_lock); + return ret; +} + +/* cqi log tool entry */ +signed int fm_cqi_log(void) +{ + signed int ret = 0; + unsigned short freq; + + if (fm_low_ops.bi.cqi_log == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + freq = fm_cur_freq_get(); + if (fm_get_channel_space(freq) == 0) + freq *= 10; + + if ((freq != 10000) && (g_dbg_level != 0xffffffff)) + return -FM_EPARA; + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_low_ops.bi.cqi_log(8750, 10800, 2, 5); + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_pre_search(struct fm *fm) +{ + signed int ret = 0; + + if (fm_low_ops.bi.pre_search == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) + return -FM_EPARA; + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + WCN_DBG(FM_INF | MAIN, "%s\n", __func__); + + ret = fm_low_ops.bi.pre_search(); + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_restore_search(struct fm *fm) +{ + signed int ret = 0; + + if (fm_low_ops.bi.restore_search == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) + return -FM_EPARA; + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + WCN_DBG(FM_INF | MAIN, "%s\n", __func__); + + ret = fm_low_ops.bi.restore_search(); + FM_UNLOCK(fm_ops_lock); + return ret; +} + +/*fm soft mute tune function*/ +signed int fm_soft_mute_tune(struct fm *fm, struct fm_softmute_tune_t *parm) +{ + signed int ret = 0; + +#if (FM_INVALID_CHAN_NOISE_REDUCING) + fm_cqi_check_timer->stop(fm_cqi_check_timer); +#endif + + if (fm_low_ops.bi.softmute_tune == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) { + parm->valid = false; + ret = -EPERM; + goto out; + } + /* fm_low_ops.bi.mute(true); */ + /* fm_op_state_set(fm, FM_STA_TUNE); */ + + if (false == fm_low_ops.bi.softmute_tune(parm->freq, &parm->rssi, &parm->valid)) { + parm->valid = false; + WCN_DBG(FM_ALT | MAIN, "sm tune failed\n"); + ret = -EPERM; + } +/* fm_low_ops.bi.mute(false); */ + WCN_DBG(FM_INF | MAIN, "%s, freq=%d, rssi=%d, valid=%d\n", __func__, parm->freq, parm->rssi, parm->valid); + +out: + FM_UNLOCK(fm_ops_lock); + + return ret; +} + +signed int fm_over_bt(struct fm *fm, signed int flag) +{ + signed int ret = 0; + + if (fm_low_ops.bi.fm_via_bt == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (fm_pwr_state_get(fm) != FM_PWR_RX_ON) + return -EPERM; + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + ret = fm_low_ops.bi.fm_via_bt(flag); + if (ret) + WCN_DBG(FM_ALT | MAIN, "%s(),failed!\n", __func__); + else + fm->via_bt = flag; + + WCN_DBG(FM_NTC | MAIN, "%s(),[ret=%d]!\n", __func__, ret); + FM_UNLOCK(fm_ops_lock); + return ret; +} + +signed int fm_tx_support(struct fm *fm, signed int *support) +{ + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if (fm_low_ops.bi.tx_support) + fm_low_ops.bi.tx_support(support); + else + *support = 0; + + WCN_DBG(FM_NTC | MAIN, "%s(),[%d]!\n", __func__, *support); + FM_UNLOCK(fm_ops_lock); + return 0; +} + +signed int fm_rdstx_support(struct fm *fm, signed int *support) +{ + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + + if (fm_low_ops.ri.rdstx_support) + fm_low_ops.ri.rdstx_support(support); + else + *support = 0; + + WCN_DBG(FM_NTC | MAIN, "support=[%d]!\n", *support); + FM_UNLOCK(fm_ops_lock); + return 0; +} + +/*1:on,0:off*/ +signed int fm_rdstx_enable(struct fm *fm, signed int enable) +{ + signed int ret = -1; + + if (fm_low_ops.ri.rds_tx_enable == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (fm_low_ops.ri.rds_tx_disable == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (fm_pwr_state_get(fm) != FM_PWR_TX_ON) + return -FM_EPARA; + + if (FM_LOCK(fm_ops_lock)) + return -FM_ELOCK; + if (enable == 1) { + ret = fm_low_ops.ri.rds_tx_enable(); + if (ret) + WCN_DBG(FM_ERR | MAIN, "rds_tx_enable fail=[%d]!\n", ret); + + fm->rdstx_on = true; + } else { + ret = fm_low_ops.ri.rds_tx_disable(); + if (ret) + WCN_DBG(FM_ERR | MAIN, "rds_tx_disable fail=[%d]!\n", ret); + + fm->rdstx_on = false; + } + WCN_DBG(FM_NTC | MAIN, "rds tx enable=[%d]!\n", enable); + FM_UNLOCK(fm_ops_lock); + return 0; +} + +static void fm_timer_func(unsigned long data) +{ + struct fm *fm = g_fm_struct; + + if (FM_LOCK(fm_timer_lock)) + return; + + if (fm_timer_sys->update(fm_timer_sys)) { + WCN_DBG(FM_NTC | MAIN, "timer skip\n"); + goto out; /* fm timer is stopped before timeout */ + } + + if (fm != NULL) { + WCN_DBG(FM_DBG | MAIN, "timer:rds_wk\n"); + fm->timer_wkthd->add_work(fm->timer_wkthd, fm->rds_wk); + } + +out: + FM_UNLOCK(fm_timer_lock); +} + +#if (FM_INVALID_CHAN_NOISE_REDUCING) +static void fm_cqi_check_timer_func(unsigned long data) +{ + struct fm *fm = g_fm_struct; + + if (FM_LOCK(fm_timer_lock)) + return; + + if (fm_cqi_check_timer->update(fm_cqi_check_timer)) { + WCN_DBG(FM_NTC | MAIN, "timer skip\n"); + goto out; /* fm timer is stopped before timeout */ + } + + if (fm != NULL) { + WCN_DBG(FM_DBG | MAIN, "timer:ch_valid_check_wk\n"); + fm->timer_wkthd->add_work(fm->timer_wkthd, fm->ch_valid_check_wk); + } + +out: + FM_UNLOCK(fm_timer_lock); +} +#endif + +static void fm_tx_power_ctrl_worker_func(unsigned long data) +{ + signed int ctrl = 0, ret = 0; + struct fm *fm = g_fm_struct; + + WCN_DBG(FM_NTC | MAIN, "+%s():\n", __func__); + + if (fm_low_ops.bi.tx_pwr_ctrl == NULL) + return; + if (FM_LOCK(fm_rxtx_lock)) + return; + + if (fm_pwr_state_get(fm) != FM_PWR_TX_ON) { + WCN_DBG(FM_ERR | MAIN, "FM is not on TX mode\n"); + goto out; + } + + ctrl = fm->tx_pwr; + WCN_DBG(FM_NTC | MAIN, "tx pwr %ddb\n", ctrl); + ret = fm_low_ops.bi.tx_pwr_ctrl(fm_cur_freq_get(), &ctrl); + if (ret) + WCN_DBG(FM_ERR | MAIN, "tx_pwr_ctrl fail\n"); + +out: + FM_UNLOCK(fm_rxtx_lock); + WCN_DBG(FM_NTC | MAIN, "-%s()\n", __func__); +} + +static void fm_tx_rtc_ctrl_worker_func(unsigned long data) +{ + signed int ret = 0; + signed int ctrl = 0; + struct fm_gps_rtc_info rtcInfo; + /* struct timeval curTime; */ + /* struct fm *fm = (struct fm*)fm_cb; */ + unsigned long curTime = 0; + + WCN_DBG(FM_NTC | MAIN, "+%s():\n", __func__); + + if (FM_LOCK(fm_rtc_mutex)) + return; + + if (gps_rtc_info.flag == FM_GPS_RTC_INFO_NEW) { + memcpy(&rtcInfo, &gps_rtc_info, sizeof(struct fm_gps_rtc_info)); + gps_rtc_info.flag = FM_GPS_RTC_INFO_OLD; + FM_UNLOCK(fm_rtc_mutex); + } else { + WCN_DBG(FM_NTC | MAIN, "there's no new rtc drift info\n"); + FM_UNLOCK(fm_rtc_mutex); + goto out; + } + + if (rtcInfo.age > rtcInfo.ageThd) { + WCN_DBG(FM_WAR | MAIN, "age over it's threshlod\n"); + goto out; + } + if ((rtcInfo.drift <= rtcInfo.driftThd) && (rtcInfo.drift >= -rtcInfo.driftThd)) { + WCN_DBG(FM_WAR | MAIN, "drift over it's MIN threshlod\n"); + goto out; + } + + if (rtcInfo.drift > FM_GPS_RTC_DRIFT_MAX) { + WCN_DBG(FM_WAR | MAIN, "drift over it's +MAX threshlod\n"); + rtcInfo.drift = FM_GPS_RTC_DRIFT_MAX; + goto out; + } else if (rtcInfo.drift < -FM_GPS_RTC_DRIFT_MAX) { + WCN_DBG(FM_WAR | MAIN, "drift over it's -MAX threshlod\n"); + rtcInfo.drift = -FM_GPS_RTC_DRIFT_MAX; + goto out; + } + + curTime = jiffies; + if (((long)curTime - (long)rtcInfo.stamp) / HZ > rtcInfo.tvThd.tv_sec) { + WCN_DBG(FM_WAR | MAIN, "time diff over it's threshlod\n"); + goto out; + } + if (fm_low_ops.bi.rtc_drift_ctrl != NULL) { + ctrl = rtcInfo.drift; + WCN_DBG(FM_NTC | MAIN, "RTC_drift_ctrl[0x%08x]\n", ctrl); + + ret = fm_low_ops.bi.rtc_drift_ctrl(fm_cur_freq_get(), &ctrl); + if (ret) + goto out; + } +out: + WCN_DBG(FM_NTC | MAIN, "-%s()\n", __func__); +} + +static void fm_tx_desense_wifi_worker_func(unsigned long data) +{ + signed int ret = 0; + signed int ctrl = 0; + struct fm *fm = g_fm_struct; + + WCN_DBG(FM_NTC | MAIN, "+%s():\n", __func__); + + if (FM_LOCK(fm_rxtx_lock)) + return; + + if (fm_pwr_state_get(fm) != FM_PWR_TX_ON) { + WCN_DBG(FM_ERR | MAIN, "FM is not on TX mode\n"); + goto out; + } + + fm_tx_rtc_ctrl_worker_func(0); + + ctrl = fm->vcoon; + if (fm_low_ops.bi.tx_desense_wifi) { + WCN_DBG(FM_NTC | MAIN, "tx_desense_wifi[%d]\n", ctrl); + ret = fm_low_ops.bi.tx_desense_wifi(fm_cur_freq_get(), &ctrl); + if (ret) + WCN_DBG(FM_ERR | MAIN, "tx_desense_wifi fail\n"); + } +out: + FM_UNLOCK(fm_rxtx_lock); + WCN_DBG(FM_NTC | MAIN, "-%s()\n", __func__); +} + +/* +************************************************************************************ +Function: fm_get_gps_rtc_info() + +Description: get GPS RTC drift info, and this function should not block + +Date: 2011/04/10 + +Return Value: success:0, failed: error coe +************************************************************************************ +*/ +signed int fm_get_gps_rtc_info(struct fm_gps_rtc_info *src) +{ + signed int ret = 0; +/* signed int retry_cnt = 0; */ + struct fm_gps_rtc_info *dst = &gps_rtc_info; + + if (src == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (dst == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (src->retryCnt > 0) { + dst->retryCnt = src->retryCnt; + WCN_DBG(FM_NTC | MAIN, "%s, new [retryCnt=%d]\n", __func__, dst->retryCnt); + } + if (src->ageThd > 0) { + dst->ageThd = src->ageThd; + WCN_DBG(FM_NTC | MAIN, "%s, new [ageThd=%d]\n", __func__, dst->ageThd); + } + if (src->driftThd > 0) { + dst->driftThd = src->driftThd; + WCN_DBG(FM_NTC | MAIN, "%s, new [driftThd=%d]\n", __func__, dst->driftThd); + } + if (src->tvThd.tv_sec > 0) { + dst->tvThd.tv_sec = src->tvThd.tv_sec; + WCN_DBG(FM_NTC | MAIN, "%s, new [tvThd=%d]\n", __func__, (signed int) dst->tvThd.tv_sec); + } + ret = fm_rtc_mutex->trylock(fm_rtc_mutex, dst->retryCnt); + if (ret) + goto out; + + dst->age = src->age; + dst->drift = src->drift; + dst->stamp = jiffies; /* get curren time stamp */ + dst->flag = FM_GPS_RTC_INFO_NEW; + + FM_UNLOCK(fm_rtc_mutex); + + +out: + return ret; +} + +static void fm_enable_rds_BlerCheck(struct fm *fm) +{ + if (FM_LOCK(fm_timer_lock)) + return; + fm_timer_sys->start(fm_timer_sys); + FM_UNLOCK(fm_timer_lock); + WCN_DBG(FM_INF | MAIN, "enable rds timer ok\n"); +} + +static void fm_disable_rds_BlerCheck(void) +{ + if (FM_LOCK(fm_timer_lock)) + return; + fm_timer_sys->stop(fm_timer_sys); + FM_UNLOCK(fm_timer_lock); + WCN_DBG(FM_INF | MAIN, "stop rds timer ok\n"); +} + +void fm_rds_reset_work_func(unsigned long data) +{ + signed int ret = 0; + + if (!fm_low_ops.ri.rds_blercheck) + return; + + if (FM_LOCK(fm_rxtx_lock)) + return; + + if (FM_LOCK(fm_rds_cnt)) + return; + + ret = fm_low_ops.ri.rds_blercheck(g_fm_struct->pstRDSData); + + if (ret || g_fm_struct->pstRDSData->AF_Data.Addr_Cnt || g_fm_struct->pstRDSData->event_status) { + WCN_DBG(FM_NTC | MAIN, "ret=%d, Addr_Cnt=0x%02x, event_status=0x%04x\n", ret, + g_fm_struct->pstRDSData->AF_Data.Addr_Cnt, g_fm_struct->pstRDSData->event_status); + } + /* check af list get,can't use event==af_list because event will clear after read rds every time */ + if (g_fm_struct->pstRDSData->AF_Data.Addr_Cnt == 0xFF) + g_fm_struct->pstRDSData->event_status |= RDS_EVENT_AF; + + if (!ret && g_fm_struct->pstRDSData->event_status) + FM_EVENT_SEND(g_fm_struct->rds_event, FM_RDS_DATA_READY); + + FM_UNLOCK(fm_rds_cnt); + FM_UNLOCK(fm_rxtx_lock); +} + +#if (FM_INVALID_CHAN_NOISE_REDUCING) +void fm_cqi_check_work_func(unsigned long data) +{ + struct fm *fm = g_fm_struct; + + if (!fm) + return; + + if (FM_LOCK(fm_ops_lock)) + return; + + if (fm_low_ops.bi.is_valid_freq) { + if (fm_low_ops.bi.is_valid_freq(fm->cur_freq)) { + if (fm->vol != 15) { + fm_low_ops.bi.volset(15); + fm->vol = 15; + WCN_DBG(FM_NTC | MAIN, "Valid freq, volset: 15\n"); + } + } else { + if (fm->vol != 5) { + fm_low_ops.bi.volset(5); + fm->vol = 5; + WCN_DBG(FM_NTC | MAIN, "Not a valid freq, volset: 5\n"); + } + } + } + + FM_UNLOCK(fm_ops_lock); +} +#endif + +void fm_subsys_reset_work_func(unsigned long data) +{ + g_dbg_level = 0xffffffff; + if (FM_LOCK(fm_ops_lock)) + return; + + fm_sys_state_set(g_fm_struct, FM_SUBSYS_RST_START); + + if (g_fm_struct->chipon == false) { + WCN_DBG(FM_ALT | MAIN, "chip off no need do recover\n"); + goto out; + } + + /* if whole chip reset, wmt will clear fm-on-flag, and firmware turn fm to off status, + * so no need turn fm off again + */ + if (g_fm_struct->wholechiprst == false) { + fm_low_ops.bi.pwrdownseq(); + /* subsystem power off */ + if (fm_low_ops.bi.pwroff(0)) { + WCN_DBG(FM_ALT | MAIN, "chip off fail\n"); + goto out; + } + } + + /* subsystem power on */ + if (fm_low_ops.bi.pwron(0)) { + WCN_DBG(FM_ALT | MAIN, "chip on fail\n"); + goto out; + } + /* recover context */ + if (g_fm_struct->chipon == false) { + fm_low_ops.bi.pwroff(0); + WCN_DBG(FM_ALT | MAIN, "no need do recover\n"); + goto out; + } + + if (fm_pwr_state_get(g_fm_struct) == FM_PWR_RX_ON) { + fm_low_ops.bi.pwrupseq(&g_fm_struct->chip_id, &g_fm_struct->device_id); + } else { + WCN_DBG(FM_ALT | MAIN, "no need do re-powerup\n"); + goto out; + } + + fm_low_ops.bi.anaswitch(g_fm_struct->ana_type); + + fm_low_ops.bi.setfreq(fm_cur_freq_get()); + + fm_low_ops.bi.volset((unsigned char) g_fm_struct->vol); + + g_fm_struct->mute = 0; + fm_low_ops.bi.mute(g_fm_struct->mute); + + if (fm_low_ops.ri.rds_bci_get) { + fm_timer_sys->init(fm_timer_sys, fm_timer_func, (unsigned long)g_fm_struct, fm_low_ops.ri.rds_bci_get(), + 0); + WCN_DBG(FM_NTC | MAIN, "initial timer ok\n"); + } else { + WCN_DBG(FM_NTC | MAIN, "initial timer fail!!!\n"); + } + +#if (FM_INVALID_CHAN_NOISE_REDUCING) + fm_cqi_check_timer->init(fm_cqi_check_timer, fm_cqi_check_timer_func, + (unsigned long)g_fm_struct, 1000, 0); +#endif + g_fm_struct->rds_on = 1; + fm_low_ops.ri.rds_onoff(g_fm_struct->pstRDSData, g_fm_struct->rds_on); + + WCN_DBG(FM_ALT | MAIN, "recover done\n"); + +out: + fm_sys_state_set(g_fm_struct, FM_SUBSYS_RST_END); + fm_sys_state_set(g_fm_struct, FM_SUBSYS_RST_OFF); + g_fm_struct->wholechiprst = true; + + FM_UNLOCK(fm_ops_lock); + g_dbg_level = 0xfffffff5; +} + +void fm_pwroff_work_func(unsigned long data) +{ + fm_powerdown(g_fm_struct, 0); +} + +static void fm_eint_handler(void) +{ + struct fm *fm = g_fm_struct; + + WCN_DBG(FM_DBG | MAIN, "intr occur, ticks:%d\n", jiffies_to_msecs(jiffies)); + + if (fm != NULL) + fm->eint_wkthd->add_work(fm->eint_wkthd, fm->eint_wk); +} + +signed int fm_rds_parser(struct rds_rx_t *rds_raw, signed int rds_size) +{ + struct fm *fm = g_fm_struct; /* (struct fm *)work->data; */ + struct rds_t *pstRDSData = fm->pstRDSData; + + if (FM_LOCK(fm_read_lock)) + return -FM_ELOCK; + /* parsing RDS data */ + fm_low_ops.ri.rds_parser(pstRDSData, rds_raw, rds_size, fm_cur_freq_get); + FM_UNLOCK(fm_read_lock); + + if ((pstRDSData->event_status != 0x0000) && (pstRDSData->event_status != RDS_EVENT_AF_LIST)) { + WCN_DBG(FM_NTC | MAIN, "Notify user to read, [event:0x%04x]\n", pstRDSData->event_status); + FM_EVENT_SEND(fm->rds_event, FM_RDS_DATA_READY); + } + + return 0; +} + +static void fm_eint_work_func(unsigned long data) +{ + if (fm_wcn_ops.ei.eint_handler) + fm_wcn_ops.ei.eint_handler(); + /* re-enable eint if need */ + fm_enable_eint(); +} + +static signed int fm_callback_register(struct fm_callback *cb) +{ + if (cb == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + cb->cur_freq_get = fm_cur_freq_get; + cb->cur_freq_set = fm_cur_freq_set; + cb->projectid_get = fm_projectid_get; + return 0; +} + +static signed int fm_ops_register(struct fm_lowlevel_ops *ops) +{ + signed int ret = 0; + + ret = fm_wcn_ops_register(); + if (ret) { + WCN_DBG(FM_ERR | MAIN, "fm_wcn_ops_register fail(%d)\n", ret); + return ret; + } + + ret = fm_callback_register(&ops->cb); + if (ret) { + WCN_DBG(FM_ERR | MAIN, "fm_callback_register fail(%d)\n", ret); + return ret; + } + + ret = fm_low_ops_register(&ops->cb, &ops->bi); + if (ret) { + WCN_DBG(FM_ERR | MAIN, "fm_low_ops_register fail(%d)\n", ret); + return ret; + } + + ret = fm_rds_ops_register(&ops->bi, &ops->ri); + if (ret) { + WCN_DBG(FM_ERR | MAIN, "fm_rds_ops_register fail(%d)\n", ret); + return ret; + } + + return ret; +} +static signed int fm_callback_unregister(struct fm_callback *cb) +{ + if (cb == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,cb invalid pointer\n", __func__); + return -FM_EPARA; + } + + fm_memset(cb, 0, sizeof(struct fm_callback)); + return 0; +} + +static signed int fm_ops_unregister(struct fm_lowlevel_ops *ops) +{ + signed int ret = 0; + + ret = fm_rds_ops_unregister(&ops->ri); + if (ret) { + WCN_DBG(FM_ERR | MAIN, "fm_rds_ops_unregister fail(%d)\n", ret); + return ret; + } + + ret = fm_low_ops_unregister(&ops->bi); + if (ret) { + WCN_DBG(FM_ERR | MAIN, "fm_low_ops_unregister fail(%d)\n", ret); + return ret; + } + + ret = fm_callback_unregister(&ops->cb); + if (ret) { + WCN_DBG(FM_ERR | MAIN, "fm_callback_unregister fail(%d)\n", ret); + return ret; + } + + return ret; +} + +static signed short fm_cust_config_setting(void) +{ + unsigned short chipid = 0; + enum fm_cfg_chip_type type = FM_CHIP_TYPE_MAX; + + if (fm_low_ops.bi.chipid_get) + chipid = fm_low_ops.bi.chipid_get(); + fm_which_chip(chipid, &type); + WCN_DBG(FM_NTC | MAIN, "chipid:0x%x, chip type:%d\n", chipid, type); + + fm_cust_config_chip(chipid, type); + /* init customer config parameter */ + fm_cust_config_setup(NULL); + + return 0; +} + +struct fm *fm_dev_init(unsigned int arg) +{ + signed int ret = 0; + struct fm *fm = NULL; + +/* if (!fm_low_ops.ri.rds_bci_get) */ +/* return NULL; */ + + /* alloc fm main data structure */ + fm = fm_zalloc(sizeof(struct fm)); + if (!fm) { + WCN_DBG(FM_ALT | MAIN, "-ENOMEM\n"); + ret = -ENOMEM; + return NULL; + } + + fm->ref = 0; + fm->chipon = false; + fm_pwr_state_set(fm, FM_PWR_OFF); + /* FM Tx */ + fm->vcoon = FM_TX_VCO_ON_DEFAULT; + fm->vcooff = FM_TX_VCO_OFF_DEFAULT; + fm->txpwrctl = FM_TX_PWR_CTRL_INVAL_DEFAULT; + fm->tx_pwr = FM_TX_PWR_LEVEL_MAX; + fm->wholechiprst = true; + gps_rtc_info.err = 0; + gps_rtc_info.age = 0; + gps_rtc_info.drift = 0; + gps_rtc_info.tv.tv_sec = 0; + gps_rtc_info.tv.tv_usec = 0; + gps_rtc_info.ageThd = FM_GPS_RTC_AGE_TH; + gps_rtc_info.driftThd = FM_GPS_RTC_DRIFT_TH; + gps_rtc_info.tvThd.tv_sec = FM_GPS_RTC_TIME_DIFF_TH; + gps_rtc_info.retryCnt = FM_GPS_RTC_RETRY_CNT; + gps_rtc_info.flag = FM_GPS_RTC_INFO_OLD; + + fm->rds_event = fm_flag_event_create("fm_rds_event"); + if (!fm->rds_event) { + WCN_DBG(FM_ALT | MAIN, "-ENOMEM for RDS event\n"); + ret = -ENOMEM; + goto ERR_EXIT; + } + + fm_flag_event_get(fm->rds_event); + + /* alloc fm rds data structure */ + fm->pstRDSData = fm_zalloc(sizeof(struct rds_t)); + if (!fm->pstRDSData) { + WCN_DBG(FM_ALT | MAIN, "-ENOMEM for RDS\n"); + ret = -ENOMEM; + goto ERR_EXIT; + } + + g_fm_struct = fm; + + fm->timer_wkthd = fm_workthread_create("fm_timer_wq"); + + if (!fm->timer_wkthd) { + WCN_DBG(FM_ALT | MAIN, "-ENOMEM for fm_timer_wq\n"); + ret = -ENOMEM; + goto ERR_EXIT; + } + + fm_workthread_get(fm->timer_wkthd); + + fm->eint_wkthd = fm_workthread_create("fm_eint_wq"); + + if (!fm->eint_wkthd) { + WCN_DBG(FM_ALT | MAIN, "-ENOMEM for fm_eint_wq\n"); + ret = -ENOMEM; + goto ERR_EXIT; + } + + fm_workthread_get(fm->eint_wkthd); + + fm->eint_wk = fm_work_create("fm_eint_work"); + + if (!fm->eint_wk) { + WCN_DBG(FM_ALT | MAIN, "-ENOMEM for eint_wk\n"); + ret = -ENOMEM; + goto ERR_EXIT; + } else { + fm_work_get(fm->eint_wk); + fm->eint_wk->init(fm->eint_wk, fm_eint_work_func, (unsigned long)fm); + } + + /* create reset work */ + fm->rst_wk = fm_work_create("fm_rst_work"); + + if (!fm->rst_wk) { + WCN_DBG(FM_ALT | MAIN, "-ENOMEM for rst_wk\n"); + ret = -ENOMEM; + goto ERR_EXIT; + } else { + fm_work_get(fm->rst_wk); + fm->rst_wk->init(fm->rst_wk, fm_subsys_reset_work_func, (unsigned long)fm); + } + + fm->rds_wk = fm_work_create("fm_rds_work"); + if (!fm->rds_wk) { + WCN_DBG(FM_ALT | MAIN, "-ENOMEM for rds_wk\n"); + ret = -ENOMEM; + goto ERR_EXIT; + } else { + fm_work_get(fm->rds_wk); + fm->rds_wk->init(fm->rds_wk, fm_rds_reset_work_func, (unsigned long)fm); + } + +#if (FM_INVALID_CHAN_NOISE_REDUCING) + fm->ch_valid_check_wk = fm_work_create("fm_ch_valid_check_work"); + if (!fm->ch_valid_check_wk) { + WCN_DBG(FM_ALT | MAIN, "-ENOMEM for ch_valid_check_wk\n"); + ret = -ENOMEM; + goto ERR_EXIT; + } else { + fm_work_get(fm->ch_valid_check_wk); + fm->ch_valid_check_wk->init(fm->ch_valid_check_wk, + fm_cqi_check_work_func, (unsigned long)fm); + } +#endif + + fm->fm_tx_power_ctrl_work = fm_work_create("tx_pwr_ctl_work"); + if (!fm->fm_tx_power_ctrl_work) { + WCN_DBG(FM_ALT | MAIN, "-ENOMEM for tx_pwr_ctl_work\n"); + ret = -ENOMEM; + goto ERR_EXIT; + } else { + fm_work_get(fm->fm_tx_power_ctrl_work); + fm->fm_tx_power_ctrl_work->init(fm->fm_tx_power_ctrl_work, + fm_tx_power_ctrl_worker_func, (unsigned long)fm); + } + + fm->fm_tx_desense_wifi_work = fm_work_create("tx_desen_wifi_work"); + if (!fm->fm_tx_desense_wifi_work) { + WCN_DBG(FM_ALT | MAIN, "-ENOMEM for tx_desen_wifi_work\n"); + ret = -ENOMEM; + goto ERR_EXIT; + } else { + fm_work_get(fm->fm_tx_desense_wifi_work); + fm->fm_tx_desense_wifi_work->init(fm->fm_tx_desense_wifi_work, + fm_tx_desense_wifi_worker_func, (unsigned long)fm); + } + + fm->pwroff_wk = fm_work_create("fm_pwroff_work"); + + if (!fm->pwroff_wk) { + WCN_DBG(FM_ALT | MAIN, "-ENOMEM for pwroff_wk\n"); + ret = -ENOMEM; + goto ERR_EXIT; + } else { + fm_work_get(fm->pwroff_wk); + fm->pwroff_wk->init(fm->pwroff_wk, fm_pwroff_work_func, (unsigned long)fm); + } + + /* fm timer was created in fm_env_setp() */ +/* fm_timer_sys->init(fm_timer_sys, fm_timer_func, (unsigned long)g_fm_struct, fm_low_ops.ri.rds_bci_get(), 0); */ +/* fm_timer_sys->start(fm_timer_sys); */ + fm_cust_config_setting(); + + return g_fm_struct; + +ERR_EXIT: + + if (!fm) { + WCN_DBG(FM_NTC | MAIN, "fm is null\n"); + return NULL; + } + + if (fm->eint_wkthd) { + ret = fm_workthread_put(fm->eint_wkthd); + if (!ret) + fm->eint_wkthd = NULL; + } + + if (fm->timer_wkthd) { + ret = fm_workthread_put(fm->timer_wkthd); + if (!ret) + fm->timer_wkthd = NULL; + } + + if (fm->eint_wk) { + ret = fm_work_put(fm->eint_wk); + if (!ret) + fm->eint_wk = NULL; + } + + if (fm->rds_wk) { + ret = fm_work_put(fm->rds_wk); + if (!ret) + fm->rds_wk = NULL; + } + + if (fm->ch_valid_check_wk) { + ret = fm_work_put(fm->ch_valid_check_wk); + if (!ret) + fm->ch_valid_check_wk = NULL; + } + + if (fm->rst_wk) { + ret = fm_work_put(fm->rst_wk); + if (!ret) + fm->rst_wk = NULL; + } + + if (fm->fm_tx_desense_wifi_work) { + ret = fm_work_put(fm->fm_tx_desense_wifi_work); + if (!ret) + fm->fm_tx_desense_wifi_work = NULL; + } + + if (fm->fm_tx_power_ctrl_work) { + ret = fm_work_put(fm->fm_tx_power_ctrl_work); + if (!ret) + fm->fm_tx_power_ctrl_work = NULL; + } + + if (fm->pwroff_wk) { + ret = fm_work_put(fm->pwroff_wk); + if (!ret) + fm->pwroff_wk = NULL; + } + + if (fm->pstRDSData) { + fm_free(fm->pstRDSData); + fm->pstRDSData = NULL; + } + + fm_free(fm); + g_fm_struct = NULL; + return NULL; +} + +signed int fm_dev_destroy(struct fm *fm) +{ + signed int ret = 0; + + WCN_DBG(FM_DBG | MAIN, "%s\n", __func__); + + fm_timer_sys->stop(fm_timer_sys); +#if (FM_INVALID_CHAN_NOISE_REDUCING) + fm_timer_sys->stop(fm_cqi_check_timer); +#endif + if (!fm) { + WCN_DBG(FM_NTC | MAIN, "fm is null\n"); + return -1; + } + + if (fm->eint_wkthd) { + ret = fm_workthread_put(fm->eint_wkthd); + if (!ret) + fm->eint_wkthd = NULL; + } + + if (fm->timer_wkthd) { + ret = fm_workthread_put(fm->timer_wkthd); + if (!ret) + fm->timer_wkthd = NULL; + } + + if (fm->eint_wk) { + ret = fm_work_put(fm->eint_wk); + if (!ret) + fm->eint_wk = NULL; + } + + if (fm->rds_wk) { + ret = fm_work_put(fm->rds_wk); + if (!ret) + fm->rds_wk = NULL; + } + + if (fm->ch_valid_check_wk) { + ret = fm_work_put(fm->ch_valid_check_wk); + if (!ret) + fm->ch_valid_check_wk = NULL; + } + + if (fm->rst_wk) { + ret = fm_work_put(fm->rst_wk); + if (!ret) + fm->rst_wk = NULL; + } + + if (fm->pwroff_wk) { + ret = fm_work_put(fm->pwroff_wk); + if (!ret) + fm->pwroff_wk = NULL; + } + + if (fm->pstRDSData) { + fm_free(fm->pstRDSData); + fm->pstRDSData = NULL; + } + + if (fm->pstRDSData) { + fm_free(fm->pstRDSData); + fm->pstRDSData = NULL; + } + + fm_flag_event_put(fm->rds_event); + + /* free all memory */ + if (fm) { + fm_free(fm); + fm = NULL; + g_fm_struct = NULL; + } + + return ret; +} + +signed int fm_env_setup(void) +{ + signed int ret = 0; + + WCN_DBG(FM_NTC | MAIN, "%s\n", __func__); + + ret = fm_ops_register(&fm_low_ops); + if (ret) + return ret; + + WCN_DBG(FM_NTC | MAIN, "fm ops registered\n"); + + + fm_ops_lock = fm_lock_create("ops_lock"); + if (!fm_ops_lock) + return -1; + + fm_read_lock = fm_lock_create("rds_read"); + if (!fm_read_lock) + return -1; + + fm_rds_cnt = fm_lock_create("rds_cnt"); + if (!fm_rds_cnt) + return -1; + + fm_timer_lock = fm_spin_lock_create("timer_lock"); + if (!fm_timer_lock) + return -1; + + fm_rxtx_lock = fm_lock_create("rxtx_lock"); + if (!fm_rxtx_lock) + return -1; + + fm_rtc_mutex = fm_lock_create("rtc_lock"); + if (!fm_rxtx_lock) + return -1; + + fm_wcn_ops.tx_lock = fm_lock_create("tx_lock"); + if (!fm_wcn_ops.tx_lock) + return -1; + + fm_wcn_ops.own_lock = fm_lock_create("own_lock"); + if (!fm_wcn_ops.own_lock) + return -1; + + fm_lock_get(fm_ops_lock); + fm_lock_get(fm_read_lock); + fm_lock_get(fm_rds_cnt); + fm_spin_lock_get(fm_timer_lock); + fm_lock_get(fm_rxtx_lock); + fm_lock_get(fm_rtc_mutex); + fm_lock_get(fm_wcn_ops.tx_lock); + fm_lock_get(fm_wcn_ops.own_lock); + WCN_DBG(FM_NTC | MAIN, "fm locks created\n"); + + fm_timer_sys = fm_timer_create("fm_sys_timer"); + + if (!fm_timer_sys) + return -1; + + fm_timer_get(fm_timer_sys); + +#if (FM_INVALID_CHAN_NOISE_REDUCING) + fm_cqi_check_timer = fm_timer_create("fm_cqi_check_timer"); + if (!fm_cqi_check_timer) + return -1; + fm_timer_get(fm_cqi_check_timer); + fm_cqi_check_timer->init(fm_cqi_check_timer, fm_cqi_check_timer_func, (unsigned long)g_fm_struct, 500, 0); +#endif + + WCN_DBG(FM_NTC | MAIN, "fm timer created\n"); + + ret = fm_link_setup((void *)fm_wholechip_rst_cb); + + if (ret) { + WCN_DBG(FM_ERR | MAIN, "fm link setup Failed\n"); + return -1; + } + + return ret; +} + +signed int fm_env_destroy(void) +{ + signed int ret = 0; + + WCN_DBG(FM_NTC | MAIN, "%s\n", __func__); + + fm_link_release(); + + ret = fm_ops_unregister(&fm_low_ops); + if (ret) + return ret; + + WCN_DBG(FM_NTC | MAIN, "fm ops unregistered\n"); + + ret = fm_lock_put(fm_ops_lock); + if (!ret) + fm_ops_lock = NULL; + + ret = fm_lock_put(fm_read_lock); + if (!ret) + fm_read_lock = NULL; + + ret = fm_lock_put(fm_rds_cnt); + if (!ret) + fm_rds_cnt = NULL; + + ret = fm_spin_lock_put(fm_timer_lock); + if (!ret) + fm_timer_lock = NULL; + + ret = fm_lock_put(fm_rxtx_lock); + if (!ret) + fm_rxtx_lock = NULL; + + ret = fm_lock_put(fm_rtc_mutex); + if (!ret) + fm_rtc_mutex = NULL; + + ret = fm_timer_put(fm_timer_sys); + if (!ret) + fm_timer_sys = NULL; + +#if (FM_INVALID_CHAN_NOISE_REDUCING) + ret = fm_timer_put(fm_cqi_check_timer); + if (!ret) + fm_cqi_check_timer = NULL; +#endif + + ret = fm_lock_put(fm_wcn_ops.tx_lock); + if (!ret) + fm_wcn_ops.tx_lock = NULL; + ret = fm_lock_put(fm_wcn_ops.own_lock); + if (!ret) + fm_wcn_ops.own_lock = NULL; + + return ret; +} + +/* + * GetChannelSpace - get the spcace of gived channel + * @freq - value in 760~1080 or 7600~10800 + * + * Return 0, if 760~1080; return 1, if 7600 ~ 10800, else err code < 0 + */ +signed int fm_get_channel_space(signed int freq) +{ + if ((freq >= 640) && (freq <= 1080)) + return 0; + else if ((freq >= 6400) && (freq <= 10800)) + return 1; + else + return -1; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/core/fm_module.c b/drivers/misc/mediatek/connectivity/fmradio/core/fm_module.c new file mode 100644 index 00000000000000..f36f45a1d29dd0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/core/fm_module.c @@ -0,0 +1,1606 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/proc_fs.h> +#include <linux/cdev.h> +#include <linux/interrupt.h> +#include <linux/uaccess.h> +#include <linux/sched.h> +#include <linux/delay.h> /* udelay() */ +#include <linux/version.h> + +#include "fm_config.h" +#include "fm_main.h" +#include "fm_ioctl.h" + +#define FM_PROC_FILE "fm" + +unsigned int g_dbg_level = 0xfffffff5; /* Debug level of FM */ + +/* fm main data structure */ +static struct fm *g_fm; +/* proc file entry */ +static struct proc_dir_entry *g_fm_proc; + +/* char device interface */ +static signed int fm_cdev_setup(struct fm *fm); +static signed int fm_cdev_destroy(struct fm *fm); + +static long fm_ops_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +static long fm_ops_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +#endif +static loff_t fm_ops_lseek(struct file *filp, loff_t off, signed int whence); +static ssize_t fm_ops_read(struct file *filp, char *buf, size_t len, loff_t *off); +static signed int fm_ops_open(struct inode *inode, struct file *filp); +static signed int fm_ops_release(struct inode *inode, struct file *filp); +static signed int fm_ops_flush(struct file *filp, fl_owner_t Id); +static const struct file_operations fm_ops = { + .owner = THIS_MODULE, + .unlocked_ioctl = fm_ops_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = fm_ops_compat_ioctl, +#endif + .llseek = fm_ops_lseek, + .read = fm_ops_read, + .open = fm_ops_open, + .release = fm_ops_release, + .flush = fm_ops_flush, +}; + +/* static signed int fm_proc_read(char *page, char **start, off_t off, signed int count, + * signed int *eof, void *data); + */ +static ssize_t fm_proc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos); +static ssize_t fm_proc_write(struct file *file, const char *buffer, size_t count, loff_t *ppos); + +static const struct file_operations fm_proc_ops = { + .owner = THIS_MODULE, + .read = fm_proc_read, + .write = fm_proc_write, +}; + +#ifdef CONFIG_COMPAT +static long fm_ops_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret; + + WCN_DBG(FM_NTC | MAIN, "COMPAT %s---pid(%d)---cmd(0x%08x)---arg(0x%08x)\n", current->comm, + current->pid, cmd, (unsigned int) arg); + + if (!filp->f_op || !filp->f_op->unlocked_ioctl) + return -ENOTTY; + switch (cmd) { + case COMPAT_FM_IOCTL_GET_AUDIO_INFO: { + ret = filp->f_op->unlocked_ioctl(filp, FM_IOCTL_GET_AUDIO_INFO, arg); + break; + } + default: + ret = filp->f_op->unlocked_ioctl(filp, ((cmd & 0xFF) | (FM_IOCTL_POWERUP & 0xFFFFFF00)), arg); + break; + } + return ret; +} +#endif + +static long fm_ops_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + signed int ret = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) + struct fm_platform *plat = container_of(filp->f_path.dentry->d_inode->i_cdev, struct fm_platform, cdev); +#else + struct fm_platform *plat = container_of(filp->f_dentry->d_inode->i_cdev, struct fm_platform, cdev); +#endif + struct fm *fm = container_of(plat, struct fm, platform); + + WCN_DBG(FM_INF | MAIN, "%s---pid(%d)---cmd(0x%08x)---arg(0x%08x)\n", current->comm, + current->pid, cmd, (unsigned int) arg); + + if (fm_sys_state_get(fm) != FM_SUBSYS_RST_OFF) { + WCN_DBG(FM_ALT | MAIN, "FM subsys is resetting, retry later\n"); + ret = -FM_ESRST; + return ret; + } + + switch (cmd) { + case FM_IOCTL_POWERUP:{ + struct fm_tune_parm parm; + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_POWERUP:0\n"); + if (copy_from_user(&parm, (void *)arg, sizeof(struct fm_tune_parm))) { + ret = -EFAULT; + goto out; + } + + if (parm.freq <= 0 || parm.freq > FM_FREQ_MAX) { + struct fm_tune_parm_old *old_parm = + (struct fm_tune_parm_old *)&parm; + + if (old_parm->freq > 0 && old_parm->freq <= FM_FREQ_MAX) { + WCN_DBG(FM_WAR | MAIN, + "convert to old version fm_tune_parm [%u]->[%u]\n", + parm.freq, old_parm->freq); + parm.freq = old_parm->freq; + parm.deemphasis = 0; + } + } + + if (parm.deemphasis == 1) + fm_config.rx_cfg.deemphasis = 1; + else + fm_config.rx_cfg.deemphasis = 0; + + ret = fm_powerup(fm, &parm); + if (ret < 0) { + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_POWERUP:fail in fm_powerup, return\n"); + goto out; + } + ret = fm_tune(fm, &parm); + if (ret < 0) { + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_POWERUP:fail in fm_tune, return\n"); + goto out; + } + + if (copy_to_user((void *)arg, &parm, sizeof(struct fm_tune_parm))) { + ret = -EFAULT; + goto out; + } + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_POWERUP:1\n"); + + break; + } + + case FM_IOCTL_POWERDOWN:{ + int powerdwn_type = 0; + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_POWERDOWN:0\n"); + + if (copy_from_user(&powerdwn_type, (void *)arg, sizeof(int))) { + ret = -EFAULT; + goto out; + } + + ret = fm_powerdown(fm, powerdwn_type); /* 0: RX 1: TX */ + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_POWERDOWN:1\n"); + break; + } + + case FM_IOCTL_TUNE:{ + struct fm_tune_parm parm; + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_TUNE:0\n"); + + if (copy_from_user(&parm, (void *)arg, sizeof(struct fm_tune_parm))) { + ret = -EFAULT; + goto out; + } + + if (parm.freq <= 0 || parm.freq > FM_FREQ_MAX) { + struct fm_tune_parm_old *old_parm = + (struct fm_tune_parm_old *)&parm; + + if (old_parm->freq > 0 && old_parm->freq <= FM_FREQ_MAX) { + WCN_DBG(FM_WAR | MAIN, + "convert to old version fm_tune_parm [%u]->[%u]\n", + parm.freq, old_parm->freq); + parm.freq = old_parm->freq; + parm.deemphasis = 0; + } + } + + ret = fm_tune(fm, &parm); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &parm, sizeof(struct fm_tune_parm))) { + ret = -EFAULT; + goto out; + } + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_TUNE:1\n"); + break; + } + + case FM_IOCTL_SOFT_MUTE_TUNE: + { + struct fm_softmute_tune_t parm; + + fm_cqi_log(); /* cqi log tool */ + if (copy_from_user(&parm, (void *)arg, sizeof(struct fm_softmute_tune_t))) { + ret = -EFAULT; + goto out; + } + + ret = fm_soft_mute_tune(fm, &parm); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &parm, sizeof(struct fm_softmute_tune_t))) { + ret = -EFAULT; + goto out; + } + break; + } + case FM_IOCTL_PRE_SEARCH: + { + ret = fm_pre_search(fm); + break; + } + case FM_IOCTL_RESTORE_SEARCH: + { + ret = fm_restore_search(fm); + break; + } + case FM_IOCTL_CQI_GET:{ + struct fm_cqi_req cqi_req; + signed char *buf = NULL; + signed int tmp; + unsigned int cpy_size = 0; + + WCN_DBG(FM_INF | MAIN, "FM_IOCTL_CQI_GET\n"); + + if (copy_from_user(&cqi_req, (void *)arg, sizeof(struct fm_cqi_req))) { + WCN_DBG(FM_ALT | MAIN, "copy_from_user failed\n"); + ret = -EFAULT; + goto out; + } + + if ((cqi_req.ch_num * sizeof(struct fm_cqi) > cqi_req.buf_size) + || !cqi_req.cqi_buf) { + ret = -FM_EPARA; + goto out; + } + + tmp = cqi_req.ch_num / 16 + ((cqi_req.ch_num % 16) ? 1 : 0); + tmp = tmp * 16 * sizeof(struct fm_cqi); + buf = fm_zalloc(tmp); + + if (!buf) { + ret = -FM_ENOMEM; + goto out; + } + + ret = fm_cqi_get(fm, cqi_req.ch_num, buf, tmp); + + if (ret) { + fm_free(buf); + WCN_DBG(FM_ALT | MAIN, "get cqi failed\n"); + goto out; + } + + cpy_size = cqi_req.ch_num * sizeof(struct fm_cqi); + if (cpy_size > tmp) + cpy_size = tmp; + if (copy_to_user((void *)cqi_req.cqi_buf, buf, cpy_size)) { + fm_free(buf); + ret = -EFAULT; + goto out; + } + + fm_free(buf); + break; + } + + case FM_IOCTL_GET_HW_INFO:{ + struct fm_hw_info info; + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_GET_HW_INFO\n"); + + ret = fm_get_hw_info(fm, &info); + + if (ret) { + WCN_DBG(FM_ALT | MAIN, "get hw info failed\n"); + goto out; + } + + if (copy_to_user((void *)arg, &info, sizeof(struct fm_hw_info))) { + ret = -EFAULT; + goto out; + } + + break; + } + + case FM_IOCTL_GET_I2S_INFO:{ + struct fm_i2s_info i2sinfo; + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_GET_I2S_INFO\n"); + + ret = fm_get_i2s_info(fm, &i2sinfo); + + if (ret) { + WCN_DBG(FM_ALT | MAIN, "get i2s info failed\n"); + goto out; + } + + if (copy_to_user((void *)arg, &i2sinfo, sizeof(struct fm_i2s_info))) { + ret = -EFAULT; + goto out; + } + + break; + } + + case FM_IOCTL_SETVOL:{ + unsigned int vol; + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_SETVOL start\n"); + if (copy_from_user(&vol, (void *)arg, sizeof(unsigned int))) { + WCN_DBG(FM_ALT | MAIN, "copy_from_user failed\n"); + ret = -EFAULT; + goto out; + } + + ret = fm_setvol(fm, vol); + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_SETVOL end:%d\n", vol); + break; + } + case FM_IOCTL_GETVOL:{ + unsigned int vol; + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_GETVOL start\n"); + ret = fm_getvol(fm, &vol); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &vol, sizeof(unsigned int))) { + ret = -EFAULT; + goto out; + } + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_GETVOL end=%d\n", vol); + break; + } + + case FM_IOCTL_MUTE:{ + unsigned int bmute; + + if (copy_from_user(&bmute, (void *)arg, sizeof(unsigned int))) { + ret = -EFAULT; + goto out; + } + + ret = fm_mute(fm, bmute); + WCN_DBG(FM_INF | MAIN, "FM_IOCTL_MUTE end-%d\n", bmute); + break; + } + + case FM_IOCTL_GETRSSI:{ + signed int rssi = 0; + + ret = fm_getrssi(fm, &rssi); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &rssi, sizeof(signed int))) { + ret = -EFAULT; + goto out; + } + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_GETRSSI:%d\n", rssi); + break; + } + + case FM_IOCTL_RW_REG:{ + struct fm_ctl_parm parm_ctl; + + WCN_DBG(FM_INF | MAIN, "FM_IOCTL_RW_REG\n"); + if (fm->chipon == false || fm_pwr_state_get(fm) == FM_PWR_OFF) { + WCN_DBG(FM_ERR | MAIN, "ERROR, FM chip is OFF\n"); + ret = -EFAULT; + goto out; + } + + if (copy_from_user(&parm_ctl, (void *)arg, sizeof(struct fm_ctl_parm))) { + WCN_DBG(FM_ALT | MAIN, "copy from user error\n"); + ret = -EFAULT; + goto out; + } + + if (parm_ctl.rw_flag == 0) + ret = fm_write(fm, parm_ctl.addr, parm_ctl.val); + else + ret = fm_read(fm, parm_ctl.addr, &parm_ctl.val); + + if (ret < 0) + goto out; + + if ((parm_ctl.rw_flag == 0x01) && (!ret)) { + if (copy_to_user((void *)arg, &parm_ctl, sizeof(struct fm_ctl_parm))) { + ret = -EFAULT; + goto out; + } + } + + break; + } + case FM_IOCTL_TOP_RDWR: + { + struct fm_top_rw_parm parm_ctl; + + WCN_DBG(FM_INF | MAIN, "FM_IOCTL_TOP_RDWR\n"); + +#ifdef CONFIG_MTK_USER_BUILD + WCN_DBG(FM_ERR | MAIN, "Not support FM_IOCTL_TOP_RDWR\n"); + ret = -EFAULT; + goto out; +#endif + + if (g_dbg_level != 0xfffffff7) { + WCN_DBG(FM_ERR | MAIN, "Not support FM_IOCTL_TOP_RDWR\n"); + ret = -EFAULT; + goto out; + } + + if (fm->chipon == false || fm_pwr_state_get(fm) == FM_PWR_OFF) { + WCN_DBG(FM_ERR | MAIN, "ERROR, FM chip is OFF\n"); + ret = -EFAULT; + goto out; + } + + if (copy_from_user(&parm_ctl, (void *)arg, sizeof(struct fm_top_rw_parm))) { + WCN_DBG(FM_ALT | MAIN, "copy from user error\n"); + ret = -EFAULT; + goto out; + } + + if (parm_ctl.rw_flag == 0) + ret = fm_top_write(fm, parm_ctl.addr, parm_ctl.val); + else + ret = fm_top_read(fm, parm_ctl.addr, &parm_ctl.val); + + if (ret < 0) + goto out; + + if ((parm_ctl.rw_flag == 0x01) && (!ret)) { + if (copy_to_user((void *)arg, &parm_ctl, sizeof(struct fm_top_rw_parm))) { + ret = -EFAULT; + goto out; + } + } + + break; + } + case FM_IOCTL_HOST_RDWR: + { + struct fm_host_rw_parm parm_ctl; + + WCN_DBG(FM_INF | MAIN, "FM_IOCTL_HOST_RDWR\n"); + +#ifdef CONFIG_MTK_USER_BUILD + WCN_DBG(FM_ERR | MAIN, "Not support FM_IOCTL_HOST_RDWR\n"); + ret = -EFAULT; + goto out; +#endif + + if (g_dbg_level != 0xfffffff7) { + WCN_DBG(FM_ERR | MAIN, "Not support FM_IOCTL_HOST_RDWR\n"); + ret = -EFAULT; + goto out; + } + + if (fm->chipon == false || fm_pwr_state_get(fm) == FM_PWR_OFF) { + WCN_DBG(FM_ERR | MAIN, "ERROR, FM chip is OFF\n"); + ret = -EFAULT; + goto out; + } + + if (copy_from_user(&parm_ctl, (void *)arg, sizeof(struct fm_host_rw_parm))) { + WCN_DBG(FM_ALT | MAIN, "copy from user error\n"); + ret = -EFAULT; + goto out; + } + + /* 4 bytes alignment and illegal address */ + if (parm_ctl.addr % 4 != 0 || parm_ctl.addr >= 0x90000000) { + ret = -FM_EPARA; + goto out; + } + WCN_DBG(FM_NTC | MAIN, "rw? (%d), addr: %x\n", parm_ctl.rw_flag, parm_ctl.addr); + if (parm_ctl.rw_flag == 0) + ret = fm_host_write(fm, parm_ctl.addr, parm_ctl.val); + else + ret = fm_host_read(fm, parm_ctl.addr, &parm_ctl.val); + + if (ret < 0) + goto out; + + if ((parm_ctl.rw_flag == 0x01) && (!ret)) { + if (copy_to_user((void *)arg, &parm_ctl, sizeof(struct fm_host_rw_parm))) { + ret = -EFAULT; + goto out; + } + } + + break; + } + case FM_IOCTL_PMIC_RDWR: + { + struct fm_pmic_rw_parm parm_ctl; + + WCN_DBG(FM_INF | MAIN, "FM_IOCTL_PMIC_RDWR\n"); + if (fm->chipon == false || fm_pwr_state_get(fm) == FM_PWR_OFF) { + WCN_DBG(FM_ERR | MAIN, "ERROR, FM chip is OFF\n"); + ret = -EFAULT; + goto out; + } + + if (copy_from_user(&parm_ctl, (void *)arg, sizeof(struct fm_pmic_rw_parm))) { + WCN_DBG(FM_ALT | MAIN, "copy from user error\n"); + ret = -EFAULT; + goto out; + } + + if (parm_ctl.rw_flag == 0) + ret = fm_pmic_write(fm, parm_ctl.addr, parm_ctl.val); + else + ret = fm_pmic_read(fm, parm_ctl.addr, &parm_ctl.val); + + if (ret < 0) + goto out; + + if ((parm_ctl.rw_flag == 0x01) && (!ret)) { + if (copy_to_user((void *)arg, &parm_ctl, sizeof(struct fm_pmic_rw_parm))) { + ret = -EFAULT; + goto out; + } + } + + break; + } + case FM_IOCTL_GETCHIPID:{ + unsigned short chipid = 0; + + ret = fm_chipid_get(fm, &chipid); + WCN_DBG(FM_INF | MAIN, "FM_IOCTL_GETCHIPID:%04x\n", chipid); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &chipid, sizeof(unsigned short))) { + ret = -EFAULT; + goto out; + } + break; + } + + case FM_IOCTL_GETMONOSTERO:{ + unsigned short usStereoMono = 0; + + ret = fm_monostereo_get(fm, &usStereoMono); + WCN_DBG(FM_INF | MAIN, "FM_IOCTL_GETMONOSTERO:%04x\n", usStereoMono); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &usStereoMono, sizeof(unsigned short))) { + ret = -EFAULT; + goto out; + } + break; + } + + case FM_IOCTL_SETMONOSTERO:{ + signed int monostero; + + WCN_DBG(FM_INF | MAIN, "FM_IOCTL_SETMONOSTERO\n"); + if (copy_from_user(&monostero, (void *)arg, sizeof(signed int))) { + WCN_DBG(FM_ALT | MAIN, "copy from user error\n"); + ret = -EFAULT; + goto out; + } + ret = fm_monostereo_set(fm, monostero); + break; + } + + case FM_IOCTL_GETCURPAMD:{ + unsigned short PamdLevl = 0; + + ret = fm_pamd_get(fm, &PamdLevl); + WCN_DBG(FM_INF | MAIN, "FM_IOCTL_GETCURPAMD:%d\n", PamdLevl); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &PamdLevl, sizeof(unsigned short))) + ret = -EFAULT; + goto out; + + break; + } + + case FM_IOCTL_GETCAPARRAY:{ + signed int ca = 0; + + ret = fm_caparray_get(fm, &ca); + WCN_DBG(FM_INF | MAIN, "FM_IOCTL_GETCAPARRAY:%d\n", ca); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &ca, sizeof(signed int))) { + ret = -EFAULT; + goto out; + } + break; + } + + case FM_IOCTL_EM_TEST:{ + struct fm_em_parm parm_em; + + WCN_DBG(FM_DBG | MAIN, "FM_IOCTL_EM_TEST\n"); + + if (copy_from_user(&parm_em, (void *)arg, sizeof(struct fm_em_parm))) { + ret = -EFAULT; + goto out; + } + ret = fm_em_test(fm, parm_em.group_idx, parm_em.item_idx, parm_em.item_value); + break; + } + + case FM_IOCTL_RDS_SUPPORT:{ + signed int support = FM_RDS_ENABLE; + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_RDS_SUPPORT\n"); + + if (copy_to_user((void *)arg, &support, sizeof(signed int))) { + ret = -EFAULT; + goto out; + } + break; + } + + case FM_IOCTL_IS_FM_POWERED_UP:{ + unsigned int powerup; + + WCN_DBG(FM_DBG | MAIN, "FM_IOCTL_IS_FM_POWERED_UP"); + + if (fm->chipon && fm_pwr_state_get(fm)) + powerup = 1; + else + powerup = 0; + + if (copy_to_user((void *)arg, &powerup, sizeof(unsigned int))) { + ret = -EFAULT; + goto out; + } + break; + } + + case FM_IOCTL_FM_SET_STATUS:{ + struct fm_status_t fm_stat; + + WCN_DBG(FM_DBG | MAIN, "FM_IOCTL_FM_SET_STATUS"); + + if (copy_from_user(&fm_stat, (void *)arg, sizeof(struct fm_status_t))) { + ret = -EFAULT; + goto out; + } + + fm_set_stat(fm, fm_stat.which, fm_stat.stat); + + break; + } + + case FM_IOCTL_FM_GET_STATUS:{ + struct fm_status_t fm_stat; + + WCN_DBG(FM_DBG | MAIN, "FM_IOCTL_FM_GET_STATUS"); + + if (copy_from_user(&fm_stat, (void *)arg, sizeof(struct fm_status_t))) { + ret = -EFAULT; + goto out; + } + + fm_get_stat(fm, fm_stat.which, &fm_stat.stat); + + if (copy_to_user((void *)arg, &fm_stat, sizeof(struct fm_status_t))) { + ret = -EFAULT; + goto out; + } + + break; + } + + case FM_IOCTL_RDS_ONOFF:{ + unsigned short rdson_off = 0; + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_RDS_ONOFF start\n"); + + if (copy_from_user(&rdson_off, (void *)arg, sizeof(unsigned short))) { + ret = -EFAULT; + goto out; + } + ret = fm_rds_onoff(fm, rdson_off); + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_RDS_ONOFF end:%d\n", rdson_off); + break; + } + + case FM_IOCTL_GETGOODBCNT:{ + unsigned short uGBLCNT = 0; + + ret = fm_rds_good_bc_get(fm, &uGBLCNT); + WCN_DBG(FM_DBG | MAIN, "FM_IOCTL_GETGOODBCNT:%d\n", uGBLCNT); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &uGBLCNT, sizeof(unsigned short))) { + ret = -EFAULT; + goto out; + } + break; + } + + case FM_IOCTL_GETBADBNT:{ + unsigned short uBadBLCNT = 0; + + ret = fm_rds_bad_bc_get(fm, &uBadBLCNT); + WCN_DBG(FM_DBG | MAIN, "FM_IOCTL_GETBADBNT:%d\n", uBadBLCNT); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &uBadBLCNT, sizeof(unsigned short))) { + ret = -EFAULT; + goto out; + } + break; + } + + case FM_IOCTL_GETBLERRATIO:{ + unsigned short uBlerRatio = 0; + + ret = fm_rds_bler_ratio_get(fm, &uBlerRatio); + WCN_DBG(FM_DBG | MAIN, "FM_IOCTL_GETBLERRATIO:%d\n", uBlerRatio); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &uBlerRatio, sizeof(unsigned short))) { + ret = -EFAULT; + goto out; + } + break; + } + + case FM_IOCTL_ANA_SWITCH:{ + signed int antenna = -1; + + WCN_DBG(FM_DBG | MAIN, "FM_IOCTL_ANA_SWITCH\n"); + + if (copy_from_user(&antenna, (void *)arg, sizeof(signed int))) { + WCN_DBG(FM_ALT | MAIN, "copy from user error\n"); + ret = -EFAULT; + goto out; + } + + ret = fm_ana_switch(fm, antenna); + break; + } + + case FM_IOCTL_RDS_GROUPCNT:{ + struct rds_group_cnt_req_t gc_req; + + WCN_DBG(FM_DBG | MAIN, "......FM_IOCTL_RDS_GROUPCNT......\n"); + + if (copy_from_user(&gc_req, (void *)arg, sizeof(struct rds_group_cnt_req_t))) { + WCN_DBG(FM_ALT | MAIN, "copy_from_user error\n"); + ret = -EFAULT; + goto out; + } + /* handle group counter request */ + switch (gc_req.op) { + case RDS_GROUP_CNT_READ: + ret = fm_rds_group_cnt_get(fm, &gc_req.gc); + break; + case RDS_GROUP_CNT_WRITE: + break; + case RDS_GROUP_CNT_RESET: + ret = fm_rds_group_cnt_reset(fm); + break; + default: + break; + } + + if (copy_to_user((void *)arg, &gc_req, sizeof(struct rds_group_cnt_req_t))) { + WCN_DBG(FM_ALT | MAIN, "copy_to_user error\n"); + ret = -EFAULT; + goto out; + } + + break; + } + + case FM_IOCTL_RDS_GET_LOG:{ + struct rds_raw_t rds_log; + signed int len = 0; + + memset(rds_log.data, 0, sizeof(rds_log.data)); + WCN_DBG(FM_DBG | MAIN, "......FM_IOCTL_RDS_GET_LOG......\n"); + /* fetch a record form RDS log buffer */ + ret = fm_rds_log_get(fm, (struct rds_rx_t *)&(rds_log.data), &len); + rds_log.dirty = true; + rds_log.len = (len < sizeof(rds_log.data)) ? len : sizeof(rds_log.data); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &rds_log, rds_log.len + 2 * sizeof(signed int))) { + WCN_DBG(FM_ALT | MAIN, "copy_to_user error\n"); + ret = -EFAULT; + goto out; + } + + break; + } + + case FM_IOCTL_RDS_BC_RST:{ + WCN_DBG(FM_DBG | MAIN, "FM_IOCTL_RDS_BC_RST\n"); + ret = fm_rds_block_cnt_reset(fm); + break; + } + + case FM_IOCTL_I2S_SETTING:{ + struct fm_i2s_setting i2s_cfg; + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_I2S_SETTING\n"); + + if (copy_from_user(&i2s_cfg, (void *)arg, sizeof(struct fm_i2s_setting))) { + WCN_DBG(FM_ALT | MAIN, "i2s set, copy_from_user err\n"); + ret = -EFAULT; + goto out; + } + + ret = fm_i2s_set(fm, i2s_cfg.onoff, i2s_cfg.mode, i2s_cfg.sample); + + if (ret) { + WCN_DBG(FM_ALT | MAIN, "Set i2s err\n"); + goto out; + } + + break; + } + + case FM_IOCTL_IS_DESE_CHAN:{ + signed int tmp; + + WCN_DBG(FM_INF | MAIN, "FM_IOCTL_IS_DESE_CHAN\n"); + + if (copy_from_user(&tmp, (void *)arg, sizeof(signed int))) { + WCN_DBG(FM_ALT | MAIN, "is dese chan, copy_from_user err\n"); + ret = -EFAULT; + goto out; + } + + tmp = fm_is_dese_chan(fm, (unsigned short) tmp); + + if (copy_to_user((void *)arg, &tmp, sizeof(signed int))) { + WCN_DBG(FM_ALT | MAIN, "is dese chan, copy_to_user err\n"); + ret = -EFAULT; + goto out; + } + + break; + } + case FM_IOCTL_DESENSE_CHECK: + { + struct fm_desense_check_t tmp; + + WCN_DBG(FM_INF | MAIN, "FM_IOCTL_DESENSE_CHECK\n"); + + if (copy_from_user(&tmp, (void *)arg, sizeof(struct fm_desense_check_t))) { + WCN_DBG(FM_ALT | MAIN, "desene check, copy_from_user err\n"); + ret = -EFAULT; + goto out; + } + ret = fm_desense_check(fm, (unsigned short) tmp.freq, tmp.rssi); + + /*if (copy_to_user((void*)arg, &tmp, sizeof(struct fm_desense_check_t))) { + * WCN_DBG(FM_ALT | MAIN, "desene check, copy_to_user err\n"); + * ret = -EFAULT; + * goto out; + * } + */ + + break; + } + case FM_IOCTL_SCAN_GETRSSI: + { + WCN_DBG(FM_ALT | MAIN, "FM_IOCTL_SCAN_GETRSSI:not support\n"); + break; + } + + case FM_IOCTL_DUMP_REG: + { + WCN_DBG(FM_NTC | MAIN, "......FM_IOCTL_DUMP_REG......\n"); + if (g_dbg_level != 0xfffffff7) { + WCN_DBG(FM_ERR | MAIN, "Not support FM_IOCTL_HOST_RDWR\n"); + ret = -EFAULT; + goto out; + } + if (fm->chipon == false || fm_pwr_state_get(fm) == FM_PWR_OFF) { + WCN_DBG(FM_ERR | MAIN, "ERROR, FM chip is OFF\n"); + ret = -EFAULT; + goto out; + } + ret = fm_dump_reg(); + if (ret) + WCN_DBG(FM_ALT | MAIN, "fm_dump_reg err\n"); + break; + } + case FM_IOCTL_GPS_RTC_DRIFT:{ + struct fm_gps_rtc_info rtc_info; + + WCN_DBG(FM_NTC | MAIN, "......FM_IOCTL_GPS_RTC_DRIFT......\n"); + + if (false == fm->chipon) { + WCN_DBG(FM_ERR | MAIN, "ERROR, FM chip is OFF\n"); + ret = -EFAULT; + goto out; + } + if (copy_from_user(&rtc_info, (void *)arg, sizeof(struct fm_gps_rtc_info))) { + WCN_DBG(FM_ERR | MAIN, "copy_from_user error\n"); + ret = -EFAULT; + goto out; + } + + ret = fm_get_gps_rtc_info(&rtc_info); + if (ret) { + WCN_DBG(FM_ERR | MAIN, "fm_get_gps_rtc_info error\n"); + goto out; + } + break; + } + case FM_IOCTL_OVER_BT_ENABLE: + { + signed int fm_via_bt = -1; + + WCN_DBG(FM_NTC | MAIN, "......FM_IOCTL_OVER_BT_ENABLE......\n"); + + if (copy_from_user(&fm_via_bt, (void *)arg, sizeof(int32_t))) { + WCN_DBG(FM_ERR | MAIN, "copy_from_user error\n"); + ret = -EFAULT; + goto out; + } + + ret = fm_over_bt(fm, fm_via_bt); + if (ret) + WCN_DBG(FM_ERR | MAIN, "fm_over_bt err\n"); + break; + } + + case FM_IOCTL_SET_SEARCH_THRESHOLD: + { + struct fm_search_threshold_t parm; + + WCN_DBG(FM_NTC | MAIN, "......FM_IOCTL_SET_SEARCH_THRESHOLD......\n"); + + if (copy_from_user(&parm, (void *)arg, sizeof(struct fm_search_threshold_t))) { + WCN_DBG(FM_ALT | MAIN, "copy_from_user error\n"); + ret = -EFAULT; + goto out; + } + ret = fm_set_search_th(fm, parm); + if (ret < 0) + WCN_DBG(FM_ERR | MAIN, "FM_IOCTL_SET_SEARCH_THRESHOLD not supported\n"); + break; + } + case FM_IOCTL_GET_AUDIO_INFO: + { + struct fm_audio_info_t aud_data; + + ret = fm_get_aud_info(&aud_data); + if (ret) + WCN_DBG(FM_ERR | MAIN, "fm_get_aud_info err\n"); + + if (copy_to_user((void *)arg, &aud_data, sizeof(struct fm_audio_info_t))) { + WCN_DBG(FM_ERR | MAIN, "copy_to_user error\n"); + ret = -EFAULT; + goto out; + } + + WCN_DBG(FM_INF | MAIN, "fm_get_aud_info ret=%d\n", ret); + break; + } + /***************************FM Tx function************************************/ + case FM_IOCTL_TX_SUPPORT: + { + signed int tx_support = -1; + + WCN_DBG(FM_NTC | MAIN, "......FM_IOCTL_TX_SUPPORT......\n"); + + ret = fm_tx_support(fm, &tx_support); + if (ret) + WCN_DBG(FM_ERR | MAIN, "fm_tx_support err\n"); + + if (copy_to_user((void *)arg, &tx_support, sizeof(signed int))) { + WCN_DBG(FM_ERR | MAIN, "copy_to_user error\n"); + ret = -EFAULT; + goto out; + } + break; + } + case FM_IOCTL_POWERUP_TX: + { + struct fm_tune_parm parm; + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_POWERUP_TX:0\n"); + if (copy_from_user(&parm, (void *)arg, sizeof(struct fm_tune_parm))) { + ret = -EFAULT; + goto out; + } + + ret = fm_powerup_tx(fm, &parm); + if (ret < 0) + goto out; + + ret = fm_tune_tx(fm, &parm); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &parm, sizeof(struct fm_tune_parm))) { + ret = -EFAULT; + goto out; + } + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_POWERUP_TX:1\n"); + break; + } + + case FM_IOCTL_TUNE_TX: + { + struct fm_tune_parm parm; + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_TUNE_TX:0\n"); + + if (copy_from_user(&parm, (void *)arg, sizeof(struct fm_tune_parm))) { + ret = -EFAULT; + goto out; + } + + ret = fm_tune_tx(fm, &parm); + if (ret < 0) + goto out; + + if (copy_to_user((void *)arg, &parm, sizeof(struct fm_tune_parm))) { + ret = -EFAULT; + goto out; + } + + WCN_DBG(FM_NTC | MAIN, "FM_IOCTL_TUNE_TX:1\n"); + break; + } + case FM_IOCTL_RDSTX_SUPPORT: + { + signed int rds_tx_support = -1; + + WCN_DBG(FM_NTC | MAIN, "......FM_IOCTL_RDSTX_SUPPORT......\n"); + + ret = fm_rdstx_support(fm, &rds_tx_support); + if (ret) + WCN_DBG(FM_ERR | MAIN, "fm_rdstx_support err\n"); + + if (copy_to_user((void *)arg, &rds_tx_support, sizeof(signed int))) { + WCN_DBG(FM_ERR | MAIN, "copy_to_user error\n"); + ret = -EFAULT; + goto out; + } + break; + } + + case FM_IOCTL_RDSTX_ENABLE: + { + signed int onoff = -1; + + WCN_DBG(FM_NTC | MAIN, "......FM_IOCTL_RDSTX_ENABLE......\n"); + + if (copy_from_user(&onoff, (void *)arg, sizeof(signed int))) { + WCN_DBG(FM_ALT | MAIN, "FM_IOCTL_RDSTX_ENABLE, copy_from_user err\n"); + ret = -EFAULT; + goto out; + } + + ret = fm_rdstx_enable(fm, onoff); + if (ret) + WCN_DBG(FM_ERR | MAIN, "fm_rdstx_enable err\n"); + + break; + } + + case FM_IOCTL_RDS_TX: + { + struct fm_rds_tx_parm parm; + + WCN_DBG(FM_NTC | MAIN, "......FM_IOCTL_RDS_TX......\n"); + + if (copy_from_user(&parm, (void *)arg, sizeof(struct fm_rds_tx_parm))) { + WCN_DBG(FM_ALT | MAIN, "RDS Tx, copy_from_user err\n"); + ret = -EFAULT; + goto out; + } + + ret = fm_rds_tx(fm, &parm); + if (ret) + WCN_DBG(FM_ALT | MAIN, "fm_rds_tx err\n"); + + if (copy_to_user((void *)arg, &parm, sizeof(struct fm_rds_tx_parm))) { + WCN_DBG(FM_ALT | MAIN, "RDS Tx, copy_to_user err\n"); + ret = -EFAULT; + goto out; + } + break; + } + + case FM_IOCTL_TX_SCAN: + { + struct fm_tx_scan_parm parm; + + WCN_DBG(FM_NTC | MAIN, "......FM_IOCTL_TX_SCAN......\n"); + + if (copy_from_user(&parm, (void *)arg, sizeof(struct fm_tx_scan_parm))) { + WCN_DBG(FM_ALT | MAIN, "copy_from_user error\n"); + ret = -EFAULT; + goto out; + } + ret = fm_tx_scan(fm, &parm); + if (ret < 0) + WCN_DBG(FM_ERR | MAIN, "FM_IOCTL_TX_SCAN failed\n"); + + if (copy_to_user((void *)arg, &parm, sizeof(struct fm_tx_scan_parm))) { + WCN_DBG(FM_ALT | MAIN, "copy_to_user error\n"); + ret = -EFAULT; + goto out; + } + break; + } + + default: + ret = -EPERM; + } + +out: + if (ret == -FM_EFW) { + if (fm_sys_state_get(fm) == FM_SUBSYS_RST_OFF) { + fm->wholechiprst = false; + /* subsystem reset */ + WCN_DBG(FM_NTC | MAIN, "fm_subsys_reset START\n"); + fm_subsys_reset(fm); + WCN_DBG(FM_NTC | MAIN, "fm_subsys_reset END\n"); + } + } + + return ret; +} + +static loff_t fm_ops_lseek(struct file *filp, loff_t off, signed int whence) +{ + struct fm *fm = filp->private_data; + + if (whence == SEEK_END) + fm_hwscan_stop(fm); + else if (whence == SEEK_SET) + FM_EVENT_SEND(fm->rds_event, FM_RDS_DATA_READY); + + return off; +} + +static ssize_t fm_ops_read(struct file *filp, char *buf, size_t len, loff_t *off) +{ + struct fm *fm = filp->private_data; + signed int copy_len = 0; + + if (!fm) { + WCN_DBG(FM_ALT | MAIN, "fm_read invalid fm pointer\n"); + return 0; + } + + WCN_DBG(FM_DBG | MAIN, "rds buf len=%zu\n", len); + WCN_DBG(FM_DBG | MAIN, "sizeof(struct rds_t)=%zu\n", sizeof(struct rds_t)); + + if (!buf || len < sizeof(struct rds_t)) { + WCN_DBG(FM_NTC | MAIN, "fm_read invliad buf\n"); + return 0; + } + /* return if FM is resetting */ + if (fm_sys_state_get(fm) != FM_SUBSYS_RST_OFF) { + WCN_DBG(FM_ALT | MAIN, "fm subsys underring reset\n"); + return 0; + } + + copy_len = sizeof(struct rds_t); + + return fm_rds_read(fm, buf, copy_len); +} + +atomic_t g_counter = ATOMIC_INIT(0); +static signed int fm_ops_open(struct inode *inode, struct file *filp) +{ + signed int ret = 0; + struct fm_platform *plat = container_of(inode->i_cdev, struct fm_platform, cdev); + struct fm *fm = container_of(plat, struct fm, platform); + + if (fm_sys_state_get(fm) != FM_SUBSYS_RST_OFF) { + WCN_DBG(FM_ALT | MAIN, "FM subsys is resetting, retry later\n"); + ret = -FM_ESRST; + return ret; + } + + ret = fm_open(fm); + filp->private_data = fm; + atomic_inc(&g_counter); + + WCN_DBG(FM_NTC | MAIN, "fm_ops_open:%d [%d]\n", current->pid, atomic_read(&g_counter)); + return ret; +} + +static signed int fm_ops_release(struct inode *inode, struct file *filp) +{ +/* signed int ret = 0; */ +/* struct fm_platform *plat = container_of(inode->i_cdev, struct fm_platform, cdev); */ +/* struct fm *fm = container_of(plat, struct fm, platform); */ + struct fm *fm = filp->private_data; + + WCN_DBG(FM_NTC | MAIN, "fm_ops_release:%d [%d]\n", current->pid, atomic_read(&g_counter)); + + if (atomic_dec_and_test(&g_counter)) { + WCN_DBG(FM_ALT | MAIN, "FM power down... [%d]\n", atomic_read(&g_counter)); + if (-FM_ELOCK == fm_powerdown(fm, 0)) { + WCN_DBG(FM_ALT | MAIN, "FM power down fail. Do it later.\n"); + fm->timer_wkthd->add_work(fm->timer_wkthd, fm->pwroff_wk); + } + } + + filp->private_data = NULL; + return 0; +} + +static signed int fm_ops_flush(struct file *filp, fl_owner_t Id) +{ + signed int ret = 0; + struct fm *fm = filp->private_data; + + WCN_DBG(FM_NTC | MAIN, "fm_ops_flush:%d\n", current->pid); + fm_close(fm); + filp->private_data = fm; + return ret; +} + +static ssize_t fm_proc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + struct fm *fm = g_fm; + ssize_t length = 0; + char tmpbuf[3]; + unsigned long pos = *ppos; + + WCN_DBG(FM_NTC | MAIN, "Enter fm_proc_read.\n"); + /* WCN_DBG(FM_NTC | MAIN, "count = %d\n", count); */ + /* WCN_DBG(FM_NTC | MAIN, "ppos = %d\n", pos); */ + + if (pos != 0) + return 0; + + if (!fm) { + WCN_DBG(FM_ALT | MAIN, "para err\n"); + return 0; + } + + if (fm->chipon && (fm_pwr_state_get(fm) == FM_PWR_RX_ON)) { + length = snprintf(tmpbuf, sizeof(tmpbuf), "1\n"); + WCN_DBG(FM_NTC | MAIN, " FM_PWR_RX_ON\n"); + } else if (fm->chipon && (fm_pwr_state_get(fm) == FM_PWR_TX_ON)) { + length = snprintf(tmpbuf, sizeof(tmpbuf), "2\n"); + WCN_DBG(FM_NTC | MAIN, " FM_PWR_TX_ON\n"); + } else { + length = snprintf(tmpbuf, sizeof(tmpbuf), "0\n"); + WCN_DBG(FM_NTC | MAIN, " FM POWER OFF\n"); + } + + if (copy_to_user(buf, tmpbuf, length)) { + WCN_DBG(FM_NTC | MAIN, " Read FM status fail!\n"); + return 0; + } + + pos += length; + *ppos = pos; + WCN_DBG(FM_NTC | MAIN, "Leave fm_proc_read. length = %zu\n", length); + + return length; +} + +static ssize_t fm_proc_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct fm *fm = g_fm; + signed char tmp_buf[50] = { 0 }; + unsigned int copysize; + + WCN_DBG(FM_NTC | MAIN, "fm_proc_write:0 count = %zu\n", count); + if (count <= 0 || buffer == NULL) { + WCN_DBG(FM_ERR | MAIN, "failed parameter not accept\n"); + return -EFAULT; + } + + copysize = (count < (sizeof(tmp_buf) - 1)) ? count : (sizeof(tmp_buf) - 1); + + memset(tmp_buf, 0, sizeof(tmp_buf)); + if (copy_from_user(tmp_buf, buffer, copysize)) { + WCN_DBG(FM_ERR | MAIN, "failed copy_from_user\n"); + return -EFAULT; + } + + if (strncmp(tmp_buf, "subsys reset", strlen("subsys reset")) == 0) { + fm_subsys_reset(fm); + return count; + } + + if (!fm->chipon || (fm_pwr_state_get(fm) != FM_PWR_RX_ON)) { + WCN_DBG(FM_ERR | MAIN, "FM is off.\n"); + return -EFAULT; + } + + if (kstrtouint(tmp_buf, 0, &g_dbg_level)) { + WCN_DBG(FM_ERR | MAIN, "Not a valid dbg_level: %s\n", tmp_buf); + if (!fm_cust_config_setup(tmp_buf)) { + WCN_DBG(FM_NTC | MAIN, "get config form %s ok\n", tmp_buf); + return count; + } + return -EFAULT; + } + + WCN_DBG(FM_NTC | MAIN, "fm_proc_write:1 g_dbg_level = 0x%x\n", g_dbg_level); + return count; +} + +/* #define FM_DEV_STATIC_ALLOC */ +/* #define FM_DEV_MAJOR 193 */ +/* static int FM_major = FM_DEV_MAJOR; *//* dynamic allocation */ + +static signed int fm_cdev_setup(struct fm *fm) +{ + signed int ret = 0; + struct fm_platform *plat = &fm->platform; + +#ifdef FM_DEV_STATIC_ALLOC + /*static allocate chrdev */ + plat->dev_t = MKDEV(FM_major, 0); + ret = register_chrdev_region(plat->dev_t, 1, FM_NAME); + + if (ret) { + WCN_DBG(FM_ERR | MAIN, "%s():fail to register chrdev\n", __func__); + return ret; + } +#endif + +#ifndef FM_DEV_STATIC_ALLOC + ret = alloc_chrdev_region(&plat->dev_t, 0, 1, FM_NAME); + + if (ret) { + WCN_DBG(FM_ALT | MAIN, "alloc dev_t failed\n"); + return ret; + } +#endif + + WCN_DBG(FM_NTC | MAIN, "alloc %s:%d:%d\n", FM_NAME, MAJOR(plat->dev_t), MINOR(plat->dev_t)); + + cdev_init(&plat->cdev, &fm_ops); + + plat->cdev.owner = THIS_MODULE; + plat->cdev.ops = &fm_ops; + + ret = cdev_add(&plat->cdev, plat->dev_t, 1); + + if (ret) { + WCN_DBG(FM_ALT | MAIN, "add dev_t failed\n"); + return ret; + } +#ifndef FM_DEV_STATIC_ALLOC + plat->cls = class_create(THIS_MODULE, FM_NAME); + + if (IS_ERR(plat->cls)) { + ret = PTR_ERR(plat->cls); + WCN_DBG(FM_ALT | MAIN, "class_create err:%d\n", ret); + return ret; + } + + plat->dev = device_create(plat->cls, NULL, plat->dev_t, NULL, FM_NAME); +#endif + + return ret; +} + +static signed int fm_cdev_destroy(struct fm *fm) +{ + if (fm == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + device_destroy(fm->platform.cls, fm->platform.dev_t); + class_destroy(fm->platform.cls); + cdev_del(&fm->platform.cdev); + unregister_chrdev_region(fm->platform.dev_t, 1); + + return 0; +} + +static signed int fm_mod_init(unsigned int arg) +{ + signed int ret = 0; + struct fm *fm = NULL; + + fm = fm_dev_init(0); + + if (!fm) { + ret = -ENOMEM; + goto ERR_EXIT; + } + + ret = fm_cdev_setup(fm); + if (ret) + goto ERR_EXIT; + + /* fm proc file create "/proc/fm" */ + g_fm_proc = proc_create(FM_PROC_FILE, 0444, NULL, &fm_proc_ops); + + if (g_fm_proc == NULL) { + WCN_DBG(FM_ALT | MAIN, "create_proc_entry failed\n"); + ret = -ENOMEM; + goto ERR_EXIT; + } else { + WCN_DBG(FM_NTC | MAIN, "create_proc_entry success\n"); + } + + g_fm = fm; + return 0; + +ERR_EXIT: + + if (fm) { + fm_cdev_destroy(fm); + fm_dev_destroy(fm); + } + + remove_proc_entry(FM_PROC_FILE, NULL); + return ret; +} + +static signed int fm_mod_destroy(struct fm *fm) +{ + signed int ret = 0; + + if (fm == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + WCN_DBG(FM_NTC | MAIN, "%s\n", __func__); + remove_proc_entry(FM_PROC_FILE, NULL); + fm_cdev_destroy(fm); + fm_dev_destroy(fm); + + return ret; +} + +static signed int mt_fm_probe(struct platform_device *pdev) +{ + signed int ret = 0; + + WCN_DBG(FM_NTC | MAIN, "%s\n", __func__); + + ret = fm_mod_init(0); + + if (ret) { + WCN_DBG(FM_ERR | MAIN, "fm mod init err\n"); + return -ENOMEM; + } + + return ret; +} + +static signed int mt_fm_remove(struct platform_device *pdev) +{ + WCN_DBG(FM_NTC | MAIN, "%s\n", __func__); + + fm_mod_destroy(g_fm); + g_fm = NULL; + return 0; +} + +static struct platform_device *pr_fm_device; +/* +static struct platform_device mt_fm_device = { + .name = FM_NAME, + .id = -1, +}; +*/ +/* platform driver entry */ +static struct platform_driver mt_fm_dev_drv = { + .probe = mt_fm_probe, + .remove = mt_fm_remove, + .driver = { + .name = FM_NAME, + .owner = THIS_MODULE, + } +}; + +static signed int mt_fm_init(void) +{ + signed int ret = 0; + + ret = fm_env_setup(); + + if (ret) { + fm_env_destroy(); + return ret; + } + /* register fm device to platform bus */ + /* ret = platform_device_register(&mt_fm_device); + * + * if (ret) + * return ret; + */ + + pr_fm_device = platform_device_alloc(FM_NAME, 0); + if (!pr_fm_device) { + WCN_DBG(FM_ERR | MAIN, "fm platform device alloc fail\n"); + return -ENOMEM; + } + + ret = platform_device_add(pr_fm_device); + if (ret) { + WCN_DBG(FM_ERR | MAIN, "fm platform device add failed(%d)\n", ret); + platform_device_put(pr_fm_device); + return ret; + } + + /* register fm driver to platform bus */ + ret = platform_driver_register(&mt_fm_dev_drv); + + if (ret) { + WCN_DBG(FM_ERR | MAIN, "fm platform driver register fail(%d)\n", ret); + platform_device_unregister(pr_fm_device); + return ret; + } + + fm_register_irq(&mt_fm_dev_drv); + + WCN_DBG(FM_NTC | MAIN, "6. fm platform driver registered\n"); + return ret; +} + +static void mt_fm_exit(void) +{ + WCN_DBG(FM_NTC | MAIN, "%s\n", __func__); + platform_driver_unregister(&mt_fm_dev_drv); + /* platform_device_unregister(&mt_fm_device); */ + platform_device_unregister(pr_fm_device); + fm_env_destroy(); +} + +#ifdef MTK_WCN_REMOVE_KERNEL_MODULE +int mtk_wcn_fm_init(void) +{ + return mt_fm_init(); +} +EXPORT_SYMBOL(mtk_wcn_fm_init); + +void mtk_wcn_fm_exit(void) +{ + mt_fm_exit(); +} +EXPORT_SYMBOL(mtk_wcn_fm_exit); +#else +module_init(mt_fm_init); +module_exit(mt_fm_exit); +#endif +EXPORT_SYMBOL(g_dbg_level); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MediaTek FM Driver"); +MODULE_AUTHOR("Hongcheng <hongcheng.xia@MediaTek.com>"); diff --git a/drivers/misc/mediatek/connectivity/fmradio/core/fm_patch.c b/drivers/misc/mediatek/connectivity/fmradio/core/fm_patch.c new file mode 100644 index 00000000000000..2034feb74e4686 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/core/fm_patch.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/fs.h> +#include <linux/firmware.h> +#include <linux/uaccess.h> + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" + +/* + * fm_file_read - read FM DSP patch/coeff/hwcoeff/rom binary file + * @filename - source file name + * @dst - target buffer + * @len - desired read length + * @position - the read position + * If success, return read length in bytes, else error code + */ +signed int fm_file_read(const signed char *filename, unsigned char *dst, signed int len, signed int position) +{ + const struct firmware *fw = NULL; + signed int ret = 0; + + ret = request_firmware(&fw, filename, NULL); + if (ret) { + WCN_DBG(FM_ERR | CHIP, "Failed to load firmware \"%s\"\n", filename); + release_firmware(fw); + return -FM_EPATCH; + } + WCN_DBG(FM_NTC | CHIP, "load firmware \"%s\" ok\n", filename); + + if (len >= fw->size) { + memcpy(dst, fw->data, fw->size); + WCN_DBG(FM_NTC | CHIP, "Copy file data(%p) size(%zu)\n", fw->data, fw->size); + ret = fw->size; + } else { + WCN_DBG(FM_NTC | CHIP, "Copy file data failed fw->size(%zu) > bufsize(%d)\n", fw->size, len); + ret = -FM_EPATCH; + } + release_firmware(fw); + return ret; +} + +signed int fm_file_write(const signed char *filename, unsigned char *dst, signed int len, signed int *ppos) +{ + signed int ret = 0; + return ret; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/core/fm_rds_parser.c b/drivers/misc/mediatek/connectivity/fmradio/core/fm_rds_parser.c new file mode 100644 index 00000000000000..960c15de8fef4d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/core/fm_rds_parser.c @@ -0,0 +1,2003 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/string.h> + +#include "fm_typedef.h" +#include "fm_rds.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_stdlib.h" + +/* static enum rds_ps_state_machine_t ps_state_machine = RDS_PS_START; */ +/* static enum rds_rt_state_machine_t rt_state_machine = RDS_RT_START; */ +struct fm_state_machine { + signed int state; + signed int (*state_get)(struct fm_state_machine *thiz); + signed int (*state_set)(struct fm_state_machine *thiz, signed int new_state); +}; + +static signed int fm_state_get(struct fm_state_machine *thiz) +{ + return thiz->state; +} + +static signed int fm_state_set(struct fm_state_machine *thiz, signed int new_state) +{ + return thiz->state = new_state; +} + +#define STATE_SET(a, s) \ +{ \ + if ((a)->state_set) { \ + (a)->state_set((a), (s)); \ + } \ +} + +#define STATE_GET(a) \ +({ \ + signed int __ret = 0; \ + if ((a)->state_get) { \ + __ret = (a)->state_get((a)); \ + } \ + __ret; \ +}) + +static unsigned short (*rds_get_freq)(void); + +/* RDS spec related handle flow */ +/* + * rds_cnt_get + * To get rds group count form raw data + * If success return 0, else return error code +*/ +static signed int rds_cnt_get(struct rds_rx_t *rds_raw, signed int raw_size, signed int *cnt) +{ + signed int gap = sizeof(rds_raw->cos) + sizeof(rds_raw->sin); + + if (rds_raw == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (cnt == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + *cnt = (raw_size - gap) / sizeof(struct rds_packet_t); + WCN_DBG(FM_INF | RDSC, "group cnt=%d\n", *cnt); + + return 0; +} + +/* + * rds_grp_get + * To get rds group[n] data form raw data with index + * If success return 0, else return error code +*/ +static signed int rds_grp_get(unsigned short *dst, struct rds_rx_t *raw, signed int idx) +{ + if (dst == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (raw == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (idx > (MAX_RDS_RX_GROUP_CNT - 1)) + return -FM_EPARA; + + dst[0] = raw->data[idx].blkA; + dst[1] = raw->data[idx].blkB; + dst[2] = raw->data[idx].blkC; + dst[3] = raw->data[idx].blkD; + dst[4] = raw->data[idx].crc; + dst[5] = raw->data[idx].cbc; + + WCN_DBG(FM_NTC | RDSC, "BLOCK:%04x %04x %04x %04x, CRC:%04x CBC:%04x\n", dst[0], dst[1], + dst[2], dst[3], dst[4], dst[5]); + + return 0; +} + +/* + * rds_checksum_check + * To check CRC rerult, if OK, *valid=true, else *valid=false + * If success return 0, else return error code +*/ +static signed int rds_checksum_check(unsigned short crc, signed int mask, bool *valid) +{ + if (valid == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if ((crc & mask) == mask) + *valid = true; + else + *valid = false; + + return 0; +} + +/* + * rds_event_set + * To set rds event, and user space can use this flag to juge which event happened + * If success return 0, else return error code +*/ +static signed int rds_event_set(unsigned short *events, signed int event_mask) +{ + if (events == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + WCN_DBG(FM_INF | RDSC, "rds set event[0x%04x->0x%04x]\n", event_mask, *events); + *events |= event_mask; + + return 0; +} + +/* + * rds_flag_set + * To set rds event flag, and user space can use this flag to juge which event happened + * If success return 0, else return error code +*/ +static signed int rds_flag_set(unsigned int *flags, signed int flag_mask) +{ + if (flags == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + WCN_DBG(FM_INF | RDSC, "rds set flag[0x%04x->0x%04x]\n", flag_mask, *flags); + *flags |= flag_mask; + + return 0; +} + +/* + * rds_grp_type_get + * To get rds group type form blockB + * If success return 0, else return error code +*/ +static signed int rds_grp_type_get(unsigned short crc, unsigned short blk, unsigned char *type, unsigned char *subtype) +{ + bool valid = false; + + if (type == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (subtype == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + /* to get the group type from block B */ + rds_checksum_check(crc, FM_RDS_GDBK_IND_B, &valid); + + if (valid == true) { + *type = (blk & 0xF000) >> 12; /* Group type(4bits) */ + *subtype = (blk & 0x0800) >> 11; /* version code(1bit), 0=vesionA, 1=versionB */ + } else { + WCN_DBG(FM_WAR | RDSC, "Block1 CRC err\n"); + return -FM_ECRC; + } + + WCN_DBG(FM_DBG | RDSC, "Type=%d, subtype:%s\n", (signed int) *type, *subtype ? "version B" : "version A"); + return 0; +} + +/* + * rds_grp_counter_add + * @type -- group type, rang: 0~15 + * @subtype -- sub group type, rang:0~1 + * + * add group counter, g0a~g15b + * we use type value as the index + * If success return 0, else return error code +*/ +static signed int rds_grp_counter_add(unsigned char type, unsigned char subtype, struct rds_group_cnt_t *gc) +{ + if (gc == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (type > 15) + return -FM_EPARA; + + switch (subtype) { + case RDS_GRP_VER_A: + gc->groupA[type]++; + break; + case RDS_GRP_VER_B: + gc->groupB[type]++; + break; + default: + return -FM_EPARA; + } + + gc->total++; + WCN_DBG(FM_INF | RDSC, "group counter:%d\n", (signed int) gc->total); + return 0; +} + +/* + * rds_grp_counter_get + * + * read group counter , g0a~g15b + * If success return 0, else return error code +*/ +extern signed int rds_grp_counter_get(struct rds_group_cnt_t *dst, struct rds_group_cnt_t *src) +{ + if (dst == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (src == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_memcpy(dst, src, sizeof(struct rds_group_cnt_t)); + WCN_DBG(FM_DBG | RDSC, "rds gc get[total=%d]\n", (signed int) dst->total); + return 0; +} + +/* + * rds_grp_counter_reset + * + * clear group counter to 0, g0a~g15b + * If success return 0, else return error code +*/ +extern signed int rds_grp_counter_reset(struct rds_group_cnt_t *gc) +{ + if (gc == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + fm_memset(gc, 0, sizeof(struct rds_group_cnt_t)); + return 0; +} + +extern signed int rds_log_in(struct rds_log_t *thiz, struct rds_rx_t *new_log, signed int new_len) +{ + if (new_log == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + new_len = (new_len < sizeof(struct rds_rx_t)) ? new_len : sizeof(struct rds_rx_t); + fm_memcpy(&(thiz->rds_log[thiz->in]), new_log, new_len); + thiz->log_len[thiz->in] = new_len; + thiz->in = (thiz->in + 1) % thiz->size; + thiz->len++; + thiz->len = (thiz->len >= thiz->size) ? thiz->size : thiz->len; + WCN_DBG(FM_DBG | RDSC, "add a new log[len=%d]\n", thiz->len); + + return 0; +} + +extern signed int rds_log_out(struct rds_log_t *thiz, struct rds_rx_t *dst, signed int *dst_len) +{ + if (dst == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (dst_len == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (thiz->len > 0) { + *dst_len = thiz->log_len[thiz->out]; + *dst_len = (*dst_len < sizeof(struct rds_rx_t)) ? *dst_len : sizeof(struct rds_rx_t); + fm_memcpy(dst, &(thiz->rds_log[thiz->out]), *dst_len); + thiz->out = (thiz->out + 1) % thiz->size; + thiz->len--; + WCN_DBG(FM_DBG | RDSC, "del a new log[len=%d]\n", thiz->len); + } else { + *dst_len = 0; + WCN_DBG(FM_WAR | RDSC, "rds log buf is empty\n"); + } + + return 0; +} + +/* + * rds_grp_pi_get + * To get rds group pi code form blockA + * If success return 0, else return error code +*/ +static signed int rds_grp_pi_get(unsigned short crc, unsigned short blk, unsigned short *pi, bool *dirty) +{ + signed int ret = 0; + bool valid = false; + + if (pi == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (dirty == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + /* to get the group pi code from block A */ + ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_A, &valid); + + if (valid == true) { + if (*pi != blk) { + /* PI=program Identication */ + *pi = blk; + *dirty = true; /* yes, we got new PI code */ + } else { + *dirty = false; /* PI is the same as last one */ + } + } else { + WCN_DBG(FM_WAR | RDSC, "Block0 CRC err\n"); + return -FM_ECRC; + } + + WCN_DBG(FM_INF | RDSC, "PI=0x%04x, %s\n", *pi, *dirty ? "new" : "old"); + return ret; +} + +/* + * rds_grp_pty_get + * To get rds group pty code form blockB + * If success return 0, else return error code +*/ +static signed int rds_grp_pty_get(unsigned short crc, unsigned short blk, unsigned char *pty, bool *dirty) +{ + signed int ret = 0; +/* bool valid = false; */ + + if (pty == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (dirty == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + /* to get PTY code from block B */ +/* ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_B, &valid); */ + +/* if (valid == false) { */ +/* WCN_DBG(FM_WAR | RDSC, "Block1 CRC err\n"); */ +/* return -FM_ECRC; */ +/* } */ + + if (*pty != ((blk & 0x03E0) >> 5)) { + /* PTY=Program Type Code */ + *pty = (blk & 0x03E0) >> 5; + *dirty = true; /* yes, we got new PTY code */ + } else { + *dirty = false; /* PTY is the same as last one */ + } + + WCN_DBG(FM_INF | RDSC, "PTY=%d, %s\n", (signed int) *pty, *dirty ? "new" : "old"); + return ret; +} + +/* + * rds_grp_tp_get + * To get rds group tp code form blockB + * If success return 0, else return error code +*/ +static signed int rds_grp_tp_get(unsigned short crc, unsigned short blk, unsigned char *tp, bool *dirty) +{ + signed int ret = 0; +/* bool valid = false; */ + + if (tp == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (dirty == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + /* to get TP code from block B */ +/* ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_B, &valid); */ + +/* if (valid == false) { */ +/* WCN_DBG(FM_WAR | RDSC, "Block1 CRC err\n"); */ +/* return -FM_ECRC; */ +/* } */ + + if (*tp != ((blk & 0x0400) >> 10)) { + /* Tranfic Program Identification */ + *tp = (blk & 0x0400) >> 10; + *dirty = true; /* yes, we got new TP code */ + } else { + *dirty = false; /* TP is the same as last one */ + } + + /* WCN_DBG(FM_INF | RDSC, "TP=%d, %s\n", (signed int) *tp, *dirty ? "new" : "old"); */ + return ret; +} + +/* + * rds_g0_ta_get + * To get rds group ta code form blockB + * If success return 0, else return error code +*/ +static signed int rds_g0_ta_get(unsigned short blk, unsigned char *ta, bool *dirty) +{ + signed int ret = 0; + + if (ta == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (dirty == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + /* TA=Traffic Announcement code */ + if (*ta != ((blk & 0x0010) >> 4)) { + *ta = (blk & 0x0010) >> 4; + *dirty = true; /* yes, we got new TA code */ + } else { + *dirty = false; /* TA is the same as last one */ + } + + WCN_DBG(FM_INF | RDSC, "TA=%d, %s\n", (signed int) *ta, *dirty ? "new" : "old"); + return ret; +} + +/* + * rds_g0_music_get + * To get music-speech switch code form blockB + * If success return 0, else return error code +*/ +static signed int rds_g0_music_get(unsigned short blk, unsigned char *music, bool *dirty) +{ + signed int ret = 0; + + if (music == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (dirty == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + /* M/S=music speech switch code */ + if (*music != ((blk & 0x0008) >> 3)) { + *music = (blk & 0x0008) >> 3; + *dirty = true; /* yes, we got new music code */ + } else { + *dirty = false; /* music is the same as last one */ + } + + WCN_DBG(FM_INF | RDSC, "Music=%d, %s\n", (signed int) *music, *dirty ? "new" : "old"); + return ret; +} + +/* + * rds_g0_ps_addr_get + * To get ps addr form blockB, blkB b0~b1 + * If success return 0, else return error code +*/ +static signed int rds_g0_ps_addr_get(unsigned short blkB, unsigned char *addr) +{ + if (addr == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + *addr = (unsigned char) blkB & 0x03; + + WCN_DBG(FM_INF | RDSC, "addr=0x%02x\n", *addr); + return 0; +} + +/* + * rds_g0_di_flag_get + * To get DI segment flag form blockB, blkB b2 + * If success return 0, else return error code +*/ +static signed int rds_g0_di_flag_get(unsigned short blkB, unsigned char *flag) +{ + if (flag == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + *flag = (unsigned char) ((blkB & 0x0004) >> 2); + + WCN_DBG(FM_INF | RDSC, "flag=0x%02x\n", *flag); + return 0; +} + +static signed int rds_g0_ps_get(unsigned short crc, unsigned short blkD, unsigned char addr, unsigned char *buf) +{ +/* bool valid = false; */ + signed int idx = 0; + + if (buf == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + /* ps segment addr rang 0~3 */ + if (addr > 0x03) { + WCN_DBG(FM_ERR | RDSC, "addr invalid(0x%02x)\n", addr); + return -FM_EPARA; + } + + idx = 2 * addr; + buf[idx] = blkD >> 8; + buf[idx + 1] = blkD & 0xFF; +#if 0 + rds_checksum_check(crc, FM_RDS_GDBK_IND_D, &valid); + + if (valid == true) { + buf[idx] = blkD >> 8; + buf[idx + 1] = blkD & 0xFF; + } else { + WCN_DBG(FM_ERR | RDSC, "ps crc check err\n"); + return -FM_ECRC; + } +#endif + + WCN_DBG(FM_INF | RDSC, "PS:addr[%02x]:0x%02x 0x%02x\n", addr, buf[idx], buf[idx + 1]); + return 0; +} + +/* + * rds_g0_ps_cmp + * this function is the most importent flow for PS parsing + * 1.Compare fresh buf with once buf per byte, if eque copy this byte to twice buf, else copy it to once buf + * 2.Check whether we got a full segment + * If success return 0, else return error code +*/ +static signed int rds_g0_ps_cmp(unsigned char addr, unsigned short cbc, unsigned char *fresh, + unsigned char *once, unsigned char *twice, /*bool *valid, */ unsigned char *bm) +{ + signed int ret = 0, indx; + /* signed int i = 0; */ + /* signed int j = 0; */ + /* signed int cnt = 0; */ + unsigned char AF_H, AF_L, PS_Num; + /* unsigned char corrBitCnt_BlkB, corrBitCnt_BlkD; */ + static signed char Pre_PS_Num = -1; + + if (fresh == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (once == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (twice == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (addr > 3) { /* ps limited in 8 chars */ + WCN_DBG(FM_NTC | RDSC, "PS Address error, addr=%x\n", addr); + return -1; + } + + /* j = 2; // PS segment width */ + PS_Num = addr; + /* corrBitCnt_BlkB = rds_cbc_get(cbc, RDS_BLK_B); */ + /* corrBitCnt_BlkD = rds_cbc_get(cbc, RDS_BLK_D); */ + + AF_H = once[2 * PS_Num]; + AF_L = once[2 * PS_Num + 1]; + if ((fresh[2 * PS_Num] == AF_H) && (fresh[2 * PS_Num + 1] == AF_L)) { + twice[2 * PS_Num] = once[2 * PS_Num]; + twice[2 * PS_Num + 1] = once[2 * PS_Num + 1]; + *bm |= 1 << PS_Num; + } else { + if (PS_Num - Pre_PS_Num > 1) { + for (indx = Pre_PS_Num + 1; indx < PS_Num; indx++) { + *bm &= ~(1 << indx); + once[2 * indx] = 0x00; + once[2 * indx + 1] = 0x00; + twice[2 * indx] = 0x00; + twice[2 * indx + 1] = 0x00; + } + } else if (PS_Num - Pre_PS_Num < 1) { + for (indx = 0; indx < PS_Num; indx++) { + *bm &= ~(1 << indx); + once[2 * indx] = 0x00; + once[2 * indx + 1] = 0x00; + twice[2 * indx] = 0x00; + twice[2 * indx + 1] = 0x00; + } + } + + if ((once[2 * PS_Num] != 0) || (once[2 * PS_Num + 1] != 0)) { + for (indx = PS_Num; indx < 4; indx++) + *bm &= ~(1 << indx); + } + /* if((corrBitCnt_BlkB == 0) && (corrBitCnt_BlkD == 0)) */ + /* ALPS00523685:6627 CBC sometime is unreliable */ +#ifdef RDS_CBC_DEPENDENCY + if (cbc == 0) { + *bm |= 1 << PS_Num; + once[2 * PS_Num] = fresh[2 * PS_Num]; + once[2 * PS_Num + 1] = fresh[2 * PS_Num + 1]; + twice[2 * PS_Num] = fresh[2 * PS_Num]; + twice[2 * PS_Num + 1] = fresh[2 * PS_Num + 1]; + } else +#endif + { + once[2 * PS_Num] = fresh[2 * PS_Num]; + once[2 * PS_Num + 1] = fresh[2 * PS_Num + 1]; + } + } + + Pre_PS_Num = PS_Num; +#if 0 + if (rds_cbc_get(cbc, RDS_BLK_D) == 0) { + once[j * addr] = fresh[j * addr]; + once[j * addr + 1] = fresh[j * addr + 1]; + } + if ((once[j * addr] == fresh[j * addr]) && (once[j * addr + 1] == fresh[j * addr + 1])) { + twice[j * addr] = once[j * addr]; + twice[j * addr + 1] = once[j * addr + 1]; + *valid = true; + } else { + once[j * addr] = fresh[j * addr]; + once[j * addr + 1] = fresh[j * addr + 1]; + *valid = false; + } +#endif +#if 0 + for (i = 0; i < j; i++) { + if (fresh[j * addr + i] == once[j * addr + i]) { + twice[j * addr + i] = once[j * addr + i]; /* get the same byte 2 times */ + cnt++; + } else { + once[j * addr + i] = fresh[j * addr + i]; /* use new val */ + } + } + + /* check if we got a valid segment */ + if (cnt == j) + *valid = true; + else + *valid = false; +#endif + /* WCN_DBG(FM_NTC | RDSC, "PS seg=%s\n", *valid == true ? "true" : "false"); */ + WCN_DBG(FM_INF | RDSC, "bitmap=%x\n", *bm); + WCN_DBG(FM_INF | RDSC, "PS[%02x][1][2]=%x %x|%x %x|%x %x|%x %x|%x %x|%x %x|%x %x|%x %x\n", + addr, once[0], twice[0], once[1], twice[1], once[2], twice[2], once[3], twice[3], + once[4], twice[4], once[5], twice[5], once[6], twice[6], once[7], twice[7]); + return ret; +} + +struct rds_bitmap { + unsigned short bm; + signed int cnt; + signed int max_addr; + unsigned short (*bm_get)(struct rds_bitmap *thiz); + signed int (*bm_cnt_get)(struct rds_bitmap *thiz); + signed int (*bm_get_pos)(struct rds_bitmap *thiz); + signed int (*bm_clr)(struct rds_bitmap *thiz); + signed int (*bm_cmp)(struct rds_bitmap *thiz, struct rds_bitmap *that); + signed int (*bm_set)(struct rds_bitmap *thiz, unsigned char addr); +}; + +static unsigned short rds_bm_get(struct rds_bitmap *thiz) +{ + return thiz->bm; +} + +static signed int rds_bm_cnt_get(struct rds_bitmap *thiz) +{ + return thiz->cnt; +} + +#define FM_RDS_USE_SOLUTION_B + +static signed int rds_bm_get_pos(struct rds_bitmap *thiz) +{ + signed int i = thiz->max_addr; + signed int j; + + j = 0; + + while ((i > -1) && !(thiz->bm & (1 << i))) + i--; + +#ifdef FM_RDS_USE_SOLUTION_B + for (j = i; j >= 0; j--) { + if (!(thiz->bm & (1 << j))) { + WCN_DBG(FM_NTC | RDSC, "uncomplete msg 0x%04x, delete it\n", thiz->bm); + return -1; + } + } +#endif + + return i; +} + +static signed int rds_bm_clr(struct rds_bitmap *thiz) +{ + thiz->bm = 0x0000; + thiz->cnt = 0; + return 0; +} + +static signed int rds_bm_cmp(struct rds_bitmap *bitmap1, struct rds_bitmap *bitmap2) +{ + return (signed int) (bitmap1->bm - bitmap2->bm); +} + +static signed int rds_bm_set(struct rds_bitmap *thiz, unsigned char addr) +{ + struct rds_bitmap bm_old; + + /* text segment addr rang */ + if (addr > thiz->max_addr) { + WCN_DBG(FM_ERR | RDSC, "addr invalid(0x%02x)\n", addr); + return -FM_EPARA; + } + + bm_old.bm = thiz->bm; + thiz->bm |= (1 << addr); /* set bitmap */ + + if (!rds_bm_cmp(&bm_old, thiz)) + thiz->cnt++; /* multi get a segment */ + else if (thiz->cnt > 0) + thiz->cnt--; + + return 0; +} + +/* + * rds_g2_rt_addr_get + * To get rt addr form blockB + * If success return 0, else return error code +*/ +static signed int rds_g2_rt_addr_get(unsigned short blkB, unsigned char *addr) +{ + signed int ret = 0; + + if (addr == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + *addr = (unsigned char) blkB & 0x0F; + + WCN_DBG(FM_INF | RDSC, "addr=0x%02x\n", *addr); + return ret; +} + +static signed int rds_g2_txtAB_get(unsigned short blk, unsigned char *txtAB, bool *dirty) +{ + signed int ret = 0; + static bool once_dirty; /* false */ + + if (txtAB == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (dirty == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + *dirty = false; + if (*txtAB != ((blk & 0x0010) >> 4)) { + if (once_dirty) { + *txtAB = (blk & 0x0010) >> 4; + *dirty = true; /* yes, we got new txtAB code */ + once_dirty = false; + WCN_DBG(FM_NTC | RDSC, "changed! txtAB=%d\n", *txtAB); + return ret; + } + once_dirty = true; + } else { + once_dirty = false; /* txtAB is the same as last one */ + } + + WCN_DBG(FM_INF | RDSC, "txtAB=%d, %s\n", *txtAB, *dirty ? "new" : "old"); + return ret; +} + +static signed int rds_g2_rt_get(unsigned short crc, unsigned char subtype, unsigned short blkC, unsigned short blkD, + unsigned char addr, unsigned char *buf) +{ + signed int ret = 0; + bool valid = false; + signed int idx = 0; + + if (buf == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + /* text segment addr rang 0~15 */ + if (addr > 0x0F) { + WCN_DBG(FM_ERR | RDSC, "addr invalid(0x%02x)\n", addr); + ret = -FM_EPARA; + return ret; + } + + switch (subtype) { + case RDS_GRP_VER_A: + idx = 4 * addr; + ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_C | FM_RDS_GDBK_IND_D, &valid); + + if (valid == true) { + buf[idx] = blkC >> 8; + buf[idx + 1] = blkC & 0xFF; + buf[idx + 2] = blkD >> 8; + buf[idx + 3] = blkD & 0xFF; + } else { + WCN_DBG(FM_ERR | RDSC, "rt crc check err\n"); + ret = -FM_ECRC; + } + + break; + case RDS_GRP_VER_B: + idx = 2 * addr; + ret = rds_checksum_check(crc, FM_RDS_GDBK_IND_D, &valid); + + if (valid == true) { + buf[idx] = blkD >> 8; + buf[idx + 1] = blkD & 0xFF; + } else { + WCN_DBG(FM_ERR | RDSC, "rt crc check err\n"); + ret = -FM_ECRC; + } + + break; + default: + break; + } + + WCN_DBG(FM_NTC | RDSC, "fresh addr[%02x]:0x%02x%02x 0x%02x%02x\n", addr, buf[idx], + buf[idx + 1], buf[idx + 2], buf[idx + 3]); + return ret; +} + +static signed int rds_g2_rt_get_len(unsigned char subtype, signed int pos, signed int *len) +{ + signed int ret = 0; + + if (len == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (subtype == RDS_GRP_VER_A) + *len = 4 * (pos + 1); + else + *len = 2 * (pos + 1); + + return ret; +} + +/* + * rds_g2_rt_cmp + * this function is the most importent flow for RT parsing + * 1.Compare fresh buf with once buf per byte, if eque copy this byte to twice buf, else copy it to once buf + * 2.Check whether we got a full segment, for typeA if copyed 4bytes to twice buf, for typeB 2bytes copyed to twice buf + * 3.Check whether we got the end of RT, if we got 0x0D + * 4.If we got the end, then caculate the RT length + * If success return 0, else return error code +*/ +static signed int rds_g2_rt_cmp(unsigned char addr, unsigned short cbc, unsigned char subtype, unsigned char *fresh, + unsigned char *once, unsigned char *twice, bool *valid) +{ + signed int ret = 0; + signed int i = 0; + signed int j = 0; + signed int cnt = 0; + + if (fresh == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (once == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (twice == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (valid == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + j = (subtype == RDS_GRP_VER_A) ? 4 : 2; /* RT segment width */ + + if (subtype == RDS_GRP_VER_A) { + /* if (rds_cbc_get(cbc, RDS_BLK_C) == 0) */ +#ifdef RDS_CBC_DEPENDENCY + if (cbc == 0) { +#endif + once[j * addr + 0] = fresh[j * addr + 0]; + once[j * addr + 1] = fresh[j * addr + 1]; + once[j * addr + 2] = fresh[j * addr + 2]; + once[j * addr + 3] = fresh[j * addr + 3]; +#ifdef RDS_CBC_DEPENDENCY + } +#endif + } else if (subtype == RDS_GRP_VER_B) { +#ifdef RDS_CBC_DEPENDENCY + if (cbc == 0) { +#endif + once[j * addr + 0] = fresh[j * addr + 0]; + once[j * addr + 1] = fresh[j * addr + 1]; +#ifdef RDS_CBC_DEPENDENCY + } +#endif + } +#ifdef RDS_CBC_DEPENDENCY + for (i = 0; i < j; i++) { + if (fresh[j * addr + i] == once[j * addr + i]) { + twice[j * addr + i] = once[j * addr + i]; /* get the same byte 2 times */ + cnt++; + /* WCN_DBG(FM_NTC | RDSC, "twice=%d\n", j * addr + i); */ + } else { + once[j * addr + i] = fresh[j * addr + i]; /* use new val */ + /* WCN_DBG(FM_NTC | RDSC, "once=%d\n", j * addr + i); */ + } + } +#else + for (i = 0; i < j; i++) { + if (twice[j * addr + i] == once[j * addr + i]) { + cnt++; + /* WCN_DBG(FM_NTC | RDSC, "twice=%d\n", j * addr + i); */ + } else { + twice[j * addr + i] = once[j * addr + i]; + /* WCN_DBG(FM_NTC | RDSC, "once=%d\n", j * addr + i); */ + } + } +#endif + + /* check if we got a valid segment 4bytes for typeA, 2bytes for typeB */ + if (cnt == j) + *valid = true; + else + *valid = false; + + WCN_DBG(FM_INF | RDSC, "RT seg=%s\n", *valid == true ? "true" : "false"); +/* WCN_DBG(FM_INF | RDSC, "RT end=%s\n", *end == true ? "true" : "false"); */ +/* WCN_DBG(FM_INF | RDSC, "RT len=%d\n", *len); */ + return ret; +} + +/* + * rds_g2_rt_check_end + * check 0x0D end flag + * If we got the end, then caculate the RT length + * If success return 0, else return error code +*/ +static signed int rds_g2_rt_check_end(unsigned char addr, unsigned char subtype, unsigned char *twice, bool *end) +{ + signed int i = 0; + signed int j = 0; + + if (twice == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (end == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + j = (subtype == RDS_GRP_VER_A) ? 4 : 2; /* RT segment width */ + *end = false; + + for (i = 0; i < j; i++) { + /* if we got 0x0D twice, it means a RT end */ + if (twice[j * addr + i] == 0x0D) { + *end = true; + WCN_DBG(FM_NTC | RDSC, "get 0x0D\n"); + break; + } + } + + return 0; +} + +static signed int rds_retrieve_g0_af(unsigned short *block_data, unsigned char SubType, struct rds_t *pstRDSData) +{ + static signed short preAF_Num; + unsigned char indx, indx2, AF_H, AF_L, num; + signed short temp_H, temp_L; + signed int ret = 0; + bool valid = false; + bool dirty = false; + unsigned short *event = &pstRDSData->event_status; + unsigned int *flag = &pstRDSData->RDSFlag.flag_status; + +/* ret = rds_checksum_check(block_data[4], FM_RDS_GDBK_IND_D, &valid); */ + +/* if (valid == false) { */ +/* WCN_DBG(FM_WAR | RDSC, "Group0 BlockD crc err\n"); */ +/* return -FM_ECRC; */ +/* } */ + + ret = rds_g0_ta_get(block_data[1], &pstRDSData->RDSFlag.TA, &dirty); + + if (ret) { + WCN_DBG(FM_WAR | RDSC, "get ta failed[ret=%d]\n", ret); + } else if (dirty == true) { + ret = rds_event_set(event, RDS_EVENT_FLAGS); /* yes, we got new TA code */ + ret = rds_flag_set(flag, RDS_FLAG_IS_TA); + } + + ret = rds_g0_music_get(block_data[1], &pstRDSData->RDSFlag.Music, &dirty); + + if (ret) { + WCN_DBG(FM_WAR | RDSC, "get music failed[ret=%d]\n", ret); + } else if (dirty == true) { + ret = rds_event_set(event, RDS_EVENT_FLAGS); /* yes, we got new MUSIC code */ + ret = rds_flag_set(flag, RDS_FLAG_IS_MUSIC); + } + + if ((pstRDSData->Switch_TP) && (pstRDSData->RDSFlag.TP) && !(pstRDSData->RDSFlag.TA)) + ret = rds_event_set(event, RDS_EVENT_TAON_OFF); + + if (SubType) /* Type B no AF information */ + goto out; + + /* Type A */ + + ret = rds_checksum_check(block_data[4], FM_RDS_GDBK_IND_C, &valid); + + if (valid == false) { + WCN_DBG(FM_WAR | RDSC, "Group0 BlockC crc err\n"); + return -FM_ECRC; + } + + AF_H = (block_data[2] & 0xFF00) >> 8; + AF_L = block_data[2] & 0x00FF; + + if ((AF_H > 224) && (AF_H < 250)) { + /* Followed AF Number, see RDS spec Table 11, valid(224-249) */ + WCN_DBG(FM_INF | RDSC, "RetrieveGroup0 AF_H:%d, AF_L:%d\n", AF_H, AF_L); + preAF_Num = AF_H - 224; /* AF Number */ + + if (preAF_Num != pstRDSData->AF_Data.AF_Num) { + pstRDSData->AF_Data.AF_Num = preAF_Num; + pstRDSData->AF_Data.isAFNum_Get = 0; + } else { + /* Get the same AFNum two times */ + pstRDSData->AF_Data.isAFNum_Get = 1; + } + + if ((AF_L < 205) && (AF_L > 0)) { + /* See RDS Spec table 10, valid VHF */ + pstRDSData->AF_Data.AF[0][0] = AF_L + 875; /* convert to 100KHz */ + pstRDSData->AF_Data.AF[0][0] *= 10; + WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 AF[0][0]:%d\n", + pstRDSData->AF_Data.AF[0][0]); + + if ((pstRDSData->AF_Data.AF[0][0]) != (pstRDSData->AF_Data.AF[1][0])) { + pstRDSData->AF_Data.AF[1][0] = pstRDSData->AF_Data.AF[0][0]; + } else { + if (pstRDSData->AF_Data.AF[1][0] != rds_get_freq()) + pstRDSData->AF_Data.isMethod_A = 1; + else + pstRDSData->AF_Data.isMethod_A = 0; + } + + WCN_DBG(FM_NTC | RDSC, + "RetrieveGroup0 isAFNum_Get:%d, isMethod_A:%d\n", + pstRDSData->AF_Data.isAFNum_Get, pstRDSData->AF_Data.isMethod_A); + + /* only one AF handle */ + if ((pstRDSData->AF_Data.isAFNum_Get) + && (pstRDSData->AF_Data.AF_Num == 1)) { + pstRDSData->AF_Data.Addr_Cnt = 0xFF; + pstRDSData->event_status |= RDS_EVENT_AF_LIST; + WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 RDS_EVENT_AF_LIST update\n"); + } + } + } else if ((pstRDSData->AF_Data.isAFNum_Get) + && (pstRDSData->AF_Data.Addr_Cnt != 0xFF)) { + /* AF Num correct */ + num = pstRDSData->AF_Data.AF_Num; + num = (num > 25) ? 25 : num; + num = num >> 1; + WCN_DBG(FM_INF | RDSC, "RetrieveGroup0 +num:%d\n", num); + + /* Put AF freq into buffer and check if AF freq is repeat again */ + for (indx = 1; indx < (num + 1); indx++) { + if ((AF_H == (pstRDSData->AF_Data.AF[0][2 * indx - 1] / 10 - 875)) + && (AF_L == (pstRDSData->AF_Data.AF[0][2 * indx] / 10 - 875))) { + WCN_DBG(FM_NTC | RDSC, + "RetrieveGroup0 +num:%d AF same as indx:%d\n", num, indx); + break; + } else if (!(pstRDSData->AF_Data.AF[0][2 * indx - 1])) { + /* null buffer */ + /* convert to 100KHz */ + pstRDSData->AF_Data.AF[0][2 * indx - 1] = AF_H + 875; + pstRDSData->AF_Data.AF[0][2 * indx] = AF_L + 875; + + pstRDSData->AF_Data.AF[0][2 * indx - 1] *= 10; + pstRDSData->AF_Data.AF[0][2 * indx] *= 10; + + WCN_DBG(FM_NTC | RDSC, + "RetrieveGroup0 +num:%d AF[0][%d]:%d, AF[0][%d]:%d\n", + num, 2 * indx - 1, + pstRDSData->AF_Data.AF[0][2 * indx - 1], + 2 * indx, pstRDSData->AF_Data.AF[0][2 * indx]); + break; + } + } + + num = pstRDSData->AF_Data.AF_Num; + num = (num > 25) ? 25 : num; + WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 ++num:%d\n", num); + + if (num <= 0) + goto out; + + if ((pstRDSData->AF_Data.AF[0][num - 1]) == 0) + goto out; + + num = num >> 1; + WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 +++num:%d\n", num); + + /* arrange frequency from low to high:start */ + for (indx = 1; indx < num; indx++) { + for (indx2 = indx + 1; indx2 < (num + 1); indx2++) { + temp_H = pstRDSData->AF_Data.AF[0][2 * indx - 1]; + temp_L = pstRDSData->AF_Data.AF[0][2 * indx]; + + if (temp_H > (pstRDSData->AF_Data.AF[0][2 * indx2 - 1])) { + pstRDSData->AF_Data.AF[0][2 * indx - 1] = + pstRDSData->AF_Data.AF[0][2 * indx2 - 1]; + pstRDSData->AF_Data.AF[0][2 * indx] = + pstRDSData->AF_Data.AF[0][2 * indx2]; + pstRDSData->AF_Data.AF[0][2 * indx2 - 1] = temp_H; + pstRDSData->AF_Data.AF[0][2 * indx2] = temp_L; + } else if (temp_H == (pstRDSData->AF_Data.AF[0][2 * indx2 - 1])) { + if (temp_L > (pstRDSData->AF_Data.AF[0][2 * indx2])) { + pstRDSData->AF_Data.AF[0][2 * indx - 1] = + pstRDSData->AF_Data.AF[0][2 * indx2 - 1]; + pstRDSData->AF_Data.AF[0][2 * indx] = + pstRDSData->AF_Data.AF[0][2 * indx2]; + pstRDSData->AF_Data.AF[0][2 * indx2 - 1] = temp_H; + pstRDSData->AF_Data.AF[0][2 * indx2] = temp_L; + } + } + } + } + + /* arrange frequency from low to high:end */ + /* compare AF buff0 and buff1 data:start */ + num = pstRDSData->AF_Data.AF_Num; + num = (num > 25) ? 25 : num; + indx2 = 0; + + for (indx = 0; indx < num; indx++) { + if ((pstRDSData->AF_Data.AF[1][indx]) == (pstRDSData->AF_Data.AF[0][indx])) { + if (pstRDSData->AF_Data.AF[1][indx] != 0) + indx2++; + } else + pstRDSData->AF_Data.AF[1][indx] = pstRDSData->AF_Data.AF[0][indx]; + } + + WCN_DBG(FM_NTC | RDSC, "RetrieveGroup0 indx2:%d, num:%d\n", indx2, num); + + /* compare AF buff0 and buff1 data:end */ + if (indx2 == num) { + pstRDSData->AF_Data.Addr_Cnt = 0xFF; + pstRDSData->event_status |= RDS_EVENT_AF_LIST; + WCN_DBG(FM_NTC | RDSC, + "RetrieveGroup0 AF_Num:%d\n", + pstRDSData->AF_Data.AF_Num); + + for (indx = 0; indx < num; indx++) { + if ((pstRDSData->AF_Data.AF[1][indx]) == 0) { + pstRDSData->AF_Data.Addr_Cnt = 0x0F; + pstRDSData->event_status &= (~RDS_EVENT_AF_LIST); + } + } + } else + pstRDSData->AF_Data.Addr_Cnt = 0x0F; + } + +out: return ret; +} + +static signed int rds_retrieve_g0_di(unsigned short *block_data, unsigned char SubType, struct rds_t *pstRDSData) +{ + unsigned char DI_Code, DI_Flag; + signed int ret = 0; +/* bool valid = false; */ + + unsigned short *event = &pstRDSData->event_status; + unsigned int *flag = &pstRDSData->RDSFlag.flag_status; + + /* parsing Program service name segment (in BlockD) */ +/* ret = rds_checksum_check(block_data[4], FM_RDS_GDBK_IND_D, &valid); */ + +/* if (valid == false) { */ +/* WCN_DBG(FM_WAR | RDSC, "Group0 BlockD crc err\n"); */ +/* return -FM_ECRC; */ +/* } */ + + rds_g0_ps_addr_get(block_data[1], &DI_Code); + rds_g0_di_flag_get(block_data[1], &DI_Flag); + + switch (DI_Code) { + case 3: + + if (pstRDSData->RDSFlag.Stereo != DI_Flag) { + pstRDSData->RDSFlag.Stereo = DI_Flag; + ret = rds_event_set(event, RDS_EVENT_FLAGS); + ret = rds_flag_set(flag, RDS_FLAG_IS_STEREO); + } + + break; + case 2: + + if (pstRDSData->RDSFlag.Artificial_Head != DI_Flag) { + pstRDSData->RDSFlag.Artificial_Head = DI_Flag; + ret = rds_event_set(event, RDS_EVENT_FLAGS); + ret = rds_flag_set(flag, RDS_FLAG_IS_ARTIFICIAL_HEAD); + } + + break; + case 1: + + if (pstRDSData->RDSFlag.Compressed != DI_Flag) { + pstRDSData->RDSFlag.Compressed = DI_Flag; + ret = rds_event_set(event, RDS_EVENT_FLAGS); + ret = rds_flag_set(flag, RDS_FLAG_IS_COMPRESSED); + } + + break; + case 0: + + if (pstRDSData->RDSFlag.Dynamic_PTY != DI_Flag) { + pstRDSData->RDSFlag.Dynamic_PTY = DI_Flag; + ret = rds_event_set(event, RDS_EVENT_FLAGS); + ret = rds_flag_set(flag, RDS_FLAG_IS_DYNAMIC_PTY); + } + + break; + default: + break; + } + + return ret; +} + +static signed int rds_retrieve_g0_ps(unsigned short *block_data, unsigned char SubType, struct rds_t *pstRDSData) +{ + unsigned char ps_addr; + signed int ret = 0, i, num; + bool valid = false; +/* signed int pos = 0; */ + static struct fm_state_machine ps_sm = { + .state = RDS_PS_START, + .state_get = fm_state_get, + .state_set = fm_state_set, + }; +#if 0 + static struct rds_bitmap ps_bm = { + .bm = 0, + .cnt = 0, + .max_addr = 0x03, + .bm_get = rds_bm_get, + .bm_cnt_get = rds_bm_cnt_get, + .bm_set = rds_bm_set, + .bm_get_pos = rds_bm_get_pos, + .bm_clr = rds_bm_clr, + .bm_cmp = rds_bm_cmp, + }; +#endif + unsigned short *event = &pstRDSData->event_status; + + /* parsing Program service name segment (in BlockD) */ + ret = rds_checksum_check(block_data[4], FM_RDS_GDBK_IND_D, &valid); + + if (valid == false) { + WCN_DBG(FM_WAR | RDSC, "Group0 BlockD crc err\n"); + return -FM_ECRC; + } + + rds_g0_ps_addr_get(block_data[1], &ps_addr); + + /* PS parsing state machine run */ + while (1) { + switch (STATE_GET(&ps_sm)) { + case RDS_PS_START: + if (rds_g0_ps_get(block_data[4], block_data[3], ps_addr, pstRDSData->PS_Data.PS[0])) { + STATE_SET(&ps_sm, RDS_PS_FINISH); /* if CRC error, we should not do parsing */ + break; + } + + rds_g0_ps_cmp(ps_addr, block_data[5], pstRDSData->PS_Data.PS[0], + pstRDSData->PS_Data.PS[1], pstRDSData->PS_Data.PS[2], + /*&valid, */ &pstRDSData->PS_Data.Addr_Cnt); + + /* if (valid == true) { */ + /* ps_bm.bm_set(&ps_bm, ps_addr); */ + /* } */ + + STATE_SET(&ps_sm, RDS_PS_DECISION); + break; + case RDS_PS_DECISION: + + if (pstRDSData->PS_Data.Addr_Cnt == 0x000F) { /* get max 8 chars */ + STATE_SET(&ps_sm, RDS_PS_GETLEN); + } else { + STATE_SET(&ps_sm, RDS_PS_FINISH); + } + + break; + case RDS_PS_GETLEN: + { + num = 0; + WCN_DBG(FM_INF | RDSC, "PS[3]=%x %x %x %x %x %x %x %x\n", + pstRDSData->PS_Data.PS[3][0], + pstRDSData->PS_Data.PS[3][1], + pstRDSData->PS_Data.PS[3][2], + pstRDSData->PS_Data.PS[3][3], + pstRDSData->PS_Data.PS[3][4], + pstRDSData->PS_Data.PS[3][5], + pstRDSData->PS_Data.PS[3][6], pstRDSData->PS_Data.PS[3][7]); + for (i = 0; i < 8; i++) { /* compare with last PS. */ + if (pstRDSData->PS_Data.PS[3][i] == pstRDSData->PS_Data.PS[2][i]) + num++; + } + if (num != 8) { + num = 0; + for (i = 0; i < 8; i++) { + /* even ps=0x20 and bitmap=0xF, send event to host to cover last ps. */ + if (pstRDSData->PS_Data.PS[2][i] == 0x0) + num++; + } + if (num != 8) { + fm_memcpy(pstRDSData->PS_Data.PS[3], pstRDSData->PS_Data.PS[2], 8); + rds_event_set(event, RDS_EVENT_PROGRAMNAME); + WCN_DBG(FM_NTC | RDSC, "Yes, get an PS!\n"); + } else { + /* clear bitmap */ + pstRDSData->PS_Data.Addr_Cnt = 0; + } + } else { + /* if px3==ps2,clear bitmap */ + pstRDSData->PS_Data.Addr_Cnt = 0; + /* clear buf */ + fm_memset(pstRDSData->PS_Data.PS[0], 0x00, 8); + fm_memset(pstRDSData->PS_Data.PS[1], 0x00, 8); + fm_memset(pstRDSData->PS_Data.PS[2], 0x00, 8); + } + } +#if 0 + ps_bm.bm_clr(&ps_bm); + /* clear buf */ + fm_memset(pstRDSData->PS_Data.PS[0], 0x20, 8); + fm_memset(pstRDSData->PS_Data.PS[1], 0x20, 8); + fm_memset(pstRDSData->PS_Data.PS[2], 0x20, 8); +#endif + STATE_SET(&ps_sm, RDS_PS_FINISH); + break; + case RDS_PS_FINISH: + STATE_SET(&ps_sm, RDS_PS_START); + goto out; + default: + break; + } + } + +out: + return ret; +} + +static signed int rds_retrieve_g0(unsigned short *block_data, unsigned char SubType, struct rds_t *pstRDSData) +{ + signed int ret = 0; + + ret = rds_retrieve_g0_af(block_data, SubType, pstRDSData); + + if (ret) + return ret; + + ret = rds_retrieve_g0_di(block_data, SubType, pstRDSData); + + if (ret) + return ret; + + ret = rds_retrieve_g0_ps(block_data, SubType, pstRDSData); + + if (ret) + return ret; + + return ret; +} + +static signed int rds_ecc_get(unsigned short blk, unsigned char *ecc, bool *dirty) +{ + signed int ret = 0; + + if (ecc == NULL) { + pr_err("%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (dirty == NULL) { + pr_err("%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (*ecc != (blk & 0xFF)) { + *ecc = (unsigned char)blk & 0xFF; + *dirty = true; /* yes, we got new ecc code */ + } else { + *dirty = false; /* ecc is the same as last one */ + } + + WCN_DBG(FM_NTC | RDSC, "ecc=%02x, %s\n", *ecc, *dirty ? "new" : "old"); + return ret; +} + +static signed int rds_retrieve_g1(unsigned short *block_data, unsigned char SubType, struct rds_t *pstRDSData) +{ + unsigned char variant_code = (block_data[2] & 0x7000) >> 12; + signed int ret = 0; + bool dirty = false; + + if (variant_code == 0) { + ret = rds_ecc_get(block_data[2], &pstRDSData->Extend_Country_Code, &dirty); + if (!ret) { + if (dirty == true) + rds_event_set(&pstRDSData->event_status, RDS_EVENT_ECC_CODE); + } else + WCN_DBG(FM_ERR | RDSC, "get ecc fail(%d)\n", ret); + WCN_DBG(FM_DBG | RDSC, "Extend_Country_Code:%d\n", pstRDSData->Extend_Country_Code); + } else if (variant_code == 3) { + pstRDSData->Language_Code = block_data[2] & 0xFFF; + WCN_DBG(FM_DBG | RDSC, "Language_Code:%d\n", pstRDSData->Language_Code); + } + + pstRDSData->Radio_Page_Code = block_data[1] & 0x001F; + pstRDSData->Program_Item_Number_Code = block_data[3]; + + return ret; +} + +static signed int rds_retrieve_g2(unsigned short *source, unsigned char subtype, struct rds_t *target) +{ + signed int ret = 0; + unsigned short crc, cbc; + unsigned short blkA, blkB, blkC, blkD; + unsigned char *fresh, *once, *twice, *display; + unsigned short *event; + unsigned int *flag; + unsigned short i = 0; + static struct fm_state_machine rt_sm = { + .state = RDS_RT_START, + .state_get = fm_state_get, + .state_set = fm_state_set, + }; + static struct rds_bitmap rt_bm = { + .bm = 0, + .cnt = 0, + .max_addr = 0xF, + .bm_get = rds_bm_get, + .bm_cnt_get = rds_bm_cnt_get, + .bm_set = rds_bm_set, + .bm_get_pos = rds_bm_get_pos, + .bm_clr = rds_bm_clr, + .bm_cmp = rds_bm_cmp, + }; + unsigned char rt_addr = 0; + bool txtAB_change = false; /* text AB flag 0 --> 1 or 1-->0 meas new RT incoming */ + bool txt_end = false; /* 0x0D means text end */ + bool seg_ok = 0; + signed int pos = 0; + signed int rt_len = 0, indx = 0, invalid_cnt = 0; + signed int bufsize = 0; + + if (source == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (target == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + /* source */ + blkA = source[0]; + blkB = source[1]; + blkC = source[2]; + blkD = source[3]; + crc = source[4]; + cbc = source[5]; + /* target */ + fresh = target->RT_Data.TextData[0]; + once = target->RT_Data.TextData[1]; + twice = target->RT_Data.TextData[2]; + display = target->RT_Data.TextData[3]; + event = &target->event_status; + flag = &target->RDSFlag.flag_status; + bufsize = sizeof(target->RT_Data.TextData[0]); + rt_bm.bm = target->RT_Data.Addr_Cnt; + + /* get basic info: addr, txtAB */ + if (rds_g2_rt_addr_get(blkB, &rt_addr)) + return ret; + + if (rds_g2_txtAB_get(blkB, &target->RDSFlag.Text_AB, &txtAB_change)) + return ret; + if (txtAB_change == true) { + /* clear buf */ + fm_memset(fresh, 0x20, bufsize); + fm_memset(once, 0x20, bufsize); + fm_memset(twice, 0x20, bufsize); + rt_bm.bm_clr(&rt_bm); + } + /* RT parsing state machine run */ + while (1) { + switch (STATE_GET(&rt_sm)) { + case RDS_RT_START: + { +#if 0 + if (txtAB_change == true) + STATE_SET(&rt_sm, RDS_RT_DECISION); + else +#endif + { + if (rds_g2_rt_get(crc, subtype, blkC, blkD, rt_addr, fresh) == 0) { + rds_g2_rt_cmp(rt_addr, cbc, subtype, fresh, once, twice, &seg_ok); + + if (seg_ok == true) + rt_bm.bm_set(&rt_bm, rt_addr); + else + rt_bm.bm &= ~(1 << rt_addr); + } + WCN_DBG(FM_NTC | RDSC, "bitmap=0x%04x, bmcnt=%d\n", rt_bm.bm, rt_bm.cnt); + rds_g2_rt_check_end(rt_addr, subtype, twice, &txt_end); + + STATE_SET(&rt_sm, RDS_RT_DECISION); + } + break; + } + case RDS_RT_DECISION: + { + if ((txt_end == true) || (rt_bm.bm_get(&rt_bm) == 0xFFFF) /* get max 64 chars */ + || (rt_bm.bm_cnt_get(&rt_bm) > RDS_RT_MULTI_REV_TH)) { + /* repeate many times, but no end char get */ + pos = rt_bm.bm_get_pos(&rt_bm); + rds_g2_rt_get_len(subtype, pos, &rt_len); + + if (pos == -1) { + STATE_SET(&rt_sm, RDS_RT_FINISH); + } else { + if (rt_addr == pos) { + STATE_SET(&rt_sm, RDS_RT_GETLEN); + } else if (pos > rt_addr) { + rt_bm.bm &= ~(1 << (rt_addr + 1)); + STATE_SET(&rt_sm, RDS_RT_FINISH); + } else + STATE_SET(&rt_sm, RDS_RT_FINISH); + } + + if (txt_end == true) { + for (i = rt_addr + 1; i < rt_bm.max_addr; i++) + rt_bm.bm &= ~(1 << i); + } + } else { + STATE_SET(&rt_sm, RDS_RT_FINISH); + } + + break; + } + case RDS_RT_GETLEN: + if (rt_len > 0) { + for (indx = 0; indx < rt_len; indx++) { + if (twice[indx] == 0x20) + invalid_cnt++; + } + if (invalid_cnt != rt_len) { + if (memcmp(display, twice, bufsize) != 0) { + fm_memcpy(display, twice, bufsize); + target->RT_Data.TextLength = rt_len; + rds_event_set(event, RDS_EVENT_LAST_RADIOTEXT); + /* yes we got a new RT */ + WCN_DBG(FM_NTC | RDSC, "Yes, get an RT! [len=%d]\n", rt_len); + } + rt_bm.bm_clr(&rt_bm); + /* clear buf */ + fm_memset(fresh, 0x20, bufsize); + fm_memset(once, 0x20, bufsize); + fm_memset(twice, 0x20, bufsize); + } else + WCN_DBG(FM_NTC | RDSC, "Get 0x20 RT %d\n", invalid_cnt); + } +#if 0 + if (txtAB_change == true) { + txtAB_change = false; + /* we need get new RT after show the old RT to the display */ + STATE_SET(&rt_sm, RDS_RT_START); + } else +#endif + { + STATE_SET(&rt_sm, RDS_RT_FINISH); + } + break; + case RDS_RT_FINISH: + STATE_SET(&rt_sm, RDS_RT_START); + goto out; + default: + break; + } + } + +out: + target->RT_Data.Addr_Cnt = rt_bm.bm; + return ret; +} + +static signed int rds_retrieve_g4(unsigned short *block_data, unsigned char SubType, struct rds_t *pstRDSData) +{ + unsigned short year, month, k = 0, D2, minute; + unsigned int MJD, D1; + signed int ret = 0; + + WCN_DBG(FM_DBG | RDSC, "RetrieveGroup4 %d\n", SubType); + + if (!SubType) { + /* Type A */ + if ((block_data[4] & FM_RDS_GDBK_IND_C) && (block_data[4] & FM_RDS_GDBK_IND_D)) { + MJD = (unsigned int) (((block_data[1] & 0x0003) << 15) + ((block_data[2] & 0xFFFE) >> 1)); + year = (MJD * 100 - 1507820) / 36525; + + if (year > 1000) { + WCN_DBG(FM_DBG | RDSC, "Abnormal year: %d.\n", year); + return ret; + } + + month = (MJD * 10000 - 149561000 - 3652500 * year) / 306001; + + if ((month == 14) || (month == 15)) + k = 1; + + D1 = (unsigned int) ((36525 * year) / 100); + D2 = (unsigned short) ((306001 * month) / 10000); + pstRDSData->CT.Year = 1900 + year + k; + pstRDSData->CT.Month = month - 1 - k * 12; + pstRDSData->CT.Day = (unsigned short) (MJD - 14956 - D1 - D2); + pstRDSData->CT.Hour = ((block_data[2] & 0x0001) << 4) + ((block_data[3] & 0xF000) >> 12); + minute = (block_data[3] & 0x0FC0) >> 6; + + if (block_data[3] & 0x0020) + pstRDSData->CT.Local_Time_offset_signbit = 1; /* 0=+, 1=- */ + + pstRDSData->CT.Local_Time_offset_half_hour = block_data[3] & 0x001F; + + if (pstRDSData->CT.Minute != minute) { + pstRDSData->CT.Minute = (block_data[3] & 0x0FC0) >> 6; + pstRDSData->event_status |= RDS_EVENT_UTCDATETIME; + } + } + } + + return ret; +} + +static signed int rds_retrieve_g14(unsigned short *block_data, unsigned char SubType, struct rds_t *pstRDSData) +{ + static signed short preAFON_Num; + unsigned char TP_ON, TA_ON, PI_ON, PS_Num, AF_H, AF_L, indx, indx2, num; + signed int ret = 0; + + WCN_DBG(FM_DBG | RDSC, "RetrieveGroup14 %d\n", SubType); + /* SubType = (*(block_data+1)&0x0800)>>11; */ + PI_ON = block_data[3]; + TP_ON = block_data[1] & 0x0010; + + if ((!SubType) && (block_data[4] & FM_RDS_GDBK_IND_C)) { + /* Type A */ + PS_Num = block_data[1] & 0x000F; /* variant code */ + + if (PS_Num < 4) { /* variant code = 0~3 represent PS */ + for (indx = 0; indx < 2; indx++) { + pstRDSData->PS_ON[2 * PS_Num] = block_data[2] >> 8; + pstRDSData->PS_ON[2 * PS_Num + 1] = block_data[2] & 0xFF; + } + + goto out; + } else if (PS_Num > 4) /* variant code > 4 */ + goto out; + + /* variant code = 4 represent AF(ON) */ + + AF_H = (block_data[2] & 0xFF00) >> 8; + AF_L = block_data[2] & 0x00FF; + + if ((AF_H > 224) && (AF_H < 250)) { + /* Followed AF Number */ + pstRDSData->AFON_Data.isAFNum_Get = 0; + preAFON_Num = AF_H - 224; + + if (pstRDSData->AFON_Data.AF_Num != preAFON_Num) + pstRDSData->AFON_Data.AF_Num = preAFON_Num; + else + pstRDSData->AFON_Data.isAFNum_Get = 1; + + if (AF_L < 205) { + pstRDSData->AFON_Data.AF[0][0] = AF_L + 875; + + if ((pstRDSData->AFON_Data.AF[0][0]) != (pstRDSData->AFON_Data.AF[1][0])) + pstRDSData->AFON_Data.AF[1][0] = pstRDSData->AFON_Data.AF[0][0]; + else + pstRDSData->AFON_Data.isMethod_A = 1; + } + + goto out; + } + + if (!(pstRDSData->AFON_Data.isAFNum_Get) || ((pstRDSData->AFON_Data.Addr_Cnt) == 0xFF)) + goto out; + + /* AF Num correct */ + num = pstRDSData->AFON_Data.AF_Num; + num = (num > 25) ? 25 : num; + num = num >> 1; + + /* Put AF freq into buffer and check if AF freq is repeat again */ + for (indx = 1; indx < (num + 1); indx++) { + if ((AF_H == (pstRDSData->AFON_Data.AF[0][2 * indx - 1])) + && (AF_L == (pstRDSData->AFON_Data.AF[0][2 * indx]))) { + WCN_DBG(FM_NTC | RDSC, "RetrieveGroup14 AFON same as indx:%d\n", indx); + break; + } else if (!(pstRDSData->AFON_Data.AF[0][2 * indx - 1])) { + /* null buffer */ + pstRDSData->AFON_Data.AF[0][2 * indx - 1] = AF_H + 875; + pstRDSData->AFON_Data.AF[0][2 * indx] = AF_L + 875; + break; + } + } + + num = pstRDSData->AFON_Data.AF_Num; + num = (num > 25) ? 25 : num; + if (num <= 0) + goto out; + + if ((pstRDSData->AFON_Data.AF[0][num - 1]) == 0) + goto out; + + num = num >> 1; + /* arrange frequency from low to high:start */ + for (indx = 1; indx < num; indx++) { + for (indx2 = indx + 1; indx2 < (num + 1); indx2++) { + AF_H = pstRDSData->AFON_Data.AF[0][2 * indx - 1]; + AF_L = pstRDSData->AFON_Data.AF[0][2 * indx]; + + if (AF_H > (pstRDSData->AFON_Data.AF[0][2 * indx2 - 1])) { + pstRDSData->AFON_Data.AF[0][2 * indx - 1] = + pstRDSData->AFON_Data.AF[0][2 * indx2 - 1]; + pstRDSData->AFON_Data.AF[0][2 * indx] = + pstRDSData->AFON_Data.AF[0][2 * indx2]; + pstRDSData->AFON_Data.AF[0][2 * indx2 - 1] = + AF_H; + pstRDSData->AFON_Data.AF[0][2 * indx2] = AF_L; + } else if (AF_H == (pstRDSData->AFON_Data.AF[0][2 * indx2 - 1])) { + if (AF_L > (pstRDSData->AFON_Data.AF[0][2 * indx2])) { + pstRDSData->AFON_Data.AF[0][2 * indx - 1] = + pstRDSData->AFON_Data.AF[0][2 * indx2 - 1]; + pstRDSData->AFON_Data.AF[0][2 * indx] = + pstRDSData->AFON_Data.AF[0][2 * indx2]; + pstRDSData->AFON_Data.AF[0][2 * indx2 - 1] = AF_H; + pstRDSData->AFON_Data.AF[0][2 * indx2] = AF_L; + } + } + } + } + + /* arrange frequency from low to high:end */ + /* compare AF buff0 and buff1 data:start */ + num = pstRDSData->AFON_Data.AF_Num; + num = (num > 25) ? 25 : num; + indx2 = 0; + + for (indx = 0; indx < num; indx++) { + if ((pstRDSData->AFON_Data.AF[1][indx]) == (pstRDSData->AFON_Data.AF[0][indx])) { + if (pstRDSData->AFON_Data.AF[1][indx] != 0) + indx2++; + } else + pstRDSData->AFON_Data.AF[1][indx] = pstRDSData->AFON_Data.AF[0][indx]; + } + + /* compare AF buff0 and buff1 data:end */ + if (indx2 == num) { + pstRDSData->AFON_Data.Addr_Cnt = 0xFF; + pstRDSData->event_status |= RDS_EVENT_AFON_LIST; + + for (indx = 0; indx < num; indx++) { + if ((pstRDSData->AFON_Data.AF[1][indx]) == 0) { + pstRDSData->AFON_Data.Addr_Cnt = 0x0F; + pstRDSData->event_status &= (~RDS_EVENT_AFON_LIST); + } + } + } else + pstRDSData->AFON_Data.Addr_Cnt = 0x0F; + } else { + /* Type B */ + TA_ON = block_data[1] & 0x0008; + WCN_DBG(FM_DBG | RDSC, + "TA g14 typeB pstRDSData->RDSFlag.TP=%d pstRDSData->RDSFlag.TA=%d TP_ON=%d TA_ON=%d\n", + pstRDSData->RDSFlag.TP, pstRDSData->RDSFlag.TA, TP_ON, TA_ON); + + if ((!pstRDSData->RDSFlag.TP) && (pstRDSData->RDSFlag.TA) && TP_ON && TA_ON) { + signed int TA_num = 0; + + for (num = 0; num < 25; num++) { + if (pstRDSData->AFON_Data.AF[1][num] != 0) + TA_num++; + else + break; + } + + WCN_DBG(FM_NTC | RDSC, "TA set RDS_EVENT_TAON"); + + if (TA_num == pstRDSData->AFON_Data.AF_Num) + pstRDSData->event_status |= RDS_EVENT_TAON; + } + } + +out: return ret; +} + +/* + * rds_parser + * Block0: PI code(16bits) + * Block1: Group type(4bits), B0=version code(1bit), TP=traffic program code(1bit), + * PTY=program type code(5bits), other(5bits) + * Block2: 16bits + * Block3: 16bits + * @rds_dst - target buffer that record RDS parsing result + * @rds_raw - rds raw data + * @rds_size - size of rds raw data + * @getfreq - function pointer, AF need get current freq + */ +signed int rds_parser(struct rds_t *rds_dst, struct rds_rx_t *rds_raw, + signed int rds_size, unsigned short(*getfreq) (void)) +{ + signed int ret = 0; + /* block_data[0] = blockA, block_data[1] = blockB, block_data[2] = blockC, block_data[3] = blockD, */ + /* block_data[4] = CRC, block_data[5] = CBC */ + unsigned short block_data[6]; + unsigned char GroupType, SubType = 0; + signed int rds_cnt = 0; + signed int i = 0; + bool dirty = false; + /* target buf to fill the result in */ + unsigned short *event = &rds_dst->event_status; + unsigned int *flag = &rds_dst->RDSFlag.flag_status; + + if (getfreq == NULL) { + WCN_DBG(FM_ERR | RDSC, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + rds_get_freq = getfreq; + + ret = rds_cnt_get(rds_raw, rds_size, &rds_cnt); + + if (ret) { + WCN_DBG(FM_WAR | RDSC, "get cnt err[ret=%d]\n", ret); + return ret; + } + + while (rds_cnt > 0) { + ret = rds_grp_get(&block_data[0], rds_raw, i); + + if (ret) { + WCN_DBG(FM_WAR | RDSC, "get group err[ret=%d]\n", ret); + goto do_next; + } + + ret = rds_grp_type_get(block_data[4], block_data[1], &GroupType, &SubType); + + if (ret) { + WCN_DBG(FM_WAR | RDSC, "get group type err[ret=%d]\n", ret); + goto do_next; + } + + ret = rds_grp_counter_add(GroupType, SubType, &rds_dst->gc); + + ret = rds_grp_pi_get(block_data[4], block_data[0], &rds_dst->PI, &dirty); + + if (ret) { + WCN_DBG(FM_WAR | RDSC, "get group pi err[ret=%d]\n", ret); + goto do_next; + } else if (dirty == false) { + WCN_DBG(FM_INF | RDSC, "dirty = %d, update PI event\n", dirty); + ret = rds_event_set(event, RDS_EVENT_PI_CODE); /* yes, we got same PI, can be trust */ + } + + ret = rds_grp_pty_get(block_data[4], block_data[1], &rds_dst->PTY, &dirty); + + if (ret) { + WCN_DBG(FM_WAR | RDSC, "get group pty err[ret=%d]\n", ret); + goto do_next; + } else if (dirty == true) { + ret = rds_event_set(event, RDS_EVENT_PTY_CODE); /* yes, we got new PTY code */ + } + + ret = rds_grp_tp_get(block_data[4], block_data[1], &rds_dst->RDSFlag.TP, &dirty); + + if (ret) { + WCN_DBG(FM_WAR | RDSC, "get group tp err[ret=%d]\n", ret); + goto do_next; + } else if (dirty == true) { + ret = rds_event_set(event, RDS_EVENT_FLAGS); /* yes, we got new TP code */ + ret = rds_flag_set(flag, RDS_FLAG_IS_TP); + } + + switch (GroupType) { + case 0: + ret = rds_retrieve_g0(&block_data[0], SubType, rds_dst); + if (ret) + goto do_next; + + break; + case 1: + ret = rds_retrieve_g1(&block_data[0], SubType, rds_dst); + if (ret) + goto do_next; + + break; + case 2: + ret = rds_retrieve_g2(&block_data[0], SubType, rds_dst); + if (ret) + goto do_next; + + break; + case 4: + ret = rds_retrieve_g4(&block_data[0], SubType, rds_dst); + if (ret) + goto do_next; + + break; + case 14: + ret = rds_retrieve_g14(&block_data[0], SubType, rds_dst); + if (ret) + goto do_next; + + break; + default: + break; + } + +do_next: + + if (ret && (ret != -FM_ECRC)) { + WCN_DBG(FM_ERR | RDSC, "parsing err[ret=%d]\n", ret); + return ret; + } + + rds_cnt--; + i++; + } + + return ret; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/core/fm_reg_utils.c b/drivers/misc/mediatek/connectivity/fmradio/core/fm_reg_utils.c new file mode 100644 index 00000000000000..76064d26ee92e3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/core/fm_reg_utils.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2019 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_stdlib.h" +#include "fm_link.h" +#include "fm_utils.h" +#include "fm_reg_utils.h" +#include "plat.h" + +struct fm_wcn_reg_ops fm_wcn_ops; + +int fm_ioremap_read(phys_addr_t addr, unsigned int *val) +{ + unsigned int size = 0x10; + void *vir_addr = NULL; + + request_mem_region(addr, size, "FM_TEMP_READ"); + vir_addr = ioremap(addr, size); + if (!vir_addr) { + WCN_DBG(FM_ERR | CHIP, "Cannot remap address.\n"); + return -1; + } + + *val = readl(vir_addr); + iounmap(vir_addr); + release_mem_region(addr, size); + + WCN_DBG(FM_NTC | CHIP, "Read 0x%08lx=0x%08x", + (unsigned long)addr, *val); + + return 0; +} + +int fm_ioremap_write(phys_addr_t addr, unsigned int val) +{ + unsigned int size = 0x10; + void *vir_addr = NULL; + + request_mem_region(addr, size, "FM_TEMP_WRITE"); + vir_addr = ioremap(addr, size); + if (!vir_addr) { + WCN_DBG(FM_ERR | CHIP, "Cannot remap address.\n"); + return -1; + } + + writel(val, vir_addr); + iounmap(vir_addr); + release_mem_region(addr, size); + + WCN_DBG(FM_NTC | CHIP, "Write 0x%08lx=0x%08x", + (unsigned long)addr, val); + + return 0; +} + +void fw_spi_read(unsigned char addr, unsigned short *data) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + int ret = 0; + unsigned int rdata; + + ret = si->sys_spi_read(si, SYS_SPI_FM, addr, &rdata); + if (ret) + WCN_DBG(FM_ERR | CHIP, "read error[%d].\n", ret); + *data = (unsigned short)rdata; +} + +void fw_spi_write(unsigned char addr, unsigned short data) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + int ret = 0; + unsigned int wdata = (unsigned int)data; + + ret = si->sys_spi_write(si, SYS_SPI_FM, addr, wdata); + if (ret) + WCN_DBG(FM_ERR | CHIP, "write error[%d].\n", ret); +} + +void fw_bop_udelay(unsigned int usec) +{ + fm_delayus(usec); +} + +void fw_bop_rd_until(unsigned char addr, unsigned short mask, + unsigned short value) +{ + unsigned short data, count = 0; + + do { + fm_delayus(1000); + fw_spi_read(addr, &data); + count++; + } while (((data & mask) != value) && (count < 3000)); + + /* 3000ms should be big enough for polling bits */ + if (count == 3000) + WCN_DBG(FM_WAR | CHIP, "Value is never changed.\n"); +} + +void fw_bop_modify(unsigned char addr, unsigned short mask_and, + unsigned short mask_or) +{ + unsigned short data; + + fw_spi_read(addr, &data); + data &= mask_and; + data |= mask_or; + fw_spi_write(addr, data); +} + +void fw_bop_spi_rd_until(unsigned char subsys, unsigned short addr, + unsigned int mask, unsigned int value) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + unsigned int data; + unsigned short count = 0; + + do { + fm_delayus(1000); + si->sys_spi_read(si, subsys, addr, &data); + count++; + } while (((data & mask) != value) && (count < 3000)); + + /* 3000ms should be big enough for polling bits */ + if (count == 3000) + WCN_DBG(FM_WAR | CHIP, "Value is never changed.\n"); +} + +void fw_bop_spi_modify(unsigned char subsys, unsigned short addr, + unsigned int mask_and, unsigned int mask_or) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + unsigned int data; + + si->sys_spi_read(si, subsys, addr, &data); + data &= mask_and; + data |= mask_or; + si->sys_spi_write(si, subsys, addr, data); +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/core/fm_utils.c b/drivers/misc/mediatek/connectivity/fmradio/core/fm_utils.c new file mode 100644 index 00000000000000..cdefaddb2e8f11 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/core/fm_utils.c @@ -0,0 +1,800 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/version.h> +#include <linux/interrupt.h> +#include <linux/wait.h> +#include <linux/uaccess.h> +#include <linux/semaphore.h> +#include <linux/timer.h> +#include <linux/delay.h> + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_stdlib.h" +#include "fm_utils.h" + +signed int fm_delayms(unsigned int data) +{ + WCN_DBG(FM_DBG | CHIP, "delay %dms\n", data); + msleep(data); + return 0; +} + +signed int fm_delayus(unsigned int data) +{ + WCN_DBG(FM_DBG | CHIP, "delay %dus\n", data); + udelay(data); + return 0; +} + +static unsigned int fm_event_send(struct fm_flag_event *thiz, unsigned int mask) +{ + thiz->flag |= mask; + /* WCN_DBG(FM_DBG|MAIN, "%s set 0x%08x\n", thiz->name, thiz->flag); */ + wake_up((wait_queue_head_t *) (thiz->priv)); + + return thiz->flag; +} + +static signed int fm_event_wait(struct fm_flag_event *thiz, unsigned int mask) +{ + return wait_event_interruptible(*(wait_queue_head_t *) (thiz->priv), ((thiz->flag & mask) == mask)); +} + +/** + * fm_event_check - sleep until a condition gets true or a timeout elapses + * @thiz: the pointer of current object + * @mask: bitmap in unsigned int + * @timeout: timeout, in jiffies + * + * fm_event_set() has to be called after changing any variable that could + * change the result of the wait condition. + * + * The function returns 0 if the @timeout elapsed, and the remaining + * jiffies if the condition evaluated to true before the timeout elapsed. + */ +long fm_event_wait_timeout(struct fm_flag_event *thiz, unsigned int mask, long timeout) +{ + return wait_event_timeout(*((wait_queue_head_t *) (thiz->priv)), ((thiz->flag & mask) == mask), timeout * HZ); +} + +static unsigned int fm_event_clr(struct fm_flag_event *thiz, unsigned int mask) +{ + thiz->flag &= ~mask; + /* WCN_DBG(FM_DBG|MAIN, "%s clr 0x%08x\n", thiz->name, thiz->flag); */ + return thiz->flag; +} + +static unsigned int fm_event_get(struct fm_flag_event *thiz) +{ + return thiz->flag; + +} + +static unsigned int fm_event_rst(struct fm_flag_event *thiz) +{ + return thiz->flag = 0; +} + +struct fm_flag_event *fm_flag_event_create(const signed char *name) +{ + struct fm_flag_event *tmp; + wait_queue_head_t *wq; + + tmp = fm_zalloc(sizeof(struct fm_flag_event)); + if (!tmp) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(fm_event) -ENOMEM\n"); + return NULL; + } + + wq = fm_zalloc(sizeof(wait_queue_head_t)); + if (!wq) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(wait_queue_head_t) -ENOMEM\n"); + fm_free(tmp); + return NULL; + } + + fm_memcpy(tmp->name, name, (strlen(name) > FM_NAME_MAX) ? (FM_NAME_MAX) : (strlen(name))); + tmp->priv = wq; + init_waitqueue_head(wq); + tmp->ref = 0; + + tmp->send = fm_event_send; + tmp->wait = fm_event_wait; + tmp->wait_timeout = fm_event_wait_timeout; + tmp->clr = fm_event_clr; + tmp->get = fm_event_get; + tmp->rst = fm_event_rst; + + tmp->rst(tmp); /* set flag to 0x00000000 */ + + return tmp; +} + +signed int fm_flag_event_get(struct fm_flag_event *thiz) +{ + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + thiz->ref++; + return 0; +} + +signed int fm_flag_event_put(struct fm_flag_event *thiz) +{ + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + thiz->ref--; + + if (thiz->ref == 0) { + fm_free(thiz->priv); + fm_free(thiz); + return 0; + } else if (thiz->ref > 0) { + return -FM_EINUSE; + } else { + return -FM_EPARA; + } +} + +/* fm lock methods */ +static signed int fm_lock_try(struct fm_lock *thiz, signed int retryCnt) +{ + signed int retry_cnt = 0; + struct semaphore *sem; + struct task_struct *task = current; + + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (thiz->priv == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + while (down_trylock((struct semaphore *)thiz->priv)) { + WCN_DBG(FM_WAR | MAIN, "down_trylock failed\n"); + if (++retry_cnt < retryCnt) { + WCN_DBG(FM_WAR | MAIN, "[retryCnt=%d]\n", retry_cnt); + msleep_interruptible(50); + continue; + } else { + WCN_DBG(FM_CRT | MAIN, "down_trylock retry failed\n"); + return -FM_ELOCK; + } + } + + sem = (struct semaphore *)thiz->priv; + WCN_DBG(FM_NTC | MAIN, "%s --->trylock, cnt=%d, pid=%d\n", thiz->name, (int)sem->count, task->pid); + return 0; +} + +/* fm try lock methods */ +static signed int fm_lock_lock(struct fm_lock *thiz) +{ + struct semaphore *sem; + struct task_struct *task = current; + + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (thiz->priv == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (down_interruptible((struct semaphore *)thiz->priv)) { + WCN_DBG(FM_CRT | MAIN, "get mutex failed\n"); + return -FM_ELOCK; + } + + sem = (struct semaphore *)thiz->priv; + WCN_DBG(FM_DBG | MAIN, "%s --->lock, cnt=%d, pid=%d\n", + thiz->name, (int)sem->count, task->pid); + return 0; +} + +static signed int fm_lock_unlock(struct fm_lock *thiz) +{ + struct semaphore *sem; + struct task_struct *task = current; + + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (thiz->priv == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + sem = (struct semaphore *)thiz->priv; + WCN_DBG(FM_DBG | MAIN, "%s <---unlock, cnt=%d, pid=%d\n", + thiz->name, (int)sem->count + 1, task->pid); + up((struct semaphore *)thiz->priv); + return 0; +} + +struct fm_lock *fm_lock_create(const signed char *name) +{ + struct fm_lock *tmp; + struct semaphore *mutex; + + tmp = fm_zalloc(sizeof(struct fm_lock)); + if (!tmp) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(fm_lock) -ENOMEM\n"); + return NULL; + } + + mutex = fm_zalloc(sizeof(struct semaphore)); + if (!mutex) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(struct semaphore) -ENOMEM\n"); + fm_free(tmp); + return NULL; + } + + tmp->priv = mutex; + sema_init(mutex, 1); + tmp->ref = 0; + fm_memcpy(tmp->name, name, (strlen(name) > FM_NAME_MAX) ? (FM_NAME_MAX) : (strlen(name))); + + tmp->lock = fm_lock_lock; + tmp->trylock = fm_lock_try; + tmp->unlock = fm_lock_unlock; + + return tmp; +} + +signed int fm_lock_get(struct fm_lock *thiz) +{ + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + thiz->ref++; + return 0; +} + +signed int fm_lock_put(struct fm_lock *thiz) +{ + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + thiz->ref--; + + if (thiz->ref == 0) { + fm_free(thiz->priv); + fm_free(thiz); + return 0; + } else if (thiz->ref > 0) { + return -FM_EINUSE; + } else { + return -FM_EPARA; + } +} + +/* fm lock methods */ +static signed int fm_spin_lock_lock(struct fm_lock *thiz) +{ + struct task_struct *task = current; + + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (thiz->priv == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + spin_lock_bh((spinlock_t *) thiz->priv); + + WCN_DBG(FM_DBG | MAIN, "%s --->lock pid=%d\n", thiz->name, task->pid); + return 0; +} + +static signed int fm_spin_lock_unlock(struct fm_lock *thiz) +{ + struct task_struct *task = current; + + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (thiz->priv == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + WCN_DBG(FM_DBG | MAIN, "%s <---unlock, pid=%d\n", thiz->name, task->pid); + spin_unlock_bh((spinlock_t *) thiz->priv); + return 0; +} + +struct fm_lock *fm_spin_lock_create(const signed char *name) +{ + struct fm_lock *tmp; + spinlock_t *spin_lock; + + tmp = fm_zalloc(sizeof(struct fm_lock)); + if (!tmp) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(fm_lock) -ENOMEM\n"); + return NULL; + } + + spin_lock = fm_zalloc(sizeof(spinlock_t)); + if (!spin_lock) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(spinlock_t) -ENOMEM\n"); + fm_free(tmp); + return NULL; + } + + tmp->priv = spin_lock; + spin_lock_init(spin_lock); + tmp->ref = 0; + fm_memcpy(tmp->name, name, (strlen(name) > FM_NAME_MAX) ? (FM_NAME_MAX) : (strlen(name))); + + tmp->lock = fm_spin_lock_lock; + tmp->unlock = fm_spin_lock_unlock; + + return tmp; +} + +signed int fm_spin_lock_get(struct fm_lock *thiz) +{ + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + thiz->ref++; + return 0; +} + +signed int fm_spin_lock_put(struct fm_lock *thiz) +{ + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + thiz->ref--; + + if (thiz->ref == 0) { + fm_free(thiz->priv); + fm_free(thiz); + return 0; + } else if (thiz->ref > 0) { + return -FM_EINUSE; + } else { + return -FM_EPARA; + } +} + +/* + * fm timer + * + */ +static signed int fm_timer_init(struct fm_timer *thiz, void (*timeout) (unsigned long data), + unsigned long data, signed long time, signed int flag) +{ + struct timer_list *timerlist = (struct timer_list *)thiz->priv; + + thiz->flag = flag; + thiz->flag &= ~FM_TIMER_FLAG_ACTIVATED; + thiz->timeout_func = timeout; + thiz->data = data; + thiz->timeout_ms = time; + + timerlist->expires = jiffies + (thiz->timeout_ms) / (1000 / HZ); + timerlist->function = thiz->timeout_func; + timerlist->data = (unsigned long)thiz->data; + + return 0; +} + +static signed int fm_timer_start(struct fm_timer *thiz) +{ + struct timer_list *timerlist = (struct timer_list *)thiz->priv; + + thiz->flag |= FM_TIMER_FLAG_ACTIVATED; + mod_timer(timerlist, jiffies + (thiz->timeout_ms) / (1000 / HZ)); + + return 0; +} + +static signed int fm_timer_update(struct fm_timer *thiz) +{ + struct timer_list *timerlist = (struct timer_list *)thiz->priv; + + if (thiz->flag & FM_TIMER_FLAG_ACTIVATED) { + mod_timer(timerlist, jiffies + (thiz->timeout_ms) / (1000 / HZ)); + return 0; + } else { + return 1; + } +} + +static signed int fm_timer_stop(struct fm_timer *thiz) +{ + struct timer_list *timerlist = (struct timer_list *)thiz->priv; + + thiz->flag &= ~FM_TIMER_FLAG_ACTIVATED; + del_timer(timerlist); + + return 0; +} + +static signed int fm_timer_control(struct fm_timer *thiz, enum fm_timer_ctrl cmd, void *arg) +{ + + return 0; +} + +struct fm_timer *fm_timer_create(const signed char *name) +{ + struct fm_timer *tmp; + struct timer_list *timerlist; + + tmp = fm_zalloc(sizeof(struct fm_timer)); + if (!tmp) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(fm_timer) -ENOMEM\n"); + return NULL; + } + + timerlist = fm_zalloc(sizeof(struct timer_list)); + if (!timerlist) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(struct timer_list) -ENOMEM\n"); + fm_free(tmp); + return NULL; + } + + init_timer(timerlist); + + fm_memcpy(tmp->name, name, (strlen(name) > FM_NAME_MAX) ? (FM_NAME_MAX) : (strlen(name))); + tmp->priv = timerlist; + tmp->ref = 0; + tmp->init = fm_timer_init; + tmp->start = fm_timer_start; + tmp->stop = fm_timer_stop; + tmp->update = fm_timer_update; + tmp->control = fm_timer_control; + + return tmp; +} + +signed int fm_timer_get(struct fm_timer *thiz) +{ + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + thiz->ref++; + return 0; +} + +signed int fm_timer_put(struct fm_timer *thiz) +{ + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + thiz->ref--; + + if (thiz->ref == 0) { + fm_free(thiz->priv); + fm_free(thiz); + return 0; + } else if (thiz->ref > 0) { + return -FM_EINUSE; + } else { + return -FM_EPARA; + } +} + +/* + * FM work thread mechanism + */ +static signed int fm_work_init(struct fm_work *thiz, void (*work_func) (unsigned long data), unsigned long data) +{ + struct work_struct *sys_work = (struct work_struct *)thiz->priv; + work_func_t func; + + thiz->work_func = work_func; + thiz->data = data; + func = (work_func_t) thiz->work_func; + + INIT_WORK(sys_work, func); + + return 0; + +} + +struct fm_work *fm_work_create(const signed char *name) +{ + struct fm_work *my_work; + struct work_struct *sys_work; + + my_work = fm_zalloc(sizeof(struct fm_work)); + if (!my_work) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(fm_work) -ENOMEM\n"); + return NULL; + } + + sys_work = fm_zalloc(sizeof(struct work_struct)); + if (!sys_work) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(struct work_struct) -ENOMEM\n"); + fm_free(my_work); + return NULL; + } + + fm_memcpy(my_work->name, name, (strlen(name) > FM_NAME_MAX) ? (FM_NAME_MAX) : (strlen(name))); + my_work->priv = sys_work; + my_work->init = fm_work_init; + + return my_work; +} + +signed int fm_work_get(struct fm_work *thiz) +{ + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + thiz->ref++; + return 0; +} + +signed int fm_work_put(struct fm_work *thiz) +{ + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + thiz->ref--; + + if (thiz->ref == 0) { + fm_free(thiz->priv); + fm_free(thiz); + return 0; + } else if (thiz->ref > 0) { + return -FM_EINUSE; + } else { + return -FM_EPARA; + } +} + +static signed int fm_workthread_add_work(struct fm_workthread *thiz, struct fm_work *work) +{ + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + if (work == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + queue_work((struct workqueue_struct *)thiz->priv, (struct work_struct *)work->priv); + return 0; +} + +struct fm_workthread *fm_workthread_create(const signed char *name) +{ + struct fm_workthread *my_thread; + struct workqueue_struct *sys_thread; + + my_thread = fm_zalloc(sizeof(struct fm_workthread)); + if (!my_thread) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(fm_workthread) -ENOMEM\n"); + return NULL; + } + + sys_thread = create_singlethread_workqueue(name); + + fm_memcpy(my_thread->name, name, (strlen(name) > FM_NAME_MAX) ? (FM_NAME_MAX) : (strlen(name))); + my_thread->priv = sys_thread; + my_thread->add_work = fm_workthread_add_work; + + return my_thread; +} + +signed int fm_workthread_get(struct fm_workthread *thiz) +{ + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + thiz->ref++; + return 0; +} + +signed int fm_workthread_put(struct fm_workthread *thiz) +{ + if (thiz == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + thiz->ref--; + + if (thiz->ref == 0) { + destroy_workqueue((struct workqueue_struct *)thiz->priv); + fm_free(thiz); + return 0; + } else if (thiz->ref > 0) { + return -FM_EINUSE; + } else { + return -FM_EPARA; + } +} + +signed int fm_fifo_in(struct fm_fifo *thiz, void *item) +{ + if (item == NULL) { + WCN_DBG(FM_ERR | MAIN, "%s,invalid pointer\n", __func__); + return -FM_EPARA; + } + + if (thiz->len < thiz->size) { + fm_memcpy((thiz->obj.priv + (thiz->item_size * thiz->in)), item, thiz->item_size); + thiz->in = (thiz->in + 1) % thiz->size; + thiz->len++; + /* WCN_DBG(FM_DBG | MAIN, "add a new item[len=%d]\n", thiz->len); */ + } else { + WCN_DBG(FM_WAR | MAIN, "%s fifo is full\n", thiz->obj.name); + return -FM_ENOMEM; + } + + return 0; +} + +signed int fm_fifo_out(struct fm_fifo *thiz, void *item) +{ + if (thiz->len > 0) { + if (item) { + fm_memcpy(item, (thiz->obj.priv + (thiz->item_size * thiz->out)), thiz->item_size); + fm_memset((thiz->obj.priv + (thiz->item_size * thiz->out)), 0, thiz->item_size); + } + thiz->out = (thiz->out + 1) % thiz->size; + thiz->len--; + /* WCN_DBG(FM_DBG | MAIN, "del an item[len=%d]\n", thiz->len); */ + } else { + WCN_DBG(FM_WAR | MAIN, "%s fifo is empty\n", thiz->obj.name); + } + + return 0; +} + +bool fm_fifo_is_full(struct fm_fifo *thiz) +{ + return (thiz->len == thiz->size) ? true : false; +} + +bool fm_fifo_is_empty(struct fm_fifo *thiz) +{ + return (thiz->len == 0) ? true : false; +} + +signed int fm_fifo_get_total_len(struct fm_fifo *thiz) +{ + return thiz->size; +} + +signed int fm_fifo_get_valid_len(struct fm_fifo *thiz) +{ + return thiz->len; +} + +signed int fm_fifo_reset(struct fm_fifo *thiz) +{ + fm_memset(thiz->obj.priv, 0, thiz->item_size * thiz->size); + thiz->in = 0; + thiz->out = 0; + thiz->len = 0; + + return 0; +} + +struct fm_fifo *fm_fifo_init(struct fm_fifo *fifo, void *buf, const signed char *name, signed int item_size, + signed int item_num) +{ + fm_memcpy(fifo->obj.name, name, 20); + fifo->size = item_num; + fifo->in = 0; + fifo->out = 0; + fifo->len = 0; + fifo->item_size = item_size; + fifo->obj.priv = buf; + + fifo->input = fm_fifo_in; + fifo->output = fm_fifo_out; + fifo->is_full = fm_fifo_is_full; + fifo->is_empty = fm_fifo_is_empty; + fifo->get_total_len = fm_fifo_get_total_len; + fifo->get_valid_len = fm_fifo_get_valid_len; + fifo->reset = fm_fifo_reset; + + WCN_DBG(FM_NTC | LINK, "%s inited\n", fifo->obj.name); + + return fifo; +} + +struct fm_fifo *fm_fifo_create(const signed char *name, signed int item_size, signed int item_num) +{ + struct fm_fifo *tmp; + void *buf; + + tmp = fm_zalloc(sizeof(struct fm_fifo)); + if (!tmp) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(fm_fifo) -ENOMEM\n"); + return NULL; + } + + buf = fm_zalloc(item_size * item_num); + if (!buf) { + WCN_DBG(FM_ALT | MAIN, "fm_zalloc(fm_fifo) -ENOMEM\n"); + fm_free(tmp); + return NULL; + } + + tmp = fm_fifo_init(tmp, buf, name, item_size, item_num); + + WCN_DBG(FM_NTC | LINK, "%s created\n", tmp->obj.name); + + return tmp; +} + +signed int fm_fifo_release(struct fm_fifo *fifo) +{ + if (fifo) { + WCN_DBG(FM_NTC | LINK, "%s released\n", fifo->obj.name); + if (fifo->obj.priv) + fm_free(fifo->obj.priv); + + fm_free(fifo); + } + + return 0; +} + +unsigned short fm_get_u16_from_auc(unsigned char *buf) +{ + return (unsigned short)((unsigned short)buf[0] + ((unsigned short) buf[1] << 8)); +} + +void fm_set_u16_to_auc(unsigned char *buf, unsigned short val) +{ + buf[0] = (unsigned char)(val & 0xFF); + buf[1] = (unsigned char)(val >> 8); +} + +unsigned int fm_get_u32_from_auc(unsigned char *buf) +{ + return ((unsigned int)(*buf) + ((unsigned int)(*(buf + 1)) << 8) + + ((unsigned int)(*(buf + 2)) << 16) + ((unsigned int)(*(buf + 3)) << 24)); +} + +void fm_set_u32_to_auc(unsigned char *buf, unsigned int val) +{ + buf[0] = (unsigned char)val; + buf[1] = (unsigned char)(val >> 8); + buf[2] = (unsigned char)(val >> 16); + buf[3] = (unsigned char)(val >> 24); +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/dummy.c b/drivers/misc/mediatek/connectivity/fmradio/dummy.c new file mode 100644 index 00000000000000..872b38b4a31a0a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/dummy.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* dummy.c + * This dummy file is just for meetting the build system's rule. + */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_cmd.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_cmd.h new file mode 100644 index 00000000000000..7ec1a881656819 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_cmd.h @@ -0,0 +1,96 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ + +#ifndef __FM_CMD_H__ +#define __FM_CMD_H__ + +#include <linux/types.h> +#include "fm_typedef.h" +#include "fm_patch.h" +#include "fm_link.h" +#include "fm_reg_utils.h" + +extern unsigned char *cmd_buf; +extern struct fm_lock *cmd_buf_lock; +extern struct fm_res_ctx *fm_res; +extern unsigned char top_index; + +#define PATCH_SEG_LEN 512 +enum IMG_TYPE { + IMG_WRONG = 0, + IMG_ROM, + IMG_PATCH, + IMG_COEFFICIENT, + IMG_HW_COEFFICIENT +}; + +/* FM BOP's size */ +#define FM_TOP_WRITE_BOP_SIZE (7) +#define FM_TOP_RD_UNTIL_BOP_SIZE (11) +#define FM_TOP_MODIFY_BOP_SIZE (11) + +#define FM_WRITE_BASIC_OP_SIZE (3) +#define FM_UDELAY_BASIC_OP_SIZE (4) +#define FM_RD_UNTIL_BASIC_OP_SIZE (5) +#define FM_MODIFY_BASIC_OP_SIZE (5) +#define FM_MSLEEP_BASIC_OP_SIZE (4) + +signed int fm_bop_write(unsigned char addr, unsigned short value, unsigned char *buf, signed int size); +signed int fm_bop_udelay(unsigned int value, unsigned char *buf, signed int size); +signed int fm_bop_rd_until(unsigned char addr, unsigned short mask, unsigned short value, unsigned char *buf, + signed int size); +signed int fm_bop_modify(unsigned char addr, unsigned short mask_and, unsigned short mask_or, unsigned char *buf, + signed int size); +signed int fm_bop_top_write(unsigned short addr, unsigned int value, unsigned char *buf, signed int size); +signed int fm_bop_top_rd_until(unsigned short addr, unsigned int mask, unsigned int value, unsigned char *buf, + signed int size); +signed int fm_op_seq_combine_cmd(unsigned char *buf, unsigned char opcode, signed int pkt_size); +signed int fm_get_reg(unsigned char *buf, signed int buf_size, unsigned char addr); +signed int fm_set_reg(unsigned char *buf, signed int buf_size, unsigned char addr, unsigned short value); +signed int fm_patch_download(unsigned char *buf, signed int buf_size, unsigned char seg_num, unsigned char seg_id, + const unsigned char *src, signed int seg_len); +signed int fm_coeff_download(unsigned char *buf, signed int buf_size, unsigned char seg_num, unsigned char seg_id, + const unsigned char *src, signed int seg_len); +signed int fm_full_cqi_req(unsigned char *buf, signed int buf_size, unsigned short *freq, signed int cnt, + signed int type); +signed int fm_top_get_reg(unsigned char *buf, signed int buf_size, unsigned short addr); +signed int fm_top_set_reg(unsigned char *buf, signed int buf_size, unsigned short addr, unsigned int value); +signed int fm_host_get_reg(unsigned char *buf, signed int buf_size, unsigned int addr); +signed int fm_host_set_reg(unsigned char *buf, signed int buf_size, unsigned int addr, unsigned int value); +signed int fm_set_bits_reg(unsigned char *buf, signed int buf_size, unsigned char addr, unsigned short bits, + unsigned short mask); +signed int fm_pmic_get_reg(unsigned char *buf, signed int buf_size, unsigned char addr); +signed int fm_pmic_set_reg(unsigned char *buf, signed int buf_size, unsigned char addr, unsigned int val); +signed int fm_pmic_mod_reg(unsigned char *buf, signed int buf_size, unsigned char addr, unsigned int mask_and, + unsigned int mask_or); +signed int fm_get_patch_path(signed int ver, unsigned char *buff, int buffsize, struct fm_patch_tbl *patch_tbl); +signed int fm_get_coeff_path(signed int ver, unsigned char *buff, int buffsize, struct fm_patch_tbl *patch_tbl); +signed int fm_download_patch(const unsigned char *img, signed int len, enum IMG_TYPE type); +signed int fm_get_read_result(struct fm_res_ctx *result); +signed int fm_reg_read(unsigned char addr, unsigned short *val); +signed int fm_reg_write(unsigned char addr, unsigned short val); +signed int fm_set_bits(unsigned char addr, unsigned short bits, unsigned short mask); +signed int fm_top_reg_read(unsigned short addr, unsigned int *val); +signed int fm_top_reg_write(unsigned short addr, unsigned int val); +signed int fm_host_reg_read(unsigned int addr, unsigned int *val); +signed int fm_host_reg_write(unsigned int addr, unsigned int val); + +/* + * fm_get_channel_space - get the spcace of gived channel + * @freq - value in 760~1080 or 7600~10800 + * + * Return 0, if 760~1080; return 1, if 7600 ~ 10800, else err code < 0 + */ +extern signed int fm_get_channel_space(int freq); + +#endif diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_config.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_config.h new file mode 100644 index 00000000000000..946de960ed3b49 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_config.h @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FM_CONFIG_H__ +#define __FM_CONFIG_H__ + +#include "fm_typedef.h" +#include "fm_rds.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_stdlib.h" +#include "fm_interface.h" +/* band */ +#define FM_BAND_UNKNOWN 0 +#define FM_BAND_UE 1 /* US/Europe band 87.5MHz ~ 108MHz (DEFAULT) */ +#define FM_BAND_JAPAN 2 /* Japan band 76MHz ~ 90MHz */ +#define FM_BAND_JAPANW 3 /* Japan wideband 76MHZ ~ 108MHz */ +#define FM_BAND_SPECIAL 4 /* special band between 76MHZ and 108MHz */ +#define FM_BAND_DEFAULT FM_BAND_UE +#define FM_RAIDO_BAND FM_BAND_UE +#define FM_FREQ_MIN FM_RX_BAND_FREQ_L +#define FM_FREQ_MAX FM_RX_BAND_FREQ_H + +#define FM_UE_FREQ_MIN 8750 +#define FM_UE_FREQ_MAX 10800 +#define FM_JP_FREQ_MIN 7600 +#define FM_JP_FREQ_MAX 10800 + +#define FM_RX_BAND_FREQ_L 8750 /* FM radio special band low freq(Default 87.5MHz) */ +#define FM_RX_BAND_FREQ_H 10800 /* FM radio special band high freq(Default 108.0MHz) */ +/* TX */ +#define FM_TX_SCAN_HOLE_LOW 9230 /* 92.3MHz~95.4MHz should not show to user */ +#define FM_TX_SCAN_HOLE_HIGH 9540 /* 92.3MHz~95.4MHz should not show to user */ + +/* space */ +#define FM_SPACE_UNKNOWN 0 +#define FM_SPACE_100K 1 +#define FM_SPACE_200K 2 +#define FM_SPACE_50K 5 + +#ifdef CONFIG_MTK_FM_50KHZ_SUPPORT +#define FM_SPACE_DEFAULT FM_SPACE_50K +#else +#define FM_SPACE_DEFAULT FM_SPACE_100K +#endif + +#define FM_INVALID_CHAN_NOISE_REDUCING 0 + +#define FM_TX_SCAN_UP (0) +#define FM_TX_SCAN_DOWN (1) +#define FM_TX_SCAN_MAX 10 +#define FM_TX_SCAN_MIN 1 + +/* seek direction */ +#define FM_SEEK_UP 0 +#define FM_SEEK_DOWN 1 + +/* ***************************************************************************************** */ +/* ***************************FM default config for customer: start************************* */ +/* ***************************************************************************************** */ + +/* RX */ +#define FM_RX_RSSI_TH_LONG -296 /* FM radio long antenna RSSI threshold(-4dBuV) */ +#define FM_RX_RSSI_TH_SHORT -296 /* FM radio short antenna RSSI threshold(-4dBuV) */ +#define FM_RX_DESENSE_RSSI -240 +#define FM_RX_PAMD_TH -12 +#define FM_RX_MR_TH -67 +#define FM_RX_ATDC_TH 3496 +#define FM_RX_PRX_TH 64 +#define FM_RX_SMG_TH 16421 /* FM soft-mute gain threshold */ +#define FM_RX_DEEMPHASIS 0 /* 0-50us, China Mainland; 1-75us China Taiwan */ +#define FM_RX_OSC_FREQ 0 /* 0-26MHz; 1-19MHz; 2-24MHz; 3-38.4MHz; 4-40MHz; 5-52MHz */ +#define FM_AUTO_HILO_OFF 0 +#define FM_AUTO_HILO_ON 1 + +/* seek threshold */ +#define FM_SEEKTH_LEVEL_DEFAULT 4 + +/* TX threshold*/ +/* #define FM_TX_PWR_LEVEL_MAX 120 */ +/* #define FM_TX_SCAN_HOLE_LOW 923 //92.3MHz~95.4MHz should not show to user */ +/* #define FM_TX_SCAN_HOLE_HIGH 954 //92.3MHz~95.4MHz should not show to user */ +#define FM_TX_PAMD_TH -23 +#define FM_TX_MR_TH 60 +#define FM_TX_SMG_TH 8231 + +/* ***************************************************************************************** */ +/* ***************************FM default config for customer: end*************************** */ +/* ***************************************************************************************** */ + +enum fm_cfg_parser_state { + FM_CFG_STAT_NONE = 0, + FM_CFG_STAT_GROUP, + FM_CFG_STAT_KEY, + FM_CFG_STAT_VALUE, + FM_CFG_STAT_COMMENT +}; + +#define COMMENT_CHAR '#' +#define DELIMIT_CHAR '=' + +#define isspace(a) ((a) == 0x20) + +struct fm_rx_cust_cfg { + signed int desene_rssi_th; + signed int pamd_th; + signed int mr_th; + signed int atdc_th; + signed int prx_th; + signed int atdev_th; + signed int short_ana_rssi_th; + signed int long_ana_rssi_th; + signed int cqi_th; + signed int smg_th; + signed int deemphasis; + signed int osc_freq; +}; + +struct fm_tx_cust_cfg { + signed int scan_hole_low; + signed int scan_hole_high; + signed int power_level; + signed int pamd_th; + signed int mr_th; + signed int smg_th; +}; +struct fm_cust_cfg { + struct fm_rx_cust_cfg rx_cfg; + struct fm_tx_cust_cfg tx_cfg; + struct fm_audio_info_t aud_cfg; +}; + +enum fm_cust_cfg_op { + FM_CFG_RX_RSSI_TH_LONG = 0, + FM_CFG_RX_RSSI_TH_SHORT, + FM_CFG_RX_CQI_TH, + FM_CFG_RX_MR_TH, + FM_CFG_RX_SMG_TH, + FM_CFG_RX_DEEMPHASIS, + FM_CFG_RX_OSC_FREQ, + FM_CFG_RX_DESENSE_RSSI_TH, + FM_CFG_RX_PAMD_TH, + FM_CFG_RX_ATDC_TH, + FM_CFG_RX_PRX_TH, + FM_CFG_RX_ATDEV_TH, + + FM_CFG_TX_SCAN_HOLE_LOW, + FM_CFG_TX_SCAN_HOLE_HIGH, + FM_CFG_TX_PWR_LEVEL, + FM_CFG_TX_PAMD_TH, + FM_CFG_TX_DEEMPHASIS, + FM_CFG_TX_SMG_TH, + + FM_CFG_MAX +}; + +enum fm_cfg_chip_type { + FM_COMBO_CHIP = 0, + FM_AD_DIE_CHIP, + FM_SOC_CHIP, + FM_CHIP_TYPE_MAX +}; + +typedef signed int(*CFG_HANDLER) (signed char *grp, signed char *key, signed char *val, struct fm_cust_cfg *cfg); +extern signed int to_upper_n(signed char *str, signed int len); +extern signed int check_hex_str(signed char *str, signed int len); +extern signed int check_dec_str(signed char *str, signed int len); +extern signed int ascii_to_hex(signed char *in_ascii, unsigned short *out_hex); +extern signed int ascii_to_dec(signed char *in_ascii, signed int *out_dec); +extern signed int trim_string(signed char **start); +extern signed int trim_path(signed char **start); +extern signed int cfg_parser(signed char *buffer, CFG_HANDLER handler, struct fm_cust_cfg *cfg); +extern signed int cfg_item_match(signed char *src_key, signed char *src_val, signed char *dst_key, signed int *dst_val); + +extern signed int fm_cust_config_setup(const signed char *filename); +extern unsigned short fm_cust_config_fetch(enum fm_cust_cfg_op op_code); +extern unsigned short fm_cust_config_chip(unsigned short chipid, enum fm_cfg_chip_type type); + +extern struct fm_cust_cfg fm_config; +extern unsigned short g_fm_chipid; +extern enum fm_cfg_chip_type g_fm_chip_type; +#endif /* __FM_CONFIG_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_dbg.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_dbg.h new file mode 100644 index 00000000000000..d8da8421dbef14 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_dbg.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FM_DBG_H__ +#define __FM_DBG_H__ + +/* #include <linux/kernel.h> //for printk() */ +#include <linux/printk.h> +#include <linux/ratelimit.h> + +/* DBG zone */ +#define BASE 4 +#define MAIN (1 << (BASE+0)) +#define LINK (1 << (BASE+1)) +#define EINT (1 << (BASE+2)) +#define CHIP (1 << (BASE+3)) +#define RDSC (1 << (BASE+4)) +#define G0 (1 << (BASE+5)) +#define G1 (1 << (BASE+6)) +#define G2 (1 << (BASE+7)) +#define G3 (1 << (BASE+8)) +#define G4 (1 << (BASE+9)) +#define G14 (1 << (BASE+10)) +#define RAW (1 << (BASE+11)) +#define OPEN (1 << (BASE+12)) +#define IOCTL (1 << (BASE+13)) +#define READ_ (1 << (BASE+14)) +#define CLOSE (1 << (BASE+15)) +#define CQI (1 << (BASE+16)) +#define ALL 0xfffffff0 + +/* DBG level */ +#define L0 0x00000000 /* EMERG, system will crush */ +#define L1 0x00000001 /* ALERT, need action in time */ +#define L2 0x00000002 /* CRIT, important HW or SW operation failed */ +#define L3 0x00000003 /* ERR, normal HW or SW ERR */ +#define L4 0x00000004 /* WARNING, importan path or somewhere may occurs err */ +#define L5 0x00000005 /* NOTICE, normal case */ +#define L6 0x00000006 /* INFO, print info if need */ +#define L7 0x00000007 /* DEBUG, for debug info */ + +#define FM_EMG L0 +#define FM_ALT L1 +#define FM_CRT L2 +#define FM_ERR L3 +#define FM_WAR L4 +#define FM_NTC L5 +#define FM_INF L6 +#define FM_DBG L7 +#define FM_DEF(x) ((x)&0x0000000f) + +extern unsigned int g_dbg_level; + +#define WCN_DBG(flag, fmt, args...) \ + do { \ + if ((FM_DEF(flag) <= (g_dbg_level&0x0000000f)) && ((flag)&ALL) & g_dbg_level) { \ + pr_info("[" #flag "] %s: " fmt, __func__, ## args); \ + } \ + } while (0) + +#define WCN_DBG_LIMITED(flag, fmt, args...) \ + do { \ + if ((FM_DEF(flag) <= (g_dbg_level&0x0000000f)) && ((flag)&ALL) & g_dbg_level) { \ + pr_info_ratelimited("[" #flag "]" fmt, ## args); \ + } \ + } while (0) + +#define FM_LOG_DBG(flag, fmt, args...) \ + do { \ + if ((FM_DBG <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0) & g_dbg_level) { \ + pr_info("[" #flag "]" fmt, ## args); \ + } \ + } while (0) + +#define FM_LOG_INF(flag, fmt, args...) \ + do { \ + if ((FM_INF <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0) & g_dbg_level) { \ + pr_info("[" #flag "]" fmt, ## args); \ + } \ + } while (0) + +#define FM_LOG_NTC(flag, fmt, args...) \ + do { \ + if ((FM_NTC <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0) & g_dbg_level) { \ + pr_info("[" #flag "]" fmt, ## args); \ + } \ + } while (0) + +#define FM_LOG_WAR(flag, fmt, args...) \ + do { \ + if ((FM_WAR <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0) & g_dbg_level) { \ + pr_notice("[" #flag "]" fmt, ## args); \ + } \ + } while (0) + +#define FM_LOG_ERR(flag, fmt, args...) \ + do { \ + if ((FM_ERR <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0) & g_dbg_level) { \ + pr_notice("[" #flag "]" fmt, ## args); \ + } \ + } while (0) + +#define FM_LOG_CRT(flag, fmt, args...) \ + do { \ + if ((FM_CRT <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0) & g_dbg_level) { \ + pr_notice("[" #flag "]" fmt, ## args); \ + } \ + } while (0) + +#define FM_LOG_ALT(flag, fmt, args...) \ + do { \ + if ((FM_ALT <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0) & g_dbg_level) { \ + pr_notice("[" #flag "]" fmt, ## args); \ + } \ + } while (0) + +#define FM_LOG_EMG(flag, fmt, args...) \ + do { \ + if ((FM_EMG <= (g_dbg_level&0x0000000f)) && ((flag)&0xfffffff0) & g_dbg_level) { \ + pr_notice("[" #flag "]" fmt, ## args); \ + } \ + } while (0) + +#endif /* __FM_DBG_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_eint.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_eint.h new file mode 100644 index 00000000000000..8b912e23792108 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_eint.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FM_EINT_H__ +#define __FM_EINT_H__ + +#include "fm_typedef.h" + +enum { + FM_EINT_PIN_EINT_MODE, + FM_EINT_PIN_GPIO_MODE, + FM_EINT_PIN_MAX_MODE +}; + +extern signed int fm_enable_eint(void); +extern signed int fm_disable_eint(void); +extern signed int fm_request_eint(void (*parser) (void)); +extern signed int fm_eint_pin_cfg(signed int mode); + +#endif /* __FM_EINT_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_err.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_err.h new file mode 100644 index 00000000000000..b118021420e0c6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_err.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FM_ERR_H__ +#define __FM_ERR_H__ + +#include <linux/kernel.h> /* for printk() */ + +#define FM_ERR_BASE 1000 +enum fm_drv_err_t { + FM_EOK = FM_ERR_BASE, + FM_EBUF, + FM_EPARA, + FM_ELINK, + FM_ELOCK, + FM_EFW, + FM_ECRC, + FM_EWRST, /* wholechip reset */ + FM_ESRST, /* subsystem reset */ + FM_EPATCH, + FM_ENOMEM, + FM_EINUSE, /* other client is using this object */ + FM_EMAX +}; + +#endif /* __FM_ERR_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_ext_api.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_ext_api.h new file mode 100644 index 00000000000000..407cd4dd3497f7 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_ext_api.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef FM_EXT_API_H +#define FM_EXT_API_H + +#include <linux/platform_device.h> + +enum fm_spi_speed { + FM_SPI_SPEED_26M, + FM_SPI_SPEED_64M, + FM_SPI_SPEED_MAX +}; + +struct fm_ext_interface { + void (*eint_handler)(void); + void (*eint_cb)(void); + void (*enable_eint)(void); + void (*disable_eint)(void); + int (*stp_send_data)(unsigned char *buf, unsigned int len); + int (*stp_recv_data)(unsigned char *buf, unsigned int len); + int (*stp_register_event_cb)(void *cb); + int (*wmt_msgcb_reg)(void *data); + int (*wmt_func_on)(void); + int (*wmt_func_off)(void); + int (*wmt_ic_info_get)(void); + int (*wmt_chipid_query)(void); + unsigned char (*get_top_index)(void); + int (*spi_clock_switch)(enum fm_spi_speed speed); + bool (*is_bus_hang)(void); + + struct platform_driver *drv; + unsigned int irq_id; +}; + +#endif /* FM_EXT_API_H */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_interface.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_interface.h new file mode 100644 index 00000000000000..26575c6fb8f4ab --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_interface.h @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FM_INTERFACE_H__ +#define __FM_INTERFACE_H__ + +#include <linux/cdev.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> + +#include "fm_typedef.h" +#include "fm_rds.h" +#include "fm_utils.h" + +/****************************************************************************** + * STRUCTURE DEFINITIONS + *****************************************************************************/ +enum fm_op_state { + FM_STA_STOP = 0, + FM_STA_PLAY = 1, + FM_STA_TUNE = 2, + FM_STA_SEEK = 3, + FM_STA_SCAN = 4, + FM_STA_RAMPDOWN = 5, + FM_STA_UNKNOWN = 100, + FM_STA_MAX +}; + +enum fm_pwr_state { + FM_PWR_OFF = 0, + FM_PWR_RX_ON = 1, + FM_PWR_TX_ON = 2, + FM_PWR_MAX +}; + +enum fm_antenna_type { + FM_ANA_LONG = 0, /* long antenna */ + FM_ANA_SHORT = 1, /* short antenna */ + FM_ANA_MAX +}; + +enum fm_gps_desense_t { + FM_GPS_DESE_ENABLE, + FM_GPS_DESE_DISABLE +}; + +struct fm_hw_info { + signed int chip_id; /* chip ID, eg. 6620 */ + signed int eco_ver; /* chip ECO version, eg. E3 */ + signed int rom_ver; /* FM DSP rom code version, eg. V2 */ + signed int patch_ver; /* FM DSP patch version, eg. 1.11 */ + signed int reserve; +}; + +struct fm_i2s_setting { + signed int onoff; + signed int mode; + signed int sample; +}; + +enum fm_i2s_state_e { + FM_I2S_ON = 0, + FM_I2S_OFF, + FM_I2S_STATE_ERR +}; + +enum fm_i2s_mode_e { + FM_I2S_MASTER = 0, + FM_I2S_SLAVE, + FM_I2S_MODE_ERR +}; + +enum fm_i2s_sample_e { + FM_I2S_32K = 0, + FM_I2S_44K, + FM_I2S_48K, + FM_I2S_SR_ERR +}; + +struct fm_i2s_info { + signed int status; /*0:FM_I2S_ON, 1:FM_I2S_OFF,2:error */ + signed int mode; /*0:FM_I2S_MASTER, 1:FM_I2S_SLAVE,2:error */ + signed int rate; /*0:FM_I2S_32K:32000,1:FM_I2S_44K:44100,2:FM_I2S_48K:48000,3:error */ +}; + +enum fm_audio_path_e { + FM_AUD_ANALOG = 0, + FM_AUD_I2S = 1, + FM_AUD_MRGIF = 2, + FM_AUD_ERR +}; + +enum fm_i2s_pad_sel_e { + FM_I2S_PAD_CONN = 0, /* sco fm chip: e.g.6627 */ + FM_I2S_PAD_IO = 1, /* combo fm chip: e.g.6628 */ + FM_I2S_PAD_ERR +}; + +struct fm_audio_info_t { + enum fm_audio_path_e aud_path; + struct fm_i2s_info i2s_info; + enum fm_i2s_pad_sel_e i2s_pad; +}; + +struct fm_platform { + struct cdev cdev; + dev_t dev_t; + struct class *cls; + struct device *dev; +}; + +struct fm { + /* chip info */ + signed int projectid; + unsigned short chip_id; /* chip id, such as 6616/6620/6626/6628 */ + unsigned short device_id; /* chip version */ + /* basic run time info */ + signed int ref; /* fm driver can be multi opened */ + bool chipon; /* Chip power state */ + enum fm_pwr_state pwr_sta; /* FM module power state */ + enum fm_op_state op_sta; /* current operation state: tune, seek, scan ... */ + /* enum fm_audio_path aud_path; //I2S or Analog */ + signed int vol; /* current audio volume from chip side */ + bool mute; /* true: mute, false: playing */ + bool rds_on; /* true: on, false: off */ + enum fm_antenna_type ana_type; /* long/short antenna */ + bool via_bt; /* true: fm over bt controller; false: fm over host */ + unsigned short min_freq; /* for UE, 875KHz */ + unsigned short max_freq; /* for UE, 1080KHz */ + unsigned short cur_freq; /* current frequency */ + unsigned char band; /* UE/JAPAN/JPANWD */ + /*FM Tx */ + unsigned int vcoon; /* TX VCO tracking ON duiration(ms) */ + unsigned int vcooff; /* TX RTC VCO tracking interval(s) */ + unsigned int txpwrctl; /* TX power contrl interval(s) */ + unsigned int tx_pwr; + bool rdstx_on; /* false:rds tx off, true:rds tx on */ + bool wholechiprst; + /* RDS data */ + struct fm_flag_event *rds_event; /* pointer to rds event */ + struct rds_t *pstRDSData; /* rds spec data buffer */ + /* platform data */ + struct fm_platform platform; /* platform related members */ + + struct fm_workthread *eint_wkthd; + struct fm_workthread *timer_wkthd; + struct fm_work *eint_wk; + struct fm_work *rds_wk; + struct fm_work *rst_wk; /* work for subsystem reset */ + struct fm_work *pwroff_wk; + struct fm_work *ch_valid_check_wk; + /* Tx */ + struct fm_work *fm_tx_desense_wifi_work; + struct fm_work *fm_tx_power_ctrl_work; + +}; + +struct fm_callback { + /* call backs */ + unsigned short (*cur_freq_get)(void); + signed int (*cur_freq_set)(unsigned short new_freq); + signed int (*projectid_get)(void); +/* unsigned short(*chan_para_get)(unsigned short freq); //get channel parameter, HL side/ FA / ATJ */ +}; + +struct fm_basic_interface { + /* mt66x6 lib interfaces */ + signed int (*low_pwr_wa)(signed int onoff); + signed int (*pwron)(signed int data); + signed int (*pwroff)(signed int data); + signed int (*pmic_read)(unsigned char addr, unsigned int *val); + signed int (*pmic_write)(unsigned char addr, unsigned int val); + unsigned short (*chipid_get)(void); + signed int (*mute)(bool mute); + signed int (*rampdown)(void); + signed int (*pwrupseq)(unsigned short *chip_id, unsigned short *device_id); + signed int (*pwrdownseq)(void); + bool (*setfreq)(unsigned short freq); + bool (*seek)(unsigned short min_freq, unsigned short max_freq, unsigned short *freq, unsigned short dir, + unsigned short space); + signed int (*seekstop)(void); + bool (*scan)(unsigned short min_freq, unsigned short max_freq, unsigned short *freq, unsigned short *tbl, + unsigned short *tblsize, unsigned short dir, unsigned short space); + bool (*jammer_scan)(unsigned short min_freq, unsigned short max_freq, unsigned short *freq, unsigned short *tbl, + unsigned short *tblsize, unsigned short dir, unsigned short space); + signed int (*cqi_get)(signed char *buf, signed int buf_len); + signed int (*scanstop)(void); + signed int (*rssiget)(signed int *rssi); + signed int (*volset)(unsigned char vol); + signed int (*volget)(unsigned char *vol); + signed int (*dumpreg)(void); + bool (*msget)(unsigned short *ms); /* mono/stereo indicator get */ + signed int (*msset)(signed int ms); /* mono/stereo force set */ + bool (*pamdget)(unsigned short *pamd); + bool (*em)(unsigned short group, unsigned short item, unsigned int val); + signed int (*anaswitch)(signed int ana); + signed int (*anaget)(void); + signed int (*caparray_get)(signed int *ca); + signed int (*i2s_set)(signed int onoff, signed int mode, signed int sample); + signed int (*i2s_get)(signed int *ponoff, signed int *pmode, signed int *psample); + signed int (*hwinfo_get)(struct fm_hw_info *req); + /* check if this is a de-sense channel */ + signed int (*is_dese_chan)(unsigned short freq); + signed int (*softmute_tune)(unsigned short freq, signed int *rssi, signed int *valid); + signed int (*pre_search)(void); + signed int (*restore_search)(void); + /* check if this is a valid channel */ + signed int (*desense_check)(unsigned short freq, signed int rssi); + signed int (*get_freq_cqi)(unsigned short freq, signed int *cqi); + /* cqi log tool */ + signed int (*cqi_log)(signed int min_freq, signed int max_freq, signed int space, signed int cnt); + signed int (*fm_via_bt)(bool flag); /* fm over BT:1:enable,0:disable */ + signed int (*set_search_th)(signed int idx, signed int val, signed int reserve); + signed int (*get_aud_info)(struct fm_audio_info_t *data); + /*tx function */ + signed int (*tx_support)(signed int *sup); + signed int (*rdstx_enable)(signed int *flag); + bool (*tune_tx)(unsigned short freq); + signed int (*pwrupseq_tx)(void); + signed int (*pwrdownseq_tx)(void); + signed int (*tx_pwr_ctrl)(unsigned short freq, signed int *ctr); + signed int (*rtc_drift_ctrl)(unsigned short freq, signed int *ctr); + signed int (*tx_desense_wifi)(unsigned short freq, signed int *ctr); + signed int (*tx_scan)(unsigned short min_freq, unsigned short max_freq, unsigned short *pFreq, + unsigned short *pScanTBL, unsigned short *ScanTBLsize, + unsigned short scandir, unsigned short space); + signed int (*rds_tx_adapter)(unsigned short pi, unsigned short *ps, unsigned short *other_rds, + unsigned char other_rds_cnt); + bool (*is_valid_freq)(unsigned short freq); + +}; + +struct fm_rds_interface { + /* rds lib interfaces */ + signed int (*rds_blercheck)(struct rds_t *dst); + bool (*rds_onoff)(struct rds_t *dst, bool onoff); + signed int (*rds_parser)(struct rds_t *rds_dst, struct rds_rx_t *rds_raw, + signed int rds_size, unsigned short(*getfreq) (void)); + unsigned short (*rds_gbc_get)(void); /* good block counter */ + unsigned short (*rds_bbc_get)(void); /* bad block counter */ + unsigned char (*rds_bbr_get)(void); /* bad block ratio */ + signed int (*rds_bc_reset)(void); /* reset block counter */ + unsigned int (*rds_bci_get)(void); /* bler check interval */ + signed int (*rds_log_get)(struct rds_rx_t *dst, signed int *dst_len); + signed int (*rds_gc_get)(struct rds_group_cnt_t *dst, struct rds_t *rdsp); + signed int (*rds_gc_reset)(struct rds_t *rdsp); + /*Tx */ + signed int (*rds_tx)(unsigned short pi, unsigned short *ps, unsigned short *other_rds, + unsigned char other_rds_cnt); + signed int (*rds_tx_enable)(void); + signed int (*rds_tx_disable)(void); + signed int (*rdstx_support)(signed int *sup); +}; + +struct fm_lowlevel_ops { + struct fm_callback cb; + struct fm_basic_interface bi; + struct fm_rds_interface ri; +}; + +extern signed int fm_low_ops_register(struct fm_callback *cb, struct fm_basic_interface *bi); +extern signed int fm_low_ops_unregister(struct fm_basic_interface *bi); +extern signed int fm_rds_ops_register(struct fm_basic_interface *bi, struct fm_rds_interface *ri); +extern signed int fm_rds_ops_unregister(struct fm_rds_interface *ri); +extern signed int fm_wcn_ops_register(void); +extern signed int fm_wcn_ops_unregister(void); +extern int fm_register_irq(struct platform_driver *drv); + +/* + * fm_get_channel_space - get the spcace of gived channel + * @freq - value in 760~1080 or 7600~10800 + * + * Return 0, if 760~1080; return 1, if 7600 ~ 10800, else err code < 0 + */ + +extern signed int fm_get_channel_space(int freq); +#endif /* __FM_INTERFACE_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_ioctl.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_ioctl.h new file mode 100644 index 00000000000000..ba120c637e6750 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_ioctl.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FM_IOCTL_H__ +#define __FM_IOCTL_H__ +#include "fm_typedef.h" +#include "fm_rds.h" +#include "fm_main.h" + +#define FM_IOC_MAGIC 0xf5 /* FIXME: any conflict? */ +#define FM_IOCTL_POWERUP _IOWR(FM_IOC_MAGIC, 0, struct fm_tune_parm*) +#define FM_IOCTL_POWERDOWN _IOWR(FM_IOC_MAGIC, 1, int32_t*) +#define FM_IOCTL_TUNE _IOWR(FM_IOC_MAGIC, 2, struct fm_tune_parm*) +#define FM_IOCTL_SEEK _IOWR(FM_IOC_MAGIC, 3, struct fm_seek_parm*) +#define FM_IOCTL_SETVOL _IOWR(FM_IOC_MAGIC, 4, uint32_t*) +#define FM_IOCTL_GETVOL _IOWR(FM_IOC_MAGIC, 5, uint32_t*) +#define FM_IOCTL_MUTE _IOWR(FM_IOC_MAGIC, 6, uint32_t*) +#define FM_IOCTL_GETRSSI _IOWR(FM_IOC_MAGIC, 7, int32_t*) +#define FM_IOCTL_SCAN _IOWR(FM_IOC_MAGIC, 8, struct fm_scan_parm*) +#define FM_IOCTL_STOP_SCAN _IO(FM_IOC_MAGIC, 9) + +/* IOCTL and struct for test */ +#define FM_IOCTL_GETCHIPID _IOWR(FM_IOC_MAGIC, 10, uint16_t*) +#define FM_IOCTL_EM_TEST _IOWR(FM_IOC_MAGIC, 11, struct fm_em_parm*) +#define FM_IOCTL_RW_REG _IOWR(FM_IOC_MAGIC, 12, struct fm_ctl_parm*) +#define FM_IOCTL_GETMONOSTERO _IOWR(FM_IOC_MAGIC, 13, uint16_t*) +#define FM_IOCTL_GETCURPAMD _IOWR(FM_IOC_MAGIC, 14, uint16_t*) +#define FM_IOCTL_GETGOODBCNT _IOWR(FM_IOC_MAGIC, 15, uint16_t*) +#define FM_IOCTL_GETBADBNT _IOWR(FM_IOC_MAGIC, 16, uint16_t*) +#define FM_IOCTL_GETBLERRATIO _IOWR(FM_IOC_MAGIC, 17, uint16_t*) + +/* IOCTL for RDS */ +#define FM_IOCTL_RDS_ONOFF _IOWR(FM_IOC_MAGIC, 18, uint16_t*) +#define FM_IOCTL_RDS_SUPPORT _IOWR(FM_IOC_MAGIC, 19, int32_t*) + +#define FM_IOCTL_POWERUP_TX _IOWR(FM_IOC_MAGIC, 20, struct fm_tune_parm*) +#define FM_IOCTL_TUNE_TX _IOWR(FM_IOC_MAGIC, 21, struct fm_tune_parm*) +#define FM_IOCTL_RDS_TX _IOWR(FM_IOC_MAGIC, 22, struct fm_rds_tx_parm*) + +#define FM_IOCTL_RDS_SIM_DATA _IOWR(FM_IOC_MAGIC, 23, uint32_t*) +#define FM_IOCTL_IS_FM_POWERED_UP _IOWR(FM_IOC_MAGIC, 24, uint32_t*) + +/* IOCTL for FM Tx */ +#define FM_IOCTL_TX_SUPPORT _IOWR(FM_IOC_MAGIC, 25, int32_t*) +#define FM_IOCTL_RDSTX_SUPPORT _IOWR(FM_IOC_MAGIC, 26, int32_t*) +#define FM_IOCTL_RDSTX_ENABLE _IOWR(FM_IOC_MAGIC, 27, int32_t*) +#define FM_IOCTL_TX_SCAN _IOWR(FM_IOC_MAGIC, 28, struct fm_tx_scan_parm*) + +/* IOCTL for FM over BT */ +#define FM_IOCTL_OVER_BT_ENABLE _IOWR(FM_IOC_MAGIC, 29, int32_t*) + +/* IOCTL for FM ANTENNA SWITCH */ +#define FM_IOCTL_ANA_SWITCH _IOWR(FM_IOC_MAGIC, 30, int32_t*) +#define FM_IOCTL_GETCAPARRAY _IOWR(FM_IOC_MAGIC, 31, int32_t*) + +/* IOCTL for FM compensation by GPS RTC */ +#define FM_IOCTL_GPS_RTC_DRIFT _IOWR(FM_IOC_MAGIC, 32, struct fm_gps_rtc_info*) + +/* IOCTL for FM I2S Setting */ +#define FM_IOCTL_I2S_SETTING _IOWR(FM_IOC_MAGIC, 33, struct fm_i2s_setting*) + +#define FM_IOCTL_RDS_GROUPCNT _IOWR(FM_IOC_MAGIC, 34, struct rds_group_cnt_req_t*) +#define FM_IOCTL_RDS_GET_LOG _IOWR(FM_IOC_MAGIC, 35, struct rds_raw_t*) + +#define FM_IOCTL_SCAN_GETRSSI _IOWR(FM_IOC_MAGIC, 36, struct fm_rssi_req*) +#define FM_IOCTL_SETMONOSTERO _IOWR(FM_IOC_MAGIC, 37, int32_t) + +#define FM_IOCTL_RDS_BC_RST _IOWR(FM_IOC_MAGIC, 38, int32_t*) +#define FM_IOCTL_CQI_GET _IOWR(FM_IOC_MAGIC, 39, struct fm_cqi_req*) +#define FM_IOCTL_GET_HW_INFO _IOWR(FM_IOC_MAGIC, 40, struct fm_hw_info*) +#define FM_IOCTL_GET_I2S_INFO _IOWR(FM_IOC_MAGIC, 41, struct fm_i2s_info*) +#define FM_IOCTL_IS_DESE_CHAN _IOWR(FM_IOC_MAGIC, 42, int32_t*) + +#define FM_IOCTL_TOP_RDWR _IOWR(FM_IOC_MAGIC, 43, struct fm_top_rw_parm*) +#define FM_IOCTL_HOST_RDWR _IOWR(FM_IOC_MAGIC, 44, struct fm_host_rw_parm*) + +#define FM_IOCTL_PRE_SEARCH _IOWR(FM_IOC_MAGIC, 45, int32_t) +#define FM_IOCTL_RESTORE_SEARCH _IOWR(FM_IOC_MAGIC, 46, int32_t) + +#define FM_IOCTL_SET_SEARCH_THRESHOLD _IOWR(FM_IOC_MAGIC, 47, struct fm_search_threshold_t*) + +#define FM_IOCTL_GET_AUDIO_INFO _IOWR(FM_IOC_MAGIC, 48, struct fm_audio_info_t*) +#define FM_IOCTL_FM_SET_STATUS _IOWR(FM_IOC_MAGIC, 49, struct fm_status_t) +#define FM_IOCTL_FM_GET_STATUS _IOWR(FM_IOC_MAGIC, 50, struct fm_status_t) + +#define FM_IOCTL_SCAN_NEW _IOWR(FM_IOC_MAGIC, 60, struct fm_scan_t*) +#define FM_IOCTL_SEEK_NEW _IOWR(FM_IOC_MAGIC, 61, struct fm_seek_t*) +#define FM_IOCTL_TUNE_NEW _IOWR(FM_IOC_MAGIC, 62, struct fm_tune_t*) +#define FM_IOCTL_SOFT_MUTE_TUNE _IOWR(FM_IOC_MAGIC, 63, struct fm_softmute_tune_t*) /*for soft mute tune */ +#define FM_IOCTL_DESENSE_CHECK _IOWR(FM_IOC_MAGIC, 64, struct fm_desense_check_t*) + +#define COMPAT_FM_IOCTL_GET_AUDIO_INFO _IOWR(FM_IOC_MAGIC, 48, struct fm_audio_info_t*) + +#define FM_IOCTL_PMIC_RDWR _IOWR(FM_IOC_MAGIC, 65, struct fm_pmic_rw_parm*) + +#define FM_IOCTL_DUMP_REG _IO(FM_IOC_MAGIC, 0xFF) +#endif /* __FM_IOCTL_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_link.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_link.h new file mode 100644 index 00000000000000..75e6b2fee022bc --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_link.h @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FM_LINK_H__ +#define __FM_LINK_H__ + +#include "fm_typedef.h" +#include "fm_rds.h" +#include "fm_utils.h" + +enum fm_task_parser_state { + FM_TASK_RX_PARSER_PKT_TYPE = 0, + FM_TASK_RX_PARSER_OPCODE, + FM_TASK_RX_PARSER_PKT_LEN_1, + FM_TASK_RX_PARSER_PKT_LEN_2, + FM_TASK_RX_PARSER_PKT_PAYLOAD, + FM_TASK_RX_PARSER_BUFFER_CONGESTION +}; + +enum { + FM_TASK_COMMAND_PKT_TYPE = 0x01, + FM_TASK_EVENT_PKT_TYPE = 0x04 +}; + +/* FM opcode */ +enum { + FM_STP_TEST_OPCODE = 0x00, + FSPI_ENABLE_OPCODE = 0x01, + FSPI_MUX_SEL_OPCODE = 0x02, + FSPI_READ_OPCODE = 0x03, + FSPI_WRITE_OPCODE = 0x04, + FI2C_READ_OPCODE = 0x05, + FI2C_WRITE_OPCODE = 0x06, + FM_ENABLE_OPCODE = 0x07, + FM_RESET_OPCODE = 0x08, + FM_TUNE_OPCODE = 0x09, + FM_SEEK_OPCODE = 0x0a, + FM_SCAN_OPCODE = 0x0b, + RDS_RX_ENABLE_OPCODE = 0x0c, + RDS_RX_DATA_OPCODE = 0x0d, + FM_RAMPDOWN_OPCODE = 0x0e, + FM_MCUCLK_SEL_OPCODE = 0x0f, + FM_MODEMCLK_SEL_OPCODE = 0x10, + RDS_TX_OPCODE = 0x11, + FM_PATCH_DOWNLOAD_OPCODE = 0x12, + FM_COEFF_DOWNLOAD_OPCODE = 0x13, + FM_HWCOEFF_DOWNLOAD_OPCODE = 0x14, + FM_ROM_DOWNLOAD_OPCODE = 0x15, + FM_SOFT_MUTE_TUNE_OPCODE = 0x17, + FM_HOST_READ_OPCODE = 0x18, /* mcu register read */ + FM_HOST_WRITE_OPCODE = 0x19, + CSPI_WRITE_OPCODE = 0x20, + CSPI_READ_OPCODE = 0x21, /* common SPI read */ + FM_HOST_MODIFY_OPCODE = 0x22, + FM_READ_PMIC_CR_OPCODE = 0x23, + FM_WRITE_PMIC_CR_OPCODE = 0x24, + FM_MODIFY_PMIC_CR_OPCODE = 0x25, + FM_OPCODE_MAX +}; + +enum { + FLAG_TEST = (1 << FM_STP_TEST_OPCODE), + FLAG_FSPI_EN = (1 << FSPI_ENABLE_OPCODE), + FLAG_FSPI_MUXSEL = (1 << FSPI_MUX_SEL_OPCODE), + FLAG_FSPI_RD = (1 << FSPI_READ_OPCODE), + FLAG_FSPI_WR = (1 << FSPI_WRITE_OPCODE), + FLAG_I2C_RD = (1 << FI2C_READ_OPCODE), + FLAG_I2C_WR = (1 << FI2C_WRITE_OPCODE), + FLAG_EN = (1 << FM_ENABLE_OPCODE), + FLAG_PMIC_READ = (1 << 8), + FLAG_TUNE = (1 << FM_TUNE_OPCODE), + FLAG_SEEK = (1 << FM_SEEK_OPCODE), + FLAG_SCAN = (1 << FM_SCAN_OPCODE), + FLAG_RDS_RX_EN = (1 << RDS_RX_ENABLE_OPCODE), + FLAG_RDS_DATA = (1 << RDS_RX_DATA_OPCODE), + FLAG_RAMPDOWN = (1 << FM_RAMPDOWN_OPCODE), + FLAG_PMIC_MODIFY = (1 << 15), + FLAG_MODEMCLK = (1 << FM_MODEMCLK_SEL_OPCODE), + FLAG_RDS_TX = (1 << RDS_TX_OPCODE), + FLAG_PATCH = (1 << FM_PATCH_DOWNLOAD_OPCODE), + FLAG_COEFF = (1 << FM_COEFF_DOWNLOAD_OPCODE), + FLAG_HWCOEFF = (1 << FM_HWCOEFF_DOWNLOAD_OPCODE), + FLAG_ROM = (1 << FM_ROM_DOWNLOAD_OPCODE), + FLAG_CSPI_READ = (1 << 22), /* 22 */ + FLAG_SM_TUNE = (1 << FM_SOFT_MUTE_TUNE_OPCODE), /* 23 */ + FLAG_HOST_READ = (1 << FM_HOST_READ_OPCODE), /* 24 */ + FLAG_HOST_WRITE = (1 << FM_HOST_WRITE_OPCODE), /* 25 */ + FLAG_CSPI_WRITE = (1 << 26), /* 26 */ + FLAG_CQI_DONE = (1 << 27), + FLAG_TUNE_DONE = (1 << 28), + FLAG_SEEK_DONE = (1 << 29), + FLAG_SCAN_DONE = (1 << 30), + FLAG_TERMINATE = (1 << 31) +}; + +#define FM_SCANTBL_SIZE 16 +#define FM_CQI_BUF_SIZE 96 +struct fm_res_ctx { + unsigned short fspi_rd; + unsigned short seek_result; + unsigned short scan_result[FM_SCANTBL_SIZE]; + signed char cqi[FM_CQI_BUF_SIZE]; + struct rds_rx_t rds_rx_result; + unsigned int cspi_rd; /* common spi read data */ + unsigned char pmic_result[8]; +}; + +#define FM_TRACE_ENABLE + +#define FM_TRACE_FIFO_SIZE 200 +#define FM_TRACE_PKT_SIZE 60 +struct fm_trace_t { + signed int type; + signed int opcode; + signed int len; + unsigned char pkt[FM_TRACE_PKT_SIZE]; /* full packet */ + unsigned long time; + signed int tid; +}; + +struct fm_trace_fifo_t { + signed char name[20 + 1]; + struct fm_trace_t trace[FM_TRACE_FIFO_SIZE]; + unsigned int size; + unsigned int in; + unsigned int out; + unsigned int len; + signed int (*trace_in)(struct fm_trace_fifo_t *thiz, struct fm_trace_t *new_tra); + signed int (*trace_out)(struct fm_trace_fifo_t *thiz, struct fm_trace_t *dst_tra); + + bool (*is_full)(struct fm_trace_fifo_t *thiz); + bool (*is_empty)(struct fm_trace_fifo_t *thiz); +}; + +#define FM_TRACE_IN(fifop, tracep) \ +({ \ + signed int __ret = (signed int)0; \ + if (fifop && (fifop)->trace_in) { \ + __ret = (fifop)->trace_in(fifop, tracep); \ + } \ + __ret; \ +}) + +#define FM_TRACE_OUT(fifop, tracep) \ +({ \ + signed int __ret = (signed int)0; \ + if (fifop && (fifop)->trace_out) { \ + __ret = (fifop)->trace_out(fifop, tracep); \ + } \ + __ret; \ +}) + +#define FM_TRACE_FULL(fifop) \ +({ \ + bool __ret = (bool)false; \ + if (fifop && (fifop)->is_full) { \ + __ret = (fifop)->is_full(fifop); \ + } \ + __ret; \ +}) + +#define FM_TRACE_EMPTY(fifop) \ +({ \ + bool __ret = (bool)false; \ + if (fifop && (fifop)->is_empty) { \ + __ret = (fifop)->is_empty(fifop); \ + } \ + __ret; \ +}) + +#define RX_BUF_SIZE 256 +#define TX_BUF_SIZE 1024 + +#define SW_RETRY_CNT (1) +#define SW_RETRY_CNT_MAX (5) +#define SW_WAIT_TIMEOUT_MAX (100) +/* FM operation timeout define for error handle */ +#define TEST_TIMEOUT (3) +#define FSPI_EN_TIMEOUT (3) +#define FSPI_MUXSEL_TIMEOUT (3) +#define FSPI_RD_TIMEOUT (3) +#define FSPI_WR_TIMEOUT (3) +#define I2C_RD_TIMEOUT (3) +#define I2C_WR_TIMEOUT (3) +#define EN_TIMEOUT (3) +#define RST_TIMEOUT (3) +#define TUNE_TIMEOUT (3) +#define SM_TUNE_TIMEOUT (6) +#define SEEK_TIMEOUT (15) +#define SCAN_TIMEOUT (15) /* usually scan will cost 10 seconds */ +#define RDS_RX_EN_TIMEOUT (3) +#define RDS_DATA_TIMEOUT (100) +#define RAMPDOWN_TIMEOUT (3) +#define MCUCLK_TIMEOUT (3) +#define MODEMCLK_TIMEOUT (3) +#define RDS_TX_TIMEOUT (3) +#define PATCH_TIMEOUT (3) +#define COEFF_TIMEOUT (3) +#define HWCOEFF_TIMEOUT (3) +#define ROM_TIMEOUT (3) +#define PMIC_CONTROL_TIMEOUT (3) + + +struct fm_link_event { + struct fm_flag_event *ln_event; + struct fm_res_ctx result; /* seek/scan/read/RDS */ +}; + +/* + * FM data and ctrl link APIs: platform related and bus related + */ +extern signed int fm_link_setup(void *data); + +extern signed int fm_link_release(void); + +extern signed int fm_cmd_tx(unsigned char *buf, unsigned short len, signed int mask, signed int cnt, signed int timeout, + signed int (*callback)(struct fm_res_ctx *result)); + +extern signed int fm_event_parser(signed int (*rds_parser)(struct rds_rx_t *, signed int)); + +extern signed int fm_ctrl_rx(unsigned char addr, unsigned short *val); + +extern signed int fm_ctrl_tx(unsigned char addr, unsigned short val); + +extern signed int fm_force_active_event(unsigned int mask); + +extern bool fm_wait_stc_done(unsigned int sec); + +extern struct fm_trace_fifo_t *fm_trace_fifo_create(const signed char *name); + +extern signed int fm_trace_fifo_release(struct fm_trace_fifo_t *fifo); + +extern signed int fm_print_cmd_fifo(void); + +extern signed int fm_print_evt_fifo(void); + +#endif /* __FM_LINK_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_main.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_main.h new file mode 100644 index 00000000000000..4a9e1592ebf90c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_main.h @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FM_MAIN_H__ +#define __FM_MAIN_H__ + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_rds.h" +#include "fm_eint.h" +#include "fm_link.h" +#include "fm_interface.h" +#include "fm_stdlib.h" +#include "fm_config.h" + +#define FM_NAME "fm" +#define FM_DEVICE_NAME "/dev/fm" + +#define FM_VOL_MAX 0x2B /* 43 volume(0-15) */ +#define FM_TIMER_TIMEOUT_DEFAULT 1000 +#define FM_TIMER_TIMEOUT_MIN 1000 +#define FM_TIMER_TIMEOUT_MAX 1000000 +/* FM Tx */ +#define FM_TX_PWR_LEVEL_MAX 120 /* FM transmitter power level, rang: 85db~120db, default 120db */ + +#define FM_TX_PWR_CTRL_INVAL_DEFAULT 10 +#define FM_TX_PWR_CTRL_INVAL_MIN 5 +#define FM_TX_PWR_CTRL_INVAL_MAX 10000 + +#define FM_TX_VCO_OFF_DEFAULT 5 +#define FM_TX_VCO_OFF_MIN 1 +#define FM_TX_VCO_OFF_MAX 10000 + +#define FM_TX_VCO_ON_DEFAULT 100 +#define FM_TX_VCO_ON_MIN 10 +#define FM_TX_VCO_ON_MAX 10000 + +#define FM_GPS_RTC_AGE_TH 2 +#define FM_GPS_RTC_DRIFT_TH 0 +#define FM_GPS_RTC_TIME_DIFF_TH 10 +#define FM_GPS_RTC_RETRY_CNT 1 +#define FM_GPS_RTC_DRIFT_MAX 5000 +enum { + FM_GPS_RTC_INFO_OLD = 0, + FM_GPS_RTC_INFO_NEW = 1, + FM_GPS_RTC_INFO_MAX +}; + +enum fm_over_bt_enable_state { + FM_OVER_BT_DISABLE = 0, + FM_OVER_BT_ENABLE +}; + +#define FM_RDS_ENABLE 0x01 /* 1: enable RDS, 0:disable RDS */ +#define FM_RDS_DATA_READY (1 << 0) + +/* errno */ +#define FM_SUCCESS 0 +#define FM_FAILED 1 +#define FM_EPARM 2 +#define FM_BADSTATUS 3 +#define FM_TUNE_FAILED 4 +#define FM_SEEK_FAILED 5 +#define FM_BUSY 6 +#define FM_SCAN_FAILED 7 + +struct fm_tune_parm { + unsigned char err; + unsigned char band; + unsigned char space; + unsigned char hilo; + unsigned char deemphasis; + unsigned short freq; /* IN/OUT parameter */ +}; + +struct fm_tune_parm_old { + unsigned char err; + unsigned char band; + unsigned char space; + unsigned char hilo; + unsigned short freq; /* IN/OUT parameter */ +}; + +struct fm_seek_parm { + unsigned char err; + unsigned char band; + unsigned char space; + unsigned char hilo; + unsigned char seekdir; + unsigned char seekth; + unsigned short freq; /* IN/OUT parameter */ +}; + +#ifdef CONFIG_MTK_FM_50KHZ_SUPPORT +struct fm_scan_parm { + unsigned char err; + unsigned char band; + unsigned char space; + unsigned char hilo; + unsigned short freq; /* OUT parameter */ + unsigned short ScanTBL[26]; /* need no less than the chip */ + unsigned short ScanTBLSize; /* IN/OUT parameter */ +}; +#else +struct fm_scan_parm { + unsigned char err; + unsigned char band; + unsigned char space; + unsigned char hilo; + unsigned short freq; /* OUT parameter */ + unsigned short ScanTBL[16]; /* need no less than the chip */ + unsigned short ScanTBLSize; /* IN/OUT parameter */ +}; +#endif + +struct fm_cqi { + signed int ch; + signed int rssi; + signed int reserve; +}; + +struct fm_cqi_req { + unsigned short ch_num; + signed int buf_size; + signed char *cqi_buf; +}; + +struct fm_ch_rssi { + unsigned short freq; + signed int rssi; +}; + +enum fm_scan_cmd_t { + FM_SCAN_CMD_INIT = 0, + FM_SCAN_CMD_START, + FM_SCAN_CMD_GET_NUM, + FM_SCAN_CMD_GET_CH, + FM_SCAN_CMD_GET_RSSI, + FM_SCAN_CMD_GET_CH_RSSI, + FM_SCAN_CMD_MAX +}; + +struct fm_scan_t { + enum fm_scan_cmd_t cmd; + signed int ret; /* 0, success; else error code */ + unsigned short lower; /* lower band, Eg, 7600 -> 76.0Mhz */ + unsigned short upper; /* upper band, Eg, 10800 -> 108.0Mhz */ + signed int space; /* 5: 50KHz, 10: 100Khz, 20: 200Khz */ + signed int num; /* valid channel number */ + void *priv; + signed int sr_size; /* scan result buffer size in bytes */ + union { + unsigned short *ch_buf; /* channel buffer */ + signed int *rssi_buf; /* rssi buffer */ + struct fm_ch_rssi *ch_rssi_buf; /* channel and RSSI buffer */ + } sr; +}; + +struct fm_seek_t { + signed int ret; /* 0, success; else error code */ + unsigned short freq; + unsigned short lower; /* lower band, Eg, 7600 -> 76.0Mhz */ + unsigned short upper; /* upper band, Eg, 10800 -> 108.0Mhz */ + signed int space; /* 5: 50KHz, 10: 100Khz, 20: 200Khz */ + signed int dir; /* 0: up; 1: down */ + signed int th; /* seek threshold in dbm(Eg, -95dbm) */ + void *priv; +}; + +struct fm_tune_t { + signed int ret; /* 0, success; else error code */ + unsigned short freq; + unsigned short lower; /* lower band, Eg, 7600 -> 76.0Mhz */ + unsigned short upper; /* upper band, Eg, 10800 -> 108.0Mhz */ + signed int space; /* 5: 50KHz, 10: 100Khz, 20: 200Khz */ + void *priv; +}; + +#ifdef CONFIG_MTK_FM_50KHZ_SUPPORT +struct fm_rssi_req { + unsigned short num; + unsigned short read_cnt; + struct fm_ch_rssi cr[26 * 16]; +}; +#else +struct fm_rssi_req { + unsigned short num; + unsigned short read_cnt; + struct fm_ch_rssi cr[16 * 16]; +}; +#endif + +struct fm_rds_tx_parm { + unsigned char err; + unsigned short pi; + unsigned short ps[12]; /* 4 ps */ + unsigned short other_rds[87]; /* 0~29 other groups */ + unsigned char other_rds_cnt; /* # of other group */ +}; + +struct fm_rds_tx_req { + unsigned char pty; /* 0~31 integer */ + unsigned char rds_rbds; /* 0:RDS, 1:RBDS */ + unsigned char dyn_pty; /* 0:static, 1:dynamic */ + unsigned short pi_code; /* 2-byte hex */ + unsigned char ps_buf[8]; /* hex buf of PS */ + unsigned char ps_len; /* length of PS, must be 0 / 8" */ + unsigned char af; /* 0~204, 0:not used, 1~204:(87.5+0.1*af)MHz */ + unsigned char ah; /* Artificial head, 0:no, 1:yes */ + unsigned char stereo; /* 0:mono, 1:stereo */ + unsigned char compress; /* Audio compress, 0:no, 1:yes */ + unsigned char tp; /* traffic program, 0:no, 1:yes */ + unsigned char ta; /* traffic announcement, 0:no, 1:yes */ + unsigned char speech; /* 0:music, 1:speech */ +}; + +#define TX_SCAN_MAX 10 +#define TX_SCAN_MIN 1 + +struct fm_tx_scan_parm { + unsigned char err; + unsigned char band; /* 87.6~108MHz */ + unsigned char space; + unsigned char hilo; + unsigned short freq; /* start freq, if less than band min freq, then will use band min freq */ + unsigned char scandir; + unsigned short ScanTBL[TX_SCAN_MAX]; /* need no less than the chip */ + unsigned short ScanTBLSize; /* IN: desired size, OUT: scan result size */ +}; + +struct fm_gps_rtc_info { + signed int err; /* error number, 0: success, other: err code */ + signed int retryCnt; /* GPS mnl can decide retry times */ + signed int ageThd; /* GPS 3D fix time diff threshold */ + signed int driftThd; /* GPS RTC drift threshold */ + struct timeval tvThd; /* time value diff threshold */ + signed int age; /* GPS 3D fix time diff */ + signed int drift; /* GPS RTC drift */ + union { + unsigned long stamp; /* time stamp in jiffies */ + struct timeval tv; /* time stamp value in RTC */ + }; + signed int flag; /* rw flag */ +}; + +struct fm_desense_check_t { + signed int freq; + signed int rssi; +}; + +struct fm_full_cqi_log_t { + uint16_t lower; /* lower band, Eg, 7600 -> 76.0Mhz */ + uint16_t upper; /* upper band, Eg, 10800 -> 108.0Mhz */ + int space; /* 0x1: 50KHz, 0x2: 100Khz, 0x4: 200Khz */ + int cycle; /* repeat times */ +}; + +enum { + FM_RX = 0, + FM_TX = 1 +}; + +struct fm_ctl_parm { + unsigned char err; + unsigned char addr; + unsigned short val; + unsigned short rw_flag; /* 0:write, 1:read */ +}; +struct fm_em_parm { + unsigned short group_idx; + unsigned short item_idx; + unsigned int item_value; +}; +struct fm_top_rw_parm { + unsigned char err; + unsigned char rw_flag; /* 0:write, 1:read */ + unsigned short addr; + unsigned int val; +}; +struct fm_host_rw_parm { + unsigned char err; + unsigned char rw_flag; /* 0:write, 1:read */ + unsigned int addr; + unsigned int val; +}; +struct fm_pmic_rw_parm { + unsigned char err; + unsigned char rw_flag; /* 0:write, 1:read */ + unsigned char addr; + unsigned int val; +}; +enum { + FM_SUBSYS_RST_OFF, + FM_SUBSYS_RST_START, + FM_SUBSYS_RST_END, + FM_SUBSYS_RST_MAX +}; +enum { + FM_TX_PWR_CTRL_DISABLE, + FM_TX_PWR_CTRL_ENABLE, + FM_TX_PWR_CTRL_MAX +}; + +enum { + FM_TX_RTC_CTRL_DISABLE, + FM_TX_RTC_CTRL_ENABLE, + FM_TX_RTC_CTRL_MAX +}; + +enum { + FM_TX_DESENSE_DISABLE, + FM_TX_DESENSE_ENABLE, + FM_TX_DESENSE_MAX +}; + +struct fm_softmute_tune_t { + signed int rssi; /* RSSI of current channel */ + unsigned short freq; /* current frequency */ + signed int valid; /* current channel is valid(true) or not(false) */ +}; +struct fm_search_threshold_t { + signed int th_type; /* 0, RSSI. 1,desense RSSI. 2,SMG. */ + signed int th_val; /* threshold value */ + signed int reserve; +}; + +struct fm_status_t { + int which; + bool stat; +}; + +struct fm_chip_mapping { + unsigned short con_chip; + unsigned short fm_chip; + enum fm_cfg_chip_type type; +}; + +/* init and deinit APIs */ +extern signed int fm_env_setup(void); +extern signed int fm_env_destroy(void); +extern struct fm *fm_dev_init(unsigned int arg); +extern signed int fm_dev_destroy(struct fm *fm); + +/* fm main basic APIs */ +extern enum fm_pwr_state fm_pwr_state_get(struct fm *fmp); +extern enum fm_pwr_state fm_pwr_state_set(struct fm *fmp, enum fm_pwr_state sta); +extern signed int fm_open(struct fm *fmp); +extern signed int fm_close(struct fm *fmp); +extern signed int fm_rds_read(struct fm *fmp, signed char *dst, signed int len); +extern signed int fm_powerup(struct fm *fm, struct fm_tune_parm *parm); +extern signed int fm_powerdown(struct fm *fm, int type); +extern signed int fm_cqi_get(struct fm *fm, signed int ch_num, signed char *buf, signed int buf_size); +extern signed int fm_get_hw_info(struct fm *pfm, struct fm_hw_info *req); +extern signed int fm_hwscan_stop(struct fm *fm); +extern signed int fm_ana_switch(struct fm *fm, signed int antenna); +extern signed int fm_setvol(struct fm *fm, unsigned int vol); +extern signed int fm_getvol(struct fm *fm, unsigned int *vol); +extern signed int fm_mute(struct fm *fm, unsigned int bmute); +extern signed int fm_getrssi(struct fm *fm, signed int *rssi); +extern signed int fm_read(struct fm *fm, unsigned char addr, unsigned short *val); +extern signed int fm_write(struct fm *fm, unsigned char addr, unsigned short val); +extern signed int fm_top_read(struct fm *fm, unsigned short addr, unsigned int *val); +extern signed int fm_top_write(struct fm *fm, unsigned short addr, unsigned int val); +extern signed int fm_host_read(struct fm *fm, unsigned int addr, unsigned int *val); +extern signed int fm_host_write(struct fm *fm, unsigned int addr, unsigned int val); +extern signed int fm_pmic_read(struct fm *fm, unsigned char addr, unsigned int *val); +extern signed int fm_pmic_write(struct fm *fm, unsigned char addr, unsigned int val); +extern signed int fm_chipid_get(struct fm *fm, unsigned short *chipid); +extern signed int fm_monostereo_get(struct fm *fm, unsigned short *ms); +extern signed int fm_monostereo_set(struct fm *fm, signed int ms); +extern signed int fm_pamd_get(struct fm *fm, unsigned short *pamd); +extern signed int fm_caparray_get(struct fm *fm, signed int *ca); +extern signed int fm_em_test(struct fm *fm, unsigned short group, unsigned short item, unsigned int val); +extern signed int fm_rds_onoff(struct fm *fm, unsigned short rdson_off); +extern signed int fm_rds_good_bc_get(struct fm *fm, unsigned short *gbc); +extern signed int fm_rds_bad_bc_get(struct fm *fm, unsigned short *bbc); +extern signed int fm_rds_bler_ratio_get(struct fm *fm, unsigned short *bbr); +extern signed int fm_rds_group_cnt_get(struct fm *fm, struct rds_group_cnt_t *dst); +extern signed int fm_rds_group_cnt_reset(struct fm *fm); +extern signed int fm_rds_log_get(struct fm *fm, struct rds_rx_t *dst, signed int *dst_len); +extern signed int fm_rds_block_cnt_reset(struct fm *fm); +extern signed int fm_i2s_set(struct fm *fm, signed int onoff, signed int mode, signed int sample); +extern signed int fm_get_i2s_info(struct fm *pfm, struct fm_i2s_info *req); +extern signed int fm_tune(struct fm *fm, struct fm_tune_parm *parm); +extern signed int fm_is_dese_chan(struct fm *pfm, unsigned short freq); +extern signed int fm_desense_check(struct fm *pfm, unsigned short freq, signed int rssi); +extern signed int fm_sys_state_get(struct fm *fmp); +extern signed int fm_sys_state_set(struct fm *fmp, signed int sta); +extern signed int fm_set_stat(struct fm *fmp, int which, bool stat); +extern signed int fm_get_stat(struct fm *fmp, int which, bool *stat); +extern signed int fm_subsys_reset(struct fm *fm); +extern signed int fm_cqi_log(void); +extern signed int fm_soft_mute_tune(struct fm *fm, struct fm_softmute_tune_t *parm); +extern signed int fm_pre_search(struct fm *fm); +extern signed int fm_restore_search(struct fm *fm); + +extern signed int fm_dump_reg(void); +extern signed int fm_get_gps_rtc_info(struct fm_gps_rtc_info *src); +extern signed int fm_over_bt(struct fm *fm, signed int flag); +extern signed int fm_set_search_th(struct fm *fm, struct fm_search_threshold_t parm); +extern signed int fm_get_aud_info(struct fm_audio_info_t *data); +/*tx function*/ +extern signed int fm_tx_support(struct fm *fm, signed int *support); + +extern signed int fm_powerup_tx(struct fm *fm, struct fm_tune_parm *parm); +extern signed int fm_tune_tx(struct fm *fm, struct fm_tune_parm *parm); +extern signed int fm_powerdowntx(struct fm *fm); +extern signed int fm_rds_tx(struct fm *fm, struct fm_rds_tx_parm *parm); +extern signed int fm_rdstx_support(struct fm *fm, signed int *support); +extern signed int fm_rdstx_enable(struct fm *fm, signed int enable); +extern signed int fm_tx_scan(struct fm *fm, struct fm_tx_scan_parm *parm); +signed int fm_full_cqi_logger(struct fm_full_cqi_log_t *setting); +signed int fm_rds_parser(struct rds_rx_t *rds_raw, signed int rds_size); + +#endif /* __FM_MAIN_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_patch.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_patch.h new file mode 100644 index 00000000000000..1dcfc8fbfb7423 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_patch.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FM_PATCH_H__ +#define __FM_PATCH_H__ + +enum { + FM_ROM_V1 = 0, + FM_ROM_V2 = 1, + FM_ROM_V3 = 2, + FM_ROM_V4 = 3, + FM_ROM_V5 = 4, + FM_ROM_MAX +}; + +struct fm_patch_tbl { + signed int idx; + signed char *patch; + signed char *coeff; + signed char *rom; + signed char *hwcoeff; +}; + +extern signed int fm_file_read(const signed char *filename, unsigned char *dst, signed int len, signed int position); + +extern signed int fm_file_write(const signed char *filename, unsigned char *dst, signed int len, signed int *ppos); + +#endif /* __FM_PATCH_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_rds.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_rds.h new file mode 100644 index 00000000000000..c2d74e9b6acbcf --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_rds.h @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FM_RDS_H__ +#define __FM_RDS_H__ +#include "fm_typedef.h" + +/* FM_RDS_DATA_CRC_FFOST */ +#define FM_RDS_GDBK_IND_A (0x08) +#define FM_RDS_GDBK_IND_B (0x04) +#define FM_RDS_GDBK_IND_C (0x02) +#define FM_RDS_GDBK_IND_D (0x01) +#define FM_RDS_DCO_FIFO_OFST (0x01E0) +#define FM_RDS_READ_DELAY (0x80) + +#define RDS_RX_BLOCK_PER_GROUP (4) +#define RDS_RX_GROUP_SIZE (2*RDS_RX_BLOCK_PER_GROUP) +#define MAX_RDS_RX_GROUP_CNT (12) +#define RDS_RT_MULTI_REV_TH 80 /* 100 */ +/* #define RDS_CBC_DEPENDENCY */ + +struct rds_packet_t { + unsigned short blkA; + unsigned short blkB; + unsigned short blkC; + unsigned short blkD; + unsigned short cbc; /* correct bit cnt */ + unsigned short crc; /* crc checksum */ +}; + +struct rds_rx_t { + unsigned short sin; + unsigned short cos; + struct rds_packet_t data[MAX_RDS_RX_GROUP_CNT]; +}; + +enum rds_ps_state_machine_t { + RDS_PS_START = 0, + RDS_PS_DECISION, + RDS_PS_GETLEN, + RDS_PS_DISPLAY, + RDS_PS_FINISH, + RDS_PS_MAX +}; + +enum rds_rt_state_machine_t { + RDS_RT_START = 0, + RDS_RT_DECISION, + RDS_RT_GETLEN, + RDS_RT_DISPLAY, + RDS_RT_FINISH, + RDS_RT_MAX +}; + +enum { + RDS_GRP_VER_A = 0, /* group version A */ + RDS_GRP_VER_B +}; + +enum rds_blk_t { + RDS_BLK_A = 0, + RDS_BLK_B, + RDS_BLK_C, + RDS_BLK_D, + RDS_BLK_MAX +}; + +/* For RDS feature, these strcutures also be defined in "fm.h" */ +struct rds_flag_t { + unsigned char TP; + unsigned char TA; + unsigned char Music; + unsigned char Stereo; + unsigned char Artificial_Head; + unsigned char Compressed; + unsigned char Dynamic_PTY; + unsigned char Text_AB; + unsigned int flag_status; +}; + +struct rds_ct_t { + unsigned short Month; + unsigned short Day; + unsigned short Year; + unsigned short Hour; + unsigned short Minute; + unsigned char Local_Time_offset_signbit; + unsigned char Local_Time_offset_half_hour; +}; + +struct rds_af_t { + signed short AF_Num; + signed short AF[2][25]; /* 100KHz */ + unsigned char Addr_Cnt; + unsigned char isMethod_A; + unsigned char isAFNum_Get; +}; + +struct rds_ps_t { + unsigned char PS[4][8]; + unsigned char Addr_Cnt; +}; + +struct rds_rt_t { + unsigned char TextData[4][64]; + unsigned char GetLength; + unsigned char isRTDisplay; + unsigned char TextLength; + unsigned char isTypeA; + unsigned char BufCnt; + unsigned short Addr_Cnt; +}; + +struct rds_raw_t { + signed int dirty; /* indicate if the data changed or not */ + signed int len; /* the data len form chip */ + unsigned char data[148]; +}; + +struct rds_group_cnt_t { + unsigned int total; + unsigned int groupA[16]; /* RDS groupA counter */ + unsigned int groupB[16]; /* RDS groupB counter */ +}; + +enum rds_group_cnt_op_t { + RDS_GROUP_CNT_READ = 0, + RDS_GROUP_CNT_WRITE, + RDS_GROUP_CNT_RESET, + RDS_GROUP_CNT_MAX +}; + +struct rds_group_cnt_req_t { + signed int err; + enum rds_group_cnt_op_t op; + struct rds_group_cnt_t gc; +}; + +struct rds_t { + struct rds_ct_t CT; + struct rds_flag_t RDSFlag; + unsigned short PI; + unsigned char Switch_TP; + unsigned char PTY; + struct rds_af_t AF_Data; + struct rds_af_t AFON_Data; + unsigned char Radio_Page_Code; + unsigned short Program_Item_Number_Code; + unsigned char Extend_Country_Code; + unsigned short Language_Code; + struct rds_ps_t PS_Data; + unsigned char PS_ON[8]; + struct rds_rt_t RT_Data; + /* will use RDSFlag_Struct RDSFlag->flag_status to check which event, is that ok? */ + unsigned short event_status; + struct rds_group_cnt_t gc; +}; + +/* Need care the following definition. */ +/* valid Rds Flag for notify */ +enum rds_flag_status_t { + RDS_FLAG_IS_TP = 0x0001, /* Program is a traffic program */ + RDS_FLAG_IS_TA = 0x0002, /* Program currently broadcasts a traffic ann. */ + RDS_FLAG_IS_MUSIC = 0x0004, /* Program currently broadcasts music */ + RDS_FLAG_IS_STEREO = 0x0008, /* Program is transmitted in stereo */ + RDS_FLAG_IS_ARTIFICIAL_HEAD = 0x0010, /* Program is an artificial head recording */ + RDS_FLAG_IS_COMPRESSED = 0x0020, /* Program content is compressed */ + RDS_FLAG_IS_DYNAMIC_PTY = 0x0040, /* Program type can change */ + RDS_FLAG_TEXT_AB = 0x0080 /* If this flag changes state, a new radio text string begins */ +}; + +enum rds_event_status_t { + RDS_EVENT_FLAGS = 0x0001, /* One of the RDS flags has changed state */ + RDS_EVENT_PI_CODE = 0x0002, /* The program identification code has changed */ + RDS_EVENT_PTY_CODE = 0x0004, /* The program type code has changed */ + RDS_EVENT_PROGRAMNAME = 0x0008, /* The program name has changed */ + RDS_EVENT_UTCDATETIME = 0x0010, /* A new UTC date/time is available */ + RDS_EVENT_LOCDATETIME = 0x0020, /* A new local date/time is available */ + RDS_EVENT_LAST_RADIOTEXT = 0x0040, /* A radio text string was completed */ + RDS_EVENT_AF = 0x0080, /* Current Channel RF signal strength too weak, need do AF switch */ + RDS_EVENT_AF_LIST = 0x0100, /* An alternative frequency list is ready */ + RDS_EVENT_AFON_LIST = 0x0200, /* An alternative frequency list is ready */ + RDS_EVENT_TAON = 0x0400, /* Other Network traffic announcement start */ + RDS_EVENT_TAON_OFF = 0x0800, /* Other Network traffic announcement finished. */ + RDS_EVENT_ECC_CODE = 0x1000, /* ECC code */ + RDS_EVENT_RDS = 0x2000, /* RDS Interrupt had arrived durint timer period */ + RDS_EVENT_NO_RDS = 0x4000, /* RDS Interrupt not arrived durint timer period */ + RDS_EVENT_RDS_TIMER = 0x8000 /* Timer for RDS Bler Check. ---- BLER block error rate */ +}; + +#define RDS_LOG_SIZE 1 +struct rds_log_t { + struct rds_rx_t rds_log[RDS_LOG_SIZE]; + signed int log_len[RDS_LOG_SIZE]; + unsigned int size; + unsigned int in; + unsigned int out; + unsigned int len; + signed int (*log_in)(struct rds_log_t *thiz, struct rds_rx_t *new_log, signed int new_len); + signed int (*log_out)(struct rds_log_t *thiz, struct rds_rx_t *dst, signed int *dst_len); +}; + +extern signed int rds_parser(struct rds_t *rds_dst, struct rds_rx_t *rds_raw, + signed int rds_size, unsigned short(*getfreq) (void)); +extern signed int rds_grp_counter_get(struct rds_group_cnt_t *dst, struct rds_group_cnt_t *src); +extern signed int rds_grp_counter_reset(struct rds_group_cnt_t *gc); +extern signed int rds_log_in(struct rds_log_t *thiz, struct rds_rx_t *new_log, signed int new_len); +extern signed int rds_log_out(struct rds_log_t *thiz, struct rds_rx_t *dst, signed int *dst_len); + +#define DEFINE_RDSLOG(name) \ + struct rds_log_t name = { \ + .size = RDS_LOG_SIZE, \ + .in = 0, \ + .out = 0, \ + .len = 0, \ + .log_in = rds_log_in, \ + .log_out = rds_log_out, \ + } + +#endif /* __FM_RDS_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_reg_utils.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_reg_utils.h new file mode 100644 index 00000000000000..ddeb47718256b4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_reg_utils.h @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2019 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef FM_REG_UTILS_H +#define FM_REG_UTILS_H + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/vmalloc.h> + +#include <fm_ext_api.h> + +/* SPI register address */ +#if CFG_FM_CONNAC2 +#define SYS_SPI_BASE_ADDR (0x0000) +#else +#define SYS_SPI_BASE_ADDR (0x6000) +#endif +#define SYS_SPI_STA (0x00 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_CRTL (0x04 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_DIV (0x08 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_FM_CTRL (0x0C + SYS_SPI_BASE_ADDR) + +/* control bit for SPI_STA */ +#define SYS_SPI_ADDR_CR_MASK (0x0FFF) +#define SYS_SPI_ADDR_CR_READ (0x01 << 12) +#define SYS_SPI_ADDR_CR_WRITE (0x00 << 12) + +#define SYS_SPI_ADDR_CR_WF1 (0x00 << 13) +#define SYS_SPI_ADDR_CR_WF (0x01 << 13) +#define SYS_SPI_ADDR_CR_BT (0x02 << 13) +#define SYS_SPI_ADDR_CR_FM (0x03 << 13) +#define SYS_SPI_ADDR_CR_GPS (0x04 << 13) +#define SYS_SPI_ADDR_CR_TOP (0x05 << 13) + +#define SYS_SPI_STA_WF_BUSY_ADDR SYS_SPI_STA +#define SYS_SPI_STA_WF_BUSY_MASK 0x0002 +#define SYS_SPI_STA_WF_BUSY_SHFT 1 + +#define SYS_SPI_STA_BT_BUSY_ADDR SYS_SPI_STA +#define SYS_SPI_STA_BT_BUSY_MASK 0x0004 +#define SYS_SPI_STA_BT_BUSY_SHFT 2 + +#define SYS_SPI_STA_FM_BUSY_ADDR SYS_SPI_STA +#define SYS_SPI_STA_FM_BUSY_MASK 0x0008 +#define SYS_SPI_STA_FM_BUSY_SHFT 3 + +#define SYS_SPI_STA_GPS_BUSY_ADDR SYS_SPI_STA +#define SYS_SPI_STA_GPS_BUSY_MASK 0x0010 +#define SYS_SPI_STA_GPS_BUSY_SHFT 4 + +#define SYS_SPI_STA_TOP_BUSY_ADDR SYS_SPI_STA +#define SYS_SPI_STA_TOP_BUSY_MASK 0x0020 +#define SYS_SPI_STA_TOP_BUSY_SHFT 5 + +/* control bit for SPI_STA */ +#define SYS_SPI_CRTL_MASTER_EN_ADDR SYS_SPI_CRTL +#define SYS_SPI_CRTL_MASTER_EN_MASK 0x8000 +#define SYS_SPI_CRTL_MASTER_EN_SHFT 15 + +/* control bit for SPI_DIV */ +#define SYS_SPI_DIV_DIV_CNT_ADDR SYS_SPI_DIV +#define SYS_SPI_DIV_DIV_CNT_MASK 0x00FF +#define SYS_SPI_DIV_DIV_CNT_SHFT 0 + +/* control bit for SPI_FM_CTRL */ +#define SYS_SPI_FM_CTRL_FM_RD_EXT_CNT_ADDR SYS_SPI_FM_CTRL +#define SYS_SPI_FM_CTRL_FM_RD_EXT_CNT_MASK 0x00FF +#define SYS_SPI_FM_CTRL_FM_RD_EXT_CNT_SHFT 0 + +#define SYS_SPI_FM_CTRL_FM_RD_EXT_EN_ADDR SYS_SPI_FM_CTRL +#define SYS_SPI_FM_CTRL_FM_RD_EXT_EN_MASK 0x8000 +#define SYS_SPI_FM_CTRL_FM_RD_EXT_EN_SHFT 15 + +/* WIFI data addr & mask */ +#define SYS_SPI_WF_ADDR_ADDR (0x10 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_WF_ADDR_MASK 0xFFFF +#define SYS_SPI_WF_ADDR_SHFT 0 + +#define SYS_SPI_WF_WDAT_ADDR (0x14 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_WF_WDAT_MASK 0xFFFFFFFF +#define SYS_SPI_WF_WDAT_SHFT 0 + +#define SYS_SPI_WF_RDAT_ADDR (0x18 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_WF_RDAT_MASK 0xFFFFFFFF +#define SYS_SPI_WF_RDAT_SHFT 0 + +/* BT data addr & mask */ +#define SYS_SPI_BT_ADDR_ADDR (0x20 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_BT_ADDR_MASK 0xFFFF +#define SYS_SPI_BT_ADDR_SHFT 0 + +#define SYS_SPI_BT_WDAT_ADDR (0x24 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_BT_WDAT_MASK 0xFF +#define SYS_SPI_BT_WDAT_SHFT 0 + +#define SYS_SPI_BT_RDAT_ADDR (0x28 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_BT_RDAT_MASK 0xFF +#define SYS_SPI_BT_RDAT_SHFT 0 + +/* FM data addr & mask */ +#define SYS_SPI_FM_ADDR_ADDR (0x30 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_FM_ADDR_MASK 0xFFFF +#define SYS_SPI_FM_ADDR_SHFT 0 + +#define SYS_SPI_FM_WDAT_ADDR (0x34 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_FM_WDAT_MASK 0xFFFF +#define SYS_SPI_FM_WDAT_SHFT 0 + +#define SYS_SPI_FM_RDAT_ADDR (0x38 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_FM_RDAT_MASK 0xFFFF +#define SYS_SPI_FM_RDAT_SHFT 0 + +/* GPS data addr & mask */ +#define SYS_SPI_GPS_ADDR_ADDR (0x40 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_GPS_ADDR_MASK 0xFFFF +#define SYS_SPI_GPS_ADDR_SHFT 0 + +#define SYS_SPI_GPS_WDAT_ADDR (0x44 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_GPS_WDAT_MASK 0xFFFFFFFF +#define SYS_SPI_GPS_WDAT_SHFT 0 + +#define SYS_SPI_GPS_RDAT_ADDR (0x48 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_GPS_RDAT_MASK 0xFFFFFFFF +#define SYS_SPI_GPS_RDAT_SHFT 0 + +/* TOP data addr & mask */ +#define SYS_SPI_TOP_ADDR_ADDR (0x50 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_TOP_ADDR_MASK 0xFFFF +#define SYS_SPI_TOP_ADDR_SHFT 0 + +#define SYS_SPI_TOP_WDAT_ADDR (0x54 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_TOP_WDAT_MASK 0xFFFFFFFF +#define SYS_SPI_TOP_WDAT_SHFT 0 + +#define SYS_SPI_TOP_RDAT_ADDR (0x58 + SYS_SPI_BASE_ADDR) +#define SYS_SPI_TOP_RDAT_MASK 0xFFFFFFFF +#define SYS_SPI_TOP_RDAT_SHFT 0 + +/* A-die TOP SPI registers */ +#define SYSCTL_HW_ID 0x24 +#define SYSCTL_ADIE_TOP_THADC 0xC4 +#define SYSCTL_CLK_STATUS 0xA00 +#define SYSCTL_WF_CLK_EN 0xA04 +#define SYSCTL_BT_CLK_EN 0xA08 +#define SYSCTL_GPS_CLK_EN 0xA0C +#define SYSCTL_TOP_CLK_EN 0xA10 + +#define SYSCTL_EFUSE_SIZE 32 +#define SYSCTL_Macro0_Efuse_D0 0x11C +#define SYSCTL_Macro1_Efuse_D0 0x124 + +/* FM basic-operation's opcode */ +#define FM_BOP_BASE (0x80) +enum { + FM_WRITE_BASIC_OP = (FM_BOP_BASE + 0x00), + FM_UDELAY_BASIC_OP = (FM_BOP_BASE + 0x01), + FM_RD_UNTIL_BASIC_OP = (FM_BOP_BASE + 0x02), + FM_MODIFY_BASIC_OP = (FM_BOP_BASE + 0x03), + FM_MSLEEP_BASIC_OP = (FM_BOP_BASE + 0x04), + FM_WRITE_SPI_BASIC_OP = (FM_BOP_BASE + 0x05), + FM_RD_SPI_UNTIL_BASIC_OP = (FM_BOP_BASE + 0x06), + FM_MODIFY_SPI_BASIC_OP = (FM_BOP_BASE + 0x07), + FM_MAX_BASIC_OP = (FM_BOP_BASE + 0x08) +}; + +/* FM SPI control registers */ +#define FSPI_MAS_BASE (0x80060000) +#define FSPI_MAS_CONTROL_REG (FSPI_MAS_BASE + 0x0000) +#define FSPI_MAS_ADDR_REG (FSPI_MAS_BASE + 0x0004) +#define FSPI_MAS_WRDATA_REG (FSPI_MAS_BASE + 0x0008) +#define FSPI_MAS_RDDATA_REG (FSPI_MAS_BASE + 0x000C) +#define FSPI_MAS_CFG1_REG (FSPI_MAS_BASE + 0x0010) +#define FSPI_MAS_CFG2_REG (FSPI_MAS_BASE + 0x0014) +#define FSPI_MAS_MODESEL_REG (FSPI_MAS_BASE + 0x0020) +#define FSPI_MAS_RESET_REG (FSPI_MAS_BASE + 0x0030) +#define FSPI_MAS_DEBUG1_REG (FSPI_MAS_BASE + 0x0034) +#define FSPI_MAS_DEBUG2_REG (FSPI_MAS_BASE + 0x0038) +#define FSPI_MAS_DEBUG3_REG (FSPI_MAS_BASE + 0x003C) +#define FSPI_MAS_DEBUG4_REG (FSPI_MAS_BASE + 0x0040) +#define FSPI_MAS_DEBUG5_REG (FSPI_MAS_BASE + 0x0048) + +/* FM Main Control Register */ +#define FM_MAIN_CTRL_TUNE (0x0001) +#define FM_MAIN_CTRL_SEEK (0x0002) +#define FM_MAIN_CTRL_SCAN (0x0004) +#define FM_MAIN_CTRL_DSP_INIT (0x0008) +#define FM_MAIN_CTRL_SCAN_CQI (0x0008) +#define FM_MAIN_CTRL_RDS (0x0010) +#define FM_MAIN_CTRL_DCOC (0x0020) +#define FM_MAIN_CTRL_MUTE (0x0040) +#define FM_MAIN_CTRL_IQCAL (0x0080) +#define FM_MAIN_CTRL_RAMPDOWN (0x0100) +#define FM_MAIN_CTRL_MEM_FLUSH (0x0200) +#define FM_MAIN_CTRL_MASK (0x0Fff) + +/* RDS control registers */ +#define FM_RDS_BASE (0x0) +#define RDS_INFO_REG (FM_RDS_BASE + 0x81) +#define RDS_CRC_CORR_CNT 0x001E +#define RDS_CRC_INFO 0x0001 +#define RDS_DATA_REG (FM_RDS_BASE + 0x82) +#define SCAN_BUFF_LEN 0xF +#define RDS_SIN_REG (FM_RDS_BASE + 0x85) +#define RDS_COS_REG (FM_RDS_BASE + 0x86) +#define RDS_FIFO_STATUS0 (FM_RDS_BASE + 0x87) +#define RDS_POINTER (FM_RDS_BASE + 0xF0) + +/* RDS Interrupt Status Register */ +#define RDS_INTR_THRE (0x0001) +#define RDS_INTR_TO (0x0002) +#define RDS_INTR_FULL (0x0004) +#define RDS_INTR_MASK (0x0007) +#define RDS_TX_INTR_MASK (0x0070) +#define RDS_TX_INTR_EMPTY (0x0010) +#define RDS_TX_INTR_LOW (0x0020) +#define RDS_TX_INTR_FULL (0x0040) +#define RDS_TX_INTR_EMPTY_MASK (0x0001) +#define RDS_TX_INTR_LOW_MASK (0x0002) +#define RDS_TX_INTR_FULL_MASK (0x0004) + +/* RDS Data CRC Offset Register */ +#define RDS_DCO_FIFO_OFST (0x007C) +#define RDS_DCO_FIFO_OFST_SHFT 2 + +/* Parameter for RDS */ +/* total 12 groups */ +#define RDS_RX_FIFO_CNT (12) +/* delay 1us between each register read */ +#define RDS_READ_DELAY (1) +#define RDS_GROUP_READ_DELAY (85) +#define FIFO_LEN (48) + +/* Parameter for DSP download */ +#define OFFSET_REG 0x91 +#define CONTROL_REG 0x90 +#define DATA_REG 0x92 + +#define FM_SOFTMUTE_TUNE_CQI_SIZE 0x16 + +#define FM_SPI_COUNT_LIMIT 100000 + +#define FM_BUFFER_SIZE (2048) +#define FM_HDR_SIZE (4) + +/* FM main registers */ +enum { + FM_MAIN_MCLKDESENSE = 0x38, + FM_MAIN_CG1_CTRL = 0x60, + FM_MAIN_CG2_CTRL = 0x61, + FM_MAIN_HWVER = 0x62, + FM_MAIN_CTRL = 0x63, + FM_MAIN_EN1 = 0x64, + FM_CHANNEL_SET = 0x65, + FM_MAIN_CFG1 = 0x66, + FM_MAIN_CFG2 = 0x67, + FM_MAIN_CFG3 = 0x68, + FM_MAIN_INTR = 0x69, + FM_MAIN_INTRMASK = 0x6A, + FM_MAIN_EXTINTRMASK = 0x6B, + FM_RSSI_IND = 0x6C, + FM_RSSI_TH = 0x6D, + FM_MAIN_RESET = 0x6E, + FM_MAIN_CHANDETSTAT = 0x6F, + FM_MAIN_IQCOMP1 = 0x70, + FM_MAIN_IQCOMP2 = 0x71, + FM_MAIN_IQCOMP3 = 0x72, + FM_MAIN_IQCOMP4 = 0x73, + FM_MAIN_RXCALSTAT1 = 0x74, + FM_MAIN_RXCALSTAT2 = 0x75, + FM_MAIN_RXCALSTAT3 = 0x76, + FM_MAIN_MCLKDESENSE2 = 0x77, + FM_MAIN_MCLKDESENSE3 = 0x78, + FM_MAIN_CHNLSCAN_CTRL = 0x79, + FM_MAIN_CHNLSCAN_STAT = 0x7a, + FM_MAIN_CHNLSCAN_STAT2 = 0x7b, + FM_RDS_CFG0 = 0x80, + FM_RDS_INFO = 0x81, + FM_RDS_DATA_REG = 0x82, + FM_RDS_GOODBK_CNT = 0x83, + FM_RDS_BADBK_CNT = 0x84, + FM_RDS_PWDI = 0x85, + FM_RDS_PWDQ = 0x86, + FM_RDS_FIFO_STATUS0 = 0x87, + FM_FT_CON9 = 0x8F, + FM_DSP_PATCH_CTRL = 0x90, + FM_DSP_PATCH_OFFSET = 0x91, + FM_DSP_PATCH_DATA = 0x92, + FM_DSP_MEM_CTRL4 = 0x93, + FM_MAIN_PGSEL = 0x9f, + FM_ADDR_PAMD = 0xB4, + FM_RDS_BDGRP_ABD_CTRL_REG = 0xB6, + FM_RDS_POINTER = 0xF0, +}; + +/* FM Main Interrupt Register */ +enum { + FM_INTR_STC_DONE = 0x0001, + FM_INTR_IQCAL_DONE = 0x0002, + FM_INTR_DESENSE_HIT = 0x0004, + FM_INTR_CHNL_CHG = 0x0008, + FM_INTR_SW_INTR = 0x0010, + FM_INTR_RDS = 0x0020, + FM_INTR_CQI = 0x0021, + FM_INTR_MASK = 0x003f +}; + +enum { + DSP_ROM = 0, + DSP_PATCH, + DSP_COEFF, + DSP_HWCOEFF +}; + +struct fm_wcn_reg_info { + phys_addr_t spi_phy_addr; + void __iomem *spi_vir_addr; + unsigned int spi_size; + phys_addr_t top_phy_addr; + void __iomem *top_vir_addr; + unsigned int top_size; + phys_addr_t mcu_phy_addr; + void __iomem *mcu_vir_addr; + unsigned int mcu_size; +}; + +struct fm_spi_interface { + struct fm_wcn_reg_info info; + void (*spi_read)(struct fm_spi_interface *si, unsigned int addr, unsigned int *val); + void (*spi_write)(struct fm_spi_interface *si, unsigned int addr, unsigned int val); + void (*host_read)(struct fm_spi_interface *si, unsigned int addr, unsigned int *val); + void (*host_write)(struct fm_spi_interface *si, unsigned int addr, unsigned int val); + int (*sys_spi_read)(struct fm_spi_interface *si, unsigned int subsystem, + unsigned int addr, unsigned int *data); + int (*sys_spi_write)(struct fm_spi_interface *si, unsigned int subsystem, + unsigned int addr, unsigned int data); + bool (*set_own)(void); + bool (*clr_own)(void); +}; + +struct fm_wcn_reg_ops { + struct fm_ext_interface ei; + struct fm_spi_interface si; + unsigned char rx_buf[FM_BUFFER_SIZE]; + unsigned int rx_len; + struct fm_lock *tx_lock; + struct fm_lock *own_lock; +}; + +struct fm_full_cqi { + unsigned short ch; + unsigned short rssi; + unsigned short pamd; + unsigned short pr; + unsigned short fpamd; + unsigned short mr; + unsigned short atdc; + unsigned short prx; + unsigned short atdev; + unsigned short smg; /* soft-mute gain */ + unsigned short drssi; /* delta rssi */ +}; + +/* FM interface */ +int fm_ioremap_read(phys_addr_t addr, unsigned int *val); +int fm_ioremap_write(phys_addr_t addr, unsigned int val); +void fw_spi_read(unsigned char addr, unsigned short *data); +void fw_spi_write(unsigned char addr, unsigned short data); +void fw_bop_udelay(unsigned int usec); +void fw_bop_rd_until(unsigned char addr, unsigned short mask, + unsigned short value); +void fw_bop_modify(unsigned char addr, unsigned short mask_and, + unsigned short mask_or); +void fw_bop_spi_rd_until(unsigned char subsys, unsigned short addr, + unsigned int mask, unsigned int value); +void fw_bop_spi_modify(unsigned char subsys, unsigned short addr, + unsigned int mask_and, unsigned int mask_or); + +extern struct fm_wcn_reg_ops fm_wcn_ops; + +#endif /* FM_REG_UTILS_H */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_stdlib.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_stdlib.h new file mode 100644 index 00000000000000..4922e6f5864121 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_stdlib.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FM_STDLIB_H__ +#define __FM_STDLIB_H__ + +#include "fm_typedef.h" +#include <linux/string.h> +#include <linux/slab.h> + +#if 1 +#define fm_memset(buf, a, len) \ +({ \ + void *__ret = (void *)0; \ + __ret = memset((buf), (a), (len)); \ + __ret; \ +}) + +#define fm_memcpy(dst, src, len) \ +({ \ + void *__ret = (void *)0; \ + __ret = memcpy((dst), (src), (len)); \ + __ret; \ +}) + +#define fm_malloc(len) \ +({ \ + void *__ret = (void *)0; \ + __ret = kmalloc(len, GFP_KERNEL); \ + __ret; \ +}) + +#define fm_zalloc(len) \ +({ \ + void *__ret = (void *)0; \ + __ret = kzalloc(len, GFP_KERNEL); \ + __ret; \ +}) + +#define fm_free(ptr) kfree(ptr) + +#define fm_vmalloc(len) \ +({ \ + void *__ret = (void *)0; \ + __ret = vmalloc(len); \ + __ret; \ +}) + +#define fm_vfree(ptr) vfree(ptr) + +#else +inline void *fm_memset(void *buf, signed char val, signed int len) +{ + return memset(buf, val, len); +} + +inline void *fm_memcpy(void *dst, const void *src, signed int len) +{ + return memcpy(dst, src, len); +} + +#endif + +#endif /* __FM_STDLIB_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_typedef.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_typedef.h new file mode 100644 index 00000000000000..9d9039463a0d05 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_typedef.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FM_TYPEDEF_H__ +#define __FM_TYPEDEF_H__ + + +#endif /* __FM_TYPEDEF_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/inc/fm_utils.h b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_utils.h new file mode 100644 index 00000000000000..57469823081dcf --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/inc/fm_utils.h @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __FM_UTILS_H__ +#define __FM_UTILS_H__ + +#include "fm_typedef.h" + +/** +* Base structure of fm object +*/ +#define FM_NAME_MAX 20 +struct fm_object { + signed char name[FM_NAME_MAX + 1]; /* name of fm object */ + unsigned char type; /* type of fm object */ + unsigned char flag; /* flag of fm object */ + signed int ref; + void *priv; +}; + +/* + * FM FIFO + */ +struct fm_fifo { + struct fm_object obj; + signed int size; + signed int in; + signed int out; + signed int len; + signed int item_size; + signed int (*input)(struct fm_fifo *thiz, void *item); + signed int (*output)(struct fm_fifo *thiz, void *item); + bool (*is_full)(struct fm_fifo *thiz); + bool (*is_empty)(struct fm_fifo *thiz); + signed int (*get_total_len)(struct fm_fifo *thiz); + signed int (*get_valid_len)(struct fm_fifo *thiz); + signed int (*reset)(struct fm_fifo *thiz); +}; + +extern struct fm_fifo *fm_fifo_init(struct fm_fifo *fifo, void *buf, const signed char *name, + signed int item_size, signed int item_num); + +extern struct fm_fifo *fm_fifo_create(const signed char *name, signed int item_size, signed int item_num); + +extern signed int fm_fifo_release(struct fm_fifo *fifo); + +#define FM_FIFO_INPUT(fifop, item) \ +({ \ + signed int __ret = (signed int)0; \ + if (fifop && (fifop)->input) { \ + __ret = (fifop)->input(fifop, item); \ + } \ + __ret; \ +}) + +#define FM_FIFO_OUTPUT(fifop, item) \ +({ \ + signed int __ret = (signed int)0; \ + if (fifop && (fifop)->output) { \ + __ret = (fifop)->output(fifop, item); \ + } \ + __ret; \ +}) + +#define FM_FIFO_IS_FULL(fifop) \ +({ \ + bool __ret = false; \ + if (fifop && (fifop)->is_full) { \ + __ret = (fifop)->is_full(fifop); \ + } \ + __ret; \ +}) + +#define FM_FIFO_IS_EMPTY(fifop) \ +({ \ + bool __ret = false; \ + if (fifop && (fifop)->is_empty) { \ + __ret = (fifop)->is_empty(fifop); \ + } \ + __ret; \ +}) + +#define FM_FIFO_RESET(fifop) \ +({ \ + signed int __ret = (signed int)0; \ + if (fifop && (fifop)->reset) { \ + __ret = (fifop)->reset(fifop); \ + } \ + __ret; \ +}) + +#define FM_FIFO_GET_TOTAL_LEN(fifop) \ +({ \ + signed int __ret = (signed int)0; \ + if (fifop && (fifop)->get_total_len) { \ + __ret = (fifop)->get_total_len(fifop); \ + } \ + __ret; \ +}) + +#define FM_FIFO_GET_VALID_LEN(fifop) \ +({ \ + signed int __ret = (signed int)0; \ + if (fifop && (fifop)->get_valid_len) { \ + __ret = (fifop)->get_valid_len(fifop); \ + } \ + __ret; \ +}) + +/* + * FM asynchronous information mechanism + */ +struct fm_flag_event { + signed int ref; + signed char name[FM_NAME_MAX + 1]; + void *priv; + + unsigned int flag; + + /* flag methods */ + unsigned int (*send)(struct fm_flag_event *thiz, unsigned int mask); + signed int (*wait)(struct fm_flag_event *thiz, unsigned int mask); + long (*wait_timeout)(struct fm_flag_event *thiz, unsigned int mask, long timeout); + unsigned int (*clr)(struct fm_flag_event *thiz, unsigned int mask); + unsigned int (*get)(struct fm_flag_event *thiz); + unsigned int (*rst)(struct fm_flag_event *thiz); +}; + +extern struct fm_flag_event *fm_flag_event_create(const signed char *name); + +extern signed int fm_flag_event_get(struct fm_flag_event *thiz); + +extern signed int fm_flag_event_put(struct fm_flag_event *thiz); + +#define FM_EVENT_SEND(eventp, mask) \ +({ \ + unsigned int __ret = (unsigned int)0; \ + if (eventp && (eventp)->send) { \ + __ret = (eventp)->send(eventp, mask); \ + } \ + __ret; \ +}) + +#define FM_EVENT_WAIT(eventp, mask) \ +({ \ + signed int __ret = (signed int)0; \ + if (eventp && (eventp)->wait) { \ + __ret = (eventp)->wait(eventp, mask); \ + } \ + __ret; \ +}) + +#define FM_EVENT_WAIT_TIMEOUT(eventp, mask, timeout) \ +({ \ + long __ret = (long)0; \ + if (eventp && (eventp)->wait_timeout) { \ + __ret = (eventp)->wait_timeout(eventp, mask, timeout); \ + } \ + __ret; \ +}) + +#define FM_EVENT_GET(eventp) \ +({ \ + unsigned int __ret = (unsigned int)0; \ + if (eventp && (eventp)->get) { \ + __ret = (eventp)->get(eventp); \ + } \ + __ret; \ +}) + +#define FM_EVENT_RESET(eventp) \ +({ \ + unsigned int __ret = (unsigned int)0; \ + if (eventp && (eventp)->rst) { \ + __ret = (eventp)->rst(eventp); \ + } \ + __ret; \ +}) + +#define FM_EVENT_CLR(eventp, mask) \ +({ \ + unsigned int __ret = (unsigned int)0; \ + if (eventp && (eventp)->clr) { \ + __ret = (eventp)->clr(eventp, mask); \ + } \ + __ret; \ +}) + +/* + * FM lock mechanism + */ +struct fm_lock { + signed char name[FM_NAME_MAX + 1]; + signed int ref; + void *priv; + + /* lock methods */ + signed int (*lock)(struct fm_lock *thiz); + signed int (*trylock)(struct fm_lock *thiz, signed int retryCnt); + signed int (*unlock)(struct fm_lock *thiz); +}; + +extern struct fm_lock *fm_lock_create(const signed char *name); + +extern signed int fm_lock_get(struct fm_lock *thiz); + +extern signed int fm_lock_put(struct fm_lock *thiz); + +extern struct fm_lock *fm_spin_lock_create(const signed char *name); + +extern signed int fm_spin_lock_get(struct fm_lock *thiz); + +extern signed int fm_spin_lock_put(struct fm_lock *thiz); + +#define FM_LOCK(a) \ + ({ \ + signed int __ret = (signed int)0; \ + if (!a) { \ + __ret = -1; \ + } else if ((a)->lock) { \ + __ret = (a)->lock(a); \ + } \ + __ret; \ + }) + +#define FM_UNLOCK(a) \ + { \ + if (a && (a)->unlock) { \ + (a)->unlock(a); \ + } \ + } + +/* + * FM timer mechanism + */ +enum fm_timer_ctrl { + FM_TIMER_CTRL_GET_TIME = 0, + FM_TIMER_CTRL_SET_TIME = 1, + FM_TIMER_CTRL_MAX +}; + +#define FM_TIMER_FLAG_ACTIVATED (1<<0) + +struct fm_timer { + signed int ref; + signed char name[FM_NAME_MAX + 1]; + void *priv; /* platform detail impliment */ + + signed int flag; /* timer active/inactive */ + void (*timeout_func)(unsigned long data); /* timeout function */ + unsigned long data; /* timeout function's parameter */ + signed long timeout_ms; /* timeout tick */ + /* Tx parameters */ + unsigned int count; + unsigned char tx_pwr_ctrl_en; + unsigned char tx_rtc_ctrl_en; + unsigned char tx_desense_en; + + /* timer methods */ + signed int (*init)(struct fm_timer *thiz, void (*timeout) (unsigned long data), + unsigned long data, signed long time, signed int flag); + signed int (*start)(struct fm_timer *thiz); + signed int (*update)(struct fm_timer *thiz); + signed int (*stop)(struct fm_timer *thiz); + signed int (*control)(struct fm_timer *thiz, enum fm_timer_ctrl cmd, void *arg); +}; + +extern struct fm_timer *fm_timer_create(const signed char *name); + +extern signed int fm_timer_get(struct fm_timer *thiz); + +extern signed int fm_timer_put(struct fm_timer *thiz); + +/* + * FM work thread mechanism + */ +struct fm_work { + signed int ref; + signed char name[FM_NAME_MAX + 1]; + void *priv; + + void (*work_func)(unsigned long data); + unsigned long data; + /* work methods */ + signed int (*init)(struct fm_work *thiz, void (*work_func) (unsigned long data), unsigned long data); +}; + +extern struct fm_work *fm_work_create(const signed char *name); + +extern signed int fm_work_get(struct fm_work *thiz); + +extern signed int fm_work_put(struct fm_work *thiz); + +struct fm_workthread { + signed int ref; + signed char name[FM_NAME_MAX + 1]; + void *priv; + + /* workthread methods */ + signed int (*add_work)(struct fm_workthread *thiz, struct fm_work *work); +}; + +extern struct fm_workthread *fm_workthread_create(const signed char *name); + +extern signed int fm_workthread_get(struct fm_workthread *thiz); + +extern signed int fm_workthread_put(struct fm_workthread *thiz); + +signed int fm_delayms(unsigned int data); + +signed int fm_delayus(unsigned int data); + +unsigned short fm_get_u16_from_auc(unsigned char *buf); + +void fm_set_u16_to_auc(unsigned char *buf, unsigned short val); + +unsigned int fm_get_u32_from_auc(unsigned char *buf); + +void fm_set_u32_to_auc(unsigned char *buf, unsigned int val); + +#endif /* __FM_UTILS_H__ */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/init.fmradio_drv.rc b/drivers/misc/mediatek/connectivity/fmradio/init.fmradio_drv.rc new file mode 100644 index 00000000000000..d1111d0c41c48f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/init.fmradio_drv.rc @@ -0,0 +1,5 @@ + +# load fmradio_drv +on property:vendor.connsys.driver.ready=yes + insmod /vendor/lib/modules/fmradio_drv.ko + diff --git a/drivers/misc/mediatek/connectivity/fmradio/plat/conn_infra.c b/drivers/misc/mediatek/connectivity/fmradio/plat/conn_infra.c new file mode 100644 index 00000000000000..e26643e9188a2b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/plat/conn_infra.c @@ -0,0 +1,1438 @@ +/* + * Copyright (C) 2019 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include "plat.h" + +/* CONNSYS register address */ +#if CFG_FM_CONNAC2 +#define AP_BASE_ADDRESS 0x18000000 +#define MCU_CFG_ADDR (AP_BASE_ADDRESS + 0x0) +#define MCU_CFG_CONSYS_BASE MCU_CFG_ADDR +#define MCU_CFG_SIZE 0x10000 +#define TOP_MISC_OFF_ADDR (AP_BASE_ADDRESS + 0x60000) +#define TOP_MISC_OFF_CONSYS_BASE TOP_MISC_OFF_ADDR +#define TOP_MISC_OFF_SIZE 0x1000 +#define TOP_RF_SPI_AON_ADDR (AP_BASE_ADDRESS + 0x4000) +#define TOP_RF_SPI_AON_CONSYS_BASE TOP_RF_SPI_AON_ADDR +#define TOP_RF_SPI_AON_SIZE 0x1000 +#else +#define AP_BASE_ADDRESS 0x18000000 +#define MCU_CFG_ADDR (AP_BASE_ADDRESS + 0x02000) +#define MCU_CFG_CONSYS_BASE 0x80000000 +#define MCU_CFG_SIZE 0x1000 +#define TOP_MISC_OFF_ADDR (AP_BASE_ADDRESS + 0xB0000) +#define TOP_MISC_OFF_CONSYS_BASE 0x80020000 +#define TOP_MISC_OFF_SIZE 0x10000 +#define TOP_RF_SPI_AON_ADDR (AP_BASE_ADDRESS + 0xC0000) +#define TOP_RF_SPI_AON_CONSYS_BASE 0x81020000 +#define TOP_RF_SPI_AON_SIZE 0x10000 +#endif /* CFG_FM_CONNAC2 */ + +#define FM_IRQ_NUMBER 0 +#define MAX_SET_OWN_COUNT 1000 + +#if CFG_FM_CONNAC2 +static int (*whole_chip_reset)(signed int sta); + +static int fm_pre_whole_chip_rst(void) +{ + WCN_DBG(FM_WAR | LINK, "FM pre whole chip rst!\n"); + if (whole_chip_reset) + whole_chip_reset(1); + return 0; +} + +static int fm_post_whole_chip_rst(void) +{ + WCN_DBG(FM_WAR | LINK, "FM post whole chip rst!\n"); + if (whole_chip_reset) + whole_chip_reset(0); + return 0; +} + +static struct sub_drv_ops_cb fm_drv_cbs = { + .rst_cb.pre_whole_chip_rst = fm_pre_whole_chip_rst, + .rst_cb.post_whole_chip_rst = fm_post_whole_chip_rst, + .pre_cal_cb.pwr_on_cb = NULL, + .pre_cal_cb.do_cal_cb = NULL, +}; + +static int drv_sys_spi_read( + struct fm_spi_interface *si, unsigned int subsystem, + unsigned int addr, unsigned int *data) +{ + WCN_DBG(FM_DBG | CHIP, "[0x%08x]=[0x%08x]\n", addr, *data); + return conninfra_spi_read(subsystem, addr, data); +} + +static int drv_sys_spi_write( + struct fm_spi_interface *si, unsigned int subsystem, + unsigned int addr, unsigned int data) +{ + WCN_DBG(FM_DBG | CHIP, "[0x%08x]=[0x%08x]\n", addr, data); + return conninfra_spi_write(subsystem, addr, data); +} +#else /* CFG_FM_CONNAC2 */ +static int sys_spi_wait(unsigned int spi_busy) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + unsigned int spi_count, rdata; + + /* It needs to prevent infinite loop */ + for (spi_count = 0; spi_count < FM_SPI_COUNT_LIMIT; spi_count++) { + si->spi_read(si, SYS_SPI_STA, &rdata); + if ((rdata & spi_busy) == 0) + break; + } + if (spi_count == FM_SPI_COUNT_LIMIT) { + WCN_DBG(FM_WAR | CHIP, + "SPI busy[0x%08x], retry count reached maximum.\n", + rdata); + return FM_SYS_SPI_BUSY; + } + return FM_SYS_SPI_OK; +} + +static int fm_sys_spi_read( + struct fm_spi_interface *si, unsigned int subsystem, + unsigned int addr, unsigned int *data) +{ + unsigned int spi_busy, spi_addr, spi_mask, spi_wdat, spi_rdat, rdata; + + if (!si->spi_read || !si->spi_write) { + WCN_DBG(FM_ERR | CHIP, "spi api is NULL.\n"); + return FM_SYS_SPI_ERR; + } + + switch (subsystem) { + case SYS_SPI_WF: + spi_busy = 1 << SYS_SPI_STA_WF_BUSY_SHFT; + spi_addr = SYS_SPI_WF_ADDR_ADDR; + spi_mask = SYS_SPI_WF_RDAT_MASK; + spi_wdat = SYS_SPI_WF_WDAT_ADDR; + spi_rdat = SYS_SPI_WF_RDAT_ADDR; + addr = SYS_SPI_ADDR_CR_READ | SYS_SPI_ADDR_CR_WF | (addr & SYS_SPI_ADDR_CR_MASK); + break; + case SYS_SPI_BT: + spi_busy = 1 << SYS_SPI_STA_BT_BUSY_SHFT; + spi_addr = SYS_SPI_BT_ADDR_ADDR; + spi_mask = SYS_SPI_BT_RDAT_MASK; + spi_wdat = SYS_SPI_BT_WDAT_ADDR; + spi_rdat = SYS_SPI_BT_RDAT_ADDR; + addr = SYS_SPI_ADDR_CR_READ | SYS_SPI_ADDR_CR_BT | (addr & SYS_SPI_ADDR_CR_MASK); + break; + case SYS_SPI_FM: + spi_busy = 1 << SYS_SPI_STA_FM_BUSY_SHFT; + spi_addr = SYS_SPI_FM_ADDR_ADDR; + spi_mask = SYS_SPI_FM_RDAT_MASK; + spi_wdat = SYS_SPI_FM_WDAT_ADDR; + spi_rdat = SYS_SPI_FM_RDAT_ADDR; + addr = SYS_SPI_ADDR_CR_READ | SYS_SPI_ADDR_CR_FM | (addr & SYS_SPI_ADDR_CR_MASK); + break; + case SYS_SPI_GPS: + spi_busy = 1 << SYS_SPI_STA_GPS_BUSY_SHFT; + spi_addr = SYS_SPI_GPS_ADDR_ADDR; + spi_mask = SYS_SPI_GPS_RDAT_MASK; + spi_wdat = SYS_SPI_GPS_WDAT_ADDR; + spi_rdat = SYS_SPI_GPS_RDAT_ADDR; + addr = SYS_SPI_ADDR_CR_READ | SYS_SPI_ADDR_CR_GPS | (addr & SYS_SPI_ADDR_CR_MASK); + break; + case SYS_SPI_TOP: + spi_busy = 1 << SYS_SPI_STA_TOP_BUSY_SHFT; + spi_addr = SYS_SPI_TOP_ADDR_ADDR; + spi_mask = SYS_SPI_TOP_RDAT_MASK; + spi_wdat = SYS_SPI_TOP_WDAT_ADDR; + spi_rdat = SYS_SPI_TOP_RDAT_ADDR; + addr = SYS_SPI_ADDR_CR_READ | SYS_SPI_ADDR_CR_TOP | (addr & SYS_SPI_ADDR_CR_MASK); + break; + case SYS_SPI_WF1: + spi_busy = 1 << SYS_SPI_STA_WF_BUSY_SHFT; + spi_addr = SYS_SPI_WF_ADDR_ADDR; + spi_mask = SYS_SPI_WF_RDAT_MASK; + spi_wdat = SYS_SPI_WF_WDAT_ADDR; + spi_rdat = SYS_SPI_WF_RDAT_ADDR; + addr = SYS_SPI_ADDR_CR_READ | SYS_SPI_ADDR_CR_WF1 | (addr & SYS_SPI_ADDR_CR_MASK); + break; + default: + return FM_SYS_SPI_ERR; + } + + if (sys_spi_wait(spi_busy) == FM_SYS_SPI_BUSY) + return FM_SYS_SPI_BUSY; + + si->spi_write(si, spi_addr, addr); + si->spi_write(si, spi_wdat, 0); + + sys_spi_wait(spi_busy); + + si->spi_read(si, spi_rdat, &rdata); + *data = rdata & spi_mask; + + WCN_DBG(FM_DBG | CHIP, "[0x%08x]=[0x%08x]\n", addr, *data); + + return FM_SYS_SPI_OK; +} + +static int fm_sys_spi_write( + struct fm_spi_interface *si, unsigned int subsystem, + unsigned int addr, unsigned int data) +{ + unsigned int spi_busy, spi_addr, spi_mask, spi_wdat; + + if (!si->spi_read || !si->spi_write) { + WCN_DBG(FM_ERR | CHIP, "spi api is NULL.\n"); + return FM_SYS_SPI_ERR; + } + + switch (subsystem) { + case SYS_SPI_WF: + spi_busy = 1 << SYS_SPI_STA_WF_BUSY_SHFT; + spi_addr = SYS_SPI_WF_ADDR_ADDR; + spi_mask = SYS_SPI_WF_WDAT_MASK; + spi_wdat = SYS_SPI_WF_WDAT_ADDR; + addr = SYS_SPI_ADDR_CR_WRITE | SYS_SPI_ADDR_CR_WF | (addr & SYS_SPI_ADDR_CR_MASK); + break; + case SYS_SPI_BT: + spi_busy = 1 << SYS_SPI_STA_BT_BUSY_SHFT; + spi_addr = SYS_SPI_BT_ADDR_ADDR; + spi_mask = SYS_SPI_BT_WDAT_MASK; + spi_wdat = SYS_SPI_BT_WDAT_ADDR; + addr = SYS_SPI_ADDR_CR_WRITE | SYS_SPI_ADDR_CR_BT | (addr & SYS_SPI_ADDR_CR_MASK); + break; + case SYS_SPI_FM: + spi_busy = 1 << SYS_SPI_STA_FM_BUSY_SHFT; + spi_addr = SYS_SPI_FM_ADDR_ADDR; + spi_mask = SYS_SPI_FM_WDAT_MASK; + spi_wdat = SYS_SPI_FM_WDAT_ADDR; + addr = SYS_SPI_ADDR_CR_WRITE | SYS_SPI_ADDR_CR_FM | (addr & SYS_SPI_ADDR_CR_MASK); + break; + case SYS_SPI_TOP: + spi_busy = 1 << SYS_SPI_STA_TOP_BUSY_SHFT; + spi_addr = SYS_SPI_TOP_ADDR_ADDR; + spi_mask = SYS_SPI_TOP_WDAT_MASK; + spi_wdat = SYS_SPI_TOP_WDAT_ADDR; + addr = SYS_SPI_ADDR_CR_WRITE | SYS_SPI_ADDR_CR_TOP | (addr & SYS_SPI_ADDR_CR_MASK); + break; + case SYS_SPI_WF1: + spi_busy = 1 << SYS_SPI_STA_WF_BUSY_SHFT; + spi_addr = SYS_SPI_WF_ADDR_ADDR; + spi_mask = SYS_SPI_WF_WDAT_MASK; + spi_wdat = SYS_SPI_WF_WDAT_ADDR; + addr = SYS_SPI_ADDR_CR_WRITE | SYS_SPI_ADDR_CR_WF1 | (addr & SYS_SPI_ADDR_CR_MASK); + break; + default: + return FM_SYS_SPI_ERR; + } + + if (sys_spi_wait(spi_busy) == FM_SYS_SPI_BUSY) + return FM_SYS_SPI_BUSY; + + si->spi_write(si, spi_addr, addr); + si->spi_write(si, spi_wdat, (data & spi_mask)); + + sys_spi_wait(spi_busy); + + WCN_DBG(FM_DBG | CHIP, "[0x%08x]=[0x%08x]\n", addr, data); + + return FM_SYS_SPI_OK; +} +#endif /* CFG_FM_CONNAC2 */ + +static void drv_spi_read( + struct fm_spi_interface *si, unsigned int addr, unsigned int *val) +{ + *val = readl(si->info.spi_vir_addr + addr); +} + +static void drv_spi_write( + struct fm_spi_interface *si, unsigned int addr, unsigned int val) +{ + writel(val, si->info.spi_vir_addr + addr); +} + +static void drv_top_read( + struct fm_spi_interface *si, unsigned int addr, unsigned int *val) +{ + *val = readl(si->info.top_vir_addr + addr); +} + +static void drv_top_write( + struct fm_spi_interface *si, unsigned int addr, unsigned int val) +{ + writel(val, si->info.top_vir_addr + addr); +} + +static void drv_mcu_read( + struct fm_spi_interface *si, unsigned int addr, unsigned int *val) +{ + *val = readl(si->info.mcu_vir_addr + addr); +} + +static void drv_mcu_write( + struct fm_spi_interface *si, unsigned int addr, unsigned int val) +{ + writel(val, si->info.mcu_vir_addr + addr); +} + +static void drv_host_read( + struct fm_spi_interface *si, unsigned int addr, unsigned int *data) +{ + unsigned new_addr = addr; + + if (addr >= TOP_RF_SPI_AON_CONSYS_BASE && + addr <= TOP_RF_SPI_AON_CONSYS_BASE + TOP_RF_SPI_AON_SIZE) { + new_addr = addr - TOP_RF_SPI_AON_CONSYS_BASE; + drv_spi_read(si, new_addr, data); + } else if (addr >= MCU_CFG_CONSYS_BASE && + addr <= MCU_CFG_CONSYS_BASE + MCU_CFG_SIZE) { + new_addr = addr - MCU_CFG_CONSYS_BASE; + drv_mcu_read(si, new_addr, data); + } else if (addr >= TOP_MISC_OFF_CONSYS_BASE && + addr <= TOP_MISC_OFF_CONSYS_BASE + TOP_MISC_OFF_SIZE) { + new_addr = addr - TOP_MISC_OFF_CONSYS_BASE; + drv_top_read(si, new_addr, data); + } else { + WCN_DBG(FM_WAR | CHIP, "not support addr[0x%08x].\n", addr); + return; + } + + WCN_DBG(FM_DBG | CHIP, "read [0x%08x]=[0x%08x]\n", + new_addr, addr, *data); +} + +static void drv_host_write( + struct fm_spi_interface *si, unsigned int addr, unsigned int data) +{ + unsigned new_addr = addr; + + if (addr >= TOP_RF_SPI_AON_CONSYS_BASE && + addr <= TOP_RF_SPI_AON_CONSYS_BASE + TOP_RF_SPI_AON_SIZE) { + new_addr = addr - TOP_RF_SPI_AON_CONSYS_BASE; + drv_spi_write(si, new_addr, data); + } else if (addr >= MCU_CFG_CONSYS_BASE && + addr <= MCU_CFG_CONSYS_BASE + MCU_CFG_SIZE) { + new_addr = addr - MCU_CFG_CONSYS_BASE; + drv_mcu_write(si, new_addr, data); + } else if (addr >= TOP_MISC_OFF_CONSYS_BASE && + addr <= TOP_MISC_OFF_CONSYS_BASE + TOP_MISC_OFF_SIZE) { + new_addr = addr - TOP_MISC_OFF_CONSYS_BASE; + drv_top_write(si, new_addr, data); + } else { + WCN_DBG(FM_WAR | CHIP, "not support addr[0x%08x].\n", addr); + return; + } + + WCN_DBG(FM_DBG | CHIP, "write [0x%08x/0x%08x]=[0x%08x]\n", + new_addr, addr, data); +} + +/** + * Send TX data via STP format + * + * @param None + * + * @return None + */ +static void fm_tx(unsigned char *buf, unsigned short length) +{ + if (FM_LOCK(fm_wcn_ops.tx_lock)) + return; + + if (length == 0xFFFF) { + length = (unsigned short)buf[2] + + (unsigned short)(buf[3] << 8) + FM_HDR_SIZE; + } + + memset(fm_wcn_ops.rx_buf, 0, RX_BUF_SIZE); + memcpy(fm_wcn_ops.rx_buf, buf, length); + fm_wcn_ops.rx_len = length; + fm_event_parser(fm_rds_parser); + + FM_UNLOCK(fm_wcn_ops.tx_lock); +} + +static void fm_stc_done_rechandler(void) +{ + unsigned short i, reg_value, freq, isr_value; + + fw_spi_read(FM_MAIN_CTRL, &isr_value); + + WCN_DBG(FM_NTC | CHIP, "isr_value[%04x]\n", isr_value); + + if (isr_value & FM_MAIN_CTRL_SEEK) { + unsigned char data[6]; + + fw_spi_read(FM_MAIN_CHANDETSTAT, ®_value); + + /* freq's unit is 10kHz */ + freq = ((((reg_value & 0x3ff0) >> 4) >> 1) + 640) * 10; + + data[0] = FM_TASK_EVENT_PKT_TYPE; + data[1] = FM_SEEK_OPCODE; + /* payload length */ + data[2] = 2; + data[3] = 0x00; + data[4] = (unsigned char)freq & 0xFF; + data[5] = (unsigned char)(freq >> 8); + + fm_tx(data, 0xFFFF); + } else if (isr_value & FM_MAIN_CTRL_SCAN) { + unsigned char data[36]; + + for (i = 0; i <= SCAN_BUFF_LEN; i++) { + fw_spi_read(RDS_DATA_REG, ®_value); + data[4 + (i * 2)] = reg_value & 0xff; + data[4 + (i * 2) + 1] = (reg_value & 0xff00) >> 8; + } + + data[0] = FM_TASK_EVENT_PKT_TYPE; + data[1] = FM_SCAN_OPCODE; + /* payload length */ + data[2] = 32; + data[3] = 0x00; + + fm_tx(data, 0xFFFF); + } else if (isr_value & FM_MAIN_CTRL_TUNE) { + unsigned char data[5]; + + data[0] = FM_TASK_EVENT_PKT_TYPE; + data[1] = FM_TUNE_OPCODE; + /* payload length */ + data[2] = 0x01; + data[3] = 0x00; + data[4] = 0x01; + fm_tx(data, 0x0005); + } +} + +static void fm_rds_rechandler(void) +{ + unsigned short fifo_cnt, reg_value, rds_data[6], reg_sin, reg_cos; + unsigned short crc = 0, corr_cnt = 0, rds_info; + unsigned short output_point, temp_data; + unsigned short i = 0; + unsigned char data[128]; + + do { + fw_spi_read(RDS_FIFO_STATUS0, &fifo_cnt); + fifo_cnt = (fifo_cnt & RDS_DCO_FIFO_OFST) >> + RDS_DCO_FIFO_OFST_SHFT; + + /* block A data and info handling */ + fw_spi_read(RDS_INFO_REG, &rds_info); + crc |= (rds_info & RDS_CRC_INFO) << 3; + corr_cnt |= ((rds_info & RDS_CRC_CORR_CNT) << 11); + fw_spi_read(RDS_DATA_REG, &(rds_data[0])); + + /* block B data and info handling */ + fw_spi_read(RDS_INFO_REG, &rds_info); + crc |= (rds_info & RDS_CRC_INFO) << 2; + corr_cnt |= ((rds_info & RDS_CRC_CORR_CNT) << 7); + fw_spi_read(RDS_DATA_REG, &(rds_data[1])); + + /* block C data and info handling */ + fw_spi_read(RDS_INFO_REG, &rds_info); + crc |= (rds_info & RDS_CRC_INFO) << 1; + corr_cnt |= ((rds_info & RDS_CRC_CORR_CNT) << 3); + fw_spi_read(RDS_DATA_REG, &(rds_data[2])); + + /* block D data and info handling */ + fw_spi_read(RDS_INFO_REG, &rds_info); + crc |= (rds_info & RDS_CRC_INFO); + corr_cnt |= ((rds_info & RDS_CRC_CORR_CNT) >> 1); + fw_spi_read(RDS_DATA_REG, &(rds_data[3])); + + + rds_data[4] = corr_cnt; + rds_data[5] = crc; + + /* -1 due to H/W behavior */ + if (fifo_cnt > 0) + fifo_cnt--; + + /* RDS recovery start */ + /* check if reading doesn't start at block A */ + fw_spi_read(RDS_POINTER, &output_point); + while (output_point & 0x3) { + fw_spi_read(RDS_DATA_REG, &temp_data); + fw_spi_read(RDS_POINTER, &output_point); + } + /* RDS recovery end */ + + fm_set_u16_to_auc(&(data[8 + 12 * i]), rds_data[0]); + fm_set_u16_to_auc(&(data[10 + 12 * i]), rds_data[1]); + fm_set_u16_to_auc(&(data[12 + 12 * i]), rds_data[2]); + fm_set_u16_to_auc(&(data[14 + 12 * i]), rds_data[3]); + fm_set_u16_to_auc(&(data[16 + 12 * i]), rds_data[4]); + fm_set_u16_to_auc(&(data[18 + 12 * i]), rds_data[5]); + + i++; + } while ((i < 10) && ((fifo_cnt & 0x1F) > 0)); + + if (i > 0) { + fw_spi_read(RDS_SIN_REG, ®_sin); + fw_spi_read(RDS_COS_REG, ®_cos); + + data[0] = FM_TASK_EVENT_PKT_TYPE; + data[1] = RDS_RX_DATA_OPCODE; + /* payload length */ + data[2] = (unsigned char)(12 * i + 4); + data[3] = 0x00; + fm_set_u16_to_auc(&(data[4]), reg_sin); + fm_set_u16_to_auc(&(data[6]), reg_cos); + fm_tx(data, 0xFFFF); + } + + fw_spi_read(FM_MAIN_EXTINTRMASK, ®_value); + reg_value |= (FM_INTR_RDS << 8); + fw_spi_write(FM_MAIN_EXTINTRMASK, reg_value); +} + +static void fm_fifo_rechandler(unsigned short intr) +{ + unsigned short reg_value; + + /* Handle channel info. data in FIFO if RDS interrupt + * and CQI interrupt arise simultaneously + */ + if ((intr & 0x0001) && (intr & 0x0020)) { + unsigned short i; + unsigned char data[100]; + + for (i = 0; i < FIFO_LEN; i++) { + fw_spi_read(RDS_DATA_REG, ®_value); + data[4 + (i * 2)] = reg_value & 0xff; + data[4 + (i * 2) + 1] = (reg_value & 0xff00) >> 8; + } + + data[0] = FM_TASK_EVENT_PKT_TYPE; + data[1] = FM_SCAN_OPCODE; + /* payload length */ + data[2] = (unsigned char)(FIFO_LEN<<1); + data[3] = 0x00; + + fm_tx(data, 0xFFFF); + } + /* Handle RDS data in FIFO, while only RDS interrupt issues */ + else if (intr & 0x0020) { + + fw_spi_read(FM_MAIN_EXTINTRMASK, ®_value); + reg_value &= ~(FM_INTR_RDS << 8); + fw_spi_write(FM_MAIN_EXTINTRMASK, reg_value); + + fm_rds_rechandler(); + } + +} + +static void fm_softmute_tune(unsigned short freq, unsigned char *pos) +{ + unsigned short rdata; + unsigned int i = 0, PRX = 0, ATEDV = 0, PR = 0; + int RSSI = 0, PAMD = 0, FPAMD = 0, MR = 0, ATDC = 0; + struct fm_full_cqi *p_cqi = (struct fm_full_cqi *)pos; + + p_cqi->ch = freq; + + /* soft mute tune */ + fw_bop_modify(FM_MAIN_CG2_CTRL, 0xBFFF, 0x4000); + /* disable interrupt */ + fw_spi_write(FM_MAIN_INTRMASK, 0x0000); + fw_spi_write(FM_MAIN_EXTINTRMASK, 0x0000); + /* ramp down */ + fw_bop_modify(FM_MAIN_CTRL, 0xFFF0, 0x0000); + /* Set DSP ramp down state */ + fw_bop_modify(FM_MAIN_CTRL, 0xFFFF, 0x0100); + + fw_bop_rd_until(FM_MAIN_INTR, 0x0001, 0x0001); + + fw_bop_modify(FM_MAIN_CTRL, 0xFEFF, 0x0000); + fw_bop_modify(FM_MAIN_INTR, 0xFFFF, 0x0001); + + /* tune */ + freq = freq / 5 - 1280; + fw_bop_modify(0x65, 0xFC00, freq); + fw_bop_modify(FM_MAIN_CTRL, 0xFFFF, 0x0001); + fw_bop_rd_until(FM_MAIN_INTR, 0x0001, 0x0001); + fw_bop_modify(FM_MAIN_INTR, 0xFFFF, 0x0001); + + /* get CQI */ + fw_bop_udelay(9000); + for (i = 0; i < 8; i++) { + /* RSSI */ + fw_spi_read(0x6C, &rdata); + RSSI += ((rdata & 0x3FF) >= 512) ? + ((rdata & 0x3FF) - 1024) : (rdata & 0x3FF); + + /* PAMD */ + fw_spi_read(0xB4, &rdata); + PAMD += ((rdata & 0x1FF) >= 256) ? + ((rdata & 0x1FF) - 512) : (rdata & 0x1FF); + + /* PR */ + fw_spi_read(0xB5, &rdata); + PR += (rdata & 0x3FF); + + /* FPAMD */ + fw_spi_read(0xBC, &rdata); + FPAMD += ((rdata & 0xFFF) >= 2048) ? + ((rdata & 0xFFF) - 4096) : (rdata & 0xFFF); + + /* MR */ + fw_spi_read(0xBD, &rdata); + MR += ((rdata & 0x1FF) >= 256) ? + ((rdata & 0x1FF) - 512) : (rdata & 0x1FF); + + /* ATDC */ + fw_spi_read(0x83, &rdata); + ATDC += (rdata >= 32768) ? (65536 - rdata) : rdata; + + /* PRX */ + fw_spi_read(0x84, &rdata); + PRX += rdata & 0xFF; + + /* ATDEV */ + fw_spi_read(0x85, &rdata); + ATEDV += rdata; + + fw_bop_udelay(2250); + } + + RSSI = (RSSI + 4) / 8; + p_cqi->rssi = RSSI & 0x03FF; + PAMD = (PAMD + 4) / 8; + p_cqi->pamd = PAMD & 0x01FF; + PR = (PR + 4) / 8; + p_cqi->pr = PR & 0x03FF; + FPAMD = (FPAMD + 4) / 8; + p_cqi->fpamd = FPAMD & 0x0FFF; + MR = (MR + 4) / 8; + p_cqi->mr = MR & 0x01FF; + ATDC = (ATDC + 4) / 8; + p_cqi->atdc = ATDC & 0xFFFF; + PRX = (PRX + 4) / 8; + p_cqi->prx = PRX & 0x00FF; + ATEDV = (ATEDV + 4) / 8; + p_cqi->atdev = ATEDV & 0xFFFF; + + /* Soft_mute Gain */ + fw_spi_read(0x86, &rdata); + p_cqi->smg = rdata; + + /* delta RSSI */ + fw_spi_read(0x88, &rdata); + p_cqi->drssi = rdata; + + /* clear soft mute tune */ + fw_bop_modify(FM_MAIN_CG2_CTRL, 0xBFFF, 0x0000); + + WCN_DBG(FM_NTC | CHIP, + "freq %d, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x, 0x%04x\n", + p_cqi->ch, p_cqi->rssi, p_cqi->pamd, + p_cqi->pr, p_cqi->fpamd, p_cqi->mr, + p_cqi->atdc, p_cqi->prx, p_cqi->atdev, + p_cqi->smg, p_cqi->drssi); +} + +static void fm_dsp_download( + unsigned char target, unsigned short length, + unsigned char total_seg, unsigned char current_seg, + unsigned char *data) +{ + unsigned int control_code = 0; + unsigned short i; + + switch (target) { + case DSP_ROM: + case DSP_PATCH: + control_code = 0x10; + break; + case DSP_COEFF: + control_code = 0xe; + break; + case DSP_HWCOEFF: + control_code = 0xd; + break; + default: + break; + } + + if (current_seg == 0) { + fw_spi_write(CONTROL_REG, 0); + /* Start address */ + fw_spi_write(OFFSET_REG, data[1] << 8 | data[0]); + /* Reset download control */ + fw_spi_write(CONTROL_REG, 0x40); + /* Set download control */ + fw_spi_write(CONTROL_REG, control_code); + data += 4; + length -= 4; + } + + if (length > 0) { + for (i = 0; i < (length >> 1); i++) + fw_spi_write(DATA_REG, data[2 * i + 1] << 8 | data[2 * i]); + } else { + WCN_DBG(FM_ERR | CHIP, "incorrect length[%d].\n", length); + } +} + +static void fm_task_rx_basic_op( + unsigned char bop, unsigned char length, unsigned char *buf) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + + switch (bop) { + case FM_WRITE_BASIC_OP: + fw_spi_write(buf[0], fm_get_u16_from_auc(&buf[1])); + break; + + case FM_UDELAY_BASIC_OP: + fw_bop_udelay(fm_get_u32_from_auc(&buf[0])); + break; + + case FM_RD_UNTIL_BASIC_OP: + fw_bop_rd_until(buf[0], fm_get_u16_from_auc(&buf[1]), + fm_get_u16_from_auc(&buf[3])); + break; + + case FM_MODIFY_BASIC_OP: + fw_bop_modify(buf[0], fm_get_u16_from_auc(&buf[1]), + fm_get_u16_from_auc(&buf[3])); + break; + + case FM_MSLEEP_BASIC_OP: + fm_delayms(fm_get_u32_from_auc(&buf[0])); + break; + + case FM_WRITE_SPI_BASIC_OP: + si->sys_spi_write(si, buf[0], fm_get_u16_from_auc(&buf[1]), + fm_get_u32_from_auc(&buf[3])); + break; + case FM_RD_SPI_UNTIL_BASIC_OP: + fw_bop_spi_rd_until(buf[0], fm_get_u16_from_auc(&buf[1]), + fm_get_u32_from_auc(&buf[3]), + fm_get_u32_from_auc(&buf[7])); + break; + case FM_MODIFY_SPI_BASIC_OP: + fw_bop_spi_modify(buf[0], fm_get_u16_from_auc(&buf[1]), + fm_get_u32_from_auc(&buf[3]), + fm_get_u32_from_auc(&buf[7])); + break; + + default: + break; + } +} + +/** + * FM task rx dispatcher default functions for basic operation processing + * + * @param opcode opcode for different packet type + * @param length the length of parameters + * @param buf the parameters for different packet type + * + * @return None + */ +static void fm_task_rx_dispatcher_default( + unsigned char opcode, unsigned short length, unsigned char *buf) +{ + int unused_op_size = length; + unsigned short used_op_size = 0; + + while (unused_op_size > 0) { + unsigned char basic_op = buf[used_op_size]; + unsigned char basic_op_length = buf[used_op_size + 1]; + unsigned char *basic_op_buf = &buf[used_op_size + 2]; + + fm_task_rx_basic_op(basic_op, basic_op_length, + basic_op_buf); + unused_op_size -= (int)(basic_op_length + 2); + used_op_size += (unsigned short)(basic_op_length + 2); + } +} + +/** + * FM task rx dispatcher functions for different packet type + * + * @param opcode opcode for different packet type + * @param length the length of parameters + * @param buf the parameters for different packet type + * + * @return None + */ +static void fm_task_rx_dispatcher( + unsigned char opcode, unsigned short length, unsigned char *buf) +{ + unsigned char event[28]; + + /* Prepare FM event packet, default no payload */ + event[0] = FM_TASK_EVENT_PKT_TYPE; + event[1] = opcode; + event[2] = 0x0; + event[3] = 0x0; + + switch (opcode) { + case FM_STP_TEST_OPCODE: + event[2] = 0x3; + event[3] = 0x0; + event[4] = 0x0; + event[5] = 0x1; + event[6] = 0x2; + break; + case FSPI_ENABLE_OPCODE: + break; + case FSPI_MUX_SEL_OPCODE: + break; + case FSPI_READ_OPCODE: + { + unsigned short data; + + fw_spi_read(buf[0], &data); + event[2] = 0x2; + event[3] = 0x0; + fm_set_u16_to_auc(&event[4], data); + break; + } + case FSPI_WRITE_OPCODE: + fw_spi_write(buf[0], fm_get_u16_from_auc(&buf[1])); + break; + + case FM_PATCH_DOWNLOAD_OPCODE: + fm_dsp_download(DSP_PATCH, length - 2, buf[0], buf[1], &buf[2]); + break; + + case FM_COEFF_DOWNLOAD_OPCODE: + fm_dsp_download(DSP_COEFF, length - 2, buf[0], buf[1], &buf[2]); + break; + + case FM_HWCOEFF_DOWNLOAD_OPCODE: + fm_dsp_download(DSP_HWCOEFF, length - 2, buf[0], buf[1], &buf[2]); + break; + + case FM_ROM_DOWNLOAD_OPCODE: + fm_dsp_download(DSP_ROM, length - 2, buf[0], buf[1], &buf[2]); + break; + case FM_SOFT_MUTE_TUNE_OPCODE: + { + switch (buf[0]) { + case 1: + { + unsigned short freq = 0; + + fm_set_u16_to_auc(&event[2], + (FM_SOFTMUTE_TUNE_CQI_SIZE + 2)); + event[4] = FM_SOFTMUTE_TUNE_CQI_SIZE; + event[5] = 0x01; + freq = fm_get_u16_from_auc(&buf[1]); + fm_softmute_tune(freq, &event[6]); + break; + } + case 2: + case 3: + case 4: + default: + { + event[2] = 0x00; + event[3] = 0x00; + memcpy(&event[2], buf, 3); + break; + } + } + break; + } + case FM_HOST_READ_OPCODE: + { + struct fm_spi_interface *si = &fm_wcn_ops.si; + unsigned int addr, data; + + addr = fm_get_u32_from_auc(&buf[0]); + si->host_read(si, addr, &data); + event[2] = 0x4; + event[3] = 0x0; + fm_set_u32_to_auc(&event[4], data); + } + break; + case FM_HOST_WRITE_OPCODE: + { + struct fm_spi_interface *si = &fm_wcn_ops.si; + unsigned int addr, data; + + addr = fm_get_u32_from_auc(&buf[0]); + data = fm_get_u32_from_auc(&buf[4]); + si->host_write(si, addr, data); + + break; + } + case CSPI_WRITE_OPCODE: + { + struct fm_spi_interface *si = &fm_wcn_ops.si; + + si->sys_spi_write(si, buf[0], fm_get_u16_from_auc(&buf[1]), + fm_get_u32_from_auc(&buf[3])); + break; + } + case CSPI_READ_OPCODE: + { + struct fm_spi_interface *si = &fm_wcn_ops.si; + unsigned int data; + unsigned short ret; + + ret = si->sys_spi_read( + si, buf[0], fm_get_u16_from_auc(&buf[1]), &data); + + if (ret != 0) + data = (unsigned short)ret; + + event[2] = 0x4; + event[3] = 0x0; + fm_set_u32_to_auc(&event[4], data); + break; + } + case FM_HOST_MODIFY_OPCODE: + { + struct fm_spi_interface *si = &fm_wcn_ops.si; + unsigned int addr, data; + + addr = fm_get_u32_from_auc(&buf[0]); + si->host_read(si, addr, &data); + data &= fm_get_u32_from_auc(&buf[4]); + data |= fm_get_u32_from_auc(&buf[8]); + si->host_write(si, addr, data); + break; + } + default: + fm_task_rx_dispatcher_default(opcode, length, buf); + break; + } + fm_tx(event, 0xFFFF); +} + +static bool drv_set_own(void) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + struct fm_ext_interface *ei = &fm_wcn_ops.ei; + unsigned int val, tmp, i; + int ret = 0; + + ret = FM_LOCK(fm_wcn_ops.own_lock); + for (i = 0; ret && i < MAX_SET_OWN_COUNT; i++) { + fm_delayms(2); + ret = FM_LOCK(fm_wcn_ops.own_lock); + } + + /* get lock fail */ + if (i == MAX_SET_OWN_COUNT) { + WCN_DBG(FM_ERR | CHIP, "get own lock fail[%d]\n", ret); + return false; + } + + /* wakeup conninfra */ + drv_host_write(si, 0x180601B0, 0x1); + + /* polling chipid */ + drv_host_read(si, 0x18001000, &val); + for (i = 0; val != 0x20010000 && i < MAX_SET_OWN_COUNT; i++) { + fm_delayms(5); + drv_host_read(si, 0x18001000, &val); + } + + /* polling fail */ + if (i == MAX_SET_OWN_COUNT) { + /* unlock if set own fail */ + drv_host_read(si, 0x180601B0, &val); + drv_host_read(si, 0x18001808, &tmp); + WCN_DBG(FM_ERR | CHIP, + "polling chip id fail [0x180601B0]=[0x%08x], [0x18001808]=[0x%08x]\n", + val, tmp); + FM_UNLOCK(fm_wcn_ops.own_lock); + return false; + } + + if (ei->is_bus_hang && ei->is_bus_hang()) { + FM_UNLOCK(fm_wcn_ops.own_lock); + return false; + } + + /* conn_infra bus debug function setting */ + conninfra_config_setup(); + + return true; +} + +static bool drv_clr_own(void) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + + drv_host_write(si, 0x180601B0, 0x0); + + FM_UNLOCK(fm_wcn_ops.own_lock); + + return true; +} + +static int drv_stp_send_data(unsigned char *buf, unsigned int len) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + + if (len < 4) { + WCN_DBG(FM_ERR | CHIP, "buf length error[%d].\n", len); + return -1; + } + + if (si->set_own && !si->set_own()) { + WCN_DBG(FM_ERR | CHIP, "set_own fail\n"); + return -1; + } + + fm_task_rx_dispatcher(buf[1], len - 4, buf + 4); + + if (si->clr_own) + si->clr_own(); + + WCN_DBG(FM_DBG | CHIP, "buffer: %02x %02x %02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + + return 1; +} + +static int drv_stp_recv_data(unsigned char *buf, unsigned int len) +{ + unsigned int length = fm_wcn_ops.rx_len; + + if (length > len) + length = len; + + memcpy(buf, fm_wcn_ops.rx_buf, length); + + return length; +} + +static void drv_enable_eint(void) +{ + struct fm_ext_interface *ei = &fm_wcn_ops.ei; + + enable_irq(ei->irq_id); +} + +static void drv_disable_eint(void) +{ + struct fm_ext_interface *ei = &fm_wcn_ops.ei; + + disable_irq_nosync(ei->irq_id); +} + +static void drv_eint_handler(void) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + unsigned short main_isr; + + if (si->set_own && !si->set_own()) { + WCN_DBG(FM_ERR | CHIP, "set_own fail\n"); + return; + } + + fw_spi_read(FM_MAIN_INTR, &main_isr); + main_isr &= FM_INTR_MASK; + + WCN_DBG(FM_NTC | CHIP, "interrupt[%04x]\n", main_isr); + + if (main_isr & FM_INTR_STC_DONE) + fm_stc_done_rechandler(); + + if (main_isr & FM_INTR_RDS) + fm_fifo_rechandler(main_isr); + + fw_spi_write(FM_MAIN_INTR, main_isr); + + if (si->clr_own) + si->clr_own(); +} + +static int drv_interface_init(void) +{ + struct fm_spi_interface *interface = &fm_wcn_ops.si; + struct fm_wcn_reg_info *info = &interface->info; + + info->spi_phy_addr = TOP_RF_SPI_AON_ADDR; + info->spi_size = TOP_RF_SPI_AON_SIZE; + request_mem_region(info->spi_phy_addr, info->spi_size, "FM_SPI"); + info->spi_vir_addr = ioremap( + info->spi_phy_addr, info->spi_size); + if (info->spi_vir_addr == NULL) { + WCN_DBG(FM_ERR | CHIP, "Cannot remap address.\n"); + return -1; + } + + info->top_phy_addr = TOP_MISC_OFF_ADDR; + info->top_size = TOP_MISC_OFF_SIZE; + request_mem_region(info->top_phy_addr, info->top_size, "FM_TOP"); + info->top_vir_addr = ioremap( + info->top_phy_addr, info->top_size); + if (info->top_vir_addr == NULL) { + WCN_DBG(FM_ERR | CHIP, "Cannot remap address.\n"); + return -1; + } + + info->mcu_phy_addr = MCU_CFG_ADDR; + info->mcu_size = MCU_CFG_SIZE; + request_mem_region(info->mcu_phy_addr, info->mcu_size, "FM_MCU"); + info->mcu_vir_addr = ioremap( + info->mcu_phy_addr, info->mcu_size); + if (info->mcu_vir_addr == NULL) { + WCN_DBG(FM_ERR | CHIP, "Cannot remap address.\n"); + return -1; + } + + interface->spi_read = drv_spi_read; + interface->spi_write = drv_spi_write; + interface->host_read = drv_host_read; + interface->host_write = drv_host_write; +#if CFG_FM_CONNAC2 + interface->sys_spi_read = drv_sys_spi_read; + interface->sys_spi_write = drv_sys_spi_write; + interface->set_own = drv_set_own; + interface->clr_own = drv_clr_own; +#else + interface->sys_spi_read = fm_sys_spi_read; + interface->sys_spi_write = fm_sys_spi_write; + interface->set_own = NULL; + interface->clr_own = NULL; +#endif + + return 0; +} + +static int drv_interface_uninit(void) +{ + struct fm_spi_interface *interface = &fm_wcn_ops.si; + struct fm_wcn_reg_info *info = &interface->info; + + if (info->spi_vir_addr) { + iounmap(info->spi_vir_addr); + release_mem_region(info->spi_phy_addr, info->spi_size); + } + + if (info->top_vir_addr) { + iounmap(info->top_vir_addr); + release_mem_region(info->top_phy_addr, info->top_size); + } + + if (info->mcu_vir_addr) { + iounmap(info->mcu_vir_addr); + release_mem_region(info->mcu_phy_addr, info->mcu_size); + } + return 0; +} + +static unsigned char drv_get_top_index(void) +{ + return SYS_SPI_TOP; +} + +#if CFG_FM_CONNAC2 + +static int fm_conninfra_stp_register_event_cb(void *cb) +{ + fm_wcn_ops.ei.eint_cb = (void (*)(void))cb; + return 0; +} + +static int fm_conninfra_msgcb_reg(void *data) +{ + /* get whole chip reset cb */ + whole_chip_reset = data; + return conninfra_sub_drv_ops_register( + CONNDRV_TYPE_FM, &fm_drv_cbs); +} + +static int fm_conninfra_func_on(void) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + int ret = 0; + + ret = conninfra_pwr_on(CONNDRV_TYPE_FM); + if (ret == -1) { + WCN_DBG(FM_ERR | CHIP, "conninfra power on fail.\n"); + return 0; + } + + if (si->set_own && !si->set_own()) { + WCN_DBG(FM_ERR | CHIP, "set_own fail\n"); + return 0; + } + + ret = conninfra_adie_top_ck_en_on(CONNSYS_ADIE_CTL_HOST_FM); + + if (si->clr_own) + si->clr_own(); + + if (ret == -1) { + WCN_DBG(FM_ERR | CHIP, "top ck en fail.\n"); + return 0; + } + + return 1; +} + +static int fm_conninfra_func_off(void) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + int ret = 0; + + if (si->set_own && !si->set_own()) { + WCN_DBG(FM_ERR | CHIP, "set_own fail\n"); + return 0; + } + + ret = conninfra_adie_top_ck_en_off(CONNSYS_ADIE_CTL_HOST_FM); + + if (si->clr_own) + si->clr_own(); + + if (ret == -1) { + WCN_DBG(FM_ERR | CHIP, "top ck en off fail.\n"); + return 0; + } + + ret = conninfra_pwr_off(CONNDRV_TYPE_FM); + if (ret == -1) { + WCN_DBG(FM_ERR | CHIP, "conninfra power off fail.\n"); + return 0; + } + + return 1; +} + +static int fm_conninfra_chipid_query(void) +{ +#ifdef CFG_FM_CHIP_ID + return CFG_FM_CHIP_ID; +#else + return 0; +#endif +} + +static int fm_conninfra_spi_clock_switch(enum fm_spi_speed speed) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + enum connsys_spi_speed_type sp_type = CONNSYS_SPI_SPEED_26M; + int ret = 0; + + if (si->set_own && !si->set_own()) { + WCN_DBG(FM_ERR | CHIP, "set_own fail\n"); + return -2; + } + + switch (speed) { + case FM_SPI_SPEED_26M: + sp_type = CONNSYS_SPI_SPEED_26M; + break; + case FM_SPI_SPEED_64M: + sp_type = CONNSYS_SPI_SPEED_64M; + break; + default: + break; + } + + ret = conninfra_spi_clock_switch(sp_type); + + if (si->clr_own) + si->clr_own(); + + if (ret == -1) { + WCN_DBG(FM_ERR | CHIP, "conninfra clock switch fail.\n"); + return -1; + } + + return 0; +} + +static bool fm_conninfra_is_bus_hang(void) +{ + int ret = 0; + + if (conninfra_reg_readable()) + return false; + + /* Check conninfra bus before accessing BGF's CR */ + ret = conninfra_is_bus_hang(); + if (ret > 0) { + WCN_DBG(FM_ERR | CHIP, "conninfra bus is hang[0x%x]\n", ret); + conninfra_trigger_whole_chip_rst(CONNDRV_TYPE_FM, "bus hang"); + return true; + } + + WCN_DBG(FM_ERR | CHIP, + "conninfra not readable, but not bus hang ret = %d", ret); + + return false; +} + +#else /* CFG_FM_CONNAC2 */ + + +static int fm_stp_register_event_cb(void *cb) +{ + fm_wcn_ops.ei.eint_cb = (void (*)(void))cb; + return mtk_wcn_stp_register_event_cb(FM_TASK_INDX, cb); +} + +static int fm_wmt_msgcb_reg(void *data) +{ + /* get whole chip reset cb */ + return 0; +} + +static int fm_wmt_func_on(void) +{ + return mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM) != MTK_WCN_BOOL_FALSE; +} + +static int fm_wmt_func_off(void) +{ + return mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM) != MTK_WCN_BOOL_FALSE; +} + +static int fm_wmt_ic_info_get(void) +{ + return mtk_wcn_wmt_ic_info_get(1); +} + +static int fm_wmt_chipid_query(void) +{ + return mtk_wcn_wmt_chipid_query(); +} + +static int fm_wmt_spi_clock_switch(enum fm_spi_speed speed) +{ + struct fm_spi_interface *si = &fm_wcn_ops.si; + unsigned int reg_val = 0; + + switch (speed) { + case FM_SPI_SPEED_26M: + si->host_read(si, 0x18004004, ®_val); + reg_val &= 0xFFFFFFFE; + si->host_write(si, 0x18004004, reg_val); + break; + case FM_SPI_SPEED_64M: + si->host_read(si, 0x18004004, ®_val); + reg_val |= 0x00000001; + si->host_write(si, 0x18004004, reg_val); + break; + default: + break; + } + + return 0; +} +#endif /* CFG_FM_CONNAC2 */ + +static irqreturn_t fm_isr(int irq, void *dev) +{ + struct fm_ext_interface *ei = &fm_wcn_ops.ei; + + if (!ei->eint_cb) { + WCN_DBG(FM_WAR | CHIP, "fm eint cb is NULL\n"); + return IRQ_NONE; + } + + if (ei->disable_eint) + ei->disable_eint(); + + ei->eint_cb(); + + return IRQ_HANDLED; +} + +int fm_register_irq(struct platform_driver *drv) +{ +#ifdef CONFIG_OF + struct device_node *node = NULL; +#endif + struct fm_ext_interface *ei = &fm_wcn_ops.ei; + int ret = 0; + + ei->drv = drv; + ei->irq_id = FM_IRQ_NUMBER; +#ifdef CONFIG_OF + node = of_find_compatible_node(NULL, NULL, "mediatek,fm"); + if (node) + ei->irq_id = irq_of_parse_and_map(node, 0); + else + WCN_DBG(FM_ERR | CHIP, "get fm dts node fail\n"); +#endif + WCN_DBG(FM_NTC | CHIP, "request_irq num(%d)\n", ei->irq_id); + ret = request_irq(ei->irq_id, fm_isr, IRQF_SHARED, FM_NAME, drv); + if (ret != 0) + WCN_DBG(FM_ERR | CHIP, "request_irq ERROR(%d)\n", ret); + + return ret; +} + +static void register_drv_ops_init(void) +{ + struct fm_ext_interface *ei = &fm_wcn_ops.ei; + + drv_interface_init(); + ei->eint_handler = drv_eint_handler; + ei->stp_send_data = drv_stp_send_data; + ei->stp_recv_data = drv_stp_recv_data; + ei->get_top_index = drv_get_top_index; + +#if CFG_FM_CONNAC2 + ei->enable_eint = drv_enable_eint; + ei->disable_eint = drv_disable_eint; + ei->stp_register_event_cb = fm_conninfra_stp_register_event_cb; + ei->wmt_msgcb_reg = fm_conninfra_msgcb_reg; + ei->wmt_func_on = fm_conninfra_func_on; + ei->wmt_func_off = fm_conninfra_func_off; + ei->wmt_ic_info_get = NULL; + ei->wmt_chipid_query = fm_conninfra_chipid_query; + ei->spi_clock_switch = fm_conninfra_spi_clock_switch; + ei->is_bus_hang = fm_conninfra_is_bus_hang; +#else + ei->enable_eint = NULL; + ei->disable_eint = NULL; + ei->stp_register_event_cb = fm_stp_register_event_cb; + ei->wmt_msgcb_reg = fm_wmt_msgcb_reg; + ei->wmt_func_on = fm_wmt_func_on; + ei->wmt_func_off = fm_wmt_func_off; + ei->wmt_ic_info_get = fm_wmt_ic_info_get; + ei->wmt_chipid_query = fm_wmt_chipid_query; + ei->spi_clock_switch = fm_wmt_spi_clock_switch; + ei->is_bus_hang = NULL; +#endif +} + +static void register_drv_ops_uninit(void) +{ + struct fm_ext_interface *ei = &fm_wcn_ops.ei; + + if (ei->irq_id) + free_irq(ei->irq_id, ei->drv); + drv_interface_uninit(); + fm_memset(&fm_wcn_ops, 0, sizeof(struct fm_wcn_reg_ops)); +} + +int fm_wcn_ops_register(void) +{ + register_drv_ops_init(); + return 0; +} + +int fm_wcn_ops_unregister(void) +{ + register_drv_ops_uninit(); + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/fmradio/plat/inc/plat.h b/drivers/misc/mediatek/connectivity/fmradio/plat/inc/plat.h new file mode 100644 index 00000000000000..3ed11752317d6f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/plat/inc/plat.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef FM_PLAT_H +#define FM_PLAT_H + +#include <linux/mm.h> +#include <linux/platform_device.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/of.h> + +#include "fm_typedef.h" +#include "fm_dbg.h" +#include "fm_err.h" +#include "fm_stdlib.h" +#include "fm_link.h" +#include "fm_utils.h" +#include "fm_rds.h" +#include "fm_ext_api.h" +#include "fm_reg_utils.h" +#include "fm_main.h" + +#if CFG_FM_CONNAC2 + +#include "conninfra.h" + +#else /* CFG_FM_CONNAC2 */ + +#include "osal_typedef.h" +#include "stp_exp.h" +#include "wmt_exp.h" + +enum { + SYS_SPI_WF1 = 0x00, + SYS_SPI_WF = 0x01, + SYS_SPI_BT = 0x02, + SYS_SPI_FM = 0x03, + SYS_SPI_GPS = 0x04, + SYS_SPI_TOP = 0x05, + SYS_SPI_WF2 = 0x06, + SYS_SPI_WF3 = 0x07, + SYS_SPI_MAX +}; + +#endif /* CFG_FM_CONNAC2 */ + +enum { + FM_SYS_SPI_OK = 0, + FM_SYS_SPI_BUSY, + FM_SYS_SPI_ERR +}; + +extern signed int fm_rds_parser( + struct rds_rx_t *rds_raw, signed int rds_size); + +#endif /* FM_PLAT_H */ diff --git a/drivers/misc/mediatek/connectivity/fmradio/plat/legacy_wmt.c b/drivers/misc/mediatek/connectivity/fmradio/plat/legacy_wmt.c new file mode 100644 index 00000000000000..b23bdee7d2850a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/fmradio/plat/legacy_wmt.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2019 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include "plat.h" + +static int (*whole_chip_reset)(signed int sta); + +static void WCNfm_wholechip_rst_cb( + ENUM_WMTDRV_TYPE_T src, ENUM_WMTDRV_TYPE_T dst, + ENUM_WMTMSG_TYPE_T type, void *buf, unsigned int sz) +{ + /* To handle reset procedure please */ + ENUM_WMTRSTMSG_TYPE_T rst_msg; + + if (sz > sizeof(ENUM_WMTRSTMSG_TYPE_T)) { + /*message format invalid */ + WCN_DBG(FM_WAR | LINK, "message format invalid!\n"); + return; + } + + memcpy((char *)&rst_msg, (char *)buf, sz); + WCN_DBG(FM_WAR | LINK, + "[src=%d], [dst=%d], [type=%d], [buf=0x%x], [sz=%d], [max=%d]\n", + src, dst, type, rst_msg, sz, WMTRSTMSG_RESET_MAX); + + if ((src == WMTDRV_TYPE_WMT) && (dst == WMTDRV_TYPE_FM) + && (type == WMTMSG_TYPE_RESET)) { + + if (rst_msg == WMTRSTMSG_RESET_START) { + WCN_DBG(FM_WAR | LINK, "FM restart start!\n"); + if (whole_chip_reset) + whole_chip_reset(1); + } else if (rst_msg == WMTRSTMSG_RESET_END_FAIL) { + WCN_DBG(FM_WAR | LINK, "FM restart end fail!\n"); + if (whole_chip_reset) + whole_chip_reset(2); + } else if (rst_msg == WMTRSTMSG_RESET_END) { + WCN_DBG(FM_WAR | LINK, "FM restart end!\n"); + if (whole_chip_reset) + whole_chip_reset(0); + } + } +} + +static void fw_eint_handler(void) +{ + fm_event_parser(fm_rds_parser); +} + +static int fm_stp_send_data(unsigned char *buf, unsigned int len) +{ + return mtk_wcn_stp_send_data(buf, len, FM_TASK_INDX); +} + +static int fm_stp_recv_data(unsigned char *buf, unsigned int len) +{ + return mtk_wcn_stp_receive_data(buf, len, FM_TASK_INDX); +} + +static int fm_stp_register_event_cb(void *cb) +{ + return mtk_wcn_stp_register_event_cb(FM_TASK_INDX, cb); +} + +static int fm_wmt_msgcb_reg(void *data) +{ + /* get whole chip reset cb */ + whole_chip_reset = data; + return mtk_wcn_wmt_msgcb_reg( + WMTDRV_TYPE_FM, WCNfm_wholechip_rst_cb); +} + +static int fm_wmt_func_on(void) +{ + int ret = 0; + + ret = mtk_wcn_wmt_func_on(WMTDRV_TYPE_FM) != MTK_WCN_BOOL_FALSE; + + return ret; +} + +static int fm_wmt_func_off(void) +{ + int ret = 0; + + ret = mtk_wcn_wmt_func_off(WMTDRV_TYPE_FM) != MTK_WCN_BOOL_FALSE; + + return ret; +} + +static int fm_wmt_ic_info_get(void) +{ + return mtk_wcn_wmt_ic_info_get(1); +} + +static int fm_wmt_chipid_query(void) +{ + return mtk_wcn_wmt_chipid_query(); +} + +static unsigned char drv_get_top_index(void) +{ +#if defined(MT6635_FM) + return 5; +#else + int chipid = fm_wmt_chipid_query(); + + if (chipid == 0x6779 || chipid == 0x6885 || chipid == 0x6873) + return 5; + return 4; +#endif +} + +void register_fw_ops_init(void) +{ + fm_wcn_ops.ei.eint_handler = fw_eint_handler; + fm_wcn_ops.ei.stp_send_data = fm_stp_send_data; + fm_wcn_ops.ei.stp_recv_data = fm_stp_recv_data; + fm_wcn_ops.ei.stp_register_event_cb = fm_stp_register_event_cb; + fm_wcn_ops.ei.wmt_msgcb_reg = fm_wmt_msgcb_reg; + fm_wcn_ops.ei.wmt_func_on = fm_wmt_func_on; + fm_wcn_ops.ei.wmt_func_off = fm_wmt_func_off; + fm_wcn_ops.ei.wmt_ic_info_get = fm_wmt_ic_info_get; + fm_wcn_ops.ei.wmt_chipid_query = fm_wmt_chipid_query; + fm_wcn_ops.ei.get_top_index = drv_get_top_index; +} + +void register_fw_ops_uninit(void) +{ +} + +int fm_register_irq(struct platform_driver *drv) +{ + return 0; +} + +int fm_wcn_ops_register(void) +{ + register_fw_ops_init(); + + return 0; +} + +int fm_wcn_ops_unregister(void) +{ + register_fw_ops_uninit(); + + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/gps/Android.mk b/drivers/misc/mediatek/connectivity/gps/Android.mk new file mode 100644 index 00000000000000..87936b5ff753bd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/gps/Android.mk @@ -0,0 +1,15 @@ +LOCAL_PATH := $(call my-dir) + +ifeq ($(MTK_GPS_SUPPORT), yes) + +include $(CLEAR_VARS) +LOCAL_MODULE := gps_drv.ko +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_OWNER := mtk +LOCAL_INIT_RC := init.gps_drv.rc + +LOCAL_REQUIRED_MODULES := wmt_drv.ko + +include $(MTK_KERNEL_MODULE) + +endif diff --git a/drivers/misc/mediatek/connectivity/gps/Makefile b/drivers/misc/mediatek/connectivity/gps/Makefile new file mode 100644 index 00000000000000..8669ac3e6d708c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/gps/Makefile @@ -0,0 +1,108 @@ +# drivers/barcelona/gps/Makefile +# +# Makefile for the Barcelona GPS driver. +# +# Copyright (C) 2004,2005 TomTom BV <http://www.tomtom.com/> +# Author: Dimitry Andric <dimitry.andric@tomtom.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. + +############################################################################### +# Necessary Check + +ifeq ($(AUTOCONF_H),) + AUTOCONF_H := $(srctree)/include/generated/autoconf.h +endif + +ccflags-y += -imacros $(AUTOCONF_H) + +ifeq ($(TARGET_BUILD_VARIANT),$(filter $(TARGET_BUILD_VARIANT),userdebug user)) + ldflags-y += -s +endif + +# Force build fail on modpost warning +KBUILD_MODPOST_FAIL_ON_WARNINGS := y +############################################################################### + +# only WMT align this design flow, but gps use this also. +#ccflags-y += -D MTK_WCN_REMOVE_KERNEL_MODULE + +ifeq ($(CONFIG_ARM64), y) + ccflags-y += -D CONFIG_MTK_WCN_ARM64 +endif + +ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y) + ccflags-y += -D WMT_IDC_SUPPORT=1 +else + ccflags-y += -D WMT_IDC_SUPPORT=0 +endif + +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/include/mt-plat/$(MTK_PLATFORM)/include/mach +ccflags-y += -I$(srctree)/drivers/misc/mediatek/freqhopping +ccflags-y += -I$(srctree)/drivers/misc/mediatek/freqhopping/$(MTK_PLATFORM) +ccflags-y += -I$(srctree)/drivers/misc/mediatek/emi/submodule +ccflags-y += -I$(srctree)/drivers/misc/mediatek/connectivity/conninfra/base/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/emi/$(MTK_PLATFORM) +ccflags-y += -I$(srctree)/drivers/misc/mediatek/mach/$(MTK_PLATFORM)/include/mach +ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/$(MTK_PLATFORM) +ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include +ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include/clkbuf_v1 +ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include/clkbuf_v1/$(MTK_PLATFORM) +ccflags-y += -I$(srctree)/drivers/devfreq +############################################################################### + +MODULE_NAME := gps_drv +obj-$(CONFIG_MTK_COMBO_GPS) += $(MODULE_NAME).o +#obj-y += $(MODULE_NAME).o + +#WMT_SRC_FOLDER := $(TOP)/vendor/mediatek/kernel_modules/connectivity/common +WMT_SRC_FOLDER := $(srctree)/drivers/misc/mediatek/connectivity/common + +#ifeq ($(CONFIG_MTK_COMBO_CHIP),) +# $(error CONFIG_MTK_COMBO_CHIP not defined) +#endif + +ifneq ($(filter "CONSYS_%",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -DSOC_CO_CLOCK_FLAG=1 + ccflags-y += -DWMT_CREATE_NODE_DYNAMIC=1 + ccflags-y += -DREMOVE_MK_NODE=0 + +ccflags-y += -I$(WMT_SRC_FOLDER)/common_main/$(MTK_PLATFORM)/include + +else + ccflags-y += -DSOC_CO_CLOCK_FLAG=0 + ccflags-y += -DWMT_CREATE_NODE_DYNAMIC=0 + ccflags-y += -DREMOVE_MK_NODE=1 +endif + +ifneq ($(filter "CONSYS_6771" "CONSYS_6775" "CONSYS_6779",$(CONFIG_MTK_COMBO_CHIP)),) + ccflags-y += -DEMI_MPU_PROTECTION_IS_READY=1 +endif + +ccflags-y += -I$(WMT_SRC_FOLDER)/common_main/include +ccflags-y += -I$(WMT_SRC_FOLDER)/common_main/linux/include +ccflags-y += -I$(WMT_SRC_FOLDER)/common_main/core/include +ccflags-y += -I$(WMT_SRC_FOLDER)/common_main/platform/include + +ifneq ($(CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH),) +ccflags-y += -I$(WMT_SRC_FOLDER)/debug_utility +endif + +ifeq ($(CONFIG_MTK_CONN_MT3337_CHIP_SUPPORT),y) + $(MODULE_NAME)-objs += gps_mt3337.o +else + $(MODULE_NAME)-objs += stp_chrdev_gps.o +endif +ifneq ($(CONFIG_MTK_GPS_EMI),) +$(MODULE_NAME)-objs += gps_emi.o +endif +ifneq ($(CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH),) +$(MODULE_NAME)-objs += fw_log_gps.o +endif + +# EOF diff --git a/drivers/misc/mediatek/connectivity/gps/README b/drivers/misc/mediatek/connectivity/gps/README new file mode 100644 index 00000000000000..9046e3ac61ef2c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/gps/README @@ -0,0 +1,2 @@ +GPS driver - kernel modules move out of kernel tree + diff --git a/drivers/misc/mediatek/connectivity/gps/fw_log_gps.c b/drivers/misc/mediatek/connectivity/gps/fw_log_gps.c new file mode 100644 index 00000000000000..5033613e3547ed --- /dev/null +++ b/drivers/misc/mediatek/connectivity/gps/fw_log_gps.c @@ -0,0 +1,254 @@ +/* + * Implementation of the GPS EMI driver. + * + * Copyright (C) 2014 Mediatek + * Authors: + * Heiping <Heiping.Lei@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/******************************************************************************* +* Dependency +*******************************************************************************/ +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/cdev.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/printk.h> +#include <linux/version.h> +#include <asm/memblock.h> +#include <linux/wait.h> +#include "gps.h" +#include "connsys_debug_utility.h" +#ifdef pr_fmt +#undef pr_fmt +#endif +#define pr_fmt(fmt) "["KBUILD_MODNAME"]" fmt + +/****************************************************************************** + * Definition +******************************************************************************/ +/* device name and major number */ +#define GPSFWLOG_DEVNAME "fw_log_gps" +#define GPS_FW_LOG_IOC_MAGIC (0xfc) +#define GPS_FW_LOG_IOCTL_ON_OFF _IOW(GPS_FW_LOG_IOC_MAGIC, 0, int) +#define GPS_FW_LOG_IOCTL_SET_LEVEL _IOW(GPS_FW_LOG_IOC_MAGIC, 1, int) +#define GPS_FW_LOG_IOCTL_GET_LEVEL _IOW(GPS_FW_LOG_IOC_MAGIC, 2, int) + +/******************************************************************************* +* structure & enumeration +*******************************************************************************/ +/*---------------------------------------------------------------------------*/ +struct gps_fw_log_dev { + struct class *cls; + struct device *dev; + dev_t devno; + struct cdev chdev; +}; +/* typedef unsigned char UINT8, *PUINT8, **PPUINT8; */ + +/****************************************************************************** + * local variables +******************************************************************************/ +/* static int flag; */ +struct gps_fw_log_dev *logdevobj; +static wait_queue_head_t GPS_log_wq; +bool fgGps_fw_log_ON; + +/*---------------------------------------------------------------------------*/ +static void log_event_cb(void); + +long fw_log_gps_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long retval = 0; + + switch (cmd) { + case GPS_FW_LOG_IOCTL_ON_OFF: + pr_info("gps PS_FW_LOG_IOCTL_ON_OFF(%lu)\n", arg); + GPS_fwlog_ctrl((bool)arg); + break; + + case GPS_FW_LOG_IOCTL_SET_LEVEL: + pr_info("gps GPS_FW_LOG_IOCTL_SET_LEVEL\n"); + break; + case GPS_FW_LOG_IOCTL_GET_LEVEL: + pr_info("gps GPS_FW_LOG_IOCTL_GET_LEVEL\n"); + break; + + default: + pr_warn("gps unknown cmd (%d)\n", cmd); + break; + } + return retval; +} + +long fw_log_gps_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + return fw_log_gps_unlocked_ioctl(filp, cmd, arg); +} + +/******************************************************************************/ +/*****************************************************************************/ +static int fw_log_open(struct inode *inode, struct file *file) +{ + pr_info("%s: gps major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid); + return 0; +} + +/*****************************************************************************/ + + +/*****************************************************************************/ +static int fw_log_close(struct inode *inode, struct file *file) +{ + pr_info("%s: gps major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid); + return 0; +} + +/******************************************************************************/ +static ssize_t fw_log_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + int retval; + + #if 0 + pr_info("GPS fw_log_read,len=%d\n", count); + #endif + + retval = connsys_log_read_to_user(CONNLOG_TYPE_GPS, buf, count); + return retval; +} +/******************************************************************************/ +static unsigned int fw_log_poll(struct file *file, poll_table *wait) +{ + unsigned int mask = 0; + + poll_wait(file, &GPS_log_wq, wait); + if (connsys_log_get_buf_size(CONNLOG_TYPE_GPS) > 0) + mask = (POLLIN | POLLRDNORM); + + return mask; +} + +/*****************************************************************************/ +/* Kernel interface */ +static const struct file_operations gps_fw_log_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = fw_log_gps_unlocked_ioctl, + .compat_ioctl = fw_log_gps_compat_ioctl, + .open = fw_log_open, + .read = fw_log_read, + .release = fw_log_close, + .poll = fw_log_poll, +}; + +void log_event_cb(void) +{ + wake_up_interruptible(&GPS_log_wq); +} + +static int __init gps_fw_log_init(void) +{ + int ret = 0; + int err = 0; + + logdevobj = kzalloc(sizeof(*logdevobj), GFP_KERNEL); + if (logdevobj == NULL) { + err = -ENOMEM; + ret = -ENOMEM; + goto err_out; + } + + pr_info("Registering chardev\n"); + ret = alloc_chrdev_region(&logdevobj->devno, 0, 1, GPSFWLOG_DEVNAME); + if (ret) { + pr_err("alloc_chrdev_region fail: %d\n", ret); + err = -ENOMEM; + goto err_out; + } else { + pr_info("major: %d, minor: %d\n", MAJOR(logdevobj->devno), MINOR(logdevobj->devno)); + } + cdev_init(&logdevobj->chdev, &gps_fw_log_fops); + logdevobj->chdev.owner = THIS_MODULE; + err = cdev_add(&logdevobj->chdev, logdevobj->devno, 1); + if (err) { + pr_err("cdev_add fail: %d\n", err); + goto err_out; + } + logdevobj->cls = class_create(THIS_MODULE, "gpsfwlog"); + if (IS_ERR(logdevobj->cls)) { + pr_err("Unable to create class, err = %d\n", (int)PTR_ERR(logdevobj->cls)); + goto err_out; + } + logdevobj->dev = device_create(logdevobj->cls, NULL, logdevobj->devno, logdevobj, "fw_log_gps"); + + connsys_log_init(CONNLOG_TYPE_GPS); + init_waitqueue_head(&GPS_log_wq); + connsys_log_register_event_cb(CONNLOG_TYPE_GPS, log_event_cb); + + pr_info("GPS FW LOG device init Done\n"); + return 0; + +err_out: + if (logdevobj != NULL) { + if (err == 0) + cdev_del(&logdevobj->chdev); + if (ret == 0) + unregister_chrdev_region(logdevobj->devno, 1); + kfree(logdevobj); + logdevobj = NULL; + } + return -1; +} + +/*****************************************************************************/ +static void __exit gps_fw_log_exit(void) +{ + if (!logdevobj) { + pr_err("null pointer: %p\n", logdevobj); + return; + } + + pr_info("Unregistering chardev\n"); + connsys_log_deinit(CONNLOG_TYPE_GPS); + cdev_del(&logdevobj->chdev); + unregister_chrdev_region(logdevobj->devno, 1); + device_destroy(logdevobj->cls, logdevobj->devno); + class_destroy(logdevobj->cls); + kfree(logdevobj); + pr_info("Done\n"); +} + +int mtk_gps_fw_log_init(void) +{ + pr_info("gps fw log init begin"); + return gps_fw_log_init(); +} + +void mtk_gps_fw_log_exit(void) +{ + pr_info("gps fw log exit begin"); + return gps_fw_log_exit(); +} + +/*****************************************************************************/ +#if 0 +module_init(gps_emi_mod_init); +module_exit(gps_emi_mod_exit); +#endif +/*****************************************************************************/ +MODULE_AUTHOR("Chaoran Zhang <Chaoran.Zhang@mediatek.com>"); +MODULE_DESCRIPTION("GPS FW log driver"); +MODULE_LICENSE("GPL"); +#endif diff --git a/drivers/misc/mediatek/connectivity/gps/gps.h b/drivers/misc/mediatek/connectivity/gps/gps.h new file mode 100644 index 00000000000000..4da5e037fb9da9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/gps/gps.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + * + * brief Declaration of library functions + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. + */ + +#ifndef _GPS_H_ +#define _GPS_H_ + +#include "wmt_core.h" +#include "wmt_dev.h" +#include "osal.h" +#include "mtk_wcn_consys_hw.h" + +extern phys_addr_t gConEmiPhyBase; + +extern int mtk_wcn_stpgps_drv_init(void); +extern void mtk_wcn_stpgps_drv_exit(void); +#ifdef CONFIG_MTK_GPS_EMI +extern int mtk_gps_emi_init(void); +extern void mtk_gps_emi_exit(void); +#endif +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +extern int mtk_gps_fw_log_init(void); +extern void mtk_gps_fw_log_exit(void); +void GPS_fwlog_ctrl(bool on); +#endif + +#endif diff --git a/drivers/misc/mediatek/connectivity/gps/gps_emi.c b/drivers/misc/mediatek/connectivity/gps/gps_emi.c new file mode 100644 index 00000000000000..f411fb9228f352 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/gps/gps_emi.c @@ -0,0 +1,541 @@ +/* + * Implementation of the GPS EMI driver. + * + * Copyright (C) 2014 Mediatek + * Authors: + * Heiping <Heiping.Lei@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/******************************************************************************* +* Dependency +*******************************************************************************/ +#ifdef CONFIG_MTK_GPS_EMI +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/cdev.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/uaccess.h> +#include <linux/printk.h> +#include <linux/version.h> +#include <asm/memblock.h> +#if EMI_MPU_PROTECTION_IS_READY +#include <mt_emi_api.h> +#endif +#include "gps.h" + +#ifdef pr_fmt +#undef pr_fmt +#endif +#define pr_fmt(fmt) "["KBUILD_MODNAME"]" fmt + +/****************************************************************************** + * Definition +******************************************************************************/ +/* device name and major number */ +#define GPSEMI_DEVNAME "gps_emi" +#define IOCTL_EMI_MEMORY_INIT 1 +#define IOCTL_MNL_NVRAM_FILE_TO_MEM 2 +#define IOCTL_MNL_NVRAM_MEM_TO_FILE 3 +#define IOCTL_ADC_CAPTURE_ADDR_GET 4 + +#if defined(CONFIG_MACH_MT6765) || defined(CONFIG_MACH_MT6761) || defined(CONFIG_MACH_MT6768) +#define GPS_EMI_MPU_REGION 29 +#define GPS_EMI_BASE_ADDR_OFFSET (2*SZ_1M + SZ_1M/2 + 0x1000) +#define GPS_EMI_MPU_SIZE (SZ_1M + SZ_1M/2 - 0x2000) +#endif +#if defined(CONFIG_MACH_MT6779) +#define GPS_EMI_MPU_REGION 29 +#define GPS_EMI_BASE_ADDR_OFFSET (3*SZ_1M + 0x10000) +#define GPS_EMI_MPU_SIZE (0xF0000) +#endif +#if defined(CONFIG_MACH_MT6771) || defined(CONFIG_MACH_MT6775) || defined(CONFIG_MACH_MT6758) +#define GPS_EMI_MPU_REGION 30 +#define GPS_EMI_BASE_ADDR_OFFSET (SZ_1M) +#define GPS_EMI_MPU_SIZE (SZ_1M) +#endif +#define GPS_ADC_CAPTURE_BUFF_SIZE 0x50000 +/****************************************************************************** + * Debug configuration +******************************************************************************/ +#define GPS_DBG_NONE(fmt, arg...) do {} while (0) +#define GPS_DBG pr_err +#define GPS_TRC GPS_DBG_NONE +#define GPS_VER pr_err +#define GPS_ERR pr_err +/******************************************************************************* +* structure & enumeration +*******************************************************************************/ +/*---------------------------------------------------------------------------*/ +struct gps_emi_dev { + struct class *cls; + struct device *dev; + dev_t devno; + struct cdev chdev; +}; +/* typedef unsigned char UINT8, *PUINT8, **PPUINT8; */ + +/****************************************************************************** + * local variables +******************************************************************************/ +phys_addr_t gGpsEmiPhyBase; +void __iomem *pGpsEmibaseaddr; +struct gps_emi_dev *devobj; + +static struct semaphore fw_dl_mtx; + +void mtk_wcn_consys_gps_memory_reserve(void) +{ +#if 0 +#ifdef MTK_WCN_ARM64 + gGpsEmiPhyBase = arm64_memblock_steal(SZ_1M, SZ_1M); +#else + gGpsEmiPhyBase = arm_memblock_steal(SZ_1M, SZ_1M); +#endif +#else + gGpsEmiPhyBase = gConEmiPhyBase + GPS_EMI_BASE_ADDR_OFFSET; + +#endif + if (gGpsEmiPhyBase) + GPS_DBG("Con:0x%zx, Gps:0x%zx\n", (size_t)gConEmiPhyBase, (size_t)gGpsEmiPhyBase); + else + GPS_DBG("memblock fail\n"); +} + +INT32 gps_emi_mpu_set_region_protection(INT32 region) +{ + #if EMI_MPU_PROTECTION_IS_READY + struct emi_region_info_t region_info; + /*set MPU for EMI share Memory */ + GPS_DBG("setting MPU for EMI share memory\n"); + region_info.start = gGpsEmiPhyBase; + region_info.end = gGpsEmiPhyBase + GPS_EMI_MPU_SIZE - 1; + region_info.region = region; + SET_ACCESS_PERMISSION(region_info.apc, LOCK, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN, + NO_PROTECTION, FORBIDDEN, NO_PROTECTION); + emi_mpu_set_protection(®ion_info); + #endif + return 0; +} + +INT32 gps_emi_patch_get(PUINT8 pPatchName, osal_firmware **ppPatch) +{ + INT32 iRet = -1; + osal_firmware *fw = NULL; + + if (!ppPatch) { + GPS_DBG("invalid ppBufptr!\n"); + return -1; + } + *ppPatch = NULL; + iRet = request_firmware((const struct firmware **)&fw, pPatchName, NULL); + if (iRet != 0) { + GPS_DBG("failed to open or read!(%s)\n", pPatchName); + return -1; + } + GPS_DBG("loader firmware %s ok!!\n", pPatchName); + iRet = 0; + *ppPatch = fw; + + return iRet; +} + +INT32 mtk_wcn_consys_gps_emi_init(void) +{ + INT32 iRet = -1; + down(&fw_dl_mtx); + mtk_wcn_consys_gps_memory_reserve(); + if (gGpsEmiPhyBase) { + /*set MPU for EMI share Memory*/ + #if EMI_MPU_PROTECTION_IS_READY + GPS_DBG("setting MPU for EMI share memory\n"); + gps_emi_mpu_set_region_protection(GPS_EMI_MPU_REGION); + #endif + GPS_DBG("get consys start phy address(0x%zx)\n", (size_t)gGpsEmiPhyBase); + #if 0 + /*consys to ap emi remapping register:10001310, cal remapping address*/ + addrPhy = (gGpsEmiPhyBase & 0xFFF00000) >> 20; + + /*enable consys to ap emi remapping bit12*/ + addrPhy -= 0x400;/*Gavin ??*/ + addrPhy = addrPhy | 0x1000; + + CONSYS_REG_WRITE(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET, + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET) | addrPhy); + + GPS_DBG("GPS_EMI_MAPPING dump(0x%08x)\n", + CONSYS_REG_READ(conn_reg.topckgen_base + CONSYS_EMI_MAPPING_OFFSET)); + #endif + + pGpsEmibaseaddr = ioremap(gGpsEmiPhyBase, GPS_EMI_MPU_SIZE); + iRet = 1; + #if 0 + if (pGpsEmibaseaddr != NULL) { + unsigned char *pFullPatchName = "MNL.bin"; + osal_firmware *pPatch = NULL; + + GPS_DBG("EMI mapping OK(0x%p)\n", pGpsEmibaseaddr); + memset_io(pGpsEmibaseaddr, 0, GPS_EMI_MPU_SIZE); + if ((pFullPatchName != NULL) + && (gps_emi_patch_get(pFullPatchName, &pPatch) == 0)) { + if (pPatch != NULL) { + /*get full name patch success*/ + GPS_DBG("get full patch name(%s) buf(0x%p) size(%ld)\n", + pFullPatchName, (pPatch)->data, (pPatch)->size); + GPS_DBG("AF get patch, pPatch(0x%p)\n", pPatch); + } + } + if (pPatch != NULL) { + if ((pPatch)->size <= GPS_EMI_MPU_SIZE) { + GPS_DBG("Prepare to copy FW\n"); + memcpy(pGpsEmibaseaddr, (pPatch)->data, (pPatch)->size); + iRet = 1; + GPS_DBG("pGpsEmibaseaddr_1:0x%08x 0x%08x 0x%08x 0x%08x\n", + *(unsigned int *)pGpsEmibaseaddr, + *(((unsigned int *)pGpsEmibaseaddr)+1), + *(((unsigned int *)pGpsEmibaseaddr)+2), + *(((unsigned int *)pGpsEmibaseaddr)+3)); + GPS_DBG("pGpsEmibaseaddr_2:0x%08x 0x%08x 0x%08x 0x%08x\n", + *(((unsigned int *)pGpsEmibaseaddr)+4), + *(((unsigned int *)pGpsEmibaseaddr)+5), + *(((unsigned int *)pGpsEmibaseaddr)+6), + *(((unsigned int *)pGpsEmibaseaddr)+7)); + } + release_firmware(pPatch); + pPatch = NULL; + } + iounmap(pGpsEmibaseaddr); + } else { + GPS_DBG("EMI mapping fail\n"); + } + #endif + } else { + GPS_DBG("gps emi memory address gGpsEmiPhyBase invalid\n"); + } + up(&fw_dl_mtx); + return iRet; +} + +/*---------------------------------------------------------------------------*/ +long gps_emi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + unsigned int *tmp; + + GPS_DBG("gps_emi:cmd (%d),arg(%ld)\n", cmd, arg); + + switch (cmd) { + case IOCTL_EMI_MEMORY_INIT: + retval = mtk_wcn_consys_gps_emi_init(); + GPS_DBG("IOCTL_EMI_MEMORY_INIT\n"); + break; + + case IOCTL_MNL_NVRAM_FILE_TO_MEM: + GPS_DBG("IOCTL_MNL_NVRAM_FILE_TO_MEM\n"); + break; + + case IOCTL_MNL_NVRAM_MEM_TO_FILE: + GPS_DBG("IOCTL_MNL_NVRAM_MEM_TO_FILE\n"); + break; + + case IOCTL_ADC_CAPTURE_ADDR_GET: + tmp = (unsigned int *)&gGpsEmiPhyBase; + GPS_DBG("gps_emi:gGpsEmiPhyBase (%x)\n", &gGpsEmiPhyBase); + GPS_DBG("gps_emi:tmp (%x)\n", tmp); + if (copy_to_user((unsigned int __user *)arg, tmp, sizeof(unsigned int))) + retval = -1; + GPS_DBG("IOCTL_ADC_CAPTURE_ADDR_GET,(%d)\n", retval); + break; + + default: + GPS_DBG("unknown cmd (%d)\n", cmd); + retval = 0; + break; + } + return retval; + +} + +/******************************************************************************/ +long gps_emi_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + return gps_emi_unlocked_ioctl(filp, cmd, arg); +} + +/*****************************************************************************/ +static int gps_emi_open(struct inode *inode, struct file *file) +{ + GPS_TRC(); + return nonseekable_open(inode, file); +} + +/*****************************************************************************/ + + +/*****************************************************************************/ +static int gps_emi_release(struct inode *inode, struct file *file) +{ + GPS_TRC(); + + return 0; +} + +/******************************************************************************/ +static ssize_t gps_emi_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + ssize_t ret = 0; + GPS_DBG("gps_emi_read begin\n"); + if (count > GPS_ADC_CAPTURE_BUFF_SIZE) + count = GPS_ADC_CAPTURE_BUFF_SIZE; + if (pGpsEmibaseaddr != NULL) { + if (copy_to_user(buf, (char *)pGpsEmibaseaddr, count)) + pr_err("Copy to user failed\n"); + } + GPS_DBG("gps_emi_read finish\n"); + return ret; +} +/******************************************************************************/ +static ssize_t gps_emi_write(struct file *file, const char __user *buf, size_t count, + loff_t *ppos) +{ + ssize_t ret = 0; + + GPS_TRC(); + + return ret; +} + + +/*****************************************************************************/ +/* Kernel interface */ +static const struct file_operations gps_emi_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = gps_emi_unlocked_ioctl, + .compat_ioctl = gps_emi_compat_ioctl, + .open = gps_emi_open, + .read = gps_emi_read, + .write = gps_emi_write, + .release = gps_emi_release, +}; + +/*****************************************************************************/ +static int gps_emi_probe(struct platform_device *dev) +{ + int ret = 0, err = 0; + + pr_err("Enter gps_emi_probe\n"); + + devobj = kzalloc(sizeof(*devobj), GFP_KERNEL); + if (devobj == NULL) { + err = -ENOMEM; + ret = -ENOMEM; + goto err_out; + } + + pr_err("Registering chardev\n"); + ret = alloc_chrdev_region(&devobj->devno, 0, 1, GPSEMI_DEVNAME); + if (ret) { + GPS_ERR("alloc_chrdev_region fail: %d\n", ret); + err = -ENOMEM; + goto err_out; + } else { + GPS_ERR("major: %d, minor: %d\n", MAJOR(devobj->devno), MINOR(devobj->devno)); + } + cdev_init(&devobj->chdev, &gps_emi_fops); + devobj->chdev.owner = THIS_MODULE; + err = cdev_add(&devobj->chdev, devobj->devno, 1); + if (err) { + GPS_ERR("cdev_add fail: %d\n", err); + goto err_out; + } + devobj->cls = class_create(THIS_MODULE, "gpsemi"); + if (IS_ERR(devobj->cls)) { + GPS_ERR("Unable to create class, err = %d\n", (int)PTR_ERR(devobj->cls)); + goto err_out; + } + devobj->dev = device_create(devobj->cls, NULL, devobj->devno, devobj, "gps_emi"); + + GPS_ERR("GPS EMI Done\n"); + return 0; + +err_out: + if (devobj != NULL) { + if (err == 0) + cdev_del(&devobj->chdev); + if (ret == 0) + unregister_chrdev_region(devobj->devno, 1); + + kfree(devobj); + devobj = NULL; + } + return -1; +} + +/*****************************************************************************/ +static int gps_emi_remove(struct platform_device *dev) +{ + if (!devobj) { + GPS_ERR("null pointer: %p\n", devobj); + return -1; + } + + GPS_DBG("Unregistering chardev\n"); + cdev_del(&devobj->chdev); + unregister_chrdev_region(devobj->devno, 1); + device_destroy(devobj->cls, devobj->devno); + class_destroy(devobj->cls); + kfree(devobj); + GPS_DBG("Done\n"); + return 0; +} + +/*****************************************************************************/ +#ifdef CONFIG_PM +/*****************************************************************************/ +static int gps_emi_suspend(struct platform_device *dev, pm_message_t state) +{ + GPS_DBG("dev = %p, event = %u,", dev, state.event); + if (state.event == PM_EVENT_SUSPEND) + GPS_DBG("Receive PM_EVENT_SUSPEND!!\n"); + return 0; +} + +/*****************************************************************************/ +static int gps_emi_resume(struct platform_device *dev) +{ + GPS_DBG(""); + return 0; +} + +/*****************************************************************************/ +#endif /* CONFIG_PM */ +/*****************************************************************************/ +#ifdef CONFIG_OF +static const struct of_device_id apgps_of_ids[] = { + { .compatible = "mediatek,gps_emi-v1", }, + {} +}; +#endif +static struct platform_driver gps_emi_driver = { + .probe = gps_emi_probe, + .remove = gps_emi_remove, +#if defined(CONFIG_PM) + .suspend = gps_emi_suspend, + .resume = gps_emi_resume, +#endif + .driver = { + .name = GPSEMI_DEVNAME, + .bus = &platform_bus_type, +#ifdef CONFIG_OF + .of_match_table = apgps_of_ids, +#endif + }, +}; + +/*****************************************************************************/ +static int __init gps_emi_mod_init(void) +{ + GPS_ERR("gps emi mod register begin"); + int ret = 0; + int err = 0; + + sema_init(&fw_dl_mtx, 1); + + devobj = kzalloc(sizeof(*devobj), GFP_KERNEL); + if (devobj == NULL) { + err = -ENOMEM; + ret = -ENOMEM; + goto err_out; + } + + GPS_ERR("Registering chardev\n"); + ret = alloc_chrdev_region(&devobj->devno, 0, 1, GPSEMI_DEVNAME); + if (ret) { + GPS_ERR("alloc_chrdev_region fail: %d\n", ret); + err = -ENOMEM; + goto err_out; + } else { + GPS_ERR("major: %d, minor: %d\n", MAJOR(devobj->devno), MINOR(devobj->devno)); + } + cdev_init(&devobj->chdev, &gps_emi_fops); + devobj->chdev.owner = THIS_MODULE; + err = cdev_add(&devobj->chdev, devobj->devno, 1); + if (err) { + GPS_ERR("cdev_add fail: %d\n", err); + goto err_out; + } + devobj->cls = class_create(THIS_MODULE, "gpsemi"); + if (IS_ERR(devobj->cls)) { + GPS_ERR("Unable to create class, err = %d\n", (int)PTR_ERR(devobj->cls)); + goto err_out; + } + devobj->dev = device_create(devobj->cls, NULL, devobj->devno, devobj, "gps_emi"); + + + GPS_ERR("GPS EMI Done\n"); + return 0; + +err_out: + if (devobj != NULL) { + if (err == 0) + cdev_del(&devobj->chdev); + if (ret == 0) + unregister_chrdev_region(devobj->devno, 1); + + kfree(devobj); + devobj = NULL; + } + return -1; +} + +/*****************************************************************************/ +static void __exit gps_emi_mod_exit(void) +{ + if (!devobj) { + GPS_ERR("null pointer: %p\n", devobj); + return; + } + + GPS_ERR("Unregistering chardev\n"); + cdev_del(&devobj->chdev); + unregister_chrdev_region(devobj->devno, 1); + device_destroy(devobj->cls, devobj->devno); + class_destroy(devobj->cls); + kfree(devobj); + GPS_ERR("Done\n"); +} + +int mtk_gps_emi_init(void) +{ + GPS_ERR("gps emi mod init begin"); + return gps_emi_mod_init(); +} + +void mtk_gps_emi_exit(void) +{ + GPS_ERR("gps emi mod exit begin"); + return gps_emi_mod_exit(); +} + +/*****************************************************************************/ +#if 0 +module_init(gps_emi_mod_init); +module_exit(gps_emi_mod_exit); +#endif +/*****************************************************************************/ +MODULE_AUTHOR("Heiping Lei <Heiping.Lei@mediatek.com>"); +MODULE_DESCRIPTION("GPS EMI Driver"); +MODULE_LICENSE("GPL"); +#endif diff --git a/drivers/misc/mediatek/connectivity/gps/gps_mt3337.c b/drivers/misc/mediatek/connectivity/gps/gps_mt3337.c new file mode 100644 index 00000000000000..ef9e8de2e3805c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/gps/gps_mt3337.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/ioctl.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> + +#define DEVICE_NAME "mt3337_gpsonly" + +#ifdef pr_fmt +#undef pr_fmt +#endif +#define pr_fmt(fmt) "["KBUILD_MODNAME"]" fmt + +#define GPS_POWER_IOCTL _IOW('G', 0, int) + +static long gps_ioctrl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct miscdevice *dev; + struct regulator *reg; + int ret; + + switch (cmd) { + case GPS_POWER_IOCTL: + dev = (struct miscdevice *)filp->private_data; + reg = dev_get_drvdata(dev->this_device); + if (arg) + ret = regulator_enable(reg); + else + ret = regulator_disable(reg); + return ret; + default: + return -EINVAL; + } + return 0; +} + +static const struct file_operations gps_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = gps_ioctrl, + .compat_ioctl = gps_ioctrl, +}; + +static struct miscdevice mt3337_gps_driver = { + .minor = MISC_DYNAMIC_MINOR, + .name = DEVICE_NAME, + .fops = &gps_fops, +}; + +static int mt3337_gps_probe(struct platform_device *pdev) +{ + int ret; + struct regulator *regulator; + + regulator = devm_regulator_get(&pdev->dev, "power"); + if (IS_ERR(regulator)) + return PTR_ERR(regulator); + + ret = misc_register(&mt3337_gps_driver); + if (ret < 0) + return ret; + + dev_set_drvdata(mt3337_gps_driver.this_device, regulator); + + return 0; +} + +static const struct of_device_id mt3337_gps_of_match[] = { + { .compatible = "mediatek,mt3337" }, + {}, +}; + +static struct platform_driver mt3337_gps_pdriver = { + .probe = mt3337_gps_probe, + .driver = { + .name = DEVICE_NAME, + .of_match_table = of_match_ptr(mt3337_gps_of_match), + }, +}; + +module_platform_driver(mt3337_gps_pdriver); + +MODULE_AUTHOR("Hao Dong <hao.dong@mediatek.com>"); +MODULE_DESCRIPTION("MT3337 GPS Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/mediatek/connectivity/gps/init.gps_drv.rc b/drivers/misc/mediatek/connectivity/gps/init.gps_drv.rc new file mode 100644 index 00000000000000..258aa6811002b2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/gps/init.gps_drv.rc @@ -0,0 +1,4 @@ + +# load gps_drv +on property:vendor.connsys.driver.ready=yes + insmod /vendor/lib/modules/gps_drv.ko diff --git a/drivers/misc/mediatek/connectivity/gps/stp_chrdev_gps.c b/drivers/misc/mediatek/connectivity/gps/stp_chrdev_gps.c new file mode 100644 index 00000000000000..b552c11d36c315 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/gps/stp_chrdev_gps.c @@ -0,0 +1,1256 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/sched.h> +#include <linux/device.h> +#include <linux/pm_wakeup.h> +#include <asm/current.h> +#include <linux/uaccess.h> +#include <linux/skbuff.h> +#include <linux/jiffies.h> +#include <linux/time.h> +#include <linux/sched.h> +#include <asm/div64.h> +#include "osal_typedef.h" +#include "stp_exp.h" +#include "wmt_exp.h" +#include <connectivity_build_in_adapter.h> +#if defined(CONFIG_MACH_MT6580) +#include <mt_clkbuf_ctl.h> +#endif +#include "gps.h" +#if defined(CONFIG_MACH_MT6739) +#include <mtk_freqhopping.h> +#include <mtk_freqhopping_drv.h> +#endif +#if defined(CONFIG_MACH_MT6765) || defined(CONFIG_MACH_MT6761) +#include <helio-dvfsrc.h> +#endif + +MODULE_LICENSE("GPL"); + +#define GPS_DRIVER_NAME "mtk_stp_GPS_chrdev" +#define GPS_DEV_MAJOR 191 /* never used number */ +#define GPS_DEBUG_TRACE_GPIO 0 +#define GPS_DEBUG_DUMP 0 + +#define PFX "[GPS] " +#define GPS_LOG_DBG 3 +#define GPS_LOG_INFO 2 +#define GPS_LOG_WARN 1 +#define GPS_LOG_ERR 0 + +#define COMBO_IOC_GPS_HWVER 6 +#define COMBO_IOC_GPS_IC_HW_VERSION 7 +#define COMBO_IOC_GPS_IC_FW_VERSION 8 +#define COMBO_IOC_D1_EFUSE_GET 9 +#define COMBO_IOC_RTC_FLAG 10 +#define COMBO_IOC_CO_CLOCK_FLAG 11 +#define COMBO_IOC_TRIGGER_WMT_ASSERT 12 +#define COMBO_IOC_WMT_STATUS 13 +#define COMBO_IOC_TAKE_GPS_WAKELOCK 14 +#define COMBO_IOC_GIVE_GPS_WAKELOCK 15 +#define COMBO_IOC_GET_GPS_LNA_PIN 16 +#define COMBO_IOC_GPS_FWCTL 17 +#define COMBO_IOC_GPS_HW_SUSPEND 18 +#define COMBO_IOC_GPS_HW_RESUME 19 +#define COMBO_IOC_GPS_LISTEN_RST_EVT 20 + +#if defined(CONFIG_MACH_MT6765) || defined(CONFIG_MACH_MT6761) || defined(CONFIG_MACH_MT6779) \ +|| defined(CONFIG_MACH_MT6768) +#define GPS_FWCTL_SUPPORT +#endif + +#ifdef GPS_FWCTL_SUPPORT +/* Disable: #define GPS_FWCTL_IOCTL_SUPPORT */ + +#if defined(CONFIG_MACH_MT6768) +#define GPS_HW_SUSPEND_SUPPORT +#endif + +#endif /* GPS_FWCTL_SUPPORT */ + +static UINT32 gDbgLevel = GPS_LOG_DBG; + +#define GPS_DBG_FUNC(fmt, arg...) \ +do { if (gDbgLevel >= GPS_LOG_DBG) \ + pr_debug(PFX "[D]%s: " fmt, __func__, ##arg); \ +} while (0) +#define GPS_INFO_FUNC(fmt, arg...) \ +do { if (gDbgLevel >= GPS_LOG_INFO) \ + pr_info(PFX "[I]%s: " fmt, __func__, ##arg); \ +} while (0) +#define GPS_WARN_FUNC(fmt, arg...) \ +do { if (gDbgLevel >= GPS_LOG_WARN) \ + pr_warn(PFX "[W]%s: " fmt, __func__, ##arg); \ +} while (0) +#define GPS_ERR_FUNC(fmt, arg...) \ +do { if (gDbgLevel >= GPS_LOG_ERR) \ + pr_err(PFX "[E]%s: " fmt, __func__, ##arg); \ +} while (0) +#define GPS_TRC_FUNC(f) \ +do { if (gDbgLevel >= GPS_LOG_DBG) \ + pr_info(PFX "<%s> <%d>\n", __func__, __LINE__); \ +} while (0) + +#ifdef GPS_FWCTL_SUPPORT +bool fgGps_fwctl_ready; +#endif + +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +bool fgGps_fwlog_on; +#endif + +static int GPS_devs = 1; /* device count */ +static int GPS_major = GPS_DEV_MAJOR; /* dynamic allocation */ +module_param(GPS_major, uint, 0); +static struct cdev GPS_cdev; + +static struct wakeup_source *gps_wake_lock_ptr; +static unsigned char wake_lock_acquired; /* default: 0 */ + +#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD)) +#define STP_GPS_BUFFER_SIZE 2048 +#else +#define STP_GPS_BUFFER_SIZE MTKSTP_BUFFER_SIZE +#endif +static unsigned char i_buf[STP_GPS_BUFFER_SIZE]; /* input buffer of read() */ +static unsigned char o_buf[STP_GPS_BUFFER_SIZE]; /* output buffer of write() */ +static struct semaphore wr_mtx, rd_mtx, fwctl_mtx, status_mtx; +static DECLARE_WAIT_QUEUE_HEAD(GPS_wq); +static DECLARE_WAIT_QUEUE_HEAD(GPS_rst_wq); +static int flag; +static int rstflag; +static int rst_listening_flag; +static int rst_happened_or_gps_close_flag; + +enum gps_ctrl_status_enum { + GPS_CLOSED, + GPS_OPENED, + GPS_SUSPENDED, + GPS_RESET_START, + GPS_RESET_DONE, + GPS_CTRL_STATUS_NUM +}; +static enum gps_ctrl_status_enum g_gps_ctrl_status; + +static void GPS_check_and_wakeup_rst_listener(enum gps_ctrl_status_enum to) +{ + if (to == GPS_RESET_START || to == GPS_RESET_DONE || to == GPS_CLOSED) { + rst_happened_or_gps_close_flag = 1; + if (rst_listening_flag) { + wake_up(&GPS_rst_wq); + GPS_WARN_FUNC("Set GPS rst_happened_or_gps_close_flag because to = %d", to); + } + } +} + +#ifdef GPS_HW_SUSPEND_SUPPORT +static void GPS_ctrl_status_change_from_to(enum gps_ctrl_status_enum from, enum gps_ctrl_status_enum to) +{ + bool okay = true; + enum gps_ctrl_status_enum status_backup; + + down(&status_mtx); + /* Due to checking status and setting status are not atomic, + * mutex is needed to make sure they are an atomic operation. + * Note: reading the status is no need to protect + */ + status_backup = g_gps_ctrl_status; + if (status_backup == from) + g_gps_ctrl_status = to; + else + okay = false; + up(&status_mtx); + + if (!okay) + GPS_WARN_FUNC("GPS unexpected status %d, not chagne from %d to %d", status_backup, from, to); + else + GPS_check_and_wakeup_rst_listener(to); +} +#endif + +static enum gps_ctrl_status_enum GPS_ctrl_status_change_to(enum gps_ctrl_status_enum to) +{ + enum gps_ctrl_status_enum status_backup; + + down(&status_mtx); + status_backup = g_gps_ctrl_status; + g_gps_ctrl_status = to; + up(&status_mtx); + + GPS_check_and_wakeup_rst_listener(to); + + return status_backup; +} + +static void GPS_event_cb(void); + +static void gps_hold_wake_lock(int hold) +{ + if (hold == 1) { + if (!wake_lock_acquired) { + GPS_DBG_FUNC("acquire gps wake_lock acquired = %d\n", wake_lock_acquired); + __pm_stay_awake(gps_wake_lock_ptr); + wake_lock_acquired = 1; + } else { + GPS_DBG_FUNC("acquire gps wake_lock acquired = %d (do nothing)\n", wake_lock_acquired); + } + } else if (hold == 0) { + if (wake_lock_acquired) { + GPS_DBG_FUNC("release gps wake_lock acquired = %d\n", wake_lock_acquired); + __pm_relax(gps_wake_lock_ptr); + wake_lock_acquired = 0; + } else { + GPS_DBG_FUNC("release gps wake_lock acquired = %d (do nothing)\n", wake_lock_acquired); + } + } +} + +bool rtc_GPS_low_power_detected(void) +{ + static bool first_query = true; + + if (first_query) { + first_query = false; + /*return rtc_low_power_detected();*/ + return 0; + } else { + return false; + } +} + +ssize_t GPS_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + int retval = 0; + int written = 0; + + down(&wr_mtx); + + /* GPS_TRC_FUNC(); */ + + /*pr_warn("%s: count %d pos %lld\n", __func__, count, *f_pos); */ + if (count > 0) { + int copy_size = (count < STP_GPS_BUFFER_SIZE) ? count : STP_GPS_BUFFER_SIZE; + + if (copy_from_user(&o_buf[0], &buf[0], copy_size)) { + retval = -EFAULT; + goto out; + } + /* pr_warn("%02x ", val); */ +#if GPS_DEBUG_TRACE_GPIO + mtk_wcn_stp_debug_gpio_assert(IDX_GPS_TX, DBG_TIE_LOW); +#endif + written = mtk_wcn_stp_send_data(&o_buf[0], copy_size, GPS_TASK_INDX); +#if GPS_DEBUG_TRACE_GPIO + mtk_wcn_stp_debug_gpio_assert(IDX_GPS_TX, DBG_TIE_HIGH); +#endif + +#if GPS_DEBUG_DUMP + { + unsigned char *buf_ptr = &o_buf[0]; + int k = 0; + + pr_warn("--[GPS-WRITE]--"); + for (k = 0; k < 10; k++) { + if (k % 16 == 0) + pr_warn("\n"); + pr_warn("0x%02x ", o_buf[k]); + } + pr_warn("\n"); + } +#endif + if (written == 0) { + retval = -ENOSPC; + /* no windowspace in STP is available, */ + /* native process should not call GPS_write with no delay at all */ + GPS_ERR_FUNC + ("target packet length:%zd, write success length:%d, retval = %d.\n", + count, written, retval); + } else { + retval = written; + } + } else { + retval = -EFAULT; + GPS_ERR_FUNC("target packet length:%zd is not allowed, retval = %d.\n", count, retval); + } +out: + up(&wr_mtx); + return retval; +} + +ssize_t GPS_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) +{ + long val = 0; + int retval; + + down(&rd_mtx); + + /* pr_debug("GPS_read(): count %d pos %lld\n", count, *f_pos); */ + if (rstflag == 1) { + if (filp->f_flags & O_NONBLOCK) { + /* GPS_DBG_FUNC("Non-blocking read, whole chip reset occurs! rstflag=%d\n", rstflag); */ + retval = -EIO; + goto OUT; + } + } + + if (count > STP_GPS_BUFFER_SIZE) + count = STP_GPS_BUFFER_SIZE; + +#if GPS_DEBUG_TRACE_GPIO + mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_LOW); +#endif + retval = mtk_wcn_stp_receive_data(i_buf, count, GPS_TASK_INDX); +#if GPS_DEBUG_TRACE_GPIO + mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_HIGH); +#endif + + while (retval == 0) { + /* got nothing, wait for STP's signal */ + /* wait_event(GPS_wq, flag != 0); *//* George: let signal wake up */ + if (filp->f_flags & O_NONBLOCK) { + /* GPS_DBG_FUNC("Non-blocking read, no data is available!\n"); */ + retval = -EAGAIN; + goto OUT; + } + + val = wait_event_interruptible(GPS_wq, flag != 0); + flag = 0; + +#if GPS_DEBUG_TRACE_GPIO + mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_LOW); +#endif + + retval = mtk_wcn_stp_receive_data(i_buf, count, GPS_TASK_INDX); + +#if GPS_DEBUG_TRACE_GPIO + mtk_wcn_stp_debug_gpio_assert(IDX_GPS_RX, DBG_TIE_HIGH); +#endif + /* if we are signaled */ + if (val) { + if (-ERESTARTSYS == val) + GPS_DBG_FUNC("signaled by -ERESTARTSYS(%ld)\n ", val); + else + GPS_DBG_FUNC("signaled by %ld\n ", val); + + break; + } + } + +#if GPS_DEBUG_DUMP + { + unsigned char *buf_ptr = &i_buf[0]; + int k = 0; + + pr_warn("--[GPS-READ]--"); + for (k = 0; k < 10; k++) { + if (k % 16 == 0) + pr_warn("\n"); + pr_warn("0x%02x ", i_buf[k]); + } + pr_warn("--\n"); + } +#endif + + if (retval > 0) { + /* we got something from STP driver */ + if (copy_to_user(buf, i_buf, retval)) { + retval = -EFAULT; + goto OUT; + } else { + /* success */ + } + } else { + /* we got nothing from STP driver, being signaled */ + retval = val; + } + +OUT: + up(&rd_mtx); +/* pr_warn("GPS_read(): retval = %d\n", retval);*/ + return retval; +} + +#ifdef GPS_FWCTL_SUPPORT +#define GPS_FWCTL_OPCODE_ENTER_SLEEP_MODE (2) +#define GPS_FWCTL_OPCODE_EXIT_SLEEP_MODE (3) +#define GPS_FWCTL_OPCODE_ENTER_STOP_MODE (4) +#define GPS_FWCTL_OPCODE_EXIT_STOP_MODE (5) +#define GPS_FWCTL_OPCODE_LOG_CFG (6) +#define GPS_FWCTL_OPCODE_LOOPBACK_TEST (7) + +#ifdef GPS_FWCTL_IOCTL_SUPPORT +struct gps_fwctl_data { + UINT32 size; + UINT32 tx_len; + UINT32 rx_max; + UINT32 pad; /* 128byte */ + UINT64 p_tx_buf; /* cast pointer to UINT64 to be compatible both 32/64bit */ + UINT64 p_rx_buf; /* 256byte */ + UINT64 p_rx_len; + UINT64 p_reserved; /* 384byte */ +}; + +#define GPS_FWCTL_BUF_MAX (128) +long GPS_fwctl(struct gps_fwctl_data *user_ptr) +{ + UINT8 tx_buf[GPS_FWCTL_BUF_MAX]; + UINT8 rx_buf[GPS_FWCTL_BUF_MAX]; + UINT8 tx0 = 0; + UINT8 rx0 = 0; + UINT8 rx1 = 0; + UINT32 rx_len = 0; + UINT32 rx_to_user_len; + struct gps_fwctl_data ctl_data; + INT32 status = 0; + UINT64 delta_time = 0; + bool fwctl_ready; + int retval = 0; + + if (copy_from_user(&ctl_data, user_ptr, sizeof(struct gps_fwctl_data))) { + pr_err("GPS_fwctl: copy_from_user error - ctl_data"); + return -EFAULT; + } + + if (ctl_data.size < sizeof(struct gps_fwctl_data)) { + /* user space data size not enough, risk to use it */ + pr_err("GPS_fwctl: struct size(%u) is too short than(%u)", + ctl_data.size, (UINT32)sizeof(struct gps_fwctl_data)); + return -EFAULT; + } + + if ((ctl_data.tx_len > GPS_FWCTL_BUF_MAX) || (ctl_data.tx_len == 0)) { + /* check tx data len */ + pr_err("GPS_fwctl: tx_len=%u too long (> %u) or too short", + ctl_data.tx_len, GPS_FWCTL_BUF_MAX); + return -EFAULT; + } + + if (copy_from_user(&tx_buf[0], (PUINT8)ctl_data.p_tx_buf, ctl_data.tx_len)) { + pr_err("GPS_fwctl: copy_from_user error - tx_buf"); + return -EFAULT; + } + + down(&fwctl_mtx); + if (fgGps_fwctl_ready) { + delta_time = local_clock(); + status = mtk_wmt_gps_mcu_ctrl( + &tx_buf[0], ctl_data.tx_len, &rx_buf[0], GPS_FWCTL_BUF_MAX, &rx_len); + delta_time = local_clock() - delta_time; + do_div(delta_time, 1e3); /* convert to us */ + fwctl_ready = true; + } else { + fwctl_ready = false; + } + up(&fwctl_mtx); + + tx0 = tx_buf[0]; + if (fwctl_ready && (status == 0) && (rx_len <= GPS_FWCTL_BUF_MAX) && (rx_len >= 2)) { + rx0 = rx_buf[0]; + rx1 = rx_buf[1]; + pr_info("GPS_fwctl: st=%d, tx_len=%u ([0]=%u), rx_len=%u ([0]=%u, [1]=%u), us=%u", + status, ctl_data.tx_len, tx0, rx_len, rx0, rx1, (UINT32)delta_time); + + if (ctl_data.rx_max < rx_len) + rx_to_user_len = ctl_data.rx_max; + else + rx_to_user_len = rx_len; + + if (copy_to_user((PUINT8)ctl_data.p_rx_buf, &rx_buf[0], rx_to_user_len)) { + pr_err("GPS_fwctl: copy_to_user error - rx_buf"); + retval = -EFAULT; + } + + if (copy_to_user((PUINT32)ctl_data.p_rx_len, &rx_len, sizeof(UINT32))) { + pr_err("GPS_fwctl: copy_to_user error - rx_len"); + retval = -EFAULT; + } + return retval; + } + + pr_info("GPS_fwctl: st=%d, tx_len=%u ([0]=%u), rx_len=%u, us=%u, ready=%u", + status, ctl_data.tx_len, tx0, rx_len, (UINT32)delta_time, (UINT32)fwctl_ready); + return -EFAULT; +} +#endif /* GPS_FWCTL_IOCTL_SUPPORT */ + +#define GPS_FWLOG_CTRL_BUF_MAX (20) +void GPS_fwlog_ctrl_inner(bool on) +{ + UINT8 tx_buf[GPS_FWLOG_CTRL_BUF_MAX]; + UINT8 rx_buf[GPS_FWLOG_CTRL_BUF_MAX]; + UINT8 rx0 = 0; + UINT8 rx1 = 0; + UINT32 tx_len; + UINT32 rx_len = 0; + INT32 status; + UINT32 fw_tick = 0; + UINT32 local_ms0, local_ms1; + struct timeval tv; + UINT64 tmp; + + do_gettimeofday(&tv); + tmp = local_clock(); + do_div(tmp, 1e6); + local_ms0 = (UINT32)tmp; /* overflow almost 4.9 days */ + + tx_buf[0] = GPS_FWCTL_OPCODE_LOG_CFG; + tx_buf[1] = (UINT8)on; + tx_buf[2] = 0; + tx_buf[3] = 0; + tx_buf[4] = 0; /* bitmask, reserved now */ + tx_buf[5] = (UINT8)((local_ms0 >> 0) & 0xFF); + tx_buf[6] = (UINT8)((local_ms0 >> 8) & 0xFF); + tx_buf[7] = (UINT8)((local_ms0 >> 16) & 0xFF); + tx_buf[8] = (UINT8)((local_ms0 >> 24) & 0xFF); /* local time msecs */ + tx_buf[9] = (UINT8)((tv.tv_usec >> 0) & 0xFF); + tx_buf[10] = (UINT8)((tv.tv_usec >> 8) & 0xFF); + tx_buf[11] = (UINT8)((tv.tv_usec >> 16) & 0xFF); + tx_buf[12] = (UINT8)((tv.tv_usec >> 24) & 0xFF); /* utc usec */ + tx_buf[13] = (UINT8)((tv.tv_sec >> 0) & 0xFF); + tx_buf[14] = (UINT8)((tv.tv_sec >> 8) & 0xFF); + tx_buf[15] = (UINT8)((tv.tv_sec >> 16) & 0xFF); + tx_buf[16] = (UINT8)((tv.tv_sec >> 24) & 0xFF); /* utc sec */ + tx_len = 17; + + status = mtk_wmt_gps_mcu_ctrl(&tx_buf[0], tx_len, &rx_buf[0], GPS_FWLOG_CTRL_BUF_MAX, &rx_len); + + /* local_ms1 = jiffies_to_msecs(jiffies); */ + tmp = local_clock(); + do_div(tmp, 1e6); + local_ms1 = (UINT32)tmp; + + + if (status == 0) { + if (rx_len >= 2) { + rx0 = rx_buf[0]; + rx1 = rx_buf[1]; + } + + if (rx_len >= 6) { + fw_tick |= (((UINT32)rx_buf[2]) << 0); + fw_tick |= (((UINT32)rx_buf[3]) << 8); + fw_tick |= (((UINT32)rx_buf[4]) << 16); + fw_tick |= (((UINT32)rx_buf[5]) << 24); + } + } + + pr_info("GPS_fwlog: st=%d, rx_len=%u ([0]=%u, [1]=%u), ms0=%u, ms1=%u, fw_tick=%u", + status, rx_len, rx0, rx1, local_ms0, local_ms1, fw_tick); +} + +#ifdef GPS_HW_SUSPEND_SUPPORT +#define HW_SUSPEND_CTRL_TX_LEN (2) +#define HW_SUSPEND_CTRL_RX_LEN (3) + +/* return 0 if okay, otherwise is fail */ +static int GPS_hw_suspend_ctrl(bool to_suspend) +{ + UINT8 tx_buf[HW_SUSPEND_CTRL_TX_LEN]; + UINT8 rx_buf[HW_SUSPEND_CTRL_RX_LEN]; + UINT8 rx0 = 0; + UINT8 rx1 = 0; + UINT32 tx_len; + UINT32 rx_len = 0; + INT32 wmt_status; + UINT32 local_ms0, local_ms1; + struct timeval tv; + UINT64 tmp; + + do_gettimeofday(&tv); + tmp = local_clock(); + do_div(tmp, 1e6); + local_ms0 = (UINT32)tmp; /* overflow almost 4.9 days */ + + tx_buf[0] = to_suspend ? GPS_FWCTL_OPCODE_ENTER_STOP_MODE : + GPS_FWCTL_OPCODE_EXIT_STOP_MODE; + tx_len = 1; + + wmt_status = mtk_wmt_gps_mcu_ctrl(&tx_buf[0], tx_len, + &rx_buf[0], HW_SUSPEND_CTRL_RX_LEN, &rx_len); + + /* local_ms1 = jiffies_to_msecs(jiffies); */ + tmp = local_clock(); + do_div(tmp, 1e6); + local_ms1 = (UINT32)tmp; + + if (wmt_status == 0) { /* 0 is okay */ + if (rx_len >= 2) { + rx0 = rx_buf[0]; /* fw_status, 0 is okay */ + rx1 = rx_buf[1]; /* opcode */ + } + } + + if (wmt_status != 0 || rx0 != 0) { + /* Fail due to WMT fail or FW not support, + * bypass the following operations + */ + GPS_WARN_FUNC("GPS_hw_suspend_ctrl %d: st=%d, rx_len=%u ([0]=%u, [1]=%u), ms0=%u, ms1=%u", + to_suspend, wmt_status, rx_len, rx0, rx1, local_ms0, local_ms1); + return -1; + } + + /* Okay */ + GPS_INFO_FUNC("GPS_hw_suspend_ctrl %d: st=%d, rx_len=%u ([0]=%u, [1]=%u), ms0=%u, ms1=%u", + to_suspend, wmt_status, rx_len, rx0, rx1, local_ms0, local_ms1); + return 0; +} + + +static void GPS_handle_desense(bool on); + +static int GPS_hw_suspend(void) +{ + MTK_WCN_BOOL wmt_okay; + enum gps_ctrl_status_enum gps_status; + + gps_status = g_gps_ctrl_status; + if (gps_status == GPS_OPENED) { + if (GPS_hw_suspend_ctrl(true) != 0) + return -EINVAL; /* Stands for not support */ + + wmt_okay = mtk_wmt_gps_suspend_ctrl(MTK_WCN_BOOL_TRUE); + if (!wmt_okay) + GPS_WARN_FUNC("mtk_wmt_gps_suspend_ctrl(1), is_ok = %d", wmt_okay); + + /* register event cb will clear GPS STP buffer */ + mtk_wcn_stp_register_event_cb(GPS_TASK_INDX, 0x0); + GPS_DBG_FUNC("mtk_wcn_stp_register_event_cb to null"); + + /* No need to clear the flag due to it just a flag and not stands for has data + * flag = 0; + * + * Keep msgcb due to GPS still need to recevice reset event under HW suspend mode + * mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_GPS); + */ + + GPS_handle_desense(false); + gps_hold_wake_lock(0); + GPS_WARN_FUNC("gps_hold_wake_lock(0)\n"); + + GPS_ctrl_status_change_from_to(GPS_OPENED, GPS_SUSPENDED); + } else + GPS_WARN_FUNC("GPS_hw_suspend(): status %d not match\n", gps_status); + + return 0; +} + +static int GPS_hw_resume(void) +{ + MTK_WCN_BOOL wmt_okay; + enum gps_ctrl_status_enum gps_status; + + gps_status = g_gps_ctrl_status; + if (gps_status == GPS_SUSPENDED) { + GPS_handle_desense(true); + gps_hold_wake_lock(1); + GPS_WARN_FUNC("gps_hold_wake_lock(1)\n"); + + wmt_okay = mtk_wmt_gps_suspend_ctrl(MTK_WCN_BOOL_FALSE); + if (!wmt_okay) + GPS_WARN_FUNC("mtk_wmt_gps_suspend_ctrl(0), is_ok = %d", wmt_okay); + + if (GPS_hw_suspend_ctrl(false) != 0) + return -EINVAL; /* Stands for not support */ + + mtk_wcn_stp_register_event_cb(GPS_TASK_INDX, GPS_event_cb); + GPS_ctrl_status_change_from_to(GPS_SUSPENDED, GPS_OPENED); + } else + GPS_WARN_FUNC("GPS_hw_resume(): status %d not match\n", gps_status); + + return 0; +} +#endif /* GPS_HW_SUSPEND_SUPPORT */ + +#endif /* GPS_FWCTL_SUPPORT */ + +void GPS_fwlog_ctrl(bool on) +{ +#if (defined(GPS_FWCTL_SUPPORT) && defined(CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH)) + down(&fwctl_mtx); + if (fgGps_fwctl_ready) + GPS_fwlog_ctrl_inner(on); + + fgGps_fwlog_on = on; + up(&fwctl_mtx); +#endif +} + +/* block until wmt reset happen or GPS_close */ +static int GPS_listen_wmt_rst(void) +{ + long val = 0; + + rst_listening_flag = 1; + while (!rst_happened_or_gps_close_flag) { + val = wait_event_interruptible(GPS_rst_wq, rst_happened_or_gps_close_flag); + + GPS_WARN_FUNC("GPS_listen_wmt_rst(): val = %ld, cond = %d, rstflag = %d, status = %d\n", + val, rst_happened_or_gps_close_flag, rstflag, g_gps_ctrl_status); + + /* if we are signaled */ + if (val) { + rst_listening_flag = 0; + return val; + } + } + + rst_listening_flag = 0; + return 0; +} + +/* int GPS_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) */ +long GPS_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + #if 0 + ENUM_WMTHWVER_TYPE_T hw_ver_sym = WMTHWVER_INVALID; + #endif + UINT32 hw_version = 0; + UINT32 fw_version = 0; + UINT32 gps_lna_pin = 0; + + pr_warn("GPS_ioctl(): cmd (%d)\n", cmd); + + switch (cmd) { + case 0: /* enable/disable STP */ + GPS_DBG_FUNC("GPS_ioctl(): disable STP control from GPS dev\n"); + retval = -EINVAL; +#if 1 +#else + /* George: STP is controlled by WMT only */ + mtk_wcn_stp_enable(arg); +#endif + break; + + case 1: /* send raw data */ + GPS_DBG_FUNC("GPS_ioctl(): disable raw data from GPS dev\n"); + retval = -EINVAL; + break; + + #if 0 + case COMBO_IOC_GPS_HWVER: + /*get combo hw version */ + hw_ver_sym = mtk_wcn_wmt_hwver_get(); + + GPS_DBG_FUNC("GPS_ioctl(): get hw version = %d, sizeof(hw_ver_sym) = %zd\n", + hw_ver_sym, sizeof(hw_ver_sym)); + if (copy_to_user((int __user *)arg, &hw_ver_sym, sizeof(hw_ver_sym))) + retval = -EFAULT; + + break; + #endif + case COMBO_IOC_GPS_IC_HW_VERSION: + /*get combo hw version from ic, without wmt mapping */ + hw_version = mtk_wcn_wmt_ic_info_get(WMTCHIN_HWVER); + + GPS_DBG_FUNC("GPS_ioctl(): get hw version = 0x%x\n", hw_version); + if (copy_to_user((int __user *)arg, &hw_version, sizeof(hw_version))) + retval = -EFAULT; + + break; + + case COMBO_IOC_GPS_IC_FW_VERSION: + /*get combo fw version from ic, without wmt mapping */ + fw_version = mtk_wcn_wmt_ic_info_get(WMTCHIN_FWVER); + + GPS_DBG_FUNC("GPS_ioctl(): get fw version = 0x%x\n", fw_version); + if (copy_to_user((int __user *)arg, &fw_version, sizeof(fw_version))) + retval = -EFAULT; + + break; + case COMBO_IOC_RTC_FLAG: + + retval = rtc_GPS_low_power_detected(); + + GPS_DBG_FUNC("low power flag (%d)\n", retval); + break; + case COMBO_IOC_CO_CLOCK_FLAG: +#if SOC_CO_CLOCK_FLAG + retval = mtk_wcn_wmt_co_clock_flag_get(); +#endif + GPS_DBG_FUNC("GPS co_clock_flag (%d)\n", retval); + break; + case COMBO_IOC_D1_EFUSE_GET: +#if defined(CONFIG_MACH_MT6735) + do { + char *addr = ioremap(0x10206198, 0x4); + + retval = *(volatile unsigned int *)addr; + GPS_DBG_FUNC("D1 efuse (0x%x)\n", retval); + iounmap(addr); + } while (0); +#elif defined(CONFIG_MACH_MT6763) + do { + char *addr = ioremap(0x11f10048, 0x4); + + retval = *(volatile unsigned int *)addr; + GPS_DBG_FUNC("bianco efuse (0x%x)\n", retval); + iounmap(addr); + } while (0); +#else + GPS_ERR_FUNC("Read Efuse not supported in this platform\n"); +#endif + break; + + case COMBO_IOC_TRIGGER_WMT_ASSERT: + /* Trigger FW assert for debug */ + GPS_INFO_FUNC("%s: Host trigger FW assert......, reason:%lu\n", __func__, arg); + retval = mtk_wcn_wmt_assert(WMTDRV_TYPE_GPS, arg); + if (retval == MTK_WCN_BOOL_TRUE) { + GPS_INFO_FUNC("Host trigger FW assert succeed\n"); + retval = 0; + } else { + GPS_ERR_FUNC("Host trigger FW assert Failed\n"); + retval = (-EBUSY); + } + break; + case COMBO_IOC_WMT_STATUS: + if (rstflag == 1) { + /* chip resetting */ + retval = -888; + } else if (rstflag == 2) { + /* chip reset end */ + retval = -889; + /* + * rstflag = 0 is cleared by GPS_open or GPS_close, + * no need to clear it here + */ + } else { + /* normal */ + retval = 0; + } + GPS_DBG_FUNC("rstflag(%d), retval(%d)\n", rstflag, retval); + break; + case COMBO_IOC_TAKE_GPS_WAKELOCK: + GPS_INFO_FUNC("Ioctl to take gps wakelock\n"); + gps_hold_wake_lock(1); + if (wake_lock_acquired == 1) + retval = 0; + else + retval = -EAGAIN; + break; + case COMBO_IOC_GIVE_GPS_WAKELOCK: + GPS_INFO_FUNC("Ioctl to give gps wakelock\n"); + gps_hold_wake_lock(0); + if (wake_lock_acquired == 0) + retval = 0; + else + retval = -EAGAIN; + break; +#ifdef GPS_FWCTL_IOCTL_SUPPORT + case COMBO_IOC_GPS_FWCTL: + GPS_INFO_FUNC("COMBO_IOC_GPS_FWCTL\n"); + retval = GPS_fwctl((struct gps_fwctl_data *)arg); + break; +#endif + +#ifdef GPS_HW_SUSPEND_SUPPORT + case COMBO_IOC_GPS_HW_SUSPEND: + GPS_INFO_FUNC("COMBO_IOC_GPS_HW_SUSPEND\n"); + retval = GPS_hw_suspend(); + break; + case COMBO_IOC_GPS_HW_RESUME: + GPS_INFO_FUNC("COMBO_IOC_GPS_HW_RESUME\n"); + retval = GPS_hw_resume(); + break; +#endif /* GPS_HW_SUSPEND_SUPPORT */ + + case COMBO_IOC_GPS_LISTEN_RST_EVT: + GPS_INFO_FUNC("COMBO_IOC_GPS_LISTEN_RST_EVT\n"); + retval = GPS_listen_wmt_rst(); + break; + + case COMBO_IOC_GET_GPS_LNA_PIN: + gps_lna_pin = mtk_wmt_get_gps_lna_pin_num(); + GPS_DBG_FUNC("GPS_ioctl(): get gps lna pin = %d\n", gps_lna_pin); + if (copy_to_user((int __user *)arg, &gps_lna_pin, sizeof(gps_lna_pin))) + retval = -EFAULT; + break; + default: + retval = -EFAULT; + GPS_DBG_FUNC("GPS_ioctl(): unknown cmd (%d)\n", cmd); + break; + } + +/*OUT:*/ + return retval; +} + +long GPS_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret; + + pr_warn("%s: cmd (%d)\n", __func__, cmd); + ret = GPS_unlocked_ioctl(filp, cmd, arg); + pr_warn("%s: cmd (%d)\n", __func__, cmd); + return ret; +} + +static void gps_cdev_rst_cb(ENUM_WMTDRV_TYPE_T src, + ENUM_WMTDRV_TYPE_T dst, ENUM_WMTMSG_TYPE_T type, void *buf, unsigned int sz) +{ + + /* To handle reset procedure please */ + ENUM_WMTRSTMSG_TYPE_T rst_msg; + + GPS_DBG_FUNC("sizeof(ENUM_WMTRSTMSG_TYPE_T) = %zd\n", sizeof(ENUM_WMTRSTMSG_TYPE_T)); + if (sz <= sizeof(ENUM_WMTRSTMSG_TYPE_T)) { + memcpy((char *)&rst_msg, (char *)buf, sz); + GPS_DBG_FUNC("src = %d, dst = %d, type = %d, buf = 0x%x sz = %d, max = %d\n", src, + dst, type, rst_msg, sz, WMTRSTMSG_RESET_MAX); + + if ((src == WMTDRV_TYPE_WMT) && (dst == WMTDRV_TYPE_GPS) && (type == WMTMSG_TYPE_RESET)) { + switch (rst_msg) { + case WMTRSTMSG_RESET_START: + GPS_INFO_FUNC("Whole chip reset start!\n"); + rstflag = 1; +#ifdef GPS_FWCTL_SUPPORT + /* down(&fwctl_mtx); */ + fgGps_fwctl_ready = false; + /* up(&fwctl_mtx); */ +#endif + GPS_ctrl_status_change_to(GPS_RESET_START); + break; + case WMTRSTMSG_RESET_END: + case WMTRSTMSG_RESET_END_FAIL: + if (rst_msg == WMTRSTMSG_RESET_END) + GPS_INFO_FUNC("Whole chip reset end!\n"); + else + GPS_INFO_FUNC("Whole chip reset fail!\n"); + rstflag = 2; + + GPS_ctrl_status_change_to(GPS_RESET_DONE); + break; + default: + break; + } + } + } else { + /*message format invalid */ + GPS_WARN_FUNC("Invalid message format!\n"); + } +} + +static bool desense_handled_flag; +static void GPS_handle_desense(bool on) +{ + bool to_do, handled; + + down(&status_mtx); + handled = desense_handled_flag; + if ((on && !handled) || (!on && handled)) + to_do = true; + else + to_do = false; + + if (on) + desense_handled_flag = true; + else + desense_handled_flag = false; + up(&status_mtx); + + if (!to_do) { + GPS_WARN_FUNC("GPS_handle_desense(%d) not to go due to handled = %d", on, handled); + return; + } + + if (on) { +#if defined(CONFIG_MACH_MT6739) + if (freqhopping_config(FH_MEM_PLLID, 0, 1) == 0) + GPS_WARN_FUNC("Enable MEMPLL successfully\n"); + else + GPS_WARN_FUNC("Error to enable MEMPLL\n"); +#endif +#if defined(CONFIG_MACH_MT6580) + GPS_WARN_FUNC("export_clk_buf: %x\n", CLK_BUF_AUDIO); + KERNEL_clk_buf_ctrl(CLK_BUF_AUDIO, 1); +#endif +#if defined(CONFIG_MACH_MT6765) || defined(CONFIG_MACH_MT6761) + dvfsrc_enable_dvfs_freq_hopping(1); + GPS_WARN_FUNC("mt6765/61 GPS desense solution on\n"); +#endif + } else { +#if defined(CONFIG_MACH_MT6739) + if (freqhopping_config(FH_MEM_PLLID, 0, 0) == 0) + GPS_WARN_FUNC("disable MEMPLL successfully\n"); + else + GPS_WARN_FUNC("Error to disable MEMPLL\n"); +#endif +#if defined(CONFIG_MACH_MT6765) || defined(CONFIG_MACH_MT6761) + dvfsrc_enable_dvfs_freq_hopping(0); + GPS_WARN_FUNC("mt6765/61 GPS desense solution off\n"); +#endif +#if defined(CONFIG_MACH_MT6580) + GPS_WARN_FUNC("export_clk_buf: %x\n", CLK_BUF_AUDIO); + KERNEL_clk_buf_ctrl(CLK_BUF_AUDIO, 0); +#endif + } +} + +static int GPS_open(struct inode *inode, struct file *file) +{ + pr_warn("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid); + if (current->pid == 1) + return 0; + if (rstflag == 1) { + GPS_WARN_FUNC("whole chip resetting...\n"); + return -EPERM; + } + +#if 1 /* GeorgeKuo: turn on function before check stp ready */ + /* turn on BT */ + + if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_GPS) == MTK_WCN_BOOL_FALSE) { + GPS_WARN_FUNC("WMT turn on GPS fail!\n"); + return -ENODEV; + } + + mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_GPS, gps_cdev_rst_cb); + GPS_WARN_FUNC("WMT turn on GPS OK!\n"); + rstflag = 0; + +#endif + + if (mtk_wcn_stp_is_ready()) { +#if 0 + if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_GPS) == MTK_WCN_BOOL_FALSE) { + GPS_WARN_FUNC("WMT turn on GPS fail!\n"); + return -ENODEV; + } + GPS_DBG_FUNC("WMT turn on GPS OK!\n"); +#endif + mtk_wcn_stp_register_event_cb(GPS_TASK_INDX, GPS_event_cb); + } else { + GPS_ERR_FUNC("STP is not ready, Cannot open GPS Devices\n\r"); + + /*return error code */ + return -ENODEV; + } + gps_hold_wake_lock(1); + GPS_WARN_FUNC("gps_hold_wake_lock(1)\n"); + + GPS_handle_desense(true); + +#ifdef GPS_FWCTL_SUPPORT + down(&fwctl_mtx); + fgGps_fwctl_ready = true; +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + if (fgGps_fwlog_on) { + /* GPS fw clear log on flag when GPS on, no need to send it if log setting is off */ + GPS_fwlog_ctrl_inner(fgGps_fwlog_on); + } +#endif + up(&fwctl_mtx); +#endif /* GPS_FWCTL_SUPPORT */ + + rst_happened_or_gps_close_flag = 0; + GPS_ctrl_status_change_to(GPS_OPENED); + return 0; +} + +static int GPS_close(struct inode *inode, struct file *file) +{ + int ret = 0; + pr_warn("%s: major %d minor %d (pid %d)\n", __func__, imajor(inode), iminor(inode), current->pid); + if (current->pid == 1) + return 0; + + if (rstflag == 1) { + GPS_WARN_FUNC("whole chip resetting...\n"); + ret = -EPERM; + goto _out; + } + +#ifdef GPS_FWCTL_SUPPORT + down(&fwctl_mtx); + fgGps_fwctl_ready = false; + up(&fwctl_mtx); +#endif + + if (mtk_wcn_wmt_func_off(WMTDRV_TYPE_GPS) == MTK_WCN_BOOL_FALSE) { + GPS_WARN_FUNC("WMT turn off GPS fail!\n"); + ret = -EIO; /* mostly, native programer does not care this return vlaue, */ + /* but we still return error code. */ + goto _out; + } + GPS_WARN_FUNC("WMT turn off GPS OK!\n"); + rstflag = 0; + /*Flush Rx Queue */ + mtk_wcn_stp_register_event_cb(GPS_TASK_INDX, 0x0); /* unregister event callback function */ + mtk_wcn_wmt_msgcb_unreg(WMTDRV_TYPE_GPS); + +_out: + gps_hold_wake_lock(0); + GPS_WARN_FUNC("gps_hold_wake_lock(0)\n"); + + GPS_handle_desense(false); + + GPS_ctrl_status_change_to(GPS_CLOSED); + return ret; +} + +const struct file_operations GPS_fops = { + .open = GPS_open, + .release = GPS_close, + .read = GPS_read, + .write = GPS_write, +/* .ioctl = GPS_ioctl */ + .unlocked_ioctl = GPS_unlocked_ioctl, + .compat_ioctl = GPS_compat_ioctl, +}; + +void GPS_event_cb(void) +{ +/* pr_debug("GPS_event_cb()\n");*/ + + flag = 1; + wake_up(&GPS_wq); +} + +#if WMT_CREATE_NODE_DYNAMIC || REMOVE_MK_NODE +struct class *stpgps_class; +#endif + +static int GPS_init(void) +{ + dev_t dev = MKDEV(GPS_major, 0); + int alloc_ret = 0; + int cdev_err = 0; +#if WMT_CREATE_NODE_DYNAMIC || REMOVE_MK_NODE + struct device *stpgps_dev = NULL; +#endif + + /*static allocate chrdev */ + alloc_ret = register_chrdev_region(dev, 1, GPS_DRIVER_NAME); + if (alloc_ret) { + pr_warn("fail to register chrdev\n"); + return alloc_ret; + } + + cdev_init(&GPS_cdev, &GPS_fops); + GPS_cdev.owner = THIS_MODULE; + + cdev_err = cdev_add(&GPS_cdev, dev, GPS_devs); + if (cdev_err) + goto error; +#if WMT_CREATE_NODE_DYNAMIC || REMOVE_MK_NODE + + stpgps_class = class_create(/*THIS_MODULE,*/ "stpgps"); + if (IS_ERR(stpgps_class)) + goto error; + stpgps_dev = device_create(stpgps_class, NULL, dev, NULL, "stpgps"); + if (IS_ERR(stpgps_dev)) + goto error; +#endif + pr_warn("%s driver(major %d) installed.\n", GPS_DRIVER_NAME, GPS_major); + + gps_wake_lock_ptr = wakeup_source_register(NULL, "gpswakelock"); + if (!gps_wake_lock_ptr) { + pr_info("%s %d: init wakeup source fail!", __func__, __LINE__); + goto error; + } + + sema_init(&status_mtx, 1); + sema_init(&fwctl_mtx, 1); + /* init_MUTEX(&wr_mtx); */ + sema_init(&wr_mtx, 1); + /* init_MUTEX(&rd_mtx); */ + sema_init(&rd_mtx, 1); + + return 0; + +error: + +#if WMT_CREATE_NODE_DYNAMIC || REMOVE_MK_NODE + if (!IS_ERR(stpgps_dev)) + device_destroy(stpgps_class, dev); + if (!IS_ERR(stpgps_class)) { + class_destroy(stpgps_class); + stpgps_class = NULL; + } +#endif + if (cdev_err == 0) + cdev_del(&GPS_cdev); + + if (alloc_ret == 0) + unregister_chrdev_region(dev, GPS_devs); + + return -1; +} + +static void GPS_exit(void) +{ + dev_t dev = MKDEV(GPS_major, 0); +#if WMT_CREATE_NODE_DYNAMIC || REMOVE_MK_NODE + device_destroy(stpgps_class, dev); + class_destroy(stpgps_class); + stpgps_class = NULL; +#endif + + cdev_del(&GPS_cdev); + unregister_chrdev_region(dev, GPS_devs); + pr_warn("%s driver removed.\n", GPS_DRIVER_NAME); + + wakeup_source_unregister(gps_wake_lock_ptr); +} + +int mtk_wcn_stpgps_drv_init(void) +{ + return GPS_init(); +} +EXPORT_SYMBOL(mtk_wcn_stpgps_drv_init); + +void mtk_wcn_stpgps_drv_exit(void) +{ + return GPS_exit(); +} +EXPORT_SYMBOL(mtk_wcn_stpgps_drv_exit); + +/*****************************************************************************/ +static int __init gps_mod_init(void) +{ + int ret = 0; + + mtk_wcn_stpgps_drv_init(); + #ifdef CONFIG_MTK_GPS_EMI + mtk_gps_emi_init(); + #endif + #ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + mtk_gps_fw_log_init(); + #endif + return ret; +} + +/*****************************************************************************/ +static void __exit gps_mod_exit(void) +{ + mtk_wcn_stpgps_drv_exit(); + #ifdef CONFIG_MTK_GPS_EMI + mtk_gps_emi_exit(); + #endif + #ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + mtk_gps_fw_log_exit(); + #endif +} + +module_init(gps_mod_init); +module_exit(gps_mod_exit); + diff --git a/drivers/misc/mediatek/connectivity/wlan/adaptor/Android.mk b/drivers/misc/mediatek/connectivity/wlan/adaptor/Android.mk new file mode 100644 index 00000000000000..a88532db570753 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/adaptor/Android.mk @@ -0,0 +1,19 @@ +LOCAL_PATH := $(call my-dir) + +ifeq ($(MTK_WLAN_SUPPORT), yes) + +include $(CLEAR_VARS) +LOCAL_MODULE := wmt_chrdev_wifi.ko +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_OWNER := mtk +LOCAL_INIT_RC := init.wlan_drv.rc +ifeq ($(WIFI_CHIP), CONNAC2X2_SOC3_0) +LOCAL_REQUIRED_MODULES := conninfra.ko +else +LOCAL_REQUIRED_MODULES := wmt_drv.ko +endif +WIFI_ADAPTOR_OPTS := ADAPTOR_OPTS=$(WIFI_CHIP) +include $(MTK_KERNEL_MODULE) +$(linked_module): OPTS += $(WIFI_ADAPTOR_OPTS) + +endif diff --git a/drivers/misc/mediatek/connectivity/wlan/adaptor/Makefile b/drivers/misc/mediatek/connectivity/wlan/adaptor/Makefile new file mode 100644 index 00000000000000..486c7debeef702 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/adaptor/Makefile @@ -0,0 +1,53 @@ +############################################################################### +# Necessary Check + +ifneq ($(KERNEL_OUT),) + ccflags-y += -imacros $(KERNEL_OUT)/include/generated/autoconf.h +endif + + +# Force build fail on modpost warning +KBUILD_MODPOST_FAIL_ON_WARNINGS := y + +ccflags-y += \ + -I$(srctree)/drivers/misc/mediatek/include/mt-plat \ + -I$(srctree)/drivers/misc/mediatek/connectivity/conninfra/base/include \ + -I$(srctree)/drivers/misc/mediatek/connectivity/common/common_main/include \ + -I$(srctree)/drivers/misc/mediatek/connectivity/common/common_main/linux/include + +ifneq ($(CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH),) +ccflags-y += -I$(srctree)/drivers/misc/mediatek/connectivity/common/debug_utility +endif + +ifeq ($(CONFIG_MTK_CONN_LTE_IDC_SUPPORT),y) + ccflags-y += -D WMT_IDC_SUPPORT=1 +else + ccflags-y += -D WMT_IDC_SUPPORT=0 +endif + +ifeq ($(ADAPTOR_OPTS),CONNAC2X2_SOC3_0) +ccflags-y += -D CFG_ANDORID_CONNINFRA_SUPPORT=1 +else +ccflags-y += -D CFG_ANDORID_CONNINFRA_SUPPORT=0 +endif + +ccflags-y += -D MTK_WCN_WMT_STP_EXP_SYMBOL_ABSTRACT +ccflags-y += -D CREATE_NODE_DYNAMIC=1 + +MODULE_NAME := wmt_chrdev_wifi +ifeq ($(CONFIG_MTK_COMBO_WIFI),y) +$(warning $(MODULE_NAME) build-in boot.img) +obj-y += $(MODULE_NAME).o +else +$(warning $(MODULE_NAME) is kernel module) +obj-m += $(MODULE_NAME).o +endif + +# Wi-Fi character device driver +$(MODULE_NAME)-objs += wmt_cdev_wifi.o +ifneq ($(CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH),) +$(MODULE_NAME)-objs += fw_log_wifi.o +endif +ifeq ($(ADAPTOR_OPTS),CONNAC2X2_SOC3_0) +$(MODULE_NAME)-objs += wifi_pwr_on.o +endif diff --git a/drivers/misc/mediatek/connectivity/wlan/adaptor/README b/drivers/misc/mediatek/connectivity/wlan/adaptor/README new file mode 100644 index 00000000000000..a0e1af5ea89370 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/adaptor/README @@ -0,0 +1,2 @@ +Wlan character device driver - kernel modules move out of kernel tree + diff --git a/drivers/misc/mediatek/connectivity/wlan/adaptor/fw_log_wifi.c b/drivers/misc/mediatek/connectivity/wlan/adaptor/fw_log_wifi.c new file mode 100644 index 00000000000000..a4c0508f527a49 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/adaptor/fw_log_wifi.c @@ -0,0 +1,303 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/sched.h> +#include <asm/current.h> +#include <linux/uaccess.h> +#include <linux/fcntl.h> +#include <linux/poll.h> +#include <linux/time.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/inetdevice.h> +#include <linux/string.h> + +#include "wmt_exp.h" +#include "stp_exp.h" +#include "connsys_debug_utility.h" + +MODULE_LICENSE("Dual BSD/GPL"); + +#define PFX "[WIFI-FW] " +#define WIFI_FW_LOG_DBG 3 +#define WIFI_FW_LOG_INFO 2 +#define WIFI_FW_LOG_WARN 1 +#define WIFI_FW_LOG_ERR 0 + +uint32_t fwDbgLevel = WIFI_FW_LOG_DBG; + +#define WIFI_DBG_FUNC(fmt, arg...) \ + do { \ + if (fwDbgLevel >= WIFI_FW_LOG_DBG) \ + pr_info(PFX "%s[D]: " fmt, __func__, ##arg); \ + } while (0) +#define WIFI_INFO_FUNC(fmt, arg...) \ + do { \ + if (fwDbgLevel >= WIFI_FW_LOG_INFO) \ + pr_info(PFX "%s[I]: " fmt, __func__, ##arg); \ + } while (0) +#define WIFI_INFO_FUNC_LIMITED(fmt, arg...) \ + do { \ + if (fwDbgLevel >= WIFI_FW_LOG_INFO) \ + pr_info_ratelimited(PFX "%s[L]: " fmt, __func__, ##arg); \ + } while (0) +#define WIFI_WARN_FUNC(fmt, arg...) \ + do { \ + if (fwDbgLevel >= WIFI_FW_LOG_WARN) \ + pr_info(PFX "%s[W]: " fmt, __func__, ##arg); \ + } while (0) +#define WIFI_ERR_FUNC(fmt, arg...) \ + do { \ + if (fwDbgLevel >= WIFI_FW_LOG_ERR) \ + pr_info(PFX "%s[E]: " fmt, __func__, ##arg); \ + } while (0) + + +#define WIFI_FW_LOG_IOC_MAGIC (0xfc) +#define WIFI_FW_LOG_IOCTL_ON_OFF _IOW(WIFI_FW_LOG_IOC_MAGIC, 0, int) +#define WIFI_FW_LOG_IOCTL_SET_LEVEL _IOW(WIFI_FW_LOG_IOC_MAGIC, 1, int) + +#define WIFI_FW_LOG_CMD_ON_OFF 0 +#define WIFI_FW_LOG_CMD_SET_LEVEL 1 + +typedef void (*wifi_fwlog_event_func_cb)(int, int); +wifi_fwlog_event_func_cb pfFwEventFuncCB; +static wait_queue_head_t wq; + +static struct semaphore ioctl_mtx; + +void wifi_fwlog_event_func_register(wifi_fwlog_event_func_cb func) +{ + WIFI_INFO_FUNC("wifi_fwlog_event_func_register %p\n", func); + pfFwEventFuncCB = func; +} +EXPORT_SYMBOL(wifi_fwlog_event_func_register); + +int wifi_fwlog_onoff_status(void) +{ + int ret = 88; + return ret; +} +EXPORT_SYMBOL(wifi_fwlog_onoff_status); + +static int fw_log_wifi_open(struct inode *inode, struct file *file) +{ + WIFI_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + + return 0; +} + +static int fw_log_wifi_release(struct inode *inode, struct file *file) +{ + WIFI_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + + return 0; +} + +static ssize_t fw_log_wifi_read(struct file *filp, char __user *buf, size_t len, loff_t *off) +{ + size_t ret = 0; + + WIFI_INFO_FUNC_LIMITED("fw_log_wifi_read len --> %d\n", (uint32_t) len); + ret = connsys_log_read_to_user(CONNLOG_TYPE_WIFI, buf, len); + return ret; +} + +static unsigned int fw_log_wifi_poll(struct file *filp, poll_table *wait) +{ + poll_wait(filp, &wq, wait); + if (connsys_log_get_buf_size(CONNLOG_TYPE_WIFI) > 0) + return POLLIN|POLLRDNORM; + + return 0; +} + + +static long fw_log_wifi_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + down(&ioctl_mtx); + switch (cmd) { + case WIFI_FW_LOG_IOCTL_ON_OFF:{ + unsigned int log_on_off = (unsigned int) arg; + + WIFI_INFO_FUNC("fw_log_wifi_unlocked_ioctl WIFI_FW_LOG_IOCTL_ON_OFF start\n"); + + if (pfFwEventFuncCB) { + WIFI_INFO_FUNC("WIFI_FW_LOG_IOCTL_ON_OFF invoke:%d\n", (int)log_on_off); + pfFwEventFuncCB(WIFI_FW_LOG_CMD_ON_OFF, log_on_off); + } + + WIFI_INFO_FUNC("fw_log_wifi_unlocked_ioctl WIFI_FW_LOG_IOCTL_ON_OFF end\n"); + break; + } + case WIFI_FW_LOG_IOCTL_SET_LEVEL:{ + unsigned int log_level = (unsigned int) arg; + + WIFI_INFO_FUNC("fw_log_wifi_unlocked_ioctl WIFI_FW_LOG_IOCTL_SET_LEVEL start\n"); + + if (pfFwEventFuncCB) { + WIFI_INFO_FUNC("WIFI_FW_LOG_IOCTL_SET_LEVEL invoke:%d\n", (int)log_level); + pfFwEventFuncCB(WIFI_FW_LOG_CMD_SET_LEVEL, log_level); + } + + WIFI_INFO_FUNC("fw_log_wifi_unlocked_ioctl WIFI_FW_LOG_IOCTL_SET_LEVEL end\n"); + break; + } + default: + ret = -EPERM; + } + WIFI_INFO_FUNC("fw_log_wifi_unlocked_ioctl cmd --> %d, ret=%d\n", cmd, ret); + up(&ioctl_mtx); + return ret; +} + +#ifdef CONFIG_COMPAT +static long fw_log_wifi_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret = 0; + + WIFI_INFO_FUNC("COMPAT fw_log_wifi_compact_ioctl cmd --> %d\n", cmd); + + if (!filp->f_op || !filp->f_op->unlocked_ioctl) + return -ENOTTY; + + fw_log_wifi_unlocked_ioctl(filp, cmd, arg); + return ret; +} +#endif + +const struct file_operations fw_log_wifi_fops = { + .open = fw_log_wifi_open, + .release = fw_log_wifi_release, + .read = fw_log_wifi_read, + .poll = fw_log_wifi_poll, + .unlocked_ioctl = fw_log_wifi_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = fw_log_wifi_compat_ioctl, +#endif +}; + +struct fw_log_wifi_device { + struct cdev cdev; + dev_t devno; + struct class *driver_class; + struct device *class_dev; +}; + +#define FW_LOG_WIFI_DRIVER_NAME "fw_log_wifi" +static struct fw_log_wifi_device *fw_log_wifi_dev; +static int fw_log_wifi_major; + +static void fw_log_wifi_event_cb(void) +{ + wake_up_interruptible(&wq); +} + +int fw_log_wifi_init(void) +{ + int result = 0; + int err = 0; + + fw_log_wifi_dev = kmalloc(sizeof(struct fw_log_wifi_device), GFP_KERNEL); + + if (fw_log_wifi_dev == NULL) { + result = -ENOMEM; + goto return_fn; + } + + fw_log_wifi_dev->devno = MKDEV(fw_log_wifi_major, 0); + + result = alloc_chrdev_region(&fw_log_wifi_dev->devno, 0, 1, FW_LOG_WIFI_DRIVER_NAME); + fw_log_wifi_major = MAJOR(fw_log_wifi_dev->devno); + WIFI_INFO_FUNC("alloc_chrdev_region result %d, major %d\n", result, fw_log_wifi_major); + + if (result < 0) + return result; + + fw_log_wifi_dev->driver_class = class_create(THIS_MODULE, FW_LOG_WIFI_DRIVER_NAME); + + if (IS_ERR(fw_log_wifi_dev->driver_class)) { + result = -ENOMEM; + WIFI_ERR_FUNC("class_create failed %d.\n", result); + goto unregister_chrdev_region; + } + + fw_log_wifi_dev->class_dev = device_create(fw_log_wifi_dev->driver_class, + NULL, fw_log_wifi_dev->devno, NULL, FW_LOG_WIFI_DRIVER_NAME); + + if (!fw_log_wifi_dev->class_dev) { + result = -ENOMEM; + WIFI_ERR_FUNC("class_device_create failed %d.\n", result); + goto class_destroy; + } + + cdev_init(&fw_log_wifi_dev->cdev, &fw_log_wifi_fops); + + fw_log_wifi_dev->cdev.owner = THIS_MODULE; + fw_log_wifi_dev->cdev.ops = &fw_log_wifi_fops; + + err = cdev_add(&fw_log_wifi_dev->cdev, fw_log_wifi_dev->devno, 1); + if (err) { + result = -ENOMEM; + WIFI_ERR_FUNC("Error %d adding fw_log_wifi dev.\n", err); + goto cdev_del; + } + + /* integrated with common debug utility */ + init_waitqueue_head(&wq); + connsys_log_init(CONNLOG_TYPE_WIFI); + connsys_log_register_event_cb(CONNLOG_TYPE_WIFI, fw_log_wifi_event_cb); + sema_init(&ioctl_mtx, 1); + pfFwEventFuncCB = NULL; + + goto return_fn; + +cdev_del: + cdev_del(&fw_log_wifi_dev->cdev); +class_destroy: + class_destroy(fw_log_wifi_dev->driver_class); +unregister_chrdev_region: + unregister_chrdev_region(fw_log_wifi_dev->devno, 1); + kfree(fw_log_wifi_dev); +return_fn: + return result; +} +EXPORT_SYMBOL(fw_log_wifi_init); + +int fw_log_wifi_deinit(void) +{ + device_destroy(fw_log_wifi_dev->driver_class, fw_log_wifi_dev->devno); + class_destroy(fw_log_wifi_dev->driver_class); + cdev_del(&fw_log_wifi_dev->cdev); + kfree(fw_log_wifi_dev); + unregister_chrdev_region(MKDEV(fw_log_wifi_major, 0), 1); + WIFI_INFO_FUNC("unregister_chrdev_region major %d\n", fw_log_wifi_major); + + /* integrated with common debug utility */ + connsys_log_deinit(CONNLOG_TYPE_WIFI); + return 0; +} +EXPORT_SYMBOL(fw_log_wifi_deinit); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/adaptor/fw_log_wifi.h b/drivers/misc/mediatek/connectivity/wlan/adaptor/fw_log_wifi.h new file mode 100644 index 00000000000000..e82413ac31daac --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/adaptor/fw_log_wifi.h @@ -0,0 +1,23 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _FW_LOG_WIFI_H_ +#define _FW_LOG_WIFI_H_ + +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH +int fw_log_wifi_init(void); +int fw_log_wifi_deinit(void); +#endif + +#endif /*_FW_LOG_WIFI_H_*/ diff --git a/drivers/misc/mediatek/connectivity/wlan/adaptor/init.wlan_drv.rc b/drivers/misc/mediatek/connectivity/wlan/adaptor/init.wlan_drv.rc new file mode 100644 index 00000000000000..f67a0967e14a6f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/adaptor/init.wlan_drv.rc @@ -0,0 +1,6 @@ + +# load wifi driver after wmt_loader finish +on property:vendor.connsys.driver.ready=yes + insmod /lib/modules/wmt_chrdev_wifi.ko + insmod /lib/modules/wlan_drv_${ro.vendor.wlan.gen}.ko + start wlan_assistant diff --git a/drivers/misc/mediatek/connectivity/wlan/adaptor/wifi_pwr_on.c b/drivers/misc/mediatek/connectivity/wlan/adaptor/wifi_pwr_on.c new file mode 100644 index 00000000000000..0e7a1695098966 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/adaptor/wifi_pwr_on.c @@ -0,0 +1,176 @@ + +/* +* Copyright (C) 2019 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + + +#include <linux/module.h> +#include <linux/uaccess.h> +#include <linux/time.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/kthread.h> +#include "wifi_pwr_on.h" + + + + + +MODULE_LICENSE("Dual BSD/GPL"); + +#define PFX "[WIFI-FW] " +#define WIFI_FW_LOG_DBG 3 +#define WIFI_FW_LOG_INFO 2 +#define WIFI_FW_LOG_WARN 1 +#define WIFI_FW_LOG_ERR 0 + +uint32_t DbgLevel = WIFI_FW_LOG_DBG; + +#define WIFI_DBG_FUNC(fmt, arg...) \ + do { \ + if (DbgLevel >= WIFI_FW_LOG_DBG) \ + pr_info(PFX "%s[D]: " fmt, __func__, ##arg); \ + } while (0) +#define WIFI_INFO_FUNC(fmt, arg...) \ + do { \ + if (DbgLevel >= WIFI_FW_LOG_INFO) \ + pr_info(PFX "%s[I]: " fmt, __func__, ##arg); \ + } while (0) +#define WIFI_INFO_FUNC_LIMITED(fmt, arg...) \ + do { \ + if (DbgLevel >= WIFI_FW_LOG_INFO) \ + pr_info_ratelimited(PFX "%s[L]: " fmt, __func__, ##arg); \ + } while (0) +#define WIFI_WARN_FUNC(fmt, arg...) \ + do { \ + if (DbgLevel >= WIFI_FW_LOG_WARN) \ + pr_info(PFX "%s[W]: " fmt, __func__, ##arg); \ + } while (0) +#define WIFI_ERR_FUNC(fmt, arg...) \ + do { \ + if (DbgLevel >= WIFI_FW_LOG_ERR) \ + pr_info(PFX "%s[E]: " fmt, __func__, ##arg); \ + } while (0) + + +wlan_probe_cb mtk_wlan_probe_function; +wlan_remove_cb mtk_wlan_remove_function; + + +struct completion wlan_pendComp; + +int g_opId; +int g_data; + + + + +static int mtk_wland_thread(void *pvData); + +int wifi_pwr_on_init(void) +{ + int result = 0; + + init_completion(&wlan_pendComp); + WIFI_INFO_FUNC("Do wifi_pwr_on_init.\n"); + return result; +} +EXPORT_SYMBOL(wifi_pwr_on_init); + +int wifi_pwr_on_deinit(void) +{ + return 0; +} +EXPORT_SYMBOL(wifi_pwr_on_deinit); +int mtk_wcn_wlan_reg(struct MTK_WCN_WLAN_CB_INFO *pWlanCbInfo) +{ + if (!pWlanCbInfo) { + WIFI_ERR_FUNC("wlan cb info in null!\n"); + return -1; + } + WIFI_INFO_FUNC("wmt wlan cb register\n"); + mtk_wlan_probe_function = pWlanCbInfo->wlan_probe_cb; + mtk_wlan_remove_function = pWlanCbInfo->wlan_remove_cb; + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_wlan_reg); + +int mtk_wcn_wlan_unreg(void) +{ + + WIFI_INFO_FUNC("wmt wlan cb unregister\n"); + mtk_wlan_probe_function = NULL; + mtk_wlan_remove_function = NULL; + + return 0; +} +EXPORT_SYMBOL(mtk_wcn_wlan_unreg); + +static int mtk_wland_thread(void *pvData) +{ + g_data = -1; + switch (g_opId) { + case WLAN_OPID_FUNC_ON: + if (mtk_wlan_probe_function != NULL) { + g_data = (*mtk_wlan_probe_function)(); + } else { + WIFI_ERR_FUNC("Invalid pointer\n"); + complete(&wlan_pendComp); + } + break; + case WLAN_OPID_FUNC_OFF: + if (mtk_wlan_remove_function != NULL) { + g_data = (*mtk_wlan_remove_function)(); + } else { + WIFI_ERR_FUNC("Invalid pointer\n"); + complete(&wlan_pendComp); + } + break; + default: + WIFI_ERR_FUNC("Unknown opid\n"); + break; + } + complete(&wlan_pendComp); + return 0; +} +struct task_struct *wland_thread; + + +static int data; +#define WIFI_PWR_ON_TIMEOUT 4000 + +int mtk_wcn_wlan_func_ctrl(enum ENUM_WLAN_OPID opId) +{ + bool bRet = MTK_WCN_BOOL_TRUE; + uint32_t waitRet = 0; + + g_opId = opId; + wland_thread = kthread_run(mtk_wland_thread, &data, "wland_thread"); + waitRet = wait_for_completion_timeout(&wlan_pendComp, MSEC_TO_JIFFIES(WIFI_PWR_ON_TIMEOUT)); + if (waitRet > 0) { + /* Case 1: No timeout. */ + if (g_data != 0) + bRet = MTK_WCN_BOOL_FALSE; + } else { + /* Case 2: timeout */ + WIFI_ERR_FUNC("WiFi on/off takes more than 4 seconds\n"); + bRet = MTK_WCN_BOOL_FALSE; + } + return bRet; +} +EXPORT_SYMBOL(mtk_wcn_wlan_func_ctrl); + + + + diff --git a/drivers/misc/mediatek/connectivity/wlan/adaptor/wifi_pwr_on.h b/drivers/misc/mediatek/connectivity/wlan/adaptor/wifi_pwr_on.h new file mode 100644 index 00000000000000..06b545f1aacbda --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/adaptor/wifi_pwr_on.h @@ -0,0 +1,48 @@ +/* +* Copyright (C) 2019 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _WIFI_PWR_ON_H_ +#define _WIFI_PWR_ON_H_ + +int wifi_pwr_on_init(void); +int wifi_pwr_on_deinit(void); + +typedef int(*wlan_probe_cb) (void); +typedef int(*wlan_remove_cb) (void); + + +struct MTK_WCN_WLAN_CB_INFO { + wlan_probe_cb wlan_probe_cb; + wlan_remove_cb wlan_remove_cb; +}; +extern int mtk_wcn_wlan_reg(struct MTK_WCN_WLAN_CB_INFO *pWlanCbInfo); + +enum ENUM_WLAN_OPID { + WLAN_OPID_FUNC_ON = 0, + WLAN_OPID_FUNC_OFF = 1, + WLAN_OPID_MAX +}; +extern int mtk_wcn_wlan_func_ctrl(enum ENUM_WLAN_OPID opId); + +extern wlan_probe_cb mtk_wlan_probe_function; +extern wlan_remove_cb mtk_wlan_remove_function; + +#ifndef MTK_WCN_BOOL_TRUE +#define MTK_WCN_BOOL_FALSE ((int) 0) +#define MTK_WCN_BOOL_TRUE ((int) 1) +#endif + +#define MSEC_TO_JIFFIES(_msec) msecs_to_jiffies(_msec) + +#endif /*_WIFI_PWR_ON_H_*/ diff --git a/drivers/misc/mediatek/connectivity/wlan/adaptor/wmt_cdev_wifi.c b/drivers/misc/mediatek/connectivity/wlan/adaptor/wmt_cdev_wifi.c new file mode 100644 index 00000000000000..265a541e9b012e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/adaptor/wmt_cdev_wifi.c @@ -0,0 +1,763 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software: you can redistribute it and/or modify it under the terms of the +* GNU General Public License version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along with this program. +* If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/sched.h> +#include <asm/current.h> +#include <linux/uaccess.h> +#include <linux/fcntl.h> +#include <linux/poll.h> +#include <linux/time.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/inetdevice.h> +#include <linux/string.h> + +#include "fw_log_wifi.h" +#if (CFG_ANDORID_CONNINFRA_SUPPORT == 1) +#include "wifi_pwr_on.h" +#else +#include "wmt_exp.h" +#include "stp_exp.h" +#endif +MODULE_LICENSE("Dual BSD/GPL"); + +#define WIFI_DRIVER_NAME "mtk_wmt_wifi_chrdev" +#define WIFI_DEV_MAJOR 153 + +#define PFX "[MTK-WIFI] " +#define WIFI_LOG_DBG 3 +#define WIFI_LOG_INFO 2 +#define WIFI_LOG_WARN 1 +#define WIFI_LOG_ERR 0 + +uint32_t gDbgLevel = WIFI_LOG_DBG; + +#define WIFI_DBG_FUNC(fmt, arg...) \ + do { \ + if (gDbgLevel >= WIFI_LOG_DBG) \ + pr_info(PFX "%s[D]: " fmt, __func__, ##arg); \ + } while (0) +#define WIFI_INFO_FUNC(fmt, arg...) \ + do { \ + if (gDbgLevel >= WIFI_LOG_INFO) \ + pr_info(PFX "%s[I]: " fmt, __func__, ##arg); \ + } while (0) +#define WIFI_INFO_FUNC_LIMITED(fmt, arg...) \ + do { \ + if (gDbgLevel >= WIFI_LOG_INFO) \ + pr_info_ratelimited(PFX "%s[L]: " fmt, __func__, ##arg); \ + } while (0) +#define WIFI_WARN_FUNC(fmt, arg...) \ + do { \ + if (gDbgLevel >= WIFI_LOG_WARN) \ + pr_info(PFX "%s[W]: " fmt, __func__, ##arg); \ + } while (0) +#define WIFI_ERR_FUNC(fmt, arg...) \ + do { \ + if (gDbgLevel >= WIFI_LOG_ERR) \ + pr_info(PFX "%s[E]: " fmt, __func__, ##arg); \ + } while (0) + +#define VERSION "2.0" + +MODULE_DESCRIPTION("MediaTek WiFi Driver"); + +static int32_t WIFI_devs = 1; +static int32_t WIFI_major = WIFI_DEV_MAJOR; +module_param(WIFI_major, uint, 0); +static struct cdev WIFI_cdev; +#if CREATE_NODE_DYNAMIC +static struct class *wmtwifi_class; +static struct device *wmtwifi_dev; +#endif + +static struct semaphore wr_mtx; + +#define WLAN_IFACE_NAME "wlan0" + +enum { + WLAN_MODE_HALT, + WLAN_MODE_AP, + WLAN_MODE_STA_P2P, + WLAN_MODE_STA_AP_P2P, + WLAN_MODE_MAX +}; +static int32_t wlan_mode = WLAN_MODE_HALT; +static int32_t powered; +static int32_t isconcurrent; +static char *ifname = WLAN_IFACE_NAME; +static uint32_t driver_loaded; +static int32_t low_latency_mode; + +/******************************************************************* + */ +enum ENUM_RESET_STATUS { + RESET_FAIL, + RESET_SUCCESS +}; + +/* + * enable = 1, mode = 0 => init P2P network + * enable = 1, mode = 1 => init Soft AP network + * enable = 0 => uninit P2P/AP network + */ +struct PARAM_CUSTOM_P2P_SET_STRUCT { + uint32_t u4Enable; + uint32_t u4Mode; +}; +typedef int32_t(*set_p2p_mode) (struct net_device *netdev, struct PARAM_CUSTOM_P2P_SET_STRUCT p2pmode); + +void register_set_p2p_mode_handler(set_p2p_mode handler); +void update_driver_loaded_status(uint8_t loaded); +void set_low_latency_mode(const char *mode); +uint32_t get_low_latency_mode(void); +typedef uint8_t(*file_buf_handler)(void *ctx, const char __user *buf, uint16_t length); +extern void register_file_buf_handler(file_buf_handler handler, void *handler_ctx, uint8_t ucType); +int32_t wifi_reset_start(void); +int32_t wifi_reset_end(enum ENUM_RESET_STATUS status); +ssize_t WIFI_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); + +static set_p2p_mode pf_set_p2p_mode; +void register_set_p2p_mode_handler(set_p2p_mode handler) +{ + WIFI_INFO_FUNC("(pid %d) register set p2p mode handler %p\n", current->pid, handler); + pf_set_p2p_mode = handler; +} +EXPORT_SYMBOL(register_set_p2p_mode_handler); + +void update_driver_loaded_status(uint8_t loaded) +{ + WIFI_INFO_FUNC("update_driver_loaded_status: %d\n", loaded); + driver_loaded = loaded; +} +EXPORT_SYMBOL(update_driver_loaded_status); + +static int atoh(const char *str, uint32_t *hval) +{ + unsigned int i; + uint32_t val = 0; + + WIFI_INFO_FUNC("*str : %s, len = %zu\n", str, + strlen((const char *)str)); + for (i = 0; i < strlen((const char *)str); i++) { + if (str[i] >= 'a' && str[i] <= 'f') + val = (val << 4) + (str[i] - 'a' + 10); + else if (str[i] >= 'A' && str[i] <= 'F') + val = (val << 4) + (str[i] - 'A' + 10); + else if (*(str + i) >= '0' && *(str + i) <= '9') + val = (val << 4) + (*(str + i) - '0'); + } + + *hval = val; + + return 0; +} + +void set_low_latency_mode(const char *mode) +{ + atoh(mode, &low_latency_mode); + WIFI_INFO_FUNC("LLM : %d\n", low_latency_mode); +} + +uint32_t get_low_latency_mode(void) +{ + WIFI_INFO_FUNC("LLM : %d\n", low_latency_mode); + return low_latency_mode; +} +EXPORT_SYMBOL(get_low_latency_mode); + + +enum ENUM_WLAN_DRV_BUF_TYPE_T { + BUF_TYPE_NVRAM, + BUF_TYPE_DRV_CFG, + BUF_TYPE_FW_CFG, + BUF_TYPE_NUM +}; + +//typedef uint8_t(*file_buf_handler)(void *ctx, const char __user *buf, uint16_t length); +static file_buf_handler buf_handler[BUF_TYPE_NUM]; +static void *buf_handler_ctx[BUF_TYPE_NUM]; +void register_file_buf_handler(file_buf_handler handler, void *handler_ctx, uint8_t ucType) +{ + if (ucType < BUF_TYPE_NUM) { + buf_handler[ucType] = handler; + buf_handler_ctx[ucType] = handler_ctx; + } +} +EXPORT_SYMBOL(register_file_buf_handler); + +/******************************************************************* + * WHOLE CHIP RESET PROCEDURE: + * + * WMTRSTMSG_RESET_START callback + * -> wlanRemove + * -> WMTRSTMSG_RESET_END callback + * + ******************************************************************* +*/ +/*-----------------------------------------------------------------*/ +/* + * Receiving RESET_START message + */ +/*-----------------------------------------------------------------*/ +int32_t wifi_reset_start(void) +{ + struct net_device *netdev = NULL; + struct PARAM_CUSTOM_P2P_SET_STRUCT p2pmode; + + down(&wr_mtx); + + if (powered == 1) { + netdev = dev_get_by_name(&init_net, ifname); + if (netdev == NULL) { + WIFI_ERR_FUNC("Fail to get %s net device\n", ifname); + } else { + p2pmode.u4Enable = 0; + p2pmode.u4Mode = 0; + + if (pf_set_p2p_mode) { + if (pf_set_p2p_mode(netdev, p2pmode) != 0) + WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); + else + WIFI_INFO_FUNC("Turn off p2p/ap mode"); + } + dev_put(netdev); + netdev = NULL; + } + } else { + /* WIFI is off before whole chip reset, do nothing */ + } + + return 0; +} +EXPORT_SYMBOL(wifi_reset_start); + +/*-----------------------------------------------------------------*/ +/* + * Receiving RESET_END/RESET_END_FAIL message + */ +/*-----------------------------------------------------------------*/ +int32_t wifi_reset_end(enum ENUM_RESET_STATUS status) +{ + struct net_device *netdev = NULL; + struct PARAM_CUSTOM_P2P_SET_STRUCT p2pmode; + int32_t wait_cnt = 0; + int32_t ret = -1; + + if (status == RESET_FAIL) { + /* whole chip reset fail, donot recover WIFI */ + ret = 0; + up(&wr_mtx); + } else if (status == RESET_SUCCESS) { + WIFI_WARN_FUNC("WIFI state recovering...\n"); + + if (powered == 1) { + /* WIFI is on before whole chip reset, reopen it now */ +#if (CFG_ANDORID_CONNINFRA_SUPPORT == 1) + if (mtk_wcn_wlan_func_ctrl(WLAN_OPID_FUNC_ON) == MTK_WCN_BOOL_FALSE) { +#else + if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI) == MTK_WCN_BOOL_FALSE) { +#endif + WIFI_ERR_FUNC("WMT turn on WIFI fail!\n"); + goto done; + } else { + WIFI_INFO_FUNC("WMT turn on WIFI success!\n"); + } + + if (pf_set_p2p_mode == NULL) { + WIFI_ERR_FUNC("Set p2p mode handler is NULL\n"); + goto done; + } + + netdev = dev_get_by_name(&init_net, ifname); + wait_cnt = 0; + while (netdev == NULL && wait_cnt < 10) { + WIFI_ERR_FUNC("Fail to get %s net device, sleep 300ms\n", ifname); + msleep(300); + wait_cnt++; + netdev = dev_get_by_name(&init_net, ifname); + } + if (wait_cnt >= 10) { + WIFI_ERR_FUNC("Get %s net device timeout\n", ifname); + goto done; + } + + if (wlan_mode == WLAN_MODE_STA_P2P) { + p2pmode.u4Enable = 1; + p2pmode.u4Mode = 0; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Set wlan mode 0 fail\n"); + } else { + WIFI_WARN_FUNC("Set wlan mode %d\n", WLAN_MODE_STA_P2P); + ret = 0; + } + } else if (wlan_mode == WLAN_MODE_AP) { + p2pmode.u4Enable = 1; + p2pmode.u4Mode = 1; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Set wlan mode 1 fail\n"); + } else { + WIFI_WARN_FUNC("Set wlan mode %d\n", WLAN_MODE_AP); + ret = 0; + } + } else if (wlan_mode == WLAN_MODE_STA_AP_P2P) { + p2pmode.u4Enable = 1; + p2pmode.u4Mode = 3; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Set wlan mode 3 fail\n"); + } else { + WIFI_WARN_FUNC("Set wlan mode %d\n", WLAN_MODE_STA_AP_P2P); + ret = 0; + } + } +done: + if (netdev != NULL) + dev_put(netdev); + } else { + /* WIFI is off before whole chip reset, do nothing */ + ret = 0; + } + up(&wr_mtx); + } + + return ret; +} +EXPORT_SYMBOL(wifi_reset_end); + +static int WIFI_open(struct inode *inode, struct file *file) +{ + WIFI_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + + return 0; +} + +static int WIFI_close(struct inode *inode, struct file *file) +{ + WIFI_INFO_FUNC("major %d minor %d (pid %d)\n", imajor(inode), iminor(inode), current->pid); + + return 0; +} + +ssize_t WIFI_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) +{ + int32_t retval = -EIO; + int8_t local[20] = { 0 }; + struct net_device *netdev = NULL; + struct PARAM_CUSTOM_P2P_SET_STRUCT p2pmode; + int32_t wait_cnt = 0; + int copy_size = 0; + + down(&wr_mtx); + if (count <= 0) { + WIFI_ERR_FUNC("WIFI_write invalid param\n"); + goto done; + } + + copy_size = min(sizeof(local) - 1, count); + if (copy_from_user(local, buf, copy_size) == 0) { + local[copy_size] = '\0'; + WIFI_INFO_FUNC("WIFI_write %s, length %zu, copy_size %d\n", + local, count, copy_size); + + if (local[0] == '0') { + if (powered == 0) { + WIFI_INFO_FUNC("WIFI is already power off!\n"); + retval = count; + wlan_mode = WLAN_MODE_HALT; + goto done; + } + + netdev = dev_get_by_name(&init_net, ifname); + if (netdev == NULL) { + WIFI_ERR_FUNC("Fail to get %s net device\n", ifname); + } else { + p2pmode.u4Enable = 0; + p2pmode.u4Mode = 0; + + if (pf_set_p2p_mode) { + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); + } else { + WIFI_INFO_FUNC("Turn off p2p/ap mode"); + wlan_mode = WLAN_MODE_HALT; + } + } + dev_put(netdev); + netdev = NULL; + } + +#if (CFG_ANDORID_CONNINFRA_SUPPORT == 1) + if (mtk_wcn_wlan_func_ctrl(WLAN_OPID_FUNC_OFF) == MTK_WCN_BOOL_FALSE) { +#else + if (mtk_wcn_wmt_func_off(WMTDRV_TYPE_WIFI) == MTK_WCN_BOOL_FALSE) { +#endif + WIFI_ERR_FUNC("WMT turn off WIFI fail!\n"); + } else { + WIFI_INFO_FUNC("WMT turn off WIFI success!\n"); + powered = 0; + retval = count; + wlan_mode = WLAN_MODE_HALT; + } + } else if (local[0] == '1') { + if (powered == 1) { + WIFI_INFO_FUNC("WIFI is already power on!\n"); + retval = count; + goto done; + } +#if (CFG_ANDORID_CONNINFRA_SUPPORT == 1) + if (mtk_wcn_wlan_func_ctrl(WLAN_OPID_FUNC_ON) == MTK_WCN_BOOL_FALSE) { +#else + if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI) == MTK_WCN_BOOL_FALSE) { +#endif + WIFI_ERR_FUNC("WMT turn on WIFI fail!\n"); + } else { + powered = 1; + retval = count; + WIFI_INFO_FUNC("WMT turn on WIFI success!\n"); + wlan_mode = WLAN_MODE_HALT; + } + } else if (!strncmp(local, "WR-BUF:", 7)) { + file_buf_handler handler = NULL; + void *ctx = NULL; + + if (!strncmp(&local[7], "NVRAM", 5)) { + copy_size = count - 12; + buf += 12; + wait_cnt = 0; + while (wait_cnt < 20) { + handler = buf_handler[BUF_TYPE_NVRAM]; + ctx = buf_handler_ctx[BUF_TYPE_NVRAM]; + if (handler) + break; + msleep(100); + wait_cnt++; + } + + if (!handler) + WIFI_ERR_FUNC("Wi-Fi driver is not ready for write NVRAM\n"); + else + WIFI_INFO_FUNC("Wi-Fi handler = %p\n", handler); + } else if (!strncmp(&local[7], "DRVCFG", 6)) { + copy_size = count - 13; + buf += 13; + handler = buf_handler[BUF_TYPE_DRV_CFG]; + ctx = buf_handler_ctx[BUF_TYPE_DRV_CFG]; + } else if (!strncmp(&local[7], "FWCFG", 5)) { + copy_size = count - 12; + buf += 12; + handler = buf_handler[BUF_TYPE_FW_CFG]; + ctx = buf_handler_ctx[BUF_TYPE_FW_CFG]; + } + if (handler && !handler(ctx, buf, (uint16_t)copy_size)) + retval = count; + else + retval = -ENOTSUPP; + } else if (!strncmp(local, "RM-BUF:", 7)) { + file_buf_handler handler = NULL; + void *ctx = NULL; + + if (!strncmp(&local[7], "DRVCFG", 6)) { + handler = buf_handler[BUF_TYPE_DRV_CFG]; + ctx = buf_handler_ctx[BUF_TYPE_DRV_CFG]; + } else if (!strncmp(&local[7], "FWCFG", 5)) { + handler = buf_handler[BUF_TYPE_FW_CFG]; + ctx = buf_handler_ctx[BUF_TYPE_FW_CFG]; + } + + if (handler && !handler(ctx, NULL, 0)) + retval = count; + else + retval = -ENOTSUPP; + } else if (local[0] == 'S' || local[0] == 'P' || local[0] == 'A') { + if (powered == 1 && driver_loaded == 0) { + WIFI_INFO_FUNC("In fact wifi is already turned off! reset related states.\n"); + powered = 0; + wlan_mode = WLAN_MODE_HALT; + } + + if (powered == 0) { + /* If WIFI is off, turn on WIFI first */ +#if (CFG_ANDORID_CONNINFRA_SUPPORT == 1) + if (mtk_wcn_wlan_func_ctrl(WLAN_OPID_FUNC_ON) == MTK_WCN_BOOL_FALSE) { +#else + if (mtk_wcn_wmt_func_on(WMTDRV_TYPE_WIFI) == MTK_WCN_BOOL_FALSE) { +#endif + WIFI_ERR_FUNC("WMT turn on WIFI fail!\n"); + goto done; + } else { + powered = 1; + WIFI_INFO_FUNC("WMT turn on WIFI success!\n"); + wlan_mode = WLAN_MODE_HALT; + } + } + + if (pf_set_p2p_mode == NULL) { + WIFI_ERR_FUNC("Set p2p mode handler is NULL\n"); + goto done; + } + + netdev = dev_get_by_name(&init_net, ifname); + wait_cnt = 0; + while (netdev == NULL && wait_cnt < 10) { + WIFI_ERR_FUNC("Fail to get %s net device, sleep 300ms\n", ifname); + msleep(300); + wait_cnt++; + netdev = dev_get_by_name(&init_net, ifname); + } + if (wait_cnt >= 10) { + WIFI_ERR_FUNC("Get %s net device timeout\n", ifname); + goto done; + } + + /* 1. Concurrent mode */ + if (isconcurrent) { + if (wlan_mode == WLAN_MODE_STA_AP_P2P) { + WIFI_INFO_FUNC("WIFI is already in cocurrent mode %d!\n", wlan_mode); + retval = count; + goto done; + } + p2pmode.u4Enable = 1; + p2pmode.u4Mode = 3; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Set wlan mode fail\n"); + /* Goto Non-concurrent mode */ + } else { + WIFI_INFO_FUNC("Set wlan mode %d --> %d\n", wlan_mode, WLAN_MODE_STA_AP_P2P); + wlan_mode = WLAN_MODE_STA_AP_P2P; + retval = count; + goto done; + } + } + + /* 2. Non-concurrent mode */ + if ((wlan_mode == WLAN_MODE_STA_P2P && (local[0] == 'S' || local[0] == 'P')) || + (wlan_mode == WLAN_MODE_AP && (local[0] == 'A'))) { + WIFI_INFO_FUNC("WIFI is already in mode %d!\n", wlan_mode); + retval = count; + goto done; + } + + if ((wlan_mode == WLAN_MODE_AP && (local[0] == 'S' || local[0] == 'P')) || + (wlan_mode == WLAN_MODE_STA_P2P && (local[0] == 'A'))) { + p2pmode.u4Enable = 0; + p2pmode.u4Mode = 0; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); + goto done; + } + } + + if (local[0] == 'S' || local[0] == 'P') { + p2pmode.u4Enable = 1; + p2pmode.u4Mode = 0; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Set wlan mode fail\n"); + } else { + WIFI_INFO_FUNC("Set wlan mode %d --> %d\n", wlan_mode, WLAN_MODE_STA_P2P); + wlan_mode = WLAN_MODE_STA_P2P; + retval = count; + } + } else if (local[0] == 'A') { + p2pmode.u4Enable = 1; + p2pmode.u4Mode = 1; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) { + WIFI_ERR_FUNC("Set wlan mode fail\n"); + } else { + WIFI_INFO_FUNC("Set wlan mode %d --> %d\n", wlan_mode, WLAN_MODE_AP); + wlan_mode = WLAN_MODE_AP; + retval = count; + } + } + dev_put(netdev); + netdev = NULL; + } else if (local[0] == 'C') { + if ((isconcurrent == 0) && + ((wlan_mode == WLAN_MODE_STA_P2P) + || (wlan_mode == WLAN_MODE_AP))) { + netdev = dev_get_by_name(&init_net, ifname); + if (netdev && pf_set_p2p_mode) { + p2pmode.u4Enable = 0; + p2pmode.u4Mode = 0; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) + WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); + else + WIFI_INFO_FUNC("Turn off p2p/ap mode success"); + } else + WIFI_ERR_FUNC("Fail to get %s netdev\n", ifname); + } + isconcurrent = 1; + WIFI_INFO_FUNC("Enable concurrent mode\n"); + retval = count; + } else if (local[0] == 'N') { + if ((isconcurrent == 1) && + (wlan_mode == WLAN_MODE_STA_AP_P2P)) { + netdev = dev_get_by_name(&init_net, ifname); + if (netdev && pf_set_p2p_mode) { + p2pmode.u4Enable = 0; + p2pmode.u4Mode = 0; + if (pf_set_p2p_mode(netdev, p2pmode) != 0) + WIFI_ERR_FUNC("Turn off p2p/ap mode fail"); + else + WIFI_INFO_FUNC("Turn off p2p/ap mode success"); + } else + WIFI_ERR_FUNC("Fail to get %s netdev\n", ifname); + } + isconcurrent = 0; + WIFI_INFO_FUNC("Disable concurrent mode\n"); + retval = count; + } else if (!strncmp(local, "LLM", 3)) { + WIFI_INFO_FUNC("local = %s", local); + if (!strncmp(local + 4, "0x", 2)) { + WIFI_INFO_FUNC("LLM val = %s", local + 6); + set_low_latency_mode(local + 6); + retval = count; + } else { + retval = -ENOTSUPP; + } + } + } +done: + if (netdev != NULL) + dev_put(netdev); + + up(&wr_mtx); + return retval; +} + +const struct file_operations WIFI_fops = { + .open = WIFI_open, + .release = WIFI_close, + .write = WIFI_write, +}; + +static int WIFI_init(void) +{ + dev_t dev = MKDEV(WIFI_major, 0); + int32_t alloc_ret = 0; + int32_t cdev_err = 0; + + low_latency_mode = 0; + + /* Allocate char device */ + alloc_ret = register_chrdev_region(dev, WIFI_devs, WIFI_DRIVER_NAME); + if (alloc_ret) { + WIFI_ERR_FUNC("Fail to register device numbers\n"); + return alloc_ret; + } + + cdev_init(&WIFI_cdev, &WIFI_fops); + WIFI_cdev.owner = THIS_MODULE; + + cdev_err = cdev_add(&WIFI_cdev, dev, WIFI_devs); + if (cdev_err) + goto error; + +#if CREATE_NODE_DYNAMIC /* mknod replace */ + wmtwifi_class = class_create(/*THIS_MODULE,*/ "wmtWifi"); + if (IS_ERR(wmtwifi_class)) + goto error; + wmtwifi_dev = device_create(wmtwifi_class, NULL, dev, NULL, "wmtWifi"); + if (IS_ERR(wmtwifi_dev)) + goto error; +#endif + + sema_init(&wr_mtx, 1); + + WIFI_INFO_FUNC("%s driver(major %d) installed\n", WIFI_DRIVER_NAME, WIFI_major); + +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + if (fw_log_wifi_init() < 0) { + WIFI_INFO_FUNC("connsys debug node init failed!!\n"); + return -1; + } +#endif +#if (CFG_ANDORID_CONNINFRA_SUPPORT == 1) + wifi_pwr_on_init(); +#endif + return 0; + +error: +#if CREATE_NODE_DYNAMIC + if (wmtwifi_dev && !IS_ERR(wmtwifi_dev)) { + device_destroy(wmtwifi_class, dev); + wmtwifi_dev = NULL; + } + if (wmtwifi_class && !IS_ERR(wmtwifi_class)) { + class_destroy(wmtwifi_class); + wmtwifi_class = NULL; + } +#endif + if (cdev_err == 0) + cdev_del(&WIFI_cdev); + + if (alloc_ret == 0) + unregister_chrdev_region(dev, WIFI_devs); + + return -1; +} + +static void WIFI_exit(void) +{ + dev_t dev = MKDEV(WIFI_major, 0); + +#if CREATE_NODE_DYNAMIC + if (wmtwifi_dev && !IS_ERR(wmtwifi_dev)) { + device_destroy(wmtwifi_class, dev); + wmtwifi_dev = NULL; + } + if (wmtwifi_class && !IS_ERR(wmtwifi_class)) { + class_destroy(wmtwifi_class); + wmtwifi_class = NULL; + } +#endif + + cdev_del(&WIFI_cdev); + unregister_chrdev_region(dev, WIFI_devs); + + WIFI_INFO_FUNC("%s driver removed\n", WIFI_DRIVER_NAME); + +#ifdef CONFIG_MTK_CONNSYS_DEDICATED_LOG_PATH + fw_log_wifi_deinit(); +#endif +#if (CFG_ANDORID_CONNINFRA_SUPPORT == 1) + wifi_pwr_on_deinit(); +#endif +} + +#ifdef MTK_WCN_BUILT_IN_DRIVER + +int mtk_wcn_wmt_wifi_init(void) +{ + return WIFI_init(); +} +EXPORT_SYMBOL(mtk_wcn_wmt_wifi_init); + +void mtk_wcn_wmt_wifi_exit(void) +{ + return WIFI_exit(); +} +EXPORT_SYMBOL(mtk_wcn_wmt_wifi_exit); + +#else + +module_init(WIFI_init); +module_exit(WIFI_exit); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/COPYING b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/COPYING new file mode 100644 index 00000000000000..d159169d105089 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/Kconfig b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/Kconfig new file mode 100644 index 00000000000000..732bf051e1af88 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/Kconfig @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0 + +config MT7668S_WIFI + tristate "Mediatek MT7668S WiFi support" + depends on MMC + select CFG80211_WEXT + select CFG80211_WEXT_EXPORT + default m + help + Enable support for the Mediatek MT7668S SDIO WiFi chipset. + This driver provides the necessary functionality to operate + the MT7668S chipset via SDIO interface. + + To compile this driver as a loadable kernel module, choose 'M' + here. This will create a module named 'mt7668s.ko'. + +config MT7668S_WIFI_MESON_G12A_PATCH + bool "MT7668S WiFi Meson G12A workaround" + depends on MT7668S_WIFI + depends on PINCTRL_MESON_G12A + default y + help + Enable this option to apply a workaround specific to the + Meson G12A platform. Due to buffer length constraints on + G12A, this workaround reduces the overall buffer length + to prevent issues with WiFi operation. + + Select 'y' to enable the workaround, ensuring stable + performance on the Meson G12A platform. Select 'n' to + disable the workaround if it is not needed. diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/LICENSE b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/LICENSE new file mode 100644 index 00000000000000..de41e5ff927dfd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/LICENSE @@ -0,0 +1,13 @@ +GPLv2 License + +Copyright (c) 2016,2017 MediaTek Inc. +Copyright (c) 2024 Yogi Hermawan <yogist.xda@gmail.com>. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See http://www.gnu.org/licenses/gpl-2.0.html for more details. \ No newline at end of file diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/Makefile b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/Makefile new file mode 100644 index 00000000000000..3f8fae3f7362f3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/Makefile @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: GPL-2.0 +ccflags-y += -Wno-error=restrict -Wno-error=unused-variable -Wno-error=unused-function -Wno-error=format -Wno-error=implicit-fallthrough -Wno-error=pointer-to-int-cast -Wno-error=empty-body \ + -D CFG_SUPPORT_SINGLE_SKU_LOCAL_DB=1 -D CFG_DRIVER_INF_NAME_CHANGE -DDBG=0 \ + -I$(src)/include \ + -I$(src)/include/nic \ + -I$(src)/include/mgmt \ + -I$(src)/include/chips \ + -I$(src)/sdio/include + +ldflags-y += --strip-debug + +ifeq ($(CONFIG_MTK_WIFI_DEVICE),y) + ccflags-y += -DCFG_BUILT_IN_DRIVER=1 +endif + +mt7668s-objs := \ + chips/mt7668.o \ + common/dump.o \ + common/wlan_lib.o \ + common/wlan_oid.o \ + common/wlan_p2p.o \ + mgmt/aaa_fsm.o \ + mgmt/ais_fsm.o \ + mgmt/assoc.o \ + mgmt/auth.o \ + mgmt/bss.o \ + mgmt/cnm.o \ + mgmt/cnm_mem.o \ + mgmt/cnm_timer.o \ + mgmt/hem_mbox.o \ + mgmt/mib.o \ + mgmt/p2p_assoc.o \ + mgmt/p2p_dev_fsm.o \ + mgmt/p2p_dev_state.o \ + mgmt/p2p_fsm.o \ + mgmt/p2p_func.o \ + mgmt/p2p_ie.o \ + mgmt/p2p_rlm.o \ + mgmt/p2p_rlm_obss.o \ + mgmt/p2p_role_fsm.o \ + mgmt/p2p_role_state.o \ + mgmt/p2p_scan.o \ + mgmt/privacy.o \ + mgmt/rate.o \ + mgmt/reg_rule.o \ + mgmt/rlm.o \ + mgmt/rlm_domain.o \ + mgmt/rlm_obss.o \ + mgmt/roaming_fsm.o \ + mgmt/rsn.o \ + mgmt/saa_fsm.o \ + mgmt/scan.o \ + mgmt/scan_fsm.o \ + mgmt/swcr.o \ + mgmt/tdls.o \ + mgmt/tkip_mic.o \ + mgmt/wnm.o \ + nic/cmd_buf.o \ + nic/nic.o \ + nic/nic_cmd_event.o \ + nic/nic_pwr_mgt.o \ + nic/nic_rate.o \ + nic/nic_rx.o \ + nic/nic_tx.o \ + nic/nic_umac.o \ + nic/que_mgt.o \ + sdio/gl_ate_agent.o \ + sdio/gl_cfg80211.o \ + sdio/gl_hook_api.o \ + sdio/gl_init.o \ + sdio/gl_kal.o \ + sdio/gl_qa_agent.o \ + sdio/gl_p2p.o \ + sdio/gl_p2p_cfg80211.o \ + sdio/gl_p2p_init.o \ + sdio/gl_p2p_kal.o \ + sdio/gl_proc.o \ + sdio/gl_wext.o \ + sdio/gl_wext_priv.o \ + sdio/hal_api.o \ + sdio/platform.o \ + sdio/sdio.o + +ifeq ($(CONFIG_MT7668S_WIFI_MESON_G12A_PATCH),y) + ccflags-y += -DCFG_MESON_G12A_PATCH=1 +else + ccflags-y += -DCFG_MESON_G12A_PATCH=0 +endif + +obj-$(CONFIG_MTK_WIFI_DEVICE) := mt7668s.o + +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/README.md b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/README.md new file mode 100644 index 00000000000000..d62d947e904954 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/README.md @@ -0,0 +1,145 @@ +# MT7668S WiFi Driver for Linux + +an initiative to port the Android MT7668S driver into Linux (OpenWrt). + +<!-- ## Current State + +### OpenWrt + +- [x] Station Mode +- [x] AP Mode +- [x] P2P Mode +- [x] Driver can load correctly after reboot + +#### Known Bugs in Openwrt +- [ ] Luci not showing connected devices +- [ ] NULL MAC address in `/etc/config/wireless` +- [ ] Need to specify interface `ap0` when creating Access Point + +### Armbian + +- [ ] Untested + +### Other Linux Distros + +- [ ] Untested --> + +<!-- ## Installation + +To install the MT7668S driver on your Linux system (as an external module), follow these steps: + +1. **Clone the repository:** + ```sh + git clone https://github.com/yhpgi/mt7668s.git + cd mt7668s + ``` + +2. **Edit the build files:** + + * Change `KERNELDIR` with your actual kernel/headers path. + * Change `CONFIG_MT7668S_WIFI_MESON_G12A_PATCH=y` to `CONFIG_MT7668S_WIFI_MESON_G12A_PATCH=n` if your target is not an Amlogic g12a. + +3. **Build the driver:** + ```sh + ./build.sh + ``` + +4. **Install the driver:** + ```sh + sudo cp mt7668s.ko /lib/modules/$(uname -r)/ + ``` + +5. **Copy firmware files:** + ```sh + sudo cp firmware/* /lib/firmware/ + ``` + +6. **Load the driver:** + ```sh + sudo modprobe mt7668s + # or + sudo insmod /lib/modules/$(uname -r)/mt7668s.ko + ``` + +7. **Load driver at every reboot:** + ```sh + echo mt7668s | sudo tee -a /etc/modules.d/mt7668s + # or + echo mt7668s | sudo tee -a /etc/modules-load.d/mt7668s + # depends on your distro + + # or you can input it directly using a file manager or your favorite text editor + ``` + +## Compiling the Driver In-tree with Your Kernel + +1. **Move working directory to `linux-x.y/drivers`** + ```sh + cd linux-x.y/drivers + ``` + +2. **Clone the repository:** + ```sh + git clone https://github.com/yhpgi/mt7668s.git + ``` + +3. **Edit `Makefile` and `Kconfig` in `linux-x.y/drivers`:** + + **Makefile:** + ```makefile + obj-y += mt7668s/ + ``` + + **Kconfig:** + ```kconfig + source "drivers/mt7668s/Kconfig" + ``` + +4. **Run menuconfig:** + ```sh + cd linux-x.y + + make menuconfig + # or + make ARCH=arm64 menuconfig + ``` + + Enable this driver in the `Device Driver` section. +--> + +> [!IMPORTANT] +> You must enable the `MT7668S WiFi Meson G12A workaround` at compile time if your target device is Amlogic g12a. +> +> DO NOT ENABLE FOR OTHER TARGETS as it will degrade WiFi performance. + +<!-- 5. **Compile the kernel as usual.** + +## Usage + +After installing and loading the driver, you can configure the WiFi settings using standard Linux networking tools such as `iwconfig` or `nmcli`. For OpenWrt, the configuration can be done via the LuCI interface or by editing `/etc/config/wireless`. + +## Troubleshooting + +If you encounter any issues, please check the following: + +- Ensure that your kernel version is compatible with the driver. +- Check the system logs for any error messages related to the driver. +--> + +## Contributing + +If you find any issues or have suggestions for improvements, please submit a pull request or open an issue in the repository. + +## Acknowledgements + +Special thanks to: + +- MediaTek Inc. +- Amazon Inc. +- [DBAI](https://github.com/armarchindo) +- Everyone who is contributing to porting this driver to Linux + +## License + +- Original FOSS code from MediaTek Ltd. is licensed under the [GPLv2 License](LICENSE), yet firmware files are licensed under Dual License BSD/GPL. +- This project is also licensed under the [GPLv2 License](LICENSE). diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/build b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/build new file mode 100755 index 00000000000000..db24dddbdb68af --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/build @@ -0,0 +1,27 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright(C) 2024 Yogi Hermawan <yogist.xda@gmail.com>. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See http://www.gnu.org/licenses/gpl-2.0.html for more details. + +export PATH="$HOME/toolchain/arm-gnu-toolchain-14.2.rel1-x86_64-aarch64-none-linux-gnu/bin/:$PATH" +export ARCH="arm64" +export CROSS_COMPILE="aarch64-none-linux-gnu-" +export INSTALL_MOD_STRIP=1 + +export CONFIG_MT7668S_WIFI=m +export CONFIG_MT7668S_WIFI_MESON_G12A_PATCH=y + +# replace KERNELDIR with your kernel path +export KERNELDIR="$HOME/projects/kcompiler/compile-kernel/kernel/linux-6.13.y" + +./clean +make -j8 KERNELDIR="${KERNELDIR}" diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/chips/mt7668.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/chips/mt7668.c new file mode 100644 index 00000000000000..6ac749468fdd59 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/chips/mt7668.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file mt7668.c + * \brief Internal driver stack will export the required procedures here for + * GLUE Layer. + * + * This file contains all routines which are exported from MediaTek 802.11 + * Wireless LAN driver stack to GLUE Layer. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +#include "mt7668.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +ECO_INFO_T mt7668_eco_table[] = { + /* HW version, ROM version, Factory version, Eco version */ + { 0x00, 0x00, 0xA, 0x1 }, /* E1 */ + { 0x10, 0x01, 0xB, 0x2 }, /* E2 */ + { 0x11, 0x01, 0xB, 0x2 }, /* E2 */ + { 0x00, 0x00, 0x0, 0x0 } /* End of table */ +}; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ +void mt7668ConstructFirmwarePrio(P_GLUE_INFO_T prGlueInfo, u8 **apucNameTable, u8 **apucName, u8 *pucNameIdx, u8 ucMaxNameIdx) +{ + struct chip_info *prChipInfo = prGlueInfo->prAdapter->chip_info; + u32 chip_id = prChipInfo->chip_id; + u8 sub_idx = 0; + + for (sub_idx = 0; apucNameTable[sub_idx]; sub_idx++) { + if (((*pucNameIdx) + 3) < ucMaxNameIdx) { + /* Type 1. WIFI_RAM_CODE_MTxxxx.bin */ + snprintf(*(apucName + (*pucNameIdx)), + CFG_FW_NAME_MAX_LEN, "%s%x.bin", + apucNameTable[sub_idx], chip_id); + (*pucNameIdx) += 1; + + /* Type 2. WIFI_RAM_CODE_MTxxxx */ + snprintf(*(apucName + (*pucNameIdx)), + CFG_FW_NAME_MAX_LEN, "%s%x", + apucNameTable[sub_idx], chip_id); + (*pucNameIdx) += 1; + + /* Type 3. WIFI_RAM_CODE_MTxxxx_Ex.bin */ + snprintf(*(apucName + (*pucNameIdx)), + CFG_FW_NAME_MAX_LEN, "%s%x_E%u.bin", + apucNameTable[sub_idx], chip_id, + wlanGetEcoVersion(prGlueInfo->prAdapter)); + (*pucNameIdx) += 1; + + /* Type 4. WIFI_RAM_CODE_MTxxxx_Ex */ + snprintf(*(apucName + (*pucNameIdx)), + CFG_FW_NAME_MAX_LEN, "%s%x_E%u", + apucNameTable[sub_idx], chip_id, + wlanGetEcoVersion(prGlueInfo->prAdapter)); + (*pucNameIdx) += 1; + } else { + /* the table is not large enough */ + DBGLOG(INIT, + ERROR, + "kalFirmwareImageMapping >> file name array is not enough.\n"); + ASSERT(0); + } + } +} + +/* Litien code refine to support multi chip */ +struct chip_info chip_info_mt7668 = { + .chip_id = MT7668_CHIP_ID, + .sw_sync0 = MT7668_SW_SYNC0, + .sw_ready_bit_offset = MT7668_SW_SYNC0_RDY_OFFSET, + .patch_addr = MT7668_PATCH_START_ADDR, + .is_pcie_32dw_read = MT7668_IS_PCIE_32DW_READ, /* Litien */ + .eco_info = mt7668_eco_table, + .constructFirmwarePrio = mt7668ConstructFirmwarePrio, + .features = 0, +}; + +struct hif_driver_data driver_data_mt7668 = { + .chip_info = &chip_info_mt7668, +}; diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/clean b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/clean new file mode 100755 index 00000000000000..e51a10118a3405 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/clean @@ -0,0 +1,29 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright(C) 2024 Yogi Hermawan <yogist.xda@gmail.com>. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See http://www.gnu.org/licenses/gpl-2.0.html for more details. + +echo "Cleaning..." + +find . -name "*.ko" -exec rm -rf {} \; 2>/dev/null +find . -name "*.o" -exec rm -rf {} \; 2>/dev/null +find . -name "*.o.*" -exec rm -rf {} \; 2>/dev/null +find . -name "*.order.cmd" -exec rm -rf {} \; 2>/dev/null +find . -name "*.mod.cmd" -exec rm -rf {} \; 2>/dev/null +find . -name "*.mod" -exec rm -rf {} \; 2>/dev/null +find . -name "*.order" -exec rm -rf {} \; 2>/dev/null +find . -name "*.cmd" -exec rm -rf {} \; 2>/dev/null +find . -name "*.symvers" -exec rm -rf {} \; 2>/dev/null +find . -name "*.mod.c" -exec rm -rf {} \; 2>/dev/null +find . -name ".tmp_*" -exec rm -rf {} \; 2>/dev/null + +echo "Clean finished" diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/common/dump.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/common/dump.c new file mode 100644 index 00000000000000..e9bf0346440b75 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/common/dump.c @@ -0,0 +1,467 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "dump.c" + * \brief Provide memory dump function for debugging. + * + * Provide memory dump function for debugging. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to dump a segment of memory in bytes. + * + * \param[in] pucStartAddr Pointer to the starting address of the memory to be + * dumped. \param[in] u4Length Length of the memory to be dumped. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void dumpMemory8(IN u8 *pucStartAddr, IN u32 u4Length) +{ + ASSERT(pucStartAddr); + + LOG_FUNC("DUMP8 ADDRESS: %x, Length: %d\n", (unsigned long)pucStartAddr, + u4Length); + + while (u4Length > 0) { + if (u4Length >= 16) { + LOG_FUNC( + "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x\n", + (unsigned long)pucStartAddr, + pucStartAddr[0], + pucStartAddr[1], + pucStartAddr[2], + pucStartAddr[3], + pucStartAddr[4], + pucStartAddr[5], + pucStartAddr[6], + pucStartAddr[7], + pucStartAddr[8], + pucStartAddr[9], + pucStartAddr[10], + pucStartAddr[11], + pucStartAddr[12], + pucStartAddr[13], + pucStartAddr[14], + pucStartAddr[15]); + u4Length -= 16; + pucStartAddr += 16; + } else { + switch (u4Length) { + case 1: + LOG_FUNC("(%p) %02x\n", pucStartAddr, + pucStartAddr[0]); + break; + + case 2: + LOG_FUNC("(%p) %02x %02x\n", pucStartAddr, + pucStartAddr[0], pucStartAddr[1]); + break; + + case 3: + LOG_FUNC("(%p) %02x %02x %02x\n", pucStartAddr, + pucStartAddr[0], pucStartAddr[1], + pucStartAddr[2]); + break; + + case 4: + LOG_FUNC("(%p) %02x %02x %02x %02x\n", + pucStartAddr, pucStartAddr[0], + pucStartAddr[1], pucStartAddr[2], + pucStartAddr[3]); + break; + + case 5: + LOG_FUNC("(%p) %02x %02x %02x %02x %02x\n", + pucStartAddr, pucStartAddr[0], + pucStartAddr[1], pucStartAddr[2], + pucStartAddr[3], pucStartAddr[4]); + break; + + case 6: + LOG_FUNC( + "(%p) %02x %02x %02x %02x %02x %02x\n", + pucStartAddr, pucStartAddr[0], + pucStartAddr[1], pucStartAddr[2], + pucStartAddr[3], pucStartAddr[4], + pucStartAddr[5]); + break; + + case 7: + LOG_FUNC( + "(%p) %02x %02x %02x %02x %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], + pucStartAddr[1], + pucStartAddr[2], + pucStartAddr[3], + pucStartAddr[4], + pucStartAddr[5], + pucStartAddr[6]); + break; + + case 8: + LOG_FUNC( + "(%p) %02x %02x %02x %02x %02x %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], + pucStartAddr[1], + pucStartAddr[2], + pucStartAddr[3], + pucStartAddr[4], + pucStartAddr[5], + pucStartAddr[6], + pucStartAddr[7]); + break; + + case 9: + LOG_FUNC( + "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x\n", + pucStartAddr, + pucStartAddr[0], + pucStartAddr[1], + pucStartAddr[2], + pucStartAddr[3], + pucStartAddr[4], + pucStartAddr[5], + pucStartAddr[6], + pucStartAddr[7], + pucStartAddr[8]); + break; + + case 10: + LOG_FUNC( + "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x\n", + pucStartAddr, + pucStartAddr[0], + pucStartAddr[1], + pucStartAddr[2], + pucStartAddr[3], + pucStartAddr[4], + pucStartAddr[5], + pucStartAddr[6], + pucStartAddr[7], + pucStartAddr[8], + pucStartAddr[9]); + break; + + case 11: + LOG_FUNC( + "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], + pucStartAddr[1], + pucStartAddr[2], + pucStartAddr[3], + pucStartAddr[4], + pucStartAddr[5], + pucStartAddr[6], + pucStartAddr[7], + pucStartAddr[8], + pucStartAddr[9], + pucStartAddr[10]); + break; + + case 12: + LOG_FUNC( + "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], + pucStartAddr[1], + pucStartAddr[2], + pucStartAddr[3], + pucStartAddr[4], + pucStartAddr[5], + pucStartAddr[6], + pucStartAddr[7], + pucStartAddr[8], + pucStartAddr[9], + pucStartAddr[10], + pucStartAddr[11]); + break; + + case 13: + LOG_FUNC( + "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], + pucStartAddr[1], + pucStartAddr[2], + pucStartAddr[3], + pucStartAddr[4], + pucStartAddr[5], + pucStartAddr[6], + pucStartAddr[7], + pucStartAddr[8], + pucStartAddr[9], + pucStartAddr[10], + pucStartAddr[11], + pucStartAddr[12]); + break; + + case 14: + LOG_FUNC( + "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], + pucStartAddr[1], + pucStartAddr[2], + pucStartAddr[3], + pucStartAddr[4], + pucStartAddr[5], + pucStartAddr[6], + pucStartAddr[7], + pucStartAddr[8], + pucStartAddr[9], + pucStartAddr[10], + pucStartAddr[11], + pucStartAddr[12], + pucStartAddr[13]); + break; + + case 15: + default: + LOG_FUNC( + "(%p) %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x\n", + pucStartAddr, + pucStartAddr[0], + pucStartAddr[1], + pucStartAddr[2], + pucStartAddr[3], + pucStartAddr[4], + pucStartAddr[5], + pucStartAddr[6], + pucStartAddr[7], + pucStartAddr[8], + pucStartAddr[9], + pucStartAddr[10], + pucStartAddr[11], + pucStartAddr[12], + pucStartAddr[13], + pucStartAddr[14]); + break; + } + u4Length = 0; + } + } + + LOG_FUNC("\n"); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to dump a segment of memory in double words. + * + * \param[in] pucStartAddr Pointer to the starting address of the memory to be + * dumped. \param[in] u4Length Length of the memory to be dumped. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void dumpMemory32(IN u32 *pu4StartAddr, IN u32 u4Length) +{ + u8 *pucAddr; + + ASSERT(pu4StartAddr); + + LOG_FUNC("DUMP32 ADDRESS: %08x, Length: %d\n", + (unsigned long)pu4StartAddr, u4Length); + + if (IS_NOT_ALIGN_4((unsigned long)pu4StartAddr)) { + u32 u4ProtrudeLen = + sizeof(u32) - ((unsigned long)pu4StartAddr % 4); + + u4ProtrudeLen = + ((u4Length < u4ProtrudeLen) ? u4Length : u4ProtrudeLen); + LOG_FUNC("pu4StartAddr is not at DW boundary.\n"); + pucAddr = (u8 *)&pu4StartAddr[0]; + + switch (u4ProtrudeLen) { + case 1: + LOG_FUNC("(%p) %02x------\n", pu4StartAddr, pucAddr[0]); + break; + + case 2: + LOG_FUNC("(%p) %02x%02x----\n", pu4StartAddr, + pucAddr[1], pucAddr[0]); + break; + + case 3: + LOG_FUNC("(%p) %02x%02x%02x--\n", pu4StartAddr, + pucAddr[2], pucAddr[1], pucAddr[0]); + break; + + default: + break; + } + + u4Length -= u4ProtrudeLen; + pu4StartAddr = + (u32 *)((unsigned long)pu4StartAddr + u4ProtrudeLen); + } + + while (u4Length > 0) { + if (u4Length >= 16) { + LOG_FUNC("(%p) %08x %08x %08x %08x\n", pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1], + pu4StartAddr[2], pu4StartAddr[3]); + pu4StartAddr += 4; + u4Length -= 16; + } else { + switch (u4Length) { + case 1: + pucAddr = (u8 *)&pu4StartAddr[0]; + LOG_FUNC("(%p) ------%02x\n", pu4StartAddr, + pucAddr[0]); + break; + + case 2: + pucAddr = (u8 *)&pu4StartAddr[0]; + LOG_FUNC("(%p) ----%02x%02x\n", pu4StartAddr, + pucAddr[1], pucAddr[0]); + break; + + case 3: + pucAddr = (u8 *)&pu4StartAddr[0]; + LOG_FUNC("(%p) --%02x%02x%02x\n", pu4StartAddr, + pucAddr[2], pucAddr[1], pucAddr[0]); + break; + + case 4: + LOG_FUNC("(%p) %08x\n", pu4StartAddr, + pu4StartAddr[0]); + break; + + case 5: + pucAddr = (u8 *)&pu4StartAddr[1]; + LOG_FUNC("(%p) %08x ------%02x\n", pu4StartAddr, + pu4StartAddr[0], pucAddr[0]); + break; + + case 6: + pucAddr = (u8 *)&pu4StartAddr[1]; + LOG_FUNC("(%p) %08x ----%02x%02x\n", + pu4StartAddr, pu4StartAddr[0], + pucAddr[1], pucAddr[0]); + break; + + case 7: + pucAddr = (u8 *)&pu4StartAddr[1]; + LOG_FUNC("(%p) %08x --%02x%02x%02x\n", + pu4StartAddr, pu4StartAddr[0], + pucAddr[2], pucAddr[1], pucAddr[0]); + break; + + case 8: + LOG_FUNC("(%p) %08x %08x\n", pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1]); + break; + + case 9: + pucAddr = (u8 *)&pu4StartAddr[2]; + LOG_FUNC("(%p) %08x %08x ------%02x\n", + pu4StartAddr, pu4StartAddr[0], + pu4StartAddr[1], pucAddr[0]); + break; + + case 10: + pucAddr = (u8 *)&pu4StartAddr[2]; + LOG_FUNC("(%p) %08x %08x ----%02x%02x\n", + pu4StartAddr, pu4StartAddr[0], + pu4StartAddr[1], pucAddr[1], + pucAddr[0]); + break; + + case 11: + pucAddr = (u8 *)&pu4StartAddr[2]; + LOG_FUNC("(%p) %08x %08x --%02x%02x%02x\n", + pu4StartAddr, pu4StartAddr[0], + pu4StartAddr[1], pucAddr[2], + pucAddr[1], pucAddr[0]); + break; + + case 12: + LOG_FUNC("(%p) %08x %08x %08x\n", pu4StartAddr, + pu4StartAddr[0], pu4StartAddr[1], + pu4StartAddr[2]); + break; + + case 13: + pucAddr = (u8 *)&pu4StartAddr[3]; + LOG_FUNC("(%p) %08x %08x %08x ------%02x\n", + pu4StartAddr, pu4StartAddr[0], + pu4StartAddr[1], pu4StartAddr[2], + pucAddr[0]); + break; + + case 14: + pucAddr = (u8 *)&pu4StartAddr[3]; + LOG_FUNC("(%p) %08x %08x %08x ----%02x%02x\n", + pu4StartAddr, pu4StartAddr[0], + pu4StartAddr[1], pu4StartAddr[2], + pucAddr[1], pucAddr[0]); + break; + + case 15: + default: + pucAddr = (u8 *)&pu4StartAddr[3]; + LOG_FUNC("(%p) %08x %08x %08x --%02x%02x%02x\n", + pu4StartAddr, pu4StartAddr[0], + pu4StartAddr[1], pu4StartAddr[2], + pucAddr[2], pucAddr[1], pucAddr[0]); + break; + } + u4Length = 0; + } + } +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/common/wlan_lib.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/common/wlan_lib.c new file mode 100644 index 00000000000000..674679149f41a7 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/common/wlan_lib.c @@ -0,0 +1,11022 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file wlan_lib.c + * \brief Internal driver stack will export the required procedures here for + * GLUE Layer. + * + * This file contains all routines which are exported from MediaTek 802.11 + * Wireless LAN driver stack to GLUE Layer. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#include "mgmt/ais_fsm.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* 6.1.1.2 Interpretation of priority parameter in MAC service primitives */ +/* Static convert the Priority Parameter/TID(User Priority/TS Identifier) to + * Traffic Class */ +const u8 aucPriorityParam2TC[] = { TC1_INDEX, TC0_INDEX, TC0_INDEX, TC1_INDEX, + TC2_INDEX, TC2_INDEX, TC3_INDEX, TC3_INDEX }; + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef struct _CODE_MAPPING_T { + u32 u4RegisterValue; + s32 u4TxpowerOffset; +} CODE_MAPPING_T, *P_CODE_MAPPING_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +u8 fgIsBusAccessFailed = false; +u32 g_au4RxMpduCnt[ENUM_BAND_NUM] = { 0 }; +u32 g_au4FcsError[ENUM_BAND_NUM] = { 0 }; +u32 g_au4RxFifoCnt[ENUM_BAND_NUM] = { 0 }; +u32 g_au4AmpduTxSfCnt[ENUM_BAND_NUM] = { 0 }; +u32 g_au4AmpduTxAckSfCnt[ENUM_BAND_NUM] = { 0 }; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define SIGNED_EXTEND(n, _sValue) \ + (((_sValue) & BIT((n) - 1)) ? ((_sValue) | BITS(n, 31)) : \ + ((_sValue) & ~BITS(n, 31))) + +/* TODO: Check */ +/* OID set handlers without the need to access HW register */ +PFN_OID_HANDLER_FUNC apfnOidSetHandlerWOHwAccess[] = { + wlanoidSetChannel, + wlanoidSetBeaconInterval, + wlanoidSetAtimWindow, + wlanoidSetFrequency, +}; + +/* TODO: Check */ +/* OID query handlers without the need to access HW register */ +PFN_OID_HANDLER_FUNC apfnOidQueryHandlerWOHwAccess[] = { + wlanoidQueryBssid, + wlanoidQuerySsid, + wlanoidQueryInfrastructureMode, + wlanoidQueryAuthMode, + wlanoidQueryEncryptionStatus, + wlanoidQueryPmkid, + wlanoidQueryNetworkTypeInUse, + wlanoidQueryBssidList, + wlanoidQueryAcpiDevicePowerState, + wlanoidQuerySupportedRates, + wlanoidQueryDesiredRates, + wlanoidQuery802dot11PowerSaveProfile, + wlanoidQueryBeaconInterval, + wlanoidQueryAtimWindow, + wlanoidQueryFrequency, +}; + +/* OID set handlers allowed in RF test mode */ +PFN_OID_HANDLER_FUNC apfnOidSetHandlerAllowedInRFTest[] = { + wlanoidRftestSetTestMode, wlanoidRftestSetAbortTestMode, + wlanoidRftestSetAutoTest, wlanoidSetMcrWrite, wlanoidSetEepromWrite +}; + +/* OID query handlers allowed in RF test mode */ +PFN_OID_HANDLER_FUNC + apfnOidQueryHandlerAllowedInRFTest[] = { wlanoidRftestQueryAutoTest, + wlanoidQueryMcrRead, + wlanoidQueryEepromRead } + +; + +PFN_OID_HANDLER_FUNC apfnOidWOTimeoutCheck[] = { + wlanoidRftestSetTestMode, + wlanoidRftestSetAbortTestMode, + wlanoidSetAcpiDevicePowerState, +}; +#if CFG_SUPPORT_COMPRESSION_FW_OPTION +#define COMPRESSION_OPTION_OFFSET 4 +#define COMPRESSION_OPTION_MASK BIT(4) +#endif + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This is a private routine, which is used to check if HW access is + * needed for the OID query/ set handlers. + * + * \param[IN] pfnOidHandler Pointer to the OID handler. + * \param[IN] fgSetInfo It is a Set information handler. + * + * \retval true This function needs HW access + * \retval false This function does not need HW access + */ +/*----------------------------------------------------------------------------*/ +u8 wlanIsHandlerNeedHwAccess(IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN u8 fgSetInfo) +{ + PFN_OID_HANDLER_FUNC *apfnOidHandlerWOHwAccess; + u32 i; + u32 u4NumOfElem; + + if (fgSetInfo) { + apfnOidHandlerWOHwAccess = apfnOidSetHandlerWOHwAccess; + u4NumOfElem = sizeof(apfnOidSetHandlerWOHwAccess) / + sizeof(PFN_OID_HANDLER_FUNC); + } else { + apfnOidHandlerWOHwAccess = apfnOidQueryHandlerWOHwAccess; + u4NumOfElem = sizeof(apfnOidQueryHandlerWOHwAccess) / + sizeof(PFN_OID_HANDLER_FUNC); + } + + for (i = 0; i < u4NumOfElem; i++) + if (apfnOidHandlerWOHwAccess[i] == pfnOidHandler) { + return false; + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set flag for later handling card + * ejected event. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * + * \return (none) + * + * \note When surprised removal happens, Glue layer should invoke this + * function to notify WPDD not to do any hw access. + */ +/*----------------------------------------------------------------------------*/ +void wlanCardEjected(IN P_ADAPTER_T prAdapter) +{ + DEBUGFUNC("wlanCardEjected"); + /* INITLOG(("\n")); */ + + ASSERT(prAdapter); + + /* mark that the card is being ejected, NDIS will shut us down soon */ + nicTxRelease(prAdapter, false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Create adapter object + * + * \param prAdapter This routine is call to allocate the driver software + * objects. If fails, return NULL. \retval NULL If it fails, NULL is returned. + * \retval NOT NULL If the adapter was initialized successfully. + */ +/*----------------------------------------------------------------------------*/ +P_ADAPTER_T wlanAdapterCreate(IN P_GLUE_INFO_T prGlueInfo) +{ + P_ADAPTER_T prAdpater = (P_ADAPTER_T)NULL; + + DEBUGFUNC("wlanAdapterCreate"); + + do { + prAdpater = (P_ADAPTER_T)kalMemAlloc(sizeof(ADAPTER_T), + VIR_MEM_TYPE); + + if (!prAdpater) { + DBGLOG(INIT, ERROR, + "Allocate ADAPTER memory ==> FAILED\n"); + break; + } +#if QM_TEST_MODE + g_rQM.prAdapter = prAdpater; +#endif + kalMemZero(prAdpater, sizeof(ADAPTER_T)); + prAdpater->prGlueInfo = prGlueInfo; + } while (false); + + return prAdpater; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Destroy adapter object + * + * \param prAdapter This routine is call to destroy the driver software objects. + * If fails, return NULL. + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void wlanAdapterDestroy(IN P_ADAPTER_T prAdapter) +{ + if (!prAdapter) { + return; + } + + kalMemFree(prAdapter, VIR_MEM_TYPE, sizeof(ADAPTER_T)); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Initialize the adapter. The sequence is + * 1. Disable interrupt + * 2. Read adapter configuration from EEPROM and registry, verify chip + * ID. + * 3. Create NIC Tx/Rx resource. + * 4. Initialize the chip + * 5. Initialize the protocol + * 6. Enable Interrupt + * + * \param prAdapter Pointer of Adapter Data Structure + * + * \retval WLAN_STATUS_SUCCESS: Success + * \retval WLAN_STATUS_FAILURE: Failed + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanAdapterStart(IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo) +{ + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + u32 i; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanAdapterStart"); + + /* 4 <0> Reset variables in ADAPTER_T */ + /* prAdapter->fgIsFwOwn = true; */ + prAdapter->fgIsEnterD3ReqIssued = false; + + prAdapter->u4OwnFailedCount = 0; + prAdapter->u4OwnFailedLogCount = 0; + + QUEUE_INITIALIZE(&(prAdapter->rPendingCmdQueue)); + QUEUE_INITIALIZE(&prAdapter->rTxCmdQueue); + QUEUE_INITIALIZE(&prAdapter->rTxCmdDoneQueue); + QUEUE_INITIALIZE(&prAdapter->rWDevLockQueue); +#if CFG_FIX_2_TX_PORT + QUEUE_INITIALIZE(&prAdapter->rTxP0Queue); + QUEUE_INITIALIZE(&prAdapter->rTxP1Queue); +#else + for (i = 0; i < TX_PORT_NUM; i++) + QUEUE_INITIALIZE(&prAdapter->rTxPQueue[i]); +#endif + QUEUE_INITIALIZE(&prAdapter->rRxQueue); + QUEUE_INITIALIZE(&prAdapter->rTxDataDoneQueue); + + /* Initialize rWlanInfo */ + kalMemSet(&(prAdapter->rWlanInfo), 0, sizeof(WLAN_INFO_T)); + + /* Initialize aprBssInfo[]. + * Important: index shall be same when mapping between aprBssInfo[] + * and arBssInfoPool[]. rP2pDevInfo is indexed to final one. + */ + for (i = 0; i < BSS_INFO_NUM; i++) + prAdapter->aprBssInfo[i] = + &prAdapter->rWifiVar.arBssInfoPool[i]; + prAdapter->aprBssInfo[P2P_DEV_BSS_INDEX] = + &prAdapter->rWifiVar.rP2pDevInfo; + + /* 4 <0.1> reset fgIsBusAccessFailed */ + fgIsBusAccessFailed = false; + + do { + u4Status = nicAllocateAdapterMemory(prAdapter); + if (u4Status != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, + "nicAllocateAdapterMemory Error!\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } + + prAdapter->u4OsPacketFilter = PARAM_PACKET_FILTER_SUPPORTED; + + DBGLOG(INIT, INFO, "wlanAdapterStart(): Acquiring LP-OWN\n"); + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + DBGLOG(INIT, INFO, + "wlanAdapterStart(): Acquiring LP-OWN-end\n"); + +#if (CFG_ENABLE_FULL_PM == 0) + nicpmSetDriverOwn(prAdapter); +#endif + + if (prAdapter->fgIsFwOwn == true) { + DBGLOG(INIT, ERROR, "nicpmSetDriverOwn() failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } + /* 4 <1> Initialize the Adapter */ + u4Status = nicInitializeAdapter(prAdapter); + if (u4Status != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "nicInitializeAdapter failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } + + /* 4 <2.1> Initialize System Service (MGMT Memory pool and + * STA_REC) */ + nicInitSystemService(prAdapter); + + /* 4 <2.2> Initialize Feature Options */ + wlanInitFeatureOption(prAdapter); +#if CFG_SUPPORT_MTK_SYNERGY + if (kalIsConfigurationExist(prAdapter->prGlueInfo) == true) { + if (prRegInfo->prNvramSettings->u2FeatureReserved & + BIT(MTK_FEATURE_2G_256QAM_DISABLED)) { + prAdapter->rWifiVar.aucMtkFeature[0] &= + ~(MTK_SYNERGY_CAP_SUPPORT_24G_MCS89); + } + } +#endif + + /* 4 <2.3> Overwrite debug level settings */ + wlanCfgSetDebugLevel(prAdapter); + + /* 4 <3> Initialize Tx */ + nicTxInitialize(prAdapter); + wlanDefTxPowerCfg(prAdapter); + + /* 4 <4> Initialize Rx */ + nicRxInitialize(prAdapter); + + /* 4 <6> Enable HIF cut-through to N9 mode, not visiting CR4 */ + HAL_ENABLE_FWDL(prAdapter, true); + + /* 4 <7> Get ECO Version */ + u4Status = wlanSetChipEcoInfo(prAdapter); + + if (u4Status != WLAN_STATUS_SUCCESS) { + break; + } + +#if CFG_ENABLE_FW_DOWNLOAD + /* 4 <8> FW/patch download */ + + /* 1. disable interrupt, download is done by polling mode only + */ + nicDisableInterrupt(prAdapter); + + /* 2. Initialize Tx Resource to fw download state */ + nicTxInitResetResource(prAdapter); + + u4Status = wlanDownloadFW(prAdapter); + + if (u4Status != WLAN_STATUS_SUCCESS) { + break; + } +#endif + + DBGLOG(INIT, INFO, "Waiting for Ready bit..\n"); + + /* 4 <9> check Wi-Fi FW asserts ready bit */ + u4Status = wlanCheckWifiFunc(prAdapter, true); + + if (u4Status == WLAN_STATUS_SUCCESS) { + u32 *pu4WHISR = NULL; + u16 au2TxCount[16]; + + pu4WHISR = + (u32 *)kalMemAlloc(sizeof(u32), PHY_MEM_TYPE); + if (!pu4WHISR) { + DBGLOG(INIT, ERROR, "Allocate pu4WHISR fail\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } + /* 1. reset interrupt status */ + HAL_READ_INTR_STATUS(prAdapter, sizeof(u32), + (u8 *)pu4WHISR); + if (HAL_IS_TX_DONE_INTR(*pu4WHISR)) { + HAL_READ_TX_RELEASED_COUNT(prAdapter, + au2TxCount); + } + + if (pu4WHISR) { + kalMemFree(pu4WHISR, PHY_MEM_TYPE, sizeof(u32)); + } + + /* Set FW download success flag */ + prAdapter->fgIsFwDownloaded = true; + + /* 2. query & reset TX Resource for normal operation */ + wlanQueryNicResourceInformation(prAdapter); + +#if (CFG_SUPPORT_NIC_CAPABILITY == 1) + /* 2.9 Workaround for Capability CMD packet lost issue + */ + DBGLOG(INIT, INFO, "Send a Dummy CMD as workaround\n"); + wlanSendDummyCmd(prAdapter, true); + + /* 3. query for NIC capability */ + wlanQueryNicCapability(prAdapter); + + /* 4. query for NIC capability V2 */ + wlanQueryNicCapabilityV2(prAdapter); + + /* 5. reset TX Resource for normal operation + * based on the information reported from + * CMD_NicCapabilityV2 + */ + wlanUpdateNicResourceInformation(prAdapter); + + wlanPrintVersion(prAdapter); +#endif + + /* 6. update basic configuration */ + wlanUpdateBasicConfig(prAdapter); + + /* 7. Override network address */ + wlanUpdateNetworkAddress(prAdapter); + + /* 8. Apply Network Address */ + nicApplyNetworkAddress(prAdapter); + + /* 9. indicate disconnection as default status */ + kalIndicateStatusAndComplete( + prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + } else { + return WLAN_STATUS_FAILURE; + } + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, false); + + if (u4Status != WLAN_STATUS_SUCCESS) { + break; + } + + /* OID timeout timer initialize */ + cnmTimerInitTimer(prAdapter, &prAdapter->rOidTimeoutTimer, + (PFN_MGMT_TIMEOUT_FUNC)wlanReleasePendingOid, + (unsigned long)NULL); + + prAdapter->ucOidTimeoutCount = 0; + + prAdapter->fgIsChipNoAck = false; + + /* Return Indicated Rfb list timer */ + cnmTimerInitTimer(prAdapter, &prAdapter->rPacketDelaySetupTimer, + (PFN_MGMT_TIMEOUT_FUNC) + wlanReturnPacketDelaySetupTimeout, + (unsigned long)NULL); + + /* Power state initialization */ + prAdapter->fgWiFiInSleepyState = false; + prAdapter->rAcpiState = ACPI_STATE_D0; + + if (prAdapter->rWifiVar.fgDisOnlineScan == 0) { + prAdapter->fgEnOnlineScan = true; + }else{ + prAdapter->fgEnOnlineScan = false; + } + + /* Beacon lost detection option */ + if (prAdapter->rWifiVar.fgDisBcnLostDetection != 0) { + prAdapter->fgDisBcnLostDetection = true; + } + + /* Load compile time constant */ + prAdapter->rWlanInfo.u2BeaconPeriod = + CFG_INIT_ADHOC_BEACON_INTERVAL; + prAdapter->rWlanInfo.u2AtimWindow = CFG_INIT_ADHOC_ATIM_WINDOW; + + prAdapter->u4PsCurrentMeasureEn = + prRegInfo->u4PsCurrentMeasureEn; + + prAdapter->fgEnArpFilter = prAdapter->rWifiVar.fgEnArpFilter; + prAdapter->u4UapsdAcBmp = prAdapter->rWifiVar.u4UapsdAcBmp; + prAdapter->u4MaxSpLen = prAdapter->rWifiVar.u4MaxSpLen; + + DBGLOG(INIT, + TRACE, + "[1] fgEnArpFilter:0x%x, u4UapsdAcBmp:0x%x, u4MaxSpLen:0x%x", + prAdapter->fgEnArpFilter, + prAdapter->u4UapsdAcBmp, + prAdapter->u4MaxSpLen); + + prAdapter->fgEnCtiaPowerMode = false; + + /* MGMT Initialization */ + nicInitMGMT(prAdapter, prRegInfo); + + /* Enable WZC Disassociation */ + prAdapter->rWifiVar.fgSupportWZCDisassociation = true; + + /* Apply Rate Setting */ + if ((ENUM_REGISTRY_FIXED_RATE_T)(prRegInfo->u4FixedRate) < + FIXED_RATE_NUM) { + prAdapter->rWifiVar.eRateSetting = + (ENUM_REGISTRY_FIXED_RATE_T)(prRegInfo + ->u4FixedRate); + } else { + prAdapter->rWifiVar.eRateSetting = FIXED_RATE_NONE; + } + + if (prAdapter->rWifiVar.eRateSetting == FIXED_RATE_NONE) { + /* Enable Auto (Long/Short) Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_AUTO; + } else if ((prAdapter->rWifiVar.eRateSetting >= + FIXED_RATE_MCS0_20M_400NS && + prAdapter->rWifiVar.eRateSetting <= + FIXED_RATE_MCS7_20M_400NS) || + (prAdapter->rWifiVar.eRateSetting >= + FIXED_RATE_MCS0_40M_400NS && + prAdapter->rWifiVar.eRateSetting <= + FIXED_RATE_MCS32_400NS)) { + /* Force Short Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_SHORT; + } else { + /* Force Long Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_LONG; + } + + /* Disable Hidden SSID Join */ + prAdapter->rWifiVar.fgEnableJoinToHiddenSSID = false; + + /* Enable Short Slot Time */ + prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable = true; + + /* configure available PHY type set */ + nicSetAvailablePhyTypeSet(prAdapter); + + /* Check if it is disabled by hardware */ + if (prAdapter->fgIsHw5GBandDisabled) { + prAdapter->fgEnable5GBand = false; + }else{ + prAdapter->fgEnable5GBand = true; + } + +#if CFG_SUPPORT_NVRAM + /* load manufacture data */ + if (kalIsConfigurationExist(prAdapter->prGlueInfo) == true) { + wlanLoadManufactureData(prAdapter, prRegInfo); + } else { + DBGLOG(INIT, INFO, "%s: load manufacture data fail\n", + __func__); + } +#endif + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK + /* Init the Rx Look Back related */ + prAdapter->ucRxLBIndex = 0; + prAdapter->ucRxLBSize = 0; + kalMemZero(prAdapter->ucRxLBList, sizeof(u8) * 4); +#endif + +#if CFG_SUPPORT_DBDC + /* Update DBDC default setting */ + cnmInitDbdcSetting(prAdapter); +#endif + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO + prAdapter->fgIsMcsInfoValid = false; +#endif + prAdapter->r1xTxDoneStatus = TX_RESULT_UNINITIALIZED; + } while (false); + + if (u4Status == WLAN_STATUS_SUCCESS) { + /* restore to hardware default */ + HAL_SET_INTR_STATUS_READ_CLEAR(prAdapter); + HAL_SET_MAILBOX_READ_CLEAR(prAdapter, false); + + /* Enable interrupt */ + nicEnableInterrupt(prAdapter); + } else { + /* release allocated memory */ + DBGLOG(INIT, INFO, "%s: Init adapter failed!\n", + __func__); + nicReleaseAdapterMemory(prAdapter); + } + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Uninitialize the adapter + * + * \param prAdapter Pointer of Adapter Data Structure + * + * \retval WLAN_STATUS_SUCCESS: Success + * \retval WLAN_STATUS_FAILURE: Failed + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanAdapterStop(IN P_ADAPTER_T prAdapter) +{ + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + + /* MGMT - unitialization */ + nicUninitMGMT(prAdapter); + + /* Release all CMD/MGMT/SEC frame in command queue */ + kalClearCommandQueue(prAdapter->prGlueInfo, true); + + /* Release all CMD in pending command queue */ + wlanClearPendingCommandQueue(prAdapter); + + /* Flush all items in queues for multi-thread */ + wlanClearTxCommandQueue(prAdapter); + + wlanClearTxCommandDoneQueue(prAdapter); + + wlanClearDataQueue(prAdapter); + + wlanClearRxToOsQueue(prAdapter); + + /* Hif power off wifi */ + wlanPowerOffWifi(prAdapter); + + nicRxUninitialize(prAdapter); + + nicTxRelease(prAdapter, false); + + /* System Service Uninitialization */ + nicUninitSystemService(prAdapter); + + nicReleaseAdapterMemory(prAdapter); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is called by ISR (interrupt). + * + * \param prAdapter Pointer of Adapter Data Structure + * + * \retval true: NIC's interrupt + * \retval false: Not NIC's interrupt + */ +/*----------------------------------------------------------------------------*/ +u8 wlanISR(IN P_ADAPTER_T prAdapter, IN u8 fgGlobalIntrCtrl) +{ + ASSERT(prAdapter); + + if (fgGlobalIntrCtrl) { + nicDisableInterrupt(prAdapter); + + /* wlanIST(prAdapter); */ + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is called by IST (task_let). + * + * \param prAdapter Pointer of Adapter Data Structure + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void wlanIST(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + + nicProcessIST(prAdapter); + + nicEnableInterrupt(prAdapter); + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, false); +} + +void wlanClearPendingInterrupt(IN P_ADAPTER_T prAdapter) +{ + u32 i; + + i = 0; + while (i < CFG_IST_LOOP_COUNT && + nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) + i++; + ; +} + +WLAN_STATUS wlanCheckWifiFunc(IN P_ADAPTER_T prAdapter, IN u8 fgRdyChk) +{ + u8 fgResult, fgTimeout; + u32 u4Result, u4Status, u4StartTime, u4CurTime; + + u4StartTime = kalGetTimeTick(); + fgTimeout = false; + + while (true) { + if (fgRdyChk) { + HAL_WIFI_FUNC_READY_CHECK( + prAdapter, WIFI_FUNC_READY_BITS, &fgResult); + } else { + HAL_WIFI_FUNC_OFF_CHECK(prAdapter, WIFI_FUNC_READY_BITS, + &fgResult); + + if (nicProcessIST(prAdapter) != + WLAN_STATUS_NOT_INDICATING) { + DBGLOG(INIT, INFO, + "Handle pending interrupt\n"); + } + } + u4CurTime = kalGetTimeTick(); + + if (CHECK_FOR_TIMEOUT(u4CurTime, u4StartTime, + CFG_RESPONSE_POLLING_TIMEOUT * + CFG_RESPONSE_POLLING_DELAY)) { + fgTimeout = true; + } + + if (fgResult) { + if (fgRdyChk) { + DBGLOG(INIT, INFO, "Ready bit asserted\n"); + }else{ + DBGLOG(INIT, INFO, "Wi-Fi power off done!\n"); + } + + u4Status = WLAN_STATUS_SUCCESS; + + break; + } else if (kalIsCardRemoved(prAdapter->prGlueInfo) == true || + fgIsBusAccessFailed == true) { + u4Status = WLAN_STATUS_FAILURE; + + break; + } else if (fgTimeout) { + HAL_WIFI_FUNC_GET_STATUS(prAdapter, u4Result); + DBGLOG(INIT, ERROR, + "Waiting for %s: Timeout, Status=0x%08x\n", + fgRdyChk ? "ready bit" : "power off", u4Result); + + u4Status = WLAN_STATUS_FAILURE; + + break; + } + kalMsleep(CFG_RESPONSE_POLLING_DELAY); + } + + return u4Status; +} + +WLAN_STATUS wlanPowerOffWifi(IN P_ADAPTER_T prAdapter) +{ + WLAN_STATUS rStatus; + /* Hif power off wifi */ + rStatus = halHifPowerOffWifi(prAdapter); + prAdapter->fgIsCr4FwDownloaded = false; + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will check command queue to find out if any could be + * dequeued and/or send to HIF to MT6620 + * + * \param prAdapter Pointer of Adapter Data Structure + * \param prCmdQue Pointer of Command Queue (in Glue Layer) + * + * \retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanProcessCommandQueue(IN P_ADAPTER_T prAdapter, + IN P_QUE_T prCmdQue) +{ + WLAN_STATUS rStatus; + QUE_T rTempCmdQue, rMergeCmdQue, rStandInCmdQue; + P_QUE_T prTempCmdQue, prMergeCmdQue, prStandInCmdQue; + P_QUE_ENTRY_T prQueueEntry; + P_CMD_INFO_T prCmdInfo; + P_MSDU_INFO_T prMsduInfo; + ENUM_FRAME_ACTION_T eFrameAction = FRAME_ACTION_DROP_PKT; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prCmdQue); + + prTempCmdQue = &rTempCmdQue; + prMergeCmdQue = &rMergeCmdQue; + prStandInCmdQue = &rStandInCmdQue; + + QUEUE_INITIALIZE(prTempCmdQue); + QUEUE_INITIALIZE(prMergeCmdQue); + QUEUE_INITIALIZE(prStandInCmdQue); + + /* 4 <1> Move whole list of CMD_INFO to temp queue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); + + /* 4 <2> Dequeue from head and check it is able to be sent */ + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + switch (prCmdInfo->eCmdType) { + case COMMAND_TYPE_GENERAL_IOCTL: + case COMMAND_TYPE_NETWORK_IOCTL: + /* command packet will be always sent */ + eFrameAction = FRAME_ACTION_TX_PKT; + break; + + case COMMAND_TYPE_SECURITY_FRAME: + /* inquire with QM */ + prMsduInfo = prCmdInfo->prMsduInfo; + +#if CFG_MESON_G12A_PATCH + if (prMsduInfo->u2FrameLength > 1408) { + DBGLOG(INIT, INFO, + "Security frame length is too long [%d]\n", + prMsduInfo->u2FrameLength); + } +#endif + + eFrameAction = qmGetFrameAction( + prAdapter, prMsduInfo->ucBssIndex, + prMsduInfo->ucStaRecIndex, NULL, + FRAME_TYPE_802_1X, prCmdInfo->u2InfoBufLen); + break; + + case COMMAND_TYPE_MANAGEMENT_FRAME: + /* inquire with QM */ + prMsduInfo = prCmdInfo->prMsduInfo; + +#if CFG_MESON_G12A_PATCH + if (prMsduInfo->u2FrameLength > 1408) { + DBGLOG(INIT, INFO, + "Management frame length is too long [%d]\n", + prMsduInfo->u2FrameLength); + } +#endif + + eFrameAction = qmGetFrameAction( + prAdapter, prMsduInfo->ucBssIndex, + prMsduInfo->ucStaRecIndex, prMsduInfo, + FRAME_TYPE_MMPDU, prMsduInfo->u2FrameLength); + break; + + default: + ASSERT(0); + break; + } + + /* 4 <3> handling upon dequeue result */ + if (eFrameAction == FRAME_ACTION_DROP_PKT) { + DBGLOG(INIT, INFO, + "DROP CMD TYPE[%u] ID[0x%02X] SEQ[%u]\n", + prCmdInfo->eCmdType, prCmdInfo->ucCID, + prCmdInfo->ucCmdSeqNum); + wlanReleaseCommand(prAdapter, prCmdInfo, + TX_RESULT_DROPPED_IN_DRIVER); + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } else if (eFrameAction == FRAME_ACTION_QUEUE_PKT) { + DBGLOG(INIT, TRACE, + "QUE back CMD TYPE[%u] ID[0x%02X] SEQ[%u]\n", + prCmdInfo->eCmdType, prCmdInfo->ucCID, + prCmdInfo->ucCmdSeqNum); + + QUEUE_INSERT_TAIL(prMergeCmdQue, prQueueEntry); + } else if (eFrameAction == FRAME_ACTION_TX_PKT) { + /* 4 <4> Send the command */ + rStatus = wlanSendCommandMthread(prAdapter, prCmdInfo); + + if (rStatus == WLAN_STATUS_RESOURCES) { + /* no more TC4 resource for further transmission + */ + DBGLOG(INIT, + INFO, + "NO Res CMD TYPE[%u] ID[0x%02X] SEQ[%u]\n", + prCmdInfo->eCmdType, + prCmdInfo->ucCID, + prCmdInfo->ucCmdSeqNum); + + set_bit(GLUE_FLAG_HIF_PRT_HIF_DBG_INFO_BIT, + &(prAdapter->prGlueInfo->ulFlag)); + + QUEUE_INSERT_TAIL(prMergeCmdQue, prQueueEntry); + break; + } else if (rStatus == WLAN_STATUS_PENDING) { + /* Do nothing */ + /* Do nothing */ + } else if (rStatus == WLAN_STATUS_SUCCESS) { + /* Do nothing */ + /* Do nothing */ + } else { + P_CMD_INFO_T prCmdInfo = + (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, + rStatus); + } + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + } else { + ASSERT(0); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + /* 4 <3> Merge back to original queue */ + /* 4 <3.1> Merge prMergeCmdQue & prTempCmdQue */ + QUEUE_CONCATENATE_QUEUES(prMergeCmdQue, prTempCmdQue); + + /* 4 <3.2> Move prCmdQue to prStandInQue, due to prCmdQue might differ + * due to incoming 802.1X frames */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prStandInCmdQue, prCmdQue); + + /* 4 <3.3> concatenate prStandInQue to prMergeCmdQue */ + QUEUE_CONCATENATE_QUEUES(prMergeCmdQue, prStandInCmdQue); + + /* 4 <3.4> then move prMergeCmdQue to prCmdQue */ + QUEUE_MOVE_ALL(prCmdQue, prMergeCmdQue); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE); + + kalSetTxCmdEvent2Hif(prAdapter->prGlueInfo); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will take CMD_INFO_T which carry some information of + * incoming OID and notify the NIC_TX to send CMD. + * + * \param prAdapter Pointer of Adapter Data Structure + * \param prCmdInfo Pointer of P_CMD_INFO_T + * + * \retval WLAN_STATUS_SUCCESS : CMD was written to HIF and be freed(CMD Done) + * immediately. \retval WLAN_STATUS_RESOURCE : No resource for current command, + * need to wait for previous frame finishing their transmission. \retval + * WLAN_STATUS_FAILURE : Get failure while access HIF or been rejected. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanSendCommand(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo) +{ + P_TX_CTRL_T prTxCtrl; + u8 ucTC; /* "Traffic Class" SW(Driver) resource classification */ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + prTxCtrl = &prAdapter->rTxCtrl; + + do { + /* <0> card removal check */ + if (kalIsCardRemoved(prAdapter->prGlueInfo) == true || + fgIsBusAccessFailed == true) { + rStatus = WLAN_STATUS_FAILURE; + break; + } + + /* <1.1> Assign Traffic Class(TC) */ + ucTC = nicTxGetCmdResourceType(prCmdInfo); + + /* <1.2> Check if pending packet or resource was exhausted */ + rStatus = nicTxAcquireResource(prAdapter, ucTC, true); + if (rStatus == WLAN_STATUS_RESOURCES) { + DBGLOG(INIT, INFO, "NO Resource:%d\n", ucTC); + break; + } + /* <1.3> Forward CMD_INFO_T to NIC Layer */ + rStatus = nicTxCmd(prAdapter, prCmdInfo, ucTC); + + /* <1.4> Set Pending in response to Query Command/Need Response + */ + if (rStatus == WLAN_STATUS_SUCCESS) { + if ((!prCmdInfo->fgSetQuery) || (prCmdInfo->fgNeedResp)) { + rStatus = WLAN_STATUS_PENDING; + } + } + } while (false); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will take CMD_INFO_T which carry some information of + * incoming OID and notify the NIC_TX to send CMD. + * + * \param prAdapter Pointer of Adapter Data Structure + * \param prCmdInfo Pointer of P_CMD_INFO_T + * + * \retval WLAN_STATUS_SUCCESS : CMD was written to HIF and be freed(CMD Done) + * immediately. \retval WLAN_STATUS_RESOURCE : No resource for current command, + * need to wait for previous frame finishing their transmission. \retval + * WLAN_STATUS_FAILURE : Get failure while access HIF or been rejected. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanSendCommandMthread(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo) +{ + P_TX_CTRL_T prTxCtrl; + u8 ucTC; /* "Traffic Class" SW(Driver) resource classification */ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + prTxCtrl = &prAdapter->rTxCtrl; + + prTempCmdQue = &rTempCmdQue; + QUEUE_INITIALIZE(prTempCmdQue); + + do { + /* <0> card removal check */ + if (kalIsCardRemoved(prAdapter->prGlueInfo) == true || + fgIsBusAccessFailed == true) { + rStatus = WLAN_STATUS_FAILURE; + break; + } + /* <1> Normal case of sending CMD Packet */ + /* <1.1> Assign Traffic Class(TC) */ + ucTC = nicTxGetCmdResourceType(prCmdInfo); + + /* <1.2> Check if pending packet or resource was exhausted */ + rStatus = nicTxAcquireResource(prAdapter, ucTC, true); + if (rStatus == WLAN_STATUS_RESOURCES) { + break; + } + + /* Process to pending command queue firest */ + if ((!prCmdInfo->fgSetQuery) || (prCmdInfo->fgNeedResp)) { + /* command packet which needs further handling upon + * response */ + /* + * KAL_ACQUIRE_SPIN_LOCK(prAdapter, + * SPIN_LOCK_CMD_PENDING); + * QUEUE_INSERT_TAIL(&(prAdapter->rPendingCmdQueue), + * (P_QUE_ENTRY_T)prCmdInfo); + * KAL_RELEASE_SPIN_LOCK(prAdapter, + * SPIN_LOCK_CMD_PENDING); + */ + } + QUEUE_INSERT_TAIL(prTempCmdQue, (P_QUE_ENTRY_T)prCmdInfo); + + /* <1.4> Set Pending in response to Query Command/Need Response + */ + if (rStatus == WLAN_STATUS_SUCCESS) { + if ((!prCmdInfo->fgSetQuery) || + (prCmdInfo->fgNeedResp) || + (prCmdInfo->eCmdType == + COMMAND_TYPE_SECURITY_FRAME)) { + rStatus = WLAN_STATUS_PENDING; + } + } + } while (false); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE); + QUEUE_CONCATENATE_QUEUES(&(prAdapter->rTxCmdQueue), prTempCmdQue); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE); + + return rStatus; +} + +void wlanTxCmdDoneCb(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + KAL_SPIN_LOCK_DECLARATION(); + + if ((prCmdInfo->fgSetQuery) || (!prCmdInfo->fgNeedResp)) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE); + QUEUE_INSERT_TAIL(&prAdapter->rTxCmdDoneQueue, + (P_QUE_ENTRY_T)prCmdInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE); + } + + /* call tx thread to work */ + set_bit(GLUE_FLAG_TX_CMD_DONE_BIT, &prAdapter->prGlueInfo->ulFlag); + wake_up_interruptible(&prAdapter->prGlueInfo->waitq); +} + +WLAN_STATUS wlanTxCmdMthread(IN P_ADAPTER_T prAdapter) +{ + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue; + QUE_T rTempCmdDoneQue; + P_QUE_T prTempCmdDoneQue; + P_QUE_ENTRY_T prQueueEntry; + P_CMD_INFO_T prCmdInfo; + /* P_CMD_ACCESS_REG prCmdAccessReg; + * P_CMD_ACCESS_REG prEventAccessReg; + * u32 u4Address; + */ + u32 u4TxDoneQueueSize; +#if CFG_MESON_G12A_PATCH + u32 tx_status; + u32 tx_retry_cnt = 0; +#endif + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + if (prAdapter == NULL) { + DBGLOG(TX, ERROR, "%s prAdapter NULL\n", __func__); + return WLAN_STATUS_FAILURE; + } + + prTempCmdQue = &rTempCmdQue; + QUEUE_INITIALIZE(prTempCmdQue); + + prTempCmdDoneQue = &rTempCmdDoneQue; + QUEUE_INITIALIZE(prTempCmdDoneQue); + + KAL_ACQUIRE_MUTEX(prAdapter, MUTEX_TX_CMD_CLEAR); + + /* TX Command Queue */ + /* 4 <1> Move whole list of CMD_INFO to temp queue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, &prAdapter->rTxCmdQueue); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE); + + /* 4 <2> Dequeue from head and check it is able to be sent */ + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + prCmdInfo->pfHifTxCmdDoneCb = wlanTxCmdDoneCb; + +#if CFG_MESON_G12A_PATCH + if (tx_retry_cnt == 0) { + if ((!prCmdInfo->fgSetQuery) || + (prCmdInfo->fgNeedResp)) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + SPIN_LOCK_CMD_PENDING); + QUEUE_INSERT_TAIL( + &(prAdapter->rPendingCmdQueue), + (P_QUE_ENTRY_T)prCmdInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, + SPIN_LOCK_CMD_PENDING); + } else { + QUEUE_INSERT_TAIL(prTempCmdDoneQue, + prQueueEntry); + } + } + tx_status = nicTxCmd(prAdapter, prCmdInfo, TC4_INDEX); + if (tx_retry_cnt < NIC_TX_RESOURCE_POLLING_TIMEOUT) { + if (tx_status == WLAN_STATUS_RESOURCES) { + tx_retry_cnt++; + kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC); + continue; + } + } else { + P_WIFI_CMD_T prWifiCmd = + (P_WIFI_CMD_T)prCmdInfo->pucInfoBuffer; + + if (prWifiCmd == NULL) { + DBGLOG(INIT, + ERROR, + "CMD cannot send, pucInfoBuffer is NULL\n"); + } else { + DBGLOG(INIT, + ERROR, + "RETRY[%d] TX CMD: ID[0x%02X] SEQ[%u] CMD cannot send\n", + tx_retry_cnt, + prWifiCmd->ucCID, + prWifiCmd->ucSeqNum); + } + tx_retry_cnt = 0; + } +#else + if ((!prCmdInfo->fgSetQuery) || (prCmdInfo->fgNeedResp)) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + QUEUE_INSERT_TAIL(&(prAdapter->rPendingCmdQueue), + (P_QUE_ENTRY_T)prCmdInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + } else { + QUEUE_INSERT_TAIL(prTempCmdDoneQue, prQueueEntry); + } + + nicTxCmd(prAdapter, prCmdInfo, TC4_INDEX); +#endif + + /* DBGLOG(INIT, INFO, + * ("==> TX CMD QID: %d (Q:%d)\n", prCmdInfo->ucCID, + * prTempCmdQue->u4NumElem)); + */ + + GLUE_DEC_REF_CNT(prAdapter->prGlueInfo->i4TxPendingCmdNum); + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + +#if CFG_MESON_G12A_PATCH + if (tx_retry_cnt) { + P_WIFI_CMD_T prWifiCmd = + (P_WIFI_CMD_T)prCmdInfo->pucInfoBuffer; + + if (prWifiCmd == NULL) { + DBGLOG(INIT, ERROR, + "RETRY done, pucInfoBuffer is NULL\n"); + } else { + DBGLOG(INIT, + STATE, + "RETRY[%d] TX CMD: ID[0x%02X] SEQ[%u]!\n", + tx_retry_cnt, + prWifiCmd->ucCID, + prWifiCmd->ucSeqNum); + } + } + tx_retry_cnt = 0; +#endif + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE); + QUEUE_CONCATENATE_QUEUES(&prAdapter->rTxCmdDoneQueue, prTempCmdDoneQue); + u4TxDoneQueueSize = prAdapter->rTxCmdDoneQueue.u4NumElem; + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE); + + KAL_RELEASE_MUTEX(prAdapter, MUTEX_TX_CMD_CLEAR); + + if (u4TxDoneQueueSize > 0) { + /* call tx thread to work */ + set_bit(GLUE_FLAG_TX_CMD_DONE_BIT, + &prAdapter->prGlueInfo->ulFlag); + wake_up_interruptible(&prAdapter->prGlueInfo->waitq); + } + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS wlanTxCmdDoneMthread(IN P_ADAPTER_T prAdapter) +{ + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue; + P_QUE_ENTRY_T prQueueEntry; + P_CMD_INFO_T prCmdInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prTempCmdQue = &rTempCmdQue; + QUEUE_INITIALIZE(prTempCmdQue); + + /* 4 <1> Move whole list of CMD_INFO to temp queue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, &prAdapter->rTxCmdDoneQueue); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE); + + /* 4 <2> Dequeue from head and check it is able to be sent */ + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, + prCmdInfo->pucInfoBuffer, + prCmdInfo->u2InfoBufLen); + } + /* Not pending cmd, free it after TX succeed! */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to clear all commands in TX command queue + * \param prAdapter Pointer of Adapter Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void wlanClearTxCommandQueue(IN P_ADAPTER_T prAdapter) +{ + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + KAL_SPIN_LOCK_DECLARATION(); + QUEUE_INITIALIZE(prTempCmdQue); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, &prAdapter->rTxCmdQueue); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->pfCmdTimeoutHandler) { + prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo); + } else { + wlanReleaseCommand(prAdapter, prCmdInfo, + TX_RESULT_QUEUE_CLEARANCE); + } + + /* Release Tx resource for CMD which resource is allocated but + * not used */ + nicTxReleaseResource( + prAdapter, nicTxGetCmdResourceType(prCmdInfo), 1, true); + + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to clear OID commands in TX command queue + * \param prAdapter Pointer of Adapter Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void wlanClearTxOidCommand(IN P_ADAPTER_T prAdapter) +{ + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + KAL_SPIN_LOCK_DECLARATION(); + QUEUE_INITIALIZE(prTempCmdQue); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE); + + QUEUE_MOVE_ALL(prTempCmdQue, &prAdapter->rTxCmdQueue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->fgIsOid) { + if (prCmdInfo->pfCmdTimeoutHandler) { + prCmdInfo->pfCmdTimeoutHandler(prAdapter, + prCmdInfo); + } else { + wlanReleaseCommand(prAdapter, prCmdInfo, + TX_RESULT_QUEUE_CLEARANCE); + } + + /* Release Tx resource for CMD which resource is + * allocated but not used */ + nicTxReleaseResource(prAdapter, + nicTxGetCmdResourceType(prCmdInfo), + 1, true); + + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } else { + QUEUE_INSERT_TAIL(&prAdapter->rTxCmdQueue, + prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to clear all commands in TX command done queue + * \param prAdapter Pointer of Adapter Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void wlanClearTxCommandDoneQueue(IN P_ADAPTER_T prAdapter) +{ + QUE_T rTempCmdDoneQue; + P_QUE_T prTempCmdDoneQue = &rTempCmdDoneQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + KAL_SPIN_LOCK_DECLARATION(); + QUEUE_INITIALIZE(prTempCmdDoneQue); + + /* 4 <1> Move whole list of CMD_INFO to temp queue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE); + QUEUE_MOVE_ALL(prTempCmdDoneQue, &prAdapter->rTxCmdDoneQueue); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE); + + /* 4 <2> Dequeue from head and check it is able to be sent */ + QUEUE_REMOVE_HEAD(prTempCmdDoneQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, + prCmdInfo->pucInfoBuffer, + prCmdInfo->u2InfoBufLen); + } + /* Not pending cmd, free it after TX succeed! */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + QUEUE_REMOVE_HEAD(prTempCmdDoneQue, prQueueEntry, + P_QUE_ENTRY_T); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to clear all buffer in port 0/1 queue + * \param prAdapter Pointer of Adapter Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void wlanClearDataQueue(IN P_ADAPTER_T prAdapter) +{ + if (HAL_IS_TX_DIRECT()) { + nicTxDirectClearHifQ(prAdapter); + } else { +#if CFG_FIX_2_TX_PORT + QUE_T qDataPort0, qDataPort1; + P_QUE_T prDataPort0, prDataPort1; + P_MSDU_INFO_T prMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + prDataPort0 = &qDataPort0; + prDataPort1 = &qDataPort1; + + QUEUE_INITIALIZE(prDataPort0); + QUEUE_INITIALIZE(prDataPort1); + + /* <1> Move whole list of CMD_INFO to temp queue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); + QUEUE_MOVE_ALL(prDataPort0, &prAdapter->rTxP0Queue); + QUEUE_MOVE_ALL(prDataPort1, &prAdapter->rTxP1Queue); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); + + /* <2> Release Tx resource */ + nicTxReleaseMsduResource( + prAdapter, (P_MSDU_INFO_T)QUEUE_GET_HEAD(prDataPort0)); + nicTxReleaseMsduResource( + prAdapter, (P_MSDU_INFO_T)QUEUE_GET_HEAD(prDataPort1)); + + /* <3> Return sk buffer */ + nicTxReturnMsduInfo(prAdapter, + (P_MSDU_INFO_T)QUEUE_GET_HEAD(prDataPort0)); + nicTxReturnMsduInfo(prAdapter, + (P_MSDU_INFO_T)QUEUE_GET_HEAD(prDataPort1)); + + /* <4> Clear pending MSDU info in data done queue */ + KAL_ACQUIRE_MUTEX(prAdapter, MUTEX_TX_DATA_DONE_QUE); + while (QUEUE_IS_NOT_EMPTY(&prAdapter->rTxDataDoneQueue)) { + QUEUE_REMOVE_HEAD(&prAdapter->rTxDataDoneQueue, + prMsduInfo, P_MSDU_INFO_T); + + nicTxFreePacket(prAdapter, prMsduInfo, false); + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + } + KAL_RELEASE_MUTEX(prAdapter, MUTEX_TX_DATA_DONE_QUE); +#else + QUE_T qDataPort[TX_PORT_NUM]; + P_QUE_T prDataPort[TX_PORT_NUM]; + P_MSDU_INFO_T prMsduInfo; + s32 i; + + KAL_SPIN_LOCK_DECLARATION(); + + for (i = 0; i < TX_PORT_NUM; i++) { + prDataPort[i] = &qDataPort[i]; + QUEUE_INITIALIZE(prDataPort[i]); + } + + /* <1> Move whole list of CMD_INFO to temp queue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); + for (i = 0; i < TX_PORT_NUM; i++) + QUEUE_MOVE_ALL(prDataPort[i], &prAdapter->rTxPQueue[i]); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); + + /* <2> Return sk buffer */ + for (i = 0; i < TX_PORT_NUM; i++) { + nicTxReleaseMsduResource( + prAdapter, + (P_MSDU_INFO_T)QUEUE_GET_HEAD(prDataPort[i])); + nicTxReturnMsduInfo( + prAdapter, + (P_MSDU_INFO_T)QUEUE_GET_HEAD(prDataPort[i])); + } + + /* <3> Clear pending MSDU info in data done queue */ + KAL_ACQUIRE_MUTEX(prAdapter, MUTEX_TX_DATA_DONE_QUE); + while (QUEUE_IS_NOT_EMPTY(&prAdapter->rTxDataDoneQueue)) { + QUEUE_REMOVE_HEAD(&prAdapter->rTxDataDoneQueue, + prMsduInfo, P_MSDU_INFO_T); + + nicTxFreePacket(prAdapter, prMsduInfo, false); + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + } + KAL_RELEASE_MUTEX(prAdapter, MUTEX_TX_DATA_DONE_QUE); +#endif + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to clear all buffer in port 0/1 queue + * \param prAdapter Pointer of Adapter Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void wlanClearRxToOsQueue(IN P_ADAPTER_T prAdapter) +{ + QUE_T rTempRxQue; + P_QUE_T prTempRxQue = &rTempRxQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + + KAL_SPIN_LOCK_DECLARATION(); + QUEUE_INITIALIZE(prTempRxQue); + + /* 4 <1> Move whole list of CMD_INFO to temp queue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_TO_OS_QUE); + QUEUE_MOVE_ALL(prTempRxQue, &prAdapter->rRxQueue); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_TO_OS_QUE); + + /* 4 <2> Remove all skbuf */ + QUEUE_REMOVE_HEAD(prTempRxQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + kalRxIndicateOnePkt( + prAdapter->prGlueInfo, + (void *)GLUE_GET_PKT_DESCRIPTOR(prQueueEntry)); + QUEUE_REMOVE_HEAD(prTempRxQue, prQueueEntry, P_QUE_ENTRY_T); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to clear all commands in pending command queue + * \param prAdapter Pointer of Adapter Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void wlanClearPendingCommandQueue(IN P_ADAPTER_T prAdapter) +{ + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + KAL_SPIN_LOCK_DECLARATION(); + QUEUE_INITIALIZE(prTempCmdQue); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + QUEUE_MOVE_ALL(prTempCmdQue, &prAdapter->rPendingCmdQueue); + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->pfCmdTimeoutHandler) { + prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo); + } else { + wlanReleaseCommand(prAdapter, prCmdInfo, + TX_RESULT_QUEUE_CLEARANCE); + } + + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } +} + +void wlanReleaseCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + wlanReleaseCommandEx(prAdapter, prCmdInfo, rTxDoneStatus, true); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will release thd CMD_INFO upon its attribution + * + * \param prAdapter Pointer of Adapter Data Structure + * \param prCmdInfo Pointer of CMD_INFO_T + * \param rTxDoneStatus Tx done status + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void wlanReleaseCommandEx(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus, + IN u8 fgIsNeedHandler) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prTxCtrl = &prAdapter->rTxCtrl; + + switch (prCmdInfo->eCmdType) { + case COMMAND_TYPE_GENERAL_IOCTL: + case COMMAND_TYPE_NETWORK_IOCTL: + DBGLOG(INIT, INFO, "Free CMD: ID[0x%x] SeqNum[%u] OID[%u]\n", + prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum, + prCmdInfo->fgIsOid); + + if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, + WLAN_STATUS_FAILURE); + } + break; + + case COMMAND_TYPE_SECURITY_FRAME: + case COMMAND_TYPE_MANAGEMENT_FRAME: + prMsduInfo = prCmdInfo->prMsduInfo; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { + kalSecurityFrameSendComplete(prAdapter->prGlueInfo, + prCmdInfo->prPacket, + WLAN_STATUS_FAILURE); + /* Avoid skb multiple free */ + prMsduInfo->prPacket = NULL; + } + + DBGLOG(INIT, + INFO, + "Free %s Frame: BSS[%u] WIDX:PID[%u:%u] SEQ[%u] STA[%u] RSP[%u] CMDSeq[%u]\n", + prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME ? + "SEC" : + "MGMT", + prMsduInfo->ucBssIndex, + prMsduInfo->ucWlanIndex, + prMsduInfo->ucPID, + prMsduInfo->ucTxSeqNum, + prMsduInfo->ucStaRecIndex, + prMsduInfo->pfTxDoneHandler ? true : false, + prCmdInfo->ucCmdSeqNum); + + /* invoke callbacks */ + if (fgIsNeedHandler) { + if (prMsduInfo->pfTxDoneHandler != NULL) { + prMsduInfo->pfTxDoneHandler( + prAdapter, prMsduInfo, rTxDoneStatus); + } + } else { + nicDumpMsduInfo(prMsduInfo); + } + + if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { + GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); + } + + cnmMgtPktFree(prAdapter, prMsduInfo); + break; + + default: + ASSERT(0); + break; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will search the CMD Queue to look for the pending OID + * and compelete it immediately when system request a reset. + * + * \param prAdapter ointer of Adapter Data Structure + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void wlanReleasePendingOid(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("wlanReleasePendingOid"); + + ASSERT(prAdapter); + + if (prAdapter->prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + DBGLOG(OID, TRACE, "%s stopped! Releasing pending OIDs ..\n", + KAL_GET_CURRENT_THREAD_NAME()); + } else { + DBGLOG(OID, ERROR, "OID Timeout! Releasing pending OIDs ..\n"); + prAdapter->ucOidTimeoutCount++; + + if (prAdapter->ucOidTimeoutCount >= WLAN_OID_NO_ACK_THRESHOLD) { + if (!prAdapter->fgIsChipNoAck) { + DBGLOG(INIT, + WARN, + "No response from chip for %u times, set NoAck flag!\n", + prAdapter->ucOidTimeoutCount); + } + + prAdapter->fgIsChipNoAck = true; + } + set_bit(GLUE_FLAG_HIF_PRT_HIF_DBG_INFO_BIT, + &(prAdapter->prGlueInfo->ulFlag)); + } + + do { + KAL_ACQUIRE_MUTEX(prAdapter, MUTEX_TX_CMD_CLEAR); + + /* 1: Clear Pending OID in prAdapter->rPendingCmdQueue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + prCmdQue = &prAdapter->rPendingCmdQueue; + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->fgIsOid) { + DBGLOG(OID, + INFO, + "Clear pending OID CMD ID[0x%02X] SEQ[%u] buf[0x%p]\n", + prCmdInfo->ucCID, + prCmdInfo->ucCmdSeqNum, + prCmdInfo->pucInfoBuffer); + + if (prCmdInfo->pfCmdTimeoutHandler) { + prCmdInfo->pfCmdTimeoutHandler( + prAdapter, prCmdInfo); + } else { + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_FAILURE); + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, + SPIN_LOCK_CMD_PENDING); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + SPIN_LOCK_CMD_PENDING); + + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } else { + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, + P_QUE_ENTRY_T); + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + /* Clear pending OID in main_thread to hif_thread command queue + */ + wlanClearTxOidCommand(prAdapter); + + /* 2: Clear pending OID in glue layer command queue */ + kalOidCmdClearance(prAdapter->prGlueInfo); + + KAL_RELEASE_MUTEX(prAdapter, MUTEX_TX_CMD_CLEAR); + } while (false); + + DBGLOG(OID, INFO, "End of Release pending OID\n"); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Return the indicated packet buffer and reallocate one to the RFB + * + * \param prAdapter Pointer of Adapter Data Structure + * \param pvPacket Pointer of returned packet + * + * \retval WLAN_STATUS_SUCCESS: Success + * \retval WLAN_STATUS_FAILURE: Failed + */ +/*----------------------------------------------------------------------------*/ +void wlanReturnPacketDelaySetupTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = NULL; + + KAL_SPIN_LOCK_DECLARATION(); + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_QUE_T prQueList; + + ASSERT(prAdapter); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + prQueList = &prRxCtrl->rIndicatedRfbList; + DBGLOG(RX, WARN, "%s: IndicatedRfbList num = %u\n", __func__, + prQueList->u4NumElem); + + while (QUEUE_IS_NOT_EMPTY(&prRxCtrl->rIndicatedRfbList)) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rIndicatedRfbList, prSwRfb, + P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + + status = nicRxSetupRFB(prAdapter, prSwRfb); + nicRxReturnRFB(prAdapter, prSwRfb); + + if (status != WLAN_STATUS_SUCCESS) { + break; + } + } + + if (status != WLAN_STATUS_SUCCESS) { + DBGLOG(RX, WARN, "Restart ReturnIndicatedRfb Timer (%u)\n", + RX_RETURN_INDICATED_RFB_TIMEOUT_SEC); + /* restart timer */ + cnmTimerStartTimer( + prAdapter, &prAdapter->rPacketDelaySetupTimer, + SEC_TO_MSEC(RX_RETURN_INDICATED_RFB_TIMEOUT_SEC)); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Return the packet buffer and reallocate one to the RFB + * + * \param prAdapter Pointer of Adapter Data Structure + * \param pvPacket Pointer of returned packet + * + * \retval WLAN_STATUS_SUCCESS: Success + * \retval WLAN_STATUS_FAILURE: Failed + */ +/*----------------------------------------------------------------------------*/ +void wlanReturnPacket(IN P_ADAPTER_T prAdapter, IN void *pvPacket) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = NULL; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("wlanReturnPacket"); + + ASSERT(prAdapter); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + if (pvPacket) { + kalPacketFree(prAdapter->prGlueInfo, pvPacket); + RX_ADD_CNT(prRxCtrl, RX_DATA_RETURNED_COUNT, 1); +#if CFG_NATIVE_802_11 + if (GLUE_TEST_FLAG(prAdapter->prGlueInfo, GLUE_FLAG_HALT)) { + /*Todo:: nothing */ + /*Todo:: nothing */ + } +#endif + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rIndicatedRfbList, prSwRfb, P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + if (!prSwRfb) { + DBGLOG(RX, WARN, "No free SwRfb!\n"); + return; + } + + if (nicRxSetupRFB(prAdapter, prSwRfb)) { + DBGLOG(RX, WARN, "Cannot allocate packet buffer for SwRfb!\n"); + if (!timerPendingTimer(&prAdapter->rPacketDelaySetupTimer)) { + DBGLOG(RX, WARN, + "Start ReturnIndicatedRfb Timer (%u)\n", + RX_RETURN_INDICATED_RFB_TIMEOUT_SEC); + cnmTimerStartTimer( + prAdapter, &prAdapter->rPacketDelaySetupTimer, + SEC_TO_MSEC( + RX_RETURN_INDICATED_RFB_TIMEOUT_SEC)); + } + } + nicRxReturnRFB(prAdapter, prSwRfb); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is a required function that returns information about + * the capabilities and status of the driver and/or its network adapter. + * + * \param[IN] prAdapter Pointer to the Adapter structure. + * \param[IN] pfnOidQryHandler Function pointer for the OID query handler. + * \param[IN] pvInfoBuf Points to a buffer for return the query + * information. \param[IN] u4QueryBufferLen Specifies the number of bytes at + * pvInfoBuf. \param[OUT] pu4QueryInfoLen Points to the number of bytes it + * written or is needed. + * + * \retval WLAN_STATUS_xxx Different WLAN_STATUS code returned by different + * handlers. + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanQueryInformation(IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfnOidQryHandler, + IN void *pvInfoBuf, IN u32 u4InfoBufLen, + OUT u32 *pu4QryInfoLen) +{ + WLAN_STATUS status = WLAN_STATUS_FAILURE; + + ASSERT(prAdapter); + ASSERT(pu4QryInfoLen); + + /* ignore any OID request after connected, under PS current measurement + * mode */ + if (prAdapter->u4PsCurrentMeasureEn && + (prAdapter->prGlueInfo->eParamMediaStateIndicated == + PARAM_MEDIA_STATE_CONNECTED)) { + /* note: return WLAN_STATUS_FAILURE or + * WLAN_STATUS_SUCCESS for blocking OIDs during current + * measurement ?? + */ + return WLAN_STATUS_SUCCESS; + } + /* most OID handler will just queue a command packet */ + status = pfnOidQryHandler(prAdapter, pvInfoBuf, u4InfoBufLen, + pu4QryInfoLen); + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is a required function that allows bound protocol + * drivers, or NDIS, to request changes in the state information that the + * miniport maintains for particular object identifiers, such as changes in + * multicast addresses. + * + * \param[IN] prAdapter Pointer to the Glue info structure. + * \param[IN] pfnOidSetHandler Points to the OID set handlers. + * \param[IN] pvInfoBuf Points to a buffer containing the OID-specific data + * for the set. \param[IN] u4InfoBufLen Specifies the number of bytes at + * prSetBuffer. \param[OUT] pu4SetInfoLen Points to the number of bytes it read + * or is needed. + * + * \retval WLAN_STATUS_xxx Different WLAN_STATUS code returned by different + * handlers. + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanSetInformation(IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfnOidSetHandler, IN void *pvInfoBuf, + IN u32 u4InfoBufLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS status = WLAN_STATUS_FAILURE; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + /* ignore any OID request after connected, under PS current measurement + * mode */ + if (prAdapter->u4PsCurrentMeasureEn && + (prAdapter->prGlueInfo->eParamMediaStateIndicated == + PARAM_MEDIA_STATE_CONNECTED)) { + /* note: return WLAN_STATUS_FAILURE or WLAN_STATUS_SUCCESS + * for blocking OIDs during current measurement ?? + */ + return WLAN_STATUS_SUCCESS; + } + /* most OID handler will just queue a command packet + * for power state transition OIDs, handler will acquire power control + * by itself + */ + status = pfnOidSetHandler(prAdapter, pvInfoBuf, u4InfoBufLen, + pu4SetInfoLen); + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is called to set RX filter to Promiscuous Mode. + * + * \param[IN] prAdapter Pointer to the Adapter structure. + * \param[IN] fgEnablePromiscuousMode Enable/ disable RX Promiscuous Mode. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void wlanSetPromiscuousMode(IN P_ADAPTER_T prAdapter, + IN u8 fgEnablePromiscuousMode) +{ + ASSERT(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is called to set RX filter to allow to receive + * broadcast address packets. + * + * \param[IN] prAdapter Pointer to the Adapter structure. + * \param[IN] fgEnableBroadcast Enable/ disable broadcast packet to be received. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void wlanRxSetBroadcast(IN P_ADAPTER_T prAdapter, IN u8 fgEnableBroadcast) +{ + ASSERT(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is called to send out CMD_ID_DUMMY command packet + * + * \param[IN] prAdapter Pointer to the Adapter structure. + * + * \return WLAN_STATUS_SUCCESS + * \return WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanSendDummyCmd(IN P_ADAPTER_T prAdapter, IN u8 fgIsReqTxRsrc) +{ + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = (u16)CMD_HDR_SIZE; + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->pfCmdTimeoutHandler = NULL; + prCmdInfo->fgIsOid = true; + prCmdInfo->ucCID = CMD_ID_DUMMY_RSV; + prCmdInfo->fgSetQuery = true; + prCmdInfo->fgNeedResp = false; + prCmdInfo->ucCmdSeqNum = 0; + prCmdInfo->u4SetInfoLen = 0; + + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + if (fgIsReqTxRsrc) { + if (wlanSendCommand(prAdapter, prCmdInfo) != + WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, + "Fail to transmit CMD_ID_DUMMY command\n"); + status = WLAN_STATUS_FAILURE; + } + } else { + if (nicTxCmd(prAdapter, prCmdInfo, TC4_INDEX) != + WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, + "Fail to transmit CMD_ID_DUMMY command\n"); + status = WLAN_STATUS_FAILURE; + } + } + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is called to send out CMD_NIC_POWER_CTRL command packet + * + * \param[IN] prAdapter Pointer to the Adapter structure. + * \param[IN] ucPowerMode refer to CMD/EVENT document + * + * \return WLAN_STATUS_SUCCESS + * \return WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanSendNicPowerCtrlCmd(IN P_ADAPTER_T prAdapter, + IN u8 ucPowerMode) +{ + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + u8 ucTC, ucCmdSeqNum; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + + /* 1. Prepare CMD */ + prCmdInfo = cmdBufAllocateCmdInfo( + prAdapter, (CMD_HDR_SIZE + sizeof(CMD_NIC_POWER_CTRL))); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + /* 2.1 increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); + + /* 2.2 Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = + (u16)(CMD_HDR_SIZE + sizeof(CMD_NIC_POWER_CTRL)); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->pfCmdTimeoutHandler = NULL; + prCmdInfo->fgIsOid = true; + prCmdInfo->ucCID = CMD_ID_NIC_POWER_CTRL; + prCmdInfo->fgSetQuery = true; + prCmdInfo->fgNeedResp = false; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_NIC_POWER_CTRL); + + /* 2.3 Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + kalMemZero(prWifiCmd->aucBuffer, sizeof(CMD_NIC_POWER_CTRL)); + ((P_CMD_NIC_POWER_CTRL)(prWifiCmd->aucBuffer))->ucPowerMode = + ucPowerMode; + + /* 3. Issue CMD for entering specific power mode */ + ucTC = TC4_INDEX; + + while (1) { + /* 3.0 Removal check */ + if (kalIsCardRemoved(prAdapter->prGlueInfo) == true || + fgIsBusAccessFailed == true) { + status = WLAN_STATUS_FAILURE; + break; + } + /* 3.1 Acquire TX Resource */ + if (nicTxAcquireResource(prAdapter, ucTC, true) == + WLAN_STATUS_RESOURCES) { + if (nicTxPollingResource(prAdapter, ucTC) != + WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, + ERROR, + "Fail to get TX resource return within timeout\n"); + status = WLAN_STATUS_FAILURE; + prAdapter->fgIsChipNoAck = true; + break; + } + continue; + } + break; + } + ; + + /* 3.2 Send CMD Info Packet */ + if (nicTxCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, + "Fail to transmit CMD_NIC_POWER_CTRL command\n"); + status = WLAN_STATUS_FAILURE; + } + + /* 4. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + /* 5. Add flag */ + if (ucPowerMode == 1) { + prAdapter->fgIsEnterD3ReqIssued = true; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is called to set g_fgKeepFullPwr flag in firmware + * + * \param[IN] prAdapter Pointer to the Adapter structure. + * \param[IN] fgEnable Boolean of enable + * True: wlan stays awake and keeps working in full + * power state False: wlan may go to sleep and consumes less power. + * + * \return WLAN_STATUS_SUCCESS + * \return WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanKeepFullPwr(IN P_ADAPTER_T prAdapter, IN u8 fgEnable) +{ + struct CMD_KEEP_FULL_PWR_T rCmdKeepFullPwr; + + kalMemZero(&rCmdKeepFullPwr, sizeof(struct CMD_KEEP_FULL_PWR_T)); + ASSERT(prAdapter); + + rCmdKeepFullPwr.ucEnable = fgEnable; + DBGLOG(HAL, STATE, "KeepFullPwr: %d\n", rCmdKeepFullPwr.ucEnable); + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_KEEP_FULL_PWR, true, false, + false, NULL, NULL, + sizeof(struct CMD_KEEP_FULL_PWR_T), + (u8 *)&rCmdKeepFullPwr, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is called to check if it is RF test mode and + * the OID is allowed to be called or not + * + * \param[IN] prAdapter Pointer to the Adapter structure. + * \param[IN] fgEnableBroadcast Enable/ disable broadcast packet to be received. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +u8 wlanIsHandlerAllowedInRFTest(IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN u8 fgSetInfo) +{ + PFN_OID_HANDLER_FUNC *apfnOidHandlerAllowedInRFTest; + u32 i; + u32 u4NumOfElem; + + if (fgSetInfo) { + apfnOidHandlerAllowedInRFTest = + apfnOidSetHandlerAllowedInRFTest; + u4NumOfElem = sizeof(apfnOidSetHandlerAllowedInRFTest) / + sizeof(PFN_OID_HANDLER_FUNC); + } else { + apfnOidHandlerAllowedInRFTest = + apfnOidQueryHandlerAllowedInRFTest; + u4NumOfElem = sizeof(apfnOidQueryHandlerAllowedInRFTest) / + sizeof(PFN_OID_HANDLER_FUNC); + } + + for (i = 0; i < u4NumOfElem; i++) + if (apfnOidHandlerAllowedInRFTest[i] == pfnOidHandler) { + return true; + } + + return false; +} + +#if CFG_ENABLE_FW_DOWNLOAD +void wlanImageSectionGetFwInfo(IN P_ADAPTER_T prAdapter, + IN void *pvFwImageMapFile, + IN u32 u4FwImageFileLength, IN u8 ucTotSecNum, + IN u8 ucCurSecNum, IN ENUM_IMG_DL_IDX_T eDlIdx, + OUT u32 *pu4StartOffset, OUT u32 *pu4Addr, + OUT u32 *pu4Len, OUT u32 *pu4DataMode) +{ + u32 u4DataMode = 0; + fw_image_tailer_t *prFwHead; + tailer_format_t *prTailer; + + prFwHead = + (fw_image_tailer_t *)(pvFwImageMapFile + u4FwImageFileLength - + sizeof(fw_image_tailer_t)); + if (ucTotSecNum == 1) { + prTailer = &prFwHead->dlm_info; + }else{ + prTailer = &prFwHead->ilm_info; + } + + prTailer = &prTailer[ucCurSecNum]; + + *pu4StartOffset = 0; + *pu4Addr = prTailer->addr; + *pu4Len = (prTailer->len + LEN_4_BYTE_CRC); + if (prTailer->feature_set & DOWNLOAD_CONFIG_ENCRYPTION_MODE) { + u4DataMode |= DOWNLOAD_CONFIG_RESET_OPTION; + u4DataMode |= (prTailer->feature_set & + DOWNLOAD_CONFIG_KEY_INDEX_MASK); + u4DataMode |= DOWNLOAD_CONFIG_ENCRYPTION_MODE; + } + + if (eDlIdx == IMG_DL_IDX_CR4_FW) { + u4DataMode |= DOWNLOAD_CONFIG_WORKING_PDA_OPTION; + } + +#if CFG_ENABLE_FW_DOWNLOAD_ACK + u4DataMode |= DOWNLOAD_CONFIG_ACK_OPTION; /* ACK needed */ +#endif + + *pu4DataMode = u4DataMode; + + /* Dump image information */ + if (ucCurSecNum == 0) { + DBGLOG(INIT, INFO, + "%s INFO: chip_info[%u:E%u] feature[0x%02X]\n", + (eDlIdx == IMG_DL_IDX_N9_FW) ? "N9" : "CR4", + prTailer->chip_info, prTailer->eco_code + 1, + prTailer->feature_set); + DBGLOG(INIT, INFO, "date[%s] version[%c%c%c%c%c%c%c%c%c%c]\n", + prTailer->ram_built_date, prTailer->ram_version[0], + prTailer->ram_version[1], prTailer->ram_version[2], + prTailer->ram_version[3], prTailer->ram_version[4], + prTailer->ram_version[5], prTailer->ram_version[6], + prTailer->ram_version[7], prTailer->ram_version[8], + prTailer->ram_version[9]); + } + + /* Backup to FW version info */ + if (eDlIdx == IMG_DL_IDX_N9_FW) { + kalMemCopy(&prAdapter->rVerInfo.rN9tailer, prTailer, + sizeof(tailer_format_t)); + } else { + kalMemCopy(&prAdapter->rVerInfo.rCR4tailer, prTailer, + sizeof(tailer_format_t)); + } +} +#if CFG_SUPPORT_COMPRESSION_FW_OPTION +void wlanImageSectionGetCompressFwInfo( + IN P_ADAPTER_T prAdapter, IN void *pvFwImageMapFile, + IN u32 u4FwImageFileLength, IN u8 ucTotSecNum, IN u8 ucCurSecNum, + IN ENUM_IMG_DL_IDX_T eDlIdx, OUT u32 *pu4StartOffset, OUT u32 *pu4Addr, + OUT u32 *pu4Len, OUT u32 *pu4DataMode, OUT u32 *pu4BlockSize, + OUT u32 *pu4CRC, OUT u32 *pu4UncompressedLength) +{ + u32 u4DataMode = 0; + fw_image_tailer_t_2 *prFwHead; + tailer_format_t_2 *prTailer; + + prFwHead = + (fw_image_tailer_t_2 *)(pvFwImageMapFile + u4FwImageFileLength - + sizeof(fw_image_tailer_t_2)); + if (ucTotSecNum == 1) { + prTailer = &prFwHead->dlm_info; + }else{ + prTailer = &prFwHead->ilm_info; + } + + prTailer = &prTailer[ucCurSecNum]; + + *pu4StartOffset = 0; + *pu4Addr = prTailer->addr; + *pu4Len = (prTailer->len); + *pu4BlockSize = (prTailer->block_size); + *pu4CRC = (prTailer->crc); + *pu4UncompressedLength = (prTailer->real_size); + if (prTailer->feature_set & DOWNLOAD_CONFIG_ENCRYPTION_MODE) { + u4DataMode |= DOWNLOAD_CONFIG_RESET_OPTION; + u4DataMode |= (prTailer->feature_set & + DOWNLOAD_CONFIG_KEY_INDEX_MASK); + u4DataMode |= DOWNLOAD_CONFIG_ENCRYPTION_MODE; + } + if (eDlIdx == IMG_DL_IDX_CR4_FW) { + u4DataMode |= DOWNLOAD_CONFIG_WORKING_PDA_OPTION; + } + +#if CFG_ENABLE_FW_DOWNLOAD_ACK + u4DataMode |= DOWNLOAD_CONFIG_ACK_OPTION; /* ACK needed */ +#endif + + *pu4DataMode = u4DataMode; + + /* Dump image information */ + if (ucCurSecNum == 0) { + DBGLOG(INIT, INFO, + "%s INFO: chip_info[%u:E%u] feature[0x%02X]\n", + (eDlIdx == IMG_DL_IDX_N9_FW) ? "N9" : "CR4", + prTailer->chip_info, prTailer->eco_code, + prTailer->feature_set); + DBGLOG(INIT, INFO, "date[%s] version[%c%c%c%c%c%c%c%c%c%c]\n", + prTailer->ram_built_date, prTailer->ram_version[0], + prTailer->ram_version[1], prTailer->ram_version[2], + prTailer->ram_version[3], prTailer->ram_version[4], + prTailer->ram_version[5], prTailer->ram_version[6], + prTailer->ram_version[7], prTailer->ram_version[8], + prTailer->ram_version[9]); + } + /* Backup to FW version info */ + if (eDlIdx == IMG_DL_IDX_N9_FW) { + kalMemCopy(&prAdapter->rVerInfo.rN9Compressedtailer, prTailer, + sizeof(tailer_format_t_2)); + prAdapter->rVerInfo.fgIsN9CompressedFW = true; + } else { + kalMemCopy(&prAdapter->rVerInfo.rCR4Compressedtailer, prTailer, + sizeof(tailer_format_t_2)); + prAdapter->rVerInfo.fgIsCR4CompressedFW = true; + } +} +#endif +void wlanImageSectionGetPatchInfo(IN P_ADAPTER_T prAdapter, + IN void *pvFwImageMapFile, + IN u32 u4FwImageFileLength, IN u8 ucTotSecNum, + IN u8 ucCurSecNum, + IN ENUM_IMG_DL_IDX_T eDlIdx, + OUT u32 *pu4StartOffset, OUT u32 *pu4Addr, + OUT u32 *pu4Len, OUT u32 *pu4DataMode) +{ + P_PATCH_FORMAT_T prPatchFormat; + u32 u4DataMode = 0; + u8 aucBuffer[32]; + struct chip_info *prChipInfo = prAdapter->chip_info; + + prPatchFormat = (P_PATCH_FORMAT_T)pvFwImageMapFile; + + *pu4StartOffset = offsetof(PATCH_FORMAT_T, ucPatchImage); + *pu4Addr = prChipInfo->patch_addr; + *pu4Len = u4FwImageFileLength - offsetof(PATCH_FORMAT_T, ucPatchImage); + +#if CFG_ENABLE_FW_DOWNLOAD_ACK + u4DataMode |= DOWNLOAD_CONFIG_ACK_OPTION; /* ACK needed */ +#endif + *pu4DataMode = u4DataMode; + + /* Dump image information */ + kalStrnCpy(aucBuffer, prPatchFormat->aucPlatform, 4); + aucBuffer[4] = '\0'; + DBGLOG(INIT, INFO, + "PATCH INFO: platform[%s] HW/SW ver[0x%04X] ver[0x%04X]\n", + aucBuffer, prPatchFormat->u4SwHwVersion, + prPatchFormat->u4PatchVersion); + + kalStrnCpy(aucBuffer, prPatchFormat->aucBuildDate, 16); + aucBuffer[16] = '\0'; + DBGLOG(INIT, INFO, "date[%s]\n", aucBuffer); + + /* Backup to FW version info */ + kalMemCopy(&prAdapter->rVerInfo.rPatchHeader, prPatchFormat, + sizeof(PATCH_FORMAT_T)); +} + +void wlanImageSectionGetInfo(IN P_ADAPTER_T prAdapter, + IN void *pvFwImageMapFile, + IN u32 u4FwImageFileLength, IN u8 ucTotSecNum, + IN u8 ucCurSecNum, IN ENUM_IMG_DL_IDX_T eDlIdx, + OUT u32 *pu4StartOffset, OUT u32 *pu4Addr, + OUT u32 *pu4Len, OUT u32 *pu4DataMode) +{ + if (eDlIdx == IMG_DL_IDX_PATCH) { + wlanImageSectionGetPatchInfo(prAdapter, pvFwImageMapFile, + u4FwImageFileLength, ucTotSecNum, + ucCurSecNum, eDlIdx, + pu4StartOffset, pu4Addr, pu4Len, + pu4DataMode); + } else { + wlanImageSectionGetFwInfo(prAdapter, pvFwImageMapFile, + u4FwImageFileLength, ucTotSecNum, + ucCurSecNum, eDlIdx, pu4StartOffset, + pu4Addr, pu4Len, pu4DataMode); + } +} +#if CFG_SUPPORT_COMPRESSION_FW_OPTION + +u8 wlanImageSectionCheckFwCompressInfo(IN P_ADAPTER_T prAdapter, + IN void *pvFwImageMapFile, + IN u32 u4FwImageFileLength, + IN ENUM_IMG_DL_IDX_T eDlIdx) +{ + u8 ucCompression; + fw_image_tailer_check *prCheckInfo; + + if (eDlIdx == IMG_DL_IDX_PATCH) { + return false; + } + + prCheckInfo = (fw_image_tailer_check *)(pvFwImageMapFile + + u4FwImageFileLength - + sizeof(fw_image_tailer_check)); + DBGLOG(INIT, INFO, "feature_set %d\n", prCheckInfo->feature_set); + ucCompression = + (u8)((prCheckInfo->feature_set & COMPRESSION_OPTION_MASK) >> + COMPRESSION_OPTION_OFFSET); + DBGLOG(INIT, INFO, "Compressed Check INFORMATION %d\n", ucCompression); + if (ucCompression == 1) { + DBGLOG(INIT, INFO, "Compressed FW\n"); + return true; + } + return false; +} + +WLAN_STATUS +wlanImageSectionDownloadStage( + IN P_ADAPTER_T prAdapter, IN void *pvFwImageMapFile, + IN u32 u4FwImageFileLength, IN u8 ucSectionNumber, + IN ENUM_IMG_DL_IDX_T eDlIdx, OUT u8 *pucIsCompressed, + OUT P_INIT_CMD_WIFI_DECOMPRESSION_START prFwImageInFo) +{ + u32 u4ImgSecSize; + u32 j, i; + s32 i4TotalLen; + u32 u4FileOffset = 0; + u32 u4StartOffset = 0; + u32 u4DataMode = 0; + u32 u4Addr, u4Len, u4BlockSize, u4CRC, u4UnCompressedLength; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + u8 *pucSecBuf, *pucStartPtr; + u32 u4offset = 0, u4ChunkSize; + /* 3a. parse file header for decision of divided firmware download or + * not */ + for (i = 0; i < ucSectionNumber; ++i) { + if (wlanImageSectionCheckFwCompressInfo( + prAdapter, pvFwImageMapFile, u4FwImageFileLength, + eDlIdx) == true) { + wlanImageSectionGetCompressFwInfo( + prAdapter, pvFwImageMapFile, + u4FwImageFileLength, ucSectionNumber, i, eDlIdx, + &u4StartOffset, &u4Addr, &u4Len, &u4DataMode, + &u4BlockSize, &u4CRC, &u4UnCompressedLength); + u4offset = 0; + if (i == 0) { + prFwImageInFo->u4BlockSize = u4BlockSize; + prFwImageInFo->u4Region1Address = u4Addr; + prFwImageInFo->u4Region1CRC = u4CRC; + prFwImageInFo->u4Region1length = + u4UnCompressedLength; + } else { + prFwImageInFo->u4Region2Address = u4Addr; + prFwImageInFo->u4Region2CRC = u4CRC; + prFwImageInFo->u4Region2length = + u4UnCompressedLength; + } + i4TotalLen = u4Len; + DBGLOG(INIT, + INFO, + "DL Offset[%u] addr[0x%08x] len[%u] datamode[0x%08x]\n", + u4FileOffset, + u4Addr, + u4Len, + u4DataMode); + DBGLOG(INIT, INFO, "DL BLOCK[%u] COMlen[%u] CRC[%u]\n", + u4BlockSize, u4UnCompressedLength, u4CRC); + pucStartPtr = (u8 *)pvFwImageMapFile + u4StartOffset; + while (i4TotalLen) { + u4ChunkSize = *((unsigned int *)(pucStartPtr + + u4FileOffset)); + u4FileOffset += 4; + DBGLOG(INIT, INFO, + "Downloaded Length %d! Addr %x\n", + i4TotalLen, u4Addr + u4offset); + DBGLOG(INIT, INFO, "u4ChunkSize Length %d!\n", + u4ChunkSize); + if (wlanImageSectionConfig( + prAdapter, (u4Addr + u4offset), + u4ChunkSize, u4DataMode, + eDlIdx) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, + ERROR, + "Firmware download configuration failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } + for (j = 0; j < u4ChunkSize; + j += CMD_PKT_SIZE_FOR_IMAGE) { + if (j + CMD_PKT_SIZE_FOR_IMAGE < + u4ChunkSize) { + u4ImgSecSize = + CMD_PKT_SIZE_FOR_IMAGE; + } else { + u4ImgSecSize = u4ChunkSize - j; + } + pucSecBuf = (u8 *)pucStartPtr + + u4FileOffset + j; + if (wlanImageSectionDownload( + prAdapter, u4ImgSecSize, + pucSecBuf) != + WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, + ERROR, + "Firmware scatter download failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } + } + /* escape from loop if any pending error occurs + */ + if (u4Status == WLAN_STATUS_FAILURE) { + break; + } + i4TotalLen -= u4ChunkSize; + u4offset += u4BlockSize; + u4FileOffset += u4ChunkSize; + if (i4TotalLen < 0) { + DBGLOG(INIT, + ERROR, + "Firmware scatter download failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } + } + *pucIsCompressed = true; + } else { + wlanImageSectionGetInfo(prAdapter, pvFwImageMapFile, + u4FwImageFileLength, + ucSectionNumber, i, eDlIdx, + &u4StartOffset, &u4Addr, &u4Len, + &u4DataMode); + pucStartPtr = (u8 *)pvFwImageMapFile + u4StartOffset; + + DBGLOG(INIT, + INFO, + "DL Offset[%u] addr[0x%08x] len[%u] datamode[0x%08x]\n", + u4FileOffset, + u4Addr, + u4Len, + u4DataMode); + + if (wlanImageSectionConfig(prAdapter, u4Addr, u4Len, + u4DataMode, eDlIdx) != + WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, + ERROR, + "Firmware download configuration failed!\n"); + + u4Status = WLAN_STATUS_FAILURE; + break; + } + for (j = 0; j < u4Len; j += CMD_PKT_SIZE_FOR_IMAGE) { + if (j + CMD_PKT_SIZE_FOR_IMAGE < u4Len) { + u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; + }else{ + u4ImgSecSize = u4Len - j; + } + + pucSecBuf = + (u8 *)pucStartPtr + u4FileOffset + j; + if (wlanImageSectionDownload( + prAdapter, u4ImgSecSize, + pucSecBuf) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, + ERROR, + "Firmware scatter download failed!\n"); + u4Status = WLAN_STATUS_FAILURE; + break; + } + } + + /* escape from loop if any pending error occurs */ + if (u4Status == WLAN_STATUS_FAILURE) { + break; + } + u4FileOffset += u4Len; + *pucIsCompressed = false; + } + } + return u4Status; +} +#else +WLAN_STATUS wlanImageSectionDownloadStage(IN P_ADAPTER_T prAdapter, + IN void *pvFwImageMapFile, + IN u32 u4FwImageFileLength, + IN u8 ucSectionNumber, + IN ENUM_IMG_DL_IDX_T eDlIdx) +{ + u32 u4ImgSecSize; + u32 j, i; + u32 u4FileOffset = 0; + u32 u4StartOffset = 0; + u32 u4DataMode = 0; + u32 u4Addr, u4Len; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + u8 *pucSecBuf, *pucStartPtr; + + /* 3a. parse file header for decision of divided firmware download or + * not */ + for (i = 0; i < ucSectionNumber; ++i) { + wlanImageSectionGetInfo(prAdapter, pvFwImageMapFile, + u4FwImageFileLength, ucSectionNumber, i, + eDlIdx, &u4StartOffset, &u4Addr, &u4Len, + &u4DataMode); + + pucStartPtr = (u8 *)pvFwImageMapFile + u4StartOffset; + + DBGLOG(INIT, INFO, + "DL Offset[%u] addr[0x%08x] len[%u] datamode[0x%08x]\n", + u4FileOffset, u4Addr, u4Len, u4DataMode); + + if (wlanImageSectionConfig(prAdapter, u4Addr, u4Len, u4DataMode, + eDlIdx) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, + "Firmware download configuration failed!\n"); + + u4Status = WLAN_STATUS_FAILURE; + break; + } + + for (j = 0; j < u4Len; j += CMD_PKT_SIZE_FOR_IMAGE) { + if (j + CMD_PKT_SIZE_FOR_IMAGE < u4Len) { + u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE; + }else{ + u4ImgSecSize = u4Len - j; + } + + pucSecBuf = (u8 *)pucStartPtr + u4FileOffset + j; + if (wlanImageSectionDownload(prAdapter, u4ImgSecSize, + pucSecBuf) != + WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, + "Firmware scatter download failed!\n"); + + u4Status = WLAN_STATUS_FAILURE; + break; + } + kalMdelay(1); + } + + /* escape from loop if any pending error occurs */ + if (u4Status == WLAN_STATUS_FAILURE) { + break; + } + + u4FileOffset += u4Len; + } + + return u4Status; +} +#endif +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to confirm the status of + * previously patch semaphore control + * + * @param prAdapter Pointer to the Adapter structure. + * ucCmdSeqNum Sequence number of previous firmware scatter + * + * @return WLAN_STATUS_SUCCESS + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanPatchRecvSemaResp(IN P_ADAPTER_T prAdapter, IN u8 ucCmdSeqNum, OUT u8 *pucPatchStatus) +{ + u8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + + sizeof(INIT_EVENT_CMD_RESULT)]; + P_INIT_HIF_RX_HEADER_T prInitHifRxHeader; + P_INIT_EVENT_CMD_RESULT prEventCmdResult; + u32 u4RxPktLength; + + ASSERT(prAdapter); + + if (kalIsCardRemoved(prAdapter->prGlueInfo) == true || + fgIsBusAccessFailed == true) { + return WLAN_STATUS_FAILURE; + } + + if (nicRxWaitResponse(prAdapter, 0, aucBuffer, + sizeof(INIT_HIF_RX_HEADER_T) + + sizeof(INIT_EVENT_CMD_RESULT), + &u4RxPktLength) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, WARN, "Wait patch semaphore response fail\n"); + return WLAN_STATUS_FAILURE; + } + + prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T)aucBuffer; + if (prInitHifRxHeader->rInitWifiEvent.ucEID != + INIT_EVENT_ID_PATCH_SEMA_CTRL) { + DBGLOG(INIT, WARN, "Unexpected EVENT ID, get 0x%0x\n", + prInitHifRxHeader->rInitWifiEvent.ucEID); + return WLAN_STATUS_FAILURE; + } + + if (prInitHifRxHeader->rInitWifiEvent.ucSeqNum != ucCmdSeqNum) { + DBGLOG(INIT, WARN, "Unexpected SeqNum %d, %d\n", ucCmdSeqNum, + prInitHifRxHeader->rInitWifiEvent.ucSeqNum); + return WLAN_STATUS_FAILURE; + } + + prEventCmdResult = + (P_INIT_EVENT_CMD_RESULT)(prInitHifRxHeader->rInitWifiEvent + .aucBuffer); + + *pucPatchStatus = prEventCmdResult->ucStatus; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to check the patch semaphore control. + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanPatchSendSemaControl(IN P_ADAPTER_T prAdapter, OUT u8 *pucSeqNum) +{ + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + P_INIT_CMD_PATCH_SEMA_CONTROL prPatchSemaControl; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanImagePatchSemaphoreCheck"); + + /* 1. Allocate CMD Info Packet and its Buffer. */ + prCmdInfo = cmdBufAllocateCmdInfo( + prAdapter, sizeof(INIT_HIF_TX_HEADER_T) + + sizeof(INIT_CMD_PATCH_SEMA_CONTROL)); + + /* DBGLOG(INIT, ERROR, "sizeof INIT_HIF_TX_HEADER_T = %d\n", + * sizeof(INIT_HIF_TX_HEADER_T)); */ + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + + sizeof(INIT_CMD_PATCH_SEMA_CONTROL); + + /* 2. Setup common CMD Info Packet */ + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T)(prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prInitHifTxHeader->u2PQ_ID = INIT_CMD_PQ_ID; + prInitHifTxHeader->ucHeaderFormat = INIT_CMD_PACKET_TYPE_ID; + prInitHifTxHeader->ucPktFt = INIT_PKT_FT_CMD; + + prInitHifTxHeader->rInitWifiCmd.ucCID = + INIT_CMD_ID_PATCH_SEMAPHORE_CONTROL; + prInitHifTxHeader->rInitWifiCmd.ucPktTypeID = + INIT_CMD_PDA_PACKET_TYPE_ID; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = + nicIncreaseCmdSeqNum(prAdapter); + + *pucSeqNum = prInitHifTxHeader->rInitWifiCmd.ucSeqNum; + + /* 3. Setup DOWNLOAD_BUF */ + prPatchSemaControl = (P_INIT_CMD_PATCH_SEMA_CONTROL) + prInitHifTxHeader->rInitWifiCmd.aucBuffer; + kalMemZero(prPatchSemaControl, sizeof(INIT_CMD_PATCH_SEMA_CONTROL)); + prPatchSemaControl->ucGetSemaphore = PATCH_GET_SEMA_CONTROL; + + /* 4. Send FW_Download command */ + if (nicTxInitCmd(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, + "Fail to transmit image download command\n"); + } + /* 5. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; +} + +u8 wlanPatchIsDownloaded(IN P_ADAPTER_T prAdapter) +{ + u8 ucSeqNum, ucPatchStatus; + WLAN_STATUS rStatus; + u32 u4Count; + + ucPatchStatus = PATCH_STATUS_NO_SEMA_NEED_PATCH; + u4Count = 0; + + while (ucPatchStatus == PATCH_STATUS_NO_SEMA_NEED_PATCH) { + if (u4Count) { + kalMdelay(100); + } + + rStatus = wlanPatchSendSemaControl(prAdapter, &ucSeqNum); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, WARN, + "Send patch SEMA control CMD failed!!\n"); + break; + } + + rStatus = wlanPatchRecvSemaResp(prAdapter, ucSeqNum, + &ucPatchStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, WARN, + "Recv patch SEMA control EVT failed!!\n"); + break; + } + + u4Count++; + + if (u4Count > 50) { + DBGLOG(INIT, WARN, "Patch status check timeout!!\n"); + break; + } + } + + if (ucPatchStatus == PATCH_STATUS_NO_NEED_TO_PATCH) { + return true; + }else{ + return false; + } +} + +WLAN_STATUS wlanPatchSendComplete(IN P_ADAPTER_T prAdapter) +{ + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + u8 ucTC, ucCmdSeqNum; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + + /* 1. Allocate CMD Info Packet and its Buffer. */ + prCmdInfo = + cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + kalMemZero(prCmdInfo->pucInfoBuffer, sizeof(INIT_HIF_TX_HEADER_T)); + prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T); + +#if (CFG_USE_TC4_RESOURCE_FOR_INIT_CMD == 1) + /* 2. Always use TC4 (TC4 as CPU) */ + ucTC = TC4_INDEX; +#else + /* 2. Use TC0's resource to send patch finish command. + * Only TC0 is allowed because SDIO HW always reports + * MCU's TXQ_CNT at TXQ0_CNT in CR4 architecutre) + */ + ucTC = TC0_INDEX; +#endif + + /* 3. increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* 4. Setup common CMD Info Packet */ + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T)(prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prInitHifTxHeader->u2PQ_ID = INIT_CMD_PQ_ID; + prInitHifTxHeader->ucPktFt = INIT_PKT_FT_CMD; + + prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_PATCH_FINISH; + prInitHifTxHeader->rInitWifiCmd.ucPktTypeID = INIT_CMD_PACKET_TYPE_ID; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + /* 5. Seend WIFI start command */ + while (1) { + /* 5.1 Acquire TX Resource */ + if (nicTxAcquireResource(prAdapter, ucTC, true) == + WLAN_STATUS_RESOURCES) { + if (nicTxPollingResource(prAdapter, ucTC) != + WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, + ERROR, + "Fail to get TX resource return within timeout\n"); + goto exit; + } + continue; + } + /* 5.2 Send CMD Info Packet */ + if (nicTxInitCmd(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, + "Fail to transmit WIFI start command\n"); + goto exit; + } + + break; + } + ; + + DBGLOG(INIT, INFO, "PATCH FINISH CMD send, waiting for RSP\n"); + + /* kalMdelay(10000); */ + + u4Status = wlanConfigWifiFuncStatus(prAdapter, ucCmdSeqNum); + + if (u4Status != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "PATCH FINISH EVT failed\n"); + }else{ + DBGLOG(INIT, INFO, "PATCH FINISH EVT success!!\n"); + } + +exit: + /* 6. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to configure FWDL parameters + * + * @param prAdapter Pointer to the Adapter structure. + * u4DestAddr Address of destination address + * u4ImgSecSize Length of the firmware block + * fgReset should be set to true if this is the 1st configuration + * + * @return WLAN_STATUS_SUCCESS + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanImageSectionConfig(IN P_ADAPTER_T prAdapter, IN u32 u4DestAddr, + IN u32 u4ImgSecSize, IN u32 u4DataMode, + IN ENUM_IMG_DL_IDX_T eDlIdx) +{ + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + P_INIT_CMD_DOWNLOAD_CONFIG prInitCmdDownloadConfig; + u8 ucTC, ucCmdSeqNum; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanImageSectionConfig"); + + if (u4ImgSecSize == 0) { + return WLAN_STATUS_SUCCESS; + } + + /* 1. Allocate CMD Info Packet and its Buffer. */ + prCmdInfo = cmdBufAllocateCmdInfo( + prAdapter, sizeof(INIT_HIF_TX_HEADER_T) + + sizeof(INIT_CMD_DOWNLOAD_CONFIG)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + prCmdInfo->u2InfoBufLen = + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_CONFIG); + +#if (CFG_USE_TC4_RESOURCE_FOR_INIT_CMD == 1) + /* 2. Use TC4's resource to download image. (TC4 as CPU) */ + ucTC = TC4_INDEX; +#else + /* 2. Use TC0's resource to send init_cmd. + * Only TC0 is allowed because SDIO HW always reports + * MCU's TXQ_CNT at TXQ0_CNT in CR4 architecutre) + */ + ucTC = TC0_INDEX; +#endif + + /* 3. increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* 4. Setup common CMD Info Packet */ + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T)(prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prInitHifTxHeader->u2PQ_ID = INIT_CMD_PQ_ID; + prInitHifTxHeader->ucHeaderFormat = INIT_CMD_PACKET_TYPE_ID; + prInitHifTxHeader->ucPktFt = INIT_PKT_FT_CMD; + + if (eDlIdx == IMG_DL_IDX_PATCH) { + prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_PATCH_START; + } else { + prInitHifTxHeader->rInitWifiCmd.ucCID = + INIT_CMD_ID_DOWNLOAD_CONFIG; + } + + prInitHifTxHeader->rInitWifiCmd.ucPktTypeID = INIT_CMD_PACKET_TYPE_ID; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + /* 5. Setup CMD_DOWNLOAD_CONFIG */ + prInitCmdDownloadConfig = + (P_INIT_CMD_DOWNLOAD_CONFIG)(prInitHifTxHeader->rInitWifiCmd + .aucBuffer); + prInitCmdDownloadConfig->u4Address = u4DestAddr; + prInitCmdDownloadConfig->u4Length = u4ImgSecSize; + prInitCmdDownloadConfig->u4DataMode = u4DataMode; + + /* 6. Send FW_Download command */ + while (1) { + /* 6.1 Acquire TX Resource */ + if (nicTxAcquireResource(prAdapter, ucTC, true) == + WLAN_STATUS_RESOURCES) { + if (nicTxPollingResource(prAdapter, ucTC) != + WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, + ERROR, + "Fail to get TX resource return within timeout\n"); + goto exit; + } + continue; + } + /* 6.2 Send CMD Info Packet */ + if (nicTxInitCmd(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, + "Fail to transmit image download command\n"); + goto exit; + } + + break; + } + ; + +#if CFG_ENABLE_FW_DOWNLOAD_ACK + /* 7. Wait for INIT_EVENT_ID_CMD_RESULT */ + u4Status = wlanImageSectionDownloadStatus(prAdapter, ucCmdSeqNum); +#endif + +exit: + /* 8. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to download FW image. + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanImageSectionDownload(IN P_ADAPTER_T prAdapter, + IN u32 u4ImgSecSize, IN u8 *pucImgSecBuf) +{ + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + ASSERT(pucImgSecBuf); + ASSERT(u4ImgSecSize <= CMD_PKT_SIZE_FOR_IMAGE); + + DEBUGFUNC("wlanImageSectionDownload"); + + if (u4ImgSecSize == 0) { + return WLAN_STATUS_SUCCESS; + } + + /* 1. Allocate CMD Info Packet and its Buffer. */ + prCmdInfo = cmdBufAllocateCmdInfo( + prAdapter, sizeof(INIT_HIF_TX_HEADER_T) + u4ImgSecSize); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + prCmdInfo->u2InfoBufLen = + sizeof(INIT_HIF_TX_HEADER_T) + (u16)u4ImgSecSize; + + /* 2. Setup common CMD Info Packet */ + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T)(prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prInitHifTxHeader->u2PQ_ID = INIT_CMD_PDA_PQ_ID; + prInitHifTxHeader->ucHeaderFormat = INIT_CMD_PDA_PACKET_TYPE_ID; + prInitHifTxHeader->ucPktFt = INIT_PKT_FT_PDA_FWDL; + + prInitHifTxHeader->rInitWifiCmd.ucCID = 0; + prInitHifTxHeader->rInitWifiCmd.ucPktTypeID = + INIT_CMD_PDA_PACKET_TYPE_ID; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = 0; + + /* 3. Setup DOWNLOAD_BUF */ + kalMemCopy(prInitHifTxHeader->rInitWifiCmd.aucBuffer, pucImgSecBuf, + u4ImgSecSize); + + /* 4. Send FW_Download command */ + if (nicTxInitCmd(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, + "Fail to transmit image download command\n"); + } + /* 5. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to confirm previously firmware download is + * done without error + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanImageQueryStatus(IN P_ADAPTER_T prAdapter) +{ + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + u8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + + sizeof(INIT_EVENT_PENDING_ERROR)]; + u32 u4RxPktLength; + P_INIT_HIF_RX_HEADER_T prInitHifRxHeader; + P_INIT_EVENT_PENDING_ERROR prEventPendingError; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + u8 ucTC, ucCmdSeqNum; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanImageQueryStatus"); + + /* 1. Allocate CMD Info Packet and it Buffer. */ + prCmdInfo = + cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + kalMemZero(prCmdInfo->pucInfoBuffer, sizeof(INIT_HIF_TX_HEADER_T)); + prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T); + +#if (CFG_USE_TC4_RESOURCE_FOR_INIT_CMD == 1) + /* 2. Always use TC4 */ + ucTC = TC4_INDEX; +#else + /* 2. Use TC0's resource to send init_cmd + * Only TC0 is allowed because SDIO HW always reports + * CPU's TXQ_CNT at TXQ0_CNT in CR4 architecutre) + */ + ucTC = TC0_INDEX; +#endif + + /* 3. increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* 4. Setup common CMD Info Packet */ + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T)(prCmdInfo->pucInfoBuffer); + + prInitHifTxHeader->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prInitHifTxHeader->u2PQ_ID = INIT_CMD_PQ_ID; + + prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_QUERY_PENDING_ERROR; + prInitHifTxHeader->rInitWifiCmd.ucPktTypeID = INIT_CMD_PACKET_TYPE_ID; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + /* 5. Send command */ + while (1) { + /* 5.1 Acquire TX Resource */ + if (nicTxAcquireResource(prAdapter, ucTC, true) == + WLAN_STATUS_RESOURCES) { + if (nicTxPollingResource(prAdapter, ucTC) != + WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, + ERROR, + "Fail to get TX resource return within timeout\n"); + break; + } + continue; + } + /* 5.2 Send CMD Info Packet */ + if (nicTxInitCmd(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, + "Fail to transmit image download command\n"); + } + + break; + } + ; + + /* 6. Wait for INIT_EVENT_ID_PENDING_ERROR */ + do { + if (kalIsCardRemoved(prAdapter->prGlueInfo) == true || + fgIsBusAccessFailed == true) { + u4Status = WLAN_STATUS_FAILURE; + } else if (nicRxWaitResponse( + prAdapter, 0, aucBuffer, + sizeof(INIT_HIF_RX_HEADER_T) + + sizeof(INIT_EVENT_PENDING_ERROR), + &u4RxPktLength) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + } else { + prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T)aucBuffer; + + /* EID / SeqNum check */ + if (prInitHifRxHeader->rInitWifiEvent.ucEID != + INIT_EVENT_ID_PENDING_ERROR) { + u4Status = WLAN_STATUS_FAILURE; + } else if (prInitHifRxHeader->rInitWifiEvent.ucSeqNum != + ucCmdSeqNum) { + u4Status = WLAN_STATUS_FAILURE; + } else { + prEventPendingError = + (P_INIT_EVENT_PENDING_ERROR)( + prInitHifRxHeader + -> + rInitWifiEvent + .aucBuffer); + if (prEventPendingError->ucStatus != 0) { /* 0 + * for + * download + * success + */ + u4Status = WLAN_STATUS_FAILURE; + } else { + u4Status = WLAN_STATUS_SUCCESS; + } + } + } + } while (false); + + /* 7. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to confirm the status of + * previously downloaded firmware scatter + * + * @param prAdapter Pointer to the Adapter structure. + * ucCmdSeqNum Sequence number of previous firmware scatter + * + * @return WLAN_STATUS_SUCCESS + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanImageSectionDownloadStatus(IN P_ADAPTER_T prAdapter, + IN u8 ucCmdSeqNum) +{ + u8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + + sizeof(INIT_EVENT_CMD_RESULT)]; + P_INIT_HIF_RX_HEADER_T prInitHifRxHeader; + P_INIT_EVENT_CMD_RESULT prEventCmdResult; + u32 u4RxPktLength; + WLAN_STATUS u4Status; + + u8 ucPortIdx = IMG_DL_STATUS_PORT_IDX; + + ASSERT(prAdapter); + + do { + if (kalIsCardRemoved(prAdapter->prGlueInfo) == true || + fgIsBusAccessFailed == true) { + u4Status = WLAN_STATUS_FAILURE; + } else if (nicRxWaitResponse( + prAdapter, ucPortIdx, aucBuffer, + sizeof(INIT_HIF_RX_HEADER_T) + + sizeof(INIT_EVENT_CMD_RESULT), + &u4RxPktLength) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + } else { + prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T)aucBuffer; + + /* EID / SeqNum check */ + if (prInitHifRxHeader->rInitWifiEvent.ucEID != + INIT_EVENT_ID_CMD_RESULT) { + pr_info("Unexpected EVENT ID, get 0x%0x\n", + prInitHifRxHeader->rInitWifiEvent.ucEID); + u4Status = WLAN_STATUS_FAILURE; + } else if (prInitHifRxHeader->rInitWifiEvent.ucSeqNum != + ucCmdSeqNum) { + pr_info("Unexpected SeqNum %d, %d\n", ucCmdSeqNum, + prInitHifRxHeader->rInitWifiEvent.ucSeqNum); + u4Status = WLAN_STATUS_FAILURE; + } else { + prEventCmdResult = + (P_INIT_EVENT_CMD_RESULT)( + prInitHifRxHeader + -> + rInitWifiEvent + .aucBuffer); + if (prEventCmdResult->ucStatus != 0) { /* 0 for download success */ + DBGLOG(INIT, ERROR, + "Start CMD failed, status[%u]\n", + prEventCmdResult->ucStatus); +#if CFG_SUPPORT_COMPRESSION_FW_OPTION + if (prEventCmdResult->ucStatus == + WIFI_FW_DECOMPRESSION_FAILED) { + DBGLOG(INIT, + ERROR, + "Start Decompression CMD failed, status[%u]\n", + prEventCmdResult + ->ucStatus); + } +#endif + u4Status = WLAN_STATUS_FAILURE; + } else { + u4Status = WLAN_STATUS_SUCCESS; + } + } + } + } while (false); + + return u4Status; +} + +WLAN_STATUS wlanConfigWifiFunc(IN P_ADAPTER_T prAdapter, IN u8 fgEnable, + IN u32 u4StartAddress, IN u8 ucPDA) +{ + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + P_INIT_CMD_WIFI_START prInitCmdWifiStart; + u8 ucTC, ucCmdSeqNum; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanConfigWifiFunc"); + + /* 1. Allocate CMD Info Packet and its Buffer. */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + sizeof(INIT_HIF_TX_HEADER_T) + + sizeof(INIT_CMD_WIFI_START)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + kalMemZero(prCmdInfo->pucInfoBuffer, + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START)); + prCmdInfo->u2InfoBufLen = + sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START); + +#if (CFG_USE_TC4_RESOURCE_FOR_INIT_CMD == 1) + /* 2. Always use TC4 (TC4 as CPU) */ + ucTC = TC4_INDEX; +#else + /* 2. Use TC0's resource to send init_cmd. + * Only TC0 is allowed because SDIO HW always reports + * CPU's TXQ_CNT at TXQ0_CNT in CR4 architecutre) + */ + ucTC = TC0_INDEX; +#endif + + /* 3. increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* 4. Setup common CMD Info Packet */ + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T)(prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prInitHifTxHeader->u2PQ_ID = INIT_CMD_PQ_ID; + prInitHifTxHeader->ucPktFt = INIT_PKT_FT_CMD; + + prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_WIFI_START; + prInitHifTxHeader->rInitWifiCmd.ucPktTypeID = INIT_CMD_PACKET_TYPE_ID; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + prInitCmdWifiStart = + (P_INIT_CMD_WIFI_START)(prInitHifTxHeader->rInitWifiCmd + .aucBuffer); + prInitCmdWifiStart->u4Override = 0; + if (fgEnable) { + prInitCmdWifiStart->u4Override |= START_OVERRIDE_START_ADDRESS; + } + + /* 5G cal until send efuse buffer mode CMD */ +#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1) + prInitCmdWifiStart->u4Override |= START_DELAY_CALIBRATION; +#endif + + if (ucPDA == PDA_CR4) { + prInitCmdWifiStart->u4Override |= START_WORKING_PDA_OPTION; + } + + prInitCmdWifiStart->u4Address = u4StartAddress; + + /* 5. Seend WIFI start command */ + while (1) { + /* 5.1 Acquire TX Resource */ + if (nicTxAcquireResource(prAdapter, ucTC, true) == + WLAN_STATUS_RESOURCES) { + if (nicTxPollingResource(prAdapter, ucTC) != + WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, + ERROR, + "Fail to get TX resource return within timeout\n"); + goto exit; + } + continue; + } + /* 5.2 Send CMD Info Packet */ + if (nicTxInitCmd(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, + "Fail to transmit WIFI start command\n"); + goto exit; + } + + break; + } + ; + + DBGLOG(INIT, INFO, "FW_START CMD send, waiting for RSP\n"); + + u4Status = wlanConfigWifiFuncStatus(prAdapter, ucCmdSeqNum); + + if (u4Status != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "FW_START EVT failed\n"); + }else{ + DBGLOG(INIT, INFO, "FW_START EVT success!!\n"); + } + +exit: + /* 6. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; +} +#if CFG_SUPPORT_COMPRESSION_FW_OPTION +WLAN_STATUS +wlanCompressedFWConfigWifiFunc( + IN P_ADAPTER_T prAdapter, IN u8 fgEnable, IN u32 u4StartAddress, + IN u8 ucPDA, IN P_INIT_CMD_WIFI_DECOMPRESSION_START prFwImageInFo) +{ + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + P_INIT_CMD_WIFI_DECOMPRESSION_START prInitCmdWifiStart; + u8 ucTC, ucCmdSeqNum; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + DEBUGFUNC("wlanConfigWifiFunc"); + /* 1. Allocate CMD Info Packet and its Buffer. */ + prCmdInfo = cmdBufAllocateCmdInfo( + prAdapter, sizeof(INIT_HIF_TX_HEADER_T) + + sizeof(INIT_CMD_WIFI_DECOMPRESSION_START)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + kalMemZero(prCmdInfo->pucInfoBuffer, + sizeof(INIT_HIF_TX_HEADER_T) + + sizeof(INIT_CMD_WIFI_DECOMPRESSION_START)); + prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + + sizeof(INIT_CMD_WIFI_DECOMPRESSION_START); + + /* 2. Always use TC0 */ + ucTC = TC0_INDEX; + + /* 3. increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* 4. Setup common CMD Info Packet */ + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T)(prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prInitHifTxHeader->u2PQ_ID = INIT_CMD_PQ_ID; + prInitHifTxHeader->ucPktFt = INIT_PKT_FT_CMD; + prInitHifTxHeader->rInitWifiCmd.ucCID = + INIT_CMD_ID_DECOMPRESSED_WIFI_START; + prInitHifTxHeader->rInitWifiCmd.ucPktTypeID = INIT_CMD_PACKET_TYPE_ID; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + prInitCmdWifiStart = + (P_INIT_CMD_WIFI_DECOMPRESSION_START)(prInitHifTxHeader + ->rInitWifiCmd + .aucBuffer); + prInitCmdWifiStart->u4Override = 0; + if (fgEnable) { + prInitCmdWifiStart->u4Override |= START_OVERRIDE_START_ADDRESS; + } + + /* 5G cal until send efuse buffer mode CMD */ +#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1) + prInitCmdWifiStart->u4Override |= START_DELAY_CALIBRATION; +#endif + if (ucPDA == PDA_CR4) { + prInitCmdWifiStart->u4Override |= START_WORKING_PDA_OPTION; + } + +#if CFG_COMPRESSION_DEBUG + prInitCmdWifiStart->u4Override |= START_CRC_CHECK; +#endif +#if CFG_DECOMPRESSION_TMP_ADDRESS + prInitCmdWifiStart->u4Override |= CHANGE_DECOMPRESSION_TMP_ADDRESS; + prInitCmdWifiStart->u4DecompressTmpAddress = 0xE6000; +#endif + prInitCmdWifiStart->u4Address = u4StartAddress; + prInitCmdWifiStart->u4Region1Address = prFwImageInFo->u4Region1Address; + prInitCmdWifiStart->u4Region1CRC = prFwImageInFo->u4Region1CRC; + prInitCmdWifiStart->u4BlockSize = prFwImageInFo->u4BlockSize; + prInitCmdWifiStart->u4Region1length = prFwImageInFo->u4Region1length; + prInitCmdWifiStart->u4Region2Address = prFwImageInFo->u4Region2Address; + prInitCmdWifiStart->u4Region2CRC = prFwImageInFo->u4Region2CRC; + prInitCmdWifiStart->u4Region2length = prFwImageInFo->u4Region2length; + + while (1) { + /* 5.1 Acquire TX Resource */ + if (nicTxAcquireResource(prAdapter, ucTC, true) == + WLAN_STATUS_RESOURCES) { + if (nicTxPollingResource(prAdapter, ucTC) != + WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, + ERROR, + "Fail to get TX resource return within timeout\n"); + break; + } + continue; + } + /* 5.2 Send CMD Info Packet */ + if (nicTxInitCmd(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, + "Fail to transmit WIFI start command\n"); + } + + break; + } + ; + + DBGLOG(INIT, INFO, "FW_START CMD send, waiting for RSP\n"); + + u4Status = wlanConfigWifiFuncStatus(prAdapter, ucCmdSeqNum); + + if (u4Status != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "FW_START EVT failed\n"); + }else{ + DBGLOG(INIT, INFO, "FW_START EVT success!!\n"); + } + + /* 6. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; +} +#endif + +WLAN_STATUS wlanDownloadFW(IN P_ADAPTER_T prAdapter) +{ + u32 u4FwSize = 0; + void *prFwBuffer = NULL; + u8 fgReady; + WLAN_STATUS rDlStatus = 0; + WLAN_STATUS rCfgStatus = 0; +#if CFG_SUPPORT_COMPRESSION_FW_OPTION + u8 fgIsCompressed = false; + INIT_CMD_WIFI_DECOMPRESSION_START rFwImageInFo; +#endif + + if (!prAdapter) { + return WLAN_STATUS_FAILURE; + } + + HAL_WIFI_FUNC_READY_CHECK(prAdapter, WIFI_FUNC_READY_BITS, &fgReady); + + if (fgReady) { + DBGLOG(INIT, INFO, + "Wi-Fi is already ON!, turn off before FW DL!\n"); + + if (wlanPowerOffWifi(prAdapter) != WLAN_STATUS_SUCCESS) { + return WLAN_STATUS_FAILURE; + } + + nicpmWakeUpWiFi(prAdapter); + HAL_HIF_INIT(prAdapter); + } + + HAL_ENABLE_FWDL(prAdapter, true); + + if (wlanDownloadPatch(prAdapter) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "Patch download failed\n"); + HAL_ENABLE_FWDL(prAdapter, false); + return WLAN_STATUS_FAILURE; + } + + DBGLOG(INIT, INFO, "FW download Start\n"); + + do { + /* N9 ILM+DLM */ + kalFirmwareImageMapping(prAdapter->prGlueInfo, &prFwBuffer, + &u4FwSize, IMG_DL_IDX_N9_FW); + if (prFwBuffer == NULL) { + rDlStatus = WLAN_STATUS_FAILURE; + DBGLOG(INIT, WARN, "FW[%u] load error!\n", + IMG_DL_IDX_N9_FW); + break; + } +#if CFG_SUPPORT_COMPRESSION_FW_OPTION + rDlStatus = wlanImageSectionDownloadStage( + prAdapter, prFwBuffer, u4FwSize, 2, IMG_DL_IDX_N9_FW, + &fgIsCompressed, &rFwImageInFo); + if (fgIsCompressed == true) { + rCfgStatus = wlanCompressedFWConfigWifiFunc( + prAdapter, false, 0, PDA_N9, &rFwImageInFo); + } else { + rCfgStatus = + wlanConfigWifiFunc(prAdapter, false, 0, PDA_N9); + } +#else + rDlStatus = wlanImageSectionDownloadStage( + prAdapter, prFwBuffer, u4FwSize, 2, IMG_DL_IDX_N9_FW); + rCfgStatus = wlanConfigWifiFunc(prAdapter, false, 0, PDA_N9); +#endif + kalFirmwareImageUnmapping(prAdapter->prGlueInfo, NULL, + prFwBuffer); + + if ((rDlStatus != WLAN_STATUS_SUCCESS) || + (rCfgStatus != WLAN_STATUS_SUCCESS)) { + break; + } + /* wlanCheckWifiN9Func(prAdapter); */ + + /* CR4 bin */ + kalFirmwareImageMapping(prAdapter->prGlueInfo, &prFwBuffer, + &u4FwSize, IMG_DL_IDX_CR4_FW); + if (prFwBuffer == NULL) { + rDlStatus = WLAN_STATUS_FAILURE; + DBGLOG(INIT, WARN, "FW[%u] load error!\n", + IMG_DL_IDX_CR4_FW); + break; + } +#if CFG_SUPPORT_COMPRESSION_FW_OPTION + rDlStatus = wlanImageSectionDownloadStage( + prAdapter, prFwBuffer, u4FwSize, CR4_FWDL_SECTION_NUM, + IMG_DL_IDX_CR4_FW, &fgIsCompressed, &rFwImageInFo); + prAdapter->fgIsCr4FwDownloaded = true; + if (fgIsCompressed == true) { + rCfgStatus = wlanCompressedFWConfigWifiFunc( + prAdapter, false, 0, PDA_CR4, &rFwImageInFo); + } else { + rCfgStatus = wlanConfigWifiFunc(prAdapter, false, 0, + PDA_CR4); + } +#else + rDlStatus = wlanImageSectionDownloadStage(prAdapter, prFwBuffer, + u4FwSize, + CR4_FWDL_SECTION_NUM, + IMG_DL_IDX_CR4_FW); + prAdapter->fgIsCr4FwDownloaded = true; + rCfgStatus = wlanConfigWifiFunc(prAdapter, false, 0, PDA_CR4); +#endif + kalFirmwareImageUnmapping(prAdapter->prGlueInfo, NULL, + prFwBuffer); + + if ((rDlStatus != WLAN_STATUS_SUCCESS) || + (rCfgStatus != WLAN_STATUS_SUCCESS)) { + break; + } + } while (0); + DBGLOG(INIT, INFO, "FW download End\n"); + + HAL_ENABLE_FWDL(prAdapter, false); + + if ((rDlStatus != WLAN_STATUS_SUCCESS) || + (rCfgStatus != WLAN_STATUS_SUCCESS)) { + return WLAN_STATUS_FAILURE; + }else{ + return WLAN_STATUS_SUCCESS; + } +} + +WLAN_STATUS wlanDownloadPatch(IN P_ADAPTER_T prAdapter) +{ + u32 u4FwSize = 0; + void *prFwBuffer = NULL; + u32 u4StartOffset, u4Addr, u4Len, u4DataMode; +#if CFG_SUPPORT_COMPRESSION_FW_OPTION + u8 ucIsCompressed; +#endif + if (!prAdapter) { + return WLAN_STATUS_FAILURE; + } + + DBGLOG(INIT, INFO, "Patch download Start\n"); + + prAdapter->rVerInfo.fgPatchIsDlByDrv = false; + + kalFirmwareImageMapping(prAdapter->prGlueInfo, &prFwBuffer, &u4FwSize, + IMG_DL_IDX_PATCH); + if (prFwBuffer == NULL) { + DBGLOG(INIT, WARN, "FW[%u] load error!\n", IMG_DL_IDX_PATCH); + return WLAN_STATUS_FAILURE; + } + + if (wlanPatchIsDownloaded(prAdapter)) { + wlanImageSectionGetInfo(prAdapter, prFwBuffer, u4FwSize, 1, 1, + IMG_DL_IDX_PATCH, &u4StartOffset, + &u4Addr, &u4Len, &u4DataMode); + kalFirmwareImageUnmapping(prAdapter->prGlueInfo, NULL, + prFwBuffer); + DBGLOG(INIT, INFO, "No need to DL patch\n"); + return WLAN_STATUS_SUCCESS; + } + + /* Patch DL */ + do { +#if CFG_SUPPORT_COMPRESSION_FW_OPTION + wlanImageSectionDownloadStage(prAdapter, prFwBuffer, u4FwSize, + 1, IMG_DL_IDX_PATCH, + &ucIsCompressed, NULL); +#else + wlanImageSectionDownloadStage(prAdapter, prFwBuffer, u4FwSize, + 1, IMG_DL_IDX_PATCH); +#endif + wlanPatchSendComplete(prAdapter); + kalFirmwareImageUnmapping(prAdapter->prGlueInfo, NULL, + prFwBuffer); + + prAdapter->rVerInfo.fgPatchIsDlByDrv = true; + } while (0); + + DBGLOG(INIT, INFO, "Patch download End\n"); + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS wlanGetPatchInfo(IN P_ADAPTER_T prAdapter) +{ + u32 u4FwSize = 0; + void *prFwBuffer = NULL; + u32 u4StartOffset, u4Addr, u4Len, u4DataMode; + + if (!prAdapter) { + return WLAN_STATUS_FAILURE; + } + + kalFirmwareImageMapping(prAdapter->prGlueInfo, &prFwBuffer, &u4FwSize, + IMG_DL_IDX_PATCH); + if (prFwBuffer == NULL) { + DBGLOG(INIT, WARN, "FW[%u] load error!\n", IMG_DL_IDX_PATCH); + return WLAN_STATUS_FAILURE; + } + + wlanImageSectionGetInfo(prAdapter, prFwBuffer, u4FwSize, 1, 1, + IMG_DL_IDX_PATCH, &u4StartOffset, &u4Addr, + &u4Len, &u4DataMode); + + kalFirmwareImageUnmapping(prAdapter->prGlueInfo, NULL, prFwBuffer); + + return WLAN_STATUS_SUCCESS; +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to get the chip information + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return + */ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS wlanSetChipEcoInfo(IN P_ADAPTER_T prAdapter) +{ + u32 hw_version, sw_version = 0; +#if !DBG_DISABLE_ALL_LOG + struct chip_info *prChipInfo = prAdapter->chip_info; + u32 chip_id = prChipInfo->chip_id; +#endif + /* WLAN_STATUS status; */ + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanSetChipEcoInfo.\n"); + + if (wlanAccessRegister(prAdapter, TOP_HVR, &hw_version, 0, 0) != + WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, + "wlanSetChipEcoInfo >> get TOP_HVR failed.\n"); + u4Status = WLAN_STATUS_FAILURE; + } else if (wlanAccessRegister(prAdapter, TOP_FVR, &sw_version, 0, 0) != + WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, + "wlanSetChipEcoInfo >> get TOP_FVR failed.\n"); + u4Status = WLAN_STATUS_FAILURE; + } else { + /* success */ + nicSetChipHwVer((u8)(GET_HW_VER(hw_version) & 0xFF)); + nicSetChipFactoryVer((u8)((GET_HW_VER(hw_version) >> 8) & 0xF)); + nicSetChipSwVer((u8)GET_FW_VER(sw_version)); + + /* Assign current chip version */ + prAdapter->chip_info->eco_ver = nicGetChipEcoVer(prAdapter); + } + + DBGLOG(INIT, INFO, "Chip ID[%04X] Version[E%u] HW[0x%08x] SW[0x%08x]\n", + chip_id, prAdapter->chip_info->eco_ver, hw_version, sw_version); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to read/write a certain N9 + * register by inband command in blocking mode in ROM code stage + * + * @param prAdapter Pointer to the Adapter structure. + * u4DestAddr Address of destination address + * u4ImgSecSize Length of the firmware block + * fgReset should be set to true if this is the 1st configuration + * + * @return WLAN_STATUS_SUCCESS + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanAccessRegister(IN P_ADAPTER_T prAdapter, IN u32 u4Addr, + IN u32 *pru4Result, IN u32 u4Data, + IN u8 ucSetQuery) +{ + P_CMD_INFO_T prCmdInfo; + P_INIT_HIF_TX_HEADER_T prInitHifTxHeader; + P_INIT_HIF_RX_HEADER_T prInitHifRxHeader; + P_INIT_CMD_ACCESS_REG prInitCmdAccessReg; + P_INIT_EVENT_ACCESS_REG prInitEventAccessReg; + u8 ucTC, ucCmdSeqNum; + u16 cmd_size; + u8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + + sizeof(INIT_EVENT_ACCESS_REG)]; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanAccessRegister"); + + /* 1. Allocate CMD Info Packet and its Buffer. */ + cmd_size = sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_ACCESS_REG); + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, cmd_size); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + prCmdInfo->u2InfoBufLen = cmd_size; + +#if (CFG_USE_TC4_RESOURCE_FOR_INIT_CMD == 1) + /* 2. Use TC4's resource to download image. (TC4 as CPU) */ + ucTC = TC4_INDEX; +#else + /* 2. Use TC0's resource to download image. + * Only TC0 is allowed because SDIO HW always reports + * MCU's TXQ_CNT at TXQ0_CNT in CR4 architecutre) + */ + ucTC = TC0_INDEX; +#endif + + /* 3. increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* 4. Setup common CMD Info Packet */ + prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T)(prCmdInfo->pucInfoBuffer); + prInitHifTxHeader->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prInitHifTxHeader->u2PQ_ID = INIT_CMD_PQ_ID; + prInitHifTxHeader->ucHeaderFormat = INIT_CMD_PACKET_TYPE_ID; + prInitHifTxHeader->ucPktFt = INIT_PKT_FT_CMD; + + prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_ACCESS_REG; + + prInitHifTxHeader->rInitWifiCmd.ucPktTypeID = INIT_CMD_PACKET_TYPE_ID; + prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum; + + /* 5. Setup CMD_ACCESS_REG */ + prInitCmdAccessReg = + (P_INIT_CMD_ACCESS_REG)(prInitHifTxHeader->rInitWifiCmd + .aucBuffer); + prInitCmdAccessReg->ucSetQuery = ucSetQuery; + prInitCmdAccessReg->u4Address = u4Addr; + prInitCmdAccessReg->u4Data = u4Data; + + /* 6. Send CMD_ACCESS_REG command */ + while (1) { + /* 6.1 Acquire TX Resource */ + if (nicTxAcquireResource(prAdapter, ucTC, true) == + WLAN_STATUS_RESOURCES) { + if (nicTxPollingResource(prAdapter, ucTC) != + WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, + ERROR, + "Fail to get TX resource return within timeout\n"); + goto exit; + } + continue; + } + /* 6.2 Send CMD Info Packet */ + if (nicTxInitCmd(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, ERROR, + "Fail to transmit image download command\n"); + goto exit; + } + + break; + } + ; + + /* 7. Wait for INIT_EVENT_ID_CMD_RESULT */ + u4Status = wlanAccessRegisterStatus(prAdapter, ucCmdSeqNum, ucSetQuery, + aucBuffer, sizeof(aucBuffer)); + if (ucSetQuery == 0) { + prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T)aucBuffer; + prInitEventAccessReg = + (P_INIT_EVENT_ACCESS_REG) + prInitHifRxHeader->rInitWifiEvent.aucBuffer; + + if (prInitEventAccessReg->u4Address != u4Addr) { + DBGLOG(INIT, + ERROR, + "Event reports address incorrect. 0x%08x, 0x%08x.\n", + u4Addr, + prInitEventAccessReg->u4Address); + u4Status = WLAN_STATUS_FAILURE; + } + *pru4Result = prInitEventAccessReg->u4Data; + } + +exit: + /* 8. Free CMD Info Packet. */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to get the response of INIT_CMD_ACCESS_REG + * + * @param prAdapter Pointer to the Adapter structure. + * ucCmdSeqNum Sequence number of previous firmware scatter + * ucSetQuery Read or write + * prEvent the pointer of buffer to store the response + * + * @return WLAN_STATUS_SUCCESS + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanAccessRegisterStatus(IN P_ADAPTER_T prAdapter, + IN u8 ucCmdSeqNum, IN u8 ucSetQuery, + IN void *prEvent, IN u32 u4EventLen) +{ + /* u8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + + * sizeof(INIT_CMD_ACCESS_REG)]; */ + P_INIT_HIF_RX_HEADER_T prInitHifRxHeader; + /* P_INIT_EVENT_CMD_RESULT prEventCmdResult; + * P_INIT_CMD_ACCESS_REG prEventCmdAccessReg; + */ + u32 u4RxPktLength; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + u8 ucPortIdx = IMG_DL_STATUS_PORT_IDX; + + ASSERT(prAdapter); + + do { + if (kalIsCardRemoved(prAdapter->prGlueInfo) == true || + fgIsBusAccessFailed == true) { + u4Status = WLAN_STATUS_FAILURE; + } else if (nicRxWaitResponse(prAdapter, ucPortIdx, prEvent, + u4EventLen, &u4RxPktLength) != + WLAN_STATUS_SUCCESS) { + u4Status = WLAN_STATUS_FAILURE; + } else { + prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T)prEvent; + + /* EID / SeqNum check */ + if (((prInitHifRxHeader->rInitWifiEvent.ucEID != + INIT_EVENT_ID_CMD_RESULT) && + (ucSetQuery == 1)) || + ((prInitHifRxHeader->rInitWifiEvent.ucEID != + INIT_EVENT_ID_ACCESS_REG) && + (ucSetQuery == 0))) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, + ERROR, + "wlanAccessRegisterStatus: incorrect ucEID. ucSetQuery = 0x%x\n", + ucSetQuery); + } else if (prInitHifRxHeader->rInitWifiEvent.ucSeqNum != + ucCmdSeqNum) { + u4Status = WLAN_STATUS_FAILURE; + DBGLOG(INIT, + ERROR, + "wlanAccessRegisterStatus: incorrect ucCmdSeqNum. = 0x%x\n", + ucCmdSeqNum); + } else { + } + } + } while (false); + + return u4Status; +} +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to process queued RX packets + * + * @param prAdapter Pointer to the Adapter structure. + * prSwRfbListHead Pointer to head of RX packets link list + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanProcessQueuedSwRfb(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfbListHead) +{ + P_SW_RFB_T prSwRfb, prNextSwRfb; + P_TX_CTRL_T prTxCtrl; + P_RX_CTRL_T prRxCtrl; + + ASSERT(prAdapter); + ASSERT(prSwRfbListHead); + + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + prSwRfb = prSwRfbListHead; + + do { + /* save next first */ + prNextSwRfb = (P_SW_RFB_T)QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prSwRfb); + + switch (prSwRfb->eDst) { + case RX_PKT_DESTINATION_HOST: + nicRxProcessPktWithoutReorder(prAdapter, prSwRfb); + break; + + case RX_PKT_DESTINATION_FORWARD: + nicRxProcessForwardPkt(prAdapter, prSwRfb); + break; + + case RX_PKT_DESTINATION_HOST_WITH_FORWARD: + nicRxProcessGOBroadcastPkt(prAdapter, prSwRfb); + break; + + case RX_PKT_DESTINATION_NULL: + nicRxReturnRFB(prAdapter, prSwRfb); + break; + + default: + break; + } + +#if CFG_HIF_RX_STARVATION_WARNING + prRxCtrl->u4DequeuedCnt++; +#endif + prSwRfb = prNextSwRfb; + } while (prSwRfb); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to purge queued TX packets + * by indicating failure to OS and returned to free list + * + * @param prAdapter Pointer to the Adapter structure. + * prMsduInfoListHead Pointer to head of TX packets link list + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanProcessQueuedMsduInfo(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead) +{ + ASSERT(prAdapter); + ASSERT(prMsduInfoListHead); + + nicTxFreeMsduInfoPacket(prAdapter, prMsduInfoListHead); + nicTxReturnMsduInfo(prAdapter, prMsduInfoListHead); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to check if the OID handler needs timeout + * + * @param prAdapter Pointer to the Adapter structure. + * pfnOidHandler Pointer to the OID handler + * + * @return true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 wlanoidTimeoutCheck(IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN u32 u4Timeout) +{ + PFN_OID_HANDLER_FUNC *apfnOidHandlerWOTimeoutCheck; + u32 i; + u32 u4NumOfElem; + u32 u4OidTimeout; + + apfnOidHandlerWOTimeoutCheck = apfnOidWOTimeoutCheck; + u4NumOfElem = + sizeof(apfnOidWOTimeoutCheck) / sizeof(PFN_OID_HANDLER_FUNC); + + for (i = 0; i < u4NumOfElem; i++) + if (apfnOidHandlerWOTimeoutCheck[i] == pfnOidHandler) { + return false; + } + + /* Decrease OID timeout threshold if chip NoAck/resetting */ + if (wlanIsChipNoAck(prAdapter)) { + u4OidTimeout = WLAN_OID_TIMEOUT_THRESHOLD_IN_RESETTING; + DBGLOG(INIT, INFO, + "Decrease OID timeout to %ums due to NoACK/CHIP-RESET\n", + u4OidTimeout); + } else { + u4OidTimeout = u4Timeout; + } + + /* Set OID timer for timeout check */ + cnmTimerStartTimer(prAdapter, &(prAdapter->rOidTimeoutTimer), + u4OidTimeout); + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to clear any pending OID timeout check + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void wlanoidClearTimeoutCheck(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + cnmTimerStopTimer(prAdapter, &(prAdapter->rOidTimeoutTimer)); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to override network address + * if NVRAM has a valid value + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return WLAN_STATUS_FAILURE The request could not be processed + * WLAN_STATUS_PENDING The request has been queued for later + * processing WLAN_STATUS_SUCCESS The request has been processed + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanUpdateNetworkAddress(IN P_ADAPTER_T prAdapter) +{ + const u8 aucZeroMacAddr[] = NULL_MAC_ADDR; + PARAM_MAC_ADDRESS rMacAddr; + u32 u4SysTime; + + DEBUGFUNC("wlanUpdateNetworkAddress"); + + ASSERT(prAdapter); + + if (kalRetrieveNetworkAddress(prAdapter->prGlueInfo, &rMacAddr) == + false || + IS_BMCAST_MAC_ADDR(rMacAddr) || + EQUAL_MAC_ADDR(aucZeroMacAddr, rMacAddr)) { + /* eFUSE has a valid address, don't do anything */ + if (prAdapter->fgIsEmbbededMacAddrValid == true) { +#if CFG_SHOW_MACADDR_SOURCE + DBGLOG(INIT, INFO, "Using embedded MAC address"); +#endif + return WLAN_STATUS_SUCCESS; + } +#if CFG_SHOW_MACADDR_SOURCE + DBGLOG(INIT, INFO, "Using dynamically generated MAC address"); +#endif + /* dynamic generate */ + u4SysTime = (u32)kalGetTimeTick(); + + rMacAddr[0] = 0x00; + rMacAddr[1] = 0x08; + rMacAddr[2] = 0x22; + + kalMemCopy(&rMacAddr[3], &u4SysTime, 3); + } else { +#if CFG_SHOW_MACADDR_SOURCE + DBGLOG(INIT, INFO, "Using host-supplied MAC address"); +#endif + } + + COPY_MAC_ADDR(prAdapter->rWifiVar.aucMacAddress, rMacAddr); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to update basic configuration into firmware + * domain + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return WLAN_STATUS_FAILURE The request could not be processed + * WLAN_STATUS_PENDING The request has been queued for later + * processing WLAN_STATUS_SUCCESS The request has been processed + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanUpdateBasicConfig(IN P_ADAPTER_T prAdapter) +{ + u8 ucCmdSeqNum; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_CMD_BASIC_CONFIG_T prCmdBasicConfig; + P_PSE_CMD_HDR_T prPseCmdHdr; + WLAN_STATUS rResult; + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; + + DEBUGFUNC("wlanUpdateBasicConfig"); + + ASSERT(prAdapter); + + prCmdInfo = cmdBufAllocateCmdInfo( + prAdapter, CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG_T)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_BUILD_CONNECTION cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_BASIC_CONFIG_T); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->pfCmdTimeoutHandler = NULL; + prCmdInfo->fgIsOid = false; + prCmdInfo->ucCID = CMD_ID_BASIC_CONFIG; + prCmdInfo->fgSetQuery = true; + prCmdInfo->fgNeedResp = false; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_BASIC_CONFIG_T); + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prPseCmdHdr = (P_PSE_CMD_HDR_T)(prCmdInfo->pucInfoBuffer); + prPseCmdHdr->u2Qidx = TXD_Q_IDX_MCU_RQ0; + prPseCmdHdr->u2Pidx = TXD_P_IDX_MCU; + prPseCmdHdr->u2Hf = TXD_HF_CMD; + prPseCmdHdr->u2Ft = TXD_FT_LONG_FORMAT; + prPseCmdHdr->u2PktFt = TXD_PKT_FT_CMD; + + prWifiCmd->u2Length = prWifiCmd->u2TxByteCount - sizeof(PSE_CMD_HDR_T); + + /* configure CMD_BASIC_CONFIG */ + + prCmdBasicConfig = (P_CMD_BASIC_CONFIG_T)(prWifiCmd->aucBuffer); + kalMemZero(prCmdBasicConfig, sizeof(CMD_BASIC_CONFIG_T)); + prCmdBasicConfig->ucNative80211 = 0; + prCmdBasicConfig->rCsumOffload.u2RxChecksum = 0; + prCmdBasicConfig->rCsumOffload.u2TxChecksum = 0; + prCmdBasicConfig->ucCtrlFlagAssertPath = + prWifiVar->ucCtrlFlagAssertPath; + prCmdBasicConfig->ucCtrlFlagDebugLevel = + prWifiVar->ucCtrlFlagDebugLevel; + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + if (prAdapter->fgIsSupportCsumOffload) { + if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_TCP) { + prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(2); + } + + if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_UDP) { + prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(1); + } + + if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_TX_IP) { + prCmdBasicConfig->rCsumOffload.u2TxChecksum |= BIT(0); + } + + if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_RX_TCP) { + prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(2); + } + + if (prAdapter->u4CSUMFlags & CSUM_OFFLOAD_EN_RX_UDP) { + prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(1); + } + + if (prAdapter->u4CSUMFlags & + (CSUM_OFFLOAD_EN_RX_IPv4 | CSUM_OFFLOAD_EN_RX_IPv6)) { + prCmdBasicConfig->rCsumOffload.u2RxChecksum |= BIT(0); + } + } +#endif + + rResult = wlanSendCommand(prAdapter, prCmdInfo); + + if (rResult != WLAN_STATUS_SUCCESS) { + kalEnqueueCommand(prAdapter->prGlueInfo, + (P_QUE_ENTRY_T)prCmdInfo); + + return WLAN_STATUS_PENDING; + } + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to check if the device is in RF test mode + * + * @param pfnOidHandler Pointer to the OID handler + * + * @return true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 wlanQueryTestMode(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + return prAdapter->fgTestMode; +} + +u8 wlanProcessTxFrame(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prPacket) +{ + u32 u4SysTime; + u8 ucMacHeaderLen; + TX_PACKET_INFO rTxPacketInfo; + struct chip_info *prChipInfo; + + ASSERT(prAdapter); + ASSERT(prPacket); + prChipInfo = prAdapter->chip_info; + + if (kalQoSFrameClassifierAndPacketInfo(prAdapter->prGlueInfo, prPacket, + &rTxPacketInfo)) { + /* Save the value of Priority Parameter */ + GLUE_SET_PKT_TID(prPacket, rTxPacketInfo.ucPriorityParam); + + if (rTxPacketInfo.u2Flag) { + if (rTxPacketInfo.u2Flag & BIT(ENUM_PKT_1X)) { + P_STA_RECORD_T prStaRec; + + DBGLOG(RSN, INFO, "T1X len=%d\n", + rTxPacketInfo.u4PacketLen); + + prStaRec = cnmGetStaRecByAddress( + prAdapter, + GLUE_GET_PKT_BSS_IDX(prPacket), + rTxPacketInfo.aucEthDestAddr); + + GLUE_SET_PKT_FLAG(prPacket, ENUM_PKT_1X); + /* + * if (secIsProtected1xFrame(prAdapter, + * prStaRec) && !kalIs24Of4Packet(prPacket)) + * GLUE_SET_PKT_FLAG(prPacket, + * ENUM_PKT_PROTECTED_1X); + */ + } + + if (rTxPacketInfo.u2Flag & + BIT(ENUM_PKT_NON_PROTECTED_1X)) { + GLUE_SET_PKT_FLAG(prPacket, + ENUM_PKT_NON_PROTECTED_1X); + } + + if (rTxPacketInfo.u2Flag & BIT(ENUM_PKT_802_3)) { + GLUE_SET_PKT_FLAG(prPacket, ENUM_PKT_802_3); + } + + if (rTxPacketInfo.u2Flag & BIT(ENUM_PKT_VLAN_EXIST) && + FEAT_SUP_LLC_VLAN_TX(prChipInfo)) { + GLUE_SET_PKT_FLAG(prPacket, + ENUM_PKT_VLAN_EXIST); + } + + if (rTxPacketInfo.u2Flag & BIT(ENUM_PKT_DHCP)) { + GLUE_SET_PKT_FLAG(prPacket, ENUM_PKT_DHCP); + } + + if (rTxPacketInfo.u2Flag & BIT(ENUM_PKT_ARP)) { + GLUE_SET_PKT_FLAG(prPacket, ENUM_PKT_ARP); + } + } + + ucMacHeaderLen = ETHER_HEADER_LEN; + + /* Save the value of Header Length */ + GLUE_SET_PKT_HEADER_LEN(prPacket, ucMacHeaderLen); + + /* Save the value of Frame Length */ + GLUE_SET_PKT_FRAME_LEN(prPacket, + (u16)rTxPacketInfo.u4PacketLen); + + /* Save the value of Arrival Time */ + u4SysTime = (u32)kalGetTimeTick(); + GLUE_SET_PKT_ARRIVAL_TIME(prPacket, u4SysTime); + + return true; + } + + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to identify 802.1x and Bluetooth-over-Wi-Fi + * security frames, and queued into command queue for strict ordering + * due to 802.1x frames before add-key OIDs are not to be encrypted + * + * @param prAdapter Pointer of Adapter Data Structure + * @param prPacket Pointer of native packet + * + * @return true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 wlanProcessSecurityFrame(IN P_ADAPTER_T prAdapter, + IN P_NATIVE_PACKET prPacket) +{ + P_CMD_INFO_T prCmdInfo; + P_STA_RECORD_T prStaRec; + u8 ucBssIndex; + u32 u4PacketLen; + u8 aucEthDestAddr[PARAM_MAC_ADDR_LEN]; + P_MSDU_INFO_T prMsduInfo; + u8 ucStaRecIndex; + + ASSERT(prAdapter); + ASSERT(prPacket); + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, 0); + + /* Get MSDU_INFO for TxDone */ + prMsduInfo = cnmPktAlloc(prAdapter, 0); + + u4PacketLen = (u32)GLUE_GET_PKT_FRAME_LEN(prPacket); + + if (prCmdInfo && prMsduInfo) { + ucBssIndex = GLUE_GET_PKT_BSS_IDX(prPacket); + + kalGetEthDestAddr(prAdapter->prGlueInfo, prPacket, + aucEthDestAddr); + + prStaRec = cnmGetStaRecByAddress(prAdapter, ucBssIndex, + aucEthDestAddr); + + prCmdInfo->eCmdType = COMMAND_TYPE_SECURITY_FRAME; + prCmdInfo->u2InfoBufLen = (u16)u4PacketLen; + prCmdInfo->prPacket = prPacket; + prCmdInfo->prMsduInfo = prMsduInfo; + prCmdInfo->pfCmdDoneHandler = wlanSecurityFrameTxDone; + prCmdInfo->pfCmdTimeoutHandler = wlanSecurityFrameTxTimeout; + prCmdInfo->fgIsOid = false; + prCmdInfo->fgSetQuery = true; + prCmdInfo->fgNeedResp = false; + + if (prStaRec) { + ucStaRecIndex = prStaRec->ucIndex; + }else{ + ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; + } + + /* Fill-up MSDU_INFO */ + nicTxSetDataPacket(prAdapter, prMsduInfo, ucBssIndex, + ucStaRecIndex, 0, u4PacketLen, + nicTxDummyTxDone, MSDU_RATE_MODE_AUTO, + TX_PACKET_OS, 0, false, true); + + prMsduInfo->prPacket = prPacket; + /* No Tx descriptor template for MMPDU */ + prMsduInfo->fgIsTXDTemplateValid = false; + + if (GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_PROTECTED_1X)) { + nicTxConfigPktOption(prMsduInfo, + MSDU_OPT_PROTECTED_FRAME, true); + } + + nicTxComposeSecurityFrameDesc(prAdapter, prCmdInfo, + prMsduInfo->aucTxDescBuffer, + NULL); + kalEnqueueCommand(prAdapter->prGlueInfo, + (P_QUE_ENTRY_T)prCmdInfo); + GLUE_SET_EVENT(prAdapter->prGlueInfo); + + return true; + } + DBGLOG(RSN, INFO, "Failed to alloc CMD/MGMT INFO for 1X frame!!\n"); + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + cnmPktFree(prAdapter, prMsduInfo); + + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called when 802.1x or Bluetooth-over-Wi-Fi + * security frames has been sent to firmware + * + * @param prAdapter Pointer of Adapter Data Structure + * @param prCmdInfo Pointer of CMD_INFO_T + * @param pucEventBuf meaningless, only for API compatibility + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void wlanSecurityFrameTxDone(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_MSDU_INFO_T prMsduInfo = prCmdInfo->prMsduInfo; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prMsduInfo->ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, "Invalid BssInfo index[%u], skip dump!\n", + prMsduInfo->ucBssIndex); + return; + } + + if (GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex) + ->eNetworkType == NETWORK_TYPE_AIS && + prAdapter->rWifiVar.rAisSpecificBssInfo.fgCounterMeasure) { + P_STA_RECORD_T prSta = + cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucBssIndex); + + if (prSta) { + kalMsleep(10); + if (authSendDeauthFrame( + prAdapter, + GET_BSS_INFO_BY_INDEX( + prAdapter, prMsduInfo->ucBssIndex), + prSta, (P_SW_RFB_T)NULL, + REASON_CODE_MIC_FAILURE, + (PFN_TX_DONE_HANDLER)NULL + /* secFsmEventDeauthTxDone left upper layer + * handle the 60 timer */ + ) != WLAN_STATUS_SUCCESS) { + ASSERT(false); + } + /* secFsmEventEapolTxDone(prAdapter, prSta, + * TX_RESULT_SUCCESS); */ + } + } + + kalSecurityFrameSendComplete(prAdapter->prGlueInfo, prCmdInfo->prPacket, + WLAN_STATUS_SUCCESS); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called when 802.1x or Bluetooth-over-Wi-Fi + * security frames has failed sending to firmware + * + * @param prAdapter Pointer of Adapter Data Structure + * @param prCmdInfo Pointer of CMD_INFO_T + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void wlanSecurityFrameTxTimeout(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo) +{ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + kalSecurityFrameSendComplete(prAdapter->prGlueInfo, prCmdInfo->prPacket, + WLAN_STATUS_FAILURE); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called before AIS is starting a new scan + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void wlanClearScanningResult(IN P_ADAPTER_T prAdapter) +{ + u8 fgKeepCurrOne = false; + u32 i; + + ASSERT(prAdapter); + + /* clear scanning result */ + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED) { + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { + if (EQUAL_MAC_ADDR( + prAdapter->rWlanInfo.rCurrBssId.arMacAddress, + prAdapter->rWlanInfo.arScanResult[i] + .arMacAddress)) { + fgKeepCurrOne = true; + + if (i != 0) { + /* copy structure */ + kalMemCopy(&(prAdapter->rWlanInfo + .arScanResult[0]), + &(prAdapter->rWlanInfo + .arScanResult[i]), + OFFSET_OF(PARAM_BSSID_EX_T, + aucIEs)); + } + + if (prAdapter->rWlanInfo.arScanResult[i] + .u4IELength > 0) { + if (prAdapter->rWlanInfo + .apucScanResultIEs[i] != + &(prAdapter->rWlanInfo + .aucScanIEBuf[0])) { + /* move IEs to head */ + kalMemCopy( + prAdapter->rWlanInfo + .aucScanIEBuf, + prAdapter->rWlanInfo + .apucScanResultIEs + [i], + prAdapter->rWlanInfo + .arScanResult[i] + .u4IELength); + } + /* modify IE pointer */ + prAdapter->rWlanInfo + .apucScanResultIEs[0] = + &(prAdapter->rWlanInfo + .aucScanIEBuf[0]); + } else { + prAdapter->rWlanInfo + .apucScanResultIEs[0] = NULL; + } + + break; + } + } + } + + if (fgKeepCurrOne == true) { + prAdapter->rWlanInfo.u4ScanResultNum = 1; + prAdapter->rWlanInfo.u4ScanIEBufferUsage = ALIGN_4( + prAdapter->rWlanInfo.arScanResult[0].u4IELength); + } else { + prAdapter->rWlanInfo.u4ScanResultNum = 0; + prAdapter->rWlanInfo.u4ScanIEBufferUsage = 0; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called when AIS received a beacon timeout event + * + * @param prAdapter Pointer of Adapter Data Structure + * @param arBSSID MAC address of the specified BSS + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void wlanClearBssInScanningResult(IN P_ADAPTER_T prAdapter, IN u8 *arBSSID) +{ + u32 i, j, u4IELength = 0, u4IEMoveLength; + u8 *pucIEPtr; + + ASSERT(prAdapter); + + /* clear scanning result */ + i = 0; + while (1) { + if (i >= prAdapter->rWlanInfo.u4ScanResultNum) { + break; + } + + if (EQUAL_MAC_ADDR(arBSSID, prAdapter->rWlanInfo.arScanResult[i] + .arMacAddress)) { + /* backup current IE length */ + u4IELength = ALIGN_4( + prAdapter->rWlanInfo.arScanResult[i].u4IELength); + pucIEPtr = prAdapter->rWlanInfo.apucScanResultIEs[i]; + + /* removed from middle */ + for (j = i + 1; + j < prAdapter->rWlanInfo.u4ScanResultNum; j++) { + kalMemCopy( + &(prAdapter->rWlanInfo + .arScanResult[j - 1]), + &(prAdapter->rWlanInfo.arScanResult[j]), + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + prAdapter->rWlanInfo.apucScanResultIEs[j - 1] = + prAdapter->rWlanInfo + .apucScanResultIEs[j]; + } + + prAdapter->rWlanInfo.u4ScanResultNum--; + + /* remove IE buffer if needed := move rest of IE buffer + */ + if (u4IELength > 0) { + u4IEMoveLength = + prAdapter->rWlanInfo + .u4ScanIEBufferUsage - + (((unsigned long)pucIEPtr) + + u4IELength - + ((unsigned long)(&( + prAdapter-> + rWlanInfo + .aucScanIEBuf[ + 0])))); + + kalMemCopy(pucIEPtr, + (u8 *)(((unsigned long)pucIEPtr) + + u4IELength), + u4IEMoveLength); + + prAdapter->rWlanInfo.u4ScanIEBufferUsage -= + u4IELength; + + /* correction of pointers to IE buffer */ + for (j = 0; + j < prAdapter->rWlanInfo.u4ScanResultNum; + j++) { + if (prAdapter->rWlanInfo + .apucScanResultIEs[j] > + pucIEPtr) { + prAdapter->rWlanInfo + .apucScanResultIEs[j] = + (u8 *)((unsigned long)( + prAdapter + -> + rWlanInfo + . + apucScanResultIEs + [ + j]) + - + u4IELength); + } + } + } + } + + i++; + } +} + +#if CFG_TEST_WIFI_DIRECT_GO + +void wlanEnableATGO(IN P_ADAPTER_T prAdapter) +{ + P_MSG_P2P_CONNECTION_REQUEST_T prMsgConnReq = + (P_MSG_P2P_CONNECTION_REQUEST_T)NULL; + u8 aucTargetDeviceID[MAC_ADDR_LEN] = { 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF }; + + prMsgConnReq = (P_MSG_P2P_CONNECTION_REQUEST_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_REQUEST_T)); + if (!prMsgConnReq) { + ASSERT(false); + return; + } + + prMsgConnReq->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; + + /*=====Param Modified for test=====*/ + COPY_MAC_ADDR(prMsgConnReq->aucDeviceID, aucTargetDeviceID); + prMsgConnReq->fgIsTobeGO = true; + prMsgConnReq->fgIsPersistentGroup = false; + + /*=====Param Modified for test=====*/ + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsgConnReq, + MSG_SEND_METHOD_BUF); +} +#endif + +void wlanPrintVersion(IN P_ADAPTER_T prAdapter) +{ + P_WIFI_VER_INFO_T prVerInfo = &prAdapter->rVerInfo; + tailer_format_t *prTailer; + u8 aucBuf[32], aucDate[32]; + + kalMemCopy(aucBuf, prVerInfo->aucFwBranchInfo, 4); + aucBuf[4] = '\0'; + dev_info(prAdapter->prGlueInfo->prDev, + "N9 FW version %s-%u.%u.%u[DEC] (%s)\n", aucBuf, + (prVerInfo->u2FwOwnVersion >> 8), + (prVerInfo->u2FwOwnVersion & BITS(0, 7)), + prVerInfo->ucFwBuildNumber, prVerInfo->aucFwDateCode); +#if CFG_SUPPORT_COMPRESSION_FW_OPTION + if (prVerInfo->fgIsN9CompressedFW) { + tailer_format_t_2 *prTailer; + + prTailer = &prVerInfo->rN9Compressedtailer; + kalMemCopy(aucBuf, prTailer->ram_version, 10); + aucBuf[10] = '\0'; + DBGLOG(SW4, INFO, "N9 tailer version %s (%s) info %u:E%u\n", + aucBuf, prTailer->ram_built_date, prTailer->chip_info, + prTailer->eco_code + 1); + } else { + prTailer = &prVerInfo->rN9tailer; + kalMemCopy(aucBuf, prTailer->ram_version, 10); + aucBuf[10] = '\0'; + DBGLOG(SW4, INFO, "N9 tailer version %s (%s) info %u:E%u\n", + aucBuf, prTailer->ram_built_date, prTailer->chip_info, + prTailer->eco_code + 1); + } + if (prVerInfo->fgIsCR4CompressedFW) { + tailer_format_t_2 *prTailer; + + prTailer = &prVerInfo->rCR4Compressedtailer; + kalMemCopy(aucBuf, prTailer->ram_version, 10); + aucBuf[10] = '\0'; + DBGLOG(SW4, INFO, "CR4 tailer version %s (%s) info %u:E%u\n", + aucBuf, prTailer->ram_built_date, prTailer->chip_info, + prTailer->eco_code + 1); + } else { + prTailer = &prVerInfo->rCR4tailer; + kalMemCopy(aucBuf, prTailer->ram_version, 10); + aucBuf[10] = '\0'; + DBGLOG(SW4, INFO, "CR4 tailer version %s (%s) info %u:E%u\n", + aucBuf, prTailer->ram_built_date, prTailer->chip_info, + prTailer->eco_code + 1); + } +#else + prTailer = &prVerInfo->rN9tailer; + kalMemCopy(aucBuf, prTailer->ram_version, 10); + aucBuf[10] = '\0'; + dev_info(prAdapter->prGlueInfo->prDev, + "N9 tailer version %s (%s) info %u:E%u\n", aucBuf, + prTailer->ram_built_date, prTailer->chip_info, + prTailer->eco_code + 1); + + prTailer = &prVerInfo->rCR4tailer; + kalMemCopy(aucBuf, prTailer->ram_version, 10); + aucBuf[10] = '\0'; + dev_info(prAdapter->prGlueInfo->prDev, + "CR4 tailer version %s (%s) info %u:E%u\n", aucBuf, + prTailer->ram_built_date, prTailer->chip_info, + prTailer->eco_code + 1); +#endif + + kalStrnCpy(aucBuf, prVerInfo->rPatchHeader.aucPlatform, 4); + aucBuf[4] = '\0'; + kalStrnCpy(aucDate, prVerInfo->rPatchHeader.aucBuildDate, 16); + aucDate[16] = '\0'; + dev_info(prAdapter->prGlueInfo->prDev, + "Patch platform %s version 0x%04X %s", aucBuf, + prVerInfo->rPatchHeader.u4PatchVersion, aucDate); + + dev_info(prAdapter->prGlueInfo->prDev, "Drv version %u.%u[DEC]\n", + (prVerInfo->u2FwPeerVersion >> 8), + (prVerInfo->u2FwPeerVersion & BITS(0, 7))); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to retrieve NIC capability from firmware + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return WLAN_STATUS_SUCCESS + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryNicCapability(IN P_ADAPTER_T prAdapter) +{ + u8 aucZeroMacAddr[] = NULL_MAC_ADDR; + u8 ucCmdSeqNum; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + u32 u4RxPktLength; + u8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(EVENT_NIC_CAPABILITY_T)]; + P_HW_MAC_RX_DESC_T prRxStatus; + P_WIFI_EVENT_T prEvent; + P_EVENT_NIC_CAPABILITY_T prEventNicCapability; + P_PSE_CMD_HDR_T prPseCmdHdr; + + ASSERT(prAdapter); + + DEBUGFUNC("wlanQueryNicCapability"); + + /* 1. Allocate CMD Info Packet and its Buffer */ + prCmdInfo = cmdBufAllocateCmdInfo( + prAdapter, CMD_HDR_SIZE + sizeof(EVENT_NIC_CAPABILITY_T)); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_BUILD_CONNECTION cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(EVENT_NIC_CAPABILITY_T); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->fgIsOid = false; + prCmdInfo->ucCID = CMD_ID_GET_NIC_CAPABILITY; + prCmdInfo->fgSetQuery = false; + prCmdInfo->fgNeedResp = true; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = 0; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prPseCmdHdr = (P_PSE_CMD_HDR_T)(prCmdInfo->pucInfoBuffer); + prPseCmdHdr->u2Qidx = TXD_Q_IDX_MCU_RQ0; + prPseCmdHdr->u2Pidx = TXD_P_IDX_MCU; + prPseCmdHdr->u2Hf = TXD_HF_CMD; + prPseCmdHdr->u2Ft = TXD_FT_LONG_FORMAT; + prPseCmdHdr->u2PktFt = TXD_PKT_FT_CMD; + + prWifiCmd->u2Length = prWifiCmd->u2TxByteCount - sizeof(PSE_CMD_HDR_T); + + wlanSendCommand(prAdapter, prCmdInfo); + + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + while (true) { + if (nicRxWaitResponse(prAdapter, 1, aucBuffer, + sizeof(WIFI_EVENT_T) + + sizeof(EVENT_NIC_CAPABILITY_T), + &u4RxPktLength) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, WARN, "%s: wait for event failed!\n", + __func__); + return WLAN_STATUS_FAILURE; + } + /* header checking .. */ + prRxStatus = (P_HW_MAC_RX_DESC_T)aucBuffer; + if (prRxStatus->u2PktTYpe != RXM_RXD_PKT_TYPE_SW_EVENT) { + DBGLOG(INIT, WARN, + "%s: skip unexpected Rx pkt type[0x%04x]\n", + __func__, prRxStatus->u2PktTYpe); + continue; + } + + prEvent = (P_WIFI_EVENT_T)aucBuffer; + if (prEvent->ucEID != EVENT_ID_NIC_CAPABILITY) { + DBGLOG(INIT, INFO, + "%s: skip unexpected event ID[0x%02x]\n", + __func__, prEvent->ucEID); + continue; + } else { + break; + } + } + + prEventNicCapability = (P_EVENT_NIC_CAPABILITY_T)(prEvent->aucBuffer); + + prAdapter->rVerInfo.u2FwProductID = prEventNicCapability->u2ProductID; + kalMemCopy(prAdapter->rVerInfo.aucFwBranchInfo, + prEventNicCapability->aucBranchInfo, 4); + prAdapter->rVerInfo.u2FwOwnVersion = prEventNicCapability->u2FwVersion; + prAdapter->rVerInfo.ucFwBuildNumber = + prEventNicCapability->ucFwBuildNumber; + kalMemCopy(prAdapter->rVerInfo.aucFwDateCode, + prEventNicCapability->aucDateCode, 16); + prAdapter->rVerInfo.u2FwPeerVersion = + prEventNicCapability->u2DriverVersion; + prAdapter->fgIsHw5GBandDisabled = + (u8)prEventNicCapability->ucHw5GBandDisabled; + prAdapter->fgIsEepromUsed = (u8)prEventNicCapability->ucEepromUsed; + prAdapter->fgIsEmbbededMacAddrValid = + (u8)(!IS_BMCAST_MAC_ADDR(prEventNicCapability->aucMacAddr) && + !EQUAL_MAC_ADDR(aucZeroMacAddr, + prEventNicCapability->aucMacAddr)); + + COPY_MAC_ADDR(prAdapter->rWifiVar.aucPermanentAddress, + prEventNicCapability->aucMacAddr); + COPY_MAC_ADDR(prAdapter->rWifiVar.aucMacAddress, + prEventNicCapability->aucMacAddr); + + prAdapter->rWifiVar.ucStaVht &= + (!(prEventNicCapability->ucHwNotSupportAC)); + prAdapter->rWifiVar.ucApVht &= + (!(prEventNicCapability->ucHwNotSupportAC)); + prAdapter->rWifiVar.ucP2pGoVht &= + (!(prEventNicCapability->ucHwNotSupportAC)); + prAdapter->rWifiVar.ucP2pGcVht &= + (!(prEventNicCapability->ucHwNotSupportAC)); + + prAdapter->rWifiVar.ucStaVhtBfee &= + (!(prEventNicCapability->ucHwNotSupportAC)); + prAdapter->rWifiVar.ucStaVhtMuBfee &= + (!(prEventNicCapability->ucHwNotSupportAC)); + prAdapter->rWifiVar.ucStaVhtBfer &= + (!(prEventNicCapability->ucHwNotSupportAC)); + + prAdapter->rWifiVar.ucVhtAmsduInAmpduRx &= + (!(prEventNicCapability->ucHwNotSupportAC)); + prAdapter->rWifiVar.ucVhtAmsduInAmpduTx &= + (!(prEventNicCapability->ucHwNotSupportAC)); + + if (prEventNicCapability->ucHwNotSupportAC) { + prAdapter->rWifiVar.ucStaBandwidth = MAX_BW_40MHZ; + prAdapter->rWifiVar.ucSta5gBandwidth = MAX_BW_40MHZ; + prAdapter->rWifiVar.ucP2p5gBandwidth = MAX_BW_40MHZ; + prAdapter->rWifiVar.ucApBandwidth = MAX_BW_40MHZ; + prAdapter->rWifiVar.ucAp5gBandwidth = MAX_BW_40MHZ; + } + + prAdapter->u4FwCompileFlag0 = prEventNicCapability->u4CompileFlag0; + prAdapter->u4FwCompileFlag1 = prEventNicCapability->u4CompileFlag1; + prAdapter->u4FwFeatureFlag0 = prEventNicCapability->u4FeatureFlag0; + prAdapter->u4FwFeatureFlag1 = prEventNicCapability->u4FeatureFlag1; + + if (prEventNicCapability->ucHwSetNss1x1) { + prAdapter->rWifiVar.ucNSS = 1; + } + +#if CFG_SUPPORT_DBDC + if (prEventNicCapability->ucHwNotSupportDBDC) { + prAdapter->rWifiVar.ucDbdcMode = DBDC_MODE_DISABLED; + } +#endif + +#if CFG_ENABLE_CAL_LOG + DBGLOG(INIT, TRACE, "RF CAL FAIL = (%d),BB CAL FAIL = (%d)\n", + prEventNicCapability->ucRfCalFail, + prEventNicCapability->ucBbCalFail); +#endif + +#if CFG_SISO_SW_DEVELOP + if ((!prEventNicCapability->ucHwNotSupportDBDC) && + (!prEventNicCapability->ucHwSetNss1x1) && + (!prEventNicCapability->ucHwWiFiZeroOnly)) { + prAdapter->rWifiFemCfg.u2WifiPath = + (WLAN_FLAG_2G4_WF0 | WLAN_FLAG_5G_WF0 | + WLAN_FLAG_2G4_WF1 | WLAN_FLAG_5G_WF1); + } else if ((!prEventNicCapability->ucHwNotSupportDBDC) && + (prEventNicCapability->ucHwSetNss1x1) && + (!prEventNicCapability->ucHwWiFiZeroOnly)) { + prAdapter->rWifiFemCfg.u2WifiPath = + (WLAN_FLAG_5G_WF0 | WLAN_FLAG_2G4_WF1); + } else if ((prEventNicCapability->ucHwNotSupportDBDC) && + (prEventNicCapability->ucHwSetNss1x1) && + (!prEventNicCapability->ucHwWiFiZeroOnly)) { + prAdapter->rWifiFemCfg.u2WifiPath = + (WLAN_FLAG_5G_WF0 | WLAN_FLAG_2G4_WF1); + } else if ((prEventNicCapability->ucHwNotSupportDBDC) && + (!prEventNicCapability->ucHwSetNss1x1) && + (!prEventNicCapability->ucHwWiFiZeroOnly)) { + prAdapter->rWifiFemCfg.u2WifiPath = + (WLAN_FLAG_2G4_WF0 | WLAN_FLAG_5G_WF0 | + WLAN_FLAG_2G4_WF1 | WLAN_FLAG_5G_WF1); + } else if ((prEventNicCapability->ucHwNotSupportDBDC) && + (prEventNicCapability->ucHwSetNss1x1) && + (prEventNicCapability->ucHwWiFiZeroOnly)) { + prAdapter->rWifiFemCfg.u2WifiPath = + (WLAN_FLAG_2G4_WF0 | WLAN_FLAG_5G_WF0); + } else { + DBGLOG(INIT, ERROR, "ucHwNotSupportDBDC = %d\n", + prEventNicCapability->ucHwNotSupportDBDC); + DBGLOG(INIT, ERROR, "ucHwSetNss1x1 = %d\n", + prEventNicCapability->ucHwSetNss1x1); + DBGLOG(INIT, ERROR, "ucHwWiFiZeroOnly = %d\n", + prEventNicCapability->ucHwWiFiZeroOnly); + ASSERT(0); + } + + DBGLOG(INIT, INFO, "wifi path = %8x\n", + prAdapter->rWifiFemCfg.u2WifiPath); +#endif + + return WLAN_STATUS_SUCCESS; +} + +#if TXPWR_USE_PDSLOPE + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return WLAN_STATUS_SUCCESS + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryPdMcr(IN P_ADAPTER_T prAdapter, + P_PARAM_MCR_RW_STRUCT_T prMcrRdInfo) +{ + u8 ucCmdSeqNum; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + u32 u4RxPktLength; + u8 aucBuffer[sizeof(WIFI_EVENT_T) + sizeof(CMD_ACCESS_REG)]; + P_HW_MAC_RX_DESC_T prRxStatus; + P_WIFI_EVENT_T prEvent; + P_CMD_ACCESS_REG prCmdMcrQuery; + + ASSERT(prAdapter); + + /* 1. Allocate CMD Info Packet and its Buffer */ + prCmdInfo = cmdBufAllocateCmdInfo( + prAdapter, CMD_HDR_SIZE + sizeof(CMD_ACCESS_REG)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_BUILD_CONNECTION cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = (u16)(CMD_HDR_SIZE + sizeof(CMD_ACCESS_REG)); + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = false; + prCmdInfo->ucCID = CMD_ID_ACCESS_REG; + prCmdInfo->fgSetQuery = false; + prCmdInfo->fgNeedResp = true; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_ACCESS_REG); + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + kalMemCopy(prWifiCmd->aucBuffer, prMcrRdInfo, sizeof(CMD_ACCESS_REG)); + + wlanSendCommand(prAdapter, prCmdInfo); + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + if (nicRxWaitResponse(prAdapter, 1, aucBuffer, + sizeof(WIFI_EVENT_T) + sizeof(CMD_ACCESS_REG), + &u4RxPktLength) != WLAN_STATUS_SUCCESS) { + return WLAN_STATUS_FAILURE; + } + /* header checking .. */ + prRxStatus = (P_HW_MAC_RX_DESC_T)aucBuffer; + if (prRxStatus->u2PktTYpe != RXM_RXD_PKT_TYPE_SW_EVENT) { + return WLAN_STATUS_FAILURE; + } + + prEvent = (P_WIFI_EVENT_T)aucBuffer; + + if (prEvent->ucEID != EVENT_ID_ACCESS_REG) { + return WLAN_STATUS_FAILURE; + } + + prCmdMcrQuery = (P_CMD_ACCESS_REG)(prEvent->aucBuffer); + prMcrRdInfo->u4McrOffset = prCmdMcrQuery->u4Address; + prMcrRdInfo->u4McrData = prCmdMcrQuery->u4Data; + + return WLAN_STATUS_SUCCESS; +} + +static s32 wlanIntRound(s32 au4Input) +{ + if (au4Input >= 0) { + if ((au4Input % 10) == 5) { + au4Input = au4Input + 5; + return au4Input; + } + } + + if (au4Input < 0) { + if ((au4Input % 10) == -5) { + au4Input = au4Input - 5; + return au4Input; + } + } + + return au4Input; +} + +static s32 wlanCal6628EfuseForm(IN P_ADAPTER_T prAdapter, s32 au4Input) +{ + PARAM_MCR_RW_STRUCT_T rMcrRdInfo; + s32 au4PdSlope, au4TxPwrOffset, au4TxPwrOffset_Round; + s8 auTxPwrOffset_Round; + + rMcrRdInfo.u4McrOffset = 0x60205c68; + rMcrRdInfo.u4McrData = 0; + au4TxPwrOffset = au4Input; + wlanQueryPdMcr(prAdapter, &rMcrRdInfo); + + au4PdSlope = (rMcrRdInfo.u4McrData) & BITS(0, 6); + au4TxPwrOffset_Round = wlanIntRound((au4TxPwrOffset * au4PdSlope)) / 10; + + au4TxPwrOffset_Round = -au4TxPwrOffset_Round; + + if (au4TxPwrOffset_Round < -128) { + au4TxPwrOffset_Round = 128; + }else if (au4TxPwrOffset_Round < 0) { + au4TxPwrOffset_Round += 256; + }else if (au4TxPwrOffset_Round > 127) { + au4TxPwrOffset_Round = 127; + } + + auTxPwrOffset_Round = (u8)au4TxPwrOffset_Round; + + return au4TxPwrOffset_Round; +} + +#endif + +#if CFG_SUPPORT_NVRAM_5G +WLAN_STATUS wlanLoadManufactureData_5G(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo) +{ + P_BANDEDGE_5G_T pr5GBandEdge; + + ASSERT(prAdapter); + + pr5GBandEdge = &prRegInfo->prOldEfuseMapping->r5GBandEdgePwr; + + /* 1. set band edge tx power if available */ + if (pr5GBandEdge->uc5GBandEdgePwrUsed != 0) { + CMD_EDGE_TXPWR_LIMIT_T rCmdEdgeTxPwrLimit; + kalMemZero(&rCmdEdgeTxPwrLimit, sizeof(CMD_EDGE_TXPWR_LIMIT_T)); + + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrCCK = 0; + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20 = + pr5GBandEdge->c5GBandEdgeMaxPwrOFDM20; + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40 = + pr5GBandEdge->c5GBandEdgeMaxPwrOFDM40; + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM80 = + pr5GBandEdge->c5GBandEdgeMaxPwrOFDM80; + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_EDGE_TXPWR_LIMIT_5G, + true, false, false, NULL, NULL, + sizeof(CMD_EDGE_TXPWR_LIMIT_T), + (u8 *)&rCmdEdgeTxPwrLimit, NULL, 0); + + /* dumpMemory8(&rCmdEdgeTxPwrLimit,4); */ + } + + DEBUGFUNC("wlanLoadManufactureData_5G"); + + /*2.set channel offset for 8 sub-band */ + if (prRegInfo->prOldEfuseMapping->uc5GChannelOffsetVaild) { + CMD_POWER_OFFSET_T rCmdPowerOffset; + u8 i; + + rCmdPowerOffset.ucBand = BAND_5G; + for (i = 0; i < MAX_SUBBAND_NUM_5G; i++) + rCmdPowerOffset.ucSubBandOffset[i] = + prRegInfo->prOldEfuseMapping->auc5GChOffset[i]; + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_CHANNEL_PWR_OFFSET, + true, false, false, NULL, NULL, + sizeof(rCmdPowerOffset), + (u8 *)&rCmdPowerOffset, NULL, 0); + /* dumpMemory8(&rCmdPowerOffset,9); */ + } + + /*3.set 5G AC power */ + if (prRegInfo->prOldEfuseMapping->uc11AcTxPwrValid) { + CMD_TX_AC_PWR_T rCmdAcPwr; + + kalMemCopy(&rCmdAcPwr.rAcPwr, + &prRegInfo->prOldEfuseMapping->r11AcTxPwr, + sizeof(AC_PWR_SETTING_STRUCT)); + rCmdAcPwr.ucBand = BAND_5G; + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_80211AC_TX_PWR, true, + false, false, NULL, NULL, + sizeof(CMD_TX_AC_PWR_T), (u8 *)&rCmdAcPwr, + NULL, 0); + /* dumpMemory8(&rCmdAcPwr,9); */ + } + + return WLAN_STATUS_SUCCESS; +} +#endif +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to load manufacture data from NVRAM + * if available and valid + * + * @param prAdapter Pointer of Adapter Data Structure + * @param prRegInfo Pointer of REG_INFO_T + * + * @return WLAN_STATUS_SUCCESS + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanLoadManufactureData(IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo) +{ +#if CFG_SUPPORT_RDD_TEST_MODE + CMD_RDD_CH_T rRddParam; +#endif + CMD_NVRAM_SETTING_T rCmdNvramSettings; + + kalMemZero(&rCmdNvramSettings, sizeof(CMD_NVRAM_SETTING_T)); + ASSERT(prAdapter); + + /* 1. Version Check */ + kalGetConfigurationVersion( + prAdapter->prGlueInfo, + &(prAdapter->rVerInfo.u2Part1CfgOwnVersion), + &(prAdapter->rVerInfo.u2Part1CfgPeerVersion), + &(prAdapter->rVerInfo.u2Part2CfgOwnVersion), + &(prAdapter->rVerInfo.u2Part2CfgPeerVersion)); + +#if (CFG_SW_NVRAM_VERSION_CHECK == 1) + if (prAdapter->rVerInfo.u2Part1CfgPeerVersion > CFG_DRV_OWN_VERSION || + prAdapter->rVerInfo.u2Part2CfgPeerVersion > CFG_DRV_OWN_VERSION || + prAdapter->rVerInfo.u2Part1CfgOwnVersion < CFG_DRV_PEER_VERSION || + prAdapter->rVerInfo.u2Part2CfgOwnVersion < CFG_DRV_PEER_VERSION) { + return WLAN_STATUS_FAILURE; + } +#endif + + /* MT6620 E1/E2 would be ignored directly */ + if (prAdapter->rVerInfo.u2Part1CfgOwnVersion == 0x0001) { + prRegInfo->ucTxPwrValid = 1; + } else { + /* 2. Load TX power gain parameters if valid */ + if (prRegInfo->ucTxPwrValid != 0) { + /* send to F/W */ + + nicUpdateTxPower( + prAdapter, + (P_CMD_TX_PWR_T)(&(prRegInfo->rTxPwr))); + } + } + + /* Todo : Temp Open 20150806 Sam */ + prRegInfo->ucEnable5GBand = 1; + prRegInfo->ucSupport5GBand = 1; + + /* 3. Check if needs to support 5GHz */ + if (prRegInfo->ucEnable5GBand) { +#if CFG_SUPPORT_NVRAM_5G + wlanLoadManufactureData_5G(prAdapter, prRegInfo); +#endif + /* check if it is disabled by hardware */ + if (prAdapter->fgIsHw5GBandDisabled || + prRegInfo->ucSupport5GBand == 0) { + prAdapter->fgEnable5GBand = false; + }else{ + prAdapter->fgEnable5GBand = true; + } + } else { + prAdapter->fgEnable5GBand = false; + } + + /* 4. Send EFUSE data */ +#if CFG_SUPPORT_NVRAM_5G + /* If NvRAM read failed, this pointer will be NULL */ + if (prRegInfo->prOldEfuseMapping) { + /*2.set channel offset for 3 sub-band */ + if (prRegInfo->prOldEfuseMapping->ucChannelOffsetVaild) { + CMD_POWER_OFFSET_T rCmdPowerOffset; + u8 i; + + kalMemZero(&rCmdPowerOffset, + sizeof(CMD_POWER_OFFSET_T)); + rCmdPowerOffset.ucBand = BAND_2G4; + for (i = 0; i < 3; i++) + rCmdPowerOffset.ucSubBandOffset[i] = + prRegInfo->prOldEfuseMapping + ->aucChOffset[i]; + rCmdPowerOffset.ucSubBandOffset[i] = + prRegInfo->prOldEfuseMapping->acAllChannelOffset; + + wlanSendSetQueryCmd(prAdapter, + CMD_ID_SET_CHANNEL_PWR_OFFSET, true, + false, false, NULL, NULL, + sizeof(rCmdPowerOffset), + (u8 *)&rCmdPowerOffset, NULL, 0); + /* dumpMemory8(&rCmdPowerOffset,9); */ + } + } +#else + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_PHY_PARAM, true, false, false, + NULL, NULL, sizeof(CMD_PHY_PARAM_T), + (u8 *)(prRegInfo->aucEFUSE), NULL, 0); +#endif + /*RSSI path compasation */ + if (prRegInfo->ucRssiPathCompasationUsed) { + CMD_RSSI_PATH_COMPASATION_T rCmdRssiPathCompasation; + kalMemZero(&rCmdRssiPathCompasation, + sizeof(CMD_RSSI_PATH_COMPASATION_T)); + + rCmdRssiPathCompasation.c2GRssiCompensation = + prRegInfo->rRssiPathCompasation.c2GRssiCompensation; + rCmdRssiPathCompasation.c5GRssiCompensation = + prRegInfo->rRssiPathCompasation.c5GRssiCompensation; + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_PATH_COMPASATION, + true, false, false, NULL, NULL, + sizeof(rCmdRssiPathCompasation), + (u8 *)&rCmdRssiPathCompasation, NULL, 0); + } +#if CFG_SUPPORT_RDD_TEST_MODE + rRddParam.ucRddTestMode = (u8)prRegInfo->u4RddTestMode; + rRddParam.ucRddShutCh = (u8)prRegInfo->u4RddShutFreq; + rRddParam.ucRddStartCh = + (u8)nicFreq2ChannelNum(prRegInfo->u4RddStartFreq); + rRddParam.ucRddStopCh = + (u8)nicFreq2ChannelNum(prRegInfo->u4RddStopFreq); + rRddParam.ucRddDfs = (u8)prRegInfo->u4RddDfs; + prAdapter->ucRddStatus = 0; + nicUpdateRddTestMode(prAdapter, (P_CMD_RDD_CH_T)(&rRddParam)); +#endif + + /* 5. Get 16-bits Country Code and Bandwidth */ + prAdapter->rWifiVar.rConnSettings.u2CountryCode = + (((u16)prRegInfo->au2CountryCode[0]) << 8) | + (((u16)prRegInfo->au2CountryCode[1]) & BITS(0, 7)); + + /* 6. Set domain and channel information to chip */ + rlmDomainSendCmd(prAdapter, false); + + /* Update supported channel list in channel table */ + wlanUpdateChannelTable(prAdapter->prGlueInfo); + + /* 7. set band edge tx power if available */ + if (prRegInfo->fg2G4BandEdgePwrUsed) { + CMD_EDGE_TXPWR_LIMIT_T rCmdEdgeTxPwrLimit; + kalMemZero(&rCmdEdgeTxPwrLimit, sizeof(CMD_EDGE_TXPWR_LIMIT_T)); + + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrCCK = + prRegInfo->cBandEdgeMaxPwrCCK; + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM20 = + prRegInfo->cBandEdgeMaxPwrOFDM20; + rCmdEdgeTxPwrLimit.cBandEdgeMaxPwrOFDM40 = + prRegInfo->cBandEdgeMaxPwrOFDM40; + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_EDGE_TXPWR_LIMIT, + true, false, false, NULL, NULL, + sizeof(CMD_EDGE_TXPWR_LIMIT_T), + (u8 *)&rCmdEdgeTxPwrLimit, NULL, 0); + } + /*8. Set 2.4G AC power */ + if (prRegInfo->prOldEfuseMapping && + prRegInfo->prOldEfuseMapping->uc11AcTxPwrValid2G) { + CMD_TX_AC_PWR_T rCmdAcPwr; + + kalMemZero(&rCmdAcPwr, sizeof(CMD_TX_AC_PWR_T)); + kalMemCopy(&rCmdAcPwr.rAcPwr, + &prRegInfo->prOldEfuseMapping->r11AcTxPwr2G, + sizeof(AC_PWR_SETTING_STRUCT)); + rCmdAcPwr.ucBand = BAND_2G4; + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_80211AC_TX_PWR, true, + false, false, NULL, NULL, + sizeof(CMD_TX_AC_PWR_T), (u8 *)&rCmdAcPwr, + NULL, 0); + /* dumpMemory8(&rCmdAcPwr,9); */ + } + /* 9. Send the full Parameters of NVRAM to FW */ + + kalMemCopy(&rCmdNvramSettings.rNvramSettings, + &prRegInfo->prNvramSettings->u2Part1OwnVersion, + sizeof(WIFI_CFG_PARAM_STRUCT)); + ASSERT(sizeof(WIFI_CFG_PARAM_STRUCT) == 512); + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_NVRAM_SETTINGS, true, false, + false, NULL, NULL, sizeof(rCmdNvramSettings), + (u8 *)&rCmdNvramSettings, NULL, 0); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to check + * Media Stream Mode is set to non-default value or not, + * and clear to default value if above criteria is met + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return true + * The media stream mode was non-default value and has been reset + * false + * The media stream mode is default value + */ +/*----------------------------------------------------------------------------*/ +u8 wlanResetMediaStreamMode(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + if (prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode != 0) { + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 0; + + return true; + } else { + return false; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to check if any pending timer has expired + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanTimerTimeoutCheck(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + cnmTimerDoTimeOutCheck(prAdapter); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to check if any pending mailbox message + * to be handled + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanProcessMboxMessage(IN P_ADAPTER_T prAdapter) +{ + u32 i; + + ASSERT(prAdapter); + + for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) + mboxRcvAllMsg(prAdapter, (ENUM_MBOX_ID_T)i); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to enqueue a single TX packet into CORE + * + * @param prAdapter Pointer of Adapter Data Structure + * prNativePacket Pointer of Native Packet + * + * @return WLAN_STATUS_SUCCESS + * WLAN_STATUS_RESOURCES + * WLAN_STATUS_INVALID_PACKET + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanEnqueueTxPacket(IN P_ADAPTER_T prAdapter, + IN P_NATIVE_PACKET prNativePacket) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo; +#if !DBG_DISABLE_ALL_LOG + struct sk_buff *prSkb = (struct sk_buff *)prNativePacket; +#endif + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + + prMsduInfo = cnmPktAlloc(prAdapter, 0); + + if (!prMsduInfo) { + return WLAN_STATUS_RESOURCES; + } + + if (nicTxFillMsduInfo(prAdapter, prMsduInfo, prNativePacket)) { + /* prMsduInfo->eSrc = TX_PACKET_OS; */ + + if (prMsduInfo->fgIs802_1x) { + P_STA_RECORD_T prStaRec; + prStaRec = cnmGetStaRecByAddress( + prAdapter, prMsduInfo->ucBssIndex, + prMsduInfo->aucEthDestAddr); + + if (prStaRec) { + if (!prStaRec->fgIsValid) { + DBGLOG(INIT, + WARN, + "%s: Free MSDU of 1X PKT [Len: %d] due to StaRec is still invalid\n", + __func__, + prSkb->len); + prMsduInfo->prPacket = NULL; + cnmPktFree(prAdapter, prMsduInfo); + return WLAN_STATUS_PENDING; + } + } + + prAdapter->r1xTxDoneStatus = TX_RESULT_1XTX_CLEAR; + if (prAdapter->fgIsTest1xTx == 1) { + DBGLOG(RSN, + STATE, + "%s: (fgIsTest1xTx == 1) test 1XTX frame skip\n", + __func__); + cnmPktFree(prAdapter, prMsduInfo); + return WLAN_STATUS_SUCCESS; + } + } + + /* Tx profiling */ + wlanTxProfilingTagMsdu(prAdapter, prMsduInfo, + TX_PROF_TAG_DRV_ENQUE); + + /* enqueue to QM */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; + } + kalSendComplete(prAdapter->prGlueInfo, prNativePacket, + WLAN_STATUS_INVALID_PACKET); + + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + + return WLAN_STATUS_INVALID_PACKET; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to flush pending TX packets in CORE + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanFlushTxPendingPackets(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + return nicTxFlush(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief this function sends pending MSDU_INFO_T to MT6620 + * + * @param prAdapter Pointer to the Adapter structure. + * @param pfgHwAccess Pointer for tracking LP-OWN status + * + * @retval WLAN_STATUS_SUCCESS Reset is done successfully. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanTxPendingPackets(IN P_ADAPTER_T prAdapter, + IN OUT u8 *pfgHwAccess) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + prMsduInfo = qmDequeueTxPacketsMthread(prAdapter, &prTxCtrl->rTc); + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + + if (prMsduInfo != NULL) { + if (kalIsCardRemoved(prAdapter->prGlueInfo) == false) { + /* <3> send packets */ + nicTxMsduInfoListMthread(prAdapter, prMsduInfo); + + /* <4> update TC by txAdjustTcQuotas() */ + nicTxAdjustTcq(prAdapter); + } else { + wlanProcessQueuedMsduInfo(prAdapter, prMsduInfo); + } + } + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to acquire power control from firmware + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanAcquirePowerControl(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + /* DBGLOG(INIT, INFO, ("Acquire Power Ctrl\n")); */ + + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + + /* Reset sleepy state */ + if (prAdapter->fgWiFiInSleepyState == true) { + prAdapter->fgWiFiInSleepyState = false; + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to release power control to firmware + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanReleasePowerControl(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + /* DBGLOG(INIT, INFO, ("Release Power Ctrl\n")); */ + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, false); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to report currently pending TX frames count + * (command packets are not included) + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return number of pending TX frames + */ +/*----------------------------------------------------------------------------*/ +u32 wlanGetTxPendingFrameCount(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + u32 u4Num; + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + u4Num = kalGetTxPendingFrameCount(prAdapter->prGlueInfo) + + (u32)GLUE_GET_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); + + return u4Num; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to report current ACPI state + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return ACPI_STATE_D0 Normal Operation Mode + * ACPI_STATE_D3 Suspend Mode + */ +/*----------------------------------------------------------------------------*/ +ENUM_ACPI_STATE_T wlanGetAcpiState(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + return prAdapter->rAcpiState; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to update current ACPI state only + * + * @param prAdapter Pointer of Adapter Data Structure + * @param ePowerState ACPI_STATE_D0 Normal Operation Mode + * ACPI_STATE_D3 Suspend Mode + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void wlanSetAcpiState(IN P_ADAPTER_T prAdapter, + IN ENUM_ACPI_STATE_T ePowerState) +{ + ASSERT(prAdapter); + ASSERT(ePowerState <= ACPI_STATE_D3); + + prAdapter->rAcpiState = ePowerState; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to query ECO version from HIFSYS CR + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return zero Unable to retrieve ECO version information + * non-zero ECO version (1-based) + */ +/*----------------------------------------------------------------------------*/ +u8 wlanGetEcoVersion(IN P_ADAPTER_T prAdapter) +{ + u8 ucEcoVersion; + + ASSERT(prAdapter); + +#if CFG_MULTI_ECOVER_SUPPORT + ucEcoVersion = nicGetChipEcoVer(prAdapter); + DBGLOG(INIT, TRACE, "%s: %u\n", __func__, ucEcoVersion); + return ucEcoVersion; + +#else + if (nicVerifyChipID(prAdapter) == true) { + return prAdapter->ucRevID + 1; + }else{ + return 0; + } + +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to query ROM version from HIFSYS CR + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return zero Unable to retrieve ROM version information + * non-zero ROM version (1-based) + */ +/*----------------------------------------------------------------------------*/ +u8 wlanGetRomVersion(IN P_ADAPTER_T prAdapter) +{ + u8 ucRomVersion; + + ASSERT(prAdapter); + + ucRomVersion = nicGetChipSwVer(); + DBGLOG(INIT, TRACE, "%s: %u\n", __func__, ucRomVersion); + + return ucRomVersion; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to setting the default Tx Power configuration + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return zero Unable to retrieve ECO version information + * non-zero ECO version (1-based) + */ +/*----------------------------------------------------------------------------*/ +void wlanDefTxPowerCfg(IN P_ADAPTER_T prAdapter) +{ + u8 i; + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + P_SET_TXPWR_CTRL_T prTxpwr; + + ASSERT(prGlueInfo); + + prTxpwr = &prGlueInfo->rTxPwr; + + prTxpwr->c2GLegacyStaPwrOffset = 0; + prTxpwr->c2GHotspotPwrOffset = 0; + prTxpwr->c2GP2pPwrOffset = 0; + prTxpwr->c2GBowPwrOffset = 0; + prTxpwr->c5GLegacyStaPwrOffset = 0; + prTxpwr->c5GHotspotPwrOffset = 0; + prTxpwr->c5GP2pPwrOffset = 0; + prTxpwr->c5GBowPwrOffset = 0; + prTxpwr->ucConcurrencePolicy = 0; + for (i = 0; i < 3; i++) + prTxpwr->acReserved1[i] = 0; + + for (i = 0; i < 14; i++) + prTxpwr->acTxPwrLimit2G[i] = 63; + + for (i = 0; i < 4; i++) + prTxpwr->acTxPwrLimit5G[i] = 63; + + for (i = 0; i < 2; i++) + prTxpwr->acReserved2[i] = 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to + * set preferred band configuration corresponding to network type + * + * @param prAdapter Pointer of Adapter Data Structure + * @param eBand Given band + * @param ucBssIndex BSS Info Index + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void wlanSetPreferBandByNetwork(IN P_ADAPTER_T prAdapter, IN ENUM_BAND_T eBand, + IN u8 ucBssIndex) +{ + ASSERT(prAdapter); + ASSERT(eBand <= BAND_NUM); + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + + /* 1. set prefer band according to network type */ + prAdapter->aePreferBand[ucBssIndex] = eBand; + + /* 2. remove buffered BSS descriptors correspondingly */ + if (eBand == BAND_2G4) { + scanRemoveBssDescByBandAndNetwork(prAdapter, BAND_5G, + ucBssIndex); + } else if (eBand == BAND_5G) { + scanRemoveBssDescByBandAndNetwork(prAdapter, BAND_2G4, + ucBssIndex); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to + * get channel information corresponding to specified network type + * + * @param prAdapter Pointer of Adapter Data Structure + * @param ucBssIndex BSS Info Index + * + * @return channel number + */ +/*----------------------------------------------------------------------------*/ +u8 wlanGetChannelNumberByNetwork(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + + if (ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, "Invalid BssInfo index[%u], skip dump!\n", + ucBssIndex); + return -1; + } + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + return prBssInfo->ucPrimaryChannel; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to + * check unconfigured system properties and generate related message on + * scan list to notify users + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanCheckSystemConfiguration(IN P_ADAPTER_T prAdapter) +{ +#if (CFG_NVRAM_EXISTENCE_CHECK == 1) || (CFG_SW_NVRAM_VERSION_CHECK == 1) + const u8 aucZeroMacAddr[] = NULL_MAC_ADDR; + u8 fgIsConfExist = true; + u8 fgGenErrMsg = false; + P_REG_INFO_T prRegInfo = NULL; +#endif + + DEBUGFUNC("wlanCheckSystemConfiguration"); + + ASSERT(prAdapter); + +#if (CFG_NVRAM_EXISTENCE_CHECK == 1) + if (kalIsConfigurationExist(prAdapter->prGlueInfo) == false) { + fgIsConfExist = false; + fgGenErrMsg = true; + } +#endif + +#if (CFG_SW_NVRAM_VERSION_CHECK == 1) + prRegInfo = kalGetConfiguration(prAdapter->prGlueInfo); + +#if (CFG_SUPPORT_PWR_LIMIT_COUNTRY == 1) + if (fgIsConfExist == true && + (prAdapter->rVerInfo.u2Part1CfgPeerVersion > CFG_DRV_OWN_VERSION || + prAdapter->rVerInfo.u2Part2CfgPeerVersion > CFG_DRV_OWN_VERSION || + prAdapter->rVerInfo.u2Part1CfgOwnVersion < CFG_DRV_PEER_VERSION || + prAdapter->rVerInfo.u2Part2CfgOwnVersion < + CFG_DRV_PEER_VERSION /* NVRAM */ + || prAdapter->rVerInfo.u2FwPeerVersion > CFG_DRV_OWN_VERSION || + prAdapter->rVerInfo.u2FwOwnVersion < CFG_DRV_PEER_VERSION || + (prAdapter->fgIsEmbbededMacAddrValid == false && + (IS_BMCAST_MAC_ADDR(prRegInfo->aucMacAddr) || + EQUAL_MAC_ADDR(aucZeroMacAddr, prRegInfo->aucMacAddr))) || + prRegInfo->ucTxPwrValid == 0 || + prAdapter->fgIsPowerLimitTableValid == false)) { + fgGenErrMsg = true; + } +#else + if (fgIsConfExist == true && + (prAdapter->rVerInfo.u2Part1CfgPeerVersion > CFG_DRV_OWN_VERSION || + prAdapter->rVerInfo.u2Part2CfgPeerVersion > CFG_DRV_OWN_VERSION || + prAdapter->rVerInfo.u2Part1CfgOwnVersion < CFG_DRV_PEER_VERSION || + prAdapter->rVerInfo.u2Part2CfgOwnVersion < + CFG_DRV_PEER_VERSION /* NVRAM */ + || prAdapter->rVerInfo.u2FwPeerVersion > CFG_DRV_OWN_VERSION || + prAdapter->rVerInfo.u2FwOwnVersion < CFG_DRV_PEER_VERSION || + (prAdapter->fgIsEmbbededMacAddrValid == false && + (IS_BMCAST_MAC_ADDR(prRegInfo->aucMacAddr) || + EQUAL_MAC_ADDR(aucZeroMacAddr, prRegInfo->aucMacAddr))) || + prRegInfo->ucTxPwrValid == 0)) { + fgGenErrMsg = true; + } +#endif +#endif + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS +wlanoidQueryBssStatistics(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_GET_BSS_STATISTICS prQueryBssStatistics; + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; + u8 ucBssIndex; + ENUM_WMM_ACI_T eAci; + + DEBUGFUNC("wlanoidQueryBssStatistics"); + + do { + ASSERT(pvQueryBuffer); + + /* 4 1. Sanity test */ + if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) { + break; + } + + if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) { + break; + } + + if (u4QueryBufferLen < sizeof(P_PARAM_GET_BSS_STATISTICS)) { + *pu4QueryInfoLen = sizeof(P_PARAM_GET_BSS_STATISTICS); + rResult = WLAN_STATUS_BUFFER_TOO_SHORT; + break; + } + + prQueryBssStatistics = + (P_PARAM_GET_BSS_STATISTICS)pvQueryBuffer; + *pu4QueryInfoLen = sizeof(PARAM_GET_BSS_STATISTICS); + + ucBssIndex = prQueryBssStatistics->ucBssIndex; + if (ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, + "invalid bssinfo index[%u], skip dump!\n", + ucBssIndex); + return WLAN_STATUS_FAILURE; + } + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if (prBssInfo) { /*AIS*/ + if (prBssInfo->eCurrentOPMode == + OP_MODE_INFRASTRUCTURE) { + prStaRec = prBssInfo->prStaRecOfAP; + if (prStaRec) { + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; + eAci++) { + prQueryBssStatistics + ->arLinkStatistics[eAci] + .u4TxMsdu = + prStaRec + ->arLinkStatistics + [eAci] + .u4TxMsdu; + prQueryBssStatistics + ->arLinkStatistics[eAci] + .u4RxMsdu = + prStaRec + ->arLinkStatistics + [eAci] + .u4RxMsdu; + prQueryBssStatistics + ->arLinkStatistics[eAci] + .u4TxDropMsdu = + prStaRec + ->arLinkStatistics + [eAci] + .u4TxDropMsdu + + prBssInfo + ->arLinkStatistics + [eAci] + .u4TxDropMsdu; + prQueryBssStatistics + ->arLinkStatistics[eAci] + .u4TxFailMsdu = + prStaRec + ->arLinkStatistics + [eAci] + .u4TxFailMsdu; + prQueryBssStatistics + ->arLinkStatistics[eAci] + .u4TxRetryMsdu = + prStaRec + ->arLinkStatistics + [eAci] + .u4TxRetryMsdu; + } + } + } + rResult = WLAN_STATUS_SUCCESS; + + /*P2P */ + /* TODO */ + + /*BOW*/ + /* TODO */ + } + } while (false); + + return rResult; +} + +void wlanDumpBssStatistics(IN P_ADAPTER_T prAdapter, u8 ucBssIdx) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + ENUM_WMM_ACI_T eAci; + WIFI_WMM_AC_STAT_T arLLStats[WMM_AC_INDEX_NUM]; + u8 ucIdx; + + if (ucBssIdx > MAX_BSS_INDEX) { + DBGLOG(SW4, INFO, "Invalid BssInfo index[%u], skip dump!\n", + ucBssIdx); + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIdx); + if (!prBssInfo) { + DBGLOG(SW4, INFO, "Invalid BssInfo index[%u], skip dump!\n", + ucBssIdx); + return; + } + /* <1> fill per-BSS statistics */ + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + arLLStats[eAci].u4TxMsdu = + prBssInfo->arLinkStatistics[eAci].u4TxMsdu; + arLLStats[eAci].u4RxMsdu = + prBssInfo->arLinkStatistics[eAci].u4RxMsdu; + arLLStats[eAci].u4TxDropMsdu = + prBssInfo->arLinkStatistics[eAci].u4TxDropMsdu; + arLLStats[eAci].u4TxFailMsdu = + prBssInfo->arLinkStatistics[eAci].u4TxFailMsdu; + arLLStats[eAci].u4TxRetryMsdu = + prBssInfo->arLinkStatistics[eAci].u4TxRetryMsdu; + } + + for (ucIdx = 0; ucIdx < CFG_STA_REC_NUM; ucIdx++) { + prStaRec = cnmGetStaRecByIndex(prAdapter, ucIdx); + if (!prStaRec) { + continue; + } + if (prStaRec->ucBssIndex != ucBssIdx) { + continue; + } + /* now the valid sta_rec is valid */ + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + arLLStats[eAci].u4TxMsdu += + prStaRec->arLinkStatistics[eAci].u4TxMsdu; + arLLStats[eAci].u4RxMsdu += + prStaRec->arLinkStatistics[eAci].u4RxMsdu; + arLLStats[eAci].u4TxDropMsdu += + prStaRec->arLinkStatistics[eAci].u4TxDropMsdu; + arLLStats[eAci].u4TxFailMsdu += + prStaRec->arLinkStatistics[eAci].u4TxFailMsdu; + arLLStats[eAci].u4TxRetryMsdu += + prStaRec->arLinkStatistics[eAci].u4TxRetryMsdu; + } + } + + /* <2>Dump BSS statistics */ + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + DBGLOG(SW4, INFO, + "LLS BSS[%u] %s: T[%06u] R[%06u] T_D[%06u] T_F[%06u]\n", + prBssInfo->ucBssIndex, apucACI2Str[eAci], + arLLStats[eAci].u4TxMsdu, arLLStats[eAci].u4RxMsdu, + arLLStats[eAci].u4TxDropMsdu, + arLLStats[eAci].u4TxFailMsdu); + } +} + +void wlanDumpAllBssStatistics(IN P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prBssInfo; + /* ENUM_WMM_ACI_T eAci; */ + u32 ucIdx; + + /* wlanUpdateAllBssStatistics(prAdapter); */ + + for (ucIdx = 0; ucIdx < BSS_INFO_NUM; ucIdx++) { + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucIdx); + if (!IS_BSS_ACTIVE(prBssInfo)) { + DBGLOG(SW4, TRACE, + "Invalid BssInfo index[%u], skip dump!\n", + ucIdx); + continue; + } + + wlanDumpBssStatistics(prAdapter, ucIdx); + } +} + +WLAN_STATUS +wlanoidQueryStaStatistics(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; + P_STA_RECORD_T prStaRec, prTempStaRec; + P_PARAM_GET_STA_STATISTICS prQueryStaStatistics; + u8 ucStaRecIdx; + P_QUE_MGT_T prQM; + CMD_GET_STA_STATISTICS_T rQueryCmdStaStatistics; + u8 ucIdx; + ENUM_WMM_ACI_T eAci; + + kalMemZero(&rQueryCmdStaStatistics, sizeof(CMD_GET_STA_STATISTICS_T)); + DEBUGFUNC("wlanoidQueryStaStatistics"); + + if (prAdapter == NULL) { + return WLAN_STATUS_FAILURE; + } + + prQM = &prAdapter->rQM; + + if (prAdapter->fgIsEnableLpdvt) { + return WLAN_STATUS_NOT_SUPPORTED; + } + + do { + ASSERT(pvQueryBuffer); + + /* 4 1. Sanity test */ + if (pu4QueryInfoLen == NULL) { + break; + } + + if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) { + break; + } + + if (u4QueryBufferLen < sizeof(PARAM_GET_STA_STATISTICS)) { + *pu4QueryInfoLen = sizeof(PARAM_GET_STA_STATISTICS); + rResult = WLAN_STATUS_BUFFER_TOO_SHORT; + break; + } + + prQueryStaStatistics = + (P_PARAM_GET_STA_STATISTICS)pvQueryBuffer; + *pu4QueryInfoLen = sizeof(PARAM_GET_STA_STATISTICS); + + /* 4 5. Get driver global QM counter */ +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + for (ucIdx = TC0_INDEX; ucIdx <= TC3_INDEX; ucIdx++) { + prQueryStaStatistics->au4TcAverageQueLen[ucIdx] = + prQM->au4AverageQueLen[ucIdx]; + prQueryStaStatistics->au4TcCurrentQueLen[ucIdx] = + prQM->au4CurrentTcResource[ucIdx]; + } +#endif + + /* 4 2. Get StaRec by MAC address */ + prStaRec = NULL; + + for (ucStaRecIdx = 0; ucStaRecIdx < CFG_STA_REC_NUM; + ucStaRecIdx++) { + prTempStaRec = &(prAdapter->arStaRec[ucStaRecIdx]); + if (prTempStaRec->fgIsValid && + prTempStaRec->fgIsInUse) { + if (EQUAL_MAC_ADDR( + prTempStaRec->aucMacAddr, + prQueryStaStatistics->aucMacAddr)) { + prStaRec = prTempStaRec; + break; + } + } + } + + if (!prStaRec) { + rResult = WLAN_STATUS_INVALID_DATA; + break; + } + + prQueryStaStatistics->u4Flag |= BIT(0); + +#if CFG_ENABLE_PER_STA_STATISTICS + /* 4 3. Get driver statistics */ + prQueryStaStatistics->u4TxTotalCount = + prStaRec->u4TotalTxPktsNumber; + prQueryStaStatistics->u4RxTotalCount = + prStaRec->u4TotalRxPktsNumber; + prQueryStaStatistics->u4TxExceedThresholdCount = + prStaRec->u4ThresholdCounter; + prQueryStaStatistics->u4TxMaxTime = prStaRec->u4MaxTxPktsTime; + if (prStaRec->u4TotalTxPktsNumber) { + prQueryStaStatistics->u4TxAverageProcessTime = + (prStaRec->u4TotalTxPktsTime / + prStaRec->u4TotalTxPktsNumber); + } else { + prQueryStaStatistics->u4TxAverageProcessTime = 0; + } + + /*link layer statistics */ + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + prQueryStaStatistics->arLinkStatistics[eAci].u4TxMsdu = + prStaRec->arLinkStatistics[eAci].u4TxMsdu; + prQueryStaStatistics->arLinkStatistics[eAci].u4RxMsdu = + prStaRec->arLinkStatistics[eAci].u4RxMsdu; + prQueryStaStatistics->arLinkStatistics[eAci] + .u4TxDropMsdu = + prStaRec->arLinkStatistics[eAci].u4TxDropMsdu; + } + + for (ucIdx = TC0_INDEX; ucIdx <= TC3_INDEX; ucIdx++) { + prQueryStaStatistics->au4TcResourceEmptyCount[ucIdx] = + prQM->au4QmTcResourceEmptyCounter + [prStaRec->ucBssIndex][ucIdx]; + /* Reset */ + prQM->au4QmTcResourceEmptyCounter[prStaRec->ucBssIndex] + [ucIdx] = 0; + } + + /* 4 4.1 Reset statistics */ + if (prQueryStaStatistics->ucReadClear) { + prStaRec->u4ThresholdCounter = 0; + prStaRec->u4TotalTxPktsNumber = 0; + prStaRec->u4TotalTxPktsTime = 0; + prStaRec->u4TotalRxPktsNumber = 0; + prStaRec->u4MaxTxPktsTime = 0; + } + /*link layer statistics */ + if (prQueryStaStatistics->ucLlsReadClear) { + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + prStaRec->arLinkStatistics[eAci].u4TxMsdu = 0; + prStaRec->arLinkStatistics[eAci].u4RxMsdu = 0; + prStaRec->arLinkStatistics[eAci].u4TxDropMsdu = + 0; + } + } +#endif + + for (ucIdx = TC0_INDEX; ucIdx <= TC3_INDEX; ucIdx++) + prQueryStaStatistics->au4TcQueLen[ucIdx] = + prStaRec->aprTargetQueue[ucIdx]->u4NumElem; + + rResult = WLAN_STATUS_SUCCESS; + + /* 4 6. Ensure FW supports get station link status */ + if (prAdapter->u4FwCompileFlag0 & + COMPILE_FLAG0_GET_STA_LINK_STATUS) { + DBGLOG(REQ, LOUD, "%s index[%x]\n", __func__, + prStaRec->ucIndex); + rQueryCmdStaStatistics.ucIndex = prStaRec->ucIndex; + COPY_MAC_ADDR(rQueryCmdStaStatistics.aucMacAddr, + prQueryStaStatistics->aucMacAddr); + rQueryCmdStaStatistics.ucReadClear = + prQueryStaStatistics->ucReadClear; + rQueryCmdStaStatistics.ucLlsReadClear = + prQueryStaStatistics->ucLlsReadClear; + rQueryCmdStaStatistics.ucResetCounter = + prQueryStaStatistics->ucResetCounter; + + rResult = wlanSendSetQueryCmd( + prAdapter, CMD_ID_GET_STA_STATISTICS, false, + true, true, nicCmdEventQueryStaStatistics, + nicOidCmdTimeoutCommon, + sizeof(CMD_GET_STA_STATISTICS_T), + (u8 *)&rQueryCmdStaStatistics, pvQueryBuffer, + u4QueryBufferLen); + + prQueryStaStatistics->u4Flag |= BIT(1); + } else { + rResult = WLAN_STATUS_NOT_SUPPORTED; + } + } while (false); + + return rResult; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to query Nic resource information + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +void wlanQueryNicResourceInformation(IN P_ADAPTER_T prAdapter) +{ + /* 3 1. Get Nic resource information from FW */ + + /* 3 2. Setup resource parameter */ + + /* 3 3. Reset Tx resource */ + nicTxResetResource(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to query Nic resource information + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS wlanQueryNicCapabilityV2(IN P_ADAPTER_T prAdapter) +{ + u8 ucCmdSeqNum; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + u32 u4RxPktLength; + u8 *prEventBuff; + P_HW_MAC_RX_DESC_T prRxStatus; + P_WIFI_EVENT_T prEvent; + struct chip_info *prChipInfo; + u32 chip_id; + + prChipInfo = prAdapter->chip_info; + chip_id = prChipInfo->chip_id; + + ASSERT(prAdapter); + + /* Get Nic resource information from FW */ + if (prAdapter->u4FwFeatureFlag0 & FEATURE_FLAG0_NIC_CAPABILITY_V2) { + DBGLOG(INIT, INFO, "Support NIC_CAPABILITY_V2 feature\n"); + + /* + * send NIC_CAPABILITY_V2 query cmd + */ + + /* 1. Allocate CMD Info Packet and its Buffer */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, + "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_BUILD_CONNECTION cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE; + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->fgIsOid = false; + prCmdInfo->ucCID = CMD_ID_GET_NIC_CAPABILITY_V2; + prCmdInfo->fgSetQuery = false; + prCmdInfo->fgNeedResp = true; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = 0; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prWifiCmd->u2Length = prCmdInfo->u2InfoBufLen - + (u16)OFFSET_OF(WIFI_CMD_T, u2Length); + + wlanSendCommand(prAdapter, prCmdInfo); + + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + + /* + * receive nic_capability_v2 event + */ + + /* allocate event buffer */ + prEventBuff = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, + CFG_RX_MAX_PKT_SIZE); + if (!prEventBuff) { + DBGLOG(INIT, WARN, "%s: event buffer alloc failed!\n", + __func__); + return WLAN_STATUS_FAILURE; + } + + /* get event */ + while (true) { + if (nicRxWaitResponse(prAdapter, 1, prEventBuff, + CFG_RX_MAX_PKT_SIZE, + &u4RxPktLength) != + WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, WARN, + "%s: wait for event failed!\n", + __func__); + + /* free event buffer */ + cnmMemFree(prAdapter, prEventBuff); + + return WLAN_STATUS_FAILURE; + } + + /* header checking .. */ + prRxStatus = (P_HW_MAC_RX_DESC_T)prEventBuff; + if ((prRxStatus->u2PktTYpe & + RXM_RXD_PKT_TYPE_SW_BITMAP) != + RXM_RXD_PKT_TYPE_SW_EVENT) { + DBGLOG(INIT, + WARN, + "%s: skip unexpected Rx pkt type[0x%04x]\n", + __func__, + prRxStatus->u2PktTYpe); + + continue; + } + + prEvent = (P_WIFI_EVENT_T)prEventBuff; + if (prEvent->ucEID != EVENT_ID_NIC_CAPABILITY_V2) { + DBGLOG(INIT, WARN, + "%s: skip unexpected event ID[0x%02x]\n", + __func__, prEvent->ucEID); + + continue; + } else { + /* hit */ + break; + } + } + + /* + * parsing elemens + */ + + nicCmdEventQueryNicCapabilityV2(prAdapter, prEvent->aucBuffer, prEvent->u2PacketLength); + +#if CFG_SUPPORT_BFER + /*This Branch doesnot support R Mode. + * if (prAdapter->ucRModeOnlyFlag) + * prAdapter->fgIsHwSupportBfer = false; + * else + */ + prAdapter->fgIsHwSupportBfer = true; +#endif + + /* + * free event buffer + */ + cnmMemFree(prAdapter, prEventBuff); + } + + /* Fill capability for different Chip version */ + /* if (chip_id == HQA_CHIP_ID_6632) { */ + /* 6632 only */ + /* prAdapter->fgIsSupportBufferBinSize16Byte = true; */ + /* prAdapter->fgIsSupportDelayCal = false; */ + /* prAdapter->fgIsSupportGetFreeEfuseBlockCount = false; */ + /* prAdapter->fgIsSupportQAAccessEfuse = false; */ + /* prAdapter->fgIsSupportPowerOnSendBufferModeCMD = false; */ + /* prAdapter->fgIsSupportGetTxPower = false; */ + /* } else { */ + /* prAdapter->fgIsSupportBufferBinSize16Byte = false; */ + /* prAdapter->fgIsSupportDelayCal = true; */ + /* prAdapter->fgIsSupportGetFreeEfuseBlockCount = true; */ + /* prAdapter->fgIsSupportQAAccessEfuse = true; */ + /* prAdapter->fgIsSupportPowerOnSendBufferModeCMD = true; */ + /* prAdapter->fgIsSupportGetTxPower = true; */ + /* } */ + + return WLAN_STATUS_SUCCESS; +} + +void wlanSetNicResourceParameters(IN P_ADAPTER_T prAdapter) +{ + u8 string[128], idx; + u32 u4share; + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + P_QUE_MGT_T prQM = &prAdapter->rQM; +#endif + + /* + * Use the settings in config file first, + * else, use the settings reported from firmware. + */ + + /* + * 1. assign free page count for each TC + */ + + /* 1 1. update free page count in TC control: MCU and LMAC */ + prWifiVar->au4TcPageCount[TC4_INDEX] = + prAdapter->nicTxReousrce.u4McuTotalResource * + NIC_TX_MAX_PAGE_PER_FRAME; /* MCU */ + + u4share = prAdapter->nicTxReousrce.u4LmacTotalResource / + (TC_NUM - 1); /* LMAC. Except TC_4, which is MCU */ + for (idx = TC0_INDEX; idx < TC_NUM; idx++) { + if (idx != TC4_INDEX) { + prWifiVar->au4TcPageCount[idx] = + u4share * NIC_TX_MAX_PAGE_PER_FRAME; + } + } + + /* 1 2. if there is remaings, give them to TC_3, which is VO */ + prWifiVar->au4TcPageCount[TC3_INDEX] += + (prAdapter->nicTxReousrce.u4LmacTotalResource % (TC_NUM - 1)) * + NIC_TX_MAX_PAGE_PER_FRAME; + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + /* + * 2. assign guaranteed page count for each TC + */ + + /* 2 1. update guaranteed page count in QM */ + for (idx = 0; idx < TC_NUM; idx++) + prQM->au4GuaranteedTcResource[idx] = + prWifiVar->au4TcPageCount[idx]; +#endif + +#if CFG_SUPPORT_CFG_FILE + /* + * 3. Use the settings in config file first, + * else, use the settings reported from firmware. + */ + + /* 3 1. update for free page count */ + for (idx = 0; idx < TC_NUM; idx++) { + /* construct prefix: Tc0Page, Tc1Page... */ + memset(string, 0, sizeof(string) / sizeof(u8)); + snprintf(string, sizeof(string) / sizeof(u8), "Tc%xPage", idx); + + /* update the final value */ + prWifiVar->au4TcPageCount[idx] = (u32)wlanCfgGetUint32( + prAdapter, string, prWifiVar->au4TcPageCount[idx]); + } + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + /* 3 2. update for guaranteed page count */ + for (idx = 0; idx < TC_NUM; idx++) { + /* construct prefix: Tc0Grt, Tc1Grt... */ + memset(string, 0, sizeof(string) / sizeof(u8)); + snprintf(string, sizeof(string) / sizeof(u8), "Tc%xGrt", idx); + + /* update the final value */ + prQM->au4GuaranteedTcResource[idx] = (u32)wlanCfgGetUint32( + prAdapter, string, prQM->au4GuaranteedTcResource[idx]); + } +#endif +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to query Nic resource information + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +void wlanUpdateNicResourceInformation(IN P_ADAPTER_T prAdapter) +{ + /* + * 3 1. Query TX resource + */ + + /* information is not got from firmware, use default value */ + if (prAdapter->fgIsNicTxReousrceValid != true) { + return; + } + + /* 3 2. Setup resource parameters */ + wlanSetNicResourceParameters(prAdapter); + + /* 3 3. Reset Tx resource */ + nicTxResetResource(prAdapter); + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + /* 3 4. Reset QM resource */ + qmResetTcControlResource(prAdapter); +#endif + + halTxResourceResetHwTQCounter(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to SET BSS index for a network interface. + * A network interface is a TX/RX data port hooked to OS. + * + * @param prGlueInfo Pointer of prGlueInfo Data Structure + * @param ucNetInterfaceIndex Index of network interface + * @param ucBssIndex Index of BSS + * + * @return void + */ +/*----------------------------------------------------------------------------*/ +void wlanBindBssIdxToNetInterface(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucBssIndex, + IN void *pvNetInterface) +{ + P_NET_INTERFACE_INFO_T prNetIfInfo; + + if (ucBssIndex >= ARRAY_SIZE(prGlueInfo->arNetInterfaceInfo)) { + DBGLOG(INIT, ERROR, "Array index out of bound, ucBssIndex=%u\n", + ucBssIndex); + return; + } + + prNetIfInfo = &prGlueInfo->arNetInterfaceInfo[ucBssIndex]; + + prNetIfInfo->ucBssIndex = ucBssIndex; + prNetIfInfo->pvNetInterface = pvNetInterface; + /* prGlueInfo->aprBssIdxToNetInterfaceInfo[ucBssIndex] = prNetIfInfo; */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to GET network interface for a BSS. + * A network interface is a TX/RX data port hooked to OS. + * + * @param prGlueInfo Pointer of prGlueInfo Data Structure + * @param ucBssIndex Index of BSS + * + * @return void * pointer of network interface structure + */ +/*----------------------------------------------------------------------------*/ +void *wlanGetNetInterfaceByBssIdx(IN P_GLUE_INFO_T prGlueInfo, + IN u8 ucBssIndex) +{ + return prGlueInfo->arNetInterfaceInfo[ucBssIndex].pvNetInterface; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to get BSS-INDEX for AIS network. + * + * @param prAdapter Pointer of ADAPTER_T + * + * @return value, as corresponding index of BSS + */ +/*----------------------------------------------------------------------------*/ +u8 wlanGetAisBssIndex(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + ASSERT(prAdapter->prAisBssInfo); + + return prAdapter->prAisBssInfo->ucBssIndex; +} +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to initialize WLAN feature options + * + * @param prAdapter Pointer of ADAPTER_T + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void wlanInitFeatureOption(IN P_ADAPTER_T prAdapter) +{ + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + P_QUE_MGT_T prQM = &prAdapter->rQM; +#endif + + /* Feature options will be filled by config file */ + + prWifiVar->ucQoS = + (u8)wlanCfgGetUint32(prAdapter, "Qos", FEATURE_ENABLED); + + prWifiVar->ucStaHt = + (u8)wlanCfgGetUint32(prAdapter, "StaHT", FEATURE_ENABLED); + prWifiVar->ucStaVht = + (u8)wlanCfgGetUint32(prAdapter, "StaVHT", FEATURE_ENABLED); + + prWifiVar->ucApHt = + (u8)wlanCfgGetUint32(prAdapter, "ApHT", FEATURE_ENABLED); + prWifiVar->ucApVht = + (u8)wlanCfgGetUint32(prAdapter, "ApVHT", FEATURE_ENABLED); + + prWifiVar->ucP2pGoHt = + (u8)wlanCfgGetUint32(prAdapter, "P2pGoHT", FEATURE_ENABLED); + prWifiVar->ucP2pGoVht = + (u8)wlanCfgGetUint32(prAdapter, "P2pGoVHT", FEATURE_ENABLED); + + prWifiVar->ucP2pGcHt = + (u8)wlanCfgGetUint32(prAdapter, "P2pGcHT", FEATURE_ENABLED); + prWifiVar->ucP2pGcVht = + (u8)wlanCfgGetUint32(prAdapter, "P2pGcVHT", FEATURE_ENABLED); + + prWifiVar->ucAmpduRx = + (u8)wlanCfgGetUint32(prAdapter, "AmpduRx", FEATURE_ENABLED); + prWifiVar->ucAmpduTx = + (u8)wlanCfgGetUint32(prAdapter, "AmpduTx", FEATURE_ENABLED); + + prWifiVar->ucAmsduInAmpduRx = (u8)wlanCfgGetUint32( + prAdapter, "AmsduInAmpduRx", FEATURE_ENABLED); + prWifiVar->ucAmsduInAmpduTx = (u8)wlanCfgGetUint32( + prAdapter, "AmsduInAmpduTx", FEATURE_ENABLED); + prWifiVar->ucHtAmsduInAmpduRx = (u8)wlanCfgGetUint32( + prAdapter, "HtAmsduInAmpduRx", FEATURE_DISABLED); + prWifiVar->ucHtAmsduInAmpduTx = (u8)wlanCfgGetUint32( + prAdapter, "HtAmsduInAmpduTx", FEATURE_DISABLED); + prWifiVar->ucVhtAmsduInAmpduRx = (u8)wlanCfgGetUint32( + prAdapter, "VhtAmsduInAmpduRx", FEATURE_ENABLED); + prWifiVar->ucVhtAmsduInAmpduTx = (u8)wlanCfgGetUint32( + prAdapter, "VhtAmsduInAmpduTx", FEATURE_ENABLED); + + prWifiVar->ucTspec = + (u8)wlanCfgGetUint32(prAdapter, "Tspec", FEATURE_DISABLED); + + prWifiVar->ucUapsd = + (u8)wlanCfgGetUint32(prAdapter, "Uapsd", FEATURE_ENABLED); + prWifiVar->ucStaUapsd = + (u8)wlanCfgGetUint32(prAdapter, "StaUapsd", FEATURE_DISABLED); + prWifiVar->ucApUapsd = + (u8)wlanCfgGetUint32(prAdapter, "ApUapsd", FEATURE_DISABLED); + prWifiVar->ucP2pUapsd = + (u8)wlanCfgGetUint32(prAdapter, "P2pUapsd", FEATURE_ENABLED); + prWifiVar->u4RegP2pIfAtProbe = (u8)wlanCfgGetUint32( + prAdapter, "RegP2pIfAtProbe", FEATURE_DISABLED); + prWifiVar->ucP2pShareMacAddr = (u8)wlanCfgGetUint32( + prAdapter, "P2pShareMacAddr", FEATURE_DISABLED); + + prWifiVar->ucTxShortGI = + (u8)wlanCfgGetUint32(prAdapter, "SgiTx", FEATURE_ENABLED); + prWifiVar->ucRxShortGI = + (u8)wlanCfgGetUint32(prAdapter, "SgiRx", FEATURE_ENABLED); + + prWifiVar->ucTxLdpc = + (u8)wlanCfgGetUint32(prAdapter, "LdpcTx", FEATURE_ENABLED); + prWifiVar->ucRxLdpc = + (u8)wlanCfgGetUint32(prAdapter, "LdpcRx", FEATURE_ENABLED); + + prWifiVar->ucTxStbc = + (u8)wlanCfgGetUint32(prAdapter, "StbcTx", FEATURE_ENABLED); + prWifiVar->ucRxStbc = + (u8)wlanCfgGetUint32(prAdapter, "StbcRx", FEATURE_ENABLED); + prWifiVar->ucRxStbcNss = + (u8)wlanCfgGetUint32(prAdapter, "StbcRxNss", 1); + + prWifiVar->ucTxGf = + (u8)wlanCfgGetUint32(prAdapter, "GfTx", FEATURE_ENABLED); + prWifiVar->ucRxGf = + (u8)wlanCfgGetUint32(prAdapter, "GfRx", FEATURE_ENABLED); + + prWifiVar->ucMCS32 = + (u8)wlanCfgGetUint32(prAdapter, "MCS32", FEATURE_DISABLED); + + prWifiVar->ucSigTaRts = + (u8)wlanCfgGetUint32(prAdapter, "SigTaRts", FEATURE_DISABLED); + prWifiVar->ucDynBwRts = + (u8)wlanCfgGetUint32(prAdapter, "DynBwRts", FEATURE_DISABLED); + prWifiVar->ucTxopPsTx = + (u8)wlanCfgGetUint32(prAdapter, "TxopPsTx", FEATURE_DISABLED); + + prWifiVar->ucStaHtBfee = + (u8)wlanCfgGetUint32(prAdapter, "StaHTBfee", FEATURE_DISABLED); + prWifiVar->ucStaVhtBfee = + (u8)wlanCfgGetUint32(prAdapter, "StaVHTBfee", FEATURE_ENABLED); + prWifiVar->ucStaVhtMuBfee = (u8)wlanCfgGetUint32( + prAdapter, "StaVHTMuBfee", FEATURE_ENABLED); + prWifiVar->ucStaHtBfer = + (u8)wlanCfgGetUint32(prAdapter, "StaHTBfer", FEATURE_DISABLED); + prWifiVar->ucStaVhtBfer = + (u8)wlanCfgGetUint32(prAdapter, "StaVHTBfer", FEATURE_DISABLED); + + /* 0: disabled + * 1: Tx done event to driver + * 2: Tx status to FW only + */ + prWifiVar->ucDataTxDone = + (u8)wlanCfgGetUint32(prAdapter, "DataTxDone", 0); + prWifiVar->ucDataTxRateMode = (u8)wlanCfgGetUint32( + prAdapter, "DataTxRateMode", DATA_RATE_MODE_AUTO); + prWifiVar->u4DataTxRateCode = + wlanCfgGetUint32(prAdapter, "DataTxRateCode", 0x0); + + prWifiVar->ucApWpsMode = + (u8)wlanCfgGetUint32(prAdapter, "ApWpsMode", 0); + DBGLOG(INIT, INFO, "ucApWpsMode = %u\n", prWifiVar->ucApWpsMode); + + prWifiVar->ucThreadScheduling = + (u8)wlanCfgGetUint32(prAdapter, "ThreadSched", 0); + prWifiVar->ucThreadPriority = (u8)wlanCfgGetUint32( + prAdapter, "ThreadPriority", WLAN_THREAD_TASK_PRIORITY); + prWifiVar->cThreadNice = (s8)wlanCfgGetInt32(prAdapter, "ThreadNice", + WLAN_THREAD_TASK_NICE); + + prAdapter->rQM.u4MaxForwardBufferCount = (u32)wlanCfgGetUint32( + prAdapter, "ApForwardBufferCnt", QM_FWD_PKT_QUE_THRESHOLD); + + /* AP channel setting + * 0: auto + */ + prWifiVar->ucApChannel = + (u8)wlanCfgGetUint32(prAdapter, "ApChannel", 0); + + /* + * 0: SCN + * 1: SCA + * 2: RES + * 3: SCB + */ + prWifiVar->ucApSco = (u8)wlanCfgGetUint32(prAdapter, "ApSco", 0); + prWifiVar->ucP2pGoSco = (u8)wlanCfgGetUint32(prAdapter, "P2pGoSco", 0); + + /* Max bandwidth setting + * 0: 20Mhz + * 1: 40Mhz + * 2: 80Mhz + * 3: 160Mhz + * 4: 80+80Mhz + * Note: For VHT STA, BW 80Mhz is a must! + */ + prWifiVar->ucStaBandwidth = + (u8)wlanCfgGetUint32(prAdapter, "StaBw", MAX_BW_160MHZ); + prWifiVar->ucSta2gBandwidth = + (u8)wlanCfgGetUint32(prAdapter, "Sta2gBw", MAX_BW_40MHZ); + prWifiVar->ucSta5gBandwidth = + (u8)wlanCfgGetUint32(prAdapter, "Sta5gBw", MAX_BW_80MHZ); + prWifiVar->ucP2p2gBandwidth = + (u8)wlanCfgGetUint32(prAdapter, "P2p2gBw", MAX_BW_20MHZ); + prWifiVar->ucP2p5gBandwidth = + (u8)wlanCfgGetUint32(prAdapter, "P2p5gBw", MAX_BW_80MHZ); + prWifiVar->ucApBandwidth = + (u8)wlanCfgGetUint32(prAdapter, "ApBw", MAX_BW_160MHZ); + prWifiVar->ucAp2gBandwidth = + (u8)wlanCfgGetUint32(prAdapter, "Ap2gBw", MAX_BW_40MHZ); + prWifiVar->ucAp5gBandwidth = + (u8)wlanCfgGetUint32(prAdapter, "Ap5gBw", MAX_BW_80MHZ); + prWifiVar->ucApChnlDefFromCfg = (u8)wlanCfgGetUint32( + prAdapter, "ApChnlDefFromCfg", FEATURE_ENABLED); + + prWifiVar->ucNSS = (u8)wlanCfgGetUint32(prAdapter, "Nss", 2); + + prWifiVar->ucAp5gNSS = (u8)wlanCfgGetUint32(prAdapter, "Ap5gNss", 2); + prWifiVar->ucAp2gNSS = (u8)wlanCfgGetUint32(prAdapter, "Ap2gNss", 2); + prWifiVar->ucGo5gNSS = (u8)wlanCfgGetUint32(prAdapter, "Go5gNss", 2); + prWifiVar->ucGo2gNSS = (u8)wlanCfgGetUint32(prAdapter, "Go2gNss", 2); + + /* Max Rx MPDU length setting + * 0: 3k + * 1: 8k + * 2: 11k + */ + prWifiVar->ucRxMaxMpduLen = (u8)wlanCfgGetUint32( + prAdapter, "RxMaxMpduLen", VHT_CAP_INFO_MAX_MPDU_LEN_3K); + /* Max Tx AMSDU in AMPDU length *in BYTES**/ + prWifiVar->u4TxMaxAmsduInAmpduLen = + wlanCfgGetUint32(prAdapter, "TxMaxAmsduInAmpduLen", 4096); + + prWifiVar->ucStaDisconnectDetectTh = + (u8)wlanCfgGetUint32(prAdapter, "StaDisconnectDetectTh", 0); + prWifiVar->ucApDisconnectDetectTh = + (u8)wlanCfgGetUint32(prAdapter, "ApDisconnectDetectTh", 0); + prWifiVar->ucP2pDisconnectDetectTh = + (u8)wlanCfgGetUint32(prAdapter, "P2pDisconnectDetectTh", 0); + + prWifiVar->ucTcRestrict = + (u8)wlanCfgGetUint32(prAdapter, "TcRestrict", 0xFF); + /* Max Tx dequeue limit: 0 => auto */ + prWifiVar->u4MaxTxDeQLimit = + (u32)wlanCfgGetUint32(prAdapter, "MaxTxDeQLimit", 0x0); + prWifiVar->ucAlwaysResetUsedRes = + (u32)wlanCfgGetUint32(prAdapter, "AlwaysResetUsedRes", 0x0); + +#if CFG_SUPPORT_MTK_SYNERGY + prWifiVar->ucMtkOui = + (u8)wlanCfgGetUint32(prAdapter, "MtkOui", FEATURE_ENABLED); + prWifiVar->u4MtkOuiCap = + (u32)wlanCfgGetUint32(prAdapter, "MtkOuiCap", 0); + prWifiVar->aucMtkFeature[0] = 0xff; + prWifiVar->aucMtkFeature[1] = 0xff; + prWifiVar->aucMtkFeature[2] = 0xff; + prWifiVar->aucMtkFeature[3] = 0xff; +#endif + + prWifiVar->ucCmdRsvResource = (u8)wlanCfgGetUint32( + prAdapter, "TxCmdRsv", QM_CMD_RESERVED_THRESHOLD); + prWifiVar->u4MgmtQueueDelayTimeout = (u32)wlanCfgGetUint32( + prAdapter, "TxMgmtQueTO", QM_MGMT_QUEUED_TIMEOUT); /* ms */ + + /* Performance related */ + prWifiVar->u4HifIstLoopCount = + (u32)wlanCfgGetUint32(prAdapter, "IstLoop", CFG_IST_LOOP_COUNT); + prWifiVar->u4Rx2OsLoopCount = + (u32)wlanCfgGetUint32(prAdapter, "Rx2OsLoop", 4); + prWifiVar->u4HifTxloopCount = + (u32)wlanCfgGetUint32(prAdapter, "HifTxLoop", 1); + prWifiVar->u4TxFromOsLoopCount = + (u32)wlanCfgGetUint32(prAdapter, "OsTxLoop", 1); + prWifiVar->u4TxRxLoopCount = + (u32)wlanCfgGetUint32(prAdapter, "Rx2ReorderLoop", 1); + prWifiVar->u4TxIntThCount = (u32)wlanCfgGetUint32(prAdapter, "IstTxTh", + HIF_IST_TX_THRESHOLD); + + prWifiVar->u4NetifStopTh = + (u32)wlanCfgGetUint32(prAdapter, "NetifStopTh", + CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD); + prWifiVar->u4NetifStartTh = + (u32)wlanCfgGetUint32(prAdapter, "NetifStartTh", + CFG_TX_START_NETIF_PER_QUEUE_THRESHOLD); + prWifiVar->ucTxBaSize = (u8)wlanCfgGetUint32(prAdapter, "TxBaSize", 64); + prWifiVar->ucRxHtBaSize = + (u8)wlanCfgGetUint32(prAdapter, "RxHtBaSize", 64); + prWifiVar->ucRxVhtBaSize = + (u8)wlanCfgGetUint32(prAdapter, "RxVhtBaSize", 64); + + /* Tx Buffer Management */ + prWifiVar->ucExtraTxDone = + (u32)wlanCfgGetUint32(prAdapter, "ExtraTxDone", 1); + prWifiVar->ucTxDbg = (u32)wlanCfgGetUint32(prAdapter, "TxDbg", 0); + + kalMemZero(prWifiVar->au4TcPageCount, + sizeof(prWifiVar->au4TcPageCount)); + + prWifiVar->au4TcPageCount[TC0_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc0Page", NIC_TX_PAGE_COUNT_TC0); + prWifiVar->au4TcPageCount[TC1_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc1Page", NIC_TX_PAGE_COUNT_TC1); + prWifiVar->au4TcPageCount[TC2_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc2Page", NIC_TX_PAGE_COUNT_TC2); + prWifiVar->au4TcPageCount[TC3_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc3Page", NIC_TX_PAGE_COUNT_TC3); + prWifiVar->au4TcPageCount[TC4_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc4Page", NIC_TX_PAGE_COUNT_TC4); + prWifiVar->au4TcPageCount[TC5_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc5Page", NIC_TX_PAGE_COUNT_TC5); + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + /*MinRsrv*/ + prQM->au4MinReservedTcResource[TC0_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc0MinRsv", QM_MIN_RESERVED_TC0_RESOURCE); + prQM->au4MinReservedTcResource[TC1_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc1MinRsv", QM_MIN_RESERVED_TC1_RESOURCE); + prQM->au4MinReservedTcResource[TC2_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc2MinRsv", QM_MIN_RESERVED_TC2_RESOURCE); + prQM->au4MinReservedTcResource[TC3_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc3MinRsv", QM_MIN_RESERVED_TC3_RESOURCE); + prQM->au4MinReservedTcResource[TC4_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc4MinRsv", QM_MIN_RESERVED_TC4_RESOURCE); + prQM->au4MinReservedTcResource[TC5_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc5MinRsv", QM_MIN_RESERVED_TC5_RESOURCE); + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + prQM->au4MinReservedTcResource[TC6_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc6MinRsv", QM_MIN_RESERVED_TC6_RESOURCE); + prQM->au4MinReservedTcResource[TC7_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc7MinRsv", QM_MIN_RESERVED_TC7_RESOURCE); + prQM->au4MinReservedTcResource[TC8_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc8MinRsv", QM_MIN_RESERVED_TC8_RESOURCE); + prQM->au4MinReservedTcResource[TC9_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc9MinRsv", QM_MIN_RESERVED_TC9_RESOURCE); + prQM->au4MinReservedTcResource[TC10_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc10MinRsv", QM_MIN_RESERVED_TC10_RESOURCE); + + prQM->au4MinReservedTcResource[TC11_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc11MinRsv", QM_MIN_RESERVED_TC11_RESOURCE); + prQM->au4MinReservedTcResource[TC12_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc12MinRsv", QM_MIN_RESERVED_TC12_RESOURCE); + prQM->au4MinReservedTcResource[TC13_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc13MinRsv", QM_MIN_RESERVED_TC13_RESOURCE); + prQM->au4MinReservedTcResource[TC14_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc14MinRsv", QM_MIN_RESERVED_TC14_RESOURCE); + prQM->au4MinReservedTcResource[TC15_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc15MinRsv", QM_MIN_RESERVED_TC15_RESOURCE); + prQM->au4MinReservedTcResource[TC16_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc16MinRsv", QM_MIN_RESERVED_TC16_RESOURCE); +#endif + + /*Guaranteed*/ + prQM->au4GuaranteedTcResource[TC0_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc0Grt", QM_GUARANTEED_TC0_RESOURCE); + prQM->au4GuaranteedTcResource[TC1_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc1Grt", QM_GUARANTEED_TC1_RESOURCE); + prQM->au4GuaranteedTcResource[TC2_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc2Grt", QM_GUARANTEED_TC2_RESOURCE); + prQM->au4GuaranteedTcResource[TC3_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc3Grt", QM_GUARANTEED_TC3_RESOURCE); + prQM->au4GuaranteedTcResource[TC4_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc4Grt", QM_GUARANTEED_TC4_RESOURCE); + prQM->au4GuaranteedTcResource[TC5_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc5Grt", QM_GUARANTEED_TC5_RESOURCE); + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + prQM->au4GuaranteedTcResource[TC6_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc6Grt", QM_GUARANTEED_TC6_RESOURCE); + prQM->au4GuaranteedTcResource[TC7_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc7Grt", QM_GUARANTEED_TC7_RESOURCE); + prQM->au4GuaranteedTcResource[TC8_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc8Grt", QM_GUARANTEED_TC8_RESOURCE); + prQM->au4GuaranteedTcResource[TC9_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc9Grt", QM_GUARANTEED_TC9_RESOURCE); + prQM->au4GuaranteedTcResource[TC10_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc10Grt", QM_GUARANTEED_TC10_RESOURCE); + prQM->au4GuaranteedTcResource[TC11_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc11Grt", QM_GUARANTEED_TC11_RESOURCE); + prQM->au4GuaranteedTcResource[TC12_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc12Grt", QM_GUARANTEED_TC12_RESOURCE); + prQM->au4GuaranteedTcResource[TC13_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc13Grt", QM_GUARANTEED_TC13_RESOURCE); + prQM->au4GuaranteedTcResource[TC14_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc14Grt", QM_GUARANTEED_TC14_RESOURCE); + prQM->au4GuaranteedTcResource[TC15_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc15Grt", QM_GUARANTEED_TC15_RESOURCE); + prQM->au4GuaranteedTcResource[TC16_INDEX] = (u32)wlanCfgGetUint32( + prAdapter, "Tc16Grt", QM_GUARANTEED_TC16_RESOURCE); +#endif + + prQM->u4TimeToAdjustTcResource = (u32)wlanCfgGetUint32( + prAdapter, "TcAdjustTime", QM_INIT_TIME_TO_ADJUST_TC_RSC); + prQM->u4TimeToUpdateQueLen = (u32)wlanCfgGetUint32( + prAdapter, "QueLenUpdateTime", QM_INIT_TIME_TO_UPDATE_QUE_LEN); + prQM->u4QueLenMovingAverage = (u32)wlanCfgGetUint32( + prAdapter, "QueLenMovingAvg", QM_QUE_LEN_MOVING_AVE_FACTOR); + prQM->u4ExtraReservedTcResource = (u32)wlanCfgGetUint32( + prAdapter, "TcExtraRsv", QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY); +#endif + + /* Stats log */ + prWifiVar->u4StatsLogTimeout = (u32)wlanCfgGetUint32( + prAdapter, "StatsLogTO", WLAN_TX_STATS_LOG_TIMEOUT); + prWifiVar->u4StatsLogDuration = (u32)wlanCfgGetUint32( + prAdapter, "StatsLogDur", WLAN_TX_STATS_LOG_DURATION); + + prWifiVar->ucDhcpTxDone = + (u8)wlanCfgGetUint32(prAdapter, "DhcpTxDone", 1); + prWifiVar->ucArpTxDone = + (u8)wlanCfgGetUint32(prAdapter, "ArpTxDone", 1); + + prWifiVar->ucMacAddrOverride = + (u8)wlanCfgGetInt32(prAdapter, "MacOverride", 0); + if (wlanCfgGet(prAdapter, "MacAddr", prWifiVar->aucMacAddrStr, + "00:0c:e7:66:32:e1", 0)) { + DBGLOG(INIT, INFO, "get MacAddr fail, use default\n"); + } + + prWifiVar->ucCtiaMode = (u8)wlanCfgGetUint32(prAdapter, "CtiaMode", 0); + + /* Combine ucTpTestMode and ucSigmaTestMode in one flag */ + /* ucTpTestMode == 0, for normal driver */ + /* ucTpTestMode == 1, for pure throughput test mode (ex: RvR) */ + /* ucTpTestMode == 2, for sigma TGn/TGac/PMF */ + /* ucTpTestMode == 3, for sigma WMM PS */ + /* ucTpTestMode == 4, for Audio MRM mode */ + prWifiVar->ucTpTestMode = + (u8)wlanCfgGetUint32(prAdapter, "TpTestMode", 0); + +#if CFG_SUPPORT_DBDC + prWifiVar->ucDbdcMode = + (u8)wlanCfgGetUint32(prAdapter, "DbdcMode", DBDC_MODE_DYNAMIC); +#endif +#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1) + prWifiVar->ucEfuseBufferModeCal = + (u8)wlanCfgGetUint32(prAdapter, "EfuseBufferModeCal", 0); +#endif + prWifiVar->ucCalTimingCtrl = (u8)wlanCfgGetUint32( + prAdapter, "CalTimingCtrl", 0 /* power on full cal */ ); + prWifiVar->ucWow = + (u8)wlanCfgGetUint32(prAdapter, "Wow", FEATURE_DISABLED); + prWifiVar->ucOffload = + (u8)wlanCfgGetUint32(prAdapter, "Offload", FEATURE_DISABLED); + prWifiVar->ucAdvPws = + (u8)wlanCfgGetUint32(prAdapter, "AdvPws", FEATURE_ENABLED); + prWifiVar->ucWowOnMdtim = + (u8)wlanCfgGetUint32(prAdapter, "WowOnMdtim", 1); + prWifiVar->ucWowOffMdtim = + (u8)wlanCfgGetUint32(prAdapter, "WowOffMdtim", 3); + prWifiVar->ucWowPwsMode = (u8)wlanCfgGetUint32(prAdapter, "WowPwsMode", + Param_PowerModeFast_PSP); + prWifiVar->ucWlanSetCamDuringAct = (u8)wlanCfgGetUint32( + prAdapter, "WlanSetCamDuringAct", FEATURE_DISABLED); +#ifdef SUPPORT_PERIODIC_PS + prWifiVar->ucPspCAMInt = (u8)wlanCfgGetUint32(prAdapter, "WowPspCAMInt", + PSP_CAM_INT_DEFAULT); + prWifiVar->ucAwakePspCAMInt = (u8)wlanCfgGetUint32( + prAdapter, "AwakePspCAMInt", AWAKE_PSP_CAM_INT_DEFAULT); + prWifiVar->ucPspPSInt = (u8)wlanCfgGetUint32(prAdapter, "WowPspPSInt", + PSP_PS_INT_DEFAULT); + prWifiVar->ucAwakePspPSInt = (u8)wlanCfgGetUint32( + prAdapter, "AwakePspPSInt", AWAKE_PSP_PS_INT_DEFAULT); +#endif + prWifiVar->ucWaitConnect = (u8)wlanCfgGetUint32( + prAdapter, "WaitConnect", WAIT_CONNECT_DEFAULT); + prWifiVar->ucListenDtimInterval = + (u8)wlanCfgGetUint32(prAdapter, "ListenDtimInt", + DEFAULT_LISTEN_INTERVAL_BY_DTIM_PERIOD); + //prWifiVar->ucEapolOffload = (u8) wlanCfgGetUint32(prAdapter, + //"EapolOffload", FEATURE_ENABLED); + + /* ucEapolOffload: only offload eapol rekey as suspen/resume case. */ + prWifiVar->ucEapolOffload = FEATURE_DISABLED; +#ifdef SUPPORT_ENFORCE_PWR_MODE + /* Support new enforce power mode. */ + prWifiVar->ucEnforce2G = (u8)wlanCfgGetUint32(prAdapter, "Enforce2G", + Param_PowerModeMax); + prWifiVar->ucEnforce5G = (u8)wlanCfgGetUint32(prAdapter, "Enforce5G", + Param_PowerModeMax); +#else + prWifiVar->ucEnforcePSMode = (u8)wlanCfgGetUint32( + prAdapter, "EnforcePSMode", Param_PowerModeMax); + prWifiVar->ucEnforceCAM2G = + (u8)wlanCfgGetUint32(prAdapter, "EnforceCAM2G", 0); +#endif + +#if CFG_SUPPORT_REPLAY_DETECTION + prWifiVar->ucRpyDetectOffload = (u8)wlanCfgGetUint32( + prAdapter, "rpydetectoffload", FEATURE_ENABLED); +#endif + +#if CFG_WOW_SUPPORT + prAdapter->rWowCtrl.fgWowEnable = + (u8)wlanCfgGetUint32(prAdapter, "WowEnable", FEATURE_ENABLED); + prAdapter->rWowCtrl.ucScenarioId = + (u8)wlanCfgGetUint32(prAdapter, "WowScenarioId", 0); + prAdapter->rWowCtrl.ucBlockCount = + (u8)wlanCfgGetUint32(prAdapter, "WowPinCnt", 1); + prAdapter->rWowCtrl.astWakeHif[0].ucWakeupHif = + (u8)wlanCfgGetUint32(prAdapter, "WowHif", ENUM_HIF_TYPE_GPIO); + prAdapter->rWowCtrl.astWakeHif[0].ucGpioPin = + (u8)wlanCfgGetUint32(prAdapter, "WowGpioPin", 0xFF); + prAdapter->rWowCtrl.astWakeHif[0].ucTriggerLvl = + (u8)wlanCfgGetUint32(prAdapter, "WowTriggerLevel", 3); + prAdapter->rWowCtrl.astWakeHif[0].u4GpioInterval = + wlanCfgGetUint32(prAdapter, "GpioInterval", 0); +#endif + + /* SW Test Mode: Mainly used for Sigma */ + prWifiVar->u4SwTestMode = (u8)wlanCfgGetUint32(prAdapter, "Sigma", + ENUM_SW_TEST_MODE_NONE); + prWifiVar->ucCtrlFlagAssertPath = (u8)wlanCfgGetUint32( + prAdapter, "AssertPath", DBG_ASSERT_PATH_DEFAULT); + prWifiVar->ucCtrlFlagDebugLevel = (u8)wlanCfgGetUint32( + prAdapter, "AssertLevel", DBG_ASSERT_CTRL_LEVEL_DEFAULT); + prWifiVar->u4ScanCtrl = (u8)wlanCfgGetUint32( + prAdapter, "ScanCtrl", SCN_CTRL_DEFAULT_SCAN_CTRL); + prWifiVar->ucScanChannelListenTime = + (u8)wlanCfgGetUint32(prAdapter, "ScnChListenTime", 0); + + /* Wake lock related configuration */ + prWifiVar->u4WakeLockRxTimeout = wlanCfgGetUint32( + prAdapter, "WakeLockRxTO", WAKE_LOCK_RX_TIMEOUT); + prWifiVar->u4WakeLockThreadWakeup = wlanCfgGetUint32( + prAdapter, "WakeLockThreadTO", WAKE_LOCK_THREAD_WAKEUP_TIMEOUT); + + prWifiVar->ucSmartRTS = (u8)wlanCfgGetUint32(prAdapter, "SmartRTS", 0); + /* add more cfg from RegInfo */ + prWifiVar->u4UapsdAcBmp = + (u32)wlanCfgGetUint32(prAdapter, "UapsdAcBmp", 0); + prWifiVar->u4MaxSpLen = (u32)wlanCfgGetUint32(prAdapter, "MaxSpLen", 0); + prWifiVar->fgDisOnlineScan = + (u32)wlanCfgGetUint32(prAdapter, "DisOnlineScan", 0); + prWifiVar->fgDisBcnLostDetection = + (u32)wlanCfgGetUint32(prAdapter, "DisBcnLostDetection", 0); + prWifiVar->fgDisRoaming = + (u32)wlanCfgGetUint32(prAdapter, "DisRoaming", 0); + prWifiVar->fgEnArpFilter = (u32)wlanCfgGetUint32( + prAdapter, "EnArpFilter", FEATURE_ENABLED); + + /* Driver Flow Control Dequeue Quota. Now is only used by DBDC */ + prWifiVar->uDeQuePercentEnable = + (u8)wlanCfgGetUint32(prAdapter, "DeQuePercentEnable", 1); + prWifiVar->u4DeQuePercentVHT80Nss1 = + (u32)wlanCfgGetUint32(prAdapter, "DeQuePercentVHT80NSS1", + QM_DEQUE_PERCENT_VHT80_NSS1); + prWifiVar->u4DeQuePercentVHT40Nss1 = + (u32)wlanCfgGetUint32(prAdapter, "DeQuePercentVHT40NSS1", + QM_DEQUE_PERCENT_VHT40_NSS1); + prWifiVar->u4DeQuePercentVHT20Nss1 = + (u32)wlanCfgGetUint32(prAdapter, "DeQuePercentVHT20NSS1", + QM_DEQUE_PERCENT_VHT20_NSS1); + prWifiVar->u4DeQuePercentHT40Nss1 = (u32)wlanCfgGetUint32( + prAdapter, "DeQuePercentHT40NSS1", QM_DEQUE_PERCENT_HT40_NSS1); + prWifiVar->u4DeQuePercentHT20Nss1 = (u32)wlanCfgGetUint32( + prAdapter, "DeQuePercentHT20NSS1", QM_DEQUE_PERCENT_HT20_NSS1); + + /* Support TDLS 5.5.4.2 optional case */ + prWifiVar->fgTdlsBufferSTASleep = (u8)wlanCfgGetUint32( + prAdapter, "TdlsBufferSTASleep", FEATURE_DISABLED); + /* Support USB Whole chip reset recover */ + prWifiVar->fgChipResetRecover = (u8)wlanCfgGetUint32( + prAdapter, "ChipResetRecover", FEATURE_ENABLED); + +#if CFG_SUPPORT_ANT_SELECT + prWifiVar->ucSpeIdxCtrl = + (u8)wlanCfgGetUint32(prAdapter, "SpeIdxCtrl", 2); + prWifiVar->ucSpeIdxCtrl2G = + (u8)wlanCfgGetUint32(prAdapter, "SpeIdxCtrl2G", 2); +#endif +#ifdef CFG_SUPPORT_ADJUST_JOIN_CH_REQ_INTERVAL + prWifiVar->u4AisJoinChReqIntervel = + (u32)wlanCfgGetUint32(prAdapter, "AisJoinChReqIntervel", + AIS_JOIN_CH_REQUEST_INTERVAL); + if (AIS_JOIN_CH_REQUEST_MAX_INTERVAL < + prWifiVar->u4AisJoinChReqIntervel) { + prWifiVar->u4AisJoinChReqIntervel = + AIS_JOIN_CH_REQUEST_MAX_INTERVAL; + } +#endif +#if CFG_SUPPORT_RSSI_COMP + prWifiVar->rRssiPathCompasation.c2GRssiCompensation = + (u8)wlanCfgGetUint32(prAdapter, "2GRssiComp", 0); + prWifiVar->rRssiPathCompasation.c5GRssiCompensation = + (u8)wlanCfgGetUint32(prAdapter, "5GRssiComp", 0); +#endif + prWifiVar->ucEd2GNonEU = + (s32)wlanCfgGetInt32(prAdapter, "Ed2GNonEU", 0); + prWifiVar->ucEd5GNonEU = + (s32)wlanCfgGetInt32(prAdapter, "Ed5GNonEU", 0); + prWifiVar->ucEd2GEU = (s32)wlanCfgGetInt32(prAdapter, "Ed2GEU", 0); + prWifiVar->ucEd5GEU = (s32)wlanCfgGetInt32(prAdapter, "Ed5GEU", 0); + prWifiVar->ucDelayTimeOfDisconnect = + (u8)wlanCfgGetUint32(prAdapter, "DelayTimeofDisconnect", + AIS_DELAY_TIME_OF_DISCONNECT_SEC); +#if CFG_KEY_ERROR_STATISTIC_RECOVERY + prWifiVar->u4BmcKeyErrorTh = + (s32)wlanCfgGetInt32(prAdapter, "BmcKeyErrorTh", 0); +#endif +} + +void wlanCfgSetSwCtrl(IN P_ADAPTER_T prAdapter) +{ + u32 i = 0; + s8 aucKey[WLAN_CFG_VALUE_LEN_MAX]; + s8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; + + const s8 acDelim[] = " "; + s8 *pcPtr = NULL; + s8 *pcDupValue = NULL; + u32 au4Values[2]; + u32 u4TokenCount = 0; + u32 u4BufLen = 0; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + s32 u4Ret = 0; + + kalMemZero(au4Values, sizeof(au4Values)); + + for (i = 0; i < WLAN_CFG_SET_SW_CTRL_LEN_MAX; i++) { + kalMemZero(aucValue, WLAN_CFG_VALUE_LEN_MAX); + kalMemZero(aucKey, WLAN_CFG_VALUE_LEN_MAX); + kalSnprintf(aucKey, sizeof(aucKey), "SwCtrl%d", i); + + /* get nothing */ + if (wlanCfgGet(prAdapter, aucKey, aucValue, "", 0) != + WLAN_STATUS_SUCCESS) { + continue; + } + if (!kalStrCmp(aucValue, "")) { + continue; + } + + pcDupValue = aucValue; + u4TokenCount = 0; + + while ((pcPtr = kalStrSep((char **)(&pcDupValue), acDelim)) != + NULL) { + if (!kalStrCmp(pcPtr, "")) { + continue; + } + + /* au4Values[u4TokenCount] = kalStrtoul(pcPtr, NULL, 0); + */ + u4Ret = kalkStrtou32(pcPtr, 0, + &(au4Values[u4TokenCount])); + if (u4Ret) { + DBGLOG(INIT, LOUD, + "parse au4Values error u4Ret=%d\n", + u4Ret); + return; + } + + u4TokenCount++; + + /* Only need 2 tokens */ + if (u4TokenCount >= 2) { + break; + } + } + + if (u4TokenCount != 2) { + continue; + } + + rSwCtrlInfo.u4Id = au4Values[0]; + rSwCtrlInfo.u4Data = au4Values[1]; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, + &rSwCtrlInfo, sizeof(rSwCtrlInfo), false, + false, true, &u4BufLen); + } +} + +void wlanCfgSetChip(IN P_ADAPTER_T prAdapter) +{ + u32 i = 0; + s8 aucKey[WLAN_CFG_VALUE_LEN_MAX]; + s8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; + + u32 u4BufLen = 0; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T rChipConfigInfo; + + for (i = 0; i < WLAN_CFG_SET_CHIP_LEN_MAX; i++) { + kalMemZero(aucValue, WLAN_CFG_VALUE_LEN_MAX); + kalMemZero(aucKey, WLAN_CFG_VALUE_LEN_MAX); + kalSnprintf(aucKey, sizeof(aucKey), "SetChip%d", i); + + /* get nothing */ + if (wlanCfgGet(prAdapter, aucKey, aucValue, "", 0) != + WLAN_STATUS_SUCCESS) { + continue; + } + if (!kalStrCmp(aucValue, "")) { + continue; + } + + kalMemZero(&rChipConfigInfo, sizeof(rChipConfigInfo)); + + rChipConfigInfo.ucType = CHIP_CONFIG_TYPE_WO_RESPONSE; + rChipConfigInfo.u2MsgSize = + kalStrnLen(aucValue, WLAN_CFG_VALUE_LEN_MAX); + kalStrnCpy(rChipConfigInfo.aucCmd, aucValue, + CHIP_CONFIG_RESP_SIZE); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetChipConfig, + &rChipConfigInfo, sizeof(rChipConfigInfo), + false, false, true, &u4BufLen); + } +} + +void wlanCfgSetDebugLevel(IN P_ADAPTER_T prAdapter) +{ + u32 i = 0; + s8 aucKey[WLAN_CFG_VALUE_LEN_MAX]; + s8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; + const s8 acDelim[] = " "; + s8 *pcDupValue; + s8 *pcPtr = NULL; + + u32 au4Values[2]; + u32 u4TokenCount = 0; + u32 u4DbgIdx = 0; + u32 u4DbgMask = 0; + s32 u4Ret = 0; + + kalMemZero(au4Values, sizeof(au4Values)); + + for (i = 0; i < WLAN_CFG_SET_DEBUG_LEVEL_LEN_MAX; i++) { + kalMemZero(aucValue, WLAN_CFG_VALUE_LEN_MAX); + kalMemZero(aucKey, WLAN_CFG_VALUE_LEN_MAX); + kalSnprintf(aucKey, sizeof(aucKey), "DbgLevel%d", i); + + /* get nothing */ + if (wlanCfgGet(prAdapter, aucKey, aucValue, "", 0) != + WLAN_STATUS_SUCCESS) { + continue; + } + if (!kalStrCmp(aucValue, "")) { + continue; + } + + pcDupValue = aucValue; + u4TokenCount = 0; + + while ((pcPtr = kalStrSep((char **)(&pcDupValue), acDelim)) != + NULL) { + if (!kalStrCmp(pcPtr, "")) { + continue; + } + + /* au4Values[u4TokenCount] = kalStrtoul(pcPtr, NULL, 0); + */ + u4Ret = kalkStrtou32(pcPtr, 0, + &(au4Values[u4TokenCount])); + if (u4Ret) { + DBGLOG(INIT, LOUD, + "parse au4Values error u4Ret=%d\n", + u4Ret); + return; + } + + u4TokenCount++; + + /* Only need 2 tokens */ + if (u4TokenCount >= 2) { + break; + } + } + + if (u4TokenCount != 2) { + continue; + } + + u4DbgIdx = au4Values[0]; + u4DbgMask = au4Values[1]; + + /* DBG level special control */ + if (u4DbgIdx == 0xFFFFFFFF) { + wlanSetDebugLevel(DBG_ALL_MODULE_IDX, u4DbgMask); + DBGLOG(INIT, INFO, + "Set ALL DBG module log level to [0x%02x]!", + (u8)u4DbgMask); + } else if (u4DbgIdx == 0xFFFFFFFE) { + wlanDebugInit(); + DBGLOG(INIT, INFO, + "Reset ALL DBG module log level to DEFAULT!"); + } else if (u4DbgIdx < DBG_MODULE_NUM) { + wlanSetDebugLevel(u4DbgIdx, u4DbgMask); + DBGLOG(INIT, INFO, + "Set DBG module[%lu] log level to [0x%02x]!", + u4DbgIdx, (u8)u4DbgMask); + } + } +} + +void wlanCfgSetCountryCode(IN P_ADAPTER_T prAdapter) +{ + s8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; + + /* Apply COUNTRY Config */ + if (wlanCfgGet(prAdapter, "Country", aucValue, "", 0) == + WLAN_STATUS_SUCCESS) { + prAdapter->rWifiVar.rConnSettings.u2CountryCode = + (((u16)aucValue[0]) << 8) | ((u16)aucValue[1]); + + DBGLOG(INIT, TRACE, "u2CountryCode=0x%04x\n", + prAdapter->rWifiVar.rConnSettings.u2CountryCode); + + if (regd_is_single_sku_en()) { + rlmDomainOidSetCountry(prAdapter, aucValue, 2); + return; + } + + /* Force to re-search country code in country domains */ + prAdapter->prDomainInfo = NULL; + rlmDomainSendCmd(prAdapter, true); + + /* Update supported channel list in channel table based on + * current country domain */ + wlanUpdateChannelTable(prAdapter->prGlueInfo); + } +} + +#if CFG_SUPPORT_CFG_FILE + +P_WLAN_CFG_ENTRY_T wlanCfgGetEntry(IN P_ADAPTER_T prAdapter, const s8 *pucKey, + u8 fgGetCfgRec) +{ + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_WLAN_CFG_T prWlanCfg = NULL; + P_WLAN_CFG_REC_T prWlanCfgRec = NULL; + u32 i, u32MaxNum; + + if (fgGetCfgRec) { + prWlanCfgRec = prAdapter->prWlanCfgRec; + u32MaxNum = WLAN_CFG_REC_ENTRY_NUM_MAX; + ASSERT(prWlanCfgRec); + } else { + prWlanCfg = prAdapter->prWlanCfg; + u32MaxNum = WLAN_CFG_ENTRY_NUM_MAX; + ASSERT(prWlanCfg); + } + + ASSERT(pucKey); + + prWlanCfgEntry = NULL; + + for (i = 0; i < u32MaxNum; i++) { + if (fgGetCfgRec) { + prWlanCfgEntry = &prWlanCfgRec->arWlanCfgBuf[i]; + }else{ + prWlanCfgEntry = &prWlanCfg->arWlanCfgBuf[i]; + } + + if (prWlanCfgEntry->aucKey[0] != '\0') { + //DBGLOG(INIT, LOUD, "compare key %s saved key %s\n", + // pucKey, prWlanCfgEntry->aucKey); + if (kalStrnCmp(pucKey, prWlanCfgEntry->aucKey, + WLAN_CFG_KEY_LEN_MAX - 1) == 0) { + return prWlanCfgEntry; + } + } + } + + DBGLOG(INIT, TRACE, "wifi config there is no entry \'%s\'\n", pucKey); + return NULL; +} + +P_WLAN_CFG_ENTRY_T wlanCfgGetEntryByIndex(IN P_ADAPTER_T prAdapter, + const u8 ucIdx, u32 flag) +{ + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_WLAN_CFG_T prWlanCfg; + P_WLAN_CFG_REC_T prWlanCfgRec; + + prWlanCfg = prAdapter->prWlanCfg; + prWlanCfgRec = prAdapter->prWlanCfgRec; + + ASSERT(prWlanCfg); + ASSERT(prWlanCfgRec); + + prWlanCfgEntry = NULL; + + if (flag & WLAN_CFG_REC_FLAG_BIT) { + prWlanCfgEntry = &prWlanCfgRec->arWlanCfgBuf[ucIdx]; + }else{ + prWlanCfgEntry = &prWlanCfg->arWlanCfgBuf[ucIdx]; + } + + if (prWlanCfgEntry->aucKey[0] != '\0') { + DBGLOG(INIT, LOUD, "get Index(%d) saved key %s\n", ucIdx, + prWlanCfgEntry->aucKey); + return prWlanCfgEntry; + } + + DBGLOG(INIT, TRACE, "wifi config there is no entry at index(%d)\n", + ucIdx); + return NULL; +} + +WLAN_STATUS wlanCfgGet(IN P_ADAPTER_T prAdapter, const s8 *pucKey, s8 *pucValue, + s8 *pucValueDef, u32 u4Flags) +{ + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_WLAN_CFG_T prWlanCfg; + + prWlanCfg = prAdapter->prWlanCfg; + + ASSERT(prWlanCfg); + ASSERT(pucValue); + + /* Find the exist */ + prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey, false); + + if (prWlanCfgEntry) { + kalStrnCpy(pucValue, prWlanCfgEntry->aucValue, + WLAN_CFG_VALUE_LEN_MAX - 1); + pucValue[WLAN_CFG_KEY_LEN_MAX - 1] = '\0'; + return WLAN_STATUS_SUCCESS; + } + if (pucValueDef) { + kalStrnCpy(pucValue, pucValueDef, WLAN_CFG_VALUE_LEN_MAX - 1); + pucValue[WLAN_CFG_KEY_LEN_MAX - 1] = '\0'; + } + return WLAN_STATUS_FAILURE; +} + +void wlanCfgRecordValue(IN P_ADAPTER_T prAdapter, const s8 *pucKey, s32 u4Value) +{ + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + u8 aucBuf[WLAN_CFG_VALUE_LEN_MAX]; + + prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey, true); + + kalMemZero(aucBuf, sizeof(aucBuf)); + + kalSnprintf(aucBuf, WLAN_CFG_VALUE_LEN_MAX, "0x%x", + u4Value); + + wlanCfgSet(prAdapter, pucKey, aucBuf, 1); +} + +u32 wlanCfgGetUint32(IN P_ADAPTER_T prAdapter, const s8 *pucKey, u32 u4ValueDef) +{ + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_WLAN_CFG_T prWlanCfg; + u32 u4Value; + s32 u4Ret; + + prWlanCfg = prAdapter->prWlanCfg; + + ASSERT(prWlanCfg); + + u4Value = u4ValueDef; + /* Find the exist */ + prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey, false); + + if (prWlanCfgEntry) { + /* u4Ret = kalStrtoul(prWlanCfgEntry->aucValue, NULL, 0); */ + u4Ret = kalkStrtou32(prWlanCfgEntry->aucValue, 0, &u4Value); + if (u4Ret) { + DBGLOG(INIT, LOUD, "parse aucValue error u4Ret=%d\n", + u4Ret); + return 0; + } + } + + wlanCfgRecordValue(prAdapter, pucKey, u4Value); + + return u4Value; +} + +s32 wlanCfgGetInt32(IN P_ADAPTER_T prAdapter, const s8 *pucKey, s32 i4ValueDef) +{ + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_WLAN_CFG_T prWlanCfg; + s32 i4Value = 0; + s32 i4Ret = 0; + + prWlanCfg = prAdapter->prWlanCfg; + + ASSERT(prWlanCfg); + + i4Value = i4ValueDef; + /* Find the exist */ + prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey, false); + + if (prWlanCfgEntry) { + /* i4Ret = kalStrtol(prWlanCfgEntry->aucValue, NULL, 0); */ + i4Ret = kalkStrtos32(prWlanCfgEntry->aucValue, 0, &i4Value); + if (i4Ret) { + DBGLOG(INIT, LOUD, "parse aucValue error i4Ret=%d\n", + i4Ret); + } + } + + wlanCfgRecordValue(prAdapter, pucKey, i4Value); + + return i4Value; +} + +WLAN_STATUS wlanCfgSet(IN P_ADAPTER_T prAdapter, const s8 *pucKey, s8 *pucValue, + u32 u4Flags) +{ + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_WLAN_CFG_T prWlanCfg = NULL; + P_WLAN_CFG_REC_T prWlanCfgRec = NULL; + u32 u4EntryIndex; + u32 i; + u8 ucExist; + u8 fgGetCfgRec = false; + + fgGetCfgRec = u4Flags & WLAN_CFG_REC_FLAG_BIT; + + ASSERT(pucKey); + + /* Find the exist */ + ucExist = 0; + if (fgGetCfgRec) { + prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey, true); + prWlanCfgRec = prAdapter->prWlanCfgRec; + ASSERT(prWlanCfgRec); + } else { + prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey, false); + prWlanCfg = prAdapter->prWlanCfg; + ASSERT(prWlanCfg); + } + + if (!prWlanCfgEntry) { + /* Find the empty */ + for (i = 0; i < WLAN_CFG_ENTRY_NUM_MAX; i++) { + if (fgGetCfgRec) { + prWlanCfgEntry = &prWlanCfgRec->arWlanCfgBuf[i]; + }else{ + prWlanCfgEntry = &prWlanCfg->arWlanCfgBuf[i]; + } + if (prWlanCfgEntry->aucKey[0] == '\0') { + break; + } + } + + u4EntryIndex = i; + if (u4EntryIndex < WLAN_CFG_ENTRY_NUM_MAX) { + if (fgGetCfgRec) { + prWlanCfgEntry = + &prWlanCfgRec + ->arWlanCfgBuf[u4EntryIndex]; + } else { + prWlanCfgEntry = + &prWlanCfg->arWlanCfgBuf[u4EntryIndex]; + } + kalMemZero(prWlanCfgEntry, sizeof(WLAN_CFG_ENTRY_T)); + } else { + prWlanCfgEntry = NULL; + DBGLOG(INIT, INFO, + "wifi config there is no empty entry\n"); + } + } /* !prWlanCfgEntry */ + else { + ucExist = 1; + } + + if (prWlanCfgEntry) { + if (ucExist == 0) { + kalStrnCpy(prWlanCfgEntry->aucKey, pucKey, + WLAN_CFG_KEY_LEN_MAX - 1); + prWlanCfgEntry->aucKey[WLAN_CFG_KEY_LEN_MAX - 1] = '\0'; + } + + if (pucValue && pucValue[0] != '\0') { + kalStrnCpy(prWlanCfgEntry->aucValue, pucValue, + WLAN_CFG_VALUE_LEN_MAX - 1); + prWlanCfgEntry->aucValue[WLAN_CFG_VALUE_LEN_MAX - 1] = + '\0'; + + if (ucExist) { + if (prWlanCfgEntry->pfSetCb) { + prWlanCfgEntry->pfSetCb( + prAdapter, + prWlanCfgEntry->aucKey, + prWlanCfgEntry->aucValue, + prWlanCfgEntry->pPrivate, 0); + } + } + } else { + /* Call the pfSetCb if value is empty ? */ + /* remove the entry if value is empty */ + kalMemZero(prWlanCfgEntry, sizeof(WLAN_CFG_ENTRY_T)); + } + } + /* prWlanCfgEntry */ + if (prWlanCfgEntry) { + DBGLOG(INIT, INFO, "Set wifi config exist %u \'%s\' \'%s\'\n", + ucExist, prWlanCfgEntry->aucKey, + prWlanCfgEntry->aucValue); + return WLAN_STATUS_SUCCESS; + } + if (pucKey) { + DBGLOG(INIT, INFO, "Set wifi config error key \'%s\'\n", + pucKey); + } + + if (pucValue) { + DBGLOG(INIT, INFO, "Set wifi config error value \'%s\'\n", + pucValue); + } + + return WLAN_STATUS_FAILURE; +} + +WLAN_STATUS +wlanCfgSetCb(IN P_ADAPTER_T prAdapter, const s8 *pucKey, + WLAN_CFG_SET_CB pfSetCb, void *pPrivate, u32 u4Flags) +{ + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_WLAN_CFG_T prWlanCfg; + + prWlanCfg = prAdapter->prWlanCfg; + ASSERT(prWlanCfg); + + /* Find the exist */ + prWlanCfgEntry = wlanCfgGetEntry(prAdapter, pucKey, false); + + if (prWlanCfgEntry) { + prWlanCfgEntry->pfSetCb = pfSetCb; + prWlanCfgEntry->pPrivate = pPrivate; + } + + if (prWlanCfgEntry) { + return WLAN_STATUS_SUCCESS; + }else{ + return WLAN_STATUS_FAILURE; + } +} + +WLAN_STATUS wlanCfgSetUint32(IN P_ADAPTER_T prAdapter, const s8 *pucKey, + u32 u4Value) +{ + P_WLAN_CFG_T prWlanCfg; + u8 aucBuf[WLAN_CFG_VALUE_LEN_MAX]; + + prWlanCfg = prAdapter->prWlanCfg; + + ASSERT(prWlanCfg); + + kalMemZero(aucBuf, sizeof(aucBuf)); + + kalSnprintf(aucBuf, WLAN_CFG_VALUE_LEN_MAX, "0x%x", + (unsigned int)u4Value); + + return wlanCfgSet(prAdapter, pucKey, aucBuf, 0); +} + +enum { + STATE_EOF = 0, + STATE_TEXT = 1, + STATE_NEWLINE = 2 +}; + +s32 wlanCfgFindNextToken(struct WLAN_CFG_PARSE_STATE_S *state) +{ + s8 *x = state->ptr; + s8 *s; + + if (state->nexttoken) { + s32 t = state->nexttoken; + + state->nexttoken = 0; + return t; + } + + for (;;) { + switch (*x) { + case 0: + state->ptr = x; + return STATE_EOF; + + case '\n': + x++; + state->ptr = x; + return STATE_NEWLINE; + + case ' ': + case ',': + /*case ':': should not including : , mac addr would be fail*/ + case '\t': + case '\r': + x++; + continue; + + case '#': + while (*x && (*x != '\n')) + x++; + if (*x == '\n') { + state->ptr = x + 1; + return STATE_NEWLINE; + } + state->ptr = x; + return STATE_EOF; + + default: + goto text; + } + } + +textdone: + state->ptr = x; + *s = 0; + return STATE_TEXT; + +text: + state->text = s = x; +textresume: + for (;;) { + switch (*x) { + case 0: + goto textdone; + + case ' ': + case ',': + /*case ':': + */ + case '\t': + case '\r': + x++; + goto textdone; + + case '\n': + state->nexttoken = STATE_NEWLINE; + x++; + goto textdone; + + case '"': + x++; + for (;;) { + switch (*x) { + case 0: + /* unterminated quoted thing */ + state->ptr = x; + return STATE_EOF; + + case '"': + x++; + goto textresume; + + default: + *s++ = *x++; + } + } + break; + + case '\\': + x++; + switch (*x) { + case 0: + goto textdone; + + case 'n': + *s++ = '\n'; + break; + + case 'r': + *s++ = '\r'; + break; + + case 't': + *s++ = '\t'; + break; + + case '\\': + *s++ = '\\'; + break; + + case '\r': + /* \ <cr> <lf> -> line continuation */ + if (x[1] != '\n') { + x++; + continue; + } + + /* FALLTHRU */ + case '\n': + /* \ <lf> -> line continuation */ + x++; + /* eat any extra whitespace */ + while ((*x == ' ') || (*x == '\t')) + x++; + continue; + + default: + /* unknown escape -- just copy */ + *s++ = *x++; + } + continue; + + default: + *s++ = *x++; +#if CFG_SUPPORT_EASY_DEBUG + state->textsize++; +#endif + } + } + return STATE_EOF; +} + +WLAN_STATUS wlanCfgParseArgument(s8 *cmdLine, s32 *argc, s8 *argv[]) +{ + struct WLAN_CFG_PARSE_STATE_S state; + s8 **args; + s32 nargs; + + if (cmdLine == NULL || argc == NULL || argv == NULL) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + args = argv; + nargs = 0; + state.ptr = cmdLine; + state.nexttoken = 0; + state.maxSize = 0; +#if CFG_SUPPORT_EASY_DEBUG + state.textsize = 0; +#endif + + if (kalStrnLen(cmdLine, 512) >= 512) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + for (;;) { + switch (wlanCfgFindNextToken(&state)) { + case STATE_EOF: + goto exit; + + case STATE_NEWLINE: + goto exit; + + case STATE_TEXT: + if (nargs < WLAN_CFG_ARGV_MAX) { + args[nargs++] = state.text; + } + break; + } + } + +exit: + *argc = nargs; + return WLAN_STATUS_SUCCESS; +} + +#if CFG_WOW_SUPPORT +WLAN_STATUS wlanCfgParseArgumentLong(s8 *cmdLine, s32 *argc, s8 *argv[]) +{ + struct WLAN_CFG_PARSE_STATE_S state; + s8 **args; + s32 nargs; + + if (cmdLine == NULL || argc == NULL || argv == NULL) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + args = argv; + nargs = 0; + state.ptr = cmdLine; + state.nexttoken = 0; + state.maxSize = 0; +#if CFG_SUPPORT_EASY_DEBUG + state.textsize = 0; +#endif + + if (kalStrnLen(cmdLine, 512) >= 512) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + + for (;;) { + switch (wlanCfgFindNextToken(&state)) { + case STATE_EOF: + goto exit; + + case STATE_NEWLINE: + goto exit; + + case STATE_TEXT: + if (nargs < WLAN_CFG_ARGV_MAX_LONG) { + args[nargs++] = state.text; + } + break; + } + } + +exit: + *argc = nargs; + return WLAN_STATUS_SUCCESS; +} +#endif + +WLAN_STATUS wlanCfgParseAddEntry(IN P_ADAPTER_T prAdapter, u8 *pucKeyHead, u8 *pucKeyTail, u8 *pucValueHead, u8 *pucValueTail) +{ + u8 aucKey[WLAN_CFG_KEY_LEN_MAX]; + u8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; + u32 u4Len; + + kalMemZero(aucKey, sizeof(aucKey)); + kalMemZero(aucValue, sizeof(aucValue)); + + if ((pucKeyHead == NULL) || (pucValueHead == NULL)) { + return WLAN_STATUS_FAILURE; + } + + if (pucKeyTail) { + if (pucKeyHead > pucKeyTail) { + return WLAN_STATUS_FAILURE; + } + + u4Len = pucKeyTail - pucKeyHead + 1; + } else { + u4Len = kalStrnLen(pucKeyHead, WLAN_CFG_KEY_LEN_MAX - 1); + } + + if (u4Len >= WLAN_CFG_KEY_LEN_MAX) { + u4Len = WLAN_CFG_KEY_LEN_MAX - 1; + } + + kalStrnCpy(aucKey, pucKeyHead, u4Len); + + if (pucValueTail) { + if (pucValueHead > pucValueTail) { + return WLAN_STATUS_FAILURE; + } + + u4Len = pucValueTail - pucValueHead + 1; + } else { + u4Len = kalStrnLen(pucValueHead, WLAN_CFG_VALUE_LEN_MAX - 1); + } + + if (u4Len >= WLAN_CFG_VALUE_LEN_MAX) { + u4Len = WLAN_CFG_VALUE_LEN_MAX - 1; + } + + kalStrnCpy(aucValue, pucValueHead, u4Len); + + return wlanCfgSet(prAdapter, aucKey, aucValue, 0); +} + +enum { + WAIT_KEY_HEAD = 0, + WAIT_KEY_TAIL, + WAIT_VALUE_HEAD, + WAIT_VALUE_TAIL, + WAIT_COMMENT_TAIL +}; + +#if CFG_SUPPORT_EASY_DEBUG + +s8 atoi(u8 ch) +{ + if (ch >= 'a' && ch <= 'f') { + return ch - 87; + }else if (ch >= 'A' && ch <= 'F') { + return ch - 55; + }else if (ch >= '0' && ch <= '9') { + return ch - 48; + } + + return 0; +} + +WLAN_STATUS wlanCfgParseToFW(s8 **args, s8 *args_size, u8 nargs, s8 *buffer, u8 times) +{ + u8 *data = NULL; + char ch; + s32 i = 0, j = 0; + u32 bufferindex = 0, base = 0; + u32 sum = 0, startOffset = 0; + CMD_FORMAT_V1_T cmd_v1; + + memset(&cmd_v1, 0, sizeof(CMD_FORMAT_V1_T)); + + cmd_v1.itemType = ITEM_TYPE_DEC; + + if (buffer == NULL || args_size[ED_STRING_SITE] == 0 || + args_size[ED_VALUE_SITE] == 0 || + (cmd_v1.itemType < ITEM_TYPE_DEC || + cmd_v1.itemType > ITEM_TYPE_STR)) { + DBGLOG(INIT, ERROR, "cfg args wrong\n"); + return WLAN_STATUS_FAILURE; + } + + cmd_v1.itemStringLength = args_size[ED_STRING_SITE]; + strncpy(cmd_v1.itemString, args[ED_STRING_SITE], + cmd_v1.itemStringLength); + DBGLOG(INIT, INFO, "itemString:"); + for (i = 0; i < cmd_v1.itemStringLength; i++) + DBGLOG(INIT, INFO, "%c", cmd_v1.itemString[i]); + DBGLOG(INIT, INFO, "\n"); + + DBGLOG(INIT, INFO, "cmd_v1.itemType = %d\n", cmd_v1.itemType); + if (cmd_v1.itemType == ITEM_TYPE_DEC || + cmd_v1.itemType == ITEM_TYPE_HEX) { + data = args[ED_VALUE_SITE]; + + switch (cmd_v1.itemType) { + case ITEM_TYPE_DEC: + base = 10; + startOffset = 0; + break; + + case ITEM_TYPE_HEX: + ch = *data; + if (args_size[ED_VALUE_SITE] < 3 || ch != '0') { + DBGLOG(INIT, WARN, + "Hex args must have prefix '0x'\n"); + return WLAN_STATUS_FAILURE; + } + + data++; + ch = *data; + if (ch != 'x' && ch != 'X') { + DBGLOG(INIT, WARN, + "Hex args must have prefix '0x'\n"); + return WLAN_STATUS_FAILURE; + } + data++; + base = 16; + startOffset = 2; + break; + } + + for (j = args_size[ED_VALUE_SITE] - 1 - startOffset; j >= 0; + j--) { + sum = sum * base + atoi(*data); + DBGLOG(INIT, WARN, "size:%d data[%d]=%u, sum=%u\n", + args_size[ED_VALUE_SITE], j, atoi(*data), sum); + + data++; + } + + bufferindex = 0; + do { + cmd_v1.itemValue[bufferindex++] = sum & 0xFF; + sum = sum >> 8; + } while (sum > 0); + cmd_v1.itemValueLength = bufferindex; + } else if (cmd_v1.itemType == ITEM_TYPE_STR) { + cmd_v1.itemValueLength = args_size[ED_VALUE_SITE]; + strncpy(cmd_v1.itemValue, args[ED_VALUE_SITE], + cmd_v1.itemValueLength); + } + + DBGLOG(INIT, INFO, "Length = %d itemValue:", cmd_v1.itemValueLength); + for (i = cmd_v1.itemValueLength - 1; i >= 0; i--) + DBGLOG(INIT, ERROR, "%d,", cmd_v1.itemValue[i]); + DBGLOG(INIT, INFO, "\n"); + memcpy(((P_CMD_FORMAT_V1_T)buffer) + times, &cmd_v1, + sizeof(CMD_FORMAT_V1_T)); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to send WLAN feature options to firmware + * + * @param prAdapter Pointer of ADAPTER_T + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void wlanFeatureToFw(IN P_ADAPTER_T prAdapter) +{ + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + u32 i; + CMD_HEADER_T rCmdV1Header; + WLAN_STATUS rStatus; + CMD_FORMAT_V1_T rCmd_v1; + u8 ucTimes = 0; + + rCmdV1Header.cmdType = CMD_TYPE_SET; + rCmdV1Header.cmdVersion = CMD_VER_1; + rCmdV1Header.cmdBufferLen = 0; + rCmdV1Header.itemNum = 0; + + kalMemSet(rCmdV1Header.buffer, 0, MAX_CMD_BUFFER_LENGTH); + kalMemSet(&rCmd_v1, 0, sizeof(CMD_FORMAT_V1_T)); + + prWlanCfgEntry = NULL; + + for (i = 0; i < WLAN_CFG_ENTRY_NUM_MAX; i++) { + prWlanCfgEntry = wlanCfgGetEntryByIndex(prAdapter, i, 0); + + if (prWlanCfgEntry) { + rCmd_v1.itemType = ITEM_TYPE_STR; + + /*send string format to firmware */ + rCmd_v1.itemStringLength = + kalStrLen(prWlanCfgEntry->aucKey); + kalMemZero(rCmd_v1.itemString, MAX_CMD_NAME_MAX_LENGTH); + kalMemCopy(rCmd_v1.itemString, prWlanCfgEntry->aucKey, + rCmd_v1.itemStringLength); + + rCmd_v1.itemValueLength = + kalStrLen(prWlanCfgEntry->aucValue); + kalMemZero(rCmd_v1.itemValue, MAX_CMD_VALUE_MAX_LENGTH); + kalMemCopy(rCmd_v1.itemValue, prWlanCfgEntry->aucValue, + rCmd_v1.itemValueLength); + + DBGLOG(INIT, INFO, + "Send key word (%s) WITH (%s) to firmware\n", + rCmd_v1.itemString, rCmd_v1.itemValue); + + kalMemCopy(((P_CMD_FORMAT_V1_T)rCmdV1Header.buffer) + + ucTimes, + &rCmd_v1, sizeof(CMD_FORMAT_V1_T)); + + ucTimes++; + rCmdV1Header.cmdBufferLen += sizeof(CMD_FORMAT_V1_T); + rCmdV1Header.itemNum += ucTimes; + + if (ucTimes == MAX_CMD_ITEM_MAX) { + /* Send to FW */ + rCmdV1Header.itemNum = ucTimes; + + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_GET_SET_CUSTOMER_CFG, /* 0x70 */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler*/ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_HEADER_T), /* u4SetQueryInfoLen + */ + (u8 *)&rCmdV1Header, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus == WLAN_STATUS_FAILURE) { + DBGLOG(INIT, + INFO, + "[Fail]kalIoctl wifiSefCFG fail 0x%x\n", + rStatus); + } + + DBGLOG(INIT, INFO, + "kalIoctl wifiSefCFG num:%d\n", ucTimes); + kalMemSet(rCmdV1Header.buffer, 0, + MAX_CMD_BUFFER_LENGTH); + rCmdV1Header.cmdBufferLen = 0; + ucTimes = 0; + } + } else { + break; + } + } + + if (ucTimes != 0) { + /* Send to FW */ + rCmdV1Header.itemNum = ucTimes; + + DBGLOG(INIT, INFO, "cmdV1Header.itemNum:%d\n", + rCmdV1Header.itemNum); + + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_GET_SET_CUSTOMER_CFG, /* 0x70 + */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler*/ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_HEADER_T), /* u4SetQueryInfoLen + */ + (u8 *)&rCmdV1Header, /* pucInfoBuffer + */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus == WLAN_STATUS_FAILURE) { + DBGLOG(INIT, INFO, + "[Fail]kalIoctl wifiSefCFG fail 0x%x\n", + rStatus); + } + + DBGLOG(INIT, INFO, "kalIoctl wifiSefCFG num:%d\n", ucTimes); + kalMemSet(rCmdV1Header.buffer, 0, MAX_CMD_BUFFER_LENGTH); + rCmdV1Header.cmdBufferLen = 0; + ucTimes = 0; + } +} + +WLAN_STATUS wlanCfgParse(IN P_ADAPTER_T prAdapter, u8 *pucConfigBuf, + u32 u4ConfigBufLen, u8 isFwConfig) +{ + struct WLAN_CFG_PARSE_STATE_S state; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s8 **ppcArgs; + s32 i4Nargs; + s8 arcArgv_size[WLAN_CFG_ARGV_MAX]; + u8 ucTimes = 0; + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + CMD_HEADER_T rCmdV1Header; + s8 ucTmp[WLAN_CFG_VALUE_LEN_MAX]; + u8 i; + + u8 *pucCurrBuf = ucTmp; + u32 u4CurrSize = ARRAY_SIZE(ucTmp); + u32 u4RetSize = 0; + + rCmdV1Header.cmdType = CMD_TYPE_SET; + rCmdV1Header.cmdVersion = CMD_VER_1; + rCmdV1Header.cmdBufferLen = 0; + kalMemSet(rCmdV1Header.buffer, 0, MAX_CMD_BUFFER_LENGTH); + + if (pucConfigBuf == NULL) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + if (kalStrnLen(pucConfigBuf, 4000) >= 4000) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + if (u4ConfigBufLen == 0) { + return WLAN_STATUS_FAILURE; + } + + ppcArgs = apcArgv; + i4Nargs = 0; + state.ptr = pucConfigBuf; + state.nexttoken = 0; + state.textsize = 0; + state.maxSize = u4ConfigBufLen; + DBGLOG(INIT, INFO, "wlanCfgParse()\n"); + + for (;;) { + switch (wlanCfgFindNextToken(&state)) { + case STATE_EOF: + if (i4Nargs < 2) { + goto exit; + } + + DBGLOG(INIT, INFO, "STATE_EOF\n"); + + /*3 parmeter mode transforation */ + if (i4Nargs == 3 && !isFwConfig && + arcArgv_size[0] == 1) { + /*parsing and transfer the format + * Format 1:Dec 2.Hex 3.String + */ + + kalMemZero(ucTmp, WLAN_CFG_VALUE_LEN_MAX); + pucCurrBuf = ucTmp; + u4CurrSize = ARRAY_SIZE(ucTmp); + + if ((*ppcArgs[0] == '2') && + (*(ppcArgs[2]) != '0') && + (*(ppcArgs[2] + 1) != 'x')) { + DBGLOG(INIT, WARN, + "config file got a hex format\n"); + kalSnprintf(pucCurrBuf, u4CurrSize, + "0x%s", ppcArgs[2]); + } else { + kalSnprintf(pucCurrBuf, u4CurrSize, + "%s", ppcArgs[2]); + } + DBGLOG(INIT, WARN, + "[3 parameter mode][%s],[%s],[%s]\n", + ppcArgs[0], ppcArgs[1], ucTmp); + wlanCfgParseAddEntry(prAdapter, ppcArgs[1], + NULL, ucTmp, NULL); + kalMemSet(arcArgv_size, 0, WLAN_CFG_ARGV_MAX); + kalMemSet(apcArgv, 0, + WLAN_CFG_ARGV_MAX * sizeof(char *)); + i4Nargs = 0; + goto exit; + } + + wlanCfgParseAddEntry(prAdapter, ppcArgs[0], NULL, + ppcArgs[1], NULL); + + if (isFwConfig) { + WLAN_STATUS ret; + + ret = wlanCfgParseToFW(ppcArgs, arcArgv_size, + i4Nargs, + rCmdV1Header.buffer, + ucTimes); + if (ret == WLAN_STATUS_SUCCESS) { + ucTimes++; + rCmdV1Header.cmdBufferLen += + sizeof(CMD_FORMAT_V1_T); + } + } + + goto exit; + + case STATE_NEWLINE: + if (i4Nargs < 2) { + break; + } + + DBGLOG(INIT, INFO, "STATE_NEWLINE\n"); + + /*3 parmeter mode transforation */ + if (i4Nargs == 3 && !isFwConfig && + arcArgv_size[0] == 1) { + /*parsing and transfer the format + * Format 1:Dec 2.Hex 3.String + */ + kalMemZero(ucTmp, WLAN_CFG_VALUE_LEN_MAX); + pucCurrBuf = ucTmp; + u4CurrSize = ARRAY_SIZE(ucTmp); + + if ((*ppcArgs[0] == '2') && + (*(ppcArgs[2]) != '0') && + (*(ppcArgs[2] + 1) != 'x')) { + DBGLOG(INIT, WARN, + "config file got a hex format\n"); + kalSnprintf(pucCurrBuf, u4CurrSize, + "0x%s", ppcArgs[2]); + } else { + kalSnprintf(pucCurrBuf, u4CurrSize, + "%s", ppcArgs[2]); + } + + DBGLOG(INIT, WARN, + "[3 parameter mode][%s],[%s],[%s]\n", + ppcArgs[0], ppcArgs[1], ucTmp); + wlanCfgParseAddEntry(prAdapter, ppcArgs[1], + NULL, ucTmp, NULL); + kalMemSet(arcArgv_size, 0, WLAN_CFG_ARGV_MAX); + kalMemSet(apcArgv, 0, + WLAN_CFG_ARGV_MAX * sizeof(char *)); + i4Nargs = 0; + break; + } + + /*combine the argument to save in temp*/ + pucCurrBuf = ucTmp; + u4CurrSize = ARRAY_SIZE(ucTmp); + + kalMemZero(ucTmp, WLAN_CFG_VALUE_LEN_MAX); + + if (i4Nargs == 2) { + /*no space for it, driver can't accept space in + * the end of the line*/ + /*ToDo: skip the space when parsing*/ + kalSnprintf(pucCurrBuf, u4CurrSize, "%s", + ppcArgs[1]); + } else { + for (i = 1; i < i4Nargs; i++) { + if (u4CurrSize <= 1) { + DBGLOG(INIT, + ERROR, + "write to pucCurrBuf out of bound, i=%d\n", + i); + break; + } + u4RetSize = scnprintf(pucCurrBuf, + u4CurrSize, "%s ", + ppcArgs[i]); + pucCurrBuf += u4RetSize; + u4CurrSize -= u4RetSize; + } + } + + DBGLOG(INIT, INFO, + "Save to driver temp buffer as [%s]\n", ucTmp); + wlanCfgParseAddEntry(prAdapter, ppcArgs[0], NULL, ucTmp, + NULL); + + if (isFwConfig) { + WLAN_STATUS ret; + + ret = wlanCfgParseToFW(ppcArgs, arcArgv_size, + i4Nargs, + rCmdV1Header.buffer, + ucTimes); + if (ret == WLAN_STATUS_SUCCESS) { + ucTimes++; + rCmdV1Header.cmdBufferLen += + sizeof(CMD_FORMAT_V1_T); + } + + if (ucTimes == MAX_CMD_ITEM_MAX) { + /* Send to FW */ + rCmdV1Header.itemNum = ucTimes; + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_GET_SET_CUSTOMER_CFG, /* 0x70 */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler*/ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_HEADER_T), /* u4SetQueryInfoLen + */ + (u8 *)&rCmdV1Header, /* pucInfoBuffer + */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus == WLAN_STATUS_FAILURE) { + DBGLOG(INIT, + INFO, + "kalIoctl wifiSefCFG fail 0x%x\n", + rStatus); + } + DBGLOG(INIT, INFO, + "kalIoctl wifiSefCFG num:%d X\n", + ucTimes); + kalMemSet(rCmdV1Header.buffer, 0, + MAX_CMD_BUFFER_LENGTH); + rCmdV1Header.cmdBufferLen = 0; + ucTimes = 0; + } + } + + kalMemSet(arcArgv_size, 0, WLAN_CFG_ARGV_MAX); + kalMemSet(apcArgv, 0, + WLAN_CFG_ARGV_MAX * sizeof(char *)); + i4Nargs = 0; + break; + + case STATE_TEXT: + if (i4Nargs < WLAN_CFG_ARGV_MAX) { + ppcArgs[i4Nargs++] = state.text; + arcArgv_size[i4Nargs - 1] = state.textsize; + state.textsize = 0; + DBGLOG(INIT, + INFO, + " nargs= %d STATE_TEXT = %s, SIZE = %d\n", + i4Nargs - 1, + ppcArgs[i4Nargs - 1], + arcArgv_size[i4Nargs - 1]); + } + break; + } + } + +exit: + if (ucTimes != 0 && isFwConfig) { + /* Send to FW */ + rCmdV1Header.itemNum = ucTimes; + + DBGLOG(INIT, INFO, "cmdV1Header.itemNum:%d\n", + rCmdV1Header.itemNum); + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_GET_SET_CUSTOMER_CFG, /* 0x70 + */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler*/ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_HEADER_T), /* u4SetQueryInfoLen + */ + (u8 *)&rCmdV1Header, /* pucInfoBuffer + */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus == WLAN_STATUS_FAILURE) { + DBGLOG(INIT, WARN, "kalIoctl wifiSefCFG fail 0x%x\n", + rStatus); + } + + DBGLOG(INIT, WARN, "kalIoctl wifiSefCFG num:%d X\n", ucTimes); + kalMemSet(rCmdV1Header.buffer, 0, MAX_CMD_BUFFER_LENGTH); + rCmdV1Header.cmdBufferLen = 0; + ucTimes = 0; + } + return WLAN_STATUS_SUCCESS; +} + +#if CFG_SUPPORT_SEND_ONLY_ONE_CFG +WLAN_STATUS wlanFeatureToFwOnlyOneCfg(IN P_ADAPTER_T prAdapter, + const s8 *pucKey, s8 *pucValue) +{ + CMD_HEADER_T rCmdV1Header; + CMD_FORMAT_V1_T rCmd_v1; + WLAN_STATUS rStatus; + u8 roffset = 0; + + ASSERT(pucKey); + + rCmdV1Header.cmdType = CMD_TYPE_SET; + rCmdV1Header.cmdVersion = CMD_VER_1; + rCmdV1Header.cmdBufferLen = 0; + rCmdV1Header.itemNum = 0; + + kalMemSet(rCmdV1Header.buffer, 0, MAX_CMD_BUFFER_LENGTH); + kalMemSet(&rCmd_v1, 0, sizeof(CMD_FORMAT_V1_T)); + + if (pucKey != NULL && pucValue != NULL) { + rCmd_v1.itemType = ITEM_TYPE_STR; + + /*send string format to firmware */ + rCmd_v1.itemStringLength = kalStrLen(pucKey); + + if (rCmd_v1.itemStringLength > MAX_CMD_NAME_MAX_LENGTH) { + return WLAN_STATUS_INVALID_LENGTH; + } + + kalMemZero(rCmd_v1.itemString, MAX_CMD_NAME_MAX_LENGTH); + kalMemCopy(rCmd_v1.itemString, pucKey, + rCmd_v1.itemStringLength); + + rCmd_v1.itemValueLength = kalStrLen(pucValue); + + if (rCmd_v1.itemValueLength > MAX_CMD_VALUE_MAX_LENGTH) { + return WLAN_STATUS_INVALID_LENGTH; + } + + kalMemZero(rCmd_v1.itemValue, MAX_CMD_VALUE_MAX_LENGTH); + kalMemCopy(rCmd_v1.itemValue, pucValue, + rCmd_v1.itemValueLength); + + DBGLOG(INIT, INFO, "Send key word (%s) WITH (%s) to firmware\n", + rCmd_v1.itemString, rCmd_v1.itemValue); + + kalMemCopy(((P_CMD_FORMAT_V1_T)rCmdV1Header.buffer) + roffset, + &rCmd_v1, sizeof(CMD_FORMAT_V1_T)); + + rCmdV1Header.cmdBufferLen = sizeof(CMD_FORMAT_V1_T); + rCmdV1Header.itemNum = 1; + + /* Send to FW */ + + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_GET_SET_CUSTOMER_CFG, /* 0x70 + */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler*/ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_HEADER_T), /* u4SetQueryInfoLen + */ + (u8 *)&rCmdV1Header, /* pucInfoBuffer + */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus == WLAN_STATUS_FAILURE) { + DBGLOG(INIT, INFO, + "[Fail]kalIoctl wifiSefCFG fail 0x%x\n", + rStatus); + } + + kalMemSet(rCmdV1Header.buffer, 0, MAX_CMD_BUFFER_LENGTH); + rCmdV1Header.cmdBufferLen = 0; + } else { + return WLAN_STATUS_INVALID_DATA; + } + return rStatus; +} +#endif + +#else +WLAN_STATUS wlanCfgParse(IN P_ADAPTER_T prAdapter, u8 *pucConfigBuf, + u32 u4ConfigBufLen) +{ + struct WLAN_CFG_PARSE_STATE_S state; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s8 **args; + s32 nargs; + + if (pucConfigBuf == NULL) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + if (kalStrnLen(pucConfigBuf, 4000) >= 4000) { + ASSERT(0); + return WLAN_STATUS_FAILURE; + } + if (u4ConfigBufLen == 0) { + return WLAN_STATUS_FAILURE; + } + + args = apcArgv; + nargs = 0; + state.ptr = pucConfigBuf; + state.nexttoken = 0; + state.maxSize = u4ConfigBufLen; + + for (;;) { + switch (wlanCfgFindNextToken(&state)) { + case STATE_EOF: + if (nargs > 1) { + wlanCfgParseAddEntry(prAdapter, args[0], NULL, + args[1], NULL); + } + goto exit; + + case STATE_NEWLINE: + if (nargs > 1) { + wlanCfgParseAddEntry(prAdapter, args[0], NULL, + args[1], NULL); + } + /*args[0] is parameter, args[1] is the value*/ + nargs = 0; + break; + + case STATE_TEXT: + if (nargs < WLAN_CFG_ARGV_MAX) { + args[nargs++] = state.text; + } + break; + } + } + +exit: + return WLAN_STATUS_SUCCESS; +} +#endif + +WLAN_STATUS wlanCfgInit(IN P_ADAPTER_T prAdapter, u8 *pucConfigBuf, + u32 u4ConfigBufLen, u32 u4Flags) +{ + P_WLAN_CFG_T prWlanCfg; + P_WLAN_CFG_REC_T prWlanCfgRec; + /* P_WLAN_CFG_ENTRY_T prWlanCfgEntry; */ + prAdapter->prWlanCfg = &prAdapter->rWlanCfg; + prWlanCfg = prAdapter->prWlanCfg; + + prAdapter->prWlanCfgRec = &prAdapter->rWlanCfgRec; + prWlanCfgRec = prAdapter->prWlanCfgRec; + + kalMemZero(prWlanCfg, sizeof(WLAN_CFG_T)); + ASSERT(prWlanCfg); + prWlanCfg->u4WlanCfgEntryNumMax = WLAN_CFG_ENTRY_NUM_MAX; + prWlanCfg->u4WlanCfgKeyLenMax = WLAN_CFG_KEY_LEN_MAX; + prWlanCfg->u4WlanCfgValueLenMax = WLAN_CFG_VALUE_LEN_MAX; + + prWlanCfgRec->u4WlanCfgEntryNumMax = WLAN_CFG_REC_ENTRY_NUM_MAX; + prWlanCfgRec->u4WlanCfgKeyLenMax = WLAN_CFG_REC_ENTRY_NUM_MAX; + prWlanCfgRec->u4WlanCfgValueLenMax = WLAN_CFG_REC_ENTRY_NUM_MAX; + + DBGLOG(INIT, INFO, "Init wifi config len %u max entry %u\n", + u4ConfigBufLen, prWlanCfg->u4WlanCfgEntryNumMax); +#if DBG + /* self test */ + wlanCfgSet(prAdapter, "ConfigValid", "0x123", 0); + if (wlanCfgGetUint32(prAdapter, "ConfigValid", 0) != 0x123) { + DBGLOG(INIT, INFO, "wifi config error %u\n", __LINE__); + } + + wlanCfgSet(prAdapter, "ConfigValid", "1", 0); + if (wlanCfgGetUint32(prAdapter, "ConfigValid", 0) != 1) { + DBGLOG(INIT, INFO, "wifi config error %u\n", __LINE__); + } +#endif + /*load default value because kalMemZero in this function*/ + wlanLoadDefaultCustomerSetting(prAdapter); + + /* Parse the pucConfigBuff */ + + if (pucConfigBuf && (u4ConfigBufLen > 0)) +#if CFG_SUPPORT_EASY_DEBUG + { wlanCfgParse(prAdapter, pucConfigBuf, u4ConfigBufLen, false); } +#else + { wlanCfgParse(prAdapter, pucConfigBuf, u4ConfigBufLen); } +#endif + return WLAN_STATUS_SUCCESS; +} + +#endif + +s32 wlanHexToNum(s8 c) +{ + if (c >= '0' && c <= '9') { + return c - '0'; + } + + if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + + if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + + return -1; +} + +s32 wlanHexToByte(s8 *hex) +{ + s32 a, b; + + a = wlanHexToNum(*hex++); + if (a < 0) { + return -1; + } + + b = wlanHexToNum(*hex++); + if (b < 0) { + return -1; + } + + return (a << 4) | b; +} + +s32 wlanHwAddrToBin(s8 *txt, u8 *addr) +{ + s32 i; + s8 *pos = txt; + + for (i = 0; i < 6; i++) { + s32 a, b; + + while (*pos == ':' || *pos == '.' || *pos == '-') + pos++; + + a = wlanHexToNum(*pos++); + if (a < 0) { + return -1; + } + + b = wlanHexToNum(*pos++); + if (b < 0) { + return -1; + } + + *addr++ = (a << 4) | b; + } + + return pos - txt; +} + +u8 wlanIsChipNoAck(IN P_ADAPTER_T prAdapter) +{ + u8 fgIsNoAck; + + fgIsNoAck = prAdapter->fgIsChipNoAck || fgIsBusAccessFailed; + + return fgIsNoAck; +} + +u8 wlanIsChipRstRecEnabled(IN P_ADAPTER_T prAdapter) +{ + return prAdapter->rWifiVar.fgChipResetRecover; +} + +u8 wlanIsChipAssert(IN P_ADAPTER_T prAdapter) +{ + return prAdapter->rWifiVar.fgChipResetRecover && + prAdapter->fgIsChipAssert; +} + +void wlanChipRstPreAct(IN P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T)NULL; + s32 i4BssIdx; + u32 u4ClientCount = 0; + P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T)NULL; + P_STA_RECORD_T prNextCurrStaRec = (P_STA_RECORD_T)NULL; + P_LINK_T prClientList; + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + + spin_lock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_CHIP_RST]); + if (prAdapter->fgIsChipAssert) { + spin_unlock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_CHIP_RST]); + return; + } + prAdapter->fgIsChipAssert = true; + spin_unlock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_CHIP_RST]); + + for (i4BssIdx = 0; i4BssIdx < HW_BSSID_NUM; i4BssIdx++) { + prBssInfo = prAdapter->aprBssInfo[i4BssIdx]; + + if (!prBssInfo->fgIsInUse) { + continue; + } + + if (prBssInfo->eNetworkType == NETWORK_TYPE_AIS) { + if (prGlueInfo->eParamMediaStateIndicated == + PARAM_MEDIA_STATE_CONNECTED) { + kalIndicateStatusAndComplete( + prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + } + } else if (prBssInfo->eNetworkType == NETWORK_TYPE_P2P) { + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + u4ClientCount = + bssGetClientCount(prAdapter, prBssInfo); + + if (u4ClientCount == 0) { + continue; + } + + prClientList = &prBssInfo->rStaRecOfClientList; + LINK_FOR_EACH_ENTRY_SAFE( + prCurrStaRec, prNextCurrStaRec, + prClientList, rLinkEntry, + STA_RECORD_T) { + kalP2PGOStationUpdate( + prAdapter->prGlueInfo, + (u8)prBssInfo->u4PrivateData, + prCurrStaRec, false); + LINK_REMOVE_KNOWN_ENTRY( + prClientList, + &prCurrStaRec->rLinkEntry); + } + } else if (prBssInfo->eCurrentOPMode == + OP_MODE_INFRASTRUCTURE) { + if (prBssInfo->prStaRecOfAP == NULL) { + continue; + } + + kalP2PGCIndicateConnectionStatus( + prGlueInfo, + (u8)prBssInfo->u4PrivateData, NULL, + NULL, 0, REASON_CODE_DEAUTH_LEAVING_BSS, + WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY); + + prBssInfo->prStaRecOfAP = NULL; + } + } + } +} + +#if CFG_ENABLE_PER_STA_STATISTICS +void wlanTxLifetimeUpdateStaStats(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_STA_RECORD_T prStaRec; + u32 u4DeltaTime; + P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (prStaRec) { + u4DeltaTime = (u32)(prPktProfile->rHifTxDoneTimestamp - + prPktProfile->rHardXmitArrivalTimestamp); + + /* Update StaRec statistics */ + prStaRec->u4TotalTxPktsNumber++; + prStaRec->u4TotalTxPktsTime += u4DeltaTime; + + if (u4DeltaTime > prStaRec->u4MaxTxPktsTime) { + prStaRec->u4MaxTxPktsTime = u4DeltaTime; + } + if (u4DeltaTime >= NIC_TX_TIME_THRESHOLD) { + prStaRec->u4ThresholdCounter++; + } + } +} +#endif + +u8 wlanTxLifetimeIsProfilingEnabled(IN P_ADAPTER_T prAdapter) +{ + u8 fgEnabled = false; +#if CFG_SUPPORT_WFD + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T)NULL; + + prWfdCfgSettings = &prAdapter->rWifiVar.rWfdConfigureSettings; + + if (prWfdCfgSettings->ucWfdEnable > 0) { + fgEnabled = true; + } +#endif + + return fgEnabled; +} + +u8 wlanTxLifetimeIsTargetMsdu(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + return true; +} + +void wlanTxLifetimeTagPacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_PROFILING_TAG_T eTag) +{ + P_PKT_PROFILE_T prPktProfile = &prMsduInfo->rPktProfile; + + if (!wlanTxLifetimeIsProfilingEnabled(prAdapter)) { + return; + } + + switch (eTag) { + case TX_PROF_TAG_OS_TO_DRV: + /* arrival time is tagged in wlanProcessTxFrame */ + break; + + case TX_PROF_TAG_DRV_ENQUE: + /* Reset packet profile */ + prPktProfile->fgIsValid = false; + if (wlanTxLifetimeIsTargetMsdu(prAdapter, prMsduInfo)) { + /* Enable packet lifetime profiling */ + prPktProfile->fgIsValid = true; + + /* Packet arrival time at kernel Hard Xmit */ + prPktProfile->rHardXmitArrivalTimestamp = + GLUE_GET_PKT_ARRIVAL_TIME(prMsduInfo->prPacket); + + /* Packet enqueue time */ + prPktProfile->rEnqueueTimestamp = (u32)kalGetTimeTick(); + } + break; + + case TX_PROF_TAG_DRV_DEQUE: + if (prPktProfile->fgIsValid) { + prPktProfile->rDequeueTimestamp = (u32)kalGetTimeTick(); + } + break; + + case TX_PROF_TAG_DRV_TX_DONE: + if (prPktProfile->fgIsValid) { + prPktProfile->rHifTxDoneTimestamp = + (u32)kalGetTimeTick(); + +#if CFG_ENABLE_PER_STA_STATISTICS + wlanTxLifetimeUpdateStaStats(prAdapter, prMsduInfo); +#endif + } + break; + + case TX_PROF_TAG_MAC_TX_DONE: + break; + + default: + break; + } +} + +void wlanTxProfilingTagPacket(IN P_ADAPTER_T prAdapter, + IN P_NATIVE_PACKET prPacket, + IN ENUM_TX_PROFILING_TAG_T eTag) +{ +#if CFG_MET_PACKET_TRACE_SUPPORT + kalMetTagPacket(prAdapter->prGlueInfo, prPacket, eTag); +#endif +} + +void wlanTxProfilingTagMsdu(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_PROFILING_TAG_T eTag) +{ + wlanTxLifetimeTagPacket(prAdapter, prMsduInfo, eTag); + + wlanTxProfilingTagPacket(prAdapter, prMsduInfo->prPacket, eTag); +} + +void wlanUpdateTxStatistics(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, IN u8 fgTxDrop) +{ + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + ENUM_WMM_ACI_T eAci = WMM_AC_BE_INDEX; + P_QUE_MGT_T prQM = &prAdapter->rQM; + u32 rCurTime; + + eAci = aucTid2ACI[prMsduInfo->ucUserPriority]; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (prStaRec) { + if (fgTxDrop) { + prStaRec->arLinkStatistics[eAci].u4TxDropMsdu++; + }else{ + prStaRec->arLinkStatistics[eAci].u4TxMsdu++; + } + } else { + if (prMsduInfo->ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, + "invalid bssinfo index[%u], skip dump!\n", + prMsduInfo->ucBssIndex); + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, + prMsduInfo->ucBssIndex); + + if (fgTxDrop) { + prBssInfo->arLinkStatistics[eAci].u4TxDropMsdu++; + }else{ + prBssInfo->arLinkStatistics[eAci].u4TxMsdu++; + } + } + + /* Trigger FW stats log every 20s */ + rCurTime = (u32)kalGetTimeTick(); + + DBGLOG(INIT, LOUD, "CUR[%u] LAST[%u] TO[%u]\n", rCurTime, + prQM->rLastTxPktDumpTime, + CHECK_FOR_TIMEOUT( + rCurTime, prQM->rLastTxPktDumpTime, + MSEC_TO_SYSTIME(prAdapter->rWifiVar.u4StatsLogTimeout))); + + if (CHECK_FOR_TIMEOUT( + rCurTime, prQM->rLastTxPktDumpTime, + MSEC_TO_SYSTIME(prAdapter->rWifiVar.u4StatsLogTimeout))) { + wlanTriggerStatsLog(prAdapter, + prAdapter->rWifiVar.u4StatsLogDuration); + wlanDumpAllBssStatistics(prAdapter); + + prQM->rLastTxPktDumpTime = rCurTime; + } +} + +void wlanUpdateRxStatistics(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_STA_RECORD_T prStaRec; + ENUM_WMM_ACI_T eAci = WMM_AC_BE_INDEX; + + eAci = aucTid2ACI[prSwRfb->ucTid]; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + if (prStaRec) { + prStaRec->arLinkStatistics[eAci].u4RxMsdu++; + } +} + +WLAN_STATUS wlanTriggerStatsLog(IN P_ADAPTER_T prAdapter, + IN u32 u4DurationInMs) +{ + CMD_STATS_LOG_T rStatsLogCmd; + WLAN_STATUS rResult; + + if (prAdapter->fgIsEnableLpdvt) { + return WLAN_STATUS_NOT_SUPPORTED; + } + + kalMemZero(&rStatsLogCmd, sizeof(CMD_STATS_LOG_T)); + + rStatsLogCmd.u4DurationInMs = u4DurationInMs; + + rResult = wlanSendSetQueryCmd(prAdapter, CMD_ID_STATS_LOG, true, false, + false, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_STATS_LOG_T), + (u8 *)&rStatsLogCmd, NULL, 0); + + return rResult; +} + +WLAN_STATUS +wlanDhcpTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + DBGLOG(SW4, INFO, "DHCP PKT[0x%08x] WIDX:PID[%u:%u] Status[%u]\n", + prMsduInfo->u4TxDoneTag, prMsduInfo->ucWlanIndex, + prMsduInfo->ucPID, rTxDoneStatus); + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS wlanArpTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + DBGLOG(SW4, INFO, "ARP PKT[0x%08x] WIDX:PID[%u:%u] Status[%u]\n", + prMsduInfo->u4TxDoneTag, prMsduInfo->ucWlanIndex, + prMsduInfo->ucPID, rTxDoneStatus); + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS wlan1xTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + DBGLOG(SW4, STATE, "1x PKT[0x%08x] WIDX:PID[%u:%u] Status[%u]\n", + prMsduInfo->u4TxDoneTag, prMsduInfo->ucWlanIndex, + prMsduInfo->ucPID, rTxDoneStatus); + + prAdapter->r1xTxDoneStatus = rTxDoneStatus; + + return WLAN_STATUS_SUCCESS; +} + +#if CFG_ASSERT_DUMP +void wlanCorDumpTimerReset(IN P_ADAPTER_T prAdapter, u8 fgIsResetN9) +{ + if (prAdapter->fgN9AssertDumpOngoing || + prAdapter->fgCr4AssertDumpOngoing) { + if (fgIsResetN9) { + cnmTimerStopTimer(prAdapter, + &prAdapter->rN9CorDumpTimer); + cnmTimerStartTimer(prAdapter, + &prAdapter->rN9CorDumpTimer, 5000); + } else { + cnmTimerStopTimer(prAdapter, + &prAdapter->rCr4CorDumpTimer); + cnmTimerStartTimer(prAdapter, + &prAdapter->rCr4CorDumpTimer, 5000); + } + } else { + DBGLOG(INIT, INFO, + "Cr4, N9 CorDump Is not ongoing, ignore timer reset\n"); + } +} + +void wlanN9CorDumpTimeOut(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr) +{ + if (prAdapter->fgN9CorDumpFileOpend) { + DBGLOG(INIT, INFO, "\n[DUMP_N9]====N9 ASSERT_END====\n"); + prAdapter->fgN9AssertDumpOngoing = false; + kalCloseCorDumpFile(true); + prAdapter->fgN9CorDumpFileOpend = false; + } +} + +void wlanCr4CorDumpTimeOut(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr) +{ + if (prAdapter->fgCr4CorDumpFileOpend) { + DBGLOG(INIT, INFO, "\n[DUMP_Cr4]====Cr4 ASSERT_END====\n"); + prAdapter->fgCr4AssertDumpOngoing = false; + kalCloseCorDumpFile(false); + prAdapter->fgCr4CorDumpFileOpend = false; + } +} +#endif + +u8 wlanGetWlanIdxByAddress(IN P_ADAPTER_T prAdapter, IN u8 *pucAddr, + OUT u8 *pucIndex) +{ + u8 ucStaRecIdx; + P_STA_RECORD_T prTempStaRec; + + for (ucStaRecIdx = 0; ucStaRecIdx < CFG_STA_REC_NUM; ucStaRecIdx++) { + prTempStaRec = &(prAdapter->arStaRec[ucStaRecIdx]); + if (pucAddr) { + if (prTempStaRec->fgIsInUse && + EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, pucAddr)) { + *pucIndex = prTempStaRec->ucWlanIndex; + return true; + } + } else { + if (prTempStaRec->fgIsInUse && + prTempStaRec->ucStaState == STA_STATE_3) { + *pucIndex = prTempStaRec->ucWlanIndex; + return true; + } + } + } + return false; +} + +u8 *wlanGetStaAddrByWlanIdx(IN P_ADAPTER_T prAdapter, IN u8 ucIndex) +{ + P_WLAN_TABLE_T prWtbl; + + if (!prAdapter) { + ASSERT(false); + } + prWtbl = prAdapter->rWifiVar.arWtbl; + if (ucIndex < WTBL_SIZE) { + if (prWtbl[ucIndex].ucUsed && prWtbl[ucIndex].ucPairwise) { + return &prWtbl[ucIndex].aucMacAddr[0]; + } + } + return NULL; +} + +#if CFG_STR_DHCP_RENEW_OFFLOAD +void wlanSetDhcpOffloadInfo(P_GLUE_INFO_T prGlueInfo, struct net_device *prDev, + u8 fgSuspend) +{ + WLAN_STATUS rStatus; + u32 u4SetInfoLen; + u8 ucBssIdx; + u8 fgOffload = false; + P_BSS_INFO_T prBssInfo; + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = + (P_NETDEV_PRIVATE_GLUE_INFO)NULL; + CMD_DHCP_OFFLOAD_SETTING_T rDhcpSetCmd; + + kalMemZero(&rDhcpSetCmd, sizeof(CMD_DHCP_OFFLOAD_SETTING_T)); + + prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(prDev); + + if (prNetDevPrivate->prGlueInfo != prGlueInfo) { + DBGLOG(REQ, WARN, "%s: unexpected prGlueInfo(0x%p)!\n", + __func__, prNetDevPrivate->prGlueInfo); + } + + ucBssIdx = prNetDevPrivate->ucBssIdx; + prBssInfo = prGlueInfo->prAdapter->aprBssInfo[ucBssIdx]; + + /* TODO: Only support AIS for now */ + if (prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex == ucBssIdx) { + if (prBssInfo->fgIsDhcpAcked == true && + prBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) { + if (fgSuspend) { + fgOffload = true; + } + } + } else { + DBGLOG(REQ, ERROR, "%s: BssIdx not matched(%d:%d)!\n", __func__, + ucBssIdx, + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + return; + } + + rDhcpSetCmd.ucEnableOffload = fgOffload; + rDhcpSetCmd.ucSuspend = fgSuspend; + rDhcpSetCmd.ucBssIndex = ucBssIdx; + rDhcpSetCmd.u4RenewIntv = prBssInfo->u4DhcpRenewIntv; + kalMemCopy(rDhcpSetCmd.aucDhcpServerIpAddr, + prBssInfo->aucDhcpServerIpAddr, + sizeof(rDhcpSetCmd.aucDhcpServerIpAddr)); + + /* When FW receive command, it check connection state to decide apply + * setting or not */ + rStatus = kalIoctl(prGlueInfo, wlanoidSetDhcpOffladInfo, + (void *)&rDhcpSetCmd, sizeof(rDhcpSetCmd), false, + false, true, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "wlanoidSetDhcpOffladInfo failed\n"); + } +} +#endif + +void wlanNotifyFwSuspend(P_GLUE_INFO_T prGlueInfo, struct net_device *prDev, + u8 fgSuspend) +{ + WLAN_STATUS rStatus; + u32 u4SetInfoLen; + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = + (P_NETDEV_PRIVATE_GLUE_INFO)NULL; + CMD_SUSPEND_MODE_SETTING_T rSuspendCmd; + + kalMemZero(&rSuspendCmd, sizeof(CMD_SUSPEND_MODE_SETTING_T)); + + prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(prDev); + + if (!prNetDevPrivate) { + DBGLOG(REQ, WARN, "prNetDevPrivate is NULL!\n"); + return; + } + + if (prNetDevPrivate->prGlueInfo != prGlueInfo) { + DBGLOG(REQ, WARN, "%s: unexpected prGlueInfo(0x%p)!\n", + __func__, prNetDevPrivate->prGlueInfo); + } + + rSuspendCmd.ucBssIndex = prNetDevPrivate->ucBssIdx; + rSuspendCmd.ucEnableSuspendMode = fgSuspend; + + if (prGlueInfo->prAdapter->rWifiVar.ucWow && + prGlueInfo->prAdapter->rWowCtrl.fgWowEnable) { + /* cfg enable + wow enable => Wow On mdtim*/ + rSuspendCmd.ucMdtim = + prGlueInfo->prAdapter->rWifiVar.ucWowOnMdtim; + DBGLOG(REQ, INFO, "mdtim [1]\n"); + } else if (prGlueInfo->prAdapter->rWifiVar.ucWow && + !prGlueInfo->prAdapter->rWowCtrl.fgWowEnable) { + if (prGlueInfo->prAdapter->rWifiVar.ucAdvPws) { + /* cfg enable + wow disable + adv pws enable => Wow Off + * mdtim */ + rSuspendCmd.ucMdtim = + prGlueInfo->prAdapter->rWifiVar.ucWowOffMdtim; + DBGLOG(REQ, INFO, "mdtim [2]\n"); + } + } else if (!prGlueInfo->prAdapter->rWifiVar.ucWow) { + if (prGlueInfo->prAdapter->rWifiVar.ucAdvPws) { + /* cfg disable + adv pws enable => MT6632 case => Wow + * Off mdtim */ + rSuspendCmd.ucMdtim = + prGlueInfo->prAdapter->rWifiVar.ucWowOffMdtim; + DBGLOG(REQ, INFO, "mdtim [3]\n"); + } + } + + /* When FW receive command, it check connection state to decide apply + * setting or not */ + + rStatus = kalIoctl(prGlueInfo, wlanoidNotifyFwSuspend, + (void *)&rSuspendCmd, sizeof(rSuspendCmd), false, + false, true, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, INFO, "wlanNotifyFwSuspend fail\n"); + } +} + +WLAN_STATUS +wlanGetStaIdxByWlanIdx(IN P_ADAPTER_T prAdapter, IN u8 ucIndex, + OUT u8 *pucStaIdx) +{ + P_WLAN_TABLE_T prWtbl; + + if (!prAdapter) { + ASSERT(false); + } + + prWtbl = prAdapter->rWifiVar.arWtbl; + + if (ucIndex < WTBL_SIZE) { + if (prWtbl[ucIndex].ucUsed && prWtbl[ucIndex].ucPairwise) { + *pucStaIdx = prWtbl[ucIndex].ucStaIndex; + return WLAN_STATUS_SUCCESS; + } + } + return WLAN_STATUS_FAILURE; +} + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query LTE safe channels. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_PENDING + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryLteSafeChannel(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; + CMD_GET_LTE_SAFE_CHN_T rQuery_LTE_SAFE_CHN; + + kalMemZero(&rQuery_LTE_SAFE_CHN, sizeof(CMD_GET_LTE_SAFE_CHN_T)); + + do { + /* Sanity test */ + if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) { + break; + } + if ((pvQueryBuffer == NULL) || (u4QueryBufferLen == 0)) { + break; + } + + /* Get LTE safe channel list */ + rResult = wlanSendSetQueryCmd( + prAdapter, CMD_ID_GET_LTE_CHN, false, true, true, + /* Query ID */ + nicCmdEventQueryLteSafeChn, + /* The handler to receive firmware notification */ + nicOidCmdTimeoutCommon, sizeof(CMD_GET_LTE_SAFE_CHN_T), + (u8 *)&rQuery_LTE_SAFE_CHN, pvQueryBuffer, + u4QueryBufferLen); + DBGLOG(P2P, INFO, "[ACS] Get safe LTE Channels\n"); + } while (false); + + return rResult; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Add dirtiness to neighbor channels of a BSS to estimate channel + * quality. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] prBssDesc Pointer to the BSS description. + * \param[in] u4Dirtiness Expected dirtiness value. + * \param[in] ucCentralChannel Central channel of the given BSS. + * \param[in] ucCoveredRange With ucCoveredRange and ucCentralChannel, + * all the affected channels can be enumerated. + */ +/*----------------------------------------------------------------------------*/ +static void wlanAddDirtinessToAffectedChannels(P_ADAPTER_T prAdapter, + P_BSS_DESC_T prBssDesc, + u32 u4Dirtiness, + u8 ucCentralChannel, + u8 ucCoveredRange) +{ + u8 ucIdx, ucStart, ucEnd; + u8 bIs5GChl = ucCentralChannel > 14; + u8 ucLeftNeighborChannel, ucRightNeighborChannel, + ucLeftNeighborChannel2 = 0, ucRightNeighborChannel2 = 0, + ucLeftestCoveredChannel, ucRightestCoveredChannel; + P_PARAM_GET_CHN_INFO prGetChnLoad = &(prAdapter->rWifiVar.rChnLoadInfo); + + ucLeftestCoveredChannel = ucCentralChannel > ucCoveredRange ? + ucCentralChannel - ucCoveredRange : + 1; + + ucLeftNeighborChannel = + ucLeftestCoveredChannel ? ucLeftestCoveredChannel - 1 : 0; + + /* align leftest covered ch and left neighbor ch to valid 5g ch */ + if (bIs5GChl) { + ucLeftestCoveredChannel += 2; + ucLeftNeighborChannel -= 1; + } else { + /* we select the nearest 2 ch to the leftest covered ch as left + * neighbor chs */ + ucLeftNeighborChannel2 = ucLeftNeighborChannel > 1 ? + ucLeftNeighborChannel - 1 : + 0; + } + + /* handle corner cases of 5g ch*/ + if (ucLeftestCoveredChannel > 14 && ucLeftestCoveredChannel <= 36) { + ucLeftestCoveredChannel = 36; + ucLeftNeighborChannel = 0; + } else if (ucLeftestCoveredChannel > 64 && + ucLeftestCoveredChannel <= 100) { + ucLeftestCoveredChannel = 100; + ucLeftNeighborChannel = 0; + } else if (ucLeftestCoveredChannel > 144 && + ucLeftestCoveredChannel <= 149) { + ucLeftestCoveredChannel = 149; + ucLeftNeighborChannel = 0; + } + + /* + * because ch 14 is 12MHz away to ch13, we must shift the leftest + * covered ch and left neighbor ch when central ch is ch 14 + */ + if (ucCentralChannel == 14) { + ucLeftestCoveredChannel = 13; + ucLeftNeighborChannel = 12; + ucLeftNeighborChannel2 = 11; + } + + ucRightestCoveredChannel = ucCentralChannel + ucCoveredRange; + ucRightNeighborChannel = ucRightestCoveredChannel + 1; + + /* align rightest covered ch and right neighbor ch to valid 5g ch */ + if (bIs5GChl) { + ucRightestCoveredChannel -= 2; + ucRightNeighborChannel += 1; + } else { + /* we select the nearest 2 ch to the rightest covered ch as + * right neighbor ch */ + ucRightNeighborChannel2 = ucRightNeighborChannel < 13 ? + ucRightNeighborChannel + 1 : + 0; + } + + /* handle corner cases */ + if (ucRightestCoveredChannel >= 14 && ucRightestCoveredChannel < 36) { + if (ucRightestCoveredChannel == 14) { + ucRightestCoveredChannel = 13; + ucRightNeighborChannel = 14; + } else { + ucRightestCoveredChannel = 14; + ucRightNeighborChannel = 0; + } + + ucRightNeighborChannel2 = 0; + } else if (ucRightestCoveredChannel >= 64 && + ucRightestCoveredChannel < 100) { + ucRightestCoveredChannel = 64; + ucRightNeighborChannel = 0; + } else if (ucRightestCoveredChannel >= 144 && + ucRightestCoveredChannel < 149) { + ucRightestCoveredChannel = 144; + ucRightNeighborChannel = 0; + } else if (ucRightestCoveredChannel >= 165) { + ucRightestCoveredChannel = 165; + ucRightNeighborChannel = 0; + } + + DBGLOG(SCN, TRACE, "central ch %d\n", ucCentralChannel); + + ucStart = wlanGetChannelIndex(ucLeftestCoveredChannel); + ucEnd = wlanGetChannelIndex(ucRightestCoveredChannel); + if (ucStart >= MAX_CHN_NUM || ucEnd >= MAX_CHN_NUM) { + DBGLOG(SCN, ERROR, "Invalid ch idx of start %u, or end %u\n", + ucStart, ucEnd); + return; + } + + for (ucIdx = ucStart; ucIdx <= ucEnd; ucIdx++) { + prGetChnLoad->rEachChnLoad[ucIdx].u4Dirtiness += u4Dirtiness; + DBGLOG(SCN, TRACE, "Add dirtiness %d, to covered ch %d\n", + u4Dirtiness, + prGetChnLoad->rEachChnLoad[ucIdx].ucChannel); + } + + if (ucLeftNeighborChannel != 0) { + ucIdx = wlanGetChannelIndex(ucLeftNeighborChannel); + if (ucIdx < MAX_CHN_NUM) { + prGetChnLoad->rEachChnLoad[ucIdx].u4Dirtiness += + (u4Dirtiness >> 1); + DBGLOG(SCN, TRACE, + "Add dirtiness %d, to neighbor ch %d\n", + u4Dirtiness >> 1, + prGetChnLoad->rEachChnLoad[ucIdx].ucChannel); + } + } + + if (ucRightNeighborChannel != 0) { + ucIdx = wlanGetChannelIndex(ucRightNeighborChannel); + if (ucIdx < MAX_CHN_NUM) { + prGetChnLoad->rEachChnLoad[ucIdx].u4Dirtiness += + (u4Dirtiness >> 1); + DBGLOG(SCN, TRACE, + "Add dirtiness %d, to neighbor ch %d\n", + u4Dirtiness >> 1, + prGetChnLoad->rEachChnLoad[ucIdx].ucChannel); + } + } + + if (bIs5GChl) { + return; + } + + /* Only necesaary for 2.5G */ + if (ucLeftNeighborChannel2 != 0) { + ucIdx = wlanGetChannelIndex(ucLeftNeighborChannel2); + if (ucIdx < MAX_CHN_NUM) { + prGetChnLoad->rEachChnLoad[ucIdx].u4Dirtiness += + (u4Dirtiness >> 1); + DBGLOG(SCN, TRACE, + "Add dirtiness %d, to neighbor ch %d\n", + u4Dirtiness >> 1, + prGetChnLoad->rEachChnLoad[ucIdx].ucChannel); + } + } + + if (ucRightNeighborChannel2 != 0) { + ucIdx = wlanGetChannelIndex(ucRightNeighborChannel2); + if (ucIdx < MAX_CHN_NUM) { + prGetChnLoad->rEachChnLoad[ucIdx].u4Dirtiness += + (u4Dirtiness >> 1); + DBGLOG(SCN, TRACE, + "Add dirtiness %d, to neighbor ch %d\n", + u4Dirtiness >> 1, + prGetChnLoad->rEachChnLoad[ucIdx].ucChannel); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief For a scanned BSS, add dirtiness to the channels 1)around its primary + * channels and 2) in its working BW to represent the quality degrade. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] prBssDesc Pointer to the BSS description. + * \param[in] u4Dirtiness Expected dirtiness value. + * \param[in] bIsIndexOne True means index 1, False means index 2. + */ +/*----------------------------------------------------------------------------*/ +static void wlanCalculateChannelDirtiness(IN P_ADAPTER_T prAdapter, + P_BSS_DESC_T prBssDesc, + u32 u4Dirtiness, u8 bIsIndexOne) +{ + u8 ucCoveredRange = 0, ucCentralChannel = 0, ucCentralChannel2 = 0; + + if (bIsIndexOne) { + DBGLOG(SCN, TRACE, "Process dirtiness index 1\n"); + ucCentralChannel = prBssDesc->ucChannelNum; + ucCoveredRange = 2; + } else { + DBGLOG(SCN, TRACE, "Process dirtiness index 2, "); + switch (prBssDesc->eChannelWidth) { + case CW_20_40MHZ: + if (prBssDesc->eSco == CHNL_EXT_SCA) { + DBGLOG(SCN, TRACE, "BW40\n"); + ucCentralChannel = prBssDesc->ucChannelNum + 2; + ucCoveredRange = 4; + } else if (prBssDesc->eSco == CHNL_EXT_SCB) { + DBGLOG(SCN, TRACE, "BW40\n"); + ucCentralChannel = prBssDesc->ucChannelNum - 2; + ucCoveredRange = 4; + } else { + DBGLOG(SCN, TRACE, "BW20\n"); + ucCentralChannel = prBssDesc->ucChannelNum; + ucCoveredRange = 2; + } + break; + + case CW_80MHZ: + DBGLOG(SCN, TRACE, "BW80\n"); + ucCentralChannel = prBssDesc->ucCenterFreqS1; + ucCoveredRange = 8; + break; + + case CW_160MHZ: + DBGLOG(SCN, TRACE, "BW160\n"); + ucCentralChannel = prBssDesc->ucCenterFreqS1; + ucCoveredRange = 16; + break; + + case CW_80P80MHZ: + DBGLOG(SCN, TRACE, "BW8080\n"); + ucCentralChannel = prBssDesc->ucCenterFreqS1; + ucCentralChannel2 = prBssDesc->ucCenterFreqS2; + ucCoveredRange = 8; + break; + + default: + ucCentralChannel = prBssDesc->ucChannelNum; + ucCoveredRange = 2; + break; + } + ; + } + + wlanAddDirtinessToAffectedChannels(prAdapter, prBssDesc, u4Dirtiness, + ucCentralChannel, ucCoveredRange); + + /* 80 + 80 secondary 80 case */ + if (bIsIndexOne || ucCentralChannel2 == 0) { + return; + } + + wlanAddDirtinessToAffectedChannels(prAdapter, prBssDesc, u4Dirtiness, + ucCentralChannel2, ucCoveredRange); +} + +void wlanInitChnLoadInfoChannelList(IN P_ADAPTER_T prAdapter) +{ + u8 ucIdx = 0; + P_PARAM_GET_CHN_INFO prGetChnLoad = &(prAdapter->rWifiVar.rChnLoadInfo); + + for (ucIdx = 0; ucIdx < MAX_CHN_NUM; ucIdx++) + prGetChnLoad->rEachChnLoad[ucIdx].ucChannel = + wlanGetChannelNumFromIndex(ucIdx); +} + +WLAN_STATUS +wlanCalculateAllChannelDirtiness(IN P_ADAPTER_T prAdapter) +{ + WLAN_STATUS rResult = WLAN_STATUS_SUCCESS; + PARAM_RSSI i4Rssi = 0; + P_BSS_DESC_T prBssDesc = NULL; + u32 u4Dirtiness = 0; + P_LINK_T prBSSDescList = &(prAdapter->rWifiVar.rScanInfo.rBSSDescList); + + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T) { + i4Rssi = RCPI_TO_dBm(prBssDesc->ucRCPI); + + if (i4Rssi >= ACS_AP_RSSI_LEVEL_HIGH) { + u4Dirtiness = ACS_DIRTINESS_LEVEL_HIGH; + }else if (i4Rssi >= ACS_AP_RSSI_LEVEL_LOW) { + u4Dirtiness = ACS_DIRTINESS_LEVEL_MID; + }else{ + u4Dirtiness = ACS_DIRTINESS_LEVEL_LOW; + } + + DBGLOG(SCN, TRACE, "Found an AP(%s), primary ch %d\n", + prBssDesc->aucSSID, prBssDesc->ucChannelNum); + + /* dirtiness index1 */ + wlanCalculateChannelDirtiness(prAdapter, prBssDesc, u4Dirtiness, + true); + + /* dirtiness index2 */ + wlanCalculateChannelDirtiness(prAdapter, prBssDesc, + u4Dirtiness >> 1, false); + } + + return rResult; +} + +u8 wlanGetChannelIndex(IN u8 channel) +{ + u8 ucIdx = MAX_CHN_NUM - 1; + + if (channel <= 14) { + ucIdx = channel - 1; + }else if (channel >= 36 && channel <= 64) { + ucIdx = 14 + (channel - 36) / 4; + }else if (channel >= 100 && channel <= 144) { + ucIdx = 14 + 8 + (channel - 100) / 4; + }else if (channel >= 149 && channel <= 165) { + ucIdx = 14 + 8 + 12 + (channel - 149) / 4; + } + + return ucIdx; +} + +/*---------------------------------------------------------------------*/ +/*! + * \brief Get ch index by the given ch num; the reverse function of + * wlanGetChannelIndex + * + * \param[in] ucIdx Channel index + * \param[out] ucChannel Channel number + */ +/*---------------------------------------------------------------------*/ + +u8 wlanGetChannelNumFromIndex(IN u8 ucIdx) +{ + u8 ucChannel = 0; + + if (ucIdx >= 34) { + ucChannel = ((ucIdx - 34) << 2) + 149; + }else if (ucIdx >= 22) { + ucChannel = ((ucIdx - 22) << 2) + 100; + }else if (ucIdx >= 14) { + ucChannel = ((ucIdx - 14) << 2) + 36; + }else{ + ucChannel = ucIdx + 1; + } + + return ucChannel; +} + +void wlanSortChannel(IN P_ADAPTER_T prAdapter) +{ + P_PARAM_GET_CHN_INFO prChnLoadInfo = + &(prAdapter->rWifiVar.rChnLoadInfo); + s8 ucIdx = 0, ucRoot = 0, ucChild = 0; + PARAM_CHN_RANK_INFO rChnRankInfo; + + /* prepare unsorted ch rank list */ + for (ucIdx = 0; ucIdx < MAX_CHN_NUM; ++ucIdx) { + prChnLoadInfo->rChnRankList[ucIdx].ucChannel = + prChnLoadInfo->rEachChnLoad[ucIdx].ucChannel; + prChnLoadInfo->rChnRankList[ucIdx].u4Dirtiness = + prChnLoadInfo->rEachChnLoad[ucIdx].u4Dirtiness; + } + + /* heapify ch rank list */ + for (ucIdx = MAX_CHN_NUM / 2 - 1; ucIdx >= 0; --ucIdx) { + for (ucRoot = ucIdx; ucRoot * 2 + 1 < MAX_CHN_NUM; + ucRoot = ucChild) { + ucChild = ucRoot * 2 + 1; + if (ucChild < MAX_CHN_NUM - 1 && + prChnLoadInfo->rChnRankList[ucChild + + 1].u4Dirtiness > + prChnLoadInfo->rChnRankList[ucChild] + .u4Dirtiness) { + ucChild += 1; + } + + if (prChnLoadInfo->rChnRankList[ucChild].u4Dirtiness <= + prChnLoadInfo->rChnRankList[ucRoot].u4Dirtiness) { + break; + } + + rChnRankInfo = prChnLoadInfo->rChnRankList[ucChild]; + prChnLoadInfo->rChnRankList[ucChild] = + prChnLoadInfo->rChnRankList[ucRoot]; + prChnLoadInfo->rChnRankList[ucRoot] = rChnRankInfo; + } + } + + /* sort ch rank list */ + for (ucIdx = MAX_CHN_NUM - 1; ucIdx > 0; ucIdx--) { + rChnRankInfo = prChnLoadInfo->rChnRankList[0]; + prChnLoadInfo->rChnRankList[0] = + prChnLoadInfo->rChnRankList[ucIdx]; + prChnLoadInfo->rChnRankList[ucIdx] = rChnRankInfo; + + for (ucRoot = 0; ucRoot * 2 + 1 < ucIdx; ucRoot = ucChild) { + ucChild = ucRoot * 2 + 1; + if (ucChild < ucIdx - 1 && + prChnLoadInfo->rChnRankList[ucChild + + 1].u4Dirtiness > + prChnLoadInfo->rChnRankList[ucChild] + .u4Dirtiness) { + ucChild += 1; + } + + if (prChnLoadInfo->rChnRankList[ucChild].u4Dirtiness <= + prChnLoadInfo->rChnRankList[ucRoot].u4Dirtiness) { + break; + } + + rChnRankInfo = prChnLoadInfo->rChnRankList[ucChild]; + prChnLoadInfo->rChnRankList[ucChild] = + prChnLoadInfo->rChnRankList[ucRoot]; + prChnLoadInfo->rChnRankList[ucRoot] = rChnRankInfo; + } + } + + for (ucIdx = 0; ucIdx < MAX_CHN_NUM; ++ucIdx) + DBGLOG(SCN, INFO, "[ACS]channel=%d, dirtiness=%d\n", + prChnLoadInfo->rChnRankList[ucIdx].ucChannel, + prChnLoadInfo->rChnRankList[ucIdx].u4Dirtiness); +} +#endif + +u8 wlanGetAntPathType(IN P_ADAPTER_T prAdapter, + IN enum ENUM_WF_PATH_FAVOR_T eWfPathFavor, + IN u8 ucBssIndex) +{ + u8 ucFianlWfPathType = eWfPathFavor; +#if CFG_SUPPORT_ANT_SELECT + u8 ucNss = prAdapter->rWifiVar.ucNSS; + u8 ucSpeIdxCtrl = prAdapter->rWifiVar.ucSpeIdxCtrl; + + P_BSS_INFO_T prBssInfo; + ENUM_BAND_T eBand = BAND_NULL; + + if (ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, "invalid bssinfo index[%u], skip dump!\n", + ucBssIndex); + ASSERT(0); // for userdebug case + return ucFianlWfPathType; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if (prBssInfo->fgIsGranted) { + eBand = prBssInfo->eBandGranted; + }else{ + eBand = prBssInfo->eBand; + } + + if (eBand == BAND_2G4 && !prAdapter->rWifiVar.ucSpeIdxCtrl2G) { + ucSpeIdxCtrl = prAdapter->rWifiVar.ucSpeIdxCtrl2G; + } + + if (ucSpeIdxCtrl == 0) { + ucFianlWfPathType = ENUM_WF_0_ONE_STREAM_PATH_FAVOR; + } else if (ucSpeIdxCtrl == 1) { + ucFianlWfPathType = ENUM_WF_1_ONE_STREAM_PATH_FAVOR; + } else if (ucSpeIdxCtrl == 2) { + if (ucNss > 1) { + ucFianlWfPathType = ENUM_WF_0_1_DUP_STREAM_PATH_FAVOR; + }else{ + ucFianlWfPathType = ENUM_WF_NON_FAVOR; + } + } else { + ucFianlWfPathType = ENUM_WF_NON_FAVOR; + } +#endif + return ucFianlWfPathType; +} + +#if ((CFG_SISO_SW_DEVELOP == 1) || (CFG_SUPPORT_ANT_SELECT == 1)) +u8 wlanAntPathFavorSelect(enum ENUM_WF_PATH_FAVOR_T eWfPathFavor) +{ + u8 ucRetValSpeIdx = 0; + + if ((eWfPathFavor == ENUM_WF_NON_FAVOR) || + (eWfPathFavor == ENUM_WF_0_ONE_STREAM_PATH_FAVOR) || + (eWfPathFavor == ENUM_WF_0_1_TWO_STREAM_PATH_FAVOR)) { + ucRetValSpeIdx = ANTENNA_WF0; + }else if (eWfPathFavor == ENUM_WF_0_1_DUP_STREAM_PATH_FAVOR) { + ucRetValSpeIdx = 0x18; + }else if (eWfPathFavor == ENUM_WF_1_ONE_STREAM_PATH_FAVOR) { + ucRetValSpeIdx = ANTENNA_WF1; + }else{ + ucRetValSpeIdx = ANTENNA_WF0; + } + + return ucRetValSpeIdx; +} +#endif + +u8 wlanGetSpeIdx(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN enum ENUM_WF_PATH_FAVOR_T eWfPathFavor) +{ + u8 ucRetValSpeIdx = 0; +#if ((CFG_SISO_SW_DEVELOP == 1) || (CFG_SUPPORT_ANT_SELECT == 1)) + P_BSS_INFO_T prBssInfo; + ENUM_BAND_T eBand = BAND_NULL; + + if (ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, "Invalid BssInfo index[%u], skip dump!\n", + ucBssIndex); + ucRetValSpeIdx = wlanAntPathFavorSelect(eWfPathFavor); + ASSERT(0); // for userdebug case + return ucRetValSpeIdx; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + /* + * if DBDC enable return 0, else depend 2.4G/5G & support WF path + * retrun accurate value + */ + #if CFG_SUPPORT_DBDC + if (!prAdapter->rWifiVar.fgDbDcModeEn) { + if (prBssInfo->fgIsGranted) { + eBand = prBssInfo->eBandGranted; + }else{ + eBand = prBssInfo->eBand; + } + + if (eBand == BAND_2G4) { + if (IS_WIFI_2G4_SISO(prAdapter)) { + if (IS_WIFI_2G4_WF0_SUPPORT(prAdapter)) { + ucRetValSpeIdx = ANTENNA_WF0; + }else{ + ucRetValSpeIdx = ANTENNA_WF1; + } + } else { + ucRetValSpeIdx = + wlanAntPathFavorSelect(eWfPathFavor); + } + } else if (eBand == BAND_5G) { + if (IS_WIFI_5G_SISO(prAdapter)) { + if (IS_WIFI_5G_WF0_SUPPORT(prAdapter)) { + ucRetValSpeIdx = ANTENNA_WF0; + }else{ + ucRetValSpeIdx = ANTENNA_WF1; + } + } else { + ucRetValSpeIdx = + wlanAntPathFavorSelect(eWfPathFavor); + } + } else { + ucRetValSpeIdx = wlanAntPathFavorSelect(eWfPathFavor); + } + } + DBGLOG(INIT, INFO, "SpeIdx:%d,D:%d,G=%d,B=%d,Bss=%d\n", ucRetValSpeIdx, + prAdapter->rWifiVar.fgDbDcModeEn, prBssInfo->fgIsGranted, eBand, + ucBssIndex); +#endif +#endif + return ucRetValSpeIdx; +} + +u8 wlanGetSupportNss(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex) +{ + P_BSS_INFO_T prBssInfo; + u8 ucRetValNss = prAdapter->rWifiVar.ucNSS; + + if (ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, "Invalid BssInfo index[%u], skip dump!\n", + ucBssIndex); + ASSERT(0); // for userdebug case + return ucRetValNss; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + if (IS_BSS_APGO(prBssInfo)) { + if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2PConnSettings + [prBssInfo->u4PrivateData])) { + if (prBssInfo->eBand == BAND_2G4) { + ucRetValNss = prAdapter->rWifiVar.ucAp2gNSS; + }else if (prBssInfo->eBand == BAND_5G) { + ucRetValNss = prAdapter->rWifiVar.ucAp5gNSS; + } + } else { + if (prBssInfo->eBand == BAND_2G4) { + ucRetValNss = prAdapter->rWifiVar.ucGo2gNSS; + }else if (prBssInfo->eBand == BAND_5G) { + ucRetValNss = prAdapter->rWifiVar.ucGo5gNSS; + } + } + } + + if (ucRetValNss > prAdapter->rWifiVar.ucNSS) { + ucRetValNss = prAdapter->rWifiVar.ucNSS; + } + +#if CFG_SUPPORT_DBDC_TC6 + if ((ucRetValNss > prBssInfo->ucNss) && (prBssInfo->ucNss != 0)) { + ucRetValNss = prBssInfo->ucNss; + } +#endif + return ucRetValNss; +} + +s32 wlanGetFileContent(P_ADAPTER_T prAdapter, const u8 *pcFileName, u8 *pucBuf, + u32 u4MaxFileLen, u32 *pu4ReadFileLen, u8 bReqFw) +{ + if (bReqFw) { + return kalRequestFirmware(pcFileName, pucBuf, u4MaxFileLen, + pu4ReadFileLen, + prAdapter->prGlueInfo->prDev); + } + + return kalReadToFile(pcFileName, pucBuf, u4MaxFileLen, pu4ReadFileLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to update some info before connected, + * some decision need some info before bss info update + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +#if CFG_SUPPORT_ANT_SELECT +WLAN_STATUS wlanUpdateExtInfo(IN P_ADAPTER_T prAdapter) +{ + u32 u4BufLen = 0; + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + rSwCtrlInfo.u4Id = 0xa0640001; + rSwCtrlInfo.u4Data = prAdapter->rWifiVar.ucNSS; + + return kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); +} +#endif + +WLAN_STATUS wlanSetEd(IN P_ADAPTER_T prAdapter, s32 u4EdVal2G, s32 u4EdVal5G, + u32 u4Sel) +{ + u32 u4BufLen = 0; + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + rSwCtrlInfo.u4Id = CMD_SW_DBGCTL_ADVCTL_SET_ID + CMD_ADVCTL_ED_ID; + rSwCtrlInfo.u4Data = ((u4EdVal2G & 0xFF) | ((u4EdVal5G & 0xFF) << 16) | + (u4Sel << 31)); + DBGLOG(REQ, INFO, "rSwCtrlInfo.u4Data=0x%x,\n", rSwCtrlInfo.u4Data); + + return kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to update 2G & 5G RSSI path compensation + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +#if CFG_SUPPORT_RSSI_COMP +WLAN_STATUS wlanUpdateRssiComp(IN P_ADAPTER_T prAdapter) +{ + CMD_RSSI_PATH_COMPASATION_T rCmdRssiPathCompasation; + + rCmdRssiPathCompasation.c2GRssiCompensation = + prAdapter->rWifiVar.rRssiPathCompasation.c2GRssiCompensation; + rCmdRssiPathCompasation.c5GRssiCompensation = + prAdapter->rWifiVar.rRssiPathCompasation.c5GRssiCompensation; + DBGLOG(INIT, ERROR, "c2GRssiCompensation=%d,c5GRssiCompensation=%d\n", + rCmdRssiPathCompasation.c2GRssiCompensation, + rCmdRssiPathCompasation.c5GRssiCompensation); + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_PATH_COMPASATION, true, + false, false, NULL, NULL, + sizeof(rCmdRssiPathCompasation), + (u8 *)&rCmdRssiPathCompasation, NULL, 0); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is a wrapper to send eapol offload (rekey) command + * + * @param prGlueInfo Pointer of prGlueInfo Data Structure + * + * @return void + */ +/*----------------------------------------------------------------------------*/ +int wlanSuspendRekeyOffload(P_GLUE_INFO_T prGlueInfo, IN u8 ucRekeyMode) +{ + u32 u4BufLen; + P_PARAM_GTK_REKEY_DATA prGtkData; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + s32 i4Rslt = -EINVAL; +#if CFG_SUPPORT_REPLAY_DETECTION + P_BSS_INFO_T prBssInfo = NULL; + struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL; + u8 ucCurKeyId; + u8 ucRpyOffload; +#endif + + ASSERT(prGlueInfo); + +#if CFG_SUPPORT_REPLAY_DETECTION + ucRpyOffload = prGlueInfo->prAdapter->rWifiVar.ucRpyDetectOffload; + + if ((ucRekeyMode == GTK_REKEY_CMD_MODE_SET_BCMC_PN) && + (ucRpyOffload == false)) { + DBGLOG(RSN, INFO, "Set PN to fw, but feature off. no action\n"); + return WLAN_STATUS_SUCCESS; + } + + if ((ucRekeyMode == GTK_REKEY_CMD_MODE_GET_BCMC_PN) && + (ucRpyOffload == false)) { + DBGLOG(RSN, INFO, + "Get PN from fw, but feature off. no action\n"); + return WLAN_STATUS_SUCCESS; + } +#endif + + prGtkData = (P_PARAM_GTK_REKEY_DATA)kalMemAlloc( + sizeof(PARAM_GTK_REKEY_DATA), VIR_MEM_TYPE); + + if (!prGtkData) { + return WLAN_STATUS_SUCCESS; + } + + kalMemZero(prGtkData, sizeof(PARAM_GTK_REKEY_DATA)); + + /* if enable => enable FW rekey offload. if disable, let rekey back to + * supplicant */ + prGtkData->ucRekeyMode = ucRekeyMode; + DBGLOG(RSN, INFO, "GTK Rekey ucRekeyMode = %d\n", ucRekeyMode); + + if (ucRekeyMode == GTK_REKEY_CMD_MODE_OFFLOAD_ON) { + DBGLOG(RSN, INFO, "kek\n"); + DBGLOG_MEM8(RSN, ERROR, (u8 *)prGlueInfo->rWpaInfo.aucKek, + NL80211_KEK_LEN); + DBGLOG(RSN, INFO, "kck\n"); + DBGLOG_MEM8(RSN, ERROR, (u8 *)prGlueInfo->rWpaInfo.aucKck, + NL80211_KCK_LEN); + DBGLOG(RSN, INFO, "replay count\n"); + DBGLOG_MEM8(RSN, ERROR, (u8 *)prGlueInfo->rWpaInfo.aucReplayCtr, + NL80211_REPLAY_CTR_LEN); + + kalMemCopy(prGtkData->aucKek, prGlueInfo->rWpaInfo.aucKek, + NL80211_KEK_LEN); + kalMemCopy(prGtkData->aucKck, prGlueInfo->rWpaInfo.aucKck, + NL80211_KCK_LEN); + kalMemCopy(prGtkData->aucReplayCtr, + prGlueInfo->rWpaInfo.aucReplayCtr, + NL80211_REPLAY_CTR_LEN); + + prGtkData->ucBssIndex = + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + + prGtkData->u4Proto = NL80211_WPA_VERSION_2; + if (prGlueInfo->rWpaInfo.u4WpaVersion == + IW_AUTH_WPA_VERSION_WPA) { + prGtkData->u4Proto = NL80211_WPA_VERSION_1; + } + + if (prGlueInfo->rWpaInfo.u4CipherPairwise == + IW_AUTH_CIPHER_TKIP) { + prGtkData->u4PairwiseCipher = BIT(3); + } else if (prGlueInfo->rWpaInfo.u4CipherPairwise == + IW_AUTH_CIPHER_CCMP) { + prGtkData->u4PairwiseCipher = BIT(4); + } else { + kalMemFree(prGtkData, VIR_MEM_TYPE, + sizeof(PARAM_GTK_REKEY_DATA)); + return WLAN_STATUS_SUCCESS; + } + + if (prGlueInfo->rWpaInfo.u4CipherGroup == IW_AUTH_CIPHER_TKIP) { + prGtkData->u4GroupCipher = BIT(3); + } else if (prGlueInfo->rWpaInfo.u4CipherGroup == + IW_AUTH_CIPHER_CCMP) { + prGtkData->u4GroupCipher = BIT(4); + } else { + kalMemFree(prGtkData, VIR_MEM_TYPE, + sizeof(PARAM_GTK_REKEY_DATA)); + return WLAN_STATUS_SUCCESS; + } + + prGtkData->u4KeyMgmt = prGlueInfo->rWpaInfo.u4KeyMgmt; + prGtkData->u4MgmtGroupCipher = 0; + } + + if (ucRekeyMode == GTK_REKEY_CMD_MODE_OFLOAD_OFF) { + /* inform FW disable EAPOL offload */ + DBGLOG(RSN, INFO, "Disable EAPOL offload\n"); + } + +#if CFG_SUPPORT_REPLAY_DETECTION + if (ucRekeyMode == GTK_REKEY_CMD_MODE_RPY_OFFLOAD_ON) { + DBGLOG(RSN, INFO, "ucRekeyMode(rpy rekey offload on): %d\n", + ucRekeyMode); + } + + if (ucRekeyMode == GTK_REKEY_CMD_MODE_RPY_OFFLOAD_OFF) { + DBGLOG(RSN, INFO, "ucRekeyMode(rpy rekey offload off): %d\n", + ucRekeyMode); + } + + if ((ucRekeyMode == GTK_REKEY_CMD_MODE_SET_BCMC_PN) && + (ucRpyOffload == true)) { + prGtkData->ucBssIndex = + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + + if (prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex > + MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, + "Invalid BssInfo index[%u], skip dump!\n", + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + return -1; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX( + prGlueInfo->prAdapter, + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + prDetRplyInfo = &prBssInfo->rDetRplyInfo; + ucCurKeyId = prDetRplyInfo->ucCurKeyId; + prGtkData->ucCurKeyId = ucCurKeyId; + DBGLOG_MEM8(RSN, INFO, (u8 *)prGtkData->aucReplayCtr, + NL80211_REPLAY_CTR_LEN); + kalMemCopy(prGtkData->aucReplayCtr, + prDetRplyInfo->arReplayPNInfo[ucCurKeyId].auPN, + NL80211_REPLAY_CTR_LEN); + + /* set bc/mc PN zero before suspend */ + kalMemZero(prDetRplyInfo->arReplayPNInfo[ucCurKeyId].auPN, + NL80211_REPLAY_CTR_LEN); + } + + if ((ucRekeyMode == GTK_REKEY_CMD_MODE_GET_BCMC_PN) && + (ucRpyOffload == true)) { + prGtkData->ucBssIndex = + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + } +#endif + + rStatus = kalIoctl(prGlueInfo, wlanoidSetGtkRekeyData, prGtkData, + sizeof(PARAM_GTK_REKEY_DATA), false, false, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "Suspend GTK rekey data error:%lx\n", + rStatus); + } else { + i4Rslt = 0; + } + + kalMemFree(prGtkData, VIR_MEM_TYPE, sizeof(PARAM_GTK_REKEY_DATA)); + + return i4Rslt; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is a wrapper to disable traffic report command + * + * @param prGlueInfo Pointer of prGlueInfo Data Structure + * + * @return void + */ +/*----------------------------------------------------------------------------*/ +void wlanDisTrafficReport(P_GLUE_INFO_T prGlueInfo) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + u8 ucBand = ENUM_BAND_0; + struct CMD_GET_TRAFFIC_REPORT *cmd = NULL; + + if (!prGlueInfo) { + return; + } + + cmd = (struct CMD_GET_TRAFFIC_REPORT *)kalMemAlloc(sizeof(*cmd), + VIR_MEM_TYPE); + if (!cmd) { + return; + } + + memset(cmd, 0, sizeof(*cmd)); + + cmd->u2Type = CMD_GET_REPORT_TYPE; + cmd->u2Len = sizeof(*cmd); + cmd->ucBand = ucBand; + cmd->ucAction = CMD_GET_REPORT_DISABLE; + cmd->u2Type |= CMD_ADV_CONTROL_SET; + rStatus = kalIoctl(prGlueInfo, wlanoidAdvCtrl, cmd, sizeof(*cmd), true, + true, true, &u4BufLen); + + if ((rStatus != WLAN_STATUS_SUCCESS) && + (rStatus != WLAN_STATUS_PENDING)) { + DBGLOG(REQ, ERROR, "Disable traffic report error:%lx\n", + rStatus); + } + + kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd)); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is a wrapper to send power-saving mode command + * when AIS enter wow, and send WOW command + * Also let GC/GO/AP enter deactivate state to enter TOP sleep + * + * @param prGlueInfo Pointer of prGlueInfo Data Structure + * + * @return void + */ +/*----------------------------------------------------------------------------*/ +void wlanSuspendPmHandle(P_GLUE_INFO_T prGlueInfo) +{ + u8 idx; + PARAM_POWER_MODE ePwrMode; + P_BSS_INFO_T prBssInfo; + u8 ucKekZeroCnt = 0; + u8 ucKckZeroCnt = 0; + u8 ucGtkOffload = true; + u8 i = 0; +#if CFG_SUPPORT_REPLAY_DETECTION + struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL; + u8 ucIdx = 0; + u8 ucKeyIdx = 0; + u8 ucRpyOffload = 0; +#endif + P_STA_RECORD_T prStaRec; + P_RX_BA_ENTRY_T prRxBaEntry; + + if (prGlueInfo->prAdapter->u4IsKeepFullPwrBitmap) { + prGlueInfo->prAdapter->u4IsKeepFullPwrBitmap |= + BLOCK_KEEP_FULL_PWR; + wlanKeepFullPwr(prGlueInfo->prAdapter, false); + } + + /* if wifi.cfg EAPOL offload is 0, we set rekey offload when enter wow + */ + if (!prGlueInfo->prAdapter->rWifiVar.ucEapolOffload) { + /* + * check if KCK, KEK not sync from supplicant. + * if no these info updated from supplicant, + * disable GTK offload feature. + */ + for (i = 0; i < NL80211_KEK_LEN; i++) + if (prGlueInfo->rWpaInfo.aucKek[i] == 0x00) { + ucKekZeroCnt++; + } + + for (i = 0; i < NL80211_KCK_LEN; i++) + if (prGlueInfo->rWpaInfo.aucKck[i] == 0x00) { + ucKckZeroCnt++; + } + + if ((ucKekZeroCnt == NL80211_KCK_LEN) || + (ucKckZeroCnt == NL80211_KCK_LEN)) { + DBGLOG(RSN, + INFO, + "no rekey offload, due to no KCK/KEK from cfg80211\n"); + + prGlueInfo->prAdapter->rWifiVar.ucRpyDetectOffload = + FEATURE_DISABLED; + + ucGtkOffload = false; + /* set bc/mc replay detection off to fw */ + wlanSuspendRekeyOffload( + prGlueInfo, GTK_REKEY_CMD_MODE_RPY_OFFLOAD_OFF); + } + +#if CFG_SUPPORT_REPLAY_DETECTION + ucRpyOffload = + prGlueInfo->prAdapter->rWifiVar.ucRpyDetectOffload; + + if (ucRpyOffload && ucGtkOffload) { + wlanSuspendRekeyOffload(prGlueInfo, + GTK_REKEY_CMD_MODE_SET_BCMC_PN); + } +#endif + if (ucGtkOffload) { + wlanSuspendRekeyOffload(prGlueInfo, + GTK_REKEY_CMD_MODE_OFFLOAD_ON); + } + +#if CFG_SUPPORT_REPLAY_DETECTION + if (prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex > + MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, + "Invalid BssInfo index[%u], skip dump!\n", + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX( + prGlueInfo->prAdapter, + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + prDetRplyInfo = &prBssInfo->rDetRplyInfo; + + for (ucKeyIdx = 0; ucKeyIdx < 4; ucKeyIdx++) { + for (ucIdx = 0; ucIdx < 6; ucIdx++) + prDetRplyInfo->arReplayPNInfo[ucKeyIdx] + .auPN[ucIdx] = 0x0; + } +#endif + DBGLOG(HAL, STATE, "Suspend rekey offload\n"); + } + + /* 1) wifi cfg "Wow" is true, 2) wow is enable 3) WIfI connected => + * execute WOW flow */ + /* Send power-saving cmd when enter wow state, even w/o cfg80211 support + */ + if (prGlueInfo->prAdapter->rWifiVar.ucWow && + prGlueInfo->prAdapter->rWowCtrl.fgWowEnable) { + if (kalGetMediaStateIndicated(prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED) { + /* AIS bss enter wow power mode, default fast + * power-saving */ + ePwrMode = prGlueInfo->prAdapter->rWifiVar.ucWowPwsMode; + idx = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + nicConfigPowerSaveWowProfile(prGlueInfo->prAdapter, idx, + ePwrMode, false, true); + DBGLOG(HAL, STATE, + "Suspend wow power save idx:%d, mode:%d\n", idx, + ePwrMode); + + DBGLOG(HAL, STATE, "enter WOW flow\n"); + kalWowProcess(prGlueInfo, true); + } + } else if (prGlueInfo->prAdapter->rWifiVar.ucWlanSetCamDuringAct) { + ucIdx = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + + prBssInfo = prGlueInfo->prAdapter->aprBssInfo[ucIdx]; + ePwrMode = prBssInfo->ePowerModeFromUser; + + DBGLOG(HAL, STATE, "Set user's PS mode idx:%d, mode:%d\n", + ucIdx, ePwrMode); + nicConfigPowerSaveProfile(prGlueInfo->prAdapter, ucIdx, + ePwrMode, false); + } + + for (idx = 0; idx < MAX_BSS_INDEX; idx++) { + prBssInfo = prGlueInfo->prAdapter->aprBssInfo[idx]; + if (!prBssInfo) { + continue; + } + + /* Stop GO/GC/AP bss to let TOP sleep */ + if ((idx != prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex) && + IS_BSS_ACTIVE(prBssInfo)) { + nicPmIndicateBssAbort(prGlueInfo->prAdapter, idx); + nicDeactivateNetwork(prGlueInfo->prAdapter, idx); + nicUpdateBss(prGlueInfo->prAdapter, idx); + } + } + + /* After resuming, WinStart will unsync with AP's SN. + * Set fgFirstSnToWinStart for all valid BA entry before suspend. + */ + for (idx = 0; idx < CFG_STA_REC_NUM; idx++) { + prStaRec = cnmGetStaRecByIndex(prGlueInfo->prAdapter, idx); + if (!prStaRec) { + continue; + } + + for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) { + prRxBaEntry = prStaRec->aprRxReorderParamRefTbl[i]; + if (!prRxBaEntry || !(prRxBaEntry->fgIsValid)) { + continue; + } + + prRxBaEntry->fgFirstSnToWinStart = true; + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to restore power-saving mode command when AIS leave + * wow But ignore GC/GO/AP role + * + * @param prGlueInfo Pointer of prGlueInfo Data Structure + * + * @return void + */ +/*----------------------------------------------------------------------------*/ +void wlanResumePmHandle(P_GLUE_INFO_T prGlueInfo) +{ + PARAM_POWER_MODE ePwrMode = Param_PowerModeCAM; + u8 ucKekZeroCnt = 0; + u8 ucKckZeroCnt = 0; + u8 ucGtkOffload = true; + u8 i = 0; +#if CFG_SUPPORT_REPLAY_DETECTION + struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL; + P_BSS_INFO_T prBssInfo = NULL; + u8 ucIdx = 0; + u8 ucKeyIdx = 0; + u8 ucRpyOffload = 0; +#endif + + /* if wifi.cfg EAPOL offload is disble, we disable FW offload when leave + * wow */ + if (!prGlueInfo->prAdapter->rWifiVar.ucEapolOffload) { + /* + * check if KCK, KEK not sync from supplicant. + * if no these info updated from supplicant, + * disable GTK offload feature. + */ + for (i = 0; i < NL80211_KEK_LEN; i++) + if (prGlueInfo->rWpaInfo.aucKek[i] == 0x00) { + ucKekZeroCnt++; + } + + for (i = 0; i < NL80211_KCK_LEN; i++) + if (prGlueInfo->rWpaInfo.aucKck[i] == 0x00) { + ucKckZeroCnt++; + } + + if ((ucKekZeroCnt == NL80211_KCK_LEN) || + (ucKckZeroCnt == NL80211_KCK_LEN)) { + DBGLOG(RSN, + INFO, + "no rekey offload, due to no KCK/KEK from cfg80211\n"); + + prGlueInfo->prAdapter->rWifiVar.ucRpyDetectOffload = + FEATURE_DISABLED; + + ucGtkOffload = false; + /* set bc/mc replay detection off to fw */ + wlanSuspendRekeyOffload( + prGlueInfo, GTK_REKEY_CMD_MODE_RPY_OFFLOAD_OFF); + } + +#if CFG_SUPPORT_REPLAY_DETECTION + if (prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex > + MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, + "Invalid BssInfo index[%u], skip dump!\n", + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX( + prGlueInfo->prAdapter, + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + prDetRplyInfo = &prBssInfo->rDetRplyInfo; + + /* as resume performed, reset BC/MC KeyRSC, to prevent incorrect + * replay detection. */ + for (ucKeyIdx = 0; ucKeyIdx < 4; ucKeyIdx++) { + for (ucIdx = 0; ucIdx < NL80211_KEYRSC_LEN; ucIdx++) + prDetRplyInfo->arReplayPNInfo[ucKeyIdx] + .auPN[ucIdx] = 0x0; + } + + ucRpyOffload = + prGlueInfo->prAdapter->rWifiVar.ucRpyDetectOffload; + + /* sync BC/MC PN */ + if (ucRpyOffload && ucGtkOffload) { + wlanSuspendRekeyOffload(prGlueInfo, + GTK_REKEY_CMD_MODE_GET_BCMC_PN); + } +#endif + + if (ucGtkOffload) { + wlanSuspendRekeyOffload(prGlueInfo, + GTK_REKEY_CMD_MODE_OFLOAD_OFF); + DBGLOG(HAL, STATE, "Resume rekey offload disable\n"); + } + } + + if (prGlueInfo->prAdapter->rWifiVar.ucWow && + prGlueInfo->prAdapter->rWowCtrl.fgWowEnable) { + if (kalGetMediaStateIndicated(prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED) { + DBGLOG(HAL, STATE, "leave WOW flow. AIS BssIndex:%d\n", + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + kalWowProcess(prGlueInfo, false); + + /* resume AIS power-saving cmd when leave wow state, + * ignore ePwrMode input */ + nicConfigPowerSaveWowProfile( + prGlueInfo->prAdapter, + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex, + ePwrMode, false, false); + } + } else if (prGlueInfo->prAdapter->rWifiVar.ucWlanSetCamDuringAct) { + ucIdx = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + + prBssInfo = prGlueInfo->prAdapter->aprBssInfo[ucIdx]; + ePwrMode = Param_PowerModeCAM; + + DBGLOG(HAL, STATE, "Set CAM mode idx:%d, mode:%d\n", ucIdx, + ePwrMode); + nicConfigPowerSaveProfile(prGlueInfo->prAdapter, ucIdx, + ePwrMode, false); + } + + if (prGlueInfo->prAdapter->u4IsKeepFullPwrBitmap) { + prGlueInfo->prAdapter->u4IsKeepFullPwrBitmap &= + ~BLOCK_KEEP_FULL_PWR; + wlanKeepFullPwr(prGlueInfo->prAdapter, true); + } +} + +void disconnect_sta(P_ADAPTER_T prAdapter, P_STA_RECORD_T sta_rec) +{ + P_GLUE_INFO_T glue_info; + P_MSG_AIS_ABORT_T ais_abort_msg = NULL; + P_MSG_P2P_CONNECTION_ABORT_T p2p_abot_msg = NULL; + P_BSS_INFO_T p2p_bss_info = NULL; + unsigned char role_idx = 0; + + if (!prAdapter) { + DBGLOG(MEM, ERROR, "prAdapter is NULL\n"); + return; + } + if (!sta_rec) { + DBGLOG(MEM, ERROR, "sta_rec is NULL\n"); + return; + } + + glue_info = prAdapter->prGlueInfo; + + switch (sta_rec->eStaType) { + case STA_TYPE_LEGACY_AP: + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + return; + } + + /* prepare message to AIS */ + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = false; + /* Send AIS Abort Message */ + ais_abort_msg = (P_MSG_AIS_ABORT_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (ais_abort_msg) { + ais_abort_msg->rMsgHdr.eMsgId = + MID_OID_AIS_FSM_JOIN_REQ; + ais_abort_msg->ucReasonOfDisconnect = + DISCONNECT_REASON_CODE_DISASSOCIATED; + ais_abort_msg->fgDelayIndication = false; + + DBGLOG(AIS, INFO, + "Disconnect STA[" MACSTR "] type:0x%x\n", + MAC2STR(sta_rec->aucMacAddr), sta_rec->eStaType); + + mboxSendMsg(prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)ais_abort_msg, + MSG_SEND_METHOD_UNBUF); +#define DISCONNECT_STATUS WLAN_STATUS_MEDIA_DISCONNECT + /* indicate for disconnection */ + if (kalGetMediaStateIndicated(glue_info) == + PARAM_MEDIA_STATE_CONNECTED) { + kalIndicateStatusAndComplete( + glue_info, DISCONNECT_STATUS, NULL, 0); + } +#undef DISCONNECT_STATUS + } + break; + + case STA_TYPE_LEGACY_CLIENT: + case STA_TYPE_P2P_GC: + case STA_TYPE_P2P_GO: + p2p_abot_msg = (P_MSG_P2P_CONNECTION_ABORT_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_CONNECTION_ABORT_T)); + + if (p2p_abot_msg) { + if (sta_rec->ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(SW4, + ERROR, + "Invalid BssInfo index[%u], skip dump!\n", + sta_rec->ucBssIndex); + return; + } + + p2p_bss_info = GET_BSS_INFO_BY_INDEX( + prAdapter, sta_rec->ucBssIndex); + role_idx = p2p_bss_info->u4PrivateData; + p2p_abot_msg->rMsgHdr.eMsgId = + MID_MNY_P2P_CONNECTION_ABORT; + COPY_MAC_ADDR(p2p_abot_msg->aucTargetID, + sta_rec->aucMacAddr); + + p2p_abot_msg->u2ReasonCode = REASON_CODE_UNSPECIFIED; + p2p_abot_msg->ucRoleIdx = role_idx; + p2p_abot_msg->fgSendDeauth = false; + + DBGLOG(P2P, INFO, + "Disconnect STA[" MACSTR "] type:0x%x\n", + MAC2STR(sta_rec->aucMacAddr), sta_rec->eStaType); + + mboxSendMsg(prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)p2p_abot_msg, + MSG_SEND_METHOD_UNBUF); + } + break; + + default: + break; + } +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/common/wlan_oid.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/common/wlan_oid.c new file mode 100644 index 00000000000000..367d0224023386 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/common/wlan_oid.c @@ -0,0 +1,11278 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file wlanoid.c + * \brief This file contains the WLAN OID processing routines of Windows + * driver for MediaTek Inc. 802.11 Wireless LAN Adapters. + */ + +/****************************************************************************** + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/****************************************************************************** + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#include "mgmt/rsn.h" +#include "gl_wext.h" +#include "debug.h" +#include <linux/stddef.h> + +/****************************************************************************** + * C O N S T A N T S + ******************************************************************************* + */ + +/****************************************************************************** + * D A T A T Y P E S + ******************************************************************************* + */ + +/****************************************************************************** + * P U B L I C D A T A + ******************************************************************************* + */ + +PARAM_CUSTOM_KEY_CFG_STRUCT_T g_rDefaulteSetting[] = { + /*format : + *: {"firmware config parameter", "firmware config value"} + */ + { "AdapScan", "0x0" } +}; + +/****************************************************************************** + * P R I V A T E D A T A + ******************************************************************************* + */ + +/****************************************************************************** + * M A C R O S + ******************************************************************************* + */ + +/****************************************************************************** + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/****************************************************************************** + * F U N C T I O N S + ******************************************************************************* + */ + +#if CFG_ENABLE_STATISTICS_BUFFERING +static u8 IsBufferedStatisticsUsable(P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + if (prAdapter->fgIsStatValid == true && + (kalGetTimeTick() - prAdapter->rStatUpdateTime) <= + CFG_STATISTICS_VALID_CYCLE) { + return true; + } else { + return false; + } +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the supported physical layer network + * type that can be used by the driver. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryNetworkTypesSupported(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen) +{ + u32 u4NumItem = 0; + ENUM_PARAM_NETWORK_TYPE_T eSupportedNetworks[PARAM_NETWORK_TYPE_NUM]; + PPARAM_NETWORK_TYPE_LIST prSupported; + + /* The array of all physical layer network subtypes that the driver + * supports. */ + + DEBUGFUNC("wlanoidQueryNetworkTypesSupported"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + /* Init. */ + for (u4NumItem = 0; u4NumItem < PARAM_NETWORK_TYPE_NUM; u4NumItem++) + eSupportedNetworks[u4NumItem] = 0; + + u4NumItem = 0; + + eSupportedNetworks[u4NumItem] = PARAM_NETWORK_TYPE_DS; + u4NumItem++; + + eSupportedNetworks[u4NumItem] = PARAM_NETWORK_TYPE_OFDM24; + u4NumItem++; + + *pu4QueryInfoLen = (u32)OFFSET_OF(PARAM_NETWORK_TYPE_LIST, eNetworkType) + + (u4NumItem * sizeof(ENUM_PARAM_NETWORK_TYPE_T)); + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prSupported = (PPARAM_NETWORK_TYPE_LIST)pvQueryBuffer; + prSupported->NumberOfItems = u4NumItem; + kalMemCopy(prSupported->eNetworkType, eSupportedNetworks, + u4NumItem * sizeof(ENUM_PARAM_NETWORK_TYPE_T)); + + DBGLOG(REQ, TRACE, "NDIS supported network type list: %ld\n", + prSupported->NumberOfItems); + DBGLOG_MEM8(REQ, INFO, prSupported, *pu4QueryInfoLen); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the current physical layer network + * type used by the driver. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the + * call failed due to invalid length of the query + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryNetworkTypeInUse(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + /* TODO: need to check the OID handler content again!! */ + + ENUM_PARAM_NETWORK_TYPE_T rCurrentNetworkTypeInUse = + PARAM_NETWORK_TYPE_OFDM24; + + DEBUGFUNC("wlanoidQueryNetworkTypeInUse"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < sizeof(ENUM_PARAM_NETWORK_TYPE_T)) { + *pu4QueryInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED) { + rCurrentNetworkTypeInUse = + (ENUM_PARAM_NETWORK_TYPE_T)(prAdapter->rWlanInfo.ucNetworkType); + } else { + rCurrentNetworkTypeInUse = + (ENUM_PARAM_NETWORK_TYPE_T)(prAdapter->rWlanInfo.ucNetworkTypeInUse); + } + + *(P_ENUM_PARAM_NETWORK_TYPE_T)pvQueryBuffer = rCurrentNetworkTypeInUse; + *pu4QueryInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); + + DBGLOG(REQ, TRACE, "Network type in use: %d\n", rCurrentNetworkTypeInUse); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set the physical layer network type used + * by the driver. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns the + * amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS The given network type is supported and accepted. + * \retval WLAN_STATUS_INVALID_DATA The given network type is not in the + * supported list. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetNetworkTypeInUse(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + /* TODO: need to check the OID handler content again!! */ + + ENUM_PARAM_NETWORK_TYPE_T eNewNetworkType; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidSetNetworkTypeInUse"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(ENUM_PARAM_NETWORK_TYPE_T)) { + *pu4SetInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); + return WLAN_STATUS_INVALID_LENGTH; + } + + eNewNetworkType = *(P_ENUM_PARAM_NETWORK_TYPE_T)pvSetBuffer; + *pu4SetInfoLen = sizeof(ENUM_PARAM_NETWORK_TYPE_T); + + DBGLOG(REQ, INFO, "New network type: %d mode\n", eNewNetworkType); + + switch (eNewNetworkType) { + case PARAM_NETWORK_TYPE_DS: + prAdapter->rWlanInfo.ucNetworkTypeInUse = (u8)PARAM_NETWORK_TYPE_DS; + break; + + case PARAM_NETWORK_TYPE_OFDM5: + prAdapter->rWlanInfo.ucNetworkTypeInUse = (u8)PARAM_NETWORK_TYPE_OFDM5; + break; + + case PARAM_NETWORK_TYPE_OFDM24: + prAdapter->rWlanInfo.ucNetworkTypeInUse = (u8)PARAM_NETWORK_TYPE_OFDM24; + break; + + case PARAM_NETWORK_TYPE_AUTOMODE: + prAdapter->rWlanInfo.ucNetworkTypeInUse = + (u8)PARAM_NETWORK_TYPE_AUTOMODE; + break; + + case PARAM_NETWORK_TYPE_FH: + DBGLOG(REQ, INFO, "Not support network type: %d\n", eNewNetworkType); + rStatus = WLAN_STATUS_NOT_SUPPORTED; + break; + + default: + DBGLOG(REQ, INFO, "Unknown network type: %d\n", eNewNetworkType); + rStatus = WLAN_STATUS_INVALID_DATA; + break; + } + + /* Verify if we support the new network type. */ + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "Unknown network type: %d\n", eNewNetworkType); + } + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the current BSSID. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBssid(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQueryBssid"); + + ASSERT(prAdapter); + + if (u4QueryBufferLen < MAC_ADDR_LEN) { + ASSERT(pu4QueryInfoLen); + *pu4QueryInfoLen = MAC_ADDR_LEN; + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + ASSERT(u4QueryBufferLen >= MAC_ADDR_LEN); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED) { + kalMemCopy(pvQueryBuffer, prAdapter->rWlanInfo.rCurrBssId.arMacAddress, + MAC_ADDR_LEN); + } else if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS) { + PARAM_MAC_ADDRESS aucTemp; /*!< BSSID */ + + COPY_MAC_ADDR(aucTemp, prAdapter->rWlanInfo.rCurrBssId.arMacAddress); + aucTemp[0] &= ~BIT(0); + aucTemp[1] |= BIT(1); + COPY_MAC_ADDR(pvQueryBuffer, aucTemp); + } else { + rStatus = WLAN_STATUS_ADAPTER_NOT_READY; + } + + *pu4QueryInfoLen = MAC_ADDR_LEN; + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the list of all BSSIDs detected by + * the driver. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBssidList(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + u32 i, u4BssidListExLen; + P_PARAM_BSSID_LIST_EX_T prList; + P_PARAM_BSSID_EX_T prBssidEx; + u8 *cp; + + DEBUGFUNC("wlanoidQueryBssidList"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + + if (!pvQueryBuffer) { + return WLAN_STATUS_INVALID_DATA; + } + } + + prGlueInfo = prAdapter->prGlueInfo; + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in qeury BSSID list! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + u4BssidListExLen = 0; + + if (prAdapter->fgIsRadioOff == false) { + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) + u4BssidListExLen += + ALIGN_4(prAdapter->rWlanInfo.arScanResult[i].u4Length); + } + + if (u4BssidListExLen) { + u4BssidListExLen += 4; /* u4NumberOfItems. */ + } else { + u4BssidListExLen = sizeof(PARAM_BSSID_LIST_EX_T); + } + + *pu4QueryInfoLen = u4BssidListExLen; + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + return WLAN_STATUS_INVALID_LENGTH; + } + + /* Clear the buffer */ + kalMemZero(pvQueryBuffer, u4BssidListExLen); + + prList = (P_PARAM_BSSID_LIST_EX_T)pvQueryBuffer; + cp = (u8 *)&prList->arBssid[0]; + + if (prAdapter->fgIsRadioOff == false && + prAdapter->rWlanInfo.u4ScanResultNum > 0) { + /* fill up for each entry */ + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { + prBssidEx = (P_PARAM_BSSID_EX_T)cp; + + /* copy structure */ + kalMemCopy(prBssidEx, &(prAdapter->rWlanInfo.arScanResult[i]), + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + /*For WHQL test, Rssi should be in range -10 ~ -200 dBm + */ + if (prBssidEx->rRssi > PARAM_WHQL_RSSI_MAX_DBM) { + prBssidEx->rRssi = PARAM_WHQL_RSSI_MAX_DBM; + } + + if (prAdapter->rWlanInfo.arScanResult[i].u4IELength > 0) { + /* copy IEs */ + kalMemCopy(prBssidEx->aucIEs, + prAdapter->rWlanInfo.apucScanResultIEs[i], + prAdapter->rWlanInfo.arScanResult[i].u4IELength); + } + /* 4-bytes alignement */ + prBssidEx->u4Length = ALIGN_4(prBssidEx->u4Length); + + cp += prBssidEx->u4Length; + prList->u4NumberOfItems++; + } + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to request the driver to perform + * scanning. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBssidListScan(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_SSID_T prSsid; + PARAM_SSID_T rSsid; + + DEBUGFUNC("wlanoidSetBssidListScan()"); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in set BSSID list scan! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pu4SetInfoLen); + *pu4SetInfoLen = 0; + + if (prAdapter->fgIsRadioOff) { + DBGLOG(REQ, WARN, + "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_SUCCESS; + } + + if (pvSetBuffer != NULL && u4SetBufferLen != 0) { + COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, pvSetBuffer, u4SetBufferLen); + prSsid = &rSsid; + } else { + prSsid = NULL; + } + +#if CFG_SUPPORT_RDD_TEST_MODE + if (prAdapter->prGlueInfo->rRegInfo.u4RddTestMode) { + if ((prAdapter->fgEnOnlineScan == true) && (prAdapter->ucRddStatus)) { + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != + PARAM_MEDIA_STATE_CONNECTED) { + aisFsmScanRequest(prAdapter, prSsid, NULL, 0); + } else { + return WLAN_STATUS_FAILURE; + } + } else { + return WLAN_STATUS_FAILURE; + } + } else +#endif + { + if (prAdapter->fgEnOnlineScan == true) { + aisFsmScanRequest(prAdapter, prSsid, NULL, 0); + } else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != + PARAM_MEDIA_STATE_CONNECTED) { + aisFsmScanRequest(prAdapter, prSsid, NULL, 0); + } else { + return WLAN_STATUS_FAILURE; + } + } + + cnmTimerStartTimer(prAdapter, + &prAdapter->rWifiVar.rAisFsmInfo.rScanDoneTimer, + SEC_TO_MSEC(AIS_SCN_DONE_TIMEOUT_SEC)); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to request the driver to perform + * scanning with attaching information elements(IEs) specified from user + * space + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBssidListScanExt(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_SCAN_REQUEST_EXT_T prScanRequest; + P_PARAM_SSID_T prSsid; + u8 *pucIe; + u32 u4IeLength; + + DEBUGFUNC("wlanoidSetBssidListScanExt()"); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in set BSSID list scan! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pu4SetInfoLen); + *pu4SetInfoLen = 0; + + if (u4SetBufferLen != sizeof(PARAM_SCAN_REQUEST_EXT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + if (prAdapter->fgIsRadioOff) { + DBGLOG(REQ, WARN, + "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_SUCCESS; + } + DBGLOG(AIS, INFO, "ScanEX\n"); + if (pvSetBuffer != NULL && u4SetBufferLen != 0) { + prScanRequest = (P_PARAM_SCAN_REQUEST_EXT_T)pvSetBuffer; + prSsid = &(prScanRequest->rSsid); + pucIe = prScanRequest->pucIE; + u4IeLength = prScanRequest->u4IELength; + } else { + prScanRequest = NULL; + prSsid = NULL; + pucIe = NULL; + u4IeLength = 0; + } + +#if CFG_SUPPORT_RDD_TEST_MODE + if (prAdapter->prGlueInfo->rRegInfo.u4RddTestMode) { + if ((prAdapter->fgEnOnlineScan == true) && (prAdapter->ucRddStatus)) { + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != + PARAM_MEDIA_STATE_CONNECTED) { + aisFsmScanRequest(prAdapter, prSsid, pucIe, u4IeLength); + } else { + return WLAN_STATUS_FAILURE; + } + } else { + return WLAN_STATUS_FAILURE; + } + } else +#endif + { + if (prAdapter->fgEnOnlineScan == true) { + aisFsmScanRequest(prAdapter, prSsid, pucIe, u4IeLength); + } else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != + PARAM_MEDIA_STATE_CONNECTED) { + aisFsmScanRequest(prAdapter, prSsid, pucIe, u4IeLength); + } else { + return WLAN_STATUS_FAILURE; + } + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to request the driver to perform + * scanning with attaching information elements(IEs) specified from user + * space and multiple SSID + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBssidListScanAdv(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_SCAN_REQUEST_ADV_T prScanRequest; + PARAM_SSID_T rSsid[CFG_SCAN_SSID_MAX_NUM]; + u8 *pucIe; + u8 ucSsidNum; + u32 i, u4IeLength; + + DEBUGFUNC("wlanoidSetBssidListScanAdv()"); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in set BSSID list scan! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pu4SetInfoLen); + *pu4SetInfoLen = 0; + + if (u4SetBufferLen != sizeof(PARAM_SCAN_REQUEST_ADV_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } else if (pvSetBuffer == NULL) { + return WLAN_STATUS_INVALID_DATA; + } + + if (prAdapter->fgIsRadioOff) { + DBGLOG(REQ, WARN, + "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_SUCCESS; + } + + prScanRequest = (P_PARAM_SCAN_REQUEST_ADV_T)pvSetBuffer; + + ucSsidNum = (u8)(prScanRequest->u4SsidNum); + for (i = 0; i < prScanRequest->u4SsidNum; i++) { + if (prScanRequest->rSsid[i].u4SsidLen > ELEM_MAX_LEN_SSID) { + DBGLOG( + REQ, ERROR, + "[%s] SSID(%s) Length(%ld) is over than ELEM_MAX_LEN_SSID(%d)\n", + __func__, prScanRequest->rSsid[i].aucSsid, + prScanRequest->rSsid[i].u4SsidLen, ELEM_MAX_LEN_SSID); + DBGLOG_MEM8(REQ, ERROR, prScanRequest, + sizeof(PARAM_SCAN_REQUEST_ADV_T)); + } + COPY_SSID(rSsid[i].aucSsid, rSsid[i].u4SsidLen, + prScanRequest->rSsid[i].aucSsid, + prScanRequest->rSsid[i].u4SsidLen); + } + + pucIe = prScanRequest->pucIE; + u4IeLength = prScanRequest->u4IELength; + +#if CFG_SUPPORT_RDD_TEST_MODE + if (prAdapter->prGlueInfo->rRegInfo.u4RddTestMode) { + if ((prAdapter->fgEnOnlineScan == true) && (prAdapter->ucRddStatus)) { + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != + PARAM_MEDIA_STATE_CONNECTED) +#if CFG_SCAN_CHANNEL_SPECIFIED + { + aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid, + prScanRequest->ucChannelListNum, + prScanRequest->arChnlInfoList, pucIe, + u4IeLength); + } +#else + { + aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid, 0, NULL, + pucIe, u4IeLength); + } +#endif + else { + return WLAN_STATUS_FAILURE; + } + } else { + return WLAN_STATUS_FAILURE; + } + } else +#endif + { + if (prAdapter->fgEnOnlineScan == true) +#if CFG_SCAN_CHANNEL_SPECIFIED + { + aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid, + prScanRequest->ucChannelListNum, + prScanRequest->arChnlInfoList, pucIe, + u4IeLength); + } +#else + { + aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid, 0, NULL, pucIe, + u4IeLength); + } +#endif + else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != + PARAM_MEDIA_STATE_CONNECTED) +#if CFG_SCAN_CHANNEL_SPECIFIED + { + aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid, + prScanRequest->ucChannelListNum, + prScanRequest->arChnlInfoList, pucIe, + u4IeLength); + } +#else + { + aisFsmScanRequestAdv(prAdapter, ucSsidNum, rSsid, 0, NULL, pucIe, + u4IeLength); + } +#endif + else { + return WLAN_STATUS_FAILURE; + } + } + cnmTimerStartTimer(prAdapter, + &prAdapter->rWifiVar.rAisFsmInfo.rScanDoneTimer, + SEC_TO_MSEC(AIS_SCN_DONE_TIMEOUT_SEC)); + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine will initiate the join procedure to attempt to associate + * with the specified BSSID. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBssid(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + u8 *pAddr; + u32 i; + s32 i4Idx = -1; + P_MSG_AIS_ABORT_T prAisAbortMsg; + u8 ucReasonOfDisconnect; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = MAC_ADDR_LEN; + if (u4SetBufferLen != MAC_ADDR_LEN) { + *pu4SetInfoLen = MAC_ADDR_LEN; + return WLAN_STATUS_INVALID_LENGTH; + } else if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + prGlueInfo = prAdapter->prGlueInfo; + pAddr = (u8 *)pvSetBuffer; + + /* re-association check */ + if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, + pAddr)) { + kalSetMediaStateIndicated(prGlueInfo, + PARAM_MEDIA_STATE_TO_BE_INDICATED); + ucReasonOfDisconnect = DISCONNECT_REASON_CODE_REASSOCIATION; + } else { + kalIndicateStatusAndComplete(prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; + } + } else { + ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; + } + + /* check if any scanned result matchs with the BSSID */ + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { + if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, + pAddr)) { + i4Idx = (s32)i; + break; + } + } + + /* prepare message to AIS */ + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS || + prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_DEDICATED_IBSS) { + /* IBSS */ /* beacon period */ + prAdapter->rWifiVar.rConnSettings.u2BeaconPeriod = + prAdapter->rWlanInfo.u2BeaconPeriod; + prAdapter->rWifiVar.rConnSettings.u2AtimWindow = + prAdapter->rWlanInfo.u2AtimWindow; + } + + /* Set Connection Request Issued Flag */ + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = true; + prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = CONNECT_BY_BSSID; + + /* Send AIS Abort Message */ + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + DBGLOG(REQ, ERROR, "Fail in allocating AisAbortMsg.\n"); + return WLAN_STATUS_FAILURE; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; + prAisAbortMsg->ucReasonOfDisconnect = ucReasonOfDisconnect; + + /* Update the information to CONNECTION_SETTINGS_T */ + prAdapter->rWifiVar.rConnSettings.ucSSIDLen = 0; + prAdapter->rWifiVar.rConnSettings.aucSSID[0] = '\0'; + COPY_MAC_ADDR(prAdapter->rWifiVar.rConnSettings.aucBSSID, pAddr); + + if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, pAddr)) { + prAisAbortMsg->fgDelayIndication = true; + } else { + prAisAbortMsg->fgDelayIndication = false; + } + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prAisAbortMsg, + MSG_SEND_METHOD_BUF); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine will initiate the join procedure to attempt + * to associate with the new SSID. If the previous scanning + * result is aged, we will scan the channels at first. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_DATA + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetSsid(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_PARAM_SSID_T pParamSsid; + u32 i; + s32 i4Idx = -1, i4MaxRSSI = INT_MIN; + P_MSG_AIS_ABORT_T prAisAbortMsg; + u8 fgIsValidSsid = true; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + /* MSDN: + * Powering on the radio if the radio is powered off through a setting + * of OID_802_11_DISASSOCIATE + */ + if (prAdapter->fgIsRadioOff == true) { + prAdapter->fgIsRadioOff = false; + } + + if (u4SetBufferLen < sizeof(PARAM_SSID_T) || + u4SetBufferLen > sizeof(PARAM_SSID_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } else if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + pParamSsid = (P_PARAM_SSID_T)pvSetBuffer; + + if (pParamSsid->u4SsidLen > 32) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prGlueInfo = prAdapter->prGlueInfo; + + /* prepare for CMD_BUILD_CONNECTION & CMD_GET_CONNECTION_STATUS */ + /* re-association check */ + if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + if (EQUAL_SSID(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen, + pParamSsid->aucSsid, pParamSsid->u4SsidLen)) { + kalSetMediaStateIndicated(prGlueInfo, + PARAM_MEDIA_STATE_TO_BE_INDICATED); + } else { + kalIndicateStatusAndComplete(prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + } + } + /* check if any scanned result matchs with the SSID */ + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { + u8 *aucSsid = prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid; + u8 ucSsidLength = + (u8)prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen; + s32 i4RSSI = prAdapter->rWlanInfo.arScanResult[i].rRssi; + + if (EQUAL_SSID(aucSsid, ucSsidLength, pParamSsid->aucSsid, + pParamSsid->u4SsidLen) && + i4RSSI >= i4MaxRSSI) { + i4Idx = (s32)i; + i4MaxRSSI = i4RSSI; + } + } + + /* prepare message to AIS */ + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_IBSS || + prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_DEDICATED_IBSS) { + /* IBSS */ /* beacon period */ + prAdapter->rWifiVar.rConnSettings.u2BeaconPeriod = + prAdapter->rWlanInfo.u2BeaconPeriod; + prAdapter->rWifiVar.rConnSettings.u2AtimWindow = + prAdapter->rWlanInfo.u2AtimWindow; + } + + if (prAdapter->rWifiVar.fgSupportWZCDisassociation) { + if (pParamSsid->u4SsidLen == ELEM_MAX_LEN_SSID) { + fgIsValidSsid = false; + + for (i = 0; i < ELEM_MAX_LEN_SSID; i++) { + if (!((pParamSsid->aucSsid[i] > 0) && + (pParamSsid->aucSsid[i] <= 0x1F))) { + fgIsValidSsid = true; + break; + } + } + } + } + + /* Set Connection Request Issued Flag */ + if (fgIsValidSsid) { + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = true; + + if (pParamSsid->u4SsidLen) { + prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = + CONNECT_BY_SSID_BEST_RSSI; + } else { + /* wildcard SSID */ + prAdapter->rWifiVar.rConnSettings.eConnectionPolicy = + CONNECT_BY_SSID_ANY; + } + } else { + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = false; + } + + /* Send AIS Abort Message */ + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + DBGLOG(REQ, ERROR, "Fail in allocating AisAbortMsg.\n"); + return WLAN_STATUS_FAILURE; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; + prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; + COPY_SSID(prAdapter->rWifiVar.rConnSettings.aucSSID, + prAdapter->rWifiVar.rConnSettings.ucSSIDLen, pParamSsid->aucSsid, + (u8)pParamSsid->u4SsidLen); + + if (EQUAL_SSID(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen, + pParamSsid->aucSsid, pParamSsid->u4SsidLen)) { + prAisAbortMsg->fgDelayIndication = true; + } else { + /* Update the information to CONNECTION_SETTINGS_T */ + prAisAbortMsg->fgDelayIndication = false; + } + DBGLOG(SCN, INFO, "SSID %s\n", prAdapter->rWifiVar.rConnSettings.aucSSID); + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prAisAbortMsg, + MSG_SEND_METHOD_BUF); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine will initiate the join procedure to attempt + * to associate with the new BSS, base on given SSID, BSSID, and + * freqency. If the target connecting BSS is in the same ESS as current + * connected BSS, roaming will be performed. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_DATA + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetConnect(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_PARAM_CONNECT_T pParamConn; + P_CONNECTION_SETTINGS_T prConnSettings; + u32 i; + P_MSG_AIS_ABORT_T prAisAbortMsg; + u8 fgIsValidSsid = true; + u8 fgEqualSsid = false; + u8 fgEqualBssid = false; + const u8 aucZeroMacAddr[] = NULL_MAC_ADDR; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + /* MSDN: + * Powering on the radio if the radio is powered off through a setting + * of OID_802_11_DISASSOCIATE + */ + if (prAdapter->fgIsRadioOff == true) { + prAdapter->fgIsRadioOff = false; + } + + if (u4SetBufferLen != sizeof(PARAM_CONNECT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } else if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in set ssid! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + DBGLOG(REQ, ERROR, "Fail in allocating AisAbortMsg.\n"); + return WLAN_STATUS_FAILURE; + } + prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; + + pParamConn = (P_PARAM_CONNECT_T)pvSetBuffer; + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + + if (pParamConn->u4SsidLen > 32) { + return WLAN_STATUS_INVALID_LENGTH; + } else if (!pParamConn->pucBssid && !pParamConn->pucSsid) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prGlueInfo = prAdapter->prGlueInfo; + kalMemZero(prConnSettings->aucSSID, sizeof(prConnSettings->aucSSID)); + prConnSettings->ucSSIDLen = 0; + kalMemZero(prConnSettings->aucBSSID, sizeof(prConnSettings->aucBSSID)); + prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_ANY; + prConnSettings->fgIsConnByBssidIssued = false; + + if (pParamConn->pucSsid) { + prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; + COPY_SSID(prConnSettings->aucSSID, prConnSettings->ucSSIDLen, + pParamConn->pucSsid, (u8)pParamConn->u4SsidLen); + if (EQUAL_SSID(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen, + pParamConn->pucSsid, pParamConn->u4SsidLen)) { + fgEqualSsid = true; + } + } + if (pParamConn->pucBssid) { + if (!EQUAL_MAC_ADDR(aucZeroMacAddr, pParamConn->pucBssid) && + IS_UCAST_MAC_ADDR(pParamConn->pucBssid)) { + prConnSettings->eConnectionPolicy = CONNECT_BY_BSSID; + prConnSettings->fgIsConnByBssidIssued = true; + COPY_MAC_ADDR(prConnSettings->aucBSSID, pParamConn->pucBssid); + if (EQUAL_MAC_ADDR(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, + pParamConn->pucBssid)) { + fgEqualBssid = true; + } + } else { + DBGLOG(INIT, INFO, "wrong bssid " MACSTR "to connect\n", + MAC2STR(pParamConn->pucBssid)); + } + } else { + DBGLOG(INIT, INFO, "No Bssid set\n"); + } + prConnSettings->u4FreqInKHz = pParamConn->u4CenterFreq; + + /* prepare for CMD_BUILD_CONNECTION & CMD_GET_CONNECTION_STATUS */ + /* re-association check */ + if (kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + if (fgEqualSsid) { + prAisAbortMsg->ucReasonOfDisconnect = + DISCONNECT_REASON_CODE_REASSOCIATION; + if (fgEqualBssid) { + kalSetMediaStateIndicated(prGlueInfo, + PARAM_MEDIA_STATE_TO_BE_INDICATED); + } + } else { + DBGLOG(INIT, INFO, "DisBySsid\n"); + kalIndicateStatusAndComplete(prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + prAisAbortMsg->ucReasonOfDisconnect = + DISCONNECT_REASON_CODE_NEW_CONNECTION; + } + } else { + prAisAbortMsg->ucReasonOfDisconnect = + DISCONNECT_REASON_CODE_NEW_CONNECTION; + } + + /* prepare message to AIS */ + if (prConnSettings->eOPMode == NET_TYPE_IBSS || + prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS) { + /* IBSS */ /* beacon period */ + prConnSettings->u2BeaconPeriod = prAdapter->rWlanInfo.u2BeaconPeriod; + prConnSettings->u2AtimWindow = prAdapter->rWlanInfo.u2AtimWindow; + } + + if (prAdapter->rWifiVar.fgSupportWZCDisassociation) { + if (pParamConn->u4SsidLen == ELEM_MAX_LEN_SSID) { + fgIsValidSsid = false; + + if (pParamConn->pucSsid) { + for (i = 0; i < ELEM_MAX_LEN_SSID; i++) { + if (!((pParamConn->pucSsid[i] > 0) && + (pParamConn->pucSsid[i] <= 0x1F))) { + fgIsValidSsid = true; + break; + } + } + } else { + DBGLOG(INIT, ERROR, "pParamConn->pucSsid is NULL\n"); + } + } + } + + /* Set Connection Request Issued Flag */ + if (fgIsValidSsid) { + prConnSettings->fgIsConnReqIssued = true; + } else { + prConnSettings->fgIsConnReqIssued = false; + } + + if (fgEqualSsid || fgEqualBssid) { + prAisAbortMsg->fgDelayIndication = true; + } else { + /* Update the information to CONNECTION_SETTINGS_T */ + prAisAbortMsg->fgDelayIndication = false; + } + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prAisAbortMsg, + MSG_SEND_METHOD_BUF); + + DBGLOG(INIT, INFO, + "ssid %s, bssid " MACSTR ", conn policy %d, disc reason %d\n", + prConnSettings->aucSSID, MAC2STR(prConnSettings->aucBSSID), + prConnSettings->eConnectionPolicy, + prAisAbortMsg->ucReasonOfDisconnect); + return WLAN_STATUS_SUCCESS; +} /* end of wlanoidSetConnect */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the currently associated SSID. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuerySsid(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_SSID_T prAssociatedSsid; + + DEBUGFUNC("wlanoidQuerySsid"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_SSID_T); + + /* Check for query buffer length */ + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(REQ, WARN, "Invalid length %lu\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prAssociatedSsid = (P_PARAM_SSID_T)pvQueryBuffer; + + kalMemZero(prAssociatedSsid->aucSsid, sizeof(prAssociatedSsid->aucSsid)); + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED) { + prAssociatedSsid->u4SsidLen = + prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen; + + if (prAssociatedSsid->u4SsidLen) { + kalMemCopy(prAssociatedSsid->aucSsid, + prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prAssociatedSsid->u4SsidLen); + } + } else { + prAssociatedSsid->u4SsidLen = 0; + + DBGLOG(REQ, TRACE, "Null SSID\n"); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the current 802.11 network type. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryInfrastructureMode(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryInfrastructureMode"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(ENUM_PARAM_OP_MODE_T); + + if (u4QueryBufferLen < sizeof(ENUM_PARAM_OP_MODE_T)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *(P_ENUM_PARAM_OP_MODE_T)pvQueryBuffer = + prAdapter->rWifiVar.rConnSettings.eOPMode; + + /* + ** According to OID_802_11_INFRASTRUCTURE_MODE + ** If there is no prior OID_802_11_INFRASTRUCTURE_MODE, + ** NDIS_STATUS_ADAPTER_NOT_READY shall be returned. + */ +#if DBG + switch (*(P_ENUM_PARAM_OP_MODE_T)pvQueryBuffer) { + case NET_TYPE_IBSS: + DBGLOG(REQ, INFO, "IBSS mode\n"); + break; + + case NET_TYPE_INFRA: + DBGLOG(REQ, INFO, "Infrastructure mode\n"); + break; + + default: + DBGLOG(REQ, INFO, "Automatic mode\n"); + } +#endif + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set mode to infrastructure or + * IBSS, or automatic switch between the two. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed due to invalid + * length of the set buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_DATA + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetInfrastructureMode(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + ENUM_PARAM_OP_MODE_T eOpMode; +/* P_WLAN_TABLE_T prWlanTable; */ +#if CFG_SUPPORT_802_11W +/* P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; */ +#endif + /* P_BSS_INFO_T prBssInfo; */ + /* u8 i; */ + + DEBUGFUNC("wlanoidSetInfrastructureMode"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + prGlueInfo = prAdapter->prGlueInfo; + + if (u4SetBufferLen < sizeof(ENUM_PARAM_OP_MODE_T)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + *pu4SetInfoLen = sizeof(ENUM_PARAM_OP_MODE_T); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in set infrastructure mode! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + eOpMode = *(P_ENUM_PARAM_OP_MODE_T)pvSetBuffer; + /* Verify the new infrastructure mode. */ + if (eOpMode >= NET_TYPE_NUM) { + DBGLOG(REQ, TRACE, "Invalid mode value %d\n", eOpMode); + return WLAN_STATUS_INVALID_DATA; + } + + /* check if possible to switch to AdHoc mode */ + if (eOpMode == NET_TYPE_IBSS || eOpMode == NET_TYPE_DEDICATED_IBSS) { + if (cnmAisIbssIsPermitted(prAdapter) == false) { + DBGLOG(REQ, TRACE, "Mode value %d unallowed\n", eOpMode); + return WLAN_STATUS_FAILURE; + } + } + + /* Save the new infrastructure mode setting. */ + prAdapter->rWifiVar.rConnSettings.eOPMode = eOpMode; + + prAdapter->rWifiVar.rConnSettings.fgWapiMode = false; + +#if CFG_SUPPORT_802_11W + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = false; + prAdapter->rWifiVar.rAisSpecificBssInfo.fgBipKeyInstalled = false; +#endif + +#if CFG_SUPPORT_WPS2 + kalMemZero(&prAdapter->prGlueInfo->aucWSCAssocInfoIE, 200); + prAdapter->prGlueInfo->u2WSCAssocInfoIELen = 0; +#endif + + /* Clean up the Tx key flag */ + if (prAdapter->prAisBssInfo != NULL) { + prAdapter->prAisBssInfo->fgBcDefaultKeyExist = false; + prAdapter->prAisBssInfo->ucBcDefaultKeyIdx = 0xFF; + } + + /* prWlanTable = prAdapter->rWifiVar.arWtbl; */ + /* prWlanTable[prAdapter->prAisBssInfo->ucBMCWlanIndex].ucKeyId = 0; */ + +#if DBG + DBGLOG(RSN, TRACE, "wlanoidSetInfrastructureMode\n"); +#endif + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_INFRASTRUCTURE, true, false, + true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, 0, NULL, pvSetBuffer, + u4SetBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the current 802.11 authentication + * mode. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryAuthMode(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryAuthMode"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(ENUM_PARAM_AUTH_MODE_T); + + if (u4QueryBufferLen < sizeof(ENUM_PARAM_AUTH_MODE_T)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + *(P_ENUM_PARAM_AUTH_MODE_T)pvQueryBuffer = + prAdapter->rWifiVar.rConnSettings.eAuthMode; + +#if DBG + switch (*(P_ENUM_PARAM_AUTH_MODE_T)pvQueryBuffer) { + case AUTH_MODE_OPEN: + DBGLOG(REQ, INFO, "Current auth mode: Open\n"); + break; + + case AUTH_MODE_SHARED: + DBGLOG(REQ, INFO, "Current auth mode: Shared\n"); + break; + + case AUTH_MODE_AUTO_SWITCH: + DBGLOG(REQ, INFO, "Current auth mode: Auto-switch\n"); + break; + + case AUTH_MODE_WPA: + DBGLOG(REQ, INFO, "Current auth mode: WPA\n"); + break; + + case AUTH_MODE_WPA_PSK: + DBGLOG(REQ, INFO, "Current auth mode: WPA PSK\n"); + break; + + case AUTH_MODE_WPA_NONE: + DBGLOG(REQ, INFO, "Current auth mode: WPA None\n"); + break; + + case AUTH_MODE_WPA2: + DBGLOG(REQ, INFO, "Current auth mode: WPA2\n"); + break; + + case AUTH_MODE_WPA2_PSK: + DBGLOG(REQ, INFO, "Current auth mode: WPA2 PSK\n"); + break; + + case AUTH_MODE_WPA2_SAE: + DBGLOG(RSN, INFO, "Current auth mode: SAE\n"); + break; + + default: + DBGLOG(REQ, INFO, "Current auth mode: %d\n", + *(P_ENUM_PARAM_AUTH_MODE_T)pvQueryBuffer); + break; + } +#endif + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set the IEEE 802.11 authentication mode + * to the driver. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_DATA + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_NOT_ACCEPTED + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAuthMode(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + /* u32 i, u4AkmSuite; */ + /* P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry; */ + + DEBUGFUNC("wlanoidSetAuthMode"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + ASSERT(pvSetBuffer); + + prGlueInfo = prAdapter->prGlueInfo; + + *pu4SetInfoLen = sizeof(ENUM_PARAM_AUTH_MODE_T); + + if (u4SetBufferLen < sizeof(ENUM_PARAM_AUTH_MODE_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + /* RF Test */ + /* if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { */ + /* return WLAN_STATUS_SUCCESS; */ + /* } */ + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in set Authentication mode! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + /* Check if the new authentication mode is valid. */ + if (*(P_ENUM_PARAM_AUTH_MODE_T)pvSetBuffer >= AUTH_MODE_NUM) { + DBGLOG(REQ, TRACE, "Invalid auth mode %d\n", + *(P_ENUM_PARAM_AUTH_MODE_T)pvSetBuffer); + return WLAN_STATUS_INVALID_DATA; + } + + switch (*(P_ENUM_PARAM_AUTH_MODE_T)pvSetBuffer) { + case AUTH_MODE_WPA: + case AUTH_MODE_WPA_PSK: + case AUTH_MODE_WPA2: + case AUTH_MODE_WPA2_PSK: + /* infrastructure mode only */ + if (prAdapter->rWifiVar.rConnSettings.eOPMode != NET_TYPE_INFRA) { + return WLAN_STATUS_NOT_ACCEPTED; + } + + break; + + case AUTH_MODE_WPA_NONE: + /* ad hoc mode only */ + if (prAdapter->rWifiVar.rConnSettings.eOPMode != NET_TYPE_IBSS) { + return WLAN_STATUS_NOT_ACCEPTED; + } + + break; + + default: + break; + } + + /* Save the new authentication mode. */ + prAdapter->rWifiVar.rConnSettings.eAuthMode = + *(P_ENUM_PARAM_AUTH_MODE_T)pvSetBuffer; + + switch (prAdapter->rWifiVar.rConnSettings.eAuthMode) { + case AUTH_MODE_OPEN: + DBGLOG(RSN, TRACE, "New auth mode: open\n"); + break; + + case AUTH_MODE_SHARED: + DBGLOG(RSN, TRACE, "New auth mode: shared\n"); + break; + + case AUTH_MODE_AUTO_SWITCH: + DBGLOG(RSN, TRACE, "New auth mode: auto-switch\n"); + break; + + case AUTH_MODE_WPA: + DBGLOG(RSN, TRACE, "New auth mode: WPA\n"); + break; + + case AUTH_MODE_WPA_PSK: + DBGLOG(RSN, TRACE, "New auth mode: WPA PSK\n"); + break; + + case AUTH_MODE_WPA_NONE: + DBGLOG(RSN, TRACE, "New auth mode: WPA None\n"); + break; + + case AUTH_MODE_WPA2: + DBGLOG(RSN, TRACE, "New auth mode: WPA2\n"); + break; + + case AUTH_MODE_WPA2_PSK: + DBGLOG(RSN, TRACE, "New auth mode: WPA2 PSK\n"); + break; + + default: + DBGLOG(RSN, TRACE, "New auth mode: unknown (%d)\n", + prAdapter->rWifiVar.rConnSettings.eAuthMode); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to reload the available default settings for + * the specified type field. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_INVALID_DATA + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetReloadDefaults(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + ENUM_PARAM_NETWORK_TYPE_T eNetworkType; + u32 u4Len; + u8 ucCmdSeqNum; + + DEBUGFUNC("wlanoidSetReloadDefaults"); + + ASSERT(prAdapter); + + ASSERT(pu4SetInfoLen); + *pu4SetInfoLen = sizeof(PARAM_RELOAD_DEFAULTS); + + /* if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { */ + /* return WLAN_STATUS_SUCCESS; */ + /* } */ + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in set Reload default! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pvSetBuffer); + /* Verify the available reload options and reload the settings. */ + switch (*(P_PARAM_RELOAD_DEFAULTS)pvSetBuffer) { + case ENUM_RELOAD_WEP_KEYS: + /* Reload available default WEP keys from the permanent + * storage. + */ + prAdapter->rWifiVar.rConnSettings.eAuthMode = AUTH_MODE_OPEN; + /* ENUM_ENCRYPTION_DISABLED; */ + prAdapter->rWifiVar.rConnSettings.eEncStatus = + ENUM_ENCRYPTION1_KEY_ABSENT; + { + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_CMD_802_11_KEY prCmdKey; + u8 aucBCAddr[] = BC_MAC_ADDR; + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = cmdBufAllocateCmdInfo( + prAdapter, (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_802_11_KEY cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = true; + prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; + prCmdInfo->fgSetQuery = true; + prCmdInfo->fgNeedResp = false; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdKey = (P_CMD_802_11_KEY)(prWifiCmd->aucBuffer); + + kalMemZero((u8 *)prCmdKey, sizeof(CMD_802_11_KEY)); + + prCmdKey->ucAddRemove = 0; /* Remove */ + prCmdKey->ucKeyId = 0; /* (u8)(prRemovedKey->u4KeyIndex + * & 0x000000ff); */ + kalMemCopy(prCmdKey->aucPeerAddr, aucBCAddr, MAC_ADDR_LEN); + + ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM); + + prCmdKey->ucKeyType = 0; + + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; + } + + break; + + default: + DBGLOG(REQ, TRACE, "Invalid reload option %d\n", + *(P_PARAM_RELOAD_DEFAULTS)pvSetBuffer); + rStatus = WLAN_STATUS_INVALID_DATA; + } + + /* OID_802_11_RELOAD_DEFAULTS requiest to reset to auto mode */ + eNetworkType = PARAM_NETWORK_TYPE_AUTOMODE; + wlanoidSetNetworkTypeInUse(prAdapter, &eNetworkType, sizeof(eNetworkType), + &u4Len); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set a WEP key to the driver. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + */ +/*----------------------------------------------------------------------------*/ + +u8 keyBuffer[sizeof(PARAM_KEY_T) + 16 /* LEGACY_KEY_MAX_LEN */]; +u8 aucBCAddr[] = BC_MAC_ADDR; + +WLAN_STATUS +wlanoidSetAddWep(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_WEP_T prNewWepKey; + P_PARAM_KEY_T prParamKey = (P_PARAM_KEY_T)keyBuffer; + u32 u4KeyId, u4SetLen; + + DEBUGFUNC("wlanoidSetAddWep"); + + ASSERT(prAdapter); + + *pu4SetInfoLen = OFFSET_OF(PARAM_WEP_T, aucKeyMaterial); + + if (u4SetBufferLen < OFFSET_OF(PARAM_WEP_T, aucKeyMaterial)) { + ASSERT(pu4SetInfoLen); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in set add WEP! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + prNewWepKey = (P_PARAM_WEP_T)pvSetBuffer; + + /* Verify the total buffer for minimum length. */ + if (u4SetBufferLen < + OFFSET_OF(PARAM_WEP_T, aucKeyMaterial) + prNewWepKey->u4KeyLength) { + DBGLOG(REQ, WARN, + "Invalid total buffer length (%d) than minimum length (%d)\n", + (u8)u4SetBufferLen, (u8)OFFSET_OF(PARAM_WEP_T, aucKeyMaterial)); + + *pu4SetInfoLen = OFFSET_OF(PARAM_WEP_T, aucKeyMaterial); + return WLAN_STATUS_INVALID_DATA; + } + + /* Verify the key structure length. */ + if (prNewWepKey->u4Length > u4SetBufferLen) { + DBGLOG( + REQ, WARN, + "Invalid key structure length (%d) greater than total buffer length " + "(%d)\n", + (u8)prNewWepKey->u4Length, + (u8)u4SetBufferLen); + + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_DATA; + } + + /* Verify the key material length for maximum key material length:16 */ + if (prNewWepKey->u4KeyLength > 16 /* LEGACY_KEY_MAX_LEN */) { + DBGLOG( + REQ, WARN, + "Invalid key material length (%d) greater than maximum key material " + "length (16)\n", + (u8)prNewWepKey->u4KeyLength); + + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_DATA; + } + + *pu4SetInfoLen = u4SetBufferLen; + + u4KeyId = prNewWepKey->u4KeyIndex & BITS(0, 29) /* WEP_KEY_ID_FIELD */; + + /* Verify whether key index is valid or not, current version + * driver support only 4 global WEP keys setting by this OID + */ + if (u4KeyId > MAX_KEY_NUM - 1) { + DBGLOG(REQ, ERROR, "Error, invalid WEP key ID: %d\n", (u8)u4KeyId); + return WLAN_STATUS_INVALID_DATA; + } + + prParamKey->u4KeyIndex = u4KeyId; + + /* Transmit key */ + if (prNewWepKey->u4KeyIndex & IS_TRANSMIT_KEY) { + prParamKey->u4KeyIndex |= IS_TRANSMIT_KEY; + } + + /* Per client key */ + if (prNewWepKey->u4KeyIndex & IS_UNICAST_KEY) { + prParamKey->u4KeyIndex |= IS_UNICAST_KEY; + } + + prParamKey->u4KeyLength = prNewWepKey->u4KeyLength; + + kalMemCopy(prParamKey->arBSSID, aucBCAddr, MAC_ADDR_LEN); + + kalMemCopy(prParamKey->aucKeyMaterial, prNewWepKey->aucKeyMaterial, + prNewWepKey->u4KeyLength); + + prParamKey->ucBssIdx = prAdapter->prAisBssInfo->ucBssIndex; + + if (prParamKey->u4KeyLength == WEP_40_LEN) { + prParamKey->ucCipher = CIPHER_SUITE_WEP40; + } else if (prParamKey->u4KeyLength == WEP_104_LEN) { + prParamKey->ucCipher = CIPHER_SUITE_WEP104; + } else if (prParamKey->u4KeyLength == WEP_128_LEN) { + prParamKey->ucCipher = CIPHER_SUITE_WEP128; + } + + prParamKey->u4Length = + OFFSET_OF(PARAM_KEY_T, aucKeyMaterial) + prNewWepKey->u4KeyLength; + + wlanoidSetAddKey(prAdapter, (void *)prParamKey, prParamKey->u4Length, + &u4SetLen); + + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to request the driver to remove the WEP key + * at the specified key index. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_DATA + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRemoveWep(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + u32 u4KeyId, u4SetLen; + PARAM_REMOVE_KEY_T rRemoveKey; + u8 aucBCAddr[] = BC_MAC_ADDR; + + DEBUGFUNC("wlanoidSetRemoveWep"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_KEY_INDEX); + + if (u4SetBufferLen < sizeof(PARAM_KEY_INDEX)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + u4KeyId = *(u32 *)pvSetBuffer; + + /* Dump PARAM_WEP content. */ + DBGLOG(REQ, INFO, "Set: Dump PARAM_KEY_INDEX content\n"); + DBGLOG(REQ, INFO, "Index : 0x%08lx\n", u4KeyId); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in set remove WEP! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + if (u4KeyId & IS_TRANSMIT_KEY) { + /* Bit 31 should not be set */ + DBGLOG(REQ, ERROR, "Invalid WEP key index: 0x%08lx\n", u4KeyId); + return WLAN_STATUS_INVALID_DATA; + } + + u4KeyId &= BITS(0, 7); + + /* Verify whether key index is valid or not. Current version + * driver support only 4 global WEP keys. + */ + if (u4KeyId > MAX_KEY_NUM - 1) { + DBGLOG(REQ, ERROR, "invalid WEP key ID %lu\n", u4KeyId); + return WLAN_STATUS_INVALID_DATA; + } + + kalMemZero(&rRemoveKey, sizeof(PARAM_REMOVE_KEY_T)); + rRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); + rRemoveKey.u4KeyIndex = *(u32 *)pvSetBuffer; + + kalMemCopy(rRemoveKey.arBSSID, aucBCAddr, MAC_ADDR_LEN); + + wlanoidSetRemoveKey(prAdapter, (void *)&rRemoveKey, + sizeof(PARAM_REMOVE_KEY_T), &u4SetLen); + + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set a key to the driver. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + * + * \note The setting buffer PARAM_KEY_T, which is set by NDIS, is unpacked. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_PARAM_KEY_T prNewKey; + P_CMD_802_11_KEY prCmdKey; + u8 ucCmdSeqNum; + P_BSS_INFO_T prBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + P_STA_RECORD_T prStaRec = NULL; + u8 fgNoHandshakeSec = false; +#if CFG_SUPPORT_TDLS + P_STA_RECORD_T prTmpStaRec; +#endif + + DEBUGFUNC("wlanoidSetAddKey"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + DBGLOG(RSN, INFO, "wlanoidSetAddKey\n"); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(RSN, WARN, + "Fail in set add key! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + prNewKey = (P_PARAM_KEY_T)pvSetBuffer; + + /* Verify the key structure length. */ + if (prNewKey->u4Length > u4SetBufferLen) { + DBGLOG( + RSN, WARN, + "Invalid key structure length (%d) greater than total buffer length " + "(%d)\n", + (u8)prNewKey->u4Length, + (u8)u4SetBufferLen); + + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_LENGTH; + } + + /* Verify the key material length for key material buffer */ + if (prNewKey->u4KeyLength > + prNewKey->u4Length - OFFSET_OF(PARAM_KEY_T, aucKeyMaterial)) { + DBGLOG(RSN, WARN, "Invalid key material length (%d)\n", + (u8)prNewKey->u4KeyLength); + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_INVALID_DATA; + } + + /* Exception check */ + if (prNewKey->u4KeyIndex & 0x0fffff00) { + return WLAN_STATUS_INVALID_DATA; + } + + /* Exception check, pairwise key must with transmit bit enabled */ + if ((prNewKey->u4KeyIndex & BITS(30, 31)) == IS_UNICAST_KEY) { + return WLAN_STATUS_INVALID_DATA; + } + + if (!(prNewKey->u4KeyLength == WEP_40_LEN || + prNewKey->u4KeyLength == WEP_104_LEN || + prNewKey->u4KeyLength == CCMP_KEY_LEN || + prNewKey->u4KeyLength == TKIP_KEY_LEN)) { + return WLAN_STATUS_INVALID_DATA; + } + + /* Exception check, pairwise key must with transmit bit enabled */ + if ((prNewKey->u4KeyIndex & BITS(30, 31)) == BITS(30, 31)) { + if ( /* ((prNewKey->u4KeyIndex & 0xff) != 0) || */ + ((prNewKey->arBSSID[0] == 0xff) && (prNewKey->arBSSID[1] == 0xff) && + (prNewKey->arBSSID[2] == 0xff) && (prNewKey->arBSSID[3] == 0xff) && + (prNewKey->arBSSID[4] == 0xff) && + (prNewKey->arBSSID[5] == 0xff))) { + return WLAN_STATUS_INVALID_DATA; + } + } + + *pu4SetInfoLen = u4SetBufferLen; + + /* Dump PARAM_KEY content. */ + DBGLOG(RSN, INFO, "Set: Dump PARAM_KEY content\n"); + DBGLOG(RSN, INFO, "Length : 0x%08lx\n", prNewKey->u4Length); + DBGLOG(RSN, INFO, "Key Index : 0x%08lx\n", prNewKey->u4KeyIndex); + DBGLOG(RSN, INFO, "Key Length: 0x%08lx\n", prNewKey->u4KeyLength); + DBGLOG(RSN, INFO, "BSSID:\n"); + DBGLOG(RSN, INFO, MACSTR "\n", MAC2STR(prNewKey->arBSSID)); + DBGLOG(RSN, INFO, "Cipher : %d\n", prNewKey->ucCipher); + DBGLOG(RSN, TRACE, "Key RSC:\n"); + DBGLOG_MEM8(RSN, TRACE, &prNewKey->rKeyRSC, sizeof(PARAM_KEY_RSC)); + DBGLOG(RSN, INFO, "Key Material:\n"); + DBGLOG_MEM8(RSN, INFO, prNewKey->aucKeyMaterial, prNewKey->u4KeyLength); + + prGlueInfo = prAdapter->prGlueInfo; + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prNewKey->ucBssIdx); + + if (!prBssInfo) { + DBGLOG(REQ, INFO, "BSS Info not exist !!\n"); + return WLAN_STATUS_SUCCESS; + } + + /* Tx Rx KeyType addr + * STA, GC: + * case1: 1 1 0 BC addr (no sta record of AP at + * this moment) WEP, notice: tx at default key setting WEP key now save + * to BSS_INFO case2: 0 1 0 BSSID (sta record of + * AP) RSN BC key case3: 1 1 1 AP + * addr (sta record of AP) RSN STA key + * + * GO: + * case1: 1 1 0 BSSID (no sta record) WEP + * -- Not support case2: 1 0 0 BSSID (no + * sta record) RSN BC key case3: 1 1 1 STA + * addr STA key + */ + + if (prNewKey->ucCipher == CIPHER_SUITE_WEP40 || + prNewKey->ucCipher == CIPHER_SUITE_WEP104 || + prNewKey->ucCipher == CIPHER_SUITE_WEP128) { + /* check if the key no need handshake, then save to bss wep key + * for global usage */ + fgNoHandshakeSec = true; + } + + if (fgNoHandshakeSec) { +#if DBG + if (IS_BSS_AIS(prBssInfo)) { + if (prAdapter->rWifiVar.rConnSettings.eAuthMode >= AUTH_MODE_WPA && + prAdapter->rWifiVar.rConnSettings.eAuthMode != + AUTH_MODE_WPA_NONE) { + DBGLOG(RSN, WARN, "Set wep at not open/shared setting\n"); + return WLAN_STATUS_SUCCESS; + } + } +#endif + } + + if ((prNewKey->u4KeyIndex & IS_UNICAST_KEY) == IS_UNICAST_KEY) { + prStaRec = cnmGetStaRecByAddress(prAdapter, prBssInfo->ucBssIndex, + prNewKey->arBSSID); + if (!prStaRec) { /* Already disconnected ? */ + DBGLOG(REQ, INFO, "[wlan] Not set the peer key while disconnect\n"); + return WLAN_STATUS_SUCCESS; + } + +#if CFG_SUPPORT_FRAG_ATTACK_DETECTION + /* clear fragment cache when rekey */ + nicRxClearFrag(prAdapter, prStaRec); +#endif + } + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, INFO, "ucCmdSeqNum = %d\n", ucCmdSeqNum); + + /* compose CMD_802_11_KEY cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); +#if CFG_SUPPORT_REPLAY_DETECTION + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetAddKey; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutSetAddKey; +#else + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; +#endif + prCmdInfo->fgIsOid = true; + prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; + prCmdInfo->fgSetQuery = true; + prCmdInfo->fgNeedResp = false; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetBufferLen; + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdKey = (P_CMD_802_11_KEY)(prWifiCmd->aucBuffer); + + kalMemZero(prCmdKey, sizeof(CMD_802_11_KEY)); + + prCmdKey->ucAddRemove = 1; /* Add */ + + prCmdKey->ucTxKey = + ((prNewKey->u4KeyIndex & IS_TRANSMIT_KEY) == IS_TRANSMIT_KEY) ? 1 : 0; + prCmdKey->ucKeyType = + ((prNewKey->u4KeyIndex & IS_UNICAST_KEY) == IS_UNICAST_KEY) ? 1 : 0; + prCmdKey->ucIsAuthenticator = + ((prNewKey->u4KeyIndex & IS_AUTHENTICATOR) == IS_AUTHENTICATOR) ? 1 : 0; + + /* Copy the addr of the key */ + if ((prNewKey->u4KeyIndex & IS_UNICAST_KEY) == IS_UNICAST_KEY) { + if (prStaRec) { + /* Overwrite the fgNoHandshakeSec in case */ + fgNoHandshakeSec = false; /* Legacy 802.1x wep case ? */ + /* ASSERT(false); */ + } + } else { + if (!IS_BSS_ACTIVE(prBssInfo)) { + DBGLOG(REQ, INFO, "[wlan] BSS info (%d) not active yet!", + prNewKey->ucBssIdx); + } + } + + prCmdKey->ucBssIdx = prBssInfo->ucBssIndex; + prCmdKey->ucKeyId = (u8)(prNewKey->u4KeyIndex & 0xff); + + /* Note: the key length may not correct for WPA-None */ + prCmdKey->ucKeyLen = (u8)prNewKey->u4KeyLength; + + kalMemCopy(prCmdKey->aucKeyMaterial, (u8 *)prNewKey->aucKeyMaterial, + prCmdKey->ucKeyLen); + + if (prNewKey->ucCipher) { + prCmdKey->ucAlgorithmId = prNewKey->ucCipher; + if (IS_BSS_AIS(prBssInfo)) { +#if CFG_SUPPORT_802_11W + if (prCmdKey->ucAlgorithmId == CIPHER_SUITE_BIP) { + if (prCmdKey->ucKeyId >= 4) { + P_AIS_SPECIFIC_BSS_INFO_T + prAisSpecBssInfo; + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + prAisSpecBssInfo->fgBipKeyInstalled = true; + DBGLOG(RSN, INFO, "Change BIP BC keyId from %d to 3\n", + prCmdKey->ucKeyId); + /* Set IGTK WTBL keyid 3 for WTBL, + * so hw can search GTK correctly. + */ + prCmdKey->ucKeyId = 3; + } + } +#endif + if ((prCmdKey->ucAlgorithmId == CIPHER_SUITE_CCMP) && + rsnCheckPmkidCandicate(prAdapter)) { + DBGLOG( + RSN, TRACE, + "Add key: Prepare a timer to indicate candidate PMKID Candidate\n"); + cnmTimerStopTimer(prAdapter, + &prAisSpecBssInfo->rPreauthenticationTimer); + cnmTimerStartTimer( + prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer, + SEC_TO_MSEC(WAIT_TIME_IND_PMKID_CANDICATE_SEC)); + } + if (prCmdKey->ucAlgorithmId == CIPHER_SUITE_TKIP) { + /* Todo:: Support AP mode defragment */ + /* for pairwise key only */ + if ((prNewKey->u4KeyIndex & BITS(30, 31)) == + ((IS_UNICAST_KEY) | (IS_TRANSMIT_KEY))) { + kalMemCopy( + prAdapter->rWifiVar.rAisSpecificBssInfo.aucRxMicKey, + &prCmdKey->aucKeyMaterial[16], MIC_KEY_LEN); + kalMemCopy( + prAdapter->rWifiVar.rAisSpecificBssInfo.aucTxMicKey, + &prCmdKey->aucKeyMaterial[24], MIC_KEY_LEN); + } + } + } else { +#if CFG_SUPPORT_802_11W + /* AP PMF */ + if ((prCmdKey->ucKeyId >= 4 && prCmdKey->ucKeyId <= 5) && + (prCmdKey->ucAlgorithmId == CIPHER_SUITE_BIP)) { + DBGLOG(RSN, INFO, "AP mode set BIP\n"); + prBssInfo->rApPmfCfg.fgBipKeyInstalled = true; + } +#endif + } + } + + { +#if CFG_SUPPORT_TDLS + prTmpStaRec = cnmGetStaRecByAddress(prAdapter, prBssInfo->ucBssIndex, + prNewKey->arBSSID); + if (prTmpStaRec) { + if (IS_DLS_STA(prTmpStaRec)) { + prStaRec = prTmpStaRec; + prCmdKey->ucAlgorithmId = + CIPHER_SUITE_CCMP; /*128 ,TODO GCMP 256 + */ + kalMemCopy(prCmdKey->aucPeerAddr, prStaRec->aucMacAddr, + MAC_ADDR_LEN); + } + } +#endif + +#if CFG_SUPPORT_802_11W + /* AP PMF */ + if (prCmdKey->ucAlgorithmId == CIPHER_SUITE_BIP) { + if (prCmdKey->ucIsAuthenticator) { + DBGLOG(RSN, INFO, "Authenticator BIP bssid:%d\n", + prBssInfo->ucBssIndex); + + prCmdKey->ucWlanIndex = secPrivacySeekForBcEntry( + prAdapter, prBssInfo->ucBssIndex, prBssInfo->aucOwnMacAddr, + STA_REC_INDEX_NOT_FOUND, prCmdKey->ucAlgorithmId, + prCmdKey->ucKeyId); + } else { + prCmdKey->ucWlanIndex = secPrivacySeekForBcEntry( + prAdapter, prBssInfo->ucBssIndex, + prBssInfo->prStaRecOfAP->aucMacAddr, + prBssInfo->prStaRecOfAP->ucIndex, prCmdKey->ucAlgorithmId, + prCmdKey->ucKeyId); + kalMemCopy(prCmdKey->aucPeerAddr, + prBssInfo->prStaRecOfAP->aucMacAddr, MAC_ADDR_LEN); + } + + DBGLOG(RSN, INFO, "BIP BC wtbl index:%d\n", prCmdKey->ucWlanIndex); + } else +#endif + if (1) { + if (prStaRec) { + if (prCmdKey->ucKeyType) { /* RSN STA */ + P_WLAN_TABLE_T prWtbl; + + prWtbl = prAdapter->rWifiVar.arWtbl; + prWtbl[prStaRec->ucWlanIndex].ucKeyId = prCmdKey->ucKeyId; + + prCmdKey->ucWlanIndex = prStaRec->ucWlanIndex; + prStaRec->fgTransmitKeyExist = + true; /* wait for CMD Done ? */ + kalMemCopy(prCmdKey->aucPeerAddr, prNewKey->arBSSID, + MAC_ADDR_LEN); +#if CFG_SUPPORT_802_11W + /* AP PMF */ + DBGLOG(RSN, INFO, "Assign client PMF flag = %d\n", + prStaRec->rPmfCfg.fgApplyPmf); + prCmdKey->ucMgmtProtection = prStaRec->rPmfCfg.fgApplyPmf; +#endif + } else { + ASSERT(false); + } + } else { /* Overwrite the old one for AP and STA WEP */ + if (prBssInfo->prStaRecOfAP) { + DBGLOG(RSN, INFO, "AP REC\n"); + prCmdKey->ucWlanIndex = secPrivacySeekForBcEntry( + prAdapter, prBssInfo->ucBssIndex, + prBssInfo->prStaRecOfAP->aucMacAddr, + prBssInfo->prStaRecOfAP->ucIndex, + prCmdKey->ucAlgorithmId, prCmdKey->ucKeyId); + + kalMemCopy(prCmdKey->aucPeerAddr, + prBssInfo->prStaRecOfAP->aucMacAddr, + MAC_ADDR_LEN); + } else { + DBGLOG(RSN, INFO, "!AP && !STA REC\n"); + prCmdKey->ucWlanIndex = secPrivacySeekForBcEntry( + prAdapter, prBssInfo->ucBssIndex, + prBssInfo->aucOwnMacAddr, + /* Should replace by + * BSSID later */ + STA_REC_INDEX_NOT_FOUND, prCmdKey->ucAlgorithmId, + prCmdKey->ucKeyId); + kalMemCopy(prCmdKey->aucPeerAddr, prBssInfo->aucOwnMacAddr, + MAC_ADDR_LEN); + } + + if (fgNoHandshakeSec) { /* WEP: STA and AP */ + prBssInfo->wepkeyWlanIdx = prCmdKey->ucWlanIndex; + prBssInfo->wepkeyUsed[prCmdKey->ucKeyId] = true; + } else if (!prBssInfo->prStaRecOfAP) { /* AP + * WPA/RSN + */ + prBssInfo->ucBMCWlanIndexS[prCmdKey->ucKeyId] = + prCmdKey->ucWlanIndex; + prBssInfo->ucBMCWlanIndexSUsed[prCmdKey->ucKeyId] = true; + } else { /* STA WPA/RSN, should not have tx but + * no sta record */ + prBssInfo->ucBMCWlanIndexS[prCmdKey->ucKeyId] = + prCmdKey->ucWlanIndex; + prBssInfo->ucBMCWlanIndexSUsed[prCmdKey->ucKeyId] = true; + DBGLOG(RSN, INFO, "BMCWlanIndex kid = %d, index = %d\n", + prCmdKey->ucKeyId, prCmdKey->ucWlanIndex); + } + if (prCmdKey->ucTxKey) { /**/ + prBssInfo->fgBcDefaultKeyExist = true; + prBssInfo->ucBcDefaultKeyIdx = prCmdKey->ucKeyId; + } + } + } + } + +#if DBG + DBGLOG(RSN, INFO, "Add key cmd to wlan index %d:", prCmdKey->ucWlanIndex); + DBGLOG(RSN, INFO, "(BSS = %d) " MACSTR "\n", prCmdKey->ucBssIdx, + MAC2STR(prCmdKey->aucPeerAddr)); + DBGLOG(RSN, INFO, "Tx = %d type = %d Auth = %d\n", prCmdKey->ucTxKey, + prCmdKey->ucKeyType, prCmdKey->ucIsAuthenticator); + DBGLOG(RSN, INFO, "cipher = %d keyid = %d keylen = %d\n", + prCmdKey->ucAlgorithmId, prCmdKey->ucKeyId, prCmdKey->ucKeyLen); + DBGLOG_MEM8(RSN, INFO, prCmdKey->aucKeyMaterial, prCmdKey->ucKeyLen); + if (prCmdKey->ucKeyId < MAX_KEY_NUM) { + DBGLOG(RSN, INFO, "wepkeyUsed = %d\n", + prBssInfo->wepkeyUsed[prCmdKey->ucKeyId]); + DBGLOG(RSN, INFO, "wepkeyWlanIdx = %d:", prBssInfo->wepkeyWlanIdx); + DBGLOG(RSN, INFO, "ucBMCWlanIndexSUsed = %d\n", + prBssInfo->ucBMCWlanIndexSUsed[prCmdKey->ucKeyId]); + DBGLOG(RSN, INFO, "ucBMCWlanIndexS = %d:", + prBssInfo->ucBMCWlanIndexS[prCmdKey->ucKeyId]); + } else { + DBGLOG(RSN, WARN, "ucKeyId(%d) oob(%d)", prCmdKey->ucKeyId, + MAX_KEY_NUM); + } +#endif + + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to request the driver to remove the key at + * the specified key index. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_DATA + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRemoveKey(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_PARAM_REMOVE_KEY_T prRemovedKey; + P_CMD_802_11_KEY prCmdKey; + u8 ucCmdSeqNum; + P_WLAN_TABLE_T prWlanTable; + P_STA_RECORD_T prStaRec = NULL; + P_BSS_INFO_T prBssInfo; + /* u8 i = 0; */ + u8 fgRemoveWepKey = false; + u32 ucRemoveBCKeyAtIdx = WTBL_RESERVED_ENTRY; + u32 u4KeyIndex; + u8 fgIsOid = true; + + DEBUGFUNC("wlanoidSetRemoveKey"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + DBGLOG(RSN, INFO, "wlanoidSetRemoveKey\n"); + + *pu4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); + + if (u4SetBufferLen < sizeof(PARAM_REMOVE_KEY_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in set remove key! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pvSetBuffer); + prRemovedKey = (P_PARAM_REMOVE_KEY_T)pvSetBuffer; + + /* Dump PARAM_REMOVE_KEY content. */ + DBGLOG(RSN, INFO, "Set: Dump PARAM_REMOVE_KEY content\n"); + DBGLOG(RSN, INFO, "Length : 0x%08lx\n", prRemovedKey->u4Length); + DBGLOG(RSN, INFO, "Key Index : 0x%08lx\n", prRemovedKey->u4KeyIndex); + DBGLOG(RSN, INFO, "BSS_INDEX : %d\n", prRemovedKey->ucBssIdx); + DBGLOG(RSN, INFO, "BSSID:\n"); + DBGLOG_MEM8(RSN, INFO, prRemovedKey->arBSSID, MAC_ADDR_LEN); + + prGlueInfo = prAdapter->prGlueInfo; + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prRemovedKey->ucBssIdx); + ASSERT(prBssInfo); + + u4KeyIndex = prRemovedKey->u4KeyIndex & 0x000000FF; +#if CFG_SUPPORT_802_11W + ASSERT(u4KeyIndex < MAX_KEY_NUM + 2); +#else + /* ASSERT(prCmdKey->ucKeyId < MAX_KEY_NUM); */ +#endif + + if (u4KeyIndex >= 4) { + DBGLOG(RSN, INFO, "Remove bip key Index : 0x%08lx\n", u4KeyIndex); + return WLAN_STATUS_SUCCESS; + } + + /* Clean up the Tx key flag */ + if (prRemovedKey->u4KeyIndex & IS_UNICAST_KEY) { + prStaRec = cnmGetStaRecByAddress(prAdapter, prRemovedKey->ucBssIdx, + prRemovedKey->arBSSID); + if (!prStaRec) { + return WLAN_STATUS_SUCCESS; + } + } else { + if (u4KeyIndex == prBssInfo->ucBcDefaultKeyIdx) { + prBssInfo->fgBcDefaultKeyExist = false; + } + } + + if (!prStaRec) { + if (prBssInfo->wepkeyUsed[u4KeyIndex] == true) { + fgRemoveWepKey = true; + } + + if (fgRemoveWepKey) { + DBGLOG(RSN, INFO, "Remove wep key id = %d", u4KeyIndex); + prBssInfo->wepkeyUsed[u4KeyIndex] = false; + if (prBssInfo->fgBcDefaultKeyExist && + prBssInfo->ucBcDefaultKeyIdx == u4KeyIndex) { + prBssInfo->fgBcDefaultKeyExist = false; + prBssInfo->ucBcDefaultKeyIdx = 0xff; + } + ASSERT(prBssInfo->wepkeyWlanIdx < WTBL_SIZE); + ucRemoveBCKeyAtIdx = prBssInfo->wepkeyWlanIdx; + } else { + DBGLOG(RSN, INFO, "Remove group key id = %d", u4KeyIndex); + + if (prBssInfo->ucBMCWlanIndexSUsed[u4KeyIndex]) { + if (prBssInfo->fgBcDefaultKeyExist && + prBssInfo->ucBcDefaultKeyIdx == u4KeyIndex) { + prBssInfo->fgBcDefaultKeyExist = false; + prBssInfo->ucBcDefaultKeyIdx = 0xff; + } + if (u4KeyIndex != 0) { + ASSERT(prBssInfo->ucBMCWlanIndexS[u4KeyIndex] < WTBL_SIZE); + } + ucRemoveBCKeyAtIdx = prBssInfo->ucBMCWlanIndexS[u4KeyIndex]; + + prBssInfo->ucBMCWlanIndexSUsed[u4KeyIndex] = false; + prBssInfo->ucBMCWlanIndexS[u4KeyIndex] = WTBL_RESERVED_ENTRY; + } + } + + DBGLOG(RSN, INFO, "ucRemoveBCKeyAtIdx = %d", ucRemoveBCKeyAtIdx); + + if (ucRemoveBCKeyAtIdx >= WTBL_SIZE) { + return WLAN_STATUS_SUCCESS; + } + } + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + (CMD_HDR_SIZE + sizeof(CMD_802_11_KEY))); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + prWlanTable = prAdapter->rWifiVar.arWtbl; + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prRemovedKey->ucBssIdx); + if (prRemovedKey->ucCtrlFlag & FLAG_RM_KEY_CTRL_WO_OID) { + fgIsOid = false; + } + + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* compose CMD_802_11_KEY cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + /* prCmdInfo->ucBssIndex = prRemovedKey->ucBssIdx; */ + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_802_11_KEY); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = fgIsOid; + prCmdInfo->ucCID = CMD_ID_ADD_REMOVE_KEY; + prCmdInfo->fgSetQuery = true; + prCmdInfo->fgNeedResp = false; + /* prCmdInfo->fgDriverDomainMCR = false; */ + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(PARAM_REMOVE_KEY_T); + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdKey = (P_CMD_802_11_KEY)(prWifiCmd->aucBuffer); + + kalMemZero((u8 *)prCmdKey, sizeof(CMD_802_11_KEY)); + + prCmdKey->ucAddRemove = 0; /* Remove */ + prCmdKey->ucKeyId = (u8)u4KeyIndex; + kalMemCopy(prCmdKey->aucPeerAddr, (u8 *)prRemovedKey->arBSSID, + MAC_ADDR_LEN); + prCmdKey->ucBssIdx = prRemovedKey->ucBssIdx; + + if (prStaRec) { + prCmdKey->ucKeyType = 1; + prCmdKey->ucWlanIndex = prStaRec->ucWlanIndex; + prStaRec->fgTransmitKeyExist = false; + } else if (ucRemoveBCKeyAtIdx < WTBL_SIZE) { + prCmdKey->ucWlanIndex = ucRemoveBCKeyAtIdx; + secPrivacyFreeForEntry(prAdapter, ucRemoveBCKeyAtIdx); + } else { + ASSERT(false); + } + + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set the default key + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + * + * \note The setting buffer PARAM_KEY_T, which is set by NDIS, is unpacked. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetDefaultKey(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_PARAM_DEFAULT_KEY_T prDefaultKey; + P_CMD_DEFAULT_KEY prCmdDefaultKey; + u8 ucCmdSeqNum; + P_BSS_INFO_T prBssInfo; + u8 fgSetWepKey = false; + u8 ucWlanIndex = WTBL_RESERVED_ENTRY; + + DEBUGFUNC("wlanoidSetDefaultKey"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in set add key! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + prDefaultKey = (P_PARAM_DEFAULT_KEY_T)pvSetBuffer; + + *pu4SetInfoLen = u4SetBufferLen; + + /* Dump PARAM_DEFAULT_KEY_T content. */ + DBGLOG(RSN, INFO, "Key Index : %d\n", prDefaultKey->ucKeyID); + DBGLOG(RSN, INFO, "Unicast Key : %d\n", prDefaultKey->ucUnicast); + DBGLOG(RSN, INFO, "Multicast Key : %d\n", prDefaultKey->ucMulticast); + + /* prWlanTable = prAdapter->rWifiVar.arWtbl; */ + prGlueInfo = prAdapter->prGlueInfo; + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prDefaultKey->ucBssIdx); + + DBGLOG(RSN, INFO, "WlanIdx = %d\n", prBssInfo->wepkeyWlanIdx); + + if (prDefaultKey->ucMulticast) { + if (!prBssInfo) { + ASSERT(false); + } + if (prBssInfo->prStaRecOfAP) { /* Actually GC not have wep */ + if (prBssInfo->wepkeyUsed[prDefaultKey->ucKeyID]) { + prBssInfo->ucBcDefaultKeyIdx = prDefaultKey->ucKeyID; + prBssInfo->fgBcDefaultKeyExist = true; + ucWlanIndex = prBssInfo->wepkeyWlanIdx; + } else { + DBGLOG(RSN, ERROR, "WPA encryption should retrun"); + return WLAN_STATUS_SUCCESS; + } + } else { /* For AP mode only */ + if (prBssInfo->wepkeyUsed[prDefaultKey->ucKeyID] == true) { + fgSetWepKey = true; + } + + if (fgSetWepKey) { + ucWlanIndex = prBssInfo->wepkeyWlanIdx; + } else { + if (!prBssInfo->ucBMCWlanIndexSUsed[prDefaultKey->ucKeyID]) { + DBGLOG(RSN, ERROR, "Set AP wep default but key not exist!"); + return WLAN_STATUS_SUCCESS; + } + ucWlanIndex = prBssInfo->ucBMCWlanIndexS[prDefaultKey->ucKeyID]; + } + prBssInfo->ucBcDefaultKeyIdx = prDefaultKey->ucKeyID; + prBssInfo->fgBcDefaultKeyExist = true; + } + if (ucWlanIndex > WTBL_SIZE) { + ASSERT(false); + } + } else { + DBGLOG(RSN, ERROR, "Check the case set unicast default key!"); + ASSERT(false); + } + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + (CMD_HDR_SIZE + sizeof(CMD_DEFAULT_KEY))); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, INFO, "ucCmdSeqNum = %d\n", ucCmdSeqNum); + + /* compose CMD_802_11_KEY cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_DEFAULT_KEY); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = true; + prCmdInfo->ucCID = CMD_ID_DEFAULT_KEY_ID; + prCmdInfo->fgSetQuery = true; + prCmdInfo->fgNeedResp = false; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetBufferLen; + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdDefaultKey = (P_CMD_DEFAULT_KEY)(prWifiCmd->aucBuffer); + + kalMemZero(prCmdDefaultKey, sizeof(CMD_DEFAULT_KEY)); + + prCmdDefaultKey->ucBssIdx = prDefaultKey->ucBssIdx; + prCmdDefaultKey->ucKeyId = prDefaultKey->ucKeyID; + prCmdDefaultKey->ucWlanIndex = ucWlanIndex; + prCmdDefaultKey->ucMulticast = prDefaultKey->ucMulticast; + + DBGLOG(RSN, INFO, "CMD_ID_DEFAULT_KEY_ID (%d) with wlan idx = %d\n", + prDefaultKey->ucKeyID, ucWlanIndex); + + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the current encryption status. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryEncryptionStatus(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + u8 fgTransmitKeyAvailable = true; + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus = 0; + + DEBUGFUNC("wlanoidQueryEncryptionStatus"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T); + + fgTransmitKeyAvailable = prAdapter->prAisBssInfo->fgBcDefaultKeyExist; + + switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) { + case ENUM_ENCRYPTION3_ENABLED: + if (fgTransmitKeyAvailable) { + eEncStatus = ENUM_ENCRYPTION3_ENABLED; + } else { + eEncStatus = ENUM_ENCRYPTION3_KEY_ABSENT; + } + break; + + case ENUM_ENCRYPTION2_ENABLED: + if (fgTransmitKeyAvailable) { + eEncStatus = ENUM_ENCRYPTION2_ENABLED; + break; + } + eEncStatus = ENUM_ENCRYPTION2_KEY_ABSENT; + break; + + case ENUM_ENCRYPTION1_ENABLED: + if (fgTransmitKeyAvailable) { + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + } else { + eEncStatus = ENUM_ENCRYPTION1_KEY_ABSENT; + } + break; + + case ENUM_ENCRYPTION_DISABLED: + eEncStatus = ENUM_ENCRYPTION_DISABLED; + break; + + default: + DBGLOG(REQ, ERROR, "Unknown Encryption Status Setting:%d\n", + prAdapter->rWifiVar.rConnSettings.eEncStatus); + } + +#if DBG + DBGLOG(REQ, INFO, "Encryption status: %d Return:%d\n", + prAdapter->rWifiVar.rConnSettings.eEncStatus, eEncStatus); +#endif + + *(P_ENUM_PARAM_ENCRYPTION_STATUS_T)pvQueryBuffer = eEncStatus; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set the encryption status to the driver. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_NOT_SUPPORTED + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetEncryptionStatus(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + ENUM_PARAM_ENCRYPTION_STATUS_T eEewEncrypt; + + DEBUGFUNC("wlanoidSetEncryptionStatus"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + prGlueInfo = prAdapter->prGlueInfo; + + *pu4SetInfoLen = sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T); + + /* if (IS_ARB_IN_RFTEST_STATE(prAdapter)) { */ + /* return WLAN_STATUS_SUCCESS; */ + /* } */ + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in set encryption status! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + eEewEncrypt = *(P_ENUM_PARAM_ENCRYPTION_STATUS_T)pvSetBuffer; + DBGLOG(REQ, INFO, "ENCRYPTION_STATUS %d\n", eEewEncrypt); + + switch (eEewEncrypt) { + case ENUM_ENCRYPTION_DISABLED: /* Disable WEP, TKIP, AES */ + DBGLOG(RSN, INFO, "Disable Encryption\n"); + secSetCipherSuite(prAdapter, CIPHER_FLAG_WEP40 | CIPHER_FLAG_WEP104 | + CIPHER_FLAG_WEP128); + break; + + case ENUM_ENCRYPTION1_ENABLED: /* Enable WEP. Disable TKIP, AES */ + DBGLOG(RSN, INFO, "Enable Encryption1\n"); + secSetCipherSuite(prAdapter, CIPHER_FLAG_WEP40 | CIPHER_FLAG_WEP104 | + CIPHER_FLAG_WEP128); + break; + + case ENUM_ENCRYPTION2_ENABLED: /* Enable WEP, TKIP. Disable AES */ + secSetCipherSuite(prAdapter, CIPHER_FLAG_WEP40 | CIPHER_FLAG_WEP104 | + CIPHER_FLAG_WEP128 | CIPHER_FLAG_TKIP); + DBGLOG(RSN, INFO, "Enable Encryption2\n"); + break; + + case ENUM_ENCRYPTION3_ENABLED: /* Enable WEP, TKIP, AES */ + secSetCipherSuite(prAdapter, CIPHER_FLAG_WEP40 | CIPHER_FLAG_WEP104 | + CIPHER_FLAG_WEP128 | CIPHER_FLAG_TKIP | + CIPHER_FLAG_CCMP); + DBGLOG(RSN, INFO, "Enable Encryption3\n"); + break; + +#if CFG_SUPPORT_SUITB + case ENUM_ENCRYPTION4_ENABLED: /* Eanble GCMP256 */ + secSetCipherSuite(prAdapter, CIPHER_FLAG_GCMP256); + DBGLOG(RSN, INFO, "Enable Encryption4\n"); + break; +#endif + + default: + DBGLOG(RSN, INFO, "Unacceptible encryption status: %d\n", + *(P_ENUM_PARAM_ENCRYPTION_STATUS_T)pvSetBuffer); + + rStatus = WLAN_STATUS_NOT_SUPPORTED; + } + + if (rStatus == WLAN_STATUS_SUCCESS) { + /* Save the new encryption status. */ + prAdapter->rWifiVar.rConnSettings.eEncStatus = + *(P_ENUM_PARAM_ENCRYPTION_STATUS_T)pvSetBuffer; + } + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to test the driver. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetTest(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_802_11_TEST_T prTest; + void *pvTestData; + void *pvStatusBuffer; + u32 u4StatusBufferSize; + + DEBUGFUNC("wlanoidSetTest"); + + ASSERT(prAdapter); + + ASSERT(pu4SetInfoLen); + ASSERT(pvSetBuffer); + + *pu4SetInfoLen = u4SetBufferLen; + + prTest = (P_PARAM_802_11_TEST_T)pvSetBuffer; + + DBGLOG(REQ, TRACE, "Test - Type %ld\n", prTest->u4Type); + + switch (prTest->u4Type) { + case 1: /* Type 1: generate an authentication event */ + pvTestData = (void *)&prTest->u.AuthenticationEvent; + pvStatusBuffer = (void *)prAdapter->aucIndicationEventBuffer; + u4StatusBufferSize = prTest->u4Length - 8; + if (u4StatusBufferSize > sizeof(prTest->u.AuthenticationEvent)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + break; + + case 2: /* Type 2: generate an RSSI status indication */ + pvTestData = (void *)&prTest->u.RssiTrigger; + pvStatusBuffer = (void *)&prAdapter->rWlanInfo.rCurrBssId.rRssi; + u4StatusBufferSize = sizeof(PARAM_RSSI); + break; + + default: + return WLAN_STATUS_INVALID_DATA; + } + + /* Get the contents of the StatusBuffer from the test structure. */ + kalMemCopy(pvStatusBuffer, pvTestData, u4StatusBufferSize); + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + pvStatusBuffer, u4StatusBufferSize); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the driver's WPA2 status. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryCapability(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_CAPABILITY_T prCap; + P_PARAM_AUTH_ENCRYPTION_T prAuthenticationEncryptionSupported; + + DEBUGFUNC("wlanoidQueryCapability"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = 4 * sizeof(u32) + 14 * sizeof(PARAM_AUTH_ENCRYPTION_T); + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prCap = (P_PARAM_CAPABILITY_T)pvQueryBuffer; + + prCap->u4Length = *pu4QueryInfoLen; + prCap->u4Version = 2; /* WPA2 */ + prCap->u4NoOfPMKIDs = CFG_MAX_PMKID_CACHE; + prCap->u4NoOfAuthEncryptPairsSupported = 14; + + prAuthenticationEncryptionSupported = + &prCap->arAuthenticationEncryptionSupported[0]; + + /* fill 14 entries of supported settings */ + prAuthenticationEncryptionSupported[0].eAuthModeSupported = AUTH_MODE_OPEN; + + prAuthenticationEncryptionSupported[0].eEncryptStatusSupported = + ENUM_ENCRYPTION_DISABLED; + + prAuthenticationEncryptionSupported[1].eAuthModeSupported = AUTH_MODE_OPEN; + prAuthenticationEncryptionSupported[1].eEncryptStatusSupported = + ENUM_ENCRYPTION1_ENABLED; + + prAuthenticationEncryptionSupported[2].eAuthModeSupported = + AUTH_MODE_SHARED; + prAuthenticationEncryptionSupported[2].eEncryptStatusSupported = + ENUM_ENCRYPTION_DISABLED; + + prAuthenticationEncryptionSupported[3].eAuthModeSupported = + AUTH_MODE_SHARED; + prAuthenticationEncryptionSupported[3].eEncryptStatusSupported = + ENUM_ENCRYPTION1_ENABLED; + + prAuthenticationEncryptionSupported[4].eAuthModeSupported = AUTH_MODE_WPA; + prAuthenticationEncryptionSupported[4].eEncryptStatusSupported = + ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[5].eAuthModeSupported = AUTH_MODE_WPA; + prAuthenticationEncryptionSupported[5].eEncryptStatusSupported = + ENUM_ENCRYPTION3_ENABLED; + + prAuthenticationEncryptionSupported[6].eAuthModeSupported = + AUTH_MODE_WPA_PSK; + prAuthenticationEncryptionSupported[6].eEncryptStatusSupported = + ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[7].eAuthModeSupported = + AUTH_MODE_WPA_PSK; + prAuthenticationEncryptionSupported[7].eEncryptStatusSupported = + ENUM_ENCRYPTION3_ENABLED; + + prAuthenticationEncryptionSupported[8].eAuthModeSupported = + AUTH_MODE_WPA_NONE; + prAuthenticationEncryptionSupported[8].eEncryptStatusSupported = + ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[9].eAuthModeSupported = + AUTH_MODE_WPA_NONE; + prAuthenticationEncryptionSupported[9].eEncryptStatusSupported = + ENUM_ENCRYPTION3_ENABLED; + + prAuthenticationEncryptionSupported[10].eAuthModeSupported = AUTH_MODE_WPA2; + prAuthenticationEncryptionSupported[10].eEncryptStatusSupported = + ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[11].eAuthModeSupported = AUTH_MODE_WPA2; + prAuthenticationEncryptionSupported[11].eEncryptStatusSupported = + ENUM_ENCRYPTION3_ENABLED; + + prAuthenticationEncryptionSupported[12].eAuthModeSupported = + AUTH_MODE_WPA2_PSK; + prAuthenticationEncryptionSupported[12].eEncryptStatusSupported = + ENUM_ENCRYPTION2_ENABLED; + + prAuthenticationEncryptionSupported[13].eAuthModeSupported = + AUTH_MODE_WPA2_PSK; + prAuthenticationEncryptionSupported[13].eEncryptStatusSupported = + ENUM_ENCRYPTION3_ENABLED; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the PMKID in the PMK cache. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryPmkid(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + u32 i; + P_PARAM_PMKID_T prPmkid; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("wlanoidQueryPmkid"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + *pu4QueryInfoLen = + OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo) + + prAisSpecBssInfo->u4PmkidCacheCount * sizeof(PARAM_BSSID_INFO_T); + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prPmkid = (P_PARAM_PMKID_T)pvQueryBuffer; + + prPmkid->u4Length = *pu4QueryInfoLen; + prPmkid->u4BSSIDInfoCount = prAisSpecBssInfo->u4PmkidCacheCount; + + for (i = 0; i < prAisSpecBssInfo->u4PmkidCacheCount; i++) { + kalMemCopy(prPmkid->arBSSIDInfo[i].arBSSID, + prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arBSSID, + sizeof(PARAM_MAC_ADDRESS)); + kalMemCopy(prPmkid->arBSSIDInfo[i].arPMKID, + prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arPMKID, + sizeof(PARAM_PMKID_VALUE)); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set the PMKID to the PMK cache in the + * driver. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + * \retval WLAN_STATUS_INVALID_DATA + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetPmkid(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + u32 i, j; + P_PARAM_PMKID_T prPmkid; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("wlanoidSetPmkid"); + + DBGLOG(REQ, INFO, "wlanoidSetPmkid\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = u4SetBufferLen; + + /* It's possibble BSSIDInfoCount is zero, because OS wishes to clean + * PMKID */ + if (u4SetBufferLen < OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + ASSERT(pvSetBuffer); + prPmkid = (P_PARAM_PMKID_T)pvSetBuffer; + + if (u4SetBufferLen < + ((prPmkid->u4BSSIDInfoCount * sizeof(PARAM_BSSID_INFO_T)) + + OFFSET_OF(PARAM_PMKID_T, arBSSIDInfo))) { + return WLAN_STATUS_INVALID_DATA; + } + + if (prPmkid->u4BSSIDInfoCount > CFG_MAX_PMKID_CACHE) { + return WLAN_STATUS_INVALID_DATA; + } + + DBGLOG(REQ, INFO, "Count %lu\n", prPmkid->u4BSSIDInfoCount); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + /* This OID replace everything in the PMKID cache. */ + if (prPmkid->u4BSSIDInfoCount == 0) { + prAisSpecBssInfo->u4PmkidCacheCount = 0; + kalMemZero(prAisSpecBssInfo->arPmkidCache, + sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); + } + if ((prAisSpecBssInfo->u4PmkidCacheCount + prPmkid->u4BSSIDInfoCount > + CFG_MAX_PMKID_CACHE)) { + prAisSpecBssInfo->u4PmkidCacheCount = 0; + kalMemZero(prAisSpecBssInfo->arPmkidCache, + sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); + } + + /* + * The driver can only clear its PMKID cache whenever it make a media + * disconnect indication. Otherwise, it must change the PMKID cache only + * when set through this OID. + */ + for (i = 0; i < prPmkid->u4BSSIDInfoCount; i++) { + /* Search for desired BSSID. If desired BSSID is found, + * then set the PMKID + */ + if (!rsnSearchPmkidEntry(prAdapter, + (u8 *)prPmkid->arBSSIDInfo[i].arBSSID, &j)) { + /* No entry found for the specified BSSID, so add one + * entry */ + if (prAisSpecBssInfo->u4PmkidCacheCount < CFG_MAX_PMKID_CACHE - 1) { + j = prAisSpecBssInfo->u4PmkidCacheCount; + kalMemCopy(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, + prPmkid->arBSSIDInfo[i].arBSSID, + sizeof(PARAM_MAC_ADDRESS)); + prAisSpecBssInfo->u4PmkidCacheCount++; + } else { + j = CFG_MAX_PMKID_CACHE; + } + } + + if (j < CFG_MAX_PMKID_CACHE) { + kalMemCopy(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arPMKID, + prPmkid->arBSSIDInfo[i].arPMKID, + sizeof(PARAM_PMKID_VALUE)); + DBGLOG( + RSN, TRACE, + "Add BSSID " MACSTR " idx=%lu PMKID value " MACSTR "\n", + MAC2STR(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID), + j, + MAC2STR(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arPMKID)); + prAisSpecBssInfo->arPmkidCache[j].fgPmkidExist = true; + } + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the set of supported data rates that + * the radio is capable of running + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query + * \param[in] u4QueryBufferLen The length of the query buffer + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the + * call failed due to invalid length of the query + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuerySupportedRates(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + PARAM_RATES eRate = { + /* BSSBasicRateSet for 802.11n Non-HT rates */ + 0x8C, /* 6M */ + 0x92, /* 9M */ + 0x98, /* 12M */ + 0xA4, /* 18M */ + 0xB0, /* 24M */ + 0xC8, /* 36M */ + 0xE0, /* 48M */ + 0xEC /* 54M */ + }; + + DEBUGFUNC("wlanoidQuerySupportedRates"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_RATES_EX); + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(REQ, WARN, "Invalid length %ld\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + kalMemCopy(pvQueryBuffer, (void *)&eRate, sizeof(PARAM_RATES)); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query current desired rates. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryDesiredRates(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryDesiredRates"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_RATES_EX); + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(REQ, WARN, "Invalid length %ld\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + kalMemCopy(pvQueryBuffer, (void *)&(prAdapter->rWlanInfo.eDesiredRates), + sizeof(PARAM_RATES)); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set the desired rates. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetDesiredRates(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + u32 i; + + DEBUGFUNC("wlanoidSetDesiredRates"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(PARAM_RATES)) { + DBGLOG(REQ, WARN, "Invalid length %ld\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = sizeof(PARAM_RATES); + + if (u4SetBufferLen < sizeof(PARAM_RATES)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + kalMemCopy((void *)&(prAdapter->rWlanInfo.eDesiredRates), pvSetBuffer, + sizeof(PARAM_RATES)); + + prAdapter->rWlanInfo.eLinkAttr.ucDesiredRateLen = PARAM_MAX_LEN_RATES; + for (i = 0; i < PARAM_MAX_LEN_RATES; i++) + prAdapter->rWlanInfo.eLinkAttr.u2DesiredRate[i] = + (u16)(prAdapter->rWlanInfo.eDesiredRates[i]); + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_LINK_ATTRIB, true, false, true, + nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + sizeof(CMD_LINK_ATTRIB), + (u8 *)&(prAdapter->rWlanInfo.eLinkAttr), + pvSetBuffer, u4SetBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the maximum frame size in bytes, + * not including the header. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the + * call failed due to invalid length of the query + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMaxFrameSize(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryMaxFrameSize"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < sizeof(u32)) { + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_INVALID_LENGTH; + } + + *(u32 *)pvQueryBuffer = ETHERNET_MAX_PKT_SZ - ETHERNET_HEADER_SZ; + *pu4QueryInfoLen = sizeof(u32); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the maximum total packet length + * in bytes. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMaxTotalSize(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryMaxTotalSize"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < sizeof(u32)) { + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_INVALID_LENGTH; + } + + *(u32 *)pvQueryBuffer = ETHERNET_MAX_PKT_SZ; + *pu4QueryInfoLen = sizeof(u32); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the vendor ID of the NIC. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryVendorId(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ +#if DBG + u8 *cp; +#endif + DEBUGFUNC("wlanoidQueryVendorId"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < sizeof(u32)) { + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_INVALID_LENGTH; + } + + kalMemCopy(pvQueryBuffer, prAdapter->aucMacAddress, 3); + *((u8 *)pvQueryBuffer + 3) = 1; + *pu4QueryInfoLen = sizeof(u32); + +#if DBG + cp = (u8 *)pvQueryBuffer; + DBGLOG(REQ, LOUD, "Vendor ID=%02x-%02x-%02x-%02x\n", cp[0], cp[1], cp[2], + cp[3]); +#endif + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the current RSSI value. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of the + * query. \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRssi(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRssi"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (prAdapter->fgIsEnableLpdvt) { + return WLAN_STATUS_NOT_SUPPORTED; + } + + *pu4QueryInfoLen = sizeof(PARAM_RSSI); + + /* Check for query buffer length */ + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(REQ, WARN, "Too short length %ld\n", u4QueryBufferLen); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == + PARAM_MEDIA_STATE_DISCONNECTED) { + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (prAdapter->fgIsLinkQualityValid == true && + (kalGetTimeTick() - prAdapter->rLinkQualityUpdateTime) <= + CFG_LINK_QUALITY_VALID_PERIOD) { + PARAM_RSSI rRssi; + + rRssi = (PARAM_RSSI)prAdapter->rLinkQuality.cRssi; /* ranged + * from (-128 + * ~ 30) in + * unit of + * dBm */ + + if (rRssi > PARAM_WHQL_RSSI_MAX_DBM) { + rRssi = PARAM_WHQL_RSSI_MAX_DBM; + } else if (rRssi < PARAM_WHQL_RSSI_MIN_DBM) { + rRssi = PARAM_WHQL_RSSI_MIN_DBM; + } + + kalMemCopy(pvQueryBuffer, &rRssi, sizeof(PARAM_RSSI)); + return WLAN_STATUS_SUCCESS; + } + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_LINK_QUALITY, false, true, + true, nicCmdEventQueryLinkQuality, + nicOidCmdTimeoutCommon, *pu4QueryInfoLen, + pvQueryBuffer, pvQueryBuffer, u4QueryBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the current RSSI trigger value. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of the + * query. \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRssiTrigger(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRssiTrigger"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (prAdapter->rWlanInfo.eRssiTriggerType == ENUM_RSSI_TRIGGER_NONE) { + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + *pu4QueryInfoLen = sizeof(PARAM_RSSI); + + /* Check for query buffer length */ + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(REQ, WARN, "Too short length %ld\n", u4QueryBufferLen); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + *(PARAM_RSSI *)pvQueryBuffer = prAdapter->rWlanInfo.rRssiTriggerValue; + DBGLOG(REQ, INFO, "RSSI trigger: %ld dBm\n", *(PARAM_RSSI *)pvQueryBuffer); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set a trigger value of the RSSI event. + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns the + * amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRssiTrigger(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + PARAM_RSSI rRssiTriggerValue; + + DEBUGFUNC("wlanoidSetRssiTrigger"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_RSSI); + rRssiTriggerValue = *(PARAM_RSSI *)pvSetBuffer; + + if (rRssiTriggerValue > PARAM_WHQL_RSSI_MAX_DBM || + rRssiTriggerValue < PARAM_WHQL_RSSI_MIN_DBM) { + return + /* Save the RSSI trigger value to the Adapter structure + */ + prAdapter->rWlanInfo.rRssiTriggerValue = rRssiTriggerValue; + } + + /* If the RSSI trigger value is equal to the current RSSI value, the + * indication triggers immediately. We need to indicate the protocol + * that an RSSI status indication event triggers. + */ + if (rRssiTriggerValue == (PARAM_RSSI)(prAdapter->rLinkQuality.cRssi)) { + prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_TRIGGERED; + + kalIndicateStatusAndComplete( + prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (void *)&prAdapter->rWlanInfo.rRssiTriggerValue, + sizeof(PARAM_RSSI)); + } else if (rRssiTriggerValue < + (PARAM_RSSI)(prAdapter->rLinkQuality.cRssi)) { + prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_GREATER; + } else if (rRssiTriggerValue > + (PARAM_RSSI)(prAdapter->rLinkQuality.cRssi)) { + prAdapter->rWlanInfo.eRssiTriggerType = ENUM_RSSI_TRIGGER_LESS; + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set a suggested value for the number of + * bytes of received packet data that will be indicated to the protocol + * driver. We just accept the set and ignore this value. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCurrentLookahead(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + DEBUGFUNC("wlanoidSetCurrentLookahead"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(u32)) { + *pu4SetInfoLen = sizeof(u32); + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = sizeof(u32); + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the number of frames that the driver + * receives but does not indicate to the protocols due to errors. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRcvError(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRcvError"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(u32) || + (u4QueryBufferLen > sizeof(u32) && + u4QueryBufferLen < sizeof(u64))) { + *pu4QueryInfoLen = sizeof(u64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == true) { + /* @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT is not + * calculated */ + if (u4QueryBufferLen == sizeof(u32)) { + *pu4QueryInfoLen = sizeof(u32); + *(u32 *)pvQueryBuffer = + (u32)prAdapter->rStatStruct.rFCSErrorCount.QuadPart; + } else { + *pu4QueryInfoLen = sizeof(u64); + *(u64 *)pvQueryBuffer = + (u64)prAdapter->rStatStruct.rFCSErrorCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_STATISTICS, false, true, + true, nicCmdEventQueryRecvError, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, + u4QueryBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the number of frames that the NIC + * cannot receive due to lack of NIC receive buffer space. + * + * \param[in] pvAdapter Pointer to the Adapter structure + * \param[in] pvQueryBuf A pointer to the buffer that holds the result of the + * query buffer + * \param[in] u4QueryBufLen The length of the query buffer + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS If success; + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRcvNoBuffer(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRcvNoBuffer"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(u32) || + (u4QueryBufferLen > sizeof(u32) && + u4QueryBufferLen < sizeof(u64))) { + *pu4QueryInfoLen = sizeof(u64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == true) { + if (u4QueryBufferLen == sizeof(u32)) { + *pu4QueryInfoLen = sizeof(u32); + *(u32 *)pvQueryBuffer = (u32)0; /* @FIXME */ + } else { + *pu4QueryInfoLen = sizeof(u64); + *(u64 *)pvQueryBuffer = (u64)0; /* @FIXME */ + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_STATISTICS, false, true, + true, nicCmdEventQueryRecvNoBuffer, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, + u4QueryBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the number of frames that the NIC + * received and it is CRC error. + * + * \param[in] pvAdapter Pointer to the Adapter structure + * \param[in] pvQueryBuf A pointer to the buffer that holds the result of the + * query buffer + * \param[in] u4QueryBufLen The length of the query buffer + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS If success; + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRcvCrcError(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRcvCrcError"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(u32) || + (u4QueryBufferLen > sizeof(u32) && + u4QueryBufferLen < sizeof(u64))) { + *pu4QueryInfoLen = sizeof(u64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == true) { + if (u4QueryBufferLen == sizeof(u32)) { + *pu4QueryInfoLen = sizeof(u32); + *(u32 *)pvQueryBuffer = + (u32)prAdapter->rStatStruct.rFCSErrorCount.QuadPart; + } else { + *pu4QueryInfoLen = sizeof(u64); + *(u64 *)pvQueryBuffer = + (u64)prAdapter->rStatStruct.rFCSErrorCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_STATISTICS, false, true, + true, nicCmdEventQueryRecvCrcError, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, + u4QueryBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the current 802.11 statistics. + * + * \param[in] pvAdapter Pointer to the Adapter structure + * \param[in] pvQueryBuf A pointer to the buffer that holds the result of the + * query buffer + * \param[in] u4QueryBufLen The length of the query buffer + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryStatistics(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + PARAM_802_11_STATISTICS_STRUCT_T rStatistics; + + DEBUGFUNC("wlanoidQueryStatistics"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(PARAM_802_11_STATISTICS_STRUCT_T)) { + DBGLOG(REQ, WARN, "Too short length %ld\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == true) { + P_PARAM_802_11_STATISTICS_STRUCT_T prStatistics; + + *pu4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics = (P_PARAM_802_11_STATISTICS_STRUCT_T)pvQueryBuffer; + + prStatistics->u4Length = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics->rTransmittedFragmentCount = + prAdapter->rStatStruct.rTransmittedFragmentCount; + prStatistics->rMulticastTransmittedFrameCount = + prAdapter->rStatStruct.rMulticastTransmittedFrameCount; + prStatistics->rFailedCount = prAdapter->rStatStruct.rFailedCount; + prStatistics->rRetryCount = prAdapter->rStatStruct.rRetryCount; + prStatistics->rMultipleRetryCount = + prAdapter->rStatStruct.rMultipleRetryCount; + prStatistics->rRTSSuccessCount = + prAdapter->rStatStruct.rRTSSuccessCount; + prStatistics->rRTSFailureCount = + prAdapter->rStatStruct.rRTSFailureCount; + prStatistics->rACKFailureCount = + prAdapter->rStatStruct.rACKFailureCount; + prStatistics->rFrameDuplicateCount = + prAdapter->rStatStruct.rFrameDuplicateCount; + prStatistics->rReceivedFragmentCount = + prAdapter->rStatStruct.rReceivedFragmentCount; + prStatistics->rMulticastReceivedFrameCount = + prAdapter->rStatStruct.rMulticastReceivedFrameCount; + prStatistics->rFCSErrorCount = prAdapter->rStatStruct.rFCSErrorCount; + prStatistics->rTKIPLocalMICFailures.QuadPart = 0; + prStatistics->rTKIPICVErrors.QuadPart = 0; + prStatistics->rTKIPCounterMeasuresInvoked.QuadPart = 0; + prStatistics->rTKIPReplays.QuadPart = 0; + prStatistics->rCCMPFormatErrors.QuadPart = 0; + prStatistics->rCCMPReplays.QuadPart = 0; + prStatistics->rCCMPDecryptErrors.QuadPart = 0; + prStatistics->rFourWayHandshakeFailures.QuadPart = 0; + prStatistics->rWEPUndecryptableCount.QuadPart = 0; + prStatistics->rWEPICVErrorCount.QuadPart = 0; + prStatistics->rDecryptSuccessCount.QuadPart = 0; + prStatistics->rDecryptFailureCount.QuadPart = 0; + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_STATISTICS, false, true, + true, nicCmdEventQueryStatistics, + nicOidCmdTimeoutCommon, + sizeof(PARAM_802_11_STATISTICS_STRUCT_T), + (u8 *)&rStatistics, pvQueryBuffer, + u4QueryBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query current media streaming status. + * + * \param[in] pvAdapter Pointer to the Adapter structure + * \param[in] pvQueryBuf A pointer to the buffer that holds the result of the + * query buffer + * \param[in] u4QueryBufLen The length of the query buffer + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMediaStreamMode(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryMediaStreamMode"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(ENUM_MEDIA_STREAM_MODE); + + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(REQ, WARN, "Invalid length %ld\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + *(P_ENUM_MEDIA_STREAM_MODE)pvQueryBuffer = + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode == 0 ? + ENUM_MEDIA_STREAM_OFF : + ENUM_MEDIA_STREAM_ON; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to enter media streaming mode or exit media + * streaming mode + * + * \param[in] pvAdapter Pointer to the Adapter structure + * \param[in] pvQueryBuf A pointer to the buffer that holds the result of the + * query buffer + * \param[in] u4QueryBufLen The length of the query buffer + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetMediaStreamMode(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + ENUM_MEDIA_STREAM_MODE eStreamMode; + + DEBUGFUNC("wlanoidSetMediaStreamMode"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(ENUM_MEDIA_STREAM_MODE)) { + DBGLOG(REQ, WARN, "Invalid length %ld\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = sizeof(ENUM_MEDIA_STREAM_MODE); + + eStreamMode = *(P_ENUM_MEDIA_STREAM_MODE)pvSetBuffer; + + if (eStreamMode == ENUM_MEDIA_STREAM_OFF) { + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 0; + } else { + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode = 1; + } + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_LINK_ATTRIB, true, false, true, + nicCmdEventSetMediaStreamMode, + nicOidCmdTimeoutCommon, sizeof(CMD_LINK_ATTRIB), + (u8 *)&(prAdapter->rWlanInfo.eLinkAttr), + pvSetBuffer, u4SetBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the permanent MAC address of the + * NIC. + * + * \param[in] pvAdapter Pointer to the Adapter structure + * \param[in] pvQueryBuf A pointer to the buffer that holds the result of the + * query buffer + * \param[in] u4QueryBufLen The length of the query buffer + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryPermanentAddr(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryPermanentAddr"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < MAC_ADDR_LEN) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + COPY_MAC_ADDR(pvQueryBuffer, prAdapter->rWifiVar.aucPermanentAddress); + *pu4QueryInfoLen = MAC_ADDR_LEN; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query the MAC address the NIC is currently + * using. + * + * \param[in] pvAdapter Pointer to the Adapter structure + * \param[in] pvQueryBuf A pointer to the buffer that holds the result of the + * query buffer + * \param[in] u4QueryBufLen The length of the query buffer + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryCurrentAddr(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryCurrentAddr"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < MAC_ADDR_LEN) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + COPY_MAC_ADDR(pvQueryBuffer, prAdapter->rWifiVar.aucMacAddress); + *pu4QueryInfoLen = MAC_ADDR_LEN; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to query NIC link speed. + * + * \param[in] pvAdapter Pointer to the Adapter structure + * \param[in] pvQueryBuf A pointer to the buffer that holds the result of the + * query buffer + * \param[in] u4QueryBufLen The length of the query buffer + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryLinkSpeed(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryLinkSpeed"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (prAdapter->fgIsEnableLpdvt) { + return WLAN_STATUS_NOT_SUPPORTED; + } + + *pu4QueryInfoLen = sizeof(u32); + + if (u4QueryBufferLen < sizeof(u32)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != + PARAM_MEDIA_STATE_CONNECTED) { + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (prAdapter->fgIsLinkRateValid == true && + (kalGetTimeTick() - prAdapter->rLinkRateUpdateTime) <= + CFG_LINK_QUALITY_VALID_PERIOD) { + *(u32 *)pvQueryBuffer = prAdapter->rLinkQuality.u2LinkSpeed * + 5000; /* change to unit of 100bps */ + return WLAN_STATUS_SUCCESS; + } else { + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_LINK_QUALITY, false, + true, true, nicCmdEventQueryLinkSpeed, + nicOidCmdTimeoutCommon, 0, NULL, + pvQueryBuffer, u4QueryBufferLen); + } +} + +#if CFG_SUPPORT_QA_TOOL +#if CFG_SUPPORT_BUFFER_MODE +WLAN_STATUS +wlanoidSetEfusBufferMode(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_EFUSE_BUFFER_MODE_T prSetEfuseBufModeInfo; + CMD_EFUSE_BUFFER_MODE_T *prCmdSetEfuseBufModeInfo = NULL; + PFN_CMD_DONE_HANDLER pfCmdDoneHandler; + u32 u4EfuseContentSize, u4QueryInfoLen; + u8 fgSetQuery, fgNeedResp; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidSetEfusBufferMode"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + ASSERT(pvSetBuffer); + + /* get the buffer mode info */ + prSetEfuseBufModeInfo = (P_PARAM_CUSTOM_EFUSE_BUFFER_MODE_T)pvSetBuffer; + + /* copy command header */ + prCmdSetEfuseBufModeInfo = (CMD_EFUSE_BUFFER_MODE_T *)kalMemAlloc( + sizeof(CMD_EFUSE_BUFFER_MODE_T), VIR_MEM_TYPE); + if (prCmdSetEfuseBufModeInfo == NULL) { + return WLAN_STATUS_FAILURE; + } + + kalMemZero(prCmdSetEfuseBufModeInfo, sizeof(CMD_EFUSE_BUFFER_MODE_T)); + prCmdSetEfuseBufModeInfo->ucSourceMode = + prSetEfuseBufModeInfo->ucSourceMode; + prCmdSetEfuseBufModeInfo->ucCount = prSetEfuseBufModeInfo->ucCount; + prCmdSetEfuseBufModeInfo->ucCmdType = prSetEfuseBufModeInfo->ucCmdType; + prCmdSetEfuseBufModeInfo->ucReserved = prSetEfuseBufModeInfo->ucReserved; + +#if (CFG_FW_Report_Efuse_Address == 1) + DBGLOG(INIT, STATE, "u4EfuseEndAddress %x u4EfuseStartAddress %x\n", + prAdapter->u4EfuseEndAddress, prAdapter->u4EfuseStartAddress); + + if (prAdapter->u4EfuseEndAddress < prAdapter->u4EfuseStartAddress) { + DBGLOG(INIT, ERROR, "invalid u4EfuseAddress!!\n"); + kalMemFree(prCmdSetEfuseBufModeInfo, VIR_MEM_TYPE, + sizeof(CMD_EFUSE_BUFFER_MODE_T)); + return WLAN_STATUS_INVALID_LENGTH; + } + u4EfuseContentSize = + (prAdapter->u4EfuseEndAddress) - (prAdapter->u4EfuseStartAddress) + 1; +#else + u4EfuseContentSize = EFUSE_CONTENT_BUFFER_SIZE; +#endif + pfCmdDoneHandler = NULL; + fgSetQuery = false; + fgNeedResp = true; + + u4QueryInfoLen = + OFFSET_OF(CMD_EFUSE_BUFFER_MODE_T, aBinContent) + u4EfuseContentSize; + + if (u4SetBufferLen < u4QueryInfoLen) { + DBGLOG(INIT, ERROR, "invalid u4SetBufferLen %d u4QueryInfoLen %d!!\n", + u4SetBufferLen, u4QueryInfoLen); + kalMemFree(prCmdSetEfuseBufModeInfo, VIR_MEM_TYPE, + sizeof(CMD_EFUSE_BUFFER_MODE_T)); + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = u4QueryInfoLen; + kalMemCopy(prCmdSetEfuseBufModeInfo->aBinContent, + prSetEfuseBufModeInfo->aBinContent, u4EfuseContentSize); + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, EXT_CMD_ID_EFUSE_BUFFER_MODE, + fgSetQuery, fgNeedResp, true, pfCmdDoneHandler, nicOidCmdTimeoutCommon, + u4QueryInfoLen, (u8 *)(prCmdSetEfuseBufModeInfo), pvSetBuffer, + u4SetBufferLen); + + kalMemFree(prCmdSetEfuseBufModeInfo, VIR_MEM_TYPE, + sizeof(CMD_EFUSE_BUFFER_MODE_T)); + + return rWlanStatus; +} + +/*#if (CFG_EEPROM_PAGE_ACCESS == 1)*/ +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to read efuse content. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryProcessAccessEfuseRead(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_ACCESS_EFUSE_T prSetAccessEfuseInfo; + CMD_ACCESS_EFUSE_T rCmdSetAccessEfuse; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQueryProcessAccessEfuseRead"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prSetAccessEfuseInfo = (P_PARAM_CUSTOM_ACCESS_EFUSE_T)pvSetBuffer; + + kalMemSet(&rCmdSetAccessEfuse, 0, sizeof(CMD_ACCESS_EFUSE_T)); + + rCmdSetAccessEfuse.u4Address = prSetAccessEfuseInfo->u4Address; + rCmdSetAccessEfuse.u4Valid = prSetAccessEfuseInfo->u4Valid; + + DBGLOG(INIT, INFO, + "MT6632 : wlanoidQueryProcessAccessEfuseRead, address=%d\n", + rCmdSetAccessEfuse.u4Address); + + kalMemCopy(rCmdSetAccessEfuse.aucData, prSetAccessEfuseInfo->aucData, + sizeof(u8) * 16); + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, EXT_CMD_ID_EFUSE_ACCESS, + false, /* Query Bit: True->write + * False->read*/ + true, true, NULL, /* No Tx done function wait until fw ack */ + nicOidCmdTimeoutCommon, sizeof(CMD_ACCESS_EFUSE_T), + (u8 *)(&rCmdSetAccessEfuse), pvSetBuffer, u4SetBufferLen); + + return rWlanStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to write efuse content. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryProcessAccessEfuseWrite(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_ACCESS_EFUSE_T prSetAccessEfuseInfo; + CMD_ACCESS_EFUSE_T rCmdSetAccessEfuse; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQueryProcessAccessEfuseWrite"); + DBGLOG(INIT, INFO, "MT6632 : wlanoidQueryProcessAccessEfuseWrite\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prSetAccessEfuseInfo = (P_PARAM_CUSTOM_ACCESS_EFUSE_T)pvSetBuffer; + + kalMemSet(&rCmdSetAccessEfuse, 0, sizeof(CMD_ACCESS_EFUSE_T)); + + rCmdSetAccessEfuse.u4Address = prSetAccessEfuseInfo->u4Address; + rCmdSetAccessEfuse.u4Valid = prSetAccessEfuseInfo->u4Valid; + + DBGLOG(INIT, INFO, + "MT6632 : wlanoidQueryProcessAccessEfuseWrite, address=%d\n", + rCmdSetAccessEfuse.u4Address); + + kalMemCopy(rCmdSetAccessEfuse.aucData, prSetAccessEfuseInfo->aucData, + sizeof(u8) * 16); + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, EXT_CMD_ID_EFUSE_ACCESS, + true, /* Query Bit: True->write + * False->read*/ + true, true, NULL, /* No Tx done function wait until fw ack */ + nicOidCmdTimeoutCommon, sizeof(CMD_ACCESS_EFUSE_T), + (u8 *)(&rCmdSetAccessEfuse), pvSetBuffer, u4SetBufferLen); + + return rWlanStatus; +} + +WLAN_STATUS +wlanoidQueryEfuseFreeBlock(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_EFUSE_FREE_BLOCK_T prGetEfuseFreeBlockInfo; + CMD_EFUSE_FREE_BLOCK_T rCmdGetEfuseFreeBlock; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQueryEfuseFreeBlock"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_EFUSE_FREE_BLOCK_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_EFUSE_FREE_BLOCK_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prGetEfuseFreeBlockInfo = (P_PARAM_CUSTOM_EFUSE_FREE_BLOCK_T)pvSetBuffer; + + kalMemSet(&rCmdGetEfuseFreeBlock, 0, sizeof(CMD_EFUSE_FREE_BLOCK_T)); + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, EXT_CMD_ID_EFUSE_FREE_BLOCK, + false, /* Query Bit: True->write + * False->read*/ + true, true, NULL, /* No Tx done function wait until fw ack */ + nicOidCmdTimeoutCommon, sizeof(CMD_EFUSE_FREE_BLOCK_T), + (u8 *)(&rCmdGetEfuseFreeBlock), pvSetBuffer, u4SetBufferLen); + + return rWlanStatus; +} + +WLAN_STATUS +wlanoidQueryGetTxPower(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_GET_TX_POWER_T prGetTxPowerInfo; + CMD_GET_TX_POWER_T rCmdGetTxPower; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQueryGetTxPower"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(P_PARAM_CUSTOM_GET_TX_POWER_T); + + if (u4SetBufferLen < sizeof(P_PARAM_CUSTOM_GET_TX_POWER_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prGetTxPowerInfo = (P_PARAM_CUSTOM_GET_TX_POWER_T)pvSetBuffer; + + kalMemSet(&rCmdGetTxPower, 0, sizeof(CMD_GET_TX_POWER_T)); + + rCmdGetTxPower.ucTxPwrType = EXT_EVENT_TARGET_TX_POWER; + rCmdGetTxPower.ucCenterChannel = prGetTxPowerInfo->ucCenterChannel; + rCmdGetTxPower.ucDbdcIdx = prGetTxPowerInfo->ucDbdcIdx; + rCmdGetTxPower.ucBand = prGetTxPowerInfo->ucBand; + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, EXT_CMD_ID_GET_TX_POWER, + false, /* Query Bit: True->write + * False->read*/ + true, true, NULL, /* No Tx done function wait until fw ack */ + nicOidCmdTimeoutCommon, sizeof(CMD_GET_TX_POWER_T), + (u8 *)(&rCmdGetTxPower), pvSetBuffer, u4SetBufferLen); + + return rWlanStatus; +} + +/*#endif*/ + +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query RX statistics. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRxStatistics(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_CUSTOM_ACCESS_RX_STAT prRxStatistics; + P_CMD_ACCESS_RX_STAT prCmdAccessRxStat; + CMD_ACCESS_RX_STAT rCmdAccessRxStat; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + /* u32 u4MemSize = PARAM_MEM_DUMP_MAX_SIZE; */ + u32 u4SeqNum = 0; + u32 u4TotalNum = 0; + + prCmdAccessRxStat = &rCmdAccessRxStat; + + DEBUGFUNC("wlanoidQueryRxStatistics"); + DBGLOG(INIT, LOUD, "\n"); + + DBGLOG(INIT, ERROR, "MT6632 : wlanoidQueryRxStatistics\n"); + + prRxStatistics = (P_PARAM_CUSTOM_ACCESS_RX_STAT)pvQueryBuffer; + + *pu4QueryInfoLen = 8 + prRxStatistics->u4TotalNum; + + u4SeqNum = prRxStatistics->u4SeqNum; + u4TotalNum = prRxStatistics->u4TotalNum; + + do { + prCmdAccessRxStat->u4SeqNum = u4SeqNum; + prCmdAccessRxStat->u4TotalNum = u4TotalNum; + + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_ACCESS_RX_STAT, false, + true, true, nicCmdEventQueryRxStatistics, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_RX_STAT), + (u8 *)prCmdAccessRxStat, pvQueryBuffer, + u4QueryBufferLen); + } while (false); + + return rStatus; +} + +#if CFG_SUPPORT_TX_BF + +WLAN_STATUS +wlanoidStaRecUpdate(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_CMD_STAREC_UPDATE_T prStaRecUpdateInfo; + P_CMD_STAREC_COMMON_T prStaRecCmm; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidStaRecUpdate"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(CMD_STAREC_COMMON_T); + if (u4SetBufferLen < sizeof(CMD_STAREC_COMMON_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prStaRecUpdateInfo = (P_CMD_STAREC_UPDATE_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, (CMD_STAREC_UPDATE_HDR_SIZE + u4SetBufferLen)); + if (!prStaRecUpdateInfo) { + DBGLOG(INIT, ERROR, "Allocate P_CMD_DEV_INFO_UPDATE_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + /* fix me: configurable ucBssIndex */ + prStaRecCmm = (P_CMD_STAREC_COMMON_T)pvSetBuffer; + prStaRecUpdateInfo->ucBssIndex = 0; + prStaRecUpdateInfo->ucWlanIdx = prStaRecCmm->u2Reserve1; + prStaRecUpdateInfo->u2TotalElementNum = 1; + kalMemCopy(prStaRecUpdateInfo->aucBuffer, pvSetBuffer, u4SetBufferLen); + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, EXT_CMD_ID_STAREC_UPDATE, true, + false, true, nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + (CMD_STAREC_UPDATE_HDR_SIZE + u4SetBufferLen), (u8 *)prStaRecUpdateInfo, + NULL, 0); + + cnmMemFree(prAdapter, prStaRecUpdateInfo); + + return rWlanStatus; +} + +WLAN_STATUS +wlanoidStaRecBFUpdate(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_CMD_STAREC_UPDATE_T prStaRecUpdateInfo; + P_CMD_STAREC_BF prStaRecBF; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidStaRecBFUpdate"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(CMD_STAREC_BF); + if (u4SetBufferLen < sizeof(CMD_STAREC_BF)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prStaRecUpdateInfo = (P_CMD_STAREC_UPDATE_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, (CMD_STAREC_UPDATE_HDR_SIZE + u4SetBufferLen)); + if (!prStaRecUpdateInfo) { + DBGLOG(INIT, ERROR, "Allocate P_CMD_DEV_INFO_UPDATE_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + /* fix me: configurable ucBssIndex */ + prStaRecBF = (P_CMD_STAREC_BF)pvSetBuffer; + prStaRecUpdateInfo->ucBssIndex = prStaRecBF->ucReserved[0]; + prStaRecUpdateInfo->ucWlanIdx = prStaRecBF->ucReserved[1]; + prStaRecUpdateInfo->u2TotalElementNum = 1; + kalMemCopy(prStaRecUpdateInfo->aucBuffer, pvSetBuffer, u4SetBufferLen); + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, EXT_CMD_ID_STAREC_UPDATE, true, + false, true, nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + (CMD_STAREC_UPDATE_HDR_SIZE + u4SetBufferLen), (u8 *)prStaRecUpdateInfo, + NULL, 0); + + cnmMemFree(prAdapter, prStaRecUpdateInfo); + + return rWlanStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief extend command packet generation utility + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] ucCID Command ID + * \param[in] ucExtCID Extend command ID + * \param[in] fgSetQuery Set or Query + * \param[in] fgNeedResp Need for response + * \param[in] pfCmdDoneHandler Function pointer when command is done + * \param[in] u4SetQueryInfoLen The length of the set/query buffer + * \param[in] pucInfoBuffer Pointer to set/query buffer + * + * + * \retval WLAN_STATUS_PENDING + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanSendSetQueryExtCmd(IN P_ADAPTER_T prAdapter, u8 ucCID, u8 ucExtCID, + u8 fgSetQuery, u8 fgNeedResp, u8 fgIsOid, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + u32 u4SetQueryInfoLen, u8 *pucInfoBuffer, + OUT void *pvSetQueryBuffer, IN u32 u4SetQueryBufferLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + u8 ucCmdSeqNum; + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = + cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); + + DEBUGFUNC("wlanSendSetQueryCmd"); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); + + /* Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->u2InfoBufLen = (u16)(CMD_HDR_SIZE + u4SetQueryInfoLen); + prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; + prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; + prCmdInfo->fgIsOid = fgIsOid; + prCmdInfo->ucCID = ucCID; + prCmdInfo->fgSetQuery = fgSetQuery; + prCmdInfo->fgNeedResp = fgNeedResp; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; + prCmdInfo->pvInformationBuffer = pvSetQueryBuffer; + prCmdInfo->u4InformationBufferLength = u4SetQueryBufferLen; + + /* Setup WIFI_CMD_T (no payload) */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->u2Length = + prCmdInfo->u2InfoBufLen - (u16)OFFSET_OF(WIFI_CMD_T, u2Length); + prWifiCmd->u2PqId = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucExtenCID = ucExtCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + if (u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) { + kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); + } + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + return WLAN_STATUS_PENDING; +} + +WLAN_STATUS +wlanoidBssInfoBasic(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_CMD_BSS_INFO_UPDATE_T prBssInfoUpdateBasic; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidManualAssoc"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(CMD_BSSINFO_BASIC_T); + if (u4SetBufferLen < sizeof(CMD_BSSINFO_BASIC_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prBssInfoUpdateBasic = + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + (CMD_BSSINFO_UPDATE_HDR_SIZE + u4SetBufferLen)); + if (!prBssInfoUpdateBasic) { + DBGLOG(INIT, ERROR, "Allocate P_CMD_DEV_INFO_UPDATE_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + /* fix me: configurable ucBssIndex */ + prBssInfoUpdateBasic->ucBssIndex = 0; + prBssInfoUpdateBasic->u2TotalElementNum = 1; + kalMemCopy(prBssInfoUpdateBasic->aucBuffer, pvSetBuffer, u4SetBufferLen); + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, EXT_CMD_ID_BSSINFO_UPDATE, + true, false, true, nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + (CMD_BSSINFO_UPDATE_HDR_SIZE + u4SetBufferLen), + (u8 *)prBssInfoUpdateBasic, NULL, 0); + + cnmMemFree(prAdapter, prBssInfoUpdateBasic); + + return rWlanStatus; +} + +WLAN_STATUS +wlanoidDevInfoActive(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_CMD_DEV_INFO_UPDATE_T prDevInfoUpdateActive; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidManualAssoc"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(CMD_DEVINFO_ACTIVE_T); + if (u4SetBufferLen < sizeof(CMD_DEVINFO_ACTIVE_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prDevInfoUpdateActive = + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + (CMD_DEVINFO_UPDATE_HDR_SIZE + u4SetBufferLen)); + if (!prDevInfoUpdateActive) { + DBGLOG(INIT, ERROR, "Allocate P_CMD_DEV_INFO_UPDATE_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + /* fix me: configurable ucOwnMacIdx */ + prDevInfoUpdateActive->ucOwnMacIdx = 0; + prDevInfoUpdateActive->ucAppendCmdTLV = 0; + prDevInfoUpdateActive->u2TotalElementNum = 1; + kalMemCopy(prDevInfoUpdateActive->aucBuffer, pvSetBuffer, u4SetBufferLen); + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, EXT_CMD_ID_DEVINFO_UPDATE, + true, false, true, nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + (CMD_DEVINFO_UPDATE_HDR_SIZE + u4SetBufferLen), + (u8 *)prDevInfoUpdateActive, NULL, 0); + + cnmMemFree(prAdapter, prDevInfoUpdateActive); + + return rWlanStatus; +} + +WLAN_STATUS +wlanoidManualAssoc(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_CMD_STAREC_UPDATE_T prStaRecManualAssoc; + P_CMD_MANUAL_ASSOC_STRUCT_T prManualAssoc; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidManualAssoc"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(CMD_STAREC_UPDATE_T); + if (u4SetBufferLen < sizeof(CMD_STAREC_UPDATE_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prStaRecManualAssoc = cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, (CMD_STAREC_UPDATE_HDR_SIZE + u4SetBufferLen)); + if (!prStaRecManualAssoc) { + DBGLOG(INIT, ERROR, "Allocate P_CMD_STAREC_UPDATE_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + + prManualAssoc = (P_CMD_MANUAL_ASSOC_STRUCT_T)pvSetBuffer; + prStaRecManualAssoc->ucWlanIdx = prManualAssoc->ucWtbl; + prStaRecManualAssoc->ucBssIndex = prManualAssoc->ucOwnmac; + prStaRecManualAssoc->u2TotalElementNum = 1; + kalMemCopy(prStaRecManualAssoc->aucBuffer, pvSetBuffer, u4SetBufferLen); + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, EXT_CMD_ID_STAREC_UPDATE, true, + false, true, nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + (CMD_STAREC_UPDATE_HDR_SIZE + u4SetBufferLen), + (u8 *)prStaRecManualAssoc, NULL, 0); + + cnmMemFree(prAdapter, prStaRecManualAssoc); + + return rWlanStatus; +} + +typedef struct _TXBF_CMD_DONE_HANDLER_T { + u32 u4TxBfCmdId; + void (*pFunc)(P_ADAPTER_T, P_CMD_INFO_T, u8 *, u32); +} TXBF_CMD_DONE_HANDLER_T, *P_TXBF_CMD_DONE_HANDLER_T; + +TXBF_CMD_DONE_HANDLER_T rTxBfCmdDoneHandler[] = { + { BF_SOUNDING_OFF, nicCmdEventSetCommon }, + { BF_SOUNDING_ON, nicCmdEventSetCommon }, + { BF_HW_CTRL, nicCmdEventSetCommon }, + { BF_DATA_PACKET_APPLY, nicCmdEventSetCommon }, + { BF_PFMU_MEM_ALLOCATE, nicCmdEventSetCommon }, + { BF_PFMU_MEM_RELEASE, nicCmdEventSetCommon }, + { BF_PFMU_TAG_READ, nicCmdEventPfmuTagRead }, + { BF_PFMU_TAG_WRITE, nicCmdEventSetCommon }, + { BF_PROFILE_READ, nicCmdEventPfmuDataRead }, + { BF_PROFILE_WRITE, nicCmdEventSetCommon }, + { BF_PN_READ, nicCmdEventSetCommon }, + { BF_PN_WRITE, nicCmdEventSetCommon }, + { BF_PFMU_MEM_ALLOC_MAP_READ, nicCmdEventSetCommon } +}; + +WLAN_STATUS +wlanoidTxBfAction(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_TXBF_ACTION_STRUCT_T prTxBfActionInfo; + CMD_TXBF_ACTION_T rCmdTxBfActionInfo; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + u8 fgSetQuery, fgNeedResp; + u32 u4TxBfCmdId; + + DEBUGFUNC("wlanoidTxBfAction"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_TXBF_ACTION_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_TXBF_ACTION_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prTxBfActionInfo = (P_PARAM_CUSTOM_TXBF_ACTION_STRUCT_T)pvSetBuffer; + + memcpy(&rCmdTxBfActionInfo, prTxBfActionInfo, sizeof(CMD_TXBF_ACTION_T)); + + u4TxBfCmdId = rCmdTxBfActionInfo.rProfileTagRead.ucTxBfCategory; + if (TXBF_CMD_NEED_TO_RESPONSE(u4TxBfCmdId) == 0) { /* don't need + * response */ + fgSetQuery = true; + fgNeedResp = false; + } else { + fgSetQuery = false; + fgNeedResp = true; + } + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, EXT_CMD_ID_BF_ACTION, + fgSetQuery, fgNeedResp, true, rTxBfCmdDoneHandler[u4TxBfCmdId].pFunc, + nicOidCmdTimeoutCommon, sizeof(CMD_TXBF_ACTION_T), + (u8 *)&rCmdTxBfActionInfo, pvSetBuffer, u4SetBufferLen); + + return rWlanStatus; +} + +#if CFG_SUPPORT_MU_MIMO +WLAN_STATUS +wlanoidMuMimoAction(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T prMuMimoActionInfo; + CMD_MUMIMO_ACTION_T rCmdMuMimoActionInfo; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + u8 fgSetQuery, fgNeedResp; + u32 u4MuMimoCmdId; + void (*pFunc)(P_ADAPTER_T, P_CMD_INFO_T, u8 *, u32); + + DEBUGFUNC("wlanoidMuMimoAction"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prMuMimoActionInfo = (P_PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T)pvSetBuffer; + + memcpy(&rCmdMuMimoActionInfo, prMuMimoActionInfo, + sizeof(CMD_MUMIMO_ACTION_T)); + + u4MuMimoCmdId = rCmdMuMimoActionInfo.ucMuMimoCategory; + if (MU_CMD_NEED_TO_RESPONSE(u4MuMimoCmdId) == 0) { + fgSetQuery = true; + fgNeedResp = false; + } else { + fgSetQuery = false; + fgNeedResp = true; + } + + pFunc = nicCmdEventSetCommon; + if (u4MuMimoCmdId == MU_HQA_GET_QD) { + pFunc = nicCmdEventGetQd; + } else if (u4MuMimoCmdId == MU_HQA_GET_CALC_LQ) { + pFunc = nicCmdEventGetCalcLq; + } else if (u4MuMimoCmdId == MU_GET_CALC_INIT_MCS) { + pFunc = nicCmdEventGetCalcInitMcs; + } + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, EXT_CMD_ID_MU_CTRL, fgSetQuery, + fgNeedResp, true, pFunc, nicOidCmdTimeoutCommon, + sizeof(CMD_MUMIMO_ACTION_T), (u8 *)&rCmdMuMimoActionInfo, pvSetBuffer, + u4SetBufferLen); + + return rWlanStatus; +} +#endif +#endif +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to do Coex Isolation Detection. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the + * call failed due to invalid length of the query buffer, returns the amount of + * storage needed. + * + * \retval WLAN_STATUS_SUCCESS* \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryCoexIso(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + struct PARAM_COEX_CTRL *prParaCoexCtrl; + struct PARAM_COEX_ISO_DETECT *prParaCoexIsoDetect; + struct CMD_COEX_CTRL rCmdCoexCtrl; + struct CMD_COEX_ISO_DETECT rCmdCoexIsoDetect; + + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + kalMemZero(&rCmdCoexCtrl, sizeof(struct CMD_COEX_CTRL)); + + *pu4QueryInfoLen = sizeof(struct PARAM_COEX_CTRL); + + if (u4QueryBufferLen < sizeof(struct PARAM_COEX_CTRL)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prParaCoexCtrl = (struct PARAM_COEX_CTRL *)pvQueryBuffer; + prParaCoexIsoDetect = + (struct PARAM_COEX_ISO_DETECT *)&prParaCoexCtrl->aucBuffer[0]; + + rCmdCoexIsoDetect.u4Channel = prParaCoexIsoDetect->u4Channel; + /*rCmdCoexIsoDetect.u4Band = prParaCoexIsoDetect->u4Band;*/ + rCmdCoexIsoDetect.u4IsoPath = prParaCoexIsoDetect->u4IsoPath; + rCmdCoexIsoDetect.u4Isolation = prParaCoexIsoDetect->u4Isolation; + + rCmdCoexCtrl.u4SubCmd = prParaCoexCtrl->u4SubCmd; + + /* Copy Memory */ + kalMemCopy(rCmdCoexCtrl.aucBuffer, &rCmdCoexIsoDetect, + sizeof(rCmdCoexIsoDetect)); + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_COEX_CTRL, false, true, true, + nicCmdEventQueryCoexIso, nicOidCmdTimeoutCommon, + sizeof(struct CMD_COEX_CTRL), + (unsigned char *)&rCmdCoexCtrl, pvQueryBuffer, + u4QueryBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query MCR value. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMcrRead(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrRdInfo; + CMD_ACCESS_REG rCmdAccessReg; + + DEBUGFUNC("wlanoidQueryMcrRead"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prMcrRdInfo = (P_PARAM_CUSTOM_MCR_RW_STRUCT_T)pvQueryBuffer; + + /* 0x9000 - 0x9EFF reserved for FW */ +#if CFG_SUPPORT_SWCR + if ((prMcrRdInfo->u4McrOffset >> 16) == 0x9F00) { + swCrReadWriteCmd(prAdapter, SWCR_READ, + (u16)(prMcrRdInfo->u4McrOffset & BITS(0, 15)), + &prMcrRdInfo->u4McrData); + return WLAN_STATUS_SUCCESS; + } +#endif + + /* Check if access F/W Domain MCR (due to WiFiSYS is placed from + * 0x6000-0000 */ + if (prMcrRdInfo->u4McrOffset & 0xFFFF0000) { + /* fill command */ + rCmdAccessReg.u4Address = prMcrRdInfo->u4McrOffset; + rCmdAccessReg.u4Data = 0; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_ACCESS_REG, false, true, + true, nicCmdEventQueryMcrRead, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), (u8 *)&rCmdAccessReg, + pvQueryBuffer, u4QueryBufferLen); + } else { + HAL_MCR_RD(prAdapter, + (prMcrRdInfo->u4McrOffset & BITS(2, 31)), /* address + * is in + * DWORD + * unit */ + &prMcrRdInfo->u4McrData); + + DBGLOG(INIT, TRACE, "MCR Read: Offset = %#08lx, Data = %#08lx\n", + prMcrRdInfo->u4McrOffset, prMcrRdInfo->u4McrData); + return WLAN_STATUS_SUCCESS; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to write MCR and enable specific function. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetMcrWrite(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrWrInfo; + CMD_ACCESS_REG rCmdAccessReg; + +#if CFG_STRESS_TEST_SUPPORT + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prBssInfo = prAdapter->prAisBssInfo; + P_STA_RECORD_T prStaRec = prBssInfo->prStaRecOfAP; + u32 u4McrOffset, u4McrData; +#endif + + DEBUGFUNC("wlanoidSetMcrWrite"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prMcrWrInfo = (P_PARAM_CUSTOM_MCR_RW_STRUCT_T)pvSetBuffer; + + /* 0x9000 - 0x9EFF reserved for FW */ + /* 0xFFFE reserved for FW */ + + /* -- Puff Stress Test Begin */ +#if CFG_STRESS_TEST_SUPPORT + /* 0xFFFFFFFE for Control Rate */ + if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFE) { + if (prMcrWrInfo->u4McrData < FIXED_RATE_NUM && + prMcrWrInfo->u4McrData > 0) { + prAdapter->rWifiVar.eRateSetting = + (ENUM_REGISTRY_FIXED_RATE_T)(prMcrWrInfo->u4McrData); + } + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + DEBUGFUNC("[Stress Test]Complete Rate is Changed...\n"); + DBGLOG(INIT, TRACE, "[Stress Test] Rate is Changed to index %d...\n", + prAdapter->rWifiVar.eRateSetting); + } + /* 0xFFFFFFFD for Switch Channel */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFD) { + if (prMcrWrInfo->u4McrData <= 11 && prMcrWrInfo->u4McrData >= 1) { + prBssInfo->ucPrimaryChannel = prMcrWrInfo->u4McrData; + } + nicUpdateBss(prAdapter, prBssInfo->ucNetTypeIndex); + DBGLOG(INIT, TRACE, "[Stress Test] Channel is switched to %d ...\n", + prBssInfo->ucPrimaryChannel); + + return WLAN_STATUS_SUCCESS; + } + /* 0xFFFFFFFFC for Control RF Band and SCO */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFC) { + /* Band */ + if (prMcrWrInfo->u4McrData & 0x80000000) { + /* prBssInfo->eBand = BAND_5G; */ + /* prBssInfo->ucPrimaryChannel = 52; // Bond to Channel + * 52 */ + } else { + prBssInfo->eBand = BAND_2G4; + prBssInfo->ucPrimaryChannel = 8; /* Bond to Channel 6 */ + } + + /* Bandwidth */ + if (prMcrWrInfo->u4McrData & 0x00010000) { + prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; + prStaRec->ucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + + if (prMcrWrInfo->u4McrData == 0x00010002) { + prBssInfo->eBssSCO = CHNL_EXT_SCB; /* U20 */ + prBssInfo->ucPrimaryChannel += 2; + } else if (prMcrWrInfo->u4McrData == 0x00010001) { + prBssInfo->eBssSCO = CHNL_EXT_SCA; /* L20 */ + prBssInfo->ucPrimaryChannel -= 2; + } else { + prBssInfo->eBssSCO = CHNL_EXT_SCA; /* 40 */ + } + } + + if (prMcrWrInfo->u4McrData & 0x00000000) { + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; + prBssInfo->eBssSCO = CHNL_EXT_SCN; + } + rlmBssInitForAPandIbss(prAdapter, prBssInfo); + } + /* 0xFFFFFFFB for HT Capability */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFB) { + /* Enable HT Capability */ + if (prMcrWrInfo->u4McrData & 0x00000001) { + prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; + DEBUGFUNC("[Stress Test]Enable HT capability...\n"); + } else { + prStaRec->u2HtCapInfo &= (~HT_CAP_INFO_HT_GF); + DEBUGFUNC("[Stress Test]Disable HT capability...\n"); + } + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + } + /* 0xFFFFFFFA for Enable Random Rx Reset */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFFA) { + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_RANDOM_RX_RESET_EN, true, + false, true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), (u8 *)&rCmdAccessReg, + pvSetBuffer, u4SetBufferLen); + } + /* 0xFFFFFFF9 for Disable Random Rx Reset */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF9) { + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_RANDOM_RX_RESET_DE, true, + false, true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), (u8 *)&rCmdAccessReg, + pvSetBuffer, u4SetBufferLen); + } + /* 0xFFFFFFF8 for Enable SAPP */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF8) { + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_SAPP_EN, true, false, true, + nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), (u8 *)&rCmdAccessReg, + pvSetBuffer, u4SetBufferLen); + } + /* 0xFFFFFFF7 for Disable SAPP */ + else if (prMcrWrInfo->u4McrOffset == 0xFFFFFFF7) { + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_SAPP_DE, true, false, true, + nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), (u8 *)&rCmdAccessReg, + pvSetBuffer, u4SetBufferLen); + } else +#endif + /* -- Puff Stress Test End */ + if (prMcrWrInfo->u4McrOffset & 0xFFFF0000) { +#if CFG_SUPPORT_SWCR + if ((prMcrWrInfo->u4McrOffset >> 16) == 0x9F00) { + swCrReadWriteCmd(prAdapter, SWCR_WRITE, + (u16)(prMcrWrInfo->u4McrOffset & BITS(0, 15)), + &prMcrWrInfo->u4McrData); + return WLAN_STATUS_SUCCESS; + } +#endif + if (prMcrWrInfo->u4McrOffset == 0x11111110) { + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + prAdapter->fgTestMode = true; + return rStatus; + } + if (prMcrWrInfo->u4McrOffset == 0x11111111) { + nicpmSetAcpiPowerD3(prAdapter); + return WLAN_STATUS_SUCCESS; + } + if (prMcrWrInfo->u4McrOffset == 0x11111112) { + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_ACCESS_REG, true, + false, true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (u8 *)&rCmdAccessReg, pvSetBuffer, + u4SetBufferLen); + } + + /* low power test special command */ + if (prMcrWrInfo->u4McrOffset == 0x11111110) { + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + prAdapter->fgTestMode = true; + return rStatus; + } + if (prMcrWrInfo->u4McrOffset == 0x11111111) { + nicpmSetAcpiPowerD3(prAdapter); + return WLAN_STATUS_SUCCESS; + } + if (prMcrWrInfo->u4McrOffset == 0x11111112) { + /* fill command */ + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_ACCESS_REG, true, + false, true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (u8 *)&rCmdAccessReg, pvSetBuffer, + u4SetBufferLen); + } + +#if CFG_SUPPORT_SDIO_READ_WRITE_PATTERN + if (prMcrWrInfo->u4McrOffset == 0x22220000) { + kalSetSdioTestPattern(prAdapter->prGlueInfo, true, true); + return WLAN_STATUS_SUCCESS; + } + + if (prMcrWrInfo->u4McrOffset == 0x22220001) { + kalSetSdioTestPattern(prAdapter->prGlueInfo, true, false); + return WLAN_STATUS_SUCCESS; + } + + if (prMcrWrInfo->u4McrOffset == 0x22220002) { + kalSetSdioTestPattern(prAdapter->prGlueInfo, false, false); + return WLAN_STATUS_SUCCESS; + } +#endif + + /* fill command */ + rCmdAccessReg.u4Address = prMcrWrInfo->u4McrOffset; + rCmdAccessReg.u4Data = prMcrWrInfo->u4McrData; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_ACCESS_REG, true, + false, true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_REG), + (u8 *)&rCmdAccessReg, pvSetBuffer, + u4SetBufferLen); + } else { + HAL_MCR_WR(prAdapter, + (prMcrWrInfo->u4McrOffset & + BITS(2, 31)), /* address is in DWORD unit */ + prMcrWrInfo->u4McrData); + + DBGLOG(INIT, TRACE, "MCR Write: Offset = %#08lx, Data = %#08lx\n", + prMcrWrInfo->u4McrOffset, prMcrWrInfo->u4McrData); + + return WLAN_STATUS_SUCCESS; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query driver MCR value. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryDrvMcrRead(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrRdInfo; + /* CMD_ACCESS_REG rCmdAccessReg; */ + + DEBUGFUNC("wlanoidQueryMcrRead"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prMcrRdInfo = (P_PARAM_CUSTOM_MCR_RW_STRUCT_T)pvQueryBuffer; + + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + HAL_MCR_RD(prAdapter, (prMcrRdInfo->u4McrOffset & BITS(2, 31)), + &prMcrRdInfo->u4McrData); + + DBGLOG(INIT, TRACE, "DRV MCR Read: Offset = %#08lx, Data = %#08lx\n", + prMcrRdInfo->u4McrOffset, prMcrRdInfo->u4McrData); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to write MCR and enable specific function. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetDrvMcrWrite(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrWrInfo; + /* CMD_ACCESS_REG rCmdAccessReg; */ + + DEBUGFUNC("wlanoidSetMcrWrite"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prMcrWrInfo = (P_PARAM_CUSTOM_MCR_RW_STRUCT_T)pvSetBuffer; + + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + HAL_MCR_WR(prAdapter, (prMcrWrInfo->u4McrOffset & BITS(2, 31)), + prMcrWrInfo->u4McrData); + + DBGLOG(INIT, TRACE, "DRV MCR Write: Offset = %#08lx, Data = %#08lx\n", + prMcrWrInfo->u4McrOffset, prMcrWrInfo->u4McrData); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query SW CTRL + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_CUSTOM_SW_CTRL_STRUCT_T prSwCtrlInfo; + WLAN_STATUS rWlanStatus; + u16 u2Id, u2SubId; + u32 u4Data; + + CMD_SW_DBG_CTRL_T rCmdSwCtrl; + + DEBUGFUNC("wlanoidQuerySwCtrlRead"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + kalMemZero(&rCmdSwCtrl, sizeof(CMD_SW_DBG_CTRL_T)); + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUCT_T)pvQueryBuffer; + + u2Id = (u16)(prSwCtrlInfo->u4Id >> 16); + u2SubId = (u16)(prSwCtrlInfo->u4Id & BITS(0, 15)); + u4Data = 0; + rWlanStatus = WLAN_STATUS_SUCCESS; + + DBGLOG(INIT, INFO, "%#06x\n", u2Id); + + switch (u2Id) { + /* 0x9000 - 0x9EFF reserved for FW */ + /* 0xFFFE reserved for FW */ + +#if CFG_SUPPORT_SWCR + case 0x9F00: + swCrReadWriteCmd(prAdapter, SWCR_READ /* Read */, (u16)u2SubId, + &u4Data); + break; +#endif + + case 0xFFFF: { + u4Data = 0x5AA56620; + } break; + + case 0xBABA: + switch ((u2SubId >> 8) & BITS(0, 7)) { + case 0x00: + /* Dump Tx resource and queue status */ + qmDumpQueueStatus(prAdapter, NULL, 0); + cnmDumpMemoryStatus(prAdapter, NULL, 0); + break; + + case 0x01: + /* Dump StaRec info by index */ + cnmDumpStaRec(prAdapter, (u8)(u2SubId & BITS(0, 7))); + break; + + case 0x02: + /* Dump BSS info by index */ + bssDumpBssInfo(prAdapter, (u8)(u2SubId & BITS(0, 7))); + break; + + case 0x03: + /*Dump BSS statistics by index */ + wlanDumpBssStatistics(prAdapter, (u8)(u2SubId & BITS(0, 7))); + break; + + case 0x04: + halDumpHifStatus(prAdapter, NULL, 0); + break; + + default: + break; + } + + u4Data = 0xBABABABA; + break; + + case 0x9000: + default: { + rCmdSwCtrl.u4Id = prSwCtrlInfo->u4Id; + if (prSwCtrlInfo->u4Id == + CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_BCNTIMOUT_NUM_ID) { + rCmdSwCtrl.u4Data = prSwCtrlInfo->u4Data; + } else { + rCmdSwCtrl.u4Data = 0; + } + rWlanStatus = wlanSendSetQueryCmd( + prAdapter, CMD_ID_SW_DBG_CTRL, false, true, true, + nicCmdEventQuerySwCtrlRead, nicOidCmdTimeoutCommon, + sizeof(CMD_SW_DBG_CTRL_T), (u8 *)&rCmdSwCtrl, pvQueryBuffer, + u4QueryBufferLen); + return rWlanStatus; + } + } /* switch(u2Id) */ + + prSwCtrlInfo->u4Data = u4Data; + + return rWlanStatus; +} + +/* end of wlanoidQuerySwCtrlRead() */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to write SW CTRL + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetSwCtrlWrite(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_SW_CTRL_STRUCT_T prSwCtrlInfo; + CMD_SW_DBG_CTRL_T rCmdSwCtrl; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + u16 u2Id, u2SubId; + s32 u4Data; + u8 ucNss; + u8 ucChannelWidth; + u8 ucBssIndex; + + DEBUGFUNC("wlanoidSetSwCtrlWrite"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + kalMemZero(&rCmdSwCtrl, sizeof(CMD_SW_DBG_CTRL_T)); + + prSwCtrlInfo = (P_PARAM_CUSTOM_SW_CTRL_STRUCT_T)pvSetBuffer; + + u2Id = (u16)(prSwCtrlInfo->u4Id >> 16); + u2SubId = (u16)(prSwCtrlInfo->u4Id & BITS(0, 15)); + u4Data = prSwCtrlInfo->u4Data; + + switch (u2Id) { + /* 0x9000 - 0x9EFF reserved for FW */ + /* 0xFFFE reserved for FW */ + +#if CFG_SUPPORT_SWCR + case 0x9F00: + swCrReadWriteCmd(prAdapter, SWCR_WRITE, (u16)u2SubId, &u4Data); + break; +#endif + + case 0x2222: + ucNss = (u8)(u4Data & BITS(0, 3)); + ucChannelWidth = (u8)((u4Data & BITS(4, 7)) >> 4); + ucBssIndex = (u8)u2SubId; + + if (!IS_BSS_INDEX_VALID(ucBssIndex)) { + DBGLOG(RLM, ERROR, "Invalid bssidx:%d\n", ucBssIndex); + break; + } + + /* ucChannelWidth 0:20MHz, 1:40MHz, 2:80MHz, 3:160MHz 4:80+80MHz + */ + DBGLOG(REQ, INFO, "Change BSS[%d] OpMode to BW[%d] Nss[%d]\n", + ucBssIndex, ucChannelWidth, ucNss); + rlmChangeOperationMode(prAdapter, ucBssIndex, ucChannelWidth, ucNss); + break; + + case 0x1000: + if (u2SubId == 0x8000) { + /* CTIA power save mode setting (code: 0x10008000) */ + prAdapter->u4CtiaPowerMode = u4Data; + prAdapter->fgEnCtiaPowerMode = true; + + /* */ + { + PARAM_POWER_MODE ePowerMode; + + if (prAdapter->u4CtiaPowerMode == 0) { + /* force to keep in CAM mode */ + ePowerMode = Param_PowerModeCAM; + } else if (prAdapter->u4CtiaPowerMode == 1) { + ePowerMode = Param_PowerModeMAX_PSP; + } else { + ePowerMode = Param_PowerModeFast_PSP; + } + + nicConfigPowerSaveProfile(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex, + ePowerMode, true); + } + } + break; + + case 0x1001: + if (u2SubId == 0x0) { + prAdapter->fgEnOnlineScan = (u8)u4Data; + } else if (u2SubId == 0x1) { + prAdapter->fgDisBcnLostDetection = (u8)u4Data; + } else if (u2SubId == 0x2) { + prAdapter->rWifiVar.ucUapsd = (u8)u4Data; + } else if (u2SubId == 0x3) { + prAdapter->u4UapsdAcBmp = u4Data & BITS(0, 15); + if ((u4Data >> 16) > HW_BSSID_NUM) { + DBGLOG(INIT, ERROR, "[%s] BSS index (%d) out of bound\n", + __func__, (u4Data >> 16)); + return WLAN_STATUS_INVALID_DATA; + } + GET_BSS_INFO_BY_INDEX(prAdapter, u4Data >> 16) + ->rPmProfSetupInfo.ucBmpDeliveryAC = + (u8)prAdapter->u4UapsdAcBmp; + GET_BSS_INFO_BY_INDEX(prAdapter, u4Data >> 16) + ->rPmProfSetupInfo.ucBmpTriggerAC = (u8)prAdapter->u4UapsdAcBmp; + } else if (u2SubId == 0x4) { + prAdapter->fgDisStaAgingTimeoutDetection = (u8)u4Data; + } else if (u2SubId == 0x5) { + prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode = (u8)u4Data; + } else if (u2SubId == 0x0100) { + if (u4Data == 2) { + prAdapter->rWifiVar.ucRxGf = FEATURE_DISABLED; + } else { + prAdapter->rWifiVar.ucRxGf = FEATURE_ENABLED; + } + } else if (u2SubId == 0x0101) { + prAdapter->rWifiVar.ucRxShortGI = (u8)u4Data; + } else if (u2SubId == 0x0110) { + prAdapter->fgIsEnableLpdvt = (u8)u4Data; + prAdapter->fgEnOnlineScan = (u8)u4Data; + DBGLOG(INIT, INFO, "--- Enable LPDVT [%d] ---\n", + prAdapter->fgIsEnableLpdvt); + } + + break; + +#if CFG_SUPPORT_SWCR + case 0x1002: +#if CFG_RX_PKTS_DUMP + if (u2SubId == 0x0) { + if (u4Data) { + u4Data = BIT(HIF_RX_PKT_TYPE_MANAGEMENT); + } + swCrFrameCheckEnable(prAdapter, u4Data); + } +#endif + if (u2SubId == 0x1) { + u8 fgIsEnable; + u8 ucType; + u32 u4Timeout; + + fgIsEnable = (u8)(u4Data & 0xff); + ucType = 0; /* ((u4Data>>4) & 0xf); */ + u4Timeout = ((u4Data >> 8) & 0xff); + swCrDebugCheckEnable(prAdapter, fgIsEnable, ucType, u4Timeout); + } + break; +#endif + +#if CFG_SUPPORT_802_11W + case 0x2000: + DBGLOG(RSN, INFO, "802.11w test 0x%x\n", u2SubId); + if (u2SubId == 0x0) { + rsnStartSaQuery(prAdapter); + } + if (u2SubId == 0x1) { + rsnStopSaQuery(prAdapter); + } + if (u2SubId == 0x2) { + rsnSaQueryRequest(prAdapter, NULL); + } + if (u2SubId == 0x3) { + P_BSS_INFO_T prBssInfo = prAdapter->prAisBssInfo; + + authSendDeauthFrame(prAdapter, prBssInfo, prBssInfo->prStaRecOfAP, + NULL, 7, NULL); + } + /* wext_set_mode */ + /* + * if (u2SubId == 0x3) { + * prAdapter->prGlueInfo->rWpaInfo.u4Mfp = + * RSN_AUTH_MFP_DISABLED; + * } + * if (u2SubId == 0x4) { + * //prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = + * true; prAdapter->prGlueInfo->rWpaInfo.u4Mfp = + * RSN_AUTH_MFP_OPTIONAL; + * } + * if (u2SubId == 0x5) { + * //prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = + * true; prAdapter->prGlueInfo->rWpaInfo.u4Mfp = + * RSN_AUTH_MFP_REQUIRED; + * } + */ + break; + +#endif + case 0xFFFF: { + /* CMD_ACCESS_REG rCmdAccessReg; */ + + if (u2SubId == 0x0123) { + DBGLOG(HAL, INFO, "set smt fixed rate: %lu\n", u4Data); + + if ((ENUM_REGISTRY_FIXED_RATE_T)(u4Data) < FIXED_RATE_NUM) { + prAdapter->rWifiVar.eRateSetting = + (ENUM_REGISTRY_FIXED_RATE_T)(u4Data); + } else { + prAdapter->rWifiVar.eRateSetting = FIXED_RATE_NONE; + } + + if (prAdapter->rWifiVar.eRateSetting == FIXED_RATE_NONE) { + /* Enable Auto (Long/Short) Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_AUTO; + } else if ((prAdapter->rWifiVar.eRateSetting >= + FIXED_RATE_MCS0_20M_400NS && + prAdapter->rWifiVar.eRateSetting <= + FIXED_RATE_MCS7_20M_400NS) || + (prAdapter->rWifiVar.eRateSetting >= + FIXED_RATE_MCS0_40M_400NS && + prAdapter->rWifiVar.eRateSetting <= + FIXED_RATE_MCS32_400NS)) { + /* Force Short Preamble */ + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_SHORT; + } else { + prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_LONG; + } + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + return WLAN_STATUS_SUCCESS; + } else if (u2SubId == 0x1234) { + /* 1. Disable On-Lin Scan */ + /* 3. Disable FIFO FULL no ack */ + /* 4. Disable Roaming */ + /* Disalbe auto tx power */ + /* 2. Keep at CAM mode */ + /* 5. Disable Beacon Timeout Detection */ + rWlanStatus = nicEnterCtiaMode(prAdapter, true, true); + } else if (u2SubId == 0x1235) { + /* 1. Enaable On-Lin Scan */ + /* 3. Enable FIFO FULL no ack */ + /* 4. Enable Roaming */ + /* Enable auto tx power */ + /* 2. Keep at Fast PS */ + /* 5. Enable Beacon Timeout Detection */ + rWlanStatus = nicEnterCtiaMode(prAdapter, false, true); + } +#if CFG_MTK_STAGE_SCAN + else if (u2SubId == 0x1250) { + prAdapter->aePreferBand[KAL_NETWORK_TYPE_AIS_INDEX] = BAND_NULL; + } else if (u2SubId == 0x1251) { + prAdapter->aePreferBand[KAL_NETWORK_TYPE_AIS_INDEX] = BAND_2G4; + } else if (u2SubId == 0x1252) { + if (prAdapter->fgEnable5GBand) { + prAdapter->aePreferBand[KAL_NETWORK_TYPE_AIS_INDEX] = BAND_5G; + } else { + /* Skip this setting if 5G band is disabled */ + DBGLOG(SCN, INFO, + "Skip 5G stage scan request due to 5G is disabled\n"); + } + } +#endif + } break; + + case 0x9000: + default: { + rCmdSwCtrl.u4Id = prSwCtrlInfo->u4Id; + rCmdSwCtrl.u4Data = prSwCtrlInfo->u4Data; + rWlanStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_SW_DBG_CTRL, true, + false, true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_SW_DBG_CTRL_T), + (u8 *)&rCmdSwCtrl, pvSetBuffer, + u4SetBufferLen); + } + } /* switch(u2Id) */ + + return rWlanStatus; +} + +WLAN_STATUS +wlanoidQueryChipConfig(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T prChipConfigInfo; + CMD_CHIP_CONFIG_T rCmdChipConfig; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQuerySwCtrlRead"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prChipConfigInfo = (P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T)pvQueryBuffer; + kalMemZero(&rCmdChipConfig, sizeof(rCmdChipConfig)); + + rCmdChipConfig.u2Id = prChipConfigInfo->u2Id; + rCmdChipConfig.ucType = prChipConfigInfo->ucType; + rCmdChipConfig.ucRespType = prChipConfigInfo->ucRespType; + rCmdChipConfig.u2MsgSize = prChipConfigInfo->u2MsgSize; + if (rCmdChipConfig.u2MsgSize > CHIP_CONFIG_RESP_SIZE) { + DBGLOG(REQ, INFO, "Chip config Msg Size %u is not valid (query)\n", + rCmdChipConfig.u2MsgSize); + rCmdChipConfig.u2MsgSize = CHIP_CONFIG_RESP_SIZE; + } + kalMemCopy(rCmdChipConfig.aucCmd, prChipConfigInfo->aucCmd, + rCmdChipConfig.u2MsgSize); + + rWlanStatus = + wlanSendSetQueryCmd(prAdapter, CMD_ID_CHIP_CONFIG, false, true, true, + /*nicCmdEventQuerySwCtrlRead, */ + nicCmdEventQueryChipConfig, nicOidCmdTimeoutCommon, + sizeof(CMD_CHIP_CONFIG_T), (u8 *)&rCmdChipConfig, + pvQueryBuffer, u4QueryBufferLen); + + return rWlanStatus; +} + +/* end of wlanoidQueryChipConfig() */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set chip + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetChipConfig(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T prChipConfigInfo; + CMD_CHIP_CONFIG_T rCmdChipConfig; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DATA_STRUCT_INSPECTING_ASSERT(sizeof(prChipConfigInfo->aucCmd) == + CHIP_CONFIG_RESP_SIZE); + DEBUGFUNC("wlanoidSetChipConfig"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prChipConfigInfo = (P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T)pvSetBuffer; + kalMemZero(&rCmdChipConfig, sizeof(rCmdChipConfig)); + + rCmdChipConfig.u2Id = prChipConfigInfo->u2Id; + rCmdChipConfig.ucType = prChipConfigInfo->ucType; + rCmdChipConfig.ucRespType = prChipConfigInfo->ucRespType; + rCmdChipConfig.u2MsgSize = prChipConfigInfo->u2MsgSize; + if (rCmdChipConfig.u2MsgSize > CHIP_CONFIG_RESP_SIZE) { + DBGLOG(REQ, INFO, "Chip config Msg Size %u is not valid (set)\n", + rCmdChipConfig.u2MsgSize); + rCmdChipConfig.u2MsgSize = CHIP_CONFIG_RESP_SIZE; + } + kalMemCopy(rCmdChipConfig.aucCmd, prChipConfigInfo->aucCmd, + rCmdChipConfig.u2MsgSize); + + rWlanStatus = wlanSendSetQueryCmd( + prAdapter, CMD_ID_CHIP_CONFIG, true, false, true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, sizeof(CMD_CHIP_CONFIG_T), + (u8 *)&rCmdChipConfig, pvSetBuffer, u4SetBufferLen); + + return rWlanStatus; +} + +void wlanLoadDefaultCustomerSetting(IN P_ADAPTER_T prAdapter) +{ + u8 ucItemNum, i; + + ucItemNum = + (sizeof(g_rDefaulteSetting) / sizeof(PARAM_CUSTOM_KEY_CFG_STRUCT_T)); + DBGLOG( + INIT, INFO, + "[wlanLoadDefaultCustomerSetting] default firmware setting %d item\n", + ucItemNum); + + for (i = 0; i < ucItemNum; i++) { + wlanCfgSet(prAdapter, g_rDefaulteSetting[i].aucKey, + g_rDefaulteSetting[i].aucValue, 0); + DBGLOG(INIT, INFO, "%s with %s\n", g_rDefaulteSetting[i].aucKey, + g_rDefaulteSetting[i].aucValue); + } + + /*If need to re-parsing , included wlanInitFeatureOption*/ + wlanInitFeatureOption(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set cfg and callback + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetKeyCfg(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_PARAM_CUSTOM_KEY_CFG_STRUCT_T prKeyCfgInfo; + + DEBUGFUNC("wlanoidSetKeyCfg"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_KEY_CFG_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_KEY_CFG_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + prKeyCfgInfo = (P_PARAM_CUSTOM_KEY_CFG_STRUCT_T)pvSetBuffer; + + if (kalMemCmp(prKeyCfgInfo->aucKey, "reload", 6) == 0) { + wlanGetConfig(prAdapter); /* Reload config file */ + } else { + wlanCfgSet(prAdapter, prKeyCfgInfo->aucKey, prKeyCfgInfo->aucValue, 0); + } + + wlanInitFeatureOption(prAdapter); +#if CFG_SUPPORT_EASY_DEBUG +#if CFG_SUPPORT_SEND_ONLY_ONE_CFG + wlanFeatureToFwOnlyOneCfg(prAdapter, prKeyCfgInfo->aucKey, + prKeyCfgInfo->aucValue); +#else + wlanFeatureToFw(prAdapter); +#endif +#endif + + return rWlanStatus; +} + +/* wlanoidSetSwCtrlWrite */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query EEPROM value. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryEepromRead(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T prEepromRwInfo; + CMD_ACCESS_EEPROM rCmdAccessEeprom; + + DEBUGFUNC("wlanoidQueryEepromRead"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prEepromRwInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T)pvQueryBuffer; + + kalMemZero(&rCmdAccessEeprom, sizeof(CMD_ACCESS_EEPROM)); + rCmdAccessEeprom.u2Offset = prEepromRwInfo->ucEepromIndex; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_ACCESS_EEPROM, false, true, + true, nicCmdEventQueryEepromRead, + nicOidCmdTimeoutCommon, + sizeof(CMD_ACCESS_EEPROM), + (u8 *)&rCmdAccessEeprom, pvQueryBuffer, + u4QueryBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to write EEPROM value. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetEepromWrite(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T prEepromRwInfo; + CMD_ACCESS_EEPROM rCmdAccessEeprom; + + DEBUGFUNC("wlanoidSetEepromWrite"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prEepromRwInfo = (P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T)pvSetBuffer; + + kalMemZero(&rCmdAccessEeprom, sizeof(CMD_ACCESS_EEPROM)); + rCmdAccessEeprom.u2Offset = prEepromRwInfo->ucEepromIndex; + rCmdAccessEeprom.u2Data = prEepromRwInfo->u2EepromData; + + return wlanSendSetQueryCmd( + prAdapter, CMD_ID_ACCESS_EEPROM, true, false, true, + nicCmdEventSetCommon, nicOidCmdTimeoutCommon, sizeof(CMD_ACCESS_EEPROM), + (u8 *)&rCmdAccessEeprom, pvSetBuffer, u4SetBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the number of the successfully + * transmitted packets. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitOk(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryXmitOk"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(u32) || + (u4QueryBufferLen > sizeof(u32) && + u4QueryBufferLen < sizeof(u64))) { + *pu4QueryInfoLen = sizeof(u64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == true) { + if (u4QueryBufferLen == sizeof(u32)) { + *pu4QueryInfoLen = sizeof(u32); + *(u32 *)pvQueryBuffer = + (u32)prAdapter->rStatStruct.rTransmittedFragmentCount.QuadPart; + } else { + *pu4QueryInfoLen = sizeof(u64); + *(u64 *)pvQueryBuffer = + (u64)prAdapter->rStatStruct.rTransmittedFragmentCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_STATISTICS, false, true, + true, nicCmdEventQueryXmitOk, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, + u4QueryBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the number of the successfully + * received packets. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRcvOk(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRcvOk"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(u32) || + (u4QueryBufferLen > sizeof(u32) && + u4QueryBufferLen < sizeof(u64))) { + *pu4QueryInfoLen = sizeof(u64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == true) { + if (u4QueryBufferLen == sizeof(u32)) { + *pu4QueryInfoLen = sizeof(u32); + *(u32 *)pvQueryBuffer = + (u32)prAdapter->rStatStruct.rReceivedFragmentCount.QuadPart; + } else { + *pu4QueryInfoLen = sizeof(u64); + *(u64 *)pvQueryBuffer = + (u64)prAdapter->rStatStruct.rReceivedFragmentCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_STATISTICS, false, true, + true, nicCmdEventQueryRecvOk, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, + u4QueryBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the number of frames that the driver + * fails to transmit. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitError(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryXmitError"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(u32) || + (u4QueryBufferLen > sizeof(u32) && + u4QueryBufferLen < sizeof(u64))) { + *pu4QueryInfoLen = sizeof(u64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == true) { + if (u4QueryBufferLen == sizeof(u32)) { + *pu4QueryInfoLen = sizeof(u32); + *(u32 *)pvQueryBuffer = + (u32)prAdapter->rStatStruct.rFailedCount.QuadPart; + } else { + *pu4QueryInfoLen = sizeof(u64); + *(u64 *)pvQueryBuffer = + (u64)prAdapter->rStatStruct.rFailedCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_STATISTICS, false, true, + true, nicCmdEventQueryXmitError, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, + u4QueryBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the number of frames successfully + * transmitted after exactly one collision. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryXmitOneCollision"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(u32) || + (u4QueryBufferLen > sizeof(u32) && + u4QueryBufferLen < sizeof(u64))) { + *pu4QueryInfoLen = sizeof(u64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == true) { + if (u4QueryBufferLen == sizeof(u32)) { + *pu4QueryInfoLen = sizeof(u32); + *(u32 *)pvQueryBuffer = + (u32)(prAdapter->rStatStruct.rMultipleRetryCount.QuadPart - + prAdapter->rStatStruct.rRetryCount.QuadPart); + } else { + *pu4QueryInfoLen = sizeof(u64); + *(u64 *)pvQueryBuffer = + (u64)(prAdapter->rStatStruct.rMultipleRetryCount.QuadPart - + prAdapter->rStatStruct.rRetryCount.QuadPart); + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_STATISTICS, false, true, + true, nicCmdEventQueryXmitOneCollision, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, + u4QueryBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the number of frames successfully + * transmitted after more than one collision. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryXmitMoreCollisions"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(u32) || + (u4QueryBufferLen > sizeof(u32) && + u4QueryBufferLen < sizeof(u64))) { + *pu4QueryInfoLen = sizeof(u64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == true) { + if (u4QueryBufferLen == sizeof(u32)) { + *pu4QueryInfoLen = sizeof(u32); + *(u32 *)pvQueryBuffer = + (u32)(prAdapter->rStatStruct.rMultipleRetryCount.QuadPart); + } else { + *pu4QueryInfoLen = sizeof(u64); + *(u64 *)pvQueryBuffer = + (u64)(prAdapter->rStatStruct.rMultipleRetryCount.QuadPart); + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_STATISTICS, false, true, + true, nicCmdEventQueryXmitMoreCollisions, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, + u4QueryBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the number of frames + * not transmitted due to excessive collisions. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryXmitMaxCollisions"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(u32) || + (u4QueryBufferLen > sizeof(u32) && + u4QueryBufferLen < sizeof(u64))) { + *pu4QueryInfoLen = sizeof(u64); + return WLAN_STATUS_INVALID_LENGTH; + } +#if CFG_ENABLE_STATISTICS_BUFFERING + if (IsBufferedStatisticsUsable(prAdapter) == true) { + if (u4QueryBufferLen == sizeof(u32)) { + *pu4QueryInfoLen = sizeof(u32); + *(u32 *)pvQueryBuffer = + (u32)prAdapter->rStatStruct.rFailedCount.QuadPart; + } else { + *pu4QueryInfoLen = sizeof(u64); + *(u64 *)pvQueryBuffer = + (u64)prAdapter->rStatStruct.rFailedCount.QuadPart; + } + + return WLAN_STATUS_SUCCESS; + } +#endif + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_STATISTICS, false, true, + true, nicCmdEventQueryXmitMaxCollisions, + nicOidCmdTimeoutCommon, 0, NULL, pvQueryBuffer, + u4QueryBufferLen); +} + +#define MTK_CUSTOM_OID_INTERFACE_VERSION 0x00006620 /* for WPDWifi DLL */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query current the OID interface version, + * which is the interface between the application and driver. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryOidInterfaceVersion(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryOidInterfaceVersion"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + *(u32 *)pvQueryBuffer = MTK_CUSTOM_OID_INTERFACE_VERSION; + *pu4QueryInfoLen = sizeof(u32); + + DBGLOG(REQ, WARN, "Custom OID interface version: %#08lX\n", + *(u32 *)pvQueryBuffer); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query current Multicast Address List. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMulticastList(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set Multicast Address List. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_MULTICAST_FULL + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetMulticastList(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + CMD_MAC_MCAST_ADDR rCmdMacMcastAddr; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + kalMemZero(&rCmdMacMcastAddr, sizeof(CMD_MAC_MCAST_ADDR)); + + /* The data must be a multiple of the Ethernet address size. */ + if ((u4SetBufferLen % MAC_ADDR_LEN)) { + DBGLOG(REQ, WARN, "Invalid MC list length %ld\n", u4SetBufferLen); + + *pu4SetInfoLen = + (((u4SetBufferLen + MAC_ADDR_LEN) - 1) / MAC_ADDR_LEN) * + MAC_ADDR_LEN; + + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = u4SetBufferLen; + + /* Verify if we can support so many multicast addresses. */ + if (u4SetBufferLen > MAX_NUM_GROUP_ADDR * MAC_ADDR_LEN) { + DBGLOG(REQ, WARN, "Too many MC addresses\n"); + + return WLAN_STATUS_MULTICAST_FULL; + } + + /* NOTE(Kevin): Windows may set u4SetBufferLen == 0 && + * pvSetBuffer == NULL to clear exist Multicast List. + */ + if (u4SetBufferLen) { + ASSERT(pvSetBuffer); + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in set multicast list! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + rCmdMacMcastAddr.u4NumOfGroupAddr = u4SetBufferLen / MAC_ADDR_LEN; + rCmdMacMcastAddr.ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex; + kalMemCopy(rCmdMacMcastAddr.arAddress, pvSetBuffer, u4SetBufferLen); + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_MAC_MCAST_ADDR, true, false, + true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_MAC_MCAST_ADDR), + (u8 *)&rCmdMacMcastAddr, pvSetBuffer, + u4SetBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set Packet Filter. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_NOT_SUPPORTED + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCurrentPacketFilter(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + u32 u4NewPacketFilter; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; + CMD_RX_PACKET_FILTER rSetRxPacketFilter; + + DBGLOG(REQ, INFO, "wlanoidSetCurrentPacketFilter"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen < sizeof(u32)) { + *pu4SetInfoLen = sizeof(u32); + return WLAN_STATUS_INVALID_LENGTH; + } + ASSERT(pvSetBuffer); + + /* Set the new packet filter. */ + u4NewPacketFilter = *(u32 *)pvSetBuffer; + + DBGLOG(REQ, INFO, "New packet filter: %#08lx\n", u4NewPacketFilter); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in set current packet filter! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + do { + /* Verify the bits of the new packet filter. If any bits are set + * that we don't support, leave. + */ + if (u4NewPacketFilter & ~(PARAM_PACKET_FILTER_SUPPORTED)) { + rStatus = WLAN_STATUS_NOT_SUPPORTED; + DBGLOG(REQ, WARN, "some flags we don't support\n"); + break; + } +#if DBG + /* Need to enable or disable promiscuous support depending on + * the new filter. + */ + if (u4NewPacketFilter & PARAM_PACKET_FILTER_PROMISCUOUS) { + DBGLOG(REQ, INFO, "Enable promiscuous mode\n"); + } else { + DBGLOG(REQ, INFO, "Disable promiscuous mode\n"); + } + + if (u4NewPacketFilter & PARAM_PACKET_FILTER_ALL_MULTICAST) { + DBGLOG(REQ, INFO, "Enable all-multicast mode\n"); + } else if (u4NewPacketFilter & PARAM_PACKET_FILTER_MULTICAST) { + DBGLOG(REQ, INFO, "Enable multicast\n"); + } else { + DBGLOG(REQ, INFO, "Disable multicast\n"); + } + + if (u4NewPacketFilter & PARAM_PACKET_FILTER_BROADCAST) { + DBGLOG(REQ, INFO, "Enable Broadcast\n"); + } else { + DBGLOG(REQ, INFO, "Disable Broadcast\n"); + } +#endif + + prAdapter->fgAllMulicastFilter = false; + if (u4NewPacketFilter & PARAM_PACKET_FILTER_ALL_MULTICAST) { + prAdapter->fgAllMulicastFilter = true; + } + } while (false); + + if (rStatus == WLAN_STATUS_SUCCESS) { + /* Store the packet filter */ + + prAdapter->u4OsPacketFilter &= PARAM_PACKET_FILTER_P2P_MASK; + prAdapter->u4OsPacketFilter |= u4NewPacketFilter; + + kalMemZero(&rSetRxPacketFilter, sizeof(rSetRxPacketFilter)); + rSetRxPacketFilter.u4RxPacketFilter = prAdapter->u4OsPacketFilter; + + rResult = wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_RX_FILTER, true, + false, true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_RX_PACKET_FILTER), + (u8 *)&rSetRxPacketFilter, pvSetBuffer, + u4SetBufferLen); + prAdapter->u4OsPacketFilter = rSetRxPacketFilter.u4RxPacketFilter; + return rResult; + } else { + return rStatus; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query current packet filter. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryCurrentPacketFilter(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryCurrentPacketFilter"); + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(u32); + + if (u4QueryBufferLen >= sizeof(u32)) { + ASSERT(pvQueryBuffer); + *(u32 *)pvQueryBuffer = prAdapter->u4OsPacketFilter; + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query ACPI device power state. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen) +{ +#if DBG + PPARAM_DEVICE_POWER_STATE prPowerState; +#endif + + DEBUGFUNC("wlanoidQueryAcpiDevicePowerState"); + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_DEVICE_POWER_STATE); + +#if DBG + prPowerState = (PPARAM_DEVICE_POWER_STATE)pvQueryBuffer; + switch (*prPowerState) { + case ParamDeviceStateD0: + DBGLOG(REQ, INFO, "Query Power State: D0\n"); + break; + + case ParamDeviceStateD1: + DBGLOG(REQ, INFO, "Query Power State: D1\n"); + break; + + case ParamDeviceStateD2: + DBGLOG(REQ, INFO, "Query Power State: D2\n"); + break; + + case ParamDeviceStateD3: + DBGLOG(REQ, INFO, "Query Power State: D3\n"); + break; + + default: + break; + } +#endif + + /* Since we will disconnect the newwork, therefore we do not + * need to check queue empty + */ + *(PPARAM_DEVICE_POWER_STATE)pvQueryBuffer = ParamDeviceStateD3; + /* WARNLOG(("Ready to transition to D3\n")); */ + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set ACPI device power state. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + PPARAM_DEVICE_POWER_STATE prPowerState; + u8 fgRetValue = true; + + DEBUGFUNC("wlanoidSetAcpiDevicePowerState"); + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_DEVICE_POWER_STATE); + + ASSERT(pvSetBuffer); + prPowerState = (PPARAM_DEVICE_POWER_STATE)pvSetBuffer; + switch (*prPowerState) { + case ParamDeviceStateD0: + DBGLOG(REQ, INFO, "Set Power State: D0\n"); + fgRetValue = nicpmSetAcpiPowerD0(prAdapter); + break; + + case ParamDeviceStateD1: + DBGLOG(REQ, INFO, "Set Power State: D1\n"); + + /* no break here */ + /* FALLTHRU */ + case ParamDeviceStateD2: + DBGLOG(REQ, INFO, "Set Power State: D2\n"); + + /* no break here */ + /* FALLTHRU */ + case ParamDeviceStateD3: + DBGLOG(REQ, INFO, "Set Power State: D3\n"); + fgRetValue = nicpmSetAcpiPowerD3(prAdapter); + break; + + default: + break; + } + + if (fgRetValue == true) { + return WLAN_STATUS_SUCCESS; + } else { + return WLAN_STATUS_FAILURE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the current fragmentation threshold. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryFragThreshold(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryFragThreshold"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + DBGLOG(REQ, LOUD, "\n"); + +#if CFG_TX_FRAGMENT + return WLAN_STATUS_SUCCESS; + +#else + return WLAN_STATUS_NOT_SUPPORTED; + +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set a new fragmentation threshold to the + * driver. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_DATA + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetFragThreshold(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ +#if CFG_TX_FRAGMENT + return WLAN_STATUS_SUCCESS; + +#else + return WLAN_STATUS_NOT_SUPPORTED; + +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the current RTS threshold. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryRtsThreshold(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryRtsThreshold"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + DBGLOG(REQ, LOUD, "\n"); + + if (u4QueryBufferLen < sizeof(PARAM_RTS_THRESHOLD)) { + *pu4QueryInfoLen = sizeof(PARAM_RTS_THRESHOLD); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + *((PARAM_RTS_THRESHOLD *)pvQueryBuffer) = + prAdapter->rWlanInfo.eRtsThreshold; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set a new RTS threshold to the driver. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_DATA + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetRtsThreshold(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + PARAM_RTS_THRESHOLD *prRtsThreshold; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_RTS_THRESHOLD); + if (u4SetBufferLen < sizeof(PARAM_RTS_THRESHOLD)) { + DBGLOG(REQ, WARN, "Invalid length %ld\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prRtsThreshold = (PARAM_RTS_THRESHOLD *)pvSetBuffer; + *prRtsThreshold = prAdapter->rWlanInfo.eRtsThreshold; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to turn radio off. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetDisassociate(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_MSG_AIS_ABORT_T prAisAbortMsg; + int ret; + + DEBUGFUNC("wlanoidSetDisassociate"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 0; + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in set disassociate! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + /* prepare message to AIS */ + prAdapter->rWifiVar.rConnSettings.fgIsConnReqIssued = false; + + /* Send AIS Abort Message */ + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + DBGLOG(REQ, ERROR, "Fail in creating AisAbortMsg.\n"); + return WLAN_STATUS_FAILURE; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_JOIN_REQ; + prAisAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_NEW_CONNECTION; + prAisAbortMsg->fgDelayIndication = false; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prAisAbortMsg, + MSG_SEND_METHOD_BUF); + + /* indicate for disconnection */ + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED) { + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY, NULL, + 0); + ret = WLAN_STATUS_SUCCESS; + } else { + ret = WLAN_STATUS_NOT_ACCEPTED; + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to query the power save profile. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuery802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQuery802dot11PowerSaveProfile"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen != 0) { + ASSERT(pvQueryBuffer); + + /**(PPARAM_POWER_MODE) pvQueryBuffer = + * (PARAM_POWER_MODE)(prAdapter->rWlanInfo.ePowerSaveMode.ucPsProfile); + */ + *(PPARAM_POWER_MODE)pvQueryBuffer = + (PARAM_POWER_MODE)(prAdapter->rWlanInfo + .arPowerSaveMode[prAdapter->prAisBssInfo + ->ucBssIndex] + .ucPsProfile); + *pu4QueryInfoLen = sizeof(PARAM_POWER_MODE); + + /* hack for CTIA power mode setting function */ + if (prAdapter->fgEnCtiaPowerMode) { + /* set to non-zero value (to prevent MMI query 0, */ + /* before it intends to set 0, which will skip its + * following state machine) */ + *(PPARAM_POWER_MODE)pvQueryBuffer = (PARAM_POWER_MODE)2; + } + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to set the power save profile. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSet802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS status; + P_PARAM_POWER_MODE_T prPowerMode; + P_BSS_INFO_T prBssInfo; + +#if !DBG_DISABLE_ALL_LOG + const u8 *apucPsMode[Param_PowerModeMax] = { + (u8 *)"CAM", + (u8 *)"MAX PS", + (u8 *)"FAST PS", +#ifdef SUPPORT_PERIODIC_PS + (u8 *)"PERIODICAL PS", +#endif + }; +#endif + + DEBUGFUNC("wlanoidSet802dot11PowerSaveProfile"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_POWER_MODE_T); + prPowerMode = (P_PARAM_POWER_MODE_T)pvSetBuffer; + + if (u4SetBufferLen < sizeof(PARAM_POWER_MODE_T)) { + DBGLOG(REQ, WARN, "Set power mode error: Invalid length %ld\n", + u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } else if (prPowerMode->ePowerMode >= Param_PowerModeMax) { + DBGLOG(REQ, WARN, "Set power mode error: Invalid power mode(%u)\n", + prPowerMode->ePowerMode); + return WLAN_STATUS_INVALID_DATA; + } else if (prPowerMode->ucBssIdx >= BSS_INFO_NUM) { + DBGLOG(REQ, WARN, "Set power mode error: Invalid BSS index(%u)\n", + prPowerMode->ucBssIdx); + return WLAN_STATUS_INVALID_DATA; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prPowerMode->ucBssIdx); + + if (prAdapter->fgEnCtiaPowerMode) { + if (prPowerMode->ePowerMode != Param_PowerModeCAM) { + /* User setting to PS mode (Param_PowerModeMAX_PSP or + * Param_PowerModeFast_PSP) */ + + if (prAdapter->u4CtiaPowerMode == 0) { + /* force to keep in CAM mode */ + prPowerMode->ePowerMode = Param_PowerModeCAM; + } else if (prAdapter->u4CtiaPowerMode == 1) { + prPowerMode->ePowerMode = Param_PowerModeMAX_PSP; + } else if (prAdapter->u4CtiaPowerMode == 2) { + prPowerMode->ePowerMode = Param_PowerModeFast_PSP; + } + } + } + + /* only CAM mode allowed when TP/Sigma on */ + if ((prAdapter->rWifiVar.ucTpTestMode == ENUM_TP_TEST_MODE_THROUGHPUT) || + (prAdapter->rWifiVar.ucTpTestMode == + ENUM_TP_TEST_MODE_SIGMA_AC_N_PMF)) { + prPowerMode->ePowerMode = Param_PowerModeCAM; + } + + /* for WMM PS Sigma certification, keep WiFi in ps mode continuously */ + /* force PS == Param_PowerModeMAX_PSP */ + if ((prAdapter->rWifiVar.ucTpTestMode == ENUM_TP_TEST_MODE_SIGMA_WMM_PS) && + (prPowerMode->ePowerMode >= Param_PowerModeMAX_PSP)) { + prPowerMode->ePowerMode = Param_PowerModeMAX_PSP; + } + + status = nicConfigPowerSaveProfile(prAdapter, prPowerMode->ucBssIdx, + prPowerMode->ePowerMode, true); + + if (prPowerMode->ePowerMode < Param_PowerModeMax) { + DBGLOG(INIT, INFO, "Set %s Network BSS(%u) PS mode to %s (%d)\n", + apucNetworkType[prBssInfo->eNetworkType], prPowerMode->ucBssIdx, + apucPsMode[prPowerMode->ePowerMode], prPowerMode->ePowerMode); + } else { + DBGLOG(INIT, INFO, + "Invalid PS mode setting (%d) for %s Network BSS(%u)\n", + prPowerMode->ePowerMode, + apucNetworkType[prBssInfo->eNetworkType], prPowerMode->ucBssIdx); + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query current status of AdHoc Mode. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryAdHocMode(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set AdHoc Mode. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAdHocMode(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query RF frequency. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryFrequency(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryFrequency"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < sizeof(u32)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) { + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED) { + *(u32 *)pvQueryBuffer = + nicChannelNum2Freq(prAdapter->prAisBssInfo->ucPrimaryChannel); + } else { + *(u32 *)pvQueryBuffer = 0; + } + } else { + *(u32 *)pvQueryBuffer = nicChannelNum2Freq( + prAdapter->rWifiVar.rConnSettings.ucAdHocChannelNum); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set RF frequency by User Settings. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetFrequency(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + u32 *pu4FreqInKHz; + + DEBUGFUNC("wlanoidSetFrequency"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(u32); + + if (u4SetBufferLen < sizeof(u32)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + pu4FreqInKHz = (u32 *)pvSetBuffer; + + prAdapter->rWifiVar.rConnSettings.ucAdHocChannelNum = + (u8)nicFreq2ChannelNum(*pu4FreqInKHz); + prAdapter->rWifiVar.rConnSettings.eAdHocBand = + *pu4FreqInKHz < 5000000 ? BAND_2G4 : BAND_5G; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set 802.11 channel of the radio frequency. + * This is a proprietary function call to Lunux currently. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetChannel(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + ASSERT(0); /* // */ + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the Beacon Interval from User + * Settings. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBeaconInterval(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryBeaconInterval"); + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(u32); + + if (u4QueryBufferLen < sizeof(u32)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED) { + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) { + *(u32 *)pvQueryBuffer = + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod; + } else { + *(u32 *)pvQueryBuffer = (u32)prAdapter->rWlanInfo.u2BeaconPeriod; + } + } else { + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) { + *(u32 *)pvQueryBuffer = 0; + } else { + *(u32 *)pvQueryBuffer = (u32)prAdapter->rWlanInfo.u2BeaconPeriod; + } + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set the Beacon Interval to User Settings. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBeaconInterval(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + u32 *pu4BeaconInterval; + + DEBUGFUNC("wlanoidSetBeaconInterval"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(u32); + if (u4SetBufferLen < sizeof(u32)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + pu4BeaconInterval = (u32 *)pvSetBuffer; + + if ((*pu4BeaconInterval < DOT11_BEACON_PERIOD_MIN) || + (*pu4BeaconInterval > DOT11_BEACON_PERIOD_MAX)) { + DBGLOG(REQ, TRACE, "Invalid Beacon Interval = %ld\n", + *pu4BeaconInterval); + return WLAN_STATUS_INVALID_DATA; + } + + prAdapter->rWlanInfo.u2BeaconPeriod = (u16) * pu4BeaconInterval; + + DBGLOG(REQ, INFO, "Set beacon interval: %d\n", + prAdapter->rWlanInfo.u2BeaconPeriod); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query the ATIM window from User Settings. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryAtimWindow(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryAtimWindow"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(u32); + + if (u4QueryBufferLen < sizeof(u32)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA) { + *(u32 *)pvQueryBuffer = 0; + } else { + *(u32 *)pvQueryBuffer = (u32)prAdapter->rWlanInfo.u2AtimWindow; + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set the ATIM window to User Settings. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAtimWindow(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + u32 *pu4AtimWindow; + + DEBUGFUNC("wlanoidSetAtimWindow"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(u32); + + if (u4SetBufferLen < sizeof(u32)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + pu4AtimWindow = (u32 *)pvSetBuffer; + + prAdapter->rWlanInfo.u2AtimWindow = (u16) * pu4AtimWindow; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set the MAC address which is currently used + * by the NIC. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCurrentAddr(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + ASSERT(0); /* // */ + + return WLAN_STATUS_SUCCESS; +} + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +/*----------------------------------------------------------------------------*/ +/*! + * \brief Setting the checksum offload function. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCSUMOffload(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + u32 u4CSUMFlags; + CMD_BASIC_CONFIG_T rCmdBasicConfig; + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; + + DEBUGFUNC("wlanoidSetCSUMOffload"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(u32); + + if (u4SetBufferLen < sizeof(u32)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + u4CSUMFlags = *(u32 *)pvSetBuffer; + + kalMemZero(&rCmdBasicConfig, sizeof(CMD_BASIC_CONFIG_T)); + + rCmdBasicConfig.ucNative80211 = 0; /* @FIXME: for Vista */ + + if (u4CSUMFlags & CSUM_OFFLOAD_EN_TX_TCP) { + rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(2); + } + + if (u4CSUMFlags & CSUM_OFFLOAD_EN_TX_UDP) { + rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(1); + } + + if (u4CSUMFlags & CSUM_OFFLOAD_EN_TX_IP) { + rCmdBasicConfig.rCsumOffload.u2TxChecksum |= BIT(0); + } + + if (u4CSUMFlags & CSUM_OFFLOAD_EN_RX_TCP) { + rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(2); + } + + if (u4CSUMFlags & CSUM_OFFLOAD_EN_RX_UDP) { + rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(1); + } + + if (u4CSUMFlags & (CSUM_OFFLOAD_EN_RX_IPv4 | CSUM_OFFLOAD_EN_RX_IPv6)) { + rCmdBasicConfig.rCsumOffload.u2RxChecksum |= BIT(0); + } + + prAdapter->u4CSUMFlags = u4CSUMFlags; + rCmdBasicConfig.ucCtrlFlagAssertPath = prWifiVar->ucCtrlFlagAssertPath; + rCmdBasicConfig.ucCtrlFlagDebugLevel = prWifiVar->ucCtrlFlagDebugLevel; + + wlanSendSetQueryCmd(prAdapter, CMD_ID_BASIC_CONFIG, true, false, true, NULL, + nicOidCmdTimeoutCommon, sizeof(CMD_BASIC_CONFIG_T), + (u8 *)&rCmdBasicConfig, pvSetBuffer, u4SetBufferLen); + + return WLAN_STATUS_SUCCESS; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Setting the IP address for pattern search function. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \return WLAN_STATUS_SUCCESS + * \return WLAN_STATUS_ADAPTER_NOT_READY + * \return WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetNetworkAddress(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 i, u4IPv4AddrIdx; + P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; + P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = + (P_PARAM_NETWORK_ADDRESS_LIST)pvSetBuffer; + P_PARAM_NETWORK_ADDRESS prNetworkAddress; + u32 u4IPv4AddrCount, u4CmdSize; + + DEBUGFUNC("wlanoidSetNetworkAddress"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 4; + + if (u4SetBufferLen < OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress)) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu4SetInfoLen = 0; + u4IPv4AddrCount = 0; + + /* 4 <1.1> Get IPv4 address count */ + /* We only suppot IPv4 address setting */ + prNetworkAddress = prNetworkAddressList->arAddress; + for (i = 0; i < prNetworkAddressList->u4AddressCount; i++) { + if ((prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP) && + (prNetworkAddress->u2AddressLength == IPV4_ADDR_LEN)) { + u4IPv4AddrCount++; + } + + prNetworkAddress = + (P_PARAM_NETWORK_ADDRESS)((unsigned long)prNetworkAddress + + (unsigned long)(prNetworkAddress + ->u2AddressLength + + OFFSET_OF( + PARAM_NETWORK_ADDRESS, + aucAddress))); + } + + /* 4 <2> Calculate command buffer size */ + /* construct payload of command packet */ + if (u4IPv4AddrCount == 0) { + u4CmdSize = sizeof(CMD_SET_NETWORK_ADDRESS_LIST); + } else { + u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + + (sizeof(IPV4_NETWORK_ADDRESS) * u4IPv4AddrCount); + } + + /* 4 <3> Allocate command buffer */ + prCmdNetworkAddressList = + (P_CMD_SET_NETWORK_ADDRESS_LIST)kalMemAlloc(u4CmdSize, VIR_MEM_TYPE); + + if (prCmdNetworkAddressList == NULL) { + return WLAN_STATUS_FAILURE; + } + + kalMemZero(prCmdNetworkAddressList, u4CmdSize); + + /* 4 <4> Fill P_CMD_SET_NETWORK_ADDRESS_LIST */ + prCmdNetworkAddressList->ucBssIndex = prNetworkAddressList->ucBssIdx; + + /* only to set IP address to FW once ARP filter is enabled */ + if (prAdapter->fgEnArpFilter) { + prCmdNetworkAddressList->ucAddressCount = (u8)u4IPv4AddrCount; + prNetworkAddress = prNetworkAddressList->arAddress; + + /* DBGLOG(INIT, INFO, ("%s: u4IPv4AddrCount (%lu)\n", + * __FUNCTION__, u4IPv4AddrCount)); */ + + for (i = 0, u4IPv4AddrIdx = 0; i < prNetworkAddressList->u4AddressCount; + i++) { + if (prNetworkAddress->u2AddressType == PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == IPV4_ADDR_LEN) { + kalMemCopy(prCmdNetworkAddressList->arNetAddress[u4IPv4AddrIdx] + .aucIpAddr, + prNetworkAddress->aucAddress, sizeof(u32)); + + DBGLOG(INIT, INFO, "%s: IPv4 Addr [%u][" IPV4STR "]\n", + __func__, u4IPv4AddrIdx, + IPV4TOSTR(prNetworkAddress->aucAddress)); + + u4IPv4AddrIdx++; + } + + prNetworkAddress = + (P_PARAM_NETWORK_ADDRESS)((unsigned long)prNetworkAddress + + (unsigned long)(prNetworkAddress + ->u2AddressLength + + OFFSET_OF( + PARAM_NETWORK_ADDRESS, + aucAddress))); + } + } else { + prCmdNetworkAddressList->ucAddressCount = 0; + } + + DBGLOG(INIT, INFO, "%s: Set %lu IPv4 address for BSS[%u]\n", __func__, + u4IPv4AddrCount, prCmdNetworkAddressList->ucBssIndex); + + /* 4 <5> Send command */ + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_IP_ADDRESS, true, false, + true, nicCmdEventSetIpAddress, + nicOidCmdTimeoutCommon, u4CmdSize, + (u8 *)prCmdNetworkAddressList, pvSetBuffer, + u4SetBufferLen); + + kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Set driver to switch into RF test mode + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set, + * should be NULL + * \param[in] u4SetBufferLen The length of the set buffer, should be 0 + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \return WLAN_STATUS_SUCCESS + * \return WLAN_STATUS_ADAPTER_NOT_READY + * \return WLAN_STATUS_INVALID_DATA + * \return WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidRftestSetTestMode(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rStatus; + CMD_TEST_CTRL_T rCmdTestCtrl; + + DEBUGFUNC("wlanoidRftestSetTestMode"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + kalMemZero(&rCmdTestCtrl, sizeof(CMD_TEST_CTRL_T)); + + *pu4SetInfoLen = 0; + + if (u4SetBufferLen == 0) { + if ((prAdapter->fgTestMode == false) || + (prAdapter->fgIcapMode == true)) { + /* switch to RF Test mode */ + rCmdTestCtrl.ucAction = 0; /* Switch mode */ + rCmdTestCtrl.u.u4OpMode = 1; /* RF test mode */ + + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_TEST_CTRL, true, + false, true, nicCmdEventEnterRfTest, + nicOidCmdEnterRFTestTimeout, + sizeof(CMD_TEST_CTRL_T), + (u8 *)&rCmdTestCtrl, pvSetBuffer, + u4SetBufferLen); + } else { + /* already in test mode .. */ + rStatus = WLAN_STATUS_SUCCESS; + } + } else { + rStatus = WLAN_STATUS_INVALID_DATA; + } + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Set driver to switch into RF test ICAP mode + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set, + * should be NULL + * \param[in] u4SetBufferLen The length of the set buffer, should be 0 + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \return WLAN_STATUS_SUCCESS + * \return WLAN_STATUS_ADAPTER_NOT_READY + * \return WLAN_STATUS_INVALID_DATA + * \return WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidRftestSetTestIcapMode(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rStatus; + CMD_TEST_CTRL_T rCmdTestCtrl; + + DEBUGFUNC("wlanoidRftestSetTestIcapMode"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + kalMemZero(&rCmdTestCtrl, sizeof(CMD_TEST_CTRL_T)); + + *pu4SetInfoLen = 0; + + if (u4SetBufferLen == 0) { + if (prAdapter->fgIcapMode == false) { + /* switch to RF Test mode */ + rCmdTestCtrl.ucAction = 0; /* Switch mode */ + rCmdTestCtrl.u.u4OpMode = 2; /* RF test mode */ + + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_TEST_CTRL, true, + false, true, nicCmdEventEnterRfTest, + nicOidCmdEnterRFTestTimeout, + sizeof(CMD_TEST_CTRL_T), + (u8 *)&rCmdTestCtrl, pvSetBuffer, + u4SetBufferLen); + } else { + /* already in ICAP mode .. */ + rStatus = WLAN_STATUS_SUCCESS; + } + } else { + rStatus = WLAN_STATUS_INVALID_DATA; + } + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Set driver to switch into normal operation mode from RF test mode + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set + * should be NULL + * \param[in] u4SetBufferLen The length of the set buffer, should be 0 + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \return WLAN_STATUS_SUCCESS + * \return WLAN_STATUS_ADAPTER_NOT_READY + * \return WLAN_STATUS_INVALID_DATA + * \return WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidRftestSetAbortTestMode(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rStatus; + CMD_TEST_CTRL_T rCmdTestCtrl; + + DEBUGFUNC("wlanoidRftestSetAbortTestMode"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + kalMemZero(&rCmdTestCtrl, sizeof(CMD_TEST_CTRL_T)); + + *pu4SetInfoLen = 0; + + if (u4SetBufferLen == 0) { + if (prAdapter->fgTestMode == true) { + /* switch to normal mode */ + rCmdTestCtrl.ucAction = 0; /* Switch mode */ + rCmdTestCtrl.u.u4OpMode = 0; /* normal mode */ + + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_TEST_CTRL, true, + false, true, nicCmdEventLeaveRfTest, + nicOidCmdTimeoutCommon, + sizeof(CMD_TEST_CTRL_T), + (u8 *)&rCmdTestCtrl, pvSetBuffer, + u4SetBufferLen); + } else { + /* already in normal mode .. */ + rStatus = WLAN_STATUS_SUCCESS; + } + } else { + rStatus = WLAN_STATUS_INVALID_DATA; + } + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief query for RF test parameter + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + * \retval WLAN_STATUS_NOT_SUPPORTED + * \retval WLAN_STATUS_NOT_ACCEPTED + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidRftestQueryAutoTest(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_MTK_WIFI_TEST_STRUCT_T prRfATInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidRftestQueryAutoTest"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T); + + if (u4QueryBufferLen != sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T)) { + DBGLOG(REQ, ERROR, "Invalid data. QueryBufferLen: %ld.\n", + u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prRfATInfo = (P_PARAM_MTK_WIFI_TEST_STRUCT_T)pvQueryBuffer; + rStatus = rftestQueryATInfo(prAdapter, prRfATInfo->u4FuncIndex, + prRfATInfo->u4FuncData, pvQueryBuffer, + u4QueryBufferLen); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Set RF test parameter + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \return WLAN_STATUS_SUCCESS + * \return WLAN_STATUS_ADAPTER_NOT_READY + * \return WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidRftestSetAutoTest(IN P_ADAPTER_T prAdapter, OUT void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_MTK_WIFI_TEST_STRUCT_T prRfATInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidRftestSetAutoTest"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T); + + if (u4SetBufferLen != sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T)) { + DBGLOG(REQ, ERROR, "Invalid data. SetBufferLen: %ld.\n", + u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prRfATInfo = (P_PARAM_MTK_WIFI_TEST_STRUCT_T)pvSetBuffer; + rStatus = rftestSetATInfo(prAdapter, prRfATInfo->u4FuncIndex, + prRfATInfo->u4FuncData); + + return rStatus; +} + +/* RF test OID set handler */ +WLAN_STATUS rftestSetATInfo(IN P_ADAPTER_T prAdapter, u32 u4FuncIndex, + u32 u4FuncData) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_CMD_TEST_CTRL_T pCmdTestCtrl; + u8 ucCmdSeqNum; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + (CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T))); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = true; + prCmdInfo->ucCID = CMD_ID_TEST_CTRL; + prCmdInfo->fgSetQuery = true; + prCmdInfo->fgNeedResp = false; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_TEST_CTRL_T); + prCmdInfo->pvInformationBuffer = NULL; + prCmdInfo->u4InformationBufferLength = 0; + + /* Setup WIFI_CMD_T (payload = CMD_TEST_CTRL_T) */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + pCmdTestCtrl = (P_CMD_TEST_CTRL_T)(prWifiCmd->aucBuffer); + pCmdTestCtrl->ucAction = 1; /* Set ATInfo */ + pCmdTestCtrl->u.rRfATInfo.u4FuncIndex = u4FuncIndex; + pCmdTestCtrl->u.rRfATInfo.u4FuncData = u4FuncData; + + if ((u4FuncIndex == RF_AT_FUNCID_COMMAND) && + (u4FuncData == RF_AT_COMMAND_ICAP)) { + g_bIcapEnable = true; + g_bCaptureDone = false; + } + /* ICAP dump name Reset */ + if ((u4FuncIndex == RF_AT_FUNCID_COMMAND) && + (u4FuncData == RF_AT_COMMAND_RESET_DUMP_NAME)) { + g_u2DumpIndex = 0; + } + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prAdapter->prGlueInfo); + + return WLAN_STATUS_PENDING; +} + +WLAN_STATUS +rftestQueryATInfo(IN P_ADAPTER_T prAdapter, u32 u4FuncIndex, u32 u4FuncData, + OUT void *pvQueryBuffer, IN u32 u4QueryBufferLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + P_CMD_TEST_CTRL_T pCmdTestCtrl; + u8 ucCmdSeqNum; + P_EVENT_TEST_STATUS prTestStatus; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + + if (u4FuncIndex == RF_AT_FUNCID_FW_INFO) { + /* driver implementation */ + prTestStatus = (P_EVENT_TEST_STATUS)pvQueryBuffer; + + prTestStatus->rATInfo.u4FuncData = + (prAdapter->rVerInfo.u2FwProductID << 16) | + (prAdapter->rVerInfo.u2FwOwnVersion); + u4QueryBufferLen = sizeof(EVENT_TEST_STATUS); + + return WLAN_STATUS_SUCCESS; + } else if (u4FuncIndex == RF_AT_FUNCID_DRV_INFO) { + /* driver implementation */ + prTestStatus = (P_EVENT_TEST_STATUS)pvQueryBuffer; + + prTestStatus->rATInfo.u4FuncData = CFG_DRV_OWN_VERSION; + u4QueryBufferLen = sizeof(EVENT_TEST_STATUS); + + return WLAN_STATUS_SUCCESS; + } else if (u4FuncIndex == RF_AT_FUNCID_QUERY_ICAP_DUMP_FILE) { + /* driver implementation */ + prTestStatus = (P_EVENT_TEST_STATUS)pvQueryBuffer; + + prTestStatus->rATInfo.u4FuncData = g_u2DumpIndex; + u4QueryBufferLen = sizeof(EVENT_TEST_STATUS); + + return WLAN_STATUS_SUCCESS; + } + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + (CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T))); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + + /* Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(CMD_TEST_CTRL_T); + prCmdInfo->pfCmdDoneHandler = nicCmdEventQueryRfTestATInfo; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = true; + prCmdInfo->ucCID = CMD_ID_TEST_CTRL; + prCmdInfo->fgSetQuery = false; + prCmdInfo->fgNeedResp = true; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = sizeof(CMD_TEST_CTRL_T); + prCmdInfo->pvInformationBuffer = pvQueryBuffer; + prCmdInfo->u4InformationBufferLength = u4QueryBufferLen; + + /* Setup WIFI_CMD_T (payload = CMD_TEST_CTRL_T) */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + pCmdTestCtrl = (P_CMD_TEST_CTRL_T)(prWifiCmd->aucBuffer); + pCmdTestCtrl->ucAction = 2; /* Get ATInfo */ + pCmdTestCtrl->u.rRfATInfo.u4FuncIndex = u4FuncIndex; + pCmdTestCtrl->u.rRfATInfo.u4FuncData = u4FuncData; + + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prAdapter->prGlueInfo); + + return WLAN_STATUS_PENDING; +} + +WLAN_STATUS rftestSetFrequency(IN P_ADAPTER_T prAdapter, IN u32 u4FreqInKHz, + IN u32 *pu4SetInfoLen) +{ + CMD_TEST_CTRL_T rCmdTestCtrl; + + ASSERT(prAdapter); + kalMemZero(&rCmdTestCtrl, sizeof(CMD_TEST_CTRL_T)); + + rCmdTestCtrl.ucAction = 5; /* Set Channel Frequency */ + rCmdTestCtrl.u.u4ChannelFreq = u4FreqInKHz; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_TEST_CTRL, true, false, true, + nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + sizeof(CMD_TEST_CTRL_T), (u8 *)&rCmdTestCtrl, + NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief command packet generation utility + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] ucCID Command ID + * \param[in] fgSetQuery Set or Query + * \param[in] fgNeedResp Need for response + * \param[in] pfCmdDoneHandler Function pointer when command is done + * \param[in] u4SetQueryInfoLen The length of the set/query buffer + * \param[in] pucInfoBuffer Pointer to set/query buffer + * + * + * \retval WLAN_STATUS_PENDING + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanSendSetQueryCmd(IN P_ADAPTER_T prAdapter, u8 ucCID, u8 fgSetQuery, + u8 fgNeedResp, u8 fgIsOid, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + u32 u4SetQueryInfoLen, u8 *pucInfoBuffer, + OUT void *pvSetQueryBuffer, IN u32 u4SetQueryBufferLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + u8 ucCmdSeqNum; + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = + cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u4SetQueryInfoLen)); + + DEBUGFUNC("wlanSendSetQueryCmd"); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); + + /* Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->u2InfoBufLen = (u16)(CMD_HDR_SIZE + u4SetQueryInfoLen); + prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; + prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; + prCmdInfo->fgIsOid = fgIsOid; + prCmdInfo->ucCID = ucCID; + prCmdInfo->fgSetQuery = fgSetQuery; + prCmdInfo->fgNeedResp = fgNeedResp; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; + prCmdInfo->pvInformationBuffer = pvSetQueryBuffer; + prCmdInfo->u4InformationBufferLength = u4SetQueryBufferLen; + + /* Setup WIFI_CMD_T (no payload) */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->u2Length = + prCmdInfo->u2InfoBufLen - (u16)OFFSET_OF(WIFI_CMD_T, u2Length); + prWifiCmd->u2PqId = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + if (u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) { + kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, u4SetQueryInfoLen); + } + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + return WLAN_STATUS_PENDING; +} + +#if CFG_SUPPORT_WPS2 +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called by WSC to set the assoc info, which is needed + * to add to Association request frame while join WPS AP. + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set + * \param[in] u4SetBufferLen The length of the set buffer + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed due to invalid length of + * the set buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. + * \retval WLAN_STATUS_INVALID_LENGTH + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetWSCAssocInfo(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + DEBUGFUNC("wlanoidSetWSCAssocInfo"); + DBGLOG(REQ, LOUD, "\r\n"); + + if (u4SetBufferLen == 0) { + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = u4SetBufferLen; + + kalMemCopy(prAdapter->prGlueInfo->aucWSCAssocInfoIE, pvSetBuffer, + u4SetBufferLen); + prAdapter->prGlueInfo->u2WSCAssocInfoIELen = (u16)u4SetBufferLen; + DBGLOG(SEC, TRACE, "Assoc Info IE sz %ld\n", u4SetBufferLen); + + return WLAN_STATUS_SUCCESS; +} +#endif + +#if CFG_ENABLE_WAKEUP_ON_LAN +WLAN_STATUS +wlanoidSetAddWakeupPattern(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_PM_PACKET_PATTERN prPacketPattern; + + DEBUGFUNC("wlanoidSetAddWakeupPattern"); + DBGLOG(REQ, LOUD, "\r\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_PM_PACKET_PATTERN); + + if (u4SetBufferLen < sizeof(PARAM_PM_PACKET_PATTERN)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prPacketPattern = (P_PARAM_PM_PACKET_PATTERN)pvSetBuffer; + + /* FIXME: Send the struct to firmware */ + + return WLAN_STATUS_FAILURE; +} + +WLAN_STATUS +wlanoidSetRemoveWakeupPattern(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_PM_PACKET_PATTERN prPacketPattern; + + DEBUGFUNC("wlanoidSetAddWakeupPattern"); + DBGLOG(REQ, LOUD, "\r\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_PM_PACKET_PATTERN); + + if (u4SetBufferLen < sizeof(PARAM_PM_PACKET_PATTERN)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prPacketPattern = (P_PARAM_PM_PACKET_PATTERN)pvSetBuffer; + + /* FIXME: Send the struct to firmware */ + + return WLAN_STATUS_FAILURE; +} + +WLAN_STATUS +wlanoidQueryEnableWakeup(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + u32 *pu4WakeupEventEnable; + + DEBUGFUNC("wlanoidQueryEnableWakeup"); + DBGLOG(REQ, LOUD, "\r\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(u32); + + if (u4QueryBufferLen < sizeof(u32)) { + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + pu4WakeupEventEnable = (u32 *)pvQueryBuffer; + + *pu4WakeupEventEnable = prAdapter->u4WakeupEventEnable; + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS +wlanoidSetEnableWakeup(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + u32 *pu4WakeupEventEnable; + + DEBUGFUNC("wlanoidSetEnableWakup"); + DBGLOG(REQ, LOUD, "\r\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(u32); + + if (u4SetBufferLen < sizeof(u32)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + pu4WakeupEventEnable = (u32 *)pvSetBuffer; + prAdapter->u4WakeupEventEnable = *pu4WakeupEventEnable; + + /* FIXME: Send Command Event for setting wakeup-pattern / Magic Packet + * to firmware */ + + return WLAN_STATUS_FAILURE; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to configure PS related settings for WMM-PS + * test. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetWiFiWmmPsTest(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T prWmmPsTestInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + CMD_SET_WMM_PS_TEST_STRUCT_T rSetWmmPsTestParam; + u16 u2CmdBufLen; + P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; + P_BSS_INFO_T prBssInfo; + + DEBUGFUNC("wlanoidSetWiFiWmmPsTest"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T); + + prWmmPsTestInfo = (P_PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T)pvSetBuffer; + + rSetWmmPsTestParam.ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex; + rSetWmmPsTestParam.bmfgApsdEnAc = prWmmPsTestInfo->bmfgApsdEnAc; + rSetWmmPsTestParam.ucIsEnterPsAtOnce = prWmmPsTestInfo->ucIsEnterPsAtOnce; + rSetWmmPsTestParam.ucIsDisableUcTrigger = + prWmmPsTestInfo->ucIsDisableUcTrigger; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, rSetWmmPsTestParam.ucBssIndex); + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + prPmProfSetupInfo->ucBmpDeliveryAC = + (rSetWmmPsTestParam.bmfgApsdEnAc >> 4) & BITS(0, 3); + prPmProfSetupInfo->ucBmpTriggerAC = rSetWmmPsTestParam.bmfgApsdEnAc & + BITS(0, 3); + + u2CmdBufLen = sizeof(CMD_SET_WMM_PS_TEST_STRUCT_T); + + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_WMM_PS_TEST_PARMS, true, + false, true, nicCmdEventSetCommon, /* TODO? */ + nicCmdTimeoutCommon, u2CmdBufLen, + (u8 *)&rSetWmmPsTestParam, NULL, 0); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to configure enable/disable TX A-MPDU feature. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetTxAmpdu(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + CMD_TX_AMPDU_T rTxAmpdu; + u16 u2CmdBufLen; + u8 *pfgEnable; + + DEBUGFUNC("wlanoidSetTxAmpdu"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + kalMemZero(&rTxAmpdu, sizeof(CMD_TX_AMPDU_T)); + + *pu4SetInfoLen = sizeof(u8); + + pfgEnable = (u8 *)pvSetBuffer; + + rTxAmpdu.fgEnable = *pfgEnable; + + u2CmdBufLen = sizeof(CMD_TX_AMPDU_T); + + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_TX_AMPDU, true, false, true, + NULL, NULL, u2CmdBufLen, (u8 *)&rTxAmpdu, + NULL, 0); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to configure reject/accept ADDBA Request. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetAddbaReject(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + CMD_ADDBA_REJECT_T rAddbaReject; + u16 u2CmdBufLen; + u8 *pfgEnable; + + DEBUGFUNC("wlanoidSetAddbaReject"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + kalMemZero(&rAddbaReject, sizeof(CMD_ADDBA_REJECT_T)); + + *pu4SetInfoLen = sizeof(u8); + + pfgEnable = (u8 *)pvSetBuffer; + + rAddbaReject.fgEnable = *pfgEnable; + + u2CmdBufLen = sizeof(CMD_ADDBA_REJECT_T); + + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_ADDBA_REJECT, true, false, + true, NULL, NULL, u2CmdBufLen, + (u8 *)&rAddbaReject, NULL, 0); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query NVRAM value. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryNvramRead(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T prNvramRwInfo; + u16 u2Data; + u8 fgStatus; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQueryNvramRead"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T); + + if (u4QueryBufferLen < sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prNvramRwInfo = (P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T)pvQueryBuffer; + + if (prNvramRwInfo->ucEepromMethod == PARAM_EEPROM_READ_METHOD_READ) { + fgStatus = + kalCfgDataRead16(prAdapter->prGlueInfo, + prNvramRwInfo->ucEepromIndex << 1, /* change to + * byte offset + */ + &u2Data); + + if (fgStatus) { + prNvramRwInfo->u2EepromData = u2Data; + DBGLOG(REQ, INFO, "NVRAM Read: index=%#X, data=%#02X\r\n", + prNvramRwInfo->ucEepromIndex, u2Data); + } else { + DBGLOG(REQ, ERROR, "NVRAM Read Failed: index=%#x.\r\n", + prNvramRwInfo->ucEepromIndex); + rStatus = WLAN_STATUS_FAILURE; + } + } else if (prNvramRwInfo->ucEepromMethod == + PARAM_EEPROM_READ_METHOD_GETSIZE) { + prNvramRwInfo->u2EepromData = CFG_FILE_WIFI_REC_SIZE; + DBGLOG(REQ, INFO, "EEPROM size =%d\r\n", prNvramRwInfo->u2EepromData); + } + + *pu4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to write NVRAM value. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetNvramWrite(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T prNvramRwInfo; + u8 fgStatus; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidSetNvramWrite"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prNvramRwInfo = (P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T)pvSetBuffer; + + fgStatus = kalCfgDataWrite16(prAdapter->prGlueInfo, + prNvramRwInfo->ucEepromIndex << 1, /* change + * to + * byte + * offset + */ + prNvramRwInfo->u2EepromData); + + if (fgStatus == false) { + DBGLOG(REQ, ERROR, "NVRAM Write Failed.\r\n"); + rStatus = WLAN_STATUS_FAILURE; + } + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to get the config data source type. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryCfgSrcType(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + ASSERT(prAdapter); + + *pu4QueryInfoLen = sizeof(ENUM_CFG_SRC_TYPE_T); + + if (kalIsConfigurationExist(prAdapter->prGlueInfo) == true) { + *(P_ENUM_CFG_SRC_TYPE_T)pvQueryBuffer = CFG_SRC_TYPE_NVRAM; + } else { + *(P_ENUM_CFG_SRC_TYPE_T)pvQueryBuffer = CFG_SRC_TYPE_EEPROM; + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to get the config data source type. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryEepromType(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + ASSERT(prAdapter); + + *pu4QueryInfoLen = sizeof(P_ENUM_EEPROM_TYPE_T); + +#if CFG_SUPPORT_NIC_CAPABILITY + if (prAdapter->fgIsEepromUsed == true) { + *(P_ENUM_EEPROM_TYPE_T)pvQueryBuffer = EEPROM_TYPE_PRESENT; + } else { + *(P_ENUM_EEPROM_TYPE_T)pvQueryBuffer = EEPROM_TYPE_NO; + } +#else + *(P_ENUM_EEPROM_TYPE_T)pvQueryBuffer = EEPROM_TYPE_NO; +#endif + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to get the config data source type. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetCountryCode(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + u8 *pucCountry; + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + + if (regd_is_single_sku_en()) { + rlmDomainOidSetCountry(prAdapter, pvSetBuffer, u4SetBufferLen); + *pu4SetInfoLen = u4SetBufferLen; + return WLAN_STATUS_SUCCESS; + } + + ASSERT(u4SetBufferLen == 2); + + *pu4SetInfoLen = 2; + + pucCountry = pvSetBuffer; + + prAdapter->rWifiVar.rConnSettings.u2CountryCode = + (((u16)pucCountry[0]) << 8) | ((u16)pucCountry[1]); + + /* Force to re-search country code in country domains */ + prAdapter->prDomainInfo = NULL; + rlmDomainSendCmd(prAdapter, true); + + /* Update supported channel list in channel table based on current + * country domain */ + wlanUpdateChannelTable(prAdapter->prGlueInfo); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set BT profile or BT information and the + * driver will set the built-in PTA configuration into chip. + * + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBT(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PTA_IPC_T prPtaIpc; + + DEBUGFUNC("wlanoidSetBT.\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PTA_IPC_T); + if (u4SetBufferLen != sizeof(PTA_IPC_T)) { + /* WARNLOG(("Invalid length %ld\n", u4SetBufferLen)); */ + return WLAN_STATUS_INVALID_LENGTH; + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, "Fail to set BT profile because of ACPI_D3\n"); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pvSetBuffer); + prPtaIpc = (P_PTA_IPC_T)pvSetBuffer; + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG + DBGLOG(INIT, INFO, "BCM BWCS CMD: BWCS CMD = %02x%02x%02x%02x\n", + prPtaIpc->u.aucBTPParams[0], prPtaIpc->u.aucBTPParams[1], + prPtaIpc->u.aucBTPParams[2], prPtaIpc->u.aucBTPParams[3]); + + DBGLOG(INIT, INFO, + "BCM BWCS CMD: aucBTPParams[0]=%02x, aucBTPParams[1]=%02x, " + "aucBTPParams[2]=%02x, aucBTPParams[3]=%02x.\n", + prPtaIpc->u.aucBTPParams[0], prPtaIpc->u.aucBTPParams[1], + prPtaIpc->u.aucBTPParams[2], prPtaIpc->u.aucBTPParams[3]); +#endif + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_BWCS, true, false, false, NULL, + NULL, sizeof(PTA_IPC_T), (u8 *)prPtaIpc, NULL, 0); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to query current BT profile and BTCR values + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBT(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + /* P_PARAM_PTA_IPC_T prPtaIpc; */ + /* u32 u4QueryBuffLen; */ + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(PTA_IPC_T); + + /* Check for query buffer length */ + if (u4QueryBufferLen != sizeof(PTA_IPC_T)) { + DBGLOG(REQ, WARN, "Invalid length %lu\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvQueryBuffer); + /* prPtaIpc = (P_PTA_IPC_T)pvQueryBuffer; */ + /* prPtaIpc->ucCmd = BT_CMD_PROFILE; */ + /* prPtaIpc->ucLen = sizeof(prPtaIpc->u); */ + /* nicPtaGetProfile(prAdapter, (u8 *)&prPtaIpc->u, &u4QueryBuffLen); */ + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set Tx power profile. + * + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetTxPower(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_SET_TXPWR_CTRL_T pTxPwr = (P_SET_TXPWR_CTRL_T)pvSetBuffer; + P_SET_TXPWR_CTRL_T prCmd; + u32 i; + WLAN_STATUS rStatus; + + DEBUGFUNC("wlanoidSetTxPower"); + DBGLOG(REQ, LOUD, "\r\n"); + + prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(SET_TXPWR_CTRL_T)); + kalMemZero(prCmd, sizeof(SET_TXPWR_CTRL_T)); + prCmd->c2GLegacyStaPwrOffset = pTxPwr->c2GLegacyStaPwrOffset; + prCmd->c2GHotspotPwrOffset = pTxPwr->c2GHotspotPwrOffset; + prCmd->c2GP2pPwrOffset = pTxPwr->c2GP2pPwrOffset; + prCmd->c2GBowPwrOffset = pTxPwr->c2GBowPwrOffset; + prCmd->c5GLegacyStaPwrOffset = pTxPwr->c5GLegacyStaPwrOffset; + prCmd->c5GHotspotPwrOffset = pTxPwr->c5GHotspotPwrOffset; + prCmd->c5GP2pPwrOffset = pTxPwr->c5GP2pPwrOffset; + prCmd->c5GBowPwrOffset = pTxPwr->c5GBowPwrOffset; + prCmd->ucConcurrencePolicy = pTxPwr->ucConcurrencePolicy; + for (i = 0; i < 14; i++) + prCmd->acTxPwrLimit2G[i] = pTxPwr->acTxPwrLimit2G[i]; + + for (i = 0; i < 4; i++) + prCmd->acTxPwrLimit5G[i] = pTxPwr->acTxPwrLimit5G[i]; + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + + /* + * DBGLOG(INIT, INFO, "c2GLegacyStaPwrOffset=%d\n", + * pTxPwr->c2GLegacyStaPwrOffset); DBGLOG(INIT, INFO, + * "c2GHotspotPwrOffset=%d\n", pTxPwr->c2GHotspotPwrOffset); + * DBGLOG(INIT, INFO, "c2GP2pPwrOffset=%d\n", pTxPwr->c2GP2pPwrOffset); + * DBGLOG(INIT, INFO, "c2GBowPwrOffset=%d\n", pTxPwr->c2GBowPwrOffset); + * DBGLOG(INIT, INFO, "c5GLegacyStaPwrOffset=%d\n", + * pTxPwr->c5GLegacyStaPwrOffset); DBGLOG(INIT, INFO, + * "c5GHotspotPwrOffset=%d\n", pTxPwr->c5GHotspotPwrOffset); + * DBGLOG(INIT, INFO, "c5GP2pPwrOffset=%d\n", pTxPwr->c5GP2pPwrOffset); + * DBGLOG(INIT, INFO, "c5GBowPwrOffset=%d\n", pTxPwr->c5GBowPwrOffset); + * DBGLOG(INIT, INFO, "ucConcurrencePolicy=%d\n", + * pTxPwr->ucConcurrencePolicy); + * + * for (i = 0; i < 14; i++) + * DBGLOG(INIT, INFO, "acTxPwrLimit2G[%d]=%d\n", i, + * pTxPwr->acTxPwrLimit2G[i]); + * + * for (i = 0; i < 4; i++) + * DBGLOG(INIT, INFO, "acTxPwrLimit5G[%d]=%d\n", i, + * pTxPwr->acTxPwrLimit5G[i]); + */ + + rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SET_TXPWR_CTRL, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + true, /* fgIsOid */ + nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + sizeof(SET_TXPWR_CTRL_T), /* u4SetQueryInfoLen + */ + (u8 *)prCmd, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + /* ASSERT(rStatus == WLAN_STATUS_PENDING); */ + cnmMemFree(prAdapter, prCmd); + + return rStatus; +} + +WLAN_STATUS wlanSendMemDumpCmd(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen) +{ + P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T prMemDumpInfo; + P_CMD_DUMP_MEM prCmdDumpMem; + CMD_DUMP_MEM rCmdDumpMem; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4MemSize = PARAM_MEM_DUMP_MAX_SIZE; + + u32 u4RemainLeng = 0; + u32 u4CurAddr = 0; + u8 ucFragNum = 0; + + prCmdDumpMem = &rCmdDumpMem; + prMemDumpInfo = (P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T)pvQueryBuffer; + + u4RemainLeng = prMemDumpInfo->u4RemainLength; + u4CurAddr = prMemDumpInfo->u4Address + prMemDumpInfo->u4Length; + ucFragNum = prMemDumpInfo->ucFragNum + 1; + + /* Query. If request length is larger than max length, do it as ping + * pong. Send a command and wait for a event. Send next command while + * the event is received. + * + */ + do { + u32 u4CurLeng = 0; + + if (u4RemainLeng > u4MemSize) { + u4CurLeng = u4MemSize; + u4RemainLeng -= u4MemSize; + } else { + u4CurLeng = u4RemainLeng; + u4RemainLeng = 0; + } + + prCmdDumpMem->u4Address = u4CurAddr; + prCmdDumpMem->u4Length = u4CurLeng; + prCmdDumpMem->u4RemainLength = u4RemainLeng; + prCmdDumpMem->ucFragNum = ucFragNum; +#if CFG_SUPPORT_QA_TOOL + prCmdDumpMem->u4IcapContent = prMemDumpInfo->u4IcapContent; +#endif + + DBGLOG(REQ, TRACE, "[%d] 0x%lX, len %lu, remain len %lu\n", ucFragNum, + prCmdDumpMem->u4Address, prCmdDumpMem->u4Length, + prCmdDumpMem->u4RemainLength); + + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_DUMP_MEM, false, true, + true, nicCmdEventQueryMemDump, + nicOidCmdTimeoutCommon, + sizeof(CMD_DUMP_MEM), (u8 *)prCmdDumpMem, + pvQueryBuffer, u4QueryBufferLen); + } while (false); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to dump memory. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryMemDump(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T prMemDumpInfo; + + DEBUGFUNC("wlanoidQueryMemDump"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + *pu4QueryInfoLen = sizeof(u32); + + prMemDumpInfo = (P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T)pvQueryBuffer; + DBGLOG(REQ, TRACE, "Dump 0x%lX, len %lu\n", prMemDumpInfo->u4Address, + prMemDumpInfo->u4Length); + + prMemDumpInfo->u4RemainLength = prMemDumpInfo->u4Length; + prMemDumpInfo->u4Length = 0; + prMemDumpInfo->ucFragNum = 0; + + return wlanSendMemDumpCmd(prAdapter, pvQueryBuffer, u4QueryBufferLen); +} + +#if CFG_ENABLE_WIFI_DIRECT +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to set the p2p mode. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2pMode(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_PARAM_CUSTOM_P2P_SET_STRUCT_T prSetP2P = + (P_PARAM_CUSTOM_P2P_SET_STRUCT_T)NULL; + /* P_MSG_P2P_NETDEV_REGISTER_T prP2pNetdevRegMsg = + * (P_MSG_P2P_NETDEV_REGISTER_T)NULL; */ + DEBUGFUNC("wlanoidSetP2pMode"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T); + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T)) { + DBGLOG(REQ, WARN, "Invalid length %ld\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prSetP2P = (P_PARAM_CUSTOM_P2P_SET_STRUCT_T)pvSetBuffer; + + DBGLOG(P2P, INFO, "Set P2P enable[%ld] mode[%ld]\n", prSetP2P->u4Enable, + prSetP2P->u4Mode); + + /* + * enable = 1, mode = 0 => init P2P network + * enable = 1, mode = 1 => init Soft AP network + * enable = 0 => uninit P2P/AP network + * enable = 1, mode = 2 => init dual Soft AP network + * enable = 1, mode = 3 => init AP+P2P network + */ + + DBGLOG(P2P, INFO, "P2P Compile as (%d)p2p-like interface\n", KAL_P2P_NUM); + + if (prSetP2P->u4Mode >= RUNNING_P2P_MODE_NUM) { + DBGLOG(P2P, ERROR, "P2P interface mode(%d) is wrong\n", + prSetP2P->u4Mode); + ASSERT(0); + } + + if (prSetP2P->u4Enable) { + p2pSetMode(prSetP2P->u4Mode); + + if (p2pLaunch(prAdapter->prGlueInfo)) { + /* ToDo:: ASSERT */ + ASSERT(prAdapter->fgIsP2PRegistered); +#if CFG_SUPPORT_DBDC_TC6 + prAdapter->u4P2pMode = prSetP2P->u4Mode; +#endif + } else { + status = WLAN_STATUS_FAILURE; + } + } else { + if (prAdapter->fgIsP2PRegistered) { + p2pRemove(prAdapter->prGlueInfo); + } + } + + return status; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set the GTK rekey data + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + * \retval WLAN_STATUS_INVALID_DATA + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetGtkRekeyData(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + u8 ucCmdSeqNum; + P_BSS_INFO_T prBssInfo; + + DBGLOG(REQ, INFO, "wlanoidSetGtkRekeyData\n"); + + ASSERT(prAdapter); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(RSN, WARN, + "Fail in set rekey! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + prBssInfo = prAdapter->prAisBssInfo; + + *pu4SetInfoLen = u4SetBufferLen; + + prGlueInfo = prAdapter->prGlueInfo; + prCmdInfo = cmdBufAllocateCmdInfo( + prAdapter, (CMD_HDR_SIZE + sizeof(PARAM_GTK_REKEY_DATA))); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, INFO, "ucCmdSeqNum = %d\n", ucCmdSeqNum); + + /* compose PARAM_GTK_REKEY_DATA cmd pkt */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->u2InfoBufLen = CMD_HDR_SIZE + sizeof(PARAM_GTK_REKEY_DATA); + prCmdInfo->pfCmdDoneHandler = nicCmdEventSetCommon; + prCmdInfo->pfCmdTimeoutHandler = nicOidCmdTimeoutCommon; + prCmdInfo->fgIsOid = true; + prCmdInfo->ucCID = CMD_ID_SET_GTK_REKEY_DATA; + prCmdInfo->fgSetQuery = true; + prCmdInfo->fgNeedResp = false; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetBufferLen; + prCmdInfo->pvInformationBuffer = pvSetBuffer; + prCmdInfo->u4InformationBufferLength = u4SetBufferLen; + + /* Setup WIFI_CMD_T */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + kalMemCopy(prWifiCmd->aucBuffer, (u8 *)pvSetBuffer, u4SetBufferLen); + + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to request starting of schedule scan + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + * + * \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetStartSchedScan(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_SCHED_SCAN_REQUEST prSchedScanRequest; + + DEBUGFUNC("wlanoidSetStartSchedScan()"); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in set scheduled scan! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + ASSERT(pu4SetInfoLen); + *pu4SetInfoLen = 0; + + if (u4SetBufferLen != sizeof(PARAM_SCHED_SCAN_REQUEST)) { + return WLAN_STATUS_INVALID_LENGTH; + } else if (pvSetBuffer == NULL) { + return WLAN_STATUS_INVALID_DATA; + } else if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED && + prAdapter->fgEnOnlineScan == false) { + return WLAN_STATUS_FAILURE; + } + + if (prAdapter->fgIsRadioOff) { + DBGLOG(REQ, WARN, + "Return from BSSID list scan! (radio off). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_SUCCESS; + } + + prSchedScanRequest = (P_PARAM_SCHED_SCAN_REQUEST)pvSetBuffer; + + if (scnFsmSchedScanRequest(prAdapter, (u8)(prSchedScanRequest->u4SsidNum), + prSchedScanRequest->arSsid, + prSchedScanRequest->u4IELength, + prSchedScanRequest->pucIE, + prSchedScanRequest->u2ScanInterval) == true) { + return WLAN_STATUS_PENDING; + } else { + return WLAN_STATUS_FAILURE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to request termination of schedule scan + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_INVALID_DATA + * + * \note The setting buffer PARAM_SCHED_SCAN_REQUEST_EXT_T + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetStopSchedScan(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + ASSERT(prAdapter); + + /* ask SCN module to stop scan request */ + if (scnFsmSchedScanStopRequest(prAdapter) == true) { + return WLAN_STATUS_PENDING; + } else { + return WLAN_STATUS_FAILURE; + } +} + +#if CFG_SUPPORT_BATCH_SCAN + +#define CMD_WLS_BATCHING "WLS_BATCHING" + +#define BATCHING_SET "SET" +#define BATCHING_GET "GET" +#define BATCHING_STOP "STOP" + +#define PARAM_SCANFREQ "SCANFREQ" +#define PARAM_MSCAN "MSCAN" +#define PARAM_BESTN "BESTN" +#define PARAM_CHANNEL "CHANNEL" +#define PARAM_RTT "RTT" + +WLAN_STATUS batchSetCmd(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, IN u32 u4SetBufferLen, OUT u32 *pu4WritenLen) +{ + P_CHANNEL_INFO_T prRfChannelInfo; + CMD_BATCH_REQ_T rCmdBatchReq; + + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + s8 *head, *p, *p2; + u32 tokens; + s32 scanfreq, mscan, bestn, rtt; + char *pcTemp; + /* s8 c_scanfreq[4], c_mscan[4], c_bestn[4], c_rtt[4], c_channel[100]; + */ + /* INT32 ch_type; */ + u32 u4Value = 0; + s32 i4Ret = 0; + + DBGLOG(SCN, TRACE, "[BATCH] command=%s, len=%d\n", pvSetBuffer, + u4SetBufferLen); + + if (!pu4WritenLen) { + return -EINVAL; + } + + *pu4WritenLen = 0; + + if (u4SetBufferLen < kalStrLen(CMD_WLS_BATCHING)) { + DBGLOG(SCN, TRACE, "[BATCH] invalid len %d\n", u4SetBufferLen); + return -EINVAL; + } + + head = pvSetBuffer + kalStrLen(CMD_WLS_BATCHING) + 1; + kalMemSet(&rCmdBatchReq, 0, sizeof(CMD_BATCH_REQ_T)); + + if (!kalStrnCmp(head, BATCHING_SET, kalStrLen(BATCHING_SET))) { + DBGLOG(SCN, TRACE, "XXX Start Batch Scan XXX\n"); + + head += kalStrLen(BATCHING_SET) + 1; + + /* SCANFREQ, MSCAN, BESTN */ + tokens = sscanf(head, "SCANFREQ=%ld MSCAN=%ld BESTN=%ld", &scanfreq, + &mscan, &bestn); + if (tokens != 3) { + DBGLOG( + SCN, TRACE, + "[BATCH] Parse fail: tokens=%d, SCANFREQ=%d MSCAN=%d BESTN=%d\n", + tokens, scanfreq, mscan, bestn); + return -EINVAL; + } + /* RTT */ + p = kalStrStr(head, PARAM_RTT); + if (!p) { + DBGLOG(SCN, TRACE, "[BATCH] Parse RTT fail. head=%s\n", head); + return -EINVAL; + } + tokens = sscanf(p, "RTT=%d", &rtt); + if (tokens != 1) { + DBGLOG(SCN, TRACE, "[BATCH] Parse fail: tokens=%d, rtt=%d\n", + tokens, rtt); + return -EINVAL; + } + /* CHANNEL */ + p = kalStrStr(head, PARAM_CHANNEL); + if (!p) { + DBGLOG(SCN, TRACE, "[BATCH] Parse CHANNEL fail(1)\n"); + return -EINVAL; + } + head = p; + p = kalStrChr(head, '>'); + if (!p) { + DBGLOG(SCN, TRACE, "[BATCH] Parse CHANNEL fail(2)\n"); + return -EINVAL; + } + /* else { + * p = '.'; // remove '>' because sscanf can not parse <%s> + *} + */ + /*tokens = sscanf(head, "CHANNEL=<%s", c_channel); + * if (tokens != 1) { + * DBGLOG(SCN, TRACE, "[BATCH] Parse fail: tokens=%d, + * CHANNEL=<%s>\n", tokens, c_channel); return -EINVAL; + * } + */ + rCmdBatchReq.ucChannelType = SCAN_CHANNEL_SPECIFIED; + rCmdBatchReq.ucChannelListNum = 0; + prRfChannelInfo = &rCmdBatchReq.arChannelList[0]; + p = head + kalStrLen(PARAM_CHANNEL) + 2; /* c_channel; */ + pcTemp = (char *)p; + while ((p2 = kalStrSep(&pcTemp, ",")) != NULL) { + if (p2 == NULL || *p2 == 0) { + break; + } + if (*p2 == '\0') { + continue; + } + if (*p2 == 'A') { + rCmdBatchReq.ucChannelType = rCmdBatchReq.ucChannelType == + SCAN_CHANNEL_2G4 ? + SCAN_CHANNEL_FULL : + SCAN_CHANNEL_5G; + } else if (*p2 == 'B') { + rCmdBatchReq.ucChannelType = rCmdBatchReq.ucChannelType == + SCAN_CHANNEL_5G ? + SCAN_CHANNEL_FULL : + SCAN_CHANNEL_2G4; + } else { + /* Translate Freq from MHz to channel number. */ + /* prRfChannelInfo->ucChannelNum = kalStrtol(p2, + * NULL, 0); */ + i4Ret = kalkStrtou32(p2, 0, &u4Value); + if (i4Ret) { + DBGLOG(SCN, TRACE, "parse ucChannelNum error i4Ret=%d\n", + i4Ret); + return -EINVAL; + } + + prRfChannelInfo->ucChannelNum = (u8)u4Value; + DBGLOG(SCN, TRACE, "Scanning Channel:%d, freq: %d\n", + prRfChannelInfo->ucChannelNum, + nicChannelNum2Freq(prRfChannelInfo->ucChannelNum)); + prRfChannelInfo->ucBand = + prRfChannelInfo->ucChannelNum < 15 ? BAND_2G4 : BAND_5G; + + rCmdBatchReq.ucChannelListNum++; + if (rCmdBatchReq.ucChannelListNum >= 32) { + break; + } + prRfChannelInfo++; + } + } + + /* set channel for test */ + rCmdBatchReq.u4Scanfreq = scanfreq; + rCmdBatchReq.ucMScan = + mscan > CFG_BATCH_MAX_MSCAN ? CFG_BATCH_MAX_MSCAN : mscan; + rCmdBatchReq.ucBestn = bestn; + rCmdBatchReq.ucRtt = rtt; + DBGLOG(SCN, TRACE, "[BATCH] SCANFREQ=%d MSCAN=%d BESTN=%d RTT=%d\n", + rCmdBatchReq.u4Scanfreq, rCmdBatchReq.ucMScan, + rCmdBatchReq.ucBestn, rCmdBatchReq.ucRtt); + + if (rCmdBatchReq.ucChannelType != SCAN_CHANNEL_SPECIFIED) { + DBGLOG(SCN, TRACE, "[BATCH] CHANNELS = %s\n", + rCmdBatchReq.ucChannelType == SCAN_CHANNEL_FULL ? "FULL" : + rCmdBatchReq.ucChannelType == SCAN_CHANNEL_2G4 ? "2.4G all" : + "5G all"); + } else { + DBGLOG(SCN, TRACE, "[BATCH] CHANNEL list\n"); + prRfChannelInfo = &rCmdBatchReq.arChannelList[0]; + for (tokens = 0; tokens < rCmdBatchReq.ucChannelListNum; tokens++) { + DBGLOG(SCN, TRACE, "[BATCH] %s, %d\n", + prRfChannelInfo->ucBand == BAND_2G4 ? "2.4G" : "5G", + prRfChannelInfo->ucChannelNum); + prRfChannelInfo++; + } + } + + rCmdBatchReq.ucSeqNum = 1; + rCmdBatchReq.ucNetTypeIndex = KAL_NETWORK_TYPE_AIS_INDEX; + rCmdBatchReq.ucCmd = SCAN_BATCH_REQ_START; + + *pu4WritenLen = kalSnprintf(pvSetBuffer, 3, "%d", rCmdBatchReq.ucMScan); + } else if (!kalStrnCmp(head, BATCHING_STOP, kalStrLen(BATCHING_STOP))) { + DBGLOG(SCN, TRACE, "XXX Stop Batch Scan XXX\n"); + + rCmdBatchReq.ucSeqNum = 1; + rCmdBatchReq.ucNetTypeIndex = KAL_NETWORK_TYPE_AIS_INDEX; + rCmdBatchReq.ucCmd = SCAN_BATCH_REQ_STOP; + } else { + return -EINVAL; + } + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_BATCH_REQ, true, false, true, + NULL, NULL, sizeof(CMD_BATCH_REQ_T), + (u8 *)&rCmdBatchReq, NULL, 0); + + /* kalMemSet(pvSetBuffer, 0, u4SetBufferLen); */ + /* rStatus = kalSnprintf(pvSetBuffer, 2, "%s", "OK"); */ + + /* exit: */ + return rStatus; +} + +WLAN_STATUS batchGetCmd(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + CMD_BATCH_REQ_T rCmdBatchReq; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_EVENT_BATCH_RESULT_T prEventBatchResult; + /* u32 i; */ + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + kalMemZero(&rCmdBatchReq, sizeof(CMD_BATCH_REQ_T)); + + prEventBatchResult = (P_EVENT_BATCH_RESULT_T)pvQueryBuffer; + + DBGLOG(SCN, TRACE, "XXX Get Batch Scan Result (%d) XXX\n", + prEventBatchResult->ucScanCount); + + *pu4QueryInfoLen = sizeof(EVENT_BATCH_RESULT_T); + + rCmdBatchReq.ucSeqNum = 2; + rCmdBatchReq.ucCmd = SCAN_BATCH_REQ_RESULT; + rCmdBatchReq.ucMScan = prEventBatchResult->ucScanCount; /* Get which + * round result + */ + + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_BATCH_REQ, false, true, + true, nicCmdEventBatchScanResult, + nicOidCmdTimeoutCommon, + sizeof(CMD_BATCH_REQ_T), (u8 *)&rCmdBatchReq, + (void *)pvQueryBuffer, u4QueryBufferLen); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set + * \param[in] u4SetBufferLen The length of the set buffer + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed due to invalid length of + * the set buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. + * \retval WLAN_STATUS_INVALID_LENGTH + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBatchScanReq(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + return batchSetCmd(prAdapter, pvSetBuffer, u4SetBufferLen, pu4SetInfoLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBatchScanResult(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + return batchGetCmd(prAdapter, pvQueryBuffer, u4QueryBufferLen, + pu4QueryInfoLen); +} + +#endif + +#if CFG_SUPPORT_SNIFFER +WLAN_STATUS +wlanoidSetMonitor(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_MONITOR_SET_STRUCT_T prMonitorSetInfo; + CMD_MONITOR_SET_INFO_T rCmdMonitorSetInfo; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidSetMonitor"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + kalMemZero(&rCmdMonitorSetInfo, sizeof(CMD_MONITOR_SET_INFO_T)); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_MONITOR_SET_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_MONITOR_SET_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prMonitorSetInfo = (P_PARAM_CUSTOM_MONITOR_SET_STRUCT_T)pvSetBuffer; + + rCmdMonitorSetInfo.ucEnable = prMonitorSetInfo->ucEnable; + rCmdMonitorSetInfo.ucBand = prMonitorSetInfo->ucBand; + rCmdMonitorSetInfo.ucPriChannel = prMonitorSetInfo->ucPriChannel; + rCmdMonitorSetInfo.ucSco = prMonitorSetInfo->ucSco; + rCmdMonitorSetInfo.ucChannelWidth = prMonitorSetInfo->ucChannelWidth; + rCmdMonitorSetInfo.ucChannelS1 = prMonitorSetInfo->ucChannelS1; + rCmdMonitorSetInfo.ucChannelS2 = prMonitorSetInfo->ucChannelS2; + + rWlanStatus = wlanSendSetQueryCmd( + prAdapter, CMD_ID_SET_MONITOR, true, false, true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, sizeof(CMD_MONITOR_SET_INFO_T), + (u8 *)&rCmdMonitorSetInfo, pvSetBuffer, u4SetBufferLen); + + return rWlanStatus; +} +#endif + +#if CFG_SUPPORT_ADVANCE_CONTROL +WLAN_STATUS +wlanoidAdvCtrl(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_CMD_ADV_CONFIG_HEADER_T cmd; + u16 type = 0; + u32 len; + u8 fgSetQuery = false; + u8 fgNeedResp = true; + + DBGLOG(REQ, LOUD, "%s>\n", __func__); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + if (prAdapter->fgTestMode) { + // refer to IS_ALLOWED_CMD_IN_TEST_MODE() in FW + DBGLOG(REQ, WARN, "cmd not supported in test mode\n"); + return WLAN_STATUS_FAILURE; + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(*cmd)) { + DBGLOG(REQ, WARN, "Too short length %ld\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + cmd = (P_CMD_ADV_CONFIG_HEADER_T)pvQueryBuffer; + + if (cmd->u2Type & CMD_ADV_CONTROL_SET) { + fgSetQuery = true; + fgNeedResp = false; + } + + type = cmd->u2Type; + type &= ~CMD_ADV_CONTROL_SET; + DBGLOG(RSN, INFO, "%s cmd type %d\n", __func__, cmd->u2Type); + switch (type) { + case CMD_PTA_CONFIG_TYPE: + *pu4QueryInfoLen = sizeof(CMD_PTA_CONFIG_T); + len = sizeof(CMD_PTA_CONFIG_T); + break; + +#ifdef CFG_SUPPORT_EXT_PTA_DEBUG_COMMAND + case CMD_EXT_PTA_CONFIG_TYPE: + *pu4QueryInfoLen = sizeof(CMD_PTA_CONFIG_T); + len = sizeof(CMD_PTA_CONFIG_T); + break; + +#endif + case CMD_GET_REPORT_TYPE: + *pu4QueryInfoLen = sizeof(struct CMD_GET_TRAFFIC_REPORT); + len = sizeof(struct CMD_GET_TRAFFIC_REPORT); + break; + + case CMD_NOISE_HISTOGRAM_TYPE: +#if CFG_IPI_2CHAIN_SUPPORT + case CMD_NOISE_HISTOGRAM_TYPE2: +#endif + *pu4QueryInfoLen = sizeof(struct CMD_NOISE_HISTOGRAM_REPORT); + len = sizeof(struct CMD_NOISE_HISTOGRAM_REPORT); + break; + +#ifdef CFG_SUPPORT_ADMINCTRL + case CMD_ADMINCTRL_CONFIG_TYPE: + *pu4QueryInfoLen = sizeof(struct CMD_ADMIN_CTRL_CONFIG); + len = sizeof(struct CMD_ADMIN_CTRL_CONFIG); + break; + +#endif + case CMD_GET_MAGIC_PKT_INFO_TYPE: + *pu4QueryInfoLen = sizeof(CMD_GET_MAGIC_PKT_INFO_T); + len = sizeof(CMD_GET_MAGIC_PKT_INFO_T); + break; + + default: + return WLAN_STATUS_INVALID_LENGTH; + } + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_ADV_CONTROL, fgSetQuery, + fgNeedResp, true, nicCmdEventQueryAdvCtrl, + nicOidCmdTimeoutCommon, len, (u8 *)cmd, + pvQueryBuffer, u4QueryBufferLen); +} +#endif + +#if CFG_SUPPORT_MSP +WLAN_STATUS +wlanoidQueryWlanInfo(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_HW_WLAN_INFO_T prHwWlanInfo; + P_BSS_INFO_T prBssInfo = NULL; + + DEBUGFUNC("wlanoidQueryWlanInfo"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(PARAM_HW_WLAN_INFO_T); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(PARAM_HW_WLAN_INFO_T)) { + DBGLOG(REQ, WARN, "Too short length %ld\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prHwWlanInfo = (P_PARAM_HW_WLAN_INFO_T)pvQueryBuffer; + + // TODO: frog 20180518 + /* If not specifying any WLAN index. + * Get the WLAN index of the AIS network if connected. + */ + if (prHwWlanInfo->u4Index == WTBL_RESERVED_ENTRY) { + prBssInfo = prAdapter->prAisBssInfo; + ASSERT(prBssInfo != NULL); + + if (prBssInfo->prStaRecOfAP != NULL) { + prHwWlanInfo->u4Index = prBssInfo->prStaRecOfAP->ucWlanIndex; + } else { + return WLAN_STATUS_FAILURE; + } + } + + DBGLOG(RSN, INFO, "MT7668 : wlanoidQueryWlanInfo index = %d\n", + prHwWlanInfo->u4Index); + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_WLAN_INFO, false, true, true, + nicCmdEventQueryWlanInfo, nicOidCmdTimeoutCommon, + sizeof(PARAM_HW_WLAN_INFO_T), (u8 *)prHwWlanInfo, + pvQueryBuffer, u4QueryBufferLen); +} + +WLAN_STATUS +wlanoidQueryMibInfo(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_PARAM_HW_MIB_INFO_T prHwMibInfo; + + DEBUGFUNC("wlanoidQueryMibInfo"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(PARAM_HW_MIB_INFO_T); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(PARAM_HW_MIB_INFO_T)) { + DBGLOG(REQ, WARN, "Too short length %ld\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prHwMibInfo = (P_PARAM_HW_MIB_INFO_T)pvQueryBuffer; + DBGLOG(RSN, INFO, "MT6632 : wlanoidQueryMibInfo index = %d\n", + prHwMibInfo->u4Index); + + /**pu4QueryInfoLen = 8 + prRxStatistics->u4TotalNum; */ + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_MIB_INFO, false, true, true, + nicCmdEventQueryMibInfo, nicOidCmdTimeoutCommon, + sizeof(PARAM_HW_MIB_INFO_T), (u8 *)prHwMibInfo, + pvQueryBuffer, u4QueryBufferLen); +} +#endif + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +WLAN_STATUS +wlanoidTxMcsInfo(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + struct PARAM_TX_MCS_INFO *prMcsInfo; + P_BSS_INFO_T prBssInfo = NULL; + + DEBUGFUNC("wlanoidQueryWlanInfo"); + DBGLOG(REQ, LOUD, "\n"); + + ASSERT(prAdapter); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + ASSERT(pu4QueryInfoLen); + + *pu4QueryInfoLen = sizeof(struct PARAM_TX_MCS_INFO); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(struct PARAM_TX_MCS_INFO)) { + DBGLOG(REQ, WARN, "Too short length %ld\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prMcsInfo = (struct PARAM_TX_MCS_INFO *)pvQueryBuffer; + + // TODO: frog 20180518 + /* Hard coded for AIS only now. + * Need more parameter if reuse for other BSS. + */ + prBssInfo = prAdapter->prAisBssInfo; + ASSERT(prBssInfo != NULL); + + if (prBssInfo->prStaRecOfAP != NULL) { + prMcsInfo->ucStaIndex = prBssInfo->prStaRecOfAP->ucIndex; + } else { + return WLAN_STATUS_FAILURE; + } + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_TX_MCS_INFO, false, true, true, + nicCmdEventTxMcsInfo, nicOidCmdTimeoutCommon, + sizeof(struct PARAM_TX_MCS_INFO), + (u8 *)prMcsInfo, pvQueryBuffer, + u4QueryBufferLen); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set FW log to Host. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_NOT_SUPPORTED + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetFwLog2Host(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_CMD_FW_LOG_2_HOST_CTRL_T prFwLog2HostCtrl; + u64 ts = KAL_GET_HOST_CLOCK(); + + DEBUGFUNC("wlanoidSetFwLog2Host"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(CMD_FW_LOG_2_HOST_CTRL_T); + + if (u4SetBufferLen) { + ASSERT(pvSetBuffer); + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in set FW log to Host! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4SetBufferLen < sizeof(CMD_FW_LOG_2_HOST_CTRL_T)) { + DBGLOG(REQ, WARN, "Too short length %ld\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prFwLog2HostCtrl = (P_CMD_FW_LOG_2_HOST_CTRL_T)pvSetBuffer; + prFwLog2HostCtrl->u4HostTimeMSec = (u32)(do_div(ts, 1000000000) / 1000); + prFwLog2HostCtrl->u4HostTimeSec = (u32)ts; + +#if CFG_SUPPORT_FW_DBG_LEVEL_CTRL + DBGLOG(REQ, INFO, "McuDest %d, LogType %d, (FwLogLevel %d)\n", + prFwLog2HostCtrl->ucMcuDest, prFwLog2HostCtrl->ucFwLog2HostCtrl, + prFwLog2HostCtrl->ucFwLogLevel); +#else + DBGLOG(REQ, INFO, "McuDest %d, LogType %d\n", prFwLog2HostCtrl->ucMcuDest, + prFwLog2HostCtrl->ucFwLog2HostCtrl); +#endif + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_FW_LOG_2_HOST, true, false, + true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_FW_LOG_2_HOST_CTRL_T), + (u8 *)prFwLog2HostCtrl, pvSetBuffer, + u4SetBufferLen); +} + +#if CFG_STR_DHCP_RENEW_OFFLOAD +WLAN_STATUS +wlanoidSetDhcpOffladInfo(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_CMD_DHCP_OFFLOAD_SETTING_T prDhcpOffloadCmd; + + if (!prAdapter || !pvSetBuffer) { + return WLAN_STATUS_INVALID_DATA; + } + + prDhcpOffloadCmd = (P_CMD_DHCP_OFFLOAD_SETTING_T)pvSetBuffer; + + DBGLOG(REQ, STATE, + "DHCP renew info set to FW Server IP: [%d.%d.%d.%d] Lease Time: %d " + "seconds\n", + prDhcpOffloadCmd->aucDhcpServerIpAddr[0], + prDhcpOffloadCmd->aucDhcpServerIpAddr[1], + prDhcpOffloadCmd->aucDhcpServerIpAddr[2], + prDhcpOffloadCmd->aucDhcpServerIpAddr[3], + prDhcpOffloadCmd->u4RenewIntv); + + DBGLOG(REQ, STATE, "DHCP renew offload Enable:%d, Suspend:%d, BssIdx:%d\n", + prDhcpOffloadCmd->ucEnableOffload, prDhcpOffloadCmd->ucSuspend, + prDhcpOffloadCmd->ucBssIndex); + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_DHCP_RENEW_OFFLOAD, true, + false, true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_DHCP_OFFLOAD_SETTING_T), + (u8 *)prDhcpOffloadCmd, NULL, 0); +} +#endif + +WLAN_STATUS +wlanoidNotifyFwSuspend(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_CMD_SUSPEND_MODE_SETTING_T prSuspendCmd; + + if (!prAdapter || !pvSetBuffer) { + return WLAN_STATUS_INVALID_DATA; + } + + prSuspendCmd = (P_CMD_SUSPEND_MODE_SETTING_T)pvSetBuffer; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_SUSPEND_MODE, true, false, + true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_SUSPEND_MODE_SETTING_T), + (u8 *)prSuspendCmd, NULL, 0); +} +#if CFG_SUPPORT_DBDC +WLAN_STATUS +wlanoidSetDbdcEnable(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + u8 ucDBDCEnable; + + if (!prAdapter || !pvSetBuffer) { + return WLAN_STATUS_INVALID_DATA; + } + + kalMemCopy(&ucDBDCEnable, pvSetBuffer, 1); + cnmUpdateDbdcSetting(prAdapter, ucDBDCEnable); + + return WLAN_STATUS_SUCCESS; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set tx target power base. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuerySetTxTargetPower(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_SET_TX_TARGET_POWER_T prSetTxTargetPowerInfo; + CMD_SET_TX_TARGET_POWER_T rCmdSetTxTargetPower; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQuerySetTxTargetPower"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(P_PARAM_CUSTOM_SET_TX_TARGET_POWER_T); + + if (u4SetBufferLen < sizeof(P_PARAM_CUSTOM_SET_TX_TARGET_POWER_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prSetTxTargetPowerInfo = (P_PARAM_CUSTOM_SET_TX_TARGET_POWER_T)pvSetBuffer; + + kalMemSet(&rCmdSetTxTargetPower, 0, sizeof(CMD_SET_TX_TARGET_POWER_T)); + + rCmdSetTxTargetPower.ucTxTargetPwr = prSetTxTargetPowerInfo->ucTxTargetPwr; + + DBGLOG(INIT, INFO, "MT6632 : wlanoidQuerySetTxTargetPower =%x dbm\n", + rCmdSetTxTargetPower.ucTxTargetPwr); + + rWlanStatus = wlanSendSetQueryCmd( + prAdapter, CMD_ID_SET_TX_PWR, true, /* fgSetQuery Bit: + * True->write False->read*/ + false, /* fgNeedResp */ + true, /* fgIsOid*/ + nicCmdEventSetCommon, /* REF: wlanoidSetDbdcEnable */ + nicOidCmdTimeoutCommon, sizeof(CMD_ACCESS_EFUSE_T), + (u8 *)(&rCmdSetTxTargetPower), pvSetBuffer, u4SetBufferLen); + + return rWlanStatus; +} + +#if (CFG_SUPPORT_DFS_MASTER == 1) +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set rdd report. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuerySetRddReport(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_SET_RDD_REPORT_T prSetRddReport; + P_CMD_RDD_ON_OFF_CTRL_T prCmdRddOnOffCtrl; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQuerySetRddReport"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(P_PARAM_CUSTOM_SET_RDD_REPORT_T); + + ASSERT(pvSetBuffer); + + prSetRddReport = (P_PARAM_CUSTOM_SET_RDD_REPORT_T)pvSetBuffer; + + prCmdRddOnOffCtrl = (P_CMD_RDD_ON_OFF_CTRL_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(*prCmdRddOnOffCtrl)); + + ASSERT(prCmdRddOnOffCtrl); + if (prCmdRddOnOffCtrl == NULL) { + DBGLOG(INIT, ERROR, "prCmdRddOnOffCtrl is NULL"); + return WLAN_STATUS_FAILURE; + } + kalMemZero(prCmdRddOnOffCtrl, sizeof(CMD_RDD_ON_OFF_CTRL_T)); + + prCmdRddOnOffCtrl->ucDfsCtrl = RDD_RADAR_EMULATE; + + prCmdRddOnOffCtrl->ucRddIdx = prSetRddReport->ucDbdcIdx; + + if (prCmdRddOnOffCtrl->ucRddIdx) { + prCmdRddOnOffCtrl->ucRddInSel = RDD_IN_SEL_1; + } else { + prCmdRddOnOffCtrl->ucRddInSel = RDD_IN_SEL_0; + } + + DBGLOG( + INIT, INFO, + "MT6632 : wlanoidQuerySetRddReport - DFS ctrl: %.d, RDD index: %d\n", + prCmdRddOnOffCtrl->ucDfsCtrl, prCmdRddOnOffCtrl->ucRddIdx); + + rWlanStatus = wlanSendSetQueryCmd( + prAdapter, CMD_ID_RDD_ON_OFF_CTRL, true, + /* fgSetQuery Bit: True->write False->read */ + false, /* fgNeedResp */ + true, /* fgIsOid*/ + nicCmdEventSetCommon, /* REF: wlanoidSetDbdcEnable */ + nicOidCmdTimeoutCommon, sizeof(*prCmdRddOnOffCtrl), + (u8 *)(prCmdRddOnOffCtrl), pvSetBuffer, u4SetBufferLen); + + cnmMemFree(prAdapter, prCmdRddOnOffCtrl); + + return rWlanStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set rdd report. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQuerySetRadarDetectMode(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + struct PARAM_CUSTOM_SET_RADAR_DETECT_MODE *prSetRadarDetectMode; + P_CMD_RDD_ON_OFF_CTRL_T prCmdRddOnOffCtrl; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DEBUGFUNC("wlanoidQuerySetRadarDetectMode"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(struct PARAM_CUSTOM_SET_RADAR_DETECT_MODE *); + + ASSERT(pvSetBuffer); + + prSetRadarDetectMode = + (struct PARAM_CUSTOM_SET_RADAR_DETECT_MODE *)pvSetBuffer; + + prCmdRddOnOffCtrl = (P_CMD_RDD_ON_OFF_CTRL_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(*prCmdRddOnOffCtrl)); + + ASSERT(prCmdRddOnOffCtrl); + if (prCmdRddOnOffCtrl == NULL) { + DBGLOG(INIT, ERROR, "prCmdRddOnOffCtrl is NULL"); + return WLAN_STATUS_FAILURE; + } + kalMemZero(prCmdRddOnOffCtrl, sizeof(CMD_RDD_ON_OFF_CTRL_T)); + + prCmdRddOnOffCtrl->ucDfsCtrl = RDD_DET_MODE; + + prCmdRddOnOffCtrl->ucRadarDetectMode = + prSetRadarDetectMode->ucRadarDetectMode; + + DBGLOG(INIT, INFO, + "MT6632 : wlanoidQuerySetRadarDetectMode - DFS ctrl: %.d, Radar " + "Detect Mode: %d\n", + prCmdRddOnOffCtrl->ucDfsCtrl, prCmdRddOnOffCtrl->ucRadarDetectMode); + + rWlanStatus = wlanSendSetQueryCmd( + prAdapter, CMD_ID_RDD_ON_OFF_CTRL, true, /* fgSetQuery Bit: + * True->write False->read*/ + false, /* fgNeedResp */ + true, /* fgIsOid*/ + nicCmdEventSetCommon, /* REF: wlanoidSetDbdcEnable */ + nicOidCmdTimeoutCommon, sizeof(*prCmdRddOnOffCtrl), + (u8 *)(prCmdRddOnOffCtrl), pvSetBuffer, u4SetBufferLen); + + cnmMemFree(prAdapter, prCmdRddOnOffCtrl); + + return rWlanStatus; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to turn radio off. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidLinkDown(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + DEBUGFUNC("wlanoidSetDisassociate"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 0; + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in set link down! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + aisBssLinkDown(prAdapter); + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS +wlanoidAbortScan(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + P_AIS_FSM_INFO_T prAisFsmInfo = NULL; + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + if (prAisFsmInfo->eCurrentState == AIS_STATE_SCAN || + prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN) { + DBGLOG(OID, INFO, "wlanoidAbortScan\n"); + prAisFsmInfo->fgIsScanOidAborted = true; + aisFsmStateAbort_SCAN(prAdapter); + } + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS +wlanoidSetCSIControl(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + struct CMD_CSI_CONTROL_T *pCSICtrl; + + DEBUGFUNC("wlanoidSetCSIControl"); + + *pu4SetInfoLen = sizeof(struct CMD_CSI_CONTROL_T); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in set CSI control! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4SetBufferLen < sizeof(struct CMD_CSI_CONTROL_T)) { + DBGLOG(REQ, WARN, "Too short length %lu\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + pCSICtrl = (struct CMD_CSI_CONTROL_T *)pvSetBuffer; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_CSI_CONTROL, true, false, true, + nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + sizeof(struct CMD_CSI_CONTROL_T), (u8 *)pCSICtrl, + pvSetBuffer, u4SetBufferLen); +} +#ifdef CFG_SUPPORT_ANT_DIV +/*----------------------------------------------------------------------------*/ +/*! + * \brief antenna diversity config + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvQueryBuffer Pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number + * of bytes written into the query buffer. If the call failed due to invalid + * length of the query buffer , returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_BUFFER_TOO_SHORT + * \retval WLAN_STATUS_NOT_SUPPORTED + * \retval WLAN_STATUS_NOT_ACCEPTED + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidAntDivCfg(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + struct CMD_ANT_DIV_CTRL *prAntDivInfo; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + u8 fgSetQuery = true; + u8 fgNeedResp = false; + + DEBUGFUNC("wlanoidSetAntDiv"); + if (prAdapter == NULL) { + return -EFAULT; + } + + if (pu4SetInfoLen == NULL) { + return -EFAULT; + } + + if (pvSetBuffer == NULL) { + return -EFAULT; + } + + *pu4SetInfoLen = sizeof(struct CMD_ANT_DIV_CTRL); + if (u4SetBufferLen < sizeof(struct CMD_ANT_DIV_CTRL)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + prAntDivInfo = (struct CMD_ANT_DIV_CTRL *)pvSetBuffer; + + /* GET need to wait for response from FW module */ + switch (prAntDivInfo->ucAction) { + case ANT_DIV_CMD_GET_ANT: + case ANT_DIV_CMD_DETC: + fgSetQuery = false; + fgNeedResp = true; + break; + + case ANT_DIV_CMD_SWH: + fgSetQuery = true; + fgNeedResp = true; + break; + + case ANT_DIV_CMD_SET_ANT: + fgSetQuery = true; + fgNeedResp = false; + break; + + default: + DBGLOG(REQ, WARN, "don't support action = %d\n", + prAntDivInfo->ucAction); + return WLAN_STATUS_INVALID_DATA; + + break; + } + rWlanStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_ANT_DIV_CTRL, + fgSetQuery, fgNeedResp, true, + nicCmdEventAntDiv, nicOidCmdTimeoutCommon, + sizeof(struct CMD_ANT_DIV_CTRL), + (u8 *)prAntDivInfo, pvSetBuffer, + u4SetBufferLen); + + return rWlanStatus; +} +#endif + +#ifdef CFG_DUMP_TXPOWR_TABLE +WLAN_STATUS +wlanoidGetTxPwrTbl(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + struct CMD_GET_TXPWR_TBL CmdPwrTbl; + struct PARAM_CMD_GET_TXPWR_TBL *prPwrTbl = NULL; + + DEBUGFUNC("wlanoidGetTxPwrTbl"); + DBGLOG(REQ, LOUD, "\n"); + kalMemZero(&CmdPwrTbl, sizeof(struct CMD_GET_TXPWR_TBL)); + + if (!prAdapter || (!pvQueryBuffer && u4QueryBufferLen) || + !pu4QueryInfoLen) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu4QueryInfoLen = sizeof(struct PARAM_CMD_GET_TXPWR_TBL); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, WARN, + "Fail in query receive error! (Adapter not ready). ACPI=D%d, " + "Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + *pu4QueryInfoLen = sizeof(u32); + return WLAN_STATUS_ADAPTER_NOT_READY; + } else if (u4QueryBufferLen < sizeof(struct PARAM_CMD_GET_TXPWR_TBL)) { + DBGLOG(REQ, WARN, "Too short length %ld\n", u4QueryBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } + + prPwrTbl = (struct PARAM_CMD_GET_TXPWR_TBL *)pvQueryBuffer; + CmdPwrTbl.ucDbdcIdx = prPwrTbl->ucDbdcIdx; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_TXPWR_TBL, false, true, + true, nicCmdEventGetTxPwrTbl, + nicOidCmdTimeoutCommon, + sizeof(struct CMD_GET_TXPWR_TBL), + (u8 *)&CmdPwrTbl, pvQueryBuffer, + u4QueryBufferLen); +} +#endif + +u32 wlanGetSupportedFeatureSet(IN P_GLUE_INFO_T prGlueInfo) +{ + u32 u4FeatureSet = WIFI_HAL_FEATURE_SET; + P_REG_INFO_T prRegInfo; + + prRegInfo = kalGetConfiguration(prGlueInfo); + if ((prRegInfo != NULL) && (prRegInfo->ucSupport5GBand)) { + u4FeatureSet |= WIFI_FEATURE_INFRA_5G; + } + + return u4FeatureSet; +} + +WLAN_STATUS +wlanSuspendLinkDown(IN P_GLUE_INFO_T prGlueInfo) +{ + u32 u4BufLen; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_AIS_FSM_INFO_T prAisFsmInfo; + + prAisFsmInfo = &(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo); + + aisFsmStateAbort_SCAN(prGlueInfo->prAdapter); + + /* 1) wifi cfg "Wow" must be true, 2) wow is disable 3) WIfI connected + * => execute link down flow */ + if (prGlueInfo->prAdapter->rWifiVar.ucWow && + !prGlueInfo->prAdapter->rWowCtrl.fgWowEnable) { + if (kalGetMediaStateIndicated(prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED || + prAisFsmInfo->eCurrentState == AIS_STATE_DISCONNECTING) { + /* Only flush all pending AIS Reqs for suspend linkdown + */ + aisFsmFlushRequest(prGlueInfo->prAdapter); + + DBGLOG(REQ, STATE, "Suspend link down\n"); + rStatus = kalIoctl(prGlueInfo, wlanoidLinkDown, NULL, 0, true, + false, false, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "Suspend link down failed\n"); + } + } + } + + return rStatus; +} +/* + * This func is mainly from bionic's strtok.c + */ + +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT +static s8 *strtok_r(s8 *s, const s8 *delim, s8 **last) +{ + char *spanp; + int c, sc; + char *tok; + + if (s == NULL) { + s = *last; + if (s == 0) { + return NULL; + } + } +cont: + c = *s++; + for (spanp = (char *)delim; (sc = *spanp++) != 0;) + if (c == sc) { + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + *last = NULL; + return NULL; + } + tok = s - 1; + + for (;;) { + c = *s++; + spanp = (char *)delim; + do { + sc = *spanp++; + if (sc == c) { + if (c == 0) { + s = NULL; + } else { + s[-1] = 0; + } + *last = s; + return tok; + } + } while (sc != 0); + } +} +#endif + +#if CFG_SUPPORT_802_11K +WLAN_STATUS wlanoidSendNeighborRequest(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, u32 u4SetBufferLen, + u32 *pu4SetInfoLen) +{ + struct SUB_ELEMENT_LIST *prSSIDIE = NULL; + P_BSS_INFO_T prAisBssInfo = NULL; + u8 ucSSIDIELen = 0; + u8 *pucSSID = (u8 *)pvSetBuffer; + + if (!prAdapter || !prAdapter->prAisBssInfo) { + return WLAN_STATUS_INVALID_DATA; + } + + prAisBssInfo = prAdapter->prAisBssInfo; + if (prAisBssInfo->eConnectionState != PARAM_MEDIA_STATE_CONNECTED) { + DBGLOG(OID, ERROR, "didn't connected any Access Point\n"); + return WLAN_STATUS_FAILURE; + } + if (u4SetBufferLen == 0 || !pucSSID) { + rlmTxNeighborReportRequest(prAdapter, prAisBssInfo->prStaRecOfAP, NULL); + return WLAN_STATUS_SUCCESS; + } + + ucSSIDIELen = (u8)(u4SetBufferLen + sizeof(*prSSIDIE)); + prSSIDIE = kalMemAlloc(ucSSIDIELen, PHY_MEM_TYPE); + if (!prSSIDIE) { + DBGLOG(OID, ERROR, "No Memory\n"); + return WLAN_STATUS_FAILURE; + } + prSSIDIE->prNext = NULL; + prSSIDIE->rSubIE.ucSubID = ELEM_ID_SSID; + prSSIDIE->rSubIE.ucLength = (u8)u4SetBufferLen; + kalMemCopy(&prSSIDIE->rSubIE.aucOptInfo[0], pucSSID, (u8)u4SetBufferLen); + DBGLOG(OID, INFO, "Send Neighbor Request, SSID=%s\n", pucSSID); + rlmTxNeighborReportRequest(prAdapter, prAisBssInfo->prStaRecOfAP, prSSIDIE); + kalMemFree(prSSIDIE, PHY_MEM_TYPE, ucSSIDIELen); + return WLAN_STATUS_SUCCESS; +} +#endif +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT +WLAN_STATUS wlanoidSendBTMQuery(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + u32 u4SetBufferLen, u32 *pu4SetInfoLen) +{ + P_STA_RECORD_T prStaRec = NULL; + P_BSS_TRANSITION_MGT_PARAM_T prBtmMgt = NULL; + u8 uReason = 0; + u8 *cReason = (u8 *)pvSetBuffer; + + if (!prAdapter->prAisBssInfo || prAdapter->prAisBssInfo->eConnectionState != + PARAM_MEDIA_STATE_CONNECTED) { + DBGLOG(OID, INFO, "Not connected yet\n"); + return WLAN_STATUS_FAILURE; + } + prStaRec = prAdapter->prAisBssInfo->prStaRecOfAP; + if (!prStaRec || !prStaRec->fgSupportBTM) { + DBGLOG(OID, INFO, + "Target BSS(%p) didn't support Bss Transition Management\n", + prStaRec); + return WLAN_STATUS_FAILURE; + } + + if (cReason != NULL) { + while (*cReason >= '0' && *cReason <= '9') { + uReason = uReason * 10; + uReason += *cReason - 48; + cReason++; + } + } + + prBtmMgt = &prAdapter->rWifiVar.rAisSpecificBssInfo.rBTMParam; + prBtmMgt->ucDialogToken = wnmGetBtmToken(); + prBtmMgt->ucQueryReason = pvSetBuffer ? uReason : BSS_TRANSITION_LOW_RSSI; + DBGLOG(OID, INFO, "Send BssTransitionManagementQuery, Reason %d\n", + prBtmMgt->ucQueryReason); + wnmSendBTMQueryFrame(prAdapter, prStaRec); + return WLAN_STATUS_SUCCESS; +} + +/* It's a Integretion Test function for RadioMeasurement. If you found errors +** during doing Radio Measurement, +** you can run this IT function with iwpriv wlan0 driver \"RM-IT +** xx,xx,xx, xx\" +** xx,xx,xx,xx is the RM request frame data +*/ +WLAN_STATUS wlanoidPktProcessIT(IN P_ADAPTER_T prAdapter, IN void *pvBuffer, + u32 u4BufferLen, u32 *pu4InfoLen) +{ + SW_RFB_T rSwRfb; + static u8 aucPacket[200] = { + 0, + }; + u8 *pucSavedPtr = (u8 *)pvBuffer; + u8 *pucItem = NULL; + u8 j = 0; + s8 i = 0; + u8 ucByte; + u8 fgBTMReq = false; + void (*process_func)(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); + + if (!pvBuffer) { + DBGLOG(OID, ERROR, "pvBuffer is NULL\n"); + return WLAN_STATUS_FAILURE; + } + + if (!strnicmp(pucSavedPtr, "BTM-IT ", 7)) { + process_func = wnmRecvBTMRequest; + pucSavedPtr += 7; + fgBTMReq = true; + } else { + pucSavedPtr[10] = 0; + DBGLOG(OID, ERROR, "IT type %s is not supported\n", pucSavedPtr); + return WLAN_STATUS_NOT_SUPPORTED; + } + kalMemZero(aucPacket, sizeof(aucPacket)); + pucItem = strtok_r(pucSavedPtr, ",", (s8 **)&pucSavedPtr); + while (pucItem) { + ucByte = *pucItem; + i = 0; + while (ucByte) { + if (i > 1) { + DBGLOG(OID, ERROR, "more than 2 char for one byte\n"); + return WLAN_STATUS_FAILURE; + } else if (i == 1) { + aucPacket[j] <<= 4; + } + if (ucByte >= '0' && ucByte <= '9') { + aucPacket[j] |= ucByte - '0'; + } else if (ucByte >= 'a' && ucByte <= 'f') { + aucPacket[j] |= ucByte - 'a' + 10; + } else if (ucByte >= 'A' && ucByte <= 'F') { + aucPacket[j] |= ucByte - 'A' + 10; + } else { + DBGLOG(OID, ERROR, "not a hex char %c\n", ucByte); + return WLAN_STATUS_FAILURE; + } + ucByte = *(++pucItem); + i++; + } + j++; + pucItem = strtok_r(NULL, ",", (s8 **)&pucSavedPtr); + } + DBGLOG(OID, INFO, "Dump IT packet, len %d\n", j); + dumpMemory8(aucPacket, j); + if (j < WLAN_MAC_MGMT_HEADER_LEN) { + DBGLOG(OID, ERROR, "packet length %d less than mac header 24\n", j); + return WLAN_STATUS_FAILURE; + } + rSwRfb.pvHeader = (void *)&aucPacket[0]; + rSwRfb.u2PacketLen = j; + rSwRfb.u2HeaderLen = WLAN_MAC_MGMT_HEADER_LEN; + rSwRfb.ucStaRecIdx = KAL_NETWORK_TYPE_AIS_INDEX; + if (fgBTMReq) { + HW_MAC_RX_DESC_T rRxStatus; + + rSwRfb.prRxStatus = (P_HW_MAC_RX_DESC_T)&rRxStatus; + rSwRfb.prRxStatus->ucChanFreq = 6; + wnmWNMAction(prAdapter, &rSwRfb); + } else { + process_func(prAdapter, &rSwRfb); + } + + return WLAN_STATUS_SUCCESS; +} +#endif + +u32 wlanoidIndicateBssInfo(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_BSS_DESC_T *pprBssDesc = NULL; + u32 rStatus = WLAN_STATUS_SUCCESS; + u8 i = 0; + + DEBUGFUNC("wlanoidIndicateBssInfo"); + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + pprBssDesc = + &prAdapter->rWifiVar.rScanInfo.rSchedScanParam.aprPendingBssDescToInd[0]; + + for (; i < SCN_SSID_MATCH_MAX_NUM; i++) { + if (pprBssDesc[i] == NULL) { + break; + } + if (pprBssDesc[i]->u2RawLength == 0) { + continue; + } + kalIndicateBssInfo(prGlueInfo, (u8 *)pprBssDesc[i]->aucRawBuf, + pprBssDesc[i]->u2RawLength, + pprBssDesc[i]->ucChannelNum, + RCPI_TO_dBm(pprBssDesc[i]->ucRCPI)); + } + + if (i > 0) { + DBGLOG(SCN, INFO, "pending %d sched scan results\n", i); + kalMemZero(&pprBssDesc[0], i * sizeof(struct BSS_DESC *)); + } else { + DBGLOG(SCN, TRACE, "pending %d sched scan results\n", i); + } + + return rStatus; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/common/wlan_p2p.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/common/wlan_p2p.c new file mode 100644 index 00000000000000..2aedffd5c3d295 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/common/wlan_p2p.c @@ -0,0 +1,1168 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file wlan_bow.c + * \brief This file contains the Wi-Fi Direct commands processing routines + * for MediaTek Inc. 802.11 Wireless LAN Adapters. + */ + +/****************************************************************************** + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/****************************************************************************** + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#include "gl_p2p_ioctl.h" + +/****************************************************************************** + * C O N S T A N T S + ******************************************************************************* + */ + +/****************************************************************************** + * D A T A T Y P E S + ******************************************************************************* + */ + +/****************************************************************************** + * P U B L I C D A T A + ******************************************************************************* + */ + +/****************************************************************************** + * P R I V A T E D A T A + ******************************************************************************* + */ + +/****************************************************************************** + * M A C R O S + ******************************************************************************* + */ + +/****************************************************************************** + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/****************************************************************************** + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief command packet generation utility + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] ucCID Command ID + * \param[in] fgSetQuery Set or Query + * \param[in] fgNeedResp Need for response + * \param[in] pfCmdDoneHandler Function pointer when command is done + * \param[in] u4SetQueryInfoLen The length of the set/query buffer + * \param[in] pucInfoBuffer Pointer to set/query buffer + * + * + * \retval WLAN_STATUS_PENDING + * \retval WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendSetQueryP2PCmd(IN P_ADAPTER_T prAdapter, IN u8 ucCID, IN u8 ucBssIdx, + IN u8 fgSetQuery, IN u8 fgNeedResp, IN u8 fgIsOid, + IN PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + IN PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + IN u32 u4SetQueryInfoLen, IN u8 *pucInfoBuffer, + OUT void *pvSetQueryBuffer, + IN u32 u4SetQueryBufferLen) +{ + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + u8 ucCmdSeqNum; + + ASSERT(prAdapter); + + prGlueInfo = prAdapter->prGlueInfo; + ASSERT(prGlueInfo); + + DEBUGFUNC("wlanoidSendSetQueryP2PCmd"); + DBGLOG(REQ, TRACE, "Command ID = 0x%08X\n", ucCID); + + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, + (CMD_HDR_SIZE + u4SetQueryInfoLen)); + + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); + + /* Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->u2InfoBufLen = (u16)(CMD_HDR_SIZE + u4SetQueryInfoLen); + prCmdInfo->pfCmdDoneHandler = pfCmdDoneHandler; + prCmdInfo->pfCmdTimeoutHandler = pfCmdTimeoutHandler; + prCmdInfo->fgIsOid = fgIsOid; + prCmdInfo->ucCID = ucCID; + prCmdInfo->fgSetQuery = fgSetQuery; + prCmdInfo->fgNeedResp = fgNeedResp; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u4SetQueryInfoLen; + prCmdInfo->pvInformationBuffer = pvSetQueryBuffer; + prCmdInfo->u4InformationBufferLength = u4SetQueryBufferLen; + + /* Setup WIFI_CMD_T (no payload) */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + if (u4SetQueryInfoLen > 0 && pucInfoBuffer != NULL) { + kalMemCopy(prWifiCmd->aucBuffer, pucInfoBuffer, + u4SetQueryInfoLen); + } + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Setting the IP address for pattern search function. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \return WLAN_STATUS_SUCCESS + * \return WLAN_STATUS_ADAPTER_NOT_READY + * \return WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanoidSetP2pNetworkAddress(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 i, j; + P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; + P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = + (P_PARAM_NETWORK_ADDRESS_LIST)pvSetBuffer; + P_PARAM_NETWORK_ADDRESS prNetworkAddress; + P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; + u32 u4IpAddressCount, u4CmdSize; + + DEBUGFUNC("wlanoidSetP2pNetworkAddress"); + DBGLOG(INIT, TRACE, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 4; + + if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu4SetInfoLen = 0; + u4IpAddressCount = 0; + + prNetworkAddress = prNetworkAddressList->arAddress; + for (i = 0; i < prNetworkAddressList->u4AddressCount; i++) { + if (prNetworkAddress->u2AddressType == + PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == + sizeof(PARAM_NETWORK_ADDRESS_IP)) { + u4IpAddressCount++; + } + + prNetworkAddress = + (P_PARAM_NETWORK_ADDRESS)((unsigned long) + prNetworkAddress + + (unsigned long)( + prNetworkAddress + -> + u2AddressLength + + OFFSET_OF( + PARAM_NETWORK_ADDRESS, + aucAddress))); + } + + /* construct payload of command packet */ + u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + + sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; + + prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST)kalMemAlloc( + u4CmdSize, VIR_MEM_TYPE); + + if (prCmdNetworkAddressList == NULL) { + return WLAN_STATUS_FAILURE; + } + + kalMemZero(prCmdNetworkAddressList, u4CmdSize); + + /* fill P_CMD_SET_NETWORK_ADDRESS_LIST */ + prCmdNetworkAddressList->ucBssIndex = prNetworkAddressList->ucBssIdx; + prCmdNetworkAddressList->ucAddressCount = (u8)u4IpAddressCount; + prNetworkAddress = prNetworkAddressList->arAddress; + for (i = 0, j = 0; i < prNetworkAddressList->u4AddressCount; i++) { + if (prNetworkAddress->u2AddressType == + PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == + sizeof(PARAM_NETWORK_ADDRESS_IP)) { + prNetAddrIp = (P_PARAM_NETWORK_ADDRESS_IP) + prNetworkAddress->aucAddress; + + kalMemCopy(prCmdNetworkAddressList->arNetAddress[j] + .aucIpAddr, + &(prNetAddrIp->in_addr), sizeof(u32)); + + j++; + } + + prNetworkAddress = + (P_PARAM_NETWORK_ADDRESS)((unsigned long) + prNetworkAddress + + (unsigned long)( + prNetworkAddress + -> + u2AddressLength + + OFFSET_OF( + PARAM_NETWORK_ADDRESS, + aucAddress))); + } + + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_IP_ADDRESS, true, + false, true, nicCmdEventSetIpAddress, + nicOidCmdTimeoutCommon, u4CmdSize, + (u8 *)prCmdNetworkAddressList, + pvSetBuffer, u4SetBufferLen); + + kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to query the power save profile. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryP2pPowerSaveProfile"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen != 0) { + ASSERT(pvQueryBuffer); + /* TODO: FIXME */ + /**(PPARAM_POWER_MODE) pvQueryBuffer = + * (PARAM_POWER_MODE)(prAdapter->rWlanInfo.arPowerSaveMode[P2P_DEV_BSS_INDEX].ucPsProfile); + */ + /**pu4QueryInfoLen = sizeof(PARAM_POWER_MODE); */ + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to set the power save profile. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS status; + PARAM_POWER_MODE ePowerMode; + + DEBUGFUNC("wlanoidSetP2pPowerSaveProfile"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_POWER_MODE); + if (u4SetBufferLen < sizeof(PARAM_POWER_MODE)) { + DBGLOG(REQ, WARN, "Invalid length %ld\n", u4SetBufferLen); + return WLAN_STATUS_INVALID_LENGTH; + } else if (*(PPARAM_POWER_MODE)pvSetBuffer >= Param_PowerModeMax) { + DBGLOG(REQ, WARN, "Invalid power mode %d\n", + *(PPARAM_POWER_MODE)pvSetBuffer); + return WLAN_STATUS_INVALID_DATA; + } + + ePowerMode = *(PPARAM_POWER_MODE)pvSetBuffer; + + if (prAdapter->fgEnCtiaPowerMode) { + if (ePowerMode == Param_PowerModeCAM) { + /*Todo:: Nothing */ + /*Todo:: Nothing */ + } else { + /* User setting to PS mode (Param_PowerModeMAX_PSP or + * Param_PowerModeFast_PSP) */ + + if (prAdapter->u4CtiaPowerMode == 0) { + /* force to keep in CAM mode */ + ePowerMode = Param_PowerModeCAM; + } else if (prAdapter->u4CtiaPowerMode == 1) { + ePowerMode = Param_PowerModeMAX_PSP; + } else if (prAdapter->u4CtiaPowerMode == 2) { + ePowerMode = Param_PowerModeFast_PSP; + } + } + } + + status = nicConfigPowerSaveProfile(prAdapter, + P2P_DEV_BSS_INDEX, /* TODO: + * FIXME + */ + ePowerMode, true); + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to set the power save profile. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2pSetNetworkAddress(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 i, j; + P_CMD_SET_NETWORK_ADDRESS_LIST prCmdNetworkAddressList; + P_PARAM_NETWORK_ADDRESS_LIST prNetworkAddressList = + (P_PARAM_NETWORK_ADDRESS_LIST)pvSetBuffer; + P_PARAM_NETWORK_ADDRESS prNetworkAddress; + P_PARAM_NETWORK_ADDRESS_IP prNetAddrIp; + u32 u4IpAddressCount, u4CmdSize; + u8 *pucBuf = (u8 *)pvSetBuffer; + + DEBUGFUNC("wlanoidSetP2pSetNetworkAddress"); + DBGLOG(INIT, TRACE, "\n"); + DBGLOG(INIT, INFO, "wlanoidSetP2pSetNetworkAddress (%d)\n", + (s16)u4SetBufferLen); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = 4; + + if (u4SetBufferLen < sizeof(PARAM_NETWORK_ADDRESS_LIST)) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu4SetInfoLen = 0; + u4IpAddressCount = 0; + + prNetworkAddress = prNetworkAddressList->arAddress; + for (i = 0; i < prNetworkAddressList->u4AddressCount; i++) { + if (prNetworkAddress->u2AddressType == + PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == + sizeof(PARAM_NETWORK_ADDRESS_IP)) { + u4IpAddressCount++; + } + + prNetworkAddress = + (P_PARAM_NETWORK_ADDRESS)((unsigned long) + prNetworkAddress + + (unsigned long)( + prNetworkAddress + -> + u2AddressLength + + OFFSET_OF( + PARAM_NETWORK_ADDRESS, + aucAddress))); + } + + /* construct payload of command packet */ + u4CmdSize = OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress) + + sizeof(IPV4_NETWORK_ADDRESS) * u4IpAddressCount; + + if (u4IpAddressCount == 0) { + u4CmdSize = sizeof(CMD_SET_NETWORK_ADDRESS_LIST); + } + + prCmdNetworkAddressList = (P_CMD_SET_NETWORK_ADDRESS_LIST)kalMemAlloc( + u4CmdSize, VIR_MEM_TYPE); + + if (prCmdNetworkAddressList == NULL) { + return WLAN_STATUS_FAILURE; + } + + kalMemZero(prCmdNetworkAddressList, u4CmdSize); + + /* fill P_CMD_SET_NETWORK_ADDRESS_LIST */ + prCmdNetworkAddressList->ucBssIndex = prNetworkAddressList->ucBssIdx; + + /* only to set IP address to FW once ARP filter is enabled */ + if (prAdapter->fgEnArpFilter) { + prCmdNetworkAddressList->ucAddressCount = (u8)u4IpAddressCount; + prNetworkAddress = prNetworkAddressList->arAddress; + + DBGLOG(INIT, INFO, "u4IpAddressCount (%ld)\n", + (s32)u4IpAddressCount); + for (i = 0, j = 0; i < prNetworkAddressList->u4AddressCount; + i++) { + if (prNetworkAddress->u2AddressType == + PARAM_PROTOCOL_ID_TCP_IP && + prNetworkAddress->u2AddressLength == + sizeof(PARAM_NETWORK_ADDRESS_IP)) { + prNetAddrIp = + (P_PARAM_NETWORK_ADDRESS_IP) + prNetworkAddress->aucAddress; + + kalMemCopy( + prCmdNetworkAddressList->arNetAddress[j] + .aucIpAddr, + &(prNetAddrIp->in_addr), sizeof(u32)); + + j++; + + pucBuf = (u8 *)&prNetAddrIp->in_addr; + DBGLOG(INIT, INFO, + "prNetAddrIp->in_addr:%d:%d:%d:%d\n", + (u8)pucBuf[0], (u8)pucBuf[1], + (u8)pucBuf[2], (u8)pucBuf[3]); + } + + prNetworkAddress = + (P_PARAM_NETWORK_ADDRESS)((unsigned long) + prNetworkAddress + + (unsigned long)( + prNetworkAddress + -> + u2AddressLength + + + OFFSET_OF + ( + PARAM_NETWORK_ADDRESS, + aucAddress))); + } + } else { + prCmdNetworkAddressList->ucAddressCount = 0; + } + + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_IP_ADDRESS, true, + false, true, nicCmdEventSetIpAddress, + nicOidCmdTimeoutCommon, u4CmdSize, + (u8 *)prCmdNetworkAddressList, + pvSetBuffer, u4SetBufferLen); + + kalMemFree(prCmdNetworkAddressList, VIR_MEM_TYPE, u4CmdSize); + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set Multicast Address List. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_MULTICAST_FULL + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2PMulticastList(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + CMD_MAC_MCAST_ADDR rCmdMacMcastAddr; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + /* The data must be a multiple of the Ethernet address size. */ + if ((u4SetBufferLen % MAC_ADDR_LEN)) { + DBGLOG(REQ, WARN, "Invalid MC list length %ld\n", + u4SetBufferLen); + + *pu4SetInfoLen = + (((u4SetBufferLen + MAC_ADDR_LEN) - 1) / MAC_ADDR_LEN) * + MAC_ADDR_LEN; + + return WLAN_STATUS_INVALID_LENGTH; + } + + *pu4SetInfoLen = u4SetBufferLen; + + /* Verify if we can support so many multicast addresses. */ + if (u4SetBufferLen > MAX_NUM_GROUP_ADDR * MAC_ADDR_LEN) { + DBGLOG(REQ, WARN, "Too many MC addresses\n"); + + return WLAN_STATUS_MULTICAST_FULL; + } + + /* NOTE(Kevin): Windows may set u4SetBufferLen == 0 && + * pvSetBuffer == NULL to clear exist Multicast List. + */ + if (u4SetBufferLen) { + ASSERT(pvSetBuffer); + } + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, + WARN, + "Fail in set multicast list! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, + prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + rCmdMacMcastAddr.u4NumOfGroupAddr = u4SetBufferLen / MAC_ADDR_LEN; + rCmdMacMcastAddr.ucBssIndex = P2P_DEV_BSS_INDEX; /* TODO: */ + kalMemCopy(rCmdMacMcastAddr.arAddress, pvSetBuffer, u4SetBufferLen); + + return wlanoidSendSetQueryP2PCmd( + prAdapter, CMD_ID_MAC_MCAST_ADDR, P2P_DEV_BSS_INDEX, + /* TODO: */ + /* This CMD response is no need to complete the OID. Or the + * event would unsync. */ + true, false, false, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, sizeof(CMD_MAC_MCAST_ADDR), + (u8 *)&rCmdMacMcastAddr, pvSetBuffer, u4SetBufferLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to send GAS frame for P2P Service Discovery + * Request + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_MULTICAST_FULL + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendP2PSDRequest(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen) { + ASSERT(pvSetBuffer); + } + + if (u4SetBufferLen < sizeof(PARAM_P2P_SEND_SD_REQUEST)) { + *pu4SetInfoLen = sizeof(PARAM_P2P_SEND_SD_REQUEST); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + /* rWlanStatus = p2pFsmRunEventSDRequest(prAdapter, + * (P_PARAM_P2P_SEND_SD_REQUEST)pvSetBuffer); */ + + return rWlanStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to send GAS frame for P2P Service Discovery + * Response + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_MULTICAST_FULL + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendP2PSDResponse(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen) { + ASSERT(pvSetBuffer); + } + + if (u4SetBufferLen < sizeof(PARAM_P2P_SEND_SD_RESPONSE)) { + *pu4SetInfoLen = sizeof(PARAM_P2P_SEND_SD_RESPONSE); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + /* rWlanStatus = p2pFsmRunEventSDResponse(prAdapter, + * (P_PARAM_P2P_SEND_SD_RESPONSE)pvSetBuffer); */ + + return rWlanStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to get GAS frame for P2P Service Discovery + * Request + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_MULTICAST_FULL + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidGetP2PSDRequest(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + /* u8 * pucChannelNum = NULL; */ + /* u8 ucChannelNum = 0, ucSeqNum = 0; */ + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < sizeof(PARAM_P2P_GET_SD_REQUEST)) { + *pu4QueryInfoLen = sizeof(PARAM_P2P_GET_SD_REQUEST); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + DBGLOG(P2P, TRACE, "Get Service Discovery Request\n"); + + *pu4QueryInfoLen = 0; + return rWlanStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to get GAS frame for P2P Service Discovery + * Response + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuffer A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufferLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_MULTICAST_FULL + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidGetP2PSDResponse(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + /* u8 ucSeqNum = 0, */ + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (u4QueryBufferLen < sizeof(PARAM_P2P_GET_SD_RESPONSE)) { + *pu4QueryInfoLen = sizeof(PARAM_P2P_GET_SD_RESPONSE); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + DBGLOG(P2P, TRACE, "Get Service Discovery Response\n"); + + *pu4QueryInfoLen = 0; + return rWlanStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to terminate P2P Service Discovery Phase + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_MULTICAST_FULL + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2PTerminateSDPhase(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_PARAM_P2P_TERMINATE_SD_PHASE prP2pTerminateSD = + (P_PARAM_P2P_TERMINATE_SD_PHASE)NULL; + u8 aucNullAddr[] = NULL_MAC_ADDR; + + do { + if ((prAdapter == NULL) || (pu4SetInfoLen == NULL)) { + break; + } + + if ((u4SetBufferLen) && (pvSetBuffer == NULL)) { + break; + } + + if (u4SetBufferLen < sizeof(PARAM_P2P_TERMINATE_SD_PHASE)) { + *pu4SetInfoLen = sizeof(PARAM_P2P_TERMINATE_SD_PHASE); + rWlanStatus = WLAN_STATUS_BUFFER_TOO_SHORT; + break; + } + + prP2pTerminateSD = (P_PARAM_P2P_TERMINATE_SD_PHASE)pvSetBuffer; + + if (EQUAL_MAC_ADDR(prP2pTerminateSD->rPeerAddr, aucNullAddr)) { + DBGLOG(P2P, TRACE, "Service Discovery Version 2.0\n"); + /* p2pFuncSetVersionNumOfSD(prAdapter, 2); */ + } + /* rWlanStatus = p2pFsmRunEventSDAbort(prAdapter); */ + } while (false); + + return rWlanStatus; +} + +#if CFG_SUPPORT_ANTI_PIRACY +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_ADAPTER_NOT_READY + * \retval WLAN_STATUS_MULTICAST_FULL + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetSecCheckRequest(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (u4SetBufferLen) { + ASSERT(pvSetBuffer); + } + + return WLAN_STATUS_NOT_SUPPORTED; +} + +#endif + +WLAN_STATUS +wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T prNoaParam; + CMD_CUSTOM_NOA_PARAM_STRUCT_T rCmdNoaParam; + + DEBUGFUNC("wlanoidSetNoaParam"); + DBGLOG(INIT, TRACE, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_NOA_PARAM_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prNoaParam = (P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T)pvSetBuffer; + + kalMemZero(&rCmdNoaParam, sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T)); + rCmdNoaParam.u4NoaDurationMs = prNoaParam->u4NoaDurationMs; + rCmdNoaParam.u4NoaIntervalMs = prNoaParam->u4NoaIntervalMs; + rCmdNoaParam.u4NoaCount = prNoaParam->u4NoaCount; + + return wlanoidSendSetQueryP2PCmd(prAdapter, CMD_ID_SET_NOA_PARAM, + prNoaParam->ucBssIdx, true, false, + true, NULL, nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_NOA_PARAM_STRUCT_T), + (u8 *)&rCmdNoaParam, pvSetBuffer, + u4SetBufferLen); +} + +WLAN_STATUS +wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T prOppPsParam; + CMD_CUSTOM_OPPPS_PARAM_STRUCT_T rCmdOppPsParam; + + DEBUGFUNC("wlanoidSetOppPsParam"); + DBGLOG(INIT, TRACE, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prOppPsParam = (P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T)pvSetBuffer; + + kalMemZero(&rCmdOppPsParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); + + rCmdOppPsParam.ucBssIdx = prOppPsParam->ucBssIdx; + + if (prOppPsParam->ucOppPs) { + /* [spec. 3.3.2] CTWindow should be at least 10 TU */ + if (prOppPsParam->u4CTwindowMs < 10) { + rCmdOppPsParam.u4CTwindowMs = 10; + } else { + rCmdOppPsParam.u4CTwindowMs = + prOppPsParam->u4CTwindowMs; + } + } else { + rCmdOppPsParam.u4CTwindowMs = 0; /* Set 0 means disable OppPs */ + } + return wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_OPPPS_PARAM, true, + false, true, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), + (u8 *)&rCmdOppPsParam, pvSetBuffer, + u4SetBufferLen); +} + +WLAN_STATUS +wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T prUapsdParam; + CMD_CUSTOM_UAPSD_PARAM_STRUCT_T rCmdUapsdParam; + P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; + P_BSS_INFO_T prBssInfo; + + DEBUGFUNC("wlanoidSetUApsdParam"); + DBGLOG(INIT, TRACE, "\n"); + + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + *pu4SetInfoLen = sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T); + + if (u4SetBufferLen < sizeof(PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T)) { + return WLAN_STATUS_INVALID_LENGTH; + } + + ASSERT(pvSetBuffer); + + prUapsdParam = (P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T)pvSetBuffer; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prUapsdParam->ucBssIdx); + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + + kalMemZero(&rCmdUapsdParam, sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T)); + rCmdUapsdParam.fgEnAPSD = prUapsdParam->fgEnAPSD; + + rCmdUapsdParam.fgEnAPSD_AcBe = prUapsdParam->fgEnAPSD_AcBe; + rCmdUapsdParam.fgEnAPSD_AcBk = prUapsdParam->fgEnAPSD_AcBk; + rCmdUapsdParam.fgEnAPSD_AcVo = prUapsdParam->fgEnAPSD_AcVo; + rCmdUapsdParam.fgEnAPSD_AcVi = prUapsdParam->fgEnAPSD_AcVi; + prPmProfSetupInfo->ucBmpDeliveryAC = + ((prUapsdParam->fgEnAPSD_AcBe << 0) | + (prUapsdParam->fgEnAPSD_AcBk << 1) | + (prUapsdParam->fgEnAPSD_AcVi << 2) | + (prUapsdParam->fgEnAPSD_AcVo << 3)); + prPmProfSetupInfo->ucBmpTriggerAC = + ((prUapsdParam->fgEnAPSD_AcBe << 0) | + (prUapsdParam->fgEnAPSD_AcBk << 1) | + (prUapsdParam->fgEnAPSD_AcVi << 2) | + (prUapsdParam->fgEnAPSD_AcVo << 3)); + + rCmdUapsdParam.ucMaxSpLen = prUapsdParam->ucMaxSpLen; + prPmProfSetupInfo->ucUapsdSp = prUapsdParam->ucMaxSpLen; + + return wlanoidSendSetQueryP2PCmd( + prAdapter, CMD_ID_SET_UAPSD_PARAM, prBssInfo->ucBssIndex, true, + false, true, NULL, nicOidCmdTimeoutCommon, + sizeof(CMD_CUSTOM_OPPPS_PARAM_STRUCT_T), (u8 *)&rCmdUapsdParam, + pvSetBuffer, u4SetBufferLen); +} + +WLAN_STATUS +wlanoidQueryP2pVersion(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; + /* u8 * pucVersionNum = (u8 *)pvQueryBuffer; */ + + do { + if ((prAdapter == NULL) || (pu4QueryInfoLen == NULL)) { + break; + } + + if ((u4QueryBufferLen) && (pvQueryBuffer == NULL)) { + break; + } + + if (u4QueryBufferLen < sizeof(u8)) { + *pu4QueryInfoLen = sizeof(u8); + rResult = WLAN_STATUS_BUFFER_TOO_SHORT; + break; + } + } while (false); + + return rResult; +} + +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to set the WPS mode. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set. + * \param[in] u4SetBufferLen The length of the set buffer. + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed + * due to invalid length of the set buffer, returns + * the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetP2pWPSmode(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS status; + u32 u4IsWPSmode = 0; + int i = 0; + + DEBUGFUNC("wlanoidSetP2pWPSmode"); + ASSERT(prAdapter); + ASSERT(pu4SetInfoLen); + + if (pvSetBuffer) { + u4IsWPSmode = *(u32 *)pvSetBuffer; + }else{ + u4IsWPSmode = 0; + } + + for (i = 0; i < KAL_P2P_NUM; i++) /* set all Role to the same value */ + if (u4IsWPSmode) { + prAdapter->rWifiVar.prP2PConnSettings[i]->fgIsWPSMode = + 1; + } else { + prAdapter->rWifiVar.prP2PConnSettings[i]->fgIsWPSMode = + 0; + } + + status = nicUpdateBss(prAdapter, P2P_DEV_BSS_INDEX); + + return status; +} + +#endif + +WLAN_STATUS +wlanoidSetP2pSupplicantVersion(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, + IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rResult = WLAN_STATUS_FAILURE; + u8 ucVersionNum; + + do { + if ((prAdapter == NULL) || (pu4SetInfoLen == NULL)) { + rResult = WLAN_STATUS_INVALID_DATA; + break; + } + + if ((u4SetBufferLen) && (pvSetBuffer == NULL)) { + rResult = WLAN_STATUS_INVALID_DATA; + break; + } + + *pu4SetInfoLen = sizeof(u8); + + if (u4SetBufferLen < sizeof(u8)) { + rResult = WLAN_STATUS_INVALID_LENGTH; + break; + } + + ucVersionNum = *((u8 *)pvSetBuffer); + + rResult = WLAN_STATUS_SUCCESS; + } while (false); + + return rResult; +} + +#if CFG_SUPPORT_P2P_RSSI_QUERY +WLAN_STATUS +wlanoidQueryP2pRssi(IN P_ADAPTER_T prAdapter, IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + DEBUGFUNC("wlanoidQueryP2pRssi"); + + ASSERT(prAdapter); + ASSERT(pu4QueryInfoLen); + if (u4QueryBufferLen) { + ASSERT(pvQueryBuffer); + } + + if (prAdapter->fgIsEnableLpdvt) { + return WLAN_STATUS_NOT_SUPPORTED; + } + + *pu4QueryInfoLen = sizeof(PARAM_RSSI); + + /* Check for query buffer length */ + if (u4QueryBufferLen < *pu4QueryInfoLen) { + DBGLOG(REQ, WARN, "Too short length %ld\n", u4QueryBufferLen); + return WLAN_STATUS_BUFFER_TOO_SHORT; + } + + if (prAdapter->fgIsP2pLinkQualityValid == true && + (kalGetTimeTick() - prAdapter->rP2pLinkQualityUpdateTime) <= + CFG_LINK_QUALITY_VALID_PERIOD) { + PARAM_RSSI rRssi; + + rRssi = (PARAM_RSSI)prAdapter->rP2pLinkQuality.cRssi; /* ranged + * from + * (-128 ~ + * 30) in + * unit of + * dBm */ + + if (rRssi > PARAM_WHQL_RSSI_MAX_DBM) { + rRssi = PARAM_WHQL_RSSI_MAX_DBM; + }else if (rRssi < PARAM_WHQL_RSSI_MIN_DBM) { + rRssi = PARAM_WHQL_RSSI_MIN_DBM; + } + + kalMemCopy(pvQueryBuffer, &rRssi, sizeof(PARAM_RSSI)); + return WLAN_STATUS_SUCCESS; + } + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_GET_LINK_QUALITY, false, + true, true, nicCmdEventQueryLinkQuality, + nicOidCmdTimeoutCommon, *pu4QueryInfoLen, + pvQueryBuffer, pvQueryBuffer, + u4QueryBufferLen); +} +#endif + +u32 wlanoidAbortP2pScan(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen) +{ + u8 ucBssIdx; + + ASSERT(prAdapter); + + ucBssIdx = *((u8 *)pvQueryBuffer); + + if (ucBssIdx == prAdapter->ucP2PDevBssIdx) { + p2pDevFsmRunEventScanAbort(prAdapter, ucBssIdx); + }else{ + p2pRoleFsmRunEventScanAbort(prAdapter, ucBssIdx); + } + + return WLAN_STATUS_SUCCESS; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/firmware/TxPwrLimit_MT76x8.dat b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/firmware/TxPwrLimit_MT76x8.dat new file mode 100644 index 00000000000000..380294f4c37d87 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/firmware/TxPwrLimit_MT76x8.dat @@ -0,0 +1,1878 @@ +# The unit of each TxPower value is 0.5dBm. +# 'x' means use efuse default value instead of from this table +# Channels in the table are treated as center channel. + +[00] +<legacy, cck1_2, cck5_11, ofdm6_9, ofdm12_18, ofdm24_36, ofdm48, ofdm54> + ch001, 24, 24, 27, 27, 27, 27, 27 + ch002, 24, 24, 27, 27, 27, 27, 27 + ch003, 24, 24, 27, 27, 27, 27, 27 + ch004, 24, 24, 27, 27, 27, 27, 27 + ch005, 24, 24, 27, 27, 27, 27, 27 + ch006, 24, 24, 27, 27, 27, 27, 27 + ch007, 24, 24, 27, 27, 27, 27, 27 + ch008, 24, 24, 27, 27, 27, 27, 27 + ch009, 24, 24, 27, 27, 27, 27, 27 + ch010, 24, 24, 27, 27, 27, 27, 27 + ch011, 24, 24, 27, 27, 27, 27, 27 + ch012, 22, 22, 27, 27, 27, 27, 27 + ch013, 22, 22, 27, 27, 27, 27, 27 + ch014, x, x, x, x, x, x, x + ch036, x, x, 20, 20, 20, 20, 20 + ch038, x, x, x, x, x, x, x + ch040, x, x, 20, 20, 20, 20, 20 + ch042, x, x, x, x, x, x, x + ch044, x, x, 20, 20, 20, 20, 20 + ch046, x, x, x, x, x, x, x + ch048, x, x, 20, 20, 20, 20, 20 + ch050, x, x, x, x, x, x, x + ch052, x, x, 16, 16, 16, 16, 16 + ch054, x, x, x, x, x, x, x + ch056, x, x, 16, 16, 16, 16, 16 + ch058, x, x, x, x, x, x, x + ch060, x, x, 15, 15, 15, 15, 15 + ch062, x, x, x, x, x, x, x + ch064, x, x, 14, 14, 14, 14, 14 + ch100, x, x, 23, 23, 23, 23, 23 + ch102, x, x, x, x, x, x, x + ch104, x, x, 23, 23, 23, 23, 23 + ch106, x, x, x, x, x, x, x + ch108, x, x, 23, 23, 23, 23, 23 + ch110, x, x, x, x, x, x, x + ch112, x, x, 23, 23, 23, 23, 23 + ch114, x, x, x, x, x, x, x + ch116, x, x, 24, 24, 24, 24, 24 + ch118, x, x, x, x, x, x, x + ch120, x, x, 24, 24, 24, 24, 24 + ch122, x, x, x, x, x, x, x + ch124, x, x, 24, 24, 24, 24, 24 + ch126, x, x, x, x, x, x, x + ch128, x, x, 24, 24, 24, 24, 24 + ch132, x, x, 24, 24, 24, 24, 24 + ch134, x, x, x, x, x, x, x + ch136, x, x, 24, 24, 24, 24, 24 + ch138, x, x, x, x, x, x, x + ch140, x, x, 24, 24, 24, 24, 24 + ch142, x, x, x, x, x, x, x + ch144, x, x, 33, 33, 33, 33, 33 + ch149, x, x, 14, 14, 14, 14, 14 + ch151, x, x, x, x, x, x, x + ch153, x, x, 14, 14, 14, 14, 14 + ch155, x, x, x, x, x, x, x + ch157, x, x, 14, 14, 14, 14, 14 + ch159, x, x, x, x, x, x, x + ch161, x, x, 14, 14, 14, 14, 14 + ch165, x, x, 15, 15, 15, 15, 15 +</legacy> + +<ht20, mcs0_8, mcs1_2_9_10, mcs3_4_11_12, mcs5_13, mcs6_14, mcs7_15> +ch001, 28, 28, 28, 28, 28, 28 +ch002, 28, 28, 28, 28, 28, 28 +ch003, 27, 27, 27, 27, 27, 27 +ch004, 27, 27, 27, 27, 27, 27 +ch005, 27, 27, 27, 27, 27, 27 +ch006, 27, 27, 27, 27, 27, 27 +ch007, 27, 27, 27, 27, 27, 27 +ch008, 27, 27, 27, 27, 27, 27 +ch009, 27, 27, 27, 27, 27, 27 +ch010, 27, 27, 27, 27, 27, 27 +ch011, 27, 27, 27, 27, 27, 27 +ch012, 27, 27, 27, 27, 27, 27 +ch013, 27, 27, 27, 27, 27, 27 +ch014, x, x, x, x, x, x +ch036, 20, 20, 20, 20, 20, 20 +ch038, x, x, x, x, x, x +ch040, 20, 20, 20, 20, 20, 20 +ch042, x, x, x, x, x, x +ch044, 20, 20, 20, 20, 20, 20 +ch046, x, x, x, x, x, x +ch048, 20, 20, 20, 20, 20, 20 +ch050, x, x, x, x, x, x +ch052, 18, 18, 18, 18, 18, 18 +ch054, x, x, x, x, x, x +ch056, 18, 18, 18, 18, 18, 18 +ch058, x, x, x, x, x, x +ch060, 17, 17, 17, 17, 17, 17 +ch062, x, x, x, x, x, x +ch064, 16, 16, 16, 16, 16, 16 +ch100, 24, 24, 24, 24, 24, 24 +ch102, x, x, x, x, x, x +ch104, 24, 24, 24, 24, 24, 24 +ch106, x, x, x, x, x, x +ch108, 24, 24, 24, 24, 24, 24 +ch110, x, x, x, x, x, x +ch112, 24, 24, 24, 24, 24, 24 +ch114, x, x, x, x, x, x +ch116, 24, 24, 24, 24, 24, 24 +ch118, x, x, x, x, x, x +ch120, 24, 24, 24, 24, 24, 24 +ch122, x, x, x, x, x, x +ch124, 24, 24, 24, 24, 24, 24 +ch126, x, x, x, x, x, x +ch128, 24, 24, 24, 24, 24, 24 +ch132, 24, 24, 24, 24, 24, 24 +ch134, x, x, x, x, x, x +ch136, 24, 24, 24, 24, 24, 24 +ch138, x, x, x, x, x, x +ch140, 24, 24, 24, 24, 24, 24 +ch142, x, x, x, x, x, x +ch144, 33, 33, 33, 33, 33, 33 +ch149, 14, 14, 14, 14, 14, 14 +ch151, x, x, x, x, x, x +ch153, 14, 14, 14, 14, 14, 14 +ch155, x, x, x, x, x, x +ch157, 14, 14, 14, 14, 14, 14 +ch159, x, x, x, x, x, x +ch161, 14, 14, 14, 14, 14, 14 +ch165, 15, 15, 15, 15, 15, 15 +</ht20> + +<ht40, mcs0_8, mcs1_2_9_10, mcs3_4_11_12, mcs5_13, mcs6_14, mcs7_15, mcs32> +ch001, x, x, x, x, x, x, x +ch002, x, x, x, x, x, x, x +ch003, x, x, x, x, x, x, x +ch004, x, x, x, x, x, x, x +ch005, x, x, x, x, x, x, x +ch006, x, x, x, x, x, x, x +ch007, x, x, x, x, x, x, x +ch008, x, x, x, x, x, x, x +ch009, x, x, x, x, x, x, x +ch010, x, x, x, x, x, x, x +ch011, x, x, x, x, x, x, x +ch012, x, x, x, x, x, x, x +ch013, x, x, x, x, x, x, x +ch014, x, x, x, x, x, x, x +ch036, x, x, x, x, x, x, x +ch038, 23, 23, 23, 23, 23, 23, 23 +ch040, x, x, x, x, x, x, x +ch042, x, x, x, x, x, x, x +ch044, x, x, x, x, x, x, x +ch046, 25, 25, 25, 25, 25, 25, 25 +ch048, x, x, x, x, x, x, x +ch050, x, x, x, x, x, x, x +ch052, x, x, x, x, x, x, x +ch054, 16, 16, 16, 16, 16, 16, 16 +ch056, x, x, x, x, x, x, x +ch058, x, x, x, x, x, x, x +ch060, x, x, x, x, x, x, x +ch062, 16, 16, 16, 16, 16, 16, 16 +ch064, x, x, x, x, x, x, x +ch100, x, x, x, x, x, x, x +ch102, 27, 27, 27, 27, 27, 27, 27 +ch104, x, x, x, x, x, x, x +ch106, x, x, x, x, x, x, x +ch108, x, x, x, x, x, x, x +ch110, 30, 30, 30, 30, 30, 30, 30 +ch112, x, x, x, x, x, x, x +ch114, x, x, x, x, x, x, x +ch116, x, x, x, x, x, x, x +ch118, 30, 30, 30, 30, 30, 30, 30 +ch120, x, x, x, x, x, x, x +ch122, x, x, x, x, x, x, x +ch124, x, x, x, x, x, x, x +ch126, 30, 30, 30, 30, 30, 30, 30 +ch128, x, x, x, x, x, x, x +ch132, x, x, x, x, x, x, x +ch134, 30, 30, 30, 30, 30, 30, 30 +ch136, x, x, x, x, x, x, x +ch138, x, x, x, x, x, x, x +ch140, x, x, x, x, x, x, x +ch142, 38, 38, 38, 38, 38, 38, 38 +ch144, x, x, x, x, x, x, x +ch149, x, x, x, x, x, x, x +ch151, 14, 14, 14, 14, 14, 14, 14 +ch153, x, x, x, x, x, x, x +ch155, x, x, x, x, x, x, x +ch157, x, x, x, x, x, x, x +ch159, 15, 15, 15, 15, 15, 15, 15 +ch161, x, x, x, x, x, x, x +ch165, x, x, x, x, x, x, x +</ht40> + +<vht20, mcs0, mcs1_2, mcs3_4, mcs5_6, mcs7, mcs8, mcs9> + ch001, 28, 28, 28, 28, 28, 28 + ch002, 28, 28, 28, 28, 28, 28 + ch003, 27, 27, 27, 27, 27, 27 + ch004, 27, 27, 27, 27, 27, 27 + ch005, 27, 27, 27, 27, 27, 27 + ch006, 27, 27, 27, 27, 27, 27 + ch007, 27, 27, 27, 27, 27, 27 + ch008, 27, 27, 27, 27, 27, 27 + ch009, 27, 27, 27, 27, 27, 27 + ch010, 27, 27, 27, 27, 27, 27 + ch011, 27, 27, 27, 27, 27, 27 + ch012, 27, 27, 27, 27, 27, 27 + ch013, 27, 27, 27, 27, 27, 27 + ch014, x, x, x, x, x, x, x + ch036, 19, 19, 19, 19, 19, 19, 19 + ch038, 20, 20, 20, 20, 20, 20, 20 + ch040, 19, 19, 19, 19, 19, 19, 19 + ch042, 21, 21, 21, 21, 21, 21, 21 + ch044, 19, 19, 19, 19, 19, 19, 19 + ch046, 20, 20, 20, 20, 20, 20, 20 + ch048, 19, 19, 19, 19, 19, 19, 19 + ch050, x, x, x, x, x, x, x + ch052, 18, 18, 18, 18, 18, 18, 18 + ch054, 18, 18, 18, 18, 18, 18, 18 + ch056, 18, 18, 18, 18, 18, 18, 18 + ch058, 22, 22, 22, 22, 22, 22, 22 + ch060, 17, 17, 17, 17, 17, 17, 17 + ch062, 17, 17, 17, 17, 17, 17, 17 + ch064, 17, 17, 17, 17, 17, 17, 17 + ch100, 24, 24, 24, 24, 24, 24, 24 + ch102, 24, 24, 24, 24, 24, 24, 24 + ch104, 24, 24, 24, 24, 24, 24, 24 + ch106, 24, 24, 24, 24, 24, 24, 24 + ch108, 24, 24, 24, 24, 24, 24, 24 + ch110, 24, 24, 24, 24, 24, 24, 24 + ch112, 24, 24, 24, 24, 24, 24, 24 + ch114, 24, 24, 24, 24, 24, 24, 24 + ch116, 24, 24, 24, 24, 24, 24, 24 + ch118, 24, 24, 24, 24, 24, 24, 24 + ch120, 24, 24, 24, 24, 24, 24, 24 + ch122, 24, 24, 24, 24, 24, 24, 24 + ch124, 24, 24, 24, 24, 24, 24, 24 + ch126, 24, 24, 24, 24, 24, 24, 24 + ch128, 24, 24, 24, 24, 24, 24, 24 + ch132, 24, 24, 24, 24, 24, 24, 24 + ch134, 24, 24, 24, 24, 24, 24, 24 + ch136, 24, 24, 24, 24, 24, 24, 24 + ch138, 38, 38, 38, 38, 38, 38, 38 + ch140, 23, 23, 23, 23, 23, 23, 23 + ch142, 32, 32, 32, 32, 32, 32, 32 + ch144, 32, 32, 32, 32, 32, 32, 32 + ch149, 14, 14, 14, 14, 14, 14, 14 + ch151, 12, 12, 12, 12, 12, 12, 12 + ch153, 14, 14, 14, 14, 14, 14, 14 + ch155, 14, 14, 14, 14, 14, 14, 14 + ch157, 14, 14, 14, 14, 14, 14, 14 + ch159, 14, 14, 14, 14, 14, 14, 14 + ch161, 14, 14, 14, 14, 14, 14, 14 + ch165, 15, 15, 15, 15, 15, 15, 15 + </vht20> + +<offset, lg40, lg80, vht40, vht80, vht160nc> + ch001, x, x, x, x, x + ch002, x, x, x, x, x + ch003, x, x, x, x, x + ch004, x, x, x, x, x + ch005, x, x, x, x, x + ch006, x, x, x, x, x + ch007, x, x, x, x, x + ch008, x, x, x, x, x + ch009, x, x, x, x, x + ch010, x, x, x, x, x + ch011, x, x, x, x, x + ch012, x, x, x, x, x + ch013, x, x, x, x, x + ch014, x, x, x, x, x + ch036, x, x, x, x, x + ch038, x, x, 3, x, x + ch040, x, x, x, x, x + ch042, x, x, x, -1, x + ch044, x, x, x, x, x + ch046, x, x, 5, x, x + ch048, x, x, x, x, x + ch050, x, x, x, x, x + ch052, x, x, x, x, x + ch054, x, x, -2, x, x + ch056, x, x, x, x, x + ch058, x, x, x, -1, x + ch060, x, x, x, x, x + ch062, x, x, -1, x, x + ch064, x, x, x, x, x + ch100, x, x, x, x, x + ch102, x, x, 4, x, x + ch104, x, x, x, x, x + ch106, x, x, x, 1, x + ch108, x, x, x, x, x + ch110, x, x, 5, x, x + ch112, x, x, x, x, x + ch114, x, x, x, x, x + ch116, x, x, x, x, x + ch118, x, x, 5, x, x + ch120, x, x, x, x, x + ch122, x, x, x, 7, x + ch124, x, x, x, x, x + ch126, x, x, 5, x, x + ch128, x, x, x, x, x + ch132, x, x, x, x, x + ch134, x, x, 5, x, x + ch136, x, x, x, x, x + ch138, x, x, x, 2, x + ch140, x, x, x, x, x + ch142, x, x, 4, x, x + ch144, x, x, x, x, x + ch149, x, x, x, x, x + ch151, x, x, 2, x, x + ch153, x, x, x, x, x + ch155, x, x, x, 1, x + ch157, x, x, x, x, x + ch159, x, x, 1, x, x + ch161, x, x, x, x, x + ch165, x, x, x, x, x +</offset> + +[US] +<legacy, cck1_2, cck5_11, ofdm6_9, ofdm12_18, ofdm24_36, ofdm48, ofdm54> + ch001, 37, 37, 33, 33, 33, 33, 33 + ch002, 37, 37, 33, 33, 33, 33, 33 + ch003, 37, 37, 38, 38, 38, 38, 38 + ch004, 37, 37, 38, 38, 38, 38, 38 + ch005, 37, 37, 38, 38, 38, 38, 38 + ch006, 37, 37, 38, 38, 38, 38, 38 + ch007, 37, 37, 38, 38, 38, 38, 38 + ch008, 37, 37, 38, 38, 38, 38, 38 + ch009, 37, 37, 38, 38, 38, 38, 38 + ch010, 33, 33, 33, 33, 33, 33, 33 + ch011, 33, 33, 33, 33, 33, 33, 33 + ch012, x, x, x, x, x, x, x + ch013, x, x, x, x, x, x, x + ch014, x, x, x, x, x, x, x + ch036, x, x, 35, 35, 35, 35, 35 + ch038, x, x, x, x, x, x, x + ch040, x, x, 35, 35, 35, 35, 35 + ch042, x, x, x, x, x, x, x + ch044, x, x, 35, 35, 35, 35, 35 + ch046, x, x, x, x, x, x, x + ch048, x, x, 34, 34, 34, 34, 34 + ch050, x, x, x, x, x, x, x + ch052, x, x, 34, 34, 34, 34, 34 + ch054, x, x, x, x, x, x, x + ch056, x, x, 34, 34, 34, 34, 34 + ch058, x, x, x, x, x, x, x + ch060, x, x, 34, 34, 34, 34, 34 + ch062, x, x, x, x, x, x, x + ch064, x, x, 34, 34, 34, 34, 34 + ch100, x, x, 34, 34, 34, 34, 34 + ch102, x, x, x, x, x, x, x + ch104, x, x, 33, 33, 33, 33, 33 + ch106 x, x, x, x, x, x, x + ch108 x, x, 33, 33, 33, 33, 33 + ch110 x, x, x, x, x, x, x + ch112 x, x, 33, 33, 33, 33, 33 + ch114, x, x, x, x, x, x, x + ch116, x, x, 33, 33, 33, 33, 33 + ch118, x, x, x, x, x, x, x + ch120, x, x, 33, 33, 33, 33, 33 + ch122, x, x, x, x, x, x, x + ch124, x, x, 33, 33, 33, 33, 33 + ch126, x, x, x, x, x, x, x + ch128, x, x, 33, 33, 33, 33, 33 + ch132, x, x, 33, 33, 33, 33, 33 + ch134, x, x, x, x, x, x, x + ch136, x, x, 33, 33, 33, 33, 33 + ch138, x, x, x, x, x, x, x + ch140, x, x, 34, 34, 34, 34, 34 + ch142, x, x, x, x, x, x, x + ch144, x, x, 34, 34, 34, 34, 34 + ch149, x, x, 38, 38, 38, 38, 38 + ch151, x, x, x, x, x, x, x + ch153, x, x, 38, 38, 38, 38, 38 + ch155, x, x, x, x, x, x, x + ch157, x, x, 38, 38, 38, 38, 38 + ch159, x, x, x, x, x, x, x + ch161, x, x, 38, 38, 38, 38, 38 + ch165, x, x, 38, 38, 38, 38, 38 +</legacy> + +<ht20, mcs0_8, mcs1_2_9_10, mcs3_4_11_12, mcs5_13, mcs6_14, mcs7_15> +ch001, 31, 31, 31, 31, 31, 31 +ch002, 31, 31, 31, 31, 31, 31 +ch003, 39, 39, 39, 39, 39, 39 +ch004, 39, 39, 39, 39, 39, 39 +ch005, 39, 39, 39, 39, 39, 39 +ch006, 39, 39, 39, 39, 39, 39 +ch007, 39, 39, 39, 39, 39, 39 +ch008, 39, 39, 39, 39, 39, 39 +ch009, 39, 39, 39, 39, 39, 39 +ch010, 30, 30, 30, 30, 30, 30 +ch011, 30, 30, 30, 30, 30, 30 +ch012, x, x, x, x, x, x +ch013, x, x, x, x, x, x +ch014, x, x, x, x, x, x +ch036, 34, 34, 34, 34, 34, 34 +ch038, x, x, x, x, x, x +ch040, 35, 35, 35, 35, 35, 35 +ch042, x, x, x, x, x, x +ch044, 35, 35, 35, 35, 35, 35 +ch046, x, x, x, x, x, x +ch048, 35, 35, 35, 35, 35, 35 +ch050, x, x, x, x, x, x +ch052, 35, 35, 35, 35, 35, 35 +ch054, x, x, x, x, x, x +ch056, 35, 35, 35, 35, 35, 35 +ch058, x, x, x, x, x, x +ch060, 35, 35, 35, 35, 35, 35 +ch062, x, x, x, x, x, x +ch064, 35, 35, 35, 35, 35, 35 +ch100, 33, 33, 33, 33, 33, 33 +ch102, x, x, x, x, x, x +ch104, 33, 33, 33, 33, 33, 33 +ch106, x, x, x, x, x, x +ch108, 33, 33, 33, 33, 33, 33 +ch110, x, x, x, x, x, x +ch112, 33, 33, 33, 33, 33, 33 +ch114, x, x, x, x, x, x +ch116, 33, 33, 33, 33, 33, 33 +ch118, x, x, x, x, x, x +ch120, 33, 33, 33, 33, 33, 33 +ch122, x, x, x, x, x, x +ch124, 33, 33, 33, 33, 33, 33 +ch126, x, x, x, x, x, x +ch128, 33, 33, 33, 33, 33, 33 +ch132, x, x, x, x, x, x +ch134, x, x, x, x, x, x +ch136, 33, 33, 33, 33, 33, 33 +ch138, x, x, x, x, x, x +ch140, 30, 30, 30, 30, 30, 30 +ch142, x, x, x, x, x, x +ch144, 33, 33, 33, 33, 33, 33 +ch149, 40, 40, 40, 40, 40, 40 +ch151, x, x, x, x, x, x +ch153, 40, 40, 40, 40, 40, 40 +ch155, x, x, x, x, x, x +ch157, 40, 40, 40, 40, 40, 40 +ch159, x, x, x, x, x, x +ch161, 40, 40, 40, 40, 40, 40 +ch165, 40, 40, 40, 40, 40, 40 +</ht20> + +<ht40, mcs0_8, mcs1_2_9_10, mcs3_4_11_12, mcs5_13, mcs6_14, mcs7_15, mcs32> +ch001, x, x, x, x, x, x, x +ch002, x, x, x, x, x, x, x +ch003, x, x, x, x, x, x, x +ch004, x, x, x, x, x, x, x +ch005, x, x, x, x, x, x, x +ch006, x, x, x, x, x, x, x +ch007, x, x, x, x, x, x, x +ch008, x, x, x, x, x, x, x +ch009, x, x, x, x, x, x, x +ch010, x, x, x, x, x, x, x +ch011, x, x, x, x, x, x, x +ch012, x, x, x, x, x, x, x +ch013, x, x, x, x, x, x, x +ch014, x, x, x, x, x, x, x +ch036, x, x, x, x, x, x, x +ch038, 27, 27, 27, 27, 27, 27, 27 +ch040, x, x, x, x, x, x, x +ch042, x, x, x, x, x, x, x +ch044, x, x, x, x, x, x, x +ch046, 38, 38, 38, 38, 38, 38, 38 +ch048, x, x, x, x, x, x, x +ch050, x, x, x, x, x, x, x +ch052, x, x, x, x, x, x, x +ch054, 39, 39, 39, 39, 39, 39, 39 +ch056, x, x, x, x, x, x, x +ch058, x, x, x, x, x, x, x +ch060, x, x, x, x, x, x, x +ch062, 28, 28, 28, 28, 28, 28, 28 +ch064, x, x, x, x, x, x, x +ch100, x, x, x, x, x, x, x +ch102, 27, 27, 27, 27, 27, 27, 27 +ch104, x, x, x, x, x, x, x +ch106, x, x, x, x, x, x, x +ch108, x, x, x, x, x, x, x +ch110, 38, 38, 38, 38, 38, 38, 38 +ch112, x, x, x, x, x, x, x +ch114, x, x, x, x, x, x, x +ch116, x, x, x, x, x, x, x +ch118, 38, 38, 38, 38, 38, 38, 38 +ch120, x, x, x, x, x, x, x +ch122, x, x, x, x, x, x, x +ch124, x, x, x, x, x, x, x +ch126, 38, 38, 38, 38, 38, 38, 38 +ch128, x, x, x, x, x, x, x +ch132, x, x, x, x, x, x, x +ch134, 33, 33, 33, 33, 33, 33, 33 +ch136, x, x, x, x, x, x, x +ch138, x, x, x, x, x, x, x +ch140, x, x, x, x, x, x, x +ch142, 39, 39, 39, 39, 39, 39, 39 +ch144, x, x, x, x, x, x, x +ch149, x, x, x, x, x, x, x +ch151, 39, 39, 39, 39, 39, 39, 39 +ch153, x, x, x, x, x, x, x +ch155, x, x, x, x, x, x, x +ch157, x, x, x, x, x, x, x +ch159, 37, 37, 37, 37, 37, 37, 37 +ch161, x, x, x, x, x, x, x +ch165, x, x, x, x, x, x, x +</ht40> + +<vht20, mcs0, mcs1_2, mcs3_4, mcs5_6, mcs7, mcs8, mcs9> + ch001, 32, 32, 32, 32, 32, 32, 32 + ch002, 32, 32, 32, 32, 32, 32, 32 + ch003, 39, 39, 39, 39, 39, 39, 39 + ch004, 39, 39, 39, 39, 39, 39, 39 + ch005, 39, 39, 39, 39, 39, 39, 39 + ch006, 39, 39, 39, 39, 39, 39, 39 + ch007, 39, 39, 39, 39, 39, 39, 39 + ch008, 39, 39, 39, 39, 39, 39, 39 + ch009, 39, 39, 39, 39, 39, 39, 39 + ch010, 31, 31, 31, 31, 31, 31, 31 + ch011, 31, 31, 31, 31, 31, 31, 31 + ch012, x, x, x, x, x, x, x + ch013, x, x, x, x, x, x, x + ch014, x, x, x, x, x, x, x + ch036, 32, 32, 32, 32, 32, 32, 32 + ch038, 31, 31, 31, 31, 31, 31, 31 + ch040, 35, 35, 35, 35, 35, 35, 35 + ch042, 27, 27, 27, 27, 27, 27, 27 + ch044, 35, 35, 35, 35, 35, 35, 35 + ch046, 31, 31, 31, 31, 31, 31, 31 + ch048, 35, 35, 35, 35, 35, 35, 35 + ch050, 31, 31, 31, 31, 31, 31, 31 + ch052, 35, 35, 35, 35, 35, 35, 35 + ch054, 31, 31, 31, 31, 31, 31, 31 + ch056, 35, 35, 35, 35, 35, 35, 35 + ch058, 31, 31, 31, 31, 31, 31, 31 + ch060, 35, 35, 35, 35, 35, 35, 35 + ch062, 31, 31, 31, 31, 31, 31, 31 + ch064, 35, 35, 35, 35, 35, 35, 35 + ch100, 33, 33, 33, 33, 33, 33, 33 + ch102, 31, 31, 31, 31, 31, 31, 31 + ch104, 33, 33, 33, 33, 33, 33, 33 + ch106, 31, 31, 31, 31, 31, 31, 31 + ch108, 33, 33, 33, 33, 33, 33, 33 + ch110, 31, 31, 31, 31, 31, 31, 31 + ch112, 33, 33, 33, 33, 33, 33, 33 + ch114, 31, 31, 31, 31, 31, 31, 31 + ch116, 33, 33, 33, 33, 33, 33, 33 + ch118, 31, 31, 31, 31, 31, 31, 31 + ch120, 33, 33, 33, 33, 33, 33, 33 + ch122, 31, 31, 31, 31, 31, 31, 31 + ch124, 33, 33, 33, 33, 33, 33, 33 + ch126, 31, 31, 31, 31, 31, 31, 31 + ch128, 33, 33, 33, 33, 33, 33, 33 + ch132, 33, 33, 33, 33, 33, 33, 33 + ch134, 31, 31, 31, 31, 31, 31, 31 + ch136, 33, 33, 33, 33, 33, 33, 33 + ch138, 33, 33, 33, 33, 33, 33, 33 + ch140, 30, 30, 30, 30, 30, 30, 30 + ch142, 30, 30, 30, 30, 30, 30, 30 + ch144, 32, 32, 32, 32, 32, 32, 32 + ch149, 40, 40, 40, 40, 40, 40, 40 + ch151, 31, 31, 31, 31, 31, 31, 31 + ch153, 40, 40, 40, 40, 40, 40, 40 + ch155, 31, 31, 31, 31, 31, 31, 31 + ch157, 40, 40, 40, 40, 40, 40, 40 + ch159, 31, 31, 31, 31, 31, 31, 31 + ch161, 40, 40, 40, 40, 40, 40, 40 + ch165, 40, 40, 40, 40, 40, 40, 40 + </vht20> + +<offset, lg40, lg80, vht40, vht80, vht160nc> + ch001, x, x, x, x, x + ch002, x, x, x, x, x + ch003, x, x, x, x, x + ch004, x, x, x, x, x + ch005, x, x, x, x, x + ch006, x, x, x, x, x + ch007, x, x, x, x, x + ch008, x, x, x, x, x + ch009, x, x, x, x, x + ch010, x, x, x, x, x + ch011, x, x, x, x, x + ch012, x, x, x, x, x + ch013, x, x, x, x, x + ch014, x, x, x, x, x + ch036, x, x, x, x, x + ch038, x, x, -3, x, x + ch040, x, x, x, x, x + ch042, x, x, x, -6, x + ch044, x, x, x, x, x + ch046, x, x, 7, x, x + ch048, x, x, x, x, x + ch050, x, x, x, x, x + ch052, x, x, x, x, x + ch054, x, x, 7, x, x + ch056, x, x, x, x, x + ch058, x, x, x, -5, x + ch060, x, x, x, x, x + ch062, x, x, -3, x, x + ch064, x, x, x, x, x + ch100, x, x, x, x, x + ch102, x, x, 2, x, x + ch104, x, x, x, x, x + ch106, x, x, x, -5, x + ch108, x, x, x, x, x + ch110, x, x, 7, x, x + ch112, x, x, x, x, x + ch114, x, x, x, x, x + ch116, x, x, x, x, x + ch118, x, x, 7, x, x + ch120, x, x, x, x, x + ch122, x, x, x, 7, x + ch124, x, x, x, x, x + ch126, x, x, 7, x, x + ch128, x, x, x, x, x + ch132, x, x, x, x, x + ch134, x, x, 3, x, x + ch136, x, x, x, x, x + ch138, x, x, x, 7, x + ch140, x, x, x, x, x + ch142, x, x, 6, x, x + ch144, x, x, x, x, x + ch149, x, x, x, x, x + ch151, x, x, 7, x, x + ch153, x, x, x, x, x + ch155, x, x, x, 1, x + ch157, x, x, x, x, x + ch159, x, x, 7, x, x + ch161, x, x, x, x, x + ch165, x, x, x, x, x +</offset> + +[GB,DE,AT,IT,ES,FR] +<legacy, cck1_2, cck5_11, ofdm6_9, ofdm12_18, ofdm24_36, ofdm48, ofdm54> + ch001, 24, 24, 27, 27, 27, 27, 27 + ch002, 24, 24, 27, 27, 27, 27, 27 + ch003, 24, 24, 27, 27, 27, 27, 27 + ch004, 24, 24, 27, 27, 27, 27, 27 + ch005, 24, 24, 27, 27, 27, 27, 27 + ch006, 24, 24, 27, 27, 27, 27, 27 + ch007, 24, 24, 27, 27, 27, 27, 27 + ch008, 24, 24, 27, 27, 27, 27, 27 + ch009, 24, 24, 27, 27, 27, 27, 27 + ch010, 24, 24, 27, 27, 27, 27, 27 + ch011, 24, 24, 27, 27, 27, 27, 27 + ch012, 22, 22, 27, 27, 27, 27, 27 + ch013, 22, 22, 27, 27, 27, 27, 27 + ch014, x, x, x, x, x, x, x + ch036, x, x, 24, 24, 24, 24, 24 + ch038, x, x, x, x, x, x, x + ch040, x, x, 24, 24, 24, 24, 24 + ch042, x, x, x, x, x, x, x + ch044, x, x, 24, 24, 24, 24, 24 + ch046, x, x, x, x, x, x, x + ch048, x, x, 24, 24, 24, 24, 24 + ch050, x, x, x, x, x, x, x + ch052, x, x, 24, 24, 24, 24, 24 + ch054, x, x, x, x, x, x, x + ch056, x, x, 24, 24, 24, 24, 24 + ch058, x, x, x, x, x, x, x + ch060, x, x, 24, 24, 24, 24, 24 + ch062, x, x, x, x, x, x, x + ch064, x, x, 22, 22, 22, 22, 22 + ch100, x, x, 23, 23, 23, 23, 23 + ch102, x, x, x, x, x, x, x + ch104, x, x, 23, 23, 23, 23, 23 + ch106, x, x, x, x, x, x, x + ch108, x, x, 23, 23, 23, 23, 23 + ch110, x, x, x, x, x, x, x + ch112, x, x, 23, 23, 23, 23, 23 + ch114, x, x, x, x, x, x, x + ch116, x, x, 24, 24, 24, 24, 24 + ch118, x, x, x, x, x, x, x + ch120, x, x, 24, 24, 24, 24, 24 + ch122, x, x, x, x, x, x, x + ch124, x, x, 24, 24, 24, 24, 24 + ch126, x, x, x, x, x, x, x + ch128, x, x, 24, 24, 24, 24, 24 + ch132, x, x, 24, 24, 24, 24, 24 + ch134, x, x, x, x, x, x, x + ch136, x, x, 24, 24, 24, 24, 24 + ch138, x, x, x, x, x, x, x + ch140, x, x, 24, 24, 24, 24, 24 + ch142, x, x, x, x, x, x, x + ch144, x, x, x, x, x, x, x + ch149, x, x, 14, 14, 14, 14, 14 + ch151, x, x, x, x, x, x, x + ch153, x, x, 14, 14, 14, 14, 14 + ch155, x, x, x, x, x, x, x + ch157, x, x, 14, 14, 14, 14, 14 + ch159, x, x, x, x, x, x, x + ch161, x, x, 14, 14, 14, 14, 14 + ch165, x, x, 15, 15, 15, 15, 15 +</legacy> + +<ht20, mcs0_8, mcs1_2_9_10, mcs3_4_11_12, mcs5_13, mcs6_14, mcs7_15> +ch001, 28, 28, 28, 28, 28, 28 +ch002, 28, 28, 28, 28, 28, 28 +ch003, 27, 27, 27, 27, 27, 27 +ch004, 27, 27, 27, 27, 27, 27 +ch005, 27, 27, 27, 27, 27, 27 +ch006, 27, 27, 27, 27, 27, 27 +ch007, 27, 27, 27, 27, 27, 27 +ch008, 27, 27, 27, 27, 27, 27 +ch009, 27, 27, 27, 27, 27, 27 +ch010, 27, 27, 27, 27, 27, 27 +ch011, 27, 27, 27, 27, 27, 27 +ch012, 27, 27, 27, 27, 27, 27 +ch013, 27, 27, 27, 27, 27, 27 +ch014, x, x, x, x, x, x +ch036, 24, 24, 24, 24, 24, 24 +ch038, x, x, x, x, x, x +ch040, 24, 24, 24, 24, 24, 24 +ch042, x, x, x, x, x, x +ch044, 24, 24, 24, 24, 24, 24 +ch046, x, x, x, x, x, x +ch048, 24, 24, 24, 24, 24, 24 +ch050, x, x, x, x, x, x +ch052, 24, 24, 24, 24, 24, 24 +ch054, x, x, x, x, x, x +ch056, 24, 24, 24, 24, 24, 24 +ch058, x, x, x, x, x, x +ch060, 24, 24, 24, 24, 24, 24 +ch062, x, x, x, x, x, x +ch064, 24, 24, 24, 24, 24, 24 +ch100, 24, 24, 24, 24, 24, 24 +ch102, x, x, x, x, x, x +ch104, 24, 24, 24, 24, 24, 24 +ch106, x, x, x, x, x, x +ch108, 24, 24, 24, 24, 24, 24 +ch110, x, x, x, x, x, x +ch112, 24, 24, 24, 24, 24, 24 +ch114, x, x, x, x, x, x +ch116, 24, 24, 24, 24, 24, 24 +ch118, x, x, x, x, x, x +ch120, 24, 24, 24, 24, 24, 24 +ch122, x, x, x, x, x, x +ch124, 24, 24, 24, 24, 24, 24 +ch126, x, x, x, x, x, x +ch128, 24, 24, 24, 24, 24, 24 +ch132, 24, 24, 24, 24, 24, 24 +ch134, x, x, x, x, x, x +ch136, 24, 24, 24, 24, 24, 24 +ch138, x, x, x, x, x, x +ch140, 24, 24, 24, 24, 24, 24 +ch142, x, x, x, x, x, x +ch144, x, x, x, x, x, x +ch149, 14, 14, 14, 14, 14, 14 +ch151, x, x, x, x, x, x +ch153, 14, 14, 14, 14, 14, 14 +ch155, x, x, x, x, x, x +ch157, 14, 14, 14, 14, 14, 14 +ch159, x, x, x, x, x, x +ch161, 14, 14, 14, 14, 14, 14 +ch165, 15, 15, 15, 15, 15, 15 +</ht20> + +<ht40, mcs0_8, mcs1_2_9_10, mcs3_4_11_12, mcs5_13, mcs6_14, mcs7_15, mcs32> +ch001, x, x, x, x, x, x, x +ch002, x, x, x, x, x, x, x +ch003, x, x, x, x, x, x, x +ch004, x, x, x, x, x, x, x +ch005, x, x, x, x, x, x, x +ch006, x, x, x, x, x, x, x +ch007, x, x, x, x, x, x, x +ch008, x, x, x, x, x, x, x +ch009, x, x, x, x, x, x, x +ch010, x, x, x, x, x, x, x +ch011, x, x, x, x, x, x, x +ch012, x, x, x, x, x, x, x +ch013, x, x, x, x, x, x, x +ch014, x, x, x, x, x, x, x +ch036, x, x, x, x, x, x, x +ch038, 30, 30, 30, 30, 30, 30, 30 +ch040, x, x, x, x, x, x, x +ch042, x, x, x, x, x, x, x +ch044, x, x, x, x, x, x, x +ch046, 30, 30, 30, 30, 30, 30, 30 +ch048, x, x, x, x, x, x, x +ch050, x, x, x, x, x, x, x +ch052, x, x, x, x, x, x, x +ch054, 30, 30, 30, 30, 30, 30, 30 +ch056, x, x, x, x, x, x, x +ch058, x, x, x, x, x, x, x +ch060, x, x, x, x, x, x, x +ch062, 30, 30, 30, 30, 30, 30, 30 +ch064, x, x, x, x, x, x, x +ch100, x, x, x, x, x, x, x +ch102, 30, 30, 30, 30, 30, 30, 30 +ch104, x, x, x, x, x, x, x +ch106, x, x, x, x, x, x, x +ch108, x, x, x, x, x, x, x +ch110, 30, 30, 30, 30, 30, 30, 30 +ch112, x, x, x, x, x, x, x +ch114, x, x, x, x, x, x, x +ch116, x, x, x, x, x, x, x +ch118, 30, 30, 30, 30, 30, 30, 30 +ch120, x, x, x, x, x, x, x +ch122, x, x, x, x, x, x, x +ch124, x, x, x, x, x, x, x +ch126, 30, 30, 30, 30, 30, 30, 30 +ch128, x, x, x, x, x, x, x +ch132, x, x, x, x, x, x, x +ch134, 30, 30, 30, 30, 30, 30, 30 +ch136, x, x, x, x, x, x, x +ch138, x, x, x, x, x, x, x +ch140, x, x, x, x, x, x, x +ch142, x, x, x, x, x, x, x +ch144, x, x, x, x, x, x, x +ch149, x, x, x, x, x, x, x +ch151, 14, 14, 14, 14, 14, 14, 14 +ch153, x, x, x, x, x, x, x +ch155, x, x, x, x, x, x, x +ch157, x, x, x, x, x, x, x +ch159, 15, 15, 15, 15, 15, 15, 15 +ch161, x, x, x, x, x, x, x +ch165, x, x, x, x, x, x, x +</ht40> + +<vht20, mcs0, mcs1_2, mcs3_4, mcs5_6, mcs7, mcs8, mcs9> + ch001, 28, 28, 28, 28, 28, 28, 28 + ch002, 28, 28, 28, 28, 28, 28, 28 + ch003, 27, 27, 27, 27, 27, 27, 27 + ch004, 27, 27, 27, 27, 27, 27, 27 + ch005, 27, 27, 27, 27, 27, 27, 27 + ch006, 27, 27, 27, 27, 27, 27, 27 + ch007, 27, 27, 27, 27, 27, 27, 27 + ch008, 27, 27, 27, 27, 27, 27, 27 + ch009, 27, 27, 27, 27, 27, 27, 27 + ch010, 27, 27, 27, 27, 27, 27, 27 + ch011, 27, 27, 27, 27, 27, 27, 27 + ch012, 27, 27, 27, 27, 27, 27, 27 + ch013, 27, 27, 27, 27, 27, 27, 27 + ch014, x, x, x, x, x, x, x + ch036, 24, 24, 24, 24, 24, 24, 24 + ch038, 21, 21, 21, 21, 21, 21, 21 + ch040, 24, 24, 24, 24, 24, 24, 24 + ch042, 24, 24, 24, 24, 24, 24, 24 + ch044, 24, 24, 24, 24, 24, 24, 24 + ch046, 21, 21, 21, 21, 21, 21, 21 + ch048, 24, 24, 24, 24, 24, 24, 24 + ch050, x, x, x, x, x, x, x + ch052, 24, 24, 24, 24, 24, 24, 24 + ch054, 21, 21, 21, 21, 21, 21, 21 + ch056, 24, 24, 24, 24, 24, 24, 24 + ch058, 26, 26, 26, 26, 26, 26, 26 + ch060, 24, 24, 24, 24, 24, 24, 24 + ch062, 21, 21, 21, 21, 21, 21, 21 + ch064, 26, 26, 26, 26, 26, 26, 26 + ch100, 24, 24, 24, 24, 24, 24, 24 + ch102, 21, 21, 21, 21, 21, 21, 21 + ch104, 24, 24, 24, 24, 24, 24, 24 + ch106, 26, 26, 26, 26, 26, 26, 26 + ch108, 24, 24, 24, 24, 24, 24, 24 + ch110, 21, 21, 21, 21, 21, 21, 21 + ch112, 26, 26, 26, 26, 26, 26, 26 + ch114, 24, 24, 24, 24, 24, 24, 24 + ch116, 24, 24, 24, 24, 24, 24, 24 + ch118, 21, 21, 21, 21, 21, 21, 21 + ch120, 24, 24, 24, 24, 24, 24, 24 + ch122, 26, 26, 26, 26, 26, 26, 26 + ch124, 24, 24, 24, 24, 24, 24, 24 + ch126, 21, 21, 21, 21, 21, 21, 21 + ch128, 24, 24, 24, 24, 24, 24, 24 + ch132, 24, 24, 24, 24, 24, 24, 24 + ch134, 21, 21, 21, 21, 21, 21, 21 + ch136, 24, 24, 24, 24, 24, 24, 24 + ch138, x, x, x, x, x, x, x + ch140, 23, 23, 23, 23, 23, 23, 23 + ch142, x, x, x, x, x, x, x + ch144, x, x, x, x, x, x, x + ch149, 14, 14, 14, 14, 14, 14, 14 + ch151, 12, 12, 12, 12, 12, 12, 12 + ch153, 14, 14, 14, 14, 14, 14, 14 + ch155, 14, 14, 14, 14, 14, 14, 14 + ch157, 14, 14, 14, 14, 14, 14, 14 + ch159, 14, 14, 14, 14, 14, 14, 14 + ch161, 14, 14, 14, 14, 14, 14, 14 + ch165, 15, 15, 15, 15, 15, 15, 15 + </vht20> + +<offset, lg40, lg80, vht40, vht80, vht160nc> + ch001, x, x, x, x, x + ch002, x, x, x, x, x + ch003, x, x, x, x, x + ch004, x, x, x, x, x + ch005, x, x, x, x, x + ch006, x, x, x, x, x + ch007, x, x, x, x, x + ch008, x, x, x, x, x + ch009, x, x, x, x, x + ch010, x, x, x, x, x + ch011, x, x, x, x, x + ch012, x, x, x, x, x + ch013, x, x, x, x, x + ch014, x, x, x, x, x + ch036, x, x, x, x, x + ch038, x, x, 8, x, x + ch040, x, x, x, x, x + ch042, x, x, x, 8, x + ch044, x, x, x, x, x + ch046, x, x, 8, x, x + ch048, x, x, x, x, x + ch050, x, x, x, x, x + ch052, x, x, x, x, x + ch054, x, x, 8, x, x + ch056, x, x, x, x, x + ch058, x, x, x, 7, x + ch060, x, x, x, x, x + ch062, x, x, 9, x, x + ch064, x, x, x, x, x + ch100, x, x, x, x, x + ch102, x, x, 8, x, x + ch104, x, x, x, x, x + ch106, x, x, x, 5, x + ch108, x, x, x, x, x + ch110, x, x, 8, x, x + ch112, x, x, x, x, x + ch114, x, x, x, x, x + ch116, x, x, x, x, x + ch118, x, x, 8, x, x + ch120, x, x, x, x, x + ch122, x, x, x, 5, x + ch124, x, x, x, x, x + ch126, x, x, 8, x, x + ch128, x, x, x, x, x + ch132, x, x, x, x, x + ch134, x, x, 8, x, x + ch136, x, x, x, x, x + ch138, x, x, x, x, x + ch140, x, x, x, x, x + ch142, x, x, x, x, x + ch144, x, x, x, x, x + ch149, x, x, x, x, x + ch151, x, x, 2, x, x + ch153, x, x, x, x, x + ch155, x, x, x, 1, x + ch157, x, x, x, x, x + ch159, x, x, 1, x, x + ch161, x, x, x, x, x + ch165, x, x, x, x, x +</offset> + +[CA] +<legacy, cck1_2, cck5_11, ofdm6_9, ofdm12_18, ofdm24_36, ofdm48, ofdm54> + ch001, 38, 38, 33, 33, 33, 33, 33 + ch002, 38, 38, 33, 33, 33, 33, 33 + ch003, 38, 38, 38, 38, 38, 38, 38 + ch004, 38, 38, 38, 38, 38, 38, 38 + ch005, 38, 38, 38, 38, 38, 38, 38 + ch006, 38, 38, 38, 38, 38, 38, 38 + ch007, 38, 38, 38, 38, 38, 38, 38 + ch008, 38, 38, 38, 38, 38, 38, 38 + ch009, 38, 38, 38, 38, 38, 38, 38 + ch010, 34, 34, 33, 33, 33, 33, 33 + ch011, 34, 34, 33, 33, 33, 33, 33 + ch012, x, x, x, x, x, x, x + ch013, x, x, x, x, x, x, x + ch014, x, x, x, x, x, x, x + ch036, x, x, 20, 20, 20, 20, 20 + ch038, x, x, x, x, x, x, x + ch040, x, x, 20, 20, 20, 20, 20 + ch042, x, x, x, x, x, x, x + ch044, x, x, 20, 20, 20, 20, 20 + ch046, x, x, x, x, x, x, x + ch048, x, x, 20, 20, 20, 20, 20 + ch050, x, x, x, x, x, x, x + ch052, x, x, 29, 29, 29, 29, 29 + ch054, x, x, x, x, x, x, x + ch056, x, x, 29, 29, 29, 29, 29 + ch058, x, x, x, x, x, x, x + ch060, x, x, 27, 27, 27, 27, 27 + ch062, x, x, x, x, x, x, x + ch064, x, x, 27, 27, 27, 27, 27 + ch100, x, x, 34, 34, 34, 34, 34 + ch102, x, x, x, x, x, x, x + ch104, x, x, 33, 33, 33, 33, 33 + ch106, x, x, x, x, x, x, x + ch108, x, x, 33, 33, 33, 33, 33 + ch110, x, x, x, x, x, x, x + ch112, x, x, 33, 33, 33, 33, 33 + ch114, x, x, x, x, x, x, x + ch116, x, x, 33, 33, 33, 33, 33 + ch118, x, x, x, x, x, x, x + ch120, x, x, 33, 33, 33, 33, 33 + ch122, x, x, x, x, x, x, x + ch124, x, x, 33, 33, 33, 33, 33 + ch126, x, x, x, x, x, x, x + ch128, x, x, 33, 33, 33, 33, 33 + ch132, x, x, 33, 33, 33, 33, 33 + ch134, x, x, x, x, x, x, x + ch136, x, x, 33, 33, 33, 33, 33 + ch138, x, x, x, x, x, x, x + ch140, x, x, 33, 33, 33, 33, 33 + ch142, x, x, x, x, x, x, x + ch144, x, x, 33, 33, 33, 33, 33 + ch149, x, x, 38, 38, 38, 38, 38 + ch151, x, x, x, x, x, x, x + ch153, x, x, 38, 38, 38, 38, 38 + ch155, x, x, x, x, x, x, x + ch157, x, x, 38, 38, 38, 38, 38 + ch159, x, x, x, x, x, x, x + ch161, x, x, 38, 38, 38, 38, 38 + ch165, x, x, 38, 38, 38, 38, 38 +</legacy> + +<ht20, mcs0_8, mcs1_2_9_10, mcs3_4_11_12, mcs5_13, mcs6_14, mcs7_15> +ch001, 31, 31, 31, 31, 31, 31 +ch002, 31, 31, 31, 31, 31, 31 +ch003, 39, 39, 39, 39, 39, 39 +ch004, 39, 39, 39, 39, 39, 39 +ch005, 39, 39, 39, 39, 39, 39 +ch006, 39, 39, 39, 39, 39, 39 +ch007, 39, 39, 39, 39, 39, 39 +ch008, 39, 39, 39, 39, 39, 39 +ch009, 39, 39, 39, 39, 39, 39 +ch010, 31, 31, 31, 31, 31, 31 +ch011, 31, 31, 31, 31, 31, 31 +ch012, x, x, x, x, x, x +ch013, x, x, x, x, x, x +ch014, x, x, x, x, x, x +ch036, 20, 20, 20, 20, 20, 20 +ch038, x, x, x, x, x, x +ch040, 20, 20, 20, 20, 20, 20 +ch042, x, x, x, x, x, x +ch044, 20, 20, 20, 20, 20, 20 +ch046, x, x, x, x, x, x +ch048, 20, 20, 20, 20, 20, 20 +ch050, x, x, x, x, x, x +ch052, 30, 30, 30, 30, 30, 30 +ch054, x, x, x, x, x, x +ch056, 30, 30, 30, 30, 30, 30 +ch058, x, x, x, x, x, x +ch060, 30, 30, 30, 30, 30, 30 +ch062, x, x, x, x, x, x +ch064, 27, 27, 27, 27, 27, 27 +ch100, 33, 33, 33, 33, 33, 33 +ch102, x, x, x, x, x, x +ch104, 33, 33, 33, 33, 33, 33 +ch106, x, x, x, x, x, x +ch108, 33, 33, 33, 33, 33, 33 +ch110, x, x, x, x, x, x +ch112, 33, 33, 33, 33, 33, 33 +ch114, x, x, x, x, x, x +ch116, 33, 33, 33, 33, 33, 33 +ch118, x, x, x, x, x, x +ch120, 33, 33, 33, 33, 33, 33 +ch122, x, x, x, x, x, x +ch124, 33, 33, 33, 33, 33, 33 +ch126, x, x, x, x, x, x +ch128, 33, 33, 33, 33, 33, 33 +ch132, 33, 33, 33, 33, 33, 33 +ch134, x, x, x, x, x, x +ch136, 33, 33, 33, 33, 33, 33 +ch138, x, x, x, x, x, x +ch140, 30, 30, 30, 30, 30, 30 +ch142, x, x, x, x, x, x +ch144, 33, 33, 33, 33, 33, 33 +ch149, 40, 40, 40, 40, 40, 40 +ch151, x, x, x, x, x, x +ch153, 40, 40, 40, 40, 40, 40 +ch155, x, x, x, x, x, x +ch157, 40, 40, 40, 40, 40, 40 +ch159, x, x, x, x, x, x +ch161, 40, 40, 40, 40, 40, 40 +ch165, 40, 40, 40, 40, 40, 40 +</ht20> + +<ht40, mcs0_8, mcs1_2_9_10, mcs3_4_11_12, mcs5_13, mcs6_14, mcs7_15, mcs32> +ch001, x, x, x, x, x, x, x +ch002, x, x, x, x, x, x, x +ch003, x, x, x, x, x, x, x +ch004, x, x, x, x, x, x, x +ch005, x, x, x, x, x, x, x +ch006, x, x, x, x, x, x, x +ch007, x, x, x, x, x, x, x +ch008, x, x, x, x, x, x, x +ch009, x, x, x, x, x, x, x +ch010, x, x, x, x, x, x, x +ch011, x, x, x, x, x, x, x +ch012, x, x, x, x, x, x, x +ch013, x, x, x, x, x, x, x +ch014, x, x, x, x, x, x, x +ch036, x, x, x, x, x, x, x +ch038, 27, 27, 27, 27, 27, 27, 27 +ch040, x, x, x, x, x, x, x +ch042, x, x, x, x, x, x, x +ch044, x, x, x, x, x, x, x +ch046, 27, 27, 27, 27, 27, 27, 27 +ch048, x, x, x, x, x, x, x +ch050, x, x, x, x, x, x, x +ch052, x, x, x, x, x, x, x +ch054, 29, 29, 29, 29, 29, 29, 29 +ch056, x, x, x, x, x, x, x +ch058, x, x, x, x, x, x, x +ch060, x, x, x, x, x, x, x +ch062, 27, 27, 27, 27, 27, 27, 27 +ch064, x, x, x, x, x, x, x +ch100, x, x, x, x, x, x, x +ch102, 27, 27, 27, 27, 27, 27, 27 +ch104, x, x, x, x, x, x, x +ch106, x, x, x, x, x, x, x +ch108, x, x, x, x, x, x, x +ch110, 38, 38, 38, 38, 38, 38, 38 +ch112, x, x, x, x, x, x, x +ch114, x, x, x, x, x, x, x +ch116, x, x, x, x, x, x, x +ch118, 38, 38, 38, 38, 38, 38, 38 +ch120, x, x, x, x, x, x, x +ch122, x, x, x, x, x, x, x +ch124, x, x, x, x, x, x, x +ch126, 38, 38, 38, 38, 38, 38, 38 +ch128, x, x, x, x, x, x, x +ch132, x, x, x, x, x, x, x +ch134, 33, 33, 33, 33, 33, 33, 33 +ch136, x, x, x, x, x, x, x +ch138, x, x, x, x, x, x, x +ch140, x, x, x, x, x, x, x +ch142, 38, 38, 38, 38, 38, 38, 38 +ch144, x, x, x, x, x, x, x +ch149, x, x, x, x, x, x, x +ch151, 39, 39, 39, 39, 39, 39, 39 +ch153, x, x, x, x, x, x, x +ch155, x, x, x, x, x, x, x +ch157, x, x, x, x, x, x, x +ch159, 37, 37, 37, 37, 37, 37, 37 +ch161, x, x, x, x, x, x, x +ch165, x, x, x, x, x, x, x +</ht40> + +<vht20, mcs0, mcs1_2, mcs3_4, mcs5_6, mcs7, mcs8, mcs9> + ch001, 31, 31, 31, 31, 31, 31, 31 + ch002, 31, 31, 31, 31, 31, 31, 31 + ch003, 39, 39, 39, 39, 39, 39, 39 + ch004, 39, 39, 39, 39, 39, 39, 39 + ch005, 39, 39, 39, 39, 39, 39, 39 + ch006, 39, 39, 39, 39, 39, 39, 39 + ch007, 39, 39, 39, 39, 39, 39, 39 + ch008, 39, 39, 39, 39, 39, 39, 39 + ch009, 39, 39, 39, 39, 39, 39, 39 + ch010, 31, 31, 31, 31, 31, 31, 31 + ch011, 31, 31, 31, 31, 31, 31, 31 + ch012, x, x, x, x, x, x, x + ch013, x, x, x, x, x, x, x + ch014, x, x, x, x, x, x, x + ch036, 19, 19, 19, 19, 19, 19, 19 + ch038, 20, 20, 20, 20, 20, 20, 20 + ch040, 19, 19, 19, 19, 19, 19, 19 + ch042, 20, 20, 20, 20, 20, 20, 20 + ch044, 19, 19, 19, 19, 19, 19, 19 + ch046, 20, 20, 20, 20, 20, 20, 20 + ch048, 19, 19, 19, 19, 19, 19, 19 + ch050, x, x, x, x, x, x, x + ch052, 30, 30, 30, 30, 30, 30, 30 + ch054, 33, 33, 33, 33, 33, 33, 33 + ch056, 30, 30, 30, 30, 30, 30, 30 + ch058, 22, 22, 22, 22, 22, 22, 22 + ch060, 30, 30, 30, 30, 30, 30, 30 + ch062, 22, 22, 22, 22, 22, 22, 22 + ch064, 28, 28, 28, 28, 28, 28, 28 + ch100, 33, 33, 33, 33, 33, 33, 33 + ch102, 31, 31, 31, 31, 31, 31, 31 + ch104, 33, 33, 33, 33, 33, 33, 33 + ch106, 22, 22, 22, 22, 22, 22, 22 + ch108, 33, 33, 33, 33, 33, 33, 33 + ch110, 31, 31, 31, 31, 31, 31, 31 + ch112, 33, 33, 33, 33, 33, 33, 33 + ch114, 31, 31, 31, 31, 31, 31, 31 + ch116, 33, 33, 33, 33, 33, 33, 33 + ch118, 31, 31, 31, 31, 31, 31, 31 + ch120, 33, 33, 33, 33, 33, 33, 33 + ch122, 31, 31, 31, 31, 31, 31, 31 + ch124, 33, 33, 33, 33, 33, 33, 33 + ch126, 31, 31, 31, 31, 31, 31, 31 + ch128, 33, 33, 33, 33, 33, 33, 33 + ch132, 33, 33, 33, 33, 33, 33, 33 + ch134, 30, 30, 30, 30, 30, 30, 30 + ch136, 33, 33, 33, 33, 33, 33, 33 + ch138, 33, 33, 33, 33, 33, 33, 33 + ch140, 30, 30, 30, 30, 30, 30, 30 + ch142, 30, 30, 30, 30, 30, 30, 30 + ch144, 32, 32, 32, 32, 32, 32, 32 + ch149, 40, 40, 40, 40, 40, 40, 40 + ch151, 31, 31, 31, 31, 31, 31, 31 + ch153, 40, 40, 40, 40, 40, 40, 40 + ch155, 31, 31, 31, 31, 31, 31, 31 + ch157, 40, 40, 40, 40, 40, 40, 40 + ch159, 31, 31, 31, 31, 31, 31, 31 + ch161, 40, 40, 40, 40, 40, 40, 40 + ch165, 40, 40, 40, 40, 40, 40, 40 + </vht20> + +<offset, lg40, lg80, vht40, vht80, vht160nc> + ch001, x, x, x, x, x + ch002, x, x, x, x, x + ch003, x, x, x, x, x + ch004, x, x, x, x, x + ch005, x, x, x, x, x + ch006, x, x, x, x, x + ch007, x, x, x, x, x + ch008, x, x, x, x, x + ch009, x, x, x, x, x + ch010, x, x, x, x, x + ch011, x, x, x, x, x + ch012, x, x, x, x, x + ch013, x, x, x, x, x + ch014, x, x, x, x, x + ch036, x, x, x, x, x + ch038, x, x, 6, x, x + ch040, x, x, x, x, x + ch042, x, x, x, 0, x + ch044, x, x, x, x, x + ch046, x, x, 6, x, x + ch048, x, x, x, x, x + ch050, x, x, x, x, x + ch052, x, x, x, x, x + ch054, x, x, -3, x, x + ch056, x, x, x, x, x + ch058, x, x, x, 4, x + ch060, x, x, x, x, x + ch062, x, x, 7, x, x + ch064, x, x, x, x, x + ch100, x, x, x, x, x + ch102, x, x, -3, x, x + ch104, x, x, x, x, x + ch106, x, x, x, 3, x + ch108, x, x, x, x, x + ch110, x, x, 7, x, x + ch112, x, x, x, x, x + ch114, x, x, x, x, x + ch116, x, x, x, x, x + ch118, x, x, 7, x, x + ch120, x, x, x, x, x + ch122, x, x, x, 7, x + ch124, x, x, x, x, x + ch126, x, x, 7, x, x + ch128, x, x, x, x, x + ch132, x, x, x, x, x + ch134, x, x, 4, x, x + ch136, x, x, x, x, x + ch138, x, x, x, 7, x + ch140, x, x, x, x, x + ch142, x, x, 8, x, x + ch144, x, x, x, x, x + ch149, x, x, x, x, x + ch151, x, x, 8, x, x + ch153, x, x, x, x, x + ch155, x, x, x, 1, x + ch157, x, x, x, x, x + ch159, x, x, 6, x, x + ch161, x, x, x, x, x + ch165, x, x, x, x, x +</offset> + +# The unit of each TxPower value is 0.5dBm. +# 'x' means use efuse default value instead of from this table +# Channels in the table are treated as center channel. + +[IN] +<legacy, cck1_2, cck5_11, ofdm6_9, ofdm12_18, ofdm24_36, ofdm48, ofdm54> + ch001, 24, 24, 27, 27, 27, 27, 27 + ch002, 24, 24, 27, 27, 27, 27, 27 + ch003, 24, 24, 27, 27, 27, 27, 27 + ch004, 24, 24, 27, 27, 27, 27, 27 + ch005, 24, 24, 27, 27, 27, 27, 27 + ch006, 24, 24, 27, 27, 27, 27, 27 + ch007, 24, 24, 27, 27, 27, 27, 27 + ch008, 24, 24, 27, 27, 27, 27, 27 + ch009, 24, 24, 27, 27, 27, 27, 27 + ch010, 24, 24, 27, 27, 27, 27, 27 + ch011, 24, 24, 27, 27, 27, 27, 27 + ch012, 22, 22, 27, 27, 27, 27, 27 + ch013, 22, 22, 27, 27, 27, 27, 27 + ch014, x, x, x, x, x, x, x + ch036, x, x, 35, 35, 35, 35, 35 + ch038, x, x, x, x, x, x, x + ch040, x, x, 35, 35, 35, 35, 35 + ch042, x, x, x, x, x, x, x + ch044, x, x, 35, 35, 35, 35, 34 + ch046, x, x, x, x, x, x, x + ch048, x, x, 34, 34, 34, 34, 34 + ch050, x, x, x, x, x, x, x + ch052, x, x, 34, 34, 34, 34, 34 + ch054, x, x, x, x, x, x, x + ch056, x, x, 34, 34, 34, 34, 34 + ch058, x, x, x, x, x, x, x + ch060, x, x, 34, 34, 34, 34, 34 + ch062, x, x, x, x, x, x, x + ch064, x, x, 34, 34, 34, 34, 34 + ch100, x, x, 34, 34, 34, 34, 34 + ch102, x, x, x, x, x, x, x + ch104, x, x, 33, 33, 33, 33, 33 + ch106, x, x, x, x, x, x, x + ch108, x, x, 33, 33, 33, 33, 33 + ch110, x, x, x, x, x, x, x + ch112, x, x, 33, 33, 33, 33, 33 + ch114, x, x, x, x, x, x, x + ch116, x, x, 33, 33, 33, 33, 33 + ch118, x, x, x, x, x, x, x + ch120, x, x, 33, 33, 33, 33, 33 + ch122, x, x, x, x, x, x, x + ch124, x, x, 33, 33, 33, 33, 33 + ch126, x, x, x, x, x, x, x + ch128, x, x, 33, 33, 33, 33, 33 + ch132, x, x, 33, 33, 33, 33, 33 + ch134, x, x, x, x, x, x, x + ch136, x, x, 33, 33, 33, 33, 33 + ch138, x, x, x, x, x, x, x + ch140, x, x, 33, 33, 33, 33, 33 + ch142, x, x, x, x, x, x, x + ch144, x, x, 33, 33, 33, 33, 33 + ch149, x, x, 38, 38, 38, 38, 38 + ch151, x, x, x, x, x, x, x + ch153, x, x, 38, 38, 38, 38, 38 + ch155, x, x, x, x, x, x, x + ch157, x, x, 38, 38, 38, 38, 38 + ch159, x, x, x, x, x, x, x + ch161, x, x, 38, 38, 38, 38, 38 + ch165, x, x, 38, 38, 38, 38, 38 +</legacy> + +<ht20, mcs0_8, mcs1_2_9_10, mcs3_4_11_12, mcs5_13, mcs6_14, mcs7_15> +ch001, 28, 28, 28, 28, 28, 28 +ch002, 28, 28, 28, 28, 28, 28 +ch003, 27, 27, 27, 27, 27, 27 +ch004, 27, 27, 27, 27, 27, 27 +ch005, 27, 27, 27, 27, 27, 27 +ch006, 27, 27, 27, 27, 27, 27 +ch007, 27, 27, 27, 27, 27, 27 +ch008, 27, 27, 27, 27, 27, 27 +ch009, 27, 27, 27, 27, 27, 27 +ch010, 27, 27, 27, 27, 27, 27 +ch011, 27, 27, 27, 27, 27, 27 +ch012, 27, 27, 27, 27, 27, 27 +ch013, 27, 27, 27, 27, 27, 27 +ch014, x, x, x, x, x, x, +ch036, 34, 34, 34, 34, 34, 34 +ch038, x, x, x, x, x, x +ch040, 35, 35, 35, 35, 35, 35 +ch042, x, x, x, x, x, x +ch044, 35, 35, 35, 35, 35, 35 +ch046, x, x, x, x, x, x +ch048, 35, 35, 35, 35, 35, 35 +ch050, x, x, x, x, x, x +ch052, 35, 35, 35, 35, 35, 35 +ch054, x, x, x, x, x, x +ch056, 35, 35, 35, 35, 35, 35 +ch058, x, x, x, x, x, x +ch060, 35, 35, 35, 35, 35, 35 +ch062, x, x, x, x, x, x +ch064, 35, 35, 35, 35, 35, 35 +ch100, 33, 33, 33, 33, 33, 33 +ch102, x, x, x, x, x, x +ch104, 33, 33, 33, 33, 33, 33 +ch106, x, x, x, x, x, x +ch108, 33, 33, 33, 33, 33, 33 +ch110, x, x, x, x, x, x +ch112, 33, 33, 33, 33, 33, 33 +ch114, x, x, x, x, x, x +ch116, 33, 33, 33, 33, 33, 33 +ch118, x, x, x, x, x, x +ch120, 33, 33, 33, 33, 33, 33 +ch122, x, x, x, x, x, x +ch124, 33, 33, 33, 33, 33, 33 +ch126, x, x, x, x, x, x +ch128, 33, 33, 33, 33, 33, 33 +ch132, 33, 33, 33, 33, 33, 33 +ch134, x, x, x, x, x, x +ch136, 33, 33, 33, 33, 33, 33 +ch138, x, x, x, x, x, x +ch140, 30, 30, 30, 30, 30, 30 +ch142, x, x, x, x, x, x +ch144, 33, 33, 33, 33, 33, 33 +ch149, 40, 40, 40, 40, 40, 40 +ch151, x, x, x, x, x, x +ch153, 40, 40, 40, 40, 40, 40 +ch155, x, x, x, x, x, x +ch157, 40, 40, 40, 40, 40, 40 +ch159, x, x, x, x, x, x +ch161, 40, 40, 40, 40, 40, 40 +ch165, 40, 40, 40, 40, 40, 40 +</ht20> + +<ht40, mcs0_8, mcs1_2_9_10, mcs3_4_11_12, mcs5_13, mcs6_14, mcs7_15, mcs32> +ch001, x, x, x, x, x, x, x +ch002, x, x, x, x, x, x, x +ch003, x, x, x, x, x, x, x +ch004, x, x, x, x, x, x, x +ch005, x, x, x, x, x, x, x +ch006, x, x, x, x, x, x, x +ch007, x, x, x, x, x, x, x +ch008, x, x, x, x, x, x, x +ch009, x, x, x, x, x, x, x +ch010, x, x, x, x, x, x, x +ch011, x, x, x, x, x, x, x +ch012, x, x, x, x, x, x, x +ch013, x, x, x, x, x, x, x +ch014, x, x, x, x, x, x, x +ch036, x, x, x, x, x, x, x +ch038, 27, 27, 27, 27, 27, 27, 27 +ch040, x, x, x, x, x, x, x +ch042, x, x, x, x, x, x, x +ch044, x, x, x, x, x, x, x +ch046, 38, 38, 38, 38, 38, 38, 38 +ch048, x, x, x, x, x, x, x +ch050, x, x, x, x, x, x, x +ch052, x, x, x, x, x, x, x +ch054, 39, 39, 39, 39, 39, 39, 39 +ch056, x, x, x, x, x, x, x +ch058, x, x, x, x, x, x, x +ch060, x, x, x, x, x, x, x +ch062, 28, 28, 28, 28, 28, 28, 28 +ch064, x, x, x, x, x, x, x +ch100, x, x, x, x, x, x, x +ch102, 27, 27, 27, 27, 27, 27, 27 +ch104, x, x, x, x, x, x, x +ch106, x, x, x, x, x, x, x +ch108, x, x, x, x, x, x, x +ch110, 38, 38, 38, 38, 38, 38, 38 +ch112, x, x, x, x, x, x, x +ch114, x, x, x, x, x, x, x +ch116, x, x, x, x, x, x, x +ch118, 38, 38, 38, 38, 38, 38, 38 +ch120, x, x, x, x, x, x, x +ch122, x, x, x, x, x, x, x +ch124, x, x, x, x, x, x, x +ch126, 38, 38, 38, 38, 38, 38, 38 +ch128, x, x, x, x, x, x, x +ch132, x, x, x, x, x, x, x +ch134, 33, 33, 33, 33, 33, 33, 33 +ch136, x, x, x, x, x, x, x +ch138, x, x, x, x, x, x, x +ch140, x, x, x, x, x, x, x +ch142, 39, 39, 39, 39, 39, 39, 39 +ch144, x, x, x, x, x, x, x +ch149, x, x, x, x, x, x, x +ch151, 39, 39, 39, 39, 39, 39, 39 +ch153, x, x, x, x, x, x, x +ch155, x, x, x, x, x, x, x +ch157, x, x, x, x, x, x, x +ch159, 37, 37, 37, 37, 37, 37, 37 +ch161, x, x, x, x, x, x, x +ch165, x, x, x, x, x, x, x +</ht40> + +<vht20, mcs0, mcs1_2, mcs3_4, mcs5_6, mcs7, mcs8, mcs9> + ch001, 28, 28, 28, 28, 28, 28, 28 + ch002, 28, 28, 28, 28, 28, 28, 28 + ch003, 27, 27, 27, 27, 27, 27, 27 + ch004, 27, 27, 27, 27, 27, 27, 27 + ch005, 27, 27, 27, 27, 27, 27, 27 + ch006, 27, 27, 27, 27, 27, 27, 27 + ch007, 27, 27, 27, 27, 27, 27, 27 + ch008, 27, 27, 27, 27, 27, 27, 27 + ch009, 27, 27, 27, 27, 27, 27, 27 + ch010, 27, 27, 27, 27, 27, 27, 27 + ch011, 27, 27, 27, 27, 27, 27, 27 + ch012, 27, 27, 27, 27, 27, 27, 27 + ch013, 27, 27, 27, 27, 27, 27, 27 + ch014, x, x, x, x, x, x, x + ch036, 32, 32, 32, 32, 32, 32, 32 + ch038, 31, 31, 31, 31, 31, 31, 31 + ch040, 35, 35, 35, 35, 35, 35, 35 + ch042, 27, 27, 27, 27, 27, 27, 27 + ch044, 35, 35, 35, 35, 35, 35, 35 + ch046, 31, 31, 31, 31, 31, 31, 31 + ch048, 35, 35, 35, 35, 35, 35, 35 + ch050, 31, 31, 31, 31, 31, 31, 31 + ch052, 35, 35, 35, 35, 35, 35, 35 + ch054, 31, 31, 31, 31, 31, 31, 31 + ch056, 35, 35, 35, 35, 35, 35, 35 + ch058, 31, 31, 31, 31, 31, 31, 31 + ch060, 35, 35, 35, 35, 35, 35, 35 + ch062, 31, 31, 31, 31, 31, 31, 31 + ch064, 35, 35, 35, 35, 35, 35, 35 + ch100, 33, 33, 33, 33, 33, 33, 33 + ch102, 31, 31, 31, 31, 31, 31, 31 + ch104, 33, 33, 33, 33, 33, 33, 33 + ch106, 31, 31, 31, 31, 31, 31, 31 + ch108, 33, 33, 33, 33, 33, 33, 33 + ch110, 31, 31, 31, 31, 31, 31, 31 + ch112, 33, 33, 33, 33, 33, 33, 33 + ch114, 31, 31, 31, 31, 31, 31, 31 + ch116, 33, 33, 33, 33, 33, 33, 33 + ch118, 31, 31, 31, 31, 31, 31, 31 + ch120, 33, 33, 33, 33, 33, 33, 33 + ch122, 31, 31, 31, 31, 31, 31, 31 + ch124, 33, 33, 33, 33, 33, 33, 33 + ch126, 31, 31, 31, 31, 31, 31, 31 + ch128, 33, 33, 33, 33, 33, 33, 33 + ch132, 33, 33, 33, 33, 33, 33, 33 + ch134, 31, 31, 31, 31, 31, 31, 31 + ch136, 33, 33, 33, 33, 33, 33, 33 + ch138, 33, 33, 33, 33, 33, 33, 33 + ch140, 30, 30, 30, 30, 30, 30, 30 + ch142, 30, 30, 30, 30, 30, 30, 30 + ch144, 32, 32, 32, 32, 32, 32, 32 + ch149, 40, 40, 40, 40, 40, 40, 40 + ch151, 31, 31, 31, 31, 31, 31, 31 + ch153, 40, 40, 40, 40, 40, 40, 40 + ch155, 31, 31, 31, 31, 31, 31, 31 + ch157, 40, 40, 40, 40, 40, 40, 40 + ch159, 31, 31, 31, 31, 31, 31, 31 + ch161, 40, 40, 40, 40, 40, 40, 40 + ch165, 40, 40, 40, 40, 40, 40, 40 + </vht20> + +<offset, lg40, lg80, vht40, vht80, vht160nc> + ch001, x, x, x, x, x + ch002, x, x, x, x, x + ch003, x, x, x, x, x + ch004, x, x, x, x, x + ch005, x, x, x, x, x + ch006, x, x, x, x, x + ch007, x, x, x, x, x + ch008, x, x, x, x, x + ch009, x, x, x, x, x + ch010, x, x, x, x, x + ch011, x, x, x, x, x + ch012, x, x, x, x, x + ch013, x, x, x, x, x + ch014, x, x, x, x, x + ch036, x, x, x, x, x + ch038, x, x, -3, x, x + ch040, x, x, x, x, x + ch042, x, x, x, -6, x + ch044, x, x, x, x, x + ch046, x, x, 7, x, x + ch048, x, x, x, x, x + ch050, x, x, x, x, x + ch052, x, x, x, x, x + ch054, x, x, 7, x, x + ch056, x, x, x, x, x + ch058, x, x, x, -5, x + ch060, x, x, x, x, x + ch062, x, x, -3, x, + ch064, x, x, x, x, x + ch100, x, x, x, x, x + ch102, x, x, 2, x, x + ch104, x, x, x, x, x + ch106, x, x, x, -5, x + ch108, x, x, x, x, x + ch110, x, x, 7, x, x + ch112, x, x, x, x, x + ch114, x, x, x, x, x + ch116, x, x, x, x, x + ch118, x, x, 7, x, x + ch120, x, x, x, x, x + ch122, x, x, x, 7, x + ch124, x, x, x, x, x + ch126, x, x, 7, x, x + ch128, x, x, x, x, x + ch132, x, x, x, x, x + ch134, x, x, 3, x, x + ch136, x, x, x, x, x + ch138, x, x, x, 7, x + ch140, x, x, x, x, x + ch142, x, x, 6, x, x + ch144, x, x, x, x, x + ch149, x, x, x, x, x + ch151, x, x, 7, x, x + ch153, x, x, x, x, x + ch155, x, x, x, 1, x + ch157, x, x, x, x, x + ch159, x, x, 7, x, x + ch161, x, x, x, x, x + ch165, x, x, x, x, x +</offset> + +# The unit of each TxPower value is 0.5dBm. +# 'x' means use efuse default value instead of from this table +# Channels in the table are treated as center channel. + +[JP] +<legacy, cck1_2, cck5_11, ofdm6_9, ofdm12_18, ofdm24_36, ofdm48, ofdm54> + ch001, 29, 29, 35, 35, 35, 35, 35 + ch002, 29, 29, 35, 35, 35, 35, 35 + ch003, 29, 29, 35, 35, 35, 35, 35 + ch004, 29, 29, 35, 35, 35, 35, 35 + ch005, 29, 29, 35, 35, 35, 35, 35 + ch006, 29, 29, 35, 35, 35, 35, 35 + ch007, 29, 29, 34, 34, 34, 34, 34 + ch008, 29, 29, 34, 34, 34, 34, 34 + ch009, 29, 29, 34, 34, 34, 34, 34 + ch010, 29, 29, 34, 34, 34, 34, 34 + ch011, 29, 29, 34, 34, 34, 34, 34 + ch012, 29, 29, 34, 34, 34, 34, 34 + ch013, 29, 29, 34, 34, 34, 34, 34 + ch014, x, x, x, x, x, x, x + ch036, x, x, 22, 22, 22, 22, 22 + ch038, x, x, 22, 22, 22, 22, 22 + ch040, x, x, 22, 22, 22, 22, 22 + ch042, x, x, 22, 22, 22, 22, 22 + ch044, x, x, 22, 22, 22, 22, 22 + ch046, x, x, 22, 22, 22, 22, 22 + ch048, x, x, 22, 22, 22, 22, 22 + ch050, x, x, x, x, x, x, x + ch052, x, x, 16, 16, 16, 16, 16 + ch054, x, x, x, x, x, x, x + ch056, x, x, 16, 16, 16, 16, 16 + ch058, x, x, x, x, x, x, x + ch060, x, x, 15, 15, 15, 15, 15 + ch062, x, x, x, x, x, x, x + ch064, x, x, 15, 15, 15, 15, 15 + ch100, x, x, 32, 32, 32, 32, 32 + ch102, x, x, x, x, x, x, x + ch104, x, x, 32, 32, 32, 32, 32 + ch106, x, x, x, x, x, x, x + ch108, x, x, 32, 32, 32, 32, 32 + ch110, x, x, x, x, x, x, x + ch112, x, x, 32, 32, 32, 32, 32 + ch114, x, x, x, x, x, x, x + ch116, x, x, 32, 32, 32, 32, 32 + ch118, x, x, x, x, x, x, x + ch120, x, x, 33, 33, 33, 33, 33 + ch122, x, x, x, x, x, x, x + ch124, x, x, 33, 33, 33, 33, 33 + ch126, x, x, x, x, x, x, x + ch128, x, x, 33, 33, 33, 33, 33 + ch132, x, x, 33, 33, 33, 33, 33 + ch134, x, x, x, x, x, x, x + ch136, x, x, 33, 33, 33, 33, 33 + ch138, x, x, x, x, x, x, x + ch140, x, x, 32, 32, 32, 32, 32 + ch142, x, x, x, x, x, x, x + ch144, x, x, x, x, x, x, x + ch149, x, x, x, x, x, x, x + ch151, x, x, x, x, x, x, x + ch153, x, x, x, x, x, x, x + ch155, x, x, x, x, x, x, x + ch157, x, x, x, x, x, x, x + ch159, x, x, x, x, x, x, x + ch161, x, x, x, x, x, x, x + ch165, x, x, x, x, x, x, x +</legacy> + +<ht20, mcs0_8, mcs1_2_9_10, mcs3_4_11_12, mcs5_13, mcs6_14, mcs7_15> +ch001, 34, 34, 34, 34, 34, 34 +ch002, 34, 34, 34, 34, 34, 34 +ch003, 34, 34, 34, 34, 34, 34 +ch004, 34, 34, 34, 34, 34, 34 +ch005, 34, 34, 34, 34, 34, 34 +ch006, 34, 34, 34, 34, 34, 34 +ch007, 34, 34, 34, 34, 34, 34 +ch008, 34, 34, 34, 34, 34, 34 +ch009, 34, 34, 34, 34, 34, 34 +ch010, 34, 34, 34, 34, 34, 34 +ch011, 34, 34, 34, 34, 34, 34 +ch012, 34, 34, 34, 34, 34, 34 +ch013, 34, 34, 34, 34, 34, 34 +ch014, x, x, x, x, x, x +ch036, 23, 23, 23, 23, 23, 23 +ch038, x, x, x, x, x, x +ch040, 23, 23, 23, 23, 23, 23 +ch042, x, x, x, x, x, x +ch044, 24, 24, 24, 24, 24, 24 +ch046, x, x, x, x, x, x +ch048, 24, 24, 24, 24, 24, 24 +ch050, x, x, x, x, x, x +ch052, 18, 18, 18, 18, 18, 18 +ch054, x, x, x, x, x, x +ch056, 18, 18, 18, 18, 18, 18 +ch058, x, x, x, x, x, x +ch060, 17, 17, 17, 17, 17, 17 +ch062, x, x, x, x, x, x +ch064, 17, 17, 17, 17, 17, 17 +ch100, 33, 33, 33, 33, 33, 33 +ch102, x, x, x, x, x, x +ch104, 33, 33, 33, 33, 33, 33 +ch106, x, x, x, x, x, x +ch108, 33, 33, 33, 33, 33, 33 +ch110, x, x, x, x, x, x +ch112, 33, 33, 33, 33, 33, 33 +ch114, x, x, x, x, x, x +ch116, 33, 33, 33, 33, 33, 33 +ch118, x, x, x, x, x, x +ch120, 33, 33, 33, 33, 33, 33 +ch122, x, x, x, x, x, x +ch124, 33, 33, 33, 33, 33, 33 +ch126, x, x, x, x, x, x +ch128, 33, 33, 33, 33, 33, 33 +ch132, 33, 33, 33, 33, 33, 33 +ch134, x, x, x, x, x, x +ch136, 33, 33, 33, 33, 33, 33 +ch138, x, x, x, x, x, x +ch140, 33, 33, 33, 33, 33, 33 +ch142, x, x, x, x, x, x +ch144, x, x, x, x, x, x +ch149, x, x, x, x, x, x +ch151, x, x, x, x, x, x +ch153, x, x, x, x, x, x +ch155, x, x, x, x, x, x +ch157, x, x, x, x, x, x +ch159, x, x, x, x, x, x +ch161, x, x, x, x, x, x +ch165, x, x, x, x, x, x +</ht20> + +<ht40, mcs0_8, mcs1_2_9_10, mcs3_4_11_12, mcs5_13, mcs6_14, mcs7_15, mcs32> +ch001, x, x, x, x, x, x, x +ch002, x, x, x, x, x, x, x +ch003, x, x, x, x, x, x, x +ch004, x, x, x, x, x, x, x +ch005, x, x, x, x, x, x, x +ch006, x, x, x, x, x, x, x +ch007, x, x, x, x, x, x, x +ch008, x, x, x, x, x, x, x +ch009, x, x, x, x, x, x, x +ch010, x, x, x, x, x, x, x +ch011, x, x, x, x, x, x, x +ch012, x, x, x, x, x, x, x +ch013, x, x, x, x, x, x, x +ch014, x, x, x, x, x, x, x +ch036, x, x, x, x, x, x, x +ch038, 23, 23, 23, 23, 23, 23, 23 +ch040, x, x, x, x, x, x, x +ch042, x, x, x, x, x, x, x +ch044, x, x, x, x, x, x, x +ch046, 25, 25, 25, 25, 25, 25, 25 +ch048, x, x, x, x, x, x, x +ch050, x, x, x, x, x, x, x +ch052, x, x, x, x, x, x, x +ch054, 16, 16, 16, 16, 16, 16, 16 +ch056, x, x, x, x, x, x, x +ch058, x, x, x, x, x, x, x +ch060, x, x, x, x, x, x, x +ch062, 16, 16, 16, 16, 16, 16, 16 +ch064, x, x, x, x, x, x, x +ch100, x, x, x, x, x, x, x +ch102, 33, 33, 33, 33, 33, 33, 33 +ch104, x, x, x, x, x, x, x +ch106, x, x, x, x, x, x, x +ch108, x, x, x, x, x, x, x +ch110, 33, 33, 33, 33, 33, 33, 33 +ch112, x, x, x, x, x, x, x +ch114, x, x, x, x, x, x, x +ch116, x, x, x, x, x, x, x +ch118, 33, 33, 33, 33, 33, 33, 33 +ch120, x, x, x, x, x, x, x +ch122, x, x, x, x, x, x, x +ch124, x, x, x, x, x, x, x +ch126, 33, 33, 33, 33, 33, 33, 33 +ch128, x, x, x, x, x, x, x +ch132, x, x, x, x, x, x, x +ch134, 33, 33, 33, 33, 33, 33, 33 +ch136, x, x, x, x, x, x, x +ch138, x, x, x, x, x, x, x +ch140, x, x, x, x, x, x, x +ch142, x, x, x, x, x, x, x +ch144, x, x, x, x, x, x, x +ch149, x, x, x, x, x, x, x +ch151, x, x, x, x, x, x, x +ch153, x, x, x, x, x, x, x +ch155, x, x, x, x, x, x, x +ch157, x, x, x, x, x, x, x +ch159, x, x, x, x, x, x, x +ch161, x, x, x, x, x, x, x +ch165, x, x, x, x, x, x, x +</ht40> + +<vht20, mcs0, mcs1_2, mcs3_4, mcs5_6, mcs7, mcs8, mcs9> + ch001, 34, 34, 34, 34, 34, 34, 34 + ch002, 34, 34, 34, 34, 34, 34, 34 + ch003, 34, 34, 34, 34, 34, 34, 34 + ch004, 34, 34, 34, 34, 34, 34, 34 + ch005, 34, 34, 34, 34, 34, 34, 34 + ch006, 34, 34, 34, 34, 34, 34, 34 + ch007, 34, 34, 34, 34, 34, 34, 34 + ch008, 34, 34, 34, 34, 34, 34, 34 + ch009, 34, 34, 34, 34, 34, 34, 34 + ch010, 34, 34, 34, 34, 34, 34, 34 + ch011, 34, 34, 34, 34, 34, 34, 34 + ch012, 34, 34, 34, 34, 34, 34, 34 + ch013, 34, 34, 34, 34, 34, 34, 34 + ch014, x, x, x, x, x, x, x + ch036, 23, 23, 23, 23, 23, 23, 23 + ch038, 22, 22, 22, 22, 22, 22, 22 + ch040, 23, 23, 23, 23, 23, 23, 23 + ch042, 17, 17, 17, 17, 17, 17, 17 + ch044, 24, 24, 24, 24, 24, 24, 24 + ch046, 24, 24, 24, 24, 24, 24, 24 + ch048, 24, 24, 24, 24, 24, 24, 24 + ch050, x, x, x, x, x, x, x + ch052, 18, 18, 18, 18, 18, 18, 18 + ch054, 18, 18, 18, 18, 18, 18, 18 + ch056, 18, 18, 18, 18, 18, 18, 18 + ch058, 22, 22, 22, 22, 22, 22, 22 + ch060, 17, 17, 17, 17, 17, 17, 17 + ch062, 17, 17, 17, 17, 17, 17, 17 + ch064, 17, 17, 17, 17, 17, 17, 17 + ch100, 33, 33, 33, 33, 33, 33, 33 + ch102, 34, 34, 34, 34, 34, 34, 34 + ch104, 33, 33, 33, 33, 33, 33, 33 + ch106, 34, 34, 34, 34, 34, 34, 34 + ch108, 33, 33, 33, 33, 33, 33, 33 + ch110, 34, 34, 34, 34, 34, 34, 34 + ch112, 33, 33, 33, 33, 33, 33, 33 + ch114, x, x, x, x, x, x, x + ch116, 33, 33, 33, 33, 33, 33, 33 + ch118, 34, 34, 34, 34, 34, 34, 34 + ch120, 33, 33, 33, 33, 33, 33, 33 + ch122, 34, 34, 34, 34, 34, 34, 34 + ch124, 33, 33, 33, 33, 33, 33, 33 + ch126, 34, 34, 34, 34, 34, 34, 34 + ch128, 33, 33, 33, 33, 33, 33, 33 + ch132, 33, 33, 33, 33, 33, 33, 33 + ch134, 34, 34, 34, 34, 34, 34, 34 + ch136, 33, 33, 33, 33, 33, 33, 33 + ch138, 33, 33, 33, 33, 33, 33, 33 + ch140, 33, 33, 33, 33, 33, 33, 33 + ch142, x, x, x, x, x, x, x + ch144, x, x, x, x, x, x, x + ch149, x, x, x, x, x, x, x + ch151, x, x, x, x, x, x, x + ch153, x, x, x, x, x, x, x + ch155, x, x, x, x, x, x, x + ch157, x, x, x, x, x, x, x + ch159, x, x, x, x, x, x, x + ch161, x, x, x, x, x, x, x + ch165, x, x, x, x, x, x, x + </vht20> + +<offset, lg40, lg80, vht40, vht80, vht160nc> + ch001, x, x, x, x, x + ch002, x, x, x, x, x + ch003, x, x, x, x, x + ch004, x, x, x, x, x + ch005, x, x, x, x, x + ch006, x, x, x, x, x + ch007, x, x, x, x, x + ch008, x, x, x, x, x + ch009, x, x, x, x, x + ch010, x, x, x, x, x + ch011, x, x, x, x, x + ch012, x, x, x, x, x + ch013, x, x, x, x, x + ch014, x, x, x, x, x + ch036, x, x, x, x, x + ch038, x, x, 1, x, x + ch040, x, x, x, x, x + ch042, x, x, x, 9, x + ch044, x, x, x, x, x + ch046, x, x, 1, x, x + ch048, x, x, x, x, x + ch050, x, x, x, x, x + ch052, x, x, x, x, x + ch054, x, x, -2, x, x + ch056, x, x, x, x, x + ch058, x, x, x, -1, x + ch060, x, x, x, x, x + ch062, x, x, -1, x, x + ch064, x, x, x, x, x + ch100, x, x, x, x, x + ch102, x, x, -1, x, x + ch104, x, x, x, x, x + ch106, x, x, x, -1, x + ch108, x, x, x, x, x + ch110, x, x, -1, x, x + ch112, x, x, x, x, x + ch114, x, x, x, x, x + ch116, x, x, x, x, x + ch118, x, x, -1, x, x + ch120, x, x, x, x, x + ch122, x, x, x, -1, x + ch124, x, x, x, x, x + ch126, x, x, -1, x, x + ch128, x, x, x, x, x + ch132, x, x, x, x, x + ch134, x, x, -1, x, x + ch136, x, x, x, x, x + ch138, x, x, x, x, x + ch140, x, x, x, x, x + ch142, x, x, x, x, x + ch144, x, x, x, x, x + ch149, x, x, x, x, x + ch151, x, x, x, x, x + ch153, x, x, x, x, x + ch155, x, x, x, x, x + ch157, x, x, x, x, x + ch159, x, x, x, x, x + ch161, x, x, x, x, x + ch165, x, x, x, x, x +</offset> + diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/firmware/wifi.cfg b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/firmware/wifi.cfg new file mode 100644 index 00000000000000..d77050542d4d83 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/firmware/wifi.cfg @@ -0,0 +1,74 @@ +#Qos 0 +LdpcTx 1 +LdpcRx 1 +#StbcRx 0 +#AmpduTx 1 +#AmpduRx 1 +#SgiTx 1 +#SgiRx 1 +StaHT 1 +StaVHT 1 +GfTx 0 +GfRx 0 +P2pGoHT 1 +P2pGoVHT 1 +P2pGcHT 1 +P2pGcVHT 1 +#ApChannel 6 +ApHT 1 +ApVHT 1 +Sta2gBw 2 +Sta5gBw 2 +P2p2gBw 2 +P2p5gBw 2 +Ap2gBw 2 +Ap5gBw 2 +#ApChnlDefFromCfg 1 +#TxBaSize 64 +#ApForwardBufferCnt 128 +RxMaxMpduLen 1 +#MacOverride 0 +#MacAddr 00:0c:e7:66:32:dd +Nss 2 +Ap5gNss 2 +AmsduInAmpduTx 0 +AmsduInAmpduRx 0 +HtAmsduInAmpduTx 0 +HtAmsduInAmpduRx 0 +VhtAmsduInAmpduTx 0 +VhtAmsduInAmpduRx 0 +DbdcMode 2 +EfuseBufferModeCal 2 +RegP2pIfAtProbe 1 +Wow 1 +SetChip0 KeepFullPwr 1 +TdlsBufferSTASleep 0 +ChipResetRecover 1 +#TpTestMode 0 +DisRoaming 1 +TxMaxAmsduInAmpduLen 4095 +GpioInterval 20000 +FastTxMode 0 +HifTxLoop 8 +OsTxLoop 8 +CoexModeCtrl 1 +CoexIsoCtrl 2 +AdapScan 1 +CalTimingCtrl 1 +Ed2GNonEU -62 +Ed5GNonEU -62 +Ed2GEU -68 +Ed5GEU -68 +#SpeIdxCtrl2G 0 +#ForceRspFrameDup2G 0 +WlanSetCamDuringAct 1 +DelayTimeofDisconnect 8 +SwCtrl0 0xa1260009 0x0032321e +Tc6MinRsv 1 +Tc7MinRsv 1 +Tc8MinRsv 1 +Tc9MinRsv 1 +MccAisScanChNum 5 +AdjustMccP2pScanStayTime 1 +MccP2pStayTime 120 +BmcKeyErrorTh 0 diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/CFG_Wifi_File.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/CFG_Wifi_File.h new file mode 100644 index 00000000000000..380ba671539f3a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/CFG_Wifi_File.h @@ -0,0 +1,281 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file CFG_Wifi_File.h + * \brief Collection of NVRAM structure used for YuSu project + * + * In this file we collect all compiler flags and detail the driver behavior + * if enable/disable such switch or adjust numeric parameters. + */ + +#ifndef _CFG_WIFI_FILE_H +#define _CFG_WIFI_FILE_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "gl_typedef.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/* duplicated from nic_cmd_event.h to avoid header dependency */ +typedef struct _TX_PWR_PARAM_T { + s8 cTxPwr2G4Cck; /* signed, in unit of 0.5dBm */ + s8 cTxPwr2G4Dsss; /* signed, in unit of 0.5dBm */ + s8 acReserved[2]; + + s8 cTxPwr2G4OFDM_BPSK; + s8 cTxPwr2G4OFDM_QPSK; + s8 cTxPwr2G4OFDM_16QAM; + s8 cTxPwr2G4OFDM_Reserved; + s8 cTxPwr2G4OFDM_48Mbps; + s8 cTxPwr2G4OFDM_54Mbps; + + s8 cTxPwr2G4HT20_BPSK; + s8 cTxPwr2G4HT20_QPSK; + s8 cTxPwr2G4HT20_16QAM; + s8 cTxPwr2G4HT20_MCS5; + s8 cTxPwr2G4HT20_MCS6; + s8 cTxPwr2G4HT20_MCS7; + + s8 cTxPwr2G4HT40_BPSK; + s8 cTxPwr2G4HT40_QPSK; + s8 cTxPwr2G4HT40_16QAM; + s8 cTxPwr2G4HT40_MCS5; + s8 cTxPwr2G4HT40_MCS6; + s8 cTxPwr2G4HT40_MCS7; + + s8 cTxPwr5GOFDM_BPSK; + s8 cTxPwr5GOFDM_QPSK; + s8 cTxPwr5GOFDM_16QAM; + s8 cTxPwr5GOFDM_Reserved; + s8 cTxPwr5GOFDM_48Mbps; + s8 cTxPwr5GOFDM_54Mbps; + + s8 cTxPwr5GHT20_BPSK; + s8 cTxPwr5GHT20_QPSK; + s8 cTxPwr5GHT20_16QAM; + s8 cTxPwr5GHT20_MCS5; + s8 cTxPwr5GHT20_MCS6; + s8 cTxPwr5GHT20_MCS7; + + s8 cTxPwr5GHT40_BPSK; + s8 cTxPwr5GHT40_QPSK; + s8 cTxPwr5GHT40_16QAM; + s8 cTxPwr5GHT40_MCS5; + s8 cTxPwr5GHT40_MCS6; + s8 cTxPwr5GHT40_MCS7; +} TX_PWR_PARAM_T, *P_TX_PWR_PARAM_T; + +typedef struct _TX_AC_PWR_T { + s8 c11AcTxPwr_BPSK; + s8 c11AcTxPwr_QPSK; + s8 c11AcTxPwr_16QAM; + s8 c11AcTxPwr_MCS5_MCS6; + s8 c11AcTxPwr_MCS7; + s8 c11AcTxPwr_MCS8; + s8 c11AcTxPwr_MCS9; + s8 c11AcTxPwrVht40_OFFSET; + s8 c11AcTxPwrVht80_OFFSET; + s8 c11AcTxPwrVht160_OFFSET; + s8 acReverse[2]; +} TX_AC_PWR_T, *P_TX_AC_PWR_T; + +typedef struct _RSSI_PATH_COMPASATION_T { + s8 c2GRssiCompensation; + s8 c5GRssiCompensation; +} RSSI_PATH_COMPASATION_T, *P_RSSI_PATH_COMPASATION_T; + +typedef struct _PWR_5G_OFFSET_T { + s8 cOffsetBand0; /* 4.915-4.980G */ + s8 cOffsetBand1; /* 5.000-5.080G */ + s8 cOffsetBand2; /* 5.160-5.180G */ + s8 cOffsetBand3; /* 5.200-5.280G */ + s8 cOffsetBand4; /* 5.300-5.340G */ + s8 cOffsetBand5; /* 5.500-5.580G */ + s8 cOffsetBand6; /* 5.600-5.680G */ + s8 cOffsetBand7; /* 5.700-5.825G */ +} PWR_5G_OFFSET_T, *P_PWR_5G_OFFSET_T; + +typedef struct _PWR_PARAM_T { + u32 au4Data[28]; + u32 u4RefValue1; + u32 u4RefValue2; +} PWR_PARAM_T, *P_PWR_PARAM_T; + +typedef struct _AC_PWR_SETTING_STRUCT { + u8 c11AcTxPwr_BPSK; + u8 c11AcTxPwr_QPSK; + u8 c11AcTxPwr_16QAM; + u8 c11AcTxPwr_MCS5_MCS6; + u8 c11AcTxPwr_MCS7; + u8 c11AcTxPwr_MCS8; + u8 c11AcTxPwr_MCS9; + u8 c11AcTxPwr_Reserved; + u8 c11AcTxPwrVht40_OFFSET; + u8 c11AcTxPwrVht80_OFFSET; + u8 c11AcTxPwrVht160_OFFSET; +} AC_PWR_SETTING_STRUCT, *P_AC_PWR_SETTING_STRUCT; + +typedef struct _BANDEDGE_5G_T { + u8 uc5GBandEdgePwrUsed; + u8 c5GBandEdgeMaxPwrOFDM20; + u8 c5GBandEdgeMaxPwrOFDM40; + u8 c5GBandEdgeMaxPwrOFDM80; +} BANDEDGE_5G_T, *P_BANDEDGE_5G_T; + +typedef struct _NEW_EFUSE_MAPPING2NVRAM_T { + u8 ucReverse1[8]; + u16 u2Signature; + BANDEDGE_5G_T r5GBandEdgePwr; + u8 ucReverse2[14]; + + /* 0x50 */ + u8 aucChOffset[3]; + u8 ucChannelOffsetVaild; + u8 acAllChannelOffset; + u8 aucChOffset3[11]; + + /* 0x60 */ + u8 auc5GChOffset[8]; + u8 uc5GChannelOffsetVaild; + u8 aucChOffset4[7]; + + /* 0x70 */ + AC_PWR_SETTING_STRUCT r11AcTxPwr; + u8 uc11AcTxPwrValid; + + u8 ucReverse4[20]; + + /* 0x90 */ + AC_PWR_SETTING_STRUCT r11AcTxPwr2G; + u8 uc11AcTxPwrValid2G; + + u8 ucReverse5[40]; +} NEW_EFUSE_MAPPING2NVRAM_T, *P_NEW_EFUSE_MAPPING2NVRAM_T; + +typedef struct _MT6620_CFG_PARAM_STRUCT { + /* 256 bytes of MP data */ + u16 u2Part1OwnVersion; + u16 u2Part1PeerVersion; + u8 aucMacAddress[6]; + u8 aucCountryCode[2]; + TX_PWR_PARAM_T rTxPwr; +#if CFG_SUPPORT_NVRAM_5G + union { + NEW_EFUSE_MAPPING2NVRAM_T u; + u8 aucEFUSE[144]; + } EfuseMapping; +#else + u8 aucEFUSE[144]; +#endif + u8 ucTxPwrValid; + u8 ucSupport5GBand; + u8 fg2G4BandEdgePwrUsed; + s8 cBandEdgeMaxPwrCCK; + s8 cBandEdgeMaxPwrOFDM20; + s8 cBandEdgeMaxPwrOFDM40; + + u8 ucRegChannelListMap; + u8 ucRegChannelListIndex; + u8 aucRegSubbandInfo[36]; + + u8 aucReserved2[256 - 240]; + + /* 256 bytes of function data */ + u16 u2Part2OwnVersion; + u16 u2Part2PeerVersion; + u8 uc2G4BwFixed20M; + u8 uc5GBwFixed20M; + u8 ucEnable5GBand; + u8 ucRxDiversity; + RSSI_PATH_COMPASATION_T rRssiPathCompensation; + u8 fgRssiCompensationVaildbit; + u8 ucGpsDesense; + u16 u2FeatureReserved; + u8 aucPreTailReserved; + u8 aucTailReserved[256 - 15]; +} MT6620_CFG_PARAM_STRUCT, *P_MT6620_CFG_PARAM_STRUCT, WIFI_CFG_PARAM_STRUCT, +*P_WIFI_CFG_PARAM_STRUCT; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#ifndef DATA_STRUCT_INSPECTING_ASSERT +#define DATA_STRUCT_INSPECTING_ASSERT(expr) \ + { \ + switch (0) { \ + case 0: \ + case (expr): \ + default:; \ + } \ + } +#endif + +#define CFG_FILE_WIFI_REC_SIZE sizeof(WIFI_CFG_PARAM_STRUCT) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#ifndef _lint +/* We don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + * We'll need this to guarantee the same member order in different structures + * to simply handling effort in some functions. + */ +static __KAL_INLINE__ void nvramOffsetCheck(void) +{ + DATA_STRUCT_INSPECTING_ASSERT( + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2OwnVersion) == 256); + + DATA_STRUCT_INSPECTING_ASSERT(sizeof(WIFI_CFG_PARAM_STRUCT) == 512); +#if CFG_SUPPORT_NVRAM_5G + DATA_STRUCT_INSPECTING_ASSERT( + (OFFSET_OF(WIFI_CFG_PARAM_STRUCT, EfuseMapping) & 0x0001) == 0); +#else + DATA_STRUCT_INSPECTING_ASSERT( + (OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucEFUSE) & 0x0001) == 0); +#endif + DATA_STRUCT_INSPECTING_ASSERT( + (OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucRegSubbandInfo) & + 0x0001) == 0); +} +#endif + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/chips/mt7668.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/chips/mt7668.h new file mode 100644 index 00000000000000..ed102ca13223af --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/chips/mt7668.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file mt7668.h + * \brief This file contains the info of MT7668 + */ + +#ifndef _MT7668_H +#define _MT7668_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define MT7668_CHIP_ID (0x7668) +#define MT7668_SW_SYNC0 WIFI_RGU_SW_SYNC0 +#define MT7668_SW_SYNC0_RDY_OFFSET WIFI_RGU_SYNC0_RDY_OFFSET +#define MT7668_PATCH_START_ADDR (0x000C8000) +#define MT7668_IS_PCIE_32DW_READ (0) + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void mt7668ConstructFirmwarePrio(P_GLUE_INFO_T prGlueInfo, u8 **apucNameTable, u8 **apucName, u8 *pucNameIdx, u8 ucMaxNameIdx); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/config.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/config.h new file mode 100644 index 00000000000000..f8353e1944576d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/config.h @@ -0,0 +1,1058 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "config.h" + * \brief This file includes the various configurable parameters for + * customers + * + * This file ncludes the configurable parameters except the parameters + * indicate the turning-on/off of some features + */ + +#ifndef _CONFIG_H +#define _CONFIG_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define BUILD_DBG_MSG 0 +#define BUILD_QA_DBG 0 +#define CFG_DEFAULT_DBG_LEVEL 0xF + +#define CFG_DUMP_TXPOWR_TABLE +#define CFG_ENABLE_1RPD_MMPS_CTRL 1 +#define CFG_ENABLE_DEWEIGHTING_CTRL 1 +#define CFG_ENABLE_PS_INTV_CTRL 1 + +#define CFG_IPI_2CHAIN_SUPPORT 1 +#define CFG_KEY_ERROR_STATISTIC_RECOVERY 1 +#define CFG_MET_PACKET_TRACE_SUPPORT 1 + +#define CFG_NUM_DIFFERENT_CHANNELS_P2P 1 +#define CFG_NUM_DIFFERENT_CHANNELS_STA 1 +#define CFG_P2P_SCAN_REPORT_ALL_BSS 0 +#define CFG_RX_DIRECT_USB 1 +#define CFG_RX_SINGLE_CHAIN_SUPPORT 1 +#define CFG_SCAN_CHANNEL_SPECIFIED 1 + +#define CFG_SUPPORT_CHNL_CONFLICT_REVISE 0 + +#define CFG_SUPPORT_DBDC_TC6 1 +#define CFG_SUPPORT_DEBUG_FS 1 +#define CFG_SUPPORT_DFS_MASTER 1 +#define CFG_SUPPORT_DISABLE_BCN_HINTS +#define CFG_SUPPORT_DISABLE_SAP_DFS_RDD +#define CFG_SUPPORT_LARGE_TX_PWR_LIMIT_TABLE 0 +#define CFG_SUPPORT_MULTICAST_ENHANCEMENT +#define CFG_SUPPORT_OWE 1 +#define CFG_SUPPORT_SAE 1 +#define CFG_SUPPORT_SAP_DFS_CHANNEL 1 +#define CFG_SUPPORT_SAME_BSS_REASSOC 1 +#define CFG_SUPPORT_SUITB 1 +#define CFG_SUPPORT_TSF_USING_BOOTTIME 1 +#define CFG_TX_WMM_ENHANCE 1 +#ifndef DBG +#define DBG 0 +#endif + +#define CFG_ANDROID_AOSP_PRIV_CMD +#define STA_P2P_MCC +#define WLAN_INCLUDE_PROC 1 + +#ifndef CFG_MESON_G12A_PATCH +#define CFG_MESON_G12A_PATCH 1 +#endif + +#define CFG_ENABLE_UNIFY_WIPHY 0 + +/* 2 Flags for OS capability */ + +#define CFG_ENABLE_EARLY_SUSPEND 0 +#define CFG_ENABLE_NET_DEV_NOTIFY 1 + +#ifndef CFG_GARP_KEEPALIVE +#define CFG_GARP_KEEPALIVE 1 +#endif + +/* 2 Flags for Driver Features */ +#define CFG_TX_FRAGMENT 1 /*!< 1: Enable TX fragmentation */ +/* 0: Disable */ +#define CFG_SUPPORT_PERFORMANCE_TEST 0 /*Only for performance Test */ + +#define CFG_COUNTRY_CODE NULL /* "US" */ +#ifndef CFG_SUPPORT_DEBUG_FS +#define CFG_SUPPORT_DEBUG_FS 1 +#endif + +#define CFG_FW_FILENAME "WIFI_RAM_CODE" +#define CFG_CR4_FW_FILENAME "WIFI_RAM_CODE2" + +#ifndef CFG_MET_PACKET_TRACE_SUPPORT +#define CFG_MET_PACKET_TRACE_SUPPORT 0 /*move to wlan/MAKEFILE */ +#endif + +/*------------------------------------------------------------------------------ + * Driver config + *------------------------------------------------------------------------------ + */ + +#define CFG_SUPPORT_CFG_FILE 1 + +#define CFG_SUPPORT_802_11D 1 /*!< 1(default): Enable 802.11d */ +/* 0: Disable */ + +#define CFG_SUPPORT_RRM 0 /* Radio Reasource Measurement (802.11k) */ +#ifndef CFG_SUPPORT_DFS +#define CFG_SUPPORT_DFS 1 /* DFS (802.11h) */ +#endif + +#ifndef CFG_DFS_NEWCH_DFS_FORCE_DISCONNECT +#define CFG_DFS_NEWCH_DFS_FORCE_DISCONNECT 1 +#endif + +#if (CFG_SUPPORT_DFS == 1) /* Add by Enlai */ +#define CFG_SUPPORT_QUIET 1 /* Quiet (802.11h) */ +#define CFG_SUPPORT_SPEC_MGMT \ + 1 /* Spectrum Management (802.11h): TPC and DFS \ + */ +#else +#define CFG_SUPPORT_QUIET 0 /* Quiet (802.11h) */ +#define CFG_SUPPORT_SPEC_MGMT \ + 0 /* Spectrum Management (802.11h): TPC and DFS \ + */ +#endif + +#define CFG_SUPPORT_RX_RDG 0 /* 11n feature. RX RDG capability */ +#define CFG_SUPPORT_MFB 0 /* 802.11n MCS Feedback responder */ +#define CFG_SUPPORT_RX_STBC 1 /* 802.11n RX STBC (1SS) */ +#define CFG_SUPPORT_RX_SGI 1 /* 802.11n RX short GI for both 20M and 40M BW */ +#define CFG_SUPPORT_RX_HT_GF 1 /* 802.11n RX HT green-field capability */ + +#ifndef CFG_SUPPORT_BFER +#define CFG_SUPPORT_BFER 0 +#endif + +#define CFG_SUPPORT_BFEE 1 + +/* Enable QA Tool Support */ +#define CFG_SUPPORT_QA_TOOL 1 + +/* Enable TX BF Support */ +#define CFG_SUPPORT_TX_BF 1 + +/* Enable MU MIMO Support */ +#define CFG_SUPPORT_MU_MIMO 1 + +/* Enable WOW Support */ +#define CFG_WOW_SUPPORT 1 + +/* Enable A-MSDU RX Reordering Support */ +#define CFG_SUPPORT_RX_AMSDU 1 + +/* Enable Fragment Support */ +#define CFG_SUPPORT_FRAG_SUPPORT 1 + +/* Enable frag and de-AMSDU security patch */ +#define CFG_FRAG_DEAMSDU_ATTACK_DETECTION 1 + +#if (CFG_FRAG_DEAMSDU_ATTACK_DETECTION) +/* Enable A-MSDU Attack Detection */ +#define CFG_SUPPORT_AMSDU_ATTACK_DETECTION 1 +/* Enable Fragment Attack Detection */ +#define CFG_SUPPORT_FRAG_ATTACK_DETECTION 1 +/* Enable Fake EAPOL Detection */ +#define CFG_SUPPORT_FAKE_EAPOL_DETECTION 1 +/* Enable TKIP MIC ERROR Detection */ +#define CFG_SUPPORT_TKIP_MICERROR_DETECTION 1 +#else +/* Enable A-MSDU Attack Detection */ +#define CFG_SUPPORT_AMSDU_ATTACK_DETECTION 0 +/* Enable Fragment Attack Detection */ +#define CFG_SUPPORT_FRAG_ATTACK_DETECTION 0 +/* Enable Fake EAPOL Detection */ +#define CFG_SUPPORT_FAKE_EAPOL_DETECTION 0 +/* Enable TKIP MIC ERROR Detection */ +#define CFG_SUPPORT_TKIP_MICERROR_DETECTION 0 +#endif + +/*------------------------------------------------------------------------------ + * Flags of Buffer mode SUPPORT + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_BUFFER_MODE 1 + +#ifdef NDIS60_MINIPORT +#define CFG_NATIVE_802_11 1 + +#if CFG_MESON_G12A_PATCH +#define CFG_TX_MAX_PKT_SIZE 1408 +#else +#define CFG_TX_MAX_PKT_SIZE 2304 +#endif +#define CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 \ + 0 /* !< 1: Enable TCP/IP header checksum offload */ +/* 0: Disable */ +#define CFG_TCP_IP_CHKSUM_OFFLOAD 0 +#define CFG_WHQL_DOT11_STATISTICS 1 +#define CFG_WHQL_ADD_REMOVE_KEY 1 +#define CFG_WHQL_CUSTOM_IE 1 +#define CFG_WHQL_SAFE_MODE_ENABLED 1 + +#else +#define CFG_TCP_IP_CHKSUM_OFFLOAD 1 +#define CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 0 +#if CFG_MESON_G12A_PATCH +#define CFG_TX_MAX_PKT_SIZE 1408 +#else +#define CFG_TX_MAX_PKT_SIZE 1600 +#endif +#define CFG_NATIVE_802_11 0 +#endif + +/* 2 Flags for Driver Parameters */ +/*------------------------------------------------------------------------------ + * Flags for EHPI Interface in Colibri Platform + *------------------------------------------------------------------------------ + */ + +/*!< 1: Do workaround for faster bus timing */ +/* 0(default): Disable */ +#define CFG_EHPI_FASTER_BUS_TIMING 0 + +/*------------------------------------------------------------------------------ + * Flags for UMAC + *------------------------------------------------------------------------------ + */ +#define CFG_UMAC_GENERATION 0x20 + +/*------------------------------------------------------------------------------ + * Flags for HIFSYS Interface + *------------------------------------------------------------------------------ + */ + +/* 1(default): Enable SDIO ISR & TX/RX status enhance mode + * 0: Disable + */ +#define CFG_SDIO_INTR_ENHANCE 1 +/* 1(default): Enable SDIO ISR & TX/RX status enhance mode + * 0: Disable + */ +#if CFG_MESON_G12A_PATCH +#define CFG_SDIO_RX_ENHANCE 0 +#else +#define CFG_SDIO_RX_ENHANCE 1 +#endif +/* 1: Enable SDIO TX enhance mode(Multiple frames in single BLOCK CMD) + * 0(default): Disable + */ +#if CFG_MESON_G12A_PATCH +#define CFG_SDIO_TX_AGG 0 +#else +#define CFG_SDIO_TX_AGG 1 +#endif + +/* 1: Enable SDIO RX enhance mode(Multiple frames in single BLOCK CMD) + * 0(default): Disable + */ +#define CFG_SDIO_RX_AGG 1 + +/* 1: Enable SDIO RX Tasklet De-Aggregation + * 0(default): Disable + */ +#define CFG_SDIO_RX_AGG_TASKLET 0 + +#if (CFG_SDIO_RX_AGG == 1) && (CFG_SDIO_INTR_ENHANCE == 0) +#error "CFG_SDIO_INTR_ENHANCE should be 1 once CFG_SDIO_RX_AGG equals to 1" +#elif (CFG_SDIO_INTR_ENHANCE == 1 || CFG_SDIO_RX_ENHANCE == 1) && \ + (CFG_SDIO_RX_AGG == 0) +#error \ + "CFG_SDIO_RX_AGG should be 1 once CFG_SDIO_INTR_ENHANCE and/or CFG_SDIO_RX_ENHANCE equals to 1" +#endif + +#ifdef WINDOWS_CE +#define CFG_SDIO_PATHRU_MODE 1 /*!< 1: Support pass through (PATHRU) mode */ +/* 0: Disable */ +#else +#define CFG_SDIO_PATHRU_MODE \ + 0 /*!< 0: Always disable if WINDOWS_CE is not defined */ +#endif + +#define CFG_SDIO_ACCESS_N9_REGISTER_BY_MAILBOX 0 +#define CFG_MAX_RX_ENHANCE_LOOP_COUNT 3 + +#define CFG_USB_TX_AGG 1 +#define CFG_USB_CONSISTENT_DMA 0 +#define CFG_USB_TX_HANDLE_IN_HIF_THREAD 0 +#define CFG_USB_RX_HANDLE_IN_HIF_THREAD 0 + +#define CFG_HW_WMM_BY_BSS 1 +/*------------------------------------------------------------------------------ + * Flags and Parameters for Integration + *------------------------------------------------------------------------------ + */ + +#define CFG_MULTI_ECOVER_SUPPORT 1 + +#define CFG_ENABLE_CAL_LOG 1 +#define CFG_REPORT_RFBB_VERSION 1 + +#define HW_BSSID_NUM 4 /* HW BSSID number by chip */ +#define HW_WMM_NUM 4 /* HW WMM number by chip */ + +#define MAX_BSSID_NUM 4 /* MAX BSSID number */ + +/*------------------------------------------------------------------------------ + * Flags for workaround + *------------------------------------------------------------------------------ + */ + +/*------------------------------------------------------------------------------ + * Flags for driver version + *------------------------------------------------------------------------------ + */ +#define CFG_DRV_OWN_VERSION \ + ((u16)((NIC_DRIVER_MAJOR_VERSION << 8) | (NIC_DRIVER_MINOR_VERSION))) +#define CFG_DRV_PEER_VERSION ((u16)0x0000) + +/*------------------------------------------------------------------------------ + * Flags and Parameters for TX path + *------------------------------------------------------------------------------ + */ + +/*! Maximum number of SW TX packet queue */ +#define CFG_TX_MAX_PKT_NUM 1024 + +/*! Maximum number of SW TX CMD packet buffer */ +#define CFG_TX_MAX_CMD_PKT_NUM 32 + +/*------------------------------------------------------------------------------ + * Flags and Parameters for RX path + *------------------------------------------------------------------------------ + */ + +/*! Max. descriptor number - sync. with firmware */ +#define CFG_NUM_OF_RX0_HIF_DESC 16 +#define CFG_NUM_OF_RX1_HIF_DESC 2 + +/*! Max. buffer hold by QM */ +#define CFG_NUM_OF_QM_RX_PKT_NUM HIF_NUM_OF_QM_RX_PKT_NUM + +/*! Maximum number of SW RX packet buffer */ +#define CFG_RX_MAX_PKT_NUM \ + ((CFG_NUM_OF_RX0_HIF_DESC + CFG_NUM_OF_RX1_HIF_DESC) * 3 + \ + CFG_NUM_OF_QM_RX_PKT_NUM) + +#define CFG_RX_REORDER_Q_THRESHOLD 8 + +#define CFG_RX_RETAINED_PKT_THRESHOLD 0 + +/*! Maximum RX packet size, if exceed this value, drop incoming packet */ +/* 7.2.3 Maganement frames */ +/* TODO: it should be 4096 under emulation mode */ +#define CFG_RX_MAX_PKT_SIZE (28 + 2312 + \ + 12 /*HIF_RX_HEADER_T*/ ) + +/*! Minimum RX packet size, if lower than this value, drop incoming packet */ +#define CFG_RX_MIN_PKT_SIZE 10 /*!< 802.11 Control Frame is 10 bytes */ + +/*! RX BA capability */ +#define CFG_NUM_OF_RX_BA_AGREEMENTS 8 +#define CFG_RX_BA_INC_SIZE 64 +#define CFG_RX_MAX_BA_TID_NUM 8 +#define CFG_RX_REORDERING_ENABLED 1 + +#define CFG_PF_ARP_NS_MAX_NUM 3 + +#define CFG_COMPRESSION_DEBUG 0 +#define CFG_DECOMPRESSION_TMP_ADDRESS 0 +#define CFG_SUPPORT_COMPRESSION_FW_OPTION 0 + +/*------------------------------------------------------------------------------ + * Flags and Parameters for CMD/RESPONSE + *------------------------------------------------------------------------------ + */ +#define CFG_RESPONSE_POLLING_TIMEOUT 1000 +#define CFG_RESPONSE_POLLING_DELAY 5 + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Protocol Stack + *------------------------------------------------------------------------------ + */ + +/*! Maximum number of BSS in the SCAN list */ +#define CFG_MAX_NUM_BSS_LIST 192 + +#define CFG_MAX_COMMON_IE_BUF_LEN ((1500 * \ + CFG_MAX_NUM_BSS_LIST) / 3) + +/*! Maximum size of Header buffer of each SCAN record */ +#define CFG_RAW_BUFFER_SIZE 1024 + +/*! Maximum size of IE buffer of each SCAN record */ +#define CFG_IE_BUFFER_SIZE 512 + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Power management + *------------------------------------------------------------------------------ + */ +#define CFG_ENABLE_FULL_PM 1 +#define CFG_ENABLE_WAKEUP_ON_LAN 0 + +#define CFG_INIT_POWER_SAVE_PROF ENUM_PSP_FAST_SWITCH + +#define CFG_INIT_ENABLE_PATTERN_FILTER_ARP 0 + +#define CFG_INIT_UAPSD_AC_BMP 0 /* (BIT(3) | BIT(2) | BIT(1) | BIT(0)) */ + +#define CFG_SUPPORT_WPS 1 +#define CFG_SUPPORT_WPS2 1 + +/*------------------------------------------------------------------------------ + * 802.11i RSN Pre-authentication PMKID cahce maximun number + *------------------------------------------------------------------------------ + */ + +/*!< max number of PMKID cache 16(default) : The Max PMKID cache */ +#define CFG_MAX_PMKID_CACHE 16 + +/*------------------------------------------------------------------------------ + * Auto Channel Selection maximun channel number + *------------------------------------------------------------------------------ + */ +#define MAX_CHN_NUM \ + 39 /* ARRAY_SIZE(mtk_5ghz_channels) + ARRAY_SIZE(mtk_2ghz_channels) */ +#define MAX_2G_BAND_CHN_NUM 14 +#define MAX_5G_BAND_CHN_NUM (MAX_CHN_NUM - \ + MAX_2G_BAND_CHN_NUM) + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Ad-Hoc + *------------------------------------------------------------------------------ + */ +#define CFG_INIT_ADHOC_FREQ (2462000) +#define CFG_INIT_ADHOC_MODE AD_HOC_MODE_MIXED_11BG +#define CFG_INIT_ADHOC_BEACON_INTERVAL (100) +#define CFG_INIT_ADHOC_ATIM_WINDOW (0) + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Maximum Scan SSID number + *------------------------------------------------------------------------------ + */ +#define CFG_SCAN_SSID_MAX_NUM (4) +#define CFG_SCAN_SSID_MATCH_MAX_NUM (16) + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Load Setup Default + *------------------------------------------------------------------------------ + */ + +/*------------------------------------------------------------------------------ + * Flags for enable 802.11A Band setting + *------------------------------------------------------------------------------ + */ + +/*------------------------------------------------------------------------------ + * Flags and Parameters for Interrupt Process + *------------------------------------------------------------------------------ + */ +#define CFG_IST_LOOP_COUNT HIF_IST_LOOP_COUNT + +#define CFG_INT_WRITE_CLEAR 0 + +/* 2 Flags for Driver Debug Options */ +/*------------------------------------------------------------------------------ + * Flags of TX Debug Option. NOTE(Kevin): Confirm with SA before modifying + * following flags. + *------------------------------------------------------------------------------ + */ + +/*!< 1: Debug statistics usage of MGMT Buffer */ +/* 0: Disable */ +#define CFG_DBG_MGT_BUF 1 + +#define CFG_HIF_STATISTICS 0 + +#define CFG_HIF_RX_STARVATION_WARNING 0 + +#define CFG_RX_PKTS_DUMP 0 + +#define CFG_ASSERT_DUMP 1 +/*------------------------------------------------------------------------------ + * Flags of Firmware Download Option. + *------------------------------------------------------------------------------ + */ +#define CFG_ENABLE_FW_DOWNLOAD 1 + +#define CFG_ENABLE_FW_DOWNLOAD_ACK 1 + +/*------------------------------------------------------------------------------ + * Flags of Bluetooth-over-WiFi (BT 3.0 + HS) support + *------------------------------------------------------------------------------ + */ + +/*------------------------------------------------------------------------------ + * Flags of Wi-Fi Direct support + *------------------------------------------------------------------------------ + */ +/*------------------------------------------------------------------------------ + * Support reporting all BSS networks to cfg80211 kernel when scan + * request is from P2P interface + * Originally only P2P networks will be reported when scan request is from p2p0 + *------------------------------------------------------------------------------ + */ +#ifndef CFG_P2P_SCAN_REPORT_ALL_BSS +#define CFG_P2P_SCAN_REPORT_ALL_BSS 0 +#endif + +/*------------------------------------------------------------------------------ + * Flags for GTK rekey offload + *------------------------------------------------------------------------------ + */ + +#ifdef CONFIG_X86 +#define CFG_ENABLE_WIFI_DIRECT 1 +#define CFG_SUPPORT_802_11W 1 +#define CONFIG_SUPPORT_GTK_REKEY 1 +#else +#define CFG_ENABLE_WIFI_DIRECT 1 +#define CFG_SUPPORT_802_11W 1 /*!< 0(default): Disable 802.11W */ +#define CONFIG_SUPPORT_GTK_REKEY 1 +#endif + +#define CFG_SUPPORT_PERSISTENT_GROUP 0 + +#define CFG_TEST_WIFI_DIRECT_GO 0 + +#define CFG_TEST_ANDROID_DIRECT_GO 0 + +#define CFG_UNITEST_P2P 0 + +/* + * Enable cfg80211 option after Android 2.2(Froyo) is suggested, + * cfg80211 on linux 2.6.29 is not mature yet + */ +#define CFG_ENABLE_WIFI_DIRECT_CFG_80211 1 + +#define CFG_SUPPORT_HOTSPOT_OPTIMIZATION 0 +#define CFG_HOTSPOT_OPTIMIZATION_BEACON_INTERVAL 300 +#define CFG_HOTSPOT_OPTIMIZATION_DTIM 1 +#define CFG_AUTO_CHANNEL_SEL_SUPPORT 1 + +/*------------------------------------------------------------------------------ + * Configuration Flags (Linux Only) + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_EXT_CONFIG 0 + +/*------------------------------------------------------------------------------ + * Statistics Buffering Mechanism + *------------------------------------------------------------------------------ + */ +#if CFG_SUPPORT_PERFORMANCE_TEST +#define CFG_ENABLE_STATISTICS_BUFFERING 1 +#else +#define CFG_ENABLE_STATISTICS_BUFFERING 0 +#endif +#define CFG_STATISTICS_VALID_CYCLE 2000 +#define CFG_LINK_QUALITY_VALID_PERIOD 500 + +/*------------------------------------------------------------------------------ + * Migration Option + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_ADHOC 1 +#define CFG_SUPPORT_AAA 1 + +#define CFG_SUPPORT_BCM 0 +#define CFG_SUPPORT_BCM_BWCS 0 +#define CFG_SUPPORT_BCM_BWCS_DEBUG 0 + +#define CFG_SUPPORT_RDD_TEST_MODE 0 + +#define CFG_SUPPORT_PWR_MGT 1 + +#define CFG_ENABLE_HOTSPOT_PRIVACY_CHECK 1 + +// WARNINNG !!! + +#define CFG_MGMT_FRAME_HANDLING 1 + +#define CFG_MGMT_HW_ACCESS_REPLACEMENT 0 + +#if CFG_SUPPORT_PERFORMANCE_TEST + +#else + +#endif + +#define CFG_SUPPORT_AIS_5GHZ 1 +#define CFG_SUPPORT_BEACON_CHANGE_DETECTION 0 + +/*------------------------------------------------------------------------------ + * Option for NVRAM and Version Checking + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_NVRAM 1 +#define CFG_NVRAM_EXISTENCE_CHECK 1 +#define CFG_SW_NVRAM_VERSION_CHECK 1 +#define CFG_SUPPORT_NIC_CAPABILITY 1 + +/*------------------------------------------------------------------------------ + * CONFIG_TITLE : Stress Test Option + * OWNER : Puff Wen + * Description : For stress test only. DO NOT enable it while normal operation + *------------------------------------------------------------------------------ + */ +#define CFG_STRESS_TEST_SUPPORT 0 + +/*------------------------------------------------------------------------------ + * Flags for LINT + *------------------------------------------------------------------------------ + */ +#define LINT_SAVE_AND_DISABLE /*lint -save -e**/ + +#define LINT_RESTORE /*lint -restore */ + +#define LINT_EXT_HEADER_BEGIN LINT_SAVE_AND_DISABLE + +#define LINT_EXT_HEADER_END LINT_RESTORE + +/*------------------------------------------------------------------------------ + * Flags of Features + *------------------------------------------------------------------------------ + */ + +#define CFG_SUPPORT_PNO 1 +#define CFG_SUPPORT_TDLS 1 + +#define CFG_SUPPORT_QOS 1 /* Enable/disable QoS TX, AMPDU */ +#define CFG_SUPPORT_AMPDU_TX 1 +#define CFG_SUPPORT_AMPDU_RX 1 +#define CFG_SUPPORT_TSPEC \ + 0 /* Enable/disable TS-related Action frames handling */ +#define CFG_SUPPORT_UAPSD 0 // 1 +#define CFG_SUPPORT_UL_PSMP 0 + +#ifndef CFG_SUPPORT_SAME_BSS_REASSOC +#define CFG_SUPPORT_SAME_BSS_REASSOC 0 /* Re-assoc to the same BSS */ +#endif + +#ifndef CFG_SUPPORT_ROAMING +#define CFG_SUPPORT_ROAMING 0 // 1 /\* Roaming System \*\/ +#endif +#if (CFG_SUPPORT_ROAMING == 1) + +/* Roaming feature: skip roaming when only one ESSID AP + * Need Android background scan + * if no roaming event occurred + * to trigger roaming scan + * after skip roaming in one ESSID AP case + */ + +#define CFG_SUPPORT_802_11K 1 +#define CFG_SUPPORT_802_11V 1 +#define CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT 1 + +#define CFG_SUPPORT_ROAMING_SKIP_ONE_AP 1 +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP +#define CFG_MAX_NUM_ROAM_BSS_LIST 64 +#endif +#else +#define CFG_SUPPORT_ROAMING_SKIP_ONE_AP 0 + +#define CFG_SUPPORT_802_11K 0 + +#ifndef CFG_SUPPORT_802_11V +#define CFG_SUPPORT_802_11V 0 +#endif + +#define CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT 0 + +#endif + +#define CFG_SUPPORT_SWCR 1 + +#define CFG_SUPPORT_ANTI_PIRACY 1 + +#define CFG_SUPPORT_OSC_SETTING 1 + +#define CFG_SUPPORT_P2P_RSSI_QUERY 0 + +#define CFG_SHOW_MACADDR_SOURCE 1 + +#define CFG_SUPPORT_802_11V_TIMING_MEASUREMENT 0 +#if (CFG_SUPPORT_802_11V_TIMING_MEASUREMENT == 1) && (CFG_SUPPORT_802_11V == 0) +#error \ + "CFG_SUPPORT_802_11V should be 1 once CFG_SUPPORT_802_11V_TIMING_MEASUREMENT equals to 1" +#endif +#if (CFG_SUPPORT_802_11V == 0) +#define WNM_UNIT_TEST 0 +#endif + +#define CFG_DRIVER_COMPOSE_ASSOC_REQ 1 +#define CFG_SUPPORT_802_11AC 1 +#define CFG_STRICT_CHECK_CAPINFO_PRIVACY 0 + +#define CFG_SUPPORT_WFD 1 +#define CFG_SUPPORT_WFD_COMPOSE_IE 1 + +#define CFG_SUPPORT_HOTSPOT_WPS_MANAGER 1 +#define CFG_SUPPORT_NFC_BEAM_PLUS 1 + +/* Refer to CONFIG_MTK_STAGE_SCAN */ +#define CFG_MTK_STAGE_SCAN 1 + +#define CFG_SUPPORT_MTK_SYNERGY 1 + +#define CFG_SUPPORT_PWR_LIMIT_COUNTRY 1 + +#define CFG_FIX_2_TX_PORT 0 + +/*------------------------------------------------------------------------------ + * Flags of bus error tolerance + *------------------------------------------------------------------------------ + */ +#define CFG_FORCE_RESET_UNDER_BUS_ERROR 0 + +/*------------------------------------------------------------------------------ + * Build Date Code Integration + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_BUILD_DATE_CODE 0 + +/*------------------------------------------------------------------------------ + * Flags of SDIO test pattern support + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_SDIO_READ_WRITE_PATTERN 0 + +/*------------------------------------------------------------------------------ + * Flags of AIS passive scan support + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_AIS_PASSIVE_SCAN 0 + +/*------------------------------------------------------------------------------ + * Flags of Workaround + *------------------------------------------------------------------------------ + */ +#define CFG_ENABLE_READ_EXTRA_4_BYTES 1 + +/* Temp workaround for 11ac certification */ +#define CFG_WORKAROUND_OPMODE_CONFLICT_OPINFO 1 + +/*------------------------------------------------------------------------------ + * Flags of 5G NVRAM SUPPORT + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_NVRAM_5G 1 + +/*------------------------------------------------------------------------------ + * Flags of Packet Lifetime Profiling Mechanism + *------------------------------------------------------------------------------ + */ +#define CFG_ENABLE_PKT_LIFETIME_PROFILE 1 +#define CFG_PRINT_PKT_LIFETIME_PROFILE 0 + +#define CFG_ENABLE_PER_STA_STATISTICS 1 + +/*------------------------------------------------------------------------------ + * Flags for prepare the FW compile flag + *------------------------------------------------------------------------------ + */ +#define COMPILE_FLAG0_GET_STA_LINK_STATUS (1 << 0) +#define COMPILE_FLAG0_WFD_ENHANCEMENT_PROTECT (1 << 1) + +/*------------------------------------------------------------------------------ + * Flags for prepare the FW feature flag + *------------------------------------------------------------------------------ + */ +#define FEATURE_FLAG0_NIC_CAPABILITY_V2 (1 << 0) + +/*------------------------------------------------------------------------------ + * Flags of Batch Scan SUPPORT + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_BATCH_SCAN 1 +#define CFG_BATCH_MAX_MSCAN 2 + +/*------------------------------------------------------------------------------ + * Flags of Sniffer SUPPORT + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_SNIFFER 1 + +#ifndef WLAN_INCLUDE_PROC +#define WLAN_INCLUDE_PROC 0 +#endif + +/*------------------------------------------------------------------------------ + * Flags of Sniffer SUPPORT + *------------------------------------------------------------------------------ + */ +#define CFG_DUAL_P2PLIKE_INTERFACE 1 + +#define RUNNING_P2P_MODE 0 +#define RUNNING_AP_MODE 1 +#define RUNNING_DUAL_AP_MODE 2 +#define RUNNING_P2P_AP_MODE 3 +#define RUNNING_P2P_MODE_NUM 4 + +#define CFG_DRIVER_INITIAL_RUNNING_MODE RUNNING_P2P_AP_MODE +/*------------------------------------------------------------------------------ + * Flags of MSP SUPPORT + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_MSP 1 + +/*------------------------------------------------------------------------------ + * Flags of Drop Packet Replay SUPPORT + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_REPLAY_DETECTION 1 + +/*------------------------------------------------------------------------------ + * Flags of Last Second MCS Tx/Rx Info + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_LAST_SEC_MCS_INFO 1 +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +#define MCS_INFO_SAMPLE_CNT 10 +#endif + +/*------------------------------------------------------------------------------ + * Flags of driver fw customization + *------------------------------------------------------------------------------ + */ + +#define CFG_SUPPORT_EASY_DEBUG 1 +#define CFG_SUPPORT_FW_DBG_LEVEL_CTRL 1 + +/*------------------------------------------------------------------------------ + * Flags of driver to send only one cfg to fw + *------------------------------------------------------------------------------ + */ + +#ifndef CFG_SUPPORT_SEND_ONLY_ONE_CFG +#define CFG_SUPPORT_SEND_ONLY_ONE_CFG 1 +#endif + +/*------------------------------------------------------------------------------ + * Flags of driver delay calibration atfer efuse buffer mode CMD + *------------------------------------------------------------------------------ + */ + +#define CFG_EFUSE_BUFFER_MODE_DELAY_CAL 1 + +/*------------------------------------------------------------------------------ + * Flags for E1 IC workaround (SPI clock divided by 2) + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_PMIC_SPI_CLOCK_SWITCH 0 + +/*------------------------------------------------------------------------------ + * Flags of driver EEPROM pages for QA tool + *------------------------------------------------------------------------------ + */ + +#define CFG_EEPROM_PAGE_ACCESS 1 + +/*------------------------------------------------------------------------------ + * Flags for HOST_OFFLOAD + *------------------------------------------------------------------------------ + */ + +#define CFG_SUPPORT_WIFI_HOST_OFFLOAD 1 + +/*------------------------------------------------------------------------------ + * Flags for DBDC Feature + *------------------------------------------------------------------------------ + */ + +#define CFG_SUPPORT_DBDC 1 + +/*------------------------------------------------------------------------------ + * Flags for Using TC4 Resource in ROM code stage + *------------------------------------------------------------------------------ + */ + +#define CFG_USE_TC4_RESOURCE_FOR_INIT_CMD 0 + +/*------------------------------------------------------------------------------ + * Flags for Efuse Start and End address report from FW + *------------------------------------------------------------------------------ + */ + +#define CFG_FW_Report_Efuse_Address 1 + +/*------------------------------------------------------------------------------ + * FW name max length + *------------------------------------------------------------------------------ + */ +#define CFG_FW_NAME_MAX_LEN (64) + +/*------------------------------------------------------------------------------ + * Chip low power debug function + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_LOW_POWER_DEBUG 1 + +/*------------------------------------------------------------------------------ + * Support WMT WIFI Path Config + *------------------------------------------------------------------------------ + */ +#define CFG_WMT_WIFI_PATH_SUPPORT 0 + +/*------------------------------------------------------------------------------ + * Support CFG_SISO_SW_DEVELOP + *------------------------------------------------------------------------------ + */ +#define CFG_SISO_SW_DEVELOP 1 + +/*------------------------------------------------------------------------------ + * Support antenna selection + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_ANT_SELECT 1 + +/*------------------------------------------------------------------------------ + * Single Sku + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_SINGLE_SKU 1 +#ifndef CFG_SUPPORT_SINGLE_SKU_LOCAL_DB +#define CFG_SUPPORT_SINGLE_SKU_LOCAL_DB 1 +#endif + +/*------------------------------------------------------------------------------ + * Auto enable SDIO asynchronous interrupt mode + *------------------------------------------------------------------------------ + */ +#define CFG_SDIO_ASYNC_IRQ_AUTO_ENABLE 1 + +/*------------------------------------------------------------------------------ + * Direct Control for RF/PHY/BB/MAC for Manual Configuration via command/api + *------------------------------------------------------------------------------ + */ +#define CFG_SUPPORT_ADVANCE_CONTROL 1 + +/*------------------------------------------------------------------------------ + * Driver pre-allocate total size of memory in one time + *------------------------------------------------------------------------------ + */ +#ifndef CFG_PRE_ALLOCATION_IO_BUFFER +#define CFG_PRE_ALLOCATION_IO_BUFFER 0 +#endif + +/*------------------------------------------------------------------------------ + * Support scan with channels specified + *------------------------------------------------------------------------------ + */ +#ifndef CFG_SCAN_CHANNEL_SPECIFIED +#define CFG_SCAN_CHANNEL_SPECIFIED 1 +#endif + +/*------------------------------------------------------------------------------ + * RSSI Path Compensation Support + *------------------------------------------------------------------------------ + */ +#ifndef CFG_SUPPORT_RSSI_COMP +#define CFG_SUPPORT_RSSI_COMP 1 +#endif + +/*------------------------------------------------------------------------------ + * Support EFUSE / EEPROM Auto Detect + *------------------------------------------------------------------------------ + */ +#ifndef CFG_EFUSE_AUTO_MODE_SUPPORT +#define CFG_EFUSE_AUTO_MODE_SUPPORT 1 +#endif + +/*------------------------------------------------------------------------------ + * Support WPA3-R3 H2E + *------------------------------------------------------------------------------ + */ +#ifndef CFG_SUPPORT_H2E +#define CFG_SUPPORT_H2E 1 +#endif + +/*------------------------------------------------------------------------------ + * Support DHCP renew offload + *------------------------------------------------------------------------------ + */ +#ifndef CFG_STR_DHCP_RENEW_OFFLOAD +#define CFG_STR_DHCP_RENEW_OFFLOAD 0 +#endif + +/*------------------------------------------------------------------------------ + * Support Single RX chain setting + *------------------------------------------------------------------------------ + */ +#ifndef CFG_RX_SINGLE_CHAIN_SUPPORT +#define CFG_RX_SINGLE_CHAIN_SUPPORT 0 +#endif + +#define CFG_SUPPORT_AAA_CHECK_NO_SSID 1 +#ifndef CFG_SUPPORT_PER_BSS_FILTER +#define CFG_SUPPORT_PER_BSS_FILTER 1 +#endif + +#define CFG_SUPPORT_PROBE_REQ_REPORT 1 + +#ifndef CFG_KEY_ERROR_STATISTIC_RECOVERY +#define CFG_KEY_ERROR_STATISTIC_RECOVERY 0 +#endif + +#ifndef CFG_IOCTL_WAIT_FOR_COMPLETION_TIMEOUT +#define CFG_IOCTL_WAIT_FOR_COMPLETION_TIMEOUT 0 +#endif + +#ifndef CFG_RESET_DUE_TO_REG_NETDEV_FAIL +#define CFG_RESET_DUE_TO_REG_NETDEV_FAIL 0 +#endif + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/debug.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/debug.h new file mode 100644 index 00000000000000..69c034f1932072 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/debug.h @@ -0,0 +1,360 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file debug.h + * \brief Definition of SW debugging level. + * + * In this file, it describes the definition of various SW debugging levels + * and assert functions. + */ + +#ifndef _DEBUG_H +#define _DEBUG_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +#ifndef BUILD_QA_DBG +#define BUILD_QA_DBG 0 +#endif + +#define DBG_DISABLE_ALL_LOG 0 + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "gl_typedef.h" + +extern u8 aucDebugModule[]; + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* Define debug category (class): + * (1) ERROR (2) WARN (3) STATE (4) EVENT (5) TRACE (6) INFO (7) LOUD (8) TEMP + */ +#define DBG_CLASS_ERROR BIT(0) +#define DBG_CLASS_WARN BIT(1) +#define DBG_CLASS_STATE BIT(2) +#define DBG_CLASS_EVENT BIT(3) +#define DBG_CLASS_TRACE BIT(4) +#define DBG_CLASS_INFO BIT(5) +#define DBG_CLASS_LOUD BIT(6) +#define DBG_CLASS_TEMP BIT(7) +#define DBG_CLASS_MASK BITS(0, 7) + +#define DBG_PRINTF_64BIT_DEC "lld" + +#define DBG_ALL_MODULE_IDX 0xFFFFFFFF +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* Define debug module index */ +typedef enum _ENUM_DBG_MODULE_T { + DBG_INIT_IDX = 0, + /* 0x00 */ /* For driver initial */ + DBG_HAL_IDX, + /* 0x01 */ /* For HAL(HW) Layer */ + DBG_INTR_IDX, + /* 0x02 */ /* For Interrupt */ + DBG_REQ_IDX, /* 0x03 */ + DBG_TX_IDX, /* 0x04 */ + DBG_RX_IDX, /* 0x05 */ + DBG_RFTEST_IDX, + /* 0x06 */ /* For RF test mode */ + DBG_EMU_IDX, + /* 0x07 */ /* Developer specific */ + DBG_SW1_IDX, + /* 0x08 */ /* Developer specific */ + DBG_SW2_IDX, + /* 0x09 */ /* Developer specific */ + DBG_SW3_IDX, + /* 0x0A */ /* Developer specific */ + DBG_SW4_IDX, + /* 0x0B */ /* Developer specific */ + DBG_HEM_IDX, + /* 0x0C */ /* HEM */ + DBG_AIS_IDX, + /* 0x0D */ /* AIS */ + DBG_RLM_IDX, + /* 0x0E */ /* RLM */ + DBG_MEM_IDX, + /* 0x0F */ /* RLM */ + DBG_CNM_IDX, + /* 0x10 */ /* CNM */ + DBG_RSN_IDX, + /* 0x11 */ /* RSN */ + DBG_BSS_IDX, + /* 0x12 */ /* BSS */ + DBG_SCN_IDX, + /* 0x13 */ /* SCN */ + DBG_SAA_IDX, + /* 0x14 */ /* SAA */ + DBG_AAA_IDX, + /* 0x15 */ /* AAA */ + DBG_P2P_IDX, + /* 0x16 */ /* P2P */ + DBG_QM_IDX, + /* 0x17 */ /* QUE_MGT */ + DBG_SEC_IDX, + /* 0x18 */ /* SEC */ + DBG_BOW_IDX, + /* 0x19 */ /* BOW */ + DBG_WAPI_IDX, + /* 0x1A */ /* WAPI */ + DBG_ROAMING_IDX, + /* 0x1B */ /* ROAMING */ + DBG_TDLS_IDX, + /* 0x1C */ /* TDLS */ /* CFG_SUPPORT_TDLS */ + DBG_PF_IDX, + /* 0x1D */ /* PF */ + DBG_OID_IDX, + DBG_NIC_IDX, +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + DBG_HIF_WMM_ENHANCE_IDX, +#endif + DBG_WNM_IDX, + /* 0x20 */ /* WNM */ + DBG_MODULE_NUM /* Notice the XLOG check */ +} ENUM_DBG_MODULE_T; +typedef enum _ENUM_DBG_ASSERT_CTRL_LEVEL_T { + DBG_ASSERT_CTRL_LEVEL_ERROR, + DBG_ASSERT_CTRL_LEVEL_WARN, + DBG_ASSERT_CTRL_LEVEL_LITE +} ENUM_DBG_ASSERT_LEVEL_CTRL_T, +*P_ENUM_DBG_ASSERT_LEVEL_CTRL_T; +typedef enum _ENUM_DBG_ASSERT_PATH_T { + DBG_ASSERT_PATH_WIFI, + DBG_ASSERT_PATH_WMT +} ENUM_DBG_ASSERT_PATH_T, +*P_ENUM_DBG_ASSERT_PATH_T; + +#define DBG_ASSERT_PATH_DEFAULT DBG_ASSERT_PATH_WIFI +#define DBG_ASSERT_CTRL_LEVEL_DEFAULT DBG_ASSERT_CTRL_LEVEL_ERROR +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/* Debug print format string for the OS system time */ +#define OS_SYSTIME_DBG_FORMAT "0x%08x" +/* Debug print argument for the OS system time */ +#define OS_SYSTIME_DBG_ARGUMENT(systime) (systime) +/* Debug print format string for the MAC Address */ +#define MACSTR "%pM" +/* Debug print argument for the MAC Address */ +#define MAC2STR(a) a +/* Debug print format string for the IPv4 Address */ +#define IPV4STR "%pI4" +/* Debug print argument for the IPv4 Address */ +#define IPV4TOSTR(a) a +/* Debug print format string for the MAC Address */ +#define IPV6STR "%pI6" +/* Debug print argument for the MAC Address */ +#define IPV6TOSTR(a) a +/* The pre-defined format to dump the value of a varaible with its name shown. + */ +#define DUMPVAR(variable, format) (#variable " = " format "\n", \ + variable) +/* The pre-defined format to dump the MAC type value with its name shown. */ +#define DUMPMACADDR(addr) (#addr " = " MACSTR "\n", \ + MAC2STR(addr)) +/* Debug print format string for the floating point */ +#define FPSTR "%u.%u" +/* Debug print argument for the floating point */ +#define DIV2INT(_dividend, \ + _divisor) ((_divisor) ? (_dividend) / \ + (_divisor) : 0) +#define DIV2DEC(_dividend, _divisor) \ + ((_divisor) ? (((_dividend) * 100) / (_divisor)) % 100 : 0) +/* Basiclly, we just do renaming of KAL functions although they should + * be defined as "Nothing to do" if DBG=0. But in some compiler, the macro + * syntax does not support #define LOG_FUNC(x,...) + * + * A caller shall not invoke these three macros when DBG=0. + */ +#define LOG_FUNC kalPrint +/* If __FUNCTION__ is already defined by compiler, we just use it. */ +#define DEBUGFUNC(_Func) +/* Disabled due to AOSP + *#if defined(__FUNCTION__) + *#define DEBUGFUNC(_Func) + *#else + * #define DEBUGFUNC(_Func) static const char __FUNCTION__[] = _Func; + *#endif + */ +#if DBG_DISABLE_ALL_LOG +#define DBGLOG(_Module, _Class, _Fmt, ...) +#define DBGLOG_RATELIMIT(_Module, _Class, _Fmt, ...) +#define TOOL_PRINTLOG(_Module, _Class, _Fmt, ...) +#define DBGLOG_MEM8(_Module, _Class, _StartAddr, _Length, ...) +#define DBGLOG_MEM32(_Module, _Class, _StartAddr, _Length, ...) +#else +#define DBGLOG(_Module, _Class, _Fmt, ...) \ + do { \ + if ((aucDebugModule[DBG_ ## _Module ## _IDX] & \ + DBG_CLASS_ ## _Class) == 0) \ + break; \ + LOG_FUNC("[%u]%s:(" #_Module " " #_Class ") " _Fmt, \ + KAL_GET_CURRENT_THREAD_ID(), __func__, \ + ## __VA_ARGS__); \ + } while (0) +#define DBGLOG_RATELIMIT(_Module, _Class, _Fmt, ...) \ + do { \ + if ((aucDebugModule[DBG_ ## _Module ## _IDX] & \ + DBG_CLASS_ ## _Class) == 0) \ + break; \ + if (kalPrintRateCtrl()) \ + break; \ + LOG_FUNC("[%u]%s:(" #_Module " " #_Class ") " _Fmt, \ + KAL_GET_CURRENT_THREAD_ID(), __func__, \ + ## __VA_ARGS__); \ + } while (0) +#define TOOL_PRINTLOG(_Module, _Class, _Fmt, ...) \ + do { \ + if ((aucDebugModule[DBG_ ## _Module ## _IDX] & \ + DBG_CLASS_ ## _Class) == 0) \ + break; \ + LOG_FUNC(_Fmt, ## __VA_ARGS__); \ + } while (0) +#define DBGLOG_MEM8(_Module, _Class, _StartAddr, _Length) \ + { \ + if (aucDebugModule[DBG_ ## _Module ## _IDX] & \ + DBG_CLASS_ ## _Class) { \ + LOG_FUNC("%s:(" #_Module " " #_Class ")\n", __func__); \ + dumpMemory8((u8 *)(_StartAddr), (u32)(_Length)); \ + } \ + } +#define DBGLOG_MEM32(_Module, _Class, _StartAddr, _Length) \ + { \ + if (aucDebugModule[DBG_ ## _Module ## _IDX] & \ + DBG_CLASS_ ## _Class) { \ + LOG_FUNC("%s:(" #_Module " " #_Class ")\n", __func__); \ + dumpMemory32((u32 *)(_StartAddr), (u32)(_Length)); \ + } \ + } +#endif +#define DISP_STRING(_str) _str +#undef ASSERT +#undef ASSERT_REPORT +#if (BUILD_QA_DBG || DBG) +#ifdef _lint +#define ASSERT(_exp) \ + { \ + if (!(_exp)) { \ + do { \ + } while (1); \ + } \ + } +#define ASSERT_REPORT(_exp, _fmt) \ + { \ + LOG_FUNC("Assertion failed: %s:%d (%s)\n", __FILE__, __LINE__, \ + #_exp); \ + LOG_FUNC _fmt; \ + if (!(_exp)) { \ + do { \ + } while (1); \ + } \ + } +#elif defined(WINDOWS_CE) +#define UNICODE_TEXT(_msg) TEXT(_msg) +#define ASSERT(_exp) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + TCHAR rUbuf[256]; \ + kalBreakPoint(); \ + _stprintf(rUbuf, TEXT("Assertion failed: %s:%d %s\n"), \ + UNICODE_TEXT(__FILE__), __LINE__, \ + UNICODE_TEXT(#_exp)); \ + MessageBox(NULL, rUbuf, TEXT("ASSERT!"), MB_OK); \ + } \ + } +#define ASSERT_REPORT(_exp, _fmt) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + TCHAR rUbuf[256]; \ + kalBreakPoint(); \ + _stprintf(rUbuf, TEXT("Assertion failed: %s:%d %s\n"), \ + UNICODE_TEXT(__FILE__), __LINE__, \ + UNICODE_TEXT(#_exp)); \ + MessageBox(NULL, rUbuf, TEXT("ASSERT!"), MB_OK); \ + } \ + } +#else +#define ASSERT(_exp) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + LOG_FUNC("Assertion failed: %s:%d (%s)\n", __FILE__, \ + __LINE__, #_exp); \ + kalBreakPoint(); \ + } \ + } +#define ASSERT_REPORT(_exp, _fmt) \ + { \ + if (!(_exp) && !fgIsBusAccessFailed) { \ + LOG_FUNC("Assertion failed: %s:%d (%s)\n", __FILE__, \ + __LINE__, #_exp); \ + LOG_FUNC _fmt; \ + kalBreakPoint(); \ + } \ + } +#endif +#else +#define ASSERT(_exp) +#define ASSERT_REPORT(_exp, _fmt) +#endif +/* LOG function for print to buffer */ +/* If buffer pointer is NULL, redirect to normal DBGLOG */ +#define LOGBUF(_pucBuf, _maxLen, _curLen, _Fmt, ...) \ + do { \ + if (_pucBuf) \ + (_curLen) += kalScnprintf((_pucBuf) + (_curLen), \ + (_maxLen) - (_curLen), _Fmt, \ + ## __VA_ARGS__); \ + else \ + DBGLOG(SW4, INFO, _Fmt, ## __VA_ARGS__); \ + } while (0) +/* The following macro is used for debugging packed structures. */ +#ifndef DATA_STRUCT_INSPECTING_ASSERT +#define DATA_STRUCT_INSPECTING_ASSERT(expr) \ + { \ + switch (0) { \ + case 0: \ + case (expr): \ + default:; \ + } \ + } +#endif +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void dumpMemory8(IN u8 *pucStartAddr, IN u32 u4Length); +void dumpMemory32(IN u32 *pu4StartAddr, IN u32 u4Length); +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/link.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/link.h new file mode 100644 index 00000000000000..e5670f2b901367 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/link.h @@ -0,0 +1,430 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file link.h + * \brief Definition for simple doubly linked list operations. + * + * In this file we define the simple doubly linked list data structure and + * its operation MACROs and INLINE functions. + */ + +#ifndef _LINK_H +#define _LINK_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "gl_typedef.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* May cause page fault & unalignment issue (data abort) */ +#define INVALID_LINK_POISON1 ((void *)0x00100101) + +/* Used to verify that nonbody uses non-initialized link entries. */ +#define INVALID_LINK_POISON2 ((void *)0x00100201) + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* Simple Doubly Linked List Structures - Entry Part */ +typedef struct _LINK_ENTRY_T { + struct _LINK_ENTRY_T *prNext, *prPrev; +} LINK_ENTRY_T, *P_LINK_ENTRY_T; + +/* Simple Doubly Linked List Structures - List Part */ +typedef struct _LINK_T { + P_LINK_ENTRY_T prNext; + P_LINK_ENTRY_T prPrev; + u32 u4NumElem; +} LINK_T, *P_LINK_T; + +/* Support AP Selection */ +typedef struct _LINK_MGMT_T { + LINK_T rUsingLink; + LINK_T rFreeLink; +} LINK_MGMT_T, *P_LINK_MGMT_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define LINK_INITIALIZE(prLink) \ + do { \ + ((P_LINK_T)(prLink))->prNext = (P_LINK_ENTRY_T)(prLink); \ + ((P_LINK_T)(prLink))->prPrev = (P_LINK_ENTRY_T)(prLink); \ + ((P_LINK_T)(prLink))->u4NumElem = 0; \ + } while (0) + +#define LINK_ENTRY_INITIALIZE(prEntry) \ + do { \ + ((P_LINK_ENTRY_T)(prEntry))->prNext = (P_LINK_ENTRY_T)NULL; \ + ((P_LINK_ENTRY_T)(prEntry))->prPrev = (P_LINK_ENTRY_T)NULL; \ + } while (0) + +#define LINK_ENTRY_INVALID(prEntry) \ + do { \ + ((P_LINK_ENTRY_T)(prEntry))->prNext = \ + (P_LINK_ENTRY_T)INVALID_LINK_POISON1; \ + ((P_LINK_ENTRY_T)(prEntry))->prPrev = \ + (P_LINK_ENTRY_T)INVALID_LINK_POISON2; \ + } while (0) + +/* Support AP Selection */ +#define LINK_MGMT_INIT(prLinkMgmt) \ + do { \ + LINK_INITIALIZE(&((P_LINK_MGMT_T)prLinkMgmt)->rUsingLink); \ + LINK_INITIALIZE(&((P_LINK_MGMT_T)prLinkMgmt)->rFreeLink); \ + } while (0) + +#define LINK_MGMT_GET_ENTRY(prLinkMgmt, prEntry, EntryType, memType) \ + do { \ + LINK_REMOVE_HEAD(&((P_LINK_MGMT_T)prLinkMgmt)->rFreeLink, \ + prEntry, EntryType *); \ + if (!prEntry) \ + prEntry = kalMemAlloc(sizeof(EntryType), memType); \ + if (prEntry) { \ + kalMemZero(prEntry, sizeof(EntryType)); \ + LINK_INSERT_TAIL( \ + &((P_LINK_MGMT_T)prLinkMgmt)->rUsingLink, \ + &prEntry->rLinkEntry); \ + } \ + } while (0) + +#define LINK_MGMT_UNINIT(prLinkMgmt, EntryType, memType) \ + do { \ + EntryType *prEntry = NULL; \ + P_LINK_T prFreeList = &((P_LINK_MGMT_T)prLinkMgmt)->rFreeLink; \ + P_LINK_T prUsingList = \ + &((P_LINK_MGMT_T)prLinkMgmt)->rUsingLink; \ + LINK_REMOVE_HEAD(prFreeList, prEntry, EntryType *); \ + while (prEntry) { \ + kalMemFree(prEntry, memType, sizeof(EntryType)); \ + LINK_REMOVE_HEAD(prFreeList, prEntry, EntryType *); \ + } \ + LINK_REMOVE_HEAD(prUsingList, prEntry, EntryType *); \ + while (prEntry) { \ + kalMemFree(prEntry, memType, sizeof(EntryType)); \ + LINK_REMOVE_HEAD(prUsingList, prEntry, EntryType *); \ + } \ + } while (0) +/* end Support AP Selection */ + +#define LINK_IS_EMPTY(prLink) \ + (((P_LINK_T)(prLink))->prNext == (P_LINK_ENTRY_T)(prLink)) + +/* NOTE: We should do memory zero before any LINK been initiated, so we can + * check if it is valid before parsing the LINK. + */ +#define LINK_IS_INVALID(prLink) \ + (((P_LINK_T)(prLink))->prNext == (P_LINK_ENTRY_T)NULL) + +#define LINK_IS_VALID(prLink) \ + (((P_LINK_T)(prLink))->prNext != (P_LINK_ENTRY_T)NULL) + +#define LINK_ENTRY(ptr, type, member) ENTRY_OF(ptr, type, member) + +/* Insert an entry into a link list's head */ +#define LINK_INSERT_HEAD(prLink, prEntry) \ + { \ + linkAdd(prEntry, prLink); \ + ((prLink)->u4NumElem)++; \ + } + +/* Append an entry into a link list's tail */ +#define LINK_INSERT_TAIL(prLink, prEntry) \ + { \ + linkAddTail(prEntry, prLink); \ + ((prLink)->u4NumElem)++; \ + } + +/* Peek head entry, but keep still in link list */ +#define LINK_PEEK_HEAD(prLink, _type, _member) \ + (LINK_IS_EMPTY(prLink) ? NULL : \ + LINK_ENTRY((prLink)->prNext, _type, _member)) + +/* Peek tail entry, but keep still in link list */ +#define LINK_PEEK_TAIL(prLink, _type, _member) \ + (LINK_IS_EMPTY(prLink) ? NULL : \ + LINK_ENTRY((prLink)->prPrev, _type, _member)) + +/* Get first entry from a link list */ +/* NOTE: We assume the link entry located at the beginning of "prEntry Type", + * so that we can cast the link entry to other data type without doubts. + * And this macro also decrease the total entry count at the same time. + */ +#define LINK_REMOVE_HEAD(prLink, prEntry, _P_TYPE) \ + { \ + ASSERT(prLink); \ + if (LINK_IS_EMPTY(prLink)) { \ + prEntry = (_P_TYPE)NULL; \ + } else { \ + prEntry = (_P_TYPE)(((P_LINK_T)(prLink))->prNext); \ + linkDel((P_LINK_ENTRY_T)prEntry); \ + ((prLink)->u4NumElem)--; \ + } \ + } + +/* Assume the link entry located at the beginning of prEntry Type. + * And also decrease the total entry count. + */ +#define LINK_REMOVE_KNOWN_ENTRY(prLink, prEntry) \ + { \ + ASSERT(prLink); \ + ASSERT(prEntry); \ + linkDel((P_LINK_ENTRY_T)prEntry); \ + ((prLink)->u4NumElem)--; \ + } + +/* Merge prSrcLink to prDstLink and put prSrcLink ahead of prDstLink */ +#define LINK_MERGE_TO_HEAD(prDstLink, prSrcLink) \ + { \ + if (!LINK_IS_EMPTY(prSrcLink)) { \ + linkMergeToHead((P_LINK_T)prDstLink, \ + (P_LINK_T)prSrcLink); \ + (prDstLink)->u4NumElem += (prSrcLink)->u4NumElem; \ + LINK_INITIALIZE(prSrcLink); \ + } \ + } + +/* Merge prSrcLink to prDstLink and put prSrcLink at tail */ +#define LINK_MERGE_TO_TAIL(prDstLink, prSrcLink) \ + { \ + if (!LINK_IS_EMPTY(prSrcLink)) { \ + linkMergeToTail((P_LINK_T)prDstLink, \ + (P_LINK_T)prSrcLink); \ + (prDstLink)->u4NumElem += (prSrcLink)->u4NumElem; \ + LINK_INITIALIZE(prSrcLink); \ + } \ + } + +/* Iterate over a link list */ +#define LINK_FOR_EACH(prEntry, prLink) \ + for (prEntry = (prLink)->prNext; prEntry != (P_LINK_ENTRY_T)(prLink); \ + prEntry = (P_LINK_ENTRY_T)prEntry->prNext) + +/* Iterate over a link list backwards */ +#define LINK_FOR_EACH_PREV(prEntry, prLink) \ + for (prEntry = (prLink)->prPrev; prEntry != (P_LINK_ENTRY_T)(prLink); \ + prEntry = (P_LINK_ENTRY_T)prEntry->prPrev) + +/* Iterate over a link list safe against removal of link entry */ +#define LINK_FOR_EACH_SAFE(prEntry, prNextEntry, prLink) \ + for (prEntry = (prLink)->prNext, prNextEntry = prEntry->prNext; \ + prEntry != (P_LINK_ENTRY_T)(prLink); \ + prEntry = prNextEntry, prNextEntry = prEntry->prNext) + +/* Iterate over a link list of given type */ +#define LINK_FOR_EACH_ENTRY(prObj, prLink, rMember, _TYPE) \ + for (prObj = LINK_ENTRY((prLink)->prNext, _TYPE, rMember); \ + &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ + prObj = LINK_ENTRY(prObj->rMember.prNext, _TYPE, rMember)) + +/* Iterate backwards over a link list of given type */ +#define LINK_FOR_EACH_ENTRY_PREV(prObj, prLink, rMember, _TYPE) \ + for (prObj = LINK_ENTRY((prLink)->prPrev, _TYPE, rMember); \ + &prObj->rMember != (P_LINK_ENTRY_T)(prLink); \ + prObj = LINK_ENTRY(prObj->rMember.prPrev, _TYPE, rMember)) + +/* Iterate over a link list of given type safe against removal of link entry */ +#define LINK_FOR_EACH_ENTRY_SAFE(prObj, prNextObj, prLink, rMember, _TYPE) \ + for (prObj = LINK_ENTRY((prLink)->prNext, _TYPE, rMember), \ + prNextObj = LINK_ENTRY(prObj->rMember.prNext, _TYPE, rMember); \ + &prObj->rMember != (P_LINK_ENTRY_T)(prLink); prObj = prNextObj, \ + prNextObj = LINK_ENTRY(prNextObj->rMember.prNext, _TYPE, rMember)) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is only for internal link list manipulation. + * + * \param[in] prNew Pointer of new link head + * \param[in] prPrev Pointer of previous link head + * \param[in] prNext Pointer of next link head + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void __linkAdd(IN P_LINK_ENTRY_T prNew, + IN P_LINK_ENTRY_T prPrev, + IN P_LINK_ENTRY_T prNext) +{ + prNext->prPrev = prNew; + prNew->prNext = prNext; + prNew->prPrev = prPrev; + prPrev->prNext = prNew; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will add a new entry after the specified link head. + * + * \param[in] prNew New entry to be added + * \param[in] prHead Specified link head to add it after + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void linkAdd(IN P_LINK_ENTRY_T prNew, IN P_LINK_T prLink) +{ + __linkAdd(prNew, (P_LINK_ENTRY_T)prLink, prLink->prNext); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will add a new entry before the specified link head. + * + * \param[in] prNew New entry to be added + * \param[in] prHead Specified link head to add it before + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void linkAddTail(IN P_LINK_ENTRY_T prNew, + IN P_LINK_T prLink) +{ + __linkAdd(prNew, prLink->prPrev, (P_LINK_ENTRY_T)prLink); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is only for internal link list manipulation. + * + * \param[in] prPrev Pointer of previous link head + * \param[in] prNext Pointer of next link head + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void __linkDel(IN P_LINK_ENTRY_T prPrev, + IN P_LINK_ENTRY_T prNext) +{ + prNext->prPrev = prPrev; + prPrev->prNext = prNext; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will delete a specified entry from link list. + * NOTE: the entry is in an initial state. + * + * \param prEntry Specified link head(entry) + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void linkDel(IN P_LINK_ENTRY_T prEntry) +{ + __linkDel(prEntry->prPrev, prEntry->prNext); + + LINK_ENTRY_INITIALIZE(prEntry); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will delete a specified entry from link list and then + * add it after the specified link head. + * + * \param[in] prEntry Specified link head(entry) + * \param[in] prOtherHead Another link head to add it after + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void linkMove(IN P_LINK_ENTRY_T prEntry, + IN P_LINK_T prLink) +{ + __linkDel(prEntry->prPrev, prEntry->prNext); + linkAdd(prEntry, prLink); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will delete a specified entry from link list and then + * add it before the specified link head. + * + * \param[in] prEntry Specified link head(entry) + * \param[in] prOtherHead Another link head to add it before + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void linkMoveTail(IN P_LINK_ENTRY_T prEntry, + IN P_LINK_T prLink) +{ + __linkDel(prEntry->prPrev, prEntry->prNext); + linkAddTail(prEntry, prLink); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will merge source link to the tail of destination link. + * + * \param[in] prDst destination link + * \param[in] prSrc source link + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void linkMergeToTail(P_LINK_T prDst, P_LINK_T prSrc) +{ + prSrc->prNext->prPrev = prDst->prPrev; + prSrc->prPrev->prNext = (P_LINK_ENTRY_T)prDst; + prDst->prPrev->prNext = prSrc->prNext; + prDst->prPrev = prSrc->prPrev; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will merge source link to the head of destination link. + * + * \param[in] prDst destination link + * \param[in] prSrc source link + * + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void linkMergeToHead(P_LINK_T prDst, P_LINK_T prSrc) +{ + prSrc->prNext->prPrev = (P_LINK_ENTRY_T)prDst; + prSrc->prPrev->prNext = prDst->prNext; + prDst->prNext->prPrev = prSrc->prPrev; + prDst->prNext = prSrc->prNext; +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/aa_fsm.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/aa_fsm.h new file mode 100644 index 00000000000000..9aa7ac700c4f7f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/aa_fsm.h @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file aa_fsm.h + * \brief Declaration of functions and finite state machine for SAA/AAA + * Module. + * + * Declaration of functions and finite state machine for SAA/AAA Module. + */ + +#ifndef _AA_FSM_H +#define _AA_FSM_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* Retry interval for retransmiting authentication-request MMPDU. */ +#define TX_AUTHENTICATION_RETRY_TIMEOUT_TU 100 /* TU. */ + +/* Retry interval for retransmiting association-request MMPDU. */ +#define TX_ASSOCIATION_RETRY_TIMEOUT_TU 100 /* TU. */ + +/* Wait for a response to a transmitted authentication-request MMPDU. */ +#define DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU 512 /* TU. */ + +/* Wait for a response to a transmitted association-request MMPDU. */ +#define DOT11_ASSOCIATION_RESPONSE_TIMEOUT_TU 512 /* TU. */ + +/* Wait for a response to a transmitted SAE authentication MMPDU. */ +/* Default value on 802.11-REVmd-D0.5 */ +#define DOT11_RSNA_SAE_RETRANS_PERIOD_TU 2000 + +/* The maximum time to wait for JOIN process complete. */ +#define JOIN_FAILURE_TIMEOUT_BEACON_INTERVAL \ + 20 /* Beacon Interval, 20 * 100TU = 2 sec. */ + +/* Retry interval for next JOIN request. */ +#define JOIN_RETRY_INTERVAL_SEC 10 /* Seconds */ + +/* Maximum Retry Count for accept a JOIN request. */ +#define JOIN_MAX_RETRY_FAILURE_COUNT 1 /* Times */ + +#define TX_AUTHENTICATION_RESPONSE_TIMEOUT_TU 512 /* TU. */ + +#define TX_ASSOCIATE_TIMEOUT_TU 512 /* TU. */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef enum _ENUM_AA_STATE_T { + AA_STATE_IDLE = 0, + SAA_STATE_SEND_AUTH1, + SAA_STATE_WAIT_AUTH2, + SAA_STATE_SEND_AUTH3, + SAA_STATE_WAIT_AUTH4, + SAA_STATE_SEND_ASSOC1, + SAA_STATE_WAIT_ASSOC2, + AAA_STATE_SEND_AUTH2, + AAA_STATE_SEND_AUTH4, /* We may not use, because P2P GO didn't support + * WEP and 11r */ + AAA_STATE_SEND_ASSOC2, + AA_STATE_RESOURCE, /* A state for debugging the case of out of msg + * buffer. */ + AA_STATE_NUM +} ENUM_AA_STATE_T; + +enum ENUM_AA_SENT_T { + AA_SENT_NONE = 0, + AA_SENT_AUTH1, /* = auth transaction SN */ + AA_SENT_AUTH2, + AA_SENT_AUTH3, + AA_SENT_AUTH4, + AA_SENT_ASSOC1, /* req */ + AA_SENT_ASSOC2, /* resp */ + AA_SENT_RESOURCE, /* A state for debug the case of out of msg buffer */ + AA_SENT_NUM +}; + +typedef enum _ENUM_AA_FRM_TYPE_T { + FRM_DISASSOC = 0, + FRM_DEAUTH +} ENUM_AA_FRM_TYPE_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Routines in saa_fsm.c */ +/*----------------------------------------------------------------------------*/ +void saaFsmSteps(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN ENUM_AA_STATE_T eNextState, + IN P_SW_RFB_T prRetainedSwRfb); + +WLAN_STATUS +saaFsmSendEventJoinComplete(IN P_ADAPTER_T prAdapter, + WLAN_STATUS rJoinStatus, + P_STA_RECORD_T prStaRec, + P_SW_RFB_T prSwRfb); + +void saaFsmRunEventStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +WLAN_STATUS +saaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +void saaFsmRunEventTxReqTimeOut(IN P_ADAPTER_T prAdapter, + IN unsigned long plParamPtr); + +void saaFsmRunEventRxRespTimeOut(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr); + +void saaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS saaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS saaFsmRunEventRxDeauth(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS saaFsmRunEventRxDisassoc(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb); + +void saaFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +void saaChkDeauthfrmParamHandler(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_STA_RECORD_T prStaRec); + +void saaChkDisassocfrmParamHandler(IN P_ADAPTER_T prAdapter, + IN P_WLAN_DISASSOC_FRAME_T prDisassocFrame, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb); + +void saaSendDisconnectMsgHandler(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_BSS_INFO_T prAisBssInfo, + IN ENUM_AA_FRM_TYPE_T eFrmType); + +void saaSendAuthAssoc(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +/*----------------------------------------------------------------------------*/ +/* Routines in aaa_fsm.c */ +/*----------------------------------------------------------------------------*/ +void aaaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS aaaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS +aaaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +void aaaFsmRunEventTxReqTimeOut(IN P_ADAPTER_T prAdapter, IN unsigned long plParamPtr); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/ais_fsm.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/ais_fsm.h new file mode 100644 index 00000000000000..c6737142b13e9f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/ais_fsm.h @@ -0,0 +1,478 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file ais_fsm.h + * \brief Declaration of functions and finite state machine for AIS Module. + * + * Declaration of functions and finite state machine for AIS Module. + */ + +#ifndef _AIS_FSM_H +#define _AIS_FSM_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define AIS_BG_SCAN_INTERVAL_MIN_SEC 2 /* 30 // exponential to 960 */ +#define AIS_BG_SCAN_INTERVAL_MAX_SEC 2 /* 960 // 16min */ +#if CFG_SUPPORT_ROAMING +#define AIS_DELAY_TIME_OF_DISCONNECT_SEC \ + 0 /* 100 Milli-seconds - Immediate indication to reduce inter-SSID \ + * roam time \ + */ +#else +#define AIS_DELAY_TIME_OF_DISCONNECT_SEC 5 /* 10 */ +#endif +#define AIS_IBSS_ALONE_TIMEOUT_SEC 20 /* seconds */ + +#define AIS_BEACON_TIMEOUT_COUNT_ADHOC 30 +#define AIS_BEACON_TIMEOUT_COUNT_INFRA 10 +#define AIS_BEACON_TIMEOUT_GUARD_TIME_SEC 1 /* Second */ + +#define AIS_BEACON_MAX_TIMEOUT_TU 100 +#define AIS_BEACON_MIN_TIMEOUT_TU 5 +#define AIS_BEACON_MAX_TIMEOUT_VALID true +#define AIS_BEACON_MIN_TIMEOUT_VALID true + +#define AIS_BMC_MAX_TIMEOUT_TU 100 +#define AIS_BMC_MIN_TIMEOUT_TU 5 +#define AIS_BMC_MAX_TIMEOUT_VALID true +#define AIS_BMC_MIN_TIMEOUT_VALID true + +#define AIS_JOIN_CH_GRANT_THRESHOLD 10 +#define AIS_JOIN_CH_REQUEST_INTERVAL 6000 + +#ifdef CFG_SUPPORT_ADJUST_JOIN_CH_REQ_INTERVAL +#define AIS_JOIN_CH_REQUEST_MAX_INTERVAL 4000 +#endif + +#define AIS_SCN_DONE_TIMEOUT_SEC 15 /* 15 for 2.4G + 5G */ /* 5 */ + +#define AIS_DEFAULT_INDEX (0) +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef enum _ENUM_AIS_STATE_T { + AIS_STATE_IDLE = 0, + AIS_STATE_SEARCH, + AIS_STATE_SCAN, + AIS_STATE_ONLINE_SCAN, + AIS_STATE_LOOKING_FOR, + AIS_STATE_WAIT_FOR_NEXT_SCAN, + AIS_STATE_REQ_CHANNEL_JOIN, + AIS_STATE_JOIN, + AIS_STATE_JOIN_FAILURE, + AIS_STATE_IBSS_ALONE, + AIS_STATE_IBSS_MERGE, + AIS_STATE_NORMAL_TR, + AIS_STATE_DISCONNECTING, + AIS_STATE_REQ_REMAIN_ON_CHANNEL, + AIS_STATE_REMAIN_ON_CHANNEL, + AIS_STATE_NUM +} ENUM_AIS_STATE_T; + +typedef struct _MSG_AIS_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucReasonOfDisconnect; + u8 fgDelayIndication; +} MSG_AIS_ABORT_T, *P_MSG_AIS_ABORT_T; + +typedef struct _MSG_AIS_IBSS_PEER_FOUND_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucBssIndex; + u8 fgIsMergeIn; /* true: Merge In, false: Merge Out */ + P_STA_RECORD_T prStaRec; +} MSG_AIS_IBSS_PEER_FOUND_T, *P_MSG_AIS_IBSS_PEER_FOUND_T; + +typedef enum _ENUM_AIS_REQUEST_TYPE_T { + AIS_REQUEST_SCAN, + AIS_REQUEST_RECONNECT, + AIS_REQUEST_ROAMING_SEARCH, + AIS_REQUEST_ROAMING_CONNECT, + AIS_REQUEST_REMAIN_ON_CHANNEL, + AIS_REQUEST_NUM +} ENUM_AIS_REQUEST_TYPE_T; + +typedef struct _AIS_REQ_HDR_T { + LINK_ENTRY_T rLinkEntry; + ENUM_AIS_REQUEST_TYPE_T eReqType; +} AIS_REQ_HDR_T, *P_AIS_REQ_HDR_T; + +typedef struct _AIS_REQ_CHNL_INFO { + ENUM_BAND_T eBand; + ENUM_CHNL_EXT_T eSco; + u8 ucChannelNum; + u32 u4DurationMs; + u64 u8Cookie; +} AIS_REQ_CHNL_INFO, *P_AIS_REQ_CHNL_INFO; + +typedef struct _AIS_MGMT_TX_REQ_INFO_T { + u8 fgIsMgmtTxRequested; + P_MSDU_INFO_T prMgmtTxMsdu; + u64 u8Cookie; +} AIS_MGMT_TX_REQ_INFO_T, *P_AIS_MGMT_TX_REQ_INFO_T; + +typedef struct _AIS_FSM_INFO_T { + ENUM_AIS_STATE_T ePreviousState; + ENUM_AIS_STATE_T eCurrentState; + + u8 fgTryScan; + + u8 fgIsInfraChannelFinished; + u8 fgIsChannelRequested; + u8 fgIsChannelGranted; + +#if CFG_SUPPORT_ROAMING + u8 fgIsRoamingScanPending; +#endif + + u8 ucAvailableAuthTypes; /* Used for AUTH_MODE_AUTO_SWITCH */ + + P_BSS_DESC_T prTargetBssDesc; /* For destination */ + + P_STA_RECORD_T prTargetStaRec; /* For JOIN Abort */ + + u32 u4SleepInterval; + + TIMER_T rBeaconLostTimer; + + TIMER_T rBGScanTimer; + + TIMER_T rIbssAloneTimer; + + TIMER_T rIndicationOfDisconnectTimer; + + TIMER_T rJoinTimeoutTimer; + + TIMER_T rChannelTimeoutTimer; + + TIMER_T rScanDoneTimer; + + TIMER_T rDeauthDoneTimer; + + u8 ucSeqNumOfReqMsg; + u8 ucSeqNumOfChReq; + u8 ucSeqNumOfScanReq; + + u32 u4ChGrantedInterval; + + u8 ucConnTrialCount; + + u8 ucScanSSIDNum; + PARAM_SSID_T arScanSSID[SCN_SSID_MAX_NUM]; + + u32 u4ScanIELength; + u8 aucScanIEBuf[MAX_IE_LENGTH]; + +#if CFG_SCAN_CHANNEL_SPECIFIED + u8 ucScanChannelListNum; + RF_CHANNEL_INFO_T arScanChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; +#endif + u8 fgIsScanOidAborted; + + /* Pending Request List */ + LINK_T rPendingReqList; + + /* Join Request Timestamp */ + u32 rJoinReqTime; + + /* for cfg80211 REMAIN_ON_CHANNEL support */ + AIS_REQ_CHNL_INFO rChReqInfo; + + /* Mgmt tx related. */ + AIS_MGMT_TX_REQ_INFO_T rMgmtTxInfo; + + /* Packet filter for AIS module. */ + u32 u4AisPacketFilter; + + /* for roaming target */ + PARAM_SSID_T rRoamingSSID; +} AIS_FSM_INFO_T, *P_AIS_FSM_INFO_T; + +enum WNM_AIS_BSS_TRANSITION { + BSS_TRANSITION_NO_MORE_ACTION, + BSS_TRANSITION_REQ_ROAMING, + BSS_TRANSITION_DISASSOC, + BSS_TRANSITION_MAX_NUM +}; + +typedef struct _MSG_AIS_BSS_TRANSITION_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucToken; + u8 fgNeedResponse; + u8 ucValidityInterval; + enum WNM_AIS_BSS_TRANSITION eTransitionType; + u16 u2CandListLen; + u8 *pucCandList; +} MSG_AIS_BSS_TRANSITION_T, *P_MSG_AIS_BSS_TRANSITION_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define aisChangeMediaState(_prAdapter, _eNewMediaState) \ + (_prAdapter->prAisBssInfo->eConnectionState = (_eNewMediaState)) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void aisInitializeConnectionSettings(IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo); + +void aisFsmInit(IN P_ADAPTER_T prAdapter); + +void aisFsmUninit(IN P_ADAPTER_T prAdapter); + +void aisFsmStateInit_JOIN(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); + +u8 aisFsmStateInit_RetryJOIN(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec); + +void aisFsmStateInit_IBSS_ALONE(IN P_ADAPTER_T prAdapter); + +void aisFsmStateInit_IBSS_MERGE(IN P_ADAPTER_T prAdapter, + P_BSS_DESC_T prBssDesc); + +void aisFsmStateAbort(IN P_ADAPTER_T prAdapter, + u8 ucReasonOfDisconnect, + u8 fgDelayIndication); + +void aisFsmStateAbort_JOIN(IN P_ADAPTER_T prAdapter); + +void aisFsmStateAbort_SCAN(IN P_ADAPTER_T prAdapter); + +void aisFsmStateAbort_NORMAL_TR(IN P_ADAPTER_T prAdapter); + +void aisFsmStateAbort_IBSS(IN P_ADAPTER_T prAdapter); + +void aisFsmSteps(IN P_ADAPTER_T prAdapter, ENUM_AIS_STATE_T eNextState); + +/*----------------------------------------------------------------------------*/ +/* Mailbox Message Handling */ +/*----------------------------------------------------------------------------*/ +void aisFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +void aisFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +void aisFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +enum _ENUM_AIS_STATE_T aisFsmJoinCompleteAction(IN struct _ADAPTER_T *prAdapter, + IN struct _MSG_HDR_T *prMsgHdr); + +void aisFsmRunEventFoundIBSSPeer(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void aisFsmRunEventRemainOnChannel(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void aisFsmRunEventCancelRemainOnChannel(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +/*----------------------------------------------------------------------------*/ +/* Handling for Ad-Hoc Network */ +/*----------------------------------------------------------------------------*/ +void aisFsmCreateIBSS(IN P_ADAPTER_T prAdapter); + +void aisFsmMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +/*----------------------------------------------------------------------------*/ +/* Handling of Incoming Mailbox Message from CNM */ +/*----------------------------------------------------------------------------*/ +void aisFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +/*----------------------------------------------------------------------------*/ +/* Generating Outgoing Mailbox Message to CNM */ +/*----------------------------------------------------------------------------*/ +void aisFsmReleaseCh(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* Event Indication */ +/*----------------------------------------------------------------------------*/ +void aisIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, + ENUM_PARAM_MEDIA_STATE_T eConnectionState, + u8 fgDelayIndication); + +void aisPostponedEventOfDisconnTimeout(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr); + +void aisUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, + P_SW_RFB_T prAssocRspSwRfb); + +void aisUpdateBssInfoForCreateIBSS(IN P_ADAPTER_T prAdapter); + +void aisUpdateBssInfoForMergeIBSS(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec); + +u8 aisValidateProbeReq(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT u32 *pu4ControlFlags); + +WLAN_STATUS +aisFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +/*----------------------------------------------------------------------------*/ +/* Disconnection Handling */ +/*----------------------------------------------------------------------------*/ +void aisFsmDisconnect(IN P_ADAPTER_T prAdapter, IN u8 fgDelayIndication); + +/*----------------------------------------------------------------------------*/ +/* Event Handling */ +/*----------------------------------------------------------------------------*/ +void aisBssBeaconTimeout(IN P_ADAPTER_T prAdapter, IN u8 ucReasonCode); + +void aisBssLinkDown(IN P_ADAPTER_T prAdapter); + +#if CFG_SUPPORT_DBDC_TC6 +u8 aisBssChangeNSS(IN P_ADAPTER_T prAdapter, IN u8 fgDbdcEn); +#endif + +WLAN_STATUS +aisDeauthXmitComplete(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +#if CFG_SUPPORT_ROAMING +void aisFsmRunEventRoamingDiscovery(IN P_ADAPTER_T prAdapter, u32 u4ReqScan); + +ENUM_AIS_STATE_T aisFsmRoamingScanResultsUpdate(IN P_ADAPTER_T prAdapter); + +void aisFsmRoamingDisconnectPrevAP(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prTargetStaRec); +#endif + +#if CFG_SUPPORT_ROAMING || CFG_SUPPORT_SAME_BSS_REASSOC +void aisUpdateBssInfoForRoamingAP(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prAssocRspSwRfb); +#endif + +/*----------------------------------------------------------------------------*/ +/* Timeout Handling */ +/*----------------------------------------------------------------------------*/ +void aisFsmRunEventBGSleepTimeOut(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr); + +void aisFsmBeaconLostTimeOut(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr); + +void aisFsmRunEventIbssAloneTimeOut(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr); + +void aisFsmRunEventJoinTimeout(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr); + +void aisFsmRunEventChannelTimeout(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr); + +void aisFsmRunEventDeauthTimeout(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr); + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +void aisRxMcsCollectionTimeout(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr); +#endif + +/*----------------------------------------------------------------------------*/ +/* OID/IOCTL Handling */ +/*----------------------------------------------------------------------------*/ +void aisFsmScanRequest(IN P_ADAPTER_T prAdapter, + IN P_PARAM_SSID_T prSsid, + IN u8 *pucIe, + IN u32 u4IeLength); + +void aisFsmScanRequestAdv(IN P_ADAPTER_T prAdapter, + IN u8 ucSsidNum, + IN P_PARAM_SSID_T prSsid, + IN u8 ucChannelListNum, + IN P_RF_CHANNEL_INFO_T prChnlInfoList, + IN u8 *pucIe, + IN u32 u4IeLength); + +/*----------------------------------------------------------------------------*/ +/* Internal State Checking */ +/*----------------------------------------------------------------------------*/ +u8 aisFsmIsRequestPending(IN P_ADAPTER_T prAdapter, + IN ENUM_AIS_REQUEST_TYPE_T eReqType, + IN u8 bRemove); + +P_AIS_REQ_HDR_T aisFsmGetNextRequest(IN P_ADAPTER_T prAdapter); + +u8 aisFsmInsertRequest(IN P_ADAPTER_T prAdapter, + IN ENUM_AIS_REQUEST_TYPE_T eReqType); + +void aisFsmFlushRequest(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS +aisFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, + IN P_AIS_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, + IN P_MSDU_INFO_T prMgmtTxMsdu, + IN u64 u8Cookie); + +void aisFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void aisFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb); + +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT +void aisFsmRunEventBssTransition(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); +#endif + +#if CFG_SUPPORT_802_11K +void aisSendNeighborRequest(IN P_ADAPTER_T prAdapter); +#endif + +#if CFG_SUPPORT_802_11K || CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT +void aisResetNeighborApList(IN P_ADAPTER_T prAdapter); + +void aisCollectNeighborAP(IN P_ADAPTER_T prAdapter, + u8 *pucApBuf, + u16 u2ApBufLen, + u8 ucValidInterval); +#endif + +enum _ENUM_AIS_STATE_T aisFsmStateSearchAction(IN struct _ADAPTER_T *prAdapter, + u8 ucPhase); +#if defined(CFG_TEST_MGMT_FSM) && (CFG_TEST_MGMT_FSM != 0) +void aisTest(void); +#endif +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/assoc.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/assoc.h new file mode 100644 index 00000000000000..064cc39d3041af --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/assoc.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file assoc.h + * \brief This file contains the ASSOC REQ/RESP of + * IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. + */ + +#ifndef _ASSOC_H +#define _ASSOC_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Routines in assoc.c */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS assocSendReAssocReqFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec); + +WLAN_STATUS assocCheckTxReAssocReqFrame(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +WLAN_STATUS assocCheckTxReAssocRespFrame(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +WLAN_STATUS +assocCheckRxReAssocRspFrameStatus(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT u16 *pu2StatusCode); + +WLAN_STATUS assocSendDisAssocFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN u16 u2ReasonCode); + +WLAN_STATUS +assocProcessRxDisassocFrame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN u8 aucBSSID[], + OUT u16 *pu2ReasonCode); + +WLAN_STATUS assocProcessRxAssocReqFrame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT u16 *pu2StatusCode); + +WLAN_STATUS assocSendReAssocRespFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec); + +u16 assocBuildCapabilityInfo(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec); + +void assocComposeReAssocReqFrameHeaderAndFF(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN u8 *pucBuffer, + IN u8 aucMACAddress[], + IN OUT u16 *pu2PayloadLen); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/auth.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/auth.h new file mode 100644 index 00000000000000..8ef22b53fa29a3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/auth.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file auth.h + * \brief This file contains the authentication REQ/RESP of + * IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. + */ + +#ifndef _AUTH_H +#define _AUTH_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Routines in auth.c */ +/*----------------------------------------------------------------------------*/ +void authAddIEChallengeText(IN P_ADAPTER_T prAdapter, + IN OUT P_MSDU_INFO_T prMsduInfo); + +#if !CFG_SUPPORT_AAA +WLAN_STATUS authSendAuthFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN u16 u2TransactionSeqNum); +#else +WLAN_STATUS +authSendAuthFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN u8 uBssIndex, + IN P_SW_RFB_T prFalseAuthSwRfb, + IN u16 u2TransactionSeqNum, + IN u16 u2StatusCode); +#endif + +WLAN_STATUS authCheckTxAuthFrame(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN u16 u2TransactionSeqNum); + +WLAN_STATUS authCheckRxAuthFrameTransSeq(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS +authCheckRxAuthFrameStatus(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN u16 u2TransactionSeqNum, + OUT u16 *pu2StatusCode); + +void authHandleIEChallengeText(P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb, + P_IE_HDR_T prIEHdr); + +WLAN_STATUS authProcessRxAuth2_Auth4Frame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS +authSendDeauthFrame(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prClassErrSwRfb, + IN u16 u2ReasonCode, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler); + +WLAN_STATUS authProcessRxDeauthFrame(IN P_SW_RFB_T prSwRfb, + IN u8 aucBSSID[], + OUT u16 *pu2ReasonCode); + +WLAN_STATUS +authProcessRxAuth1Frame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN u8 aucExpectedBSSID[], + IN u16 u2ExpectedAuthAlgNum, + IN u16 u2ExpectedTransSeqNum, + OUT u16 *pu2ReturnStatusCode); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/bss.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/bss.h new file mode 100644 index 00000000000000..1ceac069f96352 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/bss.h @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "bss.h" + * \brief In this file we define the function prototype used in BSS/IBSS. + * + * The file contains the function declarations and defines for used in + * BSS/IBSS. + */ + +#ifndef _BSS_H +#define _BSS_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "wlan_def.h" +extern const u8 *apucNetworkType[NETWORK_TYPE_NUM]; + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* Fixed value=4 for MT6630. + * It is the biggest index of this pointer array prAdapter->aprBssInfo[]. + */ +#define MAX_BSS_INDEX HW_BSSID_NUM +#define P2P_DEV_BSS_INDEX MAX_BSS_INDEX + +/* Define how many concurrent operation networks. */ +#define BSS_INFO_NUM KAL_BSS_NUM +#define BSS_P2P_NUM KAL_P2P_NUM + +#if (KAL_BSS_NUM > HW_BSSID_NUM) || (KAL_P2P_NUM > KAL_BSS_NUM) +#error Exceed HW capability (KAL_BSS_NUM or KAL_P2P_NUM)!! +#endif + +/* NOTE(Kevin): change define for george */ +/* #define MAX_LEN_TIM_PARTIAL_BMP (((MAX_ASSOC_ID + 1) + 7) / 8) */ /* Required + * bits + * = + * (MAX_ASSOC_ID + + 1) + */ +#define MAX_LEN_TIM_PARTIAL_BMP ((CFG_STA_REC_NUM + 7) / 8) +/* reserve length greater than maximum size of STA_REC */ /* obsoleted: Assume + * we + * only use AID:1~15 + */ + +/* CTRL FLAGS for Probe Response */ +#define BSS_PROBE_RESP_USE_P2P_DEV_ADDR BIT(0) +#define BSS_PROBE_RESP_INCLUDE_P2P_IE BIT(1) + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define IS_BSS_INDEX_VALID(_ucBssIndex) ((_ucBssIndex) <= \ + P2P_DEV_BSS_INDEX) + +#define IS_BSS_INDEX_AIS(_prAdapter, _BssIndex) (_BssIndex < KAL_AIS_NUM) + +#define GET_BSS_INFO_BY_INDEX(_prAdapter, _ucBssIndex) \ + ((_prAdapter)->aprBssInfo[(_ucBssIndex)]) + +#define bssAssignAssocID(_prStaRec) ((_prStaRec)->ucIndex + 1) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Routines for all Operation Modes */ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T +bssCreateStaRecFromBssDesc(IN P_ADAPTER_T prAdapter, + IN ENUM_STA_TYPE_T eStaType, + IN u8 uBssIndex, + IN P_BSS_DESC_T prBssDesc); + +void bssComposeNullFrame(IN P_ADAPTER_T prAdapter, + IN u8 *pucBuffer, + IN P_STA_RECORD_T prStaRec); + +void bssComposeQoSNullFrame(IN P_ADAPTER_T prAdapter, + IN u8 *pucBuffer, + IN P_STA_RECORD_T prStaRec, + IN u8 ucUP, + IN u8 fgSetEOSP); + +WLAN_STATUS +bssSendNullFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler); + +WLAN_STATUS +bssSendQoSNullFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN u8 ucUP, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler); + +void bssDumpBssInfo(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex); + +void bssDetermineApBssInfoPhyTypeSet(IN P_ADAPTER_T prAdapter, + IN u8 fgIsPureAp, + OUT P_BSS_INFO_T prBssInfo); + +void bssDetermineStaRecPhyTypeSet(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + OUT P_STA_RECORD_T prStaRec); + +/*----------------------------------------------------------------------------*/ +/* Routines for both IBSS(AdHoc) and BSS(AP) */ +/*----------------------------------------------------------------------------*/ +void bssGenerateExtSuppRate_IE(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +void bssBuildBeaconProbeRespFrameCommonIEs(IN P_MSDU_INFO_T prMsduInfo, + IN P_BSS_INFO_T prBssInfo, + IN u8 *pucDestAddr); + +void bssComposeBeaconProbeRespFrameHeaderAndFF(IN u8 *pucBuffer, + IN u8 *pucDestAddr, + IN u8 *pucOwnMACAddress, + IN u8 *pucBSSID, + IN u16 u2BeaconInterval, + IN u16 u2CapInfo); + +WLAN_STATUS +bssSendBeaconProbeResponse(IN P_ADAPTER_T prAdapter, + IN u8 uBssIndex, + IN u8 *pucDestAddr, + IN u32 u4ControlFlags); + +WLAN_STATUS bssProcessProbeRequest(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb); + +void bssInitializeClientList(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo); + +void bssAddClient(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_STA_RECORD_T prStaRec); + +u8 bssRemoveClient(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_STA_RECORD_T prStaRec); + +P_STA_RECORD_T bssRemoveClientByMac(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN u8 *pucMac); + +P_STA_RECORD_T bssGetClientByMac(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN u8 *pucMac); + +P_STA_RECORD_T bssRemoveHeadClient(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo); + +u32 bssGetClientCount(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); + +void bssDumpClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); + +void bssCheckClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); + +/*----------------------------------------------------------------------------*/ +/* Routines for IBSS(AdHoc) only */ +/*----------------------------------------------------------------------------*/ +void ibssProcessMatchedBeacon(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_BSS_DESC_T prBssDesc, + IN u8 ucRCPI); + +WLAN_STATUS ibssCheckCapabilityForAdHocMode(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc); + +void ibssInitForAdHoc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); + +WLAN_STATUS bssUpdateBeaconContent(IN P_ADAPTER_T prAdapter, IN u8 uBssIndex); + +/*----------------------------------------------------------------------------*/ +/* Routines for BSS(AP) only */ +/*----------------------------------------------------------------------------*/ +void bssInitForAP(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN u8 fgIsRateUpdate); + +void bssUpdateDTIMCount(IN P_ADAPTER_T prAdapter, IN u8 uBssIndex); + +void bssSetTIMBitmap(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN u16 u2AssocId); + +/*link function to p2p module for txBcnIETable*/ + +/* WMM-2.2.2 WMM ACI to AC coding */ +typedef enum _ENUM_ACI_T { + ACI_BE = 0, + ACI_BK = 1, + ACI_VI = 2, + ACI_VO = 3, + ACI_NUM +} ENUM_ACI_T, +*P_ENUM_ACI_T; + +typedef enum _ENUM_AC_PRIORITY_T { + AC_BK_PRIORITY = 0, + AC_BE_PRIORITY, + AC_VI_PRIORITY, + AC_VO_PRIORITY +} ENUM_AC_PRIORITY_T, +*P_ENUM_AC_PRIORITY_T; + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/cnm.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/cnm.h new file mode 100644 index 00000000000000..3595c005c96e2c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/cnm.h @@ -0,0 +1,336 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "cnm.h" + * \brief + */ + +#ifndef _CNM_H +#define _CNM_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#if CFG_SUPPORT_DBDC +#define DBDC_5G_WMM_INDEX 0 +#define DBDC_2G_WMM_INDEX 1 +#endif +#define MAX_HW_WMM_INDEX (HW_WMM_NUM - 1) +#define DEFAULT_HW_WMM_INDEX (MAX_HW_WMM_INDEX - 1) + +/* Define DBDC connection time */ +#if CFG_SUPPORT_DBDC +#define DBDC_SWITCH_GUARD_TIME (4 * 1000) /*ms*/ +#define DBDC_DISABLE_COUNTDOWN_TIME (2 * 1000) /*ms*/ +#if CFG_SUPPORT_DBDC_TC6 +#define DBDC_AIS_BCN_TIMEOUT_RECONNECT_COUNTDOWN_TIME (10 * 1000) /*ms*/ +#define DBDC_AIS_REASSOC_COUNTDOWN_TIME (10 * 1000) /*ms*/ +#define DBDC_AIS_CONNECT_COUNTDOWN_TIME (10 * 1000) /*ms*/ +#define DBDC_AIS_REASSOC_DELAY_DISCONNECT_EVENT_TIME (15 * 1000) /*ms*/ +#endif +#endif + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef enum _ENUM_CH_REQ_TYPE_T { + CH_REQ_TYPE_JOIN, + CH_REQ_TYPE_P2P_LISTEN, + CH_REQ_TYPE_OFFCHNL_TX, + CH_REQ_TYPE_GO_START_BSS, +#if (CFG_SUPPORT_DFS_MASTER == 1) + CH_REQ_TYPE_DFS_CAC, +#endif + CH_REQ_TYPE_NUM +} ENUM_CH_REQ_TYPE_T, +*P_ENUM_CH_REQ_TYPE_T; + +typedef struct _MSG_CH_REQ_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucBssIndex; + u8 ucTokenID; + u8 ucPrimaryChannel; + ENUM_CHNL_EXT_T eRfSco; + ENUM_BAND_T eRfBand; + ENUM_CHANNEL_WIDTH_T eRfChannelWidth; /* To support 80/160MHz bandwidth + */ + u8 ucRfCenterFreqSeg1; /* To support 80/160MHz bandwidth */ + u8 ucRfCenterFreqSeg2; /* To support 80/160MHz bandwidth */ + ENUM_CH_REQ_TYPE_T eReqType; + u32 u4MaxInterval; /* In unit of ms */ + ENUM_DBDC_BN_T eDBDCBand; +} MSG_CH_REQ_T, *P_MSG_CH_REQ_T; + +typedef struct _MSG_CH_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucBssIndex; + u8 ucTokenID; + ENUM_DBDC_BN_T eDBDCBand; +} MSG_CH_ABORT_T, *P_MSG_CH_ABORT_T; + +typedef struct _MSG_CH_GRANT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucBssIndex; + u8 ucTokenID; + u8 ucPrimaryChannel; + ENUM_CHNL_EXT_T eRfSco; + ENUM_BAND_T eRfBand; + ENUM_CHANNEL_WIDTH_T eRfChannelWidth; /* To support 80/160MHz bandwidth + */ + u8 ucRfCenterFreqSeg1; /* To support 80/160MHz bandwidth */ + u8 ucRfCenterFreqSeg2; /* To support 80/160MHz bandwidth */ + ENUM_CH_REQ_TYPE_T eReqType; + u32 u4GrantInterval; /* In unit of ms */ + ENUM_DBDC_BN_T eDBDCBand; +} MSG_CH_GRANT_T, *P_MSG_CH_GRANT_T; + +typedef struct _MSG_CH_REOCVER_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucBssIndex; + u8 ucTokenID; + u8 ucPrimaryChannel; + ENUM_CHNL_EXT_T eRfSco; + ENUM_BAND_T eRfBand; + ENUM_CHANNEL_WIDTH_T eRfChannelWidth; /* To support 80/160MHz bandwidth + */ + u8 ucRfCenterFreqSeg1; /* To support 80/160MHz bandwidth */ + u8 ucRfCenterFreqSeg2; /* To support 80/160MHz bandwidth */ + ENUM_CH_REQ_TYPE_T eReqType; +} MSG_CH_RECOVER_T, *P_MSG_CH_RECOVER_T; + +typedef struct _CNM_INFO_T { + u8 fgChGranted; + u8 ucBssIndex; + u8 ucTokenID; +#if CFG_SUPPORT_DBDC_TC6 + LINK_T + rDbdcSwitchGuradPendingReqList; /* Pending Request List for DBDC switch + * guard */ + u8 fgSkipDbdcDisable; /* Skip DBDC diable to keep DBDC status for BCN + * timeout */ +#endif +} CNM_INFO_T, *P_CNM_INFO_T; + +#if CFG_ENABLE_WIFI_DIRECT +/* Moved from p2p_fsm.h */ +typedef struct _DEVICE_TYPE_T { + u16 u2CategoryId; /* Category ID */ + u8 aucOui[4]; /* OUI */ + u16 u2SubCategoryId; /* Sub Category ID */ +} __KAL_ATTRIB_PACKED__ DEVICE_TYPE_T, *P_DEVICE_TYPE_T; +#endif + +#if CFG_SUPPORT_DBDC +typedef struct _CNM_DBDC_CAP_T { + u8 ucBssIndex; + u8 ucNss; + u8 ucWmmSetIndex; +} CNM_DBDC_CAP_T, *P_CNM_DBDC_CAP_T; + +typedef enum _ENUM_CNM_DBDC_MODE_T { + DBDC_MODE_DISABLED, /* A/G traffic separate by WMM, but both WMM TRX on + * band 0, CANNOT enable DBDC */ + DBDC_MODE_STATIC, /* A/G traffic separate by WMM, WMM0/1 TRX on band + * 0/1, CANNOT disable DBDC */ + DBDC_MODE_DYNAMIC, /* Automatically enable/disable DBDC, setting just + * like static/disable mode */ + DBDC_MODE_NUM +} ENUM_CNM_DBDC_MODE_T, +*P_ENUM_CNM_DBDC_MODE_T; + +typedef enum _ENUM_CNM_DBDC_SWITCH_MECHANISM_T { /* When DBDC available in dynamic DBDC */ + DBDC_SWITCH_MECHANISM_LATENCY_MODE, /* Switch to DBDC when available (less + * latency) */ + DBDC_SWITCH_MECHANISM_THROUGHPUT_MODE, /* Switch to DBDC when DBDC T-put > MCC + * T-put */ + DBDC_SWITCH_MECHANISM_NUM +} ENUM_CNM_DBDC_SWITCH_MECHANISM_T, +*P_ENUM_CNM_DBDC_SWITCH_MECHANISM_T; + +/* Define DBDC Decision timer */ +typedef enum _ENUM_CNM_DBDC_DECISION_TIMER_T { + DBDC_DECISION_TIMER_SWITCH_GUARD_TIME, + DBDC_DECISION_TIMER_DISABLE_COUNT_DOWN, +#if CFG_SUPPORT_DBDC_TC6 + DBDC_DECISION_TIMER_RECONNECT_COUNT_DOWN, + DBDC_DECISION_TIMER_AIS_CONNECT_COUNT_DOWN, + DBDC_DECISION_AIS_RECONNECT, +#endif + DBDC_DECISION_STATE_NUM +} ENUM_CNM_DBDC_DECISION_TIMER_T, +*P_ENUM_CNM_DBDC_DECISION_TIMER_T; + +#endif + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define CNM_CH_GRANTED_FOR_BSS(_prAdapter, _ucBssIndex) \ + ((_prAdapter)->rCnmInfo.fgChGranted && \ + (_prAdapter)->rCnmInfo.ucBssIndex == (_ucBssIndex)) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void cnmInit(P_ADAPTER_T prAdapter); + +void cnmChMngrRequestPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); + +void cnmChMngrAbortPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); + +void cnmChMngrHandleChEvent(P_ADAPTER_T prAdapter, + P_WIFI_EVENT_T prEvent, + u32 u4EventBufLen); + +#if (CFG_SUPPORT_DFS_MASTER == 1) +void cnmRadarDetectEvent(P_ADAPTER_T prAdapter, + P_WIFI_EVENT_T prEvent, + u32 u4EventBufLen); + +void cnmCsaDoneEvent(P_ADAPTER_T prAdapter, + P_WIFI_EVENT_T prEvent, + u32 u4EventBufLen); +#endif + +u8 cnmPreferredChannel(P_ADAPTER_T prAdapter, + P_ENUM_BAND_T prBand, + u8 *pucPrimaryChannel, + P_ENUM_CHNL_EXT_T prBssSCO); + +u8 cnmAisInfraChannelFixed(P_ADAPTER_T prAdapter, + P_ENUM_BAND_T prBand, + u8 *pucPrimaryChannel); + +u8 cnmAisIbssIsPermitted(P_ADAPTER_T prAdapter); + +u8 cnmP2PIsPermitted(P_ADAPTER_T prAdapter); + +u8 cnmBowIsPermitted(P_ADAPTER_T prAdapter); + +u8 cnmBss40mBwPermitted(P_ADAPTER_T prAdapter, u8 ucBssIndex); + +u8 cnmBss80mBwPermitted(P_ADAPTER_T prAdapter, u8 ucBssIndex); + +u8 cnmGetBssMaxBw(P_ADAPTER_T prAdapter, u8 ucBssIndex); + +u8 cnmGetBssMaxBwToChnlBW(P_ADAPTER_T prAdapter, u8 ucBssIndex); + +P_BSS_INFO_T cnmGetBssInfoAndInit(P_ADAPTER_T prAdapter, + ENUM_NETWORK_TYPE_T eNetworkType, + u8 fgIsP2pDevice); + +void cnmFreeBssInfo(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); +#if CFG_SUPPORT_CHNL_CONFLICT_REVISE +u8 cnmAisDetectP2PChannel(P_ADAPTER_T prAdapter, + P_ENUM_BAND_T prBand, + u8 *pucPrimaryChannel); +#endif + +#if (CFG_HW_WMM_BY_BSS == 1) +u8 cnmWmmIndexDecision(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); +void cnmFreeWmmIndex(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); +#endif + +P_BSS_INFO_T cnmGetp2pSapBssInfo(IN P_ADAPTER_T prAdapter); + +u8 cnmSapIsConcurrent(IN P_ADAPTER_T prAdapter); + +void cnmSapChannelSwitchReq(IN P_ADAPTER_T prAdapter, + IN P_RF_CHANNEL_INFO_T prRfChannelInfo, + IN u8 ucRoleIdx); + +#if CFG_SUPPORT_DBDC_TC6 +u8 cnmSapIsActive(IN P_ADAPTER_T prAdapter); +u8 cnmIdcCsaReq(IN P_ADAPTER_T prAdapter, IN u8 ch_num, IN u8 ucRoleIdx); +#endif + +#if CFG_SUPPORT_DBDC +void cnmInitDbdcSetting(IN P_ADAPTER_T prAdapter); + +void cnmUpdateDbdcSetting(IN P_ADAPTER_T prAdapter, IN u8 fgDbdcEn); + +void cnmGetDbdcCapability(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN ENUM_BAND_T eRfBand, + IN u8 ucPrimaryChannel, + IN u8 ucNss, + OUT P_CNM_DBDC_CAP_T prDbdcCap); + +void cnmDbdcEnableDecision(IN P_ADAPTER_T prAdapter, + IN u8 ucChangedBssIndex, + IN ENUM_BAND_T eRfBand); + +void cnmDbdcDisableDecision(IN P_ADAPTER_T prAdapter, IN u8 ucChangedBssIndex); +void cnmDbdcDecision(IN P_ADAPTER_T prAdapter, IN unsigned long plParamPtr); +#endif + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#ifndef _lint +/* We don't have to call following function to inspect the data structure. + * It will check automatically while at compile time. + * We'll need this to guarantee the same member order in different structures + * to simply handling effort in some functions. + */ +static __KAL_INLINE__ void cnmMsgDataTypeCheck(void) +{ + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, rMsgHdr) == 0); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, rMsgHdr) == + OFFSET_OF(MSG_CH_RECOVER_T, rMsgHdr)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, ucBssIndex) == + OFFSET_OF(MSG_CH_RECOVER_T, ucBssIndex)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, ucTokenID) == + OFFSET_OF(MSG_CH_RECOVER_T, ucTokenID)); + + DATA_STRUCT_INSPECTING_ASSERT( + OFFSET_OF(MSG_CH_GRANT_T, ucPrimaryChannel) == + OFFSET_OF(MSG_CH_RECOVER_T, ucPrimaryChannel)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, eRfSco) == + OFFSET_OF(MSG_CH_RECOVER_T, eRfSco)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, eRfBand) == + OFFSET_OF(MSG_CH_RECOVER_T, eRfBand)); + + DATA_STRUCT_INSPECTING_ASSERT(OFFSET_OF(MSG_CH_GRANT_T, eReqType) == + OFFSET_OF(MSG_CH_RECOVER_T, eReqType)); +} +#endif + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/cnm_mem.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/cnm_mem.h new file mode 100644 index 00000000000000..d29b0464dd06ae --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/cnm_mem.h @@ -0,0 +1,722 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "cnm_mem.h" + * \brief In this file we define the structure of the control unit of + * packet buffer and MGT/MSG Memory Buffer. + */ + +#ifndef _CNM_MEM_H +#define _CNM_MEM_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#ifndef POWER_OF_2 +#define POWER_OF_2(n) BIT(n) +#endif + +/* Size of a basic management buffer block in power of 2 */ +#define MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2 7 /* 7 to the power of 2 = 128 */ +#define MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2 5 /* 5 to the power of 2 = 32 */ + +/* Size of a basic management buffer block */ +#define MGT_BUF_BLOCK_SIZE POWER_OF_2( \ + MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2) +#define MSG_BUF_BLOCK_SIZE POWER_OF_2( \ + MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2) + +/* Total size of (n) basic management buffer blocks */ +#define MGT_BUF_BLOCKS_SIZE(n) ((u32)(n) << MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2) +#define MSG_BUF_BLOCKS_SIZE(n) ((u32)(n) << MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2) + +/* Number of management buffer block */ +#define MAX_NUM_OF_BUF_BLOCKS 32 /* Range: 1~32 */ + +/* Size of overall management frame buffer */ +#define MGT_BUFFER_SIZE (MAX_NUM_OF_BUF_BLOCKS * \ + MGT_BUF_BLOCK_SIZE) +#define MSG_BUFFER_SIZE (MAX_NUM_OF_BUF_BLOCKS * \ + MSG_BUF_BLOCK_SIZE) + +/* STA_REC related definitions */ +#define STA_REC_INDEX_BMCAST 0xFF +#define STA_REC_INDEX_NOT_FOUND 0xFE +#define STA_WAIT_QUEUE_NUM \ + 5 /* Number of SW queues in each STA_REC: AC0~AC4 \ + */ +#define SC_CACHE_INDEX_NUM \ + 5 /* Number of SC caches in each STA_REC: AC0~AC4 \ + */ + +/* P2P related definitions */ +#ifdef CFG_ENABLE_WIFI_DIRECT +/* Moved from p2p_fsm.h */ +#define WPS_ATTRI_MAX_LEN_DEVICE_NAME 32 /* 0x1011 */ +#define P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT 8 /* NOTE(Kevin): Shall <= 16 */ +#endif + +/* Define the argument of cnmStaFreeAllStaByNetwork when all station records + * will be free. No one will be free + */ +#define STA_REC_EXCLUDE_NONE CFG_STA_REC_NUM + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +#if ((MAX_NUM_OF_BUF_BLOCKS > 32) || (MAX_NUM_OF_BUF_BLOCKS <= 0)) +#error > #define MAX_NUM_OF_MGT_BUF_BLOCKS : Out of boundary ! +#elif MAX_NUM_OF_BUF_BLOCKS > 16 +typedef u32 BUF_BITMAP; +#elif MAX_NUM_OF_BUF_BLOCKS > 8 +typedef u16 BUF_BITMAP; +#else +typedef u8 BUF_BITMAP; +#endif + +/* Control variable of TX management memory pool */ +typedef struct _BUF_INFO_T { + u8 *pucBuf; + +#if CFG_DBG_MGT_BUF + u32 u4AllocCount; + u32 u4FreeCount; + u32 u4AllocNullCount; +#endif + + BUF_BITMAP rFreeBlocksBitmap; + u8 aucAllocatedBlockNum[MAX_NUM_OF_BUF_BLOCKS]; +} BUF_INFO_T, *P_BUF_INFO_T; + +/* Wi-Fi divides RAM into three types + * MSG: Mailbox message (Small size) + * BUF: HW DMA buffers (HIF/MAC) + */ +typedef enum _ENUM_RAM_TYPE_T { + RAM_TYPE_MSG = 0, + RAM_TYPE_BUF +} ENUM_RAM_TYPE_T, +P_ENUM_RAM_TYPE_T; + +typedef enum _ENUM_BUFFER_SOURCE_T { + BUFFER_SOURCE_HIF_TX0 = 0, + BUFFER_SOURCE_HIF_TX1, + BUFFER_SOURCE_MAC_RX, + BUFFER_SOURCE_MNG, + BUFFER_SOURCE_BCN, + BUFFER_SOURCE_NUM +} ENUM_BUFFER_SOURCE_T, +*P_ENUM_BUFFER_SOURCE_T; + +typedef enum _ENUM_SEC_STATE_T { + SEC_STATE_INIT, + SEC_STATE_INITIATOR_PORT_BLOCKED, + SEC_STATE_RESPONDER_PORT_BLOCKED, + SEC_STATE_CHECK_OK, + SEC_STATE_SEND_EAPOL, + SEC_STATE_SEND_DEAUTH, + SEC_STATE_COUNTERMEASURE, + SEC_STATE_NUM +} ENUM_SEC_STATE_T; + +typedef struct _TSPEC_ENTRY_T { + u8 ucStatus; + u8 ucToken; /* Dialog Token in ADDTS_REQ or ADDTS_RSP */ + u16 u2MediumTime; + u32 u4TsInfo; + /* PARAM_QOS_TS_INFO rParamTsInfo; */ + /* Add other retained QoS parameters below */ +} TSPEC_ENTRY_T, *P_TSPEC_ENTRY_T, TSPEC_TABLE_ENTRY_T, *P_TSPEC_TABLE_ENTRY_T; + +#define MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS 3 + +#define UPDATE_BSS_RSSI_INTERVAL_SEC 3 /* Seconds */ + +/* Fragment information structure */ +typedef struct _FRAG_INFO_T { + u16 u2SeqNo; + u8 ucNextFragNo; +#if CFG_SUPPORT_FRAG_ATTACK_DETECTION + u8 ucSecMode; + u64 u8NextPN; +#endif + u8 *pucNextFragStart; + P_SW_RFB_T pr1stFrag; + u32 rReceiveLifetimeLimit; /* The receive time of 1st fragment */ +} FRAG_INFO_T, *P_FRAG_INFO_T; + +#if CFG_SUPPORT_802_11W +/* AP PMF */ +struct AP_PMF_CFG { + u8 fgMfpc; + u8 fgMfpr; + u8 fgSha256; + u8 fgAPApplyPmfReq; + u8 fgBipKeyInstalled; +}; + +struct STA_PMF_CFG { + u8 fgMfpc; + u8 fgMfpr; + u8 fgSha256; + u8 fgApplyPmf; + u8 fgBipKeyInstalled; + u8 fgRxDeauthResp; /* for certification 4.3.3.1, 4.3.3.2 TX unprotected + * deauth */ + + /* For PMF SA query TX request retry a timer */ + u32 u4SAQueryStart; /* record the start time of 1st SAQ request */ + u32 u4SAQueryCount; + u8 ucSAQueryTimedOut; /* retry more than 1000ms */ + TIMER_T rSAQueryTimer; + u16 u2TransactionID; +}; +#endif + +/* Define STA record structure */ +struct _STA_RECORD_T { + LINK_ENTRY_T rLinkEntry; + u8 ucIndex; /* Not modify it except initializing */ + u8 ucWlanIndex; /* WLAN table index */ + + /* u8 ucBMCWlanIndex; */ /* The BSS STA Rx WLAN index, + * IBSS Rx BC WLAN table index, + * work at IBSS Open and WEP + */ + + u8 fgIsInUse; /* Indicate if this entry is in use or not */ + u8 aucMacAddr[MAC_ADDR_LEN]; /* MAC address */ + + /* SAA/AAA */ + ENUM_AA_STATE_T eAuthAssocState; /* Store STATE Value used in SAA/AAA */ + u8 ucAuthAssocReqSeqNum; + + ENUM_STA_TYPE_T eStaType; /* Indicate the role of this STA in + * the network (for example, P2P GO) + */ + + u8 ucBssIndex; /* BSS_INFO_I index */ + + u8 ucStaState; /* STATE_1,2,3 */ + + u8 ucPhyTypeSet; /* Available PHY Type Set of this peer + * (may deduced from received BSS_DESC_T) + */ + u8 ucVhtCapNumSoundingDimensions; /* record from bcn or probe response*/ + + u8 ucDesiredPhyTypeSet; /* The match result by AND operation of peer's + * PhyTypeSet and ours. + */ + u8 fgHasBasicPhyType; /* A flag to indicate a Basic Phy Type which + * is used to generate some Phy Attribute IE + * (e.g. capability, MIB) during association. + */ + u8 ucNonHTBasicPhyType; /* The Basic Phy Type chosen among the + * ucDesiredPhyTypeSet. + */ + + u16 u2HwDefaultFixedRateCode; + + u16 u2CapInfo; /* For Infra Mode, to store Capability Info. from + * Association Resp(SAA). For AP Mode, to store + * Capability Info. from Association Req(AAA). + */ + u16 u2AssocId; /* For Infra Mode, to store AID from Association + * Resp(SAA). For AP Mode, to store the Assigned + * AID(AAA). + */ + + u16 u2ListenInterval; /* Listen Interval from STA(AAA) */ + + u16 u2DesiredNonHTRateSet; /* Our Current Desired Rate Set after + * match with STA's Operational Rate Set + */ + + u16 u2OperationalRateSet; /* Operational Rate Set of peer BSS */ + u16 u2BSSBasicRateSet; /* Basic Rate Set of peer BSS */ + + u8 fgIsMerging; /* For IBSS Mode, to indicate that Merge is ongoing */ + + u8 fgDiagnoseConnection; /* For Infra/AP Mode, to diagnose the + * Connection with */ + /* this peer by sending ProbeReq/Null frame */ + + /*------------------------------------------------------------------------------------------*/ + /* 802.11n HT capabilities when (prStaRec->ucPhyTypeSet & + * PHY_TYPE_BIT_HT) is true */ + /* They have the same definition with fields of information element */ + /*------------------------------------------------------------------------------------------*/ + u8 ucMcsSet; /* MCS0~7 rate set of peer BSS */ + u8 fgSupMcs32; /* MCS32 is supported by peer BSS */ + u8 aucRxMcsBitmask[SUP_MCS_RX_BITMASK_OCTET_NUM]; + u16 u2RxHighestSupportedRate; + u32 u4TxRateInfo; + u16 u2HtCapInfo; /* HT cap info field by HT cap IE */ + u8 ucAmpduParam; /* Field A-MPDU Parameters in HT cap IE */ + u16 u2HtExtendedCap; /* HT extended cap field by HT cap IE */ + u32 u4TxBeamformingCap; /* TX beamforming cap field by HT cap IE */ + u8 ucAselCap; /* ASEL cap field by HT cap IE */ + /* CFG_SUPPORT_802_11AC */ + /*------------------------------------------------------------------------------------------*/ + /* 802.11ac VHT capabilities when (prStaRec->ucPhyTypeSet & + * PHY_TYPE_BIT_VHT) is true */ + /* They have the same definition with fields of information element */ + /*------------------------------------------------------------------------------------------*/ + u32 u4VhtCapInfo; + u16 u2VhtRxMcsMap; + u16 u2VhtRxHighestSupportedDataRate; + u16 u2VhtTxMcsMap; + u16 u2VhtTxHighestSupportedDataRate; + u8 ucVhtOpMode; + + u8 ucRCPI; /* RCPI of peer */ + + u8 ucDTIMPeriod; /* Target BSS's DTIM Period, we use this + * value for setup Listen Interval + * TODO(Kevin): TBD + */ + u8 ucAuthAlgNum; /* For Infra/AP Mode, the Auth Algorithm Num used in + * Authentication(SAA/AAA) */ + u8 fgIsReAssoc; /* For Infra/AP Mode, to indicate ReAssoc Frame was in + * used(SAA/AAA) */ + + u8 ucTxAuthAssocRetryCount; /* For Infra Mode, the Retry Count of TX + * Auth/Assod Frame(SAA) */ + u8 ucTxAuthAssocRetryLimit; /* For Infra Mode, the Retry Limit of TX + * Auth/Assod Frame(SAA) */ + + /* Record what we sent for retry TX Auth/Assoc without SAA FSM */ + enum ENUM_AA_SENT_T eAuthAssocSent; + + u16 u2StatusCode; /* Status of Auth/Assoc Req */ + u16 u2ReasonCode; /* Reason that been Deauth/Disassoc */ + u8 fgIsLocallyGenerated; + + /* Point to an allocated buffer for storing Challenge */ + /* Text for Shared Key Authentication */ + P_IE_CHALLENGE_TEXT_T prChallengeText; + + /* For Infra Mode, a timer used to send a timeout event + * while waiting for TX request done or RX response. + */ + TIMER_T rTxReqDoneOrRxRespTimer; + + /* For Infra Mode, a timer used to avoid the Deauth frame + * not be sent + */ + TIMER_T rDeauthTxDoneTimer; + + /*------------------------------------------------------------------------------------------*/ + /* Power Management related fields (for STA/ AP/ P2P/ BOW power saving + * mode) */ + /*------------------------------------------------------------------------------------------*/ + u8 fgSetPwrMgtBit; /* For Infra Mode, to indicate that outgoing frame + * need toggle the Pwr Mgt Bit in its Frame Control + * Field. + */ + + u8 fgIsInPS; /* For AP Mode, to indicate the client PS state(PM). + * true: In PS Mode; false: In Active Mode. + */ + + u8 fgIsInPsPollSP; /* For Infra Mode, to indicate we've sent a PS POLL + * to AP and start the PS_POLL Service Period(LP) + */ + + u8 fgIsInTriggerSP; /* For Infra Mode, to indicate we've sent a Trigger + * Frame to AP and start the Delivery Service + * Period(LP) + */ + + u8 ucBmpDeliveryAC; /* 0: AC0, 1: AC1, 2: AC2, 3: AC3 */ + + u8 ucBmpTriggerAC; /* 0: AC0, 1: AC1, 2: AC2, 3: AC3 */ + + u8 ucUapsdSp; /* Max SP length */ + + /*------------------------------------------------------------------------------------------*/ + + u8 fgIsRtsEnabled; + + u32 rUpdateTime; /* (4) System Timestamp of Successful TX and RX */ + + u32 rLastJoinTime; /* (4) System Timestamp of latest JOIN process */ + + u8 ucJoinFailureCount; /* Retry Count of JOIN process */ + + LINK_T arStaWaitQueue[STA_WAIT_QUEUE_NUM]; /* For TXM to defer pkt + * forwarding to MAC TX DMA + */ + + /* Duplicate removal for HT STA on a + * per-TID basis ("+1" is for MMPDU and non-QoS) + */ + u16 au2CachedSeqCtrl[TID_NUM + 1]; + + u8 afgIsIgnoreAmsduDuplicate[TID_NUM + 1]; + +#if CFG_SUPPORT_AMSDU_ATTACK_DETECTION + u16 au2AmsduInvalidSN[TID_NUM + 1]; + u8 afgIsAmsduInvalid[TID_NUM + 1]; +#endif + + FRAG_INFO_T rFragInfo[MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS]; + + /* SEC_INFO_T rSecInfo; */ /* The security state machine */ + +#if CFG_SUPPORT_ADHOC + u8 fgAdhocRsnBcKeyExist[2]; /* Ad-hoc RSN Rx BC key exist flag, + * only reserved two entry for each peer + */ + u8 ucAdhocRsnBcWlanIndex[2]; /* Ad-hoc RSN Rx BC wlan index */ +#endif + + u8 fgPortBlock; /* The 802.1x Port Control flag */ + + u8 fgTransmitKeyExist; /* Unicast key exist for this STA */ + + u8 fgTxAmpduEn; /* Enable TX AMPDU for this Peer */ + u8 fgRxAmpduEn; /* Enable RX AMPDU for this Peer */ + + u8 *pucAssocReqIe; + u16 u2AssocReqIeLen; + + WIFI_WMM_AC_STAT_T + arLinkStatistics[WMM_AC_INDEX_NUM]; /*link layer satatistics */ + + /*------------------------------------------------------------------------------------------*/ + /* WMM/QoS related fields */ + /*------------------------------------------------------------------------------------------*/ + u8 fgIsQoS; /* If the STA is associated as a QSTA or QAP (for TX/RX) */ + u8 fgIsWmmSupported; /* If the peer supports WMM, set to true (for + * association) */ + u8 fgIsUapsdSupported; /* Set according to the scan result (for + * association) */ + + /*------------------------------------------------------------------------------------------*/ + /* P2P related fields */ + /*------------------------------------------------------------------------------------------*/ +#if CFG_ENABLE_WIFI_DIRECT + u8 u2DevNameLen; + u8 aucDevName[WPS_ATTRI_MAX_LEN_DEVICE_NAME]; + + u8 aucDevAddr[MAC_ADDR_LEN]; /* P2P Device Address */ + + u16 u2ConfigMethods; + + u8 ucDeviceCap; + + u8 ucSecondaryDevTypeCount; + + DEVICE_TYPE_T rPrimaryDevTypeBE; + + DEVICE_TYPE_T arSecondaryDevTypeBE[P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT]; +#endif + + /*------------------------------------------------------------------------------------------*/ + /* QM related fields */ + /*------------------------------------------------------------------------------------------*/ + + u8 ucFreeQuota; /* Per Sta flow controal. Valid when fgIsInPS is true. + * Change it for per Queue flow control + */ + /* u8 aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES]; + */ /* used in future */ + u8 ucFreeQuotaForDelivery; + u8 ucFreeQuotaForNonDelivery; + + /*------------------------------------------------------------------------------------------*/ + /* TXM related fields */ + /*------------------------------------------------------------------------------------------*/ + void *aprTxDescTemplate[TX_DESC_TID_NUM]; + +#if CFG_ENABLE_PKT_LIFETIME_PROFILE && CFG_ENABLE_PER_STA_STATISTICS + u32 u4TotalTxPktsNumber; + u32 u4TotalTxPktsTime; + u32 u4TotalRxPktsNumber; + u32 u4MaxTxPktsTime; + u32 u4ThresholdCounter; +#endif + + /*------------------------------------------------------------------------------------------*/ + /* To be removed, this is to make que_mgt compilation success only */ + /*------------------------------------------------------------------------------------------*/ + /* When this STA_REC is in use, set to true. */ + u8 fgIsValid; + + /* TX key is ready */ + u8 fgIsTxKeyReady; + + /* When the STA is connected or TX key is ready */ + u8 fgIsTxAllowed; + + /* Per-STA Queues: [0] AC0, [1] AC1, [2] AC2, [3] AC3 */ + QUE_T arTxQueue[NUM_OF_PER_STA_TX_QUEUES]; + + /* Per-STA Pending Queues: [0] AC0, [1] AC1, [2] AC2, [3] AC3 */ + /* This queue is for Tx packet in protected BSS before key is set */ + QUE_T arPendingTxQueue[NUM_OF_PER_STA_TX_QUEUES]; + + /* Tx packet target queue pointer. Select between arTxQueue & + * arPendingTxQueue */ + P_QUE_T aprTargetQueue[NUM_OF_PER_STA_TX_QUEUES]; + + /* Reorder Parameter reference table */ + P_RX_BA_ENTRY_T aprRxReorderParamRefTbl[CFG_RX_MAX_BA_TID_NUM]; + +#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT + TIMINGMSMT_PARAM_T rWNMTimingMsmt; +#endif + u8 ucTrafficDataType; /* 0: auto 1: data 2: video 3: voice */ + u8 ucTxGfMode; /* 0: auto 1:Force enable 2: Force disable 3: enable by + * peer */ + u8 ucTxSgiMode; /* 0: auto 1:Force enable 2: Force disable 3: enable by + * peer */ + u8 ucTxStbcMode; /* 0: auto 1:Force enable 2: Force disable 3: enable by + * peer */ + u32 u4FixedPhyRate; /**/ + u16 u2MaxLinkSpeed; /* unit is 0.5 Mbps */ + u16 u2MinLinkSpeed; + u32 u4Flags; /* reserved for MTK Synergies */ + +#if CFG_SUPPORT_TDLS + u8 fgTdlsIsProhibited; /* true: AP prohibits TDLS links */ + u8 fgTdlsIsChSwProhibited; /* true: AP prohibits TDLS chan switch */ + + u8 flgTdlsIsInitiator; /* true: the peer is the initiator */ + IE_HT_CAP_T rTdlsHtCap; /* temp to queue HT capability element */ + PARAM_KEY_T rTdlsKeyTemp; /* temp to queue the key information */ + u8 ucTdlsIndex; +#endif +#if CFG_SUPPORT_TX_BF + TXBF_PFMU_STA_INFO rTxBfPfmuStaInfo; +#endif +#if CFG_SUPPORT_MSP + u32 u4RxVector0; + u32 u4RxVector1; + u32 u4RxVector2; + u32 u4RxVector3; + u32 u4RxVector4; +#endif +#if CFG_SUPPORT_LAST_SEC_MCS_INFO + u32 au4RxVect0Que[MCS_INFO_SAMPLE_CNT]; + u32 au4RxVect1Que[MCS_INFO_SAMPLE_CNT]; +#endif + u8 ucSmDialogToken; /* Spectrum Mngt Dialog Token */ + u8 ucSmMsmtRequestMode; /* Measurement Request Mode */ + u8 ucSmMsmtToken; /* Measurement Request Token */ +#if CFG_SUPPORT_802_11W + /* AP PMF */ + struct STA_PMF_CFG rPmfCfg; +#endif +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + u8 fgSupportBTM; /* Indicates whether to support BTM */ +#endif +}; + +typedef enum _ENUM_STA_REC_CMD_ACTION_T { + STA_REC_CMD_ACTION_STA = 0, + STA_REC_CMD_ACTION_BSS = 1, + STA_REC_CMD_ACTION_BSS_EXCLUDE_STA = 2 +} ENUM_STA_REC_CMD_ACTION_T, +*P_ENUM_STA_REC_CMD_ACTION_T; + +#if CFG_SUPPORT_TDLS + +/* TDLS FSM */ +typedef struct _CMD_PEER_ADD_T { + u8 aucPeerMac[6]; + ENUM_STA_TYPE_T eStaType; +} CMD_PEER_ADD_T; + +typedef struct _CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T { + u8 arRxMask[SUP_MCS_RX_BITMASK_OCTET_NUM]; + u16 u2RxHighest; + u8 ucTxParams; + u8 Reserved[3]; +} CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T; + +typedef struct _CMD_PEER_UPDATE_VHT_CAP_MCS_INFO_T { + u16 u2RxMcsMap; + u16 u2RxHighest; + u16 u2TxMcsMap; + u16 u2TxHighest; +} CMD_PEER_UPDATE_VHT_CAP_MCS_INFO_T; + +typedef struct _CMD_PEER_UPDATE_HT_CAP_T { + u16 u2CapInfo; + u8 ucAmpduParamsInfo; + + /* 16 bytes MCS information */ + CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T rMCS; + + u16 u2ExtHtCapInfo; + u32 u4TxBfCapInfo; + u8 ucAntennaSelInfo; +} CMD_PEER_UPDATE_HT_CAP_T; + +typedef struct _CMD_PEER_UPDATE_VHT_CAP_T { + u32 u4CapInfo; + /* 16 bytes MCS information */ + CMD_PEER_UPDATE_VHT_CAP_MCS_INFO_T rVMCS; +} CMD_PEER_UPDATE_VHT_CAP_T; + +typedef struct _CMD_PEER_UPDATE_T { + u8 aucPeerMac[6]; + +#define CMD_PEER_UPDATE_SUP_CHAN_MAX 50 + u8 aucSupChan[CMD_PEER_UPDATE_SUP_CHAN_MAX]; + + u16 u2StatusCode; + +#define CMD_PEER_UPDATE_SUP_RATE_MAX 50 + u8 aucSupRate[CMD_PEER_UPDATE_SUP_RATE_MAX]; + u16 u2SupRateLen; + + u8 UapsdBitmap; + u8 UapsdMaxSp; /* MAX_SP */ + + u16 u2Capability; +#define CMD_PEER_UPDATE_EXT_CAP_MAXLEN 5 + u8 aucExtCap[CMD_PEER_UPDATE_EXT_CAP_MAXLEN]; + u16 u2ExtCapLen; + + CMD_PEER_UPDATE_HT_CAP_T rHtCap; + CMD_PEER_UPDATE_VHT_CAP_T rVHtCap; + + u8 fgIsSupHt; + u8 fgIsSupVht; + ENUM_STA_TYPE_T eStaType; +} CMD_PEER_UPDATE_T; + +#endif +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#if CFG_DBG_MGT_BUF +#define cnmMgtPktAlloc(_prAdapter, _u4Length) \ + cnmPktAllocWrapper((_prAdapter), (_u4Length), (u8 *)__func__) + +#define cnmMgtPktFree(_prAdapter, _prMsduInfo) \ + cnmPktFreeWrapper((_prAdapter), (_prMsduInfo), (u8 *)__func__) +#else +#define cnmMgtPktAlloc cnmPktAlloc +#define cnmMgtPktFree cnmPktFree +#endif + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +P_MSDU_INFO_T cnmPktAllocWrapper(IN P_ADAPTER_T prAdapter, + IN u32 u4Length, + IN u8 *pucStr); + +void cnmPktFreeWrapper(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN u8 *pucStr); + +P_MSDU_INFO_T cnmPktAlloc(IN P_ADAPTER_T prAdapter, IN u32 u4Length); + +void cnmPktFree(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +void cnmMemInit(IN P_ADAPTER_T prAdapter); + +void *cnmMemAlloc(IN P_ADAPTER_T prAdapter, + IN ENUM_RAM_TYPE_T eRamType, + IN u32 u4Length); + +void cnmMemFree(IN P_ADAPTER_T prAdapter, IN void *pvMemory); + +void cnmStaRecInit(IN P_ADAPTER_T prAdapter); + +P_STA_RECORD_T +cnmStaRecAlloc(IN P_ADAPTER_T prAdapter, + IN ENUM_STA_TYPE_T eStaType, + IN u8 ucBssIndex, + IN u8 *pucMacAddr); + +void cnmStaRecFree(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +void cnmStaFreeAllStaByNetwork(P_ADAPTER_T prAdapter, + u8 ucBssIndex, + u8 ucStaRecIndexExcluded); + +P_STA_RECORD_T cnmGetStaRecByIndex(IN P_ADAPTER_T prAdapter, IN u8 ucIndex); + +P_STA_RECORD_T cnmGetStaRecByAddress(P_ADAPTER_T prAdapter, + u8 ucBssIndex, + u8 aucPeerMACAddress[]); + +P_STA_RECORD_T cnmGetAnyStaRecByAddress(P_ADAPTER_T prAdapter, + u8 *pucPeerMacAddr); + +void cnmStaRecChangeState(IN P_ADAPTER_T prAdapter, + IN OUT P_STA_RECORD_T prStaRec, + IN u8 ucNewState); + +void cnmDumpStaRec(IN P_ADAPTER_T prAdapter, IN u8 ucStaRecIdx); + +u32 cnmDumpMemoryStatus(IN P_ADAPTER_T prAdapter, IN u8 *pucBuf, IN u32 u4Max); + +#if CFG_SUPPORT_TDLS +WLAN_STATUS /* TDLS_STATUS */ +cnmPeerAdd(P_ADAPTER_T prAdapter, + void *pvSetBuffer, + u32 u4SetBufferLen, + u32 *pu4SetInfoLen); + +WLAN_STATUS /* TDLS_STATUS */ +cnmPeerUpdate(P_ADAPTER_T prAdapter, + void *pvSetBuffer, + u32 u4SetBufferLen, + u32 *pu4SetInfoLen); + +P_STA_RECORD_T cnmGetTdlsPeerByAddress(P_ADAPTER_T prAdapter, + u8 ucBssIndex, + u8 aucPeerMACAddress[]); +#endif + +void cnmStaSendUpdateCmd(P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, + P_TXBF_PFMU_STA_INFO prTxBfPfmuStaInfo, + u8 fgNeedResp); + +u8 *cnmStaRecGetTypeString(ENUM_STA_TYPE_T eStaType); +u8 *cnmStaRecGetRoleString(ENUM_STA_TYPE_T eStaType); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/cnm_scan.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/cnm_scan.h new file mode 100644 index 00000000000000..62b51acf4a4532 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/cnm_scan.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "cnm_scan.h" + * \brief + * + */ + +#ifndef _CNM_SCAN_H +#define _CNM_SCAN_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define SCN_CHANNEL_DWELL_TIME_MIN_MSEC 12 +#define SCN_CHANNEL_DWELL_TIME_EXT_MSEC 98 + +#define SCN_TOTAL_PROBEREQ_NUM_FOR_FULL 3 +#define SCN_SPECIFIC_PROBEREQ_NUM_FOR_FULL 1 + +#define SCN_TOTAL_PROBEREQ_NUM_FOR_PARTIAL 2 +#define SCN_SPECIFIC_PROBEREQ_NUM_FOR_PARTIAL 1 + +#define SCN_INTERLACED_CHANNEL_GROUPS_NUM 3 /* Used by partial scan */ + +#define SCN_PARTIAL_SCAN_NUM 3 + +#define SCN_PARTIAL_SCAN_IDLE_MSEC 100 + +#define MAXIMUM_OPERATION_CHANNEL_LIST 32 +#define SCN_P2P_FULL_SCAN_PARAM 0 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* The type of Scan Source */ +typedef enum _ENUM_SCN_REQ_SOURCE_T { + SCN_REQ_SOURCE_HEM = 0, + SCN_REQ_SOURCE_NET_FSM, + SCN_REQ_SOURCE_ROAMING, /* ROAMING Module is independent of AIS FSM */ + SCN_REQ_SOURCE_OBSS, /* 2.4G OBSS scan */ + SCN_REQ_SOURCE_NUM +} ENUM_SCN_REQ_SOURCE_T, +*P_ENUM_SCN_REQ_SOURCE_T; + +typedef enum _ENUM_SCAN_PROFILE_T { + SCAN_PROFILE_FULL = 0, + SCAN_PROFILE_PARTIAL, + SCAN_PROFILE_VOIP, + SCAN_PROFILE_FULL_2G4, + SCAN_PROFILE_NUM +} ENUM_SCAN_PROFILE_T, +*P_ENUM_SCAN_PROFILE_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/cnm_timer.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/cnm_timer.h new file mode 100644 index 00000000000000..63f83a8857bbb9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/cnm_timer.h @@ -0,0 +1,199 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file cnm_timer.h + * \brief Declaration of timer obj and related timer macro for setup time + * out event. + * + * In this file we declare the timer object and provide several macro for + * Protocol functional blocks to setup their own time out event. + */ + +#ifndef _CNM_TIMER_H +#define _CNM_TIMER_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#undef MSEC_PER_SEC +#define MSEC_PER_SEC 1000 +#undef USEC_PER_MSEC +#define USEC_PER_MSEC 1000 +#undef USEC_PER_SEC +#define USEC_PER_SEC 1000000 + +#define USEC_PER_TU 1024 /* microsecond */ + +#define MSEC_PER_MIN (60 * MSEC_PER_SEC) + +#define MGMT_MAX_TIMEOUT_INTERVAL ((u32)0x7fffffff) + +#define WAKE_LOCK_MAX_TIME 5 /* Unit: sec */ + +/* If WAKE_LOCK_MAX_TIME is too large, the whole system may always keep awake + * because of periodic timer of OBSS scanning + */ +#if (WAKE_LOCK_MAX_TIME >= OBSS_SCAN_MIN_INTERVAL) +#error WAKE_LOCK_MAX_TIME is too large +#endif + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef void (*PFN_MGMT_TIMEOUT_FUNC)(P_ADAPTER_T, unsigned long); + +typedef struct _TIMER_T { + LINK_ENTRY_T rLinkEntry; + u32 rExpiredSysTime; + u16 u2Minutes; + u16 u2Reserved; + unsigned long ulDataPtr; + PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc; +} TIMER_T, *P_TIMER_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/* Check if time "a" is before time "b" */ +/* In 32-bit variable, 0x00000001~0x7fffffff -> positive number, + * 0x80000000~0xffffffff -> negative number + */ +#define TIME_BEFORE_64bit(a, b) (a < b) + +#define TIME_BEFORE(a, b) ((u32)((u32)(a) - (u32)(b)) > 0x7fffffff) + +/* #define TIME_BEFORE(a,b) ((s32)((s32)(b) - (s32)(a)) > 0) + * may cause UNexpect result between Free build and Check build for WinCE + */ + +#define TIME_AFTER(a, b) TIME_BEFORE(b, a) + +#define SYSTIME_TO_SEC(_systime) ((_systime) / KAL_HZ) +#define SEC_TO_SYSTIME(_sec) ((_sec) * KAL_HZ) + +/* The macros to convert second & millisecond */ +#define MSEC_TO_SEC(_msec) ((_msec) / MSEC_PER_SEC) +#define SEC_TO_MSEC(_sec) ((u32)(_sec) * MSEC_PER_SEC) +#define SEC_TO_USEC(_sec) ((u32)(_sec) * USEC_PER_SEC) + +/* The macros to convert millisecond & microsecond */ +#define USEC_TO_MSEC(_usec) ((_usec) / USEC_PER_MSEC) +#define MSEC_TO_USEC(_msec) ((u32)(_msec) * USEC_PER_MSEC) + +/* The macros to convert TU & microsecond, TU & millisecond */ +#define TU_TO_USEC(_tu) ((_tu) * USEC_PER_TU) +#define TU_TO_MSEC(_tu) USEC_TO_MSEC(TU_TO_USEC(_tu)) + +/* The macros to convert TU & & OS system time, round up by 0.5 */ +#define TU_TO_SYSTIME(_tu) MSEC_TO_SYSTIME(TU_TO_MSEC(_tu)) +#define SYSTIME_TO_TU(_systime) \ + ((SYSTIME_TO_USEC(_systime) + ((USEC_PER_TU / 2) - 1)) / USEC_PER_TU) + +/* The macros to convert OS system time & microsecond */ +#define SYSTIME_TO_USEC(_systime) (((_systime) * USEC_PER_SEC) / KAL_HZ) + +/* The macro to get the current OS system time */ +#define GET_CURRENT_SYSTIME(_systime_p) \ + { \ + *(_systime_p) = kalGetTimeTick(); \ + } + +/* The macro to copy the system time */ +#define COPY_SYSTIME(_destTime, _srcTime) \ + { \ + (_destTime) = (_srcTime); \ + } + +/* The macro to get the system time difference between t1 and t2 (t1 - t2) */ +/* #define GET_SYSTIME_DIFFERENCE(_time1, _time2, _diffTime) \ + * (_diffTime) = (_time1) - (_time2) + */ + +/* The macro to check for the expiration, if true means _currentTime >= + * _expirationTime */ +#define CHECK_FOR_EXPIRATION(_currentTime, _expirationTime) \ + (((u32)(_currentTime) - (u32)(_expirationTime)) <= 0x7fffffffUL) + +/* The macro to check for the timeout */ +#define CHECK_FOR_TIMEOUT(_currentTime, _timeoutStartingTime, _timeout) \ + CHECK_FOR_EXPIRATION((_currentTime), \ + ((_timeoutStartingTime) + (_timeout))) + +/* The macro to set the expiration time with a specified timeout */ /* Watch out + * for + * round up. + */ +#define SET_EXPIRATION_TIME(_expirationTime, _timeout) \ + { \ + GET_CURRENT_SYSTIME(&(_expirationTime)); \ + (_expirationTime) += (u32)(_timeout); \ + } + +#define timerRenewTimer(adapter, tmr, interval) \ + timerStartTimer(adapter, tmr, interval, (tmr)->function, (tmr)->data) + +#define MGMT_INIT_TIMER(_adapter_p, _timer, _callbackFunc) \ + timerInitTimer(_adapter_p, &(_timer), (u32)(_callbackFunc)) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void cnmTimerInitialize(IN P_ADAPTER_T prAdapter); + +void cnmTimerDestroy(IN P_ADAPTER_T prAdapter); + +void cnmTimerInitTimer(IN P_ADAPTER_T prAdapter, + IN P_TIMER_T prTimer, + IN PFN_MGMT_TIMEOUT_FUNC pfFunc, + IN unsigned long ulDataPtr); + +void cnmTimerStopTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer); + +void cnmTimerStartTimer(IN P_ADAPTER_T prAdapter, + IN P_TIMER_T prTimer, + IN u32 u4TimeoutMs); + +void cnmTimerDoTimeOutCheck(IN P_ADAPTER_T prAdapter); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ +static __KAL_INLINE__ s32 timerPendingTimer(IN P_TIMER_T prTimer) +{ + ASSERT(prTimer); + + return prTimer->rLinkEntry.prNext != NULL; +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/hem_mbox.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/hem_mbox.h new file mode 100644 index 00000000000000..a7ec6c4dfcaef8 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/hem_mbox.h @@ -0,0 +1,273 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file hem_mbox.h + * \brief + * + */ + +#ifndef _HEM_MBOX_H +#define _HEM_MBOX_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* Message IDs */ +typedef enum _ENUM_MSG_ID_T { + MID_MNY_CNM_CH_REQ, /* MANY notify CNM to obtain channel privilege */ + MID_MNY_CNM_CH_ABORT, /* MANY notify CNM to abort/release channel + * privilege */ + + MID_CNM_AIS_CH_GRANT, /* CNM notify AIS for indicating channel granted + */ + MID_CNM_P2P_CH_GRANT, /* CNM notify P2P for indicating channel granted + */ + MID_CNM_BOW_CH_GRANT, /* CNM notify BOW for indicating channel granted + */ + +#if (CFG_SUPPORT_DFS_MASTER == 1) + MID_CNM_P2P_RADAR_DETECT, + MID_CNM_P2P_CSA_DONE, +#endif + /*--------------------------------------------------*/ + /* SCN Module Mailbox Messages */ + /*--------------------------------------------------*/ + MID_AIS_SCN_SCAN_REQ, /* AIS notify SCN for starting scan */ + MID_AIS_SCN_SCAN_REQ_V2, /* AIS notify SCN for starting scan with + * multiple SSID support */ + MID_AIS_SCN_SCAN_CANCEL, /* AIS notify SCN for cancelling scan */ + MID_P2P_SCN_SCAN_REQ, /* P2P notify SCN for starting scan */ + MID_P2P_SCN_SCAN_REQ_V2, /* P2P notify SCN for starting scan with + * multiple SSID support */ + MID_P2P_SCN_SCAN_CANCEL, /* P2P notify SCN for cancelling scan */ + MID_BOW_SCN_SCAN_REQ, /* BOW notify SCN for starting scan */ + MID_BOW_SCN_SCAN_REQ_V2, /* BOW notify SCN for starting scan with + * multiple SSID support */ + MID_BOW_SCN_SCAN_CANCEL, /* BOW notify SCN for cancelling scan */ + MID_RLM_SCN_SCAN_REQ, /* RLM notify SCN for starting scan (OBSS-SCAN) */ + MID_RLM_SCN_SCAN_REQ_V2, /* RLM notify SCN for starting scan (OBSS-SCAN) + * with multiple SSID support */ + MID_RLM_SCN_SCAN_CANCEL, /* RLM notify SCN for cancelling scan + * (OBSS-SCAN) */ + MID_SCN_AIS_SCAN_DONE, /* SCN notify AIS for scan completion */ + MID_SCN_P2P_SCAN_DONE, /* SCN notify P2P for scan completion */ + MID_SCN_BOW_SCAN_DONE, /* SCN notify BOW for scan completion */ + MID_SCN_RLM_SCAN_DONE, /* SCN notify RLM for scan completion (OBSS-SCAN) + */ + + /*--------------------------------------------------*/ + /* AIS Module Mailbox Messages */ + /*--------------------------------------------------*/ + MID_OID_AIS_FSM_JOIN_REQ, /* OID/IOCTL notify AIS for join */ + MID_OID_AIS_FSM_ABORT, /* OID/IOCTL notify AIS for abort */ + MID_AIS_SAA_FSM_START, /* AIS notify SAA for Starting + * authentication/association fsm */ + MID_AIS_SAA_FSM_ABORT, /* AIS notify SAA for Aborting + * authentication/association fsm */ + MID_SAA_AIS_JOIN_COMPLETE, /* SAA notify AIS for indicating join + * complete */ + +#if CFG_ENABLE_WIFI_DIRECT + /*--------------------------------------------------*/ + /* P2P Module Mailbox Messages */ + /*--------------------------------------------------*/ + MID_P2P_SAA_FSM_START, /* P2P notify SAA for Starting + * authentication/association fsm */ + MID_P2P_SAA_FSM_ABORT, /* P2P notify SAA for Aborting + * authentication/association fsm */ + MID_SAA_P2P_JOIN_COMPLETE, /* SAA notify P2P for indicating join + * complete */ + + MID_MNY_P2P_FUN_SWITCH, /* Enable P2P FSM. */ + MID_MNY_P2P_DEVICE_DISCOVERY, /* Start device discovery. */ + MID_MNY_P2P_CONNECTION_REQ, /* Connection request. */ + MID_MNY_P2P_CONNECTION_ABORT, /* Abort connection request, P2P FSM + * return to IDLE. */ + MID_MNY_P2P_BEACON_UPDATE, + MID_MNY_P2P_STOP_AP, + MID_MNY_P2P_CHNL_REQ, + MID_MNY_P2P_CHNL_ABORT, + MID_MNY_P2P_MGMT_TX, + MID_MNY_P2P_GROUP_DISSOLVE, + MID_MNY_P2P_MGMT_FRAME_REGISTER, + MID_MNY_P2P_NET_DEV_REGISTER, + MID_MNY_P2P_START_AP, + MID_MNY_P2P_DEL_IFACE, + MID_MNY_P2P_MGMT_FRAME_UPDATE, +#if (CFG_SUPPORT_DFS_MASTER == 1) + MID_MNY_P2P_DFS_CAC, + MID_MNY_P2P_SET_NEW_CHANNEL, +#endif +#if CFG_SUPPORT_WFD + MID_MNY_P2P_WFD_CFG_UPDATE, +#endif + MID_MNY_P2P_ACTIVE_BSS, +#endif + +#if CFG_SUPPORT_ADHOC + MID_SCN_AIS_FOUND_IBSS, /* SCN notify AIS that an IBSS Peer has been + * found and can merge into */ +#endif + + MID_SAA_AIS_FSM_ABORT, /* SAA notify AIS for indicating + * deauthentication/disassociation */ + + /*--------------------------------------------------*/ + /* AIS MGMT-TX Support */ + /*--------------------------------------------------*/ + MID_MNY_AIS_REMAIN_ON_CHANNEL, + MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL, + MID_MNY_AIS_MGMT_TX, +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + MID_WNM_AIS_BSS_TRANSITION, +#endif + MID_TOTAL_NUM +} ENUM_MSG_ID_T, +*P_ENUM_MSG_ID_T; + +/* Message header of inter-components */ +struct _MSG_HDR_T { + LINK_ENTRY_T rLinkEntry; + ENUM_MSG_ID_T eMsgId; +}; + +typedef void (*PFN_MSG_HNDL_FUNC)(P_ADAPTER_T, P_MSG_HDR_T); + +typedef struct _MSG_HNDL_ENTRY { + ENUM_MSG_ID_T eMsgId; + PFN_MSG_HNDL_FUNC pfMsgHndl; +} MSG_HNDL_ENTRY_T, *P_MSG_HNDL_ENTRY_T; + +typedef enum _EUNM_MSG_SEND_METHOD_T { + MSG_SEND_METHOD_BUF = 0, /* Message is put in the queue and will be */ + /*executed when mailbox is checked. */ + MSG_SEND_METHOD_UNBUF /* The handler function is called immediately */ + /* in the same context of the sender */ +} EUNM_MSG_SEND_METHOD_T, +*P_EUNM_MSG_SEND_METHOD_T; + +typedef enum _ENUM_MBOX_ID_T { + MBOX_ID_0 = 0, + MBOX_ID_TOTAL_NUM +} ENUM_MBOX_ID_T, +*P_ENUM_MBOX_ID_T; + +/* Define Mailbox structure */ +typedef struct _MBOX_T { + LINK_T rLinkHead; +} MBOX_T, *P_MBOX_T; + +typedef struct _MSG_SAA_FSM_START_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucSeqNum; + P_STA_RECORD_T prStaRec; +} MSG_SAA_FSM_START_T, *P_MSG_SAA_FSM_START_T; + +typedef struct _MSG_SAA_FSM_COMP_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucSeqNum; + WLAN_STATUS rJoinStatus; + P_STA_RECORD_T prStaRec; + P_SW_RFB_T prSwRfb; +} MSG_SAA_FSM_COMP_T, *P_MSG_SAA_FSM_COMP_T; + +typedef struct _MSG_SAA_FSM_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucSeqNum; + P_STA_RECORD_T prStaRec; +} MSG_SAA_FSM_ABORT_T, *P_MSG_SAA_FSM_ABORT_T; + +typedef struct _MSG_CONNECTION_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucNetTypeIndex; +} MSG_CONNECTION_ABORT_T, *P_MSG_CONNECTION_ABORT_T; + +typedef struct _MSG_REMAIN_ON_CHANNEL_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + ENUM_BAND_T eBand; + ENUM_CHNL_EXT_T eSco; + u8 ucChannelNum; + u32 u4DurationMs; + u64 u8Cookie; +} MSG_REMAIN_ON_CHANNEL_T, *P_MSG_REMAIN_ON_CHANNEL_T; + +typedef struct _MSG_CANCEL_REMAIN_ON_CHANNEL_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u64 u8Cookie; +} MSG_CANCEL_REMAIN_ON_CHANNEL_T, *P_MSG_CANCEL_REMAIN_ON_CHANNEL_T; + +typedef struct _MSG_MGMT_TX_REQUEST_T { + MSG_HDR_T rMsgHdr; + P_MSDU_INFO_T prMgmtMsduInfo; + u64 u8Cookie; /* For indication. */ + u8 fgNoneCckRate; + u8 fgIsWaitRsp; +} MSG_MGMT_TX_REQUEST_T, *P_MSG_MGMT_TX_REQUEST_T; + +/* specific message data types */ +typedef MSG_SAA_FSM_START_T MSG_JOIN_REQ_T, *P_MSG_JOIN_REQ_T; +typedef MSG_SAA_FSM_COMP_T MSG_JOIN_COMP_T, *P_MSG_JOIN_COMP_T; +typedef MSG_SAA_FSM_ABORT_T MSG_JOIN_ABORT_T, *P_MSG_JOIN_ABORT_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void mboxSetup(IN P_ADAPTER_T prAdapter, IN ENUM_MBOX_ID_T eMboxId); + +void mboxSendMsg(IN P_ADAPTER_T prAdapter, + IN ENUM_MBOX_ID_T eMboxId, + IN P_MSG_HDR_T prMsg, + IN EUNM_MSG_SEND_METHOD_T eMethod); + +void mboxRcvAllMsg(IN P_ADAPTER_T prAdapter, IN ENUM_MBOX_ID_T eMboxId); + +void mboxInitialize(IN P_ADAPTER_T prAdapter); + +void mboxDestroy(IN P_ADAPTER_T prAdapter); + +void mboxDummy(IN P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); + +void mboxInitMsgMap(void); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/mib.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/mib.h new file mode 100644 index 00000000000000..a91ca6aaf37bf5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/mib.h @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file mib.h + * \brief This file contains the IEEE 802.11 family related MIB definition + * for MediaTek 802.11 Wireless LAN Adapters. + */ + +#ifndef _MIB_H +#define _MIB_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* Entry in SMT AuthenticationAlgorithms Table: + * dot11AuthenticationAlgorithmsEntry */ +typedef struct _DOT11_AUTHENTICATION_ALGORITHMS_ENTRY { + u8 dot11AuthenticationAlgorithmsEnable; /* dot11AuthenticationAlgorithmsEntry + * 3 */ +} DOT11_AUTHENTICATION_ALGORITHMS_ENTRY, +*P_DOT11_AUTHENTICATION_ALGORITHMS_ENTRY; + +/* Entry in SMT dot11RSNAConfigPairwiseCiphersTalbe Table: + * dot11RSNAConfigPairwiseCiphersEntry */ +typedef struct _DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY { + u32 dot11RSNAConfigPairwiseCipher; /* dot11RSNAConfigPairwiseCiphersEntry + * 2 */ + u8 dot11RSNAConfigPairwiseCipherEnabled; /* dot11RSNAConfigPairwiseCiphersEntry + * 3 */ +} DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY, +*P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY; + +/* Entry in SMT dot11RSNAConfigAuthenticationSuitesTalbe Table: + * dot11RSNAConfigAuthenticationSuitesEntry */ +typedef struct _DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY { + u32 dot11RSNAConfigAuthenticationSuite; /* dot11RSNAConfigAuthenticationSuitesEntry + * 2 */ + u8 dot11RSNAConfigAuthenticationSuiteEnabled; /* dot11RSNAConfigAuthenticationSuitesEntry + * 3 */ +} DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY, +*P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY; + +/* ----- IEEE 802.11 MIB Major sections ----- */ +typedef struct _IEEE_802_11_MIB_T { + /* dot11PrivacyTable (dot11smt 5) */ + u8 dot11WEPDefaultKeyID; /* dot11PrivacyEntry 2 */ + u8 dot11TranmitKeyAvailable; + u32 dot11WEPICVErrorCount; /* dot11PrivacyEntry 5 */ + u32 dot11WEPExcludedCount; /* dot11PrivacyEntry 6 */ + + /* dot11RSNAConfigTable (dot11smt 8) */ + u32 dot11RSNAConfigGroupCipher; /* dot11RSNAConfigEntry 4 */ + + /* dot11RSNAConfigPairwiseCiphersTable (dot11smt 9) */ + DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY + dot11RSNAConfigPairwiseCiphersTable[ + MAX_NUM_SUPPORTED_CIPHER_SUITES]; + + /* dot11RSNAConfigAuthenticationSuitesTable (dot11smt 10) */ + DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY + dot11RSNAConfigAuthenticationSuitesTable[ + MAX_NUM_SUPPORTED_AKM_SUITES]; +} IEEE_802_11_MIB_T, *P_IEEE_802_11_MIB_T; + +/* ------------------ IEEE 802.11 non HT PHY characteristics ---------------- */ +typedef const struct _NON_HT_PHY_ATTRIBUTE_T { + u16 u2SupportedRateSet; + + u8 fgIsShortPreambleOptionImplemented; + + u8 fgIsShortSlotTimeOptionImplemented; +} NON_HT_PHY_ATTRIBUTE_T, *P_NON_HT_PHY_ATTRIBUTE_T; + +typedef const struct _NON_HT_ADHOC_MODE_ATTRIBUTE_T { + ENUM_PHY_TYPE_INDEX_T ePhyTypeIndex; + + u16 u2BSSBasicRateSet; +} NON_HT_ADHOC_MODE_ATTRIBUTE_T, *P_NON_HT_ADHOC_MODE_ATTRIBUTE_T; + +typedef NON_HT_ADHOC_MODE_ATTRIBUTE_T NON_HT_AP_MODE_ATTRIBUTE_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +extern NON_HT_PHY_ATTRIBUTE_T rNonHTPhyAttributes[]; +extern NON_HT_ADHOC_MODE_ATTRIBUTE_T rNonHTAdHocModeAttributes[]; +extern NON_HT_AP_MODE_ATTRIBUTE_T rNonHTApModeAttributes[]; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_assoc.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_assoc.h new file mode 100644 index 00000000000000..0288e754736845 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_assoc.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file p2p_assoc.h + * \brief This file contains the Wi-Fi Direct ASSOC REQ/RESP of + * IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. + */ + +#ifndef _P2P_ASSOC_H +#define _P2P_ASSOC_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +u8 *p2pBuildReAssocReqFrameCommonIEs(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN u8 *pucBuffer); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_dev.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_dev.h new file mode 100644 index 00000000000000..f02638df987faf --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_dev.h @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ +typedef enum _ENUM_P2P_DEV_STATE_T { + P2P_DEV_STATE_IDLE = 0, + P2P_DEV_STATE_SCAN, + P2P_DEV_STATE_REQING_CHANNEL, + P2P_DEV_STATE_CHNL_ON_HAND, + P2P_DEV_STATE_OFF_CHNL_TX, /* Requesting Channel to Send Specific Frame. + */ + P2P_DEV_STATE_NUM +} ENUM_P2P_DEV_STATE_T, +*P_ENUM_P2P_DEV_STATE_T; + +/*-------------------- EVENT MESSAGE ---------------------*/ +typedef struct _MSG_P2P_SCAN_REQUEST_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucBssIdx; + ENUM_SCAN_TYPE_T eScanType; + P_P2P_SSID_STRUCT_T prSSID; + s32 i4SsidNum; + u32 u4NumChannel; + u8 *pucIEBuf; + u32 u4IELen; + u8 fgIsAbort; + RF_CHANNEL_INFO_T arChannelListInfo[1]; +} MSG_P2P_SCAN_REQUEST_T, *P_MSG_P2P_SCAN_REQUEST_T; + +typedef struct _MSG_P2P_CHNL_REQUEST_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u64 u8Cookie; + u32 u4Duration; + ENUM_CHNL_EXT_T eChnlSco; + RF_CHANNEL_INFO_T rChannelInfo; + ENUM_CH_REQ_TYPE_T eChnlReqType; +} MSG_P2P_CHNL_REQUEST_T, *P_MSG_P2P_CHNL_REQUEST_T; + +typedef struct _MSG_P2P_MGMT_TX_REQUEST_T { + MSG_HDR_T rMsgHdr; + u8 ucBssIdx; + P_MSDU_INFO_T prMgmtMsduInfo; + u64 u8Cookie; /* For indication. */ + u8 fgNoneCckRate; + u8 fgIsOffChannel; + RF_CHANNEL_INFO_T rChannelInfo; /* Off channel TX. */ + ENUM_CHNL_EXT_T eChnlExt; + u8 fgIsWaitRsp; +} MSG_P2P_MGMT_TX_REQUEST_T, *P_MSG_P2P_MGMT_TX_REQUEST_T; + +#if CFG_SUPPORT_WFD + +#define WFD_FLAGS_DEV_INFO_VALID \ + BIT(0) /* 1. WFD_DEV_INFO, 2. WFD_CTRL_PORT, 3. WFD_MAT_TP. */ +#define WFD_FLAGS_SINK_INFO_VALID \ + BIT(1) /* 1. WFD_SINK_STATUS, 2. WFD_SINK_MAC. */ +#define WFD_FLAGS_ASSOC_MAC_VALID BIT(2) /* 1. WFD_ASSOC_MAC. */ +#define WFD_FLAGS_EXT_CAPABILITY_VALID BIT(3) /* 1. WFD_EXTEND_CAPABILITY. */ + +struct _WFD_CFG_SETTINGS_T { + u32 u4WfdCmdType; + u8 ucWfdEnable; + u8 ucWfdCoupleSinkStatus; + u8 ucWfdSessionAvailable; /* 0: NA 1:Set 2:Clear */ + u8 ucWfdSigmaMode; + u16 u2WfdDevInfo; + u16 u2WfdControlPort; + u16 u2WfdMaximumTp; + u16 u2WfdExtendCap; + u8 aucWfdCoupleSinkAddress[MAC_ADDR_LEN]; + u8 aucWfdAssociatedBssid[MAC_ADDR_LEN]; + u8 aucWfdVideoIp[4]; + u8 aucWfdAudioIp[4]; + u16 u2WfdVideoPort; + u16 u2WfdAudioPort; + u32 u4WfdFlag; + u32 u4WfdPolicy; + u32 u4WfdState; + u8 aucWfdSessionInformationIE[24 * 8]; + u16 u2WfdSessionInformationIELen; + u8 aucReserved1[2]; + u8 aucWfdPrimarySinkMac[MAC_ADDR_LEN]; + u8 aucWfdSecondarySinkMac[MAC_ADDR_LEN]; + u32 u4WfdAdvancedFlag; + /* Group 1 64 bytes */ + u8 aucWfdLocalIp[4]; + u16 u2WfdLifetimeAc2; /* Unit is 2 TU */ + u16 u2WfdLifetimeAc3; /* Unit is 2 TU */ + u16 u2WfdCounterThreshold; /* Unit is ms */ + u8 aucReverved2[54]; + /* Group 2 64 bytes */ + u8 aucReverved3[64]; + /* Group 3 64 bytes */ + u8 aucReverved4[64]; +}; + +#endif + +typedef struct _MSG_P2P_ACTIVE_DEV_BSS_T { + MSG_HDR_T rMsgHdr; +} MSG_P2P_ACTIVE_DEV_BSS_T, *P_MSG_P2P_ACTIVE_DEV_BSS_T; + +/*-------------------- P2P FSM ACTION STRUCT ---------------------*/ + +typedef struct _P2P_OFF_CHNL_TX_REQ_INFO_T { + LINK_ENTRY_T rLinkEntry; + P_MSDU_INFO_T prMgmtTxMsdu; + u8 fgNoneCckRate; + RF_CHANNEL_INFO_T rChannelInfo; /* Off channel TX. */ + ENUM_CHNL_EXT_T eChnlExt; + u8 fgIsWaitRsp; /* See if driver should keep at the same channel. */ +} P2P_OFF_CHNL_TX_REQ_INFO_T, *P_P2P_OFF_CHNL_TX_REQ_INFO_T; + +typedef struct _P2P_MGMT_TX_REQ_INFO_T { + LINK_T rP2pTxReqLink; + P_MSDU_INFO_T prMgmtTxMsdu; + u8 fgIsWaitRsp; +} P2P_MGMT_TX_REQ_INFO_T, *P_P2P_MGMT_TX_REQ_INFO_T; + +struct _P2P_DEV_FSM_INFO_T { + u8 ucBssIndex; + /* State related. */ + ENUM_P2P_DEV_STATE_T eCurrentState; + + /* Channel related. */ + P2P_CHNL_REQ_INFO_T rChnlReqInfo; + + /* Scan related. */ + P2P_SCAN_REQ_INFO_T rScanReqInfo; + + /* Mgmt tx related. */ + P2P_MGMT_TX_REQ_INFO_T rMgmtTxInfo; + + /* FSM Timer */ + TIMER_T rP2pFsmTimeoutTimer; + + /* Packet filter for P2P module. */ + u32 u4P2pPacketFilter; +}; + +typedef struct _MSG_P2P_NETDEV_REGISTER_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 fgIsEnable; + u8 ucMode; +} MSG_P2P_NETDEV_REGISTER_T, *P_MSG_P2P_NETDEV_REGISTER_T; + +#if CFG_SUPPORT_WFD +typedef struct _MSG_WFD_CONFIG_SETTINGS_CHANGED_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + P_WFD_CFG_SETTINGS_T prWfdCfgSettings; +} MSG_WFD_CONFIG_SETTINGS_CHANGED_T, *P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T; +#endif + +/*========================= Initial ============================*/ + +u8 p2pDevFsmInit(IN P_ADAPTER_T prAdapter); + +void p2pDevFsmUninit(IN P_ADAPTER_T prAdapter); + +/*========================= FUNCTIONs ============================*/ + +void p2pDevFsmStateTransition(IN P_ADAPTER_T prAdapter, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo, + IN ENUM_P2P_DEV_STATE_T eNextState); + +void p2pDevFsmRunEventAbort(IN P_ADAPTER_T prAdapter, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo); + +void p2pDevFsmRunEventTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr); + +/*================ Message Event =================*/ +void p2pDevFsmRunEventScanRequest(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pDevFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo); + +void p2pDevFsmRunEventChannelRequest(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pDevFsmRunEventChannelAbort(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pDevFsmRunEventChnlGrant(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo); + +void p2pDevFsmRunEventMgmtTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +WLAN_STATUS +p2pDevFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +void p2pDevFsmRunEventMgmtFrameRegister(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +/* /////////////////////////////// */ + +void p2pDevFsmRunEventActiveDevBss(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pDevFsmRunEventScanAbort(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx); diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_dev_state.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_dev_state.h new file mode 100644 index 00000000000000..b897c0d2506bfc --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_dev_state.h @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ +#ifndef _P2P_DEV_STATE_H +#define _P2P_DEV_STATE_H + +u8 p2pDevStateInit_IDLE(IN P_ADAPTER_T prAdapter, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + OUT P_ENUM_P2P_DEV_STATE_T peNextState); + +void p2pDevStateAbort_IDLE(IN P_ADAPTER_T prAdapter); + +u8 p2pDevStateInit_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIdx, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + OUT P_ENUM_P2P_DEV_STATE_T peNextState); + +void p2pDevStateAbort_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN ENUM_P2P_DEV_STATE_T eNextState); + +void p2pDevStateInit_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +void p2pDevStateAbort_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +void p2pDevStateInit_SCAN(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); + +void p2pDevStateAbort_SCAN(IN P_ADAPTER_T prAdapter, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo); + +u8 p2pDevStateInit_OFF_CHNL_TX(IN P_ADAPTER_T prAdapter, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN P_P2P_MGMT_TX_REQ_INFO_T prP2pMgmtTxInfo, + OUT P_ENUM_P2P_DEV_STATE_T peNextState); + +void p2pDevStateAbort_OFF_CHNL_TX(IN P_ADAPTER_T prAdapter, + IN P_P2P_MGMT_TX_REQ_INFO_T prP2pMgmtTxInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN ENUM_P2P_DEV_STATE_T eNextState); + +u8 p2pDevStateInit_IDLE(IN P_ADAPTER_T prAdapter, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + OUT P_ENUM_P2P_DEV_STATE_T peNextState); + +void p2pDevStateAbort_IDLE(IN P_ADAPTER_T prAdapter); + +u8 p2pDevStateInit_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + OUT P_ENUM_P2P_DEV_STATE_T peNextState); + +void p2pDevStateAbort_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN ENUM_P2P_DEV_STATE_T eNextState); + +void p2pDevStateInit_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +void p2pDevStateAbort_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +void p2pDevStateInit_SCAN(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); + +void p2pDevStateAbort_SCAN(IN P_ADAPTER_T prAdapter, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo); + +u8 p2pDevStateInit_OFF_CHNL_TX(IN P_ADAPTER_T prAdapter, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN P_P2P_MGMT_TX_REQ_INFO_T prP2pMgmtTxInfo, + OUT P_ENUM_P2P_DEV_STATE_T peNextState); + +void p2pDevStateAbort_OFF_CHNL_TX(IN P_ADAPTER_T prAdapter, + IN P_P2P_MGMT_TX_REQ_INFO_T prP2pMgmtTxInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN ENUM_P2P_DEV_STATE_T eNextState); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_fsm.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_fsm.h new file mode 100644 index 00000000000000..de956e46639db7 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_fsm.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file p2p_fsm.h + * \brief Declaration of functions and finite state machine for P2P Module. + * + * Declaration of functions and finite state machine for P2P Module. + */ + +#ifndef _P2P_FSM_H +#define _P2P_FSM_H + +void p2pFsmRunEventScanRequest(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +void p2pFsmRunEventNetDeviceRegister(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pFsmRunEventUpdateMgmtFrame(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +#if CFG_SUPPORT_WFD +void p2pFsmRunEventWfdSettingUpdate(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); +#endif + +void p2pFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_func.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_func.h new file mode 100644 index 00000000000000..50a30513add923 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_func.h @@ -0,0 +1,386 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ +#ifndef _P2P_FUNC_H +#define _P2P_FUNC_H + +#include "precomp.h" + +#define P2P_OFF_CHNL_TX_DEFAULT_TIME_MS 1000 + +#if (CFG_SUPPORT_DFS_MASTER == 1) +extern struct P2P_RADAR_INFO g_rP2pRadarInfo; + +enum _ENUM_DFS_STATE_T { + DFS_STATE_INACTIVE = 0, + DFS_STATE_CHECKING, + DFS_STATE_ACTIVE, + DFS_STATE_DETECTED, + DFS_STATE_NUM +}; +#endif + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define ATTRI_ID(_fp) (((P_P2P_ATTRIBUTE_T)_fp)->ucId) +#define ATTRI_LEN(_fp) \ + (((u16)((u8 *)&((P_P2P_ATTRIBUTE_T)_fp)->u2Length)[0]) | \ + ((u16)((u8 *)&((P_P2P_ATTRIBUTE_T)_fp)->u2Length)[1] << 8)) + +#define ATTRI_SIZE(_fp) (P2P_ATTRI_HDR_LEN + ATTRI_LEN(_fp)) + +#define P2P_ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ + for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ + (_u2Offset) += ATTRI_SIZE(_pucAttriBuf), \ + ((_pucAttriBuf) += ATTRI_SIZE(_pucAttriBuf))) + +#define P2P_IE(_fp) ((P_IE_P2P_T)_fp) + +#define WSC_ATTRI_ID(_fp) \ + (((u16)((u8 *)&((P_WSC_ATTRIBUTE_T)_fp)->u2Id)[0] << 8) | \ + ((u16)((u8 *)&((P_WSC_ATTRIBUTE_T)_fp)->u2Id)[1])) + +#define WSC_ATTRI_LEN(_fp) \ + (((u16)((u8 *)&((P_WSC_ATTRIBUTE_T)_fp)->u2Length)[0] << 8) | \ + ((u16)((u8 *)&((P_WSC_ATTRIBUTE_T)_fp)->u2Length)[1])) + +#define WSC_ATTRI_SIZE(_fp) (WSC_ATTRI_HDR_LEN + WSC_ATTRI_LEN(_fp)) + +#define WSC_ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ + for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ + (_u2Offset) += WSC_ATTRI_SIZE(_pucAttriBuf), \ + ((_pucAttriBuf) += WSC_ATTRI_SIZE(_pucAttriBuf))) + +#define WSC_IE(_fp) ((P_IE_P2P_T)_fp) + +#define WFD_ATTRI_SIZE(_fp) (P2P_ATTRI_HDR_LEN + WSC_ATTRI_LEN(_fp)) + +#define WFD_ATTRI_FOR_EACH(_pucAttriBuf, _u2AttriBufLen, _u2Offset) \ + for ((_u2Offset) = 0; ((_u2Offset) < (_u2AttriBufLen)); \ + (_u2Offset) += WFD_ATTRI_SIZE(_pucAttriBuf), \ + ((_pucAttriBuf) += WFD_ATTRI_SIZE(_pucAttriBuf))) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void p2pFuncRequestScan(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); + +void p2pFuncCancelScan(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); + +void p2pFuncUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + IN P_STA_RECORD_T prStaRec, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_SW_RFB_T prAssocRspSwRfb); + +void p2pFuncAcquireCh(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIdx, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +void p2pFuncDisconnect(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_STA_RECORD_T prStaRec, + IN u8 fgSendDeauth, + IN u16 u2ReasonCode, + IN u8 fgIsLocallyGenerated); + +P_BSS_INFO_T p2pFuncBSSIDFindBssInfo(IN P_ADAPTER_T prAdapter, IN u8 *pucBSSID); + +/* //////////////////////////////// MT6630 CODE + * //////////////////////////////////// */ + +void p2pFuncGCJoin(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_JOIN_INFO_T prP2pJoinInfo); + +void p2pFuncStopComplete(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo); + +void p2pFuncStartGO(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo, + IN P_P2P_CHNL_REQ_INFO_T prP2pChnlReqInfo); + +void p2pFuncStopGO(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo); + +WLAN_STATUS p2pFuncRoleToBssIdx(IN P_ADAPTER_T prAdapter, + IN u8 ucRoleIdx, + OUT u8 *pucBssIdx); + +P_P2P_ROLE_FSM_INFO_T p2pFuncGetRoleByBssIdx(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex); + +void p2pFuncSwitchOPMode(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN ENUM_OP_MODE_T eOpMode, + IN u8 fgSyncToFW); + +void p2pFuncReleaseCh(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIdx, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +#if (CFG_SUPPORT_DFS_MASTER == 1) +void p2pFuncStartRdd(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx); + +void p2pFuncStopRdd(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx); + +void p2pFuncDfsSwitchCh(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P2P_CHNL_REQ_INFO_T rP2pChnlReqInfo); + +u8 p2pFuncCheckWeatherRadarBand(IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +s32 p2pFuncSetDriverCacTime(IN u32 u4CacTime); + +void p2pFuncEnableManualCac(void); + +u32 p2pFuncGetDriverCacTime(void); + +u8 p2pFuncIsManualCac(void); + +void p2pFuncRadarInfoInit(void); + +void p2pFuncShowRadarInfo(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx); + +void p2pFuncGetRadarInfo(IN struct P2P_RADAR_INFO *prP2pRadarInfo); + +u8 *p2pFuncJpW53RadarType(void); + +u8 *p2pFuncJpW56RadarType(void); + +void p2pFuncSetRadarDetectMode(IN u8 ucRadarDetectMode); + +u8 p2pFuncGetRadarDetectMode(void); + +void p2pFuncSetDfsState(IN u8 ucDfsState); + +u8 p2pFuncGetDfsState(void); + +u8 *p2pFuncShowDfsState(void); + +void p2pFuncRecordCacStartBootTime(void); + +u32 p2pFuncGetCacRemainingTime(void); +#endif + +void p2pFuncSetChannel(IN P_ADAPTER_T prAdapter, + IN u8 ucRoleIdx, + IN P_RF_CHANNEL_INFO_T prRfChannelInfo); + +u8 p2pFuncRetryJOIN(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_P2P_JOIN_INFO_T prJoinInfo); + +WLAN_STATUS +p2pFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_MSDU_INFO_T prMgmtTxMsdu, + IN u8 fgNonCckRate); + +WLAN_STATUS +p2pFuncBeaconUpdate(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_BEACON_UPDATE_INFO_T prBcnUpdateInfo, + IN u8 *pucNewBcnHdr, + IN u32 u4NewHdrLen, + IN u8 *pucNewBcnBody, + IN u32 u4NewBodyLen); + +WLAN_STATUS +p2pFuncAssocRespUpdate(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN u8 *AssocRespIE, + IN u32 u4AssocRespLen); + +u8 p2pFuncValidateAuth(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_SW_RFB_T prSwRfb, + IN PP_STA_RECORD_T pprStaRec, + OUT u16 *pu2StatusCode); + +u8 p2pFuncValidateAssocReq(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT u16 *pu2StatusCode); + +void p2pFuncResetStaRecStatus(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec); + +void p2pFuncInitConnectionSettings(IN P_ADAPTER_T prAdapter, + IN P_P2P_CONNECTION_SETTINGS_T + prP2PConnSettings, + IN u8 fgIsApMode); + +u8 p2pFuncParseCheckForTKIPInfoElem(IN u8 *pucBuf); + +u8 p2pFuncParseCheckForP2PInfoElem(IN P_ADAPTER_T prAdapter, + IN u8 *pucBuf, + OUT u8 *pucOuiType); + +u8 p2pFuncValidateProbeReq(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT u32 *pu4ControlFlags, + IN u8 fgIsDevInterface, + IN u8 ucRoleIdx); + +void p2pFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN u8 fgIsDevInterface, + IN u8 ucRoleIdx); + +u8 p2pFuncIsAPMode(IN P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings); + +void p2pFuncParseBeaconContent(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN u8 *pucIEInfo, + IN u32 u4IELen); + +P_BSS_DESC_T +p2pFuncKeepOnConnection(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); + +void p2pFuncStoreAssocRspIEBuffer(IN P_ADAPTER_T prAdapter, + IN P_P2P_JOIN_INFO_T prP2pJoinInfo, + IN P_SW_RFB_T prSwRfb); + +void p2pFuncMgmtFrameRegister(IN P_ADAPTER_T prAdapter, + IN u16 u2FrameType, + IN u8 fgIsRegistered, + OUT u32 *pu4P2pPacketFilter); + +void p2pFuncUpdateMgmtFrameRegister(IN P_ADAPTER_T prAdapter, + IN u32 u4OsFilter); + +void p2pFuncGetStationInfo(IN P_ADAPTER_T prAdapter, + IN u8 *pucMacAddr, + OUT P_P2P_STATION_INFO_T prStaInfo); + +P_MSDU_INFO_T p2pFuncProcessP2pProbeRsp(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIdx, + IN P_MSDU_INFO_T prMgmtTxMsdu); + +u32 p2pFuncCalculateP2p_IELenForBeacon(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_STA_RECORD_T prStaRec); + +void p2pFuncGenerateP2p_IEForBeacon(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +u32 p2pFuncCalculateWSC_IELenForBeacon(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_STA_RECORD_T prStaRec); + +void p2pFuncGenerateWSC_IEForBeacon(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +u32 p2pFuncCalculateP2p_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_STA_RECORD_T prStaRec); + +void p2pFuncGenerateP2p_IEForAssocRsp(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +u32 p2pFuncCalculateP2P_IELen(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_STA_RECORD_T prStaRec, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], + IN u32 u4AttriTableSize); + +void p2pFuncGenerateP2P_IE(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN u8 fgIsAssocFrame, + IN u16 *pu2Offset, + IN u8 *pucBuf, + IN u16 u2BufSize, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], + IN u32 u4AttriTableSize); + +u32 p2pFuncAppendAttriStatusForAssocRsp(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN u8 fgIsAssocFrame, + IN u16 *pu2Offset, + IN u8 *pucBuf, + IN u16 u2BufSize); + +u32 p2pFuncAppendAttriExtListenTiming(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN u8 fgIsAssocFrame, + IN u16 *pu2Offset, + IN u8 *pucBuf, + IN u16 u2BufSize); + +void p2pFuncDissolve(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN u8 fgSendDeauth, + IN u16 u2ReasonCode, + IN u8 fgIsLocallyGenerated); + +P_IE_HDR_T +p2pFuncGetSpecIE(IN P_ADAPTER_T prAdapter, + IN u8 *pucIEBuf, + IN u16 u2BufferLen, + IN u8 ucElemID, + IN u8 *pfgIsMore); + +P_ATTRIBUTE_HDR_T +p2pFuncGetSpecAttri(IN P_ADAPTER_T prAdapter, + IN u8 ucOuiType, + IN u8 *pucIEBuf, + IN u16 u2BufferLen, + IN u8 ucAttriID); + +u32 wfdFuncCalculateWfdIELenForAssocRsp(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_STA_RECORD_T prStaRec); + +void wfdFuncGenerateWfdIEForAssocRsp(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +u32 p2pFuncCalculateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIdx, + IN P_STA_RECORD_T prStaRec); + +void p2pFuncGenerateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +void p2pFuncClassifyAction(IN P_SW_RFB_T prSwRfb); + +#if CFG_SUPPORT_DBDC_TC6 +void p2pFuncModifyChandef(IN P_ADAPTER_T prAdapter, + IN P_GL_P2P_INFO_T prGlueP2pInfo, + IN P_BSS_INFO_T prBssInfo); +#else +u8 p2pFuncSwitchSapChannel(IN P_ADAPTER_T prAdapter); +#endif + +WLAN_STATUS +p2pFuncGenerateBeaconProbeRsp(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_MSDU_INFO_T prMsduInfo, IN u8 fgIsProbeRsp); + +WLAN_STATUS +p2pFuncComposeBeaconProbeRspTemplate( + IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN u8 *pucBcnBuffer, + IN u32 u4BcnBufLen, IN u8 fgIsProbeRsp, + IN P_P2P_PROBE_RSP_UPDATE_INFO_T prP2pProbeRspInfo, IN u8 fgSynToFW); + +void p2pFuncComposeNoaAttribute(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + OUT u8 *aucNoaAttrArray, OUT u32 *pu4Len); + +WLAN_STATUS +p2pFunMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_ie.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_ie.h new file mode 100644 index 00000000000000..ab9e1a44c37bd7 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_ie.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ +#ifndef _P2P_IE_H +#define _P2P_IE_H + +#if CFG_SUPPORT_WFD + +#define ELEM_MAX_LEN_WFD 62 /* TODO: Move to appropriate place */ + +/*---------------- WFD Data Element Definitions ----------------*/ +/* WFD 4.1.1 - WFD IE format */ +#define WFD_OUI_TYPE_LEN 4 + +/* == OFFSET_OF(IE_P2P_T,*/ +/*aucP2PAttributes[0]) */ +#define WFD_IE_OUI_HDR (ELEM_HDR_LEN + WFD_OUI_TYPE_LEN) + +/* WFD 4.1.1 - General WFD Attribute */ +#define WFD_ATTRI_HDR_LEN 3 /* ID(1 octet) + Length(2 octets) */ + +/* WFD Attribute Code */ +#define WFD_ATTRI_ID_DEV_INFO 0 +#define WFD_ATTRI_ID_ASSOC_BSSID 1 +#define WFD_ATTRI_ID_COUPLED_SINK_INFO 6 +#define WFD_ATTRI_ID_EXT_CAPABILITY 7 +#define WFD_ATTRI_ID_SESSION_INFO 9 +#define WFD_ATTRI_ID_ALTER_MAC_ADDRESS 10 + +/* Maximum Length of WFD Attributes */ +#define WFD_ATTRI_MAX_LEN_DEV_INFO 6 /* 0 */ +#define WFD_ATTRI_MAX_LEN_ASSOC_BSSID 6 /* 1 */ +#define WFD_ATTRI_MAX_LEN_COUPLED_SINK_INFO 7 /* 6 */ +#define WFD_ATTRI_MAX_LEN_EXT_CAPABILITY 2 /* 7 */ +#define WFD_ATTRI_MAX_LEN_SESSION_INFO 0 /* 9 */ /* 24 * #Clients */ +#define WFD_ATTRI_MAX_LEN_ALTER_MAC_ADDRESS 6 /* 10 */ + +typedef struct _WFD_DEVICE_INFORMATION_IE_T { + u8 ucElemID; + u16 u2Length; + u16 u2WfdDevInfo; + u16 u2SessionMgmtCtrlPort; + u16 u2WfdDevMaxSpeed; +} __KAL_ATTRIB_PACKED__ WFD_DEVICE_INFORMATION_IE_T, +*P_WFD_DEVICE_INFORMATION_IE_T; + +#endif + +u32 p2pCalculate_IEForAssocReq(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_STA_RECORD_T prStaRec); + +void p2pGenerate_IEForAssocReq(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +u32 wfdFuncAppendAttriDevInfo(IN P_ADAPTER_T prAdapter, IN u8 fgIsAssocFrame, + IN u16 *pu2Offset, IN u8 *pucBuf, + IN u16 u2BufSize); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_rlm.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_rlm.h new file mode 100644 index 00000000000000..95e554c85b6e66 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_rlm.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "rlm.h" + * \brief + */ + +#ifndef _P2P_RLM_H +#define _P2P_RLM_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define CHANNEL_SPAN_20 20 + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void rlmBssInitForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +u8 rlmUpdateBwByChListForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +void rlmUpdateParamsForAP(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + u8 fgUpdateBeacon); + +void rlmFuncInitialChannelList(IN P_ADAPTER_T prAdapter); + +void rlmFuncCommonChannelList(IN P_ADAPTER_T prAdapter, + IN P_CHANNEL_ENTRY_FIELD_T prChannelEntryII, + IN u8 ucChannelListSize); + +u8 rlmFuncFindOperatingClass(IN P_ADAPTER_T prAdapter, IN u8 ucChannelNum); + +u8 rlmFuncFindAvailableChannel(IN P_ADAPTER_T prAdapter, + IN u8 ucCheckChnl, + IN u8 *pucSuggestChannel, + IN u8 fgIsSocialChannel, + IN u8 fgIsDefaultChannel); + +ENUM_CHNL_EXT_T rlmDecideScoForAP(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo); + +ENUM_CHNL_EXT_T rlmGetScoForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +u8 rlmGetVhtS1ForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_rlm_obss.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_rlm_obss.h new file mode 100644 index 00000000000000..bbc60cdb622ee4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_rlm_obss.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "rlm_obss.h" + * \brief + */ + +#ifndef _P2P_RLM_OBSS_H +#define _P2P_RLM_OBSS_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void rlmRspGenerateObssScanIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +void rlmProcessPublicAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); + +void rlmHandleObssStatusEventPkt(P_ADAPTER_T prAdapter, + P_EVENT_AP_OBSS_STATUS_T prObssStatus); + +u8 rlmObssChnlLevel(P_BSS_INFO_T prBssInfo, + ENUM_BAND_T eBand, + u8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend); + +void rlmObssScanExemptionRsp(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_SW_RFB_T prSwRfb); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_role.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_role.h new file mode 100644 index 00000000000000..6cd3a517275c11 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_role.h @@ -0,0 +1,433 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +#ifndef _P2P_ROLE_H +#define _P2P_ROLE_H + +typedef enum _ENUM_BUFFER_TYPE_T { + ENUM_FRAME_TYPE_EXTRA_IE_BEACON, + ENUM_FRAME_TYPE_EXTRA_IE_ASSOC_RSP, + ENUM_FRAME_TYPE_EXTRA_IE_PROBE_RSP, + ENUM_FRAME_TYPE_PROBE_RSP_TEMPLATE, + ENUM_FRAME_TYPE_BEACON_TEMPLATE, + ENUM_FRAME_IE_NUM +} ENUM_BUFFER_TYPE_T, +*P_ENUM_BUFFER_TYPE_T; + +typedef enum _ENUM_HIDDEN_SSID_TYPE_T { + ENUM_HIDDEN_SSID_NONE, + ENUM_HIDDEN_SSID_LEN, + ENUM_HIDDEN_SSID_ZERO_CONTENT, + ENUM_HIDDEN_SSID_NUM +} ENUM_HIDDEN_SSID_TYPE_T, +*P_ENUM_HIDDEN_SSID_TYPE_T; + +typedef struct _P2P_BEACON_UPDATE_INFO_T { + u8 *pucBcnHdr; + u32 u4BcnHdrLen; + u8 *pucBcnBody; + u32 u4BcnBodyLen; +} P2P_BEACON_UPDATE_INFO_T, *P_P2P_BEACON_UPDATE_INFO_T; + +typedef struct _P2P_PROBE_RSP_UPDATE_INFO_T { + P_MSDU_INFO_T prProbeRspMsduTemplate; +} P2P_PROBE_RSP_UPDATE_INFO_T, *P_P2P_PROBE_RSP_UPDATE_INFO_T; + +typedef struct _P2P_ASSOC_RSP_UPDATE_INFO_T { + u8 *pucAssocRspExtIE; + u16 u2AssocIELen; +} P2P_ASSOC_RSP_UPDATE_INFO_T, *P_P2P_ASSOC_RSP_UPDATE_INFO_T; + +typedef struct _AP_CRYPTO_SETTINGS_T { + u32 u4WpaVersion; + u32 u4CipherGroup; + s32 i4NumOfCiphers; + u32 aucCiphersPairwise[5]; + s32 i4NumOfAkmSuites; + u32 aucAkmSuites[2]; + u8 fgIsControlPort; + u16 u2ControlPortBE; + u8 fgIsControlPortEncrypt; +} AP_CRYPTO_SETTINGS_T, *P_AP_CRYPTO_SETTINGS_T; + +/* ////////////////////////////////// Message + * /////////////////////////////////// */ + +typedef struct _MSG_P2P_BEACON_UPDATE_T { + MSG_HDR_T rMsgHdr; + u8 ucRoleIndex; + u32 u4BcnHdrLen; + u32 u4BcnBodyLen; + u32 u4AssocRespLen; + u8 *pucBcnHdr; + u8 *pucBcnBody; + u8 *pucAssocRespIE; + u8 fgIsWepCipher; + u8 aucBuffer[1]; /* Header & Body & Extra IEs are put here. */ +} MSG_P2P_BEACON_UPDATE_T, *P_MSG_P2P_BEACON_UPDATE_T; + +typedef struct _MSG_P2P_MGMT_FRAME_UPDATE_T { + MSG_HDR_T rMsgHdr; + ENUM_BUFFER_TYPE_T eBufferType; + u32 u4BufferLen; + u8 aucBuffer[1]; +} MSG_P2P_MGMT_FRAME_UPDATE_T, *P_MSG_P2P_MGMT_FRAME_UPDATE_T; + +typedef struct _MSG_P2P_SWITCH_OP_MODE_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + ENUM_OP_MODE_T eOpMode; + u8 ucRoleIdx; +} MSG_P2P_SWITCH_OP_MODE_T, *P_MSG_P2P_SWITCH_OP_MODE_T; + +typedef struct _MSG_P2P_MGMT_FRAME_REGISTER_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u16 u2FrameType; + u8 fgIsRegister; +} MSG_P2P_MGMT_FRAME_REGISTER_T, *P_MSG_P2P_MGMT_FRAME_REGISTER_T; + +typedef struct _MSG_P2P_CHNL_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u64 u8Cookie; +} MSG_P2P_CHNL_ABORT_T, *P_MSG_P2P_CHNL_ABORT_T; + +typedef struct _MSG_P2P_CONNECTION_REQUEST_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucRoleIdx; + P2P_SSID_STRUCT_T rSsid; + u8 aucBssid[MAC_ADDR_LEN]; + u8 aucSrcMacAddr[MAC_ADDR_LEN]; + ENUM_CHNL_EXT_T eChnlSco; + RF_CHANNEL_INFO_T rChannelInfo; + u32 u4IELen; + u8 aucIEBuf[1]; + /* TODO: Auth Type, OPEN, SHARED, FT, EAP... */ +} MSG_P2P_CONNECTION_REQUEST_T, *P_MSG_P2P_CONNECTION_REQUEST_T; + +typedef struct _MSG_P2P_CONNECTION_ABORT_T { + MSG_HDR_T rMsgHdr; /* Must be the first member. */ + u8 ucRoleIdx; + u8 aucTargetID[MAC_ADDR_LEN]; + u16 u2ReasonCode; + u8 fgSendDeauth; +} MSG_P2P_CONNECTION_ABORT_T, *P_MSG_P2P_CONNECTION_ABORT_T; + +typedef struct _MSG_P2P_START_AP_T { + MSG_HDR_T rMsgHdr; + u32 u4DtimPeriod; + u32 u4BcnInterval; + u8 aucSsid[32]; + u16 u2SsidLen; + u8 ucHiddenSsidType; + u8 fgIsPrivacy; + u8 ucRoleIdx; + AP_CRYPTO_SETTINGS_T rEncryptionSettings; + s32 i4InactiveTimeout; +} MSG_P2P_START_AP_T, *P_MSG_P2P_START_AP_T; + +#if (CFG_SUPPORT_DFS_MASTER == 1) +typedef struct _MSG_P2P_DFS_CAC_T { + MSG_HDR_T rMsgHdr; + ENUM_CHANNEL_WIDTH_T eChannelWidth; + u8 ucRoleIdx; +} MSG_P2P_DFS_CAC_T, *P_MSG_P2P_DFS_CAC_T; + +typedef struct _MSG_P2P_RADAR_DETECT_T { + MSG_HDR_T rMsgHdr; + u8 ucBssIndex; +} MSG_P2P_RADAR_DETECT_T, *P_MSG_P2P_RADAR_DETECT_T; + +struct P2P_RADAR_INFO { + u8 ucRadarReportMode; /*0: Only report radar detected; 1: Add parameter + * reports*/ + u8 ucRddIdx; + u8 ucLongDetected; + u8 ucPeriodicDetected; + u8 ucLPBNum; + u8 ucPPBNum; + u8 ucLPBPeriodValid; + u8 ucLPBWidthValid; + u8 ucPRICountM1; + u8 ucPRICountM1TH; + u8 ucPRICountM2; + u8 ucPRICountM2TH; + u32 u4PRI1stUs; + LONG_PULSE_BUFFER_T arLpbContent[LPB_SIZE]; + PERIODIC_PULSE_BUFFER_T arPpbContent[PPB_SIZE]; +}; + +typedef struct _MSG_P2P_SET_NEW_CHANNEL_T { + MSG_HDR_T rMsgHdr; + ENUM_CHANNEL_WIDTH_T eChannelWidth; + u8 ucRoleIdx; + u8 ucBssIndex; +} MSG_P2P_SET_NEW_CHANNEL_T, *P_MSG_P2P_SET_NEW_CHANNEL_T; + +typedef struct _MSG_P2P_CSA_DONE_T { + MSG_HDR_T rMsgHdr; + u8 ucBssIndex; +} MSG_P2P_CSA_DONE_T, *P_MSG_P2P_CSA_DONE_T; +#endif + +typedef struct _MSG_P2P_DEL_IFACE_T { + MSG_HDR_T rMsgHdr; + u8 ucRoleIdx; +} MSG_P2P_DEL_IFACE_T, *P_MSG_P2P_DEL_IFACE_T; + +typedef struct _P2P_STATION_INFO_T { + u32 u4InactiveTime; + u32 u4RxBytes; /* TODO: */ + u32 u4TxBytes; /* TODO: */ + u32 u4RxPackets; /* TODO: */ + u32 u4TxPackets; /* TODO: */ + /* TODO: Add more for requirement. */ +} P2P_STATION_INFO_T, *P_P2P_STATION_INFO_T; + +/* 3 --------------- WFA P2P Attributes Handler prototype --------------- */ +typedef u32 (*PFN_APPEND_ATTRI_FUNC)(P_ADAPTER_T, u8, u8, u16 *, u8 *, u16); + +typedef u32 (*PFN_CALCULATE_VAR_ATTRI_LEN_FUNC)(P_ADAPTER_T, P_STA_RECORD_T); + +typedef struct _APPEND_VAR_ATTRI_ENTRY_T { + u16 u2EstimatedFixedAttriLen; /* For fixed length */ + PFN_CALCULATE_VAR_ATTRI_LEN_FUNC pfnCalculateVariableAttriLen; + PFN_APPEND_ATTRI_FUNC pfnAppendAttri; +} APPEND_VAR_ATTRI_ENTRY_T, *P_APPEND_VAR_ATTRI_ENTRY_T; + +/* //////////////////////////////////////////////////////////////// */ + +typedef enum _ENUM_P2P_ROLE_STATE_T { + P2P_ROLE_STATE_IDLE = 0, + P2P_ROLE_STATE_SCAN, + P2P_ROLE_STATE_REQING_CHANNEL, + P2P_ROLE_STATE_AP_CHNL_DETECTION, /* Requesting Channel to Send Specific + * Frame. */ + P2P_ROLE_STATE_GC_JOIN, +#if (CFG_SUPPORT_DFS_MASTER == 1) + P2P_ROLE_STATE_DFS_CAC, + P2P_ROLE_STATE_SWITCH_CHANNEL, +#endif + P2P_ROLE_STATE_NUM +} ENUM_P2P_ROLE_STATE_T, +*P_ENUM_P2P_ROLE_STATE_T; + +typedef enum _ENUM_P2P_CONNECTION_TYPE_T { + P2P_CONNECTION_TYPE_IDLE = 0, + P2P_CONNECTION_TYPE_GO, + P2P_CONNECTION_TYPE_GC, + P2P_CONNECTION_TYPE_PURE_AP, + P2P_CONNECTION_TYPE_NUM +} ENUM_P2P_CONNECTION_TYPE_T, +*P_ENUM_P2P_CONNECTION_TYPE_T; + +typedef struct _P2P_JOIN_INFO_T { + u8 ucSeqNumOfReqMsg; + u8 ucAvailableAuthTypes; + P_STA_RECORD_T prTargetStaRec; + P_BSS_DESC_T prTargetBssDesc; + u8 fgIsJoinComplete; + /* For ASSOC Rsp. */ + u32 u4BufLength; + u8 aucIEBuf[MAX_IE_LENGTH]; +} P2P_JOIN_INFO_T, *P_P2P_JOIN_INFO_T; + +/* For STA & AP mode. */ +typedef struct _P2P_CONNECTION_REQ_INFO_T { + ENUM_P2P_CONNECTION_TYPE_T eConnRequest; + P2P_SSID_STRUCT_T rSsidStruct; + u8 aucBssid[MAC_ADDR_LEN]; + + /* AP preferred channel. */ + RF_CHANNEL_INFO_T rChannelInfo; + ENUM_CHNL_EXT_T eChnlExt; + + /* To record channel bandwidth from CFG80211 */ + ENUM_MAX_BANDWIDTH_SETTING eChnlBw; + + /* To record primary channel frequency (MHz) from CFG80211 */ + u16 u2PriChnlFreq; + + /* To record Channel Center Frequency Segment 0 (MHz) from CFG80211 */ + u32 u4CenterFreq1; + + /* To record Channel Center Frequency Segment 1 (MHz) from CFG80211 */ + u32 u4CenterFreq2; + +#if (CFG_SUPPORT_DFS_MASTER == 1) + /* To record Channel DFS State */ + u32 u4ChnlDfsState; +#endif + + /* For ASSOC Req. */ + u32 u4BufLength; + u8 aucIEBuf[MAX_IE_LENGTH]; +} P2P_CONNECTION_REQ_INFO_T, *P_P2P_CONNECTION_REQ_INFO_T; + +#define P2P_ROLE_INDEX_2_ROLE_FSM_INFO(_prAdapter, _RoleIndex) \ + ((_prAdapter)->rWifiVar.aprP2pRoleFsmInfo[_RoleIndex]) + +struct _P2P_ROLE_FSM_INFO_T { + u8 ucRoleIndex; + + u8 ucBssIndex; + + /* State related. */ + ENUM_P2P_ROLE_STATE_T eCurrentState; + + /* Channel related. */ + P2P_CHNL_REQ_INFO_T rChnlReqInfo; + + /* Scan related. */ + P2P_SCAN_REQ_INFO_T rScanReqInfo; + + /* FSM Timer */ + TIMER_T rP2pRoleFsmTimeoutTimer; + +#if (CFG_SUPPORT_DFS_MASTER == 1) + TIMER_T rDfsShutDownTimer; +#if CFG_SUPPORT_DBDC + TIMER_T rDfsStartCacTimer; + ENUM_CHANNEL_WIDTH_T rChannelWidth; +#endif +#endif + + /* Packet filter for P2P module. */ + u32 u4P2pPacketFilter; + + /* GC Join related. */ + P2P_JOIN_INFO_T rJoinInfo; + + /* Connection related. */ + P2P_CONNECTION_REQ_INFO_T rConnReqInfo; + + /* Beacon Information. */ + P2P_BEACON_UPDATE_INFO_T rBeaconUpdateInfo; +}; + +/*========================= Initial ============================*/ + +u8 p2pRoleFsmInit(IN P_ADAPTER_T prAdapter, IN u8 ucRoleIdx); + +void p2pRoleFsmUninit(IN P_ADAPTER_T prAdapter, IN u8 ucRoleIdx); + +/*================== Message Event ==================*/ + +void p2pRoleFsmRunEventAbort(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo); + +void p2pRoleFsmRunEventStartAP(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pRoleFsmRunEventDelIface(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pRoleFsmRunEventStopAP(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +#if (CFG_SUPPORT_DFS_MASTER == 1) +void p2pRoleFsmRunEventDfsCac(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pRoleFsmRunEventRadarDet(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pRoleFsmRunEventSetNewChannel(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pRoleFsmRunEventCsaDone(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pRoleFsmRunEventDfsShutDownTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr); +#endif + +#if CFG_SUPPORT_DBDC_TC6 +void p2pRoleFsmRunEventStartDfsCacTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr); +#endif + +void p2pRoleFsmRunEventScanRequest(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pRoleFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo); + +void p2pRoleFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pRoleFsmRunEventTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr); + +void p2pRoleFsmDeauthTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr); + +void p2pRoleFsmRunEventBeaconTimeout(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo); + +void p2pRoleUpdateACLEntry(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx); + +u8 p2pRoleProcessACLInspection(IN P_ADAPTER_T prAdapter, + IN u8 *pMacAddr, + IN u8 ucBssIdx); + +WLAN_STATUS +p2pRoleFsmRunEventAAAComplete(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_BSS_INFO_T prP2pBssInfo); + +WLAN_STATUS +p2pRoleFsmRunEventAAASuccess(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_BSS_INFO_T prP2pBssInfo); + +void p2pRoleFsmRunEventAAATxFail(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_BSS_INFO_T prP2pBssInfo); + +void p2pRoleFsmRunEventConnectionRequest(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pRoleFsmRunEventConnectionAbort(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pRoleFsmRunEventChnlGrant(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo); + +WLAN_STATUS +p2pRoleFsmRunEventDeauthTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +void p2pRoleFsmRunEventRxDeauthentication(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb); + +void p2pRoleFsmRunEventRxDisassociation(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb); + +/* //////////////////////// TO BE REFINE ///////////////////// */ +void p2pRoleFsmRunEventSwitchOPMode(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pRoleFsmRunEventBeaconUpdate(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pRoleFsmRunEventDissolve(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr); + +void p2pProcessEvent_UpdateNOAParam(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIdx, + IN P_EVENT_UPDATE_NOA_PARAMS_T + prEventUpdateNoaParam); + +void p2pRoleFsmRunEventScanAbort(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx); + +void p2pRoleFsmStateTransition(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN ENUM_P2P_ROLE_STATE_T eNextState); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_role_state.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_role_state.h new file mode 100644 index 00000000000000..9d939a1e47f1ec --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_role_state.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ +#ifndef _P2P_ROLE_STATE_H +#define _P2P_ROLE_STATE_H + +void p2pRoleStateInit_IDLE(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN P_BSS_INFO_T prP2pBssInfo); + +void p2pRoleStateAbort_IDLE(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN P_P2P_CHNL_REQ_INFO_T prP2pChnlReqInfo); + +void p2pRoleStateInit_SCAN(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo); + +void p2pRoleStateAbort_SCAN(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo); + +void p2pRoleStateInit_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIdx, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +void p2pRoleStateAbort_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pRoleBssInfo, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN ENUM_P2P_ROLE_STATE_T eNextState); + +void p2pRoleStateInit_AP_CHNL_DETECTION(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo, + IN P_P2P_CONNECTION_REQ_INFO_T + prConnReqInfo); + +void p2pRoleStateAbort_AP_CHNL_DETECTION(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_P2P_CONNECTION_REQ_INFO_T + prP2pConnReqInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN P_P2P_SCAN_REQ_INFO_T + prP2pScanReqInfo, + IN ENUM_P2P_ROLE_STATE_T eNextState); + +void p2pRoleStateInit_GC_JOIN(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +void p2pRoleStateAbort_GC_JOIN(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN P_P2P_JOIN_INFO_T prJoinInfo, + IN ENUM_P2P_ROLE_STATE_T eNextState); + +#if (CFG_SUPPORT_DFS_MASTER == 1) +void p2pRoleStateInit_DFS_CAC(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIdx, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +void p2pRoleStateAbort_DFS_CAC(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pRoleBssInfo, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN ENUM_P2P_ROLE_STATE_T eNextState); + +void p2pRoleStateInit_SWITCH_CHANNEL(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIdx, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo); + +void p2pRoleStateAbort_SWITCH_CHANNEL(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pRoleBssInfo, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN ENUM_P2P_ROLE_STATE_T eNextState); + +void p2pRoleStatePrepare_To_DFS_CAC_STATE(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN ENUM_CHANNEL_WIDTH_T rChannelWidth, + IN P_P2P_CONNECTION_REQ_INFO_T + prConnReqInfo, + OUT P_P2P_CHNL_REQ_INFO_T + prChnlReqInfo); + +#endif + +void p2pRoleStatePrepare_To_REQING_CHANNEL_STATE(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_P2P_CONNECTION_REQ_INFO_T + prConnReqInfo, + OUT P_P2P_CHNL_REQ_INFO_T + prChnlReqInfo); + +void p2pRoleFsmScanTargetBss(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN u8 ucChannelNum, IN ENUM_BAND_T eBand, + IN P_P2P_SSID_STRUCT_T prSsid); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_scan.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_scan.h new file mode 100644 index 00000000000000..18fb74f6780221 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/p2p_scan.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "scan.h" + * \brief + * + */ + +#ifndef _P2P_SCAN_H +#define _P2P_SCAN_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void scnEventReturnChannel(IN P_ADAPTER_T prAdapter, IN u8 ucScnSeqNum); + +u8 scanUpdateP2pDeviceDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); + +void scanP2pProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_WLAN_STATUS prStatus, + IN P_BSS_DESC_T prBssDesc, + IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame); + +void scanRemoveAllP2pBssDesc(P_ADAPTER_T prAdapter); + +P_BSS_DESC_T scanP2pSearchDesc(IN P_ADAPTER_T prAdapter, + IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/privacy.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/privacy.h new file mode 100644 index 00000000000000..8d70ceedcadc87 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/privacy.h @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file privacy.h + * \brief This file contains the function declaration for privacy.c. + */ + +#ifndef _PRIVACY_H +#define _PRIVACY_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define MAX_KEY_NUM 4 +#define WEP_40_LEN 5 +#define WEP_104_LEN 13 +#define WEP_128_LEN 16 +#define LEGACY_KEY_MAX_LEN 16 +#define CCMP_KEY_LEN 16 +#define TKIP_KEY_LEN 32 +#define MAX_KEY_LEN 32 +#define MIC_RX_KEY_OFFSET 16 +#define MIC_TX_KEY_OFFSET 24 +#define MIC_KEY_LEN 8 + +#define WEP_KEY_ID_FIELD BITS(0, 29) +#define KEY_ID_FIELD BITS(0, 7) + +#define IS_TRANSMIT_KEY BIT(31) +#define IS_UNICAST_KEY BIT(30) +#define IS_AUTHENTICATOR BIT(28) + +#define CIPHER_SUITE_NONE 0 +#define CIPHER_SUITE_WEP40 1 +#define CIPHER_SUITE_TKIP 2 +#define CIPHER_SUITE_TKIP_WO_MIC 3 +#define CIPHER_SUITE_CCMP 4 +#define CIPHER_SUITE_WEP104 5 +#define CIPHER_SUITE_BIP 6 +#define CIPHER_SUITE_WEP128 7 +#define CIPHER_SUITE_WPI 8 +#define CIPHER_SUITE_CCMP_W_CCX 9 +#define CIPHER_SUITE_CCMP_256 10 +#define CIPHER_SUITE_GCMP_128 11 +#define CIPHER_SUITE_GCMP_256 12 +#define CIPHER_SUITE_GCM_WPI_128 13 + +/* Todo:: Move to register */ +#if defined(MT6630) +#define WTBL_RESERVED_ENTRY 255 +#else +#define WTBL_RESERVED_ENTRY 255 +#endif +/* Todo:: By chip capability */ +/* Max wlan table size, the max+1 used for probe request,... mgmt frame */ +/*sending use basic rate and no security */ +#define WTBL_SIZE 32 + +#define WTBL_ALLOC_FAIL WTBL_RESERVED_ENTRY +#define WTBL_DEFAULT_ENTRY 0 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef struct _IEEE_802_1X_HDR { + u8 ucVersion; + u8 ucType; + u16 u2Length; + /* followed by length octets of data */ +} IEEE_802_1X_HDR, *P_IEEE_802_1X_HDR; + +typedef struct _EAPOL_KEY { + u8 ucType; + /* Note: key_info, key_length, and key_data_length are unaligned */ + u8 aucKeyInfo[2]; /* big endian */ + u8 aucKeyLength[2]; /* big endian */ + u8 aucReplayCounter[8]; + u8 aucKeyNonce[16]; + u8 aucKeyIv[16]; + u8 aucKeyRsc[8]; + u8 aucKeyId[8]; /* Reserved in IEEE 802.11i/RSN */ + u8 aucKeyMic[16]; + u8 aucKeyDataLength[2]; /* big endian */ + /* followed by key_data_length bytes of key_data */ +} EAPOL_KEY, *P_EAPOL_KEY; + +/* WPA2 PMKID candicate structure */ +typedef struct _PMKID_CANDICATE_T { + u8 aucBssid[MAC_ADDR_LEN]; + u32 u4PreAuthFlags; +} PMKID_CANDICATE_T, *P_PMKID_CANDICATE_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void secInit(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex); + +void secSetPortBlocked(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta, + IN u8 fgPort); + +u8 secCheckClassError(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_STA_RECORD_T prStaRec); + +u8 secTxPortControlCheck(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_STA_RECORD_T prStaRec); + +u8 secRxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb); + +void secSetCipherSuite(IN P_ADAPTER_T prAdapter, IN u32 u4CipherSuitesFlags); + +u8 secIsProtectedFrame(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsdu, + IN P_STA_RECORD_T prStaRec); + +void secClearPmkid(IN P_ADAPTER_T prAdapter); + +u8 secRsnKeyHandshakeEnabled(IN P_ADAPTER_T prAdapter); + +u8 secGetBmcWlanIndex(IN P_ADAPTER_T prAdapter, + IN ENUM_NETWORK_TYPE_T eNetType, + IN P_STA_RECORD_T prStaRec); + +u8 secTransmitKeyExist(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); + +u8 secEnabledInAis(IN P_ADAPTER_T prAdapter); + +u8 secPrivacySeekForEntry(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta); + +void secPrivacyFreeForEntry(IN P_ADAPTER_T prAdapter, IN u8 ucEntry); + +void secPrivacyFreeSta(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +void secRemoveBssBcEntry(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN u8 fgRoam); + +u8 secPrivacySeekForBcEntry(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN u8 *pucAddr, + IN u8 ucStaIdx, + IN u8 ucAlg, + IN u8 ucKeyId); + +u8 secGetStaIdxByWlanIdx(IN P_ADAPTER_T prAdapter, IN u8 ucWlanIdx); + +u8 secGetBssIdxByWlanIdx(IN P_ADAPTER_T prAdapter, IN u8 ucWlanIdx); + +u8 secLookupStaRecIndexFromTA(P_ADAPTER_T prAdapter, u8 *pucMacAddress); + +void secPrivacyDumpWTBL(IN P_ADAPTER_T prAdapter); + +u8 secCheckWTBLAssign(IN P_ADAPTER_T prAdapter); + +u8 secIsProtected1xFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +u8 secIsProtectedBss(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); + +u8 tkipMicDecapsulate(IN P_SW_RFB_T prSwRfb, IN u8 *pucMicKey); + +u8 tkipMicDecapsulateInRxHdrTransMode(IN P_SW_RFB_T prSwRfb, IN u8 *pucMicKey); + +void secPostUpdateAddr(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rate.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rate.h new file mode 100644 index 00000000000000..1e8466be6fbd86 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rate.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file rate.h + * \brief This file contains the rate utility function of + * IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. + */ + +#ifndef _RATE_H +#define _RATE_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Routines in rate.c */ +/*----------------------------------------------------------------------------*/ +void rateGetRateSetFromIEs(IN P_IE_SUPPORTED_RATE_IOT_T prIeSupportedRate, + IN P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate, + OUT u16 *pu2OperationalRateSet, + OUT u16 *pu2BSSBasicRateSet, + OUT u8 *pfgIsUnknownBSSBasicRate); + +void rateGetDataRatesFromRateSet(IN u16 u2OperationalRateSet, + IN u16 u2BSSBasicRateSet, + OUT u8 *pucDataRates, + OUT u8 *pucDataRatesLen); + +u8 rateGetHighestRateIndexFromRateSet(IN u16 u2RateSet, + OUT u8 *pucHighestRateIndex); + +u8 rateGetLowestRateIndexFromRateSet(IN u16 u2RateSet, + OUT u8 *pucLowestRateIndex); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm.h new file mode 100644 index 00000000000000..c770713ba233e6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm.h @@ -0,0 +1,431 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "rlm.h" + * \brief + */ + +#ifndef _RLM_H +#define _RLM_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +extern u8 g_bIcapEnable; +extern u8 g_bCaptureDone; +extern u16 g_u2DumpIndex; +#if CFG_SUPPORT_QA_TOOL +extern u32 g_au4Offset[2][2]; +extern u32 g_au4IQData[256]; +#endif + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define ELEM_EXT_CAP_DEFAULT_VAL \ + (ELEM_EXT_CAP_20_40_COEXIST_SUPPORT /*| ELEM_EXT_CAP_PSMP_CAP*/ ) + +#if CFG_SUPPORT_RX_STBC +#define FIELD_HT_CAP_INFO_RX_STBC HT_CAP_INFO_RX_STBC_1_SS +#else +#define FIELD_HT_CAP_INFO_RX_STBC HT_CAP_INFO_RX_STBC_NO_SUPPORTED +#endif + +#if CFG_SUPPORT_RX_SGI +#define FIELD_HT_CAP_INFO_SGI_20M HT_CAP_INFO_SHORT_GI_20M +#define FIELD_HT_CAP_INFO_SGI_40M HT_CAP_INFO_SHORT_GI_40M +#else +#define FIELD_HT_CAP_INFO_SGI_20M 0 +#define FIELD_HT_CAP_INFO_SGI_40M 0 +#endif + +#if CFG_SUPPORT_RX_HT_GF +#define FIELD_HT_CAP_INFO_HT_GF HT_CAP_INFO_HT_GF +#else +#define FIELD_HT_CAP_INFO_HT_GF 0 +#endif + +#define HT_CAP_INFO_DEFAULT_VAL \ + (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_DSSS_CCK_IN_40M | \ + HT_CAP_INFO_SM_POWER_SAVE) + +#define AMPDU_PARAM_DEFAULT_VAL \ + (AMPDU_PARAM_MAX_AMPDU_LEN_64K | AMPDU_PARAM_MSS_NO_RESTRICIT) + +#define SUP_MCS_TX_DEFAULT_VAL \ + SUP_MCS_TX_SET_DEFINED /* TX defined and TX/RX equal (TBD) */ + +#if CFG_SUPPORT_MFB +#define FIELD_HT_EXT_CAP_MFB HT_EXT_CAP_MCS_FEEDBACK_BOTH +#else +#define FIELD_HT_EXT_CAP_MFB HT_EXT_CAP_MCS_FEEDBACK_NO_FB +#endif + +#if CFG_SUPPORT_RX_RDG +#define FIELD_HT_EXT_CAP_RDR HT_EXT_CAP_RD_RESPONDER +#else +#define FIELD_HT_EXT_CAP_RDR 0 +#endif + +#if CFG_SUPPORT_MFB || CFG_SUPPORT_RX_RDG +#define FIELD_HT_EXT_CAP_HTC HT_EXT_CAP_HTC_SUPPORT +#else +#define FIELD_HT_EXT_CAP_HTC 0 +#endif + +#define HT_EXT_CAP_DEFAULT_VAL \ + (HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE | \ + FIELD_HT_EXT_CAP_MFB | FIELD_HT_EXT_CAP_HTC | FIELD_HT_EXT_CAP_RDR) + +#define TX_BEAMFORMING_CAP_DEFAULT_VAL 0 + +#if CFG_SUPPORT_BFEE +#define TX_BEAMFORMING_CAP_BFEE \ + (TXBF_RX_NDP_CAPABLE | \ + TXBF_EXPLICIT_COMPRESSED_FEEDBACK_IMMEDIATE_CAPABLE | \ + TXBF_MINIMAL_GROUPING_1_2_3_CAPABLE | \ + TXBF_COMPRESSED_TX_ANTENNANUM_4_SUPPORTED | \ + TXBF_CHANNEL_ESTIMATION_4STS_CAPABILITY) +#else +#define TX_BEAMFORMING_CAP_BFEE 0 +#endif + +#if CFG_SUPPORT_BFER +#define TX_BEAMFORMING_CAP_BFER \ + (TXBF_TX_NDP_CAPABLE | TXBF_EXPLICIT_COMPRESSED_TX_CAPAB) +#else +#define TX_BEAMFORMING_CAP_BFER 0 +#endif + +#define ASEL_CAP_DEFAULT_VAL 0 + +/* Define bandwidth from user setting */ +#define CONFIG_BW_20_40M 0 +#define CONFIG_BW_20M 1 /* 20MHz only */ + +#if CFG_SUPPORT_BFER +#define MODE_LEGACY 0 +#define MODE_HT 1 +#define MODE_VHT 2 +#endif + +#if CFG_SUPPORT_802_11AC +#if CFG_SUPPORT_BFEE +#define FIELD_VHT_CAP_INFO_BFEE ( \ + VHT_CAP_INFO_SU_BEAMFORMEE_CAPABLE) +#define VHT_CAP_INFO_BEAMFORMEE_STS_CAP_MAX 3 +#else +#define FIELD_VHT_CAP_INFO_BFEE 0 +#endif + +#if CFG_SUPPORT_BFER +#define FIELD_VHT_CAP_INFO_BFER \ + (VHT_CAP_INFO_SU_BEAMFORMER_CAPABLE | \ + VHT_CAP_INFO_NUMBER_OF_SOUNDING_DIMENSIONS_2_SUPPORTED) +#else +#define FIELD_VHT_CAP_INFO_BFER 0 +#endif + +#define VHT_CAP_INFO_DEFAULT_VAL \ + (VHT_CAP_INFO_MAX_MPDU_LEN_3K | \ + (AMPDU_PARAM_MAX_AMPDU_LEN_1024K \ + << VHT_CAP_INFO_MAX_AMPDU_LENGTH_OFFSET)) + +#define VHT_CAP_INFO_DEFAULT_HIGHEST_DATA_RATE 0 +#endif + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +#if CFG_SUPPORT_DFS +typedef struct _SWITCH_CH_AND_BAND_PARAMS_T { + u8 fgBeaconNewChannelIsDFS; + u8 fgActionNewChannelIsDFS; + u8 fgNewChannelIsDisabled; + u8 ucCsaNewCh; + u8 ucCsaCount; + u8 ucVhtS1; + u8 ucVhtS2; + u8 ucVhtBw; + ENUM_CHNL_EXT_T eSco; + u8 ucBssIndex; +} SWITCH_CH_AND_BAND_PARAMS_T, *P_SWITCH_CH_AND_BAND_PARAMS_T; +#endif + +struct SUB_ELEMENT_LIST { + struct SUB_ELEMENT_LIST *prNext; + struct SUB_ELEMENT rSubIE; +}; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/* It is used for RLM module to judge if specific network is valid + * Note: Ad-hoc mode of AIS is not included now. (TBD) + */ +#define RLM_NET_PARAM_VALID(_prBssInfo) \ + (IS_BSS_ACTIVE(_prBssInfo) && \ + ((_prBssInfo)->eConnectionState == PARAM_MEDIA_STATE_CONNECTED || \ + (_prBssInfo)->eCurrentOPMode == OP_MODE_ACCESS_POINT || \ + (_prBssInfo)->eCurrentOPMode == OP_MODE_IBSS || \ + IS_BSS_BOW(_prBssInfo))) + +#define RLM_NET_IS_11N(_prBssInfo) \ + ((_prBssInfo)->ucPhyTypeSet & PHY_TYPE_SET_802_11N) +#define RLM_NET_IS_11GN(_prBssInfo) \ + ((_prBssInfo)->ucPhyTypeSet & PHY_TYPE_SET_802_11GN) + +#if CFG_SUPPORT_802_11AC +#define RLM_NET_IS_11AC(_prBssInfo) \ + ((_prBssInfo)->ucPhyTypeSet & PHY_TYPE_SET_802_11AC) +#endif + +/* The bandwidth modes are not used anymore. They represent if AP + * can use 20/40 bandwidth, not all modes. (20110411) + */ +#define RLM_AP_IS_BW_40_ALLOWED(_prAdapter, _prBssInfo) \ + (((_prBssInfo)->eBand == BAND_2G4 && \ + (_prAdapter)->rWifiVar.rConnSettings.uc2G4BandwidthMode == \ + CONFIG_BW_20_40M) || \ + ((_prBssInfo)->eBand == BAND_5G && \ + (_prAdapter)->rWifiVar.rConnSettings.uc5GBandwidthMode == \ + CONFIG_BW_20_40M)) + +#if CFG_SUPPORT_DFS +#define MAX_CSA_COUNT 255 +#define HAS_CH_SWITCH_PARAMS(prCSAParams, prBssDesc) \ + (prCSAParams->ucCsaNewCh > 0 && \ + prCSAParams->ucCsaNewCh != prBssDesc->ucChannelNum) +#define HAS_SCO_PARAMS(prCSAParams) (prCSAParams->eSco > 0) +#define HAS_WIDE_BAND_PARAMS(prCSAParams) \ + (prCSAParams->ucVhtBw > 0 || prCSAParams->ucVhtS1 > 0 || \ + prCSAParams->ucVhtS2 > 0) +#define SHOULD_CH_SWITCH(current, prCSAParams, prBssDesc) \ + (HAS_CH_SWITCH_PARAMS(prCSAParams, prBssDesc) && \ + (current < prCSAParams->ucCsaCount)) +#endif + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void rlmFsmEventInit(P_ADAPTER_T prAdapter); + +void rlmFsmEventUninit(P_ADAPTER_T prAdapter); + +void rlmReqGeneratePowerCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +void rlmReqGenerateSupportedChIE(P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo); + +void rlmReqGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +void rlmReqGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +void rlmRspGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +void rlmRspGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +void rlmRspGenerateHtOpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +void rlmRspGenerateErpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +void rlmGenerateMTKOuiIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +u8 rlmParseCheckMTKOuiIE(IN P_ADAPTER_T prAdapter, IN u8 *pucBuf, + IN u32 *pu4Cap); + +void rlmGenerateCsaIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +void rlmProcessBcn(P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb, + u8 *pucIE, + u16 u2IELength); + +void rlmProcessAssocRsp(P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb, + u8 *pucIE, + u16 u2IELength); + +void rlmProcessHtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); + +#if CFG_SUPPORT_802_11AC +void rlmProcessVhtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); +#endif + +void rlmFillSyncCmdParam(P_CMD_SET_BSS_RLM_PARAM_T prCmdBody, + P_BSS_INFO_T prBssInfo); + +void rlmSyncOperationParams(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +void rlmBssInitForAPandIbss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +void rlmProcessAssocReq(P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb, + u8 *pucIE, + u16 u2IELength); + +void rlmBssAborted(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +#if CFG_SUPPORT_TDLS +u32 rlmFillHtCapIEByParams(u8 fg40mAllowed, + u8 fgShortGIDisabled, + u8 u8SupportRxSgi20, + u8 u8SupportRxSgi40, + u8 u8SupportRxGf, + ENUM_OP_MODE_T eCurrentOPMode, + u8 *pOutBuf); + +u32 rlmFillHtCapIEByAdapter(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + u8 *pOutBuf); + +u32 rlmFillVhtCapIEByAdapter(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + u8 *pOutBuf); + +#endif + +#if CFG_SUPPORT_802_11AC +void rlmReqGenerateVhtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +void rlmRspGenerateVhtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +void rlmRspGenerateVhtOpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +void rlmFillVhtOpIE(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo); + +void rlmRspGenerateVhtOpNotificationIE(P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo); +void rlmReqGenerateVhtOpNotificationIE(P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo); + +#endif + +#if CFG_SUPPORT_DFS +void rlmProcessSpecMgtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); + +void rlmResetCSAParams(P_BSS_INFO_T prBssInfo); + +void rlmCsaTimeout(IN P_ADAPTER_T prAdapter, unsigned long ulParamPtr); +#endif + +void rlmSendOpModeNotificationFrame(P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, + u8 ucChannelWidth, + u8 ucNss); + +void rlmSendSmPowerSaveFrame(P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, + u8 ucNss); + +void rlmChangeVhtOpBwPara(P_ADAPTER_T prAdapter, u8 ucBssIndex, + u8 ucChannelWidth); + +u8 rlmChangeOperationMode(P_ADAPTER_T prAdapter, + u8 ucBssIndex, + u8 ucChannelWidth, + u8 ucNss); + +#if CFG_SUPPORT_BFER +void rlmBfStaRecPfmuUpdate(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec); + +void rlmETxBfTriggerPeriodicSounding(P_ADAPTER_T prAdapter); + +u8 rlmClientSupportsVhtETxBF(P_STA_RECORD_T prStaRec); + +u8 rlmClientSupportsVhtBfeeStsCap(P_STA_RECORD_T prStaRec); + +u8 rlmClientSupportsHtETxBF(P_STA_RECORD_T prStaRec); +#endif + +#if CFG_SUPPORT_DBDC_TC6 +void rlmSendChannelSwitchFrame(P_ADAPTER_T prAdapter, u8 ucBssIndex); + +u8 rlmGetBssOpBwByVhtAndHtOpInfo(P_BSS_INFO_T prBssInfo); + +u8 rlmGetVhtOpBwByBssOpBw(u8 ucBssOpBw); +#endif + +void rlmModifyVhtBwPara(u8 *pucVhtChannelFrequencyS1, + u8 *pucVhtChannelFrequencyS2, + u8 *pucVhtChannelWidth); + +void rlmReviseMaxBw(P_ADAPTER_T prAdapter, + u8 ucBssIndex, + P_ENUM_CHNL_EXT_T peExtend, + u8 *peChannelWidth, + u8 *pucS1, + u8 *pucPrimaryCh); + +void rlmRevisePreferBandwidthNss(P_ADAPTER_T prAdapter, + u8 ucBssIndex, + P_STA_RECORD_T prStaRec); + +#if CFG_SUPPORT_802_11K +void rlmReqGenerateRRMEnabledCapIE(P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo); + +void rlmFillRrmCapa(u8 *pucCapa); + +void rlmTxNeighborReportRequest(P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, + struct SUB_ELEMENT_LIST *prSubIEs); + +void rlmProcessNeighborReportResponse(P_ADAPTER_T prAdapter, + P_WLAN_ACTION_FRAME prAction, + u16 u2PacketLen); +#endif + +#if CFG_SUPPORT_QUIET +void rrmQuietIeNotExist(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +void rrmQuietHandleQuietIE(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_IE_QUIET_T pucQUIE); + +void rrmTxQuietTimeout(P_ADAPTER_T prAdapter, unsigned long ulParamPtr); + +#endif + +u32 rlmSendChannelSwitchTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +void rlmSendNotifyChannelWidthFrame(P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, u8 ucChannelWidth); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm_domain.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm_domain.h new file mode 100644 index 00000000000000..76a0e9c20670e4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm_domain.h @@ -0,0 +1,769 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "rlm_domain.h" + * \brief + */ + +#ifndef _RLM_DOMAIN_H +#define _RLM_DOMAIN_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define MAX_SUBBAND_NUM 6 +#define MAX_SUBBAND_NUM_5G 8 + +#define COUNTRY_CODE_NULL ((u16)0x0) + +/* ISO/IEC 3166-1 two-character country codes */ + +#define COUNTRY_CODE_AD (((u16)'A' << 8) | (u16)'D') /* Andorra */ +#define COUNTRY_CODE_AE (((u16)'A' << 8) | (u16)'E') /* UAE */ +#define COUNTRY_CODE_AF (((u16)'A' << 8) | (u16)'F') /* Afghanistan */ +#define COUNTRY_CODE_AG (((u16)'A' << 8) | (u16)'G') /* Antigua & Barbuda */ +#define COUNTRY_CODE_AI (((u16)'A' << 8) | (u16)'I') /* Anguilla */ +#define COUNTRY_CODE_AL (((u16)'A' << 8) | (u16)'L') /* Albania */ +#define COUNTRY_CODE_AM (((u16)'A' << 8) | (u16)'M') /* Armenia */ +#define COUNTRY_CODE_AN (((u16)'A' << 8) | (u16)'N') /* Netherlands Antilles */ +#define COUNTRY_CODE_AO (((u16)'A' << 8) | (u16)'O') /* Angola */ +#define COUNTRY_CODE_AR (((u16)'A' << 8) | (u16)'R') /* Argentina */ +#define COUNTRY_CODE_AS (((u16)'A' << 8) | (u16)'S') /* American Samoa (USA) */ +#define COUNTRY_CODE_AT (((u16)'A' << 8) | (u16)'T') /* Austria */ +#define COUNTRY_CODE_AU (((u16)'A' << 8) | (u16)'U') /* Australia */ +#define COUNTRY_CODE_AW (((u16)'A' << 8) | (u16)'W') /* Aruba */ +#define COUNTRY_CODE_AZ (((u16)'A' << 8) | (u16)'Z') /* Azerbaijan */ +#define COUNTRY_CODE_BA \ + (((u16)'B' << 8) | (u16)'A') /* Bosnia and Herzegovina */ +#define COUNTRY_CODE_BB (((u16)'B' << 8) | (u16)'B') /* Barbados */ +#define COUNTRY_CODE_BD (((u16)'B' << 8) | (u16)'D') /* Bangladesh */ +#define COUNTRY_CODE_BE (((u16)'B' << 8) | (u16)'E') /* Belgium */ +#define COUNTRY_CODE_BF (((u16)'B' << 8) | (u16)'F') /* Burkina Faso */ +#define COUNTRY_CODE_BG (((u16)'B' << 8) | (u16)'G') /* Bulgaria */ +#define COUNTRY_CODE_BH (((u16)'B' << 8) | (u16)'H') /* Bahrain */ +#define COUNTRY_CODE_BI (((u16)'B' << 8) | (u16)'I') /* Burundi */ +#define COUNTRY_CODE_BJ (((u16)'B' << 8) | (u16)'J') /* Benin */ +#define COUNTRY_CODE_BM (((u16)'B' << 8) | (u16)'M') /* Bermuda */ +#define COUNTRY_CODE_BN (((u16)'B' << 8) | (u16)'N') /* Brunei */ +#define COUNTRY_CODE_BO (((u16)'B' << 8) | (u16)'O') /* Bolivia */ +#define COUNTRY_CODE_BR (((u16)'B' << 8) | (u16)'R') /* Brazil */ +#define COUNTRY_CODE_BS (((u16)'B' << 8) | (u16)'S') /* Bahamas */ +#define COUNTRY_CODE_BT (((u16)'B' << 8) | (u16)'T') /* Bhutan */ +#define COUNTRY_CODE_BW (((u16)'B' << 8) | (u16)'W') /* Botswana */ +#define COUNTRY_CODE_BY (((u16)'B' << 8) | (u16)'Y') /* Belarus */ +#define COUNTRY_CODE_BZ (((u16)'B' << 8) | (u16)'Z') /* Belize */ +#define COUNTRY_CODE_CA (((u16)'C' << 8) | (u16)'A') /* Canada */ +#define COUNTRY_CODE_CD \ + (((u16)'C' << 8) | (u16)'D') /* Congo. Democratic Republic of the */ +#define COUNTRY_CODE_CF \ + (((u16)'C' << 8) | (u16)'F') /* Central African Republic */ +#define COUNTRY_CODE_CG \ + (((u16)'C' << 8) | (u16)'G') /* Congo. Republic of the */ +#define COUNTRY_CODE_CH (((u16)'C' << 8) | (u16)'H') /* Switzerland */ +#define COUNTRY_CODE_CI (((u16)'C' << 8) | (u16)'I') /* Cote d'lvoire */ +#define COUNTRY_CODE_CK (((u16)'C' << 8) | (u16)'K') /* Cook Island */ +#define COUNTRY_CODE_CL (((u16)'C' << 8) | (u16)'L') /* Chile */ +#define COUNTRY_CODE_CM (((u16)'C' << 8) | (u16)'M') /* Cameroon */ +#define COUNTRY_CODE_CN (((u16)'C' << 8) | (u16)'N') /* China */ +#define COUNTRY_CODE_CO (((u16)'C' << 8) | (u16)'O') /* Columbia */ +#define COUNTRY_CODE_CR (((u16)'C' << 8) | (u16)'R') /* Costa Rica */ +#define COUNTRY_CODE_CU (((u16)'C' << 8) | (u16)'U') /* Cuba */ +#define COUNTRY_CODE_CV (((u16)'C' << 8) | (u16)'V') /* Cape Verde */ +#define COUNTRY_CODE_CX \ + (((u16)'C' << 8) | (u16)'X') /* "Christmas Island(Australia) */ +#define COUNTRY_CODE_CY (((u16)'C' << 8) | (u16)'Y') /* Cyprus */ +#define COUNTRY_CODE_CZ (((u16)'C' << 8) | (u16)'Z') /* Czech */ +#define COUNTRY_CODE_DE (((u16)'D' << 8) | (u16)'E') /* Germany */ +#define COUNTRY_CODE_DJ (((u16)'D' << 8) | (u16)'J') /* Djibouti */ +#define COUNTRY_CODE_DK (((u16)'D' << 8) | (u16)'K') /* Denmark */ +#define COUNTRY_CODE_DM (((u16)'D' << 8) | (u16)'M') /* Dominica */ +#define COUNTRY_CODE_DO (((u16)'D' << 8) | (u16)'O') /* Dominican Republic */ +#define COUNTRY_CODE_DZ (((u16)'D' << 8) | (u16)'Z') /* Algeria */ +#define COUNTRY_CODE_EC (((u16)'E' << 8) | (u16)'C') /* Ecuador */ +#define COUNTRY_CODE_EE (((u16)'E' << 8) | (u16)'E') /* Estonia */ +#define COUNTRY_CODE_EG (((u16)'E' << 8) | (u16)'G') /* Egypt */ +#define COUNTRY_CODE_EH \ + (((u16)'E' << 8) | (u16)'H') /* Western Sahara (Morocco) */ +#define COUNTRY_CODE_ER (((u16)'E' << 8) | (u16)'R') /* Eritrea */ +#define COUNTRY_CODE_ES (((u16)'E' << 8) | (u16)'S') /* Spain */ +#define COUNTRY_CODE_ET (((u16)'E' << 8) | (u16)'T') /* Ethiopia */ +#define COUNTRY_CODE_EU (((u16)'E' << 8) | (u16)'U') /* Europe */ +#define COUNTRY_CODE_FI (((u16)'F' << 8) | (u16)'I') /* Finland */ +#define COUNTRY_CODE_FJ (((u16)'F' << 8) | (u16)'J') /* Fiji */ +#define COUNTRY_CODE_FK (((u16)'F' << 8) | (u16)'K') /* Falkland Island */ +#define COUNTRY_CODE_FM (((u16)'F' << 8) | (u16)'M') /* Micronesia */ +#define COUNTRY_CODE_FO (((u16)'F' << 8) | (u16)'O') /* Faroe Island */ +#define COUNTRY_CODE_FR (((u16)'F' << 8) | (u16)'R') /* France */ +#define COUNTRY_CODE_FR \ + (((u16)'F' << 8) | (u16)'R') /* Wallis and Futuna (France) */ +#define COUNTRY_CODE_GA (((u16)'G' << 8) | (u16)'A') /* Gabon */ +#define COUNTRY_CODE_GB (((u16)'G' << 8) | (u16)'B') /* United Kingdom */ +#define COUNTRY_CODE_GD (((u16)'G' << 8) | (u16)'D') /* Grenada */ +#define COUNTRY_CODE_GE (((u16)'G' << 8) | (u16)'E') /* Georgia */ +#define COUNTRY_CODE_GF (((u16)'G' << 8) | (u16)'F') /* French Guiana */ +#define COUNTRY_CODE_GG (((u16)'G' << 8) | (u16)'G') /* Guernsey */ +#define COUNTRY_CODE_GH (((u16)'G' << 8) | (u16)'H') /* Ghana */ +#define COUNTRY_CODE_GI (((u16)'G' << 8) | (u16)'I') /* Gibraltar */ +#define COUNTRY_CODE_GM (((u16)'G' << 8) | (u16)'M') /* Gambia */ +#define COUNTRY_CODE_GN (((u16)'G' << 8) | (u16)'N') /* Guinea */ +#define COUNTRY_CODE_GP (((u16)'G' << 8) | (u16)'P') /* Guadeloupe */ +#define COUNTRY_CODE_GQ (((u16)'G' << 8) | (u16)'Q') /* Equatorial Guinea */ +#define COUNTRY_CODE_GR (((u16)'G' << 8) | (u16)'R') /* Greece */ +#define COUNTRY_CODE_GT (((u16)'G' << 8) | (u16)'T') /* Guatemala */ +#define COUNTRY_CODE_GU (((u16)'G' << 8) | (u16)'U') /* Guam */ +#define COUNTRY_CODE_GW (((u16)'G' << 8) | (u16)'W') /* Guinea-Bissau */ +#define COUNTRY_CODE_GY (((u16)'G' << 8) | (u16)'Y') /* Guyana */ +#define COUNTRY_CODE_HK (((u16)'H' << 8) | (u16)'K') /* Hong Kong */ +#define COUNTRY_CODE_HN (((u16)'H' << 8) | (u16)'N') /* Honduras */ +#define COUNTRY_CODE_HR (((u16)'H' << 8) | (u16)'R') /* Croatia */ +#define COUNTRY_CODE_HT (((u16)'H' << 8) | (u16)'T') /* Haiti */ +#define COUNTRY_CODE_HU (((u16)'H' << 8) | (u16)'U') /* Hungary */ +#define COUNTRY_CODE_ID (((u16)'I' << 8) | (u16)'D') /* Indonesia */ +#define COUNTRY_CODE_IE (((u16)'I' << 8) | (u16)'E') /* Ireland */ +#define COUNTRY_CODE_IL (((u16)'I' << 8) | (u16)'L') /* Israel */ +#define COUNTRY_CODE_IM (((u16)'I' << 8) | (u16)'M') /* Isle of Man */ +#define COUNTRY_CODE_IN (((u16)'I' << 8) | (u16)'N') /* India */ +#define COUNTRY_CODE_IQ (((u16)'I' << 8) | (u16)'Q') /* Iraq */ +#define COUNTRY_CODE_IR (((u16)'I' << 8) | (u16)'R') /* Iran */ +#define COUNTRY_CODE_IS (((u16)'I' << 8) | (u16)'S') /* Iceland */ +#define COUNTRY_CODE_IT (((u16)'I' << 8) | (u16)'T') /* Italy */ +#define COUNTRY_CODE_JE (((u16)'J' << 8) | (u16)'E') /* Jersey */ +#define COUNTRY_CODE_JM (((u16)'J' << 8) | (u16)'M') /* Jameica */ +#define COUNTRY_CODE_JO (((u16)'J' << 8) | (u16)'O') /* Jordan */ +#define COUNTRY_CODE_JP (((u16)'J' << 8) | (u16)'P') /* Japan */ +#define COUNTRY_CODE_KE (((u16)'K' << 8) | (u16)'E') /* Kenya */ +#define COUNTRY_CODE_KG (((u16)'K' << 8) | (u16)'G') /* Kyrgyzstan */ +#define COUNTRY_CODE_KH (((u16)'K' << 8) | (u16)'H') /* Cambodia */ +#define COUNTRY_CODE_KI (((u16)'K' << 8) | (u16)'I') /* Kiribati */ +#define COUNTRY_CODE_KM (((u16)'K' << 8) | (u16)'M') /* Comoros */ +#define COUNTRY_CODE_KN (((u16)'K' << 8) | (u16)'N') /* Saint Kitts and Nevis */ +#define COUNTRY_CODE_KP (((u16)'K' << 8) | (u16)'P') /* North Korea */ +#define COUNTRY_CODE_KR (((u16)'K' << 8) | (u16)'R') /* South Korea */ +#define COUNTRY_CODE_KW (((u16)'K' << 8) | (u16)'W') /* Kuwait */ +#define COUNTRY_CODE_KY (((u16)'K' << 8) | (u16)'Y') /* Cayman Islands */ +#define COUNTRY_CODE_KZ (((u16)'K' << 8) | (u16)'Z') /* Kazakhstan */ +#define COUNTRY_CODE_LA (((u16)'L' << 8) | (u16)'A') /* Laos */ +#define COUNTRY_CODE_LB (((u16)'L' << 8) | (u16)'B') /* Lebanon */ +#define COUNTRY_CODE_LC (((u16)'L' << 8) | (u16)'C') /* Saint Lucia */ +#define COUNTRY_CODE_LI (((u16)'L' << 8) | (u16)'I') /* Liechtenstein */ +#define COUNTRY_CODE_LK (((u16)'L' << 8) | (u16)'K') /* Sri Lanka */ +#define COUNTRY_CODE_LR (((u16)'L' << 8) | (u16)'R') /* Liberia */ +#define COUNTRY_CODE_LS (((u16)'L' << 8) | (u16)'S') /* Lesotho */ +#define COUNTRY_CODE_LT (((u16)'L' << 8) | (u16)'T') /* Lithuania */ +#define COUNTRY_CODE_LU (((u16)'L' << 8) | (u16)'U') /* Luxemburg */ +#define COUNTRY_CODE_LV (((u16)'L' << 8) | (u16)'V') /* Latvia */ +#define COUNTRY_CODE_LY (((u16)'L' << 8) | (u16)'Y') /* Libya */ +#define COUNTRY_CODE_MA (((u16)'M' << 8) | (u16)'A') /* Morocco */ +#define COUNTRY_CODE_MC (((u16)'M' << 8) | (u16)'C') /* Monaco */ +#define COUNTRY_CODE_MD (((u16)'M' << 8) | (u16)'D') /* Moldova */ +#define COUNTRY_CODE_ME (((u16)'M' << 8) | (u16)'E') /* Montenegro */ +#define COUNTRY_CODE_MF \ + (((u16)'M' << 8) | (u16)'F') /* Saint Martin / Sint Marteen */ +/*(Added on window's list) */ +#define COUNTRY_CODE_MG (((u16)'M' << 8) | (u16)'G') /* Madagascar */ +#define COUNTRY_CODE_MH (((u16)'M' << 8) | (u16)'H') /* Marshall Islands */ +#define COUNTRY_CODE_MK (((u16)'M' << 8) | (u16)'K') /* Macedonia */ +#define COUNTRY_CODE_ML (((u16)'M' << 8) | (u16)'L') /* Mali */ +#define COUNTRY_CODE_MM (((u16)'M' << 8) | (u16)'M') /* Myanmar */ +#define COUNTRY_CODE_MN (((u16)'M' << 8) | (u16)'N') /* Mongolia */ +#define COUNTRY_CODE_MO (((u16)'M' << 8) | (u16)'O') /* Macao */ +#define COUNTRY_CODE_MP (((u16)'M' << 8) | (u16)'P') +/* Northern Mariana Islands (Rota Island / Saipan and Tinian Island) */ +#define COUNTRY_CODE_MQ (((u16)'M' << 8) | (u16)'Q') /* Martinique (France) */ +#define COUNTRY_CODE_MR (((u16)'M' << 8) | (u16)'R') /* Mauritania */ +#define COUNTRY_CODE_MS (((u16)'M' << 8) | (u16)'S') /* Montserrat (UK) */ +#define COUNTRY_CODE_MT (((u16)'M' << 8) | (u16)'T') /* Malta */ +#define COUNTRY_CODE_MU (((u16)'M' << 8) | (u16)'U') /* Mauritius */ +#define COUNTRY_CODE_MV (((u16)'M' << 8) | (u16)'V') /* Maldives */ +#define COUNTRY_CODE_MW (((u16)'M' << 8) | (u16)'W') /* Malawi */ +#define COUNTRY_CODE_MX (((u16)'M' << 8) | (u16)'X') /* Mexico */ +#define COUNTRY_CODE_MY (((u16)'M' << 8) | (u16)'Y') /* Malaysia */ +#define COUNTRY_CODE_MZ (((u16)'M' << 8) | (u16)'Z') /* Mozambique */ +#define COUNTRY_CODE_NA (((u16)'N' << 8) | (u16)'A') /* Namibia */ +#define COUNTRY_CODE_NC (((u16)'N' << 8) | (u16)'C') /* New Caledonia */ +#define COUNTRY_CODE_NE (((u16)'N' << 8) | (u16)'E') /* Niger */ +#define COUNTRY_CODE_NF (((u16)'N' << 8) | (u16)'F') /* Norfolk Island */ +#define COUNTRY_CODE_NG (((u16)'N' << 8) | (u16)'G') /* Nigeria */ +#define COUNTRY_CODE_NI (((u16)'N' << 8) | (u16)'I') /* Nicaragua */ +#define COUNTRY_CODE_NL (((u16)'N' << 8) | (u16)'L') /* Netherlands */ +#define COUNTRY_CODE_NO (((u16)'N' << 8) | (u16)'O') /* Norway */ +#define COUNTRY_CODE_NP (((u16)'N' << 8) | (u16)'P') /* Nepal */ +#define COUNTRY_CODE_NR (((u16)'N' << 8) | (u16)'R') /* Nauru */ +#define COUNTRY_CODE_NU (((u16)'N' << 8) | (u16)'U') /* Niue */ +#define COUNTRY_CODE_NZ (((u16)'N' << 8) | (u16)'Z') /* New Zealand */ +#define COUNTRY_CODE_OM (((u16)'O' << 8) | (u16)'M') /* Oman */ +#define COUNTRY_CODE_PA (((u16)'P' << 8) | (u16)'A') /* Panama */ +#define COUNTRY_CODE_PE (((u16)'P' << 8) | (u16)'E') /* Peru */ +#define COUNTRY_CODE_PF (((u16)'P' << 8) | (u16)'F') /* "French Polynesia */ +#define COUNTRY_CODE_PG (((u16)'P' << 8) | (u16)'G') /* Papua New Guinea */ +#define COUNTRY_CODE_PH (((u16)'P' << 8) | (u16)'H') /* Philippines */ +#define COUNTRY_CODE_PK (((u16)'P' << 8) | (u16)'K') /* Pakistan */ +#define COUNTRY_CODE_PL (((u16)'P' << 8) | (u16)'L') /* Poland */ +#define COUNTRY_CODE_PM \ + (((u16)'P' << 8) | (u16)'M') /* Saint Pierre and Miquelon */ +#define COUNTRY_CODE_PN (((u16)'P' << 8) | (u16)'N') /* Pitcairn Islands */ +#define COUNTRY_CODE_PR (((u16)'P' << 8) | (u16)'R') /* Puerto Rico (USA) */ +#define COUNTRY_CODE_PS (((u16)'P' << 8) | (u16)'S') +/* Palestinian Authority */ +#define COUNTRY_CODE_PT (((u16)'P' << 8) | (u16)'T') /* Portugal */ +#define COUNTRY_CODE_PW (((u16)'P' << 8) | (u16)'W') /* Palau */ +#define COUNTRY_CODE_PY (((u16)'P' << 8) | (u16)'Y') /* Paraguay */ +#define COUNTRY_CODE_QA (((u16)'Q' << 8) | (u16)'A') /* Qatar */ +#define COUNTRY_CODE_RE (((u16)'R' << 8) | (u16)'E') /* Reunion (France) */ +#define COUNTRY_CODE_RKS \ + (((u16)'R' << 8) | (u16)'K') /* Kosvo (Added on window's list) */ +#define COUNTRY_CODE_RO (((u16)'R' << 8) | (u16)'O') /* Romania */ +#define COUNTRY_CODE_RS (((u16)'R' << 8) | (u16)'S') /* Serbia */ +#define COUNTRY_CODE_RU (((u16)'R' << 8) | (u16)'U') /* Russia */ +#define COUNTRY_CODE_RW (((u16)'R' << 8) | (u16)'W') /* Rwanda */ +#define COUNTRY_CODE_SA (((u16)'S' << 8) | (u16)'A') /* Saudi Arabia */ +#define COUNTRY_CODE_SB (((u16)'S' << 8) | (u16)'B') /* Solomon Islands */ +#define COUNTRY_CODE_SC (((u16)'S' << 8) | (u16)'C') /* Seychelles */ +#define COUNTRY_CODE_SD (((u16)'S' << 8) | (u16)'D') /* Sudan */ +#define COUNTRY_CODE_SE (((u16)'S' << 8) | (u16)'E') /* Sweden */ +#define COUNTRY_CODE_SG (((u16)'S' << 8) | (u16)'G') /* Singapole */ +#define COUNTRY_CODE_SI (((u16)'S' << 8) | (u16)'I') /* Slovenia */ +#define COUNTRY_CODE_SK (((u16)'S' << 8) | (u16)'K') /* Slovakia */ +#define COUNTRY_CODE_SL (((u16)'S' << 8) | (u16)'L') /* Sierra Leone */ +#define COUNTRY_CODE_SM (((u16)'S' << 8) | (u16)'M') /* San Marino */ +#define COUNTRY_CODE_SN (((u16)'S' << 8) | (u16)'N') /* Senegal */ +#define COUNTRY_CODE_SO (((u16)'S' << 8) | (u16)'O') /* Somalia */ +#define COUNTRY_CODE_SR (((u16)'S' << 8) | (u16)'R') /* Suriname */ +#define COUNTRY_CODE_SS (((u16)'S' << 8) | (u16)'S') /* South_Sudan */ +#define COUNTRY_CODE_ST (((u16)'S' << 8) | (u16)'T') +/* Sao Tome and Principe */ +#define COUNTRY_CODE_SV (((u16)'S' << 8) | (u16)'V') /* El Salvador */ +#define COUNTRY_CODE_SY (((u16)'S' << 8) | (u16)'Y') /* Syria */ +#define COUNTRY_CODE_SZ (((u16)'S' << 8) | (u16)'Z') /* Swaziland */ +#define COUNTRY_CODE_TC \ + (((u16)'T' << 8) | (u16)'C') /* Turks and Caicos Islands (UK) */ +#define COUNTRY_CODE_TD (((u16)'T' << 8) | (u16)'D') /* Chad */ +#define COUNTRY_CODE_TF \ + (((u16)'T' << 8) | (u16)'F') /* French Southern and Antarctic Lands */ +#define COUNTRY_CODE_TG (((u16)'T' << 8) | (u16)'G') /* Togo */ +#define COUNTRY_CODE_TH (((u16)'T' << 8) | (u16)'H') /* Thailand */ +#define COUNTRY_CODE_TJ (((u16)'T' << 8) | (u16)'J') /* Tajikistan */ +#define COUNTRY_CODE_TL (((u16)'T' << 8) | (u16)'L') /* East Timor */ +#define COUNTRY_CODE_TM (((u16)'T' << 8) | (u16)'M') /* Turkmenistan */ +#define COUNTRY_CODE_TN (((u16)'T' << 8) | (u16)'N') /* Tunisia */ +#define COUNTRY_CODE_TO (((u16)'T' << 8) | (u16)'O') /* Tonga */ +#define COUNTRY_CODE_TR (((u16)'T' << 8) | (u16)'R') /* Turkey */ +#define COUNTRY_CODE_TT (((u16)'T' << 8) | (u16)'T') /* Trinidad and Tobago */ +#define COUNTRY_CODE_TV (((u16)'T' << 8) | (u16)'V') /* Tuvalu */ +#define COUNTRY_CODE_TW (((u16)'T' << 8) | (u16)'W') /* Taiwan */ +#define COUNTRY_CODE_TZ (((u16)'T' << 8) | (u16)'Z') /* Tanzania */ +#define COUNTRY_CODE_UA (((u16)'U' << 8) | (u16)'A') /* Ukraine */ +#define COUNTRY_CODE_UG (((u16)'U' << 8) | (u16)'G') /* Ugnada */ +#define COUNTRY_CODE_US (((u16)'U' << 8) | (u16)'S') /* US */ +#define COUNTRY_CODE_UY (((u16)'U' << 8) | (u16)'Y') /* Uruguay */ +#define COUNTRY_CODE_UZ (((u16)'U' << 8) | (u16)'Z') /* Uzbekistan */ +#define COUNTRY_CODE_VA (((u16)'V' << 8) | (u16)'A') /* Vatican (Holy See) */ +#define COUNTRY_CODE_VC \ + (((u16)'V' << 8) | (u16)'C') /* Saint Vincent and the Grenadines */ +#define COUNTRY_CODE_VE (((u16)'V' << 8) | (u16)'E') /* Venezuela */ +#define COUNTRY_CODE_VG \ + (((u16)'V' << 8) | (u16)'G') /* British Virgin Islands */ +#define COUNTRY_CODE_VI (((u16)'V' << 8) | (u16)'I') /* US Virgin Islands */ +#define COUNTRY_CODE_VN (((u16)'V' << 8) | (u16)'N') /* Vietnam */ +#define COUNTRY_CODE_VU (((u16)'V' << 8) | (u16)'U') /* Vanuatu */ +#define COUNTRY_CODE_WS (((u16)'W' << 8) | (u16)'S') /* Samoa */ +#define COUNTRY_CODE_YE (((u16)'Y' << 8) | (u16)'E') /* Yemen */ +#define COUNTRY_CODE_YT (((u16)'Y' << 8) | (u16)'T') /* Mayotte (France) */ +#define COUNTRY_CODE_ZA (((u16)'Z' << 8) | (u16)'A') /* South Africa */ +#define COUNTRY_CODE_ZM (((u16)'Z' << 8) | (u16)'M') /* Zambia */ +#define COUNTRY_CODE_ZW (((u16)'Z' << 8) | (u16)'W') /* Zimbabwe */ +#define COUNTRY_CODE_DF \ + (((u16)'D' << 8) | (u16)'F') /* Default country domain */ +#define COUNTRY_CODE_WW (((u16)'0' << 8) | (u16)'0') /* World Wide */ + +/* dot11RegDomainsSupportValue */ +#define MIB_REG_DOMAIN_FCC 0x10 /* FCC (US) */ +#define MIB_REG_DOMAIN_IC 0x20 /* IC or DOC (Canada) */ +#define MIB_REG_DOMAIN_ETSI 0x30 /* ETSI (Europe) */ +#define MIB_REG_DOMAIN_SPAIN 0x31 /* Spain */ +#define MIB_REG_DOMAIN_FRANCE 0x32 /* France */ +#define MIB_REG_DOMAIN_JAPAN 0x40 /* MPHPT (Japan) */ +#define MIB_REG_DOMAIN_OTHER 0x00 /* other */ + +/*2.4G*/ +#define BAND_2G4_LOWER_BOUND 1 +#define BAND_2G4_UPPER_BOUND 14 +/*5G SubBand FCC spec*/ +#define UNII1_LOWER_BOUND 36 +#define UNII1_UPPER_BOUND 48 +#define UNII2A_LOWER_BOUND 52 +#define UNII2A_UPPER_BOUND 64 +#define UNII2C_LOWER_BOUND 100 +#define UNII2C_UPPER_BOUND 144 +#define UNII3_LOWER_BOUND 149 +#define UNII3_UPPER_BOUND 173 + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + +#define POWER_LIMIT_TABLE_NULL 0xFFFF +#define MAX_TX_POWER 63 +#define MIN_TX_POWER -64 +#define MAX_CMD_SUPPORT_CHANNEL_NUM 64 + +#endif + +#if (CFG_SUPPORT_SINGLE_SKU == 1) +#define MAX_SUPPORTED_CH_COUNT MAX_CHN_NUM +#define REG_RULE_LIGHT(start, end, bw, reg_flags) \ + REG_RULE(start, end, bw, 0, 0, reg_flags) +#define TX_PWR_LIMIT_CMD_CH_NUM_THRESHOLD 32 +#endif +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + +typedef enum _ENUM_POWER_LIMIT_T { + PWR_LIMIT_CCK = 0, + PWR_LIMIT_20M = 1, + PWR_LIMIT_40M = 2, + PWR_LIMIT_80M = 3, + PWR_LIMIT_160M = 4, + PWR_LIMIT_NUM +} ENUM_POWER_LIMIT_T, +*P_ENUM_POWER_LIMIT_T; + +#endif + +typedef enum _ENUM_POWER_LIMIT_SUBBAND_T { + POWER_LIMIT_2G4 = 0, + POWER_LIMIT_UNII1 = 1, + POWER_LIMIT_UNII2A = 2, + POWER_LIMIT_UNII2C = 3, + POWER_LIMIT_UNII3 = 4, + POWER_LIMIT_SUBAND_NUM +} ENUM_POWER_LIMIT_SUBBAND_T, +*P_ENUM_POWER_LIMIT_SUBBAND_T; + +/* Define channel offset in unit of 5MHz bandwidth */ +typedef enum _ENUM_CHNL_SPAN_T { + CHNL_SPAN_5 = 1, + CHNL_SPAN_10 = 2, + CHNL_SPAN_20 = 4, + CHNL_SPAN_40 = 8 +} ENUM_CHNL_SPAN_T, +*P_ENUM_CHNL_SPAN_T; + +/* Define BSS operating bandwidth */ +typedef enum _ENUM_CHNL_BW_T { + CHNL_BW_20, + CHNL_BW_20_40, + CHNL_BW_10, + CHNL_BW_5 +} ENUM_CHNL_BW_T, +*P_ENUM_CHNL_BW_T; + +/* In all bands, the first channel will be SCA and the second channel is SCB, + * then iteratively. + * Note the final channel will not be SCA. + */ +typedef struct _DOMAIN_SUBBAND_INFO { + /* Note1: regulation class depends on operation bandwidth and RF band. + * For example: 2.4GHz, 1~13, 20MHz ==> regulation class = 81 + * 2.4GHz, 1~13, SCA ==> regulation class = 83 + * 2.4GHz, 1~13, SCB ==> regulation class = 84 + * Note2: TX power limit is not specified here because path loss is + * unknown + */ + u8 ucRegClass; /* Regulation class for 20MHz */ + u8 ucBand; /* Type: ENUM_BAND_T */ + u8 ucChannelSpan; /* Type: ENUM_CHNL_SPAN_T */ + u8 ucFirstChannelNum; + u8 ucNumChannels; + u8 fgDfs; /* Type: u8*/ +} DOMAIN_SUBBAND_INFO, *P_DOMAIN_SUBBAND_INFO; + +/* Use it as all available channel list for STA */ +typedef struct _DOMAIN_INFO_ENTRY { + u16 *pu2CountryGroup; + u32 u4CountryNum; + + /* If different attributes, put them into different rSubBands. + * For example, DFS shall be used or not. + */ + DOMAIN_SUBBAND_INFO rSubBand[MAX_SUBBAND_NUM]; +} DOMAIN_INFO_ENTRY, *P_DOMAIN_INFO_ENTRY; + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + +#if (CFG_SUPPORT_SINGLE_SKU == 1) +/* + * MT_TxPwrLimit.dat format + */ +#define SECTION_PREFIX (0x23232323) +#define ELEMENT_PREFIX (0xffff) +#define VERSION (0x00000001) +#define SIZE_OF_VERSION 4 +#if CFG_SUPPORT_LARGE_TX_PWR_LIMIT_TABLE +#define WLAN_TX_PWR_LIMIT_FILE_BUF_SIZE (204800 * 2) +#else +#define WLAN_TX_PWR_LIMIT_FILE_BUF_SIZE 204800 +#endif +#define WLAN_TX_PWR_LIMIT_FILE_NAME "TxPwrLimit_MT76x8.dat" + +struct tx_pwr_element { + u16 prefix; + u8 channel_num; + u8 reserved; + + /*the followings are in unit: 0.5 dbm*/ + + u8 tx_pwr_dsss_cck; + u8 tx_pwr_dsss_bpsk; + + u8 tx_pwr_ofdm_bpsk; /* 6M, 9M */ + u8 tx_pwr_ofdm_qpsk; /* 12M, 18M */ + u8 tx_pwr_ofdm_16qam; /* 24M, 36M */ + u8 tx_pwr_ofdm_48m; + u8 tx_pwr_ofdm_54m; + + u8 tx_pwr_ht20_bpsk; /* MCS0*/ + u8 tx_pwr_ht20_qpsk; /* MCS1, MCS2*/ + u8 tx_pwr_ht20_16qam; /* MCS3, MCS4*/ + u8 tx_pwr_ht20_mcs5; /* MCS5*/ + u8 tx_pwr_ht20_mcs6; /* MCS6*/ + u8 tx_pwr_ht20_mcs7; /* MCS7*/ + + u8 tx_pwr_ht40_bpsk; /* MCS0*/ + u8 tx_pwr_ht40_qpsk; /* MCS1, MCS2*/ + u8 tx_pwr_ht40_16qam; /* MCS3, MCS4*/ + u8 tx_pwr_ht40_mcs5; /* MCS5*/ + u8 tx_pwr_ht40_mcs6; /* MCS6*/ + u8 tx_pwr_ht40_mcs7; /* MCS7*/ + + u8 tx_pwr_vht20_bpsk; /* MCS0*/ + u8 tx_pwr_vht20_qpsk; /* MCS1, MCS2*/ + u8 tx_pwr_vht20_16qam; /* MCS3, MCS4*/ + u8 tx_pwr_vht20_64qam; /* MCS5, MCS6*/ + u8 tx_pwr_vht20_mcs7; + u8 tx_pwr_vht20_mcs8; + u8 tx_pwr_vht20_mcs9; + + u8 tx_pwr_vht_40; + u8 tx_pwr_vht_80; + u8 tx_pwr_vht_160nc; + u8 tx_pwr_lg_40; + u8 tx_pwr_lg_80; + + u8 tx_pwr_1ss_delta; + u8 reserved_3[3]; +}; + +struct tx_pwr_section { + u32 prefix; + u32 country_code; +}; +#endif + +/* CMD_SET_PWR_LIMIT_TABLE */ +typedef struct _CHANNEL_POWER_LIMIT { + u8 ucCentralCh; + s8 cPwrLimitCCK; + s8 cPwrLimit20; + s8 cPwrLimit40; + s8 cPwrLimit80; + s8 cPwrLimit160; + u8 ucFlag; + u8 aucReserved[1]; +} CHANNEL_POWER_LIMIT, *P_CHANNEL_POWER_LIMIT; + +typedef struct _COUNTRY_CHANNEL_POWER_LIMIT { + u8 aucCountryCode[2]; + u8 ucCountryFlag; + u8 ucChannelNum; + u8 aucReserved[4]; + CHANNEL_POWER_LIMIT rChannelPowerLimit[80]; +} COUNTRY_CHANNEL_POWER_LIMIT, *P_COUNTRY_CHANNEL_POWER_LIMIT; + +#define CHANNEL_PWR_LIMIT(_channel, _pwrLimit_cck, _pwrLimit_bw20, \ + _pwrLimit_bw40, _pwrLimit_bw80, _pwrLimit_bw160, \ + _ucFlag) \ + { \ + .ucCentralCh = (_channel), .cPwrLimitCCK = (_pwrLimit_cck), \ + .cPwrLimit20 = (_pwrLimit_bw20), \ + .cPwrLimit40 = (_pwrLimit_bw40), \ + .cPwrLimit80 = (_pwrLimit_bw80), \ + .cPwrLimit160 = (_pwrLimit_bw160), .ucFlag = (_ucFlag), \ + .aucReserved = { \ + 0 \ + } \ + } + +typedef struct _COUNTRY_POWER_LIMIT_TABLE_DEFAULT { + u8 aucCountryCode[2]; + /* 0: ch 1 ~14 , 1: ch 36 ~48, 2: ch 52 ~64, 3: ch 100 ~144, 4: ch 149 + * ~165 */ + s8 aucPwrLimitSubBand[POWER_LIMIT_SUBAND_NUM]; + /* bit0: cPwrLimit2G4, bit1: cPwrLimitUnii1; bit2: cPwrLimitUnii2A;*/ + /* bit3: cPwrLimitUnii2C; bit4: cPwrLimitUnii3; mW: 0, mW\MHz : 1 */ + u8 ucPwrUnit; +} COUNTRY_POWER_LIMIT_TABLE_DEFAULT, *P_COUNTRY_POWER_LIMIT_TABLE_DEFAULT; + +typedef struct _COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION { + u8 aucCountryCode[2]; + u8 ucCentralCh; + s8 aucPwrLimit[PWR_LIMIT_NUM]; +} COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION, +*P_COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION; + +typedef struct _SUBBAND_CHANNEL_T { + u8 ucStartCh; + u8 ucEndCh; + u8 ucInterval; + u8 ucReserved; +} SUBBAND_CHANNEL_T, *P_SUBBAND_CHANNEL_T; + +#endif + +#if (CFG_SUPPORT_SINGLE_SKU == 1) +/* + * Event from chip for single sku + */ +typedef struct _SINGLE_SKU_INFO { + u32 u4EfuseCountryCode; + u8 isEfuseValid; + u8 ucReserved[7]; +} SINGLE_SKU_INFO, *P_SINGLE_SKU_INFO; + +/* + * channel structure + */ +struct channel { + u16 chNum; + u8 reserved[2]; + u32 flags; /*enum ieee80211_channel_flags*/ +}; + +struct acctive_channel_list { + u8 n_channels_2g; + u8 n_channels_5g; + u8 ucReserved[2]; + struct channel channels[0]; +}; + +/* + * single sku control structure + */ +enum regd_state { + REGD_STATE_UNDEFINED, + REGD_STATE_INIT, + REGD_STATE_SET_WW_CORE, + REGD_STATE_SET_COUNTRY_USER, + REGD_STATE_SET_COUNTRY_DRIVER, + REGD_STATE_SET_COUNTRY_IE, + REGD_STATE_INVALID +}; + +enum regd_control_flag { + REGD_CTRL_FLAG_SUPPORT_LOCAL_REGD_DB = (0x1 << 0) +}; + +typedef struct mtk_regd_control_t { + u8 en; + u8 isEfuseCountryCodeUsed; + enum regd_state state; + u32 alpha2; + u32 tmp_alpha2; /*store country code set by iwpriv "country XX"*/ + u32 flag; /*enum regd_control_flag*/ + P_GLUE_INFO_T pGlueInfo; /*wlan GlueInfo*/ + u8 n_channel_active_2g; + u8 n_channel_active_5g; + struct channel channels[MAX_SUPPORTED_CH_COUNT]; + enum nl80211_dfs_regions dfs_region; +} mtk_regd_control; + +#if (CFG_SUPPORT_SINGLE_SKU_LOCAL_DB == 1) +struct mtk_regdomain { + char country_code[4]; + const struct ieee80211_regdomain *prRegdRules; +}; +#endif + +#endif +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define CAL_CH_OFFSET_80M(_PRIMARY_CH, _CENTRAL_CH) \ + (((_PRIMARY_CH - _CENTRAL_CH) + 6) >> 2) + +#define CAL_CH_OFFSET_160M(_PRIMARY_CH, _CENTRAL_CH) \ + (((_PRIMARY_CH - _CENTRAL_CH) + 14) >> 2) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +P_DOMAIN_INFO_ENTRY rlmDomainGetDomainInfo(P_ADAPTER_T prAdapter); + +void rlmDomainGetChnlList(P_ADAPTER_T prAdapter, + ENUM_BAND_T eSpecificBand, + u8 fgNoDfs, + u8 ucMaxChannelNum, + u8 *pucNumOfChannel, + P_RF_CHANNEL_INFO_T paucChannelList); + +#ifdef CFG_SUPPORT_SAP_DFS_CHANNEL +void rlmDomainGetDfsChnls(P_ADAPTER_T prAdapter, + u8 ucMaxChannelNum, + u8 *pucNumOfChannel, + P_RF_CHANNEL_INFO_T paucChannelList); +#endif + +void rlmDomainSendCmd(P_ADAPTER_T prAdapter, u8 fgIsOid); + +void rlmDomainSendDomainInfoCmd(P_ADAPTER_T prAdapter, u8 fgIsOid); + +void rlmDomainSendPassiveScanInfoCmd(P_ADAPTER_T prAdapter, u8 fgIsOid); + +u32 rlmDomainSupOperatingClassIeFill(u8 *pBuf); + +u8 rlmDomainCheckChannelEntryValid(P_ADAPTER_T prAdapter, u8 ucCentralCh); + +u8 rlmDomainGetCenterChannel(ENUM_BAND_T eBand, + u8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend); + +u8 rlmDomainIsValidRfSetting(P_ADAPTER_T prAdapter, + ENUM_BAND_T eBand, + u8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend, + ENUM_CHANNEL_WIDTH_T eChannelWidth, + u8 ucChannelS1, + u8 ucChannelS2); + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + +u8 rlmDomainCheckPowerLimitValid(P_ADAPTER_T prAdapter, + COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION + rPowerLimitTableConfiguration, + u8 ucPwrLimitNum); + +void rlmDomainCheckCountryPowerLimitTable(P_ADAPTER_T prAdapter); + +u16 rlmDomainPwrLimitDefaultTableDecision(P_ADAPTER_T prAdapter, + u16 u2CountryCode); + +void rlmDomainSendPwrLimitCmd(P_ADAPTER_T prAdapter); +#endif + +#if (CFG_SUPPORT_SINGLE_SKU == 1) +extern struct ieee80211_supported_band mtk_band_2ghz; +extern struct ieee80211_supported_band mtk_band_5ghz; + +u8 rlmDomainIsCtrlStateEqualTo(enum regd_state state); +u8 rlmDomainIsUsingLocalRegDomainDataBase(void); +enum regd_state rlmDomainStateTransition(enum regd_state request_state, + struct regulatory_request *pRequest); +void rlmDomainSetCountryCode(char *alpha2, u8 size_of_alpha2); +void rlmDomainSetDfsRegion(enum nl80211_dfs_regions dfs_region); +enum nl80211_dfs_regions rlmDomainGetDfsRegion(void); +void rlmDomainResetCtrlInfo(u8 force); +void rlmDomainAddActiveChannel(u8 band); +u8 rlmDomainGetActiveChannelCount(u8 band); +void rlmDomainParsingChannel(IN struct wiphy *pWiphy); +struct channel *rlmDomainGetActiveChannels(void); +void rlmExtractChannelInfo(u32 max_ch_count, + struct acctive_channel_list *prBuff); +void regd_set_using_local_regdomain_db(void); +void rlmDomainSetDefaultCountryCode(void); +enum regd_state rlmDomainGetCtrlState(void); +bool rlmDomainIsSameCountryCode(char *alpha2, u8 size_of_alpha2); +const struct ieee80211_regdomain * +rlmDomainSearchRegdomainFromLocalDataBase(char *alpha2); +P_GLUE_INFO_T rlmDomainGetGlueInfo(void); +bool rlmDomainIsEfuseUsed(void); +u8 rlmDomainGetChannelBw(u8 channelNum); +#if (CFG_SUPPORT_SINGLE_SKU_LOCAL_DB == 1) +extern const struct mtk_regdomain *g_prRegRuleTable[]; +#endif + +#endif + +const struct ieee80211_regdomain *rlmDomainGetLocalDefaultRegd(void); +void rlmDomainSendInfoToFirmware(IN P_ADAPTER_T prAdapter); +WLAN_STATUS rlmDomainExtractSingleSkuInfoFromFirmware(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +u8 regd_is_single_sku_en(void); +#ifdef CFG_SUPPORT_SAP_DFS_CHANNEL +u8 rlmDomainIsLegalDfsChannel(P_ADAPTER_T prAdapter, + ENUM_BAND_T eBand, + u8 ucChannel); +#endif +u8 rlmDomainIsLegalChannel(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, + u8 ucChannel); +ENUM_CHNL_EXT_T rlmSelectSecondaryChannelType(P_ADAPTER_T prAdapter, + ENUM_BAND_T band, + u8 primary_ch); +extern void mtk_reg_notify(IN struct wiphy *pWiphy, + IN struct regulatory_request *pRequest); +void rlmDomainOidSetCountry(IN P_ADAPTER_T prAdapter, + char *country, + u8 size_of_country); +u32 rlmDomainGetCountryCode(void); +u32 rlmDomainGetTempCountryCode(void); +void rlmDomainAssert(u8 cond); +void rlmDomainOverridePwrLimitFileName(const char *); +void rlmDomainSendPwrLimitCmd_V2(P_ADAPTER_T prAdapter); +void rlmDomainGetChnlList_V2(P_ADAPTER_T prAdapter, ENUM_BAND_T eSpecificBand, + u8 fgNoDfs, u8 ucMaxChannelNum, + u8 *pucNumOfChannel, + P_RF_CHANNEL_INFO_T paucChannelList); +void rlmDomainSendDomainInfoCmd_V2(P_ADAPTER_T prAdapter, u8 fgIsOid); +u8 rlmDomainIsLegalChannel_V2(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, + u8 ucChannel); +u32 rlmDomainAlpha2ToU32(s8 *pcAlpha2, u8 ucAlpha2Size); +u8 rlmDomainIsLegalChannel_V2(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, + u8 ucChannel); +u8 rlmDomainTxPwrLimitSearchSection(const char *pSectionName, s8 *pucBuf, + u32 *pu4Pos, u32 u4BufEnd); +u8 rlmDomainTxPwrLimitGetCountryRange(u32 u4CountryCode, u8 *pucBuf, + u32 u4BufLen, u32 *pu4CountryStart, + u32 *pu4CountryEnd); +u8 rlmDomainTxPwrLimitSectionEnd(u8 *pucBuf, const char *pSectionName, + u32 *pu4Pos, u32 u4BufEnd); +void rlmDomainTxPwrLimitRemoveComments(u8 *pucBuf, u32 u4BufLen); +void rlmDomainResetActiveChannel(void); +void rlmDomainSetTempCountryCode(char *alpha2, u8 size_of_alpha2); +void rlmDomainChannelFlagString(u32 flags, char *buf, size_t buf_size); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm_obss.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm_obss.h new file mode 100644 index 00000000000000..b5811df390caef --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm_obss.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "rlm_obss.h" + * \brief + */ + +#ifndef _RLM_OBSS_H +#define _RLM_OBSS_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define CHNL_LIST_SZ_2G 14 +#define CHNL_LIST_SZ_5G 14 + +#define CHNL_LEVEL0 0 +#define CHNL_LEVEL1 1 +#define CHNL_LEVEL2 2 + +#define AFFECTED_CHNL_OFFSET 5 + +#define OBSS_SCAN_MIN_INTERVAL 10 /* In unit of sec */ + +#define PUBLIC_ACTION_MAX_LEN 200 /* In unit of byte */ + +/* P2P GO only */ +/* Define default OBSS Scan parameters (from MIB in spec.) */ +#define dot11OBSSScanPassiveDwell 20 +#define dot11OBSSScanActiveDwell 10 +#define dot11OBSSScanPassiveTotalPerChannel 200 +#define dot11OBSSScanActiveTotalPerChannel 20 +#define dot11BSSWidthTriggerScanInterval 300 /* Unit: sec */ +#define dot11BSSWidthChannelTransitionDelayFactor 5 +#define dot11OBSSScanActivityThreshold 25 + +#define OBSS_20_40M_TIMEOUT ( \ + dot11BSSWidthTriggerScanInterval + 10) + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* Control MAC PCO function */ +typedef enum _ENUM_SYS_PCO_PHASE_T { + SYS_PCO_PHASE_DISABLED = 0, + SYS_PCO_PHASE_20M, + SYS_PCO_PHASE_40M +} ENUM_SYS_PCO_PHASE_T, +*P_ENUM_SYS_PCO_PHASE_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void rlmObssInit(P_ADAPTER_T prAdapter); + +void rlmObssScanDone(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr); + +void rlmObssTriggerScan(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +u8 rlmObssUpdateChnlLists(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm_protection.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm_protection.h new file mode 100644 index 00000000000000..49ff9a06fdf53b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm_protection.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "rlm_protection.h" + * \brief + */ + +#ifndef _RLM_PROTECTION_H +#define _RLM_PROTECTION_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef enum _ENUM_SYS_PROTECT_MODE_T { + SYS_PROTECT_MODE_NONE = 0, /* Mode 0 */ + SYS_PROTECT_MODE_ERP, /* Mode 1 */ + SYS_PROTECT_MODE_NON_HT, /* Mode 2 */ + SYS_PROTECT_MODE_20M, /* Mode 3 */ + + SYS_PROTECT_MODE_NUM +} ENUM_SYS_PROTECT_MODE_T, +*P_ENUM_SYS_PROTECT_MODE_T; + +/* This definition follows HT Protection field of HT Operation IE */ +typedef enum _ENUM_HT_PROTECT_MODE_T { + HT_PROTECT_MODE_NONE = 0, + HT_PROTECT_MODE_NON_MEMBER, + HT_PROTECT_MODE_20M, + HT_PROTECT_MODE_NON_HT, + + HT_PROTECT_MODE_NUM +} ENUM_HT_PROTECT_MODE_T, +*P_ENUM_HT_PROTECT_MODE_T; + +typedef enum _ENUM_GF_MODE_T { + GF_MODE_NORMAL = 0, + GF_MODE_PROTECT, + GF_MODE_DISALLOWED, + + GF_MODE_NUM +} ENUM_GF_MODE_T, +*P_ENUM_GF_MODE_T; + +typedef enum _ENUM_RIFS_MODE_T { + RIFS_MODE_NORMAL = 0, + RIFS_MODE_DISALLOWED, + + RIFS_MODE_NUM +} ENUM_RIFS_MODE_T, +*P_ENUM_RIFS_MODE_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm_txpwr_init.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm_txpwr_init.h new file mode 100644 index 00000000000000..1f86b0d730ca22 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rlm_txpwr_init.h @@ -0,0 +1,334 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "rlm_txpwr_init.h" + * \brief + */ + +/* +** Log: rlm_txpwr_init.h +*/ + +#ifndef _RLM_TXPWR_INIT_H +#define _RLM_TXPWR_INIT_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/*Support Tx Power Range : 63~ -64 (unit : 0.5dBm)*/ + +#define PWR_LIMIT_2G4_IN_MW_MHZ BIT(0) +#define PWR_LIMIT_UNII1_IN_MW_MHZ BIT(1) +#define PWR_LIMIT_UNII2A_IN_MW_MHZ BIT(2) +#define PWR_LIMIT_UNII2C_IN_MW_MHZ BIT(3) +#define PWR_LIMIT_UNII3_IN_MW_MHZ BIT(4) + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + +COUNTRY_POWER_LIMIT_TABLE_DEFAULT g_rRlmPowerLimitDefault[] = { + { { 'A', 'O' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'B', 'Z' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'B', 'J' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'B', 'T' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'B', 'O' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'B', 'I' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'C', 'M' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'C', 'F' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'T', 'D' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'K', 'M' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'C', 'D' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'C', 'G' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'C', 'I' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'D', 'J' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'G', 'Q' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'E', 'R' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'F', 'J' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'G', 'A' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'G', 'M' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'G', 'N' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'G', 'W' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'R', 'K' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'K', 'G' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'L', 'Y' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'M', 'G' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'M', 'L' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'N', 'R' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'N', 'C' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'S', 'T' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'S', 'C' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'S', 'L' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'S', 'B' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'S', 'O' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'S', 'R' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'S', 'Z' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'T', 'J' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'T', 'G' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'T', 'O' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'T', 'M' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'T', 'V' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'V', 'U' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'Y', 'E' }, { 40, 63, 63, 63, 63 }, 0 }, + { { 'A', 'S' }, { 60, 34, 46, 48, 60 }, 0 }, + { { 'A', 'I' }, { 60, 34, 48, 60, 60 }, 0 }, + { { 'B', 'M' }, { 60, 34, 48, 48, 60 }, 0 }, + { { 'C', 'A' }, { 60, 46, 48, 48, 60 }, 0 }, + { { 'K', 'Y' }, { 60, 34, 48, 60, 60 }, 0 }, + { { 'G', 'U' }, { 60, 34, 48, 48, 60 }, 0 }, + { { 'F', 'M' }, { 60, 34, 48, 48, 60 }, 0 }, + { { 'P', 'R' }, { 60, 34, 46, 48, 60 }, 0 }, + { { 'U', 'S' }, { 60, 34, 48, 48, 60 }, 0 }, + { { 'V', 'I' }, { 60, 34, 48, 48, 60 }, 0 }, + { { 'A', 'R' }, { 60, 34, 48, 48, 60 }, 0 }, + { { 'A', 'U' }, { 63, 46, 46, 60, 63 }, 0 }, + { { 'A', 'Z' }, { 40, 34, 48, 60, 60 }, 0 }, + { { 'B', 'W' }, { 40, 46, 46, 60, 60 }, 0 }, + { { 'K', 'H' }, { 40, 46, 46, 48, 60 }, 0 }, + { { 'C', 'X' }, { 63, 46, 46, 60, 63 }, 0 }, + { { 'C', 'O' }, { 60, 34, 48, 48, 60 }, 0 }, + { { 'C', 'R' }, { 60, 34, 48, 48, 60 }, 0 }, + { { 'E', 'C' }, { 60, 34, 48, 48, 60 }, 0 }, + { { 'G', 'D' }, { 40, 46, 46, 60, 60 }, 0 }, + { { 'G', 'T' }, { 40, 34, 48, 48, 60 }, 0 }, + { { 'H', 'K' }, { 63, 46, 46, 60, 63 }, 0 }, + { { 'K', 'I' }, { 63, 46, 46, 60, 63 }, 0 }, + { { 'L', 'B' }, { 40, 46, 46, 46, 46 }, 0 }, + { { 'L', 'R' }, { 60, 46, 60, 63, 63 }, 0 }, + { { 'M', 'N' }, { 46, 32, 46, 46, 58 }, 0 }, + { { 'A', 'N' }, { 60, 34, 48, 48, 60 }, 0 }, + { { 'N', 'Z' }, { 63, 46, 60, 48, 63 }, 0 }, + { { 'N', 'I' }, { 60, 34, 48, 48, 60 }, 0 }, + { { 'P', 'W' }, { 60, 60, 60, 60, 60 }, 0 }, + { { 'P', 'Y' }, { 60, 46, 46, 48, 60 }, 0 }, + { { 'P', 'E' }, { 54, 46, 48, 42, 48 }, 0 }, + { { 'P', 'H' }, { 40, 46, 46, 48, 48 }, 0 }, + { { 'W', 'S' }, { 40, 40, 40, 40, 60 }, 0 }, + { { 'S', 'G' }, { 46, 46, 46, 60, 60 }, 0 }, + { { 'L', 'K' }, { 46, 46, 46, 46, 46 }, 0 }, + { { 'T', 'H' }, { 40, 46, 46, 60, 60 }, 0 }, + { { 'T', 'T' }, { 60, 46, 46, 60, 60 }, 0 }, + { { 'U', 'Y' }, { 63, 46, 46, 46, 46 }, 0 }, + { { 'V', 'N' }, { 46, 46, 46, 60, 60 }, 0 }, + { { 'A', 'W' }, { 60, 46, 60, 60, 63 }, 0 }, + { { 'L', 'A' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'S', 'A' }, { 40, 46, 46, 60, 60 }, 0 }, + { { 'A', 'E' }, { 40, 46, 46, 60, 46 }, 0 }, + { { 'U', 'G' }, { 40, 46, 46, 48, 60 }, 0 }, + { { 'M', 'M' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'A', 'L' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'D', 'Z' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'A', 'D' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'A', 'T' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'B', 'Y' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'B', 'E' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'B', 'A' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'V', 'G' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'B', 'G' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'C', 'V' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'H', 'R' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'C', 'Y' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'C', 'Z' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'D', 'K' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'E', 'E' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'E', 'T' }, { 40, 40, 40, 40, 63 }, 0 }, + { { 'F', 'I' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'F', 'R' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'G', 'F' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'P', 'F' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'T', 'F' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'G', 'E' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'D', 'E' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'G', 'H' }, { 40, 34, 48, 60, 63 }, 0 }, + { { 'G', 'R' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'G', 'P' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'H', 'U' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'I', 'S' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'I', 'Q' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'I', 'E' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'I', 'T' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'K', 'E' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'L', 'V' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'L', 'S' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'L', 'I' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'L', 'T' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'L', 'U' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'M', 'K' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'M', 'T' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'M', 'Q' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'M', 'R' }, { 40, 46, 46, 46, 63 }, 0 }, + { { 'M', 'U' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'Y', 'T' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'M', 'D' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'M', 'C' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'M', 'E' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'M', 'S' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'N', 'L' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'N', 'O' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'O', 'M' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'P', 'L' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'P', 'T' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'R', 'E' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'R', 'O' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'M', 'F' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'S', 'M' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'S', 'N' }, { 40, 40, 40, 60, 63 }, 0 }, + { { 'R', 'S' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'S', 'K' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'S', 'I' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'Z', 'A' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'E', 'S' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'S', 'E' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'C', 'H' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'T', 'R' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'T', 'C' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'G', 'B' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'V', 'A' }, { 40, 46, 46, 60, 63 }, 0 }, + { { 'A', 'M' }, { 40, 40, 40, 63, 63 }, 0 }, + { { 'I', 'L' }, { 40, 46, 46, 63, 63 }, 0 }, + { { 'K', 'W' }, { 40, 46, 46, 63, 63 }, 0 }, + { { 'M', 'A' }, { 40, 46, 46, 63, 63 }, 0 }, + { { 'N', 'E' }, { 40, 46, 46, 63, 63 }, 0 }, + { { 'T', 'N' }, { 40, 46, 46, 63, 63 }, 0 }, + { { 'E', 'H' }, { 40, 46, 46, 63, 63 }, 0 }, + { { 'N', 'P' }, { 60, 46, 46, 63, 60 }, 0 }, + { { 'A', 'F' }, { 40, 46, 63, 63, 63 }, 0 }, + { { 'A', 'G' }, { 40, 46, 48, 63, 54 }, 0 }, + { { 'B', 'S' }, { 63, 46, 60, 63, 63 }, 0 }, + { { 'B', 'H' }, { 40, 46, 46, 63, 63 }, 0 }, + { { 'B', 'B' }, { 40, 46, 48, 63, 54 }, 0 }, + { { 'B', 'N' }, { 46, 46, 46, 63, 60 }, 0 }, + { { 'C', 'L' }, { 40, 44, 44, 63, 44 }, 0 }, + { { 'C', 'N' }, { 40, 46, 46, 63, 54 }, 0 }, + { { 'E', 'G' }, { 40, 46, 46, 63, 46 }, 0 }, + { { 'S', 'V' }, { 60, 34, 48, 63, 60 }, 0 }, + { { 'I', 'N' }, { 60, 46, 46, 63, 60 }, 0 }, + { { 'M', 'Y' }, { 54, 60, 60, 63, 60 }, 0 }, + { { 'M', 'V' }, { 40, 46, 46, 63, 40 }, 0 }, + { { 'P', 'A' }, { 60, 34, 48, 63, 60 }, 0 }, + { { 'V', 'E' }, { 60, 46, 46, 63, 60 }, 0 }, + { { 'Z', 'M' }, { 60, 46, 46, 63, 60 }, 0 }, + { { 'J', 'O' }, { 40, 46, 63, 63, 46 }, 0 }, + { { 'P', 'G' }, { 40, 46, 63, 63, 60 }, 0 }, + { { 'B', 'F' }, { 40, 63, 63, 63, 60 }, 0 }, + { { 'G', 'Y' }, { 60, 63, 63, 63, 60 }, 0 }, + { { 'H', 'T' }, { 40, 63, 63, 63, 60 }, 0 }, + { { 'H', 'N' }, { 60, 63, 63, 63, 60 }, 0 }, + { { 'J', 'M' }, { 54, 63, 63, 63, 57 }, 0 }, + { { 'M', 'O' }, { 40, 63, 63, 63, 40 }, 0 }, + { { 'M', 'W' }, { 60, 63, 63, 63, 60 }, 0 }, + { { 'P', 'K' }, { 40, 63, 63, 63, 40 }, 0 }, + { { 'Q', 'A' }, { 40, 63, 63, 63, 40 }, 0 }, + { { 'R', 'W' }, { 40, 63, 63, 63, 60 }, 0 }, + { { 'K', 'N' }, { 40, 63, 63, 63, 60 }, 0 }, + { { 'T', 'Z' }, { 40, 63, 63, 63, 40 }, 0 }, + { { 'I', 'D' }, { 46, 63, 63, 63, 60 }, 0 }, + { { 'N', 'G' }, { 40, 63, 46, 63, 60 }, 0 }, + { { 'B', 'D' }, { 40, 46, 46, 60, 28 }, 0 }, + { { 'B', 'R' }, { 52, 46, 46, 60, 60 }, 0 }, + { { 'D', 'M' }, { 60, 34, 46, 48, 60 }, 0 }, + { { 'D', 'O' }, { 63, 46, 46, 60, 63 }, 0 }, + { { 'F', 'K' }, { 40, 46, 46, 60, 28 }, 0 }, + { { 'K', 'Z' }, { 40, 34, 48, 60, 60 }, 0 }, + { { 'M', 'X' }, { 60, 34, 48, 60, 63 }, 0 }, + { { 'M', 'Z' }, { 40, 34, 46, 48, 60 }, 0 }, + { { 'N', 'A' }, { 40, 34, 46, 48, 60 }, 0 }, + { { 'R', 'U' }, { 40, 34, 48, 60, 60 }, 0 }, + { { 'L', 'C' }, { 40, 34, 48, 48, 60 }, 0 }, + { { 'V', 'C' }, { 40, 34, 46, 48, 60 }, 0 }, + { { 'U', 'A' }, { 40, 46, 46, 46, 48 }, 0 }, + { { 'U', 'Z' }, { 40, 48, 48, 48, 60 }, 0 }, + { { 'Z', 'W' }, { 40, 34, 46, 48, 60 }, 0 }, + { { 'M', 'P' }, { 60, 34, 46, 48, 60 }, 0 }, + { { 'T', 'W' }, { 60, 63, 34, 48, 60 }, 0 }, + { { 'C', 'K' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'C', 'U' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'T', 'L' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'F', 'O' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'G', 'I' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'G', 'G' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'I', 'R' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'I', 'M' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'J', 'E' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'K', 'P' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'M', 'H' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'N', 'U' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'N', 'F' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'P', 'S' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'P', 'N' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'P', 'M' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'S', 'S' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'S', 'D' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'S', 'Y' }, { 63, 63, 63, 63, 63 }, 0 }, + { { 'J', 'P' }, { 46, 46, 46, 60, 63 }, 0 }, + { { 'K', 'R' }, { 46, 34, 46, 46, 46 }, PWR_LIMIT_UNII1_IN_MW_MHZ }, + + /*Default*/ + { { 0, 0 }, { 63, 63, 63, 63, 63 }, 0 } +}; + +COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION g_rRlmPowerLimitConfiguration[] = { + { { 'A', 'I' }, 144, { 48, 48, 48, 48, 48 } }, + { { 'A', 'Z' }, 144, { 48, 48, 48, 48, 48 } }, + { { 'B', 'W' }, 144, { 48, 48, 48, 48, 48 } }, + { { 'G', 'D' }, 144, { 48, 48, 48, 48, 48 } }, + { { 'L', 'B' }, 144, { 48, 48, 48, 48, 48 } }, + { { 'L', 'R' }, 144, { 48, 48, 48, 48, 48 } }, + { { 'W', 'S' }, 165, { 40, 40, 40, 40, 40 } }, + { { 'V', 'N' }, 144, { 48, 48, 48, 48, 48 } }, + { { 'U', 'S' }, 1, { 38, 30, 60, 60, 60 } }, + { { 'U', 'S' }, 3, { 60, 60, 26, 60, 60 } }, + { { 'U', 'S' }, 9, { 60, 60, 26, 60, 60 } }, + { { 'U', 'S' }, 11, { 38, 30, 60, 60, 60 } }, + { { 'U', 'S' }, 36, { 34, 34, 34, 34, 34 } }, + { { 'U', 'S' }, 38, { 34, 34, 34, 34, 34 } }, + { { 'U', 'S' }, 42, { 34, 34, 34, 31, 34 } }, + { { 'U', 'S' }, 58, { 48, 48, 48, 31, 48 } }, + { { 'U', 'S' }, 62, { 48, 48, 34, 48, 48 } }, + { { 'U', 'S' }, 64, { 37, 37, 48, 48, 48 } }, + { { 'U', 'S' }, 100, { 37, 37, 48, 48, 48 } }, + { { 'U', 'S' }, 102, { 48, 48, 34, 48, 48 } }, + { { 'U', 'S' }, 106, { 48, 48, 48, 31, 48 } }, + { { 'U', 'S' }, 155, { 60, 60, 60, 31, 60 } }, + { { 'U', 'S' }, 159, { 60, 60, 34, 60, 60 } }, + { { 'U', 'S' }, 165, { 37, 37, 60, 60, 60 } }, + + /*Default*/ + { { 0, 0 }, 165, { 63, 63, 63, 63, 63 } } +}; + +#endif + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/roaming_fsm.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/roaming_fsm.h new file mode 100644 index 00000000000000..4e25ed8edebc06 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/roaming_fsm.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "roaming_fsm.h" + * \brief This file defines the FSM for Roaming MODULE. + * + * This file defines the FSM for Roaming MODULE. + */ + +#ifndef _ROAMING_FSM_H +#define _ROAMING_FSM_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* Roaming Discovery interval, SCAN result need to be updated */ +#define ROAMING_DISCOVERY_TIMEOUT_SEC 5 /* Seconds. */ +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP +#define ROAMING_ONE_AP_SKIP_TIMES 3 +#endif + +/* #define ROAMING_NO_SWING_RCPI_STEP 5 //rcpi */ +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef enum _ENUM_ROAMING_FAIL_REASON_T { + ROAMING_FAIL_REASON_CONNLIMIT = 0, + ROAMING_FAIL_REASON_NOCANDIDATE, + ROAMING_FAIL_REASON_NUM +} ENUM_ROAMING_FAIL_REASON_T; + +/* events of roaming between driver and firmware */ +typedef enum _ENUM_ROAMING_EVENT_T { + ROAMING_EVENT_START = 0, + ROAMING_EVENT_DISCOVERY, + ROAMING_EVENT_ROAM, + ROAMING_EVENT_FAIL, + ROAMING_EVENT_ABORT, + ROAMING_EVENT_NUM +} ENUM_ROAMING_EVENT_T; + +typedef enum _ENUM_ROAMING_REASON_T { + ROAMING_REASON_POOR_RCPI = 0, + ROAMING_REASON_TX_ERR, /*Lowest rate, high PER*/ + ROAMING_REASON_RETRY, + ROAMING_REASON_NUM +} ENUM_ROAMING_REASON_T; + +typedef struct _CMD_ROAMING_TRANSIT_T { + u16 u2Event; + u16 u2Data; + u16 u2RcpiLowThreshold; + u8 ucIsSupport11B; + u8 aucReserved[1]; + ENUM_ROAMING_REASON_T eReason; + u32 u4RoamingTriggerTime; /*sec in mcu*/ + u8 aucReserved2[8]; +} CMD_ROAMING_TRANSIT_T, *P_CMD_ROAMING_TRANSIT_T; + +typedef struct _CMD_ROAMING_CTRL_T { + u8 fgEnable; + u8 ucRcpiAdjustStep; + u16 u2RcpiLowThr; + u8 ucRoamingRetryLimit; + u8 ucRoamingStableTimeout; + u8 aucReserved[2]; +} CMD_ROAMING_CTRL_T, *P_CMD_ROAMING_CTRL_T; + +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP +typedef struct _CMD_ROAMING_SKIP_ONE_AP_T { + u8 fgIsRoamingSkipOneAP; + u8 aucReserved[3]; + u8 aucReserved2[8]; +} CMD_ROAMING_SKIP_ONE_AP_T, *P_CMD_ROAMING_SKIP_ONE_AP_T; +#endif + +/**/ typedef enum _ENUM_ROAMING_STATE_T { + ROAMING_STATE_IDLE = 0, + ROAMING_STATE_DECISION, + ROAMING_STATE_DISCOVERY, +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + ROAMING_STATE_REQ_CAND_LIST, +#endif + ROAMING_STATE_ROAM, + ROAMING_STATE_NUM +} ENUM_ROAMING_STATE_T; + +typedef struct _ROAMING_INFO_T { + u8 fgIsEnableRoaming; + + ENUM_ROAMING_STATE_T eCurrentState; + + u32 rRoamingDiscoveryUpdateTime; +} ROAMING_INFO_T, *P_ROAMING_INFO_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#if CFG_SUPPORT_ROAMING +#define IS_ROAMING_ACTIVE(prAdapter) \ + (prAdapter->rWifiVar.rRoamingInfo.eCurrentState == ROAMING_STATE_ROAM) +#else +#define IS_ROAMING_ACTIVE(prAdapter) false +#endif + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void roamingFsmInit(IN P_ADAPTER_T prAdapter); + +void roamingFsmUninit(IN P_ADAPTER_T prAdapter); + +void roamingFsmSendCmd(IN P_ADAPTER_T prAdapter, + IN P_CMD_ROAMING_TRANSIT_T prTransit); + +void roamingFsmScanResultsUpdate(IN P_ADAPTER_T prAdapter); + +void roamingFsmSteps(IN P_ADAPTER_T prAdapter, + IN ENUM_ROAMING_STATE_T eNextState); + +void roamingFsmRunEventStart(IN P_ADAPTER_T prAdapter); + +void roamingFsmRunEventDiscovery(IN P_ADAPTER_T prAdapter, + IN P_CMD_ROAMING_TRANSIT_T prTransit); + +void roamingFsmRunEventRoam(IN P_ADAPTER_T prAdapter); + +void roamingFsmRunEventFail(IN P_ADAPTER_T prAdapter, IN u32 u4Reason); + +void roamingFsmRunEventAbort(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS roamingFsmProcessEvent(IN P_ADAPTER_T prAdapter, + IN P_CMD_ROAMING_TRANSIT_T prTransit); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rsn.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rsn.h new file mode 100644 index 00000000000000..a6bf93196e919d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/rsn.h @@ -0,0 +1,275 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file rsn.h + * \brief The wpa/rsn related define, macro and structure are described + * here. + */ + +#ifndef _RSN_H +#define _RSN_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* ----- Definitions for Cipher Suite Selectors ----- */ +#define RSN_CIPHER_SUITE_USE_GROUP_KEY 0x00AC0F00 +#define RSN_CIPHER_SUITE_WEP40 0x01AC0F00 +#define RSN_CIPHER_SUITE_TKIP 0x02AC0F00 +#define RSN_CIPHER_SUITE_CCMP 0x04AC0F00 +#define RSN_CIPHER_SUITE_WEP104 0x05AC0F00 +#define RSN_CIPHER_SUITE_AES_128_CMAC 0x06AC0F00 + +#define RSN_CIPHER_SUITE_GROUP_NOT_USED 0x07AC0F00 +#define RSN_CIPHER_SUITE_GCMP 0x08AC0F00 +#define RSN_CIPHER_SUITE_GCMP_256 0x09AC0F00 +#define RSN_CIPHER_SUITE_CCMP_256 0x0AAC0F00 +#define RSN_CIPHER_SUITE_BIP_GMAC_128 0x0BAC0F00 +#define RSN_CIPHER_SUITE_BIP_GMAC_256 0x0CAC0F00 +#define RSN_CIPHER_SUITE_BIP_CMAC_256 0x0DAC0F00 + +#define WPA_CIPHER_SUITE_NONE 0x00F25000 +#define WPA_CIPHER_SUITE_WEP40 0x01F25000 +#define WPA_CIPHER_SUITE_TKIP 0x02F25000 +#define WPA_CIPHER_SUITE_CCMP 0x04F25000 +#define WPA_CIPHER_SUITE_WEP104 0x05F25000 + +/* ----- Definitions for Authentication and Key Management Suite Selectors ----- + */ +#define RSN_AKM_SUITE_NONE 0x00AC0F00 +#define RSN_AKM_SUITE_802_1X 0x01AC0F00 +#define RSN_AKM_SUITE_PSK 0x02AC0F00 +#define RSN_AKM_SUITE_802_1X_SHA256 0x05AC0F00 +#define RSN_AKM_SUITE_PSK_SHA256 0x06AC0F00 + +#define RSN_AKM_SUITE_SAE 0x08AC0F00 +#define RSN_AKM_SUITE_8021X_SUITE_B 0x0BAC0F00 +#define RSN_AKM_SUITE_8021X_SUITE_B_192 0x0CAC0F00 +#define RSN_AKM_SUITE_OWE 0x12AC0F00 + +#define WPA_AKM_SUITE_NONE 0x00F25000 +#define WPA_AKM_SUITE_802_1X 0x01F25000 +#define WPA_AKM_SUITE_PSK 0x02F25000 +#define WLAN_CIPHER_SUITE_NO_GROUP_ADDR 0x000fac07 + +#define ELEM_ID_RSN_LEN_FIXED 20 /* The RSN IE len for associate request */ + +#define ELEM_ID_WPA_LEN_FIXED 22 /* The RSN IE len for associate request */ + +#define MASK_RSNIE_CAP_PREAUTH BIT(0) + +#define GET_SELECTOR_TYPE(x) ((u8)(((x) >> 24) & 0x000000FF)) +#define SET_SELECTOR_TYPE(x, y) \ + (x = (((x) & 0x00FFFFFF) | (((u32)(y) << 24) & 0xFF000000))) + +#define AUTH_CIPHER_CCMP 0x00000008 + +/* Cihpher suite flags */ +#define CIPHER_FLAG_NONE 0x00000000 +#define CIPHER_FLAG_WEP40 0x00000001 /* BIT 1 */ +#define CIPHER_FLAG_TKIP 0x00000002 /* BIT 2 */ +#define CIPHER_FLAG_CCMP 0x00000008 /* BIT 4 */ +#define CIPHER_FLAG_WEP104 0x00000010 /* BIT 5 */ +#define CIPHER_FLAG_WEP128 0x00000020 /* BIT 6 */ +#if CFG_SUPPORT_SUITB +#define CIPHER_FLAG_GCMP256 0x00000080 /* BIT 7 */ +#endif + +#define WAIT_TIME_IND_PMKID_CANDICATE_SEC 6 /* seconds */ +#define TKIP_COUNTERMEASURE_SEC 60 /* seconds */ + +#if CFG_SUPPORT_802_11W +#define RSN_AUTH_MFP_DISABLED 0 /* MFP disabled */ +#define RSN_AUTH_MFP_OPTIONAL 1 /* MFP optional */ +#define RSN_AUTH_MFP_REQUIRED 2 /* MFP required */ +#endif + +#define GTK_REKEY_CMD_MODE_OFFLOAD_ON 0 +#define GTK_REKEY_CMD_MODE_OFLOAD_OFF 1 +#define GTK_REKEY_CMD_MODE_SET_BCMC_PN 2 +#define GTK_REKEY_CMD_MODE_GET_BCMC_PN 3 +#define GTK_REKEY_CMD_MODE_RPY_OFFLOAD_ON 4 +#define GTK_REKEY_CMD_MODE_RPY_OFFLOAD_OFF 5 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* Flags for PMKID Candidate list structure */ +#define EVENT_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 + +#define CONTROL_FLAG_UC_MGMT_NO_ENC BIT(5) + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +#define SA_QUERY_RETRY_TIMEOUT 3000 +#define SA_QUERY_TIMEOUT 501 + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define RSN_IE(fp) ((P_RSN_INFO_ELEM_T)fp) +#define WPA_IE(fp) ((P_WPA_INFO_ELEM_T)fp) + +#define ELEM_MAX_LEN_ASSOC_RSP_WSC_IE (32 - ELEM_HDR_LEN) +#define ELEM_MAX_LEN_TIMEOUT_IE (5) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +u8 rsnParseRsnIE(IN P_ADAPTER_T prAdapter, + IN P_RSN_INFO_ELEM_T prInfoElem, + OUT P_RSN_INFO_T prRsnInfo); + +u8 rsnParseWpaIE(IN P_ADAPTER_T prAdapter, + IN P_WPA_INFO_ELEM_T prInfoElem, + OUT P_RSN_INFO_T prWpaInfo); + +u8 rsnSearchSupportedCipher(IN P_ADAPTER_T prAdapter, + IN u32 u4Cipher, + OUT u32 *pu4Index); + +u8 rsnIsSuitableBSS(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_T prBssRsnInfo); + +u8 rsnSearchAKMSuite(IN P_ADAPTER_T prAdapter, + IN u32 u4AkmSuite, + OUT u32 *pu4Index); + +u8 rsnPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss); + +void rsnGenerateWpaNoneIE(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +void rsnGenerateWPAIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +void rsnGenerateRSNIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +u8 rsnParseCheckForWFAInfoElem(IN P_ADAPTER_T prAdapter, + IN u8 *pucBuf, + OUT u8 *pucOuiType, + OUT u16 *pu2SubTypeVersion); + +#if CFG_SUPPORT_AAA +void rsnParserCheckForRSNCCMPPSK(P_ADAPTER_T prAdapter, + P_RSN_INFO_ELEM_T prIe, + P_STA_RECORD_T prStaRec, + u16 *pu2StatusCode); +#endif + +void rsnTkipHandleMICFailure(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prSta, + IN u8 fgErrorKeyType); + +void rsnSelectPmkidCandidateList(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc); + +void rsnUpdatePmkidCandidateList(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc); + +u8 rsnSearchPmkidEntry(IN P_ADAPTER_T prAdapter, + IN u8 *pucBssid, + OUT u32 *pu4EntryIndex); + +u8 rsnCheckPmkidCandicate(IN P_ADAPTER_T prAdapter); + +void rsnCheckPmkidCache(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss); + +void rsnGeneratePmkidIndication(IN P_ADAPTER_T prAdapter); + +void rsnIndicatePmkidCand(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr); +#if CFG_SUPPORT_WPS2 +void rsnGenerateWSCIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); +#endif + +#if CFG_SUPPORT_802_11W +u32 rsnCheckBipKeyInstalled(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec); + +u8 rsnCheckSaQueryTimeout(IN P_ADAPTER_T prAdapter); + +void rsnStartSaQueryTimer(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr); + +void rsnStartSaQuery(IN P_ADAPTER_T prAdapter); + +void rsnStopSaQuery(IN P_ADAPTER_T prAdapter); + +void rsnSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +void rsnSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +u16 rsnPmfCapableValidation(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_STA_RECORD_T prStaRec); + +void rsnPmfGenerateTimeoutIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +void rsnApStartSaQuery(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +void rsnApSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +#endif + +#if CFG_SUPPORT_AAA +void rsnGenerateWSCIEForAssocRsp(P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo); +#endif + +#if CFG_SUPPORT_OWE +void rsnGenerateOWEIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); +u32 rsnCalOweIELen(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + P_STA_RECORD_T prStaRec); +#endif + +#if CFG_SUPPORT_H2E +void rsnGenerateRSNXE(IN P_ADAPTER_T prAdapter, + IN OUT P_MSDU_INFO_T prMsduInfo); +u32 rsnCalRSNXELen(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + P_STA_RECORD_T prStaRec); +#endif + +void rsnApStopSaQuery(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); +void rsnApSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); +void rsnGenMicErrorEvent(IN P_ADAPTER_T prAdapter, IN u8 fgFlags); +u8 rsnApCheckSaQueryTimeout(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec); +void rsnApStartSaQueryTimer(IN P_ADAPTER_T prAdapter, + /* IN P_STA_RECORD_T prStaRec,*/ + IN unsigned long ulParamPtr); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/scan.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/scan.h new file mode 100644 index 00000000000000..3a1975a50f51f6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/scan.h @@ -0,0 +1,752 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "scan.h" + * \brief + * + */ + +#ifndef _SCAN_H +#define _SCAN_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/*! Maximum buffer size of SCAN list */ +#define SCN_MAX_BUFFER_SIZE (CFG_MAX_NUM_BSS_LIST * \ + ALIGN_4(sizeof(BSS_DESC_T))) + +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP +#define SCN_ROAM_MAX_BUFFER_SIZE \ + (CFG_MAX_NUM_ROAM_BSS_LIST * ALIGN_4(sizeof(ROAM_BSS_DESC_T))) +#endif + +#define SCN_RM_POLICY_EXCLUDE_SPECIFIC_SSID \ + BIT(4) /* Remove SCAN result except the connected one. */ + +#define SCN_RM_POLICY_EXCLUDE_CONNECTED \ + BIT(0) /* Remove SCAN result except the connected one. */ +#define SCN_RM_POLICY_TIMEOUT BIT(1) /* Remove the timeout one */ +#define SCN_RM_POLICY_OLDEST_HIDDEN \ + BIT(2) /* Remove the oldest one with hidden ssid */ +#define SCN_RM_POLICY_SMART_WEAKEST \ + BIT(3) /* If there are more than half BSS which has the \ + * same ssid as connection setting, remove the \ + * weakest one from them \ + * Else remove the weakest one. \ + */ +#define SCN_RM_POLICY_ENTIRE BIT(5) /* Remove entire SCAN result */ + +#define SCN_BSS_DESC_SAME_SSID_THRESHOLD \ + 3 /* This is used by POLICY SMART WEAKEST, \ + * If exceed this value, remove weakest BSS_DESC_T \ + * with same SSID first in large network. \ + */ +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP +#define REMOVE_TIMEOUT_TWO_DAY (60 * 60 * 24 * 2) +#endif + +#define SCN_BSS_DESC_REMOVE_TIMEOUT_SEC 30 +#define SCN_BSS_DESC_STALE_SEC 20 /* Scan Request Timeout */ + +#define SCN_PROBE_DELAY_MSEC 0 + +#define SCN_ADHOC_BSS_DESC_TIMEOUT_SEC 5 /* Second. */ + +#define SCN_NLO_NETWORK_CHANNEL_NUM (4) + +#define SCAN_DONE_DIFFERENCE 3 + +/*----------------------------------------------------------------------------*/ +/* MSG_SCN_SCAN_REQ */ +/*----------------------------------------------------------------------------*/ +#define SCAN_REQ_SSID_WILDCARD BIT(0) +#define SCAN_REQ_SSID_P2P_WILDCARD BIT(1) +#define SCAN_REQ_SSID_SPECIFIED BIT(2) + +/*----------------------------------------------------------------------------*/ +/* Support Multiple SSID SCAN */ +/*----------------------------------------------------------------------------*/ +#define SCN_SSID_MAX_NUM CFG_SCAN_SSID_MAX_NUM +#define SCN_SSID_MATCH_MAX_NUM CFG_SCAN_SSID_MATCH_MAX_NUM + +#define SCN_AGPS_AP_LIST_MAX_NUM 32 + +#define SCN_BSS_JOIN_FAIL_THRESOLD 5 +#define SCN_BSS_JOIN_FAIL_CNT_RESET_SEC 15 +#define SCN_BSS_JOIN_FAIL_RESET_STEP 2 + +#if CFG_SUPPORT_BATCH_SCAN +/*----------------------------------------------------------------------------*/ +/* SCAN_BATCH_REQ */ +/*----------------------------------------------------------------------------*/ +#define SCAN_BATCH_REQ_START BIT(0) +#define SCAN_BATCH_REQ_STOP BIT(1) +#define SCAN_BATCH_REQ_RESULT BIT(2) +#endif + +#define SCAN_NLO_CHECK_SSID_ONLY 0x00000001 +#define SCAN_NLO_DEFAULT_INTERVAL 30000 + +#define SCN_CTRL_SCAN_CHANNEL_LISTEN_TIME_ENABLE BIT(1) +#define SCN_CTRL_IGNORE_AIS_FIX_CHANNEL BIT(1) +#define SCN_CTRL_ENABLE BIT(0) + +#define SCN_CTRL_DEFAULT_SCAN_CTRL \ + SCN_CTRL_IGNORE_AIS_FIX_CHANNEL + +#define SCN_SCAN_DONE_PRINT_BUFFER_LENGTH 200 +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef enum _ENUM_SCAN_TYPE_T { + SCAN_TYPE_PASSIVE_SCAN = 0, + SCAN_TYPE_ACTIVE_SCAN, + SCAN_TYPE_NUM +} ENUM_SCAN_TYPE_T, +*P_ENUM_SCAN_TYPE_T; + +typedef enum _ENUM_SCAN_STATE_T { + SCAN_STATE_IDLE = 0, + SCAN_STATE_SCANNING, + SCAN_STATE_NUM +} ENUM_SCAN_STATE_T; + +typedef enum _ENUM_FW_SCAN_STATE_T { + FW_SCAN_STATE_IDLE = 0, /* 0 */ + FW_SCAN_STATE_SCAN_START, /* 1 */ + FW_SCAN_STATE_REQ_CHANNEL, /* 2 */ + FW_SCAN_STATE_SET_CHANNEL, /* 3 */ + FW_SCAN_STATE_DELAYED_ACTIVE_PROB_REQ, /* 4 */ + FW_SCAN_STATE_ACTIVE_PROB_REQ, /* 5 */ + FW_SCAN_STATE_LISTEN, /* 6 */ + FW_SCAN_STATE_SCAN_DONE, /* 7 */ + FW_SCAN_STATE_NLO_START, /* 8 */ + FW_SCAN_STATE_NLO_HIT_CHECK, /* 9 */ + FW_SCAN_STATE_NLO_STOP, /* 10 */ + FW_SCAN_STATE_BATCH_START, /* 11 */ + FW_SCAN_STATE_BATCH_CHECK, /* 12 */ + FW_SCAN_STATE_BATCH_STOP, /* 13 */ + FW_SCAN_STATE_NUM /* 14 */ +} ENUM_FW_SCAN_STATE_T; + +typedef enum _ENUM_SCAN_CHANNEL_T { + SCAN_CHANNEL_FULL = 0, + SCAN_CHANNEL_2G4, + SCAN_CHANNEL_5G, + SCAN_CHANNEL_P2P_SOCIAL, + SCAN_CHANNEL_SPECIFIED, + SCAN_CHANNEL_NUM +} ENUM_SCAN_CHANNEL, +*P_ENUM_SCAN_CHANNEL; + +typedef struct _MSG_SCN_FSM_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u32 u4Dummy; +} MSG_SCN_FSM_T, *P_MSG_SCN_FSM_T; + +/*----------------------------------------------------------------------------*/ +/* BSS Descriptors */ +/*----------------------------------------------------------------------------*/ +struct _BSS_DESC_T { + LINK_ENTRY_T rLinkEntry; + + u8 aucBSSID[MAC_ADDR_LEN]; + u8 aucSrcAddr[MAC_ADDR_LEN]; /* For IBSS, the SrcAddr is different from + * BSSID */ + + u8 fgIsConnecting; /* If we are going to connect to this BSS + * (JOIN or ROAMING to another BSS), don't + * remove this record from BSS List. + */ + u8 fgIsConnected; /* If we have connected to this BSS (NORMAL_TR), + * don't removed this record from BSS list. + */ + + u8 fgIsHiddenSSID; /* When this flag is true, means the SSID + * of this BSS is not known yet. + */ + u8 ucSSIDLen; + u8 aucSSID[ELEM_MAX_LEN_SSID]; + + u32 rUpdateTime; + + ENUM_BSS_TYPE_T eBSSType; + + u16 u2CapInfo; + + u16 u2BeaconInterval; + u16 u2ATIMWindow; + + u16 u2OperationalRateSet; + u16 u2BSSBasicRateSet; + u8 fgIsUnknownBssBasicRate; + + u8 fgIsERPPresent; + u8 fgIsHTPresent; + u8 fgIsVHTPresent; + + u8 ucPhyTypeSet; /* Available PHY Type Set of this BSS */ + u8 ucVhtCapNumSoundingDimensions; /* record from bcn or probe response*/ + + u8 ucChannelNum; + + ENUM_CHNL_EXT_T eSco; /* Record bandwidth for association process */ + /*Some AP will send association resp by 40MHz BW */ + ENUM_CHANNEL_WIDTH_T eChannelWidth; /*VHT operation ie */ + u8 ucCenterFreqS1; + u8 ucCenterFreqS2; + ENUM_BAND_T eBand; + + u8 ucDTIMPeriod; + + u8 fgIsLargerTSF; /* This BSS's TimeStamp is larger than us(TCL == 1 in + * RX_STATUS_T) */ + + u8 ucRCPI; + + u8 ucWmmFlag; /* A flag to indicate this BSS's WMM capability */ + + /*! \brief The srbiter Search State will matched the scan result, + * and saved the selected cipher and akm, and report the score, + * for arbiter join state, join module will carry this target BSS + * to rsn generate ie function, for gen wpa/rsn ie + */ + u32 u4RsnSelectedGroupCipher; + u32 u4RsnSelectedPairwiseCipher; + u32 u4RsnSelectedAKMSuite; + + u16 u2RsnCap; + + RSN_INFO_T rRSNInfo; + RSN_INFO_T rWPAInfo; + + WAPI_INFO_T rIEWAPI; + u8 fgIEWAPI; + + u8 fgIERSN; + u8 fgIEWPA; + + /*! \brief RSN parameters selected for connection */ + /*! \brief The Select score for final AP selection, + * 0, no sec, 1,2,3 group cipher is WEP, TKIP, CCMP + */ + u8 ucEncLevel; + +#if CFG_ENABLE_WIFI_DIRECT + u8 fgIsP2PPresent; + u8 fgIsP2PReport; /* true: report to upper layer */ + P_P2P_DEVICE_DESC_T prP2pDesc; + + u8 aucIntendIfAddr[MAC_ADDR_LEN]; /* For IBSS, the SrcAddr is different + * from BSSID */ + /* u8 ucDevCapabilityBitmap; */ /* Device Capability Attribute. + * (P2P_DEV_CAPABILITY_XXXX) + */ + /* u8 ucGroupCapabilityBitmap; */ /* Group Capability Attribute. + * (P2P_GROUP_CAPABILITY_XXXX) + */ + + LINK_T rP2pDeviceList; + + /* P_LINK_T prP2pDeviceList; */ + + /* For + * 1. P2P Capability. + * 2. P2P Device ID. ( in aucSrcAddr[] ) + * 3. NOA (TODO:) + * 4. Extend Listen Timing. (Probe Rsp) (TODO:) + * 5. P2P Device Info. (Probe Rsp) + * 6. P2P Group Info. (Probe Rsp) + */ +#endif + + u8 fgIsIEOverflow; /* The received IE length exceed the maximum IE + * buffer size */ + u16 u2RawLength; /* The byte count of aucRawBuf[] */ + u16 u2IELength; /* The byte count of aucIEBuf[] */ + + ULARGE_INTEGER + u8TimeStamp; /* Place u8TimeStamp before aucIEBuf[1] to force DW align + */ + u8 aucRawBuf[CFG_RAW_BUFFER_SIZE]; + u8 aucIEBuf[CFG_IE_BUFFER_SIZE]; + u8 ucJoinFailureCount; + u32 rJoinFailTime; +#if CFG_SUPPORT_802_11K + u8 aucRrmCap[5]; +#endif +}; + +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP +struct _ROAM_BSS_DESC_T { + LINK_ENTRY_T rLinkEntry; + u8 ucSSIDLen; + u8 aucSSID[ELEM_MAX_LEN_SSID]; + u32 rUpdateTime; +}; +#endif + +typedef struct _SCHED_SCAN_PARAM { /* Used by SCAN FSM */ + u8 ucSeqNum; + u8 ucBssIndex; /* Network Type */ + u8 fgStopAfterIndication; /* always false */ + u8 ucMatchSSIDNum; /* Match SSID */ + P_BSS_DESC_T aprPendingBssDescToInd[SCN_SSID_MATCH_MAX_NUM]; +} SCHED_SCAN_PARAM_T, *P_SCHED_SCAN_PARAM_T; + +typedef struct _SCAN_PARAM_T { /* Used by SCAN FSM */ + /* Active or Passive */ + ENUM_SCAN_TYPE_T eScanType; + + /* Network Type */ + u8 ucBssIndex; + + /* Specified SSID Type */ + u8 ucSSIDType; + u8 ucSSIDNum; + + /* Length of Specified SSID */ + u8 ucSpecifiedSSIDLen[SCN_SSID_MAX_NUM]; + + /* Specified SSID */ + u8 aucSpecifiedSSID[SCN_SSID_MAX_NUM][ELEM_MAX_LEN_SSID]; + +#if CFG_ENABLE_WIFI_DIRECT + u8 fgFindSpecificDev; /* P2P: Discovery Protocol */ + u8 aucDiscoverDevAddr[MAC_ADDR_LEN]; + u8 fgIsDevType; + P2P_DEVICE_TYPE_T rDiscoverDevType; + + /* TODO: Find Specific Device Type. */ +#endif + + u16 u2ChannelDwellTime; + u16 u2TimeoutValue; + + u8 fgIsObssScan; + u8 fgIsScanV2; + + /* Run time flags */ + u16 u2ProbeDelayTime; + + /* channel information */ + ENUM_SCAN_CHANNEL eScanChannel; + u8 ucChannelListNum; + RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; + + /* Feedback information */ + u8 ucSeqNum; + + /* Information Element */ + u16 u2IELen; + u8 aucIE[MAX_IE_LENGTH]; +} SCAN_PARAM_T, *P_SCAN_PARAM_T; + +typedef struct _NLO_PARAM_T { /* Used by SCAN FSM */ + SCAN_PARAM_T rScanParam; + + /* NLO */ + u8 fgStopAfterIndication; + u8 ucFastScanIteration; + u16 u2FastScanPeriod; + u16 u2SlowScanPeriod; + + /* Match SSID */ + u8 ucMatchSSIDNum; + u8 ucMatchSSIDLen[SCN_SSID_MATCH_MAX_NUM]; + u8 aucMatchSSID[SCN_SSID_MATCH_MAX_NUM][ELEM_MAX_LEN_SSID]; + + u8 aucCipherAlgo[SCN_SSID_MATCH_MAX_NUM]; + u16 au2AuthAlgo[SCN_SSID_MATCH_MAX_NUM]; + u8 aucChannelHint[SCN_SSID_MATCH_MAX_NUM][SCN_NLO_NETWORK_CHANNEL_NUM]; +} NLO_PARAM_T, *P_NLO_PARAM_T; + +typedef struct _SCAN_INFO_T { + ENUM_SCAN_STATE_T + eCurrentState; /* Store the STATE variable of SCAN FSM */ + + u32 rLastScanCompletedTime; + + SCAN_PARAM_T rScanParam; + NLO_PARAM_T rNloParam; + + u32 u4NumOfBssDesc; + + u8 aucScanBuffer[SCN_MAX_BUFFER_SIZE]; + + LINK_T rBSSDescList; + + LINK_T rFreeBSSDescList; + + LINK_T rPendingMsgList; +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP + u8 aucScanRoamBuffer[SCN_ROAM_MAX_BUFFER_SIZE]; + LINK_T rRoamFreeBSSDescList; + LINK_T rRoamBSSDescList; +#endif + /* Sparse Channel Detection */ + u8 fgIsSparseChannelValid; + RF_CHANNEL_INFO_T rSparseChannel; + + /* NLO scanning state tracking */ + u8 fgNloScanning; + + /*channel idle count # Mike */ + u8 ucSparseChannelArrayValidNum; + u8 aucReserved[3]; + u8 aucChannelNum[64]; + u16 au2ChannelIdleTime[64]; + u8 aucChannelFlag[64]; + u8 aucChannelMDRDYCnt[64]; + + SCHED_SCAN_PARAM_T rSchedScanParam; +} SCAN_INFO_T, *P_SCAN_INFO_T; + +/* Incoming Mailbox Messages */ +typedef struct _MSG_SCN_SCAN_REQ_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucSeqNum; + u8 ucBssIndex; + ENUM_SCAN_TYPE_T eScanType; + u8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) + * specific */ + u8 ucSSIDLength; + u8 aucSSID[PARAM_MAX_LEN_SSID]; + u16 u2ChannelDwellTime; /* ms unit */ + u16 u2TimeoutValue; /* ms unit */ + ENUM_SCAN_CHANNEL eScanChannel; + u8 ucChannelListNum; + RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; + u16 u2IELen; + u8 aucIE[MAX_IE_LENGTH]; +} MSG_SCN_SCAN_REQ, *P_MSG_SCN_SCAN_REQ; + +typedef struct _MSG_SCN_SCAN_REQ_V2_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucSeqNum; + u8 ucBssIndex; + ENUM_SCAN_TYPE_T eScanType; + u8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) + * specific */ + u8 ucSSIDNum; + P_PARAM_SSID_T prSsid; + u16 u2ProbeDelay; + u16 u2ChannelDwellTime; /* In TU. 1024us. */ + u16 u2TimeoutValue; /* ms unit */ + ENUM_SCAN_CHANNEL eScanChannel; + u8 ucChannelListNum; + RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; + u16 u2IELen; + u8 aucIE[MAX_IE_LENGTH]; +} MSG_SCN_SCAN_REQ_V2, *P_MSG_SCN_SCAN_REQ_V2; + +typedef struct _MSG_SCN_SCAN_CANCEL_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucSeqNum; + u8 ucBssIndex; + u8 fgIsChannelExt; + u8 fgIsOidRequest; +} MSG_SCN_SCAN_CANCEL, *P_MSG_SCN_SCAN_CANCEL; + +typedef struct _tagOFFLOAD_NETWORK { + u8 aucSsid[ELEM_MAX_LEN_SSID]; + u8 ucSsidLen; + u8 ucUnicastCipher; /* ENUM_NLO_CIPHER_ALGORITHM */ + u16 u2AuthAlgo; /* ENUM_NLO_AUTH_ALGORITHM */ + u8 aucChannelList[SCN_NLO_NETWORK_CHANNEL_NUM]; +} OFFLOAD_NETWORK, *P_OFFLOAD_NETWORK; + +typedef struct _MSG_SCN_NLO_REQ_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 fgStopAfterIndication; + u8 ucSeqNum; + u8 ucBssIndex; + u32 u4FastScanPeriod; + u32 u4FastScanIterations; + u32 u4SlowScanPeriod; + u32 u4NumOfEntries; + OFFLOAD_NETWORK arNetwork[CFG_SCAN_SSID_MAX_NUM]; +} MSG_SCN_NLO_REQ, *P_MSG_SCN_NLO_REQ; + +typedef struct _MSG_SCN_NLO_CANCEL_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucSeqNum; + u8 ucBssIndex; +} MSG_SCN_NLO_CANCEL, *P_MSG_SCN_NLO_CANCEL; + +/* Outgoing Mailbox Messages */ +typedef enum _ENUM_SCAN_STATUS_T { + SCAN_STATUS_DONE = 0, + SCAN_STATUS_CANCELLED, + SCAN_STATUS_FAIL, + SCAN_STATUS_BUSY, + SCAN_STATUS_NUM +} ENUM_SCAN_STATUS, +*P_ENUM_SCAN_STATUS; + +typedef struct _MSG_SCN_SCAN_DONE_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucSeqNum; + u8 ucBssIndex; + ENUM_SCAN_STATUS eScanStatus; +} MSG_SCN_SCAN_DONE, *P_MSG_SCN_SCAN_DONE; + +typedef enum { + AGPS_PHY_A, + AGPS_PHY_B, + AGPS_PHY_G, +} AP_PHY_TYPE; + +typedef struct _AGPS_AP_INFO_T { + u8 aucBSSID[MAC_ADDR_LEN]; + s16 i2ApRssi; /* -127..128 */ + u16 u2Channel; /* 0..256 */ + AP_PHY_TYPE ePhyType; +} AGPS_AP_INFO_T, *P_AGPS_AP_INFO_T; + +typedef struct _AGPS_AP_LIST_T { + u8 ucNum; + AGPS_AP_INFO_T arApInfo[SCN_AGPS_AP_LIST_MAX_NUM]; +} AGPS_AP_LIST_T, *P_AGPS_AP_LIST_T; + +typedef enum _ENUM_NLO_STATUS_T { + NLO_STATUS_FOUND = 0, + NLO_STATUS_CANCELLED, + NLO_STATUS_FAIL, + NLO_STATUS_BUSY, + NLO_STATUS_NUM +} ENUM_NLO_STATUS, +*P_ENUM_NLO_STATUS; + +typedef struct _MSG_SCN_NLO_DONE_T { + MSG_HDR_T rMsgHdr; /* Must be the first member */ + u8 ucSeqNum; + u8 ucBssIndex; + ENUM_NLO_STATUS eNloStatus; +} MSG_SCN_NLO_DONE, *P_MSG_SCN_NLO_DONE; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Routines in scan.c */ +/*----------------------------------------------------------------------------*/ +void scnInit(IN P_ADAPTER_T prAdapter); + +void scnUninit(IN P_ADAPTER_T prAdapter); + +/* BSS-DESC Search */ +P_BSS_DESC_T scanSearchBssDescByBssid(IN P_ADAPTER_T prAdapter, + IN u8 aucBSSID[]); + +P_BSS_DESC_T +scanSearchBssDescByBssidAndSsid(IN P_ADAPTER_T prAdapter, + IN u8 aucBSSID[], + IN u8 fgCheckSsid, + IN P_PARAM_SSID_T prSsid); + +P_BSS_DESC_T +scanSearchBssDescByBssidAndChanNum(IN P_ADAPTER_T prAdapter, + IN u8 aucBSSID[], + IN u8 fgCheckChanNum, + IN u8 ucChannelNum); + +P_BSS_DESC_T scanSearchBssDescByTA(IN P_ADAPTER_T prAdapter, + IN u8 aucSrcAddr[]); + +P_BSS_DESC_T +scanSearchBssDescByTAAndSsid(IN P_ADAPTER_T prAdapter, + IN u8 aucSrcAddr[], + IN u8 fgCheckSsid, + IN P_PARAM_SSID_T prSsid); + +/* BSS-DESC Search - Alternative */ +P_BSS_DESC_T +scanSearchExistingBssDesc(IN P_ADAPTER_T prAdapter, + IN ENUM_BSS_TYPE_T eBSSType, + IN u8 aucBSSID[], + IN u8 aucSrcAddr[]); + +P_BSS_DESC_T +scanSearchExistingBssDescWithSsid(IN P_ADAPTER_T prAdapter, + IN ENUM_BSS_TYPE_T eBSSType, + IN u8 aucBSSID[], + IN u8 aucSrcAddr[], + IN u8 fgCheckSsid, + IN P_PARAM_SSID_T prSsid); + +/* BSS-DESC Allocation */ +P_BSS_DESC_T scanAllocateBssDesc(IN P_ADAPTER_T prAdapter); + +/* BSS-DESC Removal */ +void scanRemoveBssDescsByPolicy(IN P_ADAPTER_T prAdapter, + IN u32 u4RemovePolicy); + +void scanRemoveBssDescByBssid(IN P_ADAPTER_T prAdapter, IN u8 aucBSSID[]); + +void scanRemoveBssDescByBandAndNetwork(IN P_ADAPTER_T prAdapter, + IN ENUM_BAND_T eBand, + IN u8 ucBssIndex); + +/* BSS-DESC State Change */ +void scanRemoveConnFlagOfBssDescByBssid(IN P_ADAPTER_T prAdapter, + IN u8 aucBSSID[]); + +/* BSS-DESC Insertion - ALTERNATIVE */ +P_BSS_DESC_T scanAddToBssDesc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS scanProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSWRfb); + +void scanBuildProbeReqFrameCommonIEs(IN P_MSDU_INFO_T prMsduInfo, + IN u8 *pucDesiredSsid, + IN u32 u4DesiredSsidLen, + IN u16 u2SupportedRateSet); + +WLAN_STATUS scanSendProbeReqFrames(IN P_ADAPTER_T prAdapter, + IN P_SCAN_PARAM_T prScanParam); + +void scanUpdateBssDescForSearch(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc); + +P_BSS_DESC_T scanSearchBssDescByPolicy(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex); + +WLAN_STATUS scanAddScanResult(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + IN P_SW_RFB_T prSwRfb); + +void scanReportBss2Cfg80211(IN P_ADAPTER_T prAdapter, + IN ENUM_BSS_TYPE_T eBSSType, + IN P_BSS_DESC_T SpecificprBssDesc); + +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP +P_ROAM_BSS_DESC_T scanSearchRoamBssDescBySsid(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc); +P_ROAM_BSS_DESC_T scanAllocateRoamBssDesc(IN P_ADAPTER_T prAdapter); +void scanAddToRoamBssDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); +void scanSearchBssDescOfRoamSsid(IN P_ADAPTER_T prAdapter); +void scanRemoveRoamBssDescsByTime(IN P_ADAPTER_T prAdapter, + IN u32 u4RemoveTime); +#endif +/*----------------------------------------------------------------------------*/ +/* Routines in scan_fsm.c */ +/*----------------------------------------------------------------------------*/ +void scnFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_SCAN_STATE_T eNextState); + +/*----------------------------------------------------------------------------*/ +/* Command Routines */ +/*----------------------------------------------------------------------------*/ +void scnSendScanReq(IN P_ADAPTER_T prAdapter); + +void scnSendScanReqV2(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* RX Event Handling */ +/*----------------------------------------------------------------------------*/ +void scnEventScanDone(IN P_ADAPTER_T prAdapter, + IN P_EVENT_SCAN_DONE prScanDone, + u8 fgIsNewVersion); + +void scnEventNloDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_NLO_DONE_T prNloDone); + +/*----------------------------------------------------------------------------*/ +/* Mailbox Message Handling */ +/*----------------------------------------------------------------------------*/ +void scnFsmMsgStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +void scnFsmMsgAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +void scnFsmHandleScanMsg(IN P_ADAPTER_T prAdapter, + IN P_MSG_SCN_SCAN_REQ prScanReqMsg); + +void scnFsmHandleScanMsgV2(IN P_ADAPTER_T prAdapter, + IN P_MSG_SCN_SCAN_REQ_V2 prScanReqMsg); + +void scnFsmRemovePendingMsg(IN P_ADAPTER_T prAdapter, + IN u8 ucSeqNum, + IN u8 ucBssIndex); + +void scnFsmNloMsgStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +void scnFsmNloMsgAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr); + +void scnFsmHandleNloMsg(IN P_ADAPTER_T prAdapter, + IN P_MSG_SCN_NLO_REQ prNloReqMsg); + +/*----------------------------------------------------------------------------*/ +/* Mailbox Message Generation */ +/*----------------------------------------------------------------------------*/ +void scnFsmGenerateScanDoneMsg(IN P_ADAPTER_T prAdapter, + IN u8 ucSeqNum, + IN u8 ucBssIndex, + IN ENUM_SCAN_STATUS eScanStatus); + +/*----------------------------------------------------------------------------*/ +/* Query for sparse channel */ +/*----------------------------------------------------------------------------*/ +u8 scnQuerySparseChannel(IN P_ADAPTER_T prAdapter, + P_ENUM_BAND_T prSparseBand, + u8 *pucSparseChannel); + +/*----------------------------------------------------------------------------*/ +/* OID/IOCTL Handling */ +/*----------------------------------------------------------------------------*/ +u8 scnFsmSchedScanRequest(IN P_ADAPTER_T prAdapter, + IN u8 ucSsidNum, + IN P_PARAM_SSID_T prSsid, + IN u32 u4IeLength, + IN u8 *pucIe, + IN u16 u2Interval); + +u8 scnFsmSchedScanStopRequest(IN P_ADAPTER_T prAdapter); + +void scanReportScanResultToAgps(P_ADAPTER_T prAdapter); + +#if CFG_SCAN_CHANNEL_SPECIFIED +static inline bool is_valid_scan_chnl_cnt(u8 num) +{ + return num && num < MAXIMUM_OPERATION_CHANNEL_LIST; +} +#endif + +u8 scnFsmIsScanning(IN P_ADAPTER_T prAdapter); +void scnFreeAllPendingScanRquests(IN P_ADAPTER_T prAdapter); +u8 scanByPassRemoveBssDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc); +u8 scanCheckBssIsLegal(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/swcr.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/swcr.h new file mode 100644 index 00000000000000..51c61b57c0c1fc --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/swcr.h @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "swcr.h" + * \brief + */ + +/* + * + */ + +#ifndef _SWCR_H +#define _SWCR_H + +#include "nic_cmd_event.h" + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define TEST_PS 1 + +#define SWCR_VAR(x) ((void *)&x) +#define SWCR_FUNC(x) ((void *)x) + +#define SWCR_T_FUNC BIT(7) + +#define SWCR_L_32 3 +#define SWCR_L_16 2 +#define SWCR_L_8 1 + +#define SWCR_READ 0 +#define SWCR_WRITE 1 + +#define SWCR_MAP_NUM(x) (ARRAY_SIZE(x)) + +#define SWCR_CR_NUM 7 + +#define SWCR_GET_RW_INDEX(action, rw, index) \ + do { \ + index = action & 0x7F; \ + rw = action >> 7; \ + } while (0) + +extern u32 g_au4SwCr[]; /*: 0: command other: data */ + +typedef void (*PFN_SWCR_RW_T)(P_ADAPTER_T prAdapter, + u8 ucRead, + u16 u2Addr, + u32 *pu4Data); +typedef void (*PFN_CMD_RW_T)(P_ADAPTER_T prAdapter, + u8 ucCate, + u8 ucAction, + u8 ucOpt0, + u8 ucOpt1); + +typedef struct _SWCR_MAP_ENTRY_T { + u16 u2Type; + void *u4Addr; +} SWCR_MAP_ENTRY_T, *P_SWCR_MAP_ENTRY_T; + +typedef struct _SWCR_MOD_MAP_ENTRY_T { + u8 ucMapNum; + P_SWCR_MAP_ENTRY_T prSwCrMap; +} SWCR_MOD_MAP_ENTRY_T, *P_SWCR_MOD_MAP_ENTRY_T; + +typedef enum _ENUM_SWCR_DBG_TYPE_T { + SWCR_DBG_TYPE_ALL = 0, + SWCR_DBG_TYPE_TXRX, + SWCR_DBG_TYPE_RX_RATES, + SWCR_DBG_TYPE_PS, + SWCR_DBG_TYPE_NUM +} ENUM_SWCR_DBG_TYPE_T; + +typedef enum _ENUM_SWCR_DBG_ALL_T { + SWCR_DBG_ALL_TX_CNT = 0, + SWCR_DBG_ALL_TX_BCN_CNT, + SWCR_DBG_ALL_TX_FAILED_CNT, + SWCR_DBG_ALL_TX_RETRY_CNT, + SWCR_DBG_ALL_TX_AGING_TIMEOUT_CNT, + SWCR_DBG_ALL_TX_PS_OVERFLOW_CNT, + SWCR_DBG_ALL_TX_MGNT_DROP_CNT, + SWCR_DBG_ALL_TX_ERROR_CNT, + + SWCR_DBG_ALL_RX_CNT, + SWCR_DBG_ALL_RX_DROP_CNT, + SWCR_DBG_ALL_RX_DUP_DROP_CNT, + SWCR_DBG_ALL_RX_TYPE_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_CLASS_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_AMPDU_ERROR_DROP_CNT, + + SWCR_DBG_ALL_RX_STATUS_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_FORMAT_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_ICV_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_KEY_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_TKIP_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_MIC_ERROR_DROP_CNT, + SWCR_DBG_ALL_RX_BIP_ERROR_DROP_CNT, + + SWCR_DBG_ALL_RX_FCSERR_CNT, + SWCR_DBG_ALL_RX_FIFOFULL_CNT, + SWCR_DBG_ALL_RX_PFDROP_CNT, + + SWCR_DBG_ALL_PWR_PS_POLL_CNT, + SWCR_DBG_ALL_PWR_TRIGGER_NULL_CNT, + SWCR_DBG_ALL_PWR_BCN_IND_CNT, + SWCR_DBG_ALL_PWR_BCN_TIMEOUT_CNT, + SWCR_DBG_ALL_PWR_PM_STATE0, + SWCR_DBG_ALL_PWR_PM_STATE1, + SWCR_DBG_ALL_PWR_CUR_PS_PROF0, + SWCR_DBG_ALL_PWR_CUR_PS_PROF1, + + SWCR_DBG_ALL_AR_STA0_RATE, + SWCR_DBG_ALL_AR_STA0_BWGI, + SWCR_DBG_ALL_AR_STA0_RX_RATE_RCPI, + + SWCR_DBG_ALL_ROAMING_ENABLE, + SWCR_DBG_ALL_ROAMING_ROAM_CNT, + SWCR_DBG_ALL_ROAMING_INT_CNT, + + SWCR_DBG_ALL_BB_RX_MDRDY_CNT, + SWCR_DBG_ALL_BB_RX_FCSERR_CNT, + SWCR_DBG_ALL_BB_CCK_PD_CNT, + SWCR_DBG_ALL_BB_OFDM_PD_CNT, + SWCR_DBG_ALL_BB_CCK_SFDERR_CNT, + SWCR_DBG_ALL_BB_CCK_SIGERR_CNT, + SWCR_DBG_ALL_BB_OFDM_TAGERR_CNT, + SWCR_DBG_ALL_BB_OFDM_SIGERR_CNT, + + SWCR_DBG_ALL_NUM +} ENUM_SWCR_DBG_ALL_T; + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +void swCrReadWriteCmd(P_ADAPTER_T prAdapter, u8 ucRead, u16 u2Addr, + u32 *pu4Data); + +/* Debug Support */ +void swCrFrameCheckEnable(P_ADAPTER_T prAdapter, u32 u4DumpType); +void swCrDebugInit(P_ADAPTER_T prAdapter); +void swCrDebugCheckEnable(P_ADAPTER_T prAdapter, + u8 fgIsEnable, + u8 ucType, + u32 u4Timeout); +void swCrDebugUninit(P_ADAPTER_T prAdapter); + +#if CFG_SUPPORT_SWCR +void swCtrlCmdCategory0(P_ADAPTER_T prAdapter, + u8 ucCate, + u8 ucAction, + u8 ucOpt0, + u8 ucOpt1); +void swCtrlCmdCategory1(P_ADAPTER_T prAdapter, + u8 ucCate, + u8 ucAction, + u8 ucOpt0, + u8 ucOpt1); +#if TEST_PS +void testPsCmdCategory0(P_ADAPTER_T prAdapter, + u8 ucCate, + u8 ucAction, + u8 ucOpt0, + u8 ucOpt1); +void testPsCmdCategory1(P_ADAPTER_T prAdapter, + u8 ucCate, + u8 ucAction, + u8 ucOpt0, + u8 ucOpt1); +#endif +#if CFG_SUPPORT_802_11V +#if (CFG_SUPPORT_802_11V_TIMING_MEASUREMENT == 1) && (WNM_UNIT_TEST == 1) +void testWNMCmdCategory0(P_ADAPTER_T prAdapter, + u8 ucCate, + u8 ucAction, + u8 ucOpt0, + u8 ucOpt1); +#endif +#endif +void swCtrlSwCr(P_ADAPTER_T prAdapter, u8 ucRead, u16 u2Addr, u32 *pu4Data); + +/* Support Debug */ +void swCrDebugCheck(P_ADAPTER_T prAdapter, P_CMD_SW_DBG_CTRL_T prCmdSwCtrl); +void swCrDebugCheckTimeout(IN P_ADAPTER_T prAdapter, unsigned long ulParamPtr); +void swCrDebugQuery(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +void swCrDebugQueryTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); +#endif + +void dumpQueue(P_ADAPTER_T prAdapter); +void dumpSTA(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec); +void dumpBss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); +void testPsSendQoSNullFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, IN u8 ucUP, + IN u8 ucBssIndex, IN u8 fgBMC, IN u8 fgIsBurstEnd, + IN u8 ucPacketType, IN u8 ucPsSessionID, + IN u8 fgSetEOSP); +void testPsSetupBss(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/tdls.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/tdls.h new file mode 100644 index 00000000000000..904e16ad24a9f0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/tdls.h @@ -0,0 +1,444 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "tdls.h" + * \brief This file contains the internal used in TDLS modules + * for MediaTek Inc. 802.11 Wireless LAN Adapters. + */ + +#ifndef _TDLS_H +#define _TDLS_H + +#include "wlan_typedef.h" + +#if CFG_SUPPORT_TDLS + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +#define TDLS_CFG_CMD_TEST + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/* assign station record idx for the packet */ +#define TDLSEX_STA_REC_IDX_GET(__prAdapter__, __MsduInfo__) \ + { \ + STA_RECORD_T *__StaRec__; \ + __MsduInfo__->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; \ + __StaRec__ = cnmGetStaRecByAddress( \ + __prAdapter__, (u8)NETWORK_TYPE_AIS_INDEX, \ + __MsduInfo__->aucEthDestAddr); \ + if ((__StaRec__ != NULL) && (IS_DLS_STA(__StaRec__))) { \ + __MsduInfo__->ucStaRecIndex = __StaRec__->ucIndex; \ + } \ + } + +/* fill wiphy flag */ +#define TDLSEX_WIPHY_FLAGS_INIT(__fgFlag__) \ + { \ + __fgFlag__ |= (WIPHY_FLAG_SUPPORTS_TDLS | \ + WIPHY_FLAG_TDLS_EXTERNAL_SETUP); \ + } + +#define LR_TDLS_FME_FIELD_FILL(__Len) \ + { \ + pPkt += __Len; \ + u4PktLen += __Len; \ + } + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +extern int wlanHardStartXmit(struct sk_buff *prSkb, struct net_device *prDev); + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* Status code */ +#define TDLS_STATUS WLAN_STATUS + +#define TDLS_STATUS_SUCCESS WLAN_STATUS_SUCCESS +#define TDLS_STATUS_FAIL WLAN_STATUS_FAILURE +#define TDLS_STATUS_INVALID_LENGTH WLAN_STATUS_INVALID_LENGTH +#define TDLS_STATUS_RESOURCES WLAN_STATUS_RESOURCES +#define TDLS_FME_MAC_ADDR_LEN 6 +#define TDLS_EX_CAP_PEER_UAPSD BIT(0) +#define TDLS_EX_CAP_CHAN_SWITCH BIT(1) +#define TDLS_EX_CAP_TDLS BIT(2) +#define TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN 5 +#define TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX 50 +#define TDLS_CMD_PEER_UPDATE_SUP_CHAN_MAX 50 +#define TDLS_SEC_BUF_LENGTH 600 + +#define MAXNUM_TDLS_PEER 4 + +/* command */ +typedef enum _TDLS_CMD_ID { + TDLS_CMD_TEST_TX_FRAME = 0x00, + TDLS_CMD_TEST_RCV_FRAME, + TDLS_CMD_TEST_PEER_ADD, + TDLS_CMD_TEST_PEER_UPDATE, + TDLS_CMD_TEST_DATA_FRAME, + TDLS_CMD_TEST_RCV_NULL +} TDLS_CMD_ID; + +/* protocol */ +#define TDLS_FRM_PROT_TYPE 0x890d + +/* payload specific type in the LLC/SNAP header */ +#define TDLS_FRM_PAYLOAD_TYPE 2 + +#define TDLS_FRM_CATEGORY 12 + +typedef enum _TDLS_FRM_ACTION_ID { + TDLS_FRM_ACTION_SETUP_REQ = 0x00, + TDLS_FRM_ACTION_SETUP_RSP, + TDLS_FRM_ACTION_CONFIRM, + TDLS_FRM_ACTION_TEARDOWN, + TDLS_FRM_ACTION_PTI, + TDLS_FRM_ACTION_CHAN_SWITCH_REQ, + TDLS_FRM_ACTION_CHAN_SWITCH_RSP, + TDLS_FRM_ACTION_PEER_PSM_REQ, + TDLS_FRM_ACTION_PEER_PSM_RSP, + TDLS_FRM_ACTION_PTI_RSP, + TDLS_FRM_ACTION_DISCOVERY_REQ, + TDLS_FRM_ACTION_DISCOVERY_RSP = 0x0e, + TDLS_FRM_ACTION_EVENT_TEAR_DOWN_TO_SUPPLICANT = 0x30 +} TDLS_FRM_ACTION_ID; + +/* 7.3.2.62 Link Identifier element */ +#define ELEM_ID_LINK_IDENTIFIER 101 + +typedef struct _IE_LINK_IDENTIFIER_T { + u8 ucId; + u8 ucLength; + u8 aBSSID[6]; + u8 aInitiator[6]; + u8 aResponder[6]; +} __KAL_ATTRIB_PACKED__ IE_LINK_IDENTIFIER_T; + +#define TDLS_LINK_IDENTIFIER_IE(__ie__) ((IE_LINK_IDENTIFIER_T *)(__ie__)) + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef struct _STATION_PRARAMETERS { + const u8 *supported_rates; + struct net_device *vlan; + u32 sta_flags_mask, sta_flags_set; + u32 sta_modify_mask; + int listen_interval; + u16 aid; + u8 supported_rates_len; + u8 plink_action; + u8 plink_state; + const struct ieee80211_ht_cap *ht_capa; + const struct ieee80211_vht_cap *vht_capa; + u8 uapsd_queues; + u8 max_sp; + /* enum nl80211_mesh_power_mode local_pm; */ + u16 capability; + const u8 *ext_capab; + u8 ext_capab_len; +} STATION_PRARAMETERS, P_STATION_PRARAMETERS; + +/* test command use */ +typedef struct _PARAM_CUSTOM_TDLS_CMD_STRUCT_T { + u8 ucFmeType; /* TDLS_FRM_ACTION_ID */ + + u8 ucToken; + u8 ucCap; + + /* bit0: TDLS, bit1: Peer U-APSD Buffer, bit2: Channel Switching */ + + u8 ucExCap; + + u8 arSupRate[4]; + u8 arSupChan[4]; + + u32 u4Timeout; + + u8 arRspAddr[TDLS_FME_MAC_ADDR_LEN]; + u8 arBssid[TDLS_FME_MAC_ADDR_LEN]; + + /* Linux Kernel-3.10 */ + + struct ieee80211_ht_cap rHtCapa; + struct ieee80211_vht_cap rVhtCapa; + /* struct */ + STATION_PRARAMETERS rPeerInfo; +} PARAM_CUSTOM_TDLS_CMD_STRUCT_T; + +typedef enum _ENUM_TDLS_LINK_OPER { + TDLS_DISCOVERY_REQ, + TDLS_SETUP, + TDLS_TEARDOWN, + TDLS_ENABLE_LINK, + TDLS_DISABLE_LINK +} ENUM_TDLS_LINK_OPER; + +typedef struct _TDLS_CMD_LINK_OPER_T { + u8 aucPeerMac[6]; + ENUM_TDLS_LINK_OPER oper; +} TDLS_CMD_LINK_OPER_T; + +typedef struct _TDLS_CMD_LINK_MGT_T { + u8 aucPeer[6]; + u8 ucActionCode; + u8 ucDialogToken; + u16 u2StatusCode; + u32 u4SecBufLen; + u8 aucSecBuf[TDLS_SEC_BUF_LENGTH]; +} TDLS_CMD_LINK_MGT_T; + +typedef struct _TDLS_CMD_PEER_ADD_T { + u8 aucPeerMac[6]; + ENUM_STA_TYPE_T eStaType; +} TDLS_CMD_PEER_ADD_T; + +typedef struct _TDLS_CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T { + u8 arRxMask[SUP_MCS_RX_BITMASK_OCTET_NUM]; + u16 u2RxHighest; + u8 ucTxParams; + u8 Reserved[3]; +} TDLS_CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T; + +typedef struct _TDLS_CMD_PEER_UPDATE_VHT_CAP_MCS_INFO_T { + u8 arRxMask[SUP_MCS_RX_BITMASK_OCTET_NUM]; +} TDLS_CMD_PEER_UPDATE_VHT_CAP_MCS_INFO_T; + +typedef struct _TDLS_CMD_PEER_UPDATE_HT_CAP_T { + u16 u2CapInfo; + u8 ucAmpduParamsInfo; + + /* 16 bytes MCS information */ + TDLS_CMD_PEER_UPDATE_HT_CAP_MCS_INFO_T rMCS; + + u16 u2ExtHtCapInfo; + u32 u4TxBfCapInfo; + u8 ucAntennaSelInfo; +} TDLS_CMD_PEER_UPDATE_HT_CAP_T; + +typedef struct _TDLS_CMD_PEER_UPDATE_VHT_CAP_T { + u16 u2CapInfo; + /* 16 bytes MCS information */ + TDLS_CMD_PEER_UPDATE_VHT_CAP_MCS_INFO_T rVMCS; +} TDLS_CMD_PEER_UPDATE_VHT_CAP_T; + +typedef struct _TDLS_CMD_PEER_UPDATE_T { + u8 aucPeerMac[6]; + + u8 aucSupChan[TDLS_CMD_PEER_UPDATE_SUP_CHAN_MAX]; + + u16 u2StatusCode; + + u8 aucSupRate[TDLS_CMD_PEER_UPDATE_SUP_RATE_MAX]; + u16 u2SupRateLen; + + u8 UapsdBitmap; + u8 UapsdMaxSp; /* MAX_SP */ + + u16 u2Capability; + + u8 aucExtCap[TDLS_CMD_PEER_UPDATE_EXT_CAP_MAXLEN]; + u16 u2ExtCapLen; + + TDLS_CMD_PEER_UPDATE_HT_CAP_T rHtCap; + TDLS_CMD_PEER_UPDATE_VHT_CAP_T rVHtCap; + + u8 fgIsSupHt; + ENUM_STA_TYPE_T eStaType; +} TDLS_CMD_PEER_UPDATE_T; + +/* Command to TDLS core module */ +typedef enum _TDLS_CMD_CORE_ID { + TDLS_CORE_CMD_TEST_NULL_RCV = 0x00 +} TDLS_CMD_CORE_ID; + +typedef struct _TDLS_CMD_CORE_TEST_NULL_RCV_T { + u32 u4PM; +} TDLS_CMD_CORE_TEST_NULL_RCV_T; + +typedef struct _TDLS_CMD_CORE_T { + u32 u4Command; + + u8 aucPeerMac[6]; + +#define TDLS_CMD_CORE_RESERVED_SIZE 50 + union { + TDLS_CMD_CORE_TEST_NULL_RCV_T rCmdNullRcv; + u8 Reserved[TDLS_CMD_CORE_RESERVED_SIZE]; + } Content; +} TDLS_CMD_CORE_T; + +typedef enum _TDLS_EVENT_HOST_ID { + TDLS_HOST_EVENT_TEAR_DOWN = 0x00, + TDLS_HOST_EVENT_TX_DONE +} TDLS_EVENT_HOST_ID; + +typedef enum _TDLS_EVENT_HOST_SUBID_TEAR_DOWN { + TDLS_HOST_EVENT_TD_PTI_TIMEOUT = 0x00, + TDLS_HOST_EVENT_TD_AGE_TIMEOUT, + TDLS_HOST_EVENT_TD_PTI_SEND_FAIL, + TDLS_HOST_EVENT_TD_PTI_SEND_MAX_FAIL, + TDLS_HOST_EVENT_TD_WRONG_NETWORK_IDX, + TDLS_HOST_EVENT_TD_NON_STATE3, + TDLS_HOST_EVENT_TD_LOST_TEAR_DOWN +} TDLS_EVENT_HOST_SUBID_TEAR_DOWN; + +typedef enum _TDLS_REASON_CODE { + TDLS_REASON_CODE_UNREACHABLE = 25, + TDLS_REASON_CODE_UNSPECIFIED = 26, + + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_UNKNOWN = 0x80, /* 128 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_WIFI_OFF = 0x81, /* 129 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_ROAMING = 0x82, /* 130 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_TIMEOUT = 0x83, /* 131 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_AGE_TIMEOUT = 0x84, /* 132 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_REKEY = 0x85, /* 133 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_FAIL = 0x86, /* 134 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_PTI_SEND_MAX_FAIL = 0x87, /* 135 + */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_WRONG_NETWORK_IDX = 0x88, /* 136 + */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_NON_STATE3 = 0x89, /* 137 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_TX_QUOTA_EMPTY = 0x8a, /* 138 */ + TDLS_REASON_CODE_MTK_DIS_BY_US_DUE_TO_LOST_TEAR_DOWN = 0x8b /* 139 */ +} TDLS_REASON_CODE; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +u32 TdlsFrameGeneralIeAppend(ADAPTER_T *prAdapter, + STA_RECORD_T *prStaRec, + u8 *pPkt); + +WLAN_STATUS /* TDLS_STATUS */ + +TdlsDataFrameSend_TearDown(ADAPTER_T *prAdapter, + STA_RECORD_T *prStaRec, + u8 *pPeerMac, + u8 ucActionCode, + u8 ucDialogToken, + u16 u2StatusCode, + u8 *pAppendIe, + u32 AppendIeLen); + +WLAN_STATUS /* TDLS_STATUS */ + +TdlsDataFrameSend_CONFIRM(ADAPTER_T *prAdapter, + STA_RECORD_T *prStaRec, + u8 *pPeerMac, + u8 ucActionCode, + u8 ucDialogToken, + u16 u2StatusCode, + u8 *pAppendIe, + u32 AppendIeLen); + +WLAN_STATUS /* TDLS_STATUS */ + +TdlsDataFrameSend_SETUP_REQ(ADAPTER_T *prAdapter, + STA_RECORD_T *prStaRec, + u8 *pPeerMac, + u8 ucActionCode, + u8 ucDialogToken, + u16 u2StatusCode, + u8 *pAppendIe, + u32 AppendIeLen); + +WLAN_STATUS /* TDLS_STATUS */ + +TdlsDataFrameSend_DISCOVERY_REQ(ADAPTER_T *prAdapter, + STA_RECORD_T *prStaRec, + u8 *pPeerMac, + u8 ucActionCode, + u8 ucDialogToken, + u16 u2StatusCode, + u8 *pAppendIe, + u32 AppendIeLen); + +WLAN_STATUS /* TDLS_STATUS */ + +TdlsDataFrameSend_SETUP_RSP(ADAPTER_T *prAdapter, + STA_RECORD_T *prStaRec, + u8 *pPeerMac, + u8 ucActionCode, + u8 ucDialogToken, + u16 u2StatusCode, + u8 *pAppendIe, + u32 AppendIeLen); + +WLAN_STATUS /* TDLS_STATUS */ + +TdlsDataFrameSend_DISCOVERY_RSP(ADAPTER_T *prAdapter, + STA_RECORD_T *prStaRec, + u8 *pPeerMac, + u8 ucActionCode, + u8 ucDialogToken, + u16 u2StatusCode, + u8 *pAppendIe, + u32 AppendIeLen); + +u32 TdlsexLinkOper(P_ADAPTER_T prAdapter, + void *pvSetBuffer, + u32 u4SetBufferLen, + u32 *pu4SetInfoLen); + +u32 TdlsexLinkMgt(P_ADAPTER_T prAdapter, + void *pvSetBuffer, + u32 u4SetBufferLen, + u32 *pu4SetInfoLen); + +void TdlsexEventHandle(P_GLUE_INFO_T prGlueInfo, u8 *prInBuf, u32 u4InBufLen); + +void TdlsEventTearDown(GLUE_INFO_T *prGlueInfo, u8 *prInBuf, u32 u4InBufLen); + +void TdlsBssExtCapParse(P_STA_RECORD_T prStaRec, u8 *pucIE); + +WLAN_STATUS +TdlsSendChSwControlCmd(P_ADAPTER_T prAdapter, + void *pvSetBuffer, + u32 u4SetBufferLen, + u32 *pu4SetInfoLen); + +WLAN_STATUS +TdlsTxCtrl(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, u8 fgEnable); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/wlan_typedef.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/wlan_typedef.h new file mode 100644 index 00000000000000..692a9aa038ac54 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/wlan_typedef.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file wlan_typedef.h + * \brief Declaration of data type and return values of internal protocol + * stack. + * + * In this file we declare the data type and return values which will be + * exported to all MGMT Protocol Stack. + */ + +#ifndef _WLAN_TYPEDEF_H +#define _WLAN_TYPEDEF_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* Type definition for BSS_INFO_T structure, to describe the attributes used in + * a common BSS. + */ +typedef struct _BSS_INFO_T BSS_INFO_T, *P_BSS_INFO_T; +typedef struct _BSS_INFO_T P2P_DEV_INFO_T, *P_P2P_DEV_INFO_T; + +typedef struct _NEIGHBOR_AP_T NEIGHBOR_AP_T, *P_NEIGHBOR_AP_T; + +typedef struct _AIS_SPECIFIC_BSS_INFO_T AIS_SPECIFIC_BSS_INFO_T, + *P_AIS_SPECIFIC_BSS_INFO_T; +typedef struct _P2P_SPECIFIC_BSS_INFO_T P2P_SPECIFIC_BSS_INFO_T, + *P_P2P_SPECIFIC_BSS_INFO_T; +typedef struct _BOW_SPECIFIC_BSS_INFO_T BOW_SPECIFIC_BSS_INFO_T, + *P_BOW_SPECIFIC_BSS_INFO_T; +/* CFG_SUPPORT_WFD */ +typedef struct _WFD_CFG_SETTINGS_T WFD_CFG_SETTINGS_T, *P_WFD_CFG_SETTINGS_T; + +/* BSS related structures */ +/* Type definition for BSS_DESC_T structure, to describe parameter sets of a + * particular BSS */ +typedef struct _BSS_DESC_T BSS_DESC_T, *P_BSS_DESC_T, **PP_BSS_DESC_T; + +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP +typedef struct _ROAM_BSS_DESC_T ROAM_BSS_DESC_T, *P_ROAM_BSS_DESC_T, + **PP_ROAM_BSS_DESC_T; +#endif + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/wnm.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/wnm.h new file mode 100644 index 00000000000000..dc8a0dec8cea88 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/mgmt/wnm.h @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file wnm.h + * \brief This file contains the IEEE 802.11 family related 802.11v network + * management for MediaTek 802.11 Wireless LAN Adapters. + */ + +#ifndef _WNM_H +#define _WNM_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define BTM_REQ_MODE_CAND_INCLUDED_BIT BIT(0) +#define BTM_REQ_MODE_ABRIDGED BIT(1) +#define BTM_REQ_MODE_DISC_IMM BIT(2) +#define BTM_REQ_MODE_BSS_TERM_INCLUDE BIT(3) +#define BTM_REQ_MODE_ESS_DISC_IMM BIT(4) + +#define BSS_TRANSITION_MGT_STATUS_ACCEPT 0 +#define BSS_TRANSITION_MGT_STATUS_UNSPECIFIED 1 +#define BSS_TRANSITION_MGT_STATUS_NEED_SCAN 2 +#define BSS_TRANSITION_MGT_STATUS_CAND_NO_CAPACITY 3 +#define BSS_TRANSITION_MGT_STATUS_TERM_UNDESIRED 4 +#define BSS_TRANSITION_MGT_STATUS_TERM_DELAY_REQUESTED 5 +#define BSS_TRANSITION_MGT_STATUS_CAND_LIST_PROVIDED 6 +#define BSS_TRANSITION_MGT_STATUS_CAND_NO_CANDIDATES 7 +#define BSS_TRANSITION_MGT_STATUS_LEAVING_ESS 8 + +/* 802.11v: define Transtion and Transition Query reasons */ +#define BSS_TRANSITION_BETTER_AP_FOUND 6 +#define BSS_TRANSITION_LOW_RSSI 16 +#define BSS_TRANSITION_INCLUDE_PREFER_CAND_LIST 19 +#define BSS_TRANSITION_LEAVING_ESS 20 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef struct _TIMINGMSMT_PARAM_T { + u8 fgInitiator; + u8 ucTrigger; + u8 ucDialogToken; /* Dialog Token */ + u8 ucFollowUpDialogToken; /* Follow Up Dialog Token */ + u32 u4ToD; /* Timestamp of Departure [10ns] */ + u32 u4ToA; /* Timestamp of Arrival [10ns] */ +} TIMINGMSMT_PARAM_T, *P_TIMINGMSMT_PARAM_T; + +typedef struct _BSS_TRANSITION_MGT_PARAM_T { + /* for Query */ + u8 ucDialogToken; + u8 ucQueryReason; + /* for Request */ + u8 ucRequestMode; + u16 u2DisassocTimer; + u16 u2TermDuration; + u8 aucTermTsf[8]; + u8 ucSessionURLLen; + u8 aucSessionURL[255]; + /* for Respone */ + u8 fgPendingResponse : 1; + u8 fgUnsolicitedReq : 1; + u8 fgReserved : 6; + u8 ucStatusCode; + u8 ucTermDelay; + u8 aucTargetBssid[MAC_ADDR_LEN]; + u8 *pucOurNeighborBss; + u16 u2OurNeighborBssLen; +} BSS_TRANSITION_MGT_PARAM_T, *P_BSS_TRANSITION_MGT_PARAM_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void wnmWNMAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +void wnmReportTimingMeas(IN P_ADAPTER_T prAdapter, + IN u8 ucStaRecIndex, + IN u32 u4ToD, + IN u32 u4ToA); + +#define WNM_UNIT_TEST 1 + +#if WNM_UNIT_TEST +void wnmTimingMeasUnitTest1(P_ADAPTER_T prAdapter, u8 ucStaRecIndex); +#endif + +u8 wnmGetBtmToken(void); + +void wnmSendBTMQueryFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +void wnmSendBTMResponseFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec); + +void wnmRecvBTMRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/adapter.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/adapter.h new file mode 100644 index 00000000000000..c67a60350b37f4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/adapter.h @@ -0,0 +1,1538 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file adapter.h + * \brief Definition of internal data structure for driver manipulation. + * + * In this file we define the internal data structure - ADAPTER_T which + * stands for MiniPort ADAPTER(From Windows point of view) or stands for Network + * ADAPTER. + */ + +#ifndef _ADAPTER_H +#define _ADAPTER_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +enum { + ENUM_SW_TEST_MODE_NONE = 0, + ENUM_SW_TEST_MODE_SIGMA_AC = 0x1, + ENUM_SW_TEST_MODE_SIGMA_WFD = 0x2, + ENUM_SW_TEST_MODE_CTIA = 0x3, + ENUM_SW_TEST_MODE_SIGMA_TDLS = 0x4, + ENUM_SW_TEST_MODE_SIGMA_P2P = 0x5, + ENUM_SW_TEST_MODE_SIGMA_N = 0x6, + ENUM_SW_TEST_MODE_SIGMA_HS20_R1 = 0x7, + ENUM_SW_TEST_MODE_SIGMA_HS20_R2 = 0x8, + ENUM_SW_TEST_MODE_SIGMA_PMF = 0x9, + ENUM_SW_TEST_MODE_SIGMA_WMMPS = 0xA, + ENUM_SW_TEST_MODE_SIGMA_AC_R2 = 0xB, + ENUM_SW_TEST_MODE_SIGMA_NAN = 0xC, + ENUM_SW_TEST_MODE_SIGMA_AC_AP = 0xD, + ENUM_SW_TEST_MODE_SIGMA_N_AP = 0xE, + ENUM_SW_TEST_MODE_SIGMA_WFDS = 0xF, + ENUM_SW_TEST_MODE_SIGMA_WFD_R2 = 0x10, + ENUM_SW_TEST_MODE_SIGMA_LOCATION = 0x11, + ENUM_SW_TEST_MODE_SIGMA_TIMING_MANAGEMENT = 0x12, + ENUM_SW_TEST_MODE_SIGMA_WMMAC = 0x13, + ENUM_SW_TEST_MODE_SIGMA_VOICE_ENT = 0x14 +}; + +typedef struct _WLAN_INFO_T { + PARAM_BSSID_EX_T rCurrBssId; + + /* Scan Result */ + PARAM_BSSID_EX_T arScanResult[CFG_MAX_NUM_BSS_LIST]; + u8 *apucScanResultIEs[CFG_MAX_NUM_BSS_LIST]; + u32 u4ScanResultNum; + + /* IE pool for Scanning Result */ + u8 aucScanIEBuf[CFG_MAX_COMMON_IE_BUF_LEN]; + u32 u4ScanIEBufferUsage; + + u32 u4SysTime; + + /* connection parameter (for Ad-Hoc) */ + u16 u2BeaconPeriod; + u16 u2AtimWindow; + + PARAM_RATES eDesiredRates; + CMD_LINK_ATTRIB eLinkAttr; + /* CMD_PS_PROFILE_T ePowerSaveMode; */ + CMD_PS_PROFILE_T arPowerSaveMode[BSS_INFO_NUM]; + + /* trigger parameter */ + ENUM_RSSI_TRIGGER_TYPE eRssiTriggerType; + PARAM_RSSI rRssiTriggerValue; + + /* Privacy Filter */ + ENUM_PARAM_PRIVACY_FILTER_T ePrivacyFilter; + + /* RTS Threshold */ + PARAM_RTS_THRESHOLD eRtsThreshold; + + /* Network Type */ + u8 ucNetworkType; + + /* Network Type In Use */ + u8 ucNetworkTypeInUse; +} WLAN_INFO_T, *P_WLAN_INFO_T; + +/* Session for CONNECTION SETTINGS */ +typedef struct _CONNECTION_SETTINGS_T { + u8 aucMacAddress[MAC_ADDR_LEN]; + + u8 ucDelayTimeOfDisconnectEvent; + + u8 fgIsConnByBssidIssued; + u8 aucBSSID[MAC_ADDR_LEN]; + + u8 fgIsConnReqIssued; + u8 fgIsDisconnectedByNonRequest; + + u8 ucSSIDLen; + u8 aucSSID[ELEM_MAX_LEN_SSID]; + + ENUM_PARAM_OP_MODE_T eOPMode; + + ENUM_PARAM_CONNECTION_POLICY_T eConnectionPolicy; + + ENUM_PARAM_AD_HOC_MODE_T eAdHocMode; + + ENUM_PARAM_AUTH_MODE_T eAuthMode; + + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + + u8 fgIsScanReqIssued; + + /* MIB attributes */ + u16 u2BeaconPeriod; + + u16 u2RTSThreshold; /* User desired setting */ + + u16 u2DesiredNonHTRateSet; /* User desired setting */ + + u8 ucAdHocChannelNum; /* For AdHoc */ + + ENUM_BAND_T eAdHocBand; /* For AdHoc */ + + u32 u4FreqInKHz; /* Center frequency */ + + /* ATIM windows using for IBSS power saving function */ + u16 u2AtimWindow; + + /* Features */ + u8 fgIsEnableRoaming; + + u8 fgIsAdHocQoSEnable; + + ENUM_PARAM_PHY_CONFIG_T eDesiredPhyConfig; + + /* Used for AP mode for desired channel and bandwidth */ + u16 u2CountryCode; + u8 uc2G4BandwidthMode; /* 20/40M or 20M only */ /* Not used */ + u8 uc5GBandwidthMode; /* 20/40M or 20M only */ /* Not used */ + +#if CFG_SUPPORT_802_11D + u8 fgMultiDomainCapabilityEnabled; +#endif + + u8 fgWapiMode; + u32 u4WapiSelectedGroupCipher; + u32 u4WapiSelectedPairwiseCipher; + u32 u4WapiSelectedAKMSuite; + + /* CR1486, CR1640 */ + /* for WPS, disable the privacy check for AP selection policy */ + u8 fgPrivacyCheckDisable; + + /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ + u8 bmfgApsdEnAc; + + /* for RSN info store, when upper layer set rsn info */ + RSN_INFO_T rRsnInfo; + + struct cfg80211_bss *bss; + + u8 fgIsConnInitialized; + + u8 fgIsSendAssoc; + + u8 ucAuthDataLen; + /* Temp assign a fixed large number + * Additional elements for Authentication frame, + * starts with the Authentication transaction sequence number field + */ + u8 aucAuthData[AUTH_DATA_MAX_LEN]; + u8 ucChannelNum; + +#if CFG_SUPPORT_OWE + /* for OWE info store, when upper layer set rsn info */ + struct OWE_INFO_T rOweInfo; +#endif + +#if CFG_SUPPORT_H2E + struct RSNXE rRsnXE; +#endif +} CONNECTION_SETTINGS_T, *P_CONNECTION_SETTINGS_T; + +struct _BSS_INFO_T { + ENUM_NETWORK_TYPE_T eNetworkType; + + u32 u4PrivateData; /* Private data parameter for each NETWORK type + * usage. */ + /* P2P network type has 3 network interface to distinguish. */ + + ENUM_PARAM_MEDIA_STATE_T + eConnectionState; /* Connected Flag used in AIS_NORMAL_TR */ + ENUM_PARAM_MEDIA_STATE_T + eConnectionStateIndicated; /* The Media State that report to HOST */ + + ENUM_OP_MODE_T eCurrentOPMode; /* Current Operation Mode - Infra/IBSS */ +#if CFG_ENABLE_WIFI_DIRECT + ENUM_OP_MODE_T eIntendOPMode; +#endif + +#if (CFG_SUPPORT_DFS_MASTER == 1) + u8 fgIsDfsActive; +#endif + +#if CFG_SUPPORT_DBDC_TC6 + u8 fgReConnBypassScan; + /* Ignore stale state of target BSS + * during DBDC sta reconnect searching to bypass scan + */ +#endif + + u8 fgIsInUse; /* For CNM to assign BSS_INFO */ + u8 fgIsNetActive; /* true if this network has been activated */ + + u8 ucBssIndex; /* BSS_INFO_T index */ + + u8 ucReasonOfDisconnect; /* Used by media state indication */ + + u8 ucSSIDLen; /* Length of SSID */ + +#if CFG_ENABLE_WIFI_DIRECT + ENUM_HIDDEN_SSID_TYPE_T eHiddenSsidType; /* For Hidden SSID usage. */ +#endif + + u8 aucSSID[ELEM_MAX_LEN_SSID]; /* SSID used in this BSS */ + + u8 aucBSSID[MAC_ADDR_LEN]; /* The BSSID of the associated BSS */ + + u8 aucOwnMacAddr[MAC_ADDR_LEN]; /* Owned MAC Address used in this BSS */ + + u8 ucOwnMacIndex; /* Owned MAC index used in this BSS */ + + P_STA_RECORD_T prStaRecOfAP; /* For Infra Mode, and valid only if + * eConnectionState == + * MEDIA_STATE_CONNECTED + */ + LINK_T + rStaRecOfClientList; /* For IBSS/AP Mode, all known STAs in current BSS + */ + + u8 ucBMCWlanIndex; /* For open Mode, BC/MC Tx wlan index, For STA, BC/MC + * Rx wlan index */ + + u8 ucBMCWlanIndexS[MAX_KEY_NUM]; /* For AP Mode, BC/MC Tx wlan index, + * For STA, BC/MC Rx wlan index */ + u8 ucBMCWlanIndexSUsed[MAX_KEY_NUM]; + + u8 fgBcDefaultKeyExist; /* Bc Transmit key exist or not */ + u8 ucBcDefaultKeyIdx; /* Bc default key idx, for STA, the Rx just set, + * for AP, the tx key id */ + + u8 wepkeyUsed[MAX_KEY_NUM]; + u8 wepkeyWlanIdx; /* wlan index of the wep key */ + + u16 u2CapInfo; /* Change Detection */ + + u16 u2BeaconInterval; /* The Beacon Interval of this BSS */ + + u16 u2ATIMWindow; /* For IBSS Mode */ + + u16 u2AssocId; /* For Infra Mode, it is the Assoc ID assigned by AP. + */ + + u8 ucDTIMPeriod; /* For Infra/AP Mode */ + + u8 ucDTIMCount; /* For AP Mode, it is the DTIM value we should carried + * in the Beacon of next TBTT. + */ + + u8 ucPhyTypeSet; /* Available PHY Type Set of this peer + * (This is deduced from received BSS_DESC_T) + */ + + u8 ucNonHTBasicPhyType; /* The Basic PHY Type Index, used to setup Phy + * Capability */ + + u8 ucConfigAdHocAPMode; /* The configuration of AdHoc/AP Mode. e.g. 11g + * or 11b */ + + u8 ucBeaconTimeoutCount; /* For Infra/AP Mode, it is a threshold of + * Beacon Lost Count to confirm connection was + * lost + */ + + u8 fgHoldSameBssidForIBSS; /* For IBSS Mode, to keep use same BSSID to + * extend the life cycle of an IBSS */ + + u8 fgIsBeaconActivated; /* For AP/IBSS Mode, it is used to indicate that + * Beacon is sending */ + + P_MSDU_INFO_T prBeacon; /* For AP/IBSS Mode - Beacon Frame */ + + u8 fgIsIBSSMaster; /* For IBSS Mode - To indicate that we can reply + * ProbeResp Frame. In current TBTT interval + */ + + u8 fgIsShortPreambleAllowed; /* From Capability Info. of AssocResp Frame + * AND of Beacon/ProbeResp Frame + */ + u8 fgUseShortPreamble; /* Short Preamble is enabled in current BSS. */ + u8 fgUseShortSlotTime; /* Short Slot Time is enabled in current BSS. */ + + u16 u2OperationalRateSet; /* Operational Rate Set of current BSS */ + u16 u2BSSBasicRateSet; /* Basic Rate Set of current BSS */ + + u8 ucAllSupportedRatesLen; /* Used for composing Beacon Frame in AdHoc + * or AP Mode */ + u8 aucAllSupportedRates[RATE_NUM_SW]; + + u8 ucAssocClientCnt; /* TODO(Kevin): Number of associated clients */ + + u8 fgIsProtection; + u8 fgIsQBSS; + /* fgIsWmmBSS; */ /* For Infra/AP/IBSS Mode, it is used to indicate if + * we support WMM in current BSS. + */ + u8 fgIsNetAbsent; /* true: BSS is absent, false: BSS is present */ + + u8 fgIsWepCipherGroup; + u32 u4RsnSelectedGroupCipher; + u32 u4RsnSelectedPairwiseCipher; + u32 u4RsnSelectedAKMSuite; + u16 u2RsnSelectedCapInfo; + + u8 ucOpChangeChannelWidth; /* The OpMode channel width that we want to + * change to*/ + /* 0:20MHz, 1:40MHz, 2:80MHz, 3:160MHz 4:80+80MHz */ + u8 fgIsOpChangeChannelWidth; + + /*------------------------------------------------------------------------*/ + /* Power Management related information */ + /*------------------------------------------------------------------------*/ + PM_PROFILE_SETUP_INFO_T rPmProfSetupInfo; + + /*------------------------------------------------------------------------*/ + /* WMM/QoS related information */ + /*------------------------------------------------------------------------*/ + u8 ucWmmParamSetCount; /* Used to detect the change of EDCA parameters. + * For AP mode, the value is used in WMM IE + */ + + AC_QUE_PARMS_T arACQueParms[WMM_AC_INDEX_NUM]; + + u8 aucCWminLog2ForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the + * CWminLog2 */ + u8 aucCWmaxLog2ForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the + * CWmaxLog2 */ + AC_QUE_PARMS_T + arACQueParmsForBcast[WMM_AC_INDEX_NUM]; /* For AP mode, broadcast the + * value */ + u8 ucWmmQueSet; +#if (CFG_HW_WMM_BY_BSS == 1) + u8 fgIsWmmInited; +#endif + + /*------------------------------------------------------------------------*/ + /* 802.11n HT operation IE when (prStaRec->ucPhyTypeSet & + * PHY_TYPE_BIT_HT) */ + /* is true. They have the same definition with fields of */ + /* information element (CM) */ + /*------------------------------------------------------------------------*/ + ENUM_BAND_T eBand; + u8 ucPrimaryChannel; + u8 ucHtOpInfo1; + u8 ucHtPeerOpInfo1; /*Backup peer HT OP Info*/ + u16 u2HtOpInfo2; + u16 u2HtOpInfo3; + u8 ucNss; + /*------------------------------------------------------------------------*/ + /* 802.11ac VHT operation IE when (prStaRec->ucPhyTypeSet & + * PHY_TYPE_BIT_VHT) */ + /* is true. They have the same definition with fields of */ + /* information element (EASON) */ + /*------------------------------------------------------------------------*/ + + u8 ucVhtChannelWidth; + u8 ucVhtChannelFrequencyS1; + u8 ucVhtChannelFrequencyS2; + u16 u2VhtBasicMcsSet; + + /* Backup peer VHT OpInfo */ + u8 ucVhtPeerChannelWidth; + u8 ucVhtPeerChannelFrequencyS1; + u8 ucVhtPeerChannelFrequencyS2; + + /*------------------------------------------------------------------------*/ + /* Required protection modes (CM) */ + /*------------------------------------------------------------------------*/ + u8 fgErpProtectMode; + ENUM_HT_PROTECT_MODE_T eHtProtectMode; + ENUM_GF_MODE_T eGfOperationMode; + ENUM_RIFS_MODE_T eRifsOperationMode; + + u8 fgObssErpProtectMode; /* GO only */ + ENUM_HT_PROTECT_MODE_T eObssHtProtectMode; /* GO only */ + ENUM_GF_MODE_T eObssGfOperationMode; /* GO only */ + u8 fgObssRifsOperationMode; /* GO only */ + + /*------------------------------------------------------------------------*/ + /* OBSS to decide if 20/40M bandwidth is permitted. */ + /* The first member indicates the following channel list length. */ + /*------------------------------------------------------------------------*/ + u8 fgAssoc40mBwAllowed; + u8 fg40mBwAllowed; + ENUM_CHNL_EXT_T eBssSCO; /* Real setting for HW + * 20/40M AP mode will always set 40M, + * but its OP IE can be changed. + */ + u8 auc2G_20mReqChnlList[CHNL_LIST_SZ_2G + 1]; + u8 auc2G_NonHtChnlList[CHNL_LIST_SZ_2G + 1]; + u8 auc2G_PriChnlList[CHNL_LIST_SZ_2G + 1]; + u8 auc2G_SecChnlList[CHNL_LIST_SZ_2G + 1]; + + u8 auc5G_20mReqChnlList[CHNL_LIST_SZ_5G + 1]; + u8 auc5G_NonHtChnlList[CHNL_LIST_SZ_5G + 1]; + u8 auc5G_PriChnlList[CHNL_LIST_SZ_5G + 1]; + u8 auc5G_SecChnlList[CHNL_LIST_SZ_5G + 1]; + + TIMER_T rObssScanTimer; + u16 u2ObssScanInterval; /* in unit of sec */ + + u8 fgObssActionForcedTo20M; /* GO only */ + u8 fgObssBeaconForcedTo20M; /* GO only */ + +#if CFG_SUPPORT_QUIET + TIMER_T rTxQuietTimer; + u8 ucQuietPeriod; + u16 u2QuietOffset; + u16 u2QuietDuration; + u8 fgRequestQuietInterval; + u8 fgIsInQuietInterval; +#endif + /*------------------------------------------------------------------------*/ + /* HW Related Fields (Kevin) */ + /*------------------------------------------------------------------------*/ + u16 u2HwDefaultFixedRateCode; /* The default rate code copied to MAC TX + * Desc */ + u16 u2HwLPWakeupGuardTimeUsec; + + u8 ucBssFreeQuota; /* The value is updated from FW */ + + u16 u2DeauthReason; + +#if CFG_SUPPORT_TDLS + u8 fgTdlsIsProhibited; + u8 fgTdlsIsChSwProhibited; +#endif +#if CFG_SUPPORT_PNO + u8 fgIsPNOEnable; + u8 fgIsNetRequestInActive; +#endif + + WIFI_WMM_AC_STAT_T + arLinkStatistics[WMM_AC_INDEX_NUM]; /*link layer statistics */ + + ENUM_DBDC_BN_T eDBDCBand; + + u32 u4CoexPhyRateLimit; + +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP + u8 ucRoamSkipTimes; + u8 fgGoodRcpiArea; + u8 fgPoorRcpiArea; +#endif + + u8 fgIsGranted; + ENUM_BAND_T eBandGranted; + u8 ucPrimaryChannelGranted; + PARAM_CUSTOM_ACL rACL; + +#if CFG_SUPPORT_802_11W + /* AP PMF */ + struct AP_PMF_CFG rApPmfCfg; + /* STA PMF: for encrypted deauth frame */ + struct completion rDeauthComp; + u8 encryptedDeauthIsInProcess; +#endif + +#if CFG_SUPPORT_REPLAY_DETECTION + struct SEC_DETECT_REPLAY_INFO rDetRplyInfo; +#endif + + PARAM_POWER_MODE ePowerModeFromUser; + +#if CFG_SUPPORT_DFS + TIMER_T rCsaTimer; + SWITCH_CH_AND_BAND_PARAMS_T CSAParams; + u8 fgHasStopTx; +#endif + +#if CFG_STR_DHCP_RENEW_OFFLOAD + u8 fgIsDhcpAcked; + u8 aucDhcpServerIpAddr[4]; + u32 u4DhcpRenewIntv; /* DHCP renew offload interval configured by + * upper-layer */ +#endif +}; + +struct _NEIGHBOR_AP_T { + LINK_ENTRY_T rLinkEntry; + u8 aucBssid[MAC_ADDR_LEN]; + u8 fgHT : 1; + u8 fgSameMD : 1; + u8 fgRmEnabled : 1; + u8 fgFromBtm : 1; + u8 fgQoS : 1; + u8 ucReserved : 3; + u8 fgPrefPresence; + u8 ucPreference; + u8 ucChannel; + u64 u8TermTsf; +}; + +struct _AIS_SPECIFIC_BSS_INFO_T { + u8 ucRoamingAuthTypes; /* This value indicate the roaming type used in + * AIS_JOIN */ + + u8 fgIsIBSSActive; + + /*! \brief Global flag to let arbiter stay at standby and not connect to + * any network */ + u8 fgCounterMeasure; + /* u8 ucTxWlanIndex; */ /* Legacy wep, adhoc wep wpa + * Transmit + * key wlan index */ + + /* u8 fgKeyMaterialExist[4]; */ + /* u8 aucKeyMaterial[32][4]; */ + + /* While Do CounterMeasure procedure, check the EAPoL Error report have + * send out */ + u8 fgCheckEAPoLTxDone; + + u32 u4RsnaLastMICFailTime; + + /* Stored the current bss wpa rsn cap filed, used for roaming policy */ + /* u16 u2RsnCap; */ + TIMER_T rPreauthenticationTimer; + + /* By the flow chart of 802.11i, + * wait 60 sec before associating to same AP + * or roaming to a new AP + * or sending data in IBSS, + * keep a timer for handle the 60 sec counterMeasure + */ + TIMER_T rRsnaBlockTrafficTimer; + TIMER_T rRsnaEAPoLReportTimeoutTimer; + + /* For Keep the Tx/Rx Mic key for TKIP SW Calculate Mic */ + /* This is only one for AIS/AP */ + u8 aucTxMicKey[8]; + u8 aucRxMicKey[8]; + + /* Buffer for WPA2 PMKID */ + /* The PMKID cache lifetime is expire by media_disconnect_indication */ + u32 u4PmkidCandicateCount; + PMKID_CANDICATE_T arPmkidCandicate[CFG_MAX_PMKID_CACHE]; + u32 u4PmkidCacheCount; + PMKID_ENTRY_T arPmkidCache[CFG_MAX_PMKID_CACHE]; + u8 fgIndicatePMKID; +#if CFG_SUPPORT_802_11W + u8 fgMgmtProtection; + u8 fgAPApplyPmfReq; + u32 u4SaQueryStart; + u32 u4SaQueryCount; + u8 ucSaQueryTimedOut; + u8 *pucSaQueryTransId; + TIMER_T rSaQueryTimer; + u8 fgBipKeyInstalled; +#endif +#if CFG_SUPPORT_802_11V + BSS_TRANSITION_MGT_PARAM_T rBTMParam; +#endif + LINK_MGMT_T rNeighborApList; + u32 rNeiApRcvTime; + u32 u4NeiApValidInterval; +}; + +struct _BOW_SPECIFIC_BSS_INFO_T { + u16 u2Reserved; /* Reserved for Data Type Check */ +}; + +typedef struct _WLAN_TABLE_T { + u8 ucUsed; + u8 ucBssIndex; + u8 ucKeyId; + u8 ucPairwise; + u8 aucMacAddr[MAC_ADDR_LEN]; + u8 ucStaIndex; +} WLAN_TABLE_T, *P_WLAN_TABLE_T; + +/* Major member variables for WiFi FW operation. + * Variables within this region will be ready for access after WIFI function is + * enabled. + */ +typedef struct _WIFI_VAR_T { + u8 fgIsRadioOff; + + u8 fgIsEnterD3ReqIssued; + + u8 fgDebugCmdResp; + + CONNECTION_SETTINGS_T rConnSettings; + + SCAN_INFO_T rScanInfo; + +#if CFG_SUPPORT_ROAMING + ROAMING_INFO_T rRoamingInfo; +#endif + + AIS_FSM_INFO_T rAisFsmInfo; + + ENUM_PWR_STATE_T aePwrState[BSS_INFO_NUM + 1]; + + BSS_INFO_T arBssInfoPool[BSS_INFO_NUM]; + + P2P_DEV_INFO_T rP2pDevInfo; + + AIS_SPECIFIC_BSS_INFO_T rAisSpecificBssInfo; + +#if CFG_ENABLE_WIFI_DIRECT + P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings[BSS_P2P_NUM]; + + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo[BSS_P2P_NUM]; + + /* P_P2P_FSM_INFO_T prP2pFsmInfo; */ + + P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo; + + /* Currently we only support 2 p2p interface. */ + P_P2P_ROLE_FSM_INFO_T aprP2pRoleFsmInfo[BSS_P2P_NUM]; + + P_PARAM_GET_STA_STATISTICS prP2pQueryStaStatistics[BSS_P2P_NUM]; +#endif + + WLAN_TABLE_T arWtbl[WTBL_SIZE]; + + DEAUTH_INFO_T arDeauthInfo[MAX_DEAUTH_INFO_COUNT]; + + /* Current Wi-Fi Settings and Flags */ + u8 aucPermanentAddress[MAC_ADDR_LEN]; + u8 aucMacAddress[MAC_ADDR_LEN]; + u8 aucDeviceAddress[MAC_ADDR_LEN]; + u8 aucInterfaceAddress[MAC_ADDR_LEN]; + + u8 ucAvailablePhyTypeSet; + + ENUM_PHY_TYPE_INDEX_T + eNonHTBasicPhyType2G4; /* Basic Phy Type used by SCN according + * to the set of Available PHY Types + */ + + ENUM_PARAM_PREAMBLE_TYPE_T ePreambleType; + ENUM_REGISTRY_FIXED_RATE_T eRateSetting; + + u8 fgIsShortSlotTimeOptionEnable; + /* User desired setting, but will honor the capability of AP */ + + u8 fgEnableJoinToHiddenSSID; + u8 fgSupportWZCDisassociation; + +#if CFG_SUPPORT_WFD + WFD_CFG_SETTINGS_T rWfdConfigureSettings; +#endif + + u8 aucMediatekOuiIE[64]; + u16 u2MediatekOuiIELen; + + /* Feature Options */ + u8 ucQoS; + + u8 ucStaHt; + u8 ucStaVht; + u8 ucApHt; + u8 ucApVht; + u8 ucP2pGoHt; + u8 ucP2pGoVht; + u8 ucP2pGcHt; + u8 ucP2pGcVht; + + u8 ucAmpduTx; + u8 ucAmpduRx; + u8 ucAmsduInAmpduTx; + u8 ucAmsduInAmpduRx; + u8 ucHtAmsduInAmpduTx; + u8 ucHtAmsduInAmpduRx; + u8 ucVhtAmsduInAmpduTx; + u8 ucVhtAmsduInAmpduRx; + u8 ucTspec; + u8 ucUapsd; + u8 ucStaUapsd; + u8 ucApUapsd; + u8 ucP2pUapsd; + + u8 ucTxShortGI; + u8 ucRxShortGI; + u8 ucTxLdpc; + u8 ucRxLdpc; + u8 ucTxStbc; + u8 ucRxStbc; + u8 ucRxStbcNss; + u8 ucTxGf; + u8 ucRxGf; + + u8 ucMCS32; + + u8 ucTxopPsTx; + u8 ucSigTaRts; + u8 ucDynBwRts; + + u8 ucStaHtBfee; + u8 ucStaVhtBfee; + u8 ucStaHtBfer; + u8 ucStaVhtBfer; + u8 ucStaVhtMuBfee; + + u8 ucDataTxDone; + u8 ucDataTxRateMode; + u32 u4DataTxRateCode; + + u8 ucApWpsMode; + u8 ucApChannel; + + u8 ucApSco; + u8 ucP2pGoSco; + + u8 ucStaBandwidth; + u8 ucSta5gBandwidth; + u8 ucSta2gBandwidth; + u8 ucApBandwidth; + u8 ucAp2gBandwidth; + u8 ucAp5gBandwidth; + u8 ucP2p5gBandwidth; + u8 ucP2p2gBandwidth; + + /* If enable, AP channel bandwidth Channel Center Frequency Segment 0/1 + */ + /* and secondary channel offset will align wifi.cfg */ + /* Otherwise align cfg80211 */ + u8 ucApChnlDefFromCfg; + + u8 ucNSS; + + u8 ucAp5gNSS; /* Less or euqal than ucNss */ + u8 ucAp2gNSS; /* Less or euqal than ucNss */ + u8 ucGo5gNSS; /* Less or euqal than ucNss */ + u8 ucGo2gNSS; /* Less or euqal than ucNss */ + + u8 ucRxMaxMpduLen; + u32 u4TxMaxAmsduInAmpduLen; + + u8 ucTxBaSize; + u8 ucRxHtBaSize; + u8 ucRxVhtBaSize; + + u8 ucStaDisconnectDetectTh; + u8 ucApDisconnectDetectTh; + u8 ucP2pDisconnectDetectTh; + + u8 ucThreadScheduling; + u8 ucThreadPriority; + s8 cThreadNice; + + u8 ucTcRestrict; + u32 u4MaxTxDeQLimit; + u8 ucAlwaysResetUsedRes; + + u32 u4NetifStopTh; + u32 u4NetifStartTh; +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + PARAM_GET_CHN_INFO rChnLoadInfo; +#endif +#if CFG_SUPPORT_MTK_SYNERGY + u8 ucMtkOui; + u32 u4MtkOuiCap; + u8 aucMtkFeature[4]; +#endif + + u8 fgCsaInProgress; + u8 ucChannelSwitchMode; + u8 ucNewChannelNumber; + u8 ucChannelSwitchCount; +#if CFG_SUPPORT_DBDC_TC6 + u8 fgDelayInidicateDISCON; +#endif + + u32 u4HifIstLoopCount; + u32 u4Rx2OsLoopCount; + u32 u4HifTxloopCount; + u32 u4TxRxLoopCount; + u32 u4TxFromOsLoopCount; + u32 u4TxIntThCount; + + u32 au4TcPageCount[TC_NUM]; + u8 ucExtraTxDone; + u8 ucTxDbg; + + u8 ucCmdRsvResource; + u32 u4MgmtQueueDelayTimeout; + + u32 u4StatsLogTimeout; + u32 u4StatsLogDuration; + u8 ucDhcpTxDone; + u8 ucArpTxDone; + + u8 ucMacAddrOverride; + u8 aucMacAddrStr[32]; + + u8 ucCtiaMode; + u8 ucTpTestMode; + u8 ucSigmaTestMode; +#if CFG_SUPPORT_DBDC + u8 ucDbdcMode; + u8 fgDbDcModeEn; + TIMER_T + rDBDCDisableCountdownTimer; /* Prevent continuously trigger by + * reconnection */ + TIMER_T rDBDCSwitchGuardTimer; /* Prevent switch too quick*/ +#endif +#if CFG_SUPPORT_DBDC_TC6 + TIMER_T + rDBDCReconnectCountDown; /* Prevent driver-level reconnection process + * from DBDC switching */ + TIMER_T + rDBDCAisConnectCountDown; /* Prevent AIS connect process from DBDC + * switching */ +#endif + u8 u4ScanCtrl; + u8 ucScanChannelListenTime; + +#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1) + u8 ucEfuseBufferModeCal; +#endif + u8 ucCalTimingCtrl; + u8 ucWow; + u8 ucOffload; + u8 ucAdvPws; /* enable LP multiple DTIM function, default enable */ + u8 ucWowOnMdtim; /* multiple DTIM if WOW enable, default 1 */ + u8 ucWowOffMdtim; /* multiple DTIM if WOW disable, default 3 */ + u8 ucWowPwsMode; /* when enter wow, automatically enter wow power-saving + * profile */ + u8 ucWlanSetCamDuringAct; /* Set wlan PS=CAM during activity */ + u8 ucListenDtimInterval; /* adjust the listen interval by dtim interval + */ + u8 ucEapolOffload; /* eapol offload when active mode / wow mode */ +#ifdef SUPPORT_ENFORCE_PWR_MODE + u8 ucEnforce2G; /* Enforce to a specific power mode regardless of + * Android's setting */ + u8 ucEnforce5G; /* Enforce to a specific power mode regardless of + * Android's setting */ +#else + u8 ucEnforcePSMode; /* Enforce to a specific power mode regardless of + * Android's setting */ + u8 ucEnforceCAM2G; +#endif + +#ifdef SUPPORT_PERIODIC_PS + u8 ucPspCAMInt; + u8 ucAwakePspCAMInt; +#define PSP_CAM_INT_DEFAULT 20 +#define AWAKE_PSP_CAM_INT_DEFAULT 20 + u8 ucPspPSInt; + u8 ucAwakePspPSInt; +#define PSP_PS_INT_DEFAULT 10 +#define AWAKE_PSP_PS_INT_DEFAULT 10 +#endif + + u8 ucWaitConnect; +#define WAIT_CONNECT_DEFAULT 20 + +#if CFG_SUPPORT_REPLAY_DETECTION + u8 ucRpyDetectOffload; /* eapol offload when active mode / wow mode */ +#endif + + u8 u4SwTestMode; + u8 ucCtrlFlagAssertPath; + u8 ucCtrlFlagDebugLevel; + u32 u4WakeLockRxTimeout; + u32 u4WakeLockThreadWakeup; + u32 u4RegP2pIfAtProbe; /* register p2p interface during probe */ + u8 ucP2pShareMacAddr; /* p2p group interface use the same mac addr as + * p2p device interface */ + u8 ucSmartRTS; + + u32 u4UapsdAcBmp; + u32 u4MaxSpLen; + u32 fgDisOnlineScan; /* 0: enable online scan, non-zero: disable online + * scan */ + u32 fgDisBcnLostDetection; + u32 fgDisRoaming; /* 0:enable roaming 1:disable */ + u32 fgEnArpFilter; + + u8 uDeQuePercentEnable; + u32 u4DeQuePercentVHT80Nss1; + u32 u4DeQuePercentVHT40Nss1; + u32 u4DeQuePercentVHT20Nss1; + u32 u4DeQuePercentHT40Nss1; + u32 u4DeQuePercentHT20Nss1; + + u8 fgTdlsBufferSTASleep; /* Support TDLS 5.5.4.2 optional case */ + u8 fgChipResetRecover; + + u8 ucN9Log2HostCtrl; + u8 ucCR4Log2HostCtrl; + +#if CFG_SUPPORT_ANT_SELECT + u8 ucSpeIdxCtrl; /* 0:WF0, 1:WF1, 2: both WF0/1 */ + u8 ucSpeIdxCtrl2G; /* 0:WF0, 1:WF1, 2: both WF0/1 only in 2G*/ +#endif + +#ifdef CFG_SUPPORT_ADJUST_JOIN_CH_REQ_INTERVAL + u32 u4AisJoinChReqIntervel; +#endif + +#if CFG_SUPPORT_RSSI_COMP + RSSI_PATH_COMPASATION_T rRssiPathCompasation; +#endif + s32 ucEd2GNonEU; + s32 ucEd5GNonEU; + s32 ucEd2GEU; + s32 ucEd5GEU; + u8 ucDelayTimeOfDisconnect; +#if CFG_KEY_ERROR_STATISTIC_RECOVERY + s32 u4BmcKeyErrorTh; +#endif +} WIFI_VAR_T, *P_WIFI_VAR_T; /* end of _WIFI_VAR_T */ + +/* cnm_timer module */ +typedef struct { + LINK_T rLinkHead; + u32 rNextExpiredSysTime; + u8 fgWakeLocked; +} ROOT_TIMER, *P_ROOT_TIMER; + +/* FW/DRV/NVRAM version information */ +typedef struct { + /* NVRAM or Registry */ + u16 u2Part1CfgOwnVersion; + u16 u2Part1CfgPeerVersion; + u16 u2Part2CfgOwnVersion; + u16 u2Part2CfgPeerVersion; + + /* Firmware */ + /* N9 SW */ + u16 u2FwProductID; + u16 u2FwOwnVersion; + u16 u2FwPeerVersion; + u8 ucFwBuildNumber; + u8 aucFwBranchInfo[4]; + u8 aucFwDateCode[16]; + + /* N9 tailer */ + tailer_format_t rN9tailer; + + /* CR4 tailer */ + tailer_format_t rCR4tailer; +#if CFG_SUPPORT_COMPRESSION_FW_OPTION + /* N9 Compressed tailer */ + tailer_format_t_2 rN9Compressedtailer; + /* CR4 tailer */ + tailer_format_t_2 rCR4Compressedtailer; + u8 fgIsN9CompressedFW; + u8 fgIsCR4CompressedFW; +#endif + /* Patch header */ + PATCH_FORMAT_T rPatchHeader; + u8 fgPatchIsDlByDrv; +} WIFI_VER_INFO_T, *P_WIFI_VER_INFO_T; + +#if CFG_ENABLE_WIFI_DIRECT +/* + * p2p function pointer structure + */ + +typedef struct _P2P_FUNCTION_LINKER { + P2P_REMOVE prP2pRemove; + /* NIC_P2P_MEDIA_STATE_CHANGE prNicP2pMediaStateChange; + */ + /* SCAN_UPDATE_P2P_DEVICE_DESC prScanUpdateP2pDeviceDesc; */ + /* P2P_FSM_RUN_EVENT_RX_PROBE_RESPONSE_FRAME + * prP2pFsmRunEventRxProbeResponseFrame; */ + P2P_GENERATE_P2P_IE prP2pGenerateWSC_IEForBeacon; + /* P2P_CALCULATE_WSC_IE_LEN_FOR_PROBE_RSP + * prP2pCalculateWSC_IELenForProbeRsp; */ + /* P2P_GENERATE_WSC_IE_FOR_PROBE_RSP prP2pGenerateWSC_IEForProbeRsp; */ + /* SCAN_REMOVE_P2P_BSS_DESC prScanRemoveP2pBssDesc; + */ + /* P2P_HANDLE_SEC_CHECK_RSP prP2pHandleSecCheckRsp; + */ + P2P_NET_REGISTER prP2pNetRegister; + P2P_NET_UNREGISTER prP2pNetUnregister; + P2P_CALCULATE_P2P_IE_LEN + prP2pCalculateP2p_IELenForAssocReq; /* All IEs generated from + * supplicant. */ + P2P_GENERATE_P2P_IE + prP2pGenerateP2p_IEForAssocReq; /* All IEs generated from supplicant. */ +} P2P_FUNCTION_LINKER, *P_P2P_FUNCTION_LINKER; + +#endif + +typedef struct _WIFI_FEM_CFG_T { + /* WiFi FEM path */ + u16 u2WifiPath; + u16 u2Reserved; + /* Reserved */ + u32 au4Reserved[4]; +} WIFI_FEM_CFG_T, *P_WIFI_FEM_CFG_T; + +struct CSI_DATA_T { + u8 ucBw; + u8 bIsCck; + u16 u2DataCount; + s16 ac2IData[256]; + s16 ac2QData[256]; + u8 ucDbdcIdx; + u8 ucDataOutputted; /* bit 0: I data, bit 1: Q data. Set to 1 if it's + * ouputted */ +}; + +/* + * Major ADAPTER structure + * Major data structure for driver operation + */ +struct _ADAPTER_T { + struct chip_info *chip_info; + u8 ucRevID; + u8 fgIsReadRevID; + + u16 u2NicOpChnlNum; + + u8 fgIsEnableWMM; + u8 fgIsWmmAssoc; /* This flag is used to indicate that WMM is enable in + * current BSS */ + + u32 u4OsPacketFilter; /* packet filter used by OS */ + u8 fgAllMulicastFilter; /* mDNS filter used by OS */ + + P_BSS_INFO_T aprBssInfo[HW_BSSID_NUM + 1]; + P_BSS_INFO_T prAisBssInfo; + + u8 ucHwBssIdNum; + u8 ucWmmSetNum; + u8 ucWtblEntryNum; + u8 ucTxDefaultWlanIndex; + u8 ucP2PDevBssIdx; + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + u8 fgIsSupportCsumOffload; /* Does FW support Checksum Offload feature + */ + u32 u4CSUMFlags; +#endif + + ENUM_BAND_T aePreferBand[BSS_INFO_NUM]; + + /* ADAPTER flags */ + u32 u4Flags; + u32 u4HwFlags; + + u8 fgIsRadioOff; + + u8 fgIsEnterD3ReqIssued; + + u8 aucMacAddress[MAC_ADDR_LEN]; + + ENUM_PHY_TYPE_INDEX_T + eCurrentPhyType; /* Current selection basing on the set of Available PHY + * Types */ + + u32 u4CoalescingBufCachedSize; + u8 *pucCoalescingBufCached; + + /* Buffer for CMD_INFO_T, Mgt packet and mailbox message */ + BUF_INFO_T rMgtBufInfo; + BUF_INFO_T rMsgBufInfo; + u8 *pucMgtBufCached; + u32 u4MgtBufCachedSize; + u8 aucMsgBuf[MSG_BUFFER_SIZE]; +#if CFG_DBG_MGT_BUF + u32 u4MemAllocDynamicCount; /* Debug only */ + u32 u4MemFreeDynamicCount; /* Debug only */ +#endif + + STA_RECORD_T arStaRec[CFG_STA_REC_NUM]; + + /* Element for TX PATH */ + TX_CTRL_T rTxCtrl; + QUE_T rFreeCmdList; + CMD_INFO_T arHifCmdDesc[CFG_TX_MAX_CMD_PKT_NUM]; + + /* Element for RX PATH */ + RX_CTRL_T rRxCtrl; + + /* Timer for restarting RFB setup procedure */ + TIMER_T rPacketDelaySetupTimer; + + /* Buffer for Authentication Event */ + /* <Todo> Move to glue layer and refine the kal function */ + /* Reference to rsnGeneratePmkidIndication function at rsn.c */ + u8 aucIndicationEventBuffer[(CFG_MAX_PMKID_CACHE * 20) + 8]; + + u32 u4IntStatus; + + ENUM_ACPI_STATE_T rAcpiState; + + u8 fgIsIntEnable; + u8 fgIsIntEnableWithLPOwnSet; + + u8 fgIsFwOwn; + u8 fgWiFiInSleepyState; + + /* Set by callback to make sure WOW process done before system suspend + */ + u8 fgSetPfCapabilityDone; + u8 fgSetWowDone; + + u8 fgForceFwOwn; + + u32 rLastOwnFailedLogTime; + u32 u4OwnFailedCount; + u32 u4OwnFailedLogCount; + + u32 u4PwrCtrlBlockCnt; + + /* TX Direct related : BEGIN */ + u8 fgTxDirectInited; + +#define TX_DIRECT_CHECK_INTERVAL (1000 * HZ / USEC_PER_SEC) + struct timer_list rTxDirectSkbTimer; /* check if an empty MsduInfo is + * available */ + struct timer_list rTxDirectHifTimer; /* check if HIF port is ready to + * accept a new Msdu */ + + struct sk_buff_head rTxDirectSkbQueue; + QUE_T rTxDirectHifQueue[TX_PORT_NUM]; + + QUE_T rStaPsQueue[CFG_STA_REC_NUM]; + u32 u4StaPsBitmap; + QUE_T rBssAbsentQueue[HW_BSSID_NUM + 1]; + u32 u4BssAbsentBitmap; + /* TX Direct related : END */ + + QUE_T rPendingCmdQueue; + QUE_T rTxCmdQueue; + QUE_T rTxCmdDoneQueue; + QUE_T rWDevLockQueue; + +#if CFG_FIX_2_TX_PORT + QUE_T rTxP0Queue; + QUE_T rTxP1Queue; +#else + QUE_T rTxPQueue[TX_PORT_NUM]; +#endif + QUE_T rRxQueue; + QUE_T rTxDataDoneQueue; + + P_GLUE_INFO_T prGlueInfo; + + u8 ucCmdSeqNum; + u8 ucTxSeqNum; + u8 aucPidPool[WTBL_SIZE]; + + u8 fgUseWapi; + + /* RF Test flags */ + u8 fgTestMode; + u8 fgIcapMode; + + /* WLAN Info for DRIVER_CORE OID query */ + WLAN_INFO_T rWlanInfo; + +#if CFG_ENABLE_WIFI_DIRECT +#if CFG_SUPPORT_DBDC_TC6 + u8 u4P2pMode; +#endif + u8 fgIsP2PRegistered; + u8 p2p_scan_report_all_bss; /* flag to report all networks in p2p scan + */ + ENUM_NET_REG_STATE_T rP2PNetRegState; + ENUM_P2P_REG_STATE_T rP2PRegState; + /* u8 fgIsWlanLaunched; */ + P_P2P_INFO_T prP2pInfo; +#if CFG_SUPPORT_P2P_RSSI_QUERY + u32 rP2pLinkQualityUpdateTime; + u8 fgIsP2pLinkQualityValid; + EVENT_LINK_QUALITY rP2pLinkQuality; +#endif +#endif + + /* Online Scan Option */ + u8 fgEnOnlineScan; + + /* Online Scan Option */ + u8 fgDisBcnLostDetection; + + /* MAC address */ + PARAM_MAC_ADDRESS rMyMacAddr; + + /* Wake-up Event for WOL */ + u32 u4WakeupEventEnable; + + /* Event Buffering */ + EVENT_STATISTICS rStatStruct; + u32 rStatUpdateTime; + u8 fgIsStatValid; + +#if CFG_SUPPORT_MSP + EVENT_WLAN_INFO rEventWlanInfo; +#endif + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO + TIMER_T rRxMcsInfoTimer; + u8 fgIsMcsInfoValid; +#endif + + EVENT_LINK_QUALITY rLinkQuality; + u32 rLinkQualityUpdateTime; + u8 fgIsLinkQualityValid; + u32 rLinkRateUpdateTime; + u8 fgIsLinkRateValid; + + /* WIFI_VAR_T */ + WIFI_VAR_T rWifiVar; + + /* MTK WLAN NIC driver IEEE 802.11 MIB */ + IEEE_802_11_MIB_T rMib; + + /* Mailboxs for inter-module communication */ + MBOX_T arMbox[MBOX_ID_TOTAL_NUM]; + + /* Timers for OID Pending Handling */ + TIMER_T rOidTimeoutTimer; + u8 ucOidTimeoutCount; + + /* Root Timer for cnm_timer module */ + ROOT_TIMER rRootTimer; + + u8 fgIsChipNoAck; + u8 fgIsChipAssert; + + /* RLM maintenance */ + ENUM_CHNL_EXT_T eRfSco; + ENUM_SYS_PROTECT_MODE_T eSysProtectMode; + ENUM_GF_MODE_T eSysHtGfMode; + ENUM_RIFS_MODE_T eSysTxRifsMode; + ENUM_SYS_PCO_PHASE_T eSysPcoPhase; + + P_DOMAIN_INFO_ENTRY prDomainInfo; + + /* QM */ + QUE_MGT_T rQM; + + CNM_INFO_T rCnmInfo; + + u32 u4PowerMode; + + u32 u4CtiaPowerMode; + u8 fgEnCtiaPowerMode; + + /* Bitmap is defined as #define KEEP_FULL_PWR_{FEATURE}_BIT in + * wlan_lib.h Each feature controls KeepFullPwr(CMD_ID_KEEP_FULL_PWR) + * should register bitmap to ensure low power during suspend. + */ + u32 u4IsKeepFullPwrBitmap; + + u32 fgEnArpFilter; + + u32 u4UapsdAcBmp; + + u32 u4MaxSpLen; + + u32 u4PsCurrentMeasureEn; + + /* Version Information */ + WIFI_VER_INFO_T rVerInfo; + + /* 5GHz support (from F/W) */ + u8 fgIsHw5GBandDisabled; + u8 fgEnable5GBand; + u8 fgIsEepromUsed; + u8 fgIsEfuseValid; + u8 fgIsEmbbededMacAddrValid; + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + u8 fgIsPowerLimitTableValid; +#endif + + /* Packet Forwarding Tracking */ + s32 i4PendingFwdFrameCount; + +#if CFG_SUPPORT_RDD_TEST_MODE + u8 ucRddStatus; +#endif + + u8 fgDisStaAgingTimeoutDetection; + + u32 u4FwCompileFlag0; + u32 u4FwCompileFlag1; + u32 u4FwFeatureFlag0; + u32 u4FwFeatureFlag1; + +#if CFG_SUPPORT_CFG_FILE + P_WLAN_CFG_T prWlanCfg; + WLAN_CFG_T rWlanCfg; + + P_WLAN_CFG_REC_T prWlanCfgRec; + WLAN_CFG_REC_T rWlanCfgRec; +#endif + +#if CFG_ASSERT_DUMP + TIMER_T rN9CorDumpTimer; + TIMER_T rCr4CorDumpTimer; + u8 fgN9CorDumpFileOpend; + u8 fgCr4CorDumpFileOpend; + u8 fgN9AssertDumpOngoing; + u8 fgCr4AssertDumpOngoing; + u8 fgKeepPrintCoreDump; +#endif + /* Tx resource information */ + u8 fgIsNicTxReousrceValid; + NIC_TX_RESOURCE_T nicTxReousrce; + + /* Efuse Start and End address */ + u32 u4EfuseStartAddress; + u32 u4EfuseEndAddress; + + /* COEX feature */ + u32 u4FddMode; + +#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1) + /* MAC address Efuse Offset */ + u32 u4EfuseMacAddrOffset; +#endif + +#if CFG_WOW_SUPPORT + WOW_CTRL_T rWowCtrl; +#endif + u8 fgIsCfg80211SuspendCalled; + + /*#if (CFG_EEPROM_PAGE_ACCESS == 1)*/ + u8 aucEepromVaule[16]; /* HQA CMD for Efuse Block size contents */ + u32 u4FreeBlockNum; + u32 u4GetTxPower; + /*#endif*/ + u8 fgIsCr4FwDownloaded; + u8 fgIsFwDownloaded; + /* u8 fgIsSupportBufferBinSize16Byte; */ + /* u8 fgIsSupportDelayCal; */ + /* u8 fgIsSupportGetFreeEfuseBlockCount; */ + /* u8 fgIsSupportQAAccessEfuse; */ + /* u8 fgIsSupportPowerOnSendBufferModeCMD; */ + u8 fgIsBufferBinExtract; + /* u8 fgIsSupportGetTxPower; */ + u8 fgIsEnableLpdvt; + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + u8 fgIsFixedMRate; + u8 ucDupMcastPacketNum; + u32 u4TXOPPeriod; + u8 fgIsMcastBurstMode; + u8 uc11mcSupportType; + u8 fgIsUcastBurstMode; + u8 ucUnicastBurstTimeout; // the default time is 10 ms + /* Specific AudioTos */ + u8 ucAudioTOS; +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK + u8 fgIsLookBackMode; + u16 ucRxLBList[5]; + u8 ucRxLBSize; + u8 ucRxLBIndex; +#endif +#endif + + /* SER related info */ + u8 ucSerState; + +#if CFG_SUPPORT_BFER + u8 fgIsHwSupportBfer; +#endif + +#if (CFG_HW_WMM_BY_BSS == 1) + u8 ucHwWmmEnBit; +#endif + WIFI_FEM_CFG_T rWifiFemCfg; + struct CSI_DATA_T rCsiData; + + ENUM_TX_RESULT_CODE_T r1xTxDoneStatus; + + u8 fgIsTest1xTx; +}; /* end of _ADAPTER_T */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/* TODO */ +#define SUSPEND_FLAG_FOR_WAKEUP_REASON (0) +#define SUSPEND_FLAG_CLEAR_WHEN_RESUME (1) + +/* Macros for argument _BssIndex */ +#define IS_NET_ACTIVE(_prAdapter, _BssIndex) \ + ((_prAdapter)->aprBssInfo[(_BssIndex)]->fgIsNetActive) + +/* Macros for argument _prBssInfo */ +#define IS_BSS_ACTIVE(_prBssInfo) ((_prBssInfo)->fgIsNetActive) + +#define IS_BSS_AIS(_prBssInfo) ((_prBssInfo)->eNetworkType == \ + NETWORK_TYPE_AIS) + +#define IS_BSS_P2P(_prBssInfo) ((_prBssInfo)->eNetworkType == \ + NETWORK_TYPE_P2P) + +#define IS_BSS_BOW(_prBssInfo) ((_prBssInfo)->eNetworkType == \ + NETWORK_TYPE_BOW) + +#define IS_BSS_APGO(_prBssInfo) \ + (IS_BSS_P2P(_prBssInfo) && \ + (_prBssInfo)->eCurrentOPMode == OP_MODE_ACCESS_POINT) + +#define SET_NET_ACTIVE(_prAdapter, _BssIndex) \ + { \ + (_prAdapter)->aprBssInfo[(_BssIndex)]->fgIsNetActive = true; \ + } + +#define UNSET_NET_ACTIVE(_prAdapter, _BssIndex) \ + { \ + (_prAdapter)->aprBssInfo[(_BssIndex)]->fgIsNetActive = false; \ + } + +#define BSS_INFO_INIT(_prAdapter, _prBssInfo) \ + { \ + u8 _aucZeroMacAddr[] = NULL_MAC_ADDR; \ + \ + (_prBssInfo)->eConnectionState = \ + PARAM_MEDIA_STATE_DISCONNECTED; \ + (_prBssInfo)->eConnectionStateIndicated = \ + PARAM_MEDIA_STATE_DISCONNECTED; \ + (_prBssInfo)->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; \ + (_prBssInfo)->ucReasonOfDisconnect = \ + DISCONNECT_REASON_CODE_RESERVED; \ + COPY_MAC_ADDR((_prBssInfo)->aucBSSID, _aucZeroMacAddr); \ + LINK_INITIALIZE(&((_prBssInfo)->rStaRecOfClientList)); \ + (_prBssInfo)->fgIsBeaconActivated = false; \ + (_prBssInfo)->u2HwDefaultFixedRateCode = RATE_CCK_1M_LONG; \ + (_prBssInfo)->ePowerModeFromUser = Param_PowerModeFast_PSP; \ + } + +/*----------------------------------------------------------------------------*/ +/* Macros for Power State */ +/*----------------------------------------------------------------------------*/ +#define SET_NET_PWR_STATE_IDLE(_prAdapter, _BssIndex) \ + { \ + _prAdapter->rWifiVar.aePwrState[(_BssIndex)] = PWR_STATE_IDLE; \ + } + +#define SET_NET_PWR_STATE_ACTIVE(_prAdapter, _BssIndex) \ + { \ + _prAdapter->rWifiVar.aePwrState[(_BssIndex)] = \ + PWR_STATE_ACTIVE; \ + } + +#define SET_NET_PWR_STATE_PS(_prAdapter, _BssIndex) \ + { \ + _prAdapter->rWifiVar.aePwrState[(_BssIndex)] = PWR_STATE_PS; \ + } + +#define IS_NET_PWR_STATE_ACTIVE(_prAdapter, _BssIndex) \ + (_prAdapter->rWifiVar.aePwrState[(_BssIndex)] == PWR_STATE_ACTIVE) + +#define IS_NET_PWR_STATE_IDLE(_prAdapter, _BssIndex) \ + (_prAdapter->rWifiVar.aePwrState[(_BssIndex)] == PWR_STATE_IDLE) + +#define IS_SCN_PWR_STATE_ACTIVE(_prAdapter) \ + (_prAdapter->rWifiVar.rScanInfo.eScanPwrState == SCAN_PWR_STATE_ACTIVE) + +#define IS_SCN_PWR_STATE_IDLE(_prAdapter) \ + (_prAdapter->rWifiVar.rScanInfo.eScanPwrState == SCAN_PWR_STATE_IDLE) + +#define IS_WIFI_2G4_WF0_SUPPORT(_prAdapter) \ + ((_prAdapter)->rWifiFemCfg.u2WifiPath & WLAN_FLAG_2G4_WF0) + +#define IS_WIFI_5G_WF0_SUPPORT(_prAdapter) \ + ((_prAdapter)->rWifiFemCfg.u2WifiPath & WLAN_FLAG_5G_WF0) + +#define IS_WIFI_2G4_WF1_SUPPORT(_prAdapter) \ + ((_prAdapter)->rWifiFemCfg.u2WifiPath & WLAN_FLAG_2G4_WF1) + +#define IS_WIFI_5G_WF1_SUPPORT(_prAdapter) \ + ((_prAdapter)->rWifiFemCfg.u2WifiPath & WLAN_FLAG_5G_WF1) + +#define IS_WIFI_2G4_SISO(_prAdapter) \ + ((IS_WIFI_2G4_WF0_SUPPORT(_prAdapter) && \ + !(IS_WIFI_2G4_WF1_SUPPORT(_prAdapter))) || \ + (IS_WIFI_2G4_WF1_SUPPORT(_prAdapter) && \ + !(IS_WIFI_2G4_WF0_SUPPORT(_prAdapter)))) + +#define IS_WIFI_5G_SISO(_prAdapter) \ + ((IS_WIFI_5G_WF0_SUPPORT(_prAdapter) && \ + !(IS_WIFI_5G_WF1_SUPPORT(_prAdapter))) || \ + (IS_WIFI_5G_WF1_SUPPORT(_prAdapter) && \ + !(IS_WIFI_5G_WF0_SUPPORT(_prAdapter)))) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/cmd_buf.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/cmd_buf.h new file mode 100644 index 00000000000000..cb351ce0f12e2a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/cmd_buf.h @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "cmd_buf.h" + * \brief In this file we define the structure for Command Packet. + * + * In this file we define the structure for Command Packet and the control unit + * of MGMT Memory Pool. + */ + +#ifndef _CMD_BUF_H +#define _CMD_BUF_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef enum _COMMAND_TYPE { + COMMAND_TYPE_GENERAL_IOCTL, + COMMAND_TYPE_NETWORK_IOCTL, + COMMAND_TYPE_SECURITY_FRAME, + COMMAND_TYPE_MANAGEMENT_FRAME, + COMMAND_TYPE_NUM +} COMMAND_TYPE, +*P_COMMAND_TYPE; + +typedef void (*PFN_CMD_DONE_HANDLER)(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +typedef void (*PFN_CMD_TIMEOUT_HANDLER)(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo); + +typedef void (*PFN_HIF_TX_CMD_DONE_CB)(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo); + +struct _CMD_INFO_T { + QUE_ENTRY_T rQueEntry; + + COMMAND_TYPE eCmdType; + + u16 u2InfoBufLen; /* This is actual CMD buffer length */ + u8 *pucInfoBuffer; /* May pointer to structure in prAdapter */ + P_MSDU_INFO_T prMsduInfo; /* only valid when it's a security/MGMT frame + */ + P_NATIVE_PACKET prPacket; /* only valid when it's a security frame */ + + PFN_CMD_DONE_HANDLER pfCmdDoneHandler; + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler; + PFN_HIF_TX_CMD_DONE_CB pfHifTxCmdDoneCb; + + u8 fgIsOid; /* Used to check if we need indicate */ + + u8 ucCID; + u8 fgSetQuery; + u8 fgNeedResp; + u8 ucCmdSeqNum; + u32 u4SetInfoLen; /* Indicate how many byte we read for Set OID */ + + /* information indicating by OID/ioctl */ + void *pvInformationBuffer; + u32 u4InformationBufferLength; + + /* private data */ + u32 u4PrivateData; + + /* TXD/TXP pointer/len for hif tx copy */ + u32 u4TxdLen; + u32 u4TxpLen; + u8 *pucTxd; + u8 *pucTxp; +}; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void cmdBufInitialize(IN P_ADAPTER_T prAdapter); + +P_CMD_INFO_T cmdBufAllocateCmdInfo(IN P_ADAPTER_T prAdapter, IN u32 u4Length); + +void cmdBufFreeCmdInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); + +/*----------------------------------------------------------------------------*/ +/* Routines for CMDs */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanSendSetQueryCmd(IN P_ADAPTER_T prAdapter, + u8 ucCID, + u8 fgSetQuery, + u8 fgNeedResp, + u8 fgIsOid, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + u32 u4SetQueryInfoLen, + u8 *pucInfoBuffer, + OUT void *pvSetQueryBuffer, + IN u32 u4SetQueryBufferLen); + +#if CFG_SUPPORT_TX_BF +WLAN_STATUS +wlanSendSetQueryExtCmd(IN P_ADAPTER_T prAdapter, + u8 ucCID, + u8 ucExtCID, + u8 fgSetQuery, + u8 fgNeedResp, + u8 fgIsOid, + PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + u32 u4SetQueryInfoLen, + u8 *pucInfoBuffer, + OUT void *pvSetQueryBuffer, + IN u32 u4SetQueryBufferLen); +#endif + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/hal.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/hal.h new file mode 100644 index 00000000000000..ae46c29209d775 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/hal.h @@ -0,0 +1,645 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "hal.h" + * \brief The declaration of hal functions + * + * N/A + */ + +#ifndef _HAL_H +#define _HAL_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/* Macros for flag operations for the Adapter structure */ +#define HAL_SET_FLAG(_M, _F) ((_M)->u4HwFlags |= (_F)) +#define HAL_CLEAR_FLAG(_M, _F) ((_M)->u4HwFlags &= ~(_F)) +#define HAL_TEST_FLAG(_M, _F) ((_M)->u4HwFlags & (_F)) +#define HAL_TEST_FLAGS(_M, _F) (((_M)->u4HwFlags & (_F)) == (_F)) + +#define HAL_MCR_RD(_prAdapter, _u4Offset, _pu4Value) \ + do { \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == false) { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (_u4Offset > 0xFFFF) { \ + if (kalDevRegRead_mac(_prAdapter->prGlueInfo, \ + _u4Offset, \ + _pu4Value) == false) { \ + HAL_SET_FLAG(_prAdapter, \ + ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = true; \ + DBGLOG(HAL, \ + ERROR, \ + "HAL_MCR_RD (MAC) access fail! 0x%lx: 0x%lx\n", \ + (u32)(_u4Offset), \ + *((u32 *)(_pu4Value))); \ + } \ + } else { \ + if (kalDevRegRead(_prAdapter->prGlueInfo, \ + _u4Offset, \ + _pu4Value) == false) { \ + HAL_SET_FLAG(_prAdapter, \ + ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = true; \ + DBGLOG(HAL, \ + ERROR, \ + "HAL_MCR_RD (SDIO) access fail! 0x%lx: 0x%lx\n", \ + (u32)(_u4Offset), \ + *((u32 *)(_pu4Value))); \ + } \ + } \ + } else { \ + DBGLOG(HAL, WARN, "ignore HAL_MCR_RD access! 0x%lx\n", \ + (u32)(_u4Offset)); \ + } \ + } while (0) + +#define HAL_MCR_WR(_prAdapter, _u4Offset, _u4Value) \ + do { \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == false) { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (_u4Offset > 0xFFFF) { \ + if (kalDevRegWrite_mac(_prAdapter->prGlueInfo, \ + _u4Offset, \ + _u4Value) == false) { \ + HAL_SET_FLAG(_prAdapter, \ + ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = true; \ + DBGLOG(HAL, \ + ERROR, \ + "HAL_MCR_WR (MAC) access fail! 0x%lx: 0x%lx\n", \ + (u32)(_u4Offset), \ + (u32)(_u4Value)); \ + } \ + } else { \ + if (kalDevRegWrite(_prAdapter->prGlueInfo, \ + _u4Offset, \ + _u4Value) == false) { \ + HAL_SET_FLAG(_prAdapter, \ + ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = true; \ + DBGLOG(HAL, \ + ERROR, \ + "HAL_MCR_WR (SDIO) access fail! 0x%lx: 0x%lx\n", \ + (u32)(_u4Offset), \ + (u32)(_u4Value)); \ + } \ + } \ + } else { \ + DBGLOG(HAL, WARN, \ + "ignore HAL_MCR_WR access! 0x%lx: 0x%lx\n", \ + (u32)(_u4Offset), (u32)(_u4Value)); \ + } \ + } while (0) + +#define HAL_PORT_RD(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ + { \ + /*fgResult = false; */ \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == false) { \ + if (kalDevPortRead(_prAdapter->prGlueInfo, _u4Port, \ + _u4Len, _pucBuf, \ + _u4ValidBufSize) == false) { \ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = true; \ + DBGLOG(HAL, ERROR, \ + "HAL_PORT_RD access fail! 0x%lx\n", \ + (u32)(_u4Port)); \ + } else { \ + /*fgResult = true;*/ } \ + } else { \ + DBGLOG(HAL, WARN, \ + "ignore HAL_PORT_RD access! 0x%lx\n", \ + (u32)(_u4Port)); \ + } \ + } + +#define HAL_PORT_WR(_prAdapter, _u4Port, _u4Len, _pucBuf, _u4ValidBufSize) \ + { \ + /*fgResult = false; */ \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == false) { \ + if (kalDevPortWrite(_prAdapter->prGlueInfo, _u4Port, \ + _u4Len, _pucBuf, \ + _u4ValidBufSize) == false) { \ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = true; \ + DBGLOG(HAL, ERROR, \ + "HAL_PORT_WR access fail! 0x%lx\n", \ + (u32)(_u4Port)); \ + } \ + } else { \ + DBGLOG(HAL, WARN, \ + "ignore HAL_PORT_WR access! 0x%lx\n", \ + (u32)(_u4Port)); \ + } \ + } + +#define HAL_BYTE_WR(_prAdapter, _u4Port, _ucBuf) \ + { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == false) { \ + if (kalDevWriteWithSdioCmd52(_prAdapter->prGlueInfo, \ + _u4Port, \ + _ucBuf) == false) { \ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = true; \ + DBGLOG(HAL, ERROR, \ + "HAL_BYTE_WR access fail! 0x%lx\n", \ + (u32)(_u4Port)); \ + } else { \ + /* Todo:: Nothing*/ \ + } \ + } else { \ + DBGLOG(HAL, WARN, \ + "ignore HAL_BYTE_WR access! 0x%lx\n", \ + (u32)(_u4Port)); \ + } \ + } + +#define HAL_DRIVER_OWN_BY_SDIO_CMD52(_prAdapter, _pfgDriverIsOwnReady) \ + { \ + u8 ucBuf = BIT(1); \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + if (HAL_TEST_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR) == false) { \ + if (kalDevReadAfterWriteWithSdioCmd52( \ + _prAdapter->prGlueInfo, MCR_WHLPCR_BYTE1, \ + &ucBuf, 1) == false) { \ + HAL_SET_FLAG(_prAdapter, ADAPTER_FLAG_HW_ERR); \ + fgIsBusAccessFailed = true; \ + DBGLOG(HAL, \ + ERROR, \ + "kalDevReadAfterWriteWithSdioCmd52 access fail!\n"); \ + } else { \ + *_pfgDriverIsOwnReady = \ + (ucBuf & BIT(0)) ? true : false; \ + } \ + } else { \ + DBGLOG(HAL, WARN, \ + "ignore HAL_DRIVER_OWN_BY_SDIO_CMD52 access!\n"); \ + } \ + } + +#define HAL_WRITE_TX_DATA(_prAdapter, _prMsduInfo) \ + { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + kalDevWriteData(_prAdapter->prGlueInfo, _prMsduInfo); \ + } + +#define HAL_KICK_TX_DATA(_prAdapter) \ + { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + kalDevKickData(_prAdapter->prGlueInfo); \ + } + +#if CFG_MESON_G12A_PATCH +#define HAL_WRITE_TX_CMD(_prAdapter, _prCmdInfo, _ucTC) \ + ({ \ + u32 retval; \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + retval = kalDevWriteCmd(_prAdapter->prGlueInfo, _prCmdInfo, \ + _ucTC); \ + retval; \ + }) +#else +#define HAL_WRITE_TX_CMD(_prAdapter, _prCmdInfo, _ucTC) \ + { \ + if (_prAdapter->rAcpiState == ACPI_STATE_D3) { \ + ASSERT(0); \ + } \ + kalDevWriteCmd(_prAdapter->prGlueInfo, _prCmdInfo, _ucTC); \ + } +#endif + +#define HIF_H2D_SW_INT_SHFT (16) +#define SDIO_MAILBOX_FUNC_READ_REG_IDX \ + (BIT(0) << HIF_H2D_SW_INT_SHFT) /* bit16 */ +#define SDIO_MAILBOX_FUNC_WRITE_REG_IDX \ + (BIT(1) << HIF_H2D_SW_INT_SHFT) /* bit17 */ +#define SDIO_MAILBOX_FUNC_CHECKSUN16_IDX \ + (BIT(2) << HIF_H2D_SW_INT_SHFT) /* bit18 */ + +#define HAL_READ_RX_PORT(prAdapter, u4PortId, u4Len, pvBuf, _u4ValidBufSize) \ + { \ + ASSERT(u4PortId < 2); \ + HAL_PORT_RD(prAdapter, \ + ((u4PortId == 0) ? MCR_WRDR0 : MCR_WRDR1), u4Len, \ + pvBuf, _u4ValidBufSize /*temp!!*/ /*4Kbyte*/ ) \ + } + +#define HAL_WRITE_TX_PORT(_prAdapter, _u4PortId, _u4Len, _pucBuf, \ + _u4ValidBufSize) \ + { \ + if ((_u4ValidBufSize - _u4Len) >= sizeof(u32)) { \ + /* fill with single dword of zero as TX-aggregation \ + * termination */ \ + *(u32 *)(&((_pucBuf)[ALIGN_4(_u4Len)])) = 0; \ + } \ + HAL_PORT_WR(_prAdapter, MCR_WTDR1, _u4Len, _pucBuf, \ + _u4ValidBufSize /*temp!!*/ /*4KByte*/ ) \ + } + +/* The macro to read the given MCR several times to check if the wait + * condition come true. + */ +#define HAL_MCR_RD_AND_WAIT(_pAdapter, _offset, _pReadValue, _waitCondition, \ + _waitDelay, _waitCount, _status) \ + { \ + u32 count; \ + (_status) = false; \ + for (count = 0; count < (_waitCount); count++) { \ + HAL_MCR_RD((_pAdapter), (_offset), (_pReadValue)); \ + if ((_waitCondition)) { \ + (_status) = true; \ + break; \ + } \ + kalUdelay((_waitDelay)); \ + } \ + } + +/* The macro to write 1 to a R/S bit and read it several times to check if the + * command is done + */ +#define HAL_MCR_WR_AND_WAIT(_pAdapter, _offset, _writeValue, _busyMask, \ + _waitDelay, _waitCount, _status) \ + { \ + u32 u4Temp; \ + u32 u4Count = _waitCount; \ + (_status) = false; \ + HAL_MCR_WR((_pAdapter), (_offset), (_writeValue)); \ + do { \ + kalUdelay((_waitDelay)); \ + HAL_MCR_RD((_pAdapter), (_offset), &u4Temp); \ + if (!(u4Temp & (_busyMask))) { \ + (_status) = true; \ + break; \ + } \ + u4Count--; \ + } while (u4Count); \ + } + +#define HAL_GET_CHIP_ID_VER(_prAdapter, pu2ChipId, pu2Version) \ + { \ + u32 u4Value; \ + HAL_MCR_RD(_prAdapter, MCR_WCIR, &u4Value); \ + *pu2ChipId = (u16)(u4Value & WCIR_CHIP_ID); \ + *pu2Version = (u16)(u4Value & WCIR_REVISION_ID) >> 16; \ + } + +#define HAL_WIFI_FUNC_READY_CHECK(_prAdapter, _checkItem, _pfgResult) \ + do { \ + u32 u4Value; \ + *_pfgResult = false; \ + HAL_MCR_RD(_prAdapter, MCR_WCIR, &u4Value); \ + if (u4Value & WCIR_WLAN_READY) { \ + *_pfgResult = true; \ + } \ + } while (0) + +#define HAL_WIFI_FUNC_OFF_CHECK(_prAdapter, _checkItem, _pfgResult) \ + do { \ + u32 u4Value; \ + *_pfgResult = false; \ + HAL_MCR_RD(_prAdapter, MCR_WCIR, &u4Value); \ + if ((u4Value & WCIR_WLAN_READY) == 0) { \ + *_pfgResult = true; \ + } \ + halPrintMailbox(prAdapter); \ + halPollDbgCr(_prAdapter, LP_DBGCR_POLL_ROUND); \ + } while (0) + +#define HAL_WIFI_FUNC_GET_STATUS(_prAdapter, _u4Result) \ + halGetMailbox(_prAdapter, 0, &_u4Result) + +#define HAL_INTR_DISABLE(_prAdapter) \ + HAL_MCR_WR(_prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_CLR) + +#define HAL_INTR_ENABLE(_prAdapter) \ + HAL_MCR_WR(_prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_SET) + +#define HAL_INTR_ENABLE_AND_LP_OWN_SET(_prAdapter) \ + HAL_MCR_WR(_prAdapter, MCR_WHLPCR, \ + (WHLPCR_INT_EN_SET | WHLPCR_FW_OWN_REQ_SET)) + +#define HAL_LP_OWN_RD(_prAdapter, _pfgResult) \ + { \ + u32 u4RegValue; \ + *_pfgResult = false; \ + HAL_MCR_RD(_prAdapter, MCR_WHLPCR, &u4RegValue); \ + if (u4RegValue & WHLPCR_IS_DRIVER_OWN) { \ + *_pfgResult = true; \ + } \ + } + +#define HAL_LP_OWN_SET(_prAdapter, _pfgResult) \ + { \ + u32 u4RegValue; \ + *_pfgResult = false; \ + HAL_MCR_WR(_prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET); \ + HAL_MCR_RD(_prAdapter, MCR_WHLPCR, &u4RegValue); \ + if (u4RegValue & WHLPCR_IS_DRIVER_OWN) { \ + *_pfgResult = true; \ + } \ + } + +#define HAL_LP_OWN_CLR(_prAdapter, _pfgResult) \ + { \ + u32 u4RegValue; \ + *_pfgResult = false; \ + /* Software get LP ownership */ \ + HAL_MCR_WR(_prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR); \ + HAL_MCR_RD(_prAdapter, MCR_WHLPCR, &u4RegValue); \ + if (u4RegValue & WHLPCR_IS_DRIVER_OWN) { \ + *_pfgResult = true; \ + } \ + } + +#define HAL_GET_ABNORMAL_INTERRUPT_REASON_CODE(_prAdapter, pu4AbnormalReason) \ + { \ + HAL_MCR_RD(_prAdapter, MCR_WASR, pu4AbnormalReason); \ + } + +#define HAL_DISABLE_RX_ENHANCE_MODE(_prAdapter) \ + { \ + u32 u4Value; \ + HAL_MCR_RD(_prAdapter, MCR_WHCR, &u4Value); \ + HAL_MCR_WR(_prAdapter, MCR_WHCR, \ + u4Value & ~WHCR_RX_ENHANCE_MODE_EN); \ + } + +#define HAL_ENABLE_RX_ENHANCE_MODE(_prAdapter) \ + { \ + u32 u4Value; \ + HAL_MCR_RD(_prAdapter, MCR_WHCR, &u4Value); \ + HAL_MCR_WR(_prAdapter, MCR_WHCR, \ + u4Value | WHCR_RX_ENHANCE_MODE_EN); \ + } + +#define HAL_CFG_MAX_HIF_RX_LEN_NUM(_prAdapter, _ucNumOfRxLen) \ + { \ + u32 u4Value, ucNum; \ + ucNum = ((_ucNumOfRxLen >= 16) ? 0 : _ucNumOfRxLen); \ + u4Value = 0; \ + HAL_MCR_RD(_prAdapter, MCR_WHCR, &u4Value); \ + u4Value &= ~WHCR_MAX_HIF_RX_LEN_NUM; \ + u4Value |= ((((u32)ucNum) << WHCR_OFFSET_MAX_HIF_RX_LEN_NUM) & \ + WHCR_MAX_HIF_RX_LEN_NUM); \ + HAL_MCR_WR(_prAdapter, MCR_WHCR, u4Value); \ + } + +#define HAL_SET_INTR_STATUS_READ_CLEAR(prAdapter) \ + { \ + u32 u4Value; \ + HAL_MCR_RD(prAdapter, MCR_WHCR, &u4Value); \ + HAL_MCR_WR(prAdapter, MCR_WHCR, \ + u4Value & ~WHCR_W_INT_CLR_CTRL); \ + prAdapter->prGlueInfo->rHifInfo.fgIntReadClear = true; \ + } + +#define HAL_SET_INTR_STATUS_WRITE_1_CLEAR(prAdapter) \ + { \ + u32 u4Value; \ + HAL_MCR_RD(prAdapter, MCR_WHCR, &u4Value); \ + HAL_MCR_WR(prAdapter, MCR_WHCR, \ + u4Value | WHCR_W_INT_CLR_CTRL); \ + prAdapter->prGlueInfo->rHifInfo.fgIntReadClear = false; \ + } + +/* Note: enhance mode structure may also carried inside the buffer, + * if the length of the buffer is long enough + */ +#define HAL_READ_INTR_STATUS(prAdapter, length, pvBuf) \ + HAL_PORT_RD(prAdapter, MCR_WHISR, length, pvBuf, length) + +#define HAL_READ_TX_RELEASED_COUNT(_prAdapter, au2TxReleaseCount) \ + { \ + u32 *pu4Value = (u32 *)au2TxReleaseCount; \ + HAL_MCR_RD(_prAdapter, MCR_WTQCR0, &pu4Value[0]); \ + HAL_MCR_RD(_prAdapter, MCR_WTQCR1, &pu4Value[1]); \ + HAL_MCR_RD(_prAdapter, MCR_WTQCR2, &pu4Value[2]); \ + HAL_MCR_RD(_prAdapter, MCR_WTQCR3, &pu4Value[3]); \ + HAL_MCR_RD(_prAdapter, MCR_WTQCR4, &pu4Value[4]); \ + HAL_MCR_RD(_prAdapter, MCR_WTQCR5, &pu4Value[5]); \ + HAL_MCR_RD(_prAdapter, MCR_WTQCR6, &pu4Value[6]); \ + HAL_MCR_RD(_prAdapter, MCR_WTQCR7, &pu4Value[7]); \ + } + +#define HAL_READ_RX_LENGTH(prAdapter, pu2Rx0Len, pu2Rx1Len) \ + { \ + u32 u4Value; \ + u4Value = 0; \ + HAL_MCR_RD(prAdapter, MCR_WRPLR, &u4Value); \ + *pu2Rx0Len = (u16)u4Value; \ + *pu2Rx1Len = (u16)(u4Value >> 16); \ + } + +#define HAL_GET_INTR_STATUS_FROM_ENHANCE_MODE_STRUCT(pvBuf, u2Len, pu4Status) \ + { \ + u32 *pu4Buf = (u32 *)pvBuf; \ + *pu4Status = pu4Buf[0]; \ + } + +#define HAL_GET_TX_STATUS_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu4BufOut, \ + u4LenBufOut) \ + { \ + u32 *pu4Buf = (u32 *)pvInBuf; \ + ASSERT(u4LenBufOut >= 8); \ + pu4BufOut[0] = pu4Buf[1]; \ + pu4BufOut[1] = pu4Buf[2]; \ + } + +#define HAL_GET_RX_LENGTH_FROM_ENHANCE_MODE_STRUCT( \ + pvInBuf, pu2Rx0Num, au2Rx0Len, pu2Rx1Num, au2Rx1Len) \ + { \ + u32 *pu4Buf = (u32 *)pvInBuf; \ + ASSERT((sizeof(au2Rx0Len) / sizeof(u16)) >= 16); \ + ASSERT((sizeof(au2Rx1Len) / sizeof(u16)) >= 16); \ + *pu2Rx0Num = (u16)pu4Buf[3]; \ + *pu2Rx1Num = (u16)(pu4Buf[3] >> 16); \ + kalMemCopy(au2Rx0Len, &pu4Buf[4], 8); \ + kalMemCopy(au2Rx1Len, &pu4Buf[12], 8); \ + } + +#define HAL_GET_MAILBOX_FROM_ENHANCE_MODE_STRUCT(pvInBuf, pu4Mailbox0, \ + pu4Mailbox1) \ + { \ + u32 *pu4Buf = (u32 *)pvInBuf; \ + *pu4Mailbox0 = (u16)pu4Buf[21]; \ + *pu4Mailbox1 = (u16)pu4Buf[22]; \ + } + +#define HAL_IS_TX_DONE_INTR(u4IntrStatus) \ + ((u4IntrStatus & WHISR_TX_DONE_INT) ? true : false) + +#define HAL_IS_RX_DONE_INTR(u4IntrStatus) \ + ((u4IntrStatus & (WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT)) ? true : \ + false) + +#define HAL_IS_ABNORMAL_INTR(u4IntrStatus) \ + ((u4IntrStatus & WHISR_ABNORMAL_INT) ? true : false) + +#define HAL_IS_FW_OWNBACK_INTR(u4IntrStatus) \ + ((u4IntrStatus & WHISR_FW_OWN_BACK_INT) ? true : false) + +#define HAL_PUT_MAILBOX(prAdapter, u4MboxId, u4Data) \ + { \ + ASSERT(u4MboxId < 2); \ + HAL_MCR_WR(prAdapter, \ + ((u4MboxId == 0) ? MCR_H2DSM0R : MCR_H2DSM1R), \ + u4Data); \ + } + +#define HAL_GET_MAILBOX(prAdapter, u4MboxId, pu4Data) \ + { \ + ASSERT(u4MboxId < 2); \ + HAL_MCR_RD(prAdapter, \ + ((u4MboxId == 0) ? MCR_D2HRM0R : MCR_D2HRM1R), \ + pu4Data); \ + } + +#define HAL_SET_MAILBOX_READ_CLEAR(prAdapter, fgEnableReadClear) \ + { \ + u32 u4Value; \ + HAL_MCR_RD(prAdapter, MCR_WHCR, &u4Value); \ + HAL_MCR_WR(prAdapter, MCR_WHCR, \ + (fgEnableReadClear) ? \ + (u4Value | WHCR_RECV_MAILBOX_RD_CLR_EN) : \ + (u4Value & ~WHCR_RECV_MAILBOX_RD_CLR_EN)); \ + prAdapter->prGlueInfo->rHifInfo.fgMbxReadClear = \ + fgEnableReadClear; \ + } + +#define HAL_GET_MAILBOX_READ_CLEAR(prAdapter) \ + (prAdapter->prGlueInfo->rHifInfo.fgMbxReadClear) + +#define HAL_READ_INT_STATUS(prAdapter, _pu4IntStatus) \ + { \ + kalDevReadIntStatus(prAdapter, _pu4IntStatus); \ + } + +#define HAL_HIF_INIT(_prAdapter) \ + { \ + halDevInit(_prAdapter); \ + } + +#define HAL_ENABLE_FWDL(_prAdapter, _fgEnable) + +#define HAL_WAKE_UP_WIFI(_prAdapter) \ + { \ + halWakeUpWiFi(_prAdapter); \ + } + +#define HAL_IS_TX_DIRECT(_prAdapter) false + +#define HAL_IS_RX_DIRECT(_prAdapter) false + +#define INVALID_VERSION 0xFFFF /* used by HW/FW version */ +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +u8 halVerifyChipID(IN P_ADAPTER_T prAdapter); +u32 halGetChipHwVer(IN P_ADAPTER_T prAdapter); +u32 halGetChipSwVer(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS halRxWaitResponse(IN P_ADAPTER_T prAdapter, + IN u8 ucPortIdx, + OUT u8 *pucRspBuffer, + IN u32 u4MaxRespBufferLen, + OUT u32 *pu4Length); + +void halEnableInterrupt(IN P_ADAPTER_T prAdapter); +void halDisableInterrupt(IN P_ADAPTER_T prAdapter); + +u8 halSetDriverOwn(IN P_ADAPTER_T prAdapter); +void halSetFWOwn(IN P_ADAPTER_T prAdapter, IN u8 fgEnableGlobalInt); + +void halDevInit(IN P_ADAPTER_T prAdapter); +void halEnableFWDownload(IN P_ADAPTER_T prAdapter, IN u8 fgEnable); +void halWakeUpWiFi(IN P_ADAPTER_T prAdapter); +void halTxCancelAllSending(IN P_ADAPTER_T prAdapter); +void halProcessTxInterrupt(IN P_ADAPTER_T prAdapter); +WLAN_STATUS halTxPollingResource(IN P_ADAPTER_T prAdapter, IN u8 ucTC); +void halSerHifReset(IN P_ADAPTER_T prAdapter); + +void halProcessRxInterrupt(IN P_ADAPTER_T prAdapter); +void halProcessSoftwareInterrupt(IN P_ADAPTER_T prAdapter); +/* Hif power off wifi */ +WLAN_STATUS halHifPowerOffWifi(IN P_ADAPTER_T prAdapter); +u32 halDumpHifStatus(IN P_ADAPTER_T prAdapter, IN u8 *pucBuf, IN u32 u4Max); +u8 halIsPendingRx(IN P_ADAPTER_T prAdapter); +u32 halGetValidCoalescingBufSize(IN P_ADAPTER_T prAdapter); +WLAN_STATUS halAllocateIOBuffer(IN P_ADAPTER_T prAdapter); +WLAN_STATUS halReleaseIOBuffer(IN P_ADAPTER_T prAdapter); +void halDeAggRxPktWorker(struct work_struct *work); +void halPrintHifDbgInfo(IN P_ADAPTER_T prAdapter); +u8 halIsTxResourceControlEn(IN P_ADAPTER_T prAdapter); +void halTxResourceResetHwTQCounter(IN P_ADAPTER_T prAdapter); + +void halWpdmaSetup(P_GLUE_INFO_T prGlueInfo, u8 enable); + +bool halIsHifStateReady(IN P_ADAPTER_T prAdapter, u8 *pucState); + +bool halIsHifStateSuspend(IN P_ADAPTER_T prAdapter); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/hif_rx.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/hif_rx.h new file mode 100644 index 00000000000000..9c35bfa5cfe56a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/hif_rx.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "hif_rx.h" + * \brief Provide HIF RX Header Information between F/W and Driver + * + * N/A + */ + +#ifndef _HIF_RX_H +#define _HIF_RX_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/*! HIF_RX_HEADER_T */ +/* DW 0, Byte 1 */ +#define HIF_RX_HDR_PACKET_TYPE_MASK BITS(0, 1) + +/* DW 1, Byte 0 */ +#define HIF_RX_HDR_HEADER_LEN BITS(2, 7) +#define HIF_RX_HDR_HEADER_LEN_OFFSET 2 +#define HIF_RX_HDR_HEADER_OFFSET_MASK BITS(0, 1) + +/* DW 1, Byte 1 */ +#define HIF_RX_HDR_80211_HEADER_FORMAT BIT(0) +#define HIF_RX_HDR_DO_REORDER BIT(1) +#define HIF_RX_HDR_PAL BIT(2) +#define HIF_RX_HDR_TCL BIT(3) +#define HIF_RX_HDR_NETWORK_IDX_MASK BITS(4, 7) +#define HIF_RX_HDR_NETWORK_IDX_OFFSET 4 + +/* DW 1, Byte 2, 3 */ +#define HIF_RX_HDR_SEQ_NO_MASK BITS(0, 11) +#define HIF_RX_HDR_TID_MASK BITS(12, 14) +#define HIF_RX_HDR_TID_OFFSET 12 +#define HIF_RX_HDR_BAR_FRAME BIT(15) + +#define HIF_RX_HDR_FLAG_AMP_WDS BIT(0) +#define HIF_RX_HDR_FLAG_802_11_FORMAT BIT(1) +#define HIF_RX_HDR_FLAG_BAR_FRAME BIT(2) +#define HIF_RX_HDR_FLAG_DO_REORDERING BIT(3) +#define HIF_RX_HDR_FLAG_CTRL_WARPPER_FRAME BIT(4) + +#define HIF_RX_HW_APPENDED_LEN 4 + +/* For DW 2, Byte 3 - ucHwChannelNum */ +#define HW_CHNL_NUM_MAX_2G4 14 +#define HW_CHNL_NUM_MAX_4G_5G (255 - HW_CHNL_NUM_MAX_2G4) + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/hif_tx.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/hif_tx.h new file mode 100644 index 00000000000000..caa82da229b310 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/hif_tx.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +#ifndef _HIF_TX_H +#define _HIF_TX_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* Maximum buffer size for individual HIF TCQ Buffer */ +#define HIF_TX_BUFF_MAX_SIZE 1552 /* Reserved field was not included */ + +#define TX_HDR_SIZE sizeof(HIF_TX_HEADER_T) + +#define CMD_HDR_SIZE sizeof(WIFI_CMD_T) + +#if CFG_MESON_G12A_PATCH +#define CMD_PKT_SIZE_FOR_IMAGE 1408 +#else +#define CMD_PKT_SIZE_FOR_IMAGE 2048 /* !< 2048 Bytes CMD payload buffer */ +#endif + +/*! NIC_HIF_TX_HEADER_T (for short-header format) */ +/* DW 0, Byte 0,1 */ +#define HIF_TX_HDR_TX_BYTE_COUNT_MASK BITS(0, 15) + +/* DW 0, Byte 2 */ +#define HIF_TX_HDR_ETHER_TYPE_OFFSET_MASK BITS(0, 6) +#define HIF_TX_HDR_IP_CSUM BIT(7) + +/* DW 0, Byte 3 */ +#define HIF_TX_HDR_TCP_CSUM BIT(0) +#define HIF_TX_HDR_QUEUE_IDX_MASK BITS(3, 6) +#define HIF_TX_HDR_QUEUE_IDX_OFFSET 3 +#define HIF_TX_HDR_PORT_IDX_MASK BIT(7) +#define HIF_TX_HDR_PORT_IDX_OFFSET 7 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef struct _HIF_HW_TX_HEADER_T { + u16 u2TxByteCount; + u8 ucEtherTypeOffset; + u8 ucCSflags; + u8 aucBuffer[0]; +} HIF_HW_TX_HEADER_T, *P_HIF_HW_TX_HEADER_T; + +typedef struct _HIF_TX_HEADER_T { + u16 u2TxByteCount_UserPriority; + u8 ucEtherTypeOffset; + u8 ucResource_PktType_CSflags; + u8 ucWlanHeaderLength; + u8 ucPktFormtId_Flags; + u16 u2LLH; /* for BOW */ + u16 u2SeqNo; /* for BOW */ + u8 ucStaRecIdx; + u8 ucForwardingType_SessionID_Reserved; + u8 ucPacketSeqNo; + u8 ucAck_BIP_BasicRate; + u8 aucReserved[2]; +} HIF_TX_HEADER_T, *P_HIF_TX_HEADER_T; + +typedef enum _ENUM_HIF_OOB_CTRL_PKT_TYPE_T { + HIF_OOB_CTRL_PKT_TYPE_LOOPBACK = 1, + HIF_OOB_CTRL_PKT_TYP_NUM +} ENUM_HIF_OOB_CTRL_PKT_TYPE_T, +*P_ENUM_HIF_OOB_CTRL_PKT_TYPE_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define TFCB_FRAME_PAD_TO_DW(u2Length) ALIGN_4(u2Length) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/* Kevin: we don't have to call following function to inspect the data + * structure. It will check automatically while at compile time. + */ +static __KAL_INLINE__ void hif_txDataTypeCheck(void); + +static __KAL_INLINE__ void hif_txDataTypeCheck(void) +{ + DATA_STRUCT_INSPECTING_ASSERT(sizeof(HIF_TX_HEADER_T) == 16); +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/mac.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/mac.h new file mode 100644 index 00000000000000..d19325df15271f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/mac.h @@ -0,0 +1,3014 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "mac.h" + * \brief Brief description. + * + * Detail description. + */ + +#ifndef _MAC_H +#define _MAC_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define AUTH_DATA_MAX_LEN 1024 /* temp defined */ + +/* 3 --------------- Constants for Ethernet/802.11 MAC --------------- */ +/* MAC Address */ +#define MAC_ADDR_LEN 6 + +#define MAC_ADDR_LOCAL_ADMIN BIT(1) + +#define ETH_P_IPV4 0x0800 +#define ETH_P_ARP 0x0806 +#define ETH_P_IPX 0x8137 /* Novell IPX */ +#define ETH_P_AARP 0x80F3 /* AppleTalk Address Resolution Protocol (AARP) */ +#define ETH_P_IPV6 0x86DD +#define ETH_P_VLAN 0x8100 + +#define ETH_P_1X 0x888E +#define ETH_P_PRE_1X 0x88C7 +// #define ETH_WPI_1X 0x88B4 +#define ETH_EAPOL_KEY 3 + +/* 802.3 Frame If Ether Type/Len <= 1500 */ +#define ETH_802_3_MAX_LEN 1500 + +/* IP Header definition */ +#define IP_VERSION_MASK BITS(4, 7) +#define IP_VERSION_OFFSET 4 +#define IP_VERSION_4 4 +#define IP_VERSION_6 6 + +#define IP_PROTOCOL_TCP 6 +#define IP_PROTOCOL_UDP 17 + +/* IPv4 Header definition */ +#define IPV4_HDR_TOS_OFFSET 1 +#define IPV4_HDR_TOS_PREC_MASK BITS(5, 7) +#define IPV4_HDR_TOS_PREC_OFFSET 5 +#define IPV4_HDR_IP_IDENTIFICATION_OFFSET 4 +#define IPV4_HDR_IP_PROTOCOL_OFFSET 9 +#define IPV4_HDR_IP_CSUM_OFFSET 10 +#define IPV4_HDR_IP_SRC_ADDR_OFFSET 12 +#define IPV4_HDR_IP_DST_ADDR_OFFSET 16 + +#define IPV4_HDR_LEN 20 +#define IPV4_ADDR_LEN 4 + +#define IPV6_HDR_IP_PROTOCOL_OFFSET 6 +#define IPV6_HDR_IP_SRC_ADDR_OFFSET 8 +#define IPV6_HDR_IP_DST_ADDR_OFFSET 24 +#define IPV6_HDR_IP_DST_ADDR_MAC_HIGH_OFFSET 32 +#define IPV6_HDR_IP_DST_ADDR_MAC_LOW_OFFSET 37 +#define IPV6_PROTOCOL_ICMPV6 0x3A + +#define IPV6_HDR_TC_PREC_OFFSET 1 +#define IPV6_HDR_TC_PREC_MASK BITS(1, 3) +#define IPV6_HDR_PROTOCOL_OFFSET 6 +#define IPV6_HDR_LEN 40 + +#define IPV6_ADDR_LEN 16 + +#define ICMPV6_TYPE_OFFSET 0 +#define ICMPV6_FLAG_OFFSET 4 +#define ICMPV6_TARGET_ADDR_OFFSET 8 +#define ICMPV6_TARGET_LL_ADDR_TYPE_OFFSET 24 +#define ICMPV6_TARGET_LL_ADDR_LEN_OFFSET 25 +#define ICMPV6_TARGET_LL_ADDR_TA_OFFSET 26 + +#define ICMPV6_FLAG_ROUTER_BIT BIT(7) +#define ICMPV6_FLAG_SOLICITED_BIT BIT(6) +#define ICMPV6_FLAG_OVERWRITE_BIT BIT(5) +#define ICMPV6_TYPE_NEIGHBOR_SOLICITATION 0x87 +#define ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT 0x88 + +#define TCP_HDR_TCP_CSUM_OFFSET 16 + +#define UDP_HDR_LEN 8 + +#define UDP_HDR_SRC_PORT_OFFSET 0 +#define UDP_HDR_DST_PORT_OFFSET 2 +#define UDP_HDR_UDP_CSUM_OFFSET 6 + +#define IP_PORT_BOOTP_SERVER 67 +#define IP_PORT_BOOTP_CLIENT 68 + +#define DHCP_MAGIC_NUMBER 0x63825363 + +#define ARP_OPERATION_OFFSET 6 +#define ARP_SNEDER_MAC_OFFSET 8 +#define ARP_SENDER_IP_OFFSET 14 +#define ARP_TARGET_MAC_OFFSET 18 +#define ARP_TARGET_IP_OFFSET 24 +#define ARP_OPERATION_REQUEST 0x0001 +#define ARP_OPERATION_RESPONSE 0x0002 + +#define LLC_LEN 8 /* LLC(3) + SNAP(3) + EtherType(2) */ + +#define NULL_MAC_ADDR \ + { \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 \ + } +#define BC_MAC_ADDR \ + { \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF \ + } + +#define ETH_HLEN 14 +#define ETH_TYPE_LEN_OFFSET 12 + +#define IPVERSION 4 +#define IP_HEADER_LEN 20 + +#define IPVH_VERSION_OFFSET 4 /* For Little-Endian */ +#define IPVH_VERSION_MASK 0xF0 +#define IPTOS_PREC_OFFSET 5 +#define IPTOS_PREC_MASK 0xE0 + +#define SOURCE_PORT_LEN 2 + +#define LOOK_AHEAD_LEN (ETH_HLEN + \ + IP_HEADER_LEN \ + + \ + SOURCE_PORT_LEN) + +/* Ethernet Frame Field Size, in byte */ +#define ETHER_HEADER_LEN 14 +#define ETHER_TYPE_LEN 2 +#define ETHER_MIN_PKT_SZ 60 +#define ETHER_MAX_PKT_SZ 1514 + +#define ETHER_TYPE_LEN_OFFSET 12 + +/* 802.1Q (VLAN) */ +#define ETH_802_1Q_HEADER_LEN 4 + +/* 802.2 LLC/SNAP */ +#define ETH_LLC_OFFSET ( \ + ETHER_HEADER_LEN) +#define ETH_LLC_LEN 3 +#define ETH_LLC_DSAP_SNAP 0xAA +#define ETH_LLC_SSAP_SNAP 0xAA +#define ETH_LLC_CONTROL_UNNUMBERED_INFORMATION 0x03 +#define ETH_LLC \ + { \ + ETH_LLC_DSAP_SNAP, ETH_LLC_SSAP_SNAP, \ + ETH_LLC_CONTROL_UNNUMBERED_INFORMATION \ + } + +/* Bluetooth SNAP */ +#define ETH_SNAP_OFFSET ( \ + ETHER_HEADER_LEN + ETH_LLC_LEN) +#define ETH_SNAP_LEN 5 +#define ETH_SNAP_OUI_LEN 3 +#define ETH_SNAP_BT_SIG_OUI_0 0x00 +#define ETH_SNAP_BT_SIG_OUI_1 0x19 +#define ETH_SNAP_BT_SIG_OUI_2 0x58 +#define ETH_SNAP_BT_SIG_OUI \ + { \ + ETH_SNAP_BT_SIG_OUI_0, ETH_SNAP_BT_SIG_OUI_1, \ + ETH_SNAP_BT_SIG_OUI_2 \ + } + +#define BOW_PROTOCOL_ID_SECURITY_FRAME 0x0003 + +/* IEEE 802.11 WLAN Frame Field Size, in byte */ +#define WLAN_MAC_HEADER_LEN 24 /* Address 4 excluded */ +#define WLAN_MAC_HEADER_A4_LEN 30 /* Address 4 included */ +#define WLAN_MAC_HEADER_QOS_LEN 26 /* QoS Control included */ +#define WLAN_MAC_HEADER_QOS_HTC_LEN 30 /* QoS Control and HTC included */ +#define WLAN_MAC_HEADER_A4_QOS_LEN 32 /* Address 4 and QoS Control included */ +#define WLAN_MAC_HEADER_A4_QOS_HTC_LEN \ + 36 /* Address 4, QoS Control and HTC included */ +#define WLAN_MAC_MGMT_HEADER_LEN 24 /* Address 4 excluded */ +#define WLAN_MAC_MGMT_HEADER_HTC_LEN 28 /* HTC included */ + +#define QOS_CTRL_LEN 2 +#define HT_CTRL_LEN 4 + +#define WLAN_MAC_CTS_ACK_LEN ( \ + WLAN_MAC_CTS_ACK_FRAME_HEADER_LEN + FCS_LEN) + +/* 6.2.1.1.2 Semantics of the service primitive */ +#define MSDU_MAX_LENGTH 2304 + +/* 7.1.3.3.3 Broadcast BSSID */ +#define BC_BSSID BC_MAC_ADDR + +/* 7.1.3.7 FCS field */ +#define FCS_LEN 4 + +/* 7.3.1.6 Listen Interval field */ +#define DEFAULT_LISTEN_INTERVAL_BY_DTIM_PERIOD \ + 2 /* In unit of AP's DTIM interval, */ +#define DEFAULT_LISTEN_INTERVAL 10 + +/* 7.3.2.1 Broadcast(Wildcard) SSID */ +#define BC_SSID "" +#define BC_SSID_LEN 0 + +/* 7.3.2.2 Data Rate Value */ +#define RATE_1M 2 /* 1M in unit of 500kb/s */ +#define RATE_2M 4 /* 2M */ +#define RATE_5_5M 11 /* 5.5M */ +#define RATE_11M 22 /* 11M */ +#define RATE_22M 44 /* 22M */ +#define RATE_33M 66 /* 33M */ +#define RATE_6M 12 /* 6M */ +#define RATE_9M 18 /* 9M */ +#define RATE_12M 24 /* 12M */ +#define RATE_18M 36 /* 18M */ +#define RATE_24M 48 /* 24M */ +#define RATE_36M 72 /* 36M */ +#define RATE_48M 96 /* 48M */ +#define RATE_54M 108 /* 54M */ + +/* 7.3.2.14 BSS membership selector */ +#if CFG_SUPPORT_H2E +#define RATE_H2E_ONLY 123 /* BSS Selector - Hash To Element only */ +#endif +#define RATE_VHT_PHY 126 /* BSS Selector - Clause 22. HT PHY */ +#define RATE_HT_PHY 127 /* BSS Selector - Clause 20. HT PHY */ +#define RATE_MASK \ + BITS(0, 6) \ + /* mask bits for the rate */ +#define RATE_BASIC_BIT \ + BIT(7) /* mask bit for the rate belonging to the BSSBasicRateSet */ + +/* 8.3.2.2 TKIP MPDU formats */ +#define TKIP_MIC_LEN 8 + +/* 9.2.10 DIFS */ +#define DIFS 2 /* 2 x aSlotTime */ + +/* 11.3 STA Authentication and Association */ +#define STA_STATE_1 0 /* Accept Class 1 frames */ +#define STA_STATE_2 1 /* Accept Class 1 & 2 frames */ +#define STA_STATE_3 2 /* Accept Class 1,2 & 3 frames */ + +/* 15.4.8.5 802.11k RCPI-dBm mapping*/ +#define NDBM_LOW_BOUND_FOR_RCPI 110 +#define RCPI_LOW_BOUND 0 +#define RCPI_HIGH_BOUND 220 +#define RCPI_MEASUREMENT_NOT_AVAILABLE 255 + +/* PHY characteristics */ +/* 17.4.4/18.3.3/19.8.4 Slot Time (aSlotTime) */ +#define SLOT_TIME_LONG 20 /* Long Slot Time */ +#define SLOT_TIME_SHORT 9 /* Short Slot Time */ + +#define SLOT_TIME_HR_DSSS \ + SLOT_TIME_LONG \ + /* 802.11b aSlotTime */ +#define SLOT_TIME_OFDM \ + SLOT_TIME_SHORT \ + /* 802.11a aSlotTime(20M Spacing) */ +#define SLOT_TIME_OFDM_10M_SPACING 13 /* 802.11a aSlotTime(10M Spacing) */ +#define SLOT_TIME_ERP_LONG \ + SLOT_TIME_LONG \ + /* 802.11g aSlotTime(Long) */ +#define SLOT_TIME_ERP_SHORT \ + SLOT_TIME_SHORT \ + /* 802.11g aSlotTime(Short) */ + +/* 17.4.4/18.3.3/19.8.4 Contention Window (aCWmin & aCWmax) */ +#define CWMIN_OFDM 15 /* 802.11a aCWmin */ +#define CWMAX_OFDM 1023 /* 802.11a aCWmax */ + +#define CWMIN_HR_DSSS 31 /* 802.11b aCWmin */ +#define CWMAX_HR_DSSS 1023 /* 802.11b aCWmax */ + +#define CWMIN_ERP_0 \ + 31 /* 802.11g aCWmin(0) - for only have 1/2/5/11Mbps Rates */ +#define CWMIN_ERP_1 15 /* 802.11g aCWmin(1) */ +#define CWMAX_ERP 1023 /* 802.11g aCWmax */ + +/* Short Inter-Frame Space (aSIFSTime) */ +/* 15.3.3 802.11b aSIFSTime */ +#define SIFS_TIME_HR_DSSS 10 +/* 17.4.4 802.11a aSIFSTime */ +#define SIFS_TIME_OFDM 16 +/* 19.8.4 802.11g aSIFSTime */ +#define SIFS_TIME_ERP 10 + +/* 15.4.6.2 Number of operating channels */ +#define CH_1 0x1 +#define CH_2 0x2 +#define CH_3 0x3 +#define CH_4 0x4 +#define CH_5 0x5 +#define CH_6 0x6 +#define CH_7 0x7 +#define CH_8 0x8 +#define CH_9 0x9 +#define CH_10 0xa +#define CH_11 0xb +#define CH_12 0xc +#define CH_13 0xd +#define CH_14 0xe + +#define MAXIMUM_OPERATION_CHANNEL_LIST 32 + +/* 3 --------------- IEEE 802.11 PICS --------------- */ +/* Annex D - dot11OperationEntry 2 */ +#define DOT11_RTS_THRESHOLD_MIN 0 +#define DOT11_RTS_THRESHOLD_MAX 2347 /* from Windows DDK */ +/* #define DOT11_RTS_THRESHOLD_MAX 3000 // from Annex D */ + +#define DOT11_RTS_THRESHOLD_DEFAULT \ + DOT11_RTS_THRESHOLD_MAX + +/* Annex D - dot11OperationEntry 5 */ +#define DOT11_FRAGMENTATION_THRESHOLD_MIN 256 +#define DOT11_FRAGMENTATION_THRESHOLD_MAX 2346 /* from Windows DDK */ +/* #define DOT11_FRAGMENTATION_THRESHOLD_MAX 3000 // from Annex D */ + +#define DOT11_FRAGMENTATION_THRESHOLD_DEFAULT \ + DOT11_FRAGMENTATION_THRESHOLD_MAX + +/* Annex D - dot11OperationEntry 6 */ +#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_MIN 1 +#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_MAX 0xFFFFffff +#define DOT11_TRANSMIT_MSDU_LIFETIME_TU_DEFAULT 4095 /* 802.11 define 512 */ +/* MT5921 only aceept N <= 4095 */ + +/* Annex D - dot11OperationEntry 7 */ +#define DOT11_RECEIVE_LIFETIME_TU_MIN 1 +#define DOT11_RECEIVE_LIFETIME_TU_MAX 0xFFFFffff +#define DOT11_RECEIVE_LIFETIME_TU_DEFAULT 4096 /* 802.11 define 512 */ + +/* Annex D - dot11StationConfigEntry 12 */ +#define DOT11_BEACON_PERIOD_MIN 1 /* TU. */ +#define DOT11_BEACON_PERIOD_MAX 0xffff /* TU. */ +#define DOT11_BEACON_PERIOD_DEFAULT 100 /* TU. */ + +/* Annex D - dot11StationConfigEntry 13 */ +#define DOT11_DTIM_PERIOD_MIN 1 /* TU. */ +#define DOT11_DTIM_PERIOD_MAX 255 /* TU. */ +#define DOT11_DTIM_PERIOD_DEFAULT 1 /* TU. */ + +/* Annex D - dot11RegDomainsSupportValue */ +#define REGULATION_DOMAIN_FCC 0x10 /* FCC (US) */ +#define REGULATION_DOMAIN_IC 0x20 /* IC or DOC (Canada) */ +#define REGULATION_DOMAIN_ETSI 0x30 /* ETSI (Europe) */ +#define REGULATION_DOMAIN_SPAIN 0x31 /* Spain */ +#define REGULATION_DOMAIN_FRANCE 0x32 /* France */ +#define REGULATION_DOMAIN_JAPAN 0x40 /* MKK (Japan) */ +#define REGULATION_DOMAIN_CHINA 0x50 /* China */ +#define REGULATION_DOMAIN_OTHER 0x00 /* Other */ + +/* 3 --------------- IEEE 802.11 MAC header fields --------------- */ +/* 7.1.3.1 Masks for the subfields in the Frame Control field */ +#define MASK_FC_PROTOCOL_VER BITS(0, 1) +#define MASK_FC_TYPE BITS(2, 3) +#define MASK_FC_SUBTYPE BITS(4, 7) +#define MASK_FC_SUBTYPE_QOS_DATA BIT(7) +#define MASK_FC_TO_DS BIT(8) +#define MASK_FC_FROM_DS BIT(9) +#define MASK_FC_MORE_FRAG BIT(10) +#define MASK_FC_RETRY BIT(11) +#define MASK_FC_PWR_MGT BIT(12) +#define MASK_FC_MORE_DATA BIT(13) +#define MASK_FC_PROTECTED_FRAME BIT(14) +#define MASK_FC_ORDER BIT(15) + +#define MASK_FRAME_TYPE (MASK_FC_TYPE \ + | \ + MASK_FC_SUBTYPE) +#define MASK_TO_DS_FROM_DS (MASK_FC_TO_DS \ + | \ + MASK_FC_FROM_DS) + +#define MAX_NUM_OF_FC_SUBTYPES 16 +#define OFFSET_OF_FC_SUBTYPE 4 + +/* 7.1.3.1.2 MAC frame types and subtypes */ +#define MAC_FRAME_TYPE_MGT 0 +#define MAC_FRAME_TYPE_CTRL BIT(2) +#define MAC_FRAME_TYPE_DATA BIT(3) +#define MAC_FRAME_TYPE_QOS_DATA ( \ + MAC_FRAME_TYPE_DATA | MASK_FC_SUBTYPE_QOS_DATA) + +#define MAC_FRAME_ASSOC_REQ ( \ + MAC_FRAME_TYPE_MGT | 0x0000) +#define MAC_FRAME_ASSOC_RSP ( \ + MAC_FRAME_TYPE_MGT | 0x0010) +#define MAC_FRAME_REASSOC_REQ ( \ + MAC_FRAME_TYPE_MGT | 0x0020) +#define MAC_FRAME_REASSOC_RSP ( \ + MAC_FRAME_TYPE_MGT | 0x0030) +#define MAC_FRAME_PROBE_REQ ( \ + MAC_FRAME_TYPE_MGT | 0x0040) +#define MAC_FRAME_PROBE_RSP ( \ + MAC_FRAME_TYPE_MGT | 0x0050) +#define MAC_FRAME_BEACON ( \ + MAC_FRAME_TYPE_MGT | 0x0080) +#define MAC_FRAME_ATIM ( \ + MAC_FRAME_TYPE_MGT | 0x0090) +#define MAC_FRAME_DISASSOC ( \ + MAC_FRAME_TYPE_MGT | 0x00A0) +#define MAC_FRAME_AUTH ( \ + MAC_FRAME_TYPE_MGT | 0x00B0) +#define MAC_FRAME_DEAUTH ( \ + MAC_FRAME_TYPE_MGT | 0x00C0) +#define MAC_FRAME_ACTION ( \ + MAC_FRAME_TYPE_MGT | 0x00D0) +#define MAC_FRAME_ACTION_NO_ACK ( \ + MAC_FRAME_TYPE_MGT | 0x00E0) + +#define MAC_FRAME_CONTRL_WRAPPER ( \ + MAC_FRAME_TYPE_CTRL | 0x0070) +#define MAC_FRAME_BLOCK_ACK_REQ ( \ + MAC_FRAME_TYPE_CTRL | 0x0080) +#define MAC_FRAME_BLOCK_ACK ( \ + MAC_FRAME_TYPE_CTRL | 0x0090) +#define MAC_FRAME_PS_POLL ( \ + MAC_FRAME_TYPE_CTRL | 0x00A0) +#define MAC_FRAME_RTS ( \ + MAC_FRAME_TYPE_CTRL | 0x00B0) +#define MAC_FRAME_CTS ( \ + MAC_FRAME_TYPE_CTRL | 0x00C0) +#define MAC_FRAME_ACK ( \ + MAC_FRAME_TYPE_CTRL | 0x00D0) +#define MAC_FRAME_CF_END ( \ + MAC_FRAME_TYPE_CTRL | 0x00E0) +#define MAC_FRAME_CF_END_CF_ACK ( \ + MAC_FRAME_TYPE_CTRL | 0x00F0) + +#define MAC_FRAME_DATA ( \ + MAC_FRAME_TYPE_DATA | 0x0000) +#define MAC_FRAME_DATA_CF_ACK ( \ + MAC_FRAME_TYPE_DATA | 0x0010) +#define MAC_FRAME_DATA_CF_POLL ( \ + MAC_FRAME_TYPE_DATA | 0x0020) +#define MAC_FRAME_DATA_CF_ACK_CF_POLL ( \ + MAC_FRAME_TYPE_DATA | 0x0030) +#define MAC_FRAME_NULL ( \ + MAC_FRAME_TYPE_DATA | 0x0040) +#define MAC_FRAME_CF_ACK ( \ + MAC_FRAME_TYPE_DATA | 0x0050) +#define MAC_FRAME_CF_POLL ( \ + MAC_FRAME_TYPE_DATA | 0x0060) +#define MAC_FRAME_CF_ACK_CF_POLL ( \ + MAC_FRAME_TYPE_DATA | 0x0070) +#define MAC_FRAME_QOS_DATA ( \ + MAC_FRAME_TYPE_DATA | 0x0080) +#define MAC_FRAME_QOS_DATA_CF_ACK ( \ + MAC_FRAME_TYPE_DATA | 0x0090) +#define MAC_FRAME_QOS_DATA_CF_POLL ( \ + MAC_FRAME_TYPE_DATA | 0x00A0) +#define MAC_FRAME_QOS_DATA_CF_ACK_CF_POLL ( \ + MAC_FRAME_TYPE_DATA | 0x00B0) +#define MAC_FRAME_QOS_NULL ( \ + MAC_FRAME_TYPE_DATA | 0x00C0) +#define MAC_FRAME_QOS_CF_POLL ( \ + MAC_FRAME_TYPE_DATA | 0x00E0) +#define MAC_FRAME_QOS_CF_ACK_CF_POLL ( \ + MAC_FRAME_TYPE_DATA | 0x00F0) + +/* 7.1.3.2 Mask for the AID value in the Duration/ID field */ +#define MASK_DI_DURATION BITS(0, 14) +#define MASK_DI_AID BITS(0, 13) +#define MASK_DI_AID_MSB BITS(14, 15) +#define MASK_DI_CFP_FIXED_VALUE BIT(15) + +/* 7.1.3.4 Masks for the subfields in the Sequence Control field */ +#define MASK_SC_SEQ_NUM BITS(4, 15) +#define MASK_SC_SEQ_NUM_OFFSET 4 +#define MASK_SC_FRAG_NUM BITS(0, 3) +#define INVALID_SEQ_CTRL_NUM \ + 0x000F /* According to 6.2.1.1.2 \ + * FRAG_NUM won't equal to 15 \ + */ + +/* 7.1.3.5 QoS Control field */ +#define TID_NUM 16 +#define TID_MASK BITS(0, 3) +#define EOSP BIT(4) +#define ACK_POLICY BITS(5, 6) +#define A_MSDU_PRESENT BIT(7) + +#define MASK_QC_TID BITS(0, 3) +#define MASK_QC_EOSP BIT(4) +#define MASK_QC_EOSP_OFFSET 4 +#define MASK_QC_ACK_POLICY BITS(5, 6) +#define MASK_QC_ACK_POLICY_OFFSET 5 +#define MASK_QC_A_MSDU_PRESENT BIT(7) + +/* 7.1.3.5a HT Control field */ +#define HT_CTRL_LINK_ADAPTATION_CTRL BITS(0, 15) +#define HT_CTRL_CALIBRATION_POSITION BITS(16, 17) +#define HT_CTRL_CALIBRATION_SEQUENCE BITS(18, 19) +#define HT_CTRL_CSI_STEERING BITS(22, 23) +#define HT_CTRL_NDP_ANNOUNCEMENT BIT(24) +#define HT_CTRL_AC_CONSTRAINT BIT(30) +#define HT_CTRL_RDG_MORE_PPDU BIT(31) + +#define LINK_ADAPTATION_CTRL_TRQ BIT(1) +#define LINK_ADAPTATION_CTRL_MAI_MRQ BIT(2) +#define LINK_ADAPTATION_CTRL_MAI_MSI BITS(3, 5) +#define LINK_ADAPTATION_CTRL_MFSI BITS(6, 8) +#define LINK_ADAPTATION_CTRL_MFB_ASELC_CMD BITS(9, 11) +#define LINK_ADAPTATION_CTRL_MFB_ASELC_DATA BITS(12, 15) + +/* 7.1.3.5.3 Ack Policy subfield*/ +#define ACK_POLICY_NORMAL_ACK_IMPLICIT_BA_REQ 0 +#define ACK_POLICY_NO_ACK 1 +#define ACK_POLICY_NO_EXPLICIT_ACK_PSMP_ACK 2 +#define ACK_POLICY_BA 3 + +/* 7.1.3.7 FCS field */ +#define FCS_LEN 4 + +/* 7.2.1.4 WLAN Control Frame - PS-POLL Frame */ +#define PSPOLL_FRAME_LEN 16 /* w/o FCS */ + +/* 7.2.7.1 BAR */ +#define OFFSET_BAR_SSC_SN 4 + +/* 8.3.2.2 TKIP MPDU formats */ +#define TKIP_MIC_LEN 8 + +#define BA_POLICY_IMMEDIATE BIT(1) + +/* Block Ack Starting Sequence Control field */ +#define BA_START_SEQ_CTL_FRAG_NUM BITS(0, 3) +#define BA_START_SEQ_CTL_SSN BITS(4, 15) + +/* BAR Control field */ +#define BAR_CONTROL_NO_ACK_POLICY BIT(0) +#define BAR_CONTROL_MULTI_TID BIT(1) +#define BAR_CONTROL_COMPRESSED_BA BIT(2) +#define BAR_CONTROL_TID_INFO BITS(12, 15) +#define BAR_CONTROL_TID_INFO_OFFSET 12 + +/* TID Value */ +#define BAR_INFO_TID_VALUE BITS(12, 15) + +#define BAR_COMPRESSED_VARIANT_FRAME_LEN (16 + 4) + +/* 3 --------------- IEEE 802.11 frame body fields --------------- */ +/* 3 Management frame body components (I): Fixed Fields. */ +/* 7.3.1.1 Authentication Algorithm Number field */ +#define AUTH_ALGORITHM_NUM_FIELD_LEN 2 + +#define AUTH_ALGORITHM_NUM_OPEN_SYSTEM 0 /* Open System */ +#define AUTH_ALGORITHM_NUM_SHARED_KEY 1 /* Shared Key */ +#define AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION 2 /* Fast BSS Transition */ +#define AUTH_ALGORITHM_NUM_SAE 3 /* SAE */ + +/* 7.3.1.2 Authentication Transaction Sequence Number field */ +#define AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN 2 +#define AUTH_TRANSACTION_SEQ_1 1 +#define AUTH_TRANSACTION_SEQ_2 2 +#define AUTH_TRANSACTION_SEQ_3 3 +#define AUTH_TRANSACTION_SEQ_4 4 + +#if CFG_SUPPORT_H2E +#define AUTH_STATUS_CODE_FIELD_LEN 2 +#endif + +/* 7.3.1.3 Beacon Interval field */ +#define BEACON_INTERVAL_FIELD_LEN 2 + +/* 7.3.1.4 Capability Information field */ +#define CAP_INFO_FIELD_LEN 2 +#define CAP_INFO_ESS BIT(0) +#define CAP_INFO_IBSS BIT(1) +#define CAP_INFO_BSS_TYPE (CAP_INFO_ESS \ + | \ + CAP_INFO_IBSS) +#define CAP_INFO_CF_POLLABLE BIT(2) +#define CAP_INFO_CF_POLL_REQ BIT(3) +#define CAP_INFO_CF ( \ + CAP_INFO_CF_POLLABLE | CAP_INFO_CF_POLL_REQ) +#define CAP_INFO_PRIVACY BIT(4) +#define CAP_INFO_SHORT_PREAMBLE BIT(5) +#define CAP_INFO_PBCC BIT(6) +#define CAP_INFO_CH_AGILITY BIT(7) +#define CAP_INFO_SPEC_MGT BIT(8) +#define CAP_INFO_QOS BIT(9) +#define CAP_INFO_SHORT_SLOT_TIME BIT(10) +#define CAP_INFO_APSD BIT(11) +#define CAP_INFO_RADIO_MEASUREMENT BIT(12) +#define CAP_INFO_DSSS_OFDM BIT(13) +#define CAP_INFO_DELAYED_BLOCK_ACK BIT(14) +#define CAP_INFO_IMM_BLOCK_ACK BIT(15) +/* STA usage of CF-Pollable and CF-Poll Request subfields */ +/* STA: not CF-Pollable */ +#define CAP_CF_STA_NOT_POLLABLE 0x0000 +/* STA: CF-Pollable, not requesting on the CF-Polling list */ +#define CAP_CF_STA_NOT_ON_LIST \ + CAP_INFO_CF_POLL_REQ +/* STA: CF-Pollable, requesting on the CF-Polling list */ +#define CAP_CF_STA_ON_LIST \ + CAP_INFO_CF_POLLABLE +/* STA: CF-Pollable, requesting never to be polled */ +#define CAP_CF_STA_NEVER_POLLED ( \ + CAP_INFO_CF_POLLABLE | CAP_INFO_CF_POLL_REQ) + +/* AP usage of CF-Pollable and CF-Poll Request subfields */ +/* AP: No point coordinator (PC) */ +#define CAP_CF_AP_NO_PC 0x0000 +/* AP: PC at AP for delivery only (no polling) */ +#define CAP_CF_AP_DELIVERY_ONLY \ + CAP_INFO_CF_POLL_REQ +/* AP: PC at AP for delivery and polling */ +#define CAP_CF_AP_DELIVERY_POLLING \ + CAP_INFO_CF_POLLABLE + +/* 7.3.1.5 Current AP Address field */ +#define CURR_AP_ADDR_FIELD_LEN MAC_ADDR_LEN + +/* 7.3.1.6 Listen Interval field */ +#define LISTEN_INTERVAL_FIELD_LEN 2 + +/* 7.3.1.7 Reason Code field */ +#define REASON_CODE_FIELD_LEN 2 + +#define REASON_CODE_RESERVED 0 /* Reseved */ +#define REASON_CODE_UNSPECIFIED 1 /* Unspecified reason */ +#define REASON_CODE_PREV_AUTH_INVALID 2 /* Previous auth no longer valid */ +#define REASON_CODE_DEAUTH_LEAVING_BSS \ + 3 /* Deauth because sending STA is leaving BSS */ +#define REASON_CODE_DISASSOC_INACTIVITY 4 /* Disassoc due to inactivity */ +#define REASON_CODE_DISASSOC_AP_OVERLOAD \ + 5 /* Disassoc because AP is unable to handle all assoc STAs */ +#define REASON_CODE_CLASS_2_ERR 6 /* Class 2 frame rx from nonauth STA */ +#define REASON_CODE_CLASS_3_ERR 7 /* Class 3 frame rx from nonassoc STA */ +#define REASON_CODE_DISASSOC_LEAVING_BSS \ + 8 /* Disassoc because sending STA is leaving BSS */ +#define REASON_CODE_ASSOC_BEFORE_AUTH \ + 9 /* STA requesting (re)assoc is not auth with responding STA */ +/* Disassoc because the info in Power Capability is unacceptable */ +#define REASON_CODE_DISASSOC_PWR_CAP_UNACCEPTABLE 10 +/* Disassoc because the info in Supported Channels is unacceptable */ +#define REASON_CODE_DISASSOC_SUP_CHS_UNACCEPTABLE 11 +#define REASON_CODE_INVALID_INFO_ELEM 13 /* Invalid information element */ +#define REASON_CODE_MIC_FAILURE 14 /* MIC failure */ +#define REASON_CODE_4_WAY_HANDSHAKE_TIMEOUT 15 /* 4-way handshake timeout */ +#define REASON_CODE_GROUP_KEY_UPDATE_TIMEOUT 16 /* Group key update timeout */ +/* Info element in 4-way handshake different from */ +/* (Re-)associate request/Probe response/Beacon */ +#define REASON_CODE_DIFFERENT_INFO_ELEM 17 +#define REASON_CODE_MULTICAST_CIPHER_NOT_VALID \ + 18 /* Multicast Cipher is not valid */ +#define REASON_CODE_UNICAST_CIPHER_NOT_VALID \ + 19 /* Unicast Cipher is not valid */ +#define REASON_CODE_AKMP_NOT_VALID 20 /* AKMP is not valid */ +#define REASON_CODE_UNSUPPORTED_RSNE_VERSION 21 /* Unsupported RSNE version */ +#define REASON_CODE_INVALID_RSNE_CAPABILITIES \ + 22 /* Invalid RSNE Capabilities \ + */ +#define REASON_CODE_IEEE_802_1X_AUTH_FAILED \ + 23 /* IEEE 802.1X Authentication failed */ +#define REASON_CODE_CIPHER_REJECT_SEC_POLICY \ + 24 /* Cipher suite rejected because of the security policy */ +#define REASON_CODE_DISASSOC_UNSPECIFIED_QOS \ + 32 /* Disassoc for unspecified, QoS-related reason */ +/* Disassoc because QAP lacks sufficient bandwidth for this QSTA */ +#define REASON_CODE_DISASSOC_LACK_OF_BANDWIDTH 33 +/* Disassoc because of too many ACKs lost for AP transmissions */ +/* and/or poor channel conditions */ +#define REASON_CODE_DISASSOC_ACK_LOST_POOR_CHANNEL 34 +/* Disassoc because QSTA is transmitting outside the limits of its TXOPs */ +#define REASON_CODE_DISASSOC_TX_OUTSIDE_TXOP_LIMIT 35 +#define REASON_CODE_PEER_WHILE_LEAVING \ + 36 /* QSTA is leaving the QBSS or resetting */ +#define REASON_CODE_PEER_REFUSE_DLP \ + 37 /* Peer does not want to use this mechanism */ +#define REASON_CODE_PEER_SETUP_REQUIRED \ + 38 /* Frames received but a setup is reqired */ +#define REASON_CODE_PEER_TIME_OUT 39 /* Time out */ +#define REASON_CODE_PEER_CIPHER_UNSUPPORTED \ + 45 /* Peer does not support the requested cipher suite */ +#define REASON_CODE_BEACON_TIMEOUT \ + 100 /* for beacon timeout, defined by mediatek */ +/* 7.3.1.8 AID field */ +#define AID_FIELD_LEN 2 +#define AID_MASK BITS(0, 13) +#define AID_MSB BITS(14, 15) +#define AID_MIN_VALUE 1 +#define AID_MAX_VALUE 2007 + +/* 7.3.1.9 Status Code field */ +#define STATUS_CODE_FIELD_LEN 2 + +#define STATUS_CODE_RESERVED 0 /* Reserved - Used by TX Auth */ +#define STATUS_CODE_SUCCESSFUL 0 /* Successful */ +#define STATUS_CODE_UNSPECIFIED_FAILURE 1 /* Unspecified failure */ +#define STATUS_CODE_CAP_NOT_SUPPORTED \ + 10 /* Cannot support all requested cap in the Cap Info field */ +/* Reassoc denied due to inability to confirm that assoc exists */ +#define STATUS_CODE_REASSOC_DENIED_WITHOUT_ASSOC 11 +#define STATUS_CODE_ASSOC_DENIED_OUTSIDE_STANDARD \ + 12 /* Assoc denied due to reason outside the scope of this std. */ +/* Responding STA does not support the specified auth algorithm */ +#define STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED 13 +/* Rx an auth frame with auth transaction seq num out of expected seq */ +#define STATUS_CODE_AUTH_OUT_OF_SEQ 14 +#define STATUS_CODE_AUTH_REJECTED_CHAL_FAIL \ + 15 /* Auth rejected because of challenge failure */ +/* Auth rejected due to timeout waiting for next frame in sequence */ +#define STATUS_CODE_AUTH_REJECTED_TIMEOUT 16 +/* Assoc denied because AP is unable to handle additional assoc STAs */ +#define STATUS_CODE_ASSOC_DENIED_AP_OVERLOAD 17 +/* Assoc denied due to requesting STA not supporting all of basic rates */ +#define STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED 18 +/* Assoc denied due to requesting STA not supporting short preamble */ +#define STATUS_CODE_ASSOC_DENIED_NO_SHORT_PREAMBLE 19 +#define STATUS_CODE_ASSOC_DENIED_NO_PBCC \ + 20 /* Assoc denied due to requesting STA not supporting PBCC */ +/* Assoc denied due to requesting STA not supporting channel agility */ +#define STATUS_CODE_ASSOC_DENIED_NO_CH_AGILITY 21 +#define STATUS_CODE_ASSOC_REJECTED_NO_SPEC_MGT \ + 22 /* Assoc rejected because Spectrum Mgt capability is required */ +/* Assoc rejected because the info in Power Capability is unacceptable */ +#define STATUS_CODE_ASSOC_REJECTED_PWR_CAP 23 +/* Assoc rejected because the info in Supported Channels is unacceptable */ +#define STATUS_CODE_ASSOC_REJECTED_SUP_CHS 24 +/* Assoc denied due to requesting STA not supporting short slot time */ +#define STATUS_CODE_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25 +/* Assoc denied due to requesting STA not supporting DSSS-OFDM */ +#define STATUS_CODE_ASSOC_DENIED_NO_DSSS_OFDM 26 +#if CFG_SUPPORT_802_11W +#define STATUS_CODE_ASSOC_REJECTED_TEMPORARILY \ + 30 /* IEEE 802.11w, Assoc denied due to the SA query */ +/* IEEE 802.11w, Assoc denied due to the MFP select policy */ +#define STATUS_CODE_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31 +#endif +#define STATUS_CODE_UNSPECIFIED_QOS_FAILURE \ + 32 /* Unspecified, QoS-related failure */ +/* Assoc denied due to insufficient bandwidth to handle another QSTA */ +#define STATUS_CODE_ASSOC_DENIED_BANDWIDTH 33 +/* Assoc denied due to excessive frame loss rates and/or poor channel conditions + */ +#define STATUS_CODE_ASSOC_DENIED_POOR_CHANNEL 34 +/* Assoc denied due to requesting STA not supporting QoS facility */ +#define STATUS_CODE_ASSOC_DENIED_NO_QOS_FACILITY 35 +#define STATUS_CODE_REQ_DECLINED 37 /* Request has been declined */ +/* Request has not been successful as one or more parameters have invalid values + */ +#define STATUS_CODE_REQ_INVALID_PARAMETER_VALUE 38 +/* TS not created because request cannot be honored. */ +/* Suggested TSPEC provided. */ +#define STATUS_CODE_REQ_NOT_HONORED_TSPEC 39 +#define STATUS_CODE_INVALID_INFO_ELEMENT 40 /* Invalid information element */ +#define STATUS_CODE_INVALID_GROUP_CIPHER 41 /* Invalid group cipher */ +#define STATUS_CODE_INVALID_PAIRWISE_CIPHER 42 /* Invalid pairwise cipher */ +#define STATUS_CODE_INVALID_AKMP 43 /* Invalid AKMP */ +#define STATUS_CODE_UNSUPPORTED_RSN_IE_VERSION \ + 44 /* Unsupported RSN information element version */ +#define STATUS_CODE_INVALID_RSN_IE_CAP \ + 45 /* Invalid RSN information element capabilities */ +#define STATUS_CODE_CIPHER_SUITE_REJECTED \ + 46 /* Cipher suite rejected because of security policy */ +/* TS not created because request cannot be honored. */ +/* Attempt to create a TS later. */ +#define STATUS_CODE_REQ_NOT_HONORED_TS_DELAY 47 +#define STATUS_CODE_DIRECT_LINK_NOT_ALLOWED \ + 48 /* Direct Link is not allowed in the BSS by policy */ +#define STATUS_CODE_DESTINATION_STA_NOT_PRESENT \ + 49 /* Destination STA is not present within this QBSS */ +#define STATUS_CODE_DESTINATION_STA_NOT_QSTA \ + 50 /* Destination STA is not a QSTA */ +#define STATUS_CODE_ASSOC_DENIED_LARGE_LIS_INTERVAL \ + 51 /* Association denied because the ListenInterval is too large \ + */ + +#if CFG_SUPPORT_H2E +#define WLAN_STATUS_SAE_HASH_TO_ELEMENT 126 +#endif + +/* proprietary definition of reserved field of Status Code */ +#define STATUS_CODE_JOIN_FAILURE 0xFFF0 /* Join failure */ +#define STATUS_CODE_JOIN_TIMEOUT 0xFFF1 /* Join timeout */ +#define STATUS_CODE_AUTH_TIMEOUT 0xFFF2 /* Authentication timeout */ +#define STATUS_CODE_ASSOC_TIMEOUT 0xFFF3 /* (Re)Association timeout */ +#define STATUS_CODE_CCX_CCKM_REASSOC_FAILURE \ + 0xFFF4 /* CCX CCKM reassociation failure */ + +/* 7.3.1.10 Timestamp field */ +#define TIMESTAMP_FIELD_LEN 8 + +/* 7.3.1.11 Category of Action field */ +#define CATEGORY_SPEC_MGT 0 +#define CATEGORY_QOS_ACTION 1 /* QoS action */ +#define CATEGORY_DLS_ACTION 2 /* Direct Link Protocol (DLP) action */ +#define CATEGORY_BLOCK_ACK_ACTION 3 /* Block ack action */ +#define CATEGORY_PUBLIC_ACTION 4 /* Public action */ +#define CATEGORY_RM_ACTION 5 /* Radio measurement action */ +#define CATEGORY_HT_ACTION 7 +#if CFG_SUPPORT_802_11W +#define CATEGORY_SA_QUERY_ACTION 8 +#define CATEGORY_PROTECTED_DUAL_OF_PUBLIC_ACTION 9 +#endif +#define CATEGORY_WNM_ACTION 10 /* 802.11v Wireless Network Management */ +#define CATEGORY_UNPROTECTED_WNM_ACTION \ + 11 /* 802.11v Wireless Network Management */ +#define CATEGORY_WME_MGT_NOTIFICATION 17 /* WME management notification */ + +#define CATEGORY_VHT_ACTION 21 /* VHT action */ + +#if CFG_SUPPORT_802_11W +#define CATEGORY_VENDOR_SPECIFIC_ACTION_PROTECTED 126 +#endif +#define CATEGORY_VENDOR_SPECIFIC_ACTION 127 + +/* 7.3.1.14 Block Ack Parameter Set field */ +#define BA_PARAM_SET_ACK_POLICY_MASK BIT(1) +#define BA_PARAM_SET_ACK_POLICY_MASK_OFFSET 1 +#define BA_PARAM_SET_TID_MASK BITS(2, 5) +#define BA_PARAM_SET_TID_MASK_OFFSET 2 +#define BA_PARAM_SET_BUFFER_SIZE_MASK BITS(6, 15) +#define BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET 6 + +#define BA_PARAM_SET_ACK_POLICY_IMMEDIATE_BA 1 +#define BA_PARAM_SET_ACK_POLICY_DELAYED_BA 0 + +/* 3 Management frame body components (II): Information Elements. */ +/* 7.3.2 Element IDs of information elements */ +#define ELEM_HDR_LEN 2 + +#define ELEM_ID_SSID 0 /* SSID */ +#define ELEM_ID_SUP_RATES 1 /* Supported rates */ +#define ELEM_ID_FH_PARAM_SET 2 /* FH parameter set */ +#define ELEM_ID_DS_PARAM_SET 3 /* DS parameter set */ +#define ELEM_ID_CF_PARAM_SET 4 /* CF parameter set */ +#define ELEM_ID_TIM 5 /* TIM */ +#define ELEM_ID_IBSS_PARAM_SET 6 /* IBSS parameter set */ +#define ELEM_ID_COUNTRY_INFO 7 /* Country information */ +#define ELEM_ID_HOPPING_PATTERN_PARAM 8 /* Hopping pattern parameters */ +#define ELEM_ID_HOPPING_PATTERN_TABLE 9 /* Hopping pattern table */ +#define ELEM_ID_REQUEST 10 /* Request */ +#define ELEM_ID_BSS_LOAD 11 /* BSS load */ +#define ELEM_ID_EDCA_PARAM_SET 12 /* EDCA parameter set */ +#define ELEM_ID_TSPEC 13 /* Traffic specification (TSPEC) */ +#define ELEM_ID_TCLAS 14 /* Traffic classification (TCLAS) */ +#define ELEM_ID_SCHEDULE 15 /* Schedule */ +#define ELEM_ID_CHALLENGE_TEXT 16 /* Challenge text */ + +#define ELEM_ID_PWR_CONSTRAINT 32 /* Power constraint */ +#define ELEM_ID_PWR_CAP 33 /* Power capability */ +#define ELEM_ID_TPC_REQ 34 /* TPC request */ +#define ELEM_ID_TPC_REPORT 35 /* TPC report */ +#define ELEM_ID_SUP_CHS 36 /* Supported channels */ +#define ELEM_ID_CH_SW_ANNOUNCEMENT 37 /* Channel switch announcement */ +#define ELEM_ID_MEASUREMENT_REQ 38 /* Measurement request */ +#define ELEM_ID_MEASUREMENT_REPORT 39 /* Measurement report */ +#define ELEM_ID_QUIET 40 /* Quiet */ +#define ELEM_ID_IBSS_DFS 41 /* IBSS DFS */ +#define ELEM_ID_ERP_INFO 42 /* ERP information */ +#define ELEM_ID_TS_DELAY 43 /* TS delay */ +#define ELEM_ID_TCLAS_PROCESSING 44 /* TCLAS processing */ +#define ELEM_ID_HT_CAP 45 /* HT Capabilities subelement */ +#define ELEM_ID_QOS_CAP 46 /* QoS capability */ +#define ELEM_ID_RSN 48 /* RSN IE */ +#define ELEM_ID_EXTENDED_SUP_RATES 50 /* Extended supported rates */ +#define ELEM_ID_NEIGHBOR_REPORT 52 /* Neighbor Report */ +#if CFG_SUPPORT_802_11W +#define ELEM_ID_TIMEOUT_INTERVAL 56 /* 802.11w SA Timeout interval */ +#endif +#define ELEM_ID_SUP_OPERATING_CLASS 59 /* Supported Operating Classes */ + +#define ELEM_ID_HT_OP 61 /* HT Operation */ +#define ELEM_ID_SCO 62 /* Secondary Channel Offset */ +#define ELEM_ID_RRM_ENABLED_CAP \ + 70 /* Radio Resource Management Enabled Capabilities */ +#define ELEM_ID_20_40_BSS_COEXISTENCE 72 /* 20/40 BSS Coexistence */ +#define ELEM_ID_20_40_INTOLERANT_CHNL_REPORT \ + 73 /* 20/40 BSS Intolerant Channel Report */ +#define ELEM_ID_OBSS_SCAN_PARAMS 74 /* Overlapping BSS Scan Parameters */ +#define ELEM_ID_MAX_IDLE_PERIOD 90 /* Max Idle Period. */ + +#define ELEM_ID_EXTENDED_CAP 127 /* Extended capabilities */ + +#define ELEM_ID_INTERWORKING 107 /* Interworking with External Network */ +#define ELEM_ID_ADVERTISEMENT_PROTOCOL 108 /* Advertisement Protocol */ +#define ELEM_ID_ROAMING_CONSORTIUM 111 /* Roaming Consortium */ +#define ELEM_ID_EXTENDED_CAP 127 /* Extended capabilities */ + +#define ELEM_ID_VENDOR 221 /* Vendor specific IE */ +#define ELEM_ID_WPA \ + ELEM_ID_VENDOR \ + /* WPA IE */ +#define ELEM_ID_WMM \ + ELEM_ID_VENDOR \ + /* WMM IE */ +#define ELEM_ID_P2P \ + ELEM_ID_VENDOR \ + /* WiFi Direct */ +#define ELEM_ID_WSC \ + ELEM_ID_VENDOR \ + /* WSC IE */ + +#define ELEM_ID_VHT_CAP 191 /* VHT Capabilities subelement */ +#define ELEM_ID_VHT_OP 192 /* VHT Operation information */ +#define ELEM_ID_WIDE_BAND_CHANNEL_SWITCH \ + 194 /*Wide Bandwidth Channel Switch \ + */ +#define ELEM_ID_OP_MODE 199 /* Operation Mode Notification */ +#define ELEM_ID_RESERVED 255 /* Reserved */ + +/* 7.3.2.1 SSID element */ +#define ELEM_MAX_LEN_SSID 32 + +/* 7.3.2.2 Supported Rates */ +#define ELEM_MAX_LEN_SUP_RATES 8 + +#define ELEM_MAX_LEN_SUP_RATES_IOT 16 + +/* 7.3.2.4 DS Parameter Set */ +#define ELEM_MAX_LEN_DS_PARAMETER_SET 1 + +/* 7.3.2.5 CF Parameter Set */ +#define ELEM_CF_PARM_LEN 8 + +/* 7.3.2.6 TIM */ +#define ELEM_MIX_LEN_TIM 4 +#define ELEM_MAX_LEN_TIM 254 + +/* 7.3.2.7 IBSS Parameter Set element */ +#define ELEM_MAX_LEN_IBSS_PARAMETER_SET 2 + +/* 7.3.2.8 Challenge Text element */ +#define ELEM_MIN_LEN_CHALLENGE_TEXT 1 +#define ELEM_MAX_LEN_CHALLENGE_TEXT 253 + +/* 7.3.2.9 Country Information element */ +/* Country IE should contain at least 3-bytes country code string and one + * subband triplet. */ +#define ELEM_MIN_LEN_COUNTRY_INFO 6 + +#define ELEM_ID_COUNTRY_INFO_TRIPLET_LEN_FIXED 3 +#define ELEM_ID_COUNTRY_INFO_SUBBAND_TRIPLET_LEN_FIXED 3 +#define ELEM_ID_COUNTRY_INFO_REGULATORY_TRIPLET_LEN_FIXED 3 + +/* 7.3.2.13 ERP Information element */ +#define ELEM_MAX_LEN_ERP 1 +/* -- bits in the ERP Information element */ +#define ERP_INFO_NON_ERP_PRESENT BIT(0) /* NonERP_Present bit */ +#define ERP_INFO_USE_PROTECTION BIT(1) /* Use_Protection bit */ +#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2) /* Barker_Preamble_Mode bit */ + +#define ELEM_MAX_LEN_SUPPORTED_CHANNELS (MAX_CHN_NUM * \ + 2) + +/* 7.3.2.14 Extended Supported Rates */ +#define ELEM_MAX_LEN_EXTENDED_SUP_RATES 255 + +/* 7.3.2.16 Power Capability element */ +#define ELEM_MAX_LEN_POWER_CAP 2 + +/* 7.3.2.21 Measurement Request element */ +#define ELEM_RM_TYPE_BASIC_REQ 0 +#define ELEM_RM_TYPE_CCA_REQ 1 +#define ELEM_RM_TYPE_RPI_HISTOGRAM_REQ 2 +#define ELEM_RM_TYPE_CHNL_LOAD_REQ 3 +#define ELEM_RM_TYPE_NOISE_HISTOGRAM_REQ 4 +#define ELEM_RM_TYPE_BEACON_REQ 5 +#define ELEM_RM_TYPE_FRAME_REQ 6 +#define ELEM_RM_TYPE_STA_STATISTICS_REQ 7 +#define ELEM_RM_TYPE_LCI_REQ 8 +#define ELEM_RM_TYPE_TS_REQ 9 +#define ELEM_RM_TYPE_MEASURE_PAUSE_REQ 255 + +/* 7.3.2.22 Measurement Report element */ +#define ELEM_RM_TYPE_BASIC_REPORT 0 +#define ELEM_RM_TYPE_CCA_REPORT 1 +#define ELEM_RM_TYPE_RPI_HISTOGRAM_REPORT 2 +#define ELEM_RM_TYPE_CHNL_LOAD_REPORT 3 +#define ELEM_RM_TYPE_NOISE_HISTOGRAM_REPORT 4 +#define ELEM_RM_TYPE_BEACON_REPORT 5 +#define ELEM_RM_TYPE_FRAME_REPORT 6 +#define ELEM_RM_TYPE_STA_STATISTICS_REPORT 7 +#define ELEM_RM_TYPE_LCI_REPORT 8 +#define ELEM_RM_TYPE_TS_REPORT 9 + +/* 7.3.2.37 Subelement IDs for Neighbor Report, Table 7-43b */ +#define ELEM_ID_NR_BSS_TRANSITION_CAND_PREF 3 +#define ELEM_ID_NR_BSS_TERMINATION_DURATION 4 + +/* 7.3.2.25 RSN information element */ +#define ELEM_MAX_LEN_WPA 34 /* one pairwise, one AKM suite, one PMKID */ +#define ELEM_MAX_LEN_RSN 38 /* one pairwise, one AKM suite, one PMKID */ +#define ELEM_MAX_LEN_WAPI 38 /* one pairwise, one AKM suite, one BKID */ +#define ELEM_MAX_LEN_WSC 200 /* one pairwise, one AKM suite, one BKID */ + +/* 802.11i */ +/* length of one PMKID */ +#define RSN_PMKID_LEN 16 + +#if CFG_SUPPORT_802_11W +#define ELEM_WPA_CAP_MFPR BIT(6) +#define ELEM_WPA_CAP_MFPC BIT(7) +#endif + +/* 7.3.2.27 Extended Capabilities information element */ +#define ELEM_EXT_CAP_20_40_COEXIST_SUPPORT BIT(0) +#define ELEM_EXT_CAP_PSMP_CAP BIT(4) +#define ELEM_EXT_CAP_SERVICE_INTERVAL_GRANULARITY BIT(5) +#define ELEM_EXT_CAP_SCHEDULE_PSMP BIT(6) + +#define ELEM_EXT_CAP_BSS_TRANSITION_BIT 19 +#define ELEM_EXT_CAP_UTC_TSF_OFFSET_BIT 27 +#define ELEM_EXT_CAP_INTERWORKING_BIT 31 +#define ELEM_EXT_CAP_WNM_NOTIFICATION_BIT 46 +#define ELEM_EXT_CAP_OP_MODE_NOTIFICATION_BIT 62 + +#define ELEM_MAX_LEN_EXT_CAP (8) + +/* 7.3.2.30 TSPEC element */ +#define TS_INFO_TRAFFIC_TYPE_MASK \ + BIT(0) /* WMM: 0 (Asynchronous TS of low-duty cycles) */ +#define TS_INFO_TID_OFFSET 1 +#define TS_INFO_TID_MASK BITS(1, 4) +#define TS_INFO_DIRECTION_OFFSET 5 +#define TS_INFO_DIRECTION_MASK BITS(5, 6) +#define TS_INFO_ACCESS_POLICY_OFFSET 7 +#define TS_INFO_ACCESS_POLICY_MASK BITS(7, 8) +#define TS_INFO_AGGREGATION_MASK BIT(9) /* WMM: 0 */ +#define TS_INFO_APSD_MASK BIT(10) +#define TS_INFO_UP_OFFSET 11 +#define TS_INFO_UP_MASK BITS(11, 13) +#define TS_INFO_ACK_POLICY_OFFSET 14 +#define TS_INFO_ACK_POLICY_MASK BITS(14, 15) +#define TS_INFO_SCHEDULE_MASK 16 + +/* 7.3.2.45 RRM Enabled Capabilities element */ +#define ELEM_MAX_LEN_RRM_CAP 5 +#define RRM_CAP_INFO_LINK_MEASURE_BIT 0 +#define RRM_CAP_INFO_NEIGHBOR_REPORT_BIT 1 +#define RRM_CAP_INFO_REPEATED_MEASUREMENT 3 +#define RRM_CAP_INFO_BEACON_PASSIVE_MEASURE_BIT 4 +#define RRM_CAP_INFO_BEACON_ACTIVE_MEASURE_BIT 5 +#define RRM_CAP_INFO_BEACON_TABLE_BIT 6 +#define RRM_CAP_INFO_TSM_BIT 14 +#define RRM_CAP_INFO_RRM_BIT 17 + +/* 7.3.2.56 HT capabilities element */ +#define ELEM_MAX_LEN_HT_CAP (28 - \ + ELEM_HDR_LEN) \ + /* sizeof(IE_HT_CAP_T)-2 */ + +/* 7.3.2.56.2 HT capabilities Info field */ +#define HT_CAP_INFO_LDPC_CAP BIT(0) +#define HT_CAP_INFO_SUP_CHNL_WIDTH BIT(1) +#define HT_CAP_INFO_SM_POWER_SAVE BITS(2, 3) +#define HT_CAP_INFO_SM_POWER_SAVE_OFFSET 2 +#define HT_CAP_INFO_HT_GF BIT(4) +#define HT_CAP_INFO_SHORT_GI_20M BIT(5) +#define HT_CAP_INFO_SHORT_GI_40M BIT(6) +#define HT_CAP_INFO_TX_STBC BIT(7) +#define HT_CAP_INFO_RX_STBC BITS(8, 9) +#define HT_CAP_INFO_HT_DELAYED_BA BIT(10) +#define HT_CAP_INFO_MAX_AMSDU_LEN BIT(11) +#define HT_CAP_INFO_DSSS_CCK_IN_40M BIT(12) +#define HT_CAP_INFO_40M_INTOLERANT BIT(14) +#define HT_CAP_INFO_LSIG_TXOP_SUPPORT BIT(15) + +#define HT_CAP_INFO_RX_STBC_NO_SUPPORTED 0 +#define HT_CAP_INFO_RX_STBC_1_SS BIT(8) +#define HT_CAP_INFO_RX_STBC_2_SS BIT(9) +#define HT_CAP_INFO_RX_STBC_3_SS \ + HT_CAP_INFO_RX_STBC + +#define ELEM_MAX_LEN_VHT_CAP (14 - \ + ELEM_HDR_LEN) \ + /* sizeof(IE_VHT_CAP_T)-2 */ +/* 8.4.2.161 VHT Operation element */ +#define ELEM_MAX_LEN_VHT_OP (7 - \ + ELEM_HDR_LEN) \ + /* sizeof(IE_VHT_OP_T)-2 */ + +#define ELEM_MAX_LEN_VHT_OP_MODE_NOTIFICATION \ + (3 - ELEM_HDR_LEN) /* sizeof(IE_VHT_OP_MODE_T)-2 */ + +/*8.4.2.160.3 VHT Supported MCS Set field*/ + +/*8.4.2.160.2 VHT Capabilities Info field*/ +#define VHT_CAP_INFO_MAX_MPDU_LEN_3K 0 +#define VHT_CAP_INFO_MAX_MPDU_LEN_8K BIT(0) +#define VHT_CAP_INFO_MAX_MPDU_LEN_11K BIT(1) +#define VHT_CAP_INFO_MAX_MPDU_LEN_MASK BITS(0, 1) + +#define VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_SET_NONE 0 +#define VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_SET_160 BIT(2) +#define VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_SET_160_80P80 BIT(3) +#define VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_MASK BITS(2, 3) + +#define VHT_CAP_INFO_RX_LDPC BIT(4) +#define VHT_CAP_INFO_SHORT_GI_80 BIT(5) +#define VHT_CAP_INFO_SHORT_GI_160_80P80 BIT(6) +#define VHT_CAP_INFO_TX_STBC BIT(7) + +#define VHT_CAP_INFO_RX_STBC_NONE 0 +#define VHT_CAP_INFO_RX_STBC_MASK BITS(8, 10) +#define VHT_CAP_INFO_RX_STBC_OFFSET 8 +#define VHT_CAP_INFO_RX_STBC_ONE_STREAM BIT(8) +#define VHT_CAP_INFO_RX_STBC_TWO_STREAM BIT(9) +#define VHT_CAP_INFO_RX_STBC_THREE_STREAM BITS(8, 9) +#define VHT_CAP_INFO_RX_STBC_FOUR_STREAM BIT(10) + +#define VHT_CAP_INFO_SU_BEAMFORMER_CAPABLE BIT(11) +#define VHT_CAP_INFO_SU_BEAMFORMEE_CAPABLE BIT(12) +#define VHT_CAP_INFO_SU_BEAMFORMEE_CAPABLE_OFFSET 12 + +#define VHT_CAP_INFO_COMP_STEERING_NUM_OF_BFER_ANT_SUP_OFFSET 13 +#define VHT_CAP_INFO_COMP_STEERING_NUM_OF_BFER_ANT_SUP BITS(13, 15) +#define \ + VHT_CAP_INFO_COMPRESSED_STEERING_NUMBER_OF_BEAMFORMER_ANTENNAS_2_SUPPOERTED \ + BIT(13) +#define \ + VHT_CAP_INFO_COMPRESSED_STEERING_NUMBER_OF_BEAMFORMER_ANTENNAS_3_SUPPOERTED \ + BIT(14) +#define \ + VHT_CAP_INFO_COMPRESSED_STEERING_NUMBER_OF_BEAMFORMER_ANTENNAS_4_SUPPOERTED \ + BITS(13, 14) + +#define VHT_CAP_INFO_NUMBER_OF_SOUNDING_DIMENSIONS_OFFSET 16 +#define VHT_CAP_INFO_NUMBER_OF_SOUNDING_DIMENSIONS BITS(16, 18) +#define VHT_CAP_INFO_NUMBER_OF_SOUNDING_DIMENSIONS_2_SUPPORTED BIT(16) +#define VHT_CAP_INFO_NUMBER_OF_SOUNDING_DIMENSIONS_3_SUPPORTED BIT(17) +#define VHT_CAP_INFO_NUMBER_OF_SOUNDING_DIMENSIONS_4_SUPPORTED BITS(16, 17) + +#define VHT_CAP_INFO_MU_BEAMFOMER_CAPABLE BIT(19) +#define VHT_CAP_INFO_MU_BEAMFOMEE_CAPABLE BIT(20) +#define VHT_CAP_INFO_VHT_TXOP_PS BIT(21) +#define VHT_CAP_INFO_HTC_VHT_CAPABLE BIT(22) + +#define VHT_CAP_INFO_MAX_AMPDU_LENGTH_OFFSET 23 + +#define VHT_CAP_INFO_VHT_LINK_ADAPTATION_CAPABLE_NOFEEDBACK 0 +#define VHT_CAP_INFO_VHT_LINK_ADAPTATION_CAPABLE_UNSOLICITED BITS(27) +#define VHT_CAP_INFO_VHT_LINK_ADAPTATION_CAPABLE_BOTH BITS(26, 27) + +#define VHT_CAP_INFO_RX_ANTENNA_PATTERN_CONSISTENCY BIT(28) +#define VHT_CAP_INFO_TX_ANTENNA_PATTERN_CONSISTENCY BIT(29) + +#define VHT_CAP_INFO_MCS_MAP_MCS7 0 +#define VHT_CAP_INFO_MCS_MAP_MCS8 BIT(0) +#define VHT_CAP_INFO_MCS_MAP_MCS9 BIT(1) +#define VHT_CAP_INFO_MCS_NOT_SUPPORTED BITS(0, 1) + +#define VHT_CAP_INFO_MCS_1SS_OFFSET 0 +#define VHT_CAP_INFO_MCS_2SS_OFFSET 2 +#define VHT_CAP_INFO_MCS_3SS_OFFSET 4 +#define VHT_CAP_INFO_MCS_4SS_OFFSET 6 +#define VHT_CAP_INFO_MCS_5SS_OFFSET 8 +#define VHT_CAP_INFO_MCS_6SS_OFFSET 10 +#define VHT_CAP_INFO_MCS_7SS_OFFSET 12 +#define VHT_CAP_INFO_MCS_8SS_OFFSET 14 + +#define VHT_CAP_INFO_MCS_1SS_MASK BITS(0, 1) +#define VHT_CAP_INFO_MCS_2SS_MASK BITS(2, 3) +#define VHT_CAP_INFO_MCS_3SS_MASK BITS(4, 5) +#define VHT_CAP_INFO_MCS_4SS_MASK BITS(6, 7) +#define VHT_CAP_INFO_MCS_5SS_MASK BITS(8, 9) +#define VHT_CAP_INFO_MCS_6SS_MASK BITS(10, 11) +#define VHT_CAP_INFO_MCS_7SS_MASK BITS(12, 13) +#define VHT_CAP_INFO_MCS_8SS_MASK BITS(14, 15) + +#define VHT_OP_CHANNEL_WIDTH_20_40 0 +#define VHT_OP_CHANNEL_WIDTH_80 1 +#define VHT_OP_CHANNEL_WIDTH_160 2 +#define VHT_OP_CHANNEL_WIDTH_80P80 3 + +/*8.4.1.50 Operating Mode Field*/ +#define VHT_OP_MODE_CHANNEL_WIDTH BITS(0, 1) +#define VHT_OP_MODE_RX_NSS BITS(4, 6) +#define VHT_OP_MODE_RX_NSS_TYPE BIT(7) + +#define VHT_OP_MODE_CHANNEL_WIDTH_OFFSET 0 +#define VHT_OP_MODE_RX_NSS_OFFSET 4 +#define VHT_OP_MODE_RX_NSS_TYPE_OFFSET 7 + +#define VHT_OP_MODE_CHANNEL_WIDTH_20 0 +#define VHT_OP_MODE_CHANNEL_WIDTH_40 1 +#define VHT_OP_MODE_CHANNEL_WIDTH_80 2 +#define VHT_OP_MODE_CHANNEL_WIDTH_160_80P80 3 + +/* 8.4.1.22 SM Power Control field*/ +#define HT_SM_POWER_SAVE_CONTROL_ENABLED BIT(0) +#define HT_SM_POWER_SAVE_CONTROL_SM_MODE BIT(1) /* 0:static, 1:dynamic */ +#define HT_SM_POWER_SAVE_CONTROL_SM_MODE_OFFSET 1 + +/* 8.4.1.21 Channel Width field */ +#define HT_NOTIFY_CHANNEL_WIDTH_20 0 +#define HT_NOTIFY_CHANNEL_WIDTH_ANY_SUPPORT_CAHNNAEL_WIDTH 1 + +/* 7.3.2.56.3 A-MPDU Parameters field */ +#define AMPDU_PARAM_MAX_AMPDU_LEN_EXP BITS(0, 1) +#define AMPDU_PARAM_MIN_START_SPACING BITS(2, 4) + +#define AMPDU_PARAM_MAX_AMPDU_LEN_8K 0 +#define AMPDU_PARAM_MAX_AMPDU_LEN_16K BIT(0) +#define AMPDU_PARAM_MAX_AMPDU_LEN_32K BIT(1) +#define AMPDU_PARAM_MAX_AMPDU_LEN_64K BITS(0, 1) +#define AMPDU_PARAM_MAX_AMPDU_LEN_128K BIT(2) +#define AMPDU_PARAM_MAX_AMPDU_LEN_256K (BIT(2) | \ + BIT(0)) +#define AMPDU_PARAM_MAX_AMPDU_LEN_512K BITS(1, 2) +#define AMPDU_PARAM_MAX_AMPDU_LEN_1024K BITS(0, 2) + +#define AMPDU_PARAM_MSS_NO_RESTRICIT 0 +#define AMPDU_PARAM_MSS_1_4_US BIT(2) +#define AMPDU_PARAM_MSS_1_2_US BIT(3) +#define AMPDU_PARAM_MSS_1_US BITS(2, 3) +#define AMPDU_PARAM_MSS_2_US BIT(4) +#define AMPDU_PARAM_MSS_4_US (BIT(4) | \ + BIT(2)) +#define AMPDU_PARAM_MSS_8_US (BIT(4) | \ + BIT(3)) +#define AMPDU_PARAM_MSS_16_US BITS(2, 4) + +/* 7.3.2.56.4 Supported MCS Set field (TX rate: octects 12~15) */ +#define SUP_MCS_TX_SET_DEFINED BIT(0) +#define SUP_MCS_TX_RX_SET_NOT_EQUAL BIT(1) +#define SUP_MCS_TX_MAX_NUM_SS BITS(2, 3) +#define SUP_MCS_TX_UNEQUAL_MODULATION BIT(4) + +#define SUP_MCS_TX_MAX_NUM_1_SS 0 +#define SUP_MCS_TX_MAX_NUM_2_SS BIT(2) +#define SUP_MCS_TX_MAX_NUM_3_SS BIT(3) +#define SUP_MCS_TX_MAX_NUM_4_SS BITS(2, 3) + +#define SUP_MCS_RX_BITMASK_OCTET_NUM 10 +#define SUP_MCS_RX_DEFAULT_HIGHEST_RATE 0 /* Not specify */ + +/* 7.3.2.56.5 HT Extended Capabilities field */ +#define HT_EXT_CAP_PCO BIT(0) +#define HT_EXT_CAP_PCO_TRANSITION_TIME BITS(1, 2) +#define HT_EXT_CAP_MCS_FEEDBACK BITS(8, 9) +#define HT_EXT_CAP_HTC_SUPPORT BIT(10) +#define HT_EXT_CAP_RD_RESPONDER BIT(11) + +#define HT_EXT_CAP_PCO_TRANS_TIME_NONE 0 +#define HT_EXT_CAP_PCO_TRANS_TIME_400US BIT(1) +#define HT_EXT_CAP_PCO_TRANS_TIME_1_5MS BIT(2) +#define HT_EXT_CAP_PCO_TRANS_TIME_5MS BITS(1, 2) + +#define HT_EXT_CAP_MCS_FEEDBACK_NO_FB 0 +#define HT_EXT_CAP_MCS_FEEDBACK_UNSOLICITED BIT(9) +#define HT_EXT_CAP_MCS_FEEDBACK_BOTH BITS(8, 9) + +/* 7.3.2.56.6 Transmit Beamforming Capabilities field */ +#define TXBF_IMPLICIT_RX_CAPABLE BIT(0) +#define TXBF_RX_STAGGERED_SOUNDING_CAPABLE BIT(1) +#define TXBF_TX_STAGGERED_SOUNDING_CAPABLE BIT(2) +#define TXBF_RX_NDP_CAPABLE_OFFSET 3 +#define TXBF_RX_NDP_CAPABLE BIT(3) +#define TXBF_TX_NDP_CAPABLE BIT(4) +#define TXBF_IMPLICIT_TX_CAPABLE BIT(5) +#define TXBF_CALIBRATION_CAPABLE BITS(6, 7) +#define TXBF_EXPLICIT_CSI_TX_CAPABLE BIT(8) +#define TXBF_EXPLICIT_NONCOMPRESSED_TX_CAPABLE BIT(9) +#define TXBF_EXPLICIT_COMPRESSED_TX_CAPAB BIT(10) +#define TXBF_EXPLICIT_CSI_FEEDBACK_CAPABLE BITS(11, 12) +#define TXBF_EXPLICIT_NONCOMPRESSED_FEEDBACK_CAPABLE BITS(13, 14) + +#define TXBF_EXPLICIT_COMPRESSED_FEEDBACK_CAPABLE_OFFSET 15 +#define TXBF_EXPLICIT_COMPRESSED_FEEDBACK_CAPABLE BITS(15, 16) +#define TXBF_EXPLICIT_COMPRESSED_FEEDBACK_IMMEDIATE_CAPABLE BIT(16) + +#define TXBF_MINIMAL_GROUPING_CAPABLE BITS(17, 18) +#define TXBF_MINIMAL_GROUPING_1_2_3_CAPABLE BITS(17, 18) + +#define TXBF_CSI_BFER_ANTENNANUM_SUPPORTED BITS(19, 20) +#define TXBF_NONCOMPRESSED_TX_ANTENNANUM_SUPPORTED BITS(21, 22) + +#define TXBF_COMPRESSED_TX_ANTENNANUM_SUPPORTED_OFFSET 23 +#define TXBF_COMPRESSED_TX_ANTENNANUM_SUPPORTED BITS(23, 24) +#define TXBF_COMPRESSED_TX_ANTENNANUM_4_SUPPORTED BITS(23, 24) + +#define TXBF_CSI_MAX_ROWS_BFER_SUPPORTED BITS(25, 26) + +#define TXBF_CHANNEL_ESTIMATION_CAPABILITY BITS(27, 28) +#define TXBF_CHANNEL_ESTIMATION_4STS_CAPABILITY BITS(27, 28) + +/* 7.3.2.56.7 Antenna Selection Capability field */ +#define ASEL_CAP_CAPABLE BIT(0) +#define ASEL_CAP_CSI_FB_BY_TX_ASEL_CAPABLE BIT(1) +#define ASEL_CAP_ANT_INDICES_FB_BY_TX_ASEL_CAPABLE BIT(2) +#define ASEL_CAP_EXPLICIT_CSI_FB_CAPABLE BIT(3) +#define ASEL_CAP_ANT_INDICES_CAPABLE BIT(4) +#define ASEL_CAP_RX_ASEL_CAPABLE BIT(5) +#define ASEL_CAP_TX_SOUNDING_CAPABLE BIT(6) + +/* 7.3.2.57 HT Operation element */ +#define ELEM_MAX_LEN_HT_OP (24 - \ + ELEM_HDR_LEN) \ + /* sizeof(IE_HT_OP_T)-2 */ + +#define HT_OP_INFO1_SCO BITS(0, 1) +#define HT_OP_INFO1_STA_CHNL_WIDTH BIT(2) +#define HT_OP_INFO1_RIFS_MODE BIT(3) + +#define HT_OP_INFO2_HT_PROTECTION BITS(0, 1) +#define HT_OP_INFO2_NON_GF_HT_STA_PRESENT BIT(2) +#define HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT BIT(4) + +#define HT_OP_INFO3_DUAL_BEACON BIT(6) +#define HT_OP_INFO3_DUAL_CTS_PROTECTION BIT(7) +#define HT_OP_INFO3_STBC_BEACON BIT(8) +#define HT_OP_INFO3_LSIG_TXOP_FULL_SUPPORT BIT(9) +#define HT_OP_INFO3_PCO_ACTIVE BIT(10) +#define HT_OP_INFO3_PCO_PHASE BIT(11) + +/* 7.3.2.59 OBSS Scan Parameter element */ +#define ELEM_MAX_LEN_OBSS_SCAN (16 - \ + ELEM_HDR_LEN) + +/* 7.3.2.60 20/40 BSS Coexistence element */ +#define ELEM_MAX_LEN_20_40_BSS_COEXIST (3 - \ + ELEM_HDR_LEN) + +#define BSS_COEXIST_INFO_REQ BIT(0) +#define BSS_COEXIST_40M_INTOLERANT BIT(1) +#define BSS_COEXIST_20M_REQ BIT(2) +#define BSS_COEXIST_OBSS_SCAN_EXEMPTION_REQ BIT(3) +#define BSS_COEXIST_OBSS_SCAN_EXEMPTION_GRANT BIT(4) + +#define BSS_MAX_IDLE_PROTECTED_REQUIRED BIT(0) + +/* 802.11u 7.3.2.92 Interworking IE */ +#define ELEM_MAX_LEN_INTERWORKING (11 - \ + ELEM_HDR_LEN) + +/* 802.11u 7.3.2.93 Advertisement Protocol IE */ +#define ELEM_MAX_LEN_ADV_PROTOCOL (4 - \ + ELEM_HDR_LEN) + +/* 802.11u 7.3.2.96 Roaming Consortium IE */ +#define ELEM_MAX_LEN_ROAMING_CONSORTIUM (19 - \ + ELEM_HDR_LEN) + +#define IW_IE_LENGTH_ANO 1 +#define IW_IE_LENGTH_ANO_VENUE 3 +#define IW_IE_LENGTH_ANO_HESSID 7 +#define IW_IE_LENGTH_ANO_VENUE_HESSID 9 + +/* MTK Vendor Specific OUI */ +#define ELEM_MIN_LEN_MTK_OUI 7 +#define VENDOR_OUI_MTK \ + { \ + 0x00, 0x0C, 0xE7 \ + } +#define MTK_SYNERGY_CAP_SUPPORT_24G_MCS89 BIT(3) +#define MTK_SYNERGY_CAP0 ( \ + MTK_SYNERGY_CAP_SUPPORT_24G_MCS89) +#define MTK_SYNERGY_CAP1 0x0 +#define MTK_SYNERGY_CAP2 0x0 +#define MTK_SYNERGY_CAP3 0x0 + +/* 802.11h CSA element */ +#define ELEM_MIN_LEN_CSA 3 + +/* 3 Management frame body components (III): 7.4 Action frame format details. */ +/* 7.4.1 Spectrum Measurement Action frame details */ +#define ACTION_MEASUREMENT_REQ 0 /* Spectrum measurement request */ +#define ACTION_MEASUREMENT_REPORT 1 /* Spectrum measurement report */ +#define ACTION_TPC_REQ 2 /* TPC request */ +#define ACTION_TPC_REPORT 3 /* TPC report */ +#define ACTION_CHNL_SWITCH 4 /* Channel Switch Announcement */ + +#define ACTION_SM_TPC_REQ_LEN 5 +#define ACTION_SM_TPC_REPORT_LEN 7 +#define ACTION_SM_MEASURE_REQ_LEN 19 +#define ACTION_SM_MEASURE_REPORT_LEN 8 +#define ACTION_SM_BASIC_REPORT_LEN 12 +#define ACTION_SM_CCA_REPORT_LEN 12 +#define ACTION_SM_PRI_REPORT_LEN 19 +#define MIN_RCV_PWR 100 /* Negative value ((dBm) */ + +/* 7.4.2 QoS Action frame details */ +#define ACTION_ADDTS_REQ 0 /* ADDTS request */ +#define ACTION_ADDTS_RSP 1 /* ADDTS response */ +#define ACTION_DELTS 2 /* DELTS */ +#define ACTION_SCHEDULE 3 /* Schedule */ + +#define ACTION_ADDTS_REQ_FRAME_LEN (24 + 3 + 63) /* WMM TSPEC IE: 63 */ +#define ACTION_ADDTS_RSP_FRAME_LEN \ + (24 + 4 + 63) /* WMM Status Code: 1; WMM TSPEC IE: 63 */ + +/* 7.4.3 DLS Action frame details */ +#define ACTION_DLS_REQ 0 /* DLS request */ +#define ACTION_DLS_RSP 1 /* DLS response */ +#define ACTION_DLS_TEARDOWN 2 /* DLS teardown */ + +/* 7.4.4 Block ack Action frame details */ +#define ACTION_ADDBA_REQ 0 /* ADDBA request */ +#define ACTION_ADDBA_RSP 1 /* ADDBA response */ +#define ACTION_DELBA 2 /* DELBA */ + +#define ACTION_ADDBA_REQ_FRAME_LEN (24 + 9) +#define ACTION_ADDBA_RSP_FRAME_LEN (24 + 9) + +#define ACTION_DELBA_INITIATOR_MASK BIT(11) +#define ACTION_DELBA_TID_MASK BITS(12, 15) +#define ACTION_DELBA_TID_OFFSET 12 +#define ACTION_DELBA_FRAME_LEN (24 + 6) + +/* 7.4.6 Radio Measurement Action frame details */ +#define ACTION_RM_REQ 0 /* Radio measurement request */ +#define ACTION_RM_REPORT 1 /* Radio measurement report */ +#define ACTION_LM_REQ 2 /* Link measurement request */ +#define ACTION_LM_REPORT 3 /* Link measurement report */ +#define ACTION_NEIGHBOR_REPORT_REQ 4 /* Neighbor report request */ +#define ACTION_NEIGHBOR_REPORT_RSP 5 /* Neighbor report response */ + +/* 7.4.7 Public Action frame details */ +#define ACTION_PUBLIC_20_40_COEXIST 0 /* 20/40 BSS coexistence */ +/* 20/40 BSS coexistence */ +#define ACTION_PUBLIC_VENDOR_SPECIFIC 9 + +#if CFG_SUPPORT_802_11W +/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */ +#define ACTION_SA_QUERY_REQUEST 0 +#define ACTION_SA_QUERY_RESPONSE 1 + +#define ACTION_SA_QUERY_TR_ID_LEN 2 + +/* Timeout Interval Type */ +#define ACTION_SA_TIMEOUT_REASSOC_DEADLINE 1 +#define ACTION_SA_TIMEOUT_KEY_LIFETIME 2 +#define ACTION_SA_TIMEOUT_ASSOC_COMEBACK 3 +#endif + +/* 7.4.10.1 HT action frame details */ +#define ACTION_HT_NOTIFY_CHANNEL_WIDTH 0 /* Notify Channel Width */ +#define ACTION_HT_SM_POWER_SAVE 1 /* SM Power Save */ +#define ACTION_HT_PSMP 2 /* PSMP */ +#define ACTION_HT_SET_PCO_PHASE 3 /* Set PCO Phase */ +#define ACTION_HT_CSI 4 /* CSI */ +#define ACTION_HT_NON_COMPRESSED_BEAMFORM 5 /* Non-compressed Beamforming */ +#define ACTION_HT_COMPRESSED_BEAMFORM 6 /* Compressed Beamforming */ +#define ACTION_HT_ANT_SEL_INDICES_FB \ + 7 /* Antenna Selection Indices Feedback \ + */ + +/* 802.11v Wireless Network Management */ +#define ACTION_WNM_TIMING_MEASUREMENT_REQUEST 27 + +#define ACTION_UNPROTECTED_WNM_TIM 0 +#define ACTION_UNPROTECTED_WNM_TIMING_MEASUREMENT 1 + +#define ACTION_WNM_BSS_TRANSITION_MANAGEMENT_QUERY 6 +#define ACTION_WNM_BSS_TRANSITION_MANAGEMENT_REQ 7 +#define ACTION_WNM_BSS_TRANSITION_MANAGEMENT_RSP 8 + +#define ACTION_UNPROTECTED_WNM_TIMING_MEAS_LEN 12 + +/* 8.5.23.1 VHT Action */ +#define ACTION_VHT_COMPRESSED_BFEAMFORMING 0 +#define ACTION_GROUP_ID_MANAGEMENT 1 +#define ACTION_OPERATING_MODE_NOTIFICATION 2 + +/* 3 --------------- WFA frame body fields --------------- */ +#define VENDOR_OUI_WFA \ + { \ + 0x00, 0x50, 0xF2 \ + } +#define VENDOR_OUI_WFA_SPECIFIC \ + { \ + 0x50, 0x6F, 0x9A \ + } +#define VENDOR_OUI_TYPE_WPA 1 +#define VENDOR_OUI_TYPE_WMM 2 +#define VENDOR_OUI_TYPE_WPS 4 +#define VENDOR_OUI_TYPE_P2P 9 +#define VENDOR_OUI_TYPE_WFD 10 + +#define VENDOR_OUI_TYPE_LEN 4 /* Length of OUI and Type */ + +/* VERSION(2 octets for WPA) / SUBTYPE(1 octet)-VERSION(1 octet) fields for WMM + * in WFA IE */ +#define VERSION_WPA 0x0001 /* Little Endian Format */ +#define VENDOR_OUI_SUBTYPE_VERSION_WMM_INFO 0x0100 +#define VENDOR_OUI_SUBTYPE_VERSION_WMM_PARAM 0x0101 + +/* SUBTYPE(1 octet) for WMM */ +#define VENDOR_OUI_SUBTYPE_WMM_INFO 0x00 /* WMM Spec version 1.1 */ +#define VENDOR_OUI_SUBTYPE_WMM_PARAM 0x01 +#define VENDOR_OUI_SUBTYPE_WMM_TSPEC 0x02 + +/* VERSION(1 octet) for WMM */ +#define VERSION_WMM 0x01 /* WMM Spec version 1.1 */ + +/* WMM-2.1.6 QoS Control Field */ +#define WMM_QC_UP_MASK BITS(0, 2) +#define WMM_QC_EOSP BIT(4) +#define WMM_QC_ACK_POLICY_MASK BITS(5, 6) +#define WMM_QC_ACK_POLICY_OFFSET 5 +#define WMM_QC_ACK_POLICY_ACKNOWLEDGE 0 +#define WMM_QC_ACK_POLICY_NOT_ACKNOWLEDGE (1 << \ + WMM_QC_ACK_POLICY_OFFSET) + +/* WMM-2.2.1 WMM Information Element */ +#define ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE 6 + +/* 3 Control frame body */ +/* 7.2.1.7 BlockAckReq */ +#define CTRL_BAR_BAR_CONTROL_OFFSET 16 +#define CTRL_BAR_BAR_CONTROL_TID_OFFSET 12 +#define CTRL_BAR_BAR_INFORMATION_OFFSET 18 +#define CTRL_BAR_BAR_INFORMATION_SSN_OFFSET 4 + +/* 802.11-2012, 8.5.7 Radio Measurement action fields, table 8-206 */ +#define RM_ACTION_RM_REQUEST 0 +#define RM_ACTION_RM_REPORT 1 +#define RM_ACTION_LM_REQUEST 2 +#define RM_ACTION_LM_REPORT 3 +#define RM_ACTION_NEIGHBOR_REQUEST 4 +#define RM_ACTION_REIGHBOR_RESPONSE 5 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) +#pragma pack(1) +#endif + +typedef struct _LLC_SNAP_HEADER_T { + u8 ucDSAP; + u8 ucSSAP; + u8 ucControl; + u8 aucCode[3]; + u16 u2Type; +} __KAL_ATTRIB_PACKED__ LLC_SNAP_HEADER_T, *P_LLC_SNAP_HEADER_T; + +/* 3 MAC Header. */ +/* Ethernet Frame Header */ +typedef struct _ETH_FRAME_HEADER_T { + u8 aucDestAddr[MAC_ADDR_LEN]; + u8 aucSrcAddr[MAC_ADDR_LEN]; + u16 u2TypeLen; +} __KAL_ATTRIB_PACKED__ ETH_FRAME_HEADER_T, *P_ETH_FRAME_HEADER_T; + +/* Ethernet Frame Structure */ +typedef struct _ETH_FRAME_T { + u8 aucDestAddr[MAC_ADDR_LEN]; + u8 aucSrcAddr[MAC_ADDR_LEN]; + u16 u2TypeLen; + u8 aucData[1]; +} __KAL_ATTRIB_PACKED__ ETH_FRAME_T, *P_ETH_FRAME_T; + +typedef struct _BOOTP_PROTOCOL_T { + u8 ucOperation; + u8 ucHdrType; + u8 ucHdrLen; + u8 ucHops; + u32 u4TransId; + u16 u2Seconds; + u16 u2Flags; + u32 u4CIAddr; + u32 u4YIAddr; + u32 u4SIAddr; + u32 u4GIAddr; + u8 aucCHAddr[16]; + u8 aucServerName[64]; + u8 aucFileName[128]; + u8 aucOptions[0]; +} __KAL_ATTRIB_PACKED__ BOOTP_PROTOCOL_T, *P_BOOTP_PROTOCOL_T; + +/* IEEE 802.11 WLAN Frame Structure */ +/* WLAN MAC Header (without Address 4 and QoS Control fields) */ +typedef struct _WLAN_MAC_HEADER_T { + u16 u2FrameCtrl; + u16 u2DurationID; + u8 aucAddr1[MAC_ADDR_LEN]; + u8 aucAddr2[MAC_ADDR_LEN]; + u8 aucAddr3[MAC_ADDR_LEN]; + u16 u2SeqCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_T, *P_WLAN_MAC_HEADER_T; + +/* WLAN MAC Header (QoS Control fields included) */ +typedef struct _WLAN_MAC_HEADER_QOS_T { + u16 u2FrameCtrl; + u16 u2DurationID; + u8 aucAddr1[MAC_ADDR_LEN]; + u8 aucAddr2[MAC_ADDR_LEN]; + u8 aucAddr3[MAC_ADDR_LEN]; + u16 u2SeqCtrl; + u16 u2QosCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_QOS_T, *P_WLAN_MAC_HEADER_QOS_T; + +/* WLAN MAC Header (HT Control fields included) */ +typedef struct _WLAN_MAC_HEADER_HT_T { + u16 u2FrameCtrl; + u16 u2DurationID; + u8 aucAddr1[MAC_ADDR_LEN]; + u8 aucAddr2[MAC_ADDR_LEN]; + u8 aucAddr3[MAC_ADDR_LEN]; + u16 u2SeqCtrl; + u16 u2QosCtrl; + u32 u4HtCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_HT_T, *P_WLAN_MAC_HEADER_HT_T; + +/* WLAN MAC Header (Address 4 included) */ +typedef struct _WLAN_MAC_HEADER_A4_T { + u16 u2FrameCtrl; + u16 u2DurationID; + u8 aucAddr1[MAC_ADDR_LEN]; + u8 aucAddr2[MAC_ADDR_LEN]; + u8 aucAddr3[MAC_ADDR_LEN]; + u16 u2SeqCtrl; + u8 aucAddr4[MAC_ADDR_LEN]; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_T, *P_WLAN_MAC_HEADER_A4_T; + +/* WLAN MAC Header (Address 4 and QoS Control fields included) */ +typedef struct _WLAN_MAC_HEADER_A4_QOS_T { + u16 u2FrameCtrl; + u16 u2DurationID; + u8 aucAddr1[MAC_ADDR_LEN]; + u8 aucAddr2[MAC_ADDR_LEN]; + u8 aucAddr3[MAC_ADDR_LEN]; + u16 u2SeqCtrl; + u8 aucAddr4[MAC_ADDR_LEN]; + u16 u2QosCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_QOS_T, *P_WLAN_MAC_HEADER_A4_QOS_T; + +typedef struct _WLAN_MAC_HEADER_A4_HT_T { + u16 u2FrameCtrl; + u16 u2DurationID; + u8 aucAddr1[MAC_ADDR_LEN]; + u8 aucAddr2[MAC_ADDR_LEN]; + u8 aucAddr3[MAC_ADDR_LEN]; + u16 u2SeqCtrl; + u8 aucAddr4[MAC_ADDR_LEN]; + u16 u2QosCtrl; + u32 u4HtCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_HEADER_A4_HT_T, *P_WLAN_MAC_HEADER_A4_HT_T; + +/* 7.2.3 WLAN MAC Header for Management Frame - MMPDU */ +typedef struct _WLAN_MAC_MGMT_HEADER_T { + u16 u2FrameCtrl; + u16 u2Duration; + u8 aucDestAddr[MAC_ADDR_LEN]; + u8 aucSrcAddr[MAC_ADDR_LEN]; + u8 aucBSSID[MAC_ADDR_LEN]; + u16 u2SeqCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_MGMT_HEADER_T, *P_WLAN_MAC_MGMT_HEADER_T; + +/* WLAN MAC Header for Management Frame (HT Control fields included) */ +typedef struct _WLAN_MAC_MGMT_HEADER_HT_T { + u16 u2FrameCtrl; + u16 u2DurationID; + u8 aucAddr1[MAC_ADDR_LEN]; + u8 aucAddr2[MAC_ADDR_LEN]; + u8 aucAddr3[MAC_ADDR_LEN]; + u16 u2SeqCtrl; + u32 u4HtCtrl; +} __KAL_ATTRIB_PACKED__ WLAN_MAC_MGMT_HEADER_HT_T, *P_WLAN_MAC_MGMT_HEADER_HT_T; + +/* 3 WLAN CONTROL Frame */ +/* 7.2.1.4 WLAN Control Frame - PS-POLL Frame */ +typedef struct _CTRL_PSPOLL_FRAME_T { + u16 u2FrameCtrl; /* Frame Control */ + u16 u2AID; /* AID */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u8 aucTA[MAC_ADDR_LEN]; /* TA */ +} __KAL_ATTRIB_PACKED__ CTRL_PSPOLL_FRAME_T, *P_CTRL_PSPOLL_FRAME_T; + +/* BAR */ +typedef struct _CTRL_BAR_FRAME_T { + u16 u2FrameCtrl; /* Frame Control */ + u16 u2DurationID; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* RA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* TA */ + u16 u2BarControl; + u8 aucBarInfo[2]; /* Variable size */ +} __KAL_ATTRIB_PACKED__ CTRL_BAR_FRAME_T, *P_CTRL_BAR_FRAME_T; + +/* 3 WLAN Management Frame. */ +/* 7.2.3.1 WLAN Management Frame - Beacon Frame */ +typedef struct _WLAN_BEACON_FRAME_T { + /* Beacon header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2DurationID; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Beacon frame body */ + u32 au4Timestamp[2]; /* Timestamp */ + u16 u2BeaconInterval; /* Beacon Interval */ + u16 u2CapInfo; /* Capability */ + u8 aucInfoElem[1]; /* Various IEs, start from SSID */ +} __KAL_ATTRIB_PACKED__ WLAN_BEACON_FRAME_T, *P_WLAN_BEACON_FRAME_T; + +typedef struct _WLAN_BEACON_FRAME_BODY_T { + /* Beacon frame body */ + u32 au4Timestamp[2]; /* Timestamp */ + u16 u2BeaconInterval; /* Beacon Interval */ + u16 u2CapInfo; /* Capability */ + u8 aucInfoElem[1]; /* Various IEs, start from SSID */ +} __KAL_ATTRIB_PACKED__ WLAN_BEACON_FRAME_BODY_T, *P_WLAN_BEACON_FRAME_BODY_T; + +/* 7.2.3.3 WLAN Management Frame - Disassociation Frame */ +typedef struct _WLAN_DISASSOC_FRAME_T { + /* Authentication MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2DurationID; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Disassociation frame body */ + u16 u2ReasonCode; /* Reason code */ + u8 aucInfoElem[1]; /* Various IEs, possible no. */ +} __KAL_ATTRIB_PACKED__ WLAN_DISASSOC_FRAME_T, *P_WLAN_DISASSOC_FRAME_T; + +/* 7.2.3.4 WLAN Management Frame - Association Request frame */ +typedef struct _WLAN_ASSOC_REQ_FRAME_T { + /* Association Request MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2DurationID; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Association Request frame body */ + u16 u2CapInfo; /* Capability information */ + u16 u2ListenInterval; /* Listen interval */ + u8 aucInfoElem[1]; /* Information elements, include WPA IE */ +} __KAL_ATTRIB_PACKED__ WLAN_ASSOC_REQ_FRAME_T, *P_WLAN_ASSOC_REQ_FRAME_T; + +/* 7.2.3.5 WLAN Management Frame - Association Response frame */ +typedef struct _WLAN_ASSOC_RSP_FRAME_T { + /* Association Response MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2DurationID; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Association Response frame body */ + u16 u2CapInfo; /* Capability information */ + u16 u2StatusCode; /* Status code */ + u16 u2AssocId; /* Association ID */ + u8 aucInfoElem[1]; /* Information elements, such as */ + /* supported rates, and etc. */ +} __KAL_ATTRIB_PACKED__ WLAN_ASSOC_RSP_FRAME_T, *P_WLAN_ASSOC_RSP_FRAME_T; + +/* 7.2.3.6 WLAN Management Frame - Reassociation Request frame */ +typedef struct _WLAN_REASSOC_REQ_FRAME_T { + /* Reassociation Request MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2DurationID; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Reassociation Request frame body */ + u16 u2CapInfo; /* Capability information */ + u16 u2ListenInterval; /* Listen interval */ + u8 aucCurrentAPAddr[MAC_ADDR_LEN]; /* Current AP address */ + u8 aucInfoElem[1]; /* Information elements, include WPA IE */ +} __KAL_ATTRIB_PACKED__ WLAN_REASSOC_REQ_FRAME_T, *P_WLAN_REASSOC_REQ_FRAME_T; + +/* 7.2.3.7 WLAN Management Frame - Reassociation Response frame */ +/* (the same as Association Response frame) */ +typedef WLAN_ASSOC_RSP_FRAME_T WLAN_REASSOC_RSP_FRAME_T, + *P_WLAN_REASSOC_RSP_FRAME_T; + +/* 7.2.3.9 WLAN Management Frame - Probe Response Frame */ +typedef WLAN_BEACON_FRAME_T WLAN_PROBE_RSP_FRAME_T, *P_WLAN_PROBE_RSP_FRAME_T; + +/* 7.2.3.10 WLAN Management Frame - Authentication Frame */ +typedef struct _WLAN_AUTH_FRAME_T { + /* Authentication MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2DurationID; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Authentication frame body */ + u16 u2AuthAlgNum; /* Authentication algorithm number */ + u8 aucAuthData[AUTH_DATA_MAX_LEN]; + u8 aucInfoElem[1]; /* Various IEs for Fast BSS Transition */ +} __KAL_ATTRIB_PACKED__ WLAN_AUTH_FRAME_T, *P_WLAN_AUTH_FRAME_T; + +/* 7.2.3.11 WLAN Management Frame - Deauthentication Frame */ +typedef struct _WLAN_DEAUTH_FRAME_T { + /* Authentication MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2DurationID; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Deauthentication frame body */ + u16 u2ReasonCode; /* Reason code */ + u8 aucInfoElem[1]; /* Various IEs, possible no. */ +} __KAL_ATTRIB_PACKED__ WLAN_DEAUTH_FRAME_T, *P_WLAN_DEAUTH_FRAME_T; + +/* 3 Information Elements. */ +/* 7.3.2 Generic element format */ +typedef struct _IE_HDR_T { + u8 ucId; + u8 ucLength; + u8 aucInfo[1]; +} __KAL_ATTRIB_PACKED__ IE_HDR_T, *P_IE_HDR_T; + +/* 7.3.2.1 SSID element */ +typedef struct _IE_SSID_T { + u8 ucId; + u8 ucLength; + u8 aucSSID[ELEM_MAX_LEN_SSID]; +} __KAL_ATTRIB_PACKED__ IE_SSID_T, *P_IE_SSID_T; + +/* 7.3.2.2 Supported Rates element */ +typedef struct _IE_SUPPORTED_RATE_T { + u8 ucId; + u8 ucLength; + u8 aucSupportedRates[ELEM_MAX_LEN_SUP_RATES]; +} __KAL_ATTRIB_PACKED__ IE_SUPPORTED_RATE_T, *P_IE_SUPPORTED_RATE_T; + +/* Some IOT AP will carry Rates > 8*/ +typedef struct IE_SUPPORTED_RATE_IOT { + u8 ucId; + u8 ucLength; + u8 aucSupportedRates[ELEM_MAX_LEN_SUP_RATES_IOT]; +} __KAL_ATTRIB_PACKED__ IE_SUPPORTED_RATE_IOT_T, *P_IE_SUPPORTED_RATE_IOT_T; + +/* 7.3.2.4 DS Parameter Set element */ +typedef struct _IE_DS_PARAM_SET_T { + u8 ucId; + u8 ucLength; + u8 ucCurrChnl; +} __KAL_ATTRIB_PACKED__ IE_DS_PARAM_SET_T, *P_IE_DS_PARAM_SET_T; + +/* 7.3.2.5 CF Parameter Set element */ +typedef struct _IE_CF_PARAM_SET_T { + u8 ucId; + u8 ucLength; + u8 ucCFPCount; + u8 ucCFPPeriod; + u16 u2CFPMaxDur; + u16 u2DurRemaining; +} __KAL_ATTRIB_PACKED__ IE_CF_PARAM_SET_T, *P_IE_CF_PARAM_SET_T; + +/* 7.3.2.6 TIM */ +typedef struct _IE_TIM_T { + u8 ucId; + u8 ucLength; + u8 ucDTIMCount; + u8 ucDTIMPeriod; + u8 ucBitmapControl; + u8 aucPartialVirtualMap[1]; +} __KAL_ATTRIB_PACKED__ IE_TIM_T, *P_IE_TIM_T; + +/* 7.3.2.7 IBSS Parameter Set element */ +typedef struct _IE_IBSS_PARAM_SET_T { + u8 ucId; + u8 ucLength; + u16 u2ATIMWindow; +} __KAL_ATTRIB_PACKED__ IE_IBSS_PARAM_SET_T, *P_IE_IBSS_PARAM_SET_T; + +/* 7.3.2.8 Challenge Text element */ +typedef struct _IE_CHALLENGE_TEXT_T { + u8 ucId; + u8 ucLength; + u8 aucChallengeText[ELEM_MAX_LEN_CHALLENGE_TEXT]; +} __KAL_ATTRIB_PACKED__ IE_CHALLENGE_TEXT_T, *P_IE_CHALLENGE_TEXT_T; + +/* 7.3.2.9 Country information element */ +#if CFG_SUPPORT_802_11D +/*! \brief COUNTRY_INFO_TRIPLET is defined for the COUNTRY_INFO_ELEM structure. + */ +typedef struct _COUNTRY_INFO_TRIPLET_T { + u8 ucParam1; /*!< If param1 >= 201, this triplet is referred to as */ + /* Regulatory Triplet in 802_11J. */ + u8 ucParam2; + u8 ucParam3; +} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_TRIPLET_T, *P_COUNTRY_INFO_TRIPLET_T; + +typedef struct _COUNTRY_INFO_SUBBAND_TRIPLET_T { + u8 ucFirstChnlNum; /*!< First Channel Number */ + u8 ucNumOfChnl; /*!< Number of Channels */ + s8 cMaxTxPwrLv; /*!< Maximum Transmit Power Level */ +} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_SUBBAND_TRIPLET_T, +*P_COUNTRY_INFO_SUBBAND_TRIPLET_T; + +typedef struct _COUNTRY_INFO_REGULATORY_TRIPLET_T { + u8 ucRegExtId; /*!< Regulatory Extension Identifier, should */ + /* be greater than or equal to 201 */ + u8 ucRegClass; /*!< Regulatory Class */ + u8 ucCoverageClass; /*!< Coverage Class, unsigned 1-octet value 0~31 */ + /* , 32~255 reserved */ +} __KAL_ATTRIB_PACKED__ COUNTRY_INFO_REGULATORY_TRIPLET_T, +*P_COUNTRY_INFO_REGULATORY_TRIPLET_T; + +typedef struct _IE_COUNTRY_T { + u8 ucId; + u8 ucLength; + u8 aucCountryStr[3]; + COUNTRY_INFO_SUBBAND_TRIPLET_T arCountryStr[1]; +} __KAL_ATTRIB_PACKED__ IE_COUNTRY_T, *P_IE_COUNTRY_T; +#endif + +/* 7.3.2.13 ERP element */ +typedef struct _IE_ERP_T { + u8 ucId; + u8 ucLength; + u8 ucERP; +} __KAL_ATTRIB_PACKED__ IE_ERP_T, *P_IE_ERP_T; + +/* 7.3.2.14 Extended Supported Rates element */ +typedef struct _IE_EXT_SUPPORTED_RATE_T { + u8 ucId; + u8 ucLength; + u8 aucExtSupportedRates[ELEM_MAX_LEN_EXTENDED_SUP_RATES]; +} __KAL_ATTRIB_PACKED__ IE_EXT_SUPPORTED_RATE_T, *P_IE_EXT_SUPPORTED_RATE_T; + +/* 7.3.2.15 Power Constraint element */ +typedef struct _IE_POWER_CONSTRAINT_T { + u8 ucId; + u8 ucLength; + u8 ucLocalPowerConstraint; /* Unit: dBm */ +} __KAL_ATTRIB_PACKED__ IE_POWER_CONSTRAINT_T, *P_IE_POWER_CONSTRAINT_T; + +/* 7.3.2.16 Power Capability element */ +typedef struct _IE_POWER_CAP_T { + u8 ucId; + u8 ucLength; + s8 cMinTxPowerCap; /* Unit: dBm */ + s8 cMaxTxPowerCap; /* Unit: dBm */ +} __KAL_ATTRIB_PACKED__ IE_POWER_CAP_T, *P_IE_POWER_CAP_T; + +/* 7.3.2.17 TPC request element */ +typedef struct _IE_TPC_REQ_T { + u8 ucId; + u8 ucLength; +} __KAL_ATTRIB_PACKED__ IE_TPC_REQ_T, *P_IE_TPC_REQ_T; + +/* 7.3.2.18 TPC report element */ +typedef struct _IE_TPC_REPORT_T { + u8 ucId; + u8 ucLength; + s8 cTxPower; /* Unit: dBm */ + s8 cLinkMargin; /* Unit: dB */ +} __KAL_ATTRIB_PACKED__ IE_TPC_REPORT_T, *P_IE_TPC_REPORT_T; + +/* 7.3.2.19 Supported Channels element*/ +typedef struct _IE_SUPPORTED_CHANNELS_T { + u8 ucId; + u8 ucLength; + u8 ucChannelNum[0]; +} __KAL_ATTRIB_PACKED__ IE_SUPPORTED_CHANNELS_T, *P_IE_SUPPORTED_CHANNELS_T; + +/* 7.3.2.20 Channel Switch Announcement element*/ +typedef struct _IE_CHANNEL_SWITCH_T { + u8 ucId; + u8 ucLength; + u8 ucChannelSwitchMode; + u8 ucNewChannelNum; + u8 ucChannelSwitchCount; +} __KAL_ATTRIB_PACKED__ IE_CHANNEL_SWITCH_T, *P_IE_CHANNEL_SWITCH_T; + +typedef struct _IE_TIMEOUT_INTERVAL_T { + u8 ucId; + u8 ucLength; +#define IE_TIMEOUT_INTERVAL_TYPE_RESERVED 0 +#define IE_TIMEOUT_INTERVAL_TYPE_REASSOC 1 +#define IE_TIMEOUT_INTERVAL_TYPE_KEY_LIFETIME 43200 +#define IE_TIMEOUT_INTERVAL_TYPE_ASSOC_COMEBACK 3 + u8 ucType; + u32 u4Value; +} __KAL_ATTRIB_PACKED__ IE_TIMEOUT_INTERVAL_T; + +/* 7.3.2.20 Channel Switch Announcement element */ +typedef struct _IE_CHNL_SWITCH_T { + u8 ucId; + u8 ucLength; + u8 ucSwitchMode; + u8 ucNewChannel; + u8 ucSwitchCount; +} __KAL_ATTRIB_PACKED__ IE_CHNL_SWITCH_T, *P_IE_CHNL_SWITCH_T; + +/* 7.3.2.21 Measurement Request element */ +typedef struct _IE_MEASUREMENT_REQ_T { + u8 ucId; + u8 ucLength; + u8 ucToken; + u8 ucRequestMode; + u8 ucMeasurementType; + u8 aucRequestFields[1]; +} __KAL_ATTRIB_PACKED__ IE_MEASUREMENT_REQ_T, *P_IE_MEASUREMENT_REQ_T; + +/* 7.3.2.60 20/40 BSS Coexistence element */ +typedef struct _IE_SUP_OPERATING_CLASS_T { + u8 ucId; + u8 ucLength; + u8 ucCur; + u8 ucSup[255]; +} __KAL_ATTRIB_PACKED__ IE_SUP_OPERATING_CLASS_T, *P_IE_SUP_OPERATING_CLASS_T; + +/* 8.4.2.39 Neighbor Report Element */ +typedef struct _IE_NEIGHBOR_REPORT_T { + u8 ucId; /* Element ID */ + u8 ucLength; /* Length */ + u8 aucBSSID[MAC_ADDR_LEN]; /* OUI */ + u32 u4BSSIDInfo; /* Type */ + u8 ucOperClass; /* Hotspot Configuration */ + u8 ucChnlNumber; + u8 ucPhyType; + u8 aucSubElem[0]; +} __KAL_ATTRIB_PACKED__ IE_NEIGHBOR_REPORT_T, *P_IE_NEIGHBOR_REPORT_T; + +/* 8.5.7.6/8.5.7.7 Neighbor Report Request/Response frame format */ +typedef struct _ACTION_NEIGHBOR_REPORT_FRAME_T { + /* Neighbor Report Request/Response MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Neighbor Report Request/Response frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucDialogToken; /* Dialog Token */ + u8 aucInfoElem[1]; /* subelements */ +} __KAL_ATTRIB_PACKED__ ACTION_NEIGHBOR_REPORT_FRAME_T, +*P_ACTION_NEIGHBOR_REPORT_FRAME_T; + +typedef struct _ACTION_BTM_QUERY_FRAME_T { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* BSS Coexistence Management frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + + u8 ucDialogToken; + u8 ucQueryReason; + u8 *pucNeighborBss; +} __KAL_ATTRIB_PACKED__ ACTION_BTM_QUERY_FRAME_T, *P_ACTION_BTM_QUERY_FRAME_T; + +typedef struct _ACTION_BTM_REQ_FRAME_T { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* BSS Coexistence Management frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + + u8 ucDialogToken; + u8 ucRequestMode; + u16 u2DisassocTimer; + u8 ucValidityInterval; + u8 aucOptInfo[0]; + /* Optional: Bss Termination Duration(0~12 bytes), + ** Session Information URL, Bss Transition Candidate List + */ +} __KAL_ATTRIB_PACKED__ ACTION_BTM_REQ_FRAME_T, *P_ACTION_BTM_REQ_FRAME_T; + +typedef struct _ACTION_BTM_RSP_FRAME_T { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* BSS Coexistence Management frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + + u8 ucDialogToken; + u8 ucStatusCode; + u8 ucBssTermDelay; + u8 aucOptInfo[0]; + /* Optional Target BSSID and Transition Candidate Entry list */ +} __KAL_ATTRIB_PACKED__ ACTION_BTM_RSP_FRAME_T, *P_ACTION_BTM_RSP_FRAME_T; + +struct SUB_ELEMENT { + u8 ucSubID; + u8 ucLength; + u8 aucOptInfo[1]; +}; + +typedef struct _SM_BASIC_REQ_T { + u8 ucChannel; + u32 au4StartTime[2]; + u16 u2Duration; +} __KAL_ATTRIB_PACKED__ SM_BASIC_REQ_T, *P_SM_BASIC_REQ_T; + +/* SM_COMMON_REQ_T is not specified in Spec. Use it as common structure of SM */ +typedef SM_BASIC_REQ_T SM_REQ_COMMON_T, *P_SM_REQ_COMMON_T; +typedef SM_BASIC_REQ_T SM_CCA_REQ_T, *P_SM_CCA_REQ_T; +typedef SM_BASIC_REQ_T SM_RPI_HISTOGRAM_REQ_T, *P_SM_RPI_HISTOGRAM_REQ_T; + +typedef struct _RM_CHNL_LOAD_REQ_T { + u8 ucRegulatoryClass; + u8 ucChannel; + u16 u2RandomInterval; + u16 u2Duration; + u8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_CHNL_LOAD_REQ_T, *P_RM_CHNL_LOAD_REQ_T; + +typedef RM_CHNL_LOAD_REQ_T RM_NOISE_HISTOGRAM_REQ_T, + *P_RM_NOISE_HISTOGRAM_REQ_T; + +typedef struct _RM_BCN_REQ_T { + u8 ucRegulatoryClass; + u8 ucChannel; + u16 u2RandomInterval; + u16 u2Duration; + u8 ucMeasurementMode; + u8 aucBssid[6]; + u8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_BCN_REQ_T, *P_RM_BCN_REQ_T; + +typedef struct _RM_FRAME_REQ_T { + u8 ucRegulatoryClass; + u8 ucChannel; + u16 u2RandomInterval; + u16 u2Duration; + u8 ucFrameReqType; + u8 aucMacAddr[6]; + u8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_FRAME_REQ_T, *P_RM_FRAME_REQ_T; + +typedef struct _RM_STA_STATS_REQ_T { + u8 aucPeerMacAddr[6]; + u16 u2RandomInterval; + u16 u2Duration; + u8 ucGroupID; + u8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_STA_STATS_REQ_T, *P_RM_STA_STATS_REQ_T; + +typedef struct _RM_LCI_REQ_T { + u8 ucLocationSubject; + u8 ucLatitudeResolution; + u8 ucLongitudeResolution; + u8 ucAltitudeResolution; + u8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_LCI_REQ_T, *P_RM_LCI_REQ_T; + +typedef struct _RM_TS_MEASURE_REQ_T { + u16 u2RandomInterval; + u16 u2Duration; + u8 aucPeerStaAddr[6]; + u8 ucTrafficID; + u8 ucBin0Range; + u8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_TS_MEASURE_REQ_T, *P_RM_TS_MEASURE_REQ_T; + +typedef struct _RM_MEASURE_PAUSE_REQ_T { + u16 u2PauseTime; + u8 aucSubElements[1]; +} __KAL_ATTRIB_PACKED__ RM_MEASURE_PAUSE_REQ_T, *P_RM_MEASURE_PAUSE_REQ_T; + +/* 7.3.2.22 Measurement Report element */ +typedef struct _IE_MEASUREMENT_REPORT_T { + u8 ucId; + u8 ucLength; + u8 ucToken; + u8 ucReportMode; + u8 ucMeasurementType; + u8 aucReportFields[1]; +} __KAL_ATTRIB_PACKED__ IE_MEASUREMENT_REPORT_T, *P_IE_MEASUREMENT_REPORT_T; + +typedef struct _SM_BASIC_REPORT_T { + u8 ucChannel; + u32 u4StartTime[2]; + u16 u2Duration; + u8 ucMap; +} __KAL_ATTRIB_PACKED__ SM_BASIC_REPORT_T, *P_SM_BASIC_REPORT_T; + +typedef struct _SM_CCA_REPORT_T { + u8 ucChannel; + u32 u4StartTime[2]; + u16 u2Duration; + u8 ucCcaBusyFraction; +} __KAL_ATTRIB_PACKED__ SM_CCA_REPORT_T, *P_SM_CCA_REPORT_T; + +typedef struct _SM_RPI_REPORT_T { + u8 ucChannel; + u32 u4StartTime[2]; + u16 u2Duration; + u8 aucRPI[8]; +} __KAL_ATTRIB_PACKED__ SM_RPI_REPORT_T, *P_SM_RPI_REPORT_T; + +typedef struct _RM_CHNL_LOAD_REPORT_T { + u8 ucRegulatoryClass; + u8 ucChannel; + u32 u4StartTime[2]; + u16 u2Duration; + u8 ucChnlLoad; +} __KAL_ATTRIB_PACKED__ RM_CHNL_LOAD_REPORT_T, *P_RM_CHNL_LOAD_REPORT_T; + +typedef struct _RM_IPI_REPORT_T { + u8 ucRegulatoryClass; + u8 ucChannel; + u32 u4StartTime[2]; + u16 u2Duration; + u8 ucAntennaId; + s8 cANPI; + u8 aucIPI[11]; +} __KAL_ATTRIB_PACKED__ RM_IPI_REPORT_T, *P_RM_IPI_REPORT_T; + +/* 7.3.2.23 Quiet element */ +typedef struct _IE_QUIET_T { + u8 ucId; + u8 ucLength; + u8 ucCount; + u8 ucPeriod; + u16 u2Duration; + u16 u2Offset; +} __KAL_ATTRIB_PACKED__ IE_QUIET_T, *P_IE_QUIET_T; + +/* 7.3.2.27 Extended Capabilities element */ +typedef struct _IE_EXT_CAP_T { + u8 ucId; + u8 ucLength; + u8 aucCapabilities[1]; +} __KAL_ATTRIB_PACKED__ IE_EXT_CAP_T, *P_EXT_CAP_T; + +/* 7.3.2.27 Extended Capabilities element */ +typedef struct _IE_RRM_ENABLED_CAP_T { + u8 ucId; + u8 ucLength; + u8 aucCap[5]; +} __KAL_ATTRIB_PACKED__ IE_RRM_ENABLED_CAP_T, *P_IE_RRM_ENABLED_CAP_T; + +/* 7.3.2.56 HT Capabilities element */ +typedef struct _SUP_MCS_SET_FIELD { + u8 aucRxMcsBitmask[SUP_MCS_RX_BITMASK_OCTET_NUM]; + u16 u2RxHighestSupportedRate; + u32 u4TxRateInfo; +} __KAL_ATTRIB_PACKED__ SUP_MCS_SET_FIELD, *P_SUP_MCS_SET_FIELD; + +typedef struct _IE_HT_CAP_T { + u8 ucId; + u8 ucLength; + u16 u2HtCapInfo; + u8 ucAmpduParam; + SUP_MCS_SET_FIELD rSupMcsSet; + u16 u2HtExtendedCap; + u32 u4TxBeamformingCap; + u8 ucAselCap; +} __KAL_ATTRIB_PACKED__ IE_HT_CAP_T, *P_IE_HT_CAP_T; + +/* 7.3.2.57 HT Operation element */ +typedef struct _IE_HT_OP_T { + u8 ucId; + u8 ucLength; + u8 ucPrimaryChannel; + u8 ucInfo1; + u16 u2Info2; + u16 u2Info3; + u8 aucBasicMcsSet[16]; +} __KAL_ATTRIB_PACKED__ IE_HT_OP_T, *P_IE_HT_OP_T; + +/*8.4.2.160.3 VHT Supported MCS Set field*/ +typedef struct _VHT_SUPPORTED_MCS_FIELD { + u16 u2RxMcsMap; + u16 u2RxHighestSupportedDataRate; + u16 u2TxMcsMap; + u16 u2TxHighestSupportedDataRate; +} __KAL_ATTRIB_PACKED__ VHT_SUPPORTED_MCS_FIELD, *P_VHT_SUPPORTED_MCS_FIELD; + +typedef struct _IE_VHT_CAP_T { + u8 ucId; + u8 ucLength; + u32 u4VhtCapInfo; + VHT_SUPPORTED_MCS_FIELD rVhtSupportedMcsSet; +} __KAL_ATTRIB_PACKED__ IE_VHT_CAP_T, *P_IE_VHT_CAP_T; + +/*8.4.2.161 VHT Operation element*/ +typedef struct _IE_VHT_OP_T { + u8 ucId; + u8 ucLength; + u8 ucVhtOperation[3]; + u16 u2VhtBasicMcsSet; +} __KAL_ATTRIB_PACKED__ IE_VHT_OP_T, *P_IE_VHT_OP_T; + +/*8.4.1.50 Operating Mode field*/ +typedef struct _IE_VHT_OP_MODE_NOTIFICATION_T { + u8 ucId; + u8 ucLength; + u8 ucOperatingMode; +} __KAL_ATTRIB_PACKED__ IE_VHT_OP_MODE_NOTIFICATION_T, +*P_IE_VHT_OP_MODE_NOTIFICATION_T; + +/*8.4.2.22 Secondary Channel Offset element*/ +typedef struct _IE_SECONDARY_OFFSET_T { + u8 ucId; + u8 ucLength; + u8 ucSecondaryOffset; +} __KAL_ATTRIB_PACKED__ IE_SECONDARY_OFFSET_T, *P_IE_SECONDARY_OFFSET_T; + +/*8.4.2.105 Mesh Channel Switch Parameters element*/ +typedef struct _IE_MESH_CHANNEL_T { + u8 ucId; + u8 ucLength; + u8 ucTimetoLive; + u8 ucFlags; + u16 u2ReasonCodes; + u16 u2ProcedenceValue; +} __KAL_ATTRIB_PACKED__ IE_MESH_CHANNEL_T, *P_IE_MESH_CHANNEL_T; + +/*8.4.2.163 Wide Bandwidth Channel Switch element*/ +typedef struct _IE_WIDE_BAND_CHANNEL_T { + u8 ucId; + u8 ucLength; + u8 ucNewChannelWidth; + u8 ucChannelS1; + u8 ucChannelS2; +} __KAL_ATTRIB_PACKED__ IE_WIDE_BAND_CHANNEL_T, *P_IE_WIDE_BAND_CHANNEL_T; + +/*8.4.2.168 Operating Mode Notification element*/ +typedef struct _IE_OP_MODE_NOTIFICATION_T { + u8 ucId; + u8 ucLength; + u8 ucOpMode; +} __KAL_ATTRIB_PACKED__ IE_OP_MODE_NOTIFICATION_T, *P_IE_OP_MODE_NOTIFICATION_T; + +/* 7.3.2.25 RSN Information element format */ +typedef struct _RSN_INFO_ELEM_T { + u8 ucElemId; + u8 ucLength; + u16 u2Version; + u32 u4GroupKeyCipherSuite; + u16 u2PairwiseKeyCipherSuiteCount; + u8 aucPairwiseKeyCipherSuite1[4]; +} __KAL_ATTRIB_PACKED__ RSN_INFO_ELEM_T, *P_RSN_INFO_ELEM_T; + +/* 7.3.2.26 WPA Information element format */ +typedef struct _WPA_INFO_ELEM_T { + u8 ucElemId; + u8 ucLength; + u8 aucOui[3]; + u8 ucOuiType; + u16 u2Version; + u32 u4GroupKeyCipherSuite; + u16 u2PairwiseKeyCipherSuiteCount; + u8 aucPairwiseKeyCipherSuite1[4]; +} __KAL_ATTRIB_PACKED__ WPA_INFO_ELEM_T, *P_WPA_INFO_ELEM_T; + +/* 7.3.2.58 20/40 BSS Intolerant Channel Report element */ +typedef struct _IE_INTOLERANT_CHNL_REPORT_T { + u8 ucId; + u8 ucLength; + u8 ucRegulatoryClass; + u8 aucChannelList[1]; +} __KAL_ATTRIB_PACKED__ IE_INTOLERANT_CHNL_REPORT_T, +*P_IE_INTOLERANT_CHNL_REPORT_T; + +/* 7.3.2.59 OBSS Scan Parameters element */ +typedef struct _IE_OBSS_SCAN_PARAM_T { + u8 ucId; + u8 ucLength; + u16 u2ScanPassiveDwell; + u16 u2ScanActiveDwell; + u16 u2TriggerScanInterval; + u16 u2ScanPassiveTotalPerChnl; + u16 u2ScanActiveTotalPerChnl; + u16 u2WidthTransDelayFactor; + u16 u2ScanActivityThres; +} __KAL_ATTRIB_PACKED__ IE_OBSS_SCAN_PARAM_T, *P_IE_OBSS_SCAN_PARAM_T; + +/* 7.3.2.60 20/40 BSS Coexistence element */ +typedef struct _IE_20_40_COEXIST_T { + u8 ucId; + u8 ucLength; + u8 ucData; +} __KAL_ATTRIB_PACKED__ IE_20_40_COEXIST_T, *P_IE_20_40_COEXIST_T; + +#if CFG_SUPPORT_802_11V +typedef struct _IE_MAX_IDLE_PERIOD_T { + u8 ucId; + u8 ucLength; + u16 u2MaxIdlePeriod; + u8 ucOption; +} __KAL_ATTRIB_PACKED__ IE_MAX_IDLE_PERIOD_T, *P_IE_MAX_IDLE_PERIOD_T; +#endif + +/* 3 7.4 Action Frame. */ +/* 7.4 Action frame format */ +typedef struct _WLAN_ACTION_FRAME { + /* Action MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2DurationID; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Action frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucActionDetails[1]; /* Action details */ +} __KAL_ATTRIB_PACKED__ WLAN_ACTION_FRAME, *P_WLAN_ACTION_FRAME; + +/* 7.4.1.1 Spectrum Measurement Request frame format */ +typedef struct _ACTION_SM_REQ_FRAME { + /* ADDTS Request MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* ADDTS Request frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucDialogToken; /* Dialog Token */ + u8 aucInfoElem[1]; /* Information elements */ +} __KAL_ATTRIB_PACKED__ ACTION_SM_REQ_FRAME, *P_ACTION_SM_REQ_FRAME; + +/* 7.4.1.2 Spectrum Measurement Report frame format */ +typedef ACTION_SM_REQ_FRAME ACTION_SM_REPORT_FRAME, *P_ACTION_SM_REPORT_FRAME; + +/* 7.4.1.3 Spectrum TPC Request frame format */ +typedef struct _ACTION_TPC_REQ_FRAME { + /* ADDTS Request MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* ADDTS Request frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucDialogToken; /* Dialog Token */ + u8 ucElemId; /* Element ID */ + u8 ucLength; /* Length */ +} __KAL_ATTRIB_PACKED__ ACTION_TPC_REQ_FRAME, *P_ACTION_TPC_REQ_FRAME; + +/* 7.4.1.4 Spectrum TPC Report frame format */ +typedef struct _ACTION_TPC_REPORT_FRAME { + /* ADDTS Request MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* ADDTS Request frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucDialogToken; /* Dialog Token */ + u8 ucElemId; /* Element ID */ + u8 ucLength; /* Length */ + u8 ucTransPwr; /* Transmit Power */ + u8 ucLinkMargin; /* Link Margin */ +} __KAL_ATTRIB_PACKED__ ACTION_TPC_REPORT_FRAME, *P_ACTION_TPC_REPORT_FRAME; + +/* 7.4.1.5 Channel Switch Announcement frame format */ +typedef struct _ACTION_CHANNEL_SWITCH_FRAME { + /* ADDTS Request MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* ADDTS Request frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 aucInfoElem[5]; /* Information elements */ +} __KAL_ATTRIB_PACKED__ ACTION_CHANNEL_SWITCH_FRAME, +*P_ACTION_CHANNEL_SWITCH_FRAME; + +/* 7.4.2.1 ADDTS Request frame format */ +typedef struct _ACTION_ADDTS_REQ_FRAME { + /* ADDTS Request MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* ADDTS Request frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucDialogToken; /* Dialog Token */ + u8 aucInfoElem[1]; /* Information elements, such as */ + /* TS Delay, and etc. */ +} __KAL_ATTRIB_PACKED__ ACTION_ADDTS_REQ_FRAME, *P_ACTION_ADDTS_REQ_FRAME; + +/* 7.4.2.2 ADDTS Response frame format */ +typedef struct _ACTION_ADDTS_RSP_FRAME { + /* ADDTS Response MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* ADDTS Response frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucDialogToken; /* Dialog Token */ + u8 ucStatusCode; /* WMM Status Code is of one byte */ + u8 aucInfoElem[1]; /* Information elements, such as */ + /* TS Delay, and etc. */ +} __KAL_ATTRIB_PACKED__ ACTION_ADDTS_RSP_FRAME, *P_ACTION_ADDTS_RSP_FRAME; + +/* 7.4.2.3 DELTS frame format */ +typedef struct _ACTION_DELTS_FRAME { + /* DELTS MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2DurationID; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* DELTS frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 aucTsInfo[3]; /* TS Info */ +} __KAL_ATTRIB_PACKED__ ACTION_DELTS_FRAME, *P_ACTION_DELTS_FRAME; + +/* 7.4.4.1 ADDBA Request frame format */ +typedef struct _ACTION_ADDBA_REQ_FRAME_T { + /* Action MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2DurationID; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Action frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucDialogToken; /* Dialog Token chosen by the sender */ + u8 aucBAParameterSet[2]; /* BA policy, TID, buffer size */ + u8 aucBATimeoutValue[2]; + u8 aucBAStartSeqCtrl[2]; /* SSN */ +} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_REQ_FRAME_T, *P_ACTION_ADDBA_REQ_FRAME_T; + +typedef struct _ACTION_ADDBA_REQ_BODY_T { + u16 u2BAParameterSet; /* BA policy, TID, buffer size */ + u16 u2BATimeoutValue; + u16 u2BAStartSeqCtrl; /* SSN */ +} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_REQ_BODY_T, *P_ACTION_ADDBA_REQ_BODY_T; + +/* 7.4.4.2 ADDBA Response frame format */ +typedef struct _ACTION_ADDBA_RSP_FRAME_T { + /* Action MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2DurationID; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Action frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucDialogToken; /* Dialog Token chosen by the sender */ + u8 aucStatusCode[2]; + u8 aucBAParameterSet[2]; /* BA policy, TID, buffer size */ + u8 aucBATimeoutValue[2]; +} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_RSP_FRAME_T, *P_ACTION_ADDBA_RSP_FRAME_T; + +typedef struct _ACTION_ADDBA_RSP_BODY_T { + u16 u2StatusCode; + u16 u2BAParameterSet; /* BA policy, TID, buffer size */ + u16 u2BATimeoutValue; +} __KAL_ATTRIB_PACKED__ ACTION_ADDBA_RSP_BODY_T, *P_ACTION_ADDBA_RSP_BODY_T; + +/* 7.4.4.3 DELBA frame format */ +typedef struct _ACTION_DELBA_FRAME_T { + /* Action MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2DurationID; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Action frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u16 u2DelBaParameterSet; /* Bit 11 Initiator, Bits 12-15 TID */ + u16 u2ReasonCode; /* 7.3.1.7 */ +} __KAL_ATTRIB_PACKED__ ACTION_DELBA_FRAME_T, *P_ACTION_DELBA_FRAME_T; + +/* 7.4.6.1 Radio Measurement Request frame format */ +typedef struct _ACTION_RM_REQ_FRAME { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Radio Measurement Request frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucDialogToken; /* Dialog Token */ + u16 u2Repetitions; /* Number of repetitions */ + u8 aucInfoElem[1]; /* Measurement Request elements, such as */ + /* channel load request, and etc. */ +} __KAL_ATTRIB_PACKED__ ACTION_RM_REQ_FRAME, *P_ACTION_RM_REQ_FRAME; + +/* 7.4.6.2 Radio Measurement Report frame format */ +typedef struct _ACTION_RM_REPORT_FRAME { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Radio Measurement Report frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucDialogToken; /* Dialog Token */ + u8 aucInfoElem[1]; /* Measurement Report elements, such as */ + /* channel load report, and etc. */ +} __KAL_ATTRIB_PACKED__ ACTION_RM_REPORT_FRAME, *P_ACTION_RM_REPORT_FRAME; + +/* 7.4.7.1a 20/40 BSS Coexistence Management frame format */ +typedef struct _ACTION_20_40_COEXIST_FRAME { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* BSS Coexistence Management frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + + IE_20_40_COEXIST_T rBssCoexist; /* 20/40 BSS coexistence element */ + IE_INTOLERANT_CHNL_REPORT_T rChnlReport; /* Intolerant channel report */ +} __KAL_ATTRIB_PACKED__ ACTION_20_40_COEXIST_FRAME, +*P_ACTION_20_40_COEXIST_FRAME; + +#if CFG_SUPPORT_802_11W +/* 7.4.9 SA Query Management frame format */ +typedef struct _ACTION_SA_QUERY_FRAME { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* BSS Coexistence Management frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + + u8 ucTransId[ACTION_SA_QUERY_TR_ID_LEN]; /* Transaction id */ +} __KAL_ATTRIB_PACKED__ ACTION_SA_QUERY_FRAME, *P_ACTION_SA_QUERY_FRAME; +#endif + +/* 7.4.10 Notify Channel Width Management frame format */ +typedef struct _ACTION_NOTIFY_CHNL_WIDTH_FRAME { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* BSS Coexistence Management frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucChannelWidth; /* Channel Width */ +} __KAL_ATTRIB_PACKED__ ACTION_NOTIFY_CHNL_WIDTH_FRAME, +*P_ACTION_NOTIFY_CHNL_WIDTH_FRAME; + +/* 802.11v Wireless Network Management: Timing Measurement Request */ +typedef struct _ACTION_WNM_TIMING_MEAS_REQ_FRAME { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Timing Measurement Request Management frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucTrigger; /* Trigger */ +} __KAL_ATTRIB_PACKED__ ACTION_WNM_TIMING_MEAS_REQ_FRAME, +*P_ACTION_WNM_TIMING_MEAS_REQ_FRAME; + +/* 802.11v Wireless Network Management: Timing Measurement */ +typedef struct _ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Timing Measurement Management frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucDialogToken; /* Dialog Token */ + u8 ucFollowUpDialogToken; /* Follow Up Dialog Token */ + u32 u4ToD; /* Timestamp of Departure [10ns] */ + u32 u4ToA; /* Timestamp of Arrival [10ns] */ + u8 ucMaxToDErr; /* Maximum of ToD Error [10ns] */ + u8 ucMaxToAErr; /* Maximum of ToA Error [10ns] */ +} __KAL_ATTRIB_PACKED__ ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME, +*P_ACTION_UNPROTECTED_WNM_TIMING_MEAS_FRAME; + +/* 8.5.23.4 Operating Mode Notification frame format */ +typedef struct _ACTION_OP_MODE_NOTIFICATION_FRAME { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* Operating Mode Notification frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucOperatingMode; /* Operating Mode */ +} __KAL_ATTRIB_PACKED__ ACTION_OP_MODE_NOTIFICATION_FRAME, +*P_ACTION_OP_MODE_NOTIFICATION_FRAME; + +/* 8.5.12.3 SM Power Save frame format */ +typedef struct _ACTION_SM_POWER_SAVE_FRAME { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* SM power save frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucSmPowerCtrl; /* SM Power Control (see 8.4.1.22) */ +} __KAL_ATTRIB_PACKED__ ACTION_SM_POWER_SAVE_FRAME, +*P_ACTION_SM_POWER_SAVE_FRAME; + +/* 8.5.12.2 Notify Channel Width frame format */ +typedef struct _ACTION_NOTIFY_CHANNEL_WIDTH_FRAME { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* SM power save frame body */ + u8 ucCategory; /* Category */ + u8 ucAction; /* Action Value */ + u8 ucChannelWidth; /* Channel Width (see 8.4.1.21) */ +} __KAL_ATTRIB_PACKED__ ACTION_NOTIFY_CHANNEL_WIDTH_FRAME, +*P_ACTION_NOTIFY_CHANNEL_WIDTH_FRAME; + +/* 3 Information Elements from WFA. */ +typedef struct _IE_WFA_T { + u8 ucId; + u8 ucLength; + u8 aucOui[3]; + u8 ucOuiType; + u8 aucOuiSubTypeVersion[2]; + /*!< Please be noted. WPA defines a 16 bit field version */ + /* instead of one subtype field and one version field */ +} __KAL_ATTRIB_PACKED__ IE_WFA_T, *P_IE_WFA_T; + +/* WAPI Information element format */ +typedef struct _WAPI_INFO_ELEM_T { + u8 ucElemId; + u8 ucLength; + u16 u2Version; + u16 u2AuthKeyMgtSuiteCount; + u8 aucAuthKeyMgtSuite1[4]; +} __KAL_ATTRIB_PACKED__ WAPI_INFO_ELEM_T, *P_WAPI_INFO_ELEM_T; + +/* Information Elements from MTK Synergies.*/ +typedef struct _IE_MTK_OUI_T { + u8 ucId; + u8 ucLength; + u8 aucOui[3]; + u8 aucCapability[4]; + u8 aucInfoElem[1]; +} __KAL_ATTRIB_PACKED__ IE_MTK_OUI_T, *P_IE_MTK_OUI_T; + +typedef struct _SUB_IE_BSS_TERM_DURATION_T { + u8 ucSubId; + u8 ucLength; + u8 aucTermTsf[8]; + u16 u2Duration; +} __KAL_ATTRIB_PACKED__ SUB_IE_BSS_TERM_DURATION_T, +*P_SUB_IE_BSS_TERM_DURATION_T; + +#if defined(WINDOWS_DDK) || defined(WINDOWS_CE) +#pragma pack() +#endif + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/* Convert the ECWmin(max) to CWmin(max) */ +#define ECW_TO_CW(_ECW) ((1 << (_ECW)) - 1) + +/* Convert the RCPI to dBm */ +#define RCPI_TO_dBm(_rcpi) \ + ((PARAM_RSSI)(((_rcpi) > RCPI_HIGH_BOUND ? RCPI_HIGH_BOUND : \ + (_rcpi)) >> \ + 1) - \ + NDBM_LOW_BOUND_FOR_RCPI) + +/* Convert the dBm to RCPI */ +#define dBm_TO_RCPI(_dbm) \ + (RCPI)(((((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) << 1) > \ + RCPI_HIGH_BOUND) ? \ + RCPI_HIGH_BOUND : \ + ((((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) \ + << 1) < RCPI_LOW_BOUND ? \ + RCPI_LOW_BOUND : \ + (((PARAM_RSSI)(_dbm) + NDBM_LOW_BOUND_FOR_RCPI) \ + << 1))) + +/* Convert an unsigned char pointer to an information element pointer */ +#define IE_ID(fp) (((P_IE_HDR_T)fp)->ucId) +#define IE_LEN(fp) (((P_IE_HDR_T)fp)->ucLength) +#define IE_SIZE(fp) (ELEM_HDR_LEN + IE_LEN(fp)) + +#define SSID_IE(fp) ((P_IE_SSID_T)fp) + +#define SUP_RATES_IE(fp) ((P_IE_SUPPORTED_RATE_T)fp) + +#define SUP_RATES_IOT_IE(fp) ((struct IE_SUPPORTED_RATE_IOT *)fp) + +#define DS_PARAM_IE(fp) ((P_IE_DS_PARAM_SET_T)fp) + +#define TIM_IE(fp) ((P_IE_TIM_T)fp) + +#define IBSS_PARAM_IE(fp) ((P_IE_IBSS_PARAM_SET_T)fp) + +#define ERP_INFO_IE(fp) ((P_IE_ERP_T)fp) + +#define EXT_SUP_RATES_IE(fp) ((P_IE_EXT_SUPPORTED_RATE_T)fp) + +#define WFA_IE(fp) ((P_IE_WFA_T)fp) + +#if CFG_SUPPORT_802_11D +#define COUNTRY_IE(fp) ((P_IE_COUNTRY_T)fp) +#endif + +#define EXT_CAP_IE(fp) ((P_EXT_CAP_T)fp) + +#define POWER_CAP_IE(fp) ((P_IE_POWER_CAP_T)fp) + +#define SUP_CH_IE(fp) ((P_IE_SUPPORTED_CHANNELS_T)fp) + +#define HT_CAP_IE(fp) ((P_IE_HT_CAP_T)fp) + +#define HT_OP_IE(fp) ((P_IE_HT_OP_T)fp) + +#define VHT_CAP_IE(fp) ((P_IE_VHT_CAP_T)fp) + +#define VHT_OP_IE(fp) ((P_IE_VHT_OP_T)fp) + +#define OBSS_SCAN_PARAM_IE(fp) ((P_IE_OBSS_SCAN_PARAM_T)fp) + +#define BSS_20_40_COEXIST_IE(fp) ((P_IE_20_40_COEXIST_T)fp) + +#define SUP_OPERATING_CLASS_IE(fp) ((P_IE_SUP_OPERATING_CLASS_T)fp) + +#define QUIET_IE(fp) ((P_IE_QUIET_T)fp) + +#define MTK_OUI_IE(fp) ((P_IE_MTK_OUI_T)fp) + +#define CSA_IE(fp) ((P_IE_CHANNEL_SWITCH_T)fp) + +#if CFG_SUPPORT_802_11V +#define MAX_IDLE_PERIOD_IE(fp) ((P_IE_MAX_IDLE_PERIOD_T)fp) +#endif + +#define SUPPORTED_CHANNELS_IE(fp) ((P_IE_SUPPORTED_CHANNELS_T)fp) +#define TIMEOUT_INTERVAL_IE(fp) ((IE_TIMEOUT_INTERVAL_T *)fp) + +#define SM_TPC_REQ_IE(fp) ((P_IE_TPC_REQ_T)fp) +#define SM_TPC_REP_IE(fp) ((P_IE_TPC_REPORT_T)fp) +#define SM_MEASUREMENT_REQ_IE(fp) ((P_IE_MEASUREMENT_REQ_T)fp) +#define SM_MEASUREMENT_REP_IE(fp) ((P_IE_MEASUREMENT_REPORT_T)fp) +#define SM_BASIC_REQ_IE(fp) ((P_SM_BASIC_REQ_T)fp) + +/* The macro to check if the MAC address is B/MCAST Address */ +#define IS_BMCAST_MAC_ADDR(_pucDestAddr) \ + ((u8)(((u8 *)(_pucDestAddr))[0] & BIT(0))) + +/* The macro to check if the MAC address is UCAST Address */ +#define IS_UCAST_MAC_ADDR(_pucDestAddr) \ + ((u8) !(((u8 *)(_pucDestAddr))[0] & BIT(0))) + +/* The macro to copy the MAC address */ +#define COPY_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ + kalMemCopy(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN) + +/* The macro to check if two MAC addresses are equal */ +#define EQUAL_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ + (!kalMemCmp(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN)) + +/* The macro to check if two MAC addresses are not equal */ +#define UNEQUAL_MAC_ADDR(_pucDestAddr, _pucSrcAddr) \ + (kalMemCmp(_pucDestAddr, _pucSrcAddr, MAC_ADDR_LEN)) + +/* The macro to check whether two SSIDs are equal */ +#define EQUAL_SSID(pucSsid1, ucSsidLen1, pucSsid2, ucSsidLen2) \ + ((ucSsidLen1 <= ELEM_MAX_LEN_SSID) && \ + (ucSsidLen2 <= ELEM_MAX_LEN_SSID) && \ + ((ucSsidLen1) == (ucSsidLen2)) && \ + !kalMemCmp(pucSsid1, pucSsid2, ucSsidLen1)) + +/* The macro to check whether two SSIDs are equal */ +#define UNEQUAL_SSID(pucSsid1, ucSsidLen1, pucSsid2, ucSsidLen2) \ + ((ucSsidLen1 > ELEM_MAX_LEN_SSID) || \ + (ucSsidLen2 > ELEM_MAX_LEN_SSID) || ((ucSsidLen1) != (ucSsidLen2)) || \ + kalMemCmp(pucSsid1, pucSsid2, ucSsidLen1)) + +/* The macro to copy the SSID, the length of pucDestSsid should have at least 32 + * bytes */ +#define COPY_SSID(pucDestSsid, ucDestSsidLen, pucSrcSsid, ucSrcSsidLen) \ + do { \ + ucDestSsidLen = ucSrcSsidLen; \ + if (ucSrcSsidLen) { \ + ASSERT(ucSrcSsidLen <= ELEM_MAX_LEN_SSID); \ + kalMemCopy(pucDestSsid, pucSrcSsid, \ + ((ucSrcSsidLen > ELEM_MAX_LEN_SSID) ? \ + ELEM_MAX_LEN_SSID : \ + ucSrcSsidLen)); \ + } \ + } while (false) + +/* The macro to copy the IE */ +#define COPY_IE(pucDestIE, pucSrcIE) \ + do { \ + kalMemCopy((u8 *)pucDestIE, (u8 *)pucSrcIE, \ + IE_SIZE(pucSrcIE)); \ + } while (false) + +#define IE_FOR_EACH(_pucIEsBuf, _u2IEsBufLen, _u2Offset) \ + for ((_u2Offset) = 0; \ + ((((_u2Offset) + 2) <= (_u2IEsBufLen)) && \ + (((_u2Offset) + IE_SIZE(_pucIEsBuf)) <= (_u2IEsBufLen))); \ + (_u2Offset) += IE_SIZE(_pucIEsBuf), \ + (_pucIEsBuf) += IE_SIZE(_pucIEsBuf)) + +#define SET_EXT_CAP(_aucField, _ucFieldLength, _ucBit) \ + do { \ + if ((_ucBit) < ((_ucFieldLength) * 8)) { \ + u8 *aucExtCap = (u8 *)(_aucField); \ + ((aucExtCap)[(_ucBit) / 8]) |= BIT((_ucBit) % 8); \ + } \ + } while (false) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic.h new file mode 100644 index 00000000000000..89ddc8c0cefc3c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic.h @@ -0,0 +1,369 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "nic.h" + * \brief The declaration of nic functions + * + * Detail description. + */ + +#ifndef _NIC_H +#define _NIC_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +struct _REG_ENTRY_T { + u32 u4Offset; + u32 u4Value; +}; + +struct _TABLE_ENTRY_T { + P_REG_ENTRY_T pu4TablePtr; + u16 u2Size; +}; + +/*! INT status to event map */ +typedef struct _INT_EVENT_MAP_T { + u32 u4Int; + u32 u4Event; +} INT_EVENT_MAP_T, *P_INT_EVENT_MAP_T; + +typedef struct _ECO_INFO_T { + u8 ucHwVer; + u8 ucRomVer; + u8 ucFactoryVer; + u8 ucEcoVer; +} ECO_INFO_T, *P_ECO_INFO_T; + +enum ENUM_INT_EVENT_T { + INT_EVENT_ABNORMAL, + INT_EVENT_SW_INT, + INT_EVENT_TX, + INT_EVENT_RX, + INT_EVENT_NUM +}; + +typedef enum _ENUM_IE_UPD_METHOD_T { + IE_UPD_METHOD_UPDATE_RANDOM, + IE_UPD_METHOD_UPDATE_ALL, + IE_UPD_METHOD_DELETE_ALL, +} ENUM_IE_UPD_METHOD_T, +*P_ENUM_IE_UPD_METHOD_T; + +typedef enum _ENUM_SER_STATE_T { + SER_IDLE_DONE, /* SER is idle or done */ + SER_STOP_HOST_TX, /* Host HIF Tx is stopped */ + SER_STOP_HOST_TX_RX, /* Host HIF Tx/Rx is stopped */ + SER_REINIT_HIF, /* Host HIF is reinit */ + + SER_STATE_NUM +} ENUM_SER_STATE_T, +*P_ENUM_SER_STATE_T; + +/* Test mode bitmask of disable flag */ +#define TEST_MODE_DISABLE_ONLINE_SCAN BIT(0) +#define TEST_MODE_DISABLE_ROAMING BIT(1) +#define TEST_MODE_FIXED_CAM_MODE BIT(2) +#define TEST_MODE_DISABLE_BCN_LOST_DET BIT(3) +#define TEST_MODE_NONE 0 +#define TEST_MODE_THROUGHPUT \ + (TEST_MODE_DISABLE_ONLINE_SCAN | TEST_MODE_DISABLE_ROAMING | \ + TEST_MODE_FIXED_CAM_MODE | TEST_MODE_DISABLE_BCN_LOST_DET) +#define TEST_MODE_SIGMA_AC_N_PMF \ + (TEST_MODE_DISABLE_ONLINE_SCAN | TEST_MODE_FIXED_CAM_MODE) +#define TEST_MODE_SIGMA_WMM_PS (TEST_MODE_DISABLE_ONLINE_SCAN) +#define TEST_MODE_AUDIO_MRM \ + (TEST_MODE_DISABLE_ONLINE_SCAN | TEST_MODE_DISABLE_ROAMING | \ + TEST_MODE_FIXED_CAM_MODE) + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Routines in nic.c */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicAllocateAdapterMemory(IN P_ADAPTER_T prAdapter); + +void nicReleaseAdapterMemory(IN P_ADAPTER_T prAdapter); + +void nicDisableInterrupt(IN P_ADAPTER_T prAdapter); + +void nicEnableInterrupt(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicProcessIST(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicProcessIST_impl(IN P_ADAPTER_T prAdapter, IN u32 u4IntStatus); + +WLAN_STATUS nicInitializeAdapter(IN P_ADAPTER_T prAdapter); + +void nicMCRInit(IN P_ADAPTER_T prAdapter); + +u8 nicVerifyChipID(IN P_ADAPTER_T prAdapter); + +void nicpmWakeUpWiFi(IN P_ADAPTER_T prAdapter); + +u8 nicpmSetDriverOwn(IN P_ADAPTER_T prAdapter); + +void nicpmSetFWOwn(IN P_ADAPTER_T prAdapter, IN u8 fgEnableGlobalInt); + +u8 nicpmSetAcpiPowerD0(IN P_ADAPTER_T prAdapter); + +u8 nicpmSetAcpiPowerD3(IN P_ADAPTER_T prAdapter); + +void nicProcessSoftwareInterrupt(IN P_ADAPTER_T prAdapter); + +void nicProcessAbnormalInterrupt(IN P_ADAPTER_T prAdapter); + +void nicSetSwIntr(IN P_ADAPTER_T prAdapter, IN u32 u4SwIntrBitmap); + +P_CMD_INFO_T nicGetPendingCmdInfo(IN P_ADAPTER_T prAdapter, IN u8 ucSeqNum); + +P_MSDU_INFO_T nicGetPendingTxMsduInfo(IN P_ADAPTER_T prAdapter, + IN u8 ucWlanIndex, + IN u8 ucSeqNum); + +void nicFreePendingTxMsduInfoByBssIdx(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex); + +u8 nicIncreaseCmdSeqNum(IN P_ADAPTER_T prAdapter); + +u8 nicIncreaseTxSeqNum(IN P_ADAPTER_T prAdapter); + +/* Media State Change */ +WLAN_STATUS +nicMediaStateChange(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_EVENT_CONNECTION_STATUS prConnectionStatus); + +WLAN_STATUS nicMediaJoinFailure(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN WLAN_STATUS rStatus); + +/* Utility function for channel number conversion */ +u32 nicChannelNum2Freq(IN u32 u4ChannelNum); + +u32 nicFreq2ChannelNum(IN u32 u4FreqInKHz); + +u8 nicGetVhtS1(IN u8 ucPrimaryChannel, IN u8 ucBandwidth); + +/* firmware command wrapper */ +/* NETWORK (WIFISYS) */ +WLAN_STATUS nicActivateNetwork(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex); + +WLAN_STATUS nicDeactivateNetwork(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex); + +/* BSS-INFO */ +WLAN_STATUS nicUpdateBss(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex); + +/* BSS-INFO Indication (PM) */ +WLAN_STATUS nicPmIndicateBssCreated(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex); + +WLAN_STATUS nicPmIndicateBssConnected(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex); + +WLAN_STATUS nicPmIndicateBssAbort(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex); + +/* Beacon Template Update */ +WLAN_STATUS +nicUpdateBeaconIETemplate(IN P_ADAPTER_T prAdapter, + IN ENUM_IE_UPD_METHOD_T eIeUpdMethod, + IN u8 ucBssIndex, + IN u16 u2Capability, + IN u8 *aucIe, + IN u16 u2IELen); + +WLAN_STATUS nicQmUpdateWmmParms(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex); + +WLAN_STATUS nicSetAutoTxPower(IN P_ADAPTER_T prAdapter, + IN P_CMD_AUTO_POWER_PARAM_T prAutoPwrParam); + +/*----------------------------------------------------------------------------*/ +/* Calibration Control */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicUpdateTxPower(IN P_ADAPTER_T prAdapter, + IN P_CMD_TX_PWR_T prTxPwrParam); + +WLAN_STATUS nicUpdate5GOffset(IN P_ADAPTER_T prAdapter, + IN P_CMD_5G_PWR_OFFSET_T pr5GPwrOffset); + +WLAN_STATUS nicUpdateDPD(IN P_ADAPTER_T prAdapter, + IN P_CMD_PWR_PARAM_T prDpdCalResult); + +/*----------------------------------------------------------------------------*/ +/* PHY configuration */ +/*----------------------------------------------------------------------------*/ +void nicSetAvailablePhyTypeSet(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* MGMT and System Service Control */ +/*----------------------------------------------------------------------------*/ +void nicInitSystemService(IN P_ADAPTER_T prAdapter); + +void nicResetSystemService(IN P_ADAPTER_T prAdapter); + +void nicUninitSystemService(IN P_ADAPTER_T prAdapter); + +void nicInitMGMT(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo); + +void nicUninitMGMT(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS +nicConfigPowerSaveProfile(IN P_ADAPTER_T prAdapter, + u8 ucBssIndex, + PARAM_POWER_MODE ePwrMode, + u8 fgEnCmdEvent); + +WLAN_STATUS +nicConfigPowerSaveWowProfile(IN P_ADAPTER_T prAdapter, + u8 ucBssIndex, + PARAM_POWER_MODE ePwrMode, + u8 fgEnCmdEvent, + u8 fgSuspend); + +WLAN_STATUS nicEnterCtiaMode(IN P_ADAPTER_T prAdapter, + u8 fgEnterCtia, + u8 fgEnCmdEvent); +WLAN_STATUS nicEnterTPTestMode(IN P_ADAPTER_T prAdapter, IN u8 ucFuncMask); + +/*----------------------------------------------------------------------------*/ +/* Scan Result Processing */ +/*----------------------------------------------------------------------------*/ +void nicAddScanResult(IN P_ADAPTER_T prAdapter, + IN PARAM_MAC_ADDRESS rMacAddr, + IN P_PARAM_SSID_T prSsid, + IN u32 u4Privacy, + IN PARAM_RSSI rRssi, + IN ENUM_PARAM_NETWORK_TYPE_T eNetworkType, + IN P_PARAM_802_11_CONFIG_T prConfiguration, + IN ENUM_PARAM_OP_MODE_T eOpMode, + IN PARAM_RATES_EX rSupportedRates, + IN u16 u2IELength, + IN u8 *pucIEBuf); + +void nicFreeScanResultIE(IN P_ADAPTER_T prAdapter, IN u32 u4Idx); + +/*----------------------------------------------------------------------------*/ +/* Fixed Rate Hacking */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdateRateParams(IN P_ADAPTER_T prAdapter, + IN ENUM_REGISTRY_FIXED_RATE_T eRateSetting, + IN u8 *pucDesiredPhyTypeSet, + IN u16 *pu2DesiredNonHTRateSet, + IN u16 *pu2BSSBasicRateSet, + IN u8 *pucMcsSet, + IN u8 *pucSupMcs32, + IN u16 *u2HtCapInfo); + +/*----------------------------------------------------------------------------*/ +/* Write registers */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicWriteMcr(IN P_ADAPTER_T prAdapter, + IN u32 u4Address, + IN u32 u4Value); + +/*----------------------------------------------------------------------------*/ +/* Update auto rate */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicRlmArUpdateParms(IN P_ADAPTER_T prAdapter, + IN u32 u4ArSysParam0, + IN u32 u4ArSysParam1, + IN u32 u4ArSysParam2, + IN u32 u4ArSysParam3); + +/*----------------------------------------------------------------------------*/ +/* Enable/Disable Roaming */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicRoamingUpdateParams(IN P_ADAPTER_T prAdapter, + IN u32 u4EnableRoaming); + +/*----------------------------------------------------------------------------*/ +/* Link Quality Updating */ +/*----------------------------------------------------------------------------*/ +void nicUpdateLinkQuality(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_EVENT_LINK_QUALITY_V2 prEventLinkQuality); + +void nicUpdateRSSI(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN s8 cRssi, + IN s8 cLinkQuality); + +void nicUpdateLinkSpeed(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN u16 u2LinkSpeed); + +#if CFG_SUPPORT_RDD_TEST_MODE +WLAN_STATUS nicUpdateRddTestMode(IN P_ADAPTER_T prAdapter, + IN P_CMD_RDD_CH_T prRddChParam); +#endif + +/*----------------------------------------------------------------------------*/ +/* Address Setting Apply */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicApplyNetworkAddress(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* ECO Version */ +/*----------------------------------------------------------------------------*/ +u8 nicGetChipSwVer(void); +u8 nicGetChipEcoVer(IN P_ADAPTER_T prAdapter); +u8 nicIsEcoVerEqualTo(IN P_ADAPTER_T prAdapter, u8 ucEcoVer); +u8 nicIsEcoVerEqualOrLaterTo(IN P_ADAPTER_T prAdapter, u8 ucEcoVer); +u8 nicSetChipHwVer(u8 value); +u8 nicSetChipSwVer(u8 value); +u8 nicSetChipFactoryVer(u8 value); + +void nicSerStopTxRx(IN P_ADAPTER_T prAdapter); +void nicSerStopTx(IN P_ADAPTER_T prAdapter); +void nicSerStartTxRx(IN P_ADAPTER_T prAdapter); +u8 nicSerIsWaitingReset(IN P_ADAPTER_T prAdapter); +u8 nicSerIsTxStop(IN P_ADAPTER_T prAdapter); +u8 nicSerIsRxStop(IN P_ADAPTER_T prAdapter); + +void nicDumpMsduInfo(IN P_MSDU_INFO_T prMsduInfo); +u8 nicGetChipHwVer(void); +u8 nicGetChipFactoryVer(void); +WLAN_STATUS nicSetAutoTxPowerControl(IN P_ADAPTER_T prAdapter, + IN P_CMD_TX_PWR_T prTxPwrParam); +void nicHifInit(IN P_ADAPTER_T prAdapter); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic_rate.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic_rate.h new file mode 100644 index 00000000000000..8af06206173853 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic_rate.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file nic_rate.h + * \brief This file contains the rate utility function of + * IEEE 802.11 family for MediaTek 802.11 Wireless LAN Adapters. + */ + +#ifndef _NIC_RATE_H +#define _NIC_RATE_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +u32 nicGetPhyRateByMcsRate(IN u8 ucIdx, IN u8 ucBw, IN u8 ucGI); + +u32 nicGetHwRateByPhyRate(IN u8 ucIdx); + +WLAN_STATUS +nicSwIndex2RateIndex(IN u8 ucRateSwIndex, + OUT u8 *pucRateIndex, + OUT u8 *pucPreambleOption); + +WLAN_STATUS +nicRateIndex2RateCode(IN u8 ucPreambleOption, + IN u8 ucRateIndex, + OUT u16 *pu2RateCode); + +u32 nicRateCode2PhyRate(IN u16 u2RateCode, + IN u8 ucBandwidth, + IN u8 ucGI, + IN u8 ucRateNss); + +u32 nicRateCode2DataRate(IN u16 u2RateCode, IN u8 ucBandwidth, IN u8 ucGI); + +u8 nicGetRateIndexFromRateSetWithLimit(IN u16 u2RateSet, + IN u32 u4PhyRateLimit, + IN u8 fgGetLowest, + OUT u8 *pucRateSwIndex); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic_rx.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic_rx.h new file mode 100644 index 00000000000000..1a7e73758c195e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic_rx.h @@ -0,0 +1,1135 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "nic_rx.h" + * \brief The declaration of the nic rx functions + * + */ + +#ifndef _NIC_RX_H +#define _NIC_RX_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define UNIFIED_MAC_RX_FORMAT 1 + +#define MAX_SEQ_NO 4095 +#define MAX_SEQ_NO_COUNT 4096 +#define HALF_SEQ_NO_CNOUT 2048 + +#define HALF_SEQ_NO_COUNT 2048 + +#define MT6620_FIXED_WIN_SIZE 64 +#define CFG_RX_MAX_BA_ENTRY 4 +#define CFG_RX_MAX_BA_TID_NUM 8 + +#define RX_STATUS_FLAG_MORE_PACKET BIT(30) +#define RX_STATUS_CHKSUM_MASK BITS(0, 10) + +#define RX_RFB_LEN_FIELD_LEN 4 +#define RX_HEADER_OFFSET 2 + +#define RX_RETURN_INDICATED_RFB_TIMEOUT_SEC 1 + +#define RX_BEHIND_CONTINUOUS_THRESHOLD 256 + +#define SDIO_MAXIMUM_RX_LEN_NUM 0 /*!< 0~15 (0: un-limited) */ + +/* RXM Definitions */ +/* The payload format of a RX packet */ +#define RX_PAYLOAD_FORMAT_MSDU 0 +#define RX_PAYLOAD_FORMAT_FIRST_SUB_AMSDU 3 +#define RX_PAYLOAD_FORMAT_MIDDLE_SUB_AMSDU 2 +#define RX_PAYLOAD_FORMAT_LAST_SUB_AMSDU 1 + +/* HAL RX from hal_hw_def_rom.h */ +/*------------------------------------------------------------------------------ + * Cipher define + *------------------------------------------------------------------------------ + */ +#define CIPHER_SUITE_NONE 0 +#define CIPHER_SUITE_WEP40 1 +#define CIPHER_SUITE_TKIP 2 +#define CIPHER_SUITE_TKIP_WO_MIC 3 +#define CIPHER_SUITE_CCMP 4 +#define CIPHER_SUITE_WEP104 5 +#define CIPHER_SUITE_BIP 6 +#define CIPHER_SUITE_WEP128 7 +#define CIPHER_SUITE_WPI 8 +#define CIPHER_SUITE_CCMP_W_CCX 9 +#define CIPHER_SUITE_GCMP 10 + +/*------------------------------------------------------------------------------ + * Bit fields for HW_MAC_RX_DESC_T + *------------------------------------------------------------------------------ + */ + +/*! MAC RX DMA Descriptor */ +/* DW 0*/ +/* Word 0 */ +#define RX_STATUS_RX_BYTE_COUNT_MASK BITS(0, 16) +/* Word 1 */ +#define RX_STATUS_ETH_TYPE_OFFSET_MASK BITS(0, 6) +#define RX_STATUS_ETH_TYPE_OFFSET 0 +#define RX_STATUS_IP_CHKSUM BIT(7) +#define RX_STATUS_UDP_TCP_CHKSUM BIT(8) +#define RX_STATUS_GROUP_VLD_MASK BITS(9, 12) +#define RX_STATUS_GROUP_VLD_OFFSET 9 +#define RX_STATUS_PKT_TYPE_MASK BITS(13, 15) +#define RX_STATUS_PKT_TYPE_OFFSET 13 + +/* DW 1 */ +/* Byte 0 */ +#define RX_STATUS_HTC BIT(0) +#define RX_STATUS_UC2ME 1 +#define RX_STATUS_MC_FRAME 2 +#define RX_STATUS_BC_FRAME 3 +#define RX_STATUS_A1_TYPE_MASK BITS(1, 2) +#define RX_STATUS_A1_TYPE_OFFSET 1 +#define RX_STATUS_BCN_WITH_BMC BIT(4) +#define RX_STATUS_BCN_WITH_UC BIT(5) +#define RX_STATUS_KEYID_MASK BITS(6, 7) +#define RX_STATUS_KEYID_OFFSET 6 + +/* Byte 1 */ +#define RX_STATUS_CHAN_FREQ_MASK BITS(0, 7) +/* Byte 2 */ +#define RX_STATUS_HEADER_LEN_MASK BITS(0, 5) +#define RX_STATUS_HEADER_OFFSET BIT(6) +#define RX_STATUS_HEADER_TRAN BIT(7) +/* Byte 3 */ +#define RX_STATUS_PAYLOAD_FORMAT_MASK BITS(0, 1) +#define RX_STATUS_PAYLOAD_FORMAT_OFFSET 0 +#define RX_STATUS_BSSID_MASK BITS(2, 7) +#define RX_STATUS_BSSID_OFFSET 2 + +/* DW 2 */ +/* Byte 1 */ +#define RX_STATUS_TID_MASK BITS(0, 3) +#define RX_STATUS_SEC_MASK BITS(4, 7) +#define RX_STATUS_SEC_OFFSET 4 +/* Byte 2-3 */ +#define RX_STATUS_SW_BIT BIT(0) +#define RX_STATUS_FLAG_FCS_ERROR BIT(1) +#define RX_STATUS_FLAG_CIPHER_MISMATCH BIT(2) +#define RX_STATUS_FLAG_CIPHER_LENGTH_MISMATCH BIT(3) +#define RX_STATUS_FLAG_ICV_ERROR BIT(4) +#define RX_STATUS_FLAG_TKIPMIC_ERROR BIT(5) +#define RX_STATUS_FLAG_LEN_MISMATCH BIT(6) +#define RX_STATUS_FLAG_DE_AMSDU_FAIL BIT(7) +#define RX_STATUS_FLAG_EXCEED_LEN BIT(8) +#define RX_STATUS_LLC_MIS BIT(9) +#define RX_STATUS_UDF_VLT BIT(10) +#define RX_STATUS_FRAG BIT(11) +#define RX_STATUS_NULL BIT(12) +#define RX_STATUS_DATA BIT(13) +#define RX_STATUS_AMPDU_SUB_FRAME BIT(14) +#define RX_STATUS_AMPDU_FORMAT BIT(15) +#define PAYLOAD_FORMAT_IS_MSDU_FRAME 0 +#define RX_STATUS_FLAG_ERROR_MASK \ + (RX_STATUS_FLAG_FCS_ERROR | RX_STATUS_FLAG_ICV_ERROR | \ + RX_STATUS_FLAG_CIPHER_LENGTH_MISMATCH) /* No TKIP MIC error \ + */ + +/* DW 3 */ +#define RX_STATUS_RXV_SEQ_NO_MASK BITS(0, 7) +#define RX_STATUS_TCL BIT(8) +#define RX_STATUS_CLS BIT(11) +#define RX_STATUS_OFLD_MASK BITS(12, 13) +#define RX_STATUS_OFLD_OFFSET 12 +#define RX_STATUS_EAPOL_PACKET BIT(12) +#define RX_STATUS_ARP_NS_PACKET BIT(13) +#define RX_STATUS_TDLS_PACKET BITS(12, 13) +#define RX_STATUS_MGC BIT(14) +#define RX_STATUS_WOL_MASK BITS(15, 19) +#define RX_STATUS_WOL_OFFSET 15 +#define RX_STATUS_CLS_BITMAP_MASK BITS(20, 29) +#define RX_STATUS_CLS_BITMAP_OFFSET 20 +#define RX_STATUS_PF_MODE_BLACK_LIST BIT(30) +#define RX_STATUS_PF_STS_CHECKED BIT(31) + +/* DW 12 */ +#define RX_STATUS_FRAG_NUM_MASK BITS(0, 3) +#define RX_STATUS_SEQ_NUM_MASK BITS(4, 15) +#define RX_STATUS_SEQ_NUM_OFFSET 4 + +#define RX_STATUS_GROUP1_VALID BIT(0) +#define RX_STATUS_GROUP2_VALID BIT(1) +#define RX_STATUS_GROUP3_VALID BIT(2) +#define RX_STATUS_GROUP4_VALID BIT(3) + +#define RX_STATUS_FIXED_LEN 16 + +#define RX_STATUS_CHAN_FREQ_MASK_FOR_BY_PASS_MPDE BITS(0, 7) +#define RX_STATUS_FLAG_FCS_ERROR_FOR_BY_PASS_MODE BIT(16) + +/* Timing Measurement Report */ +/* DW0 Word 1 */ +#define RX_TMR_TOA_VALID BIT(11) +#define RX_TMR_TOD_VALID BIT(10) +#define RX_TMR_TYPE_MASK BITS(8, 9) +#define RX_TMR_TYPE_OFFSET 8 +#define RX_TMR_SUBTYPE_MASK BITS(4, 7) +#define RX_TMR_SUBTYPE_OFFSET 4 + +/* DW0 Byte 1*/ +#define RX_TMR_TM_FAILED BIT(2) +#define RX_TMR_NOISY_CHAN BIT(1) +#define RX_TMR_RESPONDER BIT(0) + +/* TBD */ +#define DMA_OWN_TO_HW BIT(0) +#define DMA_OWN_TO_FW_PENDING BIT(1) +#define STATUS_IS_OWN_TO_FW(flag) (((flag) & DMA_OWN_TO_HW) ? false : true) +#define STATUS_IS_FW_PENDING(flag) \ + (((flag) & DMA_OWN_TO_FW_PENDING) ? true : false) + +/* DW 2 */ +#define RX_STATUS_PACKET_LENGTH_MASK BITS(0, 16) + +#define RX_STATUS_HEADER_TRAN_MASK BIT(7) +#define RX_STATUS_HEADER_TRAN_OFFSET 7 +#define RX_STATUS_HEADER_TRAN_BSS0_MASK BIT(6) +#define RX_STATUS_HEADER_TRAN_BSS0_OFFSET 6 +#define RX_STATUS_HEADER_TRAN_BSS1_MASK BIT(7) +#define RX_STATUS_HEADER_TRAN_BSS1_OFFSET 7 + +/* DW 4 */ +#define RX_STATUS_MATCH_PACKET BIT(4) + +#define RX_STATUS_HEADER_OFFSET_MASK 0xC0 +#define RX_STATUS_HEADER_OFFSET_OFFSET 6 + +/*------------------------------------------------------------------------------ + * Bit fields for HW_RX_VECTOR_DESC_T + *------------------------------------------------------------------------------ + */ +/* DW 2 */ +#define RX_VECTOR_FOR_BA_ACK BIT(7) + +/*! HIF RX DMA Descriptor */ +/* DW 2 */ +#define HIF_RX_DESC_BUFFER_LEN BITS(0, 15) +#define HIF_RX_DESC_ETHER_TYPE_OFFSET_MASK BITS(16, 23) +#define HIF_RX_DESC_ETHER_TYPE_OFFSET_OFFSET 16 +#define HIF_RX_DESC_IP_CHKSUM_CHECK BIT(24) +#define HIF_RX_DESC_TCP_UDP_CHKSUM_CHECK BIT(25) + +#define HIF_RX_DATA_QUEUE 0 +#define HIF_RX_EVENT_QUEUE 1 + +/*------------------------------------------------------------------------------ + * Bit fields for PHY Vector + *------------------------------------------------------------------------------ + */ + +/* RX Vector, 1st Cycle */ +#define RX_VT_RX_RATE_AC_MASK BITS(0, 3) +#define RX_VT_RX_RATE_MASK BITS(0, 6) +#define RX_VT_RX_RATE_OFFSET 0 +#define RX_VT_STBC_MASK BITS(7, 8) +#define RX_VT_STBC_OFFSET 7 +#define RX_VT_LDPC BIT(9) +#define RX_VT_NESS_MASK BITS(10, 11) +#define RX_VT_NESS_OFFSET 10 +#define RX_VT_RX_MODE_MASK BITS(12, 14) +#define RX_VT_RX_MODE_OFFSET 12 +#define RX_VT_RX_MODE_VHT BIT(14) +#define RX_VT_FR_MODE_MASK BITS(15, 16) +#define RX_VT_FR_MODE_OFFSET 15 +#define RX_VT_TXOP_PS_NOT_ALLOWED BIT(17) +#define RX_VT_AGGREGATION BIT(18) +#define RX_VT_SHORT_GI BIT(19) +#define RX_VT_SMOOTH BIT(20) +#define RX_VT_NO_SOUNDING BIT(21) +#define RX_VT_SOUNDING BIT(21) +#define RX_VT_NUM_RX_MASK BITS(22, 23) +#define RX_VT_NUM_RX_OFFSET 22 +#define RX_VT_LDPC_EXTRA_OFDM_SYM BIT(24) /* VHT_SIG_A2[B3] */ +#define RX_VT_SU_VHT_MU1_3_CODING BITS(25, 28) /* VHT_SIG_A2[B4:B7] */ +#define RX_VT_SU_VHT_MU1_3_CODING_OFFSET 25 +#define RX_VT_BEAMFORMED BIT(29) /* VHT_SIG_A2[B8] */ +#define RX_VT_ACID_DET_LOW BIT(30) +#define RX_VT_ACID_DET_HIGH BIT(31) + +#define RX_VT_RX_RATE_1M 0x0 +#define RX_VT_RX_RATE_2M 0x1 +#define RX_VT_RX_RATE_5M 0x2 +#define RX_VT_RX_RATE_11M 0x3 +#define RX_VT_RX_RATE_6M 0xB +#define RX_VT_RX_RATE_9M 0xF +#define RX_VT_RX_RATE_12M 0xA +#define RX_VT_RX_RATE_18M 0xE +#define RX_VT_RX_RATE_24M 0x9 +#define RX_VT_RX_RATE_36M 0xD +#define RX_VT_RX_RATE_48M 0x8 +#define RX_VT_RX_RATE_54M 0xC + +#define RX_VT_RX_RATE_MCS0 0 +#define RX_VT_RX_RATE_MCS1 1 +#define RX_VT_RX_RATE_MCS2 2 +#define RX_VT_RX_RATE_MCS3 3 +#define RX_VT_RX_RATE_MCS4 4 +#define RX_VT_RX_RATE_MCS5 5 +#define RX_VT_RX_RATE_MCS6 6 +#define RX_VT_RX_RATE_MCS7 7 +#define RX_VT_RX_RATE_MCS32 32 + +#define RX_VT_LEGACY_CCK 0 +#define RX_VT_LEGACY_OFDM 1 +#define RX_VT_MIXED_MODE 2 +#define RX_VT_GREEN_MODE 3 +#define RX_VT_VHT_MODE 4 + +#define RX_VT_LG20_HT20 0 +#define RX_VT_DL40_HT40 1 +#define RX_VT_U20 2 +#define RX_VT_L20 3 + +#define RX_VT_FR_MODE_20 0 +#define RX_VT_FR_MODE_40 1 +#define RX_VT_FR_MODE_80 2 +#define RX_VT_FR_MODE_160 3 /*BW160 or BW80+80*/ + +#define RX_VT_CCK_SHORT_PREAMBLE BIT(2) + +/* RX Vector, 2nd Cycle */ +#define RX_VT_RX_LEN_HT_MASK BITS(0, 15) +#define RX_VT_RX_LEN_LEACY_MASK BITS(0, 11) +#define RX_VT_RX_LEN_VHT_MASK BITS(0, 20) +#define RX_VT_GROUP_ID_MASK BITS(21, 26) +#define RX_VT_GROUP_ID_OFFSET 21 +#define RX_VT_GROUPID_0_MASK BITS(21, 22) /* VHT_SIG_A1[B4:B5] */ +#define RX_VT_GROUPID_0_OFFSET 21 +#define RX_VT_GROUPID_1_MASK BITS(23, 26) /* VHT_SIG_A1[B6:B9] */ +#define RX_VT_GROUPID_1_OFFSET 23 + +#define RX_VT_NSTS_MASK BITS(27, 29) +#define RX_VT_NSTS_OFFSET 27 +#define RX_VT_RX_INDICATOR BIT(30) +#define RX_VT_SEL_ANT BIT(31) /* Not use in MT7615 and MT6632 */ + +/* RX Vector, 3rd Cycle */ +#define RX_VT_PART_AID_MASK BITS(3, 11) +#define RX_VT_PART_AID_OFFSET 3 +#define RX_VT_AID_0_MASK BITS(3, 6) /* VHT_SIG_A1[B13:B16] */ +#define RX_VT_AID_0_OFFSET 3 +#define RX_VT_AID_1_MASK BITS(7, 11) /* VHT_SIG_A1[B17:B21] */ +#define RX_VT_AID_1_OFFSET 7 + +#define RX_VT_NSTS_PART_AID_MASK BITS(0, 11) +#define RX_VT_NSTS_PART_AID_OFFSET 0 +#define RX_VT_POP_EVER_TRIG BIT(12) +#define RX_VT_FAGC_LNA_RX_MASK BITS(13, 15) +#define RX_VT_FAGC_LNA_RX_OFFSET 13 +#define RX_VT_IB_RSSI_MASK BITS(16, 23) +#define RX_VT_IB_RSSI_OFFSET 16 +#define RX_VT_WB_RSSI_MASK BITS(24, 31) +#define RX_VT_WB_RSSI_OFFSET 24 + +/* RX Vector, 4th Cycle */ +#define RX_VT_RCPI0_MASK BITS(0, 7) +#define RX_VT_RCPI0_OFFSET 0 +#define RX_VT_RCPI1_MASK BITS(8, 15) +#define RX_VT_RCPI1_OFFSET 8 +#define RX_VT_RCPI2_MASK BITS(16, 23) +#define RX_VT_RCPI2_OFFSET 16 +#define RX_VT_RCPI3_MASK BITS(24, 31) +#define RX_VT_RCPI3_OFFSET 24 + +/* RX Vector, 5th Cycle */ +#define RX_VT_FAGC_LNA_GAIN_MASK BITS(0, 2) +#define RX_VT_FAGC_LNA_GAIN_OFFSET 0 +#define RX_VT_FAGC_LPF_GAIN_MASK BITS(3, 6) +#define RX_VT_FAGC_LPF_GAIN_OFFSET 3 +#define RX_VT_OFDM_FOE_MASK BITS(7, 18) +#define RX_VT_OFDM_FOE_OFFSET 7 +#define RX_VT_LTF_PROC_TIME_MASK BITS(19, 25) +#define RX_VT_LTF_PROC_TIME_OFFSET 19 +#define RX_VT_LTF_SNR_MASK BITS(26, 31) +#define RX_VT_LTF_SNR_OFFSET 26 + +/*RX Vector, 6th Cycle*/ +#define RX_VT_NF0_MASK BITS(0, 7) +#define RX_VT_NF0_OFFSET 0 +#define RX_VT_NF1_MASK BITS(8, 15) +#define RX_VT_NF1_OFFSET 8 +#define RX_VT_NF2_MASK BITS(16, 23) +#define RX_VT_NF2_OFFSET 16 +#define RX_VT_NF3_MASK BITS(24, 31) +#define RX_VT_NF3_OFFSET 24 + +/* RX Vector Group 2, the 1st cycle */ +#define RX_VT_PRIM_ITFR_ENV BIT(0) +#define RX_VT_SEC_ITFR_ENV BIT(1) +#define RX_VT_SEC40_ITFR_ENV BIT(2) +#define RX_VT_SEC80_ITFR_ENV BIT(3) +#define RX_VT_OFDM_LQ_BPSK_MASK BITS(4, 10) +#define RX_VT_OFDM_LQ_BPSK_OFFSET 4 +#define RX_VT_OFDM_CAPACITY_LQ_MASK BITS(11, 17) +#define RX_VT_OFDM_CAPACITY_LQ_OFFSET 11 +#define RX_VT_CCK_LQ_MASK BITS(4, 13) +#define RX_VT_CCK_LQ_OFFSET 4 + +/* RX Vector Group 2, the 2nd cycle */ +#define RX_VT_DYNA_BW_IN_NON_HT_DYNA BIT(19) +#define RX_VT_CH_BW_IN_NON_HT_MASK BITS(20, 21) +#define RX_VT_CH_BW_IN_NON_HT_OFFSET 20 + +#define RX_VT_CH_BW_IN_NON_HT_CBW40 BIT(20) +#define RX_VT_CH_BW_IN_NON_HT_CBW80 BIT(21) +#define RX_VT_CH_BW_IN_NON_HT_CBW160 BITS(20, 21) + +/* RX Data Type */ +#define RX_DATA_TYPE_RX_VECTOR 0 +#define RX_DATA_TYPE_RX_DATA 1 +#define RX_DATA_TYPE_RX_EVM 2 +#define RX_DATA_TYPE_RX_AMBI 3 +#define RX_DATA_TYPE_RX_BT 4 + +/*------------------------------------------------------------------------------ + * Radiotap define + *------------------------------------------------------------------------------ + */ + +/*Radiotap VHT*/ +#define RADIOTAP_VHT_ALL_KNOWN BITS(0, 8) +#define RADIOTAP_VHT_STBC_KNOWN BIT(0) +#define RADIOTAP_VHT_TXOP_PS_NOT_ALLOWED_KNOWN BIT(1) +#define RADIOTAP_VHT_GI_KNOWN BIT(2) +#define RADIOTAP_VHT_SHORT_GI_NSYM_KNOWN BIT(3) +#define RADIOTAP_VHT_LDPC_EXTRA_OFDM_SYM_KNOWN BIT(4) +#define RADIOTAP_VHT_BEAMFORMED_KNOWN BIT(5) +#define RADIOTAP_VHT_BAND_WIDTH_KNOWN BIT(6) +#define RADIOTAP_VHT_BAND_GROUP_ID_KNOWN BIT(7) +#define RADIOTAP_VHT_BAND_PARTIAL_AID_KNOWN BIT(8) + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef enum _ENUM_RX_STATISTIC_COUNTER_T { + RX_MPDU_TOTAL_COUNT = 0, + RX_SIZE_ERR_DROP_COUNT, + + RX_DATA_INDICATION_COUNT, + RX_DATA_RETURNED_COUNT, + RX_DATA_RETAINED_COUNT, + + RX_DATA_REORDER_TOTAL_COUINT, + RX_DATA_REORDER_MISS_COUNT, + RX_DATA_REORDER_WITHIN_COUNT, + RX_DATA_REORDER_AHEAD_COUNT, + RX_DATA_REORDER_BEHIND_COUNT, + RX_DATA_REORDER_BEHIND_CONTINUOUS_COUNT, + + RX_DATA_MSDU_IN_AMSDU_COUNT, + RX_DATA_AMSDU_MISS_COUNT, + RX_DATA_AMSDU_COUNT, + + RX_DROP_TOTAL_COUNT, + + RX_NO_STA_DROP_COUNT, + RX_INACTIVE_BSS_DROP_COUNT, + RX_HS20_DROP_COUNT, + RX_LESS_SW_RFB_DROP_COUNT, + RX_DUPICATE_DROP_COUNT, + RX_MIC_ERROR_DROP_COUNT, + RX_BAR_DROP_COUNT, + RX_NO_INTEREST_DROP_COUNT, + RX_TYPE_ERR_DROP_COUNT, + RX_CLASS_ERR_DROP_COUNT, + RX_DST_NULL_DROP_COUNT, + +#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 + RX_CSUM_TCP_FAILED_COUNT, + RX_CSUM_UDP_FAILED_COUNT, + RX_CSUM_IP_FAILED_COUNT, + RX_CSUM_TCP_SUCCESS_COUNT, + RX_CSUM_UDP_SUCCESS_COUNT, + RX_CSUM_IP_SUCCESS_COUNT, + RX_CSUM_UNKNOWN_L4_PKT_COUNT, + RX_CSUM_UNKNOWN_L3_PKT_COUNT, + RX_IP_V6_PKT_CCOUNT, +#endif +#if CFG_KEY_ERROR_STATISTIC_RECOVERY + RX_BMC_NO_KEY_COUNT, + RX_BMC_KEY_ERROR_COUNT, + RX_BMC_PKT_COUNT, +#endif + RX_STATISTIC_COUNTER_NUM +} ENUM_RX_STATISTIC_COUNTER_T; + +typedef enum _ENUM_RX_PKT_DESTINATION_T { + RX_PKT_DESTINATION_HOST, /* to OS */ + RX_PKT_DESTINATION_FORWARD, /* to TX queue for forward, AP mode */ + RX_PKT_DESTINATION_HOST_WITH_FORWARD, /* to both TX and OS, AP mode + * broadcast packet */ + RX_PKT_DESTINATION_NULL, /* packet to be freed */ + RX_PKT_DESTINATION_NUM +} ENUM_RX_PKT_DESTINATION_T; + +/* Used for MAC RX */ +typedef enum _ENUM_MAC_RX_PKT_TYPE_T { + RX_PKT_TYPE_TX_STATUS = 0, + RX_PKT_TYPE_RX_VECTOR, + RX_PKT_TYPE_RX_DATA, + RX_PKT_TYPE_DUP_RFB, + RX_PKT_TYPE_TM_REPORT, + RX_PKT_TYPE_MSDU_REPORT = 6, + RX_PKT_TYPE_SW_DEFINED = 7 +} ENUM_MAC_RX_PKT_TYPE_T; + +typedef enum _ENUM_MAC_RX_GROUP_VLD_T { + RX_GROUP_VLD_1 = 0, + RX_GROUP_VLD_2, + RX_GROUP_VLD_3, + RX_GROUP_VLD_4, + RX_GROUP_VLD_NUM +} ENUM_MAC_RX_GROUP_VLD_T; + +typedef enum _ENUM_MAC_GI_INFO_T { + MAC_GI_NORMAL = 0, + MAC_GI_SHORT +} ENUM_MAC_GI_INFO_T, +*P_ENUM_MAC_GI_INFO_T; + +typedef enum _ENUM_RXPI_MODE_T { + RCPI_MODE_WF0 = 0, + RCPI_MODE_WF1, + RCPI_MODE_WF2, + RCPI_MODE_WF3, + RCPI_MODE_AVG, + RCPI_MODE_MAX, + RCPI_MODE_MIN, + RCPI_MODE_NUM +} ENUM_RXPI_MODE_T; + +#define RXM_RXD_PKT_TYPE_SW_BITMAP 0xE00F +#define RXM_RXD_PKT_TYPE_SW_EVENT 0xE000 +#define RXM_RXD_PKT_TYPE_SW_FRAME 0xE001 + +/* AMPDU data frame with no errors including FC/FM/I/T/LM/DAF/EL/LLC-MIS/ UDFVLT + * and Class 3 error */ +#define RXS_DW2_AMPDU_nERR_BITMAP 0xFFFB /* ignore CM bit (2) 0xFFFF */ +#define RXS_DW2_AMPDU_nERR_VALUE 0x0000 +/* no error including FC/CLM/I/T/LM/DAF/EL/HTF */ +#define RXS_DW2_RX_nERR_BITMAP 0x03FA /* ignore CM bit (2) 0x03FE */ +#define RXS_DW2_RX_nERR_VALUE 0x0000 +/* Non-Data frames */ +#define RXS_DW2_RX_nDATA_BITMAP 0x3000 +#define RXS_DW2_RX_nDATA_VALUE 0x2000 +/* Claas Error */ +#define RXS_DW2_RX_CLASSERR_BITMAP 0x0001 +#define RXS_DW2_RX_CLASSERR_VALUE 0x0001 +/* Fragmentation */ +#define RXS_DW2_RX_FRAG_BITMAP 0x3800 +#define RXS_DW2_RX_FRAG_VALUE 0x0800 + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/*! A data structure which is identical with MAC RX DMA Descriptor */ +typedef struct _HW_MAC_RX_DESC_T { + u16 u2RxByteCount; /* DW 0 */ + u16 u2PktTYpe; + u8 ucMatchPacket; /* DW 1 */ + u8 ucChanFreq; + u8 ucHeaderLen; + u8 ucBssid; + u8 ucWlanIdx; /* DW 2 */ + u8 ucTidSecMode; + u16 u2StatusFlag; + u32 u4PatternFilterInfo; /* DW 3 */ +} HW_MAC_RX_DESC_T, *P_HW_MAC_RX_DESC_T; + +typedef struct _HW_MAC_RX_STS_GROUP_1_T { + u8 aucPN[16]; +} HW_MAC_RX_STS_GROUP_1_T, *P_HW_MAC_RX_STS_GROUP_1_T; + +typedef struct _HW_MAC_RX_STS_GROUP_2_T { + u32 u4Timestamp; /* DW 12 */ + u32 u4CRC; /* DW 13 */ +} HW_MAC_RX_STS_GROUP_2_T, *P_HW_MAC_RX_STS_GROUP_2_T; + +typedef struct _HW_MAC_RX_STS_GROUP_4_T { + /* For HDR_TRAN */ + u16 u2FrameCtl; /* DW 4 */ + u8 aucTA[6]; /* DW 4~5 */ + u16 u2SeqFrag; /* DW 6 */ + u16 u2Qos; /* DW 6 */ + u32 u4HTC; /* DW 7 */ +} HW_MAC_RX_STS_GROUP_4_T, *P_HW_MAC_RX_STS_GROUP_4_T; + +typedef struct _HW_MAC_RX_STS_GROUP_3_T { + /*! RX Vector Info */ + u32 u4RxVector[6]; /* DW 14~19 */ +} HW_MAC_RX_STS_GROUP_3_T, *P_HW_MAC_RX_STS_GROUP_3_T; + +typedef struct _HW_MAC_RX_TMRI_PKT_FORMAT_T { + u8 ucPID; + u8 ucStatus; + u16 u2PktTYpe; + u32 u4Reserved[2]; + u32 u4ToA; + u32 u4ToD; +} HW_MAC_RX_TMRI_PKT_FORMAT_T, *P_HW_MAC_RX_TMRI_PKT_FORMAT_T; + +typedef struct _HW_MAC_RX_TMRR_PKT_FORMAT_T { + u8 ucVtSeq; + u8 ucStatus; + u16 u2PktTYpe; + u8 aucTALow[2]; + u16 u2SnField; + u8 aucTAHigh[4]; + u32 u4ToA; + u32 u4ToD; +} HW_MAC_RX_TMRR_PKT_FORMAT_T, *P_HW_MAC_RX_TMRR_PKT_FORMAT_T; + +/*! A data structure which is identical with MAC RX Vector DMA Descriptor */ +typedef struct _HW_RX_VECTOR_DESC_T { + u8 aucTA[6]; /* DW 0~1 */ + u8 ucRxVtSeqNo; + /*! RX Vector Info */ + u32 u4RxVector[9]; /* DW 2~10 */ +} HW_RX_VECTOR_DESC_T, *P_HW_RX_VECTOR_DESC_T; + +typedef struct _HW_MAC_MSDU_REPORT_T { + /* 1st DW */ + u16 u2BufByteCount; + u16 u2MsduCount : 7; + u16 u2DoneEventType : 6; + u16 u2PktType : 3; + /* 2nd DW */ + u32 u4TxdCount : 8; + u32 u4RvS2 : 24; + /* MSDU token array */ + u16 au2MsduToken[0]; +} HW_MAC_MSDU_REPORT_T, *P_HW_MAC_MSDU_REPORT_T; + +struct _SW_RFB_T { + QUE_ENTRY_T rQueEntry; + void *pvPacket; /*!< ptr to rx Packet Descriptor */ + u8 *pucRecvBuff; /*!< ptr to receive data buffer */ + + /* add fot mt6630 */ + u8 ucGroupVLD; + u16 u2RxStatusOffst; + P_HW_MAC_RX_DESC_T prRxStatus; + P_HW_MAC_RX_STS_GROUP_1_T prRxStatusGroup1; + P_HW_MAC_RX_STS_GROUP_2_T prRxStatusGroup2; + P_HW_MAC_RX_STS_GROUP_3_T prRxStatusGroup3; + P_HW_MAC_RX_STS_GROUP_4_T prRxStatusGroup4; + + /* rx data information */ + void *pvHeader; + u16 u2PacketLen; + u16 u2HeaderLen; + u8 ucHeaderOffset; + + u8 *pucPayload; + u16 u2PayloadLength; + + P_STA_RECORD_T prStaRec; + + u8 ucPacketType; + u8 ucPayloadFormat; + u8 ucSecMode; + + /* rx sta record */ + u8 ucWlanIdx; + u8 ucStaRecIdx; + + u8 fgReorderBuffer; + u8 fgDataFrame; + u8 fgFragFrame; + u8 fgHdrTran; + u8 fgIsBC; + u8 fgIsMC; + /* duplicate detection */ + u16 u2FrameCtrl; + u16 u2SequenceControl; + u16 u2SSN; + u8 ucTid; + + ENUM_CSUM_RESULT_T aeCSUM[CSUM_TYPE_NUM]; + ENUM_RX_PKT_DESTINATION_T eDst; + ENUM_TRAFFIC_CLASS_INDEX_T eTC; /* only valid when eDst == FORWARD */ +}; + +/*! RX configuration type structure */ +typedef struct _RX_CTRL_T { + u32 u4RxCachedSize; + u8 *pucRxCached; + QUE_T rFreeSwRfbList; + QUE_T rReceivedRfbList; + QUE_T rIndicatedRfbList; + +#if CFG_SDIO_RX_AGG + u8 *pucRxCoalescingBufPtr; +#endif + + void *apvIndPacket[CFG_RX_MAX_PKT_NUM]; + void *apvRetainedPacket[CFG_RX_MAX_PKT_NUM]; + + u8 ucNumIndPacket; + u8 ucNumRetainedPacket; + u64 au8Statistics[RX_STATISTIC_COUNTER_NUM]; /*!< RX Counters */ + +#if CFG_HIF_STATISTICS + u32 u4TotalRxAccessNum; + u32 u4TotalRxPacketNum; +#endif + +#if CFG_HIF_RX_STARVATION_WARNING + u32 u4QueuedCnt; + u32 u4DequeuedCnt; +#endif + +#if CFG_RX_PKTS_DUMP + u32 u4RxPktsDumpTypeMask; +#endif + +#if CFG_SUPPORT_SNIFFER + u32 u4AmpduRefNum; +#endif +} RX_CTRL_T, *P_RX_CTRL_T; + +typedef struct _RX_MAILBOX_T { + u32 u4RxMailbox[2]; /* for Device-to-Host Mailbox */ +} RX_MAILBOX_T, *P_RX_MAILBOX_T; + +typedef WLAN_STATUS (*PROCESS_RX_MGT_FUNCTION)(P_ADAPTER_T, P_SW_RFB_T); + +typedef void (*PROCESS_RX_EVENT_FUNCTION)(P_ADAPTER_T, P_WIFI_EVENT_T, u32); + +typedef struct _RX_EVENT_HANDLER_T { + ENUM_EVENT_ID_T eEID; + PROCESS_RX_EVENT_FUNCTION pfnHandler; +} RX_EVENT_HANDLER_T, *P_RX_EVENT_HANDLER_T; + +typedef struct _EMU_MAC_RATE_INFO_T { + u8 ucPhyRateCode; + u32 u4PhyRate[4][2]; +} EMU_MAC_RATE_INFO_T, *P_EMU_MAC_RATE_INFO_T; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define RATE_INFO(_RateCode, _Bw20, _Bw20SGI, _Bw40, _BW40SGI, _Bw80, \ + _Bw80SGI, _Bw160, _Bw160SGI) \ + { \ + .ucPhyRateCode = (_RateCode), \ + .u4PhyRate[RX_VT_FR_MODE_20][MAC_GI_NORMAL] = (_Bw20), \ + .u4PhyRate[RX_VT_FR_MODE_20][MAC_GI_SHORT] = (_Bw20SGI), \ + .u4PhyRate[RX_VT_FR_MODE_40][MAC_GI_NORMAL] = (_Bw40), \ + .u4PhyRate[RX_VT_FR_MODE_40][MAC_GI_SHORT] = (_BW40SGI), \ + .u4PhyRate[RX_VT_FR_MODE_80][MAC_GI_NORMAL] = (_Bw80), \ + .u4PhyRate[RX_VT_FR_MODE_80][MAC_GI_SHORT] = (_Bw80SGI), \ + .u4PhyRate[RX_VT_FR_MODE_160][MAC_GI_NORMAL] = (_Bw160), \ + .u4PhyRate[RX_VT_FR_MODE_160][MAC_GI_SHORT] = (_Bw160SGI), \ + } + +#define RX_INC_CNT(prRxCtrl, eCounter) \ + { \ + ((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter]++; \ + } + +#define RX_ADD_CNT(prRxCtrl, eCounter, u8Amount) \ + { \ + ((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter] += \ + (u64)u8Amount; \ + } + +#define RX_GET_CNT(prRxCtrl, eCounter) \ + (((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter]) + +#define RX_RESET_CNT(prRxCtrl, eCounter) \ + { \ + ((P_RX_CTRL_T)prRxCtrl)->au8Statistics[eCounter] = 0; \ + } + +#define RX_RESET_ALL_CNTS(prRxCtrl) \ + { \ + kalMemZero(&prRxCtrl->au8Statistics[0], \ + sizeof(prRxCtrl->au8Statistics)); \ + } + +#define RX_STATUS_TEST_MORE_FLAG(flag) \ + ((u8)((flag & RX_STATUS_FLAG_MORE_PACKET) ? true : false)) + +/*------------------------------------------------------------------------------ + * MACRO for HW_MAC_RX_DESC_T + *------------------------------------------------------------------------------ + */ +/* DW 0 */ +#define HAL_RX_STATUS_GET_RX_BYTE_CNT(_prHwMacRxDesc) \ + ((_prHwMacRxDesc)->u2RxByteCount) +#define HAL_RX_STATUS_GET_ETH_TYPE_OFFSET(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2PktTYpe & RX_STATUS_ETH_TYPE_OFFSET_MASK) >> \ + RX_STATUS_ETH_TYPE_OFFSET) +#define HAL_RX_STATUS_GET_GROUP_VLD(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2PktTYpe & RX_STATUS_GROUP_VLD_MASK) >> \ + RX_STATUS_GROUP_VLD_OFFSET) +#define HAL_RX_STATUS_GET_PKT_TYPE(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2PktTYpe & RX_STATUS_PKT_TYPE_MASK) >> \ + RX_STATUS_PKT_TYPE_OFFSET) + +/* DW 1 */ +#define HAL_RX_STATUS_IS_HTC_EXIST(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->ucMatchPacket & RX_STATUS_HTC) ? true : false) +#define HAL_RX_STATUS_IS_U2ME(_prHwMacRxDesc) \ + ((((_prHwMacRxDesc)->ucMatchPacket & RX_STATUS_A1_TYPE_MASK) >> \ + RX_STATUS_A1_TYPE_OFFSET == \ + RX_STATUS_UC2ME) ? \ + true : \ + false) +#define HAL_RX_STATUS_IS_MC(_prHwMacRxDesc) \ + ((((_prHwMacRxDesc)->ucMatchPacket & RX_STATUS_A1_TYPE_MASK) >> \ + RX_STATUS_A1_TYPE_OFFSET == \ + RX_STATUS_MC_FRAME) ? \ + true : \ + false) +#define HAL_RX_STATUS_IS_BC(_prHwMacRxDesc) \ + ((((_prHwMacRxDesc)->ucMatchPacket & RX_STATUS_A1_TYPE_MASK) >> \ + RX_STATUS_A1_TYPE_OFFSET == \ + RX_STATUS_BC_FRAME) ? \ + true : \ + false) +#define HAL_RX_STATUS_IS_BCN_WITH_BMC(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->ucMatchPacket & RX_STATUS_BCN_WITH_BMC) ? true : \ + false) +#define HAL_RX_STATUS_IS_BCN_WITH_UC(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->ucMatchPacket & RX_STATUS_BCN_WITH_UC) ? true : \ + false) +#define HAL_RX_STATUS_GET_KEY_ID(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->ucMatchPacket & RX_STATUS_KEYID_MASK) >> \ + RX_STATUS_KEYID_OFFSET) +#define HAL_RX_STATUS_GET_CHAN_FREQ(_prHwMacRxDesc) \ + ((_prHwMacRxDesc)->ucChanFreq) +#define HAL_RX_STATUS_GET_HEADER_LEN(_prHwMacRxDesc) \ + ((_prHwMacRxDesc)->ucHeaderLen & RX_STATUS_HEADER_LEN_MASK) +#define HAL_RX_STATUS_IS_HEADER_OFFSET(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->ucHeaderLen & RX_STATUS_HEADER_OFFSET) ? true : \ + false) +#define HAL_RX_STATUS_GET_HEADER_OFFSET(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->ucHeaderLen & RX_STATUS_HEADER_OFFSET) ? 2 : 0) +#define HAL_RX_STATUS_IS_HEADER_TRAN(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->ucHeaderLen & RX_STATUS_HEADER_TRAN) ? true : false) +#define HAL_RX_STATUS_GET_HEADER_TRAN(_prHwMacRxDesc) \ + HAL_RX_STATUS_IS_HEADER_TRAN(_prHwMacRxDesc) +#define HAL_RX_STATUS_GET_PAYLOAD_FORMAT(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->ucBssid & RX_STATUS_PAYLOAD_FORMAT_MASK) >> \ + RX_STATUS_PAYLOAD_FORMAT_OFFSET) +#define HAL_RX_STATUS_GET_BSSID(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->ucBssid & RX_STATUS_BSSID_MASK) >> \ + RX_STATUS_BSSID_OFFSET) + +/* DW 2 */ +#define HAL_RX_STATUS_GET_WLAN_IDX( \ + _prHwMacRxDesc) ((_prHwMacRxDesc)->ucWlanIdx) +#define HAL_RX_STATUS_GET_TID(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->ucTidSecMode & RX_STATUS_TID_MASK)) +#define HAL_RX_STATUS_GET_SEC_MODE(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->ucTidSecMode & RX_STATUS_SEC_MASK) >> \ + RX_STATUS_SEC_OFFSET) +#define HAL_RX_STATUS_GET_SW_BIT(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_SW_BIT) ? true : false) +#define HAL_RX_STATUS_IS_FCS_ERROR(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_FLAG_FCS_ERROR) ? true : \ + false) +#define HAL_RX_STATUS_IS_CIPHER_MISMATCH(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_FLAG_CIPHER_MISMATCH) ? \ + true : \ + false) +#define HAL_RX_STATUS_IS_CLM_ERROR(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & \ + RX_STATUS_FLAG_CIPHER_LENGTH_MISMATCH) ? \ + true : \ + false) +#define HAL_RX_STATUS_IS_ICV_ERROR(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_FLAG_ICV_ERROR) ? true : \ + false) +#define HAL_RX_STATUS_IS_TKIP_MIC_ERROR(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_FLAG_TKIPMIC_ERROR) > 0 ? \ + true : \ + false) +#define HAL_RX_STATUS_IS_ERROR(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_FLAG_ERROR_MASK) ? true : \ + false) +#define HAL_RX_STATUS_IS_LEN_MISMATCH(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_FLAG_LEN_MISMATCH) ? \ + true : \ + false) +#define HAL_RX_STATUS_IS_DE_AMSDU_FAIL(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_FLAG_DE_AMSDU_FAIL) ? \ + true : \ + false) +#define HAL_RX_STATUS_IS_EXCEED_LEN(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_FLAG_EXCEED_LEN) ? true : \ + false) +#define HAL_RX_STATUS_IS_LLC_MIS(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_LLC_MIS) ? true : false) +#define HAL_RX_STATUS_IS_UDF_VLT(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_UDF_VLT) ? true : false) +#define HAL_RX_STATUS_IS_FRAG(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_FRAG) ? true : false) +#define HAL_RX_STATUS_IS_NULL(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_NULL) ? true : false) +#define HAL_RX_STATUS_IS_DATA(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_DATA) ? false : true) +#define HAL_RX_STATUS_IS_AMPDU_SUB_FRAME(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_AMPDU_SUB_FRAME) ? \ + false : \ + true) +#define HAL_RX_STATUS_IS_AMPDU_FORMAT(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u2StatusFlag & RX_STATUS_AMPDU_FORMAT) ? false : \ + true) + +/* DW 3 */ +#define HAL_RX_STATUS_IS_RV_VALID(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u4PatternFilterInfo & RX_STATUS_RXV_SEQ_NO_MASK) ? \ + true : \ + false) +#define HAL_RX_STATUS_GET_RXV_SEQ_NO(_prHwMacRxDesc) \ + ((_prHwMacRxDesc)->u4PatternFilterInfo & RX_STATUS_RXV_SEQ_NO_MASK) +#define HAL_RX_STATUS_GET_TCL(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u4PatternFilterInfo & RX_STATUS_TCL) ? true : false) +#define HAL_RX_STATUS_IS_CLS(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u4PatternFilterInfo & RX_STATUS_CLS) ? true : false) +#define HAL_RX_STATUS_GET_OFLD(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u4PatternFilterInfo & RX_STATUS_OFLD_MASK) >> \ + RX_STATUS_OFLD_OFFSET) +#define HAL_RX_STATUS_IS_MGC(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u4PatternFilterInfo & RX_STATUS_MGC) ? true : false) +#define HAL_RX_STATUS_GET_WOL(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u4PatternFilterInfo & RX_STATUS_WOL_MASK) >> \ + RX_STATUS_WOL_OFFSET) +#define HAL_RX_STATUS_GET_CLS_BITMAP(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u4PatternFilterInfo & \ + RX_STATUS_CLS_BITMAP_MASK) >> \ + RX_STATUS_CLS_BITMAP_OFFSET) +#define HAL_RX_STATUS_IS_PF_BLACK_LIST(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u4PatternFilterInfo & \ + RX_STATUS_PF_MODE_BLACK_LIST) ? \ + true : \ + false) +#define HAL_RX_STATUS_IS_PF_CHECKED(_prHwMacRxDesc) \ + (((_prHwMacRxDesc)->u4PatternFilterInfo & RX_STATUS_PF_STS_CHECKED) ? \ + true : \ + false) + +/* DW 4~7 */ +#define HAL_RX_STATUS_GET_FRAME_CTL_FIELD(_prHwMacRxStsGroup4) \ + ((_prHwMacRxStsGroup4)->u2FrameCtl) +#define HAL_RX_STATUS_GET_TA(_prHwMacRxStsGroup4, pucTA) \ + { \ + kalMemCopy(pucTA, &(_prHwMacRxStsGroup4)->aucTA[0], 6); \ + } +#define HAL_RX_STATUS_GET_SEQ_FRAG_NUM(_prHwMacRxStsGroup4) \ + ((_prHwMacRxStsGroup4)->u2SeqFrag) +#define HAL_RX_STATUS_GET_QOS_CTL_FIELD(_prHwMacRxStsGroup4) \ + ((_prHwMacRxStsGroup4)->u2Qos) + +#define HAL_RX_STATUS_GET_SEQFrag_NUM(_prHwMacRxStsGroup4) \ + ((_prHwMacRxStsGroup4)->u2SeqFrag) +#define HAL_RX_STATUS_GET_HTC(_prHwMacRxStsGroup4) \ + ((_prHwMacRxStsGroup4)->u4HTC) + +/* DW 8~11 */ +#define HAL_RX_STATUS_GET_RSC(_prHwMacRxStsGroup1, pucRSC) \ + { \ + kalMemCopy(pucRSC, &(_prHwMacRxStsGroup1)->aucPN[0], 6); \ + } + +#define HAL_RX_STATUS_GET_PN(_prHwMacRxStsGroup1, pucPN) \ + { \ + kalMemCopy(pucPN, &(_prHwMacRxStsGroup1)->aucPN[0], 16); \ + } + +/* DW 12~13 */ +#define HAL_RX_STATUS_GET_TIMESTAMP(_prHwMacRxStsGroup2, _ucIdx) \ + ((_prHwMacRxStsGroup2)->u4Timestamp) +#define HAL_RX_STATUS_GET_FCS32(_prHwMacRxStsGroup2) \ + ((_prHwMacRxStsGroup2)->u4CRC) + +/* DW 14~19 */ +#define HAL_RX_STATUS_GET_RX_VECTOR(_prHwMacRxStsGroup3, _ucIdx) \ + ((_prHwMacRxStsGroup3)->u4RxVector[_ucIdx]) + +#define HAL_RX_STATUS_GET_RX_NUM(_prHwMacRxStsGroup3) \ + (((_prHwMacRxStsGroup3)->u4RxVector[0] & RX_VT_NUM_RX_MASK) >> \ + RX_VT_NUM_RX_OFFSET) + +#define HAL_RX_STATUS_GET_RCPI0(_prHwMacRxStsGroup3) \ + (((_prHwMacRxStsGroup3)->u4RxVector[3] & RX_VT_RCPI0_MASK) >> \ + RX_VT_RCPI0_OFFSET) +#define HAL_RX_STATUS_GET_RCPI1(_prHwMacRxStsGroup3) \ + (((_prHwMacRxStsGroup3)->u4RxVector[3] & RX_VT_RCPI1_MASK) >> \ + RX_VT_RCPI1_OFFSET) + +/* TBD */ +#define HAL_RX_STATUS_GET_RX_PACKET_LEN(_prHwMacRxDesc) +#define HAL_RX_STATUS_IS_MATCH_PACKET(_prHwMacRxDesc) + +#define HAL_RX_STATUS_GET_CHNL_NUM(_prHwMacRxDesc) \ + ((((_prHwMacRxDesc)->ucChanFreq) > HW_CHNL_NUM_MAX_4G_5G) ? \ + (((_prHwMacRxDesc)->ucChanFreq) - HW_CHNL_NUM_MAX_4G_5G) : \ + ((_prHwMacRxDesc)->ucChanFreq)) + +/* To do: support more bands other than 2.4G and 5G */ +#define HAL_RX_STATUS_GET_RF_BAND(_prHwMacRxDesc) \ + ((((_prHwMacRxDesc)->ucChanFreq) <= HW_CHNL_NUM_MAX_2G4) ? BAND_2G4 : \ + BAND_5G) + +/*------------------------------------------------------------------------------ + * MACRO for HW_RX_VECTOR_DESC_T + *------------------------------------------------------------------------------ + */ +#define HAL_RX_VECTOR_GET_TA(_prHwRxVector, pucTA) \ + { \ + kalMemCopy(pucTA, &(_prHwRxVector)->aucTA[0], 6); \ + } + +#define HAL_RX_VECTOR_GET_SEQ_NO(_prHwRxVector) \ + ((_prHwRxVector)->ucRxVtSeqNo & RX_STATUS_RXV_SEQ_NO_MASK) +#define HAL_RX_VECTOR_IS_FOR_BA_ACK(_prHwRxVector) \ + (((_prHwRxVector)->ucRxVtSeqNo & RX_VECTOR_FOR_BA_ACK) ? true : false) +#define HAL_RX_VECTOR_GET_RX_VECTOR(_prHwRxVector, _ucIdx) \ + ((_prHwRxVector)->u4RxVector[_ucIdx]) + +#define RXM_IS_QOS_DATA_FRAME(_u2FrameCtrl) \ + (((_u2FrameCtrl & MASK_FRAME_TYPE) == MAC_FRAME_QOS_DATA) ? true : \ + false) +#define RXM_IS_TO_DS(_u2FrameCtrl) \ + (((_u2FrameCtrl & MASK_TO_DS_FROM_DS) == MASK_FC_TO_DS) ? true : false) +#define RXM_IS_FROM_DS(_u2FrameCtrl) \ + (((_u2FrameCtrl & MASK_TO_DS_FROM_DS) == MASK_FC_FROM_DS) ? true : \ + false) +#define RXM_IS_MORE_DATA(_u2FrameCtrl) \ + (((_u2FrameCtrl & MASK_FC_MORE_DATA) == MASK_FC_MORE_DATA) ? true : \ + false) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void nicRxInitialize(IN P_ADAPTER_T prAdapter); + +void nicRxUninitialize(IN P_ADAPTER_T prAdapter); + +void nicRxProcessRFBs(IN P_ADAPTER_T prAdapter); + +void nicRxProcessMsduReport(IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb); + +WLAN_STATUS nicRxSetupRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prRfb); + +void nicRxReturnRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prRfb); + +void nicProcessRxInterrupt(IN P_ADAPTER_T prAdapter); + +void nicRxProcessPktWithoutReorder(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb); + +void nicRxProcessForwardPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +void nicRxProcessGOBroadcastPkt(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb); + +u8 nicRxFillRFB(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb); + +void nicRxClearFrag(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +P_SW_RFB_T incRxDefragMPDU(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSWRfb, + OUT P_QUE_T prReturnedQue); + +u8 nicRxIsDuplicateFrame(IN OUT P_SW_RFB_T prSwRfb); + +#if CFG_SUPPORT_SNIFFER +void nicRxProcessMonitorPacket(IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb); +#endif + +void nicRxProcessDataPacket(IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb); + +void nicRxProcessEventPacket(IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb); + +void nicRxProcessMgmtPacket(IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +void nicRxFillChksumStatus(IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb, + IN u32 u4TcpUdpIpCksStatus); + +void nicRxUpdateCSUMStatistics(IN P_ADAPTER_T prAdapter, + IN const ENUM_CSUM_RESULT_T aeCSUM[]); +#endif + +void nicRxQueryStatus(IN P_ADAPTER_T prAdapter, + IN u8 *pucBuffer, + OUT u32 *pu4Count); + +void nicRxClearStatistics(IN P_ADAPTER_T prAdapter); + +void nicRxQueryStatistics(IN P_ADAPTER_T prAdapter, + IN u8 *pucBuffer, + OUT u32 *pu4Count); + +WLAN_STATUS +nicRxWaitResponse(IN P_ADAPTER_T prAdapter, + IN u8 ucPortIdx, + OUT u8 *pucRspBuffer, + IN u32 u4MaxRespBufferLen, + OUT u32 *pu4Length); + +void nicRxEnablePromiscuousMode(IN P_ADAPTER_T prAdapter); + +void nicRxDisablePromiscuousMode(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicRxFlush(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicRxProcessActionFrame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb); + +u8 nicRxGetRcpiValueFromRxv(IN u8 ucRcpiMode, IN P_SW_RFB_T prSwRfb); + +#if CFG_SUPPORT_SNIFFER +void nicRxFillRadiotapMCS(IN OUT P_MONITOR_RADIOTAP_T prMonitorRadiotap, + IN P_HW_MAC_RX_STS_GROUP_3_T prRxStatusGroup3); +#endif + +void nicRxFillRadiotapVHT(IN OUT P_MONITOR_RADIOTAP_T prMonitorRadiotap, + IN P_HW_MAC_RX_STS_GROUP_3_T prRxStatusGroup3); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic_tx.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic_tx.h new file mode 100644 index 00000000000000..944b0bdd0dce86 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic_tx.h @@ -0,0 +1,1790 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file nic_tx.h + * \brief Functions that provide TX operation in NIC's point of view. + * + * This file provides TX functions which are responsible for both Hardware + * and Software Resource Management and keep their Synchronization. + * + */ + +#ifndef _NIC_TX_H +#define _NIC_TX_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define UNIFIED_MAC_TX_FORMAT 1 + +#define MAC_TX_RESERVED_FIELD 0 + +#define NIC_TX_RESOURCE_POLLING_TIMEOUT 256 +#define NIC_TX_RESOURCE_POLLING_DELAY_MSEC 5 + +#define NIC_TX_CMD_INFO_RESERVED_COUNT 4 + +/* Maximum buffer count for individual HIF TCQ */ +#define NIC_TX_PAGE_COUNT_TC0 \ + (NIC_TX_BUFF_COUNT_TC0 * NIC_TX_MAX_PAGE_PER_FRAME) +#define NIC_TX_PAGE_COUNT_TC1 \ + (NIC_TX_BUFF_COUNT_TC1 * NIC_TX_MAX_PAGE_PER_FRAME) +#define NIC_TX_PAGE_COUNT_TC2 \ + (NIC_TX_BUFF_COUNT_TC2 * NIC_TX_MAX_PAGE_PER_FRAME) +#define NIC_TX_PAGE_COUNT_TC3 \ + (NIC_TX_BUFF_COUNT_TC3 * NIC_TX_MAX_PAGE_PER_FRAME) +#define NIC_TX_PAGE_COUNT_TC4 \ + (NIC_TX_BUFF_COUNT_TC4 * NIC_TX_MAX_PAGE_PER_FRAME) +#define NIC_TX_PAGE_COUNT_TC5 \ + (NIC_TX_BUFF_COUNT_TC5 * NIC_TX_MAX_PAGE_PER_FRAME) + +#define NIC_TX_BUFF_COUNT_TC0 HIF_TX_BUFF_COUNT_TC0 +#define NIC_TX_BUFF_COUNT_TC1 HIF_TX_BUFF_COUNT_TC1 +#define NIC_TX_BUFF_COUNT_TC2 HIF_TX_BUFF_COUNT_TC2 +#define NIC_TX_BUFF_COUNT_TC3 HIF_TX_BUFF_COUNT_TC3 +#define NIC_TX_BUFF_COUNT_TC4 HIF_TX_BUFF_COUNT_TC4 +#define NIC_TX_BUFF_COUNT_TC5 HIF_TX_BUFF_COUNT_TC5 + +#define NIC_TX_RESOURCE_CTRL \ + HIF_TX_RESOURCE_CTRL /* to enable/disable TX resource control */ + +#if CFG_ENABLE_FW_DOWNLOAD + +#define NIC_TX_INIT_BUFF_COUNT_TC0 8 +#define NIC_TX_INIT_BUFF_COUNT_TC1 0 +#define NIC_TX_INIT_BUFF_COUNT_TC2 0 +#define NIC_TX_INIT_BUFF_COUNT_TC3 0 +#define NIC_TX_INIT_BUFF_COUNT_TC4 8 +#define NIC_TX_INIT_BUFF_COUNT_TC5 0 + +#define NIC_TX_INIT_BUFF_SUM \ + (NIC_TX_INIT_BUFF_COUNT_TC0 + NIC_TX_INIT_BUFF_COUNT_TC1 + \ + NIC_TX_INIT_BUFF_COUNT_TC2 + NIC_TX_INIT_BUFF_COUNT_TC3 + \ + NIC_TX_INIT_BUFF_COUNT_TC4 + NIC_TX_INIT_BUFF_COUNT_TC5) + +#define NIC_TX_INIT_PAGE_COUNT_TC0 \ + (NIC_TX_INIT_BUFF_COUNT_TC0 * NIC_TX_MAX_PAGE_PER_FRAME) +#define NIC_TX_INIT_PAGE_COUNT_TC1 \ + (NIC_TX_INIT_BUFF_COUNT_TC1 * NIC_TX_MAX_PAGE_PER_FRAME) +#define NIC_TX_INIT_PAGE_COUNT_TC2 \ + (NIC_TX_INIT_BUFF_COUNT_TC2 * NIC_TX_MAX_PAGE_PER_FRAME) +#define NIC_TX_INIT_PAGE_COUNT_TC3 \ + (NIC_TX_INIT_BUFF_COUNT_TC3 * NIC_TX_MAX_PAGE_PER_FRAME) +#define NIC_TX_INIT_PAGE_COUNT_TC4 \ + (NIC_TX_INIT_BUFF_COUNT_TC4 * NIC_TX_MAX_PAGE_PER_FRAME) +#define NIC_TX_INIT_PAGE_COUNT_TC5 \ + (NIC_TX_INIT_BUFF_COUNT_TC5 * NIC_TX_MAX_PAGE_PER_FRAME) + +#endif + +#define NIC_TX_ENABLE_SECOND_HW_QUEUE 0 + +/* 4 TODO: The following values shall be got from FW by query CMD */ +/*------------------------------------------------------------------------*/ +/* Resource Management related information */ +/*------------------------------------------------------------------------*/ +#define NIC_TX_PAGE_SIZE_IS_POWER_OF_2 true +#define NIC_TX_PAGE_SIZE_IN_POWER_OF_2 HIF_TX_PAGE_SIZE_IN_POWER_OF_2 +#define NIC_TX_PAGE_SIZE HIF_TX_PAGE_SIZE + +/* For development only */ +#define NIC_TX_MAX_SIZE_PER_FRAME \ + 1532 /* calculated by MS native 802.11 format */ +#define NIC_TX_MAX_PAGE_PER_FRAME \ + ((NIC_TX_DESC_AND_PADDING_LENGTH + NIC_TX_DESC_HEADER_PADDING_LENGTH + \ + NIC_TX_MAX_SIZE_PER_FRAME + NIC_TX_PAGE_SIZE - 1) / \ + NIC_TX_PAGE_SIZE) + +/*------------------------------------------------------------------------*/ +/* Tx descriptor related information */ +/*------------------------------------------------------------------------*/ + +/* Frame Buffer + * |<--Tx Descriptor-->|<--Tx descriptor padding-->|<--802.3/802.11 + * Header-->|<--Header padding-->|<--Payload-->| + */ + +/* Tx descriptor length by format (TXD.FT) */ +#define NIC_TX_DESC_LONG_FORMAT_LENGTH_DW 8 /* in unit of double word */ +#define NIC_TX_DESC_LONG_FORMAT_LENGTH \ + DWORD_TO_BYTE(NIC_TX_DESC_LONG_FORMAT_LENGTH_DW) +#define NIC_TX_DESC_SHORT_FORMAT_LENGTH_DW 3 /* in unit of double word */ +#define NIC_TX_DESC_SHORT_FORMAT_LENGTH \ + DWORD_TO_BYTE(NIC_TX_DESC_SHORT_FORMAT_LENGTH_DW) + +/* Tx descriptor padding length (DMA.MICR.TXDSCR_PAD) */ +#define NIC_TX_DESC_PADDING_LENGTH_DW 0 /* in unit of double word */ +#define NIC_TX_DESC_PADDING_LENGTH DWORD_TO_BYTE( \ + NIC_TX_DESC_PADDING_LENGTH_DW) + +#define NIC_TX_PSE_HEADER_LENGTH 4 + +#define NIC_TX_DESC_AND_PADDING_LENGTH \ + (NIC_TX_DESC_LONG_FORMAT_LENGTH + NIC_TX_DESC_PADDING_LENGTH) + +/* Tx header padding (TXD.HeaderPadding) */ +/* Warning!! To use MAC header padding, every Tx packet must be decomposed */ +#define NIC_TX_DESC_HEADER_PADDING_LENGTH 0 /* in unit of bytes */ + +#define NIC_TX_DEFAULT_WLAN_INDEX \ + 31 /* For Tx packets to peer who has no WLAN table index. */ + +#define NIC_TX_DESC_PID_RESERVED 0 +#define NIC_TX_DESC_DRIVER_PID_MIN 1 +#define NIC_TX_DESC_DRIVER_PID_MAX 127 + +#define NIC_TX_DATA_DEFAULT_RETRY_COUNT_LIMIT 30 +#define NIC_TX_MGMT_DEFAULT_RETRY_COUNT_LIMIT 30 + +#define NIC_TX_AC_BE_REMAINING_TX_TIME \ + TX_DESC_TX_TIME_NO_LIMIT /* in unit of ms */ +#define NIC_TX_AC_BK_REMAINING_TX_TIME \ + TX_DESC_TX_TIME_NO_LIMIT /* in unit of ms */ +#define NIC_TX_AC_VO_REMAINING_TX_TIME \ + TX_DESC_TX_TIME_NO_LIMIT /* in unit of ms */ +#define NIC_TX_AC_VI_REMAINING_TX_TIME \ + TX_DESC_TX_TIME_NO_LIMIT /* in unit of ms */ +#define NIC_TX_MGMT_REMAINING_TX_TIME 2000 /* in unit of ms */ + +#define NIC_TX_CRITICAL_DATA_TID 7 +#define NIC_TX_AC_VO_TID 6 +#define NIC_TX_AC_VI_TID 5 +#define NIC_TX_AC_BE_TID 0 +#define NIC_TX_AC_BK_TID 1 + +#define HW_MAC_TX_DESC_APPEND_T_LENGTH 44 +#define NIC_TX_HEAD_ROOM \ + (NIC_TX_DESC_LONG_FORMAT_LENGTH + NIC_TX_DESC_PADDING_LENGTH + \ + HW_MAC_TX_DESC_APPEND_T_LENGTH) + +/*------------------------------------------------------------------------*/ +/* Tx status related information */ +/*------------------------------------------------------------------------*/ + +/* Tx status header & content length */ +#define NIC_TX_STATUS_HEADER_LENGTH_DW 1 /* in unit of double word */ +#define NIC_TX_STATUS_HEADER_LENGTH \ + DWORD_TO_BYTE(NIC_TX_STATUS_HEADER_LENGTH_DW) +#define NIC_TX_STATUS_LENGTH_DW 7 /* in unit of double word */ +#define NIC_TX_STATUS_LENGTH DWORD_TO_BYTE( \ + NIC_TX_STATUS_LENGTH_DW) + +/*------------------------------------------------------------------------*/ +/* Tx descriptor field related information */ +/*------------------------------------------------------------------------*/ +/* DW 0 */ +#define TX_DESC_TX_BYTE_COUNT_MASK BITS(0, 15) +#define TX_DESC_TX_BYTE_COUNT_OFFSET 0 + +#define TX_DESC_ETHER_TYPE_OFFSET_MASK BITS(0, 6) +#define TX_DESC_ETHER_TYPE_OFFSET_OFFSET 0 +#define TX_DESC_IP_CHKSUM_OFFLOAD BIT(7) +#define TX_DESC_TCP_UDP_CHKSUM_OFFLOAD BIT(0) +#define TX_DESC_USB_NEXT_VLD BIT(1) +#define TX_DESC_USB_TX_BURST BIT(2) +#define TX_DESC_QUEUE_INDEX_MASK BITS(2, 6) +#define TX_DESC_QUEUE_INDEX_OFFSET 2 +#define TX_DESC_PORT_INDEX BIT(7) +#define TX_DESC_PORT_INDEX_OFFSET 7 + +#define PORT_INDEX_LMAC 0 +#define PORT_INDEX_MCU 1 + +/* DW 1 */ +#define TX_DESC_WLAN_INDEX_MASK BITS(0, 7) +#define TX_DESC_WLAN_INDEX_OFFSET 0 +#define TX_DESC_HEADER_FORMAT_MASK BITS(5, 6) +#define TX_DESC_HEADER_FORMAT_OFFSET 5 + +#define HEADER_FORMAT_NON_802_11 0 /* Non-802.11 */ +#define HEADER_FORMAT_COMMAND 1 /* Command */ +#define HEADER_FORMAT_802_11_NORMAL_MODE 2 /* 802.11 (normal mode) */ +#define HEADER_FORMAT_802_11_ENHANCE_MODE 3 /* 802.11 (Enhancement mode) */ +#define HEADER_FORMAT_802_11_MASK BIT(1) + +#define TX_DESC_NON_802_11_MORE_DATA BIT(0) +#define TX_DESC_NON_802_11_EOSP BIT(1) +#define TX_DESC_NON_802_11_REMOVE_VLAN BIT(2) +#define TX_DESC_NON_802_11_VLAN_FIELD BIT(3) +#define TX_DESC_NON_802_11_ETHERNET_II BIT(4) +#define TX_DESC_NOR_802_11_HEADER_LENGTH_MASK BITS(0, 4) +#define TX_DESC_NOR_802_11_HEADER_LENGTH_OFFSET 0 +#define TX_DESC_ENH_802_11_EOSP BIT(1) +#define TX_DESC_ENH_802_11_AMSDU BIT(2) + +#define TX_DESC_FORMAT BIT(7) +#define TX_DESC_SHORT_FORMAT 0 +#define TX_DESC_LONG_FORMAT 1 + +#define TX_DESC_TXD_LENGTH_MASK BIT(0) +#define TX_DESC_TXD_LENGTH_OFFSET 0 + +#define TX_DESC_HEADER_PADDING_LENGTH_MASK BIT(1) +#define TX_DESC_HEADER_PADDING_LENGTH_OFFSET 1 +#define TX_DESC_HEADER_PADDING_MODE BIT(2) + +#define TX_DESC_TXD_EXTEND_LENGTH_MASK BIT(3) +#define TX_DESC_TXD_EXTEND_LENGTH_OFFSET 3 + +#define TX_DESC_TXD_UTXB_AMSDU_MASK BIT(4) +#define TX_DESC_TXD_UTXB_AMSDU_OFFSET 4 + +#define TX_DESC_TID_MASK BITS(5, 7) +#define TX_DESC_TID_OFFSET 5 +#define TX_DESC_TID_NUM 8 + +#define TX_DESC_PACKET_FORMAT_MASK BITS(0, 1) /* SW Field */ +#define TX_DESC_PACKET_FORMAT_OFFSET 0 +#define TX_DESC_OWN_MAC_MASK BITS(2, 7) +#define TX_DESC_OWN_MAC_OFFSET 2 + +/* DW 2 */ +#define TX_DESC_SUB_TYPE_MASK BITS(0, 3) +#define TX_DESC_SUB_TYPE_OFFSET 0 +#define TX_DESC_TYPE_MASK BITS(4, 5) +#define TX_DESC_TYPE_OFFSET 4 +#define TX_DESC_NDP BIT(6) +#define TX_DESC_NDPA BIT(7) + +#define TX_DESC_SOUNDING BIT(0) +#define TX_DESC_FORCE_RTS_CTS BIT(1) +#define TX_DESC_BROADCAST_MULTICAST BIT(2) +#define TX_DESC_BIP_PROTECTED BIT(3) +#define TX_DESC_DURATION_FIELD_CONTROL BIT(4) +#define TX_DESC_HTC_EXISTS BIT(5) +#define TX_DESC_FRAGMENT_MASK BITS(6, 7) +#define TX_DESC_FRAGMENT_OFFSET 6 +#define FRAGMENT_FISRT_PACKET 1 +#define FRAGMENT_MIDDLE_PACKET 2 +#define FRAGMENT_LAST_PACKET 3 + +#define TX_DESC_REMAINING_MAX_TX_TIME BITS(0, 7) +#define TX_DESC_TX_TIME_NO_LIMIT 0 +/* Unit of life time calculation of Tx descriptor */ +#define TX_DESC_LIFE_TIME_UNIT_IN_POWER_OF_2 5 +#define TX_DESC_LIFE_TIME_UNIT POWER_OF_2( \ + TX_DESC_LIFE_TIME_UNIT_IN_POWER_OF_2) +#define TX_DESC_POWER_OFFSET_MASK BITS(0, 4) +#define TX_DESC_BA_DISABLE BIT(5) +#define TX_DESC_TIMING_MEASUREMENT BIT(6) +#define TX_DESC_FIXED_RATE BIT(7) + +/* DW 3 */ +#define TX_DESC_NO_ACK BIT(0) +#define TX_DESC_PROTECTED_FRAME BIT(1) +#define TX_DESC_EXTEND_MORE_DATA BIT(2) +#define TX_DESC_EXTEND_EOSP BIT(3) + +#define TX_DESC_SW_RESERVED_MASK BITS(4, 5) +#define TX_DESC_SW_RESERVED_OFFSET 4 + +#define TX_DESC_TX_COUNT_MASK BITS(6, 10) +#define TX_DESC_TX_COUNT_OFFSET 6 +#define TX_DESC_TX_COUNT_NO_ATTEMPT 0 +#define TX_DESC_TX_COUNT_NO_LIMIT 31 +#define TX_DESC_REMAINING_TX_COUNT_MASK BITS(11, 15) +#define TX_DESC_REMAINING_TX_COUNT_OFFSET 11 +#define TX_DESC_SEQUENCE_NUMBER BITS(0, 11) +#define TX_DESC_HW_RESERVED_MASK BITS(12, 13) +#define TX_DESC_HW_RESERVED_OFFSET 12 +#define TX_DESC_PN_IS_VALID BIT(14) +#define TX_DESC_SN_IS_VALID BIT(15) + +/* DW 4 */ +#define TX_DESC_PN_PART1 BITS(0, 31) + +/* DW 5 */ +#define TX_DESC_PACKET_ID BIT(0, 7) +#define TX_DESC_TX_STATUS_FORMAT BIT(0) +#define TX_DESC_TX_STATUS_FORMAT_OFFSET 0 +#define TX_DESC_TX_STATUS_TO_MCU BIT(1) +#define TX_DESC_TX_STATUS_TO_HOST BIT(2) +#define TX_DESC_DA_SOURCE BIT(3) +#define TX_DESC_POWER_MANAGEMENT_CONTROL BIT(5) +#define TX_DESC_PN_PART2 BITS(0, 15) + +/* DW 6 */ /* FR = 1 */ +#define TX_DESC_BANDWIDTH_MASK BITS(0, 2) +#define TX_DESC_BANDWIDTH_OFFSET 0 +#define TX_DESC_DYNAMIC_BANDWIDTH BIT(3) +#define TX_DESC_ANTENNA_INDEX_MASK BITS(4, 15) +#define TX_DESC_ANTENNA_INDEX_OFFSET 4 + +#define TX_DESC_FIXDE_RATE_MASK BITS(0, 11) +#define TX_DESC_FIXDE_RATE_OFFSET 0 +#define TX_DESC_TX_RATE BITS(0, 5) +#define TX_DESC_TX_RATE_OFFSET 0 +#define TX_DESC_TX_MODE BITS(6, 8) +#define TX_DESC_TX_MODE_OFFSET 6 +#define TX_DESC_NSTS_MASK BITS(9, 10) +#define TX_DESC_NSTS_OFFSET 9 +#define TX_DESC_STBC BIT(11) +#define TX_DESC_BF BIT(12) +#define TX_DESC_LDPC BIT(13) +#define TX_DESC_GUARD_INTERVAL BIT(14) +#define TX_DESC_FIXED_RATE_MODE BIT(15) + +/* DW 7 */ +#define TX_DESC_SPE_EXT_IDX_MASK BITS(11, 15) +#define TX_DESC_SPE_EXT_IDX_OFFSET 11 + +#if CFG_ENABLE_PKT_LIFETIME_PROFILE +#define NIC_TX_TIME_THRESHOLD 100 /* in unit of ms */ +#endif + +#define NIC_TX_INIT_CMD_PORT HIF_TX_INIT_CMD_PORT + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* 3 */ /* Session for TX QUEUES */ +/* The definition in this ENUM is used to categorize packet's Traffic Class + * according to the their TID(User Priority). In order to achieve QoS goal, a + * particular TC should not block the process of another packet with different + * TC. In current design we will have 5 categories(TCs) of SW resource. + */ +/* TXD_PKT_FORMAT options*/ +typedef enum _ENUM_TXD_PKT_FORMAT_OPTION_T { + TXD_PKT_FORMAT_TXD = 0, /* TXD only */ + TXD_PKT_FORMAT_TXD_PAYLOAD, /* TXD and paload */ + TXD_PKT_FORMAT_COMMAND, /* Command */ + TXD_PKT_FORMAT_FWDL, /* Firmware download */ + TXD_PKT_FORMAT_NUM, +} ENUM_TXD_PKT_FORMAT_OPTION_T; + +/* HIF Tx interrupt status queue index*/ +typedef enum _ENUM_HIF_TX_INDEX_T { + HIF_TX_AC0_INDEX = 0, + HIF_TX_AC1_INDEX, + HIF_TX_AC2_INDEX, + HIF_TX_AC3_INDEX, + + HIF_TX_AC10_INDEX, + HIF_TX_AC11_INDEX, + HIF_TX_AC12_INDEX, + HIF_TX_AC13_INDEX, + + HIF_TX_AC20_INDEX, + HIF_TX_AC21_INDEX, + HIF_TX_AC22_INDEX, + HIF_TX_AC23_INDEX, + + HIF_TX_RSV0_INDEX, + HIF_TX_RSV1_INDEX, + HIF_TX_FFA_INDEX, + HIF_TX_CPU_INDEX, + + HIF_TX_NUM +} ENUM_HIF_TX_INDEX_T; + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) +#define HIF_TX_AC3X_INDEX HIF_TX_RSV0_INDEX +#endif + +/* LMAC Tx queue index */ +typedef enum _ENUM_MAC_TXQ_INDEX_T { + MAC_TXQ_AC0_INDEX = 0, + MAC_TXQ_AC1_INDEX, + MAC_TXQ_AC2_INDEX, + MAC_TXQ_AC3_INDEX, + + MAC_TXQ_AC10_INDEX, + MAC_TXQ_AC11_INDEX, + MAC_TXQ_AC12_INDEX, + MAC_TXQ_AC13_INDEX, + + MAC_TXQ_AC20_INDEX, + MAC_TXQ_AC21_INDEX, + MAC_TXQ_AC22_INDEX, + MAC_TXQ_AC23_INDEX, + + MAC_TXQ_AC30_INDEX, + MAC_TXQ_AC31_INDEX, + MAC_TXQ_AC32_INDEX, + MAC_TXQ_AC33_INDEX, + + MAC_TXQ_ALTX_0_INDEX, + MAC_TXQ_BMC_0_INDEX, + MAC_TXQ_BCN_0_INDEX, + MAC_TXQ_PSMP_0_INDEX, + + MAC_TXQ_ALTX_1_INDEX, + MAC_TXQ_BMC_1_INDEX, + MAC_TXQ_BCN_1_INDEX, + MAC_TXQ_PSMP_1_INDEX, + + MAC_TXQ_NAF_INDEX, + MAC_TXQ_NBCN_INDEX, + + MAC_TXQ_NUM +} ENUM_MAC_TXQ_INDEX_T; + +/* MCU quque index */ +typedef enum _ENUM_MCU_Q_INDEX_T { + MCU_Q0_INDEX = 0, + MCU_Q1_INDEX, + MCU_Q2_INDEX, + MCU_Q3_INDEX, + MCU_Q_NUM +} ENUM_MCU_Q_INDEX_T; + +/* Tc Resource index */ +typedef enum _ENUM_TRAFFIC_CLASS_INDEX_T { + /*First HW queue */ + TC0_INDEX = 0, /* HIF TX: AC0 packets */ + TC1_INDEX, /* HIF TX: AC1 packets */ + TC2_INDEX, /* HIF TX: AC2 packets */ + TC3_INDEX, /* HIF TX: AC3 packets */ + TC4_INDEX, /* HIF TX: CPU packets */ + TC5_INDEX, /* HIF TX: AC4 packets */ + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + TC6_INDEX, /* HIF TX: AC10 packets */ + TC7_INDEX, /* HIF TX: AC11 packets */ + TC8_INDEX, /* HIF TX: AC12 packets */ + TC9_INDEX, /* HIF TX: AC13 packets */ + TC10_INDEX, /* HIF TX: AC14 packets */ + + TC11_INDEX, /* HIF TX: AC20 packets */ + TC12_INDEX, /* HIF TX: AC21 packets */ + TC13_INDEX, /* HIF TX: AC22 packets */ + TC14_INDEX, /* HIF TX: AC23 packets */ + TC15_INDEX, /* HIF TX: AC24 packets */ + + TC16_INDEX, /* HIF TX: AC3x packets */ +#endif + +/* Second HW queue */ +#if NIC_TX_ENABLE_SECOND_HW_QUEUE + TC6_INDEX, /* HIF TX: AC10 packets */ + TC7_INDEX, /* HIF TX: AC11 packets */ + TC8_INDEX, /* HIF TX: AC12 packets */ + TC9_INDEX, /* HIF TX: AC13 packets */ + TC10_INDEX, /* HIF TX: AC14 packets */ +#endif + + TC_NUM /* Maximum number of Traffic Classes. */ +} ENUM_TRAFFIC_CLASS_INDEX_T; +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) +#define HIF_WMM_SET_NUM HW_WMM_NUM +#endif + +/* +1 for DBDC */ +#define TX_PORT_NUM (TC_NUM + 1) + +#define TX_2G_WMM_PORT_NUM (TC_NUM) + +#define BMC_TC_INDEX TC1_INDEX + +/* per-Network Tc Resource index */ +typedef enum _ENUM_NETWORK_TC_RESOURCE_INDEX_T { + /* QoS Data frame, WMM AC index */ + NET_TC_WMM_AC_BE_INDEX = 0, + NET_TC_WMM_AC_BK_INDEX, + NET_TC_WMM_AC_VI_INDEX, + NET_TC_WMM_AC_VO_INDEX, + /* Mgmt frame */ + NET_TC_MGMT_INDEX, + /* nonQoS / non StaRec frame (BMC/non-associated frame) */ + NET_TC_BMC_INDEX, + + NET_TC_NUM +} ENUM_NETWORK_TC_RESOURCE_INDEX_T; + +typedef enum _ENUM_TX_STATISTIC_COUNTER_T { + TX_MPDU_TOTAL_COUNT = 0, + TX_INACTIVE_BSS_DROP, + TX_INACTIVE_STA_DROP, + TX_FORWARD_OVERFLOW_DROP, + TX_AP_BORADCAST_DROP, + TX_INVALID_MSDUINFO_COUNT, + TX_DROP_PID_COUNT, + TX_STATISTIC_COUNTER_NUM +} ENUM_TX_STATISTIC_COUNTER_T; + +typedef enum _ENUM_FIX_BW_T { + FIX_BW_NO_FIXED = 0, + FIX_BW_20 = 4, + FIX_BW_40, + FIX_BW_80, + FIX_BW_160, + FIX_BW_NUM +} ENUM_FIX_BW_T; + +typedef enum _ENUM_MSDU_OPTION_T { + MSDU_OPT_NO_ACK = BIT(0), + MSDU_OPT_NO_AGGREGATE = BIT(1), + MSDU_OPT_TIMING_MEASURE = BIT(2), + MSDU_OPT_RCPI_NOISE_STATUS = BIT(3), + + /* Option by Frame Format */ + /* Non-80211 */ + MSDU_OPT_MORE_DATA = BIT(4), + MSDU_OPT_REMOVE_VLAN = BIT(5), /* Remove VLAN tag if exists */ + + /* 80211-enhanced */ + MSDU_OPT_AMSDU = BIT(6), + + /* 80211-enhanced & Non-80211 */ + MSDU_OPT_EOSP = BIT(7), + + /* Beamform */ + MSDU_OPT_NDP = BIT(8), + MSDU_OPT_NDPA = BIT(9), + MSDU_OPT_SOUNDING = BIT(10), + + /* Protection */ + MSDU_OPT_FORCE_RTS = BIT(11), + + /* Security */ + MSDU_OPT_BIP = BIT(12), + MSDU_OPT_PROTECTED_FRAME = BIT(13), + + /* SW Field */ + MSDU_OPT_SW_DURATION = BIT(14), + MSDU_OPT_SW_PS_BIT = BIT(15), + MSDU_OPT_SW_HTC = BIT(16), + MSDU_OPT_SW_BAR_SN = BIT(17), + + /* Manual Mode */ + MSDU_OPT_MANUAL_FIRST_BIT = BIT(18), + + MSDU_OPT_MANUAL_LIFE_TIME = MSDU_OPT_MANUAL_FIRST_BIT, + MSDU_OPT_MANUAL_RETRY_LIMIT = BIT(19), + MSDU_OPT_MANUAL_POWER_OFFSET = BIT(20), + MSDU_OPT_MANUAL_TX_QUE = BIT(21), + MSDU_OPT_MANUAL_SN = BIT(22), + + MSDU_OPT_MANUAL_LAST_BIT = MSDU_OPT_MANUAL_SN +} ENUM_MSDU_OPTION_T; + +typedef enum _ENUM_MSDU_CONTROL_FLAG_T { + MSDU_CONTROL_FLAG_FORCE_TX = BIT(0) +} ENUM_MSDU_CONTROL_FLAG_T; + +typedef enum _ENUM_MSDU_RATE_MODE_T { + MSDU_RATE_MODE_AUTO = 0, + MSDU_RATE_MODE_MANUAL_DESC, + /* The following rate mode is not implemented yet */ + /* DON'T use!!! */ + MSDU_RATE_MODE_MANUAL_CR, + MSDU_RATE_MODE_LOWEST_RATE +} ENUM_MSDU_RATE_MODE_T; + +typedef enum _ENUM_DATA_RATE_MODE_T { + DATA_RATE_MODE_AUTO = 0, + DATA_RATE_MODE_MANUAL, + DATA_RATE_MODE_BSS_LOWEST +} ENUM_DATA_RATE_MODE_T; + +typedef struct _TX_TCQ_STATUS_T { + /* HIF reported page count delta */ + u32 au4TxDonePageCount[TC_NUM]; /* other TC */ + u32 au4PreUsedPageCount[TC_NUM]; + u32 u4AvaliablePageCount; /* FFA */ + u8 ucNextTcIdx; /* For round-robin distribute free page count */ + + /* distributed page count */ + u32 au4FreePageCount[TC_NUM]; + u32 au4MaxNumOfPage[TC_NUM]; + + /* buffer count */ + u32 au4FreeBufferCount[TC_NUM]; + u32 au4MaxNumOfBuffer[TC_NUM]; + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + u8 ucNextHifWmmIdx; +#endif +} TX_TCQ_STATUS_T, *P_TX_TCQ_STATUS_T; + +typedef struct _TX_TCQ_ADJUST_T { + s32 ai4Variation[TC_NUM]; +} TX_TCQ_ADJUST_T, *P_TX_TCQ_ADJUST_T; + +typedef struct _TX_CTRL_T { + u32 u4TxCachedSize; + u8 *pucTxCached; + + u32 u4PageSize; + + u32 u4TotalPageNum; + + u32 u4TotalTxRsvPageNum; + + /* Elements below is classified according to TC (Traffic Class) value. + */ + + TX_TCQ_STATUS_T rTc; + + u8 *pucTxCoalescingBufPtr; + + u32 u4WrIdx; + + QUE_T rFreeMsduInfoList; + + /* Management Frame Tracking */ + /* number of management frames to be sent */ + s32 i4TxMgmtPendingNum; + + /* to tracking management frames need TX done callback */ + QUE_T rTxMgmtTxingQueue; + +#if CFG_HIF_STATISTICS + u32 u4TotalTxAccessNum; + u32 u4TotalTxPacketNum; +#endif + u32 au4Statistics[TX_STATISTIC_COUNTER_NUM]; + + /* Number to track forwarding frames */ + s32 i4PendingFwdFrameCount; + + /* enable/disable TX resource control */ + u8 fgIsTxResourceCtrl; +} TX_CTRL_T, *P_TX_CTRL_T; + +typedef enum _ENUM_TX_PACKET_TYPE_T { + TX_PACKET_TYPE_DATA = 0, + TX_PACKET_TYPE_MGMT, + /* TX_PACKET_TYPE_1X, */ + X_PACKET_TYPE_NUM +} ENUM_TX_PACKET_TYPE_T, +*P_ENUM_TX_PACKET_TYPE_T; + +typedef enum _ENUM_TX_PACKET_SRC_T { + TX_PACKET_OS, + TX_PACKET_OS_OID, + TX_PACKET_FORWARDING, + TX_PACKET_MGMT, + TX_PACKET_NUM +} ENUM_TX_PACKET_SRC_T; + +/* TX Call Back Function */ +typedef WLAN_STATUS (*PFN_TX_DONE_HANDLER)(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T + rTxDoneStatus); + +#if CFG_ENABLE_PKT_LIFETIME_PROFILE +typedef struct _PKT_PROFILE_T { + u8 fgIsValid; +#if CFG_PRINT_PKT_LIFETIME_PROFILE + u8 fgIsPrinted; + u16 u2IpSn; + u16 u2RtpSn; + u8 ucTcxFreeCount; +#endif + u32 rHardXmitArrivalTimestamp; + u32 rEnqueueTimestamp; + u32 rDequeueTimestamp; + u32 rHifTxDoneTimestamp; +} PKT_PROFILE_T, *P_PKT_PROFILE_T; +#endif +/* TX transactions could be divided into 4 kinds: + * + * 1) 802.1X / Bluetooth-over-Wi-Fi Security Frames + * [CMD_INFO_T] - [prPacket] - in skb or NDIS_PACKET form + * + * 2) MMPDU + * [CMD_INFO_T] - [prPacket] - [MSDU_INFO_T] - [prPacket] - direct buffer for + * frame body + * + * 3) Command Packets + * [CMD_INFO_T] - [pucInfoBuffer] - direct buffer for content of command + * packet + * + * 4) Normal data frame + * [MSDU_INFO_T] - [prPacket] - in skb or NDIS_PACKET form + */ + +/* PS_FORWARDING_TYPE_NON_PS means that the receiving STA is in Active Mode + * from the perspective of host driver (maybe not synchronized with FW --> SN + * is needed) + */ + +struct _MSDU_INFO_T { + QUE_ENTRY_T rQueEntry; + P_NATIVE_PACKET prPacket; /* Pointer to packet buffer */ + + ENUM_TX_PACKET_SRC_T eSrc; /* specify OS/FORWARD packet */ + u8 ucUserPriority; /* QoS parameter, convert to TID */ + + /* For composing TX descriptor header */ + u8 ucTC; /* Traffic Class: 0~4 (HIF TX0), 5 (HIF TX1) */ + u8 ucPacketType; /* 0: Data, 1: Management Frame */ + u8 ucStaRecIndex; /* STA_REC index */ + u8 ucBssIndex; /* BSS_INFO_T index */ + u8 ucWlanIndex; /* Wlan entry index */ + u8 ucPacketFormat; /* TXD.DW1[25:24] Packet Format */ + + u8 fgIs802_1x; /* true: 802.1x frame */ + u8 fgIs802_1x_NonProtected; /* true: 802.1x frame - Non-Protected */ + u8 fgIs802_11; /* true: 802.11 header is present */ + u8 fgIs802_3; /* true: 802.3 frame */ + u8 fgIsVlanExists; /* true: VLAN tag is exists */ + + /* u8 fgIsBIP; */ /* Management Frame + * Protection + */ + /* u8 fgIsBasicRate; */ /* Force Basic Rate + * Transmission + */ + /* u8 fgIsMoreData; */ /* More data */ + /* u8 fgIsEOSP; */ /* End of service + * period + */ + + /* Special Option */ + u32 u4Option; /* Special option in bitmask, no ACK, etc... */ + s8 cPowerOffset; /* Per-packet power offset, in 2's complement */ + u16 u2SwSN; /* SW assigned sequence number */ + u8 ucRetryLimit; /* The retry limit */ + u32 u4RemainingLifetime; /* Remaining lifetime, unit:ms */ + + /* Control flag */ + u8 ucControlFlag; /* Control flag in bitmask */ + + /* Fixed Rate Option */ + u8 ucRateMode; /* Rate mode: AUTO, MANUAL_DESC, MANUAL_CR */ + u32 u4FixedRateOption; /* The rate option, rate code, GI, etc... */ + + u8 fgIsTXDTemplateValid; /* There is a valid Tx descriptor for this + * packet */ + + /* flattened from PACKET_INFO_T */ + u8 ucMacHeaderLength; /* MAC header legth */ + u8 ucLlcLength; /* w/o EtherType */ + u16 u2FrameLength; /* Total frame length */ + u8 aucEthDestAddr[MAC_ADDR_LEN]; /* Ethernet Destination Address */ + u32 u4PageCount; /* Required page count for this MSDU */ + + /* for TX done tracking */ + u8 ucTxSeqNum; /* MGMT frame serial number */ + u8 ucPID; /* PID */ + u8 ucWmmQueSet; /* WMM Set */ + PFN_TX_DONE_HANDLER pfTxDoneHandler; /* Tx done handler */ + u32 u4TxDoneTag; /* Tag for data frame Tx done log */ + +#if CFG_ENABLE_PKT_LIFETIME_PROFILE + PKT_PROFILE_T rPktProfile; +#endif + + /* To be removed */ + u8 ucFormatID; /* 0: MAUI, Linux, Windows NDIS 5.1 */ + u8 ucPsForwardingType; /* See ENUM_PS_FORWARDING_TYPE_T */ + + /* Compose TxDesc in main_thread and place here */ + u8 aucTxDescBuffer[NIC_TX_DESC_AND_PADDING_LENGTH]; + + /* sanity drop flag */ + u8 fgDrop; +}; + +#define HIT_PKT_FLAGS_CT_WITH_TXD BIT(0) +#define HIF_PKT_FLAGS_COPY_HOST_TXD_ALL BIT(1) + +#define MAX_BUF_NUM_PER_PKT 6 + +typedef struct _HW_MAC_TX_DESC_APPEND_T { + u16 u2PktFlags; + u16 u2MsduToken; + u8 ucBssIndex; + u8 aucReserved[2]; + u8 ucBufNum; + + u32 au4BufPtr[MAX_BUF_NUM_PER_PKT]; + u16 au2BufLen[MAX_BUF_NUM_PER_PKT]; + u8 aucPktContent[0]; +} HW_MAC_TX_DESC_APPEND_T, *P_HW_MAC_TX_DESC_APPEND_T; + +/*!A data structure which is identical with HW MAC TX DMA Descriptor */ +typedef struct _HW_MAC_TX_DESC_T { + /* DW 0 */ + u16 u2TxByteCount; + u8 ucEtherOffset; /* Ether-Type Offset, IP checksum offload */ + u8 ucPortIdx_QueueIdx; /* UDP/TCP checksum offload, USB + * NextVLD/TxBURST, Queue index, Port index */ + /* DW 1 */ + u8 ucWlanIdx; + u8 ucHeaderFormat; /* Header format, TX descriptor format */ + u8 ucHeaderPadding; /* Header padding, no ACK, TID, Protect frame */ + u8 ucOwnMAC; + + /* Long Format, the following structure is for long format ONLY */ + /* DW 2 */ + u8 ucType_SubType; /* Type, Sub-type, NDP, NDPA */ + u8 ucFrag; /* Sounding, force RTS/CTS, BMC, BIP, Duration, HTC exist, + * Fragment */ + u8 ucRemainingMaxTxTime; + u8 ucPowerOffset; /* Power offset, Disable BA, Timing measurement, Fixed + * rate */ + /* DW 3 */ + u16 u2TxCountLimit; /* TX count limit */ + u16 u2SN; /* SN, HW own, PN valid, SN valid */ + /* DW 4 */ + u32 u4PN1; + /* DW 5 */ + u8 ucPID; + u8 ucTxStatus; /* TXS format, TXS to mcu, TXS to host, DA source, BAR + * SSN, Power management */ + u16 u2PN2; + /* DW 6 */ + u16 u2AntID; /* Fixed rate, Antenna ID */ + u16 u2FixedRate; /* Explicit/implicit beamforming, Fixed rate table, + * LDPC, GI */ + /* DW 7 */ + u16 u2SwTxTime; /* Sw Tx time[9:0], SPE_IDX[15:11] */ + u16 u2PseFid; /* indicate frame ID in PSE for this TXD */ +} HW_MAC_TX_DESC_T, *P_HW_MAC_TX_DESC_T, **PP_HW_MAC_TX_DESC_T; + +typedef struct _TX_RESOURCE_CONTROL_T { + /* HW TX queue definition */ + u8 ucDestPortIndex; + u8 ucDestQueueIndex; + /* HIF Interrupt status index */ + u8 ucHifTxQIndex; +} TX_RESOURCE_CONTROL_T, *PTX_RESOURCE_CONTROL_T; + +typedef struct _TX_TC_TRAFFIC_SETTING_T { + u32 u4TxDescLength; + u32 u4RemainingTxTime; + u8 ucTxCountLimit; +} TX_TC_TRAFFIC_SETTING_T, P_TX_TC_TRAFFIC_SETTING_T; + +typedef void (*PFN_TX_DATA_DONE_CB)(IN P_GLUE_INFO_T prGlueInfo, + IN P_QUE_T prQue); + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +extern PFN_TX_DATA_DONE_CB g_pfTxDataDoneCb; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define TX_INC_CNT(prTxCtrl, eCounter) \ + { \ + ((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter]++; \ + } + +#define TX_ADD_CNT(prTxCtrl, eCounter, u8Amount) \ + { \ + ((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter] += \ + (u32)u8Amount; \ + } + +#define TX_GET_CNT(prTxCtrl, eCounter) \ + (((P_TX_CTRL_T)prTxCtrl)->au4Statistics[eCounter]) + +#define TX_RESET_ALL_CNTS(prTxCtrl) \ + { \ + kalMemZero(&prTxCtrl->au4Statistics[0], \ + sizeof(prTxCtrl->au4Statistics)); \ + } +#if CFG_ENABLE_PKT_LIFETIME_PROFILE + +#if CFG_PRINT_PKT_LIFETIME_PROFILE +#define PRINT_PKT_PROFILE(_pkt_profile, _note) \ + do { \ + if (!(_pkt_profile)->fgIsPrinted) { \ + DBGLOG(TX, \ + TRACE, \ + "X[%lu] E[%lu] D[%lu] HD[%lu] B[%d] RTP[%d] %s\n", \ + (u32)((_pkt_profile)-> \ + rHardXmitArrivalTimestamp), \ + (u32)((_pkt_profile)->rEnqueueTimestamp), \ + (u32)((_pkt_profile)->rDequeueTimestamp), \ + (u32)((_pkt_profile)->rHifTxDoneTimestamp), \ + (u8)((_pkt_profile)->ucTcxFreeCount), \ + (u16)((_pkt_profile)->u2RtpSn), \ + (_note)); \ + (_pkt_profile)->fgIsPrinted = true; \ + } \ + } while (0) +#else +#define PRINT_PKT_PROFILE(_pkt_profile, _note) +#endif + +#define CHK_PROFILES_DELTA(_pkt1, _pkt2, _delta) \ + (CHECK_FOR_TIMEOUT((_pkt1)->rHardXmitArrivalTimestamp, \ + (_pkt2)->rHardXmitArrivalTimestamp, (_delta)) || \ + CHECK_FOR_TIMEOUT((_pkt1)->rEnqueueTimestamp, \ + (_pkt2)->rEnqueueTimestamp, (_delta)) || \ + CHECK_FOR_TIMEOUT((_pkt1)->rDequeueTimestamp, \ + (_pkt2)->rDequeueTimestamp, (_delta)) || \ + CHECK_FOR_TIMEOUT((_pkt1)->rHifTxDoneTimestamp, \ + (_pkt2)->rHifTxDoneTimestamp, (_delta))) + +#define CHK_PROFILE_DELTA(_pkt, _delta) \ + (CHECK_FOR_TIMEOUT((_pkt)->rEnqueueTimestamp, \ + (_pkt)->rHardXmitArrivalTimestamp, (_delta)) || \ + CHECK_FOR_TIMEOUT((_pkt)->rDequeueTimestamp, \ + (_pkt)->rEnqueueTimestamp, (_delta)) || \ + CHECK_FOR_TIMEOUT((_pkt)->rHifTxDoneTimestamp, \ + (_pkt)->rDequeueTimestamp, (_delta))) +#endif + +/*------------------------------------------------------------------------------ + * MACRO for MSDU_INFO + *------------------------------------------------------------------------------ + */ +#define TX_SET_MMPDU nicTxSetMngPacket +#define TX_SET_DATA_PACKET nicTxSetDataPacket + +/*------------------------------------------------------------------------------ + * MACRO for HW_MAC_TX_DESC_T + *------------------------------------------------------------------------------ + */ +#define TX_DESC_GET_FIELD(_rHwMacTxDescField, _mask, _offset) \ + (((_rHwMacTxDescField) & (_mask)) >> (_offset)) +#define TX_DESC_SET_FIELD(_rHwMacTxDescField, _value, _mask, _offset) \ + { \ + (_rHwMacTxDescField) &= ~(_mask); \ + (_rHwMacTxDescField) |= (((_value) << (_offset)) & (_mask)); \ + } + +#define HAL_MAC_TX_DESC_SET_DW(_prHwMacTxDesc, _ucOffsetInDw, _ucLengthInDw, \ + _pucValueAddr) \ + kalMemCopy((u32 *)(_prHwMacTxDesc) + (_ucOffsetInDw), \ + (u8 *)(_pucValueAddr), DWORD_TO_BYTE(_ucLengthInDw)) +#define HAL_MAC_TX_DESC_GET_DW(_prHwMacTxDesc, _ucOffsetInDw, _ucLengthInDw, \ + _pucValueAddr) \ + kalMemCopy((u8 *)(_pucValueAddr), \ + (u32 *)(_prHwMacTxDesc) + (_ucOffsetInDw), \ + DWORD_TO_BYTE(_ucLengthInDw)) + +/* DW 0 */ +#define HAL_MAC_TX_DESC_GET_TX_BYTE_COUNT(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2TxByteCount) +#define HAL_MAC_TX_DESC_SET_TX_BYTE_COUNT(_prHwMacTxDesc, _u2TxByteCount) \ + (((_prHwMacTxDesc)->u2TxByteCount) = ((u16)_u2TxByteCount)) + +#define HAL_MAC_TX_DESC_GET_ETHER_TYPE_OFFSET(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucEtherOffset, \ + TX_DESC_ETHER_TYPE_OFFSET_MASK, \ + TX_DESC_ETHER_TYPE_OFFSET_OFFSET) +#define HAL_MAC_TX_DESC_SET_ETHER_TYPE_OFFSET(_prHwMacTxDesc, \ + _ucEtherTypeOffset) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucEtherOffset), \ + ((u8)_ucEtherTypeOffset), \ + TX_DESC_ETHER_TYPE_OFFSET_MASK, \ + TX_DESC_ETHER_TYPE_OFFSET_OFFSET) + +#define HAL_MAC_TX_DESC_IS_IP_CHKSUM_ENABLED(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucEtherOffset & TX_DESC_IP_CHKSUM_OFFLOAD) ? \ + false : \ + true) +#define HAL_MAC_TX_DESC_SET_IP_CHKSUM(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucEtherOffset |= TX_DESC_IP_CHKSUM_OFFLOAD) +#define HAL_MAC_TX_DESC_UNSET_IP_CHKSUM(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucEtherOffset &= ~TX_DESC_IP_CHKSUM_OFFLOAD) + +#define HAL_MAC_TX_DESC_IS_TCP_UDP_CHKSUM_ENABLED(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucPortIdx_QueueIdx & \ + TX_DESC_TCP_UDP_CHKSUM_OFFLOAD) ? \ + false : \ + true) +#define HAL_MAC_TX_DESC_SET_TCP_UDP_CHKSUM(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPortIdx_QueueIdx |= TX_DESC_TCP_UDP_CHKSUM_OFFLOAD) +#define HAL_MAC_TX_DESC_UNSET_TCP_UDP_CHKSUM(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPortIdx_QueueIdx &= \ + ~TX_DESC_TCP_UDP_CHKSUM_OFFLOAD) + +#define HAL_MAC_TX_DESC_IS_USB_NEXT_VLD_ENABLED(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucPortIdx_QueueIdx & TX_DESC_USB_NEXT_VLD) ? \ + true : \ + false) +#define HAL_MAC_TX_DESC_SET_USB_NEXT_VLD(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPortIdx_QueueIdx |= TX_DESC_USB_NEXT_VLD) +#define HAL_MAC_TX_DESC_UNSET_USB_NEXT_VLD(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPortIdx_QueueIdx &= ~TX_DESC_USB_NEXT_VLD) + +#define HAL_MAC_TX_DESC_GET_QUEUE_INDEX(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucPortIdx_QueueIdx, \ + TX_DESC_QUEUE_INDEX_MASK, \ + TX_DESC_QUEUE_INDEX_OFFSET) +#define HAL_MAC_TX_DESC_SET_QUEUE_INDEX(_prHwMacTxDesc, _ucQueueIndex) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucPortIdx_QueueIdx), \ + ((u8)_ucQueueIndex), TX_DESC_QUEUE_INDEX_MASK, \ + TX_DESC_QUEUE_INDEX_OFFSET) + +#define HAL_MAC_TX_DESC_GET_PORT_INDEX(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucPortIdx_QueueIdx, \ + TX_DESC_PORT_INDEX, TX_DESC_PORT_INDEX_OFFSET) +#define HAL_MAC_TX_DESC_SET_PORT_INDEX(_prHwMacTxDesc, _ucPortIndex) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucPortIdx_QueueIdx), \ + ((u8)_ucPortIndex), TX_DESC_PORT_INDEX, \ + TX_DESC_PORT_INDEX_OFFSET) + +/* DW 1 */ +#define HAL_MAC_TX_DESC_GET_WLAN_INDEX(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucWlanIdx) +#define HAL_MAC_TX_DESC_SET_WLAN_INDEX(_prHwMacTxDesc, _ucWlanIdx) \ + (((_prHwMacTxDesc)->ucWlanIdx) = (_ucWlanIdx)) + +#define HAL_MAC_TX_DESC_IS_LONG_FORMAT(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucHeaderFormat & TX_DESC_FORMAT) ? true : false) +#define HAL_MAC_TX_DESC_SET_LONG_FORMAT(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat |= TX_DESC_FORMAT) +#define HAL_MAC_TX_DESC_SET_SHORT_FORMAT(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat &= ~TX_DESC_FORMAT) + +#define HAL_MAC_TX_DESC_GET_HEADER_FORMAT(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucHeaderFormat, \ + TX_DESC_HEADER_FORMAT_MASK, \ + TX_DESC_HEADER_FORMAT_OFFSET) +#define HAL_MAC_TX_DESC_SET_HEADER_FORMAT(_prHwMacTxDesc, _ucHdrFormat) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucHeaderFormat), \ + ((u8)_ucHdrFormat), TX_DESC_HEADER_FORMAT_MASK, \ + TX_DESC_HEADER_FORMAT_OFFSET) + +/* HF = 0x00, 802.11 normal mode */ +#define HAL_MAC_TX_DESC_IS_MORE_DATA(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucHeaderFormat & TX_DESC_NON_802_11_MORE_DATA) ? \ + true : \ + false) +#define HAL_MAC_TX_DESC_SET_MORE_DATA(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat |= TX_DESC_NON_802_11_MORE_DATA) +#define HAL_MAC_TX_DESC_UNSET_MORE_DATA(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat &= ~TX_DESC_NON_802_11_MORE_DATA) + +#define HAL_MAC_TX_DESC_IS_REMOVE_VLAN(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucHeaderFormat & TX_DESC_NON_802_11_REMOVE_VLAN) ? \ + true : \ + false) +#define HAL_MAC_TX_DESC_SET_REMOVE_VLAN(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat |= TX_DESC_NON_802_11_REMOVE_VLAN) +#define HAL_MAC_TX_DESC_UNSET_REMOVE_VLAN(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat &= ~TX_DESC_NON_802_11_REMOVE_VLAN) + +#define HAL_MAC_TX_DESC_IS_VLAN(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucHeaderFormat & TX_DESC_NON_802_11_VLAN_FIELD) ? \ + true : \ + false) +#define HAL_MAC_TX_DESC_SET_VLAN(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat |= TX_DESC_NON_802_11_VLAN_FIELD) +#define HAL_MAC_TX_DESC_UNSET_VLAN(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat &= ~TX_DESC_NON_802_11_VLAN_FIELD) + +#define HAL_MAC_TX_DESC_IS_ETHERNET_II(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucHeaderFormat & TX_DESC_NON_802_11_ETHERNET_II) ? \ + true : \ + false) +#define HAL_MAC_TX_DESC_SET_ETHERNET_II(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat |= TX_DESC_NON_802_11_ETHERNET_II) +#define HAL_MAC_TX_DESC_UNSET_ETHERNET_II(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat &= ~TX_DESC_NON_802_11_ETHERNET_II) + +/* HF = 0x00/0x11, 802.11 normal/enhancement mode */ +#define HAL_MAC_TX_DESC_IS_EOSP(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucHeaderFormat & TX_DESC_NON_802_11_EOSP) ? true : \ + false) +#define HAL_MAC_TX_DESC_SET_EOSP(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat |= TX_DESC_NON_802_11_EOSP) +#define HAL_MAC_TX_DESC_UNSET_EOSP(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat &= ~TX_DESC_NON_802_11_EOSP) + +/* HF = 0x11, 802.11 enhancement mode */ +#define HAL_MAC_TX_DESC_IS_AMSDU(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucHeaderFormat & TX_DESC_ENH_802_11_AMSDU) ? \ + true : \ + false) +#define HAL_MAC_TX_DESC_SET_AMSDU(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat |= TX_DESC_ENH_802_11_AMSDU) +#define HAL_MAC_TX_DESC_UNSET_AMSDU(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderFormat &= ~TX_DESC_ENH_802_11_AMSDU) + +/* HF = 0x10, non-802.11 */ +#define HAL_MAC_TX_DESC_GET_802_11_HEADER_LENGTH(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucHeaderFormat, \ + TX_DESC_NOR_802_11_HEADER_LENGTH_MASK, \ + TX_DESC_NOR_802_11_HEADER_LENGTH_OFFSET) +#define HAL_MAC_TX_DESC_SET_802_11_HEADER_LENGTH(_prHwMacTxDesc, _ucHdrLength) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucHeaderFormat), \ + ((u8)_ucHdrLength), \ + TX_DESC_NOR_802_11_HEADER_LENGTH_MASK, \ + TX_DESC_NOR_802_11_HEADER_LENGTH_OFFSET) + +#define HAL_MAC_TX_DESC_GET_TXD_LENGTH(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucHeaderPadding, \ + TX_DESC_TXD_LENGTH_MASK, TX_DESC_TXD_LENGTH_OFFSET) +#define HAL_MAC_TX_DESC_SET_TXD_LENGTH(_prHwMacTxDesc, _ucHdrPadding) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucHeaderPadding), \ + ((u8)_ucHdrPadding), TX_DESC_TXD_LENGTH_MASK, \ + TX_DESC_TXD_LENGTH_OFFSET) + +#define HAL_MAC_TX_DESC_GET_TXD_EXTEND_LENGTH(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucHeaderPadding, \ + TX_DESC_TXD_EXTEND_LENGTH_MASK, \ + TX_DESC_TXD_EXTEND_LENGTH_OFFSET) +#define HAL_MAC_TX_DESC_SET_TXD_EXTEND_LENGTH(_prHwMacTxDesc, _ucHdrPadding) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucHeaderPadding), \ + ((u8)_ucHdrPadding), TX_DESC_TXD_EXTEND_LENGTH_MASK, \ + TX_DESC_TXD_EXTEND_LENGTH_OFFSET) + +#define HAL_MAC_TX_DESC_GET_HEADER_PADDING(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucHeaderPadding, \ + TX_DESC_HEADER_PADDING_LENGTH_MASK, \ + TX_DESC_HEADER_PADDING_LENGTH_OFFSET) +#define HAL_MAC_TX_DESC_SET_HEADER_PADDING(_prHwMacTxDesc, _ucHdrPadding) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucHeaderPadding), \ + ((u8)_ucHdrPadding), \ + TX_DESC_HEADER_PADDING_LENGTH_MASK, \ + TX_DESC_HEADER_PADDING_LENGTH_OFFSET) + +#define HAL_MAC_TX_DESC_GET_UTXB_AMSDU(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucHeaderPadding, \ + TX_DESC_TXD_UTXB_AMSDU_MASK, \ + TX_DESC_TXD_UTXB_AMSDU_OFFSET) +#define HAL_MAC_TX_DESC_SET_UTXB_AMSDU(_prHwMacTxDesc, _ucHdrPadding) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucHeaderPadding), \ + ((u8)_ucHdrPadding), TX_DESC_TXD_UTXB_AMSDU_MASK, \ + TX_DESC_TXD_UTXB_AMSDU_OFFSET) + +#define HAL_MAC_TX_DESC_IS_HEADER_PADDING_IN_THE_HEAD(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucHeaderPadding & TX_DESC_HEADER_PADDING_MODE) ? \ + true : \ + false) +#define HAL_MAC_TX_DESC_SET_HEADER_PADDING_IN_THE_HEAD(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderPadding |= TX_DESC_HEADER_PADDING_MODE) +#define HAL_MAC_TX_DESC_SET_HEADER_PADDING_IN_THE_TAIL(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucHeaderPadding &= ~TX_DESC_HEADER_PADDING_MODE) + +#define HAL_MAC_TX_DESC_GET_TID(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucHeaderPadding, TX_DESC_TID_MASK, \ + TX_DESC_TID_OFFSET) +#define HAL_MAC_TX_DESC_SET_TID(_prHwMacTxDesc, _ucTID) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucHeaderPadding), ((u8)_ucTID), \ + TX_DESC_TID_MASK, TX_DESC_TID_OFFSET) + +#define HAL_MAC_TX_DESC_GET_PKT_FORMAT(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucOwnMAC, \ + TX_DESC_PACKET_FORMAT_MASK, \ + TX_DESC_PACKET_FORMAT_OFFSET) +#define HAL_MAC_TX_DESC_SET_PKT_FORMAT(_prHwMacTxDesc, _ucPktFormat) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucOwnMAC), ((u8)_ucPktFormat), \ + TX_DESC_PACKET_FORMAT_MASK, \ + TX_DESC_PACKET_FORMAT_OFFSET) + +#define HAL_MAC_TX_DESC_GET_OWN_MAC_INDEX(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucOwnMAC, TX_DESC_OWN_MAC_MASK, \ + TX_DESC_OWN_MAC_OFFSET) +#define HAL_MAC_TX_DESC_SET_OWN_MAC_INDEX(_prHwMacTxDesc, _ucOwnMacIdx) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucOwnMAC), ((u8)_ucOwnMacIdx), \ + TX_DESC_OWN_MAC_MASK, TX_DESC_OWN_MAC_OFFSET) + +/* DW 2 */ +#define HAL_MAC_TX_DESC_GET_SUB_TYPE(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucType_SubType, \ + TX_DESC_SUB_TYPE_MASK, TX_DESC_SUB_TYPE_OFFSET) +#define HAL_MAC_TX_DESC_SET_SUB_TYPE(_prHwMacTxDesc, _ucSubType) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucType_SubType), \ + ((u8)_ucSubType), TX_DESC_SUB_TYPE_MASK, \ + TX_DESC_SUB_TYPE_OFFSET) + +#define HAL_MAC_TX_DESC_GET_TYPE(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucType_SubType, TX_DESC_TYPE_MASK, \ + TX_DESC_TYPE_OFFSET) +#define HAL_MAC_TX_DESC_SET_TYPE(_prHwMacTxDesc, _ucType) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucType_SubType), ((u8)_ucType), \ + TX_DESC_TYPE_MASK, TX_DESC_TYPE_OFFSET) + +#define HAL_MAC_TX_DESC_IS_NDP(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucType_SubType & TX_DESC_NDP) ? true : false) +#define HAL_MAC_TX_DESC_SET_NDP(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucType_SubType |= TX_DESC_NDP) +#define HAL_MAC_TX_DESC_UNSET_NDP(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucType_SubType &= ~TX_DESC_NDP) + +#define HAL_MAC_TX_DESC_IS_NDPA(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucType_SubType & TX_DESC_NDPA) ? true : false) +#define HAL_MAC_TX_DESC_SET_NDPA(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucType_SubType |= TX_DESC_NDPA) +#define HAL_MAC_TX_DESC_UNSET_NDPA(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucType_SubType &= ~TX_DESC_NDPA) + +#define HAL_MAC_TX_DESC_IS_SOUNDING_FRAME(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucFrag & TX_DESC_SOUNDING) ? true : false) +#define HAL_MAC_TX_DESC_SET_SOUNDING_FRAME(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucFrag |= TX_DESC_SOUNDING) +#define HAL_MAC_TX_DESC_UNSET_SOUNDING_FRAME(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucFrag &= ~TX_DESC_SOUNDING) + +#define HAL_MAC_TX_DESC_IS_FORCE_RTS_CTS_EN(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucFrag & TX_DESC_FORCE_RTS_CTS) ? true : false) +#define HAL_MAC_TX_DESC_SET_FORCE_RTS_CTS(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucFrag |= TX_DESC_FORCE_RTS_CTS) +#define HAL_MAC_TX_DESC_UNSET_FORCE_RTS_CTS(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucFrag &= ~TX_DESC_FORCE_RTS_CTS) + +#define HAL_MAC_TX_DESC_IS_BMC(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucFrag & TX_DESC_BROADCAST_MULTICAST) ? true : \ + false) +#define HAL_MAC_TX_DESC_SET_BMC(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucFrag |= TX_DESC_BROADCAST_MULTICAST) +#define HAL_MAC_TX_DESC_UNSET_BMC(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucFrag &= ~TX_DESC_BROADCAST_MULTICAST) + +#define HAL_MAC_TX_DESC_IS_BIP(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucFrag & TX_DESC_BIP_PROTECTED) ? true : false) +#define HAL_MAC_TX_DESC_SET_BIP(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucFrag |= TX_DESC_BIP_PROTECTED) +#define HAL_MAC_TX_DESC_UNSET_BIP(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucFrag &= ~TX_DESC_BIP_PROTECTED) + +#define HAL_MAC_TX_DESC_IS_DURATION_CONTROL_BY_SW(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucFrag & TX_DESC_DURATION_FIELD_CONTROL) ? true : \ + false) +#define HAL_MAC_TX_DESC_SET_DURATION_CONTROL_BY_SW(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucFrag |= TX_DESC_DURATION_FIELD_CONTROL) +#define HAL_MAC_TX_DESC_SET_DURATION_CONTROL_BY_HW(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucFrag &= ~TX_DESC_DURATION_FIELD_CONTROL) + +#define HAL_MAC_TX_DESC_IS_HTC_EXIST(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucFrag & TX_DESC_HTC_EXISTS) ? true : false) +#define HAL_MAC_TX_DESC_SET_HTC_EXIST(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucFrag |= TX_DESC_HTC_EXISTS) +#define HAL_MAC_TX_DESC_UNSET_HTC_EXIST(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucFrag &= ~TX_DESC_HTC_EXISTS) + +#define HAL_MAC_TX_DESC_IS_FRAG_PACKET(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucFrag & TX_DESC_FRAGMENT_MASK) ? true : false) +#define HAL_MAC_TX_DESC_GET_FRAG_PACKET_POS(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucFrag, TX_DESC_FRAGMENT_MASK, \ + TX_DESC_FRAGMENT_OFFSET) +#define HAL_MAC_TX_DESC_SET_FRAG_PACKET_POS(_prHwMacTxDesc, _ucFragPos) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucFrag), ((u8)_ucFragPos), \ + TX_DESC_FRAGMENT_MASK, TX_DESC_FRAGMENT_OFFSET) + +/* For driver */ +/* in unit of 32TU */ +#define HAL_MAC_TX_DESC_GET_REMAINING_LIFE_TIME(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucRemainingMaxTxTime) +#define HAL_MAC_TX_DESC_SET_REMAINING_LIFE_TIME(_prHwMacTxDesc, _ucLifeTime) \ + ((_prHwMacTxDesc)->ucRemainingMaxTxTime = (_ucLifeTime)) +/* in unit of ms (minimal value is about 40ms) */ +#define HAL_MAC_TX_DESC_GET_REMAINING_LIFE_TIME_IN_MS(_prHwMacTxDesc) \ + (TU_TO_MSEC(HAL_MAC_TX_DESC_GET_REMAINING_LIFE_TIME(_prHwMacTxDesc) \ + << TX_DESC_LIFE_TIME_UNIT_IN_POWER_OF_2)) +#define HAL_MAC_TX_DESC_SET_REMAINING_LIFE_TIME_IN_MS(_prHwMacTxDesc, \ + _u4LifeTimeMs) \ + do { \ + u32 u4LifeTimeInUnit = \ + ((MSEC_TO_USEC(_u4LifeTimeMs) / USEC_PER_TU) >> \ + TX_DESC_LIFE_TIME_UNIT_IN_POWER_OF_2); \ + if (u4LifeTimeInUnit >= BIT(8)) \ + u4LifeTimeInUnit = BITS(0, 7); \ + else if ((_u4LifeTimeMs != TX_DESC_TX_TIME_NO_LIMIT) && \ + (u4LifeTimeInUnit == TX_DESC_TX_TIME_NO_LIMIT)) \ + u4LifeTimeInUnit = 1; \ + HAL_MAC_TX_DESC_SET_REMAINING_LIFE_TIME(_prHwMacTxDesc, \ + (u8)u4LifeTimeInUnit); \ + } while (0) + +#define HAL_MAC_TX_DESC_GET_POWER_OFFSET(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucPowerOffset, \ + TX_DESC_POWER_OFFSET_MASK, 0) +#define HAL_MAC_TX_DESC_SET_POWER_OFFSET(_prHwMacTxDesc, _ucPowerOffset) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucPowerOffset), \ + ((u8)_ucPowerOffset), TX_DESC_POWER_OFFSET_MASK, 0) + +#define HAL_MAC_TX_DESC_IS_BA_DISABLE(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucPowerOffset & TX_DESC_BA_DISABLE) ? true : false) +#define HAL_MAC_TX_DESC_SET_BA_DISABLE(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPowerOffset |= TX_DESC_BA_DISABLE) +#define HAL_MAC_TX_DESC_SET_BA_ENABLE(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPowerOffset &= ~TX_DESC_BA_DISABLE) + +#define HAL_MAC_TX_DESC_IS_TIMING_MEASUREMENT(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucPowerOffset & TX_DESC_TIMING_MEASUREMENT) ? \ + true : \ + false) +#define HAL_MAC_TX_DESC_SET_TIMING_MEASUREMENT(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPowerOffset |= TX_DESC_TIMING_MEASUREMENT) +#define HAL_MAC_TX_DESC_UNSET_TIMING_MEASUREMENT(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPowerOffset &= ~TX_DESC_TIMING_MEASUREMENT) + +#define HAL_MAC_TX_DESC_IS_FIXED_RATE_ENABLE(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucPowerOffset & TX_DESC_FIXED_RATE) ? true : false) +#define HAL_MAC_TX_DESC_SET_FIXED_RATE_ENABLE(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPowerOffset |= TX_DESC_FIXED_RATE) +#define HAL_MAC_TX_DESC_SET_FIXED_RATE_DISABLE(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPowerOffset &= ~TX_DESC_FIXED_RATE) + +/* DW 3 */ +#define HAL_MAC_TX_DESC_IS_NO_ACK(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->u2TxCountLimit & TX_DESC_NO_ACK) ? true : false) +#define HAL_MAC_TX_DESC_SET_NO_ACK(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2TxCountLimit |= TX_DESC_NO_ACK) +#define HAL_MAC_TX_DESC_UNSET_NO_ACK(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2TxCountLimit &= ~TX_DESC_NO_ACK) + +#define HAL_MAC_TX_DESC_IS_PROTECTION(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->u2TxCountLimit & TX_DESC_PROTECTED_FRAME) ? true : \ + false) +#define HAL_MAC_TX_DESC_SET_PROTECTION(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2TxCountLimit |= TX_DESC_PROTECTED_FRAME) +#define HAL_MAC_TX_DESC_UNSET_PROTECTION(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2TxCountLimit &= ~TX_DESC_PROTECTED_FRAME) + +#define HAL_MAC_TX_DESC_IS_EXTEND_MORE_DATA(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->u2TxCountLimit & TX_DESC_EXTEND_MORE_DATA) ? \ + true : \ + false) +#define HAL_MAC_TX_DESC_SET_EXTEND_MORE_DATA(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2TxCountLimit |= TX_DESC_EXTEND_MORE_DATA) +#define HAL_MAC_TX_DESC_UNSET_EXTEND_MORE_DATA(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2TxCountLimit &= ~TX_DESC_EXTEND_MORE_DATA) + +#define HAL_MAC_TX_DESC_IS_EXTEND_EOSP(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->u2TxCountLimit & TX_DESC_EXTEND_EOSP) ? true : \ + false) +#define HAL_MAC_TX_DESC_SET_EXTEND_EOSP(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2TxCountLimit |= TX_DESC_EXTEND_EOSP) +#define HAL_MAC_TX_DESC_UNSET_EXTEND_EOSP(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2TxCountLimit &= ~TX_DESC_EXTEND_EOSP) + +#define HAL_MAC_TX_DESC_GET_SW_RESERVED(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->u2TxCountLimit, \ + TX_DESC_SW_RESERVED_MASK, \ + TX_DESC_SW_RESERVED_OFFSET) +#define HAL_MAC_TX_DESC_SET_SW_RESERVED(_prHwMacTxDesc, _ucSwReserved) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->u2TxCountLimit), \ + ((u8)_ucSwReserved), TX_DESC_SW_RESERVED_MASK, \ + TX_DESC_SW_RESERVED_OFFSET) +#define HAL_MAC_TX_DESC_GET_TX_COUNT(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->u2TxCountLimit, \ + TX_DESC_TX_COUNT_MASK, TX_DESC_TX_COUNT_OFFSET) +#define HAL_MAC_TX_DESC_SET_TX_COUNT(_prHwMacTxDesc, _ucTxCountLimit) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->u2TxCountLimit), \ + ((u8)_ucTxCountLimit), TX_DESC_TX_COUNT_MASK, \ + TX_DESC_TX_COUNT_OFFSET) +#define HAL_MAC_TX_DESC_GET_REMAINING_TX_COUNT(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->u2TxCountLimit, \ + TX_DESC_REMAINING_TX_COUNT_MASK, \ + TX_DESC_REMAINING_TX_COUNT_OFFSET) +#define HAL_MAC_TX_DESC_SET_REMAINING_TX_COUNT(_prHwMacTxDesc, \ + _ucTxCountLimit) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->u2TxCountLimit), \ + ((u8)_ucTxCountLimit), \ + TX_DESC_REMAINING_TX_COUNT_MASK, \ + TX_DESC_REMAINING_TX_COUNT_OFFSET) +#define HAL_MAC_TX_DESC_GET_SEQUENCE_NUMBER(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->u2SN, TX_DESC_SEQUENCE_NUMBER, 0) +#define HAL_MAC_TX_DESC_SET_SEQUENCE_NUMBER(_prHwMacTxDesc, _u2SN) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->u2SN), ((u16)_u2SN), \ + TX_DESC_SEQUENCE_NUMBER, 0) +#define HAL_MAC_TX_DESC_SET_HW_RESERVED(_prHwMacTxDesc, _ucHwReserved) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->u2SN), ((u8)_ucHwReserved), \ + TX_DESC_HW_RESERVED_MASK, \ + TX_DESC_HW_RESERVED_OFFSET) +#define HAL_MAC_TX_DESC_IS_TXD_SN_VALID(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->u2SN & TX_DESC_SN_IS_VALID) ? true : false) +#define HAL_MAC_TX_DESC_SET_TXD_SN_VALID(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2SN |= TX_DESC_SN_IS_VALID) +#define HAL_MAC_TX_DESC_SET_TXD_SN_INVALID(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2SN &= ~TX_DESC_SN_IS_VALID) + +#define HAL_MAC_TX_DESC_IS_TXD_PN_VALID(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->u2SN & TX_DESC_PN_IS_VALID) ? true : false) +#define HAL_MAC_TX_DESC_SET_TXD_PN_VALID(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2SN |= TX_DESC_PN_IS_VALID) +#define HAL_MAC_TX_DESC_SET_TXD_PN_INVALID(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2SN &= ~TX_DESC_PN_IS_VALID) + +#define HAL_MAC_TX_DESC_ASSIGN_SN_BY_SW(_prHwMacTxDesc, _u2SN) \ + { \ + HAL_MAC_TX_DESC_SET_SEQUENCE_NUMBER(_prHwMacTxDesc, _u2SN); \ + HAL_MAC_TX_DESC_SET_TXD_SN_VALID(_prHwMacTxDesc); \ + } +#define HAL_MAC_TX_DESC_ASSIGN_SN_BY_HW(_prHwMacTxDesc) \ + { \ + HAL_MAC_TX_DESC_SET_SEQUENCE_NUMBER(_prHwMacTxDesc, 0); \ + HAL_MAC_TX_DESC_SET_TXD_SN_INVALID(_prHwMacTxDesc); \ + } + +/* DW 4 */ +#define HAL_MAC_TX_DESC_GET_PN(_prHwMacTxDesc, _u4PN_0_31, _u2PN_32_47) \ + { \ + ((u32)_u4PN_0_31) = (_prHwMacTxDesc)->u4PN1; \ + ((u16)_u2PN_32_47) = (_prHwMacTxDesc)->u2PN2; \ + } +#define HAL_MAC_TX_DESC_SET_PN(_prHwMacTxDesc, _u4PN_0_31, _u2PN_32_47) \ + { \ + (_prHwMacTxDesc)->u4PN1 = ((u32)_u4PN_0_31); \ + (_prHwMacTxDesc)->u2PN2 = ((u16)_u2PN_32_47); \ + } + +#define HAL_MAC_TX_DESC_ASSIGN_PN_BY_SW(_prHwMacTxDesc, _u4PN_0_31, \ + _u2PN_32_47) \ + { \ + HAL_MAC_TX_DESC_SET_PN(_prHwMacTxDesc, _u4PN_0_31, \ + _u2PN_32_47); \ + HAL_MAC_TX_DESC_SET_TXD_PN_VALID(_prHwMacTxDesc); \ + } +#define HAL_MAC_TX_DESC_ASSIGN_PSN_BY_HW(_prHwMacTxDesc) \ + { \ + HAL_MAC_TX_DESC_SET_PN(_prHwMacTxDesc, 0, 0); \ + HAL_MAC_TX_DESC_SET_TXD_PN_INVALID(_prHwMacTxDesc); \ + } + +/* DW 5 */ +#define HAL_MAC_TX_DESC_GET_PID(_prHwMacTxDesc) ((_prHwMacTxDesc)->ucPID) +#define HAL_MAC_TX_DESC_SET_PID(_prHwMacTxDesc, _ucPID) \ + (((_prHwMacTxDesc)->ucPID) = (_ucPID)) + +#define HAL_MAC_TX_DESC_GET_TXS_FORMAT(_prHwMacTxDesc) \ + TX_DESC_GET_FIELD((_prHwMacTxDesc)->ucTxStatus, \ + TX_DESC_TX_STATUS_FORMAT, \ + TX_DESC_TX_STATUS_FORMAT_OFFSET) +#define HAL_MAC_TX_DESC_SET_TXS_FORMAT(_prHwMacTxDesc, _ucTXSFormat) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->ucTxStatus), ((u8)_ucTXSFormat), \ + TX_DESC_TX_STATUS_FORMAT, \ + TX_DESC_TX_STATUS_FORMAT_OFFSET) + +#define HAL_MAC_TX_DESC_IS_TXS_TO_MCU(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucTxStatus & TX_DESC_TX_STATUS_TO_MCU) ? true : \ + false) +#define HAL_MAC_TX_DESC_SET_TXS_TO_MCU(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucTxStatus |= TX_DESC_TX_STATUS_TO_MCU) +#define HAL_MAC_TX_DESC_UNSET_TXS_TO_MCU(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucTxStatus &= ~TX_DESC_TX_STATUS_TO_MCU) + +#define HAL_MAC_TX_DESC_IS_TXS_TO_HOST(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucTxStatus & TX_DESC_TX_STATUS_TO_HOST) ? true : \ + false) +#define HAL_MAC_TX_DESC_SET_TXS_TO_HOST(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucTxStatus |= TX_DESC_TX_STATUS_TO_HOST) +#define HAL_MAC_TX_DESC_UNSET_TXS_TO_HOST(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucTxStatus &= ~TX_DESC_TX_STATUS_TO_HOST) + +#define HAL_MAC_TX_DESC_IS_DA_FROM_WTBL(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucPowerOffset & TX_DESC_DA_SOURCE) ? true : false) +#define HAL_MAC_TX_DESC_SET_DA_FROM_WTBL(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPowerOffset |= TX_DESC_DA_SOURCE) +#define HAL_MAC_TX_DESC_SET_DA_FROM_MSDU(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPowerOffset &= ~TX_DESC_DA_SOURCE) + +#define HAL_MAC_TX_DESC_IS_SW_PM_CONTROL(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->ucPowerOffset & \ + TX_DESC_POWER_MANAGEMENT_CONTROL) ? \ + true : \ + false) +#define HAL_MAC_TX_DESC_SET_SW_PM_CONTROL(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPowerOffset |= TX_DESC_POWER_MANAGEMENT_CONTROL) +#define HAL_MAC_TX_DESC_SET_HW_PM_CONTROL(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->ucPowerOffset &= ~TX_DESC_POWER_MANAGEMENT_CONTROL) + +/* DW 6 */ +#define HAL_MAC_TX_DESC_SET_FR_BW(_prHwMacTxDesc, ucBw) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->u2AntID), ((u8)ucBw), \ + TX_DESC_BANDWIDTH_MASK, TX_DESC_BANDWIDTH_OFFSET) + +#define HAL_MAC_TX_DESC_SET_FR_DYNAMIC_BW_RTS(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2AntID |= TX_DESC_DYNAMIC_BANDWIDTH) + +#define HAL_MAC_TX_DESC_SET_FR_ANTENNA_ID(_prHwMacTxDesc, _ucAntId) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->u2AntID), ((u8)_ucAntId), \ + TX_DESC_ANTENNA_INDEX_MASK, \ + TX_DESC_ANTENNA_INDEX_OFFSET) + +#define HAL_MAC_TX_DESC_SET_FR_RATE(_prHwMacTxDesc, _u2RatetoFixed) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->u2FixedRate), \ + ((u8)_u2RatetoFixed), TX_DESC_FIXDE_RATE_MASK, \ + TX_DESC_FIXDE_RATE_OFFSET) + +#define HAL_MAC_TX_DESC_SET_FR_BF(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2FixedRate |= TX_DESC_BF) + +#define HAL_MAC_TX_DESC_SET_FR_LDPC(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2FixedRate |= TX_DESC_LDPC) + +#define HAL_MAC_TX_DESC_SET_FR_SHORT_GI(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2FixedRate |= TX_DESC_GUARD_INTERVAL) + +#define HAL_MAC_TX_DESC_SET_FR_NORMAL_GI(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2FixedRate &= ~TX_DESC_GUARD_INTERVAL) + +#define HAL_MAC_TX_DESC_IS_CR_FIXED_RATE_MODE(_prHwMacTxDesc) \ + (((_prHwMacTxDesc)->u2FixedRate & TX_DESC_FIXED_RATE_MODE) ? true : \ + false) + +#define HAL_MAC_TX_DESC_SET_FIXED_RATE_MODE_TO_DESC(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2FixedRate &= ~TX_DESC_FIXED_RATE_MODE) +#define HAL_MAC_TX_DESC_SET_FIXED_RATE_MODE_TO_CR(_prHwMacTxDesc) \ + ((_prHwMacTxDesc)->u2FixedRate |= TX_DESC_FIXED_RATE_MODE) + +/* DW 7 */ +#define HAL_MAC_TX_DESC_SET_SPE_IDX(_prHwMacTxDesc, _ucSpeIdx) \ + TX_DESC_SET_FIELD(((_prHwMacTxDesc)->u2SwTxTime), ((u16)_ucSpeIdx), \ + TX_DESC_SPE_EXT_IDX_MASK, \ + TX_DESC_SPE_EXT_IDX_OFFSET) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void nicTxInitialize(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicTxAcquireResource(IN P_ADAPTER_T prAdapter, + IN u8 ucTC, + IN u8 fgReqLock); + +WLAN_STATUS nicTxPollingResource(IN P_ADAPTER_T prAdapter, IN u8 ucTC); + +u8 nicTxReleaseResource(IN P_ADAPTER_T prAdapter, + IN u8 ucTc, + IN u32 u4PageCount, + IN u8 fgReqLock); + +void nicTxDropInvalidMsduInfo(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +void nicTxReleaseMsduResource(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead); + +WLAN_STATUS nicTxResetResource(IN P_ADAPTER_T prAdapter); + +u32 nicTxGetAdjustableResourceCnt(IN P_ADAPTER_T prAdapter); + +u16 nicTxGetResource(IN P_ADAPTER_T prAdapter, IN u8 ucTC); + +u8 nicTxGetFrameResourceType(IN u8 eFrameType, IN P_MSDU_INFO_T prMsduInfo); + +u8 nicTxGetCmdResourceType(IN P_CMD_INFO_T prCmdInfo); + +u8 nicTxSanityCheckResource(IN P_ADAPTER_T prAdapter); + +void nicTxFillDesc(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + OUT u8 *prTxDescBuffer, + OUT u32 *pu4TxDescLength); + +void nicTxFillDataDesc(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); + +void nicTxComposeSecurityFrameDesc(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + OUT u8 *prTxDescBuffer, + OUT u8 *pucTxDescLength); + +WLAN_STATUS nicTxMsduInfoList(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead); + +u8 nicTxGetTxQByTc(IN P_ADAPTER_T prAdapter, IN u8 ucTc); + +WLAN_STATUS nicTxMsduInfoListMthread(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead); + +u32 nicTxMsduQueueMthread(IN P_ADAPTER_T prAdapter); + +u32 nicTxGetMsduPendingCnt(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicTxMsduQueue(IN P_ADAPTER_T prAdapter, u8 ucPortIdx, + P_QUE_T prQue); + +WLAN_STATUS nicTxCmd(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 ucTC); + +void nicTxRelease(IN P_ADAPTER_T prAdapter, IN u8 fgProcTxDoneHandler); + +void nicProcessTxInterrupt(IN P_ADAPTER_T prAdapter); + +void nicTxFreeMsduInfoPacket(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead); + +void nicTxReturnMsduInfo(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead); + +u8 nicTxFillMsduInfo(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_NATIVE_PACKET prNdisPacket); + +WLAN_STATUS nicTxAdjustTcq(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicTxFlush(IN P_ADAPTER_T prAdapter); + +#if CFG_ENABLE_FW_DOWNLOAD +WLAN_STATUS nicTxInitCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); + +WLAN_STATUS nicTxInitResetResource(IN P_ADAPTER_T prAdapter); +#endif + +WLAN_STATUS nicTxEnqueueMsdu(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +u8 nicTxGetWlanIdx(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx, IN u8 ucStaRecIdx); + +u8 nicTxIsMgmtResourceEnough(IN P_ADAPTER_T prAdapter); + +u32 nicTxGetFreeCmdCount(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS nicTxGenerateDescTemplate(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec); + +void nicTxFreeDescTemplate(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec); + +void nicTxFreePacket(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN u8 fgDrop); + +void nicTxSetMngPacket(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN u8 ucBssIndex, + IN u8 ucStaRecIndex, + IN u8 ucMacHeaderLength, + IN u16 u2FrameLength, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler, + IN u8 ucRateMode); + +void nicTxSetDataPacket(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN u8 ucBssIndex, + IN u8 ucStaRecIndex, + IN u8 ucMacHeaderLength, + IN u16 u2FrameLength, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler, + IN u8 ucRateMode, + IN ENUM_TX_PACKET_SRC_T eSrc, + IN u8 ucTID, + IN u8 fgIs802_11Frame, + IN u8 fgIs1xFrame); + +void nicTxFillDescByPktOption(IN P_MSDU_INFO_T prMsduInfo, + IN P_HW_MAC_TX_DESC_T prTxDesc); + +void nicTxConfigPktOption(IN P_MSDU_INFO_T prMsduInfo, + IN u32 u4OptionMask, + IN u8 fgSetOption); + +void nicTxFillDescByPktControl(P_MSDU_INFO_T prMsduInfo, + P_HW_MAC_TX_DESC_T prTxDesc); + +void nicTxConfigPktControlFlag(IN P_MSDU_INFO_T prMsduInfo, + IN u8 ucControlFlagMask, + IN u8 fgSetFlag); + +void nicTxSetPktLifeTime(IN P_MSDU_INFO_T prMsduInfo, IN u32 u4TxLifeTimeInMs); + +void nicTxSetPktRetryLimit(IN P_MSDU_INFO_T prMsduInfo, IN u8 ucRetryLimit); + +void nicTxSetPktPowerOffset(IN P_MSDU_INFO_T prMsduInfo, IN s8 cPowerOffset); + +void nicTxSetPktSequenceNumber(IN P_MSDU_INFO_T prMsduInfo, IN u16 u2SN); + +void nicTxSetPktMacTxQue(IN P_MSDU_INFO_T prMsduInfo, IN u8 ucMacTxQue); + +void nicTxSetPktFixedRateOptionFull(P_MSDU_INFO_T prMsduInfo, + u16 u2RateCode, + u8 ucBandwidth, + u8 fgShortGI, + u8 fgLDPC, + u8 fgDynamicBwRts, + u8 fgBeamforming, + u8 ucAntennaIndex); + +void nicTxSetPktFixedRateOption(IN P_MSDU_INFO_T prMsduInfo, + IN u16 u2RateCode, + IN u8 ucBandwidth, + IN u8 fgShortGI, + IN u8 fgDynamicBwRts); + +void nicTxSetPktLowestFixedRate(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +void nicTxSetPktMoreData(IN P_MSDU_INFO_T prCurrentMsduInfo, + IN u8 fgSetMoreDataBit); + +void nicTxSetPktEOSP(IN P_MSDU_INFO_T prCurrentMsduInfo, IN u8 fgSetEOSPBit); + +u8 nicTxAssignPID(IN P_ADAPTER_T prAdapter, IN u8 ucWlanIndex); + +WLAN_STATUS +nicTxDummyTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +void nicTxUpdateBssDefaultRate(IN P_BSS_INFO_T prBssInfo); + +void nicTxUpdateStaRecDefaultRate(IN P_STA_RECORD_T prStaRec); + +void nicTxPrintMetRTP(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_NATIVE_PACKET prPacket, + IN u32 u4PacketLen, + IN u8 bFreeSkb); + +void nicTxProcessTxDoneEvent(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); + +void nicTxMsduDoneCb(IN P_GLUE_INFO_T prGlueInfo, IN P_QUE_T prQue); + +/* TX Direct functions : BEGIN */ +void nicTxDirectStartCheckQTimer(IN P_ADAPTER_T prAdapter); +void nicTxDirectClearSkbQ(IN P_ADAPTER_T prAdapter); +void nicTxDirectClearHifQ(IN P_ADAPTER_T prAdapter); +void nicTxDirectClearStaPsQ(IN P_ADAPTER_T prAdapter, u8 ucStaRecIndex); +void nicTxDirectClearBssAbsentQ(IN P_ADAPTER_T prAdapter, u8 ucBssIndex); +void nicTxDirectClearAllStaPsQ(IN P_ADAPTER_T prAdapter); +#if KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE +void nicTxDirectTimerCheckSkbQ(struct timer_list *timer); +void nicTxDirectTimerCheckHifQ(struct timer_list *timer); +#else +void nicTxDirectTimerCheckSkbQ(unsigned long data); +void nicTxDirectTimerCheckHifQ(unsigned long data); +#endif +WLAN_STATUS nicTxDirectStartXmit(struct sk_buff *prSkb, + P_GLUE_INFO_T prGlueInfo); +/* TX Direct functions : END */ + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) +u8 nicTxGetWmmIdxByTc(u8 ucTC); +extern const u8 arTcRemapTable[HW_WMM_NUM][TC3_INDEX + 1]; +#endif + +u8 nicTxProcessMngPacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); +void nicTxComposeDescAppend(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + OUT u8 *prTxDescBuffer); +void nicTxComposeDesc(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + IN u32 u4TxDescLength, IN u8 fgIsTemplate, + OUT u8 *prTxDescBuffer); +u8 nicTxIsTXDTemplateAllowed(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_STA_RECORD_T prStaRec); +void nicTxCopyDesc(IN P_ADAPTER_T prAdapter, IN u8 *pucTarTxDesc, + IN u8 *pucSrcTxDesc, OUT u8 *pucTxDescLength); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic_umac.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic_umac.h new file mode 100644 index 00000000000000..f5165d8697c4c6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/nic_umac.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "nic_umac.h" + * \brief The declaration of the nic umac debug functions + * + */ + +#ifndef _NIC_UMAC_H +#define _NIC_UMAC_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define UMAC_FID_MASK 0xFFF + +#define UMAC_FID_FAULT 0xFFF + +#define UMAC_PLE_CFG_POOL_INDEX 0 +#define UMAC_PSE_CFG_POOL_INDEX 1 + +#define UMAC_PG_HIF0_GROUP_0 0 +#define UMAC_PG_HIF1_GROUP_1 1 +#define UMAC_PG_CPU_GROUP_2 2 +#define UMAC_PG_LMAC0_GROUP_3 3 +#define UMAC_PG_LMAC1_GROUP_4 4 +#define UMAC_PG_LMAC2_GROUP_5 5 +#define UMAC_PG_PLE_GROUP_6 6 + +#define UMAC_PBUF_CTRL_TOTAL_PAGE_NUM_MASK BITS(0, 11) +#define UMAC_PBUF_CTRL_TOTAL_PAGE_NUM_OFFSET 0 + +#define UMAC_FREEPG_CNT_FREEPAGE_CNT_MASK BITS(0, 11) +#define UMAC_FREEPG_CNT_FREEPAGE_CNT_OFFSET 0 + +#define UMAC_FREEPG_CNT_FFA_CNT_MASK BITS(16, 27) +#define UMAC_FREEPG_CNT_FFA_CNT_OFFSET 16 + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +OUT u8 halUmacInfoGetMiscStatus(IN P_ADAPTER_T prAdapter, + IN P_UMAC_STAT2_GET_T pUmacStat2Get); + +OUT u16 halUmacPbufCtrlTotalPageNum(IN P_ADAPTER_T prAdapter, + IN u16 fgPsePleFlag); + +OUT u16 halUmacWrapFfaCnt(IN P_ADAPTER_T prAdapter, IN u8 fgPsePleFlag); + +OUT u16 halUmacWrapFrePageCnt(IN P_ADAPTER_T prAdapter, IN u8 fgPsePleFlag); + +OUT u16 halUmacWrapSrcPgCnt(IN P_ADAPTER_T prAdapter, IN u8 fgPsePleFlag, + IN u8 ucPageGroupID); + +OUT u8 halUmacWrapSourcePortSanityCheck(IN u8 fgPsePleFlag, + IN u8 ucPageGroupID); + +OUT u16 halUmacWrapRsvPgCnt(IN P_ADAPTER_T prAdapter, IN u8 fgPsePleFlag, + IN u8 ucPageGroupID); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p.h new file mode 100644 index 00000000000000..7df4dd6804dbc7 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p.h @@ -0,0 +1,293 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +#ifndef _P2P_H +#define _P2P_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* refer to 'Config Methods' in WPS */ +#define WPS_CONFIG_USBA 0x0001 +#define WPS_CONFIG_ETHERNET 0x0002 +#define WPS_CONFIG_LABEL 0x0004 +#define WPS_CONFIG_DISPLAY 0x0008 +#define WPS_CONFIG_EXT_NFC 0x0010 +#define WPS_CONFIG_INT_NFC 0x0020 +#define WPS_CONFIG_NFC 0x0040 +#define WPS_CONFIG_PBC 0x0080 +#define WPS_CONFIG_KEYPAD 0x0100 + +/* refer to 'Device Password ID' in WPS */ +#define WPS_DEV_PASSWORD_ID_PIN 0x0000 +#define WPS_DEV_PASSWORD_ID_USER 0x0001 +#define WPS_DEV_PASSWORD_ID_MACHINE 0x0002 +#define WPS_DEV_PASSWORD_ID_REKEY 0x0003 +#define WPS_DEV_PASSWORD_ID_PUSHBUTTON 0x0004 +#define WPS_DEV_PASSWORD_ID_REGISTRAR 0x0005 + +#define P2P_DEVICE_TYPE_NUM 2 +#define P2P_DEVICE_NAME_LENGTH 32 +#define P2P_NETWORK_NUM 8 +#define P2P_MEMBER_NUM 8 + +/* Device Capability Definition. */ +#define P2P_MAXIMUM_CLIENT_COUNT 10 +#define P2P_MAXIMUM_NOA_COUNT 8 + +#define P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE 51 /* Contains 6 sub-band. */ + +/* Memory Size Definition. */ +#define P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE 768 +#define WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE 300 + +#define P2P_WILDCARD_SSID "DIRECT-" + +/* Device Charactoristic. */ +#define P2P_AP_CHNL_HOLD_TIME_MS \ + 5000 /* 1000 is too short , the deauth would block in the queue */ +#define P2P_DEFAULT_LISTEN_CHANNEL 1 + +#if (CFG_SUPPORT_DFS_MASTER == 1) +#define P2P_AP_CAC_WEATHER_CHNL_HOLD_TIME_MS (600 * 1000) +#endif + +#define P2P_DEAUTH_TIMEOUT_TIME_MS 1000 + +#define P2P_SAA_RETRY_COUNT 3 + +/* Define the Delay time for DBDC DFS Master mode */ +#if CFG_SUPPORT_DBDC_TC6 +#define P2P_DFS_CAC_DELAY_TIME_MS 5000 +#endif + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#if DBG +#define ASSERT_BREAK(_exp) \ + { \ + if (!(_exp)) { \ + ASSERT(false); \ + } \ + } + +#else +#define ASSERT_BREAK(_exp) +#endif + +#define p2pChangeMediaState(_prAdapter, _prP2pBssInfo, _eNewMediaState) \ + (_prP2pBssInfo->eConnectionState = (_eNewMediaState)) + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +struct _P2P_INFO_T { + u32 u4DeviceNum; + EVENT_P2P_DEV_DISCOVER_RESULT_T + arP2pDiscoverResult[CFG_MAX_NUM_BSS_LIST]; + u8 *pucCurrIePtr; + /* A common pool for IE of all scan results. */ + u8 aucCommIePool[CFG_MAX_COMMON_IE_BUF_LEN]; +}; + +typedef enum { + ENUM_P2P_PEER_GROUP, + ENUM_P2P_PEER_DEVICE, + ENUM_P2P_PEER_NUM +} ENUM_P2P_PEER_TYPE, +*P_ENUM_P2P_PEER_TYPE; + +typedef struct _P2P_DEVICE_INFO { + u8 aucDevAddr[PARAM_MAC_ADDR_LEN]; + u8 aucIfAddr[PARAM_MAC_ADDR_LEN]; + u8 ucDevCapabilityBitmap; + s32 i4ConfigMethod; + u8 aucPrimaryDeviceType[8]; + u8 aucSecondaryDeviceType[8]; + u8 aucDeviceName[P2P_DEVICE_NAME_LENGTH]; +} P2P_DEVICE_INFO, *P_P2P_DEVICE_INFO; + +typedef struct _P2P_GROUP_INFO { + PARAM_SSID_T rGroupID; + P2P_DEVICE_INFO rGroupOwnerInfo; + u8 ucMemberNum; + P2P_DEVICE_INFO arMemberInfo[P2P_MEMBER_NUM]; +} P2P_GROUP_INFO, *P_P2P_GROUP_INFO; + +typedef struct _P2P_NETWORK_INFO { + ENUM_P2P_PEER_TYPE eNodeType; + + union { + P2P_GROUP_INFO rGroupInfo; + P2P_DEVICE_INFO rDeviceInfo; + } node; +} P2P_NETWORK_INFO, *P_P2P_NETWORK_INFO; + +typedef struct _P2P_NETWORK_LIST { + u8 ucNetworkNum; + P2P_NETWORK_INFO rP2PNetworkInfo[P2P_NETWORK_NUM]; +} P2P_NETWORK_LIST, *P_P2P_NETWORK_LIST; + +typedef struct _P2P_DISCONNECT_INFO { + u8 ucRole; + u8 ucRsv[3]; +} P2P_DISCONNECT_INFO, *P_P2P_DISCONNECT_INFO; + +typedef struct _P2P_SSID_STRUCT_T { + u8 aucSsid[32]; + u8 ucSsidLen; +} P2P_SSID_STRUCT_T, *P_P2P_SSID_STRUCT_T; + +typedef struct _P2P_SCAN_REQ_INFO_T { + ENUM_SCAN_TYPE_T eScanType; + ENUM_SCAN_CHANNEL eChannelSet; + u16 u2PassiveDewellTime; + u8 ucSeqNumOfScnMsg; + u8 fgIsAbort; + u8 fgIsScanRequest; + u8 ucNumChannelList; + RF_CHANNEL_INFO_T arScanChannelList[MAXIMUM_OPERATION_CHANNEL_LIST]; + u32 u4BufLength; + u8 aucIEBuf[MAX_IE_LENGTH]; + u8 ucSsidNum; + P2P_SSID_STRUCT_T arSsidStruct[SCN_SSID_MAX_NUM]; /* Currently we can + * only take one SSID + * scan request */ +} P2P_SCAN_REQ_INFO_T, *P_P2P_SCAN_REQ_INFO_T; + +typedef struct _P2P_CHNL_REQ_INFO_T { + LINK_T rP2pChnlReqLink; + u8 fgIsChannelRequested; + u8 ucSeqNumOfChReq; + u64 u8Cookie; + u8 ucReqChnlNum; + ENUM_BAND_T eBand; + ENUM_CHNL_EXT_T eChnlSco; + u8 ucOriChnlNum; + ENUM_CHANNEL_WIDTH_T eChannelWidth; /*VHT operation ie */ + u8 ucCenterFreqS1; + u8 ucCenterFreqS2; + ENUM_BAND_T eOriBand; + ENUM_CHNL_EXT_T eOriChnlSco; + u32 u4MaxInterval; + ENUM_CH_REQ_TYPE_T eChnlReqType; +#if CFG_SUPPORT_NFC_BEAM_PLUS + u32 NFC_BEAM; /*NFC Beam + Indication */ +#endif +} P2P_CHNL_REQ_INFO_T, *P_P2P_CHNL_REQ_INFO_T; + +/* Glubal Connection Settings. */ +struct _P2P_CONNECTION_SETTINGS_T { + /*u8 ucRfChannelListSize;*/ +#if P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE + /*u8 aucChannelEntriesField[P2P_MAX_SUPPORTED_CHANNEL_LIST_SIZE];*/ +#endif + + u8 fgIsApMode; +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER + u8 fgIsWPSMode; +#endif +}; + +typedef struct _NOA_TIMING_T { + u8 fgIsInUse; /* Indicate if this entry is in use or not */ + u8 ucCount; /* Count */ + + u8 aucReserved[2]; + + u32 u4Duration; /* Duration */ + u32 u4Interval; /* Interval */ + u32 u4StartTime; /* Start Time */ +} NOA_TIMING_T, *P_NOA_TIMING_T; + +struct _P2P_SPECIFIC_BSS_INFO_T { + /* For GO(AP) Mode - Compose TIM IE */ + /*u16 u2SmallestAID;*/ /* TH3 multiple P2P */ + /*u16 u2LargestAID;*/ /* TH3 multiple P2P */ + /*u8 ucBitmapCtrl;*/ /* TH3 multiple P2P */ + /* u8 aucPartialVirtualBitmap[MAX_LEN_TIM_PARTIAL_BMP]; + */ + + /* For GC/GO OppPS */ + u8 fgEnableOppPS; + u16 u2CTWindow; + + /* For GC/GO NOA */ + u8 ucNoAIndex; + u8 ucNoATimingCount; /* Number of NoA Timing */ + NOA_TIMING_T arNoATiming[P2P_MAXIMUM_NOA_COUNT]; + + u8 fgIsNoaAttrExisted; + + /* For P2P Device */ + /*u8 ucRegClass;*/ /* TH3 multiple P2P */ /* Regulatory Class for + * channel. + */ + /* Linten Channel only on channels 1, 6 and 11 in the 2.4 GHz. */ + /*u8 ucListenChannel;*/ /* TH3 multiple P2P */ + + /* Operating Channel, should be one of channel */ + /* list in p2p connection settings. */ + u8 ucPreferredChannel; + ENUM_CHNL_EXT_T eRfSco; + ENUM_BAND_T eRfBand; + + /* Extended Listen Timing. */ + u16 u2AvailabilityPeriod; + u16 u2AvailabilityInterval; + + u16 u2AttributeLen; + u8 aucAttributesCache[P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE]; + + /*u16 u2WscAttributeLen;*/ /* TH3 multiple P2P */ + /*u8 aucWscAttributesCache[WPS_MAXIMUM_ATTRIBUTES_CACHE_SIZE];*/ /* TH3 + * multiple + * P2P + */ + + /*u8 aucGroupID[MAC_ADDR_LEN];*/ /* TH3 multiple P2P */ + u16 u2GroupSsidLen; + u8 aucGroupSsid[ELEM_MAX_LEN_SSID]; + + PARAM_CUSTOM_NOA_PARAM_STRUCT_T rNoaParam; + PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T rOppPsParam; + + u16 u2WpaIeLen; + u8 aucWpaIeBuffer[ELEM_HDR_LEN + ELEM_MAX_LEN_WPA]; +}; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p_cmd_buf.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p_cmd_buf.h new file mode 100644 index 00000000000000..2b88bcdfc14cdd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p_cmd_buf.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "p2p_cmd_buf.h" + * \brief In this file we define the structure for Command Packet. + * + * In this file we define the structure for Command Packet and the + * control unit of MGMT Memory Pool. + */ + +#ifndef _P2P_CMD_BUF_H +#define _P2P_CMD_BUF_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*--------------------------------------------------------------*/ +/* Firmware Command Packer */ +/*--------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendSetQueryP2PCmd(IN P_ADAPTER_T prAdapter, + IN u8 ucCID, + IN u8 ucBssIdx, + IN u8 fgSetQuery, + IN u8 fgNeedResp, + IN u8 fgIsOid, + IN PFN_CMD_DONE_HANDLER pfCmdDoneHandler, + IN PFN_CMD_TIMEOUT_HANDLER pfCmdTimeoutHandler, + IN u32 u4SetQueryInfoLen, + IN u8 *pucInfoBuffer, + OUT void *pvSetQueryBuffer, + IN u32 u4SetQueryBufferLen); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p_mac.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p_mac.h new file mode 100644 index 00000000000000..d667ad5e45aa8d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p_mac.h @@ -0,0 +1,354 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "p2p_mac.h" + * \brief Brief description. + * + * Detail description. + */ + +#ifndef _P2P_MAC_H +#define _P2P_MAC_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define ACTION_PUBLIC_WIFI_DIRECT 9 +#define ACTION_GAS_INITIAL_REQUEST 10 +#define ACTION_GAS_INITIAL_RESPONSE 11 +#define ACTION_GAS_COMEBACK_REQUEST 12 +#define ACTION_GAS_COMEBACK_RESPONSE 13 + +/* P2P 4.2.8.1 - P2P Public Action Frame Type. */ +#define P2P_PUBLIC_ACTION_GO_NEGO_REQ 0 +#define P2P_PUBLIC_ACTION_GO_NEGO_RSP 1 +#define P2P_PUBLIC_ACTION_GO_NEGO_CFM 2 +#define P2P_PUBLIC_ACTION_INVITATION_REQ 3 +#define P2P_PUBLIC_ACTION_INVITATION_RSP 4 +#define P2P_PUBLIC_ACTION_DEV_DISCOVER_REQ 5 +#define P2P_PUBLIC_ACTION_DEV_DISCOVER_RSP 6 +#define P2P_PUBLIC_ACTION_PROV_DISCOVERY_REQ 7 +#define P2P_PUBLIC_ACTION_PROV_DISCOVERY_RSP 8 + +/* P2P 4.2.9.1 - P2P Action Frame Type */ +#define P2P_ACTION_NOTICE_OF_ABSENCE 0 +#define P2P_ACTION_P2P_PRESENCE_REQ 1 +#define P2P_ACTION_P2P_PRESENCE_RSP 2 +#define P2P_ACTION_GO_DISCOVER_REQ 3 + +#define P2P_PUBLIC_ACTION_FRAME_LEN (WLAN_MAC_MGMT_HEADER_LEN + 8) +#define P2P_ACTION_FRAME_LEN (WLAN_MAC_MGMT_HEADER_LEN + 7) + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/* --------------- WPS Data Element Definitions --------------- */ +/* P2P 4.2.2 - General WSC Attribute */ +#define WSC_ATTRI_HDR_LEN 4 /* ID(2 octet) + Length(2 octets) */ +#define WSC_ATTRI_MAX_LEN_VERSION 1 +#define WSC_ATTRI_MAX_LEN_DEVICE_PASSWORD_ID 2 +#define WSC_ATTRI_LEN_CONFIG_METHOD 2 + +/* --------------- WFA P2P IE --------------- */ +/* P2P 4.1.1 - P2P IE format */ +#define P2P_OUI_TYPE_LEN 4 +/* == OFFSET_OF(IE_P2P_T, aucP2PAttributes[0]) */ +#define P2P_IE_OUI_HDR (ELEM_HDR_LEN + \ + P2P_OUI_TYPE_LEN) + +/* P2P 4.1.1 - General P2P Attribute */ +#define P2P_ATTRI_HDR_LEN 3 /* ID(1 octet) + Length(2 octets) */ + +/* P2P 4.1.1 - P2P Attribute ID definitions */ +#define P2P_ATTRI_ID_STATUS 0 +#define P2P_ATTRI_ID_REASON_CODE 1 +#define P2P_ATTRI_ID_P2P_CAPABILITY 2 +#define P2P_ATTRI_ID_P2P_DEV_ID 3 +#define P2P_ATTRI_ID_GO_INTENT 4 +#define P2P_ATTRI_ID_CFG_TIMEOUT 5 +#define P2P_ATTRI_ID_LISTEN_CHANNEL 6 +#define P2P_ATTRI_ID_P2P_GROUP_BSSID 7 +#define P2P_ATTRI_ID_EXT_LISTEN_TIMING 8 +#define P2P_ATTRI_ID_INTENDED_P2P_IF_ADDR 9 +#define P2P_ATTRI_ID_P2P_MANAGEABILITY 10 +#define P2P_ATTRI_ID_CHANNEL_LIST 11 +#define P2P_ATTRI_ID_NOTICE_OF_ABSENCE 12 +#define P2P_ATTRI_ID_P2P_DEV_INFO 13 +#define P2P_ATTRI_ID_P2P_GROUP_INFO 14 +#define P2P_ATTRI_ID_P2P_GROUP_ID 15 +#define P2P_ATTRI_ID_P2P_INTERFACE 16 +#define P2P_ATTRI_ID_OPERATING_CHANNEL 17 +#define P2P_ATTRI_ID_INVITATION_FLAG 18 +#define P2P_ATTRI_ID_VENDOR_SPECIFIC 221 + +/* Maximum Length of P2P Attributes */ +#define P2P_ATTRI_MAX_LEN_STATUS 1 /* 0 */ +#define P2P_ATTRI_MAX_LEN_REASON_CODE 1 /* 1 */ +#define P2P_ATTRI_MAX_LEN_P2P_CAPABILITY 2 /* 2 */ +#define P2P_ATTRI_MAX_LEN_P2P_DEV_ID 6 /* 3 */ +#define P2P_ATTRI_MAX_LEN_GO_INTENT 1 /* 4 */ +#define P2P_ATTRI_MAX_LEN_CFG_TIMEOUT 2 /* 5 */ +#define P2P_ATTRI_MAX_LEN_LISTEN_CHANNEL 5 /* 6 */ +#define P2P_ATTRI_MAX_LEN_P2P_GROUP_BSSID 6 /* 7 */ +#define P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING 4 /* 8 */ +#define P2P_ATTRI_MAX_LEN_INTENDED_P2P_IF_ADDR 6 /* 9 */ +#define P2P_ATTRI_MAX_LEN_P2P_MANAGEABILITY 1 /* 10 */ +/* #define P2P_ATTRI_MAX_LEN_CHANNEL_LIST 3 + (n* (2 + + * num_of_ch)) */ /* 11 */ +#define P2P_ATTRI_LEN_CHANNEL_LIST 3 /* 11 */ +#define P2P_ATTRI_LEN_CHANNEL_ENTRY 2 /* 11 */ + +#define P2P_MAXIMUM_ATTRIBUTE_LEN 251 + +/* P2P 4.1.2 - P2P Status definitions */ +#define P2P_STATUS_SUCCESS 0 +#define P2P_STATUS_FAIL_INFO_IS_CURRENTLY_UNAVAILABLE 1 +#define P2P_STATUS_FAIL_INCOMPATIBLE_PARAM 2 +#define P2P_STATUS_FAIL_LIMIT_REACHED 3 +#define P2P_STATUS_FAIL_INVALID_PARAM 4 +#define P2P_STATUS_FAIL_UNABLE_ACCOMMODATE_REQ 5 +#define P2P_STATUS_FAIL_PREVIOUS_PROTOCOL_ERR 6 +#define P2P_STATUS_FAIL_NO_COMMON_CHANNELS 7 +#define P2P_STATUS_FAIL_UNKNOWN_P2P_GROUP 8 +#define P2P_STATUS_FAIL_SAME_INTENT_VALUE_15 9 +#define P2P_STATUS_FAIL_INCOMPATIBLE_PROVISION_METHOD 10 +#define P2P_STATUS_FAIL_REJECTED_BY_USER 11 + +/* P2P 4.1.14 - CTWindow and OppPS Parameters definitions */ +#define P2P_CTW_OPPPS_PARAM_OPPPS_FIELD BIT(7) +#define P2P_CTW_OPPPS_PARAM_CTWINDOW_MASK BITS(0, 6) + +/* --------------- WFA P2P IE and Attributes --------------- */ + +/* P2P 4.1.1 - P2P Information Element */ +typedef struct _IE_P2P_T { + u8 ucId; /* Element ID */ + u8 ucLength; /* Length */ + u8 aucOui[3]; /* OUI */ + u8 ucOuiType; /* OUI Type */ + u8 aucP2PAttributes[1]; /* P2P Attributes */ +} __KAL_ATTRIB_PACKED__ IE_P2P_T, *P_IE_P2P_T; + +/* P2P 4.1.1 - General WSC Attribute */ +typedef struct _WSC_ATTRIBUTE_T { + u16 u2Id; /* Attribute ID */ + u16 u2Length; /* Length */ + u8 aucBody[1]; /* Body field */ +} __KAL_ATTRIB_PACKED__ WSC_ATTRIBUTE_T, *P_WSC_ATTRIBUTE_T; + +/* P2P 4.1.2 - P2P Status Attribute */ +typedef struct _P2P_ATTRI_STATUS_T { + u8 ucId; /* Attribute ID */ + u16 u2Length; /* Length */ + u8 ucStatusCode; /* Status Code */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_STATUS_T, *P_P2P_ATTRI_STATUS_T; + +/* P2P 4.1.10 - Extended Listen Timing Attribute */ +typedef struct _P2P_ATTRI_EXT_LISTEN_TIMING_T { + u8 ucId; /* Attribute ID */ + u16 u2Length; /* Length */ + u16 u2AvailPeriod; /* Availability Period */ + u16 u2AvailInterval; /* Availability Interval */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_EXT_LISTEN_TIMING_T, +*P_P2P_ATTRI_EXT_LISTEN_TIMING_T; + +/* P2P 4.2.8.2 P2P Public Action Frame Format */ +typedef struct _P2P_PUBLIC_ACTION_FRAME_T { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + u8 ucCategory; /* Category, 0x04 */ + u8 ucAction; /* Action Value, 0x09 */ + u8 aucOui[3]; /* 0x50, 0x6F, 0x9A */ + u8 ucOuiType; /* 0x09 */ + u8 ucOuiSubtype; /* GO Nego Req/Rsp/Cfm, P2P Invittion Req/Rsp, Device + * Discoverability Req/Rsp */ + u8 ucDialogToken; /* Dialog Token. */ + u8 aucInfoElem[1]; /* P2P IE, WSC IE. */ +} __KAL_ATTRIB_PACKED__ P2P_PUBLIC_ACTION_FRAME_T, *P_P2P_PUBLIC_ACTION_FRAME_T; + +/* P2P 4.2.9.1 - General Action Frame Format. */ +typedef struct _P2P_ACTION_FRAME_T { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* P2P Action Frame Body */ + u8 ucCategory; /* 0x7F */ + u8 aucOui[3]; /* 0x50, 0x6F, 0x9A */ + u8 ucOuiType; /* 0x09 */ + u8 ucOuiSubtype; /* */ + u8 ucDialogToken; + u8 aucInfoElem[1]; +} __KAL_ATTRIB_PACKED__ P2P_ACTION_FRAME_T, *P_P2P_ACTION_FRAME_T; + +/* P2P C.1 GAS Public Action Initial Request Frame Format */ +typedef struct _GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + u8 ucCategory; /* Category, 0x04 */ + u8 ucAction; /* Action Value, 0x09 */ + u8 ucDialogToken; /* Dialog Token. */ + u8 aucInfoElem[1]; /* Advertisement IE. */ +} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T, +*P_GAS_PUBLIC_ACTION_INITIAL_REQUEST_FRAME_T; + +/* P2P C.2 GAS Public Action Initial Response Frame Format */ +typedef struct _GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + u8 ucCategory; /* Category, 0x04 */ + u8 ucAction; /* Action Value, 0x09 */ + u8 ucDialogToken; /* Dialog Token. */ + u16 u2StatusCode; /* Initial Response. */ + u16 u2ComebackDelay; /* Initial Response. */ /* In unit of TU. */ + u8 aucInfoElem[1]; /* Advertisement IE. */ +} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T, +*P_GAS_PUBLIC_ACTION_INITIAL_RESPONSE_FRAME_T; + +/* P2P C.3-1 GAS Public Action Comeback Request Frame Format */ +typedef struct _GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + u8 ucCategory; /* Category, 0x04 */ + u8 ucAction; /* Action Value, 0x09 */ + u8 ucDialogToken; /* Dialog Token. */ +} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T, +*P_GAS_PUBLIC_ACTION_COMEBACK_REQUEST_FRAME_T; + +/* P2P C.3-2 GAS Public Action Comeback Response Frame Format */ +typedef struct _GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T { + /* MAC header */ + u16 u2FrameCtrl; /* Frame Control */ + u16 u2Duration; /* Duration */ + u8 aucDestAddr[MAC_ADDR_LEN]; /* DA */ + u8 aucSrcAddr[MAC_ADDR_LEN]; /* SA */ + u8 aucBSSID[MAC_ADDR_LEN]; /* BSSID */ + u16 u2SeqCtrl; /* Sequence Control */ + /* P2P Public Action Frame Body */ + u8 ucCategory; /* Category, 0x04 */ + u8 ucAction; /* Action Value, 0x09 */ + u8 ucDialogToken; /* Dialog Token. */ + u16 u2StatusCode; /* Comeback Response. */ + u8 ucFragmentID; /*Comeback Response. */ + u16 u2ComebackDelay; /* Comeback Response. */ + u8 aucInfoElem[1]; /* Advertisement IE. */ +} __KAL_ATTRIB_PACKED__ GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T, +*P_GAS_PUBLIC_ACTION_COMEBACK_RESPONSE_FRAME_T; + +typedef struct _P2P_SD_VENDER_SPECIFIC_CONTENT_T { + /* Service Discovery Vendor-specific Content. */ + u8 ucOuiSubtype; /* 0x09 */ + u16 u2ServiceUpdateIndicator; + u8 aucServiceTLV[1]; +} __KAL_ATTRIB_PACKED__ P2P_SD_VENDER_SPECIFIC_CONTENT_T, +*P_P2P_SD_VENDER_SPECIFIC_CONTENT_T; + +typedef struct _P2P_SERVICE_REQUEST_TLV_T { + u16 u2Length; + u8 ucServiceProtocolType; + u8 ucServiceTransID; + u8 aucQueryData[1]; +} __KAL_ATTRIB_PACKED__ P2P_SERVICE_REQUEST_TLV_T, *P_P2P_SERVICE_REQUEST_TLV_T; + +typedef struct _P2P_SERVICE_RESPONSE_TLV_T { + u16 u2Length; + u8 ucServiceProtocolType; + u8 ucServiceTransID; + u8 ucStatusCode; + u8 aucResponseData[1]; +} __KAL_ATTRIB_PACKED__ P2P_SERVICE_RESPONSE_TLV_T, +*P_P2P_SERVICE_RESPONSE_TLV_T; + +/* P2P 4.1.1 - General P2P Attribute */ +typedef struct _P2P_ATTRIBUTE_T { + u8 ucId; /* Attribute ID */ + u16 u2Length; /* Length */ + u8 aucBody[1]; /* Body field */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRIBUTE_T, ATTRIBUTE_HDR_T, *P_P2P_ATTRIBUTE_T, +*P_ATTRIBUTE_HDR_T; + +/* P2P 4.1.14 - Notice of Absence Attribute */ +typedef struct _P2P_ATTRI_NOA_T { + u8 ucId; /* Attribute ID */ + u16 u2Length; /* Length */ + u8 ucIndex; /* Index */ + u8 ucCTWOppPSParam; /* CTWindow and OppPS Parameters */ + u8 aucNoADesc[1]; /* NoA Descriptor */ +} __KAL_ATTRIB_PACKED__ P2P_ATTRI_NOA_T, *P_P2P_ATTRI_NOA_T; + +typedef struct _NOA_DESCRIPTOR_T { + u8 ucCountType; /* Count/Type */ + u32 u4Duration; /* Duration */ + u32 u4Interval; /* Interval */ + u32 u4StartTime; /* Start Time */ +} __KAL_ATTRIB_PACKED__ NOA_DESCRIPTOR_T, *P_NOA_DESCRIPTOR_T; +typedef struct _CHANNEL_ENTRY_FIELD_T { + u8 ucRegulatoryClass; /* Regulatory Class */ + u8 ucNumberOfChannels; /* Number Of Channels */ + u8 aucChannelList[1]; /* Channel List */ +} __KAL_ATTRIB_PACKED__ CHANNEL_ENTRY_FIELD_T, *P_CHANNEL_ENTRY_FIELD_T; + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p_nic.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p_nic.h new file mode 100644 index 00000000000000..73a2b33b6b0e1e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p_nic.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "p2p_nic.h" + * \brief The declaration of nic functions + * + * Detail description. + */ + +#ifndef _P2P_NIC_H +#define _P2P_NIC_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void nicP2pMediaStateChange(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_EVENT_CONNECTION_STATUS prConnectionStatus); + +void nicRxAddP2pDevice(IN P_ADAPTER_T prAdapter, + IN P_EVENT_P2P_DEV_DISCOVER_RESULT_T prP2pResult, + IN u8 *pucRxIEBuf, + IN u16 u2RxIELength); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p_nic_cmd_event.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p_nic_cmd_event.h new file mode 100644 index 00000000000000..5cffb7ab7b85c4 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/p2p_nic_cmd_event.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file p2p_nic_cmd_event.h + * \brief + */ + +#ifndef _P2P_NIC_CMD_EVENT_H +#define _P2P_NIC_CMD_EVENT_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +typedef struct _EVENT_P2P_DEV_DISCOVER_RESULT_T { + /* u8 aucCommunicateAddr[MAC_ADDR_LEN]; // + * Deprecated. */ + u8 aucDeviceAddr[MAC_ADDR_LEN]; /* Device Address. */ + u8 aucInterfaceAddr[MAC_ADDR_LEN]; /* Device Address. */ + u8 ucDeviceCapabilityBitmap; + u8 ucGroupCapabilityBitmap; + u16 u2ConfigMethod; /* Configure Method. */ + P2P_DEVICE_TYPE_T rPriDevType; + u8 ucSecDevTypeNum; + P2P_DEVICE_TYPE_T arSecDevType[2]; + u16 u2NameLength; + u8 aucName[32]; + u8 *pucIeBuf; + u16 u2IELength; + u8 aucBSSID[MAC_ADDR_LEN]; + /* TODO: Service Information or PasswordID valid? */ +} EVENT_P2P_DEV_DISCOVER_RESULT_T, *P_EVENT_P2P_DEV_DISCOVER_RESULT_T; + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/que_mgt.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/que_mgt.h new file mode 100644 index 00000000000000..b7a233a955aecf --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/que_mgt.h @@ -0,0 +1,992 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "que_mgt.h" + * \brief TX/RX queues management header file + * + * The main tasks of queue management include TC-based HIF TX flow control, + * adaptive TC quota adjustment, HIF TX grant scheduling, Power-Save + * forwarding control, RX packet reordering, and RX BA agreement management. + */ + +#ifndef _QUE_MGT_H +#define _QUE_MGT_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +extern u8 g_arTdlsLink[MAXNUM_TDLS_PEER]; +extern const u8 *apucACI2Str[4]; +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* Queue Manager Features */ +#define QM_BURST_END_INFO_ENABLED \ + 0 /* 1: Indicate the last TX packet to the FW for each burst */ +#define QM_FORWARDING_FAIRNESS \ + 1 /* 1: To fairly share TX resource among active STAs */ + +#define QM_ADAPTIVE_TC_RESOURCE_CTRL \ + 1 /* 1: To adaptively adjust resource for each TC */ +#define QM_FAST_TC_RESOURCE_CTRL \ + 1 /* 1: To fast adjust resource for EMPTY TC (assigned resource is 0) \ + */ +#define QM_PRINT_TC_RESOURCE_CTRL \ + 0 /* 1: To print TC resource adjustment results */ +/* 1: If pkt with SSN is missing, auto advance the RX reordering window */ +#define QM_RX_WIN_SSN_AUTO_ADVANCING 1 +/* 1: Indicate the packets falling behind to OS before the frame with SSN is + * received */ +#define QM_RX_INIT_FALL_BEHIND_PASS 1 +#define QM_TC_RESOURCE_EMPTY_COUNTER \ + 1 /* 1: Count times of TC resource empty happened */ + +/* Parameters */ +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) +/* p: Update queue lengths when p TX packets are enqueued */ +#define QM_INIT_TIME_TO_UPDATE_QUE_LEN 128 +#else +#define QM_INIT_TIME_TO_UPDATE_QUE_LEN \ + 256 /* p: Update queue lengths when p TX packets are enqueued */ +#endif +#define QM_INIT_TIME_TO_ADJUST_TC_RSC \ + 2 /* s: Adjust the TC resource every s updates of queue lengths */ +#define QM_QUE_LEN_MOVING_AVE_FACTOR 3 /* Factor for Que Len averaging */ + +#define QM_MIN_RESERVED_TC0_RESOURCE 0 +#define QM_MIN_RESERVED_TC1_RESOURCE 1 +#define QM_MIN_RESERVED_TC2_RESOURCE 0 +#define QM_MIN_RESERVED_TC3_RESOURCE 1 +#define QM_MIN_RESERVED_TC4_RESOURCE \ + 2 /* Resource for TC4 is not adjustable \ + */ +#define QM_MIN_RESERVED_TC5_RESOURCE 0 + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) +#define QM_MIN_RESERVED_TC6_RESOURCE 0 +#define QM_MIN_RESERVED_TC7_RESOURCE 0 +#define QM_MIN_RESERVED_TC8_RESOURCE 0 +#define QM_MIN_RESERVED_TC9_RESOURCE 0 +#define QM_MIN_RESERVED_TC10_RESOURCE 0 +#define QM_MIN_RESERVED_TC11_RESOURCE 0 +#define QM_MIN_RESERVED_TC12_RESOURCE 0 +#define QM_MIN_RESERVED_TC13_RESOURCE 0 +#define QM_MIN_RESERVED_TC14_RESOURCE 0 +#define QM_MIN_RESERVED_TC15_RESOURCE 0 +#define QM_MIN_RESERVED_TC16_RESOURCE 0 +#endif + +#define QM_GUARANTEED_TC0_RESOURCE 4 +#define QM_GUARANTEED_TC1_RESOURCE 4 +#define QM_GUARANTEED_TC2_RESOURCE 9 +#define QM_GUARANTEED_TC3_RESOURCE 11 +#define QM_GUARANTEED_TC4_RESOURCE 2 /* Resource for TC4 is not adjustable */ +#define QM_GUARANTEED_TC5_RESOURCE 4 + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) +#define QM_GUARANTEED_TC6_RESOURCE 4 +#define QM_GUARANTEED_TC7_RESOURCE 4 +#define QM_GUARANTEED_TC8_RESOURCE 9 +#define QM_GUARANTEED_TC9_RESOURCE 11 +#define QM_GUARANTEED_TC10_RESOURCE 0 +#define QM_GUARANTEED_TC11_RESOURCE 4 +#define QM_GUARANTEED_TC12_RESOURCE 4 +#define QM_GUARANTEED_TC13_RESOURCE 9 +#define QM_GUARANTEED_TC14_RESOURCE 11 +#define QM_GUARANTEED_TC15_RESOURCE 0 +#define QM_GUARANTEED_TC16_RESOURCE 11 +#endif + +#define QM_EXTRA_RESERVED_RESOURCE_WHEN_BUSY 0 + +#define QM_AVERAGE_TC_RESOURCE 6 + +#define QM_ACTIVE_TC_NUM TC_NUM + +#define QM_MGMT_QUEUED_THRESHOLD 6 +#define QM_CMD_RESERVED_THRESHOLD 4 +#define QM_MGMT_QUEUED_TIMEOUT 1000 /* ms */ + +#define QM_TEST_MODE 0 +#define QM_TEST_TRIGGER_TX_COUNT 50 +#define QM_TEST_STA_REC_DETERMINATION 0 +#define QM_TEST_STA_REC_DEACTIVATION 0 +#define QM_TEST_FAIR_FORWARDING 0 + +#define QM_DEBUG_COUNTER 0 + +/* Per-STA Queues: [0] AC0, [1] AC1, [2] AC2, [3] AC3 */ +/* Per-Type Queues: [0] BMCAST */ +#define NUM_OF_PER_STA_TX_QUEUES 4 +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) +/*Each wmm set has its own BCM_IDX tx queue*/ +#define NUM_OF_PER_TYPE_TX_QUEUES HIF_WMM_SET_NUM +#else +#define NUM_OF_PER_TYPE_TX_QUEUES 1 +#endif + +/* TX Queue Index */ +/* Per-Type */ +#define TX_QUEUE_INDEX_BMCAST 0 +#define TX_QUEUE_INDEX_NO_STA_REC 0 + +/* Per-STA */ +#define TX_QUEUE_INDEX_AC0 0 +#define TX_QUEUE_INDEX_AC1 1 +#define TX_QUEUE_INDEX_AC2 2 +#define TX_QUEUE_INDEX_AC3 3 +#define TX_QUEUE_INDEX_NON_QOS TX_QUEUE_INDEX_AC1 + +#define QM_DEFAULT_USER_PRIORITY 0 + +#define QM_STA_FORWARD_COUNT_UNLIMITED 0xFFFFFFFF +#define QM_FWD_PKT_QUE_THRESHOLD 128 + +/* 1 WMM-related */ +/* WMM FLAGS */ +#define WMM_FLAG_SUPPORT_WMM BIT(0) +#define WMM_FLAG_SUPPORT_WMMSA BIT(1) +#define WMM_FLAG_AC_PARAM_PRESENT BIT(2) +#define WMM_FLAG_SUPPORT_UAPSD BIT(3) + +/* WMM Admission Control Mandatory FLAGS */ +#define ACM_FLAG_ADM_NOT_REQUIRED 0 +#define ACM_FLAG_ADM_GRANTED BIT(0) +#define ACM_FLAG_ADM_REQUIRED BIT(1) + +/* WMM Power Saving FLAGS */ +#define AC_FLAG_TRIGGER_ENABLED BIT(1) +#define AC_FLAG_DELIVERY_ENABLED BIT(2) + +/* WMM-2.2.1 WMM Information Element */ +#define ELEM_MAX_LEN_WMM_INFO 7 + +/* WMM-2.2.2 WMM Parameter Element */ +#define ELEM_MAX_LEN_WMM_PARAM 24 + +/* WMM-2.2.1 WMM QoS Info field */ +#define WMM_QOS_INFO_PARAM_SET_CNT BITS(0, 3) /* Sent by AP */ +#define WMM_QOS_INFO_UAPSD BIT(7) + +#define WMM_QOS_INFO_VO_UAPSD BIT(0) /* Sent by non-AP STA */ +#define WMM_QOS_INFO_VI_UAPSD BIT(1) +#define WMM_QOS_INFO_BK_UAPSD BIT(2) +#define WMM_QOS_INFO_BE_UAPSD BIT(3) +#define WMM_QOS_INFO_MAX_SP_LEN_MASK BITS(5, 6) +#define WMM_QOS_INFO_MAX_SP_ALL 0 +#define WMM_QOS_INFO_MAX_SP_2 BIT(5) +#define WMM_QOS_INFO_MAX_SP_4 BIT(6) +#define WMM_QOS_INFO_MAX_SP_6 BITS(5, 6) + +/* -- definitions for Max SP length field */ +#define WMM_MAX_SP_LENGTH_ALL 0 +#define WMM_MAX_SP_LENGTH_2 2 +#define WMM_MAX_SP_LENGTH_4 4 +#define WMM_MAX_SP_LENGTH_6 6 + +/* WMM-2.2.2 WMM ACI/AIFSN field */ +/* -- subfields in the ACI/AIFSN field */ +#define WMM_ACIAIFSN_AIFSN BITS(0, 3) +#define WMM_ACIAIFSN_ACM BIT(4) +#define WMM_ACIAIFSN_ACI BITS(5, 6) +#define WMM_ACIAIFSN_ACI_OFFSET 5 + +/* -- definitions for ACI field */ +#define WMM_ACI_AC_BE 0 +#define WMM_ACI_AC_BK BIT(5) +#define WMM_ACI_AC_VI BIT(6) +#define WMM_ACI_AC_VO BITS(5, 6) + +#define WMM_ACI(_AC) (_AC << WMM_ACIAIFSN_ACI_OFFSET) + +/* -- definitions for ECWmin/ECWmax field */ +#define WMM_ECW_WMIN_MASK BITS(0, 3) +#define WMM_ECW_WMAX_MASK BITS(4, 7) +#define WMM_ECW_WMAX_OFFSET 4 + +#define TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME 0 /* Unit: 64 us */ + +#ifdef CFG_RX_BA_ENTRY_MISS_TIMEOUT +#define QM_RX_BA_ENTRY_MISS_TIMEOUT_MS (CFG_RX_BA_ENTRY_MISS_TIMEOUT) +#else +#define QM_RX_BA_ENTRY_MISS_TIMEOUT_MS (200) +#endif + +#define QM_DEQUE_PERCENT_VHT80_NSS1 75 /* BW80 NSS1 rate: MCS9 433 Mbps */ +#define QM_DEQUE_PERCENT_VHT40_NSS1 35 /* BW40 NSS1 Max rate: 200 Mbps */ +#define QM_DEQUE_PERCENT_VHT20_NSS1 15 /* BW20 NSS1 Max rate: 86.7Mbps */ + +#define QM_DEQUE_PERCENT_HT40_NSS1 \ + 25 /* BW40 NSS1 Max rate: 150 Mbps (MCS9 200Mbps)*/ +#define QM_DEQUE_PERCENT_HT20_NSS1 \ + 12 /* BW20 NSS1 Max rate: 72.2Mbps (MCS8 86.7Mbps)*/ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +enum { + QM_DBG_CNT_00 = 0, + QM_DBG_CNT_01, + QM_DBG_CNT_02, + QM_DBG_CNT_03, + QM_DBG_CNT_04, + QM_DBG_CNT_05, + QM_DBG_CNT_06, + QM_DBG_CNT_07, + QM_DBG_CNT_08, + QM_DBG_CNT_09, + QM_DBG_CNT_10, + QM_DBG_CNT_11, + QM_DBG_CNT_12, + QM_DBG_CNT_13, + QM_DBG_CNT_14, + QM_DBG_CNT_15, + QM_DBG_CNT_16, + QM_DBG_CNT_17, + QM_DBG_CNT_18, + QM_DBG_CNT_19, + QM_DBG_CNT_20, + QM_DBG_CNT_21, + QM_DBG_CNT_22, + QM_DBG_CNT_23, + QM_DBG_CNT_24, + QM_DBG_CNT_25, + QM_DBG_CNT_26, + QM_DBG_CNT_27, + QM_DBG_CNT_28, + QM_DBG_CNT_29, + QM_DBG_CNT_30, + QM_DBG_CNT_31, + QM_DBG_CNT_NUM +}; + +/* Used for MAC TX */ +typedef enum _ENUM_MAC_TX_QUEUE_INDEX_T { + MAC_TX_QUEUE_AC0_INDEX = 0, + MAC_TX_QUEUE_AC1_INDEX, + MAC_TX_QUEUE_AC2_INDEX, + MAC_TX_QUEUE_AC3_INDEX, + MAC_TX_QUEUE_AC4_INDEX, + MAC_TX_QUEUE_AC5_INDEX, + MAC_TX_QUEUE_AC6_INDEX, + MAC_TX_QUEUE_BCN_INDEX, + MAC_TX_QUEUE_BMC_INDEX, + MAC_TX_QUEUE_NUM +} ENUM_MAC_TX_QUEUE_INDEX_T; + +typedef struct _RX_BA_ENTRY_T { + u8 fgIsValid; + QUE_T rReOrderQue; + u16 u2WinStart; + u16 u2WinEnd; + u16 u2WinSize; + + /* For identifying the RX BA agreement */ + u8 ucStaRecIdx; + u8 ucTid; + + u8 fgIsWaitingForPktWithSsn; + + TIMER_T rReorderBubbleTimer; + u16 u2FirstBubbleSn; + u8 fgHasBubble; + + /* u8 ucTxBufferSize; */ + /* u8 fgIsAcConstrain; */ + /* u8 fgIsBaEnabled; */ +#if CFG_SUPPORT_RX_AMSDU + /* RX reorder for one MSDU in AMSDU issue */ + /* P_SW_RFB_T prMpduSwRfb; */ + u32 u4SeqNo; /* for statistic */ + u8 fgAmsduNeedLastFrame; /* for statistic */ + u8 u8LastAmsduSubIdx; + u8 fgIsAmsduDuplicated; +#endif + u8 fgFirstSnToWinStart; +} RX_BA_ENTRY_T, *P_RX_BA_ENTRY_T; + +typedef u32 (*PFN_DEQUEUE_FUNCTION)(IN P_ADAPTER_T prAdapter, + OUT P_QUE_T prQue, + IN u8 ucTC, + IN u32 u4CurrentQuota, + IN u32 u4TotalQuota); + +/* The mailbox message (could be used for Host-To-Device or Device-To-Host + * Mailbox) */ +typedef struct _MAILBOX_MSG_T { + u32 u4Msg[2]; /* [0]: D2HRM0R or H2DRM0R, [1]: D2HRM1R or H2DRM1R */ +} MAILBOX_MSG_T, *P_MAILBOX_MSG_T; + +/* Used for adaptively adjusting TC resources */ +typedef struct _TC_RESOURCE_CTRL_T { + /* TC0, TC1, TC2, TC3, TC5 */ + u32 au4AverageQueLen[TC_NUM - 1]; +} TC_RESOURCE_CTRL_T, *P_TC_RESOURCE_CTRL_T; + +typedef struct _QUE_MGT_T { /* Queue Management Control Info */ + /* Per-Type Queues: [0] BMCAST or UNKNOWN-STA packets */ + QUE_T arTxQueue[NUM_OF_PER_TYPE_TX_QUEUES]; + + /* Reordering Queue Parameters */ + RX_BA_ENTRY_T arRxBaTable[CFG_NUM_OF_RX_BA_AGREEMENTS]; + + /* Current number of activated RX BA agreements <= + * CFG_NUM_OF_RX_BA_AGREEMENTS */ + u8 ucRxBaCount; + +#if QM_TEST_MODE + u32 u4PktCount; + P_ADAPTER_T prAdapter; + +#if QM_TEST_FAIR_FORWARDING + u32 u4CurrentStaRecIndexToEnqueue; +#endif +#endif + +#if QM_FORWARDING_FAIRNESS + /* The current resource used count for a STA with respect to a TC index + */ +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + u32 au4ResourceUsedCount[TC_NUM]; +#else + u32 au4ResourceUsedCount[NUM_OF_PER_STA_TX_QUEUES]; +#endif + + /* The current serving STA with respect to a TC index */ +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + u8 au4HeadStaRecIndex[TC_NUM]; +#else + u32 au4HeadStaRecIndex[NUM_OF_PER_STA_TX_QUEUES]; +#endif + + /* For TC5 only */ + u8 fgGlobalQFirst; + u32 u4GlobalResourceUsedCount; +#endif + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + u32 au4AverageQueLen[TC_NUM]; + u32 au4CurrentTcResource[TC_NUM]; + u32 au4MinReservedTcResource[TC_NUM]; /* The minimum amount of resource + * no matter busy or idle */ + u32 au4GuaranteedTcResource[TC_NUM]; /* The minimum amount of resource + * when extremely busy */ + + u32 u4TimeToAdjustTcResource; + u32 u4TimeToUpdateQueLen; + + u32 u4QueLenMovingAverage; + u32 u4ExtraReservedTcResource; + u32 u4ResidualTcResource; + + /* Set to true if the last TC adjustment has not been completely applied + * (i.e., waiting more TX-Done events */ + /* to align the TC quotas to the TC resource assignment) */ + u8 fgTcResourcePostAnnealing; + +#if QM_FAST_TC_RESOURCE_CTRL + u8 fgTcResourceFastReaction; +#endif +#endif + +#if QM_DEBUG_COUNTER + u32 au4QmDebugCounters[QM_DBG_CNT_NUM]; +#endif + + u32 u4TxAllowedStaCount; + +#if QM_TC_RESOURCE_EMPTY_COUNTER + u32 au4QmTcResourceEmptyCounter[MAX_BSS_INDEX][TC_NUM]; +#endif + + u32 u4MaxForwardBufferCount; + + u32 rLastTxPktDumpTime; + u8 fgIsTxResrouceControlEn; +} QUE_MGT_T, *P_QUE_MGT_T; + +typedef struct _EVENT_RX_ADDBA_T { + /* Fields not present in the received ADDBA_REQ */ + u8 ucStaRecIdx; + + /* Fields that are present in the received ADDBA_REQ */ + u8 ucDialogToken; /* Dialog Token chosen by the sender */ + u16 u2BAParameterSet; /* BA policy, TID, buffer size */ + u16 u2BATimeoutValue; + u16 u2BAStartSeqCtrl; /* SSN */ +} EVENT_RX_ADDBA_T, *P_EVENT_RX_ADDBA_T; + +typedef struct _EVENT_RX_DELBA_T { + /* Fields not present in the received ADDBA_REQ */ + u8 ucStaRecIdx; + u8 ucTid; + u8 aucReserved[2]; +} EVENT_RX_DELBA_T, *P_EVENT_RX_DELBA_T; + +typedef struct _EVENT_BSS_ABSENCE_PRESENCE_T { + /* Event Body */ + u8 ucBssIndex; + u8 ucIsAbsent; + u8 ucBssFreeQuota; + u8 aucReserved[1]; +} EVENT_BSS_ABSENCE_PRESENCE_T, *P_EVENT_BSS_ABSENCE_PRESENCE_T; + +typedef struct _EVENT_STA_CHANGE_PS_MODE_T { + /* Event Body */ + u8 ucStaRecIdx; + u8 ucIsInPs; + u8 ucUpdateMode; + u8 ucFreeQuota; +} EVENT_STA_CHANGE_PS_MODE_T, *P_EVENT_STA_CHANGE_PS_MODE_T; + +/* The free quota is used by PS only now */ +/* The event may be used by per STA flow conttrol in general */ +typedef struct _EVENT_STA_UPDATE_FREE_QUOTA_T { + /* Event Body */ + u8 ucStaRecIdx; + u8 ucUpdateMode; + u8 ucFreeQuota; + u8 aucReserved[1]; +} EVENT_STA_UPDATE_FREE_QUOTA_T, *P_EVENT_STA_UPDATE_FREE_QUOTA_T; + +typedef struct _EVENT_CHECK_REORDER_BUBBLE_T { + /* Event Body */ + u8 ucStaRecIdx; + u8 ucTid; +} EVENT_CHECK_REORDER_BUBBLE_T, *P_EVENT_CHECK_REORDER_BUBBLE_T; + +/* WMM-2.2.1 WMM Information Element */ +typedef struct _IE_WMM_INFO_T { + u8 ucId; /* Element ID */ + u8 ucLength; /* Length */ + u8 aucOui[3]; /* OUI */ + u8 ucOuiType; /* OUI Type */ + u8 ucOuiSubtype; /* OUI Subtype */ + u8 ucVersion; /* Version */ + u8 ucQosInfo; /* QoS Info field */ + u8 ucDummy[3]; /* Dummy for pack */ +} IE_WMM_INFO_T, *P_IE_WMM_INFO_T; + +typedef struct _WMM_AC_PARAM_T { + u8 ucAciAifsn; + u8 ucEcw; + u16 u2TxopLimit; +} WMM_AC_PARAM_T, *P_WMM_AC_PARAM_T; + +/* WMM-2.2.2 WMM Parameter Element */ +typedef struct _IE_WMM_PARAM_T { + u8 ucId; /* Element ID */ + u8 ucLength; /* Length */ + + /* IE Body */ + u8 aucOui[3]; /* OUI */ + u8 ucOuiType; /* OUI Type */ + u8 ucOuiSubtype; /* OUI Subtype */ + u8 ucVersion; /* Version */ + + /* WMM IE Body */ + u8 ucQosInfo; /* QoS Info field */ + u8 ucReserved; + + /* AC Parameters */ + WMM_AC_PARAM_T arAcParam[4]; +} IE_WMM_PARAM_T, *P_IE_WMM_PARAM_T; + +typedef struct _IE_WMM_TSPEC_T { + u8 ucId; /* Element ID */ + u8 ucLength; /* Length */ + u8 aucOui[3]; /* OUI */ + u8 ucOuiType; /* OUI Type */ + u8 ucOuiSubtype; /* OUI Subtype */ + u8 ucVersion; /* Version */ + /* WMM TSPEC body */ + u8 aucTsInfo[3]; /* TS Info */ + u8 aucTspecBodyPart[1]; /* Note: Utilize PARAM_QOS_TSPEC to fill (memory + * copy) */ +} IE_WMM_TSPEC_T, *P_IE_WMM_TSPEC_T; + +typedef struct _IE_WMM_HDR_T { + u8 ucId; /* Element ID */ + u8 ucLength; /* Length */ + u8 aucOui[3]; /* OUI */ + u8 ucOuiType; /* OUI Type */ + u8 ucOuiSubtype; /* OUI Subtype */ + u8 ucVersion; /* Version */ + u8 aucBody[1]; /* IE body */ +} IE_WMM_HDR_T, *P_IE_WMM_HDR_T; + +typedef struct _AC_QUE_PARMS_T { + u16 u2CWmin; /*!< CWmin */ + u16 u2CWmax; /*!< CWmax */ + u16 u2TxopLimit; /*!< TXOP limit */ + u16 u2Aifsn; /*!< AIFSN */ + u8 ucGuradTime; /*!< GuardTime for STOP/FLUSH. */ + u8 ucIsACMSet; +} AC_QUE_PARMS_T, *P_AC_QUE_PARMS_T; + +/* WMM ACI (AC index) */ +typedef enum _ENUM_WMM_ACI_T { + WMM_AC_BE_INDEX = 0, + WMM_AC_BK_INDEX, + WMM_AC_VI_INDEX, + WMM_AC_VO_INDEX, + WMM_AC_INDEX_NUM +} ENUM_WMM_ACI_T, +*P_ENUM_WMM_ACI_T; + +/* Used for CMD Queue Operation */ +typedef enum _ENUM_FRAME_ACTION_T { + FRAME_ACTION_DROP_PKT = 0, + FRAME_ACTION_QUEUE_PKT, + FRAME_ACTION_TX_PKT, + FRAME_ACTION_NUM +} ENUM_FRAME_ACTION_T; + +typedef enum _ENUM_FRAME_TYPE_IN_CMD_Q_T { + FRAME_TYPE_802_1X = 0, + FRAME_TYPE_MMPDU, + FRAME_TYPE_NUM +} ENUM_FRAME_TYPE_IN_CMD_Q_T; + +typedef enum _ENUM_FREE_QUOTA_MODET_T { + FREE_QUOTA_UPDATE_MODE_INIT = 0, + FREE_QUOTA_UPDATE_MODE_OVERWRITE, + FREE_QUOTA_UPDATE_MODE_INCREASE, + FREE_QUOTA_UPDATE_MODE_DECREASE +} ENUM_FREE_QUOTA_MODET_T, +*P_ENUM_FREE_QUOTA_MODET_T; + +typedef struct _CMD_UPDATE_WMM_PARMS_T { + AC_QUE_PARMS_T arACQueParms[AC_NUM]; + u8 ucBssIndex; + u8 fgIsQBSS; + u8 ucWmmSet; + u8 aucReserved; +} CMD_UPDATE_WMM_PARMS_T, *P_CMD_UPDATE_WMM_PARMS_T; + +typedef struct _CMD_TX_AMPDU_T { + u8 fgEnable; + u8 aucReserved[3]; +} CMD_TX_AMPDU_T, *P_CMD_TX_AMPDU_T; + +typedef struct _CMD_ADDBA_REJECT { + u8 fgEnable; + u8 aucReserved[3]; +} CMD_ADDBA_REJECT_T, *P_CMD_ADDBA_REJECT_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define QM_TX_SET_NEXT_MSDU_INFO(_prMsduInfoPreceding, _prMsduInfoNext) \ + ((((_prMsduInfoPreceding)->rQueEntry).prNext) = \ + (P_QUE_ENTRY_T)(_prMsduInfoNext)) + +#define QM_TX_SET_NEXT_SW_RFB(_prSwRfbPreceding, _prSwRfbNext) \ + ((((_prSwRfbPreceding)->rQueEntry).prNext) = \ + (P_QUE_ENTRY_T)(_prSwRfbNext)) + +#define QM_TX_GET_NEXT_MSDU_INFO(_prMsduInfo) \ + ((P_MSDU_INFO_T)(((_prMsduInfo)->rQueEntry).prNext)) + +#define QM_RX_SET_NEXT_SW_RFB(_prSwRfbPreceding, _prSwRfbNext) \ + ((((_prSwRfbPreceding)->rQueEntry).prNext) = \ + (P_QUE_ENTRY_T)(_prSwRfbNext)) + +#define QM_RX_GET_NEXT_SW_RFB(_prSwRfb) \ + ((P_SW_RFB_T)(((_prSwRfb)->rQueEntry).prNext)) + +#define QM_GET_STA_REC_PTR_FROM_INDEX(_prAdapter, _ucIndex) \ + cnmGetStaRecByIndex(_prAdapter, _ucIndex) + +#define QM_TX_SET_MSDU_INFO_FOR_DATA_PACKET(_prMsduInfo, _ucTC, _ucPacketType, \ + _ucFormatID, _fgIs802_1x, \ + _fgIs802_11, _ucPsForwardingType) \ + { \ + ASSERT(_prMsduInfo); \ + (_prMsduInfo)->ucTC = (_ucTC); \ + (_prMsduInfo)->ucPacketType = (_ucPacketType); \ + (_prMsduInfo)->ucFormatID = (_ucFormatID); \ + (_prMsduInfo)->fgIs802_1x = (_fgIs802_1x); \ + (_prMsduInfo)->fgIs802_11 = (_fgIs802_11); \ + (_prMsduInfo)->ucPsForwardingType = (_ucPsForwardingType); \ + } + +#define QM_INIT_STA_REC(_prStaRec, _fgIsValid, _fgIsQoS, _pucMacAddr) \ + { \ + ASSERT(_prStaRec); \ + (_prStaRec)->fgIsValid = (_fgIsValid); \ + (_prStaRec)->fgIsQoS = (_fgIsQoS); \ + (_prStaRec)->fgIsInPS = false; \ + (_prStaRec)->ucPsSessionID = 0xFF; \ + COPY_MAC_ADDR((_prStaRec)->aucMacAddr, (_pucMacAddr)); \ + } + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL +#define QM_GET_TX_QUEUE_LEN(_prAdapter, _u4QueIdx) \ + (((_prAdapter)->rQM.au4AverageQueLen[(_u4QueIdx)] >> \ + (_prAdapter)->rQM.u4QueLenMovingAverage)) +#endif + +#define WMM_IE_OUI_TYPE(fp) (((P_IE_WMM_HDR_T)(fp))->ucOuiType) +#define WMM_IE_OUI_SUBTYPE(fp) (((P_IE_WMM_HDR_T)(fp))->ucOuiSubtype) +#define WMM_IE_OUI(fp) (((P_IE_WMM_HDR_T)(fp))->aucOui) + +#if QM_DEBUG_COUNTER +#define QM_DBG_CNT_INC(_prQM, _index) \ + { \ + (_prQM)->au4QmDebugCounters[(_index)]++; \ + } +#else +#define QM_DBG_CNT_INC(_prQM, _index) \ + { \ + } +#endif + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Queue Management and STA_REC Initialization */ +/*----------------------------------------------------------------------------*/ + +void qmInit(IN P_ADAPTER_T prAdapter, IN u8 isTxResrouceControlEn); + +#if QM_TEST_MODE +void qmTestCases(IN P_ADAPTER_T prAdapter); +#endif + +void qmActivateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +void qmDeactivateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +void qmUpdateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); + +/*----------------------------------------------------------------------------*/ +/* TX-Related Queue Management */ +/*----------------------------------------------------------------------------*/ + +P_MSDU_INFO_T qmFlushTxQueues(IN P_ADAPTER_T prAdapter); + +P_MSDU_INFO_T qmFlushStaTxQueues(IN P_ADAPTER_T prAdapter, IN u32 u4StaRecIdx); + +P_MSDU_INFO_T qmEnqueueTxPackets(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead); + +P_MSDU_INFO_T qmDequeueTxPackets(IN P_ADAPTER_T prAdapter, + IN P_TX_TCQ_STATUS_T prTcqStatus); + +P_MSDU_INFO_T qmDequeueTxPacketsMthread(IN P_ADAPTER_T prAdapter, + IN P_TX_TCQ_STATUS_T prTcqStatus); + +u8 qmAdjustTcQuotasMthread(IN P_ADAPTER_T prAdapter, + OUT P_TX_TCQ_ADJUST_T prTcqAdjust, + IN P_TX_TCQ_STATUS_T prTcqStatus); + +u8 qmAdjustTcQuotas(IN P_ADAPTER_T prAdapter, + OUT P_TX_TCQ_ADJUST_T prTcqAdjust, + IN P_TX_TCQ_STATUS_T prTcqStatus); + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL +void qmReassignTcResource(IN P_ADAPTER_T prAdapter); + +void qmUpdateAverageTxQueLen(IN P_ADAPTER_T prAdapter); + +void qmDoAdaptiveTcResourceCtrl(IN P_ADAPTER_T prAdapter); + +void qmCheckForFastTcResourceCtrl(IN P_ADAPTER_T prAdapter, IN u8 ucTc); + +#endif + +void qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +u32 qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter, + OUT P_QUE_T prQue, + IN u8 ucTC, + IN u32 u4CurrentQuota, + IN u32 u4TotalQuota); + +void qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter, + OUT P_QUE_T prQue, + IN u8 ucTC, + IN u32 u4CurrentQuota, + IN u32 u4TotalQuota); + +u32 qmDequeueTxPacketsFromGlobalQueue(IN P_ADAPTER_T prAdapter, + OUT P_QUE_T prQue, + IN u8 ucTC, + IN u32 u4CurrentQuota, + IN u32 u4TotalQuota); + +void qmSetStaRecTxAllowed(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN u8 fgIsTxAllowed); + +u32 gmGetDequeueQuota(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_BSS_INFO_T prBssInfo, + IN u32 u4TotalQuota); + +/*----------------------------------------------------------------------------*/ +/* RX-Related Queue Management */ +/*----------------------------------------------------------------------------*/ + +void qmInitRxQueues(IN P_ADAPTER_T prAdapter); + +P_SW_RFB_T qmFlushRxQueues(IN P_ADAPTER_T prAdapter); + +P_QUE_T qmDetermineStaTxQueue(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + OUT u8 *pucTC); + +void qmSetTxPacketDescTemplate(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +P_SW_RFB_T qmHandleRxPackets(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfbListHead); + +void qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT P_QUE_T prReturnedQue); + +void qmProcessBarFrame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT P_QUE_T prReturnedQue); + +void qmInsertReorderPkt(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue); + +void qmInsertFallWithinReorderPkt(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue); + +void qmInsertFallAheadReorderPkt(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue); + +void qmPopOutReorderPkt(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT P_QUE_T prReturnedQue, + IN ENUM_RX_STATISTIC_COUNTER_T eRxCounter); + +void qmPopOutDueToFallWithin(IN P_ADAPTER_T prAdapter, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue); + +void qmPopOutDueToFallAhead(IN P_ADAPTER_T prAdapter, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue); + +void qmHandleReorderBubbleTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr); + +void qmHandleEventCheckReorderBubble(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); + +void qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg); + +u8 qmCompareSnIsLessThan(IN u32 u4SnLess, IN u32 u4SnGreater); + +void qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); + +void qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); + +P_RX_BA_ENTRY_T qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter, + IN u8 ucStaRecIdx, + IN u8 ucTid); + +u8 qmAddRxBaEntry(IN P_ADAPTER_T prAdapter, + IN u8 ucStaRecIdx, + IN u8 ucTid, + IN u16 u2WinStart, + IN u16 u2WinSize); + +void qmDelRxBaEntry(IN P_ADAPTER_T prAdapter, + IN u8 ucStaRecIdx, + IN u8 ucTid, + IN u8 fgFlushToHost); + +void mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN u8 *pucIE, + IN u16 u2IELength); + +void mqmProcessBcn(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN u8 *pucIE, + IN u16 u2IELength); + +u8 mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN u8 *pucIE, + IN u16 u2IELength, + IN u8 fgForceOverride); + +u8 mqmCompareEdcaParameters(IN P_IE_WMM_PARAM_T prIeWmmParam, + IN P_BSS_INFO_T prBssInfo); + +void mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam, + IN u32 u4AcOffset, + OUT P_AC_QUE_PARMS_T prAcQueParams); + +void mqmProcessScanResult(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prScanResult, + OUT P_STA_RECORD_T prStaRec); + +u32 mqmFillWmmInfoIE(u8 *pucOutBuf, + u8 fgSupportUAPSD, + u8 ucBmpDeliveryAC, + u8 ucBmpTriggerAC, + u8 ucUapsdSp); + +u32 mqmGenerateWmmInfoIEByStaRec(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_STA_RECORD_T prStaRec, + u8 *pucOutBuf); + +void mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +void mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +#if CFG_SUPPORT_TDLS + +u32 mqmGenerateWmmParamIEByParam(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + u8 *pOutBuf); +#endif + +ENUM_FRAME_ACTION_T qmGetFrameAction(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN u8 ucStaRecIdx, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType, + IN u16 u2FrameLength); + +void qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); + +void qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); + +void mqmProcessAssocReq(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN u8 *pucIE, + IN u16 u2IELength); + +void qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); + +void qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN u8 ucUpdateMode, + IN u8 ucFreeQuota); + +void qmFreeAllByBssIdx(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex); + +u32 qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter); + +u32 qmDumpQueueStatus(IN P_ADAPTER_T prAdapter, IN u8 *pucBuf, IN u32 u4MaxLen); + +void qmResetTcControlResource(IN P_ADAPTER_T prAdapter); + +#if (CFG_SUPPORT_REPLAY_DETECTION || CFG_SUPPORT_FRAG_ATTACK_DETECTION) +#define CCMPTSCPNNUM 6 +u8 qmRxPNtoU64(u8 *pucPN, u8 uPNNum, u64 *pu64Rets); +#endif + +#if CFG_SUPPORT_REPLAY_DETECTION +u8 qmHandleRxReplay(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb); +u8 qmRxDetectReplay(u8 *pucPNS, u8 *pucPNT); +#endif + +#if CFG_SUPPORT_FAKE_EAPOL_DETECTION +u8 qmDetectRxInvalidEAPOL(P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); +#endif + +#if CFG_SUPPORT_AMSDU_ATTACK_DETECTION +u8 qmAmsduAttackDetection(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); +#endif + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT +void qmFuncChangeBmcTcIdx(u8 ucTc); +u8 qmFuncGetBmcTcIdx(u8 ucWmmIdx); +#endif + +P_SW_RFB_T qmFlushStaRxQueue(IN P_ADAPTER_T prAdapter, IN u32 u4StaRecIdx, + IN u32 u4Tid); + +P_STA_RECORD_T qmDetermineStaToBeDequeued(IN P_ADAPTER_T prAdapter, + IN u32 u4StartStaRecIndex); + +P_QUE_T qmDequeueStaTxPackets(IN P_ADAPTER_T prAdapter); + +void qmAllocateResidualTcResource(IN P_ADAPTER_T prAdapter, + IN s32 *ai4TcResDemand, + IN u32 *pu4ResidualResource, + IN u32 *pu4ShareCount); + +void qmCalAveQLen(P_QUE_MGT_T prQM, u8 u4Tc, u32 u4CurrQueLen); + +void mqmParseAssocReqWmmIe(IN P_ADAPTER_T prAdapter, IN u8 *pucIE, + IN P_STA_RECORD_T prStaRec); + +void mqmParseAssocRspWmmIe(IN u8 *pucIE, IN P_STA_RECORD_T prStaRec); + +u8 mqmUpdateEdcaParameters(IN P_BSS_INFO_T prBssInfo, IN u8 *pucIE, + IN u8 fgForceOverride); + +u8 isProbeResponse(IN P_MSDU_INFO_T prMgmtTxMsdu); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#if QM_TEST_MODE +extern QUE_MGT_T g_rQM; +#endif +extern const u8 aucTid2ACI[TX_DESC_TID_NUM]; +extern u8 arNetwork2TcResource[HW_BSSID_NUM + 1][NET_TC_NUM]; + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/reg.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/reg.h new file mode 100644 index 00000000000000..fa99fe89ff750b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/reg.h @@ -0,0 +1,649 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "reg.h" + * \brief The common register definition of MT6630 + * + * N/A + */ + +#ifndef _REG_H +#define _REG_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +extern struct hif_driver_data driver_data_mt6632; +extern struct hif_driver_data driver_data_mt7668; + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* 1 MT6630 MCR Definition */ + +/* 2 Host Interface */ + +/* #define TOP_CFG_BASE 0x0000 */ +#define TOP_CFG_BASE 0x80020000 +#define TOP_RGU_BASE 0x81020000 +#define TOP_CFG_AON_base 0x81021000 +#define MCU_CFG_BASE 0x80000000 + +#define TOP_HVR (TOP_CFG_BASE + 0x1000) +#define HW_VER_MASK (0xffff) +#define GET_HW_VER(p) (((p) & HW_VER_MASK)) +#define RESC_CID_MASK (0xf << 28) +#define GET_RESC_CID(p) (((p) & RESC_CID_MASK) >> 28) + +#define TOP_FVR (TOP_CFG_BASE + 0x1004) +#define FW_VER_MASK (0xff) +#define GET_FW_VER(p) (((p) & FW_VER_MASK)) + +#define TOP_HCR (TOP_CFG_BASE + 0x1008) +#define HW_CODE_MASK (0xffff) +#define GET_HW_CODE(p) (((p) & HW_CODE_MASK)) + +#define STRAP_STA (TOP_CFG_BASE + 0x1010) +#define XTAL_SEL_MASK (0x3) +#define GET_XTAL_SEL(p) (((p) & XTAL_SEL_MASK)) +#define EEPROM_SEL (1 << 2) +#define GET_EEPROM_SEL(p) (((p) & EEPROM_SEL) >> 2) +#define CO_CLOCK_SEL (1 << 8) +#define GET_CO_CLOCK_SEL(p) (((p) & CO_CLOCK_SEL) >> 8) +#define ONE_ANT (1 << 24) +#define GET_ONE_ANT(p) (((p) & ONE_ANT) >> 24) +#define USB_MODE (1 << 25) +#define GET_USB_MODE(p) (((p) & USB_MODE) >> 25) + +#define TOP_MISC2 (TOP_CFG_BASE + 0x1134) + +#define TOP_CKGEN2_CR_PMIC_CK_MANUAL (TOP_CFG_AON_base + 0x00000108) +#define TOP_CKGEN2_CR_PMIC_CK_MANUAL_MASK 0x00080000 + +#define MTK_CHIP_REV 0x00006632 + +#define WIFI_RGU_SW_SYNC0 (TOP_RGU_BASE + 0x1250) +#define WIFI_RGU_SYNC0_RDY_OFFSET (0) +#define MCU_CFG_PCIE_REMAP1 (MCU_CFG_BASE + 0x0500) +#define PCIE_REMAP1_OFFSET (18) +#define PCIE_REMAP1_MASK (BITS(18, 31)) +#define PCIE_REMAP1_BUS_ADDR (0x40000) +#define MCU_CFG_PCIE_REMAP2 (MCU_CFG_BASE + 0x0504) +#define PCIE_REMAP2_OFFSET (19) +#define PCIE_REMAP2_MASK (BITS(19, 31)) +#define PCIE_REMAP2_BUS_ADDR (0x80000) + +/* UMAC Register */ +#define UMAC_PLE_CR_CFG_BASE_ADDR 0x82060000 +#define UMAC_PSE_CR_CFG_BASE_ADDR 0x82068000 + +#define UMAC_PSE_PLE_CR_ADDR_DIFF \ + (UMAC_PSE_CR_CFG_BASE_ADDR - UMAC_PLE_CR_CFG_BASE_ADDR) +#define UMAC_PSE_CR_BITMAP_OFFSET 15 +#define UMAC_PSE_PLE_ADDR_DIFF_MAR(_x) (_x << UMAC_PSE_CR_BITMAP_OFFSET) + +#define UMAC_PLE_BASE_ADDRESS (0xa << 28) + +#define UMAC_PSE_BASE_ADDRESS (0xb << 28) + +#define UMAC_FID_SHIFT_16_BIT_VM_MAP 16 + +#define UMAC_BASE(_x) \ + (UMAC_PLE_CR_CFG_BASE_ADDR | (_x << UMAC_PSE_CR_BITMAP_OFFSET)) + +#define UMAC_RESET(_x) (UMAC_BASE(_x) + 0x00000000) + +#define UMAC_INT_CR4_EN_MASK(_x) (UMAC_BASE(_x) + 0x00000004) +#define UMAC_INT_CR4_STS(_x) (UMAC_BASE(_x) + 0x00000008) +#define UMAC_INT_CR4_ERR_RES(_x) (UMAC_BASE(_x) + 0x0000000C) +#define UMAC_INT_CR4_ERR_MASK(_x) (UMAC_BASE(_x) + 0x00000010) + +#define UMAC_PBUF_CTRL(_x) (UMAC_BASE(_x) + 0x00000014) + +#define UMAC_CHIP_ID_VER(_x) (UMAC_BASE(_x) + 0x00000018) + +#define UMAC_TIMER_CNF(_x) (UMAC_BASE(_x) + 0x0000001C) + +#define UMAC_INT_N9_EN_MASK(_x) (UMAC_BASE(_x) + 0x00000020) +#define UMAC_INT_N9_STS(_x) (UMAC_BASE(_x) + 0x00000024) +#define UMAC_INT_N9_ERR_STS(_x) (UMAC_BASE(_x) + 0x00000028) +#define UMAC_INT_N9_ERR_MASK(_x) (UMAC_BASE(_x) + 0x0000002C) +#define UMAC_IGNORE_BUSY_EN_MASK(_x) (UMAC_BASE(_x) + 0x0000038C) + +#define UMAC_RELEASE_CTRL(_x) (UMAC_BASE(_x) + 0x00000030) + +#define UMAC_HIF_REPROT(_x) (UMAC_BASE(_x) + 0x00000034) + +#define UMAC_C_GET_FID_0(_x) (UMAC_BASE(_x) + 0x00000040) +#define UMAC_C_GET_FID_1(_x) (UMAC_BASE(_x) + 0x00000044) + +#define UMAC_C_EN_QUEUE_0(_x) (UMAC_BASE(_x) + 0x00000060) +#define UMAC_C_EN_QUEUE_1(_x) (UMAC_BASE(_x) + 0x00000064) +#define UMAC_C_EN_QUEUE_2(_x) (UMAC_BASE(_x) + 0x00000068) + +#define UMAC_C_DE_QUEUE_0(_x) (UMAC_BASE(_x) + 0x00000080) +#define UMAC_C_DE_QUEUE_1(_x) (UMAC_BASE(_x) + 0x00000084) +#define UMAC_C_DE_QUEUE_2(_x) (UMAC_BASE(_x) + 0x00000088) +#define UMAC_C_DE_QUEUE_3(_x) (UMAC_BASE(_x) + 0x0000008C) + +#define UMAC_ALLOCATE_0(_x) (UMAC_BASE(_x) + 0x000000A0) +#define UMAC_ALLOCATE_1(_x) (UMAC_BASE(_x) + 0x000000A4) +#define UMAC_ALLOCATE_2(_x) (UMAC_BASE(_x) + 0x000000A8) + +#define UMAC_QUEUE_EMPTY(_x) (UMAC_BASE(_x) + 0x000000B0) + +/* 0x820680B4 QUEUE_EMPTY_MAS + * Queue empty status mask register, 7615 E3 eco + * item only PSE with this setting, but ple + */ + +#define UMAC_QUEUE_EMPTY_MASK (UMAC_BASE(UMAC_PSE_CFG_POOL_INDEX) + \ + 0x000000B4) + +#define UMAC_TO_CR4_INT(_x) (UMAC_BASE(_x) + 0x000000e0) +#define UMAC_TO_N9_INT(_x) (UMAC_BASE(_x) + 0x000000f0) + +#define UMAC_FREEPG_CNT(_x) (UMAC_BASE(_x) + 0x00000100) + +#define UMAC_FREEPG_HEAD_TAIL(_x) (UMAC_BASE(_x) + 0x00000104) + +#define UMAC_PG_HIF0_GROUP(_x) (UMAC_BASE(_x) + 0x00000110) +#define UMAC_HIF0_PG_INFO(_x) (UMAC_BASE(_x) + 0x00000114) + +#define UMAC_PG_HIF1_GROUP(_x) (UMAC_BASE(_x) + 0x00000118) +#define UMAC_HIF1_PG_INFO(_x) (UMAC_BASE(_x) + 0x0000011C) + +#define UMAC_PG_CPU_GROUP(_x) (UMAC_BASE(_x) + 0x00000150) +#define UMAC_CPU_PG_INFO(_x) (UMAC_BASE(_x) + 0x00000154) + +#define UMAC_PG_LMAC0_GROUP(_x) (UMAC_BASE(_x) + 0x00000170) +#define UMAC_LMAC0_PG_INFO(_x) (UMAC_BASE(_x) + 0x00000174) + +#define UMAC_PG_LMAC1_GROUP(_x) (UMAC_BASE(_x) + 0x00000178) +#define UMAC_LMAC1_PG_INFO(_x) (UMAC_BASE(_x) + 0x0000017C) + +#define UMAC_PG_LMAC2_GROUP(_x) (UMAC_BASE(_x) + 0x00000180) +#define UMAC_LMAC2_PG_INFO(_x) (UMAC_BASE(_x) + 0x00000184) + +#define UMAC_PG_PLE_GROUP(_x) (UMAC_BASE(_x) + 0x00000190) +#define UMAC_PLE_PG_INFO(_x) (UMAC_BASE(_x) + 0x00000194) + +#define UMAC_RL_BUF_CTRL_0(_x) (UMAC_BASE(_x) + 0x000001A0) +#define UMAC_RL_BUF_CTRL_1(_x) (UMAC_BASE(_x) + 0x000001A4) + +#define UMAC_FL_QUE_CTRL_0(_x) (UMAC_BASE(_x) + 0x000001B0) +#define UMAC_FL_QUE_CTRL_1(_x) (UMAC_BASE(_x) + 0x000001B4) +#define UMAC_FL_QUE_CTRL_2(_x) (UMAC_BASE(_x) + 0x000001B8) +#define UMAC_FL_QUE_CTRL_3(_x) (UMAC_BASE(_x) + 0x000001BC) + +#define UMAC_HIF_ENQ_PKT_NUM(_x) (UMAC_BASE(_x) + 0x000001F0) +#define UMAC_CPU_ENQ_PKT_NUM(_x) (UMAC_BASE(_x) + 0x000001F4) +#define UMAC_RLS_MSDU_PKT_NUM(_x) (UMAC_BASE(_x) + 0x000001F8) +#define UMAC_HOST_REPORT_NUM(_x) (UMAC_BASE(_x) + 0x000001FC) + +#define UMAC_PL_QUE_CTRL_0(_x) (UMAC_BASE(_x) + 0x000001C0) + +#define UMAC_TP_HIF_EN(_x) (UMAC_BASE(_x) + 0x00000200) + +#define UMAC_TP_HIF_Q_CTRL0(_x) (UMAC_BASE(_x) + 0x00000204) +#define UMAC_TP_HIF_Q_CTRL1(_x) (UMAC_BASE(_x) + 0x00000208) +#define UMAC_TP_HIF_Q_CTRL2(_x) (UMAC_BASE(_x) + 0x0000020C) + +#define UMAC_TP_HIF_ALLOC0(_x) (UMAC_BASE(_x) + 0x00000210) +#define UMAC_TP_HIF_ALLOC1(_x) (UMAC_BASE(_x) + 0x00000214) + +#define UMAC_TP_HIF_OPER0(_x) (UMAC_BASE(_x) + 0x00000218) +#define UMAC_TP_HIF_OPER1(_x) (UMAC_BASE(_x) + 0x0000021C) + +#define UMAC_TP_LMAC_EN(_x) (UMAC_BASE(_x) + 0x00000220) + +#define UMAC_TP_LMAC_Q_CTRL0(_x) (UMAC_BASE(_x) + 0x00000224) +#define UMAC_TP_LMAC_Q_CTRL1(_x) (UMAC_BASE(_x) + 0x00000228) +#define UMAC_TP_LMAC_Q_CTRL2(_x) (UMAC_BASE(_x) + 0x0000022C) + +#define UMAC_TP_LMAC_ALLOC0(_x) (UMAC_BASE(_x) + 0x00000230) +#define UMAC_TP_LMAC_ALLOC1(_x) (UMAC_BASE(_x) + 0x00000234) + +#define UMAC_TP_LMAC_OPER0(_x) (UMAC_BASE(_x) + 0x00000238) +#define UMAC_TP_LMAC_OPER1(_x) (UMAC_BASE(_x) + 0x0000023C) + +#define UMAC_STATE_IDLE_CTL(_x) (UMAC_BASE(_x) + 0x0000024C) + +#define UMAC_DIS_STA_MAP0(_x) (UMAC_BASE(_x) + 0x00000260) +#define UMAC_DIS_STA_MAP1(_x) (UMAC_BASE(_x) + 0x00000264) +#define UMAC_DIS_STA_MAP2(_x) (UMAC_BASE(_x) + 0x00000268) +#define UMAC_DIS_STA_MAP3(_x) (UMAC_BASE(_x) + 0x0000026c) + +#define UMAC_AC0_QUEUE_EMPTY0(_x) (UMAC_BASE(_x) + 0x00000300) +#define UMAC_AC0_QUEUE_EMPTY1(_x) (UMAC_BASE(_x) + 0x00000304) +#define UMAC_AC0_QUEUE_EMPTY2(_x) (UMAC_BASE(_x) + 0x00000308) +#define UMAC_AC0_QUEUE_EMPTY3(_x) (UMAC_BASE(_x) + 0x0000030C) + +#define UMAC_AC1_QUEUE_EMPTY0(_x) (UMAC_BASE(_x) + 0x00000310) +#define UMAC_AC1_QUEUE_EMPTY1(_x) (UMAC_BASE(_x) + 0x00000314) +#define UMAC_AC1_QUEUE_EMPTY2(_x) (UMAC_BASE(_x) + 0x00000318) +#define UMAC_AC1_QUEUE_EMPTY3(_x) (UMAC_BASE(_x) + 0x0000031C) + +#define UMAC_AC2_QUEUE_EMPTY0(_x) (UMAC_BASE(_x) + 0x00000320) +#define UMAC_AC2_QUEUE_EMPTY1(_x) (UMAC_BASE(_x) + 0x00000324) +#define UMAC_AC2_QUEUE_EMPTY2(_x) (UMAC_BASE(_x) + 0x00000328) +#define UMAC_AC2_QUEUE_EMPTY3(_x) (UMAC_BASE(_x) + 0x0000032C) + +#define UMAC_AC3_QUEUE_EMPTY0(_x) (UMAC_BASE(_x) + 0x00000330) +#define UMAC_AC3_QUEUE_EMPTY1(_x) (UMAC_BASE(_x) + 0x00000334) +#define UMAC_AC3_QUEUE_EMPTY2(_x) (UMAC_BASE(_x) + 0x00000338) +#define UMAC_AC3_QUEUE_EMPTY3(_x) (UMAC_BASE(_x) + 0x0000033C) + +#define UMAC_QUEUE_EMPTY_MASK (UMAC_BASE(UMAC_PSE_CFG_POOL_INDEX) + \ + 0x000000B4) + +/* BSS PS INT */ +#define UMAC_N9_BSS_PS_INT_EN (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x000000F4) +#define UMAC_N9_BSS_PS_INT_STS (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x000000F8) + +/* CR for VoW and BW Ctrl */ + +#define UMAC_DRR_TABLE_CTRL0 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000388) + +#define UMAC_DRR_TABLE_WDATA0 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000340) +#define UMAC_DRR_TABLE_WDATA1 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000344) +#define UMAC_DRR_TABLE_WDATA2 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000348) +#define UMAC_DRR_TABLE_WDATA3 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x0000034C) + +#define UMAC_DRR_TABLE_RDATA0 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000350) +#define UMAC_DRR_TABLE_RDATA1 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000354) +#define UMAC_DRR_TABLE_RDATA2 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000358) +#define UMAC_DRR_TABLE_RDATA3 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x0000035C) + +#define UMAC_STATION_PAUSE_0 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000360) +#define UMAC_STATION_PAUSE_1 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000364) +#define UMAC_STATION_PAUSE_2 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000368) +#define UMAC_STATION_PAUSE_3 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x0000036C) +#define UMAC_VOW_ENABLE (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000370) +#define UMAC_AIR_TIME_DRR_SIZE (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000374) +#define UMAC_CHECK_TIME_TOKEN (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000378) +#define UMAC_CHECK_LENGTH_TOKEN \ + (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + 0x0000037C) +#define UMAC_WDRR0 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000380) +#define UMAC_WDRR1 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x00000384) + +#define UMAC_VOW_CTRL1 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x0000038C) + +#define UMAC_VOW_DBG_MUX (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x000003A0) +#define UMAC_AIRTIME_DBG_INFO0 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x000003A4) +#define UMAC_AIRTIME_DBG_INFO1 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x000003A8) + +#define UMAC_BW_DBG_INFO (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x000003AC) + +#define UMAC_BW_WDRR0 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x000003B0) +#define UMAC_BW_WDRR1 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x000003B4) +#define UMAC_BW_WDRR2 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x000003B8) +#define UMAC_BW_WDRR3 (UMAC_BASE(UMAC_PLE_CFG_POOL_INDEX) + \ + 0x000003BC) +/* UMAC Register */ + +#define WIFI_CFG_SW_SYNC0 0 +#define WIFI_CFG_SYNC0_RDY_OFFSET 0 + +/* 4 CHIP ID Register */ +#define MCR_WCIR 0x0000 + +/* 4 HIF Low Power Control Register */ +#define MCR_WHLPCR 0x0004 + +/* 4 Control Status Register */ +#define MCR_WSDIOCSR 0x0008 + +/* 4 HIF Control Register */ +#define MCR_WHCR 0x000C + +/* 4 HIF Interrupt Status Register */ +#define MCR_WHISR 0x0010 + +/* 4 HIF Interrupt Enable Register */ +#define MCR_WHIER 0x0014 + +/* 4 Abnormal Status Register */ +#define MCR_WASR 0x0020 + +/* 4 WLAN Software Interrupt Control Register */ +#define MCR_WSICR 0x0024 + +/* 4 WLAN TX Data Register 1 */ +#define MCR_WTDR1 0x0034 + +/* 4 WLAN RX Data Register 0 */ +#define MCR_WRDR0 0x0050 + +/* 4 WLAN RX Data Register 1 */ +#define MCR_WRDR1 0x0054 + +/* 4 Host to Device Send Mailbox 0 Register */ +#define MCR_H2DSM0R 0x0070 + +/* 4 Host to Device Send Mailbox 1 Register */ +#define MCR_H2DSM1R 0x0074 + +/* 4 Device to Host Receive Mailbox 0 Register */ +#define MCR_D2HRM0R 0x0078 + +/* 4 Device to Host Receive Mailbox 1 Register */ +#define MCR_D2HRM1R 0x007c + +/* 4 WLAN RX Packet Length Register */ +#define MCR_WRPLR 0x0090 + +/* 4 Test Mode Data Port */ +#define MCR_WTMDR 0x00b0 + +/* 4 Test Mode Control Register */ +#define MCR_WTMCR 0x00b4 + +/* 4 Test Mode Data Pattern Control Register #0 */ +#define MCR_WTMDPCR0 0x00b8 + +/* 4 Test Mode Data Pattern Control Register #1 */ +#define MCR_WTMDPCR1 0x00bc + +/* 4 WLAN Packet Length Report Control Register */ +#define MCR_WPLRCR 0x00d4 + +/* 4 WLAN Snapshot Register */ +#define MCR_WSR 0x00D8 + +/* 4 Clock Pad Macro IO Control Register */ +#define MCR_CLKIOCR 0x0100 + +/* 4 Command Pad Macro IO Control Register */ +#define MCR_CMDIOCR 0x0104 + +/* 4 Data 0 Pad Macro IO Control Register */ +#define MCR_DAT0IOCR 0x0108 + +/* 4 Data 1 Pad Macro IO Control Register */ +#define MCR_DAT1IOCR 0x010C + +/* 4 Data 2 Pad Macro IO Control Register */ +#define MCR_DAT2IOCR 0x0110 + +/* 4 Data 3 Pad Macro IO Control Register */ +#define MCR_DAT3IOCR 0x0114 + +/* 4 Clock Pad Macro Delay Chain Control Register */ +#define MCR_CLKDLYCR 0x0118 + +/* 4 Command Pad Macro Delay Chain Control Register */ +#define MCR_CMDDLYCR 0x011C + +/* 4 SDIO Output Data Delay Chain Control Register */ +#define MCR_ODATDLYCR 0x0120 + +/* 4 SDIO Input Data Delay Chain Control Register 1 */ +#define MCR_IDATDLYCR1 0x0124 + +/* 4 SDIO Input Data Delay Chain Control Register 2 */ +#define MCR_IDATDLYCR2 0x0128 + +/* 4 SDIO Input Data Latch Time Control Register */ +#define MCR_ILCHCR 0x012C + +/* 4 WLAN TXQ Count Register 0 */ +#define MCR_WTQCR0 0x0130 + +/* 4 WLAN TXQ Count Register 1 */ +#define MCR_WTQCR1 0x0134 + +/* 4 WLAN TXQ Count Register 2 */ +#define MCR_WTQCR2 0x0138 + +/* 4 WLAN TXQ Count Register 3 */ +#define MCR_WTQCR3 0x013C + +/* 4 WLAN TXQ Count Register 4 */ +#define MCR_WTQCR4 0x0140 + +/* 4 WLAN TXQ Count Register 5 */ +#define MCR_WTQCR5 0x0144 + +/* 4 WLAN TXQ Count Register 6 */ +#define MCR_WTQCR6 0x0148 + +/* 4 WLAN TXQ Count Register 7 */ +#define MCR_WTQCR7 0x014C + +/* WLAN/Common PC value Debug registre */ +#define MCR_SWPCDBGR 0x0154 + +/* #if CFG_SDIO_INTR_ENHANCE */ +typedef struct _ENHANCE_MODE_DATA_STRUCT_T { + u32 u4WHISR; + union { + struct { + u16 u2TQ0Cnt; + u16 u2TQ1Cnt; + u16 u2TQ2Cnt; + u16 u2TQ3Cnt; + u16 u2TQ4Cnt; + u16 u2TQ5Cnt; + u16 u2TQ6Cnt; + u16 u2TQ7Cnt; + u16 u2TQ8Cnt; + u16 u2TQ9Cnt; + u16 u2TQ10Cnt; + u16 u2TQ11Cnt; + u16 u2TQ12Cnt; + u16 u2TQ13Cnt; + u16 u2TQ14Cnt; + u16 u2TQ15Cnt; + } u; + u32 au4WTSR[8]; + } rTxInfo; + union { + struct { + u16 u2NumValidRx0Len; + u16 u2NumValidRx1Len; + u16 au2Rx0Len[16]; + u16 au2Rx1Len[16]; + } u; + u32 au4RxStatusRaw[17]; + } rRxInfo; + u32 u4RcvMailbox0; + u32 u4RcvMailbox1; +} ENHANCE_MODE_DATA_STRUCT_T, *P_ENHANCE_MODE_DATA_STRUCT_T; +/* #endif */ /* ENHANCE_MODE_DATA_STRUCT_T */ + +/* 2 Definition in each register */ +/* 3 WCIR 0x0000 */ +#define WCIR_WLAN_READY BIT(21) +#define WCIR_POR_INDICATOR BIT(20) +#define WCIR_REVISION_ID BITS(16, 19) +#define WCIR_CHIP_ID BITS(0, 15) + +#define MTK_CHIP_REV 0x00006632 +#define MTK_CHIP_MP_REVERSION_ID 0x0 + +/* 3 WHLPCR 0x0004 */ +#define WHLPCR_FW_OWN_REQ_CLR BIT(9) +#define WHLPCR_FW_OWN_REQ_SET BIT(8) +#define WHLPCR_IS_DRIVER_OWN BIT(8) +#define WHLPCR_INT_EN_CLR BIT(1) +#define WHLPCR_INT_EN_SET BIT(0) + +/* 3 WSDIOCSR 0x0008 */ +#define WSDIOCSR_DB_CMD7_RESELECT_DIS BIT(4) +#define WSDIOCSR_DB_WR_BUSY_EN BIT(3) +#define WSDIOCSR_DB_RD_BUSY_EN BIT(2) +#define WSDIOCSR_SDIO_INT_CTL BIT(1) +#define WSDIOCSR_SDIO_RE_INIT_EN BIT(0) + +/* 3 WHCR 0x000C */ +#define WHCR_RX_ENHANCE_MODE_EN BIT(16) +#define WHCR_MAX_HIF_RX_LEN_NUM BITS(8, 13) +#define WHCR_RPT_OWN_RX_PACKET_LEN BIT(3) +#define WHCR_RECV_MAILBOX_RD_CLR_EN BIT(2) +#define WHCR_W_INT_CLR_CTRL BIT(1) +#define WHCR_MCU_DBG_EN BIT(0) +#define WHCR_OFFSET_MAX_HIF_RX_LEN_NUM 8 + +/* 3 WHISR 0x0010 */ +#define WHISR_D2H_SW_INT BITS(8, 31) +#define WHISR_D2H_SW_ASSERT_INFO_INT BIT(31) +#define WHISR_D2H_WKUP_BY_RX_PACKET BIT(30) +#define WHISR_D2H_SW_RD_MAILBOX_INT BIT(29) +#define WHISR_FW_OWN_BACK_INT BIT(7) +#define WHISR_ABNORMAL_INT BIT(6) +#define WHISR_RX1_DONE_INT BIT(2) +#define WHISR_RX0_DONE_INT BIT(1) +#define WHISR_TX_DONE_INT BIT(0) + +/* 3 WHIER 0x0014 */ +#define WHIER_D2H_SW_INT BITS(8, 31) +#define WHIER_FW_OWN_BACK_INT_EN BIT(7) +#define WHIER_ABNORMAL_INT_EN BIT(6) +#define WHIER_RX1_DONE_INT_EN BIT(2) +#define WHIER_RX0_DONE_INT_EN BIT(1) +#define WHIER_TX_DONE_INT_EN BIT(0) +#define WHIER_DEFAULT \ + (WHIER_RX0_DONE_INT_EN | WHIER_RX1_DONE_INT_EN | \ + WHIER_TX_DONE_INT_EN | WHIER_ABNORMAL_INT_EN | WHIER_D2H_SW_INT) + +/* 3 WASR 0x0020 */ +#define WASR_FW_OWN_INVALID_ACCESS BIT(16) +#define WASR_RX1_UNDER_FLOW BIT(9) +#define WASR_RX0_UNDER_FLOW BIT(8) +#define WASR_TX1_OVER_FLOW BIT(1) + +/* 3 WSICR 0x0024 */ +#define WSICR_H2D_SW_INT_SET BITS(16, 31) + +/* 3 WRPLR 0x0090 */ +#define WRPLR_RX1_PACKET_LENGTH BITS(16, 31) +#define WRPLR_RX0_PACKET_LENGTH BITS(0, 15) + +/* 3 WTMCR 0x00b4 */ +#define WMTCR_TEST_MODE_FW_OWN BIT(24) +#define WMTCR_PRBS_INIT_VAL BITS(16, 23) +#define WMTCR_TEST_MODE_STATUS BIT(8) +#define WMTCR_TEST_MODE_SELECT BITS(0, 1) + +/* Support features */ +/* Options for VLAN-over-ethernet pkt to/from 802.11 LLC VLAN pkt. + * This should depend on the configurations of HW-header-translation. + */ +#define FEAT_BITS_LLC_VLAN_TX BIT(0) +#define FEAT_BITS_LLC_VLAN_RX BIT(1) + +/* Support features API */ +#define FEAT_SUP_LLC_VLAN_TX(__chip_info) \ + ((__chip_info)->features & FEAT_BITS_LLC_VLAN_TX) +#define FEAT_SUP_LLC_VLAN_RX(__chip_info) \ + ((__chip_info)->features & FEAT_BITS_LLC_VLAN_RX) + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef enum _ENUM_WIFI_FUNC_T { + WIFI_FUNC_INIT_DONE = BIT(0), + WIFI_FUNC_N9_DONE = BIT(1), + WIFI_FUNC_CR4_READY = BIT(2), + WIFI_FUNC_READY_BITS = BITS(0, 2), + WIFI_FUNC_DUMMY_REQ = BIT(3) +} ENUM_WIFI_FUNC_T; + +enum enum_chip { + CHIP_6632 = 0, + CHIP_7666, + CHIP_7668, + CHIP_NUM +}; + +struct chip_info { + const unsigned int chip_id; /* chip id */ + const unsigned int sw_sync0; /* sw_sync0 address */ + const unsigned int sw_ready_bit_offset; /* sw_sync0 ready bit offset */ + const unsigned int patch_addr; /* patch download start address */ + const unsigned char is_pcie_32dw_read; /* diff PDMA config */ + + const P_ECO_INFO_T eco_info; /* chip version table */ + u8 eco_ver; /* chip version */ + + void (*constructFirmwarePrio)(P_GLUE_INFO_T prGlueInfo, + u8 **apucNameTable, + u8 **apucName, + u8 *pucNameIdx, + u8 ucMaxNameIdx); + + const u32 features; /* feature bits */ +}; + +struct hif_driver_data { + struct chip_info *chip_info; +}; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/wlan_def.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/wlan_def.h new file mode 100644 index 00000000000000..89bb058878e3a0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic/wlan_def.h @@ -0,0 +1,1120 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "wlan_def.h" + * \brief This file includes the basic definition of WLAN + * + */ + +#ifndef _WLAN_DEF_H +#define _WLAN_DEF_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* disconnect reason */ +#define DISCONNECT_REASON_CODE_RESERVED 0 +#define DISCONNECT_REASON_CODE_RADIO_LOST 1 +#define DISCONNECT_REASON_CODE_DEAUTHENTICATED 2 +#define DISCONNECT_REASON_CODE_DISASSOCIATED 3 +#define DISCONNECT_REASON_CODE_NEW_CONNECTION 4 +#define DISCONNECT_REASON_CODE_REASSOCIATION 5 +#if CFG_SUPPORT_DBDC_TC6 +#define DISCONNECT_REASON_CODE_DBDC_REASSOCIATION 6 +#endif + +/* Beacon Timeout Event Reason */ +#define BEACON_TIMEOUT_REASON_DUE_2_BMC_ERR 0x40 +#define BEACON_TIMEOUT_EVENT_DUE_2_RX_DEAUTH_IN_STR 0x41 +#define BEACON_TIMEOUT_REASON_DUE_2_DBDC_RECONNECT 0x42 + +/* The rate definitions */ +#define TX_MODE_CCK 0x00 +#define TX_MODE_OFDM 0x40 +#define TX_MODE_HT_MM 0x80 +#define TX_MODE_HT_GF 0xC0 +#define TX_MODE_VHT 0x100 + +#define RATE_CCK_SHORT_PREAMBLE 0x4 + +#define PHY_RATE_1M 0x0 +#define PHY_RATE_2M 0x1 +#define PHY_RATE_5_5M 0x2 +#define PHY_RATE_11M 0x3 +#define PHY_RATE_6M 0xB +#define PHY_RATE_9M 0xF +#define PHY_RATE_12M 0xA +#define PHY_RATE_18M 0xE +#define PHY_RATE_24M 0x9 +#define PHY_RATE_36M 0xD +#define PHY_RATE_48M 0x8 +#define PHY_RATE_54M 0xC + +#define PHY_RATE_MCS0 0x0 +#define PHY_RATE_MCS1 0x1 +#define PHY_RATE_MCS2 0x2 +#define PHY_RATE_MCS3 0x3 +#define PHY_RATE_MCS4 0x4 +#define PHY_RATE_MCS5 0x5 +#define PHY_RATE_MCS6 0x6 +#define PHY_RATE_MCS7 0x7 +#define PHY_RATE_MCS8 0x8 +#define PHY_RATE_MCS9 0x9 +#define PHY_RATE_MCS32 0x20 + +#define RATE_CCK_1M_LONG (TX_MODE_CCK | \ + PHY_RATE_1M) +#define RATE_CCK_2M_LONG (TX_MODE_CCK | \ + PHY_RATE_2M) +#define RATE_CCK_5_5M_LONG (TX_MODE_CCK | \ + PHY_RATE_5_5M) +#define RATE_CCK_11M_LONG (TX_MODE_CCK | \ + PHY_RATE_11M) +#define RATE_CCK_2M_SHORT (TX_MODE_CCK | \ + PHY_RATE_2M | \ + RATE_CCK_SHORT_PREAMBLE) +#define RATE_CCK_5_5M_SHORT \ + (TX_MODE_CCK | PHY_RATE_5_5M | RATE_CCK_SHORT_PREAMBLE) +#define RATE_CCK_11M_SHORT \ + (TX_MODE_CCK | PHY_RATE_11M | RATE_CCK_SHORT_PREAMBLE) +#define RATE_OFDM_6M (TX_MODE_OFDM | \ + PHY_RATE_6M) +#define RATE_OFDM_9M (TX_MODE_OFDM | \ + PHY_RATE_9M) +#define RATE_OFDM_12M (TX_MODE_OFDM | \ + PHY_RATE_12M) +#define RATE_OFDM_18M (TX_MODE_OFDM | \ + PHY_RATE_18M) +#define RATE_OFDM_24M (TX_MODE_OFDM | \ + PHY_RATE_24M) +#define RATE_OFDM_36M (TX_MODE_OFDM | \ + PHY_RATE_36M) +#define RATE_OFDM_48M (TX_MODE_OFDM | \ + PHY_RATE_48M) +#define RATE_OFDM_54M (TX_MODE_OFDM | \ + PHY_RATE_54M) + +#define RATE_MM_MCS_0 (TX_MODE_HT_MM | \ + PHY_RATE_MCS0) +#define RATE_MM_MCS_1 (TX_MODE_HT_MM | \ + PHY_RATE_MCS1) +#define RATE_MM_MCS_2 (TX_MODE_HT_MM | \ + PHY_RATE_MCS2) +#define RATE_MM_MCS_3 (TX_MODE_HT_MM | \ + PHY_RATE_MCS3) +#define RATE_MM_MCS_4 (TX_MODE_HT_MM | \ + PHY_RATE_MCS4) +#define RATE_MM_MCS_5 (TX_MODE_HT_MM | \ + PHY_RATE_MCS5) +#define RATE_MM_MCS_6 (TX_MODE_HT_MM | \ + PHY_RATE_MCS6) +#define RATE_MM_MCS_7 (TX_MODE_HT_MM | \ + PHY_RATE_MCS7) +#define RATE_MM_MCS_32 (TX_MODE_HT_MM | \ + PHY_RATE_MCS32) + +#define RATE_GF_MCS_0 (TX_MODE_HT_GF | \ + PHY_RATE_MCS0) +#define RATE_GF_MCS_1 (TX_MODE_HT_GF | \ + PHY_RATE_MCS1) +#define RATE_GF_MCS_2 (TX_MODE_HT_GF | \ + PHY_RATE_MCS2) +#define RATE_GF_MCS_3 (TX_MODE_HT_GF | \ + PHY_RATE_MCS3) +#define RATE_GF_MCS_4 (TX_MODE_HT_GF | \ + PHY_RATE_MCS4) +#define RATE_GF_MCS_5 (TX_MODE_HT_GF | \ + PHY_RATE_MCS5) +#define RATE_GF_MCS_6 (TX_MODE_HT_GF | \ + PHY_RATE_MCS6) +#define RATE_GF_MCS_7 (TX_MODE_HT_GF | \ + PHY_RATE_MCS7) +#define RATE_GF_MCS_32 (TX_MODE_HT_GF | \ + PHY_RATE_MCS32) + +#define RATE_VHT_MCS_0 (TX_MODE_VHT | \ + PHY_RATE_MCS0) +#define RATE_VHT_MCS_1 (TX_MODE_VHT | \ + PHY_RATE_MCS1) +#define RATE_VHT_MCS_2 (TX_MODE_VHT | \ + PHY_RATE_MCS2) +#define RATE_VHT_MCS_3 (TX_MODE_VHT | \ + PHY_RATE_MCS3) +#define RATE_VHT_MCS_4 (TX_MODE_VHT | \ + PHY_RATE_MCS4) +#define RATE_VHT_MCS_5 (TX_MODE_VHT | \ + PHY_RATE_MCS5) +#define RATE_VHT_MCS_6 (TX_MODE_VHT | \ + PHY_RATE_MCS6) +#define RATE_VHT_MCS_7 (TX_MODE_VHT | \ + PHY_RATE_MCS7) +#define RATE_VHT_MCS_8 (TX_MODE_VHT | \ + PHY_RATE_MCS8) +#define RATE_VHT_MCS_9 (TX_MODE_VHT | \ + PHY_RATE_MCS9) + +#define RATE_NSTS_MASK BITS(9, 10) +#define RATE_NSTS_OFFSET 9 +#define RATE_TX_MODE_MASK BITS(6, 8) +#define RATE_TX_MODE_OFFSET 6 +#define RATE_CODE_GET_TX_MODE(_ucRateCode) \ + ((_ucRateCode & RATE_TX_MODE_MASK) >> RATE_TX_MODE_OFFSET) +#define RATE_PHY_RATE_MASK BITS(0, 5) +#define RATE_PHY_RATE_OFFSET 0 +#define RATE_CODE_GET_PHY_RATE(_ucRateCode) \ + ((_ucRateCode & RATE_PHY_RATE_MASK) >> RATE_PHY_RATE_OFFSET) +#define RATE_PHY_RATE_SHORT_PREAMBLE BIT(2) +#define RATE_CODE_IS_SHORT_PREAMBLE(_ucRateCode) \ + ((_ucRateCode & RATE_PHY_RATE_SHORT_PREAMBLE) ? true : false) + +#define CHNL_LIST_SZ_2G 14 +#define CHNL_LIST_SZ_5G 14 + +/*! CNM(STA_RECORD_T) related definition */ +#define CFG_STA_REC_NUM 27 + +/* PHY TYPE bit definitions */ +#define PHY_TYPE_BIT_HR_DSSS \ + BIT(PHY_TYPE_HR_DSSS_INDEX) /* HR/DSSS PHY (clause 18) */ +#define PHY_TYPE_BIT_ERP BIT(PHY_TYPE_ERP_INDEX) /* ERP PHY (clause 19) */ +#define PHY_TYPE_BIT_OFDM \ + BIT(PHY_TYPE_OFDM_INDEX) /* OFDM 5 GHz PHY (clause 17) */ +#define PHY_TYPE_BIT_HT BIT(PHY_TYPE_HT_INDEX) /* HT PHY (clause 20) */ +#define PHY_TYPE_BIT_VHT BIT(PHY_TYPE_VHT_INDEX) /* HT PHY (clause 22) */ + +/* PHY TYPE set definitions */ +#define PHY_TYPE_SET_802_11ABGN \ + (PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_HR_DSSS | PHY_TYPE_BIT_ERP | \ + PHY_TYPE_BIT_HT) + +#define PHY_TYPE_SET_802_11BGN \ + (PHY_TYPE_BIT_HR_DSSS | PHY_TYPE_BIT_ERP | PHY_TYPE_BIT_HT) + +#define PHY_TYPE_SET_802_11GN (PHY_TYPE_BIT_ERP | \ + PHY_TYPE_BIT_HT) + +#define PHY_TYPE_SET_802_11AN (PHY_TYPE_BIT_OFDM | \ + PHY_TYPE_BIT_HT) + +#define PHY_TYPE_SET_802_11ABG \ + (PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_HR_DSSS | PHY_TYPE_BIT_ERP) + +#define PHY_TYPE_SET_802_11BG (PHY_TYPE_BIT_HR_DSSS | \ + PHY_TYPE_BIT_ERP) + +#define PHY_TYPE_SET_802_11A (PHY_TYPE_BIT_OFDM) + +#define PHY_TYPE_SET_802_11G (PHY_TYPE_BIT_ERP) + +#define PHY_TYPE_SET_802_11B (PHY_TYPE_BIT_HR_DSSS) + +#define PHY_TYPE_SET_802_11N (PHY_TYPE_BIT_HT) + +#define PHY_TYPE_SET_802_11AC (PHY_TYPE_BIT_VHT) + +#define PHY_TYPE_SET_802_11ANAC \ + (PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_HT | PHY_TYPE_BIT_VHT) + +#define PHY_TYPE_SET_802_11ABGNAC \ + (PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_HR_DSSS | PHY_TYPE_BIT_ERP | \ + PHY_TYPE_BIT_HT | PHY_TYPE_BIT_VHT) + +/* Rate set bit definitions */ +#define RATE_SET_BIT_1M BIT(RATE_1M_SW_INDEX) /* Bit 0: 1M */ +#define RATE_SET_BIT_2M BIT(RATE_2M_SW_INDEX) /* Bit 1: 2M */ +#define RATE_SET_BIT_5_5M BIT(RATE_5_5M_SW_INDEX) /* Bit 2: 5.5M */ +#define RATE_SET_BIT_11M BIT(RATE_11M_SW_INDEX) /* Bit 3: 11M */ +#define RATE_SET_BIT_22M BIT(RATE_22M_SW_INDEX) /* Bit 4: 22M */ +#define RATE_SET_BIT_33M BIT(RATE_33M_SW_INDEX) /* Bit 5: 33M */ +#define RATE_SET_BIT_6M BIT(RATE_6M_SW_INDEX) /* Bit 6: 6M */ +#define RATE_SET_BIT_9M BIT(RATE_9M_SW_INDEX) /* Bit 7: 9M */ +#define RATE_SET_BIT_12M BIT(RATE_12M_SW_INDEX) /* Bit 8: 12M */ +#define RATE_SET_BIT_18M BIT(RATE_18M_SW_INDEX) /* Bit 9: 18M */ +#define RATE_SET_BIT_24M BIT(RATE_24M_SW_INDEX) /* Bit 10: 24M */ +#define RATE_SET_BIT_36M BIT(RATE_36M_SW_INDEX) /* Bit 11: 36M */ +#define RATE_SET_BIT_48M BIT(RATE_48M_SW_INDEX) /* Bit 12: 48M */ +#define RATE_SET_BIT_54M BIT(RATE_54M_SW_INDEX) /* Bit 13: 54M */ +#define RATE_SET_BIT_HT_PHY \ + BIT(RATE_HT_PHY_SW_INDEX) /* Bit 14: BSS Selector \ + */ + +/* Rate set definitions */ +#define RATE_SET_HR_DSSS \ + (RATE_SET_BIT_1M | RATE_SET_BIT_2M | RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M) + +#define RATE_SET_ERP \ + (RATE_SET_BIT_1M | RATE_SET_BIT_2M | RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M | RATE_SET_BIT_6M | RATE_SET_BIT_9M | \ + RATE_SET_BIT_12M | RATE_SET_BIT_18M | RATE_SET_BIT_24M | \ + RATE_SET_BIT_36M | RATE_SET_BIT_48M | RATE_SET_BIT_54M) + +#define RATE_SET_ERP_P2P \ + (RATE_SET_BIT_6M | RATE_SET_BIT_9M | RATE_SET_BIT_12M | \ + RATE_SET_BIT_18M | RATE_SET_BIT_24M | RATE_SET_BIT_36M | \ + RATE_SET_BIT_48M | RATE_SET_BIT_54M) + +#define RATE_SET_OFDM \ + (RATE_SET_BIT_6M | RATE_SET_BIT_9M | RATE_SET_BIT_12M | \ + RATE_SET_BIT_18M | RATE_SET_BIT_24M | RATE_SET_BIT_36M | \ + RATE_SET_BIT_48M | RATE_SET_BIT_54M) + +#define RATE_SET_HT (RATE_SET_ERP) +/* #define RATE_SET_HT (RATE_SET_ERP | RATE_SET_BIT_HT_PHY) */ /* NOTE(Kevin): TBD */ + +#define RATE_SET_ALL_ABG RATE_SET_ERP + +#define BASIC_RATE_SET_HR_DSSS (RATE_SET_BIT_1M | RATE_SET_BIT_2M) + +#define BASIC_RATE_SET_HR_DSSS_ERP \ + (RATE_SET_BIT_1M | RATE_SET_BIT_2M | RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M) + +#define BASIC_RATE_SET_ERP \ + (RATE_SET_BIT_1M | RATE_SET_BIT_2M | RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M | RATE_SET_BIT_6M | RATE_SET_BIT_12M | \ + RATE_SET_BIT_24M) + +#define BASIC_RATE_SET_OFDM \ + (RATE_SET_BIT_6M | RATE_SET_BIT_12M | RATE_SET_BIT_24M) + +#define BASIC_RATE_SET_ERP_P2P \ + (RATE_SET_BIT_6M | RATE_SET_BIT_12M | RATE_SET_BIT_24M) + +#define INITIAL_RATE_SET_RCPI_100 RATE_SET_ALL_ABG + +#define INITIAL_RATE_SET_RCPI_80 \ + (RATE_SET_BIT_1M | RATE_SET_BIT_2M | RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M | RATE_SET_BIT_6M | RATE_SET_BIT_9M | \ + RATE_SET_BIT_12M | RATE_SET_BIT_24M) + +#define INITIAL_RATE_SET_RCPI_60 \ + (RATE_SET_BIT_1M | RATE_SET_BIT_2M | RATE_SET_BIT_5_5M | \ + RATE_SET_BIT_11M | RATE_SET_BIT_6M) + +#define INITIAL_RATE_SET(_rcpi) (INITIAL_RATE_SET_ ## _rcpi) + +#define RCPI_100 100 /* -60 dBm */ +#define RCPI_80 80 /* -70 dBm */ +#define RCPI_60 60 /* -80 dBm */ + +/* The number of RCPI records used to calculate their average value */ +#define MAX_NUM_RCPI_RECORDS 10 + +/* The number of RCPI records used to calculate their average value */ +#define NO_RCPI_RECORDS -128 +#define MAX_RCPI_DBM 0 +#define MIN_RCPI_DBM -100 + +#define MAX_ASSOC_ID \ + (CFG_STA_REC_NUM) /* Available AID: 1 ~ 20(STA_REC_NUM) \ + */ + +#define MAX_DEAUTH_INFO_COUNT 4 /* NOTE(Kevin): Used in auth.c */ +#define MIN_DEAUTH_INTERVAL_MSEC \ + 500 /* The minimum interval if continuously send Deauth Frame */ + +/* Authentication Type */ +#define AUTH_TYPE_OPEN_SYSTEM BIT( \ + AUTH_ALGORITHM_NUM_OPEN_SYSTEM) +#define AUTH_TYPE_SHARED_KEY BIT( \ + AUTH_ALGORITHM_NUM_SHARED_KEY) +#define AUTH_TYPE_FAST_BSS_TRANSITION \ + BIT(AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION) +#define AUTH_TYPE_SAE BIT(AUTH_ALGORITHM_NUM_SAE) + +/* Authentication Retry Limit */ +#define TX_AUTH_ASSOCI_RETRY_LIMIT 2 +#define TX_AUTH_ASSOCI_RETRY_LIMIT_FOR_ROAMING 8 + +/* WMM-2.2.1 WMM Information Element */ +#define ELEM_MAX_LEN_WMM_INFO 7 + +/* PF TCP/UDP max port number */ +#define MAX_TCP_UDP_PORT 20 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef u16 PHY_TYPE, *P_PHY_TYPE; +typedef u8 RCPI, *P_RCPI; +typedef u8 ALC_VAL, *P_ALC_VAL; + +typedef enum _ENUM_HW_BSSID_T { + BSSID_0 = 0, + BSSID_1, + BSSID_2, + BSSID_3, + BSSID_NUM +} ENUM_HW_BSSID_T; + +typedef enum _ENUM_HW_MAC_ADDR_T { + MAC_ADDR_0 = 0, + MAC_ADDR_1, + MAC_ADDR_NUM +} ENUM_HW_MAC_ADDR_T; + +typedef enum _ENUM_HW_OP_MODE_T { + HW_OP_MODE_STA = 0, + HW_OP_MODE_AP, + HW_OP_MODE_ADHOC, + HW_OP_MODE_NUM +} ENUM_HW_OP_MODE_T; + +typedef enum _ENUM_TSF_T { + ENUM_LOCAL_TSF_0, + ENUM_LOCAL_TSF_1, + ENUM_LOCAL_TSF_NUM +} ENUM_LOCAL_TSF_T, +*P_ENUM_LOCAL_TSF_T; + +typedef enum _HAL_TS_HW_UPDATE_MODE { + HAL_TSF_HW_UPDATE_BY_TICK_AND_RECEIVED_FRAME, + HAL_TSF_HW_UPDATE_BY_TICK_ONLY, + HAL_TSF_HW_UPDATE_BY_RECEIVED_FRAME_ONLY, + HAL_TSF_HW_UPDATE_BY_TICK_AND_RECEIVED_FRAME_AD_HOC +} HAL_TSF_HW_UPDATE_MODE; + +typedef enum _ENUM_AC_T { + AC0 = 0, + AC1, + AC2, + AC3, + AC_NUM +} ENUM_AC_T, +*P_ENUM_AC_T; + +typedef enum _ENUM_NETWORK_TYPE_T { + NETWORK_TYPE_AIS, + NETWORK_TYPE_P2P, + NETWORK_TYPE_BOW, + NETWORK_TYPE_MBSS, + NETWORK_TYPE_NUM +} ENUM_NETWORK_TYPE_T; + +/* The Type of STA Type. */ +typedef enum _ENUM_STA_TYPE_INDEX_T { + STA_TYPE_LEGACY_INDEX = 0, + STA_TYPE_P2P_INDEX, + STA_TYPE_BOW_INDEX, + STA_TYPE_INDEX_NUM +} ENUM_STA_TYPE_INDEX_T; + +#define STA_ROLE_BASE_INDEX 4 + +typedef enum _ENUM_STA_ROLE_INDEX_T { + STA_ROLE_ADHOC_INDEX = STA_ROLE_BASE_INDEX, /* 4 */ + STA_ROLE_CLIENT_INDEX, + STA_ROLE_AP_INDEX, + STA_ROLE_DLS_INDEX, + STA_ROLE_MAX_INDEX +} ENUM_STA_ROLE_INDEX_T; + +#define STA_ROLE_INDEX_NUM (STA_ROLE_MAX_INDEX - STA_ROLE_BASE_INDEX) + +/* The Power State of a specific Network */ +typedef enum _ENUM_PWR_STATE_T { + PWR_STATE_IDLE = 0, + PWR_STATE_ACTIVE, + PWR_STATE_PS, + PWR_STATE_NUM +} ENUM_PWR_STATE_T; + +typedef enum _ENUM_PHY_TYPE_INDEX_T { + /* PHY_TYPE_DSSS_INDEX, */ /* DSSS PHY (clause 15) -- Not used anymore + */ + PHY_TYPE_HR_DSSS_INDEX = 0, /* HR/DSSS PHY (clause 18) */ + PHY_TYPE_ERP_INDEX, /* ERP PHY (clause 19) */ + PHY_TYPE_ERP_P2P_INDEX, /* ERP PHY (clause 19) w/o HR/DSSS */ + PHY_TYPE_OFDM_INDEX, /* OFDM 5 GHz PHY (clause 17) */ + PHY_TYPE_HT_INDEX, /* HT PHY (clause 20) */ + PHY_TYPE_VHT_INDEX, /* HT PHY (clause 22) */ + PHY_TYPE_INDEX_NUM /* 6 */ +} ENUM_PHY_TYPE_INDEX_T, +*P_ENUM_PHY_TYPE_INDEX_T; + +typedef enum _ENUM_SW_RATE_INDEX_T { + RATE_1M_SW_INDEX = 0, /* 1M */ + RATE_2M_SW_INDEX, /* 2M */ + RATE_5_5M_SW_INDEX, /* 5.5M */ + RATE_11M_SW_INDEX, /* 11M */ + RATE_22M_SW_INDEX, /* 22M */ + RATE_33M_SW_INDEX, /* 33M */ + RATE_6M_SW_INDEX, /* 6M */ + RATE_9M_SW_INDEX, /* 9M */ + RATE_12M_SW_INDEX, /* 12M */ + RATE_18M_SW_INDEX, /* 18M */ + RATE_24M_SW_INDEX, /* 24M */ + RATE_36M_SW_INDEX, /* 36M */ + RATE_48M_SW_INDEX, /* 48M */ + RATE_54M_SW_INDEX, /* 54M */ + RATE_HT_PHY_SW_INDEX, /* BSS Selector - HT PHY */ + RATE_NUM_SW /* 15 */ +} ENUM_SW_RATE_INDEX_T, +*P_ENUM_SW_RATE_INDEX_T; + +typedef enum _ENUM_CCK_RATE_INDEX_T { + RATE_1M_INDEX = 0, /* 1M */ + RATE_2M_INDEX, /* 2M */ + RATE_5_5M_INDEX, /* 5.5M */ + RATE_11M_INDEX, /* 11M */ + CCK_RATE_NUM /* 4 */ +} ENUM_CCK_RATE_INDEX_T, +*P_ENUM_CCK_RATE_INDEX_T; + +typedef enum _ENUM_OFDM_RATE_INDEX_T { + RATE_6M_INDEX = 0, /* 6M */ + RATE_9M_INDEX, /* 9M */ + RATE_12M_INDEX, /* 12M */ + RATE_18M_INDEX, /* 18M */ + RATE_24M_INDEX, /* 24M */ + RATE_36M_INDEX, /* 36M */ + RATE_48M_INDEX, /* 48M */ + RATE_54M_INDEX, /* 54M */ + OFDM_RATE_NUM /* 8 */ +} ENUM_OFDM_RATE_INDEX_T, +*P_ENUM_OFDM_RATE_INDEX_T; + +typedef enum _ENUM_HT_RATE_INDEX_T { + HT_RATE_MCS32_INDEX = 0, + HT_RATE_MCS0_INDEX, + HT_RATE_MCS1_INDEX, + HT_RATE_MCS2_INDEX, + HT_RATE_MCS3_INDEX, + HT_RATE_MCS4_INDEX, + HT_RATE_MCS5_INDEX, + HT_RATE_MCS6_INDEX, + HT_RATE_MCS7_INDEX, + HT_RATE_MCS8_INDEX, + HT_RATE_MCS9_INDEX, + HT_RATE_MCS10_INDEX, + HT_RATE_MCS11_INDEX, + HT_RATE_MCS12_INDEX, + HT_RATE_MCS13_INDEX, + HT_RATE_MCS14_INDEX, + HT_RATE_MCS15_INDEX, + HT_RATE_NUM /* 16 */ +} ENUM_HT_RATE_INDEX_T, +*P_ENUM_HT_RATE_INDEX_T; + +typedef enum _ENUM_VHT_RATE_INDEX_T { + VHT_RATE_MCS0_INDEX = 0, + VHT_RATE_MCS1_INDEX, + VHT_RATE_MCS2_INDEX, + VHT_RATE_MCS3_INDEX, + VHT_RATE_MCS4_INDEX, + VHT_RATE_MCS5_INDEX, + VHT_RATE_MCS6_INDEX, + VHT_RATE_MCS7_INDEX, + VHT_RATE_MCS8_INDEX, + VHT_RATE_MCS9_INDEX, + VHT_RATE_NUM /* 10 */ +} ENUM_VHT_RATE_INDEX_T, +*P_ENUM_VHT_RATE_INDEX_T; + +typedef enum _ENUM_PREMABLE_OPTION_T { + PREAMBLE_DEFAULT_LONG_NONE = 0, /* long for PHY_TYPE_HR_DSSS, NONE for + * PHY_TYPE_OFDM */ + PREAMBLE_OPTION_SHORT, /* SHORT mandatory for PHY_TYPE_ERP, SHORT option + * for PHY_TYPE_HR_DSSS */ + PREAMBLE_OFDM_MODE, + PREAMBLE_HT_MIXED_MODE, + PREAMBLE_HT_GREEN_FIELD, + PREAMBLE_VHT_FIELD, + PREAMBLE_OPTION_NUM +} ENUM_PREMABLE_OPTION_T, +*P_ENUM_PREMABLE_OPTION_T; + +typedef enum _ENUM_MODULATION_SYSTEM_T { + MODULATION_SYSTEM_CCK = 0, + MODULATION_SYSTEM_OFDM, + MODULATION_SYSTEM_HT20, + MODULATION_SYSTEM_HT40, + MODULATION_SYSTEM_NUM +} ENUM_MODULATION_SYSTEM_T, +*P_ENUM_MODULATION_SYSTEM_T; + +typedef enum _ENUM_MODULATION_TYPE_T { + MODULATION_TYPE_CCK_BPSK = 0, + MODULATION_TYPE_QPSK, + MODULATION_TYPE_16QAM, + MODULATION_TYPE_64QAM, + MODULATION_TYPE_MCS6, + MODULATION_TYPE_54M_MCS7, + MODULATION_TYPE_MCS32, + MODULATION_TYPE_NUM +} ENUM_MODULATION_TYPE_T, +*P_ENUM_MODULATION_TYPE_T; + +enum ENUM_VHT_SYSTEM { + VHT_SYSTEM_VHT20 = 0, + VHT_SYSTEM_VHT40, + VHT_SYSTEM_VHT80, + VHT_SYSTEM_VHT160C, + VHT_SYSTEM_VHT160NC, + VHT_SYSTEM_LG_VHT40, + VHT_SYSTEM_LG_VHT80, + VHT_SYSTEM_LG_VHT160, + VHT_SYSTEM_NUM +}; + +enum ENUM_VHT_MODULATION_TYPE { + MODULATION_TYPE_VHT_BPSK = 0, + MODULATION_TYPE_VHT_QPSK, + MODULATION_TYPE_VHT_16QAM, + MODULATION_TYPE_VHT_64QAM_MSC5_6, + MODULATION_TYPE_VHT_64QAM_MSC7, + MODULATION_TYPE_VHT_64QAM_MSC8, + MODULATION_TYPE_VHT_64QAM_MSC9, + MODULATION_TYPE_VHT_NUM +}; + +enum PWR_DSSS_CAT { + PWR_DSSS_CCK, + PWR_DSSS_BPKS, + PWR_DSSS_NUM +}; + +enum PWR_OFDM_CAT { + PWR_OFDM_BPSK, /* 6M, 9M */ + PWR_OFDM_QPSK, /* 12M, 18M */ + PWR_OFDM_16QAM, /* 24M, 36M */ + PWR_OFDM_48Mbps, /* 48M */ + PWR_OFDM_54Mbps, /* 54M */ + PWR_OFDM_NUM +}; + +enum PWR_HT20_CAT { + PWR_HT_BPSK, /* MCS0*/ + PWR_HT_QPSK, /* MCS1, MCS2 */ + PWR_HT_16QAM, /* MCS3, MCS4 */ + PWR_HT_MCS5, /* MCS5 */ + PWR_HT_MCS6, /* MCS6 */ + PWR_HT_MCS7, /* MCS7 */ + PWR_HT_MCS32, /* MCS32 */ + PWR_HT_NUM +}; + +enum PWR_VHT20_CAT { + PWR_VHT20_BPSK, + PWR_VHT20_QPSK, + PWR_VHT20_16QAM, + PWR_VHT20_64QAM, + PWR_VHT20_MCS7, + PWR_VHT20_MCS8, + PWR_VHT20_MCS9, + PWR_VHT20_NUM +}; + +enum PWR_VHT_OFST_CAT { + PWR_Vht40_OFFSET = VHT_SYSTEM_VHT40, /*to sync to ENUM_VHT_SYSTEM_T*/ + PWR_Vht80_OFFSET, + PWR_Vht160c_OFFSET, + PWR_Vht160nc_OFFSET, + PWR_LgVht40_OFFSET, + PWR_LgVht80_OFFSET, + PWR_VHT_OFST_NUM +}; + +#ifdef CFG_DUMP_TXPOWR_TABLE +struct POWER_LIMIT { + u8 ucCentralCh; + u8 tx_pwr_dsss[PWR_DSSS_NUM]; /*unit: 0.5 dbm*/ + u8 tx_pwr_ofdm[PWR_OFDM_NUM]; /*unit: 0.5 dbm*/ + u8 tx_pwr_ht20[PWR_HT_NUM]; /*unit: 0.5 dbm*/ + u8 tx_pwr_ht40[PWR_HT_NUM]; /*unit: 0.5 dbm*/ + u8 tx_pwr_vht20[PWR_VHT20_NUM]; /*unit: 0.5 dbm*/ + u8 tx_pwr_vht_OFST[PWR_VHT_OFST_NUM]; /*unit: 0.5 dbm*/ +}; + +enum ENUM_TXPWR_TBL_IDX { + LIMIT_TBL, + EEPROM_TBL, + MAC_TBL, + TXPWR_TBL_NUM +}; +#endif + +typedef enum _ENUM_ACPI_STATE_T { + ACPI_STATE_D0 = 0, + ACPI_STATE_D1, + ACPI_STATE_D2, + ACPI_STATE_D3 +} ENUM_ACPI_STATE_T; + +/* The operation mode of a specific Network */ +typedef enum _ENUM_OP_MODE_T { + OP_MODE_INFRASTRUCTURE = 0, /* Infrastructure/GC */ + OP_MODE_IBSS, /* AdHoc */ + OP_MODE_ACCESS_POINT, /* For GO */ + OP_MODE_P2P_DEVICE, /* P2P Device */ + OP_MODE_BOW, + OP_MODE_NUM +} ENUM_OP_MODE_T, +*P_ENUM_OP_MODE_T; + +typedef enum _ENUM_CHNL_EXT_T { + CHNL_EXT_SCN = 0, + CHNL_EXT_SCA = 1, + CHNL_EXT_RES = 2, + CHNL_EXT_SCB = 3 +} ENUM_CHNL_EXT_T, +*P_ENUM_CHNL_EXT_T; + +typedef enum _ENUM_CHANNEL_WIDTH_T { + CW_20_40MHZ = 0, + CW_80MHZ = 1, + CW_160MHZ = 2, + CW_80P80MHZ = 3 +} ENUM_CHANNEL_WIDTH_T, +*P_ENUM_CHANNEL_WIDTH_P; + +/* This starting freq of the band is unit of kHz */ +typedef enum _ENUM_BAND_T { + BAND_NULL, + BAND_2G4, + BAND_5G, + BAND_NUM +} ENUM_BAND_T, +*P_ENUM_BAND_T; + +typedef enum _ENUM_DBDC_BN_T { + ENUM_BAND_0, + ENUM_BAND_1, + ENUM_BAND_NUM, + ENUM_BAND_ALL, + ENUM_BAND_AUTO /*Auto select by A/G band, Driver only*/ +} ENUM_DBDC_BN_T, +*P_ENUM_DBDC_BN_T; + +/* Provide supported channel list to other components in array format */ +typedef struct _RF_CHANNEL_INFO_T { + ENUM_BAND_T eBand; + u32 u4CenterFreq1; /* To record Channel Center Frequency Segment 0 (MHz) + * from CFG80211 */ + u32 u4CenterFreq2; /* To record Channel Center Frequency Segment 1 (MHz) + * from CFG80211 */ + u16 u2PriChnlFreq; /* To record primary channel frequency (MHz) from + * CFG80211 */ + u8 ucChnlBw; /* To record channel bandwidth from CFG80211 */ + u8 ucChannelNum; +#if (CFG_SUPPORT_DFS_MASTER == 1) + u32 u4ChnlDfsState; /* Channel DFS State */ +#endif +} RF_CHANNEL_INFO_T, *P_RF_CHANNEL_INFO_T; + +typedef enum _ENUM_PS_FORWARDING_TYPE_T { + PS_FORWARDING_TYPE_NON_PS = 0, + PS_FORWARDING_TYPE_DELIVERY_ENABLED, + PS_FORWARDING_TYPE_NON_DELIVERY_ENABLED, + PS_FORWARDING_MORE_DATA_ENABLED, + PS_FORWARDING_TYPE_NUM +} ENUM_PS_FORWARDING_TYPE_T, +*P_ENUM_PS_FORWARDING_TYPE_T; + +typedef enum _ENUM_AR_SS_T { + AR_SS_NULL = 0, + AR_SS_1, + AR_SS_2, + AR_SS_3, + AR_SS_4, + AR_SS_NUM +} ENUM_AR_SS_T, +P_ENUM_AR_SS_T; + +typedef enum _ENUM_MAC_BANDWIDTH_T { + MAC_BW_20 = 0, + MAC_BW_40, + MAC_BW_80, + MAC_BW_160 +} ENUM_MAC_BANDWIDTH_T, +*P_ENUM_MAC_BANDWIDTH_T; + +typedef struct _DEAUTH_INFO_T { + u8 aucRxAddr[MAC_ADDR_LEN]; + u32 rLastSendTime; +} DEAUTH_INFO_T, *P_DEAUTH_INFO_T; + +/*----------------------------------------------------------------------------*/ +/* Information Element (IE) handlers */ +/*----------------------------------------------------------------------------*/ +typedef void (*PFN_APPEND_IE_FUNC)(P_ADAPTER_T, P_MSDU_INFO_T); +typedef void (*PFN_HANDLE_IE_FUNC)(P_ADAPTER_T, P_SW_RFB_T, P_IE_HDR_T); +typedef void (*PFN_VERIFY_IE_FUNC)(P_ADAPTER_T, P_SW_RFB_T, P_IE_HDR_T, u16 *); +typedef u32 (*PFN_CALCULATE_VAR_IE_LEN_FUNC)(P_ADAPTER_T, u8, P_STA_RECORD_T); + +typedef struct _APPEND_IE_ENTRY_T { + u16 u2EstimatedIELen; + PFN_APPEND_IE_FUNC pfnAppendIE; +} APPEND_IE_ENTRY_T, *P_APPEND_IE_ENTRY_T; + +typedef struct _APPEND_VAR_IE_ENTRY_T { + u16 u2EstimatedFixedIELen; /* For Fixed Length */ + PFN_CALCULATE_VAR_IE_LEN_FUNC pfnCalculateVariableIELen; + PFN_APPEND_IE_FUNC pfnAppendIE; +} APPEND_VAR_IE_ENTRY_T, *P_APPEND_VAR_IE_ENTRY_T; + +typedef struct _HANDLE_IE_ENTRY_T { + u8 ucElemID; + PFN_HANDLE_IE_FUNC pfnHandleIE; +} HANDLE_IE_ENTRY_T, *P_HANDLE_IE_ENTRY_T; + +typedef struct _VERIFY_IE_ENTRY_T { + u8 ucElemID; + PFN_VERIFY_IE_FUNC pfnVarifyIE; +} VERIFY_IE_ENTRY_T, *P_VERIFY_IE_ENTRY_T; + +/*----------------------------------------------------------------------------*/ +/* Parameters of User Configuration */ +/*----------------------------------------------------------------------------*/ +typedef enum _ENUM_PARAM_CONNECTION_POLICY_T { + CONNECT_BY_SSID_BEST_RSSI = 0, + CONNECT_BY_SSID_GOOD_RSSI_MIN_CH_LOAD, + CONNECT_BY_SSID_ANY, /* NOTE(Kevin): Needed by WHQL */ + CONNECT_BY_BSSID, + CONNECT_BY_CUSTOMIZED_RULE /* NOTE(Kevin): TBD */ +} ENUM_PARAM_CONNECTION_POLICY_T, +*P_ENUM_PARAM_CONNECTION_POLICY_T; + +typedef enum _ENUM_PARAM_PREAMBLE_TYPE_T { + PREAMBLE_TYPE_LONG = 0, + PREAMBLE_TYPE_SHORT, + PREAMBLE_TYPE_AUTO /*!< Try preamble short first, if fail tray preamble + * long. */ +} ENUM_PARAM_PREAMBLE_TYPE_T, +*P_ENUM_PARAM_PREAMBLE_TYPE_T; + +/* This is enum defined for user to select a phy config listed in combo box */ +typedef enum _ENUM_PARAM_PHY_CONFIG_T { + PHY_CONFIG_802_11ABG = 0, /*!< Can associated with 802.11abg AP but + * without n capability, Scan dual band. + **/ + PHY_CONFIG_802_11BG, /*!< Can associated with 802_11bg AP, Scan single + * band and not report 5G BSSs. + **/ + PHY_CONFIG_802_11G, /*!< Can associated with 802_11g only AP, Scan + * single band and not report 5G BSSs. */ + PHY_CONFIG_802_11A, /*!< Can associated with 802_11a only AP, Scan + * single band and not report 2.4G BSSs. */ + PHY_CONFIG_802_11B, /*!< Can associated with 802_11b only AP, Scan + * single band and not report 5G BSSs. */ + PHY_CONFIG_802_11ABGN, /*!< Can associated with 802.11abgn AP, Scan dual + * band. */ + PHY_CONFIG_802_11BGN, /*!< Can associated with 802_11bgn AP, Scan single + * band and not report 5G BSSs. + **/ + PHY_CONFIG_802_11AN, /*!< Can associated with 802_11an AP, Scan single + * band and not report 2.4G BSSs. + **/ + PHY_CONFIG_802_11GN, /*!< Can associated with 802_11gn AP, Scan single + * band and not report 5G BSSs. + **/ + PHY_CONFIG_802_11AC, + PHY_CONFIG_802_11ANAC, + PHY_CONFIG_802_11ABGNAC, + PHY_CONFIG_NUM /* 12 */ +} ENUM_PARAM_PHY_CONFIG_T, +*P_ENUM_PARAM_PHY_CONFIG_T; + +/* This is enum defined for user to select an AP Mode */ +typedef enum _ENUM_PARAM_AP_MODE_T { + AP_MODE_11B = 0, /*!< Create 11b BSS if we support 802.11abg/802.11bg. + */ + AP_MODE_MIXED_11BG, /*!< Create 11bg mixed BSS if we support + * 802.11abg/802.11bg/802.11g. */ + AP_MODE_11G, /*!< Create 11g only BSS if we support + * 802.11abg/802.11bg/802.11g. */ + AP_MODE_11G_P2P, /*!< Create 11g only BSS for P2P if we support + * 802.11abg/802.11bg/802.11g. */ + AP_MODE_11A, /*!< Create 11a only BSS if we support 802.11abg. */ + AP_MODE_NUM /* 4 */ +} ENUM_PARAM_AP_MODE_T, +*P_ENUM_PARAM_AP_MODE_T; + +/* Masks for determining the Network Type or the Station Role, given the + * ENUM_STA_TYPE_T */ +#define STA_TYPE_LEGACY_MASK BIT(STA_TYPE_LEGACY_INDEX) +#define STA_TYPE_P2P_MASK BIT(STA_TYPE_P2P_INDEX) +#define STA_TYPE_BOW_MASK BIT(STA_TYPE_BOW_INDEX) +#define STA_TYPE_ADHOC_MASK BIT(STA_ROLE_ADHOC_INDEX) +#define STA_TYPE_CLIENT_MASK BIT(STA_ROLE_CLIENT_INDEX) +#define STA_TYPE_AP_MASK BIT(STA_ROLE_AP_INDEX) +#define STA_TYPE_DLS_MASK BIT(STA_ROLE_DLS_INDEX) + +/* Macros for obtaining the Network Type or the Station Role, given the + * ENUM_STA_TYPE_T */ +#define IS_STA_IN_AIS(_prStaRec) ((prAdapter->prAisBssInfo != NULL) && \ + ((_prStaRec)->ucBssIndex == \ + prAdapter->prAisBssInfo->ucBssIndex)) +#define IS_STA_IN_P2P(_prStaRec) \ + (prAdapter->aprBssInfo[(_prStaRec)->ucBssIndex]->eNetworkType == \ + NETWORK_TYPE_P2P) +#define IS_STA_LEGACY_TYPE(_prStaRec) \ + ((_prStaRec->eStaType) & STA_TYPE_LEGACY_MASK) +#define IS_STA_P2P_TYPE(_prStaRec) ((_prStaRec->eStaType) & \ + STA_TYPE_P2P_MASK) +#define IS_STA_BOW_TYPE(_prStaRec) ((_prStaRec->eStaType) & \ + STA_TYPE_BOW_MASK) +#define IS_ADHOC_STA( \ + _prStaRec) ((_prStaRec->eStaType) & STA_TYPE_ADHOC_MASK) +#define IS_CLIENT_STA( \ + _prStaRec) ((_prStaRec->eStaType) & \ + STA_TYPE_CLIENT_MASK) +#define IS_AP_STA(_prStaRec) ((_prStaRec->eStaType) & STA_TYPE_AP_MASK) +#define IS_DLS_STA(_prStaRec) ((_prStaRec->eStaType) & \ + STA_TYPE_DLS_MASK) + +/* The ENUM_STA_TYPE_T accounts for ENUM_NETWORK_TYPE_T and + * ENUM_STA_ROLE_INDEX_T. It is a merged version of Network Type and STA Role. + */ +typedef enum _ENUM_STA_TYPE_T { + STA_TYPE_LEGACY_AP = (STA_TYPE_LEGACY_MASK | STA_TYPE_AP_MASK), + STA_TYPE_LEGACY_CLIENT = (STA_TYPE_LEGACY_MASK | STA_TYPE_CLIENT_MASK), + STA_TYPE_ADHOC_PEER = (STA_TYPE_LEGACY_MASK | STA_TYPE_ADHOC_MASK), +#if CFG_ENABLE_WIFI_DIRECT + STA_TYPE_P2P_GO = (STA_TYPE_P2P_MASK | STA_TYPE_AP_MASK), + STA_TYPE_P2P_GC = (STA_TYPE_P2P_MASK | STA_TYPE_CLIENT_MASK), +#endif + + STA_TYPE_DLS_PEER = (STA_TYPE_LEGACY_MASK | STA_TYPE_DLS_MASK), +} ENUM_STA_TYPE_T, +*P_ENUM_STA_TYPE_T; + +/* The type of BSS we discovered */ +typedef enum _ENUM_BSS_TYPE_T { + BSS_TYPE_INFRASTRUCTURE = 1, + BSS_TYPE_IBSS, + BSS_TYPE_P2P_DEVICE, + BSS_TYPE_BOW_DEVICE, + BSS_TYPE_NUM +} ENUM_BSS_TYPE_T, +*P_ENUM_BSS_TYPE_T; + +typedef enum _ENUM_ANTENNA_NUM { + ANTENNA_WF0 = 0, + ANTENNA_WF1 = 1, + MAX_ANTENNA_NUM +} ENUM_ANTENNA_NUM, +*P_ENUM_ANTENNA_NUM; + +/*----------------------------------------------------------------------------*/ +/* RSN structures */ +/*----------------------------------------------------------------------------*/ + +/* max number of supported cipher suites */ +#define MAX_NUM_SUPPORTED_CIPHER_SUITES 10 + +/* max number of supported AKM suites */ +#define MAX_NUM_SUPPORTED_AKM_SUITES 15 + +/* max number of supported PMKID */ +#define MAX_NUM_SUPPORTED_PMKID 10 + +/* Structure of RSN Information */ +typedef struct _RSN_INFO_T { + u8 ucElemId; + u8 ucRsneLen; + u16 u2Version; + u32 u4GroupKeyCipherSuite; + u32 u4PairwiseKeyCipherSuiteCount; + u32 au4PairwiseKeyCipherSuite[MAX_NUM_SUPPORTED_CIPHER_SUITES]; + u32 u4AuthKeyMgtSuiteCount; + u32 au4AuthKeyMgtSuite[MAX_NUM_SUPPORTED_AKM_SUITES]; + u16 u2RsnCap; + u8 fgRsnCapPresent; + u16 u2PmkidCnt; + u8 aucPmkidList[MAX_NUM_SUPPORTED_PMKID * RSN_PMKID_LEN]; + u32 u4GroupMgmtKeyCipherSuite; +} /*__KAL_ATTRIB_PACKED__*/ RSN_INFO_T, *P_RSN_INFO_T; + +#define MAX_NUM_SUPPORTED_WAPI_AKM_SUITES \ + 1 /* max number of supported AKM suites */ +#define MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES \ + 1 /* max number of supported cipher suites */ + +/* Structure of WAPI Information */ +typedef struct _WAPI_INFO_T { + u8 ucElemId; + u8 ucLength; + u16 u2Version; + u32 u4AuthKeyMgtSuiteCount; + u32 au4AuthKeyMgtSuite[MAX_NUM_SUPPORTED_WAPI_AKM_SUITES]; + u32 u4PairwiseKeyCipherSuiteCount; + u32 au4PairwiseKeyCipherSuite[MAX_NUM_SUPPORTED_WAPI_CIPHER_SUITES]; + u32 u4GroupKeyCipherSuite; + u16 u2WapiCap; + u16 u2Bkid; + u8 aucBkid[1][16]; +} WAPI_INFO_T, *P_WAPI_INFO_T; + +/* #if defined(WINDOWS_DDK) || defined(WINDOWS_CE) */ +/* #pragma pack() */ +/* #endif */ + +#if CFG_ENABLE_WIFI_DIRECT + +typedef struct _P2P_DEVICE_TYPE_T { + u16 u2CategoryID; + u16 u2SubCategoryID; +} P2P_DEVICE_TYPE_T, *P_P2P_DEVICE_TYPE_T; + +typedef struct _P2P_DEVICE_DESC_T { + LINK_ENTRY_T rLinkEntry; + u8 fgDevInfoValid; + u8 aucDeviceAddr[MAC_ADDR_LEN]; /* Device Address. */ + u8 aucInterfaceAddr[MAC_ADDR_LEN]; /* Interface Address. */ + u8 ucDeviceCapabilityBitmap; + u8 ucGroupCapabilityBitmap; + u16 u2ConfigMethod; /* Configure Method support. */ + P2P_DEVICE_TYPE_T rPriDevType; + u8 ucSecDevTypeNum; + P2P_DEVICE_TYPE_T + arSecDevType[8]; /* Reference to P2P_GC_MAX_CACHED_SEC_DEV_TYPE_COUNT */ + u16 u2NameLength; + u8 aucName[32]; /* Reference to WPS_ATTRI_MAX_LEN_DEVICE_NAME */ + /* TODO: Service Information or PasswordID valid? */ +} P2P_DEVICE_DESC_T, *P_P2P_DEVICE_DESC_T; + +#endif + +#if CFG_SUPPORT_OWE +/* Structure of OWE Information */ +struct OWE_INFO_T { + u8 ucElemId; + u8 ucLength; + u8 ucElemIdExt; + u16 u2Group; + u8 aucPublicKey[100]; +}; +#endif + +#if CFG_SUPPORT_H2E +struct RSNXE { + u8 ucElemId; + u8 ucLength; + u16 u2Cap; +} __KAL_ATTRIB_PACKED__; +#endif + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/* Macros to get and set the wireless LAN frame fields those are 16/32 bits in + * length. */ +#define WLAN_GET_FIELD_16(_memAddr_p, _value_p) \ + { \ + u8 *__cp = (u8 *)(_memAddr_p); \ + *(u16 *)(_value_p) = ((u16)__cp[0]) | ((u16)__cp[1] << 8); \ + } + +#define WLAN_GET_FIELD_BE16(_memAddr_p, _value_p) \ + { \ + u8 *__cp = (u8 *)(_memAddr_p); \ + *(u16 *)(_value_p) = ((u16)__cp[0] << 8) | ((u16)__cp[1]); \ + } + +#define WLAN_GET_FIELD_32(_memAddr_p, _value_p) \ + { \ + u8 *__cp = (u8 *)(_memAddr_p); \ + *(u32 *)(_value_p) = ((u32)__cp[0]) | ((u32)__cp[1] << 8) | \ + ((u32)__cp[2] << 16) | \ + ((u32)__cp[3] << 24); \ + } + +#define WLAN_GET_FIELD_BE32(_memAddr_p, _value_p) \ + { \ + u8 *__cp = (u8 *)(_memAddr_p); \ + *(u32 *)(_value_p) = ((u32)__cp[0] << 24) | \ + ((u32)__cp[1] << 16) | \ + ((u32)__cp[2] << 8) | ((u32)__cp[3]); \ + } + +#define WLAN_GET_FIELD_64(_memAddr_p, _value_p) \ + { \ + u8 *__cp = (u8 *)(_memAddr_p); \ + *(u64 *)(_value_p) = \ + ((u64)__cp[0]) | ((u64)__cp[1] << 8) | \ + ((u64)__cp[2] << 16) | ((u64)__cp[3] << 24) | \ + ((u64)__cp[4] << 32) | ((u64)__cp[5] << 40) | \ + ((u64)__cp[6] << 48) | ((u64)__cp[7] << 56); \ + } + +#define WLAN_SET_FIELD_16(_memAddr_p, _value) \ + { \ + u8 *__cp = (u8 *)(_memAddr_p); \ + __cp[0] = (u8)(_value); \ + __cp[1] = (u8)((_value) >> 8); \ + } + +#define WLAN_SET_FIELD_BE16(_memAddr_p, _value) \ + { \ + u8 *__cp = (u8 *)(_memAddr_p); \ + __cp[0] = (u8)((_value) >> 8); \ + __cp[1] = (u8)(_value); \ + } + +#define WLAN_SET_FIELD_32(_memAddr_p, _value) \ + { \ + u8 *__cp = (u8 *)(_memAddr_p); \ + __cp[0] = (u8)(_value); \ + __cp[1] = (u8)((_value) >> 8); \ + __cp[2] = (u8)((_value) >> 16); \ + __cp[3] = (u8)((_value) >> 24); \ + } + +#define WLAN_SET_FIELD_BE24(_memAddr_p, _value) \ + { \ + u8 *__cp = (u8 *)(_memAddr_p); \ + __cp[0] = (u8)((_value) >> 16); \ + __cp[1] = (u8)((_value) >> 8); \ + __cp[2] = (u8)(_value); \ + } + +#define WLAN_SET_FIELD_BE32(_memAddr_p, _value) \ + { \ + u8 *__cp = (u8 *)(_memAddr_p); \ + __cp[0] = (u8)((_value) >> 24); \ + __cp[1] = (u8)((_value) >> 16); \ + __cp[2] = (u8)((_value) >> 8); \ + __cp[3] = (u8)(_value); \ + } + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic_cmd_event.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic_cmd_event.h new file mode 100644 index 00000000000000..f0c82c840f2e67 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic_cmd_event.h @@ -0,0 +1,3715 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "nic_cmd_event.h" + * \brief This file contains the declairation file of the WLAN OID processing + * routines of Windows driver for MediaTek Inc. 802.11 Wireless LAN Adapters. + */ + +#ifndef _NIC_CMD_EVENT_H +#define _NIC_CMD_EVENT_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define CMD_PQ_ID (0x8000) +#define CMD_PACKET_TYPE_ID (0xA0) + +#define PKT_FT_CMD 0x2 + +#define CMD_STATUS_SUCCESS 0 +#define CMD_STATUS_REJECTED 1 +#define CMD_STATUS_UNKNOWN 2 + +#define EVENT_HDR_WITHOUT_RXD_SIZE \ + (OFFSET_OF(WIFI_EVENT_T, aucBuffer[0]) - \ + OFFSET_OF(WIFI_EVENT_T, u2PacketLength)) + +#define MAX_IE_LENGTH (600) +#define MAX_WSC_IE_LENGTH (400) + +/* Action field in structure CMD_CH_PRIVILEGE_T */ +#define CMD_CH_ACTION_REQ 0 +#define CMD_CH_ACTION_ABORT 1 + +/* Status field in structure EVENT_CH_PRIVILEGE_T */ +#define EVENT_CH_STATUS_GRANT 0 + +/*CMD_POWER_OFFSET_T , follow 5G sub-band*/ +/* #define MAX_SUBBAND_NUM 8 */ +/* */ +/* */ +/* */ +/* */ +#define S2D_INDEX_CMD_H2N 0x0 +#define S2D_INDEX_CMD_C2N 0x1 +#define S2D_INDEX_CMD_H2C 0x2 +#define S2D_INDEX_CMD_H2N_H2C 0x3 + +#define S2D_INDEX_EVENT_N2H 0x0 +#define S2D_INDEX_EVENT_N2C 0x1 +#define S2D_INDEX_EVENT_C2H 0x2 +#define S2D_INDEX_EVENT_N2H_N2C 0x3 + +#define RDD_EVENT_HDR_SIZE 20 +#define RDD_ONEPLUSE_SIZE 8 /* size of one pulse is 8 bytes */ +#define RDD_PULSE_OFFSET0 0 +#define RDD_PULSE_OFFSET1 1 +#define RDD_PULSE_OFFSET2 2 +#define RDD_PULSE_OFFSET3 3 +#define RDD_PULSE_OFFSET4 4 +#define RDD_PULSE_OFFSET5 5 +#define RDD_PULSE_OFFSET6 6 +#define RDD_PULSE_OFFSET7 7 + +#if (CFG_SUPPORT_DFS_MASTER == 1) +#define RDD_IN_SEL_0 0 +#define RDD_IN_SEL_1 1 +#define PPB_SIZE 32 +#define LPB_SIZE 32 +#endif + +#if CFG_SUPPORT_QA_TOOL +#define IQ_FILE_LINE_OFFSET 18 +#define IQ_FILE_IQ_STR_LEN 8 +#define RTN_IQ_DATA_LEN 1024 /* return 1k per packet */ + +#define MCAST_WCID_TO_REMOVE 0 + +/* Network type */ +#define NETWORK_INFRA BIT(16) +#define NETWORK_P2P BIT(17) +#define NETWORK_IBSS BIT(18) +#define NETWORK_MESH BIT(19) +#define NETWORK_BOW BIT(20) +#define NETWORK_WDS BIT(21) + +/* Station role */ +#define STA_TYPE_STA BIT(0) +#define STA_TYPE_AP BIT(1) +#define STA_TYPE_ADHOC BIT(2) +#define STA_TYPE_TDLS BIT(3) +#define STA_TYPE_WDS BIT(4) + +/* Connection type */ +#define CONNECTION_INFRA_STA (STA_TYPE_STA | NETWORK_INFRA) +#define CONNECTION_INFRA_AP (STA_TYPE_AP | NETWORK_INFRA) +#define CONNECTION_P2P_GC (STA_TYPE_STA | NETWORK_P2P) +#define CONNECTION_P2P_GO (STA_TYPE_AP | NETWORK_P2P) +#define CONNECTION_MESH_STA (STA_TYPE_STA | NETWORK_MESH) +#define CONNECTION_MESH_AP (STA_TYPE_AP | NETWORK_MESH) +#define CONNECTION_IBSS_ADHOC (STA_TYPE_ADHOC | NETWORK_IBSS) +#define CONNECTION_TDLS (STA_TYPE_STA | NETWORK_INFRA | \ + STA_TYPE_TDLS) +#define CONNECTION_WDS (STA_TYPE_WDS | NETWORK_WDS) + +#define ICAP_CONTENT_ADC 0x10000006 +#define ICAP_CONTENT_TOAE 0x7 +#define ICAP_CONTENT_SPECTRUM 0xB +#define ICAP_CONTENT_RBIST 0x10 +#define ICAP_CONTENT_DCOC 0x20 +#define ICAP_CONTENT_FIIQ 0x48 +#define ICAP_CONTENT_FDIQ 0x49 + +#define MAX_MEMORY_DUMP_SIZE \ + 4096 /* Same setting as MT7668 FW: hemFsmEventCmdDumpMem() */ + +#if CFG_SUPPORT_BUFFER_MODE + +typedef struct _CMD_EFUSE_BUFFER_MODE_T { + u8 ucSourceMode; + u8 ucCount; + u8 ucCmdType; /* 0:6632, 1: 7668 */ + u8 ucReserved; + u8 aBinContent[MAX_EEPROM_BUFFER_SIZE]; +} CMD_EFUSE_BUFFER_MODE_T, *P_CMD_EFUSE_BUFFER_MODE_T; + +/*#if (CFG_EEPROM_PAGE_ACCESS == 1)*/ +typedef struct _CMD_ACCESS_EFUSE_T { + u32 u4Address; + u32 u4Valid; + u8 aucData[16]; +} CMD_ACCESS_EFUSE_T, *P_CMD_ACCESS_EFUSE_T; + +typedef struct _CMD_EFUSE_FREE_BLOCK_T { + u8 ucGetFreeBlock; + u8 aucReserved[3]; +} CMD_EFUSE_FREE_BLOCK_T, *P_CMD_EFUSE_FREE_BLOCK_T; + +typedef struct _CMD_GET_TX_POWER_T { + u8 ucTxPwrType; + u8 ucCenterChannel; + u8 ucDbdcIdx; /* 0:Band 0, 1: Band1 */ + u8 ucBand; /* 0:G-band 1: A-band*/ + u8 ucReserved[4]; +} CMD_GET_TX_POWER_T, *P_CMD_GET_TX_POWER_T; + +/*#endif*/ + +#endif + +typedef struct _CMD_SET_TX_TARGET_POWER_T { + s8 cTxPwr2G4Cck; /* signed, in unit of 0.5dBm */ + s8 cTxPwr2G4Dsss; /* signed, in unit of 0.5dBm */ + u8 ucTxTargetPwr; /* Tx target power base for all*/ + u8 ucReserved; + + s8 cTxPwr2G4OFDM_BPSK; + s8 cTxPwr2G4OFDM_QPSK; + s8 cTxPwr2G4OFDM_16QAM; + s8 cTxPwr2G4OFDM_Reserved; + s8 cTxPwr2G4OFDM_48Mbps; + s8 cTxPwr2G4OFDM_54Mbps; + + s8 cTxPwr2G4HT20_BPSK; + s8 cTxPwr2G4HT20_QPSK; + s8 cTxPwr2G4HT20_16QAM; + s8 cTxPwr2G4HT20_MCS5; + s8 cTxPwr2G4HT20_MCS6; + s8 cTxPwr2G4HT20_MCS7; + + s8 cTxPwr2G4HT40_BPSK; + s8 cTxPwr2G4HT40_QPSK; + s8 cTxPwr2G4HT40_16QAM; + s8 cTxPwr2G4HT40_MCS5; + s8 cTxPwr2G4HT40_MCS6; + s8 cTxPwr2G4HT40_MCS7; + + s8 cTxPwr5GOFDM_BPSK; + s8 cTxPwr5GOFDM_QPSK; + s8 cTxPwr5GOFDM_16QAM; + s8 cTxPwr5GOFDM_Reserved; + s8 cTxPwr5GOFDM_48Mbps; + s8 cTxPwr5GOFDM_54Mbps; + + s8 cTxPwr5GHT20_BPSK; + s8 cTxPwr5GHT20_QPSK; + s8 cTxPwr5GHT20_16QAM; + s8 cTxPwr5GHT20_MCS5; + s8 cTxPwr5GHT20_MCS6; + s8 cTxPwr5GHT20_MCS7; + + s8 cTxPwr5GHT40_BPSK; + s8 cTxPwr5GHT40_QPSK; + s8 cTxPwr5GHT40_16QAM; + s8 cTxPwr5GHT40_MCS5; + s8 cTxPwr5GHT40_MCS6; + s8 cTxPwr5GHT40_MCS7; +} CMD_SET_TX_TARGET_POWER_T, *P_CMD_SET_TX_TARGET_POWER_T; + +/* + * Definitions for extension CMD_ID + */ +typedef enum _ENUM_EXT_CMD_ID_T { + EXT_CMD_ID_EFUSE_ACCESS = 0x01, + EXT_CMD_ID_RF_REG_ACCESS = 0x02, + EXT_CMD_ID_EEPROM_ACCESS = 0x03, + EXT_CMD_ID_RF_TEST = 0x04, + EXT_CMD_ID_RADIO_ON_OFF_CTRL = 0x05, + EXT_CMD_ID_WIFI_RX_DISABLE = 0x06, + EXT_CMD_ID_PM_STATE_CTRL = 0x07, + EXT_CMD_ID_CHANNEL_SWITCH = 0x08, + EXT_CMD_ID_NIC_CAPABILITY = 0x09, + EXT_CMD_ID_AP_PWR_SAVING_CLEAR = 0x0A, + EXT_CMD_ID_SET_WTBL2_RATETABLE = 0x0B, + EXT_CMD_ID_GET_WTBL_INFORMATION = 0x0C, + EXT_CMD_ID_ASIC_INIT_UNINIT_CTRL = 0x0D, + EXT_CMD_ID_MULTIPLE_REG_ACCESS = 0x0E, + EXT_CMD_ID_AP_PWR_SAVING_CAPABILITY = 0x0F, + EXT_CMD_ID_SECURITY_ADDREMOVE_KEY = 0x10, + EXT_CMD_ID_SET_TX_POWER_CONTROL = 0x11, + EXT_CMD_ID_SET_THERMO_CALIBRATION = 0x12, + EXT_CMD_ID_FW_LOG_2_HOST = 0x13, + EXT_CMD_ID_AP_PWR_SAVING_START = 0x14, + EXT_CMD_ID_MCC_OFFLOAD_START = 0x15, + EXT_CMD_ID_MCC_OFFLOAD_STOP = 0x16, + EXT_CMD_ID_LED = 0x17, + EXT_CMD_ID_PACKET_FILTER = 0x18, + EXT_CMD_ID_COEXISTENCE = 0x19, + EXT_CMD_ID_PWR_MGT_BIT_WIFI = 0x1B, + EXT_CMD_ID_GET_TX_POWER = 0x1C, + EXT_CMD_ID_BF_ACTION = 0x1E, + + EXT_CMD_ID_WMT_CMD_OVER_WIFI = 0x20, + EXT_CMD_ID_EFUSE_BUFFER_MODE = 0x21, + EXT_CMD_ID_OFFLOAD_CTRL = 0x22, + EXT_CMD_ID_THERMAL_PROTECT = 0x23, + EXT_CMD_ID_CLOCK_SWITCH_DISABLE = 0x24, + EXT_CMD_ID_STAREC_UPDATE = 0x25, + EXT_CMD_ID_BSSINFO_UPDATE = 0x26, + EXT_CMD_ID_EDCA_SET = 0x27, + EXT_CMD_ID_SLOT_TIME_SET = 0x28, + EXT_CMD_ID_DEVINFO_UPDATE = 0x2A, + EXT_CMD_ID_NOA_OFFLOAD_CTRL = 0x2B, + EXT_CMD_ID_GET_SENSOR_RESULT = 0x2C, + EXT_CMD_ID_TMR_CAL = 0x2D, + EXT_CMD_ID_WAKEUP_OPTION = 0x2E, + EXT_CMD_ID_OBTW = 0x2F, + + EXT_CMD_ID_GET_TX_STATISTICS = 0x30, + EXT_CMD_ID_AC_QUEUE_CONTROL = 0x31, + EXT_CMD_ID_WTBL_UPDATE = 0x32, + EXT_CMD_ID_BCN_UPDATE = 0x33, + + EXT_CMD_ID_DRR_CTRL = 0x36, + EXT_CMD_ID_BSSGROUP_CTRL = 0x37, + EXT_CMD_ID_VOW_FEATURE_CTRL = 0x38, + EXT_CMD_ID_PKT_PROCESSOR_CTRL = 0x39, + EXT_CMD_ID_PALLADIUM = 0x3A, +#if CFG_SUPPORT_MU_MIMO + EXT_CMD_ID_MU_CTRL = 0x40, +#endif + + EXT_CMD_ID_EFUSE_FREE_BLOCK = 0x4F +} ENUM_EXT_CMD_ID_T, +*P_ENUM_EXT_CMD_ID_T; + +typedef enum _NDIS_802_11_WEP_STATUS { + Ndis802_11WEPEnabled, + Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled, + Ndis802_11WEPDisabled, + Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled, + Ndis802_11WEPKeyAbsent, + Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent, + Ndis802_11WEPNotSupported, + Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported, + Ndis802_11TKIPEnable, + Ndis802_11Encryption2Enabled = Ndis802_11TKIPEnable, + Ndis802_11Encryption2KeyAbsent, + Ndis802_11AESEnable, + Ndis802_11Encryption3Enabled = Ndis802_11AESEnable, + Ndis802_11CCMP256Enable, + Ndis802_11GCMP128Enable, + Ndis802_11GCMP256Enable, + Ndis802_11Encryption3KeyAbsent, + Ndis802_11TKIPAESMix, + Ndis802_11Encryption4Enabled = Ndis802_11TKIPAESMix, /* TKIP or AES mix + */ + Ndis802_11Encryption4KeyAbsent, + Ndis802_11GroupWEP40Enabled, + Ndis802_11GroupWEP104Enabled, +#ifdef WAPI_SUPPORT + Ndis802_11EncryptionSMS4Enabled, /* WPI SMS4 support */ +#endif +} NDIS_802_11_WEP_STATUS, +*PNDIS_802_11_WEP_STATUS, NDIS_802_11_ENCRYPTION_STATUS, +*PNDIS_802_11_ENCRYPTION_STATUS; + +#if CFG_SUPPORT_MU_MIMO +enum { + /* debug commands */ + MU_SET_ENABLE = 0, + MU_GET_ENABLE, + MU_SET_MUPROFILE_ENTRY, + MU_GET_MUPROFILE_ENTRY, + MU_SET_GROUP_TBL_ENTRY, + MU_GET_GROUP_TBL_ENTRY, + MU_SET_CLUSTER_TBL_ENTRY, + MU_GET_CLUSTER_TBL_ENTRY, + MU_SET_GROUP_USER_THRESHOLD, + MU_GET_GROUP_USER_THRESHOLD, + MU_SET_GROUP_NSS_THRESHOLD, + MU_GET_GROUP_NSS_THRESHOLD, + MU_SET_TXREQ_MIN_TIME, + MU_GET_TXREQ_MIN_TIME, + MU_SET_SU_NSS_CHECK, + MU_GET_SU_NSS_CHECK, + MU_SET_CALC_INIT_MCS, + MU_GET_CALC_INIT_MCS, + MU_SET_TXOP_DEFAULT, + MU_GET_TXOP_DEFAULT, + MU_SET_SU_LOSS_THRESHOLD, + MU_GET_SU_LOSS_THRESHOLD, + MU_SET_MU_GAIN_THRESHOLD, + MU_GET_MU_GAIN_THRESHOLD, + MU_SET_SECONDARY_AC_POLICY, + MU_GET_SECONDARY_AC_POLICY, + MU_SET_GROUP_TBL_DMCS_MASK, + MU_GET_GROUP_TBL_DMCS_MASK, + MU_SET_MAX_GROUP_SEARCH_CNT, + MU_GET_MAX_GROUP_SEARCH_CNT, + MU_GET_MU_PROFILE_TX_STATUS_CNT, + MU_SET_TRIGGER_MU_TX, + /* F/W flow test commands */ + MU_SET_TRIGGER_GID_MGMT_FRAME, + /* HQA commands */ + MU_HQA_SET_STA_PARAM, + MU_HQA_SET_ENABLE, + MU_HQA_SET_SNR_OFFSET, + MU_HQA_SET_ZERO_NSS, + MU_HQA_SET_SPEED_UP_LQ, + MU_HQA_SET_GROUP, + MU_HQA_SET_MU_TABLE, + MU_HQA_SET_CALC_LQ, + MU_HQA_GET_CALC_LQ, + MU_HQA_SET_CALC_INIT_MCS, + MU_HQA_GET_CALC_INIT_MCS, + MU_HQA_GET_QD, +}; +#endif +#endif + +typedef enum _ENUM_CMD_ID_T { + CMD_ID_DUMMY_RSV = 0x00, /* 0x00 (Set) */ + CMD_ID_TEST_CTRL = 0x01, /* 0x01 (Set) */ + CMD_ID_BASIC_CONFIG, /* 0x02 (Set) */ + CMD_ID_SCAN_REQ_V2, /* 0x03 (Set) */ + CMD_ID_NIC_POWER_CTRL, /* 0x04 (Set) */ + CMD_ID_POWER_SAVE_MODE, /* 0x05 (Set) */ + CMD_ID_LINK_ATTRIB, /* 0x06 (Set) */ + CMD_ID_ADD_REMOVE_KEY, /* 0x07 (Set) */ + CMD_ID_DEFAULT_KEY_ID, /* 0x08 (Set) */ + CMD_ID_INFRASTRUCTURE, /* 0x09 (Set) */ + CMD_ID_SET_RX_FILTER, /* 0x0a (Set) */ + CMD_ID_DOWNLOAD_BUF, /* 0x0b (Set) */ + CMD_ID_WIFI_START, /* 0x0c (Set) */ + CMD_ID_CMD_BT_OVER_WIFI, /* 0x0d (Set) */ + CMD_ID_SET_MEDIA_CHANGE_DELAY_TIME, /* 0x0e (Set) */ + CMD_ID_SET_DOMAIN_INFO, /* 0x0f (Set) */ + CMD_ID_SET_IP_ADDRESS, /* 0x10 (Set) */ + CMD_ID_BSS_ACTIVATE_CTRL, /* 0x11 (Set) */ + CMD_ID_SET_BSS_INFO, /* 0x12 (Set) */ + CMD_ID_UPDATE_STA_RECORD, /* 0x13 (Set) */ + CMD_ID_REMOVE_STA_RECORD, /* 0x14 (Set) */ + CMD_ID_INDICATE_PM_BSS_CREATED, /* 0x15 (Set) */ + CMD_ID_INDICATE_PM_BSS_CONNECTED, /* 0x16 (Set) */ + CMD_ID_INDICATE_PM_BSS_ABORT, /* 0x17 (Set) */ + CMD_ID_UPDATE_BEACON_CONTENT, /* 0x18 (Set) */ + CMD_ID_SET_BSS_RLM_PARAM, /* 0x19 (Set) */ + CMD_ID_SCAN_REQ, /* 0x1a (Set) */ + CMD_ID_SCAN_CANCEL, /* 0x1b (Set) */ + CMD_ID_CH_PRIVILEGE, /* 0x1c (Set) */ + CMD_ID_UPDATE_WMM_PARMS, /* 0x1d (Set) */ + CMD_ID_SET_WMM_PS_TEST_PARMS, /* 0x1e (Set) */ + CMD_ID_TX_AMPDU, /* 0x1f (Set) */ + CMD_ID_ADDBA_REJECT, /* 0x20 (Set) */ + CMD_ID_SET_PS_PROFILE_ADV, /* 0x21 (Set) */ + CMD_ID_SET_RAW_PATTERN, /* 0x22 (Set) */ + CMD_ID_CONFIG_PATTERN_FUNC, /* 0x23 (Set) */ + CMD_ID_SET_TX_PWR, /* 0x24 (Set) */ + CMD_ID_SET_PWR_PARAM, /* 0x25 (Set) */ + CMD_ID_P2P_ABORT, /* 0x26 (Set) */ + CMD_ID_SET_DBDC_PARMS = 0x28, /* 0x28 (Set) */ + + CMD_ID_KEEP_FULL_PWR = 0x2A, /* 0x2A (Set) */ + + /* SLT commands */ + CMD_ID_RANDOM_RX_RESET_EN = 0x2C, /* 0x2C (Set ) */ + CMD_ID_RANDOM_RX_RESET_DE = 0x2D, /* 0x2D (Set ) */ + CMD_ID_SAPP_EN = 0x2E, /* 0x2E (Set ) */ + CMD_ID_SAPP_DE = 0x2F, /* 0x2F (Set ) */ + + CMD_ID_ROAMING_TRANSIT = 0x30, /* 0x30 (Set) */ + CMD_ID_SET_PHY_PARAM, /* 0x31 (Set) */ + CMD_ID_SET_NOA_PARAM, /* 0x32 (Set) */ + CMD_ID_SET_OPPPS_PARAM, /* 0x33 (Set) */ + CMD_ID_SET_UAPSD_PARAM, /* 0x34 (Set) */ + CMD_ID_SET_SIGMA_STA_SLEEP, /* 0x35 (Set) */ + CMD_ID_SET_EDGE_TXPWR_LIMIT, /* 0x36 (Set) */ + CMD_ID_SET_DEVICE_MODE, /* 0x37 (Set) */ + CMD_ID_SET_TXPWR_CTRL, /* 0x38 (Set) */ + CMD_ID_SET_AUTOPWR_CTRL, /* 0x39 (Set) */ + CMD_ID_SET_WFD_CTRL, /* 0x3a (Set) */ + CMD_ID_SET_NLO_REQ, /* 0x3b (Set) */ + CMD_ID_SET_NLO_CANCEL, /* 0x3c (Set) */ + CMD_ID_SET_GTK_REKEY_DATA, /* 0x3d (Set) */ + CMD_ID_ROAMING_CONTROL, /* 0x3e (Set) */ + /* CFG_M0VE_BA_TO_DRIVER */ + CMD_ID_RESET_BA_SCOREBOARD = 0x3f, /* 0x3f (Set) */ + CMD_ID_SET_EDGE_TXPWR_LIMIT_5G = 0x40, /* 0x40 (Set) */ + CMD_ID_SET_CHANNEL_PWR_OFFSET, /* 0x41 (Set) */ + CMD_ID_SET_80211AC_TX_PWR, /* 0x42 (Set) */ + CMD_ID_SET_PATH_COMPASATION, /* 0x43 (Set) */ + + CMD_ID_SET_BATCH_REQ = 0x47, /* 0x47 (Set) */ + CMD_ID_SET_NVRAM_SETTINGS, /* 0x48 (Set) */ + CMD_ID_SET_COUNTRY_POWER_LIMIT, /* 0x49 (Set) */ + +#if CFG_WOW_SUPPORT + CMD_ID_SET_WOWLAN, /* 0x4a (Set) */ +#endif + + CMD_ID_CSI_CONTROL = 0x4c, /* 0x4c (Set /Query) */ + +#if CFG_SUPPORT_WIFI_HOST_OFFLOAD + CMD_ID_SET_AM_FILTER = 0x55, /* 0x55 (Set) */ + CMD_ID_SET_AM_HEARTBEAT, /* 0x56 (Set) */ + CMD_ID_SET_AM_TCP, /* 0x57 (Set) */ +#endif + CMD_ID_SET_SUSPEND_MODE = 0x58, /* 0x58 (Set) */ + +#if CFG_WOW_SUPPORT + CMD_ID_SET_PF_CAPABILITY = 0x59, /* 0x59 (Set) */ +#endif + +#if CFG_STR_DHCP_RENEW_OFFLOAD + CMD_ID_SET_DHCP_RENEW_OFFLOAD = 0x5A, /* 0x5A (Set) */ +#endif + +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP + CMD_ID_SET_ROAMING_SKIP = 0x6D, /* 0x6D (Set) used to setting roaming + * skip*/ +#endif + CMD_ID_GET_SET_CUSTOMER_CFG = 0x70, /* 0x70(Set) */ + CMD_ID_COEX_CTRL = 0x7C, /* 0x7C (Set/Query) */ + CMD_ID_GET_NIC_CAPABILITY = 0x80, /* 0x80 (Query) */ + CMD_ID_GET_LINK_QUALITY, /* 0x81 (Query) */ + CMD_ID_GET_STATISTICS, /* 0x82 (Query) */ + CMD_ID_GET_CONNECTION_STATUS, /* 0x83 (Query) */ + CMD_ID_GET_STA_STATISTICS = 0x85, /* 0x85 (Query) */ + + CMD_ID_GET_LTE_CHN = 0x87, /* 0x87 (Query) */ + CMD_ID_GET_CHN_LOADING = 0x88, /* 0x88 (Query) */ + CMD_ID_GET_BUG_REPORT = 0x89, /* 0x89 (Query) */ + CMD_ID_GET_NIC_CAPABILITY_V2 = 0x8A, /* 0x8A (Query) */ + CMD_ID_GET_TEMPERATURE = 0x8C, /* 0x8B (Query) */ + +#if (CFG_SUPPORT_DFS_MASTER == 1) + CMD_ID_RDD_ON_OFF_CTRL = 0x8F, /* 0x8F(Set) */ +#endif + +#ifdef CFG_SUPPORT_ANT_DIV + CMD_ID_ANT_DIV_CTRL = 0x91, +#endif + + CMD_ID_ACCESS_REG = 0xc0, /* 0xc0 (Set / Query) */ + CMD_ID_MAC_MCAST_ADDR, /* 0xc1 (Set / Query) */ + CMD_ID_802_11_PMKID, /* 0xc2 (Set / Query) */ + CMD_ID_ACCESS_EEPROM, /* 0xc3 (Set / Query) */ + CMD_ID_SW_DBG_CTRL, /* 0xc4 (Set / Query) */ + CMD_ID_FW_LOG_2_HOST, /* 0xc5 (Set) */ + CMD_ID_DUMP_MEM, /* 0xc6 (Query) */ + CMD_ID_RESOURCE_CONFIG, /* 0xc7 (Set / Query) */ +#if CFG_SUPPORT_QA_TOOL + CMD_ID_ACCESS_RX_STAT, /* 0xc8 (Query) */ +#endif + CMD_ID_CHIP_CONFIG = 0xCA, /* 0xca (Set / Query) */ + CMD_ID_STATS_LOG = 0xCB, /* 0xcb (Set) */ + + CMD_ID_WLAN_INFO = 0xCD, /* 0xcd (Query) */ + CMD_ID_MIB_INFO = 0xCE, /* 0xce (Query) */ + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO + CMD_ID_TX_MCS_INFO = 0xCF, /* 0xcf (Query) */ +#endif +#ifdef CFG_DUMP_TXPOWR_TABLE + CMD_ID_GET_TXPWR_TBL = 0xD0, /* 0xd0 (Query) */ +#endif + + CMD_ID_SET_RDD_CH = 0xE1, + +#if CFG_SUPPORT_QA_TOOL + CMD_ID_LAYER_0_EXT_MAGIC_NUM = 0xED, /* magic number for Extending + * MT6630 original CMD header */ +#endif + + CMD_ID_SET_BWCS = 0xF1, + CMD_ID_SET_OSC = 0xF2, + + CMD_ID_HIF_CTRL = 0xF6, /* 0xF6 (Set) */ + + CMD_ID_GET_BUILD_DATE_CODE = 0xF8, /* 0xf8 (Query) */ + CMD_ID_GET_BSS_INFO = 0xF9, /* 0xF9 (Query) */ + CMD_ID_SET_HOTSPOT_OPTIMIZATION = 0xFA, /* 0xFA (Set) */ + CMD_ID_SET_TDLS_CH_SW = 0xFB, + CMD_ID_SET_MONITOR = 0xFC, /* 0xFC (Set) */ +#if CFG_SUPPORT_ADVANCE_CONTROL + CMD_ID_ADV_CONTROL = 0xFE, /* 0xFE (Set / Query) */ +#endif + CMD_ID_END +} ENUM_CMD_ID_T, +*P_ENUM_CMD_ID_T; + +typedef enum _ENUM_EVENT_ID_T { + EVENT_ID_NIC_CAPABILITY = 0x01, /* 0x01 (Query) */ + EVENT_ID_LINK_QUALITY, /* 0x02 (Query / Unsolicited) */ + EVENT_ID_STATISTICS, /* 0x03 (Query) */ + EVENT_ID_MIC_ERR_INFO, /* 0x04 (Unsolicited) */ + EVENT_ID_ACCESS_REG, /* 0x05 (Query - CMD_ID_ACCESS_REG) */ + EVENT_ID_ACCESS_EEPROM, /* 0x06 (Query - CMD_ID_ACCESS_EEPROM) */ + EVENT_ID_SLEEPY_INFO, /* 0x07 (Unsolicited) */ + EVENT_ID_BT_OVER_WIFI, /* 0x08 (Unsolicited) */ + EVENT_ID_TEST_STATUS, /* 0x09 (Query - CMD_ID_TEST_CTRL) */ + EVENT_ID_RX_ADDBA, /* 0x0a (Unsolicited) */ + EVENT_ID_RX_DELBA, /* 0x0b (Unsolicited) */ + EVENT_ID_ACTIVATE_STA_REC, /* 0x0c (Response) */ + EVENT_ID_SCAN_DONE, /* 0x0d (Unsoiicited) */ + EVENT_ID_RX_FLUSH, /* 0x0e (Unsolicited) */ + EVENT_ID_TX_DONE, /* 0x0f (Unsolicited) */ + EVENT_ID_CH_PRIVILEGE, /* 0x10 (Unsolicited) */ + EVENT_ID_BSS_ABSENCE_PRESENCE, /* 0x11 (Unsolicited) */ + EVENT_ID_STA_CHANGE_PS_MODE, /* 0x12 (Unsolicited) */ + EVENT_ID_BSS_BEACON_TIMEOUT, /* 0x13 (Unsolicited) */ + EVENT_ID_UPDATE_NOA_PARAMS, /* 0x14 (Unsolicited) */ + EVENT_ID_AP_OBSS_STATUS, /* 0x15 (Unsolicited) */ + EVENT_ID_STA_UPDATE_FREE_QUOTA, /* 0x16 (Unsolicited) */ + EVENT_ID_SW_DBG_CTRL, /* 0x17 (Query - CMD_ID_SW_DBG_CTRL) */ + EVENT_ID_ROAMING_STATUS, /* 0x18 (Unsolicited) */ + EVENT_ID_STA_AGING_TIMEOUT, /* 0x19 (Unsolicited) */ + EVENT_ID_SEC_CHECK_RSP, /* 0x1a (Query - CMD_ID_SEC_CHECK) */ + EVENT_ID_SEND_DEAUTH, /* 0x1b (Unsolicited) */ + EVENT_ID_UPDATE_RDD_STATUS, /* 0x1c (Unsolicited) */ + EVENT_ID_UPDATE_BWCS_STATUS, /* 0x1d (Unsolicited) */ + EVENT_ID_UPDATE_BCM_DEBUG, /* 0x1e (Unsolicited) */ + EVENT_ID_RX_ERR, /* 0x1f (Unsolicited) */ + EVENT_ID_DUMP_MEM = 0x20, /* 0x20 (Query - CMD_ID_DUMP_MEM) */ + EVENT_ID_STA_STATISTICS, /* 0x21 (Query ) */ + EVENT_ID_STA_STATISTICS_UPDATE, /* 0x22 (Unsolicited) */ + EVENT_ID_NLO_DONE, /* 0x23 (Unsoiicited) */ + EVENT_ID_ADD_PKEY_DONE, /* 0x24 (Unsoiicited) */ + EVENT_ID_ICAP_DONE, /* 0x25 (Unsoiicited) */ + EVENT_ID_RESOURCE_CONFIG = 0x26, /* 0x26 (Query - + * CMD_ID_RESOURCE_CONFIG) */ + EVENT_ID_DEBUG_MSG = 0x27, /* 0x27 (Unsoiicited) */ + EVENT_ID_RTT_CALIBR_DONE = 0x28, /* 0x28 (Unsoiicited) */ + EVENT_ID_RTT_UPDATE_RANGE = 0x29, /* 0x29 (Unsoiicited) */ + EVENT_ID_CHECK_REORDER_BUBBLE = 0x2a, /* 0x2a (Unsoiicited) */ + EVENT_ID_BATCH_RESULT = 0x2b, /* 0x2b (Query) */ + + EVENT_ID_CSI_DATA = 0x3c, /* 0x3c (Query) */ + EVENT_ID_GET_GTK_REKEY_DATA = 0x3d, /* 0x3d (Query) */ + + EVENT_ID_UART_ACK = 0x40, /* 0x40 (Unsolicited) */ + EVENT_ID_UART_NAK, /* 0x41 (Unsolicited) */ + EVENT_ID_GET_CHIPID, /* 0x42 (Query - CMD_ID_GET_CHIPID) */ + EVENT_ID_SLT_STATUS, /* 0x43 (Query - CMD_ID_SET_SLTINFO) */ + EVENT_ID_CHIP_CONFIG, /* 0x44 (Query - CMD_ID_CHIP_CONFIG) */ +#if CFG_SUPPORT_QA_TOOL + EVENT_ID_ACCESS_RX_STAT, /* 0x45 (Query - CMD_ID_ACCESS_RX_STAT) */ +#endif + + EVENT_ID_RDD_SEND_PULSE = 0x50, + +#if CFG_SUPPORT_TX_BF + EVENT_ID_PFMU_TAG_READ = 0x51, + EVENT_ID_PFMU_DATA_READ = 0x52, +#endif + +#if CFG_SUPPORT_MU_MIMO + EVENT_ID_MU_GET_QD = 0x53, + EVENT_ID_MU_GET_LQ = 0x54, +#endif + +#if (CFG_SUPPORT_DFS_MASTER == 1) + EVENT_ID_RDD_REPORT = 0x60, + EVENT_ID_CSA_DONE = 0x61, +#endif + +#if (CFG_WOW_SUPPORT == 1) + EVENT_ID_WOW_WAKEUP_REASON = 0x62, +#endif + + EVENT_ID_TDLS = 0x80, /* TDLS event_id */ + EVENT_ID_GET_TEMPERATURE = 0x8C, + + EVENT_ID_UPDATE_COEX_PHYRATE = 0x90, /* 0x90 (Unsolicited) */ + + EVENT_ID_WLAN_INFO = 0xCD, + EVENT_ID_MIB_INFO = 0xCE, + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO + EVENT_ID_TX_MCS_INFO = 0xCF, +#endif +#ifdef CFG_DUMP_TXPOWR_TABLE + EVENT_ID_GET_TXPWR_TBL = 0xD0, +#endif + + EVENT_ID_NIC_CAPABILITY_V2 = 0xEC, /* 0xEC (Query - + * CMD_ID_GET_NIC_CAPABILITY_V2) */ + /*#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1)*/ + EVENT_ID_LAYER_0_EXT_MAGIC_NUM = 0xED, /* magic number for Extending + * MT6630 original EVENT header + */ +/*#endif*/ + +#if CFG_ASSERT_DUMP + EVENT_ID_ASSERT_DUMP = 0xF0, +#endif + EVENT_ID_HIF_CTRL = 0xF6, + EVENT_ID_BUILD_DATE_CODE = 0xF8, + EVENT_ID_GET_AIS_BSS_INFO = 0xF9, + EVENT_ID_DEBUG_CODE = 0xFB, + EVENT_ID_RFTEST_READY = 0xFC, /* 0xFC */ +#if CFG_SUPPORT_ADVANCE_CONTROL + EVENT_ID_ADV_CONTROL = 0xFE, +#endif + EVENT_ID_END +} ENUM_EVENT_ID_T, +*P_ENUM_EVENT_ID_T; + +#if CFG_WOW_SUPPORT + +/* Filter Flag */ +#define WOWLAN_FF_DROP_ALL BIT(0) +#define WOWLAN_FF_SEND_MAGIC_TO_HOST BIT(1) +#define WOWLAN_FF_ALLOW_ARP BIT(2) +#define WOWLAN_FF_ALLOW_BMC BIT(3) +#define WOWLAN_FF_ALLOW_UC BIT(4) +#define WOWLAN_FF_ALLOW_1X BIT(5) +#define WOWLAN_FF_ALLOW_ARP_REQ2ME BIT(6) + +/* wow detect type */ +#define WOWLAN_DETECT_TYPE_MAGIC BIT(0) +#define WOWLAN_DETECT_TYPE_ALLOW_NORMAL BIT(1) +#define WOWLAN_DETECT_TYPE_ONLY_PHONE_SUSPEND BIT(2) +#define WOWLAN_DETECT_TYPE_DISASSOCIATION BIT(3) +#define WOWLAN_DETECT_TYPE_BCN_LOST BIT(4) + +/* Wakeup command bit define */ +#define PF_WAKEUP_CMD_BIT0_OUTPUT_MODE_EN BIT(0) +#define PF_WAKEUP_CMD_BIT1_OUTPUT_DATA BIT(1) +#define PF_WAKEUP_CMD_BIT2_WAKEUP_LEVEL BIT(2) + +#define PM_WOWLAN_REQ_START 0x1 +#define PM_WOWLAN_REQ_STOP 0x2 + +typedef struct _CMD_WAKE_HIF_T { + u8 ucWakeupHif; /* use in-band signal to wakeup system, ENUM_HIF_TYPE */ + u8 ucGpioPin; /* GPIO Pin */ + u8 ucTriggerLvl; /* GPIO Pin */ + u8 aucResv1[1]; + u32 u4GpioInterval; /* 0: low to high, 1: high to low */ + u8 aucResv2[4]; +} CMD_WAKE_HIF_T, *P_CMD_WAKE_HIF_T; + +typedef struct _CMD_WOWLAN_PARAM_T { + u8 ucCmd; + u8 ucDetectType; + u16 u2FilterFlag; /* ARP/MC/DropExceptMagic/SendMagicToHost */ + u8 ucScenarioID; /* WOW/WOBLE/Proximity */ + u8 ucBlockCount; + u8 ucDbdcBand; + u8 aucReserved1[1]; + CMD_WAKE_HIF_T astWakeHif[2]; + WOW_PORT_T stWowPort; + u8 aucReserved2[32]; +} CMD_WOWLAN_PARAM_T, *P_CMD_WOWLAN_PARAM_T; + +typedef struct _EVENT_WOWLAN_NOTIFY_T { + u8 ucNetTypeIndex; + u8 aucReserved[3]; +} EVENT_WOWLAN_NOTIFY_T, *P_EVENT_WOWLAN_NOTIFY_T; + +/* PACKETFILTER CAPABILITY TYPE */ + +#define PACKETF_CAP_TYPE_ARP BIT(1) +#define PACKETF_CAP_TYPE_MAGIC BIT(2) +#define PACKETF_CAP_TYPE_BITMAP BIT(3) +#define PACKETF_CAP_TYPE_EAPOL BIT(4) +#define PACKETF_CAP_TYPE_TDLS BIT(5) +#define PACKETF_CAP_TYPE_CF BIT(6) +#define PACKETF_CAP_TYPE_HEARTBEAT BIT(7) +#define PACKETF_CAP_TYPE_TCP_SYN BIT(8) +#define PACKETF_CAP_TYPE_UDP_SYN BIT(9) +#define PACKETF_CAP_TYPE_BCAST_SYN BIT(10) +#define PACKETF_CAP_TYPE_MCAST_SYN BIT(11) +#define PACKETF_CAP_TYPE_V6 BIT(12) +#define PACKETF_CAP_TYPE_TDIM BIT(13) + +typedef enum _ENUM_FUNCTION_SELECT { + FUNCTION_PF = 1, + FUNCTION_BITMAP = 2, + FUNCTION_EAPOL = 3, + FUNCTION_TDLS = 4, + FUNCTION_ARPNS = 5, + FUNCTION_CF = 6, + FUNCTION_MODE = 7, + FUNCTION_BSSID = 8, + FUNCTION_MGMT = 9, + FUNCTION_BMC_DROP = 10, + FUNCTION_UC_DROP = 11, + FUNCTION_ALL_TOMCU = 12, +} _ENUM_FUNCTION_SELECT, +*P_ENUM_FUNCTION_SELECT; + +typedef enum _ENUM_PF_OPCODE_T { + PF_OPCODE_ADD = 0, + PF_OPCODE_DEL, + PF_OPCODE_ENABLE, + PF_OPCODE_DISABLE, + PF_OPCODE_NUM +} ENUM_PF_OPCODE_T; + +typedef struct _CMD_PACKET_FILTER_CAP_T { + u8 ucCmd; + u16 packet_cap_type; + u8 aucReserved1[1]; + /* GLOBAL */ + u32 PFType; + u32 FunctionSelect; + u32 Enable; + /* MAGIC */ + u8 ucBssid; + u16 usEnableBits; + u8 aucReserved5[1]; + /* DTIM */ + u8 DtimEnable; + u8 DtimValue; + u8 aucReserved2[2]; + /* BITMAP_PATTERN_T */ + u32 Index; + u32 Offset; + u32 FeatureBits; + u32 Resv; + u32 PatternLength; + u32 Mask[4]; + u32 Pattern[32]; + /* COALESCE */ + u32 FilterID; + u32 PacketType; + u32 CoalesceOP; + u8 FieldLength; + u8 CompareOP; + u8 FieldID; + u8 aucReserved3[1]; + u32 Pattern3[4]; + /* TCPSYN */ + u32 AddressType; + u32 TCPSrcPort; + u32 TCPDstPort; + u32 SourceIP[4]; + u32 DstIP[4]; + u8 aucReserved4[64]; +} CMD_PACKET_FILTER_CAP_T, *P_CMD_PACKET_FILTER_CAP_T; +#endif + +#if CFG_SUPPORT_WIFI_HOST_OFFLOAD +typedef struct _CMD_TCP_GENERATOR { + ENUM_PF_OPCODE_T eOpcode; + u32 u4ReplyId; + u32 u4Period; + u32 u4Timeout; + u32 u4IpId; + u32 u4DestPort; + u32 u4SrcPort; + u32 u4Seq; + u8 aucDestIp[4]; + u8 aucSrcIp[4]; + u8 aucDestMac[6]; + u8 ucBssId; + u8 aucReserved1[1]; + u8 aucReserved2[64]; +} CMD_TCP_GENERATOR, *P_CMD_TCP_GENERATOR; + +typedef struct _CMD_PATTERN_GENERATOR { + ENUM_PF_OPCODE_T eOpcode; + u32 u4ReplyId; + u32 u4EthernetLength; + u32 u4Period; + u8 aucEthernetFrame[128]; + u8 ucBssId; + u8 aucReserved1[3]; + u8 aucReserved2[64]; +} CMD_PATTERN_GENERATOR, *P_CMD_PATTERN_GENERATOR; + +typedef struct _CMD_BITMAP_FILTER { + ENUM_PF_OPCODE_T eOpcode; + u32 u4ReplyId; + u32 u4Offset; + u32 u4Length; + u8 aucPattern[64]; + u8 aucBitMask[64]; + u8 fgIsEqual; + u8 fgIsAccept; + u8 ucBssId; + u8 aucReserved1[1]; + u8 aucReserved2[64]; +} CMD_BITMAP_FILTER, *P_CMD_BITMAP_FILTER; + +#endif + +#if CFG_SUPPORT_PER_BSS_FILTER +typedef struct _CMD_RX_PACKET_FILTER { + u32 u4RxPacketFilter; + u8 ucIsPerBssFilter; + u8 ucBssIndex; + u8 aucReserved[2]; + u32 u4BssMgmtFilter; + u8 aucReserved2[56]; +} CMD_RX_PACKET_FILTER, *P_CMD_RX_PACKET_FILTER; +#else +typedef struct _CMD_RX_PACKET_FILTER { + u32 u4RxPacketFilter; + u8 aucReserved[64]; +} CMD_RX_PACKET_FILTER, *P_CMD_RX_PACKET_FILTER; +#endif + +#if defined(MT6632) +#define S2D_INDEX_CMD_H2N 0x0 +#define S2D_INDEX_CMD_C2N 0x1 +#define S2D_INDEX_CMD_H2C 0x2 +#define S2D_INDEX_CMD_H2N_H2C 0x3 + +#define S2D_INDEX_EVENT_N2H 0x0 +#define S2D_INDEX_EVENT_N2C 0x1 +#define S2D_INDEX_EVENT_C2H 0x2 +#define S2D_INDEX_EVENT_N2H_N2C 0x3 +#endif + +#define EXT_EVENT_ID_CMD_RESULT 0x00 + +/*#if (CFG_EEPROM_PAGE_ACCESS == 1)*/ +#define EXT_EVENT_ID_CMD_EFUSE_ACCESS 0x1 +#define EXT_EVENT_ID_EFUSE_FREE_BLOCK 0x4D +#define EXT_EVENT_ID_GET_TX_POWER 0x1C +#define EXT_EVENT_TARGET_TX_POWER 0x1 + +/*#endif*/ +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* for Event Packet (via HIF-RX) */ +typedef struct _PSE_CMD_HDR_T { + /* DW0 */ + u16 u2TxByteCount; + u16 u2Reserved1 : 10; + u16 u2Qidx : 5; + u16 u2Pidx : 1; + + /* DW1 */ + u16 u2Reserved2 : 13; + u16 u2Hf : 2; + u16 u2Ft : 1; + u16 u2Reserved3 : 8; + u16 u2PktFt : 2; + u16 u2Reserved4 : 6; + + /* DW2~7 */ + u32 au4Reserved[6]; +} PSE_CMD_HDR_T, *P_PSE_CMD_HDR_T; + +typedef struct _WIFI_CMD_T { + u16 u2TxByteCount; /* Max value is over 2048 */ + u16 u2PQ_ID; /* Must be 0x8000 (Port1, Queue 0) */ + + u8 ucWlanIdx; + u8 ucHeaderFormat; + u8 ucHeaderPadding; + u8 ucPktFt : 2; + u8 ucOwnMAC : 6; + u32 au4Reserved1[6]; + + u16 u2Length; + u16 u2PqId; + + u8 ucCID; + u8 ucPktTypeID; /* Must be 0x20 (CMD Packet) */ + u8 ucSetQuery; + u8 ucSeqNum; + + u8 ucD2B0Rev; /* padding fields, hw may auto modify this field */ + u8 ucExtenCID; /* Extend CID */ + u8 ucS2DIndex; /* Index for Src to Dst in CMD usage */ + u8 ucExtCmdOption; /* Extend CID option */ + + u8 ucCmdVersion; + u8 ucReserved2[3]; + u32 au4Reserved3[4]; /* padding fields */ + + u8 aucBuffer[0]; +} WIFI_CMD_T, *P_WIFI_CMD_T; + +/* for Command Packet (via HIF-TX) */ +/* following CM's documentation v0.7 */ +typedef struct _WIFI_EVENT_T { + u32 au4HwMacRxDesc[4]; + + u16 u2PacketLength; + u16 u2PacketType; /* Must be filled with 0xE000 (EVENT Packet) */ + u8 ucEID; + u8 ucSeqNum; + u8 ucEventVersion; + u8 aucReserved[1]; + + u8 ucExtenEID; + u8 aucReserved2[2]; + u8 ucS2DIndex; + + u8 aucBuffer[]; +} WIFI_EVENT_T, *P_WIFI_EVENT_T; + +/* CMD_ID_TEST_CTRL */ +typedef struct _CMD_TEST_CTRL_T { + u8 ucAction; + u8 aucReserved[3]; + union { + u32 u4OpMode; + u32 u4ChannelFreq; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + } u; +} CMD_TEST_CTRL_T, *P_CMD_TEST_CTRL_T; + +/* EVENT_TEST_STATUS */ +typedef struct _PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T { + u32 u4PktSentStatus; + u32 u4PktSentCount; + u16 u2AvgAlc; + u8 ucCckGainControl; + u8 ucOfdmGainControl; +} PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T, +*P_PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T; + +typedef struct _PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T { + u32 u4IntRxOk; /*!< number of packets that Rx ok from interrupt */ + u32 u4IntCrcErr; /*!< number of packets that CRC error from interrupt */ + u32 u4IntShort; /*!< number of packets that is short preamble from + * interrupt */ + u32 u4IntLong; /*!< number of packets that is long preamble from + * interrupt */ + u32 u4PauRxPktCount; /*!< number of packets that Rx ok from PAU */ + u32 u4PauCrcErrCount; /*!< number of packets that CRC error from PAU */ + u32 u4PauRxFifoFullCount; /*!< number of packets that is short preamble + * from PAU */ + u32 u4PauCCACount; /*!< CCA rising edge count */ +} PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T, +*P_PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T; + +typedef union _EVENT_TEST_STATUS { + PARAM_MTK_WIFI_TEST_STRUCT_T rATInfo; + /* PARAM_CUSTOM_RFTEST_TX_STATUS_STRUCT_T rTxStatus; */ + /* PARAM_CUSTOM_RFTEST_RX_STATUS_STRUCT_T rRxStatus; */ +} EVENT_TEST_STATUS, *P_EVENT_TEST_STATUS; + +/* CMD_BUILD_CONNECTION */ +typedef struct _CMD_BUILD_CONNECTION { + u8 ucInfraMode; + u8 ucAuthMode; + u8 ucEncryptStatus; + u8 ucSsidLen; + u8 aucSsid[PARAM_MAX_LEN_SSID]; + u8 aucBssid[PARAM_MAC_ADDR_LEN]; + + /* Ad-hoc mode */ + u16 u2BeaconPeriod; + u16 u2ATIMWindow; + u8 ucJoinOnly; + u8 ucReserved; + u32 u4FreqInKHz; + + /* for faster connection */ + u8 aucScanResult[0]; +} CMD_BUILD_CONNECTION, *P_CMD_BUILD_CONNECTION; + +/* CMD_ADD_REMOVE_KEY */ +typedef struct _CMD_802_11_KEY { + u8 ucAddRemove; + u8 ucTxKey; + u8 ucKeyType; + u8 ucIsAuthenticator; + u8 aucPeerAddr[6]; + u8 ucBssIdx; + u8 ucAlgorithmId; + u8 ucKeyId; + u8 ucKeyLen; + u8 ucWlanIndex; + u8 ucMgmtProtection; + u8 aucKeyMaterial[32]; + u8 aucKeyRsc[16]; +} CMD_802_11_KEY, *P_CMD_802_11_KEY; + +/* CMD_ID_DEFAULT_KEY_ID */ +typedef struct _CMD_DEFAULT_KEY { + u8 ucBssIdx; + u8 ucKeyId; + u8 ucWlanIndex; + u8 ucMulticast; +} CMD_DEFAULT_KEY, *P_CMD_DEFAULT_KEY; + +/* WPA2 PMKID cache structure */ +typedef struct _PMKID_ENTRY_T { + PARAM_BSSID_INFO_T rBssidInfo; + u8 fgPmkidExist; +} PMKID_ENTRY_T, *P_PMKID_ENTRY_T; + +typedef struct _CMD_802_11_PMKID { + u32 u4BSSIDInfoCount; + P_PMKID_ENTRY_T arPMKIDInfo[1]; +} CMD_802_11_PMKID, *P_CMD_802_11_PMKID; + +typedef struct _CMD_GTK_REKEY_DATA_T { + u8 aucKek[16]; + u8 aucKck[16]; + u8 aucReplayCtr[8]; +} CMD_GTK_REKEY_DATA_T, *P_CMD_GTK_REKEY_DATA_T; + +typedef struct _CMD_CSUM_OFFLOAD_T { + u16 u2RxChecksum; /* bit0: IP, bit1: UDP, bit2: TCP */ + u16 u2TxChecksum; /* bit0: IP, bit1: UDP, bit2: TCP */ +} CMD_CSUM_OFFLOAD_T, *P_CMD_CSUM_OFFLOAD_T; + +/* CMD_BASIC_CONFIG */ +typedef struct _CMD_BASIC_CONFIG_T { + u8 ucNative80211; + u8 ucCtrlFlagAssertPath; + u8 ucCtrlFlagDebugLevel; + u8 aucReserved[1]; + CMD_CSUM_OFFLOAD_T rCsumOffload; + u8 ucCrlFlagSegememt; + u8 aucReserved2[3]; +} CMD_BASIC_CONFIG_T, *P_CMD_BASIC_CONFIG_T; + +/* CMD_MAC_MCAST_ADDR */ +typedef struct _CMD_MAC_MCAST_ADDR { + u32 u4NumOfGroupAddr; + u8 ucBssIndex; + u8 aucReserved[3]; + PARAM_MAC_ADDRESS arAddress[MAX_NUM_GROUP_ADDR]; +} CMD_MAC_MCAST_ADDR, *P_CMD_MAC_MCAST_ADDR, EVENT_MAC_MCAST_ADDR, +*P_EVENT_MAC_MCAST_ADDR; + +/* CMD_ACCESS_EEPROM */ +typedef struct _CMD_ACCESS_EEPROM { + u16 u2Offset; + u16 u2Data; +} CMD_ACCESS_EEPROM, *P_CMD_ACCESS_EEPROM, EVENT_ACCESS_EEPROM, +*P_EVENT_ACCESS_EEPROM; + +typedef struct _CMD_CUSTOM_NOA_PARAM_STRUCT_T { + u32 u4NoaDurationMs; + u32 u4NoaIntervalMs; + u32 u4NoaCount; + u8 ucBssIdx; + u8 aucReserved[3]; +} CMD_CUSTOM_NOA_PARAM_STRUCT_T, *P_CMD_CUSTOM_NOA_PARAM_STRUCT_T; + +typedef struct _CMD_CUSTOM_OPPPS_PARAM_STRUCT_T { + u32 u4CTwindowMs; + u8 ucBssIdx; + u8 aucReserved[3]; +} CMD_CUSTOM_OPPPS_PARAM_STRUCT_T, *P_CMD_CUSTOM_OPPPS_PARAM_STRUCT_T; + +typedef struct _CMD_CUSTOM_UAPSD_PARAM_STRUCT_T { + u8 fgEnAPSD; + u8 fgEnAPSD_AcBe; + u8 fgEnAPSD_AcBk; + u8 fgEnAPSD_AcVo; + u8 fgEnAPSD_AcVi; + u8 ucMaxSpLen; + u8 aucResv[2]; +} CMD_CUSTOM_UAPSD_PARAM_STRUCT_T, *P_CMD_CUSTOM_UAPSD_PARAM_STRUCT_T; + +/* EVENT_CONNECTION_STATUS */ +typedef struct _EVENT_CONNECTION_STATUS { + u8 ucMediaStatus; + u8 ucReasonOfDisconnect; + + u8 ucInfraMode; + u8 ucSsidLen; + u8 aucSsid[PARAM_MAX_LEN_SSID]; + u8 aucBssid[PARAM_MAC_ADDR_LEN]; + u8 ucAuthenMode; + u8 ucEncryptStatus; + u16 u2BeaconPeriod; + u16 u2AID; + u16 u2ATIMWindow; + u8 ucNetworkType; + u8 aucReserved[1]; + u32 u4FreqInKHz; + +#if CFG_ENABLE_WIFI_DIRECT + u8 aucInterfaceAddr[PARAM_MAC_ADDR_LEN]; +#endif +} EVENT_CONNECTION_STATUS, *P_EVENT_CONNECTION_STATUS; + +/* EVENT_NIC_CAPABILITY */ +typedef struct _EVENT_NIC_CAPABILITY_T { + u16 u2ProductID; + u16 u2FwVersion; + u16 u2DriverVersion; + u8 ucHw5GBandDisabled; + u8 ucEepromUsed; + u8 aucMacAddr[6]; + u8 ucEndianOfMacAddrNumber; + u8 ucHwNotSupportAC; + + u8 ucRfVersion; + u8 ucPhyVersion; + u8 ucRfCalFail; + u8 ucBbCalFail; + u8 aucDateCode[16]; + u32 u4FeatureFlag0; + u32 u4FeatureFlag1; + u32 u4CompileFlag0; + u32 u4CompileFlag1; + u8 aucBranchInfo[4]; + u8 ucFwBuildNumber; + u8 ucHwSetNss1x1; + u8 ucHwNotSupportDBDC; + u8 ucHwWiFiZeroOnly; + u8 aucReserved1[56]; +} EVENT_NIC_CAPABILITY_T, *P_EVENT_NIC_CAPABILITY_T; + +typedef struct _EVENT_NIC_CAPABILITY_V2_T { + u16 u2TotalElementNum; + u8 aucReserved[2]; + u8 aucBuffer[]; +} EVENT_NIC_CAPABILITY_V2_T, *P_EVENT_NIC_CAPABILITY_V2_T; + +typedef struct _NIC_CAPABILITY_V2_ELEMENT { + u32 tag_type; /* NIC_CAPABILITY_V2_TAG_T */ + u32 body_len; + u8 aucbody[]; +} NIC_CAPABILITY_V2_ELEMENT, *P_NIC_CAPABILITY_V2_ELEMENT; + +typedef WLAN_STATUS (*NIC_CAP_V2_ELEMENT_HDLR)(P_ADAPTER_T prAdapter, + u8 *buff, + u32 buff_len); +typedef struct _NIC_CAPABILITY_V2_REF_TABLE_T { + u32 tag_type; /* NIC_CAPABILITY_V2_TAG_T */ + NIC_CAP_V2_ELEMENT_HDLR hdlr; +} NIC_CAPABILITY_V2_REF_TABLE_T, *P_NIC_CAPABILITY_V2_REF_TABLE_T; + +typedef enum _NIC_CAPABILITY_V2_TAG_T { + TAG_CAP_TX_RESOURCE = 0x0, + TAG_CAP_TX_EFUSEADDRESS = 0x1, + TAG_CAP_COEX_FEATURE = 0x2, + TAG_CAP_SINGLE_SKU = 0x3, +#if CFG_TCP_IP_CHKSUM_OFFLOAD + TAG_CAP_CSUM_OFFLOAD = 0x4, +#endif + TAG_CAP_EFUSE_OFFSET = 0x5, + TAG_CAP_TOTAL +} NIC_CAPABILITY_V2_TAG_T; + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +typedef struct _NIC_CSUM_OFFLOAD_T { + u8 ucIsSupportCsumOffload; /* 1: Support, 0: Not Support */ + u8 acReseved[3]; +} NIC_CSUM_OFFLOAD_T, *P_NIC_CSUM_OFFLOAD_T; +#endif + +typedef struct _NIC_COEX_FEATURE_T { + u32 u4FddMode; /* true for COEX FDD mode */ +} NIC_COEX_FEATURE_T, *P_NIC_COEX_FEATURE_T; + +typedef struct _NIC_EFUSE_ADDRESS_T { + u32 u4EfuseStartAddress; /* Efuse Start Address */ + u32 u4EfuseEndAddress; /* Efuse End Address */ +} NIC_EFUSE_ADDRESS_T, *P_NIC_EFUSE_ADDRESS_T; + +struct _NIC_EFUSE_OFFSET_T { + u32 u4TotalItem; /* Efuse offset items */ + u32 u4WlanMacAddr; /* Efuse Offset 1 */ +}; + +typedef struct _NIC_TX_RESOURCE_T { + u32 u4McuTotalResource; /* the total usable resource for MCU port */ + u32 u4McuResourceUnit; /* the unit of a MCU resource */ + u32 u4LmacTotalResource; /* the total usable resource for LMAC port */ + u32 u4LmacResourceUnit; /* the unit of a LMAC resource */ +} NIC_TX_RESOURCE_T, *P_NIC_TX_RESOURCE_T; + +/* modified version of WLAN_BEACON_FRAME_BODY_T for simplier buffering */ +typedef struct _WLAN_BEACON_FRAME_BODY_T_LOCAL { + /* Beacon frame body */ + u32 au4Timestamp[2]; /* Timestamp */ + u16 u2BeaconInterval; /* Beacon Interval */ + u16 u2CapInfo; /* Capability */ + u8 aucInfoElem[MAX_IE_LENGTH]; /* Various IEs, start from SSID */ + u16 u2IELength; /* This field is *NOT* carried by F/W but caculated by + * nic_rx */ +} WLAN_BEACON_FRAME_BODY_T_LOCAL, *P_WLAN_BEACON_FRAME_BODY_T_LOCAL; + +/* EVENT_SCAN_RESULT */ +typedef struct _EVENT_SCAN_RESULT_T { + s32 i4RSSI; + u32 u4LinkQuality; + u32 u4DSConfig; /* Center frequency */ + u32 u4DomainInfo; /* Require CM opinion */ + u32 u4Reserved; + u8 ucNetworkType; + u8 ucOpMode; + u8 aucBssid[MAC_ADDR_LEN]; + u8 aucRatesEx[PARAM_MAX_LEN_RATES_EX]; + WLAN_BEACON_FRAME_BODY_T_LOCAL rBeaconFrameBody; +} EVENT_SCAN_RESULT_T, *P_EVENT_SCAN_RESULT_T; + +/* event of tkip mic error */ +typedef struct _EVENT_MIC_ERR_INFO { + u32 u4Flags; +} EVENT_MIC_ERR_INFO, *P_EVENT_MIC_ERR_INFO; + +/* event of add key done for port control */ +typedef struct _EVENT_ADD_KEY_DONE_INFO { + u8 ucBSSIndex; + u8 ucReserved; + u8 aucStaAddr[6]; +} EVENT_ADD_KEY_DONE_INFO, *P_EVENT_ADD_KEY_DONE_INFO; + +typedef struct _EVENT_PMKID_CANDIDATE_LIST_T { + u32 u4Version; /*!< Version */ + u32 u4NumCandidates; /*!< How many candidates follow */ + PARAM_PMKID_CANDIDATE_T arCandidateList[1]; +} EVENT_PMKID_CANDIDATE_LIST_T, *P_EVENT_PMKID_CANDIDATE_LIST_T; + +typedef struct _EVENT_CMD_RESULT { + u8 ucCmdID; + u8 ucStatus; + u8 aucReserved[2]; +} EVENT_CMD_RESULT, *P_EVENT_CMD_RESULT; + +/* CMD_ID_ACCESS_REG & EVENT_ID_ACCESS_REG */ +typedef struct _CMD_ACCESS_REG { + u32 u4Address; + u32 u4Data; +} CMD_ACCESS_REG, *P_CMD_ACCESS_REG; + +/* CMD_COEX_CTRL & EVENT_COEX_CTRL */ +/************************************************/ +/* u32 u4SubCmd : Coex Ctrl Sub Command */ +/* u8 aucBuffer : Reserve for Sub Command */ +/* Data Structure */ +/************************************************/ +struct CMD_COEX_CTRL { + u32 u4SubCmd; + u8 aucBuffer[64]; +}; + +/* Sub Command Data Structure */ +/************************************************/ +/* u32 u4IsoPath : WF Path (WF0/WF1) */ +/* u32 u4Channel : WF Channel */ +/* u32 u4Band : WF Band (Band0/Band1)(Not used now) */ +/* u32 u4Isolation : Isolation value */ +/************************************************/ +struct CMD_COEX_ISO_DETECT { + u32 u4IsoPath; + u32 u4Channel; + /*u32 u4Band;*/ + u32 u4Isolation; +}; + +/* Use for Coex Ctrl Cmd */ +enum ENUM_COEX_CTRL_CMD { + ENUM_COEX_CTRL_ISO_DETECT = 1, + ENUM_COEX_CTRL_NUM +}; + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +typedef struct _CMD_ACCESS_CHN_LOAD { + u32 u4Address; + u32 u4Data; + u16 u2Channel; + u8 aucReserved[2]; +} CMD_ACCESS_CHN_LOAD, *P_ACCESS_CHN_LOAD; + +typedef struct _CMD_GET_LTE_SAFE_CHN_T { + u8 ucIndex; + u8 ucFlags; + u8 aucReserved0[2]; + u8 aucReserved2[16]; +} CMD_GET_LTE_SAFE_CHN_T, *P_CMD_GET_LTE_SAFE_CHN_T; +#endif + +/* CMD_DUMP_MEMORY */ +typedef struct _CMD_DUMP_MEM { + u32 u4Address; + u32 u4Length; + u32 u4RemainLength; +#if CFG_SUPPORT_QA_TOOL + u32 u4IcapContent; +#endif + u8 ucFragNum; +} CMD_DUMP_MEM, *P_CMD_DUMP_MEM; + +typedef struct _EVENT_DUMP_MEM_T { + u32 u4Address; + u32 u4Length; + u32 u4RemainLength; +#if CFG_SUPPORT_QA_TOOL + u32 eIcapContent; +#endif + u8 ucFragNum; + u8 aucBuffer[1]; +} EVENT_DUMP_MEM_T, *P_EVENT_DUMP_MEM_T; + +#if CFG_SUPPORT_QA_TOOL +typedef struct _CMD_ACCESS_RX_STAT { + u32 u4SeqNum; + u32 u4TotalNum; +} CMD_ACCESS_RX_STAT, *P_CMD_ACCESS_RX_STAT; + +typedef struct _EVENT_ACCESS_RX_STAT { + u32 u4SeqNum; + u32 u4TotalNum; + u32 au4Buffer[1]; +} EVENT_ACCESS_RX_STAT, *P_EVENT_ACCESS_RX_STAT; + +#if CFG_SUPPORT_TX_BF +typedef union _CMD_TXBF_ACTION_T { + PROFILE_TAG_READ_T rProfileTagRead; + PROFILE_TAG_WRITE_T rProfileTagWrite; + PROFILE_DATA_READ_T rProfileDataRead; + PROFILE_DATA_WRITE_T rProfileDataWrite; + PROFILE_PN_READ_T rProfilePnRead; + PROFILE_PN_WRITE_T rProfilePnWrite; + TX_BF_SOUNDING_START_T rTxBfSoundingStart; + TX_BF_SOUNDING_STOP_T rTxBfSoundingStop; + TX_BF_TX_APPLY_T rTxBfTxApply; + TX_BF_PFMU_MEM_ALLOC_T rTxBfPfmuMemAlloc; + TX_BF_PFMU_MEM_RLS_T rTxBfPfmuMemRls; +} CMD_TXBF_ACTION_T, *P_CMD_TXBF_ACTION_T; + +#define CMD_DEVINFO_UPDATE_HDR_SIZE 8 +typedef struct _CMD_DEV_INFO_UPDATE_T { + u8 ucOwnMacIdx; + u8 ucReserve; + u16 u2TotalElementNum; + u8 ucAppendCmdTLV; + u8 aucReserve[3]; + u8 aucBuffer[0]; + /* CMD_DEVINFO_ACTIVE_T rCmdDevInfoActive; */ +} CMD_DEV_INFO_UPDATE_T, *P_CMD_DEV_INFO_UPDATE_T; + +#define CMD_BSSINFO_UPDATE_HDR_SIZE 8 +typedef struct _CMD_BSS_INFO_UPDATE_T { + u8 ucBssIndex; + u8 ucReserve; + u16 u2TotalElementNum; + u32 u4Reserve; + /* CMD_BSSINFO_BASIC_T rCmdBssInfoBasic; */ + u8 aucBuffer[0]; +} CMD_BSS_INFO_UPDATE_T, *P_CMD_BSS_INFO_UPDATE_T; + +/* STA record command */ +#define CMD_STAREC_UPDATE_HDR_SIZE 8 +typedef struct _CMD_STAREC_UPDATE_T { + u8 ucBssIndex; + u8 ucWlanIdx; + u16 u2TotalElementNum; + u32 u4Reserve; + u8 aucBuffer[0]; +} CMD_STAREC_UPDATE_T, *P_CMD_STAREC_UPDATE_T; + +typedef struct _EVENT_PFMU_TAG_READ_T { + PFMU_PROFILE_TAG1 ru4TxBfPFMUTag1; + PFMU_PROFILE_TAG2 ru4TxBfPFMUTag2; +} EVENT_PFMU_TAG_READ_T, *P_EVENT_PFMU_TAG_READ_T; + +#if CFG_SUPPORT_MU_MIMO +typedef struct _EVENT_HQA_GET_QD { + u32 u4EventId; + u32 au4RawData[14]; +} EVENT_HQA_GET_QD, *P_EVENT_HQA_GET_QD; + +typedef struct _EVENT_HQA_GET_MU_CALC_LQ { + u32 u4EventId; + MU_STRUCT_LQ_REPORT rEntry; +} EVENT_HQA_GET_MU_CALC_LQ, *P_EVENT_HQA_GET_MU_CALC_LQ; + +typedef struct _EVENT_SHOW_GROUP_TBL_ENTRY { + u32 u4EventId; + u8 index; + u8 numUser : 2; + u8 BW : 2; + u8 NS0 : 2; + u8 NS1 : 2; + /* u8 NS2:1; */ + /* u8 NS3:1; */ + u8 PFIDUser0; + u8 PFIDUser1; + /* u8 PFIDUser2; */ + /* u8 PFIDUser3; */ + u8 fgIsShortGI; + u8 fgIsUsed; + u8 fgIsDisable; + u8 initMcsUser0 : 4; + u8 initMcsUser1 : 4; + /* u8 initMcsUser2:4; */ + /* u8 initMcsUser3:4; */ + u8 dMcsUser0 : 4; + u8 dMcsUser1 : 4; + /* u8 dMcsUser2:4; */ + /* u8 dMcsUser3:4; */ +} EVENT_SHOW_GROUP_TBL_ENTRY, *P_EVENT_SHOW_GROUP_TBL_ENTRY; + +typedef union _CMD_MUMIMO_ACTION_T { + u8 ucMuMimoCategory; + u8 aucRsv[3]; + union { + MU_GET_CALC_INIT_MCS_T rMuGetCalcInitMcs; + MU_SET_INIT_MCS_T rMuSetInitMcs; + MU_SET_CALC_LQ_T rMuSetCalcLq; + MU_GET_LQ_T rMuGetLq; + MU_SET_SNR_OFFSET_T rMuSetSnrOffset; + MU_SET_ZERO_NSS_T rMuSetZeroNss; + MU_SPEED_UP_LQ_T rMuSpeedUpLq; + MU_SET_MU_TABLE_T rMuSetMuTable; + MU_SET_GROUP_T rMuSetGroup; + MU_GET_QD_T rMuGetQd; + MU_SET_ENABLE_T rMuSetEnable; + MU_SET_GID_UP_T rMuSetGidUp; + MU_TRIGGER_MU_TX_T rMuTriggerMuTx; + } unMuMimoParam; +} CMD_MUMIMO_ACTION_T, *P_CMD_MUMIMO_ACTION_T; +#endif +#endif +#endif + +typedef struct _CMD_SW_DBG_CTRL_T { + u32 u4Id; + s32 u4Data; + /* Debug Support */ + u32 u4DebugCnt[64]; +} CMD_SW_DBG_CTRL_T, *P_CMD_SW_DBG_CTRL_T; + +#ifdef CFG_SUPPORT_ANT_DIV +enum { + ANT_DIV_DISABLE = 0, + ANT_DIV_ANT_1, + ANT_DIV_ANT_2, + ANT_DIV_SUCCESS, + ANT_DIV_WF_SCNING, + ANT_DIV_BT_SCNING, + ANT_DIV_DISCONNECT, + ANT_DIV_INVALID_RSSI, + ANT_DIV_MSG_TIMEOUT, + ANT_DIV_SWH_FAIL, + ANT_DIV_PARA_ERR, + ANT_DIV_OTHER_FAIL, + ANT_DIV_STATE_NUM +}; + +enum { + ANT_DIV_CMD_SET_ANT = 0, + ANT_DIV_CMD_GET_ANT, + ANT_DIV_CMD_DETC, + ANT_DIV_CMD_SWH, +}; + +struct CMD_ANT_DIV_CTRL { + u8 ucAction; + u8 ucAntId; + u8 ucState; + u8 ucRcpi; + u8 ucReserve[8]; +}; +#endif + +typedef struct _CMD_FW_LOG_2_HOST_CTRL_T { + u8 ucFwLog2HostCtrl; + u8 ucMcuDest; +#if CFG_SUPPORT_FW_DBG_LEVEL_CTRL + u8 ucFwLogLevel; + u8 ucReserve; +#else + u8 ucReserve[2]; +#endif + u32 u4HostTimeSec; + u32 u4HostTimeMSec; +} CMD_FW_LOG_2_HOST_CTRL_T, *P_CMD_FW_LOG_2_HOST_CTRL_T; + +typedef struct _CMD_GET_MAGIC_PKT_INFO { + u16 u2Type; + u16 u2Len; + u32 u4ConfigMask; + u32 u4MagicPktCntTotal; + u32 u4GpioPullLowCntTotal; + u32 u4GpioPullHighCntTotal; +} CMD_GET_MAGIC_PKT_INFO_T, *P_CMD_GET_MAGIC_PKT_INFO_T; + +typedef struct _CMD_CHIP_CONFIG_T { + u16 u2Id; + u8 ucType; + u8 ucRespType; + u16 u2MsgSize; + u8 aucReserved0[2]; + u8 aucCmd[CHIP_CONFIG_RESP_SIZE]; +} CMD_CHIP_CONFIG_T, *P_CMD_CHIP_CONFIG_T; + +/* CMD_ID_LINK_ATTRIB */ +typedef struct _CMD_LINK_ATTRIB { + s8 cRssiTrigger; + u8 ucDesiredRateLen; + u16 u2DesiredRate[32]; + u8 ucMediaStreamMode; + u8 aucReserved[1]; +} CMD_LINK_ATTRIB, *P_CMD_LINK_ATTRIB; + +/* CMD_ID_NIC_POWER_CTRL */ +typedef struct _CMD_NIC_POWER_CTRL { + u8 ucPowerMode; + u8 aucReserved[3]; +} CMD_NIC_POWER_CTRL, *P_CMD_NIC_POWER_CTRL; + +/* CMD_ID_KEEP_FULL_PWR */ +struct CMD_KEEP_FULL_PWR_T { + u8 ucEnable; + u8 aucReserved[3]; +}; + +/* CMD_ID_POWER_SAVE_MODE */ +typedef struct _CMD_PS_PROFILE_T { + u8 ucBssIndex; + u8 ucPsProfile; +#ifdef SUPPORT_PERIODIC_PS + u8 ucPspCAMInt; + u8 ucPspPSInt; +#else + u8 aucReserved[2]; +#endif +} CMD_PS_PROFILE_T, *P_CMD_PS_PROFILE_T; + +/* EVENT_LINK_QUALITY */ + +typedef struct _LINK_QUALITY_ { + s8 cRssi; /* AIS Network. */ + s8 cLinkQuality; + u16 u2LinkSpeed; /* TX rate1 */ + u8 ucMediumBusyPercentage; /* Read clear */ + u8 ucIsLQ0Rdy; /* Link Quality BSS0 Ready. */ +} LINK_QUALITY, *P_LINK_QUALITY; + +typedef struct _EVENT_LINK_QUALITY_V2 { + LINK_QUALITY rLq[BSSID_NUM]; +} EVENT_LINK_QUALITY_V2, *P_EVENT_LINK_QUALITY_V2; + +typedef struct _EVENT_LINK_QUALITY { + s8 cRssi; + s8 cLinkQuality; + u16 u2LinkSpeed; + u8 ucMediumBusyPercentage; +} EVENT_LINK_QUALITY, *P_EVENT_LINK_QUALITY; + +#if CFG_SUPPORT_P2P_RSSI_QUERY +/* EVENT_LINK_QUALITY */ +typedef struct _EVENT_LINK_QUALITY_EX { + s8 cRssi; + s8 cLinkQuality; + u16 u2LinkSpeed; + u8 ucMediumBusyPercentage; + u8 ucIsLQ0Rdy; + s8 cRssiP2P; /* For P2P Network. */ + s8 cLinkQualityP2P; + u16 u2LinkSpeedP2P; + u8 ucMediumBusyPercentageP2P; + u8 ucIsLQ1Rdy; +} EVENT_LINK_QUALITY_EX, *P_EVENT_LINK_QUALITY_EX; +#endif + +/* EVENT_ID_STATISTICS */ +typedef struct _EVENT_STATISTICS { + LARGE_INTEGER rTransmittedFragmentCount; + LARGE_INTEGER rMulticastTransmittedFrameCount; + LARGE_INTEGER rFailedCount; + LARGE_INTEGER rRetryCount; + LARGE_INTEGER rMultipleRetryCount; + LARGE_INTEGER rRTSSuccessCount; + LARGE_INTEGER rRTSFailureCount; + LARGE_INTEGER rACKFailureCount; + LARGE_INTEGER rFrameDuplicateCount; + LARGE_INTEGER rReceivedFragmentCount; + LARGE_INTEGER rMulticastReceivedFrameCount; + LARGE_INTEGER rFCSErrorCount; +} EVENT_STATISTICS, *P_EVENT_STATISTICS; + +/* EVENT_ID_FW_SLEEPY_NOTIFY */ +typedef struct _EVENT_SLEEPY_INFO_T { + u8 ucSleepyState; + u8 aucReserved[3]; +} EVENT_SLEEPY_INFO_T, *P_EVENT_SLEEPY_INFO_T; + +typedef struct _EVENT_ACTIVATE_STA_REC_T { + u8 aucMacAddr[6]; + u8 ucStaRecIdx; + u8 ucBssIndex; +} EVENT_ACTIVATE_STA_REC_T, *P_EVENT_ACTIVATE_STA_REC_T; + +typedef struct _EVENT_DEACTIVATE_STA_REC_T { + u8 ucStaRecIdx; + u8 aucReserved[3]; +} EVENT_DEACTIVATE_STA_REC_T, *P_EVENT_DEACTIVATE_STA_REC_T; + +/* CMD_BT_OVER_WIFI */ +typedef struct _CMD_BT_OVER_WIFI { + u8 ucAction; /* 0: query, 1: setup, 2: destroy */ + u8 ucChannelNum; + PARAM_MAC_ADDRESS rPeerAddr; + u16 u2BeaconInterval; + u8 ucTimeoutDiscovery; + u8 ucTimeoutInactivity; + u8 ucRole; + u8 PAL_Capabilities; + u8 cMaxTxPower; + u8 ucChannelBand; + u8 ucReserved[1]; +} CMD_BT_OVER_WIFI, *P_CMD_BT_OVER_WIFI; + +#if (CFG_SUPPORT_DFS_MASTER == 1) +typedef enum _ENUM_REG_DOMAIN_T { + REG_DEFAULT = 0, + REG_JP_53, + REG_JP_56 +} ENUM_REG_DOMAIN_T, +*P_ENUM_REG_DOMAIN_T; + +typedef struct _CMD_RDD_ON_OFF_CTRL_T { + u8 ucDfsCtrl; + u8 ucRddIdx; + u8 ucRddInSel; + u8 ucRegDomain; + u8 ucRadarDetectMode; +} CMD_RDD_ON_OFF_CTRL_T, *P_CMD_RDD_ON_OFF_CTRL_T; +#endif + +/* EVENT_BT_OVER_WIFI */ +typedef struct _EVENT_BT_OVER_WIFI { + u8 ucLinkStatus; + u8 ucSelectedChannel; + s8 cRSSI; + u8 ucReserved[1]; +} EVENT_BT_OVER_WIFI, *P_EVENT_BT_OVER_WIFI; + +/* Same with DOMAIN_SUBBAND_INFO */ +typedef struct _CMD_SUBBAND_INFO { + u8 ucRegClass; + u8 ucBand; + u8 ucChannelSpan; + u8 ucFirstChannelNum; + u8 ucNumChannels; + u8 aucReserved[3]; +} CMD_SUBBAND_INFO, *P_CMD_SUBBAND_INFO; + +/* CMD_SET_DOMAIN_INFO */ +#if (CFG_SUPPORT_SINGLE_SKU == 1) +typedef struct _CMD_SET_DOMAIN_INFO_V2_T { + u32 u4CountryCode; + + u8 uc2G4Bandwidth; /* CONFIG_BW_20_40M or CONFIG_BW_20M */ + u8 uc5GBandwidth; /* CONFIG_BW_20_40M or CONFIG_BW_20M */ + u8 aucReserved[2]; + struct acctive_channel_list active_chs; +} CMD_SET_DOMAIN_INFO_V2_T, *P_CMD_SET_DOMAIN_INFO_V2_T; +#endif + +typedef struct _CMD_SET_DOMAIN_INFO_T { + u16 u2CountryCode; + u16 u2IsSetPassiveScan; + CMD_SUBBAND_INFO rSubBand[6]; + + u8 uc2G4Bandwidth; /* CONFIG_BW_20_40M or CONFIG_BW_20M */ + u8 uc5GBandwidth; /* CONFIG_BW_20_40M or CONFIG_BW_20M */ + u8 aucReserved[2]; +} CMD_SET_DOMAIN_INFO_T, *P_CMD_SET_DOMAIN_INFO_T; + +#if (CFG_SUPPORT_PWR_LIMIT_COUNTRY == 1) + +/* CMD_SET_PWR_LIMIT_TABLE */ +typedef struct _CMD_CHANNEL_POWER_LIMIT { + u8 ucCentralCh; + s8 cPwrLimitCCK; + s8 cPwrLimit20; + s8 cPwrLimit40; + s8 cPwrLimit80; + s8 cPwrLimit160; + u8 ucFlag; + u8 aucReserved[1]; +} CMD_CHANNEL_POWER_LIMIT, *P_CMD_CHANNEL_POWER_LIMIT; + +typedef struct _CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T { + u16 u2CountryCode; + u8 ucCountryFlag; + u8 ucNum; + u8 aucReserved[4]; + CMD_CHANNEL_POWER_LIMIT rChannelPowerLimit[1]; +} CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T, +*P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T; + +#if (CFG_SUPPORT_SINGLE_SKU == 1) +typedef struct _CMD_CHANNEL_POWER_LIMIT_V2 { + u8 ucCentralCh; + u8 ucReserved[3]; + + u8 tx_pwr_dsss_cck; + u8 tx_pwr_dsss_bpsk; + + u8 tx_pwr_ofdm_bpsk; /* 6M, 9M */ + u8 tx_pwr_ofdm_qpsk; /* 12M, 18M */ + u8 tx_pwr_ofdm_16qam; /* 24M, 36M */ + u8 tx_pwr_ofdm_48m; + u8 tx_pwr_ofdm_54m; + + u8 tx_pwr_ht20_bpsk; /* MCS0*/ + u8 tx_pwr_ht20_qpsk; /* MCS1, MCS2*/ + u8 tx_pwr_ht20_16qam; /* MCS3, MCS4*/ + u8 tx_pwr_ht20_mcs5; /* MCS5*/ + u8 tx_pwr_ht20_mcs6; /* MCS6*/ + u8 tx_pwr_ht20_mcs7; /* MCS7*/ + + u8 tx_pwr_ht40_bpsk; /* MCS0*/ + u8 tx_pwr_ht40_qpsk; /* MCS1, MCS2*/ + u8 tx_pwr_ht40_16qam; /* MCS3, MCS4*/ + u8 tx_pwr_ht40_mcs5; /* MCS5*/ + u8 tx_pwr_ht40_mcs6; /* MCS6*/ + u8 tx_pwr_ht40_mcs7; /* MCS7*/ + u8 tx_pwr_ht40_mcs32; /* MCS32*/ + + u8 tx_pwr_vht20_bpsk; /* MCS0*/ + u8 tx_pwr_vht20_qpsk; /* MCS1, MCS2*/ + u8 tx_pwr_vht20_16qam; /* MCS3, MCS4*/ + u8 tx_pwr_vht20_64qam; /* MCS5, MCS6*/ + u8 tx_pwr_vht20_mcs7; + u8 tx_pwr_vht20_mcs8; + u8 tx_pwr_vht20_mcs9; + + u8 tx_pwr_vht_40; + u8 tx_pwr_vht_80; + u8 tx_pwr_vht_160c; + u8 tx_pwr_vht_160nc; + u8 tx_pwr_lg_40; + u8 tx_pwr_lg_80; + + u8 tx_pwr_1ss_delta; + u8 ucReserved_1[2]; +} CMD_CHANNEL_POWER_LIMIT_V2, *P_CMD_CHANNEL_POWER_LIMIT_V2; + +typedef struct _CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T { + u8 ucNum; + u8 eband; /*ENUM_BAND_T*/ + u8 usReserved[2]; + u32 countryCode; + CMD_CHANNEL_POWER_LIMIT_V2 rChannelPowerLimit[0]; +} CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T, +*P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T; + +#define TX_PWR_LIMIT_SECTION_NUM 5 +#define TX_PWR_LIMIT_ELEMENT_NUM 7 +#define TX_PWR_LIMIT_COUNTRY_STR_MAX_LEN 4 +#define TX_PWR_LIMIT_MAX_VAL 63 + +struct CHANNEL_TX_PWR_LIMIT { + u8 ucChannel; + s8 rTxPwrLimitValue[TX_PWR_LIMIT_SECTION_NUM][TX_PWR_LIMIT_ELEMENT_NUM]; +}; + +struct TX_PWR_LIMIT_DATA { + u32 countryCode; + u32 ucChNum; + struct CHANNEL_TX_PWR_LIMIT *rChannelTxPwrLimit; +}; + +#endif + +#endif + +/* CMD_SET_IP_ADDRESS */ +typedef struct _IPV4_NETWORK_ADDRESS { + u8 aucIpAddr[4]; +} IPV4_NETWORK_ADDRESS, *P_IPV4_NETWORK_ADDRESS; + +typedef struct _CMD_SET_NETWORK_ADDRESS_LIST { + u8 ucBssIndex; + u8 ucAddressCount; + u8 ucReserved[2]; + IPV4_NETWORK_ADDRESS arNetAddress[1]; +} CMD_SET_NETWORK_ADDRESS_LIST, *P_CMD_SET_NETWORK_ADDRESS_LIST; + +typedef struct _PATTERN_DESCRIPTION { + u8 fgCheckBcA1; + u8 fgCheckMcA1; + u8 ePatternHeader; + u8 fgAndOp; + u8 fgNotOp; + u8 ucPatternMask; + u16 u2PatternOffset; + u8 aucPattern[8]; +} PATTERN_DESCRIPTION, *P_PATTERN_DESCRIPTION; + +typedef struct _CMD_RAW_PATTERN_CONFIGURATION_T { + PATTERN_DESCRIPTION arPatternDesc[4]; +} CMD_RAW_PATTERN_CONFIGURATION_T, *P_CMD_RAW_PATTERN_CONFIGURATION_T; + +typedef struct _CMD_PATTERN_FUNC_CONFIG { + u8 fgBcA1En; + u8 fgMcA1En; + u8 fgBcA1MatchDrop; + u8 fgMcA1MatchDrop; +} CMD_PATTERN_FUNC_CONFIG, *P_CMD_PATTERN_FUNC_CONFIG; + +typedef struct _EVENT_TX_DONE_T { + u8 ucPacketSeq; + u8 ucStatus; + u16 u2SequenceNumber; + + u8 ucWlanIndex; + u8 ucTxCount; + u16 u2TxRate; + + u8 ucFlag; + u8 ucTid; + u8 ucRspRate; + u8 ucRateTableIdx; + + u8 ucBandwidth; + u8 ucTxPower; + u8 aucReserved0[2]; + + u32 u4TxDelay; + u32 u4Timestamp; + u32 u4AppliedFlag; + + u8 aucRawTxS[28]; + + u8 aucReserved1[32]; +} EVENT_TX_DONE_T, *P_EVENT_TX_DONE_T; + +typedef enum _ENUM_TXS_APPLIED_FLAG_T { + TX_FRAME_IN_AMPDU_FORMAT = 0, + TX_FRAME_EXP_BF, + TX_FRAME_IMP_BF, + TX_FRAME_PS_BIT +} ENUM_TXS_APPLIED_FLAG_T, +*P_ENUM_TXS_APPLIED_FLAG_T; + +typedef enum _ENUM_TXS_CONTROL_FLAG_T { + TXS_WITH_ADVANCED_INFO = 0, + TXS_IS_EXIST +} ENUM_TXS_CONTROL_FLAG_T, +*P_ENUM_TXS_CONTROL_FLAG_T; + +#if (CFG_SUPPORT_DFS_MASTER == 1) +typedef enum _ENUM_DFS_CTRL_T { + RDD_STOP = 0, + RDD_START, + RDD_DET_MODE, + RDD_RADAR_EMULATE, + RDD_START_TXQ +} ENUM_DFS_CTRL_T, +*P_ENUM_DFS_CTRL_T; +#endif + +typedef struct _CMD_BSS_ACTIVATE_CTRL { + u8 ucBssIndex; + u8 ucActive; + u8 ucNetworkType; + u8 ucOwnMacAddrIndex; + u8 aucBssMacAddr[6]; + u8 ucBMCWlanIndex; + u8 ucReserved; +} CMD_BSS_ACTIVATE_CTRL, *P_CMD_BSS_ACTIVATE_CTRL; + +typedef struct _CMD_SET_BSS_RLM_PARAM_T { + u8 ucBssIndex; + u8 ucRfBand; + u8 ucPrimaryChannel; + u8 ucRfSco; + u8 ucErpProtectMode; + u8 ucHtProtectMode; + u8 ucGfOperationMode; + u8 ucTxRifsMode; + u16 u2HtOpInfo3; + u16 u2HtOpInfo2; + u8 ucHtOpInfo1; + u8 ucUseShortPreamble; + u8 ucUseShortSlotTime; + u8 ucVhtChannelWidth; + u8 ucVhtChannelFrequencyS1; + u8 ucVhtChannelFrequencyS2; + u16 u2VhtBasicMcsSet; + u8 ucNss; +} CMD_SET_BSS_RLM_PARAM_T, *P_CMD_SET_BSS_RLM_PARAM_T; + +typedef struct _CMD_SET_BSS_INFO { + u8 ucBssIndex; + u8 ucConnectionState; + u8 ucCurrentOPMode; + u8 ucSSIDLen; + u8 aucSSID[32]; + u8 aucBSSID[6]; + u8 ucIsQBSS; + u8 ucReserved1; + u16 u2OperationalRateSet; + u16 u2BSSBasicRateSet; + u8 ucStaRecIdxOfAP; + u16 u2HwDefaultFixedRateCode; + u8 ucNonHTBasicPhyType; /* For Slot Time and CWmin */ + u8 ucAuthMode; + u8 ucEncStatus; + u8 ucPhyTypeSet; + u8 ucWapiMode; + u8 ucIsApMode; + u8 ucBMCWlanIndex; + u8 ucHiddenSsidMode; + u8 ucDisconnectDetectTh; + u32 u4PrivateData; + CMD_SET_BSS_RLM_PARAM_T rBssRlmParam; + u8 ucDBDCBand; + u8 ucWmmSet; + u8 ucDBDCAction; + u8 ucNss; + u8 aucReserved[20]; +} CMD_SET_BSS_INFO, *P_CMD_SET_BSS_INFO; + +typedef enum _ENUM_RTS_POLICY_T { + RTS_POLICY_AUTO, + RTS_POLICY_STATIC_BW, + RTS_POLICY_DYNAMIC_BW, + RTS_POLICY_LEGACY, + RTS_POLICY_NO_RTS +} ENUM_RTS_POLICY; + +typedef struct _CMD_UPDATE_STA_RECORD_T { + u8 ucStaIndex; + u8 ucStaType; + /* This field should assign at create and keep consistency for update + * usage */ + u8 aucMacAddr[MAC_ADDR_LEN]; + + u16 u2AssocId; + u16 u2ListenInterval; + u8 ucBssIndex; /* This field should assign at create and keep + * consistency for update usage */ + u8 ucDesiredPhyTypeSet; + u16 u2DesiredNonHTRateSet; + + u16 u2BSSBasicRateSet; + u8 ucIsQoS; + u8 ucIsUapsdSupported; + u8 ucStaState; + u8 ucMcsSet; + u8 ucSupMcs32; + u8 aucReserved1[1]; + + u8 aucRxMcsBitmask[10]; + u16 u2RxHighestSupportedRate; + u32 u4TxRateInfo; + + u16 u2HtCapInfo; + u16 u2HtExtendedCap; + u32 u4TxBeamformingCap; + + u8 ucAmpduParam; + u8 ucAselCap; + u8 ucRCPI; + u8 ucNeedResp; + u8 ucUapsdAc; /* b0~3: Trigger enabled, b4~7: Delivery enabled */ + u8 ucUapsdSp; /* 0: all, 1: max 2, 2: max 4, 3: max 6 */ + u8 ucWlanIndex; /* This field should assign at create and keep + * consistency for update usage */ + u8 ucBMCWlanIndex; /* This field should assign at create and keep + * consistency for update usage */ + + u32 u4VhtCapInfo; + u16 u2VhtRxMcsMap; + u16 u2VhtRxHighestSupportedDataRate; + u16 u2VhtTxMcsMap; + u16 u2VhtTxHighestSupportedDataRate; + u8 ucRtsPolicy; /* 0: auto 1: Static BW 2: Dynamic BW 3: Legacy 7: WoRts + */ + u8 ucVhtOpMode; /* VHT operating mode, bit 7: Rx NSS Type, bit 4-6, Rx + * NSS, bit 0-1: Channel Width */ + + u8 ucTrafficDataType; /* 0: auto 1: data 2: video 3: voice */ + u8 ucTxGfMode; + u8 ucTxSgiMode; + u8 ucTxStbcMode; + u16 u2HwDefaultFixedRateCode; + u8 ucTxAmpdu; + u8 ucRxAmpdu; + u32 u4FixedPhyRate; /**/ + u16 u2MaxLinkSpeed; /* unit is 0.5 Mbps */ + u16 u2MinLinkSpeed; + + u32 u4Flags; + + u8 ucTxBaSize; + u8 ucRxBaSize; + u8 aucReserved3[2]; + + TXBF_PFMU_STA_INFO rTxBfPfmuInfo; + + u8 ucTxAmsduInAmpdu; + u8 ucRxAmsduInAmpdu; + u8 aucReserved5[2]; + + u32 u4TxMaxAmsduInAmpduLen; + /* u8 aucReserved4[30]; */ +} CMD_UPDATE_STA_RECORD_T, *P_CMD_UPDATE_STA_RECORD_T; + +typedef struct _CMD_REMOVE_STA_RECORD_T { + u8 ucActionType; + u8 ucStaIndex; + u8 ucBssIndex; + u8 ucReserved; +} CMD_REMOVE_STA_RECORD_T, *P_CMD_REMOVE_STA_RECORD_T; + +typedef struct _CMD_INDICATE_PM_BSS_CREATED_T { + u8 ucBssIndex; + u8 ucDtimPeriod; + u16 u2BeaconInterval; + u16 u2AtimWindow; + u8 aucReserved[2]; +} CMD_INDICATE_PM_BSS_CREATED, *P_CMD_INDICATE_PM_BSS_CREATED; + +typedef struct _CMD_INDICATE_PM_BSS_CONNECTED_T { + u8 ucBssIndex; + u8 ucDtimPeriod; + u16 u2AssocId; + u16 u2BeaconInterval; + u16 u2AtimWindow; + u8 fgIsUapsdConnection; + u8 ucBmpDeliveryAC; + u8 ucBmpTriggerAC; + u8 aucReserved[1]; +} CMD_INDICATE_PM_BSS_CONNECTED, *P_CMD_INDICATE_PM_BSS_CONNECTED; + +typedef struct _CMD_INDICATE_PM_BSS_ABORT { + u8 ucBssIndex; + u8 aucReserved[3]; +} CMD_INDICATE_PM_BSS_ABORT, *P_CMD_INDICATE_PM_BSS_ABORT; + +typedef struct _CMD_BEACON_TEMPLATE_UPDATE { + /* 0: update randomly, 1: update all, 2: delete all (1 and 2 will update + * directly without search) */ + u8 ucUpdateMethod; + u8 ucBssIndex; + u8 aucReserved[2]; + u16 u2Capability; + u16 u2IELen; + u8 aucIE[MAX_IE_LENGTH]; +} CMD_BEACON_TEMPLATE_UPDATE, *P_CMD_BEACON_TEMPLATE_UPDATE; + +typedef struct _CMD_SET_WMM_PS_TEST_STRUCT_T { + u8 ucBssIndex; + u8 bmfgApsdEnAc; /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ + u8 ucIsEnterPsAtOnce; /* enter PS immediately without 5 second guard + * after connected */ + u8 ucIsDisableUcTrigger; /* not to trigger UC on beacon TIM is matched + * (under U-APSD) */ +} CMD_SET_WMM_PS_TEST_STRUCT_T, *P_CMD_SET_WMM_PS_TEST_STRUCT_T; + +/* Definition for CHANNEL_INFO.ucBand: + * 0: Reserved + * 1: BAND_2G4 + * 2: BAND_5G + * Others: Reserved + */ +typedef struct _CHANNEL_INFO_T { + u8 ucBand; + u8 ucChannelNum; +} CHANNEL_INFO_T, *P_CHANNEL_INFO_T; + +typedef struct _CMD_SCAN_REQ_T { + u8 ucSeqNum; + u8 ucBssIndex; + u8 ucScanType; + u8 ucSSIDType; /* BIT(0) wildcard / BIT(1) P2P-wildcard / BIT(2) + * specific */ + u8 ucSSIDLength; + u8 ucNumProbeReq; + u16 u2ChannelMinDwellTime; + u16 u2ChannelDwellTime; + u16 u2TimeoutValue; + u8 aucSSID[32]; + u8 ucChannelType; + u8 ucChannelListNum; + u8 aucReserved[2]; + CHANNEL_INFO_T arChannelList[32]; + u16 u2IELen; + u8 aucIE[MAX_IE_LENGTH]; +} CMD_SCAN_REQ, *P_CMD_SCAN_REQ; + +typedef struct _CMD_SCAN_REQ_V2_T { + u8 ucSeqNum; + u8 ucBssIndex; + u8 ucScanType; + u8 ucSSIDType; + u8 ucSSIDNum; + u8 ucNumProbeReq; + u8 aucReserved[2]; /*total 8*/ + PARAM_SSID_T arSSID[4]; /*(4+32)*4 = 144, total 152*/ + u16 u2ProbeDelayTime; + u16 u2ChannelDwellTime; + u16 u2TimeoutValue; + u8 ucChannelType; + u8 ucChannelListNum; /*total 160*/ + CHANNEL_INFO_T arChannelList[32]; /*total 160+64=224*/ + u16 u2IELen; /*total 226*/ + u8 aucIE[MAX_IE_LENGTH]; /*total 826*/ + u8 ucScnCtrlFlag; + u8 aucReserved2; /*total 828*/ + /*Extend for Scan cmds*/ + CHANNEL_INFO_T arChannelListExtend[32]; /*total 892*/ + u8 arPerChannelControl[32]; + u8 arPerExtendChannelControl[32]; /*total 956*/ + u8 ucScanChannelListenTime; /*total 957*/ + u8 aucReserved3[3]; /*total 960, max 1024*/ +} CMD_SCAN_REQ_V2, *P_CMD_SCAN_REQ_V2; + +typedef struct _CMD_SCAN_CANCEL_T { + u8 ucSeqNum; + u8 ucIsExtChannel; /* For P2P channel extension. */ + u8 aucReserved[2]; +} CMD_SCAN_CANCEL, *P_CMD_SCAN_CANCEL; + +/* 20150107 Daniel Added complete channels number in the scan done event */ +/* before*/ +/* + * typedef struct _EVENT_SCAN_DONE_T { + * u8 ucSeqNum; + * u8 ucSparseChannelValid; + * CHANNEL_INFO_T rSparseChannel; + *} EVENT_SCAN_DONE, *P_EVENT_SCAN_DONE; + */ +/* after */ + +#define EVENT_SCAN_DONE_CHANNEL_NUM_MAX 64 +typedef struct _EVENT_SCAN_DONE_T { + u8 ucSeqNum; + u8 ucSparseChannelValid; + CHANNEL_INFO_T rSparseChannel; + /*scan done version #2 */ + u8 ucCompleteChanCount; + u8 ucCurrentState; + u8 ucScanDoneVersion; + /*scan done version #3 */ + u8 ucReserved; + u32 u4ScanDurBcnCnt; + u8 fgIsPNOenabled; + u8 aucReserving[3]; + /*channel idle count # Mike */ + u8 ucSparseChannelArrayValidNum; + u8 aucReserved[3]; + u8 aucChannelNum[EVENT_SCAN_DONE_CHANNEL_NUM_MAX]; + /* Idle format for au2ChannelIdleTime */ + /* 0: first bytes: idle time(ms) 2nd byte: dwell time(ms) */ + /* 1: first bytes: idle time(8ms) 2nd byte: dwell time(8ms) */ + /* 2: dwell time (16us) */ + u16 au2ChannelIdleTime[EVENT_SCAN_DONE_CHANNEL_NUM_MAX]; + /* B0: Active/Passive B3-B1: Idle format */ + u8 aucChannelFlag[EVENT_SCAN_DONE_CHANNEL_NUM_MAX]; + u8 aucChannelMDRDYCnt[EVENT_SCAN_DONE_CHANNEL_NUM_MAX]; +} EVENT_SCAN_DONE, *P_EVENT_SCAN_DONE; + +#if CFG_SUPPORT_BATCH_SCAN +typedef struct _CMD_BATCH_REQ_T { + u8 ucSeqNum; + u8 ucNetTypeIndex; + u8 ucCmd; /* Start/ Stop */ + u8 ucMScan; /* an integer number of scans per batch */ + u8 ucBestn; /* an integer number of the max AP to remember per scan */ + u8 ucRtt; /* an integer number of highest-strength AP for which we'd */ + /* like approximate distance reported */ + u8 ucChannel; /* channels */ + u8 ucChannelType; + u8 ucChannelListNum; + u8 aucReserved[3]; + u32 u4Scanfreq; /* an integer number of seconds between scans */ + CHANNEL_INFO_T arChannelList[32]; /* channels */ +} CMD_BATCH_REQ_T, *P_CMD_BATCH_REQ_T; + +typedef struct _EVENT_BATCH_RESULT_ENTRY_T { + u8 aucBssid[MAC_ADDR_LEN]; + u8 aucSSID[ELEM_MAX_LEN_SSID]; + u8 ucSSIDLen; + s8 cRssi; + u32 ucFreq; + u32 u4Age; + u32 u4Dist; + u32 u4Distsd; +} EVENT_BATCH_RESULT_ENTRY_T, *P_EVENT_BATCH_RESULT_ENTRY_T; + +typedef struct _EVENT_BATCH_RESULT_T { + u8 ucScanCount; + u8 aucReserved[3]; + EVENT_BATCH_RESULT_ENTRY_T + arBatchResult[12]; /* Must be the same with SCN_BATCH_STORE_MAX_NUM */ +} EVENT_BATCH_RESULT_T, *P_EVENT_BATCH_RESULT_T; +#endif + +typedef struct _CMD_CH_PRIVILEGE_T { + u8 ucBssIndex; + u8 ucTokenID; + u8 ucAction; + u8 ucPrimaryChannel; + u8 ucRfSco; + u8 ucRfBand; + u8 ucRfChannelWidth; /* To support 80/160MHz bandwidth */ + u8 ucRfCenterFreqSeg1; /* To support 80/160MHz bandwidth */ + u8 ucRfCenterFreqSeg2; /* To support 80/160MHz bandwidth */ + u8 ucReqType; + u8 ucDBDCBand; + u8 aucReserved; + u32 u4MaxInterval; /* In unit of ms */ + u8 aucReserved2[8]; +} CMD_CH_PRIVILEGE_T, *P_CMD_CH_PRIVILEGE_T; + +typedef struct _CMD_TX_PWR_T { + s8 cTxPwr2G4Cck; /* signed, in unit of 0.5dBm */ + s8 cTxPwr2G4Dsss; /* signed, in unit of 0.5dBm */ + s8 acReserved[2]; + + s8 cTxPwr2G4OFDM_BPSK; + s8 cTxPwr2G4OFDM_QPSK; + s8 cTxPwr2G4OFDM_16QAM; + s8 cTxPwr2G4OFDM_Reserved; + s8 cTxPwr2G4OFDM_48Mbps; + s8 cTxPwr2G4OFDM_54Mbps; + + s8 cTxPwr2G4HT20_BPSK; + s8 cTxPwr2G4HT20_QPSK; + s8 cTxPwr2G4HT20_16QAM; + s8 cTxPwr2G4HT20_MCS5; + s8 cTxPwr2G4HT20_MCS6; + s8 cTxPwr2G4HT20_MCS7; + + s8 cTxPwr2G4HT40_BPSK; + s8 cTxPwr2G4HT40_QPSK; + s8 cTxPwr2G4HT40_16QAM; + s8 cTxPwr2G4HT40_MCS5; + s8 cTxPwr2G4HT40_MCS6; + s8 cTxPwr2G4HT40_MCS7; + + s8 cTxPwr5GOFDM_BPSK; + s8 cTxPwr5GOFDM_QPSK; + s8 cTxPwr5GOFDM_16QAM; + s8 cTxPwr5GOFDM_Reserved; + s8 cTxPwr5GOFDM_48Mbps; + s8 cTxPwr5GOFDM_54Mbps; + + s8 cTxPwr5GHT20_BPSK; + s8 cTxPwr5GHT20_QPSK; + s8 cTxPwr5GHT20_16QAM; + s8 cTxPwr5GHT20_MCS5; + s8 cTxPwr5GHT20_MCS6; + s8 cTxPwr5GHT20_MCS7; + + s8 cTxPwr5GHT40_BPSK; + s8 cTxPwr5GHT40_QPSK; + s8 cTxPwr5GHT40_16QAM; + s8 cTxPwr5GHT40_MCS5; + s8 cTxPwr5GHT40_MCS6; + s8 cTxPwr5GHT40_MCS7; +} CMD_TX_PWR_T, *P_CMD_TX_PWR_T; + +typedef struct _CMD_TX_AC_PWR_T { + s8 ucBand; + AC_PWR_SETTING_STRUCT rAcPwr; +} CMD_TX_AC_PWR_T, *P_CMD_TX_AC_PWR_T; + +typedef struct _CMD_RSSI_PATH_COMPASATION_T { + s8 c2GRssiCompensation; + s8 c5GRssiCompensation; +} CMD_RSSI_PATH_COMPASATION_T, *P_CMD_RSSI_PATH_COMPASATION_T; +typedef struct _CMD_5G_PWR_OFFSET_T { + s8 cOffsetBand0; /* 4.915-4.980G */ + s8 cOffsetBand1; /* 5.000-5.080G */ + s8 cOffsetBand2; /* 5.160-5.180G */ + s8 cOffsetBand3; /* 5.200-5.280G */ + s8 cOffsetBand4; /* 5.300-5.340G */ + s8 cOffsetBand5; /* 5.500-5.580G */ + s8 cOffsetBand6; /* 5.600-5.680G */ + s8 cOffsetBand7; /* 5.700-5.825G */ +} CMD_5G_PWR_OFFSET_T, *P_CMD_5G_PWR_OFFSET_T; + +typedef struct _CMD_PWR_PARAM_T { + u32 au4Data[28]; + u32 u4RefValue1; + u32 u4RefValue2; +} CMD_PWR_PARAM_T, *P_CMD_PWR_PARAM_T; + +typedef struct _CMD_PHY_PARAM_T { + u8 aucData[144]; /* eFuse content */ +} CMD_PHY_PARAM_T, *P_CMD_PHY_PARAM_T; + +typedef struct _CMD_AUTO_POWER_PARAM_T { + u8 ucType; /* 0: Disable 1: Enalbe 0x10: Change parameters */ + u8 ucBssIndex; + u8 aucReserved[2]; + u8 aucLevelRcpiTh[3]; + u8 aucReserved2[1]; + s8 aicLevelPowerOffset[3]; /* signed, in unit of 0.5dBm */ + u8 aucReserved3[1]; + u8 aucReserved4[8]; +} CMD_AUTO_POWER_PARAM_T, *P_CMD_AUTO_POWER_PARAM_T; + +typedef struct _CMD_DBDC_SETTING_T { + u8 ucDbdcEn; + u8 ucWmmBandBitmap; + u8 ucUpdateSettingNextChReq; + u8 aucReserved1; + u8 aucReserved2[32]; +} CMD_DBDC_SETTING_T, *P_CMD_DBDC_SETTING_T; + +typedef struct _EVENT_CH_PRIVILEGE_T { + u8 ucBssIndex; + u8 ucTokenID; + u8 ucStatus; + u8 ucPrimaryChannel; + u8 ucRfSco; + u8 ucRfBand; + u8 ucRfChannelWidth; /* To support 80/160MHz bandwidth */ + u8 ucRfCenterFreqSeg1; /* To support 80/160MHz bandwidth */ + u8 ucRfCenterFreqSeg2; /* To support 80/160MHz bandwidth */ + u8 ucReqType; + u8 ucDBDCBand; + u8 aucReserved; + u32 u4GrantInterval; /* In unit of ms */ + u8 aucReserved2[8]; +} EVENT_CH_PRIVILEGE_T, *P_EVENT_CH_PRIVILEGE_T; + +#if (CFG_SUPPORT_DFS_MASTER == 1) +typedef struct _LONG_PULSE_BUFFER_T { + u32 u4LongStartTime; + u16 u2LongPulseWidth; +} LONG_PULSE_BUFFER_T, *PLONG_PULSE_BUFFER_T; + +typedef struct _PERIODIC_PULSE_BUFFER_T { + u32 u4PeriodicStartTime; + u16 u2PeriodicPulseWidth; + s16 i2PeriodicPulsePower; +} PERIODIC_PULSE_BUFFER_T, *PPERIODIC_PULSE_BUFFER_T; + +typedef struct _EVENT_RDD_REPORT_T { + u8 ucRadarReportMode; /*0: Only report radar detected; 1: Add parameter + * reports*/ + u8 ucRddIdx; + u8 ucLongDetected; + u8 ucPeriodicDetected; + u8 ucLPBNum; + u8 ucPPBNum; + u8 ucLPBPeriodValid; + u8 ucLPBWidthValid; + u8 ucPRICountM1; + u8 ucPRICountM1TH; + u8 ucPRICountM2; + u8 ucPRICountM2TH; + u32 u4PRI1stUs; + LONG_PULSE_BUFFER_T arLpbContent[LPB_SIZE]; + PERIODIC_PULSE_BUFFER_T arPpbContent[PPB_SIZE]; +} EVENT_RDD_REPORT_T, *P_EVENT_RDD_REPORT_T; +#endif + +#if (CFG_WOW_SUPPORT == 1) +/* event of wake up reason */ +struct _EVENT_WAKEUP_REASON_INFO { + u8 reason; + u8 aucReserved[3]; +}; +#endif + +typedef struct _EVENT_BSS_BEACON_TIMEOUT_T { + u8 ucBssIndex; + u8 ucReasonCode; + u8 aucReserved[2]; +} EVENT_BSS_BEACON_TIMEOUT_T, *P_EVENT_BSS_BEACON_TIMEOUT_T; + +typedef struct _EVENT_STA_AGING_TIMEOUT_T { + u8 ucStaRecIdx; + u8 aucReserved[3]; +} EVENT_STA_AGING_TIMEOUT_T, *P_EVENT_STA_AGING_TIMEOUT_T; + +typedef struct _EVENT_NOA_TIMING_T { + u8 ucIsInUse; /* Indicate if this entry is in use or not */ + u8 ucCount; /* Count */ + u8 aucReserved[2]; + + u32 u4Duration; /* Duration */ + u32 u4Interval; /* Interval */ + u32 u4StartTime; /* Start Time */ +} EVENT_NOA_TIMING_T, *P_EVENT_NOA_TIMING_T; + +typedef struct _EVENT_UPDATE_NOA_PARAMS_T { + u8 ucBssIndex; + u8 aucReserved[2]; + u8 ucEnableOppPS; + u16 u2CTWindow; + + u8 ucNoAIndex; + u8 ucNoATimingCount; /* Number of NoA Timing */ + EVENT_NOA_TIMING_T arEventNoaTiming[8 /*P2P_MAXIMUM_NOA_COUNT */ ]; +} EVENT_UPDATE_NOA_PARAMS_T, *P_EVENT_UPDATE_NOA_PARAMS_T; + +typedef struct _EVENT_AP_OBSS_STATUS_T { + u8 ucBssIndex; + u8 ucObssErpProtectMode; + u8 ucObssHtProtectMode; + u8 ucObssGfOperationMode; + u8 ucObssRifsOperationMode; + u8 ucObssBeaconForcedTo20M; + u8 aucReserved[2]; +} EVENT_AP_OBSS_STATUS_T, *P_EVENT_AP_OBSS_STATUS_T; + +typedef struct _EVENT_DEBUG_MSG_T { + u16 u2DebugMsgId; + u8 ucMsgType; + u8 ucFlags; /* unused */ + u32 u4Value; /* memory addre or ... */ + u16 u2MsgSize; + u8 aucReserved0[2]; + u8 aucMsg[1]; +} EVENT_DEBUG_MSG_T, *P_EVENT_DEBUG_MSG_T; + +typedef struct _CMD_EDGE_TXPWR_LIMIT_T { + s8 cBandEdgeMaxPwrCCK; + s8 cBandEdgeMaxPwrOFDM20; + s8 cBandEdgeMaxPwrOFDM40; + s8 cBandEdgeMaxPwrOFDM80; +} CMD_EDGE_TXPWR_LIMIT_T, *P_CMD_EDGE_TXPWR_LIMIT_T; + +typedef struct _CMD_POWER_OFFSET_T { + u8 ucBand; /*1:2.4G ; 2:5G */ + u8 ucSubBandOffset[MAX_SUBBAND_NUM_5G]; /*the max num subband is 5G, + * devide with 8 subband */ + u8 aucReverse[3]; +} CMD_POWER_OFFSET_T, *P_CMD_POWER_OFFSET_T; + +typedef struct _CMD_NVRAM_SETTING_T { + WIFI_CFG_PARAM_STRUCT rNvramSettings; +} CMD_NVRAM_SETTING_T, *P_CMD_NVRAM_SETTING_T; + +#if CFG_SUPPORT_TDLS +typedef struct _CMD_TDLS_CH_SW_T { + u8 fgIsTDLSChSwProhibit; +} CMD_TDLS_CH_SW_T, *P_CMD_TDLS_CH_SW_T; +#endif + +struct EVENT_CSI_DATA_T { + u8 ucBw; + u8 bIsCck; + u16 u2DataCount; + s16 ac2IData[256]; + s16 ac2QData[256]; + u8 ucDbdcIdx; + u8 aucReserved[3]; +}; + +#if CFG_SUPPORT_ADVANCE_CONTROL +/* command type */ +#define CMD_ADV_CONTROL_SET (1 << 15) +#define CMD_PTA_CONFIG_TYPE (0x1) +#define CMD_AFH_CONFIG_TYPE (0x2) +#define CMD_BA_CONFIG_TYPE (0x3) +#define CMD_GET_REPORT_TYPE (0x4) +#define CMD_NOISE_HISTOGRAM_TYPE (0x5) +#if CFG_IPI_2CHAIN_SUPPORT +#define CMD_NOISE_HISTOGRAM_TYPE2 (0x51) +#endif +#define CMD_ADMINCTRL_CONFIG_TYPE (0x6) +#ifdef CFG_SUPPORT_EXT_PTA_DEBUG_COMMAND +#define CMD_EXT_PTA_CONFIG_TYPE (0x7) +#endif +/* 0x8 is reserved for GARP count */ +#define CMD_GET_MAGIC_PKT_INFO_TYPE (0x9) + +/* for PtaConfig field */ +#define CMD_PTA_CONFIG_PTA_EN (1 << 0) +#define CMD_PTA_CONFIG_RW_EN (1 << 1) +#define CMD_PTA_CONFIG_PTA_STAT_EN (1 << 2) + +/* pta config related mask */ +#define CMD_PTA_CONFIG_PTA (1 << 0) +#define CMD_PTA_CONFIG_RW (1 << 1) +#define CMD_PTA_CONFIG_TXDATA_TAG (1 << 2) +#define CMD_PTA_CONFIG_RXDATAACK_TAG (1 << 3) +#define CMD_PTA_CONFIG_RX_NSW_TAG (1 << 4) +#define CMD_PTA_CONFIG_TXACK_TAG (1 << 5) +#define CMD_PTA_CONFIG_TXPROTFRAME_TAG (1 << 6) +#define CMD_PTA_CONFIG_RXPROTFRAMEACK_TAG (1 << 7) +#define CMD_PTA_CONFIG_TX_BMC_TAG (1 << 8) +#define CMD_PTA_CONFIG_TX_BCN_TAG (1 << 9) +#define CMD_PTA_CONFIG_RX_SP_TAG (1 << 10) +#define CMD_PTA_CONFIG_TX_MGMT_TAG (1 << 11) +#define CMD_PTA_CONFIG_RXMGMTACK_TAG (1 << 12) +#define CMD_PTA_CONFIG_PTA_STAT (1 << 13) +#define CMD_PTA_CONFIG_PTA_STAT_RESET (1 << 14) +#define CMD_PTA_CONFIG_COMM_ACT_BT_WF0_INBAND (1 << 15) +#define CMD_PTA_CONFIG_COMM_ACT_BT_WF0_OUTBAND (1 << 16) +#define CMD_PTA_CONFIG_COMM_ACT_BT_WF1_INBAND (1 << 17) +#define CMD_PTA_CONFIG_COMM_ACT_BT_WF1_OUTBAND (1 << 18) + +#ifdef CFG_SUPPORT_EXT_PTA_DEBUG_COMMAND +/* ext pta config related mask */ +#define CMD_EXT_PTA_CONFIG_EXT_PTA (1 << 0) +#define CMD_EXT_PTA_CONFIG_HI_RX_TAG (1 << 1) +#define CMD_EXT_PTA_CONFIG_LO_RX_TAG (1 << 2) +#define CMD_EXT_PTA_CONFIG_HI_TX_TAG (1 << 3) +#define CMD_EXT_PTA_CONFIG_LO_TX_TAG (1 << 4) +#define CMD_EXT_PTA_CONFIG_COMM_ACT_ZB_BT_UNSAFE (1 << 5) +#define CMD_EXT_PTA_CONFIG_COMM_ACT_ZB_WF0_UNSAFE (1 << 6) +#define CMD_EXT_PTA_CONFIG_COMM_ACT_ZB_WF1_UNSAFE (1 << 7) +#define CMD_EXT_PTA_CONFIG_COMM_ACT_ZB_BT_HSF (1 << 8) +#define CMD_EXT_PTA_CONFIG_COMM_ACT_ZB_WF0_HSF (1 << 9) +#define CMD_EXT_PTA_CONFIG_COMM_ACT_ZB_WF1_HSF (1 << 10) +#endif + +/* for config PTA Tag */ +#define EVENT_CONFIG_PTA_OFFSET (0) +#define EVENT_CONFIG_PTA_FEILD (0x1) +#define EVENT_CONFIG_PTA_WIFI_OFFSET (12) +#define EVENT_CONFIG_PTA_WIFI_FEILD (0x1) +#define EVENT_CONFIG_PTA_BT_OFFSET (15) +#define EVENT_CONFIG_PTA_BT_FEILD (0x1) +#define EVENT_CONFIG_PTA_ARB_OFFSET (16) +#define EVENT_CONFIG_PTA_ARB_FEILD (0x1) + +#define EVENT_CONFIG_WIFI_GRANT_OFFSET (30) +#define EVENT_CONFIG_WIFI_GRANT_FEILD (0x1) +#define EVENT_CONFIG_WIFI_PRI_OFFSET (12) +#define EVENT_CONFIG_WIFI_PRI_FEILD (0xf) +#define EVENT_CONFIG_WIFI_TXREQ_OFFSET (8) +#define EVENT_CONFIG_WIFI_TXREQ_FEILD (0x1) +#define EVENT_CONFIG_WIFI_RXREQ_OFFSET (9) +#define EVENT_CONFIG_WIFI_RXREQ_FEILD (0x1) + +#define EVENT_CONFIG_BT_GRANT_OFFSET (29) +#define EVENT_CONFIG_BT_GRANT_FEILD (0x1) +#define EVENT_CONFIG_BT_PRI_OFFSET (4) +#define EVENT_CONFIG_BT_PRI_FEILD (0xf) +#define EVENT_CONFIG_BT_TXREQ_OFFSET (0) +#define EVENT_CONFIG_BT_TXREQ_FEILD (0x1) +#define EVENT_CONFIG_BT_RXREQ_OFFSET (1) +#define EVENT_CONFIG_BT_RXREQ_FEILD (0x1) + +#define EVENT_PTA_BTTRX_CNT_OFFSET (16) +#define EVENT_PTA_BTTRX_CNT_FEILD (0xFFFF) +#define EVENT_PTA_BTTRX_GRANT_CNT_OFFSET (0) +#define EVENT_PTA_BTTRX_GRANT_CNT_FEILD (0xFFFF) + +#define EVENT_PTA_WFTRX_CNT_OFFSET (16) +#define EVENT_PTA_WFTRX_CNT_FEILD (0xFFFF) +#define EVENT_PTA_WFTRX_GRANT_CNT_OFFSET (0) +#define EVENT_PTA_WFTRX_GRANT_CNT_FEILD (0xFFFF) + +#define EVENT_PTA_TX_ABT_CNT_OFFSET (16) +#define EVENT_PTA_TX_ABT_CNT_FEILD (0xFFFF) +#define EVENT_PTA_RX_ABT_CNT_OFFSET (0) +#define EVENT_PTA_RX_ABT_CNT_FEILD (0xFFFF) +typedef struct _CMD_PTA_CONFIG { + u16 u2Type; + u16 u2Len; + u32 u4ConfigMask; + /* common usage in set/get */ + u32 u4PtaConfig; + u32 u4TxDataTag; + u32 u4RxDataAckTag; + u32 u4RxNswTag; + u32 u4TxAckTag; + u32 u4TxProtFrameTag; + u32 u4RxProtFrameAckTag; + u32 u4TxBMCTag; + u32 u4TxBCNTag; + u32 u4RxSPTag; + u32 u4TxMgmtTag; + u32 u4RxMgmtAckTag; + u32 u4CommActBtWf0Inband; + u32 u4CommActBtWf0Outband; + u32 u4CommActBtWf1Inband; + u32 u4CommActBtWf1Outband; + /* Only used in get */ + u32 u4PtaWF0TxCnt; + u32 u4PtaWF0RxCnt; + u32 u4PtaWF0AbtCnt; + u32 u4PtaWF1TxCnt; + u32 u4PtaWF1RxCnt; + u32 u4PtaWF1AbtCnt; + u32 u4PtaBTTxCnt; + u32 u4PtaBTRxCnt; + u32 u4PtaBTAbtCnt; + u32 u4GrantStat; + u32 u4CoexMode; +} CMD_PTA_CONFIG_T, *P_CMD_PTA_CONFIG_T; + +#ifdef CFG_SUPPORT_EXT_PTA_DEBUG_COMMAND +typedef struct _CMD_EXT_PTA_CONFIG { + u16 u2Type; + u16 u2Len; + u32 u4ConfigMask; + /* common usage in set/get */ + u32 u4ExtPtaConfig; + u32 u4ZbHiRxTag; + u32 u4ZbLoRxTag; + u32 u4ZbHiTxTag; + u32 u4ZbLoTxTag; + u32 u4CommActZbBtUnsafe; + u32 u4CommActZbWf0Unsafe; + u32 u4CommActZbWf1Unsafe; + u32 u4CommActZbBtHsf; + u32 u4CommActZbWf0Hsf; + u32 u4CommActZbWf1Hsf; + /* used in get */ + u32 u4ZbGntCnt; + u32 u4ZbAbtCnt; + u32 u4ZbLoTxReqCnt; + u32 u4ZbHiTxReqCnt; + u32 u4ZbLoRxReqCnt; + u32 u4ZbHiRxReqCnt; +} CMD_EXT_PTA_CONFIG_T, *P_CMD_EXT_PTA_CONFIG_T; +#endif + +/* get report related */ +enum _ENUM_GET_REPORT_ACTION_T { + CMD_GET_REPORT_ENABLE = 1, + CMD_GET_REPORT_DISABLE, + CMD_GET_REPORT_RESET, + CMD_GET_REPORT_GET, + CMD_SET_REPORT_SAMPLE_DUR, + CMD_SET_REPORT_SAMPLE_POINT, + CMD_SET_REPORT_TXTHRES, + CMD_SET_REPORT_RXTHRES, + CMD_GET_REPORT_ACTIONS +}; +#define EVENT_REPORT_OFDM_FCCA (16) +#define EVENT_REPORT_OFDM_FCCA_FEILD (0xffff) +#define EVENT_REPORT_CCK_FCCA (0) +#define EVENT_REPORT_CCK_FCCA_FEILD (0xffff) +#define EVENT_REPORT_OFDM_SIGERR (16) +#define EVENT_REPORT_OFDM_SIGERR_FEILD (0xffff) +#define EVENT_REPORT_CCK_SIGERR (0) +#define EVENT_REPORT_CCK_SIGERR_FEILD (0xffff) +struct CMD_GET_TRAFFIC_REPORT { + u16 u2Type; + u16 u2Len; + /* parameter */ + u8 ucBand; + u8 ucAction; + u8 reserved[2]; + /* report 1 */ + u32 u4FalseCCA; + u32 u4HdrCRC; + u32 u4PktSent; + u32 u4PktRetried; + u32 u4PktTxfailed; + u32 u4RxMPDU; + u32 u4RxFcs; + /* air time report */ + u32 u4FetchSt; /* ms */ + u32 u4FetchEd; /* ms */ + u32 u4ChBusy; /* us */ + u32 u4ChIdle; /* us */ + u32 u4TxAirTime; /* us */ + u32 u4RxAirTime; /* us */ + u32 u4TimerDur; /* ms */ + u32 u4FetchCost; /* us */ + s32 TimerDrift; /* ms */ + s16 u2SamplePoints; /* ms */ + s8 ucTxThres; /* ms */ + s8 ucRxThres; /* ms */ +}; + +/* admission control related define */ +/* support set operations */ +#define ADMIN_CTRL_SET_MODE (0) +#define ADMIN_CTRL_SET_BASE (1) +#define ADMIN_CTRL_SET_TBL1 (2) +#define ADMIN_CTRL_SET_TBL2 (3) +#define ADMIN_CTRL_SET_TBL3 (4) +#define ADMIN_CTRL_SET_METHOD (5) + +/* admission ctrl mode */ +#define ADMIN_CTRL_MODE_DIS (0) +#define ADMIN_CTRL_MODE_AUTO (1) +#define ADMIN_CTRL_MODE_MAN (2) +#define ADMIN_CTRL_MODE_RESET (3) +/* default value */ +#define ADMIN_CTRL_RATE_CODE_NUM (8) /* AUTO_RATE_NUM */ +#define ADMIN_CTRL_TBL_ENTRY_NUM (6) +#define ADMIN_CTRL_MAX_PERCENTAGE (100) +/* status define */ +#define BT_PROF_A2DP_SRC 0x02 +#define BT_PROF_LINK_CONNECTED 0x04 +#define BT_PROF_A2DP_SINK 0x400 +#define ADMIN_LINK_2G BIT(0) +#define ADMIN_LINK_OTHER BIT(1) +#define ADMIN_ENABLED BIT(2) +#define ADMIN_PER_PKT_ENABLED BIT(3) +#define ADMIN_METHOD1_ENABLED BIT(4) +#define ADMIN_METHOD2_ENABLED BIT(5) + +struct ADMIN_CTRL_PARAM { + /* bt info updated to admin ctrl */ + u32 u4CoexMode; + /* Ctrl mode */ + u16 u2eMode; + /* Admin ctrl related */ + u16 u2AdminCtrlBase; + u16 u2CurAdminTime; + u16 u2ForceAdminTime; + /* Rate related */ + u16 au2RateCode[ADMIN_CTRL_RATE_CODE_NUM]; + /* admin ctrl % tbl */ + u8 aucAdminTbl1[ADMIN_CTRL_TBL_ENTRY_NUM]; + u8 aucAdminTbl2[ADMIN_CTRL_TBL_ENTRY_NUM]; + u8 aucAdminTbl3[ADMIN_CTRL_TBL_ENTRY_NUM]; + u8 ucAdminThermalLimit; + u8 ucLastChosenTbl; + u8 ucAdminStatus; + u8 reserved[3]; +}; + +struct CMD_ADMIN_CTRL_CONFIG { + u16 u2Type; + u16 u2Len; + /* parameter */ + u16 u2Action; + u8 reserved[2]; + /* content */ + struct ADMIN_CTRL_PARAM content; +}; + +typedef struct _CMD_ADV_CONFIG_HEADER { + u16 u2Type; + u16 u2Len; +} CMD_ADV_CONFIG_HEADER_T, *P_CMD_ADV_CONFIG_HEADER_T; + +/* noise histogram related */ +enum _ENUM_NOISE_HISTOGRAM_ACTION_T { + CMD_NOISE_HISTOGRAM_ENABLE = 1, + CMD_NOISE_HISTOGRAM_DISABLE, + CMD_NOISE_HISTOGRAM_RESET, + CMD_NOISE_HISTOGRAM_GET, +#if CFG_IPI_2CHAIN_SUPPORT + CMD_NOISE_HISTOGRAM_GET2 +#endif +}; +struct CMD_NOISE_HISTOGRAM_REPORT { + u16 u2Type; + u16 u2Len; + /* parameter */ + u8 ucAction; + u8 reserved[3]; + /* IPI_report */ + u32 u4IPI0; /* Power <= -92 */ + u32 u4IPI1; /* -92 < Power <= -89 */ + u32 u4IPI2; /* -89 < Power <= -86 */ + u32 u4IPI3; /* -86 < Power <= -83 */ + u32 u4IPI4; /* -83 < Power <= -80 */ + u32 u4IPI5; /* -80 < Power <= -75 */ + u32 u4IPI6; /* -75 < Power <= -70 */ + u32 u4IPI7; /* -70 < Power <= -65 */ + u32 u4IPI8; /* -65 < Power <= -60 */ + u32 u4IPI9; /* -60 < Power <= -55 */ + u32 u4IPI10; /* -55 < Power */ +}; +#endif +typedef struct _CMD_SET_DEVICE_MODE_T { + u16 u2ChipID; + u16 u2Mode; +} CMD_SET_DEVICE_MODE_T, *P_CMD_SET_DEVICE_MODE_T; + +#if CFG_SUPPORT_RDD_TEST_MODE +typedef struct _CMD_RDD_CH_T { + u8 ucRddTestMode; + u8 ucRddShutCh; + u8 ucRddStartCh; + u8 ucRddStopCh; + u8 ucRddDfs; + u8 ucReserved; + u8 ucReserved1; + u8 ucReserved2; +} CMD_RDD_CH_T, *P_CMD_RDD_CH_T; + +typedef struct _EVENT_RDD_STATUS_T { + u8 ucRddStatus; + u8 aucReserved[3]; +} EVENT_RDD_STATUS_T, *P_EVENT_RDD_STATUS_T; +#endif + +typedef struct _EVENT_ICAP_STATUS_T { + u8 ucRddStatus; + u8 aucReserved[3]; + u32 u4StartAddress; + u32 u4IcapSieze; +#if CFG_SUPPORT_QA_TOOL + u32 u4IcapContent; +#endif +} EVENT_ICAP_STATUS_T, *P_EVENT_ICAP_STATUS_T; + +#if CFG_SUPPORT_QA_TOOL +typedef struct _ADC_BUS_FMT_T { + u32 u4Dcoc0Q : 14; /* [13:0] */ + u32 u4Dcoc0I : 14; /* [27:14] */ + u32 u4DbgData1 : 4; /* [31:28] */ + + u32 u4Dcoc1Q : 14; /* [45:32] */ + u32 u4Dcoc1I : 14; /* [46:59] */ + u32 u4DbgData2 : 4; /* [63:60] */ + + u32 u4DbgData3; /* [95:64] */ +} ADC_BUS_FMT_T, *P_ADC_BUS_FMT_T; + +typedef struct _IQC_BUS_FMT_T { + s32 u4Iqc0Q : 14; /* [13:0] */ + s32 u4Iqc0I : 14; /* [27:14] */ + s32 u4Na1 : 4; /* [31:28] */ + + s32 u4Iqc1Q : 14; /* [45:32] */ + s32 u4Iqc1I : 14; /* [59:46] */ + s32 u4Na2 : 4; /* [63:60] */ + + s32 u4Na3; /* [95:64] */ +} IQC_BUS_FMT_T, *P_IQC_BUS_FMT_T; + +typedef struct _IQC_160_BUS_FMT_T { + s32 u4Iqc0Q1 : 12; /* [11:0] */ + s32 u4Iqc0I1 : 12; /* [23:12] */ + u32 u4Iqc0Q0P1 : 8; /* [31:24] */ + + s32 u4Iqc0Q0P2 : 4; /* [35:32] */ + s32 u4Iqc0I0 : 12; /* [47:36] */ + s32 u4Iqc1Q1 : 12; /* [59:48] */ + u32 u4Iqc1I1P1 : 4; /* [63:60] */ + + s32 u4Iqc1I1P2 : 8; /* [71:64] */ + s32 u4Iqc1Q0 : 12; /* [83:72] */ + s32 u4Iqc1I0 : 12; /* [95:84] */ +} IQC_160_BUS_FMT_T, *P_IQC_160_BUS_FMT_T; + +typedef struct _SPECTRUM_BUS_FMT_T { + s32 u4DcocQ : 12; /* [11:0] */ + s32 u4DcocI : 12; /* [23:12] */ + s32 u4LpfGainIdx : 4; /* [27:24] */ + s32 u4LnaGainIdx : 2; /* [29:28] */ + s32 u4AssertData : 2; /* [31:30] */ +} SPECTRUM_BUS_FMT_T, *P_SPECTRUM_BUS_FMT_T; + +typedef struct _PACKED_ADC_BUS_FMT_T { + u32 u4AdcQ0T2 : 4; /* [19:16] */ + u32 u4AdcQ0T1 : 4; /* [11:8] */ + u32 u4AdcQ0T0 : 4; /* [3:0] */ + + u32 u4AdcI0T2 : 4; /* [23:20] */ + u32 u4AdcI0T1 : 4; /* [15:12] */ + u32 u4AdcI0T0 : 4; /* [7:4] */ + + u32 u4AdcQ0T5 : 4; /* [43:40] */ + u32 u4AdcQ0T4 : 4; /* [35:32] */ + u32 u4AdcQ0T3 : 4; /* [27:24] */ + + u32 u4AdcI0T5 : 4; /* [47:44] */ + u32 u4AdcI0T4 : 4; /* [39:36] */ + u32 u4AdcI0T3 : 4; /* [31:28] */ + + u32 u4AdcQ1T2 : 4; /* [19:16] */ + u32 u4AdcQ1T1 : 4; /* [11:8] */ + u32 u4AdcQ1T0 : 4; /* [3:0] */ + + u32 u4AdcI1T2 : 4; /* [23:20] */ + u32 u4AdcI1T1 : 4; /* [15:12] */ + u32 u4AdcI1T0 : 4; /* [7:4] */ + + u32 u4AdcQ1T5 : 4; /* [43:40] */ + u32 u4AdcQ1T4 : 4; /* [35:32] */ + u32 u4AdcQ1T3 : 4; /* [27:24] */ + + u32 u4AdcI1T5 : 4; /* [47:44] */ + u32 u4AdcI1T4 : 4; /* [39:36] */ + u32 u4AdcI1T3 : 4; /* [31:28] */ +} PACKED_ADC_BUS_FMT_T, *P_PACKED_ADC_BUS_FMT_T; + +typedef union _ICAP_BUS_FMT { + ADC_BUS_FMT_T rAdcBusData; /* 12 bytes */ + IQC_BUS_FMT_T rIqcBusData; /* 12 bytes */ + IQC_160_BUS_FMT_T rIqc160BusData; /* 12 bytes */ + SPECTRUM_BUS_FMT_T rSpectrumBusData; /* 4 bytes */ + PACKED_ADC_BUS_FMT_T rPackedAdcBusData; /* 12 bytes */ +} ICAP_BUS_FMT, *P_ICAP_BUS_FMT; +#endif + +typedef struct _CMD_SET_TXPWR_CTRL_T { + s8 c2GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ + s8 c2GHotspotPwrOffset; + s8 c2GP2pPwrOffset; + s8 c2GBowPwrOffset; + s8 c5GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ + s8 c5GHotspotPwrOffset; + s8 c5GP2pPwrOffset; + s8 c5GBowPwrOffset; + /* TX power policy when concurrence + * in the same channel + * 0: Highest power has priority + * 1: Lowest power has priority + */ + u8 ucConcurrencePolicy; + s8 acReserved1[3]; /* Must be zero */ + + /* Power limit by channel for all data rates */ + s8 acTxPwrLimit2G[14]; /* Channel 1~14, Unit: 0.5dBm */ + s8 acTxPwrLimit5G[4]; /* UNII 1~4 */ + s8 acReserved2[2]; /* Must be zero */ +} CMD_SET_TXPWR_CTRL_T, *P_CMD_SET_TXPWR_CTRL_T; + +typedef enum _ENUM_NLO_CIPHER_ALGORITHM { + NLO_CIPHER_ALGO_NONE = 0x00, + NLO_CIPHER_ALGO_WEP40 = 0x01, + NLO_CIPHER_ALGO_TKIP = 0x02, + NLO_CIPHER_ALGO_CCMP = 0x04, + NLO_CIPHER_ALGO_WEP104 = 0x05, + NLO_CIPHER_ALGO_WPA_USE_GROUP = 0x100, + NLO_CIPHER_ALGO_RSN_USE_GROUP = 0x100, + NLO_CIPHER_ALGO_WEP = 0x101, +} ENUM_NLO_CIPHER_ALGORITHM, +*P_ENUM_NLO_CIPHER_ALGORITHM; + +typedef enum _ENUM_NLO_AUTH_ALGORITHM { + NLO_AUTH_ALGO_80211_OPEN = 1, + NLO_AUTH_ALGO_80211_SHARED_KEY = 2, + NLO_AUTH_ALGO_WPA = 3, + NLO_AUTH_ALGO_WPA_PSK = 4, + NLO_AUTH_ALGO_WPA_NONE = 5, + NLO_AUTH_ALGO_RSNA = 6, + NLO_AUTH_ALGO_RSNA_PSK = 7, +} ENUM_NLO_AUTH_ALGORITHM, +*P_ENUM_NLO_AUTH_ALGORITHM; + +typedef struct _NLO_NETWORK { + u8 ucNumChannelHint[4]; + u8 ucSSIDLength; + u8 ucCipherAlgo; + u16 u2AuthAlgo; + u8 aucSSID[32]; +} NLO_NETWORK, *P_NLO_NETWORK; + +typedef struct _CMD_NLO_REQ { + u8 ucSeqNum; + u8 ucBssIndex; + u8 fgStopAfterIndication; + u8 ucFastScanIteration; + u16 u2FastScanPeriod; + u16 u2SlowScanPeriod; + u8 ucEntryNum; + u8 ucFlag; /* BIT(0) Check cipher */ + u16 u2IELen; + NLO_NETWORK arNetworkList[16]; + u8 aucIE[0]; +} CMD_NLO_REQ, *P_CMD_NLO_REQ; + +typedef struct _CMD_NLO_CANCEL_T { + u8 ucSeqNum; + u8 ucBssIndex; + u8 aucReserved[2]; +} CMD_NLO_CANCEL, *P_CMD_NLO_CANCEL; + +typedef struct _EVENT_NLO_DONE_T { + u8 ucSeqNum; + u8 ucStatus; + u8 aucReserved[2]; +} EVENT_NLO_DONE_T, *P_EVENT_NLO_DONE_T; + +typedef struct _CMD_HIF_CTRL_T { + u8 ucHifType; + u8 ucHifDirection; + u8 ucHifStop; + u8 aucReserved1; + u8 aucReserved2[32]; +} CMD_HIF_CTRL_T, *P_CMD_HIF_CTRL_T; + +typedef enum _ENUM_HIF_TYPE { + ENUM_HIF_TYPE_SDIO = 0x00, + ENUM_HIF_TYPE_USB = 0x01, + ENUM_HIF_TYPE_PCIE = 0x02, + ENUM_HIF_TYPE_GPIO = 0x03, +} ENUM_HIF_TYPE, +*P_ENUM_HIF_TYPE; + +typedef enum _ENUM_HIF_DIRECTION { + ENUM_HIF_TX = 0x01, + ENUM_HIF_RX = 0x02, + ENUM_HIF_TRX = 0x03, +} ENUM_HIF_DIRECTION, +*P_ENUM_HIF_DIRECTION; + +typedef enum _ENUM_HIF_TRAFFIC_STATUS { + ENUM_HIF_TRAFFIC_BUSY = 0x01, + ENUM_HIF_TRAFFIC_IDLE = 0x02, + ENUM_HIF_TRAFFIC_INVALID = 0x3, +} ENUM_HIF_TRAFFIC_STATUS, +*P_ENUM_HIF_TRAFFIC_STATUS; + +typedef struct _EVENT_HIF_CTRL_T { + u8 ucHifType; + u8 ucHifTxTrafficStatus; + u8 ucHifRxTrafficStatus; + u8 ucReserved1; + u8 aucReserved2[32]; +} EVENT_HIF_CTRL_T, *P_EVENT_HIF_CTRL_T; + +#if CFG_SUPPORT_BUILD_DATE_CODE +typedef struct _CMD_GET_BUILD_DATE_CODE { + u8 aucReserved[4]; +} CMD_GET_BUILD_DATE_CODE, *P_CMD_GET_BUILD_DATE_CODE; + +typedef struct _EVENT_BUILD_DATE_CODE { + u8 aucDateCode[16]; +} EVENT_BUILD_DATE_CODE, *P_EVENT_BUILD_DATE_CODE; +#endif + +typedef struct _CMD_GET_STA_STATISTICS_T { + u8 ucIndex; + u8 ucFlags; + u8 ucReadClear; + u8 ucLlsReadClear; + u8 aucMacAddr[MAC_ADDR_LEN]; + u8 ucResetCounter; + u8 aucReserved1[1]; + u8 aucReserved2[16]; +} CMD_GET_STA_STATISTICS_T, *P_CMD_GET_STA_STATISTICS_T; + +/* per access category statistics */ +typedef struct _WIFI_WMM_AC_STAT_GET_FROM_FW_T { + u32 u4TxFailMsdu; + u32 u4TxRetryMsdu; +} WIFI_WMM_AC_STAT_GET_FROM_FW_T, *P_WIFI_WMM_AC_STAT_GET_FROM_FW_T; + +/* CFG_SUPPORT_WFD */ +typedef struct _EVENT_STA_STATISTICS_T { + /* Event header */ + /* u16 u2Length; */ + /* u16 u2Reserved1; */ /* Must be filled with 0x0001 (EVENT Packet) + */ + /* u8 ucEID; */ + /* u8 ucSeqNum; */ + /* u8 aucReserved2[2]; */ + + /* Event Body */ + u8 ucVersion; + u8 aucReserved1[3]; + u32 u4Flags; /* Bit0: valid */ + + u8 ucStaRecIdx; + u8 ucNetworkTypeIndex; + u8 ucWTEntry; + u8 aucReserved4[1]; + + u8 ucMacAddr[MAC_ADDR_LEN]; + u8 ucPer; /* base: 128 */ + u8 ucRcpi; + + u32 u4PhyMode; /* SGI BW */ + u16 u2LinkSpeed; /* unit is 0.5 Mbits */ + u8 ucLinkQuality; + u8 ucLinkReserved; + + u32 u4TxCount; + u32 u4TxFailCount; + u32 u4TxLifeTimeoutCount; + u32 u4TxDoneAirTime; + u32 u4TransmitCount; /* Transmit in the air (wtbl) */ + u32 u4TransmitFailCount; /* Transmit without ack/ba in the air (wtbl) */ + + WIFI_WMM_AC_STAT_GET_FROM_FW_T + arLinkStatistics[AC_NUM]; /*link layer statistics */ + + u8 ucTemperature; + u8 ucSkipAr; + u8 ucArTableIdx; + u8 ucRateEntryIdx; + u8 ucRateEntryIdxPrev; + u8 ucTxSgiDetectPassCnt; + u8 ucAvePer; + u8 aucArRatePer[AR_RATE_TABLE_ENTRY_MAX]; + u8 aucRateEntryIndex[AUTO_RATE_NUM]; + u8 ucArStateCurr; + u8 ucArStatePrev; + u8 ucArActionType; + u8 ucHighestRateCnt; + u8 ucLowestRateCnt; + u16 u2TrainUp; + u16 u2TrainDown; + u32 u4Rate1TxCnt; + u32 u4Rate1FailCnt; + TX_VECTOR_BBP_LATCH_T rTxVector[ENUM_BAND_NUM]; + MIB_INFO_STAT_T rMibInfo[ENUM_BAND_NUM]; + u8 fgIsForceTxStream; + u8 fgIsForceSeOff; + u8 aucReserved[21]; +} EVENT_STA_STATISTICS_T, *P_EVENT_STA_STATISTICS_T; + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +typedef struct _EVENT_LTE_SAFE_CHN_T { + u8 ucVersion; + u8 aucReserved[3]; + u32 u4Flags; /* Bit0: valid */ + LTE_SAFE_CHN_INFO_T rLteSafeChn; +} EVENT_LTE_SAFE_CHN_T, *P_EVENT_LTE_SAFE_CHN_T; +#endif + +#if CFG_SUPPORT_SNIFFER +typedef struct _CMD_MONITOR_SET_INFO_T { + u8 ucEnable; + u8 ucBand; + u8 ucPriChannel; + u8 ucSco; + u8 ucChannelWidth; + u8 ucChannelS1; + u8 ucChannelS2; + u8 aucResv[9]; +} CMD_MONITOR_SET_INFO_T, *P_CMD_MONITOR_SET_INFO_T; +#endif + +typedef struct _CMD_STATS_LOG_T { + u32 u4DurationInMs; + u8 aucReserved[32]; +} CMD_STATS_LOG_T, *P_CMD_STATS_LOG_T; + +typedef struct _EVENT_WIFI_RDD_TEST_T { + u32 u4FuncIndex; + u32 u4FuncLength; + u32 u4Prefix; + u32 u4Count; + u32 u4SubBandRssi0; + u32 u4SubBandRssi1; + u8 ucRddIdx; + u8 aucReserve[3]; + u8 aucBuffer[0]; +} EVENT_WIFI_RDD_TEST_T, *P_EVENT_WIFI_RDD_TEST_T; + +#if CFG_SUPPORT_MSP +/* EVENT_ID_WLAN_INFO */ +typedef struct _EVENT_WLAN_INFO { + PARAM_TX_CONFIG_T rWtblTxConfig; + PARAM_SEC_CONFIG_T rWtblSecConfig; + PARAM_KEY_CONFIG_T rWtblKeyConfig; + PARAM_PEER_RATE_INFO_T rWtblRateInfo; + PARAM_PEER_BA_CONFIG_T rWtblBaConfig; + PARAM_PEER_CAP_T rWtblPeerCap; + PARAM_PEER_RX_COUNTER_ALL_T rWtblRxCounter; + PARAM_PEER_TX_COUNTER_ALL_T rWtblTxCounter; +} EVENT_WLAN_INFO, *P_EVENT_WLAN_INFO; + +/* EVENT_ID_MIB_INFO */ +typedef struct _EVENT_MIB_INFO { + HW_MIB_COUNTER_T rHwMibCnt; + HW_MIB2_COUNTER_T rHwMib2Cnt; + HW_TX_AMPDU_METRICS_T rHwTxAmpduMts; +} EVENT_MIB_INFO, *P_EVENT_MIB_INFO; +#endif + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +struct EVENT_TX_MCS_INFO { + u16 au2TxRateCode[MCS_INFO_SAMPLE_CNT]; + u8 aucTxRatePer[MCS_INFO_SAMPLE_CNT]; + u8 aucReserved[2]; +}; +#endif + +/*#if (CFG_EEPROM_PAGE_ACCESS == 1)*/ +typedef struct _EVENT_ACCESS_EFUSE { + u32 u4Address; + u32 u4Valid; + u8 aucData[16]; +} EVENT_ACCESS_EFUSE, *P_EVENT_ACCESS_EFUSE; + +typedef struct _EXT_EVENT_EFUSE_FREE_BLOCK_T { + u16 u2FreeBlockNum; + u8 aucReserved[2]; +} EVENT_EFUSE_FREE_BLOCK_T, *P_EVENT_EFUSE_FREE_BLOCK_T; + +typedef struct _EXT_EVENT_GET_TX_POWER_T { + u8 ucTxPwrType; + u8 ucEfuseAddr; + u8 ucTx0TargetPower; + u8 ucDbdcIdx; +} EVENT_GET_TX_POWER_T, *P_EVENT_GET_TX_POWER_T; + +#if CFG_STR_DHCP_RENEW_OFFLOAD +typedef struct _CMD_DHCP_OFFLOAD_SETTING_T { + u32 u4RenewIntv; /* DHCP renew offload interval configured by + * upper-layer */ + u8 aucDhcpServerIpAddr[4]; + u8 ucBssIndex; + u8 ucEnableOffload; + u8 ucSuspend; + u8 ucReserved[1]; +} CMD_DHCP_OFFLOAD_SETTING_T, *P_CMD_DHCP_OFFLOAD_SETTING_T; +#endif + +typedef struct _CMD_SUSPEND_MODE_SETTING_T { + u8 ucBssIndex; + u8 ucEnableSuspendMode; + u8 ucMdtim; /* LP parameter */ + u8 ucReserved1[1]; + u8 ucReserved2[64]; +} CMD_SUSPEND_MODE_SETTING_T, *P_CMD_SUSPEND_MODE_SETTING_T; + +typedef struct _EVENT_UPDATE_COEX_PHYRATE_T { + u8 ucVersion; + u8 aucReserved1[3]; /* 4 byte alignment */ + u32 u4Flags; + u32 au4PhyRateLimit[HW_BSSID_NUM + 1]; +} EVENT_UPDATE_COEX_PHYRATE_T, *P_EVENT_UPDATE_COEX_PHYRATE_T; + +enum CSI_CONTROL_MODE_T { + CSI_CONTROL_MODE_STOP, + CSI_CONTROL_MODE_START, + CSI_CONTROL_MODE_NUM +}; + +enum ENUM_RTT_ROLE_T { + RTT_ROLE_RECEIVING = 0, + RTT_ROLE_SENDING, + RTT_ROLE_NUM +}; + +enum ENUM_RTT_FRAME_TYPE_T { + RTT_FRAME_TYPE_BEACON, + RTT_FRAME_TYPE_QOS_DATA, + RTT_FRAME_TYPE_NUM +}; + +struct CMD_CSI_CONTROL_T { + u8 ucMode; + u8 ucBand; + u8 ucWf; + u8 ucRole; + u8 ucFrameType; + u8 ucFrameTypeIndex; + u8 ucReserved[2]; +}; + +#ifdef CFG_DUMP_TXPOWR_TABLE +struct CMD_GET_TXPWR_TBL { + u8 ucDbdcIdx; + u8 aucReserved[3]; +}; + +struct EVENT_GET_TXPWR_TBL { + u8 ucCenterCh; + u8 ucFeLoss; + u8 aucReserved[2]; + struct POWER_LIMIT tx_pwr_tbl[TXPWR_TBL_NUM]; +}; +#endif + +struct EVENT_GET_TEMPERATURE { + u8 ucTemperaute; + u8 aucReserved[3]; +}; +/*#endif*/ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void nicCmdEventQueryMcrRead(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +/* Nic cmd/event for Coex related */ +void nicCmdEventQueryCoexIso(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +#if CFG_SUPPORT_QA_TOOL +void nicCmdEventQueryRxStatistics(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +u32 TsfRawData2IqFmt(P_EVENT_DUMP_MEM_T prEventDumpMem); + +s32 GetIQData(s32 **prIQAry, u32 *prDataLen, u32 u4IQ, u32 u4GetWf1); + +#if CFG_SUPPORT_TX_BF +void nicCmdEventPfmuDataRead(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventPfmuTagRead(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +#endif +#if CFG_SUPPORT_MU_MIMO +void nicCmdEventGetQd(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +void nicCmdEventGetCalcLq(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +void nicCmdEventGetCalcInitMcs(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +#endif +#endif + +void nicEventQueryMemDump(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryMemDump(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryChipConfig(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryRfTestATInfo(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventSetCommon(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventSetDisassociate(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventSetIpAddress(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryLinkQuality(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryLinkSpeed(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryStatistics(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventEnterRfTest(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventLeaveRfTest(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryMcastAddr(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryEepromRead(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventSetMediaStreamMode(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventSetStopSchedScan(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +/* Statistics responder */ +void nicCmdEventQueryXmitOk(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryRecvOk(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryXmitError(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryRecvError(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryRecvNoBuffer(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryRecvCrcError(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryRecvErrorAlignment(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +/* for timeout check */ +void nicOidCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo); + +void nicCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); + +void nicOidCmdEnterRFTestTimeout(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo); + +#if CFG_SUPPORT_BUILD_DATE_CODE +void nicCmdEventBuildDateCode(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +#endif + +void nicCmdEventQueryStaStatistics(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +/* 4 Auto Channel Selection */ +void nicCmdEventQueryLteSafeChn(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +#endif + +#if CFG_SUPPORT_BATCH_SCAN +void nicCmdEventBatchScanResult(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +#endif + +#if CFG_SUPPORT_ADVANCE_CONTROL +void nicCmdEventQueryAdvCtrl(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +#endif + +void nicEventRddPulseDump(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryWlanInfo(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void nicCmdEventQueryMibInfo(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +void nicCmdEventTxMcsInfo(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +#endif + +void nicCmdEventQueryNicCapabilityV2(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +WLAN_STATUS nicCmdEventQueryNicTxResource(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +WLAN_STATUS nicCmdEventQueryNicEfuseAddr(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +WLAN_STATUS nicCmdEventQueryEfuseOffset(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +WLAN_STATUS nicCmdEventQueryNicCoexFeature(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +WLAN_STATUS nicCmdEventQueryNicCsumOffload(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +#endif + +void nicEventLinkQuality(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventLayer0ExtMagic(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventMicErrorInfo(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventScanDone(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventNloDone(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventSleepyNotify(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventBtOverWifi(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventStatistics(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventWlanInfo(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventMibInfo(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +void nicEventTxMcsInfo(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +#endif +void nicEventBeaconTimeout(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventUpdateNoaParams(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventStaAgingTimeout(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventApObssStatus(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventRoamingStatus(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventSendDeauth(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventUpdateRddStatus(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventUpdateBwcsStatus(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventUpdateBcmDebug(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventAddPkeyDone(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventIcapDone(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventDebugMsg(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventTdls(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventDumpMem(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventAssertDump(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventRddSendPulse(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +void nicEventUpdateCoexPhyrate(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +#ifdef CFG_SUPPORT_ANT_DIV +void nicCmdEventAntDiv(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +#endif + +#if (CFG_WOW_SUPPORT == 1) +void nicEventWakeUpReason(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +#endif +void nicEventCSIData(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); + +#if CFG_SUPPORT_REPLAY_DETECTION +void nicCmdEventSetAddKey(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +void nicOidCmdTimeoutSetAddKey(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo); + +void nicEventGetGtkDataSync(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen); +#endif + +#ifdef CFG_DUMP_TXPOWR_TABLE +void nicCmdEventGetTxPwrTbl(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); +#endif + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic_init_cmd_event.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic_init_cmd_event.h new file mode 100644 index 00000000000000..8db65f510552e3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/nic_init_cmd_event.h @@ -0,0 +1,269 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "nic_init_cmd_event.h" + * \brief This file contains the declairation file of the WLAN initialization + * routines for MediaTek Inc. 802.11 Wireless LAN Adapters. + */ + +#ifndef _NIC_INIT_CMD_EVENT_H +#define _NIC_INIT_CMD_EVENT_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "gl_typedef.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define INIT_CMD_STATUS_SUCCESS 0 +#define INIT_CMD_STATUS_REJECTED_INVALID_PARAMS 1 +#define INIT_CMD_STATUS_REJECTED_CRC_ERROR 2 +#define INIT_CMD_STATUS_REJECTED_DECRYPT_FAIL 3 +#define INIT_CMD_STATUS_UNKNOWN 4 + +#define EVENT_HDR_WITHOUT_RXD_SIZE \ + (OFFSET_OF(WIFI_EVENT_T, aucBuffer[0]) - \ + OFFSET_OF(WIFI_EVENT_T, u2PacketLength)) + +#define INIT_PKT_FT_CMD 0x2 +#define INIT_PKT_FT_PDA_FWDL 0x3 + +#define INIT_CMD_PQ_ID (0x8000) +#define INIT_CMD_PACKET_TYPE_ID (0xA0) + +#define INIT_CMD_PDA_PQ_ID (0xF800) +#define INIT_CMD_PDA_PACKET_TYPE_ID (0xA0) + +#if (CFG_UMAC_GENERATION >= 0x20) +#define TXD_Q_IDX_MCU_RQ0 0 +#define TXD_Q_IDX_MCU_RQ1 1 +#define TXD_Q_IDX_MCU_RQ2 2 +#define TXD_Q_IDX_MCU_RQ3 3 + +#define TXD_Q_IDX_PDA_FW_DL 0x1E + +/* DW0 Bit31 */ +#define TXD_P_IDX_LMAC 0 +#define TXD_P_IDX_MCU 1 + +/* DW1 Bit 14:13 */ +#define TXD_HF_NON_80211_FRAME 0x0 +#define TXD_HF_CMD 0x1 +#define TXD_HF_80211_NORMAL 0x2 +#define TXD_HF_80211_ENHANCEMENT 0x3 + +/* DW1 Bit 15 */ +#define TXD_FT_OFFSET 15 +#define TXD_FT_SHORT_FORMAT 0x0 +#define TXD_FT_LONG_FORMAT 0x1 + +/* DW1 Bit 16 */ +#define TXD_TXDLEN_OFFSET 16 +#define TXD_TXDLEN_1PAGE 0x0 +#define TXD_TXDLEN_2PAGE 0x1 + +/* DW1 Bit 25:24 */ +#define TXD_PKT_FT_CUT_THROUGH 0x0 +#define TXD_PKT_FT_STORE_FORWARD 0X1 +#define TXD_PKT_FT_CMD 0X2 +#define TXD_PKT_FT_PDA_FW 0X3 +#endif + +typedef enum _ENUM_INIT_CMD_ID { + INIT_CMD_ID_DOWNLOAD_CONFIG = 1, + INIT_CMD_ID_WIFI_START, + INIT_CMD_ID_ACCESS_REG, + INIT_CMD_ID_QUERY_PENDING_ERROR, + INIT_CMD_ID_PATCH_START, + INIT_CMD_ID_PATCH_WRITE, + INIT_CMD_ID_PATCH_FINISH, + INIT_CMD_ID_PATCH_SEMAPHORE_CONTROL = 0x10, + INIT_CMD_ID_HIF_LOOPBACK = 0x20, +#if CFG_SUPPORT_COMPRESSION_FW_OPTION + INIT_CMD_ID_DECOMPRESSED_WIFI_START = 0xFF, +#endif + INIT_CMD_ID_NUM +} ENUM_INIT_CMD_ID, +*P_ENUM_INIT_CMD_ID; + +typedef enum _ENUM_INIT_EVENT_ID { + INIT_EVENT_ID_CMD_RESULT = 1, + INIT_EVENT_ID_ACCESS_REG, + INIT_EVENT_ID_PENDING_ERROR, + INIT_EVENT_ID_PATCH_SEMA_CTRL +} ENUM_INIT_EVENT_ID, +*P_ENUM_INIT_EVENT_ID; + +typedef enum _ENUM_INIT_PATCH_STATUS { + PATCH_STATUS_NO_SEMA_NEED_PATCH = 0, /* no SEMA, need patch */ + PATCH_STATUS_NO_NEED_TO_PATCH, /* patch is DL & ready */ + PATCH_STATUS_GET_SEMA_NEED_PATCH, /* get SEMA, need patch */ + PATCH_STATUS_RELEASE_SEMA /* release SEMA */ +} ENUM_INIT_PATCH_STATUS, +*P_ENUM_INIT_PATCH_STATUS; + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef u8 CMD_STATUS; + +/* commands */ +typedef struct _INIT_WIFI_CMD_T { + u8 ucCID; + u8 ucPktTypeID; /* Must be 0xA0 (CMD Packet) */ + u8 ucReserved; + u8 ucSeqNum; + + u8 ucD2B0Rev; /* padding fields, hw may auto modify this field */ + u8 ucExtenCID; /* Extend CID */ + u8 ucS2DIndex; /* Index for Src to Dst in CMD usage */ + u8 ucExtCmdOption; /* Extend CID option */ + + u32 au4D3toD7Rev[5]; /* padding fields */ + + u8 aucBuffer[0]; +} INIT_WIFI_CMD_T, *P_INIT_WIFI_CMD_T; + +typedef struct _INIT_HIF_TX_HEADER_T { + u16 u2TxByteCount; /* Max value is over 2048 */ + u16 u2PQ_ID; /* Must be 0x8000 (Port1, Queue 0) */ + + u8 ucWlanIdx; + u8 ucHeaderFormat; + u8 ucHeaderPadding; + u8 ucPktFt : 2; + u8 ucOwnMAC : 6; + u32 au4D2toD7Rev[6]; + + u16 u2Length; + u16 u2PqId; + + INIT_WIFI_CMD_T rInitWifiCmd; +} INIT_HIF_TX_HEADER_T, *P_INIT_HIF_TX_HEADER_T; + +#define DOWNLOAD_CONFIG_ENCRYPTION_MODE BIT(0) +#define DOWNLOAD_CONFIG_KEY_INDEX_MASK BITS(1, 2) +#define DOWNLOAD_CONFIG_RESET_OPTION BIT(3) +#define DOWNLOAD_CONFIG_WORKING_PDA_OPTION BIT(4) +#define DOWNLOAD_CONFIG_ACK_OPTION BIT(31) +typedef struct _INIT_CMD_DOWNLOAD_CONFIG { + u32 u4Address; + u32 u4Length; + u32 u4DataMode; +} INIT_CMD_DOWNLOAD_CONFIG, *P_INIT_CMD_DOWNLOAD_CONFIG; + +#define START_OVERRIDE_START_ADDRESS BIT(0) +#define START_DELAY_CALIBRATION BIT(1) +#define START_WORKING_PDA_OPTION BIT(2) +#define START_CRC_CHECK BIT(3) +#define CHANGE_DECOMPRESSION_TMP_ADDRESS BIT(4) + +#if CFG_SUPPORT_COMPRESSION_FW_OPTION +#define WIFI_FW_DECOMPRESSION_FAILED 0xFF +typedef struct _INIT_CMD_WIFI_DECOMPRESSION_START { + u32 u4Override; + u32 u4Address; + u32 u4Region1length; + u32 u4Region2length; + u32 u4Region1Address; + u32 u4Region2Address; + u32 u4BlockSize; + u32 u4Region1CRC; + u32 u4Region2CRC; + u32 u4DecompressTmpAddress; +} INIT_CMD_WIFI_DECOMPRESSION_START, *P_INIT_CMD_WIFI_DECOMPRESSION_START; +#endif + +typedef struct _INIT_CMD_WIFI_START { + u32 u4Override; + u32 u4Address; +} INIT_CMD_WIFI_START, *P_INIT_CMD_WIFI_START; + +#define PATCH_GET_SEMA_CONTROL 1 +#define PATCH_RELEASE_SEMA_CONTROL 0 +typedef struct _INIT_CMD_PATCH_SEMA_CONTROL { + u8 ucGetSemaphore; + u8 aucReserved[3]; +} INIT_CMD_PATCH_SEMA_CONTROL, *P_INIT_CMD_PATCH_SEMA_CONTROL; + +typedef struct _INIT_CMD_ACCESS_REG { + u8 ucSetQuery; + u8 aucReserved[3]; + u32 u4Address; + u32 u4Data; +} INIT_CMD_ACCESS_REG, *P_INIT_CMD_ACCESS_REG; + +/* Events */ +typedef struct _INIT_WIFI_EVENT_T { + u32 au4HwMacRxDesc[4]; + + u16 u2RxByteCount; + u16 u2PacketType; /* Must be filled with 0xE000 (EVENT Packet) */ + u8 ucEID; + u8 ucSeqNum; + u8 aucReserved[2]; + + u8 aucBuffer[0]; +} INIT_WIFI_EVENT_T, *P_INIT_WIFI_EVENT_T; + +typedef struct _INIT_HIF_RX_HEADER_T { + INIT_WIFI_EVENT_T rInitWifiEvent; +} INIT_HIF_RX_HEADER_T, *P_INIT_HIF_RX_HEADER_T; + +typedef struct _INIT_EVENT_CMD_RESULT { + u8 ucStatus; /* 0: success */ + /* 1: rejected by invalid param */ + /* 2: rejected by incorrect CRC */ + /* 3: rejected by decryption failure */ + /* 4: unknown CMD */ + /* 5: timeout */ + u8 aucReserved[3]; +} INIT_EVENT_CMD_RESULT, *P_INIT_EVENT_CMD_RESULT, INIT_EVENT_PENDING_ERROR, +*P_INIT_EVENT_PENDING_ERROR; + +typedef struct _INIT_EVENT_ACCESS_REG { + u32 u4Address; + u32 u4Data; +} INIT_EVENT_ACCESS_REG, *P_INIT_EVENT_ACCESS_REG; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/p2p_precomp.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/p2p_precomp.h new file mode 100644 index 00000000000000..3928bb9229e673 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/p2p_precomp.h @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file p2p_precomp.h + * \brief Collection of most compiler flags for p2p driver are described + * here. + * + * In this file we collect all compiler flags and detail the p2p driver + * behavior if enable/disable such switch or adjust numeric parameters. + */ + +#ifndef _P2P_PRECOMP_H +#define _P2P_PRECOMP_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "gl_os.h" /* Include "config.h" */ + +#include "gl_p2p_os.h" + +#include "debug.h" + +#include "link.h" +#include "queue.h" + +/*------------------------------------------------------------------------------ + * .\include\mgmt + *------------------------------------------------------------------------------ + */ +#include "wlan_typedef.h" + +#include "mac.h" + +/* Dependency: mac.h (MAC_ADDR_LEN) */ +#include "wlan_def.h" + +#include "roaming_fsm.h" + +/*------------------------------------------------------------------------------ + * .\include\nic + *------------------------------------------------------------------------------ + */ +/* Dependency: wlan_def.h (ENUM_NETWORK_TYPE_T) */ +#include "cmd_buf.h" + +/* Dependency: mac.h (MAC_ADDR_LEN) */ +#include "nic_cmd_event.h" + +/* Dependency: nic_cmd_event.h (P_EVENT_CONNECTION_STATUS) */ +#include "nic.h" + +#include "nic_init_cmd_event.h" + +#include "hif_rx.h" +#include "hif_tx.h" + +#include "nic_tx.h" + +/* Dependency: hif_rx.h (P_HIF_RX_HEADER_T) */ +#include "nic_rx.h" + +#include "que_mgt.h" + +#include "nic_rate.h" + +#if CFG_ENABLE_WIFI_DIRECT +#include "p2p_typedef.h" +#include "p2p_cmd_buf.h" +#include "p2p_nic_cmd_event.h" +#include "p2p_mac.h" +#include "p2p_nic.h" +#endif + +/*------------------------------------------------------------------------------ + * .\include\mgmt + *------------------------------------------------------------------------------ + */ + +#include "hem_mbox.h" + +#include "scan.h" +#include "bss.h" + +#include "wlan_lib.h" +#include "wlan_oid.h" +#include "wlan_bow.h" + +#include "wlan_p2p.h" + +#include "hal.h" + +#include "reg.h" + +#include "rlm.h" +#include "rlm_domain.h" +#include "rlm_protection.h" +#include "rlm_obss.h" +#include "rate.h" + +#include "aa_fsm.h" + +#include "cnm_timer.h" + +#include "pwr_mgt.h" + +#include "cnm.h" +/* Dependency: aa_fsm.h (ENUM_AA_STATE_T), p2p_fsm.h + * (WPS_ATTRI_MAX_LEN_DEVICE_NAME) */ +#include "cnm_mem.h" +#include "cnm_scan.h" + +#include "p2p_rlm_obss.h" +#include "p2p_bss.h" +#include "p2p.h" +/* Dependency: cnm_timer.h (TIMER_T) */ +#include "p2p_fsm.h" +#include "p2p_scan.h" +#include "p2p_func.h" +#include "p2p_rlm.h" +#include "p2p_assoc.h" +#include "p2p_ie.h" + +#include "privacy.h" + +#include "mib.h" + +#include "auth.h" +#include "assoc.h" + +#include "ais_fsm.h" + +#include "adapter.h" + +#include "que_mgt.h" +#include "rftest.h" + +#include "rsn.h" + +/*------------------------------------------------------------------------------ + * NVRAM structure + *------------------------------------------------------------------------------ + */ +#include "CFG_Wifi_File.h" + +#include "gl_p2p_kal.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/p2p_typedef.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/p2p_typedef.h new file mode 100644 index 00000000000000..79734f53324bc0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/p2p_typedef.h @@ -0,0 +1,202 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file p2p_typedef.h + * \brief Declaration of data type and return values of internal protocol + * stack. + * + * In this file we declare the data type and return values which will be + * exported to all MGMT Protocol Stack. + */ + +#ifndef _P2P_TYPEDEF_H +#define _P2P_TYPEDEF_H + +#if CFG_ENABLE_WIFI_DIRECT + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* + * type definition of pointer to p2p structure + */ +/* typedef struct _GL_P2P_INFO_T GL_P2P_INFO_T, *P_GL_P2P_INFO_T; */ +typedef struct _P2P_INFO_T P2P_INFO_T, *P_P2P_INFO_T; + +typedef struct _P2P_FSM_INFO_T P2P_FSM_INFO_T, *P_P2P_FSM_INFO_T; + +typedef struct _P2P_DEV_FSM_INFO_T P2P_DEV_FSM_INFO_T, *P_P2P_DEV_FSM_INFO_T; + +typedef struct _P2P_ROLE_FSM_INFO_T P2P_ROLE_FSM_INFO_T, *P_P2P_ROLE_FSM_INFO_T; + +typedef struct _P2P_CONNECTION_SETTINGS_T P2P_CONNECTION_SETTINGS_T, + *P_P2P_CONNECTION_SETTINGS_T; + +/* Type definition for function pointer to p2p function*/ +typedef u8 (*P2P_LAUNCH)(P_GLUE_INFO_T prGlueInfo); + +typedef u8 (*P2P_REMOVE)(P_GLUE_INFO_T prGlueInfo, u8 fgIsWlanLaunched); + +typedef u8 (*KAL_P2P_GET_CIPHER)(IN P_GLUE_INFO_T prGlueInfo); + +typedef u8 (*KAL_P2P_GET_TKIP_CIPHER)(IN P_GLUE_INFO_T prGlueInfo); + +typedef u8 (*KAL_P2P_GET_CCMP_CIPHER)(IN P_GLUE_INFO_T prGlueInfo); + +typedef u8 (*KAL_P2P_GET_WSC_MODE)(IN P_GLUE_INFO_T prGlueInfo); + +typedef struct net_device *(*KAL_P2P_GET_DEV_HDLR)(P_GLUE_INFO_T prGlueInfo); + +typedef void (*KAL_P2P_SET_MULTICAST_WORK_ITEM)(P_GLUE_INFO_T prGlueInfo); + +typedef void (*P2P_NET_REGISTER)(P_GLUE_INFO_T prGlueInfo); + +typedef void (*P2P_NET_UNREGISTER)(P_GLUE_INFO_T prGlueInfo); + +typedef void (*KAL_P2P_UPDATE_ASSOC_INFO)(IN P_GLUE_INFO_T prGlueInfo, + IN u8 *pucFrameBody, + IN u32 u4FrameBodyLen, + IN u8 fgReassocRequest); + +typedef u8 (*P2P_VALIDATE_AUTH)(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN PP_STA_RECORD_T pprStaRec, + OUT u16 *pu2StatusCode); + +typedef u8 (*P2P_VALIDATE_ASSOC_REQ)(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT u16 *pu4ControlFlags); + +typedef void (*P2P_RUN_EVENT_AAA_TX_FAIL)(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec); + +typedef u8 (*P2P_PARSE_CHECK_FOR_P2P_INFO_ELEM)(IN P_ADAPTER_T prAdapter, + IN u8 *pucBuf, + OUT u8 *pucOuiType); + +typedef WLAN_STATUS (*P2P_RUN_EVENT_AAA_COMPLETE)(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec); + +typedef void (*P2P_PROCESS_EVENT_UPDATE_NOA_PARAM)(IN P_ADAPTER_T prAdapter, + u8 ucNetTypeIndex, + P_EVENT_UPDATE_NOA_PARAMS_T + prEventUpdateNoaParam); + +typedef void (*SCAN_P2P_PROCESS_BEACON_AND_PROBE_RESP)(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_WLAN_STATUS prStatus, + IN P_BSS_DESC_T prBssDesc, + IN P_WLAN_BEACON_FRAME_T + prWlanBeaconFrame); + +typedef void (*P2P_RX_PUBLIC_ACTION_FRAME)(P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb); + +typedef void (*RLM_RSP_GENERATE_OBSS_SCAN_IE)(P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo); + +typedef void (*RLM_UPDATE_BW_BY_CH_LIST_FOR_AP)(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo); + +typedef void (*RLM_PROCESS_PUBLIC_ACTION)(P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb); + +typedef void (*RLM_PROCESS_HT_ACTION)(P_ADAPTER_T prAdapter, + P_SW_RFB_T prSwRfb); + +typedef void (*RLM_UPDATE_PARAMS_FOR_AP)(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + u8 fgUpdateBeacon); + +typedef void (*RLM_HANDLE_OBSS_STATUS_EVENT_PKT)(P_ADAPTER_T prAdapter, + P_EVENT_AP_OBSS_STATUS_T + prObssStatus); + +typedef u8 (*P2P_FUNC_VALIDATE_PROBE_REQ)(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT u32 *pu4ControlFlags); + +typedef void (*RLM_BSS_INIT_FOR_AP)(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo); + +typedef u32 (*P2P_GET_PROB_RSP_IE_TABLE_SIZE)(void); + +typedef u8 *(*P2P_BUILD_REASSOC_REQ_FRAME_COMMON_IES)(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T + prMsduInfo, + IN u8 *pucBuffer); + +typedef void (*P2P_FUNC_DISCONNECT)(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN u8 fgSendDeauth, + IN u16 u2ReasonCode); + +typedef void (*P2P_FSM_RUN_EVENT_RX_DEAUTH)(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb); + +typedef void (*P2P_FSM_RUN_EVENT_RX_DISASSOC)(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb); + +typedef u8 (*P2P_FUN_IS_AP_MODE)(IN P_P2P_FSM_INFO_T prP2pFsmInfo); + +typedef void (*P2P_FSM_RUN_EVENT_BEACON_TIMEOUT)(IN P_ADAPTER_T prAdapter); + +typedef void (*P2P_FUNC_STORE_ASSOC_RSP_IE_BUFFER)(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb); + +typedef void (*P2P_GENERATE_P2P_IE)(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo); + +typedef u32 (*P2P_CALCULATE_P2P_IE_LEN)(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_STA_RECORD_T prStaRec); + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/precomp.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/precomp.h new file mode 100644 index 00000000000000..814cab3d0ef2de --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/precomp.h @@ -0,0 +1,313 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file precomp.h + * \brief Collection of most compiler flags are described here. + * + * In this file we collect all compiler flags and detail the driver behavior + * if enable/disable such switch or adjust numeric parameters. + */ + +#ifndef _PRECOMP_H +#define _PRECOMP_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +//#define DBG 1 + +#ifdef __GNUC__ +#ifdef DBG +#if (DBG == 0) +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" +#pragma GCC diagnostic ignored "-Wdeclaration-after-statement" +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#pragma GCC diagnostic ignored "-Wcast-function-type" +#pragma GCC diagnostic ignored "-Wstringop-overread" +#pragma GCC diagnostic ignored "-Wenum-conversion" +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wempty-body" +#endif +#endif +#endif + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "gl_os.h" /* Include "config.h" */ + +#if CFG_ENABLE_WIFI_DIRECT +#include "gl_p2p_os.h" +#endif + +#include "debug.h" + +#include "link.h" +#include "queue.h" + +/*------------------------------------------------------------------------------ + * .\include\mgmt + *------------------------------------------------------------------------------ + */ +#include "wlan_typedef.h" + +#include "mac.h" + +/* Dependency: mac.h (MAC_ADDR_LEN) */ +#include "wlan_def.h" + +#if CFG_SUPPORT_SWCR +#include "swcr.h" +#endif + +/*------------------------------------------------------------------------------ + * .\include\nic + *------------------------------------------------------------------------------ + */ +/* Dependency: wlan_def.h (ENUM_NETWORK_TYPE_T) */ +#include "cmd_buf.h" + +/* Dependency: mac.h (MAC_ADDR_LEN) */ +#include "nic_cmd_event.h" + +/* Dependency: nic_cmd_event.h (P_EVENT_CONNECTION_STATUS) */ +#include "nic.h" + +#include "nic_init_cmd_event.h" + +#include "hif_rx.h" +#include "hif_tx.h" + +#include "nic_tx.h" + +/* Dependency: hif_rx.h (P_HIF_RX_HEADER_T) */ +#include "nic_rx.h" + +#include "nic_umac.h" + +#include "bss.h" + +#include "nic_rate.h" + +#if CFG_ENABLE_WIFI_DIRECT +#include "p2p_typedef.h" +#include "p2p_cmd_buf.h" +#include "p2p_nic_cmd_event.h" +#include "p2p_mac.h" +#include "p2p_nic.h" +#endif + +/*------------------------------------------------------------------------------ + * .\include\mgmt + *------------------------------------------------------------------------------ + */ + +#include "hem_mbox.h" + +#include "scan.h" + +#include "wlan_lib.h" +#include "wlan_oid.h" + +#if CFG_ENABLE_WIFI_DIRECT +#include "wlan_p2p.h" +#endif + +#include "hal.h" + +#include "reg.h" + +#include "rlm.h" +#include "rlm_domain.h" +#include "rlm_protection.h" +#include "rlm_obss.h" +#include "rate.h" +#if CFG_SUPPORT_802_11V +#include "wnm.h" +#endif + +#include "aa_fsm.h" + +#include "cnm_timer.h" + +#include "que_mgt.h" + +#include "pwr_mgt.h" + +#include "cnm.h" +/* Dependency: aa_fsm.h (ENUM_AA_STATE_T), p2p_fsm.h + * (WPS_ATTRI_MAX_LEN_DEVICE_NAME) */ +#include "cnm_mem.h" +#include "cnm_scan.h" + +#if CFG_ENABLE_WIFI_DIRECT +#include "p2p_rlm_obss.h" +#include "p2p.h" + +#include "p2p_rlm.h" +#include "p2p_assoc.h" +#include "p2p_ie.h" +#include "p2p_role.h" + +#include "p2p_func.h" +#include "p2p_scan.h" +#include "p2p_dev.h" +#include "p2p_fsm.h" +#endif + +#include "privacy.h" + +#include "mib.h" + +#include "auth.h" +#include "assoc.h" + +#if CFG_SUPPORT_ROAMING +#include "roaming_fsm.h" +#endif + +#include "ais_fsm.h" + +#include "adapter.h" + +#include "que_mgt.h" +#include "rftest.h" + +#include "rsn.h" + +/*------------------------------------------------------------------------------ + * NVRAM structure + *------------------------------------------------------------------------------ + */ +#include "CFG_Wifi_File.h" + +#if CFG_ENABLE_WIFI_DIRECT +#include "gl_p2p_kal.h" +#endif + +#if CFG_SUPPORT_TDLS +#include "tdls.h" +#endif + +#if CFG_SUPPORT_QA_TOOL +#include "gl_qa_agent.h" +#endif + +/*------------------------------------------------------------------------------ + * Memory Prealloc + *------------------------------------------------------------------------------ + */ +#ifdef CFG_PREALLOC_MEMORY +#include "prealloc.h" +#endif + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +void rlmDomainBuildCmdByDefaultTable( + P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd, u16 u2DefaultTableIndex); +void rlmDomainBuildCmdByConfigTable( + P_ADAPTER_T prAdapter, P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd); +u8 rlmDomainGetTxPwrLimit(u32 country_code, P_GLUE_INFO_T prGlueInfo, + P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T pSetCmd_2g, + P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T pSetCmd_5g); +s8 rlmDomainTxPwrLimitGetChIdx(struct TX_PWR_LIMIT_DATA *pTxPwrLimit, + u8 ucChannel); +u8 rlmDomainTxPwrLimitLoadChannelSetting(u8 *pucBuf, u32 *pu4Pos, u32 u4BufEnd, + struct TX_PWR_LIMIT_DATA *pTxPwrLimit, + u8 ucSectionIdx); +u8 rlmDomainTxPwrLimitLoad(P_ADAPTER_T prAdapter, u8 *pucBuf, u32 u4BufLen, + u32 u4CountryCode, + struct TX_PWR_LIMIT_DATA *pTxPwrLimit); +void rlmDomainTxPwrLimitSetChValues(P_CMD_CHANNEL_POWER_LIMIT_V2 pCmd, + struct CHANNEL_TX_PWR_LIMIT *pChTxPwrLimit); +void rlmDomainTxPwrLimitSetValues( + P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T pSetCmd, + struct TX_PWR_LIMIT_DATA *pTxPwrLimit); +u8 rlmDomainTxPwrLimitLoadFromFile(P_ADAPTER_T prAdapter, u32 u4CountryCode, + struct TX_PWR_LIMIT_DATA *pTxPwrLimit); +void saaSendAuthSeq3(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec); +void tkipMicB(IN OUT u32 *pu4L, IN OUT u32 *pu4R); +void tkipMicGen(IN u8 *pucMickey, IN u8 *pucData, IN u32 u4DataLen, + IN u8 *pucSa, IN u8 *pucDa, IN u8 ucPriority, OUT u8 *pucMic); +void tkipMicEncapsulate(IN u8 *pucDa, IN u8 *pucSa, IN u8 ucPriority, + IN u16 u2PayloadLen, IN u8 *pucPayload, IN u8 *pucMic, + IN u8 *pucMicKey); + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +s32 priv_driver_last_sec_mcs_info(IN P_ADAPTER_T prAdapter, IN char *pcCommand, + IN int i4TotalLen, + P_PARAM_HW_WLAN_INFO_T prHwWlanInfo, + struct PARAM_TX_MCS_INFO *prTxMcsInfo); +#endif + +s32 priv_driver_tx_rate_info(IN char *pcCommand, IN int i4TotalLen, + u8 fgDumpAll, P_PARAM_HW_WLAN_INFO_T prHwWlanInfo, + P_PARAM_GET_STA_STATISTICS prQueryStaStatistics); + +s32 priv_driver_last_rx_rssi(P_ADAPTER_T prAdapter, IN char *pcCommand, + IN int i4TotalLen, IN u8 ucWlanIdx); + +s32 priv_driver_rx_rate_info(P_ADAPTER_T prAdapter, IN char *pcCommand, + IN int i4TotalLen, IN u8 ucWlanIdx); + +s32 priv_driver_tx_vector_info(IN char *pcCommand, IN int i4TotalLen, + IN P_TX_VECTOR_BBP_LATCH_T prTxV); + +s32 priv_driver_rate_to_string(IN char *pcCommand, IN int i4TotalLen, u8 TxRx, + P_PARAM_HW_WLAN_INFO_T prHwWlanInfo); + +void parseNoiseHistogramReport(s32 *i4BytesWritten, s8 *pcCommand, + int *i4TotalLen, + IN struct CMD_NOISE_HISTOGRAM_REPORT *cmd); + +WLAN_STATUS +batchConvertResult(IN P_EVENT_BATCH_RESULT_T prEventBatchResult, + OUT void *pvBuffer, IN u32 u4MaxBufferLen, + OUT u32 *pu4RetLen); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +extern int mtk_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id); +extern void mtk_sdio_remove(struct sdio_func *func); +int mtk_sdio_async_irq_enable(struct sdio_func *func); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/pwr_mgt.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/pwr_mgt.h new file mode 100644 index 00000000000000..b0c3cd1c5efe82 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/pwr_mgt.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "pwr_mgt.h" + * \brief In this file we define the STATE and EVENT for Power Management + * FSM. + * + * The SCAN FSM is responsible for performing SCAN behavior when the Arbiter + * enter ARB_STATE_SCAN. The STATE and EVENT for SCAN FSM are defined here with + * detail description. + */ + +#ifndef _PWR_MGT_H +#define _PWR_MGT_H +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define PM_UAPSD_AC0 (BIT(0)) +#define PM_UAPSD_AC1 (BIT(1)) +#define PM_UAPSD_AC2 (BIT(2)) +#define PM_UAPSD_AC3 (BIT(3)) + +#define PM_UAPSD_ALL (PM_UAPSD_AC0 | PM_UAPSD_AC1 | \ + PM_UAPSD_AC2 | PM_UAPSD_AC3) +#define PM_UAPSD_NONE 0 + +#define LP_OWN_BACK_TOTAL_DELAY_MS 2048 /* exponential of 2 */ +#define LP_OWN_BACK_LOOP_DELAY_MS 1 /* exponential of 2 */ +#define LP_OWN_BACK_CLR_OWN_ITERATION 256 /* exponential of 2 */ +#define LP_OWN_BACK_FAILED_RETRY_CNT 5 +#define LP_OWN_BACK_FAILED_LOG_SKIP_MS 2000 +#define LP_OWN_BACK_FAILED_RESET_CNT 5 +#define LP_OWN_BACK_FAILED_DBGCR_POLL_ROUND 5 +#define LP_DBGCR_POLL_ROUND 1 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef struct _PM_PROFILE_SETUP_INFO_T { + /* Profile setup */ + u8 ucBmpDeliveryAC; /* 0: AC_BE, 1: AC_BK, 2: AC_VI, 3: AC_VO */ + u8 ucBmpTriggerAC; /* 0: AC_BE, 1: AC_BK, 2: AC_VI, 3: AC_VO */ + + u8 ucUapsdSp; /* Number of triggered packets in UAPSD */ +} PM_PROFILE_SETUP_INFO_T, *P_PM_PROFILE_SETUP_INFO_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#if !CFG_ENABLE_FULL_PM +#define ACQUIRE_POWER_CONTROL_FROM_PM(_prAdapter) +#define RECLAIM_POWER_CONTROL_TO_PM(_prAdapter, _fgEnableGINT_in_IST) +#else +#define ACQUIRE_POWER_CONTROL_FROM_PM(_prAdapter) \ + { \ + nicpmSetDriverOwn(_prAdapter); \ + } + +#define RECLAIM_POWER_CONTROL_TO_PM(_prAdapter, _fgEnableGINT_in_IST) \ + { \ + nicpmSetFWOwn(_prAdapter, _fgEnableGINT_in_IST); \ + } +#endif + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/queue.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/queue.h new file mode 100644 index 00000000000000..dc8800265175dd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/queue.h @@ -0,0 +1,194 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file queue.h + * \brief Definition for singly queue operations. + * + * In this file we define the singly queue data structure and its + * queue operation MACROs. + */ + +#ifndef _QUEUE_H +#define _QUEUE_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "gl_typedef.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* Singly Queue Structures - Entry Part */ +typedef struct _QUE_ENTRY_T { + struct _QUE_ENTRY_T *prNext; + struct _QUE_ENTRY_T *prPrev; /* For Rx buffer reordering used only */ +} QUE_ENTRY_T, *P_QUE_ENTRY_T; + +/* Singly Queue Structures - Queue Part */ +typedef struct _QUE_T { + P_QUE_ENTRY_T prHead; + P_QUE_ENTRY_T prTail; + u32 u4NumElem; +} QUE_T, *P_QUE_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define MAXNUM_TDLS_PEER 4 + +#define QUEUE_INITIALIZE(prQueue) \ + { \ + (prQueue)->prHead = (P_QUE_ENTRY_T)NULL; \ + (prQueue)->prTail = (P_QUE_ENTRY_T)NULL; \ + (prQueue)->u4NumElem = 0; \ + } + +#define QUEUE_IS_EMPTY(prQueue) \ + (((P_QUE_T)(prQueue))->prHead == (P_QUE_ENTRY_T)NULL) + +#define QUEUE_IS_NOT_EMPTY(prQueue) ((prQueue)->u4NumElem > 0) + +#define QUEUE_GET_HEAD(prQueue) ((prQueue)->prHead) + +#define QUEUE_GET_TAIL(prQueue) ((prQueue)->prTail) + +#define QUEUE_GET_SIZE(prQueue) (((prQueue)->u4NumElem) + +#define QUEUE_GET_NEXT_ENTRY(prQueueEntry) ((prQueueEntry)->prNext) + +#define QUEUE_INSERT_HEAD(prQueue, prQueueEntry) \ + { \ + ASSERT(prQueue); \ + ASSERT(prQueueEntry); \ + (prQueueEntry)->prNext = (prQueue)->prHead; \ + (prQueue)->prHead = (prQueueEntry); \ + if ((prQueue)->prTail == (P_QUE_ENTRY_T)NULL) { \ + (prQueue)->prTail = (prQueueEntry); \ + } \ + ((prQueue)->u4NumElem)++; \ + } + +#define QUEUE_INSERT_TAIL(prQueue, prQueueEntry) \ + { \ + ASSERT(prQueue); \ + ASSERT(prQueueEntry); \ + (prQueueEntry)->prNext = (P_QUE_ENTRY_T)NULL; \ + if ((prQueue)->prTail) { \ + ((prQueue)->prTail)->prNext = (prQueueEntry); \ + } else { \ + (prQueue)->prHead = (prQueueEntry); \ + } \ + (prQueue)->prTail = (prQueueEntry); \ + ((prQueue)->u4NumElem)++; \ + } + +/* NOTE: We assume the queue entry located at the beginning of "prQueueEntry + * Type", so that we can cast the queue entry to other data type without doubts. + * And this macro also decrease the total entry count at the same time. + */ +#define QUEUE_REMOVE_HEAD(prQueue, prQueueEntry, _P_TYPE) \ + { \ + ASSERT(prQueue); \ + prQueueEntry = (_P_TYPE)((prQueue)->prHead); \ + if (prQueueEntry) { \ + (prQueue)->prHead = \ + ((P_QUE_ENTRY_T)(prQueueEntry))->prNext; \ + if ((prQueue)->prHead == (P_QUE_ENTRY_T)NULL) { \ + (prQueue)->prTail = (P_QUE_ENTRY_T)NULL; \ + } \ + ((P_QUE_ENTRY_T)(prQueueEntry))->prNext = \ + (P_QUE_ENTRY_T)NULL; \ + ((prQueue)->u4NumElem)--; \ + } \ + } + +#define QUEUE_MOVE_ALL(prDestQueue, prSrcQueue) \ + { \ + ASSERT(prDestQueue); \ + ASSERT(prSrcQueue); \ + *(P_QUE_T)prDestQueue = *(P_QUE_T)prSrcQueue; \ + QUEUE_INITIALIZE(prSrcQueue); \ + } + +#define QUEUE_CONCATENATE_QUEUES(prDestQueue, prSrcQueue) \ + { \ + ASSERT(prDestQueue); \ + ASSERT(prSrcQueue); \ + if ((prSrcQueue)->u4NumElem > 0) { \ + if ((prDestQueue)->prTail) { \ + ((prDestQueue)->prTail)->prNext = \ + (prSrcQueue)->prHead; \ + } else { \ + (prDestQueue)->prHead = (prSrcQueue)->prHead; \ + } \ + (prDestQueue)->prTail = (prSrcQueue)->prTail; \ + ((prDestQueue)->u4NumElem) += \ + ((prSrcQueue)->u4NumElem); \ + QUEUE_INITIALIZE(prSrcQueue); \ + } \ + } + +#define QUEUE_CONCATENATE_QUEUES_HEAD(prDestQueue, prSrcQueue) \ + { \ + ASSERT(prDestQueue); \ + ASSERT(prSrcQueue); \ + if ((prSrcQueue)->u4NumElem > 0) { \ + ((prSrcQueue)->prTail)->prNext = \ + (prDestQueue)->prHead; \ + (prDestQueue)->prHead = (prSrcQueue)->prHead; \ + ((prDestQueue)->u4NumElem) += \ + ((prSrcQueue)->u4NumElem); \ + if ((prDestQueue)->prTail == NULL) { \ + (prDestQueue)->prTail = (prSrcQueue)->prTail; \ + } \ + QUEUE_INITIALIZE(prSrcQueue); \ + } \ + } + +/******************************************************************************* + * E X T E R N A L D A T A + ******************************************************************************* + */ + +extern u8 g_arTdlsLink[MAXNUM_TDLS_PEER]; + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/rftest.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/rftest.h new file mode 100644 index 00000000000000..abc9905ca9fd56 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/rftest.h @@ -0,0 +1,388 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "rftest.h" + * \brief definitions for RF Productino test + * + */ + +#ifndef _RFTEST_H +#define _RFTEST_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* Table Version */ +#define RF_AUTO_TEST_FUNCTION_TABLE_VERSION 0x01000001 + +/* Power */ +#define RF_AT_PARAM_POWER_MASK BITS(0, 7) +#define RF_AT_PARAM_POWER_MAX RF_AT_PARAM_POWER_MASK + +/* Rate */ +#define RF_AT_PARAM_RATE_MCS_MASK BIT(31) +#define RF_AT_PARAM_RATE_MASK BITS(0, 7) +#define RF_AT_PARAM_RATE_CCK_MAX 3 +#define RF_AT_PARAM_RATE_1M 0 +#define RF_AT_PARAM_RATE_2M 1 +#define RF_AT_PARAM_RATE_5_5M 2 +#define RF_AT_PARAM_RATE_11M 3 +#define RF_AT_PARAM_RATE_6M 4 +#define RF_AT_PARAM_RATE_9M 5 +#define RF_AT_PARAM_RATE_12M 6 +#define RF_AT_PARAM_RATE_18M 7 +#define RF_AT_PARAM_RATE_24M 8 +#define RF_AT_PARAM_RATE_36M 9 +#define RF_AT_PARAM_RATE_48M 10 +#define RF_AT_PARAM_RATE_54M 11 + +/* Antenna */ +#define RF_AT_PARAM_ANTENNA_ID_MASK BITS(0, 7) +#define RF_AT_PARAM_ANTENNA_ID_MAX 1 + +/* Packet Length */ +#define RF_AT_PARAM_TX_80211HDR_BYTE_MAX (32) +#define RF_AT_PARAM_TX_80211PAYLOAD_BYTE_MAX (2048) + +#define RF_AT_PARAM_TX_PKTLEN_BYTE_DEFAULT 1024 +#define RF_AT_PARAM_TX_PKTLEN_BYTE_MAX \ + ((u16)(RF_AT_PARAM_TX_80211HDR_BYTE_MAX + \ + RF_AT_PARAM_TX_80211PAYLOAD_BYTE_MAX)) + +/* Packet Count */ +#define RF_AT_PARAM_TX_PKTCNT_DEFAULT 1000 +#define RF_AT_PARAM_TX_PKTCNT_UNLIMITED 0 + +/* Packet Interval */ +#define RF_AT_PARAM_TX_PKT_INTERVAL_US_DEFAULT 50 + +/* ALC */ +#define RF_AT_PARAM_ALC_DISABLE 0 +#define RF_AT_PARAM_ALC_ENABLE 1 + +/* TXOP */ +#define RF_AT_PARAM_TXOP_DEFAULT 0 +#define RF_AT_PARAM_TXOPQUE_QMASK BITS(16, 31) +#define RF_AT_PARAM_TXOPQUE_TMASK BITS(0, 15) +#define RF_AT_PARAM_TXOPQUE_AC0 (0 << 16) +#define RF_AT_PARAM_TXOPQUE_AC1 (1 << 16) +#define RF_AT_PARAM_TXOPQUE_AC2 (2 << 16) +#define RF_AT_PARAM_TXOPQUE_AC3 (3 << 16) +#define RF_AT_PARAM_TXOPQUE_AC4 (4 << 16) +#define RF_AT_PARAM_TXOPQUE_QOFFSET 16 + +/* Retry Limit */ +#define RF_AT_PARAM_TX_RETRY_DEFAULT 0 +#define RF_AT_PARAM_TX_RETRY_MAX 6 + +/* QoS Queue */ +#define RF_AT_PARAM_QOSQUE_AC0 0 +#define RF_AT_PARAM_QOSQUE_AC1 1 +#define RF_AT_PARAM_QOSQUE_AC2 2 +#define RF_AT_PARAM_QOSQUE_AC3 3 +#define RF_AT_PARAM_QOSQUE_AC4 4 +#define RF_AT_PARAM_QOSQUE_DEFAULT RF_AT_PARAM_QOSQUE_AC0 + +/* Bandwidth */ +#define RF_AT_PARAM_BANDWIDTH_20MHZ 0 +#define RF_AT_PARAM_BANDWIDTH_40MHZ 1 +#define RF_AT_PARAM_BANDWIDTH_U20_IN_40MHZ 2 +#define RF_AT_PARAM_BANDWIDTH_D20_IN_40MHZ 3 +#define RF_AT_PARAM_BANDWIDTH_DEFAULT RF_AT_PARAM_BANDWIDTH_20MHZ + +/* GI (Guard Interval) */ +#define RF_AT_PARAM_GI_800NS 0 +#define RF_AT_PARAM_GI_400NS 1 +#define RF_AT_PARAM_GI_DEFAULT RF_AT_PARAM_GI_800NS + +/* STBC */ +#define RF_AT_PARAM_STBC_DISABLE 0 +#define RF_AT_PARAM_STBC_ENABLE 1 + +/* RIFS */ +#define RF_AT_PARAM_RIFS_DISABLE 0 +#define RF_AT_PARAM_RIFS_ENABLE 1 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* Function ID List */ +typedef enum _ENUM_RF_AT_FUNCID_T { + RF_AT_FUNCID_VERSION = 0, + RF_AT_FUNCID_COMMAND, + RF_AT_FUNCID_POWER, + RF_AT_FUNCID_RATE, + RF_AT_FUNCID_PREAMBLE, + RF_AT_FUNCID_ANTENNA, + RF_AT_FUNCID_PKTLEN, + RF_AT_FUNCID_PKTCNT, + RF_AT_FUNCID_PKTINTERVAL, + RF_AT_FUNCID_TEMP_COMPEN, + RF_AT_FUNCID_TXOPLIMIT, + RF_AT_FUNCID_ACKPOLICY, + RF_AT_FUNCID_PKTCONTENT, + RF_AT_FUNCID_RETRYLIMIT, + RF_AT_FUNCID_QUEUE, + RF_AT_FUNCID_BANDWIDTH, + RF_AT_FUNCID_GI, + RF_AT_FUNCID_STBC, + RF_AT_FUNCID_CHNL_FREQ, + RF_AT_FUNCID_RIFS, + RF_AT_FUNCID_TRSW_TYPE, + RF_AT_FUNCID_RF_SX_SHUTDOWN, + RF_AT_FUNCID_PLL_SHUTDOWN, + RF_AT_FUNCID_SLOW_CLK_MODE, + RF_AT_FUNCID_ADC_CLK_MODE, + RF_AT_FUNCID_MEASURE_MODE, + RF_AT_FUNCID_VOLT_COMPEN, + RF_AT_FUNCID_DPD_TX_GAIN, + RF_AT_FUNCID_DPD_MODE, + RF_AT_FUNCID_TSSI_MODE, + RF_AT_FUNCID_TX_GAIN_CODE, + RF_AT_FUNCID_TX_PWR_MODE, + + /* Query command */ + RF_AT_FUNCID_TXED_COUNT = 32, + RF_AT_FUNCID_TXOK_COUNT, + RF_AT_FUNCID_RXOK_COUNT, + RF_AT_FUNCID_RXERROR_COUNT, + RF_AT_FUNCID_RESULT_INFO, + RF_AT_FUNCID_TRX_IQ_RESULT, + RF_AT_FUNCID_TSSI_RESULT, + RF_AT_FUNCID_DPD_RESULT, + RF_AT_FUNCID_RXV_DUMP, + RF_AT_FUNCID_RX_PHY_STATIS, + RF_AT_FUNCID_MEASURE_RESULT, + RF_AT_FUNCID_TEMP_SENSOR, + RF_AT_FUNCID_VOLT_SENSOR, + RF_AT_FUNCID_READ_EFUSE, + RF_AT_FUNCID_RX_RSSI, + RF_AT_FUNCID_FW_INFO, + RF_AT_FUNCID_DRV_INFO, + RF_AT_FUNCID_PWR_DETECTOR, + RF_AT_FUNCID_WBRSSI_IBSSI, + + /* Set command */ + RF_AT_FUNCID_SET_DPD_RESULT = 64, + RF_AT_FUNCID_SET_CW_MODE, + RF_AT_FUNCID_SET_JAPAN_CH14_FILTER, + RF_AT_FUNCID_WRITE_EFUSE, + RF_AT_FUNCID_SET_MAC_ADDRESS, + RF_AT_FUNCID_SET_TA, + RF_AT_FUNCID_SET_RX_MATCH_RULE, + + /* 80211AC & Jmode */ + RF_AT_FUNCID_SET_CBW = 71, + RF_AT_FUNCID_SET_DBW, + RF_AT_FUNCID_SET_PRIMARY_CH, + RF_AT_FUNCID_SET_ENCODE_MODE, + RF_AT_FUNCID_SET_J_MODE, + + /* ICAP command */ + RF_AT_FUNCID_SET_ICAP_CONTENT = 80, + RF_AT_FUNCID_SET_ICAP_MODE, + RF_AT_FUNCID_SET_ICAP_STARTCAP, + RF_AT_FUNCID_SET_ICAP_SIZE = 83, + RF_AT_FUNCID_SET_ICAP_TRIGGER_OFFSET, + RF_AT_FUNCID_QUERY_ICAP_DUMP_FILE = 85, + +#if CFG_SUPPORT_QA_TOOL + /* 2G 5G Band */ + RF_AT_FUNCID_SET_BAND = 90, + + /* Reset Counter */ + RF_AT_FUNCID_RESETTXRXCOUNTER = 91, + + /* FAGC RSSI Path */ + RF_AT_FUNCID_FAGC_RSSI_PATH = 92, + + /* Set RX Filter Packet Length */ + RF_AT_FUNCID_RX_FILTER_PKT_LEN = 93, + + /* Tone */ + RF_AT_FUNCID_SET_TONE_RF_GAIN = 96, + RF_AT_FUNCID_SET_TONE_DIGITAL_GAIN = 97, + RF_AT_FUNCID_SET_TONE_TYPE = 98, + RF_AT_FUNCID_SET_TONE_DC_OFFSET = 99, + RF_AT_FUNCID_SET_TONE_BW = 100, + + /* MT6632 Add */ + RF_AT_FUNCID_SET_MAC_HEADER = 101, + RF_AT_FUNCID_SET_SEQ_CTRL = 102, + RF_AT_FUNCID_SET_PAYLOAD = 103, + RF_AT_FUNCID_SET_DBDC_BAND_IDX = 104, + RF_AT_FUNCID_SET_BYPASS_CAL_STEP = 105, + + /* Set RX Path */ + RF_AT_FUNCID_SET_RX_PATH = 106, + + /* Set Frequency Offset */ + RF_AT_FUNCID_SET_FRWQ_OFFSET = 107, + + /* Get Frequency Offset */ + RF_AT_FUNCID_GET_FREQ_OFFSET = 108, + + /* Set RXV Debug Index */ + RF_AT_FUNCID_SET_RXV_INDEX = 109, + + /* Set Test Mode DBDC Enable */ + RF_AT_FUNCID_SET_DBDC_ENABLE = 110, + + /* Get Test Mode DBDC Enable */ + RF_AT_FUNCID_GET_DBDC_ENABLE = 111, + + /* Set ICAP Ring Capture */ + RF_AT_FUNCID_SET_ICAP_RING = 112, + + /* Set TX Path */ + RF_AT_FUNCID_SET_TX_PATH = 113, + + /* Set Nss */ + RF_AT_FUNCID_SET_NSS = 114, + + /* Set TX Antenna Mask */ + RF_AT_FUNCID_SET_ANTMASK = 115, + + /* TMR set command */ + RF_AT_FUNCID_SET_TMR_ROLE = 116, + RF_AT_FUNCID_SET_TMR_MODULE = 117, + RF_AT_FUNCID_SET_TMR_DBM = 118, + RF_AT_FUNCID_SET_TMR_ITER = 119, + + /* Set ADC For IRR Feature */ + RF_AT_FUNCID_SET_ADC = 120, + + /* Set RX Gain For IRR Feature */ + RF_AT_FUNCID_SET_RX_GAIN = 121, + + /* Set TTG For IRR Feature */ + RF_AT_FUNCID_SET_TTG = 122, + + /* Set TTG ON/OFF For IRR Feature */ + RF_AT_FUNCID_TTG_ON_OFF = 123, + + /* Set TSSI for QA Tool Setting */ + RF_AT_FUNCID_SET_TSSI = 124, + + /* Set Recal Cal Step */ + RF_AT_FUNCID_SET_RECAL_CAL_STEP = 125, + + /* Set iBF/eBF enable */ + RF_AT_FUNCID_SET_IBF_ENABLE = 126, + RF_AT_FUNCID_SET_EBF_ENABLE = 127, + + /* Set MPS Setting */ + RF_AT_FUNCID_SET_MPS_SIZE = 128, + RF_AT_FUNCID_SET_MPS_SEQ_DATA = 129, + RF_AT_FUNCID_SET_MPS_PAYLOAD_LEN = 130, + RF_AT_FUNCID_SET_MPS_PKT_CNT = 131, + RF_AT_FUNCID_SET_MPS_PWR_GAIN = 132, + RF_AT_FUNCID_SET_MPS_NSS = 133, + RF_AT_FUNCID_SET_MPS_PACKAGE_BW = 134 +#endif +} ENUM_RF_AT_FUNCID_T; + +/* Command */ +typedef enum _ENUM_RF_AT_COMMAND_T { + RF_AT_COMMAND_STOPTEST = 0, + RF_AT_COMMAND_STARTTX, + RF_AT_COMMAND_STARTRX, + RF_AT_COMMAND_RESET, + RF_AT_COMMAND_OUTPUT_POWER, /* Payload */ + RF_AT_COMMAND_LO_LEAKAGE, /* Local freq is renamed to Local leakage */ + RF_AT_COMMAND_CARRIER_SUPPR, /* OFDM (LTF/STF), CCK (PI,PI/2) */ + RF_AT_COMMAND_TRX_IQ_CAL, + RF_AT_COMMAND_TSSI_CAL, + RF_AT_COMMAND_DPD_CAL, + RF_AT_COMMAND_CW, + RF_AT_COMMAND_ICAP, + RF_AT_COMMAND_RDD, + RF_AT_COMMAND_CH_SWITCH_FOR_ICAP, + RF_AT_COMMAND_RESET_DUMP_NAME, + RF_AT_COMMAND_SINGLE_TONE, + RF_AT_COMMAND_RDD_OFF, + RF_AT_COMMAND_NUM +} ENUM_RF_AT_COMMAND_T; + +/* Preamble */ +typedef enum _ENUM_RF_AT_PREAMBLE_T { + RF_AT_PREAMBLE_NORMAL = 0, + RF_AT_PREAMBLE_CCK_SHORT, + RF_AT_PREAMBLE_11N_MM, + RF_AT_PREAMBLE_11N_GF, + RF_AT_PREAMBLE_11AC, + RF_AT_PREAMBLE_NUM +} ENUM_RF_AT_PREAMBLE_T; + +/* Ack Policy */ +typedef enum _ENUM_RF_AT_ACK_POLICY_T { + RF_AT_ACK_POLICY_NORMAL = 0, + RF_AT_ACK_POLICY_NOACK, + RF_AT_ACK_POLICY_NOEXPLICTACK, + RF_AT_ACK_POLICY_BLOCKACK, + RF_AT_ACK_POLICY_NUM +} ENUM_RF_AT_ACK_POLICY_T; + +typedef enum _ENUM_RF_AUTOTEST_STATE_T { + RF_AUTOTEST_STATE_STANDBY = 0, + RF_AUTOTEST_STATE_TX, + RF_AUTOTEST_STATE_RX, + RF_AUTOTEST_STATE_RESET, + RF_AUTOTEST_STATE_OUTPUT_POWER, + RF_AUTOTEST_STATE_LOCA_FREQUENCY, + RF_AUTOTEST_STATE_CARRIER_SUPRRESION, + RF_AUTOTEST_STATE_NUM +} ENUM_RF_AUTOTEST_STATE_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +WLAN_STATUS rftestSetATInfo(IN P_ADAPTER_T prAdapter, + u32 u4FuncIndex, + u32 u4FuncData); + +WLAN_STATUS +rftestQueryATInfo(IN P_ADAPTER_T prAdapter, + u32 u4FuncIndex, + u32 u4FuncData, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen); + +WLAN_STATUS rftestSetFrequency(IN P_ADAPTER_T prAdapter, + IN u32 u4FreqInKHz, + IN u32 *pu4SetInfoLen); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/typedef.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/typedef.h new file mode 100644 index 00000000000000..f8bcff412367da --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/typedef.h @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file typedef.h + * \brief Declaration of data type and return values of internal protocol + * stack. + * + * In this file we declare the data type and return values which will be + * exported to the GLUE Layer. + */ + +#ifndef _TYPEDEF_H +#define _TYPEDEF_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* ieee80211.h of linux has duplicated definitions */ +#if defined(WLAN_STATUS_SUCCESS) +#undef WLAN_STATUS_SUCCESS +#endif + +#define WLAN_STATUS_SUCCESS ((WLAN_STATUS)0x00000000L) +#define WLAN_STATUS_PENDING ((WLAN_STATUS)0x00000103L) +#define WLAN_STATUS_NOT_ACCEPTED ((WLAN_STATUS)0x00010003L) + +#define WLAN_STATUS_MEDIA_CONNECT ((WLAN_STATUS)0x4001000BL) +#define WLAN_STATUS_MEDIA_DISCONNECT ((WLAN_STATUS)0x4001000CL) +#define WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY ((WLAN_STATUS)0x4001000DL) +#define WLAN_STATUS_MEDIA_SPECIFIC_INDICATION ((WLAN_STATUS)0x40010012L) + +#define WLAN_STATUS_SCAN_COMPLETE ((WLAN_STATUS)0x60010001L) +#define WLAN_STATUS_MSDU_OK ((WLAN_STATUS)0x60010002L) + +/* TODO(Kevin): double check if 0x60010001 & 0x60010002 is proprietary */ +#define WLAN_STATUS_ROAM_OUT_FIND_BEST ((WLAN_STATUS)0x60010101L) +#define WLAN_STATUS_ROAM_DISCOVERY ((WLAN_STATUS)0x60010102L) + +#define WLAN_STATUS_FAILURE ((WLAN_STATUS)0xC0000001L) +#define WLAN_STATUS_RESOURCES ((WLAN_STATUS)0xC000009AL) +#define WLAN_STATUS_NOT_SUPPORTED ((WLAN_STATUS)0xC00000BBL) + +#define WLAN_STATUS_MULTICAST_FULL ((WLAN_STATUS)0xC0010009L) +#define WLAN_STATUS_INVALID_PACKET ((WLAN_STATUS)0xC001000FL) +#define WLAN_STATUS_ADAPTER_NOT_READY ((WLAN_STATUS)0xC0010011L) +#define WLAN_STATUS_NOT_INDICATING ((WLAN_STATUS)0xC0010013L) +#define WLAN_STATUS_INVALID_LENGTH ((WLAN_STATUS)0xC0010014L) +#define WLAN_STATUS_INVALID_DATA ((WLAN_STATUS)0xC0010015L) +#define WLAN_STATUS_BUFFER_TOO_SHORT ((WLAN_STATUS)0xC0010016L) +#define WLAN_STATUS_BWCS_UPDATE ((WLAN_STATUS)0xC0010017L) + +#define WLAN_STATUS_JOIN_TIMEOUT ((WLAN_STATUS)0xc0010018L) +#define WLAN_STATUS_BEACON_TIMEOUT ((WLAN_STATUS)0xc0010019L) +#define WLAN_STATUS_JOIN_ABORT ((WLAN_STATUS)0xc0010020L) +#define WLAN_STATUS_ASSOC_RESP ((WLAN_STATUS)0xc0010021L) + +/* NIC status flags */ +#define ADAPTER_FLAG_HW_ERR 0x00400000 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* Type definition for GLUE_INFO structure */ +typedef struct _GLUE_INFO_T GLUE_INFO_T, *P_GLUE_INFO_T; + +/* Type definition for WLAN STATUS */ +typedef u32 WLAN_STATUS, *P_WLAN_STATUS; + +/* Type definition for ADAPTER structure */ +typedef struct _ADAPTER_T ADAPTER_T, *P_ADAPTER_T; + +/* Type definition for MESSAGE HEADER structure */ +typedef struct _MSG_HDR_T MSG_HDR_T, *P_MSG_HDR_T; + +/* Type definition for Pointer to OS Native Packet */ +typedef void *P_NATIVE_PACKET; + +/* Type definition for WLAN configuration */ +typedef struct _WLAN_CFG_T WLAN_CFG_T, *P_WLAN_CFG_T; + +typedef struct _WLAN_CFG_REC_T WLAN_CFG_REC_T, *P_WLAN_CFG_REC_T; + +/* Type definition for WLAN configuration entry */ +typedef struct _WLAN_CFG_ENTRY_T WLAN_CFG_ENTRY_T, *P_WLAN_CFG_ENTRY_T; + +/* Type definition for WLAN configuration callback */ +typedef WLAN_STATUS (*WLAN_CFG_SET_CB)(P_ADAPTER_T prAdapter, + u8 *pucKey, + u8 *pucValue, + void *pPrivate, + u32 u4Flags); + +/* Type definition for STA_RECORD_T structure to handle the connectivity and + * packet reception for a particular STA. + */ +typedef struct _STA_RECORD_T STA_RECORD_T, *P_STA_RECORD_T, **PP_STA_RECORD_T; + +/* CMD_INFO_T is used by Glue Layer to send a cluster of Command(OID) + * information to the TX Path to reduce the parameters of a function call. + */ +typedef struct _CMD_INFO_T CMD_INFO_T, *P_CMD_INFO_T; + +/* Following typedef should be removed later, because Glue Layer should not + * be aware of following data type. + */ +typedef struct _SW_RFB_T SW_RFB_T, *P_SW_RFB_T, **PP_SW_RFB_T; + +typedef struct _MSDU_INFO_T MSDU_INFO_T, *P_MSDU_INFO_T; + +typedef struct _REG_ENTRY_T REG_ENTRY_T, *P_REG_ENTRY_T; + +/* IST handler definition */ +typedef void (*IST_EVENT_FUNCTION)(P_ADAPTER_T); + +/* Type definition for function pointer of timer handler */ +typedef void (*PFN_TIMER_CALLBACK)(IN P_GLUE_INFO_T); + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/wlan_lib.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/wlan_lib.h new file mode 100644 index 00000000000000..a7eac0904dc471 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/wlan_lib.h @@ -0,0 +1,1507 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "wlan_lib.h" + * \brief The declaration of the functions of the wlanAdpater objects + * + * Detail description. + */ + +#ifndef _WLAN_LIB_H +#define _WLAN_LIB_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "CFG_Wifi_File.h" +#include "rlm_domain.h" +#include "nic_init_cmd_event.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* These values must sync from Wifi HAL + * /hardware/libhardware_legacy/include/hardware_legacy/wifi_hal.h + */ +/* Basic infrastructure mode */ +//#define WIFI_FEATURE_INFRA (0x0001) +/* Support for 5 GHz Band */ +#define WIFI_FEATURE_INFRA_5G (0x0002) +/* Support for GAS/ANQP */ +//#define WIFI_FEATURE_HOTSPOT (0x0004) +/* Wifi-Direct */ +#define WIFI_FEATURE_P2P (0x0008) +/* Soft AP */ +#define WIFI_FEATURE_SOFT_AP (0x0010) +/* Tunnel directed link setup */ +#define WIFI_FEATURE_TDLS (0x1000) + +/* note: WIFI_FEATURE_GSCAN be enabled just for ACTS test item: scanner */ +#define WIFI_HAL_FEATURE_SET ((WIFI_FEATURE_P2P) | \ + (WIFI_FEATURE_SOFT_AP)) + +#define MAX_NUM_GROUP_ADDR 32 /* max number of group addresses */ +#define AUTO_RATE_NUM 8 +#define AR_RATE_TABLE_ENTRY_MAX 25 +#define AR_RATE_ENTRY_INDEX_NULL 0x80 + +#define TX_CS_TCP_UDP_GEN BIT(1) +#define TX_CS_IP_GEN BIT(0) + +#define CSUM_OFFLOAD_EN_TX_TCP BIT(0) +#define CSUM_OFFLOAD_EN_TX_UDP BIT(1) +#define CSUM_OFFLOAD_EN_TX_IP BIT(2) +#define CSUM_OFFLOAD_EN_RX_TCP BIT(3) +#define CSUM_OFFLOAD_EN_RX_UDP BIT(4) +#define CSUM_OFFLOAD_EN_RX_IPv4 BIT(5) +#define CSUM_OFFLOAD_EN_RX_IPv6 BIT(6) +#define CSUM_OFFLOAD_EN_TX_MASK BITS(0, 2) +#define CSUM_OFFLOAD_EN_ALL BITS(0, 6) + +/* TCP, UDP, IP Checksum */ +#define RX_CS_TYPE_UDP BIT(7) +#define RX_CS_TYPE_TCP BIT(6) +#define RX_CS_TYPE_IPv6 BIT(5) +#define RX_CS_TYPE_IPv4 BIT(4) + +#define RX_CS_STATUS_UDP BIT(3) +#define RX_CS_STATUS_TCP BIT(2) +#define RX_CS_STATUS_IP BIT(0) + +#define CSUM_NOT_SUPPORTED 0x0 + +#define TXPWR_USE_PDSLOPE 0 + +/* NVRAM error code definitions */ +#define NVRAM_ERROR_VERSION_MISMATCH BIT(1) +#define NVRAM_ERROR_INVALID_TXPWR BIT(2) +#define NVRAM_ERROR_INVALID_DPD BIT(3) +#define NVRAM_ERROR_INVALID_MAC_ADDR BIT(4) +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY +#define NVRAM_POWER_LIMIT_TABLE_INVALID BIT(5) +#endif + +#define NUM_TC_RESOURCE_TO_STATISTICS 4 + +#define WLAN_CFG_ARGV_MAX 23 +#define WLAN_CFG_ARGV_MAX_LONG 22 /* for WOW, 2+20 */ +#define WLAN_CFG_ENTRY_NUM_MAX 200 /* 128 */ +#define WLAN_CFG_KEY_LEN_MAX 32 /* include \x00 EOL */ +#define WLAN_CFG_VALUE_LEN_MAX 32 /* include \x00 EOL */ +#define WLAN_CFG_FLAG_SKIP_CB BIT(0) +#define WLAN_CFG_FILE_BUF_SIZE 2048 + +#define WLAN_CFG_REC_ENTRY_NUM_MAX 200 +#define WLAN_CFG_REC_FLAG_BIT BIT(0) + +#define WLAN_CFG_SET_CHIP_LEN_MAX 10 +#define WLAN_CFG_SET_DEBUG_LEVEL_LEN_MAX 10 +#define WLAN_CFG_SET_SW_CTRL_LEN_MAX 10 + +#define WLAN_OID_TIMEOUT_THRESHOLD 2000 /* OID timeout (in ms) */ +#define WLAN_OID_TIMEOUT_THRESHOLD_MAX 10000 /* OID max timeout (in ms) */ +#define WLAN_OID_TIMEOUT_THRESHOLD_IN_RESETTING \ + 300 /* OID timeout during chip-resetting (in ms) */ + +#define WLAN_OID_NO_ACK_THRESHOLD 3 + +#define WLAN_THREAD_TASK_PRIORITY \ + 0 /* If not setting the priority, 0 is the default */ +#define WLAN_THREAD_TASK_NICE \ + (-10) /* If not setting the nice, -10 is the default */ + +#define WLAN_TX_STATS_LOG_TIMEOUT 30000 +#define WLAN_TX_STATS_LOG_DURATION 1500 + +/* Define for wifi path usage */ +#define WLAN_FLAG_2G4_WF0 BIT(0) /*1: support, 0: NOT support */ +#define WLAN_FLAG_5G_WF0 BIT(1) /*1: support, 0: NOT support */ +#define WLAN_FLAG_2G4_WF1 BIT(2) /*1: support, 0: NOT support */ +#define WLAN_FLAG_5G_WF1 BIT(3) /*1: support, 0: NOT support */ +#define WLAN_FLAG_2G4_COANT_SUPPORT BIT(4) /*1: support, 0: NOT support */ +#define WLAN_FLAG_2G4_COANT_PATH BIT(5) /*1: WF1, 0:WF0 */ +#define WLAN_FLAG_5G_COANT_SUPPORT BIT(6) /*1: support, 0: NOT support */ +#define WLAN_FLAG_5G_COANT_PATH BIT(7) /*1: WF1, 0:WF0 */ + +#if CFG_SUPPORT_EASY_DEBUG + +#define MAX_CMD_ITEM_MAX 4 /* Max item per cmd. */ +#define MAX_CMD_NAME_MAX_LENGTH 32 /* Max name string length */ +#define MAX_CMD_VALUE_MAX_LENGTH 32 /* Max value string length */ +#define MAX_CMD_TYPE_LENGTH 1 +#define MAX_CMD_STRING_LENGTH 1 +#define MAX_CMD_VALUE_LENGTH 1 +#define MAX_CMD_RESERVE_LENGTH 1 + +#define CMD_FORMAT_V1_LENGTH \ + (MAX_CMD_NAME_MAX_LENGTH + MAX_CMD_VALUE_MAX_LENGTH + \ + MAX_CMD_TYPE_LENGTH + MAX_CMD_STRING_LENGTH + MAX_CMD_VALUE_LENGTH + \ + MAX_CMD_RESERVE_LENGTH) + +#define MAX_CMD_BUFFER_LENGTH (CMD_FORMAT_V1_LENGTH * \ + MAX_CMD_ITEM_MAX) + +#define ED_STRING_SITE 0 +#define ED_VALUE_SITE 1 + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +#define ACS_AP_RSSI_LEVEL_HIGH -50 +#define ACS_AP_RSSI_LEVEL_LOW -80 +#define ACS_DIRTINESS_LEVEL_HIGH 52 +#define ACS_DIRTINESS_LEVEL_MID 40 +#define ACS_DIRTINESS_LEVEL_LOW 32 +#endif + +#if CFG_WOW_SUPPORT +#define INVALID_WOW_WAKE_UP_REASON 255 +#endif + +#if CFG_SUPPORT_ADVANCE_CONTROL +#define KEEP_FULL_PWR_TRAFFIC_REPORT_BIT BIT(0) +#define KEEP_FULL_PWR_NOISE_HISTOGRAM_BIT BIT(1) +#define BLOCK_KEEP_FULL_PWR BIT(31) +#endif + +typedef enum _CMD_VER_T { + CMD_VER_1, /* Type[2]+String[32]+Value[32] */ + CMD_VER_2 /* for furtur define. */ +} CMD_VER_T, +*P_CMD_VER_T; + +typedef enum _CMD_TYPE_T { + CMD_TYPE_QUERY, + CMD_TYPE_SET +} CMD_TYPE_T, +*P_CMD_TYPE_T; + +#define ITEM_TYPE_DEC 1 +#define ITEM_TYPE_HEX 2 +#define ITEM_TYPE_STR 3 + +typedef enum _CMD_DEFAULT_SETTING_VALUE { + CMD_PNO_ENABLE, + CMD_PNO_SCAN_PERIOD, + CMD_SCN_CHANNEL_PLAN, + CMD_SCN_DWELL_TIME, + CMD_SCN_STOP_SCAN, + CMD_MAX, +} CMD_DEFAULT_SETTING_VALUE; + +typedef enum _CMD_DEFAULT_STR_SETTING_VALUE { + CMD_STR_TEST_STR, + CMD_STR_MAX, +} CMD_DEFAULT_STR_SETTING_VALUE; + +typedef struct _CMD_FORMAT_V1_T { + u8 itemType; + u8 itemStringLength; + u8 itemValueLength; + u8 Reserved; + u8 itemString[MAX_CMD_NAME_MAX_LENGTH]; + u8 itemValue[MAX_CMD_VALUE_MAX_LENGTH]; +} CMD_FORMAT_V1_T, *P_CMD_FORMAT_V1_T; + +typedef struct _CMD_HEADER_T { + CMD_VER_T cmdVersion; + CMD_TYPE_T cmdType; + u8 itemNum; + u16 cmdBufferLen; + u8 buffer[MAX_CMD_BUFFER_LENGTH]; +} CMD_HEADER_T, *P_CMD_HEADER_T; + +typedef struct _CFG_DEFAULT_SETTING_TABLE_T { + u32 itemNum; + const char *String; + u8 itemType; + u32 defaultValue; + u32 minValue; + u32 maxValue; +} CFG_DEFAULT_SETTING_TABLE_T, *P_CFG_DEFAULT_SETTING_TABLE_T; + +typedef struct _CFG_DEFAULT_SETTING_STR_TABLE_T { + u32 itemNum; + const char *String; + u8 itemType; + const char *DefString; + u16 minLen; + u16 maxLen; +} CFG_DEFAULT_SETTING_STR_TABLE_T, *P_CFG_DEFAULT_SETTING_STR_TABLE_T; + +typedef struct _CFG_QUERY_FORMAT_T { + u32 Length; + u32 Value; + u32 Type; + u32 *ptr; +} CFG_QUERY_FORMAT_T, *P_CFG_QUERY_FORMAT_T; + +/*Globol Configure define */ +typedef struct _CFG_SETTING_T { + u8 PnoEnable; + u32 PnoScanPeriod; + u8 ScnChannelPlan; + u16 ScnDwellTime; + u8 ScnStopScan; + u8 TestStr[80]; +} CFG_SETTING_T, *P_CFG_SETTING_T; + +#endif + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef WLAN_STATUS (*PFN_OID_HANDLER_FUNC)(IN P_ADAPTER_T prAdapter, + IN void *pvBuf, + IN u32 u4BufLen, + OUT u32 *pu4OutInfoLen); + +typedef enum _ENUM_CSUM_TYPE_T { + CSUM_TYPE_IPV4, + CSUM_TYPE_IPV6, + CSUM_TYPE_TCP, + CSUM_TYPE_UDP, + CSUM_TYPE_NUM +} ENUM_CSUM_TYPE_T, +*P_ENUM_CSUM_TYPE_T; + +typedef enum _ENUM_CSUM_RESULT_T { + CSUM_RES_NONE, + CSUM_RES_SUCCESS, + CSUM_RES_FAILED, + CSUM_RES_NUM +} ENUM_CSUM_RESULT_T, +*P_ENUM_CSUM_RESULT_T; + +typedef enum _ENUM_PHY_MODE_T { + ENUM_PHY_2G4_CCK, + ENUM_PHY_2G4_OFDM_BPSK, + ENUM_PHY_2G4_OFDM_QPSK, + ENUM_PHY_2G4_OFDM_16QAM, + ENUM_PHY_2G4_OFDM_48M, + ENUM_PHY_2G4_OFDM_54M, + ENUM_PHY_2G4_HT20_BPSK, + ENUM_PHY_2G4_HT20_QPSK, + ENUM_PHY_2G4_HT20_16QAM, + ENUM_PHY_2G4_HT20_MCS5, + ENUM_PHY_2G4_HT20_MCS6, + ENUM_PHY_2G4_HT20_MCS7, + ENUM_PHY_2G4_HT40_BPSK, + ENUM_PHY_2G4_HT40_QPSK, + ENUM_PHY_2G4_HT40_16QAM, + ENUM_PHY_2G4_HT40_MCS5, + ENUM_PHY_2G4_HT40_MCS6, + ENUM_PHY_2G4_HT40_MCS7, + ENUM_PHY_5G_OFDM_BPSK, + ENUM_PHY_5G_OFDM_QPSK, + ENUM_PHY_5G_OFDM_16QAM, + ENUM_PHY_5G_OFDM_48M, + ENUM_PHY_5G_OFDM_54M, + ENUM_PHY_5G_HT20_BPSK, + ENUM_PHY_5G_HT20_QPSK, + ENUM_PHY_5G_HT20_16QAM, + ENUM_PHY_5G_HT20_MCS5, + ENUM_PHY_5G_HT20_MCS6, + ENUM_PHY_5G_HT20_MCS7, + ENUM_PHY_5G_HT40_BPSK, + ENUM_PHY_5G_HT40_QPSK, + ENUM_PHY_5G_HT40_16QAM, + ENUM_PHY_5G_HT40_MCS5, + ENUM_PHY_5G_HT40_MCS6, + ENUM_PHY_5G_HT40_MCS7, + ENUM_PHY_MODE_NUM +} ENUM_PHY_MODE_T, +*P_ENUM_PHY_MODE_T; + +typedef enum _ENUM_POWER_SAVE_POLL_MODE_T { + ENUM_POWER_SAVE_POLL_DISABLE, + ENUM_POWER_SAVE_POLL_LEGACY_NULL, + ENUM_POWER_SAVE_POLL_QOS_NULL, + ENUM_POWER_SAVE_POLL_NUM +} ENUM_POWER_SAVE_POLL_MODE_T, +*P_ENUM_POWER_SAVE_POLL_MODE_T; + +typedef enum _ENUM_AC_TYPE_T { + ENUM_AC_TYPE_AC0, + ENUM_AC_TYPE_AC1, + ENUM_AC_TYPE_AC2, + ENUM_AC_TYPE_AC3, + ENUM_AC_TYPE_AC4, + ENUM_AC_TYPE_AC5, + ENUM_AC_TYPE_AC6, + ENUM_AC_TYPE_BMC, + ENUM_AC_TYPE_NUM +} ENUM_AC_TYPE_T, +*P_ENUM_AC_TYPE_T; + +typedef enum _ENUM_ADV_AC_TYPE_T { + ENUM_ADV_AC_TYPE_RX_NSW, + ENUM_ADV_AC_TYPE_RX_PTA, + ENUM_ADV_AC_TYPE_RX_SP, + ENUM_ADV_AC_TYPE_TX_PTA, + ENUM_ADV_AC_TYPE_TX_RSP, + ENUM_ADV_AC_TYPE_NUM +} ENUM_ADV_AC_TYPE_T, +*P_ENUM_ADV_AC_TYPE_T; + +typedef enum _ENUM_REG_CH_MAP_T { + REG_CH_MAP_COUNTRY_CODE, + REG_CH_MAP_TBL_IDX, + REG_CH_MAP_CUSTOMIZED, + REG_CH_MAP_NUM +} ENUM_REG_CH_MAP_T, +*P_ENUM_REG_CH_MAP_T; + +typedef enum _ENUM_FEATURE_OPTION_T { + FEATURE_DISABLED, + FEATURE_ENABLED, + FEATURE_FORCE_ENABLED +} ENUM_FEATURE_OPTION_T, +*P_ENUM_FEATURE_OPTION_T; + +/* This enum is for later added feature options which use command reserved field + * as option switch */ +typedef enum _ENUM_FEATURE_OPTION_IN_CMD_T { + FEATURE_OPT_CMD_AUTO, + FEATURE_OPT_CMD_DISABLED, + FEATURE_OPT_CMD_ENABLED, + FEATURE_OPT_CMD_FORCE_ENABLED +} ENUM_FEATURE_OPTION_IN_CMD_T, +*P_ENUM_FEATURE_OPTION_IN_CMD_T; + +#define DEBUG_MSG_SIZE_MAX 1200 +enum { + DEBUG_MSG_ID_UNKNOWN = 0x00, + DEBUG_MSG_ID_PRINT = 0x01, + DEBUG_MSG_ID_FWLOG = 0x02, + DEBUG_MSG_ID_END +}; + +enum { + DEBUG_MSG_TYPE_UNKNOWN = 0x00, + DEBUG_MSG_TYPE_MEM8 = 0x01, + DEBUG_MSG_TYPE_MEM32 = 0x02, + DEBUG_MSG_TYPE_ASCII = 0x03, + DEBUG_MSG_TYPE_BINARY = 0x04, + DEBUG_MSG_TYPE_END +}; + +#define CHIP_CONFIG_RESP_SIZE 320 +enum { + CHIP_CONFIG_TYPE_WO_RESPONSE = 0x00, + CHIP_CONFIG_TYPE_MEM8 = 0x01, + CHIP_CONFIG_TYPE_MEM32 = 0x02, + CHIP_CONFIG_TYPE_ASCII = 0x03, + CHIP_CONFIG_TYPE_BINARY = 0x04, + CHIP_CONFIG_TYPE_DRV_PASSTHROUGH = 0x05, + CHIP_CONFIG_TYPE_END +}; + +typedef struct _SET_TXPWR_CTRL_T { + s8 c2GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ + s8 c2GHotspotPwrOffset; + s8 c2GP2pPwrOffset; + s8 c2GBowPwrOffset; + s8 c5GLegacyStaPwrOffset; /* Unit: 0.5dBm, default: 0 */ + s8 c5GHotspotPwrOffset; + s8 c5GP2pPwrOffset; + s8 c5GBowPwrOffset; + u8 ucConcurrencePolicy; /* TX power policy when concurrence + * in the same channel + * 0: Highest power has priority + * 1: Lowest power has priority + */ + s8 acReserved1[3]; /* Must be zero */ + + /* Power limit by channel for all data rates */ + s8 acTxPwrLimit2G[14]; /* Channel 1~14, Unit: 0.5dBm */ + s8 acTxPwrLimit5G[4]; /* UNII 1~4 */ + s8 acReserved2[2]; /* Must be zero */ +} SET_TXPWR_CTRL_T, *P_SET_TXPWR_CTRL_T; + +#if CFG_WOW_SUPPORT + +typedef struct _WOW_WAKE_HIF_T { + u8 ucWakeupHif; /* use in-band signal to wakeup system, ENUM_HIF_TYPE */ + u8 ucGpioPin; /* GPIO Pin */ + u8 ucTriggerLvl; /* refer to PF_WAKEUP_CMD_BIT0_OUTPUT_MODE_EN */ + u32 u4GpioInterval; /* non-zero means output reverse wakeup signal after + * delay time */ + u8 aucResv[5]; +} WOW_WAKE_HIF_T, *P_WOW_WAKE_HIF_T; + +typedef struct _WOW_PORT_T { + u8 ucIPv4UdpPortCnt; + u8 ucIPv4TcpPortCnt; + u8 ucIPv6UdpPortCnt; + u8 ucIPv6TcpPortCnt; + u16 ausIPv4UdpPort[MAX_TCP_UDP_PORT]; + u16 ausIPv4TcpPort[MAX_TCP_UDP_PORT]; + u16 ausIPv6UdpPort[MAX_TCP_UDP_PORT]; + u16 ausIPv6TcpPort[MAX_TCP_UDP_PORT]; +} WOW_PORT_T, *P_WOW_PORT_T; + +typedef struct _WOW_CTRL_T { + u8 fgWowEnable; /* 0: disable, 1: wow enable */ + u8 ucScenarioId; /* just a profile ID */ + u8 ucBlockCount; + u8 aucReserved1[1]; + WOW_WAKE_HIF_T astWakeHif[2]; + WOW_PORT_T stWowPort; + u8 ucReason; +} WOW_CTRL_T, *P_WOW_CTRL_T; + +#endif + +typedef enum _ENUM_NVRAM_MTK_FEATURE_T { + MTK_FEATURE_2G_256QAM_DISABLED = 0, + MTK_FEATURE_NUM +} ENUM_NVRAM_MTK_FEATURES_T, +*P_ENUM_NVRAM_MTK_FEATURES_T; + +/* For storing driver initialization value from glue layer */ +typedef struct _REG_INFO_T { + u32 u4SdBlockSize; /* SDIO block size */ + u32 u4SdBusWidth; /* SDIO bus width. 1 or 4 */ + u32 u4SdClockRate; /* SDIO clock rate. (in unit of HZ) */ + u32 u4StartFreq; /* Start Frequency for Ad-Hoc network : in unit of KHz + */ + u32 u4AdhocMode; /* Default mode for Ad-Hoc network : + * ENUM_PARAM_AD_HOC_MODE_T */ + u32 u4RddStartFreq; + u32 u4RddStopFreq; + u32 u4RddTestMode; + u32 u4RddShutFreq; + u32 u4RddDfs; + s32 i4HighRssiThreshold; + s32 i4MediumRssiThreshold; + s32 i4LowRssiThreshold; + s32 au4TxPriorityTag[ENUM_AC_TYPE_NUM]; + s32 au4RxPriorityTag[ENUM_AC_TYPE_NUM]; + s32 au4AdvPriorityTag[ENUM_ADV_AC_TYPE_NUM]; + u32 u4FastPSPoll; + u32 u4PTA; /* 0: disable, 1: enable */ + u32 u4TXLimit; /* 0: disable, 1: enable */ + u32 u4SilenceWindow; /* range: 100 - 625, unit: us */ + u32 u4TXLimitThreshold; /* range: 250 - 1250, unit: us */ + u32 u4PowerMode; + u32 fgEnArpFilter; + u32 u4PsCurrentMeasureEn; + u32 u4UapsdAcBmp; + u32 u4MaxSpLen; + u32 fgDisOnlineScan; /* 0: enable online scan, non-zero: disable online + * scan */ + u32 fgDisBcnLostDetection; /* 0: enable online scan, non-zero: disable + * online scan */ + u32 u4FixedRate; /* 0: automatic, non-zero: fixed rate */ + u32 u4ArSysParam0; + u32 u4ArSysParam1; + u32 u4ArSysParam2; + u32 u4ArSysParam3; + u32 fgDisRoaming; /* 0:enable roaming 1:disable */ + + /* NVRAM - MP Data -START- */ + u16 u2Part1OwnVersion; + u16 u2Part1PeerVersion; + + u8 aucMacAddr[6]; + u16 au2CountryCode[4]; /* Country code (in ISO 3166-1 expression, ex: + * "US", "TW") */ + TX_PWR_PARAM_T rTxPwr; + u8 aucEFUSE[144]; + u8 ucTxPwrValid; + u8 ucSupport5GBand; + u8 fg2G4BandEdgePwrUsed; + s8 cBandEdgeMaxPwrCCK; + s8 cBandEdgeMaxPwrOFDM20; + s8 cBandEdgeMaxPwrOFDM40; + ENUM_REG_CH_MAP_T eRegChannelListMap; + u8 ucRegChannelListIndex; + DOMAIN_INFO_ENTRY rDomainInfo; + RSSI_PATH_COMPASATION_T rRssiPathCompasation; + u8 ucRssiPathCompasationUsed; + /* NVRAM - MP Data -END- */ + + /* NVRAM - Functional Data -START- */ + u8 uc2G4BwFixed20M; + u8 uc5GBwFixed20M; + u8 ucEnable5GBand; + u8 ucGpsDesense; + u8 ucRxDiversity; + /* NVRAM - Functional Data -END- */ + + P_NEW_EFUSE_MAPPING2NVRAM_T prOldEfuseMapping; + + u8 aucNvram[512]; + P_WIFI_CFG_PARAM_STRUCT prNvramSettings; +} REG_INFO_T, *P_REG_INFO_T; + +/* for divided firmware loading */ +typedef struct _FWDL_SECTION_INFO_T { + u32 u4DestAddr; + u8 ucChipInfo; + u8 ucFeatureSet; + u8 ucEcoCode; + u8 aucReserved[9]; + u8 aucBuildDate[16]; + u32 u4Length; +} FWDL_SECTION_INFO_T, *P_FWDL_SECTION_INFO_T; + +typedef struct _FIRMWARE_DIVIDED_DOWNLOAD_T { + FWDL_SECTION_INFO_T arSection[2]; +} FIRMWARE_DIVIDED_DOWNLOAD_T, *P_FIRMWARE_DIVIDED_DOWNLOAD_T; + +#if (CFG_UMAC_GENERATION >= 0x20) +#define LEN_4_BYTE_CRC (4) + +typedef struct _tailer_format_tag { + u32 addr; + u8 chip_info; + u8 feature_set; + u8 eco_code; + u8 ram_version[10]; + u8 ram_built_date[15]; + u32 len; +} tailer_format_t; + +typedef struct _fw_image_tailer_tag { + tailer_format_t ilm_info; + tailer_format_t dlm_info; +} fw_image_tailer_t; +#if CFG_SUPPORT_COMPRESSION_FW_OPTION +typedef struct _tailer_format_tag_2 { + u32 crc; + u32 addr; + u32 block_size; + u32 real_size; + u8 chip_info; + u8 feature_set; + u8 eco_code; + u8 ram_version[10]; + u8 ram_built_date[15]; + u32 len; +} tailer_format_t_2; +typedef struct _fw_image_tailer_tag_2 { + tailer_format_t_2 ilm_info; + tailer_format_t_2 dlm_info; +} fw_image_tailer_t_2; +typedef struct _fw_image_tailer_check { + u8 chip_info; + u8 feature_set; + u8 eco_code; + u8 ram_version[10]; + u8 ram_built_date[15]; + u32 len; +} fw_image_tailer_check; +#endif +typedef struct _PATCH_FORMAT_T { + u8 aucBuildDate[16]; + u8 aucPlatform[4]; + u32 u4SwHwVersion; + u32 u4PatchVersion; + u16 u2CRC; /* CRC calculated for image only */ + u8 ucPatchImage[0]; +} PATCH_FORMAT_T, *P_PATCH_FORMAT_T; + +/* PDA - Patch Decryption Accelerator */ +#define PDA_N9 0 +#define PDA_CR4 1 + +#define CR4_FWDL_SECTION_NUM HIF_CR4_FWDL_SECTION_NUM +#define IMG_DL_STATUS_PORT_IDX HIF_IMG_DL_STATUS_PORT_IDX + +typedef enum _ENUM_IMG_DL_IDX_T { + IMG_DL_IDX_N9_FW, + IMG_DL_IDX_CR4_FW, + IMG_DL_IDX_PATCH +} ENUM_IMG_DL_IDX_T, +*P_ENUM_IMG_DL_IDX_T; + +#endif + +typedef struct _PARAM_MCR_RW_STRUCT_T { + u32 u4McrOffset; + u32 u4McrData; +} PARAM_MCR_RW_STRUCT_T, *P_PARAM_MCR_RW_STRUCT_T; + +/* per access category statistics */ +typedef struct _WIFI_WMM_AC_STAT_T { + u32 u4TxMsdu; + u32 u4RxMsdu; + u32 u4TxDropMsdu; + u32 u4TxFailMsdu; + u32 u4TxRetryMsdu; +} WIFI_WMM_AC_STAT_T, *P_WIFI_WMM_AC_STAT_T; + +typedef struct _TX_VECTOR_BBP_LATCH_T { + u32 u4TxVector1; + u32 u4TxVector2; + u32 u4TxVector4; +} TX_VECTOR_BBP_LATCH_T, *P_TX_VECTOR_BBP_LATCH_T; + +typedef struct _MIB_INFO_STAT_T { + u32 u4RxMpduCnt; + u32 u4FcsError; + u32 u4RxFifoFull; + u32 u4AmpduTxSfCnt; + u32 u4AmpduTxAckSfCnt; + u16 u2TxRange1AmpduCnt; + u16 u2TxRange2AmpduCnt; + u16 u2TxRange3AmpduCnt; + u16 u2TxRange4AmpduCnt; + u16 u2TxRange5AmpduCnt; + u16 u2TxRange6AmpduCnt; + u16 u2TxRange7AmpduCnt; + u16 u2TxRange8AmpduCnt; +} MIB_INFO_STAT_T, *P_MIB_INFO_STAT_T; + +typedef struct _PARAM_GET_STA_STATISTICS { + /* Per-STA statistic */ + u8 aucMacAddr[MAC_ADDR_LEN]; + + u32 u4Flag; + + u8 ucReadClear; + u8 ucLlsReadClear; + + /* From driver */ + u32 u4TxTotalCount; + u32 u4TxExceedThresholdCount; + + u32 u4TxMaxTime; + u32 u4TxAverageProcessTime; + + u32 u4RxTotalCount; + + u32 au4TcResourceEmptyCount[NUM_TC_RESOURCE_TO_STATISTICS]; + u32 au4TcQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; + + /* From FW */ + u8 ucPer; /* base: 128 */ + u8 ucRcpi; + u32 u4PhyMode; + u16 u2LinkSpeed; /* unit is 0.5 Mbits */ + + u32 u4TxFailCount; + u32 u4TxLifeTimeoutCount; + + u32 u4TxAverageAirTime; + u32 u4TransmitCount; /* Transmit in the air (wtbl) */ + u32 u4TransmitFailCount; /* Transmit without ack/ba in the air (wtbl) */ + + WIFI_WMM_AC_STAT_T arLinkStatistics[AC_NUM]; /*link layer statistics */ + + /* Global queue management statistic */ + u32 au4TcAverageQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; + u32 au4TcCurrentQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; + + u8 ucTemperature; + u8 ucSkipAr; + u8 ucArTableIdx; + u8 ucRateEntryIdx; + u8 ucRateEntryIdxPrev; + u8 ucTxSgiDetectPassCnt; + u8 ucAvePer; + u8 aucArRatePer[AR_RATE_TABLE_ENTRY_MAX]; + u8 aucRateEntryIndex[AUTO_RATE_NUM]; + u8 ucArStateCurr; + u8 ucArStatePrev; + u8 ucArActionType; + u8 ucHighestRateCnt; + u8 ucLowestRateCnt; + u16 u2TrainUp; + u16 u2TrainDown; + u32 u4Rate1TxCnt; + u32 u4Rate1FailCnt; + TX_VECTOR_BBP_LATCH_T rTxVector[ENUM_BAND_NUM]; + MIB_INFO_STAT_T rMibInfo[ENUM_BAND_NUM]; + u8 ucResetCounter; + u8 fgIsForceTxStream; + u8 fgIsForceSeOff; + + /* Reserved fields */ + u8 au4Reserved[20]; +} PARAM_GET_STA_STATISTICS, *P_PARAM_GET_STA_STATISTICS; + +typedef struct _PARAM_GET_BSS_STATISTICS { + /* Per-STA statistic */ + u8 aucMacAddr[MAC_ADDR_LEN]; + + u32 u4Flag; + + u8 ucReadClear; + + u8 ucLlsReadClear; + + u8 ucBssIndex; + + /* From driver */ + u32 u4TxTotalCount; + u32 u4TxExceedThresholdCount; + + u32 u4TxMaxTime; + u32 u4TxAverageProcessTime; + + u32 u4RxTotalCount; + + u32 au4TcResourceEmptyCount[NUM_TC_RESOURCE_TO_STATISTICS]; + u32 au4TcQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; + + /* From FW */ + u8 ucPer; /* base: 128 */ + u8 ucRcpi; + u32 u4PhyMode; + u16 u2LinkSpeed; /* unit is 0.5 Mbits */ + + u32 u4TxFailCount; + u32 u4TxLifeTimeoutCount; + + u32 u4TxAverageAirTime; + u32 u4TransmitCount; /* Transmit in the air (wtbl) */ + u32 u4TransmitFailCount; /* Transmit without ack/ba in the air (wtbl) */ + + WIFI_WMM_AC_STAT_T arLinkStatistics[AC_NUM]; /*link layer statistics */ + + /* Global queue management statistic */ + u32 au4TcAverageQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; + u32 au4TcCurrentQueLen[NUM_TC_RESOURCE_TO_STATISTICS]; + + /* Reserved fields */ + u8 au4Reserved[32]; /* insufficient for LLS?? */ +} PARAM_GET_BSS_STATISTICS, *P_PARAM_GET_BSS_STATISTICS; + +typedef struct _PARAM_GET_DRV_STATISTICS { + s32 i4TxPendingFrameNum; + s32 i4TxPendingSecurityFrameNum; + s32 i4TxPendingCmdNum; + s32 i4PendingFwdFrameCount; /* sync i4PendingFwdFrameCount in _TX_CTRL_T + */ + u32 u4MsduNumElem; /* sync pad->rTxCtrl.rFreeMsduInfoList.u4NumElem */ + u32 u4TxMgmtTxringQueueNumElem; /* sync + * pad->rTxCtrl.rTxMgmtTxingQueue.u4NumElem + */ + + u32 u4RxFreeSwRfbMsduNumElem; /* sync + * pad->prRxCtrl.rFreeSwRfbList.u4NumElem + */ + u32 u4RxReceivedRfbNumElem; /* sync + * pad->prRxCtrl.rReceivedRfbList.u4NumElem + */ + u32 u4RxIndicatedNumElem; /* sync + * pad->prRxCtrl.rIndicatedRfbList.u4NumElem + */ +} PARAM_GET_DRV_STATISTICS, *P_PARAM_GET_DRV_STATISTICS; + +typedef struct _NET_INTERFACE_INFO_T { + u8 ucBssIndex; + void *pvNetInterface; +} NET_INTERFACE_INFO_T, *P_NET_INTERFACE_INFO_T; + +typedef enum _ENUM_TX_RESULT_CODE_T { + TX_RESULT_SUCCESS = 0, + TX_RESULT_LIFE_TIMEOUT, + TX_RESULT_RTS_ERROR, + TX_RESULT_MPDU_ERROR, + TX_RESULT_AGING_TIMEOUT, + TX_RESULT_FLUSHED, + TX_RESULT_BIP_ERROR, + TX_RESULT_UNSPECIFIED_ERROR, + TX_RESULT_DROPPED_IN_DRIVER = 32, + TX_RESULT_DROPPED_IN_FW, + TX_RESULT_QUEUE_CLEARANCE, + TX_RESULT_UNINITIALIZED = 48, // driver only + TX_RESULT_1XTX_CLEAR, // driver only + TX_RESULT_NUM +} ENUM_TX_RESULT_CODE_T, +*P_ENUM_TX_RESULT_CODE_T; + +struct _WLAN_CFG_ENTRY_T { + u8 aucKey[WLAN_CFG_KEY_LEN_MAX]; + u8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; + WLAN_CFG_SET_CB pfSetCb; + void *pPrivate; + u32 u4Flags; +}; + +struct _WLAN_CFG_T { + u32 u4WlanCfgEntryNumMax; + u32 u4WlanCfgKeyLenMax; + u32 u4WlanCfgValueLenMax; + WLAN_CFG_ENTRY_T arWlanCfgBuf[WLAN_CFG_ENTRY_NUM_MAX]; +}; + +struct _WLAN_CFG_REC_T { + u32 u4WlanCfgEntryNumMax; + u32 u4WlanCfgKeyLenMax; + u32 u4WlanCfgValueLenMax; + WLAN_CFG_ENTRY_T arWlanCfgBuf[WLAN_CFG_REC_ENTRY_NUM_MAX]; +}; + +typedef enum _ENUM_MAX_BANDWIDTH_SETTING_T { + MAX_BW_20MHZ = 0, + MAX_BW_40MHZ, + MAX_BW_80MHZ, + MAX_BW_160MHZ, + MAX_BW_80_80_MHZ +} ENUM_MAX_BANDWIDTH_SETTING, +*P_ENUM_MAX_BANDWIDTH_SETTING_T; + +typedef struct _TX_PACKET_INFO { + u8 ucPriorityParam; + u32 u4PacketLen; + u8 aucEthDestAddr[MAC_ADDR_LEN]; + u16 u2Flag; +} TX_PACKET_INFO, *P_TX_PACKET_INFO; + +typedef enum _ENUM_TX_PROFILING_TAG_T { + TX_PROF_TAG_OS_TO_DRV = 0, + TX_PROF_TAG_DRV_ENQUE, + TX_PROF_TAG_DRV_DEQUE, + TX_PROF_TAG_DRV_TX_DONE, + TX_PROF_TAG_MAC_TX_DONE +} ENUM_TX_PROFILING_TAG_T, +*P_ENUM_TX_PROFILING_TAG_T; + +enum ENUM_WF_PATH_FAVOR_T { + ENUM_WF_NON_FAVOR = 0xff, + ENUM_WF_0_ONE_STREAM_PATH_FAVOR = 0, + ENUM_WF_1_ONE_STREAM_PATH_FAVOR = 1, + ENUM_WF_0_1_TWO_STREAM_PATH_FAVOR = 2, + ENUM_WF_0_1_DUP_STREAM_PATH_FAVOR = 3, +}; + +struct WLAN_CFG_PARSE_STATE_S { + s8 *ptr; + s8 *text; +#if CFG_SUPPORT_EASY_DEBUG + u32 textsize; +#endif + s32 nexttoken; + u32 maxSize; +}; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define BUILD_SIGN(ch0, ch1, ch2, ch3) \ + ((u32)(u8)(ch0) | ((u32)(u8)(ch1) << 8) | ((u32)(u8)(ch2) << 16) | \ + ((u32)(u8)(ch3) << 24)) + +#define MTK_WIFI_SIGNATURE BUILD_SIGN('M', 'T', 'K', 'W') + +#define IS_FEATURE_ENABLED(_ucFeature) \ + (((_ucFeature) == FEATURE_ENABLED) || \ + ((_ucFeature) == FEATURE_FORCE_ENABLED)) +#define IS_FEATURE_FORCE_ENABLED(_ucFeature) \ + ((_ucFeature) == FEATURE_FORCE_ENABLED) +#define IS_FEATURE_DISABLED(_ucFeature) ((_ucFeature) == FEATURE_DISABLED) + +/* This macro is for later added feature options which use command reserved + * field as option switch */ +/* 0: AUTO + * 1: Disabled + * 2: Enabled + * 3: Force disabled + */ +#define FEATURE_OPT_IN_COMMAND(_ucFeature) ((_ucFeature) + 1) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +P_ADAPTER_T wlanAdapterCreate(IN P_GLUE_INFO_T prGlueInfo); + +void wlanAdapterDestroy(IN P_ADAPTER_T prAdapter); + +void wlanCardEjected(IN P_ADAPTER_T prAdapter); + +void wlanIST(IN P_ADAPTER_T prAdapter); + +u8 wlanISR(IN P_ADAPTER_T prAdapter, IN u8 fgGlobalIntrCtrl); + +WLAN_STATUS wlanProcessCommandQueue(IN P_ADAPTER_T prAdapter, + IN P_QUE_T prCmdQue); + +WLAN_STATUS wlanSendCommand(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo); + +WLAN_STATUS wlanSendCommandMthread(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo); + +WLAN_STATUS wlanTxCmdMthread(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanTxCmdDoneMthread(IN P_ADAPTER_T prAdapter); + +void wlanClearTxCommandQueue(IN P_ADAPTER_T prAdapter); + +void wlanClearTxCommandDoneQueue(IN P_ADAPTER_T prAdapter); + +void wlanClearDataQueue(IN P_ADAPTER_T prAdapter); + +void wlanClearRxToOsQueue(IN P_ADAPTER_T prAdapter); + +void wlanClearPendingCommandQueue(IN P_ADAPTER_T prAdapter); + +void wlanReleaseCommand(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +void wlanReleaseCommandEx(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus, + IN u8 fgIsNeedHandler); + +void wlanReleasePendingOid(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr); + +void wlanReturnPacketDelaySetupTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr); + +void wlanReturnPacket(IN P_ADAPTER_T prAdapter, IN void *pvPacket); + +WLAN_STATUS +wlanQueryInformation(IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfOidQryHandler, + IN void *pvInfoBuf, + IN u32 u4InfoBufLen, + OUT u32 *pu4QryInfoLen); + +WLAN_STATUS +wlanSetInformation(IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfOidSetHandler, + IN void *pvInfoBuf, + IN u32 u4InfoBufLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS wlanAdapterStart(IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo); + +WLAN_STATUS wlanAdapterStop(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanCheckWifiFunc(IN P_ADAPTER_T prAdapter, IN u8 fgRdyChk); + +void wlanReturnRxPacket(IN void *pvAdapter, IN void *pvPacket); + +void wlanRxSetBroadcast(IN P_ADAPTER_T prAdapter, IN u8 fgEnableBroadcast); + +u8 wlanIsHandlerNeedHwAccess(IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN u8 fgSetInfo); + +void wlanSetPromiscuousMode(IN P_ADAPTER_T prAdapter, + IN u8 fgEnablePromiscuousMode); +#if CFG_SUPPORT_COMPRESSION_FW_OPTION +WLAN_STATUS +wlanImageSectionDownloadStage(IN P_ADAPTER_T prAdapter, + IN void *pvFwImageMapFile, + IN u32 u4FwImageFileLength, + u8 ucSectionNumber, + IN ENUM_IMG_DL_IDX_T eDlIdx, + OUT u8 *ucIsCompressed, + OUT P_INIT_CMD_WIFI_DECOMPRESSION_START + prFwImageInFo); +#else +WLAN_STATUS wlanImageSectionDownloadStage(IN P_ADAPTER_T prAdapter, + IN void *pvFwImageMapFile, + IN u32 u4FwImageFileLength, + u8 ucSectionNumber, + IN ENUM_IMG_DL_IDX_T eDlIdx); + +#endif + +#if CFG_ENABLE_FW_DOWNLOAD +WLAN_STATUS wlanImageSectionConfig(IN P_ADAPTER_T prAdapter, + IN u32 u4DestAddr, + IN u32 u4ImgSecSize, + IN u32 u4DataMode, + IN ENUM_IMG_DL_IDX_T eDlIdx); + +WLAN_STATUS wlanImageSectionDownload(IN P_ADAPTER_T prAdapter, + IN u32 u4ImgSecSize, + IN u8 *pucImgSecBuf); + +WLAN_STATUS wlanImageQueryStatus(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanImageSectionDownloadStatus(IN P_ADAPTER_T prAdapter, + IN u8 ucCmdSeqNum); +#define wlanConfigWifiFuncStatus wlanImageSectionDownloadStatus + +WLAN_STATUS wlanConfigWifiFunc(IN P_ADAPTER_T prAdapter, + IN u8 fgEnable, + IN u32 u4StartAddress, + IN u8 ucPDA); + +u32 wlanCRC32(u8 *buf, u32 len); +#endif + +WLAN_STATUS wlanSendDummyCmd(IN P_ADAPTER_T prAdapter, IN u8 fgIsReqTxRsrc); + +WLAN_STATUS wlanSendNicPowerCtrlCmd(IN P_ADAPTER_T prAdapter, + IN u8 ucPowerMode); + +WLAN_STATUS wlanKeepFullPwr(IN P_ADAPTER_T prAdapter, IN u8 fgEnable); + +u8 wlanIsHandlerAllowedInRFTest(IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN u8 fgSetInfo); + +WLAN_STATUS wlanProcessQueuedSwRfb(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfbListHead); + +WLAN_STATUS wlanProcessQueuedMsduInfo(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead); + +u8 wlanoidTimeoutCheck(IN P_ADAPTER_T prAdapter, + IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN u32 u4Timeout); + +void wlanoidClearTimeoutCheck(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanUpdateNetworkAddress(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanUpdateBasicConfig(IN P_ADAPTER_T prAdapter); + +u8 wlanQueryTestMode(IN P_ADAPTER_T prAdapter); + +u8 wlanProcessTxFrame(IN P_ADAPTER_T prAdapter, IN P_NATIVE_PACKET prPacket); + +/* Security Frame Handling */ +u8 wlanProcessSecurityFrame(IN P_ADAPTER_T prAdapter, + IN P_NATIVE_PACKET prPacket); + +void wlanSecurityFrameTxDone(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen); + +void wlanSecurityFrameTxTimeout(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo); + +/*----------------------------------------------------------------------------*/ +/* OID/IOCTL Handling */ +/*----------------------------------------------------------------------------*/ +void wlanClearScanningResult(IN P_ADAPTER_T prAdapter); + +void wlanClearBssInScanningResult(IN P_ADAPTER_T prAdapter, IN u8 *arBSSID); + +#if CFG_TEST_WIFI_DIRECT_GO +void wlanEnableP2pFunction(IN P_ADAPTER_T prAdapter); + +void wlanEnableATGO(IN P_ADAPTER_T prAdapter); +#endif + +/*----------------------------------------------------------------------------*/ +/* NIC Capability Retrieve by Polling */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryNicCapability(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* PD MCR Retrieve by Polling */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanQueryPdMcr(IN P_ADAPTER_T prAdapter, + IN P_PARAM_MCR_RW_STRUCT_T prMcrRdInfo); + +/*----------------------------------------------------------------------------*/ +/* Loading Manufacture Data */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanLoadManufactureData(IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo); + +/*----------------------------------------------------------------------------*/ +/* Media Stream Mode */ +/*----------------------------------------------------------------------------*/ +u8 wlanResetMediaStreamMode(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* Timer Timeout Check (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanTimerTimeoutCheck(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* Mailbox Message Check (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanProcessMboxMessage(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* TX Pending Packets Handling (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanEnqueueTxPacket(IN P_ADAPTER_T prAdapter, + IN P_NATIVE_PACKET prNativePacket); + +WLAN_STATUS wlanFlushTxPendingPackets(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanTxPendingPackets(IN P_ADAPTER_T prAdapter, + IN OUT u8 *pfgHwAccess); + +/*----------------------------------------------------------------------------*/ +/* Low Power Acquire/Release (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanAcquirePowerControl(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanReleasePowerControl(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* Pending Packets Number Reporting (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +u32 wlanGetTxPendingFrameCount(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* ACPI state inquiry (for Glue Layer) */ +/*----------------------------------------------------------------------------*/ +ENUM_ACPI_STATE_T wlanGetAcpiState(IN P_ADAPTER_T prAdapter); + +void wlanSetAcpiState(IN P_ADAPTER_T prAdapter, + IN ENUM_ACPI_STATE_T ePowerState); + +void wlanDefTxPowerCfg(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* get ECO version from Revision ID register (for Win32) */ +/*----------------------------------------------------------------------------*/ +u8 wlanGetEcoVersion(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* get Rom version */ +/*----------------------------------------------------------------------------*/ +u8 wlanGetRomVersion(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* set preferred band configuration corresponding to network type */ +/*----------------------------------------------------------------------------*/ +void wlanSetPreferBandByNetwork(IN P_ADAPTER_T prAdapter, + IN ENUM_BAND_T eBand, + IN u8 ucBssIndex); + +/*----------------------------------------------------------------------------*/ +/* get currently operating channel information */ +/*----------------------------------------------------------------------------*/ +u8 wlanGetChannelNumberByNetwork(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex); + +/*----------------------------------------------------------------------------*/ +/* check for system configuration to generate message on scan list */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanCheckSystemConfiguration(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* query bss statistics information from driver and firmware */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryBssStatistics(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +/*----------------------------------------------------------------------------*/ +/* dump per-BSS statistics */ +/*----------------------------------------------------------------------------*/ +void wlanDumpBssStatistics(IN P_ADAPTER_T prAdapter, u8 ucBssIndex); + +/*----------------------------------------------------------------------------*/ +/* query sta statistics information from driver and firmware */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidQueryStaStatistics(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +/*----------------------------------------------------------------------------*/ +/* query NIC resource information from chip and reset Tx resource for normal + * operation */ +/*----------------------------------------------------------------------------*/ +void wlanQueryNicResourceInformation(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanQueryNicCapabilityV2(IN P_ADAPTER_T prAdapter); + +void wlanUpdateNicResourceInformation(IN P_ADAPTER_T prAdapter); + +/*----------------------------------------------------------------------------*/ +/* GET/SET BSS index mapping for network interfaces */ +/*----------------------------------------------------------------------------*/ +void wlanBindNetInterface(IN P_GLUE_INFO_T prGlueInfo, + IN u8 ucNetInterfaceIndex, + IN void *pvNetInterface); + +void wlanBindBssIdxToNetInterface(IN P_GLUE_INFO_T prGlueInfo, + IN u8 ucBssIndex, + IN void *pvNetInterface); + +u8 wlanGetBssIdxByNetInterface(IN P_GLUE_INFO_T prGlueInfo, + IN void *pvNetInterface); + +void *wlanGetNetInterfaceByBssIdx(IN P_GLUE_INFO_T prGlueInfo, + IN u8 ucBssIndex); + +/* for windows as windows glue cannot see through P_ADAPTER_T */ +u8 wlanGetAisBssIndex(IN P_ADAPTER_T prAdapter); + +void wlanInitFeatureOption(IN P_ADAPTER_T prAdapter); + +void wlanCfgSetSwCtrl(IN P_ADAPTER_T prAdapter); + +void wlanCfgSetChip(IN P_ADAPTER_T prAdapter); + +void wlanCfgSetDebugLevel(IN P_ADAPTER_T prAdapter); + +void wlanCfgSetCountryCode(IN P_ADAPTER_T prAdapter); + +P_WLAN_CFG_ENTRY_T wlanCfgGetEntry(IN P_ADAPTER_T prAdapter, + const s8 *pucKey, + u8 fgGetCfgRec); + +WLAN_STATUS +wlanCfgGet(IN P_ADAPTER_T prAdapter, + const s8 *pucKey, + s8 *pucValue, + s8 *pucValueDef, + u32 u4Flags); + +u32 wlanCfgGetUint32(IN P_ADAPTER_T prAdapter, const s8 *pucKey, + u32 u4ValueDef); + +s32 wlanCfgGetInt32(IN P_ADAPTER_T prAdapter, const s8 *pucKey, s32 i4ValueDef); + +WLAN_STATUS wlanCfgSetUint32(IN P_ADAPTER_T prAdapter, + const s8 *pucKey, + u32 u4Value); + +WLAN_STATUS wlanCfgSet(IN P_ADAPTER_T prAdapter, + const s8 *pucKey, + s8 *pucValue, + u32 u4Flags); + +WLAN_STATUS +wlanCfgSetCb(IN P_ADAPTER_T prAdapter, + const s8 *pucKey, + WLAN_CFG_SET_CB pfSetCb, + void *pPrivate, + u32 u4Flags); + +#if CFG_SUPPORT_EASY_DEBUG + +WLAN_STATUS wlanCfgParse(IN P_ADAPTER_T prAdapter, + u8 *pucConfigBuf, + u32 u4ConfigBufLen, + u8 isFwConfig); +void wlanFeatureToFw(IN P_ADAPTER_T prAdapter); +#if CFG_SUPPORT_SEND_ONLY_ONE_CFG +WLAN_STATUS wlanFeatureToFwOnlyOneCfg(IN P_ADAPTER_T prAdapter, + const s8 *pucKey, + s8 *pucValue); +#endif +#endif + +void wlanLoadDefaultCustomerSetting(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanCfgInit(IN P_ADAPTER_T prAdapter, + u8 *pucConfigBuf, + u32 u4ConfigBufLen, + u32 u4Flags); + +WLAN_STATUS wlanCfgParseArgument(s8 *cmdLine, s32 *argc, s8 *argv[]); + +#if CFG_WOW_SUPPORT +WLAN_STATUS wlanCfgParseArgumentLong(s8 *cmdLine, s32 *argc, s8 *argv[]); +#endif + +s32 wlanHexToNum(s8 c); +s32 wlanHexToByte(s8 *hex); + +s32 wlanHwAddrToBin(s8 *txt, u8 *addr); + +u8 wlanIsChipNoAck(IN P_ADAPTER_T prAdapter); + +u8 wlanIsChipRstRecEnabled(IN P_ADAPTER_T prAdapter); + +u8 wlanIsChipAssert(IN P_ADAPTER_T prAdapter); + +void wlanChipRstPreAct(IN P_ADAPTER_T prAdapter); + +void wlanTxProfilingTagPacket(IN P_ADAPTER_T prAdapter, + IN P_NATIVE_PACKET prPacket, + IN ENUM_TX_PROFILING_TAG_T eTag); + +void wlanTxProfilingTagMsdu(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_PROFILING_TAG_T eTag); +#if CFG_ASSERT_DUMP +void wlanCorDumpTimerReset(IN P_ADAPTER_T prAdapter, u8 fgIsResetN9); + +void wlanN9CorDumpTimeOut(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr); + +void wlanCr4CorDumpTimeOut(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr); +#endif +#endif + +u8 wlanGetWlanIdxByAddress(IN P_ADAPTER_T prAdapter, + IN u8 *pucAddr, + OUT u8 *pucIndex); + +u8 *wlanGetStaAddrByWlanIdx(IN P_ADAPTER_T prAdapter, IN u8 ucIndex); + +P_WLAN_CFG_ENTRY_T wlanCfgGetEntryByIndex(IN P_ADAPTER_T prAdapter, + const u8 ucIdx, + u32 flag); + +WLAN_STATUS wlanGetStaIdxByWlanIdx(IN P_ADAPTER_T prAdapter, + IN u8 ucIndex, + OUT u8 *pucStaIdx); + +/*----------------------------------------------------------------------------*/ +/* update per-AC statistics for LLS */ +/*----------------------------------------------------------------------------*/ +void wlanUpdateTxStatistics(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + u8 fgTxDrop); + +void wlanUpdateRxStatistics(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb); + +WLAN_STATUS wlanTriggerStatsLog(IN P_ADAPTER_T prAdapter, + IN u32 u4DurationInMs); + +WLAN_STATUS wlanDhcpTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +WLAN_STATUS wlanArpTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +WLAN_STATUS wlan1xTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus); + +WLAN_STATUS wlanDownloadFW(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanDownloadPatch(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanGetPatchInfo(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanPowerOffWifi(IN P_ADAPTER_T prAdapter); + +void wlanPrintVersion(P_ADAPTER_T prAdapter); +WLAN_STATUS wlanAccessRegister(IN P_ADAPTER_T prAdapter, + IN u32 u4Addr, + IN u32 *pru4Result, + IN u32 u4Data, + IN u8 ucSetQuery); + +WLAN_STATUS wlanAccessRegisterStatus(IN P_ADAPTER_T prAdapter, + IN u8 ucCmdSeqNum, + IN u8 ucSetQuery, + IN void *prEvent, + IN u32 u4EventLen); + +WLAN_STATUS wlanSetChipEcoInfo(IN P_ADAPTER_T prAdapter); + +#if CFG_STR_DHCP_RENEW_OFFLOAD +void wlanSetDhcpOffloadInfo(P_GLUE_INFO_T prGlueInfo, + struct net_device *prDev, + u8 fgSuspend); +#endif + +void wlanNotifyFwSuspend(P_GLUE_INFO_T prGlueInfo, + struct net_device *prDev, + u8 fgSuspend); + +void wlanClearPendingInterrupt(IN P_ADAPTER_T prAdapter); + +u8 wlanGetAntPathType(IN P_ADAPTER_T prAdapter, + IN enum ENUM_WF_PATH_FAVOR_T eWfPathFavor, + IN u8 ucBssIndex); + +u8 wlanGetSpeIdx(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN enum ENUM_WF_PATH_FAVOR_T eWfPathFavor); + +u8 wlanGetSupportNss(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex); + +s32 wlanGetFileContent(P_ADAPTER_T prAdapter, + const u8 *pcFileName, + u8 *pucBuf, + u32 u4MaxFileLen, + u32 *pu4ReadFileLen, + u8 bReqFw); + +#if CFG_SUPPORT_ANT_SELECT +WLAN_STATUS wlanUpdateExtInfo(IN P_ADAPTER_T prAdapter); +#endif + +#if CFG_SUPPORT_RSSI_COMP +WLAN_STATUS wlanUpdateRssiComp(IN P_ADAPTER_T prAdapter); +#endif + +WLAN_STATUS wlanSetEd(IN P_ADAPTER_T prAdapter, + s32 u4EdVal2G, + s32 u4EdVal5G, + u32 u4Sel); +int wlanSuspendRekeyOffload(P_GLUE_INFO_T prGlueInfo, IN u8 ucRekeyMode); +void wlanDisTrafficReport(P_GLUE_INFO_T prGlueInfo); +void wlanSuspendPmHandle(P_GLUE_INFO_T prGlueInfo); +void wlanResumePmHandle(P_GLUE_INFO_T prGlueInfo); +void wlanTxCmdDoneCb(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo); +void wlanClearTxOidCommand(IN P_ADAPTER_T prAdapter); +void wlanImageSectionGetFwInfo(IN P_ADAPTER_T prAdapter, + IN void *pvFwImageMapFile, + IN u32 u4FwImageFileLength, IN u8 ucTotSecNum, + IN u8 ucCurSecNum, IN ENUM_IMG_DL_IDX_T eDlIdx, + OUT u32 *pu4StartOffset, OUT u32 *pu4Addr, + OUT u32 *pu4Len, OUT u32 *pu4DataMode); +void wlanImageSectionGetPatchInfo(IN P_ADAPTER_T prAdapter, + IN void *pvFwImageMapFile, + IN u32 u4FwImageFileLength, IN u8 ucTotSecNum, + IN u8 ucCurSecNum, + IN ENUM_IMG_DL_IDX_T eDlIdx, + OUT u32 *pu4StartOffset, OUT u32 *pu4Addr, + OUT u32 *pu4Len, OUT u32 *pu4DataMode); +void wlanImageSectionGetInfo(IN P_ADAPTER_T prAdapter, + IN void *pvFwImageMapFile, + IN u32 u4FwImageFileLength, IN u8 ucTotSecNum, + IN u8 ucCurSecNum, IN ENUM_IMG_DL_IDX_T eDlIdx, + OUT u32 *pu4StartOffset, OUT u32 *pu4Addr, + OUT u32 *pu4Len, OUT u32 *pu4DataMode); +WLAN_STATUS wlanPatchRecvSemaResp(IN P_ADAPTER_T prAdapter, IN u8 ucCmdSeqNum, OUT u8 *pucPatchStatus); +WLAN_STATUS wlanPatchSendSemaControl(IN P_ADAPTER_T prAdapter, OUT u8 *pucSeqNum); +u8 wlanPatchIsDownloaded(IN P_ADAPTER_T prAdapter); +WLAN_STATUS wlanPatchSendComplete(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanLoadManufactureData_5G(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo); +void wlanDumpAllBssStatistics(IN P_ADAPTER_T prAdapter); +void wlanSetNicResourceParameters(IN P_ADAPTER_T prAdapter); + +void wlanCfgRecordValue(IN P_ADAPTER_T prAdapter, const s8 *pucKey, s32 u4Value); +s32 wlanCfgFindNextToken(struct WLAN_CFG_PARSE_STATE_S *state); +WLAN_STATUS wlanCfgParseAddEntry(IN P_ADAPTER_T prAdapter, u8 *pucKeyHead, u8 *pucKeyTail, u8 *pucValueHead, u8 *pucValueTail); +s8 atoi(u8 ch); +WLAN_STATUS wlanCfgParseToFW(s8 **args, s8 *args_size, u8 nargs, s8 *buffer, u8 times); +void wlanTxLifetimeUpdateStaStats(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); +u8 wlanTxLifetimeIsProfilingEnabled(IN P_ADAPTER_T prAdapter); +u8 wlanTxLifetimeIsTargetMsdu(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo); +void wlanTxLifetimeTagPacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_PROFILING_TAG_T eTag); +u8 wlanAntPathFavorSelect(enum ENUM_WF_PATH_FAVOR_T eWfPathFavor); + +void disconnect_sta(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec); diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/wlan_oid.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/wlan_oid.h new file mode 100644 index 00000000000000..09cfb9c2d03d38 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/wlan_oid.h @@ -0,0 +1,3019 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "wlan_oid.h" + * \brief This file contains the declairation file of the WLAN OID processing + * routines of Windows driver for MediaTek Inc. 802.11 Wireless LAN Adapters. + */ + +#ifndef _WLAN_OID_H +#define _WLAN_OID_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define PARAM_MAX_LEN_SSID 32 + +#define PARAM_MAC_ADDR_LEN 6 + +#define ETHERNET_HEADER_SZ 14 +#define ETHERNET_MIN_PKT_SZ 60 +#define ETHERNET_MAX_PKT_SZ 1514 + +#define PARAM_MAX_LEN_RATES 8 +#define PARAM_MAX_LEN_RATES_EX 16 + +#define PARAM_AUTH_REQUEST_REAUTH 0x01 +#define PARAM_AUTH_REQUEST_KEYUPDATE 0x02 +#define PARAM_AUTH_REQUEST_PAIRWISE_ERROR 0x06 +#define PARAM_AUTH_REQUEST_GROUP_ERROR 0x0E + +#define PARAM_EEPROM_READ_METHOD_READ 1 +#define PARAM_EEPROM_READ_METHOD_GETSIZE 0 + +#define PARAM_WHQL_RSSI_MAX_DBM (-10) +#define PARAM_WHQL_RSSI_MIN_DBM (-200) + +#define PARAM_DEVICE_WAKE_UP_ENABLE 0x00000001 +#define PARAM_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002 +#define PARAM_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004 + +#define PARAM_WAKE_UP_MAGIC_PACKET 0x00000001 +#define PARAM_WAKE_UP_PATTERN_MATCH 0x00000002 +#define PARAM_WAKE_UP_LINK_CHANGE 0x00000004 + +/* Packet filter bit definitioin (u32 bit-wise definition) */ +#define PARAM_PACKET_FILTER_DIRECTED 0x00000001 +#define PARAM_PACKET_FILTER_MULTICAST 0x00000002 +#define PARAM_PACKET_FILTER_ALL_MULTICAST 0x00000004 +#define PARAM_PACKET_FILTER_BROADCAST 0x00000008 +#define PARAM_PACKET_FILTER_PROMISCUOUS 0x00000020 +#define PARAM_PACKET_FILTER_ALL_LOCAL 0x00000080 +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +#define PARAM_PACKET_FILTER_P2P_MASK 0xC0000000 +#define PARAM_PACKET_FILTER_PROBE_REQ 0x80000000 +#define PARAM_PACKET_FILTER_ACTION_FRAME 0x40000000 +#endif + +#define PARAM_PACKET_FILTER_SUPPORTED \ + (PARAM_PACKET_FILTER_DIRECTED | PARAM_PACKET_FILTER_MULTICAST | \ + PARAM_PACKET_FILTER_BROADCAST | PARAM_PACKET_FILTER_ALL_MULTICAST) + +#define PARAM_MEM_DUMP_MAX_SIZE 1536 + +#define BT_PROFILE_PARAM_LEN 8 + +#define EFUSE_ADDR_MAX 0x3BF /* Based on EEPROM layout 20160120 */ +#if CFG_SUPPORT_BUFFER_MODE + +/* For MT7668 */ +#define EFUSE_CONTENT_BUFFER_START 0x03A +#define EFUSE_CONTENT_BUFFER_END 0x1D9 +#define EFUSE_CONTENT_BUFFER_SIZE \ + (EFUSE_CONTENT_BUFFER_END - EFUSE_CONTENT_BUFFER_START + 1) + +#define DEFAULT_EFUSE_MACADDR_OFFSET 4 + +/* For MT6632 */ +#define EFUSE_CONTENT_SIZE 16 + +#define EFUSE_BLOCK_SIZE 16 +#define EEPROM_SIZE 1184 +#define MAX_EEPROM_BUFFER_SIZE 1200 +#endif + +#if CFG_SUPPORT_TX_BF +#define TXBF_CMD_NEED_TO_RESPONSE(u4TxBfCmdId) \ + (u4TxBfCmdId == BF_PFMU_TAG_READ || u4TxBfCmdId == BF_PROFILE_READ) +#endif +#define MU_CMD_NEED_TO_RESPONSE(u4MuCmdId) \ + (u4MuCmdId == MU_GET_CALC_INIT_MCS || u4MuCmdId == MU_HQA_GET_QD || \ + u4MuCmdId == MU_HQA_GET_CALC_LQ) +#if CFG_SUPPORT_MU_MIMO +/* @NITESH: MACROS For Init MCS calculation (MU Metric Table) */ +#define NUM_MUT_FEC 2 +#define NUM_MUT_MCS 10 +#define NUM_MUT_NR_NUM 3 +#define NUM_MUT_INDEX 8 + +#define NUM_OF_USER 2 +#define NUM_OF_MODUL 5 +#endif + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Parameters of User Configuration which match to NDIS5.1 */ +/*----------------------------------------------------------------------------*/ +/* NDIS_802_11_AUTHENTICATION_MODE */ +typedef enum _ENUM_PARAM_AUTH_MODE_T { + AUTH_MODE_OPEN, /*!< Open system */ + AUTH_MODE_SHARED, /*!< Shared key */ + AUTH_MODE_AUTO_SWITCH, /*!< Either open system or shared key */ + AUTH_MODE_WPA, + AUTH_MODE_WPA_PSK, + AUTH_MODE_WPA_NONE, /*!< For Ad hoc */ + AUTH_MODE_WPA2, + AUTH_MODE_WPA2_PSK, + AUTH_MODE_WPA2_SAE, + AUTH_MODE_NUM /*!< Upper bound, not real case */ +} ENUM_PARAM_AUTH_MODE_T, +*P_ENUM_PARAM_AUTH_MODE_T; + +/* NDIS_802_11_ENCRYPTION_STATUS */ /* Encryption types */ +typedef enum _ENUM_WEP_STATUS_T { + ENUM_WEP_ENABLED, + ENUM_ENCRYPTION1_ENABLED = ENUM_WEP_ENABLED, + ENUM_WEP_DISABLED, + ENUM_ENCRYPTION_DISABLED = ENUM_WEP_DISABLED, + ENUM_WEP_KEY_ABSENT, + ENUM_ENCRYPTION1_KEY_ABSENT = ENUM_WEP_KEY_ABSENT, + ENUM_WEP_NOT_SUPPORTED, + ENUM_ENCRYPTION_NOT_SUPPORTED = ENUM_WEP_NOT_SUPPORTED, + ENUM_ENCRYPTION2_ENABLED, + ENUM_ENCRYPTION2_KEY_ABSENT, + ENUM_ENCRYPTION3_ENABLED, + ENUM_ENCRYPTION3_KEY_ABSENT, +#if CFG_SUPPORT_SUITB + ENUM_ENCRYPTION4_ENABLED, + ENUM_ENCRYPTION4_KEY_ABSENT, +#endif + ENUM_ENCRYPTION_NUM +} ENUM_PARAM_ENCRYPTION_STATUS_T, +*P_ENUM_PARAM_ENCRYPTION_STATUS_T; + +typedef u8 PARAM_MAC_ADDRESS[PARAM_MAC_ADDR_LEN]; + +typedef u32 PARAM_KEY_INDEX; +typedef u64 PARAM_KEY_RSC; +typedef s32 PARAM_RSSI; + +typedef u32 PARAM_FRAGMENTATION_THRESHOLD; +typedef u32 PARAM_RTS_THRESHOLD; + +typedef u8 PARAM_RATES[PARAM_MAX_LEN_RATES]; +typedef u8 PARAM_RATES_EX[PARAM_MAX_LEN_RATES_EX]; + +typedef enum _ENUM_PARAM_PHY_TYPE_T { + PHY_TYPE_802_11ABG = 0, /*!< Can associated with 802.11abg AP, + * Scan dual band. + */ + PHY_TYPE_802_11BG, /*!< Can associated with 802_11bg AP, + * Scan single band and not report 802_11a BSSs. + */ + PHY_TYPE_802_11G, /*!< Can associated with 802_11g only AP, + * Scan single band and not report 802_11ab BSSs. + */ + PHY_TYPE_802_11A, /*!< Can associated with 802_11a only AP, + * Scan single band and not report 802_11bg BSSs. + */ + PHY_TYPE_802_11B, /*!< Can associated with 802_11b only AP + * Scan single band and not report 802_11ag BSSs. + */ + PHY_TYPE_NUM /* 5 */ +} ENUM_PARAM_PHY_TYPE_T, +*P_ENUM_PARAM_PHY_TYPE_T; + +typedef enum _ENUM_PARAM_OP_MODE_T { + NET_TYPE_IBSS = 0, /*!< Try to merge/establish an AdHoc, do periodic + * SCAN for merging. */ + NET_TYPE_INFRA, /*!< Try to join an Infrastructure, do periodic SCAN for + * joining. */ + NET_TYPE_AUTO_SWITCH, /*!< Try to join an Infrastructure, if fail then + * try to merge or */ + /* establish an AdHoc, do periodic SCAN for joining or merging. */ + NET_TYPE_DEDICATED_IBSS, /*!< Try to merge an AdHoc first, */ + /* if fail then establish AdHoc permanently, no more SCAN. */ + NET_TYPE_NUM /* 4 */ +} ENUM_PARAM_OP_MODE_T, +*P_ENUM_PARAM_OP_MODE_T; + +enum ENUM_CFG80211_WDEV_LOCK_FUNC { + CFG80211_RX_ASSOC_RESP = 0, + CFG80211_RX_MLME_MGMT, + CFG80211_TX_MLME_MGMT, + CFG80211_ASSOC_TIMEOUT +}; + +typedef struct _PARAM_SSID_T { + u32 u4SsidLen; /*!< SSID length in bytes. Zero length is broadcast(any) + * SSID */ + u8 aucSsid[PARAM_MAX_LEN_SSID]; +} PARAM_SSID_T, *P_PARAM_SSID_T; + +typedef struct _PARAM_CONNECT_T { + u32 u4SsidLen; /*!< SSID length in bytes. Zero length is broadcast(any) + * SSID */ + u8 *pucSsid; + u8 *pucBssid; + u32 u4CenterFreq; +} PARAM_CONNECT_T, *P_PARAM_CONNECT_T; + +/* This is enum defined for user to select an AdHoc Mode */ +typedef enum _ENUM_PARAM_AD_HOC_MODE_T { + AD_HOC_MODE_11B = 0, /*!< Create 11b IBSS if we support + * 802.11abg/802.11bg. */ + AD_HOC_MODE_MIXED_11BG, /*!< Create 11bg mixed IBSS if we support + * 802.11abg/802.11bg/802.11g. */ + AD_HOC_MODE_11G, /*!< Create 11g only IBSS if we support + * 802.11abg/802.11bg/802.11g. */ + AD_HOC_MODE_11A, /*!< Create 11a only IBSS if we support 802.11abg. */ + AD_HOC_MODE_NUM /* 4 */ +} ENUM_PARAM_AD_HOC_MODE_T, +*P_ENUM_PARAM_AD_HOC_MODE_T; + +typedef enum _ENUM_PARAM_MEDIA_STATE_T { + PARAM_MEDIA_STATE_CONNECTED, + PARAM_MEDIA_STATE_DISCONNECTED, + PARAM_MEDIA_STATE_TO_BE_INDICATED /* for following MSDN re-association + * behavior */ +} ENUM_PARAM_MEDIA_STATE_T, +*P_ENUM_PARAM_MEDIA_STATE_T; + +typedef enum _ENUM_PARAM_NETWORK_TYPE_T { + PARAM_NETWORK_TYPE_FH, + PARAM_NETWORK_TYPE_DS, + PARAM_NETWORK_TYPE_OFDM5, + PARAM_NETWORK_TYPE_OFDM24, + PARAM_NETWORK_TYPE_AUTOMODE, + PARAM_NETWORK_TYPE_NUM /*!< Upper bound, not real case */ +} ENUM_PARAM_NETWORK_TYPE_T, +*P_ENUM_PARAM_NETWORK_TYPE_T; + +typedef struct _PARAM_NETWORK_TYPE_LIST { + u32 NumberOfItems; /*!< At least 1 */ + ENUM_PARAM_NETWORK_TYPE_T eNetworkType[1]; +} PARAM_NETWORK_TYPE_LIST, *PPARAM_NETWORK_TYPE_LIST; + +typedef enum _ENUM_PARAM_PRIVACY_FILTER_T { + PRIVACY_FILTER_ACCEPT_ALL, + PRIVACY_FILTER_8021xWEP, + PRIVACY_FILTER_NUM +} ENUM_PARAM_PRIVACY_FILTER_T, +*P_ENUM_PARAM_PRIVACY_FILTER_T; + +typedef enum _ENUM_RELOAD_DEFAULTS { + ENUM_RELOAD_WEP_KEYS +} PARAM_RELOAD_DEFAULTS, +*P_PARAM_RELOAD_DEFAULTS; + +typedef struct _PARAM_PM_PACKET_PATTERN { + u32 Priority; /* Importance of the given pattern. */ + u32 Reserved; /* Context information for transports. */ + u32 MaskSize; /* Size in bytes of the pattern mask. */ + u32 PatternOffset; /* Offset from beginning of this */ + /* structure to the pattern bytes. */ + u32 PatternSize; /* Size in bytes of the pattern. */ + u32 PatternFlags; /* Flags (TBD). */ +} PARAM_PM_PACKET_PATTERN, *P_PARAM_PM_PACKET_PATTERN; + +/* Combine ucTpTestMode and ucSigmaTestMode in one flag */ +/* ucTpTestMode == 0, for normal driver */ +/* ucTpTestMode == 1, for pure throughput test mode (ex: RvR) */ +/* ucTpTestMode == 2, for sigma TGn/TGac/PMF */ +/* ucTpTestMode == 3, for sigma WMM PS */ +/* ucTpTestMode == 4, for Audio MRM mode */ +typedef enum _ENUM_TP_TEST_MODE_T { + ENUM_TP_TEST_MODE_NORMAL = 0, + ENUM_TP_TEST_MODE_THROUGHPUT, + ENUM_TP_TEST_MODE_SIGMA_AC_N_PMF, + ENUM_TP_TEST_MODE_SIGMA_WMM_PS, + ENUM_TP_TEST_MODE_AUDIO_MRM, + ENUM_TP_TEST_MODE_NUM +} ENUM_TP_TEST_MODE_T, +*P_ENUM_TP_TEST_MODE_T; + +/*--------------------------------------------------------------*/ +/*! \brief Struct definition to indicate specific event. */ +/*--------------------------------------------------------------*/ +typedef enum _ENUM_STATUS_TYPE_T { + ENUM_STATUS_TYPE_AUTHENTICATION, + ENUM_STATUS_TYPE_MEDIA_STREAM_MODE, + ENUM_STATUS_TYPE_CANDIDATE_LIST, + ENUM_STATUS_TYPE_NUM /*!< Upper bound, not real case */ +} ENUM_STATUS_TYPE_T, +*P_ENUM_STATUS_TYPE_T; + +typedef struct _PARAM_802_11_CONFIG_FH_T { + u32 u4Length; /*!< Length of structure */ + u32 u4HopPattern; /*!< Defined as 802.11 */ + u32 u4HopSet; /*!< to one if non-802.11 */ + u32 u4DwellTime; /*!< In unit of Kusec */ +} PARAM_802_11_CONFIG_FH_T, *P_PARAM_802_11_CONFIG_FH_T; + +typedef struct _PARAM_802_11_CONFIG_T { + u32 u4Length; /*!< Length of structure */ + u32 u4BeaconPeriod; /*!< In unit of Kusec */ + u32 u4ATIMWindow; /*!< In unit of Kusec */ + u32 u4DSConfig; /*!< Channel frequency in unit of kHz */ + PARAM_802_11_CONFIG_FH_T rFHConfig; +} PARAM_802_11_CONFIG_T, *P_PARAM_802_11_CONFIG_T; + +typedef struct _PARAM_STATUS_INDICATION_T { + ENUM_STATUS_TYPE_T eStatusType; +} PARAM_STATUS_INDICATION_T, *P_PARAM_STATUS_INDICATION_T; + +typedef struct _PARAM_AUTH_REQUEST_T { + u32 u4Length; /*!< Length of this struct */ + PARAM_MAC_ADDRESS arBssid; + u32 u4Flags; /*!< Definitions are as follows */ +} PARAM_AUTH_REQUEST_T, *P_PARAM_AUTH_REQUEST_T; + +typedef struct _PARAM_AUTH_EVENT_T { + PARAM_STATUS_INDICATION_T rStatus; + PARAM_AUTH_REQUEST_T arRequest[1]; +} PARAM_AUTH_EVENT_T, *P_PARAM_AUTH_EVENT_T; + +/*! \brief Capabilities, privacy, rssi and IEs of each BSSID */ +typedef struct _PARAM_BSSID_EX_T { + u32 u4Length; /*!< Length of structure */ + PARAM_MAC_ADDRESS arMacAddress; /*!< BSSID */ + u8 Reserved[2]; + PARAM_SSID_T rSsid; /*!< SSID */ + u32 u4Privacy; /*!< Need WEP encryption */ + PARAM_RSSI rRssi; /*!< in dBm */ + ENUM_PARAM_NETWORK_TYPE_T eNetworkTypeInUse; + PARAM_802_11_CONFIG_T rConfiguration; + ENUM_PARAM_OP_MODE_T eOpMode; + PARAM_RATES_EX rSupportedRates; + u32 u4IELength; + u8 aucIEs[1]; +} PARAM_BSSID_EX_T, *P_PARAM_BSSID_EX_T; + +typedef struct _PARAM_BSSID_LIST_EX { + u32 u4NumberOfItems; /*!< at least 1 */ + PARAM_BSSID_EX_T arBssid[1]; +} PARAM_BSSID_LIST_EX_T, *P_PARAM_BSSID_LIST_EX_T; + +typedef struct _PARAM_WEP_T { + u32 u4Length; /*!< Length of structure */ + u32 u4KeyIndex; /*!< 0: pairwise key, others group keys */ + u32 u4KeyLength; /*!< Key length in bytes */ + u8 aucKeyMaterial[32]; /*!< Key content by above setting */ +} PARAM_WEP_T, *P_PARAM_WEP_T; + +/*! \brief Key mapping of BSSID */ +typedef struct _PARAM_KEY_T { + u32 u4Length; /*!< Length of structure */ + u32 u4KeyIndex; /*!< KeyID */ + u32 u4KeyLength; /*!< Key length in bytes */ + PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ + PARAM_KEY_RSC rKeyRSC; + u8 ucBssIdx; + u8 ucCipher; + u8 aucKeyMaterial[32]; /*!< Key content by above setting */ + /* Following add to change the original windows structure */ +} PARAM_KEY_T, *P_PARAM_KEY_T; + +/* for more remove key control (ucCtrlFlag) */ +#define FLAG_RM_KEY_CTRL_WO_OID BIT(0) /* not OID operation */ + +typedef struct _PARAM_REMOVE_KEY_T { + u32 u4Length; /*!< Length of structure */ + u32 u4KeyIndex; /*!< KeyID */ + PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ + u8 ucBssIdx; + u8 ucCtrlFlag; /* Ctrl Flag for RM key CMD */ +} PARAM_REMOVE_KEY_T, *P_PARAM_REMOVE_KEY_T; + +/*! \brief Default key */ +typedef struct _PARAM_DEFAULT_KEY_T { + u8 ucKeyID; + u8 ucUnicast; + u8 ucMulticast; + u8 ucBssIdx; +} PARAM_DEFAULT_KEY_T, *P_PARAM_DEFAULT_KEY_T; + +typedef enum _PARAM_POWER_MODE { + Param_PowerModeCAM, + Param_PowerModeMAX_PSP, + Param_PowerModeFast_PSP, +#ifdef SUPPORT_PERIODIC_PS + Param_PowerModePeriodic_PSP, +#endif + Param_PowerModeMax /* Upper bound, not real case */ +} PARAM_POWER_MODE, +*PPARAM_POWER_MODE; + +typedef enum _PARAM_DEVICE_POWER_STATE { + ParamDeviceStateUnspecified = 0, + ParamDeviceStateD0, + ParamDeviceStateD1, + ParamDeviceStateD2, + ParamDeviceStateD3, + ParamDeviceStateMaximum +} PARAM_DEVICE_POWER_STATE, +*PPARAM_DEVICE_POWER_STATE; + +#if CFG_SUPPORT_FW_DBG_LEVEL_CTRL +/* FW debug control level related definition and enumerations */ +#define FW_DBG_LEVEL_DONT_SET 0 +#define FW_DBG_LEVEL_ERROR (1 << 0) +#define FW_DBG_LEVEL_WARN (1 << 1) +#define FW_DBG_LEVEL_STATE (1 << 2) +#define FW_DBG_LEVEL_INFO (1 << 3) +#define FW_DBG_LEVEL_LOUD (1 << 4) +#endif + +typedef struct _PARAM_POWER_MODE_T { + u8 ucBssIdx; + PARAM_POWER_MODE ePowerMode; +} PARAM_POWER_MODE_T, *P_PARAM_POWER_MODE_T; + +#if CFG_SUPPORT_802_11D + +/*! \brief The enumeration definitions for OID_IPN_MULTI_DOMAIN_CAPABILITY */ +typedef enum _PARAM_MULTI_DOMAIN_CAPABILITY { + ParamMultiDomainCapDisabled, + ParamMultiDomainCapEnabled +} PARAM_MULTI_DOMAIN_CAPABILITY, +*P_PARAM_MULTI_DOMAIN_CAPABILITY; +#endif + +typedef struct _COUNTRY_STRING_ENTRY { + u8 aucCountryCode[2]; + u8 aucEnvironmentCode[2]; +} COUNTRY_STRING_ENTRY, *P_COUNTRY_STRING_ENTRY; + +/* Power management related definition and enumerations */ +#define UAPSD_NONE 0 +#define UAPSD_AC0 (BIT(0) | BIT(4)) +#define UAPSD_AC1 (BIT(1) | BIT(5)) +#define UAPSD_AC2 (BIT(2) | BIT(6)) +#define UAPSD_AC3 (BIT(3) | BIT(7)) +#define UAPSD_ALL (UAPSD_AC0 | UAPSD_AC1 | UAPSD_AC2 | UAPSD_AC3) + +typedef enum _ENUM_POWER_SAVE_PROFILE_T { + ENUM_PSP_CONTINUOUS_ACTIVE = 0, + ENUM_PSP_CONTINUOUS_POWER_SAVE, + ENUM_PSP_FAST_SWITCH, + ENUM_PSP_NUM +} ENUM_POWER_SAVE_PROFILE_T, +*PENUM_POWER_SAVE_PROFILE_T; + +/*--------------------------------------------------------------*/ +/*! \brief Set/Query testing type. */ +/*--------------------------------------------------------------*/ +typedef struct _PARAM_802_11_TEST_T { + u32 u4Length; + u32 u4Type; + union { + PARAM_AUTH_EVENT_T AuthenticationEvent; + PARAM_RSSI RssiTrigger; + } u; +} PARAM_802_11_TEST_T, *P_PARAM_802_11_TEST_T; + +/*--------------------------------------------------------------*/ +/*! \brief Set/Query authentication and encryption capability. */ +/*--------------------------------------------------------------*/ +typedef struct _PARAM_AUTH_ENCRYPTION_T { + ENUM_PARAM_AUTH_MODE_T eAuthModeSupported; + ENUM_PARAM_ENCRYPTION_STATUS_T eEncryptStatusSupported; +} PARAM_AUTH_ENCRYPTION_T, *P_PARAM_AUTH_ENCRYPTION_T; + +typedef struct _PARAM_CAPABILITY_T { + u32 u4Length; + u32 u4Version; + u32 u4NoOfPMKIDs; + u32 u4NoOfAuthEncryptPairsSupported; + PARAM_AUTH_ENCRYPTION_T arAuthenticationEncryptionSupported[1]; +} PARAM_CAPABILITY_T, *P_PARAM_CAPABILITY_T; + +typedef u8 PARAM_PMKID_VALUE[16]; + +typedef struct _PARAM_BSSID_INFO_T { + PARAM_MAC_ADDRESS arBSSID; + PARAM_PMKID_VALUE arPMKID; +} PARAM_BSSID_INFO_T, *P_PARAM_BSSID_INFO_T; + +typedef struct _PARAM_PMKID_T { + u32 u4Length; + u32 u4BSSIDInfoCount; + PARAM_BSSID_INFO_T arBSSIDInfo[1]; +} PARAM_PMKID_T, *P_PARAM_PMKID_T; + +/*! \brief PMKID candidate lists. */ +typedef struct _PARAM_PMKID_CANDIDATE_T { + PARAM_MAC_ADDRESS arBSSID; + u32 u4Flags; +} PARAM_PMKID_CANDIDATE_T, *P_PARAM_PMKID_CANDIDATE_T; + +typedef struct _PARAM_PMKID_CANDIDATE_LIST_T { + u32 u4Version; /*!< Version */ + u32 u4NumCandidates; /*!< How many candidates follow */ + PARAM_PMKID_CANDIDATE_T arCandidateList[1]; +} PARAM_PMKID_CANDIDATE_LIST_T, *P_PARAM_PMKID_CANDIDATE_LIST_T; + +#define NL80211_KCK_LEN 16 +#define NL80211_KEK_LEN 16 +#define NL80211_REPLAY_CTR_LEN 8 +#define NL80211_KEYRSC_LEN 8 + +typedef struct _PARAM_GTK_REKEY_DATA { + u8 aucKek[NL80211_KEK_LEN]; + u8 aucKck[NL80211_KCK_LEN]; + u8 aucReplayCtr[NL80211_REPLAY_CTR_LEN]; + u8 ucBssIndex; + u8 ucRekeyMode; + u8 ucCurKeyId; + u8 ucRsv; + u32 u4Proto; + u32 u4PairwiseCipher; + u32 u4GroupCipher; + u32 u4KeyMgmt; + u32 u4MgmtGroupCipher; +} PARAM_GTK_REKEY_DATA, *P_PARAM_GTK_REKEY_DATA; + +typedef struct _PARAM_CUSTOM_MCR_RW_STRUCT_T { + u32 u4McrOffset; + u32 u4McrData; +} PARAM_CUSTOM_MCR_RW_STRUCT_T, *P_PARAM_CUSTOM_MCR_RW_STRUCT_T; + +/* CMD_COEX_CTRL & EVENT_COEX_CTRL */ +/************************************************/ +/* u32 u4SubCmd : Coex Ctrl Sub Command */ +/* u8 aucBuffer : Reserve for Sub Command */ +/* Data Structure */ +/************************************************/ +struct PARAM_COEX_CTRL { + u32 u4SubCmd; + u8 aucBuffer[64]; +}; + +/* Isolation Structure */ +/************************************************/ +/* u32 u4IsoPath : WF Path (WF0/WF1) */ +/* u32 u4Channel : WF Channel */ +/* u32 u4Band : WF Band (Band0/Band1)(Not used now) */ +/* u32 u4Isolation : Isolation value */ +/************************************************/ +struct PARAM_COEX_ISO_DETECT { + u32 u4IsoPath; + u32 u4Channel; + /*u32 u4Band;*/ + u32 u4Isolation; +}; + +#if CFG_SUPPORT_QA_TOOL +#if CFG_SUPPORT_BUFFER_MODE +typedef struct _BIN_CONTENT_T { + u16 u2Addr; + u8 ucValue; + u8 ucReserved; +} BIN_CONTENT_T, *P_BIN_CONTENT_T; + +typedef struct _PARAM_CUSTOM_EFUSE_BUFFER_MODE_T { + u8 ucSourceMode; + u8 ucCount; + u8 ucCmdType; + u8 ucReserved; + u8 aBinContent[MAX_EEPROM_BUFFER_SIZE]; +} PARAM_CUSTOM_EFUSE_BUFFER_MODE_T, *P_PARAM_CUSTOM_EFUSE_BUFFER_MODE_T; + +/*#if (CFG_EEPROM_PAGE_ACCESS == 1)*/ +typedef struct _PARAM_CUSTOM_ACCESS_EFUSE_T { + u32 u4Address; + u32 u4Valid; + u8 aucData[16]; +} PARAM_CUSTOM_ACCESS_EFUSE_T, *P_PARAM_CUSTOM_ACCESS_EFUSE_T; + +typedef struct _PARAM_CUSTOM_EFUSE_FREE_BLOCK_T { + u8 ucGetFreeBlock; + u8 aucReserved[3]; +} PARAM_CUSTOM_EFUSE_FREE_BLOCK_T, *P_PARAM_CUSTOM_EFUSE_FREE_BLOCK_T; + +typedef struct _PARAM_CUSTOM_GET_TX_POWER_T { + u8 ucTxPwrType; + u8 ucCenterChannel; + u8 ucDbdcIdx; /* 0:Band 0, 1: Band1 */ + u8 ucBand; /* 0:G-band 1: A-band*/ + u8 ucReserved[4]; +} PARAM_CUSTOM_GET_TX_POWER_T, *P_PARAM_CUSTOM_GET_TX_POWER_T; + +/*#endif*/ + +#endif + +typedef struct _PARAM_CUSTOM_SET_TX_TARGET_POWER_T { + s8 cTxPwr2G4Cck; /* signed, in unit of 0.5dBm */ + s8 cTxPwr2G4Dsss; /* signed, in unit of 0.5dBm */ + u8 ucTxTargetPwr; /* Tx target power base for all*/ + u8 ucReserved; + + s8 cTxPwr2G4OFDM_BPSK; + s8 cTxPwr2G4OFDM_QPSK; + s8 cTxPwr2G4OFDM_16QAM; + s8 cTxPwr2G4OFDM_Reserved; + s8 cTxPwr2G4OFDM_48Mbps; + s8 cTxPwr2G4OFDM_54Mbps; + + s8 cTxPwr2G4HT20_BPSK; + s8 cTxPwr2G4HT20_QPSK; + s8 cTxPwr2G4HT20_16QAM; + s8 cTxPwr2G4HT20_MCS5; + s8 cTxPwr2G4HT20_MCS6; + s8 cTxPwr2G4HT20_MCS7; + + s8 cTxPwr2G4HT40_BPSK; + s8 cTxPwr2G4HT40_QPSK; + s8 cTxPwr2G4HT40_16QAM; + s8 cTxPwr2G4HT40_MCS5; + s8 cTxPwr2G4HT40_MCS6; + s8 cTxPwr2G4HT40_MCS7; + + s8 cTxPwr5GOFDM_BPSK; + s8 cTxPwr5GOFDM_QPSK; + s8 cTxPwr5GOFDM_16QAM; + s8 cTxPwr5GOFDM_Reserved; + s8 cTxPwr5GOFDM_48Mbps; + s8 cTxPwr5GOFDM_54Mbps; + + s8 cTxPwr5GHT20_BPSK; + s8 cTxPwr5GHT20_QPSK; + s8 cTxPwr5GHT20_16QAM; + s8 cTxPwr5GHT20_MCS5; + s8 cTxPwr5GHT20_MCS6; + s8 cTxPwr5GHT20_MCS7; + + s8 cTxPwr5GHT40_BPSK; + s8 cTxPwr5GHT40_QPSK; + s8 cTxPwr5GHT40_16QAM; + s8 cTxPwr5GHT40_MCS5; + s8 cTxPwr5GHT40_MCS6; + s8 cTxPwr5GHT40_MCS7; +} PARAM_CUSTOM_SET_TX_TARGET_POWER_T, *P_PARAM_CUSTOM_SET_TX_TARGET_POWER_T; + +#if (CFG_SUPPORT_DFS_MASTER == 1) +typedef struct _PARAM_CUSTOM_SET_RDD_REPORT_T { + u8 ucDbdcIdx; /* 0:Band 0, 1: Band1 */ +} PARAM_CUSTOM_SET_RDD_REPORT_T, *P_PARAM_CUSTOM_SET_RDD_REPORT_T; + +struct PARAM_CUSTOM_SET_RADAR_DETECT_MODE { + u8 ucRadarDetectMode; /* 0:Switch channel, 1: Don't switch channel */ +}; +#endif + +typedef struct _PARAM_CUSTOM_ACCESS_RX_STAT { + u32 u4SeqNum; + u32 u4TotalNum; +} PARAM_CUSTOM_ACCESS_RX_STAT, *P_PARAM_CUSTOM_ACCESS_RX_STAT; + +/* Ext DevInfo Tag */ +typedef enum _EXT_ENUM_DEVINFO_TAG_HANDLE_T { + DEV_INFO_ACTIVE = 0, + DEV_INFO_BSSID, + DEV_INFO_MAX_NUM +} EXT_ENUM_TAG_DEVINFO_HANDLE_T; + +/* STA record TLV tag */ +typedef enum _EXT_ENUM_STAREC_TAG_HANDLE_T { + STA_REC_BASIC = 0, + STA_REC_RA, + STA_REC_RA_COMMON_INFO, + STA_REC_RA_UPDATE, + STA_REC_BF, + STA_REC_MAUNAL_ASSOC, + STA_REC_BA = 6, + STA_REC_MAX_NUM +} EXT_ENUM_TAG_STAREC_HANDLE_T; + +#if CFG_SUPPORT_TX_BF +typedef enum _BF_ACTION_CATEGORY { + BF_SOUNDING_OFF = 0, + BF_SOUNDING_ON, + BF_HW_CTRL, + BF_DATA_PACKET_APPLY, + BF_PFMU_MEM_ALLOCATE, + BF_PFMU_MEM_RELEASE, + BF_PFMU_TAG_READ, + BF_PFMU_TAG_WRITE, + BF_PROFILE_READ, + BF_PROFILE_WRITE, + BF_PN_READ, + BF_PN_WRITE, + BF_PFMU_MEM_ALLOC_MAP_READ +} BF_ACTION_CATEGORY; + +enum { + DEVINFO_ACTIVE = 0, + DEVINFO_MAX_NUM = 1, +}; + +enum { + DEVINFO_ACTIVE_FEATURE = (1 << DEVINFO_ACTIVE), + DEVINFO_MAX_NUM_FEATURE = (1 << DEVINFO_MAX_NUM) +}; + +enum { + BSS_INFO_OWN_MAC = 0, + BSS_INFO_BASIC = 1, + BSS_INFO_RF_CH = 2, + BSS_INFO_PM = 3, + BSS_INFO_UAPSD = 4, + BSS_INFO_ROAM_DETECTION = 5, + BSS_INFO_LQ_RM = 6, + BSS_INFO_EXT_BSS = 7, + BSS_INFO_BROADCAST_INFO = 8, + BSS_INFO_SYNC_MODE = 9, + BSS_INFO_MAX_NUM +}; + +typedef union _PFMU_PROFILE_TAG1 { + struct { + u32 ucProfileID : 7; /* [6:0] : 0 ~ 63 */ + u32 ucTxBf : 1; /* [7] : 0: iBF, 1: eBF */ + u32 ucDBW : 2; /* [9:8] : 0/1/2/3: DW20/40/80/160NC */ + u32 ucSU_MU : 1; /* [10] : 0:SU, 1: MU */ + u32 ucInvalidProf : 1; /* [11] : 0:default, 1: This profile + * number is invalid by SW */ + u32 ucRMSD : 3; /* [14:12] : RMSD value from CE */ + u32 ucMemAddr1ColIdx : 3; /* [17 : 15] : column index : 0 ~ 5 */ + u32 ucMemAddr1RowIdx : 6; /* [23 : 18] : row index : 0 ~ 63 */ + u32 ucMemAddr2ColIdx : 3; /* [26 : 24] : column index : 0 ~ 5 */ + u32 ucMemAddr2RowIdx : 5; /* [31 : 27] : row index : 0 ~ 63 */ + u32 ucMemAddr2RowIdxMsb : 1; /* [32] : MSB of row index */ + u32 ucMemAddr3ColIdx : 3; /* [35 : 33] : column index : 0 ~ 5 */ + u32 ucMemAddr3RowIdx : 6; /* [41 : 36] : row index : 0 ~ 63 */ + u32 ucMemAddr4ColIdx : 3; /* [44 : 42] : column index : 0 ~ 5 */ + u32 ucMemAddr4RowIdx : 6; /* [50 : 45] : row index : 0 ~ 63 */ + u32 ucReserved : 1; /* [51] : Reserved */ + u32 ucNrow : 2; /* [53 : 52] : Nrow */ + u32 ucNcol : 2; /* [55 : 54] : Ncol */ + u32 ucNgroup : 2; /* [57 : 56] : Ngroup */ + u32 ucLM : 2; /* [59 : 58] : 0/1/2 */ + u32 ucCodeBook : 2; /* [61:60] : Code book */ + u32 ucHtcExist : 1; /* [62] : HtcExist */ + u32 ucReserved1 : 1; /* [63] : Reserved */ + u32 ucSNR_STS0 : 8; /* [71:64] : SNR_STS0 */ + u32 ucSNR_STS1 : 8; /* [79:72] : SNR_STS1 */ + u32 ucSNR_STS2 : 8; /* [87:80] : SNR_STS2 */ + u32 ucSNR_STS3 : 8; /* [95:88] : SNR_STS3 */ + u32 ucIBfLnaIdx : 8; /* [103:96] : iBF LNA index */ + } rField; + u32 au4RawData[4]; +} PFMU_PROFILE_TAG1, *P_PFMU_PROFILE_TAG1; + +typedef union _PFMU_PROFILE_TAG2 { + struct { + u32 u2SmartAnt : 12; /* [11:0] : Smart Ant config */ + u32 ucReserved0 : 3; /* [14:12] : Reserved */ + u32 ucSEIdx : 5; /* [19:15] : SE index */ + u32 ucRMSDThd : 3; /* [22:20] : RMSD Threshold */ + u32 ucReserved1 : 1; /* [23] : Reserved */ + u32 ucMCSThL1SS : 4; /* [27:24] : MCS TH long 1SS */ + u32 ucMCSThS1SS : 4; /* [31:28] : MCS TH short 1SS */ + u32 ucMCSThL2SS : 4; /* [35:32] : MCS TH long 2SS */ + u32 ucMCSThS2SS : 4; /* [39:36] : MCS TH short 2SS */ + u32 ucMCSThL3SS : 4; /* [43:40] : MCS TH long 3SS */ + u32 ucMCSThS3SS : 4; /* [47:44] : MCS TH short 3SS */ + u32 uciBfTimeOut : 8; /* [55:48] : iBF timeout limit */ + u32 ucReserved2 : 8; /* [63:56] : Reserved */ + u32 ucReserved3 : 8; /* [71:64] : Reserved */ + u32 ucReserved4 : 8; /* [79:72] : Reserved */ + u32 uciBfDBW : 2; /* [81:80] : iBF desired DBW 0/1/2/3 : + * BW20/40/80/160NC */ + u32 uciBfNcol : 2; /* [83:82] : iBF desired Ncol = 1 ~ 3 */ + u32 uciBfNrow : 2; /* [85:84] : iBF desired Nrow = 1 ~ 4 */ + u32 u2Reserved5 : 10; /* [95:86] : Reserved */ + } rField; + u32 au4RawData[3]; +} PFMU_PROFILE_TAG2, *P_PFMU_PROFILE_TAG2; + +typedef union _PFMU_DATA { + struct { + u32 u2Phi11 : 9; + u32 ucPsi21 : 7; + u32 u2Phi21 : 9; + u32 ucPsi31 : 7; + u32 u2Phi31 : 9; + u32 ucPsi41 : 7; + u32 u2Phi22 : 9; + u32 ucPsi32 : 7; + u32 u2Phi32 : 9; + u32 ucPsi42 : 7; + u32 u2Phi33 : 9; + u32 ucPsi43 : 7; + u32 u2dSNR00 : 4; + u32 u2dSNR01 : 4; + u32 u2dSNR02 : 4; + u32 u2dSNR03 : 4; + u32 u2Reserved : 16; + } rField; + u32 au4RawData[5]; +} PFMU_DATA, *P_PFMU_DATA; + +typedef struct _PROFILE_TAG_READ_T { + u8 ucTxBfCategory; + u8 ucProfileIdx; + u8 fgBfer; + u8 ucRsv; +} PROFILE_TAG_READ_T, *P_PROFILE_TAG_READ_T; + +typedef struct _PROFILE_TAG_WRITE_T { + u8 ucTxBfCategory; + u8 ucPfmuId; + u8 ucBuffer[28]; +} PROFILE_TAG_WRITE_T, *P_PROFILE_TAG_WRITE_T; + +typedef struct _PROFILE_DATA_READ_T { + u8 ucTxBfCategory; + u8 ucPfmuIdx; + u8 fgBFer; + u8 ucReserved[3]; + u8 ucSubCarrIdxLsb; + u8 ucSubCarrIdxMsb; +} PROFILE_DATA_READ_T, *P_PROFILE_DATA_READ_T; + +typedef struct _PROFILE_DATA_WRITE_T { + u8 ucTxBfCategory; + u8 ucPfmuIdx; + u8 u2SubCarrIdxLsb; + u8 u2SubCarrIdxMsb; + PFMU_DATA rTxBfPfmuData; +} PROFILE_DATA_WRITE_T, *P_PROFILE_DATA_WRITE_T; + +typedef struct _PROFILE_PN_READ_T { + u8 ucTxBfCategory; + u8 ucPfmuIdx; + u8 ucReserved[2]; +} PROFILE_PN_READ_T, *P_PROFILE_PN_READ_T; + +typedef struct _PROFILE_PN_WRITE_T { + u8 ucTxBfCategory; + u8 ucPfmuIdx; + u16 u2bw; + u8 ucBuf[32]; +} PROFILE_PN_WRITE_T, *P_PROFILE_PN_WRITE_T; + +typedef enum _BF_SOUNDING_MODE { + SU_SOUNDING = 0, + MU_SOUNDING, + SU_PERIODIC_SOUNDING, + MU_PERIODIC_SOUNDING, + AUTO_SU_PERIODIC_SOUNDING +} BF_SOUNDING_MODE; + +typedef struct _EXT_CMD_ETXBf_SND_PERIODIC_TRIGGER_CTRL_T { + u8 ucCmdCategoryID; + u8 ucSuMuSndMode; + u8 ucWlanIdx; + u32 u4SoundingInterval; /* By ms */ +} EXT_CMD_ETXBf_SND_PERIODIC_TRIGGER_CTRL_T, +*P_EXT_CMD_ETXBf_SND_PERIODIC_TRIGGER_CTRL_T; + +typedef struct _EXT_CMD_ETXBf_MU_SND_PERIODIC_TRIGGER_CTRL_T { + u8 ucCmdCategoryID; + u8 ucSuMuSndMode; + u8 ucWlanId[4]; + u8 ucStaNum; + u32 u4SoundingInterval; /* By ms */ +} EXT_CMD_ETXBf_MU_SND_PERIODIC_TRIGGER_CTRL_T, +*P_EXT_CMD_ETXBf_MU_SND_PERIODIC_TRIGGER_CTRL_T; + +/* Device information (Tag0) */ +typedef struct _CMD_DEVINFO_ACTIVE_T { + u16 u2Tag; /* Tag = 0x00 */ + u16 u2Length; + u8 ucActive; + u8 ucBandNum; + u8 aucOwnMacAddr[6]; + u8 aucReserve[4]; +} CMD_DEVINFO_ACTIVE_T, *P_CMD_DEVINFO_ACTIVE_T; + +typedef struct _BSSINFO_BASIC_T { + /* Basic BSS information (Tag1) */ + u16 u2Tag; /* Tag = 0x01 */ + u16 u2Length; + u32 u4NetworkType; + u8 ucActive; + u8 ucReserve0; + u16 u2BcnInterval; + u8 aucBSSID[6]; + u8 ucWmmIdx; + u8 ucDtimPeriod; + u8 ucBcMcWlanidx; /* indicate which wlan-idx used for MC/BC + * transmission. */ + u8 ucCipherSuit; + u8 acuReserve[6]; +} CMD_BSSINFO_BASIC_T, *P_CMD_BSSINFO_BASIC_T; + +typedef struct _TXBF_PFMU_STA_INFO { + u16 u2PfmuId; /* 0xFFFF means no access right for PFMU */ + u8 fgSU_MU; /* 0 : SU, 1 : MU */ + u8 fgETxBfCap; /* 0 : ITxBf, 1 : ETxBf */ + u8 ucSoundingPhy; /* 0: legacy, 1: OFDM, 2: HT, 4: VHT */ + u8 ucNdpaRate; + u8 ucNdpRate; + u8 ucReptPollRate; + u8 ucTxMode; /* 0: legacy, 1: OFDM, 2: HT, 4: VHT */ + u8 ucNc; + u8 ucNr; + u8 ucCBW; /* 0 : 20M, 1 : 40M, 2 : 80M, 3 : 80 + 80M */ + u8 ucTotMemRequire; + u8 ucMemRequire20M; + u8 ucMemRow0; + u8 ucMemCol0; + u8 ucMemRow1; + u8 ucMemCol1; + u8 ucMemRow2; + u8 ucMemCol2; + u8 ucMemRow3; + u8 ucMemCol3; + u16 u2SmartAnt; + u8 ucSEIdx; + u8 uciBfTimeOut; + u8 uciBfDBW; + u8 uciBfNcol; + u8 uciBfNrow; + u8 aucReserved[3]; +} TXBF_PFMU_STA_INFO, *P_TXBF_PFMU_STA_INFO; + +typedef struct _STA_REC_UPD_ENTRY_T { + TXBF_PFMU_STA_INFO rTxBfPfmuStaInfo; + u8 aucAddr[PARAM_MAC_ADDR_LEN]; + u8 ucAid; + u8 ucRsv; +} STA_REC_UPD_ENTRY_T, *P_STA_REC_UPD_ENTRY_T; + +typedef struct _STAREC_COMMON_T { + /* Basic STA record (Group0) */ + u16 u2Tag; /* Tag = 0x00 */ + u16 u2Length; + u32 u4ConnectionType; + u8 ucConnectionState; + u8 ucIsQBSS; + u16 u2AID; + u8 aucPeerMacAddr[6]; + u16 u2Reserve1; +} CMD_STAREC_COMMON_T, *P_CMD_STAREC_COMMON_T; + +typedef struct _CMD_STAREC_BF { + u16 u2Tag; /* Tag = 0x02 */ + u16 u2Length; + TXBF_PFMU_STA_INFO rTxBfPfmuInfo; + u8 ucReserved[3]; +} CMD_STAREC_BF, *P_CMD_STAREC_BF; + +/* QA tool: maunal assoc */ +typedef struct _CMD_MANUAL_ASSOC_STRUCT_T { + /* + * u8 ucBssIndex; + * u8 ucWlanIdx; + * u16 u2TotalElementNum; + * u32 u4Reserve; + */ + /* extension */ + u16 u2Tag; /* Tag = 0x05 */ + u16 u2Length; + u8 aucMac[MAC_ADDR_LEN]; + u8 ucType; + u8 ucWtbl; + u8 ucOwnmac; + u8 ucMode; + u8 ucBw; + u8 ucNss; + u8 ucPfmuId; + u8 ucMarate; + u8 ucSpeIdx; + u8 ucaid; +} CMD_MANUAL_ASSOC_STRUCT_T, *P_CMD_MANUAL_ASSOC_STRUCT_T; + +typedef struct _TX_BF_SOUNDING_START_T { + union { + EXT_CMD_ETXBf_SND_PERIODIC_TRIGGER_CTRL_T + rExtCmdExtBfSndPeriodicTriggerCtrl; + EXT_CMD_ETXBf_MU_SND_PERIODIC_TRIGGER_CTRL_T + rExtCmdExtBfMuSndPeriodicTriggerCtrl; + } rTxBfSounding; +} TX_BF_SOUNDING_START_T, *P_TX_BF_SOUNDING_START_T; + +typedef struct _TX_BF_SOUNDING_STOP_T { + u8 ucTxBfCategory; + u8 ucSndgStop; + u8 ucReserved[2]; +} TX_BF_SOUNDING_STOP_T, *P_TX_BF_SOUNDING_STOP_T; + +typedef struct _TX_BF_TX_APPLY_T { + u8 ucTxBfCategory; + u8 ucWlanId; + u8 fgETxBf; + u8 fgITxBf; + u8 fgMuTxBf; + u8 ucReserved[3]; +} TX_BF_TX_APPLY_T, *P_TX_BF_TX_APPLY_T; + +typedef struct _TX_BF_PFMU_MEM_ALLOC_T { + u8 ucTxBfCategory; + u8 ucSuMuMode; + u8 ucWlanIdx; + u8 ucReserved; +} TX_BF_PFMU_MEM_ALLOC_T, *P_TX_BF_PFMU_MEM_ALLOC_T; + +typedef struct _TX_BF_PFMU_MEM_RLS_T { + u8 ucTxBfCategory; + u8 ucWlanId; + u8 ucReserved[2]; +} TX_BF_PFMU_MEM_RLS_T, *P_TX_BF_PFMU_MEM_RLS_T; + +typedef union _PARAM_CUSTOM_TXBF_ACTION_STRUCT_T { + PROFILE_TAG_READ_T rProfileTagRead; + PROFILE_TAG_WRITE_T rProfileTagWrite; + PROFILE_DATA_READ_T rProfileDataRead; + PROFILE_DATA_WRITE_T rProfileDataWrite; + PROFILE_PN_READ_T rProfilePnRead; + PROFILE_PN_WRITE_T rProfilePnWrite; + TX_BF_SOUNDING_START_T rTxBfSoundingStart; + TX_BF_SOUNDING_STOP_T rTxBfSoundingStop; + TX_BF_TX_APPLY_T rTxBfTxApply; + TX_BF_PFMU_MEM_ALLOC_T rTxBfPfmuMemAlloc; + TX_BF_PFMU_MEM_RLS_T rTxBfPfmuMemRls; +} PARAM_CUSTOM_TXBF_ACTION_STRUCT_T, *P_PARAM_CUSTOM_TXBF_ACTION_STRUCT_T; + +typedef struct _PARAM_CUSTOM_STA_REC_UPD_STRUCT_T { + u8 ucBssIndex; + u8 ucWlanIdx; + u16 u2TotalElementNum; + u8 ucAppendCmdTLV; + u8 ucMuarIdx; + u8 aucReserve[2]; + u32 *prStaRec; + CMD_STAREC_BF rCmdStaRecBf; +} PARAM_CUSTOM_STA_REC_UPD_STRUCT_T, *P_PARAM_CUSTOM_STA_REC_UPD_STRUCT_T; + +typedef struct _BSSINFO_ARGUMENT_T { + u8 OwnMacIdx; + u8 ucBssIndex; + u8 Bssid[PARAM_MAC_ADDR_LEN]; + u8 ucBcMcWlanIdx; + u8 ucPeerWlanIdx; + u32 NetworkType; + u32 u4ConnectionType; + u8 CipherSuit; + u8 Active; + u8 WmmIdx; + u32 u4BssInfoFeature; + u8 aucBuffer[0]; +} BSSINFO_ARGUMENT_T, *P_BSSINFO_ARGUMENT_T; + +typedef struct _PARAM_CUSTOM_PFMU_TAG_READ_STRUCT_T { + PFMU_PROFILE_TAG1 ru4TxBfPFMUTag1; + PFMU_PROFILE_TAG2 ru4TxBfPFMUTag2; +} PARAM_CUSTOM_PFMU_TAG_READ_STRUCT_T, *P_PARAM_CUSTOM_PFMU_TAG_READ_STRUCT_T; + +#if CFG_SUPPORT_MU_MIMO +typedef struct _PARAM_CUSTOM_SHOW_GROUP_TBL_ENTRY_STRUCT_T { + u32 u4EventId; + u8 index; + u8 numUser : 2; + u8 BW : 2; + u8 NS0 : 2; + u8 NS1 : 2; + /* u8 NS2:1; */ + /* u8 NS3:1; */ + u8 PFIDUser0; + u8 PFIDUser1; + /* u8 PFIDUser2; */ + /* u8 PFIDUser3; */ + u8 fgIsShortGI; + u8 fgIsUsed; + u8 fgIsDisable; + u8 initMcsUser0 : 4; + u8 initMcsUser1 : 4; + /* u8 initMcsUser2:4; */ + /* u8 initMcsUser3:4; */ + u8 dMcsUser0 : 4; + u8 dMcsUser1 : 4; + /* u8 dMcsUser2:4; */ + /* u8 dMcsUser3:4; */ +} PARAM_CUSTOM_SHOW_GROUP_TBL_ENTRY_STRUCT_T, +*P_PARAM_CUSTOM_SHOW_GROUP_TBL_ENTRY_STRUCT_T; + +typedef struct _PARAM_CUSTOM_GET_QD_STRUCT_T { + u32 u4EventId; + u32 au4RawData[14]; +} PARAM_CUSTOM_GET_QD_STRUCT_T, *P_PARAM_CUSTOM_GET_QD_STRUCT_T; + +typedef struct _MU_STRUCT_LQ_REPORT { + int lq_report[NUM_OF_USER][NUM_OF_MODUL]; +} MU_STRUCT_LQ_REPORT, *P_MU_STRUCT_LQ_REPORT; + +typedef struct _PARAM_CUSTOM_GET_MU_CALC_LQ_STRUCT_T { + u32 u4EventId; + MU_STRUCT_LQ_REPORT rEntry; +} PARAM_CUSTOM_GET_MU_CALC_LQ_STRUCT_T, *P_PARAM_CUSTOM_GET_MU_CALC_LQ_STRUCT_T; + +typedef struct _MU_GET_CALC_INIT_MCS_T { + u8 ucgroupIdx; + u8 ucRsv[3]; +} MU_GET_CALC_INIT_MCS_T, *P_MU_GET_CALC_INIT_MCS_T; + +typedef struct _MU_SET_INIT_MCS_T { + u8 ucNumOfUser; /* zero-base : 0~3: means 1~2 users */ + u8 ucBandwidth; /* zero-base : 0:20 hz 1:40 hz 2: 80 hz 3: 160 */ + u8 ucNssOfUser0; /* zero-base : 0~1 means uesr0 use 1~2 ss , if no use + * keep 0 */ + u8 ucNssOfUser1; /* zero-base : 0~1 means uesr0 use 1~2 ss , if no use + * keep 0 */ + u8 ucPfMuIdOfUser0; /* zero-base : for now, uesr0 use pf mu id 0 */ + u8 ucPfMuIdOfUser1; /* zero-base : for now, uesr1 use pf mu id 1 */ + u8 ucNumOfTxer; /* 0~3: mean use 1~4 anntain, for now, should fix 3 */ + u8 ucSpeIndex; /*add new field to fill special extension index which + * replace reserve */ + u32 u4GroupIndex; /* 0~ :the index of group table entry for calculation + */ +} MU_SET_INIT_MCS_T, *P_MU_SET_INIT_MCS_T; + +typedef struct _MU_SET_CALC_LQ_T { + u8 ucNumOfUser; /* zero-base : 0~3: means 1~2 users */ + u8 ucBandwidth; /* zero-base : 0:20 hz 1:40 hz 2: 80 hz 3: 160 */ + u8 ucNssOfUser0; /* zero-base : 0~1 means uesr0 use 1~2 ss , if no use + * keep 0 */ + u8 ucNssOfUser1; /* zero-base : 0~1 means uesr0 use 1~2 ss , if no use + * keep 0 */ + u8 ucPfMuIdOfUser0; /* zero-base : for now, uesr0 use pf mu id 0 */ + u8 ucPfMuIdOfUser1; /* zero-base : for now, uesr1 use pf mu id 1 */ + u8 ucNumOfTxer; /* 0~3: mean use 1~4 anntain, for now, should fix 3 */ + u8 ucSpeIndex; /*add new field to fill special extension index which + * replace reserve */ + u32 u4GroupIndex; /* 0~ :the index of group table entry for calculation + */ +} MU_SET_CALC_LQ_T, *P_MU_SET_CALC_LQ_T; + +typedef struct _MU_GET_LQ_T { + u8 ucType; + u8 ucRsv[3]; +} MU_GET_LQ_T, *P_MU_GET_LQ_T; + +typedef struct _MU_SET_SNR_OFFSET_T { + u8 ucVal; + u8 ucRsv[3]; +} MU_SET_SNR_OFFSET_T, *P_MU_SET_SNR_OFFSET_T; + +typedef struct _MU_SET_ZERO_NSS_T { + u8 ucVal; + u8 ucRsv[3]; +} MU_SET_ZERO_NSS_T, *P_MU_SET_ZERO_NSS_T; + +typedef struct _MU_SPEED_UP_LQ_T { + u32 u4Val; +} MU_SPEED_UP_LQ_T, *P_MU_SPEED_UP_LQ_T; + +typedef struct _MU_SET_MU_TABLE_T { + /* u16 u2Type; */ + /* u32 u4Length; */ + u8 aucMetricTable[NUM_MUT_NR_NUM * NUM_MUT_FEC * NUM_MUT_MCS * + NUM_MUT_INDEX]; +} MU_SET_MU_TABLE_T, *P_MU_SET_MU_TABLE_T; + +typedef struct _MU_SET_GROUP_T { + u32 u4GroupIndex; /* Group Table Idx */ + u32 u4NumOfUser; + u32 u4User0Ldpc; + u32 u4User1Ldpc; + u32 u4ShortGI; + u32 u4Bw; + u32 u4User0Nss; + u32 u4User1Nss; + u32 u4GroupId; + u32 u4User0UP; + u32 u4User1UP; + u32 u4User0MuPfId; + u32 u4User1MuPfId; + u32 u4User0InitMCS; + u32 u4User1InitMCS; + u8 aucUser0MacAddr[PARAM_MAC_ADDR_LEN]; + u8 aucUser1MacAddr[PARAM_MAC_ADDR_LEN]; +} MU_SET_GROUP_T, *P_MU_SET_GROUP_T; + +typedef struct _MU_GET_QD_T { + u8 ucSubcarrierIndex; + /* u32 u4Length; */ + /* u8 *prQd; */ +} MU_GET_QD_T, *P_MU_GET_QD_T; + +typedef struct _MU_SET_ENABLE_T { + u8 ucVal; + u8 ucRsv[3]; +} MU_SET_ENABLE_T, *P_MU_SET_ENABLE_T; + +typedef struct _MU_SET_GID_UP_T { + u32 au4Gid[2]; + u32 au4Up[4]; +} MU_SET_GID_UP_T, *P_MU_SET_GID_UP_T; + +typedef struct _MU_TRIGGER_MU_TX_T { + u8 fgIsRandomPattern; /* is random pattern or not */ + u32 u4MsduPayloadLength0; /* payload length of the MSDU for user 0 */ + u32 u4MsduPayloadLength1; /* payload length of the MSDU for user 1 */ + u32 u4MuPacketCount; /* MU TX count */ + u32 u4NumOfSTAs; /* number of user in the MU TX */ + u8 aucMacAddrs[2][6]; /* MAC address of users*/ +} MU_TRIGGER_MU_TX_T, *P_MU_TRIGGER_MU_TX_T; + +typedef struct _PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T { + u8 ucMuMimoCategory; + u8 aucRsv[3]; + union { + MU_GET_CALC_INIT_MCS_T rMuGetCalcInitMcs; + MU_SET_INIT_MCS_T rMuSetInitMcs; + MU_SET_CALC_LQ_T rMuSetCalcLq; + MU_GET_LQ_T rMuGetLq; + MU_SET_SNR_OFFSET_T rMuSetSnrOffset; + MU_SET_ZERO_NSS_T rMuSetZeroNss; + MU_SPEED_UP_LQ_T rMuSpeedUpLq; + MU_SET_MU_TABLE_T rMuSetMuTable; + MU_SET_GROUP_T rMuSetGroup; + MU_GET_QD_T rMuGetQd; + MU_SET_ENABLE_T rMuSetEnable; + MU_SET_GID_UP_T rMuSetGidUp; + MU_TRIGGER_MU_TX_T rMuTriggerMuTx; + } unMuMimoParam; +} PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T, *P_PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T; +#endif +#endif +#endif + +typedef struct _PARAM_CUSTOM_MEM_DUMP_STRUCT_T { + u32 u4Address; + u32 u4Length; + u32 u4RemainLength; +#if CFG_SUPPORT_QA_TOOL + u32 u4IcapContent; +#endif + u8 ucFragNum; +} PARAM_CUSTOM_MEM_DUMP_STRUCT_T, *P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T; + +typedef struct _PARAM_CUSTOM_SW_CTRL_STRUCT_T { + u32 u4Id; + s32 u4Data; +} PARAM_CUSTOM_SW_CTRL_STRUCT_T, *P_PARAM_CUSTOM_SW_CTRL_STRUCT_T; + +typedef struct _PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T { + u16 u2Id; + u8 ucType; + u8 ucRespType; + u16 u2MsgSize; + u8 aucReserved0[2]; + u8 aucCmd[CHIP_CONFIG_RESP_SIZE]; +} PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T, *P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T; + +typedef struct _PARAM_CUSTOM_KEY_CFG_STRUCT_T { + u8 aucKey[WLAN_CFG_KEY_LEN_MAX]; + u8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; +} PARAM_CUSTOM_KEY_CFG_STRUCT_T, *P_PARAM_CUSTOM_KEY_CFG_STRUCT_T; + +typedef struct _PARAM_CUSTOM_EEPROM_RW_STRUCT_T { + u8 ucEepromMethod; /* For read only read: 1, query size: 0 */ + u8 ucEepromIndex; + u8 reserved; + u16 u2EepromData; +} PARAM_CUSTOM_EEPROM_RW_STRUCT_T, *P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T, +PARAM_CUSTOM_NVRAM_RW_STRUCT_T, *P_PARAM_CUSTOM_NVRAM_RW_STRUCT_T; + +typedef struct _PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T { + u8 bmfgApsdEnAc; /* b0~3: trigger-en AC0~3. b4~7: delivery-en AC0~3 */ + u8 ucIsEnterPsAtOnce; /* enter PS immediately without 5 second guard + * after connected */ + u8 ucIsDisableUcTrigger; /* not to trigger UC on beacon TIM is matched + * (under U-APSD) */ + u8 reserved; +} PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T, *P_PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T; + +typedef struct _PARAM_CUSTOM_NOA_PARAM_STRUCT_T { + u32 u4NoaDurationMs; + u32 u4NoaIntervalMs; + u32 u4NoaCount; + u8 ucBssIdx; +} PARAM_CUSTOM_NOA_PARAM_STRUCT_T, *P_PARAM_CUSTOM_NOA_PARAM_STRUCT_T; + +typedef struct _PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T { + u8 ucBssIdx; + u8 ucLegcyPS; + u8 ucOppPs; + u8 aucResv[1]; + u32 u4CTwindowMs; +} PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T, *P_PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T; + +typedef struct _PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T { + u8 ucBssIdx; + u8 fgEnAPSD; + u8 fgEnAPSD_AcBe; + u8 fgEnAPSD_AcBk; + u8 fgEnAPSD_AcVo; + u8 fgEnAPSD_AcVi; + u8 ucMaxSpLen; + u8 aucResv[2]; +} PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T, *P_PARAM_CUSTOM_UAPSD_PARAM_STRUCT_T; + +typedef struct _PARAM_CUSTOM_P2P_SET_STRUCT_T { + u32 u4Enable; + u32 u4Mode; +} PARAM_CUSTOM_P2P_SET_STRUCT_T, *P_PARAM_CUSTOM_P2P_SET_STRUCT_T; + +#define MAX_NUMBER_OF_ACL 20 + +typedef enum _ENUM_PARAM_CUSTOM_ACL_POLICY_T { + PARAM_CUSTOM_ACL_POLICY_DISABLE, + PARAM_CUSTOM_ACL_POLICY_ACCEPT, + PARAM_CUSTOM_ACL_POLICY_DENY, + PARAM_CUSTOM_ACL_POLICY_NUM +} ENUM_PARAM_CUSTOM_ACL_POLICY_T, +*P_ENUM_PARAM_CUSTOM_ACL_POLICY_T; + +typedef struct _PARAM_CUSTOM_ACL_ENTRY { + u8 aucAddr[MAC_ADDR_LEN]; + u16 u2Rsv; +} PARAM_CUSTOM_ACL_ENTRY, *PPARAM_CUSTOM_ACL_ENTRY; + +typedef struct _PARAM_CUSTOM_ACL { + ENUM_PARAM_CUSTOM_ACL_POLICY_T ePolicy; + u32 u4Num; + PARAM_CUSTOM_ACL_ENTRY rEntry[MAX_NUMBER_OF_ACL]; +} PARAM_CUSTOM_ACL, *PPARAM_CUSTOM_ACL; + +typedef enum _ENUM_CFG_SRC_TYPE_T { + CFG_SRC_TYPE_EEPROM, + CFG_SRC_TYPE_NVRAM, + CFG_SRC_TYPE_UNKNOWN, + CFG_SRC_TYPE_NUM +} ENUM_CFG_SRC_TYPE_T, +*P_ENUM_CFG_SRC_TYPE_T; + +typedef enum _ENUM_EEPROM_TYPE_T { + EEPROM_TYPE_NO, + EEPROM_TYPE_PRESENT, + EEPROM_TYPE_NUM +} ENUM_EEPROM_TYPE_T, +*P_ENUM_EEPROM_TYPE_T; + +typedef struct _PARAM_QOS_TSINFO { + u8 ucTrafficType; /* Traffic Type: 1 for isochronous 0 for asynchronous + */ + u8 ucTid; /* TSID: must be between 8 ~ 15 */ + u8 ucDirection; /* direction */ + u8 ucAccessPolicy; /* access policy */ + u8 ucAggregation; /* aggregation */ + u8 ucApsd; /* APSD */ + u8 ucuserPriority; /* user priority */ + u8 ucTsInfoAckPolicy; /* TSINFO ACK policy */ + u8 ucSchedule; /* Schedule */ +} PARAM_QOS_TSINFO, *P_PARAM_QOS_TSINFO; + +typedef struct _PARAM_QOS_TSPEC { + PARAM_QOS_TSINFO rTsInfo; /* TS info field */ + u16 u2NominalMSDUSize; /* nominal MSDU size */ + u16 u2MaxMSDUsize; /* maximum MSDU size */ + u32 u4MinSvcIntv; /* minimum service interval */ + u32 u4MaxSvcIntv; /* maximum service interval */ + u32 u4InactIntv; /* inactivity interval */ + u32 u4SpsIntv; /* suspension interval */ + u32 u4SvcStartTime; /* service start time */ + u32 u4MinDataRate; /* minimum Data rate */ + u32 u4MeanDataRate; /* mean data rate */ + u32 u4PeakDataRate; /* peak data rate */ + u32 u4MaxBurstSize; /* maximum burst size */ + u32 u4DelayBound; /* delay bound */ + u32 u4MinPHYRate; /* minimum PHY rate */ + u16 u2Sba; /* surplus bandwidth allowance */ + u16 u2MediumTime; /* medium time */ +} PARAM_QOS_TSPEC, *P_PARAM_QOS_TSPEC; + +typedef struct _PARAM_QOS_ADDTS_REQ_INFO { + PARAM_QOS_TSPEC rTspec; +} PARAM_QOS_ADDTS_REQ_INFO, *P_PARAM_QOS_ADDTS_REQ_INFO; + +typedef struct _PARAM_VOIP_CONFIG { + u32 u4VoipTrafficInterval; /* 0: disable VOIP configuration */ +} PARAM_VOIP_CONFIG, *P_PARAM_VOIP_CONFIG; + +/*802.11 Statistics Struct*/ +typedef struct _PARAM_802_11_STATISTICS_STRUCT_T { + u32 u4Length; /* Length of structure */ + LARGE_INTEGER rTransmittedFragmentCount; + LARGE_INTEGER rMulticastTransmittedFrameCount; + LARGE_INTEGER rFailedCount; + LARGE_INTEGER rRetryCount; + LARGE_INTEGER rMultipleRetryCount; + LARGE_INTEGER rRTSSuccessCount; + LARGE_INTEGER rRTSFailureCount; + LARGE_INTEGER rACKFailureCount; + LARGE_INTEGER rFrameDuplicateCount; + LARGE_INTEGER rReceivedFragmentCount; + LARGE_INTEGER rMulticastReceivedFrameCount; + LARGE_INTEGER rFCSErrorCount; + LARGE_INTEGER rTKIPLocalMICFailures; + LARGE_INTEGER rTKIPICVErrors; + LARGE_INTEGER rTKIPCounterMeasuresInvoked; + LARGE_INTEGER rTKIPReplays; + LARGE_INTEGER rCCMPFormatErrors; + LARGE_INTEGER rCCMPReplays; + LARGE_INTEGER rCCMPDecryptErrors; + LARGE_INTEGER rFourWayHandshakeFailures; + LARGE_INTEGER rWEPUndecryptableCount; + LARGE_INTEGER rWEPICVErrorCount; + LARGE_INTEGER rDecryptSuccessCount; + LARGE_INTEGER rDecryptFailureCount; +} PARAM_802_11_STATISTICS_STRUCT_T, *P_PARAM_802_11_STATISTICS_STRUCT_T; + +/* Linux Network Device Statistics Struct */ +typedef struct _PARAM_LINUX_NETDEV_STATISTICS_T { + u32 u4RxPackets; + u32 u4TxPackets; + u32 u4RxBytes; + u32 u4TxBytes; + u32 u4RxErrors; + u32 u4TxErrors; + u32 u4Multicast; +} PARAM_LINUX_NETDEV_STATISTICS_T, *P_PARAM_LINUX_NETDEV_STATISTICS_T; + +typedef struct _PARAM_MTK_WIFI_TEST_STRUCT_T { + u32 u4FuncIndex; + u32 u4FuncData; +} PARAM_MTK_WIFI_TEST_STRUCT_T, *P_PARAM_MTK_WIFI_TEST_STRUCT_T; + +/* 802.11 Media stream constraints */ +typedef enum _ENUM_MEDIA_STREAM_MODE { + ENUM_MEDIA_STREAM_OFF, + ENUM_MEDIA_STREAM_ON +} ENUM_MEDIA_STREAM_MODE, +*P_ENUM_MEDIA_STREAM_MODE; + +/* for NDIS 5.1 Media Streaming Change */ +typedef struct _PARAM_MEDIA_STREAMING_INDICATION { + PARAM_STATUS_INDICATION_T rStatus; + ENUM_MEDIA_STREAM_MODE eMediaStreamMode; +} PARAM_MEDIA_STREAMING_INDICATION, *P_PARAM_MEDIA_STREAMING_INDICATION; + +#define PARAM_PROTOCOL_ID_DEFAULT 0x00 +#define PARAM_PROTOCOL_ID_TCP_IP 0x02 +#define PARAM_PROTOCOL_ID_IPX 0x06 +#define PARAM_PROTOCOL_ID_NBF 0x07 +#define PARAM_PROTOCOL_ID_MAX 0x0F +#define PARAM_PROTOCOL_ID_MASK 0x0F + +/* for NDIS OID_GEN_NETWORK_LAYER_ADDRESSES */ +typedef struct _PARAM_NETWORK_ADDRESS_IP { + u16 sin_port; + u32 in_addr; + u8 sin_zero[8]; +} PARAM_NETWORK_ADDRESS_IP, *P_PARAM_NETWORK_ADDRESS_IP; + +typedef struct _PARAM_NETWORK_ADDRESS { + u16 u2AddressLength; /* length in bytes of Address[] in this */ + u16 u2AddressType; /* type of this address (PARAM_PROTOCOL_ID_XXX above) + */ + u8 aucAddress[1]; /* actually AddressLength bytes long */ +} PARAM_NETWORK_ADDRESS, *P_PARAM_NETWORK_ADDRESS; + +/* The following is used with OID_GEN_NETWORK_LAYER_ADDRESSES to set network + * layer addresses on an interface */ + +typedef struct _PARAM_NETWORK_ADDRESS_LIST { + u8 ucBssIdx; + u32 u4AddressCount; /* number of addresses following */ + u16 u2AddressType; /* type of this address (NDIS_PROTOCOL_ID_XXX above) + */ + PARAM_NETWORK_ADDRESS + arAddress[1]; /* actually AddressCount elements long */ +} PARAM_NETWORK_ADDRESS_LIST, *P_PARAM_NETWORK_ADDRESS_LIST; + +#if CFG_SUPPORT_MSP +/* Should by chip */ +typedef struct _PARAM_SEC_CONFIG_T { + u8 fgWPIFlag; + u8 fgRV; + u8 fgIKV; + u8 fgRKV; + + u8 fgRCID; + u8 fgRCA1; + u8 fgRCA2; + u8 fgEvenPN; + + u8 ucKeyID; + u8 ucMUARIdx; + u8 ucCipherSuit; + u8 aucReserved[1]; +} PARAM_SEC_CONFIG_T, *P_PARAM_SEC_CONFIG_T; + +typedef struct _PARAM_TX_CONFIG_T { + u8 aucPA[6]; + u8 fgSW; + u8 fgDisRxHdrTran; + + u8 fgAADOM; + u8 ucPFMUIdx; + u16 u2PartialAID; + + u8 fgTIBF; + u8 fgTEBF; + u8 fgIsHT; + u8 fgIsVHT; + + u8 fgMesh; + u8 fgBAFEn; + u8 fgCFAck; + u8 fgRdgBA; + + u8 fgRDG; + u8 fgIsPwrMgt; + u8 fgRTS; + u8 fgSMPS; + + u8 fgTxopPS; + u8 fgDonotUpdateIPSM; + u8 fgSkipTx; + u8 fgLDPC; + + u8 fgIsQoS; + u8 fgIsFromDS; + u8 fgIsToDS; + u8 fgDynBw; + + u8 fgIsAMSDUCrossLG; + u8 fgCheckPER; + u8 fgIsGID63; + u8 aucReserved[1]; + +#if (1) + u8 fgVhtTIBF; + u8 fgVhtTEBF; + u8 fgVhtLDPC; + u8 aucReserved2[1]; +#endif +} PARAM_TX_CONFIG_T, *P_PARAM_TX_CONFIG_T; + +typedef struct _PARAM_KEY_CONFIG_T { + u8 aucKey[32]; +} PARAM_KEY_CONFIG_T, *P_PARAM_KEY_CONFIG_T; + +typedef struct _PARAM_PEER_RATE_INFO_T { + u8 ucCounterMPDUFail; + u8 ucCounterMPDUTx; + u8 ucRateIdx; + u8 ucReserved[1]; + + u16 au2RateCode[AUTO_RATE_NUM]; +} PARAM_PEER_RATE_INFO_T, *P_PARAM_PEER_RATE_INFO_T; + +typedef struct _PARAM_PEER_BA_CONFIG_T { + u8 ucBaEn; + u8 ucRsv[3]; + u32 u4BaWinSize; +} PARAM_PEER_BA_CONFIG_T, *P_PARAM_PEER_BA_CONFIG_T; + +typedef struct _PARAM_ANT_ID_CONFIG_T { + u8 ucANTIDSts0; + u8 ucANTIDSts1; + u8 ucANTIDSts2; + u8 ucANTIDSts3; +} PARAM_ANT_ID_CONFIG_T, *P_PARAM_ANT_ID_CONFIG_T; + +typedef struct _PARAM_PEER_CAP_T { + PARAM_ANT_ID_CONFIG_T rAntIDConfig; + + u8 ucTxPowerOffset; + u8 ucCounterBWSelector; + u8 ucChangeBWAfterRateN; + u8 ucFrequencyCapability; + u8 ucSpatialExtensionIndex; + + u8 fgG2; + u8 fgG4; + u8 fgG8; + u8 fgG16; + + u8 ucMMSS; + u8 ucAmpduFactor; + u8 ucReserved[1]; +} PARAM_PEER_CAP_T, *P_PARAM_PEER_CAP_T; + +typedef struct _PARAM_PEER_RX_COUNTER_ALL_T { + u8 ucRxRcpi0; + u8 ucRxRcpi1; + u8 ucRxRcpi2; + u8 ucRxRcpi3; + + u8 ucRxCC0; + u8 ucRxCC1; + u8 ucRxCC2; + u8 ucRxCC3; + + u8 fgRxCCSel; + u8 ucCeRmsd; + u8 aucReserved[2]; +} PARAM_PEER_RX_COUNTER_ALL_T, *P_PARAM_PEER_RX_COUNTER_ALL_T; + +typedef struct _PARAM_PEER_TX_COUNTER_ALL_T { + u16 u2Rate1TxCnt; + u16 u2Rate1FailCnt; + u16 u2Rate2OkCnt; + u16 u2Rate3OkCnt; + u16 u2CurBwTxCnt; + u16 u2CurBwFailCnt; + u16 u2OtherBwTxCnt; + u16 u2OtherBwFailCnt; +} PARAM_PEER_TX_COUNTER_ALL_T, *P_PARAM_PEER_TX_COUNTER_ALL_T; + +typedef struct _PARAM_HW_WLAN_INFO_T { + u32 u4Index; + PARAM_TX_CONFIG_T rWtblTxConfig; + PARAM_SEC_CONFIG_T rWtblSecConfig; + PARAM_KEY_CONFIG_T rWtblKeyConfig; + PARAM_PEER_RATE_INFO_T rWtblRateInfo; + PARAM_PEER_BA_CONFIG_T rWtblBaConfig; + PARAM_PEER_CAP_T rWtblPeerCap; + PARAM_PEER_RX_COUNTER_ALL_T rWtblRxCounter; + PARAM_PEER_TX_COUNTER_ALL_T rWtblTxCounter; +} PARAM_HW_WLAN_INFO_T, *P_PARAM_HW_WLAN_INFO_T; + +typedef struct _HW_TX_AMPDU_METRICS_T { + u32 u4TxSfCnt; + u32 u4TxAckSfCnt; + u32 u2TxAmpduCnt; + u32 u2TxRspBaCnt; + u16 u2TxEarlyStopCnt; + u16 u2TxRange1AmpduCnt; + u16 u2TxRange2AmpduCnt; + u16 u2TxRange3AmpduCnt; + u16 u2TxRange4AmpduCnt; + u16 u2TxRange5AmpduCnt; + u16 u2TxRange6AmpduCnt; + u16 u2TxRange7AmpduCnt; + u16 u2TxRange8AmpduCnt; + u16 u2TxRange9AmpduCnt; +} HW_TX_AMPDU_METRICS_T, *P_HW_TX_AMPDU_METRICS_T; + +typedef struct _HW_MIB_COUNTER_T { + u32 u4RxFcsErrCnt; + u32 u4RxFifoFullCnt; + u32 u4RxMpduCnt; + u32 u4RxAMPDUCnt; + u32 u4RxTotalByte; + u32 u4RxValidAMPDUSF; + u32 u4RxValidByte; + u32 u4ChannelIdleCnt; + u32 u4RxVectorDropCnt; + u32 u4DelimiterFailedCnt; + u32 u4RxVectorMismatchCnt; + u32 u4MdrdyCnt; + u32 u4CCKMdrdyCnt; + u32 u4OFDMLGMixMdrdy; + u32 u4OFDMGreenMdrdy; + u32 u4PFDropCnt; + u32 u4RxLenMismatchCnt; + u32 u4PCcaTime; + u32 u4SCcaTime; + u32 u4CcaNavTx; + u32 u4PEDTime; + u32 u4BeaconTxCnt; + u32 au4BaMissedCnt[BSSID_NUM]; + u32 au4RtsTxCnt[BSSID_NUM]; + u32 au4FrameRetryCnt[BSSID_NUM]; + u32 au4FrameRetry2Cnt[BSSID_NUM]; + u32 au4RtsRetryCnt[BSSID_NUM]; + u32 au4AckFailedCnt[BSSID_NUM]; +} HW_MIB_COUNTER_T, *P_HW_MIB_COUNTER_T; + +typedef struct _HW_MIB2_COUNTER_T { + u32 u4Tx40MHzCnt; + u32 u4Tx80MHzCnt; + u32 u4Tx160MHzCnt; +} HW_MIB2_COUNTER_T, *P_HW_MIB2_COUNTER_T; + +typedef struct _PARAM_HW_MIB_INFO_T { + u32 u4Index; + HW_MIB_COUNTER_T rHwMibCnt; + HW_MIB2_COUNTER_T rHwMib2Cnt; + HW_TX_AMPDU_METRICS_T rHwTxAmpduMts; +} PARAM_HW_MIB_INFO_T, *P_PARAM_HW_MIB_INFO_T; +#endif + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +struct PARAM_TX_MCS_INFO { + u8 ucStaIndex; + u16 au2TxRateCode[MCS_INFO_SAMPLE_CNT]; + u8 aucTxRatePer[MCS_INFO_SAMPLE_CNT]; +}; +#endif + +#ifdef CFG_DUMP_TXPOWR_TABLE +struct PARAM_CMD_GET_TXPWR_TBL { + u8 ucDbdcIdx; + u8 ucCenterCh; + u8 ucFeLoss; + struct POWER_LIMIT tx_pwr_tbl[TXPWR_TBL_NUM]; +}; + +enum ENUM_TXPWR_TYPE { + DSSS = 0, + OFDM_24G, + OFDM_5G, + HT20, + HT40, + VHT20, + VHT40, + VHT80, + TXPWR_TYPE_NUM, +}; + +enum ENUM_STREAM_MODE { + STREAM_SISO, + STREAM_CDD, + STREAM_MIMO, + STREAM_NUM +}; + +struct txpwr_table_entry { + char mcs[STREAM_NUM][8]; + unsigned int idx; +}; + +struct txpwr_table { + char phy_mode[8]; + struct txpwr_table_entry *tables; + int n_tables; +}; +#endif + +/*--------------------------------------------------------------*/ +/*! \brief For Fixed Rate Configuration (Registry) */ +/*--------------------------------------------------------------*/ +typedef enum _ENUM_REGISTRY_FIXED_RATE_T { + FIXED_RATE_NONE, + FIXED_RATE_1M, + FIXED_RATE_2M, + FIXED_RATE_5_5M, + FIXED_RATE_11M, + FIXED_RATE_6M, + FIXED_RATE_9M, + FIXED_RATE_12M, + FIXED_RATE_18M, + FIXED_RATE_24M, + FIXED_RATE_36M, + FIXED_RATE_48M, + FIXED_RATE_54M, + FIXED_RATE_MCS0_20M_800NS, + FIXED_RATE_MCS1_20M_800NS, + FIXED_RATE_MCS2_20M_800NS, + FIXED_RATE_MCS3_20M_800NS, + FIXED_RATE_MCS4_20M_800NS, + FIXED_RATE_MCS5_20M_800NS, + FIXED_RATE_MCS6_20M_800NS, + FIXED_RATE_MCS7_20M_800NS, + FIXED_RATE_MCS0_20M_400NS, + FIXED_RATE_MCS1_20M_400NS, + FIXED_RATE_MCS2_20M_400NS, + FIXED_RATE_MCS3_20M_400NS, + FIXED_RATE_MCS4_20M_400NS, + FIXED_RATE_MCS5_20M_400NS, + FIXED_RATE_MCS6_20M_400NS, + FIXED_RATE_MCS7_20M_400NS, + FIXED_RATE_MCS0_40M_800NS, + FIXED_RATE_MCS1_40M_800NS, + FIXED_RATE_MCS2_40M_800NS, + FIXED_RATE_MCS3_40M_800NS, + FIXED_RATE_MCS4_40M_800NS, + FIXED_RATE_MCS5_40M_800NS, + FIXED_RATE_MCS6_40M_800NS, + FIXED_RATE_MCS7_40M_800NS, + FIXED_RATE_MCS32_800NS, + FIXED_RATE_MCS0_40M_400NS, + FIXED_RATE_MCS1_40M_400NS, + FIXED_RATE_MCS2_40M_400NS, + FIXED_RATE_MCS3_40M_400NS, + FIXED_RATE_MCS4_40M_400NS, + FIXED_RATE_MCS5_40M_400NS, + FIXED_RATE_MCS6_40M_400NS, + FIXED_RATE_MCS7_40M_400NS, + FIXED_RATE_MCS32_400NS, + FIXED_RATE_NUM +} ENUM_REGISTRY_FIXED_RATE_T, +*P_ENUM_REGISTRY_FIXED_RATE_T; + +typedef enum _ENUM_BT_CMD_T { + BT_CMD_PROFILE = 0, + BT_CMD_UPDATE, + BT_CMD_NUM +} ENUM_BT_CMD_T; + +typedef enum _ENUM_BT_PROFILE_T { + BT_PROFILE_CUSTOM = 0, + BT_PROFILE_SCO, + BT_PROFILE_ACL, + BT_PROFILE_MIXED, + BT_PROFILE_NO_CONNECTION, + BT_PROFILE_NUM +} ENUM_BT_PROFILE_T; + +typedef struct _PTA_PROFILE_T { + ENUM_BT_PROFILE_T eBtProfile; + union { + u8 aucBTPParams[BT_PROFILE_PARAM_LEN]; + /* 0: sco reserved slot time, + * 1: sco idle slot time, + * 2: acl throughput, + * 3: bt tx power, + * 4: bt rssi + * 5: VoIP interval + * 6: BIT(0) Use this field, BIT(1) 0 apply single/ 1 dual PTA + * setting. + */ + u32 au4Btcr[4]; + } u; +} PTA_PROFILE_T, *P_PTA_PROFILE_T; + +typedef struct _PTA_IPC_T { + u8 ucCmd; + u8 ucLen; + union { + PTA_PROFILE_T rProfile; + u8 aucBTPParams[BT_PROFILE_PARAM_LEN]; + } u; +} PARAM_PTA_IPC_T, *P_PARAM_PTA_IPC_T, PTA_IPC_T, *P_PTA_IPC_T; + +/*--------------------------------------------------------------*/ +/*! \brief CFG80211 Scan Request Container */ +/*--------------------------------------------------------------*/ +typedef struct _PARAM_SCAN_REQUEST_EXT_T { + PARAM_SSID_T rSsid; + u32 u4IELength; + u8 *pucIE; +} PARAM_SCAN_REQUEST_EXT_T, *P_PARAM_SCAN_REQUEST_EXT_T; + +typedef struct _PARAM_SCAN_REQUEST_ADV_T { + u32 u4SsidNum; + PARAM_SSID_T rSsid[CFG_SCAN_SSID_MAX_NUM]; + u32 u4IELength; + u8 *pucIE; +#if CFG_SCAN_CHANNEL_SPECIFIED + u8 ucChannelListNum; + RF_CHANNEL_INFO_T arChnlInfoList[MAXIMUM_OPERATION_CHANNEL_LIST]; +#endif +} PARAM_SCAN_REQUEST_ADV_T, *P_PARAM_SCAN_REQUEST_ADV_T; + +/*--------------------------------------------------------------*/ +/*! \brief CFG80211 Scheduled Scan Request Container */ +/*--------------------------------------------------------------*/ +typedef struct _PARAM_SCHED_SCAN_REQUEST_T { + u32 u4SsidNum; + PARAM_SSID_T arSsid[CFG_SCAN_SSID_MATCH_MAX_NUM]; + u32 u4IELength; + u8 *pucIE; + u16 u2ScanInterval; /* in milliseconds */ +} PARAM_SCHED_SCAN_REQUEST, *P_PARAM_SCHED_SCAN_REQUEST; + +#if CFG_SUPPORT_SNIFFER +typedef struct _PARAM_CUSTOM_MONITOR_SET_STRUCT_T { + u8 ucEnable; + u8 ucBand; + u8 ucPriChannel; + u8 ucSco; + u8 ucChannelWidth; + u8 ucChannelS1; + u8 ucChannelS2; + u8 aucResv[9]; +} PARAM_CUSTOM_MONITOR_SET_STRUCT_T, *P_PARAM_CUSTOM_MONITOR_SET_STRUCT_T; +#endif + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +/*--------------------------------------------------------------*/ +/*! \brief MTK Auto Channel Selection related Container */ +/*--------------------------------------------------------------*/ +typedef struct _LTE_SAFE_CHN_INFO_T { + u32 au4SafeChannelBitmask[5]; /* NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_MAX + */ +} LTE_SAFE_CHN_INFO_T, *P_CMD_LTE_SAFE_CHN_INFO_T; + +typedef struct _PARAM_CHN_LOAD_INFO { + /* Per-CHN Load */ + u8 ucChannel; + u16 u2APNum; + u32 u4Dirtiness; + u8 ucReserved; +} PARAM_CHN_LOAD_INFO, *P_PARAM_CHN_LOAD_INFO; + +typedef struct _PARAM_CHN_RANK_INFO { + u8 ucChannel; + u32 u4Dirtiness; + u8 ucReserved; +} PARAM_CHN_RANK_INFO, *P_PARAM_CHN_RANK_INFO; + +typedef struct _PARAM_GET_CHN_INFO { + LTE_SAFE_CHN_INFO_T rLteSafeChnList; + PARAM_CHN_LOAD_INFO rEachChnLoad[MAX_CHN_NUM]; + u8 fgDataReadyBit; + PARAM_CHN_RANK_INFO rChnRankList[MAX_CHN_NUM]; + u8 aucReserved[3]; +} PARAM_GET_CHN_INFO, *P_PARAM_GET_CHN_INFO; + +typedef struct _PARAM_PREFER_CHN_INFO { + u8 ucChannel; + u16 u2APNumScore; + u8 ucReserved; +} PARAM_PREFER_CHN_INFO, *P_PARAM_PREFER_CHN_INFO; +#endif + +typedef struct _UMAC_STAT2_GET_T { + u16 u2PleRevPgHif0Group0; + u16 u2PleRevPgCpuGroup2; + + u16 u2PseRevPgHif0Group0; + u16 u2PseRevPgHif1Group1; + u16 u2PseRevPgCpuGroup2; + u16 u2PseRevPgLmac0Group3; + u16 u2PseRevPgLmac1Group4; + u16 u2PseRevPgLmac2Group5; + u16 u2PseRevPgPleGroup6; + + u16 u2PleSrvPgHif0Group0; + u16 u2PleSrvPgCpuGroup2; + + u16 u2PseSrvPgHif0Group0; + u16 u2PseSrvPgHif1Group1; + u16 u2PseSrvPgCpuGroup2; + u16 u2PseSrvPgLmac0Group3; + u16 u2PseSrvPgLmac1Group4; + u16 u2PseSrvPgLmac2Group5; + u16 u2PseSrvPgPleGroup6; + + u16 u2PleTotalPageNum; + u16 u2PleFreePageNum; + u16 u2PleFfaNum; + + u16 u2PseTotalPageNum; + u16 u2PseFreePageNum; + u16 u2PseFfaNum; +} UMAC_STAT2_GET_T, *P_UMAC_STAT2_GET_T; + +typedef struct _CNM_STATUS_T { + u8 fgDbDcModeEn; + u8 ucChNumB0; + u8 ucChNumB1; + u8 usReserved; +} CNM_STATUS_T, *P_CNM_STATUS_T; + +typedef struct _CNM_CH_LIST_T { + u8 ucChNum[4]; +} CNM_CH_LIST_T, *P_CNM_CH_LIST_T; + +typedef struct _PARAM_WDEV_LOCK_THREAD_T { + QUE_ENTRY_T rQueEntry; + struct net_device *pDev; + enum ENUM_CFG80211_WDEV_LOCK_FUNC fn; + u8 *pFrameBuf; + size_t frameLen; + struct cfg80211_bss *pBss; + u32 uapsd_queues; + u8 fgIsInterruptContext; + const u8 *req_ies; + size_t req_ies_len; +} PARAM_WDEV_LOCK_THREAD_T, *P_PARAM_WDEV_LOCK_THREAD_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*--------------------------------------------------------------*/ +/* Routines to set parameters or query information. */ +/*--------------------------------------------------------------*/ +/***** Routines in wlan_oid.c *****/ +WLAN_STATUS +wlanoidQueryNetworkTypesSupported(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryNetworkTypeInUse(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetNetworkTypeInUse(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryBssid(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetBssidListScan(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetBssidListScanExt(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetBssidListScanAdv(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryBssidList(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetBssid(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetConnect(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetSsid(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQuerySsid(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryInfrastructureMode(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetInfrastructureMode(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryAuthMode(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetAuthMode(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetEncryptionStatus(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryEncryptionStatus(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetAddWep(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetRemoveWep(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetAddKey(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetRemoveKey(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetReloadDefaults(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetTest(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryCapability(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryFrequency(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetFrequency(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryAtimWindow(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetAtimWindow(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetChannel(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryRssi(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryRssiTrigger(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetRssiTrigger(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryRtsThreshold(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetRtsThreshold(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQuery802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSet802dot11PowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN void *prSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryPmkid(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetPmkid(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQuerySupportedRates(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryDesiredRates(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetDesiredRates(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryPermanentAddr(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuf, + IN u32 u4QueryBufLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryCurrentAddr(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuf, + IN u32 u4QueryBufLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryPermanentAddr(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuf, + IN u32 u4QueryBufLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryLinkSpeed(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +#if CFG_SUPPORT_QA_TOOL +#if CFG_SUPPORT_BUFFER_MODE +WLAN_STATUS wlanoidSetEfusBufferMode(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +/*#if (CFG_EEPROM_PAGE_ACCESS == 1)*/ +WLAN_STATUS +wlanoidQueryProcessAccessEfuseRead(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryProcessAccessEfuseWrite(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryEfuseFreeBlock(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryGetTxPower(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +/*#endif*/ + +#endif +WLAN_STATUS +wlanoidQueryRxStatistics(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidBssInfoBasic(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidDevInfoActive(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidManualAssoc(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +#if CFG_SUPPORT_TX_BF +WLAN_STATUS +wlanoidTxBfAction(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +WLAN_STATUS wlanoidMuMimoAction(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +WLAN_STATUS wlanoidStaRecUpdate(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +WLAN_STATUS wlanoidStaRecBFUpdate(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +#endif +#endif + +WLAN_STATUS +wlanoidQueryMcrRead(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryMemDump(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetMcrWrite(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryDrvMcrRead(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetDrvMcrWrite(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetSwCtrlWrite(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetChipConfig(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryChipConfig(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetKeyCfg(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryEepromRead(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetEepromWrite(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryRfTestRxStatus(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryRfTestTxStatus(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryOidInterfaceVersion(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryVendorId(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryMulticastList(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetMulticastList(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryRcvError(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryRcvNoBuffer(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryRcvCrcError(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryStatistics(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryCoexIso(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +#ifdef LINUX + +WLAN_STATUS +wlanoidQueryStatisticsForLinux(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +#endif + +WLAN_STATUS +wlanoidQueryMediaStreamMode(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetMediaStreamMode(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryRcvOk(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryXmitOk(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryXmitError(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetCurrentPacketFilter(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryCurrentPacketFilter(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryAcpiDevicePowerState(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetDisassociate(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryFragThreshold(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetFragThreshold(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryAdHocMode(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetAdHocMode(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryBeaconInterval(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetBeaconInterval(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetCurrentAddr(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +WLAN_STATUS +wlanoidSetCSUMOffload(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +#endif + +WLAN_STATUS +wlanoidSetNetworkAddress(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryMaxFrameSize(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryMaxTotalSize(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetCurrentLookahead(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +/* RF Test related APIs */ +WLAN_STATUS +wlanoidRftestSetTestMode(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidRftestSetTestIcapMode(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidRftestSetAbortTestMode(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidRftestQueryAutoTest(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidRftestSetAutoTest(IN P_ADAPTER_T prAdapter, + OUT void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +#if CFG_SUPPORT_WPS2 +WLAN_STATUS +wlanoidSetWSCAssocInfo(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +#endif + +#if CFG_ENABLE_WAKEUP_ON_LAN +WLAN_STATUS +wlanoidSetAddWakeupPattern(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetRemoveWakeupPattern(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryEnableWakeup(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *u4QueryInfoLen); + +WLAN_STATUS +wlanoidSetEnableWakeup(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +#endif + +WLAN_STATUS +wlanoidSetWiFiWmmPsTest(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetTxAmpdu(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetAddbaReject(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryNvramRead(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetNvramWrite(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryCfgSrcType(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryEepromType(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetCountryCode(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS wlanSendMemDumpCmd(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen); + +#if CFG_SUPPORT_ADVANCE_CONTROL +WLAN_STATUS +wlanoidAdvCtrl(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); +#endif + +WLAN_STATUS +wlanoidQueryWlanInfo(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidQueryMibInfo(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +WLAN_STATUS +wlanoidTxMcsInfo(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); +#endif + +WLAN_STATUS +wlanoidSetFwLog2Host(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSetBT(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryBT(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetTxPower(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +#if CFG_ENABLE_WIFI_DIRECT +WLAN_STATUS +wlanoidSetP2pMode(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +#endif + +WLAN_STATUS +wlanoidSetDefaultKey(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetGtkRekeyData(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetStartSchedScan(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetStopSchedScan(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +#if CFG_SUPPORT_BATCH_SCAN +WLAN_STATUS +wlanoidSetBatchScanReq(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryBatchScanResult(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); +#endif + +#if CFG_SUPPORT_SNIFFER +WLAN_STATUS wlanoidSetMonitor(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +#endif + +#if CFG_STR_DHCP_RENEW_OFFLOAD +WLAN_STATUS +wlanoidSetDhcpOffladInfo(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +#endif + +WLAN_STATUS +wlanoidNotifyFwSuspend(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +#if CFG_SUPPORT_DBDC +WLAN_STATUS +wlanoidSetDbdcEnable(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +#endif + +WLAN_STATUS +wlanoidQuerySetTxTargetPower(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +#if (CFG_SUPPORT_DFS_MASTER == 1) +WLAN_STATUS +wlanoidQuerySetRddReport(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQuerySetRadarDetectMode(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +#endif + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +WLAN_STATUS +wlanoidQueryLteSafeChannel(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); +WLAN_STATUS +wlanCalculateAllChannelDirtiness(IN P_ADAPTER_T prAdapter); +void wlanInitChnLoadInfoChannelList(IN P_ADAPTER_T prAdapter); +u8 wlanGetChannelIndex(IN u8 channel); +u8 wlanGetChannelNumFromIndex(IN u8 ucIdx); +void wlanSortChannel(IN P_ADAPTER_T prAdapter); +#endif + +#ifdef CFG_SUPPORT_ANT_DIV +WLAN_STATUS +wlanoidAntDivCfg(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); +#endif + +WLAN_STATUS +wlanoidLinkDown(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidAbortScan(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetCSIControl(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +#ifdef CFG_DUMP_TXPOWR_TABLE +WLAN_STATUS +wlanoidGetTxPwrTbl(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); +#endif + +u32 wlanGetSupportedFeatureSet(IN P_GLUE_INFO_T prGlueInfo); + +WLAN_STATUS wlanSuspendLinkDown(IN P_GLUE_INFO_T prGlueInfo); + +#if CFG_SUPPORT_802_11K +WLAN_STATUS +wlanoidSendNeighborRequest(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + u32 u4SetBufferLen, + u32 *pu4SetInfoLen); +#endif + +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT +WLAN_STATUS +wlanoidSendBTMQuery(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + u32 u4SetBufferLen, + u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidPktProcessIT(IN P_ADAPTER_T prAdapter, + IN void *pvBuffer, + u32 u4BufferLen, + u32 *pu4InfoLen); +#endif + +u32 wlanoidIndicateBssInfo(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS batchSetCmd(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, IN u32 u4SetBufferLen, OUT u32 *pu4WritenLen); +WLAN_STATUS batchGetCmd(IN P_ADAPTER_T prAdapter, OUT void *pvQueryBuffer, IN u32 u4QueryBufferLen, OUT u32 *pu4QueryInfoLen); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/wlan_p2p.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/wlan_p2p.h new file mode 100644 index 00000000000000..2302cb252ccf70 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/include/wlan_p2p.h @@ -0,0 +1,265 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "wlan_p2p.h" + * \brief This file contains the declairations of Wi-Fi Direct command + * processing routines for MediaTek Inc. 802.11 Wireless LAN Adapters. + */ + +#ifndef _WLAN_P2P_H +#define _WLAN_P2P_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#if CFG_ENABLE_WIFI_DIRECT +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/* Service Discovery */ +typedef struct _PARAM_P2P_SEND_SD_RESPONSE { + PARAM_MAC_ADDRESS rReceiverAddr; + u8 fgNeedTxDoneIndication; + u8 ucChannelNum; + u16 u2PacketLength; + u8 aucPacketContent[0]; /*native 802.11 */ +} PARAM_P2P_SEND_SD_RESPONSE, *P_PARAM_P2P_SEND_SD_RESPONSE; + +typedef struct _PARAM_P2P_GET_SD_REQUEST { + PARAM_MAC_ADDRESS rTransmitterAddr; + u16 u2PacketLength; + u8 aucPacketContent[0]; /*native 802.11 */ +} PARAM_P2P_GET_SD_REQUEST, *P_PARAM_P2P_GET_SD_REQUEST; + +typedef struct _PARAM_P2P_GET_SD_REQUEST_EX { + PARAM_MAC_ADDRESS rTransmitterAddr; + u16 u2PacketLength; + u8 ucChannelNum; /* Channel Number Where SD Request is received. */ + u8 ucSeqNum; /* Get SD Request by sequence number. */ + u8 aucPacketContent[0]; /*native 802.11 */ +} PARAM_P2P_GET_SD_REQUEST_EX, *P_PARAM_P2P_GET_SD_REQUEST_EX; + +typedef struct _PARAM_P2P_SEND_SD_REQUEST { + PARAM_MAC_ADDRESS rReceiverAddr; + u8 fgNeedTxDoneIndication; + u8 ucVersionNum; /* Indicate the Service Discovery Supplicant Version. + */ + u16 u2PacketLength; + u8 aucPacketContent[0]; /*native 802.11 */ +} PARAM_P2P_SEND_SD_REQUEST, *P_PARAM_P2P_SEND_SD_REQUEST; + +/* Service Discovery 1.0. */ +typedef struct _PARAM_P2P_GET_SD_RESPONSE { + PARAM_MAC_ADDRESS rTransmitterAddr; + u16 u2PacketLength; + u8 aucPacketContent[0]; /*native 802.11 */ +} PARAM_P2P_GET_SD_RESPONSE, *P_PARAM_P2P_GET_SD_RESPONSE; + +/* Service Discovery 2.0. */ +typedef struct _PARAM_P2P_GET_SD_RESPONSE_EX { + PARAM_MAC_ADDRESS rTransmitterAddr; + u16 u2PacketLength; + u8 ucSeqNum; /* Get SD Response by sequence number. */ + u8 aucPacketContent[0]; /*native 802.11 */ +} PARAM_P2P_GET_SD_RESPONSE_EX, *P_PARAM_P2P_GET_SD_RESPONSE_EX; + +typedef struct _PARAM_P2P_TERMINATE_SD_PHASE { + PARAM_MAC_ADDRESS rPeerAddr; +} PARAM_P2P_TERMINATE_SD_PHASE, *P_PARAM_P2P_TERMINATE_SD_PHASE; + +/*! \brief Key mapping of BSSID */ +typedef struct _P2P_PARAM_KEY_T { + u32 u4Length; /*!< Length of structure */ + u32 u4KeyIndex; /*!< KeyID */ + u32 u4KeyLength; /*!< Key length in bytes */ + PARAM_MAC_ADDRESS arBSSID; /*!< MAC address */ + PARAM_KEY_RSC rKeyRSC; + /* Following add to change the original windows structure */ + u8 ucBssIdx; /* for specific P2P BSS interface. */ + u8 ucCipher; + u8 aucKeyMaterial[32]; /*!< Key content by above setting */ +} P2P_PARAM_KEY_T, *P_P2P_PARAM_KEY_T; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*--------------------------------------------------------------*/ +/* Routines to handle command */ +/*--------------------------------------------------------------*/ +/* WLAN_STATUS */ +/* wlanoidSetAddP2PKey(IN P_ADAPTER_T prAdapter, */ +/* IN void * pvSetBuffer, IN u32 u4SetBufferLen, OUT u32 * pu4SetInfoLen); */ + +/* WLAN_STATUS */ +/* wlanoidSetRemoveP2PKey(IN P_ADAPTER_T prAdapter, */ +/* IN void * pvSetBuffer, IN u32 u4SetBufferLen, OUT u32 * pu4SetInfoLen); */ + +WLAN_STATUS +wlanoidSetNetworkAddress(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetP2PMulticastList(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +/*--------------------------------------------------------------*/ +/* Service Discovery Subroutines */ +/*--------------------------------------------------------------*/ +WLAN_STATUS +wlanoidSendP2PSDRequest(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSendP2PSDResponse(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidGetP2PSDRequest(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidGetP2PSDResponse(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *puQueryInfoLen); + +WLAN_STATUS +wlanoidSetP2PTerminateSDPhase(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +#if CFG_SUPPORT_ANTI_PIRACY +WLAN_STATUS +wlanoidSetSecCheckRequest(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +/*WLAN_STATUS + * wlanoidGetSecCheckResponse(IN P_ADAPTER_T prAdapter, + * IN void * pvQueryBuffer, IN u32 u4QueryBufferLen, OUT u32 * + * pu4QueryInfoLen); + */ +#endif + +WLAN_STATUS +wlanoidSetNoaParam(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetOppPsParam(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetUApsdParam(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetP2pPowerSaveProfile(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidSetP2pSetNetworkAddress(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +WLAN_STATUS +wlanoidQueryP2pVersion(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS +wlanoidSetP2pSupplicantVersion(IN P_ADAPTER_T prAdapter, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER +WLAN_STATUS +wlanoidSetP2pWPSmode(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); +#endif + +#if CFG_SUPPORT_P2P_RSSI_QUERY +WLAN_STATUS +wlanoidQueryP2pRssi(IN P_ADAPTER_T prAdapter, + IN void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); +#endif + +u32 wlanoidAbortP2pScan(IN P_ADAPTER_T prAdapter, + OUT void *pvQueryBuffer, + IN u32 u4QueryBufferLen, + OUT u32 *pu4QueryInfoLen); + +WLAN_STATUS wlanoidSetP2pNetworkAddress(IN P_ADAPTER_T prAdapter, IN void *pvSetBuffer, IN u32 u4SetBufferLen, OUT u32 *pu4SetInfoLen); + +/*--------------------------------------------------------------*/ +/* Callbacks for event indication */ +/*--------------------------------------------------------------*/ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/aaa_fsm.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/aaa_fsm.c new file mode 100644 index 00000000000000..654727ce747d1b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/aaa_fsm.c @@ -0,0 +1,651 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "aaa_fsm.c" + * \brief This file defines the FSM for AAA MODULE. + * + * This file defines the FSM for AAA MODULE. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#if CFG_SUPPORT_AAA + +void aaaFsmRunEventTxReqTimeOut(IN P_ADAPTER_T prAdapter, IN unsigned long plParamPtr) +{ + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)plParamPtr; + P_BSS_INFO_T prBssInfo; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + ASSERT(prStaRec); + if (!prStaRec) { + return; + } + + DBGLOG(AAA, LOUD, "EVENT-TIMER: TX REQ TIMEOUT, Current Time = %d\n", + kalGetTimeTick()); + + /* Trigger statistics log if Auth/Assoc Tx timeout */ + wlanTriggerStatsLog(prAdapter, prAdapter->rWifiVar.u4StatsLogDuration); + + switch (prStaRec->eAuthAssocState) { + case AAA_STATE_SEND_AUTH2: + DBGLOG(AAA, ERROR, + "LOST EVENT ,Auth Tx done disappear for (%d)Ms\n", + TU_TO_MSEC(TX_AUTHENTICATION_RESPONSE_TIMEOUT_TU)); + + prStaRec->eAuthAssocState = AA_STATE_IDLE; + + /* NOTE(Kevin): Change to STATE_1 */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + +#if CFG_ENABLE_WIFI_DIRECT + if (prBssInfo->eNetworkType == NETWORK_TYPE_P2P) { + p2pRoleFsmRunEventAAATxFail(prAdapter, prStaRec, + prBssInfo); + } +#endif + break; + + default: + return; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will process the Rx Auth Request Frame and then + * trigger AAA FSM. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prSwRfb Pointer to the SW_RFB_T structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aaaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + u16 u2StatusCode; + u8 fgReplyAuth = false; + P_WLAN_AUTH_FRAME_T prAuthFrame = (P_WLAN_AUTH_FRAME_T)NULL; + + ASSERT(prAdapter); + + do { + prAuthFrame = (P_WLAN_AUTH_FRAME_T)prSwRfb->pvHeader; + +#if CFG_ENABLE_WIFI_DIRECT + prBssInfo = p2pFuncBSSIDFindBssInfo(prAdapter, + prAuthFrame->aucBSSID); + + /* 4 <1> Check P2P network conditions */ + + /* if (prBssInfo && prAdapter->fgIsP2PRegistered) */ + /* modify coding sytle to reduce indent */ + + if (!prAdapter->fgIsP2PRegistered) { + goto bow_proc; + } + + if (prBssInfo && prBssInfo->fgIsNetActive) { + /* 4 <1.1> Validate Auth Frame by Auth + * Algorithm/Transation Seq */ + if (WLAN_STATUS_SUCCESS == + authProcessRxAuth1Frame( + prAdapter, + prSwRfb, + prBssInfo->aucBSSID, + AUTH_ALGORITHM_NUM_OPEN_SYSTEM, + AUTH_TRANSACTION_SEQ_1, + &u2StatusCode)) { + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + DBGLOG(AAA, TRACE, + "process RxAuth status success\n"); + /* 4 <1.2> Validate Auth Frame for + * Network Specific Conditions */ + fgReplyAuth = p2pFuncValidateAuth( + prAdapter, prBssInfo, prSwRfb, + &prStaRec, &u2StatusCode); + +#if CFG_SUPPORT_802_11W + /* AP PMF, if PMF connection, ignore Rx + * auth */ + /* Certification 4.3.3.4 */ + if (rsnCheckBipKeyInstalled(prAdapter, + prStaRec)) { + DBGLOG(AAA, INFO, + "Drop RxAuth\n"); + return; + } +#endif + } else { + fgReplyAuth = true; + } + break; + } + } +#endif + +bow_proc: + return; + } while (false); + + if (prStaRec) { + /* update RCPI */ + ASSERT(prSwRfb->prRxStatusGroup3); + prStaRec->ucRCPI = + nicRxGetRcpiValueFromRxv(RCPI_MODE_WF0, prSwRfb); + } + /* 4 <3> Update STA_RECORD_T and reply Auth_2(Response to Auth_1) Frame + */ + if (fgReplyAuth) { + if (prStaRec) { + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + if (prStaRec->eAuthAssocState != + AA_STATE_IDLE) { + DBGLOG(AAA, + WARN, + "Previous AuthAssocState (%d) != IDLE.\n", + prStaRec->eAuthAssocState); + } + + prStaRec->eAuthAssocState = + AAA_STATE_SEND_AUTH2; + } else { + prStaRec->eAuthAssocState = AA_STATE_IDLE; + + /* NOTE(Kevin): Change to STATE_1 */ + cnmStaRecChangeState(prAdapter, prStaRec, + STA_STATE_1); + } + + /* Update the record join time. */ + GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); + + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = u2StatusCode; + + prStaRec->ucAuthAlgNum = AUTH_ALGORITHM_NUM_OPEN_SYSTEM; + } else { + /* NOTE(Kevin): We should have STA_RECORD_T if the + * status code was successful */ + ASSERT(!(u2StatusCode == STATUS_CODE_SUCCESSFUL) +#if CFG_SUPPORT_H2E + && + (u2StatusCode != WLAN_STATUS_SAE_HASH_TO_ELEMENT) +#endif + ); + } + + /* NOTE: Ignore the return status for AAA */ + /* 4 <4> Reply Auth */ + authSendAuthFrame(prAdapter, prStaRec, prBssInfo->ucBssIndex, + prSwRfb, AUTH_TRANSACTION_SEQ_2, + u2StatusCode); + + /*sta_rec might be removed when client list full, skip timer + * setting*/ + if (prStaRec) { + cnmTimerStopTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer); + /*ToDo:Init Timer to check get Auth Txdone avoid sta_rec + * not clear*/ + cnmTimerInitTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC) + aaaFsmRunEventTxReqTimeOut, + (unsigned long)prStaRec); + + cnmTimerStartTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC( + TX_AUTHENTICATION_RESPONSE_TIMEOUT_TU)); + } + } else if (prStaRec) { + cnmStaRecFree(prAdapter, prStaRec); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will process the Rx (Re)Association Request Frame and + * then trigger AAA FSM. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prSwRfb Pointer to the SW_RFB_T structure. + * + * @retval WLAN_STATUS_SUCCESS Always return success + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS aaaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + u16 u2StatusCode = STATUS_CODE_RESERVED; + u8 fgReplyAssocResp = false; + u8 fgSendSAQ = false; + + ASSERT(prAdapter); + DBGLOG(AAA, INFO, "aaaFsmRunEventRxAssoc\n"); + + do { + /* 4 <1> Check if we have the STA_RECORD_T for incoming Assoc + * Req */ + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + /* We should have the corresponding Sta Record. */ + if ((!prStaRec) || (!prStaRec->fgIsInUse)) { + /* Not to reply association response with failure code + * due to lack of STA_REC */ + break; + } + + if (!IS_CLIENT_STA(prStaRec)) { + break; + } + + DBGLOG(AAA, TRACE, + "RxAssoc enter ucStaState:%d, eAuthassocState:%d\n", + prStaRec->ucStaState, prStaRec->eAuthAssocState); + + if (prStaRec->ucStaState == STA_STATE_3) { + /* Do Reassocation */ + } else if ((prStaRec->ucStaState == STA_STATE_2) && + (prStaRec->eAuthAssocState == + AAA_STATE_SEND_AUTH2)) { + /* Normal case */ + } else { + DBGLOG(AAA, WARN, + "Previous AuthAssocState (%d) != SEND_AUTH2.\n", + prStaRec->eAuthAssocState); + + /* Maybe Auth Response TX fail, but actually it success. + */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + } + + /* update RCPI */ + ASSERT(prSwRfb->prRxStatusGroup3); + prStaRec->ucRCPI = + nicRxGetRcpiValueFromRxv(RCPI_MODE_WF0, prSwRfb); + + /* 4 <2> Check P2P network conditions */ +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && + (IS_STA_IN_P2P(prStaRec))) { + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, + prStaRec->ucBssIndex); + + if (prBssInfo->fgIsNetActive) { + /* 4 <2.1> Validate Assoc Req Frame and get + * Status Code */ + /* Check if for this BSSID */ + if (WLAN_STATUS_SUCCESS == + assocProcessRxAssocReqFrame( + prAdapter, prSwRfb, + &u2StatusCode)) { + if (u2StatusCode == + STATUS_CODE_SUCCESSFUL) { + /* 4 <2.2> Validate Assoc Req + * Frame for Network Specific + * Conditions */ + fgReplyAssocResp = + p2pFuncValidateAssocReq( + prAdapter, + prSwRfb, + (u16 *)& + u2StatusCode); + } else { + fgReplyAssocResp = true; + } + + break; + } + } + } +#endif + + return WLAN_STATUS_SUCCESS; /* To release the SW_RFB_T */ + } while (false); + + /* 4 <4> Update STA_RECORD_T and reply Assoc Resp Frame */ + if (fgReplyAssocResp) { + u16 u2IELength; + u8 *pucIE; + + cnmTimerStopTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer); + + if ((((P_WLAN_ASSOC_REQ_FRAME_T)(prSwRfb->pvHeader)) + ->u2FrameCtrl & + MASK_FRAME_TYPE) == MAC_FRAME_REASSOC_REQ) { + u2IELength = prSwRfb->u2PacketLen - + (u16)OFFSET_OF(WLAN_REASSOC_REQ_FRAME_T, + aucInfoElem[0]); + + pucIE = + ((P_WLAN_REASSOC_REQ_FRAME_T)(prSwRfb->pvHeader)) + ->aucInfoElem; + } else { + u2IELength = prSwRfb->u2PacketLen - + (u16)OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, + aucInfoElem[0]); + + pucIE = ((P_WLAN_ASSOC_REQ_FRAME_T)(prSwRfb->pvHeader)) + ->aucInfoElem; + } + + rlmProcessAssocReq(prAdapter, prSwRfb, pucIE, u2IELength); + + /* 4 <4.1> Assign Association ID */ + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && + (IS_STA_IN_P2P(prStaRec))) { + prBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, prStaRec->ucBssIndex); + if (p2pRoleFsmRunEventAAAComplete( + prAdapter, prStaRec, prBssInfo) == + WLAN_STATUS_SUCCESS) { + prStaRec->u2AssocId = + bssAssignAssocID(prStaRec); + /* prStaRec->eAuthAssocState = + * AA_STATE_IDLE; */ + /* NOTE(Kevin): for TX done */ + prStaRec->eAuthAssocState = + AAA_STATE_SEND_ASSOC2; + /* NOTE(Kevin): Method A: Change to + * STATE_3 before handle TX Done */ + /* cnmStaRecChangeState(prAdapter, + * prStaRec, STA_STATE_3); */ + } else { + /* Client List FULL. */ + u2StatusCode = STATUS_CODE_REQ_DECLINED; + + prStaRec->u2AssocId = 0; /* Invalid + * Association + * ID */ + + /* If(Re)association fail,remove sta + * record and use class error to handle + * sta */ + prStaRec->eAuthAssocState = + AA_STATE_IDLE; + + /* NOTE(Kevin): Better to change state + * here, not at TX Done */ + cnmStaRecChangeState(prAdapter, + prStaRec, + STA_STATE_2); + } + } +#endif + } else { +#if CFG_SUPPORT_802_11W + /* AP PMF */ + /* don't change state, just send assoc resp (NO need TX + * done, TIE + code30) and then SAQ */ + if (u2StatusCode == + STATUS_CODE_ASSOC_REJECTED_TEMPORARILY) { + DBGLOG(AAA, INFO, "AP send SAQ\n"); + fgSendSAQ = true; + } else +#endif + { + prStaRec->u2AssocId = 0; /* Invalid Association + * ID */ + + /* If (Re)association fail, remove sta record + * and use class error to handle sta */ + prStaRec->eAuthAssocState = AA_STATE_IDLE; + /* Remove from client list if it was previously + * associated */ + if ((prStaRec->ucStaState > STA_STATE_1) && + prAdapter->fgIsP2PRegistered && + (IS_STA_IN_P2P(prStaRec))) { + P_BSS_INFO_T prBssInfo = NULL; + + prBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, + prStaRec->ucBssIndex); + if (prBssInfo) { + DBGLOG(AAA, INFO, + "Remove client!\n"); + bssRemoveClient(prAdapter, + prBssInfo, + prStaRec); + } + } + /* NOTE(Kevin): Better to change state here, not + * at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, + STA_STATE_2); + } + } + + /* Update the record join time. */ + GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); + + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = u2StatusCode; + + /* NOTE: Ignore the return status for AAA */ + /* 4 <4.2> Reply Assoc Resp */ + assocSendReAssocRespFrame(prAdapter, prStaRec); + +#if CFG_SUPPORT_802_11W + /* AP PMF */ + if (fgSendSAQ) { + /* if PMF connection, and return code 30, send SAQ */ + rsnApStartSaQuery(prAdapter, prStaRec); + } +#endif + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will handle TxDone(Auth2/AssocReq) Event of AAA FSM. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prMsduInfo Pointer to the MSDU_INFO_T. + * @param[in] rTxDoneStatus Return TX status of the Auth1/Auth3/AssocReq frame. + * + * @retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +aaaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + DBGLOG(AAA, LOUD, "EVENT-TX DONE: Current Time = %ld\n", + kalGetTimeTick()); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if ((!prStaRec) || (!prStaRec->fgIsInUse)) { + return WLAN_STATUS_SUCCESS; /* For the case of replying ERROR + * STATUS CODE */ + + } + ASSERT(prStaRec->ucBssIndex <= MAX_BSS_INDEX); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + DBGLOG(AAA, LOUD, "TxDone ucStaState:%d, eAuthAssocState:%d\n", + prStaRec->ucStaState, prStaRec->eAuthAssocState); + + /* Trigger statistics log if Auth/Assoc Tx failed */ + if (rTxDoneStatus != TX_RESULT_SUCCESS) { + wlanTriggerStatsLog(prAdapter, + prAdapter->rWifiVar.u4StatsLogDuration); + } + + switch (prStaRec->eAuthAssocState) { + case AAA_STATE_SEND_AUTH2: { + /* Strictly check the outgoing frame is matched with current AA + * STATE */ + if (authCheckTxAuthFrame(prAdapter, prMsduInfo, + AUTH_TRANSACTION_SEQ_2) != + WLAN_STATUS_SUCCESS) { + break; + } + + cnmTimerStopTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer); + + if (prStaRec->u2StatusCode == STATUS_CODE_SUCCESSFUL) { + if (rTxDoneStatus == TX_RESULT_SUCCESS) { + /* NOTE(Kevin): Change to STATE_2 at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, + STA_STATE_2); + /* Error handle if can not complete the ASSOC + * flow */ + cnmTimerStartTimer( + prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(TX_ASSOCIATE_TIMEOUT_TU)); + } else { + prStaRec->eAuthAssocState = AA_STATE_IDLE; + + /* NOTE(Kevin): Change to STATE_1 */ + cnmStaRecChangeState(prAdapter, prStaRec, + STA_STATE_1); + +#if CFG_ENABLE_WIFI_DIRECT + if (prBssInfo->eNetworkType == + NETWORK_TYPE_P2P) { + p2pRoleFsmRunEventAAATxFail( + prAdapter, prStaRec, prBssInfo); + } +#endif + } + } + /* NOTE(Kevin): Ignore the TX Done Event of Auth Frame with + * Error Status Code */ + } break; + + case AAA_STATE_SEND_ASSOC2: { + /* Strictly check the outgoing frame is matched with current SAA + * STATE */ + if (assocCheckTxReAssocRespFrame(prAdapter, prMsduInfo) != + WLAN_STATUS_SUCCESS) { + break; + } + + if (prStaRec->u2StatusCode == STATUS_CODE_SUCCESSFUL) { + if (rTxDoneStatus == TX_RESULT_SUCCESS) { + prStaRec->eAuthAssocState = AA_STATE_IDLE; + + /* NOTE(Kevin): Change to STATE_3 at TX Done */ +#if CFG_ENABLE_WIFI_DIRECT + if (prBssInfo->eNetworkType == + NETWORK_TYPE_P2P) { + p2pRoleFsmRunEventAAASuccess( + prAdapter, prStaRec, prBssInfo); + } +#endif + } else { + prStaRec->eAuthAssocState = + AAA_STATE_SEND_AUTH2; + + /* NOTE(Kevin): Change to STATE_2 */ + cnmStaRecChangeState(prAdapter, prStaRec, + STA_STATE_2); + +#if CFG_ENABLE_WIFI_DIRECT + if (prBssInfo->eNetworkType == + NETWORK_TYPE_P2P) { + p2pRoleFsmRunEventAAATxFail( + prAdapter, prStaRec, prBssInfo); + } +#endif + } + } + /* NOTE(Kevin): Ignore the TX Done Event of Auth Frame with + * Error Status Code */ + } break; + + case AA_STATE_IDLE: + /* 2013-08-27 frog: Do nothing. + * Somtimes we may send Assoc Resp twice. (Rx Assoc Req before + * the first Assoc TX Done) The AssocState is changed to IDLE + * after first TX done. Free station record when IDLE is + * seriously wrong. + */ + /* 2017-01-12 Do nothing only when STA is in state 3 */ + /* Free the StaRec if found any unexpected status */ + if (prStaRec->ucStaState != STA_STATE_3) { + cnmStaRecFree(prAdapter, prStaRec); + } + break; + + default: + break; /* Ignore other cases */ + } + + DBGLOG(AAA, LOUD, "TxDone end ucStaState:%d, eAuthAssocState:%d\n", + prStaRec->ucStaState, prStaRec->eAuthAssocState); + + return WLAN_STATUS_SUCCESS; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/ais_fsm.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/ais_fsm.c new file mode 100644 index 00000000000000..0d9c4a7f39cad5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/ais_fsm.c @@ -0,0 +1,5354 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "aa_fsm.c" + * \brief This file defines the FSM for SAA and AAA MODULE. + * + * This file defines the FSM for SAA and AAA MODULE. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define AIS_ROAMING_CONNECTION_TRIAL_LIMIT 2 +#define AIS_JOIN_TIMEOUT 7 + +#define AIS_FSM_STATE_SEARCH_ACTION_PHASE_0 0 +#define AIS_FSM_STATE_SEARCH_ACTION_PHASE_1 1 +#define AIS_FSM_STATE_SEARCH_ACTION_PHASE_2 2 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +#if !DBG_DISABLE_ALL_LOG +static u8 *apucDebugAisState[AIS_STATE_NUM] = { + (u8 *)DISP_STRING("IDLE"), + (u8 *)DISP_STRING("SEARCH"), + (u8 *)DISP_STRING("SCAN"), + (u8 *)DISP_STRING("ONLINE_SCAN"), + (u8 *)DISP_STRING("LOOKING_FOR"), + (u8 *)DISP_STRING("WAIT_FOR_NEXT_SCAN"), + (u8 *)DISP_STRING("REQ_CHANNEL_JOIN"), + (u8 *)DISP_STRING("JOIN"), + (u8 *)DISP_STRING("JOIN_FAILURE"), + (u8 *)DISP_STRING("IBSS_ALONE"), + (u8 *)DISP_STRING("IBSS_MERGE"), + (u8 *)DISP_STRING("NORMAL_TR"), + (u8 *)DISP_STRING("DISCONNECTING"), + (u8 *)DISP_STRING("REQ_REMAIN_ON_CHANNEL"), + (u8 *)DISP_STRING("REMAIN_ON_CHANNEL") +}; +#endif +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +static void aisFsmRunEventScanDoneTimeOut(IN P_ADAPTER_T prAdapter, + unsigned long ulParam); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief the function is used to initialize the value of the connection + * settings for AIS network + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisInitializeConnectionSettings(IN P_ADAPTER_T prAdapter, + IN P_REG_INFO_T prRegInfo) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + u8 aucAnyBSSID[] = BC_BSSID; + u8 aucZeroMacAddr[] = NULL_MAC_ADDR; + int i = 0; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* Setup default values for operation */ + COPY_MAC_ADDR(prConnSettings->aucMacAddress, aucZeroMacAddr); + + prConnSettings->ucDelayTimeOfDisconnectEvent = + prAdapter->rWifiVar.ucDelayTimeOfDisconnect; + + COPY_MAC_ADDR(prConnSettings->aucBSSID, aucAnyBSSID); + prConnSettings->fgIsConnByBssidIssued = false; + + prConnSettings->fgIsConnReqIssued = false; + prConnSettings->fgIsDisconnectedByNonRequest = false; + + prConnSettings->ucSSIDLen = 0; + + prConnSettings->eOPMode = NET_TYPE_INFRA; + + prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; + + if (prRegInfo) { + prConnSettings->ucAdHocChannelNum = + (u8)nicFreq2ChannelNum(prRegInfo->u4StartFreq); + prConnSettings->eAdHocBand = + prRegInfo->u4StartFreq < 5000000 ? BAND_2G4 : BAND_5G; + prConnSettings->eAdHocMode = + (ENUM_PARAM_AD_HOC_MODE_T)(prRegInfo->u4AdhocMode); + } + + prConnSettings->eAuthMode = AUTH_MODE_OPEN; + + prConnSettings->eEncStatus = ENUM_ENCRYPTION_DISABLED; + + prConnSettings->fgIsScanReqIssued = false; + + /* MIB attributes */ + prConnSettings->u2BeaconPeriod = DOT11_BEACON_PERIOD_DEFAULT; + + prConnSettings->u2RTSThreshold = DOT11_RTS_THRESHOLD_DEFAULT; + + prConnSettings->u2DesiredNonHTRateSet = RATE_SET_ALL_ABG; + + /* prConnSettings->u4FreqInKHz; */ /* Center frequency */ + + /* Set U-APSD AC */ + prConnSettings->bmfgApsdEnAc = PM_UAPSD_NONE; + + secInit(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + /* Features */ + prConnSettings->fgIsEnableRoaming = false; +#if CFG_SUPPORT_ROAMING + if (prAdapter->rWifiVar.fgDisRoaming) { + prConnSettings->fgIsEnableRoaming = false; + } else { + prConnSettings->fgIsEnableRoaming = true; + } +#endif + + prConnSettings->fgIsAdHocQoSEnable = false; + +#if CFG_SUPPORT_802_11AC + prConnSettings->eDesiredPhyConfig = PHY_CONFIG_802_11ABGNAC; +#else + prConnSettings->eDesiredPhyConfig = PHY_CONFIG_802_11ABGN; +#endif + + /* Set default bandwidth modes */ + prConnSettings->uc2G4BandwidthMode = CONFIG_BW_20M; + prConnSettings->uc5GBandwidthMode = CONFIG_BW_20_40M; + + prConnSettings->rRsnInfo.ucElemId = 0x30; + prConnSettings->rRsnInfo.u2Version = 0x0001; + prConnSettings->rRsnInfo.u4GroupKeyCipherSuite = 0; + prConnSettings->rRsnInfo.u4GroupMgmtKeyCipherSuite = 0; + prConnSettings->rRsnInfo.u4PairwiseKeyCipherSuiteCount = 0; + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) + prConnSettings->rRsnInfo.au4PairwiseKeyCipherSuite[i] = 0; + prConnSettings->rRsnInfo.u4AuthKeyMgtSuiteCount = 0; + for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) + prConnSettings->rRsnInfo.au4AuthKeyMgtSuite[i] = 0; + prConnSettings->rRsnInfo.u2RsnCap = 0; + prConnSettings->rRsnInfo.fgRsnCapPresent = false; + prConnSettings->rRsnInfo.u2PmkidCnt = 0; + kalMemZero(prConnSettings->rRsnInfo.aucPmkidList, + (sizeof(u8) * MAX_NUM_SUPPORTED_PMKID * RSN_PMKID_LEN)); + prConnSettings->bss = NULL; + +#if CFG_SUPPORT_OWE + kalMemSet(&prConnSettings->rOweInfo, 0, sizeof(struct OWE_INFO_T)); +#endif +#if CFG_SUPPORT_H2E + kalMemSet(&prConnSettings->rRsnXE, 0, sizeof(struct RSNXE)); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief the function is used to initialize the value in AIS_FSM_INFO_T for + * AIS FSM operation + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmInit(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; + u8 i; + + DEBUGFUNC("aisFsmInit()"); + DBGLOG(SW1, INFO, "->aisFsmInit()\n"); + + /* avoid that the prAisBssInfo is realloc */ + if (prAdapter->prAisBssInfo != NULL) { + return; + } + + prAdapter->prAisBssInfo = prAisBssInfo = + cnmGetBssInfoAndInit(prAdapter, NETWORK_TYPE_AIS, false); + ASSERT(prAisBssInfo); + + /* update MAC address */ + COPY_MAC_ADDR(prAdapter->prAisBssInfo->aucOwnMacAddr, + prAdapter->rMyMacAddr); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + + /* 4 <1> Initiate FSM */ + prAisFsmInfo->ePreviousState = AIS_STATE_IDLE; + prAisFsmInfo->eCurrentState = AIS_STATE_IDLE; + + prAisFsmInfo->ucAvailableAuthTypes = 0; + + prAisFsmInfo->prTargetBssDesc = (P_BSS_DESC_T)NULL; + + prAisFsmInfo->ucSeqNumOfReqMsg = 0; + prAisFsmInfo->ucSeqNumOfChReq = 0; + prAisFsmInfo->ucSeqNumOfScanReq = 0; + + prAisFsmInfo->fgIsInfraChannelFinished = true; +#if CFG_SUPPORT_ROAMING + prAisFsmInfo->fgIsRoamingScanPending = false; +#endif + prAisFsmInfo->fgIsChannelRequested = false; + prAisFsmInfo->fgIsChannelGranted = false; + prAisFsmInfo->fgIsScanOidAborted = false; + + /* 4 <1.1> Initiate FSM - Timer INIT */ + cnmTimerInitTimer(prAdapter, &prAisFsmInfo->rBGScanTimer, + (PFN_MGMT_TIMEOUT_FUNC)aisFsmRunEventBGSleepTimeOut, + (unsigned long)NULL); + + cnmTimerInitTimer(prAdapter, &prAisFsmInfo->rBeaconLostTimer, + (PFN_MGMT_TIMEOUT_FUNC)aisFsmBeaconLostTimeOut, + (unsigned long)NULL); + + cnmTimerInitTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer, + (PFN_MGMT_TIMEOUT_FUNC)aisFsmRunEventIbssAloneTimeOut, + (unsigned long)NULL); + + cnmTimerInitTimer(prAdapter, &prAisFsmInfo->rIndicationOfDisconnectTimer, + (PFN_MGMT_TIMEOUT_FUNC)aisPostponedEventOfDisconnTimeout, + (unsigned long)NULL); + + cnmTimerInitTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer, + (PFN_MGMT_TIMEOUT_FUNC)aisFsmRunEventScanDoneTimeOut, + (unsigned long)NULL); + + cnmTimerInitTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer, + (PFN_MGMT_TIMEOUT_FUNC)aisFsmRunEventJoinTimeout, + (unsigned long)NULL); + + cnmTimerInitTimer(prAdapter, &prAisFsmInfo->rDeauthDoneTimer, + (PFN_MGMT_TIMEOUT_FUNC)aisFsmRunEventDeauthTimeout, + (unsigned long)NULL); + + /* 4 <1.2> Initiate PWR STATE */ + SET_NET_PWR_STATE_IDLE(prAdapter, prAisBssInfo->ucBssIndex); + + /* 4 <2> Initiate BSS_INFO_T - common part */ + BSS_INFO_INIT(prAdapter, prAisBssInfo); + COPY_MAC_ADDR(prAisBssInfo->aucOwnMacAddr, + prAdapter->rWifiVar.aucMacAddress); + + /* 4 <3> Initiate BSS_INFO_T - private part */ + /* TODO */ + prAisBssInfo->eBand = BAND_2G4; + prAisBssInfo->ucPrimaryChannel = 1; + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + prAisBssInfo->ucNss = + wlanGetSupportNss(prAdapter, prAisBssInfo->ucBssIndex); + prAisBssInfo->eDBDCBand = ENUM_BAND_0; +#if (CFG_HW_WMM_BY_BSS == 0) + prAisBssInfo->ucWmmQueSet = + (prAdapter->rWifiVar.ucDbdcMode == DBDC_MODE_DISABLED) ? + DBDC_5G_WMM_INDEX : + DBDC_2G_WMM_INDEX; +#endif + + /* 4 <4> Allocate MSDU_INFO_T for Beacon */ + prAisBssInfo->prBeacon = cnmMgtPktAlloc( + prAdapter, + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); + + if (prAisBssInfo->prBeacon) { + prAisBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; + prAisBssInfo->prBeacon->ucStaRecIndex = 0xFF; /* NULL STA_REC */ + } else { + ASSERT(0); + } + + prAisBssInfo->ucBMCWlanIndex = WTBL_RESERVED_ENTRY; + + for (i = 0; i < MAX_KEY_NUM; i++) { + prAisBssInfo->ucBMCWlanIndexS[i] = WTBL_RESERVED_ENTRY; + prAisBssInfo->ucBMCWlanIndexSUsed[i] = false; + prAisBssInfo->wepkeyUsed[i] = false; + } + + if (prAdapter->u4UapsdAcBmp == 0) { + prAdapter->u4UapsdAcBmp = CFG_INIT_UAPSD_AC_BMP; + /* ASSERT(prAdapter->u4UapsdAcBmp); */ + } + prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = + (u8)prAdapter->u4UapsdAcBmp; + prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = (u8)prAdapter->u4UapsdAcBmp; + prAisBssInfo->rPmProfSetupInfo.ucUapsdSp = (u8)prAdapter->u4MaxSpLen; + + /* request list initialization */ + LINK_INITIALIZE(&prAisFsmInfo->rPendingReqList); + + LINK_MGMT_INIT(&prAisSpecificBssInfo->rNeighborApList); +#if CFG_SUPPORT_802_11V + kalMemZero(&prAisSpecificBssInfo->rBTMParam, + sizeof(prAisSpecificBssInfo->rBTMParam)); +#endif +#if CFG_SUPPORT_802_11W + init_completion(&prAisBssInfo->rDeauthComp); + prAisBssInfo->encryptedDeauthIsInProcess = false; +#endif + /* DBGPRINTF("[2] ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x, + * ucUapsdSp:0x%x", */ + /* prAisBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC, */ + /* prAisBssInfo->rPmProfSetupInfo.ucBmpTriggerAC, */ + /* prAisBssInfo->rPmProfSetupInfo.ucUapsdSp); */ + + /* Bind NetDev & BssInfo */ + /* wlanBindBssIdxToNetInterface(prAdapter->prGlueInfo, NET_DEV_WLAN_IDX, + * prAisBssInfo->ucBssIndex); */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief the function is used to uninitialize the value in AIS_FSM_INFO_T for + * AIS FSM operation + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmUninit(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; + + DEBUGFUNC("aisFsmUninit()"); + DBGLOG(SW1, INFO, "->aisFsmUninit()\n"); + + /* avoid that the prAisBssInfo is double freed */ + if (prAdapter->prAisBssInfo == NULL) { + return; + } + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = prAdapter->prAisBssInfo; + prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + + /* 4 <1> Stop all timers */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rBGScanTimer); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rBeaconLostTimer); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIndicationOfDisconnectTimer); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); + + /* 4 <2> flush pending request */ + aisFsmFlushRequest(prAdapter); + + /* 4 <3> Reset driver-domain BSS-INFO */ + if (prAisBssInfo) { + if (prAisBssInfo->prBeacon) { + cnmMgtPktFree(prAdapter, prAisBssInfo->prBeacon); + prAisBssInfo->prBeacon = NULL; + } + + cnmFreeBssInfo(prAdapter, prAisBssInfo); + prAdapter->prAisBssInfo = NULL; + } + +#if CFG_SUPPORT_802_11W + rsnStopSaQuery(prAdapter); +#endif + /* end Support AP Selection */ + LINK_MGMT_UNINIT(&prAisSpecificBssInfo->rNeighborApList, NEIGHBOR_AP_T, + VIR_MEM_TYPE); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Initialization of JOIN STATE + * + * @param[in] prBssDesc The pointer of BSS_DESC_T which is the BSS we will try + * to join with. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmStateInit_JOIN(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_STA_RECORD_T prStaRec; + P_MSG_JOIN_REQ_T prJoinReqMsg; + + DEBUGFUNC("aisFsmStateInit_JOIN()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = prAdapter->prAisBssInfo; + prAisSpecificBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + ASSERT(prBssDesc); + + /* 4 <1> We are going to connect to this BSS. */ + prBssDesc->fgIsConnecting = true; + + /* 4 <2> Setup corresponding STA_RECORD_T */ + prStaRec = bssCreateStaRecFromBssDesc(prAdapter, STA_TYPE_LEGACY_AP, + prAdapter->prAisBssInfo->ucBssIndex, + prBssDesc); + + prAisFsmInfo->prTargetStaRec = prStaRec; + + /* 4 <2.1> sync. to firmware domain */ + /* 20200622 frog: Always sync STATE 1 to FW. + * This is for same STA reassoc case. + * STA need stop TX/RX and back to STATE_1 when auth/reassoc. + */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + /* 4 <3> Update ucAvailableAuthTypes which we can choice during SAA */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + prStaRec->fgIsReAssoc = false; + + /*Fill Auth Type */ + prAisFsmInfo->ucAvailableAuthTypes = + (u8)prAdapter->prGlueInfo->rWpaInfo.u4AuthAlg; + DBGLOG(AIS, INFO, "JOIN INIT: Auth Algorithm :%d\n", + prAisFsmInfo->ucAvailableAuthTypes); + /* TODO(tyhsu): Assume that Roaming Auth Type is equal to + * ConnSettings eAuthMode */ + prAisSpecificBssInfo->ucRoamingAuthTypes = + prAisFsmInfo->ucAvailableAuthTypes; + + prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; + + /* Update Bss info before join */ + prAisBssInfo->eBand = prBssDesc->eBand; + prAisBssInfo->ucPrimaryChannel = prBssDesc->ucChannelNum; + } else { + ASSERT(prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE); + DBGLOG(AIS, LOUD, "JOIN INIT: AUTH TYPE = %d for Roaming\n", + prAisSpecificBssInfo->ucRoamingAuthTypes); + + prStaRec->fgIsReAssoc = true; /* We do roaming while the medium + is connected */ + prAisFsmInfo->ucAvailableAuthTypes = + (u8)prAdapter->prGlueInfo->rWpaInfo.u4AuthAlg; + + DBGLOG(AIS, INFO, "JOIN INIT: Auth Algorithm for Roaming:%d\n", + prAisFsmInfo->ucAvailableAuthTypes); + prStaRec->ucTxAuthAssocRetryLimit = + TX_AUTH_ASSOCI_RETRY_LIMIT_FOR_ROAMING; + } + + /* 4 <4> Use an appropriate Authentication Algorithm Number among the + * ucAvailableAuthTypes */ + if (prAisFsmInfo->ucAvailableAuthTypes & (u8)AUTH_TYPE_OPEN_SYSTEM) { + DBGLOG( + AIS, LOUD, + "JOIN INIT: Try to do Authentication with AuthType == OPEN_SYSTEM.\n"); + prAisFsmInfo->ucAvailableAuthTypes &= ~(u8)AUTH_TYPE_OPEN_SYSTEM; + + prStaRec->ucAuthAlgNum = (u8)AUTH_ALGORITHM_NUM_OPEN_SYSTEM; + } else if (prAisFsmInfo->ucAvailableAuthTypes & (u8)AUTH_TYPE_SHARED_KEY) { + DBGLOG( + AIS, LOUD, + "JOIN INIT: Try to do Authentication with AuthType == SHARED_KEY.\n"); + + prAisFsmInfo->ucAvailableAuthTypes &= ~(u8)AUTH_TYPE_SHARED_KEY; + + prStaRec->ucAuthAlgNum = (u8)AUTH_ALGORITHM_NUM_SHARED_KEY; + } else if (prAisFsmInfo->ucAvailableAuthTypes & + (u8)AUTH_TYPE_FAST_BSS_TRANSITION) { + DBGLOG(AIS, LOUD, + "JOIN INIT: Try to do Authentication with AuthType == " + "FAST_BSS_TRANSITION.\n"); + + prAisFsmInfo->ucAvailableAuthTypes &= + ~(u8)AUTH_TYPE_FAST_BSS_TRANSITION; + + prStaRec->ucAuthAlgNum = (u8)AUTH_ALGORITHM_NUM_FAST_BSS_TRANSITION; +#if CFG_SUPPORT_SAE + } else if (prAisFsmInfo->ucAvailableAuthTypes & (u8)AUTH_TYPE_SAE) { + DBGLOG(AIS, LOUD, + "JOIN INIT: Try to do Authentication with AuthType == SAE.\n"); + + prAisFsmInfo->ucAvailableAuthTypes &= ~(u8)AUTH_TYPE_SAE; + + prStaRec->ucAuthAlgNum = (u8)AUTH_ALGORITHM_NUM_SAE; +#endif + } else { + ASSERT(0); + } + + /* 4 <5> Overwrite Connection Setting for eConnectionPolicy == ANY (Used + * by Assoc Req) */ + if (prBssDesc->ucSSIDLen) { + COPY_SSID(prConnSettings->aucSSID, prConnSettings->ucSSIDLen, + prBssDesc->aucSSID, prBssDesc->ucSSIDLen); + } + /* 4 <6> Send a Msg to trigger SAA to start JOIN process. */ + prJoinReqMsg = (P_MSG_JOIN_REQ_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_JOIN_REQ_T)); + if (!prJoinReqMsg) { + ASSERT(0); /* Can't trigger SAA FSM */ + return; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + nicRxClearFrag(prAdapter, prStaRec); + prConnSettings->fgIsConnInitialized = true; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prJoinReqMsg, + MSG_SEND_METHOD_BUF); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Retry JOIN for AUTH_MODE_AUTO_SWITCH + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @retval true We will retry JOIN + * @retval false We will not retry JOIN + */ +/*----------------------------------------------------------------------------*/ +u8 aisFsmStateInit_RetryJOIN(IN P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_JOIN_REQ_T prJoinReqMsg; + + DEBUGFUNC("aisFsmStateInit_RetryJOIN()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* Retry other AuthType if possible */ + if (!prAisFsmInfo->ucAvailableAuthTypes) { + return false; + } + + if (prAisFsmInfo->ucAvailableAuthTypes & (u8)AUTH_TYPE_SHARED_KEY) { + DBGLOG( + AIS, INFO, + "RETRY JOIN INIT: Retry Authentication with AuthType == SHARED_KEY.\n"); + + prAisFsmInfo->ucAvailableAuthTypes &= ~(u8)AUTH_TYPE_SHARED_KEY; + + prStaRec->ucAuthAlgNum = (u8)AUTH_ALGORITHM_NUM_SHARED_KEY; + } else { + DBGLOG( + AIS, ERROR, + "RETRY JOIN INIT: Retry Authentication with Unexpected AuthType.\n"); + ASSERT(0); + } + + prAisFsmInfo->ucAvailableAuthTypes = 0; /* No more available Auth Types + */ + + /* Trigger SAA to start JOIN process. */ + prJoinReqMsg = (P_MSG_JOIN_REQ_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_JOIN_REQ_T)); + if (!prJoinReqMsg) { + ASSERT(0); /* Can't trigger SAA FSM */ + return false; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prJoinReqMsg, + MSG_SEND_METHOD_BUF); + + return true; +} + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/*! + * @brief State Initialization of AIS_STATE_IBSS_ALONE + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmStateInit_IBSS_ALONE(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = prAdapter->prAisBssInfo; + + /* 4 <1> Check if IBSS was created before ? */ + if (prAisBssInfo->fgIsBeaconActivated) { + /* 4 <2> Start IBSS Alone Timer for periodic SCAN and then + * SEARCH */ + cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer, + SEC_TO_MSEC(AIS_IBSS_ALONE_TIMEOUT_SEC)); + } + + aisFsmCreateIBSS(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief State Initialization of AIS_STATE_IBSS_MERGE + * + * @param[in] prBssDesc The pointer of BSS_DESC_T which is the IBSS we will try + * to merge with. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmStateInit_IBSS_MERGE(IN P_ADAPTER_T prAdapter, + P_BSS_DESC_T prBssDesc) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + ASSERT(prBssDesc); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = prAdapter->prAisBssInfo; + + /* 4 <1> We will merge with to this BSS immediately. */ + prBssDesc->fgIsConnecting = false; + prBssDesc->fgIsConnected = true; + + /* 4 <2> Setup corresponding STA_RECORD_T */ + prStaRec = bssCreateStaRecFromBssDesc(prAdapter, STA_TYPE_ADHOC_PEER, + prAdapter->prAisBssInfo->ucBssIndex, + prBssDesc); + + prStaRec->fgIsMerging = true; + + prAisFsmInfo->prTargetStaRec = prStaRec; + + /* 4 <2.1> sync. to firmware domain */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + /* 4 <3> IBSS-Merge */ + aisFsmMergeIBSS(prAdapter, prStaRec); +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process of JOIN Abort + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmStateAbort_JOIN(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_JOIN_ABORT_T prJoinAbortMsg; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* 1. Abort JOIN process */ + prJoinAbortMsg = (P_MSG_JOIN_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_JOIN_ABORT_T)); + if (!prJoinAbortMsg) { + ASSERT(0); /* Can't abort SAA FSM */ + return; + } + + prJoinAbortMsg->rMsgHdr.eMsgId = MID_AIS_SAA_FSM_ABORT; + prJoinAbortMsg->ucSeqNum = prAisFsmInfo->ucSeqNumOfReqMsg; + prJoinAbortMsg->prStaRec = prAisFsmInfo->prTargetStaRec; + + scanRemoveConnFlagOfBssDescByBssid( + prAdapter, prAisFsmInfo->prTargetStaRec->aucMacAddr); + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prJoinAbortMsg, + MSG_SEND_METHOD_BUF); + + /* 2. Return channel privilege */ + aisFsmReleaseCh(prAdapter); + + /* 3.1 stop join timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); + + /* 3.2 reset local variable */ + prAisFsmInfo->fgIsInfraChannelFinished = true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process of SCAN Abort + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmStateAbort_SCAN(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_SCN_SCAN_CANCEL prScanCancelMsg; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + DBGLOG(AIS, STATE, "aisFsmStateAbort_SCAN\n"); + + /* Abort JOIN process. */ + prScanCancelMsg = (P_MSG_SCN_SCAN_CANCEL)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); + if (!prScanCancelMsg) { + ASSERT(0); /* Can't abort SCN FSM */ + return; + } + + prScanCancelMsg->rMsgHdr.eMsgId = MID_AIS_SCN_SCAN_CANCEL; + prScanCancelMsg->ucSeqNum = prAisFsmInfo->ucSeqNumOfScanReq; + prScanCancelMsg->ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex; + prScanCancelMsg->fgIsChannelExt = false; + if (prAisFsmInfo->fgIsScanOidAborted) { + prScanCancelMsg->fgIsOidRequest = true; + prAisFsmInfo->fgIsScanOidAborted = false; + } + /* unbuffered message to guarantee scan is cancelled in sequence */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prScanCancelMsg, + MSG_SEND_METHOD_UNBUF); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process of NORMAL_TR Abort + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmStateAbort_NORMAL_TR(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* TODO(Kevin): Do abort other MGMT func */ + + /* 1. Release channel to CNM */ + aisFsmReleaseCh(prAdapter); + + /* 2.1 stop join timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); + + /* 2.2 reset local variable */ + prAisFsmInfo->fgIsInfraChannelFinished = true; +} + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process of NORMAL_TR Abort + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmStateAbort_IBSS(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_DESC_T prBssDesc; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* reset BSS-DESC */ + if (prAisFsmInfo->prTargetStaRec) { + prBssDesc = scanSearchBssDescByTA( + prAdapter, prAisFsmInfo->prTargetStaRec->aucMacAddr); + + if (prBssDesc) { + prBssDesc->fgIsConnected = false; + prBssDesc->fgIsConnecting = false; + } + } + /* release channel privilege */ + aisFsmReleaseCh(prAdapter); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief The Core FSM engine of AIS(Ad-hoc, Infra STA) + * + * @param[in] eNextState Enum value of next AIS STATE + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmSteps(IN P_ADAPTER_T prAdapter, ENUM_AIS_STATE_T eNextState) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_DESC_T prBssDesc; + P_MSG_CH_REQ_T prMsgChReq; + P_MSG_SCN_SCAN_REQ_V2 prScanReqMsg; + P_AIS_REQ_HDR_T prAisReq; + ENUM_BAND_T eBand; + u8 ucChannel; + u16 u2ScanIELen; + u8 fgIsTransition = (u8)false; +#if CFG_SUPPORT_DBDC + CNM_DBDC_CAP_T rDbdcCap; +#if CFG_SUPPORT_DBDC_TC6 + u8 ucBssIndex; + P_BSS_INFO_T prBssInfo; + u8 fgDiffBandExist = false; +#endif +#endif + + DEBUGFUNC("aisFsmSteps()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = prAdapter->prAisBssInfo; + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + do { + /* Do entering Next State */ + prAisFsmInfo->ePreviousState = prAisFsmInfo->eCurrentState; + + // DBGLOG(AIS, STATE, "[AIS]TRANSITION: [%s] -> [%s]\n", + // apucDebugAisState[prAisFsmInfo->eCurrentState], + // apucDebugAisState[eNextState]); + + /* NOTE(Kevin): This is the only place to change the + * eCurrentState(except initial) */ + prAisFsmInfo->eCurrentState = eNextState; + + fgIsTransition = (u8)false; + + /* Do tasks of the State that we just entered */ + switch (prAisFsmInfo->eCurrentState) { + /* NOTE(Kevin): we don't have to rearrange the sequence of + * following switch case. Instead I would like to use a common + * lookup table of array of function pointer to speed up state + * search. + */ + case AIS_STATE_IDLE: + if (prAisFsmInfo->ePreviousState != prAisFsmInfo->eCurrentState) { + prConnSettings->fgIsConnInitialized = false; + } + + prAisReq = aisFsmGetNextRequest(prAdapter); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rBeaconLostTimer); + + if (prAisReq == NULL || + prAisReq->eReqType == AIS_REQUEST_RECONNECT) { + if (prConnSettings->fgIsConnReqIssued == true && + prConnSettings->fgIsDisconnectedByNonRequest == false) { + prAisFsmInfo->fgTryScan = true; + + if (!IS_NET_ACTIVE(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex)) { + SET_NET_ACTIVE(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex); + /* sync with firmware */ + nicActivateNetwork(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex); + } + + SET_NET_PWR_STATE_ACTIVE( + prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + prAisBssInfo->fgIsNetRequestInActive = false; + + /* reset trial count */ + prAisFsmInfo->ucConnTrialCount = 0; + + eNextState = AIS_STATE_SEARCH; + fgIsTransition = true; + } else { + SET_NET_PWR_STATE_IDLE(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex); + + /* sync with firmware */ + prAisBssInfo->fgIsNetRequestInActive = true; + if (prAisBssInfo->fgIsPNOEnable) { + DBGLOG( + BSS, INFO, + "[BSSidx][Network]=%d " + "PNOEnable&&OP_MODE_INFRASTRUCTURE,KEEP ACTIVE\n", + prAisBssInfo->ucBssIndex); + } else { + UNSET_NET_ACTIVE(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex); + nicDeactivateNetwork( + prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + } + + /* check for other pending request */ + if (prAisReq && + (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, + true) == true)) { + wlanClearScanningResult(prAdapter); + eNextState = AIS_STATE_SCAN; + + fgIsTransition = true; + } + } + + if (prAisReq) { + /* free the message */ + cnmMemFree(prAdapter, prAisReq); + } + } else if (prAisReq->eReqType == AIS_REQUEST_SCAN) { +#if CFG_SUPPORT_ROAMING + prAisFsmInfo->fgIsRoamingScanPending = false; +#endif + wlanClearScanningResult(prAdapter); + + eNextState = AIS_STATE_SCAN; + fgIsTransition = true; + + /* free the message */ + cnmMemFree(prAdapter, prAisReq); + } else if (prAisReq->eReqType == AIS_REQUEST_ROAMING_CONNECT || + prAisReq->eReqType == AIS_REQUEST_ROAMING_SEARCH) { + /* ignore */ + /* free the message */ + cnmMemFree(prAdapter, prAisReq); + } else if (prAisReq->eReqType == AIS_REQUEST_REMAIN_ON_CHANNEL) { + eNextState = AIS_STATE_REQ_REMAIN_ON_CHANNEL; + fgIsTransition = true; + + /* free the message */ + cnmMemFree(prAdapter, prAisReq); + } + + prAisFsmInfo->u4SleepInterval = AIS_BG_SCAN_INTERVAL_MIN_SEC; + + break; + + case AIS_STATE_SEARCH: + /* 4 <1> Search for a matched candidate and save it to + * prTargetBssDesc. */ + prBssDesc = scanSearchBssDescByPolicy( + prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + /* we are under Roaming Condition. */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + if (prAisFsmInfo->ucConnTrialCount > + AIS_ROAMING_CONNECTION_TRIAL_LIMIT) { +#if CFG_SUPPORT_ROAMING + roamingFsmRunEventFail(prAdapter, + ROAMING_FAIL_REASON_CONNLIMIT); +#endif + /* reset retry count */ + prAisFsmInfo->ucConnTrialCount = 0; + + /* abort connection trial */ + prConnSettings->fgIsConnReqIssued = false; + eNextState = AIS_STATE_NORMAL_TR; + fgIsTransition = true; + + break; + } + } + /* 4 <2> We are not under Roaming Condition. */ + if (prAisBssInfo->eConnectionState == + PARAM_MEDIA_STATE_DISCONNECTED) { + /* 4 <2.a> If we have the matched one */ + if (prBssDesc) { + /* 4 <A> Stored the Selected BSS + * security cipher. */ + /* or later asoc req compose IE */ + prAisBssInfo->u4RsnSelectedGroupCipher = + prBssDesc->u4RsnSelectedGroupCipher; + prAisBssInfo->u4RsnSelectedPairwiseCipher = + prBssDesc->u4RsnSelectedPairwiseCipher; + prAisBssInfo->u4RsnSelectedAKMSuite = + prBssDesc->u4RsnSelectedAKMSuite; +#if (CFG_HW_WMM_BY_BSS == 1) + prAisBssInfo->eBand = prBssDesc->eBand; + if (prAisBssInfo->fgIsWmmInited == false) { + prAisBssInfo->ucWmmQueSet = + cnmWmmIndexDecision(prAdapter, prAisBssInfo); + } +#endif +#if CFG_SUPPORT_DBDC +#if CFG_SUPPORT_DBDC_TC6 + /* DBDC case: SAP exists, but STA is + * going to connect to AP check current + * existing BSS to decide enable DBDC or + * not + */ + fgDiffBandExist = false; + + for (ucBssIndex = 0; ucBssIndex < HW_BSSID_NUM; + ucBssIndex++) { + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + + if (!prBssInfo->fgIsInUse || + !prBssInfo->fgIsNetActive || + (prBssInfo->eConnectionState != + PARAM_MEDIA_STATE_CONNECTED && + prBssInfo->eCurrentOPMode != + OP_MODE_ACCESS_POINT)) { + continue; + } + + if (prBssInfo->eBand != BAND_2G4 && + prBssInfo->eBand != BAND_5G) { + continue; + } + + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT && + prBssInfo->eBand != prBssDesc->eBand) { + fgDiffBandExist = true; + DBGLOG( + CNM, INFO, + "[DBDC] GO/SAP[%d] exists on different band[%d] \n", + prBssInfo->ucBssIndex, prBssInfo->eBand); + + /* Planing to Enable + * DBDC */ + if (timerPendingTimer( + &prAdapter->rWifiVar + .rDBDCDisableCountdownTimer)) { + cnmTimerStopTimer( + prAdapter, + &prAdapter->rWifiVar + .rDBDCDisableCountdownTimer); + } + + /* only stop pening + * Switch Guard Timer + * when DBDC is being + * disabled */ + if (timerPendingTimer( + &prAdapter->rWifiVar.rDBDCSwitchGuardTimer) + && + !prAdapter->rWifiVar.fgDbDcModeEn) { + cnmTimerStopTimer( + prAdapter, + &prAdapter->rWifiVar.rDBDCSwitchGuardTimer); + } + + if (!prAdapter->rWifiVar.fgDbDcModeEn) { + /* Enable DBDC + * only when + * DBDC is + * disable Do + * nothing if + * DBDC is + * already + * enable + */ + cnmUpdateDbdcSetting(prAdapter, true); + + /* Start Switch + * Guard Time */ + DBGLOG( + CNM, INFO, + "Start DBDC Switch Guard timer for DBDC Enable\n"); + cnmTimerStartTimer( + prAdapter, + &prAdapter->rWifiVar.rDBDCSwitchGuardTimer, + DBDC_SWITCH_GUARD_TIME); + } + break; + } + } + + if (timerPendingTimer( + &prAdapter->rWifiVar.rDBDCDisableCountdownTimer) && + !fgDiffBandExist) { + /* DBDC Disable CountDown timer + * is on-going however, DBDC + * disable is confirmed + */ + DBGLOG(CNM, INFO, "Confirm to Disable DBDC\n"); + cnmTimerStopTimer( + prAdapter, + &prAdapter->rWifiVar.rDBDCDisableCountdownTimer); + cnmDbdcDecision(prAdapter, + DBDC_DECISION_TIMER_DISABLE_COUNT_DOWN); + } + + cnmTimerStartTimer( + prAdapter, + &prAdapter->rWifiVar.rDBDCAisConnectCountDown, + DBDC_AIS_CONNECT_COUNTDOWN_TIME); + + if (prAdapter->rCnmInfo.fgSkipDbdcDisable) { + prAdapter->rCnmInfo.fgSkipDbdcDisable = false; + } +#else + cnmDbdcEnableDecision(prAdapter, prAisBssInfo->ucBssIndex, + prBssDesc->eBand); +#endif + cnmGetDbdcCapability( + prAdapter, prAisBssInfo->ucBssIndex, prBssDesc->eBand, + prBssDesc->ucChannelNum, + wlanGetSupportNss(prAdapter, prAisBssInfo->ucBssIndex), + &rDbdcCap); + + prAisBssInfo->eDBDCBand = ENUM_BAND_AUTO; + prAisBssInfo->ucNss = rDbdcCap.ucNss; +#if (CFG_HW_WMM_BY_BSS == 0) + prAisBssInfo->ucWmmQueSet = rDbdcCap.ucWmmSetIndex; +#endif +#endif + /* 4 <B> Do STATE transition and update + * current Operation Mode. */ + if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) { + prAisBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; + + /* Record the target BSS_DESC_T + * for next STATE. */ + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + /* Transit to channel acquire */ + eNextState = AIS_STATE_REQ_CHANNEL_JOIN; + fgIsTransition = true; + + /* increase connection trial + * count */ + prAisFsmInfo->ucConnTrialCount++; + } +#if CFG_SUPPORT_ADHOC + else if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + + /* Record the target BSS_DESC_T + * for next STATE. */ + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + eNextState = AIS_STATE_IBSS_MERGE; + fgIsTransition = true; + } +#endif + else { + ASSERT(0); + eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; + fgIsTransition = true; + } + } else { + /* 4 <2.b> If we don't have the matched one */ +#if CFG_SUPPORT_DBDC_TC6 + if (prAdapter->rCnmInfo.fgSkipDbdcDisable) { + /* Beacon timeout */ + prAdapter->rCnmInfo.fgSkipDbdcDisable = false; + DBGLOG( + CNM, INFO, + "[DBDC] Beacon timeout: Keep current DBDC Status [%s] \n", + prAdapter->rWifiVar.fgDbDcModeEn ? "Enable" : + "Disable"); + } +#endif + /* increase connection trial count for + * infrastructure connection */ + if (prConnSettings->eOPMode == NET_TYPE_INFRA) { + prAisFsmInfo->ucConnTrialCount++; + } + + /* 4 <A> Try to SCAN */ + if (prAisFsmInfo->fgTryScan) { + eNextState = AIS_STATE_LOOKING_FOR; + + fgIsTransition = true; + } + /* 4 <B> We've do SCAN already, now wait + in some STATE. */ + else { + eNextState = aisFsmStateSearchAction( + prAdapter, AIS_FSM_STATE_SEARCH_ACTION_PHASE_0); + fgIsTransition = true; + } + } + } else { + /* 4 <3> We are under Roaming Condition. */ + /* prAdapter->eConnectionState == + MEDIA_STATE_CONNECTED. */ + /* 4 <3.a> This BSS_DESC_T is our AP. */ + /* NOTE(Kevin 2008/05/16): Following cases will + * go back to NORMAL_TR. CASE I: During Roaming, + * APP(WZC/NDISTEST) change the connection + * settings. That make we can NOT match + * the original AP, so the prBssDesc is NULL. + * CASE II: The same reason as CASE I. Because + * APP change the eOPMode to other network type + * in connection setting (e.g. NET_TYPE_IBSS), + * so the BssDesc become the IBSS node. (For + * CASE I/II, before WZC/NDISTEST set the + * OID_SSID, it will change other parameters in + * connection setting first. So if we do roaming + * at the same time, it will hit these cases.) + * + * CASE III: Normal case, we can't find other + * candidate to roam out, so only the current AP + * will be matched. + * + * CASE VI: Timestamp of the current AP might be + * reset + */ + if (prAisBssInfo->ucReasonOfDisconnect != + DISCONNECT_REASON_CODE_REASSOCIATION && + ((!prBssDesc) || /* CASE I */ + (prBssDesc->eBSSType != + BSS_TYPE_INFRASTRUCTURE) || /* CASE II */ + (prBssDesc->fgIsConnected) || /* CASE III + */ + (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, + prAisBssInfo->aucBSSID))) /* CASE VI */) { +#if DBG + if ((prBssDesc) && (prBssDesc->fgIsConnected)) { + ASSERT(EQUAL_MAC_ADDR(prBssDesc->aucBSSID, + prAisBssInfo->aucBSSID)); + } +#endif + /* We already associated with + * it, go back to NORMAL_TR */ + /* TODO(Kevin): Roaming Fail */ +#if CFG_SUPPORT_ROAMING + roamingFsmRunEventFail(prAdapter, + ROAMING_FAIL_REASON_NOCANDIDATE); +#endif + + /* Retreat to NORMAL_TR state */ + eNextState = AIS_STATE_NORMAL_TR; + fgIsTransition = true; + } else { + /* 4 <3.b> Try to roam out for JOIN this + BSS_DESC_T. */ + if (prBssDesc == NULL) { + fgIsTransition = true; + eNextState = aisFsmStateSearchAction( + prAdapter, AIS_FSM_STATE_SEARCH_ACTION_PHASE_1); + } else { + aisFsmStateSearchAction( + prAdapter, AIS_FSM_STATE_SEARCH_ACTION_PHASE_2); + /* 4 <A> Record the target + * BSS_DESC_T for next STATE. */ + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + /* tyhsu: increase connection + * trial count */ + prAisFsmInfo->ucConnTrialCount++; + + /* set NSS for re-assoc */ + prAisBssInfo->ucNss = prAdapter->rWifiVar.ucNSS; + + /* Transit to channel acquire */ + eNextState = AIS_STATE_REQ_CHANNEL_JOIN; + fgIsTransition = true; + } + } + } + + break; + + case AIS_STATE_WAIT_FOR_NEXT_SCAN: + + DBGLOG(AIS, LOUD, "SCAN: Idle Begin - Current Time = %u\n", + kalGetTimeTick()); + + cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rBGScanTimer, + SEC_TO_MSEC(prAisFsmInfo->u4SleepInterval)); + + SET_NET_PWR_STATE_IDLE(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex); + + if (prAisFsmInfo->u4SleepInterval < AIS_BG_SCAN_INTERVAL_MAX_SEC) { + prAisFsmInfo->u4SleepInterval <<= 1; + } + + break; + + case AIS_STATE_SCAN: + case AIS_STATE_ONLINE_SCAN: + case AIS_STATE_LOOKING_FOR: + + if (!IS_NET_ACTIVE(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex)) { + SET_NET_ACTIVE(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + /* sync with firmware */ + nicActivateNetwork(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex); + prAisBssInfo->fgIsNetRequestInActive = false; + } + + /* IE length decision */ + if (prAisFsmInfo->u4ScanIELength > 0) { + u2ScanIELen = (u16)prAisFsmInfo->u4ScanIELength; + } else { +#if CFG_SUPPORT_WPS2 + u2ScanIELen = prAdapter->prGlueInfo->u2WSCIELen; +#else + u2ScanIELen = 0; +#endif + } + + prScanReqMsg = (P_MSG_SCN_SCAN_REQ_V2)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, + OFFSET_OF(MSG_SCN_SCAN_REQ_V2, aucIE) + u2ScanIELen); + if (!prScanReqMsg) { + ASSERT(0); /* Can't trigger SCAN FSM */ + return; + } + + prScanReqMsg->rMsgHdr.eMsgId = MID_AIS_SCN_SCAN_REQ_V2; + prScanReqMsg->ucSeqNum = ++prAisFsmInfo->ucSeqNumOfScanReq; + prScanReqMsg->ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex; + +#if CFG_SUPPORT_RDD_TEST_MODE + prScanReqMsg->eScanType = SCAN_TYPE_PASSIVE_SCAN; +#else + if (prAisFsmInfo->eCurrentState == AIS_STATE_SCAN || + prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN) { + if (prAisFsmInfo->ucScanSSIDNum == 0) { +#if CFG_SUPPORT_AIS_PASSIVE_SCAN + prScanReqMsg->eScanType = SCAN_TYPE_PASSIVE_SCAN; + + prScanReqMsg->ucSSIDType = 0; + prScanReqMsg->ucSSIDNum = 0; +#else + prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; + + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_WILDCARD; + prScanReqMsg->ucSSIDNum = 0; +#endif + } else if (prAisFsmInfo->ucScanSSIDNum == 1 && + prAisFsmInfo->arScanSSID[0].u4SsidLen == 0) { + prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; + + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_WILDCARD; + prScanReqMsg->ucSSIDNum = 0; + } else { + prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; + + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + prScanReqMsg->ucSSIDNum = prAisFsmInfo->ucScanSSIDNum; + prScanReqMsg->prSsid = prAisFsmInfo->arScanSSID; + } + } else { + prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; + + COPY_SSID(prAisFsmInfo->rRoamingSSID.aucSsid, + prAisFsmInfo->rRoamingSSID.u4SsidLen, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + + /* Scan for determined SSID */ + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + prScanReqMsg->ucSSIDNum = 1; + prScanReqMsg->prSsid = &(prAisFsmInfo->rRoamingSSID); + } +#endif + + /* using default channel dwell time/timeout value */ + prScanReqMsg->u2ProbeDelay = 0; + prScanReqMsg->u2ChannelDwellTime = 0; + prScanReqMsg->u2TimeoutValue = 0; + + /* check if tethering is running and need to fix on + * specific channel */ + if (cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel) == + true) { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED; + prScanReqMsg->ucChannelListNum = 1; + prScanReqMsg->arChnlInfoList[0].eBand = eBand; + prScanReqMsg->arChnlInfoList[0].ucChannelNum = ucChannel; +#if CFG_SCAN_CHANNEL_SPECIFIED + } else if (is_valid_scan_chnl_cnt( + prAisFsmInfo->ucScanChannelListNum)) { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_SPECIFIED; + prScanReqMsg->ucChannelListNum = + prAisFsmInfo->ucScanChannelListNum; + kalMemCopy(prScanReqMsg->arChnlInfoList, + prAisFsmInfo->arScanChnlInfoList, + sizeof(RF_CHANNEL_INFO_T) * + prScanReqMsg->ucChannelListNum); +#endif + } else if (prAdapter + ->aePreferBand[prAdapter->prAisBssInfo->ucBssIndex] == + BAND_NULL) { + if (prAdapter->fgEnable5GBand == true) { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; + } else { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; + } + } else if (prAdapter + ->aePreferBand[prAdapter->prAisBssInfo->ucBssIndex] == + BAND_2G4) { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; + } else if (prAdapter + ->aePreferBand[prAdapter->prAisBssInfo->ucBssIndex] == + BAND_5G) { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_5G; + } else { + prScanReqMsg->eScanChannel = SCAN_CHANNEL_FULL; + ASSERT(0); + } + + if (prAisFsmInfo->u4ScanIELength > 0) { + kalMemCopy(prScanReqMsg->aucIE, prAisFsmInfo->aucScanIEBuf, + prAisFsmInfo->u4ScanIELength); + } else { +#if CFG_SUPPORT_WPS2 + if (prAdapter->prGlueInfo->u2WSCIELen > 0) { + kalMemCopy(prScanReqMsg->aucIE, + &prAdapter->prGlueInfo->aucWSCIE, + prAdapter->prGlueInfo->u2WSCIELen); + } +#endif + } + + prScanReqMsg->u2IELen = u2ScanIELen; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prScanReqMsg, + MSG_SEND_METHOD_BUF); + + prAisFsmInfo->fgTryScan = false; /* Will enable + background sleep for + infrastructure */ + + break; + + case AIS_STATE_REQ_CHANNEL_JOIN: + /* send message to CNM for acquiring channel */ + prMsgChReq = (P_MSG_CH_REQ_T)cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_CH_REQ_T)); + if (!prMsgChReq) { + ASSERT(0); /* Can't indicate CNM for channel + acquiring */ + return; + } + + prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; + prMsgChReq->ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex; + prMsgChReq->ucTokenID = ++prAisFsmInfo->ucSeqNumOfChReq; + prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; +#ifdef CFG_SUPPORT_ADJUST_JOIN_CH_REQ_INTERVAL + prMsgChReq->u4MaxInterval = + prAdapter->rWifiVar.u4AisJoinChReqIntervel; +#else + prMsgChReq->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; +#endif + DBGLOG(AIS, INFO, "Request join interval: %u\n", + prMsgChReq->u4MaxInterval); + prMsgChReq->ucPrimaryChannel = + prAisFsmInfo->prTargetBssDesc->ucChannelNum; + prMsgChReq->eRfSco = prAisFsmInfo->prTargetBssDesc->eSco; + prMsgChReq->eRfBand = prAisFsmInfo->prTargetBssDesc->eBand; +#if CFG_SUPPORT_DBDC + prMsgChReq->eDBDCBand = ENUM_BAND_AUTO; +#endif + /* To do: check if 80/160MHz bandwidth is needed here */ + prMsgChReq->eRfChannelWidth = + prAisFsmInfo->prTargetBssDesc->eChannelWidth; + prMsgChReq->ucRfCenterFreqSeg1 = + prAisFsmInfo->prTargetBssDesc->ucCenterFreqS1; + prMsgChReq->ucRfCenterFreqSeg2 = + prAisFsmInfo->prTargetBssDesc->ucCenterFreqS2; + + rlmReviseMaxBw(prAdapter, prAisBssInfo->ucBssIndex, + &prMsgChReq->eRfSco, + (u8 *)&prMsgChReq->eRfChannelWidth, + &prMsgChReq->ucRfCenterFreqSeg1, + &prMsgChReq->ucPrimaryChannel); + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsgChReq, + MSG_SEND_METHOD_BUF); + + prAisFsmInfo->fgIsChannelRequested = true; + break; + + case AIS_STATE_JOIN: + aisFsmStateInit_JOIN(prAdapter, prAisFsmInfo->prTargetBssDesc); + break; + + case AIS_STATE_JOIN_FAILURE: + if (prAisFsmInfo->prTargetBssDesc) { + if (prAisFsmInfo->prTargetBssDesc->fgIsConnecting != + false) { + DBGLOG( + AIS, ERROR, + "Connecting Flag(%d) is unusual in JOIN_FAILURE state\n", + prAisFsmInfo->prTargetBssDesc->fgIsConnecting); + } + } + + nicMediaJoinFailure(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex, + (prConnSettings-> + fgIsDisconnectedByNonRequest) ? + (WLAN_STATUS_JOIN_ABORT) : + (WLAN_STATUS_JOIN_TIMEOUT)); + + prConnSettings->fgIsDisconnectedByNonRequest = true; + + eNextState = AIS_STATE_IDLE; + fgIsTransition = true; + + break; + +#if CFG_SUPPORT_ADHOC + case AIS_STATE_IBSS_ALONE: + aisFsmStateInit_IBSS_ALONE(prAdapter); + break; + + case AIS_STATE_IBSS_MERGE: + aisFsmStateInit_IBSS_MERGE(prAdapter, + prAisFsmInfo->prTargetBssDesc); + break; +#endif + + case AIS_STATE_NORMAL_TR: + if (prAisFsmInfo->fgIsInfraChannelFinished == false) { + /* Don't do anything when rJoinTimeoutTimer is + * still ticking */ + } else { + /* 1. Process for pending scan */ + if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, + true) == + true) { + wlanClearScanningResult(prAdapter); + eNextState = AIS_STATE_ONLINE_SCAN; + fgIsTransition = true; + } + /* 2. Process for pending roaming scan */ + else if (aisFsmIsRequestPending(prAdapter, + AIS_REQUEST_ROAMING_SEARCH, + true) == true) { + eNextState = AIS_STATE_LOOKING_FOR; + fgIsTransition = true; + } + /* 3. Process for pending roaming scan */ + else if (aisFsmIsRequestPending(prAdapter, + AIS_REQUEST_ROAMING_CONNECT, + true) == true) { + eNextState = AIS_STATE_SEARCH; + fgIsTransition = true; + } else if (aisFsmIsRequestPending(prAdapter, + AIS_REQUEST_REMAIN_ON_CHANNEL, + true) == true) { + eNextState = AIS_STATE_REQ_REMAIN_ON_CHANNEL; + fgIsTransition = true; + } + } + + break; + + case AIS_STATE_DISCONNECTING: + cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, + STA_STATE_1); + /* send for deauth frame for disconnection */ + authSendDeauthFrame(prAdapter, prAisBssInfo, + prAisBssInfo->prStaRecOfAP, + (P_SW_RFB_T)NULL, + REASON_CODE_DEAUTH_LEAVING_BSS, + aisDeauthXmitComplete); + cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rDeauthDoneTimer, + 200); + break; + + case AIS_STATE_REQ_REMAIN_ON_CHANNEL: + /* send message to CNM for acquiring channel */ + prMsgChReq = (P_MSG_CH_REQ_T)cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_CH_REQ_T)); + if (!prMsgChReq) { + ASSERT(0); /* Can't indicate CNM for channel + acquiring */ + return; + } + + /* zero-ize */ + kalMemZero(prMsgChReq, sizeof(MSG_CH_REQ_T)); + + /* filling */ + prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; + prMsgChReq->ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex; + prMsgChReq->ucTokenID = ++prAisFsmInfo->ucSeqNumOfChReq; + prMsgChReq->eReqType = CH_REQ_TYPE_JOIN; + prMsgChReq->u4MaxInterval = + prAisFsmInfo->rChReqInfo.u4DurationMs; + prMsgChReq->ucPrimaryChannel = + prAisFsmInfo->rChReqInfo.ucChannelNum; + prMsgChReq->eRfSco = prAisFsmInfo->rChReqInfo.eSco; + prMsgChReq->eRfBand = prAisFsmInfo->rChReqInfo.eBand; +#if CFG_SUPPORT_DBDC + prMsgChReq->eDBDCBand = ENUM_BAND_AUTO; +#endif + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsgChReq, + MSG_SEND_METHOD_BUF); + + prAisFsmInfo->fgIsChannelRequested = true; + + break; + + case AIS_STATE_REMAIN_ON_CHANNEL: + if (!IS_NET_ACTIVE(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex)) { + SET_NET_ACTIVE(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex); + /* sync with firmware */ + /* FW will re-activate BSS, and set BSS: */ + /* 1. pwr state = IDLE */ + /* 2. connected = Disconnected */ + nicActivateNetwork(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex); + } + prAisBssInfo->fgIsNetRequestInActive = false; + break; + + default: + ASSERT(0); /* Make sure we have handle all STATEs */ + break; + } + }while (fgIsTransition); + + return; +} + +enum _ENUM_AIS_STATE_T aisFsmStateSearchAction( + IN struct _ADAPTER_T *prAdapter, + u8 ucPhase) +{ + struct _CONNECTION_SETTINGS_T *prConnSettings; + struct _BSS_INFO_T *prAisBssInfo; + struct _AIS_FSM_INFO_T *prAisFsmInfo; + struct _BSS_DESC_T *prBssDesc; + enum _ENUM_AIS_STATE_T eState = AIS_STATE_IDLE; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = prAdapter->prAisBssInfo; + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prBssDesc = scanSearchBssDescByPolicy(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex); + + if (ucPhase == AIS_FSM_STATE_SEARCH_ACTION_PHASE_0) { + if (prConnSettings->eOPMode == NET_TYPE_INFRA) { + /* issue reconnect request, */ + /*and retreat to idle state for scheduling */ + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + eState = AIS_STATE_IDLE; + } +#if CFG_SUPPORT_ADHOC + else if ((prConnSettings->eOPMode == NET_TYPE_IBSS) || + (prConnSettings->eOPMode == NET_TYPE_AUTO_SWITCH) || + (prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS)) { + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + prAisFsmInfo->prTargetBssDesc = NULL; + eState = AIS_STATE_IBSS_ALONE; + } +#endif + else { + ASSERT(0); + eState = AIS_STATE_WAIT_FOR_NEXT_SCAN; + } + } else if (ucPhase == AIS_FSM_STATE_SEARCH_ACTION_PHASE_1) { + /* increase connection trial count for infrastructure connection + */ + if (prConnSettings->eOPMode == NET_TYPE_INFRA) { + prAisFsmInfo->ucConnTrialCount++; + } + /* 4 <A> Try to SCAN */ + if (prAisFsmInfo->fgTryScan) { + eState = AIS_STATE_LOOKING_FOR; + } + /* 4 <B> We've do SCAN already, now wait in some STATE. */ + else { + if (prConnSettings->eOPMode == NET_TYPE_INFRA) { + /* issue reconnect request, and */ + /* retreat to idle state for scheduling */ + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + + eState = AIS_STATE_IDLE; + } +#if CFG_SUPPORT_ADHOC + else if ((prConnSettings->eOPMode == NET_TYPE_IBSS) || + (prConnSettings->eOPMode == NET_TYPE_AUTO_SWITCH) || + (prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS)) { + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + prAisFsmInfo->prTargetBssDesc = NULL; + + eState = AIS_STATE_IBSS_ALONE; + } +#endif + else { + ASSERT(0); + eState = AIS_STATE_WAIT_FOR_NEXT_SCAN; + } + } + } else { +#if DBG + if (prAisBssInfo->ucReasonOfDisconnect != + DISCONNECT_REASON_CODE_REASSOCIATION) { + ASSERT( + UNEQUAL_MAC_ADDR(prBssDesc->aucBSSID, + prAisBssInfo->aucBSSID)); + } +#endif + } + return eState; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void aisFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_SCN_SCAN_DONE prScanDoneMsg; + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + u8 ucSeqNumOfCompMsg; + P_CONNECTION_SETTINGS_T prConnSettings; + + DEBUGFUNC("aisFsmRunEventScanDone()"); + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + DBGLOG(AIS, INFO, "ScanDone\n"); + + DBGLOG(AIS, LOUD, "EVENT-SCAN DONE: Current Time = %u\n", + kalGetTimeTick()); + + if (prAdapter->prAisBssInfo == NULL) { + /* This case occurs when the AIS isn't done, but the wlan0 */ + /* has changed to AP mode. And the prAisBssInfo is freed. */ + DBGLOG(AIS, WARN, "prAisBssInfo is NULL, and then return\n"); + return; + } + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE)prMsgHdr; + ASSERT(prScanDoneMsg->ucBssIndex == + prAdapter->prAisBssInfo->ucBssIndex); + + ucSeqNumOfCompMsg = prScanDoneMsg->ucSeqNum; + cnmMemFree(prAdapter, prMsgHdr); + + eNextState = prAisFsmInfo->eCurrentState; + + if (ucSeqNumOfCompMsg != prAisFsmInfo->ucSeqNumOfScanReq) { + DBGLOG(AIS, WARN, "SEQ NO of AIS SCN DONE MSG is not matched.\n"); + } else { + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rScanDoneTimer); + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_IDLE: + case AIS_STATE_SCAN: + prConnSettings->fgIsScanReqIssued = false; + + /* reset scan IE buffer */ + prAisFsmInfo->u4ScanIELength = 0; + + kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, + WLAN_STATUS_SUCCESS); + eNextState = AIS_STATE_IDLE; + scanReportScanResultToAgps(prAdapter); + + break; + + case AIS_STATE_ONLINE_SCAN: + prConnSettings->fgIsScanReqIssued = false; + + /* reset scan IE buffer */ + prAisFsmInfo->u4ScanIELength = 0; + + kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, + WLAN_STATUS_SUCCESS); +#if CFG_SUPPORT_ROAMING + eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); +#else + eNextState = AIS_STATE_NORMAL_TR; +#endif + scanReportScanResultToAgps(prAdapter); + break; + + case AIS_STATE_LOOKING_FOR: + if (prConnSettings->fgIsDisconnectedByNonRequest) { + eNextState = AIS_STATE_IDLE; + } else { +#if CFG_SUPPORT_ROAMING + eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); +#else + eNextState = AIS_STATE_SEARCH; +#endif + } + break; + + default: + prConnSettings->fgIsScanReqIssued = false; + + /* reset scan IE buffer */ + prAisFsmInfo->u4ScanIELength = 0; + + kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, + WLAN_STATUS_SUCCESS); + break; + } + } + + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void aisFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_AIS_ABORT_T prAisAbortMsg; + P_AIS_FSM_INFO_T prAisFsmInfo; + u8 ucReasonOfDisconnect; + u8 fgDelayIndication; + P_CONNECTION_SETTINGS_T prConnSettings; + struct _BSS_INFO_T *prAisBssInfo; + + DEBUGFUNC("aisFsmRunEventAbort()"); + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = prAdapter->prAisBssInfo; + + if (prMsgHdr != NULL && prMsgHdr->eMsgId == MID_MNY_AIS_MGMT_TX) { + if (prAdapter != NULL && prAdapter->prGlueInfo != NULL && prAdapter->prGlueInfo->prDevHandler != NULL) { + struct wireless_dev *wdev = prAdapter->prGlueInfo->prDevHandler->ieee80211_ptr; + + if (wdev && wdev->connected) { + DBGLOG(AIS, WARN, "FENCE DROP: Suppressed a false-alarm MGMT_TX abort event to preserve active link.\n"); + + /* Free the allocated message memory immediately to prevent a resource leak */ + cnmMemFree(prAdapter, prMsgHdr); + return; /* Block the abort pipeline from execution completely */ + } + } + } + + // @ShiuanWen - Bug fix when run WPA3-SAE 5.2.1 then 5.2.6 + // TC5.2.1, prAisBssInfo->aucSSID keep the ssid Wi-Fi-5.2.1 due to + // connect successful. TC5.2.6, aisFsmJoinCompleteAction use the wrong + // prAisBssInfo->aucSSID and run to scanSearchBssDescByBssidAndSsid. It + // caused the prBssDesc is NULL and return to + // aisFsmRunEventJoinComplete. AIS state machine is blocked on JOIN + // state. + kalMemZero(prAisBssInfo->aucSSID, sizeof(prAisBssInfo->aucSSID)); + prAisBssInfo->ucSSIDLen = 0; + + /* 4 <1> Extract information of Abort Message and then free memory. */ + prAisAbortMsg = (P_MSG_AIS_ABORT_T)prMsgHdr; + ucReasonOfDisconnect = prAisAbortMsg->ucReasonOfDisconnect; + fgDelayIndication = prAisAbortMsg->fgDelayIndication; + + cnmMemFree(prAdapter, prMsgHdr); + + DBGLOG(AIS, STATE, + "EVENT-ABORT: Current State %s, ucReasonOfDisconnect:%d\n", + apucDebugAisState[prAisFsmInfo->eCurrentState], + ucReasonOfDisconnect); + + /* record join request time */ + GET_CURRENT_SYSTIME(&(prAisFsmInfo->rJoinReqTime)); + + /* 4 <2> clear previous pending connection request and insert new one */ + if (ucReasonOfDisconnect == DISCONNECT_REASON_CODE_DEAUTHENTICATED +#if CFG_SUPPORT_DBDC_TC6 + || ucReasonOfDisconnect == DISCONNECT_REASON_CODE_DBDC_REASSOCIATION +#endif + || ucReasonOfDisconnect == DISCONNECT_REASON_CODE_DISASSOCIATED) { + prConnSettings->fgIsDisconnectedByNonRequest = true; + } else { + prConnSettings->fgIsDisconnectedByNonRequest = false; + } + + /* to support user space triggered roaming */ + if (ucReasonOfDisconnect == DISCONNECT_REASON_CODE_REASSOCIATION && + prAisFsmInfo->eCurrentState != AIS_STATE_DISCONNECTING) { + if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR && + prAisFsmInfo->fgIsInfraChannelFinished == true) { +#if CFG_SUPPORT_SAME_BSS_REASSOC + P_BSS_INFO_T prAisBssInfo = prAdapter->prAisBssInfo; + prAisBssInfo->ucReasonOfDisconnect = ucReasonOfDisconnect; +#endif + aisFsmSteps(prAdapter, AIS_STATE_SEARCH); + } else { + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, + true); + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, + true); + aisFsmInsertRequest(prAdapter, AIS_REQUEST_ROAMING_CONNECT); + } + return; + } + + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, true); + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + + if (prAisFsmInfo->eCurrentState != AIS_STATE_DISCONNECTING) { + /* 4 <3> invoke abort handler */ + DBGLOG(AIS, STATE, "ucReasonOfDisconnect:%d\n", + ucReasonOfDisconnect); + aisFsmStateAbort(prAdapter, ucReasonOfDisconnect, + fgDelayIndication); + } +} + +#if 0 +void aisFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_AIS_ABORT_T prAisAbortMsg; + P_AIS_FSM_INFO_T prAisFsmInfo; + u8 ucReasonOfDisconnect; + u8 fgDelayIndication; + P_CONNECTION_SETTINGS_T prConnSettings; + struct _BSS_INFO_T *prAisBssInfo; + + DEBUGFUNC("aisFsmRunEventAbort()"); + + /* 1. STAGE 1 SAFETY CRASH PREVENTION GATES: + * Enforce strict validation on input address arguments before performing + * any structural memory tracking assignments or variable dereferencing! */ + ASSERT(prAdapter); + ASSERT(prMsgHdr); + if (!prAdapter || !prMsgHdr) { + return; + } + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = prAdapter->prAisBssInfo; + + /* 2. THE PRODUCTION UNBREAKABLE FSM STATE FENCE HOOK: + * Intercept the outbound management frame transmit failure message (MID_MNY_AIS_MGMT_TX). + * If our driver state machine has already successfully achieved the active operational mode + * (AIS_STATE_NORMAL_TR), DISCARD the error packet. This blocks the hardware watchdog + * from forcefully tearing down a healthy connected network payload pipeline! */ + if (prMsgHdr->eMsgId == MID_MNY_AIS_MGMT_TX && + prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR) { + + DBGLOG(AIS, WARN, "CRITICAL FENCE: Suppressed false-alarm MGMT_TX abort event to preserve live link.\n"); + + /* Free the allocated message memory block immediately to prevent a resource leak */ + cnmMemFree(prAdapter, prMsgHdr); + return; /* Force early function context termination to shield the link variables */ + } + + /* 3. WPA3-SAE SSID Leakage Mitigation Patch Block (ShiuanWen fix runs safely below) */ + // @ShiuanWen - Bug fix when run WPA3-SAE 5.2.1 then 5.2.6 + // TC5.2.1, prAisBssInfo->aucSSID keep the ssid Wi-Fi-5.2.1 due to + // connect successful. TC5.2.6, aisFsmJoinCompleteAction use the wrong + // prAisBssInfo->aucSSID and run to scanSearchBssDescByBssidAndSsid. It + // caused the prBssDesc is NULL and return to + // aisFsmRunEventJoinComplete. AIS state machine is blocked on JOIN + // state. + if (prAisBssInfo != NULL) { + kalMemZero(prAisBssInfo->aucSSID, sizeof(prAisBssInfo->aucSSID)); + prAisBssInfo->ucSSIDLen = 0; + } + + /* 4. Extract information of Abort Message and then free memory. */ + prAisAbortMsg = (P_MSG_AIS_ABORT_T)prMsgHdr; + ucReasonOfDisconnect = prAisAbortMsg->ucReasonOfDisconnect; + fgDelayIndication = prAisAbortMsg->fgDelayIndication; + cnmMemFree(prAdapter, prMsgHdr); + + /* record join request time */ + GET_CURRENT_SYSTIME(&(prAisFsmInfo->rJoinReqTime)); + + /* clear previous pending connection request and insert new one */ + if (ucReasonOfDisconnect == DISCONNECT_REASON_CODE_DEAUTHENTICATED +#if CFG_SUPPORT_DBDC_TC6 + || ucReasonOfDisconnect == DISCONNECT_REASON_CODE_DBDC_REASSOCIATION +#endif + || ucReasonOfDisconnect == DISCONNECT_REASON_CODE_DISASSOCIATED) { + prConnSettings->fgIsDisconnectedByNonRequest = true; + } else { + prConnSettings->fgIsDisconnectedByNonRequest = false; + } + + /* to support user space triggered roaming */ + if (ucReasonOfDisconnect == DISCONNECT_REASON_CODE_REASSOCIATION && + prAisFsmInfo->eCurrentState != AIS_STATE_DISCONNECTING) { + + if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR && + prAisFsmInfo->fgIsInfraChannelFinished == true) { +#if CFG_SUPPORT_SAME_BSS_REASSOC + if (prAisBssInfo != NULL) { + prAisBssInfo->ucReasonOfDisconnect = ucReasonOfDisconnect; + } +#endif + aisFsmSteps(prAdapter, AIS_STATE_SEARCH); + } else { + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, true); + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, true); + aisFsmInsertRequest(prAdapter, AIS_REQUEST_ROAMING_CONNECT); + } + return; + } + + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, true); + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + + if (prAisFsmInfo->eCurrentState != AIS_STATE_DISCONNECTING) { + /* invoke abort handler */ + DBGLOG(AIS, STATE, "ucReasonOfDisconnect:%d\n", ucReasonOfDisconnect); + aisFsmStateAbort(prAdapter, ucReasonOfDisconnect, fgDelayIndication); + } +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function handles AIS-FSM abort event/command + * + * \param[in] prAdapter Pointer of ADAPTER_T + * ucReasonOfDisconnect Reason for disonnection + * fgDelayIndication Option to delay disconnection indication + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void aisFsmStateAbort(IN P_ADAPTER_T prAdapter, u8 ucReasonOfDisconnect, + u8 fgDelayIndication) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + u8 fgIsCheckConnected; + + ASSERT(prAdapter); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = prAdapter->prAisBssInfo; + + /* XXX: The wlan0 may has been changed to AP mode. */ + if (prAisBssInfo == NULL) { + return; + } + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + fgIsCheckConnected = false; + + DBGLOG(AIS, STATE, "aisFsmStateAbort DiscReason[%d], CurState[%d]\n", + ucReasonOfDisconnect, prAisFsmInfo->eCurrentState); + + /* 4 <1> Save information of Abort Message and then free memory. */ + prAisBssInfo->ucReasonOfDisconnect = ucReasonOfDisconnect; + + /* 4 <2> Abort current job. */ + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_IDLE: + case AIS_STATE_SEARCH: + case AIS_STATE_JOIN_FAILURE: + break; + + case AIS_STATE_WAIT_FOR_NEXT_SCAN: + /* Do cancel timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rBGScanTimer); + + /* in case roaming is triggered */ + fgIsCheckConnected = true; + break; + + case AIS_STATE_SCAN: + /* Do abort SCAN */ + aisFsmStateAbort_SCAN(prAdapter); + + /* queue for later handling */ + if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, false) == + false) { + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + } + + break; + + case AIS_STATE_LOOKING_FOR: + /* Do abort SCAN */ + aisFsmStateAbort_SCAN(prAdapter); + + /* in case roaming is triggered */ + fgIsCheckConnected = true; + break; + + case AIS_STATE_REQ_CHANNEL_JOIN: + /* Release channel to CNM */ + aisFsmReleaseCh(prAdapter); + + /* in case roaming is triggered */ + fgIsCheckConnected = true; + break; + + case AIS_STATE_JOIN: + /* Do abort JOIN */ + aisFsmStateAbort_JOIN(prAdapter); + + /* in case roaming is triggered */ + fgIsCheckConnected = true; + break; + +#if CFG_SUPPORT_ADHOC + case AIS_STATE_IBSS_ALONE: + case AIS_STATE_IBSS_MERGE: + aisFsmStateAbort_IBSS(prAdapter); + break; +#endif + + case AIS_STATE_ONLINE_SCAN: + /* Do abort SCAN */ + aisFsmStateAbort_SCAN(prAdapter); + + /* queue for later handling */ + if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, false) == + false) { + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + } + + fgIsCheckConnected = true; + break; + + case AIS_STATE_NORMAL_TR: + fgIsCheckConnected = true; + break; + + case AIS_STATE_DISCONNECTING: + /* Do abort NORMAL_TR */ + aisFsmStateAbort_NORMAL_TR(prAdapter); + + break; + + case AIS_STATE_REQ_REMAIN_ON_CHANNEL: + fgIsCheckConnected = true; + + /* release channel */ + aisFsmReleaseCh(prAdapter); + break; + + case AIS_STATE_REMAIN_ON_CHANNEL: + fgIsCheckConnected = true; + + /* 1. release channel */ + aisFsmReleaseCh(prAdapter); + + /* 2. stop channel timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); + + break; + + default: + break; + } + + if (fgIsCheckConnected && + (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED)) { + /* switch into DISCONNECTING state for sending DEAUTH if + * necessary */ + if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && + prAisBssInfo->ucReasonOfDisconnect != + DISCONNECT_REASON_CODE_DEAUTHENTICATED && + prAisBssInfo->prStaRecOfAP && + prAisBssInfo->prStaRecOfAP->fgIsInUse) { + aisFsmSteps(prAdapter, AIS_STATE_DISCONNECTING); + + return; + } + /* Do abort NORMAL_TR */ + aisFsmStateAbort_NORMAL_TR(prAdapter); + } + + aisFsmDisconnect(prAdapter, fgDelayIndication); + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will handle the Join Complete Event from SAA FSM for AIS + * FSM + * + * @param[in] prMsgHdr Message of Join Complete of SAA FSM. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmRunEventJoinComplete(IN struct _ADAPTER_T *prAdapter, + IN struct _MSG_HDR_T *prMsgHdr) +{ + struct _MSG_SAA_FSM_COMP_T *prJoinCompMsg; + struct _AIS_FSM_INFO_T *prAisFsmInfo; + enum _ENUM_AIS_STATE_T eNextState; + struct _SW_RFB_T *prAssocRspSwRfb; + + DEBUGFUNC("aisFsmRunEventJoinComplete()"); + ASSERT(prMsgHdr); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prJoinCompMsg = (struct _MSG_SAA_FSM_COMP_T *)prMsgHdr; + prAssocRspSwRfb = prJoinCompMsg->prSwRfb; + + eNextState = prAisFsmInfo->eCurrentState; + + /* Check State and SEQ NUM */ + if (prAisFsmInfo->eCurrentState == AIS_STATE_JOIN) { + /* Check SEQ NUM */ + if (prJoinCompMsg->ucSeqNum == prAisFsmInfo->ucSeqNumOfReqMsg) { + eNextState = aisFsmJoinCompleteAction(prAdapter, prMsgHdr); + } +#if DBG + else { + DBGLOG(AIS, WARN, + "SEQ NO of AIS JOIN COMP MSG is not matched.\n"); + } +#endif + } + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } + + if (eNextState == AIS_STATE_NORMAL_TR) { + DBGLOG(AIS, STATE, "cancel beacon lost timer.\n"); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rBeaconLostTimer); + +#if 0 + P_BSS_INFO_T prBssInfo = prAdapter->prAisBssInfo; + + if (prBssInfo != NULL) { + DBGLOG(AIS, WARN, "AIS FSM Core: Synchronizing hardware registers down to silicon tables.\n"); + + nicUpdateBss(prAdapter, prBssInfo->ucBssIndex); + + P_STA_RECORD_T prStaRec = cnmGetStaRecByAddress(prAdapter, prBssInfo->ucBssIndex, prBssInfo->aucBSSID); + + if (prStaRec != NULL) { + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + qmSetStaRecTxAllowed(prAdapter, prStaRec, true); + } else { + DBGLOG(AIS, WARN, "AIS FSM: Active StaRec not cached yet for target BSSID.\n"); + } + } +#endif + } + + if (prAssocRspSwRfb) { + nicRxReturnRFB(prAdapter, prAssocRspSwRfb); + } + + cnmMemFree(prAdapter, prMsgHdr); +} + +enum _ENUM_AIS_STATE_T aisFsmJoinCompleteAction( + IN struct _ADAPTER_T *prAdapter, + IN struct _MSG_HDR_T *prMsgHdr) +{ + struct _MSG_SAA_FSM_COMP_T *prJoinCompMsg; + struct _AIS_FSM_INFO_T *prAisFsmInfo; + enum _ENUM_AIS_STATE_T eNextState; + struct _STA_RECORD_T *prStaRec; + struct _SW_RFB_T *prAssocRspSwRfb; + struct _BSS_INFO_T *prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + u32 rCurrentTime; +#if CFG_SUPPORT_BFER + u8 ucStaVhtBfer = prAdapter->rWifiVar.ucStaVhtBfer; + u8 ucStaHtBfer = prAdapter->rWifiVar.ucStaHtBfer; +#endif + + DEBUGFUNC("aisFsmJoinCompleteAction()"); + + ASSERT(prMsgHdr); + + GET_CURRENT_SYSTIME(&rCurrentTime); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prJoinCompMsg = (struct _MSG_SAA_FSM_COMP_T *)prMsgHdr; + prStaRec = prJoinCompMsg->prStaRec; + prAssocRspSwRfb = prJoinCompMsg->prSwRfb; + prAisBssInfo = prAdapter->prAisBssInfo; + eNextState = prAisFsmInfo->eCurrentState; + + /* 4 <1> JOIN was successful */ + if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { + /* 1. Reset retry count */ + prAisFsmInfo->ucConnTrialCount = 0; + + /* Completion of roaming */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { +#if CFG_SUPPORT_ROAMING + /* 2. Deactivate previous BSS */ + aisFsmRoamingDisconnectPrevAP(prAdapter, prStaRec); +#endif + +#if CFG_SUPPORT_ROAMING || CFG_SUPPORT_SAME_BSS_REASSOC + /* 3. Update bss based on roaming staRec */ + aisUpdateBssInfoForRoamingAP(prAdapter, prStaRec, + prAssocRspSwRfb); +#endif +#if CFG_SUPPORT_SAME_BSS_REASSOC + aisFsmReleaseCh(prAdapter); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); + prAisFsmInfo->fgIsInfraChannelFinished = true; +#endif + } else { + /* 4 <1.1> Change FW's Media State immediately. */ + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + /* 4 <1.2> Deactivate previous AP's STA_RECORD_T in + * Driver if have. */ + if ((prAisBssInfo->prStaRecOfAP) && + (prAisBssInfo->prStaRecOfAP != prStaRec) && + (prAisBssInfo->prStaRecOfAP->fgIsInUse)) { + cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, + STA_STATE_1); + cnmStaRecFree(prAdapter, prAisBssInfo->prStaRecOfAP); + } + + /* For temp solution, need to refine */ + /* 4 <1.4> Update BSS_INFO_T */ + aisUpdateBssInfoForJOIN(prAdapter, prStaRec, prAssocRspSwRfb); + + /* 4 <1.3> Activate current AP's STA_RECORD_T in Driver. + */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + +#if CFG_SUPPORT_BFER + if ((IS_FEATURE_ENABLED(ucStaVhtBfer) || + IS_FEATURE_ENABLED(ucStaHtBfer)) && + prAdapter->fgIsHwSupportBfer) { + rlmBfStaRecPfmuUpdate(prAdapter, prStaRec); + rlmETxBfTriggerPeriodicSounding(prAdapter); + } +#endif + + /* 4 <1.5> Update RSSI if necessary */ + nicUpdateRSSI(prAdapter, prAdapter->prAisBssInfo->ucBssIndex, + (s8)(RCPI_TO_dBm(prStaRec->ucRCPI)), 0); + + /* 4 <1.6> Indicate Connected Event to Host immediately. + */ + /* Require BSSID, Association ID, Beacon Interval */ + /* .. from AIS_BSS_INFO_T */ + aisIndicationOfMediaStateToHost(prAdapter, + PARAM_MEDIA_STATE_CONNECTED, + false); + + if (prAdapter->rWifiVar.ucTpTestMode == + ENUM_TP_TEST_MODE_THROUGHPUT) { + nicEnterTPTestMode(prAdapter, TEST_MODE_THROUGHPUT); + } else if (prAdapter->rWifiVar.ucTpTestMode == + ENUM_TP_TEST_MODE_SIGMA_AC_N_PMF) { + nicEnterTPTestMode(prAdapter, TEST_MODE_SIGMA_AC_N_PMF); + } else if (prAdapter->rWifiVar.ucTpTestMode == + ENUM_TP_TEST_MODE_SIGMA_WMM_PS) { + nicEnterTPTestMode(prAdapter, TEST_MODE_SIGMA_WMM_PS); + } +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + else if (prAdapter->rWifiVar.ucTpTestMode == + ENUM_TP_TEST_MODE_AUDIO_MRM) { + nicEnterTPTestMode(prAdapter, TEST_MODE_AUDIO_MRM); + } +#endif + } + +#if CFG_SUPPORT_ROAMING + /* if user space roaming is enabled, we should disable driver/fw + * roaming */ +#ifdef CONFIG_CFG80211_ALLOW_RECONNECT + if (prAdapter->rWifiVar.rConnSettings.eConnectionPolicy != + CONNECT_BY_BSSID) +#endif + roamingFsmRunEventStart(prAdapter); +#endif + +#if CFG_SUPPORT_802_11K || CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + aisResetNeighborApList(prAdapter); +#endif +#if CFG_SUPPORT_802_11K + if (prAisFsmInfo->prTargetBssDesc->aucRrmCap[0] & + BIT(RRM_CAP_INFO_NEIGHBOR_REPORT_BIT)) { + aisSendNeighborRequest(prAdapter); + } +#endif +#if CFG_SUPPORT_DBDC_TC6 + if (timerPendingTimer(&prAdapter->rWifiVar.rDBDCReconnectCountDown)) { + DBGLOG( + CNM, INFO, + "DBDC reconnect timer protection end due to join complete\n"); + cnmTimerStopTimer(prAdapter, + &prAdapter->rWifiVar.rDBDCReconnectCountDown); + + if (timerPendingTimer( + &prAdapter->rWifiVar.rDBDCSwitchGuardTimer)) { + DBGLOG(CNM, INFO, + "DBDC switch guard timer end due to join complete\n"); + cnmTimerStopTimer(prAdapter, + &prAdapter->rWifiVar.rDBDCSwitchGuardTimer); + } + } + + if (timerPendingTimer(&prAdapter->rWifiVar.rDBDCAisConnectCountDown)) { + DBGLOG( + CNM, INFO, + "DBDC AIS connect timer protection end due to join complete\n"); + cnmTimerStopTimer(prAdapter, + &prAdapter->rWifiVar.rDBDCAisConnectCountDown); + } +#endif + /* 4 <1.7> Set the Next State of AIS FSM */ + eNextState = AIS_STATE_NORMAL_TR; + } + /* 4 <2> JOIN was not successful */ + else { + /* 4 <2.1> Redo JOIN process with other Auth Type if possible */ + if (aisFsmStateInit_RetryJOIN(prAdapter, prStaRec) == false) { + struct _BSS_DESC_T *prBssDesc; + PARAM_SSID_T rParamSsid; + + prBssDesc = prAisFsmInfo->prTargetBssDesc; + + /* 1. Increase Failure Count */ + prStaRec->ucJoinFailureCount++; + + /* 2. release channel */ + aisFsmReleaseCh(prAdapter); + + /* 3.1 stop join timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer); + + /* 3.2 reset local variable */ + prAisFsmInfo->fgIsInfraChannelFinished = true; + + kalMemZero(&rParamSsid, sizeof(PARAM_SSID_T)); + + if (prBssDesc) { + COPY_SSID(rParamSsid.aucSsid, rParamSsid.u4SsidLen, + prBssDesc->aucSSID, prBssDesc->ucSSIDLen); + } else { + COPY_SSID(rParamSsid.aucSsid, rParamSsid.u4SsidLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen); + } + + prBssDesc = scanSearchBssDescByBssidAndSsid( + prAdapter, prStaRec->aucMacAddr, true, &rParamSsid); + + if (prBssDesc == NULL) { + prBssDesc = scanSearchBssDescByBssidAndChanNum( + prAdapter, prConnSettings->aucBSSID, true, + prConnSettings->ucChannelNum); + } + + if (prBssDesc == NULL) { + return eNextState; + } + + /* ASSERT(prBssDesc); */ + /* ASSERT(prBssDesc->fgIsConnecting); */ + prBssDesc->ucJoinFailureCount++; + if (prBssDesc->ucJoinFailureCount > + SCN_BSS_JOIN_FAIL_THRESOLD) { + GET_CURRENT_SYSTIME(&prBssDesc->rJoinFailTime); + DBGLOG(AIS, INFO, "Bss " MACSTR " join fail %d times,", + MAC2STR(prBssDesc->aucBSSID), + SCN_BSS_JOIN_FAIL_THRESOLD); + DBGLOG(AIS, INFO, " temp disable it at time: %u\n", + prBssDesc->rJoinFailTime); + } + + if (prBssDesc) { + prBssDesc->fgIsConnecting = false; + } + + /* 3.3 Free STA-REC */ + if (prStaRec != prAisBssInfo->prStaRecOfAP) { + cnmStaRecFree(prAdapter, prStaRec); + } + + if (prAisBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) { +#if CFG_SUPPORT_ROAMING + eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; +#endif + } else if (CHECK_FOR_TIMEOUT(rCurrentTime, + prAisFsmInfo->rJoinReqTime, + SEC_TO_SYSTIME(AIS_JOIN_TIMEOUT))) { + /* 4.a temrminate join operation */ + eNextState = AIS_STATE_JOIN_FAILURE; + } else { + /* 20210419 frog: Won't retry join if supplicant + * SME. Require upper layer trigger connection + * again. + */ + eNextState = AIS_STATE_JOIN_FAILURE; + + if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_JOIN_ABORT) { + prConnSettings->fgIsDisconnectedByNonRequest = true; + DBGLOG(AIS, WARN, "Join abort, disconnect\n"); + } + DBGLOG(AIS, WARN, "Join fail, disconnect\n"); + } + } + } + DBGLOG(AIS, STATE, "Joined BSS eBand %d channel %d ucChannelBw %d\n", + prAisBssInfo->eBand, prAisBssInfo->ucPrimaryChannel, + rlmDomainGetChannelBw(prAisBssInfo->ucPrimaryChannel)); + return eNextState; +} + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will handle the Grant Msg of IBSS Create which was sent + * by CNM to indicate that channel was changed for creating IBSS. + * + * @param[in] prAdapter Pointer of ADAPTER_T + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmCreateIBSS(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + + ASSERT(prAdapter); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + do { + /* Check State */ + if (prAisFsmInfo->eCurrentState == AIS_STATE_IBSS_ALONE) { + aisUpdateBssInfoForCreateIBSS(prAdapter); + } + } while (false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will handle the Grant Msg of IBSS Merge which was sent + * by CNM to indicate that channel was changed for merging IBSS. + * + * @param[in] prAdapter Pointer of ADAPTER_T + * @param[in] prStaRec Pointer of STA_RECORD_T for merge + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmMergeIBSS(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + P_BSS_INFO_T prAisBssInfo; + + ASSERT(prAdapter); + ASSERT(prStaRec); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = prAdapter->prAisBssInfo; + + do { + eNextState = prAisFsmInfo->eCurrentState; + + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_IBSS_MERGE: { + P_BSS_DESC_T prBssDesc; + + /* 4 <1.1> Change FW's Media State immediately. */ + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + /* 4 <1.2> Deactivate previous Peers' STA_RECORD_T in + * Driver if have. */ + bssInitializeClientList(prAdapter, prAisBssInfo); + + /* 4 <1.3> Unmark connection flag of previous + * BSS_DESC_T. */ + prBssDesc = + scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + if (prBssDesc != NULL) { + prBssDesc->fgIsConnecting = false; + prBssDesc->fgIsConnected = false; + } + /* 4 <1.4> Add Peers' STA_RECORD_T to Client List */ + bssAddClient(prAdapter, prAisBssInfo, prStaRec); + + /* 4 <1.5> Activate current Peer's STA_RECORD_T in + * Driver. */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + prStaRec->fgIsMerging = false; + + /* 4 <1.6> Update BSS_INFO_T */ + aisUpdateBssInfoForMergeIBSS(prAdapter, prStaRec); + + /* 4 <1.7> Enable other features */ + + /* 4 <1.8> Indicate Connected Event to Host immediately. + */ + aisIndicationOfMediaStateToHost(prAdapter, + PARAM_MEDIA_STATE_CONNECTED, + false); + + /* 4 <1.9> Set the Next State of AIS FSM */ + eNextState = AIS_STATE_NORMAL_TR; + + /* 4 <1.10> Release channel privilege */ + aisFsmReleaseCh(prAdapter); + } break; + + default: + break; + } + + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } + } while (false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will handle the Notification of existing IBSS was found + * from SCN. + * + * @param[in] prMsgHdr Message of Notification of an IBSS was present. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmRunEventFoundIBSSPeer(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_AIS_IBSS_PEER_FOUND_T prAisIbssPeerFoundMsg; + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prAisBssInfo; + P_BSS_DESC_T prBssDesc; + u8 fgIsMergeIn; + + ASSERT(prMsgHdr); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = prAdapter->prAisBssInfo; + + prAisIbssPeerFoundMsg = (P_MSG_AIS_IBSS_PEER_FOUND_T)prMsgHdr; + + ASSERT(prAisIbssPeerFoundMsg->ucBssIndex == + prAdapter->prAisBssInfo->ucBssIndex); + + prStaRec = prAisIbssPeerFoundMsg->prStaRec; + ASSERT(prStaRec); + + fgIsMergeIn = prAisIbssPeerFoundMsg->fgIsMergeIn; + + cnmMemFree(prAdapter, prMsgHdr); + + eNextState = prAisFsmInfo->eCurrentState; + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_IBSS_ALONE: { + /* 4 <1> An IBSS Peer 'merged in'. */ + if (fgIsMergeIn) { + /* 4 <1.1> Change FW's Media State immediately. */ + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + /* 4 <1.2> Add Peers' STA_RECORD_T to Client List */ + bssAddClient(prAdapter, prAisBssInfo, prStaRec); + + /* 4 <1.3> Mark connection flag of BSS_DESC_T. */ + prBssDesc = + scanSearchBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + + if (prBssDesc != NULL) { + prBssDesc->fgIsConnecting = false; + prBssDesc->fgIsConnected = true; + } else { + ASSERT(0); /* Should be able to find a + BSS_DESC_T here. */ + } + + /* 4 <1.4> Activate current Peer's STA_RECORD_T in + * Driver. */ + prStaRec->fgIsQoS = false; /* TODO(Kevin): TBD */ + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + prStaRec->fgIsMerging = false; + + /* 4 <1.6> sync. to firmware */ + nicUpdateBss(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + /* 4 <1.7> Indicate Connected Event to Host immediately. + */ + aisIndicationOfMediaStateToHost(prAdapter, + PARAM_MEDIA_STATE_CONNECTED, + false); + + /* 4 <1.8> indicate PM for connected */ + nicPmIndicateBssConnected(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex); + + /* 4 <1.9> Set the Next State of AIS FSM */ + eNextState = AIS_STATE_NORMAL_TR; + + /* 4 <1.10> Release channel privilege */ + aisFsmReleaseCh(prAdapter); + } + /* 4 <2> We need 'merge out' to this IBSS */ + else { + /* 4 <2.1> Get corresponding BSS_DESC_T */ + prBssDesc = scanSearchBssDescByTA(prAdapter, + prStaRec->aucMacAddr); + + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + /* 4 <2.2> Set the Next State of AIS FSM */ + eNextState = AIS_STATE_IBSS_MERGE; + } + } break; + + case AIS_STATE_NORMAL_TR: { + /* 4 <3> An IBSS Peer 'merged in'. */ + if (fgIsMergeIn) { + /* 4 <3.1> Add Peers' STA_RECORD_T to Client List */ + bssAddClient(prAdapter, prAisBssInfo, prStaRec); + + /* 4 <3.2> Activate current Peer's STA_RECORD_T in + * Driver. */ + prStaRec->fgIsQoS = false; /* TODO(Kevin): TBD */ + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + prStaRec->fgIsMerging = false; + } + /* 4 <4> We need 'merge out' to this IBSS */ + else { + /* 4 <4.1> Get corresponding BSS_DESC_T */ + prBssDesc = scanSearchBssDescByTA(prAdapter, + prStaRec->aucMacAddr); + + prAisFsmInfo->prTargetBssDesc = prBssDesc; + + /* 4 <4.2> Set the Next State of AIS FSM */ + eNextState = AIS_STATE_IBSS_MERGE; + } + } break; + + default: + break; + } + + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will indicate the Media State to HOST + * + * @param[in] eConnectionState Current Media State + * @param[in] fgDelayIndication Set true for postponing the Disconnect + * Indication. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisIndicationOfMediaStateToHost(IN P_ADAPTER_T prAdapter, + ENUM_PARAM_MEDIA_STATE_T eConnectionState, + u8 fgDelayIndication) +{ + EVENT_CONNECTION_STATUS rEventConnStatus; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + P_AIS_FSM_INFO_T prAisFsmInfo; + + DEBUGFUNC("aisIndicationOfMediaStateToHost()"); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = prAdapter->prAisBssInfo; + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + DBGLOG(AIS, LOUD, + "AIS indicate Media State to Host Current State [%d]\n", + prAisBssInfo->eConnectionState); + + /* NOTE(Kevin): Move following line to aisChangeMediaState() macro per + * CM's request. */ + /* prAisBssInfo->eConnectionState = eConnectionState; */ + + /* For indicating the Disconnect Event only if current media state is + * disconnected and we didn't do indication yet. + */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + if (prAisBssInfo->eConnectionStateIndicated == eConnectionState) { + return; + } + } + + if (!fgDelayIndication) { + /* 4 <0> Cancel Delay Timer */ + cnmTimerStopTimer(prAdapter, + &prAisFsmInfo->rIndicationOfDisconnectTimer); + + /* 4 <1> Fill EVENT_CONNECTION_STATUS */ + rEventConnStatus.ucMediaStatus = (u8)eConnectionState; + + if (eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + rEventConnStatus.ucReasonOfDisconnect = + DISCONNECT_REASON_CODE_RESERVED; + + if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + rEventConnStatus.ucInfraMode = (u8)NET_TYPE_INFRA; + rEventConnStatus.u2AID = prAisBssInfo->u2AssocId; + rEventConnStatus.u2ATIMWindow = 0; + } else if (prAisBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + rEventConnStatus.ucInfraMode = (u8)NET_TYPE_IBSS; + rEventConnStatus.u2AID = 0; + rEventConnStatus.u2ATIMWindow = prAisBssInfo->u2ATIMWindow; + } else { + ASSERT(0); + } + + COPY_SSID(rEventConnStatus.aucSsid, rEventConnStatus.ucSsidLen, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + + COPY_MAC_ADDR(rEventConnStatus.aucBssid, + prAisBssInfo->aucBSSID); + + rEventConnStatus.u2BeaconPeriod = + prAisBssInfo->u2BeaconInterval; + rEventConnStatus.u4FreqInKHz = + nicChannelNum2Freq(prAisBssInfo->ucPrimaryChannel); + + switch (prAisBssInfo->ucNonHTBasicPhyType) { + case PHY_TYPE_HR_DSSS_INDEX: + rEventConnStatus.ucNetworkType = (u8)PARAM_NETWORK_TYPE_DS; + break; + + case PHY_TYPE_ERP_INDEX: + rEventConnStatus.ucNetworkType = + (u8)PARAM_NETWORK_TYPE_OFDM24; + break; + + case PHY_TYPE_OFDM_INDEX: + rEventConnStatus.ucNetworkType = + (u8)PARAM_NETWORK_TYPE_OFDM5; + break; + + default: + ASSERT(0); + rEventConnStatus.ucNetworkType = (u8)PARAM_NETWORK_TYPE_DS; + break; + } + } else { + /* Clear the pmkid cache while media disconnect */ + secClearPmkid(prAdapter); + rEventConnStatus.ucReasonOfDisconnect = + prAisBssInfo->ucReasonOfDisconnect; + } + + /* 4 <2> Indication */ + nicMediaStateChange(prAdapter, prAdapter->prAisBssInfo->ucBssIndex, + &rEventConnStatus); + prAisBssInfo->eConnectionStateIndicated = eConnectionState; + } else { + /* NOTE: Only delay the Indication of Disconnect Event */ + ASSERT(eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED); + +#if CFG_SUPPORT_DBDC_TC6 + if (prAisBssInfo->ucReasonOfDisconnect == + DISCONNECT_REASON_CODE_DBDC_REASSOCIATION || + cnmGetp2pSapBssInfo(prAdapter) || + prAdapter->rWifiVar.fgDbDcModeEn) { + DBGLOG( + AIS, INFO, + "[DBDC] Postpone the indication of Disconnect for %d seconds\n", + DBDC_AIS_REASSOC_DELAY_DISCONNECT_EVENT_TIME / 1000); + + cnmTimerStartTimer(prAdapter, + &prAisFsmInfo->rIndicationOfDisconnectTimer, + DBDC_AIS_REASSOC_DELAY_DISCONNECT_EVENT_TIME); + } else +#endif + { + DBGLOG(AIS, INFO, + "Postpone the indication of Disconnect for %d seconds\n", + prConnSettings->ucDelayTimeOfDisconnectEvent); + + cnmTimerStartTimer( + prAdapter, &prAisFsmInfo->rIndicationOfDisconnectTimer, + SEC_TO_MSEC(prConnSettings->ucDelayTimeOfDisconnectEvent)); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will indicate an Event of "Media Disconnect" to HOST + * + * @param[in] u4Param Unused timer parameter + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisPostponedEventOfDisconnTimeout(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr) +{ + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + + prAisBssInfo = prAdapter->prAisBssInfo; + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + DBGLOG(AIS, EVENT, "aisPostponedEventOfDisconnTimeout\n"); + + /* 4 <1> Deactivate previous AP's STA_RECORD_T in Driver if have. */ + if (prAisBssInfo->prStaRecOfAP) { + /* cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, + * STA_STATE_1); */ + + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + } + /* 4 <2> Remove pending connection request */ + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, true); + prConnSettings->fgIsDisconnectedByNonRequest = true; + prAisBssInfo->u2DeauthReason += REASON_CODE_BEACON_TIMEOUT; + /* 4 <3> Indicate Disconnected Event to Host immediately. */ + aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_RADIO_LOST, false); + //aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED, false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will update the contain of BSS_INFO_T for AIS network + * once the association was completed. + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] prAssocRspSwRfb Pointer to SW RFB of ASSOC RESP FRAME. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, + P_SW_RFB_T prAssocRspSwRfb) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; + P_BSS_DESC_T prBssDesc; + u16 u2IELength; + u8 *pucIE; + PARAM_SSID_T rParamSsid; + + DEBUGFUNC("aisUpdateBssInfoForJOIN()"); + + ASSERT(prStaRec); + ASSERT(prAssocRspSwRfb); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = prAdapter->prAisBssInfo; + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)prAssocRspSwRfb->pvHeader; + + DBGLOG(AIS, INFO, "Update AIS_BSS_INFO_T and apply settings to MAC\n"); + + /* 3 <1> Update BSS_INFO_T from AIS_FSM_INFO_T or User Settings */ + /* 4 <1.1> Setup Operation Mode */ + prAisBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; + + /* 4 <1.2> Setup SSID */ + COPY_SSID(prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + + /* 4 <1.3> Setup Channel, Band */ + prAisBssInfo->ucPrimaryChannel = + prAisFsmInfo->prTargetBssDesc->ucChannelNum; + prAisBssInfo->eBand = prAisFsmInfo->prTargetBssDesc->eBand; + + /* 3 <2> Update BSS_INFO_T from STA_RECORD_T */ + /* 4 <2.1> Save current AP's STA_RECORD_T and current AID */ + prAisBssInfo->prStaRecOfAP = prStaRec; + DBGLOG(AIS, EVENT, "Update target Sta Rec to :%d\n", prStaRec->ucIndex); + prAisBssInfo->u2AssocId = prStaRec->u2AssocId; + + /* 4 <2.2> Setup Capability */ + prAisBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use AP's Cap Info as + BSS Cap Info */ + + if (prAisBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) { + prAisBssInfo->fgIsShortPreambleAllowed = true; + } else { + prAisBssInfo->fgIsShortPreambleAllowed = false; + } + +#if CFG_SUPPORT_TDLS + prAisBssInfo->fgTdlsIsProhibited = prStaRec->fgTdlsIsProhibited; + prAisBssInfo->fgTdlsIsChSwProhibited = prStaRec->fgTdlsIsChSwProhibited; +#endif + + /* 4 <2.3> Setup PHY Attributes and Basic Rate Set/Operational Rate Set + */ + prAisBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; + + prAisBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; + + prAisBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; + prAisBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; + + nicTxUpdateBssDefaultRate(prAisBssInfo); + + /* 3 <3> Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) */ + /* 4 <3.1> Setup BSSID */ + COPY_MAC_ADDR(prAisBssInfo->aucBSSID, prAssocRspFrame->aucBSSID); + + u2IELength = + (u16)((prAssocRspSwRfb->u2PacketLen - + prAssocRspSwRfb->u2HeaderLen) - + (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - + WLAN_MAC_MGMT_HEADER_LEN)); + pucIE = prAssocRspFrame->aucInfoElem; + + /* 4 <3.2> Parse WMM and setup QBSS flag */ + /* Parse WMM related IEs and configure HW CRs accordingly */ + mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + prAisBssInfo->fgIsQBSS = prStaRec->fgIsQoS; + + /* 3 <4> Update BSS_INFO_T from BSS_DESC_T */ + if (prAisBssInfo->ucSSIDLen) { + rParamSsid.u4SsidLen = prAisBssInfo->ucSSIDLen; + COPY_SSID(rParamSsid.aucSsid, rParamSsid.u4SsidLen, + prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen); + prBssDesc = scanSearchBssDescByBssidAndSsid( + prAdapter, prAisBssInfo->aucBSSID, true, &rParamSsid); + } else { + prBssDesc = scanSearchBssDescByBssidAndChanNum( + prAdapter, prConnSettings->aucBSSID, true, + prConnSettings->ucChannelNum); + } + + if (prBssDesc) { + prBssDesc->fgIsConnecting = false; + prBssDesc->fgIsConnected = true; + prBssDesc->ucJoinFailureCount = 0; + /* 4 <4.1> Setup MIB for current BSS */ + prAisBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; + } else { + /* should never happen */ + ASSERT(0); + } + + /* NOTE: Defer ucDTIMPeriod updating to when beacon is received after + * connection */ + prAisBssInfo->ucDTIMPeriod = 0; + prAisBssInfo->u2ATIMWindow = 0; + + prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_INFRA; +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP + prAisBssInfo->ucRoamSkipTimes = ROAMING_ONE_AP_SKIP_TIMES; + prAisBssInfo->fgGoodRcpiArea = false; + prAisBssInfo->fgPoorRcpiArea = false; +#endif + +#if CFG_SUPPORT_QUIET + prAisBssInfo->ucQuietPeriod = 0; + prAisBssInfo->u2QuietOffset = 0; + prAisBssInfo->u2QuietDuration = 0; + prAisBssInfo->fgRequestQuietInterval = false; + prAisBssInfo->fgIsInQuietInterval = false; +#endif + + /* 4 <4.2> Update HT information and set channel */ + /* Record HT related parameters in rStaRec and rBssInfo + * Note: it shall be called before nicUpdateBss() + */ + rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + secPostUpdateAddr(prAdapter, prAdapter->prAisBssInfo); + + /* 4 <4.3> Sync with firmware for BSS-INFO */ + nicUpdateBss(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + /* 4 <4.4> *DEFER OPERATION* nicPmIndicateBssConnected() will be invoked + */ + /* inside scanProcessBeaconAndProbeResp() after 1st beacon is received + */ +} + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will create an Ad-Hoc network and start sending Beacon + * Frames. + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisUpdateBssInfoForCreateIBSS(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = prAdapter->prAisBssInfo; + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + if (prAisBssInfo->fgIsBeaconActivated) { + return; + } + + /* 3 <1> Update BSS_INFO_T per Network Basis */ + /* 4 <1.1> Setup Operation Mode */ + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + + /* 4 <1.2> Setup SSID */ + COPY_SSID(prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + + /* 4 <1.3> Clear current AP's STA_RECORD_T and current AID */ + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + prAisBssInfo->u2AssocId = 0; + + /* 4 <1.4> Setup Channel, Band and Phy Attributes */ + prAisBssInfo->ucPrimaryChannel = prConnSettings->ucAdHocChannelNum; + prAisBssInfo->eBand = prConnSettings->eAdHocBand; + + if (prAisBssInfo->eBand == BAND_2G4) { + /* Depend on eBand */ + prAisBssInfo->ucPhyTypeSet = + prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11BGN; + /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prAisBssInfo->ucConfigAdHocAPMode = AD_HOC_MODE_MIXED_11BG; + } else { + /* Depend on eBand */ + prAisBssInfo->ucPhyTypeSet = + prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11ANAC; + /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prAisBssInfo->ucConfigAdHocAPMode = AD_HOC_MODE_11A; + } + + /* 4 <1.5> Setup MIB for current BSS */ + prAisBssInfo->u2BeaconInterval = prConnSettings->u2BeaconPeriod; + prAisBssInfo->ucDTIMPeriod = 0; + prAisBssInfo->u2ATIMWindow = prConnSettings->u2AtimWindow; + + prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_ADHOC; + + if (prConnSettings->eEncStatus == ENUM_ENCRYPTION1_ENABLED || + prConnSettings->eEncStatus == ENUM_ENCRYPTION2_ENABLED || + prConnSettings->eEncStatus == ENUM_ENCRYPTION3_ENABLED) { + prAisBssInfo->fgIsProtection = true; + } else { + prAisBssInfo->fgIsProtection = false; + } + + /* 3 <2> Update BSS_INFO_T common part */ + ibssInitForAdHoc(prAdapter, prAisBssInfo); + /* 4 <2.1> Initialize client list */ + bssInitializeClientList(prAdapter, prAisBssInfo); + + /* 3 <3> Set MAC HW */ + /* 4 <3.1> Setup channel and bandwidth */ + rlmBssInitForAPandIbss(prAdapter, prAisBssInfo); + + /* 4 <3.2> use command packets to inform firmware */ + nicUpdateBss(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + /* 4 <3.3> enable beaconing */ + bssUpdateBeaconContent(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + /* 4 <3.4> Update AdHoc PM parameter */ + nicPmIndicateBssCreated(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + /* 3 <4> Set ACTIVE flag. */ + prAisBssInfo->fgIsBeaconActivated = true; + prAisBssInfo->fgHoldSameBssidForIBSS = true; + + /* 3 <5> Start IBSS Alone Timer */ + cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer, + SEC_TO_MSEC(AIS_IBSS_ALONE_TIMEOUT_SEC)); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will update the contain of BSS_INFO_T for AIS network + * once the existing IBSS was found. + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisUpdateBssInfoForMergeIBSS(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_DESC_T prBssDesc; + /* u16 u2IELength; */ + /* u8 * pucIE; */ + + ASSERT(prStaRec); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = prAdapter->prAisBssInfo; + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rIbssAloneTimer); + + if (!prAisBssInfo->fgIsBeaconActivated) { + /* 3 <1> Update BSS_INFO_T per Network Basis */ + /* 4 <1.1> Setup Operation Mode */ + prAisBssInfo->eCurrentOPMode = OP_MODE_IBSS; + + /* 4 <1.2> Setup SSID */ + COPY_SSID(prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + + /* 4 <1.3> Clear current AP's STA_RECORD_T and current AID */ + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + prAisBssInfo->u2AssocId = 0; + } + /* 3 <2> Update BSS_INFO_T from STA_RECORD_T */ + /* 4 <2.1> Setup Capability */ + prAisBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use Peer's Cap Info as + IBSS Cap Info */ + + if (prAisBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) { + prAisBssInfo->fgIsShortPreambleAllowed = true; + prAisBssInfo->fgUseShortPreamble = true; + } else { + prAisBssInfo->fgIsShortPreambleAllowed = false; + prAisBssInfo->fgUseShortPreamble = false; + } + + /* 7.3.1.4 For IBSS, the Short Slot Time subfield shall be set to 0. */ + prAisBssInfo->fgUseShortSlotTime = false; /* Set to false for AdHoc */ + prAisBssInfo->u2CapInfo &= ~CAP_INFO_SHORT_SLOT_TIME; + + if (prAisBssInfo->u2CapInfo & CAP_INFO_PRIVACY) { + prAisBssInfo->fgIsProtection = true; + } else { + prAisBssInfo->fgIsProtection = false; + } + + /* 4 <2.2> Setup PHY Attributes and Basic Rate Set/Operational Rate Set + */ + prAisBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; + + prAisBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; + + prAisBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; + prAisBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; + + rateGetDataRatesFromRateSet(prAisBssInfo->u2OperationalRateSet, + prAisBssInfo->u2BSSBasicRateSet, + prAisBssInfo->aucAllSupportedRates, + &prAisBssInfo->ucAllSupportedRatesLen); + + /* 3 <3> X Update BSS_INFO_T from SW_RFB_T (Association Resp Frame) */ + + /* 3 <4> Update BSS_INFO_T from BSS_DESC_T */ + prBssDesc = scanSearchBssDescByTA(prAdapter, prStaRec->aucMacAddr); + if (prBssDesc) { + prBssDesc->fgIsConnecting = false; + prBssDesc->fgIsConnected = true; + + /* 4 <4.1> Setup BSSID */ + COPY_MAC_ADDR(prAisBssInfo->aucBSSID, prBssDesc->aucBSSID); + + /* 4 <4.2> Setup Channel, Band */ + prAisBssInfo->ucPrimaryChannel = prBssDesc->ucChannelNum; + prAisBssInfo->eBand = prBssDesc->eBand; + + /* 4 <4.3> Setup MIB for current BSS */ + prAisBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; + prAisBssInfo->ucDTIMPeriod = 0; + prAisBssInfo->u2ATIMWindow = 0; /* TBD(Kevin) */ + + prAisBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_ADHOC; + } else { + /* should never happen */ + ASSERT(0); + } + + /* 3 <5> Set MAC HW */ + /* 4 <5.1> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ + nicTxUpdateBssDefaultRate(prAisBssInfo); + + /* 4 <5.2> Setup channel and bandwidth */ + rlmBssInitForAPandIbss(prAdapter, prAisBssInfo); + + /* 4 <5.3> use command packets to inform firmware */ + nicUpdateBss(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + /* 4 <5.4> enable beaconing */ + bssUpdateBeaconContent(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + /* 4 <5.5> Update AdHoc PM parameter */ + nicPmIndicateBssConnected(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex); + + /* 3 <6> Set ACTIVE flag. */ + prAisBssInfo->fgIsBeaconActivated = true; + prAisBssInfo->fgHoldSameBssidForIBSS = true; +} +#endif + +#if (CFG_SUPPORT_ADHOC || CFG_SUPPORT_PROBE_REQ_REPORT) +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will validate the Rx Probe Request Frame and then return + * result to BSS to indicate if need to send the corresponding Probe + * Response Frame if the specified conditions were matched. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prSwRfb Pointer to SW RFB data structure. + * @param[out] pu4ControlFlags Control flags for replying the Probe Response + * + * @retval true Reply the Probe Response + * @retval false Don't reply the Probe Response + */ +/*----------------------------------------------------------------------------*/ +u8 aisValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + OUT u32 *pu4ControlFlags) +{ + P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; + P_BSS_INFO_T prBssInfo; + P_IE_SSID_T prIeSsid = (P_IE_SSID_T)NULL; + u8 *pucIE; + u16 u2IELength; + u16 u2Offset = 0; + u8 fgReplyProbeResp = false; + P_AIS_FSM_INFO_T prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + ASSERT(prSwRfb); + ASSERT(pu4ControlFlags); + + prBssInfo = prAdapter->prAisBssInfo; + + /* 4 <1> Parse Probe Req IE and Get IE ptr (SSID, Supported Rate IE, + * ...) */ + prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T)prSwRfb->pvHeader; + + u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; + pucIE = (u8 *)((unsigned long)prSwRfb->pvHeader + prSwRfb->u2HeaderLen); + + IE_FOR_EACH(pucIE, u2IELength, u2Offset){ + if (IE_ID(pucIE) == ELEM_ID_SSID) { + if ((!prIeSsid) && (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { + prIeSsid = (P_IE_SSID_T)pucIE; + } + + break; + } + } /* end of IE_FOR_EACH */ + + /* 4 <2> Check network conditions */ + + if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + if ((prIeSsid) && + ((prIeSsid->ucLength == BC_SSID_LEN) || /* WILDCARD SSID */ + EQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, /* CURRENT + SSID + */ + prIeSsid->aucSSID, prIeSsid->ucLength))) { + fgReplyProbeResp = true; + } + } + + if (prAisFsmInfo->u4AisPacketFilter & PARAM_PACKET_FILTER_PROBE_REQ) { + DBGLOG(AIS, INFO, "[AIS] RX Probe Req Frame\n"); + kalIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); + } + + return fgReplyProbeResp; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will modify and update necessary information to firmware + * for disconnection handling + * + * @param[in] prAdapter Pointer to the Adapter structure. + * + * @retval None + */ +/*----------------------------------------------------------------------------*/ +void aisFsmDisconnect(IN P_ADAPTER_T prAdapter, IN u8 fgDelayIndication) +{ + P_BSS_INFO_T prAisBssInfo; + + ASSERT(prAdapter); + + prAisBssInfo = prAdapter->prAisBssInfo; + + nicPmIndicateBssAbort(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + +#if CFG_SUPPORT_ADHOC + if (prAisBssInfo->fgIsBeaconActivated) { + nicUpdateBeaconIETemplate(prAdapter, IE_UPD_METHOD_DELETE_ALL, + prAdapter->prAisBssInfo->ucBssIndex, 0, + NULL, + 0); + + prAisBssInfo->fgIsBeaconActivated = false; + } +#endif + + rlmBssAborted(prAdapter, prAisBssInfo); + + /* 4 <3> Unset the fgIsConnected flag of BSS_DESC_T and send Deauth if + * needed. */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + { + if (prAdapter->rWifiVar.ucTpTestMode != + ENUM_TP_TEST_MODE_NORMAL) { + nicEnterTPTestMode(prAdapter, TEST_MODE_NONE); + } + } + + if (prAisBssInfo->ucReasonOfDisconnect == + DISCONNECT_REASON_CODE_RADIO_LOST) { + scanRemoveBssDescByBssid(prAdapter, prAisBssInfo->aucBSSID); + + /* remove from scanning results as well */ + wlanClearBssInScanningResult(prAdapter, prAisBssInfo->aucBSSID); + + /* trials for re-association */ + if (fgDelayIndication) { + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_RECONNECT, + true); + aisFsmInsertRequest(prAdapter, AIS_REQUEST_RECONNECT); + } + } else { + scanRemoveConnFlagOfBssDescByBssid(prAdapter, + prAisBssInfo->aucBSSID); + } + + if (fgDelayIndication) { + if (prAisBssInfo->eCurrentOPMode != OP_MODE_IBSS) { + prAisBssInfo->fgHoldSameBssidForIBSS = false; + } + } else { + prAisBssInfo->fgHoldSameBssidForIBSS = false; + } + } else { + prAisBssInfo->fgHoldSameBssidForIBSS = false; + } + + /* 4 <4> Change Media State immediately. */ + if (prAisBssInfo->ucReasonOfDisconnect != + DISCONNECT_REASON_CODE_REASSOCIATION) { + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + +#if CFG_STR_DHCP_RENEW_OFFLOAD + if (prAisBssInfo->fgIsDhcpAcked) { + prAisBssInfo->fgIsDhcpAcked = false; + prAisBssInfo->u4DhcpRenewIntv = 0; + kalMemZero(prAisBssInfo->aucDhcpServerIpAddr, + sizeof(prAisBssInfo->aucDhcpServerIpAddr)); + } +#endif + + /* 4 <4.1> sync. with firmware */ + nicUpdateBss(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + } + + if (!fgDelayIndication) { + /* 4 <5> Deactivate previous AP's STA_RECORD_T or all Clients in + * Driver if have. */ + if (prAisBssInfo->prStaRecOfAP) { + /* cnmStaRecChangeState(prAdapter, + * prAisBssInfo->prStaRecOfAP, STA_STATE_1); */ + prAisBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + } + } +#if CFG_SUPPORT_ROAMING + roamingFsmRunEventAbort(prAdapter); + + /* clear pending roaming connection request */ + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, true); + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, true); +#endif + + /* 4 <6> Indicate Disconnected Event to Host */ + aisIndicationOfMediaStateToHost(prAdapter, + PARAM_MEDIA_STATE_DISCONNECTED, + fgDelayIndication); + + /* 4 <7> Trigger AIS FSM */ + aisFsmSteps(prAdapter, AIS_STATE_IDLE); +} + +static void aisFsmRunEventScanDoneTimeOut(IN P_ADAPTER_T prAdapter, + unsigned long ulParam) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + P_CONNECTION_SETTINGS_T prConnSettings; + + DEBUGFUNC("aisFsmRunEventScanDoneTimeOut()"); + + ASSERT(prAdapter); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + DBGLOG(AIS, STATE, "aisFsmRunEventScanDoneTimeOut Current[%d]\n", + prAisFsmInfo->eCurrentState); + + /* report all scanned frames to upper layer to avoid scanned frame is + * timeout */ + /* must be put before kalScanDone */ + /* scanReportBss2Cfg80211(prAdapter,BSS_TYPE_INFRASTRUCTURE,NULL); */ + + prConnSettings->fgIsScanReqIssued = false; + kalScanDone(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, + WLAN_STATUS_SUCCESS); + eNextState = prAisFsmInfo->eCurrentState; + + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_SCAN: + prAisFsmInfo->u4ScanIELength = 0; + eNextState = AIS_STATE_IDLE; + break; + case AIS_STATE_ONLINE_SCAN: + /* reset scan IE buffer */ + prAisFsmInfo->u4ScanIELength = 0; +#if CFG_SUPPORT_ROAMING + eNextState = aisFsmRoamingScanResultsUpdate(prAdapter); +#else + eNextState = AIS_STATE_NORMAL_TR; +#endif + break; + default: + break; + } + + /* try to stop scan in CONNSYS */ + aisFsmStateAbort_SCAN(prAdapter); + + /* wlanQueryDebugCode(prAdapter); */ /* display current SCAN FSM in FW, + debug use */ + + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will run aisBssBeaconTimeout + * + * @param[in] u4Param Unused timer parameter + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmBeaconLostTimeOut(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr) +{ + DBGLOG(AIS, STATE, "Beacon Lost timer expires\n"); + ASSERT(prAdapter); + aisBssBeaconTimeout(prAdapter, DISCONNECT_REASON_CODE_RADIO_LOST); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will indicate an Event of "Background Scan Time-Out" to + * AIS FSM. + * + * @param[in] u4Param Unused timer parameter + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmRunEventBGSleepTimeOut(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + + DEBUGFUNC("aisFsmRunEventBGSleepTimeOut()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + eNextState = prAisFsmInfo->eCurrentState; + + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_WAIT_FOR_NEXT_SCAN: + DBGLOG(AIS, LOUD, + "EVENT - SCAN TIMER: Idle End - Current Time = %u\n", + kalGetTimeTick()); + + eNextState = AIS_STATE_LOOKING_FOR; + + SET_NET_PWR_STATE_ACTIVE(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex); + + break; + + default: + break; + } + + /* Call aisFsmSteps() when we are going to change AIS STATE */ + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will indicate an Event of "IBSS ALONE Time-Out" to AIS + * FSM. + * + * @param[in] u4Param Unused timer parameter + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmRunEventIbssAloneTimeOut(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + + DEBUGFUNC("aisFsmRunEventIbssAloneTimeOut()"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + eNextState = prAisFsmInfo->eCurrentState; + + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_IBSS_ALONE: + + /* There is no one participate in our AdHoc during this TIMEOUT + * Interval so go back to search for a valid IBSS again. + */ + + DBGLOG(AIS, LOUD, "EVENT-IBSS ALONE TIMER: Start pairing\n"); + + prAisFsmInfo->fgTryScan = true; + + /* abort timer */ + aisFsmReleaseCh(prAdapter); + + /* Pull back to SEARCH to find candidate again */ + eNextState = AIS_STATE_SEARCH; + + break; + + default: + break; + } + + /* Call aisFsmSteps() when we are going to change AIS STATE */ + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will indicate an Event of "Join Time-Out" to AIS FSM. + * + * @param[in] u4Param Unused timer parameter + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmRunEventJoinTimeout(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr) +{ + P_BSS_INFO_T prAisBssInfo; + P_AIS_FSM_INFO_T prAisFsmInfo; + ENUM_AIS_STATE_T eNextState; + u32 rCurrentTime; + + DEBUGFUNC("aisFsmRunEventJoinTimeout()"); + + prAisBssInfo = prAdapter->prAisBssInfo; + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + eNextState = prAisFsmInfo->eCurrentState; + + GET_CURRENT_SYSTIME(&rCurrentTime); + + switch (prAisFsmInfo->eCurrentState) { + case AIS_STATE_JOIN: + DBGLOG(AIS, LOUD, "EVENT- JOIN TIMEOUT\n"); + + /* 1. Do abort JOIN */ + aisFsmStateAbort_JOIN(prAdapter); + + /* 2. Increase Join Failure Count */ + prAisFsmInfo->prTargetStaRec->ucJoinFailureCount++; + + if (prAisFsmInfo->prTargetStaRec->ucJoinFailureCount < + JOIN_MAX_RETRY_FAILURE_COUNT) { + /* 3.1 Retreat to AIS_STATE_SEARCH state for next try */ + eNextState = AIS_STATE_SEARCH; + } else if (prAisBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) { + /* roaming cases */ + /* 3.2 Retreat to AIS_STATE_WAIT_FOR_NEXT_SCAN state for + * next try */ + eNextState = AIS_STATE_WAIT_FOR_NEXT_SCAN; + } else { + /* 3.4 Retreat to AIS_STATE_JOIN_FAILURE to terminate + * join operation */ + eNextState = AIS_STATE_JOIN_FAILURE; + } + + break; + + case AIS_STATE_NORMAL_TR: + /* 1. release channel */ + aisFsmReleaseCh(prAdapter); + prAisFsmInfo->fgIsInfraChannelFinished = true; + + /* 2. process if there is pending scan */ + if (aisFsmIsRequestPending(prAdapter, AIS_REQUEST_SCAN, + true) == true) { + wlanClearScanningResult(prAdapter); + eNextState = AIS_STATE_ONLINE_SCAN; + } + /* 3. Process for pending roaming scan */ + else if (aisFsmIsRequestPending(prAdapter, + AIS_REQUEST_ROAMING_SEARCH, + true) == true) { + eNextState = AIS_STATE_LOOKING_FOR; + } + /* 4. Process for pending roaming scan */ + else if (aisFsmIsRequestPending(prAdapter, + AIS_REQUEST_ROAMING_CONNECT, + true) == true) { + eNextState = AIS_STATE_SEARCH; + } else if (aisFsmIsRequestPending(prAdapter, + AIS_REQUEST_REMAIN_ON_CHANNEL, + true) == true) { + eNextState = AIS_STATE_REQ_REMAIN_ON_CHANNEL; + } + + break; + + default: + /* release channel */ + aisFsmReleaseCh(prAdapter); + prAisFsmInfo->fgIsInfraChannelFinished = true; + DBGLOG(AIS, WARN, "Join Timeout in state(%d)\n", + prAisFsmInfo->eCurrentState); + break; + } + + /* Call aisFsmSteps() when we are going to change AIS STATE */ + if (eNextState != prAisFsmInfo->eCurrentState) { + aisFsmSteps(prAdapter, eNextState); + } +} + +void aisFsmRunEventDeauthTimeout(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr) +{ + DBGLOG(AIS, EVENT, "aisDeauthTimeout\n"); + aisDeauthXmitComplete(prAdapter, NULL, TX_RESULT_LIFE_TIMEOUT); +} + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +void aisRxMcsCollectionTimeout(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr) +{ + static u8 ucSmapleCnt; + u8 ucStaIdx = 0; + + if (prAdapter->prAisBssInfo->prStaRecOfAP == NULL) { + goto out; + } + + ucStaIdx = prAdapter->prAisBssInfo->prStaRecOfAP->ucIndex; + + if (prAdapter->arStaRec[ucStaIdx].fgIsValid && + prAdapter->arStaRec[ucStaIdx].fgIsInUse) { + prAdapter->arStaRec[ucStaIdx].au4RxVect0Que[ucSmapleCnt] = + prAdapter->arStaRec[ucStaIdx].u4RxVector0; + prAdapter->arStaRec[ucStaIdx].au4RxVect1Que[ucSmapleCnt] = + prAdapter->arStaRec[ucStaIdx].u4RxVector1; + ucSmapleCnt = (ucSmapleCnt + 1) % MCS_INFO_SAMPLE_CNT; + } + +out: + cnmTimerStartTimer(prAdapter, &prAdapter->rRxMcsInfoTimer, 100); +} +#endif + +#if defined(CFG_TEST_MGMT_FSM) && (CFG_TEST_MGMT_FSM != 0) +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void aisTest(void) +{ + P_MSG_AIS_ABORT_T prAisAbortMsg; + P_CONNECTION_SETTINGS_T prConnSettings; + u8 aucSSID[] = "pci-11n"; + u8 ucSSIDLen = 7; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* Set Connection Request Issued Flag */ + prConnSettings->fgIsConnReqIssued = true; + prConnSettings->ucSSIDLen = ucSSIDLen; + kalMemCopy(prConnSettings->aucSSID, aucSSID, ucSSIDLen); + + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + ASSERT(0); /* Can't trigger SCAN FSM */ + return; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_HEM_AIS_FSM_ABORT; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prAisAbortMsg, + MSG_SEND_METHOD_BUF); + + wifi_send_msg(INDX_WIFI, MSG_ID_WIFI_IST, 0); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is used to handle OID_802_11_BSSID_LIST_SCAN + * + * \param[in] prAdapter Pointer of ADAPTER_T + * \param[in] prSsid Pointer of SSID_T if specified + * \param[in] pucIe Pointer to buffer of extra information elements to be + * attached \param[in] u4IeLength Length of information elements + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void aisFsmScanRequest(IN P_ADAPTER_T prAdapter, IN P_PARAM_SSID_T prSsid, + IN u8 *pucIe, IN u32 u4IeLength) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + P_AIS_FSM_INFO_T prAisFsmInfo; + + DEBUGFUNC("aisFsmScanRequest()"); + + ASSERT(prAdapter); + ASSERT(u4IeLength <= MAX_IE_LENGTH); + + prAisBssInfo = prAdapter->prAisBssInfo; + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + if (!prConnSettings->fgIsScanReqIssued) { + prConnSettings->fgIsScanReqIssued = true; + + if (prSsid == NULL) { + prAisFsmInfo->ucScanSSIDNum = 0; + } else { + prAisFsmInfo->ucScanSSIDNum = 1; + + COPY_SSID(prAisFsmInfo->arScanSSID[0].aucSsid, + prAisFsmInfo->arScanSSID[0].u4SsidLen, + prSsid->aucSsid, + prSsid->u4SsidLen); + } + + if (u4IeLength > 0) { + prAisFsmInfo->u4ScanIELength = u4IeLength; + kalMemCopy(prAisFsmInfo->aucScanIEBuf, pucIe, u4IeLength); + } else { + prAisFsmInfo->u4ScanIELength = 0; + } + + if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR) { + if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && + prAisFsmInfo->fgIsInfraChannelFinished == false) { + /* 802.1x might not finished yet, pend it for + * later handling .. */ + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + } else { + if (prAisFsmInfo->fgIsChannelGranted == true) { + DBGLOG( + AIS, WARN, + "Scan Request with channel granted for join operation: %d, %d", + prAisFsmInfo->fgIsChannelGranted, + prAisFsmInfo->fgIsChannelRequested); + } + + /* start online scan */ + wlanClearScanningResult(prAdapter); + aisFsmSteps(prAdapter, AIS_STATE_ONLINE_SCAN); + } + } else if (prAisFsmInfo->eCurrentState == AIS_STATE_IDLE) { + wlanClearScanningResult(prAdapter); + aisFsmSteps(prAdapter, AIS_STATE_SCAN); + } else { + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + } + } else { + DBGLOG(AIS, WARN, "Scan Request dropped. (state: %d)\n", + prAisFsmInfo->eCurrentState); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is used to handle OID_802_11_BSSID_LIST_SCAN + * + * \param[in] prAdapter Pointer of ADAPTER_T + * \param[in] ucSsidNum Number of SSID + * \param[in] prSsid Pointer to the array of SSID_T if specified + * \param[in] pucIe Pointer to buffer of extra information elements to be + * attached \param[in] u4IeLength Length of information elements + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void aisFsmScanRequestAdv(IN P_ADAPTER_T prAdapter, IN u8 ucSsidNum, + IN P_PARAM_SSID_T prSsid, IN u8 ucChannelListNum, + IN P_RF_CHANNEL_INFO_T prChnlInfoList, + IN u8 *pucIe, + IN u32 u4IeLength) +{ + u32 i; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + P_AIS_FSM_INFO_T prAisFsmInfo; + + DEBUGFUNC("aisFsmScanRequestAdv()"); + + ASSERT(prAdapter); + ASSERT(ucSsidNum <= SCN_SSID_MAX_NUM); + ASSERT(u4IeLength <= MAX_IE_LENGTH); + + prAisBssInfo = prAdapter->prAisBssInfo; + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + if (!prConnSettings->fgIsScanReqIssued) { + prConnSettings->fgIsScanReqIssued = true; + + if (ucSsidNum == 0) { + prAisFsmInfo->ucScanSSIDNum = 0; + } else { + prAisFsmInfo->ucScanSSIDNum = ucSsidNum; + + for (i = 0; i < ucSsidNum; i++) { + COPY_SSID(prAisFsmInfo->arScanSSID[i].aucSsid, + prAisFsmInfo->arScanSSID[i].u4SsidLen, + prSsid[i].aucSsid, prSsid[i].u4SsidLen); + } + } + + if (u4IeLength > 0) { + prAisFsmInfo->u4ScanIELength = u4IeLength; + kalMemCopy(prAisFsmInfo->aucScanIEBuf, pucIe, u4IeLength); + } else { + prAisFsmInfo->u4ScanIELength = 0; + } + +#if CFG_SCAN_CHANNEL_SPECIFIED + if (ucChannelListNum) { + prAisFsmInfo->ucScanChannelListNum = ucChannelListNum; + kalMemCopy(prAisFsmInfo->arScanChnlInfoList, prChnlInfoList, + sizeof(RF_CHANNEL_INFO_T) * + prAisFsmInfo->ucScanChannelListNum); + } else { + prAisFsmInfo->ucScanChannelListNum = 0; + } +#endif + + if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR) { + if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE && + prAisFsmInfo->fgIsInfraChannelFinished == false) { + /* 802.1x might not finished yet, pend it for + * later handling .. */ + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + } else { + if (prAisFsmInfo->fgIsChannelGranted == true) { + DBGLOG( + AIS, WARN, + "Scan Request with channel granted for join operation: %d, %d", + prAisFsmInfo->fgIsChannelGranted, + prAisFsmInfo->fgIsChannelRequested); + } + + /* start online scan */ + wlanClearScanningResult(prAdapter); + aisFsmSteps(prAdapter, AIS_STATE_ONLINE_SCAN); + } + } else if (prAisFsmInfo->eCurrentState == AIS_STATE_IDLE) { + wlanClearScanningResult(prAdapter); + aisFsmSteps(prAdapter, AIS_STATE_SCAN); + } else { + aisFsmInsertRequest(prAdapter, AIS_REQUEST_SCAN); + } + } else { + DBGLOG(AIS, WARN, "Scan Request dropped. (state: %d)\n", + prAisFsmInfo->eCurrentState); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is invoked when CNM granted channel privilege + * + * \param[in] prAdapter Pointer of ADAPTER_T + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void aisFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_BSS_INFO_T prAisBssInfo; + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_CH_GRANT_T prMsgChGrant; + u8 ucTokenID; + u32 u4GrantInterval; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prAisBssInfo = prAdapter->prAisBssInfo; + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prMsgChGrant = (P_MSG_CH_GRANT_T)prMsgHdr; + + ucTokenID = prMsgChGrant->ucTokenID; + u4GrantInterval = prMsgChGrant->u4GrantInterval; +#if CFG_SUPPORT_DBDC + if (prAisBssInfo->eDBDCBand == ENUM_BAND_AUTO) { + prAisBssInfo->eDBDCBand = prMsgChGrant->eDBDCBand; + } +#endif + +#if CFG_SISO_SW_DEVELOP + /* Driver record granted CH in BSS info */ + prAisBssInfo->fgIsGranted = true; + prAisBssInfo->eBandGranted = prMsgChGrant->eRfBand; + prAisBssInfo->ucPrimaryChannelGranted = prMsgChGrant->ucPrimaryChannel; +#endif + + /* 1. free message */ + cnmMemFree(prAdapter, prMsgHdr); + + if (prAisFsmInfo->eCurrentState == AIS_STATE_REQ_CHANNEL_JOIN && + prAisFsmInfo->ucSeqNumOfChReq == ucTokenID) { + /* 2. channel privilege has been approved */ + prAisFsmInfo->u4ChGrantedInterval = u4GrantInterval; + + /* 3. state transition to join/ibss-alone/ibss-merge */ + /* 3.1 set timeout timer in cases join could not be completed */ + cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rJoinTimeoutTimer, + prAisFsmInfo->u4ChGrantedInterval - + AIS_JOIN_CH_GRANT_THRESHOLD); + /* 3.2 set local variable to indicate join timer is ticking */ + prAisFsmInfo->fgIsInfraChannelFinished = false; + + /* 3.3 switch to join state */ + aisFsmSteps(prAdapter, AIS_STATE_JOIN); + + prAisFsmInfo->fgIsChannelGranted = true; + } else if (prAisFsmInfo->eCurrentState == + AIS_STATE_REQ_REMAIN_ON_CHANNEL && + prAisFsmInfo->ucSeqNumOfChReq == ucTokenID) { + /* 2. channel privilege has been approved */ + prAisFsmInfo->u4ChGrantedInterval = u4GrantInterval; + + /* 3.1 set timeout timer in cases upper layer + * cancel_remain_on_channel never comes */ + cnmTimerStartTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer, + prAisFsmInfo->u4ChGrantedInterval); + + /* 3.2 switch to remain_on_channel state */ + aisFsmSteps(prAdapter, AIS_STATE_REMAIN_ON_CHANNEL); + + /* 3.3. indicate upper layer for channel ready */ + kalReadyOnChannel(prAdapter->prGlueInfo, + prAisFsmInfo->rChReqInfo.u8Cookie, + prAisFsmInfo->rChReqInfo.eBand, + prAisFsmInfo->rChReqInfo.eSco, + prAisFsmInfo->rChReqInfo.ucChannelNum, + prAisFsmInfo->rChReqInfo.u4DurationMs); + + prAisFsmInfo->fgIsChannelGranted = true; + } else { /* mismatched grant */ + /* 2. return channel privilege to CNM immediately */ + aisFsmReleaseCh(prAdapter); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is to inform CNM that channel privilege + * has been released + * + * \param[in] prAdapter Pointer of ADAPTER_T + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void aisFsmReleaseCh(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_CH_ABORT_T prMsgChAbort; + + ASSERT(prAdapter); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + if (prAisFsmInfo->fgIsChannelGranted == true || + prAisFsmInfo->fgIsChannelRequested == true) { + prAisFsmInfo->fgIsChannelRequested = false; + prAisFsmInfo->fgIsChannelGranted = false; + + /* 1. return channel privilege to CNM immediately */ + prMsgChAbort = (P_MSG_CH_ABORT_T)cnmMemAlloc(prAdapter, + RAM_TYPE_MSG, + sizeof(MSG_CH_ABORT_T)); + if (!prMsgChAbort) { + ASSERT(0); /* Can't release Channel to CNM */ + return; + } + + prMsgChAbort->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; + prMsgChAbort->ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex; + prMsgChAbort->ucTokenID = prAisFsmInfo->ucSeqNumOfChReq; +#if CFG_SUPPORT_DBDC + prMsgChAbort->eDBDCBand = ENUM_BAND_AUTO; +#endif + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsgChAbort, + MSG_SEND_METHOD_BUF); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is to inform AIS that corresponding beacon has not + * been received for a while and probing is not successful + * + * \param[in] prAdapter Pointer of ADAPTER_T + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void aisBssBeaconTimeout(IN P_ADAPTER_T prAdapter, IN u8 ucReasonCode) +{ + P_BSS_INFO_T prAisBssInfo; + u8 fgDoAbortIndication = false; + P_CONNECTION_SETTINGS_T prConnSettings; + P_AIS_FSM_INFO_T prAisFsmInfo; +#if CFG_SUPPORT_DBDC_TC6 + P_CNM_INFO_T prCnmInfo; +#endif + + ASSERT(prAdapter); + + prAisBssInfo = prAdapter->prAisBssInfo; + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); +#if CFG_SUPPORT_DBDC_TC6 + prCnmInfo = &prAdapter->rCnmInfo; +#endif + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + GET_CURRENT_SYSTIME(&(prAisFsmInfo->rJoinReqTime)); + + /* 4 <1> Diagnose Connection for Beacon Timeout Event */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + P_STA_RECORD_T prStaRec = prAisBssInfo->prStaRecOfAP; + + if (prStaRec) { + fgDoAbortIndication = true; + } + } else if (prAisBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + fgDoAbortIndication = true; + } + } + /* 4 <2> invoke abort handler */ + if (fgDoAbortIndication) { + prConnSettings->fgIsDisconnectedByNonRequest = false; + DBGLOG(AIS, EVENT, "aisBssBeaconTimeout\n"); + +#ifdef CFG_STR_DEAUTH_DELAY + if (ucReasonCode == BEACON_TIMEOUT_EVENT_DUE_2_RX_DEAUTH_IN_STR) { + int iCount = 0; + DBGLOG(AIS, STATE, "[STR]: Deauth From STR (%d) \r\n", + kalPmResumeState()); + netif_carrier_off(prAdapter->prGlueInfo->prDevHandler); + + while ((kalPmResumeState() != 1) && (iCount < 400)) { + kalMsleep(20); + iCount++; + } + + DBGLOG(AIS, STATE, "[STR]: PM Resume State (%d, %d)\r\n", + kalPmResumeState(), iCount); + + aisFsmStateAbort(prAdapter, + DISCONNECT_REASON_CODE_DEAUTHENTICATED, + true); + } else +#endif + { + /* 20210326 frog: Once BCN timeout, disconnect + * imediately. */ + prConnSettings->fgIsConnReqIssued = false; +#if CFG_SUPPORT_DBDC + prCnmInfo->fgSkipDbdcDisable = true; + + if (ucReasonCode == + BEACON_TIMEOUT_REASON_DUE_2_DBDC_RECONNECT) { + aisFsmStateAbort( + prAdapter, DISCONNECT_REASON_CODE_DBDC_REASSOCIATION, + true); + } else +#endif + aisFsmStateAbort(prAdapter, + DISCONNECT_REASON_CODE_RADIO_LOST, + true); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is to inform AIS that corresponding beacon has not + * been received for a while and probing is not successful + * + * \param[in] prAdapter Pointer of ADAPTER_T + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void aisBssLinkDown(IN P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prAisBssInfo; + u8 fgDoAbortIndication = false; + P_CONNECTION_SETTINGS_T prConnSettings; + P_AIS_FSM_INFO_T prAisFsmInfo; + + ASSERT(prAdapter); + + prAisBssInfo = prAdapter->prAisBssInfo; + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + if (!prAisFsmInfo) { + return; + } + + /* 4 <1> Diagnose Connection for Beacon Timeout Event */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + if (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + P_STA_RECORD_T prStaRec = prAisBssInfo->prStaRecOfAP; + + if (prStaRec) { + fgDoAbortIndication = true; + } + } else if (prAisBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + fgDoAbortIndication = true; + } + } + /* 4 <2> invoke abort handler */ + if (fgDoAbortIndication) { + prConnSettings->fgIsDisconnectedByNonRequest = true; + DBGLOG(AIS, EVENT, "aisBssLinkDown\n"); + aisFsmStateAbort(prAdapter, DISCONNECT_REASON_CODE_DISASSOCIATED, + false); + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rDeauthDoneTimer); + aisDeauthXmitComplete(prAdapter, NULL, TX_RESULT_LIFE_TIMEOUT); + } else { + DBGLOG(AIS, EVENT, "Skip aisBssLinkDown (state=%d)\n", + prAisBssInfo->eConnectionState); + } + + /* kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + * WLAN_STATUS_SCAN_COMPLETE, NULL, 0); */ +} +#if CFG_SUPPORT_DBDC_TC6 +u8 aisBssChangeNSS(IN P_ADAPTER_T prAdapter, IN u8 fgDbdcEn) +{ + P_BSS_INFO_T prAisBssInfo; + + ASSERT(prAdapter); + + prAisBssInfo = prAdapter->prAisBssInfo; + + /* Update AIS NSS */ + if (fgDbdcEn && prAisBssInfo->ucNss == prAdapter->rWifiVar.ucNSS) { + prAisBssInfo->ucNss = 1; + return true; + } else if (!fgDbdcEn && + prAisBssInfo->ucNss != prAdapter->rWifiVar.ucNSS) { + prAisBssInfo->ucNss = prAdapter->rWifiVar.ucNSS; + return true; + } + + return false; +} +#endif +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is to inform AIS that DEAUTH frame has been + * sent and thus state machine could go ahead + * + * \param[in] prAdapter Pointer of ADAPTER_T + * \param[in] prMsduInfo Pointer of MSDU_INFO_T for DEAUTH frame + * \param[in] prAdapter Pointer of ADAPTER_T + * + * \return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +aisDeauthXmitComplete(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + u8 ucBssIndex = 0; + + ASSERT(prAdapter); + + ucBssIndex = prMsduInfo->ucBssIndex; + if (!IS_BSS_INDEX_AIS(prAdapter, ucBssIndex)) { + DBGLOG(AIS, INFO, "Use default, invalid index = %d\n", ucBssIndex); + ucBssIndex = AIS_DEFAULT_INDEX; + } + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = (prAdapter->aprBssInfo[ucBssIndex]); +#if CFG_SUPPORT_802_11W + /* Notify completion after encrypted deauth frame tx done */ + if (prAisBssInfo->encryptedDeauthIsInProcess == true) { + if (!completion_done(&prAisBssInfo->rDeauthComp)) { + DBGLOG(AIS, EVENT, "Complete rDeauthComp\n"); + complete(&prAisBssInfo->rDeauthComp); + } + } + prAisBssInfo->encryptedDeauthIsInProcess = false; +#endif + if (rTxDoneStatus == TX_RESULT_SUCCESS || + rTxDoneStatus == TX_RESULT_DROPPED_IN_DRIVER) { + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rDeauthDoneTimer); + } + + if (prAisFsmInfo->eCurrentState == AIS_STATE_DISCONNECTING) { + DBGLOG(AIS, EVENT, "aisDeauthXmitComplete, status code: %d\n", + rTxDoneStatus); + if (rTxDoneStatus != TX_RESULT_DROPPED_IN_DRIVER && + rTxDoneStatus != TX_RESULT_QUEUE_CLEARANCE) { + aisFsmStateAbort(prAdapter, + DISCONNECT_REASON_CODE_NEW_CONNECTION, + false); + } + } else { + DBGLOG(AIS, WARN, + "DEAUTH frame transmitted without further handling," + "status code: %d\n", + rTxDoneStatus); + } + + return WLAN_STATUS_SUCCESS; +} + +#if CFG_SUPPORT_ROAMING +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will indicate an Event of "Looking for a candidate due + * to weak signal" to AIS FSM. + * + * @param[in] u4ReqScan Requesting Scan or not + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmRunEventRoamingDiscovery(IN P_ADAPTER_T prAdapter, + u32 u4ReqScan) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + ENUM_AIS_REQUEST_TYPE_T eAisRequest; + + DBGLOG(AIS, LOUD, "aisFsmRunEventRoamingDiscovery()\n"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* search candidates by best rssi */ + prConnSettings->eConnectionPolicy = CONNECT_BY_SSID_BEST_RSSI; + prConnSettings->fgIsConnByBssidIssued = false; + + /* TODO: Stop roaming event in FW */ +#if CFG_SUPPORT_WFD +#if CFG_ENABLE_WIFI_DIRECT + { + /* Check WFD is running */ + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T)NULL; + + prWfdCfgSettings = &(prAdapter->rWifiVar.rWfdConfigureSettings); + if ((prWfdCfgSettings->ucWfdEnable != 0)) { + DBGLOG(ROAMING, INFO, "WFD is running. Stop roaming.\n"); + roamingFsmRunEventRoam(prAdapter); + roamingFsmRunEventFail(prAdapter, + ROAMING_FAIL_REASON_NOCANDIDATE); + return; + } + } +#endif +#endif + + /* results are still new */ + if (!u4ReqScan) { + roamingFsmRunEventRoam(prAdapter); + eAisRequest = AIS_REQUEST_ROAMING_CONNECT; + } else { + if (prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN || + prAisFsmInfo->eCurrentState == AIS_STATE_LOOKING_FOR) { + eAisRequest = AIS_REQUEST_ROAMING_CONNECT; + } else { + eAisRequest = AIS_REQUEST_ROAMING_SEARCH; + } + } + + if (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR && + prAisFsmInfo->fgIsInfraChannelFinished == true) { + if (eAisRequest == AIS_REQUEST_ROAMING_SEARCH) { + aisFsmSteps(prAdapter, AIS_STATE_LOOKING_FOR); + } else { + aisFsmSteps(prAdapter, AIS_STATE_SEARCH); + } + } else { + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_SEARCH, true); + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_ROAMING_CONNECT, + true); + + aisFsmInsertRequest(prAdapter, eAisRequest); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Update the time of ScanDone for roaming and transit to Roam state. + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +ENUM_AIS_STATE_T aisFsmRoamingScanResultsUpdate(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_AIS_STATE_T eNextState; + + DBGLOG(AIS, LOUD, "->aisFsmRoamingScanResultsUpdate()\n"); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prRoamingFsmInfo = + (P_ROAMING_INFO_T)&(prAdapter->rWifiVar.rRoamingInfo); + + roamingFsmScanResultsUpdate(prAdapter); + + eNextState = prAisFsmInfo->eCurrentState; + if (prRoamingFsmInfo->eCurrentState == ROAMING_STATE_DISCOVERY) { + roamingFsmRunEventRoam(prAdapter); + eNextState = AIS_STATE_SEARCH; + } else if (prAisFsmInfo->eCurrentState == AIS_STATE_LOOKING_FOR) { + eNextState = AIS_STATE_SEARCH; + } else if (prAisFsmInfo->eCurrentState == AIS_STATE_ONLINE_SCAN) { + eNextState = AIS_STATE_NORMAL_TR; + } + + return eNextState; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will modify and update necessary information to firmware + * for disconnection of last AP before switching to roaming bss. + * + * @param IN prAdapter Pointer to the Adapter structure. + * prTargetStaRec Target of StaRec of roaming + * + * @retval None + */ +/*----------------------------------------------------------------------------*/ +void aisFsmRoamingDisconnectPrevAP(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prTargetStaRec) +{ + P_BSS_INFO_T prAisBssInfo; + + DBGLOG(AIS, EVENT, "aisFsmRoamingDisconnectPrevAP()"); + + ASSERT(prAdapter); + + prAisBssInfo = prAdapter->prAisBssInfo; + + nicPmIndicateBssAbort(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + /* Not invoke rlmBssAborted() here to avoid prAisBssInfo->fg40mBwAllowed + * to be reset. RLM related parameters will be reset again when handling + * association response in rlmProcessAssocRsp(). 20110413 + */ + /* rlmBssAborted(prAdapter, prAisBssInfo); */ + + /* 4 <3> Unset the fgIsConnected flag of BSS_DESC_T and send Deauth if + * needed. */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + authSendDeauthFrame(prAdapter, prAisBssInfo, + prAisBssInfo->prStaRecOfAP, + (P_SW_RFB_T)NULL, + REASON_CODE_DEAUTH_LEAVING_BSS, + (PFN_TX_DONE_HANDLER)NULL); + + scanRemoveConnFlagOfBssDescByBssid(prAdapter, + prAisBssInfo->aucBSSID); + } + + /* 4 <4> Change Media State immediately. */ + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_DISCONNECTED); + + /* 4 <4.1> sync. with firmware */ + prTargetStaRec->ucBssIndex = (MAX_BSS_INDEX + 1); /* Virtial BSSID */ + nicUpdateBss(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + secRemoveBssBcEntry(prAdapter, prAisBssInfo, true); + prTargetStaRec->ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex; +} +#endif + +#if CFG_SUPPORT_ROAMING || CFG_SUPPORT_SAME_BSS_REASSOC +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will update the contain of BSS_INFO_T for AIS network + * once the roaming was completed. + * + * @param IN prAdapter Pointer to the Adapter structure. + * prStaRec StaRec of roaming AP + * prAssocRspSwRfb + * + * @retval None + */ +/*----------------------------------------------------------------------------*/ +void aisUpdateBssInfoForRoamingAP(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prAssocRspSwRfb) +{ + P_BSS_INFO_T prAisBssInfo; + + DBGLOG(AIS, LOUD, "aisUpdateBssInfoForRoamingAP()"); + + ASSERT(prAdapter); + + prAisBssInfo = prAdapter->prAisBssInfo; + + /* 4 <1.1> Change FW's Media State immediately. */ + aisChangeMediaState(prAdapter, PARAM_MEDIA_STATE_CONNECTED); + + /* 4 <1.2> Deactivate previous AP's STA_RECORD_T in Driver if have. */ + if ((prAisBssInfo->prStaRecOfAP) && + (prAisBssInfo->prStaRecOfAP != prStaRec) && + (prAisBssInfo->prStaRecOfAP->fgIsInUse)) { + /* cnmStaRecChangeState(prAdapter, prAisBssInfo->prStaRecOfAP, + * STA_STATE_1); */ + cnmStaRecFree(prAdapter, prAisBssInfo->prStaRecOfAP); + } + + /* 4 <1.4> Update BSS_INFO_T */ + aisUpdateBssInfoForJOIN(prAdapter, prStaRec, prAssocRspSwRfb); + + /* 4 <1.3> Activate current AP's STA_RECORD_T in Driver. */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + + /* 4 <1.6> Indicate Connected Event to Host immediately. */ + /* Require BSSID, Association ID, Beacon Interval.. from AIS_BSS_INFO_T + */ + aisIndicationOfMediaStateToHost(prAdapter, PARAM_MEDIA_STATE_CONNECTED, + false); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Check if there is any pending request and remove it (optional) + * + * @param prAdapter + * eReqType + * bRemove + * + * @return true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 aisFsmIsRequestPending(IN P_ADAPTER_T prAdapter, + IN ENUM_AIS_REQUEST_TYPE_T eReqType, + IN u8 bRemove) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_AIS_REQ_HDR_T prPendingReqHdr, prPendingReqHdrNext; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + /* traverse through pending request list */ + LINK_FOR_EACH_ENTRY_SAFE(prPendingReqHdr, prPendingReqHdrNext, + &(prAisFsmInfo->rPendingReqList), rLinkEntry, + AIS_REQ_HDR_T){ + /* check for specified type */ + if (prPendingReqHdr->eReqType == eReqType) { + /* check if need to remove */ + if (bRemove == true) { + LINK_REMOVE_KNOWN_ENTRY(&(prAisFsmInfo->rPendingReqList), + &(prPendingReqHdr->rLinkEntry)); + + cnmMemFree(prAdapter, prPendingReqHdr); + } + + return true; + } + } + + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Get next pending request + * + * @param prAdapter + * + * @return P_AIS_REQ_HDR_T + */ +/*----------------------------------------------------------------------------*/ +P_AIS_REQ_HDR_T aisFsmGetNextRequest(IN P_ADAPTER_T prAdapter) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_AIS_REQ_HDR_T prPendingReqHdr; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + LINK_REMOVE_HEAD(&(prAisFsmInfo->rPendingReqList), prPendingReqHdr, + P_AIS_REQ_HDR_T); + + return prPendingReqHdr; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Insert a new request + * + * @param prAdapter + * eReqType + * + * @return true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 aisFsmInsertRequest(IN P_ADAPTER_T prAdapter, + IN ENUM_AIS_REQUEST_TYPE_T eReqType) +{ + P_AIS_REQ_HDR_T prAisReq; + P_AIS_FSM_INFO_T prAisFsmInfo; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + prAisReq = (P_AIS_REQ_HDR_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(AIS_REQ_HDR_T)); + + if (!prAisReq) { + ASSERT(0); /* Can't generate new message */ + return false; + } + + prAisReq->eReqType = eReqType; + + /* attach request into pending request list */ + LINK_INSERT_TAIL(&prAisFsmInfo->rPendingReqList, &prAisReq->rLinkEntry); + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Flush all pending requests + * + * @param prAdapter + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void aisFsmFlushRequest(IN P_ADAPTER_T prAdapter) +{ + P_AIS_REQ_HDR_T prAisReq; + + ASSERT(prAdapter); + + while ((prAisReq = aisFsmGetNextRequest(prAdapter)) != NULL) + cnmMemFree(prAdapter, prAisReq); +} + +void aisFsmRunEventRemainOnChannel(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_REMAIN_ON_CHANNEL_T prRemainOnChannel; + P_AIS_FSM_INFO_T prAisFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + + DEBUGFUNC("aisFsmRunEventRemainOnChannel()"); + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + prRemainOnChannel = (P_MSG_REMAIN_ON_CHANNEL_T)prMsgHdr; + + /* record parameters */ + prAisFsmInfo->rChReqInfo.eBand = prRemainOnChannel->eBand; + prAisFsmInfo->rChReqInfo.eSco = prRemainOnChannel->eSco; + prAisFsmInfo->rChReqInfo.ucChannelNum = prRemainOnChannel->ucChannelNum; + prAisFsmInfo->rChReqInfo.u4DurationMs = prRemainOnChannel->u4DurationMs; + prAisFsmInfo->rChReqInfo.u8Cookie = prRemainOnChannel->u8Cookie; + + if (prAisFsmInfo->eCurrentState == AIS_STATE_IDLE || + (prAisFsmInfo->eCurrentState == AIS_STATE_NORMAL_TR && + prAisFsmInfo->fgIsInfraChannelFinished == true)) { + /* transit to next state */ + aisFsmSteps(prAdapter, AIS_STATE_REQ_REMAIN_ON_CHANNEL); + } else { + aisFsmInsertRequest(prAdapter, AIS_REQUEST_REMAIN_ON_CHANNEL); + } + + /* free messages */ + cnmMemFree(prAdapter, prMsgHdr); +} + +void aisFsmRunEventCancelRemainOnChannel(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + P_MSG_CANCEL_REMAIN_ON_CHANNEL_T prCancelRemainOnChannel; + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = prAdapter->prAisBssInfo; + + prCancelRemainOnChannel = (P_MSG_CANCEL_REMAIN_ON_CHANNEL_T)prMsgHdr; + + /* 1. Check the cookie first */ + if (prCancelRemainOnChannel->u8Cookie == + prAisFsmInfo->rChReqInfo.u8Cookie) { + /* 2. release channel privilege/request */ + if (prAisFsmInfo->eCurrentState == + AIS_STATE_REQ_REMAIN_ON_CHANNEL) { + /* 2.1 elease channel */ + aisFsmReleaseCh(prAdapter); + } else if (prAisFsmInfo->eCurrentState == + AIS_STATE_REMAIN_ON_CHANNEL) { + /* 2.1 release channel */ + aisFsmReleaseCh(prAdapter); + + /* 2.2 stop channel timeout timer */ + cnmTimerStopTimer(prAdapter, + &prAisFsmInfo->rChannelTimeoutTimer); + } + + /* 3. clear pending request of remain_on_channel */ + aisFsmIsRequestPending(prAdapter, AIS_REQUEST_REMAIN_ON_CHANNEL, + true); + + /* 4. decide which state to retreat */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + aisFsmSteps(prAdapter, AIS_STATE_NORMAL_TR); + } else { + aisFsmSteps(prAdapter, AIS_STATE_IDLE); + } + } + + /* 5. free message */ + cnmMemFree(prAdapter, prMsgHdr); +} + +void aisFsmRunEventMgmtFrameTx(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_MSG_MGMT_TX_REQUEST_T prMgmtTxMsg = (P_MSG_MGMT_TX_REQUEST_T)NULL; + + do { + ASSERT((prAdapter != NULL) && (prMsgHdr != NULL)); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + + if (prAisFsmInfo == NULL) { + break; + } + + prMgmtTxMsg = (P_MSG_MGMT_TX_REQUEST_T)prMsgHdr; + + aisFuncTxMgmtFrame(prAdapter, &prAisFsmInfo->rMgmtTxInfo, + prMgmtTxMsg->prMgmtMsduInfo, + prMgmtTxMsg->u8Cookie); + } while (false); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } +} + +void aisFsmRunEventChannelTimeout(IN P_ADAPTER_T prAdapter, + unsigned long ulParamPtr) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_BSS_INFO_T prAisBssInfo; + + DEBUGFUNC("aisFsmRunEventRemainOnChannel()"); + + ASSERT(prAdapter); + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prAisBssInfo = prAdapter->prAisBssInfo; + + if (prAisFsmInfo->eCurrentState == AIS_STATE_REMAIN_ON_CHANNEL) { + /* 1. release channel */ + aisFsmReleaseCh(prAdapter); + + /* 2. stop channel timeout timer */ + cnmTimerStopTimer(prAdapter, &prAisFsmInfo->rChannelTimeoutTimer); + + /* 3. expiration indication to upper layer */ + kalRemainOnChannelExpired(prAdapter->prGlueInfo, + prAisFsmInfo->rChReqInfo.u8Cookie, + prAisFsmInfo->rChReqInfo.eBand, + prAisFsmInfo->rChReqInfo.eSco, + prAisFsmInfo->rChReqInfo.ucChannelNum); + + /* 4. decide which state to retreat */ + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + aisFsmSteps(prAdapter, AIS_STATE_NORMAL_TR); + } else { + aisFsmSteps(prAdapter, AIS_STATE_IDLE); + } + } else { + DBGLOG(AIS, WARN, "Unexpected remain_on_channel timeout event\n"); + DBGLOG(AIS, STATE, "CURRENT State: [%s]\n", + apucDebugAisState[prAisFsmInfo->eCurrentState]); + } +} + +WLAN_STATUS +aisFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_AIS_FSM_INFO_T prAisFsmInfo; + P_AIS_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo = + (P_AIS_MGMT_TX_REQ_INFO_T)NULL; + u8 fgIsSuccess = false; + + do { + ASSERT((prAdapter != NULL) && (prMsduInfo != NULL)); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + prMgmtTxReqInfo = &(prAisFsmInfo->rMgmtTxInfo); + + if (rTxDoneStatus == TX_RESULT_SUCCESS) { + fgIsSuccess = true; + } + + if (prMgmtTxReqInfo->prMgmtTxMsdu == prMsduInfo) { + kalIndicateMgmtTxStatus(prAdapter->prGlueInfo, + prMgmtTxReqInfo->u8Cookie, fgIsSuccess, + prMsduInfo->prPacket, + (u32)prMsduInfo->u2FrameLength); + + prMgmtTxReqInfo->prMgmtTxMsdu = NULL; + } + } while (false); + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS +aisFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, + IN P_AIS_MGMT_TX_REQ_INFO_T prMgmtTxReqInfo, + IN P_MSDU_INFO_T prMgmtTxMsdu, IN u64 u8Cookie) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_MSDU_INFO_T prTxMsduInfo = (P_MSDU_INFO_T)NULL; + P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + do { + ASSERT((prAdapter != NULL) && (prMgmtTxReqInfo != NULL)); + + if (prMgmtTxReqInfo->fgIsMgmtTxRequested) { + /* 1. prMgmtTxReqInfo->prMgmtTxMsdu != NULL */ + /* Packet on driver, not done yet, drop it. */ + prTxMsduInfo = prMgmtTxReqInfo->prMgmtTxMsdu; + if (prTxMsduInfo != NULL) { + kalIndicateMgmtTxStatus(prAdapter->prGlueInfo, + prMgmtTxReqInfo->u8Cookie, false, + prTxMsduInfo->prPacket, + (u32)prTxMsduInfo->u2FrameLength); + + /* Leave it to TX Done handler. */ + /* cnmMgtPktFree(prAdapter, prTxMsduInfo); */ + prMgmtTxReqInfo->prMgmtTxMsdu = NULL; + } + /* 2. prMgmtTxReqInfo->prMgmtTxMsdu == NULL */ + /* Packet transmitted, wait tx done. (cookie issue) */ + } + + ASSERT(prMgmtTxReqInfo->prMgmtTxMsdu == NULL); + + prWlanHdr = + (P_WLAN_MAC_HEADER_T)((unsigned long)prMgmtTxMsdu->prPacket + + MAC_TX_RESERVED_FIELD); + prStaRec = cnmGetStaRecByAddress(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex, + prWlanHdr->aucAddr1); + + TX_SET_MMPDU(prAdapter, prMgmtTxMsdu, + (prStaRec != NULL) ? (prStaRec->ucBssIndex) : + (prAdapter->prAisBssInfo->ucBssIndex), + (prStaRec != NULL) ? (prStaRec->ucIndex) : + (STA_REC_INDEX_NOT_FOUND), + WLAN_MAC_MGMT_HEADER_LEN, prMgmtTxMsdu->u2FrameLength, + aisFsmRunEventMgmtFrameTxDone, MSDU_RATE_MODE_AUTO); + + if ((prWlanHdr->u2FrameCtrl & MASK_FRAME_TYPE) == + MAC_FRAME_PROBE_RSP) { + nicTxSetPktLifeTime(prMgmtTxMsdu, 100); + nicTxSetPktRetryLimit(prMgmtTxMsdu, 3); + } + + prMgmtTxReqInfo->u8Cookie = u8Cookie; + prMgmtTxReqInfo->prMgmtTxMsdu = prMgmtTxMsdu; + prMgmtTxReqInfo->fgIsMgmtTxRequested = true; + + nicTxConfigPktControlFlag(prMgmtTxMsdu, MSDU_CONTROL_FLAG_FORCE_TX, + true); + + /* send to TX queue */ + nicTxEnqueueMsdu(prAdapter, prMgmtTxMsdu); + } while (false); + + return rWlanStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will validate the Rx Action Frame and indicate to uppoer + * layer if the specified conditions were matched. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prSwRfb Pointer to SW RFB data structure. + * @param[out] pu4ControlFlags Control flags for replying the Probe Response + * + * @retval none + */ +/*----------------------------------------------------------------------------*/ +void aisFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb) +{ + P_AIS_FSM_INFO_T prAisFsmInfo = (P_AIS_FSM_INFO_T)NULL; + + DEBUGFUNC("aisFuncValidateRxActionFrame"); + + do { + ASSERT((prAdapter != NULL) && (prSwRfb != NULL)); + + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); + if (prAisFsmInfo->u4AisPacketFilter & + PARAM_PACKET_FILTER_ACTION_FRAME) { + /* Leave the action frame to wpa_supplicant. */ + kalIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); + } + } while (false); + + return; +} + +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT +void aisFsmRunEventBssTransition(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_AIS_BSS_TRANSITION_T prMsg = (P_MSG_AIS_BSS_TRANSITION_T)prMsgHdr; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo = + &prAdapter->rWifiVar.rAisSpecificBssInfo; + P_BSS_TRANSITION_MGT_PARAM_T prBtmParam = + &prAisSpecificBssInfo->rBTMParam; + enum WNM_AIS_BSS_TRANSITION eTransType = BSS_TRANSITION_MAX_NUM; + P_BSS_DESC_T prBssDesc = + prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc; + u8 fgNeedBtmResponse = false; + u8 ucStatus = BSS_TRANSITION_MGT_STATUS_UNSPECIFIED; + u8 ucRcvToken = 0; + static u8 aucChnlList[MAXIMUM_OPERATION_CHANNEL_LIST]; + + if (!prMsg) { + DBGLOG(AIS, WARN, "Msg Header is NULL\n"); + return; + } + eTransType = prMsg->eTransitionType; + fgNeedBtmResponse = prMsg->fgNeedResponse; + ucRcvToken = prMsg->ucToken; + + DBGLOG(AIS, INFO, "Transition Type: %d\n", eTransType); + aisCollectNeighborAP(prAdapter, prMsg->pucCandList, + prMsg->u2CandListLen, + prMsg->ucValidityInterval); + cnmMemFree(prAdapter, prMsgHdr); + /* Solicited BTM request: the case we're waiting btm request + ** after send btm query before roaming scan + */ + if (prBtmParam->ucDialogToken == ucRcvToken) { + prBtmParam->fgPendingResponse = fgNeedBtmResponse; + prBtmParam->fgUnsolicitedReq = false; + + switch (prAdapter->rWifiVar.rRoamingInfo.eCurrentState) { + case ROAMING_STATE_REQ_CAND_LIST: + roamingFsmSteps(prAdapter, ROAMING_STATE_DISCOVERY); + return; + case ROAMING_STATE_DISCOVERY: + /* this case need to fall through */ + case ROAMING_STATE_ROAM: + ucStatus = BSS_TRANSITION_MGT_STATUS_UNSPECIFIED; + goto send_response; + default: + /* not solicited btm request, but dialog token matches + ** occasionally. + */ + break; + } + } + prBtmParam->fgUnsolicitedReq = true; + /* Unsolicited BTM request */ + switch (eTransType) { + case BSS_TRANSITION_DISASSOC: + ucStatus = BSS_TRANSITION_MGT_STATUS_ACCEPT; + break; + case BSS_TRANSITION_REQ_ROAMING: { + P_NEIGHBOR_AP_T prNeiAP = NULL; + P_LINK_T prUsingLink = + &prAisSpecificBssInfo->rNeighborApList.rUsingLink; + u8 i = 0; + u8 ucChannel = 0; + u8 ucChnlCnt = 0; + u16 u2LeftTime = 0; + + if (!prBssDesc) { + DBGLOG(AIS, ERROR, "Target Bss Desc is NULL\n"); + break; + } + prBtmParam->fgPendingResponse = fgNeedBtmResponse; + kalMemZero(aucChnlList, sizeof(aucChnlList)); + LINK_FOR_EACH_ENTRY(prNeiAP, prUsingLink, rLinkEntry, + NEIGHBOR_AP_T){ + ucChannel = prNeiAP->ucChannel; + for (i = 0; i < ucChnlCnt && ucChannel != aucChnlList[i]; i++) + ; + if (i == ucChnlCnt) { + ucChnlCnt++; + } + } + /* reserve 1 second for association */ + u2LeftTime = + prBtmParam->u2DisassocTimer * prBssDesc->u2BeaconInterval - + 1000; + /* check if left time is enough to do partial scan, if not + ** enought, reject directly + */ + if (u2LeftTime < ucChnlCnt * prBssDesc->u2BeaconInterval) { + ucStatus = BSS_TRANSITION_MGT_STATUS_UNSPECIFIED; + goto send_response; + } + roamingFsmSteps(prAdapter, ROAMING_STATE_DISCOVERY); + return; + } + default: + ucStatus = BSS_TRANSITION_MGT_STATUS_ACCEPT; + break; + } +send_response: + if (fgNeedBtmResponse && prAdapter->prAisBssInfo && + prAdapter->prAisBssInfo->prStaRecOfAP) { + prBtmParam->ucStatusCode = ucStatus; + prBtmParam->ucTermDelay = 0; + kalMemZero(prBtmParam->aucTargetBssid, MAC_ADDR_LEN); + prBtmParam->u2OurNeighborBssLen = 0; + prBtmParam->fgPendingResponse = false; + wnmSendBTMResponseFrame(prAdapter, + prAdapter->prAisBssInfo->prStaRecOfAP); + } +} +#endif + +#if CFG_SUPPORT_802_11K +void aisSendNeighborRequest(IN P_ADAPTER_T prAdapter) +{ + struct SUB_ELEMENT_LIST *prSSIDIE; + u8 aucBuffer[sizeof(*prSSIDIE) + 31]; + P_BSS_INFO_T prBssInfo = prAdapter->prAisBssInfo; + + kalMemZero(aucBuffer, sizeof(aucBuffer)); + prSSIDIE = (struct SUB_ELEMENT_LIST *)&aucBuffer[0]; + prSSIDIE->rSubIE.ucSubID = ELEM_ID_SSID; + COPY_SSID(&prSSIDIE->rSubIE.aucOptInfo[0], prSSIDIE->rSubIE.ucLength, + prBssInfo->aucSSID, prBssInfo->ucSSIDLen); + rlmTxNeighborReportRequest(prAdapter, prBssInfo->prStaRecOfAP, + prSSIDIE); +} +#endif + +#if CFG_SUPPORT_802_11K || CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT +static u8 aisCandPrefIEIsExist(u8 *pucSubIe, u8 ucLength) +{ + u16 u2Offset = 0; + + IE_FOR_EACH(pucSubIe, ucLength, u2Offset){ + if (IE_ID(pucSubIe) == ELEM_ID_NR_BSS_TRANSITION_CAND_PREF) { + return true; + } + } + return false; +} + +static u8 aisGetNeighborApPreference(u8 *pucSubIe, u8 ucLength) +{ + u16 u2Offset = 0; + + IE_FOR_EACH(pucSubIe, ucLength, u2Offset){ + if (IE_ID(pucSubIe) == ELEM_ID_NR_BSS_TRANSITION_CAND_PREF) { + return pucSubIe[2]; + } + } + /* If no preference element is presence, give default value(lowest) 0, + */ + /* but it will not be used as a reference. */ + return 0; +} + +static u64 aisGetBssTermTsf(u8 *pucSubIe, u8 ucLength) +{ + u16 u2Offset = 0; + + IE_FOR_EACH(pucSubIe, ucLength, u2Offset){ + if (IE_ID(pucSubIe) == ELEM_ID_NR_BSS_TERMINATION_DURATION) { + return *(u64 *)&pucSubIe[2]; + } + } + /* If no preference element is presence, give default value(lowest) 0 */ + return 0; +} + +void aisCollectNeighborAP(IN P_ADAPTER_T prAdapter, u8 *pucApBuf, + u16 u2ApBufLen, u8 ucValidInterval) +{ + P_NEIGHBOR_AP_T prNeighborAP = NULL; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo = + &prAdapter->rWifiVar.rAisSpecificBssInfo; + P_LINK_MGMT_T prAPlist = &prAisSpecBssInfo->rNeighborApList; + P_IE_NEIGHBOR_REPORT_T prIe = (P_IE_NEIGHBOR_REPORT_T)pucApBuf; + u16 u2BufLen; + u16 u2PrefIsZeroCount = 0; + + if (!prIe || !u2ApBufLen || u2ApBufLen < prIe->ucLength) { + return; + } + + LINK_MERGE_TO_TAIL(&prAPlist->rFreeLink, &prAPlist->rUsingLink); + for (u2BufLen = u2ApBufLen; u2BufLen > 0; u2BufLen -= IE_SIZE(prIe), + prIe = (P_IE_NEIGHBOR_REPORT_T)((u8 *)prIe + IE_SIZE(prIe))) { + /* BIT0-1: AP reachable, BIT2: same security with current + ** setting, + ** BIT3: same authenticator with current AP + */ + if (prIe->ucId != ELEM_ID_NEIGHBOR_REPORT || + (prIe->u4BSSIDInfo & 0x7) != 0x7) { + continue; + } + + LINK_MGMT_GET_ENTRY(prAPlist, prNeighborAP, NEIGHBOR_AP_T, + VIR_MEM_TYPE); + if (!prNeighborAP) { + break; + } + prNeighborAP->fgHT = !!(prIe->u4BSSIDInfo & BIT(11)); + prNeighborAP->fgFromBtm = !!ucValidInterval; + prNeighborAP->fgRmEnabled = !!(prIe->u4BSSIDInfo & BIT(7)); + prNeighborAP->fgQoS = !!(prIe->u4BSSIDInfo & BIT(5)); + prNeighborAP->fgSameMD = !!(prIe->u4BSSIDInfo & BIT(10)); + prNeighborAP->ucChannel = prIe->ucChnlNumber; + prNeighborAP->fgPrefPresence = aisCandPrefIEIsExist( + prIe->aucSubElem, + IE_SIZE(prIe) - OFFSET_OF(IE_NEIGHBOR_REPORT_T, aucSubElem)); + prNeighborAP->ucPreference = aisGetNeighborApPreference( + prIe->aucSubElem, + IE_SIZE(prIe) - OFFSET_OF(IE_NEIGHBOR_REPORT_T, aucSubElem)); + prNeighborAP->u8TermTsf = aisGetBssTermTsf( + prIe->aucSubElem, + IE_SIZE(prIe) - OFFSET_OF(IE_NEIGHBOR_REPORT_T, aucSubElem)); + COPY_MAC_ADDR(prNeighborAP->aucBssid, prIe->aucBSSID); + DBGLOG(AIS, INFO, + "Bssid" MACSTR + ", PrefPresence %d, Pref %d, Chnl %d, BssidInfo 0x%08x\n", + MAC2STR( + prNeighborAP->aucBssid), prNeighborAP->fgPrefPresence, + prNeighborAP->ucPreference, prIe->ucChnlNumber, + prIe->u4BSSIDInfo); + /* No need to save neighbor ap list with decendant preference + ** for (prTemp = LINK_ENTRY(prAPlist->rUsingLink.prNext, struct + ** NEIGHBOR_AP_T, rLinkEntry); + ** prTemp != prNeighborAP; + ** prTemp = LINK_ENTRY(prTemp->rLinkEntry.prNext, struct + ** NEIGHBOR_AP_T, rLinkEntry)) { + ** if (prTemp->ucPreference < prNeighborAP->ucPreference) { + ** __linkDel(prNeighborAP->rLinkEntry.prPrev, + ** prNeighborAP->rLinkEntry.prNext); + ** __linkAdd(&prNeighborAP->rLinkEntry, + ** prTemp->rLinkEntry.prPrev, &prTemp->rLinkEntry); + ** break; + ** } + ** } + */ + if (prNeighborAP->fgPrefPresence && + prNeighborAP->ucPreference == 0) { + u2PrefIsZeroCount++; + } + } + prAisSpecBssInfo->rNeiApRcvTime = kalGetTimeTick(); + prAisSpecBssInfo->u4NeiApValidInterval = + !ucValidInterval ? + 0xffffffff : + TU_TO_MSEC(ucValidInterval * + prAdapter->prAisBssInfo->u2BeaconInterval); + + if (prAPlist->rUsingLink.u4NumElem > 0 && + prAPlist->rUsingLink.u4NumElem == u2PrefIsZeroCount) { + DBGLOG( + AIS, INFO, + "The number of valid neighbors is equal to the number of perf value " + "is 0.\n"); + } +} +#endif + +#if CFG_SUPPORT_802_11K || CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT +void aisResetNeighborApList(IN P_ADAPTER_T prAdapter) +{ + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo = + &prAdapter->rWifiVar.rAisSpecificBssInfo; + P_LINK_MGMT_T prAPlist = &prAisSpecBssInfo->rNeighborApList; + + LINK_MERGE_TO_TAIL(&prAPlist->rFreeLink, &prAPlist->rUsingLink); +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/assoc.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/assoc.c new file mode 100644 index 00000000000000..b31acea5234e43 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/assoc.c @@ -0,0 +1,1842 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "assoc.c" + * \brief This file includes the association-related functions. + * + * This file includes the association-related functions. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +APPEND_VAR_IE_ENTRY_T txAssocReqIETable[] = { +#if CFG_SUPPORT_SPEC_MGMT + { (ELEM_HDR_LEN + ELEM_MAX_LEN_POWER_CAP), NULL, + rlmReqGeneratePowerCapIE }, /* 33 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_SUPPORTED_CHANNELS), NULL, + rlmReqGenerateSupportedChIE }, /* 36 */ +#endif + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, + rlmReqGenerateHtCapIE }, /* 45 */ +#if CFG_SUPPORT_802_11K + { (ELEM_HDR_LEN + 5), NULL, rlmReqGenerateRRMEnabledCapIE }, /* 70 */ +#endif +#if CFG_SUPPORT_WPS2 + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WSC), NULL, rsnGenerateWSCIE }, /* 221 */ +#endif + { (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, + rlmReqGenerateExtCapIE }, /* 127 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_INFO), NULL, + mqmGenerateWmmInfoIE }, /* 221 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE }, /* 48 */ +#if CFG_SUPPORT_802_11AC + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_CAP), NULL, + rlmReqGenerateVhtCapIE }, /*191 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_OP_MODE_NOTIFICATION), NULL, + rlmReqGenerateVhtOpNotificationIE }, /*199 */ +#endif +#if CFG_SUPPORT_MTK_SYNERGY + { (ELEM_HDR_LEN + ELEM_MIN_LEN_MTK_OUI), NULL, + rlmGenerateMTKOuiIE }, /* 221 */ +#endif + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWPAIE }, +#if CFG_SUPPORT_H2E + { 0, rsnCalRSNXELen, rsnGenerateRSNXE } +#endif +}; + +#if CFG_SUPPORT_AAA +VERIFY_IE_ENTRY_T rxAssocReqIETable[] = { { ELEM_ID_RESERVED, NULL } }; + +APPEND_VAR_IE_ENTRY_T txAssocRespIETable[] = { + { (ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE }, /* 42 + */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, + rlmRspGenerateHtCapIE }, /* 45 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, + rlmRspGenerateHtOpIE }, /* 61 */ +#if CFG_ENABLE_WIFI_DIRECT + { (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, + rlmRspGenerateObssScanIE }, /* 74 */ + { (0), p2pFuncCalculateP2p_IELenForAssocRsp, + p2pFuncGenerateP2p_IEForAssocRsp }, /* 221 */ +#if (CFG_SUPPORT_WFD) + { (0), wfdFuncCalculateWfdIELenForAssocRsp, + wfdFuncGenerateWfdIEForAssocRsp }, /* 221 */ +#endif +#endif + { (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, + rlmRspGenerateExtCapIE }, /* 127 */ +#if CFG_SUPPORT_802_11AC + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_CAP), NULL, + rlmRspGenerateVhtCapIE }, /*191 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_OP), NULL, + rlmRspGenerateVhtOpIE }, /*192 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_OP_MODE_NOTIFICATION), NULL, + rlmRspGenerateVhtOpNotificationIE }, /*199 */ +#endif + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, + mqmGenerateWmmParamIE }, /* 221 */ + { (ELEM_HDR_LEN + ELEM_MAX_LEN_ASSOC_RSP_WSC_IE), NULL, + rsnGenerateWSCIEForAssocRsp }, /* 221 */ +#if CFG_SUPPORT_MTK_SYNERGY + { (ELEM_HDR_LEN + ELEM_MIN_LEN_MTK_OUI), NULL, rlmGenerateMTKOuiIE }, +#endif +#if CFG_SUPPORT_802_11W + { (ELEM_HDR_LEN + ELEM_MAX_LEN_TIMEOUT_IE), NULL, rsnPmfGenerateTimeoutIE } +#endif +}; +#endif + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to compose the Capability Info Field. + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @retval Capability Info Field + */ +/*----------------------------------------------------------------------------*/ + +u16 assocBuildCapabilityInfo(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec) +{ + u32 u4NonHTPhyType; + u16 u2CapInfo; + P_BSS_INFO_T prBssInfo; + + ASSERT(prStaRec); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + /* Set up our requested capabilities. */ + u2CapInfo = CAP_INFO_ESS; + u2CapInfo |= CAP_CF_STA_NOT_POLLABLE; +#if CFG_SUPPORT_802_11K + u2CapInfo |= CAP_INFO_RADIO_MEASUREMENT; +#endif + if (prStaRec->u2CapInfo & CAP_INFO_PRIVACY) { + u2CapInfo |= CAP_INFO_PRIVACY; + } + + /* 7.3.1.4 */ + if (prStaRec->fgHasBasicPhyType) { + u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; + + if ((rNonHTPhyAttributes[u4NonHTPhyType] + .fgIsShortPreambleOptionImplemented) && + /* Short Preamble Option Enable is true */ + ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || + ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO) && + (prStaRec->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)))) { + /* Case I: Implemented == true and Short Preamble Option + * Enable == true. Case II: Implemented == true and + * Short Preamble == AUTO (depends on BSS_DESC_T's + * capability) + */ + u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; + } + +#if CFG_SUPPORT_SPEC_MGMT + /* 802.11h spectrum management is for 5G band, so + * now we only enable spectrum management bit for 5G case. + * In TGn 5.2.22, spectrum management bit should set to 1 + * to pass the UCC's check. + */ + if (prBssInfo && prBssInfo->eBand == BAND_5G) { + u2CapInfo |= CAP_INFO_SPEC_MGT; + } +#endif + + if (rNonHTPhyAttributes[u4NonHTPhyType] + .fgIsShortSlotTimeOptionImplemented && + prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable) { + u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; + } + } + + DBGLOG(SAA, LOUD, + "ASSOC REQ: Compose Capability = 0x%04x for Target BSS [" MACSTR + "].\n", + u2CapInfo, MAC2STR(prStaRec->aucMacAddr)); + + return u2CapInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to compose Common Information Elements for + * Association Request Frame. + * + * @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void +assocBuildReAssocReqFrameCommonIEs(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_STA_RECORD_T prStaRec; + u8 *pucBuffer; + u16 u2SupportedRateSet; + u8 aucAllSupportedRates[RATE_NUM_SW] = { 0 }; + u8 ucAllSupportedRatesLen; + u8 ucSupRatesLen; + u8 ucExtSupRatesLen; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + ASSERT(prMsduInfo); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if (!prStaRec) { + return; + } + + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + ASSERT(pucBuffer); + + if (IS_STA_IN_AIS(prStaRec)) { + /* Fill the SSID element. */ + SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; + + /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for + * the case of Passive Scan and the target BSS didn't broadcast + * SSID on its Beacon Frame. + */ + + COPY_SSID(SSID_IE(pucBuffer)->aucSSID, SSID_IE(pucBuffer)->ucLength, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } +#if CFG_ENABLE_WIFI_DIRECT + else if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { + pucBuffer = + p2pBuildReAssocReqFrameCommonIEs(prAdapter, prMsduInfo, pucBuffer); + } +#endif + + /* NOTE(Kevin 2008/12/19): 16.3.6.3 MLME-ASSOCIATE.indication - + * SupportedRates - The set of data rates that are supported by the STA + * that is requesting association. + * Original(Portable Driver): Only send the Rates that we'll support. + * New: Send the Phy Rates if the result of following & operation == + * NULL. + */ + /* rateGetDataRatesFromRateSet((prBssDesc->u2OperationalRateSet & */ + /* rPhyAttributes[prBssDesc->ePhyType].u2SupportedRateSet), */ + + if (prStaRec->fgHasBasicPhyType) { + u32 u4NonHTPhyType; + + u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; + + u2SupportedRateSet = + (prStaRec->u2OperationalRateSet & + rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet); + + ASSERT(u2SupportedRateSet); + + if (!u2SupportedRateSet) { + u2SupportedRateSet = + rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet; + } + + /* TODO(Kevin): For P2P, we shouldn't send support rate set + * which contains 11b rate */ + + rateGetDataRatesFromRateSet(u2SupportedRateSet, 0, aucAllSupportedRates, + &ucAllSupportedRatesLen); + + ucSupRatesLen = ((ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) ? + ELEM_MAX_LEN_SUP_RATES : + ucAllSupportedRatesLen); + + ucExtSupRatesLen = ucAllSupportedRatesLen - ucSupRatesLen; + + /* Fill the Supported Rates element. */ + if (ucSupRatesLen) { + SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; + SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; + kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, + aucAllSupportedRates, ucSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + + /* Fill the Extended Supported Rates element. */ + if (ucExtSupRatesLen) { + EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; + EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; + + kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, + &aucAllSupportedRates[ucSupRatesLen], ucExtSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will compose the (Re)Association Request frame header + * and its fixed fields + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] pucBuffer Pointer to the frame buffer. + * @param[in] aucMACAddress Given Our MAC Address. + * @param[in out] pu2PayloadLen Return the length of the composed fixed + * fields + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void assocComposeReAssocReqFrameHeaderAndFF(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN u8 *pucBuffer, + IN u8 aucMACAddress[], + IN OUT u16 *pu2PayloadLen) +{ + P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; + u8 fgIsReAssoc; + + u16 u2FrameCtrl; + u16 u2CapInfo; + u16 u2ListenInterval; + + ASSERT(prStaRec); + ASSERT(pucBuffer); + ASSERT(aucMACAddress); + ASSERT(pu2PayloadLen); + + prAssocFrame = (P_WLAN_ASSOC_REQ_FRAME_T)pucBuffer; + fgIsReAssoc = prStaRec->fgIsReAssoc; + + /* 4 <1> Compose the frame header of the (Re)Association Request frame. + */ + /* Fill the Frame Control field. */ + if (fgIsReAssoc) { + u2FrameCtrl = MAC_FRAME_REASSOC_REQ; + } else { + u2FrameCtrl = MAC_FRAME_ASSOC_REQ; + } + + WLAN_SET_FIELD_16(&prAssocFrame->u2FrameCtrl, u2FrameCtrl); + + /* Fill the DA field with Target BSSID. */ + COPY_MAC_ADDR(prAssocFrame->aucDestAddr, prStaRec->aucMacAddr); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prAssocFrame->aucSrcAddr, aucMACAddress); + + /* Fill the BSSID field with Target BSSID. */ + COPY_MAC_ADDR(prAssocFrame->aucBSSID, prStaRec->aucMacAddr); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need + * to clear it). */ + prAssocFrame->u2SeqCtrl = 0; + + /* 4 <2> Compose the frame body's common fixed field part of the + * (Re)Association Request frame. */ + u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec); + + /* Fill the Capability Information field. */ + WLAN_SET_FIELD_16(&prAssocFrame->u2CapInfo, u2CapInfo); + + /* Calculate the listen interval for the maximum power mode. Currently, + * we set it to the value 2 times DTIM period by default. + */ + if (prStaRec->ucDTIMPeriod) { + u2ListenInterval = + prStaRec->ucDTIMPeriod * prAdapter->rWifiVar.ucListenDtimInterval; + } else { + DBGLOG(SAA, TRACE, "Use default listen interval\n"); + u2ListenInterval = DEFAULT_LISTEN_INTERVAL; + } + prStaRec->u2ListenInterval = u2ListenInterval; + + /* Fill the Listen Interval field. */ + WLAN_SET_FIELD_16(&prAssocFrame->u2ListenInterval, u2ListenInterval); + + /* 4 <3> Compose the Current AP Address field for ReAssociation Request + * frame. */ + /* Fill the Current AP Address field. */ + if (prStaRec->fgIsReAssoc) { + if (IS_STA_IN_AIS(prStaRec)) { + P_BSS_INFO_T prAisBssInfo = prAdapter->prAisBssInfo; + P_WLAN_REASSOC_REQ_FRAME_T prReAssocFrame = + (P_WLAN_REASSOC_REQ_FRAME_T)prAssocFrame; + + COPY_MAC_ADDR(prReAssocFrame->aucCurrentAPAddr, + prAisBssInfo->aucBSSID); + } else { + ASSERT(0); /* We don't support ReAssociation for other + * network */ + } + + *pu2PayloadLen = (CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN + + CURR_AP_ADDR_FIELD_LEN); + } else { + *pu2PayloadLen = (CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will send the (Re)Association Request frame + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @retval WLAN_STATUS_RESOURCES No available resource for frame composing. + * @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS assocSendReAssocReqFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec) +{ + P_MSDU_INFO_T prMsduInfo; + P_BSS_INFO_T prBssInfo; + + u16 u2PayloadLen; + u16 u2EstimatedFrameLen; + u16 u2EstimatedExtraIELen; + u8 fgIsReAssoc; + u32 i; + + ASSERT(prStaRec); + + /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ + fgIsReAssoc = prStaRec->fgIsReAssoc; + + /* Init with MGMT Header Length + Length of Fixed Fields + Common IE + * Length */ + if (fgIsReAssoc) { + u2EstimatedFrameLen = + MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + + CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN + + CURR_AP_ADDR_FIELD_LEN + (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + + (ELEM_HDR_LEN + (RATE_NUM_SW - ELEM_MAX_LEN_SUP_RATES)); + } else { + u2EstimatedFrameLen = + MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + + CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + + (ELEM_HDR_LEN + (RATE_NUM_SW - ELEM_MAX_LEN_SUP_RATES)); + } + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 && CFG_ENABLE_WIFI_DIRECT + if (IS_STA_IN_P2P(prStaRec)) { + if ((prAdapter->fgIsP2PRegistered)) { + u2EstimatedExtraIELen = p2pCalculate_IEForAssocReq( + prAdapter, prStaRec->ucBssIndex, prStaRec); + } else { + DBGLOG(P2P, TRACE, "Function Linker Lost.\n"); + ASSERT(false); + } + } else { + for (i = 0; + i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); + i++) { + if (txAssocReqIETable[i].u2EstimatedFixedIELen != 0) { + u2EstimatedExtraIELen += + txAssocReqIETable[i].u2EstimatedFixedIELen; + } else { + u2EstimatedExtraIELen += + (u16)txAssocReqIETable[i].pfnCalculateVariableIELen( + prAdapter, prStaRec->ucBssIndex, prStaRec); + } + } + } +#else + for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); + i++) { + if (txAssocReqIETable[i].u2EstimatedFixedIELen != 0) { + u2EstimatedExtraIELen += txAssocReqIETable[i].u2EstimatedFixedIELen; + } else { + u2EstimatedExtraIELen += + (u16)txAssocReqIETable[i].pfnCalculateVariableIELen( + prAdapter, prStaRec->ucBssIndex, prStaRec); + } + } +#endif + + ASSERT(prStaRec->ucBssIndex <= MAX_BSS_INDEX); + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(SAA, WARN, "No PKT_INFO_T for sending (Re)Assoc Request.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose (Re)Association Request frame header and fixed fields + * in MSDU_INfO_T. */ + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + /* Compose Header and Fixed Field */ + assocComposeReAssocReqFrameHeaderAndFF( + prAdapter, prStaRec, + (u8 *)((unsigned long)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prBssInfo->aucOwnMacAddr, &u2PayloadLen); + + /* 4 <3> Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prStaRec->ucBssIndex, prStaRec->ucIndex, + WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, saaFsmRunEventTxDone, + MSDU_RATE_MODE_AUTO); + + /* 4 <4> Compose the frame body's IEs of the (Re)Association Request + * frame. */ + assocBuildReAssocReqFrameCommonIEs(prAdapter, prMsduInfo); + + /* 4 <5> Compose IEs in MSDU_INFO_T */ +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 && CFG_ENABLE_WIFI_DIRECT + if (IS_STA_IN_P2P(prStaRec)) { + if ((prAdapter->fgIsP2PRegistered)) { + p2pGenerate_IEForAssocReq(prAdapter, prMsduInfo); + } else { + DBGLOG(P2P, TRACE, "Function Linker Lost.\n"); + ASSERT(false); + } + } else { + /* Append IE */ + for (i = 0; + i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); + i++) { + if (txAssocReqIETable[i].pfnAppendIE) { + txAssocReqIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + } + } +#else + /* Append IE */ + for (i = 0; i < sizeof(txAssocReqIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); + i++) + if (txAssocReqIETable[i].pfnAppendIE) { + txAssocReqIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + +#endif + + /* 4 <6> Update the (Re)association request information */ + if (IS_STA_IN_AIS(prStaRec)) { + P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; + + prAssocFrame = + (P_WLAN_ASSOC_REQ_FRAME_T)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD); + + kalUpdateReAssocReqInfo(prAdapter->prGlueInfo, + (u8 *)&prAssocFrame->u2CapInfo, + prMsduInfo->u2FrameLength - + offsetof(WLAN_ASSOC_REQ_FRAME_T, u2CapInfo), + fgIsReAssoc); + } +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { + P_WLAN_ASSOC_REQ_FRAME_T prAssocFrame; + + prAssocFrame = + (P_WLAN_ASSOC_REQ_FRAME_T)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD); + + kalP2PUpdateAssocInfo(prAdapter->prGlueInfo, + (u8 *)&prAssocFrame->u2CapInfo, + prMsduInfo->u2FrameLength - + offsetof(WLAN_ASSOC_REQ_FRAME_T, u2CapInfo), + fgIsReAssoc, prStaRec->ucBssIndex); + } +#endif + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU + */ + + nicTxConfigPktControlFlag(prMsduInfo, MSDU_CONTROL_FLAG_FORCE_TX, true); + + /* 4 <6> Enqueue the frame to send this (Re)Association request frame. + */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will strictly check the TX (Re)Association Request frame + * for SAA event handling. + * + * @param[in] prMsduInfo Pointer of MSDU_INFO_T + * + * @retval WLAN_STATUS_FAILURE This is not the frame we should handle at + * current state. + * @retval WLAN_STATUS_SUCCESS This is the frame we should handle. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS assocCheckTxReAssocReqFrame(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; + P_STA_RECORD_T prStaRec; + u16 u2TxFrameCtrl; + + ASSERT(prMsduInfo); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T)(prMsduInfo->prPacket); + ASSERT(prAssocReqFrame); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if (!prStaRec) { + return WLAN_STATUS_INVALID_PACKET; + } + + /* WLAN_GET_FIELD_16(&prAssocReqFrame->u2FrameCtrl, &u2TxFrameCtrl) */ + u2TxFrameCtrl = prAssocReqFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized + * for ARM */ + u2TxFrameCtrl &= MASK_FRAME_TYPE; + if (prStaRec->fgIsReAssoc) { + if (u2TxFrameCtrl != MAC_FRAME_REASSOC_REQ) { + return WLAN_STATUS_FAILURE; + } + } else { + if (u2TxFrameCtrl != MAC_FRAME_ASSOC_REQ) { + return WLAN_STATUS_FAILURE; + } + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will strictly check the TX (Re)Association Response + * frame for AAA event handling. + * + * @param[in] prMsduInfo Pointer of MSDU_INFO_T + * + * @retval WLAN_STATUS_FAILURE This is not the frame we should handle at + * current state. + * @retval WLAN_STATUS_SUCCESS This is the frame we should handle. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS assocCheckTxReAssocRespFrame(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; + P_STA_RECORD_T prStaRec; + u16 u2TxFrameCtrl; + + ASSERT(prMsduInfo); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)(prMsduInfo->prPacket); + ASSERT(prAssocRspFrame); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if (!prStaRec) { + return WLAN_STATUS_INVALID_PACKET; + } + + /* WLAN_GET_FIELD_16(&prAssocFrame->u2FrameCtrl, &u2TxFrameCtrl) */ + u2TxFrameCtrl = prAssocRspFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized + * for ARM */ + u2TxFrameCtrl &= MASK_FRAME_TYPE; + if (prStaRec->fgIsReAssoc) { + if (u2TxFrameCtrl != MAC_FRAME_REASSOC_RSP) { + return WLAN_STATUS_FAILURE; + } + } else { + if (u2TxFrameCtrl != MAC_FRAME_ASSOC_RSP) { + return WLAN_STATUS_FAILURE; + } + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will validate the incoming (Re)Association Frame and + * take out the status code. + * + * @param[in] prSwRfb Pointer to SW RFB data structure. + * @param[out] pu2StatusCode Pointer to store the Status Code from + * Authentication. + * + * @retval WLAN_STATUS_FAILURE This is not the frame we should handle at + * current state. + * @retval WLAN_STATUS_SUCCESS This is the frame we should handle. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +assocCheckRxReAssocRspFrameStatus(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT u16 *pu2StatusCode) +{ + P_STA_RECORD_T prStaRec; + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; + u16 u2RxFrameCtrl; + u16 u2RxCapInfo; + u16 u2RxStatusCode; + u16 u2RxAssocId; + + if (!prSwRfb || !pu2StatusCode) { + DBGLOG(SAA, ERROR, "Invalid parameter, ignore!\n"); + return WLAN_STATUS_FAILURE; + } + + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < + (CAP_INFO_FIELD_LEN + STATUS_CODE_FIELD_LEN + AID_FIELD_LEN)) { + DBGLOG( + SAA, WARN, + "Invalid AssocRsp packet length. u2PacketLen(%u) u2HeaderLen(%u)\n", + prSwRfb->u2PacketLen, prSwRfb->u2HeaderLen); + return WLAN_STATUS_FAILURE; + } + + DBGLOG(SAA, LOUD, "prSwRfb->u2PayloadLength = %d\n", + prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (!prStaRec) { + DBGLOG(SAA, ERROR, "Invalid prStaRec, ignore!\n"); + return WLAN_STATUS_INVALID_PACKET; + } + + /* 4 <1> locate the (Re)Association Resp Frame. */ + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)prSwRfb->pvHeader; + + /* if Association Response's BSSID doesn't match our target, ignore */ + if (!EQUAL_MAC_ADDR(prAssocRspFrame->aucBSSID, prStaRec->aucMacAddr)) { + DBGLOG(SAA, INFO, "Unknown BSSID\n"); + return WLAN_STATUS_FAILURE; + } + + /* 4 <2> Parse the Header of (Re)Association Resp Frame. */ + /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2FrameCtrl, &u2RxFrameCtrl); */ + u2RxFrameCtrl = prAssocRspFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized + * for ARM */ + u2RxFrameCtrl &= MASK_FRAME_TYPE; + if (prStaRec->fgIsReAssoc) { + if (u2RxFrameCtrl != MAC_FRAME_REASSOC_RSP) { + return WLAN_STATUS_FAILURE; + } + } else { + if (u2RxFrameCtrl != MAC_FRAME_ASSOC_RSP) { + return WLAN_STATUS_FAILURE; + } + } + + /* 4 <3> Parse the Fixed Fields of (Re)Association Resp Frame Body. */ + /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2CapInfo, &u2RxCapInfo); */ + u2RxCapInfo = prAssocRspFrame->u2CapInfo; /* NOTE(Kevin): Optimized for + * ARM */ + + /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2StatusCode, &u2RxStatusCode); + */ + u2RxStatusCode = prAssocRspFrame->u2StatusCode; /* NOTE(Kevin): + * Optimized for ARM */ + + /* 4 <4> Check CAP_INFO */ + /* NOTE(Kevin): CM suggest to add MGMT workaround for those APs didn't + * check the CAP Privacy Bit to overcome a corner case that the Privacy + * Bit of our SCAN result didn't consist with AP's Association Resp. + */ + if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && 1) { + /* Todo:: Fixed this */ + } else +#endif + { + } + +#if CFG_STRICT_CHECK_CAPINFO_PRIVACY + if ((prStaRec->u2CapInfo & CAP_INFO_PRIVACY) ^ + (u2RxCapInfo & CAP_INFO_PRIVACY)) { + u2RxStatusCode = STATUS_CODE_CAP_NOT_SUPPORTED; + } +#endif + } + + if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { + /* Update the information in the structure used to query and set + * OID_802_11_ASSOCIATION_INFORMATION. + */ + kalUpdateReAssocRspInfo( + prAdapter->prGlueInfo, (u8 *)&prAssocRspFrame->u2CapInfo, + (u32)(prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen)); + } + /* 4 <5> Update CAP_INFO and ASSOC_ID */ + if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { + prStaRec->u2CapInfo = u2RxCapInfo; + + /* WLAN_GET_FIELD_16(&prAssocRspFrame->u2AssocId, &u2RxAssocId); + */ + u2RxAssocId = prAssocRspFrame->u2AssocId; /* NOTE(Kevin): + * Optimized for ARM + */ + + /* 20110715 Workaround for Kingnet 710 AP (Realtek 8186) + * This AP raises the bit 6&7 not bit 14&15 in AID field. + * It cause wrong AID assignment. + * For AID = 2 + * Normal case: 0xC002(1100 0000 0000 0010) => 2 + * Kingnet 710: 0x00C2(0000 0000 1100 0010) => 194 + * workaround: mask bit 6&7 for this AP + */ + if ((u2RxAssocId & BIT(6)) && (u2RxAssocId & BIT(7)) && + !(u2RxAssocId & BITS(8, 15))) { + prStaRec->u2AssocId = u2RxAssocId & ~BITS(6, 7); + } else { + prStaRec->u2AssocId = u2RxAssocId & ~AID_MSB; +#if CFG_SUPPORT_802_11W + if (prStaRec->eStaType == STA_TYPE_LEGACY_AP) { + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + prBssSpecInfo->ucSaQueryTimedOut = 0; + } +#endif + } + } + +#if CFG_SUPPORT_802_11V + if (u2RxStatusCode == STATUS_CODE_SUCCESSFUL) { +#define DEFAULT_AGE_NULL_PERIOD 30 + u8 *pucIE; + u16 u2IELength, u2IdlePeriod = DEFAULT_AGE_NULL_PERIOD; + u16 u2Offset = 0; + char pcCommand[10]; /* AgingPeriod 1~255*/ + + u2IELength = (u16)(prSwRfb->u2PacketLen - + OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0])); + pucIE = prAssocRspFrame->aucInfoElem; + + IE_FOR_EACH(pucIE, u2IELength, u2Offset){ + if (IE_ID(pucIE) == ELEM_ID_MAX_IDLE_PERIOD && IE_LEN(pucIE) == 3) { + if (MAX_IDLE_PERIOD_IE(pucIE)->u2MaxIdlePeriod > + u2IdlePeriod) { /* Default Againg Period + * less than Max IDLE time. + */ + DBGLOG( + SAA, INFO, + "Max IDLE Period greater than %d seconds. (%d X 1000TU)\n", + u2IdlePeriod, + (MAX_IDLE_PERIOD_IE(pucIE)->u2MaxIdlePeriod)); + break; + } + + DBGLOG(SAA, EVENT, + "Max IDLE Period less than %d seconds. (%d X 1000TU)\n", + u2IdlePeriod, + (MAX_IDLE_PERIOD_IE(pucIE)->u2MaxIdlePeriod)); + + if (MAX_IDLE_PERIOD_IE(pucIE)->ucOption & + BSS_MAX_IDLE_PROTECTED_REQUIRED) { + DBGLOG( + SAA, EVENT, + "AP require protected keep alive,(0x%08x) " + "adjusting NULL frame period no use, follow default\n", + (MAX_IDLE_PERIOD_IE(pucIE)->ucOption)); + break; + } + + u2IdlePeriod = MAX_IDLE_PERIOD_IE(pucIE)->u2MaxIdlePeriod; + break; + } + } /* end of IE_FOR_EACH */ + + kalMemZero(pcCommand, 10); + kalScnprintf(pcCommand, 10, "%d", u2IdlePeriod); + + wlanCfgSet(prAdapter, "AgeNullPeriod", pcCommand, 0); + } +#endif + +#if CFG_SUPPORT_802_11W + if (u2RxStatusCode == STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED) { + DBGLOG(SAA, INFO, + "AP rejected due the authentication algorithm not support\n"); + } else if (u2RxStatusCode == STATUS_CODE_ASSOC_REJECTED_TEMPORARILY) { + u8 *pucIE, *pucTime; + u16 u2IELength; + u16 u2Offset = 0; + + u2IELength = prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen; + pucIE = (u8 *)((unsigned long)prSwRfb->pvHeader + prSwRfb->u2HeaderLen); + + IE_FOR_EACH(pucIE, u2IELength, u2Offset){ + if (IE_ID(pucIE) == ELEM_ID_TIMEOUT_INTERVAL && + IE_LEN(pucIE) == 5) { + pucTime = ((P_IE_HDR_T)pucIE)->aucInfo; + if (pucTime[0] == ACTION_SA_TIMEOUT_ASSOC_COMEBACK) { + u32 tu; + + WLAN_GET_FIELD_32(pucTime + 1, &tu); + DBGLOG( + SAA, INFO, + "AP rejected association temporarily;comeback duration %u TU " + "(%u ms)\n", + tu, TU_TO_MSEC( + tu)); + if (tu > TX_ASSOCIATION_RETRY_TIMEOUT_TU) { + DBGLOG(SAA, INFO, + "Update timer based on comeback duration\n"); + /* ieee80211_reschedule_timer(wpa_s, + * ms); */ + } + } + break; + } + } /* end of IE_FOR_EACH */ + } +#endif + *pu2StatusCode = u2RxStatusCode; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will compose the Disassociation frame + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] pucBuffer Pointer to the frame buffer. + * @param[in] aucMACAddress Given Our MAC Address. + * @param[in] u2ReasonCode The reason code of disassociation + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void assocComposeDisassocFrame(IN P_STA_RECORD_T prStaRec, + IN u8 *pucBuffer, + IN u8 aucMACAddress[], + IN u16 u2ReasonCode) +{ + P_WLAN_DISASSOC_FRAME_T prDisAssocFrame; + u16 u2FrameCtrl; + + ASSERT(pucBuffer); + ASSERT(pucBuffer); + ASSERT(aucMACAddress); + + prDisAssocFrame = (P_WLAN_DISASSOC_FRAME_T)pucBuffer; + + /* 4 <1> Compose the frame header of the DisAssociation frame. */ + /* Fill the Frame Control field. */ + u2FrameCtrl = MAC_FRAME_DISASSOC; + + WLAN_SET_FIELD_16(&prDisAssocFrame->u2FrameCtrl, u2FrameCtrl); + + /* Fill the DA field with Target BSSID. */ + COPY_MAC_ADDR(prDisAssocFrame->aucDestAddr, prStaRec->aucMacAddr); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prDisAssocFrame->aucSrcAddr, aucMACAddress); + + /* Fill the BSSID field with Target BSSID. */ + COPY_MAC_ADDR(prDisAssocFrame->aucBSSID, prStaRec->aucMacAddr); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need + * to clear it). */ + prDisAssocFrame->u2SeqCtrl = 0; + + /* 4 <2> Compose the frame body's fixed field part of the Disassociation + * frame. */ + /* Fill the Reason Code field. */ + WLAN_SET_FIELD_16(&prDisAssocFrame->u2ReasonCode, u2ReasonCode); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will send the Disassociation frame + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] u2ReasonCode The reason code of disassociation + * + * @retval WLAN_STATUS_RESOURCES No available resource for frame composing. + * @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS assocSendDisAssocFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN u16 u2ReasonCode) +{ + u8 *pucMacAddress; + P_MSDU_INFO_T prMsduInfo; + u16 u2PayloadLen; + u16 u2EstimatedFrameLen; + u8 ucRoleIdx = 0; + P_BSS_INFO_T prBssInfo = NULL; + u8 *pFrameBuf; + u8 fgIsInterruptContext = false; + + ASSERT(prStaRec); + ASSERT(prStaRec->ucBssIndex <= MAX_BSS_INDEX); + + DBGLOG(RSN, INFO, "assocSendDisAssocFrame\n"); + + /* 4 <1> Allocate a PKT_INFO_T for Disassociation Frame */ + /* Init with MGMT Header Length + Length of Fixed Fields + IE Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + + REASON_CODE_FIELD_LEN; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(SAA, WARN, "No PKT_INFO_T for sending DisAssoc.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose Disassociation frame header and fixed fields in + * MSDU_INfO_T. */ + pucMacAddress = + GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex)->aucOwnMacAddr; + + /* Compose Header and Fixed Field */ + assocComposeDisassocFrame( + prStaRec, + (u8 *)((unsigned long)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + pucMacAddress, u2ReasonCode); + +#if CFG_SUPPORT_802_11W + /* AP PMF */ + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + /* PMF certification 4.3.3.1, 4.3.3.2 send unprotected deauth + * reason 6/7 */ + if (prStaRec->rPmfCfg.fgRxDeauthResp != true) { + P_WLAN_DISASSOC_FRAME_T prDisassocFrame; + + prDisassocFrame = + (P_WLAN_DISASSOC_FRAME_T)((unsigned long)(prMsduInfo->prPacket) + + + MAC_TX_RESERVED_FIELD); + + prDisassocFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + } + } +#endif + + u2PayloadLen = REASON_CODE_FIELD_LEN; + + /* 4 <3> Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prStaRec->ucBssIndex, prStaRec->ucIndex, + WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, NULL, + MSDU_RATE_MODE_AUTO); + +#if CFG_SUPPORT_802_11W + /* AP PMF */ + /* caution: access prStaRec only if true */ + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + /* 4.3.3.1 send unprotected deauth reason 6/7 */ + if (prStaRec->rPmfCfg.fgRxDeauthResp != true) { + DBGLOG(RSN, INFO, "Disassoc Set MSDU_OPT_PROTECTED_FRAME\n"); + nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, true); + } + + prStaRec->rPmfCfg.fgRxDeauthResp = false; + } +#endif + + { + P_WLAN_DISASSOC_FRAME_T prDisassocFrame; + + prDisassocFrame = + (P_WLAN_DISASSOC_FRAME_T)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD); + DBGLOG(SAA, INFO, "notification of TX disassociation, %d\n", + prMsduInfo->u2FrameLength); + + /* + * check prStaRec is not NULL first + * prStaRec can be NULL if it is P2P GO + */ + if ((prStaRec) && (IS_STA_IN_AIS(prStaRec))) { + if (in_interrupt()) { + pFrameBuf = + kalMemAlloc(prMsduInfo->u2FrameLength, PHY_MEM_TYPE); + fgIsInterruptContext = true; + } else { + pFrameBuf = + kalMemAlloc(prMsduInfo->u2FrameLength, VIR_MEM_TYPE); + fgIsInterruptContext = false; + } + + if (!pFrameBuf) { + DBGLOG(SAA, ERROR, "Alloc buffer for frame failed\n"); + return WLAN_STATUS_RESOURCES; + } + + kalMemCopy((void *)pFrameBuf, (void *)prDisassocFrame, + prMsduInfo->u2FrameLength); + + kalWDevLockThread(prAdapter->prGlueInfo, + prAdapter->prGlueInfo->prDevHandler, + CFG80211_TX_MLME_MGMT, pFrameBuf, + prMsduInfo->u2FrameLength, NULL, 0, NULL, 0, + fgIsInterruptContext); + } else if (prAdapter->fgIsP2PRegistered) { + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + ucRoleIdx = (u8)prBssInfo->u4PrivateData; + + if (in_interrupt()) { + pFrameBuf = + kalMemAlloc(prMsduInfo->u2FrameLength, PHY_MEM_TYPE); + fgIsInterruptContext = true; + } else { + pFrameBuf = + kalMemAlloc(prMsduInfo->u2FrameLength, VIR_MEM_TYPE); + fgIsInterruptContext = false; + } + + if (!pFrameBuf) { + DBGLOG(SAA, ERROR, "Alloc buffer for frame failed\n"); + return WLAN_STATUS_RESOURCES; + } + + kalMemCopy((void *)pFrameBuf, (void *)prDisassocFrame, + prMsduInfo->u2FrameLength); + kalWDevLockThread( + prAdapter->prGlueInfo, + prAdapter->prGlueInfo->prP2PInfo[ucRoleIdx]->aprRoleHandler, + CFG80211_TX_MLME_MGMT, pFrameBuf, prMsduInfo->u2FrameLength, + NULL, 0, NULL, 0, fgIsInterruptContext); + } else { + DBGLOG(SAA, INFO, "notification of TX deauthentication, FAILED\n"); + } + DBGLOG(SAA, INFO, "notification of TX disassociation, Done\n"); + } + + /* 4 <4> Enqueue the frame to send this (Re)Association request frame. + */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will parse and process the incoming Disassociation frame + * if the given BSSID is matched. + * + * @param[in] prSwRfb Pointer to SW RFB data structure. + * @param[in] aucBSSID Given BSSID + * @param[out] pu2ReasonCode Pointer to store the Reason Code from + * Deauthentication. + * + * @retval WLAN_STATUS_FAILURE This is not the frame we should handle at + * current state. + * @retval WLAN_STATUS_SUCCESS This is the frame we should handle. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +assocProcessRxDisassocFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + IN u8 aucBSSID[], OUT u16 *pu2ReasonCode) +{ + P_WLAN_DISASSOC_FRAME_T prDisassocFrame; + u16 u2RxReasonCode; + + if (!prSwRfb || !aucBSSID || !pu2ReasonCode) { + DBGLOG(SAA, WARN, "Invalid parameters, ignore this pkt!\n"); + return WLAN_STATUS_FAILURE; + } + + /* 4 <1> locate the Disassociation Frame. */ + prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T)prSwRfb->pvHeader; + + /* 4 <2> Parse the Header of Disassociation Frame. */ + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < REASON_CODE_FIELD_LEN) { + DBGLOG( + SAA, WARN, + "Invalid DisAssoc packet length. u2PacketLen(%u) u2HeaderLen(%u)\n", + prSwRfb->u2PacketLen, prSwRfb->u2HeaderLen); + return WLAN_STATUS_FAILURE; + } + + /* Check if this Disassoc Frame is coming from Target BSSID */ + if (UNEQUAL_MAC_ADDR(prDisassocFrame->aucBSSID, aucBSSID)) { + DBGLOG(SAA, LOUD, "Ignore Disassoc Frame from other BSS [" MACSTR "]\n", + MAC2STR(prDisassocFrame->aucSrcAddr)); + return WLAN_STATUS_FAILURE; + } + + /* 4 <3> Parse the Fixed Fields of Deauthentication Frame Body. */ + WLAN_GET_FIELD_16(&prDisassocFrame->u2ReasonCode, &u2RxReasonCode); + *pu2ReasonCode = u2RxReasonCode; + + return WLAN_STATUS_SUCCESS; +} + +#if CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will parse and process the incoming Association Req + * frame and return a Status Code. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prSwRfb Pointer to SW RFB data structure. + * @param[out] pu2StatusCode Pointer to store the Status Code for carried in + * Association Response. + * + * @retval WLAN_STATUS_FAILURE This is not the frame we should handle at + * current state. + * @retval WLAN_STATUS_SUCCESS This is the frame we should handle. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS assocProcessRxAssocReqFrame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + OUT u16 *pu2StatusCode) +{ + P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + P_IE_SSID_T prIeSsid = (P_IE_SSID_T)NULL; + P_RSN_INFO_ELEM_T prIeRsn = (P_RSN_INFO_ELEM_T)NULL; + P_IE_SUPPORTED_RATE_IOT_T prIeSupportedRate = + (P_IE_SUPPORTED_RATE_IOT_T)NULL; + P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = + (P_IE_EXT_SUPPORTED_RATE_T)NULL; + u8 *pucIE, *pucIEStart; + u16 u2IELength; + u16 u2Offset = 0; + u16 u2StatusCode = STATUS_CODE_SUCCESSFUL; + u16 u2RxFrameCtrl; + u8 ucFixedFieldLength; + u8 fgIsHT = false, fgIsTKIP = false; + u32 i; + + if (!prAdapter || !prSwRfb || !pu2StatusCode) { + DBGLOG(SAA, WARN, "Invalid parameters, ignore this pkt!\n"); + return WLAN_STATUS_FAILURE; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prStaRec == NULL) { + return WLAN_STATUS_FAILURE; + } + + /* 4 <1> locate the Association Req Frame. */ + prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T)prSwRfb->pvHeader; + + /* WLAN_GET_FIELD_16(&prAssocReqFrame->u2FrameCtrl, &u2RxFrameCtrl); */ + u2RxFrameCtrl = prAssocReqFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized + * for ARM */ + u2RxFrameCtrl &= MASK_FRAME_TYPE; + + /* 4 <2> Parse the Header of Association Req Frame. */ + if (u2RxFrameCtrl == MAC_FRAME_REASSOC_REQ) { + ucFixedFieldLength = CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN + + CURR_AP_ADDR_FIELD_LEN; + } else { + ucFixedFieldLength = CAP_INFO_FIELD_LEN + LISTEN_INTERVAL_FIELD_LEN; + } + + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) <= ucFixedFieldLength) { + /* Length of this (re)association req is invalid, ignore it */ + return WLAN_STATUS_FAILURE; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + /* Check if this Disassoc Frame is coming from Target BSSID */ + if (UNEQUAL_MAC_ADDR(prAssocReqFrame->aucBSSID, prBssInfo->aucBSSID)) { + return WLAN_STATUS_FAILURE; /* Just Ignore this MMPDU */ + } + if (u2RxFrameCtrl == MAC_FRAME_REASSOC_REQ) { + prStaRec->fgIsReAssoc = true; + + u2IELength = prSwRfb->u2PacketLen - + (u16)OFFSET_OF(WLAN_REASSOC_REQ_FRAME_T, aucInfoElem[0]); + + pucIEStart = pucIE = + ((P_WLAN_REASSOC_REQ_FRAME_T)(prSwRfb->pvHeader))->aucInfoElem; + } else { + prStaRec->fgIsReAssoc = false; + + u2IELength = prSwRfb->u2PacketLen - + (u16)OFFSET_OF(WLAN_ASSOC_REQ_FRAME_T, aucInfoElem[0]); + + pucIEStart = pucIE = prAssocReqFrame->aucInfoElem; + } + + /* 4 <3> Parse the Fixed Fields of Assoc Req Frame Body. */ + prStaRec->u2CapInfo = prAssocReqFrame->u2CapInfo; + + prStaRec->u2ListenInterval = prAssocReqFrame->u2ListenInterval; + prStaRec->ucPhyTypeSet = 0; + + /* Might be legacy client or p2p gc. */ + prStaRec->eStaType = STA_TYPE_LEGACY_CLIENT; + + /* 4 <4> Parse the IE of Assoc Req Frame Body. */ + IE_FOR_EACH(pucIE, u2IELength, u2Offset){ + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: + if ((!prIeSsid) && /* NOTE(Kevin): Get SSID once */ + (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { + prIeSsid = (P_IE_SSID_T)pucIE; + } + break; + + case ELEM_ID_SUP_RATES: + if ((!prIeSupportedRate) && (IE_LEN(pucIE) <= RATE_NUM_SW)) { + prIeSupportedRate = SUP_RATES_IOT_IE(pucIE); + } + + break; + + case ELEM_ID_PWR_CAP: + if (IE_LEN(pucIE) != ELEM_MAX_LEN_POWER_CAP) { + return WLAN_STATUS_FAILURE; + } + + break; + + case ELEM_ID_SUP_CHS: + if ((IE_LEN(pucIE) > ELEM_MAX_LEN_SUPPORTED_CHANNELS) || + (IE_LEN(pucIE) & 0x01)) { + return WLAN_STATUS_FAILURE; + } + + break; + + case ELEM_ID_EXTENDED_SUP_RATES: + if (!prIeExtSupportedRate) { + prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); + } + break; + + case ELEM_ID_HT_CAP: + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + fgIsHT = true; + break; + + case ELEM_ID_VHT_CAP: + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_VHT; + break; + + case ELEM_ID_RSN: +#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK + if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + prIeRsn = RSN_IE(pucIE); + rsnParserCheckForRSNCCMPPSK(prAdapter, prIeRsn, prStaRec, + &u2StatusCode); + if (u2StatusCode == STATUS_CODE_INVALID_INFO_ELEMENT) { + return WLAN_STATUS_FAILURE; + } + if (u2StatusCode != STATUS_CODE_SUCCESSFUL) { + *pu2StatusCode = u2StatusCode; + return WLAN_STATUS_SUCCESS; + } + } +#endif + break; + + case ELEM_ID_VENDOR: + if (p2pFuncParseCheckForTKIPInfoElem(pucIE)) { + fgIsTKIP = true; + } + +#if CFG_ENABLE_WIFI_DIRECT + { + if ((prAdapter->fgIsP2PRegistered)) { + u8 ucOuiType = 0; + + p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIE, + &ucOuiType); + + if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + DBGLOG(P2P, TRACE, + "Target Client is a P2P group client\n"); + prStaRec->eStaType = STA_TYPE_P2P_GC; + } + } + } +#endif + break; + + case ELEM_ID_IBSS_PARAM_SET: + /* Check IBSS parameter set length to avoid abnormal + * content */ + if (IE_LEN(pucIE) != ELEM_MAX_LEN_IBSS_PARAMETER_SET) { + *pu2StatusCode = STATUS_CODE_UNSPECIFIED_FAILURE; + DBGLOG(SAA, WARN, "Invalid IBSS Parameter IE length!\n"); + return WLAN_STATUS_FAILURE; + } + break; + + default: + for (i = 0; + i < (sizeof(rxAssocReqIETable) / sizeof(VERIFY_IE_ENTRY_T)); + i++) { + if (((IE_ID(pucIE)) == rxAssocReqIETable[i].ucElemID) && + (rxAssocReqIETable[i].pfnVarifyIE != NULL)) { + rxAssocReqIETable[i].pfnVarifyIE( + prAdapter, prSwRfb, (P_IE_HDR_T)pucIE, &u2StatusCode); + + if (u2StatusCode != STATUS_CODE_SUCCESSFUL) { + *pu2StatusCode = u2StatusCode; + return WLAN_STATUS_SUCCESS; + } + } + } + + break; + } + } /* end of IE_FOR_EACH */ + + /* parsing for WMM related information (2010/12/21) */ + mqmProcessAssocReq(prAdapter, prSwRfb, pucIEStart, u2IELength); + + do { +#if CFG_SUPPORT_AAA_CHECK_NO_SSID + DBGLOG(SAA, WARN, + "Driver configured to not check SSID field of Assoc Req!\n"); +#else + if (prIeSsid) { + if (UNEQUAL_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, + prIeSsid->aucSSID, prIeSsid->ucLength)) { + u2StatusCode = STATUS_CODE_UNSPECIFIED_FAILURE; + break; + } + } else { + u2StatusCode = STATUS_CODE_UNSPECIFIED_FAILURE; + break; + } +#endif + + prStaRec->u2OperationalRateSet = 0; + prStaRec->u2BSSBasicRateSet = 0; + + if (!prIeSupportedRate) { + DBGLOG(SAA, WARN, "Supported Rate IE not present!\n"); + u2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; + break; + } + /* Ignore any Basic Bit */ +#ifdef IGNORE_BASSIC_BIT + /*! + * FIXME + */ + rateGetRateSetFromIEs(prIeSupportedRate, prIeExtSupportedRate, + &prStaRec->u2OperationalRateSet, + &u2BSSBasicRateSet, &fgIsUnknownBssBasicRate); + + if ((prBssInfo->u2BSSBasicRateSet & prStaRec->u2OperationalRateSet) != + prBssInfo->u2BSSBasicRateSet) { + u2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; + DBGLOG(SAA, WARN, "Basic rate not supported!\n"); + break; + } +#endif + + /* Accpet the Sta, update BSSBasicRateSet from Bss */ + prStaRec->u2BSSBasicRateSet = prBssInfo->u2BSSBasicRateSet; + prStaRec->u2DesiredNonHTRateSet = + (prStaRec->u2OperationalRateSet & RATE_SET_ALL_ABG); + + if (HAL_RX_STATUS_GET_RF_BAND(prSwRfb->prRxStatus) == BAND_2G4) { + if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; + } + if (prStaRec->u2OperationalRateSet & RATE_SET_HR_DSSS) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; + } + } else { /* (BAND_5G == prBssDesc->eBande) */ + if (prStaRec->u2OperationalRateSet & RATE_SET_OFDM) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; + } + } + /* Update default Tx rate */ + nicTxUpdateStaRecDefaultRate(prStaRec); + +#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_HOTSPOT_PRIVACY_CHECK + if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + if (prIeRsn) { + if (!kalP2PGetCipher(prAdapter->prGlueInfo, + (u8)prBssInfo->u4PrivateData)) { + u2StatusCode = STATUS_CODE_CIPHER_SUITE_REJECTED; + break; + } + } else { + /* prStaRec->rSecInfo.fgAllowOnly1x = false; */ + /* if (kalP2PGetCipher(prAdapter->prGlueInfo)) { + */ + /* Only Allow 1x */ + /* prStaRec->rSecInfo.fgAllowOnly1x = true; */ + /* break; */ + /* } */ + } + } +#endif + } while (false); + +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + { + u8 *cp = (u8 *)&prAssocReqFrame->u2CapInfo; + + if (prStaRec->fgIsReAssoc) { + cp += 10; + } else { + cp += 4; + } + if (prStaRec->pucAssocReqIe) { + kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, + prStaRec->u2AssocReqIeLen); + prStaRec->pucAssocReqIe = NULL; + } + prStaRec->u2AssocReqIeLen = u2IELength; + if (u2IELength) { + prStaRec->pucAssocReqIe = kalMemAlloc(u2IELength, VIR_MEM_TYPE); + + if (prStaRec->pucAssocReqIe) { + kalMemCopy(prStaRec->pucAssocReqIe, cp, u2IELength); + } else { + DBGLOG( + SAA, LOUD, + "allocate memory for prStaRec->pucAssocReqIe failed!\n"); + } + } + } + + kalP2PUpdateAssocInfo(prAdapter->prGlueInfo, + (u8 *)&prAssocReqFrame->u2CapInfo, + u2IELength + (prStaRec->fgIsReAssoc ? 10 : 4), + prStaRec->fgIsReAssoc, prStaRec->ucBssIndex); + } +#endif + + if (fgIsHT && fgIsTKIP && + prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + u2StatusCode = STATUS_CODE_REQ_DECLINED; + } + + *pu2StatusCode = u2StatusCode; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to compose Common Information Elements for + * Association Response Frame. + * + * @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. + * @param[in] prBssInfo Pointer to the BSS_INFO_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void +assocBuildReAssocRespFrameCommonIEs(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_BSS_INFO_T prBssInfo) +{ + u8 *pucBuffer; + P_STA_RECORD_T prStaRec; + u8 ucSupRatesLen; + u8 ucExtSupRatesLen; + + ASSERT(prMsduInfo); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + ASSERT(pucBuffer); + + if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) { + ucSupRatesLen = ELEM_MAX_LEN_SUP_RATES; + ucExtSupRatesLen = + prBssInfo->ucAllSupportedRatesLen - ELEM_MAX_LEN_SUP_RATES; + } else { + ucSupRatesLen = prBssInfo->ucAllSupportedRatesLen; + ucExtSupRatesLen = 0; + } + + /* Fill the Supported Rates element. */ + if (ucSupRatesLen) { + SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; + SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; + kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, + prBssInfo->aucAllSupportedRates, ucSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + + /* Fill the Extended Supported Rates element. */ + if (ucExtSupRatesLen) { + EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; + EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; + + kalMemCopy(EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, + &prBssInfo->aucAllSupportedRates[ucSupRatesLen], + ucExtSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will compose the (Re)Association Response frame + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] pucBuffer Pointer to the frame buffer. + * @param[in] aucBssid Given BSSID. + * @param[in] u2CapInfo Capability Field of current BSS. + * @param[in out] pu2PayloadLen Return the length of the composed fixed + * fields + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void assocComposeReAssocRespFrameHeaderAndFF( + IN P_STA_RECORD_T prStaRec, IN u8 *pucBuffer, IN u8 aucBSSID[], + IN u16 u2CapInfo, IN OUT u16 *pu2PayloadLen) +{ + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame; + u8 fgIsReAssoc; + + u16 u2FrameCtrl; + + ASSERT(prStaRec); + ASSERT(pucBuffer); + ASSERT(aucBSSID); + ASSERT(pu2PayloadLen); + + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)pucBuffer; + fgIsReAssoc = prStaRec->fgIsReAssoc; + + /* 4 <1> Compose the frame header of the (Re)Association Request frame. + */ + /* Fill the Frame Control field. */ + if (fgIsReAssoc) { + u2FrameCtrl = MAC_FRAME_REASSOC_RSP; + } else { + u2FrameCtrl = MAC_FRAME_ASSOC_RSP; + } + + /* WLAN_SET_FIELD_16(&prAssocFrame->u2FrameCtrl, u2FrameCtrl); */ + prAssocRspFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized + * for ARM */ + + /* Fill the DA field with Target MAC Address. */ + COPY_MAC_ADDR(prAssocRspFrame->aucDestAddr, prStaRec->aucMacAddr); + + /* Fill the SA field with current BSSID. */ + COPY_MAC_ADDR(prAssocRspFrame->aucSrcAddr, aucBSSID); + + /* Fill the BSSID field with current BSSID. */ + COPY_MAC_ADDR(prAssocRspFrame->aucBSSID, aucBSSID); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need + * to clear it). */ + prAssocRspFrame->u2SeqCtrl = 0; + + /* 4 <2> Compose the frame body's common fixed field part of the + * (Re)Association Request frame. */ + /* Fill the Capability Information field. */ + /* WLAN_SET_FIELD_16(&prAssocFrame->u2CapInfo, u2CapInfo); */ + prAssocRspFrame->u2CapInfo = u2CapInfo; /* NOTE(Kevin): Optimized for + * ARM */ + + /* WLAN_SET_FIELD_16(&prAssocFrame->u2StatusCode, + * prStaRec->u2StatusCode); */ + prAssocRspFrame->u2StatusCode = prStaRec->u2StatusCode; /* NOTE(Kevin): + * Optimized for + * ARM */ + + /* WLAN_SET_FIELD_16(&prAssocFrame->u2AssocId, ((prStaRec->u2AssocId & + * AID_MASK) | AID_MSB)); */ + /* NOTE(Kevin): Optimized for ARM */ + prAssocRspFrame->u2AssocId = ((prStaRec->u2AssocId & AID_MASK) | AID_MSB); + + *pu2PayloadLen = + (CAP_INFO_FIELD_LEN + STATUS_CODE_FIELD_LEN + AID_FIELD_LEN); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will send the (Re)Association Resp frame + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @retval WLAN_STATUS_RESOURCES No available resource for frame composing. + * @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS assocSendReAssocRespFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + + u16 u2PayloadLen; + u16 u2EstimatedFrameLen; + u16 u2EstimatedExtraIELen; + u8 fgIsReAssoc; + u32 i; + + ASSERT(prStaRec); + ASSERT(prStaRec->ucBssIndex <= MAX_BSS_INDEX); + + /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ + fgIsReAssoc = prStaRec->fgIsReAssoc; + + /* Init with MGMT Header Length + Length of Fixed Fields + Common IE + * Length */ + u2EstimatedFrameLen = + MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + CAP_INFO_FIELD_LEN + + STATUS_CODE_FIELD_LEN + AID_FIELD_LEN + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + + (ELEM_HDR_LEN + (RATE_NUM_SW - ELEM_MAX_LEN_SUP_RATES)); + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + + for (i = 0; i < sizeof(txAssocRespIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); + i++) { + if (txAssocRespIETable[i].u2EstimatedFixedIELen != 0) { + u2EstimatedExtraIELen += + txAssocRespIETable[i].u2EstimatedFixedIELen; + } else if (txAssocRespIETable[i].pfnCalculateVariableIELen != NULL) { + u2EstimatedExtraIELen += + (u16)txAssocRespIETable[i].pfnCalculateVariableIELen( + prAdapter, prStaRec->ucBssIndex, prStaRec); + } + } + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(AAA, WARN, "No PKT_INFO_T for sending (Re)Assoc Response.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose (Re)Association Request frame header and fixed fields + * in MSDU_INfO_T. */ + if (prAdapter->prAisBssInfo != NULL) { + ASSERT(prStaRec->ucBssIndex != prAdapter->prAisBssInfo->ucBssIndex); + } + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + /* Compose Header and Fixed Field */ + assocComposeReAssocRespFrameHeaderAndFF( + prStaRec, + (u8 *)((unsigned long)(prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD), + prBssInfo->aucBSSID, prBssInfo->u2CapInfo, &u2PayloadLen); + + /* 4 <3> Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prStaRec->ucBssIndex, prStaRec->ucIndex, + WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, aaaFsmRunEventTxDone, + MSDU_RATE_MODE_AUTO); + + /* 4 <4> Compose the frame body's IEs of the (Re)Association Request + * frame. */ + assocBuildReAssocRespFrameCommonIEs(prAdapter, prMsduInfo, prBssInfo); + + /* 4 <5> Compose IEs in MSDU_INFO_T */ + + /* Append IE */ + for (i = 0; i < sizeof(txAssocRespIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); + i++) { + if (txAssocRespIETable[i].pfnAppendIE) { + txAssocRespIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + } + +#if CFG_SUPPORT_WFD + /* TODO put WFD IE in assoc resp if driver will send assoc resp */ +#endif + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU + */ + + nicTxConfigPktControlFlag(prMsduInfo, MSDU_CONTROL_FLAG_FORCE_TX, true); + + /* 4 <6> Enqueue the frame to send this (Re)Association request frame. + */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/auth.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/auth.c new file mode 100644 index 00000000000000..d9d26000e3af25 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/auth.c @@ -0,0 +1,1277 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "auth.c" + * \brief This file includes the authentication-related functions. + * + * This file includes the authentication-related functions. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +APPEND_IE_ENTRY_T txAuthIETable[] = { + { (ELEM_HDR_LEN + ELEM_MAX_LEN_CHALLENGE_TEXT), authAddIEChallengeText } +}; + +HANDLE_IE_ENTRY_T rxAuthIETable[] = { { ELEM_ID_CHALLENGE_TEXT, + authHandleIEChallengeText } }; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will compose the Authentication frame header and fixed + * fields. + * + * @param[in] pucBuffer Pointer to the frame buffer. + * @param[in] aucPeerMACAddress Given Peer MAC Address. + * @param[in] aucMACAddress Given Our MAC Address. + * @param[in] u2AuthAlgNum Authentication Algorithm Number + * @param[in] u2TransactionSeqNum Transaction Sequence Number + * @param[in] u2StatusCode Status Code + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void authComposeAuthFrameHeaderAndFF( + IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, IN u8 *pucBuffer, + IN u8 aucPeerMACAddress[], IN u8 aucMACAddress[], IN u16 u2AuthAlgNum, + IN u16 u2TransactionSeqNum, IN u16 u2StatusCode) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + u16 u2FrameCtrl; + P_CONNECTION_SETTINGS_T prConnSettings; + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + ASSERT(pucBuffer); + ASSERT(aucPeerMACAddress); + ASSERT(aucMACAddress); + + prAuthFrame = (P_WLAN_AUTH_FRAME_T)pucBuffer; + + /* 4 <1> Compose the frame header of the Authentication frame. */ + /* Fill the Frame Control field. */ + u2FrameCtrl = MAC_FRAME_AUTH; + + /* If this frame is the third frame in the shared key authentication + * sequence, it shall be encrypted. + */ + if ((u2AuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) && + (u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_3)) { + u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; /* HW will also detect + this bit for applying + encryption */ + } + /* WLAN_SET_FIELD_16(&prAuthFrame->u2FrameCtrl, u2FrameCtrl); */ + prAuthFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for + ARM */ + + /* Fill the DA field with Target BSSID. */ + COPY_MAC_ADDR(prAuthFrame->aucDestAddr, aucPeerMACAddress); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prAuthFrame->aucSrcAddr, aucMACAddress); + + if (prStaRec != NULL && IS_AP_STA(prStaRec)) { + /* Fill the BSSID field with Target BSSID. */ + COPY_MAC_ADDR(prAuthFrame->aucBSSID, aucPeerMACAddress); + } else if (prStaRec != NULL && IS_CLIENT_STA(prStaRec)) { + /* Fill the BSSID field with Current BSSID. */ + COPY_MAC_ADDR(prAuthFrame->aucBSSID, aucMACAddress); + } else { + COPY_MAC_ADDR(prAuthFrame->aucBSSID, aucMACAddress); + DBGLOG(SAA, INFO, "Error status code flow!\n"); + } + + /* Clear the SEQ/FRAG_NO field. */ + prAuthFrame->u2SeqCtrl = 0; + + /* 4 <2> Compose the frame body's fixed field part of the Authentication + * frame. */ + /* Fill the Authentication Algorithm Number field. */ + /* WLAN_SET_FIELD_16(&prAuthFrame->u2AuthAlgNum, u2AuthAlgNum); */ + prAuthFrame->u2AuthAlgNum = u2AuthAlgNum; /* NOTE(Kevin): Optimized for + ARM */ + + if ((prConnSettings->ucAuthDataLen != 0) && !IS_STA_IN_P2P(prStaRec)) { + kalMemCopy(prAuthFrame->aucAuthData, + prConnSettings->aucAuthData, + prConnSettings->ucAuthDataLen); + } else { + /* Fill the Authentication Transaction Sequence Number field. */ + /* NOTE(Kevin): Optimized for ARM */ + prAuthFrame->aucAuthData[0] = (u8)(u2TransactionSeqNum & 0xff); + prAuthFrame->aucAuthData[1] = + (u8)((u2TransactionSeqNum >> 8) & 0xff); + + /* Fill the Status Code field. */ + /* NOTE(Kevin): Optimized for ARM */ + prAuthFrame->aucAuthData[2] = (u8)(u2StatusCode & 0xff); + prAuthFrame->aucAuthData[3] = (u8)((u2StatusCode >> 8) & 0xff); + } + DBGLOG(SAA, INFO, "Compose auth with TransSN = %d,Status = %d\n", + prAuthFrame->aucAuthData[0], prAuthFrame->aucAuthData[2]); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will append Challenge Text IE to the Authentication + * frame + * + * @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void authAddIEChallengeText(IN P_ADAPTER_T prAdapter, + IN OUT P_MSDU_INFO_T prMsduInfo) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + P_STA_RECORD_T prStaRec; + u16 u2TransactionSeqNum; + + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (!prStaRec) { + return; + } + + ASSERT(prStaRec); + + /* For Management, frame header and payload are in a continuous buffer + */ + prAuthFrame = (P_WLAN_AUTH_FRAME_T)prMsduInfo->prPacket; + + WLAN_GET_FIELD_16(&prAuthFrame->aucAuthData[0], &u2TransactionSeqNum) + + /* Only consider SEQ_3 for Challenge Text */ + if ((u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_3) && + (prStaRec->ucAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) && + (prStaRec->prChallengeText != NULL)) { + COPY_IE(((unsigned long)(prMsduInfo->prPacket) + + prMsduInfo->u2FrameLength), + (prStaRec->prChallengeText)); + + prMsduInfo->u2FrameLength += IE_SIZE(prStaRec->prChallengeText); + } + + return; +} + +#if !CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will send the Authenticiation frame + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] u2TransactionSeqNum Transaction Sequence Number + * + * @retval WLAN_STATUS_RESOURCES No available resource for frame composing. + * @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS authSendAuthFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN u16 u2TransactionSeqNum) +{ + P_MSDU_INFO_T prMsduInfo; + P_BSS_INFO_T prBssInfo; + u16 u2EstimatedFrameLen; + u16 u2EstimatedExtraIELen; + u16 u2PayloadLen; + u32 i; + + DBGLOG(SAA, LOUD, "Send Auth Frame\n"); + + ASSERT(prStaRec); + + /* 4 <1> Allocate a PKT_INFO_T for Authentication Frame */ + /* Init with MGMT Header Length + Length of Fixed Fields */ + u2EstimatedFrameLen = + (MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + + AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + + STATUS_CODE_FIELD_LEN); + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + + for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) + u2EstimatedExtraIELen += txAuthIETable[i].u2EstimatedIELen; + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(SAA, WARN, "No PKT_INFO_T for sending Auth Frame.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose Authentication Request frame header and fixed fields in + * MSDU_INfO_T. */ + ASSERT(prStaRec->ucBssIndex <= MAX_BSS_INDEX); + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex) + + /* Compose Header and some Fixed Fields */ + authComposeAuthFrameHeaderAndFF( + prAdapter, prStaRec, + (u8 *)((u32)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD), + prStaRec->aucMacAddr, prBssInfo->aucOwnMacAddr, + prStaRec->ucAuthAlgNum, u2TransactionSeqNum, + STATUS_CODE_RESERVED); + + u2PayloadLen = (AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + + STATUS_CODE_FIELD_LEN); + + /* 4 <3> Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prStaRec->ucBssIndex, + prStaRec->ucIndex, WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, + saaFsmRunEventTxDone, MSDU_RATE_MODE_AUTO); + + /* 4 <4> Compose IEs in MSDU_INFO_T */ + for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); + i++) + if (txAuthIETable[i].pfnAppendIE) { + txAuthIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU + */ + + nicTxConfigPktControlFlag(prMsduInfo, MSDU_CONTROL_FLAG_FORCE_TX, true); + + /* 4 <6> Inform TXM to send this Authentication frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} + +#else + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will send the Authenticiation frame + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] u2TransactionSeqNum Transaction Sequence Number + * + * @retval WLAN_STATUS_RESOURCES No available resource for frame composing. + * @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authSendAuthFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, + IN u8 ucBssIndex, IN P_SW_RFB_T prFalseAuthSwRfb, + IN u16 u2TransactionSeqNum, IN u16 u2StatusCode) +{ + u8 *pucReceiveAddr; + u8 *pucTransmitAddr; + P_MSDU_INFO_T prMsduInfo; + P_BSS_INFO_T prBssInfo; + /*get from input parameter */ + /* ENUM_NETWORK_TYPE_INDEX_T eNetTypeIndex = NETWORK_TYPE_AIS_INDEX; */ + PFN_TX_DONE_HANDLER pfTxDoneHandler = (PFN_TX_DONE_HANDLER)NULL; + u16 u2EstimatedFrameLen; + u16 u2EstimatedExtraIELen; + u16 u2PayloadLen; + u16 ucAuthAlgNum; + u32 i; + + P_CONNECTION_SETTINGS_T prConnSettings; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + DBGLOG(SAA, LOUD, "Send Auth Frame %d, Status Code = %d\n", + u2TransactionSeqNum, u2StatusCode); + + if (prStaRec && !IS_STA_IN_P2P(prStaRec) && + (prConnSettings->ucAuthDataLen != 0)) { + DBGLOG(SAA, INFO, "prConnSettings->ucAuthDataLen = %d\n", + prConnSettings->ucAuthDataLen); + u2EstimatedFrameLen = + (MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + + AUTH_ALGORITHM_NUM_FIELD_LEN + + prConnSettings->ucAuthDataLen); + } else { + u2EstimatedFrameLen = + (MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + + AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + + STATUS_CODE_FIELD_LEN); + } + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + + for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); i++) + u2EstimatedExtraIELen += txAuthIETable[i].u2EstimatedIELen; + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(SAA, WARN, "No PKT_INFO_T for sending Auth Frame.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose Authentication Request frame header and fixed fields in + * MSDU_INfO_T. */ + if (prStaRec) { + ASSERT(prStaRec->ucBssIndex <= MAX_BSS_INDEX); + prBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + pucTransmitAddr = prBssInfo->aucOwnMacAddr; + + pucReceiveAddr = prStaRec->aucMacAddr; + + ucAuthAlgNum = prStaRec->ucAuthAlgNum; + + if (!IS_STA_IN_P2P(prStaRec)) { + if (IS_AP_STA(prStaRec)) { /* STA mode */ + pfTxDoneHandler = saaFsmRunEventTxDone; + } else if (IS_CLIENT_STA(prStaRec)) { + pfTxDoneHandler = aaaFsmRunEventTxDone; + } else { + DBGLOG(SAA, WARN, + "Can't send auth with unsupport peer's StaType:%d\n", + prStaRec->eStaType); + return WLAN_STATUS_FAILURE; + } + } else { + switch (u2TransactionSeqNum) { + case AUTH_TRANSACTION_SEQ_1: + case AUTH_TRANSACTION_SEQ_3: + pfTxDoneHandler = saaFsmRunEventTxDone; + break; + + case AUTH_TRANSACTION_SEQ_2: + case AUTH_TRANSACTION_SEQ_4: + pfTxDoneHandler = aaaFsmRunEventTxDone; + break; + } + } + } else { /* For Error Status Code */ + P_WLAN_AUTH_FRAME_T prFalseAuthFrame; + + ASSERT(prFalseAuthSwRfb); + prFalseAuthFrame = + (P_WLAN_AUTH_FRAME_T)prFalseAuthSwRfb->pvHeader; + + ASSERT(u2StatusCode != STATUS_CODE_SUCCESSFUL && + (u2StatusCode != WLAN_STATUS_SAE_HASH_TO_ELEMENT)); + + pucTransmitAddr = prFalseAuthFrame->aucDestAddr; + pucReceiveAddr = prFalseAuthFrame->aucSrcAddr; + ucAuthAlgNum = prFalseAuthFrame->u2AuthAlgNum; + + u2TransactionSeqNum = (prFalseAuthFrame->aucAuthData[1] << 8) + + (prFalseAuthFrame->aucAuthData[0] + 1); + } + + /* Compose Header and some Fixed Fields */ + authComposeAuthFrameHeaderAndFF( + prAdapter, prStaRec, + (u8 *)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD), + pucReceiveAddr, pucTransmitAddr, ucAuthAlgNum, + u2TransactionSeqNum, u2StatusCode); + + /* fill the length of auth frame body */ + if ((prConnSettings->ucAuthDataLen != 0) && !IS_STA_IN_P2P(prStaRec)) { + u2PayloadLen = (AUTH_ALGORITHM_NUM_FIELD_LEN + + prConnSettings->ucAuthDataLen); + }else{ + u2PayloadLen = (AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + + STATUS_CODE_FIELD_LEN); + } + + /* 4 <3> Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, ucBssIndex, + (prStaRec != NULL) ? (prStaRec->ucIndex) : + (STA_REC_INDEX_NOT_FOUND), + WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, pfTxDoneHandler, + MSDU_RATE_MODE_AUTO); + + if ((ucAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) && + (u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_3)) { + nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, + true); + } + /* 4 <4> Compose IEs in MSDU_INFO_T */ + for (i = 0; i < sizeof(txAuthIETable) / sizeof(APPEND_IE_ENTRY_T); + i++) + if (txAuthIETable[i].pfnAppendIE) { + txAuthIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU + */ + + nicTxConfigPktControlFlag(prMsduInfo, MSDU_CONTROL_FLAG_FORCE_TX, true); + + /* 4 <6> Inform TXM to send this Authentication frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will strictly check the TX Authentication frame for + * SAA/AAA event handling. + * + * @param[in] prMsduInfo Pointer of MSDU_INFO_T + * @param[in] u2TransactionSeqNum Transaction Sequence Number + * + * @retval WLAN_STATUS_FAILURE This is not the frame we should handle at + * current state. + * @retval WLAN_STATUS_SUCCESS This is the frame we should handle. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS authCheckTxAuthFrame(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN u16 u2TransactionSeqNum) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + P_STA_RECORD_T prStaRec; + u16 u2TxFrameCtrl; + u16 u2TxAuthAlgNum; + u16 u2TxTransactionSeqNum; + + ASSERT(prMsduInfo); + + prAuthFrame = (P_WLAN_AUTH_FRAME_T)(prMsduInfo->prPacket); + ASSERT(prAuthFrame); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if (!prStaRec) { + return WLAN_STATUS_INVALID_PACKET; + } + + /* WLAN_GET_FIELD_16(&prAuthFrame->u2FrameCtrl, &u2TxFrameCtrl) */ + u2TxFrameCtrl = prAuthFrame->u2FrameCtrl; /* NOTE(Kevin): Optimized for + ARM */ + u2TxFrameCtrl &= MASK_FRAME_TYPE; + if (u2TxFrameCtrl != MAC_FRAME_AUTH) { + return WLAN_STATUS_FAILURE; + } + + /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthAlgNum, &u2TxAuthAlgNum) */ + u2TxAuthAlgNum = prAuthFrame->u2AuthAlgNum; /* NOTE(Kevin): Optimized + for ARM */ + if (u2TxAuthAlgNum != (u16)(prStaRec->ucAuthAlgNum)) { + return WLAN_STATUS_FAILURE; + } + + u2TxTransactionSeqNum = (prAuthFrame->aucAuthData[1] << 8) + + prAuthFrame->aucAuthData[0]; + if (u2TxTransactionSeqNum != u2TransactionSeqNum) { + return WLAN_STATUS_FAILURE; + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will check the incoming Auth Frame's Transaction + * Sequence Number before delivering it to the corresponding SAA or AAA Module. + * + * @param[in] prSwRfb Pointer to the SW_RFB_T structure. + * + * @retval WLAN_STATUS_SUCCESS Always not retain authentication frames + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS authCheckRxAuthFrameTransSeq(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + u16 u2RxTransactionSeqNum; + u16 u2MinPayloadLen; +#if CFG_SUPPORT_SAE + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo = NULL; +#endif + + ASSERT(prSwRfb); + + /* 4 <1> locate the Authentication Frame. */ + prAuthFrame = (P_WLAN_AUTH_FRAME_T)prSwRfb->pvHeader; + + /* 4 <2> Parse the Header of Authentication Frame. */ + u2MinPayloadLen = (AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + + STATUS_CODE_FIELD_LEN); + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < u2MinPayloadLen) { + DBGLOG(SAA, WARN, + "Rx Auth payload: len[%u] < min expected len[%u]\n", + (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen), + u2MinPayloadLen); + DBGLOG(SAA, WARN, "=== Dump Rx Auth ===\n"); + DBGLOG_MEM8(SAA, WARN, prAuthFrame, prSwRfb->u2PacketLen); + return WLAN_STATUS_SUCCESS; + } + + u2RxTransactionSeqNum = (prAuthFrame->aucAuthData[1] << 8) + + prAuthFrame->aucAuthData[0]; + + if ((u2RxTransactionSeqNum < 0) || (u2RxTransactionSeqNum > 4)) { + DBGLOG(SAA, WARN, + "RX auth with unexpected TransactionSeqNum:%d\n", + u2RxTransactionSeqNum); + return WLAN_STATUS_SUCCESS; + } + + if (prAuthFrame->u2AuthAlgNum == AUTH_ALGORITHM_NUM_SAE) { + if ((u2RxTransactionSeqNum == AUTH_TRANSACTION_SEQ_1) || + (u2RxTransactionSeqNum == AUTH_TRANSACTION_SEQ_2)) { + prStaRec = prSwRfb->prStaRec; + if (prStaRec) { + prBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, prStaRec->ucBssIndex); + } else { + prBssInfo = p2pFuncBSSIDFindBssInfo( + prAdapter, prAuthFrame->aucBSSID); + } + + if (prBssInfo == NULL) { + return WLAN_STATUS_SUCCESS; + } + + if (prBssInfo->eCurrentOPMode == + OP_MODE_INFRASTRUCTURE) { + saaFsmRunEventRxAuth(prAdapter, prSwRfb); + } else if (prBssInfo->eCurrentOPMode == + OP_MODE_ACCESS_POINT) { + aaaFsmRunEventRxAuth(prAdapter, prSwRfb); + } else { + DBGLOG(SAA, WARN, + "Don't support SAE for non-AIS/P2P network\n"); + } + } else { + DBGLOG(SAA, WARN, + "RX SAE auth with unexpected TransSeqNum:%d\n", + u2RxTransactionSeqNum); + } + } else { + switch (u2RxTransactionSeqNum) { + case AUTH_TRANSACTION_SEQ_2: + case AUTH_TRANSACTION_SEQ_4: + saaFsmRunEventRxAuth(prAdapter, prSwRfb); + break; + case AUTH_TRANSACTION_SEQ_1: + case AUTH_TRANSACTION_SEQ_3: + aaaFsmRunEventRxAuth(prAdapter, prSwRfb); + break; + default: + DBGLOG(SAA, WARN, + "Strange Authentication Packet: Auth Trans Seq No = %d\n", + u2RxTransactionSeqNum); + } + } + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will validate the incoming Authentication Frame and take + * the status code out. + * + * @param[in] prSwRfb Pointer to SW RFB data structure. + * @param[in] u2TransactionSeqNum Transaction Sequence Number + * @param[out] pu2StatusCode Pointer to store the Status Code from + * Authentication. + * + * @retval WLAN_STATUS_FAILURE This is not the frame we should handle at + * current state. + * @retval WLAN_STATUS_SUCCESS This is the frame we should handle. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authCheckRxAuthFrameStatus(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + IN u16 u2TransactionSeqNum, + OUT u16 *pu2StatusCode) +{ + P_STA_RECORD_T prStaRec; + P_WLAN_AUTH_FRAME_T prAuthFrame; + u16 u2RxAuthAlgNum; + u16 u2RxTransactionSeqNum; + /* u16 u2RxStatusCode; // NOTE(Kevin): Optimized for ARM */ + + ASSERT(prSwRfb); + ASSERT(pu2StatusCode); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if (!prStaRec) { + return WLAN_STATUS_INVALID_PACKET; + } + + /* 4 <1> locate the Authentication Frame. */ + prAuthFrame = (P_WLAN_AUTH_FRAME_T)prSwRfb->pvHeader; + + /* 4 <2> Parse the Fixed Fields of Authentication Frame Body. */ + /* WLAN_GET_FIELD_16(&prAuthFrame->u2AuthAlgNum, &u2RxAuthAlgNum); */ + u2RxAuthAlgNum = prAuthFrame->u2AuthAlgNum; /* NOTE(Kevin): Optimized + for ARM */ + if (u2RxAuthAlgNum != (u16)prStaRec->ucAuthAlgNum) { + DBGLOG(SAA, LOUD, + "Discard Auth frame with auth type = %d, current = %d\n", + u2RxAuthAlgNum, prStaRec->ucAuthAlgNum); + return WLAN_STATUS_FAILURE; + } + + u2RxTransactionSeqNum = (prAuthFrame->aucAuthData[1] << 8) + + prAuthFrame->aucAuthData[0]; + /* Still report to upper layer to let it do the error handling */ + if (u2RxTransactionSeqNum < u2TransactionSeqNum) { + DBGLOG(SAA, WARN, + "Rx Auth frame with unexpected Transaction Seq No = %d\n", + u2RxTransactionSeqNum); + } + + *pu2StatusCode = (prAuthFrame->aucAuthData[3] << 8) + + prAuthFrame->aucAuthData[2]; + + DBGLOG(SAA, INFO, + "Rx Auth frame with auth type = %d, SN = %d, Status Code = %d\n", + u2RxAuthAlgNum, u2RxTransactionSeqNum, *pu2StatusCode); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will handle the Challenge Text IE from the + * Authentication frame + * + * @param[in] prSwRfb Pointer to SW RFB data structure. + * @param[in] prIEHdr Pointer to start address of IE + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void authHandleIEChallengeText(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, + P_IE_HDR_T prIEHdr) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + P_STA_RECORD_T prStaRec; + u16 u2TransactionSeqNum; + + ASSERT(prSwRfb); + ASSERT(prIEHdr); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if (!prStaRec) { + return; + } + + /* For Management, frame header and payload are in a continuous buffer + */ + prAuthFrame = (P_WLAN_AUTH_FRAME_T)prSwRfb->pvHeader; + + u2TransactionSeqNum = (prAuthFrame->aucAuthData[1] << 8) + + prAuthFrame->aucAuthData[0]; + + /* Only consider SEQ_2 for Challenge Text */ + if ((u2TransactionSeqNum == AUTH_TRANSACTION_SEQ_2) && + (prStaRec->ucAuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY)) { + /* Free previous allocated TCM memory */ + if (prStaRec->prChallengeText) { + /* ASSERT(0); */ + cnmMemFree(prAdapter, prStaRec->prChallengeText); + prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T)NULL; + } + prStaRec->prChallengeText = + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, IE_SIZE(prIEHdr)); + if (prStaRec->prChallengeText == NULL) { + return; + } + + /* Save the Challenge Text from Auth Seq 2 Frame, before sending + * Auth Seq 3 Frame */ + COPY_IE(prStaRec->prChallengeText, prIEHdr); + } + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will parse and process the incoming Authentication + * frame. + * + * @param[in] prSwRfb Pointer to SW RFB data structure. + * + * @retval WLAN_STATUS_SUCCESS This is the frame we should handle. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS authProcessRxAuth2_Auth4Frame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + u8 *pucIEsBuffer; + u16 u2IEsLen; + u16 u2Offset; + u8 ucIEID; + u32 i; + + ASSERT(prSwRfb); + + prAuthFrame = (P_WLAN_AUTH_FRAME_T)prSwRfb->pvHeader; + pucIEsBuffer = (u8 *)&prAuthFrame->aucAuthData[0] + 4; + + u2IEsLen = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (AUTH_ALGORITHM_NUM_FIELD_LEN + + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN + + STATUS_CODE_FIELD_LEN); + + IE_FOR_EACH(pucIEsBuffer, u2IEsLen, u2Offset){ + ucIEID = IE_ID(pucIEsBuffer); + + for (i = 0; + i < (sizeof(rxAuthIETable) / sizeof(HANDLE_IE_ENTRY_T)); + i++) { + if ((ucIEID == rxAuthIETable[i].ucElemID) && + (rxAuthIETable[i].pfnHandleIE != NULL)) { + rxAuthIETable[i].pfnHandleIE( + prAdapter, prSwRfb, + (P_IE_HDR_T)pucIEsBuffer); + } + } + } + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will compose the Deauthentication frame + * + * @param[in] pucBuffer Pointer to the frame buffer. + * @param[in] aucPeerMACAddress Given Peer MAC Address. + * @param[in] aucMACAddress Given Our MAC Address. + * @param[in] u2StatusCode Status Code + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +static __KAL_INLINE__ void +authComposeDeauthFrameHeaderAndFF(IN u8 *pucBuffer, + IN u8 aucPeerMACAddress[], + IN u8 aucMACAddress[], IN u8 aucBssid[], + IN u16 u2ReasonCode) +{ + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; + u16 u2FrameCtrl; + + ASSERT(pucBuffer); + ASSERT(aucPeerMACAddress); + ASSERT(aucMACAddress); + ASSERT(aucBssid); + + prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T)pucBuffer; + + /* 4 <1> Compose the frame header of the Deauthentication frame. */ + /* Fill the Frame Control field. */ + u2FrameCtrl = MAC_FRAME_DEAUTH; + + /* WLAN_SET_FIELD_16(&prDeauthFrame->u2FrameCtrl, u2FrameCtrl); */ + prDeauthFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for + ARM */ + + /* Fill the DA field with Target BSSID. */ + COPY_MAC_ADDR(prDeauthFrame->aucDestAddr, aucPeerMACAddress); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prDeauthFrame->aucSrcAddr, aucMACAddress); + + /* Fill the BSSID field with Target BSSID. */ + COPY_MAC_ADDR(prDeauthFrame->aucBSSID, aucBssid); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need + * to clear it). */ + prDeauthFrame->u2SeqCtrl = 0; + + /* 4 <2> Compose the frame body's fixed field part of the Authentication + * frame. */ + /* Fill the Status Code field. */ + /* WLAN_SET_FIELD_16(&prDeauthFrame->u2ReasonCode, u2ReasonCode); */ + prDeauthFrame->u2ReasonCode = u2ReasonCode; /* NOTE(Kevin): Optimized + for ARM */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will send the Deauthenticiation frame + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] prClassErrSwRfb Pointer to the SW_RFB_T which is Class Error. + * @param[in] u2ReasonCode A reason code to indicate why to leave BSS. + * @param[in] pfTxDoneHandler TX Done call back function + * + * @retval WLAN_STATUS_RESOURCES No available resource for frame composing. + * @retval WLAN_STATUS_SUCCESS Successfully send frame to TX Module + * @retval WLAN_STATUS_FAILURE Didn't send Deauth frame for various reasons. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authSendDeauthFrame(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prClassErrSwRfb, + IN u16 u2ReasonCode, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler) +{ + u8 *pucReceiveAddr; + u8 *pucTransmitAddr; + u8 *pucBssid = NULL; + P_MSDU_INFO_T prMsduInfo; + u16 u2EstimatedFrameLen; + u8 ucRoleIdx = 0; + u8 fgIsInterruptContext = false; + u8 *pFrameBuf; + P_DEAUTH_INFO_T prDeauthInfo; + u32 rCurrentTime; + s32 i4NewEntryIndex, i; + u8 ucStaRecIdx = STA_REC_INDEX_NOT_FOUND; + u8 ucBssIndex = BSS_INFO_NUM; + u8 aucBMC[] = BC_MAC_ADDR; + + DBGLOG(RSN, INFO, "authSendDeauthFrame\n"); + + /* NOTE(Kevin): The best way to reply the Deauth is according to the + * incoming data frame + */ + /* 4 <1.1> Find the Receiver Address */ + if (prClassErrSwRfb) { + u8 fgIsAbleToSendDeauth = false; + u16 u2RxFrameCtrl; + P_WLAN_MAC_HEADER_A4_T prWlanMacHeader = NULL; + + prWlanMacHeader = + (P_WLAN_MAC_HEADER_A4_T)prClassErrSwRfb->pvHeader; + + /* WLAN_GET_FIELD_16(&prWlanMacHeader->u2FrameCtrl, + * &u2RxFrameCtrl); */ + u2RxFrameCtrl = prWlanMacHeader->u2FrameCtrl; /* NOTE(Kevin): + Optimized for + ARM */ + + /* TODO(Kevin): Currently we won't send Deauth for IBSS node. + * How about DLS ? */ + if ((prWlanMacHeader->u2FrameCtrl & MASK_TO_DS_FROM_DS) == 0) { + return WLAN_STATUS_FAILURE; + } + + /* Check if corresponding BSS is able to send Deauth */ + for (i = 0; i < BSS_INFO_NUM; i++) { + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, i); + + if (IS_NET_ACTIVE(prAdapter, i) && + (EQUAL_MAC_ADDR(prWlanMacHeader->aucAddr1, + prBssInfo->aucOwnMacAddr))) { + fgIsAbleToSendDeauth = true; + ucBssIndex = (u8)i; + break; + } + } + + if (!fgIsAbleToSendDeauth) { + return WLAN_STATUS_FAILURE; + } + + pucReceiveAddr = prWlanMacHeader->aucAddr2; + } else if (prStaRec) { + prBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + ucStaRecIdx = prStaRec->ucIndex; + ucBssIndex = prBssInfo->ucBssIndex; + + pucReceiveAddr = prStaRec->aucMacAddr; + } else if (prBssInfo) { + ucBssIndex = prBssInfo->ucBssIndex; + ucStaRecIdx = STA_REC_INDEX_BMCAST; + + pucReceiveAddr = aucBMC; + } else { + DBGLOG(SAA, WARN, "Not to send Deauth, invalid data!\n"); + return WLAN_STATUS_INVALID_DATA; + } + + /* 4 <1.2> Find Transmitter Address and BSSID. */ + pucTransmitAddr = prBssInfo->aucOwnMacAddr; + pucBssid = prBssInfo->aucBSSID; + + if (ucStaRecIdx != STA_REC_INDEX_BMCAST) { + /* 4 <2> Check if already send a Deauth frame in + * MIN_DEAUTH_INTERVAL_MSEC */ + GET_CURRENT_SYSTIME(&rCurrentTime); + + i4NewEntryIndex = -1; + for (i = 0; i < MAX_DEAUTH_INFO_COUNT; i++) { + prDeauthInfo = &(prAdapter->rWifiVar.arDeauthInfo[i]); + + /* For continuously sending Deauth frame, the minimum + * interval is MIN_DEAUTH_INTERVAL_MSEC. + */ + if (CHECK_FOR_TIMEOUT( + rCurrentTime, prDeauthInfo->rLastSendTime, + MSEC_TO_SYSTIME(MIN_DEAUTH_INTERVAL_MSEC))) { + i4NewEntryIndex = i; + } else if (EQUAL_MAC_ADDR(pucReceiveAddr, + prDeauthInfo->aucRxAddr) && + (!pfTxDoneHandler)) { + return WLAN_STATUS_FAILURE; + } + } + + /* 4 <3> Update information. */ + if (i4NewEntryIndex > 0) { + prDeauthInfo = + &(prAdapter->rWifiVar + .arDeauthInfo[i4NewEntryIndex]); + + COPY_MAC_ADDR(prDeauthInfo->aucRxAddr, pucReceiveAddr); + prDeauthInfo->rLastSendTime = rCurrentTime; + } else { + /* NOTE(Kevin): for the case of AP mode, we may + * encounter this case if deauth all the associated + * clients. + */ + DBGLOG(SAA, WARN, "No unused DEAUTH_INFO_T !\n"); + } + } + /* 4 <5> Allocate a PKT_INFO_T for Deauthentication Frame */ + /* Init with MGMT Header Length + Length of Fixed Fields + IE Length */ + u2EstimatedFrameLen = + (MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + + REASON_CODE_FIELD_LEN); + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(SAA, WARN, + "No PKT_INFO_T for sending Deauth Request.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <6> compose Deauthentication frame header and some fixed fields */ + authComposeDeauthFrameHeaderAndFF( + (u8 *)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD), + pucReceiveAddr, pucTransmitAddr, pucBssid, u2ReasonCode); + +#if CFG_SUPPORT_802_11W + /* AP PMF */ + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + /* PMF certification 4.3.3.1, 4.3.3.2 send unprotected deauth + * reason 6/7 */ + /* if (AP mode & not for PMF reply case) OR (STA PMF) */ + if (((GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex) + ->eCurrentOPMode == OP_MODE_ACCESS_POINT) && + (prStaRec->rPmfCfg.fgRxDeauthResp != true)) || + (GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex) + ->eNetworkType == (u8)NETWORK_TYPE_AIS)) { + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; + + prDeauthFrame = + (P_WLAN_DEAUTH_FRAME_T)(u8 *)((unsigned long)(prMsduInfo + ->prPacket) + + MAC_TX_RESERVED_FIELD); + + prDeauthFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + } + } +#endif + nicTxSetPktLifeTime(prMsduInfo, 100); + + if (pfTxDoneHandler) { + nicTxSetPktRetryLimit(prMsduInfo, TX_DESC_TX_COUNT_NO_LIMIT); + }else{ + nicTxSetPktRetryLimit(prMsduInfo, 5); + } + + /* 4 <7> Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, ucBssIndex, ucStaRecIdx, + WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + REASON_CODE_FIELD_LEN, + pfTxDoneHandler, MSDU_RATE_MODE_AUTO); + +#if CFG_SUPPORT_802_11W + /* AP PMF */ + /* caution: access prStaRec only if true */ + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + /* 4.3.3.1 send unprotected deauth reason 6/7 */ + if (prStaRec->rPmfCfg.fgRxDeauthResp != true) { + DBGLOG(RSN, INFO, + "Deauth Set MSDU_OPT_PROTECTED_FRAME\n"); + nicTxConfigPktOption(prMsduInfo, + MSDU_OPT_PROTECTED_FRAME, true); + } + + prStaRec->rPmfCfg.fgRxDeauthResp = false; + } +#endif + + { + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; + prDeauthFrame = + (P_WLAN_DEAUTH_FRAME_T)(u8 *)((unsigned long)(prMsduInfo + ->prPacket) + + MAC_TX_RESERVED_FIELD); + DBGLOG(SAA, INFO, "notification of TX deauthentication, %d\n", + prMsduInfo->u2FrameLength); + + /* + * check prStaRec is not NULL first + * prStaRec can be NULL if it is P2P GO + */ + if ((prStaRec) && (IS_STA_IN_AIS(prStaRec))) { + if (in_interrupt()) { + pFrameBuf = + kalMemAlloc(prMsduInfo->u2FrameLength, + PHY_MEM_TYPE); + fgIsInterruptContext = true; + } else { + pFrameBuf = + kalMemAlloc(prMsduInfo->u2FrameLength, + VIR_MEM_TYPE); + fgIsInterruptContext = false; + } + + if (!pFrameBuf) { + DBGLOG(SAA, ERROR, + "Alloc buffer for frame failed\n"); + return WLAN_STATUS_RESOURCES; + } + + kalMemCopy((void *)pFrameBuf, (void *)prDeauthFrame, + prMsduInfo->u2FrameLength); + + kalWDevLockThread(prAdapter->prGlueInfo, + prAdapter->prGlueInfo->prDevHandler, + CFG80211_TX_MLME_MGMT, pFrameBuf, + prMsduInfo->u2FrameLength, NULL, 0, + NULL, 0, fgIsInterruptContext); + } else if (prAdapter->fgIsP2PRegistered) { + ucRoleIdx = (u8)prBssInfo->u4PrivateData; + if (in_interrupt()) { + pFrameBuf = + kalMemAlloc(prMsduInfo->u2FrameLength, + PHY_MEM_TYPE); + fgIsInterruptContext = true; + } else { + pFrameBuf = + kalMemAlloc(prMsduInfo->u2FrameLength, + VIR_MEM_TYPE); + fgIsInterruptContext = false; + } + + if (!pFrameBuf) { + DBGLOG(SAA, ERROR, + "Alloc buffer for frame failed\n"); + return WLAN_STATUS_RESOURCES; + } + + kalMemCopy((void *)pFrameBuf, (void *)prDeauthFrame, + prMsduInfo->u2FrameLength); + kalWDevLockThread(prAdapter->prGlueInfo, + prAdapter->prGlueInfo + ->prP2PInfo[ucRoleIdx] + ->aprRoleHandler, + CFG80211_TX_MLME_MGMT, pFrameBuf, + prMsduInfo->u2FrameLength, NULL, 0, + NULL, 0, fgIsInterruptContext); + } else { + DBGLOG(SAA, INFO, + "notification of TX deauthentication, FAILED\n"); + } + DBGLOG(SAA, INFO, + "notification of TX deauthentication, Done\n"); + } + + nicTxConfigPktControlFlag(prMsduInfo, MSDU_CONTROL_FLAG_FORCE_TX, true); + + /* 4 <8> Inform TXM to send this Deauthentication frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will parse and process the incoming Deauthentication + * frame if the given BSSID is matched. + * + * @param[in] prSwRfb Pointer to SW RFB data structure. + * @param[in] aucBSSID Given BSSID + * @param[out] pu2ReasonCode Pointer to store the Reason Code from + * Deauthentication. + * + * @retval WLAN_STATUS_FAILURE This is not the frame we should handle at + * current state. + * @retval WLAN_STATUS_SUCCESS This is the frame we should handle. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS authProcessRxDeauthFrame(IN P_SW_RFB_T prSwRfb, + IN u8 aucBSSID[], + OUT u16 *pu2ReasonCode) +{ + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; + u16 u2RxReasonCode; + + if (!prSwRfb || !aucBSSID || !pu2ReasonCode) { + DBGLOG(SAA, WARN, "Invalid parameters, ignore this pkt!\n"); + return WLAN_STATUS_FAILURE; + } + + /* 4 <1> locate the Deauthentication Frame. */ + prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T)prSwRfb->pvHeader; + + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < + REASON_CODE_FIELD_LEN) { + DBGLOG(SAA, WARN, + "Invalid Deauth packet length. u2PacketLen(%u), u2HeaderLen(%u)\n", + prSwRfb->u2PacketLen, prSwRfb->u2HeaderLen); + return WLAN_STATUS_FAILURE; + } + + /* Check if this Deauth Frame is coming from Target BSSID */ + if (UNEQUAL_MAC_ADDR(prDeauthFrame->aucBSSID, aucBSSID)) { + DBGLOG(SAA, LOUD, + "Ignore Deauth Frame from other BSS [" MACSTR "]\n", + MAC2STR(prDeauthFrame->aucSrcAddr)); + return WLAN_STATUS_FAILURE; + } + /* 4 <3> Parse the Fixed Fields of Deauthentication Frame Body. */ + WLAN_GET_FIELD_16(&prDeauthFrame->u2ReasonCode, &u2RxReasonCode); + *pu2ReasonCode = u2RxReasonCode; + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will parse and process the incoming Authentication + * frame. + * + * @param[in] prSwRfb Pointer to SW RFB data structure. + * @param[in] aucExpectedBSSID Given Expected BSSID. + * @param[in] u2ExpectedAuthAlgNum Given Expected Authentication Algorithm + * Number + * @param[in] u2ExpectedTransSeqNum Given Expected Transaction Sequence Number. + * @param[out] pu2ReturnStatusCode Return Status Code. + * + * @retval WLAN_STATUS_SUCCESS This is the frame we should handle. + * @retval WLAN_STATUS_FAILURE The frame we will ignore. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +authProcessRxAuth1Frame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + IN u8 aucExpectedBSSID[], + IN u16 u2ExpectedAuthAlgNum, + IN u16 u2ExpectedTransSeqNum, + OUT u16 *pu2ReturnStatusCode) +{ + P_WLAN_AUTH_FRAME_T prAuthFrame; + u16 u2RxStatusCode; + u16 u2ReturnStatusCode = STATUS_CODE_SUCCESSFUL; + + ASSERT(prSwRfb); + ASSERT(aucExpectedBSSID); + ASSERT(pu2ReturnStatusCode); + + /* 4 <1> locate the Authentication Frame. */ + prAuthFrame = (P_WLAN_AUTH_FRAME_T)prSwRfb->pvHeader; + + /* 4 <2> Check the BSSID */ + if (UNEQUAL_MAC_ADDR(prAuthFrame->aucBSSID, aucExpectedBSSID)) { + return WLAN_STATUS_FAILURE; /* Just Ignore this MMPDU */ + + } + /* 4 <3> Check the SA, which should not be MC/BC */ + if (prAuthFrame->aucSrcAddr[0] & BIT(0)) { + DBGLOG(P2P, WARN, + "Invalid STA MAC with MC/BC bit set: " MACSTR "\n", + MAC2STR(prAuthFrame->aucSrcAddr)); + return WLAN_STATUS_FAILURE; + } + + /* 4 <4> Parse the Fixed Fields of Authentication Frame Body. */ + u2RxStatusCode = (prAuthFrame->aucAuthData[3] << 8) + + prAuthFrame->aucAuthData[2]; + + if (u2RxStatusCode != STATUS_CODE_RESERVED) { + DBGLOG(AAA, LOUD, "Invalid Status code %d\n", u2RxStatusCode); + return WLAN_STATUS_FAILURE; + } + + if (prAuthFrame->u2AuthAlgNum != u2ExpectedAuthAlgNum) { + u2ReturnStatusCode = STATUS_CODE_AUTH_ALGORITHM_NOT_SUPPORTED; + } + + if (prAuthFrame->aucAuthData[0] != u2ExpectedTransSeqNum) { + u2ReturnStatusCode = STATUS_CODE_AUTH_OUT_OF_SEQ; + } + + *pu2ReturnStatusCode = u2ReturnStatusCode; + return WLAN_STATUS_SUCCESS; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/bss.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/bss.c new file mode 100644 index 00000000000000..ec240b7faf10f7 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/bss.c @@ -0,0 +1,2106 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "bss.c" + * \brief This file contains the functions for creating BSS(AP)/IBSS(AdHoc). + * + * This file contains the functions for BSS(AP)/IBSS(AdHoc). We may create a + * BSS/IBSS network, or merge with exist IBSS network and sending Beacon Frame + * or reply the Probe Response Frame for received Probe Request Frame. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +const u8 *apucNetworkType[NETWORK_TYPE_NUM] = { (u8 *)"AIS", (u8 *)"P2P", + (u8 *)"BOW", (u8 *)"MBSS" }; + +const u8 *apucNetworkOpMode[] = { (u8 *)"INFRASTRUCTURE", (u8 *)"IBSS", + (u8 *)"ACCESS_POINT", (u8 *)"P2P_DEVICE", + (u8 *)"BOW" }; + +#if (CFG_SUPPORT_ADHOC) || (CFG_SUPPORT_AAA) +APPEND_VAR_IE_ENTRY_T txBcnIETable[] = { + { (ELEM_HDR_LEN + (RATE_NUM_SW - ELEM_MAX_LEN_SUP_RATES)), NULL, + bssGenerateExtSuppRate_IE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE } +#if CFG_ENABLE_WIFI_DIRECT + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, + rlmRspGenerateObssScanIE } +#endif + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE } +#if CFG_ENABLE_WIFI_DIRECT + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWPAIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE }, + { 0, p2pFuncCalculateP2p_IELenForBeacon, + p2pFuncGenerateP2p_IEForBeacon }, + { 0, p2pFuncCalculateWSC_IELenForBeacon, + p2pFuncGenerateWSC_IEForBeacon }, + { 0, p2pFuncCalculateP2P_IE_NoA, p2pFuncGenerateP2P_IE_NoA } +#endif +#if CFG_SUPPORT_802_11AC + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_CAP), NULL, + rlmRspGenerateVhtCapIE } /*191 */ + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_OP), NULL, + rlmRspGenerateVhtOpIE } /*192 */ + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_OP_MODE_NOTIFICATION), NULL, + rlmRspGenerateVhtOpNotificationIE } /*199 */ +#endif +#if CFG_SUPPORT_MTK_SYNERGY + , + { (ELEM_HDR_LEN + ELEM_MIN_LEN_MTK_OUI), NULL, rlmGenerateMTKOuiIE } +#endif +#if (CFG_SUPPORT_DFS_MASTER == 1) + , + { (ELEM_HDR_LEN + ELEM_MIN_LEN_CSA), NULL, rlmGenerateCsaIE } +#endif +}; + +APPEND_VAR_IE_ENTRY_T txProbRspIETable[] = { + { (ELEM_HDR_LEN + (RATE_NUM_SW - ELEM_MAX_LEN_SUP_RATES)), NULL, + bssGenerateExtSuppRate_IE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE } +#if CFG_ENABLE_WIFI_DIRECT + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, + rlmRspGenerateObssScanIE } +#endif + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE } +#if CFG_SUPPORT_802_11AC + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_CAP), NULL, + rlmRspGenerateVhtCapIE } /*191 */ + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_OP), NULL, + rlmRspGenerateVhtOpIE } /*192 */ + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_OP_MODE_NOTIFICATION), NULL, + rlmRspGenerateVhtOpNotificationIE } /*199 */ +#endif +#if CFG_SUPPORT_MTK_SYNERGY + , + { (ELEM_HDR_LEN + ELEM_MIN_LEN_MTK_OUI), NULL, rlmGenerateMTKOuiIE } +#endif +}; + +#endif + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Routines for all Operation Modes */ +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will decide PHY type set of STA_RECORD_T by given + * BSS_DESC_T for Infrastructure or AdHoc Mode. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prBssDesc Received Beacon/ProbeResp from this STA + * @param[out] prStaRec StaRec to be decided PHY type set + * + * @retval void + */ +/*----------------------------------------------------------------------------*/ +void bssDetermineStaRecPhyTypeSet(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + OUT P_STA_RECORD_T prStaRec) +{ + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; + u8 ucHtOption = FEATURE_ENABLED; + u8 ucVhtOption = FEATURE_ENABLED; + + prStaRec->ucPhyTypeSet = prBssDesc->ucPhyTypeSet; +#if CFG_SUPPORT_BFEE + prStaRec->ucVhtCapNumSoundingDimensions = + prBssDesc->ucVhtCapNumSoundingDimensions; +#endif + + /* Decide AIS PHY type set */ + if (prStaRec->eStaType == STA_TYPE_LEGACY_AP) { + if (!((prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION3_ENABLED) || + (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION3_KEY_ABSENT) || + (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION_DISABLED) || + (prAdapter->prGlueInfo->u2WSCAssocInfoIELen))) { + DBGLOG(BSS, + INFO, + "Ignore the HT Bit for TKIP as pairwise cipher configed!\n"); + prStaRec->ucPhyTypeSet &= + ~(PHY_TYPE_BIT_HT | PHY_TYPE_BIT_VHT); + } + + ucHtOption = prWifiVar->ucStaHt; + ucVhtOption = prWifiVar->ucStaVht; + } + /* Decide P2P GC PHY type set */ + else if (prStaRec->eStaType == STA_TYPE_P2P_GO) { + ucHtOption = prWifiVar->ucP2pGcHt; + ucVhtOption = prWifiVar->ucP2pGcVht; + } + + /* Set HT/VHT capability from Feature Option */ + if (IS_FEATURE_DISABLED(ucHtOption)) { + prStaRec->ucPhyTypeSet &= ~PHY_TYPE_BIT_HT; + }else if (IS_FEATURE_FORCE_ENABLED(ucHtOption)) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + } + + if (IS_FEATURE_DISABLED(ucVhtOption)) { + prStaRec->ucPhyTypeSet &= ~PHY_TYPE_BIT_VHT; + }else if (IS_FEATURE_FORCE_ENABLED(ucVhtOption)) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_VHT; + } + + prStaRec->ucDesiredPhyTypeSet = + prStaRec->ucPhyTypeSet & + prAdapter->rWifiVar.ucAvailablePhyTypeSet; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will decide PHY type set of BSS_INFO for + * AP Mode. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] fgIsApMode Legacy AP mode or P2P GO + * @param[out] prBssInfo BssInfo to be decided PHY type set + * + * @retval void + */ +/*----------------------------------------------------------------------------*/ +void bssDetermineApBssInfoPhyTypeSet(IN P_ADAPTER_T prAdapter, IN u8 fgIsPureAp, + OUT P_BSS_INFO_T prBssInfo) +{ + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; + u8 ucHtOption = FEATURE_ENABLED; + u8 ucVhtOption = FEATURE_ENABLED; + + /* Decide AP mode PHY type set */ + if (fgIsPureAp) { + ucHtOption = prWifiVar->ucApHt; + ucVhtOption = prWifiVar->ucApVht; + } + /* Decide P2P GO PHY type set */ + else { + ucHtOption = prWifiVar->ucP2pGoHt; + ucVhtOption = prWifiVar->ucP2pGoVht; + } + + /* Set HT/VHT capability from Feature Option */ + if (IS_FEATURE_DISABLED(ucHtOption)) { + prBssInfo->ucPhyTypeSet &= ~PHY_TYPE_BIT_HT; + }else if (IS_FEATURE_ENABLED(ucHtOption)) { + prBssInfo->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + } + + if (IS_FEATURE_DISABLED(ucVhtOption)) { + prBssInfo->ucPhyTypeSet &= ~PHY_TYPE_BIT_VHT; + } else if (IS_FEATURE_FORCE_ENABLED(ucVhtOption) || + (IS_FEATURE_ENABLED(ucVhtOption) && + (prBssInfo->eBand == BAND_5G))) { + /* Enable HT capability if VHT is enabled */ + prBssInfo->ucPhyTypeSet |= PHY_TYPE_BIT_VHT; + } + + prBssInfo->ucPhyTypeSet &= prAdapter->rWifiVar.ucAvailablePhyTypeSet; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will create or reset a STA_RECORD_T by given BSS_DESC_T + * for Infrastructure or AdHoc Mode. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] eStaType Assign STA Type for this STA_RECORD_T + * @param[in] eNetTypeIndex Assign Net Type Index for this STA_RECORD_T + * @param[in] prBssDesc Received Beacon/ProbeResp from this STA + * + * @retval Pointer to STA_RECORD_T + */ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T +bssCreateStaRecFromBssDesc(IN P_ADAPTER_T prAdapter, + IN ENUM_STA_TYPE_T eStaType, IN u8 ucBssIndex, + IN P_BSS_DESC_T prBssDesc) +{ + P_STA_RECORD_T prStaRec; + u8 ucNonHTPhyTypeSet; + P_CONNECTION_SETTINGS_T prConnSettings; + + ASSERT(prBssDesc); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* 4 <1> Get a valid STA_RECORD_T */ + prStaRec = cnmGetStaRecByAddress(prAdapter, ucBssIndex, + prBssDesc->aucSrcAddr); + if (!prStaRec) { + prStaRec = cnmStaRecAlloc(prAdapter, eStaType, ucBssIndex, + prBssDesc->aucSrcAddr); + + if (!prStaRec) { + DBGLOG(BSS, + WARN, + "STA_REC entry is full, cannot acquire new entry for [" + MACSTR + "]!!\n", + MAC2STR(prBssDesc->aucSrcAddr)); + ASSERT(false); + return NULL; + } + + prStaRec->ucStaState = STA_STATE_1; + prStaRec->ucJoinFailureCount = 0; + /* TODO(Kevin): If this is an old entry, we may also reset the + * ucJoinFailureCount to 0. */ + } + /* 4 <2> Update information from BSS_DESC_T to current P_STA_RECORD_T */ + prStaRec->u2CapInfo = prBssDesc->u2CapInfo; + + prStaRec->u2OperationalRateSet = prBssDesc->u2OperationalRateSet; + prStaRec->u2BSSBasicRateSet = prBssDesc->u2BSSBasicRateSet; + + bssDetermineStaRecPhyTypeSet(prAdapter, prBssDesc, prStaRec); + + ucNonHTPhyTypeSet = prStaRec->ucDesiredPhyTypeSet & + PHY_TYPE_SET_802_11ABG; + + /* Check for Target BSS's non HT Phy Types */ + if (ucNonHTPhyTypeSet) { + if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_ERP) { + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_ERP_INDEX; + } else if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_OFDM) { + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_OFDM_INDEX; + } else { /* if (ucNonHTPhyTypeSet & PHY_TYPE_HR_DSSS_INDEX) */ + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; + } + + prStaRec->fgHasBasicPhyType = true; + } else { + /* Use mandatory for 11N only BSS */ + ASSERT(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N); + + { + /* TODO(Kevin): which value should we set for 11n ? ERP + * ? */ + prStaRec->ucNonHTBasicPhyType = PHY_TYPE_HR_DSSS_INDEX; + } + + prStaRec->fgHasBasicPhyType = false; + } + + /* Update non HT Desired Rate Set */ + prStaRec->u2DesiredNonHTRateSet = + (prStaRec->u2OperationalRateSet & + prConnSettings->u2DesiredNonHTRateSet); + + /* 4 <3> Update information from BSS_DESC_T to current P_STA_RECORD_T */ + if (IS_AP_STA(prStaRec)) { + /* do not need to parse IE for DTIM, + * which have been parsed before inserting into BSS_DESC_T + */ + if (prBssDesc->ucDTIMPeriod) { + prStaRec->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; + } else { + prStaRec->ucDTIMPeriod = 0; /* Means that TIM was not + * parsed. */ + } + } + /* 4 <4> Update default value */ + prStaRec->fgDiagnoseConnection = false; + + /* 4 <5> Update default value for other Modules */ + /* Determine WMM related parameters for STA_REC */ + mqmProcessScanResult(prAdapter, prBssDesc, prStaRec); + + /* 4 <6> Update Tx Rate */ + /* Update default Tx rate */ + nicTxUpdateStaRecDefaultRate(prStaRec); + + return prStaRec; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will compose the Null Data frame. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] pucBuffer Pointer to the frame buffer. + * @param[in] prStaRec Pointer to the STA_RECORD_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void bssComposeNullFrame(IN P_ADAPTER_T prAdapter, IN u8 *pucBuffer, + IN P_STA_RECORD_T prStaRec) +{ + P_WLAN_MAC_HEADER_T prNullFrame; + P_BSS_INFO_T prBssInfo; + u16 u2FrameCtrl; + u8 ucBssIndex; + + ASSERT(prStaRec); + ucBssIndex = prStaRec->ucBssIndex; + + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + + ASSERT(pucBuffer); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + ASSERT(prBssInfo); + + prNullFrame = (P_WLAN_MAC_HEADER_T)pucBuffer; + + /* 4 <1> Decide the Frame Control Field */ + u2FrameCtrl = MAC_FRAME_NULL; + + if (IS_AP_STA(prStaRec)) { + u2FrameCtrl |= MASK_FC_TO_DS; + + if (prStaRec->fgSetPwrMgtBit) { + u2FrameCtrl |= MASK_FC_PWR_MGT; + } + } else if (IS_CLIENT_STA(prStaRec)) { + u2FrameCtrl |= MASK_FC_FROM_DS; + } else if (IS_DLS_STA(prStaRec)) { + /* TODO(Kevin) */ + } else { + /* NOTE(Kevin): We won't send Null frame for IBSS */ + ASSERT(0); + return; + } + + /* 4 <2> Compose the Null frame */ + /* Fill the Frame Control field. */ + /* WLAN_SET_FIELD_16(&prNullFrame->u2FrameCtrl, u2FrameCtrl); */ + prNullFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for + * ARM */ + + /* Fill the Address 1 field with Target Peer Address. */ + COPY_MAC_ADDR(prNullFrame->aucAddr1, prStaRec->aucMacAddr); + + /* Fill the Address 2 field with our MAC Address. */ + COPY_MAC_ADDR(prNullFrame->aucAddr2, prBssInfo->aucOwnMacAddr); + + /* Fill the Address 3 field with Target BSSID. */ + COPY_MAC_ADDR(prNullFrame->aucAddr3, prBssInfo->aucBSSID); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need + * to clear it). */ + prNullFrame->u2SeqCtrl = 0; + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will compose the QoS Null Data frame. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] pucBuffer Pointer to the frame buffer. + * @param[in] prStaRec Pointer to the STA_RECORD_T. + * @param[in] ucUP User Priority. + * @param[in] fgSetEOSP Set the EOSP bit. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void bssComposeQoSNullFrame(IN P_ADAPTER_T prAdapter, IN u8 *pucBuffer, + IN P_STA_RECORD_T prStaRec, IN u8 ucUP, + IN u8 fgSetEOSP) +{ + P_WLAN_MAC_HEADER_QOS_T prQoSNullFrame; + P_BSS_INFO_T prBssInfo; + u16 u2FrameCtrl; + u16 u2QosControl; + u8 ucBssIndex; + + ASSERT(prStaRec); + ucBssIndex = prStaRec->ucBssIndex; + + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + + ASSERT(pucBuffer); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + ASSERT(prBssInfo); + + prQoSNullFrame = (P_WLAN_MAC_HEADER_QOS_T)pucBuffer; + + /* 4 <1> Decide the Frame Control Field */ + u2FrameCtrl = MAC_FRAME_QOS_NULL; + + if (IS_AP_STA(prStaRec)) { + u2FrameCtrl |= MASK_FC_TO_DS; + + if (prStaRec->fgSetPwrMgtBit) { + u2FrameCtrl |= MASK_FC_PWR_MGT; + } + } else if (IS_CLIENT_STA(prStaRec)) { + u2FrameCtrl |= MASK_FC_FROM_DS; + } else if (IS_DLS_STA(prStaRec)) { + /* TODO(Kevin) */ + } else { + /* NOTE(Kevin): We won't send QoS Null frame for IBSS */ + ASSERT(0); + return; + } + + /* 4 <2> Compose the QoS Null frame */ + /* Fill the Frame Control field. */ + /* WLAN_SET_FIELD_16(&prQoSNullFrame->u2FrameCtrl, u2FrameCtrl); */ + prQoSNullFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized for + * ARM */ + + /* Fill the Address 1 field with Target Peer Address. */ + COPY_MAC_ADDR(prQoSNullFrame->aucAddr1, prStaRec->aucMacAddr); + + /* Fill the Address 2 field with our MAC Address. */ + COPY_MAC_ADDR(prQoSNullFrame->aucAddr2, prBssInfo->aucOwnMacAddr); + + /* Fill the Address 3 field with Target BSSID. */ + COPY_MAC_ADDR(prQoSNullFrame->aucAddr3, prBssInfo->aucBSSID); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need + * to clear it). */ + prQoSNullFrame->u2SeqCtrl = 0; + + u2QosControl = (u16)(ucUP & WMM_QC_UP_MASK); + + if (fgSetEOSP) { + u2QosControl |= WMM_QC_EOSP; + } + + /* WLAN_SET_FIELD_16(&prQoSNullFrame->u2QosCtrl, u2QosControl); */ + prQoSNullFrame->u2QosCtrl = u2QosControl; /* NOTE(Kevin): Optimized for + * ARM */ + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Send the Null Frame + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] pfTxDoneHandler TX Done call back function + * + * @retval WLAN_STATUS_RESOURCE No available resources to send frame. + * @retval WLAN_STATUS_SUCCESS Succe]ss. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bssSendNullFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler) +{ + P_MSDU_INFO_T prMsduInfo; + u16 u2EstimatedFrameLen; + + /* 4 <1> Allocate a PKT_INFO_T for Null Frame */ + /* Init with MGMT Header Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_LEN; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(BSS, WARN, "No PKT_INFO_T for sending Null Frame.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose Null frame in MSDU_INfO_T. */ + bssComposeNullFrame(prAdapter, + (u8 *)((unsigned long)prMsduInfo->prPacket + + MAC_TX_RESERVED_FIELD), + prStaRec); + + TX_SET_MMPDU(prAdapter, prMsduInfo, prStaRec->ucBssIndex, + prStaRec->ucIndex, WLAN_MAC_HEADER_LEN, + WLAN_MAC_HEADER_LEN, pfTxDoneHandler, MSDU_RATE_MODE_AUTO); + + /* 4 <4> Inform TXM to send this Null frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Send the QoS Null Frame + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] pfTxDoneHandler TX Done call back function + * + * @retval WLAN_STATUS_RESOURCE No available resources to send frame. + * @retval WLAN_STATUS_SUCCESS Success. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bssSendQoSNullFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, + IN u8 ucUP, IN PFN_TX_DONE_HANDLER pfTxDoneHandler) +{ + P_MSDU_INFO_T prMsduInfo; + u16 u2EstimatedFrameLen; + + /* 4 <1> Allocate a PKT_INFO_T for Null Frame */ + /* Init with MGMT Header Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_QOS_LEN; + + /* Allocate a MSDU_INFO_T */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(BSS, WARN, "No PKT_INFO_T for sending Null Frame.\n"); + return WLAN_STATUS_RESOURCES; + } + /* 4 <2> Compose Null frame in MSDU_INfO_T. */ + bssComposeQoSNullFrame(prAdapter, + (u8 *)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD), + prStaRec, ucUP, false); + + TX_SET_MMPDU(prAdapter, prMsduInfo, prStaRec->ucBssIndex, + prStaRec->ucIndex, WLAN_MAC_HEADER_QOS_LEN, + WLAN_MAC_HEADER_QOS_LEN, pfTxDoneHandler, + MSDU_RATE_MODE_AUTO); + + /* 4 <4> Inform TXM to send this Null frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} + +#if (CFG_SUPPORT_ADHOC) || (CFG_SUPPORT_AAA) +/*----------------------------------------------------------------------------*/ +/* Routines for both IBSS(AdHoc) and BSS(AP) */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to generate Information Elements of Extended + * Support Rate + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void bssGenerateExtSuppRate_IE(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + u8 *pucBuffer; + u8 ucExtSupRatesLen; + + ASSERT(prMsduInfo); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + ASSERT(prBssInfo); + + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + ASSERT(pucBuffer); + + if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) { + ucExtSupRatesLen = prBssInfo->ucAllSupportedRatesLen - + ELEM_MAX_LEN_SUP_RATES; + } else { + ucExtSupRatesLen = 0; + } + + /* Fill the Extended Supported Rates element. */ + if (ucExtSupRatesLen) { + EXT_SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_EXTENDED_SUP_RATES; + EXT_SUP_RATES_IE(pucBuffer)->ucLength = ucExtSupRatesLen; + + kalMemCopy( + EXT_SUP_RATES_IE(pucBuffer)->aucExtSupportedRates, + &prBssInfo->aucAllSupportedRates[ELEM_MAX_LEN_SUP_RATES], + ucExtSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to compose Common Information Elements for + * Beacon or Probe Response Frame. + * + * @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. + * @param[in] prBssInfo Pointer to the BSS_INFO_T. + * @param[in] pucDestAddr Pointer to the Destination Address, if NULL, means + * Beacon. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void bssBuildBeaconProbeRespFrameCommonIEs(IN P_MSDU_INFO_T prMsduInfo, + IN P_BSS_INFO_T prBssInfo, + IN u8 *pucDestAddr) +{ + u8 *pucBuffer; + u8 ucSupRatesLen; + + ASSERT(prMsduInfo); + ASSERT(prBssInfo); + + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + ASSERT(pucBuffer); + + /* Compose the frame body of the Probe Response frame. */ + /* 4 <1> Fill the SSID element. */ + SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; + + if (prBssInfo->eHiddenSsidType == ENUM_HIDDEN_SSID_LEN) { + if ((!pucDestAddr) && /* For Beacon only. */ + (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { + SSID_IE(pucBuffer)->ucLength = 0; + } else { /* probe response */ + SSID_IE(pucBuffer)->ucLength = prBssInfo->ucSSIDLen; + if (prBssInfo->ucSSIDLen) { + kalMemCopy(SSID_IE(pucBuffer)->aucSSID, + prBssInfo->aucSSID, + prBssInfo->ucSSIDLen); + } + } + } else { + SSID_IE(pucBuffer)->ucLength = prBssInfo->ucSSIDLen; + if (prBssInfo->ucSSIDLen) { + kalMemCopy(SSID_IE(pucBuffer)->aucSSID, + prBssInfo->aucSSID, prBssInfo->ucSSIDLen); + } + } + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + + /* 4 <2> Fill the Supported Rates element. */ + if (prBssInfo->ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) { + ucSupRatesLen = ELEM_MAX_LEN_SUP_RATES; + } else { + ucSupRatesLen = prBssInfo->ucAllSupportedRatesLen; + } + + if (ucSupRatesLen) { + SUP_RATES_IE(pucBuffer)->ucId = ELEM_ID_SUP_RATES; + SUP_RATES_IE(pucBuffer)->ucLength = ucSupRatesLen; + kalMemCopy(SUP_RATES_IE(pucBuffer)->aucSupportedRates, + prBssInfo->aucAllSupportedRates, ucSupRatesLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + + /* 4 <3> Fill the DS Parameter Set element. */ + if (prBssInfo->eBand == BAND_2G4) { + DS_PARAM_IE(pucBuffer)->ucId = ELEM_ID_DS_PARAM_SET; + DS_PARAM_IE(pucBuffer)->ucLength = + ELEM_MAX_LEN_DS_PARAMETER_SET; + DS_PARAM_IE(pucBuffer)->ucCurrChnl = + prBssInfo->ucPrimaryChannel; + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + + /* 4 <4> IBSS Parameter Set element, ID: 6 */ + if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + IBSS_PARAM_IE(pucBuffer)->ucId = ELEM_ID_IBSS_PARAM_SET; + IBSS_PARAM_IE(pucBuffer)->ucLength = + ELEM_MAX_LEN_IBSS_PARAMETER_SET; + WLAN_SET_FIELD_16(&(IBSS_PARAM_IE(pucBuffer)->u2ATIMWindow), + prBssInfo->u2ATIMWindow); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } + + /* 4 <5> TIM element, ID: 5 */ + if ((!pucDestAddr) && /* For Beacon only. */ + (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { +#if CFG_ENABLE_WIFI_DIRECT + /*no fgIsP2PRegistered protect */ + if (prBssInfo->eNetworkType == NETWORK_TYPE_P2P) { + /* IEEE 802.11 2007 - 7.3.2.6 */ + TIM_IE(pucBuffer)->ucId = ELEM_ID_TIM; + /* NOTE: fixed PVB length (AID is allocated from 8 ~ 15 + * only) */ + TIM_IE(pucBuffer)->ucLength = + (3 + MAX_LEN_TIM_PARTIAL_BMP) /*((u4N2 - u4N1) + + * 4) */ + ; + TIM_IE(pucBuffer)->ucDTIMCount = + 0 /*prBssInfo->ucDTIMCount */; + /* will be overwritten by FW */ + TIM_IE(pucBuffer)->ucDTIMPeriod = + prBssInfo->ucDTIMPeriod; + /* will be overwritten by FW */ + TIM_IE(pucBuffer)->ucBitmapControl = + 0 /*ucBitmapControl | (u8)u4N1 */; + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + } else +#endif + { + /* NOTE(Kevin): 1. AIS - Didn't Support AP Mode. + * 2. BOW - Didn't Support BCAST and PS. + */ + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will compose the Beacon/Probe Response frame header and + * its fixed fields. + * + * @param[in] pucBuffer Pointer to the frame buffer. + * @param[in] pucDestAddr Pointer to the Destination Address, if + * NULL, means Beacon. + * @param[in] pucOwnMACAddress Given Our MAC Address. + * @param[in] pucBSSID Given BSSID of the BSS. + * @param[in] u2BeaconInterval Given Beacon Interval. + * @param[in] u2CapInfo Given Capability Info. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void bssComposeBeaconProbeRespFrameHeaderAndFF( + IN u8 *pucBuffer, IN u8 *pucDestAddr, IN u8 *pucOwnMACAddress, + IN u8 *pucBSSID, IN u16 u2BeaconInterval, IN u16 u2CapInfo) +{ + P_WLAN_BEACON_FRAME_T prBcnProbRspFrame; + u8 aucBCAddr[] = BC_MAC_ADDR; + u16 u2FrameCtrl; + + DEBUGFUNC("bssComposeBeaconProbeRespFrameHeaderAndFF"); + /* DBGLOG(INIT, LOUD, ("\n")); */ + + ASSERT(pucBuffer); + ASSERT(pucOwnMACAddress); + ASSERT(pucBSSID); + + prBcnProbRspFrame = (P_WLAN_BEACON_FRAME_T)pucBuffer; + + /* 4 <1> Compose the frame header of the Beacon /ProbeResp frame. */ + /* Fill the Frame Control field. */ + if (pucDestAddr) { + u2FrameCtrl = MAC_FRAME_PROBE_RSP; + } else { + u2FrameCtrl = MAC_FRAME_BEACON; + pucDestAddr = aucBCAddr; + } + /* WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2FrameCtrl, u2FrameCtrl); */ + prBcnProbRspFrame->u2FrameCtrl = u2FrameCtrl; /* NOTE(Kevin): Optimized + * for ARM */ + + /* Fill the DA field with BCAST MAC ADDR or TA of ProbeReq. */ + COPY_MAC_ADDR(prBcnProbRspFrame->aucDestAddr, pucDestAddr); + + /* Fill the SA field with our MAC Address. */ + COPY_MAC_ADDR(prBcnProbRspFrame->aucSrcAddr, pucOwnMACAddress); + + /* Fill the BSSID field with current BSSID. */ + COPY_MAC_ADDR(prBcnProbRspFrame->aucBSSID, pucBSSID); + + /* Clear the SEQ/FRAG_NO field(HW won't overide the FRAG_NO, so we need + * to clear it). */ + prBcnProbRspFrame->u2SeqCtrl = 0; + + /* 4 <2> Compose the frame body's common fixed field part of the Beacon + * /ProbeResp frame. */ + /* MAC will update TimeStamp field */ + + /* Fill the Beacon Interval field. */ + /* WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2BeaconInterval, + * u2BeaconInterval); */ + prBcnProbRspFrame->u2BeaconInterval = u2BeaconInterval; /* NOTE(Kevin): + * Optimized for + * ARM */ + + /* Fill the Capability Information field. */ + /* WLAN_SET_FIELD_16(&prBcnProbRspFrame->u2CapInfo, u2CapInfo); */ + prBcnProbRspFrame->u2CapInfo = u2CapInfo; /* NOTE(Kevin): Optimized for + * ARM */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Update the Beacon Frame Template to FW for AIS AdHoc and P2P GO. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] ucBssIndex Specify which network reply the Probe Response. + * + * @retval WLAN_STATUS_SUCCESS Success. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bssUpdateBeaconContent(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + P_WLAN_BEACON_FRAME_T prBcnFrame; + u32 i; + + DEBUGFUNC("bssUpdateBeaconContent"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + /* 4 <1> Allocate a PKT_INFO_T for Beacon Frame */ + /* Allocate a MSDU_INFO_T */ + /* For Beacon */ + prMsduInfo = prBssInfo->prBeacon; + + /* beacon prMsduInfo will be NULLify once BSS deactivated, so skip if it + * is */ + if (prMsduInfo == NULL) { + return WLAN_STATUS_SUCCESS; + } + + /* 4 <2> Compose header */ + bssComposeBeaconProbeRespFrameHeaderAndFF( + (u8 *)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD), + NULL, prBssInfo->aucOwnMacAddr, prBssInfo->aucBSSID, + prBssInfo->u2BeaconInterval, prBssInfo->u2CapInfo); + + prMsduInfo->u2FrameLength = + (WLAN_MAC_MGMT_HEADER_LEN + + (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + + CAP_INFO_FIELD_LEN)); + + prMsduInfo->ucBssIndex = ucBssIndex; + + /* 4 <3> Compose the frame body's Common IEs of the Beacon frame. */ + bssBuildBeaconProbeRespFrameCommonIEs(prMsduInfo, prBssInfo, NULL); + + /* 4 <4> Compose IEs in MSDU_INFO_T */ + + /* Append IE for Beacon */ + for (i = 0; i < sizeof(txBcnIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); + i++) + if (txBcnIETable[i].pfnAppendIE) { + txBcnIETable[i].pfnAppendIE(prAdapter, prMsduInfo); + } + + prBcnFrame = (P_WLAN_BEACON_FRAME_T)prMsduInfo->prPacket; + + return nicUpdateBeaconIETemplate( + prAdapter, IE_UPD_METHOD_UPDATE_ALL, ucBssIndex, + prBssInfo->u2CapInfo, (u8 *)prBcnFrame->aucInfoElem, + prMsduInfo->u2FrameLength - + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem)); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Send the Beacon Frame(for BOW) or Probe Response Frame according to + * the given Destination Address. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] ucBssIndex Specify which network reply the Probe Response. + * @param[in] pucDestAddr Pointer to the Destination Address to reply + * @param[in] u4ControlFlags Control flags for information on Probe + * Response. + * + * @retval WLAN_STATUS_RESOURCE No available resources to send frame. + * @retval WLAN_STATUS_SUCCESS Success. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +bssSendBeaconProbeResponse(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN u8 *pucDestAddr, IN u32 u4ControlFlags) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + u16 u2EstimatedFrameLen; + u16 u2EstimatedFixedIELen; + u16 u2EstimatedExtraIELen; + P_APPEND_VAR_IE_ENTRY_T prIeArray = NULL; + u32 u4IeArraySize = 0; + u32 i; + + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if (!pucDestAddr) { /* For Beacon */ + prIeArray = &txBcnIETable[0]; + u4IeArraySize = + sizeof(txBcnIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); + } else { + prIeArray = &txProbRspIETable[0]; + u4IeArraySize = sizeof(txProbRspIETable) / + sizeof(APPEND_VAR_IE_ENTRY_T); + } + + /* 4 <1> Allocate a PKT_INFO_T for Beacon /Probe Response Frame */ + /* Allocate a MSDU_INFO_T */ + + /* Init with MGMT Header Length + Length of Fixed Fields + Common IE + * Fields */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_MGMT_HEADER_LEN + + TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + + CAP_INFO_FIELD_LEN + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + + (ELEM_HDR_LEN + ELEM_MAX_LEN_DS_PARAMETER_SET) + + (ELEM_HDR_LEN + ELEM_MAX_LEN_IBSS_PARAMETER_SET) + + (ELEM_HDR_LEN + (3 + MAX_LEN_TIM_PARTIAL_BMP)); + + /* + Extra IE Length */ + u2EstimatedExtraIELen = 0; + + for (i = 0; i < u4IeArraySize; i++) { + u2EstimatedFixedIELen = prIeArray[i].u2EstimatedFixedIELen; + + if (u2EstimatedFixedIELen) { + u2EstimatedExtraIELen += u2EstimatedFixedIELen; + } else { + ASSERT(prIeArray[i].pfnCalculateVariableIELen); + + u2EstimatedExtraIELen += + (u16)prIeArray[i].pfnCalculateVariableIELen( + prAdapter, ucBssIndex, NULL); + } + } + + u2EstimatedFrameLen += u2EstimatedExtraIELen; + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + if (prMsduInfo == NULL) { + DBGLOG(BSS, WARN, "No PKT_INFO_T for sending %s.\n", + ((!pucDestAddr) ? "Beacon" : "Probe Response")); + return WLAN_STATUS_RESOURCES; + } + + /* 4 <2> Compose Beacon/Probe Response frame header and fixed fields in + * MSDU_INfO_T. */ + /* Compose Header and Fixed Field */ +#if CFG_ENABLE_WIFI_DIRECT + if (u4ControlFlags & BSS_PROBE_RESP_USE_P2P_DEV_ADDR) { + if (prAdapter->fgIsP2PRegistered) { + bssComposeBeaconProbeRespFrameHeaderAndFF( + (u8 *)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD), + pucDestAddr, + prAdapter->rWifiVar.aucDeviceAddress, + prAdapter->rWifiVar.aucDeviceAddress, + DOT11_BEACON_PERIOD_DEFAULT, + (prBssInfo->u2CapInfo & + ~(CAP_INFO_ESS | CAP_INFO_IBSS))); + } + } else +#endif + { + bssComposeBeaconProbeRespFrameHeaderAndFF( + (u8 *)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD), + pucDestAddr, prBssInfo->aucOwnMacAddr, + prBssInfo->aucBSSID, prBssInfo->u2BeaconInterval, + prBssInfo->u2CapInfo); + } + + /* 4 <3> Update information of MSDU_INFO_T */ + + TX_SET_MMPDU(prAdapter, prMsduInfo, ucBssIndex, STA_REC_INDEX_NOT_FOUND, + WLAN_MAC_MGMT_HEADER_LEN, + (WLAN_MAC_MGMT_HEADER_LEN + TIMESTAMP_FIELD_LEN + + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN), + NULL, MSDU_RATE_MODE_AUTO); + + /* 4 <4> Compose the frame body's Common IEs of the Beacon/ProbeResp + * frame. */ + bssBuildBeaconProbeRespFrameCommonIEs(prMsduInfo, prBssInfo, + pucDestAddr); + + /* 4 <5> Compose IEs in MSDU_INFO_T */ + + /* Append IE */ + for (i = 0; i < u4IeArraySize; i++) + if (prIeArray[i].pfnAppendIE) { + prIeArray[i].pfnAppendIE(prAdapter, prMsduInfo); + } + + /* Set limited retry count and lifetime for Probe Resp is reasonable */ + nicTxSetPktLifeTime(prMsduInfo, 100); + nicTxSetPktRetryLimit(prMsduInfo, 2); + + /* TODO(Kevin): Also release the unused tail room of the composed MMPDU + */ + + /* 4 <6> Inform TXM to send this Beacon /Probe Response frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will process the Rx Probe Request Frame and then send + * back the corresponding Probe Response Frame if the specified + * conditions were matched. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prSwRfb Pointer to SW RFB data structure. + * + * @retval WLAN_STATUS_SUCCESS Always return success + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS bssProcessProbeRequest(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb) +{ + P_WLAN_MAC_MGMT_HEADER_T prMgtHdr; + P_BSS_INFO_T prBssInfo; + u8 ucBssIndex; + u8 aucBCBSSID[] = BC_BSSID; + u8 fgIsBcBssid; + u8 fgReplyProbeResp; + u32 u4CtrlFlagsForProbeResp = 0; + ENUM_BAND_T eBand; + u8 ucHwChannelNum; + + ASSERT(prSwRfb); + + /* 4 <1> Parse Probe Req and Get BSSID */ + prMgtHdr = (P_WLAN_MAC_MGMT_HEADER_T)prSwRfb->pvHeader; + + if (EQUAL_MAC_ADDR(aucBCBSSID, prMgtHdr->aucBSSID)) { + fgIsBcBssid = true; + }else{ + fgIsBcBssid = false; + } + + /* 4 <2> Check network conditions before reply Probe Response Frame + * (Consider Concurrent) */ + for (ucBssIndex = 0; ucBssIndex <= P2P_DEV_BSS_INDEX; ucBssIndex++) { + if (!IS_NET_ACTIVE(prAdapter, ucBssIndex)) { + continue; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if ((!fgIsBcBssid) && + UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prMgtHdr->aucBSSID)) { + continue; + } + + eBand = HAL_RX_STATUS_GET_RF_BAND(prSwRfb->prRxStatus); + ucHwChannelNum = + HAL_RX_STATUS_GET_CHNL_NUM(prSwRfb->prRxStatus); + + if (prBssInfo->eBand != eBand) { + continue; + } + + if (prBssInfo->ucPrimaryChannel != ucHwChannelNum) { + continue; + } + + fgReplyProbeResp = false; + + if (prBssInfo->eNetworkType == NETWORK_TYPE_AIS) { +#if CFG_SUPPORT_ADHOC + fgReplyProbeResp = aisValidateProbeReq( + prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp); +#endif + } +#if CFG_ENABLE_WIFI_DIRECT + else if ((prAdapter->fgIsP2PRegistered) && + (prBssInfo->eNetworkType == NETWORK_TYPE_P2P)) { + fgReplyProbeResp = p2pFuncValidateProbeReq( + prAdapter, prSwRfb, &u4CtrlFlagsForProbeResp, + (prBssInfo->ucBssIndex == P2P_DEV_BSS_INDEX), + (u8)prBssInfo->u4PrivateData); + } +#endif + + if (fgReplyProbeResp) { + if (nicTxGetFreeCmdCount(prAdapter) > + (CFG_TX_MAX_CMD_PKT_NUM / 2)) { + /* Resource margin is enough */ + bssSendBeaconProbeResponse( + prAdapter, ucBssIndex, + prMgtHdr->aucSrcAddr, + u4CtrlFlagsForProbeResp); + } + } + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to initialize the client list for AdHoc or AP + * Mode + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prBssInfo Given related BSS_INFO_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void bssInitializeClientList(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo) +{ + P_LINK_T prStaRecOfClientList; + + ASSERT(prBssInfo); + + prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; + + if (!LINK_IS_EMPTY(prStaRecOfClientList)) { + LINK_INITIALIZE(prStaRecOfClientList); + } + + DBGLOG(BSS, INFO, "Init BSS[%u] Client List\n", prBssInfo->ucBssIndex); + + bssCheckClientList(prAdapter, prBssInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to Add a STA_RECORD_T to the client list for + * AdHoc or AP Mode + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prBssInfo Given related BSS_INFO_T. + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void bssAddClient(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, + IN P_STA_RECORD_T prStaRec) +{ + P_LINK_T prClientList; + P_STA_RECORD_T prCurrStaRec; + + ASSERT(prBssInfo); + + prClientList = &prBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH_ENTRY(prCurrStaRec, prClientList, rLinkEntry, + STA_RECORD_T) { + if (prCurrStaRec == prStaRec) { + DBGLOG(BSS, + WARN, + "Current Client List already contains that STA_RECORD_T[" + MACSTR + "]\n", + MAC2STR(prStaRec->aucMacAddr)); + return; + } + } + + LINK_INSERT_TAIL(prClientList, &prStaRec->rLinkEntry); + + bssCheckClientList(prAdapter, prBssInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to Remove a STA_RECORD_T from the client list + * for AdHoc or AP Mode + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +u8 bssRemoveClient(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, + IN P_STA_RECORD_T prStaRec) +{ + P_LINK_T prClientList; + P_STA_RECORD_T prCurrStaRec; + + ASSERT(prBssInfo); + + prClientList = &prBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH_ENTRY(prCurrStaRec, prClientList, rLinkEntry, + STA_RECORD_T) { + if (prCurrStaRec == prStaRec) { + LINK_REMOVE_KNOWN_ENTRY(prClientList, + &prStaRec->rLinkEntry); + + return true; + } + } + + DBGLOG(BSS, INFO, + "Current Client List didn't contain that STA_RECORD_T[" MACSTR + "] before removing.\n", + MAC2STR(prStaRec->aucMacAddr)); + + bssCheckClientList(prAdapter, prBssInfo); + + return false; +} + +P_STA_RECORD_T bssRemoveClientByMac(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, IN u8 *pucMac) +{ + P_LINK_T prClientList; + P_STA_RECORD_T prCurrStaRec; + + ASSERT(prBssInfo); + + prClientList = &prBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH_ENTRY(prCurrStaRec, prClientList, rLinkEntry, + STA_RECORD_T) { + if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, pucMac)) { + LINK_REMOVE_KNOWN_ENTRY(prClientList, + &prCurrStaRec->rLinkEntry); + + return prCurrStaRec; + } + } + + DBGLOG(BSS, INFO, + "Current Client List didn't contain that STA_RECORD_T[" MACSTR + "] before removing.\n", + MAC2STR(pucMac)); + + bssCheckClientList(prAdapter, prBssInfo); + + return NULL; +} + +P_STA_RECORD_T bssGetClientByMac(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, IN u8 *pucMac) +{ + P_LINK_T prClientList; + P_STA_RECORD_T prCurrStaRec; + + ASSERT(prBssInfo); + + prClientList = &prBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH_ENTRY(prCurrStaRec, prClientList, rLinkEntry, + STA_RECORD_T) { + if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, pucMac)) { + return prCurrStaRec; + } + } + + DBGLOG(BSS, INFO, + "Current Client List didn't contain that STA_RECORD_T[" MACSTR + "] before removing.\n", + MAC2STR(pucMac)); + + bssCheckClientList(prAdapter, prBssInfo); + + return NULL; +} + +P_STA_RECORD_T bssRemoveHeadClient(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo) +{ + P_LINK_T prStaRecOfClientList; + P_STA_RECORD_T prStaRec = NULL; + + ASSERT(prBssInfo); + + prStaRecOfClientList = &prBssInfo->rStaRecOfClientList; + + if (!LINK_IS_EMPTY(prStaRecOfClientList)) { + LINK_REMOVE_HEAD(prStaRecOfClientList, prStaRec, + P_STA_RECORD_T); + } + + bssCheckClientList(prAdapter, prBssInfo); + + return prStaRec; +} + +u32 bssGetClientCount(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) +{ + return prBssInfo->rStaRecOfClientList.u4NumElem; +} + +void bssDumpClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) +{ + P_LINK_T prClientList; + P_STA_RECORD_T prCurrStaRec; + u8 ucCount = 0; + + ASSERT(prBssInfo); + + prClientList = &prBssInfo->rStaRecOfClientList; + + DBGLOG(SW4, INFO, "Dump BSS[%u] Client List NUM[%u]\n", + prBssInfo->ucBssIndex, prClientList->u4NumElem); + + LINK_FOR_EACH_ENTRY(prCurrStaRec, prClientList, rLinkEntry, + STA_RECORD_T) { + if (!prCurrStaRec) { + DBGLOG(SW4, INFO, "[%2u] is NULL STA_REC\n", ucCount); + break; + } + DBGLOG(SW4, INFO, "[%2u] STA[%u] [" MACSTR "]\n", ucCount, + prCurrStaRec->ucIndex, + MAC2STR(prCurrStaRec->aucMacAddr)); + + ucCount++; + } +} + +void bssCheckClientList(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) +{ + P_LINK_T prClientList; + P_STA_RECORD_T prCurrStaRec; + u8 ucCount = 0; + u8 fgError = false; + + ASSERT(prBssInfo); + + prClientList = &prBssInfo->rStaRecOfClientList; + + /* Check MAX number */ + if (prClientList->u4NumElem > P2P_MAXIMUM_CLIENT_COUNT) { + DBGLOG(SW4, INFO, "BSS[%u] Client List NUM[%u] ERR\n", + prBssInfo->ucBssIndex, prClientList->u4NumElem); + + fgError = true; + } + + /* Check default list status */ + if (prClientList->u4NumElem == 0) { + if ((void *)prClientList->prNext != (void *)prClientList) { + fgError = true; + } + if ((void *)prClientList->prPrev != (void *)prClientList) { + fgError = true; + } + + if (fgError) { + DBGLOG(SW4, INFO, + "BSS[%u] Client List PTR next/prev[%p/%p] ERR\n", + prBssInfo->ucBssIndex, prClientList->prNext, + prClientList->prPrev); + } + } + + /* Traverse list */ + LINK_FOR_EACH_ENTRY(prCurrStaRec, prClientList, rLinkEntry, + STA_RECORD_T) { + if (!prCurrStaRec) { + fgError = true; + DBGLOG(SW4, INFO, "BSS[%u] Client List NULL PTR ERR\n", + prBssInfo->ucBssIndex); + + break; + } + + ucCount++; + } + + /* Check real count and list number */ + if (ucCount != prClientList->u4NumElem) { + DBGLOG(SW4, INFO, + "BSS[%u] Client List NUM[%u] REAL CNT[%u] ERR\n", + prBssInfo->ucBssIndex, prClientList->u4NumElem, ucCount); + + fgError = true; + } + + if (fgError) { + bssDumpClientList(prAdapter, prBssInfo); + } +} + +#endif + +#if CFG_SUPPORT_ADHOC +/*----------------------------------------------------------------------------*/ +/* Routines for IBSS(AdHoc) only */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to process Beacons from current Ad-Hoc network + * peers. We also process Beacons from other Ad-Hoc network during SCAN. If it + * has the same SSID and we'll decide to merge into it if it has a larger TSF. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prBssInfo Pointer to the BSS_INFO_T. + * @param[in] prBSSDesc Pointer to the BSS Descriptor. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void ibssProcessMatchedBeacon(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_BSS_DESC_T prBssDesc, IN u8 ucRCPI) +{ + P_STA_RECORD_T prStaRec = NULL; + + u8 fgIsCheckCapability = false; + u8 fgIsCheckTSF = false; + u8 fgIsGoingMerging = false; + u8 fgIsSameBSSID; + + ASSERT(prBssInfo); + ASSERT(prBssDesc); + + /* 4 <1> Process IBSS Beacon only after we create or merge with other + * IBSS. */ + if (!prBssInfo->fgIsBeaconActivated) { + return; + } + + /* 4 <2> Get the STA_RECORD_T of TA. */ + prStaRec = cnmGetStaRecByAddress(prAdapter, + prAdapter->prAisBssInfo->ucBssIndex, + prBssDesc->aucSrcAddr); + + fgIsSameBSSID = + UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, prBssDesc->aucBSSID) ? + false : + true; + + /* 4 <3> IBSS Merge Decision Flow for Processing Beacon. */ + if (fgIsSameBSSID) { + /* Same BSSID: + * Case I. This is a new TA and it has decide to merged with + * us. a) If fgIsMerging == false - we will send msg to notify + * AIS. b) If fgIsMerging == true - already notify AIS. Case + * II. This is an old TA and we've already merged together. + */ + if (!prStaRec) { + /* For Case I - Check this IBSS's capability first + * before adding this Sta Record. */ + fgIsCheckCapability = true; + + /* If check is passed, then we perform merging with this + * new IBSS */ + fgIsGoingMerging = true; + } else { + ASSERT((prStaRec->ucBssIndex == + prAdapter->prAisBssInfo->ucBssIndex) && + IS_ADHOC_STA(prStaRec)); + + if (prStaRec->ucStaState != STA_STATE_3) { + if (!prStaRec->fgIsMerging) { + /* For Case I - */ + /* Check this IBSS's capability first + * before */ + /* adding this Sta Record. */ + fgIsCheckCapability = true; + + /* If check is passed, then we perform + * merging with this new IBSS */ + fgIsGoingMerging = true; + } else { + /* For Case II - Update rExpirationTime + * of Sta Record */ + GET_CURRENT_SYSTIME( + &prStaRec->rUpdateTime); + } + } else { + /* For Case II - Update rExpirationTime of Sta + * Record */ + GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); + } + } + } else { + /* Unequal BSSID: + * Case III. This is a new TA and we need to compare the TSF and + * get the winner. Case IV. This is an old TA and it merge into + * a new IBSS before we do the same thing. We need to compare + * the TSF to get the winner. Case V. This is an old TA and it + * restart a new IBSS. We also need to compare the TSF to get + * the winner. + */ + + /* For Case III, IV & V - We'll always check this new IBSS's + * capability first before merging into new IBSS. + */ + fgIsCheckCapability = true; + + /* If check is passed, we need to perform TSF check to decide + * the major BSSID */ + fgIsCheckTSF = true; + + /* For Case IV & V - We won't update rExpirationTime of Sta + * Record */ + } + + /* 4 <7> Check this BSS_DESC_T's capability. */ + if (fgIsCheckCapability) { + u8 fgIsCapabilityMatched = false; + + do { + if (!(prBssDesc->ucPhyTypeSet & + (prAdapter->rWifiVar.ucAvailablePhyTypeSet))) { + DBGLOG(BSS, LOUD, + "IBSS MERGE: Ignore Peer MAC: " MACSTR + " - Unsupported Phy.\n", + MAC2STR(prBssDesc->aucSrcAddr)); + + break; + } + + if (prBssDesc->fgIsUnknownBssBasicRate) { + DBGLOG(BSS, LOUD, + "IBSS MERGE: Ignore Peer MAC: " MACSTR + " - Unknown Basic Rate.\n", + MAC2STR(prBssDesc->aucSrcAddr)); + + break; + } + + if (ibssCheckCapabilityForAdHocMode(prAdapter, + prBssDesc) == + WLAN_STATUS_FAILURE) { + DBGLOG(BSS, LOUD, + "IBSS MERGE: Ignore Peer MAC: " MACSTR + " - Capability is not matched.\n", + MAC2STR(prBssDesc->aucSrcAddr)); + + break; + } + + fgIsCapabilityMatched = true; + } while (false); + + if (!fgIsCapabilityMatched) { + if (prStaRec) { + /* For Case II - We merge this STA_RECORD in RX + * Path. Case IV & V - They change their BSSID + * after we merge with them. + */ + + DBGLOG(BSS, LOUD, + "IBSS MERGE: Ignore Peer MAC: " MACSTR + " - Capability is not matched.\n", + MAC2STR(prBssDesc->aucSrcAddr)); + } + + return; + } + + DBGLOG(BSS, LOUD, + "IBSS MERGE: Peer MAC: " MACSTR + " - Check capability was passed.\n", + MAC2STR(prBssDesc->aucSrcAddr)); + } + + if (fgIsCheckTSF) { + if (prBssDesc->fgIsLargerTSF) { + fgIsGoingMerging = true; + }else{ + return; + } + } + + if (fgIsGoingMerging) { + P_MSG_AIS_IBSS_PEER_FOUND_T prAisIbssPeerFoundMsg; + + /* 4 <1> We will merge with to this BSS immediately. */ + prBssDesc->fgIsConnecting = true; + prBssDesc->fgIsConnected = false; + + /* 4 <2> Setup corresponding STA_RECORD_T */ + prStaRec = bssCreateStaRecFromBssDesc( + prAdapter, STA_TYPE_ADHOC_PEER, + prAdapter->prAisBssInfo->ucBssIndex, prBssDesc); + + if (!prStaRec) { + /* no memory ? */ + return; + } + + prStaRec->fgIsMerging = true; + + /* update RCPI */ + prStaRec->ucRCPI = ucRCPI; + + /* 4 <3> Send Merge Msg to CNM to obtain the channel privilege. + */ + prAisIbssPeerFoundMsg = + (P_MSG_AIS_IBSS_PEER_FOUND_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, + sizeof(MSG_AIS_IBSS_PEER_FOUND_T)); + + if (!prAisIbssPeerFoundMsg) { + ASSERT(0); /* Can't send Merge Msg */ + return; + } + + prAisIbssPeerFoundMsg->rMsgHdr.eMsgId = MID_SCN_AIS_FOUND_IBSS; + prAisIbssPeerFoundMsg->ucBssIndex = + prAdapter->prAisBssInfo->ucBssIndex; + prAisIbssPeerFoundMsg->prStaRec = prStaRec; + + /* Inform AIS to do STATE TRANSITION + * For Case I - If AIS in IBSS_ALONE, let it jump to NORMAL_TR + * after we know the new member. For Case III, IV - Now this new + * BSSID wins the TSF, follow it. + */ + if (fgIsSameBSSID) { + prAisIbssPeerFoundMsg->fgIsMergeIn = true; + } else { + prAisIbssPeerFoundMsg->fgIsMergeIn = + (prBssDesc->fgIsLargerTSF) ? false : true; + } + + mboxSendMsg(prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prAisIbssPeerFoundMsg, + MSG_SEND_METHOD_BUF); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will check the Capability for Ad-Hoc to decide if we are + * able to merge with(same capability). + * + * @param[in] prBSSDesc Pointer to the BSS Descriptor. + * + * @retval WLAN_STATUS_FAILURE Can't pass the check of Capability. + * @retval WLAN_STATUS_SUCCESS Pass the check of Capability. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS ibssCheckCapabilityForAdHocMode(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + + ASSERT(prBssDesc); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + do { + /* 4 <1> Check the BSS Basic Rate Set for current AdHoc Mode */ + if ((prConnSettings->eAdHocMode == AD_HOC_MODE_11B) && + (prBssDesc->u2BSSBasicRateSet & ~RATE_SET_HR_DSSS)) { + break; + } else if ((prConnSettings->eAdHocMode == AD_HOC_MODE_11A) && + (prBssDesc->u2BSSBasicRateSet & ~RATE_SET_OFDM)) { + break; + } + + /* 4 <3> Check the ATIM window setting. */ + if (prBssDesc->u2ATIMWindow) { + DBGLOG(BSS, INFO, + "AdHoc PS was not supported(ATIM Window: %d)\n", + prBssDesc->u2ATIMWindow); + break; + } + /* 4 <4> Check the Security setting. */ + if (!rsnPerformPolicySelection(prAdapter, prBssDesc)) { + break; + } + + rStatus = WLAN_STATUS_SUCCESS; + } while (false); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will initial the BSS_INFO_T for IBSS Mode. + * + * @param[in] prBssInfo Pointer to the BSS_INFO_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void ibssInitForAdHoc(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) +{ + u8 aucBSSID[MAC_ADDR_LEN]; + u16 *pu2BSSID = (u16 *)&aucBSSID[0]; + u32 i; + + ASSERT(prBssInfo); + ASSERT(prBssInfo->eCurrentOPMode == OP_MODE_IBSS); + + /* 4 <1> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ + prBssInfo->ucNonHTBasicPhyType = + (u8)rNonHTAdHocModeAttributes[prBssInfo->ucConfigAdHocAPMode] + .ePhyTypeIndex; + prBssInfo->u2BSSBasicRateSet = + rNonHTAdHocModeAttributes[prBssInfo->ucConfigAdHocAPMode] + .u2BSSBasicRateSet; + + prBssInfo->u2OperationalRateSet = + rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType] + .u2SupportedRateSet; + + rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, + prBssInfo->u2BSSBasicRateSet, + prBssInfo->aucAllSupportedRates, + &prBssInfo->ucAllSupportedRatesLen); + + /* 4 <2> Setup BSSID */ + if (!prBssInfo->fgHoldSameBssidForIBSS) { + for (i = 0; i < sizeof(aucBSSID) / sizeof(u16); i++) + pu2BSSID[i] = (u16)(kalRandomNumber() & 0xFFFF); + + aucBSSID[0] &= ~0x01; /* 7.1.3.3.3 - The individual/group bit of + * the address is set to 0. */ + aucBSSID[0] |= 0x02; /* 7.1.3.3.3 - The universal/local bit of + * the address is set to 1. */ + + COPY_MAC_ADDR(prBssInfo->aucBSSID, aucBSSID); + } + + /* 4 <3> Setup Capability - Short Preamble */ + if (rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType] + .fgIsShortPreambleOptionImplemented && + /* Short Preamble Option Enable is true */ + ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || + (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO))) { + prBssInfo->fgIsShortPreambleAllowed = true; + prBssInfo->fgUseShortPreamble = true; + } else { + prBssInfo->fgIsShortPreambleAllowed = false; + prBssInfo->fgUseShortPreamble = false; + } + + /* 4 <4> Setup Capability - Short Slot Time */ + /* 7.3.1.4 For IBSS, the Short Slot Time subfield shall be set to 0. */ + prBssInfo->fgUseShortSlotTime = false; /* Set to false for AdHoc */ + + /* 4 <5> Compoase Capability */ + prBssInfo->u2CapInfo = CAP_INFO_IBSS; + + if (prBssInfo->fgIsProtection) { + prBssInfo->u2CapInfo |= CAP_INFO_PRIVACY; + } + + if (prBssInfo->fgIsShortPreambleAllowed) { + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; + } + + if (prBssInfo->fgUseShortSlotTime) { + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; + } + + /* 4 <6> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ + nicTxUpdateBssDefaultRate(prBssInfo); +} + +#endif // CFG_SUPPORT_ADHOC + +#if CFG_SUPPORT_AAA + +/*----------------------------------------------------------------------------*/ +/* Routines for BSS(AP) only */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will initial the BSS_INFO_T for AP Mode. + * + * @param[in] prBssInfo Given related BSS_INFO_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void bssInitForAP(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, + IN u8 fgIsRateUpdate) +{ + P_AC_QUE_PARMS_T prACQueParms; + + ENUM_WMM_ACI_T eAci; + + u8 auCWminLog2ForBcast[WMM_AC_INDEX_NUM] = { 4 /*BE*/, 4 /*BK*/, + 3 /*VO*/, 2 /*VI*/ }; + u8 auCWmaxLog2ForBcast[WMM_AC_INDEX_NUM] = { 10, 10, 4, 3 }; + u8 auAifsForBcast[WMM_AC_INDEX_NUM] = { 3, 7, 2, 2 }; + u8 auTxopForBcast[WMM_AC_INDEX_NUM] = { 0, 0, 94, 47 }; /* If the AP is + * OFDM */ + + u8 auCWminLog2[WMM_AC_INDEX_NUM] = { 4 /*BE*/, 4 /*BK*/, 3 /*VO*/, + 2 /*VI*/ }; + u8 auCWmaxLog2[WMM_AC_INDEX_NUM] = { 6, 10, 4, 3 }; + u8 auAifs[WMM_AC_INDEX_NUM] = { 3, 7, 1, 1 }; + u8 auTxop[WMM_AC_INDEX_NUM] = { 0, 0, 94, 47 }; /* If the AP is OFDM */ + + DEBUGFUNC("bssInitForAP"); + DBGLOG(BSS, LOUD, "\n"); + + ASSERT(prBssInfo); + ASSERT((prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) || + (prBssInfo->eCurrentOPMode == OP_MODE_BOW)); + + /* 4 <1> Setup PHY Attributes and Basic Rate Set/Operational Rate Set */ + prBssInfo->ucNonHTBasicPhyType = + (u8)rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode] + .ePhyTypeIndex; + prBssInfo->u2BSSBasicRateSet = + rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode] + .u2BSSBasicRateSet; + + /* 4 <1.1> Mask CCK 1M For Sco scenario except FDD mode */ + if (prAdapter->u4FddMode == false) { + prBssInfo->u2BSSBasicRateSet &= ~RATE_SET_BIT_1M; + } + /* prBssInfo->u2OperationalRateSet &= ~RATE_SET_BIT_1M; */ + + prBssInfo->u2OperationalRateSet = + rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType] + .u2SupportedRateSet; + + if (fgIsRateUpdate) { + rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, + prBssInfo->u2BSSBasicRateSet, + prBssInfo->aucAllSupportedRates, + &prBssInfo->ucAllSupportedRatesLen); + } + /* 4 <2> Setup BSSID */ + COPY_MAC_ADDR(prBssInfo->aucBSSID, prBssInfo->aucOwnMacAddr); + + /* 4 <3> Setup Capability - Short Preamble */ + if (rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType] + .fgIsShortPreambleOptionImplemented && + /* Short Preamble Option Enable is true */ + ((prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_SHORT) || + (prAdapter->rWifiVar.ePreambleType == PREAMBLE_TYPE_AUTO))) { + prBssInfo->fgIsShortPreambleAllowed = true; + prBssInfo->fgUseShortPreamble = true; + } else { + prBssInfo->fgIsShortPreambleAllowed = false; + prBssInfo->fgUseShortPreamble = false; + } + + /* 4 <4> Setup Capability - Short Slot Time */ + prBssInfo->fgUseShortSlotTime = true; + + /* 4 <5> Compoase Capability */ + prBssInfo->u2CapInfo = CAP_INFO_ESS; + + if (prBssInfo->fgIsProtection) { + prBssInfo->u2CapInfo |= CAP_INFO_PRIVACY; + } + + if (prBssInfo->fgIsShortPreambleAllowed) { + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_PREAMBLE; + } + + if (prBssInfo->fgUseShortSlotTime) { + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; + } + + /* 4 <6> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ + nicTxUpdateBssDefaultRate(prBssInfo); + + /* 4 <7> Fill the EDCA */ + + prACQueParms = prBssInfo->arACQueParmsForBcast; + + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + prACQueParms[eAci].ucIsACMSet = false; + prACQueParms[eAci].u2Aifsn = auAifsForBcast[eAci]; + prACQueParms[eAci].u2CWmin = BIT(auCWminLog2ForBcast[eAci]) - 1; + prACQueParms[eAci].u2CWmax = BIT(auCWmaxLog2ForBcast[eAci]) - 1; + prACQueParms[eAci].u2TxopLimit = auTxopForBcast[eAci]; + + prBssInfo->aucCWminLog2ForBcast[eAci] = + auCWminLog2ForBcast[eAci]; /* used to send WMM IE */ + prBssInfo->aucCWmaxLog2ForBcast[eAci] = + auCWmaxLog2ForBcast[eAci]; + + DBGLOG(BSS, + INFO, + "Bcast: eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", + eAci, + prACQueParms[eAci].ucIsACMSet, + prACQueParms[eAci].u2Aifsn, + prACQueParms[eAci].u2CWmin, + prACQueParms[eAci].u2CWmax, + prACQueParms[eAci].u2TxopLimit); + } + + prACQueParms = prBssInfo->arACQueParms; + + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + prACQueParms[eAci].ucIsACMSet = false; + prACQueParms[eAci].u2Aifsn = auAifs[eAci]; + prACQueParms[eAci].u2CWmin = BIT(auCWminLog2[eAci]) - 1; + prACQueParms[eAci].u2CWmax = BIT(auCWmaxLog2[eAci]) - 1; + prACQueParms[eAci].u2TxopLimit = auTxop[eAci]; + + DBGLOG(BSS, + INFO, + "eAci = %d, ACM = %d, Aifsn = %d, CWmin = %d, CWmax = %d, TxopLimit = %d\n", + eAci, + prACQueParms[eAci].ucIsACMSet, + prACQueParms[eAci].u2Aifsn, + prACQueParms[eAci].u2CWmin, + prACQueParms[eAci].u2CWmax, + prACQueParms[eAci].u2TxopLimit); + } + + /* Note: Caller should update the EDCA setting to HW by + * nicQmUpdateWmmParms() it there is no AIS network */ + /* Note: In E2, only 4 HW queues. The the Edca parameters should be + * folow by AIS network */ + /* Note: In E3, 8 HW queues. the Wmm parameters should be updated to + * right queues according to BSS */ +} + +#endif + +void bssDumpBssInfo(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex) +{ + P_BSS_INFO_T prBssInfo; + /* P_LINK_T prStaRecOfClientList = (P_LINK_T) NULL; */ + /* P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T) NULL; */ + + if (ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(SW4, INFO, "Invalid BssInfo index[%u], skip dump!\n", + ucBssIndex); + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if (!prBssInfo) { + DBGLOG(SW4, INFO, "Invalid BssInfo index[%u], skip dump!\n", + ucBssIndex); + return; + } + + DBGLOG(SW4, INFO, "OWNMAC[" MACSTR "] BSSID[" MACSTR "] SSID[%s]\n", + MAC2STR(prBssInfo->aucOwnMacAddr), MAC2STR(prBssInfo->aucBSSID), + prBssInfo->aucSSID); + + DBGLOG(SW4, INFO, + "BSS IDX[%u] Type[%s] OPMode[%s] ConnState[%u] Absent[%u]\n", + prBssInfo->ucBssIndex, apucNetworkType[prBssInfo->eNetworkType], + apucNetworkOpMode[prBssInfo->eCurrentOPMode], + prBssInfo->eConnectionState, prBssInfo->fgIsNetAbsent); + + DBGLOG(SW4, + INFO, + "Channel[%u] Band[%u] SCO[%u] Assoc40mBwAllowed[%u] 40mBwAllowed[%u] MaxBw[%u] Nss[%u] eDBDCBand[%u]\n", + prBssInfo->ucPrimaryChannel, + prBssInfo->eBand, + prBssInfo->eBssSCO, + prBssInfo->fgAssoc40mBwAllowed, + prBssInfo->fg40mBwAllowed, + cnmGetBssMaxBw(prAdapter, prBssInfo->ucBssIndex), + prBssInfo->ucNss, + prBssInfo->eDBDCBand); + + DBGLOG(SW4, INFO, "QBSS[%u] CapInfo[0x%04x] AID[%u]\n", + prBssInfo->fgIsQBSS, prBssInfo->u2CapInfo, prBssInfo->u2AssocId); + + DBGLOG(SW4, INFO, + "ShortPreamble Allowed[%u] EN[%u], ShortSlotTime[%u]\n", + prBssInfo->fgIsShortPreambleAllowed, + prBssInfo->fgUseShortPreamble, prBssInfo->fgUseShortSlotTime); + + DBGLOG(SW4, INFO, "PhyTypeSet: Basic[0x%02x] NonHtBasic[0x%02x]\n", + prBssInfo->ucPhyTypeSet, prBssInfo->ucNonHTBasicPhyType); + + DBGLOG(SW4, INFO, "RateSet: BssBasic[0x%04x] Operational[0x%04x]\n", + prBssInfo->u2BSSBasicRateSet, prBssInfo->u2OperationalRateSet); + + DBGLOG(SW4, INFO, "ATIMWindow[%u] DTIM Period[%u] Count[%u]\n", + prBssInfo->u2ATIMWindow, prBssInfo->ucDTIMPeriod, + prBssInfo->ucDTIMCount); + + DBGLOG(SW4, INFO, + "HT Operation Info1[0x%02x] Info2[0x%04x] Info3[0x%04x]\n", + prBssInfo->ucHtOpInfo1, prBssInfo->u2HtOpInfo2, + prBssInfo->u2HtOpInfo3); + + DBGLOG(SW4, INFO, + "ProtectMode HT[%u] ERP[%u], OperationMode GF[%u] RIFS[%u]\n", + prBssInfo->eHtProtectMode, prBssInfo->fgErpProtectMode, + prBssInfo->eGfOperationMode, prBssInfo->eRifsOperationMode); + + DBGLOG(SW4, + INFO, + "(OBSS) ProtectMode HT[%u] ERP[%u], OperationMode GF[%u] RIFS[%u]\n", + prBssInfo->eObssHtProtectMode, + prBssInfo->fgObssErpProtectMode, + prBssInfo->eObssGfOperationMode, + prBssInfo->fgObssRifsOperationMode); + + DBGLOG(SW4, + INFO, + "VhtChannelWidth[%u] OpChangeChannelWidth[%u], IsOpChangeChannelWidth[%u]\n", + prBssInfo->ucVhtChannelWidth, + prBssInfo->ucOpChangeChannelWidth, + prBssInfo->fgIsOpChangeChannelWidth); + + DBGLOG(SW4, INFO, "======== Dump Connected Client ========\n"); + + bssDumpClientList(prAdapter, prBssInfo); + + DBGLOG(SW4, INFO, "============== Dump Done ==============\n"); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/cnm.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/cnm.c new file mode 100644 index 00000000000000..c37c3a5b79532f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/cnm.c @@ -0,0 +1,1996 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "cnm.c" + * \brief Module of Concurrent Network Management + * + * Module of Concurrent Network Management + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to initialize variables in CNM_INFO_T. + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmInit(P_ADAPTER_T prAdapter) +{ + P_CNM_INFO_T prCnmInfo; + + ASSERT(prAdapter); + + prCnmInfo = &prAdapter->rCnmInfo; + prCnmInfo->fgChGranted = false; +#if CFG_SUPPORT_DBDC + cnmTimerInitTimer(prAdapter, &prAdapter->rWifiVar.rDBDCSwitchGuardTimer, + (PFN_MGMT_TIMEOUT_FUNC)cnmDbdcDecision, + (unsigned long)DBDC_DECISION_TIMER_SWITCH_GUARD_TIME); + + cnmTimerInitTimer( + prAdapter, &prAdapter->rWifiVar.rDBDCDisableCountdownTimer, + (PFN_MGMT_TIMEOUT_FUNC)cnmDbdcDecision, + (unsigned long)DBDC_DECISION_TIMER_DISABLE_COUNT_DOWN); +#endif +#if CFG_SUPPORT_DBDC_TC6 + cnmTimerInitTimer( + prAdapter, &prAdapter->rWifiVar.rDBDCReconnectCountDown, + (PFN_MGMT_TIMEOUT_FUNC)cnmDbdcDecision, + (unsigned long)DBDC_DECISION_TIMER_RECONNECT_COUNT_DOWN); + + cnmTimerInitTimer( + prAdapter, &prAdapter->rWifiVar.rDBDCAisConnectCountDown, + (PFN_MGMT_TIMEOUT_FUNC)cnmDbdcDecision, + (unsigned long)DBDC_DECISION_TIMER_AIS_CONNECT_COUNT_DOWN); +#endif +} /* end of cnmInit()*/ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Before handle the message from other module, it need to obtain + * the Channel privilege from Channel Manager + * + * @param[in] prMsgHdr The message need to be handled. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmChMngrRequestPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr) +{ + P_MSG_CH_REQ_T prMsgChReq; + P_CMD_CH_PRIVILEGE_T prCmdBody; + WLAN_STATUS rStatus; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prMsgChReq = (P_MSG_CH_REQ_T)prMsgHdr; + +#if CFG_SUPPORT_DBDC_TC6 + if (timerPendingTimer(&prAdapter->rWifiVar.rDBDCSwitchGuardTimer) || + timerPendingTimer( + &prAdapter->rWifiVar.rDBDCDisableCountdownTimer)) { + LINK_INSERT_TAIL( + &prAdapter->rCnmInfo.rDbdcSwitchGuradPendingReqList, + &prMsgHdr->rLinkEntry); + DBGLOG(CNM, STATE, "[DBDC] ChReq: queued BSS %u Token %u REQ\n", + prMsgChReq->ucBssIndex, prMsgChReq->ucTokenID); + return; + } +#endif + + prCmdBody = (P_CMD_CH_PRIVILEGE_T)cnmMemAlloc( + prAdapter, RAM_TYPE_BUF, sizeof(CMD_CH_PRIVILEGE_T)); + ASSERT(prCmdBody); + + /* To do: exception handle */ + if (!prCmdBody) { + DBGLOG(CNM, ERROR, + "ChReq: fail to get buf (net=%d, token=%d)\n", + prMsgChReq->ucBssIndex, prMsgChReq->ucTokenID); + + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + DBGLOG(CNM, INFO, "ChReq net=%d token=%d b=%d c=%d s=%d w=%d\n", + prMsgChReq->ucBssIndex, prMsgChReq->ucTokenID, + prMsgChReq->eRfBand, prMsgChReq->ucPrimaryChannel, + prMsgChReq->eRfSco, prMsgChReq->eRfChannelWidth); + + prCmdBody->ucBssIndex = prMsgChReq->ucBssIndex; + prCmdBody->ucTokenID = prMsgChReq->ucTokenID; + prCmdBody->ucAction = CMD_CH_ACTION_REQ; /* Request */ + prCmdBody->ucPrimaryChannel = prMsgChReq->ucPrimaryChannel; + prCmdBody->ucRfSco = (u8)prMsgChReq->eRfSco; + prCmdBody->ucRfBand = (u8)prMsgChReq->eRfBand; + prCmdBody->ucRfChannelWidth = (u8)prMsgChReq->eRfChannelWidth; + prCmdBody->ucRfCenterFreqSeg1 = (u8)prMsgChReq->ucRfCenterFreqSeg1; + prCmdBody->ucRfCenterFreqSeg2 = (u8)prMsgChReq->ucRfCenterFreqSeg2; + prCmdBody->ucReqType = (u8)prMsgChReq->eReqType; + prCmdBody->ucDBDCBand = (u8)prMsgChReq->eDBDCBand; + prCmdBody->aucReserved = 0; + prCmdBody->u4MaxInterval = prMsgChReq->u4MaxInterval; + prCmdBody->aucReserved2[0] = 0; + prCmdBody->aucReserved2[1] = 0; + prCmdBody->aucReserved2[2] = 0; + prCmdBody->aucReserved2[3] = 0; + prCmdBody->aucReserved2[4] = 0; + prCmdBody->aucReserved2[5] = 0; + prCmdBody->aucReserved2[6] = 0; + prCmdBody->aucReserved2[7] = 0; + + ASSERT(prCmdBody->ucBssIndex <= MAX_BSS_INDEX); + + /* For monkey testing 20110901 */ + if (prCmdBody->ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(CNM, ERROR, "CNM: ChReq with wrong netIdx=%d\n\n", + prCmdBody->ucBssIndex); + } + + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_CH_PRIVILEGE, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_CH_PRIVILEGE_T), /* u4SetQueryInfoLen + */ + (u8 *)prCmdBody, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + /* ASSERT(rStatus == WLAN_STATUS_PENDING); */ + + cnmMemFree(prAdapter, prCmdBody); + cnmMemFree(prAdapter, prMsgHdr); +} /* end of cnmChMngrRequestPrivilege()*/ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Before deliver the message to other module, it need to release + * the Channel privilege to Channel Manager. + * + * @param[in] prMsgHdr The message need to be delivered + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmChMngrAbortPrivilege(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr) +{ + P_MSG_CH_ABORT_T prMsgChAbort; + P_CMD_CH_PRIVILEGE_T prCmdBody; + P_CNM_INFO_T prCnmInfo; + WLAN_STATUS rStatus; +#if CFG_SISO_SW_DEVELOP + P_BSS_INFO_T prBssInfo; +#endif +#if CFG_SUPPORT_DBDC_TC6 + P_LINK_ENTRY_T prLinkEntry_pendingMsg; + P_MSG_CH_REQ_T prPendingMsg; +#endif + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prMsgChAbort = (P_MSG_CH_ABORT_T)prMsgHdr; + +#if CFG_SUPPORT_DBDC_TC6 + if (timerPendingTimer(&prAdapter->rWifiVar.rDBDCSwitchGuardTimer) || + timerPendingTimer( + &prAdapter->rWifiVar.rDBDCDisableCountdownTimer)) { + LINK_FOR_EACH( + prLinkEntry_pendingMsg, + &prAdapter->rCnmInfo.rDbdcSwitchGuradPendingReqList) { + prPendingMsg = (P_MSG_CH_REQ_T)LINK_ENTRY( + prLinkEntry_pendingMsg, MSG_HDR_T, rLinkEntry); + + /* Find matched request and check + * if it is being served. + */ + if (prPendingMsg->ucBssIndex == + prMsgChAbort->ucBssIndex && + prPendingMsg->ucTokenID == + prMsgChAbort->ucTokenID) { + LINK_REMOVE_KNOWN_ENTRY( + &prAdapter->rCnmInfo + .rDbdcSwitchGuradPendingReqList, + &prPendingMsg->rMsgHdr.rLinkEntry); + + DBGLOG(CNM, + STATE, + "[DBDC] ChAbort: remove BSS %u Token %u REQ)\n", + prPendingMsg->ucBssIndex, + prPendingMsg->ucTokenID); + + cnmMemFree(prAdapter, prPendingMsg); + cnmMemFree(prAdapter, prMsgHdr); + + return; + } + } + } +#endif + + /* Check if being granted channel privilege is aborted */ + prCnmInfo = &prAdapter->rCnmInfo; + if (prCnmInfo->fgChGranted && + prCnmInfo->ucBssIndex == prMsgChAbort->ucBssIndex && + prCnmInfo->ucTokenID == prMsgChAbort->ucTokenID) { + prCnmInfo->fgChGranted = false; + } + + prCmdBody = (P_CMD_CH_PRIVILEGE_T)cnmMemAlloc( + prAdapter, RAM_TYPE_BUF, sizeof(CMD_CH_PRIVILEGE_T)); + ASSERT(prCmdBody); + + /* To do: exception handle */ + if (!prCmdBody) { + DBGLOG(CNM, ERROR, + "ChAbort: fail to get buf (net=%d, token=%d)\n", + prMsgChAbort->ucBssIndex, prMsgChAbort->ucTokenID); + + cnmMemFree(prAdapter, prMsgHdr); + return; + } + kalMemZero(prCmdBody, sizeof(CMD_CH_PRIVILEGE_T)); + + prCmdBody->ucBssIndex = prMsgChAbort->ucBssIndex; + prCmdBody->ucTokenID = prMsgChAbort->ucTokenID; + prCmdBody->ucAction = CMD_CH_ACTION_ABORT; /* Abort */ + prCmdBody->ucDBDCBand = (u8)prMsgChAbort->eDBDCBand; + + DBGLOG(CNM, INFO, "ChAbort net=%d token=%d dbdc=%u\n", + prCmdBody->ucBssIndex, prCmdBody->ucTokenID, + prCmdBody->ucDBDCBand); + + ASSERT(prCmdBody->ucBssIndex <= MAX_BSS_INDEX); + + /* For monkey testing 20110901 */ + if (prCmdBody->ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(CNM, ERROR, "CNM: ChAbort with wrong netIdx=%d\n\n", + prCmdBody->ucBssIndex); + } + + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_CH_PRIVILEGE, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_CH_PRIVILEGE_T), /* u4SetQueryInfoLen + */ + (u8 *)prCmdBody, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + /* ASSERT(rStatus == WLAN_STATUS_PENDING); */ + +#if CFG_SISO_SW_DEVELOP + prBssInfo = prAdapter->aprBssInfo[prMsgChAbort->ucBssIndex]; + /* Driver clear granted CH in BSS info */ + prBssInfo->fgIsGranted = false; + prBssInfo->eBandGranted = BAND_NULL; + prBssInfo->ucPrimaryChannelGranted = 0; +#endif + + cnmMemFree(prAdapter, prCmdBody); + cnmMemFree(prAdapter, prMsgHdr); +} /* end of cnmChMngrAbortPrivilege()*/ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmChMngrHandleChEvent(P_ADAPTER_T prAdapter, P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_EVENT_CH_PRIVILEGE_T prEventBody; + P_MSG_CH_GRANT_T prChResp; + P_BSS_INFO_T prBssInfo; + P_CNM_INFO_T prCnmInfo; + + ASSERT(prAdapter); + ASSERT(prEvent); + if (u4EventBufLen < sizeof(EVENT_CH_PRIVILEGE_T)) { + DBGLOG(CNM, ERROR, "%s: Invalid event length: %d < %d\n", + __func__, u4EventBufLen, sizeof(EVENT_CH_PRIVILEGE_T)); + return; + } + prEventBody = (P_EVENT_CH_PRIVILEGE_T)(prEvent->aucBuffer); + prChResp = (P_MSG_CH_GRANT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_CH_GRANT_T)); + ASSERT(prChResp); + + /* To do: exception handle */ + if (!prChResp) { + DBGLOG(CNM, ERROR, + "ChGrant: fail to get buf (net=%d, token=%d)\n", + prEventBody->ucBssIndex, prEventBody->ucTokenID); + + return; + } + + DBGLOG(CNM, INFO, "ChGrant net=%d token=%d ch=%d sco=%d\n", + prEventBody->ucBssIndex, prEventBody->ucTokenID, + prEventBody->ucPrimaryChannel, prEventBody->ucRfSco); + + ASSERT(prEventBody->ucBssIndex <= MAX_BSS_INDEX); + ASSERT(prEventBody->ucStatus == EVENT_CH_STATUS_GRANT); + if (prEventBody->ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(CNM, + ERROR, + "cnmChMngrHandleChEvent: (ucBssIndex = %d) out-of-bound\n", + prEventBody->ucBssIndex); + return; + } + + prBssInfo = prAdapter->aprBssInfo[prEventBody->ucBssIndex]; + + /* Decide message ID based on network and response status */ + if (IS_BSS_AIS(prBssInfo)) { + prChResp->rMsgHdr.eMsgId = MID_CNM_AIS_CH_GRANT; + } +#if CFG_ENABLE_WIFI_DIRECT + else if (prAdapter->fgIsP2PRegistered && IS_BSS_P2P(prBssInfo)) { + prChResp->rMsgHdr.eMsgId = MID_CNM_P2P_CH_GRANT; + } +#endif + + else { + cnmMemFree(prAdapter, prChResp); + return; + } + + prChResp->ucBssIndex = prEventBody->ucBssIndex; + prChResp->ucTokenID = prEventBody->ucTokenID; + prChResp->ucPrimaryChannel = prEventBody->ucPrimaryChannel; + prChResp->eRfSco = (ENUM_CHNL_EXT_T)prEventBody->ucRfSco; + prChResp->eRfBand = (ENUM_BAND_T)prEventBody->ucRfBand; + prChResp->eRfChannelWidth = + (ENUM_CHANNEL_WIDTH_T)prEventBody->ucRfChannelWidth; + prChResp->ucRfCenterFreqSeg1 = prEventBody->ucRfCenterFreqSeg1; + prChResp->ucRfCenterFreqSeg2 = prEventBody->ucRfCenterFreqSeg2; + prChResp->eReqType = (ENUM_CH_REQ_TYPE_T)prEventBody->ucReqType; + prChResp->eDBDCBand = (ENUM_DBDC_BN_T)prEventBody->ucDBDCBand; + prChResp->u4GrantInterval = prEventBody->u4GrantInterval; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prChResp, + MSG_SEND_METHOD_BUF); + + /* Record current granted BSS for TXM's reference */ + prCnmInfo = &prAdapter->rCnmInfo; + prCnmInfo->ucBssIndex = prEventBody->ucBssIndex; + prCnmInfo->ucTokenID = prEventBody->ucTokenID; + prCnmInfo->fgChGranted = true; +} + +#if (CFG_SUPPORT_DFS_MASTER == 1) +void cnmRadarDetectEvent(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_EVENT_RDD_REPORT_T prEventBody; + P_BSS_INFO_T prBssInfo; + P_MSG_P2P_RADAR_DETECT_T prP2pRddDetMsg; + u8 ucBssIndex; + + ASSERT(prAdapter); + ASSERT(prEvent); + + DBGLOG(CNM, INFO, "cnmRadarDetectEvent.\n"); + if (u4EventBufLen < sizeof(EVENT_RDD_REPORT_T)) { + DBGLOG(CNM, ERROR, "%s: Invalid event length: %d < %d\n", + __func__, u4EventBufLen, sizeof(EVENT_RDD_REPORT_T)); + return; + } + prEventBody = (P_EVENT_RDD_REPORT_T)(prEvent->aucBuffer); + + prP2pRddDetMsg = (P_MSG_P2P_RADAR_DETECT_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(*prP2pRddDetMsg)); + + if (!prP2pRddDetMsg) { + DBGLOG(CNM, ERROR, "cnmMemAlloc for prP2pRddDetMsg failed!\n"); + return; + } + + prP2pRddDetMsg->rMsgHdr.eMsgId = MID_CNM_P2P_RADAR_DETECT; + + for (ucBssIndex = 0; ucBssIndex < BSS_INFO_NUM; ucBssIndex++) { + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if (prBssInfo && prBssInfo->fgIsDfsActive) { + prP2pRddDetMsg->ucBssIndex = ucBssIndex; + break; + } + } + + p2pFuncSetDfsState(DFS_STATE_DETECTED); + + p2pFuncRadarInfoInit(); + + g_rP2pRadarInfo.ucRadarReportMode = prEventBody->ucRadarReportMode; + g_rP2pRadarInfo.ucRddIdx = prEventBody->ucRddIdx; + g_rP2pRadarInfo.ucLongDetected = prEventBody->ucLongDetected; + g_rP2pRadarInfo.ucPeriodicDetected = prEventBody->ucPeriodicDetected; + g_rP2pRadarInfo.ucLPBNum = prEventBody->ucLPBNum; + g_rP2pRadarInfo.ucPPBNum = prEventBody->ucPPBNum; + g_rP2pRadarInfo.ucLPBPeriodValid = prEventBody->ucLPBPeriodValid; + g_rP2pRadarInfo.ucLPBWidthValid = prEventBody->ucLPBWidthValid; + g_rP2pRadarInfo.ucPRICountM1 = prEventBody->ucPRICountM1; + g_rP2pRadarInfo.ucPRICountM1TH = prEventBody->ucPRICountM1TH; + g_rP2pRadarInfo.ucPRICountM2 = prEventBody->ucPRICountM2; + g_rP2pRadarInfo.ucPRICountM2TH = prEventBody->ucPRICountM2TH; + g_rP2pRadarInfo.u4PRI1stUs = prEventBody->u4PRI1stUs; + if (prEventBody->ucLPBNum <= LPB_SIZE) { + kalMemCopy(&g_rP2pRadarInfo.arLpbContent[0], + &prEventBody->arLpbContent[0], + prEventBody->ucLPBNum * sizeof(LONG_PULSE_BUFFER_T)); + } + if (prEventBody->ucPPBNum <= PPB_SIZE) { + kalMemCopy(&g_rP2pRadarInfo.arPpbContent[0], + &prEventBody->arPpbContent[0], + prEventBody->ucPPBNum * + sizeof(PERIODIC_PULSE_BUFFER_T)); + } + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prP2pRddDetMsg, + MSG_SEND_METHOD_BUF); +} + +void cnmCsaDoneEvent(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_BSS_INFO_T prBssInfo; + P_MSG_P2P_CSA_DONE_T prP2pCsaDoneMsg; + u8 ucBssIndex; +#if CFG_SUPPORT_DBDC_TC6 + u8 fgBssDfsActive = false; +#endif + + DBGLOG(CNM, INFO, "cnmCsaDoneEvent.\n"); + + prP2pCsaDoneMsg = (P_MSG_P2P_CSA_DONE_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(*prP2pCsaDoneMsg)); + + if (!prP2pCsaDoneMsg) { + DBGLOG(CNM, ERROR, "cnmMemAlloc for prP2pCsaDoneMsg failed!\n"); + return; + } + + prAdapter->rWifiVar.fgCsaInProgress = false; + + prP2pCsaDoneMsg->rMsgHdr.eMsgId = MID_CNM_P2P_CSA_DONE; + + for (ucBssIndex = 0; ucBssIndex < BSS_INFO_NUM; ucBssIndex++) { + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if (prBssInfo && prBssInfo->fgIsDfsActive) { + prP2pCsaDoneMsg->ucBssIndex = ucBssIndex; +#if CFG_SUPPORT_DBDC_TC6 + fgBssDfsActive = true; +#endif + break; + } + } + +#if CFG_SUPPORT_DBDC_TC6 + prBssInfo = cnmGetp2pSapBssInfo(prAdapter); + if (!fgBssDfsActive && prBssInfo) { + prP2pCsaDoneMsg->ucBssIndex = prBssInfo->ucBssIndex; + DBGLOG(CNM, INFO, "cnmCsaDoneEvent.ucBssIndex=%d\n", + prP2pCsaDoneMsg->ucBssIndex); + } +#endif + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prP2pCsaDoneMsg, + MSG_SEND_METHOD_BUF); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is invoked for P2P or BOW networks + * + * @param (none) + * + * @return true: suggest to adopt the returned preferred channel + * false: No suggestion. Caller should adopt its preference + */ +/*----------------------------------------------------------------------------*/ +u8 cnmPreferredChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, + u8 *pucPrimaryChannel, P_ENUM_CHNL_EXT_T prBssSCO) +{ + P_BSS_INFO_T prBssInfo; + u8 i; + + ASSERT(prAdapter); + ASSERT(prBand); + ASSERT(pucPrimaryChannel); + ASSERT(prBssSCO); + + for (i = 0; i < BSS_INFO_NUM; i++) { + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, i); + + if (prBssInfo) { + if (IS_BSS_AIS(prBssInfo) && + RLM_NET_PARAM_VALID(prBssInfo)) { + *prBand = prBssInfo->eBand; + *pucPrimaryChannel = + prBssInfo->ucPrimaryChannel; + *prBssSCO = prBssInfo->eBssSCO; + + return true; + } + } + } + + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param (none) + * + * @return true: available channel is limited to return value + * false: no limited + */ +/*----------------------------------------------------------------------------*/ +u8 cnmAisInfraChannelFixed(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, + u8 *pucPrimaryChannel) +{ + P_BSS_INFO_T prBssInfo; + u8 i; + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; + + ASSERT(prAdapter); + + if (prWifiVar->u4ScanCtrl & SCN_CTRL_DEFAULT_SCAN_CTRL) { + /*DBGLOG(CNM, INFO, "cnmAisInfraChannelFixed: ByPass AIS channel + * Fix check\n");*/ + return false; + } + + for (i = 0; i < BSS_INFO_NUM; i++) { + prBssInfo = prAdapter->aprBssInfo[i]; + + if (!IS_NET_ACTIVE(prAdapter, i)) { + continue; + } + +#if CFG_ENABLE_WIFI_DIRECT + if (prBssInfo->eNetworkType == NETWORK_TYPE_P2P) { + u8 fgFixedChannel = p2pFuncIsAPMode( + prAdapter->rWifiVar.prP2PConnSettings + [prBssInfo->u4PrivateData]); + + if (fgFixedChannel) { + *prBand = prBssInfo->eBand; + *pucPrimaryChannel = + prBssInfo->ucPrimaryChannel; + + return true; + } + } +#endif + } + + return false; +} + +#if CFG_SUPPORT_CHNL_CONFLICT_REVISE +u8 cnmAisDetectP2PChannel(P_ADAPTER_T prAdapter, P_ENUM_BAND_T prBand, + u8 *pucPrimaryChannel) +{ + u8 i = 0; + P_BSS_INFO_T prBssInfo; +#if CFG_ENABLE_WIFI_DIRECT + for (; i < BSS_INFO_NUM; i++) { + prBssInfo = prAdapter->aprBssInfo[i]; + if (prBssInfo->eNetworkType != NETWORK_TYPE_P2P) { + continue; + } + if (prBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED || + (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT && + prBssInfo->eIntendOPMode == OP_MODE_NUM)) { + *prBand = prBssInfo->eBand; + *pucPrimaryChannel = prBssInfo->ucPrimaryChannel; + return true; + } + } +#endif + return false; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param (none) + * + * @return true: permitted + * false: Not permitted + */ +/*----------------------------------------------------------------------------*/ +u8 cnmAisIbssIsPermitted(P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prBssInfo; + u8 i; + + ASSERT(prAdapter); + + /* P2P device network shall be included */ + for (i = 0; i <= BSS_INFO_NUM; i++) { + prBssInfo = prAdapter->aprBssInfo[i]; + + if (prBssInfo && IS_BSS_ACTIVE(prBssInfo) && + !IS_BSS_AIS(prBssInfo)) { + return false; + } + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param (none) + * + * @return true: permitted + * false: Not permitted + */ +/*----------------------------------------------------------------------------*/ +u8 cnmP2PIsPermitted(P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prBssInfo; + u8 i; + u8 fgBowIsActive; + + ASSERT(prAdapter); + + fgBowIsActive = false; + + for (i = 0; i < BSS_INFO_NUM; i++) { + prBssInfo = prAdapter->aprBssInfo[i]; + + if (prBssInfo && IS_BSS_ACTIVE(prBssInfo)) { + if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + return false; + }else if (IS_BSS_BOW(prBssInfo)) { + fgBowIsActive = true; + } + } + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param (none) + * + * @return true: permitted + * false: Not permitted + */ +/*----------------------------------------------------------------------------*/ +u8 cnmBowIsPermitted(P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prBssInfo; + u8 i; + + ASSERT(prAdapter); + + /* P2P device network shall be included */ + for (i = 0; i <= BSS_INFO_NUM; i++) { + prBssInfo = prAdapter->aprBssInfo[i]; + + if (prBssInfo && IS_BSS_ACTIVE(prBssInfo) && + (IS_BSS_P2P(prBssInfo) || + prBssInfo->eCurrentOPMode == OP_MODE_IBSS)) { + return false; + } + } + + return true; +} + +static u8 cnmGetAPBwPermitted(P_ADAPTER_T prAdapter, u8 ucBssIndex) +{ + P_BSS_INFO_T prBssInfo; + u8 ucAPBandwidth = MAX_BW_160MHZ; + P_BSS_DESC_T prBssDesc = NULL; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + u8 i = 0; + u8 ucOffset = (MAX_BW_80MHZ - CW_80MHZ); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if (IS_BSS_AIS(prBssInfo)) { + /*AIS station mode*/ + prBssDesc = prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc; + } else if (IS_BSS_P2P(prBssInfo)) { + /* P2P mode */ + + for (i = 0; i < BSS_P2P_NUM; i++) { + if (!prAdapter->rWifiVar.aprP2pRoleFsmInfo[i]) { + continue; + } + + if (prAdapter->rWifiVar.aprP2pRoleFsmInfo[i] + ->ucBssIndex == ucBssIndex) { + break; + } + } + + if (i >= BSS_P2P_NUM) { + prP2pRoleFsmInfo = NULL; + } else { + prP2pRoleFsmInfo = + prAdapter->rWifiVar.aprP2pRoleFsmInfo[i]; + + /*only GC need to consider GO's BW*/ + if (!p2pFuncIsAPMode( + prAdapter->rWifiVar.prP2PConnSettings + [prBssInfo->u4PrivateData])) { + prBssDesc = prP2pRoleFsmInfo->rJoinInfo + .prTargetBssDesc; + } + } + } + + if (prBssDesc) { + if (prBssDesc->eChannelWidth == CW_20_40MHZ) { + if ((prBssDesc->eSco == CHNL_EXT_SCA) || + (prBssDesc->eSco == CHNL_EXT_SCB)) { + ucAPBandwidth = MAX_BW_40MHZ; + }else{ + ucAPBandwidth = MAX_BW_20MHZ; + } + } else { + ucAPBandwidth = prBssDesc->eChannelWidth + ucOffset; + } + } + + return ucAPBandwidth; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param (none) + * + * @return true: permitted + * false: Not permitted + */ +/*----------------------------------------------------------------------------*/ +u8 cnmBss40mBwPermitted(P_ADAPTER_T prAdapter, u8 ucBssIndex) +{ + ASSERT(prAdapter); + + /* Note: To support real-time decision instead of current + * activated-time, the STA roaming case shall be considered about + * synchronization problem. Another variable fgAssoc40mBwAllowed is + * added to represent HT capability when association + */ + + /* Decide max bandwidth by feature option */ + if (cnmGetBssMaxBw(prAdapter, ucBssIndex) < MAX_BW_40MHZ) { + return false; + } + + /*check AP or GO capbility for Station or GC */ + if (cnmGetAPBwPermitted(prAdapter, ucBssIndex) < MAX_BW_40MHZ) { + return false; + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param (none) + * + * @return true: permitted + * false: Not permitted + */ +/*----------------------------------------------------------------------------*/ +u8 cnmBss80mBwPermitted(P_ADAPTER_T prAdapter, u8 ucBssIndex) +{ + ASSERT(prAdapter); + + /* Note: To support real-time decision instead of current + * activated-time, the STA roaming case shall be considered about + * synchronization problem. Another variable fgAssoc40mBwAllowed is + * added to represent HT capability when association + */ + + /* Check 40Mhz first */ + if (!cnmBss40mBwPermitted(prAdapter, ucBssIndex)) { + return false; + } + + /* Decide max bandwidth by feature option */ + if (cnmGetBssMaxBw(prAdapter, ucBssIndex) < MAX_BW_80MHZ) { + return false; + } + + /*check AP or GO capbility for Station or GC */ + if (cnmGetAPBwPermitted(prAdapter, ucBssIndex) < MAX_BW_80MHZ) { + return false; + } + + return true; +} + +u8 cnmGetBssMaxBw(P_ADAPTER_T prAdapter, u8 ucBssIndex) +{ + P_BSS_INFO_T prBssInfo; + u8 ucMaxBandwidth = MAX_BW_80_80_MHZ; /*chip capability*/ + P_BSS_DESC_T prBssDesc = NULL; + ENUM_BAND_T eBand = BAND_NULL; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo = + (P_P2P_CONNECTION_REQ_INFO_T)NULL; +#if (CFG_SUPPORT_SINGLE_SKU == 1) + u8 ucChannelBw = MAX_BW_80_80_MHZ; +#endif + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if (IS_BSS_AIS(prBssInfo)) { + /* STA mode */ + + /*should check Bss_info could be used or not + * the info might not be trustable before state3 + */ + prBssDesc = prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc; + + if (prBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) { + eBand = prBssInfo->eBand; + DBGLOG(CNM, + INFO, + "use connected bcn eBand %d target prBssDesc %p\n", + eBand, + prBssDesc); + } else { + if (prBssDesc) { + eBand = prBssDesc->eBand; + DBGLOG(CNM, INFO, "use target bcn eBand %d\n", + eBand); + } else { + eBand = prBssInfo->eBand; + DBGLOG(CNM, INFO, "use bcn eBand %d\n", eBand); + } + } + + ASSERT(eBand != BAND_NULL); + + if (eBand == BAND_2G4) { + ucMaxBandwidth = prAdapter->rWifiVar.ucSta2gBandwidth; + }else{ + ucMaxBandwidth = prAdapter->rWifiVar.ucSta5gBandwidth; + } + + if (ucMaxBandwidth > prAdapter->rWifiVar.ucStaBandwidth) { + ucMaxBandwidth = prAdapter->rWifiVar.ucStaBandwidth; + } + } else if (IS_BSS_P2P(prBssInfo)) { + prP2pRoleFsmInfo = + p2pFuncGetRoleByBssIdx(prAdapter, ucBssIndex); + if (!prAdapter->rWifiVar.ucApChnlDefFromCfg && + prP2pRoleFsmInfo && + prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + prP2pConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo); + ucMaxBandwidth = prP2pConnReqInfo->eChnlBw; + } else { + /* AP mode */ + if (p2pFuncIsAPMode( + prAdapter->rWifiVar.prP2PConnSettings + [prBssInfo->u4PrivateData])) { + if (prBssInfo->eBand == BAND_2G4) { + ucMaxBandwidth = + prAdapter->rWifiVar + .ucAp2gBandwidth; + } else { + ucMaxBandwidth = + prAdapter->rWifiVar + .ucAp5gBandwidth; + } + + if (ucMaxBandwidth > + prAdapter->rWifiVar.ucApBandwidth) { + ucMaxBandwidth = prAdapter->rWifiVar + .ucApBandwidth; + } + } + /* P2P mode */ + else { + if (prBssInfo->eBand == BAND_2G4) { + ucMaxBandwidth = + prAdapter->rWifiVar + .ucP2p2gBandwidth; + } else { + ucMaxBandwidth = + prAdapter->rWifiVar + .ucP2p5gBandwidth; + } + } + } + } + +#if (CFG_SUPPORT_SINGLE_SKU == 1) + if (IS_BSS_AIS(prBssInfo) && + (prBssInfo->eConnectionState != PARAM_MEDIA_STATE_CONNECTED) && + prBssDesc) { + ucChannelBw = rlmDomainGetChannelBw(prBssDesc->ucChannelNum); + DBGLOG(CNM, INFO, "target channel %d ucChannelBw %d\n", + prBssDesc->ucChannelNum, ucChannelBw); + } else { // P2P and IS_BSS_AIS(prBssInfo) in connected state + ucChannelBw = + rlmDomainGetChannelBw(prBssInfo->ucPrimaryChannel); + DBGLOG(CNM, INFO, "channel %d ucChannelBw %d\n", + prBssInfo->ucPrimaryChannel, ucChannelBw); + } + if (ucMaxBandwidth > ucChannelBw) { + ucMaxBandwidth = ucChannelBw; + } +#endif + + DBGLOG(CNM, INFO, "ucMaxBandwidth %d\n", ucMaxBandwidth); + + return ucMaxBandwidth; +} + +u8 cnmGetBssMaxBwToChnlBW(P_ADAPTER_T prAdapter, u8 ucBssIndex) +{ + u8 ucMaxBandwidth = cnmGetBssMaxBw(prAdapter, ucBssIndex); + return ucMaxBandwidth == MAX_BW_20MHZ ? ucMaxBandwidth : + (ucMaxBandwidth - 1); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Search available HW ID and BSS_INFO structure and initialize + * these parameters, i.e., fgIsNetActive, ucBssIndex, eNetworkType + * and ucOwnMacIndex + * + * @param (none) + * + * @return + */ +/*----------------------------------------------------------------------------*/ +P_BSS_INFO_T cnmGetBssInfoAndInit(P_ADAPTER_T prAdapter, + ENUM_NETWORK_TYPE_T eNetworkType, + u8 fgIsP2pDevice) +{ + P_BSS_INFO_T prBssInfo; + u8 ucBssIndex, ucOwnMacIdx; + + ASSERT(prAdapter); + + /*specific case for p2p device scan*/ + if (eNetworkType == NETWORK_TYPE_P2P && fgIsP2pDevice) { + prBssInfo = prAdapter->aprBssInfo[P2P_DEV_BSS_INDEX]; + + prBssInfo->fgIsInUse = true; + prBssInfo->ucBssIndex = P2P_DEV_BSS_INDEX; + prBssInfo->eNetworkType = eNetworkType; + prBssInfo->ucOwnMacIndex = HW_BSSID_NUM; +#if CFG_SUPPORT_PNO + prBssInfo->fgIsPNOEnable = false; + prBssInfo->fgIsNetRequestInActive = false; +#endif + return prBssInfo; + } + + /*reserve ownMAC0 for MBSS*/ + ucOwnMacIdx = (eNetworkType == NETWORK_TYPE_MBSS) ? 0 : 1; + + /* Find available HW set with the order 1,2,..*/ + do { + for (ucBssIndex = 0; ucBssIndex < BSS_INFO_NUM; ucBssIndex++) { + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + + if (prBssInfo && prBssInfo->fgIsInUse && + ucOwnMacIdx == prBssInfo->ucOwnMacIndex) { + break; + } + } + + if (ucBssIndex >= BSS_INFO_NUM) { + /* No hit the ucOwnMacIndex could be assigned to this + * new bss */ + break; + } + } while (++ucOwnMacIdx < HW_BSSID_NUM); + + /*should not dispatch P2P_DEV_BSS_INDEX (HW_BSSID_NUM)to general bss, + * It means total BSS_INFO_NUM BSS are created, + * no more reseve for MBSS + */ + if (ucOwnMacIdx == HW_BSSID_NUM) { + for (ucBssIndex = 0; ucBssIndex < BSS_INFO_NUM; ucBssIndex++) { + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + + /*If the Bss was alredy assigned, and in use*/ + if (prBssInfo && prBssInfo->fgIsInUse && + prBssInfo->ucOwnMacIndex == 0) { + break; + } + } + + if (ucBssIndex >= BSS_INFO_NUM) { + /*there is no NETWORK_TYPE_MBSS used before */ + DBGLOG(INIT, + WARN, + "[Warning] too much Bss in use, take reserve OwnMac(%d)for usage!\n", + ucOwnMacIdx); + ucOwnMacIdx = 0; + } + } + + /* Find available BSS_INFO */ + for (ucBssIndex = 0; ucBssIndex < BSS_INFO_NUM; ucBssIndex++) { + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + + if (prBssInfo && !prBssInfo->fgIsInUse) { + prBssInfo->fgIsInUse = true; + prBssInfo->ucBssIndex = ucBssIndex; + prBssInfo->eNetworkType = eNetworkType; + prBssInfo->ucOwnMacIndex = ucOwnMacIdx; +#if (CFG_HW_WMM_BY_BSS == 1) + prBssInfo->ucWmmQueSet = DEFAULT_HW_WMM_INDEX; + prBssInfo->fgIsWmmInited = false; +#endif + break; + } + } + + if (ucOwnMacIdx >= HW_BSSID_NUM || ucBssIndex >= BSS_INFO_NUM) { + prBssInfo = NULL; + } +#if CFG_SUPPORT_PNO + if (prBssInfo) { + prBssInfo->fgIsPNOEnable = false; + prBssInfo->fgIsNetRequestInActive = false; + } +#endif + +#if CFG_SUPPORT_DFS + if (prBssInfo) { + cnmTimerInitTimer(prAdapter, &prBssInfo->rCsaTimer, + (PFN_MGMT_TIMEOUT_FUNC)rlmCsaTimeout, + (unsigned long)ucBssIndex); + + rlmResetCSAParams(prBssInfo); + } +#endif + + return prBssInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Search available HW ID and BSS_INFO structure and initialize + * these parameters, i.e., ucBssIndex, eNetworkType and ucOwnMacIndex + * + * @param (none) + * + * @return + */ +/*----------------------------------------------------------------------------*/ +void cnmFreeBssInfo(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + ASSERT(prAdapter); + ASSERT(prBssInfo); + +#if CFG_SUPPORT_DFS + cnmTimerStopTimer(prAdapter, &prBssInfo->rCsaTimer); +#endif + + prBssInfo->fgIsInUse = false; +} + +#if CFG_SUPPORT_DBDC +void cnmInitDbdcSetting(IN P_ADAPTER_T prAdapter) +{ +#if CFG_SUPPORT_DBDC_TC6 + P_CNM_INFO_T prCnmInfo; + + prCnmInfo = &prAdapter->rCnmInfo; + prCnmInfo->fgSkipDbdcDisable = false; +#endif + + /* Parameter decision */ + switch (prAdapter->rWifiVar.ucDbdcMode) { + case DBDC_MODE_DISABLED: + case DBDC_MODE_DYNAMIC: + cnmUpdateDbdcSetting(prAdapter, false); +#if CFG_SUPPORT_DBDC_TC6 + LINK_INITIALIZE(&prCnmInfo->rDbdcSwitchGuradPendingReqList); +#endif + break; + + case DBDC_MODE_STATIC: + cnmUpdateDbdcSetting(prAdapter, true); + break; + + default: + break; + } +} + +void cnmUpdateDbdcSetting(IN P_ADAPTER_T prAdapter, IN u8 fgDbdcEn) +{ + u8 ucWmmSetBitmap = 0; + CMD_DBDC_SETTING_T rDbdcSetting; + P_CMD_DBDC_SETTING_T prCmdBody; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u8 ucBssIndex; + P_BSS_INFO_T prBssInfo; +#if !CFG_SUPPORT_DBDC_TC6 + u8 ucMaxBw; +#else + P_AIS_FSM_INFO_T prAisFsmInfo; +#endif + + DBGLOG(CNM, STATE, "DBDC %s\n", fgDbdcEn ? "Enable" : "Disable"); + +#if CFG_SUPPORT_DBDC_TC6 + prAisFsmInfo = &(prAdapter->rWifiVar.rAisFsmInfo); +#endif + + /* Parameter decision */ +#if (CFG_HW_WMM_BY_BSS == 1) + if (fgDbdcEn) { + u8 ucWmmSetBitmapPerBSS; + /* + * As DBDC enabled, for BSS use 2.4g Band, assign related + * WmmGroupSet bitmask to 1. This is used to indicate the + * WmmGroupSet is associated to Band#1 (otherwise, use for + * band#0) + */ + for (ucBssIndex = 0; ucBssIndex < BSS_INFO_NUM; ucBssIndex++) { + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + + if (!prBssInfo || prBssInfo->fgIsInUse == false) { + continue; + } + + if (prBssInfo->eBand == BAND_2G4) { + ucWmmSetBitmapPerBSS = prBssInfo->ucWmmQueSet; + ucWmmSetBitmap |= BIT(ucWmmSetBitmapPerBSS); + } + } + ucWmmSetBitmap |= BIT(MAX_HW_WMM_INDEX); /* For P2P Device*/ + } +#else + if (fgDbdcEn) { + ucWmmSetBitmap |= BIT(DBDC_2G_WMM_INDEX); + } +#endif + + /* Send event to FW */ + prCmdBody = (P_CMD_DBDC_SETTING_T)&rDbdcSetting; + + kalMemZero(prCmdBody, sizeof(CMD_DBDC_SETTING_T)); + + prCmdBody->ucDbdcEn = fgDbdcEn; + prCmdBody->ucWmmBandBitmap = ucWmmSetBitmap; + + if (!fgDbdcEn) { + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_SET_DBDC_PARMS, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_DBDC_SETTING_T), /* u4SetQueryInfoLen + */ + (u8 *)prCmdBody, /* pucInfoBuffer + */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ ); + } + + for (ucBssIndex = 0; ucBssIndex <= HW_BSSID_NUM; ucBssIndex++) { + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + + /* TC6 DBDC Case: Switch DBDC mode, change Nss and reconnect to + * AP */ + if (IS_BSS_AIS(prBssInfo) && + (ucBssIndex == prAdapter->prAisBssInfo->ucBssIndex)) { + /* Update AIS NSS */ + prAdapter->rWifiVar.fgDbDcModeEn = fgDbdcEn; + if (aisBssChangeNSS(prAdapter, fgDbdcEn) && + kalGetMediaStateIndicated(prAdapter->prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED && + !timerPendingTimer(&( + prAisFsmInfo + -> + rIndicationOfDisconnectTimer))) { + DBGLOG(CNM, STATE, + "[DBDC] station mode trigger reconnect\n"); + /* start DBDC reconnect countdown timer */ + cnmTimerStartTimer( + prAdapter, + &prAdapter->rWifiVar + .rDBDCReconnectCountDown, + DBDC_AIS_REASSOC_COUNTDOWN_TIME); + prBssInfo->fgReConnBypassScan = 1; + prBssInfo->u2DeauthReason = + BEACON_TIMEOUT_REASON_DUE_2_DBDC_RECONNECT; + + if (!timerPendingTimer( + &prAdapter->rWifiVar.rAisFsmInfo + .rBeaconLostTimer)) { + cnmTimerStartTimer( + prAdapter, + &prAdapter->rWifiVar.rAisFsmInfo + .rBeaconLostTimer, + prAdapter->rWifiVar + .ucWaitConnect * + MSEC_PER_SEC); + } + + kalIndicateStatusAndComplete( + prAdapter->prGlueInfo, + WLAN_STATUS_BEACON_TIMEOUT, NULL, 0); + } + DBGLOG(CNM, + STATE, + "[DBDC %s] station mode is on and NSS:%d, AIS BssIndex:%d\n", + fgDbdcEn ? "Enable" : "Disable", + prBssInfo->ucNss, + prAdapter->prAisBssInfo->ucBssIndex); + } + } + + if (fgDbdcEn) { + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_SET_DBDC_PARMS, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_DBDC_SETTING_T), /* u4SetQueryInfoLen + */ + (u8 *)prCmdBody, /* pucInfoBuffer + */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ ); + } + + /*DBGLOG(CNM, INFO, "DBDC CMD status %u\n", rStatus);*/ + + if (rStatus == WLAN_STATUS_SUCCESS || rStatus == WLAN_STATUS_PENDING) { + for (ucBssIndex = 0; ucBssIndex <= HW_BSSID_NUM; ucBssIndex++) { + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + + if (prBssInfo->eBand == BAND_2G4) { + if (fgDbdcEn) { + prBssInfo->eDBDCBand = ENUM_BAND_1; + }else{ + prBssInfo->eDBDCBand = ENUM_BAND_0; + } + } + } + } +} + +void cnmGetDbdcCapability(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN ENUM_BAND_T eRfBand, IN u8 ucPrimaryChannel, + IN u8 ucNss, OUT P_CNM_DBDC_CAP_T prDbdcCap) +{ + if (!prDbdcCap) { + return; + } + + /* BSS index */ + prDbdcCap->ucBssIndex = ucBssIndex; + +#if (CFG_HW_WMM_BY_BSS == 0) + /* WMM set */ + if (eRfBand == BAND_5G) { + prDbdcCap->ucWmmSetIndex = DBDC_5G_WMM_INDEX; + } else { + prDbdcCap->ucWmmSetIndex = + (prAdapter->rWifiVar.ucDbdcMode == DBDC_MODE_DISABLED) ? + DBDC_5G_WMM_INDEX : + DBDC_2G_WMM_INDEX; + } +#endif + + /* Nss & band 0/1 */ + switch (prAdapter->rWifiVar.ucDbdcMode) { + case DBDC_MODE_DISABLED: + /* DBDC is disabled, all BSS run on band 0 */ + if (wlanGetSupportNss(prAdapter, ucBssIndex) < ucNss) { + prDbdcCap->ucNss = + wlanGetSupportNss(prAdapter, ucBssIndex); + } else { + prDbdcCap->ucNss = ucNss; + } + break; + + case DBDC_MODE_STATIC: + /* Static DBDC mode, 1SS only */ + prDbdcCap->ucNss = 1; + break; + + case DBDC_MODE_DYNAMIC: + if (prAdapter->rWifiVar.fgDbDcModeEn) { + prDbdcCap->ucNss = 1; + } else { + prDbdcCap->ucNss = + wlanGetSupportNss(prAdapter, ucBssIndex); + } + break; + + default: + break; + } + DBGLOG(CNM, INFO, "[DBDC] mode:%d enable:%s NSS:%d \n", + prAdapter->rWifiVar.ucDbdcMode, + prAdapter->rWifiVar.fgDbDcModeEn ? "Enable" : "Disable", + prDbdcCap->ucNss); +} + +void cnmDbdcEnableDecision(IN P_ADAPTER_T prAdapter, IN u8 ucChangedBssIndex, + IN ENUM_BAND_T eRfBand) +{ + P_BSS_INFO_T prBssInfo; + u8 ucBssIndex; + + DBGLOG(CNM, STATE, "[DBDC][Enable Decison] mode:%d enable:%s \n", + prAdapter->rWifiVar.ucDbdcMode, + prAdapter->rWifiVar.fgDbDcModeEn ? "Enable" : "Disable"); + + if ((prAdapter->rWifiVar.ucDbdcMode != DBDC_MODE_DYNAMIC) && + (prAdapter->rWifiVar.ucDbdcMode != DBDC_MODE_STATIC)) { + return; + } + + if (prAdapter->rWifiVar.fgDbDcModeEn) { + if (timerPendingTimer( + &prAdapter->rWifiVar.rDBDCSwitchGuardTimer)) { + /* update timer for connection retry */ + DBGLOG(CNM, INFO, "DBDC guard time extend\n"); + cnmTimerStopTimer( + prAdapter, + &prAdapter->rWifiVar.rDBDCSwitchGuardTimer); + cnmTimerStartTimer( + prAdapter, + &prAdapter->rWifiVar.rDBDCSwitchGuardTimer, + DBDC_SWITCH_GUARD_TIME); + } + +#if CFG_SUPPORT_DBDC_TC6 + if (timerPendingTimer( + &prAdapter->rWifiVar.rDBDCReconnectCountDown)) { + DBGLOG(CNM, INFO, + "DBDC reconnect timer protection stop\n"); + cnmTimerStopTimer( + prAdapter, + &prAdapter->rWifiVar.rDBDCReconnectCountDown); + } + + if (timerPendingTimer( + &prAdapter->rWifiVar.rDBDCDisableCountdownTimer)) { + DBGLOG(CNM, + INFO, + "DBDC disable count down stop for SoftAP re-start\n"); + cnmTimerStopTimer( + prAdapter, + &prAdapter->rWifiVar.rDBDCDisableCountdownTimer); + } +#endif + + /* DBDC is already ON, so renew WMM band information only */ + cnmUpdateDbdcSetting(prAdapter, true); + return; + } + + if (timerPendingTimer(&prAdapter->rWifiVar.rDBDCSwitchGuardTimer)) { + cnmTimerStopTimer(prAdapter, + &prAdapter->rWifiVar.rDBDCSwitchGuardTimer); + + cnmUpdateDbdcSetting(prAdapter, true); + + /* Extend guard timer for connection retry */ + DBGLOG(CNM, STATE, + "DBDC switch guard time extend for SoftAP Re-Start\n"); + cnmTimerStartTimer(prAdapter, + &prAdapter->rWifiVar.rDBDCSwitchGuardTimer, + DBDC_SWITCH_GUARD_TIME); + return; + } + + if (eRfBand != BAND_2G4 && eRfBand != BAND_5G) { + return; + } + + for (ucBssIndex = 0; ucBssIndex < HW_BSSID_NUM; ucBssIndex++) { + if (ucBssIndex == ucChangedBssIndex) { + continue; + } + + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + + if (!prBssInfo->fgIsInUse || !prBssInfo->fgIsNetActive || + (prBssInfo->eConnectionState != + PARAM_MEDIA_STATE_CONNECTED && + prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT)) { + continue; + } + + if (prBssInfo->eBand != BAND_2G4 && prBssInfo->eBand != BAND_5G) { + continue; + } + + if (prBssInfo->eBand != eRfBand) { + /* Enable DBDC */ + + /* if disable timer exist, close it*/ + if (timerPendingTimer( + &prAdapter->rWifiVar + .rDBDCDisableCountdownTimer)) { + cnmTimerStopTimer( + prAdapter, + &prAdapter->rWifiVar + .rDBDCDisableCountdownTimer); + } + + cnmUpdateDbdcSetting(prAdapter, true); + + /* Start Switch Guard Time */ + DBGLOG(CNM, INFO, + "Start DBDC Switch Guard timer for DBDC Enable\n"); + cnmTimerStartTimer( + prAdapter, + &prAdapter->rWifiVar.rDBDCSwitchGuardTimer, + DBDC_SWITCH_GUARD_TIME); + return; + } + } +} + +void cnmDbdcDisableDecision(IN P_ADAPTER_T prAdapter, IN u8 ucChangedBssIndex) +{ + P_BSS_INFO_T prBssInfo; + u8 ucBssIndex; + ENUM_BAND_T eBandCompare; +#if CFG_SUPPORT_DBDC_TC6 + P_CNM_INFO_T prCnmInfo; +#endif + + DBGLOG(CNM, STATE, "[DBDC][Disable Decision] mode:%d enable:%s \n", + prAdapter->rWifiVar.ucDbdcMode, + prAdapter->rWifiVar.fgDbDcModeEn ? "Enable" : "Disable"); + +#if CFG_SUPPORT_DBDC_TC6 + prCnmInfo = &prAdapter->rCnmInfo; +#endif + + if (prAdapter->rWifiVar.ucDbdcMode != DBDC_MODE_DYNAMIC) { + return; + } + + if (!prAdapter->rWifiVar.fgDbDcModeEn) { + DBGLOG(CNM, STATE, "[DBDC] Keep DBDC status [%s]\n", + prAdapter->rWifiVar.fgDbDcModeEn ? "Enable" : "Disable"); + return; + } + + if (timerPendingTimer(&prAdapter->rWifiVar.rDBDCDisableCountdownTimer)) { + return; + } + + if (timerPendingTimer(&prAdapter->rWifiVar.rDBDCSwitchGuardTimer)) { + return; + } + +#if CFG_SUPPORT_DBDC_TC6 + if (timerPendingTimer(&prAdapter->rWifiVar.rDBDCReconnectCountDown)) { + return; + } + +#endif + + eBandCompare = BAND_NULL; + for (ucBssIndex = 0; ucBssIndex < HW_BSSID_NUM; ucBssIndex++) { + if (ucBssIndex == ucChangedBssIndex) { + continue; + } + + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + + if (!prBssInfo->fgIsInUse || !prBssInfo->fgIsNetActive || + (prBssInfo->eConnectionState != + PARAM_MEDIA_STATE_CONNECTED && + prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT)) { + continue; + } + + if (prBssInfo->eBand != BAND_2G4 && prBssInfo->eBand != BAND_5G) { + continue; + } + + if (eBandCompare == BAND_NULL) { + eBandCompare = prBssInfo->eBand; + continue; + } + + if (prBssInfo->eBand != eBandCompare) { + /*no need to disable DBDC*/ + return; + } + } + +#if CFG_SUPPORT_DBDC_TC6 + if (prCnmInfo->fgSkipDbdcDisable) { + DBGLOG(CNM, INFO, "Skip DBDC disable for Beacon Timeout\n"); + cnmTimerStartTimer( + prAdapter, &prAdapter->rWifiVar.rDBDCReconnectCountDown, + DBDC_AIS_BCN_TIMEOUT_RECONNECT_COUNTDOWN_TIME); + } else +#endif + { + /* start DBDC disable countdown timer */ + DBGLOG(CNM, INFO, "Start DBDC disable countdown timer\n"); + cnmTimerStartTimer( + prAdapter, + &prAdapter->rWifiVar.rDBDCDisableCountdownTimer, + DBDC_DISABLE_COUNTDOWN_TIME); + } +} + +void cnmDbdcDecision(IN P_ADAPTER_T prAdapter, IN unsigned long plParamPtr) +{ + P_BSS_INFO_T prBssInfo; + u8 ucBssIndex; + ENUM_BAND_T eBandCompare; +#if CFG_SUPPORT_DBDC_TC6 + P_MSG_CH_REQ_T prPendingMsg; + P_MSG_HDR_T prMsgHdr; +#endif + + DBGLOG(CNM, STATE, "[DBDC] mode:%d enable:%s \n", + prAdapter->rWifiVar.ucDbdcMode, + prAdapter->rWifiVar.fgDbDcModeEn ? "Enable" : "Disable"); + + if (prAdapter->rWifiVar.ucDbdcMode != DBDC_MODE_DYNAMIC) { + return; + } + + if (plParamPtr == DBDC_DECISION_TIMER_SWITCH_GUARD_TIME) { + DBGLOG(CNM, INFO, + "DBDC timer timeout : switch guard time end\n"); + +#if CFG_SUPPORT_DBDC_TC6 + while (!LINK_IS_EMPTY( + &prAdapter->rCnmInfo. + rDbdcSwitchGuradPendingReqList)) { + LINK_REMOVE_HEAD( + &prAdapter->rCnmInfo + .rDbdcSwitchGuradPendingReqList, + prMsgHdr, P_MSG_HDR_T); + + if (prMsgHdr) { + prPendingMsg = (P_MSG_CH_REQ_T)prMsgHdr; + + DBGLOG(CNM, + STATE, + "[DBDC] ChReq: send queued REQ of BSS %u Token %u\n", + prPendingMsg->ucBssIndex, + prPendingMsg->ucTokenID); + + cnmChMngrRequestPrivilege( + prAdapter, &prPendingMsg->rMsgHdr); + } else { + ASSERT(0); + } + } +#endif + } else if (plParamPtr == DBDC_DECISION_TIMER_DISABLE_COUNT_DOWN) { + DBGLOG(CNM, INFO, + "DBDC timer timeout : disable countdown finish\n"); + } +#if CFG_SUPPORT_DBDC_TC6 + else if (plParamPtr == DBDC_DECISION_TIMER_RECONNECT_COUNT_DOWN) { + DBGLOG(CNM, INFO, + "DBDC timer timeout : reconnect countdown finish\n"); + return; + } else if (plParamPtr == DBDC_DECISION_TIMER_AIS_CONNECT_COUNT_DOWN) { + DBGLOG(CNM, INFO, + "DBDC timer timeout : AIS connect countdown finish\n"); + return; + } +#endif + + eBandCompare = BAND_NULL; + for (ucBssIndex = 0; ucBssIndex < HW_BSSID_NUM; ucBssIndex++) { + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + + if (!prBssInfo->fgIsInUse || !prBssInfo->fgIsNetActive || + (prBssInfo->eConnectionState != + PARAM_MEDIA_STATE_CONNECTED && + prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT)) { + continue; + } + + if (prBssInfo->eBand != BAND_2G4 && prBssInfo->eBand != BAND_5G) { + continue; + } + + if (eBandCompare == BAND_NULL) { + eBandCompare = prBssInfo->eBand; + continue; + } + + if (prBssInfo->eBand != eBandCompare) { + DBGLOG(CNM, INFO, "exist two different bands\n"); + if (!prAdapter->rWifiVar.fgDbDcModeEn) { +#if CFG_SUPPORT_DBDC_TC6 + if (timerPendingTimer( + &prAdapter->rWifiVar + .rDBDCReconnectCountDown)) { + DBGLOG(CNM, + INFO, + "DBDC-ReconnectCountDown still on, skip DBDC Enable this time\n"); + return; + } + + if (timerPendingTimer( + &prAdapter->rWifiVar + .rDBDCAisConnectCountDown)) { + DBGLOG(CNM, + INFO, + "DBDC-AISconnectCountDown still on, skip DBDC Enable this time\n"); + return; + } +#endif + /* DBDC Enable */ + cnmUpdateDbdcSetting(prAdapter, true); + DBGLOG(CNM, + STATE, + "Start DBDC Switch Guard timer for DBDC Enable\n"); + cnmTimerStartTimer( + prAdapter, + &prAdapter->rWifiVar + .rDBDCSwitchGuardTimer, + DBDC_SWITCH_GUARD_TIME); + } + return; + } + } + + if (prAdapter->rWifiVar.fgDbDcModeEn) { +#if CFG_SUPPORT_DBDC_TC6 + if (timerPendingTimer( + &prAdapter->rWifiVar.rDBDCReconnectCountDown)) { + DBGLOG(CNM, + INFO, + "DBDC-ReconnectCountDown still on, skip DBDC Disable this time\n"); + return; + } + + if (timerPendingTimer( + &prAdapter->rWifiVar.rDBDCAisConnectCountDown)) { + DBGLOG(CNM, + INFO, + "DBDC-AISconnectCountDown still on, skip DBDC Disable this time\n"); + return; + } +#endif + /* DBDC Disable */ + cnmUpdateDbdcSetting(prAdapter, false); + DBGLOG(CNM, STATE, + "Start DBDC Switch Guard timer for DBDC Disable\n"); + cnmTimerStartTimer(prAdapter, + &prAdapter->rWifiVar.rDBDCSwitchGuardTimer, + DBDC_SWITCH_GUARD_TIME); + } + return; +} + +#endif + +#if (CFG_HW_WMM_BY_BSS == 1) +/*----------------------------------------------------------------------------*/ +/*! + * @brief Search available HW WMM index. + * + * @param (none) + * + * @return + */ +/*----------------------------------------------------------------------------*/ +u8 cnmWmmIndexDecision(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) +{ + u8 ucWmmIndex; + + for (ucWmmIndex = 0; ucWmmIndex < HW_WMM_NUM; ucWmmIndex++) { + if (prBssInfo && prBssInfo->fgIsInUse && + prBssInfo->fgIsWmmInited == false) { + if (!(prAdapter->ucHwWmmEnBit & BIT(ucWmmIndex))) { + prAdapter->ucHwWmmEnBit |= BIT(ucWmmIndex); + prBssInfo->fgIsWmmInited = true; + break; + } + } + } + return (ucWmmIndex < HW_WMM_NUM) ? ucWmmIndex : MAX_HW_WMM_INDEX; +} +/*----------------------------------------------------------------------------*/ +/*! + * @brief Free BSS HW WMM index. + * + * @param (none) + * + * @return None + */ +/*----------------------------------------------------------------------------*/ +void cnmFreeWmmIndex(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) +{ + prAdapter->ucHwWmmEnBit &= (~BIT(prBssInfo->ucWmmQueSet)); + prBssInfo->ucWmmQueSet = DEFAULT_HW_WMM_INDEX; + prBssInfo->fgIsWmmInited = false; +} +#endif + +#if CFG_SUPPORT_DBDC_TC6 +u8 cnmSapIsConcurrent(IN P_ADAPTER_T prAdapter) +{ + if (prAdapter) { + return prAdapter->u4P2pMode == RUNNING_P2P_AP_MODE; + }else{ + return false; + } +} + +u8 cnmSapIsActive(IN P_ADAPTER_T prAdapter) +{ + return cnmGetp2pSapBssInfo(prAdapter) != NULL; +} + +P_BSS_INFO_T cnmGetp2pSapBssInfo(IN P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prBssInfo; + u8 i; + + if (!prAdapter) { + return NULL; + } + + for (i = 0; i < BSS_INFO_NUM; i++) { + prBssInfo = prAdapter->aprBssInfo[i]; + + if (prBssInfo && IS_BSS_P2P(prBssInfo) && + p2pFuncIsAPMode(prAdapter->rWifiVar.prP2PConnSettings + [prBssInfo->u4PrivateData]) && + IS_NET_PWR_STATE_ACTIVE(prAdapter, prBssInfo->ucBssIndex)) { + return prBssInfo; + } + } + + return NULL; +} + +void cnmSapChannelSwitchReq(IN P_ADAPTER_T prAdapter, + IN P_RF_CHANNEL_INFO_T prRfChannelInfo, + IN u8 ucRoleIdx) +{ + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + P_MSG_P2P_SET_NEW_CHANNEL_T prP2pSetNewChannelMsg = + (P_MSG_P2P_SET_NEW_CHANNEL_T)NULL; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo = + (P_P2P_CONNECTION_REQ_INFO_T)NULL; + u8 ucBssIdx = 0; + + DBGLOG(P2P, INFO, "role(%d) c=%d b=%d opw=%d\n", ucRoleIdx, + prRfChannelInfo->ucChannelNum, prRfChannelInfo->eBand, + prRfChannelInfo->ucChnlBw); + + /* Free chandef buffer */ + if (!prGlueInfo) { + DBGLOG(P2P, WARN, "glue info is not active\n"); + return; + } + prGlueP2pInfo = prGlueInfo->prP2PInfo[ucRoleIdx]; + if (!prGlueP2pInfo) { + DBGLOG(P2P, WARN, "p2p glue info is not active\n"); + return; + } + if (prGlueP2pInfo->chandef != NULL) { + if (prGlueP2pInfo->chandef->chan) { + cnmMemFree(prGlueInfo->prAdapter, + prGlueP2pInfo->chandef->chan); + prGlueP2pInfo->chandef->chan = NULL; + } + cnmMemFree(prGlueInfo->prAdapter, prGlueP2pInfo->chandef); + prGlueP2pInfo->chandef = NULL; + } + + /* Fill conn info */ + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, ucRoleIdx); + if (!prP2pRoleFsmInfo) { + return; + } + + prP2pConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo); + if (!prP2pConnReqInfo) { + return; + } + + prP2pConnReqInfo->rChannelInfo.ucChannelNum = + prRfChannelInfo->ucChannelNum; + prP2pConnReqInfo->rChannelInfo.eBand = prRfChannelInfo->eBand; + prP2pConnReqInfo->eChnlBw = prRfChannelInfo->ucChnlBw; + + p2pFuncSetDfsState(DFS_STATE_INACTIVE); + + if (p2pFuncRoleToBssIdx(prAdapter, ucRoleIdx, &ucBssIdx) != + WLAN_STATUS_SUCCESS) { + DBGLOG(P2P, WARN, "Incorrect role index"); + return; + } + + /* Set CSA IE */ + prAdapter->rWifiVar.fgCsaInProgress = true; + prAdapter->rWifiVar.ucChannelSwitchMode = 1; + prAdapter->rWifiVar.ucNewChannelNumber = prRfChannelInfo->ucChannelNum; + prAdapter->rWifiVar.ucChannelSwitchCount = 5; + + /* Set new channel parameters */ + prP2pSetNewChannelMsg = (P_MSG_P2P_SET_NEW_CHANNEL_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(*prP2pSetNewChannelMsg)); + + if (prP2pSetNewChannelMsg == NULL) { + DBGLOG(P2P, WARN, "prP2pSetNewChannelMsg alloc fail\n"); + return; + } + + prP2pSetNewChannelMsg->rMsgHdr.eMsgId = MID_MNY_P2P_SET_NEW_CHANNEL; + prP2pSetNewChannelMsg->eChannelWidth = + (ENUM_CHANNEL_WIDTH_T)rlmGetVhtOpBwByBssOpBw( + prRfChannelInfo->ucChnlBw); + prP2pSetNewChannelMsg->ucRoleIdx = ucRoleIdx; + prP2pSetNewChannelMsg->ucBssIndex = ucBssIdx; + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prP2pSetNewChannelMsg, MSG_SEND_METHOD_BUF); + + kalP2PSetRole(prGlueInfo, 2, ucRoleIdx); + + /* Send Action Frame */ + rlmSendChannelSwitchFrame(prAdapter, ucBssIdx); + + /* Update Beacon */ + bssUpdateBeaconContent(prAdapter, ucBssIdx); +} + +u8 cnmIdcCsaReq(IN P_ADAPTER_T prAdapter, IN u8 ch_num, IN u8 ucRoleIdx) +{ + P_BSS_INFO_T prBssInfo = NULL; + u8 ucBssIdx = 0; + RF_CHANNEL_INFO_T rRfChnlInfo; + + ASSERT(ch_num); + + if (p2pFuncRoleToBssIdx(prAdapter, ucRoleIdx, &ucBssIdx) != + WLAN_STATUS_SUCCESS) { + return -1; + } + + DBGLOG(REQ, INFO, "[CSA]RoleIdx = %d ,CH = %d BssIdx = %d\n", ucRoleIdx, + ch_num, ucBssIdx); + + prBssInfo = prAdapter->aprBssInfo[ucBssIdx]; + + if (prBssInfo->ucPrimaryChannel != ch_num) { + rRfChnlInfo.ucChannelNum = ch_num; + rRfChnlInfo.eBand = + (rRfChnlInfo.ucChannelNum <= 14) ? BAND_2G4 : BAND_5G; + rRfChnlInfo.ucChnlBw = MAX_BW_20MHZ; + rRfChnlInfo.u2PriChnlFreq = nicChannelNum2Freq(ch_num) / 1000; + rRfChnlInfo.u4CenterFreq1 = rRfChnlInfo.u2PriChnlFreq; + rRfChnlInfo.u4CenterFreq2 = 0; + + DBGLOG(REQ, ERROR, + "[CSA]CH=%d,Band=%d,BW=%d,PriFreq=%d,S1=%d\n", + rRfChnlInfo.ucChannelNum, rRfChnlInfo.eBand, + rRfChnlInfo.ucChnlBw, rRfChnlInfo.u2PriChnlFreq, + rRfChnlInfo.u4CenterFreq1); + + prAdapter->rWifiVar.ucNewChannelNumber = ch_num; + cnmSapChannelSwitchReq(prAdapter, &rRfChnlInfo, ucRoleIdx); + + return 0; /* Return Success */ + } else { + DBGLOG(CNM, INFO, "[CSA]Req CH = cur CH:%d, Stop Req\n", + prBssInfo->ucPrimaryChannel); + return -1; + } +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/cnm_mem.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/cnm_mem.c new file mode 100644 index 00000000000000..21dfd43ef8a867 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/cnm_mem.c @@ -0,0 +1,1786 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "cnm_mem.c" + * \brief This file contain the management function of packet buffers and + * generic memory alloc/free functioin for mailbox message. + * + * A data packet has a fixed size of buffer, but a management + * packet can be equipped with a variable size of buffer. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +static u8 *apucStaRecType[STA_TYPE_INDEX_NUM] = { (u8 *)"LEGACY", (u8 *)"P2P", + (u8 *)"BOW" }; + +static u8 *apucStaRecRole[STA_ROLE_INDEX_NUM] = { (u8 *)"ADHOC", (u8 *)"CLIENT", + (u8 *)"AP", (u8 *)"DLS" }; + +#if CFG_SUPPORT_TDLS +/* The list of valid data rates. */ +const u8 aucValidDataRate[] = { + RATE_1M, /* RATE_1M_INDEX = 0 */ + RATE_2M, /* RATE_2M_INDEX */ + RATE_5_5M, /* RATE_5_5M_INDEX */ + RATE_11M, /* RATE_11M_INDEX */ + RATE_22M, /* RATE_22M_INDEX */ + RATE_33M, /* RATE_33M_INDEX */ + RATE_6M, /* RATE_6M_INDEX */ + RATE_9M, /* RATE_9M_INDEX */ + RATE_12M, /* RATE_12M_INDEX */ + RATE_18M, /* RATE_18M_INDEX */ + RATE_24M, /* RATE_24M_INDEX */ + RATE_36M, /* RATE_36M_INDEX */ + RATE_48M, /* RATE_48M_INDEX */ + RATE_54M, /* RATE_54M_INDEX */ + RATE_VHT_PHY, /* RATE_VHT_PHY_INDEX */ + RATE_HT_PHY /* RATE_HT_PHY_INDEX */ +}; +#endif + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +static void cnmStaRoutinesForAbort(P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec); + +static void cnmStaRecHandleEventPkt(P_ADAPTER_T prAdapter, + P_CMD_INFO_T prCmdInfo, + u8 *pucEventBuf, + IN u32 u4EventBufLen); + +static void cnmStaSendRemoveCmd(P_ADAPTER_T prAdapter, + ENUM_STA_REC_CMD_ACTION_T eActionType, + u8 ucStaRecIndex, + u8 ucBssIndex); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T cnmPktAllocWrapper(P_ADAPTER_T prAdapter, u32 u4Length, + u8 *pucStr) +{ + P_MSDU_INFO_T prMsduInfo; + + prMsduInfo = cnmPktAlloc(prAdapter, u4Length); + DBGLOG(MEM, LOUD, "Alloc MSDU_INFO[0x%p] by [%s]\n", prMsduInfo, + pucStr); + + return prMsduInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void cnmPktFreeWrapper(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo, + u8 *pucStr) +{ + DBGLOG(MEM, LOUD, "Free MSDU_INFO[0x%p] by [%s]\n", prMsduInfo, pucStr); + + cnmPktFree(prAdapter, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T cnmPktAlloc(P_ADAPTER_T prAdapter, u32 u4Length) +{ + P_MSDU_INFO_T prMsduInfo; + P_QUE_T prQueList; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + prQueList = &prAdapter->rTxCtrl.rFreeMsduInfoList; + + /* Get a free MSDU_INFO_T */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_REMOVE_HEAD(prQueList, prMsduInfo, P_MSDU_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + + if (prMsduInfo) { + if (u4Length) { + prMsduInfo->prPacket = + cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4Length); + prMsduInfo->eSrc = TX_PACKET_MGMT; + + if (prMsduInfo->prPacket == NULL) { + KAL_ACQUIRE_SPIN_LOCK( + prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_INSERT_TAIL(prQueList, + &prMsduInfo->rQueEntry); + KAL_RELEASE_SPIN_LOCK( + prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + prMsduInfo = NULL; + } + } else { + prMsduInfo->prPacket = NULL; + } + } +#if DBG + if (prMsduInfo == NULL) { + DBGLOG(MEM, WARN, "\n"); + DBGLOG(MEM, WARN, "MgtDesc#=%ld\n", prQueList->u4NumElem); + +#if CFG_DBG_MGT_BUF + DBGLOG(MEM, WARN, + "rMgtBufInfo: alloc#=%ld, free#=%ld, null#=%ld\n", + prAdapter->rMgtBufInfo.u4AllocCount, + prAdapter->rMgtBufInfo.u4FreeCount, + prAdapter->rMgtBufInfo.u4AllocNullCount); +#endif + + DBGLOG(MEM, WARN, "\n"); + } +#endif + + return prMsduInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void cnmPktFree(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_QUE_T prQueList; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + if (!prMsduInfo) { + return; + } + + prQueList = &prAdapter->rTxCtrl.rFreeMsduInfoList; + + /* ASSERT(prMsduInfo->prPacket); */ + if (prMsduInfo->prPacket) { + cnmMemFree(prAdapter, prMsduInfo->prPacket); + prMsduInfo->prPacket = NULL; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_INSERT_TAIL(prQueList, &prMsduInfo->rQueEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is used to initial the MGMT/MSG memory pool. + * + * \param (none) + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmMemInit(P_ADAPTER_T prAdapter) +{ + P_BUF_INFO_T prBufInfo; + + /* Initialize Management buffer pool */ + prBufInfo = &prAdapter->rMgtBufInfo; + kalMemZero(prBufInfo, sizeof(prAdapter->rMgtBufInfo)); + prBufInfo->pucBuf = prAdapter->pucMgtBufCached; + + /* Setup available memory blocks. 1 indicates FREE */ + prBufInfo->rFreeBlocksBitmap = + (BUF_BITMAP)BITS(0, MAX_NUM_OF_BUF_BLOCKS - 1); + + /* Initialize Message buffer pool */ + prBufInfo = &prAdapter->rMsgBufInfo; + kalMemZero(prBufInfo, sizeof(prAdapter->rMsgBufInfo)); + prBufInfo->pucBuf = &prAdapter->aucMsgBuf[0]; + + /* Setup available memory blocks. 1 indicates FREE */ + prBufInfo->rFreeBlocksBitmap = + (BUF_BITMAP)BITS(0, MAX_NUM_OF_BUF_BLOCKS - 1); + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Allocate MGMT/MSG memory pool. + * + * \param[in] eRamType Target RAM type. + * TCM blk_sz= 16bytes, BUF blk_sz= 256bytes + * \param[in] u4Length Length of the buffer to allocate. + * + * \retval !NULL Pointer to the start address of allocated memory. + * \retval NULL Fail to allocat memory + */ +/*----------------------------------------------------------------------------*/ +void *cnmMemAlloc(IN P_ADAPTER_T prAdapter, IN ENUM_RAM_TYPE_T eRamType, + IN u32 u4Length) +{ + P_BUF_INFO_T prBufInfo; + BUF_BITMAP rRequiredBitmap; + u32 u4BlockNum; + u32 i, u4BlkSzInPower; + void *pvMemory; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + if (u4Length == 0) { + DBGLOG(MEM, WARN, "%s: Length to be allocated is ZERO, skip!\n", + __func__); + return NULL; + } + + if (eRamType == RAM_TYPE_MSG && u4Length <= 256) { + prBufInfo = &prAdapter->rMsgBufInfo; + u4BlkSzInPower = MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; + + u4BlockNum = (u4Length + MSG_BUF_BLOCK_SIZE - 1) >> + MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; + + ASSERT(u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS); + } else { + eRamType = RAM_TYPE_BUF; + + prBufInfo = &prAdapter->rMgtBufInfo; + u4BlkSzInPower = MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; + + u4BlockNum = (u4Length + MGT_BUF_BLOCK_SIZE - 1) >> + MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; + + ASSERT(u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS); + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? + SPIN_LOCK_MSG_BUF : + SPIN_LOCK_MGT_BUF); + +#if CFG_DBG_MGT_BUF + prBufInfo->u4AllocCount++; +#endif + + if ((u4BlockNum > 0) && (u4BlockNum <= MAX_NUM_OF_BUF_BLOCKS)) { + /* Convert number of block into bit cluster */ + rRequiredBitmap = BITS(0, u4BlockNum - 1); + + for (i = 0; i <= (MAX_NUM_OF_BUF_BLOCKS - u4BlockNum); i++) { + /* Have available memory blocks */ + if ((prBufInfo->rFreeBlocksBitmap & rRequiredBitmap) == + rRequiredBitmap) { + /* Clear corresponding bits of allocated memory + * blocks */ + prBufInfo->rFreeBlocksBitmap &= + ~rRequiredBitmap; + + /* Store how many blocks be allocated */ + prBufInfo->aucAllocatedBlockNum[i] = + (u8)u4BlockNum; + + KAL_RELEASE_SPIN_LOCK( + prAdapter, eRamType == RAM_TYPE_MSG ? + SPIN_LOCK_MSG_BUF : + SPIN_LOCK_MGT_BUF); + + /* Return the start address of allocated memory + */ + return (void *)(prBufInfo->pucBuf + + (i << u4BlkSzInPower)); + } + + rRequiredBitmap <<= 1; + } + } + +#if CFG_DBG_MGT_BUF + prBufInfo->u4AllocNullCount++; +#endif + + /* kalMemAlloc() shall not included in spin_lock */ + KAL_RELEASE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? + SPIN_LOCK_MSG_BUF : + SPIN_LOCK_MGT_BUF); + + pvMemory = (void *)kalMemAlloc(u4Length, PHY_MEM_TYPE); + if (!pvMemory) { + DBGLOG(MEM, WARN, "kmalloc fail: %u\n", u4Length); + } + +#if CFG_DBG_MGT_BUF + if (pvMemory) { + GLUE_INC_REF_CNT(prAdapter->u4MemAllocDynamicCount); + } +#endif + + return pvMemory; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Release memory to MGT/MSG memory pool. + * + * \param pucMemory Start address of previous allocated memory + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmMemFree(IN P_ADAPTER_T prAdapter, IN void *pvMemory) +{ + P_BUF_INFO_T prBufInfo; + u32 u4BlockIndex; + BUF_BITMAP rAllocatedBlocksBitmap; + ENUM_RAM_TYPE_T eRamType; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + if (!pvMemory || prAdapter->pucMgtBufCached == NULL) { + return; + } + + /* Judge it belongs to which RAM type */ + if (((unsigned long)pvMemory >= + (unsigned long)&prAdapter->aucMsgBuf[0]) && + ((unsigned long)pvMemory <= + (unsigned long)&prAdapter->aucMsgBuf[MSG_BUFFER_SIZE - 1])) { + prBufInfo = &prAdapter->rMsgBufInfo; + u4BlockIndex = ((unsigned long)pvMemory - + (unsigned long)prBufInfo->pucBuf) >> + MSG_BUF_BLOCK_SIZE_IN_POWER_OF_2; + ASSERT(u4BlockIndex < MAX_NUM_OF_BUF_BLOCKS); + eRamType = RAM_TYPE_MSG; + } else if (((unsigned long)pvMemory >= + (unsigned long)prAdapter->pucMgtBufCached) && + ((unsigned long)pvMemory <= + ((unsigned long)prAdapter->pucMgtBufCached + + MGT_BUFFER_SIZE - 1))) { + prBufInfo = &prAdapter->rMgtBufInfo; + u4BlockIndex = ((unsigned long)pvMemory - + (unsigned long)prBufInfo->pucBuf) >> + MGT_BUF_BLOCK_SIZE_IN_POWER_OF_2; + ASSERT(u4BlockIndex < MAX_NUM_OF_BUF_BLOCKS); + eRamType = RAM_TYPE_BUF; + } else { + /* For Linux, it is supported because size is not needed */ + kalMemFree(pvMemory, PHY_MEM_TYPE, 0); + +#if CFG_DBG_MGT_BUF + GLUE_INC_REF_CNT(prAdapter->u4MemFreeDynamicCount); +#endif + return; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? + SPIN_LOCK_MSG_BUF : + SPIN_LOCK_MGT_BUF); + +#if CFG_DBG_MGT_BUF + prBufInfo->u4FreeCount++; +#endif + + /* Convert number of block into bit cluster */ + if (prBufInfo->aucAllocatedBlockNum[u4BlockIndex] > 0) { + rAllocatedBlocksBitmap = BITS( + 0, prBufInfo->aucAllocatedBlockNum[u4BlockIndex] - 1); + rAllocatedBlocksBitmap <<= u4BlockIndex; + + /* Clear saved block count for this memory segment */ + prBufInfo->aucAllocatedBlockNum[u4BlockIndex] = 0; + + /* Set corresponding bit of released memory block */ + prBufInfo->rFreeBlocksBitmap |= rAllocatedBlocksBitmap; + } else { + dump_stack(); + DBGLOG(MEM, ERROR, "aucAllocatedBlockNum[%d] = 0\n", + u4BlockIndex); + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, eRamType == RAM_TYPE_MSG ? + SPIN_LOCK_MSG_BUF : + SPIN_LOCK_MGT_BUF); + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void cnmStaRecInit(P_ADAPTER_T prAdapter) +{ + P_STA_RECORD_T prStaRec; + u16 i; + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + prStaRec->ucIndex = (u8)i; + prStaRec->fgIsInUse = false; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T cnmStaRecAlloc(P_ADAPTER_T prAdapter, ENUM_STA_TYPE_T eStaType, + u8 ucBssIndex, u8 *pucMacAddr) +{ + P_STA_RECORD_T prStaRec; + u16 i, k; + + ASSERT(prAdapter); + + prStaRec = cnmGetAnyStaRecByAddress(prAdapter, pucMacAddr); + + if (prStaRec != NULL) { + disconnect_sta(prAdapter, prStaRec); + } + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + if (!prStaRec->fgIsInUse) { + kalMemZero(prStaRec, sizeof(STA_RECORD_T)); + prStaRec->ucIndex = (u8)i; + prStaRec->ucBssIndex = ucBssIndex; + prStaRec->fgIsInUse = true; + + prStaRec->eStaType = eStaType; + prStaRec->ucBssIndex = ucBssIndex; + + /* Initialize the SN caches for duplicate detection */ + for (k = 0; k < TID_NUM + 1; k++) { + prStaRec->au2CachedSeqCtrl[k] = 0xFFFF; + prStaRec->afgIsIgnoreAmsduDuplicate[k] = false; + } + +#if CFG_SUPPORT_AMSDU_ATTACK_DETECTION + for (k = 0; k < TID_NUM + 1; k++) { + prStaRec->au2AmsduInvalidSN[k] = 0xFFFF; + prStaRec->afgIsAmsduInvalid[k] = false; + } +#endif + + /* Initialize SW TX queues in STA_REC */ + for (k = 0; k < STA_WAIT_QUEUE_NUM; k++) + LINK_INITIALIZE(&prStaRec->arStaWaitQueue[k]); + +#if CFG_ENABLE_PER_STA_STATISTICS && CFG_ENABLE_PKT_LIFETIME_PROFILE + prStaRec->u4TotalTxPktsNumber = 0; + prStaRec->u4TotalTxPktsTime = 0; + prStaRec->u4TotalRxPktsNumber = 0; + prStaRec->u4MaxTxPktsTime = 0; +#endif + + for (k = 0; k < NUM_OF_PER_STA_TX_QUEUES; k++) { + QUEUE_INITIALIZE(&prStaRec->arTxQueue[k]); + QUEUE_INITIALIZE( + &prStaRec->arPendingTxQueue[k]); + prStaRec->aprTargetQueue[k] = + &prStaRec->arPendingTxQueue[k]; + } + + break; + } + } + + /* Sync to chip to allocate WTBL resource */ + if (i < CFG_STA_REC_NUM) { + COPY_MAC_ADDR(prStaRec->aucMacAddr, pucMacAddr); + if (secPrivacySeekForEntry(prAdapter, prStaRec)) { + cnmStaSendUpdateCmd(prAdapter, prStaRec, NULL, false); + } +#if DBG + else { + prStaRec->fgIsInUse = false; + prStaRec = NULL; + ASSERT(false); + } +#endif + } else { + prStaRec = NULL; + } + + return prStaRec; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void cnmStaRecFree(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) +{ + u8 ucStaRecIndex, ucBssIndex; + + ASSERT(prAdapter); + + if (!prStaRec) { + return; + } + + DBGLOG(RSN, INFO, "cnmStaRecFree %d", prStaRec->ucIndex); + + ucStaRecIndex = prStaRec->ucIndex; + ucBssIndex = prStaRec->ucBssIndex; + + cnmStaRoutinesForAbort(prAdapter, prStaRec); + + cnmStaSendRemoveCmd(prAdapter, STA_REC_CMD_ACTION_STA, ucStaRecIndex, + ucBssIndex); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static void cnmStaRoutinesForAbort(P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec) +{ + ASSERT(prAdapter); + + if (!prStaRec) { + return; + } + + /* To do: free related resources, e.g. timers, buffers, etc */ + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + cnmTimerStopTimer(prAdapter, &prStaRec->rDeauthTxDoneTimer); + prStaRec->fgTransmitKeyExist = false; + + prStaRec->fgSetPwrMgtBit = false; + + if (prStaRec->pucAssocReqIe) { + kalMemFree(prStaRec->pucAssocReqIe, VIR_MEM_TYPE, + prStaRec->u2AssocReqIeLen); + prStaRec->pucAssocReqIe = NULL; + prStaRec->u2AssocReqIeLen = 0; + } + + /* Free previous allocated TCM memory */ + if (prStaRec->prChallengeText) { + cnmMemFree(prAdapter, prStaRec->prChallengeText); + prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T)NULL; + } + + qmDeactivateStaRec(prAdapter, prStaRec); + + /* Update the driver part table setting */ + secPrivacyFreeSta(prAdapter, prStaRec); + + prStaRec->fgIsInUse = false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void cnmStaFreeAllStaByNetwork(P_ADAPTER_T prAdapter, u8 ucBssIndex, + u8 ucStaRecIndexExcluded) +{ +#if CFG_ENABLE_WIFI_DIRECT + P_BSS_INFO_T prBssInfo; +#endif + P_STA_RECORD_T prStaRec; + u16 i; + + if (ucBssIndex > MAX_BSS_INDEX) { + return; + } + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = (P_STA_RECORD_T)&prAdapter->arStaRec[i]; + + if (prStaRec->fgIsInUse && prStaRec->ucBssIndex == ucBssIndex && + i != ucStaRecIndexExcluded) { + DBGLOG(CNM, EVENT, "%s: Free Sta Rec Idx:%d\n", + __func__, i); + cnmStaRoutinesForAbort(prAdapter, prStaRec); + } + } /* end of for loop */ + + cnmStaSendRemoveCmd(prAdapter, + (ucStaRecIndexExcluded < CFG_STA_REC_NUM) ? + STA_REC_CMD_ACTION_BSS_EXCLUDE_STA : + STA_REC_CMD_ACTION_BSS, + ucStaRecIndexExcluded, ucBssIndex); + +#if CFG_ENABLE_WIFI_DIRECT + /* To do: Confirm if it is invoked here or other location, but it should + * be invoked after state sync of STA_REC + * Update system operation parameters for AP mode + */ + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + if (prAdapter->fgIsP2PRegistered && + prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + rlmUpdateParamsForAP(prAdapter, prBssInfo, false); + } +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T cnmGetStaRecByIndex(P_ADAPTER_T prAdapter, u8 ucIndex) +{ + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + + prStaRec = (ucIndex < CFG_STA_REC_NUM) ? &prAdapter->arStaRec[ucIndex] : + NULL; + + if (prStaRec && prStaRec->fgIsInUse == false) { + prStaRec = NULL; + } + + return prStaRec; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Get STA_RECORD_T by Peer MAC Address(Usually TA). + * + * @param[in] pucPeerMacAddr Given Peer MAC Address. + * + * @retval Pointer to STA_RECORD_T, if found. NULL, if not found + */ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T cnmGetStaRecByAddress(P_ADAPTER_T prAdapter, u8 ucBssIndex, + u8 *pucPeerMacAddr) +{ + P_STA_RECORD_T prStaRec; + u16 i; + + ASSERT(prAdapter); + + if (!pucPeerMacAddr) { + return NULL; + } + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + if (prStaRec->fgIsInUse && prStaRec->ucBssIndex == ucBssIndex && + EQUAL_MAC_ADDR(prStaRec->aucMacAddr, pucPeerMacAddr)) { + break; + } + } + + return (i < CFG_STA_REC_NUM) ? prStaRec : NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Get STA_RECORD_T by Peer MAC Address(Usually TA). + * + * @param[in] pucPeerMacAddr Given Peer MAC Address. + * + * @retval Pointer to STA_RECORD_T, if found. NULL, if not found + */ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T cnmGetAnyStaRecByAddress(P_ADAPTER_T prAdapter, + u8 *pucPeerMacAddr) +{ + P_STA_RECORD_T prStaRec; + u16 i; + + ASSERT(prAdapter); + + if (!pucPeerMacAddr) { + return NULL; + } + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + if (prStaRec->fgIsInUse && + EQUAL_MAC_ADDR(prStaRec->aucMacAddr, pucPeerMacAddr)) { + break; + } + } + + return (i < CFG_STA_REC_NUM) ? prStaRec : NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will change the ucStaState of STA_RECORD_T and also do + * event indication to HOST to sync the STA_RECORD_T in driver. + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] u4NewState New STATE to change. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmStaRecChangeState(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, + u8 ucNewState) +{ + u8 fgNeedResp; + + if (!prAdapter) { + return; + } + + if (!prStaRec) { + DBGLOG(MEM, WARN, "%s: StaRec is NULL, skip!\n", __func__); + return; + } + + if (!prStaRec->fgIsInUse) { + DBGLOG(MEM, WARN, "%s: StaRec[%u] is not in use, skip!\n", + __func__, prStaRec->ucIndex); + return; + } + + /* Do nothing when following state transitions happen, + * other 6 conditions should be sync to FW, including 1-->1, 3-->3 + */ + if ((ucNewState == STA_STATE_2 && + prStaRec->ucStaState != STA_STATE_3) || + (ucNewState == STA_STATE_1 && + prStaRec->ucStaState == STA_STATE_2)) { + prStaRec->ucStaState = ucNewState; + return; + } + + fgNeedResp = false; + if (ucNewState == STA_STATE_3) { + /* secFsmEventStart(prAdapter, prStaRec); */ + if (ucNewState != prStaRec->ucStaState) { + fgNeedResp = true; + cnmDumpStaRec(prAdapter, prStaRec->ucIndex); + } + } else { + if (ucNewState != prStaRec->ucStaState && + prStaRec->ucStaState == STA_STATE_3) { + qmDeactivateStaRec(prAdapter, prStaRec); + } + fgNeedResp = false; + } + prStaRec->ucStaState = ucNewState; + + cnmStaSendUpdateCmd(prAdapter, prStaRec, NULL, fgNeedResp); + +#if CFG_ENABLE_WIFI_DIRECT + /* To do: Confirm if it is invoked here or other location, but it should + * be invoked after state sync of STA_REC + * Update system operation parameters for AP mode + */ + if (prAdapter->fgIsP2PRegistered && (IS_STA_IN_P2P(prStaRec))) { + P_BSS_INFO_T prBssInfo; + + prBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + rlmUpdateParamsForAP(prAdapter, prBssInfo, false); + } + } +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param[in] + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +static void cnmStaRecHandleEventPkt(P_ADAPTER_T prAdapter, + P_CMD_INFO_T prCmdInfo, u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_EVENT_ACTIVATE_STA_REC_T prEventContent; + P_STA_RECORD_T prStaRec; + if (u4EventBufLen < sizeof(EVENT_ACTIVATE_STA_REC_T)) { + DBGLOG(CNM, ERROR, "%s: Invalid event length: %d < %d\n", + __func__, u4EventBufLen, + sizeof(EVENT_ACTIVATE_STA_REC_T)); + return; + } + prEventContent = (P_EVENT_ACTIVATE_STA_REC_T)pucEventBuf; + prStaRec = cnmGetStaRecByIndex(prAdapter, prEventContent->ucStaRecIdx); + + if (prStaRec && prStaRec->ucStaState == STA_STATE_3 && + !kalMemCmp(&prStaRec->aucMacAddr[0], &prEventContent->aucMacAddr[0], + MAC_ADDR_LEN)) { + qmActivateStaRec(prAdapter, prStaRec); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param[in] + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmStaSendUpdateCmd(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, + P_TXBF_PFMU_STA_INFO prTxBfPfmuStaInfo, u8 fgNeedResp) +{ + P_CMD_UPDATE_STA_RECORD_T prCmdContent; + WLAN_STATUS rStatus; + + if (!prAdapter) { + return; + } + + if (!prStaRec) { + DBGLOG(MEM, WARN, "%s: StaRec is NULL, skip!\n", __func__); + return; + } + + if (!prStaRec->fgIsInUse) { + DBGLOG(MEM, WARN, "%s: StaRec[%u] is not in use, skip!\n", + __func__, prStaRec->ucIndex); + return; + } + + /* To do: come out a mechanism to limit one STA_REC sync once for AP + * mode to avoid buffer empty case when many STAs are associated + * simultaneously. + */ + + /* To do: how to avoid 2 times of allocated memory. Use Stack? + * One is here, the other is in wlanSendQueryCmd() + */ + prCmdContent = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, + sizeof(CMD_UPDATE_STA_RECORD_T)); + + /* To do: exception handle */ + if (!prCmdContent) { + DBGLOG(MEM, + WARN, + "%s: CMD_ID_UPDATE_STA_RECORD command allocation failed\n", + __func__); + return; + } + + /* Reset command buffer */ + kalMemZero(prCmdContent, sizeof(CMD_UPDATE_STA_RECORD_T)); + + if (prTxBfPfmuStaInfo) { + memcpy(&prCmdContent->rTxBfPfmuInfo, prTxBfPfmuStaInfo, + sizeof(TXBF_PFMU_STA_INFO)); + } + + prCmdContent->ucStaIndex = prStaRec->ucIndex; + prCmdContent->ucStaType = (u8)prStaRec->eStaType; + kalMemCopy(&prCmdContent->aucMacAddr[0], &prStaRec->aucMacAddr[0], + MAC_ADDR_LEN); + prCmdContent->u2AssocId = prStaRec->u2AssocId; + prCmdContent->u2ListenInterval = prStaRec->u2ListenInterval; + prCmdContent->ucBssIndex = prStaRec->ucBssIndex; + + prCmdContent->ucDesiredPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; + prCmdContent->u2DesiredNonHTRateSet = prStaRec->u2DesiredNonHTRateSet; + prCmdContent->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; + prCmdContent->ucMcsSet = prStaRec->ucMcsSet; + prCmdContent->ucSupMcs32 = (u8)prStaRec->fgSupMcs32; + prCmdContent->u2HwDefaultFixedRateCode = + prStaRec->u2HwDefaultFixedRateCode; + + kalMemCopy( + prCmdContent->aucRxMcsBitmask, prStaRec->aucRxMcsBitmask, + sizeof(prCmdContent + ->aucRxMcsBitmask) /*SUP_MCS_RX_BITMASK_OCTET_NUM */ ); + prCmdContent->u2RxHighestSupportedRate = + prStaRec->u2RxHighestSupportedRate; + prCmdContent->u4TxRateInfo = prStaRec->u4TxRateInfo; + + prCmdContent->u2HtCapInfo = prStaRec->u2HtCapInfo; + prCmdContent->ucNeedResp = (u8)fgNeedResp; + + if (prAdapter->rWifiVar.eRateSetting != FIXED_RATE_NONE) { + /* override rate configuration */ + nicUpdateRateParams(prAdapter, prAdapter->rWifiVar.eRateSetting, + &(prCmdContent->ucDesiredPhyTypeSet), + &(prCmdContent->u2DesiredNonHTRateSet), + &(prCmdContent->u2BSSBasicRateSet), + &(prCmdContent->ucMcsSet), + &(prCmdContent->ucSupMcs32), + &(prCmdContent->u2HtCapInfo)); + } + + prCmdContent->ucIsQoS = prStaRec->fgIsQoS; + prCmdContent->ucIsUapsdSupported = prStaRec->fgIsUapsdSupported; + prCmdContent->ucStaState = prStaRec->ucStaState; + + prCmdContent->ucAmpduParam = prStaRec->ucAmpduParam; + prCmdContent->u2HtExtendedCap = prStaRec->u2HtExtendedCap; + prCmdContent->u4TxBeamformingCap = prStaRec->u4TxBeamformingCap; + prCmdContent->ucAselCap = prStaRec->ucAselCap; + prCmdContent->ucRCPI = prStaRec->ucRCPI; + + prCmdContent->u4VhtCapInfo = prStaRec->u4VhtCapInfo; + prCmdContent->u2VhtRxMcsMap = prStaRec->u2VhtRxMcsMap; + prCmdContent->u2VhtRxHighestSupportedDataRate = + prStaRec->u2VhtRxHighestSupportedDataRate; + prCmdContent->u2VhtTxMcsMap = prStaRec->u2VhtTxMcsMap; + prCmdContent->u2VhtTxHighestSupportedDataRate = + prStaRec->u2VhtTxHighestSupportedDataRate; + prCmdContent->ucVhtOpMode = prStaRec->ucVhtOpMode; + + prCmdContent->ucUapsdAc = prStaRec->ucBmpTriggerAC | + (prStaRec->ucBmpDeliveryAC << 4); + prCmdContent->ucUapsdSp = prStaRec->ucUapsdSp; + + prCmdContent->ucWlanIndex = prStaRec->ucWlanIndex; + prCmdContent->ucBMCWlanIndex = WTBL_RESERVED_ENTRY; + + prCmdContent->ucTrafficDataType = prStaRec->ucTrafficDataType; + prCmdContent->ucTxGfMode = prStaRec->ucTxGfMode; + prCmdContent->ucTxSgiMode = prStaRec->ucTxSgiMode; + prCmdContent->ucTxStbcMode = prStaRec->ucTxStbcMode; + prCmdContent->u4FixedPhyRate = prStaRec->u4FixedPhyRate; + prCmdContent->u2MaxLinkSpeed = prStaRec->u2MaxLinkSpeed; + prCmdContent->u2MinLinkSpeed = prStaRec->u2MinLinkSpeed; + prCmdContent->u4Flags = prStaRec->u4Flags; + + prCmdContent->ucTxAmpdu = prAdapter->rWifiVar.ucAmpduTx; + prCmdContent->ucRxAmpdu = prAdapter->rWifiVar.ucAmpduRx; + + /* AMSDU in AMPDU global configuration */ + prCmdContent->ucTxAmsduInAmpdu = prAdapter->rWifiVar.ucAmsduInAmpduTx; + prCmdContent->ucRxAmsduInAmpdu = prAdapter->rWifiVar.ucAmsduInAmpduRx; + if ((prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11AC) || + (prStaRec->u4Flags & MTK_SYNERGY_CAP_SUPPORT_24G_MCS89)) { + /* VHT pear AMSDU in AMPDU configuration */ + prCmdContent->ucTxAmsduInAmpdu &= + prAdapter->rWifiVar.ucVhtAmsduInAmpduTx; + prCmdContent->ucRxAmsduInAmpdu &= + prAdapter->rWifiVar.ucVhtAmsduInAmpduRx; + } else if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11N) { + /* HT peer AMSDU in AMPDU configuration */ + prCmdContent->ucTxAmsduInAmpdu &= + prAdapter->rWifiVar.ucHtAmsduInAmpduTx; + prCmdContent->ucRxAmsduInAmpdu &= + prAdapter->rWifiVar.ucHtAmsduInAmpduRx; + } + + prCmdContent->u4TxMaxAmsduInAmpduLen = + prAdapter->rWifiVar.u4TxMaxAmsduInAmpduLen; + + prCmdContent->ucTxBaSize = prAdapter->rWifiVar.ucTxBaSize; + + if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11AC) { + prCmdContent->ucRxBaSize = prAdapter->rWifiVar.ucRxVhtBaSize; + }else{ + prCmdContent->ucRxBaSize = prAdapter->rWifiVar.ucRxHtBaSize; + } + + /* RTS Policy */ + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucSigTaRts)) { + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucDynBwRts)) { + prCmdContent->ucRtsPolicy = RTS_POLICY_DYNAMIC_BW; + }else{ + prCmdContent->ucRtsPolicy = RTS_POLICY_STATIC_BW; + } + } else { + prCmdContent->ucRtsPolicy = RTS_POLICY_LEGACY; + } + + DBGLOG(REQ, + INFO, + "Update StaRec[%u] WIDX[%u] State[%u] Type[%u] BssIdx[%u] AID[%u]\n", + prCmdContent->ucStaIndex, + prCmdContent->ucWlanIndex, + prCmdContent->ucStaState, + prCmdContent->ucStaType, + prCmdContent->ucBssIndex, + prCmdContent->u2AssocId); + + DBGLOG(REQ, INFO, "Update StaRec[%u] QoS[%u] UAPSD[%u]\n", + prCmdContent->ucStaIndex, prCmdContent->ucIsQoS, + prCmdContent->ucIsUapsdSupported); + + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_UPDATE_STA_RECORD, /* ucCID */ + true, /* fgSetQuery */ + fgNeedResp, /* fgNeedResp */ + false, /* fgIsOid */ + fgNeedResp ? cnmStaRecHandleEventPkt : NULL, NULL, + /* pfCmdTimeoutHandler */ + sizeof(CMD_UPDATE_STA_RECORD_T), /* u4SetQueryInfoLen */ + (u8 *)prCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + cnmMemFree(prAdapter, prCmdContent); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(MEM, WARN, + "%s: CMD_ID_UPDATE_STA_RECORD result 0x%08x\n", __func__, + rStatus); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param[in] + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +static void cnmStaSendRemoveCmd(P_ADAPTER_T prAdapter, + ENUM_STA_REC_CMD_ACTION_T eActionType, + u8 ucStaRecIndex, u8 ucBssIndex) +{ + CMD_REMOVE_STA_RECORD_T rCmdContent; + WLAN_STATUS rStatus; + + ASSERT(prAdapter); + + rCmdContent.ucActionType = (u8)eActionType; + rCmdContent.ucStaIndex = ucStaRecIndex; + rCmdContent.ucBssIndex = ucBssIndex; + rCmdContent.ucReserved = 0; + + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_REMOVE_STA_RECORD, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_REMOVE_STA_RECORD_T), /* u4SetQueryInfoLen + */ + (u8 *)&rCmdContent, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(MEM, WARN, + "%s: CMD_ID_REMOVE_STA_RECORD result 0x%08x\n", __func__, + rStatus); + } +} + +u8 *cnmStaRecGetTypeString(ENUM_STA_TYPE_T eStaType) +{ + u8 *pucTypeString = NULL; + + if (eStaType & STA_TYPE_LEGACY_MASK) { + pucTypeString = apucStaRecType[STA_TYPE_LEGACY_INDEX]; + } + if (eStaType & STA_TYPE_P2P_MASK) { + pucTypeString = apucStaRecType[STA_TYPE_P2P_INDEX]; + } + if (eStaType & STA_TYPE_BOW_MASK) { + pucTypeString = apucStaRecType[STA_TYPE_BOW_INDEX]; + } + + return pucTypeString; +} + +u8 *cnmStaRecGetRoleString(ENUM_STA_TYPE_T eStaType) +{ + u8 *pucRoleString = NULL; + + if (eStaType & STA_TYPE_ADHOC_MASK) { + pucRoleString = apucStaRecRole[STA_ROLE_ADHOC_INDEX - + STA_ROLE_BASE_INDEX]; + } + if (eStaType & STA_TYPE_CLIENT_MASK) { + pucRoleString = apucStaRecRole[STA_ROLE_CLIENT_INDEX - + STA_ROLE_BASE_INDEX]; + } + if (eStaType & STA_TYPE_AP_MASK) { + pucRoleString = + apucStaRecRole[STA_ROLE_AP_INDEX - STA_ROLE_BASE_INDEX]; + } + if (eStaType & STA_TYPE_DLS_MASK) { + pucRoleString = + apucStaRecRole[STA_ROLE_DLS_INDEX - + STA_ROLE_BASE_INDEX]; + } + + return pucRoleString; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param[in] + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmDumpStaRec(IN P_ADAPTER_T prAdapter, IN u8 ucStaRecIdx) +{ + u8 ucWTEntry; + u32 i; + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("cnmDumpStaRec"); + + prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIdx); + + if (!prStaRec) { + DBGLOG(SW4, INFO, "Invalid StaRec index[%u], skip dump!\n", + ucStaRecIdx); + return; + } + + ucWTEntry = prStaRec->ucWlanIndex; + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + ASSERT(prBssInfo); + + DBGLOG(SW4, INFO, "============= DUMP STA[%u] ===========\n", + ucStaRecIdx); + + DBGLOG(SW4, INFO, + "STA_IDX[%u] BSS_IDX[%u] MAC[" MACSTR + "] TYPE[%s %s] WTBL[%u] USED[%u] State[%u]\n", + prStaRec->ucIndex, prStaRec->ucBssIndex, + MAC2STR(prStaRec->aucMacAddr), + cnmStaRecGetTypeString(prStaRec->eStaType), + cnmStaRecGetRoleString(prStaRec->eStaType), ucWTEntry, + prStaRec->fgIsInUse, prStaRec->ucStaState); + + DBGLOG(SW4, INFO, + "QoS[%u] HT/VHT[%u/%u] AID[%u] WMM[%u] UAPSD[%u] SEC[%u]\n", + prStaRec->fgIsQoS, + (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11N) ? true : + false, + (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11AC) ? true : + false, + prStaRec->u2AssocId, prStaRec->fgIsWmmSupported, + prStaRec->fgIsUapsdSupported, + secIsProtectedBss(prAdapter, prBssInfo)); + + DBGLOG(SW4, INFO, + "PhyTypeSet: BSS[0x%02x] Desired[0x%02x] NonHtBasic[0x%02x]\n", + prBssInfo->ucPhyTypeSet, prStaRec->ucDesiredPhyTypeSet, + prStaRec->ucNonHTBasicPhyType); + + DBGLOG(SW4, + INFO, + "RateSet: BssBasic[0x%04x] Operational[0x%04x] DesiredNonHT[0x%02x] DeafultFixedRate[0x%02x]\n", + prBssInfo->u2BSSBasicRateSet, + prStaRec->u2OperationalRateSet, + prStaRec->u2DesiredNonHTRateSet, + prStaRec->u2HwDefaultFixedRateCode); + + DBGLOG(SW4, + INFO, + "HT Cap[0x%04x] ExtCap[0x%04x] BeemCap[0x%08x] MCS[0x%02x] MCS32[%u]\n", + prStaRec->u2HtCapInfo, + prStaRec->u2HtExtendedCap, + prStaRec->u4TxBeamformingCap, + prStaRec->ucMcsSet, + prStaRec->fgSupMcs32); + + DBGLOG(SW4, + INFO, + "VHT Cap[0x%08x] TxMCS[0x%04x] RxMCS[0x%04x] VhtOpMode[0x%02x]\n", + prStaRec->u4VhtCapInfo, + prStaRec->u2VhtTxMcsMap, + prStaRec->u2VhtRxMcsMap, + prStaRec->ucVhtOpMode); + + DBGLOG(SW4, INFO, + "RCPI[%u] InPS[%u] TxAllowed[%u] KeyRdy[%u] AMPDU T/R[%u/%u]\n", + prStaRec->ucRCPI, prStaRec->fgIsInPS, prStaRec->fgIsTxAllowed, + prStaRec->fgIsTxKeyReady, prStaRec->fgTxAmpduEn, + prStaRec->fgRxAmpduEn); + + DBGLOG(SW4, INFO, "TxQ LEN TC[0~5] [%03u:%03u:%03u:%03u:%03u:%03u]\n", + prStaRec->aprTargetQueue[0]->u4NumElem, + prStaRec->aprTargetQueue[1]->u4NumElem, + prStaRec->aprTargetQueue[2]->u4NumElem, + prStaRec->aprTargetQueue[3]->u4NumElem); + + DBGLOG(SW4, INFO, "BMP AC Delivery/Trigger[%02x/%02x]\n", + prStaRec->ucBmpDeliveryAC, prStaRec->ucBmpTriggerAC); + + DBGLOG(SW4, INFO, "FreeQuota: Total[%u] Delivery/NonDelivery[%u/%u]\n", + prStaRec->ucFreeQuota, prStaRec->ucFreeQuotaForDelivery, + prStaRec->ucFreeQuotaForNonDelivery); + + DBGLOG(SW4, INFO, "aucRxMcsBitmask: [0][0x%02x] [1][0x%02x]\n", + prStaRec->aucRxMcsBitmask[0], prStaRec->aucRxMcsBitmask[1]); + + for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) { + if (prStaRec->aprRxReorderParamRefTbl[i]) { + DBGLOG(SW4, INFO, "<Rx BA Entry TID[%u]>\n", + prStaRec->aprRxReorderParamRefTbl[i]->ucTid); + DBGLOG(SW4, + INFO, + " Valid[%u] WinStart/End[%u/%u] WinSize[%u] ReOrderQueLen[%u]\n", + prStaRec->aprRxReorderParamRefTbl[i]->fgIsValid, + prStaRec->aprRxReorderParamRefTbl[i]->u2WinStart, + prStaRec->aprRxReorderParamRefTbl[i]->u2WinEnd, + prStaRec->aprRxReorderParamRefTbl[i]->u2WinSize, + prStaRec->aprRxReorderParamRefTbl[i] + ->rReOrderQue.u4NumElem); + DBGLOG(SW4, + INFO, + " Bubble Exist[%u] SN[%u]\n", + prStaRec->aprRxReorderParamRefTbl[i]->fgHasBubble, + prStaRec->aprRxReorderParamRefTbl[i] + ->u2FirstBubbleSn); + } + } + + DBGLOG(SW4, INFO, "============= DUMP END ===========\n"); +} + +u32 cnmDumpMemoryStatus(IN P_ADAPTER_T prAdapter, IN u8 *pucBuf, IN u32 u4Max) +{ + u32 u4Len = 0; +#if CFG_DBG_MGT_BUF + P_BUF_INFO_T prBufInfo; + + LOGBUF(pucBuf, u4Max, u4Len, "\n"); + LOGBUF(pucBuf, u4Max, u4Len, + "============= DUMP Memory Status =============\n"); + + LOGBUF(pucBuf, u4Max, u4Len, + "Dynamic alloc OS memory count: alloc[%u] free[%u]\n", + prAdapter->u4MemAllocDynamicCount, + prAdapter->u4MemFreeDynamicCount); + + prBufInfo = &prAdapter->rMsgBufInfo; + LOGBUF(pucBuf, u4Max, u4Len, + "MSG memory count: alloc[%u] free[%u] null[%u] bitmap[0x%08x]\n", + prBufInfo->u4AllocCount, prBufInfo->u4FreeCount, + prBufInfo->u4AllocNullCount, (u32)prBufInfo->rFreeBlocksBitmap); + + prBufInfo = &prAdapter->rMgtBufInfo; + LOGBUF(pucBuf, u4Max, u4Len, + "MGT memory count: alloc[%u] free[%u] null[%u] bitmap[0x%08x]\n", + prBufInfo->u4AllocCount, prBufInfo->u4FreeCount, + prBufInfo->u4AllocNullCount, (u32)prBufInfo->rFreeBlocksBitmap); + + LOGBUF(pucBuf, u4Max, u4Len, "============= DUMP END =============\n"); +#endif + + return u4Len; +} + +#if CFG_SUPPORT_TDLS +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to add a peer record. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS /* TDLS_STATUS //prStaRec->ucNetTypeIndex */ +cnmPeerAdd(P_ADAPTER_T prAdapter, void *pvSetBuffer, u32 u4SetBufferLen, + u32 *pu4SetInfoLen) +{ + CMD_PEER_ADD_T *prCmd; + BSS_INFO_T *prAisBssInfo; + STA_RECORD_T *prStaRec; + + /* sanity check */ + + if ((prAdapter == NULL) || (pvSetBuffer == NULL) || + (pu4SetInfoLen == NULL)) { + return TDLS_STATUS_FAIL; + } + + /* init */ + *pu4SetInfoLen = sizeof(CMD_PEER_ADD_T); + prCmd = (CMD_PEER_ADD_T *)pvSetBuffer; + + prAisBssInfo = prAdapter->prAisBssInfo; /* for AIS only test */ + prStaRec = cnmGetStaRecByAddress( + prAdapter, (u8)prAdapter->prAisBssInfo->ucBssIndex, + prCmd->aucPeerMac); + + if (prStaRec == NULL) { + prStaRec = + cnmStaRecAlloc(prAdapter, STA_TYPE_DLS_PEER, + (u8)prAdapter->prAisBssInfo->ucBssIndex, + prCmd->aucPeerMac); + + if (prStaRec == NULL) { + return TDLS_STATUS_RESOURCES; + } + + if (prAisBssInfo) { + if (prAisBssInfo->ucBssIndex) { + prStaRec->ucBssIndex = prAisBssInfo->ucBssIndex; + } + } + + /* init the prStaRec */ + /* prStaRec will be zero first in cnmStaRecAlloc() */ + COPY_MAC_ADDR(prStaRec->aucMacAddr, prCmd->aucPeerMac); + + prStaRec->u2BSSBasicRateSet = prAisBssInfo->u2BSSBasicRateSet; + + prStaRec->u2DesiredNonHTRateSet = + prAdapter->rWifiVar.ucAvailablePhyTypeSet; + + prStaRec->u2OperationalRateSet = + prAisBssInfo->u2OperationalRateSet; + prStaRec->ucPhyTypeSet = prAisBssInfo->ucPhyTypeSet; + prStaRec->eStaType = prCmd->eStaType; + + /* NOTE(Kevin): Better to change state here, not at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + } else { + if ((prStaRec->ucStaState > STA_STATE_1) && + (IS_DLS_STA(prStaRec))) { + /* TODO: Teardown the peer */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + } + } + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to update a peer record. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[out] pvQueryBuf A pointer to the buffer that holds the result of + * the query. + * \param[in] u4QueryBufLen The length of the query buffer. + * \param[out] pu4QueryInfoLen If the call is successful, returns the number of + * bytes written into the query buffer. If the call + * failed due to invalid length of the query buffer, + * returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS /* TDLS_STATUS */ +cnmPeerUpdate(P_ADAPTER_T prAdapter, void *pvSetBuffer, u32 u4SetBufferLen, + u32 *pu4SetInfoLen) +{ + CMD_PEER_UPDATE_T *prCmd; + BSS_INFO_T *prAisBssInfo; + STA_RECORD_T *prStaRec; + u8 ucNonHTPhyTypeSet; + + u16 u2OperationalRateSet = 0; + + u8 ucRate; + u16 i, j; + +#if CFG_SUPPORT_802_11AC + u8 ucRxNss = 1; + P_WIFI_VAR_T prWifiVar; +#endif + + /* sanity check */ + if ((!prAdapter) || (!pvSetBuffer) || (!pu4SetInfoLen)) { + return TDLS_STATUS_FAIL; + } + + /* init */ + *pu4SetInfoLen = sizeof(CMD_PEER_ADD_T); + prCmd = (CMD_PEER_UPDATE_T *)pvSetBuffer; + + prAisBssInfo = prAdapter->prAisBssInfo; + + prStaRec = cnmGetStaRecByAddress( + prAdapter, (u8)prAdapter->prAisBssInfo->ucBssIndex, + prCmd->aucPeerMac); + + if ((!prStaRec) || !(prStaRec->fgIsInUse)) { + return TDLS_STATUS_FAIL; + } + + if (!IS_DLS_STA(prStaRec)) { + return TDLS_STATUS_FAIL; + } + + if (prAisBssInfo) { + if (prAisBssInfo->ucBssIndex) { + prStaRec->ucBssIndex = prAisBssInfo->ucBssIndex; + } + } + + /* update the record join time. */ + GET_CURRENT_SYSTIME(&prStaRec->rUpdateTime); + + /* update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = prCmd->u2StatusCode; + prStaRec->u2AssocId = 0; /* no use */ + prStaRec->u2ListenInterval = 0; /* unknown */ + prStaRec->fgIsQoS = true; + prStaRec->fgIsUapsdSupported = (prCmd->UapsdBitmap == 0) ? false : true; + prStaRec->u4TxBeamformingCap = 0; /* no use */ + prStaRec->ucAselCap = 0; /* no use */ + prStaRec->ucRCPI = 0; + prStaRec->ucBmpTriggerAC = prCmd->UapsdBitmap; + prStaRec->ucBmpDeliveryAC = prCmd->UapsdBitmap; + prStaRec->ucUapsdSp = prCmd->UapsdMaxSp; + prStaRec->eStaType = prCmd->eStaType; + + /* ++ support rate */ + if (prCmd->u2SupRateLen) { + for (i = 0; i < prCmd->u2SupRateLen; i++) { + if (prCmd->aucSupRate[i]) { + ucRate = prCmd->aucSupRate[i] & RATE_MASK; + /* Search all valid data rates */ + for (j = 0; + j < sizeof(aucValidDataRate) / sizeof(u8); + j++) { + if (ucRate == aucValidDataRate[j]) { + u2OperationalRateSet |= BIT(j); + break; + } + } + } + } + + prStaRec->u2OperationalRateSet = u2OperationalRateSet; + prStaRec->u2BSSBasicRateSet = prAisBssInfo->u2BSSBasicRateSet; + + /* 4 <5> PHY type setting */ + + prStaRec->ucPhyTypeSet = 0; + + if (prAisBssInfo->eBand == BAND_2G4) { + if (prCmd->fgIsSupHt) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + } + + /* if not 11n only */ + if (!(prStaRec->u2BSSBasicRateSet & + RATE_SET_BIT_HT_PHY)) { + /* check if support 11g */ + if ((prStaRec->u2OperationalRateSet & + RATE_SET_OFDM)) { + prStaRec->ucPhyTypeSet |= + PHY_TYPE_BIT_ERP; + } + + /* if not 11g only */ + if (!(prStaRec->u2BSSBasicRateSet & + RATE_SET_OFDM)) { + /* check if support 11b */ + if ((prStaRec->u2OperationalRateSet & + RATE_SET_HR_DSSS)) { + prStaRec->ucPhyTypeSet |= + PHY_TYPE_BIT_HR_DSSS; + } + } + } + } else { + if (prCmd->fgIsSupVht) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_VHT; + } + + if (prCmd->fgIsSupHt) { + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + } + + /* if not 11n only */ + if (!(prStaRec->u2BSSBasicRateSet & + RATE_SET_BIT_HT_PHY)) { + /* Support 11a definitely */ + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; + } + } + + if (IS_STA_IN_AIS(prStaRec)) { + if (!((prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION3_ENABLED) || + (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION3_KEY_ABSENT) || + (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION_DISABLED) || + (prAdapter->prGlueInfo->u2WSCAssocInfoIELen))) { + prStaRec->ucPhyTypeSet &= ~PHY_TYPE_BIT_HT; + } + } + + prStaRec->ucDesiredPhyTypeSet = + prStaRec->ucPhyTypeSet & + prAdapter->rWifiVar.ucAvailablePhyTypeSet; + ucNonHTPhyTypeSet = prStaRec->ucDesiredPhyTypeSet & + PHY_TYPE_SET_802_11ABG; + + /* Check for Target BSS's non HT Phy Types */ + if (ucNonHTPhyTypeSet) { + if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_ERP) { + prStaRec->ucNonHTBasicPhyType = + PHY_TYPE_ERP_INDEX; + } else if (ucNonHTPhyTypeSet & PHY_TYPE_BIT_OFDM) { + prStaRec->ucNonHTBasicPhyType = + PHY_TYPE_OFDM_INDEX; + } else { + prStaRec->ucNonHTBasicPhyType = + PHY_TYPE_HR_DSSS_INDEX; + } + + prStaRec->fgHasBasicPhyType = true; + } else { + /* Use mandatory for 11N only BSS */ + ASSERT(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N); + { + /* TODO(Kevin): which value should we set for + * 11n ? ERP ? */ + prStaRec->ucNonHTBasicPhyType = + PHY_TYPE_HR_DSSS_INDEX; + } + + prStaRec->fgHasBasicPhyType = false; + } + } + + /* ++HT capability */ + + if (prCmd->fgIsSupHt) { + prStaRec->ucDesiredPhyTypeSet |= PHY_TYPE_BIT_HT; + prStaRec->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + prStaRec->u2HtCapInfo = prCmd->rHtCap.u2CapInfo; + prStaRec->ucAmpduParam = prCmd->rHtCap.ucAmpduParamsInfo; + prStaRec->u2HtExtendedCap = prCmd->rHtCap.u2ExtHtCapInfo; + prStaRec->u4TxBeamformingCap = prCmd->rHtCap.u4TxBfCapInfo; + prStaRec->ucAselCap = prCmd->rHtCap.ucAntennaSelInfo; + prStaRec->ucMcsSet = prCmd->rHtCap.rMCS.arRxMask[0]; + prStaRec->fgSupMcs32 = + (prCmd->rHtCap.rMCS.arRxMask[32 / 8] & BIT(0)) ? true : + false; + kalMemCopy(prStaRec->aucRxMcsBitmask, + prCmd->rHtCap.rMCS.arRxMask, + sizeof(prStaRec->aucRxMcsBitmask)); + } + +#if CFG_SUPPORT_802_11AC + prWifiVar = &prAdapter->rWifiVar; + /* ++VHT capability */ + if (prCmd->fgIsSupVht) { + prStaRec->u4VhtCapInfo = prCmd->rVHtCap.u4CapInfo; + + /* Set Tx LDPC capability */ + if (IS_FEATURE_FORCE_ENABLED(prWifiVar->ucTxLdpc)) { + prStaRec->u4VhtCapInfo |= VHT_CAP_INFO_RX_LDPC; + }else if (IS_FEATURE_DISABLED(prWifiVar->ucTxLdpc)) { + prStaRec->u4VhtCapInfo &= ~VHT_CAP_INFO_RX_LDPC; + } + + /* Set Tx STBC capability */ + if (IS_FEATURE_FORCE_ENABLED(prWifiVar->ucTxStbc)) { + prStaRec->u4VhtCapInfo |= VHT_CAP_INFO_RX_STBC_MASK; + }else if (IS_FEATURE_DISABLED(prWifiVar->ucTxStbc)) { + prStaRec->u4VhtCapInfo &= ~VHT_CAP_INFO_RX_STBC_MASK; + } + + /* Set Tx TXOP PS capability */ + if (IS_FEATURE_FORCE_ENABLED(prWifiVar->ucTxopPsTx)) { + prStaRec->u4VhtCapInfo |= VHT_CAP_INFO_VHT_TXOP_PS; + }else if (IS_FEATURE_DISABLED(prWifiVar->ucTxopPsTx)) { + prStaRec->u4VhtCapInfo &= ~VHT_CAP_INFO_VHT_TXOP_PS; + } + + /* Set Tx Short GI capability */ + if (IS_FEATURE_FORCE_ENABLED(prWifiVar->ucTxShortGI)) { + prStaRec->u4VhtCapInfo |= VHT_CAP_INFO_SHORT_GI_80; + prStaRec->u4VhtCapInfo |= + VHT_CAP_INFO_SHORT_GI_160_80P80; + } else if (IS_FEATURE_DISABLED(prWifiVar->ucTxShortGI)) { + prStaRec->u4VhtCapInfo &= ~VHT_CAP_INFO_SHORT_GI_80; + prStaRec->u4VhtCapInfo &= + ~VHT_CAP_INFO_SHORT_GI_160_80P80; + } + + prStaRec->u2VhtRxMcsMap = prCmd->rVHtCap.rVMCS.u2RxMcsMap; + prStaRec->u2VhtRxHighestSupportedDataRate = + prCmd->rVHtCap.rVMCS.u2RxHighest; + + prStaRec->u2VhtTxMcsMap = prCmd->rVHtCap.rVMCS.u2TxMcsMap; + prStaRec->u2VhtTxHighestSupportedDataRate = + prCmd->rVHtCap.rVMCS.u2TxHighest; + + prStaRec->ucVhtOpMode = VHT_OP_MODE_CHANNEL_WIDTH_20 | + VHT_OP_MODE_CHANNEL_WIDTH_80; + /* no op mode IE, use HT/VHT cap to check BW */ + if (prCmd->fgIsSupHt && prAisBssInfo->fg40mBwAllowed && + (prCmd->rHtCap.u2CapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH)) { + prStaRec->ucVhtOpMode |= VHT_OP_MODE_CHANNEL_WIDTH_40; + } + if ((prCmd->rVHtCap.u4CapInfo & + VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_SET_160) || + (prCmd->rVHtCap.u4CapInfo & + VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_SET_160_80P80)) { + prStaRec->ucVhtOpMode |= + VHT_OP_MODE_CHANNEL_WIDTH_160_80P80; + } + + /* no op mode IE, use MCS set to check NSS */ + if (((prCmd->rVHtCap.rVMCS.u2RxMcsMap & + VHT_CAP_INFO_MCS_2SS_MASK) >> + VHT_CAP_INFO_MCS_2SS_OFFSET) != + VHT_CAP_INFO_MCS_NOT_SUPPORTED) { + ucRxNss = 2; + } + prStaRec->ucVhtOpMode |= + ((ucRxNss - 1) << VHT_OP_MODE_RX_NSS_OFFSET) & + VHT_OP_MODE_RX_NSS; + } +#endif + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Get TDLS peer STA_RECORD_T by Peer MAC Address(Usually TA). + * + * @param[in] pucPeerMacAddr Given Peer MAC Address. + * + * @retval Pointer to STA_RECORD_T, if found. NULL, if not found + */ +/*----------------------------------------------------------------------------*/ +P_STA_RECORD_T cnmGetTdlsPeerByAddress(P_ADAPTER_T prAdapter, u8 ucBssIndex, + u8 aucPeerMACAddress[]) +{ + P_STA_RECORD_T prStaRec; + u16 i; + + ASSERT(prAdapter); + ASSERT(aucPeerMACAddress); + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + if (prStaRec) { + if (prStaRec->fgIsInUse && + prStaRec->eStaType == STA_TYPE_DLS_PEER && + EQUAL_MAC_ADDR(prStaRec->aucMacAddr, + aucPeerMACAddress)) { + break; + } + } + } + + return prStaRec; +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/cnm_timer.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/cnm_timer.c new file mode 100644 index 00000000000000..3cd23ddc9f2ad6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/cnm_timer.c @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "cnm_timer.c" + * \brief + * + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routines is called to initialize a root timer. + * + * \param[in] prAdapter + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmTimerInitialize(IN P_ADAPTER_T prAdapter) +{ + P_ROOT_TIMER prRootTimer; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prRootTimer = &prAdapter->rRootTimer; + + /* Note: glue layer have configured timer */ + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + LINK_INITIALIZE(&prRootTimer->rLinkHead); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routines is called to destroy a root timer. + * When WIFI is off, the token shall be returned back to system. + * + * \param[in] + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmTimerDestroy(IN P_ADAPTER_T prAdapter) +{ + P_ROOT_TIMER prRootTimer; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prRootTimer = &prAdapter->rRootTimer; + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + LINK_INITIALIZE(&prRootTimer->rLinkHead); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + + /* Note: glue layer will be responsible for timer destruction */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routines is called to initialize a timer. + * + * \param[in] prTimer Pointer to a timer structure. + * \param[in] pfnFunc Pointer to the call back function. + * \param[in] u4Data Parameter for call back function. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmTimerInitTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, + IN PFN_MGMT_TIMEOUT_FUNC pfFunc, + IN unsigned long ulDataPtr) +{ + ASSERT(prAdapter); + + ASSERT(prTimer); + +#if DBG + /* Note: NULL function pointer is permitted for HEM POWER */ + if (pfFunc == NULL) { + DBGLOG(CNM, WARN, "Init timer with NULL callback function!\n"); + } +#endif + + ASSERT(prAdapter->rRootTimer.rLinkHead.prNext); + { + P_LINK_T prTimerList; + P_LINK_ENTRY_T prLinkEntry; + P_TIMER_T prPendingTimer; + + prTimerList = &(prAdapter->rRootTimer.rLinkHead); + + LINK_FOR_EACH(prLinkEntry, prTimerList) { + prPendingTimer = + LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry); + ASSERT(prPendingTimer); + ASSERT(prPendingTimer != prTimer); + } + } + + LINK_ENTRY_INITIALIZE(&prTimer->rLinkEntry); + + prTimer->pfMgmtTimeOutFunc = pfFunc; + prTimer->ulDataPtr = ulDataPtr; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routines is called to stop a timer. + * + * \param[in] prTimer Pointer to a timer structure. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static void cnmTimerStopTimer_impl(IN P_ADAPTER_T prAdapter, + IN P_TIMER_T prTimer, + IN u8 fgAcquireSpinlock) +{ + P_ROOT_TIMER prRootTimer; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prTimer); + + prRootTimer = &prAdapter->rRootTimer; + + if (fgAcquireSpinlock) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + } + + if (timerPendingTimer(prTimer)) { + LINK_REMOVE_KNOWN_ENTRY(&prRootTimer->rLinkHead, + &prTimer->rLinkEntry); + + /* Reduce dummy timeout for power saving, especially HIF + * activity. If two or more timers exist and being removed timer + * is smallest, this dummy timeout will still happen, but it is + * OK. + */ + if (LINK_IS_EMPTY(&prRootTimer->rLinkHead)) { + kalCancelTimer(prAdapter->prGlueInfo); + } + } + + if (fgAcquireSpinlock) { + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routines is called to stop a timer. + * + * \param[in] prTimer Pointer to a timer structure. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmTimerStopTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer) +{ + ASSERT(prAdapter); + ASSERT(prTimer); + + cnmTimerStopTimer_impl(prAdapter, prTimer, true); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routines is called to start a timer with wake_lock. + * + * \param[in] prTimer Pointer to a timer structure. + * \param[in] u4TimeoutMs Timeout to issue the timer and call back function + * (unit: ms). + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmTimerStartTimer(IN P_ADAPTER_T prAdapter, IN P_TIMER_T prTimer, + IN u32 u4TimeoutMs) +{ + P_ROOT_TIMER prRootTimer; + P_LINK_T prTimerList; + u32 rExpiredSysTime, rTimeoutSystime; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prTimer); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + + prRootTimer = &prAdapter->rRootTimer; + prTimerList = &prRootTimer->rLinkHead; + + /* If timeout interval is larger than 1 minute, the mod value is set + * to the timeout value first, then per minutue. + */ + if (u4TimeoutMs > MSEC_PER_MIN) { + ASSERT(u4TimeoutMs <= ((u32)0xFFFF * MSEC_PER_MIN)); + + prTimer->u2Minutes = (u16)(u4TimeoutMs / MSEC_PER_MIN); + u4TimeoutMs -= (prTimer->u2Minutes * MSEC_PER_MIN); + if (u4TimeoutMs == 0) { + u4TimeoutMs = MSEC_PER_MIN; + prTimer->u2Minutes--; + } + } else { + prTimer->u2Minutes = 0; + } + + /* The assertion check if MSEC_TO_SYSTIME() may be overflow. */ + ASSERT(u4TimeoutMs < (((u32)0x80000000 - MSEC_PER_SEC) / KAL_HZ)); + rTimeoutSystime = MSEC_TO_SYSTIME(u4TimeoutMs); + if (rTimeoutSystime == 0) { + rTimeoutSystime = 1; + } + rExpiredSysTime = kalGetTimeTick() + rTimeoutSystime; + + /* If no timer pending or the fast time interval is used. */ + if (LINK_IS_EMPTY(prTimerList) || + TIME_BEFORE(rExpiredSysTime, prRootTimer->rNextExpiredSysTime)) { + prRootTimer->rNextExpiredSysTime = rExpiredSysTime; + } + + /* Add this timer to checking list */ + prTimer->rExpiredSysTime = rExpiredSysTime; + + if (!timerPendingTimer(prTimer)) { + LINK_INSERT_TAIL(prTimerList, &prTimer->rLinkEntry); + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routines is called to check the timer list. + * + * \param[in] + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void cnmTimerDoTimeOutCheck(IN P_ADAPTER_T prAdapter) +{ + P_ROOT_TIMER prRootTimer; + P_LINK_T prTimerList; + P_LINK_ENTRY_T prLinkEntry; + P_TIMER_T prTimer; + u32 rCurSysTime; + PFN_MGMT_TIMEOUT_FUNC pfMgmtTimeOutFunc; + unsigned long ulTimeoutDataPtr; + u8 fgNeedWakeLock; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + /* acquire spin lock */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); + + prRootTimer = &prAdapter->rRootTimer; + prTimerList = &prRootTimer->rLinkHead; + + rCurSysTime = kalGetTimeTick(); + + /* Set the permitted max timeout value for new one */ + prRootTimer->rNextExpiredSysTime = + rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL; + + LINK_FOR_EACH(prLinkEntry, prTimerList) { + prTimer = LINK_ENTRY(prLinkEntry, TIMER_T, rLinkEntry); + ASSERT(prTimer); + + /* Check if this entry is timeout. */ + if (!TIME_BEFORE(rCurSysTime, prTimer->rExpiredSysTime)) { + cnmTimerStopTimer_impl(prAdapter, prTimer, false); + + pfMgmtTimeOutFunc = prTimer->pfMgmtTimeOutFunc; + ulTimeoutDataPtr = prTimer->ulDataPtr; + + if (prTimer->u2Minutes > 0) { + prTimer->u2Minutes--; + prTimer->rExpiredSysTime = + rCurSysTime + + MSEC_TO_SYSTIME(MSEC_PER_MIN); + LINK_INSERT_TAIL(prTimerList, + &prTimer->rLinkEntry); + } else if (pfMgmtTimeOutFunc) { + KAL_RELEASE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TIMER); + (pfMgmtTimeOutFunc)(prAdapter, + ulTimeoutDataPtr); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TIMER); + } + + /* Search entire list again because of nest del and add + * timers and current MGMT_TIMER could be volatile after + * stopped + */ + prLinkEntry = (P_LINK_ENTRY_T)prTimerList; + + prRootTimer->rNextExpiredSysTime = + rCurSysTime + MGMT_MAX_TIMEOUT_INTERVAL; + } else if (TIME_BEFORE(prTimer->rExpiredSysTime, + prRootTimer->rNextExpiredSysTime)) { + prRootTimer->rNextExpiredSysTime = + prTimer->rExpiredSysTime; + } + } /* end of for loop */ + + /* Setup the prNext timeout event. It is possible the timer was already + * set in the above timeout callback function. + */ + fgNeedWakeLock = false; + if (!LINK_IS_EMPTY(prTimerList)) { + ASSERT(TIME_AFTER(prRootTimer->rNextExpiredSysTime, + rCurSysTime)); + } + + /* release spin lock */ + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TIMER); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/hem_mbox.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/hem_mbox.c new file mode 100644 index 00000000000000..569e5159532b20 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/hem_mbox.c @@ -0,0 +1,501 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "hem_mbox.c" + * \brief + * + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +#if DBG +/*lint -save -e64 Type mismatch */ +static u8 *apucDebugMsg[] = { + (u8 *)DISP_STRING("MID_MNY_CNM_CH_REQ"), + (u8 *)DISP_STRING("MID_MNY_CNM_CH_ABORT"), + (u8 *)DISP_STRING("MID_CNM_AIS_CH_GRANT"), + (u8 *)DISP_STRING("MID_CNM_P2P_CH_GRANT"), + (u8 *)DISP_STRING("MID_CNM_BOW_CH_GRANT"), + + (u8 *)DISP_STRING("MID_AIS_SCN_SCAN_REQ"), + (u8 *)DISP_STRING("MID_AIS_SCN_SCAN_REQ_V2"), + (u8 *)DISP_STRING("MID_AIS_SCN_SCAN_CANCEL"), + (u8 *)DISP_STRING("MID_P2P_SCN_SCAN_REQ"), + (u8 *)DISP_STRING("MID_P2P_SCN_SCAN_REQ_V2"), + (u8 *)DISP_STRING("MID_P2P_SCN_SCAN_CANCEL"), + (u8 *)DISP_STRING("MID_BOW_SCN_SCAN_REQ"), + (u8 *)DISP_STRING("MID_BOW_SCN_SCAN_REQ_V2"), + (u8 *)DISP_STRING("MID_BOW_SCN_SCAN_CANCEL"), + (u8 *)DISP_STRING("MID_RLM_SCN_SCAN_REQ"), + (u8 *)DISP_STRING("MID_RLM_SCN_SCAN_REQ_V2"), + (u8 *)DISP_STRING("MID_RLM_SCN_SCAN_CANCEL"), + (u8 *)DISP_STRING("MID_SCN_AIS_SCAN_DONE"), + (u8 *)DISP_STRING("MID_SCN_P2P_SCAN_DONE"), + (u8 *)DISP_STRING("MID_SCN_BOW_SCAN_DONE"), + (u8 *)DISP_STRING("MID_SCN_RLM_SCAN_DONE"), + + (u8 *)DISP_STRING("MID_OID_AIS_FSM_JOIN_REQ"), + (u8 *)DISP_STRING("MID_OID_AIS_FSM_ABORT"), + (u8 *)DISP_STRING("MID_AIS_SAA_FSM_START"), + (u8 *)DISP_STRING("MID_AIS_SAA_FSM_ABORT"), + (u8 *)DISP_STRING("MID_SAA_AIS_JOIN_COMPLETE"), + +#if CFG_ENABLE_WIFI_DIRECT + (u8 *)DISP_STRING("MID_P2P_SAA_FSM_START"), + (u8 *)DISP_STRING("MID_P2P_SAA_FSM_ABORT"), + (u8 *)DISP_STRING("MID_SAA_P2P_JOIN_COMPLETE"), + + (u8 *)DISP_STRING("MID_MNY_P2P_FUN_SWITCH"), + (u8 *)DISP_STRING("MID_MNY_P2P_DEVICE_DISCOVERY"), + (u8 *)DISP_STRING("MID_MNY_P2P_CONNECTION_REQ"), + (u8 *)DISP_STRING("MID_MNY_P2P_CONNECTION_ABORT"), + (u8 *)DISP_STRING("MID_MNY_P2P_BEACON_UPDATE"), + (u8 *)DISP_STRING("MID_MNY_P2P_STOP_AP"), + (u8 *)DISP_STRING("MID_MNY_P2P_CHNL_REQ"), + (u8 *)DISP_STRING("MID_MNY_P2P_CHNL_ABORT"), + (u8 *)DISP_STRING("MID_MNY_P2P_MGMT_TX"), + (u8 *)DISP_STRING("MID_MNY_P2P_GROUP_DISSOLVE"), + (u8 *)DISP_STRING("MID_MNY_P2P_MGMT_FRAME_REGISTER"), + (u8 *)DISP_STRING("MID_MNY_P2P_NET_DEV_REGISTER"), + (u8 *)DISP_STRING("MID_MNY_P2P_START_AP"), + (u8 *)DISP_STRING("MID_MNY_P2P_UPDATE_IE_BUF"), +#if (CFG_SUPPORT_DFS_MASTER == 1) + (u8 *)DISP_STRING("MID_CNM_P2P_RADAR_DETECT"), + (u8 *)DISP_STRING("MID_CNM_P2P_CSA_DONE"), + (u8 *)DISP_STRING("MID_MNY_P2P_DFS_CAC"), + (u8 *)DISP_STRING("MID_MNY_P2P_SET_NEW_CHANNEL"), +#endif +#endif + +#if CFG_SUPPORT_ADHOC + /* (u8 *)DISP_STRING("MID_AIS_CNM_CREATE_IBSS_REQ"), */ + /* (u8 *)DISP_STRING("MID_CNM_AIS_CREATE_IBSS_GRANT"), */ + /* (u8 *)DISP_STRING("MID_AIS_CNM_MERGE_IBSS_REQ"), */ + /* (u8 *)DISP_STRING("MID_CNM_AIS_MERGE_IBSS_GRANT"), */ + (u8 *)DISP_STRING("MID_SCN_AIS_FOUND_IBSS"), +#endif + + (u8 *)DISP_STRING("MID_SAA_AIS_FSM_ABORT"), + (u8 *)DISP_STRING("MID_MNY_AIS_REMAIN_ON_CHANNEL"), + (u8 *)DISP_STRING("MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL"), +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + (u8 *)DISP_STRING("MID_WNM_AIS_BSS_TRANSITION"), +#endif + (u8 *)DISP_STRING("MID_MNY_AIS_MGMT_TX") +}; + +/*lint -restore */ +#endif + +/* This message entry will be re-ordered based on the message ID order + * by invoking mboxInitMsgMap() + */ +static MSG_HNDL_ENTRY_T arMsgMapTable[] = { + { MID_MNY_CNM_CH_REQ, cnmChMngrRequestPrivilege }, + { MID_MNY_CNM_CH_ABORT, cnmChMngrAbortPrivilege }, + { MID_CNM_AIS_CH_GRANT, aisFsmRunEventChGrant }, +#if CFG_ENABLE_WIFI_DIRECT + { MID_CNM_P2P_CH_GRANT, p2pFsmRunEventChGrant }, /*set in gl_p2p_init.c + */ +#else + { MID_CNM_P2P_CH_GRANT, mboxDummy }, +#endif + +#if (CFG_SUPPORT_DFS_MASTER == 1) + { MID_CNM_P2P_RADAR_DETECT, p2pRoleFsmRunEventRadarDet }, + { MID_CNM_P2P_CSA_DONE, p2pRoleFsmRunEventCsaDone }, +#endif + + { MID_CNM_BOW_CH_GRANT, mboxDummy }, + + /*--------------------------------------------------*/ + /* SCN Module Mailbox Messages */ + /*--------------------------------------------------*/ + { MID_AIS_SCN_SCAN_REQ, scnFsmMsgStart }, + { MID_AIS_SCN_SCAN_REQ_V2, scnFsmMsgStart }, + { MID_AIS_SCN_SCAN_CANCEL, scnFsmMsgAbort }, + { MID_P2P_SCN_SCAN_REQ, scnFsmMsgStart }, + { MID_P2P_SCN_SCAN_REQ_V2, scnFsmMsgStart }, + { MID_P2P_SCN_SCAN_CANCEL, scnFsmMsgAbort }, + { MID_BOW_SCN_SCAN_REQ, scnFsmMsgStart }, + { MID_BOW_SCN_SCAN_REQ_V2, scnFsmMsgStart }, + { MID_BOW_SCN_SCAN_CANCEL, scnFsmMsgAbort }, + { MID_RLM_SCN_SCAN_REQ, scnFsmMsgStart }, + { MID_RLM_SCN_SCAN_REQ_V2, scnFsmMsgStart }, + { MID_RLM_SCN_SCAN_CANCEL, scnFsmMsgAbort }, + { MID_SCN_AIS_SCAN_DONE, aisFsmRunEventScanDone }, +#if CFG_ENABLE_WIFI_DIRECT + { MID_SCN_P2P_SCAN_DONE, p2pFsmRunEventScanDone }, /*set in + * gl_p2p_init.c */ +#else + { MID_SCN_P2P_SCAN_DONE, mboxDummy }, +#endif + + { MID_SCN_BOW_SCAN_DONE, mboxDummy }, + + { MID_SCN_RLM_SCAN_DONE, rlmObssScanDone }, + + /*--------------------------------------------------*/ + /* AIS Module Mailbox Messages */ + /*--------------------------------------------------*/ + { MID_OID_AIS_FSM_JOIN_REQ, aisFsmRunEventAbort }, + { MID_OID_AIS_FSM_ABORT, aisFsmRunEventAbort }, + { MID_AIS_SAA_FSM_START, saaFsmRunEventStart }, + { MID_AIS_SAA_FSM_ABORT, saaFsmRunEventAbort }, + { MID_SAA_AIS_JOIN_COMPLETE, aisFsmRunEventJoinComplete }, + +#if CFG_ENABLE_WIFI_DIRECT /*set in gl_p2p_init.c */ + { MID_P2P_SAA_FSM_START, saaFsmRunEventStart }, + { MID_P2P_SAA_FSM_ABORT, saaFsmRunEventAbort }, + { MID_SAA_P2P_JOIN_COMPLETE, p2pRoleFsmRunEventJoinComplete }, /* V */ + + { MID_MNY_P2P_FUN_SWITCH, p2pRoleFsmRunEventSwitchOPMode }, + { MID_MNY_P2P_DEVICE_DISCOVERY, p2pFsmRunEventScanRequest }, /* V */ + { MID_MNY_P2P_CONNECTION_REQ, p2pRoleFsmRunEventConnectionRequest }, + { MID_MNY_P2P_CONNECTION_ABORT, p2pRoleFsmRunEventConnectionAbort }, + { MID_MNY_P2P_BEACON_UPDATE, p2pRoleFsmRunEventBeaconUpdate }, + { MID_MNY_P2P_STOP_AP, p2pRoleFsmRunEventStopAP }, + { MID_MNY_P2P_CHNL_REQ, p2pDevFsmRunEventChannelRequest }, /* V */ + { MID_MNY_P2P_CHNL_ABORT, p2pDevFsmRunEventChannelAbort }, /* V */ + { MID_MNY_P2P_MGMT_TX, p2pDevFsmRunEventMgmtTx }, /* V */ + { MID_MNY_P2P_GROUP_DISSOLVE, p2pRoleFsmRunEventDissolve }, + { MID_MNY_P2P_MGMT_FRAME_REGISTER, p2pDevFsmRunEventMgmtFrameRegister }, + { MID_MNY_P2P_NET_DEV_REGISTER, p2pFsmRunEventNetDeviceRegister }, + { MID_MNY_P2P_START_AP, p2pRoleFsmRunEventStartAP }, + { MID_MNY_P2P_DEL_IFACE, p2pRoleFsmRunEventDelIface }, + { MID_MNY_P2P_MGMT_FRAME_UPDATE, p2pFsmRunEventUpdateMgmtFrame }, +#if (CFG_SUPPORT_DFS_MASTER == 1) + { MID_MNY_P2P_DFS_CAC, p2pRoleFsmRunEventDfsCac }, + { MID_MNY_P2P_SET_NEW_CHANNEL, p2pRoleFsmRunEventSetNewChannel }, +#endif +#if CFG_SUPPORT_WFD + { MID_MNY_P2P_WFD_CFG_UPDATE, p2pFsmRunEventWfdSettingUpdate }, +#endif + { MID_MNY_P2P_ACTIVE_BSS, p2pDevFsmRunEventActiveDevBss }, +#endif + +#if CFG_SUPPORT_ADHOC + { MID_SCN_AIS_FOUND_IBSS, aisFsmRunEventFoundIBSSPeer }, +#endif + + { MID_SAA_AIS_FSM_ABORT, aisFsmRunEventAbort }, + { MID_MNY_AIS_REMAIN_ON_CHANNEL, aisFsmRunEventRemainOnChannel }, + { MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL, + aisFsmRunEventCancelRemainOnChannel }, + +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + { MID_WNM_AIS_BSS_TRANSITION, aisFsmRunEventBssTransition }, +#endif + { MID_MNY_AIS_MGMT_TX, aisFsmRunEventMgmtFrameTx } +}; + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#if DBG +#define MBOX_HNDL_MSG(prAdapter, prMsg) \ + do { \ + ASSERT(arMsgMapTable[prMsg->eMsgId].pfMsgHndl); \ + if (arMsgMapTable[prMsg->eMsgId].pfMsgHndl) { \ + DBGLOG(CNM, LOUD, "DO MSG [%d: %s]\n", prMsg->eMsgId, \ + apucDebugMsg[prMsg->eMsgId]); \ + arMsgMapTable[prMsg->eMsgId].pfMsgHndl(prAdapter, \ + prMsg); \ + } else { \ + DBGLOG(CNM, ERROR, "NULL fptr for MSG [%d]\n", \ + prMsg->eMsgId); \ + cnmMemFree(prAdapter, prMsg); \ + } \ + } while (0) +#else +#define MBOX_HNDL_MSG(prAdapter, prMsg) \ + do { \ + ASSERT(arMsgMapTable[prMsg->eMsgId].pfMsgHndl); \ + if (arMsgMapTable[prMsg->eMsgId].pfMsgHndl) { \ + DBGLOG(CNM, LOUD, "DO MSG [%d]\n", prMsg->eMsgId); \ + arMsgMapTable[prMsg->eMsgId].pfMsgHndl(prAdapter, \ + prMsg); \ + } else { \ + DBGLOG(CNM, ERROR, "NULL fptr for MSG [%d]\n", \ + prMsg->eMsgId); \ + cnmMemFree(prAdapter, prMsg); \ + } \ + } while (0) +#endif +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void mboxInitMsgMap(void) +{ + u32 i, idx; + MSG_HNDL_ENTRY_T rTempEntry; + + ASSERT((sizeof(arMsgMapTable) / sizeof(MSG_HNDL_ENTRY_T)) == + MID_TOTAL_NUM); + + for (i = 0; i < MID_TOTAL_NUM; i++) { + if (arMsgMapTable[i].eMsgId == (ENUM_MSG_ID_T)i) { + continue; + } + for (idx = i + 1; idx < MID_TOTAL_NUM; idx++) + if (arMsgMapTable[idx].eMsgId == (ENUM_MSG_ID_T)i) { + break; + } + ASSERT(idx < MID_TOTAL_NUM); + if (idx >= MID_TOTAL_NUM) { + continue; + } + + /* Swap target entry and current entry */ + rTempEntry.eMsgId = arMsgMapTable[idx].eMsgId; + rTempEntry.pfMsgHndl = arMsgMapTable[idx].pfMsgHndl; + + arMsgMapTable[idx].eMsgId = arMsgMapTable[i].eMsgId; + arMsgMapTable[idx].pfMsgHndl = arMsgMapTable[i].pfMsgHndl; + + arMsgMapTable[i].eMsgId = rTempEntry.eMsgId; + arMsgMapTable[i].pfMsgHndl = rTempEntry.pfMsgHndl; + } + + /* Verify the correctness of final message map */ + for (i = 0; i < MID_TOTAL_NUM; i++) { + ASSERT(arMsgMapTable[i].eMsgId == (ENUM_MSG_ID_T)i); + while (arMsgMapTable[i].eMsgId != (ENUM_MSG_ID_T)i) + ; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void mboxSetup(IN P_ADAPTER_T prAdapter, IN ENUM_MBOX_ID_T eMboxId) +{ + P_MBOX_T prMbox; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); + ASSERT(prAdapter); + + prMbox = &(prAdapter->arMbox[eMboxId]); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + LINK_INITIALIZE(&prMbox->rLinkHead); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void mboxSendMsg(IN P_ADAPTER_T prAdapter, IN ENUM_MBOX_ID_T eMboxId, + IN P_MSG_HDR_T prMsg, IN EUNM_MSG_SEND_METHOD_T eMethod) +{ + P_MBOX_T prMbox; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); + ASSERT(prMsg); + if (!prMsg) { + DBGLOG(CNM, ERROR, "prMsg is NULL\n"); + return; + } + + ASSERT(prAdapter); + if (!prAdapter) { + DBGLOG(CNM, ERROR, "prAdapter is NULL\n"); + return; + } + + prMbox = &(prAdapter->arMbox[eMboxId]); + + switch (eMethod) { + case MSG_SEND_METHOD_BUF: + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + LINK_INSERT_TAIL(&prMbox->rLinkHead, &prMsg->rLinkEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + + /* to wake up main service thread */ + GLUE_SET_EVENT(prAdapter->prGlueInfo); + + break; + + case MSG_SEND_METHOD_UNBUF: + MBOX_HNDL_MSG(prAdapter, prMsg); + break; + + default: + ASSERT(0); + break; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void mboxRcvAllMsg(IN P_ADAPTER_T prAdapter, ENUM_MBOX_ID_T eMboxId) +{ + P_MBOX_T prMbox; + P_MSG_HDR_T prMsg; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(eMboxId < MBOX_ID_TOTAL_NUM); + ASSERT(prAdapter); + + prMbox = &(prAdapter->arMbox[eMboxId]); + + while (!LINK_IS_EMPTY(&prMbox->rLinkHead)) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + LINK_REMOVE_HEAD(&prMbox->rLinkHead, prMsg, P_MSG_HDR_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + + ASSERT(prMsg); + if (!prMsg) { + DBGLOG(CNM, ERROR, "prMsg is NULL\n"); + continue; + } + MBOX_HNDL_MSG(prAdapter, prMsg); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void mboxInitialize(IN P_ADAPTER_T prAdapter) +{ + u32 i; + + ASSERT(prAdapter); + + /* Initialize Mailbox */ + mboxInitMsgMap(); + + /* Setup/initialize each mailbox */ + for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) + mboxSetup(prAdapter, i); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void mboxDestroy(IN P_ADAPTER_T prAdapter) +{ + P_MBOX_T prMbox; + P_MSG_HDR_T prMsg; + u8 i; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + for (i = 0; i < MBOX_ID_TOTAL_NUM; i++) { + prMbox = &(prAdapter->arMbox[i]); + + while (!LINK_IS_EMPTY(&prMbox->rLinkHead)) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + LINK_REMOVE_HEAD(&prMbox->rLinkHead, prMsg, + P_MSG_HDR_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_MAILBOX); + + ASSERT(prMsg); + cnmMemFree(prAdapter, prMsg); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This is dummy function to prevent empty arMsgMapTable[] for compiling. + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void mboxDummy(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + ASSERT(prAdapter); + + cnmMemFree(prAdapter, prMsgHdr); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/mib.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/mib.c new file mode 100644 index 00000000000000..b124c755300b63 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/mib.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "mib.c" + * \brief This file includes the mib default vale and functions. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +NON_HT_PHY_ATTRIBUTE_T rNonHTPhyAttributes[] = { + { RATE_SET_HR_DSSS, true, false }, /* For PHY_TYPE_HR_DSSS_INDEX(0) */ + { RATE_SET_ERP, true, true }, /* For PHY_TYPE_ERP_INDEX(1) */ + { RATE_SET_ERP_P2P, true, true }, /* For PHY_TYPE_ERP_P2P_INDEX(2) */ + { RATE_SET_OFDM, false, false }, /* For PHY_TYPE_OFDM_INDEX(3) */ +}; + +NON_HT_ADHOC_MODE_ATTRIBUTE_T rNonHTAdHocModeAttributes[AD_HOC_MODE_NUM] = { + { PHY_TYPE_HR_DSSS_INDEX, BASIC_RATE_SET_HR_DSSS }, /* For + * AD_HOC_MODE_11B(0) + */ + { PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_HR_DSSS_ERP }, /* For + * AD_HOC_MODE_MIXED_11BG(1) + */ + { PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_ERP }, /* For AD_HOC_MODE_11G(2) */ + { PHY_TYPE_OFDM_INDEX, BASIC_RATE_SET_OFDM }, /* For AD_HOC_MODE_11A(3) + */ +}; + +NON_HT_AP_MODE_ATTRIBUTE_T rNonHTApModeAttributes[AP_MODE_NUM] = { + { PHY_TYPE_HR_DSSS_INDEX, BASIC_RATE_SET_HR_DSSS }, /* For + * AP_MODE_11B(0) */ + { PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_HR_DSSS_ERP }, /* For + * AP_MODE_MIXED_11BG(1) + */ + { PHY_TYPE_ERP_INDEX, BASIC_RATE_SET_ERP }, /* For AP_MODE_11G(2) */ + { PHY_TYPE_ERP_P2P_INDEX, BASIC_RATE_SET_ERP_P2P }, /* For + * AP_MODE_11G_P2P(3) + */ + { PHY_TYPE_OFDM_INDEX, BASIC_RATE_SET_OFDM }, /* For AP_MODE_11A(4) */ +}; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_assoc.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_assoc.c new file mode 100644 index 00000000000000..382f7884ed1aee --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_assoc.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "p2p_assoc.c" + * \brief This file includes the Wi-Fi Direct association-related functions. + * + * This file includes the association-related functions. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to compose Common Information Elements for P2P + * Association Request Frame. + * + * @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +u8 *p2pBuildReAssocReqFrameCommonIEs(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN u8 *pucBuffer) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + + /* Fill the SSID element. */ + SSID_IE(pucBuffer)->ucId = ELEM_ID_SSID; + + /* NOTE(Kevin): We copy the SSID from CONNECTION_SETTINGS for the case + * of Passive Scan and the target BSS didn't broadcast SSID on its + * Beacon Frame. + */ + + COPY_SSID(SSID_IE(pucBuffer)->aucSSID, SSID_IE(pucBuffer)->ucLength, + prP2pBssInfo->aucSSID, prP2pBssInfo->ucSSIDLen); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + return pucBuffer; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_dev_fsm.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_dev_fsm.c new file mode 100644 index 00000000000000..e31f9f7f8d19b7 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_dev_fsm.c @@ -0,0 +1,905 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ +#include "precomp.h" +#include "p2p_dev_state.h" +#if CFG_ENABLE_WIFI_DIRECT + +#if !DBG_DISABLE_ALL_LOG +/*lint -save -e64 Type mismatch */ +static u8 *apucDebugP2pDevState[P2P_DEV_STATE_NUM] = { + (u8 *)DISP_STRING("P2P_DEV_STATE_IDLE"), + (u8 *)DISP_STRING("P2P_DEV_STATE_SCAN"), + (u8 *)DISP_STRING("P2P_DEV_STATE_REQING_CHANNEL"), + (u8 *)DISP_STRING("P2P_DEV_STATE_CHNL_ON_HAND"), + (u8 *)DISP_STRING("P2P_DEV_STATE_NUM") +}; + +/*lint -restore */ +#endif + +u8 p2pDevFsmInit(IN P_ADAPTER_T prAdapter) +{ + P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo = (P_P2P_DEV_FSM_INFO_T)NULL; + P_P2P_CHNL_REQ_INFO_T prP2pChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + P_P2P_MGMT_TX_REQ_INFO_T prP2pMgmtTxReqInfo = + (P_P2P_MGMT_TX_REQ_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + prP2pDevFsmInfo = prAdapter->rWifiVar.prP2pDevFsmInfo; + + ASSERT_BREAK(prP2pDevFsmInfo != NULL); + + kalMemZero(prP2pDevFsmInfo, sizeof(P2P_DEV_FSM_INFO_T)); + + prP2pDevFsmInfo->eCurrentState = P2P_DEV_STATE_IDLE; + + cnmTimerInitTimer( + prAdapter, &(prP2pDevFsmInfo->rP2pFsmTimeoutTimer), + (PFN_MGMT_TIMEOUT_FUNC)p2pDevFsmRunEventTimeout, + (unsigned long)prP2pDevFsmInfo); + + prP2pBssInfo = + cnmGetBssInfoAndInit(prAdapter, NETWORK_TYPE_P2P, true); + + if (prP2pBssInfo != NULL) { + COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, + prAdapter->rMyMacAddr); + prP2pBssInfo->aucOwnMacAddr[0] ^= 0x2; /* change to + * local + * administrated + * address */ + + prP2pDevFsmInfo->ucBssIndex = prP2pBssInfo->ucBssIndex; + + prP2pBssInfo->eCurrentOPMode = OP_MODE_P2P_DEVICE; + prP2pBssInfo->ucConfigAdHocAPMode = AP_MODE_11G_P2P; + prP2pBssInfo->u2HwDefaultFixedRateCode = RATE_OFDM_6M; + + prP2pBssInfo->eBand = BAND_2G4; + prP2pBssInfo->eDBDCBand = ENUM_BAND_0; +#if (CFG_HW_WMM_BY_BSS == 1) + prP2pBssInfo->ucWmmQueSet = MAX_HW_WMM_INDEX; +#else + prP2pBssInfo->ucWmmQueSet = + (prAdapter->rWifiVar.ucDbdcMode == + DBDC_MODE_DISABLED) ? + DBDC_5G_WMM_INDEX : + DBDC_2G_WMM_INDEX; +#endif + prP2pBssInfo->ucPhyTypeSet = + prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11GN; + + prP2pBssInfo->ucNonHTBasicPhyType = + (u8)rNonHTApModeAttributes + [prP2pBssInfo->ucConfigAdHocAPMode] + .ePhyTypeIndex; + prP2pBssInfo->u2BSSBasicRateSet = + rNonHTApModeAttributes + [prP2pBssInfo->ucConfigAdHocAPMode] + .u2BSSBasicRateSet; + + prP2pBssInfo->u2OperationalRateSet = + rNonHTPhyAttributes + [prP2pBssInfo->ucNonHTBasicPhyType] + .u2SupportedRateSet; + prP2pBssInfo->u4PrivateData = 0; /* TH3 Huang */ + + rateGetDataRatesFromRateSet( + prP2pBssInfo->u2OperationalRateSet, + prP2pBssInfo->u2BSSBasicRateSet, + prP2pBssInfo->aucAllSupportedRates, + &prP2pBssInfo->ucAllSupportedRatesLen); + } + prP2pChnlReqInfo = &prP2pDevFsmInfo->rChnlReqInfo; + LINK_INITIALIZE(&prP2pChnlReqInfo->rP2pChnlReqLink); + + prP2pMgmtTxReqInfo = &prP2pDevFsmInfo->rMgmtTxInfo; + LINK_INITIALIZE(&prP2pMgmtTxReqInfo->rP2pTxReqLink); + + p2pDevFsmStateTransition(prAdapter, prP2pDevFsmInfo, + P2P_DEV_STATE_IDLE); + } while (false); + + if (prP2pBssInfo) { + return prP2pBssInfo->ucBssIndex; + }else{ + return P2P_DEV_BSS_INDEX + 1; + } +} + +void p2pDevFsmUninit(IN P_ADAPTER_T prAdapter) +{ + P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo = (P_P2P_DEV_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + prP2pDevFsmInfo = prAdapter->rWifiVar.prP2pDevFsmInfo; + + ASSERT_BREAK(prP2pDevFsmInfo != NULL); + + prP2pBssInfo = + prAdapter->aprBssInfo[prP2pDevFsmInfo->ucBssIndex]; + + cnmTimerStopTimer(prAdapter, + &(prP2pDevFsmInfo->rP2pFsmTimeoutTimer)); + + /* Abort device FSM */ + p2pDevFsmStateTransition(prAdapter, prP2pDevFsmInfo, + P2P_DEV_STATE_IDLE); + p2pDevFsmRunEventAbort(prAdapter, prP2pDevFsmInfo); + + SET_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex); + + /* Clear CmdQue */ + kalClearMgmtFramesByBssIdx(prAdapter->prGlueInfo, + prP2pBssInfo->ucBssIndex); + kalClearSecurityFramesByBssIdx(prAdapter->prGlueInfo, + prP2pBssInfo->ucBssIndex); + + /* Clear PendingTxMsdu */ + nicFreePendingTxMsduInfoByBssIdx(prAdapter, + prP2pBssInfo->ucBssIndex); + + /* Deactivate BSS. */ + UNSET_NET_ACTIVE(prAdapter, prP2pBssInfo->ucBssIndex); + + nicDeactivateNetwork(prAdapter, prP2pBssInfo->ucBssIndex); + + cnmFreeBssInfo(prAdapter, prP2pBssInfo); + } while (false); +} + +void p2pDevFsmStateTransition(IN P_ADAPTER_T prAdapter, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo, + IN ENUM_P2P_DEV_STATE_T eNextState) +{ + u8 fgIsLeaveState = (u8)false; + + ASSERT(prP2pDevFsmInfo); + if (!prP2pDevFsmInfo) { + DBGLOG(P2P, ERROR, "prP2pDevFsmInfo is NULL!\n"); + return; + } + + ASSERT(prP2pDevFsmInfo->ucBssIndex == P2P_DEV_BSS_INDEX); + if (prP2pDevFsmInfo->ucBssIndex != P2P_DEV_BSS_INDEX) { + DBGLOG(P2P, + ERROR, + "prP2pDevFsmInfo->ucBssIndex %s should be P2P_DEV_BSS_INDEX(%d)!\n", + prP2pDevFsmInfo->ucBssIndex, + P2P_DEV_BSS_INDEX); + return; + } + + do { + if (!IS_BSS_ACTIVE( + prAdapter->aprBssInfo[prP2pDevFsmInfo->ucBssIndex])) { + if (!cnmP2PIsPermitted(prAdapter)) { + return; + } + + SET_NET_ACTIVE(prAdapter, prP2pDevFsmInfo->ucBssIndex); + nicActivateNetwork(prAdapter, + prP2pDevFsmInfo->ucBssIndex); + } + + fgIsLeaveState = fgIsLeaveState ? false : true; + + if (!fgIsLeaveState) { + DBGLOG(P2P, STATE, + "[P2P_DEV]TRANSITION: [%s] -> [%s]\n", + apucDebugP2pDevState[prP2pDevFsmInfo + ->eCurrentState], + apucDebugP2pDevState[eNextState]); + + /* Transition into current state. */ + prP2pDevFsmInfo->eCurrentState = eNextState; + } + + switch (prP2pDevFsmInfo->eCurrentState) { + case P2P_DEV_STATE_IDLE: + if (!fgIsLeaveState) { + fgIsLeaveState = p2pDevStateInit_IDLE( + prAdapter, + &prP2pDevFsmInfo->rChnlReqInfo, + &eNextState); + } else { + p2pDevStateAbort_IDLE(prAdapter); + } + break; + + case P2P_DEV_STATE_SCAN: + if (!fgIsLeaveState) { + p2pDevStateInit_SCAN( + prAdapter, prP2pDevFsmInfo->ucBssIndex, + &prP2pDevFsmInfo->rScanReqInfo); + } else { + p2pDevStateAbort_SCAN(prAdapter, + prP2pDevFsmInfo); + } + break; + + case P2P_DEV_STATE_REQING_CHANNEL: + if (!fgIsLeaveState) { + fgIsLeaveState = p2pDevStateInit_REQING_CHANNEL( + prAdapter, prP2pDevFsmInfo->ucBssIndex, + &(prP2pDevFsmInfo->rChnlReqInfo), + &eNextState); + } else { + p2pDevStateAbort_REQING_CHANNEL( + prAdapter, + &(prP2pDevFsmInfo->rChnlReqInfo), + eNextState); + } + break; + + case P2P_DEV_STATE_CHNL_ON_HAND: + if (!fgIsLeaveState) { + p2pDevStateInit_CHNL_ON_HAND( + prAdapter, + prAdapter->aprBssInfo + [prP2pDevFsmInfo->ucBssIndex], + prP2pDevFsmInfo, + &(prP2pDevFsmInfo->rChnlReqInfo)); + } else { + p2pDevStateAbort_CHNL_ON_HAND( + prAdapter, + prAdapter->aprBssInfo + [prP2pDevFsmInfo->ucBssIndex], + prP2pDevFsmInfo, + &(prP2pDevFsmInfo->rChnlReqInfo)); + } + break; + + case P2P_DEV_STATE_OFF_CHNL_TX: + if (!fgIsLeaveState) { + fgIsLeaveState = p2pDevStateInit_OFF_CHNL_TX( + prAdapter, prP2pDevFsmInfo, + &(prP2pDevFsmInfo->rChnlReqInfo), + &(prP2pDevFsmInfo->rMgmtTxInfo), + &eNextState); + } else { + p2pDevStateAbort_OFF_CHNL_TX( + prAdapter, + &(prP2pDevFsmInfo->rMgmtTxInfo), + &(prP2pDevFsmInfo->rChnlReqInfo), + eNextState); + } + break; + + default: + /* Unexpected state. */ + ASSERT(false); + break; + } + } while (fgIsLeaveState); +} + +void p2pDevFsmRunEventAbort(IN P_ADAPTER_T prAdapter, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pDevFsmInfo != NULL)); + + if (prP2pDevFsmInfo->eCurrentState != P2P_DEV_STATE_IDLE) { + /* Get into IDLE state. */ + p2pDevFsmStateTransition(prAdapter, prP2pDevFsmInfo, + P2P_DEV_STATE_IDLE); + } + + /* Abort IDLE. */ + p2pDevStateAbort_IDLE(prAdapter); + } while (false); +} + +void p2pDevFsmRunEventTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr) +{ + P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo = (P_P2P_DEV_FSM_INFO_T)ulParamPtr; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pDevFsmInfo != NULL)); + + switch (prP2pDevFsmInfo->eCurrentState) { + case P2P_DEV_STATE_IDLE: + /* TODO: IDLE timeout for low power mode. */ + break; + + case P2P_DEV_STATE_CHNL_ON_HAND: + p2pDevFsmStateTransition(prAdapter, prP2pDevFsmInfo, + P2P_DEV_STATE_IDLE); + break; + + default: + ASSERT(false); + DBGLOG(P2P, + ERROR, + "Current P2P Dev State %d is unexpected for FSM timeout event.\n", + prP2pDevFsmInfo->eCurrentState); + break; + } + } while (false); +} + +/*================ Message Event =================*/ +void p2pDevFsmRunEventScanRequest(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_P2P_SCAN_REQUEST_T prP2pScanReqMsg = + (P_MSG_P2P_SCAN_REQUEST_T)NULL; + P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo = (P_P2P_DEV_FSM_INFO_T)NULL; + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T)NULL; + u32 u4ChnlListSize = 0; + P_P2P_SSID_STRUCT_T prP2pSsidStruct = (P_P2P_SSID_STRUCT_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prP2pDevFsmInfo = prAdapter->rWifiVar.prP2pDevFsmInfo; + + if (prP2pDevFsmInfo == NULL) { + break; + } + + if (prP2pDevFsmInfo->eCurrentState != P2P_DEV_STATE_IDLE) { + p2pDevFsmRunEventAbort(prAdapter, prP2pDevFsmInfo); + } + + prP2pScanReqMsg = (P_MSG_P2P_SCAN_REQUEST_T)prMsgHdr; + prScanReqInfo = &(prP2pDevFsmInfo->rScanReqInfo); + + DBGLOG(P2P, TRACE, "p2pDevFsmRunEventScanRequest\n"); + + /* Do we need to be in IDLE state? */ + /* p2pDevFsmRunEventAbort(prAdapter, prP2pDevFsmInfo); */ + + ASSERT(prScanReqInfo->fgIsScanRequest == false); + + prScanReqInfo->fgIsAbort = true; + prScanReqInfo->eScanType = prP2pScanReqMsg->eScanType; + prScanReqInfo->u2PassiveDewellTime = 0; + + if (prP2pScanReqMsg->u4NumChannel) { + prScanReqInfo->eChannelSet = SCAN_CHANNEL_SPECIFIED; + + /* Channel List */ + prScanReqInfo->ucNumChannelList = + prP2pScanReqMsg->u4NumChannel; + DBGLOG(P2P, TRACE, + "Scan Request Channel List Number: %d\n", + prScanReqInfo->ucNumChannelList); + if (prScanReqInfo->ucNumChannelList > + MAXIMUM_OPERATION_CHANNEL_LIST) { + DBGLOG(P2P, + TRACE, + "Channel List Number Overloaded: %d, change to: %d\n", + prScanReqInfo->ucNumChannelList, + MAXIMUM_OPERATION_CHANNEL_LIST); + prScanReqInfo->ucNumChannelList = + MAXIMUM_OPERATION_CHANNEL_LIST; + } + + u4ChnlListSize = sizeof(RF_CHANNEL_INFO_T) * + prScanReqInfo->ucNumChannelList; + kalMemCopy(prScanReqInfo->arScanChannelList, + prP2pScanReqMsg->arChannelListInfo, + u4ChnlListSize); + } else { + /* If channel number is ZERO. + * It means do a FULL channel scan. + */ + prScanReqInfo->eChannelSet = SCAN_CHANNEL_FULL; + } + + /* SSID */ + prP2pSsidStruct = prP2pScanReqMsg->prSSID; + for (prScanReqInfo->ucSsidNum = 0; + prScanReqInfo->ucSsidNum < prP2pScanReqMsg->i4SsidNum; + prScanReqInfo->ucSsidNum++) { + kalMemCopy( + prScanReqInfo + ->arSsidStruct[prScanReqInfo->ucSsidNum] + .aucSsid, + prP2pSsidStruct->aucSsid, + prP2pSsidStruct->ucSsidLen); + + prScanReqInfo->arSsidStruct[prScanReqInfo->ucSsidNum] + .ucSsidLen = prP2pSsidStruct->ucSsidLen; + + prP2pSsidStruct++; + } + + /* IE Buffer */ + kalMemCopy(prScanReqInfo->aucIEBuf, prP2pScanReqMsg->pucIEBuf, + prP2pScanReqMsg->u4IELen); + + prScanReqInfo->u4BufLength = prP2pScanReqMsg->u4IELen; + + p2pDevFsmStateTransition(prAdapter, prP2pDevFsmInfo, + P2P_DEV_STATE_SCAN); + } while (false); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } +} + +void p2pDevFsmRunEventScanAbort(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx) +{ + P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo = (P_P2P_DEV_FSM_INFO_T)NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + DBGLOG(P2P, TRACE, "p2pDevFsmRunEventScanAbort\n"); + + prP2pDevFsmInfo = prAdapter->rWifiVar.prP2pDevFsmInfo; + + if (prP2pDevFsmInfo->eCurrentState == P2P_DEV_STATE_SCAN) { + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = + &(prP2pDevFsmInfo->rScanReqInfo); + + prScanReqInfo->fgIsAbort = true; + + p2pDevFsmStateTransition(prAdapter, prP2pDevFsmInfo, + P2P_DEV_STATE_IDLE); + } + } while (false); +} + +void p2pDevFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo) +{ + P_MSG_SCN_SCAN_DONE prScanDoneMsg = (P_MSG_SCN_SCAN_DONE)prMsgHdr; + P_P2P_SCAN_REQ_INFO_T prP2pScanReqInfo = (P_P2P_SCAN_REQ_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL) && + (prP2pDevFsmInfo != NULL)); + + if (!prP2pDevFsmInfo) { + DBGLOG(P2P, + ERROR, + "prP2pDevFsmInfo is null, maybe remove p2p already\n"); + break; + } + + prP2pScanReqInfo = &(prP2pDevFsmInfo->rScanReqInfo); + + if (prScanDoneMsg->ucSeqNum != + prP2pScanReqInfo->ucSeqNumOfScnMsg) { + DBGLOG(P2P, + TRACE, + "P2P Scan Done SeqNum:%d <-> P2P Dev FSM Scan SeqNum:%d", + prScanDoneMsg->ucSeqNum, + prP2pScanReqInfo->ucSeqNumOfScnMsg); + break; + } + + ASSERT_BREAK(prScanDoneMsg->ucBssIndex == + prP2pDevFsmInfo->ucBssIndex); + + prP2pScanReqInfo->fgIsAbort = false; + prP2pScanReqInfo->fgIsScanRequest = false; + + p2pDevFsmStateTransition(prAdapter, prP2pDevFsmInfo, + P2P_DEV_STATE_IDLE); + } while (false); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } +} + +void p2pDevFsmRunEventChannelRequest(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo = (P_P2P_DEV_FSM_INFO_T)NULL; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + u8 fgIsChnlFound = false; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + DBGLOG(P2P, STATE, "p2pDevFsmRunEventChannelRequest\n"); + + prP2pDevFsmInfo = prAdapter->rWifiVar.prP2pDevFsmInfo; + + if (prP2pDevFsmInfo == NULL) { + break; + } + + prChnlReqInfo = &(prP2pDevFsmInfo->rChnlReqInfo); + + DBGLOG(P2P, TRACE, "p2pDevFsmRunEventChannelRequest\n"); + + if (!LINK_IS_EMPTY(&prChnlReqInfo->rP2pChnlReqLink)) { + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T)NULL; + P_MSG_P2P_CHNL_REQUEST_T prP2pMsgChnlReq = + (P_MSG_P2P_CHNL_REQUEST_T)NULL; + + LINK_FOR_EACH(prLinkEntry, + &prChnlReqInfo->rP2pChnlReqLink) { + prP2pMsgChnlReq = + (P_MSG_P2P_CHNL_REQUEST_T)LINK_ENTRY( + prLinkEntry, MSG_HDR_T, + rLinkEntry); + + if (prP2pMsgChnlReq->eChnlReqType == + CH_REQ_TYPE_P2P_LISTEN) { + LINK_REMOVE_KNOWN_ENTRY( + &prChnlReqInfo->rP2pChnlReqLink, + prLinkEntry); + cnmMemFree(prAdapter, prP2pMsgChnlReq); + /* DBGLOG(P2P, TRACE, */ + /* ("p2pDevFsmRunEventChannelAbort: + * Channel Abort, cookie found:%d\n", */ + /* prChnlAbortMsg->u8Cookie)); */ + fgIsChnlFound = true; + break; + } + } + } + + /* Queue the channel request. */ + LINK_INSERT_TAIL(&(prChnlReqInfo->rP2pChnlReqLink), + &(prMsgHdr->rLinkEntry)); + prMsgHdr = NULL; + + /* If channel is not requested, it may due to channel is + * released. */ + if ((!fgIsChnlFound) && + (prChnlReqInfo->eChnlReqType == CH_REQ_TYPE_P2P_LISTEN) && + (prChnlReqInfo->fgIsChannelRequested)) { + ASSERT((prP2pDevFsmInfo->eCurrentState == + P2P_DEV_STATE_REQING_CHANNEL) || + (prP2pDevFsmInfo->eCurrentState == + P2P_DEV_STATE_CHNL_ON_HAND)); + + p2pDevFsmRunEventAbort(prAdapter, prP2pDevFsmInfo); + + break; + } + + if (prP2pDevFsmInfo->eCurrentState == P2P_DEV_STATE_IDLE) { + /* Re-enter IDLE state would trigger channel request. */ + p2pDevFsmStateTransition(prAdapter, prP2pDevFsmInfo, + P2P_DEV_STATE_IDLE); + } + } while (false); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } +} + +void p2pDevFsmRunEventChannelAbort(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo = (P_P2P_DEV_FSM_INFO_T)NULL; + P_MSG_P2P_CHNL_ABORT_T prChnlAbortMsg = (P_MSG_P2P_CHNL_ABORT_T)NULL; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prChnlAbortMsg = (P_MSG_P2P_CHNL_ABORT_T)prMsgHdr; + + prP2pDevFsmInfo = prAdapter->rWifiVar.prP2pDevFsmInfo; + + if (prP2pDevFsmInfo == NULL) { + break; + } + + prChnlReqInfo = &(prP2pDevFsmInfo->rChnlReqInfo); + + DBGLOG(P2P, TRACE, "p2pDevFsmRunEventChannelAbort\n"); + + /* If channel is not requested, it may due to channel is + * released. */ + if ((prChnlAbortMsg->u8Cookie == prChnlReqInfo->u8Cookie) && + (prChnlReqInfo->fgIsChannelRequested)) { + ASSERT((prP2pDevFsmInfo->eCurrentState == + P2P_DEV_STATE_REQING_CHANNEL) || + (prP2pDevFsmInfo->eCurrentState == + P2P_DEV_STATE_CHNL_ON_HAND)); + + p2pDevFsmRunEventAbort(prAdapter, prP2pDevFsmInfo); + + break; + } else if (!LINK_IS_EMPTY(&prChnlReqInfo->rP2pChnlReqLink)) { + P_LINK_ENTRY_T prLinkEntry = (P_LINK_ENTRY_T)NULL; + P_MSG_P2P_CHNL_REQUEST_T prP2pMsgChnlReq = + (P_MSG_P2P_CHNL_REQUEST_T)NULL; + + LINK_FOR_EACH(prLinkEntry, + &prChnlReqInfo->rP2pChnlReqLink) { + prP2pMsgChnlReq = + (P_MSG_P2P_CHNL_REQUEST_T)LINK_ENTRY( + prLinkEntry, MSG_HDR_T, + rLinkEntry); + + if (prP2pMsgChnlReq->u8Cookie == + prChnlAbortMsg->u8Cookie) { + LINK_REMOVE_KNOWN_ENTRY( + &prChnlReqInfo->rP2pChnlReqLink, + prLinkEntry); + cnmMemFree(prAdapter, prP2pMsgChnlReq); + DBGLOG(P2P, + TRACE, + "p2pDevFsmRunEventChannelAbort: Channel Abort, cookie found:%d\n", + prChnlAbortMsg->u8Cookie); + break; + } + } + } else { + DBGLOG(P2P, + WARN, + "p2pDevFsmRunEventChannelAbort: Channel Abort Fail, cookie not found:%d\n", + prChnlAbortMsg->u8Cookie); + } + } while (false); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } +} + +void p2pDevFsmRunEventChnlGrant(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo) +{ + P_MSG_CH_GRANT_T prMsgChGrant = (P_MSG_CH_GRANT_T)NULL; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + + do { + ASSERT((prAdapter != NULL) && (prMsgHdr != NULL) && + (prP2pDevFsmInfo != NULL)); + if ((prAdapter == NULL) || (prMsgHdr == NULL) || + (prP2pDevFsmInfo == NULL)) { + break; + } + + prMsgChGrant = (P_MSG_CH_GRANT_T)prMsgHdr; + prChnlReqInfo = &(prP2pDevFsmInfo->rChnlReqInfo); + + if ((prMsgChGrant->ucTokenID != + prChnlReqInfo->ucSeqNumOfChReq) || + (!prChnlReqInfo->fgIsChannelRequested)) { + break; + } + + ASSERT(prMsgChGrant->ucPrimaryChannel == + prChnlReqInfo->ucReqChnlNum); + ASSERT(prMsgChGrant->eReqType == prChnlReqInfo->eChnlReqType); + ASSERT(prMsgChGrant->u4GrantInterval == + prChnlReqInfo->u4MaxInterval); + prChnlReqInfo->u4MaxInterval = prMsgChGrant->u4GrantInterval; + + if (prMsgChGrant->eReqType == CH_REQ_TYPE_P2P_LISTEN) { + p2pDevFsmStateTransition(prAdapter, prP2pDevFsmInfo, + P2P_DEV_STATE_CHNL_ON_HAND); + } else { + ASSERT(prMsgChGrant->eReqType == + CH_REQ_TYPE_OFFCHNL_TX); + p2pDevFsmStateTransition(prAdapter, prP2pDevFsmInfo, + P2P_DEV_STATE_OFF_CHNL_TX); + } + } while (false); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } +} + +void p2pDevFsmRunEventMgmtTx(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo = (P_P2P_DEV_FSM_INFO_T)NULL; + P_MSG_P2P_MGMT_TX_REQUEST_T prMgmtTxMsg = + (P_MSG_P2P_MGMT_TX_REQUEST_T)NULL; + P_P2P_CHNL_REQ_INFO_T prP2pChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + P_P2P_MGMT_TX_REQ_INFO_T prP2pMgmtTxReqInfo = + (P_P2P_MGMT_TX_REQ_INFO_T)NULL; + + prMgmtTxMsg = (P_MSG_P2P_MGMT_TX_REQUEST_T)prMsgHdr; + + if ((prMgmtTxMsg->ucBssIdx != P2P_DEV_BSS_INDEX) && + (IS_NET_ACTIVE(prAdapter, prMgmtTxMsg->ucBssIdx))) { + DBGLOG(P2P, TRACE, " Role Interface\n"); + p2pFuncTxMgmtFrame(prAdapter, prMgmtTxMsg->ucBssIdx, + prMgmtTxMsg->prMgmtMsduInfo, + prMgmtTxMsg->fgNoneCckRate); + goto error; + } + + DBGLOG(P2P, TRACE, " Device Interface\n"); + DBGLOG(P2P, STATE, "p2pDevFsmRunEventMgmtTx\n"); + + prMgmtTxMsg->ucBssIdx = P2P_DEV_BSS_INDEX; + + prP2pDevFsmInfo = prAdapter->rWifiVar.prP2pDevFsmInfo; + + if (prP2pDevFsmInfo == NULL) { + DBGLOG(P2P, ERROR, "prP2pDevFsmInfo is NULL!\n"); + goto error; + } + + prP2pChnlReqInfo = &(prP2pDevFsmInfo->rChnlReqInfo); + prP2pMgmtTxReqInfo = &(prP2pDevFsmInfo->rMgmtTxInfo); + + if ((!prMgmtTxMsg->fgIsOffChannel) || + ((prP2pDevFsmInfo->eCurrentState == P2P_DEV_STATE_OFF_CHNL_TX) && + (LINK_IS_EMPTY(&prP2pMgmtTxReqInfo->rP2pTxReqLink)))) { + p2pFuncTxMgmtFrame(prAdapter, prP2pDevFsmInfo->ucBssIndex, + prMgmtTxMsg->prMgmtMsduInfo, + prMgmtTxMsg->fgNoneCckRate); + } else { + P_P2P_OFF_CHNL_TX_REQ_INFO_T prOffChnlTxReq = + (P_P2P_OFF_CHNL_TX_REQ_INFO_T)NULL; + + prOffChnlTxReq = + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(P2P_OFF_CHNL_TX_REQ_INFO_T)); + + if (prOffChnlTxReq == NULL) { + DBGLOG(P2P, + ERROR, + "Can not serve TX request due to MSG buffer not enough\n"); + ASSERT(false); + goto error; + } + + prOffChnlTxReq->prMgmtTxMsdu = prMgmtTxMsg->prMgmtMsduInfo; + prOffChnlTxReq->fgNoneCckRate = prMgmtTxMsg->fgNoneCckRate; + kalMemCopy(&prOffChnlTxReq->rChannelInfo, + &prMgmtTxMsg->rChannelInfo, + sizeof(RF_CHANNEL_INFO_T)); + prOffChnlTxReq->eChnlExt = prMgmtTxMsg->eChnlExt; + prOffChnlTxReq->fgIsWaitRsp = prMgmtTxMsg->fgIsWaitRsp; + + LINK_INSERT_TAIL(&prP2pMgmtTxReqInfo->rP2pTxReqLink, + &prOffChnlTxReq->rLinkEntry); + + /* Channel Request if needed. */ + if (prP2pDevFsmInfo->eCurrentState != + P2P_DEV_STATE_OFF_CHNL_TX) { + P_MSG_P2P_CHNL_REQUEST_T prP2pMsgChnlReq = + (P_MSG_P2P_CHNL_REQUEST_T)NULL; + + prP2pMsgChnlReq = + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_CHNL_REQUEST_T)); + + if (prP2pMsgChnlReq == NULL) { + cnmMemFree(prAdapter, prOffChnlTxReq); + ASSERT(false); + DBGLOG(P2P, + ERROR, + "Not enough MSG buffer for channel request\n"); + goto error; + } + + prP2pMsgChnlReq->eChnlReqType = CH_REQ_TYPE_OFFCHNL_TX; + + /* Not used in TX OFFCHNL REQ fields. */ + prP2pMsgChnlReq->rMsgHdr.eMsgId = MID_MNY_P2P_CHNL_REQ; + prP2pMsgChnlReq->u8Cookie = 0; + prP2pMsgChnlReq->u4Duration = + P2P_OFF_CHNL_TX_DEFAULT_TIME_MS; + + kalMemCopy(&prP2pMsgChnlReq->rChannelInfo, + &prMgmtTxMsg->rChannelInfo, + sizeof(RF_CHANNEL_INFO_T)); + prP2pMsgChnlReq->eChnlSco = prMgmtTxMsg->eChnlExt; + + p2pDevFsmRunEventChannelRequest( + prAdapter, (P_MSG_HDR_T)prP2pMsgChnlReq); + } + } + +error: + cnmMemFree(prAdapter, prMsgHdr); +} + +WLAN_STATUS +p2pDevFsmRunEventMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + u8 fgIsSuccess = false; + P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo = (P_P2P_DEV_FSM_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + prP2pDevFsmInfo = prAdapter->rWifiVar.prP2pDevFsmInfo; + + if (prP2pDevFsmInfo->eCurrentState == + P2P_DEV_STATE_OFF_CHNL_TX) { + p2pDevFsmStateTransition(prAdapter, prP2pDevFsmInfo, + P2P_DEV_STATE_OFF_CHNL_TX); + } + + if (rTxDoneStatus != TX_RESULT_SUCCESS) { + DBGLOG(P2P, TRACE, "Mgmt Frame TX Fail, Status:%d.\n", + rTxDoneStatus); + } else { + fgIsSuccess = true; + DBGLOG(P2P, TRACE, "Mgmt Frame TX Done.\n"); + } + + kalP2PIndicateMgmtTxStatus(prAdapter->prGlueInfo, prMsduInfo, + fgIsSuccess); + } while (false); + + return WLAN_STATUS_SUCCESS; +} + +void p2pDevFsmRunEventMgmtFrameRegister(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + /* TODO: RX Filter Management. */ + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } +} + +void p2pDevFsmRunEventActiveDevBss(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo = (P_P2P_DEV_FSM_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + prP2pDevFsmInfo = prAdapter->rWifiVar.prP2pDevFsmInfo; + + if (prP2pDevFsmInfo->eCurrentState == P2P_DEV_STATE_IDLE) { + /* Get into IDLE state to let BSS be active and do not + * Deactive. */ + p2pDevFsmStateTransition(prAdapter, prP2pDevFsmInfo, + P2P_DEV_STATE_IDLE); + } + } while (false); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } +} + +#endif + +void p2pRoleFsmRunEventScanAbort(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = NULL; + P_BSS_INFO_T prP2pBssInfo = NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + DBGLOG(P2P, TRACE, "p2pRoleFsmRunEventScanAbort\n"); + + prP2pBssInfo = prAdapter->aprBssInfo[ucBssIdx]; + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO( + prAdapter, prP2pBssInfo->u4PrivateData); + + if (prP2pRoleFsmInfo->eCurrentState == P2P_ROLE_STATE_SCAN) { + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = + &(prP2pRoleFsmInfo->rScanReqInfo); + + prScanReqInfo->fgIsAbort = true; + + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_IDLE); + } + } while (false); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_dev_state.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_dev_state.c new file mode 100644 index 00000000000000..adb1475a5afcb9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_dev_state.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ +#include "precomp.h" +#include "p2p_dev_state.h" + +u8 p2pDevStateInit_IDLE(IN P_ADAPTER_T prAdapter, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + OUT P_ENUM_P2P_DEV_STATE_T peNextState) +{ + u8 fgIsTransition = false, fgIsShareInterface = true; + u32 u4Idx = 0; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo) && + (peNextState != NULL)); + + if (!LINK_IS_EMPTY(&(prChnlReqInfo->rP2pChnlReqLink))) { + fgIsTransition = true; + *peNextState = P2P_DEV_STATE_REQING_CHANNEL; + break; + } + + /* Check the interface shared by P2P_DEV and P2P_ROLE or not? */ + /* If not shared, we shall let BSSID4 alive to receive PROVISION + * REQUEST from GC */ + prGlueInfo = prAdapter->prGlueInfo; + if (prGlueInfo) { + for (u4Idx = 0; u4Idx < KAL_P2P_NUM; u4Idx++) { + if ((prGlueInfo->prP2PInfo[u4Idx] != NULL) && + (prGlueInfo->prP2PInfo[u4Idx] + ->aprRoleHandler != NULL) && + (prGlueInfo->prP2PInfo[u4Idx] + ->aprRoleHandler != + prGlueInfo->prP2PInfo[u4Idx] + ->prDevHandler)) { + fgIsShareInterface = false; + break; + } + } + } + /************************* End *************************/ + + if (fgIsShareInterface) { + /* Stay in IDLE state. */ + UNSET_NET_ACTIVE(prAdapter, P2P_DEV_BSS_INDEX); + nicDeactivateNetwork(prAdapter, P2P_DEV_BSS_INDEX); + } + } while (false); + + return fgIsTransition; +} + +void p2pDevStateAbort_IDLE(IN P_ADAPTER_T prAdapter) +{ + /* Currently Aobrt IDLE do nothing. */ +} + +u8 p2pDevStateInit_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + OUT P_ENUM_P2P_DEV_STATE_T peNextState) +{ + u8 fgIsTransition = false; + P_MSG_P2P_CHNL_REQUEST_T prP2pMsgChnlReq = + (P_MSG_P2P_CHNL_REQUEST_T)NULL; + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T)NULL; +#if CFG_SUPPORT_DBDC + CNM_DBDC_CAP_T rDbdcCap; +#endif + + do { + ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL) && + (peNextState != NULL)); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIdx); + + if (LINK_IS_EMPTY(&(prChnlReqInfo->rP2pChnlReqLink))) { + /* NO Channel Request Pending. */ + DBGLOG(P2P, + ERROR, + "NO Pending Channel Request, but enter Req Channel State\n"); + fgIsTransition = true; + *peNextState = P2P_DEV_STATE_IDLE; + break; + } + + LINK_REMOVE_HEAD(&(prChnlReqInfo->rP2pChnlReqLink), + prP2pMsgChnlReq, P_MSG_P2P_CHNL_REQUEST_T); + + ASSERT(prP2pMsgChnlReq); + +#if (CFG_HW_WMM_BY_BSS == 1) + if (prBssInfo->fgIsWmmInited == false) { + prBssInfo->ucWmmQueSet = MAX_HW_WMM_INDEX; + } +#endif +#if CFG_SUPPORT_DBDC + cnmGetDbdcCapability(prAdapter, prBssInfo->ucBssIndex, + prP2pMsgChnlReq->rChannelInfo.eBand, + prP2pMsgChnlReq->rChannelInfo.ucChannelNum, + wlanGetSupportNss(prAdapter, + prBssInfo->ucBssIndex), + &rDbdcCap); + + prBssInfo->eDBDCBand = ENUM_BAND_AUTO; + prBssInfo->ucNss = rDbdcCap.ucNss; +#if (CFG_HW_WMM_BY_BSS == 0) + prBssInfo->ucWmmQueSet = rDbdcCap.ucWmmSetIndex; +#endif +#endif + prChnlReqInfo->u4MaxInterval = prP2pMsgChnlReq->u4Duration; + prChnlReqInfo->ucReqChnlNum = + prP2pMsgChnlReq->rChannelInfo.ucChannelNum; + prChnlReqInfo->eChnlSco = prP2pMsgChnlReq->eChnlSco; + prChnlReqInfo->eBand = prP2pMsgChnlReq->rChannelInfo.eBand; + prChnlReqInfo->u8Cookie = prP2pMsgChnlReq->u8Cookie; + prChnlReqInfo->eChnlReqType = prP2pMsgChnlReq->eChnlReqType; + prChnlReqInfo->eChannelWidth = prBssInfo->ucVhtChannelWidth; + prChnlReqInfo->ucCenterFreqS1 = + prBssInfo->ucVhtChannelFrequencyS1; + prChnlReqInfo->ucCenterFreqS2 = + prBssInfo->ucVhtChannelFrequencyS2; + + p2pFuncAcquireCh(prAdapter, ucBssIdx, prChnlReqInfo); + } while (false); + + if (prP2pMsgChnlReq) { + cnmMemFree(prAdapter, prP2pMsgChnlReq); + } + + return fgIsTransition; +} + +void p2pDevStateAbort_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN ENUM_P2P_DEV_STATE_T eNextState) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL) && + (eNextState < P2P_DEV_STATE_NUM)); + + switch (eNextState) { + case P2P_DEV_STATE_IDLE: + /* Channel abort case. */ + p2pFuncReleaseCh(prAdapter, P2P_DEV_BSS_INDEX, + prChnlReqInfo); + break; + + case P2P_DEV_STATE_CHNL_ON_HAND: + /* Channel on hand case. */ + break; + + default: + /* Un-expected state transition. */ + DBGLOG(P2P, ERROR, + "Unexpected State Transition(eNextState=%d)\n", + eNextState); + ASSERT(false); + break; + } + } while (false); +} + +void p2pDevStateInit_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pDevFsmInfo != NULL) && + (prChnlReqInfo != NULL)); + + ASSERT(prChnlReqInfo->eChnlReqType == CH_REQ_TYPE_P2P_LISTEN); + + prChnlReqInfo->ucOriChnlNum = prP2pBssInfo->ucPrimaryChannel; + prChnlReqInfo->eOriBand = prP2pBssInfo->eBand; + prChnlReqInfo->eOriChnlSco = prP2pBssInfo->eBssSCO; + + prP2pBssInfo->ucPrimaryChannel = prChnlReqInfo->ucReqChnlNum; + prP2pBssInfo->eBand = prChnlReqInfo->eBand; + prP2pBssInfo->eBssSCO = prChnlReqInfo->eChnlSco; + + cnmTimerStartTimer(prAdapter, + &(prP2pDevFsmInfo->rP2pFsmTimeoutTimer), + prChnlReqInfo->u4MaxInterval); + + kalP2PIndicateChannelReady( + prAdapter->prGlueInfo, prChnlReqInfo->u8Cookie, + prChnlReqInfo->ucReqChnlNum, prChnlReqInfo->eBand, + prChnlReqInfo->eChnlSco, prChnlReqInfo->u4MaxInterval); + } while (false); +} + +void p2pDevStateAbort_CHNL_ON_HAND(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + do { + ASSERT_BREAK((prAdapter != NULL) || (prChnlReqInfo != NULL)); + + cnmTimerStopTimer(prAdapter, + &(prP2pDevFsmInfo->rP2pFsmTimeoutTimer)); + + prP2pBssInfo->ucPrimaryChannel = prChnlReqInfo->ucOriChnlNum; + prP2pBssInfo->eBand = prChnlReqInfo->eOriBand; + prP2pBssInfo->eBssSCO = prChnlReqInfo->eOriChnlSco; + + kalP2PIndicateChannelExpired(prAdapter->prGlueInfo, + prChnlReqInfo->u8Cookie, + prChnlReqInfo->ucReqChnlNum, + prChnlReqInfo->eBand, + prChnlReqInfo->eChnlSco); + + p2pFuncReleaseCh(prAdapter, prP2pDevFsmInfo->ucBssIndex, + prChnlReqInfo); + } while (false); +} + +void p2pDevStateInit_SCAN(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prScanReqInfo != NULL)); + + prScanReqInfo->fgIsScanRequest = true; + + p2pFuncRequestScan(prAdapter, ucBssIndex, prScanReqInfo); + } while (false); +} + +void p2pDevStateAbort_SCAN(IN P_ADAPTER_T prAdapter, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo) +{ + P_P2P_SCAN_REQ_INFO_T prScanInfo = (P_P2P_SCAN_REQ_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pDevFsmInfo != NULL)); + + prScanInfo = &(prP2pDevFsmInfo->rScanReqInfo); + + p2pFuncCancelScan(prAdapter, prP2pDevFsmInfo->ucBssIndex, + prScanInfo); + + kalP2PIndicateScanDone(prAdapter->prGlueInfo, 0xFF, + prScanInfo->fgIsAbort); + } while (false); +} + +u8 p2pDevStateInit_OFF_CHNL_TX(IN P_ADAPTER_T prAdapter, + IN P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN P_P2P_MGMT_TX_REQ_INFO_T prP2pMgmtTxInfo, + OUT P_ENUM_P2P_DEV_STATE_T peNextState) +{ + P_P2P_OFF_CHNL_TX_REQ_INFO_T prP2pOffChnlTxPkt = + (P_P2P_OFF_CHNL_TX_REQ_INFO_T)NULL; + u8 fgIsTransition = false; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pMgmtTxInfo != NULL) && + (peNextState != NULL)); + + if (!LINK_IS_EMPTY(&(prP2pMgmtTxInfo->rP2pTxReqLink))) { + prP2pOffChnlTxPkt = LINK_PEEK_HEAD( + &(prP2pMgmtTxInfo->rP2pTxReqLink), + P2P_OFF_CHNL_TX_REQ_INFO_T, rLinkEntry); + + if (prP2pOffChnlTxPkt == NULL) { + DBGLOG(P2P, + ERROR, + "Fetal Error, Link not empty but get NULL pointer.\n"); + ASSERT(false); + break; + } + + if (prChnlReqInfo->ucReqChnlNum != + prP2pOffChnlTxPkt->rChannelInfo.ucChannelNum) { + prChnlReqInfo->ucReqChnlNum = + prP2pOffChnlTxPkt->rChannelInfo + .ucChannelNum; + prChnlReqInfo->eChnlSco = + prP2pOffChnlTxPkt->eChnlExt; + prChnlReqInfo->eBand = + prP2pOffChnlTxPkt->rChannelInfo.eBand; + prChnlReqInfo->u8Cookie = 0; + prChnlReqInfo->eChannelWidth = CW_20_40MHZ; + prChnlReqInfo->ucCenterFreqS1 = 0; + prChnlReqInfo->ucCenterFreqS2 = 0; + ASSERT(prChnlReqInfo->eChnlReqType == + CH_REQ_TYPE_OFFCHNL_TX); + + p2pFuncAcquireCh(prAdapter, + prP2pDevFsmInfo->ucBssIndex, + prChnlReqInfo); + } else { + LINK_REMOVE_HEAD( + &(prP2pMgmtTxInfo->rP2pTxReqLink), + prP2pOffChnlTxPkt, + P_P2P_OFF_CHNL_TX_REQ_INFO_T); + + p2pFuncTxMgmtFrame( + prAdapter, prP2pDevFsmInfo->ucBssIndex, + prP2pOffChnlTxPkt->prMgmtTxMsdu, + prP2pOffChnlTxPkt->fgNoneCckRate); + + prP2pMgmtTxInfo->prMgmtTxMsdu = + prP2pOffChnlTxPkt->prMgmtTxMsdu; + prP2pMgmtTxInfo->fgIsWaitRsp = + prP2pOffChnlTxPkt->fgIsWaitRsp; + } + } else { + /* Link is empty, return back to IDLE. */ + *peNextState = P2P_DEV_STATE_IDLE; + fgIsTransition = true; + } + } while (false); + + return fgIsTransition; +} + +void p2pDevStateAbort_OFF_CHNL_TX(IN P_ADAPTER_T prAdapter, + IN P_P2P_MGMT_TX_REQ_INFO_T prP2pMgmtTxInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN ENUM_P2P_DEV_STATE_T eNextState) +{ + P_P2P_OFF_CHNL_TX_REQ_INFO_T prP2pOffChnlTxPkt = + (P_P2P_OFF_CHNL_TX_REQ_INFO_T)NULL; + + if (eNextState != P2P_DEV_STATE_OFF_CHNL_TX) { + while (!LINK_IS_EMPTY(&(prP2pMgmtTxInfo->rP2pTxReqLink))) { + LINK_REMOVE_HEAD(&(prP2pMgmtTxInfo->rP2pTxReqLink), + prP2pOffChnlTxPkt, + P_P2P_OFF_CHNL_TX_REQ_INFO_T); + + if (prP2pOffChnlTxPkt) { + kalP2PIndicateMgmtTxStatus( + prAdapter->prGlueInfo, + prP2pOffChnlTxPkt->prMgmtTxMsdu, false); + } else { + DBGLOG(P2P, INFO, + "No packet for indicating Tx status!\n"); + } + } + + p2pFuncReleaseCh(prAdapter, P2P_DEV_BSS_INDEX, prChnlReqInfo); + } +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_fsm.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_fsm.c new file mode 100644 index 00000000000000..7fb557ffa171bb --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_fsm.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "p2p_fsm.c" + * \brief This file defines the FSM for P2P Module. + * + * This file defines the FSM for P2P Module. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +#if CFG_ENABLE_WIFI_DIRECT + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ +void p2pFsmRunEventScanRequest(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_P2P_SCAN_REQUEST_T prP2pScanReqMsg = + (P_MSG_P2P_SCAN_REQUEST_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + if ((prAdapter == NULL) || (prMsgHdr == NULL)) { + break; + } + + prP2pScanReqMsg = (P_MSG_P2P_SCAN_REQUEST_T)prMsgHdr; + + if (prP2pScanReqMsg->ucBssIdx == P2P_DEV_BSS_INDEX) { + p2pDevFsmRunEventScanRequest(prAdapter, prMsgHdr); + }else{ + p2pRoleFsmRunEventScanRequest(prAdapter, prMsgHdr); + } + + prMsgHdr = NULL; + /* Both p2pDevFsmRunEventScanRequest and + * p2pRoleFsmRunEventScanRequest free prMsgHdr before return, so + * prMsgHdr is needed to be NULL. + */ + } while (false); + + if (prMsgHdr != NULL) { + cnmMemFree(prAdapter, prMsgHdr); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is call when channel is granted by CNM module from + * FW. + * + * \param[in] prAdapter Pointer of ADAPTER_T + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void p2pFsmRunEventChGrant(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_CH_GRANT_T prMsgChGrant = (P_MSG_CH_GRANT_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsgHdr != NULL)); + + prMsgChGrant = (P_MSG_CH_GRANT_T)prMsgHdr; + + prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, + prMsgChGrant->ucBssIndex); + + if (!prP2pBssInfo) { + break; + } + + DBGLOG(P2P, TRACE, "P2P Run Event Channel Grant\n"); + +#if CFG_SUPPORT_DBDC + if (prP2pBssInfo->eDBDCBand == ENUM_BAND_AUTO) { + prP2pBssInfo->eDBDCBand = prMsgChGrant->eDBDCBand; + } +#endif + +#if CFG_SISO_SW_DEVELOP + /* Driver record granted CH in BSS info */ + prP2pBssInfo->fgIsGranted = true; + prP2pBssInfo->eBandGranted = prMsgChGrant->eRfBand; + prP2pBssInfo->ucPrimaryChannelGranted = + prMsgChGrant->ucPrimaryChannel; +#endif + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_P2P_DEVICE: + ASSERT(prP2pBssInfo->ucBssIndex == P2P_DEV_BSS_INDEX); + p2pDevFsmRunEventChnlGrant( + prAdapter, prMsgHdr, + prAdapter->rWifiVar.prP2pDevFsmInfo); + break; + + case OP_MODE_INFRASTRUCTURE: + case OP_MODE_ACCESS_POINT: + ASSERT(prP2pBssInfo->ucBssIndex < P2P_DEV_BSS_INDEX); + p2pRoleFsmRunEventChnlGrant( + prAdapter, prMsgHdr, + P2P_ROLE_INDEX_2_ROLE_FSM_INFO( + prAdapter, + prP2pBssInfo->u4PrivateData)); + break; + + default: + ASSERT(false); + break; + } + } while (false); +} + +void p2pFsmRunEventNetDeviceRegister(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_P2P_NETDEV_REGISTER_T prNetDevRegisterMsg = + (P_MSG_P2P_NETDEV_REGISTER_T)NULL; + + DBGLOG(P2P, TRACE, "p2pFsmRunEventNetDeviceRegister\n"); + + prNetDevRegisterMsg = (P_MSG_P2P_NETDEV_REGISTER_T)prMsgHdr; + + if (prNetDevRegisterMsg->fgIsEnable) { + p2pSetMode((prNetDevRegisterMsg->ucMode == 1) ? true : false); + if (p2pLaunch(prAdapter->prGlueInfo)) { + ASSERT(prAdapter->fgIsP2PRegistered); + } + } else { + if (prAdapter->fgIsP2PRegistered) { + p2pRemove(prAdapter->prGlueInfo); + } + } + + cnmMemFree(prAdapter, prMsgHdr); +} + +void p2pFsmRunEventUpdateMgmtFrame(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_P2P_MGMT_FRAME_UPDATE_T prP2pMgmtFrameUpdateMsg = + (P_MSG_P2P_MGMT_FRAME_UPDATE_T)NULL; + + DBGLOG(P2P, TRACE, "p2pFsmRunEventUpdateMgmtFrame\n"); + + prP2pMgmtFrameUpdateMsg = (P_MSG_P2P_MGMT_FRAME_UPDATE_T)prMsgHdr; + + switch (prP2pMgmtFrameUpdateMsg->eBufferType) { + case ENUM_FRAME_TYPE_EXTRA_IE_BEACON: + break; + + case ENUM_FRAME_TYPE_EXTRA_IE_ASSOC_RSP: + break; + + case ENUM_FRAME_TYPE_EXTRA_IE_PROBE_RSP: + break; + + case ENUM_FRAME_TYPE_PROBE_RSP_TEMPLATE: + break; + + case ENUM_FRAME_TYPE_BEACON_TEMPLATE: + break; + + default: + break; + } + + cnmMemFree(prAdapter, prMsgHdr); +} + +#if CFG_SUPPORT_WFD +void p2pFsmRunEventWfdSettingUpdate(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T)NULL; + P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgSettings = + (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T)NULL; + u32 i; + + /* WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; */ + + DBGLOG(P2P, INFO, "p2pFsmRunEventWfdSettingUpdate\n"); + + do { + ASSERT_BREAK((prAdapter != NULL)); + + if (prMsgHdr != NULL) { + prMsgWfdCfgSettings = + (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T)prMsgHdr; + prWfdCfgSettings = + prMsgWfdCfgSettings->prWfdCfgSettings; + } else { + prWfdCfgSettings = + &prAdapter->rWifiVar.rWfdConfigureSettings; + } + + DBGLOG(P2P, INFO, + "WFD Enalbe %x info %x state %x flag %x adv %x\n", + prWfdCfgSettings->ucWfdEnable, + prWfdCfgSettings->u2WfdDevInfo, + (u32)prWfdCfgSettings->u4WfdState, + (u32)prWfdCfgSettings->u4WfdFlag, + (u32)prWfdCfgSettings->u4WfdAdvancedFlag); + + if (prWfdCfgSettings->ucWfdEnable == 0) { + for (i = 0; i < KAL_P2P_NUM; i++) { + if (prAdapter->prGlueInfo->prP2PInfo[i]) { + prAdapter->prGlueInfo->prP2PInfo[i] + ->u2WFDIELen = 0; + } + } + } + } while (false); + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } +} + +/* p2pFsmRunEventWfdSettingUpdate */ + +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is used to handle scan done event during Device + * Discovery. + * + * \param[in] prAdapter Pointer of ADAPTER_T + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void p2pFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_SCN_SCAN_DONE prScanDoneMsg = (P_MSG_SCN_SCAN_DONE)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE)prMsgHdr; + + prP2pBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, + prScanDoneMsg->ucBssIndex); + + if (prAdapter->fgIsP2PRegistered == false) { + DBGLOG(P2P, TRACE, + "P2P BSS Info is removed, break p2pFsmRunEventScanDone\n"); + + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + DBGLOG(P2P, TRACE, "P2P Scan Done Event\n"); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_P2P_DEVICE: + ASSERT(prP2pBssInfo->ucBssIndex == P2P_DEV_BSS_INDEX); + p2pDevFsmRunEventScanDone(prAdapter, prMsgHdr, + prAdapter->rWifiVar.prP2pDevFsmInfo); + break; + + case OP_MODE_INFRASTRUCTURE: + case OP_MODE_ACCESS_POINT: + ASSERT(prP2pBssInfo->ucBssIndex < P2P_DEV_BSS_INDEX); + p2pRoleFsmRunEventScanDone( + prAdapter, prMsgHdr, + P2P_ROLE_INDEX_2_ROLE_FSM_INFO( + prAdapter, prP2pBssInfo->u4PrivateData)); + break; + + default: + ASSERT(false); + break; + } +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_func.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_func.c new file mode 100644 index 00000000000000..56b5e98c7cd9a6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_func.c @@ -0,0 +1,4391 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ +#include "precomp.h" + +APPEND_VAR_ATTRI_ENTRY_T txAssocRspAttributesTable[] = { + { (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_STATUS), NULL, + p2pFuncAppendAttriStatusForAssocRsp } + /* 0 */ /* Status */ + , + { (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING), NULL, + p2pFuncAppendAttriExtListenTiming } +}; + +APPEND_VAR_IE_ENTRY_T txProbeRspIETable[] = { + { (ELEM_HDR_LEN + (RATE_NUM_SW - ELEM_MAX_LEN_SUP_RATES)), NULL, + bssGenerateExtSuppRate_IE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_ERP), NULL, rlmRspGenerateErpIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP), NULL, rlmRspGenerateHtCapIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP), NULL, rlmRspGenerateHtOpIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_RSN), NULL, rsnGenerateRSNIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN), NULL, rlmRspGenerateObssScanIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP), NULL, rlmRspGenerateExtCapIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WPA), NULL, rsnGenerateWpaNoneIE }, + { (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_PARAM), NULL, mqmGenerateWmmParamIE } +#if CFG_SUPPORT_802_11AC + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_CAP), NULL, + rlmRspGenerateVhtCapIE } /*191 */ + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_OP), NULL, + rlmRspGenerateVhtOpIE } /*192 */ + , + { (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_OP_MODE_NOTIFICATION), NULL, + rlmRspGenerateVhtOpNotificationIE } /*199 */ +#endif +#if CFG_SUPPORT_MTK_SYNERGY + , + { (ELEM_HDR_LEN + ELEM_MIN_LEN_MTK_OUI), NULL, rlmGenerateMTKOuiIE } +#endif +}; + +#if (CFG_SUPPORT_DFS_MASTER == 1) +u8 g_fgManualCac = false; +u32 g_u4DriverCacTime; +u32 g_u4CacStartBootTime; +u8 g_ucRadarDetectMode = false; +struct P2P_RADAR_INFO g_rP2pRadarInfo; +u8 g_ucDfsState = DFS_STATE_INACTIVE; +static u8 *apucDfsState[DFS_STATE_NUM] = { + (u8 *)DISP_STRING("DFS_STATE_INACTIVE"), + (u8 *)DISP_STRING("DFS_STATE_CHECKING"), + (u8 *)DISP_STRING("DFS_STATE_ACTIVE"), + (u8 *)DISP_STRING("DFS_STATE_DETECTED") +}; + +u8 *apucW53RadarType[3] = { (u8 *)DISP_STRING("Unknown Type"), + (u8 *)DISP_STRING("Type 1 (short pulse)"), + (u8 *)DISP_STRING("Type 2 (short pulse)") }; +u8 *apucW56RadarType[12] = { + (u8 *)DISP_STRING("Unknown Type"), + (u8 *)DISP_STRING("Type 1 (short pulse)"), + (u8 *)DISP_STRING("Type 2 (short pulse)"), + (u8 *)DISP_STRING("Type 3 (short pulse)"), + (u8 *)DISP_STRING("Type 4 (short pulse)"), + (u8 *)DISP_STRING("Type 5 (short pulse)"), + (u8 *)DISP_STRING("Type 6 (short pulse)"), + (u8 *)DISP_STRING("Type 7 (long pulse)"), + (u8 *)DISP_STRING("Type 8 (short pulse)"), + (u8 *)DISP_STRING("Type 4 or Type 5 or Type 6 (short pulse)"), + (u8 *)DISP_STRING("Type 5 or Type 6 or Type 8 (short pulse)"), + (u8 *)DISP_STRING("Type 5 or Type 6 (short pulse)") +}; +#endif + +static void +p2pFuncParseBeaconVenderId(IN P_ADAPTER_T prAdapter, IN u8 *pucIE, + IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo, + IN u8 ucRoleIndex); + +static void p2pFuncProcessP2pProbeRspAction( + IN P_ADAPTER_T prAdapter, IN u8 *pucIEBuf, IN u8 ucElemIdType, + OUT u8 *ucBssIdx, OUT P_BSS_INFO_T *prP2pBssInfo, OUT u8 *fgIsWSCIE, + OUT u8 *fgIsP2PIE, OUT u8 *fgIsWFDIE); +static void p2pFuncGetSpecAttriAction(IN P_IE_P2P_T prP2pIE, IN u8 ucOuiType, + IN u8 ucAttriID, + OUT P_ATTRIBUTE_HDR_T *prTargetAttri); +/*----------------------------------------------------------------------------*/ +/*! + * @brief Function for requesting scan. There is an option to do ACTIVE or + * PASSIVE scan. + * + * @param eScanType - Specify the scan type of the scan request. It can be an + * ACTIVE/PASSIVE Scan. eChannelSet - Specify the preferred channel set. A FULL + * scan would request a legacy full channel normal scan.(usually ACTIVE). A + * P2P_SOCIAL scan would scan 1+6+11 channels.(usually ACTIVE) A SPECIFIC scan + * would only 1/6/11 channels scan. (Passive Listen/Specific Search) + * ucChannelNum - A specific channel number. (Only when channel is + * specified) eBand - A specific band. (Only when channel is specified) + * + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void p2pFuncRequestScan(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo) +{ + P_MSG_SCN_SCAN_REQ_V2 prScanReqV2 = (P_MSG_SCN_SCAN_REQ_V2)NULL; + +#ifdef CFG_SUPPORT_BEAM_PLUS + /*NFC Beam + Indication */ + P_P2P_FSM_INFO_T prP2pFsmInfo = (P_P2P_FSM_INFO_T)NULL; +#endif + + DEBUGFUNC("p2pFuncRequestScan()"); + + do { + ASSERT_BREAK((prAdapter != NULL) && (prScanReqInfo != NULL)); + + if (prScanReqInfo->eChannelSet == SCAN_CHANNEL_SPECIFIED) { + ASSERT_BREAK(prScanReqInfo->ucNumChannelList > 0); + DBGLOG(P2P, LOUD, "P2P Scan Request Channel:%d\n", + prScanReqInfo->arScanChannelList[0].ucChannelNum); + } + + prScanReqV2 = (P_MSG_SCN_SCAN_REQ_V2)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, + (sizeof(MSG_SCN_SCAN_REQ_V2) + + (sizeof(PARAM_SSID_T) * prScanReqInfo->ucSsidNum))); + if (!prScanReqV2) { + ASSERT(0); /* Can't trigger SCAN FSM */ + DBGLOG( + P2P, ERROR, + "p2pFuncRequestScan: Memory allocation fail, can not send SCAN " + "MSG to scan module\n"); + break; + } + + prScanReqV2->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_REQ_V2; + prScanReqV2->ucSeqNum = ++prScanReqInfo->ucSeqNumOfScnMsg; + prScanReqV2->ucBssIndex = ucBssIndex; + prScanReqV2->eScanType = prScanReqInfo->eScanType; + prScanReqV2->eScanChannel = prScanReqInfo->eChannelSet; + prScanReqV2->u2IELen = 0; + prScanReqV2->prSsid = (P_PARAM_SSID_T)((unsigned long)prScanReqV2 + + sizeof(MSG_SCN_SCAN_REQ_V2)); + + /* Copy IE for Probe Request. */ + kalMemCopy(prScanReqV2->aucIE, prScanReqInfo->aucIEBuf, + prScanReqInfo->u4BufLength); + prScanReqV2->u2IELen = (u16)prScanReqInfo->u4BufLength; + + prScanReqV2->u2ChannelDwellTime = prScanReqInfo->u2PassiveDewellTime; + prScanReqV2->u2TimeoutValue = 0; + prScanReqV2->u2ProbeDelay = 0; + + switch (prScanReqInfo->eChannelSet) { + case SCAN_CHANNEL_SPECIFIED: { + u32 u4Idx = 0; + P_RF_CHANNEL_INFO_T prDomainInfo = + (P_RF_CHANNEL_INFO_T)prScanReqInfo->arScanChannelList; + + if (prScanReqInfo->ucNumChannelList > + MAXIMUM_OPERATION_CHANNEL_LIST) { + prScanReqInfo->ucNumChannelList = + MAXIMUM_OPERATION_CHANNEL_LIST; + } + + for (u4Idx = 0; u4Idx < prScanReqInfo->ucNumChannelList; u4Idx++) { + prScanReqV2->arChnlInfoList[u4Idx].ucChannelNum = + prDomainInfo->ucChannelNum; + prScanReqV2->arChnlInfoList[u4Idx].eBand = prDomainInfo->eBand; + prDomainInfo++; + } + + prScanReqV2->ucChannelListNum = prScanReqInfo->ucNumChannelList; + } + + /* fallthrough */ + case SCAN_CHANNEL_FULL: + /* fallthrough */ + case SCAN_CHANNEL_2G4: + /* fallthrough */ + case SCAN_CHANNEL_P2P_SOCIAL: { + /* u8 aucP2pSsid[] = P2P_WILDCARD_SSID; */ + P_PARAM_SSID_T prParamSsid = (P_PARAM_SSID_T)NULL; + + prParamSsid = prScanReqV2->prSsid; + + for (prScanReqV2->ucSSIDNum = 0; + prScanReqV2->ucSSIDNum < prScanReqInfo->ucSsidNum; + prScanReqV2->ucSSIDNum++) { + COPY_SSID( + prParamSsid->aucSsid, prParamSsid->u4SsidLen, + prScanReqInfo->arSsidStruct[prScanReqV2->ucSSIDNum].aucSsid, + prScanReqInfo->arSsidStruct[prScanReqV2->ucSSIDNum] + .ucSsidLen); + + prParamSsid++; + } + + /* For compatible. (in FW?) need to check. */ + if (prScanReqV2->ucSSIDNum == 0) { + prScanReqV2->ucSSIDType = SCAN_REQ_SSID_P2P_WILDCARD; + } else { + prScanReqV2->ucSSIDType = SCAN_REQ_SSID_SPECIFIED; + } + } break; + + default: + /* Currently there is no other scan channel set. */ + ASSERT(false); + break; + } + + prScanReqInfo->fgIsScanRequest = true; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prScanReqV2, + MSG_SEND_METHOD_BUF); + } while (false); +} + +void p2pFuncCancelScan(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN P_P2P_SCAN_REQ_INFO_T prScanInfo) +{ + P_MSG_SCN_SCAN_CANCEL prScanCancelMsg = (P_MSG_SCN_SCAN_CANCEL)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prScanInfo != NULL)); + + if (!prScanInfo->fgIsScanRequest) { + break; + } + + if (prScanInfo->ucSeqNumOfScnMsg) { + /* There is a channel privilege on hand. */ + DBGLOG(P2P, TRACE, "P2P Cancel Scan\n"); + + prScanCancelMsg = (P_MSG_SCN_SCAN_CANCEL)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_CANCEL)); + if (!prScanCancelMsg) { + /* Buffer not enough, can not cancel scan + * request. */ + DBGLOG(P2P, TRACE, "Buffer not enough, can not cancel scan.\n"); + ASSERT(false); + break; + } + kalMemZero(prScanCancelMsg, sizeof(MSG_SCN_SCAN_CANCEL)); + + prScanCancelMsg->rMsgHdr.eMsgId = MID_P2P_SCN_SCAN_CANCEL; + prScanCancelMsg->ucBssIndex = ucBssIndex; + prScanCancelMsg->ucSeqNum = prScanInfo->ucSeqNumOfScnMsg++; + prScanCancelMsg->fgIsChannelExt = false; + prScanInfo->fgIsScanRequest = false; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prScanCancelMsg, + MSG_SEND_METHOD_BUF); + } + } while (false); +} + +void p2pFuncGCJoin(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_JOIN_INFO_T prP2pJoinInfo) +{ + P_MSG_JOIN_REQ_T prJoinReqMsg = (P_MSG_JOIN_REQ_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL) && + (prP2pJoinInfo != NULL)); + + prBssDesc = prP2pJoinInfo->prTargetBssDesc; + if ((prBssDesc) == NULL) { + DBGLOG(P2P, ERROR, "p2pFuncGCJoin: NO Target BSS Descriptor\n"); + ASSERT(false); + break; + } + + if (prBssDesc->ucSSIDLen) { + COPY_SSID(prP2pBssInfo->aucSSID, prP2pBssInfo->ucSSIDLen, + prBssDesc->aucSSID, prBssDesc->ucSSIDLen); + } + + /* 2 <1> We are goin to connect to this BSS */ + prBssDesc->fgIsConnecting = true; + + /* 2 <2> Setup corresponding STA_RECORD_T */ + prStaRec = bssCreateStaRecFromBssDesc( + prAdapter, + (prBssDesc->fgIsP2PPresent ? (STA_TYPE_P2P_GO) : + (STA_TYPE_LEGACY_AP)), + prP2pBssInfo->ucBssIndex, prBssDesc); + + if (prStaRec == NULL) { + DBGLOG(P2P, TRACE, "Create station record fail\n"); + ASSERT(false); + break; + } + + prP2pJoinInfo->prTargetStaRec = prStaRec; + prP2pJoinInfo->fgIsJoinComplete = false; + prP2pJoinInfo->u4BufLength = 0; + + /* 2 <2.1> Sync. to FW domain */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + if (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + prStaRec->fgIsReAssoc = false; + prP2pJoinInfo->ucAvailableAuthTypes = (u8)AUTH_TYPE_OPEN_SYSTEM; + prStaRec->ucTxAuthAssocRetryLimit = TX_AUTH_ASSOCI_RETRY_LIMIT; + } else { + DBGLOG(P2P, ERROR, "JOIN INIT: Join Request when connected.\n"); + ASSERT(false); + /* TODO: Shall we considering ROAMIN case for P2P + * Device?. */ + break; + } + + /* 2 <4> Use an appropriate Authentication Algorithm Number + * among the ucAvailableAuthTypes. */ + if (prP2pJoinInfo->ucAvailableAuthTypes & (u8)AUTH_TYPE_OPEN_SYSTEM) { + DBGLOG(P2P, TRACE, + "JOIN INIT: Try to do Authentication with AuthType == " + "OPEN_SYSTEM.\n"); + + prP2pJoinInfo->ucAvailableAuthTypes &= ~(u8)AUTH_TYPE_OPEN_SYSTEM; + + prStaRec->ucAuthAlgNum = (u8)AUTH_ALGORITHM_NUM_OPEN_SYSTEM; + } else { + DBGLOG(P2P, ERROR, "JOIN INIT: ucAvailableAuthTypes Error.\n"); + ASSERT(false); + break; + } + + /* 4 <5> Overwrite Connection Setting for eConnectionPolicy == + * ANY (Used by Assoc Req) */ + + /* 2 <5> Backup desired channel. */ + + /* 2 <6> Send a Msg to trigger SAA to start JOIN process. */ + prJoinReqMsg = (P_MSG_JOIN_REQ_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_JOIN_REQ_T)); + + if (!prJoinReqMsg) { + DBGLOG(P2P, TRACE, "Allocation Join Message Fail\n"); + ASSERT(false); + return; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prP2pJoinInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + /* TODO: Consider fragmentation info in station record. */ + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prJoinReqMsg, + MSG_SEND_METHOD_BUF); + } while (false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will update the contain of BSS_INFO_T for AIS network + * once the association was completed. + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] prAssocRspSwRfb Pointer to SW RFB of ASSOC RESP FRAME. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void p2pFuncUpdateBssInfoForJOIN(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, + IN P_STA_RECORD_T prStaRec, + IN P_BSS_INFO_T prP2pBssInfo, + IN P_SW_RFB_T prAssocRspSwRfb) +{ + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)NULL; + u16 u2IELength; + u8 *pucIE; + + DEBUGFUNC("p2pUpdateBssInfoForJOIN()"); + + do { + ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL) && + (prP2pBssInfo != NULL) && (prAssocRspSwRfb != NULL)); + + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)prAssocRspSwRfb->pvHeader; + + if (prBssDesc == NULL) { + /* Target BSS NULL. */ + DBGLOG(P2P, TRACE, "Target BSS NULL\n"); + break; + } + + DBGLOG(P2P, INFO, "Update P2P_BSS_INFO_T and apply settings to MAC\n"); + + /* 3 <1> Update BSS_INFO_T from AIS_FSM_INFO_T or User Settings + */ + /* 4 <1.1> Setup Operation Mode */ + ASSERT_BREAK(prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE); + + if (UNEQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAssocRspFrame->aucBSSID)) { + ASSERT(false); + } + /* 4 <1.2> Setup SSID */ + COPY_SSID(prP2pBssInfo->aucSSID, prP2pBssInfo->ucSSIDLen, + prBssDesc->aucSSID, prBssDesc->ucSSIDLen); + + /* 4 <1.3> Setup Channel, Band */ + prP2pBssInfo->ucPrimaryChannel = prBssDesc->ucChannelNum; + prP2pBssInfo->eBand = prBssDesc->eBand; + + /* 3 <2> Update BSS_INFO_T from STA_RECORD_T */ + /* 4 <2.1> Save current AP's STA_RECORD_T and current AID */ + prP2pBssInfo->prStaRecOfAP = prStaRec; + prP2pBssInfo->u2AssocId = prStaRec->u2AssocId; + + /* 4 <2.2> Setup Capability */ + prP2pBssInfo->u2CapInfo = prStaRec->u2CapInfo; /* Use AP's Cap + * Info as BSS + * Cap Info */ + + if (prP2pBssInfo->u2CapInfo & CAP_INFO_SHORT_PREAMBLE) { + prP2pBssInfo->fgIsShortPreambleAllowed = true; + } else { + prP2pBssInfo->fgIsShortPreambleAllowed = false; + } + + /* 4 <2.3> Setup PHY Attributes and Basic Rate Set/Operational + * Rate Set */ + prP2pBssInfo->ucPhyTypeSet = prStaRec->ucDesiredPhyTypeSet; + + prP2pBssInfo->ucNonHTBasicPhyType = prStaRec->ucNonHTBasicPhyType; + + prP2pBssInfo->u2OperationalRateSet = prStaRec->u2OperationalRateSet; + prP2pBssInfo->u2BSSBasicRateSet = prStaRec->u2BSSBasicRateSet; + + nicTxUpdateBssDefaultRate(prP2pBssInfo); + + /* 3 <3> Update BSS_INFO_T from SW_RFB_T (Association Resp + * Frame) */ + /* 4 <3.1> Setup BSSID */ + COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prAssocRspFrame->aucBSSID); + + u2IELength = (u16)((prAssocRspSwRfb->u2PacketLen - + prAssocRspSwRfb->u2HeaderLen) - + (OFFSET_OF(WLAN_ASSOC_RSP_FRAME_T, aucInfoElem[0]) - + WLAN_MAC_MGMT_HEADER_LEN)); + pucIE = prAssocRspFrame->aucInfoElem; + + /* 4 <3.2> Parse WMM and setup QBSS flag */ + /* Parse WMM related IEs and configure HW CRs accordingly */ + mqmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + prP2pBssInfo->fgIsQBSS = prStaRec->fgIsQoS; + + /* 3 <4> Update BSS_INFO_T from BSS_DESC_T */ + + prBssDesc->fgIsConnecting = false; + prBssDesc->fgIsConnected = true; + + /* 4 <4.1> Setup MIB for current BSS */ + prP2pBssInfo->u2BeaconInterval = prBssDesc->u2BeaconInterval; + /* NOTE: Defer ucDTIMPeriod updating to when beacon is received + * after connection */ + prP2pBssInfo->ucDTIMPeriod = 0; + prP2pBssInfo->u2ATIMWindow = 0; + + prP2pBssInfo->ucBeaconTimeoutCount = AIS_BEACON_TIMEOUT_COUNT_INFRA; + + /* 4 <4.2> Update HT information and set channel */ + /* Record HT related parameters in rStaRec and rBssInfo + * Note: it shall be called before nicUpdateBss() + */ + rlmProcessAssocRsp(prAdapter, prAssocRspSwRfb, pucIE, u2IELength); + + /* 4 <4.3> Sync with firmware for BSS-INFO */ + nicUpdateBss(prAdapter, prP2pBssInfo->ucBssIndex); + + /* 4 <4.4> *DEFER OPERATION* nicPmIndicateBssConnected() will be + * invoked */ + /* inside scanProcessBeaconAndProbeResp() after 1st beacon is + * received */ + } while (false); +} + +WLAN_STATUS +p2pFunMgmtFrameTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + u8 fgIsSuccess = false; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + if (rTxDoneStatus != TX_RESULT_SUCCESS) { + DBGLOG(P2P, TRACE, "Mgmt Frame TX Fail, Status:%d.\n", + rTxDoneStatus); + } else { + fgIsSuccess = true; + DBGLOG(P2P, TRACE, "Mgmt Frame TX Done.\n"); + } + + kalP2PIndicateMgmtTxStatus(prAdapter->prGlueInfo, prMsduInfo, + fgIsSuccess); + } while (false); + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS +p2pFuncTxMgmtFrame(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN P_MSDU_INFO_T prMgmtTxMsdu, IN u8 fgNonCckRate) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + /* P_MSDU_INFO_T prTxMsduInfo = (P_MSDU_INFO_T)NULL; */ + P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + u8 ucRetryLimit = 30; /* TX_DESC_TX_COUNT_NO_LIMIT; */ + u8 fgDrop = false; + P_BSS_INFO_T prBssInfo; + + do { + ASSERT_BREAK(prAdapter != NULL); + + /* Drop this frame if BSS inactive */ + if (!IS_NET_ACTIVE(prAdapter, ucBssIndex)) { + p2pDevFsmRunEventMgmtFrameTxDone(prAdapter, prMgmtTxMsdu, + TX_RESULT_DROPPED_IN_DRIVER); + cnmMgtPktFree(prAdapter, prMgmtTxMsdu); + fgDrop = true; + + break; + } + + prWlanHdr = + (P_WLAN_MAC_HEADER_T)((unsigned long)prMgmtTxMsdu->prPacket + + MAC_TX_RESERVED_FIELD); + prStaRec = + cnmGetStaRecByAddress(prAdapter, ucBssIndex, prWlanHdr->aucAddr1); + /* prMgmtTxMsdu->ucBssIndex = ucBssIndex; */ + + switch (prWlanHdr->u2FrameCtrl & MASK_FRAME_TYPE) { + case MAC_FRAME_PROBE_RSP: + DBGLOG(P2P, TRACE, "TX Probe Resposne Frame\n"); + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + if ((!nicTxIsMgmtResourceEnough(prAdapter)) || + (prBssInfo->fgIsNetAbsent)) { + DBGLOG(P2P, TRACE, + "Drop Tx probe response due to resource issue\n"); + fgDrop = true; + + break; + } + prMgmtTxMsdu->ucStaRecIndex = (prStaRec != NULL) ? + (prStaRec->ucIndex) : + (STA_REC_INDEX_NOT_FOUND); + /* Modifiy Lie time to 100 mS due to the STA only wait + * 30-50mS */ + /* and AP do not need send it after STA left */ + nicTxSetPktLifeTime(prMgmtTxMsdu, 100); + prMgmtTxMsdu = + p2pFuncProcessP2pProbeRsp(prAdapter, ucBssIndex, prMgmtTxMsdu); + ucRetryLimit = 6; + break; + + default: + prMgmtTxMsdu->ucBssIndex = ucBssIndex; + break; + } + + if (fgDrop) { + /* Drop this frame */ + p2pDevFsmRunEventMgmtFrameTxDone(prAdapter, prMgmtTxMsdu, + TX_RESULT_DROPPED_IN_DRIVER); + cnmMgtPktFree(prAdapter, prMgmtTxMsdu); + + break; + } + + TX_SET_MMPDU(prAdapter, prMgmtTxMsdu, prMgmtTxMsdu->ucBssIndex, + (prStaRec != NULL) ? (prStaRec->ucIndex) : + (STA_REC_INDEX_NOT_FOUND), + WLAN_MAC_MGMT_HEADER_LEN, prMgmtTxMsdu->u2FrameLength, + p2pDevFsmRunEventMgmtFrameTxDone, MSDU_RATE_MODE_AUTO); + + nicTxSetPktRetryLimit(prMgmtTxMsdu, ucRetryLimit); + + nicTxConfigPktControlFlag(prMgmtTxMsdu, MSDU_CONTROL_FLAG_FORCE_TX, + true); + + nicTxEnqueueMsdu(prAdapter, prMgmtTxMsdu); + } while (false); + + return rWlanStatus; +} + +void p2pFuncStopComplete(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL)); + + DBGLOG(P2P, TRACE, "p2pFuncStopComplete\n"); + + /* GO: It would stop Beacon TX. GC: Stop all BSS related PS + * function. */ + nicPmIndicateBssAbort(prAdapter, prP2pBssInfo->ucBssIndex); + /* Reset RLM related field of BSSINFO. */ + rlmBssAborted(prAdapter, prP2pBssInfo); + + UNSET_NET_ACTIVE(prAdapter, prP2pBssInfo->ucBssIndex); + nicDeactivateNetwork(prAdapter, prP2pBssInfo->ucBssIndex); + /* Release CNM channel */ + nicUpdateBss(prAdapter, prP2pBssInfo->ucBssIndex); + + /* Reset current OPMode */ + /* 20170628, remove reset opmode, otherwise we cannot free P2P + * beacon buffer */ + prP2pBssInfo->eCurrentOPMode = OP_MODE_INFRASTRUCTURE; + prP2pBssInfo->u4RsnSelectedAKMSuite = 0; + + /* Point StaRecOfAP to NULL when GC role stop Complete */ + prP2pBssInfo->prStaRecOfAP = NULL; + } while (false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will start a P2P Group Owner and send Beacon Frames. + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void p2pFuncStartGO(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, + IN P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo, + IN P_P2P_CHNL_REQ_INFO_T prP2pChnlReqInfo) +{ +#if (CFG_SUPPORT_DFS_MASTER == 1) + P_CMD_RDD_ON_OFF_CTRL_T prCmdRddOnOffCtrl; +#endif + +#ifdef CFG_SUPPORT_P2P_OPEN_SECURITY + u8 fgIsOpenP2P = true; +#else + u8 fgIsOpenP2P = false; +#endif + +#ifdef CFG_SUPPORT_P2P_GO_11b_RATE + u8 fgIs11bRate = true; +#else + u8 fgIs11bRate = false; +#endif + + do { + ASSERT_BREAK((prAdapter != NULL) && (prBssInfo != NULL)); + + if (prBssInfo->ucBssIndex >= MAX_BSS_INDEX) { + DBGLOG(P2P, ERROR, + "P2P BSS exceed the number of P2P interface number."); + ASSERT(false); + break; + } + + DBGLOG(P2P, TRACE, "p2pFuncStartGO:\n"); + +#if (CFG_SUPPORT_DFS_MASTER == 1) + prCmdRddOnOffCtrl = (P_CMD_RDD_ON_OFF_CTRL_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(CMD_RDD_ON_OFF_CTRL_T)); + + if (prCmdRddOnOffCtrl == NULL) { + DBGLOG(P2P, ERROR, "Allocate memory for prCmdRddOnOffCtrl failed."); + return; + } + kalMemZero(prCmdRddOnOffCtrl, sizeof(CMD_RDD_ON_OFF_CTRL_T)); + + prCmdRddOnOffCtrl->ucDfsCtrl = RDD_START_TXQ; + prCmdRddOnOffCtrl->ucRddIdx = + prAdapter->aprBssInfo[prBssInfo->ucBssIndex]->eDBDCBand; + + DBGLOG(P2P, INFO, "p2pFuncStartGO: Start TXQ - DFS ctrl: %.d\n", + prCmdRddOnOffCtrl->ucDfsCtrl); + + wlanSendSetQueryCmd(prAdapter, CMD_ID_RDD_ON_OFF_CTRL, true, false, + false, NULL, NULL, sizeof(*prCmdRddOnOffCtrl), + (u8 *)prCmdRddOnOffCtrl, NULL, 0); + + cnmMemFree(prAdapter, prCmdRddOnOffCtrl); +#endif + + /* Re-start AP mode. */ + p2pFuncSwitchOPMode(prAdapter, prBssInfo, prBssInfo->eIntendOPMode, + false); + + prBssInfo->eIntendOPMode = OP_MODE_NUM; + + /* 4 <1.1> Assign SSID */ + COPY_SSID(prBssInfo->aucSSID, prBssInfo->ucSSIDLen, + prP2pConnReqInfo->rSsidStruct.aucSsid, + prP2pConnReqInfo->rSsidStruct.ucSsidLen); + + DBGLOG(P2P, TRACE, "GO SSID:%s\n", prBssInfo->aucSSID); + + /* 4 <1.2> Clear current AP's STA_RECORD_T and current AID */ + prBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + prBssInfo->u2AssocId = 0; + + /* 4 <1.3> Setup Channel, Band and Phy Attributes */ + prBssInfo->ucPrimaryChannel = prP2pChnlReqInfo->ucReqChnlNum; + prBssInfo->eBand = prP2pChnlReqInfo->eBand; + prBssInfo->eBssSCO = prP2pChnlReqInfo->eChnlSco; + + DBGLOG(P2P, TRACE, "GO Channel:%d SCO:%d\n", + prBssInfo->ucPrimaryChannel, prBssInfo->eBssSCO); + + if (prBssInfo->eBand == BAND_5G) { + /* Depend on eBand */ + prBssInfo->ucPhyTypeSet = + (prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11AN); + prBssInfo->ucConfigAdHocAPMode = AP_MODE_11A; /* Depend + * on + * eCurrentOPMode + * and + * ucPhyTypeSet + */ + } else if ((prP2pConnReqInfo->eConnRequest == + P2P_CONNECTION_TYPE_PURE_AP) || + fgIs11bRate) { + /* Depend on eBand */ + prBssInfo->ucPhyTypeSet = + (prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11BGN); + /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; + } else { + ASSERT(prP2pConnReqInfo->eConnRequest == P2P_CONNECTION_TYPE_GO); + /* Depend on eBand */ + prBssInfo->ucPhyTypeSet = + (prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11GN); + /* Depend on eCurrentOPMode and ucPhyTypeSet */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_11G_P2P; + } + + /* Overwrite BSS PHY type set by Feature Options */ + bssDetermineApBssInfoPhyTypeSet(prAdapter, + (prP2pConnReqInfo->eConnRequest == + P2P_CONNECTION_TYPE_PURE_AP) ? + true : + false, + prBssInfo); + + prBssInfo->ucNonHTBasicPhyType = + (u8)rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode] + .ePhyTypeIndex; + prBssInfo->u2BSSBasicRateSet = + rNonHTApModeAttributes[prBssInfo->ucConfigAdHocAPMode] + .u2BSSBasicRateSet; + prBssInfo->u2OperationalRateSet = + rNonHTPhyAttributes[prBssInfo->ucNonHTBasicPhyType] + .u2SupportedRateSet; + + if ((prBssInfo->ucAllSupportedRatesLen == 0) || fgIs11bRate) { + rateGetDataRatesFromRateSet(prBssInfo->u2OperationalRateSet, + prBssInfo->u2BSSBasicRateSet, + prBssInfo->aucAllSupportedRates, + &prBssInfo->ucAllSupportedRatesLen); + } + /* 4 <1.5> Setup MIB for current BSS */ + prBssInfo->u2ATIMWindow = 0; + prBssInfo->ucBeaconTimeoutCount = 0; + + /* 3 <2> Update BSS_INFO_T common part */ +#if CFG_SUPPORT_AAA + prBssInfo->fgIsProtection = false; + /* Always enable protection at P2P GO But OOBE AP*/ + if ((prP2pConnReqInfo->eConnRequest == P2P_CONNECTION_TYPE_GO) && + (!fgIsOpenP2P)) { + prBssInfo->fgIsProtection = true; /* Always enable + * protection at P2P + * GO */ + } else { + if (!fgIsOpenP2P) { + ASSERT(prP2pConnReqInfo->eConnRequest == + P2P_CONNECTION_TYPE_PURE_AP); + } + if (kalP2PGetCipher(prAdapter->prGlueInfo, + (u8)prBssInfo->u4PrivateData)) { + prBssInfo->fgIsProtection = true; + } + } + + bssInitForAP(prAdapter, prBssInfo, true); + + nicQmUpdateWmmParms(prAdapter, prBssInfo->ucBssIndex); +#endif + + /* 3 <3> Set MAC HW */ + /* 4 <3.1> Setup channel and bandwidth */ + rlmBssInitForAPandIbss(prAdapter, prBssInfo); + + /* 4 <3.2> Reset HW TSF Update Mode and Beacon Mode */ + nicUpdateBss(prAdapter, prBssInfo->ucBssIndex); + + /* 4 <3.3> Update Beacon again for network phy type confirmed. + */ + bssUpdateBeaconContent(prAdapter, prBssInfo->ucBssIndex); + + /* 4 <3.4> Setup BSSID */ + nicPmIndicateBssCreated(prAdapter, prBssInfo->ucBssIndex); + } while (false); +} /* p2pFuncStartGO() */ + +void p2pFuncStopGO(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo) +{ + u32 u4ClientCount = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL)); + + DBGLOG(P2P, TRACE, "p2pFuncStopGO\n"); + + u4ClientCount = bssGetClientCount(prAdapter, prP2pBssInfo); + + if ((prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) && + (prP2pBssInfo->eIntendOPMode == OP_MODE_NUM)) { + /* AP is created, Beacon Updated. */ + p2pFuncDissolve(prAdapter, prP2pBssInfo, true, + REASON_CODE_DEAUTH_LEAVING_BSS, true); + prP2pBssInfo->eIntendOPMode = OP_MODE_P2P_DEVICE; + } + + /* Do not Deactivate Network if any Client existed, we'll + * deactive it after Deauth Tx done */ + if (u4ClientCount == 0) { + DBGLOG(P2P, INFO, "No client! Deactive GO immediately.\n"); + p2pChangeMediaState(prAdapter, prP2pBssInfo, + PARAM_MEDIA_STATE_DISCONNECTED); + p2pFuncStopComplete(prAdapter, prP2pBssInfo); + } + } while (false); +} + +WLAN_STATUS p2pFuncRoleToBssIdx(IN P_ADAPTER_T prAdapter, IN u8 ucRoleIdx, + OUT u8 *pucBssIdx) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBssIdx != NULL)); + + if (ucRoleIdx >= BSS_P2P_NUM) { + rWlanStatus = WLAN_STATUS_FAILURE; + break; + } + if (!prAdapter->rWifiVar.aprP2pRoleFsmInfo[ucRoleIdx]) { + DBGLOG(P2P, WARN, "%s, invalid aprP2pRoleFsmInfo, ignore\n", + __func__); + rWlanStatus = WLAN_STATUS_FAILURE; + } else { + *pucBssIdx = + prAdapter->rWifiVar.aprP2pRoleFsmInfo[ucRoleIdx]->ucBssIndex; + } + } while (false); + + return rWlanStatus; +} + +P_P2P_ROLE_FSM_INFO_T p2pFuncGetRoleByBssIdx(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex) +{ + s32 i = 0; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL)); + + for (i = 0; i < BSS_P2P_NUM; i++) { + if (!prAdapter->rWifiVar.aprP2pRoleFsmInfo[i]) { + continue; + } + + if (prAdapter->rWifiVar.aprP2pRoleFsmInfo[i]->ucBssIndex == + ucBssIndex) { + break; + } + } + if (i < BSS_P2P_NUM) { + prP2pRoleFsmInfo = prAdapter->rWifiVar.aprP2pRoleFsmInfo[i]; + } + } while (false); + + return prP2pRoleFsmInfo; +} + +/* ///////////////////////////////// MT6630 CODE END + * //////////////////////////////////////////////// */ +void p2pFuncSwitchOPMode(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, + IN ENUM_OP_MODE_T eOpMode, IN u8 fgSyncToFW) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL) && + (eOpMode < OP_MODE_NUM)); + + if (prP2pBssInfo->eCurrentOPMode != eOpMode) { + DBGLOG(P2P, TRACE, + "p2pFuncSwitchOPMode: Switch to from %d, to %d.\n", + prP2pBssInfo->eCurrentOPMode, eOpMode); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_ACCESS_POINT: + /* p2pFuncDissolve will be done in + * p2pFuncStopGO(). */ + /* p2pFuncDissolve(prAdapter, prP2pBssInfo, + * true, REASON_CODE_DEAUTH_LEAVING_BSS); */ + if (prP2pBssInfo->eIntendOPMode != OP_MODE_P2P_DEVICE) { + p2pFuncStopGO(prAdapter, prP2pBssInfo); + + SET_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex); + } + break; + + default: + break; + } + + prP2pBssInfo->eIntendOPMode = eOpMode; + + /* The state is in disconnecting and can not change any + * BSS status */ + if (IS_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex) && + IS_NET_ACTIVE(prAdapter, prP2pBssInfo->ucBssIndex)) { + DBGLOG(P2P, TRACE, "under deauth procedure, Quit.\n"); + break; + } + + prP2pBssInfo->eCurrentOPMode = eOpMode; + switch (eOpMode) { + case OP_MODE_INFRASTRUCTURE: + DBGLOG(P2P, TRACE, "p2pFuncSwitchOPMode: Switch to Client.\n"); + + /* fall through */ + case OP_MODE_ACCESS_POINT: + /* Change interface address. */ + if (eOpMode == OP_MODE_ACCESS_POINT) { + DBGLOG(P2P, TRACE, "p2pFuncSwitchOPMode: Switch to AP.\n"); + prP2pBssInfo->ucSSIDLen = 0; + } + +#if CFG_DUAL_P2PLIKE_INTERFACE + /*avoid ap1 Bss have diff A2 & A3, */ + /*ToDo : fix for P2P case*/ +#else + COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, + prAdapter->rWifiVar.aucInterfaceAddress); + COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, + prAdapter->rWifiVar.aucInterfaceAddress); +#endif + break; + + case OP_MODE_P2P_DEVICE: { + /* Change device address. */ + DBGLOG(P2P, TRACE, + "p2pFuncSwitchOPMode: Switch back to P2P Device.\n"); + + p2pChangeMediaState(prAdapter, prP2pBssInfo, + PARAM_MEDIA_STATE_DISCONNECTED); + + COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, + prAdapter->rWifiVar.aucDeviceAddress); + COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, + prAdapter->rWifiVar.aucDeviceAddress); + } break; + + default: + ASSERT(false); + break; + } + + if (1) { + P2P_DISCONNECT_INFO rP2PDisInfo; + + kalMemZero(&rP2PDisInfo, sizeof(P2P_DISCONNECT_INFO)); + rP2PDisInfo.ucRole = 2; + wlanSendSetQueryCmd(prAdapter, CMD_ID_P2P_ABORT, true, false, + false, NULL, NULL, + sizeof(P2P_DISCONNECT_INFO), + (u8 *)&rP2PDisInfo, NULL, 0); + } + + DBGLOG(P2P, TRACE, "The device address is changed to " MACSTR "\n", + MAC2STR(prP2pBssInfo->aucOwnMacAddr)); + DBGLOG(P2P, TRACE, "The BSSID is changed to " MACSTR "\n", + MAC2STR(prP2pBssInfo->aucBSSID)); + + /* Update BSS INFO to FW. */ + if ((fgSyncToFW) && (eOpMode != OP_MODE_ACCESS_POINT)) { + nicUpdateBss(prAdapter, prP2pBssInfo->ucBssIndex); + } + } + } while (false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is to inform CNM that channel privilege + * has been released + * + * \param[in] prAdapter Pointer of ADAPTER_T + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void p2pFuncReleaseCh(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + P_MSG_CH_ABORT_T prMsgChRelease = (P_MSG_CH_ABORT_T)NULL; + + DEBUGFUNC("p2pFuncReleaseCh()"); + + do { + ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL)); + + if (!prChnlReqInfo->fgIsChannelRequested) { + break; + } + DBGLOG(P2P, TRACE, "P2P Release Channel\n"); + prChnlReqInfo->fgIsChannelRequested = false; + + /* 1. return channel privilege to CNM immediately */ + prMsgChRelease = (P_MSG_CH_ABORT_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_CH_ABORT_T)); + if (!prMsgChRelease) { + ASSERT(0); /* Can't release Channel to CNM */ + break; + } + + prMsgChRelease->rMsgHdr.eMsgId = MID_MNY_CNM_CH_ABORT; + prMsgChRelease->ucBssIndex = ucBssIdx; + prMsgChRelease->ucTokenID = prChnlReqInfo->ucSeqNumOfChReq++; +#if CFG_SUPPORT_DBDC + prMsgChRelease->eDBDCBand = ENUM_BAND_AUTO; + + DBGLOG(P2P, INFO, "p2pFuncReleaseCh: P2P abort channel on band %u.\n", + prMsgChRelease->eDBDCBand); +#endif + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsgChRelease, + MSG_SEND_METHOD_BUF); + } while (false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process of CHANNEL_REQ_JOIN Initial. Enter CHANNEL_REQ_JOIN State. + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void p2pFuncAcquireCh(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + P_MSG_CH_REQ_T prMsgChReq = (P_MSG_CH_REQ_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL)); + + p2pFuncReleaseCh(prAdapter, ucBssIdx, prChnlReqInfo); + + /* send message to CNM for acquiring channel */ + prMsgChReq = (P_MSG_CH_REQ_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_CH_REQ_T)); + + if (!prMsgChReq) { + ASSERT(0); /* Can't indicate CNM for channel acquiring + */ + break; + } + + prMsgChReq->rMsgHdr.eMsgId = MID_MNY_CNM_CH_REQ; + prMsgChReq->ucBssIndex = ucBssIdx; + prMsgChReq->ucTokenID = ++prChnlReqInfo->ucSeqNumOfChReq; + prMsgChReq->eReqType = prChnlReqInfo->eChnlReqType; + prMsgChReq->u4MaxInterval = prChnlReqInfo->u4MaxInterval; + prMsgChReq->ucPrimaryChannel = prChnlReqInfo->ucReqChnlNum; + prMsgChReq->eRfSco = prChnlReqInfo->eChnlSco; + prMsgChReq->eRfBand = prChnlReqInfo->eBand; + prMsgChReq->eRfChannelWidth = prChnlReqInfo->eChannelWidth; + prMsgChReq->ucRfCenterFreqSeg1 = prChnlReqInfo->ucCenterFreqS1; + prMsgChReq->ucRfCenterFreqSeg2 = prChnlReqInfo->ucCenterFreqS2; +#if CFG_SUPPORT_DBDC + prMsgChReq->eDBDCBand = ENUM_BAND_AUTO; + + DBGLOG( + P2P, INFO, + "p2pFuncAcquireCh: P2P Request channel on band %u. RfBand:%d. CH:%d\n", + prMsgChReq->eDBDCBand, prChnlReqInfo->eBand, + prChnlReqInfo->ucReqChnlNum); +#endif + /* Channel request join BSSID. */ + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsgChReq, + MSG_SEND_METHOD_BUF); + + prChnlReqInfo->fgIsChannelRequested = true; + } while (false); +} + +#if (CFG_SUPPORT_DFS_MASTER == 1) +void p2pFuncStartRdd(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx) +{ + P_CMD_RDD_ON_OFF_CTRL_T prCmdRddOnOffCtrl; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + u8 ucReqChnlNum; + + DEBUGFUNC("p2pFuncStartRdd()"); + + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO( + prAdapter, prAdapter->aprBssInfo[ucBssIdx]->u4PrivateData); + + ucReqChnlNum = prP2pRoleFsmInfo->rChnlReqInfo.ucReqChnlNum; + + prCmdRddOnOffCtrl = (P_CMD_RDD_ON_OFF_CTRL_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(CMD_RDD_ON_OFF_CTRL_T)); + + if (!prCmdRddOnOffCtrl) { + DBGLOG(P2P, ERROR, "cnmMemAlloc for prCmdRddOnOffCtrl failed!\n"); + return; + } + kalMemZero(prCmdRddOnOffCtrl, sizeof(CMD_RDD_ON_OFF_CTRL_T)); + + prCmdRddOnOffCtrl->ucDfsCtrl = RDD_START; + + prCmdRddOnOffCtrl->ucRddIdx = prAdapter->aprBssInfo[ucBssIdx]->eDBDCBand; + + if (rlmDomainGetDfsRegion() == NL80211_DFS_JP) { + if (ucReqChnlNum >= 52 && ucReqChnlNum <= 64) { + prCmdRddOnOffCtrl->ucRegDomain = REG_JP_53; + } else if (ucReqChnlNum >= 100 && ucReqChnlNum <= 140) { + prCmdRddOnOffCtrl->ucRegDomain = REG_JP_56; + } + } else { + prCmdRddOnOffCtrl->ucRegDomain = REG_DEFAULT; + } + + if (prCmdRddOnOffCtrl->ucRddIdx) { + prCmdRddOnOffCtrl->ucRddInSel = RDD_IN_SEL_1; + } else { + prCmdRddOnOffCtrl->ucRddInSel = RDD_IN_SEL_0; + } + + DBGLOG( + P2P, INFO, + "p2pFuncStartRdd: Start Radar detection - DFS ctrl: %d, RDD index: %d\n", + prCmdRddOnOffCtrl->ucDfsCtrl, prCmdRddOnOffCtrl->ucRddIdx); + + wlanSendSetQueryCmd(prAdapter, CMD_ID_RDD_ON_OFF_CTRL, true, false, false, + NULL, NULL, sizeof(*prCmdRddOnOffCtrl), + (u8 *)prCmdRddOnOffCtrl, NULL, 0); + + cnmMemFree(prAdapter, prCmdRddOnOffCtrl); +} + +void p2pFuncStopRdd(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx) +{ + P_CMD_RDD_ON_OFF_CTRL_T prCmdRddOnOffCtrl; + + DEBUGFUNC("p2pFuncStopRdd()"); + + prCmdRddOnOffCtrl = (P_CMD_RDD_ON_OFF_CTRL_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(CMD_RDD_ON_OFF_CTRL_T)); + + if (!prCmdRddOnOffCtrl) { + DBGLOG(P2P, ERROR, "cnmMemAlloc for prCmdRddOnOffCtrl failed!\n"); + return; + } + kalMemZero(prCmdRddOnOffCtrl, sizeof(CMD_RDD_ON_OFF_CTRL_T)); + + prCmdRddOnOffCtrl->ucDfsCtrl = RDD_STOP; + + prCmdRddOnOffCtrl->ucRddIdx = prAdapter->aprBssInfo[ucBssIdx]->eDBDCBand; + + if (prCmdRddOnOffCtrl->ucRddIdx) { + prCmdRddOnOffCtrl->ucRddInSel = RDD_IN_SEL_1; + } else { + prCmdRddOnOffCtrl->ucRddInSel = RDD_IN_SEL_0; + } + + DBGLOG( + P2P, INFO, + "p2pFuncStopRdd: Stop Radar detection - DFS ctrl: %d, RDD index: %d\n", + prCmdRddOnOffCtrl->ucDfsCtrl, prCmdRddOnOffCtrl->ucRddIdx); + + wlanSendSetQueryCmd(prAdapter, CMD_ID_RDD_ON_OFF_CTRL, true, false, false, + NULL, NULL, sizeof(*prCmdRddOnOffCtrl), + (u8 *)prCmdRddOnOffCtrl, NULL, 0); + + cnmMemFree(prAdapter, prCmdRddOnOffCtrl); +} + +void p2pFuncDfsSwitchCh(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, + IN P2P_CHNL_REQ_INFO_T rP2pChnlReqInfo) +{ + P_GLUE_INFO_T prGlueInfo; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_CMD_RDD_ON_OFF_CTRL_T prCmdRddOnOffCtrl; + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + + DEBUGFUNC("p2pFuncDfsSwitchCh()"); + + if (!prBssInfo) { + DBGLOG(P2P, ERROR, "prBssInfo shouldn't be NULL!\n"); + return; + } + + /* Setup Channel, Band */ + prBssInfo->ucPrimaryChannel = rP2pChnlReqInfo.ucReqChnlNum; + prBssInfo->eBand = rP2pChnlReqInfo.eBand; + prBssInfo->eBssSCO = rP2pChnlReqInfo.eChnlSco; + + /* Setup channel and bandwidth */ + rlmBssInitForAPandIbss(prAdapter, prBssInfo); + + /* Update Beacon again for network phy type confirmed. */ + bssUpdateBeaconContent(prAdapter, prBssInfo->ucBssIndex); + + /* Reset HW TSF Update Mode and Beacon Mode */ + nicUpdateBss(prAdapter, prBssInfo->ucBssIndex); + + prCmdRddOnOffCtrl = (P_CMD_RDD_ON_OFF_CTRL_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(CMD_RDD_ON_OFF_CTRL_T)); + + if (!prCmdRddOnOffCtrl) { + DBGLOG(P2P, ERROR, "cnmMemAlloc for prCmdRddOnOffCtrl failed!\n"); + return; + } + kalMemZero(prCmdRddOnOffCtrl, sizeof(CMD_RDD_ON_OFF_CTRL_T)); + + prCmdRddOnOffCtrl->ucDfsCtrl = RDD_START_TXQ; + prCmdRddOnOffCtrl->ucRddIdx = + prAdapter->aprBssInfo[prBssInfo->ucBssIndex]->eDBDCBand; + + DBGLOG(P2P, STATE, "p2pFuncDfsSwitchCh: Start TXQ - DFS ctrl: %.d\n", + prCmdRddOnOffCtrl->ucDfsCtrl); + + wlanSendSetQueryCmd(prAdapter, CMD_ID_RDD_ON_OFF_CTRL, true, false, false, + NULL, NULL, sizeof(*prCmdRddOnOffCtrl), + (u8 *)prCmdRddOnOffCtrl, NULL, 0); + + cnmMemFree(prAdapter, prCmdRddOnOffCtrl); + + prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prBssInfo->u4PrivateData); + + prGlueInfo = prAdapter->prGlueInfo; + +#if CFG_SUPPORT_DBDC_TC6 + prGlueP2pInfo = prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]; + p2pFuncModifyChandef(prAdapter, prGlueP2pInfo, prBssInfo); + WARN_ON(!cfg80211_chandef_valid(prGlueP2pInfo->chandef)); + + DBGLOG(P2P, INFO, "role(%d) b=%d f=%d w=%d s1=%d s2=%d\n", + prP2pRoleFsmInfo->ucRoleIndex, prGlueP2pInfo->chandef->chan->band, + prGlueP2pInfo->chandef->chan->center_freq, + prGlueP2pInfo->chandef->width, prGlueP2pInfo->chandef->center_freq1, + prGlueP2pInfo->chandef->center_freq2); +#endif + + DBGLOG(P2P, STATE, "p2pFuncDfsSwitchCh: Update to OS\n"); + /* NL80211 event should send to p2p group netdevice. + * Otherwise wpa_supplicant wouldn't perform beacon update. + * Hostapd case: prDevHandler same with aprRoleHandler + * P2P GO case: p2p0=>prDevHandler, p2p-xxx-x=> aprRoleHandler + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 2)) + cfg80211_ch_switch_notify( + prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->aprRoleHandler, + prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->chandef); +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) + cfg80211_ch_switch_notify( + prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->prDevHandler, + prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->chandef, 0); +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(6, 9, 0)) + cfg80211_ch_switch_notify( + prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->aprRoleHandler, + prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->chandef, 0, 0); +#else + cfg80211_ch_switch_notify( + prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->aprRoleHandler, + prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->chandef, 0); +#endif + DBGLOG(P2P, STATE, "p2pFuncDfsSwitchCh: Update to OS Done\n"); + +#if !CFG_SUPPORT_DBDC_TC6 /* Fix sap will stop to disconnect sta caused by \ + * incorrect memory free */ + if (prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->chandef->chan) { + cnmMemFree(prGlueInfo->prAdapter, prGlueP2pInfo->chandef->chan); + } + + prGlueP2pInfo->chandef->chan = NULL; + + if (prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->chandef) { + cnmMemFree( + prGlueInfo->prAdapter, + prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->chandef); + } +#endif + +#if CFG_SUPPORT_DBDC_TC6 + if (prAdapter->rWifiVar.fgDelayInidicateDISCON) { + DBGLOG(P2P, STATE, + "p2pFuncDfsSwitchCh Done, report AIS disconnect event\n"); + cfg80211_disconnected(prAdapter->prGlueInfo->prDevHandler, 0, NULL, 0, + true, GFP_KERNEL); + prAdapter->rWifiVar.fgDelayInidicateDISCON = false; + } +#endif + prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]->chandef = NULL; +} + +u8 p2pFuncCheckWeatherRadarBand(IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + u8 ucReqChnlNum; + u8 ucCenterFreqS1; + ENUM_CHANNEL_WIDTH_T eChannelWidth; + ENUM_CHNL_EXT_T eChnlSco; + + ucReqChnlNum = prChnlReqInfo->ucReqChnlNum; + ucCenterFreqS1 = prChnlReqInfo->ucCenterFreqS1; + eChannelWidth = prChnlReqInfo->eChannelWidth; + eChnlSco = prChnlReqInfo->eChnlSco; + + if (rlmDomainGetDfsRegion() == NL80211_DFS_ETSI) { + if (eChannelWidth == VHT_OP_CHANNEL_WIDTH_80) { + if (ucCenterFreqS1 >= 120 && ucCenterFreqS1 <= 128) { + return true; + } + } else { + if ((ucReqChnlNum >= 120 && ucReqChnlNum <= 128)) { + return true; + } else if (ucReqChnlNum == 116 && + eChnlSco == CHNL_EXT_SCA) { /* ch116, 120 BW40 */ + return true; + } + } + } + + return false; +} + +s32 p2pFuncSetDriverCacTime(IN u32 u4CacTime) +{ + WLAN_STATUS i4Status = WLAN_STATUS_SUCCESS; + + g_u4DriverCacTime = u4CacTime; + + DBGLOG(P2P, INFO, "p2pFuncSetDriverCacTime: g_u4ManualCacTime = %dsec\n", + g_u4DriverCacTime); + + return i4Status; +} + +void p2pFuncEnableManualCac(void) +{ + g_fgManualCac = true; +} + +u32 p2pFuncGetDriverCacTime(void) +{ + return g_u4DriverCacTime; +} + +u8 p2pFuncIsManualCac(void) +{ + return g_fgManualCac; +} + +void p2pFuncRadarInfoInit(void) +{ + kalMemZero(&g_rP2pRadarInfo, sizeof(g_rP2pRadarInfo)); +} + +void p2pFuncShowRadarInfo(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx) +{ + u8 ucCnt = 0; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + u8 ucReqChnlNum; + + if (g_rP2pRadarInfo.ucRadarReportMode == 1) { + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO( + prAdapter, prAdapter->aprBssInfo[ucBssIdx]->u4PrivateData); + + ucReqChnlNum = prP2pRoleFsmInfo->rChnlReqInfo.ucReqChnlNum; + + DBGLOG(P2P, INFO, "-----Radar Detected Event-----\n"); + DBGLOG(P2P, INFO, "Radar detected in DBDC band%d\n", + g_rP2pRadarInfo.ucRddIdx); + + switch (rlmDomainGetDfsRegion()) { + case NL80211_DFS_FCC: + DBGLOG(P2P, INFO, "Regulation domain: FCC\n"); + break; + + case NL80211_DFS_ETSI: + DBGLOG(P2P, INFO, "Regulation domain: ETSI\n"); + break; + + case NL80211_DFS_JP: + DBGLOG(P2P, INFO, "Regulation domain: JP\n"); + + if (ucReqChnlNum >= 52 && ucReqChnlNum <= 64) { + DBGLOG(P2P, INFO, "Radar type: W53 - %s\n", + p2pFuncJpW53RadarType()); + } else if (ucReqChnlNum >= 100 && ucReqChnlNum <= 140) { + DBGLOG(P2P, INFO, "Radar type: W56 - %s\n", + p2pFuncJpW56RadarType()); + } + break; + + default: + break; + } + + DBGLOG(P2P, INFO, "Radar Content:\n"); + + DBGLOG(P2P, INFO, "start time pulse width PRI\n"); + + if (g_rP2pRadarInfo.ucPeriodicDetected) { + DBGLOG(P2P, INFO, "%-10d %-11d -\n", + g_rP2pRadarInfo.arPpbContent[ucCnt].u4PeriodicStartTime, + g_rP2pRadarInfo.arPpbContent[ucCnt].u2PeriodicPulseWidth); + + for (ucCnt = 1; ucCnt < g_rP2pRadarInfo.ucPPBNum; ucCnt++) { + DBGLOG( + P2P, INFO, "%-10d %-11d %d\n", + g_rP2pRadarInfo.arPpbContent[ucCnt].u4PeriodicStartTime, + g_rP2pRadarInfo.arPpbContent[ucCnt].u2PeriodicPulseWidth, + (g_rP2pRadarInfo.arPpbContent[ucCnt].u4PeriodicStartTime - + g_rP2pRadarInfo.arPpbContent[ucCnt - 1] + .u4PeriodicStartTime) * + 2 / 5); + } + } else if (g_rP2pRadarInfo.ucLongDetected) { + DBGLOG(P2P, INFO, "%-10d %-11d -\n", + g_rP2pRadarInfo.arLpbContent[ucCnt].u4LongStartTime, + g_rP2pRadarInfo.arLpbContent[ucCnt].u2LongPulseWidth); + + for (ucCnt = 1; ucCnt < g_rP2pRadarInfo.ucLPBNum; ucCnt++) { + DBGLOG( + P2P, INFO, "%-10d %-11d %d\n", + g_rP2pRadarInfo.arLpbContent[ucCnt].u4LongStartTime, + g_rP2pRadarInfo.arLpbContent[ucCnt].u2LongPulseWidth, + (g_rP2pRadarInfo.arLpbContent[ucCnt].u4LongStartTime - + g_rP2pRadarInfo.arLpbContent[ucCnt - 1].u4LongStartTime) * + 2 / 5); + } + } + } +} + +void p2pFuncGetRadarInfo(IN struct P2P_RADAR_INFO *prP2pRadarInfo) +{ + kalMemCopy(prP2pRadarInfo, &g_rP2pRadarInfo, sizeof(*prP2pRadarInfo)); +} + +u8 *p2pFuncJpW53RadarType(void) +{ + u32 u4Type1Diff; + u32 u4Type2Diff; + + if (g_rP2pRadarInfo.u4PRI1stUs >= 1428) { + u4Type1Diff = g_rP2pRadarInfo.u4PRI1stUs - 1428; + } else { + u4Type1Diff = 1428 - g_rP2pRadarInfo.u4PRI1stUs; + } + + if (g_rP2pRadarInfo.u4PRI1stUs >= 3846) { + u4Type2Diff = g_rP2pRadarInfo.u4PRI1stUs - 3846; + } else { + u4Type2Diff = 3846 - g_rP2pRadarInfo.u4PRI1stUs; + } + + if (u4Type1Diff < u4Type2Diff) { + return apucW53RadarType[1]; + } else { + return apucW53RadarType[2]; + } +} + +u8 *p2pFuncJpW56RadarType(void) +{ + u32 u4Type1Diff; + u32 u4Type2Diff; + + if (g_rP2pRadarInfo.ucLongDetected) { + return apucW56RadarType[7]; + } + + if (g_rP2pRadarInfo.u4PRI1stUs >= 3980 && + g_rP2pRadarInfo.u4PRI1stUs <= 4020) { + return apucW56RadarType[3]; + } + + if (g_rP2pRadarInfo.u4PRI1stUs >= 1368 && + g_rP2pRadarInfo.u4PRI1stUs <= 1448) { + if (g_rP2pRadarInfo.u4PRI1stUs >= 1388) { + u4Type1Diff = g_rP2pRadarInfo.u4PRI1stUs - 1388; + } else { + u4Type1Diff = 1388 - g_rP2pRadarInfo.u4PRI1stUs; + } + + if (g_rP2pRadarInfo.u4PRI1stUs >= 1428) { + u4Type2Diff = g_rP2pRadarInfo.u4PRI1stUs - 1428; + } else { + u4Type2Diff = 1428 - g_rP2pRadarInfo.u4PRI1stUs; + } + + if (u4Type1Diff < u4Type2Diff) { + return apucW56RadarType[1]; + } else { + return apucW56RadarType[2]; + } + } + + if (g_rP2pRadarInfo.u4PRI1stUs >= 130 && g_rP2pRadarInfo.u4PRI1stUs < 200) { + return apucW56RadarType[4]; + } + + if (g_rP2pRadarInfo.u4PRI1stUs >= 200 && + g_rP2pRadarInfo.u4PRI1stUs <= 520) { + if (g_rP2pRadarInfo.u4PRI1stUs <= 230) { + return apucW56RadarType[9]; + } + + if (g_rP2pRadarInfo.u4PRI1stUs >= 323 && + g_rP2pRadarInfo.u4PRI1stUs <= 343) { + return apucW56RadarType[10]; + } + + return apucW56RadarType[11]; + } + + return apucW56RadarType[0]; +} + +void p2pFuncSetRadarDetectMode(IN u8 ucRadarDetectMode) +{ + g_ucRadarDetectMode = ucRadarDetectMode; + + DBGLOG(P2P, INFO, "p2pFuncSetRadarDetectMode: g_ucRadarDetectMode: %d\n", + g_ucRadarDetectMode); +} + +u8 p2pFuncGetRadarDetectMode(void) +{ + return g_ucRadarDetectMode; +} + +void p2pFuncSetDfsState(IN u8 ucDfsState) +{ + DBGLOG(P2P, INFO, "[DFS_STATE] TRANSITION: [%s] -> [%s]\n", + apucDfsState[g_ucDfsState], apucDfsState[ucDfsState]); + + g_ucDfsState = ucDfsState; +} + +u8 p2pFuncGetDfsState(void) +{ + return g_ucDfsState; +} + +u8 *p2pFuncShowDfsState(void) +{ + return apucDfsState[g_ucDfsState]; +} + +void p2pFuncRecordCacStartBootTime(void) +{ + g_u4CacStartBootTime = kalGetBootTime(); +} + +u32 p2pFuncGetCacRemainingTime(void) +{ + u32 u4CurrentBootTime; + u32 u4CacRemainingTime; + + u4CurrentBootTime = kalGetBootTime(); + + u4CacRemainingTime = g_u4DriverCacTime - + (u4CurrentBootTime - g_u4CacStartBootTime) / 1000000; + + return u4CacRemainingTime; +} +#endif + +WLAN_STATUS +p2pFuncBeaconUpdate(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, + IN P_P2P_BEACON_UPDATE_INFO_T prBcnUpdateInfo, + IN u8 *pucNewBcnHdr, IN u32 u4NewHdrLen, + IN u8 *pucNewBcnBody, IN u32 u4NewBodyLen) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_WLAN_BEACON_FRAME_T prBcnFrame = (P_WLAN_BEACON_FRAME_T)NULL; + P_MSDU_INFO_T prBcnMsduInfo = (P_MSDU_INFO_T)NULL; + u8 *pucIEBuf = (u8 *)NULL; + u8 aucIEBuf[MAX_IE_LENGTH]; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL) && + (prBcnUpdateInfo != NULL)); + + prBcnMsduInfo = prP2pBssInfo->prBeacon; + +#if DBG + if (prBcnUpdateInfo->pucBcnHdr != NULL) { + ASSERT((u32)prBcnUpdateInfo->pucBcnHdr == + ((u32)prBcnMsduInfo->prPacket + MAC_TX_RESERVED_FIELD)); + } + + if (prBcnUpdateInfo->pucBcnBody != NULL) { + ASSERT((u32)prBcnUpdateInfo->pucBcnBody == + ((u32)prBcnUpdateInfo->pucBcnHdr + + (u32)prBcnUpdateInfo->u4BcnHdrLen)); + } +#endif + prBcnFrame = + (P_WLAN_BEACON_FRAME_T)((unsigned long)prBcnMsduInfo->prPacket + + MAC_TX_RESERVED_FIELD); + + if (!pucNewBcnBody) { + /* Old body. */ + pucNewBcnBody = prBcnUpdateInfo->pucBcnBody; + ASSERT(u4NewBodyLen == 0); + u4NewBodyLen = prBcnUpdateInfo->u4BcnBodyLen; + } else { + prBcnUpdateInfo->u4BcnBodyLen = u4NewBodyLen; + } + + /* Temp buffer body part. */ + kalMemCopy(aucIEBuf, pucNewBcnBody, u4NewBodyLen); + + if (pucNewBcnHdr) { + kalMemCopy(prBcnFrame, pucNewBcnHdr, u4NewHdrLen); + prBcnUpdateInfo->pucBcnHdr = (u8 *)prBcnFrame; + prBcnUpdateInfo->u4BcnHdrLen = u4NewHdrLen; + } + + pucIEBuf = (u8 *)((unsigned long)prBcnUpdateInfo->pucBcnHdr + + (unsigned long)prBcnUpdateInfo->u4BcnHdrLen); + kalMemCopy(pucIEBuf, aucIEBuf, u4NewBodyLen); + prBcnUpdateInfo->pucBcnBody = pucIEBuf; + + /* Frame Length */ + prBcnMsduInfo->u2FrameLength = + (u16)(prBcnUpdateInfo->u4BcnHdrLen + prBcnUpdateInfo->u4BcnBodyLen); + + prBcnMsduInfo->ucPacketType = TX_PACKET_TYPE_MGMT; + prBcnMsduInfo->fgIs802_11 = true; + prBcnMsduInfo->ucBssIndex = prP2pBssInfo->ucBssIndex; + + /* Update BSS INFO related information. */ + COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, prBcnFrame->aucSrcAddr); + COPY_MAC_ADDR(prP2pBssInfo->aucBSSID, prBcnFrame->aucBSSID); + prP2pBssInfo->u2CapInfo = prBcnFrame->u2CapInfo; + + p2pFuncParseBeaconContent( + prAdapter, prP2pBssInfo, (u8 *)prBcnFrame->aucInfoElem, + (prBcnMsduInfo->u2FrameLength - + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem))); + } while (false); + + return rWlanStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is to update extra IEs (ex: WPS) for assoc resp. + * Caller should sanity check the params. + * + * \param[in] prAdapter Pointer of ADAPTER_T + * \param[in] prP2pBssInfo Pointer to BSS_INFO_T structure + * \param[in] AssocRespIE Pointer to extra IEs for assoc resp + * \param[in] u4AssocRespLen Length of extra IEs for assoc resp + * + * \return WLAN_STATUS + */ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS +p2pFuncAssocRespUpdate(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, + IN u8 *AssocRespIE, IN u32 u4AssocRespLen) +{ + u8 ucOuiType = 0; + u16 u2SubTypeVersion = 0; + + if (!rsnParseCheckForWFAInfoElem(prAdapter, AssocRespIE, &ucOuiType, + &u2SubTypeVersion)) { + return WLAN_STATUS_FAILURE; + } + + if (ucOuiType == VENDOR_OUI_TYPE_WPS) { + kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 3, (u8 *)AssocRespIE, + IE_SIZE(AssocRespIE), + (u8)(prP2pBssInfo->u4PrivateData)); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to dissolve from group or one group. (Would + * not change P2P FSM.) + * 1. GC: Disconnect from AP. (Send Deauth) + * 2. GO: Disconnect all STA + * + * @param[in] prAdapter Pointer to the adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void p2pFuncDissolve(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, + IN u8 fgSendDeauth, IN u16 u2ReasonCode, + IN u8 fgIsLocallyGenerated) +{ + P_STA_RECORD_T prCurrStaRec, prStaRecNext; + P_LINK_T prClientList; + + DEBUGFUNC("p2pFuncDissolve()"); + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL)); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_INFRASTRUCTURE: + /* Reset station record status. */ + if (prP2pBssInfo->prStaRecOfAP) { + kalP2PGCIndicateConnectionStatus( + prAdapter->prGlueInfo, (u8)prP2pBssInfo->u4PrivateData, + NULL, NULL, 0, REASON_CODE_DEAUTH_LEAVING_BSS, + fgIsLocallyGenerated ? + WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY : + WLAN_STATUS_MEDIA_DISCONNECT); + + /* 2012/02/14 frog: After formation before join + * group, prStaRecOfAP is NULL. */ + p2pFuncDisconnect(prAdapter, prP2pBssInfo, + prP2pBssInfo->prStaRecOfAP, fgSendDeauth, + u2ReasonCode, fgIsLocallyGenerated); + } + + /* Fix possible KE when RX Beacon & call + * nicPmIndicateBssConnected(). hit prStaRecOfAP == + * NULL. + */ + p2pChangeMediaState(prAdapter, prP2pBssInfo, + PARAM_MEDIA_STATE_DISCONNECTED); + + prP2pBssInfo->prStaRecOfAP = NULL; + + break; + + case OP_MODE_ACCESS_POINT: + /* Under AP mode, we would net send deauthentication + * frame to each STA. We only stop the Beacon & let all + * stations timeout. + */ + /* Send deauth. */ + authSendDeauthFrame(prAdapter, prP2pBssInfo, NULL, (P_SW_RFB_T)NULL, + u2ReasonCode, (PFN_TX_DONE_HANDLER)NULL); + + prClientList = &prP2pBssInfo->rStaRecOfClientList; + + /* This case may let LINK_FOR_EACH_ENTRY_SAFE crash */ + if (prClientList == NULL) { + break; + } + + LINK_FOR_EACH_ENTRY_SAFE(prCurrStaRec, prStaRecNext, prClientList, + rLinkEntry, STA_RECORD_T){ + ASSERT(prCurrStaRec); + p2pFuncDisconnect(prAdapter, prP2pBssInfo, prCurrStaRec, true, + u2ReasonCode, fgIsLocallyGenerated); + } + break; + + default: + return; /* 20110420 -- alreay in Device Mode. */ + } + + /* Make the deauth frame send to FW ASAP. */ + wlanProcessCommandQueue(prAdapter, &prAdapter->prGlueInfo->rCmdQueue); + } while (false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to dissolve from group or one group. (Would + * not change P2P FSM.) + * 1. GC: Disconnect from AP. (Send Deauth) + * 2. GO: Disconnect all STA + * + * @param[in] prAdapter Pointer to the adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void p2pFuncDisconnect(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, + IN P_STA_RECORD_T prStaRec, IN u8 fgSendDeauth, + IN u16 u2ReasonCode, IN u8 fgIsLocallyGenerated) +{ + ENUM_PARAM_MEDIA_STATE_T eOriMediaStatus; + + DBGLOG(P2P, INFO, "p2pFuncDisconnect()"); + + do { + ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL) && + (prP2pBssInfo != NULL)); + + ASSERT_BREAK(prP2pBssInfo->eNetworkType == NETWORK_TYPE_P2P); + + ASSERT_BREAK(prP2pBssInfo->ucBssIndex < P2P_DEV_BSS_INDEX); + + eOriMediaStatus = prP2pBssInfo->eConnectionState; + + /* Indicate disconnect. */ + if (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, + prP2pBssInfo->u4PrivateData); + + kalP2PGOStationUpdate(prAdapter->prGlueInfo, + prP2pRoleFsmInfo->ucRoleIndex, prStaRec, + false); + } else { + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, + prP2pBssInfo->u4PrivateData); + + prP2pRoleFsmInfo->rJoinInfo.prTargetBssDesc = NULL; + prP2pRoleFsmInfo->rJoinInfo.prTargetStaRec = NULL; + + scanRemoveConnFlagOfBssDescByBssid(prAdapter, + prP2pBssInfo->aucBSSID); + } + + if (fgSendDeauth) { + prStaRec->u2ReasonCode = u2ReasonCode; + prStaRec->fgIsLocallyGenerated = fgIsLocallyGenerated; + /* Send deauth. */ + authSendDeauthFrame( + prAdapter, prP2pBssInfo, prStaRec, (P_SW_RFB_T)NULL, + u2ReasonCode, + (PFN_TX_DONE_HANDLER)p2pRoleFsmRunEventDeauthTxDone); + wlanProcessCommandQueue(prAdapter, + &prAdapter->prGlueInfo->rCmdQueue); + } else { + /* Change station state. */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + /* Reset Station Record Status. */ + p2pFuncResetStaRecStatus(prAdapter, prStaRec); + + cnmStaRecFree(prAdapter, prStaRec); + + if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || + (bssGetClientCount(prAdapter, prP2pBssInfo) == 0)) { + DBGLOG(P2P, TRACE, + "No More Client, Media Status DISCONNECTED\n"); + p2pChangeMediaState(prAdapter, prP2pBssInfo, + PARAM_MEDIA_STATE_DISCONNECTED); + } + + if (eOriMediaStatus != prP2pBssInfo->eConnectionState) { + /* Update Disconnected state to FW. */ + nicUpdateBss(prAdapter, prP2pBssInfo->ucBssIndex); + } + } + } while (false); + + return; +} + +void p2pFuncSetChannel(IN P_ADAPTER_T prAdapter, IN u8 ucRoleIdx, + IN P_RF_CHANNEL_INFO_T prRfChannelInfo) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo = + (P_P2P_CONNECTION_REQ_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prRfChannelInfo != NULL)); + + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, ucRoleIdx); + if (!prP2pRoleFsmInfo) { + break; + } + prP2pConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo); + + prP2pConnReqInfo->rChannelInfo.ucChannelNum = + prRfChannelInfo->ucChannelNum; + prP2pConnReqInfo->rChannelInfo.eBand = prRfChannelInfo->eBand; + prP2pConnReqInfo->eChnlBw = prRfChannelInfo->ucChnlBw; + prP2pConnReqInfo->u2PriChnlFreq = prRfChannelInfo->u2PriChnlFreq; + prP2pConnReqInfo->u4CenterFreq1 = prRfChannelInfo->u4CenterFreq1; + prP2pConnReqInfo->u4CenterFreq2 = prRfChannelInfo->u4CenterFreq2; + +#if (CFG_SUPPORT_DFS_MASTER == 1) + prP2pConnReqInfo->u4ChnlDfsState = prRfChannelInfo->u4ChnlDfsState; +#endif + } while (false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Retry JOIN for AUTH_MODE_AUTO_SWITCH + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @retval true We will retry JOIN + * @retval false We will not retry JOIN + */ +/*----------------------------------------------------------------------------*/ +u8 p2pFuncRetryJOIN(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, + IN P_P2P_JOIN_INFO_T prJoinInfo) +{ + P_MSG_JOIN_REQ_T prJoinReqMsg = (P_MSG_JOIN_REQ_T)NULL; + u8 fgRetValue = false; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL) && + (prJoinInfo != NULL)); + + /* Retry other AuthType if possible */ + if (!prJoinInfo->ucAvailableAuthTypes) { + break; + } + + if (prJoinInfo->ucAvailableAuthTypes & (u8)AUTH_TYPE_SHARED_KEY) { + DBGLOG(P2P, INFO, + "RETRY JOIN INIT: Retry Authentication with AuthType == " + "SHARED_KEY.\n"); + + prJoinInfo->ucAvailableAuthTypes &= ~(u8)AUTH_TYPE_SHARED_KEY; + + prStaRec->ucAuthAlgNum = (u8)AUTH_ALGORITHM_NUM_SHARED_KEY; + } else { + DBGLOG( + P2P, ERROR, + "RETRY JOIN INIT: Retry Authentication with Unexpected AuthType.\n"); + ASSERT(0); + break; + } + + prJoinInfo->ucAvailableAuthTypes = 0; /* No more available Auth + * Types */ + + /* Trigger SAA to start JOIN process. */ + prJoinReqMsg = (P_MSG_JOIN_REQ_T)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_JOIN_REQ_T)); + if (!prJoinReqMsg) { + ASSERT(0); /* Can't trigger SAA FSM */ + break; + } + + prJoinReqMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_START; + prJoinReqMsg->ucSeqNum = ++prJoinInfo->ucSeqNumOfReqMsg; + prJoinReqMsg->prStaRec = prStaRec; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prJoinReqMsg, + MSG_SEND_METHOD_BUF); + + fgRetValue = true; + } while (false); + + return fgRetValue; +} + +P_BSS_INFO_T p2pFuncBSSIDFindBssInfo(IN P_ADAPTER_T prAdapter, IN u8 *pucBSSID) +{ + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T)NULL; + u8 ucBssIdx = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBSSID != NULL)); + + for (ucBssIdx = 0; ucBssIdx < BSS_INFO_NUM; ucBssIdx++) { + if (!IS_NET_ACTIVE(prAdapter, ucBssIdx)) { + continue; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIdx); + + if (EQUAL_MAC_ADDR(prBssInfo->aucBSSID, pucBSSID) && + IS_BSS_P2P(prBssInfo)) { + break; + } + + prBssInfo = NULL; + } + } while (false); + + return prBssInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will validate the Rx Auth Frame and then return + * the status code to AAA to indicate if need to perform following + * actions when the specified conditions were matched. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prSwRfb Pointer to SW RFB data structure. + * @param[in] pprStaRec Pointer to pointer of STA_RECORD_T structure. + * @param[out] pu2StatusCode The Status Code of Validation Result + * + * @retval true Reply the Auth + * @retval false Don't reply the Auth + */ +/*----------------------------------------------------------------------------*/ +u8 p2pFuncValidateAuth(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, + IN P_SW_RFB_T prSwRfb, IN PP_STA_RECORD_T pprStaRec, + OUT u16 *pu2StatusCode) +{ + u8 fgPmfConn = false; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + P_WLAN_AUTH_FRAME_T prAuthFrame = (P_WLAN_AUTH_FRAME_T)NULL; + + DBGLOG(P2P, TRACE, "p2pValidate Authentication Frame\n"); + + /* P2P 3.2.8 */ + *pu2StatusCode = STATUS_CODE_REQ_DECLINED; + prAuthFrame = (P_WLAN_AUTH_FRAME_T)prSwRfb->pvHeader; + + if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || + (prP2pBssInfo->eIntendOPMode != OP_MODE_NUM)) { + /* We are not under AP Mode yet. */ + DBGLOG(P2P, WARN, "Current OP mode is not under AP mode. (%d)\n", + prP2pBssInfo->eCurrentOPMode); + return false; + } + + prStaRec = cnmGetStaRecByAddress(prAdapter, prP2pBssInfo->ucBssIndex, + prAuthFrame->aucSrcAddr); + + if (!prStaRec) { + prStaRec = cnmStaRecAlloc(prAdapter, STA_TYPE_P2P_GC, + prP2pBssInfo->ucBssIndex, + prAuthFrame->aucSrcAddr); + + /* TODO(Kevin): Error handling of allocation of STA_RECORD_T for + * exhausted case and do removal of unused STA_RECORD_T. + */ + /* Sent a message event to clean un-used STA_RECORD_T. */ + ASSERT(prStaRec); + + prSwRfb->ucStaRecIdx = prStaRec->ucIndex; + + prStaRec->u2BSSBasicRateSet = prP2pBssInfo->u2BSSBasicRateSet; + + prStaRec->u2DesiredNonHTRateSet = RATE_SET_ERP_P2P; + + prStaRec->u2OperationalRateSet = RATE_SET_ERP_P2P; + prStaRec->ucPhyTypeSet = PHY_TYPE_SET_802_11GN; + + /* Update default Tx rate */ + nicTxUpdateStaRecDefaultRate(prStaRec); + + /* NOTE(Kevin): Better to change state here, not at TX Done */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + } else { +#if CFG_SUPPORT_802_11W + /* AP PMF. if PMF connection, do not reset state & FSM */ + fgPmfConn = rsnCheckBipKeyInstalled(prAdapter, prStaRec); + if (fgPmfConn) { + DBGLOG(P2P, WARN, "PMF Connction, return false\n"); + return false; + } +#endif + + prSwRfb->ucStaRecIdx = prStaRec->ucIndex; + + if ((prStaRec->ucStaState > STA_STATE_1) && (IS_STA_IN_P2P(prStaRec))) { + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + p2pFuncResetStaRecStatus(prAdapter, prStaRec); + + bssRemoveClient(prAdapter, prP2pBssInfo, prStaRec); +#if CFG_SUPPORT_802_11W + if (timerPendingTimer(&(prStaRec->rPmfCfg.rSAQueryTimer))) { + cnmTimerStopTimer(prAdapter, + &(prStaRec->rPmfCfg.rSAQueryTimer)); + } +#endif + p2pFuncDisconnect(prAdapter, prP2pBssInfo, prStaRec, false, + REASON_CODE_DISASSOC_INACTIVITY, true); + } + } + + if (bssGetClientCount(prAdapter, prP2pBssInfo) >= + P2P_MAXIMUM_CLIENT_COUNT || + !p2pRoleProcessACLInspection(prAdapter, prStaRec->aucMacAddr, + prP2pBssInfo->ucBssIndex) +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER + || kalP2PMaxClients(prAdapter->prGlueInfo, + bssGetClientCount(prAdapter, prP2pBssInfo), + (u8)prP2pBssInfo->u4PrivateData) +#endif + ) { + /* GROUP limit full. */ + /* P2P 3.2.8 */ + DBGLOG(P2P, WARN, "Group Limit Full. (%d)\n", + bssGetClientCount(prAdapter, prP2pBssInfo)); + cnmStaRecFree(prAdapter, prStaRec); + return true; + } +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER + else { + /* Hotspot Blacklist */ + if (kalP2PCmpBlackList(prAdapter->prGlueInfo, prAuthFrame->aucSrcAddr, + (u8)prP2pBssInfo->u4PrivateData)) { + return false; + } + } +#endif + /* prStaRec->eStaType = STA_TYPE_INFRA_CLIENT; */ + prStaRec->eStaType = STA_TYPE_P2P_GC; + + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + + prStaRec->ucJoinFailureCount = 0; + + *pprStaRec = prStaRec; + + *pu2StatusCode = STATUS_CODE_SUCCESSFUL; + + return true; +} + +void p2pFuncResetStaRecStatus(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec) +{ + do { + if ((prAdapter == NULL) || (prStaRec == NULL)) { + ASSERT(false); + break; + } + + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + prStaRec->u2ReasonCode = REASON_CODE_RESERVED; + prStaRec->ucJoinFailureCount = 0; + prStaRec->fgTransmitKeyExist = false; + + prStaRec->fgSetPwrMgtBit = false; + } while (false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief The function is used to initialize the value of the connection + * settings for P2P network + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void p2pFuncInitConnectionSettings( + IN P_ADAPTER_T prAdapter, IN P_P2P_CONNECTION_SETTINGS_T prP2PConnSettings, + IN u8 fgIsApMode) +{ + P_WIFI_VAR_T prWifiVar = NULL; + + ASSERT(prP2PConnSettings); + + prWifiVar = &(prAdapter->rWifiVar); + ASSERT(prWifiVar); + + prP2PConnSettings->fgIsApMode = fgIsApMode; + +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER + prP2PConnSettings->fgIsWPSMode = prWifiVar->ucApWpsMode; +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will validate the Rx Assoc Req Frame and then return + * the status code to AAA to indicate if need to perform following + * actions when the specified conditions were matched. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prSwRfb Pointer to SW RFB data structure. + * @param[out] pu2StatusCode The Status Code of Validation Result + * + * @retval true Reply the Assoc Resp + * @retval false Don't reply the Assoc Resp + */ +/*----------------------------------------------------------------------------*/ +u8 p2pFuncValidateAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + OUT u16 *pu2StatusCode) +{ + u8 fgReplyAssocResp = true; + P_WLAN_ASSOC_REQ_FRAME_T prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + /* TODO(Kevin): Call P2P functions to check .. + * 2. Check we can accept connection from thsi peer + * a. If we are in PROVISION state, only accept the peer we do the GO + * formation previously. b. If we are in OPERATION state, only accept + * the other peer when P2P_GROUP_LIMIT is 0. + * 3. Check Black List here. + */ + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL) && + (pu2StatusCode != NULL)); + + *pu2StatusCode = STATUS_CODE_REQ_DECLINED; + prAssocReqFrame = (P_WLAN_ASSOC_REQ_FRAME_T)prSwRfb->pvHeader; + + prP2pBssInfo = + p2pFuncBSSIDFindBssInfo(prAdapter, prAssocReqFrame->aucBSSID); + + if (prP2pBssInfo == NULL) { + DBGLOG(P2P, ERROR, + "RX ASSOC frame without BSS active / BSSID match\n"); + ASSERT(false); + break; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prStaRec == NULL) { + /* Station record should be ready while RX AUTH frame. + */ + fgReplyAssocResp = false; + ASSERT(false); + break; + } + ASSERT(prSwRfb->prRxStatusGroup3); + prStaRec->ucRCPI = nicRxGetRcpiValueFromRxv(RCPI_MODE_WF0, prSwRfb); + + prStaRec->u2DesiredNonHTRateSet &= prP2pBssInfo->u2OperationalRateSet; + prStaRec->ucDesiredPhyTypeSet = prStaRec->ucPhyTypeSet & + prP2pBssInfo->ucPhyTypeSet; + + if (prStaRec->ucDesiredPhyTypeSet == 0) { + /* The station only support 11B rate. */ + *pu2StatusCode = STATUS_CODE_ASSOC_DENIED_RATE_NOT_SUPPORTED; + break; + } + + *pu2StatusCode = STATUS_CODE_SUCCESSFUL; + } while (false); + + return fgReplyAssocResp; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to check the TKIP IE + * + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +u8 p2pFuncParseCheckForTKIPInfoElem(IN u8 *pucBuf) +{ + u8 aucWfaOui[] = VENDOR_OUI_WFA; + P_WPA_INFO_ELEM_T prWpaIE = (P_WPA_INFO_ELEM_T)NULL; + u32 u4GroupKeyCipher = 0; + + if (pucBuf == NULL) { + return false; + } + + prWpaIE = (P_WPA_INFO_ELEM_T)pucBuf; + + if (prWpaIE->ucLength <= ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE) { + return false; + } + + if (kalMemCmp(prWpaIE->aucOui, aucWfaOui, sizeof(aucWfaOui))) { + return false; + } + + WLAN_GET_FIELD_32(&prWpaIE->u4GroupKeyCipherSuite, &u4GroupKeyCipher); + + if (prWpaIE->ucOuiType == VENDOR_OUI_TYPE_WPA && + u4GroupKeyCipher == WPA_CIPHER_SUITE_TKIP) { + return true; + } else { + return false; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to check the P2P IE + * + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +u8 p2pFuncParseCheckForP2PInfoElem(IN P_ADAPTER_T prAdapter, IN u8 *pucBuf, + OUT u8 *pucOuiType) +{ + u8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; + P_IE_WFA_T prWfaIE = (P_IE_WFA_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && + (pucOuiType != NULL)); + + prWfaIE = (P_IE_WFA_T)pucBuf; + + if (IE_LEN(pucBuf) <= ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE) { + break; + } else if (prWfaIE->aucOui[0] != aucWfaOui[0] || + prWfaIE->aucOui[1] != aucWfaOui[1] || + prWfaIE->aucOui[2] != aucWfaOui[2]) { + break; + } + + *pucOuiType = prWfaIE->ucOuiType; + + return true; + } while (false); + + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will validate the Rx Probe Request Frame and then return + * result to BSS to indicate if need to send the corresponding Probe + * Response Frame if the specified conditions were matched. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prSwRfb Pointer to SW RFB data structure. + * @param[out] pu4ControlFlags Control flags for replying the Probe Response + * + * @retval true Reply the Probe Response + * @retval false Don't reply the Probe Response + */ +/*----------------------------------------------------------------------------*/ +u8 p2pFuncValidateProbeReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + OUT u32 *pu4ControlFlags, IN u8 fgIsDevInterface, + IN u8 ucRoleIdx) +{ + u8 fgIsReplyProbeRsp = false; + u8 fgApplyp2PDevFilter = false; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + DEBUGFUNC("p2pFuncValidateProbeReq"); + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + prP2pRoleFsmInfo = prAdapter->rWifiVar.aprP2pRoleFsmInfo[ucRoleIdx]; + + /* Process both cases that with amd without add p2p interface */ + if (fgIsDevInterface) { + fgApplyp2PDevFilter = true; + } else { + if (prAdapter->prGlueInfo->prP2PInfo[0]->prDevHandler == + prAdapter->prGlueInfo->prP2PInfo[ucRoleIdx]->aprRoleHandler) { + fgApplyp2PDevFilter = true; + } else { + fgApplyp2PDevFilter = false; + } + } + /* TODO: */ + if ((fgApplyp2PDevFilter && + (prAdapter->u4OsPacketFilter & PARAM_PACKET_FILTER_PROBE_REQ)) || + (!fgApplyp2PDevFilter && (prP2pRoleFsmInfo->u4P2pPacketFilter & + PARAM_PACKET_FILTER_PROBE_REQ))) { + /* Leave the probe response to p2p_supplicant. */ + kalP2PIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb, + fgIsDevInterface, ucRoleIdx); + } + } while (false); + + return fgIsReplyProbeRsp; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will validate the Rx Probe Request Frame and then return + * result to BSS to indicate if need to send the corresponding Probe + * Response Frame if the specified conditions were matched. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prSwRfb Pointer to SW RFB data structure. + * @param[out] pu4ControlFlags Control flags for replying the Probe Response + * + * @retval true Reply the Probe Response + * @retval false Don't reply the Probe Response + */ +/*----------------------------------------------------------------------------*/ +void p2pFuncValidateRxActionFrame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, IN u8 fgIsDevInterface, + IN u8 ucRoleIdx) +{ + u32 u4PacketFilter = 0; + DEBUGFUNC("p2pFuncValidateRxActionFrame"); + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + /* 20181109: frog. upper layer would crash if frame is not + * registered. */ + if (fgIsDevInterface) { + if (prAdapter->prGlueInfo->prP2PDevInfo) { + u4PacketFilter = + prAdapter->prGlueInfo->prP2PDevInfo->u4OsMgmtFrameFilter; + } + } else { + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = + prAdapter->rWifiVar.aprP2pRoleFsmInfo[ucRoleIdx]; + if (prP2pRoleFsmInfo) { + u4PacketFilter = prP2pRoleFsmInfo->u4P2pPacketFilter; + } + } + + if (u4PacketFilter & PARAM_PACKET_FILTER_ACTION_FRAME) { + /* Leave the probe response to p2p_supplicant. */ + kalP2PIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb, + fgIsDevInterface, ucRoleIdx); + } else { + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + struct net_device *prNetdevice = (struct net_device *)NULL; + + if (ucRoleIdx >= BSS_P2P_NUM) { + break; + } + prGlueP2pInfo = prAdapter->prGlueInfo->prP2PInfo[ucRoleIdx]; + if (!prGlueP2pInfo) { + break; + } + if (fgIsDevInterface) { + prNetdevice = prGlueP2pInfo->prDevHandler; + } else { + prNetdevice = prGlueP2pInfo->aprRoleHandler; + } + if (prNetdevice /* && prNetdevice->name >> this comparation are never be NULL (?) */) + { + DBGLOG(P2P, WARN, + "[%s] unregistered p2p action packet filter 0x%x\n", + prNetdevice->name, u4PacketFilter); + } + } + } while (false); + + return; +} + +u8 p2pFuncIsAPMode(IN P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings) +{ + if (prP2pConnSettings) { + if (prP2pConnSettings->fgIsWPSMode == 1) { + return false; + } + + return prP2pConnSettings->fgIsApMode; + } else { + return false; + } +} + +/* p2pFuncIsAPMode */ + +void p2pFuncParseBeaconContent(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo, IN u8 *pucIEInfo, + IN u32 u4IELen) +{ + u8 *pucIE = (u8 *)NULL; + u16 u2Offset = 0; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = + (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + u8 i = 0; + RSN_INFO_T rRsnIe; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL)); + + if (u4IELen == 0) { + break; + } + + prP2pSpecificBssInfo = + prAdapter->rWifiVar + .prP2pSpecificBssInfo[prP2pBssInfo->u4PrivateData]; + prP2pSpecificBssInfo->u2AttributeLen = 0; + + ASSERT_BREAK(pucIEInfo != NULL); + + pucIE = pucIEInfo; + + if (prP2pBssInfo->u2CapInfo & CAP_INFO_PRIVACY) { + kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_WEP40, + (u8)prP2pBssInfo->u4PrivateData); + } else { + kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_NONE, + (u8)prP2pBssInfo->u4PrivateData); + } + + IE_FOR_EACH(pucIE, u4IELen, u2Offset){ + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: /* 0 */ /* V */ /* Done */ + { + /* DBGLOG(P2P, TRACE, ("SSID update\n")); */ + /* SSID is saved when start AP/GO */ + /* SSID IE set in beacon from supplicant will + * not always be the true since hidden SSID case + */ + } break; + + case ELEM_ID_SUP_RATES: /* 1 */ /* V */ /* Done */ + { +#ifndef CFG_SUPPORT_P2P_GO_KEEP_RATE_SETTING + DBGLOG(P2P, TRACE, "Support Rate IE\n"); + if ((SUP_RATES_IE(pucIE)->ucLength) > ELEM_MAX_LEN_SUP_RATES) { + SUP_RATES_IE(pucIE)->ucLength = ELEM_MAX_LEN_SUP_RATES; + } + kalMemCopy(prP2pBssInfo->aucAllSupportedRates, + SUP_RATES_IE(pucIE)->aucSupportedRates, + SUP_RATES_IE(pucIE)->ucLength); + prP2pBssInfo->ucAllSupportedRatesLen = + SUP_RATES_IE(pucIE)->ucLength; + DBGLOG_MEM8(P2P, TRACE, SUP_RATES_IE(pucIE)->aucSupportedRates, + SUP_RATES_IE(pucIE)->ucLength); +#endif + } break; + + case ELEM_ID_DS_PARAM_SET: /* 3 */ /* V */ /* Done */ + { + DBGLOG(P2P, TRACE, "DS PARAM IE: %d.\n", + DS_PARAM_IE(pucIE)->ucCurrChnl); + + /* prP2pBssInfo->ucPrimaryChannel = + * DS_PARAM_IE(pucIE)->ucCurrChnl; */ + + /* prP2pBssInfo->eBand = BAND_2G4; */ + } break; + + case ELEM_ID_TIM: /* 5 */ /* V */ + TIM_IE(pucIE)->ucDTIMPeriod = prP2pBssInfo->ucDTIMPeriod; + DBGLOG(P2P, TRACE, "TIM IE, Len:%d, DTIM:%d\n", IE_LEN(pucIE), + TIM_IE(pucIE)->ucDTIMPeriod); + break; + + case ELEM_ID_ERP_INFO: /* 42 */ /* V */ + { + /* This IE would dynamic change due to FW + * detection change is required. */ + DBGLOG(P2P, TRACE, "ERP IE will be over write by driver\n"); + DBGLOG(P2P, TRACE, " ucERP: %x.\n", ERP_INFO_IE(pucIE)->ucERP); + } break; + + case ELEM_ID_HT_CAP: /* 45 */ /* V */ + { + DBGLOG(P2P, TRACE, + "HT CAP IE would be overwritten by driver\n"); + + DBGLOG(P2P, TRACE, "HT Cap Info:%x, AMPDU Param:%x\n", + HT_CAP_IE(pucIE)->u2HtCapInfo, + HT_CAP_IE(pucIE)->ucAmpduParam); + + DBGLOG( + P2P, TRACE, + "HT Extended Cap:%x, TX Beamforming Cap:%lx, Ant Selection " + "Cap:%x\n", + HT_CAP_IE(pucIE)->u2HtExtendedCap, + HT_CAP_IE(pucIE)->u4TxBeamformingCap, + HT_CAP_IE(pucIE)->ucAselCap); + } break; + + case ELEM_ID_RSN: /* 48 */ /* V */ + + DBGLOG(P2P, TRACE, "RSN IE\n"); + kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_CCMP, + (u8)prP2pBssInfo->u4PrivateData); + + if (rsnParseRsnIE(prAdapter, RSN_IE(pucIE), &rRsnIe)) { + prP2pBssInfo->u4RsnSelectedGroupCipher = + RSN_CIPHER_SUITE_CCMP; + prP2pBssInfo->u4RsnSelectedPairwiseCipher = + RSN_CIPHER_SUITE_CCMP; + prP2pBssInfo->u4RsnSelectedAKMSuite = RSN_AKM_SUITE_PSK; + prP2pBssInfo->u2RsnSelectedCapInfo = rRsnIe.u2RsnCap; + prAdapter->prGlueInfo->rWpaInfo.ucRsneLen = + rRsnIe.ucRsneLen; + DBGLOG(RSN, TRACE, "RsnIe CAP:0x%x\n", rRsnIe.u2RsnCap); + } + +#if CFG_SUPPORT_802_11W + /* AP PMF */ + prP2pBssInfo->rApPmfCfg.fgMfpc = + (rRsnIe.u2RsnCap & ELEM_WPA_CAP_MFPC) ? 1 : 0; + prP2pBssInfo->rApPmfCfg.fgMfpr = + (rRsnIe.u2RsnCap & ELEM_WPA_CAP_MFPR) ? 1 : 0; + + for (i = 0; i < rRsnIe.u4AuthKeyMgtSuiteCount; i++) { + if ((rRsnIe.au4AuthKeyMgtSuite[i] == + RSN_AKM_SUITE_PSK_SHA256) || + (rRsnIe.au4AuthKeyMgtSuite[i] == + RSN_AKM_SUITE_802_1X_SHA256)) { + DBGLOG(RSN, INFO, "SHA256 support\n"); + /* over-write + * u4RsnSelectedAKMSuite by + * SHA256 AKM */ + prP2pBssInfo->u4RsnSelectedAKMSuite = + rRsnIe.au4AuthKeyMgtSuite[i]; + prP2pBssInfo->rApPmfCfg.fgSha256 = true; + break; + } + } + DBGLOG_RATELIMIT(RSN, INFO, "bcn mfpc:%d, mfpr:%d, sha256:%d\n", + prP2pBssInfo->rApPmfCfg.fgMfpc, + prP2pBssInfo->rApPmfCfg.fgMfpr, + prP2pBssInfo->rApPmfCfg.fgSha256); +#endif + + break; + + case ELEM_ID_EXTENDED_SUP_RATES: /* 50 */ /* V */ + /* ELEM_ID_SUP_RATES should be placed before + * ELEM_ID_EXTENDED_SUP_RATES. */ +#ifndef CFG_SUPPORT_P2P_GO_KEEP_RATE_SETTING + DBGLOG(P2P, TRACE, "Ex Support Rate IE\n"); + kalMemCopy(&(prP2pBssInfo->aucAllSupportedRates + [prP2pBssInfo->ucAllSupportedRatesLen]), + EXT_SUP_RATES_IE(pucIE)->aucExtSupportedRates, + EXT_SUP_RATES_IE(pucIE)->ucLength); + + DBGLOG_MEM8(P2P, TRACE, + EXT_SUP_RATES_IE(pucIE)->aucExtSupportedRates, + EXT_SUP_RATES_IE(pucIE)->ucLength); + + prP2pBssInfo->ucAllSupportedRatesLen += + EXT_SUP_RATES_IE(pucIE)->ucLength; +#endif + break; + + case ELEM_ID_HT_OP: + /* 61 */ /* V */ /* TODO: */ + { + DBGLOG(P2P, TRACE, + "HT OP IE would be overwritten by driver\n"); + + DBGLOG( + P2P, TRACE, + " Primary Channel: %x, Info1: %x, Info2: %x, Info3: %x\n", + HT_OP_IE(pucIE)->ucPrimaryChannel, + HT_OP_IE(pucIE)->ucInfo1, HT_OP_IE(pucIE)->u2Info2, + HT_OP_IE(pucIE)->u2Info3); + } + break; + + case ELEM_ID_OBSS_SCAN_PARAMS: /* 74 */ /* V */ + { + DBGLOG( + P2P, TRACE, + "ELEM_ID_OBSS_SCAN_PARAMS IE would be replaced by driver\n"); + } break; + + case ELEM_ID_EXTENDED_CAP: /* 127 */ /* V */ + { + DBGLOG(P2P, TRACE, + "ELEM_ID_EXTENDED_CAP IE would be replaced by driver\n"); + } break; + + case ELEM_ID_VENDOR: /* 221 */ /* V */ + DBGLOG(P2P, TRACE, "Vender Specific IE\n"); + { + p2pFuncParseBeaconVenderId(prAdapter, pucIE, + prP2pSpecificBssInfo, + (u8)prP2pBssInfo->u4PrivateData); + /* TODO: Store other Vender IE except + * for WMM Param. */ + } + break; + + default: + DBGLOG(P2P, TRACE, "Unprocessed element ID:%d\n", IE_ID(pucIE)); + break; + } + } + } while (false); +} + +/* Code refactoring for AOSP */ +static void +p2pFuncParseBeaconVenderId(IN P_ADAPTER_T prAdapter, IN u8 *pucIE, + IN P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo, + IN u8 ucRoleIndex) +{ + do { + u8 ucOuiType; + u16 u2SubTypeVersion; + + if (rsnParseCheckForWFAInfoElem(prAdapter, pucIE, &ucOuiType, + &u2SubTypeVersion)) { + if ((ucOuiType == VENDOR_OUI_TYPE_WPA) && + (u2SubTypeVersion == VERSION_WPA)) { + if (IE_SIZE(pucIE) > (ELEM_HDR_LEN + ELEM_MAX_LEN_WPA)) { + DBGLOG(P2P, ERROR, + "wpa type only max 36 bytes but %d received\n", + IE_SIZE(pucIE)); + ASSERT(false); + break; + } + if (!kalP2PGetCcmpCipher(prAdapter->prGlueInfo, ucRoleIndex)) { + kalP2PSetCipher(prAdapter->prGlueInfo, IW_AUTH_CIPHER_TKIP, + ucRoleIndex); + } + kalMemCopy(prP2pSpecificBssInfo->aucWpaIeBuffer, pucIE, + IE_SIZE(pucIE)); + prP2pSpecificBssInfo->u2WpaIeLen = IE_SIZE(pucIE); + DBGLOG(P2P, TRACE, "WPA IE in supplicant\n"); + } else if (ucOuiType == VENDOR_OUI_TYPE_WPS) { + kalP2PUpdateWSC_IE(prAdapter->prGlueInfo, 0, pucIE, + IE_SIZE(pucIE), ucRoleIndex); + DBGLOG(P2P, TRACE, "WPS IE in supplicant\n"); + } else if (ucOuiType == VENDOR_OUI_TYPE_WMM) { + DBGLOG(P2P, TRACE, "WMM IE in supplicant\n"); + } + /* WMM here. */ + } else if (p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIE, + &ucOuiType)) { + /* TODO Store the whole P2P IE & generate later. */ + /* Be aware that there may be one or more P2P IE. */ + if (prP2pSpecificBssInfo->u2AttributeLen + IE_SIZE(pucIE) > + P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE) { + DBGLOG(P2P, ERROR, + "aucAttributesCache only 768 bytes but received more\n"); + ASSERT(false); + break; + } + if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache + [prP2pSpecificBssInfo->u2AttributeLen], + pucIE, IE_SIZE(pucIE)); + prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); + DBGLOG(P2P, TRACE, "P2P IE in supplicant\n"); + } else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { + kalMemCopy(&prP2pSpecificBssInfo->aucAttributesCache + [prP2pSpecificBssInfo->u2AttributeLen], + pucIE, IE_SIZE(pucIE)); + + prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); + } else { + DBGLOG(P2P, TRACE, "Unknown 50-6F-9A-%d IE.\n", ucOuiType); + } + } else { + if (prP2pSpecificBssInfo->u2AttributeLen + IE_SIZE(pucIE) > + P2P_MAXIMUM_ATTRIBUTES_CACHE_SIZE) { + DBGLOG(P2P, ERROR, + "aucAttributesCache only 768 bytes but received more\n"); + ASSERT(false); + break; + } + kalMemCopy( + &prP2pSpecificBssInfo + ->aucAttributesCache[prP2pSpecificBssInfo->u2AttributeLen], + pucIE, IE_SIZE(pucIE)); + + prP2pSpecificBssInfo->u2AttributeLen += IE_SIZE(pucIE); + DBGLOG(P2P, TRACE, "Driver unprocessed Vender Specific IE\n"); + ASSERT(false); + } + } while (0); +} + +P_BSS_DESC_T +p2pFuncKeepOnConnection(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, + IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo) +{ + P_BSS_DESC_T prTargetBss = (P_BSS_DESC_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prBssInfo != NULL) && + (prConnReqInfo != NULL) && (prChnlReqInfo != NULL) && + (prScanReqInfo != NULL)); + + if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + break; + } + /* Update connection request information. */ + ASSERT(prConnReqInfo->eConnRequest == P2P_CONNECTION_TYPE_GC); + + /* Find BSS Descriptor first. */ + prTargetBss = scanP2pSearchDesc(prAdapter, prConnReqInfo); + + if (prTargetBss == NULL) { + /* Update scan parameter... to scan target device. */ + /* TODO: Need refine. */ + prScanReqInfo->ucNumChannelList = 1; + prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqInfo->eChannelSet = SCAN_CHANNEL_FULL; + prScanReqInfo->u4BufLength = 0; /* Prevent other P2P ID + * in IE. */ + prScanReqInfo->fgIsAbort = true; + } else { + prChnlReqInfo->u8Cookie = 0; + prChnlReqInfo->ucReqChnlNum = prTargetBss->ucChannelNum; + prChnlReqInfo->eBand = prTargetBss->eBand; + prChnlReqInfo->eChnlSco = prTargetBss->eSco; + prChnlReqInfo->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; + prChnlReqInfo->eChnlReqType = CH_REQ_TYPE_JOIN; + + prChnlReqInfo->eChannelWidth = prTargetBss->eChannelWidth; + prChnlReqInfo->ucCenterFreqS1 = prTargetBss->ucCenterFreqS1; + prChnlReqInfo->ucCenterFreqS2 = prTargetBss->ucCenterFreqS2; + } + } while (false); + + return prTargetBss; +} + +/* Currently Only for ASSOC Response Frame. */ +void p2pFuncStoreAssocRspIEBuffer(IN P_ADAPTER_T prAdapter, + IN P_P2P_JOIN_INFO_T prP2pJoinInfo, + IN P_SW_RFB_T prSwRfb) +{ + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)NULL; + s16 i2IELen = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pJoinInfo != NULL) && + (prSwRfb != NULL)); + + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)prSwRfb->pvHeader; + + if (prAssocRspFrame->u2FrameCtrl != MAC_FRAME_ASSOC_RSP) { + break; + } + + i2IELen = + prSwRfb->u2PacketLen - (WLAN_MAC_HEADER_LEN + CAP_INFO_FIELD_LEN + + STATUS_CODE_FIELD_LEN + AID_FIELD_LEN); + + if (i2IELen <= 0) { + break; + } + + prP2pJoinInfo->u4BufLength = (u32)i2IELen; + + kalMemCopy(prP2pJoinInfo->aucIEBuf, prAssocRspFrame->aucInfoElem, + prP2pJoinInfo->u4BufLength); + } while (false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set Packet Filter. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] pvSetBuffer Pointer to the buffer that holds the data to be + * set. \param[in] u4SetBufferLen The length of the set buffer. \param[out] + * pu4SetInfoLen If the call is successful, returns the number of bytes read + * from the set buffer. If the call failed due to invalid length of the set + * buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + * \retval WLAN_STATUS_NOT_SUPPORTED + * \retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +void p2pFuncMgmtFrameRegister(IN P_ADAPTER_T prAdapter, IN u16 u2FrameType, + IN u8 fgIsRegistered, + OUT u32 *pu4P2pPacketFilter) +{ + u32 u4NewPacketFilter = 0; + CMD_RX_PACKET_FILTER rSetRxPacketFilter; + + DEBUGFUNC("p2pFuncMgmtFrameRegister"); + + do { + ASSERT_BREAK(prAdapter != NULL); + + if (pu4P2pPacketFilter) { + u4NewPacketFilter = *pu4P2pPacketFilter; + } + + switch (u2FrameType) { + case MAC_FRAME_PROBE_REQ: + if (fgIsRegistered) { + u4NewPacketFilter |= PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(P2P, TRACE, "Open packet filer probe request\n"); + } else { + u4NewPacketFilter &= ~PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(P2P, TRACE, "Close packet filer probe request\n"); + } + break; + + case MAC_FRAME_ACTION: + if (fgIsRegistered) { + u4NewPacketFilter |= PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(P2P, TRACE, "Open packet filer action frame.\n"); + } else { + u4NewPacketFilter &= ~PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(P2P, TRACE, "Close packet filer action frame.\n"); + } + break; + + default: + DBGLOG(P2P, TRACE, "unsupported frame type:%x\n", u2FrameType); + break; + } + + if (pu4P2pPacketFilter) { + *pu4P2pPacketFilter = u4NewPacketFilter; + } + + /* u4NewPacketFilter |= prAdapter->u4OsPacketFilter; */ + + prAdapter->u4OsPacketFilter &= ~PARAM_PACKET_FILTER_P2P_MASK; + prAdapter->u4OsPacketFilter |= u4NewPacketFilter; + + DBGLOG(P2P, TRACE, "P2P Set PACKET filter:0x%lx\n", + prAdapter->u4OsPacketFilter); + + kalMemZero(&rSetRxPacketFilter, sizeof(rSetRxPacketFilter)); + rSetRxPacketFilter.u4RxPacketFilter = prAdapter->u4OsPacketFilter; + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_RX_FILTER, true, false, false, + nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + sizeof(CMD_RX_PACKET_FILTER), + (u8 *)&rSetRxPacketFilter, &u4NewPacketFilter, + sizeof(u4NewPacketFilter)); + + prAdapter->u4OsPacketFilter = rSetRxPacketFilter.u4RxPacketFilter; + } while (false); +} + +void p2pFuncUpdateMgmtFrameRegister(IN P_ADAPTER_T prAdapter, + IN u32 u4OsFilter) +{ + CMD_RX_PACKET_FILTER rSetRxPacketFilter; + + do { + /* TODO: Filter need to be done. */ + /* prAdapter->rWifiVar.prP2pFsmInfo->u4P2pPacketFilter = + * u4OsFilter; */ + + if ((prAdapter->u4OsPacketFilter & PARAM_PACKET_FILTER_P2P_MASK) ^ + u4OsFilter) { + prAdapter->u4OsPacketFilter &= ~PARAM_PACKET_FILTER_P2P_MASK; + + prAdapter->u4OsPacketFilter |= + (u4OsFilter & PARAM_PACKET_FILTER_P2P_MASK); + + kalMemZero(&rSetRxPacketFilter, sizeof(rSetRxPacketFilter)); + rSetRxPacketFilter.u4RxPacketFilter = prAdapter->u4OsPacketFilter; + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_RX_FILTER, true, false, + false, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_RX_PACKET_FILTER), + (u8 *)&rSetRxPacketFilter, &u4OsFilter, + sizeof(u4OsFilter)); + + prAdapter->u4OsPacketFilter = rSetRxPacketFilter.u4RxPacketFilter; + DBGLOG(P2P, TRACE, "P2P Set PACKET filter:0x%lx\n", + prAdapter->u4OsPacketFilter); + } + } while (false); +} + +void p2pFuncGetStationInfo(IN P_ADAPTER_T prAdapter, IN u8 *pucMacAddr, + OUT P_P2P_STATION_INFO_T prStaInfo) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (pucMacAddr != NULL) && + (prStaInfo != NULL)); + + prStaInfo->u4InactiveTime = 0; + prStaInfo->u4RxBytes = 0; + prStaInfo->u4TxBytes = 0; + prStaInfo->u4RxPackets = 0; + prStaInfo->u4TxPackets = 0; + /* TODO: */ + } while (false); +} + +P_MSDU_INFO_T p2pFuncProcessP2pProbeRsp(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIdx, + IN P_MSDU_INFO_T prMgmtTxMsdu) +{ + P_MSDU_INFO_T prRetMsduInfo = prMgmtTxMsdu; + P_WLAN_PROBE_RSP_FRAME_T prProbeRspFrame = (P_WLAN_PROBE_RSP_FRAME_T)NULL; + u8 *pucIEBuf = (u8 *)NULL; + u16 u2Offset = 0, u2IELength = 0, u2ProbeRspHdrLen = 0; + u8 fgIsP2PIE = false, fgIsWSCIE = false; + u8 fgIsWFDIE = false; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + u16 u2EstimateSize = 0, u2EstimatedExtraIELen = 0; + u32 u4IeArraySize = 0, u4Idx = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMgmtTxMsdu != NULL)); + + prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIdx); + + /* 3 Make sure this is probe response frame. */ + prProbeRspFrame = + (P_WLAN_PROBE_RSP_FRAME_T)((unsigned long)prMgmtTxMsdu->prPacket + + MAC_TX_RESERVED_FIELD); + ASSERT_BREAK((prProbeRspFrame->u2FrameCtrl & MASK_FRAME_TYPE) == + MAC_FRAME_PROBE_RSP); + + /* 3 Get the importent P2P IE. */ + u2ProbeRspHdrLen = (WLAN_MAC_MGMT_HEADER_LEN + TIMESTAMP_FIELD_LEN + + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); + pucIEBuf = prProbeRspFrame->aucInfoElem; + u2IELength = prMgmtTxMsdu->u2FrameLength - u2ProbeRspHdrLen; + +#if CFG_SUPPORT_WFD + /* prAdapter->prGlueInfo->prP2PInfo[0]->u2VenderIELen = 0; */ + /* Reset in each time ?? */ + prAdapter->prGlueInfo->prP2PInfo[prP2pBssInfo->u4PrivateData] + ->u2WFDIELen = 0; +#endif + + IE_FOR_EACH(pucIEBuf, u2IELength, u2Offset){ + switch (IE_ID(pucIEBuf)) { + case ELEM_ID_SSID: { + p2pFuncProcessP2pProbeRspAction(prAdapter, pucIEBuf, + ELEM_ID_SSID, &ucBssIdx, + &prP2pBssInfo, &fgIsWSCIE, + &fgIsP2PIE, &fgIsWFDIE); + } break; + + case ELEM_ID_VENDOR: { + p2pFuncProcessP2pProbeRspAction(prAdapter, pucIEBuf, + ELEM_ID_VENDOR, &ucBssIdx, + &prP2pBssInfo, &fgIsWSCIE, + &fgIsP2PIE, &fgIsWFDIE); + } break; + + default: + break; + } + } + + /* 3 Check the total size & current frame. */ + u2EstimateSize = WLAN_MAC_MGMT_HEADER_LEN + TIMESTAMP_FIELD_LEN + + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SSID) + + (ELEM_HDR_LEN + ELEM_MAX_LEN_SUP_RATES) + + (ELEM_HDR_LEN + ELEM_MAX_LEN_DS_PARAMETER_SET); + + u2EstimatedExtraIELen = 0; + + u4IeArraySize = + sizeof(txProbeRspIETable) / sizeof(APPEND_VAR_IE_ENTRY_T); + for (u4Idx = 0; u4Idx < u4IeArraySize; u4Idx++) { + if (txProbeRspIETable[u4Idx].u2EstimatedFixedIELen) { + u2EstimatedExtraIELen += + txProbeRspIETable[u4Idx].u2EstimatedFixedIELen; + } else { + ASSERT(txProbeRspIETable[u4Idx].pfnCalculateVariableIELen); + + u2EstimatedExtraIELen += + (u16)(txProbeRspIETable[u4Idx].pfnCalculateVariableIELen( + prAdapter, ucBssIdx, NULL)); + } + } + + if (fgIsWSCIE) { + u2EstimatedExtraIELen += kalP2PCalWSC_IELen( + prAdapter->prGlueInfo, 2, (u8)prP2pBssInfo->u4PrivateData); + } + + if (fgIsP2PIE) { + u2EstimatedExtraIELen += kalP2PCalWSC_IELen( + prAdapter->prGlueInfo, 1, (u8)prP2pBssInfo->u4PrivateData); + u2EstimatedExtraIELen += + p2pFuncCalculateP2P_IE_NoA(prAdapter, ucBssIdx, NULL); + } +#if CFG_SUPPORT_WFD + ASSERT( + sizeof(prAdapter->prGlueInfo->prP2PInfo[prP2pBssInfo->u4PrivateData] + ->aucWFDIE) >= + prAdapter->prGlueInfo->prP2PInfo[prP2pBssInfo->u4PrivateData] + ->u2WFDIELen); + if (fgIsWFDIE) { + u2EstimatedExtraIELen += + prAdapter->prGlueInfo->prP2PInfo[prP2pBssInfo->u4PrivateData] + ->u2WFDIELen; + } +#endif + + u2EstimateSize += u2EstimatedExtraIELen; + if ((u2EstimateSize) > (prRetMsduInfo->u2FrameLength)) { + prRetMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimateSize); + + if (prRetMsduInfo == NULL) { + DBGLOG( + P2P, WARN, + "No packet for sending new probe response, use original one\n"); + prRetMsduInfo = prMgmtTxMsdu; + break; + } + } + + prRetMsduInfo->ucBssIndex = ucBssIdx; + + /* 3 Compose / Re-compose probe response frame. */ + bssComposeBeaconProbeRespFrameHeaderAndFF( + (u8 *)((unsigned long)(prRetMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD), + prProbeRspFrame->aucDestAddr, prProbeRspFrame->aucSrcAddr, + prProbeRspFrame->aucBSSID, prProbeRspFrame->u2BeaconInterval, + prProbeRspFrame->u2CapInfo); + + prRetMsduInfo->u2FrameLength = + (WLAN_MAC_MGMT_HEADER_LEN + TIMESTAMP_FIELD_LEN + + BEACON_INTERVAL_FIELD_LEN + CAP_INFO_FIELD_LEN); + + bssBuildBeaconProbeRespFrameCommonIEs(prRetMsduInfo, prP2pBssInfo, + prProbeRspFrame->aucDestAddr); + + prRetMsduInfo->ucStaRecIndex = prMgmtTxMsdu->ucStaRecIndex; + + for (u4Idx = 0; u4Idx < u4IeArraySize; u4Idx++) { + if (txProbeRspIETable[u4Idx].pfnAppendIE) { + txProbeRspIETable[u4Idx].pfnAppendIE(prAdapter, prRetMsduInfo); + } + } + + if (fgIsWSCIE) { + kalP2PGenWSC_IE(prAdapter->prGlueInfo, 2, + (u8 *)((unsigned long)prRetMsduInfo->prPacket + + (unsigned long)prRetMsduInfo->u2FrameLength), + (u8)prP2pBssInfo->u4PrivateData); + + prRetMsduInfo->u2FrameLength += (u16)kalP2PCalWSC_IELen( + prAdapter->prGlueInfo, 2, (u8)prP2pBssInfo->u4PrivateData); + } + + if (fgIsP2PIE) { + kalP2PGenWSC_IE(prAdapter->prGlueInfo, 1, + (u8 *)((unsigned long)prRetMsduInfo->prPacket + + (unsigned long)prRetMsduInfo->u2FrameLength), + (u8)prP2pBssInfo->u4PrivateData); + + prRetMsduInfo->u2FrameLength += (u16)kalP2PCalWSC_IELen( + prAdapter->prGlueInfo, 1, (u8)prP2pBssInfo->u4PrivateData); + p2pFuncGenerateP2P_IE_NoA(prAdapter, prRetMsduInfo); + } +#if CFG_SUPPORT_WFD + if (fgIsWFDIE > 0) { + ASSERT(prAdapter->prGlueInfo->prP2PInfo[prP2pBssInfo->u4PrivateData] + ->u2WFDIELen > 0); + kalMemCopy( + (u8 *)((unsigned long)prRetMsduInfo->prPacket + + (unsigned long)prRetMsduInfo->u2FrameLength), + prAdapter->prGlueInfo->prP2PInfo[prP2pBssInfo->u4PrivateData] + ->aucWFDIE, + prAdapter->prGlueInfo->prP2PInfo[prP2pBssInfo->u4PrivateData] + ->u2WFDIELen); + prRetMsduInfo->u2FrameLength += + (u16)prAdapter->prGlueInfo + ->prP2PInfo[prP2pBssInfo->u4PrivateData] + ->u2WFDIELen; + } +#endif + } while (false); + + if (prRetMsduInfo != prMgmtTxMsdu) { + cnmMgtPktFree(prAdapter, prMgmtTxMsdu); + } + + return prRetMsduInfo; +} + +/* Code refactoring for AOSP */ +static void p2pFuncProcessP2pProbeRspAction( + IN P_ADAPTER_T prAdapter, IN u8 *pucIEBuf, IN u8 ucElemIdType, + OUT u8 *ucBssIdx, OUT P_BSS_INFO_T *prP2pBssInfo, OUT u8 *fgIsWSCIE, + OUT u8 *fgIsP2PIE, OUT u8 *fgIsWFDIE) +{ + u8 ucOuiType = 0; + u16 u2SubTypeVersion = 0; + + switch (ucElemIdType) { + case ELEM_ID_SSID: { + if (SSID_IE(pucIEBuf)->ucLength > 7) { + for ((*ucBssIdx) = 0; (*ucBssIdx) < MAX_BSS_INDEX; (*ucBssIdx)++) { + *prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, *ucBssIdx); + if (!(*prP2pBssInfo)) { + continue; + } + if (EQUAL_SSID((*prP2pBssInfo)->aucSSID, + (*prP2pBssInfo)->ucSSIDLen, + SSID_IE(pucIEBuf)->aucSSID, + SSID_IE(pucIEBuf)->ucLength)) { + break; + } + } + if ((*ucBssIdx) == P2P_DEV_BSS_INDEX) { + *prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, *ucBssIdx); + } + } else { + *prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, P2P_DEV_BSS_INDEX); + COPY_SSID((*prP2pBssInfo)->aucSSID, (*prP2pBssInfo)->ucSSIDLen, + SSID_IE(pucIEBuf)->aucSSID, SSID_IE(pucIEBuf)->ucLength); + } + } break; + + case ELEM_ID_VENDOR: + if (rsnParseCheckForWFAInfoElem(prAdapter, pucIEBuf, &ucOuiType, + &u2SubTypeVersion)) { + if (ucOuiType == VENDOR_OUI_TYPE_WPS) { + kalP2PUpdateWSC_IE( + prAdapter->prGlueInfo, 2, pucIEBuf, IE_SIZE(pucIEBuf), + (u8)((P_BSS_INFO_T)*prP2pBssInfo)->u4PrivateData); + *fgIsWSCIE = true; + } + } else if (p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIEBuf, + &ucOuiType)) { + if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + /* 2 Note(frog): I use WSC IE buffer for Probe + * Request to store the P2P IE for Probe + * Response. + */ + kalP2PUpdateWSC_IE( + prAdapter->prGlueInfo, 1, pucIEBuf, IE_SIZE(pucIEBuf), + (u8)((P_BSS_INFO_T)*prP2pBssInfo)->u4PrivateData); + *fgIsP2PIE = true; + } +#if CFG_SUPPORT_WFD + else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { + DBGLOG(P2P, INFO, + "WFD IE is found in probe resp (supp). Len %u\n", + IE_SIZE(pucIEBuf)); + if ((sizeof(prAdapter->prGlueInfo + ->prP2PInfo[((P_BSS_INFO_T)*prP2pBssInfo) + ->u4PrivateData] + ->aucWFDIE) >= + (prAdapter->prGlueInfo + ->prP2PInfo[((P_BSS_INFO_T)*prP2pBssInfo) + ->u4PrivateData] + ->u2WFDIELen + + IE_SIZE(pucIEBuf)))) { + *fgIsWFDIE = true; + kalMemCopy(prAdapter->prGlueInfo + ->prP2PInfo[((P_BSS_INFO_T)*prP2pBssInfo) + ->u4PrivateData] + ->aucWFDIE, + pucIEBuf, IE_SIZE(pucIEBuf)); + prAdapter->prGlueInfo + ->prP2PInfo[((P_BSS_INFO_T)*prP2pBssInfo)->u4PrivateData] + ->u2WFDIELen += IE_SIZE(pucIEBuf); + } + } /* VENDOR_OUI_TYPE_WFD */ +#endif + } else { + DBGLOG(P2P, INFO, + "Other vender IE is found in probe resp (supp). Len %u\n", + IE_SIZE(pucIEBuf)); + } + break; + + default: + break; + } +} + +u32 p2pFuncCalculateP2p_IELenForBeacon(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx, + IN P_STA_RECORD_T prStaRec) +{ + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + u32 u4IELen = 0; + P_BSS_INFO_T prBssInfo; + + do { + ASSERT_BREAK((prAdapter != NULL) && (ucBssIdx < BSS_INFO_NUM)); + + prBssInfo = prAdapter->aprBssInfo[ucBssIdx]; + + if (!prAdapter->fgIsP2PRegistered) { + break; + } + + if (p2pFuncIsAPMode(prAdapter->rWifiVar + .prP2PConnSettings[prBssInfo->u4PrivateData])) { + break; + } + + prP2pSpeBssInfo = + prAdapter->rWifiVar.prP2pSpecificBssInfo[prBssInfo->u4PrivateData]; + + u4IELen = prP2pSpeBssInfo->u2AttributeLen; + } while (false); + + return u4IELen; +} + +void p2pFuncGenerateP2p_IEForBeacon(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpeBssInfo = (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + u8 *pucIEBuf = (u8 *)NULL; + P_BSS_INFO_T prBssInfo; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + if (!prAdapter->fgIsP2PRegistered) { + break; + } + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + + prP2pSpeBssInfo = + prAdapter->rWifiVar.prP2pSpecificBssInfo[prBssInfo->u4PrivateData]; + + if (p2pFuncIsAPMode(prAdapter->rWifiVar + .prP2PConnSettings[prBssInfo->u4PrivateData])) { + break; + } + + pucIEBuf = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + + kalMemCopy(pucIEBuf, prP2pSpeBssInfo->aucAttributesCache, + prP2pSpeBssInfo->u2AttributeLen); + + prMsduInfo->u2FrameLength += prP2pSpeBssInfo->u2AttributeLen; + } while (false); +} + +u32 p2pFuncCalculateWSC_IELenForBeacon(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx, + IN P_STA_RECORD_T prStaRec) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIdx); + + if (prP2pBssInfo->eNetworkType != NETWORK_TYPE_P2P) { + return 0; + } + + return kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0, + (u8)prP2pBssInfo->u4PrivateData); +} + +void p2pFuncGenerateWSC_IEForBeacon(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + u8 *pucBuffer; + u16 u2IELen = 0; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + + if (prP2pBssInfo->eNetworkType != NETWORK_TYPE_P2P) { + return; + } + + u2IELen = (u16)kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 0, + (u8)prP2pBssInfo->u4PrivateData); + + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + /* TODO: Check P2P FSM State. */ + kalP2PGenWSC_IE(prAdapter->prGlueInfo, 0, pucBuffer, + (u8)prP2pBssInfo->u4PrivateData); + + prMsduInfo->u2FrameLength += u2IELen; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to calculate P2P IE length for Beacon frame. + * + * @param[in] eNetTypeIndex Specify which network + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @return The length of P2P IE added + */ +/*----------------------------------------------------------------------------*/ +u32 p2pFuncCalculateP2p_IELenForAssocRsp(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_STA_RECORD_T prStaRec) +{ + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T)NULL; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if (prBssInfo->eNetworkType != NETWORK_TYPE_P2P) { + return 0; + } + + return p2pFuncCalculateP2P_IELen( + prAdapter, ucBssIndex, prStaRec, txAssocRspAttributesTable, + sizeof(txAssocRspAttributesTable) / sizeof(APPEND_VAR_ATTRI_ENTRY_T)); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to generate P2P IE for Beacon frame. + * + * @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void p2pFuncGenerateP2p_IEForAssocRsp(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (!prStaRec) { + DBGLOG(P2P, ERROR, "prStaRec of ucStaRecIndex %d is NULL!\n", + prMsduInfo->ucStaRecIndex); + return; + } + + if (IS_STA_IN_P2P(prStaRec)) { + DBGLOG(P2P, TRACE, "Generate NULL P2P IE for Assoc Rsp.\n"); + + p2pFuncGenerateP2P_IE(prAdapter, prMsduInfo->ucBssIndex, true, + &prMsduInfo->u2FrameLength, prMsduInfo->prPacket, + 1500, txAssocRspAttributesTable, + sizeof(txAssocRspAttributesTable) / + sizeof(APPEND_VAR_ATTRI_ENTRY_T)); + } else { + DBGLOG(P2P, TRACE, "Legacy device, no P2P IE.\n"); + } +} + +u32 p2pFuncCalculateP2P_IELen(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN P_STA_RECORD_T prStaRec, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], + IN u32 u4AttriTableSize) +{ + u32 u4OverallAttriLen, u4Dummy; + u16 u2EstimatedFixedAttriLen; + u32 i; + + /* Overall length of all Attributes */ + u4OverallAttriLen = 0; + + for (i = 0; i < u4AttriTableSize; i++) { + u2EstimatedFixedAttriLen = + arAppendAttriTable[i].u2EstimatedFixedAttriLen; + + if (u2EstimatedFixedAttriLen) { + u4OverallAttriLen += u2EstimatedFixedAttriLen; + } else { + ASSERT(arAppendAttriTable[i].pfnCalculateVariableAttriLen); + + u4OverallAttriLen += + arAppendAttriTable[i].pfnCalculateVariableAttriLen(prAdapter, + prStaRec); + } + } + + u4Dummy = u4OverallAttriLen; + u4OverallAttriLen += P2P_IE_OUI_HDR; + + for (; (u4Dummy > P2P_MAXIMUM_ATTRIBUTE_LEN);) { + u4OverallAttriLen += P2P_IE_OUI_HDR; + u4Dummy -= P2P_MAXIMUM_ATTRIBUTE_LEN; + } + + return u4OverallAttriLen; +} + +void p2pFuncGenerateP2P_IE(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN u8 fgIsAssocFrame, IN u16 *pu2Offset, + IN u8 *pucBuf, IN u16 u2BufSize, + IN APPEND_VAR_ATTRI_ENTRY_T arAppendAttriTable[], + IN u32 u4AttriTableSize) +{ + u8 *pucBuffer = (u8 *)NULL; + P_IE_P2P_T prIeP2P = (P_IE_P2P_T)NULL; + u32 u4OverallAttriLen; + u32 u4AttriLen; + u8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; + u8 aucTempBuffer[P2P_MAXIMUM_ATTRIBUTE_LEN]; + u32 i; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL)); + + pucBuffer = (u8 *)((unsigned long)pucBuf + (*pu2Offset)); + + ASSERT_BREAK(pucBuffer != NULL); + + /* Check buffer length is still enough. */ + ASSERT_BREAK((u2BufSize - (*pu2Offset)) >= P2P_IE_OUI_HDR); + + prIeP2P = (P_IE_P2P_T)pucBuffer; + + prIeP2P->ucId = ELEM_ID_P2P; + + prIeP2P->aucOui[0] = aucWfaOui[0]; + prIeP2P->aucOui[1] = aucWfaOui[1]; + prIeP2P->aucOui[2] = aucWfaOui[2]; + prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; + + (*pu2Offset) += P2P_IE_OUI_HDR; + + /* Overall length of all Attributes */ + u4OverallAttriLen = 0; + + for (i = 0; i < u4AttriTableSize; i++) { + if (arAppendAttriTable[i].pfnAppendAttri) { + u4AttriLen = arAppendAttriTable[i].pfnAppendAttri( + prAdapter, ucBssIndex, fgIsAssocFrame, pu2Offset, pucBuf, + u2BufSize); + + u4OverallAttriLen += u4AttriLen; + + if (u4OverallAttriLen > P2P_MAXIMUM_ATTRIBUTE_LEN) { + u4OverallAttriLen -= P2P_MAXIMUM_ATTRIBUTE_LEN; + + prIeP2P->ucLength = + (VENDOR_OUI_TYPE_LEN + P2P_MAXIMUM_ATTRIBUTE_LEN); + + pucBuffer = (u8 *)((unsigned long)prIeP2P + + (VENDOR_OUI_TYPE_LEN + + P2P_MAXIMUM_ATTRIBUTE_LEN)); + + prIeP2P = (P_IE_P2P_T)((unsigned long)prIeP2P + + (ELEM_HDR_LEN + + (VENDOR_OUI_TYPE_LEN + + P2P_MAXIMUM_ATTRIBUTE_LEN))); + + kalMemCopy(aucTempBuffer, pucBuffer, u4OverallAttriLen); + + prIeP2P->ucId = ELEM_ID_P2P; + + prIeP2P->aucOui[0] = aucWfaOui[0]; + prIeP2P->aucOui[1] = aucWfaOui[1]; + prIeP2P->aucOui[2] = aucWfaOui[2]; + prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; + + kalMemCopy(prIeP2P->aucP2PAttributes, aucTempBuffer, + u4OverallAttriLen); + (*pu2Offset) += P2P_IE_OUI_HDR; + } + } + } + + prIeP2P->ucLength = (u8)(VENDOR_OUI_TYPE_LEN + u4OverallAttriLen); + } while (false); +} + +u32 p2pFuncAppendAttriStatusForAssocRsp(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, IN u8 fgIsAssocFrame, + IN u16 *pu2Offset, IN u8 *pucBuf, + IN u16 u2BufSize) +{ + u8 *pucBuffer; + P_P2P_ATTRI_STATUS_T prAttriStatus; + u32 u4AttriLen = 0; + + ASSERT(prAdapter); + ASSERT(pucBuf); + + if (fgIsAssocFrame) { + return u4AttriLen; + } + + /* TODO: For assoc request P2P IE check in driver & return status in P2P + * IE. */ + + pucBuffer = (u8 *)((unsigned long)pucBuf + (unsigned long)(*pu2Offset)); + + ASSERT(pucBuffer); + prAttriStatus = (P_P2P_ATTRI_STATUS_T)pucBuffer; + + ASSERT(u2BufSize >= ((*pu2Offset) + (u16)u4AttriLen)); + + prAttriStatus->ucId = P2P_ATTRI_ID_STATUS; + WLAN_SET_FIELD_16(&prAttriStatus->u2Length, P2P_ATTRI_MAX_LEN_STATUS); + + prAttriStatus->ucStatusCode = P2P_STATUS_SUCCESS; + + u4AttriLen = (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_STATUS); + + (*pu2Offset) += (u16)u4AttriLen; + + return u4AttriLen; +} + +u32 p2pFuncAppendAttriExtListenTiming(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, IN u8 fgIsAssocFrame, + IN u16 *pu2Offset, IN u8 *pucBuf, + IN u16 u2BufSize) +{ + u32 u4AttriLen = 0; + P_P2P_ATTRI_EXT_LISTEN_TIMING_T prP2pExtListenTiming = + (P_P2P_ATTRI_EXT_LISTEN_TIMING_T)NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = + (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + u8 *pucBuffer = NULL; + P_BSS_INFO_T prBssInfo = NULL; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + ASSERT(prAdapter); + ASSERT(pucBuf); + ASSERT(prBssInfo); + + if (fgIsAssocFrame) { + return u4AttriLen; + } + + /* TODO: For extend listen timing. */ + + prP2pSpecificBssInfo = + prAdapter->rWifiVar.prP2pSpecificBssInfo[prBssInfo->u4PrivateData]; + + u4AttriLen = (P2P_ATTRI_HDR_LEN + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING); + + ASSERT(u2BufSize >= ((*pu2Offset) + (u16)u4AttriLen)); + + pucBuffer = (u8 *)((unsigned long)pucBuf + (unsigned long)(*pu2Offset)); + + ASSERT(pucBuffer); + + prP2pExtListenTiming = (P_P2P_ATTRI_EXT_LISTEN_TIMING_T)pucBuffer; + + prP2pExtListenTiming->ucId = P2P_ATTRI_ID_EXT_LISTEN_TIMING; + WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2Length, + P2P_ATTRI_MAX_LEN_EXT_LISTEN_TIMING); + WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2AvailInterval, + prP2pSpecificBssInfo->u2AvailabilityInterval); + WLAN_SET_FIELD_16(&prP2pExtListenTiming->u2AvailPeriod, + prP2pSpecificBssInfo->u2AvailabilityPeriod); + + (*pu2Offset) += (u16)u4AttriLen; + + return u4AttriLen; +} + +P_IE_HDR_T +p2pFuncGetSpecIE(IN P_ADAPTER_T prAdapter, IN u8 *pucIEBuf, IN u16 u2BufferLen, + IN u8 ucElemID, IN u8 *pfgIsMore) +{ + P_IE_HDR_T prTargetIE = (P_IE_HDR_T)NULL; + u8 *pucIE = (u8 *)NULL; + u16 u2Offset = 0; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucIEBuf != NULL)); + + pucIE = pucIEBuf; + + if (pfgIsMore) { + *pfgIsMore = false; + } + + IE_FOR_EACH(pucIE, u2BufferLen, u2Offset){ + if (IE_ID(pucIE) == ucElemID) { + if ((prTargetIE) && (pfgIsMore)) { + *pfgIsMore = true; + break; + } + prTargetIE = (P_IE_HDR_T)pucIE; + + if (pfgIsMore == NULL) { + break; + } + } + } + } while (false); + + return prTargetIE; +} + +P_ATTRIBUTE_HDR_T +p2pFuncGetSpecAttri(IN P_ADAPTER_T prAdapter, IN u8 ucOuiType, IN u8 *pucIEBuf, + IN u16 u2BufferLen, IN u8 ucAttriID) +{ + P_IE_P2P_T prP2pIE = (P_IE_P2P_T)NULL; + P_ATTRIBUTE_HDR_T prTargetAttri = (P_ATTRIBUTE_HDR_T)NULL; + u8 fgIsMore = false; + u8 *pucIE = (u8 *)NULL; + u16 u2BufferLenLeft = 0; + + DBGLOG(P2P, INFO, "Check AssocReq Oui type %u attri %u for len %u\n", + ucOuiType, ucAttriID, u2BufferLen); + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucIEBuf != NULL)); + + u2BufferLenLeft = u2BufferLen; + pucIE = pucIEBuf; + + do { + fgIsMore = false; + prP2pIE = (P_IE_P2P_T)p2pFuncGetSpecIE( + prAdapter, pucIE, u2BufferLenLeft, ELEM_ID_VENDOR, &fgIsMore); + if (prP2pIE) { + ASSERT((unsigned long)prP2pIE >= (unsigned long)pucIE); + u2BufferLenLeft = + u2BufferLen - + (u16)(((unsigned long)prP2pIE) - ((unsigned long)pucIEBuf)); + + DBGLOG(P2P, INFO, + "Find vendor id %u len %u oui %u more %u LeftLen %u\n", + IE_ID(prP2pIE), IE_LEN(prP2pIE), prP2pIE->ucOuiType, + fgIsMore, u2BufferLenLeft); + + if (IE_LEN(prP2pIE) > P2P_OUI_TYPE_LEN) { + p2pFuncGetSpecAttriAction(prP2pIE, ucOuiType, ucAttriID, + &prTargetAttri); + } + /* P2P_OUI_TYPE_LEN */ + pucIE = (u8 *)(((unsigned long)prP2pIE) + IE_SIZE(prP2pIE)); + } + /* prP2pIE */ + } while (prP2pIE && fgIsMore && u2BufferLenLeft); + } while (false); + + return prTargetAttri; +} + +/* p2pFuncGetSpecAttri */ + +/* Code refactoring for AOSP */ +static void p2pFuncGetSpecAttriAction(IN P_IE_P2P_T prP2pIE, IN u8 ucOuiType, + IN u8 ucAttriID, + OUT P_ATTRIBUTE_HDR_T *prTargetAttri) +{ + u8 *pucAttri = (u8 *)NULL; + u16 u2OffsetAttri = 0; + u8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; + + if (prP2pIE->ucOuiType == ucOuiType) { + switch (ucOuiType) { + case VENDOR_OUI_TYPE_WPS: + aucWfaOui[0] = 0x00; + aucWfaOui[1] = 0x50; + aucWfaOui[2] = 0xF2; + break; + + case VENDOR_OUI_TYPE_P2P: + break; + + case VENDOR_OUI_TYPE_WPA: + case VENDOR_OUI_TYPE_WMM: + case VENDOR_OUI_TYPE_WFD: + default: + break; + } + + if ((prP2pIE->aucOui[0] == aucWfaOui[0]) && + (prP2pIE->aucOui[1] == aucWfaOui[1]) && + (prP2pIE->aucOui[2] == aucWfaOui[2])) { + u2OffsetAttri = 0; + pucAttri = prP2pIE->aucP2PAttributes; + + if (ucOuiType == VENDOR_OUI_TYPE_WPS) { + WSC_ATTRI_FOR_EACH(pucAttri, (IE_LEN(prP2pIE) - P2P_IE_OUI_HDR), + u2OffsetAttri){ + if (WSC_ATTRI_ID(pucAttri) == ucAttriID) { + *prTargetAttri = (P_ATTRIBUTE_HDR_T)pucAttri; + break; + } + } + } else if (ucOuiType == VENDOR_OUI_TYPE_P2P) { + P2P_ATTRI_FOR_EACH(pucAttri, (IE_LEN(prP2pIE) - P2P_IE_OUI_HDR), + u2OffsetAttri){ + if (ATTRI_ID(pucAttri) == ucAttriID) { + *prTargetAttri = (P_ATTRIBUTE_HDR_T)pucAttri; + break; + } + } + } +#if CFG_SUPPORT_WFD + else if (ucOuiType == VENDOR_OUI_TYPE_WFD) { + WFD_ATTRI_FOR_EACH(pucAttri, (IE_LEN(prP2pIE) - P2P_IE_OUI_HDR), + u2OffsetAttri){ + if (ATTRI_ID(pucAttri) == (u8)ucAttriID) { + *prTargetAttri = (P_ATTRIBUTE_HDR_T)pucAttri; + break; + } + } + } +#endif + else { + /* Todo:: Nothing */ + /* Possible or else. */ + } + } + } +} + +WLAN_STATUS +p2pFuncGenerateBeaconProbeRsp(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prBssInfo, + IN P_MSDU_INFO_T prMsduInfo, IN u8 fgIsProbeRsp) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_WLAN_BEACON_FRAME_T prBcnFrame = (P_WLAN_BEACON_FRAME_T)NULL; + /* P_APPEND_VAR_IE_ENTRY_T prAppendIeTable = + * (P_APPEND_VAR_IE_ENTRY_T)NULL; */ + + do { + ASSERT_BREAK((prAdapter != NULL) && (prBssInfo != NULL) && + (prMsduInfo != NULL)); + + /* txBcnIETable */ + + /* txProbeRspIETable */ + + prBcnFrame = (P_WLAN_BEACON_FRAME_T)prMsduInfo->prPacket; + + return nicUpdateBeaconIETemplate( + prAdapter, IE_UPD_METHOD_UPDATE_ALL, prBssInfo->ucBssIndex, + prBssInfo->u2CapInfo, (u8 *)prBcnFrame->aucInfoElem, + prMsduInfo->u2FrameLength - + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem)); + } while (false); + + return rWlanStatus; +} + +WLAN_STATUS +p2pFuncComposeBeaconProbeRspTemplate( + IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prP2pBssInfo, IN u8 *pucBcnBuffer, + IN u32 u4BcnBufLen, IN u8 fgIsProbeRsp, + IN P_P2P_PROBE_RSP_UPDATE_INFO_T prP2pProbeRspInfo, IN u8 fgSynToFW) +{ + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T)NULL; + P_WLAN_MAC_HEADER_T prWlanBcnFrame = (P_WLAN_MAC_HEADER_T)NULL; + + u8 *pucBuffer = (u8 *)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBcnBuffer != NULL) && + (prP2pBssInfo != NULL)); + + prWlanBcnFrame = (P_WLAN_MAC_HEADER_T)pucBcnBuffer; + + if ((prWlanBcnFrame->u2FrameCtrl != MAC_FRAME_BEACON) && + (!fgIsProbeRsp)) { + rWlanStatus = WLAN_STATUS_INVALID_DATA; + break; + } else if (prWlanBcnFrame->u2FrameCtrl != MAC_FRAME_PROBE_RSP) { + rWlanStatus = WLAN_STATUS_INVALID_DATA; + break; + } + + if (fgIsProbeRsp) { + ASSERT_BREAK(prP2pProbeRspInfo != NULL); + + if (!prP2pProbeRspInfo->prProbeRspMsduTemplate) { + cnmMgtPktFree(prAdapter, + prP2pProbeRspInfo->prProbeRspMsduTemplate); + } + + prP2pProbeRspInfo->prProbeRspMsduTemplate = + cnmMgtPktAlloc(prAdapter, u4BcnBufLen); + + prMsduInfo = prP2pProbeRspInfo->prProbeRspMsduTemplate; + + prMsduInfo->eSrc = TX_PACKET_MGMT; + prMsduInfo->ucStaRecIndex = 0xFF; + prMsduInfo->ucBssIndex = prP2pBssInfo->ucBssIndex; + } else { + prMsduInfo = prP2pBssInfo->prBeacon; + + if (prMsduInfo == NULL) { + rWlanStatus = WLAN_STATUS_FAILURE; + break; + } + + if (u4BcnBufLen > (OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + + MAX_IE_LENGTH)) { + /* Unexpected error, buffer overflow. */ + ASSERT(false); + break; + } + } + + pucBuffer = (u8 *)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD); + + kalMemCopy(pucBuffer, pucBcnBuffer, u4BcnBufLen); + + prMsduInfo->fgIs802_11 = true; + prMsduInfo->u2FrameLength = (u16)u4BcnBufLen; + + if (fgSynToFW) { + rWlanStatus = p2pFuncGenerateBeaconProbeRsp( + prAdapter, prP2pBssInfo, prMsduInfo, fgIsProbeRsp); + } + } while (false); + + return rWlanStatus; +} + +u32 wfdFuncCalculateWfdIELenForAssocRsp(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex, + IN P_STA_RECORD_T prStaRec) +{ +#if CFG_SUPPORT_WFD_COMPOSE_IE + u16 u2EstimatedExtraIELen = 0; + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T)NULL; + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T)NULL; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if (prBssInfo->eNetworkType != NETWORK_TYPE_P2P) { + return 0; + } + + prWfdCfgSettings = &(prAdapter->rWifiVar.rWfdConfigureSettings); + + if (IS_STA_P2P_TYPE(prStaRec) && (prWfdCfgSettings->ucWfdEnable > 0)) { + u2EstimatedExtraIELen = prAdapter->prGlueInfo->prP2PInfo[0]->u2WFDIELen; + ASSERT(u2EstimatedExtraIELen < 128); + } + return u2EstimatedExtraIELen; + +#else + return 0; + +#endif +} + +void wfdFuncGenerateWfdIEForAssocRsp(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ +#if CFG_SUPPORT_WFD_COMPOSE_IE + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T)NULL; + P_STA_RECORD_T prStaRec; + u16 u2EstimatedExtraIELen; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + + prWfdCfgSettings = &(prAdapter->rWifiVar.rWfdConfigureSettings); + + do { + ASSERT_BREAK((prMsduInfo != NULL) && (prAdapter != NULL)); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (prStaRec) { + if (IS_STA_P2P_TYPE(prStaRec)) { + if (prWfdCfgSettings->ucWfdEnable > 0) { + u2EstimatedExtraIELen = + prAdapter->prGlueInfo + ->prP2PInfo[prP2pBssInfo->u4PrivateData] + ->u2WFDIELen; + if (u2EstimatedExtraIELen > 0) { + ASSERT(u2EstimatedExtraIELen < 128); + ASSERT( + sizeof(prAdapter->prGlueInfo + ->prP2PInfo[prP2pBssInfo->u4PrivateData] + ->aucWFDIE) >= + prAdapter->prGlueInfo + ->prP2PInfo[prP2pBssInfo->u4PrivateData] + ->u2WFDIELen); + kalMemCopy( + (prMsduInfo->prPacket + prMsduInfo->u2FrameLength), + prAdapter->prGlueInfo + ->prP2PInfo[prP2pBssInfo->u4PrivateData] + ->aucWFDIE, + u2EstimatedExtraIELen); + prMsduInfo->u2FrameLength += u2EstimatedExtraIELen; + } + } + } + } else { + } + } while (false); + + return; + +#else + return; + +#endif +} + +void p2pFuncComposeNoaAttribute(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + OUT u8 *aucNoaAttrArray, OUT u32 *pu4Len) +{ + P_BSS_INFO_T prBssInfo = NULL; + P_P2P_ATTRI_NOA_T prNoaAttr = NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = NULL; + P_NOA_DESCRIPTOR_T prNoaDesc = NULL; + u32 u4NumOfNoaDesc = 0; + u32 i = 0; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + prP2pSpecificBssInfo = + prAdapter->rWifiVar.prP2pSpecificBssInfo[prBssInfo->u4PrivateData]; + + prNoaAttr = (P_P2P_ATTRI_NOA_T)aucNoaAttrArray; + + prNoaAttr->ucId = P2P_ATTRI_ID_NOTICE_OF_ABSENCE; + prNoaAttr->ucIndex = prP2pSpecificBssInfo->ucNoAIndex; + + if (prP2pSpecificBssInfo->fgEnableOppPS) { + prNoaAttr->ucCTWOppPSParam = P2P_CTW_OPPPS_PARAM_OPPPS_FIELD | + (prP2pSpecificBssInfo->u2CTWindow & + P2P_CTW_OPPPS_PARAM_CTWINDOW_MASK); + } else { + prNoaAttr->ucCTWOppPSParam = 0; + } + + for (i = 0; i < prP2pSpecificBssInfo->ucNoATimingCount; i++) { + if (prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse) { + prNoaDesc = + (P_NOA_DESCRIPTOR_T)&prNoaAttr->aucNoADesc[u4NumOfNoaDesc]; + + prNoaDesc->ucCountType = + prP2pSpecificBssInfo->arNoATiming[i].ucCount; + prNoaDesc->u4Duration = + prP2pSpecificBssInfo->arNoATiming[i].u4Duration; + prNoaDesc->u4Interval = + prP2pSpecificBssInfo->arNoATiming[i].u4Interval; + prNoaDesc->u4StartTime = + prP2pSpecificBssInfo->arNoATiming[i].u4StartTime; + + u4NumOfNoaDesc++; + } + } + + /* include "index" + "OppPs Params" + "NOA descriptors" */ + prNoaAttr->u2Length = 2 + u4NumOfNoaDesc * sizeof(NOA_DESCRIPTOR_T); + + /* include "Attribute ID" + "Length" + "index" + "OppPs Params" + "NOA + * descriptors" */ + *pu4Len = P2P_ATTRI_HDR_LEN + prNoaAttr->u2Length; +} + +u32 p2pFuncCalculateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx, + IN P_STA_RECORD_T prStaRec) +{ + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = NULL; + u8 ucIdx; + u32 u4NumOfNoaDesc = 0; + P_BSS_INFO_T prBssInfo; + + prBssInfo = prAdapter->aprBssInfo[ucBssIdx]; + + if (p2pFuncIsAPMode( + prAdapter->rWifiVar.prP2PConnSettings[prBssInfo->u4PrivateData])) { + return 0; + } + + prP2pSpecificBssInfo = + prAdapter->rWifiVar.prP2pSpecificBssInfo[prBssInfo->u4PrivateData]; + + for (ucIdx = 0; ucIdx < prP2pSpecificBssInfo->ucNoATimingCount; ucIdx++) + if (prP2pSpecificBssInfo->arNoATiming[ucIdx].fgIsInUse) { + u4NumOfNoaDesc++; + } + + /* include "index" + "OppPs Params" + "NOA descriptors" */ + /* include "Attribute ID" + "Length" + "index" + "OppPs Params" + "NOA + * descriptors" */ + return P2P_ATTRI_HDR_LEN + 2 + (u4NumOfNoaDesc * sizeof(NOA_DESCRIPTOR_T)); +} + +void p2pFuncGenerateP2P_IE_NoA(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + P_IE_P2P_T prIeP2P; + u8 aucWfaOui[] = VENDOR_OUI_WFA_SPECIFIC; + u32 u4AttributeLen; + P_BSS_INFO_T prBssInfo; + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + + if (p2pFuncIsAPMode( + prAdapter->rWifiVar.prP2PConnSettings[prBssInfo->u4PrivateData])) { + return; + } + + prIeP2P = (P_IE_P2P_T)((unsigned long)prMsduInfo->prPacket + + (u32)prMsduInfo->u2FrameLength); + + prIeP2P->ucId = ELEM_ID_P2P; + prIeP2P->aucOui[0] = aucWfaOui[0]; + prIeP2P->aucOui[1] = aucWfaOui[1]; + prIeP2P->aucOui[2] = aucWfaOui[2]; + prIeP2P->ucOuiType = VENDOR_OUI_TYPE_P2P; + + /* Compose NoA attribute */ + p2pFuncComposeNoaAttribute(prAdapter, prMsduInfo->ucBssIndex, + prIeP2P->aucP2PAttributes, &u4AttributeLen); + + prIeP2P->ucLength = VENDOR_OUI_TYPE_LEN + u4AttributeLen; + + prMsduInfo->u2FrameLength += (ELEM_HDR_LEN + prIeP2P->ucLength); +} + +void p2pFuncClassifyAction(IN P_SW_RFB_T prSwRfb) +{ + P_P2P_PUBLIC_ACTION_FRAME_T pFrame = + (P_P2P_PUBLIC_ACTION_FRAME_T)prSwRfb->pvHeader; + + if ((pFrame->ucCategory == CATEGORY_PUBLIC_ACTION) && + (pFrame->ucAction == ACTION_PUBLIC_WIFI_DIRECT)) { + switch (pFrame->ucOuiSubtype) { + case P2P_PUBLIC_ACTION_GO_NEGO_REQ: + DBGLOG(P2P, WARN, "NEGO Req\n"); + break; + + case P2P_PUBLIC_ACTION_GO_NEGO_RSP: + DBGLOG(P2P, WARN, "NEGO Resp\n"); + break; + + case P2P_PUBLIC_ACTION_GO_NEGO_CFM: + DBGLOG(P2P, WARN, "NEGO Confirm\n"); + break; + + case P2P_PUBLIC_ACTION_INVITATION_REQ: + DBGLOG(P2P, WARN, "Invitation Req\n"); + break; + + case P2P_PUBLIC_ACTION_INVITATION_RSP: + DBGLOG(P2P, WARN, "Invitation Resp\n"); + break; + + case P2P_PUBLIC_ACTION_DEV_DISCOVER_REQ: + DBGLOG(P2P, WARN, "Discovery Req\n"); + break; + + case P2P_PUBLIC_ACTION_DEV_DISCOVER_RSP: + DBGLOG(P2P, WARN, "Discovery Resp\n"); + break; + + case P2P_PUBLIC_ACTION_PROV_DISCOVERY_REQ: + DBGLOG(P2P, WARN, "Provision Req\n"); + break; + + case P2P_PUBLIC_ACTION_PROV_DISCOVERY_RSP: + DBGLOG(P2P, WARN, "Provision Resp\n"); + break; + + default: + DBGLOG(P2P, WARN, "unkown action type %d\n", pFrame->ucOuiSubtype); + break; + } + } +} + +#if CFG_SUPPORT_DBDC_TC6 +void p2pFuncModifyChandef(IN P_ADAPTER_T prAdapter, + IN P_GL_P2P_INFO_T prGlueP2pInfo, + IN P_BSS_INFO_T prBssInfo) +{ + if (!prGlueP2pInfo) { + DBGLOG(P2P, WARN, "p2p glue info is not active\n"); + return; + } + + if (prGlueP2pInfo->chandef == NULL) { + prGlueP2pInfo->chandef = (struct cfg80211_chan_def *)cnmMemAlloc( + prAdapter, RAM_TYPE_BUF, sizeof(struct cfg80211_chan_def)); + prGlueP2pInfo->chandef->chan = (struct ieee80211_channel *)cnmMemAlloc( + prAdapter, RAM_TYPE_BUF, sizeof(struct ieee80211_channel)); + if (!prGlueP2pInfo->chandef->chan) { + DBGLOG(P2P, WARN, "ieee80211_channel alloc fail\n"); + return; + } + /* Fill chan def */ + prGlueP2pInfo->chandef->chan->band = (prBssInfo->eBand == BAND_5G) ? + NL80211_BAND_5GHZ : + NL80211_BAND_2GHZ; + prGlueP2pInfo->chandef->chan->center_freq = + nicChannelNum2Freq(prBssInfo->ucPrimaryChannel) / 1000; + + if (rlmDomainIsLegalDfsChannel(prAdapter, prBssInfo->eBand, + prBssInfo->ucPrimaryChannel)) { + prGlueP2pInfo->chandef->chan->dfs_state = NL80211_DFS_USABLE; + } else { + prGlueP2pInfo->chandef->chan->dfs_state = NL80211_DFS_AVAILABLE; + } + + switch (prBssInfo->ucVhtChannelWidth) { + case VHT_OP_CHANNEL_WIDTH_80P80: + prGlueP2pInfo->chandef->width = NL80211_CHAN_WIDTH_80P80; + prGlueP2pInfo->chandef->center_freq1 = + nicChannelNum2Freq(prBssInfo->ucVhtChannelFrequencyS1) / 1000; + prGlueP2pInfo->chandef->center_freq2 = + nicChannelNum2Freq(prBssInfo->ucVhtChannelFrequencyS2) / 1000; + break; + + case VHT_OP_CHANNEL_WIDTH_160: + prGlueP2pInfo->chandef->width = NL80211_CHAN_WIDTH_160; + prGlueP2pInfo->chandef->center_freq1 = + nicChannelNum2Freq(prBssInfo->ucVhtChannelFrequencyS1) / 1000; + prGlueP2pInfo->chandef->center_freq2 = + nicChannelNum2Freq(prBssInfo->ucVhtChannelFrequencyS2) / 1000; + break; + + case VHT_OP_CHANNEL_WIDTH_80: + prGlueP2pInfo->chandef->width = NL80211_CHAN_WIDTH_80; + prGlueP2pInfo->chandef->center_freq1 = + nicChannelNum2Freq(prBssInfo->ucVhtChannelFrequencyS1) / 1000; + prGlueP2pInfo->chandef->center_freq2 = + nicChannelNum2Freq(prBssInfo->ucVhtChannelFrequencyS2) / 1000; + break; + + case VHT_OP_CHANNEL_WIDTH_20_40: + prGlueP2pInfo->chandef->center_freq1 = + prGlueP2pInfo->chandef->chan->center_freq; + if (prBssInfo->eBssSCO == CHNL_EXT_SCA) { + prGlueP2pInfo->chandef->width = NL80211_CHAN_WIDTH_40; + prGlueP2pInfo->chandef->center_freq1 += 10; + } else if (prBssInfo->eBssSCO == CHNL_EXT_SCB) { + prGlueP2pInfo->chandef->width = NL80211_CHAN_WIDTH_40; + prGlueP2pInfo->chandef->center_freq1 -= 10; + } else { + prGlueP2pInfo->chandef->width = NL80211_CHAN_WIDTH_20; + } + prGlueP2pInfo->chandef->center_freq2 = 0; + break; + + default: + prGlueP2pInfo->chandef->width = NL80211_CHAN_WIDTH_20; + prGlueP2pInfo->chandef->center_freq1 = + prGlueP2pInfo->chandef->chan->center_freq; + prGlueP2pInfo->chandef->center_freq2 = 0; + break; + } + } + return; +} +#else +u8 p2pFuncSwitchSapChannel(IN P_ADAPTER_T prAdapter) +{ + u8 fgDbDcModeEn = false; + u8 fgIsSapDfs = false; + P_BSS_INFO_T prP2pBssInfo = NULL; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = NULL; + u8 ucStaChannelNum = 0; + u8 ucSapChannelNum = 0; + ENUM_BAND_T eStaBand = BAND_NULL; + ENUM_BAND_T eSapBand = BAND_NULL; + u8 fgAisDiscon = false; + + if (!prAdapter || !prAdapter->prAisBssInfo) { + DBGLOG(P2P, WARN, "Not support concurrent STA + SAP\n"); + goto exit; + } + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != + PARAM_MEDIA_STATE_CONNECTED) { + ucStaChannelNum = 0; +#if CFG_SUPPORT_SAP_DFS_CHANNEL + wlanUpdateDfsChannelTable(prAdapter->prGlueInfo, 0); +#endif + } else { + /* Get current channel info */ + ucStaChannelNum = prAdapter->prAisBssInfo->ucPrimaryChannel; + eStaBand = (prAdapter->prAisBssInfo->ucPrimaryChannel <= 14) ? + BAND_2G4 : + BAND_5G; + if (eStaBand != BAND_2G4 && eStaBand != BAND_5G) { + DBGLOG(P2P, WARN, "STA has invalid band\n"); + goto exit; + } +#if CFG_SUPPORT_SAP_DFS_CHANNEL + wlanUpdateDfsChannelTable(prAdapter->prGlueInfo, ucStaChannelNum); +#endif + } + + /* Assume only one sap bss info */ + prP2pBssInfo = cnmGetp2pSapBssInfo(prAdapter); + if (!prP2pBssInfo) { + DBGLOG(P2P, WARN, "SAP is not active\n"); + goto exit; + } + prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pBssInfo->u4PrivateData); + if (!prP2pRoleFsmInfo) { + DBGLOG(P2P, WARN, "SAP is not active\n"); + goto exit; + } + + ucSapChannelNum = prP2pBssInfo->ucPrimaryChannel; + eSapBand = prP2pBssInfo->eBand; + if (eSapBand != BAND_2G4 && eSapBand != BAND_5G) { + DBGLOG(P2P, WARN, "SAP has invalid band\n"); + goto exit; + } + + if (eSapBand == BAND_5G) { + fgIsSapDfs = + rlmDomainIsLegalDfsChannel(prAdapter, eSapBand, ucSapChannelNum); + } + + /* STA is not connected */ + if (ucStaChannelNum == 0) { + if (fgIsSapDfs) { + /* Choose one 5G channel */ + ucStaChannelNum = 36; + eStaBand = BAND_5G; + DBGLOG(P2P, INFO, "[SCC] Choose a channel\n"); + } else { + DBGLOG(P2P, WARN, "STA is not connected\n"); + goto exit; + } + } + +#if CFG_SUPPORT_DBDC + fgDbDcModeEn = prAdapter->rWifiVar.fgDbDcModeEn; +#endif + + /* Check channel no */ + if (ucStaChannelNum == ucSapChannelNum) { + /* Do nothing, i.e. SCC */ + DBGLOG(P2P, STATE, "[SCC] Keep StaCH(%d)\n", ucStaChannelNum); + goto exit; + } else if (fgDbDcModeEn == true && (eStaBand != eSapBand) && !fgIsSapDfs) { + /* Do nothing, i.e. DBDC */ + DBGLOG(P2P, STATE, "[DBDC] Keep StaCH(%d), SapCH(%d)(dfs: %u)\n", + ucStaChannelNum, ucSapChannelNum, fgIsSapDfs); + goto exit; + } else { + /* Otherwise, switch to STA channel, i.e. SCC */ + + RF_CHANNEL_INFO_T rRfChnlInfo; + + /* Use sta ch info to do sap ch switch */ + rRfChnlInfo.ucChannelNum = ucStaChannelNum; + rRfChnlInfo.eBand = eStaBand; + rRfChnlInfo.ucChnlBw = rlmGetBssOpBwByVhtAndHtOpInfo(prP2pBssInfo); + + /* Delay report disconnect event to NL80211 */ + if (eStaBand == BAND_5G) { + prAdapter->rWifiVar.fgDelayInidicateDISCON = true; + } else { + prAdapter->rWifiVar.fgDelayInidicateDISCON = false; + } + + /* Disconnect the AIS link */ + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED) { + DBGLOG(AIS, STATE, "Trigger aisBssLinkDown\n"); + aisBssLinkDown(prAdapter); + fgAisDiscon = true; + } + + DBGLOG(P2P, STATE, + "[SCC] StaCH(%d), SapCH(%d), eBand(%d), ChnlBw(%d) (dfs: %u)\n", + ucStaChannelNum, ucSapChannelNum, rRfChnlInfo.eBand, + rRfChnlInfo.ucChnlBw, fgIsSapDfs); + + if (eStaBand == BAND_5G) { + cnmSapChannelSwitchReq(prAdapter, &rRfChnlInfo, + prP2pBssInfo->u4PrivateData); + } + } + +exit: + + DBGLOG(P2P, TRACE, "Check done\n"); + return fgAisDiscon; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_ie.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_ie.c new file mode 100644 index 00000000000000..75c0f1517b608a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_ie.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ +#include "precomp.h" + +u32 p2pCalculate_IEForAssocReq(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN P_STA_RECORD_T prStaRec) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = + (P_P2P_CONNECTION_REQ_INFO_T)NULL; + u32 u4RetValue = 0; + + do { + ASSERT_BREAK((prStaRec != NULL) && (prAdapter != NULL)); + + prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO( + prAdapter, (u8)prP2pBssInfo->u4PrivateData); + + prConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo); + + u4RetValue = prConnReqInfo->u4BufLength; + + /* ADD WMM Information Element */ + u4RetValue += (ELEM_HDR_LEN + ELEM_MAX_LEN_WMM_INFO); + + /* ADD HT Capability */ + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11N) && + (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { + u4RetValue += (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP); + } +#if CFG_SUPPORT_802_11AC + /* ADD VHT Capability */ + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11AC) && + (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11AC)) { + u4RetValue += (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_CAP); + } +#endif + +#if CFG_SUPPORT_MTK_SYNERGY + if (prAdapter->rWifiVar.ucMtkOui == FEATURE_ENABLED) { + u4RetValue += (ELEM_HDR_LEN + ELEM_MIN_LEN_MTK_OUI); + } +#endif + } while (false); + + return u4RetValue; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to generate P2P IE for Beacon frame. + * + * @param[in] prMsduInfo Pointer to the composed MSDU_INFO_T. + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void p2pGenerate_IEForAssocReq(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = + (P_P2P_CONNECTION_REQ_INFO_T)NULL; + u8 *pucIEBuf = (u8 *)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, + prMsduInfo->ucBssIndex); + + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO( + prAdapter, (u8)prBssInfo->u4PrivateData); + + prConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo); + + pucIEBuf = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + + kalMemCopy(pucIEBuf, prConnReqInfo->aucIEBuf, + prConnReqInfo->u4BufLength); + + prMsduInfo->u2FrameLength += prConnReqInfo->u4BufLength; + + /* Add WMM IE */ + mqmGenerateWmmInfoIE(prAdapter, prMsduInfo); + + /* Add HT IE */ + rlmReqGenerateHtCapIE(prAdapter, prMsduInfo); + +#if CFG_SUPPORT_802_11AC + /* Add VHT IE */ + rlmReqGenerateVhtCapIE(prAdapter, prMsduInfo); + rlmReqGenerateVhtOpNotificationIE(prAdapter, prMsduInfo); +#endif + +#if CFG_SUPPORT_MTK_SYNERGY + rlmGenerateMTKOuiIE(prAdapter, prMsduInfo); +#endif + } while (false); + + return; +} + +u32 wfdFuncAppendAttriDevInfo(IN P_ADAPTER_T prAdapter, IN u8 fgIsAssocFrame, + IN u16 *pu2Offset, IN u8 *pucBuf, + IN u16 u2BufSize) +{ + u32 u4AttriLen = 0; + u8 *pucBuffer = NULL; + P_WFD_DEVICE_INFORMATION_IE_T prWfdDevInfo = + (P_WFD_DEVICE_INFORMATION_IE_T)NULL; + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL) && + (pu2Offset != NULL)); + + prWfdCfgSettings = &(prAdapter->rWifiVar.rWfdConfigureSettings); + + ASSERT_BREAK((prWfdCfgSettings != NULL)); + + if ((prWfdCfgSettings->ucWfdEnable == 0) || + ((prWfdCfgSettings->u4WfdFlag & WFD_FLAGS_DEV_INFO_VALID) == + 0)) { + break; + } + + pucBuffer = (u8 *)((unsigned long)pucBuf + + (unsigned long)(*pu2Offset)); + + ASSERT_BREAK(pucBuffer != NULL); + + prWfdDevInfo = (P_WFD_DEVICE_INFORMATION_IE_T)pucBuffer; + + prWfdDevInfo->ucElemID = WFD_ATTRI_ID_DEV_INFO; + + WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2WfdDevInfo, + prWfdCfgSettings->u2WfdDevInfo); + + WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2SessionMgmtCtrlPort, + prWfdCfgSettings->u2WfdControlPort); + + WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2WfdDevMaxSpeed, + prWfdCfgSettings->u2WfdMaximumTp); + + WLAN_SET_FIELD_BE16(&prWfdDevInfo->u2Length, + WFD_ATTRI_MAX_LEN_DEV_INFO); + + u4AttriLen = WFD_ATTRI_MAX_LEN_DEV_INFO + WFD_ATTRI_HDR_LEN; + } while (false); + + (*pu2Offset) += (u16)u4AttriLen; + + return u4AttriLen; +} + +/* wfdFuncAppendAttriDevInfo */ diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_rlm.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_rlm.c new file mode 100644 index 00000000000000..b4fc188cf7020b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_rlm.c @@ -0,0 +1,840 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "p2p_rlm.c" + * \brief + * + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#include "rlm.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Init AP Bss + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmBssInitForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + u8 i; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + + if (prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) { + return; + } + + /* Operation band, channel shall be ready before invoking this function. + * Bandwidth may be ready if other network is connected + */ + prBssInfo->fg40mBwAllowed = false; + prBssInfo->fgAssoc40mBwAllowed = false; + prBssInfo->eBssSCO = CHNL_EXT_SCN; + + /* Check if AP can set its bw to 40MHz + * But if any of BSS is setup in 40MHz, the second BSS would prefer to + * use 20MHz in order to remain in SCC case + */ + if (cnmBss40mBwPermitted(prAdapter, prBssInfo->ucBssIndex)) { + prBssInfo->eBssSCO = rlmGetScoForAP(prAdapter, prBssInfo); + + if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { + prBssInfo->fg40mBwAllowed = true; + prBssInfo->fgAssoc40mBwAllowed = true; + + prBssInfo->ucHtOpInfo1 = + (u8)(((u32)prBssInfo->eBssSCO) | + HT_OP_INFO1_STA_CHNL_WIDTH); + + rlmUpdateBwByChListForAP(prAdapter, prBssInfo); + } + } + + /* Filled the VHT BW/S1/S2 and MCS rate set */ + if (prBssInfo->ucPhyTypeSet & PHY_TYPE_BIT_VHT) { + for (i = 0; i < 8; i++) + prBssInfo->u2VhtBasicMcsSet |= BITS(2 * i, (2 * i + 1)); + prBssInfo->u2VhtBasicMcsSet &= (VHT_CAP_INFO_MCS_MAP_MCS9 + << VHT_CAP_INFO_MCS_1SS_OFFSET); + + prBssInfo->ucVhtChannelWidth = cnmGetBssMaxBwToChnlBW( + prAdapter, prBssInfo->ucBssIndex); + if (prBssInfo->ucVhtChannelWidth == + VHT_OP_CHANNEL_WIDTH_80P80) { + /* TODO: BW80+80 support */ + DBGLOG(RLM, + WARN, + "BW80+80 not support. Fallback to VHT_OP_CHANNEL_WIDTH_20_40\n"); + prBssInfo->ucVhtChannelWidth = + VHT_OP_CHANNEL_WIDTH_20_40; + prBssInfo->ucVhtChannelFrequencyS1 = 0; + prBssInfo->ucVhtChannelFrequencyS2 = 0; + } else { + prBssInfo->ucVhtChannelFrequencyS1 = + rlmGetVhtS1ForAP(prAdapter, prBssInfo); + prBssInfo->ucVhtChannelFrequencyS2 = 0; + } + + /* If the S1 is invalid, force to change bandwidth */ + if (prBssInfo->ucVhtChannelFrequencyS1 == 0) { + prBssInfo->ucVhtChannelWidth = + VHT_OP_CHANNEL_WIDTH_20_40; + } + } else { + prBssInfo->ucVhtChannelWidth = VHT_OP_CHANNEL_WIDTH_20_40; + prBssInfo->ucVhtChannelFrequencyS1 = 0; + prBssInfo->ucVhtChannelFrequencyS2 = 0; + } + + /*ERROR HANDLE*/ + if ((prBssInfo->ucVhtChannelWidth == VHT_OP_CHANNEL_WIDTH_80) || + (prBssInfo->ucVhtChannelWidth == VHT_OP_CHANNEL_WIDTH_160) || + (prBssInfo->ucVhtChannelWidth == VHT_OP_CHANNEL_WIDTH_80P80)) { + if (prBssInfo->ucVhtChannelFrequencyS1 == 0) { + DBGLOG(RLM, + INFO, + "Wrong AP S1 parameter setting, back to BW20!!!\n"); + + prBssInfo->ucVhtChannelWidth = + VHT_OP_CHANNEL_WIDTH_20_40; + prBssInfo->ucVhtChannelFrequencyS1 = 0; + prBssInfo->ucVhtChannelFrequencyS2 = 0; + } + } + + DBGLOG(RLM, INFO, "WLAN AP SCO=%d BW=%d S1=%d S2=%d CH=%d Band=%d\n", + prBssInfo->eBssSCO, prBssInfo->ucVhtChannelWidth, + prBssInfo->ucVhtChannelFrequencyS1, + prBssInfo->ucVhtChannelFrequencyS2, prBssInfo->ucPrimaryChannel, + prBssInfo->eBand); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief For probe response (GO, IBSS) and association response + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmRspGenerateObssScanIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_IE_OBSS_SCAN_PARAM_T prObssScanIe; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + if (!prBssInfo) { + return; + } + + if (!IS_BSS_ACTIVE(prBssInfo)) { + return; + } + + if (RLM_NET_IS_11N(prBssInfo) && /* !RLM_NET_IS_BOW(prBssInfo) && FIXME. + */ + prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) && + prBssInfo->eBand == BAND_2G4 && + prBssInfo->eBssSCO != CHNL_EXT_SCN) { + prObssScanIe = + (P_IE_OBSS_SCAN_PARAM_T)(((u8 *)prMsduInfo->prPacket) + + prMsduInfo->u2FrameLength); + + /* Add 20/40 BSS coexistence IE */ + prObssScanIe->ucId = ELEM_ID_OBSS_SCAN_PARAMS; + prObssScanIe->ucLength = + sizeof(IE_OBSS_SCAN_PARAM_T) - ELEM_HDR_LEN; + + prObssScanIe->u2ScanPassiveDwell = dot11OBSSScanPassiveDwell; + prObssScanIe->u2ScanActiveDwell = dot11OBSSScanActiveDwell; + prObssScanIe->u2TriggerScanInterval = + dot11BSSWidthTriggerScanInterval; + prObssScanIe->u2ScanPassiveTotalPerChnl = + dot11OBSSScanPassiveTotalPerChannel; + prObssScanIe->u2ScanActiveTotalPerChnl = + dot11OBSSScanActiveTotalPerChannel; + prObssScanIe->u2WidthTransDelayFactor = + dot11BSSWidthChannelTransitionDelayFactor; + prObssScanIe->u2ScanActivityThres = + dot11OBSSScanActivityThreshold; + + ASSERT(IE_SIZE(prObssScanIe) <= + (ELEM_HDR_LEN + ELEM_MAX_LEN_OBSS_SCAN)); + + prMsduInfo->u2FrameLength += IE_SIZE(prObssScanIe); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief P2P GO. + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u8 rlmUpdateBwByChListForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + u8 ucLevel; + u8 fgBwChange; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + + fgBwChange = false; + + if (prBssInfo->eBssSCO == CHNL_EXT_SCN) { + return fgBwChange; + } + + ucLevel = rlmObssChnlLevel(prBssInfo, prBssInfo->eBand, + prBssInfo->ucPrimaryChannel, + prBssInfo->eBssSCO); + + if (ucLevel == CHNL_LEVEL0) { + /* Forced to 20MHz, so extended channel is SCN and STA width is + * zero */ + prBssInfo->fgObssActionForcedTo20M = true; + + if (prBssInfo->ucHtOpInfo1 != (u8)CHNL_EXT_SCN) { + prBssInfo->ucHtOpInfo1 = (u8)CHNL_EXT_SCN; + fgBwChange = true; + } + + cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, + OBSS_20_40M_TIMEOUT * MSEC_PER_SEC); + } + + /* Clear up all channel lists */ + prBssInfo->auc2G_20mReqChnlList[0] = 0; + prBssInfo->auc2G_NonHtChnlList[0] = 0; + prBssInfo->auc2G_PriChnlList[0] = 0; + prBssInfo->auc2G_SecChnlList[0] = 0; + prBssInfo->auc5G_20mReqChnlList[0] = 0; + prBssInfo->auc5G_NonHtChnlList[0] = 0; + prBssInfo->auc5G_PriChnlList[0] = 0; + prBssInfo->auc5G_SecChnlList[0] = 0; + + return fgBwChange; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmProcessPublicAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) +{ + P_ACTION_20_40_COEXIST_FRAME prRxFrame; + P_IE_20_40_COEXIST_T prCoexist; + P_IE_INTOLERANT_CHNL_REPORT_T prChnlReport; + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + u8 *pucIE; + u16 u2IELength, u2Offset; + u8 i, j; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxFrame = (P_ACTION_20_40_COEXIST_FRAME)prSwRfb->pvHeader; + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (!(prSwRfb->prStaRec)) { + DBGLOG(P2P, INFO, "prSwRfb->prStaRec is null.\n"); + return; + } + + if (prRxFrame->ucAction != ACTION_PUBLIC_20_40_COEXIST || !prStaRec || + prStaRec->ucStaState != STA_STATE_3 || + prSwRfb->u2PacketLen < (WLAN_MAC_MGMT_HEADER_LEN + 5) || + prSwRfb->prStaRec->ucBssIndex != + /* HIF_RX_HDR_GET_NETWORK_IDX(prSwRfb->prHifRxHdr) != */ + prStaRec->ucBssIndex) { + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + ASSERT(prBssInfo); + + if (!IS_BSS_ACTIVE(prBssInfo) || + prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT || + prBssInfo->eBssSCO == CHNL_EXT_SCN) { + return; + } + + prCoexist = &prRxFrame->rBssCoexist; + if (prCoexist->ucData & + (BSS_COEXIST_40M_INTOLERANT | BSS_COEXIST_20M_REQ)) { + ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && + i <= CHNL_LIST_SZ_2G; + i++) { + if (prBssInfo->auc2G_20mReqChnlList[i] == + prBssInfo->ucPrimaryChannel) { + break; + } + } + if ((i > prBssInfo->auc2G_20mReqChnlList[0]) && + (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_20mReqChnlList[i] = + prBssInfo->ucPrimaryChannel; + prBssInfo->auc2G_20mReqChnlList[0]++; + } + } + + /* Process intolerant channel report IE */ + pucIE = (u8 *)&prRxFrame->rChnlReport; + u2IELength = prSwRfb->u2PacketLen - (WLAN_MAC_MGMT_HEADER_LEN + 5); + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_20_40_INTOLERANT_CHNL_REPORT: + prChnlReport = (P_IE_INTOLERANT_CHNL_REPORT_T)pucIE; + + if (prChnlReport->ucLength <= 1) { + break; + } + + /* To do: process regulatory class. Now we assume 2.4G + * band */ + + for (j = 0; j < prChnlReport->ucLength - 1; j++) { + /* Update non-HT channel list */ + ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= + CHNL_LIST_SZ_2G); + for (i = 1; + i <= prBssInfo->auc2G_NonHtChnlList[0] && + i <= CHNL_LIST_SZ_2G; + i++) { + if (prBssInfo->auc2G_NonHtChnlList[i] == + prChnlReport->aucChannelList[j]) { + break; + } + } + if ((i > prBssInfo->auc2G_NonHtChnlList[0]) && + (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_NonHtChnlList[i] = + prChnlReport->aucChannelList[j]; + prBssInfo->auc2G_NonHtChnlList[0]++; + } + } + break; + + default: + break; + } + } /* end of IE_FOR_EACH */ + + if (rlmUpdateBwByChListForAP(prAdapter, prBssInfo)) { + bssUpdateBeaconContent(prAdapter, prBssInfo->ucBssIndex); + rlmSyncOperationParams(prAdapter, prBssInfo); + } + + /* Check if OBSS scan exemption response should be sent */ + if (prCoexist->ucData & BSS_COEXIST_OBSS_SCAN_EXEMPTION_REQ) { + rlmObssScanExemptionRsp(prAdapter, prBssInfo, prSwRfb); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmHandleObssStatusEventPkt(P_ADAPTER_T prAdapter, + P_EVENT_AP_OBSS_STATUS_T prObssStatus) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prObssStatus); + // ASSERT(prObssStatus->ucBssIndex < MAX_BSS_INDEX); + if (prObssStatus->ucBssIndex >= MAX_BSS_INDEX) { + DBGLOG(RLM, + ERROR, + "rlmHandleObssStatusEventPkt: (ucBssIndex = %d) out-of-bound\n", + prObssStatus->ucBssIndex); + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prObssStatus->ucBssIndex); + + if (prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) { + return; + } + + prBssInfo->fgObssErpProtectMode = + (u8)prObssStatus->ucObssErpProtectMode; + prBssInfo->eObssHtProtectMode = + (ENUM_HT_PROTECT_MODE_T)prObssStatus->ucObssHtProtectMode; + prBssInfo->eObssGfOperationMode = + (ENUM_GF_MODE_T)prObssStatus->ucObssGfOperationMode; + prBssInfo->fgObssRifsOperationMode = + (u8)prObssStatus->ucObssRifsOperationMode; + prBssInfo->fgObssBeaconForcedTo20M = + (u8)prObssStatus->ucObssBeaconForcedTo20M; + + /* Check if Beacon content need to be updated */ + rlmUpdateParamsForAP(prAdapter, prBssInfo, true); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief It is only for AP mode in NETWORK_TYPE_P2P_INDEX. + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmUpdateParamsForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + u8 fgUpdateBeacon) +{ + P_LINK_T prStaList; + P_STA_RECORD_T prStaRec; + u8 fgErpProtectMode, fgSta40mIntolerant; + u8 fgUseShortPreamble, fgUseShortSlotTime; + ENUM_HT_PROTECT_MODE_T eHtProtectMode; + ENUM_GF_MODE_T eGfOperationMode; + u8 ucHtOpInfo1; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + + if (!IS_BSS_ACTIVE(prBssInfo) || + prBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) { + return; + } + + fgErpProtectMode = false; + eHtProtectMode = HT_PROTECT_MODE_NONE; + eGfOperationMode = GF_MODE_NORMAL; + fgSta40mIntolerant = false; + fgUseShortPreamble = prBssInfo->fgIsShortPreambleAllowed; + fgUseShortSlotTime = true; + ucHtOpInfo1 = (u8)CHNL_EXT_SCN; + + prStaList = &prBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH_ENTRY(prStaRec, prStaList, rLinkEntry, STA_RECORD_T) { + if (!prStaRec) { + DBGLOG(P2P, WARN, + "NULL STA_REC ptr in BSS client list\n"); + bssDumpClientList(prAdapter, prBssInfo); + break; + } + + if (prStaRec->fgIsInUse && + prStaRec->ucStaState == STA_STATE_3 && + prStaRec->ucBssIndex == prBssInfo->ucBssIndex) { + if (!(prStaRec->ucPhyTypeSet & + (PHY_TYPE_SET_802_11GN | PHY_TYPE_SET_802_11A))) { + /* B-only mode, so mode 1 (ERP protection) */ + fgErpProtectMode = true; + } + + if (!(prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { + /* BG-only or A-only */ + eHtProtectMode = HT_PROTECT_MODE_NON_HT; + } else if (prBssInfo->fg40mBwAllowed && + !(prStaRec->u2HtCapInfo & + HT_CAP_INFO_SUP_CHNL_WIDTH)) { + /* 20MHz-only */ + if (eHtProtectMode == HT_PROTECT_MODE_NONE) { + eHtProtectMode = HT_PROTECT_MODE_20M; + } + } + + if (!(prStaRec->u2HtCapInfo & HT_CAP_INFO_HT_GF)) { + eGfOperationMode = GF_MODE_PROTECT; + } + + if (!(prStaRec->u2CapInfo & CAP_INFO_SHORT_PREAMBLE)) { + fgUseShortPreamble = false; + } + + /*ap mode throughput enhancement + * only 2.4G with B mode client connecion use long slot + * time + */ + if ((!(prStaRec->u2CapInfo & + CAP_INFO_SHORT_SLOT_TIME)) && + fgErpProtectMode && prBssInfo->eBand == BAND_2G4) { + fgUseShortSlotTime = false; + } + + if (prStaRec->u2HtCapInfo & HT_CAP_INFO_40M_INTOLERANT) { + fgSta40mIntolerant = true; + } + } + } /* end of LINK_FOR_EACH_ENTRY */ + + /* Check if HT operation IE about 20/40M bandwidth shall be updated */ + if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { + if ( /*!LINK_IS_EMPTY(prStaList) && */ !fgSta40mIntolerant && + !prBssInfo->fgObssActionForcedTo20M && + !prBssInfo->fgObssBeaconForcedTo20M) { + ucHtOpInfo1 = (u8)(((u32)prBssInfo->eBssSCO) | + HT_OP_INFO1_STA_CHNL_WIDTH); + } + } + + /* Check if any new parameter may be updated */ + if (prBssInfo->fgErpProtectMode != fgErpProtectMode || + prBssInfo->eHtProtectMode != eHtProtectMode || + prBssInfo->eGfOperationMode != eGfOperationMode || + prBssInfo->ucHtOpInfo1 != ucHtOpInfo1 || + prBssInfo->fgUseShortPreamble != fgUseShortPreamble || + prBssInfo->fgUseShortSlotTime != fgUseShortSlotTime) { + prBssInfo->fgErpProtectMode = fgErpProtectMode; + prBssInfo->eHtProtectMode = eHtProtectMode; + prBssInfo->eGfOperationMode = eGfOperationMode; + prBssInfo->ucHtOpInfo1 = ucHtOpInfo1; + prBssInfo->fgUseShortPreamble = fgUseShortPreamble; + prBssInfo->fgUseShortSlotTime = fgUseShortSlotTime; + + if (fgUseShortSlotTime) { + prBssInfo->u2CapInfo |= CAP_INFO_SHORT_SLOT_TIME; + }else{ + prBssInfo->u2CapInfo &= ~CAP_INFO_SHORT_SLOT_TIME; + } + + rlmSyncOperationParams(prAdapter, prBssInfo); + fgUpdateBeacon = true; + } + + /* Update Beacon content if related IE content is changed */ + if (fgUpdateBeacon) { + bssUpdateBeaconContent(prAdapter, prBssInfo->ucBssIndex); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +ENUM_CHNL_EXT_T rlmDecideScoForAP(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo) +{ + P_DOMAIN_SUBBAND_INFO prSubband; + P_DOMAIN_INFO_ENTRY prDomainInfo; + u8 ucSecondChannel, i, j; + ENUM_CHNL_EXT_T eSCO; + ENUM_CHNL_EXT_T eTempSCO; + u8 ucMaxBandwidth = MAX_BW_80_80_MHZ; /*chip capability*/ + + eSCO = CHNL_EXT_SCN; + eTempSCO = CHNL_EXT_SCN; + + if (prBssInfo->eBand == BAND_2G4) { + if (prBssInfo->ucPrimaryChannel != 14) { + eSCO = (prBssInfo->ucPrimaryChannel > 7) ? + CHNL_EXT_SCB : + CHNL_EXT_SCA; + } + } else { + if (regd_is_single_sku_en()) { + if (rlmDomainIsLegalChannel( + prAdapter, prBssInfo->eBand, + prBssInfo->ucPrimaryChannel)) { + eSCO = rlmSelectSecondaryChannelType( + prAdapter, prBssInfo->eBand, + prBssInfo->ucPrimaryChannel); + } + } else { + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubband = &prDomainInfo->rSubBand[i]; + if (prSubband->ucBand == prBssInfo->eBand) { + for (j = 0; + j < prSubband->ucNumChannels; + j++) { + if ((prSubband-> + ucFirstChannelNum + + j * + prSubband->ucChannelSpan) + == + prBssInfo->ucPrimaryChannel) { + eSCO = (j & 1) ? + CHNL_EXT_SCB : + CHNL_EXT_SCA; + break; + } + } + + if (j < prSubband->ucNumChannels) { + break; /* Found */ + } + } + } + } + } + + /* Check if it is boundary channel and 40MHz BW is permitted */ + if (eSCO != CHNL_EXT_SCN) { + ucSecondChannel = + (eSCO == CHNL_EXT_SCA) ? + (prBssInfo->ucPrimaryChannel + CHNL_SPAN_20) : + (prBssInfo->ucPrimaryChannel - CHNL_SPAN_20); + + if (!rlmDomainIsLegalChannel(prAdapter, prBssInfo->eBand, + ucSecondChannel)) { + eSCO = CHNL_EXT_SCN; + } + } + + /* Overwrite SCO settings by wifi cfg */ + if (IS_BSS_P2P(prBssInfo)) { + /* AP mode */ + if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2PConnSettings + [prBssInfo->u4PrivateData])) { + if (prAdapter->rWifiVar.ucApSco == CHNL_EXT_SCA || + prAdapter->rWifiVar.ucApSco == CHNL_EXT_SCB) { + eTempSCO = (ENUM_CHNL_EXT_T) + prAdapter->rWifiVar.ucApSco; + } + } + /* P2P mode */ + else { + if (prAdapter->rWifiVar.ucP2pGoSco == CHNL_EXT_SCA || + prAdapter->rWifiVar.ucP2pGoSco == CHNL_EXT_SCB) { + eTempSCO = + (ENUM_CHNL_EXT_T) + prAdapter->rWifiVar.ucP2pGoSco; + } + } + + /* Check again if it is boundary channel and 40MHz BW is + * permitted */ + if (eTempSCO != CHNL_EXT_SCN) { + ucSecondChannel = + (eTempSCO == CHNL_EXT_SCA) ? + (prBssInfo->ucPrimaryChannel + 4) : + (prBssInfo->ucPrimaryChannel - 4); + if (rlmDomainIsLegalChannel(prAdapter, prBssInfo->eBand, + ucSecondChannel)) { + eSCO = eTempSCO; + } + } + } + + /* Overwrite SCO settings by wifi cfg bandwidth setting */ + if (IS_BSS_P2P(prBssInfo)) { + /* AP mode */ + if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2PConnSettings + [prBssInfo->u4PrivateData])) { + if (prBssInfo->eBand == BAND_2G4) { + ucMaxBandwidth = + prAdapter->rWifiVar.ucAp2gBandwidth; + } else { + ucMaxBandwidth = + prAdapter->rWifiVar.ucAp5gBandwidth; + } + } + /* P2P mode */ + else { + if (prBssInfo->eBand == BAND_2G4) { + ucMaxBandwidth = + prAdapter->rWifiVar.ucP2p2gBandwidth; + } else { + ucMaxBandwidth = + prAdapter->rWifiVar.ucP2p5gBandwidth; + } + } + + if (ucMaxBandwidth < MAX_BW_40MHZ) { + eSCO = CHNL_EXT_SCN; + } + } + + return eSCO; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief: Get AP secondary channel offset from cfg80211 or wifi.cfg + * + * \param[in] prAdapter Pointer of ADAPTER_T, prBssInfo Pointer of BSS_INFO_T, + * + * \return ENUM_CHNL_EXT_T AP secondary channel offset + */ +/*----------------------------------------------------------------------------*/ +ENUM_CHNL_EXT_T rlmGetScoForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + ENUM_BAND_T eBand; + u8 ucChannel; + ENUM_CHNL_EXT_T eSCO; + s32 i4DeltaBw; + u32 u4AndOneSCO; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo = + (P_P2P_CONNECTION_REQ_INFO_T)NULL; + + prP2pRoleFsmInfo = + p2pFuncGetRoleByBssIdx(prAdapter, prBssInfo->ucBssIndex); + + if (!prAdapter->rWifiVar.ucApChnlDefFromCfg && prP2pRoleFsmInfo) { + prP2pConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo); + eSCO = CHNL_EXT_SCN; + if (cnmGetBssMaxBw(prAdapter, prBssInfo->ucBssIndex) == + MAX_BW_40MHZ) { + /* If BW 40, compare S0 and primary channel freq */ + if (prP2pConnReqInfo->u4CenterFreq1 > + prP2pConnReqInfo->u2PriChnlFreq) { + eSCO = CHNL_EXT_SCA; + }else{ + eSCO = CHNL_EXT_SCB; + } + } else if (cnmGetBssMaxBw(prAdapter, prBssInfo->ucBssIndex) > + MAX_BW_40MHZ) { + /* P: PriChnlFreq, A:CHNL_EXT_SCA, B: CHNL_EXT_SCB, -:BW + * SPAN 5M */ + /* --|----|--CenterFreq1--|----|-- */ + /* --|----|--CenterFreq1--B----P-- */ + /* --|----|--CenterFreq1--P----A-- */ + i4DeltaBw = prP2pConnReqInfo->u2PriChnlFreq - + prP2pConnReqInfo->u4CenterFreq1; + u4AndOneSCO = CHNL_EXT_SCB; + eSCO = CHNL_EXT_SCA; + if (i4DeltaBw < 0) { + /* --|----|--CenterFreq1--|----|-- */ + /* --P----A--CenterFreq1--|----|-- */ + /* --B----P--CenterFreq1--|----|-- */ + u4AndOneSCO = CHNL_EXT_SCA; + eSCO = CHNL_EXT_SCB; + i4DeltaBw = -i4DeltaBw; + } + i4DeltaBw = i4DeltaBw - (CHANNEL_SPAN_20 >> 1); + if ((i4DeltaBw / CHANNEL_SPAN_20) & 1) { + eSCO = u4AndOneSCO; + } + } + } else { + /* In this case, the first BSS's SCO is 40MHz and known, so AP + * can apply 40MHz bandwidth, but the first BSS's SCO may be + * changed later if its Beacon lost timeout occurs + */ + if (!(cnmPreferredChannel(prAdapter, &eBand, &ucChannel, + &eSCO) && + eSCO != CHNL_EXT_SCN && + ucChannel == prBssInfo->ucPrimaryChannel && + eBand == prBssInfo->eBand)) { + eSCO = rlmDecideScoForAP(prAdapter, prBssInfo); + } + } + return eSCO; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief: Get AP channel number of Channel Center Frequency Segment 0 from + * cfg80211 or wifi.cfg + * + * \param[in] prAdapter Pointer of ADAPTER_T, prBssInfo Pointer of BSS_INFO_T, + * + * \return u8 AP channel number of Channel Center Frequency Segment 0 + */ +/*----------------------------------------------------------------------------*/ +u8 rlmGetVhtS1ForAP(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + u32 ucFreq1Channel; + u8 ucPrimaryChannel = prBssInfo->ucPrimaryChannel; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo = + (P_P2P_CONNECTION_REQ_INFO_T)NULL; + + prP2pRoleFsmInfo = + p2pFuncGetRoleByBssIdx(prAdapter, prBssInfo->ucBssIndex); + + if (prBssInfo->ucVhtChannelWidth == VHT_OP_CHANNEL_WIDTH_20_40) { + return 0; + } + + if (!prAdapter->rWifiVar.ucApChnlDefFromCfg && prP2pRoleFsmInfo) { + prP2pConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo); + ucFreq1Channel = nicFreq2ChannelNum( + prP2pConnReqInfo->u4CenterFreq1 * 1000); + } else { + ucFreq1Channel = nicGetVhtS1(ucPrimaryChannel, + prBssInfo->ucVhtChannelWidth); + } + + return ucFreq1Channel; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_rlm_obss.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_rlm_obss.c new file mode 100644 index 00000000000000..ca57b8e730485c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_rlm_obss.c @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_p2p_cfg80211.c + * \brief Main routines of Linux driver interface for Wi-Fi Direct + * using cfg80211 interface + * + * This file contains the main routines of Linux driver for MediaTek Inc. + * 802.11 Wireless LAN Adapters. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#include "precomp.h" + +static u8 rlmObssChnlLevelIn2G4(P_BSS_INFO_T prBssInfo, + u8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend); + +static u8 rlmObssChnlLevelIn5G(P_BSS_INFO_T prBssInfo, + u8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend); + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Different concurrent network has itself channel lists, and + * concurrent networks should have been recorded in channel lists. + * If role of active P2P is GO, assume associated AP of AIS will + * record our Beacon for P2P GO because of same channel. + * + * Note: If we have scenario of different channel in the future, + * the internal FW communication channel shall be established. + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u8 rlmObssChnlLevel(P_BSS_INFO_T prBssInfo, ENUM_BAND_T eBand, u8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend) +{ + u8 ucChannelLevel; + + ASSERT(prBssInfo); + + if (eBand == BAND_2G4) { + ucChannelLevel = + rlmObssChnlLevelIn2G4(prBssInfo, ucPriChannel, eExtend); + + /* (TBD) If concurrent networks permit different channel, extra + * channel judgement should be added. Please refer to + * previous version of this file. + */ + } else if (eBand == BAND_5G) { + ucChannelLevel = + rlmObssChnlLevelIn5G(prBssInfo, ucPriChannel, eExtend); + + /* (TBD) If concurrent networks permit different channel, extra + * channel judgement should be added. Please refer to + * previous version of this file. + */ + } else { + ucChannelLevel = CHNL_LEVEL0; + } + + return ucChannelLevel; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static u8 rlmObssChnlLevelIn2G4(P_BSS_INFO_T prBssInfo, u8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend) +{ + u8 i, ucChannelLevel; + u8 ucSecChannel, ucCenterChannel; + u8 ucAffectedChnl_L, ucAffectedChnl_H; + + ASSERT(prBssInfo); + + ucChannelLevel = CHNL_LEVEL2; + + /* Calculate center channel for 2.4G band */ + if (eExtend == CHNL_EXT_SCA) { + ucCenterChannel = ucPriChannel + 2; + ucSecChannel = ucPriChannel + 4; + } else if (eExtend == CHNL_EXT_SCB) { + ucCenterChannel = ucPriChannel - 2; + ucSecChannel = ucPriChannel - 4; + } else { + return CHNL_LEVEL0; + } + ASSERT(ucCenterChannel >= 1 && ucCenterChannel <= 14); + + /* Calculated low/upper channels in affected freq range */ + ucAffectedChnl_L = (ucCenterChannel <= AFFECTED_CHNL_OFFSET) ? + 1 : + (ucCenterChannel - AFFECTED_CHNL_OFFSET); + + ucAffectedChnl_H = (ucCenterChannel >= (14 - AFFECTED_CHNL_OFFSET)) ? + 14 : + (ucCenterChannel + AFFECTED_CHNL_OFFSET); + + /* Check intolerant (Non-HT) channel list */ + ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; + i <= prBssInfo->auc2G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_2G; + i++) { + if ((prBssInfo->auc2G_NonHtChnlList[i] >= ucAffectedChnl_L && + prBssInfo->auc2G_NonHtChnlList[i] <= ucAffectedChnl_H) && + prBssInfo->auc2G_NonHtChnlList[i] != ucPriChannel) { + ucChannelLevel = CHNL_LEVEL0; + goto L_2G4_level_end; + } + } + + /* Check 20M BW request channel list */ + ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; + i <= prBssInfo->auc2G_20mReqChnlList[0] && i <= CHNL_LIST_SZ_2G; + i++) { + if ((prBssInfo->auc2G_20mReqChnlList[i] >= ucAffectedChnl_L && + prBssInfo->auc2G_20mReqChnlList[i] <= ucAffectedChnl_H)) { + ucChannelLevel = CHNL_LEVEL0; + goto L_2G4_level_end; + } + } + + /* Check 2.4G primary channel list */ + ASSERT(prBssInfo->auc2G_PriChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; + i <= prBssInfo->auc2G_PriChnlList[0] && i <= CHNL_LIST_SZ_2G; + i++) { + if ((prBssInfo->auc2G_PriChnlList[i] >= ucAffectedChnl_L && + prBssInfo->auc2G_PriChnlList[i] <= ucAffectedChnl_H) && + prBssInfo->auc2G_PriChnlList[i] != ucPriChannel) { + ucChannelLevel = CHNL_LEVEL0; + goto L_2G4_level_end; + } + } + + /* Check 2.4G secondary channel list */ + ASSERT(prBssInfo->auc2G_SecChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; + i <= prBssInfo->auc2G_SecChnlList[0] && i <= CHNL_LIST_SZ_2G; + i++) { + if ((prBssInfo->auc2G_SecChnlList[i] >= ucAffectedChnl_L && + prBssInfo->auc2G_SecChnlList[i] <= ucAffectedChnl_H) && + prBssInfo->auc2G_SecChnlList[i] != ucSecChannel) { + ucChannelLevel = CHNL_LEVEL0; + goto L_2G4_level_end; + } + } + +L_2G4_level_end: + + return ucChannelLevel; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static u8 rlmObssChnlLevelIn5G(P_BSS_INFO_T prBssInfo, u8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend) +{ + u8 i, ucChannelLevel; + u8 ucSecChannel; + + ASSERT(prBssInfo); + + ucChannelLevel = CHNL_LEVEL2; + + /* Calculate center channel for 2.4G band */ + if (eExtend == CHNL_EXT_SCA) { + ucSecChannel = ucPriChannel + 4; + }else if (eExtend == CHNL_EXT_SCB) { + ucSecChannel = ucPriChannel - 4; + }else{ + return CHNL_LEVEL0; + } + + ASSERT(ucSecChannel >= 36); + + /* Check 5G primary channel list */ + ASSERT(prBssInfo->auc5G_PriChnlList[0] <= CHNL_LIST_SZ_5G); + for (i = 1; + i <= prBssInfo->auc5G_PriChnlList[0] && i <= CHNL_LIST_SZ_5G; + i++) { + if (prBssInfo->auc5G_PriChnlList[i] == ucSecChannel) { + ucChannelLevel = CHNL_LEVEL0; + goto L_5G_level_end; + } else if (prBssInfo->auc5G_PriChnlList[i] == ucPriChannel) { + ucChannelLevel = CHNL_LEVEL1; + } + } + + /* Check non-HT channel list */ + ASSERT(prBssInfo->auc5G_NonHtChnlList[0] <= CHNL_LIST_SZ_5G); + for (i = 1; + i <= prBssInfo->auc5G_NonHtChnlList[0] && i <= CHNL_LIST_SZ_5G; + i++) { + if (prBssInfo->auc5G_NonHtChnlList[i] == ucSecChannel) { + ucChannelLevel = CHNL_LEVEL0; + goto L_5G_level_end; + } else if (prBssInfo->auc5G_NonHtChnlList[i] == ucPriChannel) { + ucChannelLevel = CHNL_LEVEL1; + } + } + + /* Check secondary channel list */ + ASSERT(prBssInfo->auc5G_SecChnlList[0] <= CHNL_LIST_SZ_5G); + for (i = 1; + i <= prBssInfo->auc5G_SecChnlList[0] && i <= CHNL_LIST_SZ_5G; + i++) { + if (prBssInfo->auc5G_SecChnlList[i] == ucPriChannel) { + ucChannelLevel = CHNL_LEVEL0; + goto L_5G_level_end; + } + } + +L_5G_level_end: + + return ucChannelLevel; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmObssScanExemptionRsp(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + P_SW_RFB_T prSwRfb) +{ + P_MSDU_INFO_T prMsduInfo; + P_ACTION_20_40_COEXIST_FRAME prTxFrame; + + /* To do: need an algorithm to do judgement. Now always reject request + */ + + prMsduInfo = + (P_MSDU_INFO_T)cnmMgtPktAlloc(prAdapter, PUBLIC_ACTION_MAX_LEN); + if (prMsduInfo == NULL) { + return; + } + + DBGLOG(RLM, INFO, "Send 20/40 coexistence rsp frame!\n"); + + prTxFrame = (P_ACTION_20_40_COEXIST_FRAME)prMsduInfo->prPacket; + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + COPY_MAC_ADDR( + prTxFrame->aucDestAddr, + ((P_ACTION_20_40_COEXIST_FRAME)prSwRfb->pvHeader)->aucSrcAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_PUBLIC_ACTION; + prTxFrame->ucAction = ACTION_PUBLIC_20_40_COEXIST; + + /* To do: find correct algorithm */ + prTxFrame->rBssCoexist.ucId = ELEM_ID_20_40_BSS_COEXISTENCE; + prTxFrame->rBssCoexist.ucLength = 1; + prTxFrame->rBssCoexist.ucData = 0; + + ASSERT((WLAN_MAC_HEADER_LEN + 5) <= PUBLIC_ACTION_MAX_LEN); + + TX_SET_MMPDU(prAdapter, prMsduInfo, prBssInfo->ucBssIndex, + prSwRfb->ucStaRecIdx, WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_HTC_LEN + 5, NULL, + MSDU_RATE_MODE_AUTO); + + /* Send them to HW queue */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_role_fsm.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_role_fsm.c new file mode 100644 index 00000000000000..398e69d7426a24 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_role_fsm.c @@ -0,0 +1,2906 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ +#include "precomp.h" +#include "p2p_role_state.h" +#include "gl_p2p_os.h" + +#if !DBG_DISABLE_ALL_LOG +/*lint -save -e64 Type mismatch */ +static u8 *apucDebugP2pRoleState[P2P_ROLE_STATE_NUM] = { + (u8 *)DISP_STRING("P2P_ROLE_STATE_IDLE"), + (u8 *)DISP_STRING("P2P_ROLE_STATE_SCAN"), + (u8 *)DISP_STRING("P2P_ROLE_STATE_REQING_CHANNEL"), + (u8 *)DISP_STRING("P2P_ROLE_STATE_AP_CHNL_DETECTION"), +#if (CFG_SUPPORT_DFS_MASTER == 1) + (u8 *)DISP_STRING("P2P_ROLE_STATE_GC_JOIN"), + (u8 *)DISP_STRING("P2P_ROLE_STATE_DFS_CAC"), + (u8 *)DISP_STRING("P2P_ROLE_STATE_SWITCH_CHANNEL") +#else + (u8 *)DISP_STRING("P2P_ROLE_STATE_GC_JOIN") +#endif +}; + +/*lint -restore */ +#endif + +u8 p2pRoleFsmInit(IN P_ADAPTER_T prAdapter, IN u8 ucRoleIdx) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_CHNL_REQ_INFO_T prP2pChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + P_GL_P2P_INFO_T prP2PInfo = NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + ASSERT_BREAK(P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, ucRoleIdx) == + NULL); + + prP2pRoleFsmInfo = + kalMemAlloc(sizeof(P2P_ROLE_FSM_INFO_T), VIR_MEM_TYPE); + + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, ucRoleIdx) = prP2pRoleFsmInfo; + + ASSERT_BREAK(prP2pRoleFsmInfo != NULL); + + kalMemZero(prP2pRoleFsmInfo, sizeof(P2P_ROLE_FSM_INFO_T)); + + prP2pRoleFsmInfo->ucRoleIndex = ucRoleIdx; + + prP2pRoleFsmInfo->eCurrentState = P2P_ROLE_STATE_IDLE; + + prP2pRoleFsmInfo->u4P2pPacketFilter = PARAM_PACKET_FILTER_SUPPORTED; + + prP2pChnlReqInfo = &prP2pRoleFsmInfo->rChnlReqInfo; + LINK_INITIALIZE(&(prP2pChnlReqInfo->rP2pChnlReqLink)); + + cnmTimerInitTimer(prAdapter, + &(prP2pRoleFsmInfo->rP2pRoleFsmTimeoutTimer), + (PFN_MGMT_TIMEOUT_FUNC)p2pRoleFsmRunEventTimeout, + (unsigned long)prP2pRoleFsmInfo); + +#if (CFG_SUPPORT_DFS_MASTER == 1) + cnmTimerInitTimer( + prAdapter, &(prP2pRoleFsmInfo->rDfsShutDownTimer), + (PFN_MGMT_TIMEOUT_FUNC)p2pRoleFsmRunEventDfsShutDownTimeout, + (unsigned long)prP2pRoleFsmInfo); +#if CFG_SUPPORT_DBDC_TC6 + cnmTimerInitTimer( + prAdapter, &(prP2pRoleFsmInfo->rDfsStartCacTimer), + (PFN_MGMT_TIMEOUT_FUNC)p2pRoleFsmRunEventStartDfsCacTimeout, + (unsigned long)prP2pRoleFsmInfo); +#endif +#endif + + prP2pBssInfo = cnmGetBssInfoAndInit(prAdapter, NETWORK_TYPE_P2P, false); + + if (!prP2pBssInfo) { + DBGLOG(P2P, ERROR, "Error allocating BSS Info Structure\n"); + break; + } + + BSS_INFO_INIT(prAdapter, prP2pBssInfo); + prP2pRoleFsmInfo->ucBssIndex = prP2pBssInfo->ucBssIndex; + + /* For state identify, not really used. */ + prP2pBssInfo->eIntendOPMode = OP_MODE_P2P_DEVICE; + + /* glRegisterP2P has setup the mac address */ + /* For wlan0 as AP mode case, this function will be called when + * changing interface type. And the MAC Addr overwrite by Role + * isn't expected. + * Maybe only using ucRoleIdx to calc MAC addr is better than + * using Role type. + */ + prP2PInfo = prAdapter->prGlueInfo->prP2PInfo[ucRoleIdx]; + COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, + prP2PInfo->prDevHandler->dev_addr); + + /* For BSS_INFO back trace to P2P Role & get Role FSM. */ + prP2pBssInfo->u4PrivateData = ucRoleIdx; + + if (p2pFuncIsAPMode(prAdapter->rWifiVar.prP2PConnSettings[ucRoleIdx])) { + prP2pBssInfo->ucConfigAdHocAPMode = AP_MODE_11G; + prP2pBssInfo->u2HwDefaultFixedRateCode = RATE_CCK_1M_LONG; + } else { + prP2pBssInfo->ucConfigAdHocAPMode = AP_MODE_11G_P2P; + prP2pBssInfo->u2HwDefaultFixedRateCode = RATE_OFDM_6M; + } + + prP2pBssInfo->ucNonHTBasicPhyType = + (u8)rNonHTApModeAttributes[prP2pBssInfo->ucConfigAdHocAPMode] + .ePhyTypeIndex; + prP2pBssInfo->u2BSSBasicRateSet = + rNonHTApModeAttributes[prP2pBssInfo->ucConfigAdHocAPMode] + .u2BSSBasicRateSet; + + prP2pBssInfo->u2OperationalRateSet = + rNonHTPhyAttributes[prP2pBssInfo->ucNonHTBasicPhyType] + .u2SupportedRateSet; + + rateGetDataRatesFromRateSet(prP2pBssInfo->u2OperationalRateSet, + prP2pBssInfo->u2BSSBasicRateSet, + prP2pBssInfo->aucAllSupportedRates, + &prP2pBssInfo->ucAllSupportedRatesLen); + + prP2pBssInfo->prBeacon = cnmMgtPktAlloc( + prAdapter, + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); + + if (prP2pBssInfo->prBeacon) { + prP2pBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; + prP2pBssInfo->prBeacon->ucStaRecIndex = + STA_REC_INDEX_BMCAST; /* NULL STA_REC */ + prP2pBssInfo->prBeacon->ucBssIndex = prP2pBssInfo->ucBssIndex; + } else { + /* Out of memory. */ + ASSERT(false); + } + + prP2pBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = PM_UAPSD_ALL; + prP2pBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = PM_UAPSD_ALL; + prP2pBssInfo->rPmProfSetupInfo.ucUapsdSp = WMM_MAX_SP_LENGTH_2; + prP2pBssInfo->ucPrimaryChannel = P2P_DEFAULT_LISTEN_CHANNEL; + prP2pBssInfo->eBand = BAND_2G4; + prP2pBssInfo->eBssSCO = CHNL_EXT_SCN; + prP2pBssInfo->ucNss = + wlanGetSupportNss(prAdapter, prP2pBssInfo->ucBssIndex); + prP2pBssInfo->eDBDCBand = ENUM_BAND_0; +#if (CFG_HW_WMM_BY_BSS == 0) + prP2pBssInfo->ucWmmQueSet = + (prAdapter->rWifiVar.ucDbdcMode == DBDC_MODE_DISABLED) ? + DBDC_5G_WMM_INDEX : + DBDC_2G_WMM_INDEX; +#endif + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) { + prP2pBssInfo->fgIsQBSS = true; + } else { + prP2pBssInfo->fgIsQBSS = false; + } + +#if (CFG_SUPPORT_DFS_MASTER == 1) + p2pFuncRadarInfoInit(); +#endif +#if CFG_SUPPORT_802_11W + init_completion(&prP2pBssInfo->rDeauthComp); + prP2pBssInfo->encryptedDeauthIsInProcess = false; +#endif + /* SET_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex); + */ + + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_IDLE); + } while (false); + + if (prP2pBssInfo) { + return prP2pBssInfo->ucBssIndex; + } else { + return P2P_DEV_BSS_INDEX; + } +} + +void p2pRoleFsmUninit(IN P_ADAPTER_T prAdapter, IN u8 ucRoleIdx) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + do { + ASSERT_BREAK(prAdapter != NULL); + + DEBUGFUNC("p2pRoleFsmUninit()"); + DBGLOG(P2P, INFO, "->p2pRoleFsmUninit()\n"); + + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, ucRoleIdx); + + ASSERT_BREAK(prP2pRoleFsmInfo != NULL); + + if (!prP2pRoleFsmInfo) { + return; + } + + prP2pBssInfo = prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex]; + + p2pFuncDissolve(prAdapter, prP2pBssInfo, true, + REASON_CODE_DEAUTH_LEAVING_BSS, true); + + SET_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex); + + /* Function Dissolve should already enter IDLE state. */ + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_IDLE); + + p2pRoleFsmRunEventAbort(prAdapter, prP2pRoleFsmInfo); + + /* Clear CmdQue */ + kalClearMgmtFramesByBssIdx(prAdapter->prGlueInfo, + prP2pBssInfo->ucBssIndex); + kalClearSecurityFramesByBssIdx(prAdapter->prGlueInfo, + prP2pBssInfo->ucBssIndex); + /* Clear PendingTxMsdu */ + nicFreePendingTxMsduInfoByBssIdx(prAdapter, prP2pBssInfo->ucBssIndex); + + /* Deactivate BSS. */ + UNSET_NET_ACTIVE(prAdapter, prP2pRoleFsmInfo->ucBssIndex); + + nicDeactivateNetwork(prAdapter, prP2pRoleFsmInfo->ucBssIndex); + + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, ucRoleIdx) = NULL; + + if (prP2pBssInfo->prBeacon) { + cnmMgtPktFree(prAdapter, prP2pBssInfo->prBeacon); + prP2pBssInfo->prBeacon = NULL; + } + + cnmFreeBssInfo(prAdapter, prP2pBssInfo); + + /* ensure the timer be stopped */ + cnmTimerStopTimer(prAdapter, + &(prP2pRoleFsmInfo->rP2pRoleFsmTimeoutTimer)); + +#if (CFG_SUPPORT_DFS_MASTER == 1) + cnmTimerStopTimer(prAdapter, &(prP2pRoleFsmInfo->rDfsShutDownTimer)); +#if CFG_SUPPORT_DBDC + cnmTimerStopTimer(prAdapter, &(prP2pRoleFsmInfo->rDfsStartCacTimer)); +#endif +#endif + + if (prP2pRoleFsmInfo) { + kalMemFree(prP2pRoleFsmInfo, VIR_MEM_TYPE, + sizeof(P2P_ROLE_FSM_INFO_T)); + } + } while (false); + + return; +} + +void p2pRoleFsmStateTransition(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN ENUM_P2P_ROLE_STATE_T eNextState) +{ + u8 fgIsTransitionOut = (u8)false; + P_BSS_INFO_T prP2pRoleBssInfo = (P_BSS_INFO_T)NULL; + + prP2pRoleBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prP2pRoleFsmInfo->ucBssIndex); + + do { + if (!IS_BSS_ACTIVE(prP2pRoleBssInfo)) { + if (!cnmP2PIsPermitted(prAdapter)) { + return; + } + + SET_NET_ACTIVE(prAdapter, prP2pRoleBssInfo->ucBssIndex); + nicActivateNetwork(prAdapter, prP2pRoleBssInfo->ucBssIndex); + } + + fgIsTransitionOut = fgIsTransitionOut ? false : true; + + if (!fgIsTransitionOut) { + DBGLOG(P2P, STATE, + "[P2P_ROLE][%d]TRANSITION(Bss%d): [%s] -> [%s]\n", + prP2pRoleFsmInfo->ucRoleIndex, prP2pRoleFsmInfo->ucBssIndex, + apucDebugP2pRoleState[prP2pRoleFsmInfo->eCurrentState], + apucDebugP2pRoleState[eNextState]); + + /* Transition into current state. */ + prP2pRoleFsmInfo->eCurrentState = eNextState; + } + + switch (prP2pRoleFsmInfo->eCurrentState) { + case P2P_ROLE_STATE_IDLE: + if (!fgIsTransitionOut) { + p2pRoleStateInit_IDLE(prAdapter, prP2pRoleFsmInfo, + prP2pRoleBssInfo); + } else { + p2pRoleStateAbort_IDLE(prAdapter, prP2pRoleFsmInfo, + &(prP2pRoleFsmInfo->rChnlReqInfo)); + } + break; + + case P2P_ROLE_STATE_SCAN: + if (!fgIsTransitionOut) { + p2pRoleStateInit_SCAN(prAdapter, prP2pRoleFsmInfo->ucBssIndex, + &(prP2pRoleFsmInfo->rScanReqInfo)); + } else { + p2pRoleStateAbort_SCAN(prAdapter, prP2pRoleFsmInfo); + } + break; + + case P2P_ROLE_STATE_REQING_CHANNEL: + if (!fgIsTransitionOut) { + p2pRoleStateInit_REQING_CHANNEL( + prAdapter, prP2pRoleFsmInfo->ucBssIndex, + &(prP2pRoleFsmInfo->rChnlReqInfo)); + } else { + p2pRoleStateAbort_REQING_CHANNEL(prAdapter, prP2pRoleBssInfo, + prP2pRoleFsmInfo, eNextState); + } + break; + + case P2P_ROLE_STATE_AP_CHNL_DETECTION: + if (!fgIsTransitionOut) { + p2pRoleStateInit_AP_CHNL_DETECTION( + prAdapter, prP2pRoleFsmInfo->ucBssIndex, + &(prP2pRoleFsmInfo->rScanReqInfo), + &(prP2pRoleFsmInfo->rConnReqInfo)); + } else { + p2pRoleStateAbort_AP_CHNL_DETECTION( + prAdapter, prP2pRoleFsmInfo->ucBssIndex, + &(prP2pRoleFsmInfo->rConnReqInfo), + &(prP2pRoleFsmInfo->rChnlReqInfo), + &(prP2pRoleFsmInfo->rScanReqInfo), eNextState); + } + break; + + case P2P_ROLE_STATE_GC_JOIN: + if (!fgIsTransitionOut) { + p2pRoleStateInit_GC_JOIN(prAdapter, prP2pRoleFsmInfo, + &(prP2pRoleFsmInfo->rChnlReqInfo)); + } else { + p2pRoleStateAbort_GC_JOIN(prAdapter, prP2pRoleFsmInfo, + &(prP2pRoleFsmInfo->rJoinInfo), + eNextState); + } + break; + +#if (CFG_SUPPORT_DFS_MASTER == 1) + case P2P_ROLE_STATE_DFS_CAC: + if (!fgIsTransitionOut) { + p2pRoleStateInit_DFS_CAC(prAdapter, + prP2pRoleFsmInfo->ucBssIndex, + &(prP2pRoleFsmInfo->rChnlReqInfo)); + } else { + p2pRoleStateAbort_DFS_CAC(prAdapter, prP2pRoleBssInfo, + prP2pRoleFsmInfo, eNextState); + } + break; + + case P2P_ROLE_STATE_SWITCH_CHANNEL: + if (!fgIsTransitionOut) { + p2pRoleStateInit_SWITCH_CHANNEL( + prAdapter, prP2pRoleFsmInfo->ucBssIndex, + &(prP2pRoleFsmInfo->rChnlReqInfo)); + } else { + p2pRoleStateAbort_SWITCH_CHANNEL(prAdapter, prP2pRoleBssInfo, + prP2pRoleFsmInfo, eNextState); + } + break; + +#endif + default: + ASSERT(false); + break; + } + } while (fgIsTransitionOut); +} + +void p2pRoleFsmRunEventTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)ulParamPtr; + P_P2P_CHNL_REQ_INFO_T prP2pChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pRoleFsmInfo != NULL)); + + switch (prP2pRoleFsmInfo->eCurrentState) { + case P2P_ROLE_STATE_IDLE: + prP2pChnlReqInfo = &(prP2pRoleFsmInfo->rChnlReqInfo); + if (prP2pChnlReqInfo->fgIsChannelRequested) { + p2pFuncReleaseCh(prAdapter, prP2pRoleFsmInfo->ucBssIndex, + prP2pChnlReqInfo); + if (IS_NET_PWR_STATE_IDLE(prAdapter, + prP2pRoleFsmInfo->ucBssIndex)) { + ASSERT(false); + } + } + + if (IS_NET_PWR_STATE_IDLE(prAdapter, + prP2pRoleFsmInfo->ucBssIndex)) { + DBGLOG(P2P, TRACE, "Role BSS IDLE, deactive network.\n"); + UNSET_NET_ACTIVE(prAdapter, prP2pRoleFsmInfo->ucBssIndex); + nicDeactivateNetwork(prAdapter, prP2pRoleFsmInfo->ucBssIndex); + nicUpdateBss(prAdapter, prP2pRoleFsmInfo->ucBssIndex); + } + break; + + case P2P_ROLE_STATE_GC_JOIN: + DBGLOG( + P2P, ERROR, + "Current P2P Role State P2P_ROLE_STATE_GC_JOIN is unexpected for " + "FSM timeout event.\n"); + break; + +#if (CFG_SUPPORT_DFS_MASTER == 1) + case P2P_ROLE_STATE_DFS_CAC: + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_IDLE); + kalP2PCacFinishedUpdate(prAdapter->prGlueInfo, + prP2pRoleFsmInfo->ucRoleIndex); +#ifndef CFG_SUPPORT_DISABLE_SAP_DFS_RDD + p2pFuncSetDfsState(DFS_STATE_ACTIVE); + cnmTimerStartTimer(prAdapter, + &(prP2pRoleFsmInfo->rDfsShutDownTimer), 5000); +#else + p2pFuncSetDfsState(DFS_STATE_INACTIVE); +#endif + break; + +#endif + default: + DBGLOG( + P2P, ERROR, + "Current P2P Role State %d is unexpected for FSM timeout event.\n", + prP2pRoleFsmInfo->eCurrentState); + ASSERT(false); + break; + } + } while (false); +} + +static void p2pRoleFsmDeauthComplete(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + ENUM_PARAM_MEDIA_STATE_T eOriMediaStatus; + P_GL_P2P_INFO_T prP2PInfo; + u16 u2ReasonCode; + u8 fgIsLocallyGenerated; + + DBGLOG(P2P, INFO, "Deauth TX Complete!\n"); + + if (!prAdapter) { + DBGLOG(P2P, ERROR, "prAdapter shouldn't be NULL!\n"); + return; + } + + if (!prStaRec) { + DBGLOG(P2P, ERROR, "prStaRec shouldn't be NULL!\n"); + return; + } + + prP2pBssInfo = prAdapter->aprBssInfo[prStaRec->ucBssIndex]; + if (!prP2pBssInfo) { + DBGLOG(P2P, ERROR, "prP2pBssInfo shouldn't be NULL!\n"); + return; + } + + eOriMediaStatus = prP2pBssInfo->eConnectionState; + prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pBssInfo->u4PrivateData); + + if (!prP2pRoleFsmInfo) { + DBGLOG(P2P, ERROR, "prP2pRoleFsmInfo shouldn't be NULL!\n"); + return; + } + + prP2PInfo = prAdapter->prGlueInfo->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex]; + + if (!prP2PInfo) { + DBGLOG(P2P, ERROR, "prP2PInfo shouldn't be NULL!\n"); + return; + } + +#if CFG_SUPPORT_802_11W + /* Notify completion after encrypted deauth frame tx done */ + if (prP2pBssInfo->encryptedDeauthIsInProcess == true) { + if (!completion_done(&prP2pBssInfo->rDeauthComp)) { + DBGLOG(P2P, TRACE, "Complete rDeauthComp\n"); + complete(&prP2pBssInfo->rDeauthComp); + } + } + prP2pBssInfo->encryptedDeauthIsInProcess = false; +#endif + + /* + * After EAP exchange, GO/GC will disconnect + * and re-connect in short time. + * GC's new station record will be removed unexpectedly at GO's side + * if new GC's connection happens + * when previous GO's disconnection flow is + * processing. 4-way handshake will NOT be triggered. + */ + if ((prStaRec->eAuthAssocState == AAA_STATE_SEND_AUTH2 || + prStaRec->eAuthAssocState == AAA_STATE_SEND_ASSOC2) && + (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) && + (p2pFuncIsAPMode(prAdapter->rWifiVar + .prP2PConnSettings[prP2pBssInfo->u4PrivateData]) == + false)) { + DBGLOG(P2P, WARN, + "Skip deauth tx done since AAA fsm is in progress.\n"); + return; + } else if (prStaRec->eAuthAssocState == SAA_STATE_SEND_AUTH1 || + prStaRec->eAuthAssocState == SAA_STATE_SEND_ASSOC1) { + DBGLOG(P2P, WARN, + "Skip deauth tx done since SAA fsm is in progress.\n"); + return; + } + + /* Change station state. */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + /* Save ReasonCode */ + u2ReasonCode = prStaRec->u2ReasonCode; + fgIsLocallyGenerated = prStaRec->fgIsLocallyGenerated; + + /* Reset Station Record Status. */ + p2pFuncResetStaRecStatus(prAdapter, prStaRec); + + /* Try to remove StaRec in BSS client list before free it */ + bssRemoveClient(prAdapter, prP2pBssInfo, prStaRec); + + /* STA_RECORD free */ + cnmStaRecFree(prAdapter, prStaRec); + + if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || + (bssGetClientCount(prAdapter, prP2pBssInfo) == 0)) { + if (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + DBGLOG(P2P, TRACE, "No More Client, Media Status DISCONNECTED\n"); + } else { + DBGLOG(P2P, INFO, + "Deauth done, Media Status DISCONNECTED, reason=%d\n", + u2ReasonCode); + } + p2pChangeMediaState(prAdapter, prP2pBssInfo, + PARAM_MEDIA_STATE_DISCONNECTED); + if (prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + kalP2PGCIndicateConnectionStatus( + prAdapter->prGlueInfo, prP2pRoleFsmInfo->ucRoleIndex, NULL, + NULL, 0, u2ReasonCode, + fgIsLocallyGenerated ? WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY : + WLAN_STATUS_MEDIA_DISCONNECT); + } + } + + /* STOP BSS if power is IDLE */ + if (prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + if (IS_NET_PWR_STATE_IDLE(prAdapter, prP2pRoleFsmInfo->ucBssIndex) && + (bssGetClientCount(prAdapter, prP2pBssInfo) == 0)) { + /* All Peer disconnected !! Stop BSS now!! */ + p2pFuncStopComplete(prAdapter, prP2pBssInfo); + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_IDLE); + } else if (eOriMediaStatus != prP2pBssInfo->eConnectionState) { + /* Update the Media State if necessary */ + nicUpdateBss(prAdapter, prP2pBssInfo->ucBssIndex); + } + } else { /* GC : Stop BSS when Deauth done */ + p2pFuncStopComplete(prAdapter, prP2pBssInfo); + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_IDLE); + } +} + +void p2pRoleFsmDeauthTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr) +{ + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)ulParamPtr; + + p2pRoleFsmDeauthComplete(prAdapter, prStaRec); +} + +void p2pRoleFsmRunEventAbort(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pRoleFsmInfo != NULL)); + + if (prP2pRoleFsmInfo->eCurrentState != P2P_ROLE_STATE_IDLE) { + /* Get into IDLE state. */ + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_IDLE); + } + + /* Abort IDLE. */ + p2pRoleStateAbort_IDLE(prAdapter, prP2pRoleFsmInfo, + &(prP2pRoleFsmInfo->rChnlReqInfo)); + } while (false); +} + +WLAN_STATUS +p2pRoleFsmRunEventDeauthTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + DBGLOG(P2P, INFO, "Deauth TX Done,rTxDoneStatus = %d\n", rTxDoneStatus); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (prStaRec == NULL) { + DBGLOG(P2P, TRACE, "Station Record NULL, Index:%d\n", + prMsduInfo->ucStaRecIndex); + break; + } + + p2pRoleFsmDeauthComplete(prAdapter, prStaRec); + /* Avoid re-entry */ + cnmTimerStopTimer(prAdapter, &(prStaRec->rDeauthTxDoneTimer)); + } while (false); + + return WLAN_STATUS_SUCCESS; +} + +void p2pRoleFsmRunEventRxDeauthentication(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + u16 u2ReasonCode = 0; + u8 fgSendDeauth = false; /* flag to send deauth when rx sta + * disassc/deauth */ + + do { + ASSERT_BREAK((prAdapter != NULL) && (prSwRfb != NULL)); + + if (prStaRec == NULL) { + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + } + + if (!prStaRec) { + break; + } + + prP2pBssInfo = prAdapter->aprBssInfo[prStaRec->ucBssIndex]; + + if (prStaRec->ucStaState == STA_STATE_1) { + break; + } + + DBGLOG(P2P, TRACE, "RX Deauth\n"); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_INFRASTRUCTURE: + if (authProcessRxDeauthFrame(prSwRfb, prStaRec->aucMacAddr, + &u2ReasonCode) == + WLAN_STATUS_SUCCESS) { + P_WLAN_DEAUTH_FRAME_T prDeauthFrame = + (P_WLAN_DEAUTH_FRAME_T)prSwRfb->pvHeader; + u16 u2IELength = 0; + + if (prP2pBssInfo->prStaRecOfAP != prStaRec) { + break; + } + + prStaRec->u2ReasonCode = u2ReasonCode; + u2IELength = prSwRfb->u2PacketLen - + (WLAN_MAC_HEADER_LEN + REASON_CODE_FIELD_LEN); + + ASSERT(prP2pBssInfo->prStaRecOfAP == prStaRec); + + /* Indicate disconnect to Host. */ + kalP2PGCIndicateConnectionStatus( + prAdapter->prGlueInfo, (u8)prP2pBssInfo->u4PrivateData, + NULL, prDeauthFrame->aucInfoElem, u2IELength, u2ReasonCode, + WLAN_STATUS_MEDIA_DISCONNECT); + + prP2pBssInfo->prStaRecOfAP = NULL; + + p2pFuncDisconnect(prAdapter, prP2pBssInfo, prStaRec, false, + u2ReasonCode, false); + + p2pFuncStopComplete(prAdapter, prP2pBssInfo); + + SET_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex); + + p2pRoleFsmStateTransition( + prAdapter, + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, + prP2pBssInfo->u4PrivateData), + P2P_ROLE_STATE_IDLE); + } + break; + + case OP_MODE_ACCESS_POINT: + /* Delete client from client list. */ + if (authProcessRxDeauthFrame(prSwRfb, prP2pBssInfo->aucBSSID, + &u2ReasonCode) == + WLAN_STATUS_SUCCESS) { +#if CFG_SUPPORT_802_11W + /* AP PMF */ + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + if (HAL_RX_STATUS_IS_CIPHER_MISMATCH(prSwRfb->prRxStatus) || + HAL_RX_STATUS_IS_CLM_ERROR(prSwRfb->prRxStatus)) { + /* if cipher mismatch, or + * incorrect encrypt, just drop + */ + DBGLOG(P2P, ERROR, "Rx deauth CM/CLM=1\n"); + return; + } + + /* 4.3.3.1 send unprotected deauth + * reason 6/7 */ + DBGLOG(P2P, INFO, "deauth reason=6\n"); + fgSendDeauth = true; + u2ReasonCode = REASON_CODE_CLASS_2_ERR; + prStaRec->rPmfCfg.fgRxDeauthResp = true; + } +#endif + + if (bssRemoveClient(prAdapter, prP2pBssInfo, prStaRec)) { + /* Indicate disconnect to Host. */ + p2pFuncDisconnect(prAdapter, prP2pBssInfo, prStaRec, + fgSendDeauth, u2ReasonCode, false); + /* Deactive BSS if PWR is IDLE and no + * peer */ + if (IS_NET_PWR_STATE_IDLE(prAdapter, + prP2pBssInfo->ucBssIndex) && + (bssGetClientCount(prAdapter, prP2pBssInfo) == 0)) { + /* All Peer disconnected !! Stop + * BSS now!! */ + p2pFuncStopComplete(prAdapter, prP2pBssInfo); + } + } + } + break; + + case OP_MODE_P2P_DEVICE: + default: + /* Findout why someone sent deauthentication frame to + * us. */ + ASSERT(false); + break; + } + + DBGLOG(P2P, TRACE, "Deauth Reason:%d\n", u2ReasonCode); + } while (false); +} + +void p2pRoleFsmRunEventRxDisassociation(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + u16 u2ReasonCode = 0; + u8 fgSendDeauth = false; /* flag to send deauth when rx sta + * disassc/deauth */ + + if (prStaRec == NULL) { + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + } + + if (!prStaRec) { + DBGLOG(P2P, ERROR, "prStaRec of prSwRfb->ucStaRecIdx %d is NULL!\n", + prSwRfb->ucStaRecIdx); + return; + } + + prP2pBssInfo = prAdapter->aprBssInfo[prStaRec->ucBssIndex]; + + if (prStaRec->ucStaState == STA_STATE_1) { + return; + } + + DBGLOG(P2P, TRACE, "RX Disassoc\n"); + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_INFRASTRUCTURE: + if (assocProcessRxDisassocFrame( + prAdapter, prSwRfb, prStaRec->aucMacAddr, + &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { + P_WLAN_DISASSOC_FRAME_T prDisassocFrame = + (P_WLAN_DISASSOC_FRAME_T)prSwRfb->pvHeader; + u16 u2IELength = 0; + + ASSERT(prP2pBssInfo->prStaRecOfAP == prStaRec); + + if (prP2pBssInfo->prStaRecOfAP != prStaRec) { + break; + } + + u2IELength = prSwRfb->u2PacketLen - + (WLAN_MAC_HEADER_LEN + REASON_CODE_FIELD_LEN); + + /* Indicate disconnect to Host. */ + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + (u8)prP2pBssInfo->u4PrivateData, + NULL, prDisassocFrame->aucInfoElem, + u2IELength, prStaRec->u2ReasonCode, + WLAN_STATUS_MEDIA_DISCONNECT); + + prP2pBssInfo->prStaRecOfAP = NULL; + + p2pFuncDisconnect(prAdapter, prP2pBssInfo, prStaRec, false, + prStaRec->u2ReasonCode, false); + + p2pFuncStopComplete(prAdapter, prP2pBssInfo); + + SET_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex); + + p2pRoleFsmStateTransition( + prAdapter, + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, + prP2pBssInfo->u4PrivateData), + P2P_ROLE_STATE_IDLE); + } + break; + + case OP_MODE_ACCESS_POINT: + /* Delete client from client list. */ + if (assocProcessRxDisassocFrame(prAdapter, prSwRfb, + prP2pBssInfo->aucBSSID, + &u2ReasonCode) == WLAN_STATUS_SUCCESS) { +#if CFG_SUPPORT_802_11W + /* AP PMF */ + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + if (HAL_RX_STATUS_IS_CIPHER_MISMATCH(prSwRfb->prRxStatus) || + HAL_RX_STATUS_IS_CLM_ERROR(prSwRfb->prRxStatus)) { + /* if cipher mismatch, or incorrect + * encrypt, just drop */ + DBGLOG(P2P, ERROR, "Rx disassoc CM/CLM=1\n"); + return; + } + + /* 4.3.3.1 send unprotected deauth reason 6/7 */ + DBGLOG(P2P, INFO, "deauth reason=6\n"); + fgSendDeauth = true; + u2ReasonCode = REASON_CODE_CLASS_2_ERR; + prStaRec->rPmfCfg.fgRxDeauthResp = true; + } +#endif + + if (bssRemoveClient(prAdapter, prP2pBssInfo, prStaRec)) { + /* Indicate disconnect to Host. */ + p2pFuncDisconnect(prAdapter, prP2pBssInfo, prStaRec, + fgSendDeauth, u2ReasonCode, false); + /* Deactive BSS if PWR is IDLE and no peer */ + if (IS_NET_PWR_STATE_IDLE(prAdapter, + prP2pBssInfo->ucBssIndex) && + (bssGetClientCount(prAdapter, prP2pBssInfo) == 0)) { + /* All Peer disconnected !! Stop BSS + * now!! */ + p2pFuncStopComplete(prAdapter, prP2pBssInfo); + } + } + } + break; + + case OP_MODE_P2P_DEVICE: + default: + ASSERT(false); + break; + } +} + +void p2pRoleFsmRunEventBeaconTimeout(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pBssInfo) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prP2pBssInfo != NULL)); + + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO( + prAdapter, prP2pBssInfo->u4PrivateData); + + /* Only client mode would have beacon lost event. */ + if (prP2pBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + DBGLOG(P2P, ERROR, + "Error case, P2P BSS %d not INFRA mode but beacon timeout\n", + prP2pRoleFsmInfo->ucRoleIndex); + break; + } + + DBGLOG(P2P, TRACE, + "p2pFsmRunEventBeaconTimeout: BSS %d Beacon Timeout\n", + prP2pRoleFsmInfo->ucRoleIndex); + + if (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + /* Indicate disconnect to Host. */ + kalP2PGCIndicateConnectionStatus( + prAdapter->prGlueInfo, prP2pRoleFsmInfo->ucRoleIndex, NULL, + NULL, 0, REASON_CODE_DISASSOC_LEAVING_BSS, + WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY); + + if (prP2pBssInfo->prStaRecOfAP != NULL) { + P_STA_RECORD_T prStaRec = prP2pBssInfo->prStaRecOfAP; + prP2pBssInfo->prStaRecOfAP = NULL; + + p2pFuncDisconnect(prAdapter, prP2pBssInfo, prStaRec, true, + REASON_CODE_DISASSOC_LEAVING_BSS, true); + p2pRoleFsmDeauthComplete(prAdapter, prStaRec); + + SET_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex); + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_IDLE); + } + } + } while (false); +} + +/*================== Message Event ==================*/ +void p2pRoleFsmRunEventStartAP(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_MSG_P2P_START_AP_T prP2pStartAPMsg = (P_MSG_P2P_START_AP_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo = + (P_P2P_CONNECTION_REQ_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = + (P_P2P_SPECIFIC_BSS_INFO_T)NULL; +#if CFG_SUPPORT_DBDC + CNM_DBDC_CAP_T rDbdcCap; +#endif + + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventStartAP\n"); + + prP2pStartAPMsg = (P_MSG_P2P_START_AP_T)prMsgHdr; + + prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pStartAPMsg->ucRoleIdx); + + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventStartAP with Role(%d)\n", + prP2pStartAPMsg->ucRoleIdx); + + if (!prP2pRoleFsmInfo) { + DBGLOG( + P2P, ERROR, + "p2pRoleFsmRunEventStartAP: Corresponding P2P Role FSM empty: %d.\n", + prP2pStartAPMsg->ucRoleIdx); + goto error; + } + + prP2pBssInfo = prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex]; + prP2pSpecificBssInfo = + prAdapter->rWifiVar.prP2pSpecificBssInfo[prP2pBssInfo->u4PrivateData]; + prP2pConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo); + + if (prP2pStartAPMsg->u4BcnInterval) { + DBGLOG(P2P, TRACE, "Beacon interval updated to :%ld\n", + prP2pStartAPMsg->u4BcnInterval); + prP2pBssInfo->u2BeaconInterval = (u16)prP2pStartAPMsg->u4BcnInterval; + } else if (prP2pBssInfo->u2BeaconInterval == 0) { + prP2pBssInfo->u2BeaconInterval = DOT11_BEACON_PERIOD_DEFAULT; + } + + if (prP2pStartAPMsg->u4DtimPeriod) { + DBGLOG(P2P, TRACE, "DTIM interval updated to :%ld\n", + prP2pStartAPMsg->u4DtimPeriod); + prP2pBssInfo->ucDTIMPeriod = (u8)prP2pStartAPMsg->u4DtimPeriod; + } else if (prP2pBssInfo->ucDTIMPeriod == 0) { + prP2pBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; + } + + if (prP2pStartAPMsg->u2SsidLen != 0) { + kalMemCopy(prP2pConnReqInfo->rSsidStruct.aucSsid, + prP2pStartAPMsg->aucSsid, prP2pStartAPMsg->u2SsidLen); + prP2pConnReqInfo->rSsidStruct.ucSsidLen = + prP2pSpecificBssInfo->u2GroupSsidLen = prP2pStartAPMsg->u2SsidLen; + kalMemCopy(prP2pSpecificBssInfo->aucGroupSsid, prP2pStartAPMsg->aucSsid, + prP2pStartAPMsg->u2SsidLen); + } + + if (p2pFuncIsAPMode( + prAdapter->rWifiVar.prP2PConnSettings[prP2pStartAPMsg->ucRoleIdx])) + { + prP2pConnReqInfo->eConnRequest = P2P_CONNECTION_TYPE_PURE_AP; + + /* Overwrite AP channel */ + if (prAdapter->rWifiVar.ucApChannel && + prAdapter->rWifiVar.ucApChnlDefFromCfg) { + prP2pConnReqInfo->rChannelInfo.ucChannelNum = + prAdapter->rWifiVar.ucApChannel; + + if (prAdapter->rWifiVar.ucApChannel <= 14) { + prP2pConnReqInfo->rChannelInfo.eBand = BAND_2G4; + } else { + prP2pConnReqInfo->rChannelInfo.eBand = BAND_5G; + } + } + } else { + prP2pConnReqInfo->eConnRequest = P2P_CONNECTION_TYPE_GO; + } + + /* Clear current AP's STA_RECORD_T and current AID to prevent + * using previous p2p connection state. This is needed because + * upper layer may add keys before we start SAP/GO. + */ + prP2pBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + prP2pBssInfo->u2AssocId = 0; + + /* Clear list to ensure no client staRec */ + if (bssGetClientCount(prAdapter, prP2pBssInfo) != 0) { + DBGLOG(P2P, WARN, "Clear list to ensure no empty/client staRec\n"); + bssInitializeClientList(prAdapter, prP2pBssInfo); + } + + /* The supplicant may start AP before rP2pRoleFsmTimeoutTimer is time + * out */ + /* We need to make sure the BSS was deactivated and all StaRec can be + * free */ + if (timerPendingTimer(&(prP2pRoleFsmInfo->rP2pRoleFsmTimeoutTimer))) { + /* call p2pRoleFsmRunEventTimeout() to deactive BSS and free + * channel */ + p2pRoleFsmRunEventTimeout(prAdapter, (unsigned long)prP2pRoleFsmInfo); + cnmTimerStopTimer(prAdapter, + &(prP2pRoleFsmInfo->rP2pRoleFsmTimeoutTimer)); + } + +#if (CFG_SUPPORT_DFS_MASTER == 1) + if (timerPendingTimer(&(prP2pRoleFsmInfo->rDfsShutDownTimer))) { + DBGLOG(P2P, INFO, + "p2pRoleFsmRunEventStartAP: Stop DFS shut down timer.\n"); + cnmTimerStopTimer(prAdapter, &(prP2pRoleFsmInfo->rDfsShutDownTimer)); + } + + /* Check if Channel is DFS Available State. If yes, Change DFS State and + * Start RDD */ + if ((prP2pConnReqInfo->u4ChnlDfsState == NL80211_DFS_AVAILABLE) && + (p2pFuncGetDfsState() != DFS_STATE_ACTIVE)) { +#ifndef CFG_SUPPORT_DISABLE_SAP_DFS_RDD + p2pFuncSetDfsState(DFS_STATE_ACTIVE); + p2pFuncStartRdd(prAdapter, prP2pRoleFsmInfo->ucBssIndex); +#endif + } +#endif + +#if (CFG_HW_WMM_BY_BSS == 1) + if (prP2pBssInfo->fgIsWmmInited == false) { + prP2pBssInfo->ucWmmQueSet = + cnmWmmIndexDecision(prAdapter, prP2pBssInfo); + } + prP2pBssInfo->eBand = prP2pConnReqInfo->rChannelInfo.eBand; +#endif +#if CFG_SUPPORT_DBDC + cnmDbdcEnableDecision(prAdapter, prP2pBssInfo->ucBssIndex, + prP2pConnReqInfo->rChannelInfo.eBand); + cnmGetDbdcCapability(prAdapter, prP2pBssInfo->ucBssIndex, + prP2pConnReqInfo->rChannelInfo.eBand, + prP2pConnReqInfo->rChannelInfo.ucChannelNum, + wlanGetSupportNss(prAdapter, prP2pBssInfo->ucBssIndex), + &rDbdcCap); + + DBGLOG(P2P, STATE, "p2pRoleFsmRunEventStartAP: start AP at CH %u NSS=%u.\n", + prP2pConnReqInfo->rChannelInfo.ucChannelNum, rDbdcCap.ucNss); + + prP2pBssInfo->eDBDCBand = ENUM_BAND_AUTO; + prP2pBssInfo->ucNss = rDbdcCap.ucNss; +#if (CFG_HW_WMM_BY_BSS == 0) + prP2pBssInfo->ucWmmQueSet = rDbdcCap.ucWmmSetIndex; +#endif +#endif + prP2pBssInfo->eHiddenSsidType = prP2pStartAPMsg->ucHiddenSsidType; + + /* + * beacon content is related with Nss number , + * need to update because of modification + */ + bssUpdateBeaconContent(prAdapter, prP2pBssInfo->ucBssIndex); + + if ((prP2pBssInfo->eCurrentOPMode != OP_MODE_ACCESS_POINT) || + (prP2pBssInfo->eIntendOPMode != OP_MODE_NUM)) { + /* 1. No switch to AP mode. + * 2. Not started yet. + */ + + if (prP2pRoleFsmInfo->eCurrentState != + P2P_ROLE_STATE_AP_CHNL_DETECTION && + prP2pRoleFsmInfo->eCurrentState != P2P_ROLE_STATE_IDLE) { + /* Make sure the state is in IDLE state. */ + p2pRoleFsmRunEventAbort(prAdapter, prP2pRoleFsmInfo); + } else if (prP2pRoleFsmInfo->eCurrentState == + P2P_ROLE_STATE_AP_CHNL_DETECTION) { + goto error; + } + + /* Leave IDLE state. */ + SET_NET_PWR_STATE_ACTIVE(prAdapter, prP2pBssInfo->ucBssIndex); + prP2pBssInfo->eIntendOPMode = OP_MODE_ACCESS_POINT; + + if (prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum != 0) { + DBGLOG(P2P, INFO, "Role(%d) StartAP at CH(%d)\n", + prP2pStartAPMsg->ucRoleIdx, + prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum); + + p2pRoleStatePrepare_To_REQING_CHANNEL_STATE( + prAdapter, + GET_BSS_INFO_BY_INDEX(prAdapter, prP2pRoleFsmInfo->ucBssIndex), + &(prP2pRoleFsmInfo->rConnReqInfo), + &(prP2pRoleFsmInfo->rChnlReqInfo)); + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_REQING_CHANNEL); + } else { + DBGLOG(P2P, INFO, "Role(%d) StartAP Scan for working channel\n", + prP2pStartAPMsg->ucRoleIdx); + + /* For AP/GO mode with specific channel or non-specific + * channel. */ + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_AP_CHNL_DETECTION); + } + } + +error: + cnmMemFree(prAdapter, prMsgHdr); +} + +void p2pRoleFsmRunEventDelIface(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_MSG_P2P_DEL_IFACE_T prP2pDelIfaceMsg = (P_MSG_P2P_DEL_IFACE_T)NULL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + u8 ucRoleIdx; + P_GL_P2P_INFO_T prP2pInfo = (P_GL_P2P_INFO_T)NULL; + + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventDelIface\n"); + + prGlueInfo = prAdapter->prGlueInfo; + if (prGlueInfo == NULL) { + DBGLOG(P2P, ERROR, "prGlueInfo shouldn't be NULL!\n"); + goto error; + } + + prP2pDelIfaceMsg = (P_MSG_P2P_DEL_IFACE_T)prMsgHdr; + ucRoleIdx = prP2pDelIfaceMsg->ucRoleIdx; + prAdapter = prGlueInfo->prAdapter; + prP2pInfo = prGlueInfo->prP2PInfo[ucRoleIdx]; + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, ucRoleIdx); + if (!prP2pRoleFsmInfo) { + DBGLOG( + P2P, ERROR, + "p2pRoleFsmRunEventDelIface: Corresponding P2P Role FSM empty: %d.\n", + prP2pDelIfaceMsg->ucRoleIdx); + goto error; + } + + prP2pBssInfo = prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex]; + + /* The state is in disconnecting and can not change any BSS status */ + if (IS_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex) && + IS_NET_ACTIVE(prAdapter, prP2pBssInfo->ucBssIndex)) { + DBGLOG(P2P, TRACE, "under deauth procedure, Quit.\n"); + } else { + /*p2pFuncDissolve(prAdapter, prP2pBssInfo, true, + * REASON_CODE_DEAUTH_LEAVING_BSS);*/ + + SET_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex); + + /* Function Dissolve should already enter IDLE state. */ + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_IDLE); + + p2pRoleFsmRunEventAbort(prAdapter, prP2pRoleFsmInfo); + + /* Clear CmdQue */ + kalClearMgmtFramesByBssIdx(prAdapter->prGlueInfo, + prP2pBssInfo->ucBssIndex); + kalClearSecurityFramesByBssIdx(prAdapter->prGlueInfo, + prP2pBssInfo->ucBssIndex); + /* Clear PendingTxMsdu */ + nicFreePendingTxMsduInfoByBssIdx(prAdapter, prP2pBssInfo->ucBssIndex); + + /* Deactivate BSS. */ + UNSET_NET_ACTIVE(prAdapter, prP2pRoleFsmInfo->ucBssIndex); + + nicDeactivateNetwork(prAdapter, prP2pRoleFsmInfo->ucBssIndex); + nicUpdateBss(prAdapter, prP2pRoleFsmInfo->ucBssIndex); + } + +error: + cnmMemFree(prAdapter, prMsgHdr); +} + +void p2pRoleFsmRunEventStopAP(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_MSG_P2P_SWITCH_OP_MODE_T prP2pSwitchMode = + (P_MSG_P2P_SWITCH_OP_MODE_T)NULL; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_STA_RECORD_T prCurrStaRec; + P_LINK_T prClientList; + + prP2pSwitchMode = (P_MSG_P2P_SWITCH_OP_MODE_T)prMsgHdr; + + prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pSwitchMode->ucRoleIdx); + + if (!prP2pRoleFsmInfo) { + DBGLOG( + P2P, ERROR, + "p2pRoleFsmRunEventStopAP: Corresponding P2P Role FSM empty: %d.\n", + prP2pSwitchMode->ucRoleIdx); + goto error; + } + + prP2pBssInfo = prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex]; + + if (!prP2pBssInfo) { + DBGLOG(P2P, ERROR, + "prP2pBssInfo of prP2pRoleFsmInfo->ucBssIndex %d is NULL!\n", + prP2pRoleFsmInfo->ucBssIndex); + goto error; + } + +#if (CFG_SUPPORT_DFS_MASTER == 1) + p2pFuncSetDfsState(DFS_STATE_INACTIVE); + p2pFuncStopRdd(prAdapter, prP2pBssInfo->ucBssIndex); +#endif + + if (prP2pRoleFsmInfo->eCurrentState != P2P_ROLE_STATE_REQING_CHANNEL) { + p2pFuncStopGO(prAdapter, prP2pBssInfo); + + /* Start all Deauth done timer for all client */ + prClientList = &prP2pBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH_ENTRY(prCurrStaRec, prClientList, rLinkEntry, + STA_RECORD_T){ + ASSERT(prCurrStaRec); + /* Do not restart timer if the timer is pending, */ + /* (start in p2pRoleFsmRunEventConnectionAbort()) */ + if (!timerPendingTimer(&(prCurrStaRec->rDeauthTxDoneTimer))) { + cnmTimerInitTimer( + prAdapter, &(prCurrStaRec->rDeauthTxDoneTimer), + (PFN_MGMT_TIMEOUT_FUNC)p2pRoleFsmDeauthTimeout, + (unsigned long)prCurrStaRec); + + cnmTimerStartTimer(prAdapter, + &(prCurrStaRec->rDeauthTxDoneTimer), + P2P_DEAUTH_TIMEOUT_TIME_MS); + } + } + } + + SET_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex); + + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, P2P_ROLE_STATE_IDLE); + +error: + cnmMemFree(prAdapter, prMsgHdr); +} + +#if (CFG_SUPPORT_DFS_MASTER == 1) +#if CFG_SUPPORT_DBDC_TC6 +void p2pRoleFsmRunEventDfsCac(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_MSG_P2P_DFS_CAC_T prP2pDfsCacMsg = (P_MSG_P2P_DFS_CAC_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo = + (P_P2P_CONNECTION_REQ_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; +#if CFG_SUPPORT_DBDC + CNM_DBDC_CAP_T rDbdcCap; +#endif + + DBGLOG(P2P, STATE, "p2pRoleFsmRunEventDfsCac\n"); + + prP2pDfsCacMsg = (P_MSG_P2P_DFS_CAC_T)prMsgHdr; + + prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pDfsCacMsg->ucRoleIdx); + + prP2pRoleFsmInfo->rChannelWidth = prP2pDfsCacMsg->eChannelWidth; + + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventDfsCac with Role(%d)\n", + prP2pDfsCacMsg->ucRoleIdx); + + if (!prP2pRoleFsmInfo) { + DBGLOG( + P2P, ERROR, + "p2pRoleFsmRunEventDfsCac: Corresponding P2P Role FSM empty: %d.\n", + prP2pDfsCacMsg->ucRoleIdx); + goto error; + } + + if (timerPendingTimer(&(prP2pRoleFsmInfo->rDfsShutDownTimer))) { + DBGLOG(P2P, INFO, + "p2pRoleFsmRunEventDfsCac: Stop DFS shut down timer.\n"); + cnmTimerStopTimer(prAdapter, &(prP2pRoleFsmInfo->rDfsShutDownTimer)); + } + + prP2pBssInfo = prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex]; + + prP2pConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo); + + if (p2pFuncIsAPMode( + prAdapter->rWifiVar.prP2PConnSettings[prP2pDfsCacMsg->ucRoleIdx])) { + prP2pConnReqInfo->eConnRequest = P2P_CONNECTION_TYPE_PURE_AP; + } else { + prP2pConnReqInfo->eConnRequest = P2P_CONNECTION_TYPE_GO; + } + +#if (CFG_HW_WMM_BY_BSS == 1) + if (prP2pBssInfo->fgIsWmmInited == false) { + prP2pBssInfo->ucWmmQueSet = + cnmWmmIndexDecision(prAdapter, prP2pBssInfo); + } + prP2pBssInfo->eBand = prP2pConnReqInfo->rChannelInfo.eBand; +#endif +#if CFG_SUPPORT_DBDC + cnmDbdcEnableDecision(prAdapter, prP2pBssInfo->ucBssIndex, + prP2pConnReqInfo->rChannelInfo.eBand); + cnmGetDbdcCapability(prAdapter, prP2pBssInfo->ucBssIndex, + prP2pConnReqInfo->rChannelInfo.eBand, + prP2pConnReqInfo->rChannelInfo.ucChannelNum, + prAdapter->rWifiVar.ucNSS, &rDbdcCap); + + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventDfsCac: Set channel at CH %u.\n", + prP2pConnReqInfo->rChannelInfo.ucChannelNum); + + prP2pBssInfo->eDBDCBand = ENUM_BAND_AUTO; + prP2pBssInfo->ucNss = rDbdcCap.ucNss; +#if (CFG_HW_WMM_BY_BSS == 0) + prP2pBssInfo->ucWmmQueSet = rDbdcCap.ucWmmSetIndex; +#endif + + if (prAdapter->rWifiVar.fgDbDcModeEn == true) { + DBGLOG(P2P, INFO, "Delay DFS CAC for DBDC Switch: %d sec\n", + P2P_DFS_CAC_DELAY_TIME_MS / 1000); + cnmTimerStartTimer(prAdapter, &(prP2pRoleFsmInfo->rDfsStartCacTimer), + P2P_DFS_CAC_DELAY_TIME_MS); + } else { + DBGLOG(P2P, INFO, "Start DFS CAC immediately\n"); + cnmTimerStartTimer(prAdapter, &(prP2pRoleFsmInfo->rDfsStartCacTimer), + 0); + } +#endif + +error: + cnmMemFree(prAdapter, prMsgHdr); +} + +void p2pRoleFsmRunEventStartDfsCacTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)ulParamPtr; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventStartDfsCacTimeout\n"); + + if (timerPendingTimer(&prAdapter->rWifiVar.rDBDCReconnectCountDown)) { + DBGLOG(CNM, INFO, "DBDC reconnect timer protection still on\n"); + DBGLOG(P2P, INFO, "Extend DFS CAC Delay for another %d sec\n", + P2P_DFS_CAC_DELAY_TIME_MS / 1000); + cnmTimerStartTimer(prAdapter, &(prP2pRoleFsmInfo->rDfsStartCacTimer), + P2P_DFS_CAC_DELAY_TIME_MS); + return; + } + + if (prP2pRoleFsmInfo->eCurrentState != P2P_ROLE_STATE_IDLE) { + /* Make sure the state is in IDLE state. */ + p2pRoleFsmRunEventAbort(prAdapter, prP2pRoleFsmInfo); + } + + prP2pBssInfo = prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex]; + + /* Leave IDLE state. */ + SET_NET_PWR_STATE_ACTIVE(prAdapter, prP2pBssInfo->ucBssIndex); + + prP2pBssInfo->eIntendOPMode = OP_MODE_ACCESS_POINT; + prP2pBssInfo->fgIsDfsActive = true; + + if (prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum != 0) { + DBGLOG(P2P, INFO, "Role(%d) Set channel at CH(%d)\n", + prP2pRoleFsmInfo->ucRoleIndex, + prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum); + + p2pRoleStatePrepare_To_DFS_CAC_STATE( + prAdapter, + GET_BSS_INFO_BY_INDEX(prAdapter, prP2pRoleFsmInfo->ucBssIndex), + prP2pRoleFsmInfo->rChannelWidth, &(prP2pRoleFsmInfo->rConnReqInfo), + &(prP2pRoleFsmInfo->rChnlReqInfo)); + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_DFS_CAC); + } else { + DBGLOG(P2P, ERROR, + "prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum %d " + "shouldn't be 0\n"); + } +} /*p2pRoleFsmRunEventDfsCac*/ + +#else + +void p2pRoleFsmRunEventDfsCac(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_MSG_P2P_DFS_CAC_T prP2pDfsCacMsg = (P_MSG_P2P_DFS_CAC_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo = + (P_P2P_CONNECTION_REQ_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + ENUM_CHANNEL_WIDTH_T rChannelWidth; +#if CFG_SUPPORT_DBDC + CNM_DBDC_CAP_T rDbdcCap; +#endif + + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventDfsCac\n"); + + prP2pDfsCacMsg = (P_MSG_P2P_DFS_CAC_T)prMsgHdr; + + rChannelWidth = prP2pDfsCacMsg->eChannelWidth; + + prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pDfsCacMsg->ucRoleIdx); + + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventDfsCac with Role(%d)\n", + prP2pDfsCacMsg->ucRoleIdx); + + if (!prP2pRoleFsmInfo) { + DBGLOG( + P2P, ERROR, + "p2pRoleFsmRunEventDfsCac: Corresponding P2P Role FSM empty: %d.\n", + prP2pDfsCacMsg->ucRoleIdx); + goto error; + } + + if (timerPendingTimer(&(prP2pRoleFsmInfo->rDfsShutDownTimer))) { + DBGLOG(P2P, INFO, + "p2pRoleFsmRunEventDfsCac: Stop DFS shut down timer.\n"); + cnmTimerStopTimer(prAdapter, &(prP2pRoleFsmInfo->rDfsShutDownTimer)); + } + + prP2pBssInfo = prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex]; + + prP2pConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo); + + if (p2pFuncIsAPMode( + prAdapter->rWifiVar.prP2PConnSettings[prP2pDfsCacMsg->ucRoleIdx])) { + prP2pConnReqInfo->eConnRequest = P2P_CONNECTION_TYPE_PURE_AP; + } else { + prP2pConnReqInfo->eConnRequest = P2P_CONNECTION_TYPE_GO; + } + +#if (CFG_HW_WMM_BY_BSS == 1) + if (prP2pBssInfo->fgIsWmmInited == false) { + prP2pBssInfo->ucWmmQueSet = + cnmWmmIndexDecision(prAdapter, prP2pBssInfo); + } + prP2pBssInfo->eBand = prP2pConnReqInfo->rChannelInfo.eBand; +#endif +#if CFG_SUPPORT_DBDC + cnmDbdcEnableDecision(prAdapter, prP2pBssInfo->ucBssIndex, + prP2pConnReqInfo->rChannelInfo.eBand); + cnmGetDbdcCapability(prAdapter, prP2pBssInfo->ucBssIndex, + prP2pConnReqInfo->rChannelInfo.eBand, + prP2pConnReqInfo->rChannelInfo.ucChannelNum, + prAdapter->rWifiVar.ucNSS, &rDbdcCap); + + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventDfsCac: Set channel at CH %u.\n", + prP2pConnReqInfo->rChannelInfo.ucChannelNum); + + prP2pBssInfo->eDBDCBand = ENUM_BAND_AUTO; + prP2pBssInfo->ucNss = rDbdcCap.ucNss; +#if (CFG_HW_WMM_BY_BSS == 0) + prP2pBssInfo->ucWmmQueSet = rDbdcCap.ucWmmSetIndex; +#endif +#endif + + if (prP2pRoleFsmInfo->eCurrentState != P2P_ROLE_STATE_IDLE) { + /* Make sure the state is in IDLE state. */ + p2pRoleFsmRunEventAbort(prAdapter, prP2pRoleFsmInfo); + } + + /* Leave IDLE state. */ + SET_NET_PWR_STATE_ACTIVE(prAdapter, prP2pBssInfo->ucBssIndex); + + prP2pBssInfo->eIntendOPMode = OP_MODE_ACCESS_POINT; + prP2pBssInfo->fgIsDfsActive = true; + + if (prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum != 0) { + DBGLOG(P2P, INFO, "Role(%d) Set channel at CH(%d)\n", + prP2pDfsCacMsg->ucRoleIdx, + prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum); + + p2pRoleStatePrepare_To_DFS_CAC_STATE( + prAdapter, + GET_BSS_INFO_BY_INDEX(prAdapter, prP2pRoleFsmInfo->ucBssIndex), + rChannelWidth, &(prP2pRoleFsmInfo->rConnReqInfo), + &(prP2pRoleFsmInfo->rChnlReqInfo)); + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_DFS_CAC); + } else { + DBGLOG(P2P, ERROR, + "prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum %d " + "shouldn't be 0\n"); + } + +error: + cnmMemFree(prAdapter, prMsgHdr); +} /*p2pRoleFsmRunEventDfsCac*/ + +#endif + +void p2pRoleFsmRunEventRadarDet(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_MSG_P2P_RADAR_DETECT_T prMsgP2pRddDetMsg; + + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventRadarDet\n"); + + prMsgP2pRddDetMsg = (P_MSG_P2P_RADAR_DETECT_T)prMsgHdr; + + prP2pBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prMsgP2pRddDetMsg->ucBssIndex); + + prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pBssInfo->u4PrivateData); + + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventRadarDet with Role(%d)\n", + prP2pRoleFsmInfo->ucRoleIndex); + + if (prP2pRoleFsmInfo->eCurrentState != P2P_ROLE_STATE_DFS_CAC && + prP2pRoleFsmInfo->eCurrentState != P2P_ROLE_STATE_IDLE) { + DBGLOG(P2P, ERROR, "Wrong prP2pRoleFsmInfo->eCurrentState \"%s\"!", + (prP2pRoleFsmInfo->eCurrentState < P2P_ROLE_STATE_NUM ? + (const char *) + apucDebugP2pRoleState[prP2pRoleFsmInfo->eCurrentState] : + "")); + goto error; + } + + if (p2pFuncGetRadarDetectMode()) { + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventRadarDet: Ignore radar event\n"); + if (prP2pRoleFsmInfo->eCurrentState == P2P_ROLE_STATE_DFS_CAC) { + p2pFuncSetDfsState(DFS_STATE_CHECKING); + } else { + p2pFuncSetDfsState(DFS_STATE_ACTIVE); + } + } else { + if (prP2pRoleFsmInfo->eCurrentState == P2P_ROLE_STATE_DFS_CAC) { + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_IDLE); + } + + kalP2PRddDetectUpdate(prAdapter->prGlueInfo, + prP2pRoleFsmInfo->ucRoleIndex); + cnmTimerStartTimer(prAdapter, &(prP2pRoleFsmInfo->rDfsShutDownTimer), + 5000); + } + + p2pFuncShowRadarInfo(prAdapter, prMsgP2pRddDetMsg->ucBssIndex); + +error: + cnmMemFree(prAdapter, prMsgHdr); +} /*p2pRoleFsmRunEventRadarDet*/ + +void p2pRoleFsmRunEventSetNewChannel(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_MSG_P2P_SET_NEW_CHANNEL_T prMsgP2pSetNewChannelMsg; + + DBGLOG(P2P, STATE, "p2pRoleFsmRunEventSetNewChannel\n"); + + prMsgP2pSetNewChannelMsg = (P_MSG_P2P_SET_NEW_CHANNEL_T)prMsgHdr; + DBGLOG(P2P, STATE, "ucBssIndex:%d\n", prMsgP2pSetNewChannelMsg->ucBssIndex); + + prP2pBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prMsgP2pSetNewChannelMsg->ucBssIndex); + + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO( + prAdapter, prMsgP2pSetNewChannelMsg->ucRoleIdx); + + prP2pRoleFsmInfo->rChnlReqInfo.ucReqChnlNum = + prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum; + prP2pRoleFsmInfo->rChnlReqInfo.eBand = + prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.eBand; + prP2pRoleFsmInfo->rChnlReqInfo.eChannelWidth = + prMsgP2pSetNewChannelMsg->eChannelWidth; + prP2pBssInfo->ucPrimaryChannel = + prP2pRoleFsmInfo->rConnReqInfo.rChannelInfo.ucChannelNum; + + prP2pRoleFsmInfo->rChnlReqInfo.ucCenterFreqS1 = + nicGetVhtS1(prP2pBssInfo->ucPrimaryChannel, + prP2pRoleFsmInfo->rChnlReqInfo.eChannelWidth); + prP2pRoleFsmInfo->rChnlReqInfo.ucCenterFreqS2 = 0; + + cnmMemFree(prAdapter, prMsgHdr); +} /*p2pRoleFsmRunEventCsaDone*/ + +void p2pRoleFsmRunEventCsaDone(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_MSG_P2P_CSA_DONE_T prMsgP2pCsaDoneMsg; + + DBGLOG(P2P, TRACE, "p2pRoleFsmRunEventCsaDone\n"); + + prMsgP2pCsaDoneMsg = (P_MSG_P2P_CSA_DONE_T)prMsgHdr; + + prP2pBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prMsgP2pCsaDoneMsg->ucBssIndex); + + prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pBssInfo->u4PrivateData); + + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_SWITCH_CHANNEL); + + cnmMemFree(prAdapter, prMsgHdr); +} /*p2pRoleFsmRunEventCsaDone*/ + +void p2pRoleFsmRunEventDfsShutDownTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)ulParamPtr; + + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventDfsShutDownTimeout: DFS shut down.\n"); + + p2pFuncSetDfsState(DFS_STATE_INACTIVE); + p2pFuncStopRdd(prAdapter, prP2pRoleFsmInfo->ucBssIndex); +} + +#endif + +void p2pRoleFsmScanTargetBss(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN u8 ucChannelNum, IN ENUM_BAND_T eBand, + IN P_P2P_SSID_STRUCT_T prSsid) +{ + /* Update scan parameter... to scan target device. */ + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = &(prP2pRoleFsmInfo->rScanReqInfo); + + prScanReqInfo->ucNumChannelList = 1; + prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqInfo->eChannelSet = SCAN_CHANNEL_SPECIFIED; + prScanReqInfo->arScanChannelList[0].ucChannelNum = ucChannelNum; + prScanReqInfo->arScanChannelList[0].eBand = eBand; + prScanReqInfo->ucSsidNum = 1; + kalMemCopy(&(prScanReqInfo->arSsidStruct[0]), prSsid, + sizeof(P2P_SSID_STRUCT_T)); + prScanReqInfo->u4BufLength = 0; /* Prevent other P2P ID in IE. */ + prScanReqInfo->fgIsAbort = true; + + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, P2P_ROLE_STATE_SCAN); +} + +void p2pRoleFsmRunEventConnectionRequest(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_MSG_P2P_CONNECTION_REQUEST_T prP2pConnReqMsg = + (P_MSG_P2P_CONNECTION_REQUEST_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = + (P_P2P_CONNECTION_REQ_INFO_T)NULL; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + P_P2P_JOIN_INFO_T prJoinInfo = (P_P2P_JOIN_INFO_T)NULL; +#if CFG_SUPPORT_DBDC + CNM_DBDC_CAP_T rDbdcCap; +#endif + + prP2pConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T)prMsgHdr; + + prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pConnReqMsg->ucRoleIdx); + + if (!prP2pRoleFsmInfo) { + DBGLOG(P2P, ERROR, "Corresponding P2P Role FSM empty: %d.\n", + prP2pConnReqMsg->ucRoleIdx); + goto error; + } + + prP2pBssInfo = prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex]; + + if (!prP2pBssInfo) { + DBGLOG( + P2P, ERROR, + "prP2pRoleFsmInfo->ucBssIndex %d of prAdapter->aprBssInfo is NULL!\n", + prP2pRoleFsmInfo->ucBssIndex); + goto error; + } + + prConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo); + prChnlReqInfo = &(prP2pRoleFsmInfo->rChnlReqInfo); + prJoinInfo = &(prP2pRoleFsmInfo->rJoinInfo); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventConnectionRequest\n"); + + if (prP2pBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + goto error; + } + + /* In case the network is already activated, we need to re-activate + * the network. Otherwise, the connection may be failed in dbdc cases. + */ + if (IS_NET_ACTIVE(prAdapter, prP2pBssInfo->ucBssIndex)) { + UNSET_NET_ACTIVE(prAdapter, prP2pBssInfo->ucBssIndex); + nicDeactivateNetwork(prAdapter, prP2pBssInfo->ucBssIndex); + } + + SET_NET_PWR_STATE_ACTIVE(prAdapter, prP2pBssInfo->ucBssIndex); + + /* In P2P GC case, the interval of two ASSOC flow could be very short, + */ + /* we must start to connect directly before Deauth done */ + prStaRec = prP2pBssInfo->prStaRecOfAP; + if (prStaRec) { + if (timerPendingTimer(&prStaRec->rDeauthTxDoneTimer)) { + cnmTimerStopTimer(prAdapter, &(prStaRec->rDeauthTxDoneTimer)); + p2pRoleFsmDeauthComplete(prAdapter, prStaRec); /* Force + * to + * stop + */ + } + } + /* Make sure the state is in IDLE state. */ + if (prP2pRoleFsmInfo->eCurrentState != P2P_ROLE_STATE_IDLE) { + p2pRoleFsmRunEventAbort(prAdapter, prP2pRoleFsmInfo); + } + /* Update connection request information. */ + prConnReqInfo->eConnRequest = P2P_CONNECTION_TYPE_GC; + COPY_MAC_ADDR(prConnReqInfo->aucBssid, prP2pConnReqMsg->aucBssid); + COPY_MAC_ADDR(prP2pBssInfo->aucOwnMacAddr, prP2pConnReqMsg->aucSrcMacAddr); + kalMemCopy(&(prConnReqInfo->rSsidStruct), &(prP2pConnReqMsg->rSsid), + sizeof(P2P_SSID_STRUCT_T)); + kalMemCopy(prConnReqInfo->aucIEBuf, prP2pConnReqMsg->aucIEBuf, + prP2pConnReqMsg->u4IELen); + prConnReqInfo->u4BufLength = prP2pConnReqMsg->u4IELen; + + /* Find BSS Descriptor first. */ + prJoinInfo->prTargetBssDesc = scanP2pSearchDesc(prAdapter, prConnReqInfo); + + if (prJoinInfo->prTargetBssDesc == NULL) { + p2pRoleFsmScanTargetBss(prAdapter, prP2pRoleFsmInfo, + prP2pConnReqMsg->rChannelInfo.ucChannelNum, + prP2pConnReqMsg->rChannelInfo.eBand, + &(prP2pConnReqMsg->rSsid)); + } else { + prChnlReqInfo->u8Cookie = 0; + prChnlReqInfo->ucReqChnlNum = + prP2pConnReqMsg->rChannelInfo.ucChannelNum; + prChnlReqInfo->eBand = prP2pConnReqMsg->rChannelInfo.eBand; + prChnlReqInfo->eChnlSco = prP2pConnReqMsg->eChnlSco; + prChnlReqInfo->u4MaxInterval = AIS_JOIN_CH_REQUEST_INTERVAL; + prChnlReqInfo->eChnlReqType = CH_REQ_TYPE_JOIN; + + prChnlReqInfo->eChannelWidth = + prJoinInfo->prTargetBssDesc->eChannelWidth; + prChnlReqInfo->ucCenterFreqS1 = + prJoinInfo->prTargetBssDesc->ucCenterFreqS1; + prChnlReqInfo->ucCenterFreqS2 = + prJoinInfo->prTargetBssDesc->ucCenterFreqS2; + + rlmReviseMaxBw(prAdapter, prP2pBssInfo->ucBssIndex, + &prChnlReqInfo->eChnlSco, + (u8 *)&prChnlReqInfo->eChannelWidth, + &prChnlReqInfo->ucCenterFreqS1, + &prChnlReqInfo->ucReqChnlNum); + +#if (CFG_HW_WMM_BY_BSS == 1) + if (prP2pBssInfo->fgIsWmmInited == false) { + prP2pBssInfo->ucWmmQueSet = + cnmWmmIndexDecision(prAdapter, prP2pBssInfo); + } + prP2pBssInfo->eBand = prChnlReqInfo->eBand; +#endif +#if CFG_SUPPORT_DBDC + cnmDbdcEnableDecision(prAdapter, prP2pBssInfo->ucBssIndex, + prChnlReqInfo->eBand); + cnmGetDbdcCapability( + prAdapter, prP2pBssInfo->ucBssIndex, prChnlReqInfo->eBand, + prChnlReqInfo->ucReqChnlNum, + wlanGetSupportNss(prAdapter, prP2pBssInfo->ucBssIndex), &rDbdcCap); + + DBGLOG( + P2P, INFO, + "p2pRoleFsmRunEventConnectionRequest: start GC at CH %u, NSS=%u.\n", + prChnlReqInfo->ucReqChnlNum, rDbdcCap.ucNss); + + prP2pBssInfo->eDBDCBand = ENUM_BAND_AUTO; + prP2pBssInfo->ucNss = rDbdcCap.ucNss; +#if (CFG_HW_WMM_BY_BSS == 0) + prP2pBssInfo->ucWmmQueSet = rDbdcCap.ucWmmSetIndex; +#endif +#endif + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_REQING_CHANNEL); + } + +error: + cnmMemFree(prAdapter, prMsgHdr); +} + +void p2pRoleFsmRunEventConnectionAbort(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_MSG_P2P_CONNECTION_ABORT_T prDisconnMsg = + (P_MSG_P2P_CONNECTION_ABORT_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + + prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T)prMsgHdr; + + prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prDisconnMsg->ucRoleIdx); + + DBGLOG(P2P, TRACE, "p2pFsmRunEventConnectionAbort: Connection Abort.\n"); + + if (!prP2pRoleFsmInfo) { + DBGLOG(P2P, ERROR, + "p2pRoleFsmRunEventConnectionAbort: Corresponding P2P Role FSM " + "empty: %d.\n", + prDisconnMsg->ucRoleIdx); + goto error; + } + + prP2pBssInfo = prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex]; + + if (!prP2pBssInfo) { + DBGLOG( + P2P, ERROR, + "prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex(%d)] is NULL!", + prP2pRoleFsmInfo->ucBssIndex); + goto error; + } + + switch (prP2pBssInfo->eCurrentOPMode) { + case OP_MODE_INFRASTRUCTURE: { + u8 aucBCBSSID[] = BC_BSSID; + + if (!prP2pBssInfo->prStaRecOfAP) { + DBGLOG(P2P, TRACE, "GO's StaRec is NULL\n"); + break; + } + if (UNEQUAL_MAC_ADDR(prP2pBssInfo->prStaRecOfAP->aucMacAddr, + prDisconnMsg->aucTargetID) && + UNEQUAL_MAC_ADDR(prDisconnMsg->aucTargetID, aucBCBSSID)) { + DBGLOG(P2P, TRACE, "Unequal MAC ADDR [" MACSTR ":" MACSTR "]\n", + MAC2STR(prP2pBssInfo->prStaRecOfAP->aucMacAddr), + MAC2STR(prDisconnMsg->aucTargetID)); + break; + } + + kalP2PGCIndicateConnectionStatus(prAdapter->prGlueInfo, + prP2pRoleFsmInfo->ucRoleIndex, NULL, + NULL, 0, 0, + WLAN_STATUS_MEDIA_DISCONNECT); + + prStaRec = prP2pBssInfo->prStaRecOfAP; + + /* Stop rejoin timer if it is started. */ + /* TODO: If it has. */ + + p2pFuncDisconnect(prAdapter, prP2pBssInfo, prStaRec, + prDisconnMsg->fgSendDeauth, + prDisconnMsg->u2ReasonCode, true); + + cnmTimerStopTimer(prAdapter, &(prStaRec->rDeauthTxDoneTimer)); + + cnmTimerInitTimer(prAdapter, &(prStaRec->rDeauthTxDoneTimer), + (PFN_MGMT_TIMEOUT_FUNC)p2pRoleFsmDeauthTimeout, + (unsigned long)prStaRec); + + cnmTimerStartTimer(prAdapter, &(prStaRec->rDeauthTxDoneTimer), + P2P_DEAUTH_TIMEOUT_TIME_MS); + + SET_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex); + + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_IDLE); + } break; + + case OP_MODE_ACCESS_POINT: { + /* Search specific client device, and disconnect. */ + /* 1. Send deauthentication frame. */ + /* 2. Indication: Device disconnect. */ + P_STA_RECORD_T prCurrStaRec = (P_STA_RECORD_T)NULL; + + DBGLOG(P2P, TRACE, "Disconnecting with Target ID: " MACSTR "\n", + MAC2STR(prDisconnMsg->aucTargetID)); + + prCurrStaRec = bssGetClientByMac(prAdapter, prP2pBssInfo, + prDisconnMsg->aucTargetID); + + if (prCurrStaRec) { + DBGLOG(P2P, TRACE, "Disconnecting: " MACSTR "\n", + MAC2STR(prCurrStaRec->aucMacAddr)); + + if (!prDisconnMsg->fgSendDeauth) { + p2pRoleFsmDeauthComplete(prAdapter, prCurrStaRec); + break; + } + + /* Glue layer indication. */ + /* kalP2PGOStationUpdate(prAdapter->prGlueInfo, + * prCurrStaRec, false); */ + + /* Send deauth & do indication. */ + p2pFuncDisconnect(prAdapter, prP2pBssInfo, prCurrStaRec, + prDisconnMsg->fgSendDeauth, + prDisconnMsg->u2ReasonCode, true); + + cnmTimerStopTimer(prAdapter, &(prCurrStaRec->rDeauthTxDoneTimer)); + + cnmTimerInitTimer(prAdapter, &(prCurrStaRec->rDeauthTxDoneTimer), + (PFN_MGMT_TIMEOUT_FUNC)p2pRoleFsmDeauthTimeout, + (unsigned long)prCurrStaRec); + + cnmTimerStartTimer(prAdapter, &(prCurrStaRec->rDeauthTxDoneTimer), + P2P_DEAUTH_TIMEOUT_TIME_MS); +#if CFG_SUPPORT_802_11W + } else if (prP2pBssInfo->u4RsnSelectedAKMSuite == RSN_AKM_SUITE_SAE) { + if (!completion_done(&prP2pBssInfo->rDeauthComp)) { + DBGLOG(P2P, INFO, "Complete rDeauthComp\n"); + complete(&prP2pBssInfo->rDeauthComp); + } + prP2pBssInfo->encryptedDeauthIsInProcess = false; +#endif + } + } break; + + case OP_MODE_P2P_DEVICE: + default: + ASSERT(false); + break; + } + +error: + cnmMemFree(prAdapter, prMsgHdr); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is called when JOIN complete message event is + * received from SAA. + * + * \param[in] prAdapter Pointer of ADAPTER_T + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void p2pRoleFsmRunEventJoinComplete(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_P2P_JOIN_INFO_T prJoinInfo = (P_P2P_JOIN_INFO_T)NULL; + P_MSG_JOIN_COMP_T prJoinCompMsg = (P_MSG_JOIN_COMP_T)NULL; + P_SW_RFB_T prAssocRspSwRfb = (P_SW_RFB_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + prJoinCompMsg = (P_MSG_JOIN_COMP_T)prMsgHdr; + prStaRec = prJoinCompMsg->prStaRec; + prAssocRspSwRfb = prJoinCompMsg->prSwRfb; + + DBGLOG(P2P, TRACE, "P2P BSS %d, Join Complete\n", prStaRec->ucBssIndex); + + ASSERT(prStaRec); + if (!prStaRec) { + DBGLOG(P2P, ERROR, "prJoinCompMsg->prStaRec is NULL!\n"); + goto error; + } + + ASSERT(prStaRec->ucBssIndex < P2P_DEV_BSS_INDEX); + if (!(prStaRec->ucBssIndex < P2P_DEV_BSS_INDEX)) { + DBGLOG(P2P, ERROR, + "prStaRec->ucBssIndex % should < P2P_DEV_BSS_INDEX(%d)!\n", + prStaRec->ucBssIndex, P2P_DEV_BSS_INDEX); + goto error; + } + + prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + ASSERT(prP2pBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE); + if (prP2pBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + DBGLOG( + P2P, ERROR, + "prP2pBssInfo->eCurrentOPMode %d != OP_MODE_INFRASTRUCTURE(%d)!\n", + prP2pBssInfo->eCurrentOPMode, OP_MODE_INFRASTRUCTURE); + goto error; + } + + ASSERT(prP2pBssInfo->u4PrivateData < BSS_P2P_NUM); + if (!(prP2pBssInfo->u4PrivateData < BSS_P2P_NUM)) { + DBGLOG(P2P, ERROR, + "prP2pBssInfo->u4PrivateData %s should < BSS_P2P_NUM(%d)!\n", + prP2pBssInfo->u4PrivateData, BSS_P2P_NUM); + goto error; + } + + prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pBssInfo->u4PrivateData); + + prJoinInfo = &(prP2pRoleFsmInfo->rJoinInfo); + + if (!prJoinInfo->prTargetStaRec) { + DBGLOG(P2P, ERROR, "prJoinInfo->prTargetStaRec is NULL!\n"); + goto error; + } + + /* Check SEQ NUM */ + if (prJoinCompMsg->ucSeqNum == prJoinInfo->ucSeqNumOfReqMsg) { + ASSERT(prStaRec == prJoinInfo->prTargetStaRec); + prJoinInfo->fgIsJoinComplete = true; + + if (prJoinCompMsg->rJoinStatus == WLAN_STATUS_SUCCESS) { + /* 4 <1.1> Change FW's Media State immediately. */ + p2pChangeMediaState(prAdapter, prP2pBssInfo, + PARAM_MEDIA_STATE_CONNECTED); + + /* 4 <1.2> Deactivate previous AP's STA_RECORD_T in + * Driver if have. */ + if ((prP2pBssInfo->prStaRecOfAP) && + (prP2pBssInfo->prStaRecOfAP != prStaRec)) { + cnmStaRecChangeState(prAdapter, prP2pBssInfo->prStaRecOfAP, + STA_STATE_1); + + cnmStaRecFree(prAdapter, prP2pBssInfo->prStaRecOfAP); + + prP2pBssInfo->prStaRecOfAP = NULL; + } + /* 4 <1.3> Update BSS_INFO_T */ + if (prAssocRspSwRfb) { + p2pFuncUpdateBssInfoForJOIN(prAdapter, + prJoinInfo->prTargetBssDesc, + prStaRec, prP2pBssInfo, + prAssocRspSwRfb); + } else { + DBGLOG( + P2P, INFO, + "prAssocRspSwRfb is NULL! Skip p2pFuncUpdateBssInfoForJOIN\n"); + } + + /* 4 <1.4> Activate current AP's STA_RECORD_T in Driver. + */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + +#if CFG_SUPPORT_P2P_RSSI_QUERY + /* <1.5> Update RSSI if necessary */ + nicUpdateRSSI(prAdapter, prP2pBssInfo->ucBssIndex, + (s8)(RCPI_TO_dBm(prStaRec->ucRCPI)), 0); +#endif + + /* 4 <1.6> Indicate Connected Event to Host immediately. + */ + /* Require BSSID, Association ID, Beacon Interval.. from + * AIS_BSS_INFO_T */ + /* p2pIndicationOfMediaStateToHost(prAdapter, + * PARAM_MEDIA_STATE_CONNECTED, prStaRec->aucMacAddr); + */ + if (prJoinInfo->prTargetBssDesc) { + scanReportBss2Cfg80211(prAdapter, BSS_TYPE_P2P_DEVICE, + prJoinInfo->prTargetBssDesc); + } + + kalP2PGCIndicateConnectionStatus( + prAdapter->prGlueInfo, prP2pRoleFsmInfo->ucRoleIndex, + &prP2pRoleFsmInfo->rConnReqInfo, prJoinInfo->aucIEBuf, + prJoinInfo->u4BufLength, prStaRec->u2StatusCode, + WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY); + } else { + /* Join Fail */ + /* 4 <2.1> Redo JOIN process with other Auth Type if + * possible */ + if (p2pFuncRetryJOIN(prAdapter, prStaRec, prJoinInfo) == false) { + P_BSS_DESC_T prBssDesc; + + /* Increase Failure Count */ + prStaRec->ucJoinFailureCount++; + + prBssDesc = prJoinInfo->prTargetBssDesc; + + ASSERT(prBssDesc); + ASSERT(prBssDesc->fgIsConnecting); + + prBssDesc->fgIsConnecting = false; + + if (prStaRec->ucJoinFailureCount >= P2P_SAA_RETRY_COUNT) { + kalP2PGCIndicateConnectionStatus( + prAdapter->prGlueInfo, prP2pRoleFsmInfo->ucRoleIndex, + &prP2pRoleFsmInfo->rConnReqInfo, prJoinInfo->aucIEBuf, + prJoinInfo->u4BufLength, prStaRec->u2StatusCode, + WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY); + + /* Reset p2p state */ + prJoinInfo->prTargetBssDesc = NULL; + prJoinInfo->prTargetStaRec = NULL; + + SET_NET_PWR_STATE_IDLE(prAdapter, prP2pBssInfo->ucBssIndex); + + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_IDLE); + + p2pFuncStopComplete(prAdapter, prP2pBssInfo); + } + } + } + } + + if (prP2pRoleFsmInfo->eCurrentState == P2P_ROLE_STATE_GC_JOIN) { + if (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + /* do nothing & wait for timeout or EAPOL 4/4 TX done */ + } else { + P_BSS_DESC_T prBssDesc; + P2P_SSID_STRUCT_T rSsid; + + prBssDesc = prJoinInfo->prTargetBssDesc; + + if (prBssDesc) { + COPY_SSID(rSsid.aucSsid, rSsid.ucSsidLen, prBssDesc->aucSSID, + prBssDesc->ucSSIDLen); + p2pRoleFsmScanTargetBss(prAdapter, prP2pRoleFsmInfo, + prBssDesc->ucChannelNum, + prBssDesc->eBand, &rSsid); + } + } + } + +error: + if (prAssocRspSwRfb) { + nicRxReturnRFB(prAdapter, prAssocRspSwRfb); + } + + cnmMemFree(prAdapter, prMsgHdr); +} + +void p2pRoleFsmRunEventScanRequest(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_P2P_SCAN_REQUEST_T prP2pScanReqMsg = (P_MSG_P2P_SCAN_REQUEST_T)NULL; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T)NULL; + u32 u4ChnlListSize = 0; + P_P2P_SSID_STRUCT_T prP2pSsidStruct = (P_P2P_SSID_STRUCT_T)NULL; + P_BSS_INFO_T prP2pBssInfo = NULL; + + prP2pScanReqMsg = (P_MSG_P2P_SCAN_REQUEST_T)prMsgHdr; + + prP2pBssInfo = prAdapter->aprBssInfo[prP2pScanReqMsg->ucBssIdx]; + + prP2pRoleFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prP2pBssInfo->u4PrivateData); + + if (!prP2pRoleFsmInfo) { + DBGLOG(P2P, ERROR, "prP2pRoleFsmInfo is NULL!"); + goto error; + } + + prP2pScanReqMsg = (P_MSG_P2P_SCAN_REQUEST_T)prMsgHdr; + prScanReqInfo = &(prP2pRoleFsmInfo->rScanReqInfo); + + DBGLOG(P2P, TRACE, "p2pDevFsmRunEventScanRequest\n"); + + /* Do we need to be in IDLE state? */ + /* p2pDevFsmRunEventAbort(prAdapter, prP2pDevFsmInfo); */ + + ASSERT(prScanReqInfo->fgIsScanRequest == false); + + prScanReqInfo->fgIsAbort = true; + prScanReqInfo->eScanType = prP2pScanReqMsg->eScanType; + + if (prP2pScanReqMsg->u4NumChannel) { + prScanReqInfo->eChannelSet = SCAN_CHANNEL_SPECIFIED; + + /* Channel List */ + prScanReqInfo->ucNumChannelList = prP2pScanReqMsg->u4NumChannel; + DBGLOG(P2P, TRACE, "Scan Request Channel List Number: %d\n", + prScanReqInfo->ucNumChannelList); + if (prScanReqInfo->ucNumChannelList > MAXIMUM_OPERATION_CHANNEL_LIST) { + DBGLOG(P2P, TRACE, + "Channel List Number Overloaded: %d, change to: %d\n", + prScanReqInfo->ucNumChannelList, + MAXIMUM_OPERATION_CHANNEL_LIST); + prScanReqInfo->ucNumChannelList = MAXIMUM_OPERATION_CHANNEL_LIST; + } + + u4ChnlListSize = + sizeof(RF_CHANNEL_INFO_T) * prScanReqInfo->ucNumChannelList; + kalMemCopy(prScanReqInfo->arScanChannelList, + prP2pScanReqMsg->arChannelListInfo, u4ChnlListSize); + } else { + /* If channel number is ZERO. + * It means do a FULL channel scan. + */ + prScanReqInfo->eChannelSet = SCAN_CHANNEL_FULL; + } + + /* SSID */ + prP2pSsidStruct = prP2pScanReqMsg->prSSID; + for (prScanReqInfo->ucSsidNum = 0; + prScanReqInfo->ucSsidNum < prP2pScanReqMsg->i4SsidNum; + prScanReqInfo->ucSsidNum++) { + kalMemCopy( + prScanReqInfo->arSsidStruct[prScanReqInfo->ucSsidNum].aucSsid, + prP2pSsidStruct->aucSsid, prP2pSsidStruct->ucSsidLen); + + prScanReqInfo->arSsidStruct[prScanReqInfo->ucSsidNum].ucSsidLen = + prP2pSsidStruct->ucSsidLen; + + prP2pSsidStruct++; + } + + /* IE Buffer */ + kalMemCopy(prScanReqInfo->aucIEBuf, prP2pScanReqMsg->pucIEBuf, + prP2pScanReqMsg->u4IELen); + + prScanReqInfo->u4BufLength = prP2pScanReqMsg->u4IELen; + + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, P2P_ROLE_STATE_SCAN); + +error: + cnmMemFree(prAdapter, prMsgHdr); +} + +void p2pRoleFsmRunEventScanDone(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo) +{ + P_MSG_SCN_SCAN_DONE prScanDoneMsg = (P_MSG_SCN_SCAN_DONE)prMsgHdr; + P_P2P_SCAN_REQ_INFO_T prScanReqInfo = (P_P2P_SCAN_REQ_INFO_T)NULL; + ENUM_P2P_ROLE_STATE_T eNextState = P2P_ROLE_STATE_NUM; + P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = + &(prP2pRoleFsmInfo->rConnReqInfo); + P_P2P_JOIN_INFO_T prP2pJoinInfo = &(prP2pRoleFsmInfo->rJoinInfo); + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; +#if CFG_SUPPORT_DBDC + CNM_DBDC_CAP_T rDbdcCap; +#endif + + if (prP2pRoleFsmInfo == NULL) { + DBGLOG(P2P, TRACE, "prP2pRoleFsmInfo is NULL\n"); + goto error; + } + + DBGLOG(P2P, TRACE, "P2P Role Scan Done Event\n"); + + prScanReqInfo = &(prP2pRoleFsmInfo->rScanReqInfo); + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE)prMsgHdr; + + if (prScanDoneMsg->ucSeqNum != prScanReqInfo->ucSeqNumOfScnMsg) { + /* Scan Done message sequence number mismatch. + * Ignore this event. (P2P FSM issue two scan events.) + */ + /* The scan request has been cancelled. + * Ignore this message. It is possible. + */ + DBGLOG(P2P, TRACE, + "P2P Role Scan Don SeqNum Received:%d <-> P2P Role Fsm SCAN Seq " + "Issued:%d\n", + prScanDoneMsg->ucSeqNum, prScanReqInfo->ucSeqNumOfScnMsg); + + goto error; + } + + switch (prP2pRoleFsmInfo->eCurrentState) { + case P2P_ROLE_STATE_SCAN: + prScanReqInfo->fgIsAbort = false; + + if (prConnReqInfo->eConnRequest == P2P_CONNECTION_TYPE_GC) { + prP2pJoinInfo->prTargetBssDesc = p2pFuncKeepOnConnection( + prAdapter, prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex], + prConnReqInfo, &prP2pRoleFsmInfo->rChnlReqInfo, + &prP2pRoleFsmInfo->rScanReqInfo); + if ((prP2pJoinInfo->prTargetBssDesc) == NULL) { + eNextState = P2P_ROLE_STATE_SCAN; + } else { + prP2pBssInfo = + prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex]; + if (!prP2pBssInfo) { + break; + } + prChnlReqInfo = &(prP2pRoleFsmInfo->rChnlReqInfo); + if (!prChnlReqInfo) { + break; + } +#if (CFG_HW_WMM_BY_BSS == 1) + if (prP2pBssInfo->fgIsWmmInited == false) { + prP2pBssInfo->ucWmmQueSet = + cnmWmmIndexDecision(prAdapter, prP2pBssInfo); + } + prP2pBssInfo->eBand = prChnlReqInfo->eBand; +#endif +#if CFG_SUPPORT_DBDC + cnmDbdcEnableDecision(prAdapter, prP2pRoleFsmInfo->ucBssIndex, + prChnlReqInfo->eBand); + cnmGetDbdcCapability( + prAdapter, prP2pRoleFsmInfo->ucBssIndex, + prChnlReqInfo->eBand, prChnlReqInfo->ucReqChnlNum, + wlanGetSupportNss(prAdapter, prP2pRoleFsmInfo->ucBssIndex), + &rDbdcCap); + + DBGLOG( + P2P, INFO, + "p2pRoleFsmRunEventScanDone: start GC at CH %u, NSS=%u.\n", + prChnlReqInfo->ucReqChnlNum, rDbdcCap.ucNss); + + prP2pBssInfo->eDBDCBand = ENUM_BAND_AUTO; + prP2pBssInfo->ucNss = rDbdcCap.ucNss; +#if (CFG_HW_WMM_BY_BSS == 0) + prP2pBssInfo->ucWmmQueSet = rDbdcCap.ucWmmSetIndex; +#endif +#endif + /* For GC join. */ + eNextState = P2P_ROLE_STATE_REQING_CHANNEL; + } + } else { + eNextState = P2P_ROLE_STATE_IDLE; + } + break; + + case P2P_ROLE_STATE_AP_CHNL_DETECTION: + eNextState = P2P_ROLE_STATE_REQING_CHANNEL; + break; + + default: + /* Unexpected channel scan done event without being chanceled. + */ + ASSERT(false); + break; + } + + prScanReqInfo->fgIsScanRequest = false; + + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, eNextState); + +error: + cnmMemFree(prAdapter, prMsgHdr); +} + +void p2pRoleFsmRunEventChnlGrant(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo) +{ + P_P2P_CHNL_REQ_INFO_T prChnlReqInfo = (P_P2P_CHNL_REQ_INFO_T)NULL; + P_MSG_CH_GRANT_T prMsgChGrant = (P_MSG_CH_GRANT_T)NULL; +#if (CFG_SUPPORT_DFS_MASTER == 1) + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + u32 u4CacTimeMs; +#endif + u8 ucTokenID = 0; + + if (!prP2pRoleFsmInfo) { + DBGLOG(P2P, ERROR, "prP2pRoleFsmInfo is NULL!\n"); + goto error; + } + + DBGLOG(P2P, TRACE, "P2P Run Event Role Channel Grant\n"); + + prMsgChGrant = (P_MSG_CH_GRANT_T)prMsgHdr; + ucTokenID = prMsgChGrant->ucTokenID; + prChnlReqInfo = &(prP2pRoleFsmInfo->rChnlReqInfo); + +#if (CFG_SUPPORT_DFS_MASTER == 1) + prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsgChGrant->ucBssIndex); +#endif + if (prChnlReqInfo->u4MaxInterval != prMsgChGrant->u4GrantInterval) { + DBGLOG(P2P, WARN, + "P2P Role:%d Request Channel Interval:%d, Grant Interval:%d\n", + prP2pRoleFsmInfo->ucRoleIndex, prChnlReqInfo->u4MaxInterval, + prMsgChGrant->u4GrantInterval); + prChnlReqInfo->u4MaxInterval = prMsgChGrant->u4GrantInterval; + } + + if (ucTokenID == prChnlReqInfo->ucSeqNumOfChReq) { + ENUM_P2P_ROLE_STATE_T eNextState = P2P_ROLE_STATE_NUM; + + switch (prP2pRoleFsmInfo->eCurrentState) { + case P2P_ROLE_STATE_REQING_CHANNEL: + switch (prChnlReqInfo->eChnlReqType) { + case CH_REQ_TYPE_JOIN: + eNextState = P2P_ROLE_STATE_GC_JOIN; + break; + + case CH_REQ_TYPE_GO_START_BSS: + eNextState = P2P_ROLE_STATE_IDLE; + break; + + default: + DBGLOG( + P2P, WARN, + "p2pRoleFsmRunEventChnlGrant: Invalid Channel Request Type:%d\n", + prChnlReqInfo->eChnlReqType); + ASSERT(false); + break; + } + + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, eNextState); + break; + +#if (CFG_SUPPORT_DFS_MASTER == 1) + case P2P_ROLE_STATE_DFS_CAC: +#ifndef CFG_SUPPORT_DISABLE_SAP_DFS_RDD + p2pFuncStartRdd(prAdapter, prMsgChGrant->ucBssIndex); + + if (p2pFuncCheckWeatherRadarBand(prChnlReqInfo)) { + u4CacTimeMs = P2P_AP_CAC_WEATHER_CHNL_HOLD_TIME_MS; + } else { + u4CacTimeMs = prP2pRoleFsmInfo->rChnlReqInfo.u4MaxInterval; + } +#else + u4CacTimeMs = 0; +#endif + + if (p2pFuncIsManualCac()) { + u4CacTimeMs = p2pFuncGetDriverCacTime() * 1000; + } else { + p2pFuncSetDriverCacTime(u4CacTimeMs / 1000); + } + + cnmTimerStartTimer(prAdapter, + &(prP2pRoleFsmInfo->rP2pRoleFsmTimeoutTimer), + u4CacTimeMs); + + p2pFuncRecordCacStartBootTime(); + + p2pFuncSetDfsState(DFS_STATE_CHECKING); + + DBGLOG(P2P, INFO, "p2pRoleFsmRunEventChnlGrant: CAC time = %ds\n", + u4CacTimeMs / 1000); + break; + + case P2P_ROLE_STATE_SWITCH_CHANNEL: + p2pFuncDfsSwitchCh(prAdapter, prP2pBssInfo, + prP2pRoleFsmInfo->rChnlReqInfo); + p2pRoleFsmStateTransition(prAdapter, prP2pRoleFsmInfo, + P2P_ROLE_STATE_IDLE); + break; + +#endif + default: + /* Channel is granted under unexpected state. + * Driver should cancel channel privileagea before + * leaving the states. + */ + if (IS_BSS_ACTIVE( + prAdapter->aprBssInfo[prP2pRoleFsmInfo->ucBssIndex])) { + DBGLOG(P2P, WARN, + "p2pRoleFsmRunEventChnlGrant: Invalid CurrentState:%d\n", + prP2pRoleFsmInfo->eCurrentState); + ASSERT(false); + } + break; + } + } else { + /* Channel requsted, but released. */ + ASSERT(!prChnlReqInfo->fgIsChannelRequested); + if (prChnlReqInfo->fgIsChannelRequested) { + DBGLOG(P2P, ERROR, + "fgIsChannelRequested is true!Channel was requested, but " + "released!\n"); + } + } + +error: + cnmMemFree(prAdapter, prMsgHdr); +} + +/* ////////////////////////////////////// */ +void p2pRoleFsmRunEventDissolve(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + /* TODO: */ + + if (prMsgHdr) { + cnmMemFree(prAdapter, prMsgHdr); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @ This routine update the current MAC table based on the current ACL. + * If ACL change causing an associated STA become un-authorized. This STA + * will be kicked out immediately. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] ucBssIdx Bss index. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void p2pRoleUpdateACLEntry(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx) +{ + u8 bMatchACL = false; + s32 i = 0, i4Ret = 0; + P_LINK_T prClientList; + P_STA_RECORD_T prCurrStaRec, prNextStaRec; + P_BSS_INFO_T prP2pBssInfo; + + if ((!prAdapter) || (ucBssIdx > HW_BSSID_NUM)) { + return; + } + + DBGLOG(P2P, TRACE, "Update ACL Entry ucBssIdx = %d\n", ucBssIdx); + prP2pBssInfo = prAdapter->aprBssInfo[ucBssIdx]; + + /* ACL is disabled. Do nothing about the MAC table. */ + if (prP2pBssInfo->rACL.ePolicy == PARAM_CUSTOM_ACL_POLICY_DISABLE) { + return; + } + + prClientList = &prP2pBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH_ENTRY_SAFE(prCurrStaRec, prNextStaRec, prClientList, + rLinkEntry, STA_RECORD_T){ + bMatchACL = false; + for (i = 0; i < prP2pBssInfo->rACL.u4Num; i++) { + if (EQUAL_MAC_ADDR(prCurrStaRec->aucMacAddr, + prP2pBssInfo->rACL.rEntry[i].aucAddr)) { + bMatchACL = true; + break; + } + } + + if (((!bMatchACL) && + (prP2pBssInfo->rACL.ePolicy == PARAM_CUSTOM_ACL_POLICY_ACCEPT)) || + ((bMatchACL) && + (prP2pBssInfo->rACL.ePolicy == PARAM_CUSTOM_ACL_POLICY_DENY))) { + DBGLOG(P2P, TRACE, "ucBssIdx=%d, ACL Policy=%d\n", ucBssIdx, + prP2pBssInfo->rACL.ePolicy); + + i4Ret = assocSendDisAssocFrame(prAdapter, prCurrStaRec, + STATUS_CODE_REQ_DECLINED); + if (!i4Ret) { + DBGLOG(P2P, TRACE, + "Send DISASSOC to [" MACSTR "], Reason = %d\n", + MAC2STR(prCurrStaRec->aucMacAddr), + STATUS_CODE_REQ_DECLINED); + } + LINK_REMOVE_KNOWN_ENTRY(prClientList, &prCurrStaRec->rLinkEntry); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @ Check if the specified STA pass the Access Control List inspection. + * If fails to pass the checking, then no authentication or association is + * allowed. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] pMacAddr Pointer to the mac address. + * @param[in] ucBssIdx Bss index. + * + * @return true - pass ACL inspection, false - ACL inspection fail + */ +/*----------------------------------------------------------------------------*/ +u8 p2pRoleProcessACLInspection(IN P_ADAPTER_T prAdapter, IN u8 *pMacAddr, + IN u8 ucBssIdx) +{ + u8 bPassACL = true; + s32 i = 0; + P_BSS_INFO_T prP2pBssInfo; + + if ((!prAdapter) || (!pMacAddr) || (ucBssIdx > HW_BSSID_NUM)) { + return false; + } + + prP2pBssInfo = prAdapter->aprBssInfo[ucBssIdx]; + + if (prP2pBssInfo->rACL.ePolicy == PARAM_CUSTOM_ACL_POLICY_DISABLE) { + return true; + } + + if (prP2pBssInfo->rACL.ePolicy == PARAM_CUSTOM_ACL_POLICY_ACCEPT) { + bPassACL = false; + } else { + bPassACL = true; + } + + for (i = 0; i < prP2pBssInfo->rACL.u4Num; i++) { + if (EQUAL_MAC_ADDR(pMacAddr, prP2pBssInfo->rACL.rEntry[i].aucAddr)) { + bPassACL = !bPassACL; + break; + } + } + + if (bPassACL == false) { + DBGLOG(P2P, WARN, + "this mac [" MACSTR "] is fail to pass ACL inspection.\n", + MAC2STR(pMacAddr)); + } + + return bPassACL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will indicate the Event of Successful Completion of AAA + * Module. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +p2pRoleFsmRunEventAAAComplete(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_BSS_INFO_T prP2pBssInfo) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + ENUM_PARAM_MEDIA_STATE_T eOriMediaState; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL) && + (prP2pBssInfo != NULL)); + + eOriMediaState = prP2pBssInfo->eConnectionState; + + bssRemoveClient(prAdapter, prP2pBssInfo, prStaRec); + + if (prP2pBssInfo->rStaRecOfClientList.u4NumElem >= + P2P_MAXIMUM_CLIENT_COUNT || + !p2pRoleProcessACLInspection(prAdapter, prStaRec->aucMacAddr, + prP2pBssInfo->ucBssIndex) +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER + || kalP2PMaxClients(prAdapter->prGlueInfo, + prP2pBssInfo->rStaRecOfClientList.u4NumElem, + (u8)prP2pBssInfo->u4PrivateData) +#endif + ) { + rStatus = WLAN_STATUS_RESOURCES; + break; + } + + bssAddClient(prAdapter, prP2pBssInfo, prStaRec); + + prStaRec->u2AssocId = bssAssignAssocID(prStaRec); + + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_3); + +#if CFG_SUPPORT_BFER + if ((IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucStaVhtBfer) || + IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucStaHtBfer)) && + prAdapter->fgIsHwSupportBfer) { + rlmBfStaRecPfmuUpdate(prAdapter, prStaRec); + rlmETxBfTriggerPeriodicSounding(prAdapter); + } +#endif + + p2pChangeMediaState(prAdapter, prP2pBssInfo, + PARAM_MEDIA_STATE_CONNECTED); + + /* Update Connected state to FW. */ + if (eOriMediaState != prP2pBssInfo->eConnectionState) { + nicUpdateBss(prAdapter, prP2pBssInfo->ucBssIndex); + } + } while (false); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will indicate the Event of Successful Completion of AAA + * Module. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +p2pRoleFsmRunEventAAASuccess(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_BSS_INFO_T prP2pBssInfo) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prStaRec != NULL) && + (prP2pBssInfo != NULL)); + + if ((prP2pBssInfo->eNetworkType != NETWORK_TYPE_P2P) || + (prP2pBssInfo->u4PrivateData >= BSS_P2P_NUM)) { + ASSERT(false); + rStatus = WLAN_STATUS_INVALID_DATA; + break; + } + + ASSERT(prP2pBssInfo->ucBssIndex < P2P_DEV_BSS_INDEX); + + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO( + prAdapter, prP2pBssInfo->u4PrivateData); + + /* Glue layer indication. */ + kalP2PGOStationUpdate(prAdapter->prGlueInfo, + prP2pRoleFsmInfo->ucRoleIndex, prStaRec, true); + } while (false); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will indicate the Event of Tx Fail of AAA Module. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void p2pRoleFsmRunEventAAATxFail(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_BSS_INFO_T prP2pBssInfo) +{ + ASSERT(prAdapter); + ASSERT(prStaRec); + + bssRemoveClient(prAdapter, prP2pBssInfo, prStaRec); + + p2pFuncDisconnect(prAdapter, prP2pBssInfo, prStaRec, false, + prStaRec->eAuthAssocState == AAA_STATE_SEND_AUTH2 ? + STATUS_CODE_AUTH_TIMEOUT : + STATUS_CODE_ASSOC_TIMEOUT, + true); + + /* 20120830 moved into p2puUncDisconnect. */ + /* cnmStaRecFree(prAdapter, prStaRec); */ +} + +void p2pRoleFsmRunEventSwitchOPMode(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_MSG_P2P_SWITCH_OP_MODE_T prSwitchOpMode = + (P_MSG_P2P_SWITCH_OP_MODE_T)prMsgHdr; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + + ASSERT(prSwitchOpMode->ucRoleIdx < BSS_P2P_NUM); + if (!(prSwitchOpMode->ucRoleIdx < BSS_P2P_NUM)) { + DBGLOG(P2P, ERROR, + "prSwitchOpMode->ucRoleIdx %d should < BSS_P2P_NUM(%d)\n", + prSwitchOpMode->ucRoleIdx, BSS_P2P_NUM); + goto error; + } + + DBGLOG(P2P, TRACE, "p2pRoleFsmRunEventSwitchOPMode\n"); + + prP2pRoleFsmInfo = + prAdapter->rWifiVar.aprP2pRoleFsmInfo[prSwitchOpMode->ucRoleIdx]; + + ASSERT(prP2pRoleFsmInfo->ucBssIndex < P2P_DEV_BSS_INDEX); + + prP2pBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prP2pRoleFsmInfo->ucBssIndex); + + if (!(prSwitchOpMode->eOpMode < OP_MODE_NUM)) { + DBGLOG(P2P, ERROR, + "prSwitchOpMode->eOpMode %d should < OP_MODE_NUM(%d)\n", + prSwitchOpMode->eOpMode, OP_MODE_NUM); + goto error; + } + + /* P2P Device / GC. */ + p2pFuncSwitchOPMode(prAdapter, prP2pBssInfo, prSwitchOpMode->eOpMode, true); + +error: + cnmMemFree(prAdapter, prMsgHdr); +} + +/* /////////////////////////////// TO BE REFINE //////////////////////////////// + */ +void p2pRoleFsmRunEventBeaconUpdate(IN P_ADAPTER_T prAdapter, + IN P_MSG_HDR_T prMsgHdr) +{ + P_P2P_ROLE_FSM_INFO_T prRoleP2pFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + P_MSG_P2P_BEACON_UPDATE_T prBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T)NULL; + P_P2P_BEACON_UPDATE_INFO_T prBcnUpdateInfo = + (P_P2P_BEACON_UPDATE_INFO_T)NULL; + + DBGLOG(P2P, TRACE, "p2pRoleFsmRunEventBeaconUpdate\n"); + prBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T)prMsgHdr; + if (prBcnUpdateMsg->ucRoleIndex >= BSS_P2P_NUM) { + DBGLOG(P2P, ERROR, + "prBcnUpdateMsg->ucRoleIndex %d should < BSS_P2P_NUM(%d)\n", + prBcnUpdateMsg->ucRoleIndex, BSS_P2P_NUM); + goto error; + } + + prRoleP2pFsmInfo = + P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, prBcnUpdateMsg->ucRoleIndex); + if (!prRoleP2pFsmInfo) { + DBGLOG(P2P, ERROR, + "prRoleP2pFsmInfo of prBcnUpdateMsg->ucRoleIndex %d is NULL\n", + prBcnUpdateMsg->ucRoleIndex); + goto error; + } + + prP2pBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prRoleP2pFsmInfo->ucBssIndex); + + prP2pBssInfo->fgIsWepCipherGroup = prBcnUpdateMsg->fgIsWepCipher; + + prBcnUpdateInfo = &(prRoleP2pFsmInfo->rBeaconUpdateInfo); + + p2pFuncBeaconUpdate(prAdapter, prP2pBssInfo, prBcnUpdateInfo, + prBcnUpdateMsg->pucBcnHdr, prBcnUpdateMsg->u4BcnHdrLen, + prBcnUpdateMsg->pucBcnBody, + prBcnUpdateMsg->u4BcnBodyLen); + + if (prBcnUpdateMsg->pucAssocRespIE != NULL && + prBcnUpdateMsg->u4AssocRespLen > 0) { + DBGLOG(P2P, TRACE, "Copy extra IEs for assoc resp (Length= %d)\n", + prBcnUpdateMsg->u4AssocRespLen); + DBGLOG_MEM8(P2P, INFO, prBcnUpdateMsg->pucAssocRespIE, + prBcnUpdateMsg->u4AssocRespLen); + + if (p2pFuncAssocRespUpdate( + prAdapter, prP2pBssInfo, prBcnUpdateMsg->pucAssocRespIE, + prBcnUpdateMsg->u4AssocRespLen) == WLAN_STATUS_FAILURE) { + DBGLOG(P2P, INFO, "Update extra IEs for asso resp fail!\n"); + } + } + + if ((prP2pBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) && + (prP2pBssInfo->eIntendOPMode == OP_MODE_NUM)) { + /* AP is created, Beacon Update. */ + /* nicPmIndicateBssAbort(prAdapter, NETWORK_TYPE_P2P_INDEX); */ + + DBGLOG(P2P, TRACE, "p2pRoleFsmRunEventBeaconUpdate with Bssidex(%d)\n", + prRoleP2pFsmInfo->ucBssIndex); + + bssUpdateBeaconContent(prAdapter, prRoleP2pFsmInfo->ucBssIndex); + + /* nicPmIndicateBssCreated(prAdapter, NETWORK_TYPE_P2P_INDEX); + */ + } + +error: + cnmMemFree(prAdapter, prMsgHdr); +} + +void p2pProcessEvent_UpdateNOAParam(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx, + IN P_EVENT_UPDATE_NOA_PARAMS_T + prEventUpdateNoaParam) +{ + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T)NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; + u32 i; + u8 fgNoaAttrExisted = false; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIdx); + prP2pSpecificBssInfo = + prAdapter->rWifiVar.prP2pSpecificBssInfo[prBssInfo->u4PrivateData]; + + prP2pSpecificBssInfo->fgEnableOppPS = prEventUpdateNoaParam->ucEnableOppPS; + prP2pSpecificBssInfo->u2CTWindow = prEventUpdateNoaParam->u2CTWindow; + prP2pSpecificBssInfo->ucNoAIndex = prEventUpdateNoaParam->ucNoAIndex; + prP2pSpecificBssInfo->ucNoATimingCount = + prEventUpdateNoaParam->ucNoATimingCount; + + fgNoaAttrExisted |= prP2pSpecificBssInfo->fgEnableOppPS; + + ASSERT(prP2pSpecificBssInfo->ucNoATimingCount <= P2P_MAXIMUM_NOA_COUNT); + + for (i = 0; i < prP2pSpecificBssInfo->ucNoATimingCount; i++) { + /* in used */ + prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse = + prEventUpdateNoaParam->arEventNoaTiming[i].ucIsInUse; + /* count */ + prP2pSpecificBssInfo->arNoATiming[i].ucCount = + prEventUpdateNoaParam->arEventNoaTiming[i].ucCount; + /* duration */ + prP2pSpecificBssInfo->arNoATiming[i].u4Duration = + prEventUpdateNoaParam->arEventNoaTiming[i].u4Duration; + /* interval */ + prP2pSpecificBssInfo->arNoATiming[i].u4Interval = + prEventUpdateNoaParam->arEventNoaTiming[i].u4Interval; + /* start time */ + prP2pSpecificBssInfo->arNoATiming[i].u4StartTime = + prEventUpdateNoaParam->arEventNoaTiming[i].u4StartTime; + + fgNoaAttrExisted |= prP2pSpecificBssInfo->arNoATiming[i].fgIsInUse; + } + + prP2pSpecificBssInfo->fgIsNoaAttrExisted = fgNoaAttrExisted; + + DBGLOG(P2P, TRACE, "p2pProcessEvent_UpdateNOAParam\n"); + /* update beacon content by the change */ + bssUpdateBeaconContent(prAdapter, ucBssIdx); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_role_state.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_role_state.c new file mode 100644 index 00000000000000..e19ed9a754fee1 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_role_state.c @@ -0,0 +1,529 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ +#include "precomp.h" +#include "p2p_role_state.h" + +void p2pRoleStateInit_IDLE(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN P_BSS_INFO_T prP2pBssInfo) +{ + cnmTimerStartTimer(prAdapter, + &(prP2pRoleFsmInfo->rP2pRoleFsmTimeoutTimer), + P2P_AP_CHNL_HOLD_TIME_MS); +} + +void p2pRoleStateAbort_IDLE(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN P_P2P_CHNL_REQ_INFO_T prP2pChnlReqInfo) +{ + /* AP mode channel hold time. */ + if (prP2pChnlReqInfo->fgIsChannelRequested) { + p2pFuncReleaseCh(prAdapter, prP2pRoleFsmInfo->ucBssIndex, + prP2pChnlReqInfo); + } + + cnmTimerStopTimer(prAdapter, + &(prP2pRoleFsmInfo->rP2pRoleFsmTimeoutTimer)); +} + +void p2pRoleStateInit_SCAN(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo) +{ + P_P2P_DEV_FSM_INFO_T prP2pDevFsmInfo = (P_P2P_DEV_FSM_INFO_T)NULL; + P_P2P_SCAN_REQ_INFO_T prDevScanReqInfo = NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (prScanReqInfo != NULL)); + + prScanReqInfo->fgIsScanRequest = true; + if (prScanReqInfo->u4BufLength == 0) { + /* If we let u4BufLength be zero, scan module will copy + * the IE buf from ScanParam */ + /* Sometime this content is from AIS, so we need copy it + * from P2Pdev */ + prP2pDevFsmInfo = prAdapter->rWifiVar.prP2pDevFsmInfo; + if (prP2pDevFsmInfo) { + prDevScanReqInfo = + &(prP2pDevFsmInfo->rScanReqInfo); + if (prDevScanReqInfo->u4BufLength != 0) { + /* IE Buffer */ + kalMemCopy( + prScanReqInfo->aucIEBuf, + prDevScanReqInfo->aucIEBuf, + prDevScanReqInfo->u4BufLength); + prScanReqInfo->u4BufLength = + prDevScanReqInfo->u4BufLength; + DBGLOG(P2P, + TRACE, + "p2pRoleStateInit_SCAN Copy p2p IE from P2P dev\n"); + } + } else { + DBGLOG(P2P, ERROR, "No prP2pDevFsmInfo ptr\n"); + } + } + p2pFuncRequestScan(prAdapter, ucBssIndex, prScanReqInfo); + } while (false); +} + +void p2pRoleStateAbort_SCAN(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo) +{ + P_P2P_SCAN_REQ_INFO_T prScanInfo = (P_P2P_SCAN_REQ_INFO_T)NULL; + + do { + prScanInfo = &prP2pRoleFsmInfo->rScanReqInfo; + + p2pFuncCancelScan(prAdapter, prP2pRoleFsmInfo->ucBssIndex, + prScanInfo); + + /* TODO: May need indicate port index to upper layer. */ + kalP2PIndicateScanDone(prAdapter->prGlueInfo, + prP2pRoleFsmInfo->ucRoleIndex, + prScanInfo->fgIsAbort); + } while (false); +} + +void p2pRoleStateInit_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL)); + + p2pFuncAcquireCh(prAdapter, ucBssIdx, prChnlReqInfo); + } while (false); +} + +void p2pRoleStateAbort_REQING_CHANNEL(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pRoleBssInfo, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN ENUM_P2P_ROLE_STATE_T eNextState) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && + (prP2pRoleBssInfo != NULL) && + (prP2pRoleFsmInfo != NULL)); + + if (eNextState == P2P_ROLE_STATE_IDLE) { + if (prP2pRoleBssInfo->eIntendOPMode == + OP_MODE_ACCESS_POINT) { + P_P2P_CHNL_REQ_INFO_T prP2pChnlReqInfo = + &(prP2pRoleFsmInfo->rChnlReqInfo); + + if (IS_NET_PWR_STATE_ACTIVE( + prAdapter, + prP2pRoleFsmInfo->ucBssIndex)) { + p2pFuncStartGO( + prAdapter, prP2pRoleBssInfo, + &(prP2pRoleFsmInfo + ->rConnReqInfo), + &(prP2pRoleFsmInfo + ->rChnlReqInfo)); + } else if (prP2pChnlReqInfo + ->fgIsChannelRequested) { + p2pFuncReleaseCh( + prAdapter, + prP2pRoleFsmInfo->ucBssIndex, + prP2pChnlReqInfo); + } + } else { + p2pFuncReleaseCh( + prAdapter, prP2pRoleFsmInfo->ucBssIndex, + &(prP2pRoleFsmInfo->rChnlReqInfo)); + } + } + } while (false); +} + +void p2pRoleStateInit_AP_CHNL_DETECTION( + IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN P_P2P_SCAN_REQ_INFO_T prScanReqInfo, + IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo) +{ + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = + (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + P_BSS_INFO_T prBssInfo = NULL; + u8 ucPreferedChnl = 0; + ENUM_BAND_T eBand = BAND_NULL; + ENUM_CHNL_EXT_T eSco = CHNL_EXT_SCN; + + do { + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + ASSERT_BREAK((prAdapter != NULL) && (prScanReqInfo != NULL) && + (prConnReqInfo != NULL) && (prBssInfo != NULL)); + + prP2pSpecificBssInfo = + prAdapter->rWifiVar + .prP2pSpecificBssInfo[prBssInfo->u4PrivateData]; + + if ((cnmPreferredChannel(prAdapter, &eBand, &ucPreferedChnl, + &eSco) == false) && + (prConnReqInfo->rChannelInfo.ucChannelNum == 0)) { + /* Sparse channel detection. */ + prP2pSpecificBssInfo->ucPreferredChannel = 0; + + prScanReqInfo->eScanType = SCAN_TYPE_PASSIVE_SCAN; + prScanReqInfo->u2PassiveDewellTime = 50; /* 50ms for + * passive + * channel load + * detection */ + } else { + /* Active scan to shorten scan time. */ + prScanReqInfo->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqInfo->u2PassiveDewellTime = 0; + + if (prConnReqInfo->rChannelInfo.ucChannelNum != 0) { + prP2pSpecificBssInfo->ucPreferredChannel = + prConnReqInfo->rChannelInfo.ucChannelNum; + prP2pSpecificBssInfo->eRfBand = + prConnReqInfo->rChannelInfo.eBand; + prP2pSpecificBssInfo->eRfSco = CHNL_EXT_SCN; + } else { + prP2pSpecificBssInfo->ucPreferredChannel = + ucPreferedChnl; + prP2pSpecificBssInfo->eRfBand = eBand; + prP2pSpecificBssInfo->eRfSco = eSco; + } + } + + /* TODO: See if channel set to include 5G or only 2.4G */ + prScanReqInfo->eChannelSet = SCAN_CHANNEL_2G4; + + prScanReqInfo->fgIsAbort = true; + prScanReqInfo->fgIsScanRequest = true; + prScanReqInfo->ucNumChannelList = 0; + prScanReqInfo->u4BufLength = 0; + prScanReqInfo->ucSsidNum = 1; + prScanReqInfo->arSsidStruct[0].ucSsidLen = 0; + + p2pFuncRequestScan(prAdapter, ucBssIndex, prScanReqInfo); + } while (false); + + return; +} + +void p2pRoleStateAbort_AP_CHNL_DETECTION( + IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN P_P2P_CONNECTION_REQ_INFO_T prP2pConnReqInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo, + IN P_P2P_SCAN_REQ_INFO_T prP2pScanReqInfo, + IN ENUM_P2P_ROLE_STATE_T eNextState) +{ + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = + (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + P_BSS_INFO_T prBssInfo = NULL; + + do { + if (eNextState == P2P_ROLE_STATE_REQING_CHANNEL) { + prBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + prP2pSpecificBssInfo = + prAdapter->rWifiVar.prP2pSpecificBssInfo + [prBssInfo->u4PrivateData]; + + if (prP2pSpecificBssInfo->ucPreferredChannel == 0) { + if (scnQuerySparseChannel( + prAdapter, + &prP2pSpecificBssInfo->eRfBand, + &prP2pSpecificBssInfo + ->ucPreferredChannel)) { + prP2pSpecificBssInfo->eRfSco = + CHNL_EXT_SCN; + } else { + DBGLOG(P2P, + ERROR, + "Sparse Channel Error, use default settings\n"); + /* Sparse channel false. */ + prP2pSpecificBssInfo + ->ucPreferredChannel = + P2P_DEFAULT_LISTEN_CHANNEL; + prP2pSpecificBssInfo->eRfBand = + BAND_2G4; + prP2pSpecificBssInfo->eRfSco = + CHNL_EXT_SCN; + } + } + + prChnlReqInfo->u8Cookie = 0; + prChnlReqInfo->ucReqChnlNum = + prP2pSpecificBssInfo->ucPreferredChannel; + prChnlReqInfo->eBand = prP2pSpecificBssInfo->eRfBand; + prChnlReqInfo->eChnlSco = prP2pSpecificBssInfo->eRfSco; + prChnlReqInfo->u4MaxInterval = P2P_AP_CHNL_HOLD_TIME_MS; + prChnlReqInfo->eChnlReqType = CH_REQ_TYPE_GO_START_BSS; + + prChnlReqInfo->eChannelWidth = CW_20_40MHZ; + prChnlReqInfo->ucCenterFreqS1 = 0; + prChnlReqInfo->ucCenterFreqS2 = 0; + } else { + p2pFuncCancelScan(prAdapter, ucBssIndex, + prP2pScanReqInfo); + } + } while (false); +} + +void p2pRoleStateInit_GC_JOIN(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + /* P_MSG_JOIN_REQ_T prJoinReqMsg = (P_MSG_JOIN_REQ_T)NULL; */ + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && + (prP2pRoleFsmInfo != NULL) && + (prChnlReqInfo != NULL)); + + prP2pBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, prP2pRoleFsmInfo->ucBssIndex); + + /* Setup a join timer. */ + DBGLOG(P2P, TRACE, "Start a join init timer\n"); + cnmTimerStartTimer(prAdapter, + &(prP2pRoleFsmInfo->rP2pRoleFsmTimeoutTimer), + (prChnlReqInfo->u4MaxInterval - + AIS_JOIN_CH_GRANT_THRESHOLD)); + + p2pFuncGCJoin(prAdapter, prP2pBssInfo, + &(prP2pRoleFsmInfo->rJoinInfo)); + } while (false); +} + +void p2pRoleStateAbort_GC_JOIN(IN P_ADAPTER_T prAdapter, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN P_P2P_JOIN_INFO_T prJoinInfo, + IN ENUM_P2P_ROLE_STATE_T eNextState) +{ + do { + if (prJoinInfo->fgIsJoinComplete == false) { + P_MSG_JOIN_ABORT_T prJoinAbortMsg = + (P_MSG_JOIN_ABORT_T)NULL; + + prJoinAbortMsg = (P_MSG_JOIN_ABORT_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, + sizeof(MSG_JOIN_ABORT_T)); + if (!prJoinAbortMsg) { + DBGLOG(P2P, + TRACE, + "Fail to allocate join abort message buffer\n"); + ASSERT(false); + return; + } + + prJoinAbortMsg->rMsgHdr.eMsgId = MID_P2P_SAA_FSM_ABORT; + prJoinAbortMsg->ucSeqNum = prJoinInfo->ucSeqNumOfReqMsg; + prJoinAbortMsg->prStaRec = prJoinInfo->prTargetStaRec; + + mboxSendMsg(prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prJoinAbortMsg, + MSG_SEND_METHOD_BUF); + } + + /* Stop Join Timer. */ + cnmTimerStopTimer(prAdapter, + &(prP2pRoleFsmInfo->rP2pRoleFsmTimeoutTimer)); + + /* Release channel requested. */ + p2pFuncReleaseCh(prAdapter, prP2pRoleFsmInfo->ucBssIndex, + &(prP2pRoleFsmInfo->rChnlReqInfo)); + + prP2pRoleFsmInfo->rJoinInfo.prTargetStaRec = NULL; + } while (false); +} + +#if (CFG_SUPPORT_DFS_MASTER == 1) +void p2pRoleStateInit_DFS_CAC(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL)); + + p2pFuncAcquireCh(prAdapter, ucBssIdx, prChnlReqInfo); + } while (false); +} + +void p2pRoleStateAbort_DFS_CAC(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pRoleBssInfo, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN ENUM_P2P_ROLE_STATE_T eNextState) +{ + do { + cnmTimerStopTimer(prAdapter, + &(prP2pRoleFsmInfo->rP2pRoleFsmTimeoutTimer)); + + p2pFuncReleaseCh(prAdapter, prP2pRoleFsmInfo->ucBssIndex, + &(prP2pRoleFsmInfo->rChnlReqInfo)); + } while (false); +} + +void p2pRoleStateInit_SWITCH_CHANNEL(IN P_ADAPTER_T prAdapter, IN u8 ucBssIdx, + IN P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prChnlReqInfo != NULL)); + + p2pFuncAcquireCh(prAdapter, ucBssIdx, prChnlReqInfo); + } while (false); +} + +void p2pRoleStateAbort_SWITCH_CHANNEL(IN P_ADAPTER_T prAdapter, + IN P_BSS_INFO_T prP2pRoleBssInfo, + IN P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo, + IN ENUM_P2P_ROLE_STATE_T eNextState) +{ + do + p2pFuncReleaseCh(prAdapter, prP2pRoleFsmInfo->ucBssIndex, + &(prP2pRoleFsmInfo->rChnlReqInfo)); + while (false); +} +#endif + +void p2pRoleStatePrepare_To_REQING_CHANNEL_STATE( + IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, + IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo, + OUT P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + ENUM_BAND_T eBandBackup; + u8 ucChannelBackup; + ENUM_CHNL_EXT_T eSCOBackup; + + do { + /* P2P BSS info is for temporarily use + * Request a 80MHz channel before starting AP/GO + * to prevent from STA/GC connected too early (before CH abort) + * Therefore, STA/GC Rate will drop during DHCP exchange packets + */ + + /* Previous issue: + * Always request 20MHz channel, but carry 40MHz HT cap/80MHz + * VHT cap, then if GC/STA connected before CH abort, GO/AP + * cannot listen to GC/STA's 40MHz/80MHz packets. + */ + + eBandBackup = prBssInfo->eBand; + ucChannelBackup = prBssInfo->ucPrimaryChannel; + eSCOBackup = prBssInfo->eBssSCO; + + prBssInfo->ucPrimaryChannel = + prConnReqInfo->rChannelInfo.ucChannelNum; + prBssInfo->eBand = prConnReqInfo->rChannelInfo.eBand; + + prBssInfo->eBssSCO = rlmGetScoForAP(prAdapter, prBssInfo); + + ASSERT_BREAK((prAdapter != NULL) && (prConnReqInfo != NULL) && + (prChnlReqInfo != NULL)); + prChnlReqInfo->u8Cookie = 0; + prChnlReqInfo->ucReqChnlNum = + prConnReqInfo->rChannelInfo.ucChannelNum; + prChnlReqInfo->eBand = prConnReqInfo->rChannelInfo.eBand; + prChnlReqInfo->eChnlSco = prBssInfo->eBssSCO; + prChnlReqInfo->u4MaxInterval = P2P_AP_CHNL_HOLD_TIME_MS; + prChnlReqInfo->eChnlReqType = CH_REQ_TYPE_GO_START_BSS; + + /*rlmBssInitForAP would decide the real AP bandwidth*/ + prBssInfo->ucVhtChannelWidth = cnmGetBssMaxBwToChnlBW( + prAdapter, prBssInfo->ucBssIndex); + prChnlReqInfo->eChannelWidth = prBssInfo->ucVhtChannelWidth; + if (prChnlReqInfo->eChannelWidth == + VHT_OP_CHANNEL_WIDTH_80P80) { + /* TODO: BW80+80 support */ + DBGLOG(RLM, + WARN, + "BW80+80 not support. Fallback to VHT_OP_CHANNEL_WIDTH_20_40\n"); + prChnlReqInfo->eChannelWidth = + VHT_OP_CHANNEL_WIDTH_20_40; + prChnlReqInfo->ucCenterFreqS1 = 0; + prChnlReqInfo->ucCenterFreqS2 = 0; + } else { + prChnlReqInfo->ucCenterFreqS1 = + rlmGetVhtS1ForAP(prAdapter, prBssInfo); + prChnlReqInfo->ucCenterFreqS2 = 0; + } + + /* If the S1 is invalid, force to change bandwidth */ + if ((prBssInfo->eBand == BAND_5G) && + (prChnlReqInfo->ucCenterFreqS1 == 0)) { + prChnlReqInfo->eChannelWidth = + VHT_OP_CHANNEL_WIDTH_20_40; + } + + DBGLOG(P2P, TRACE, + "p2pRoleStatePrepare_To_REQING_CHANNEL_STATE\n"); + + /* Reset */ + prBssInfo->ucPrimaryChannel = ucChannelBackup; + prBssInfo->eBand = eBandBackup; + prBssInfo->eBssSCO = eSCOBackup; + } while (false); +} + +#if (CFG_SUPPORT_DFS_MASTER == 1) +void p2pRoleStatePrepare_To_DFS_CAC_STATE( + IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, + IN ENUM_CHANNEL_WIDTH_T rChannelWidth, + IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo, + OUT P_P2P_CHNL_REQ_INFO_T prChnlReqInfo) +{ + ENUM_BAND_T eBandBackup; + u8 ucChannelBackup; + ENUM_CHNL_EXT_T eSCOBackup; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + + do { + eBandBackup = prBssInfo->eBand; + ucChannelBackup = prBssInfo->ucPrimaryChannel; + eSCOBackup = prBssInfo->eBssSCO; + + prBssInfo->ucPrimaryChannel = + prConnReqInfo->rChannelInfo.ucChannelNum; + prBssInfo->eBand = prConnReqInfo->rChannelInfo.eBand; + + prBssInfo->eBssSCO = rlmGetScoForAP(prAdapter, prBssInfo); + + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO( + prAdapter, prBssInfo->u4PrivateData); + + ASSERT_BREAK((prAdapter != NULL) && (prConnReqInfo != NULL) && + (prChnlReqInfo != NULL)); + prChnlReqInfo->u8Cookie = 0; + prChnlReqInfo->ucReqChnlNum = + prConnReqInfo->rChannelInfo.ucChannelNum; + prChnlReqInfo->eBand = prConnReqInfo->rChannelInfo.eBand; + prChnlReqInfo->eChnlSco = prBssInfo->eBssSCO; + prChnlReqInfo->u4MaxInterval = + prAdapter->prGlueInfo + ->prP2PInfo[prP2pRoleFsmInfo->ucRoleIndex] + ->cac_time_ms; + prChnlReqInfo->eChnlReqType = CH_REQ_TYPE_DFS_CAC; + + prBssInfo->ucVhtChannelWidth = cnmGetBssMaxBwToChnlBW( + prAdapter, prBssInfo->ucBssIndex); + prChnlReqInfo->eChannelWidth = prBssInfo->ucVhtChannelWidth; + + if (prChnlReqInfo->eChannelWidth == + VHT_OP_CHANNEL_WIDTH_80P80) { + /* TODO: BW80+80 support */ + DBGLOG(RLM, + WARN, + "BW80+80 not support. Fallback to VHT_OP_CHANNEL_WIDTH_20_40\n"); + prChnlReqInfo->eChannelWidth = + VHT_OP_CHANNEL_WIDTH_20_40; + prChnlReqInfo->ucCenterFreqS1 = 0; + prChnlReqInfo->ucCenterFreqS2 = 0; + } else { + prChnlReqInfo->ucCenterFreqS1 = + rlmGetVhtS1ForAP(prAdapter, prBssInfo); + prChnlReqInfo->ucCenterFreqS2 = 0; + } + + DBGLOG(P2P, TRACE, + "p2pRoleStatePrepare_To_REQING_CHANNEL_STATE\n"); + + /* Reset */ + prBssInfo->ucPrimaryChannel = ucChannelBackup; + prBssInfo->eBand = eBandBackup; + prBssInfo->eBssSCO = eSCOBackup; + } while (false); +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_scan.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_scan.c new file mode 100644 index 00000000000000..857066ceb6a819 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/p2p_scan.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "p2p_scan.c" + * \brief This file defines the p2p scan profile and the processing function + * of scan result for SCAN Module. + * + * The SCAN Profile selection is part of SCAN MODULE and responsible for + * defining SCAN Parameters - e.g. MIN_CHANNEL_TIME, number of scan channels. In + * this file we also define the process of SCAN Result including adding, + * searching and removing SCAN record from the list. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ +void scanP2pProcessBeaconAndProbeResp( + IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + IN P_WLAN_STATUS prStatus, IN P_BSS_DESC_T prBssDesc, + IN P_WLAN_BEACON_FRAME_T prWlanBeaconFrame) +{ + u8 fgIsSkipThisBeacon = false; + u8 fgIsP2pNetRegistered = false; + + /* Sanity check for p2p net device state */ + GLUE_SPIN_LOCK_DECLARATION(); + GLUE_ACQUIRE_SPIN_LOCK(prAdapter->prGlueInfo, SPIN_LOCK_NET_DEV); + if (prAdapter->fgIsP2PRegistered && + prAdapter->rP2PNetRegState == ENUM_NET_REG_STATE_REGISTERED) { + fgIsP2pNetRegistered = true; + } + GLUE_RELEASE_SPIN_LOCK(prAdapter->prGlueInfo, SPIN_LOCK_NET_DEV); + + if (!fgIsP2pNetRegistered) { + return; + } + + /* Indicate network to kernel for P2P interface when: + * 1. This is P2P network + * 2. Driver is configured to report all networks + */ + if (prBssDesc->fgIsP2PPresent || prAdapter->p2p_scan_report_all_bss) { + if ((prBssDesc->fgIsConnected) && /* P2P GC connected. */ + ((prWlanBeaconFrame->u2FrameCtrl & MASK_FRAME_TYPE) == + MAC_FRAME_BEACON) /* TX Beacon */ + ) { + u32 u4Idx = 0; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + + for (u4Idx = 0; u4Idx < BSS_INFO_NUM; u4Idx++) { + /* Check BSS for P2P. */ + /* Check BSSID. */ + prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, + (u8)u4Idx); + + if (!IS_BSS_ACTIVE(prP2pBssInfo)) { + continue; + } + + if ((prP2pBssInfo->eNetworkType != + NETWORK_TYPE_P2P) || + (UNEQUAL_MAC_ADDR(prP2pBssInfo->aucBSSID, + prBssDesc->aucBSSID) || + (!EQUAL_SSID(prP2pBssInfo->aucSSID, + prP2pBssInfo->ucSSIDLen, + prBssDesc->aucSSID, + prBssDesc->ucSSIDLen)))) { + continue; + } + if ((prP2pBssInfo->eCurrentOPMode == + OP_MODE_INFRASTRUCTURE) && /* P2P GC */ + (prP2pBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED)) { /* Connected + */ + fgIsSkipThisBeacon = true; + if ((!prP2pBssInfo + ->ucDTIMPeriod)) { /* First + * Time. + */ + prP2pBssInfo->ucDTIMPeriod = + prBssDesc->ucDTIMPeriod; + nicPmIndicateBssConnected( + prAdapter, + prP2pBssInfo + ->ucBssIndex); + } + } + } + } + + do { + RF_CHANNEL_INFO_T rChannelInfo; + + ASSERT_BREAK((prSwRfb != NULL) && (prBssDesc != NULL)); + + if (((prWlanBeaconFrame->u2FrameCtrl & + MASK_FRAME_TYPE) != MAC_FRAME_PROBE_RSP)) { + /* Only report Probe Response frame to + * supplicant except passive scan. */ + /* Probe response collect much more information. + */ + if (fgIsSkipThisBeacon) { + break; + } + } + + rChannelInfo.ucChannelNum = prBssDesc->ucChannelNum; + rChannelInfo.eBand = prBssDesc->eBand; + prBssDesc->fgIsP2PReport = true; + + DBGLOG(P2P, INFO, "indicate %s [%d]\n", + prBssDesc->aucSSID, prBssDesc->ucChannelNum); + + kalP2PIndicateBssInfo(prAdapter->prGlueInfo, + (u8 *)prSwRfb->pvHeader, + (u32)prSwRfb->u2PacketLen, + &rChannelInfo, + RCPI_TO_dBm(prBssDesc->ucRCPI)); + } while (false); + } +} + +void scnEventReturnChannel(IN P_ADAPTER_T prAdapter, IN u8 ucScnSeqNum) +{ + CMD_SCAN_CANCEL rCmdScanCancel; + + kalMemZero(&rCmdScanCancel, sizeof(rCmdScanCancel)); + + /* send cancel message to firmware domain */ + rCmdScanCancel.ucSeqNum = ucScnSeqNum; + rCmdScanCancel.ucIsExtChannel = (u8)false; + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SCAN_CANCEL, true, false, false, + NULL, NULL, sizeof(CMD_SCAN_CANCEL), + (u8 *)&rCmdScanCancel, NULL, 0); +} + +void scanRemoveAllP2pBssDesc(IN P_ADAPTER_T prAdapter) +{ + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc; + P_BSS_DESC_T prBSSDescNext; + + ASSERT(prAdapter); + + prBSSDescList = &(prAdapter->rWifiVar.rScanInfo.rBSSDescList); + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, + rLinkEntry, BSS_DESC_T) { + } +} + +P_BSS_DESC_T scanP2pSearchDesc(IN P_ADAPTER_T prAdapter, + IN P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo) +{ + P_BSS_DESC_T prCandidateBssDesc = (P_BSS_DESC_T)NULL, + prBssDesc = (P_BSS_DESC_T)NULL; + P_LINK_T prBssDescList = (P_LINK_T)NULL; + + do { + if ((prAdapter == NULL) || (prConnReqInfo == NULL)) { + break; + } + + prBssDescList = &(prAdapter->rWifiVar.rScanInfo.rBSSDescList); + + DBGLOG(P2P, LOUD, "Connecting to BSSID: " MACSTR "\n", + MAC2STR(prConnReqInfo->aucBssid)); + DBGLOG(P2P, LOUD, "Connecting to SSID:%s, length:%d\n", + prConnReqInfo->rSsidStruct.aucSsid, + prConnReqInfo->rSsidStruct.ucSsidLen); + + LINK_FOR_EACH_ENTRY(prBssDesc, prBssDescList, rLinkEntry, + BSS_DESC_T) { + DBGLOG(P2P, LOUD, "Checking BSS: " MACSTR "\n", + MAC2STR(prBssDesc->aucBSSID)); + + if (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE) { + DBGLOG(P2P, LOUD, + "Ignore mismatch BSS type.\n"); + continue; + } + + if (UNEQUAL_MAC_ADDR(prBssDesc->aucBSSID, + prConnReqInfo->aucBssid)) { + DBGLOG(P2P, LOUD, "Ignore mismatch BSSID.\n"); + continue; + } + + /* SSID should be the same? SSID is vary for each + * connection. so... */ + if (UNEQUAL_SSID(prConnReqInfo->rSsidStruct.aucSsid, + prConnReqInfo->rSsidStruct.ucSsidLen, + prBssDesc->aucSSID, + prBssDesc->ucSSIDLen)) { + DBGLOG(P2P, TRACE, + "Connecting to BSSID: " MACSTR "\n", + MAC2STR(prConnReqInfo->aucBssid)); + DBGLOG(P2P, TRACE, + "Connecting to SSID:%s, length:%d\n", + prConnReqInfo->rSsidStruct.aucSsid, + prConnReqInfo->rSsidStruct.ucSsidLen); + DBGLOG(P2P, TRACE, + "Checking SSID:%s, length:%d\n", + prBssDesc->aucSSID, + prBssDesc->ucSSIDLen); + DBGLOG(P2P, + TRACE, + "Ignore mismatch SSID, (But BSSID match).\n"); + /* ASSERT(false); */ /*let p2p re-scan again */ + continue; + } + + if (!prBssDesc->fgIsP2PPresent) { + DBGLOG(P2P, + ERROR, + "SSID, BSSID, BSSTYPE match, but no P2P IE present.\n"); + continue; + } + + /* Final decision. */ + prCandidateBssDesc = prBssDesc; + break; + } + } while (false); + + return prCandidateBssDesc; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/privacy.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/privacy.c new file mode 100644 index 00000000000000..84bbd486283903 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/privacy.c @@ -0,0 +1,1123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "privacy.c" + * \brief This file including the protocol layer privacy function. + * + * This file provided the macros and functions library support for the + * protocol layer security setting from rsn.c and nic_privacy.c + * + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to initialize the privacy-related + * parameters. + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] ucNetTypeIdx Pointer to netowrk type index + * + * \retval NONE + */ +/*----------------------------------------------------------------------------*/ +void secInit(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex) +{ + u8 i; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("secInit"); + + ASSERT(prAdapter); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + prBssInfo->u4RsnSelectedGroupCipher = 0; + prBssInfo->u4RsnSelectedPairwiseCipher = 0; + prBssInfo->u4RsnSelectedAKMSuite = 0; + + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[0] + .dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_WEP40; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[1] + .dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_TKIP; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[2] + .dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_CCMP; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[3] + .dot11RSNAConfigPairwiseCipher = WPA_CIPHER_SUITE_WEP104; + + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[4] + .dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_WEP40; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[5] + .dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_TKIP; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[6] + .dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_CCMP; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[7] + .dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_WEP104; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[8] + .dot11RSNAConfigPairwiseCipher = + RSN_CIPHER_SUITE_GROUP_NOT_USED; + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[9] + .dot11RSNAConfigPairwiseCipher = RSN_CIPHER_SUITE_GCMP_256; + + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) + prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[i] + .dot11RSNAConfigPairwiseCipherEnabled = false; + + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[0] + .dot11RSNAConfigAuthenticationSuite = WPA_AKM_SUITE_NONE; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[1] + .dot11RSNAConfigAuthenticationSuite = WPA_AKM_SUITE_802_1X; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[2] + .dot11RSNAConfigAuthenticationSuite = WPA_AKM_SUITE_PSK; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[3] + .dot11RSNAConfigAuthenticationSuite = RSN_AKM_SUITE_NONE; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[4] + .dot11RSNAConfigAuthenticationSuite = RSN_AKM_SUITE_802_1X; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[5] + .dot11RSNAConfigAuthenticationSuite = RSN_AKM_SUITE_PSK; + + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[6] + .dot11RSNAConfigAuthenticationSuite = + RSN_AKM_SUITE_802_1X_SHA256; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[7] + .dot11RSNAConfigAuthenticationSuite = RSN_AKM_SUITE_PSK_SHA256; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[8] + .dot11RSNAConfigAuthenticationSuite = + RSN_AKM_SUITE_8021X_SUITE_B; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[9] + .dot11RSNAConfigAuthenticationSuite = + RSN_AKM_SUITE_8021X_SUITE_B_192; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[10] + .dot11RSNAConfigAuthenticationSuite = RSN_AKM_SUITE_SAE; + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[11] + .dot11RSNAConfigAuthenticationSuite = RSN_AKM_SUITE_OWE; + + for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) + prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i] + .dot11RSNAConfigAuthenticationSuiteEnabled = false; + + secClearPmkid(prAdapter); + + cnmTimerInitTimer(prAdapter, &prAisSpecBssInfo->rPreauthenticationTimer, + (PFN_MGMT_TIMEOUT_FUNC)rsnIndicatePmkidCand, + (unsigned long)NULL); + +#if CFG_SUPPORT_802_11W + cnmTimerInitTimer(prAdapter, &prAisSpecBssInfo->rSaQueryTimer, + (PFN_MGMT_TIMEOUT_FUNC)rsnStartSaQueryTimer, + (unsigned long)NULL); +#endif + + prAisSpecBssInfo->fgCounterMeasure = false; + prAdapter->prAisBssInfo->ucBcDefaultKeyIdx = 0xff; + prAdapter->prAisBssInfo->fgBcDefaultKeyExist = false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will indicate an Event of "Rx Class Error" to SEC_FSM + * for JOIN Module. + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] prSwRfb Pointer to the SW RFB. + * + * \return false Class Error + */ +/*----------------------------------------------------------------------------*/ +u8 secCheckClassError(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + IN P_STA_RECORD_T prStaRec) +{ + P_HW_MAC_RX_DESC_T prRxStatus; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxStatus = prSwRfb->prRxStatus; + + if (!prStaRec || + (prRxStatus->u2StatusFlag & RXS_DW2_RX_CLASSERR_BITMAP) == + RXS_DW2_RX_CLASSERR_VALUE) { + DBGLOG(RSN, ERROR, + "prStaRec=%x RX Status = %x RX_CLASSERR check!\n", + prStaRec, prRxStatus->u2StatusFlag); + + /* if (IS_NET_ACTIVE(prAdapter, ucBssIndex)) { */ + authSendDeauthFrame(prAdapter, NULL, NULL, prSwRfb, + REASON_CODE_CLASS_3_ERR, + (PFN_TX_DONE_HANDLER)NULL); + return false; + /* } */ + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to handle The Rx Security process MSDU. + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] prSWRfb SW rfb pinter + * + * \retval true Accept the packet + * \retval false Refuse the MSDU packet due port control + */ +/*----------------------------------------------------------------------------*/ +u8 secRxPortControlCheck(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb) +{ + ASSERT(prSWRfb); + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine will enable/disable the cipher suite + * + * \param[in] prAdapter Pointer to the adapter object data area. + * \param[in] u4CipherSuitesFlags flag for cipher suite + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void secSetCipherSuite(IN P_ADAPTER_T prAdapter, IN u32 u4CipherSuitesFlags) +{ + u32 i; + P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY prEntry; + P_IEEE_802_11_MIB_T prMib; + + ASSERT(prAdapter); + + prMib = &prAdapter->rMib; + + ASSERT(prMib); + + if (u4CipherSuitesFlags == CIPHER_FLAG_NONE) { + /* Disable all the pairwise cipher suites. */ + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) + prMib->dot11RSNAConfigPairwiseCiphersTable[i] + .dot11RSNAConfigPairwiseCipherEnabled = false; + + /* Update the group cipher suite. */ + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_NONE; + + return; + } + + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) { + prEntry = &prMib->dot11RSNAConfigPairwiseCiphersTable[i]; + + switch (prEntry->dot11RSNAConfigPairwiseCipher) { +#if CFG_SUPPORT_SUITB + case RSN_CIPHER_SUITE_GCMP_256: + if (u4CipherSuitesFlags & CIPHER_FLAG_GCMP256) { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = + true; + } else { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = + false; + } + break; + +#endif + case WPA_CIPHER_SUITE_WEP40: + case RSN_CIPHER_SUITE_WEP40: + if (u4CipherSuitesFlags & CIPHER_FLAG_WEP40) { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = + true; + } else { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = + false; + } + break; + + case WPA_CIPHER_SUITE_TKIP: + case RSN_CIPHER_SUITE_TKIP: + if (u4CipherSuitesFlags & CIPHER_FLAG_TKIP) { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = + true; + } else { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = + false; + } + break; + + case WPA_CIPHER_SUITE_CCMP: + case RSN_CIPHER_SUITE_CCMP: + if (u4CipherSuitesFlags & CIPHER_FLAG_CCMP) { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = + true; + } else { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = + false; + } + break; + + case WPA_CIPHER_SUITE_WEP104: + case RSN_CIPHER_SUITE_WEP104: + if (u4CipherSuitesFlags & CIPHER_FLAG_WEP104) { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = + true; + } else { + prEntry->dot11RSNAConfigPairwiseCipherEnabled = + false; + } + break; + + default: + break; + } + } + + /* Update the group cipher suite. */ + if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_CCMP, &i)) { + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_CCMP; + } else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_TKIP, + &i)) { + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_TKIP; + } else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP104, + &i)) { + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_WEP104; + } else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP40, + &i)) { + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_WEP40; + } +#if CFG_SUPPORT_SUITB + else if (rsnSearchSupportedCipher( + prAdapter, RSN_CIPHER_SUITE_GROUP_NOT_USED, &i)) { + prMib->dot11RSNAConfigGroupCipher = + RSN_CIPHER_SUITE_GROUP_NOT_USED; + } else if (rsnSearchSupportedCipher(prAdapter, + RSN_CIPHER_SUITE_GCMP_256, &i)) { + prMib->dot11RSNAConfigGroupCipher = RSN_CIPHER_SUITE_GCMP_256; + } +#endif + else { + prMib->dot11RSNAConfigGroupCipher = WPA_CIPHER_SUITE_NONE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to initialize the pmkid parameters. + * + * \param[in] prAdapter Pointer to the Adapter structure + * + * \retval NONE + */ +/*----------------------------------------------------------------------------*/ +void secClearPmkid(IN P_ADAPTER_T prAdapter) +{ + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("secClearPmkid"); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + DBGLOG(RSN, TRACE, "secClearPmkid\n"); + prAisSpecBssInfo->u4PmkidCandicateCount = 0; + prAisSpecBssInfo->u4PmkidCacheCount = 0; + kalMemZero((void *)prAisSpecBssInfo->arPmkidCandicate, + sizeof(PMKID_CANDICATE_T) * CFG_MAX_PMKID_CACHE); + kalMemZero((void *)prAisSpecBssInfo->arPmkidCache, + sizeof(PMKID_ENTRY_T) * CFG_MAX_PMKID_CACHE); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Whether 802.11 privacy is enabled. + * + * \param[in] prAdapter Pointer to the Adapter structure + * + * \retval u8 + */ +/*----------------------------------------------------------------------------*/ +u8 secEnabledInAis(IN P_ADAPTER_T prAdapter) +{ + DEBUGFUNC("secEnabledInAis"); + + ASSERT(prAdapter->rWifiVar.rConnSettings.eEncStatus < + ENUM_ENCRYPTION_NUM); + + if ((prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION1_ENABLED) || + (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION2_ENABLED) || + (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION3_ENABLED) +#if CFG_SUPPORT_SUITB + || (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION4_ENABLED) +#endif + ) { + return true; + } else if ((prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION_DISABLED)) { + DBGLOG(RSN, TRACE, "Unknown encryption setting %d\n", + prAdapter->rWifiVar.rConnSettings.eEncStatus); + } + return false; +} + +u8 secIsProtected1xFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + + if (prStaRec) { + prBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + if (prBssInfo && prBssInfo->eNetworkType == NETWORK_TYPE_AIS) { + } + + return prStaRec->fgTransmitKeyExist; + } + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set the privacy bit at mac header for TxM + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] prMsdu the msdu for known the sta record + * + * \return true the privacy need to set + * false the privacy no need to set + */ +/*----------------------------------------------------------------------------*/ +u8 secIsProtectedFrame(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsdu, + IN P_STA_RECORD_T prStaRec) +{ + ASSERT(prAdapter); + ASSERT(prMsdu); + + if (prMsdu->ucPacketType == TX_PACKET_TYPE_MGMT) { + return false; + } + + return secIsProtectedBss(prAdapter, + GET_BSS_INFO_BY_INDEX(prAdapter, + prMsdu->ucBssIndex)); +} + +u8 secIsProtectedBss(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) +{ + ASSERT(prBssInfo); + + if (prBssInfo->eNetworkType == NETWORK_TYPE_AIS) { + return secEnabledInAis(prAdapter); + } +#if CFG_ENABLE_WIFI_DIRECT + else if (prBssInfo->eNetworkType == NETWORK_TYPE_P2P) { + return kalP2PGetCipher(prAdapter->prGlueInfo, + (u8)prBssInfo->u4PrivateData); + } +#endif + else if (prBssInfo->eNetworkType == NETWORK_TYPE_BOW) { + return true; + } + + ASSERT(false); + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used before add/update a WLAN entry. + * Info the WLAN Table has available entry for this request + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] prSta the P_STA_RECORD_T for store + * + * \return true Free Wlan table is reserved for this request + * false No free entry for this request + * + * \note + */ +/*----------------------------------------------------------------------------*/ +u8 secPrivacySeekForEntry(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta) +{ + P_BSS_INFO_T prP2pBssInfo; + u8 ucEntry = WTBL_RESERVED_ENTRY; + u8 i; + u8 ucStartIDX = 0, ucMaxIDX = 0; + P_WLAN_TABLE_T prWtbl; + u8 ucRoleIdx = 0; + + ASSERT(prSta); + + if (!prSta->fgIsInUse) { + ASSERT(false); + } + + prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prSta->ucBssIndex); + ucRoleIdx = prP2pBssInfo->u4PrivateData; + + prWtbl = prAdapter->rWifiVar.arWtbl; + + ucStartIDX = 1; + ucMaxIDX = NIC_TX_DEFAULT_WLAN_INDEX - 1; + + DBGLOG(RSN, INFO, "secPrivacySeekForEntry\n"); + + for (i = ucStartIDX; i <= ucMaxIDX; i++) { + if (prWtbl[i].ucUsed && + EQUAL_MAC_ADDR(prSta->aucMacAddr, prWtbl[i].aucMacAddr) && + prWtbl[i].ucPairwise /* This function for ucPairwise only */ ) { + ucEntry = i; + DBGLOG(RSN, INFO, "[Wlan index]: Reuse entry #%d\n", i); + break; + } + } + + if (i == (ucMaxIDX + 1)) { + for (i = ucStartIDX; i <= ucMaxIDX; i++) { + if (prWtbl[i].ucUsed == false) { + ucEntry = i; + DBGLOG(RSN, INFO, + "[Wlan index]: Assign entry #%d\n", i); + break; + } + } + } + + /* Save to the driver maintain table */ + if (ucEntry < NIC_TX_DEFAULT_WLAN_INDEX) { + prWtbl[ucEntry].ucUsed = true; + prWtbl[ucEntry].ucBssIndex = prSta->ucBssIndex; + prWtbl[ucEntry].ucKeyId = 0xFF; + prWtbl[ucEntry].ucPairwise = 1; + COPY_MAC_ADDR(prWtbl[ucEntry].aucMacAddr, prSta->aucMacAddr); + prWtbl[ucEntry].ucStaIndex = prSta->ucIndex; + + prSta->ucWlanIndex = ucEntry; + + { + P_BSS_INFO_T prBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, prSta->ucBssIndex); + /* for AP mode , if wep key exist, peer sta should also + * fgTransmitKeyExist */ + if (IS_BSS_P2P(prBssInfo) && + kalP2PGetRole(prAdapter->prGlueInfo, ucRoleIdx) == + 2) { + if (prBssInfo->fgBcDefaultKeyExist && + !(kalP2PGetCcmpCipher(prAdapter->prGlueInfo, + ucRoleIdx) || + kalP2PGetTkipCipher(prAdapter->prGlueInfo, + ucRoleIdx))) { + prSta->fgTransmitKeyExist = true; + prWtbl[ucEntry].ucKeyId = + prBssInfo->ucBcDefaultKeyIdx; + DBGLOG(RSN, + INFO, + "peer sta set fgTransmitKeyExist\n"); + } + } + } + + DBGLOG(RSN, + INFO, + "[Wlan index] BSS#%d keyid#%d P=%d use WlanIndex#%d STAIdx=%d " + MACSTR + " staType=%x\n", + prSta->ucBssIndex, + 0, + prWtbl[ucEntry].ucPairwise, + ucEntry, + prSta->ucIndex, + MAC2STR(prSta->aucMacAddr), + prSta->eStaType); + + secCheckWTBLAssign(prAdapter); + + return true; + } +#if DBG + secCheckWTBLAssign(prAdapter); +#endif + DBGLOG(RSN, WARN, + "[Wlan index] No more wlan table entry available!!!!\n"); + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used free a WLAN entry. + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] ucEntry the wlan table index to free + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void secPrivacyFreeForEntry(IN P_ADAPTER_T prAdapter, IN u8 ucEntry) +{ + P_WLAN_TABLE_T prWtbl; + + ASSERT(prAdapter); + + if (ucEntry >= WTBL_SIZE) { + return; + } + + DBGLOG(RSN, INFO, "secPrivacyFreeForEntry %d", ucEntry); + + prWtbl = prAdapter->rWifiVar.arWtbl; + + if (prWtbl[ucEntry].ucUsed) { + prWtbl[ucEntry].ucUsed = false; + prWtbl[ucEntry].ucKeyId = 0xff; + prWtbl[ucEntry].ucBssIndex = MAX_BSS_INDEX + 1; + prWtbl[ucEntry].ucPairwise = 0; + kalMemZero(prWtbl[ucEntry].aucMacAddr, MAC_ADDR_LEN); + prWtbl[ucEntry].ucStaIndex = STA_REC_INDEX_NOT_FOUND; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used free a STA WLAN entry. + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] prStaRec the sta which want to free + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void secPrivacyFreeSta(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + u32 entry; + P_WLAN_TABLE_T prWtbl; + + if (!prStaRec) { + return; + } + + prWtbl = prAdapter->rWifiVar.arWtbl; + + for (entry = 0; entry < WTBL_SIZE; entry++) { + /* Consider GTK case !! */ + if (prWtbl[entry].ucUsed && + EQUAL_MAC_ADDR(prStaRec->aucMacAddr, + prWtbl[entry].aucMacAddr) && + prWtbl[entry].ucPairwise) { + DBGLOG(RSN, INFO, "Free STA entry (%lu)!\n", entry); + + secPrivacyFreeForEntry(prAdapter, entry); + prStaRec->ucWlanIndex = WTBL_RESERVED_ENTRY; + /* prStaRec->ucBMCWlanIndex = WTBL_RESERVED_ENTRY; */ + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to clear the group WEP key + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] ucBssIndex The BSS index + * \param[in] u4KeyId The key index + * + * \note + */ +/*----------------------------------------------------------------------------*/ + +static inline u32 secRemoveBmcWepKey(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN u32 u4KeyId) +{ + PARAM_REMOVE_KEY_T rRemoveKey; + u32 u4SetLen = 0; + u32 u4Ret; + + DBGLOG(RSN, INFO, "BssIdx=%d, KeyId=%d\n", ucBssIndex, u4KeyId); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG(REQ, + WARN, + "Fail in set remove WEP! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, + prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + if (u4KeyId > MAX_KEY_NUM - 1) { + DBGLOG(REQ, ERROR, "invalid WEP key ID %u\n", u4KeyId); + return WLAN_STATUS_INVALID_DATA; + } + + kalMemZero(&rRemoveKey, sizeof(PARAM_REMOVE_KEY_T)); + rRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); + rRemoveKey.u4KeyIndex = u4KeyId; + rRemoveKey.ucBssIdx = ucBssIndex; + /* Should set FLAG_RM_KEY_CTRL_WO_OID for not OID operation */ + rRemoveKey.ucCtrlFlag = FLAG_RM_KEY_CTRL_WO_OID; + + u4Ret = wlanoidSetRemoveKey(prAdapter, (void *)&rRemoveKey, + sizeof(PARAM_REMOVE_KEY_T), &u4SetLen); + + if (u4Ret != WLAN_STATUS_PENDING) { + DBGLOG(RSN, WARN, "Can't send remove bmc wep key cmd\n"); + } + + return u4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used for remove the BC entry of the BSS + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] ucBssIndex The BSS index + * + * \note + */ +/*----------------------------------------------------------------------------*/ +void secRemoveBssBcEntry(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, + IN u8 fgRoam) +{ + int i; + P_CONNECTION_SETTINGS_T prConnSettings = + &(prAdapter->rWifiVar.rConnSettings); + + if (!prBssInfo) { + return; + } + + DBGLOG(RSN, INFO, "remove all the key related with BSS!"); + + if (fgRoam) { + if (IS_BSS_AIS(prBssInfo) && prBssInfo->prStaRecOfAP && + (prConnSettings->eAuthMode >= AUTH_MODE_WPA && + prConnSettings->eAuthMode != AUTH_MODE_WPA_NONE)) { + for (i = 0; i < MAX_KEY_NUM; i++) { + if (prBssInfo->ucBMCWlanIndexSUsed[i]) { + secPrivacyFreeForEntry( + prAdapter, + prBssInfo->ucBMCWlanIndexS[i]); + } + } + prBssInfo->fgBcDefaultKeyExist = false; + prBssInfo->ucBcDefaultKeyIdx = 0xff; + } + } else { + prBssInfo->ucBMCWlanIndex = WTBL_RESERVED_ENTRY; + secPrivacyFreeForEntry(prAdapter, prBssInfo->ucBMCWlanIndex); + + for (i = 0; i < MAX_KEY_NUM; i++) { + if (prBssInfo->wepkeyUsed[i] == false) { + continue; + } + /* remove key to avoid that cfg80211_del_key is called + * after nicDeactivateNetwork. + */ + secRemoveBmcWepKey(prAdapter, prBssInfo->ucBssIndex, i); + prBssInfo->wepkeyUsed[i] = false; + } + /* wlanoidSetRemoveKey would clear prBssInfo->wepkeyUsed[], + * but won't call secPrivacyFreeForEntry. + * For the case that the cfg80211_del_key is called before + * nicDeactivateNetwork, check wepkeyWlanIdx to do + * secPrivacyFreeForEntry. + */ + if (prBssInfo->wepkeyWlanIdx != WTBL_RESERVED_ENTRY) { + secPrivacyFreeForEntry(prAdapter, + prBssInfo->wepkeyWlanIdx); + } + + prBssInfo->wepkeyWlanIdx = WTBL_RESERVED_ENTRY; + prBssInfo->fgBcDefaultKeyExist = false; + prBssInfo->ucBcDefaultKeyIdx = 0xff; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used for adding the broadcast key used, to assign a + * wlan table entry for reserved the specific entry for these key for + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] ucBssIndex The BSS index + * \param[in] ucNetTypeIdx The Network index + * \param[in] ucAlg the entry assign related with algorithm + * \param[in] ucKeyId The key id + * \param[in] ucTxRx The Type of the key + * + * \return ucEntryIndex The entry to be used, WTBL_ALLOC_FAIL for allocation + * fail + * + * \note + */ +/*----------------------------------------------------------------------------*/ +u8 secPrivacySeekForBcEntry(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN u8 *pucAddr, IN u8 ucStaIdx, IN u8 ucAlg, + IN u8 ucKeyId) +{ + u8 ucEntry = WTBL_ALLOC_FAIL; + u8 ucStartIDX = 0, ucMaxIDX = 0; + u8 i = 0; + u8 fgCheckKeyId = true; + P_WLAN_TABLE_T prWtbl; + P_BSS_INFO_T prBSSInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + prWtbl = prAdapter->rWifiVar.arWtbl; + ASSERT(prAdapter); + ASSERT(pucAddr); + + if (ucAlg == CIPHER_SUITE_WPI || /* CIPHER_SUITE_GCM_WPI || */ + ucAlg == CIPHER_SUITE_WEP40 || ucAlg == CIPHER_SUITE_WEP104 || + ucAlg == CIPHER_SUITE_WEP128 || ucAlg == CIPHER_SUITE_NONE) { + fgCheckKeyId = false; + } + + if (ucKeyId == 0xFF || ucAlg == CIPHER_SUITE_BIP) { + fgCheckKeyId = false; + } + + if (prBSSInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + fgCheckKeyId = false; + } + + ucStartIDX = 1; + ucMaxIDX = NIC_TX_DEFAULT_WLAN_INDEX - 1; + + /*always use index 0 for BIP*/ + if (ucAlg == CIPHER_SUITE_BIP) { + ucEntry = 0; + } else { + for (i = ucStartIDX; i <= ucMaxIDX; i++) { + if (prWtbl[i].ucUsed && !prWtbl[i].ucPairwise && + prWtbl[i].ucBssIndex == ucBssIndex) { + if (!fgCheckKeyId) { + ucEntry = i; + DBGLOG(RSN, + INFO, + "[Wlan index]: Reuse entry #%d for open/wep/wpi\n", + i); + break; + } + + if (fgCheckKeyId && + (prWtbl[i].ucKeyId == ucKeyId || + prWtbl[i].ucKeyId == 0xFF)) { + ucEntry = i; + DBGLOG(RSN, + INFO, + "[Wlan index]: Reuse entry #%d\n", + i); + break; + } + } + } + } + + if (i == (ucMaxIDX + 1)) { + for (i = ucStartIDX; i <= ucMaxIDX; i++) { + if (prWtbl[i].ucUsed == false) { + ucEntry = i; + DBGLOG(RSN, INFO, + "[Wlan index]: Assign entry #%d\n", i); + break; + } + } + } + + if (ucEntry < NIC_TX_DEFAULT_WLAN_INDEX) { + prWtbl[ucEntry].ucUsed = true; + prWtbl[ucEntry].ucKeyId = ucKeyId; + prWtbl[ucEntry].ucBssIndex = ucBssIndex; + prWtbl[ucEntry].ucPairwise = 0; + kalMemCopy(prWtbl[ucEntry].aucMacAddr, pucAddr, MAC_ADDR_LEN); + prWtbl[ucEntry].ucStaIndex = ucStaIdx; + + DBGLOG(RSN, + INFO, + "[Wlan index] BSS#%d keyid#%d P=%d use WlanIndex#%d STAIdx=%d " + MACSTR + "\n", + ucBssIndex, + ucKeyId, + prWtbl[ucEntry].ucPairwise, + ucEntry, + ucStaIdx, + MAC2STR(pucAddr)); + + /* DBG */ + secCheckWTBLAssign(prAdapter); + } else { + secCheckWTBLAssign(prAdapter); + DBGLOG(RSN, ERROR, + "[Wlan index] No more wlan entry available!!!!\n"); + } + + return ucEntry; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] prAdapter Pointer to the Adapter structure + * + * \return ucEntryIndex The entry to be used, WTBL_ALLOC_FAIL for allocation + * fail + * + * \note + */ +/*----------------------------------------------------------------------------*/ +u8 secCheckWTBLAssign(IN P_ADAPTER_T prAdapter) +{ + u8 fgCheckFail = false; + + secPrivacyDumpWTBL(prAdapter); + + /* AIS STA should just has max 2 entry */ + /* Max STA check */ + if (fgCheckFail) { + ASSERT(false); + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Got the STA record index by wlan index + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] ucWlanIdx The Rx wlan index + * + * \return The STA record index, 0xff for invalid sta index + */ +/*----------------------------------------------------------------------------*/ +u8 secGetStaIdxByWlanIdx(P_ADAPTER_T prAdapter, u8 ucWlanIdx) +{ + P_WLAN_TABLE_T prWtbl; + + ASSERT(prAdapter); + + if (ucWlanIdx >= WTBL_SIZE) { + return STA_REC_INDEX_NOT_FOUND; + } + + prWtbl = prAdapter->rWifiVar.arWtbl; + + /* DBGLOG(RSN, TRACE, ("secGetStaIdxByWlanIdx=%d "MACSTR" used=%d\n", + * ucWlanIdx, MAC2STR(prWtbl[ucWlanIdx].aucMacAddr), + * prWtbl[ucWlanIdx].ucUsed)); + */ + + if (prWtbl[ucWlanIdx].ucUsed) { + return prWtbl[ucWlanIdx].ucStaIndex; + }else{ + return STA_REC_INDEX_NOT_FOUND; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief At Sw wlan table, got the BSS index by wlan index + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] ucWlanIdx The Rx wlan index + * + * \return The BSS index, 0xff for invalid bss index + */ +/*----------------------------------------------------------------------------*/ +u8 secGetBssIdxByWlanIdx(P_ADAPTER_T prAdapter, u8 ucWlanIdx) +{ + P_WLAN_TABLE_T prWtbl; + + ASSERT(prAdapter); + + if (ucWlanIdx >= WTBL_SIZE) { + return WTBL_RESERVED_ENTRY; + } + + prWtbl = prAdapter->rWifiVar.arWtbl; + + if (prWtbl[ucWlanIdx].ucUsed) { + return prWtbl[ucWlanIdx].ucBssIndex; + }else{ + return WTBL_RESERVED_ENTRY; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Got the STA record index by mac addr + * + * \param[in] prAdapter Pointer to the Adapter structure + * \param[in] pucMacAddress MAC Addr + * + * \return The STA record index, 0xff for invalid sta index + */ +/*----------------------------------------------------------------------------*/ +u8 secLookupStaRecIndexFromTA(P_ADAPTER_T prAdapter, u8 *pucMacAddress) +{ + int i; + P_WLAN_TABLE_T prWtbl; + + ASSERT(prAdapter); + prWtbl = prAdapter->rWifiVar.arWtbl; + + for (i = 0; i < WTBL_SIZE; i++) { + if (prWtbl[i].ucUsed) { + if (EQUAL_MAC_ADDR(pucMacAddress, + prWtbl[i].aucMacAddr) && + prWtbl[i].ucPairwise) { + return prWtbl[i].ucStaIndex; + } + } + } + + return STA_REC_INDEX_NOT_FOUND; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] prAdapter Pointer to the Adapter structure + * + * \note + */ +/*----------------------------------------------------------------------------*/ +void secPrivacyDumpWTBL(IN P_ADAPTER_T prAdapter) +{ + P_WLAN_TABLE_T prWtbl; + u8 i; + + prWtbl = prAdapter->rWifiVar.arWtbl; + + DBGLOG(RSN, INFO, "The Wlan index\n"); + + for (i = 0; i < WTBL_SIZE; i++) { + if (prWtbl[i].ucUsed) { + DBGLOG(RSN, + INFO, + "#%d Used=%d BSSIdx=%d keyid=%d P=%d STA=%d Addr=" + MACSTR + "\n", + i, + prWtbl[i].ucUsed, + prWtbl[i].ucBssIndex, + prWtbl[i].ucKeyId, + prWtbl[i].ucPairwise, + prWtbl[i].ucStaIndex, + MAC2STR(prWtbl[i].aucMacAddr)); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Assin the wlan table with the join AP info + * + * \param[in] prAdapter Pointer to the Adapter structure + * + * \note + */ +/*----------------------------------------------------------------------------*/ +void secPostUpdateAddr(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo) +{ + P_CONNECTION_SETTINGS_T prConnSettings = + &(prAdapter->rWifiVar.rConnSettings); + P_WLAN_TABLE_T prWtbl; + + if (IS_BSS_AIS(prBssInfo) && prBssInfo->prStaRecOfAP) { + if (prConnSettings->eEncStatus == ENUM_ENCRYPTION1_ENABLED) { + if (prBssInfo->fgBcDefaultKeyExist) { + prWtbl = &prAdapter->rWifiVar.arWtbl + [prBssInfo->wepkeyWlanIdx]; + + kalMemCopy(prWtbl->aucMacAddr, + prBssInfo->prStaRecOfAP->aucMacAddr, + MAC_ADDR_LEN); + prWtbl->ucStaIndex = + prBssInfo->prStaRecOfAP->ucIndex; + DBGLOG(RSN, INFO, + "secPostUpdateAddr at [%d] " MACSTR + "= STA Index=%d\n", + prBssInfo->wepkeyWlanIdx, + MAC2STR(prWtbl->aucMacAddr), + prBssInfo->prStaRecOfAP->ucIndex); + + /* Update the wlan table of the prStaRecOfAP */ + prWtbl = + &prAdapter->rWifiVar + .arWtbl[prBssInfo->prStaRecOfAP + ->ucWlanIndex]; + prWtbl->ucKeyId = prBssInfo->ucBcDefaultKeyIdx; + prBssInfo->prStaRecOfAP->fgTransmitKeyExist = + true; + } + } + if (prConnSettings->eEncStatus == ENUM_ENCRYPTION_DISABLED) { + prWtbl = &prAdapter->rWifiVar + .arWtbl[prBssInfo->ucBMCWlanIndex]; + + kalMemCopy(prWtbl->aucMacAddr, + prBssInfo->prStaRecOfAP->aucMacAddr, + MAC_ADDR_LEN); + prWtbl->ucStaIndex = prBssInfo->prStaRecOfAP->ucIndex; + DBGLOG(RSN, INFO, + "secPostUpdateAddr at [%d] " MACSTR + "= STA Index=%d\n", + prBssInfo->ucBMCWlanIndex, + MAC2STR(prWtbl->aucMacAddr), + prBssInfo->prStaRecOfAP->ucIndex); + } + } +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rate.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rate.c new file mode 100644 index 00000000000000..d0d4105a11830d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rate.c @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "rate.c" + * \brief This file contains the transmission rate handling routines. + * + * This file contains the transmission rate handling routines for setting up + * ACK/CTS Rate, Highest Tx Rate, Lowest Tx Rate, Initial Tx Rate and do + * conversion between Rate Set and Data Rates. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* The list of valid data rates. */ +const u8 aucDataRate[] = { + RATE_1M, /* RATE_1M_INDEX = 0 */ + RATE_2M, /* RATE_2M_INDEX */ + RATE_5_5M, /* RATE_5_5M_INDEX */ + RATE_11M, /* RATE_11M_INDEX */ + RATE_22M, /* RATE_22M_INDEX */ + RATE_33M, /* RATE_33M_INDEX */ + RATE_6M, /* RATE_6M_INDEX */ + RATE_9M, /* RATE_9M_INDEX */ + RATE_12M, /* RATE_12M_INDEX */ + RATE_18M, /* RATE_18M_INDEX */ + RATE_24M, /* RATE_24M_INDEX */ + RATE_36M, /* RATE_36M_INDEX */ + RATE_48M, /* RATE_48M_INDEX */ + RATE_54M, /* RATE_54M_INDEX */ + RATE_VHT_PHY, /* RATE_VHT_PHY_INDEX */ + RATE_HT_PHY, /* RATE_HT_PHY_INDEX */ +#if CFG_SUPPORT_H2E + RATE_H2E_ONLY /* RATE_H2E_ONLY_INDEX */ +#endif +}; + +static const u8 aucDefaultAckCtsRateIndex[RATE_NUM_SW] = { + RATE_1M_SW_INDEX, /* RATE_1M_SW_INDEX = 0 */ + RATE_2M_SW_INDEX, /* RATE_2M_SW_INDEX */ + RATE_5_5M_SW_INDEX, /* RATE_5_5M_SW_INDEX */ + RATE_11M_SW_INDEX, /* RATE_11M_SW_INDEX */ + RATE_1M_SW_INDEX, /* RATE_22M_SW_INDEX - Not supported */ + RATE_1M_SW_INDEX, /* RATE_33M_SW_INDEX - Not supported */ + RATE_6M_SW_INDEX, /* RATE_6M_SW_INDEX */ + RATE_6M_SW_INDEX, /* RATE_9M_SW_INDEX */ + RATE_12M_SW_INDEX, /* RATE_12M_SW_INDEX */ + RATE_12M_SW_INDEX, /* RATE_18M_SW_INDEX */ + RATE_24M_SW_INDEX, /* RATE_24M_SW_INDEX */ + RATE_24M_SW_INDEX, /* RATE_36M_SW_INDEX */ + RATE_24M_SW_INDEX, /* RATE_48M_SW_INDEX */ + RATE_24M_SW_INDEX /* RATE_54M_SW_INDEX */ +}; + +const u8 afgIsOFDMRate[RATE_NUM_SW] = { + false, /* RATE_1M_INDEX = 0 */ + false, /* RATE_2M_INDEX */ + false, /* RATE_5_5M_INDEX */ + false, /* RATE_11M_INDEX */ + false, /* RATE_22M_INDEX - Not supported */ + false, /* RATE_33M_INDEX - Not supported */ + true, /* RATE_6M_INDEX */ + true, /* RATE_9M_INDEX */ + true, /* RATE_12M_INDEX */ + true, /* RATE_18M_INDEX */ + true, /* RATE_24M_INDEX */ + true, /* RATE_36M_INDEX */ + true, /* RATE_48M_INDEX */ + true /* RATE_54M_INDEX */ +}; + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Convert the given Supported Rate & Extended Supported Rate IE to the + * Operational Rate Set and Basic Rate Set, and also check if any Basic + * Rate Code is unknown by driver. + * + * @param[in] prIeSupportedRate Pointer to the Supported Rate IE + * @param[in] prIeExtSupportedRate Pointer to the Ext Supported Rate IE + * @param[out] pu2OperationalRateSet Pointer to the Operational Rate Set + * @param[out] pu2BSSBasicRateSet Pointer to the Basic Rate Set + * @param[out] pfgIsUnknownBSSBasicRate Pointer to a Flag to indicate that + * Basic Rate Set has unknown Rate Code + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void rateGetRateSetFromIEs(IN P_IE_SUPPORTED_RATE_IOT_T prIeSupportedRate, + IN P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate, + OUT u16 *pu2OperationalRateSet, + OUT u16 *pu2BSSBasicRateSet, + OUT u8 *pfgIsUnknownBSSBasicRate) +{ + u16 u2OperationalRateSet = 0; + u16 u2BSSBasicRateSet = 0; + u8 fgIsUnknownBSSBasicRate = false; + u8 ucRate; + u32 i, j; + + ASSERT(pu2OperationalRateSet); + ASSERT(pu2BSSBasicRateSet); + ASSERT(pfgIsUnknownBSSBasicRate); + + if (prIeSupportedRate) { + /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE + * exceed 8. IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), 6(B), + * 9(B), 11(B), 12(B), 18(B), 24(B), 36(B), 48(B), 54(B)" + */ + /* ASSERT(prIeSupportedRate->ucLength <= + * ELEM_MAX_LEN_SUP_RATES); */ + if (prIeSupportedRate->ucLength > ELEM_MAX_LEN_SUP_RATES_IOT) { + *pu2OperationalRateSet = 0; + *pu2BSSBasicRateSet = 0; + *pfgIsUnknownBSSBasicRate = true; + return; + } + + for (i = 0; i < prIeSupportedRate->ucLength; i++) { + ucRate = prIeSupportedRate->aucSupportedRates[i] & + RATE_MASK; + + /* Search all valid data rates */ + for (j = 0; j < sizeof(aucDataRate) / sizeof(u8); j++) { + if (ucRate == aucDataRate[j]) { + u2OperationalRateSet |= BIT(j); + + if (prIeSupportedRate + ->aucSupportedRates[i] & + RATE_BASIC_BIT) { + u2BSSBasicRateSet |= BIT(j); + } + + break; + } + } + + if ((j == sizeof(aucDataRate) / sizeof(u8)) && + (prIeSupportedRate->aucSupportedRates[i] & + RATE_BASIC_BIT)) { + fgIsUnknownBSSBasicRate = true; /* A data rate + * not list in + * the + * aucDataRate[] + */ + } + } + } + + if (prIeExtSupportedRate) { + /* ASSERT(prIeExtSupportedRate->ucLength <= + * ELEM_MAX_LEN_EXTENDED_SUP_RATES); */ + for (i = 0; i < prIeExtSupportedRate->ucLength; i++) { + ucRate = prIeExtSupportedRate->aucExtSupportedRates[i] & + RATE_MASK; + + /* Search all valid data rates */ + for (j = 0; j < sizeof(aucDataRate) / sizeof(u8); j++) { + if (ucRate == aucDataRate[j]) { + u2OperationalRateSet |= BIT(j); + + if (prIeExtSupportedRate + ->aucExtSupportedRates[i] & + RATE_BASIC_BIT) { + u2BSSBasicRateSet |= BIT(j); + } + + break; + } + } + + if ((j == sizeof(aucDataRate) / sizeof(u8)) && + (prIeExtSupportedRate->aucExtSupportedRates[i] & + RATE_BASIC_BIT)) { + fgIsUnknownBSSBasicRate = true; /* A data rate + * not list in + * the + * aucDataRate[] + */ + } + } + } + + *pu2OperationalRateSet = u2OperationalRateSet; + *pu2BSSBasicRateSet = u2BSSBasicRateSet; + *pfgIsUnknownBSSBasicRate = fgIsUnknownBSSBasicRate; + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Convert the given Operational Rate Set & Basic Rate Set to the Rate + * Code Format for used in (Ext)Supportec Rate IE. + * + * @param[in] u2OperationalRateSet Operational Rate Set + * @param[in] u2BSSBasicRateSet Basic Rate Set + * @param[out] pucDataRates Pointer to the Data Rate Buffer + * @param[out] pucDataRatesLen Pointer to the Data Rate Buffer Length + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void rateGetDataRatesFromRateSet(IN u16 u2OperationalRateSet, + IN u16 u2BSSBasicRateSet, OUT u8 *pucDataRates, + OUT u8 *pucDataRatesLen) +{ + u32 i, j; + + ASSERT(pucDataRates); + ASSERT(pucDataRatesLen); + + ASSERT(u2BSSBasicRateSet == (u2OperationalRateSet & u2BSSBasicRateSet)); + + for (i = RATE_1M_SW_INDEX, j = 0; i < RATE_NUM_SW; i++) { + if (u2OperationalRateSet & BIT(i)) { + *(pucDataRates + j) = aucDataRate[i]; + + if (u2BSSBasicRateSet & BIT(i)) { + *(pucDataRates + j) |= RATE_BASIC_BIT; + } + + j++; + } + } + + *pucDataRatesLen = (u8)j; + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Get the highest rate from given Rate Set. + * + * \param[in] u2RateSet Rate Set + * \param[out] pucHighestRateIndex Pointer to buffer of the Highest Rate Index + * + * \retval true Highest Rate Index was found + * \retval false Highest Rate Index was not found + */ +/*----------------------------------------------------------------------------*/ +u8 rateGetHighestRateIndexFromRateSet(IN u16 u2RateSet, + OUT u8 *pucHighestRateIndex) +{ + s32 i; + + ASSERT(pucHighestRateIndex); + + for (i = RATE_54M_SW_INDEX; i >= RATE_1M_SW_INDEX; i--) { + if (u2RateSet & BIT(i)) { + *pucHighestRateIndex = (u8)i; + return true; + } + } + + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Get the lowest rate from given Rate Set. + * + * \param[in] u2RateSet Rate Set + * \param[out] pucLowestRateIndex Pointer to buffer of the Lowest Rate Index + * + * \retval true Lowest Rate Index was found + * \retval false Lowest Rate Index was not found + */ +/*----------------------------------------------------------------------------*/ +u8 rateGetLowestRateIndexFromRateSet(IN u16 u2RateSet, + OUT u8 *pucLowestRateIndex) +{ + u32 i; + + ASSERT(pucLowestRateIndex); + + for (i = RATE_1M_SW_INDEX; i <= RATE_54M_SW_INDEX; i++) { + if (u2RateSet & BIT(i)) { + *pucLowestRateIndex = (u8)i; + return true; + } + } + + return false; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/reg_rule.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/reg_rule.c new file mode 100644 index 00000000000000..cb7b6947dbe521 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/reg_rule.c @@ -0,0 +1,189 @@ +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +#if (CFG_SUPPORT_SINGLE_SKU == 1) +#if (CFG_SUPPORT_SINGLE_SKU_LOCAL_DB == 1) +#include "rlm_domain.h" + +/*************************************************** + * Hello ^++++^ + * Here to describe the regulatory rules of yours. + **************************************************/ + +/* + * Step1. Decclare struct ieee80211_regdomain + */ + +const struct ieee80211_regdomain + regdom_us01 = { .n_reg_rules = 6, + .reg_rules = { + /* channels 1..11 */ + REG_RULE_LIGHT(2412 - 10, 2462 + 10, 40, 0), + /* channels 36..48 */ + REG_RULE_LIGHT(5180 - 10, 5240 + 10, 40, 0), + /* channels 56..64 */ + REG_RULE_LIGHT(5260 - 10, 5320 + 10, 40, + NL80211_RRF_DFS), + /* channels 100..118 */ + REG_RULE_LIGHT(5500 - 10, 5590 + 10, 40, + NL80211_RRF_DFS), + /* channels 132..140 */ + REG_RULE_LIGHT(5660 - 10, 5700 + 10, 40, + NL80211_RRF_DFS), + /* channels 149..165 */ + REG_RULE_LIGHT(5745 - 10, 5825 + 10, 40, 0) + } }; + +const struct ieee80211_regdomain + regdom_us = { .n_reg_rules = 5, + .dfs_region = NL80211_DFS_FCC, + .reg_rules = { + /* channels 1..11 */ + REG_RULE_LIGHT(2412 - 10, 2462 + 10, 40, 0), + /* channels 36..48 */ + REG_RULE_LIGHT(5180 - 10, 5240 + 10, 80, 0), + /* channels 52..64 */ + REG_RULE_LIGHT(5260 - 10, 5320 + 10, 80, + NL80211_RRF_DFS | 0), + /* channels 100..140 */ + REG_RULE_LIGHT(5500 - 10, 5720 + 10, 160, + NL80211_RRF_DFS), + /* channels 149..165 */ + REG_RULE_LIGHT(5745 - 10, 5825 + 10, 80, 0) + } }; + +const struct ieee80211_regdomain + regdom_cn = { .n_reg_rules = 4, + .dfs_region = NL80211_DFS_FCC, + .reg_rules = { + /* channels 1..13 */ + REG_RULE_LIGHT(2412 - 10, 2472 + 10, 40, 0), + /* channels 36..48 */ + REG_RULE_LIGHT(5180 - 10, 5240 + 10, 80, 0), + /* channels 52..64 */ + REG_RULE_LIGHT(5260 - 10, 5320 + 10, 80, + NL80211_RRF_DFS | 0), + /* channels 149..165 */ + REG_RULE_LIGHT(5745 - 10, 5825 + 10, 80, 0) + } }; + +const struct ieee80211_regdomain + regdom_cz_nl = { .n_reg_rules = 5, + .reg_rules = { + /* channels 1..11 */ + REG_RULE_LIGHT(2412 - 10, 2462 + 10, 40, 0), + /* channels 12,13 */ + REG_RULE_LIGHT(2467 - 10, 2472 + 10, 40, 0), + /* channels 36..48 */ + REG_RULE_LIGHT(5180 - 10, 5240 + 10, 80, 0), + /* channels 52..64 */ + REG_RULE_LIGHT(5260 - 10, 5320 + 10, 80, + NL80211_RRF_DFS), + /* channels 100..140 */ + REG_RULE_LIGHT(5500 - 10, 5700 + 10, 160, + NL80211_RRF_DFS) + } }; + +const struct ieee80211_regdomain + regdom_jp = { .n_reg_rules = 7, + .dfs_region = NL80211_DFS_JP, + .reg_rules = { + /* channels 1..13 */ + REG_RULE_LIGHT(2412 - 10, 2472 + 10, 40, 0), + /* channels 14 */ + REG_RULE_LIGHT(2484 - 10, 2484 + 10, 20, + NL80211_RRF_NO_OFDM), + /* channels 184..196 */ + REG_RULE_LIGHT(4920 - 10, 4980 + 10, 40, 0), + /* channels 8..16 */ + REG_RULE_LIGHT(5040 - 10, 5080 + 10, 40, 0), + /* channels 36..48 */ + REG_RULE_LIGHT(5180 - 10, 5240 + 10, 80, 0), + /* channels 52..64 */ + REG_RULE_LIGHT(5260 - 10, 5320 + 10, 80, + NL80211_RRF_DFS | 0), + /* channels 100..140 */ + REG_RULE_LIGHT(5500 - 10, 5700 + 10, 160, + NL80211_RRF_DFS) + } }; + +const struct ieee80211_regdomain + regdom_tr = { .n_reg_rules = 4, + .dfs_region = NL80211_DFS_ETSI, + .reg_rules = { + /* channels 1..13 */ + REG_RULE_LIGHT(2412 - 10, 2472 + 10, 40, 0), + /* channels 36..48 */ + REG_RULE_LIGHT(5180 - 10, 5240 + 10, 80, 0), + /* channels 52..64 */ + REG_RULE_LIGHT(5260 - 10, 5320 + 10, 80, + NL80211_RRF_DFS | 0), + /* channels 100..140 */ + REG_RULE_LIGHT(5500 - 10, 5700 + 10, 160, + NL80211_RRF_DFS) + } }; + +const struct ieee80211_regdomain regdom_ru = { + .n_reg_rules = 5, + .dfs_region = NL80211_DFS_ETSI, + .reg_rules = { + /* channels 1..13 */ + REG_RULE_LIGHT(2412-10, 2472+10, 40, 0), + /* channels 36..48 */ + REG_RULE_LIGHT(5180-10, 5240+10, 80, NL80211_RRF_AUTO_BW), + /* channels 52..64 */ + REG_RULE_LIGHT(5260-10, 5320+10, 80, NL80211_RRF_DFS | NL80211_RRF_AUTO_BW), + REG_RULE_LIGHT(5660-10, 5720+10, 80, NL80211_RRF_DFS), + /* channels 149..165 */ + REG_RULE_LIGHT(5745-10, 5825+10, 80, 0) } +}; + +/* + * Step2. Decclare struct mtk_regdomain + */ + +const struct mtk_regdomain my_regdom_us01 = { .country_code = "US01", + .prRegdRules = ®dom_us01 }; + +const struct mtk_regdomain my_regdom_us = { .country_code = "US", + .prRegdRules = ®dom_us }; + +const struct mtk_regdomain my_regdom_cn = { .country_code = "CN", + .prRegdRules = ®dom_cn }; + +const struct mtk_regdomain my_regdom_nl = { .country_code = "NL", + .prRegdRules = ®dom_cz_nl }; + +const struct mtk_regdomain my_regdom_cz = { .country_code = "CZ", + .prRegdRules = ®dom_cz_nl }; + +const struct mtk_regdomain my_regdom_jp = { .country_code = "JP", + .prRegdRules = ®dom_jp }; + +const struct mtk_regdomain my_regdom_tr = { .country_code = "TR", + .prRegdRules = ®dom_tr }; + +const struct mtk_regdomain my_regdom_ru = { .country_code = "RU", + .prRegdRules = ®dom_ru }; + +/* + * Step3. Register to table + */ + +const struct mtk_regdomain *g_prRegRuleTable[] = { + &my_regdom_us01, &my_regdom_us, &my_regdom_cn, + &my_regdom_nl, &my_regdom_cz, &my_regdom_jp, + &my_regdom_tr, &my_regdom_ru, NULL /* this NULL SHOULD be at the end of the array */ +}; + +#endif +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rlm.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rlm.c new file mode 100644 index 00000000000000..1d6c4afc459177 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rlm.c @@ -0,0 +1,5745 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "rlm.c" + * \brief + * + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#include "rlm.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +u8 g_bCaptureDone = false; +u8 g_bIcapEnable = false; +u16 g_u2DumpIndex; +u8 g_fgFowardBcn2Supplicant = false; + +#if CFG_SUPPORT_QA_TOOL +u32 g_au4Offset[2][2]; +u32 g_au4IQData[256]; +#endif + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +static void rlmFillHtCapIE(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo); + +static void rlmFillExtCapIE(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo); + +static void rlmFillHtOpIE(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo); + +static u8 rlmRecIeInfoForClient(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + u8 *pucIE, + u16 u2IELength); + +static u8 rlmRecBcnFromNeighborForClient(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_SW_RFB_T prSwRfb, + u8 *pucIE, + u16 u2IELength); + +static u8 rlmRecBcnInfoForClient(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_SW_RFB_T prSwRfb, + u8 *pucIE, + u16 u2IELength); + +static void rlmBssReset(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo); + +#if CFG_SUPPORT_802_11AC +static void rlmFillVhtCapIE(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo); +static void rlmFillVhtOpNotificationIE(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo, + u8 fgIsMaxCap); + +#endif +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmFsmEventInit(P_ADAPTER_T prAdapter) +{ +#if CFG_SUPPORT_QUIET + P_BSS_INFO_T prBssInfo; + u8 i; +#endif + ASSERT(prAdapter); + + /* Note: assume TIMER_T structures are reset to zero or stopped + * before invoking this function. + */ + + /* Initialize OBSS FSM */ + rlmObssInit(prAdapter); + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + rlmDomainCheckCountryPowerLimitTable(prAdapter); +#endif + +#if CFG_SUPPORT_QUIET + for (i = 0; i < BSS_INFO_NUM; i++) { + prBssInfo = prAdapter->aprBssInfo[i]; + prBssInfo->fgRequestQuietInterval = false; + prBssInfo->fgIsInQuietInterval = false; + cnmTimerInitTimer(prAdapter, &prBssInfo->rTxQuietTimer, + (PFN_MGMT_TIMEOUT_FUNC)rrmTxQuietTimeout, + (unsigned long)prBssInfo); + } +#endif + g_bCaptureDone = false; + g_bIcapEnable = false; + g_u2DumpIndex = 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmFsmEventUninit(P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prBssInfo; + u8 i; + + ASSERT(prAdapter); + + for (i = 0; i < BSS_INFO_NUM; i++) { + prBssInfo = prAdapter->aprBssInfo[i]; + + /* Note: all RLM timers will also be stopped. + * Now only one OBSS scan timer. + */ + rlmBssReset(prAdapter, prBssInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief For association request, power capability + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmReqGeneratePowerCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + u8 *pucBuffer; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + + /* We should add power capability IE in assoc/reassoc req if the + * spectrum management bit is set to 1 in Capability Infor field, or the + * connection will be rejected by Marvell APs in some TGn items. + * (e.g. 5.2.32). Spectrum management related feature (802.11h) is for + * 5G band. + */ + if (!prBssInfo || prBssInfo->eBand != BAND_5G) { + return; + } + + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + + POWER_CAP_IE(pucBuffer)->ucId = ELEM_ID_PWR_CAP; + POWER_CAP_IE(pucBuffer)->ucLength = ELEM_MAX_LEN_POWER_CAP; + POWER_CAP_IE(pucBuffer)->cMinTxPowerCap = 15; + POWER_CAP_IE(pucBuffer)->cMaxTxPowerCap = 20; + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief For association request, supported channels + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmReqGenerateSupportedChIE(P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo) +{ + u8 *pucBuffer; + P_BSS_INFO_T prBssInfo; + RF_CHANNEL_INFO_T auc2gChannelList[MAX_2G_BAND_CHN_NUM]; + RF_CHANNEL_INFO_T auc5gChannelList[MAX_5G_BAND_CHN_NUM]; + u8 ucNumOf2gChannel = 0; + u8 ucNumOf5gChannel = 0; + u8 ucChIdx = 0; + u8 ucIdx = 0; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + + /* We should add supported channels IE in assoc/reassoc req if the + * spectrum management bit is set to 1 in Capability Infor field, or the + * connection will be rejected by Marvell APs in some TGn items. + * (e.g. 5.2.3). Spectrum management related feature (802.11h) is for 5G + * band. + */ + if (!prBssInfo || prBssInfo->eBand != BAND_5G) { + return; + } + + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + + rlmDomainGetChnlList(prAdapter, BAND_2G4, true, MAX_2G_BAND_CHN_NUM, + &ucNumOf2gChannel, auc2gChannelList); + rlmDomainGetChnlList(prAdapter, BAND_5G, true, MAX_5G_BAND_CHN_NUM, + &ucNumOf5gChannel, auc5gChannelList); + + SUP_CH_IE(pucBuffer)->ucId = ELEM_ID_SUP_CHS; + SUP_CH_IE(pucBuffer)->ucLength = + (ucNumOf2gChannel + ucNumOf5gChannel) * 2; + + for (ucIdx = 0; ucIdx < ucNumOf2gChannel; ucIdx++, ucChIdx += 2) { + SUP_CH_IE(pucBuffer)->ucChannelNum[ucChIdx] = + auc2gChannelList[ucIdx].ucChannelNum; + SUP_CH_IE(pucBuffer)->ucChannelNum[ucChIdx + 1] = 1; + } + + for (ucIdx = 0; ucIdx < ucNumOf5gChannel; ucIdx++, ucChIdx += 2) { + SUP_CH_IE(pucBuffer)->ucChannelNum[ucChIdx] = + auc5gChannelList[ucIdx].ucChannelNum; + SUP_CH_IE(pucBuffer)->ucChannelNum[ucChIdx + 1] = 1; + } + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief For probe request, association request + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmReqGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + if (!prBssInfo) { + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + /*Re check PHY type set for eEncStatus not sync */ + if (prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc && prStaRec) { + bssDetermineStaRecPhyTypeSet( + prAdapter, + prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc, + prStaRec); + } + + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11N) && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) { + rlmFillHtCapIE(prAdapter, prBssInfo, prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief For probe request, association request + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmReqGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + if (!prBssInfo) { + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11N) && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N))) { + rlmFillExtCapIE(prAdapter, prBssInfo, prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief For probe response (GO, IBSS) and association response + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmRspGenerateHtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + u8 ucPhyTypeSet; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + if (!prBssInfo) { + return; + } + + if (!IS_BSS_ACTIVE(prBssInfo)) { + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + /* Decide PHY type set source */ + if (prStaRec) { + /* Get PHY type set from target STA */ + ucPhyTypeSet = prStaRec->ucPhyTypeSet; + } else { + /* Get PHY type set from current BSS */ + ucPhyTypeSet = prBssInfo->ucPhyTypeSet; + } + + if (RLM_NET_IS_11N(prBssInfo) && + (ucPhyTypeSet & PHY_TYPE_SET_802_11N) && + (!prBssInfo->fgIsWepCipherGroup)) { + rlmFillHtCapIE(prAdapter, prBssInfo, prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief For probe response (GO, IBSS) and association response + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmRspGenerateExtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + u8 ucPhyTypeSet; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + if (!prBssInfo) { + return; + } + + if (!IS_BSS_ACTIVE(prBssInfo)) { + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + /* Decide PHY type set source */ + if (prStaRec) { + /* Get PHY type set from target STA */ + ucPhyTypeSet = prStaRec->ucPhyTypeSet; + } else { + /* Get PHY type set from current BSS */ + ucPhyTypeSet = prBssInfo->ucPhyTypeSet; + } + + if (RLM_NET_IS_11N(prBssInfo) && (ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { + rlmFillExtCapIE(prAdapter, prBssInfo, prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief For probe response (GO, IBSS) and association response + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmRspGenerateHtOpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + u8 ucPhyTypeSet; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + if (!prBssInfo) { + return; + } + + if (!IS_BSS_ACTIVE(prBssInfo)) { + return; + } + + /* Decide PHY type set source */ + if (prStaRec) { + /* Get PHY type set from target STA */ + ucPhyTypeSet = prStaRec->ucPhyTypeSet; + } else { + /* Get PHY type set from current BSS */ + ucPhyTypeSet = prBssInfo->ucPhyTypeSet; + } + + if (RLM_NET_IS_11N(prBssInfo) && + (ucPhyTypeSet & PHY_TYPE_SET_802_11N) && + (!prBssInfo->fgIsWepCipherGroup)) { + rlmFillHtOpIE(prAdapter, prBssInfo, prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief For probe response (GO, IBSS) and association response + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmRspGenerateErpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + P_IE_ERP_T prErpIe; + u8 ucPhyTypeSet; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + if (!prBssInfo) { + return; + } + + if (!IS_BSS_ACTIVE(prBssInfo)) { + return; + } + + /* Decide PHY type set source */ + if (prStaRec) { + /* Get PHY type set from target STA */ + ucPhyTypeSet = prStaRec->ucPhyTypeSet; + } else { + /* Get PHY type set from current BSS */ + ucPhyTypeSet = prBssInfo->ucPhyTypeSet; + } + + if (RLM_NET_IS_11GN(prBssInfo) && prBssInfo->eBand == BAND_2G4 && + (ucPhyTypeSet & PHY_TYPE_SET_802_11GN)) { + prErpIe = (P_IE_ERP_T)(((u8 *)prMsduInfo->prPacket) + + prMsduInfo->u2FrameLength); + + /* Add ERP IE */ + prErpIe->ucId = ELEM_ID_ERP_INFO; + prErpIe->ucLength = 1; + + prErpIe->ucERP = prBssInfo->fgObssErpProtectMode ? + ERP_INFO_USE_PROTECTION : + 0; + + if (prBssInfo->fgErpProtectMode) { + prErpIe->ucERP |= (ERP_INFO_NON_ERP_PRESENT | + ERP_INFO_USE_PROTECTION); + } + + /* Handle barker preamble */ + if (!prBssInfo->fgUseShortPreamble) { + prErpIe->ucERP |= ERP_INFO_BARKER_PREAMBLE_MODE; + } + + ASSERT(IE_SIZE(prErpIe) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_ERP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prErpIe); + } +} + +#if CFG_SUPPORT_MTK_SYNERGY +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is used to generate MTK Vendor Specific OUI + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmGenerateMTKOuiIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + u8 *pucBuffer; + u8 aucMtkOui[] = VENDOR_OUI_MTK; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + if (prAdapter->rWifiVar.ucMtkOui == FEATURE_DISABLED) { + return; + } + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + if (!prBssInfo) { + return; + } + + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + + MTK_OUI_IE(pucBuffer)->ucId = ELEM_ID_VENDOR; + MTK_OUI_IE(pucBuffer)->ucLength = ELEM_MIN_LEN_MTK_OUI; + MTK_OUI_IE(pucBuffer)->aucOui[0] = aucMtkOui[0]; + MTK_OUI_IE(pucBuffer)->aucOui[1] = aucMtkOui[1]; + MTK_OUI_IE(pucBuffer)->aucOui[2] = aucMtkOui[2]; + MTK_OUI_IE(pucBuffer)->aucCapability[0] = + MTK_SYNERGY_CAP0 & (prAdapter->rWifiVar.aucMtkFeature[0]); + MTK_OUI_IE(pucBuffer)->aucCapability[1] = + MTK_SYNERGY_CAP1 & (prAdapter->rWifiVar.aucMtkFeature[1]); + MTK_OUI_IE(pucBuffer)->aucCapability[2] = + MTK_SYNERGY_CAP2 & (prAdapter->rWifiVar.aucMtkFeature[2]); + MTK_OUI_IE(pucBuffer)->aucCapability[3] = + MTK_SYNERGY_CAP3 & (prAdapter->rWifiVar.aucMtkFeature[3]); + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to check MTK Vendor Specific OUI + * + * + * @return true: correct MTK OUI + * false: incorrect MTK OUI + */ +/*----------------------------------------------------------------------------*/ +u8 rlmParseCheckMTKOuiIE(IN P_ADAPTER_T prAdapter, IN u8 *pucBuf, + IN u32 *pu4Cap) +{ + u8 aucMtkOui[] = VENDOR_OUI_MTK; + P_IE_MTK_OUI_T prMtkOuiIE = (P_IE_MTK_OUI_T)NULL; + + do { + ASSERT_BREAK((prAdapter != NULL) && (pucBuf != NULL)); + + prMtkOuiIE = (P_IE_MTK_OUI_T)pucBuf; + + if (prAdapter->rWifiVar.ucMtkOui == FEATURE_DISABLED) { + break; + }else if (IE_LEN(pucBuf) < ELEM_MIN_LEN_MTK_OUI) { + break; + }else if (prMtkOuiIE->aucOui[0] != aucMtkOui[0] || + prMtkOuiIE->aucOui[1] != aucMtkOui[1] || + prMtkOuiIE->aucOui[2] != aucMtkOui[2]) { + break; + } + /* apply NvRam setting */ + prMtkOuiIE->aucCapability[0] = + prMtkOuiIE->aucCapability[0] & + (prAdapter->rWifiVar.aucMtkFeature[0]); + prMtkOuiIE->aucCapability[1] = + prMtkOuiIE->aucCapability[1] & + (prAdapter->rWifiVar.aucMtkFeature[1]); + prMtkOuiIE->aucCapability[2] = + prMtkOuiIE->aucCapability[2] & + (prAdapter->rWifiVar.aucMtkFeature[2]); + prMtkOuiIE->aucCapability[3] = + prMtkOuiIE->aucCapability[3] & + (prAdapter->rWifiVar.aucMtkFeature[3]); + + kalMemCopy(pu4Cap, prMtkOuiIE->aucCapability, sizeof(u32)); + + return true; + } while (false); + + return false; +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmGenerateCsaIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + u8 *pucBuffer; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + if (prAdapter->rWifiVar.fgCsaInProgress) { + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + + CSA_IE(pucBuffer)->ucId = ELEM_ID_CH_SW_ANNOUNCEMENT; + CSA_IE(pucBuffer)->ucLength = ELEM_MIN_LEN_CSA; + CSA_IE(pucBuffer)->ucChannelSwitchMode = + prAdapter->rWifiVar.ucChannelSwitchMode; + CSA_IE(pucBuffer)->ucNewChannelNum = + prAdapter->rWifiVar.ucNewChannelNumber; + CSA_IE(pucBuffer)->ucChannelSwitchCount = + prAdapter->rWifiVar.ucChannelSwitchCount; + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + pucBuffer += IE_SIZE(pucBuffer); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static void rlmFillHtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo) +{ + P_IE_HT_CAP_T prHtCap; + P_SUP_MCS_SET_FIELD prSupMcsSet; + u8 fg40mAllowed; + u8 ucIdx; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(prMsduInfo); + + fg40mAllowed = prBssInfo->fgAssoc40mBwAllowed; + + prHtCap = (P_IE_HT_CAP_T)(((u8 *)prMsduInfo->prPacket) + + prMsduInfo->u2FrameLength); + + /* Add HT capabilities IE */ + prHtCap->ucId = ELEM_ID_HT_CAP; + prHtCap->ucLength = sizeof(IE_HT_CAP_T) - ELEM_HDR_LEN; + + prHtCap->u2HtCapInfo = HT_CAP_INFO_DEFAULT_VAL; + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxShortGI)) { + prHtCap->u2HtCapInfo |= + (HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxLdpc)) { + prHtCap->u2HtCapInfo |= HT_CAP_INFO_LDPC_CAP; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucTxStbc)) { + prHtCap->u2HtCapInfo |= HT_CAP_INFO_TX_STBC; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxStbc)) { + u8 tempRxStbcNss; + + tempRxStbcNss = prAdapter->rWifiVar.ucRxStbcNss; + tempRxStbcNss = + (tempRxStbcNss > + wlanGetSupportNss(prAdapter, prBssInfo->ucBssIndex)) ? + wlanGetSupportNss(prAdapter, + prBssInfo->ucBssIndex) : + (tempRxStbcNss); + if (tempRxStbcNss != prAdapter->rWifiVar.ucRxStbcNss) { + DBGLOG(RLM, WARN, "Apply Nss:%d as RxStbcNss in HT Cap", + wlanGetSupportNss(prAdapter, + prBssInfo->ucBssIndex)); + DBGLOG(RLM, + WARN, + " due to set RxStbcNss more than Nss is not appropriate.\n"); + } + if (tempRxStbcNss == 1) { + prHtCap->u2HtCapInfo |= HT_CAP_INFO_RX_STBC_1_SS; + }else if (tempRxStbcNss == 2) { + prHtCap->u2HtCapInfo |= HT_CAP_INFO_RX_STBC_2_SS; + }else if (tempRxStbcNss >= 3) { + prHtCap->u2HtCapInfo |= HT_CAP_INFO_RX_STBC_3_SS; + } + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxGf)) { + prHtCap->u2HtCapInfo |= HT_CAP_INFO_HT_GF; + } + + if (prAdapter->rWifiVar.ucRxMaxMpduLen > VHT_CAP_INFO_MAX_MPDU_LEN_3K) { + prHtCap->u2HtCapInfo |= HT_CAP_INFO_MAX_AMSDU_LEN; + } + + if (!fg40mAllowed) { + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | + HT_CAP_INFO_DSSS_CCK_IN_40M); + } + + /* SM power saving */ /* TH3_Huang */ + if (prBssInfo->ucNss < + wlanGetSupportNss(prAdapter, prBssInfo->ucBssIndex)) { + prHtCap->u2HtCapInfo &= ~HT_CAP_INFO_SM_POWER_SAVE; /*Set as + * static + * power + * save */ + } + prHtCap->ucAmpduParam = AMPDU_PARAM_DEFAULT_VAL; + + prSupMcsSet = &prHtCap->rSupMcsSet; + kalMemZero((void *)&prSupMcsSet->aucRxMcsBitmask[0], + SUP_MCS_RX_BITMASK_OCTET_NUM); + + for (ucIdx = 0; + ucIdx < wlanGetSupportNss(prAdapter, prBssInfo->ucBssIndex); + ucIdx++) + prSupMcsSet->aucRxMcsBitmask[ucIdx] = BITS(0, 7); + + /* prSupMcsSet->aucRxMcsBitmask[0] = BITS(0, 7); */ + + if (fg40mAllowed && IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucMCS32)) { + prSupMcsSet->aucRxMcsBitmask[32 / 8] = BIT(0); /* MCS32 */ + } + prSupMcsSet->u2RxHighestSupportedRate = SUP_MCS_RX_DEFAULT_HIGHEST_RATE; + prSupMcsSet->u4TxRateInfo = SUP_MCS_TX_DEFAULT_VAL; + + prHtCap->u2HtExtendedCap = HT_EXT_CAP_DEFAULT_VAL; + if (!fg40mAllowed || + prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + prHtCap->u2HtExtendedCap &= + ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE); + } + + prHtCap->u4TxBeamformingCap = TX_BEAMFORMING_CAP_DEFAULT_VAL; +#if CFG_SUPPORT_DBDC + if ((prAdapter->rWifiVar.ucDbdcMode == DBDC_MODE_DISABLED) || + (prBssInfo->eBand == BAND_5G)) { + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucStaHtBfee)) { + prHtCap->u4TxBeamformingCap = TX_BEAMFORMING_CAP_BFEE; + } + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucStaHtBfer)) { + prHtCap->u4TxBeamformingCap |= TX_BEAMFORMING_CAP_BFER; + } + } +#endif + + prHtCap->ucAselCap = ASEL_CAP_DEFAULT_VAL; + + ASSERT(IE_SIZE(prHtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prHtCap); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static void rlmFillExtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo) +{ + P_EXT_CAP_T prExtCap; + u8 fg40mAllowed, fgAppendVhtCap; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + fg40mAllowed = prBssInfo->fgAssoc40mBwAllowed; + + /* Add Extended Capabilities IE */ + prExtCap = (P_EXT_CAP_T)(((u8 *)prMsduInfo->prPacket) + + prMsduInfo->u2FrameLength); + + prExtCap->ucId = ELEM_ID_EXTENDED_CAP; + + prExtCap->ucLength = 1; + + /* Reset memory */ + kalMemZero(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP); + + prExtCap->aucCapabilities[0] = ELEM_EXT_CAP_DEFAULT_VAL; + + if (!fg40mAllowed) { + prExtCap->aucCapabilities[0] &= + ~ELEM_EXT_CAP_20_40_COEXIST_SUPPORT; + } + + if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + prExtCap->aucCapabilities[0] &= ~ELEM_EXT_CAP_PSMP_CAP; + } + +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, + ELEM_EXT_CAP_BSS_TRANSITION_BIT); +#endif + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + +#if CFG_SUPPORT_802_11AC + fgAppendVhtCap = false; + + /* Check append rule */ + if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AC) { + /* Note: For AIS connecting state, structure in BSS_INFO will + * not be inited */ + /* So, we check StaRec instead of BssInfo */ + if (prStaRec) { + if (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11AC) { + fgAppendVhtCap = true; + } + } else if ((RLM_NET_IS_11AC(prBssInfo)) && + ((prBssInfo->eCurrentOPMode == + OP_MODE_INFRASTRUCTURE) || + (prBssInfo->eCurrentOPMode == + OP_MODE_ACCESS_POINT))) { + fgAppendVhtCap = true; + } + } + + if (fgAppendVhtCap) { + if (prExtCap->ucLength < ELEM_MAX_LEN_EXT_CAP) { + prExtCap->ucLength = ELEM_MAX_LEN_EXT_CAP; + } + + SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, + ELEM_EXT_CAP_OP_MODE_NOTIFICATION_BIT); + } +#endif + +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + prExtCap->ucLength = ELEM_MAX_LEN_EXT_CAP; + SET_EXT_CAP(prExtCap->aucCapabilities, ELEM_MAX_LEN_EXT_CAP, + ELEM_EXT_CAP_BSS_TRANSITION_BIT); +#endif + + ASSERT(IE_SIZE(prExtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_EXT_CAP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prExtCap); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static void rlmFillHtOpIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo) +{ + P_IE_HT_OP_T prHtOp; + u16 i; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(prMsduInfo); + + prHtOp = (P_IE_HT_OP_T)(((u8 *)prMsduInfo->prPacket) + + prMsduInfo->u2FrameLength); + + /* Add HT operation IE */ + prHtOp->ucId = ELEM_ID_HT_OP; + prHtOp->ucLength = sizeof(IE_HT_OP_T) - ELEM_HDR_LEN; + + /* RIFS and 20/40 bandwidth operations are included */ + prHtOp->ucPrimaryChannel = prBssInfo->ucPrimaryChannel; + prHtOp->ucInfo1 = prBssInfo->ucHtOpInfo1; + + /* Decide HT protection mode field */ + if (prBssInfo->eHtProtectMode == HT_PROTECT_MODE_NON_HT) { + prHtOp->u2Info2 = (u8)HT_PROTECT_MODE_NON_HT; + } else if (prBssInfo->eObssHtProtectMode == + HT_PROTECT_MODE_NON_MEMBER) { + prHtOp->u2Info2 = (u8)HT_PROTECT_MODE_NON_MEMBER; + } else { + /* It may be SYS_PROTECT_MODE_NONE or SYS_PROTECT_MODE_20M */ + prHtOp->u2Info2 = (u8)prBssInfo->eHtProtectMode; + } + + if (prBssInfo->eGfOperationMode != GF_MODE_NORMAL) { + /* It may be GF_MODE_PROTECT or GF_MODE_DISALLOWED + * Note: it will also be set in ad-hoc network + */ + prHtOp->u2Info2 |= HT_OP_INFO2_NON_GF_HT_STA_PRESENT; + } + + if (0 /* Regulatory class 16 */ && + prBssInfo->eObssHtProtectMode == HT_PROTECT_MODE_NON_MEMBER) { + /* (TBD) It is HT_PROTECT_MODE_NON_MEMBER, so require protection + * although it is possible to have no protection by spec. + */ + prHtOp->u2Info2 |= HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT; + } + + prHtOp->u2Info3 = prBssInfo->u2HtOpInfo3; /* To do: handle L-SIG TXOP */ + + /* No basic MCSx are needed temporarily */ + for (i = 0; i < 16; i++) + prHtOp->aucBasicMcsSet[i] = 0; + + ASSERT(IE_SIZE(prHtOp) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_OP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prHtOp); +} + +#if CFG_SUPPORT_802_11AC + +/*----------------------------------------------------------------------------*/ +/*! + * \brief For probe request, association request + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmReqGenerateVhtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + if (!prBssInfo) { + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11AC) && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11AC))) { + rlmFillVhtCapIE(prAdapter, prBssInfo, prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief For probe response (GO, IBSS) and association response + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmRspGenerateVhtCapIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + u8 ucPhyTypeSet; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + if (!prBssInfo) { + return; + } + + if (!IS_BSS_ACTIVE(prBssInfo)) { + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + /* Decide PHY type set source */ + if (prStaRec) { + /* Get PHY type set from target STA */ + ucPhyTypeSet = prStaRec->ucPhyTypeSet; + } else { + /* Get PHY type set from current BSS */ + ucPhyTypeSet = prBssInfo->ucPhyTypeSet; + } + + if (RLM_NET_IS_11AC(prBssInfo) && + (ucPhyTypeSet & PHY_TYPE_SET_802_11AC)) { + rlmFillVhtCapIE(prAdapter, prBssInfo, prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmRspGenerateVhtOpIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + u8 ucPhyTypeSet; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + if (!prBssInfo) { + return; + } + + if (!IS_BSS_ACTIVE(prBssInfo)) { + return; + } + + /* Decide PHY type set source */ + if (prStaRec) { + /* Get PHY type set from target STA */ + ucPhyTypeSet = prStaRec->ucPhyTypeSet; + } else { + /* Get PHY type set from current BSS */ + ucPhyTypeSet = prBssInfo->ucPhyTypeSet; + } + + if (RLM_NET_IS_11AC(prBssInfo) && + (ucPhyTypeSet & PHY_TYPE_SET_802_11AC)) { + rlmFillVhtOpIE(prAdapter, prBssInfo, prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief For probe request, association request + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmReqGenerateVhtOpNotificationIE(P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + if (!prBssInfo) { + return; + } + + /* [TGac 5.2.46 STBC Receive Test with UCC 9.2.x] + * Operating Notification IE of Nss=2 will make Ralink testbed send data + * frames without STBC + * Enable the Operating Notification IE only for DBDC enable case. + */ +#if CFG_SUPPORT_DBDC + if (!prAdapter->rWifiVar.fgDbDcModeEn) { + return; + } +#endif + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11AC) && + (!prStaRec || (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11AC))) { + rlmFillVhtOpNotificationIE(prAdapter, prBssInfo, prMsduInfo, + true); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmRspGenerateVhtOpNotificationIE(P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + u8 ucPhyTypeSet; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + prBssInfo = prAdapter->aprBssInfo[prMsduInfo->ucBssIndex]; + if (!prBssInfo) { + return; + } + + if (!IS_BSS_ACTIVE(prBssInfo)) { + return; + } + + /* Decide PHY type set source */ + if (prStaRec) { + /* Get PHY type set from target STA */ + ucPhyTypeSet = prStaRec->ucPhyTypeSet; + } else { + /* Get PHY type set from current BSS */ + ucPhyTypeSet = prBssInfo->ucPhyTypeSet; + } + + if (RLM_NET_IS_11AC(prBssInfo) && + (ucPhyTypeSet & PHY_TYPE_SET_802_11AC)) { + rlmFillVhtOpNotificationIE(prAdapter, prBssInfo, prMsduInfo, + false); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * add VHT operation notification IE for VHT-BW40 case specific + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static void rlmFillVhtOpNotificationIE(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo, u8 fgIsMaxCap) +{ + P_IE_VHT_OP_MODE_NOTIFICATION_T prVhtOpMode; + u8 ucMaxBw; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(prMsduInfo); + + prVhtOpMode = + (P_IE_VHT_OP_MODE_NOTIFICATION_T)(((u8 *)prMsduInfo->prPacket) + + prMsduInfo->u2FrameLength); + + kalMemZero((void *)prVhtOpMode, sizeof(IE_VHT_OP_MODE_NOTIFICATION_T)); + + prVhtOpMode->ucId = ELEM_ID_OP_MODE; + prVhtOpMode->ucLength = + sizeof(IE_VHT_OP_MODE_NOTIFICATION_T) - ELEM_HDR_LEN; + + DBGLOG(RLM, INFO, "rlmFillVhtOpNotificationIE(%d) %u %u\n", + prBssInfo->ucBssIndex, fgIsMaxCap, prBssInfo->ucNss); + + if (fgIsMaxCap) { + ucMaxBw = cnmGetBssMaxBw(prAdapter, prBssInfo->ucBssIndex); + + /*handle 80P80 case*/ + if (ucMaxBw >= MAX_BW_160MHZ) { + ucMaxBw = MAX_BW_160MHZ; + } + + prVhtOpMode->ucOperatingMode |= ucMaxBw; + + prVhtOpMode->ucOperatingMode |= + (((prBssInfo->ucNss - 1) << VHT_OP_MODE_RX_NSS_OFFSET) & + VHT_OP_MODE_RX_NSS); + } else { + switch (prBssInfo->ucVhtChannelWidth) { + case VHT_OP_CHANNEL_WIDTH_80P80: + ucMaxBw = MAX_BW_160MHZ; + break; + + case VHT_OP_CHANNEL_WIDTH_160: + ucMaxBw = MAX_BW_160MHZ; + break; + + case VHT_OP_CHANNEL_WIDTH_80: + ucMaxBw = MAX_BW_80MHZ; + break; + + case VHT_OP_CHANNEL_WIDTH_20_40: { + ucMaxBw = MAX_BW_40MHZ; + } break; + + default: + /*VHT default IE should support BW 80*/ + ucMaxBw = MAX_BW_80MHZ; + break; + } + + prVhtOpMode->ucOperatingMode |= ucMaxBw; + + prVhtOpMode->ucOperatingMode |= + (((prBssInfo->ucNss - 1) << VHT_OP_MODE_RX_NSS_OFFSET) & + VHT_OP_MODE_RX_NSS); + } + + prMsduInfo->u2FrameLength += IE_SIZE(prVhtOpMode); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static void rlmFillVhtCapIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo) +{ + P_IE_VHT_CAP_T prVhtCap; + P_VHT_SUPPORTED_MCS_FIELD prVhtSupportedMcsSet; + u8 i; + u8 ucMaxBw; + P_STA_RECORD_T prStaRec; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(prMsduInfo); + + prVhtCap = (P_IE_VHT_CAP_T)(((u8 *)prMsduInfo->prPacket) + + prMsduInfo->u2FrameLength); + + prVhtCap->ucId = ELEM_ID_VHT_CAP; + prVhtCap->ucLength = sizeof(IE_VHT_CAP_T) - ELEM_HDR_LEN; + prVhtCap->u4VhtCapInfo = VHT_CAP_INFO_DEFAULT_VAL; + + ucMaxBw = cnmGetBssMaxBw(prAdapter, prBssInfo->ucBssIndex); + + prVhtCap->u4VhtCapInfo |= (prAdapter->rWifiVar.ucRxMaxMpduLen & + VHT_CAP_INFO_MAX_MPDU_LEN_MASK); + + if (ucMaxBw == MAX_BW_160MHZ) { + prVhtCap->u4VhtCapInfo |= + VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_SET_160; + } else if (ucMaxBw == MAX_BW_80_80_MHZ) { + prVhtCap->u4VhtCapInfo |= + VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_SET_160_80P80; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucStaVhtBfee)) { + prVhtCap->u4VhtCapInfo |= FIELD_VHT_CAP_INFO_BFEE; +#if CFG_SUPPORT_BFEE + prStaRec = cnmGetStaRecByIndex(prAdapter, + prMsduInfo->ucStaRecIndex); + + if (prStaRec && + (prStaRec->ucVhtCapNumSoundingDimensions == 0x2)) { + /* For the compatibility with netgear R7000 AP */ + prVhtCap->u4VhtCapInfo |= + (((u32)prStaRec->ucVhtCapNumSoundingDimensions) + << + VHT_CAP_INFO_COMP_STEERING_NUM_OF_BFER_ANT_SUP_OFFSET); + DBGLOG(RLM, INFO, "Set VHT Cap BFEE STS CAP=%d\n", + prStaRec->ucVhtCapNumSoundingDimensions); + } else { + /* For 11ac cert. VHT-5.2.63C MU-BFee step3, + * it requires STAUT to set its maximum STS capability + * here + */ + prVhtCap->u4VhtCapInfo |= + VHT_CAP_INFO_COMPRESSED_STEERING_NUMBER_OF_BEAMFORMER_ANTENNAS_4_SUPPOERTED; + DBGLOG(RLM, INFO, "Set VHT Cap BFEE STS CAP=%d\n", + VHT_CAP_INFO_BEAMFORMEE_STS_CAP_MAX); + } +#endif + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucStaVhtMuBfee)) { + prVhtCap->u4VhtCapInfo |= + VHT_CAP_INFO_MU_BEAMFOMEE_CAPABLE; + } + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucStaVhtBfer)) { + prVhtCap->u4VhtCapInfo |= FIELD_VHT_CAP_INFO_BFER; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxShortGI)) { + prVhtCap->u4VhtCapInfo |= VHT_CAP_INFO_SHORT_GI_80; + + if (ucMaxBw >= MAX_BW_160MHZ) { + prVhtCap->u4VhtCapInfo |= + VHT_CAP_INFO_SHORT_GI_160_80P80; + } + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxLdpc)) { + prVhtCap->u4VhtCapInfo |= VHT_CAP_INFO_RX_LDPC; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxStbc)) { + u8 tempRxStbcNss; + + if (prAdapter->rWifiVar.u4SwTestMode == + ENUM_SW_TEST_MODE_SIGMA_AC) { + tempRxStbcNss = 1; + DBGLOG(RLM, INFO, + "Set RxStbcNss to 1 for 11ac certification.\n"); + } else { + tempRxStbcNss = prAdapter->rWifiVar.ucRxStbcNss; + tempRxStbcNss = + (tempRxStbcNss > + wlanGetSupportNss(prAdapter, + prBssInfo->ucBssIndex)) ? + wlanGetSupportNss( + prAdapter, + prBssInfo->ucBssIndex) : + (tempRxStbcNss); + if (tempRxStbcNss != prAdapter->rWifiVar.ucRxStbcNss) { + DBGLOG(RLM, WARN, + "Apply Nss:%d as RxStbcNss in VHT Cap", + wlanGetSupportNss(prAdapter, + prBssInfo->ucBssIndex)); + DBGLOG(RLM, + WARN, + "due to set RxStbcNss more than Nss is not appropriate.\n"); + } + } + prVhtCap->u4VhtCapInfo |= + ((tempRxStbcNss << VHT_CAP_INFO_RX_STBC_OFFSET) & + VHT_CAP_INFO_RX_STBC_MASK); + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucTxStbc)) { + prVhtCap->u4VhtCapInfo |= VHT_CAP_INFO_TX_STBC; + } + + /*set MCS map */ + prVhtSupportedMcsSet = &prVhtCap->rVhtSupportedMcsSet; + kalMemZero((void *)prVhtSupportedMcsSet, + sizeof(VHT_SUPPORTED_MCS_FIELD)); + + for (i = 0; i < 8; i++) { + u8 ucOffset = i * 2; + u8 ucMcsMap; + + if (i < wlanGetSupportNss(prAdapter, prBssInfo->ucBssIndex)) { + ucMcsMap = VHT_CAP_INFO_MCS_MAP_MCS9; + }else{ + ucMcsMap = VHT_CAP_INFO_MCS_NOT_SUPPORTED; + } + + prVhtSupportedMcsSet->u2RxMcsMap |= (ucMcsMap << ucOffset); + prVhtSupportedMcsSet->u2TxMcsMap |= (ucMcsMap << ucOffset); + } + + prVhtSupportedMcsSet->u2RxHighestSupportedDataRate = + VHT_CAP_INFO_DEFAULT_HIGHEST_DATA_RATE; + prVhtSupportedMcsSet->u2TxHighestSupportedDataRate = + VHT_CAP_INFO_DEFAULT_HIGHEST_DATA_RATE; + + ASSERT(IE_SIZE(prVhtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_CAP)); + + prMsduInfo->u2FrameLength += IE_SIZE(prVhtCap); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmFillVhtOpIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + P_MSDU_INFO_T prMsduInfo) +{ + P_IE_VHT_OP_T prVhtOp; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(prMsduInfo); + + prVhtOp = (P_IE_VHT_OP_T)(((u8 *)prMsduInfo->prPacket) + + prMsduInfo->u2FrameLength); + + /* Add HT operation IE */ + prVhtOp->ucId = ELEM_ID_VHT_OP; + prVhtOp->ucLength = sizeof(IE_VHT_OP_T) - ELEM_HDR_LEN; + + ASSERT(IE_SIZE(prVhtOp) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_OP)); + + prVhtOp->ucVhtOperation[0] = + prBssInfo->ucVhtChannelWidth; /* (UINT8)VHT_OP_CHANNEL_WIDTH_80; + */ + prVhtOp->ucVhtOperation[1] = prBssInfo->ucVhtChannelFrequencyS1; + prVhtOp->ucVhtOperation[2] = prBssInfo->ucVhtChannelFrequencyS2; + + prVhtOp->u2VhtBasicMcsSet = prBssInfo->u2VhtBasicMcsSet; + + prMsduInfo->u2FrameLength += IE_SIZE(prVhtOp); +} + +#endif + +void rlmModifyVhtBwPara(u8 *pucVhtChannelFrequencyS1, + u8 *pucVhtChannelFrequencyS2, u8 *pucVhtChannelWidth) +{ + u8 i = 0, ucTempS = 0; + + if ((*pucVhtChannelFrequencyS1 != 0) && + (*pucVhtChannelFrequencyS2 != 0)) { + u8 ucBW160Inteval = 8; + + DBGLOG(RLM, WARN, "S1=%d, S2=%d\n", *pucVhtChannelFrequencyS1, + *pucVhtChannelFrequencyS2); + + if (((*pucVhtChannelFrequencyS2 - *pucVhtChannelFrequencyS1) == + ucBW160Inteval) || + ((*pucVhtChannelFrequencyS1 - *pucVhtChannelFrequencyS2) == + ucBW160Inteval)) { + /*C160 case*/ + + /*NEW spec should set central ch of bw80 at S1, + * set central ch of bw160 at S2 + */ + for (i = 0; i < 2; i++) { + if (i == 0) { + ucTempS = *pucVhtChannelFrequencyS1; + }else{ + ucTempS = *pucVhtChannelFrequencyS2; + } + + if ((ucTempS == 50) || (ucTempS == 82) || + (ucTempS == 114) || (ucTempS == 163)) { + break; + } + } + + if (ucTempS == 0) { + DBGLOG(RLM, + WARN, + "please check BW160 setting, find central freq fail\n"); + return; + } + + *pucVhtChannelFrequencyS1 = ucTempS; + *pucVhtChannelFrequencyS2 = 0; + *pucVhtChannelWidth = CW_160MHZ; + DBGLOG(RLM, WARN, "[BW160][new spec] S1 change to %d\n", + *pucVhtChannelFrequencyS1); + } else { + /*real 80P80 case*/ + } + } +} + +void rlmRevisePreferBandwidthNss(P_ADAPTER_T prAdapter, u8 ucBssIndex, + P_STA_RECORD_T prStaRec) +{ + ENUM_CHANNEL_WIDTH_T eChannelWidth = CW_20_40MHZ; + P_BSS_INFO_T prBssInfo; + +#define VHT_MCS_TX_RX_MAX_2SS BITS(2, 3) +#define VHT_MCS_TX_RX_MAX_2SS_SHIFT 2 + +#define AR_STA_2AC_MCS(prStaRec) \ + (((prStaRec)->u2VhtRxMcsMap & VHT_MCS_TX_RX_MAX_2SS) >> \ + VHT_MCS_TX_RX_MAX_2SS_SHIFT) + +#define AR_IS_STA_2SS_AC(prStaRec) ((AR_STA_2AC_MCS(prStaRec) != BITS(0, 1))) + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + eChannelWidth = prBssInfo->ucVhtChannelWidth; + + /* + * Prefer setting modification + * 80+80 1x1 and 80 2x2 have the same phy rate, choose the 80 2x2 + */ + + if (AR_IS_STA_2SS_AC(prStaRec)) { + /* + * DBGLOG(RLM, WARN, "support 2ss\n"); + */ + + if ((eChannelWidth == CW_80P80MHZ && + prBssInfo->ucVhtChannelFrequencyS2 != 0)) { + DBGLOG(RLM, WARN, "support (2Nss) and (80+80)\n"); + DBGLOG(RLM, WARN, + "choose (2Nss) and (80) for Bss_info\n"); + prBssInfo->ucVhtChannelWidth = CW_80MHZ; + prBssInfo->ucVhtChannelFrequencyS2 = 0; + } + } +} + +/* P_ENUM_CHANNEL_WIDTH_P peChannelWidth will be treated as u16 * pointer + * updating peChannelWidth will overwrite pucS1 + */ +void rlmReviseMaxBw(P_ADAPTER_T prAdapter, u8 ucBssIndex, + P_ENUM_CHNL_EXT_T peExtend, + // P_ENUM_CHANNEL_WIDTH_P peChannelWidth, + u8 *peChannelWidth, u8 *pucS1, u8 *pucPrimaryCh) +{ + u8 ucMaxBandwidth = MAX_BW_80MHZ; + u8 ucCurrentBandwidth = MAX_BW_20MHZ; + u8 ucOffset = (MAX_BW_80MHZ - CW_80MHZ); + + ucMaxBandwidth = cnmGetBssMaxBw(prAdapter, ucBssIndex); + + if (*peChannelWidth > CW_20_40MHZ) { + /*case BW > 80 , 160 80P80 */ + ucCurrentBandwidth = (u8) * peChannelWidth + ucOffset; + } else { + /*case BW20 BW40 */ + if (*peExtend != CHNL_EXT_SCN) { + /*case BW40 */ + ucCurrentBandwidth = MAX_BW_40MHZ; + } + } + + if (ucCurrentBandwidth > ucMaxBandwidth) { + DBGLOG(RLM, INFO, "Decreasse the BW to (%d)\n", ucMaxBandwidth); + + if (ucMaxBandwidth <= MAX_BW_40MHZ) { + /*BW20 * BW40*/ + *peChannelWidth = CW_20_40MHZ; + + if (ucMaxBandwidth == MAX_BW_20MHZ) { + *peExtend = CHNL_EXT_SCN; + } + } else { + /* BW80, BW160, BW80P80 */ + /* ucMaxBandwidth Must be + * MAX_BW_80MHZ,MAX_BW_160MHZ,MAX_BW_80MHZ */ + /* peExtend should not change */ + *peChannelWidth = (ucMaxBandwidth - ucOffset); + + if (ucMaxBandwidth == MAX_BW_80MHZ) { + /* modify S1 for Bandwidth 160 downgrade 80 case + */ + if (ucCurrentBandwidth == MAX_BW_160MHZ) { + if ((*pucPrimaryCh >= 36) && + (*pucPrimaryCh <= 48)) { + *pucS1 = 42; + } else if ((*pucPrimaryCh >= 52) && + (*pucPrimaryCh <= 64)) { + *pucS1 = 58; + } else if ((*pucPrimaryCh >= 100) && + (*pucPrimaryCh <= 112)) { + *pucS1 = 106; + } else if ((*pucPrimaryCh >= 116) && + (*pucPrimaryCh <= 128)) { + *pucS1 = 122; + } else if ((*pucPrimaryCh >= 132) && + (*pucPrimaryCh <= 144)) { + *pucS1 = 138; /*160 downgrade + * should not in + * this case*/ + } else if ((*pucPrimaryCh >= 149) && + (*pucPrimaryCh <= 161)) { + *pucS1 = 155; /*160 downgrade + * should not in + * this case*/ + } else { + DBGLOG(RLM, + INFO, + "Check connect 160 downgrde (%d) case\n", + ucMaxBandwidth); + } + + DBGLOG(RLM, + INFO, + "Decreasse the BW160 to BW80, shift S1 to (%d)\n", + *pucS1); + } + } + } + + DBGLOG(RLM, + INFO, + "Modify ChannelWidth (%d) and Extend (%d)\n", + *peChannelWidth, + *peExtend); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Change VHT OP Channel Width, S1, S2 + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmChangeVhtOpBwPara(P_ADAPTER_T prAdapter, u8 ucBssIndex, + u8 ucChannelWidth) +{ + P_BSS_INFO_T prBssInfo; + u8 ucVhtLowerChannelFrequency, ucVhtUpperChannelFrequency = 0; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if (!prBssInfo) { + return; + } + + if (ucChannelWidth == MAX_BW_80_80_MHZ) { + prBssInfo->ucVhtChannelWidth = VHT_OP_CHANNEL_WIDTH_80P80; + } else if (ucChannelWidth == MAX_BW_160MHZ) { + prBssInfo->ucVhtChannelWidth = VHT_OP_CHANNEL_WIDTH_160; + } else if (ucChannelWidth == MAX_BW_80MHZ) { + prBssInfo->ucVhtChannelWidth = VHT_OP_CHANNEL_WIDTH_80; + if (prBssInfo->ucVhtPeerChannelWidth == + VHT_OP_CHANNEL_WIDTH_160) { + prBssInfo->ucVhtChannelFrequencyS1 = + (prBssInfo->ucVhtPeerChannelFrequencyS1 > + prBssInfo->ucPrimaryChannel) ? + (prBssInfo->ucVhtPeerChannelFrequencyS1 - + 8) : + (prBssInfo->ucVhtPeerChannelFrequencyS1 + + 8); + } else if (prBssInfo->ucVhtPeerChannelWidth == + VHT_OP_CHANNEL_WIDTH_80P80) { + if (prBssInfo->ucVhtChannelFrequencyS1 < + prBssInfo->ucVhtChannelFrequencyS2) { + ucVhtLowerChannelFrequency = + prBssInfo->ucVhtChannelFrequencyS1; + ucVhtUpperChannelFrequency = + prBssInfo->ucVhtChannelFrequencyS2; + } else { + ucVhtLowerChannelFrequency = + prBssInfo->ucVhtChannelFrequencyS2; + ucVhtUpperChannelFrequency = + prBssInfo->ucVhtChannelFrequencyS1; + } + prBssInfo->ucVhtChannelFrequencyS1 = + prBssInfo->ucPrimaryChannel < + ((ucVhtLowerChannelFrequency + + ucVhtUpperChannelFrequency) / + 2) ? + ucVhtLowerChannelFrequency : + ucVhtUpperChannelFrequency; + prBssInfo->ucVhtChannelFrequencyS2 = 0; + } + } else if ((ucChannelWidth == MAX_BW_40MHZ) || + (ucChannelWidth == MAX_BW_20MHZ)) { + prBssInfo->ucVhtChannelWidth = VHT_OP_CHANNEL_WIDTH_20_40; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function should be invoked to update parameters of associated AP. + * (Association response and Beacon) + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static u8 rlmRecIeInfoForClient(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + u8 *pucIE, u16 u2IELength) +{ + u16 u2Offset; + P_STA_RECORD_T prStaRec; + P_IE_HT_CAP_T prHtCap; + P_IE_HT_OP_T prHtOp; + P_IE_OBSS_SCAN_PARAM_T prObssScnParam; + u8 ucERP, ucPrimaryChannel; + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; +#if CFG_SUPPORT_QUIET + u8 fgHasQuietIE = false; +#endif + u8 IsfgHtCapChange = false; + +#if CFG_SUPPORT_802_11AC + P_IE_VHT_OP_T prVhtOp; + P_IE_VHT_CAP_T prVhtCap; + P_IE_OP_MODE_NOTIFICATION_T + prOPModeNotification; /* Operation Mode Notification */ + u8 fgHasOPModeIE = false; + u8 ucVhtOpModeChannelWidth = 0; + u8 ucVhtOpModeRxNss = 0; + u8 ucVhtCapMcsOwnNotSupportOffset; + u8 ucMaxBwAllowed; + u8 ucInitVhtOpMode = 0; +#endif + +#if CFG_SUPPORT_DFS + P_BSS_DESC_T prBssDesc; + P_IE_CHANNEL_SWITCH_T prCSAIE; + P_SWITCH_CH_AND_BAND_PARAMS_T prCSAParams; + u8 ucCurrentCsaCount; + P_IE_SECONDARY_OFFSET_T prSecondaryOffsetIE; + P_IE_WIDE_BAND_CHANNEL_T prWideBandChannelIE; +#if CFG_DFS_NEWCH_DFS_FORCE_DISCONNECT + struct channel *Channel = NULL; + u8 max_count, i; +#endif +#endif + u8 *pucDumpIE; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(pucIE); + + prStaRec = prBssInfo->prStaRecOfAP; + ASSERT(prStaRec); + if (!prStaRec) { + return 0; + } + + prBssInfo->fgUseShortPreamble = prBssInfo->fgIsShortPreambleAllowed; + ucPrimaryChannel = 0; + prObssScnParam = NULL; + ucMaxBwAllowed = cnmGetBssMaxBw(prAdapter, prBssInfo->ucBssIndex); + prBssDesc = prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc; + pucDumpIE = pucIE; +#if CFG_SUPPORT_DFS + prCSAParams = &prBssInfo->CSAParams; + ucCurrentCsaCount = MAX_CSA_COUNT; +#endif + + /* Note: HT-related members in staRec may not be zero before, so + * if following IE does not exist, they are still not zero. + * These HT-related parameters are valid only when the + * corresponding BssInfo supports 802.11n, i.e., RLM_NET_IS_11N() + */ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_HT_CAP: + if (!RLM_NET_IS_11N(prBssInfo) || + IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) { + break; + } + prHtCap = (P_IE_HT_CAP_T)pucIE; + prStaRec->ucMcsSet = + prHtCap->rSupMcsSet.aucRxMcsBitmask[0]; + prStaRec->fgSupMcs32 = + (prHtCap->rSupMcsSet.aucRxMcsBitmask[32 / 8] & + BIT(0)) ? + true : + false; + + kalMemCopy( + prStaRec->aucRxMcsBitmask, + prHtCap->rSupMcsSet.aucRxMcsBitmask, + sizeof(prStaRec->aucRxMcsBitmask) /*SUP_MCS_RX_BITMASK_OCTET_NUM */ ); + + prStaRec->u2RxHighestSupportedRate = + prHtCap->rSupMcsSet.u2RxHighestSupportedRate; + prStaRec->u4TxRateInfo = + prHtCap->rSupMcsSet.u4TxRateInfo; + + if ((prStaRec->u2HtCapInfo & + HT_CAP_INFO_SM_POWER_SAVE) != + (prHtCap->u2HtCapInfo & + HT_CAP_INFO_SM_POWER_SAVE)) { + IsfgHtCapChange = true; /* Purpose : To detect + * SMPS change */ + } + prStaRec->u2HtCapInfo = prHtCap->u2HtCapInfo; + /* Set LDPC Tx capability */ + if (IS_FEATURE_FORCE_ENABLED(prWifiVar->ucTxLdpc)) { + prStaRec->u2HtCapInfo |= HT_CAP_INFO_LDPC_CAP; + }else if (IS_FEATURE_DISABLED(prWifiVar->ucTxLdpc)) { + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_LDPC_CAP; + } + + /* Set STBC Tx capability */ + if (IS_FEATURE_FORCE_ENABLED(prWifiVar->ucTxStbc)) { + prStaRec->u2HtCapInfo |= HT_CAP_INFO_RX_STBC; + }else if (IS_FEATURE_DISABLED(prWifiVar->ucTxStbc)) { + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_RX_STBC; + } + + /* Set Short GI Tx capability */ + if (IS_FEATURE_FORCE_ENABLED(prWifiVar->ucTxShortGI)) { + prStaRec->u2HtCapInfo |= + HT_CAP_INFO_SHORT_GI_20M; + prStaRec->u2HtCapInfo |= + HT_CAP_INFO_SHORT_GI_40M; + } else if (IS_FEATURE_DISABLED( + prWifiVar->ucTxShortGI)) { + prStaRec->u2HtCapInfo &= + ~HT_CAP_INFO_SHORT_GI_20M; + prStaRec->u2HtCapInfo &= + ~HT_CAP_INFO_SHORT_GI_40M; + } + + /* Set HT Greenfield Tx capability */ + if (IS_FEATURE_FORCE_ENABLED(prWifiVar->ucTxGf)) { + prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; + }else if (IS_FEATURE_DISABLED(prWifiVar->ucTxGf)) { + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_HT_GF; + } + + prStaRec->ucAmpduParam = prHtCap->ucAmpduParam; + prStaRec->u2HtExtendedCap = prHtCap->u2HtExtendedCap; + prStaRec->u4TxBeamformingCap = + prHtCap->u4TxBeamformingCap; + prStaRec->ucAselCap = prHtCap->ucAselCap; + break; + + case ELEM_ID_HT_OP: + if (!RLM_NET_IS_11N(prBssInfo) || + IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) { + break; + } + prHtOp = (P_IE_HT_OP_T)pucIE; + /* Workaround that some APs fill primary channel field + * by its secondary channel, but its DS IE is correct + * 20110610 + */ + if (ucPrimaryChannel == 0) { + ucPrimaryChannel = prHtOp->ucPrimaryChannel; + } + prBssInfo->ucHtOpInfo1 = prHtOp->ucInfo1; + prBssInfo->u2HtOpInfo2 = prHtOp->u2Info2; + prBssInfo->u2HtOpInfo3 = prHtOp->u2Info3; + + /*Backup peer HT OP Info*/ + prBssInfo->ucHtPeerOpInfo1 = prHtOp->ucInfo1; + + if (!prBssInfo->fg40mBwAllowed) { + prBssInfo->ucHtOpInfo1 &= + ~(HT_OP_INFO1_SCO | + HT_OP_INFO1_STA_CHNL_WIDTH); + } + + if ((prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_SCO) != + CHNL_EXT_RES) { + prBssInfo->eBssSCO = + (ENUM_CHNL_EXT_T)(prBssInfo->ucHtOpInfo1 + & + HT_OP_INFO1_SCO); + } + + if (prBssInfo->ucOpChangeChannelWidth == MAX_BW_20MHZ && + prBssInfo->fgIsOpChangeChannelWidth) { + prBssInfo->ucHtOpInfo1 &= + ~(HT_OP_INFO1_SCO | + HT_OP_INFO1_STA_CHNL_WIDTH); + prBssInfo->eBssSCO = CHNL_EXT_SCN; + } + + prBssInfo->eHtProtectMode = + (ENUM_HT_PROTECT_MODE_T)(prBssInfo->u2HtOpInfo2 + & + HT_OP_INFO2_HT_PROTECTION); + + /* To do: process regulatory class 16 */ + if ((prBssInfo->u2HtOpInfo2 & + HT_OP_INFO2_OBSS_NON_HT_STA_PRESENT) && + 0 /* && regulatory class is 16 */ ) { + prBssInfo->eGfOperationMode = + GF_MODE_DISALLOWED; + } else if (prBssInfo->u2HtOpInfo2 & + HT_OP_INFO2_NON_GF_HT_STA_PRESENT) { + prBssInfo->eGfOperationMode = GF_MODE_PROTECT; + } else { + prBssInfo->eGfOperationMode = GF_MODE_NORMAL; + } + + prBssInfo->eRifsOperationMode = + (prBssInfo->ucHtOpInfo1 & + HT_OP_INFO1_RIFS_MODE) ? + RIFS_MODE_NORMAL : + RIFS_MODE_DISALLOWED; + + break; + +#if CFG_SUPPORT_802_11AC + case ELEM_ID_VHT_CAP: + if (!RLM_NET_IS_11AC(prBssInfo) || + IE_LEN(pucIE) != (sizeof(IE_VHT_CAP_T) - 2)) { + break; + } + + prVhtCap = (P_IE_VHT_CAP_T)pucIE; + + prStaRec->u4VhtCapInfo = prVhtCap->u4VhtCapInfo; + /* Set Tx LDPC capability */ + if (IS_FEATURE_FORCE_ENABLED(prWifiVar->ucTxLdpc)) { + prStaRec->u4VhtCapInfo |= VHT_CAP_INFO_RX_LDPC; + }else if (IS_FEATURE_DISABLED(prWifiVar->ucTxLdpc)) { + prStaRec->u4VhtCapInfo &= ~VHT_CAP_INFO_RX_LDPC; + } + + /* Set Tx STBC capability */ + if (IS_FEATURE_FORCE_ENABLED(prWifiVar->ucTxStbc)) { + prStaRec->u4VhtCapInfo |= + VHT_CAP_INFO_RX_STBC_MASK; + } else if (IS_FEATURE_DISABLED(prWifiVar->ucTxStbc)) { + prStaRec->u4VhtCapInfo &= + ~VHT_CAP_INFO_RX_STBC_MASK; + } + + /* Set Tx TXOP PS capability */ + if (IS_FEATURE_FORCE_ENABLED(prWifiVar->ucTxopPsTx)) { + prStaRec->u4VhtCapInfo |= + VHT_CAP_INFO_VHT_TXOP_PS; + } else if (IS_FEATURE_DISABLED(prWifiVar->ucTxopPsTx)) { + prStaRec->u4VhtCapInfo &= + ~VHT_CAP_INFO_VHT_TXOP_PS; + } + + /* Set Tx Short GI capability */ + if (IS_FEATURE_FORCE_ENABLED(prWifiVar->ucTxShortGI)) { + prStaRec->u4VhtCapInfo |= + VHT_CAP_INFO_SHORT_GI_80; + prStaRec->u4VhtCapInfo |= + VHT_CAP_INFO_SHORT_GI_160_80P80; + } else if (IS_FEATURE_DISABLED( + prWifiVar->ucTxShortGI)) { + prStaRec->u4VhtCapInfo &= + ~VHT_CAP_INFO_SHORT_GI_80; + prStaRec->u4VhtCapInfo &= + ~VHT_CAP_INFO_SHORT_GI_160_80P80; + } + + /*Set Vht Rx Mcs Map upon peer's capability and our + * capability */ + prStaRec->u2VhtRxMcsMap = + prVhtCap->rVhtSupportedMcsSet.u2RxMcsMap; + if (wlanGetSupportNss(prAdapter, prStaRec->ucBssIndex) < + 8) { + ucVhtCapMcsOwnNotSupportOffset = + wlanGetSupportNss( + prAdapter, + prStaRec->ucBssIndex) * + 2; + /*Mark Rx Mcs Map which we don't support*/ + prStaRec->u2VhtRxMcsMap |= BITS( + ucVhtCapMcsOwnNotSupportOffset, 15); + } + if (prStaRec->u2VhtRxMcsMap != + prVhtCap->rVhtSupportedMcsSet.u2RxMcsMap) { + DBGLOG(RLM, + INFO, + "Change VhtRxMcsMap from 0x%x to 0x%x due to our Nss setting\n", + prVhtCap->rVhtSupportedMcsSet.u2RxMcsMap, + prStaRec->u2VhtRxMcsMap); + } + + prStaRec->u2VhtRxHighestSupportedDataRate = + prVhtCap->rVhtSupportedMcsSet + .u2RxHighestSupportedDataRate; + prStaRec->u2VhtTxMcsMap = + prVhtCap->rVhtSupportedMcsSet.u2TxMcsMap; + prStaRec->u2VhtTxHighestSupportedDataRate = + prVhtCap->rVhtSupportedMcsSet + .u2TxHighestSupportedDataRate; + + break; + + case ELEM_ID_VHT_OP: + if (!RLM_NET_IS_11AC(prBssInfo) || + IE_LEN(pucIE) != (sizeof(IE_VHT_OP_T) - 2)) { + break; + } + + prVhtOp = (P_IE_VHT_OP_T)pucIE; + + /*Backup peer VHT OpInfo*/ + prBssInfo->ucVhtPeerChannelWidth = + prVhtOp->ucVhtOperation[0]; + prBssInfo->ucVhtPeerChannelFrequencyS1 = + prVhtOp->ucVhtOperation[1]; + prBssInfo->ucVhtPeerChannelFrequencyS2 = + prVhtOp->ucVhtOperation[2]; + + rlmModifyVhtBwPara( + &prBssInfo->ucVhtPeerChannelFrequencyS1, + &prBssInfo->ucVhtPeerChannelFrequencyS2, + &prBssInfo->ucVhtPeerChannelWidth); + + prBssInfo->ucVhtChannelWidth = + prVhtOp->ucVhtOperation[0]; + prBssInfo->ucVhtChannelFrequencyS1 = + prVhtOp->ucVhtOperation[1]; + prBssInfo->ucVhtChannelFrequencyS2 = + prVhtOp->ucVhtOperation[2]; + prBssInfo->u2VhtBasicMcsSet = prVhtOp->u2VhtBasicMcsSet; + + rlmModifyVhtBwPara(&prBssInfo->ucVhtChannelFrequencyS1, + &prBssInfo->ucVhtChannelFrequencyS2, + &prBssInfo->ucVhtChannelWidth); + + if (prBssInfo->fgIsOpChangeChannelWidth) { + rlmChangeVhtOpBwPara( + prAdapter, prBssInfo->ucBssIndex, + prBssInfo->ucOpChangeChannelWidth); + } + + /* Set initial value of VHT OP mode */ + ucInitVhtOpMode = 0; + switch (prBssInfo->ucVhtChannelWidth) { + case VHT_OP_CHANNEL_WIDTH_20_40: + ucInitVhtOpMode |= VHT_OP_MODE_CHANNEL_WIDTH_40; + break; + + case VHT_OP_CHANNEL_WIDTH_80: + ucInitVhtOpMode |= VHT_OP_MODE_CHANNEL_WIDTH_80; + break; + + case VHT_OP_CHANNEL_WIDTH_160: + case VHT_OP_CHANNEL_WIDTH_80P80: + ucInitVhtOpMode |= + VHT_OP_MODE_CHANNEL_WIDTH_160_80P80; + break; + + default: + ucInitVhtOpMode |= VHT_OP_MODE_CHANNEL_WIDTH_80; + break; + } + ucInitVhtOpMode |= ((prBssInfo->ucNss - 1) + << VHT_OP_MODE_RX_NSS_OFFSET) & + VHT_OP_MODE_RX_NSS; + break; + + case ELEM_ID_OP_MODE: + if (!RLM_NET_IS_11AC(prBssInfo) || + IE_LEN(pucIE) != + (sizeof(IE_OP_MODE_NOTIFICATION_T) - 2)) { + break; + } + prOPModeNotification = + (P_IE_OP_MODE_NOTIFICATION_T)pucIE; + + if ((prOPModeNotification->ucOpMode & + VHT_OP_MODE_RX_NSS_TYPE) != + VHT_OP_MODE_RX_NSS_TYPE) { + if (prStaRec->ucVhtOpMode != + prOPModeNotification->ucOpMode) { + prStaRec->ucVhtOpMode = + prOPModeNotification->ucOpMode; + fgHasOPModeIE = true; + ucVhtOpModeChannelWidth = + ((prOPModeNotification + ->ucOpMode) & + VHT_OP_MODE_CHANNEL_WIDTH); + ucVhtOpModeRxNss = + ((prOPModeNotification + ->ucOpMode) & + VHT_OP_MODE_RX_NSS) >> + VHT_OP_MODE_RX_NSS_OFFSET; + } else { /* Let the further flow not to update + * VhtOpMode */ + ucInitVhtOpMode = prStaRec->ucVhtOpMode; + } + } + + break; + +#if CFG_SUPPORT_DFS + case ELEM_ID_WIDE_BAND_CHANNEL_SWITCH: + if (!RLM_NET_IS_11AC(prBssInfo) || + IE_LEN(pucIE) != + (sizeof(IE_WIDE_BAND_CHANNEL_T) - 2)) { + break; + } + DBGLOG(RLM, + INFO, + "[Channel Switch] ELEM_ID_WIDE_BAND_CHANNEL_SWITCH, 11AC\n"); + prWideBandChannelIE = (P_IE_WIDE_BAND_CHANNEL_T)pucIE; + prCSAParams->ucVhtBw = + prWideBandChannelIE->ucNewChannelWidth; + prCSAParams->ucVhtS1 = prWideBandChannelIE->ucChannelS1; + prCSAParams->ucVhtS2 = prWideBandChannelIE->ucChannelS2; + DBGLOG(RLM, STATE, "[Ch] BW=%d, s1=%d, s2=%d\n", + prCSAParams->ucVhtBw, prCSAParams->ucVhtS1, + prCSAParams->ucVhtS2); + break; + +#endif +#endif + case ELEM_ID_20_40_BSS_COEXISTENCE: + if (!RLM_NET_IS_11N(prBssInfo)) { + break; + } + /* To do: store if scanning exemption grant to BssInfo + */ + break; + + case ELEM_ID_OBSS_SCAN_PARAMS: + if (!RLM_NET_IS_11N(prBssInfo) || + IE_LEN(pucIE) != (sizeof(IE_OBSS_SCAN_PARAM_T) - 2)) { + break; + } + /* Store OBSS parameters to BssInfo */ + prObssScnParam = (P_IE_OBSS_SCAN_PARAM_T)pucIE; + break; + + case ELEM_ID_EXTENDED_CAP: + if (!RLM_NET_IS_11N(prBssInfo)) { + break; + } + /* To do: store extended capability (PSMP, coexist) to + * BssInfo */ + break; + + case ELEM_ID_ERP_INFO: + if (IE_LEN(pucIE) != (sizeof(IE_ERP_T) - 2) || + prBssInfo->eBand != BAND_2G4) { + break; + } + ucERP = ERP_INFO_IE(pucIE)->ucERP; + prBssInfo->fgErpProtectMode = + (ucERP & ERP_INFO_USE_PROTECTION) ? true : + false; + + if (ucERP & ERP_INFO_BARKER_PREAMBLE_MODE) { + prBssInfo->fgUseShortPreamble = false; + } + break; + + case ELEM_ID_DS_PARAM_SET: + if (IE_LEN(pucIE) == ELEM_MAX_LEN_DS_PARAMETER_SET) { + ucPrimaryChannel = + DS_PARAM_IE(pucIE)->ucCurrChnl; + } + break; + +#if CFG_SUPPORT_DFS + case ELEM_ID_CH_SW_ANNOUNCEMENT: + if (IE_LEN(pucIE) != (sizeof(IE_CHANNEL_SWITCH_T) - 2)) { + break; + } + + prCSAIE = (P_IE_CHANNEL_SWITCH_T)pucIE; + + DBGLOG(RLM, STATE, "[Ch] Count=%d\n", + prCSAIE->ucChannelSwitchCount); + + prCSAParams->ucCsaNewCh = prCSAIE->ucNewChannelNum; + ucCurrentCsaCount = prCSAIE->ucChannelSwitchCount; + + if (prCSAIE->ucChannelSwitchMode == 1) { + /* Need to stop data transmission immediately */ + if (!prBssInfo->fgHasStopTx) { + prBssInfo->fgHasStopTx = true; + g_fgFowardBcn2Supplicant = true; +#if CFG_SUPPORT_TDLS + /* TDLS peers */ + TdlsTxCtrl(prAdapter, prBssInfo, false); +#endif + /* AP */ + qmSetStaRecTxAllowed(prAdapter, + prStaRec, false); + DBGLOG(RLM, EVENT, + "[CSA] TxAllowed = false\n"); + } + } + +#if CFG_DFS_NEWCH_DFS_FORCE_DISCONNECT + max_count = rlmDomainGetActiveChannelCount( + NL80211_BAND_5GHZ) + + rlmDomainGetActiveChannelCount( + NL80211_BAND_2GHZ); + for (i = 0; i < max_count; i++) { + Channel = rlmDomainGetActiveChannels() + i; + + if (Channel->chNum != + prCSAIE->ucNewChannelNum) { + Channel = NULL; + continue; + } else if (Channel->chNum == + prCSAIE->ucNewChannelNum) { + break; + } + } + + DBGLOG(RLM, + INFO, + "[DFS][CSA][CLIENT] Switch to new channel: new ChNum = [%d]\n", + prCSAIE->ucNewChannelNum); + if ((Channel) && + (Channel->flags & IEEE80211_CHAN_RADAR)) { + prCSAParams->fgBeaconNewChannelIsDFS = true; + DBGLOG(RLM, + INFO, + "[DFS][CSA][CLIENT] New channel is DFS channel!"); + } else if (!Channel) { + prCSAParams->fgNewChannelIsDisabled = true; + DBGLOG(RLM, + INFO, + "[DFS][CSA][CLIENT] New channel is un-supported channel!"); + } else { + DBGLOG(RLM, + INFO, + "[DFS][CSA][CLIENT] New channel is non-DFS channel!"); + } +#endif + break; + + case ELEM_ID_SCO: + if (IE_LEN(pucIE) != + (sizeof(IE_SECONDARY_OFFSET_T) - 2)) { + break; + } + + prSecondaryOffsetIE = (P_IE_SECONDARY_OFFSET_T)pucIE; + DBGLOG(RLM, INFO, "[Channel Switch] SCO [%d]->[%d]\n", + prBssInfo->eBssSCO, + prSecondaryOffsetIE->ucSecondaryOffset); + prCSAParams->eSco = + (ENUM_CHNL_EXT_T) + prSecondaryOffsetIE->ucSecondaryOffset; + break; +#endif + +#if CFG_SUPPORT_QUIET + /* Note: RRM code should be moved to independent RRM function by + * component design rule. But we attach it to RLM + * temporarily + */ + case ELEM_ID_QUIET: + rrmQuietHandleQuietIE(prAdapter, prBssInfo, + (P_IE_QUIET_T)pucIE); + g_fgFowardBcn2Supplicant = true; + fgHasQuietIE = true; + break; + +#endif + default: + break; + } /* end of switch */ + } /* end of IE_FOR_EACH */ + + if (IsfgHtCapChange && (prStaRec->ucStaState == STA_STATE_3)) { + cnmStaSendUpdateCmd(prAdapter, prStaRec, NULL, false); + } + + /* Some AP will have wrong channel number (255) when running time. + * Check if correct channel number information. 20110501 + */ + if ((prBssInfo->eBand == BAND_2G4 && ucPrimaryChannel > 14) || + (prBssInfo->eBand != BAND_2G4 && + (ucPrimaryChannel >= 200 || ucPrimaryChannel <= 14))) { + ucPrimaryChannel = 0; + } +#if CFG_SUPPORT_802_11AC + /* Check whether the Operation Mode IE is exist or not. + * If exists, then the channel bandwidth of VHT operation field is + * changed with the channel bandwidth setting of Operation Mode field. + * The channel bandwidth of OP Mode IE is 0, represent as 20MHz. + * The channel bandwidth of OP Mode IE is 1, represent as 40MHz. + * The channel bandwidth of OP Mode IE is 2, represent as 80MHz. + * The channel bandwidth of OP Mode IE is 3, represent as + * 160/80+80MHz. + */ + if (fgHasOPModeIE == true) { + /* 1.Channel width change */ + + if (ucVhtOpModeChannelWidth == VHT_OP_MODE_CHANNEL_WIDTH_20) { + prBssInfo->ucVhtChannelWidth = CW_20_40MHZ; + prBssInfo->ucHtOpInfo1 &= ~HT_OP_INFO1_STA_CHNL_WIDTH; + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; + +#if CFG_WORKAROUND_OPMODE_CONFLICT_OPINFO + if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { + DBGLOG(RLM, + WARN, + "HT_OP_Info != OPmode_Notifify, follow OPmode_Notify to BW20.\n"); + prBssInfo->eBssSCO = CHNL_EXT_SCN; + } +#endif + } else if (ucVhtOpModeChannelWidth == + VHT_OP_MODE_CHANNEL_WIDTH_40) { + prBssInfo->ucVhtChannelWidth = CW_20_40MHZ; + prBssInfo->ucHtOpInfo1 |= HT_OP_INFO1_STA_CHNL_WIDTH; + prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; + +#if CFG_WORKAROUND_OPMODE_CONFLICT_OPINFO + if (prBssInfo->eBssSCO == CHNL_EXT_SCN) { + prBssInfo->ucHtOpInfo1 &= + ~HT_OP_INFO1_STA_CHNL_WIDTH; + prStaRec->u2HtCapInfo &= + ~HT_CAP_INFO_SUP_CHNL_WIDTH; + DBGLOG(RLM, + WARN, + "HT_OP_Info != OPmode_Notifify, follow HT_OP_Info to BW20.\n"); + } +#endif + } else if (ucVhtOpModeChannelWidth == + VHT_OP_MODE_CHANNEL_WIDTH_80) { + prBssInfo->ucVhtChannelWidth = CW_80MHZ; + prBssInfo->ucHtOpInfo1 |= HT_OP_INFO1_STA_CHNL_WIDTH; + prStaRec->u4VhtCapInfo &= + ~VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_MASK; + prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; + } else if (ucVhtOpModeChannelWidth == + VHT_OP_MODE_CHANNEL_WIDTH_160_80P80) { + prBssInfo->ucHtOpInfo1 |= HT_OP_INFO1_STA_CHNL_WIDTH; + prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; + + /* Use VHT OP Info to determine it's BW160 or BW80+BW80 + */ + prStaRec->u4VhtCapInfo &= + ~VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_MASK; + if (prBssInfo->ucVhtChannelWidth == + VHT_OP_CHANNEL_WIDTH_160) { + prStaRec->u4VhtCapInfo |= + VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_SET_160; + } else if (prBssInfo->ucVhtChannelWidth == + VHT_OP_CHANNEL_WIDTH_80P80) { + prStaRec->u4VhtCapInfo |= + VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_SET_160_80P80; + } + } + + if (prStaRec->ucStaState == STA_STATE_3) { + DBGLOG(RLM, INFO, "Update OpMode to 0x%x", + prStaRec->ucVhtOpMode); + DBGLOG(RLM, INFO, + "to FW due to OpMode Notificaition\n"); + cnmStaSendUpdateCmd(prAdapter, prStaRec, NULL, false); + } + } else { /* Set Default if the VHT OP mode field is not present */ + if ((prStaRec->ucVhtOpMode != ucInitVhtOpMode) && + (prStaRec->ucStaState == STA_STATE_3)) { + prStaRec->ucVhtOpMode = ucInitVhtOpMode; + DBGLOG(RLM, INFO, "Update OpMode to 0x%x", + prStaRec->ucVhtOpMode); + DBGLOG(RLM, INFO, + "to FW due to NO OpMode Notificaition\n"); + cnmStaSendUpdateCmd(prAdapter, prStaRec, NULL, false); + } else { + prStaRec->ucVhtOpMode = ucInitVhtOpMode; + } + } +#endif + +#if CFG_SUPPORT_DFS + if (SHOULD_CH_SWITCH(ucCurrentCsaCount, prCSAParams, prBssDesc)) { + cnmTimerStopTimer(prAdapter, &prBssInfo->rCsaTimer); + cnmTimerStartTimer(prAdapter, &prBssInfo->rCsaTimer, + TU_TO_MSEC(prBssInfo->u2BeaconInterval * + ucCurrentCsaCount)); + prCSAParams->ucCsaCount = ucCurrentCsaCount; + DBGLOG(RLM, INFO, "Channel switch Countdown: %d msecs\n", + TU_TO_MSEC(prBssInfo->u2BeaconInterval * + prCSAParams->ucCsaCount)); + } + if (!HAS_CH_SWITCH_PARAMS(prCSAParams, prBssDesc) && + prBssInfo->fgHasStopTx +#if CFG_SUPPORT_QUIET + && !prBssInfo->fgIsInQuietInterval +#endif + ) { +#if CFG_SUPPORT_TDLS + /* TDLS peers */ + TdlsTxCtrl(prAdapter, prBssInfo, true); +#endif + prBssInfo->fgHasStopTx = false; + } +#endif + + rlmReviseMaxBw(prAdapter, prBssInfo->ucBssIndex, &prBssInfo->eBssSCO, + (u8 *)&prBssInfo->ucVhtChannelWidth, + &prBssInfo->ucVhtChannelFrequencyS1, + &prBssInfo->ucPrimaryChannel); + + rlmRevisePreferBandwidthNss(prAdapter, prBssInfo->ucBssIndex, prStaRec); + + /*printk("Modify ChannelWidth (%d) and Extend + * (%d)\n",prBssInfo->eBssSCO,prBssInfo->ucVhtChannelWidth);*/ + + /* Revise and align S1 to primary channel */ + if (prBssInfo->ucVhtChannelFrequencyS1 != + nicGetVhtS1(prBssInfo->ucPrimaryChannel, + prBssInfo->ucVhtChannelWidth)) { + DBGLOG(RLM, STATE, "Revise BSS %d Ch=%d BW=%d S1=%d\n", + prBssInfo->ucBssIndex, prBssInfo->ucPrimaryChannel, + prBssInfo->ucVhtChannelWidth, + prBssInfo->ucVhtChannelFrequencyS1); + } + + if (!rlmDomainIsValidRfSetting( + prAdapter, prBssInfo->eBand, prBssInfo->ucPrimaryChannel, + prBssInfo->eBssSCO, prBssInfo->ucVhtChannelWidth, + prBssInfo->ucVhtChannelFrequencyS1, + prBssInfo->ucVhtChannelFrequencyS2)) { + /*Dump IE Inforamtion */ + DBGLOG(RLM, WARN, "rlmRecIeInfoForClient IE Information\n"); + DBGLOG(RLM, WARN, "IE Length = %d\n", u2IELength); + DBGLOG_MEM8(RLM, WARN, pucDumpIE, u2IELength); + + /*Error Handling for Non-predicted IE - Fixed to set 20MHz */ + prBssInfo->ucVhtChannelWidth = CW_20_40MHZ; + prBssInfo->ucVhtChannelFrequencyS1 = 0; + prBssInfo->ucVhtChannelFrequencyS2 = 0; + prBssInfo->eBssSCO = CHNL_EXT_SCN; + prBssInfo->ucHtOpInfo1 &= + ~(HT_OP_INFO1_SCO | HT_OP_INFO1_STA_CHNL_WIDTH); + } + + /* Check if OBSS scan process will launch */ + if (!prAdapter->fgEnOnlineScan || !prObssScnParam || + !(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH) || + prBssInfo->eBand != BAND_2G4 || !prBssInfo->fg40mBwAllowed) { + /* Note: it is ok not to stop rObssScanTimer() here */ + prBssInfo->u2ObssScanInterval = 0; + } else { + if (prObssScnParam->u2TriggerScanInterval < + OBSS_SCAN_MIN_INTERVAL) { + prObssScnParam->u2TriggerScanInterval = + OBSS_SCAN_MIN_INTERVAL; + } + if (prBssInfo->u2ObssScanInterval != + prObssScnParam->u2TriggerScanInterval) { + prBssInfo->u2ObssScanInterval = + prObssScnParam->u2TriggerScanInterval; + + /* Start timer to trigger OBSS scanning */ + cnmTimerStartTimer( + prAdapter, &prBssInfo->rObssScanTimer, + prBssInfo->u2ObssScanInterval * MSEC_PER_SEC); + } + } + + return ucPrimaryChannel; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Update parameters from Association Response frame + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static void rlmRecAssocRespIeInfoForClient(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, u8 *pucIE, + u16 u2IELength) +{ + u16 u2Offset; + P_STA_RECORD_T prStaRec; + u8 fgIsHasHtCap = false; + u8 fgIsHasVhtCap = false; + P_BSS_DESC_T prBssDesc; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(pucIE); + + prStaRec = prBssInfo->prStaRecOfAP; + + ASSERT(prStaRec); + if (!prStaRec) { + return; + } + + prBssDesc = scanSearchBssDescByBssid(prAdapter, prStaRec->aucMacAddr); + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_HT_CAP: + if (!RLM_NET_IS_11N(prBssInfo) || + IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) { + break; + } + fgIsHasHtCap = true; + break; + +#if CFG_SUPPORT_802_11AC + case ELEM_ID_VHT_CAP: + if (!RLM_NET_IS_11AC(prBssInfo) || + IE_LEN(pucIE) != (sizeof(IE_VHT_CAP_T) - 2)) { + break; + } + fgIsHasVhtCap = true; + break; + +#endif + default: + break; + } /* end of switch */ + } /* end of IE_FOR_EACH */ + + if (!fgIsHasHtCap) { + prStaRec->ucDesiredPhyTypeSet &= ~PHY_TYPE_BIT_HT; + if (prBssDesc) { + if (prBssDesc->ucPhyTypeSet & PHY_TYPE_BIT_HT) { + DBGLOG(RLM, + WARN, + "PhyTypeSet in Beacon and AssocResp are unsync. "); + DBGLOG(RLM, WARN, + "Follow AssocResp to disable HT.\n"); + } + } + } + if (!fgIsHasVhtCap) { + prStaRec->ucDesiredPhyTypeSet &= ~PHY_TYPE_BIT_VHT; + if (prBssDesc) { + if (prBssDesc->ucPhyTypeSet & PHY_TYPE_BIT_VHT) { + DBGLOG(RLM, + WARN, + "PhyTypeSet in Beacon and AssocResp are unsync. "); + DBGLOG(RLM, WARN, + "Follow AssocResp to disable VHT.\n"); + } + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief AIS or P2P GC. + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static u8 rlmRecBcnFromNeighborForClient(P_ADAPTER_T prAdapter, + P_BSS_INFO_T prBssInfo, + P_SW_RFB_T prSwRfb, u8 *pucIE, + u16 u2IELength) +{ + u16 u2Offset, i; + u8 ucPriChannel, ucSecChannel; + ENUM_CHNL_EXT_T eSCO; + u8 fgHtBss, fg20mReq; + + ASSERT(prAdapter); + ASSERT(prBssInfo && prSwRfb); + ASSERT(pucIE); + + /* Record it to channel list to change 20/40 bandwidth */ + ucPriChannel = 0; + eSCO = CHNL_EXT_SCN; + + fgHtBss = false; + fg20mReq = false; + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_HT_CAP: { + P_IE_HT_CAP_T prHtCap; + + if (IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) { + break; + } + + prHtCap = (P_IE_HT_CAP_T)pucIE; + if (prHtCap->u2HtCapInfo & HT_CAP_INFO_40M_INTOLERANT) { + fg20mReq = true; + } + fgHtBss = true; + break; + } + + case ELEM_ID_HT_OP: { + P_IE_HT_OP_T prHtOp; + + if (IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) { + break; + } + + prHtOp = (P_IE_HT_OP_T)pucIE; + /* Workaround that some APs fill primary channel field + * by its secondary channel, but its DS IE is correct + * 20110610 + */ + if (ucPriChannel == 0) { + ucPriChannel = prHtOp->ucPrimaryChannel; + } + + if ((prHtOp->ucInfo1 & HT_OP_INFO1_SCO) != + CHNL_EXT_RES) { + eSCO = (ENUM_CHNL_EXT_T)(prHtOp->ucInfo1 & + HT_OP_INFO1_SCO); + } + break; + } + + case ELEM_ID_20_40_BSS_COEXISTENCE: { + P_IE_20_40_COEXIST_T prCoexist; + + if (IE_LEN(pucIE) != (sizeof(IE_20_40_COEXIST_T) - 2)) { + break; + } + + prCoexist = (P_IE_20_40_COEXIST_T)pucIE; + if (prCoexist->ucData & BSS_COEXIST_40M_INTOLERANT) { + fg20mReq = true; + } + break; + } + + case ELEM_ID_DS_PARAM_SET: + if (IE_LEN(pucIE) != (sizeof(IE_DS_PARAM_SET_T) - 2)) { + break; + } + ucPriChannel = DS_PARAM_IE(pucIE)->ucCurrChnl; + break; + + default: + break; + } + } + + /* To do: Update channel list and 5G band. All channel lists have the + * same update procedure. We should give it the entry pointer of desired + * channel list. + */ + if (HAL_RX_STATUS_GET_RF_BAND(prSwRfb->prRxStatus) != BAND_2G4) { + return false; + } + + if (ucPriChannel == 0 || ucPriChannel > 14) { + ucPriChannel = HAL_RX_STATUS_GET_CHNL_NUM(prSwRfb->prRxStatus); + } + + if (fgHtBss) { + ASSERT(prBssInfo->auc2G_PriChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_PriChnlList[0] && + i <= CHNL_LIST_SZ_2G; + i++) + if (prBssInfo->auc2G_PriChnlList[i] == ucPriChannel) { + break; + } + if ((i > prBssInfo->auc2G_PriChnlList[0]) && + (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_PriChnlList[i] = ucPriChannel; + prBssInfo->auc2G_PriChnlList[0]++; + } + + /* Update secondary channel */ + if (eSCO != CHNL_EXT_SCN) { + ucSecChannel = (eSCO == CHNL_EXT_SCA) ? + (ucPriChannel + 4) : + (ucPriChannel - 4); + + ASSERT(prBssInfo->auc2G_SecChnlList[0] <= + CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_SecChnlList[0] && + i <= CHNL_LIST_SZ_2G; + i++) { + if (prBssInfo->auc2G_SecChnlList[i] == + ucSecChannel) { + break; + } + } + if ((i > prBssInfo->auc2G_SecChnlList[0]) && + (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_SecChnlList[i] = ucSecChannel; + prBssInfo->auc2G_SecChnlList[0]++; + } + } + + /* Update 20M bandwidth request channels */ + if (fg20mReq) { + ASSERT(prBssInfo->auc2G_20mReqChnlList[0] <= + CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_20mReqChnlList[0] && + i <= CHNL_LIST_SZ_2G; + i++) { + if (prBssInfo->auc2G_20mReqChnlList[i] == + ucPriChannel) { + break; + } + } + if ((i > prBssInfo->auc2G_20mReqChnlList[0]) && + (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_20mReqChnlList[i] = + ucPriChannel; + prBssInfo->auc2G_20mReqChnlList[0]++; + } + } + } else { + /* Update non-HT channel list */ + ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= CHNL_LIST_SZ_2G); + for (i = 1; i <= prBssInfo->auc2G_NonHtChnlList[0] && + i <= CHNL_LIST_SZ_2G; + i++) + if (prBssInfo->auc2G_NonHtChnlList[i] == ucPriChannel) { + break; + } + if ((i > prBssInfo->auc2G_NonHtChnlList[0]) && + (i <= CHNL_LIST_SZ_2G)) { + prBssInfo->auc2G_NonHtChnlList[i] = ucPriChannel; + prBssInfo->auc2G_NonHtChnlList[0]++; + } + } + + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief AIS or P2P GC. + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static u8 rlmRecBcnInfoForClient(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + P_SW_RFB_T prSwRfb, u8 *pucIE, u16 u2IELength) +{ + ASSERT(prAdapter); + ASSERT(prBssInfo && prSwRfb); + ASSERT(pucIE); + + /* Handle change of slot time */ + prBssInfo->u2CapInfo = + ((P_WLAN_BEACON_FRAME_T)(prSwRfb->pvHeader))->u2CapInfo; + prBssInfo->fgUseShortSlotTime = + ((prBssInfo->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME) || + (prBssInfo->eBand != BAND_2G4)) ? + true : + false; + + rlmRecIeInfoForClient(prAdapter, prBssInfo, pucIE, u2IELength); + + if (g_fgFowardBcn2Supplicant) { + g_fgFowardBcn2Supplicant = false; + kalIndicateRxMgmtFrame(prAdapter->prGlueInfo, prSwRfb); + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmProcessBcn(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, u8 *pucIE, + u16 u2IELength) +{ + P_BSS_INFO_T prBssInfo; + u8 fgNewParameter; + u8 i; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + ASSERT(pucIE); + + fgNewParameter = false; + + /* When concurrent networks exist, GO shall have the same handle as + * the other BSS, so the Beacon shall be processed for bandwidth and + * protection mechanism. + * Note1: we do not have 2 AP (GO) cases simultaneously now. + * Note2: If we are GO, concurrent AIS AP should detect it and reflect + * action in its Beacon, so AIS STA just follows Beacon from AP. + */ + for (i = 0; i < BSS_INFO_NUM; i++) { + prBssInfo = prAdapter->aprBssInfo[i]; + + if (IS_BSS_BOW(prBssInfo)) { + continue; + } + + if (IS_BSS_ACTIVE(prBssInfo)) { + if (prBssInfo->eCurrentOPMode == + OP_MODE_INFRASTRUCTURE && + prBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) { + /* P2P client or AIS infra STA */ + if (EQUAL_MAC_ADDR( + prBssInfo->aucBSSID, + ((P_WLAN_MAC_MGMT_HEADER_T)(prSwRfb + -> + pvHeader)) + ->aucBSSID)) { + fgNewParameter = rlmRecBcnInfoForClient( + prAdapter, prBssInfo, prSwRfb, + pucIE, u2IELength); + } else { + fgNewParameter = + rlmRecBcnFromNeighborForClient( + prAdapter, prBssInfo, + prSwRfb, pucIE, + u2IELength); + } + } +#if CFG_ENABLE_WIFI_DIRECT + else if (prAdapter->fgIsP2PRegistered && + (prBssInfo->eCurrentOPMode == + OP_MODE_ACCESS_POINT || + prBssInfo->eCurrentOPMode == + OP_MODE_P2P_DEVICE)) { + /* AP scan to check if 20/40M bandwidth is + * permitted */ + rlmRecBcnFromNeighborForClient(prAdapter, + prBssInfo, + prSwRfb, pucIE, + u2IELength); + } +#endif + else if (prBssInfo->eCurrentOPMode == OP_MODE_IBSS) { + /* To do: Nothing */ + /* To do: Ad-hoc */ + } + + /* Appy new parameters if necessary */ + if (fgNewParameter) { + rlmSyncOperationParams(prAdapter, prBssInfo); + fgNewParameter = false; + } + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function should be invoked after judging successful association. + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmProcessAssocRsp(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, u8 *pucIE, + u16 u2IELength) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + u8 ucPriChannel; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + if (!prStaRec) { + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + if (!prBssInfo) { + return; + } + + if (prStaRec != prBssInfo->prStaRecOfAP) { + return; + } + + /* To do: the invoked function is used to clear all members. It may be + * done by center mechanism in invoker. + */ + rlmBssReset(prAdapter, prBssInfo); + + prBssInfo->fgUseShortSlotTime = + ((prBssInfo->u2CapInfo & CAP_INFO_SHORT_SLOT_TIME) || + (prBssInfo->eBand != BAND_2G4)) ? + true : + false; + ucPriChannel = + rlmRecIeInfoForClient(prAdapter, prBssInfo, pucIE, u2IELength); + + /*Update the parameters from Association Response only, + * if the parameters need to be updated by both Beacon and Association + * Response, user should use another function, rlmRecIeInfoForClient() + */ + rlmRecAssocRespIeInfoForClient(prAdapter, prBssInfo, pucIE, u2IELength); + + if (prBssInfo->ucPrimaryChannel != ucPriChannel) { + DBGLOG(RLM, + INFO, + "Use RF pri channel[%u].Pri channel in HT OP IE is :[%u]\n", + prBssInfo->ucPrimaryChannel, + ucPriChannel); + } + /*Avoid wrong primary channel info in HT operation IE info when accept + * association response */ + + if (!RLM_NET_IS_11N(prBssInfo) || + !(prStaRec->u2HtCapInfo & HT_CAP_INFO_SUP_CHNL_WIDTH)) { + prBssInfo->fg40mBwAllowed = false; + } + + /* Note: Update its capabilities to WTBL by cnmStaRecChangeState(), + * which shall be invoked afterwards. Update channel, bandwidth and + * protection mode by nicUpdateBss() + */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmProcessHtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) +{ + P_ACTION_NOTIFY_CHNL_WIDTH_FRAME prRxFrame; + P_ACTION_SM_POWER_SAVE_FRAME prRxSmpsFrame; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + u16 u2HtCapInfoBitmask = 0; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxFrame = (P_ACTION_NOTIFY_CHNL_WIDTH_FRAME)prSwRfb->pvHeader; + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (!prStaRec) { + return; + } + + switch (prRxFrame->ucAction) { + case ACTION_HT_NOTIFY_CHANNEL_WIDTH: + if (prStaRec->ucStaState != STA_STATE_3 || + prSwRfb->u2PacketLen < + sizeof(ACTION_NOTIFY_CHNL_WIDTH_FRAME)) { + return; + } + + /* To do: depending regulation class 13 and 14 based on spec + * Note: (ucChannelWidth==1) shall restored back to original + * capability, not current setting to 40MHz BW here + */ + /* 1. Update StaRec for AP/STA mode */ + if (prRxFrame->ucChannelWidth == 0) { + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SUP_CHNL_WIDTH; + }else if (prRxFrame->ucChannelWidth == 1) { + prStaRec->u2HtCapInfo |= HT_CAP_INFO_SUP_CHNL_WIDTH; + } + + cnmStaSendUpdateCmd(prAdapter, prStaRec, NULL, false); + + /* 2. Update BssInfo for STA mode */ + prBssInfo = prAdapter->aprBssInfo[prStaRec->ucBssIndex]; + if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + if (prRxFrame->ucChannelWidth == 0) { + prBssInfo->ucHtOpInfo1 &= + ~HT_OP_INFO1_STA_CHNL_WIDTH; + } + if (prRxFrame->ucChannelWidth == 1) { + prBssInfo->ucHtOpInfo1 |= + HT_OP_INFO1_STA_CHNL_WIDTH; + } + + nicUpdateBss(prAdapter, prBssInfo->ucBssIndex); + } + break; + + /* Support SM power save */ /* TH3_Huang */ + case ACTION_HT_SM_POWER_SAVE: + prRxSmpsFrame = (P_ACTION_SM_POWER_SAVE_FRAME)prSwRfb->pvHeader; + if (prStaRec->ucStaState != STA_STATE_3 || + prSwRfb->u2PacketLen < sizeof(ACTION_SM_POWER_SAVE_FRAME)) { + return; + } + + /* The SM power enable bit is different definition in HtCap and + * SMpower IE field */ + if (!(prRxSmpsFrame->ucSmPowerCtrl & + (HT_SM_POWER_SAVE_CONTROL_ENABLED | + HT_SM_POWER_SAVE_CONTROL_SM_MODE))) { + u2HtCapInfoBitmask |= HT_CAP_INFO_SM_POWER_SAVE; + } + + /* Support SMPS action frame, TH3_Huang */ + /* Update StaRec if SM power state changed */ + if ((prStaRec->u2HtCapInfo & HT_CAP_INFO_SM_POWER_SAVE) != + u2HtCapInfoBitmask) { + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_SM_POWER_SAVE; + prStaRec->u2HtCapInfo |= u2HtCapInfoBitmask; + DBGLOG(RLM, + INFO, + "rlmProcessHtAction -- SMPS change u2HtCapInfo to (%x)\n", + prStaRec->u2HtCapInfo); + cnmStaSendUpdateCmd(prAdapter, prStaRec, NULL, false); + } + break; + + default: + break; + } +} + +#if CFG_SUPPORT_802_11AC +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmProcessVhtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) +{ + P_ACTION_OP_MODE_NOTIFICATION_FRAME prRxFrame; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxFrame = (P_ACTION_OP_MODE_NOTIFICATION_FRAME)prSwRfb->pvHeader; + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (!prStaRec) { + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + if (!prBssInfo) { + return; + } + + switch (prRxFrame->ucAction) { + /* Support Operating mode notification action frame, TH3_Huang */ + case ACTION_OPERATING_MODE_NOTIFICATION: + if (prStaRec->ucStaState != STA_STATE_3 || + prSwRfb->u2PacketLen < + sizeof(ACTION_OP_MODE_NOTIFICATION_FRAME)) { + return; + } + + if (((prRxFrame->ucOperatingMode & VHT_OP_MODE_RX_NSS_TYPE) != + VHT_OP_MODE_RX_NSS_TYPE) && + (prStaRec->ucVhtOpMode != prRxFrame->ucOperatingMode)) { + prStaRec->ucVhtOpMode = prRxFrame->ucOperatingMode; + DBGLOG(RLM, + INFO, + "rlmProcessVhtAction -- Update ucVhtOpMode to 0x%x\n", + prStaRec->ucVhtOpMode); + cnmStaSendUpdateCmd(prAdapter, prStaRec, NULL, false); + } + break; + + default: + break; + } +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function should be invoked after judging successful association. + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmFillSyncCmdParam(P_CMD_SET_BSS_RLM_PARAM_T prCmdBody, + P_BSS_INFO_T prBssInfo) +{ + ASSERT(prCmdBody && prBssInfo); + if (!prCmdBody || !prBssInfo) { + return; + } + + prCmdBody->ucBssIndex = prBssInfo->ucBssIndex; + prCmdBody->ucRfBand = (u8)prBssInfo->eBand; + prCmdBody->ucPrimaryChannel = prBssInfo->ucPrimaryChannel; + prCmdBody->ucRfSco = (u8)prBssInfo->eBssSCO; + prCmdBody->ucErpProtectMode = (u8)prBssInfo->fgErpProtectMode; + prCmdBody->ucHtProtectMode = (u8)prBssInfo->eHtProtectMode; + prCmdBody->ucGfOperationMode = (u8)prBssInfo->eGfOperationMode; + prCmdBody->ucTxRifsMode = (u8)prBssInfo->eRifsOperationMode; + prCmdBody->u2HtOpInfo3 = prBssInfo->u2HtOpInfo3; + prCmdBody->u2HtOpInfo2 = prBssInfo->u2HtOpInfo2; + prCmdBody->ucHtOpInfo1 = prBssInfo->ucHtOpInfo1; + prCmdBody->ucUseShortPreamble = prBssInfo->fgUseShortPreamble; + prCmdBody->ucUseShortSlotTime = prBssInfo->fgUseShortSlotTime; + prCmdBody->ucVhtChannelWidth = prBssInfo->ucVhtChannelWidth; + prCmdBody->ucVhtChannelFrequencyS1 = prBssInfo->ucVhtChannelFrequencyS1; + prCmdBody->ucVhtChannelFrequencyS2 = prBssInfo->ucVhtChannelFrequencyS2; + prCmdBody->u2VhtBasicMcsSet = prBssInfo->u2BSSBasicRateSet; + prCmdBody->ucNss = prBssInfo->ucNss; + + if (RLM_NET_PARAM_VALID(prBssInfo)) { + DBGLOG(RLM, + INFO, + "N=%d b=%d c=%d s=%d e=%d h=%d I=0x%02x l=%d p=%d w=%d s1=%d s2=%d n=%d\n", + prCmdBody->ucBssIndex, + prCmdBody->ucRfBand, + prCmdBody->ucPrimaryChannel, + prCmdBody->ucRfSco, + prCmdBody->ucErpProtectMode, + prCmdBody->ucHtProtectMode, + prCmdBody->ucHtOpInfo1, + prCmdBody->ucUseShortSlotTime, + prCmdBody->ucUseShortPreamble, + prCmdBody->ucVhtChannelWidth, + prCmdBody->ucVhtChannelFrequencyS1, + prCmdBody->ucVhtChannelFrequencyS2, + prCmdBody->ucNss); + } else { + DBGLOG(RLM, STATE, "N=%d closed\n", prCmdBody->ucBssIndex); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will operation parameters based on situations of + * concurrent networks. Channel, bandwidth, protection mode, supported + * rate will be modified. + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmSyncOperationParams(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + P_CMD_SET_BSS_RLM_PARAM_T prCmdBody; + WLAN_STATUS rStatus; + + ASSERT(prAdapter); + ASSERT(prBssInfo); + + prCmdBody = (P_CMD_SET_BSS_RLM_PARAM_T)cnmMemAlloc( + prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_BSS_RLM_PARAM_T)); + + /* ASSERT(prCmdBody); */ + /* To do: exception handle */ + if (!prCmdBody) { + DBGLOG(RLM, WARN, "No buf for sync RLM params (Net=%d)\n", + prBssInfo->ucBssIndex); + return; + } + + rlmFillSyncCmdParam(prCmdBody, prBssInfo); + + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_SET_BSS_RLM_PARAM, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_SET_BSS_RLM_PARAM_T), /* u4SetQueryInfoLen + */ + (u8 *)prCmdBody, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + /* ASSERT(rStatus == WLAN_STATUS_PENDING); */ + if (rStatus != WLAN_STATUS_PENDING) { + DBGLOG(RLM, + WARN, + "rlmSyncOperationParams set cmd fail\n"); + } + + cnmMemFree(prAdapter, prCmdBody); +} + +#if CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function should be invoked after judging successful association. + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmProcessAssocReq(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb, u8 *pucIE, + u16 u2IELength) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + u16 u2Offset; + P_IE_HT_CAP_T prHtCap; +#if CFG_SUPPORT_802_11AC + P_IE_VHT_CAP_T prVhtCap; + u8 ucVhtCapMcsOwnNotSupportOffset; + /* u8 ucVhtCapMcsPeerNotSupportOffset; */ + P_IE_OP_MODE_NOTIFICATION_T + prOPModeNotification; /* Operation Mode Notification */ +#endif + + ASSERT(prAdapter); + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + if (!prStaRec) { + return; + } + + ASSERT(prStaRec->ucBssIndex <= MAX_BSS_INDEX); + + prBssInfo = prAdapter->aprBssInfo[prStaRec->ucBssIndex]; + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_HT_CAP: + if (!RLM_NET_IS_11N(prBssInfo) || + IE_LEN(pucIE) != (sizeof(IE_HT_CAP_T) - 2)) { + break; + } + prHtCap = (P_IE_HT_CAP_T)pucIE; + prStaRec->ucMcsSet = + prHtCap->rSupMcsSet.aucRxMcsBitmask[0]; + prStaRec->fgSupMcs32 = + (prHtCap->rSupMcsSet.aucRxMcsBitmask[32 / 8] & + BIT(0)) ? + true : + false; + + kalMemCopy( + prStaRec->aucRxMcsBitmask, + prHtCap->rSupMcsSet.aucRxMcsBitmask, + sizeof(prStaRec->aucRxMcsBitmask) /*SUP_MCS_RX_BITMASK_OCTET_NUM */ ); + + prStaRec->u2HtCapInfo = prHtCap->u2HtCapInfo; + + /* Set Short LDPC Tx capability */ + if (IS_FEATURE_FORCE_ENABLED( + prAdapter->rWifiVar.ucTxLdpc)) { + prStaRec->u2HtCapInfo |= HT_CAP_INFO_LDPC_CAP; + }else if (IS_FEATURE_DISABLED( + prAdapter->rWifiVar.ucTxLdpc)) { + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_LDPC_CAP; + } + + /* Set STBC Tx capability */ + if (IS_FEATURE_FORCE_ENABLED( + prAdapter->rWifiVar.ucTxStbc)) { + prStaRec->u2HtCapInfo |= HT_CAP_INFO_TX_STBC; + }else if (IS_FEATURE_DISABLED( + prAdapter->rWifiVar.ucTxStbc)) { + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_TX_STBC; + } + /* Set Short GI Tx capability */ + if (IS_FEATURE_FORCE_ENABLED( + prAdapter->rWifiVar.ucTxShortGI)) { + prStaRec->u2HtCapInfo |= + HT_CAP_INFO_SHORT_GI_20M; + prStaRec->u2HtCapInfo |= + HT_CAP_INFO_SHORT_GI_40M; + } else if (IS_FEATURE_DISABLED( + prAdapter->rWifiVar.ucTxShortGI)) { + prStaRec->u2HtCapInfo &= + ~HT_CAP_INFO_SHORT_GI_20M; + prStaRec->u2HtCapInfo &= + ~HT_CAP_INFO_SHORT_GI_40M; + } + + /* Set HT Greenfield Tx capability */ + if (IS_FEATURE_FORCE_ENABLED( + prAdapter->rWifiVar.ucTxGf)) { + prStaRec->u2HtCapInfo |= HT_CAP_INFO_HT_GF; + }else if (IS_FEATURE_DISABLED( + prAdapter->rWifiVar.ucTxGf)) { + prStaRec->u2HtCapInfo &= ~HT_CAP_INFO_HT_GF; + } + + prStaRec->ucAmpduParam = prHtCap->ucAmpduParam; + prStaRec->u2HtExtendedCap = prHtCap->u2HtExtendedCap; + prStaRec->u4TxBeamformingCap = + prHtCap->u4TxBeamformingCap; + prStaRec->ucAselCap = prHtCap->ucAselCap; + break; + +#if CFG_SUPPORT_802_11AC + case ELEM_ID_VHT_CAP: + if (!RLM_NET_IS_11AC(prBssInfo) || + IE_LEN(pucIE) != (sizeof(IE_VHT_CAP_T) - 2)) { + break; + } + + prVhtCap = (P_IE_VHT_CAP_T)pucIE; + + prStaRec->u4VhtCapInfo = prVhtCap->u4VhtCapInfo; + + /* Set Tx LDPC capability */ + if (IS_FEATURE_FORCE_ENABLED( + prAdapter->rWifiVar.ucTxLdpc)) { + prStaRec->u4VhtCapInfo |= VHT_CAP_INFO_RX_LDPC; + }else if (IS_FEATURE_DISABLED( + prAdapter->rWifiVar.ucTxLdpc)) { + prStaRec->u4VhtCapInfo &= ~VHT_CAP_INFO_RX_LDPC; + } + + /* Set Tx STBC capability */ + if (IS_FEATURE_FORCE_ENABLED( + prAdapter->rWifiVar.ucTxStbc)) { + prStaRec->u4VhtCapInfo |= VHT_CAP_INFO_TX_STBC; + }else if (IS_FEATURE_DISABLED( + prAdapter->rWifiVar.ucTxStbc)) { + prStaRec->u4VhtCapInfo &= ~VHT_CAP_INFO_TX_STBC; + } + + /* Set Tx TXOP PS capability */ + if (IS_FEATURE_FORCE_ENABLED( + prAdapter->rWifiVar.ucTxopPsTx)) { + prStaRec->u4VhtCapInfo |= + VHT_CAP_INFO_VHT_TXOP_PS; + } else if (IS_FEATURE_DISABLED( + prAdapter->rWifiVar.ucTxopPsTx)) { + prStaRec->u4VhtCapInfo &= + ~VHT_CAP_INFO_VHT_TXOP_PS; + } + + /* Set Tx Short GI capability */ + if (IS_FEATURE_FORCE_ENABLED( + prAdapter->rWifiVar.ucTxShortGI)) { + prStaRec->u4VhtCapInfo |= + VHT_CAP_INFO_SHORT_GI_80; + prStaRec->u4VhtCapInfo |= + VHT_CAP_INFO_SHORT_GI_160_80P80; + } else if (IS_FEATURE_DISABLED( + prAdapter->rWifiVar.ucTxShortGI)) { + prStaRec->u4VhtCapInfo &= + ~VHT_CAP_INFO_SHORT_GI_80; + prStaRec->u4VhtCapInfo &= + ~VHT_CAP_INFO_SHORT_GI_160_80P80; + } + + /*Set Vht Rx Mcs Map upon peer's capability and our + * capability */ + prStaRec->u2VhtRxMcsMap = + prVhtCap->rVhtSupportedMcsSet.u2RxMcsMap; + if (wlanGetSupportNss(prAdapter, prStaRec->ucBssIndex) < + 8) { + ucVhtCapMcsOwnNotSupportOffset = + wlanGetSupportNss( + prAdapter, + prStaRec->ucBssIndex) * + 2; + prStaRec->u2VhtRxMcsMap |= BITS( + ucVhtCapMcsOwnNotSupportOffset, 15); + /*Mark Rx Mcs Map which we don't support*/ + } + if (prStaRec->u2VhtRxMcsMap != + prVhtCap->rVhtSupportedMcsSet.u2RxMcsMap) { + DBGLOG(RLM, + INFO, + "Change VhtRxMcsMap from 0x%x to 0x%x due to our Nss setting\n", + prVhtCap->rVhtSupportedMcsSet.u2RxMcsMap, + prStaRec->u2VhtRxMcsMap); + } + + prStaRec->u2VhtRxHighestSupportedDataRate = + prVhtCap->rVhtSupportedMcsSet + .u2RxHighestSupportedDataRate; + prStaRec->u2VhtTxMcsMap = + prVhtCap->rVhtSupportedMcsSet.u2TxMcsMap; + prStaRec->u2VhtTxHighestSupportedDataRate = + prVhtCap->rVhtSupportedMcsSet + .u2TxHighestSupportedDataRate; + + /* Set initial value of VHT OP mode */ + prStaRec->ucVhtOpMode = 0; + switch (prBssInfo->ucVhtChannelWidth) { + case VHT_OP_CHANNEL_WIDTH_20_40: + prStaRec->ucVhtOpMode |= + VHT_OP_MODE_CHANNEL_WIDTH_40; + break; + + case VHT_OP_CHANNEL_WIDTH_80: + prStaRec->ucVhtOpMode |= + VHT_OP_MODE_CHANNEL_WIDTH_80; + break; + + case VHT_OP_CHANNEL_WIDTH_160: + case VHT_OP_CHANNEL_WIDTH_80P80: + prStaRec->ucVhtOpMode |= + VHT_OP_MODE_CHANNEL_WIDTH_160_80P80; + break; + + default: + prStaRec->ucVhtOpMode |= + VHT_OP_MODE_CHANNEL_WIDTH_80; + break; + } + prStaRec->ucVhtOpMode |= + ((prBssInfo->ucNss - 1) + << VHT_OP_MODE_RX_NSS_OFFSET) & + VHT_OP_MODE_RX_NSS; + + break; + + case ELEM_ID_OP_MODE: + if (!RLM_NET_IS_11AC(prBssInfo) || + IE_LEN(pucIE) != + (sizeof(IE_OP_MODE_NOTIFICATION_T) - 2)) { + break; + } + prOPModeNotification = + (P_IE_OP_MODE_NOTIFICATION_T)pucIE; + + if ((prOPModeNotification->ucOpMode & + VHT_OP_MODE_RX_NSS_TYPE) != + VHT_OP_MODE_RX_NSS_TYPE) { + prStaRec->ucVhtOpMode = + prOPModeNotification->ucOpMode; + } + + break; +#endif + + default: + break; + } /* end of switch */ + } /* end of IE_FOR_EACH */ +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief It is for both STA and AP modes + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmBssInitForAPandIbss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + ASSERT(prAdapter); + ASSERT(prBssInfo); + +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && + prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + rlmBssInitForAP(prAdapter, prBssInfo); + } +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief It is for both STA and AP modes + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmBssAborted(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + ASSERT(prAdapter); + ASSERT(prBssInfo); + + rlmBssReset(prAdapter, prBssInfo); + + prBssInfo->fg40mBwAllowed = false; + prBssInfo->fgAssoc40mBwAllowed = false; + + /* Assume FW state is updated by CMD_ID_SET_BSS_INFO, so + * the sync CMD is not needed here. + */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief All RLM timers will also be stopped. + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static void rlmBssReset(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + ASSERT(prAdapter); + ASSERT(prBssInfo); + + /* HT related parameters */ + prBssInfo->ucHtOpInfo1 = 0; /* RIFS disabled. 20MHz */ + prBssInfo->u2HtOpInfo2 = 0; + prBssInfo->u2HtOpInfo3 = 0; + +#if CFG_SUPPORT_802_11AC + prBssInfo->ucVhtChannelWidth = 0; /* VHT_OP_CHANNEL_WIDTH_80; */ + prBssInfo->ucVhtChannelFrequencyS1 = 0; /* 42; */ + prBssInfo->ucVhtChannelFrequencyS2 = 0; + prBssInfo->u2VhtBasicMcsSet = 0; /* 0xFFFF; */ +#endif + + prBssInfo->eBssSCO = 0; + prBssInfo->fgErpProtectMode = 0; + prBssInfo->eHtProtectMode = 0; + prBssInfo->eGfOperationMode = 0; + prBssInfo->eRifsOperationMode = 0; + + /* OBSS related parameters */ + prBssInfo->auc2G_20mReqChnlList[0] = 0; + prBssInfo->auc2G_NonHtChnlList[0] = 0; + prBssInfo->auc2G_PriChnlList[0] = 0; + prBssInfo->auc2G_SecChnlList[0] = 0; + prBssInfo->auc5G_20mReqChnlList[0] = 0; + prBssInfo->auc5G_NonHtChnlList[0] = 0; + prBssInfo->auc5G_PriChnlList[0] = 0; + prBssInfo->auc5G_SecChnlList[0] = 0; + + /* All RLM timers will also be stopped */ + cnmTimerStopTimer(prAdapter, &prBssInfo->rObssScanTimer); + prBssInfo->u2ObssScanInterval = 0; + + prBssInfo->fgObssErpProtectMode = 0; /* GO only */ + prBssInfo->eObssHtProtectMode = 0; /* GO only */ + prBssInfo->eObssGfOperationMode = 0; /* GO only */ + prBssInfo->fgObssRifsOperationMode = 0; /* GO only */ + prBssInfo->fgObssActionForcedTo20M = 0; /* GO only */ + prBssInfo->fgObssBeaconForcedTo20M = 0; /* GO only */ +} + +#if CFG_SUPPORT_TDLS +#if CFG_SUPPORT_802_11AC +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u32 rlmFillVhtCapIEByAdapter(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + u8 *pOutBuf) +{ + P_IE_VHT_CAP_T prVhtCap; + P_VHT_SUPPORTED_MCS_FIELD prVhtSupportedMcsSet; + u8 i; + u8 ucMaxBw; + u8 supportNss = wlanGetSupportNss(prAdapter, prBssInfo->ucBssIndex); + + if (!prAdapter) { + DBGLOG(TDLS, ERROR, "prAdapter error!\n"); + return 0; + } + if (!prBssInfo) { + DBGLOG(TDLS, ERROR, "prBssInfo error!\n"); + return 0; + } + + prVhtCap = (P_IE_VHT_CAP_T)pOutBuf; + + prVhtCap->ucId = ELEM_ID_VHT_CAP; + prVhtCap->ucLength = sizeof(IE_VHT_CAP_T) - ELEM_HDR_LEN; + prVhtCap->u4VhtCapInfo = VHT_CAP_INFO_DEFAULT_VAL; + + ucMaxBw = cnmGetBssMaxBw(prAdapter, prBssInfo->ucBssIndex); + + prVhtCap->u4VhtCapInfo |= (prAdapter->rWifiVar.ucRxMaxMpduLen & + VHT_CAP_INFO_MAX_MPDU_LEN_MASK); + + if (ucMaxBw == MAX_BW_160MHZ) { + prVhtCap->u4VhtCapInfo |= + VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_SET_160; + } else if (ucMaxBw == MAX_BW_80_80_MHZ) { + prVhtCap->u4VhtCapInfo |= + VHT_CAP_INFO_MAX_SUP_CHANNEL_WIDTH_SET_160_80P80; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxShortGI)) { + if (ucMaxBw >= MAX_BW_80MHZ) { + prVhtCap->u4VhtCapInfo |= VHT_CAP_INFO_SHORT_GI_80; + } + + if (ucMaxBw >= MAX_BW_160MHZ) { + prVhtCap->u4VhtCapInfo |= + VHT_CAP_INFO_SHORT_GI_160_80P80; + } + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxLdpc)) { + prVhtCap->u4VhtCapInfo |= VHT_CAP_INFO_RX_LDPC; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxStbc)) { + u8 tempRxStbcNss = prAdapter->rWifiVar.ucRxStbcNss; + + if (tempRxStbcNss > supportNss) { + DBGLOG(TDLS, WARN, + "Apply Nss:%d -> %d as RxStbcNss in VHT Cap", + tempRxStbcNss, supportNss); + tempRxStbcNss = supportNss; + } + prVhtCap->u4VhtCapInfo |= + ((tempRxStbcNss << VHT_CAP_INFO_RX_STBC_OFFSET) & + VHT_CAP_INFO_RX_STBC_MASK); + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucTxStbc)) { + // && prBssInfo->ucOpTxNss >= 2) + prVhtCap->u4VhtCapInfo |= VHT_CAP_INFO_TX_STBC; + } + + /*set MCS map */ + prVhtSupportedMcsSet = &prVhtCap->rVhtSupportedMcsSet; + kalMemZero((void *)prVhtSupportedMcsSet, + sizeof(VHT_SUPPORTED_MCS_FIELD)); + + for (i = 0; i < 8; i++) { + u8 ucOffset = i * 2; + u8 ucMcsMap; + + if (i < supportNss) { + ucMcsMap = VHT_CAP_INFO_MCS_MAP_MCS9; + }else{ + ucMcsMap = VHT_CAP_INFO_MCS_NOT_SUPPORTED; + } + + prVhtSupportedMcsSet->u2RxMcsMap |= (ucMcsMap << ucOffset); + prVhtSupportedMcsSet->u2TxMcsMap |= (ucMcsMap << ucOffset); + } + + prVhtSupportedMcsSet->u2RxHighestSupportedDataRate = + VHT_CAP_INFO_DEFAULT_HIGHEST_DATA_RATE; + prVhtSupportedMcsSet->u2TxHighestSupportedDataRate = + VHT_CAP_INFO_DEFAULT_HIGHEST_DATA_RATE; + + if (IE_SIZE(prVhtCap) > (ELEM_HDR_LEN + ELEM_MAX_LEN_VHT_CAP)) { + DBGLOG(TDLS, ERROR, "prVhtCap size error!\n"); + return 0; + } + + return IE_SIZE(prVhtCap); +} +#endif +#endif + +#if CFG_SUPPORT_TDLS +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u32 rlmFillHtCapIEByParams(u8 fg40mAllowed, u8 fgShortGIDisabled, + u8 u8SupportRxSgi20, u8 u8SupportRxSgi40, + u8 u8SupportRxGf, ENUM_OP_MODE_T eCurrentOPMode, + u8 *pOutBuf) +{ + P_IE_HT_CAP_T prHtCap; + P_SUP_MCS_SET_FIELD prSupMcsSet; + + ASSERT(pOutBuf); + + prHtCap = (P_IE_HT_CAP_T)pOutBuf; + + /* Add HT capabilities IE */ + prHtCap->ucId = ELEM_ID_HT_CAP; + prHtCap->ucLength = sizeof(IE_HT_CAP_T) - ELEM_HDR_LEN; + + prHtCap->u2HtCapInfo = HT_CAP_INFO_DEFAULT_VAL; + if (!fg40mAllowed) { + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | + HT_CAP_INFO_DSSS_CCK_IN_40M); + } + if (fgShortGIDisabled) { + prHtCap->u2HtCapInfo &= + ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); + } + + if (u8SupportRxSgi20 == 2) { + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_20M); + } + if (u8SupportRxSgi40 == 2) { + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SHORT_GI_40M); + } + if (u8SupportRxGf == 2) { + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_HT_GF); + } + + prHtCap->ucAmpduParam = AMPDU_PARAM_DEFAULT_VAL; + + prSupMcsSet = &prHtCap->rSupMcsSet; + kalMemZero((void *)&prSupMcsSet->aucRxMcsBitmask[0], + SUP_MCS_RX_BITMASK_OCTET_NUM); + + prSupMcsSet->aucRxMcsBitmask[0] = BITS(0, 7); + + if (fg40mAllowed) { + prSupMcsSet->aucRxMcsBitmask[32 / 8] = BIT(0); /* MCS32 */ + } + prSupMcsSet->u2RxHighestSupportedRate = SUP_MCS_RX_DEFAULT_HIGHEST_RATE; + prSupMcsSet->u4TxRateInfo = SUP_MCS_TX_DEFAULT_VAL; + + prHtCap->u2HtExtendedCap = HT_EXT_CAP_DEFAULT_VAL; + if (!fg40mAllowed || eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + prHtCap->u2HtExtendedCap &= + ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE); + } + + prHtCap->u4TxBeamformingCap = TX_BEAMFORMING_CAP_DEFAULT_VAL; + + prHtCap->ucAselCap = ASEL_CAP_DEFAULT_VAL; + + ASSERT(IE_SIZE(prHtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP)); + + return IE_SIZE(prHtCap); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u32 rlmFillHtCapIEByAdapter(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + u8 *pOutBuf) +{ + P_IE_HT_CAP_T prHtCap; + P_SUP_MCS_SET_FIELD prSupMcsSet; + u8 fg40mAllowed; + u8 ucIdx; + u8 supportNss = wlanGetSupportNss(prAdapter, prBssInfo->ucBssIndex); + + ASSERT(prAdapter); + ASSERT(prBssInfo); + ASSERT(pOutBuf); + + fg40mAllowed = prBssInfo->fgAssoc40mBwAllowed; + + prHtCap = (P_IE_HT_CAP_T)pOutBuf; + + /* Add HT capabilities IE */ + prHtCap->ucId = ELEM_ID_HT_CAP; + prHtCap->ucLength = sizeof(IE_HT_CAP_T) - ELEM_HDR_LEN; + + prHtCap->u2HtCapInfo = HT_CAP_INFO_DEFAULT_VAL; + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxShortGI)) { + prHtCap->u2HtCapInfo |= + (HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_SHORT_GI_40M); + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxLdpc)) { + prHtCap->u2HtCapInfo |= HT_CAP_INFO_LDPC_CAP; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucTxStbc)) { + // && prBssInfo->ucOpTxNss >= 2) + prHtCap->u2HtCapInfo |= HT_CAP_INFO_TX_STBC; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxStbc)) { + u8 tempRxStbcNss = prAdapter->rWifiVar.ucRxStbcNss; + + if (tempRxStbcNss > supportNss) { + DBGLOG(TDLS, WARN, + "Apply Nss:%d -> %d as RxStbcNss in HT Cap", + tempRxStbcNss, supportNss); + tempRxStbcNss = supportNss; + } + + if (tempRxStbcNss == 1) { + prHtCap->u2HtCapInfo |= HT_CAP_INFO_RX_STBC_1_SS; + }else if (tempRxStbcNss == 2) { + prHtCap->u2HtCapInfo |= HT_CAP_INFO_RX_STBC_2_SS; + }else if (tempRxStbcNss >= 3) { + prHtCap->u2HtCapInfo |= HT_CAP_INFO_RX_STBC_3_SS; + } + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucRxGf)) { + prHtCap->u2HtCapInfo |= HT_CAP_INFO_HT_GF; + } + + if (prAdapter->rWifiVar.ucRxMaxMpduLen > VHT_CAP_INFO_MAX_MPDU_LEN_3K) { + prHtCap->u2HtCapInfo |= HT_CAP_INFO_MAX_AMSDU_LEN; + } + + if (!fg40mAllowed) { + prHtCap->u2HtCapInfo &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | + HT_CAP_INFO_DSSS_CCK_IN_40M); + } + + /* SM power saving (IEEE 802.11, 2016, 10.2.4) + * A non-AP HT STA may also use SM Power Save bits in the HT + * Capabilities element of its Association Request to achieve + * the same purpose. The latter allows the STA to use only a + * single receive chain immediately after association. + */ + // if (prBssInfo->ucOpRxNss < supportNss) + // prHtCap->u2HtCapInfo &= + // ~HT_CAP_INFO_SM_POWER_SAVE; /*Set as static power save*/ + + prHtCap->ucAmpduParam = AMPDU_PARAM_DEFAULT_VAL; + + prSupMcsSet = &prHtCap->rSupMcsSet; + kalMemZero((void *)&prSupMcsSet->aucRxMcsBitmask[0], + SUP_MCS_RX_BITMASK_OCTET_NUM); + + for (ucIdx = 0; ucIdx < supportNss; ucIdx++) + prSupMcsSet->aucRxMcsBitmask[ucIdx] = BITS(0, 7); + + if (fg40mAllowed && IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucMCS32)) { + prSupMcsSet->aucRxMcsBitmask[32 / 8] = BIT(0); /* MCS32 */ + } + prSupMcsSet->u2RxHighestSupportedRate = SUP_MCS_RX_DEFAULT_HIGHEST_RATE; + prSupMcsSet->u4TxRateInfo = SUP_MCS_TX_DEFAULT_VAL; + + prHtCap->u2HtExtendedCap = HT_EXT_CAP_DEFAULT_VAL; + if (!fg40mAllowed || + prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + prHtCap->u2HtExtendedCap &= + ~(HT_EXT_CAP_PCO | HT_EXT_CAP_PCO_TRANS_TIME_NONE); + } + + prHtCap->u4TxBeamformingCap = TX_BEAMFORMING_CAP_DEFAULT_VAL; + + prHtCap->ucAselCap = ASEL_CAP_DEFAULT_VAL; + + ASSERT(IE_SIZE(prHtCap) <= (ELEM_HDR_LEN + ELEM_MAX_LEN_HT_CAP)); + + return IE_SIZE(prHtCap); +} + +#endif + +#if CFG_SUPPORT_DFS +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will compose the TPC Report frame. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prStaRec Pointer to the STA_RECORD_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +static void tpcComposeReportFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler) +{ + P_MSDU_INFO_T prMsduInfo; + P_BSS_INFO_T prBssInfo; + P_ACTION_TPC_REPORT_FRAME prTxFrame; + u16 u2PayloadLen; + + ASSERT(prAdapter); + ASSERT(prStaRec); + + prBssInfo = &prAdapter->rWifiVar.arBssInfoPool[prStaRec->ucBssIndex]; + ASSERT(prBssInfo); + + prMsduInfo = (P_MSDU_INFO_T)cnmMgtPktAlloc( + prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + + if (!prMsduInfo) { + return; + } + + prTxFrame = + (P_ACTION_TPC_REPORT_FRAME)((unsigned long)(prMsduInfo + ->prPacket) + + MAC_TX_RESERVED_FIELD); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_SPEC_MGT; + prTxFrame->ucAction = ACTION_TPC_REPORT; + + /* 3 Compose the frame body's frame. */ + prTxFrame->ucDialogToken = prStaRec->ucSmDialogToken; + prTxFrame->ucElemId = ELEM_ID_TPC_REPORT; + prTxFrame->ucLength = + sizeof(prTxFrame->ucLinkMargin) + sizeof(prTxFrame->ucTransPwr); + prTxFrame->ucTransPwr = prAdapter->u4GetTxPower; + prTxFrame->ucLinkMargin = + prAdapter->rLinkQuality.cRssi - (0 - MIN_RCV_PWR); + + u2PayloadLen = ACTION_SM_TPC_REPORT_LEN; + + /* 4 Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prStaRec->ucBssIndex, + prStaRec->ucIndex, WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, pfTxDoneHandler, + MSDU_RATE_MODE_AUTO); + + DBGLOG(RLM, TRACE, "ucDialogToken %d ucTransPwr %d ucLinkMargin %d\n", + prTxFrame->ucDialogToken, prTxFrame->ucTransPwr, + prTxFrame->ucLinkMargin); + + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will compose the Measurement Report frame. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prStaRec Pointer to the STA_RECORD_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +static void msmtComposeReportFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN PFN_TX_DONE_HANDLER pfTxDoneHandler) +{ + P_MSDU_INFO_T prMsduInfo; + P_BSS_INFO_T prBssInfo; + P_ACTION_SM_REPORT_FRAME prTxFrame; + P_IE_MEASUREMENT_REPORT_T prMeasurementRepIE; + u8 *pucIE; + u16 u2PayloadLen; + + ASSERT(prAdapter); + ASSERT(prStaRec); + + prBssInfo = &prAdapter->rWifiVar.arBssInfoPool[prStaRec->ucBssIndex]; + ASSERT(prBssInfo); + + prMsduInfo = (P_MSDU_INFO_T)cnmMgtPktAlloc( + prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + + if (!prMsduInfo) { + return; + } + + prTxFrame = + (P_ACTION_SM_REPORT_FRAME)((unsigned long)(prMsduInfo->prPacket) + + + MAC_TX_RESERVED_FIELD); + pucIE = prTxFrame->aucInfoElem; + prMeasurementRepIE = SM_MEASUREMENT_REP_IE(pucIE); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_SPEC_MGT; + prTxFrame->ucAction = ACTION_MEASUREMENT_REPORT; + + /* 3 Compose the frame body's frame. */ + prTxFrame->ucDialogToken = prStaRec->ucSmDialogToken; + prMeasurementRepIE->ucId = ELEM_ID_MEASUREMENT_REPORT; + + prMeasurementRepIE->ucLength = 3; + u2PayloadLen = ACTION_SM_MEASURE_REPORT_LEN; + prMeasurementRepIE->ucToken = prStaRec->ucSmMsmtToken; + prMeasurementRepIE->ucReportMode = BIT(1); + prMeasurementRepIE->ucMeasurementType = prStaRec->ucSmMsmtRequestMode; + + /* 4 Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prStaRec->ucBssIndex, + prStaRec->ucIndex, WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, pfTxDoneHandler, + MSDU_RATE_MODE_AUTO); + + DBGLOG(RLM, + TRACE, + "ucDialogToken %d ucToken %d ucReportMode %d ucMeasurementType %d\n", + prTxFrame->ucDialogToken, + prMeasurementRepIE->ucToken, + prMeasurementRepIE->ucReportMode, + prMeasurementRepIE->ucMeasurementType); + + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function handle spectrum management action frame + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmProcessSpecMgtAction(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) +{ + u8 *pucIE; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + u16 u2IELength; +#if CFG_SUPPORT_DFS + u16 u2Offset = 0; + P_IE_CHANNEL_SWITCH_T prChannelSwitchAnnounceIE; + P_IE_SECONDARY_OFFSET_T prSecondaryOffsetIE; + P_IE_WIDE_BAND_CHANNEL_T prWideBandChannelIE; + P_SWITCH_CH_AND_BAND_PARAMS_T prCSAParams; + P_BSS_DESC_T prBssDesc; + u8 ucCurrentCsaCount; +#if CFG_DFS_NEWCH_DFS_FORCE_DISCONNECT + struct channel *Channel = NULL; + u8 max_count, i; +#endif +#endif + P_IE_TPC_REQ_T prTpcReqIE; + P_IE_TPC_REPORT_T prTpcRepIE; + P_IE_MEASUREMENT_REQ_T prMeasurementReqIE; + P_IE_MEASUREMENT_REPORT_T prMeasurementRepIE; + P_ACTION_SM_REQ_FRAME prRxFrame; + + DBGLOG(RLM, INFO, "[Mgt Action]rlmProcessSpecMgtAction\n"); + ASSERT(prAdapter); + ASSERT(prSwRfb); + + u2IELength = prSwRfb->u2PacketLen - + (u16)OFFSET_OF(ACTION_SM_REQ_FRAME, aucInfoElem[0]); + + prRxFrame = (P_ACTION_SM_REQ_FRAME)prSwRfb->pvHeader; + pucIE = prRxFrame->aucInfoElem; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + if (!prStaRec) { + return; + } + + if (prStaRec->ucBssIndex > MAX_BSS_INDEX) { + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + prBssDesc = prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc; + + prStaRec->ucSmDialogToken = prRxFrame->ucDialogToken; + + DBGLOG_MEM8(RLM, INFO, pucIE, u2IELength); + switch (prRxFrame->ucAction) { + case ACTION_MEASUREMENT_REQ: + DBGLOG(RLM, INFO, "[Mgt Action] Measure Request\n"); + prMeasurementReqIE = SM_MEASUREMENT_REQ_IE(pucIE); + if (prMeasurementReqIE->ucId == ELEM_ID_MEASUREMENT_REQ) { + /* Check IE length is valid */ + if (prMeasurementReqIE->ucLength != 0 && + (prMeasurementReqIE->ucLength >= + sizeof(IE_MEASUREMENT_REQ_T) - 2)) { + prStaRec->ucSmMsmtRequestMode = + prMeasurementReqIE->ucRequestMode; + prStaRec->ucSmMsmtToken = + prMeasurementReqIE->ucToken; + msmtComposeReportFrame(prAdapter, prStaRec, + NULL); + } + } + + break; + + case ACTION_MEASUREMENT_REPORT: + DBGLOG(RLM, INFO, "[Mgt Action] Measure Report\n"); + prMeasurementRepIE = SM_MEASUREMENT_REP_IE(pucIE); + if (prMeasurementRepIE->ucId == ELEM_ID_MEASUREMENT_REPORT) { + DBGLOG(RLM, TRACE, + "[Mgt Action] Correct Measurement report IE !!\n"); + } + break; + + case ACTION_TPC_REQ: + DBGLOG(RLM, INFO, "[Mgt Action] TPC Request\n"); + prTpcReqIE = SM_TPC_REQ_IE(pucIE); + + if (prTpcReqIE->ucId == ELEM_ID_TPC_REQ) { + tpcComposeReportFrame(prAdapter, prStaRec, NULL); + } + + break; + + case ACTION_TPC_REPORT: + DBGLOG(RLM, INFO, "[Mgt Action] TPC Report\n"); + prTpcRepIE = SM_TPC_REP_IE(pucIE); + + if (prTpcRepIE->ucId == ELEM_ID_TPC_REPORT) { + DBGLOG(RLM, TRACE, + "[Mgt Action] Correct TPC report IE !!\n"); + } + + break; + +#if CFG_SUPPORT_DFS + case ACTION_CHNL_SWITCH: + prCSAParams = &prBssInfo->CSAParams; + ucCurrentCsaCount = MAX_CSA_COUNT; + + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_WIDE_BAND_CHANNEL_SWITCH: + if (!RLM_NET_IS_11AC(prBssInfo) || + IE_LEN(pucIE) != + (sizeof(IE_WIDE_BAND_CHANNEL_T) - + 2)) { + DBGLOG(RLM, + INFO, + "[CSA Mgt] ELEM_ID_WIDE_BAND_CHANNEL_SWITCH, Length\n"); + break; + } + DBGLOG(RLM, + INFO, + "[CSA Mgt] ELEM_ID_WIDE_BAND_CHANNEL_SWITCH, 11AC\n"); + prWideBandChannelIE = + (P_IE_WIDE_BAND_CHANNEL_T)pucIE; + prCSAParams->ucVhtBw = + prWideBandChannelIE->ucNewChannelWidth; + prCSAParams->ucVhtS1 = + prWideBandChannelIE->ucChannelS1; + prCSAParams->ucVhtS2 = + prWideBandChannelIE->ucChannelS2; + DBGLOG(RLM, STATE, + "[CSA Mgt] ACT BW=%d, s1=%d, s2=%d\n", + prCSAParams->ucVhtBw, + prCSAParams->ucVhtS1, + prCSAParams->ucVhtS2); + break; + + case ELEM_ID_CH_SW_ANNOUNCEMENT: + if (IE_LEN(pucIE) != + (sizeof(IE_CHANNEL_SWITCH_T) - 2)) { + DBGLOG(RLM, + INFO, + "[CSA Mgt] ELEM_ID_CH_SW_ANNOUNCEMENT, Length\n"); + break; + } + + prChannelSwitchAnnounceIE = + (P_IE_CHANNEL_SWITCH_T)pucIE; + + DBGLOG(RLM, STATE, + "[CSA Mgt] switch channel [%d]->[%d]\n", + prBssInfo->ucPrimaryChannel, + prChannelSwitchAnnounceIE + ->ucNewChannelNum); + + prCSAParams->ucCsaNewCh = + prChannelSwitchAnnounceIE + ->ucNewChannelNum; + ucCurrentCsaCount = + prChannelSwitchAnnounceIE + ->ucChannelSwitchCount; + + if (prChannelSwitchAnnounceIE + ->ucChannelSwitchMode == 1) { + /* Need to stop data transmission + * immediately */ + if (!prBssInfo->fgHasStopTx) { + prBssInfo->fgHasStopTx = true; +#if CFG_SUPPORT_TDLS + /* TDLS peers */ + TdlsTxCtrl(prAdapter, prBssInfo, + false); +#endif + /* AP */ + qmSetStaRecTxAllowed(prAdapter, + prStaRec, + false); + DBGLOG(RLM, + EVENT, + "[CSA Mgt] TxAllowed = false\n"); + } + } else { + DBGLOG(RLM, + INFO, + "[CSA Mgt] ucChannelSwitchMode = 0\n"); + } + +#if CFG_DFS_NEWCH_DFS_FORCE_DISCONNECT + max_count = rlmDomainGetActiveChannelCount( + NL80211_BAND_5GHZ) + + rlmDomainGetActiveChannelCount( + NL80211_BAND_2GHZ); + for (i = 0; i < max_count; i++) { + Channel = rlmDomainGetActiveChannels() + + i; + + if (Channel->chNum != + prChannelSwitchAnnounceIE + ->ucNewChannelNum) { + Channel = NULL; + continue; + } else if (Channel->chNum == + prChannelSwitchAnnounceIE + ->ucNewChannelNum) { + break; + } + } + + DBGLOG(RLM, + INFO, + "[DFS][CSA][CLIENT] Switch to new channel: new ChNum = [%d]\n", + prChannelSwitchAnnounceIE + ->ucNewChannelNum); + if ((Channel) && + (Channel->flags & IEEE80211_CHAN_RADAR)) { + prCSAParams->fgBeaconNewChannelIsDFS = + true; + DBGLOG(RLM, + INFO, + "[DFS][CSA][CLIENT] New channel is DFS channel!"); + } else if (!Channel) { + prCSAParams->fgNewChannelIsDisabled = + true; + DBGLOG(RLM, + INFO, + "[DFS][CSA][CLIENT] New channel is un-supported channel!"); + } else { + DBGLOG(RLM, + INFO, + "[DFS][CSA][CLIENT] New channel is non-DFS channel!"); + } +#endif + break; + + case ELEM_ID_SCO: + if (IE_LEN(pucIE) != + (sizeof(IE_SECONDARY_OFFSET_T) - 2)) { + DBGLOG(RLM, INFO, + "[CSA Mgt] ELEM_ID_SCO, Length\n"); + break; + } + prSecondaryOffsetIE = + (P_IE_SECONDARY_OFFSET_T)pucIE; + + DBGLOG(RLM, INFO, "[CSA Mgt] SCO [%d]->[%d]\n", + prBssInfo->eBssSCO, + prSecondaryOffsetIE->ucSecondaryOffset); + + prCSAParams->eSco = + (ENUM_CHNL_EXT_T)prSecondaryOffsetIE + ->ucSecondaryOffset; + break; + + default: + break; + } /*end of switch IE_ID */ + } /*end of IE_FOR_EACH */ + + if (SHOULD_CH_SWITCH(ucCurrentCsaCount, prCSAParams, + prBssDesc)) { + cnmTimerStopTimer(prAdapter, &prBssInfo->rCsaTimer); + cnmTimerStartTimer( + prAdapter, &prBssInfo->rCsaTimer, + TU_TO_MSEC(prBssInfo->u2BeaconInterval * + ucCurrentCsaCount)); + prCSAParams->ucCsaCount = ucCurrentCsaCount; + DBGLOG(RLM, INFO, + "[CSA Mgt] Channel switch Countdown: %d msecs\n", + TU_TO_MSEC(prBssInfo->u2BeaconInterval * + prCSAParams->ucCsaCount)); + } + + break; + +#endif + default: + break; + } +} + +#if CFG_SUPPORT_DBDC_TC6 +/*----------------------------------------------------------------------------*/ +/*! + * \brief Send channel switch frame + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u32 rlmSendChannelSwitchTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + do { + ASSERT_BREAK((prAdapter != NULL) && (prMsduInfo != NULL)); + + DBGLOG(P2P, INFO, "CSA TX Done Status: %d, seqNo: %d\n", + rTxDoneStatus, prMsduInfo->ucTxSeqNum); + } while (false); + + return WLAN_STATUS_SUCCESS; +} + +void rlmSendChannelSwitchFrame(IN P_ADAPTER_T prAdapter, u8 ucBssIndex) +{ + P_MSDU_INFO_T prMsduInfo; + P_ACTION_CHANNEL_SWITCH_FRAME prTxFrame; + P_BSS_INFO_T prBssInfo; + u16 u2EstimatedFrameLen; + PFN_TX_DONE_HANDLER pfTxDoneHandler = (PFN_TX_DONE_HANDLER)NULL; + u8 aucBMC[] = BC_MAC_ADDR; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + if (!prBssInfo) { + return; + } + + /* Calculate MSDU buffer length */ + u2EstimatedFrameLen = + MAC_TX_RESERVED_FIELD + sizeof(ACTION_CHANNEL_SWITCH_FRAME); + + /* Alloc MSDU_INFO */ + prMsduInfo = + (P_MSDU_INFO_T)cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + + kalMemZero(prMsduInfo->prPacket, u2EstimatedFrameLen); + + prTxFrame = prMsduInfo->prPacket; + + /* Fill frame ctrl */ + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + + COPY_MAC_ADDR(prTxFrame->aucDestAddr, aucBMC); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + /* 3 Compose the frame body's frame */ + prTxFrame->ucCategory = CATEGORY_SPEC_MGT; + prTxFrame->ucAction = ACTION_CHNL_SWITCH; + + prTxFrame->aucInfoElem[0] = ELEM_ID_CH_SW_ANNOUNCEMENT; + prTxFrame->aucInfoElem[1] = 3; + prTxFrame->aucInfoElem[2] = prAdapter->rWifiVar.ucChannelSwitchMode; + prTxFrame->aucInfoElem[3] = prAdapter->rWifiVar.ucNewChannelNumber; + prTxFrame->aucInfoElem[4] = prAdapter->rWifiVar.ucChannelSwitchCount; + + pfTxDoneHandler = rlmSendChannelSwitchTxDone; + + /* 4 Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prBssInfo->ucBssIndex, + STA_REC_INDEX_BMCAST, WLAN_MAC_MGMT_HEADER_LEN, + sizeof(ACTION_CHANNEL_SWITCH_FRAME), pfTxDoneHandler, + MSDU_RATE_MODE_AUTO); + + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); +} +#endif + +void rlmResetCSAParams(P_BSS_INFO_T prBssInfo) +{ + P_SWITCH_CH_AND_BAND_PARAMS_T prCSAParams; + + if (!prBssInfo) { + DBGLOG(RLM, ERROR, "Reset CSA params failed, Bssinfo null!"); + return; + } + + prCSAParams = &(prBssInfo->CSAParams); + kalMemZero(prCSAParams, sizeof(SWITCH_CH_AND_BAND_PARAMS_T)); + prCSAParams->ucCsaCount = MAX_CSA_COUNT; + prCSAParams->fgBeaconNewChannelIsDFS = false; + prCSAParams->fgActionNewChannelIsDFS = false; + prCSAParams->fgNewChannelIsDisabled = false; + DBGLOG(RLM, INFO, "Reset CSA count to %u for BSS%d", + prCSAParams->ucCsaCount, prBssInfo->ucBssIndex); + prBssInfo->fgHasStopTx = false; +} + +void rlmCsaTimeout(IN P_ADAPTER_T prAdapter, unsigned long ulParamPtr) +{ + u8 ucBssIndex = (u8)ulParamPtr; + P_BSS_INFO_T prBssInfo; + P_SWITCH_CH_AND_BAND_PARAMS_T prCSAParams; + P_BSS_DESC_T prBssDesc; + P_STA_RECORD_T prStaRec; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + if (!prBssInfo) { + DBGLOG(AIS, INFO, "No prBssInfo\n"); + return; + } + + prStaRec = prBssInfo->prStaRecOfAP; + if (!prStaRec) { + rlmResetCSAParams(prBssInfo); + DBGLOG(AIS, INFO, "No prStaRec\n"); + return; + } + + prCSAParams = &prBssInfo->CSAParams; + + DBGLOG(RLM, EVENT, + "[CSA] CSA timeout and prepare to switch to new channel(%d)\n", + prCSAParams->ucCsaNewCh); + + if (prCSAParams->fgNewChannelIsDisabled) { + prCSAParams->fgNewChannelIsDisabled = false; + /* do aisBSSlinkdown directly here without sending CSA + * notification */ + DBGLOG(RLM, + EVENT, + "[CSA] Disconnect with the AP due to the new channel is un-supported\n"); + aisBssLinkDown(prAdapter); + rlmResetCSAParams(prBssInfo); + return; + } + + prBssInfo->ucPrimaryChannel = prCSAParams->ucCsaNewCh; + prBssInfo->eBand = (prCSAParams->ucCsaNewCh <= 14) ? BAND_2G4 : BAND_5G; + + if (HAS_WIDE_BAND_PARAMS(prCSAParams)) { + prBssInfo->ucVhtChannelWidth = prCSAParams->ucVhtBw; + prBssInfo->ucVhtChannelFrequencyS1 = prCSAParams->ucVhtS1; + prBssInfo->ucVhtChannelFrequencyS2 = prCSAParams->ucVhtS2; + +#if CFG_SUPPORT_DBDC + if (prBssInfo->fgIsOpChangeChannelWidth && + rlmGetVhtOpBwByBssOpBw(prBssInfo->ucOpChangeChannelWidth) < + prBssInfo->ucVhtChannelWidth) { + DBGLOG(RLM, + LOUD, + "Change to w:%d s1:%d s2:%d since own changed BW < peer's WideBand BW", + prBssInfo->ucVhtChannelWidth, + prBssInfo->ucVhtChannelFrequencyS1, + prBssInfo->ucVhtChannelFrequencyS2); + } +#endif + } + + if (HAS_SCO_PARAMS(prCSAParams)) { + prBssInfo->eBssSCO = prCSAParams->eSco; + } + + prBssDesc = prAdapter->rWifiVar.rAisFsmInfo.prTargetBssDesc; + + if (prBssDesc) { + DBGLOG(RLM, INFO, + "DFS: BSS: " MACSTR + " Desc found, channel from %u to %u with sco:%u\n ", + MAC2STR(prBssInfo->aucBSSID), prBssDesc->ucChannelNum, + prCSAParams->ucCsaNewCh, prBssInfo->eBssSCO); + prBssDesc->ucChannelNum = prBssInfo->ucPrimaryChannel; + prBssDesc->eChannelWidth = prBssInfo->ucVhtChannelWidth; + prBssDesc->ucCenterFreqS1 = prBssInfo->ucVhtChannelFrequencyS1; + prBssDesc->ucCenterFreqS2 = prBssInfo->ucVhtChannelFrequencyS2; + + kalUpdateBssChannel(prAdapter->prGlueInfo, prBssDesc->aucSSID, + prBssDesc->ucSSIDLen, prBssDesc->aucBSSID, + prBssDesc->ucChannelNum); + + kalIndicateChannelSwitch(prAdapter->prGlueInfo, + prBssInfo->eBssSCO, + prBssDesc->ucChannelNum); + } else { + DBGLOG(RLM, INFO, "DFS: BSS: " MACSTR " Desc is not found\n ", + MAC2STR(prBssInfo->aucBSSID)); + } + +#ifdef CFG_DFS_CHSW_FORCE_BW20 + /*DFS Certification for Channel Bandwidth 20MHz */ + prBssInfo->eBssSCO = CHNL_EXT_SCN; + prBssInfo->ucVhtChannelWidth = CW_20_40MHZ; + prBssInfo->ucVhtChannelFrequencyS1 = 0; + prBssInfo->ucVhtChannelFrequencyS2 = 255; + prBssInfo->ucHtOpInfo1 &= + ~(HT_OP_INFO1_SCO | HT_OP_INFO1_STA_CHNL_WIDTH); + DBGLOG(RLM, INFO, "Ch : DFS has Appeared\n"); +#endif + + rlmReviseMaxBw(prAdapter, prBssInfo->ucBssIndex, &prBssInfo->eBssSCO, + (u8 *)&prBssInfo->ucVhtChannelWidth, + &prBssInfo->ucVhtChannelFrequencyS1, + &prBssInfo->ucPrimaryChannel); + + rlmRevisePreferBandwidthNss(prAdapter, prBssInfo->ucBssIndex, prStaRec); + + /* Revise and align S1 to primary channel */ + if (prBssInfo->ucVhtChannelFrequencyS1 != + nicGetVhtS1(prBssInfo->ucPrimaryChannel, + prBssInfo->ucVhtChannelWidth)) { + DBGLOG(RLM, STATE, "DFS:Revise BSS %d Ch=%d BW=%d S1=%d\n", + prBssInfo->ucBssIndex, prBssInfo->ucPrimaryChannel, + prBssInfo->ucVhtChannelWidth, + prBssInfo->ucVhtChannelFrequencyS1); + } + + if (!rlmDomainIsValidRfSetting( + prAdapter, prBssInfo->eBand, prBssInfo->ucPrimaryChannel, + prBssInfo->eBssSCO, prBssInfo->ucVhtChannelWidth, + prBssInfo->ucVhtChannelFrequencyS1, + prBssInfo->ucVhtChannelFrequencyS2)) { + prBssInfo->ucVhtChannelWidth = CW_20_40MHZ; + prBssInfo->ucVhtChannelFrequencyS1 = 0; + prBssInfo->ucVhtChannelFrequencyS2 = 0; + prBssInfo->eBssSCO = CHNL_EXT_SCN; + prBssInfo->ucHtOpInfo1 &= + ~(HT_OP_INFO1_SCO | HT_OP_INFO1_STA_CHNL_WIDTH); + +#if (!CFG_SUPPORT_DBDC_TC6) + /* Check SAP channel */ + p2pFuncSwitchSapChannel(prAdapter); +#else + DBGLOG(RLM, EVENT, + "[CSA] Bypass SAP channel switch triggered by driver\n"); +#endif + } + + rlmSyncOperationParams(prAdapter, prBssInfo); + + /* After Channel Switch */ +#if CFG_DFS_NEWCH_DFS_FORCE_DISCONNECT + if (prCSAParams->fgBeaconNewChannelIsDFS || + prCSAParams->fgActionNewChannelIsDFS) { + prCSAParams->fgBeaconNewChannelIsDFS = false; + prCSAParams->fgActionNewChannelIsDFS = false; + aisBssLinkDown(prAdapter); + } else +#endif + { + qmUpdateStaRec(prAdapter, prStaRec); + DBGLOG(RLM, EVENT, "[CSA] TxAllowed = %d\n", + prStaRec->fgIsTxAllowed); + } + + rlmResetCSAParams(prBssInfo); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Send OpMode Norification frame (VHT action frame) + * + * \param[in] ucChannelWidth 0:20MHz, 1:40MHz, 2:80MHz, 3:160MHz or 80+80MHz + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmSendOpModeNotificationFrame(P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, u8 ucChannelWidth, + u8 ucNss) +{ + P_MSDU_INFO_T prMsduInfo; + P_ACTION_OP_MODE_NOTIFICATION_FRAME prTxFrame; + P_BSS_INFO_T prBssInfo; + u16 u2EstimatedFrameLen; + /* PFN_TX_DONE_HANDLER pfTxDoneHandler = (PFN_TX_DONE_HANDLER) NULL; */ + + /* Sanity Check */ + if (!prStaRec) { + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + if (!prBssInfo) { + return; + } + + /* Calculate MSDU buffer length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + + sizeof(ACTION_OP_MODE_NOTIFICATION_FRAME); + + /* Alloc MSDU_INFO */ + prMsduInfo = + (P_MSDU_INFO_T)cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + + if (!prMsduInfo) { + return; + } + + kalMemZero(prMsduInfo->prPacket, u2EstimatedFrameLen); + + prTxFrame = prMsduInfo->prPacket; + + /* Fill frame ctrl */ + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + /* 3 Compose the frame body's frame */ + prTxFrame->ucCategory = CATEGORY_VHT_ACTION; + prTxFrame->ucAction = ACTION_OPERATING_MODE_NOTIFICATION; + + prTxFrame->ucOperatingMode |= + (ucChannelWidth & VHT_OP_MODE_CHANNEL_WIDTH); + + if (ucNss == 0) { + ucNss = 1; + } + prTxFrame->ucOperatingMode |= (((ucNss - 1) << 4) & VHT_OP_MODE_RX_NSS); + prTxFrame->ucOperatingMode &= ~VHT_OP_MODE_RX_NSS_TYPE; + + /* 4 Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prBssInfo->ucBssIndex, + prStaRec->ucIndex, WLAN_MAC_MGMT_HEADER_LEN, + sizeof(ACTION_OP_MODE_NOTIFICATION_FRAME), NULL, + MSDU_RATE_MODE_AUTO); + + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Send SM Power Save frame (HT action frame) + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmSendSmPowerSaveFrame(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, + u8 ucNss) +{ + P_MSDU_INFO_T prMsduInfo; + P_ACTION_SM_POWER_SAVE_FRAME prTxFrame; + P_BSS_INFO_T prBssInfo; + u16 u2EstimatedFrameLen; + /* PFN_TX_DONE_HANDLER pfTxDoneHandler = (PFN_TX_DONE_HANDLER) NULL; */ + + /* Sanity Check */ + if (!prStaRec) { + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + if (!prBssInfo) { + return; + } + + /* Calculate MSDU buffer length */ + u2EstimatedFrameLen = + MAC_TX_RESERVED_FIELD + sizeof(ACTION_SM_POWER_SAVE_FRAME); + + /* Alloc MSDU_INFO */ + prMsduInfo = + (P_MSDU_INFO_T)cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + + if (!prMsduInfo) { + return; + } + + kalMemZero(prMsduInfo->prPacket, u2EstimatedFrameLen); + + prTxFrame = prMsduInfo->prPacket; + + /* Fill frame ctrl */ + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + /* 3 Compose the frame body's frame */ + prTxFrame->ucCategory = CATEGORY_HT_ACTION; + prTxFrame->ucAction = ACTION_HT_SM_POWER_SAVE; + + if (ucNss == 1) { + prTxFrame->ucSmPowerCtrl |= HT_SM_POWER_SAVE_CONTROL_ENABLED; + } else if (ucNss == 2) { + prTxFrame->ucSmPowerCtrl &= ~HT_SM_POWER_SAVE_CONTROL_ENABLED; + } else { + DBGLOG(RLM, WARN, + "Can't switch to Nss = %d since we don't support.\n", + ucNss); + return; + } + + prTxFrame->ucSmPowerCtrl &= + (~HT_SM_POWER_SAVE_CONTROL_SM_MODE); /* Static + * SM + * power + * save + * mode + */ + + /* 4 Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prBssInfo->ucBssIndex, + prStaRec->ucIndex, WLAN_MAC_MGMT_HEADER_LEN, + sizeof(ACTION_SM_POWER_SAVE_FRAME), NULL, + MSDU_RATE_MODE_AUTO); + + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Send Notify Channel Width frame (HT action frame) + * + * \param[in] ucChannelWidth 0:20MHz, 1:Any channel width in the STA¡¦s + * Supported Channel Width Set subfield + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmSendNotifyChannelWidthFrame(P_ADAPTER_T prAdapter, + P_STA_RECORD_T prStaRec, u8 ucChannelWidth) +{ + P_MSDU_INFO_T prMsduInfo; + P_ACTION_NOTIFY_CHANNEL_WIDTH_FRAME prTxFrame; + P_BSS_INFO_T prBssInfo; + u16 u2EstimatedFrameLen; + /* PFN_TX_DONE_HANDLER pfTxDoneHandler = (PFN_TX_DONE_HANDLER) NULL; */ + + /* Sanity Check */ + if (!prStaRec) { + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + if (!prBssInfo) { + return; + } + + /* Calculate MSDU buffer length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + + sizeof(ACTION_NOTIFY_CHANNEL_WIDTH_FRAME); + + /* Alloc MSDU_INFO */ + prMsduInfo = + (P_MSDU_INFO_T)cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + + if (!prMsduInfo) { + return; + } + + kalMemZero(prMsduInfo->prPacket, u2EstimatedFrameLen); + + prTxFrame = prMsduInfo->prPacket; + + /* Fill frame ctrl */ + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + /* 3 Compose the frame body's frame */ + prTxFrame->ucCategory = CATEGORY_HT_ACTION; + prTxFrame->ucAction = ACTION_HT_NOTIFY_CHANNEL_WIDTH; + + prTxFrame->ucChannelWidth = ucChannelWidth; + + /* 4 Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prBssInfo->ucBssIndex, + prStaRec->ucIndex, WLAN_MAC_MGMT_HEADER_LEN, + sizeof(ACTION_NOTIFY_CHANNEL_WIDTH_FRAME), NULL, + MSDU_RATE_MODE_AUTO); + + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Change OpMode Nss/Channel Width + * + * \param[in] ucChannelWidth 0:20MHz, 1:40MHz, 2:80MHz, 3:160MHz 4:80+80MHz + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u8 rlmChangeOperationMode(P_ADAPTER_T prAdapter, u8 ucBssIndex, + u8 ucChannelWidth, u8 ucNss) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + /*u8 fgIsSuccess = false;*/ + u8 fgIsChangeVhtBw = true, fgIsChangeHtBw = true; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + /* No need to change BSS 4 rlm parameter */ + if (ucBssIndex >= HW_BSSID_NUM) { + return false; + } + + if (!prBssInfo) { + return false; + } + + DBGLOG(RLM, INFO, + "Intend to change BSS[%d] OP Mode to BW[%d] Nss[%d]\n", + ucBssIndex, ucChannelWidth, ucNss); + +#if CFG_SUPPORT_802_11AC + /* Check peer VHT/HT OP Channel Width */ + if (ucChannelWidth == prBssInfo->ucOpChangeChannelWidth) { + fgIsChangeVhtBw = false; + } else if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + switch (ucChannelWidth) { + case MAX_BW_80_80_MHZ: + if (prBssInfo->ucVhtPeerChannelWidth != + VHT_OP_CHANNEL_WIDTH_80P80) { + DBGLOG(RLM, + INFO, + "Can't change to BW80_80 due to peer VHT OP BW is BW[%d]\n", + prBssInfo->ucVhtPeerChannelWidth); + fgIsChangeVhtBw = false; + } + break; + + case MAX_BW_160MHZ: + if (prBssInfo->ucVhtPeerChannelWidth != + VHT_OP_CHANNEL_WIDTH_160) { + DBGLOG(RLM, + INFO, + "Can't change to BW160 due to peer VHT OP BW is BW[%d]\n", + prBssInfo->ucVhtPeerChannelWidth); + fgIsChangeVhtBw = false; + } + break; + + case MAX_BW_80MHZ: + if (prBssInfo->ucVhtPeerChannelWidth < + VHT_OP_CHANNEL_WIDTH_80) { + DBGLOG(RLM, + INFO, + "Can't change to BW80 due to peer VHT OP BW is BW[%d]\n", + prBssInfo->ucVhtPeerChannelWidth); + fgIsChangeVhtBw = false; + } + break; + + case MAX_BW_40MHZ: + if (!(prBssInfo->ucHtPeerOpInfo1 & + HT_OP_INFO1_STA_CHNL_WIDTH) || + (!prBssInfo->fg40mBwAllowed)) { + DBGLOG(RLM, + INFO, + "Can't change to BW40: PeerOpBw[%d] fg40mBwAllowed[%d]\n", + (prBssInfo->ucHtPeerOpInfo1 & + HT_OP_INFO1_STA_CHNL_WIDTH), + prBssInfo->fg40mBwAllowed); + fgIsChangeVhtBw = false; + } + break; + + case MAX_BW_20MHZ: + break; + + default: + DBGLOG(RLM, WARN, + "BW[%d] is invalid for OpMode change\n", + ucChannelWidth); + fgIsChangeVhtBw = false; + } + } +#endif + + /* Check HT OP Channel Width */ + if (ucChannelWidth == prBssInfo->ucOpChangeChannelWidth) { + fgIsChangeHtBw = false; + } else if (ucChannelWidth >= MAX_BW_80MHZ) { + DBGLOG(RLM, WARN, "BW[%d] is invalid for HT OpMode change\n", + ucChannelWidth); + fgIsChangeHtBw = false; + } else if (ucChannelWidth == MAX_BW_40MHZ) { + if (!(prBssInfo->ucHtPeerOpInfo1 & + HT_OP_INFO1_STA_CHNL_WIDTH) || + (!prBssInfo->fg40mBwAllowed)) { + DBGLOG(RLM, + INFO, + "Can't change to BW40: PeerOpBw[%d] fg40mBwAllowed[%d]\n", + (prBssInfo->ucHtPeerOpInfo1 & + HT_OP_INFO1_STA_CHNL_WIDTH), + prBssInfo->fg40mBwAllowed); + fgIsChangeHtBw = false; + } + } + + if (fgIsChangeHtBw) { + /* <4>Update HT Channel Width */ + if (ucChannelWidth == MAX_BW_20MHZ) { + prBssInfo->ucHtOpInfo1 &= ~HT_OP_INFO1_STA_CHNL_WIDTH; + prBssInfo->eBssSCO = CHNL_EXT_SCN; + } else if (ucChannelWidth == MAX_BW_40MHZ) { + prBssInfo->ucHtOpInfo1 |= HT_OP_INFO1_STA_CHNL_WIDTH; + if ((prBssInfo->ucHtPeerOpInfo1 & HT_OP_INFO1_SCO) != + CHNL_EXT_RES) { + prBssInfo->eBssSCO = + (ENUM_CHNL_EXT_T)(prBssInfo-> + ucHtPeerOpInfo1 & + HT_OP_INFO1_SCO); + } + } else { + fgIsChangeHtBw = false; + } + } + +#if CFG_SUPPORT_802_11AC + if (fgIsChangeVhtBw) { + prBssInfo->ucOpChangeChannelWidth = ucChannelWidth; + prBssInfo->fgIsOpChangeChannelWidth = true; + /* <3>Update VHT Channel Width*/ + rlmChangeVhtOpBwPara(prAdapter, ucBssIndex, + prBssInfo->ucOpChangeChannelWidth); + + DBGLOG(RLM, INFO, + "Update VHT Channel Width Info to w=%d s1=%d s2=%d\n", + prBssInfo->ucVhtChannelWidth, + prBssInfo->ucVhtChannelFrequencyS1, + prBssInfo->ucVhtChannelFrequencyS2); + } +#endif + if (fgIsChangeHtBw) { + prBssInfo->ucOpChangeChannelWidth = ucChannelWidth; + prBssInfo->fgIsOpChangeChannelWidth = true; + + DBGLOG(RLM, INFO, + "Update HT Channel Width Info to bw=%d s=%d\n", + (prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_STA_CHNL_WIDTH) >> + 2, + prBssInfo->eBssSCO); + } + + if ((prBssInfo->ucNss != ucNss) || fgIsChangeVhtBw || fgIsChangeHtBw) { + /* 1. Update BSS Info */ + prBssInfo->ucNss = ucNss; + rlmSyncOperationParams(prAdapter, prBssInfo); + + if (prBssInfo->eCurrentOPMode == + OP_MODE_INFRASTRUCTURE) { /* For + * infrastructure, + * GC + */ + if (prBssInfo->prStaRecOfAP) { + prStaRec = prBssInfo->prStaRecOfAP; +#if CFG_SUPPORT_802_11AC + /* 2. Check if we can change OpMode and Send + * OPmode notification frame */ + if (prStaRec->ucDesiredPhyTypeSet & + PHY_TYPE_BIT_VHT) { /*Send VHT notification + * frame*/ + /* <1> Notify VHT Nss and Channel Width + * change*/ + rlmSendOpModeNotificationFrame( + prAdapter, prStaRec, + ucChannelWidth, + prBssInfo->ucNss); + DBGLOG(RLM, + INFO, + "Send VHT OPmode notification frame, BW=%d, Nss=%d\n", + ucChannelWidth, + prBssInfo->ucNss); + } else +#endif + if (prStaRec->ucDesiredPhyTypeSet & + PHY_TYPE_BIT_HT) { /*Send HT + * notification + * frame*/ + /* <1> Notify HT Nss change */ + rlmSendSmPowerSaveFrame( + prAdapter, prStaRec, + prBssInfo->ucNss); + DBGLOG(RLM, + INFO, + "Send HT SM Power Save frame, Nss=%d\n", + prBssInfo->ucNss); + } + + if (fgIsChangeHtBw) { + /* <3> Notify HT Channel Width change */ + rlmSendNotifyChannelWidthFrame( + prAdapter, prStaRec, + ucChannelWidth); + DBGLOG(RLM, + INFO, + "Send HT Notify Channel Width frame, BW=%d\n", + ucChannelWidth); + } + } else { + DBGLOG(RLM, WARN, + "Can't change OpMode at legacy mode\n"); + } + } else if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + P_LINK_T prClientList; + + /* 4. Update BCN/Probe Resp IE to notify peers the OP is + * be changed */ + DBGLOG(RLM, INFO, + "Beacon content update with Bssidex(%d)\n", + prBssInfo->ucBssIndex); + + prClientList = &prBssInfo->rStaRecOfClientList; + + LINK_FOR_EACH_ENTRY(prStaRec, prClientList, rLinkEntry, + STA_RECORD_T) { +#if CFG_SUPPORT_802_11AC + /* 2. Check if we can change OpMode and Send + * OPmode notification frame */ + if (prStaRec->ucDesiredPhyTypeSet & + PHY_TYPE_BIT_VHT) { /*Send VHT notification + * frame*/ + /* <1> Notify VHT Nss and Channel Width + * change*/ + rlmSendOpModeNotificationFrame( + prAdapter, prStaRec, + ucChannelWidth, + prBssInfo->ucNss); + DBGLOG(RLM, + INFO, + "Send VHT OPmode notification frame, BW=%d, Nss=%d\n", + ucChannelWidth, + prBssInfo->ucNss); + } else +#endif + if (prStaRec->ucDesiredPhyTypeSet & + PHY_TYPE_BIT_HT) { /*Send HT + * notification + * frame*/ + /* <1> Notify HT Nss change */ + rlmSendSmPowerSaveFrame( + prAdapter, prStaRec, + prBssInfo->ucNss); + DBGLOG(RLM, + INFO, + "Send HT SM Power Save frame, Nss=%d\n", + prBssInfo->ucNss); + } + + if (fgIsChangeHtBw) { + /* <3> Notify HT Channel Width change */ + rlmSendNotifyChannelWidthFrame( + prAdapter, prStaRec, + ucChannelWidth); + DBGLOG(RLM, + INFO, + "Send HT Notify Channel Width frame, BW=%d\n", + ucChannelWidth); + } + } + + bssUpdateBeaconContent(prAdapter, + prBssInfo->ucBssIndex); + } else { + return false; + } + } + return true; +} + +#if CFG_SUPPORT_802_11K +void rlmReqGenerateRRMEnabledCapIE(P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo) +{ + P_IE_RRM_ENABLED_CAP_T prRrmEnabledCap = NULL; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prRrmEnabledCap = + (P_IE_RRM_ENABLED_CAP_T)(((u8 *)prMsduInfo->prPacket) + + prMsduInfo->u2FrameLength); + prRrmEnabledCap->ucId = ELEM_ID_RRM_ENABLED_CAP; + prRrmEnabledCap->ucLength = ELEM_MAX_LEN_RRM_CAP; + kalMemZero(&prRrmEnabledCap->aucCap[0], ELEM_MAX_LEN_RRM_CAP); + rlmFillRrmCapa(&prRrmEnabledCap->aucCap[0]); + prMsduInfo->u2FrameLength += IE_SIZE(prRrmEnabledCap); +} + +void rlmFillRrmCapa(u8 *pucCapa) +{ + u8 ucIndex = 0; + u8 aucEnabledBits[] = { RRM_CAP_INFO_LINK_MEASURE_BIT, + RRM_CAP_INFO_NEIGHBOR_REPORT_BIT, + RRM_CAP_INFO_REPEATED_MEASUREMENT, + RRM_CAP_INFO_BEACON_PASSIVE_MEASURE_BIT, + RRM_CAP_INFO_BEACON_ACTIVE_MEASURE_BIT, + RRM_CAP_INFO_BEACON_TABLE_BIT, + RRM_CAP_INFO_RRM_BIT }; + + for (; ucIndex < sizeof(aucEnabledBits); ucIndex++) + SET_EXT_CAP(pucCapa, ELEM_MAX_LEN_RRM_CAP, + aucEnabledBits[ucIndex]); +} + +void rlmTxNeighborReportRequest(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec, + struct SUB_ELEMENT_LIST *prSubIEs) +{ + static u8 ucDialogToken = 1; + P_MSDU_INFO_T prMsduInfo = NULL; + P_BSS_INFO_T prBssInfo = NULL; + u8 *pucPayload = NULL; + P_ACTION_NEIGHBOR_REPORT_FRAME_T prTxFrame = NULL; + u16 u2TxFrameLen = 500; + u16 u2FrameLen = 0; + + if (!prStaRec) { + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + ASSERT(prBssInfo); + /* 1 Allocate MSDU Info */ + prMsduInfo = (P_MSDU_INFO_T)cnmMgtPktAlloc( + prAdapter, MAC_TX_RESERVED_FIELD + u2TxFrameLen); + if (!prMsduInfo) { + return; + } + + prTxFrame = (ACTION_NEIGHBOR_REPORT_FRAME_T + *)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD); + + /* 2 Compose The Mac Header. */ + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + prTxFrame->ucCategory = CATEGORY_RM_ACTION; + prTxFrame->ucAction = ACTION_NEIGHBOR_REPORT_REQ; + u2FrameLen = OFFSET_OF(ACTION_NEIGHBOR_REPORT_FRAME_T, aucInfoElem); + /* 3 Compose the frame body's frame. */ + prTxFrame->ucDialogToken = ucDialogToken++; + u2TxFrameLen -= sizeof(*prTxFrame) - 1; + pucPayload = &prTxFrame->aucInfoElem[0]; + while (prSubIEs && u2TxFrameLen >= (prSubIEs->rSubIE.ucLength + 2)) { + kalMemCopy(pucPayload, &prSubIEs->rSubIE, + prSubIEs->rSubIE.ucLength + 2); + pucPayload += prSubIEs->rSubIE.ucLength + 2; + u2FrameLen += prSubIEs->rSubIE.ucLength + 2; + prSubIEs = prSubIEs->prNext; + } + nicTxSetMngPacket(prAdapter, prMsduInfo, prStaRec->ucBssIndex, + prStaRec->ucIndex, WLAN_MAC_MGMT_HEADER_LEN, + u2FrameLen, NULL, MSDU_RATE_MODE_AUTO); + + /* 5 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); +} + +void rlmProcessNeighborReportResponse(P_ADAPTER_T prAdapter, + P_WLAN_ACTION_FRAME prAction, + u16 u2PacketLen) +{ + P_ACTION_NEIGHBOR_REPORT_FRAME_T prNeighborResponse = + (P_ACTION_NEIGHBOR_REPORT_FRAME_T)prAction; + + ASSERT(prAdapter); + ASSERT(prNeighborResponse); + DBGLOG(RLM, INFO, "Neighbor Resp From " MACSTR ", DialogToken %d\n", + MAC2STR(prNeighborResponse->aucSrcAddr), + prNeighborResponse->ucDialogToken); + aisCollectNeighborAP(prAdapter, &prNeighborResponse->aucInfoElem[0], + u2PacketLen - + OFFSET_OF(ACTION_NEIGHBOR_REPORT_FRAME_T, + aucInfoElem), + 0); +} +#endif + +#if CFG_SUPPORT_QUIET +void rrmQuietIeNotExist(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + P_STA_RECORD_T prStaRec; + u32 u4QuietDuration = TU_TO_MSEC(prBssInfo->u2QuietDuration); + /* connected to AP */ + if (prBssInfo->prStaRecOfAP) { + prStaRec = prBssInfo->prStaRecOfAP; + } else { + prBssInfo->fgHasStopTx = false; + return; + } + + if (prBssInfo->fgRequestQuietInterval) { + cnmTimerStopTimer(prAdapter, &prBssInfo->rTxQuietTimer); + if (u4QuietDuration > 0) { + if (!prBssInfo->fgHasStopTx) { + prBssInfo->fgHasStopTx = true; + qmSetStaRecTxAllowed(prAdapter, prStaRec, + false); + } + cnmTimerStartTimer(prAdapter, &prBssInfo->rTxQuietTimer, + u4QuietDuration); + + prBssInfo->fgIsInQuietInterval = true; + DBGLOG(RLM, INFO, "[QIE] Tx disallow\n"); + } else { + if (prBssInfo->fgHasStopTx) { + qmUpdateStaRec(prAdapter, prStaRec); + prBssInfo->fgHasStopTx = false; + } + prBssInfo->fgIsInQuietInterval = false; + DBGLOG(RLM, INFO, "[QIE] Tx allow by Beacon IE\n"); + } + prBssInfo->fgRequestQuietInterval = false; + } +} + +void rrmQuietHandleQuietIE(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + P_IE_QUIET_T pucQUIE) +{ + u32 u4NextQuietTime; + cnmTimerStopTimer(prAdapter, &prBssInfo->rTxQuietTimer); + prBssInfo->u2QuietDuration = pucQUIE->u2Duration; + prBssInfo->ucQuietPeriod = pucQUIE->ucPeriod; + prBssInfo->u2QuietOffset = pucQUIE->u2Offset; + + DBGLOG(RLM, EVENT, "[QIE] Cnt[%d] Duration[%d] Offset[%d] Period[%d]\n", + pucQUIE->ucCount, pucQUIE->u2Duration, pucQUIE->u2Offset, + pucQUIE->ucPeriod); + + prBssInfo->fgRequestQuietInterval = true; + u4NextQuietTime = (u32)(pucQUIE->ucCount * prBssInfo->u2BeaconInterval + + pucQUIE->u2Offset); + u4NextQuietTime = TU_TO_MSEC(u4NextQuietTime); + if (u4NextQuietTime > 0) { + cnmTimerStartTimer(prAdapter, &prBssInfo->rTxQuietTimer, + u4NextQuietTime); + } else { + rrmQuietIeNotExist(prAdapter, prBssInfo); + } +} + +void rrmTxQuietTimeout(P_ADAPTER_T prAdapter, unsigned long ulParamPtr) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + u32 u4QuietPeriod; + prBssInfo = (P_BSS_INFO_T)ulParamPtr; + ASSERT(prBssInfo); + /* connected to AP */ + if (prBssInfo->prStaRecOfAP) { + prStaRec = prBssInfo->prStaRecOfAP; + } else { + prBssInfo->fgHasStopTx = false; + return; + } + + if (prBssInfo->fgRequestQuietInterval) { + rrmQuietIeNotExist(prAdapter, prBssInfo); + return; + } + + if (prBssInfo->fgIsInQuietInterval) { + if (prBssInfo->fgHasStopTx) { + qmUpdateStaRec(prAdapter, prStaRec); + prBssInfo->fgHasStopTx = false; + } + prBssInfo->fgIsInQuietInterval = false; + + if (prBssInfo->ucQuietPeriod) { + prBssInfo->fgRequestQuietInterval = true; + u4QuietPeriod = + (u32)(prBssInfo->ucQuietPeriod * + prBssInfo->u2BeaconInterval + + prBssInfo->u2QuietOffset); + u4QuietPeriod = TU_TO_MSEC(u4QuietPeriod); + cnmTimerStartTimer(prAdapter, &prBssInfo->rTxQuietTimer, + u4QuietPeriod); + } else { + prBssInfo->fgRequestQuietInterval = false; + } + } + DBGLOG(RLM, INFO, "[QIE] [TIMEOUT] Tx allow\n"); +} +#endif +#if CFG_SUPPORT_BFER +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmBfStaRecPfmuUpdate(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) +{ + u8 ucBFerMaxNr, ucBFeeMaxNr, ucMode; + P_BSS_INFO_T prBssInfo; + P_CMD_STAREC_BF prStaRecBF; + P_CMD_STAREC_UPDATE_T prStaRecUpdateInfo; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + u32 u4SetBufferLen = sizeof(CMD_STAREC_BF); + + prBssInfo = prAdapter->aprBssInfo[prStaRec->ucBssIndex]; + + if (RLM_NET_IS_11AC(prBssInfo) && + IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucStaVhtBfer)) { + ucMode = MODE_VHT; + }else if (RLM_NET_IS_11N(prBssInfo) && + IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucStaHtBfer)) { + ucMode = MODE_HT; + }else{ + ucMode = MODE_LEGACY; + } + + prStaRecBF = (P_CMD_STAREC_BF)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + u4SetBufferLen); + + if (!prStaRecBF) { + DBGLOG(RLM, ERROR, "STA Rec memory alloc fail\n"); + return; + } + + prStaRecUpdateInfo = (P_CMD_STAREC_UPDATE_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, + (CMD_STAREC_UPDATE_HDR_SIZE + u4SetBufferLen)); + + if (!prStaRecUpdateInfo) { + cnmMemFree(prAdapter, prStaRecBF); + DBGLOG(RLM, ERROR, "STA Rec Update Info memory alloc fail\n"); + return; + } + + switch (ucMode) { + case MODE_VHT: + prStaRec->rTxBfPfmuStaInfo.fgSU_MU = false; + prStaRec->rTxBfPfmuStaInfo.fgETxBfCap = + rlmClientSupportsVhtETxBF(prStaRec); + + if (prStaRec->rTxBfPfmuStaInfo.fgETxBfCap) { + /* OFDM, NDPA/Report Poll/CTS2Self tx mode */ + prStaRec->rTxBfPfmuStaInfo.ucSoundingPhy = + TX_RATE_MODE_OFDM; + + /* 9: OFDM 24M */ + prStaRec->rTxBfPfmuStaInfo.ucNdpaRate = PHY_RATE_24M; + + /* VHT mode, NDP tx mode */ + prStaRec->rTxBfPfmuStaInfo.ucTxMode = TX_RATE_MODE_VHT; + + /* 0: MCS0 */ + prStaRec->rTxBfPfmuStaInfo.ucNdpRate = PHY_RATE_MCS0; + + switch (prBssInfo->ucVhtChannelWidth) { + case VHT_OP_CHANNEL_WIDTH_80: + prStaRec->rTxBfPfmuStaInfo.ucCBW = MAX_BW_80MHZ; + break; + + case VHT_OP_CHANNEL_WIDTH_20_40: + default: + prStaRec->rTxBfPfmuStaInfo.ucCBW = MAX_BW_20MHZ; + if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { + prStaRec->rTxBfPfmuStaInfo.ucCBW = + MAX_BW_40MHZ; + } + break; + } + + ucBFerMaxNr = 1; /* 7668 is 2x2 */ + ucBFeeMaxNr = rlmClientSupportsVhtBfeeStsCap(prStaRec); + prStaRec->rTxBfPfmuStaInfo.ucNr = + (ucBFerMaxNr < ucBFeeMaxNr) ? ucBFerMaxNr : + ucBFeeMaxNr; + prStaRec->rTxBfPfmuStaInfo.ucNc = + ((prStaRec->u2VhtRxMcsMap & + VHT_CAP_INFO_MCS_2SS_MASK) != BITS(2, 3)) ? + 1 : + 0; + } + break; + + case MODE_HT: + prStaRec->rTxBfPfmuStaInfo.fgSU_MU = false; + prStaRec->rTxBfPfmuStaInfo.fgETxBfCap = + rlmClientSupportsHtETxBF(prStaRec); + + if (prStaRec->rTxBfPfmuStaInfo.fgETxBfCap) { + /* 0: HT MCS0 */ + prStaRec->rTxBfPfmuStaInfo.ucNdpaRate = PHY_RATE_MCS0; + + /* HT mode, NDPA/NDP tx mode */ + prStaRec->rTxBfPfmuStaInfo.ucTxMode = + TX_RATE_MODE_HTMIX; + + prStaRec->rTxBfPfmuStaInfo.ucCBW = MAX_BW_20MHZ; + if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { + prStaRec->rTxBfPfmuStaInfo.ucCBW = MAX_BW_40MHZ; + } + + ucBFerMaxNr = 1; /* 7668 is 2x2 */ + ucBFeeMaxNr = + (prStaRec->u4TxBeamformingCap & + TXBF_COMPRESSED_TX_ANTENNANUM_SUPPORTED) >> + TXBF_COMPRESSED_TX_ANTENNANUM_SUPPORTED_OFFSET; + prStaRec->rTxBfPfmuStaInfo.ucNr = + (ucBFerMaxNr < ucBFeeMaxNr) ? ucBFerMaxNr : + ucBFeeMaxNr; + prStaRec->rTxBfPfmuStaInfo.ucNc = + (prStaRec->aucRxMcsBitmask[1] > 0) ? 1 : 0; + prStaRec->rTxBfPfmuStaInfo.ucNdpRate = + prStaRec->rTxBfPfmuStaInfo.ucNr * 8; + } + break; + + default: + break; + } + + DBGLOG(RLM, INFO, "ucMode=%d\n", ucMode); + DBGLOG(RLM, INFO, "rlmClientSupportsVhtETxBF(prStaRec)=%d\n", + rlmClientSupportsVhtETxBF(prStaRec)); + DBGLOG(RLM, INFO, "rlmClientSupportsVhtBfeeStsCap(prStaRec)=%d\n", + rlmClientSupportsVhtBfeeStsCap(prStaRec)); + DBGLOG(RLM, INFO, "prStaRec->u2VhtRxMcsMap=%x\n", + prStaRec->u2VhtRxMcsMap); + + DBGLOG(RLM, INFO, + "====================== BF StaRec Info =====================\n"); + DBGLOG(RLM, INFO, "u2PfmuId =%d\n", + prStaRec->rTxBfPfmuStaInfo.u2PfmuId); + DBGLOG(RLM, INFO, "fgSU_MU =%d\n", prStaRec->rTxBfPfmuStaInfo.fgSU_MU); + DBGLOG(RLM, INFO, "fgETxBfCap =%d\n", + prStaRec->rTxBfPfmuStaInfo.fgETxBfCap); + DBGLOG(RLM, INFO, "ucSoundingPhy =%d\n", + prStaRec->rTxBfPfmuStaInfo.ucSoundingPhy); + DBGLOG(RLM, INFO, "ucNdpaRate =%d\n", + prStaRec->rTxBfPfmuStaInfo.ucNdpaRate); + DBGLOG(RLM, INFO, "ucNdpRate =%d\n", + prStaRec->rTxBfPfmuStaInfo.ucNdpRate); + DBGLOG(RLM, INFO, "ucReptPollRate =%d\n", + prStaRec->rTxBfPfmuStaInfo.ucReptPollRate); + DBGLOG(RLM, INFO, "ucTxMode =%d\n", + prStaRec->rTxBfPfmuStaInfo.ucTxMode); + DBGLOG(RLM, INFO, "ucNc =%d\n", prStaRec->rTxBfPfmuStaInfo.ucNc); + DBGLOG(RLM, INFO, "ucNr =%d\n", prStaRec->rTxBfPfmuStaInfo.ucNr); + DBGLOG(RLM, INFO, "ucCBW =%d\n", prStaRec->rTxBfPfmuStaInfo.ucCBW); + DBGLOG(RLM, INFO, "ucTotMemRequire=%d\n", + prStaRec->rTxBfPfmuStaInfo.ucTotMemRequire); + DBGLOG(RLM, INFO, "ucMemRequire20M=%d\n", + prStaRec->rTxBfPfmuStaInfo.ucMemRequire20M); + DBGLOG(RLM, INFO, "ucMemRow0 =%d\n", + prStaRec->rTxBfPfmuStaInfo.ucMemRow0); + DBGLOG(RLM, INFO, "ucMemCol0 =%d\n", + prStaRec->rTxBfPfmuStaInfo.ucMemCol0); + DBGLOG(RLM, INFO, "ucMemRow1 =%d\n", + prStaRec->rTxBfPfmuStaInfo.ucMemRow1); + DBGLOG(RLM, INFO, "ucMemCol1 =%d\n", + prStaRec->rTxBfPfmuStaInfo.ucMemCol1); + DBGLOG(RLM, INFO, "ucMemRow2 =%d\n", + prStaRec->rTxBfPfmuStaInfo.ucMemRow2); + DBGLOG(RLM, INFO, "ucMemCol2 =%d\n", + prStaRec->rTxBfPfmuStaInfo.ucMemCol2); + DBGLOG(RLM, INFO, "ucMemRow3 =%d\n", + prStaRec->rTxBfPfmuStaInfo.ucMemRow3); + DBGLOG(RLM, INFO, "ucMemCol3 =%d\n", + prStaRec->rTxBfPfmuStaInfo.ucMemCol3); + DBGLOG(RLM, INFO, + "===========================================================\n"); + + prStaRecBF->u2Tag = STA_REC_BF; + prStaRecBF->u2Length = u4SetBufferLen; + kalMemCopy(&prStaRecBF->rTxBfPfmuInfo, &prStaRec->rTxBfPfmuStaInfo, + sizeof(TXBF_PFMU_STA_INFO)); + + prStaRecUpdateInfo->ucBssIndex = prStaRec->ucBssIndex; + prStaRecUpdateInfo->ucWlanIdx = prStaRec->ucWlanIndex; + prStaRecUpdateInfo->u2TotalElementNum = 1; + kalMemCopy(prStaRecUpdateInfo->aucBuffer, prStaRecBF, u4SetBufferLen); + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, + EXT_CMD_ID_STAREC_UPDATE, true, false, false, + nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + (CMD_STAREC_UPDATE_HDR_SIZE + u4SetBufferLen), + (u8 *)prStaRecUpdateInfo, NULL, 0); + + if (rWlanStatus == WLAN_STATUS_FAILURE) { + DBGLOG(RLM, ERROR, "Send starec update cmd fail\n"); + } + + cnmMemFree(prAdapter, prStaRecBF); + cnmMemFree(prAdapter, prStaRecUpdateInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmETxBfTriggerPeriodicSounding(P_ADAPTER_T prAdapter) +{ + u32 u4SetBufferLen = sizeof(PARAM_CUSTOM_TXBF_ACTION_STRUCT_T); + PARAM_CUSTOM_TXBF_ACTION_STRUCT_T rTxBfActionInfo; + CMD_TXBF_ACTION_T rCmdTxBfActionInfo; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + DBGLOG(RLM, INFO, "rlmETxBfTriggerPeriodicSounding\n"); + + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfSndPeriodicTriggerCtrl.ucCmdCategoryID = + BF_SOUNDING_ON; + + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfSndPeriodicTriggerCtrl.ucSuMuSndMode = + AUTO_SU_PERIODIC_SOUNDING; + + kalMemCopy(&rCmdTxBfActionInfo, &rTxBfActionInfo, + sizeof(CMD_TXBF_ACTION_T)); + + rWlanStatus = wlanSendSetQueryExtCmd( + prAdapter, CMD_ID_LAYER_0_EXT_MAGIC_NUM, EXT_CMD_ID_BF_ACTION, + true, false, false, nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, sizeof(CMD_TXBF_ACTION_T), + (u8 *)&rCmdTxBfActionInfo, &rTxBfActionInfo, u4SetBufferLen); + + if (rWlanStatus == WLAN_STATUS_FAILURE) { + DBGLOG(RLM, ERROR, "Send BF sounding cmd fail\n"); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u8 rlmClientSupportsVhtETxBF(P_STA_RECORD_T prStaRec) +{ + u8 ucVhtCapSuBfeeCap; + + ucVhtCapSuBfeeCap = + (prStaRec->u4VhtCapInfo & VHT_CAP_INFO_SU_BEAMFORMEE_CAPABLE) >> + VHT_CAP_INFO_SU_BEAMFORMEE_CAPABLE_OFFSET; + + return (ucVhtCapSuBfeeCap) ? true : false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u8 rlmClientSupportsVhtBfeeStsCap(P_STA_RECORD_T prStaRec) +{ + u8 ucVhtCapBfeeStsCap; + + ucVhtCapBfeeStsCap = + (prStaRec->u4VhtCapInfo & + VHT_CAP_INFO_COMP_STEERING_NUM_OF_BFER_ANT_SUP) >> + VHT_CAP_INFO_COMP_STEERING_NUM_OF_BFER_ANT_SUP_OFFSET; + + return ucVhtCapBfeeStsCap; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u8 rlmClientSupportsHtETxBF(P_STA_RECORD_T prStaRec) +{ + u32 u4RxNDPCap, u4ComBfFbkCap; + + u4RxNDPCap = (prStaRec->u4TxBeamformingCap & TXBF_RX_NDP_CAPABLE) >> + TXBF_RX_NDP_CAPABLE_OFFSET; + /* Support compress feedback */ + u4ComBfFbkCap = (prStaRec->u4TxBeamformingCap & + TXBF_EXPLICIT_COMPRESSED_FEEDBACK_IMMEDIATE_CAPABLE) >> + TXBF_EXPLICIT_COMPRESSED_FEEDBACK_CAPABLE_OFFSET; + + return (u4RxNDPCap == 1) && (u4ComBfFbkCap > 0); +} +#endif + +#if CFG_SUPPORT_DBDC_TC6 +/*----------------------------------------------------------------------------*/ +/*! + * \brief Get BSS operating channel width by VHT and HT OP Info + * + * \param[in] + * + * \return ucBssOpBw 0:20MHz, 1:40MHz, 2:80MHz, 3:160MHz 4:80+80MHz + * + */ +/*----------------------------------------------------------------------------*/ +u8 rlmGetBssOpBwByVhtAndHtOpInfo(P_BSS_INFO_T prBssInfo) +{ + u8 ucBssOpBw = MAX_BW_20MHZ; + + ASSERT(prBssInfo); + + switch (prBssInfo->ucVhtChannelWidth) { + case VHT_OP_CHANNEL_WIDTH_80P80: + ucBssOpBw = MAX_BW_80_80_MHZ; + break; + + case VHT_OP_CHANNEL_WIDTH_160: + ucBssOpBw = MAX_BW_160MHZ; + break; + + case VHT_OP_CHANNEL_WIDTH_80: + ucBssOpBw = MAX_BW_80MHZ; + break; + + case VHT_OP_CHANNEL_WIDTH_20_40: + if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { + ucBssOpBw = MAX_BW_40MHZ; + } + break; + + default: + DBGLOG(RLM, WARN, "%s: unexpected VHT channel width: %d\n", + __func__, prBssInfo->ucVhtChannelWidth); +#if CFG_SUPPORT_802_11AC + if (RLM_NET_IS_11AC(prBssInfo)) { + /*VHT default should support BW 80*/ + ucBssOpBw = MAX_BW_80MHZ; + } +#endif + break; + } + + return ucBssOpBw; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return ucVhtOpBw 0:20M/40Hz, 1:80MHz, 2:160MHz, 3:80+80MHz + * + */ +/*----------------------------------------------------------------------------*/ +u8 rlmGetVhtOpBwByBssOpBw(u8 ucBssOpBw) +{ + u8 ucVhtOpBw = VHT_OP_CHANNEL_WIDTH_80; /*VHT default should support BW + * 80*/ + + switch (ucBssOpBw) { + case MAX_BW_20MHZ: + case MAX_BW_40MHZ: + ucVhtOpBw = VHT_OP_CHANNEL_WIDTH_20_40; + break; + + case MAX_BW_80MHZ: + ucVhtOpBw = VHT_OP_CHANNEL_WIDTH_80; + break; + + case MAX_BW_160MHZ: + ucVhtOpBw = VHT_OP_CHANNEL_WIDTH_160; + break; + + case MAX_BW_80_80_MHZ: + ucVhtOpBw = VHT_OP_CHANNEL_WIDTH_80P80; + break; + + default: + DBGLOG(RLM, WARN, "%s: unexpected Bss OP BW: %d\n", __func__, + ucBssOpBw); + break; + } + + return ucVhtOpBw; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rlm_domain.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rlm_domain.c new file mode 100644 index 00000000000000..6e12827eac4dfc --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rlm_domain.c @@ -0,0 +1,3384 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "rlm_domain.c" + * \brief + * + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +#include "rlm_txpwr_init.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/* The following country or domain shall be set from host driver. + * And host driver should pass specified DOMAIN_INFO_ENTRY to MT6620 as + * the channel list of being a STA to do scanning/searching AP or being an + * AP to choose an adequate channel if auto-channel is set. + */ + +/* Define mapping tables between country code and its channel set + */ +static const u16 g_u2CountryGroup0[] = { + COUNTRY_CODE_AO, COUNTRY_CODE_BZ, COUNTRY_CODE_BJ, COUNTRY_CODE_BT, + COUNTRY_CODE_BO, COUNTRY_CODE_BI, COUNTRY_CODE_CM, COUNTRY_CODE_CF, + COUNTRY_CODE_TD, COUNTRY_CODE_KM, COUNTRY_CODE_CD, COUNTRY_CODE_CG, + COUNTRY_CODE_CI, COUNTRY_CODE_DJ, COUNTRY_CODE_GQ, COUNTRY_CODE_ER, + COUNTRY_CODE_FJ, COUNTRY_CODE_GA, COUNTRY_CODE_GM, COUNTRY_CODE_GN, + COUNTRY_CODE_GW, COUNTRY_CODE_RKS, COUNTRY_CODE_KG, COUNTRY_CODE_LY, + COUNTRY_CODE_MG, COUNTRY_CODE_ML, COUNTRY_CODE_NR, COUNTRY_CODE_NC, + COUNTRY_CODE_ST, COUNTRY_CODE_SC, COUNTRY_CODE_SL, COUNTRY_CODE_SB, + COUNTRY_CODE_SO, COUNTRY_CODE_SR, COUNTRY_CODE_SZ, COUNTRY_CODE_TJ, + COUNTRY_CODE_TG, COUNTRY_CODE_TO, COUNTRY_CODE_TM, COUNTRY_CODE_TV, + COUNTRY_CODE_VU, COUNTRY_CODE_YE +}; + +static const u16 g_u2CountryGroup1[] = { + COUNTRY_CODE_AS, COUNTRY_CODE_AI, COUNTRY_CODE_BM, COUNTRY_CODE_CA, + COUNTRY_CODE_KY, COUNTRY_CODE_GU, COUNTRY_CODE_FM, COUNTRY_CODE_PR, + COUNTRY_CODE_US, COUNTRY_CODE_VI, +}; + +static const u16 g_u2CountryGroup2[] = { + COUNTRY_CODE_AR, COUNTRY_CODE_AU, COUNTRY_CODE_AZ, COUNTRY_CODE_BW, + COUNTRY_CODE_KH, COUNTRY_CODE_CX, COUNTRY_CODE_CO, COUNTRY_CODE_CR, + COUNTRY_CODE_EC, COUNTRY_CODE_GD, COUNTRY_CODE_GT, COUNTRY_CODE_HK, + COUNTRY_CODE_KI, COUNTRY_CODE_LB, COUNTRY_CODE_LR, COUNTRY_CODE_MN, + COUNTRY_CODE_AN, COUNTRY_CODE_NZ, COUNTRY_CODE_NI, COUNTRY_CODE_PW, + COUNTRY_CODE_PY, COUNTRY_CODE_PE, COUNTRY_CODE_PH, COUNTRY_CODE_WS, + COUNTRY_CODE_SG, COUNTRY_CODE_LK, COUNTRY_CODE_TH, COUNTRY_CODE_TT, + COUNTRY_CODE_UY, COUNTRY_CODE_VN +}; + +static const u16 g_u2CountryGroup3[] = { COUNTRY_CODE_AW, COUNTRY_CODE_LA, + COUNTRY_CODE_SA, COUNTRY_CODE_AE, + COUNTRY_CODE_UG }; + +static const u16 g_u2CountryGroup4[] = { COUNTRY_CODE_MM }; + +static const u16 g_u2CountryGroup5[] = { + COUNTRY_CODE_AL, COUNTRY_CODE_DZ, COUNTRY_CODE_AD, COUNTRY_CODE_AT, + COUNTRY_CODE_BY, COUNTRY_CODE_BE, COUNTRY_CODE_BA, COUNTRY_CODE_VG, + COUNTRY_CODE_BG, COUNTRY_CODE_CV, COUNTRY_CODE_HR, COUNTRY_CODE_CY, + COUNTRY_CODE_CZ, COUNTRY_CODE_DK, COUNTRY_CODE_EE, COUNTRY_CODE_ET, + COUNTRY_CODE_FI, COUNTRY_CODE_FR, COUNTRY_CODE_GF, COUNTRY_CODE_PF, + COUNTRY_CODE_TF, COUNTRY_CODE_GE, COUNTRY_CODE_DE, COUNTRY_CODE_GH, + COUNTRY_CODE_GR, COUNTRY_CODE_GP, COUNTRY_CODE_HU, COUNTRY_CODE_IS, + COUNTRY_CODE_IQ, COUNTRY_CODE_IE, COUNTRY_CODE_IT, COUNTRY_CODE_KE, + COUNTRY_CODE_LV, COUNTRY_CODE_LS, COUNTRY_CODE_LI, COUNTRY_CODE_LT, + COUNTRY_CODE_LU, COUNTRY_CODE_MK, COUNTRY_CODE_MT, COUNTRY_CODE_MQ, + COUNTRY_CODE_MR, COUNTRY_CODE_MU, COUNTRY_CODE_YT, COUNTRY_CODE_MD, + COUNTRY_CODE_MC, COUNTRY_CODE_ME, COUNTRY_CODE_MS, COUNTRY_CODE_NL, + COUNTRY_CODE_NO, COUNTRY_CODE_OM, COUNTRY_CODE_PL, COUNTRY_CODE_PT, + COUNTRY_CODE_RE, COUNTRY_CODE_RO, COUNTRY_CODE_MF, COUNTRY_CODE_SM, + COUNTRY_CODE_SN, COUNTRY_CODE_RS, COUNTRY_CODE_SK, COUNTRY_CODE_SI, + COUNTRY_CODE_ZA, COUNTRY_CODE_ES, COUNTRY_CODE_SE, COUNTRY_CODE_CH, + COUNTRY_CODE_TR, COUNTRY_CODE_TC, COUNTRY_CODE_GB, COUNTRY_CODE_VA, + COUNTRY_CODE_EU +}; +static const u16 g_u2CountryGroup6[] = { COUNTRY_CODE_JP }; + +static const u16 g_u2CountryGroup7[] = { + COUNTRY_CODE_AM, COUNTRY_CODE_IL, COUNTRY_CODE_KW, + COUNTRY_CODE_MA, COUNTRY_CODE_NE, COUNTRY_CODE_TN, +}; +static const u16 g_u2CountryGroup8[] = { COUNTRY_CODE_NP }; +static const u16 g_u2CountryGroup9[] = { COUNTRY_CODE_AF }; + +static const u16 g_u2CountryGroup10[] = { + COUNTRY_CODE_AG, COUNTRY_CODE_BS, COUNTRY_CODE_BH, COUNTRY_CODE_BB, + COUNTRY_CODE_BN, COUNTRY_CODE_CL, COUNTRY_CODE_CN, COUNTRY_CODE_EG, + COUNTRY_CODE_SV, COUNTRY_CODE_IN, COUNTRY_CODE_MY, COUNTRY_CODE_MV, + COUNTRY_CODE_PA, COUNTRY_CODE_VE, COUNTRY_CODE_ZM, +}; +static const u16 g_u2CountryGroup11[] = { COUNTRY_CODE_JO, COUNTRY_CODE_PG }; + +static const u16 g_u2CountryGroup12[] = { + COUNTRY_CODE_BF, COUNTRY_CODE_GY, COUNTRY_CODE_HT, COUNTRY_CODE_HN, + COUNTRY_CODE_JM, COUNTRY_CODE_MO, COUNTRY_CODE_MW, COUNTRY_CODE_PK, + COUNTRY_CODE_QA, COUNTRY_CODE_RW, COUNTRY_CODE_KN, COUNTRY_CODE_TZ, +}; +static const u16 g_u2CountryGroup13[] = { COUNTRY_CODE_ID }; +static const u16 g_u2CountryGroup14[] = { COUNTRY_CODE_KR }; +static const u16 g_u2CountryGroup15[] = { COUNTRY_CODE_NG }; + +static const u16 g_u2CountryGroup16[] = { + COUNTRY_CODE_BD, COUNTRY_CODE_BR, COUNTRY_CODE_DM, COUNTRY_CODE_DO, + COUNTRY_CODE_FK, COUNTRY_CODE_KZ, COUNTRY_CODE_MX, COUNTRY_CODE_MZ, + COUNTRY_CODE_NA, COUNTRY_CODE_RU, COUNTRY_CODE_LC, COUNTRY_CODE_VC, + COUNTRY_CODE_UA, COUNTRY_CODE_UZ, COUNTRY_CODE_ZW +}; +static const u16 g_u2CountryGroup17[] = { COUNTRY_CODE_MP }; +static const u16 g_u2CountryGroup18[] = { COUNTRY_CODE_TW }; + +static const u16 g_u2CountryGroup19[] = { + COUNTRY_CODE_CK, COUNTRY_CODE_CU, COUNTRY_CODE_TL, COUNTRY_CODE_FO, + COUNTRY_CODE_GI, COUNTRY_CODE_GG, COUNTRY_CODE_IR, COUNTRY_CODE_IM, + COUNTRY_CODE_JE, COUNTRY_CODE_KP, COUNTRY_CODE_MH, COUNTRY_CODE_NU, + COUNTRY_CODE_NF, COUNTRY_CODE_PS, COUNTRY_CODE_PN, COUNTRY_CODE_PM, + COUNTRY_CODE_SS, COUNTRY_CODE_SD, COUNTRY_CODE_SY +}; + +static const u16 g_u2CountryGroup20[] = { + COUNTRY_CODE_DF + /* When country code is not found, this domain info will be used. + * So mark all country codes to reduce search time. 20110908 + */ +}; + +#define TX_PWR_LIMIT_FILE_NAME_LENGTH (50) +static const char *g_tx_pwr_limit_file = WLAN_TX_PWR_LIMIT_FILE_NAME; + +#if (CFG_SUPPORT_SINGLE_SKU == 1) +mtk_regd_control g_mtk_regd_control = { .en = false, + .state = REGD_STATE_UNDEFINED }; + +#if (CFG_SUPPORT_SINGLE_SKU_LOCAL_DB == 1) +const struct ieee80211_regdomain + default_regdom_ww = { .n_reg_rules = 4, + .alpha2 = "99", + .reg_rules = { + /* channels 1..13 */ + REG_RULE_LIGHT(2412 - 10, 2472 + 10, 40, 0), + /* channels 14 */ + REG_RULE_LIGHT(2484 - 10, 2484 + 10, 20, 0), + /* channel 36..64 */ + REG_RULE_LIGHT(5150 - 10, 5350 + 10, 80, 0), + /* channel 100..165 */ + REG_RULE_LIGHT(5470 - 10, 5850 + 10, 80, 0), + } }; +#endif + +const char *gTx_Pwr_Limit_Section[TX_PWR_LIMIT_SECTION_NUM] = { + "legacy", "ht20", "ht40", "vht20", "offset" +}; + +const u8 gTx_Pwr_Limit_Element_Num[TX_PWR_LIMIT_SECTION_NUM] = { 7, 6, 7, 7, + 5 }; + +const char * + gTx_Pwr_Limit_Element[TX_PWR_LIMIT_SECTION_NUM][TX_PWR_LIMIT_ELEMENT_NUM] = +{ + { "cck1_2", "cck_5_11", "ofdm6_9", "ofdm12_18", "ofdm24_36", "ofdm48", + "ofdm54" }, + { "mcs0_8", "mcs1_2_9_10", "mcs3_4_11_12", "mcs5_13", "mcs6_14", + "mcs7_15" }, + { "mcs0_8", "mcs1_2_9_10", "mcs3_4_11_12", "mcs5_13", "mcs6_14", + "mcs7_15", "mcs32" }, + { "mcs0", "mcs1_2", "mcs3_4", "mcs5_6", "mcs7", "mcs8", "mcs9" }, + { "lg40", "lg80", "vht40", "vht80", "vht160nc" } +}; + +static const s8 gTx_Pwr_Limit_2g_Ch[] = { 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14 }; +static const s8 gTx_Pwr_Limit_5g_Ch[] = { + 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, + 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, + 132, 134, 136, 138, 140, 142, 144, 149, 151, 153, 155, 157, 159, 161, 165 +}; + +#define TX_PWR_LIMIT_2G_CH_NUM (ARRAY_SIZE(gTx_Pwr_Limit_2g_Ch)) +#define TX_PWR_LIMIT_5G_CH_NUM (ARRAY_SIZE(gTx_Pwr_Limit_5g_Ch)) + +#endif + +DOMAIN_INFO_ENTRY arSupportedRegDomains[] = { + { (u16 *)g_u2CountryGroup0, + sizeof(g_u2CountryGroup0) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 + */ + + { 115, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_LOW_NA + */ + { 118, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_MID_NA + */ + { 121, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_WW_NA + */ + { 125, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_UPPER_NA + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup1, + sizeof(g_u2CountryGroup1) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 11, false }, /* CH_SET_2G4_1_11 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, true }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 12, true }, /* CH_SET_UNII_WW_100_144 + */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, + false }, /* CH_SET_UNII_UPPER_149_165 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup2, + sizeof(g_u2CountryGroup2) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, true }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 12, true }, /* CH_SET_UNII_WW_100_144 + */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, + false }, /* CH_SET_UNII_UPPER_149_165 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup3, + sizeof(g_u2CountryGroup3) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, true }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 12, true }, /* CH_SET_UNII_WW_100_144 + */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 4, + false }, /* CH_SET_UNII_UPPER_149_161 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup4, + sizeof(g_u2CountryGroup4) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, true }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 12, true }, /* CH_SET_UNII_WW_100_144 + */ + { 125, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_UPPER_NA */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup5, + sizeof(g_u2CountryGroup5) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, true }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, true }, /* CH_SET_UNII_WW_100_140 + */ + { 125, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_UPPER_NA */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup6, + sizeof(g_u2CountryGroup6) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 + */ + { 82, BAND_2G4, CHNL_SPAN_5, 14, 1, false }, /* CH_SET_2G4_14_14 + */ + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, true }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, + true }, /* CH_SET_UNII_WW_100_140 + */ + { 125, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_UPPER_NA */ + } }, + { (u16 *)g_u2CountryGroup7, + sizeof(g_u2CountryGroup7) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, true }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_WW_NA */ + { 125, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_UPPER_NA */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup8, + sizeof(g_u2CountryGroup8) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, true }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_WW_NA */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 4, + false }, /* CH_SET_UNII_UPPER_149_161 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup9, + sizeof(g_u2CountryGroup9) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_MID_NA */ + { 121, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_WW_NA */ + { 125, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_UPPER_NA */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup10, + sizeof(g_u2CountryGroup10) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, true }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_WW_NA */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, + false }, /* CH_SET_UNII_UPPER_149_165 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup11, + sizeof(g_u2CountryGroup11) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_MID_NA */ + { 121, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_WW_NA */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, + false }, /* CH_SET_UNII_UPPER_149_165 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup12, + sizeof(g_u2CountryGroup12) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_LOW_NA */ + { 118, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_MID_NA */ + { 121, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_WW_NA */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, + false }, /* CH_SET_UNII_UPPER_149_165 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup13, + sizeof(g_u2CountryGroup13) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_LOW_NA */ + { 118, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_MID_NA */ + { 121, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_WW_NA */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 4, + false }, /* CH_SET_UNII_UPPER_149_161 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup14, + sizeof(g_u2CountryGroup14) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, false }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 8, false }, /* CH_SET_UNII_WW_100_128 + */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 4, + false }, /* CH_SET_UNII_UPPER_149_161 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup15, + sizeof(g_u2CountryGroup15) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_NULL, 0, 0, 0, false }, /* CH_SET_UNII_LOW_36_48 */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, true }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, true }, /* CH_SET_UNII_WW_100_140 + */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, + false }, /* CH_SET_UNII_UPPER_149_165 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup16, + sizeof(g_u2CountryGroup16) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, false }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, true }, /* CH_SET_UNII_WW_100_140 + */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, + false }, /* CH_SET_UNII_UPPER_149_165 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup17, + sizeof(g_u2CountryGroup17) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 11, false }, /* CH_SET_2G4_1_11 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, true }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, true }, /* CH_SET_UNII_WW_100_140 + */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, + false }, /* CH_SET_UNII_UPPER_149_165 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup18, + sizeof(g_u2CountryGroup18) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 11, false }, /* CH_SET_2G4_1_11 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, false }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, false }, /* CH_SET_UNII_WW_100_140 + */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, + false }, /* CH_SET_UNII_UPPER_149_165 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { (u16 *)g_u2CountryGroup19, + sizeof(g_u2CountryGroup19) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, true }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 12, true }, /* CH_SET_UNII_WW_100_144 + */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 5, + false }, /* CH_SET_UNII_UPPER_149_165 + */ + { 0, BAND_NULL, 0, 0, 0, false } } }, + { /* Note: The final one is for Europe union now.(Default group if no + * matched country code) */ + (u16 *)g_u2CountryGroup20, + sizeof(g_u2CountryGroup20) / 2, + { { 81, BAND_2G4, CHNL_SPAN_5, 1, 13, false }, /* CH_SET_2G4_1_13 */ + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, false }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, true }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 12, true }, /* CH_SET_UNII_WW_100_144 + */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 7, + false }, /* CH_SET_UNII_UPPER_149_173 + */ + { 0, BAND_NULL, 0, 0, 0, false } } + } +}; + +#define REG_DOMAIN_PASSIVE_DEF_IDX 1 + +static const u16 g_u2CountryGroup0_Passive[] = { COUNTRY_CODE_TW }; + +DOMAIN_INFO_ENTRY arSupportedRegDomains_Passive[] = { + { (u16 *)g_u2CountryGroup0_Passive, + sizeof(g_u2CountryGroup0_Passive) / 2, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 0, 0 }, /* CH_SET_2G4_1_14_NA + */ + { 82, BAND_2G4, CHNL_SPAN_5, 14, 0, 0 }, + + { 115, BAND_5G, CHNL_SPAN_20, 36, 4, 0 }, /* CH_SET_UNII_LOW_36_48 + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, 0 }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 11, 0 }, /* CH_SET_UNII_WW_100_140 + */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 0, 0 }, /* CH_SET_UNII_UPPER_NA + */ + } }, + + { /* default passive channel table is empty */ + COUNTRY_CODE_NULL, + 0, + { + { 81, BAND_2G4, CHNL_SPAN_5, 1, 0, 0 }, /* CH_SET_2G4_1_14_NA + */ + { 82, BAND_2G4, CHNL_SPAN_5, 14, 0, 0 }, + + { 115, BAND_5G, CHNL_SPAN_20, 36, 0, 0 }, /* CH_SET_UNII_LOW_NA + */ + { 118, BAND_5G, CHNL_SPAN_20, 52, 4, 0 }, /* CH_SET_UNII_MID_52_64 + */ + { 121, BAND_5G, CHNL_SPAN_20, 100, 12, 0 }, /* CH_SET_UNII_WW_100_144 + */ + { 125, BAND_5G, CHNL_SPAN_20, 149, 0, 0 }, /* CH_SET_UNII_UPPER_NA + */ + } + } +}; + +#define REG_DOMAIN_PASSIVE_GROUP_NUM \ + (sizeof(arSupportedRegDomains_Passive) / sizeof(DOMAIN_INFO_ENTRY)) + +SUBBAND_CHANNEL_T g_rRlmSubBand[] = { + { BAND_2G4_LOWER_BOUND, BAND_2G4_UPPER_BOUND, 1, 0 }, /* 2.4G */ + { UNII1_LOWER_BOUND, UNII1_UPPER_BOUND, 2, 0 }, /* ch36,38,40,..,48 */ + { UNII2A_LOWER_BOUND, UNII2A_UPPER_BOUND, 2, 0 }, /* ch52,54,56,..,64 */ + { UNII2C_LOWER_BOUND, UNII2C_UPPER_BOUND, 2, 0 }, /* ch100,102,104,...,144 + */ + { UNII3_LOWER_BOUND, UNII3_UPPER_BOUND, 2, 0 } /* ch149,151,153,....,173 + */ +}; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in/out] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +P_DOMAIN_INFO_ENTRY rlmDomainGetDomainInfo(P_ADAPTER_T prAdapter) +{ +#define REG_DOMAIN_DEF_IDX 20 /* EU (Europe Union) */ +#define REG_DOMAIN_GROUP_NUM \ + (sizeof(arSupportedRegDomains) / sizeof(DOMAIN_INFO_ENTRY)) + + P_DOMAIN_INFO_ENTRY prDomainInfo; + P_REG_INFO_T prRegInfo; + u16 u2TargetCountryCode; + u16 i, j; + + ASSERT(prAdapter); + + if (prAdapter->prDomainInfo) { + return prAdapter->prDomainInfo; + } + + prRegInfo = &prAdapter->prGlueInfo->rRegInfo; + + DBGLOG(RLM, TRACE, "eRegChannelListMap=%d, u2CountryCode=0x%04x\n", + prRegInfo->eRegChannelListMap, + prAdapter->rWifiVar.rConnSettings.u2CountryCode); + + /* + * Domain info can be specified by given idx of arSupportedRegDomains + * table, customized, or searched by country code, only one is set among + * these three methods in NVRAM. + */ + if (prRegInfo->eRegChannelListMap == REG_CH_MAP_TBL_IDX && + prRegInfo->ucRegChannelListIndex < REG_DOMAIN_GROUP_NUM) { + /* by given table idx */ + DBGLOG(RLM, TRACE, "ucRegChannelListIndex=%d\n", + prRegInfo->ucRegChannelListIndex); + prDomainInfo = &arSupportedRegDomains[prRegInfo->ucRegChannelListIndex]; + } else if (prRegInfo->eRegChannelListMap == REG_CH_MAP_CUSTOMIZED) { + /* by customized */ + prDomainInfo = &prRegInfo->rDomainInfo; + } else { + /* by country code */ + u2TargetCountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; + + for (i = 0; i < REG_DOMAIN_GROUP_NUM; i++) { + prDomainInfo = &arSupportedRegDomains[i]; + + if ((prDomainInfo->u4CountryNum && prDomainInfo->pu2CountryGroup) || + prDomainInfo->u4CountryNum == 0) { + for (j = 0; j < prDomainInfo->u4CountryNum; j++) { + if (prDomainInfo->pu2CountryGroup[j] == + u2TargetCountryCode) { + break; + } + } + if (j < prDomainInfo->u4CountryNum) { + break; /* Found */ + } + } + } + + /* If no matched country code, use the default regulatory domain + */ + if (i >= REG_DOMAIN_GROUP_NUM) { + DBGLOG( + RLM, INFO, + "No matched country code, use the default regulatory domain\n"); + prDomainInfo = &arSupportedRegDomains[REG_DOMAIN_DEF_IDX]; + } + } + + prAdapter->prDomainInfo = prDomainInfo; + return prDomainInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in/out] The input variable pointed by pucNumOfChannel is the max + * arrary size. The return value indciates meaning list size. + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmDomainGetChnlList_V2(P_ADAPTER_T prAdapter, ENUM_BAND_T eSpecificBand, + u8 fgNoDfs, u8 ucMaxChannelNum, + u8 *pucNumOfChannel, + P_RF_CHANNEL_INFO_T paucChannelList) +{ +#if (CFG_SUPPORT_SINGLE_SKU == 1) + ENUM_BAND_T band; + u8 max_count, i, ucNum; + struct channel *prCh; + + if (eSpecificBand == BAND_2G4) { + i = 0; + max_count = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ); + } else if (eSpecificBand == BAND_5G) { + i = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ); + max_count = rlmDomainGetActiveChannelCount(NL80211_BAND_5GHZ) + + rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ); + } else { + i = 0; + max_count = rlmDomainGetActiveChannelCount(NL80211_BAND_5GHZ) + + rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ); + } + + ucNum = 0; + for (; i < max_count; i++) { + prCh = rlmDomainGetActiveChannels() + i; + if (fgNoDfs && (prCh->flags & IEEE80211_CHAN_RADAR)) { + continue; /*not match*/ + } + if (i < rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ)) { + band = BAND_2G4; + } else { + band = BAND_5G; + } + + paucChannelList[ucNum].eBand = band; + paucChannelList[ucNum].ucChannelNum = prCh->chNum; + + ucNum++; + if (ucMaxChannelNum == ucNum) { + break; + } + } + + *pucNumOfChannel = ucNum; +#else + *pucNumOfChannel = 0; +#endif +} + +void rlmDomainGetChnlList(P_ADAPTER_T prAdapter, ENUM_BAND_T eSpecificBand, + u8 fgNoDfs, u8 ucMaxChannelNum, u8 *pucNumOfChannel, + P_RF_CHANNEL_INFO_T paucChannelList) +{ + u8 i, j, ucNum; + P_DOMAIN_SUBBAND_INFO prSubband; + P_DOMAIN_INFO_ENTRY prDomainInfo; + + ASSERT(prAdapter); + ASSERT(paucChannelList); + ASSERT(pucNumOfChannel); + + if (regd_is_single_sku_en()) { + return rlmDomainGetChnlList_V2(prAdapter, eSpecificBand, fgNoDfs, + ucMaxChannelNum, pucNumOfChannel, + paucChannelList); + } + + /* If no matched country code, the final one will be used */ + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + ucNum = 0; + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubband = &prDomainInfo->rSubBand[i]; + + if (prSubband->ucBand == BAND_NULL || prSubband->ucBand >= BAND_NUM || + (prSubband->ucBand == BAND_5G && !prAdapter->fgEnable5GBand)) { + continue; + } + + /*repoert to upper layer only non-DFS channel for ap mode + * usage*/ + if (fgNoDfs == true && prSubband->fgDfs == true) { + continue; + } + + if (eSpecificBand == BAND_NULL || prSubband->ucBand == eSpecificBand) { + for (j = 0; j < prSubband->ucNumChannels; j++) { + if (ucNum >= ucMaxChannelNum) { + break; + } + paucChannelList[ucNum].eBand = prSubband->ucBand; + paucChannelList[ucNum].ucChannelNum = + prSubband->ucFirstChannelNum + j * prSubband->ucChannelSpan; + ucNum++; + } + } + } + + *pucNumOfChannel = ucNum; +} + +#ifdef CFG_SUPPORT_SAP_DFS_CHANNEL +/*----------------------------------------------------------------------------*/ +/*! + * \brief Retrieve DFS channels from 5G band + * + * \param[in/out] ucMaxChannelNum: max array size + * pucNumOfChannel: pointer to returned channel number + * paucChannelList: pointer to returned channel list array + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmDomainGetDfsChnls(P_ADAPTER_T prAdapter, u8 ucMaxChannelNum, + u8 *pucNumOfChannel, + P_RF_CHANNEL_INFO_T paucChannelList) +{ + u8 i, j, ucNum; + P_DOMAIN_SUBBAND_INFO prSubband; + P_DOMAIN_INFO_ENTRY prDomainInfo; + + ASSERT(prAdapter); + ASSERT(paucChannelList); + ASSERT(pucNumOfChannel); + + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + ucNum = 0; + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubband = &prDomainInfo->rSubBand[i]; + + if (prSubband->ucBand == BAND_5G) { + if (!prAdapter->fgEnable5GBand) { + continue; + } + + if (prSubband->fgDfs == true) { + for (j = 0; j < prSubband->ucNumChannels; j++) { + if (ucNum >= ucMaxChannelNum) { + break; + } + paucChannelList[ucNum].eBand = prSubband->ucBand; + paucChannelList[ucNum].ucChannelNum = + prSubband->ucFirstChannelNum + + j * prSubband->ucChannelSpan; + ucNum++; + } + } + } + } + + *pucNumOfChannel = ucNum; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param[in] + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void rlmDomainSendCmd(P_ADAPTER_T prAdapter, u8 fgIsOid) +{ + if (!regd_is_single_sku_en()) { + rlmDomainSendPassiveScanInfoCmd(prAdapter, fgIsOid); + } + rlmDomainSendDomainInfoCmd(prAdapter, fgIsOid); +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + rlmDomainSendPwrLimitCmd(prAdapter); +#endif +} + +static u8 isEUCountry(P_ADAPTER_T prAdapter, u32 u4CountryCode) +{ + u16 i; + u16 u2TargetCountryCode = 0; + + ASSERT(prAdapter); + + u2TargetCountryCode = ((u4CountryCode & 0xff) << 8) | + ((u4CountryCode & 0xff00) >> 8); + DBGLOG(RLM, INFO, " Target country code=0x%4x\n", u2TargetCountryCode); + for (i = 0; i < (sizeof(g_u2CountryGroup5) / sizeof(u16)); i++) { + if (g_u2CountryGroup5[i] == u2TargetCountryCode) { + return true; + } + } + return false; +} + +static void rlmSetEd_EU(P_ADAPTER_T prAdapter, u32 u4CountryCode) +{ + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; + + if (isEUCountry(prAdapter, u4CountryCode)) { + if ((prWifiVar->ucEd2GEU != 0) && (prWifiVar->ucEd5GEU != 0)) { + wlanSetEd(prAdapter, prWifiVar->ucEd2GEU, prWifiVar->ucEd5GEU, 1); + DBGLOG(RLM, INFO, "Ed 2G for EU=%d, Ed 5G for EU=%d\n", + prWifiVar->ucEd2GEU, prWifiVar->ucEd5GEU); + } + } else { + if ((prWifiVar->ucEd2GNonEU != 0) && (prWifiVar->ucEd5GNonEU != 0)) { + wlanSetEd(prAdapter, prWifiVar->ucEd2GNonEU, prWifiVar->ucEd5GNonEU, 1); + DBGLOG(RLM, INFO, "Ed 2G for non EU=%d, Ed 5G for non EU=%d\n", + prWifiVar->ucEd2GNonEU, prWifiVar->ucEd5GNonEU); + } + } +} + +void rlmDomainSendDomainInfoCmd_V2(P_ADAPTER_T prAdapter, u8 fgIsOid) +{ +#if (CFG_SUPPORT_SINGLE_SKU == 1) + u8 max_channel_count = 0; + u32 buff_max_size, buff_valid_size; + P_CMD_SET_DOMAIN_INFO_V2_T prCmd; + struct acctive_channel_list *prChs; + struct wiphy *pWiphy; + + pWiphy = priv_to_wiphy(prAdapter->prGlueInfo); + if (pWiphy->bands[NL80211_BAND_2GHZ] != NULL) { + max_channel_count += pWiphy->bands[NL80211_BAND_2GHZ]->n_channels; + } + if (pWiphy->bands[NL80211_BAND_5GHZ] != NULL) { + max_channel_count += pWiphy->bands[NL80211_BAND_5GHZ]->n_channels; + } + + if (max_channel_count == 0) { + DBGLOG(RLM, ERROR, "%s, invalid channel count.\n", __func__); + ASSERT(0); + } + + buff_max_size = sizeof(CMD_SET_DOMAIN_INFO_V2_T) + + max_channel_count * sizeof(struct channel); + + prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, buff_max_size); + ASSERT(prCmd); + if (!prCmd) { + DBGLOG(RLM, ERROR, "Allocate prCmd ==> FAILED.\n"); + return; + } + + kalMemZero(prCmd, buff_max_size); + prChs = &(prCmd->active_chs); + + /* + * Fill in the active channels + */ + rlmExtractChannelInfo(max_channel_count, prChs); + + prCmd->u4CountryCode = rlmDomainGetCountryCode(); + prCmd->uc2G4Bandwidth = + prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode; + prCmd->uc5GBandwidth = prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode; + prCmd->aucReserved[0] = 0; + prCmd->aucReserved[1] = 0; + + buff_valid_size = + sizeof(CMD_SET_DOMAIN_INFO_V2_T) + + (prChs->n_channels_2g + prChs->n_channels_5g) * sizeof(struct channel); + + DBGLOG(RLM, INFO, + "rlmDomainSendDomainInfoCmd_V2(), buff_valid_size = 0x%x\n", + buff_valid_size); + + /* Set domain info to chip */ + wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SET_DOMAIN_INFO, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + fgIsOid, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + buff_valid_size, (u8 *)prCmd, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + rlmSetEd_EU(prAdapter, prCmd->u4CountryCode); + + cnmMemFree(prAdapter, prCmd); +#endif +} + +void rlmDomainSendDomainInfoCmd(P_ADAPTER_T prAdapter, u8 fgIsOid) +{ + P_DOMAIN_INFO_ENTRY prDomainInfo; + P_CMD_SET_DOMAIN_INFO_T prCmd; + P_DOMAIN_SUBBAND_INFO prSubBand; + u8 i; + + if (regd_is_single_sku_en()) { + return rlmDomainSendDomainInfoCmd_V2(prAdapter, fgIsOid); + } + + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_DOMAIN_INFO_T)); + if (!prCmd) { + DBGLOG(RLM, ERROR, "Alloc cmd buffer failed\n"); + return; + } + kalMemZero(prCmd, sizeof(CMD_SET_DOMAIN_INFO_T)); + + prCmd->u2CountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; + prCmd->u2IsSetPassiveScan = 0; + prCmd->uc2G4Bandwidth = + prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode; + prCmd->uc5GBandwidth = prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode; + prCmd->aucReserved[0] = 0; + prCmd->aucReserved[1] = 0; + + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubBand = &prDomainInfo->rSubBand[i]; + + prCmd->rSubBand[i].ucRegClass = prSubBand->ucRegClass; + prCmd->rSubBand[i].ucBand = prSubBand->ucBand; + + if (prSubBand->ucBand != BAND_NULL && prSubBand->ucBand < BAND_NUM) { + prCmd->rSubBand[i].ucChannelSpan = prSubBand->ucChannelSpan; + prCmd->rSubBand[i].ucFirstChannelNum = prSubBand->ucFirstChannelNum; + prCmd->rSubBand[i].ucNumChannels = prSubBand->ucNumChannels; + } + } + + /* Set domain info to chip */ + wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SET_DOMAIN_INFO, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + fgIsOid, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_SET_DOMAIN_INFO_T), /* u4SetQueryInfoLen + */ + (u8 *)prCmd, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + rlmSetEd_EU(prAdapter, prCmd->u2CountryCode); + + cnmMemFree(prAdapter, prCmd); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param[in] + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void rlmDomainSendPassiveScanInfoCmd(P_ADAPTER_T prAdapter, u8 fgIsOid) +{ + P_DOMAIN_INFO_ENTRY prDomainInfo; + P_CMD_SET_DOMAIN_INFO_T prCmd; + WLAN_STATUS rStatus; + P_DOMAIN_SUBBAND_INFO prSubBand; + u16 u2TargetCountryCode; + u8 i, j; + + prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, sizeof(CMD_SET_DOMAIN_INFO_T)); + if (!prCmd) { + DBGLOG(RLM, ERROR, "Alloc cmd buffer failed\n"); + return; + } + kalMemZero(prCmd, sizeof(CMD_SET_DOMAIN_INFO_T)); + + prCmd->u2CountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; + prCmd->u2IsSetPassiveScan = 1; + prCmd->uc2G4Bandwidth = + prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode; + prCmd->uc5GBandwidth = prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode; + prCmd->aucReserved[0] = 0; + prCmd->aucReserved[1] = 0; + + DBGLOG(RLM, TRACE, "u2CountryCode=0x%04x\n", + prAdapter->rWifiVar.rConnSettings.u2CountryCode); + + u2TargetCountryCode = prAdapter->rWifiVar.rConnSettings.u2CountryCode; + + for (i = 0; i < REG_DOMAIN_PASSIVE_GROUP_NUM; i++) { + prDomainInfo = &arSupportedRegDomains_Passive[i]; + + for (j = 0; j < prDomainInfo->u4CountryNum; j++) { + if (prDomainInfo->pu2CountryGroup[j] == u2TargetCountryCode) { + break; + } + } + if (j < prDomainInfo->u4CountryNum) { + break; /* Found */ + } + } + + if (i >= REG_DOMAIN_PASSIVE_GROUP_NUM) { + prDomainInfo = + &arSupportedRegDomains_Passive[REG_DOMAIN_PASSIVE_DEF_IDX]; + } + + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubBand = &prDomainInfo->rSubBand[i]; + + prCmd->rSubBand[i].ucRegClass = prSubBand->ucRegClass; + prCmd->rSubBand[i].ucBand = prSubBand->ucBand; + + if (prSubBand->ucBand != BAND_NULL && prSubBand->ucBand < BAND_NUM) { + prCmd->rSubBand[i].ucChannelSpan = prSubBand->ucChannelSpan; + prCmd->rSubBand[i].ucFirstChannelNum = prSubBand->ucFirstChannelNum; + prCmd->rSubBand[i].ucNumChannels = prSubBand->ucNumChannels; + } + } + + /* Set passive scan channel info to chip */ + rStatus = + wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SET_DOMAIN_INFO, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + fgIsOid, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_SET_DOMAIN_INFO_T), /* u4SetQueryInfoLen + */ + (u8 *)prCmd, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); + + rlmSetEd_EU(prAdapter, prCmd->u2CountryCode); + + cnmMemFree(prAdapter, prCmd); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in/out] + * + * \return true Legal channel + * false Illegal channel for current regulatory domain + */ +/*----------------------------------------------------------------------------*/ +u8 rlmDomainIsLegalChannel_V2(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, + u8 ucChannel) +{ +#if (CFG_SUPPORT_SINGLE_SKU == 1) + u8 idx, start_idx, end_idx; + struct channel *prCh; + + if (eBand == BAND_2G4) { + start_idx = 0; + end_idx = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ); + } else { + start_idx = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ); + end_idx = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ) + + rlmDomainGetActiveChannelCount(NL80211_BAND_5GHZ); + } + + for (idx = start_idx; idx < end_idx; idx++) { + prCh = rlmDomainGetActiveChannels() + idx; + + if (prCh->chNum == ucChannel) { + return true; + } + } + + return false; + +#else + return false; + +#endif +} +#ifdef CFG_SUPPORT_SAP_DFS_CHANNEL +u8 rlmDomainIsLegalDfsChannel(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, + u8 ucChannel) +{ + u8 i, j; + P_DOMAIN_SUBBAND_INFO prSubband; + P_DOMAIN_INFO_ENTRY prDomainInfo; + + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubband = &prDomainInfo->rSubBand[i]; + + if (prSubband->ucBand == BAND_5G && !prAdapter->fgEnable5GBand) { + continue; + } + + if (prSubband->ucBand == eBand && prSubband->fgDfs == true) { + for (j = 0; j < prSubband->ucNumChannels; j++) { + if ((prSubband->ucFirstChannelNum + + j * prSubband->ucChannelSpan) == ucChannel) { + return true; + } + } + } + } + + return false; +} +#endif +u8 rlmDomainIsLegalChannel(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, + u8 ucChannel) +{ + u8 i, j; + P_DOMAIN_SUBBAND_INFO prSubband; + P_DOMAIN_INFO_ENTRY prDomainInfo; + + if (regd_is_single_sku_en()) { + return rlmDomainIsLegalChannel_V2(prAdapter, eBand, ucChannel); + } + + prDomainInfo = rlmDomainGetDomainInfo(prAdapter); + ASSERT(prDomainInfo); + + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + prSubband = &prDomainInfo->rSubBand[i]; + + if (prSubband->ucBand == BAND_5G && !prAdapter->fgEnable5GBand) { + continue; + } + + if (prSubband->ucBand == eBand) { + for (j = 0; j < prSubband->ucNumChannels; j++) { + if ((prSubband->ucFirstChannelNum + + j * prSubband->ucChannelSpan) == ucChannel) { + return true; + } + } + } + } + + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in/out] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ + +u32 rlmDomainSupOperatingClassIeFill(u8 *pBuf) +{ + /* + * The Country element should only be included for Status Code 0 + * (Successful). + */ + u32 u4IeLen; + u8 aucClass[12] = { 0x01, 0x02, 0x03, 0x05, 0x16, 0x17, + 0x19, 0x1b, 0x1c, 0x1e, 0x20, 0x21 }; + + /* + * The Supported Operating Classes element is used by a STA to + * advertise the operating classes that it is capable of operating with + * in this country. + * + * The Country element (see 8.4.2.10) allows a STA to configure its PHY + * and MAC for operation when the operating triplet of Operating + * Extension Identifier, Operating Class, and Coverage Class fields is + * present. + */ + SUP_OPERATING_CLASS_IE(pBuf)->ucId = ELEM_ID_SUP_OPERATING_CLASS; + SUP_OPERATING_CLASS_IE(pBuf)->ucLength = 1 + sizeof(aucClass); + SUP_OPERATING_CLASS_IE(pBuf)->ucCur = 0x0c; /* 0x51 */ + kalMemCopy(SUP_OPERATING_CLASS_IE(pBuf)->ucSup, aucClass, sizeof(aucClass)); + u4IeLen = (SUP_OPERATING_CLASS_IE(pBuf)->ucLength + 2); + pBuf += u4IeLen; + + COUNTRY_IE(pBuf)->ucId = ELEM_ID_COUNTRY_INFO; + COUNTRY_IE(pBuf)->ucLength = 6; + COUNTRY_IE(pBuf)->aucCountryStr[0] = 0x55; + COUNTRY_IE(pBuf)->aucCountryStr[1] = 0x53; + COUNTRY_IE(pBuf)->aucCountryStr[2] = 0x20; + COUNTRY_IE(pBuf)->arCountryStr[0].ucFirstChnlNum = 1; + COUNTRY_IE(pBuf)->arCountryStr[0].ucNumOfChnl = 11; + COUNTRY_IE(pBuf)->arCountryStr[0].cMaxTxPwrLv = 0x1e; + u4IeLen += (COUNTRY_IE(pBuf)->ucLength + 2); + + return u4IeLen; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param[in] + * + * @return (fgValid) : 0 -> inValid, 1 -> Valid + */ +/*----------------------------------------------------------------------------*/ +u8 rlmDomainCheckChannelEntryValid(P_ADAPTER_T prAdapter, u8 ucCentralCh) +{ + u8 fgValid = false; + u8 ucTemp = 0xff; + u8 i; + /*Check Power limit table channel efficient or not */ + + for (i = POWER_LIMIT_2G4; i < POWER_LIMIT_SUBAND_NUM; i++) { + if ((ucCentralCh >= g_rRlmSubBand[i].ucStartCh) && + (ucCentralCh <= g_rRlmSubBand[i].ucEndCh)) { + ucTemp = (ucCentralCh - g_rRlmSubBand[i].ucStartCh) % + g_rRlmSubBand[i].ucInterval; + } + } + + if (ucTemp == 0) { + fgValid = true; + } + return fgValid; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return + */ +/*----------------------------------------------------------------------------*/ +u8 rlmDomainGetCenterChannel(ENUM_BAND_T eBand, u8 ucPriChannel, + ENUM_CHNL_EXT_T eExtend) +{ + u8 ucCenterChannel; + + if (eExtend == CHNL_EXT_SCA) { + ucCenterChannel = ucPriChannel + 2; + } else if (eExtend == CHNL_EXT_SCB) { + ucCenterChannel = ucPriChannel - 2; + } else { + ucCenterChannel = ucPriChannel; + } + + return ucCenterChannel; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return + */ +/*----------------------------------------------------------------------------*/ +u8 rlmDomainIsValidRfSetting(P_ADAPTER_T prAdapter, ENUM_BAND_T eBand, + u8 ucPriChannel, ENUM_CHNL_EXT_T eExtend, + ENUM_CHANNEL_WIDTH_T eChannelWidth, u8 ucChannelS1, + u8 ucChannelS2) +{ + u8 ucCenterChannel = 0; + u8 ucUpperChannel; + u8 ucLowerChannel; + u8 fgValidChannel = true; + u8 fgUpperChannel = true; + u8 fgLowerChannel = true; + u8 fgValidBW = true; + u8 fgValidRfSetting = true; + u32 u4PrimaryOffset; + + /*DBG msg for Channel InValid */ + if (eChannelWidth == CW_20_40MHZ) { + ucCenterChannel = + rlmDomainGetCenterChannel(eBand, ucPriChannel, eExtend); + + /* Check Central Channel Valid or Not */ + fgValidChannel = + rlmDomainCheckChannelEntryValid(prAdapter, ucCenterChannel); + if (fgValidChannel == false) { + DBGLOG(RLM, WARN, "Rf20: CentralCh=%d\n", ucCenterChannel); + } + + /* Check Upper Channel and Lower Channel */ + switch (eExtend) { + case CHNL_EXT_SCA: + ucUpperChannel = ucPriChannel + 4; + ucLowerChannel = ucPriChannel; + break; + + case CHNL_EXT_SCB: + ucUpperChannel = ucPriChannel; + ucLowerChannel = ucPriChannel - 4; + break; + + default: + ucUpperChannel = ucPriChannel; + ucLowerChannel = ucPriChannel; + break; + } + + fgUpperChannel = + rlmDomainCheckChannelEntryValid(prAdapter, ucUpperChannel); + if (fgUpperChannel == false) { + DBGLOG(RLM, WARN, "Rf20: UpperCh=%d\n", ucUpperChannel); + } + + fgLowerChannel = + rlmDomainCheckChannelEntryValid(prAdapter, ucLowerChannel); + if (fgLowerChannel == false) { + DBGLOG(RLM, WARN, "Rf20: LowerCh=%d\n", ucLowerChannel); + } + } else if ((eChannelWidth == CW_80MHZ) || (eChannelWidth == CW_160MHZ)) { + ucCenterChannel = ucChannelS1; + + /* Check Central Channel Valid or Not */ + if (eChannelWidth != CW_160MHZ) { + /*BW not check , ex: primary 36 and central channel 50 + * will fail the check*/ + fgValidChannel = + rlmDomainCheckChannelEntryValid(prAdapter, ucCenterChannel); + } + + if (fgValidChannel == false) { + DBGLOG(RLM, WARN, "Rf80/160C: CentralCh=%d\n", ucCenterChannel); + } + } else if (eChannelWidth == CW_80P80MHZ) { + ucCenterChannel = ucChannelS1; + + fgValidChannel = + rlmDomainCheckChannelEntryValid(prAdapter, ucCenterChannel); + + if (fgValidChannel == false) { + DBGLOG(RLM, WARN, "Rf160NC: CentralCh1=%d\n", ucCenterChannel); + } + + ucCenterChannel = ucChannelS2; + + fgValidChannel = + rlmDomainCheckChannelEntryValid(prAdapter, ucCenterChannel); + + if (fgValidChannel == false) { + DBGLOG(RLM, WARN, "Rf160NC: CentralCh2=%d\n", ucCenterChannel); + } + + /* Check Central Channel Valid or Not */ + } else { + DBGLOG(RLM, ERROR, "Wrong BW =%d\n", eChannelWidth); + fgValidChannel = false; + } + + /* Check BW Setting Correct or Not */ + if (eBand == BAND_2G4) { + if (eChannelWidth != CW_20_40MHZ) { + fgValidBW = false; + DBGLOG(RLM, WARN, "Rf: B=%d, W=%d\n", eBand, eChannelWidth); + } + } else { + if ((eChannelWidth == CW_80MHZ) || (eChannelWidth == CW_80P80MHZ)) { + u4PrimaryOffset = CAL_CH_OFFSET_80M(ucPriChannel, ucChannelS1); + if (u4PrimaryOffset >= 4) { + fgValidBW = false; + DBGLOG(RLM, WARN, "Rf: PriOffSet=%d, W=%d\n", u4PrimaryOffset, + eChannelWidth); + } + } else if (eChannelWidth == CW_160MHZ) { + u4PrimaryOffset = CAL_CH_OFFSET_160M(ucPriChannel, ucCenterChannel); + if (u4PrimaryOffset >= 8) { + fgValidBW = false; + DBGLOG(RLM, WARN, "Rf: PriOffSet=%d, W=%d\n", u4PrimaryOffset, + eChannelWidth); + } + } + } + + if ((fgValidBW == false) || (fgValidChannel == false) || + (fgUpperChannel == false) || (fgLowerChannel == false)) { + fgValidRfSetting = false; + } + + return fgValidRfSetting; +} + +#if (CFG_SUPPORT_SINGLE_SKU == 1) + +/* + * This function coverts country code from alphabet chars to u32, + * the caller need to pass country code chars and do size check + */ +u32 rlmDomainAlpha2ToU32(s8 *pcAlpha2, u8 ucAlpha2Size) +{ + u8 ucIdx; + u32 u4CountryCode = 0; + + if (ucAlpha2Size > TX_PWR_LIMIT_COUNTRY_STR_MAX_LEN) { + DBGLOG(RLM, ERROR, "alpha2 size %d is invalid!(max: %d)\n", + ucAlpha2Size, TX_PWR_LIMIT_COUNTRY_STR_MAX_LEN); + ucAlpha2Size = TX_PWR_LIMIT_COUNTRY_STR_MAX_LEN; + } + + for (ucIdx = 0; ucIdx < ucAlpha2Size; ucIdx++) + u4CountryCode |= (pcAlpha2[ucIdx] << (ucIdx * 8)); + + return u4CountryCode; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Search the tx power limit setting range of the specified in the text + * file + * + * \param[IN] u4CountryCode The u32 type of the specified country. + * \param[IN] pucBuf The content of the text file. + * \param[IN] u4cBufLen End boundary of the text file. + * \param[OUT] pu4CountryStart Store the start position of the desired country + * settings. \param[OUT] pu4CountryEnd Store the end position of the desired + * country settings. + * + * \retval true Success. + * \retval false Failure. + */ +/*----------------------------------------------------------------------------*/ + +u8 rlmDomainTxPwrLimitGetCountryRange(u32 u4CountryCode, u8 *pucBuf, + u32 u4BufLen, u32 *pu4CountryStart, + u32 *pu4CountryEnd) +{ + u32 u4TmpPos = 0; + char pcrCountryStr[TX_PWR_LIMIT_COUNTRY_STR_MAX_LEN + 1] = { 0 }; + u8 cIdx = 0; + bool search_next = false; + + while (1) { + if (!search_next) { + /* Search country code entry */ + while (u4TmpPos < u4BufLen && pucBuf[u4TmpPos] != '[') + u4TmpPos++; + /* skip the '[' char */ + u4TmpPos++; + } + + if (u4TmpPos >= u4BufLen) { + DBGLOG(RLM, STATE, + "Cannot find CountryCode(0x%x) in TxPwrLimit table\n", + u4CountryCode); + return false; + } + + cIdx = 0; + while (u4TmpPos < u4BufLen && cIdx < TX_PWR_LIMIT_COUNTRY_STR_MAX_LEN && + pucBuf[u4TmpPos] != ']' && pucBuf[u4TmpPos] != ',') { + pcrCountryStr[cIdx++] = pucBuf[u4TmpPos]; + u4TmpPos++; + } + + if (pucBuf[u4TmpPos] == ',') { + search_next = true; + } else { + search_next = false; + } + + /* skip the ']' or ',' char */ + u4TmpPos++; + + if (u4TmpPos >= u4BufLen || cIdx > TX_PWR_LIMIT_COUNTRY_STR_MAX_LEN) { + return false; + } + + if (u4CountryCode == rlmDomainAlpha2ToU32(pcrCountryStr, cIdx)) { + DBGLOG(RLM, INFO, "Found TxPwrLimit table for CountryCode \"%s\"\n", + pcrCountryStr); + /* the location after char ']' or ',' */ + *pu4CountryStart = u4TmpPos; + break; + } + } + + while (u4TmpPos < u4BufLen && pucBuf[u4TmpPos] != '[') + u4TmpPos++; + + *pu4CountryEnd = u4TmpPos; + + return true; +} + +u8 rlmDomainTxPwrLimitSearchSection(const char *pSectionName, s8 *pucBuf, + u32 *pu4Pos, u32 u4BufEnd) +{ + u32 u4TmpPos = *pu4Pos; + u8 uSectionNameLen = kalStrLen(pSectionName); + + while (1) { + while (u4TmpPos < u4BufEnd && pucBuf[u4TmpPos] != '<') + u4TmpPos++; + + u4TmpPos++; /* skip char '<' */ + + if (u4TmpPos + uSectionNameLen >= u4BufEnd) { + return false; + } + + if (kalStrnCmp(&pucBuf[u4TmpPos], pSectionName, uSectionNameLen) == 0) { + /* Go to the end of section header line */ + while (u4TmpPos < u4BufEnd && pucBuf[u4TmpPos] != '\n') + u4TmpPos++; + + *pu4Pos = u4TmpPos; + + break; + } + } + + return true; +} + +u8 rlmDomainTxPwrLimitSectionEnd(u8 *pucBuf, const char *pSectionName, + u32 *pu4Pos, u32 u4BufEnd) +{ + u32 u4TmpPos = *pu4Pos; + char cTmpChar = 0; + u8 uSectionNameLen = kalStrLen(pSectionName); + + while (u4TmpPos < u4BufEnd) { + cTmpChar = pucBuf[u4TmpPos]; + + /* skip blank lines */ + if (cTmpChar == ' ' || cTmpChar == '\t' || cTmpChar == '\n' || + cTmpChar == '\r') { + u4TmpPos++; + continue; + } + + break; + } + + if (u4TmpPos + uSectionNameLen + 2 >= u4BufEnd) { /* 2 means '/' and '>' + */ + *pu4Pos = u4BufEnd; + return false; + } + + if (pucBuf[u4TmpPos] != '<') { + return false; + } + + if (pucBuf[u4TmpPos + 1] != '/' || + pucBuf[u4TmpPos + 2 + uSectionNameLen] != '>' || + kalStrnCmp(&pucBuf[u4TmpPos + 2], pSectionName, uSectionNameLen)) { + *pu4Pos = u4TmpPos + uSectionNameLen + 2; + return false; + } + + *pu4Pos = u4TmpPos + uSectionNameLen + 3; /* 3 means go to the location + * after '>' */ + + return true; +} + +s8 rlmDomainTxPwrLimitGetChIdx(struct TX_PWR_LIMIT_DATA *pTxPwrLimit, + u8 ucChannel) +{ + s8 cIdx = 0; + + for (cIdx = 0; cIdx < pTxPwrLimit->ucChNum; cIdx++) + if (ucChannel == pTxPwrLimit->rChannelTxPwrLimit[cIdx].ucChannel) { + return cIdx; + } + + DBGLOG(RLM, ERROR, "Can't find idx of channel %d in TxPwrLimit data\n", + ucChannel); + + return -1; +} + +u8 rlmDomainTxPwrLimitLoadChannelSetting(u8 *pucBuf, u32 *pu4Pos, u32 u4BufEnd, + struct TX_PWR_LIMIT_DATA *pTxPwrLimit, + u8 ucSectionIdx) +{ + u32 u4TmpPos = *pu4Pos; + char cTmpChar = 0; + struct CHANNEL_TX_PWR_LIMIT *prChTxPwrLimit = NULL; + u8 bNeg = false; + s8 cLimitValue = 0, cChIdx = 0; + u8 ucIdx = 0, ucChannel = 0; + + /* skip blank lines */ + while (u4TmpPos < u4BufEnd) { + cTmpChar = pucBuf[u4TmpPos]; + + if (cTmpChar == ' ' || cTmpChar == '\t' || cTmpChar == '\n' || + cTmpChar == '\r') { + u4TmpPos++; + continue; + } + + break; + } + + /* current is at the location of 'c', check remaining buf length for + * 'chxxx' */ + if (u4TmpPos + 5 >= u4BufEnd) { + DBGLOG(RLM, ERROR, "Invalid location of ch setting: %u/%u\n", u4TmpPos, + u4BufEnd); + return false; + } + + if (pucBuf[u4TmpPos] == 'c' && pucBuf[u4TmpPos + 1] == 'h') { + ucChannel = (pucBuf[u4TmpPos + 2] - '0') * 100 + + (pucBuf[u4TmpPos + 3] - '0') * 10 + + (pucBuf[u4TmpPos + 4] - '0'); + } else { /* invalid format */ + *pu4Pos = u4TmpPos; + DBGLOG(RLM, ERROR, "Invalid ch setting starting chars: %c%c\n", + pucBuf[u4TmpPos], pucBuf[u4TmpPos + 1]); + + /* goto next line */ + while (*pu4Pos < u4BufEnd && pucBuf[*pu4Pos] != '\n') + (*pu4Pos)++; + + return true; + } + + cChIdx = rlmDomainTxPwrLimitGetChIdx(pTxPwrLimit, ucChannel); + + if (cChIdx == -1) { + *pu4Pos = u4TmpPos; + DBGLOG(RLM, ERROR, "Invalid ch %u %c%c%c\n", ucChannel, + pucBuf[u4TmpPos + 2], pucBuf[u4TmpPos + 3], + pucBuf[u4TmpPos + 4]); + + /* goto next line */ + while (*pu4Pos < u4BufEnd && pucBuf[*pu4Pos] != '\n') + (*pu4Pos)++; + + return true; + } + + u4TmpPos += 5; + + prChTxPwrLimit = &pTxPwrLimit->rChannelTxPwrLimit[cChIdx]; + + /* read the channel TxPwrLimit settings */ + for (ucIdx = 0; ucIdx < gTx_Pwr_Limit_Element_Num[ucSectionIdx]; ucIdx++) { + /* skip blank and comma */ + while (u4TmpPos < u4BufEnd) { + cTmpChar = pucBuf[u4TmpPos]; + + if (cTmpChar == ' ' || cTmpChar == '\t' || cTmpChar == ',') { + u4TmpPos++; + continue; + } + break; + } + + if (u4TmpPos >= u4BufEnd) { + *pu4Pos = u4BufEnd; + DBGLOG(RLM, ERROR, + "Invalid location of ch tx pwr limit val: %u/%u\n", u4TmpPos, + u4BufEnd); + return false; + } + + bNeg = false; + + cTmpChar = pucBuf[u4TmpPos]; + + if (cTmpChar == '-') { + bNeg = true; + u4TmpPos++; + } else if (cTmpChar == 'x') { + prChTxPwrLimit->rTxPwrLimitValue[ucSectionIdx][ucIdx] = + TX_PWR_LIMIT_MAX_VAL; + u4TmpPos++; + continue; + } + + cLimitValue = 0; + while (u4TmpPos < u4BufEnd) { + cTmpChar = pucBuf[u4TmpPos]; + + if (cTmpChar < '0' || cTmpChar > '9') { + break; + } + + cLimitValue = (cLimitValue * 10) + (cTmpChar - '0'); + u4TmpPos++; + } + + if (bNeg) { + cLimitValue = -cLimitValue; + } + + prChTxPwrLimit->rTxPwrLimitValue[ucSectionIdx][ucIdx] = cLimitValue; + } + + *pu4Pos = u4TmpPos; + return true; +} + +void rlmDomainTxPwrLimitRemoveComments(u8 *pucBuf, u32 u4BufLen) +{ + u32 u4TmpPos = 0; + char cTmpChar = 0; + + while (u4TmpPos < u4BufLen) { + cTmpChar = pucBuf[u4TmpPos]; + + if (cTmpChar == '#') { + while (cTmpChar != '\n') { + pucBuf[u4TmpPos] = ' '; + + u4TmpPos++; + if (u4TmpPos >= u4BufLen) { + break; + } + + cTmpChar = pucBuf[u4TmpPos]; + } + } + u4TmpPos++; + } +} + +u8 rlmDomainTxPwrLimitLoad(P_ADAPTER_T prAdapter, u8 *pucBuf, u32 u4BufLen, + u32 u4CountryCode, + struct TX_PWR_LIMIT_DATA *pTxPwrLimit) +{ + u8 uSecIdx = 0; + u32 u4CountryStart = 0, u4CountryEnd = 0, u4Pos = 0; + + rlmDomainTxPwrLimitRemoveComments(pucBuf, u4BufLen); + + if (!rlmDomainTxPwrLimitGetCountryRange(u4CountryCode, pucBuf, u4BufLen, + &u4CountryStart, &u4CountryEnd)) { + DBGLOG(RLM, ERROR, "Can't find specified table in %s\n", + g_tx_pwr_limit_file); + + /* Use WW as default country */ + if (!rlmDomainTxPwrLimitGetCountryRange(COUNTRY_CODE_WW, pucBuf, + u4BufLen, &u4CountryStart, + &u4CountryEnd)) { + DBGLOG(RLM, ERROR, "Can't find default table (WW) in %s\n", + g_tx_pwr_limit_file); + return false; + } + } + + u4Pos = u4CountryStart; + + for (uSecIdx = 0; uSecIdx < TX_PWR_LIMIT_SECTION_NUM; uSecIdx++) { + if (!rlmDomainTxPwrLimitSearchSection(gTx_Pwr_Limit_Section[uSecIdx], + pucBuf, &u4Pos, u4CountryEnd)) { + DBGLOG(RLM, ERROR, "Can't find specified section %s in %s\n", + gTx_Pwr_Limit_Section[uSecIdx], g_tx_pwr_limit_file); + return false; + } + + DBGLOG(RLM, INFO, "Find specified section %s in %s\n", + gTx_Pwr_Limit_Section[uSecIdx], g_tx_pwr_limit_file); + + while (!rlmDomainTxPwrLimitSectionEnd(pucBuf, + gTx_Pwr_Limit_Section[uSecIdx], + &u4Pos, u4CountryEnd) && + u4Pos < u4CountryEnd) { + if (!rlmDomainTxPwrLimitLoadChannelSetting( + pucBuf, &u4Pos, u4CountryEnd, pTxPwrLimit, uSecIdx)) { + return false; + } + } + } + + DBGLOG(RLM, INFO, "Load %s finished\n", g_tx_pwr_limit_file); + return true; +} + +void rlmDomainTxPwrLimitSetChValues(P_CMD_CHANNEL_POWER_LIMIT_V2 pCmd, + struct CHANNEL_TX_PWR_LIMIT *pChTxPwrLimit) +{ +#if !DBG_DISABLE_ALL_LOG + u8 section = 0, e = 0; +#endif + + pCmd->tx_pwr_dsss_cck = pChTxPwrLimit->rTxPwrLimitValue[0][0]; + pCmd->tx_pwr_dsss_bpsk = pChTxPwrLimit->rTxPwrLimitValue[0][1]; + + pCmd->tx_pwr_ofdm_bpsk = pChTxPwrLimit->rTxPwrLimitValue[0][2]; /* 6M, + * 9M */ + pCmd->tx_pwr_ofdm_qpsk = pChTxPwrLimit->rTxPwrLimitValue[0][3]; /* 12M, + * 18M + */ + pCmd->tx_pwr_ofdm_16qam = pChTxPwrLimit->rTxPwrLimitValue[0][4]; /* 24M, + * 36M + */ + pCmd->tx_pwr_ofdm_48m = pChTxPwrLimit->rTxPwrLimitValue[0][5]; + pCmd->tx_pwr_ofdm_54m = pChTxPwrLimit->rTxPwrLimitValue[0][6]; + + pCmd->tx_pwr_ht20_bpsk = pChTxPwrLimit->rTxPwrLimitValue[1][0]; /* MCS0*/ + pCmd->tx_pwr_ht20_qpsk = + pChTxPwrLimit->rTxPwrLimitValue[1][1]; /* MCS1, MCS2*/ + pCmd->tx_pwr_ht20_16qam = + pChTxPwrLimit->rTxPwrLimitValue[1][2]; /* MCS3, MCS4*/ + pCmd->tx_pwr_ht20_mcs5 = pChTxPwrLimit->rTxPwrLimitValue[1][3]; /* MCS5*/ + pCmd->tx_pwr_ht20_mcs6 = pChTxPwrLimit->rTxPwrLimitValue[1][4]; /* MCS6*/ + pCmd->tx_pwr_ht20_mcs7 = pChTxPwrLimit->rTxPwrLimitValue[1][5]; /* MCS7*/ + + pCmd->tx_pwr_ht40_bpsk = pChTxPwrLimit->rTxPwrLimitValue[2][0]; /* MCS0*/ + pCmd->tx_pwr_ht40_qpsk = + pChTxPwrLimit->rTxPwrLimitValue[2][1]; /* MCS1, MCS2*/ + pCmd->tx_pwr_ht40_16qam = + pChTxPwrLimit->rTxPwrLimitValue[2][2]; /* MCS3, MCS4*/ + pCmd->tx_pwr_ht40_mcs5 = pChTxPwrLimit->rTxPwrLimitValue[2][3]; /* MCS5*/ + pCmd->tx_pwr_ht40_mcs6 = pChTxPwrLimit->rTxPwrLimitValue[2][4]; /* MCS6*/ + pCmd->tx_pwr_ht40_mcs7 = pChTxPwrLimit->rTxPwrLimitValue[2][5]; /* MCS7*/ + pCmd->tx_pwr_ht40_mcs32 = pChTxPwrLimit->rTxPwrLimitValue[2][6]; /* MCS32*/ + + pCmd->tx_pwr_vht20_bpsk = pChTxPwrLimit->rTxPwrLimitValue[3][0]; /* MCS0*/ + pCmd->tx_pwr_vht20_qpsk = + pChTxPwrLimit->rTxPwrLimitValue[3][1]; /* MCS1, MCS2*/ + pCmd->tx_pwr_vht20_16qam = + pChTxPwrLimit->rTxPwrLimitValue[3][2]; /* MCS3, MCS4*/ + pCmd->tx_pwr_vht20_64qam = + pChTxPwrLimit->rTxPwrLimitValue[3][3]; /* MCS5, MCS6*/ + pCmd->tx_pwr_vht20_mcs7 = pChTxPwrLimit->rTxPwrLimitValue[3][4]; + pCmd->tx_pwr_vht20_mcs8 = pChTxPwrLimit->rTxPwrLimitValue[3][5]; + pCmd->tx_pwr_vht20_mcs9 = pChTxPwrLimit->rTxPwrLimitValue[3][6]; + + pCmd->tx_pwr_vht_40 = pChTxPwrLimit->rTxPwrLimitValue[4][2]; + pCmd->tx_pwr_vht_80 = pChTxPwrLimit->rTxPwrLimitValue[4][3]; + pCmd->tx_pwr_vht_160c = pChTxPwrLimit->rTxPwrLimitValue[4][5]; + pCmd->tx_pwr_vht_160nc = pChTxPwrLimit->rTxPwrLimitValue[4][4]; + pCmd->tx_pwr_lg_40 = pChTxPwrLimit->rTxPwrLimitValue[4][0]; + pCmd->tx_pwr_lg_80 = pChTxPwrLimit->rTxPwrLimitValue[4][1]; + +#if !DBG_DISABLE_ALL_LOG + DBGLOG(RLM, TRACE, "ch %d\n", pCmd->ucCentralCh); + for (section = 0; section < TX_PWR_LIMIT_SECTION_NUM; section++) + for (e = 0; e < gTx_Pwr_Limit_Element_Num[section]; e++) + DBGLOG(RLM, TRACE, "TxPwrLimit[%s][%s]= %d\n", + gTx_Pwr_Limit_Section[section], + gTx_Pwr_Limit_Element[section][e], + pChTxPwrLimit->rTxPwrLimitValue[section][e]); + +#endif +} + +void rlmDomainTxPwrLimitSetValues( + P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T pSetCmd, + struct TX_PWR_LIMIT_DATA *pTxPwrLimit) +{ + u8 ucIdx = 0; + s8 cChIdx = 0; + P_CMD_CHANNEL_POWER_LIMIT_V2 pCmd = NULL; + struct CHANNEL_TX_PWR_LIMIT *pChTxPwrLimit = NULL; + + if (!pSetCmd || !pTxPwrLimit) { + DBGLOG(RLM, ERROR, "%s: Invalid request!!!\n", __func__); + return; + } + + for (ucIdx = 0; ucIdx < pSetCmd->ucNum; ucIdx++) { + pCmd = &(pSetCmd->rChannelPowerLimit[ucIdx]); + cChIdx = rlmDomainTxPwrLimitGetChIdx(pTxPwrLimit, pCmd->ucCentralCh); + if (cChIdx == -1) { + DBGLOG(RLM, ERROR, "Invalid ch idx found while assigning values\n"); + continue; + } + pChTxPwrLimit = &pTxPwrLimit->rChannelTxPwrLimit[cChIdx]; + rlmDomainTxPwrLimitSetChValues(pCmd, pChTxPwrLimit); + } +} + +u8 rlmDomainTxPwrLimitLoadFromFile(P_ADAPTER_T prAdapter, u32 u4CountryCode, + struct TX_PWR_LIMIT_DATA *pTxPwrLimit) +{ + u8 *pucConfigBuf; + u32 u4ConfigReadLen; + u8 bRet = true; + char tx_pwr_limit_file_sdcard0[TX_PWR_LIMIT_FILE_NAME_LENGTH] = + "/storage/sdcard0/"; + char tx_pwr_limit_file_misc[TX_PWR_LIMIT_FILE_NAME_LENGTH] = "/data/misc/"; + char tx_pwr_limit_file_misc_wifi[TX_PWR_LIMIT_FILE_NAME_LENGTH] = + "/data/misc/wifi/"; + + kalStrCat(tx_pwr_limit_file_sdcard0, g_tx_pwr_limit_file); + kalStrCat(tx_pwr_limit_file_misc, g_tx_pwr_limit_file); + kalStrCat(tx_pwr_limit_file_misc_wifi, g_tx_pwr_limit_file); + + pucConfigBuf = + (u8 *)kalMemAlloc(WLAN_TX_PWR_LIMIT_FILE_BUF_SIZE, VIR_MEM_TYPE); + + if (!pucConfigBuf) { + DBGLOG(RLM, ERROR, "Alloc buffer for TxPwrLimit failed\n"); + return false; + } + + kalMemZero(pucConfigBuf, WLAN_TX_PWR_LIMIT_FILE_BUF_SIZE); + u4ConfigReadLen = 0; + + if (wlanGetFileContent(prAdapter, (char *)g_tx_pwr_limit_file, pucConfigBuf, + WLAN_TX_PWR_LIMIT_FILE_BUF_SIZE, &u4ConfigReadLen, + true) == 0) { + /* ToDo:: Nothing */ + } else if (wlanGetFileContent(prAdapter, tx_pwr_limit_file_sdcard0, + pucConfigBuf, WLAN_TX_PWR_LIMIT_FILE_BUF_SIZE, + &u4ConfigReadLen, false) == 0) { + /* ToDo:: Nothing */ + } else if (wlanGetFileContent(prAdapter, tx_pwr_limit_file_misc, + pucConfigBuf, WLAN_TX_PWR_LIMIT_FILE_BUF_SIZE, + &u4ConfigReadLen, false) == 0) { + /* ToDo:: Nothing */ + } else if (wlanGetFileContent(prAdapter, tx_pwr_limit_file_misc_wifi, + pucConfigBuf, WLAN_TX_PWR_LIMIT_FILE_BUF_SIZE, + &u4ConfigReadLen, false) == 0) { + /* ToDo:: Nothing */ + } else { + bRet = false; + goto error; + } + + if (pucConfigBuf[0] == '\0' || u4ConfigReadLen == 0) { + bRet = false; + goto error; + } + + if (!rlmDomainTxPwrLimitLoad(prAdapter, pucConfigBuf, u4ConfigReadLen, + u4CountryCode, pTxPwrLimit)) { + bRet = false; + goto error; + } + +error: + kalMemFree(pucConfigBuf, VIR_MEM_TYPE, WLAN_TX_PWR_LIMIT_FILE_BUF_SIZE); + return bRet; +} + +u8 rlmDomainGetTxPwrLimit(u32 country_code, P_GLUE_INFO_T prGlueInfo, + P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T pSetCmd_2g, + P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T pSetCmd_5g) +{ + int bRet = true; + u8 ucIdx = 0, ucCnt = 0; + struct TX_PWR_LIMIT_DATA *pTxPwrLimit = + (struct TX_PWR_LIMIT_DATA *)kalMemAlloc( + sizeof(struct TX_PWR_LIMIT_DATA), VIR_MEM_TYPE); + + if (!pTxPwrLimit) { + bRet = false; + DBGLOG(RLM, ERROR, "Alloc buffer for TxPwrLimit main struct failed\n"); + return bRet; + } + + pTxPwrLimit->ucChNum = (pSetCmd_2g ? pSetCmd_2g->ucNum : 0) + + (pSetCmd_5g ? pSetCmd_5g->ucNum : 0); + + pTxPwrLimit->rChannelTxPwrLimit = + (struct CHANNEL_TX_PWR_LIMIT *)kalMemAlloc( + sizeof(struct CHANNEL_TX_PWR_LIMIT) * (pTxPwrLimit->ucChNum), + VIR_MEM_TYPE); + + if (!pTxPwrLimit->rChannelTxPwrLimit) { + bRet = false; + DBGLOG(RLM, ERROR, "Alloc buffer for TxPwrLimit ch values failed\n"); + goto error; + } + + kalMemSet(pTxPwrLimit->rChannelTxPwrLimit, MAX_TX_POWER, + sizeof(struct CHANNEL_TX_PWR_LIMIT) * (pTxPwrLimit->ucChNum)); + + if (pSetCmd_2g) { + for (ucIdx = 0; ucIdx < pSetCmd_2g->ucNum; ucIdx++) { + pTxPwrLimit->rChannelTxPwrLimit[ucCnt].ucChannel = + pSetCmd_2g->rChannelPowerLimit[ucIdx].ucCentralCh; + ucCnt++; + } + } + + if (pSetCmd_5g) { + for (ucIdx = 0; ucIdx < pSetCmd_5g->ucNum; ucIdx++) { + pTxPwrLimit->rChannelTxPwrLimit[ucCnt].ucChannel = + pSetCmd_5g->rChannelPowerLimit[ucIdx].ucCentralCh; + ucCnt++; + } + } + +#ifdef CFG_SUPPORT_PWR_LIMIT_FILE_LOAD + bRet = rlmDomainTxPwrLimitLoadFromFile(prGlueInfo->prAdapter, country_code, + pTxPwrLimit); +#endif + if (bRet) { + rlmDomainTxPwrLimitSetValues(pSetCmd_2g, pTxPwrLimit); + rlmDomainTxPwrLimitSetValues(pSetCmd_5g, pTxPwrLimit); + } + + kalMemFree(pTxPwrLimit->rChannelTxPwrLimit, VIR_MEM_TYPE, + sizeof(struct CHANNEL_TX_PWR_LIMIT) * pTxPwrLimit->ucChNum); + +error: + kalMemFree(pTxPwrLimit, VIR_MEM_TYPE, sizeof(struct TX_PWR_LIMIT_DATA)); + + return bRet; +} + +#endif + +#if CFG_SUPPORT_PWR_LIMIT_COUNTRY + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param[in] + * + * @return (fgValid) : 0 -> inValid, 1 -> Valid + */ +/*----------------------------------------------------------------------------*/ +u8 rlmDomainCheckPowerLimitValid( + P_ADAPTER_T prAdapter, + COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION rPowerLimitTableConfiguration, + u8 ucPwrLimitNum) +{ + u8 i; + u8 fgValid = true; + s8 *prPwrLimit; + + prPwrLimit = &rPowerLimitTableConfiguration.aucPwrLimit[0]; + + for (i = 0; i < ucPwrLimitNum; i++, prPwrLimit++) { + if (*prPwrLimit > MAX_TX_POWER || *prPwrLimit < MIN_TX_POWER) { + fgValid = false; + break; /*Find out Wrong Power limit */ + } + } + return fgValid; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param[in] + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void rlmDomainCheckCountryPowerLimitTable(P_ADAPTER_T prAdapter) +{ + u8 i, j; + u16 u2CountryCodeTable, u2CountryCodeCheck; + u8 fgChannelValid = false; + u8 fgPowerLimitValid = false; + u8 fgEntryRepetetion = false; + u8 fgTableValid = true; + + /*Configuration Table Check */ + for (i = 0; i < sizeof(g_rRlmPowerLimitConfiguration) / + sizeof(COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION); + i++) { + /*Table Country Code */ + WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], + &u2CountryCodeTable); + + /*Repetition Entry Check */ + for (j = i + 1; j < ARRAY_SIZE(g_rRlmPowerLimitConfiguration); j++) { + WLAN_GET_FIELD_BE16( + &g_rRlmPowerLimitConfiguration[j].aucCountryCode[0], + &u2CountryCodeCheck); + if (((g_rRlmPowerLimitConfiguration[i].ucCentralCh) == + g_rRlmPowerLimitConfiguration[j].ucCentralCh) && + (u2CountryCodeTable == u2CountryCodeCheck)) { + fgEntryRepetetion = true; + DBGLOG(RLM, INFO, + "Domain: Configuration Repetition CC=%c%c, Ch=%d\n", + g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], + g_rRlmPowerLimitConfiguration[i].aucCountryCode[1], + g_rRlmPowerLimitConfiguration[i].ucCentralCh); + } + } + + /*Channel Number Check */ + fgChannelValid = rlmDomainCheckChannelEntryValid( + prAdapter, g_rRlmPowerLimitConfiguration[i].ucCentralCh); + + /*Power Limit Check */ + fgPowerLimitValid = rlmDomainCheckPowerLimitValid( + prAdapter, g_rRlmPowerLimitConfiguration[i], PWR_LIMIT_NUM); + + if (fgChannelValid == false || fgPowerLimitValid == false) { + fgTableValid = false; + DBGLOG( + RLM, INFO, "Domain: CC=%c%c, Ch=%d, Limit: %d,%d,%d,%d,%d\n", + g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], + g_rRlmPowerLimitConfiguration[i].aucCountryCode[1], + g_rRlmPowerLimitConfiguration[i].ucCentralCh, + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_CCK], + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_20M], + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_40M], + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_80M], + g_rRlmPowerLimitConfiguration[i].aucPwrLimit[PWR_LIMIT_160M]); + } + + if (u2CountryCodeTable == COUNTRY_CODE_NULL) { + DBGLOG(RLM, INFO, "Domain: Full search down\n"); + break; /*End of country table entry */ + } + } + + if (fgEntryRepetetion == false) { + DBGLOG(RLM, INFO, "Domain: Configuration Table no Repetiton.\n"); + } + + /*Configuration Table no error */ + if (fgTableValid == true) { + prAdapter->fgIsPowerLimitTableValid = true; + } else { + prAdapter->fgIsPowerLimitTableValid = false; + } + + /*Default Table Check */ + fgEntryRepetetion = false; + for (i = 0; i < sizeof(g_rRlmPowerLimitDefault) / + sizeof(COUNTRY_POWER_LIMIT_TABLE_DEFAULT); + i++) { + WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[i].aucCountryCode[0], + &u2CountryCodeTable); + + for (j = i + 1; j < sizeof(g_rRlmPowerLimitDefault) / + sizeof(COUNTRY_POWER_LIMIT_TABLE_DEFAULT); + j++) { + WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[j].aucCountryCode[0], + &u2CountryCodeCheck); + if (u2CountryCodeTable == u2CountryCodeCheck) { + fgEntryRepetetion = true; + DBGLOG(RLM, INFO, "Domain: Default Repetition CC=%c%c\n", + g_rRlmPowerLimitDefault[j].aucCountryCode[0], + g_rRlmPowerLimitDefault[j].aucCountryCode[1]); + } + } + } + if (fgEntryRepetetion == false) { + DBGLOG(RLM, INFO, "Domain: Default Table no Repetiton.\n"); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param[in] + * + * @return (u2TableIndex) : if 0xFFFF -> No Table Match + */ +/*----------------------------------------------------------------------------*/ +u16 rlmDomainPwrLimitDefaultTableDecision(P_ADAPTER_T prAdapter, + u16 u2CountryCode) +{ + u16 i; + u16 u2CountryCodeTable = COUNTRY_CODE_NULL; + u16 u2TableIndex = POWER_LIMIT_TABLE_NULL; /* No Table Match */ + + /*Default Table Index */ + for (i = 0; i < sizeof(g_rRlmPowerLimitDefault) / + sizeof(COUNTRY_POWER_LIMIT_TABLE_DEFAULT); + i++) { + WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitDefault[i].aucCountryCode[0], + &u2CountryCodeTable); + + if (u2CountryCodeTable == u2CountryCode) { + u2TableIndex = i; + break; /*match country code */ + } else if (u2CountryCodeTable == COUNTRY_CODE_NULL) { + u2TableIndex = i; + break; /*find last one country- Default */ + } + } + + DBGLOG(RLM, INFO, "Domain: Default Table Index = %d\n", u2TableIndex); + + return u2TableIndex; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param[in] + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void rlmDomainBuildCmdByDefaultTable( + P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd, u16 u2DefaultTableIndex) +{ + u8 i, k; + P_COUNTRY_POWER_LIMIT_TABLE_DEFAULT prPwrLimitSubBand; + P_CMD_CHANNEL_POWER_LIMIT prCmdPwrLimit; + + prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; + prPwrLimitSubBand = &g_rRlmPowerLimitDefault[u2DefaultTableIndex]; + + /*Build power limit cmd by default table information */ + + for (i = POWER_LIMIT_2G4; i < POWER_LIMIT_SUBAND_NUM; i++) { + if (prPwrLimitSubBand->aucPwrLimitSubBand[i] < MAX_TX_POWER) { + for (k = g_rRlmSubBand[i].ucStartCh; k <= g_rRlmSubBand[i].ucEndCh; + k += g_rRlmSubBand[i].ucInterval) { + if ((prPwrLimitSubBand->ucPwrUnit & BIT(i)) == 0) { + prCmdPwrLimit->ucCentralCh = k; + kalMemSet(&prCmdPwrLimit->cPwrLimitCCK, + prPwrLimitSubBand->aucPwrLimitSubBand[i], + PWR_LIMIT_NUM); + prCmdPwrLimit++; + prCmd->ucNum++; + } else { + /* ex: 40MHz power limit(mW\MHz) = + * 20MHz power limit(mW\MHz) * 2 + * ---> 40MHz power limit(dBm) = 20MHz + * power limit(dBm) + 6; + */ + prCmdPwrLimit->ucCentralCh = k; + prCmdPwrLimit->cPwrLimitCCK = + prPwrLimitSubBand->aucPwrLimitSubBand[i]; + prCmdPwrLimit->cPwrLimit20 = + prPwrLimitSubBand->aucPwrLimitSubBand[i]; + prCmdPwrLimit->cPwrLimit40 = + prPwrLimitSubBand->aucPwrLimitSubBand[i] + 6; + if (prCmdPwrLimit->cPwrLimit40 > MAX_TX_POWER) { + prCmdPwrLimit->cPwrLimit40 = MAX_TX_POWER; + } + prCmdPwrLimit->cPwrLimit80 = + prPwrLimitSubBand->aucPwrLimitSubBand[i] + 12; + if (prCmdPwrLimit->cPwrLimit80 > MAX_TX_POWER) { + prCmdPwrLimit->cPwrLimit80 = MAX_TX_POWER; + } + prCmdPwrLimit->cPwrLimit160 = + prPwrLimitSubBand->aucPwrLimitSubBand[i] + 18; + if (prCmdPwrLimit->cPwrLimit160 > MAX_TX_POWER) { + prCmdPwrLimit->cPwrLimit160 = MAX_TX_POWER; + } + prCmdPwrLimit++; + prCmd->ucNum++; + } + } + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param[in] + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void rlmDomainBuildCmdByConfigTable( + P_ADAPTER_T prAdapter, P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd) +{ + u8 i, k; + u16 u2CountryCodeTable = COUNTRY_CODE_NULL; + P_CMD_CHANNEL_POWER_LIMIT prCmdPwrLimit; + u8 fgChannelValid; + + /*Build power limit cmd by configuration table information */ + + for (i = 0; i < sizeof(g_rRlmPowerLimitConfiguration) / + sizeof(COUNTRY_POWER_LIMIT_TABLE_CONFIGURATION); + i++) { + WLAN_GET_FIELD_BE16(&g_rRlmPowerLimitConfiguration[i].aucCountryCode[0], + &u2CountryCodeTable); + + fgChannelValid = rlmDomainCheckChannelEntryValid( + prAdapter, g_rRlmPowerLimitConfiguration[i].ucCentralCh); + + if (u2CountryCodeTable == COUNTRY_CODE_NULL) { + DBGLOG(RLM, INFO, + "Domain: full search configuration table done.\n"); + break; /*end of configuration table */ + } else if ((u2CountryCodeTable == prCmd->u2CountryCode) && + (fgChannelValid == true)) { + prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; + + if (prCmd->ucNum != 0) { + for (k = 0; k < prCmd->ucNum; k++) { + if (prCmdPwrLimit->ucCentralCh == + g_rRlmPowerLimitConfiguration[i].ucCentralCh) { + /*Cmd setting (Default table + * information) and + * Configuration table has + * repetition channel entry, ex + * : Default table (ex: 2.4G, + * limit = 20dBm) --> ch1~14 + * limit =20dBm, Configuration + * table (ex: ch1, limit = + * 22dBm) --> ch 1 = 22 dBm Cmd + * final setting --> ch1 = + * 22dBm, ch12~14 = 20dBm + */ + kalMemCopy( + &prCmdPwrLimit->cPwrLimitCCK, + &g_rRlmPowerLimitConfiguration[i].aucPwrLimit, + PWR_LIMIT_NUM); + + DBGLOG( + RLM, INFO, + "Domain: CC=%c%c,ConfigCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", + ((prCmd->u2CountryCode & 0xff00) >> 8), + (prCmd->u2CountryCode & 0x00ff), + prCmdPwrLimit->ucCentralCh, + prCmdPwrLimit->cPwrLimitCCK, + prCmdPwrLimit->cPwrLimit20, + prCmdPwrLimit->cPwrLimit40, + prCmdPwrLimit->cPwrLimit80, + prCmdPwrLimit->cPwrLimit160, prCmdPwrLimit->ucFlag); + + break; + } + prCmdPwrLimit++; + } + if (k == prCmd->ucNum) { + /*Full search cmd (Default table + * setting) no match channey, ex : + * Default table (ex: 2.4G, limit = + * 20dBm) --> ch1~14 limit =20dBm, + * Configuration table (ex: ch36, limit + * = 22dBm) --> ch 36 = 22 dBm Cmd final + * setting --> ch1~14 = 20dBm, ch36= + * 22dBm + */ + kalMemCopy(&prCmdPwrLimit->cPwrLimitCCK, + &g_rRlmPowerLimitConfiguration[i].aucPwrLimit, + PWR_LIMIT_NUM); + prCmd->ucNum++; + + DBGLOG( + RLM, INFO, + "Domain: Full CC=%c%c,ConfigCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", + ((prCmd->u2CountryCode & 0xff00) >> 8), + (prCmd->u2CountryCode & 0x00ff), + prCmdPwrLimit->ucCentralCh, prCmdPwrLimit->cPwrLimitCCK, + prCmdPwrLimit->cPwrLimit20, prCmdPwrLimit->cPwrLimit40, + prCmdPwrLimit->cPwrLimit80, prCmdPwrLimit->cPwrLimit160, + prCmdPwrLimit->ucFlag); + } + } else { + /*Default table power limit value are 63--> cmd + * table no channel entry ex : Default table + * (ex: 2.4G, limit = 63Bm) --> no channel entry + * in cmd, Configuration table (ex: ch36, limit + * = 22dBm) --> ch 36 = 22 dBm Cmd final setting + * --> ch36= 22dBm + */ + prCmdPwrLimit->ucCentralCh = + g_rRlmPowerLimitConfiguration[i].ucCentralCh; + kalMemCopy(&prCmdPwrLimit->cPwrLimitCCK, + &g_rRlmPowerLimitConfiguration[i].aucPwrLimit, + PWR_LIMIT_NUM); + prCmd->ucNum++; + + DBGLOG(RLM, INFO, + "Domain: Default table power limit value are 63.\n"); + DBGLOG( + RLM, INFO, + "Domain: CC=%c%c,ConfigCh=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", + ((prCmd->u2CountryCode & 0xff00) >> 8), + (prCmd->u2CountryCode & 0x00ff), prCmdPwrLimit->ucCentralCh, + prCmdPwrLimit->cPwrLimitCCK, prCmdPwrLimit->cPwrLimit20, + prCmdPwrLimit->cPwrLimit40, prCmdPwrLimit->cPwrLimit80, + prCmdPwrLimit->cPwrLimit160, prCmdPwrLimit->ucFlag); + } + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param[in] + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void rlmDomainSendPwrLimitCmd_V2(P_ADAPTER_T prAdapter) +{ +#if (CFG_SUPPORT_SINGLE_SKU == 1) + WLAN_STATUS rStatus; + u32 u4SetQueryInfoLen; + u32 ch_cnt; + struct wiphy *wiphy; + u8 band_idx, ch_idx; + P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T prCmd[NUM_NL80211_BANDS] = { + NULL + }; + u32 u4SetCmdTableMaxSize[NUM_NL80211_BANDS] = { 0 }; + const s8 *prChannelList = NULL; + + DBGLOG(RLM, INFO, "rlmDomainSendPwrLimitCmd()\n"); + + wiphy = priv_to_wiphy(prAdapter->prGlueInfo); + for (band_idx = 0; band_idx < NUM_NL80211_BANDS; band_idx++) { + if (band_idx != NL80211_BAND_2GHZ && band_idx != NL80211_BAND_5GHZ) { + continue; + } + + prChannelList = (band_idx == NL80211_BAND_2GHZ) ? gTx_Pwr_Limit_2g_Ch : + gTx_Pwr_Limit_5g_Ch; + + ch_cnt = (band_idx == NL80211_BAND_2GHZ) ? TX_PWR_LIMIT_2G_CH_NUM : + TX_PWR_LIMIT_5G_CH_NUM; + + if (!ch_cnt) { + continue; + } + + u4SetCmdTableMaxSize[band_idx] = + sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T) + + ch_cnt * sizeof(CMD_CHANNEL_POWER_LIMIT_V2); + + /* compile time assertion on firmware command structs */ + DATA_STRUCT_INSPECTING_ASSERT( + sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T) == 8); + DATA_STRUCT_INSPECTING_ASSERT(sizeof(CMD_CHANNEL_POWER_LIMIT_V2) == 40); + DATA_STRUCT_INSPECTING_ASSERT( + OFFSET_OF(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T, + rChannelPowerLimit) == + sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T)); + DATA_STRUCT_INSPECTING_ASSERT( + OFFSET_OF(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T, + rChannelPowerLimit[1]) == + sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T) + + 1 * sizeof(CMD_CHANNEL_POWER_LIMIT_V2)); + DATA_STRUCT_INSPECTING_ASSERT( + OFFSET_OF(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T, + rChannelPowerLimit[2]) == + sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T) + + 2 * sizeof(CMD_CHANNEL_POWER_LIMIT_V2)); + + prCmd[band_idx] = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, + u4SetCmdTableMaxSize[band_idx]); + + if (!prCmd[band_idx]) { + DBGLOG(RLM, ERROR, "Domain: no buf to send cmd\n"); + goto error; + } + + /*initialize tw pwr table*/ + kalMemSet(prCmd[band_idx], MAX_TX_POWER, + u4SetCmdTableMaxSize[band_idx]); + + prCmd[band_idx]->ucNum = ch_cnt; + prCmd[band_idx]->eband = (band_idx == NL80211_BAND_2GHZ) ? BAND_2G4 : + BAND_5G; + prCmd[band_idx]->countryCode = rlmDomainGetCountryCode(); + + DBGLOG(RLM, INFO, "%s, active n_channels=%d, band=%d\n", __func__, + ch_cnt, prCmd[band_idx]->eband); + + for (ch_idx = 0; ch_idx < ch_cnt; ch_idx++) + prCmd[band_idx]->rChannelPowerLimit[ch_idx].ucCentralCh = + prChannelList[ch_idx]; + } + + /* + * Get Max Tx Power from MT_TxPwrLimit.dat + */ + rlmDomainGetTxPwrLimit(rlmDomainGetCountryCode(), prAdapter->prGlueInfo, + prCmd[NL80211_BAND_2GHZ], prCmd[NL80211_BAND_5GHZ]); + + for (band_idx = 0; band_idx < NUM_NL80211_BANDS; band_idx++) { + u8 ucRemainChNum, i, ucTempChNum, prCmdBatchNum; + u32 u4BufSize = 0; + P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T prTempCmd = NULL; + ENUM_BAND_T eBand = (band_idx == NL80211_BAND_2GHZ) ? BAND_2G4 : + BAND_5G; + + if (!prCmd[band_idx]) { + continue; + } + + ucRemainChNum = prCmd[band_idx]->ucNum; + prCmdBatchNum = + (ucRemainChNum + TX_PWR_LIMIT_CMD_CH_NUM_THRESHOLD - 1) / + TX_PWR_LIMIT_CMD_CH_NUM_THRESHOLD; + + for (i = 0; i < prCmdBatchNum; i++) { + if (i == prCmdBatchNum - 1) { + ucTempChNum = ucRemainChNum; + } else { + ucTempChNum = TX_PWR_LIMIT_CMD_CH_NUM_THRESHOLD; + } + + u4BufSize = sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_V2_T) + + ucTempChNum * sizeof(CMD_CHANNEL_POWER_LIMIT_V2); + + prTempCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4BufSize); + + if (!prTempCmd) { + DBGLOG(RLM, ERROR, "Domain: no buf to send cmd\n"); + goto error; + } + kalMemZero(prTempCmd, u4BufSize); + + /*copy partial tx pwr limit*/ + prTempCmd->ucNum = ucTempChNum; + prTempCmd->eband = eBand; + prTempCmd->countryCode = rlmDomainGetCountryCode(); + kalMemCopy( + &prTempCmd->rChannelPowerLimit[0], + &prCmd[band_idx] + ->rChannelPowerLimit[i * TX_PWR_LIMIT_CMD_CH_NUM_THRESHOLD], + ucTempChNum * sizeof(CMD_CHANNEL_POWER_LIMIT_V2)); + + u4SetQueryInfoLen = u4BufSize; + /* Update tx max. power info to chip */ + rStatus = + wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SET_COUNTRY_POWER_LIMIT, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + u4SetQueryInfoLen, /* u4SetQueryInfoLen */ + (u8 *)prTempCmd, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + cnmMemFree(prAdapter, prTempCmd); + + ucRemainChNum -= ucTempChNum; + } + } + +error: + for (band_idx = 0; band_idx < NUM_NL80211_BANDS; band_idx++) + if (prCmd[band_idx]) { + cnmMemFree(prAdapter, prCmd[band_idx]); + } + +#endif +} + +void rlmDomainSendPwrLimitCmd(P_ADAPTER_T prAdapter) +{ + P_CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T prCmd; + WLAN_STATUS rStatus; + u8 i; + u16 u2DefaultTableIndex; + u32 u4SetCmdTableMaxSize; + u32 u4SetQueryInfoLen; + P_CMD_CHANNEL_POWER_LIMIT prCmdPwrLimit; /* for print usage */ + + if (regd_is_single_sku_en()) { + return rlmDomainSendPwrLimitCmd_V2(prAdapter); + } + + u4SetCmdTableMaxSize = + sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T) + + MAX_CMD_SUPPORT_CHANNEL_NUM * sizeof(CMD_CHANNEL_POWER_LIMIT); + + prCmd = cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4SetCmdTableMaxSize); + + if (!prCmd) { + DBGLOG(RLM, ERROR, "Domain: no buf to send cmd\n"); + return; + } + kalMemZero(prCmd, u4SetCmdTableMaxSize); + + u2DefaultTableIndex = rlmDomainPwrLimitDefaultTableDecision( + prAdapter, prAdapter->rWifiVar.rConnSettings.u2CountryCode); + + if (u2DefaultTableIndex != POWER_LIMIT_TABLE_NULL) { + WLAN_GET_FIELD_BE16( + &g_rRlmPowerLimitDefault[u2DefaultTableIndex].aucCountryCode[0], + &prCmd->u2CountryCode); + + prCmd->ucNum = 0; + + if (prCmd->u2CountryCode != COUNTRY_CODE_NULL) { + /*Command - default table information */ + rlmDomainBuildCmdByDefaultTable(prCmd, u2DefaultTableIndex); + + /*Command - configuration table information */ + rlmDomainBuildCmdByConfigTable(prAdapter, prCmd); + } + } + + if (prCmd->u2CountryCode != 0) { + DBGLOG(RLM, INFO, "Domain: ValidCC =%c%c, ChNum=%d\n", + ((prCmd->u2CountryCode & 0xff00) >> 8), + (prCmd->u2CountryCode & 0x00ff), prCmd->ucNum); + } else { + DBGLOG(RLM, INFO, "Domain: ValidCC =0x%04x, ChNum=%d\n", + prCmd->u2CountryCode, prCmd->ucNum); + } + prCmdPwrLimit = &prCmd->rChannelPowerLimit[0]; + + for (i = 0; i < prCmd->ucNum; i++) { + DBGLOG(RLM, INFO, "Domain: Ch=%d,Limit=%d,%d,%d,%d,%d,Fg=%d\n", + prCmdPwrLimit->ucCentralCh, prCmdPwrLimit->cPwrLimitCCK, + prCmdPwrLimit->cPwrLimit20, prCmdPwrLimit->cPwrLimit40, + prCmdPwrLimit->cPwrLimit80, prCmdPwrLimit->cPwrLimit160, + prCmdPwrLimit->ucFlag); + prCmdPwrLimit++; + } + + u4SetQueryInfoLen = (sizeof(CMD_SET_COUNTRY_CHANNEL_POWER_LIMIT_T) + + (prCmd->ucNum) * sizeof(CMD_CHANNEL_POWER_LIMIT)); + + /* Update domain info to chip */ + if (prCmd->ucNum <= MAX_CMD_SUPPORT_CHANNEL_NUM) { + rStatus = + wlanSendSetQueryCmd(prAdapter, /* prAdapter */ + CMD_ID_SET_COUNTRY_POWER_LIMIT, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + u4SetQueryInfoLen, /* u4SetQueryInfoLen */ + (u8 *)prCmd, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + } else { + DBGLOG(RLM, INFO, "Domain: illegal power limit table"); + } + + /* ASSERT(rStatus == WLAN_STATUS_PENDING); */ + + cnmMemFree(prAdapter, prCmd); +} +#endif +u8 regd_is_single_sku_en(void) +{ +#if (CFG_SUPPORT_SINGLE_SKU == 1) + return g_mtk_regd_control.en; + +#else + return false; + +#endif +} + +#if (CFG_SUPPORT_SINGLE_SKU == 1) +u8 rlmDomainIsCtrlStateEqualTo(enum regd_state state) +{ + return (g_mtk_regd_control.state == state) ? true : false; +} + +enum regd_state rlmDomainGetCtrlState(void) +{ + return g_mtk_regd_control.state; +} + +void rlmDomainResetActiveChannel(void) +{ + g_mtk_regd_control.n_channel_active_2g = 0; + g_mtk_regd_control.n_channel_active_5g = 0; +} + +void rlmDomainAddActiveChannel(u8 band) +{ + if (band == NL80211_BAND_2GHZ) { + g_mtk_regd_control.n_channel_active_2g += 1; + } else if (band == NL80211_BAND_5GHZ) { + g_mtk_regd_control.n_channel_active_5g += 1; + } +} + +u8 rlmDomainGetActiveChannelCount(u8 band) +{ + if (band == NL80211_BAND_2GHZ) { + return g_mtk_regd_control.n_channel_active_2g; + } else if (band == NL80211_BAND_5GHZ) { + return g_mtk_regd_control.n_channel_active_5g; + } else { + return 0; + } +} + +struct channel *rlmDomainGetActiveChannels(void) +{ + return g_mtk_regd_control.channels; +} + +void rlmDomainSetDefaultCountryCode(void) +{ + g_mtk_regd_control.alpha2 = COUNTRY_CODE_WW; +} + +void rlmDomainResetCtrlInfo(u8 force) +{ + if ((g_mtk_regd_control.state == REGD_STATE_UNDEFINED) || (force == true)) { + memset(&g_mtk_regd_control, 0, sizeof(mtk_regd_control)); + + g_mtk_regd_control.state = REGD_STATE_INIT; + + rlmDomainSetDefaultCountryCode(); + +#if (CFG_SUPPORT_SINGLE_SKU_LOCAL_DB == 1) + g_mtk_regd_control.flag |= REGD_CTRL_FLAG_SUPPORT_LOCAL_REGD_DB; +#endif + } +} + +u8 rlmDomainIsUsingLocalRegDomainDataBase(void) +{ +#if (CFG_SUPPORT_SINGLE_SKU_LOCAL_DB == 1) + return (g_mtk_regd_control.flag & REGD_CTRL_FLAG_SUPPORT_LOCAL_REGD_DB) ? + true : + false; + +#else + return false; + +#endif +} + +bool rlmDomainIsSameCountryCode(char *alpha2, u8 size_of_alpha2) +{ + u8 idx; + u32 alpha2_hex = 0; + + for (idx = 0; idx < size_of_alpha2; idx++) + alpha2_hex |= (alpha2[idx] << (idx * 8)); + + return (rlmDomainGetCountryCode() == alpha2_hex) ? true : false; +} + +void rlmDomainSetCountryCode(char *alpha2, u8 size_of_alpha2) +{ + u8 max; + u8 buf_size; + + buf_size = sizeof(g_mtk_regd_control.alpha2); + max = (buf_size < size_of_alpha2) ? buf_size : size_of_alpha2; + + g_mtk_regd_control.alpha2 = rlmDomainAlpha2ToU32(alpha2, max); +} +void rlmDomainSetDfsRegion(enum nl80211_dfs_regions dfs_region) +{ + g_mtk_regd_control.dfs_region = dfs_region; +} + +enum nl80211_dfs_regions rlmDomainGetDfsRegion(void) +{ + return g_mtk_regd_control.dfs_region; +} + +void rlmDomainSetTempCountryCode(char *alpha2, u8 size_of_alpha2) +{ + u8 idx, max; + u8 buf_size; + + buf_size = sizeof(g_mtk_regd_control.tmp_alpha2); + max = (buf_size < size_of_alpha2) ? buf_size : size_of_alpha2; + + g_mtk_regd_control.tmp_alpha2 = 0; + + for (idx = 0; idx < max; idx++) + g_mtk_regd_control.tmp_alpha2 |= (alpha2[idx] << (idx * 8)); +} + +enum regd_state rlmDomainStateTransition(enum regd_state request_state, + struct regulatory_request *pRequest) +{ + enum regd_state next_state, old_state; +#if !DBG_DISABLE_ALL_LOG + bool the_same = 0; +#endif + + old_state = g_mtk_regd_control.state; + next_state = REGD_STATE_INVALID; + + if (old_state == REGD_STATE_INVALID) { + DBGLOG(RLM, ERROR, "%s(): invalid state. trasntion is not allowed.\n", + __func__); + } + + switch (request_state) { + case REGD_STATE_SET_WW_CORE: + if ((old_state == REGD_STATE_SET_WW_CORE) || + (old_state == REGD_STATE_INIT) || + old_state == REGD_STATE_SET_COUNTRY_USER || + old_state == REGD_STATE_SET_COUNTRY_IE) { + next_state = request_state; + } + + break; + + case REGD_STATE_SET_COUNTRY_USER: + /* Allow user to set multiple times */ + if ((old_state == REGD_STATE_SET_WW_CORE) || + (old_state == REGD_STATE_INIT) || + old_state == REGD_STATE_SET_COUNTRY_USER || + old_state == REGD_STATE_SET_COUNTRY_IE) { + next_state = request_state; + } else { + DBGLOG(RLM, ERROR, "Invalid old state = %d\n", old_state); + } + break; + + case REGD_STATE_SET_COUNTRY_DRIVER: + if (old_state == REGD_STATE_SET_COUNTRY_USER) { + /* + * Error. + * Mixing using set_country_by_user and + * set_country_by_driver is not allowed. + */ + break; + } + + next_state = request_state; + break; + + case REGD_STATE_SET_COUNTRY_IE: + next_state = request_state; + break; + + default: + break; + } + + if (next_state == REGD_STATE_INVALID) { + DBGLOG(RLM, ERROR, + "%s(): ERROR. trasntion to invalid state. o=%x, r=%x, s=%x\n", + __func__, old_state, request_state, the_same); + } else { + DBGLOG(RLM, INFO, "%s(): trasntion to state = %x (old = %x)\n", + __func__, next_state, g_mtk_regd_control.state); + } + + g_mtk_regd_control.state = next_state; + + return g_mtk_regd_control.state; +} + +/** + * rlmDomainChannelFlagString - Transform channel flags to readable string + * + * @ flags: the ieee80211_channel->flags for a channel + * @ buf: string buffer to put the transformed string + * @ buf_size: size of the buf + **/ +void rlmDomainChannelFlagString(u32 flags, char *buf, size_t buf_size) +{ + s32 buf_written = 0; + + if (!flags || !buf || !buf_size) { + return; + } + + if (flags & IEEE80211_CHAN_DISABLED) { + LOGBUF(buf, ((s32)buf_size), buf_written, "DISABLED "); + /* If DISABLED, don't need to check other flags */ + return; + } + if (flags & IEEE80211_CHAN_NO_IR) { + LOGBUF(buf, ((s32)buf_size), buf_written, "NO_IR "); + } + if (flags & IEEE80211_CHAN_RADAR) { + LOGBUF(buf, ((s32)buf_size), buf_written, "RADAR "); + } + if (flags & IEEE80211_CHAN_NO_HT40PLUS) { + LOGBUF(buf, ((s32)buf_size), buf_written, "NO_HT40PLUS "); + } + if (flags & IEEE80211_CHAN_NO_HT40MINUS) { + LOGBUF(buf, ((s32)buf_size), buf_written, "NO_HT40MINUS "); + } + if (flags & IEEE80211_CHAN_NO_80MHZ) { + LOGBUF(buf, ((s32)buf_size), buf_written, "NO_80MHZ "); + } + if (flags & IEEE80211_CHAN_NO_160MHZ) { + LOGBUF(buf, ((s32)buf_size), buf_written, "NO_160MHZ "); + } +} + +void rlmDomainParsingChannel(IN struct wiphy *pWiphy) +{ + u32 band_idx, ch_idx; + u32 ch_count; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + struct channel *pCh; + char chan_flag_string[64] = { 0 }; + P_GLUE_INFO_T prGlueInfo; + u8 ucChannelNum = 0; + u8 fgDisconnection = false; + WLAN_STATUS rStatus; + u32 u4BufLen; + + if (!pWiphy) { + DBGLOG(RLM, ERROR, "%s(): ERROR. pWiphy = NULL.\n", __func__); + ASSERT(0); + return; + } + + /* Retrieve connected channel */ + prGlueInfo = rlmDomainGetGlueInfo(); + if (prGlueInfo && + kalGetMediaStateIndicated(prGlueInfo) == PARAM_MEDIA_STATE_CONNECTED) { + ucChannelNum = wlanGetChannelNumberByNetwork( + prGlueInfo->prAdapter, + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + } + + /* + * Ready to parse the channel for bands + */ + + rlmDomainResetActiveChannel(); + + ch_count = 0; + for (band_idx = 0; band_idx < NUM_NL80211_BANDS; band_idx++) { + sband = pWiphy->bands[band_idx]; + if (!sband) { + continue; + } + + for (ch_idx = 0; ch_idx < sband->n_channels; ch_idx++) { + chan = &sband->channels[ch_idx]; + pCh = (rlmDomainGetActiveChannels() + ch_count); + /* Parse flags and get readable string */ + rlmDomainChannelFlagString(chan->flags, chan_flag_string, + sizeof(chan_flag_string)); + + if (chan->flags & IEEE80211_CHAN_DISABLED) { + DBGLOG(RLM, INFO, + "channels[%d][%d]: ch%d (freq = %d) flags=0x%x [ %s]\n", + band_idx, ch_idx, chan->hw_value, chan->center_freq, + chan->flags, chan_flag_string); + + /* Disconnect AP in the end of this function*/ + if (chan->hw_value == ucChannelNum) { + fgDisconnection = true; + } + + continue; + } + + /* Allowable channel */ + if (ch_count == MAX_SUPPORTED_CH_COUNT) { + DBGLOG(RLM, ERROR, + "%s(): no buffer to store channel information.\n", + __func__); + break; + } + + rlmDomainAddActiveChannel(band_idx); + + DBGLOG(RLM, INFO, + "channels[%d][%d]: ch%d (freq = %d) flgs=0x%x [ %s]\n", + band_idx, ch_idx, chan->hw_value, chan->center_freq, + chan->flags, chan_flag_string); + + pCh->chNum = chan->hw_value; + pCh->flags = chan->flags; + + ch_count += 1; + } + } + + /* Disconnect with AP if connected channel is disabled in new country */ + if (fgDisconnection) { + DBGLOG(RLM, STATE, "Disconnect! CH%d is DISABLED in this country\n", + ucChannelNum); + rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, false, + false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(RLM, WARN, "disassociate error:%lx\n", rStatus); + } + } +} +void rlmExtractChannelInfo(u32 max_ch_count, + struct acctive_channel_list *prBuff) +{ + u32 ch_count, idx; + struct channel *pCh; + + prBuff->n_channels_2g = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ); + prBuff->n_channels_5g = rlmDomainGetActiveChannelCount(NL80211_BAND_5GHZ); + ch_count = prBuff->n_channels_2g + prBuff->n_channels_5g; + + if (ch_count > max_ch_count) { + ch_count = max_ch_count; + DBGLOG(RLM, WARN, "%s(); active channel list is not a complete one.\n", + __func__); + } + + for (idx = 0; idx < ch_count; idx++) { + pCh = &(prBuff->channels[idx]); + + pCh->chNum = (rlmDomainGetActiveChannels() + idx)->chNum; + pCh->flags = (rlmDomainGetActiveChannels() + idx)->flags; + } +} + +const struct ieee80211_regdomain * +rlmDomainSearchRegdomainFromLocalDataBase(char *alpha2) +{ +#if (CFG_SUPPORT_SINGLE_SKU_LOCAL_DB == 1) + u8 idx; + const struct mtk_regdomain *prRegd; + + idx = 0; + while (g_prRegRuleTable[idx]) { + prRegd = g_prRegRuleTable[idx]; + + if ((prRegd->country_code[0] == alpha2[0]) && + (prRegd->country_code[1] == alpha2[1]) && + (prRegd->country_code[2] == alpha2[2]) && + (prRegd->country_code[3] == alpha2[3])) { + return prRegd->prRegdRules; + } + + idx++; + } + + DBGLOG(RLM, INFO, + "%s(): Error, Cannot find the correct RegDomain. country = %s.\n", + __func__, alpha2); + DBGLOG(RLM, INFO, " Set as default WW.\n"); + + return &default_regdom_ww; /*default world wide*/ + +#else + return NULL; + +#endif +} + +const struct ieee80211_regdomain *rlmDomainGetLocalDefaultRegd(void) +{ +#if (CFG_SUPPORT_SINGLE_SKU_LOCAL_DB == 1) + const struct ieee80211_regdomain *pRegdom; + u32 country_code = rlmDomainGetCountryCode(); + char alpha2[4]; + + /*fetch regulatory rules from local data base*/ + alpha2[0] = country_code & 0xFF; + alpha2[1] = (country_code >> 8) & 0xFF; + alpha2[2] = (country_code >> 16) & 0xFF; + alpha2[3] = (country_code >> 24) & 0xFF; + + pRegdom = rlmDomainSearchRegdomainFromLocalDataBase(alpha2); + if (!pRegdom) { + DBGLOG(RLM, INFO, + "%s(): Error, Cannot find the correct RegDomain. country = %s\n", + __func__, rlmDomainGetCountryCode()); + return &default_regdom_ww; + } + + return pRegdom; + +#else + return NULL; + +#endif +} +P_GLUE_INFO_T rlmDomainGetGlueInfo(void) +{ + return g_mtk_regd_control.pGlueInfo; +} + +bool rlmDomainIsEfuseUsed(void) +{ + return g_mtk_regd_control.isEfuseCountryCodeUsed; +} + +u8 rlmDomainGetChannelBw(u8 channelNum) +{ + u32 ch_idx = 0, start_idx = 0, end_idx = 0; + u32 channelBw = MAX_BW_80_80_MHZ; + struct channel *pCh; + + end_idx = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ) + + rlmDomainGetActiveChannelCount(NL80211_BAND_5GHZ); + + for (ch_idx = start_idx; ch_idx < end_idx; ch_idx++) { + pCh = (rlmDomainGetActiveChannels() + ch_idx); + + if (pCh->chNum != channelNum) { + continue; + } + + /* Max BW */ + if ((pCh->flags & IEEE80211_CHAN_NO_160MHZ) == + IEEE80211_CHAN_NO_160MHZ) { + channelBw = MAX_BW_80MHZ; + } + if ((pCh->flags & IEEE80211_CHAN_NO_80MHZ) == IEEE80211_CHAN_NO_80MHZ) { + channelBw = MAX_BW_40MHZ; + } + if ((pCh->flags & IEEE80211_CHAN_NO_HT40) == IEEE80211_CHAN_NO_HT40) { + channelBw = MAX_BW_20MHZ; + break; + } + + if (pCh->chNum > rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ)) { + u16 u2Bw40 = (pCh->chNum >> 2) & 0x1; /* 1, 0 */ + u16 u2Bw80 = (pCh->chNum >> 2) & 0x3; /* 1, 2, 3, 0 */ + + if (channelBw > MAX_BW_20MHZ) { + /* MAX_BW_40MHz/MAX_BW_80MHz */ + if ((u2Bw40) && (pCh->flags & IEEE80211_CHAN_NO_HT40PLUS)) { + channelBw = MAX_BW_20MHZ; + break; + } + + if ((!u2Bw40) && (pCh->flags & IEEE80211_CHAN_NO_HT40MINUS)) { + channelBw = MAX_BW_20MHZ; + break; + } + } else { + break; + } + + if (channelBw > MAX_BW_40MHZ) { + /* MAX_BW_80MHz */ + struct channel *pAdj40Chnl = NULL, *pAdj20Chnl = NULL; + s32 ch_idx_offset = 0; + + switch (u2Bw80) { + case 1: + /* Check if 2 boundary. */ + ch_idx_offset = 1; + ASSERT((ch_idx + ch_idx_offset) < end_idx); + pAdj20Chnl = + (rlmDomainGetActiveChannels() + ch_idx + ch_idx_offset); + + /* FALLTHRU */ + case 2: + /* Check if 3 20MHz only. */ + ch_idx_offset++; + break; + + case 0: + /* Check if 3 boundary. */ + ch_idx_offset = -1; + ASSERT((ch_idx + ch_idx_offset) < end_idx); + pAdj20Chnl = + (rlmDomainGetActiveChannels() + ch_idx + ch_idx_offset); + + /* FALLTHRU */ + case 3: + ch_idx_offset--; + + /* Check if 2 only 20MHz */ + default: + break; + } + ASSERT((ch_idx + ch_idx_offset) < end_idx); + pAdj40Chnl = + (rlmDomainGetActiveChannels() + ch_idx + ch_idx_offset); + + if ((pAdj20Chnl) && + (pAdj20Chnl->flags & (IEEE80211_CHAN_NO_HT40PLUS | + IEEE80211_CHAN_NO_HT40MINUS))) { + channelBw = MAX_BW_40MHZ; + break; + } + + if ((pAdj40Chnl) && + (pAdj40Chnl->flags & (IEEE80211_CHAN_NO_HT40PLUS | + IEEE80211_CHAN_NO_HT40MINUS))) { + channelBw = MAX_BW_40MHZ; + break; + } + } + } + } + + DBGLOG(RLM, INFO, "ch=%d, BW=%d\n", channelNum, channelBw); + return channelBw; +} + +#endif + +WLAN_STATUS rlmDomainExtractSingleSkuInfoFromFirmware(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ +#if (CFG_SUPPORT_SINGLE_SKU == 1) + P_SINGLE_SKU_INFO prSkuInfo = (P_SINGLE_SKU_INFO)pucEventBuf; + if (u4EventBufLen < sizeof(SINGLE_SKU_INFO)) { + DBGLOG(RLM, ERROR, "%s(): Invalid length:%d < %d\n", __func__, + u4EventBufLen, sizeof(SINGLE_SKU_INFO)); + return WLAN_STATUS_FAILURE; + } + DBGLOG(RLM, INFO, + "%s(): Info. Enable regulatory database control.\n", + __func__); + g_mtk_regd_control.en = true; + + if (prSkuInfo->isEfuseValid) { + if (!rlmDomainIsUsingLocalRegDomainDataBase()) { + DBGLOG(RLM, ERROR, + "%s(): Error. In efuse mode, must use local data base.\n", + __func__); + + ASSERT(0); + return WLAN_STATUS_NOT_SUPPORTED; /*force using local db + * if getting country + * code from efuse*/ + } + + DBGLOG(RLM, INFO, + "%s(): Info. Using EFuse country code.\n", + __func__); + rlmDomainSetCountryCode((char *)&prSkuInfo->u4EfuseCountryCode, + sizeof(prSkuInfo->u4EfuseCountryCode)); + g_mtk_regd_control.isEfuseCountryCodeUsed = true; + } +#endif + + return WLAN_STATUS_SUCCESS; +} + +void rlmDomainSendInfoToFirmware(IN P_ADAPTER_T prAdapter) +{ +#if (CFG_SUPPORT_SINGLE_SKU == 1) + struct regulatory_request request; + struct regulatory_request *prReq = NULL; + + if (!regd_is_single_sku_en()) { + return; /*not support single sku*/ + } + if (rlmDomainIsEfuseUsed()) { + request.initiator = NL80211_REGDOM_SET_BY_DRIVER; + prReq = &request; + } + + g_mtk_regd_control.pGlueInfo = prAdapter->prGlueInfo; + mtk_reg_notify(priv_to_wiphy(prAdapter->prGlueInfo), prReq); +#endif +} + +ENUM_CHNL_EXT_T rlmSelectSecondaryChannelType(P_ADAPTER_T prAdapter, + ENUM_BAND_T band, u8 primary_ch) +{ +#if (CFG_SUPPORT_SINGLE_SKU == 1) + u8 below_ch, above_ch; + + below_ch = primary_ch - CHNL_SPAN_20; + above_ch = primary_ch + CHNL_SPAN_20; + + if (rlmDomainIsLegalChannel(prAdapter, band, above_ch)) { + return CHNL_EXT_SCA; + } + + if (rlmDomainIsLegalChannel(prAdapter, band, below_ch)) { + return CHNL_EXT_SCB; + } + +#endif + + return CHNL_EXT_SCN; +} + +void rlmDomainOidSetCountry(IN P_ADAPTER_T prAdapter, char *country, + u8 size_of_country) +{ +#if (CFG_SUPPORT_SINGLE_SKU == 1) + struct regulatory_request request; + + if (rlmDomainIsUsingLocalRegDomainDataBase()) { + rlmDomainSetTempCountryCode(country, size_of_country); + request.initiator = NL80211_REGDOM_SET_BY_DRIVER; + mtk_reg_notify(priv_to_wiphy(prAdapter->prGlueInfo), &request); + } else { + DBGLOG(RLM, INFO, + "%s(): Using driver hint to query CRDA getting regd.\n", + __func__); + regulatory_hint(priv_to_wiphy(prAdapter->prGlueInfo), country); + } +#endif +} + +u32 rlmDomainGetCountryCode(void) +{ +#if (CFG_SUPPORT_SINGLE_SKU == 1) + return g_mtk_regd_control.alpha2; + +#else + return 0; + +#endif +} + +u32 rlmDomainGetTempCountryCode(void) +{ +#if (CFG_SUPPORT_SINGLE_SKU == 1) + return g_mtk_regd_control.tmp_alpha2; + +#else + return 0; + +#endif +} + +void rlmDomainAssert(u8 cond) +{ + /* bypass this check because single sku is not enable */ + if (!regd_is_single_sku_en()) { + return; + } + + if (!cond) { + WARN_ON(1); + DBGLOG(RLM, ERROR, "[WARNING!!] RLM unexpected case.\n"); + } +} + +void rlmDomainOverridePwrLimitFileName(const char *tx_pwr_limit_file_override) +{ + g_tx_pwr_limit_file = tx_pwr_limit_file_override; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rlm_obss.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rlm_obss.c new file mode 100644 index 00000000000000..19600571bcf2ee --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rlm_obss.c @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "rlm_obss.c" + * \brief + * + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +static void rlmObssScanTimeout(P_ADAPTER_T prAdapter, unsigned long ulParamPtr); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmObssInit(P_ADAPTER_T prAdapter) +{ + P_BSS_INFO_T prBssInfo; + u8 i; + + for (i = 0; i < BSS_INFO_NUM; i++) { + prBssInfo = prAdapter->aprBssInfo[i]; + + cnmTimerInitTimer(prAdapter, &prBssInfo->rObssScanTimer, + (PFN_MGMT_TIMEOUT_FUNC)rlmObssScanTimeout, + (unsigned long)prBssInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u8 rlmObssUpdateChnlLists(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) +{ + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmObssScanDone(P_ADAPTER_T prAdapter, P_MSG_HDR_T prMsgHdr) +{ + P_MSG_SCN_SCAN_DONE prScanDoneMsg; + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + P_ACTION_20_40_COEXIST_FRAME prTxFrame; + u16 i, u2PayloadLen; + + ASSERT(prMsgHdr); + + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE)prMsgHdr; + prBssInfo = prAdapter->aprBssInfo[prScanDoneMsg->ucBssIndex]; + ASSERT(prBssInfo); + + DBGLOG(RLM, INFO, "OBSS Scan Done (NetIdx=%d, Mode=%d)\n", + prScanDoneMsg->ucBssIndex, prBssInfo->eCurrentOPMode); + + cnmMemFree(prAdapter, prMsgHdr); + +#if CFG_ENABLE_WIFI_DIRECT + /* AP mode */ + if ((prAdapter->fgIsP2PRegistered) && + (IS_NET_ACTIVE(prAdapter, prBssInfo->ucBssIndex)) && + (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { + return; + } +#endif + + /* STA mode */ + if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE || + !RLM_NET_PARAM_VALID(prBssInfo) || + prBssInfo->u2ObssScanInterval == 0) { + DBGLOG(RLM, WARN, "OBSS Scan Done (NetIdx=%d) -- Aborted!!\n", + prBssInfo->ucBssIndex); + return; + } + + /* To do: check 2.4G channel list to decide if obss mgmt should be + * sent to associated AP. Note: how to handle concurrent network? + * To do: invoke rlmObssChnlLevel() to decide if 20/40 BSS coexistence + * management frame is needed. + */ + if (prBssInfo->auc2G_20mReqChnlList[0] > 0 || + prBssInfo->auc2G_NonHtChnlList[0] > 0) { + DBGLOG(RLM, INFO, + "Send 20/40 coexistence mgmt(20mReq=%d, NonHt=%d)\n", + prBssInfo->auc2G_20mReqChnlList[0], + prBssInfo->auc2G_NonHtChnlList[0]); + + prMsduInfo = (P_MSDU_INFO_T)cnmMgtPktAlloc( + prAdapter, + MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + + if (prMsduInfo) { + prTxFrame = + (P_ACTION_20_40_COEXIST_FRAME)((unsigned long)( + prMsduInfo + -> + prPacket) + + + MAC_TX_RESERVED_FIELD); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + COPY_MAC_ADDR(prTxFrame->aucDestAddr, + prBssInfo->aucBSSID); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, + prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_PUBLIC_ACTION; + prTxFrame->ucAction = ACTION_PUBLIC_20_40_COEXIST; + + /* To do: find correct algorithm */ + prTxFrame->rBssCoexist.ucId = + ELEM_ID_20_40_BSS_COEXISTENCE; + prTxFrame->rBssCoexist.ucLength = 1; + prTxFrame->rBssCoexist.ucData = + (prBssInfo->auc2G_20mReqChnlList[0] > 0) ? + BSS_COEXIST_20M_REQ : + 0; + + u2PayloadLen = 2 + 3; + + if (prBssInfo->auc2G_NonHtChnlList[0] > 0) { + ASSERT(prBssInfo->auc2G_NonHtChnlList[0] <= + CHNL_LIST_SZ_2G); + + prTxFrame->rChnlReport.ucId = + ELEM_ID_20_40_INTOLERANT_CHNL_REPORT; + prTxFrame->rChnlReport.ucLength = + prBssInfo->auc2G_NonHtChnlList[0] + 1; + prTxFrame->rChnlReport.ucRegulatoryClass = + 81; /* 2.4GHz, ch1~13 */ + for (i = 0; + i < prBssInfo->auc2G_NonHtChnlList[0] && + i < CHNL_LIST_SZ_2G; + i++) + prTxFrame->rChnlReport + .aucChannelList[i] = + prBssInfo->auc2G_NonHtChnlList + [i + 1]; + + u2PayloadLen += + IE_SIZE(&prTxFrame->rChnlReport); + } + ASSERT((WLAN_MAC_HEADER_LEN + u2PayloadLen) <= + PUBLIC_ACTION_MAX_LEN); + + /* Clear up channel lists in 2.4G band */ + prBssInfo->auc2G_20mReqChnlList[0] = 0; + prBssInfo->auc2G_NonHtChnlList[0] = 0; + + /* 4 Update information of MSDU_INFO_T */ + + TX_SET_MMPDU(prAdapter, prMsduInfo, + prBssInfo->ucBssIndex, + prBssInfo->prStaRecOfAP->ucIndex, + WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, + NULL, MSDU_RATE_MODE_AUTO); + + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + } + } + /* end of prMsduInfo != NULL */ + if (prBssInfo->u2ObssScanInterval > 0) { + DBGLOG(RLM, INFO, "Set OBSS timer (NetIdx=%d, %d sec)\n", + prBssInfo->ucBssIndex, prBssInfo->u2ObssScanInterval); + + cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, + prBssInfo->u2ObssScanInterval * + MSEC_PER_SEC); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +static void rlmObssScanTimeout(P_ADAPTER_T prAdapter, unsigned long ulParamPtr) +{ + P_BSS_INFO_T prBssInfo; + + prBssInfo = (P_BSS_INFO_T)ulParamPtr; + ASSERT(prBssInfo); + +#if CFG_ENABLE_WIFI_DIRECT + /* AP mode */ + if (prAdapter->fgIsP2PRegistered && + (IS_NET_ACTIVE(prAdapter, prBssInfo->ucBssIndex)) && + (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { + prBssInfo->fgObssActionForcedTo20M = false; + + /* Check if Beacon content need to be updated */ + rlmUpdateParamsForAP(prAdapter, prBssInfo, false); + + return; + } +#if CFG_SUPPORT_WFD + /* WFD streaming */ + else { + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = + &prAdapter->rWifiVar.rWfdConfigureSettings; + + /* If WFD is enabled & connected */ + if (prWfdCfgSettings->ucWfdEnable) { + /* Skip OBSS scan */ + prBssInfo->u2ObssScanInterval = 0; + DBGLOG(RLM, INFO, "WFD is running. Stop OBSS scan.\n"); + return; + } /* WFD is enabled */ + } +#endif +#endif + + /* STA mode */ + if (prBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE || + !RLM_NET_PARAM_VALID(prBssInfo) || + prBssInfo->u2ObssScanInterval == 0) { + DBGLOG(RLM, WARN, + "OBSS Scan timeout (NetIdx=%d) -- Aborted!!\n", + prBssInfo->ucBssIndex); + return; + } + + rlmObssTriggerScan(prAdapter, prBssInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rlmObssTriggerScan(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + P_MSG_SCN_SCAN_REQ prScanReqMsg; + + ASSERT(prBssInfo); + + prScanReqMsg = (P_MSG_SCN_SCAN_REQ)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(MSG_SCN_SCAN_REQ)); + ASSERT(prScanReqMsg); + + if (!prScanReqMsg) { + DBGLOG(RLM, WARN, "No buf for OBSS scan (NetIdx=%d)!!\n", + prBssInfo->ucBssIndex); + + cnmTimerStartTimer(prAdapter, &prBssInfo->rObssScanTimer, + prBssInfo->u2ObssScanInterval * + MSEC_PER_SEC); + return; + } + + /* It is ok that ucSeqNum is set to fixed value because the same network + * OBSS scan interval is limited to OBSS_SCAN_MIN_INTERVAL (min 10 sec) + * and scan module don't care seqNum of OBSS scanning + */ + prScanReqMsg->rMsgHdr.eMsgId = MID_RLM_SCN_SCAN_REQ; + prScanReqMsg->ucSeqNum = 0x33; + prScanReqMsg->ucBssIndex = prBssInfo->ucBssIndex; + prScanReqMsg->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prScanReqMsg->ucSSIDType = SCAN_REQ_SSID_WILDCARD; + prScanReqMsg->ucSSIDLength = 0; + prScanReqMsg->eScanChannel = SCAN_CHANNEL_2G4; + prScanReqMsg->u2IELen = 0; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prScanReqMsg, + MSG_SEND_METHOD_BUF); + + DBGLOG(RLM, INFO, "Timeout to trigger OBSS scan (NetIdx=%d)!!\n", + prBssInfo->ucBssIndex); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/roaming_fsm.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/roaming_fsm.c new file mode 100644 index 00000000000000..2f396c0f22c564 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/roaming_fsm.c @@ -0,0 +1,646 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "roaming_fsm.c" + * \brief This file defines the FSM for Roaming MODULE. + * + * This file defines the FSM for Roaming MODULE. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +#if CFG_SUPPORT_ROAMING +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +#if !DBG_DISABLE_ALL_LOG +static u8 *apucDebugRoamingState[ROAMING_STATE_NUM] = { + (u8 *)DISP_STRING("IDLE"), (u8 *)DISP_STRING("DECISION"), + (u8 *)DISP_STRING("DISCOVERY"), (u8 *)DISP_STRING("ROAM") +}; +#endif + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Initialize the value in ROAMING_FSM_INFO_T for ROAMING FSM operation + * + * @param [IN P_ADAPTER_T] prAdapter + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void roamingFsmInit(IN P_ADAPTER_T prAdapter) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + + DBGLOG(ROAMING, LOUD, "->roamingFsmInit(): Current Time = %ld\n", + kalGetTimeTick()); + + prRoamingFsmInfo = (P_ROAMING_INFO_T)& + (prAdapter->rWifiVar.rRoamingInfo); + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + /* 4 <1> Initiate FSM */ + prRoamingFsmInfo->fgIsEnableRoaming = prConnSettings->fgIsEnableRoaming; + prRoamingFsmInfo->eCurrentState = ROAMING_STATE_IDLE; + prRoamingFsmInfo->rRoamingDiscoveryUpdateTime = 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Uninitialize the value in AIS_FSM_INFO_T for AIS FSM operation + * + * @param [IN P_ADAPTER_T] prAdapter + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void roamingFsmUninit(IN P_ADAPTER_T prAdapter) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + + DBGLOG(ROAMING, LOUD, "->roamingFsmUninit(): Current Time = %ld\n", + kalGetTimeTick()); + + prRoamingFsmInfo = (P_ROAMING_INFO_T)& + (prAdapter->rWifiVar.rRoamingInfo); + + prRoamingFsmInfo->eCurrentState = ROAMING_STATE_IDLE; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Send commands to firmware + * + * @param [IN P_ADAPTER_T] prAdapter + * [IN P_ROAMING_PARAM_T] prParam + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void roamingFsmSendCmd(IN P_ADAPTER_T prAdapter, + IN P_CMD_ROAMING_TRANSIT_T prTransit) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + WLAN_STATUS rStatus; + + DBGLOG(ROAMING, LOUD, "->roamingFsmSendCmd(): Current Time = %ld\n", + kalGetTimeTick()); + + prRoamingFsmInfo = (P_ROAMING_INFO_T)& + (prAdapter->rWifiVar.rRoamingInfo); + + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_ROAMING_TRANSIT, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_ROAMING_TRANSIT_T), /* u4SetQueryInfoLen + */ + (u8 *)prTransit, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + /* ASSERT(rStatus == WLAN_STATUS_PENDING); */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Update the recent time when ScanDone occurred + * + * @param [IN P_ADAPTER_T] prAdapter + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void roamingFsmScanResultsUpdate(IN P_ADAPTER_T prAdapter) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + + prRoamingFsmInfo = (P_ROAMING_INFO_T)& + (prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + if (!(prRoamingFsmInfo->fgIsEnableRoaming)) { + return; + } + + DBGLOG(ROAMING, LOUD, + "->roamingFsmScanResultsUpdate(): Current Time = %ld\n", + kalGetTimeTick()); + + GET_CURRENT_SYSTIME(&prRoamingFsmInfo->rRoamingDiscoveryUpdateTime); +} + +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP +/*----------------------------------------------------------------------------*/ +/* + * @brief Check if need to do scan for roaming + * + * @param[out] fgIsNeedScan Set to true if need to scan since + * there is roaming candidate in current scan result or skip roaming times > + * limit times + * @return + */ +/*----------------------------------------------------------------------------*/ +static u8 roamingFsmIsNeedScan(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prRoamBSSDescList; + P_ROAM_BSS_DESC_T prRoamBssDesc; + P_BSS_INFO_T prAisBssInfo; + P_BSS_DESC_T prBssDesc; + /*CMD_SW_DBG_CTRL_T rCmdSwCtrl;*/ + CMD_ROAMING_SKIP_ONE_AP_T rCmdRoamingSkipOneAP; + u8 fgIsNeedScan, fgIsRoamingSSID; + + fgIsNeedScan = false; + fgIsRoamingSSID = false; /*Whether there's roaming candidate in + * RoamBssDescList*/ + + kalMemZero(&rCmdRoamingSkipOneAP, sizeof(CMD_ROAMING_SKIP_ONE_AP_T)); + + prAisBssInfo = prAdapter->prAisBssInfo; + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prRoamBSSDescList = &prScanInfo->rRoamBSSDescList; + /* <1> Count same BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prRoamBssDesc, prRoamBSSDescList, rLinkEntry, + ROAM_BSS_DESC_T) { + if (EQUAL_SSID(prRoamBssDesc->aucSSID, prRoamBssDesc->ucSSIDLen, + prAisBssInfo->aucSSID, + prAisBssInfo->ucSSIDLen)) { + fgIsRoamingSSID = true; + fgIsNeedScan = true; + DBGLOG(ROAMING, INFO, + "roamingFsmSteps: IsRoamingSSID:%d\n", + fgIsRoamingSSID); + break; + } + } + + /* <2> Start skip roaming scan mechanism if there is no candidate in + * current SCAN result list */ + if (!fgIsRoamingSSID) { + prBssDesc = scanSearchBssDescByBssid( + prAdapter, prAisBssInfo->aucBSSID); /* Get current + * BssDesc */ + if (prBssDesc) { + /*rCmdSwCtrl.u4Id = 0xa0280000;*/ + /*rCmdSwCtrl.u4Data = 0x1;*/ + rCmdRoamingSkipOneAP.fgIsRoamingSkipOneAP = 1; + + DBGLOG(ROAMING, INFO, + "roamingFsmSteps: RCPI:%d RoamSkipTimes:%d\n", + prBssDesc->ucRCPI, + prAisBssInfo->ucRoamSkipTimes); + if (prBssDesc->ucRCPI > 90) { /* Set parameters related + * to Good Area */ + prAisBssInfo->ucRoamSkipTimes = 3; + prAisBssInfo->fgGoodRcpiArea = true; + prAisBssInfo->fgPoorRcpiArea = false; + } else { + if (prAisBssInfo->fgGoodRcpiArea) { + prAisBssInfo->ucRoamSkipTimes--; + } else if (prBssDesc->ucRCPI > 67) { + if (!prAisBssInfo + ->fgPoorRcpiArea) { /* Set + * parameters + * related + * to + * Poor + * Area + */ + prAisBssInfo->ucRoamSkipTimes = + 2; + prAisBssInfo->fgPoorRcpiArea = + true; + prAisBssInfo->fgGoodRcpiArea = + false; + } else { + prAisBssInfo->ucRoamSkipTimes--; + } + } else { + prAisBssInfo->fgPoorRcpiArea = false; + prAisBssInfo->fgGoodRcpiArea = false; + prAisBssInfo->ucRoamSkipTimes--; + } + } + + if (prAisBssInfo->ucRoamSkipTimes == 0) { + prAisBssInfo->ucRoamSkipTimes = 3; + prAisBssInfo->fgPoorRcpiArea = false; + prAisBssInfo->fgGoodRcpiArea = false; + DBGLOG(ROAMING, INFO, + "roamingFsmSteps: Need Scan\n"); + fgIsNeedScan = true; + } else { + wlanSendSetQueryCmd( + prAdapter, CMD_ID_SET_ROAMING_SKIP, + true, false, false, NULL, NULL, + sizeof(CMD_ROAMING_SKIP_ONE_AP_T), + (u8 *)&rCmdRoamingSkipOneAP, NULL, 0); + } + } else { + DBGLOG(ROAMING, + WARN, + "Can't find the current associated AP in BssDescList\n"); + } + } + + return fgIsNeedScan; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief The Core FSM engine of ROAMING for AIS Infra. + * + * @param [IN P_ADAPTER_T] prAdapter + * [IN ENUM_ROAMING_STATE_T] eNextState Enum value of next AIS STATE + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void roamingFsmSteps(IN P_ADAPTER_T prAdapter, + IN ENUM_ROAMING_STATE_T eNextState) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T ePreviousState; + u8 fgIsTransition = (u8)false; + u8 fgIsNeedScan = false; + + prRoamingFsmInfo = (P_ROAMING_INFO_T)& + (prAdapter->rWifiVar.rRoamingInfo); + + do { + /* Do entering Next State */ + DBGLOG(ROAMING, STATE, "[ROAMING]TRANSITION: [%s] -> [%s]\n", + apucDebugRoamingState[prRoamingFsmInfo->eCurrentState], + apucDebugRoamingState[eNextState]); + + /* NOTE(Kevin): This is the only place to change the + * eCurrentState(except initial) */ + ePreviousState = prRoamingFsmInfo->eCurrentState; + prRoamingFsmInfo->eCurrentState = eNextState; + + fgIsTransition = (u8)false; + + /* Do tasks of the State that we just entered */ + switch (prRoamingFsmInfo->eCurrentState) { + /* NOTE(Kevin): we don't have to rearrange the sequence of + * following switch case. Instead I would like to use a common + * lookup table of array of function pointer to speed up state + * search. + */ + case ROAMING_STATE_IDLE: + case ROAMING_STATE_DECISION: + break; + + case ROAMING_STATE_DISCOVERY: { + u32 rCurrentTime; +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP + fgIsNeedScan = roamingFsmIsNeedScan(prAdapter); +#else + fgIsNeedScan = true; +#endif + + GET_CURRENT_SYSTIME(&rCurrentTime); + if (CHECK_FOR_TIMEOUT( + rCurrentTime, + prRoamingFsmInfo + ->rRoamingDiscoveryUpdateTime, + SEC_TO_SYSTIME( + ROAMING_DISCOVERY_TIMEOUT_SEC)) && + fgIsNeedScan) { + DBGLOG(ROAMING, + LOUD, + "roamingFsmSteps: DiscoveryUpdateTime Timeout\n"); + aisFsmRunEventRoamingDiscovery(prAdapter, true); + } else { + DBGLOG(ROAMING, + LOUD, + "roamingFsmSteps: DiscoveryUpdateTime Updated\n"); + aisFsmRunEventRoamingDiscovery(prAdapter, + false); + } + } break; + + case ROAMING_STATE_ROAM: + break; + + default: + ASSERT(0); /* Make sure we have handle all STATEs */ + } + } while (fgIsTransition); + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Transit to Decision state after join completion + * + * @param [IN P_ADAPTER_T] prAdapter + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void roamingFsmRunEventStart(IN P_ADAPTER_T prAdapter) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + P_BSS_INFO_T prAisBssInfo; + CMD_ROAMING_TRANSIT_T rTransit; + + kalMemZero(&rTransit, sizeof(CMD_ROAMING_TRANSIT_T)); + + prRoamingFsmInfo = (P_ROAMING_INFO_T)& + (prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + if (!(prRoamingFsmInfo->fgIsEnableRoaming)) { + return; + } + + prAisBssInfo = prAdapter->prAisBssInfo; + if (prAisBssInfo->eCurrentOPMode != OP_MODE_INFRASTRUCTURE) { + return; + } + + DBGLOG(ROAMING, EVENT, "EVENT-ROAMING START: Current Time = %ld\n", + kalGetTimeTick()); + + /* IDLE, ROAM -> DECISION */ + /* Errors as DECISION, DISCOVERY -> DECISION */ + if (!(prRoamingFsmInfo->eCurrentState == ROAMING_STATE_IDLE || + prRoamingFsmInfo->eCurrentState == ROAMING_STATE_ROAM)) { + return; + } + + eNextState = ROAMING_STATE_DECISION; + if (eNextState != prRoamingFsmInfo->eCurrentState) { + rTransit.u2Event = ROAMING_EVENT_START; + rTransit.u2Data = prAisBssInfo->ucBssIndex; + roamingFsmSendCmd(prAdapter, + (P_CMD_ROAMING_TRANSIT_T)&rTransit); + + /* Step to next state */ + roamingFsmSteps(prAdapter, eNextState); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Transit to Discovery state when deciding to find a candidate + * + * @param [IN P_ADAPTER_T] prAdapter + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void roamingFsmRunEventDiscovery(IN P_ADAPTER_T prAdapter, + IN P_CMD_ROAMING_TRANSIT_T prTransit) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + + prRoamingFsmInfo = (P_ROAMING_INFO_T)& + (prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + if (!(prRoamingFsmInfo->fgIsEnableRoaming)) { + return; + } + + DBGLOG(ROAMING, EVENT, "EVENT-ROAMING DISCOVERY: Current Time = %ld\n", + kalGetTimeTick()); + + /* DECISION -> DISCOVERY */ + /* Errors as IDLE, DISCOVERY, ROAM -> DISCOVERY */ + if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_DECISION) { + return; + } + + eNextState = ROAMING_STATE_DISCOVERY; + /* DECISION -> DISCOVERY */ + if (eNextState != prRoamingFsmInfo->eCurrentState) { + P_BSS_INFO_T prAisBssInfo; + P_BSS_DESC_T prBssDesc; + + /* sync. rcpi with firmware */ + prAisBssInfo = prAdapter->prAisBssInfo; + prBssDesc = scanSearchBssDescByBssid(prAdapter, + prAisBssInfo->aucBSSID); + if (prBssDesc) { + prBssDesc->ucRCPI = (u8)(prTransit->u2Data & 0xff); + } + + roamingFsmSteps(prAdapter, eNextState); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Transit to Roam state after Scan Done + * + * @param [IN P_ADAPTER_T] prAdapter + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void roamingFsmRunEventRoam(IN P_ADAPTER_T prAdapter) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + CMD_ROAMING_TRANSIT_T rTransit; + + kalMemZero(&rTransit, sizeof(CMD_ROAMING_TRANSIT_T)); + + prRoamingFsmInfo = (P_ROAMING_INFO_T)& + (prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + if (!(prRoamingFsmInfo->fgIsEnableRoaming)) { + return; + } + + DBGLOG(ROAMING, EVENT, "EVENT-ROAMING ROAM: Current Time = %ld\n", + kalGetTimeTick()); + + /* IDLE, ROAM -> DECISION */ + /* Errors as IDLE, DECISION, ROAM -> ROAM */ + if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_DISCOVERY) { + return; + } + + eNextState = ROAMING_STATE_ROAM; + /* DISCOVERY -> ROAM */ + if (eNextState != prRoamingFsmInfo->eCurrentState) { + rTransit.u2Event = ROAMING_EVENT_ROAM; + roamingFsmSendCmd(prAdapter, + (P_CMD_ROAMING_TRANSIT_T)&rTransit); + + /* Step to next state */ + roamingFsmSteps(prAdapter, eNextState); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Transit to Decision state as being failed to find out any candidate + * + * @param [IN P_ADAPTER_T] prAdapter + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void roamingFsmRunEventFail(IN P_ADAPTER_T prAdapter, IN u32 u4Param) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + CMD_ROAMING_TRANSIT_T rTransit; + + kalMemZero(&rTransit, sizeof(CMD_ROAMING_TRANSIT_T)); + prRoamingFsmInfo = (P_ROAMING_INFO_T)& + (prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + if (!(prRoamingFsmInfo->fgIsEnableRoaming)) { + return; + } + + DBGLOG(ROAMING, EVENT, + "EVENT-ROAMING FAIL: reason %x Current Time = %ld\n", u4Param, + kalGetTimeTick()); + + /* IDLE, ROAM -> DECISION */ + /* Errors as IDLE, DECISION, DISCOVERY -> DECISION */ + if (prRoamingFsmInfo->eCurrentState != ROAMING_STATE_ROAM) { + return; + } + + eNextState = ROAMING_STATE_DECISION; + /* ROAM -> DECISION */ + if (eNextState != prRoamingFsmInfo->eCurrentState) { + rTransit.u2Event = ROAMING_EVENT_FAIL; + rTransit.u2Data = (u16)(u4Param & 0xffff); + roamingFsmSendCmd(prAdapter, + (P_CMD_ROAMING_TRANSIT_T)&rTransit); + + /* Step to next state */ + roamingFsmSteps(prAdapter, eNextState); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Transit to Idle state as beging aborted by other moduels, AIS + * + * @param [IN P_ADAPTER_T] prAdapter + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void roamingFsmRunEventAbort(IN P_ADAPTER_T prAdapter) +{ + P_ROAMING_INFO_T prRoamingFsmInfo; + ENUM_ROAMING_STATE_T eNextState; + CMD_ROAMING_TRANSIT_T rTransit; + + kalMemZero(&rTransit, sizeof(CMD_ROAMING_TRANSIT_T)); + prRoamingFsmInfo = (P_ROAMING_INFO_T)& + (prAdapter->rWifiVar.rRoamingInfo); + + /* Check Roaming Conditions */ + if (!(prRoamingFsmInfo->fgIsEnableRoaming)) { + return; + } + + DBGLOG(ROAMING, EVENT, "EVENT-ROAMING ABORT: Current Time = %ld\n", + kalGetTimeTick()); + + eNextState = ROAMING_STATE_IDLE; + /* IDLE, DECISION, DISCOVERY, ROAM -> IDLE */ + if (eNextState != prRoamingFsmInfo->eCurrentState) { + rTransit.u2Event = ROAMING_EVENT_ABORT; + roamingFsmSendCmd(prAdapter, + (P_CMD_ROAMING_TRANSIT_T)&rTransit); + + /* Step to next state */ + roamingFsmSteps(prAdapter, eNextState); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process events from firmware + * + * @param [IN P_ADAPTER_T] prAdapter + * [IN P_ROAMING_PARAM_T] prParam + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS roamingFsmProcessEvent(IN P_ADAPTER_T prAdapter, + IN P_CMD_ROAMING_TRANSIT_T prTransit) +{ + DBGLOG(ROAMING, LOUD, "ROAMING Process Events: Current Time = %ld\n", + kalGetTimeTick()); + + if (prTransit->u2Event == ROAMING_EVENT_DISCOVERY) { + roamingFsmRunEventDiscovery(prAdapter, prTransit); + } + + return WLAN_STATUS_SUCCESS; +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rsn.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rsn.c new file mode 100644 index 00000000000000..2e218d36162ad5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/rsn.c @@ -0,0 +1,3229 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "rsn.c" + * \brief This file including the 802.11i, wpa and wpa2(rsn) related + * function. + * + * This file provided the macros and functions library support the wpa/rsn ie + * parsing, cipher and AKM check to help the AP seleced deciding, tkip mic error + * handler and rsn PMKID support. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to parse RSN IE. + * + * \param[in] prInfoElem Pointer to the RSN IE + * \param[out] prRsnInfo Pointer to the BSSDescription structure to store the + ** RSN information from the given RSN IE + * + * \retval true - Succeeded + * \retval false - Failed + */ +/*----------------------------------------------------------------------------*/ +u8 rsnParseRsnIE(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_ELEM_T prInfoElem, + OUT P_RSN_INFO_T prRsnInfo) +{ + u32 i; + s32 u4RemainRsnIeLen; + u16 u2Version; + u16 u2Cap = 0; + u32 u4GroupSuite = RSN_CIPHER_SUITE_CCMP; + u32 u4GroupMgmtSuite = 0; + u16 u2PairSuiteCount = 0; + u16 u2AuthSuiteCount = 0; + u8 *pucPairSuite = NULL; + u8 *pucAuthSuite = NULL; + u8 *cp; + u16 u2DesiredPmkidCnt = 0; + u16 u2SupportedPmkidCnt = 0; + + DEBUGFUNC("rsnParseRsnIE"); + + ASSERT(prInfoElem); + ASSERT(prRsnInfo); + + /* Verify the length of the RSN IE. */ + if (prInfoElem->ucLength < 2) { + DBGLOG(RSN, TRACE, "RSN IE length too short (length=%d)\n", + prInfoElem->ucLength); + return false; + } + + /* Check RSN version: currently, we only support version 1. */ + WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); + if (u2Version != 1) { + DBGLOG(RSN, TRACE, "Unsupported RSN IE version: %d\n", u2Version); + return false; + } + + cp = (u8 *)&prInfoElem->u4GroupKeyCipherSuite; + u4RemainRsnIeLen = (s32)prInfoElem->ucLength - 2; + + do { + if (u4RemainRsnIeLen == 0) { + break; + } + + /* Parse the Group Key Cipher Suite field. */ + if (u4RemainRsnIeLen < 4) { + DBGLOG(RSN, TRACE, + "Fail to parse RSN IE in group cipher suite (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + WLAN_GET_FIELD_32(cp, &u4GroupSuite); + cp += 4; + u4RemainRsnIeLen -= 4; + + if (u4RemainRsnIeLen == 0) { + break; + } + + /* Parse the Pairwise Key Cipher Suite Count field. */ + if (u4RemainRsnIeLen < 2) { + DBGLOG( + RSN, TRACE, + "Fail to parse RSN IE in pairwise cipher suite count (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); + cp += 2; + u4RemainRsnIeLen -= 2; + + /* Parse the Pairwise Key Cipher Suite List field. */ + i = (u32)u2PairSuiteCount * 4; + if (u4RemainRsnIeLen < (s32)i) { + DBGLOG( + RSN, TRACE, + "Fail to parse RSN IE in pairwise cipher suite list (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + pucPairSuite = cp; + + cp += i; + u4RemainRsnIeLen -= (s32)i; + + if (u4RemainRsnIeLen == 0) { + break; + } + + /* Parse the Authentication and Key Management Cipher Suite + * Count field. */ + if (u4RemainRsnIeLen < 2) { + DBGLOG( + RSN, TRACE, + "Fail to parse RSN IE in auth & key mgt suite count (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); + cp += 2; + u4RemainRsnIeLen -= 2; + + /* Parse the Authentication and Key Management Cipher Suite List + * field. */ + i = (u32)u2AuthSuiteCount * 4; + if (u4RemainRsnIeLen < (s32)i) { + DBGLOG( + RSN, TRACE, + "Fail to parse RSN IE in auth & key mgt suite list (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + pucAuthSuite = cp; + + cp += i; + u4RemainRsnIeLen -= (s32)i; + + if (u4RemainRsnIeLen == 0) { + break; + } + + /* Parse the RSN u2Capabilities field. */ + if (u4RemainRsnIeLen < 2) { + DBGLOG(RSN, TRACE, + "Fail to parse RSN IE in RSN capabilities (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + WLAN_GET_FIELD_16(cp, &u2Cap); + cp += 2; + u4RemainRsnIeLen -= 2; + + if (u4RemainRsnIeLen == 0) { + break; + } + + /* 9.4.2.25.5 PMKID + * The PMKID Count and List fields are used only in + * the RSNE in the (Re)Association Request frame to an AP + * and in FT authentication sequence frames. + */ + /* Parse PMKID count field */ + if (u4RemainRsnIeLen < 2) { + DBGLOG(RSN, TRACE, "Fail to parse RSN IE in PMKID (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + WLAN_GET_FIELD_16(cp, &u2DesiredPmkidCnt); + cp += 2; + u4RemainRsnIeLen -= 2; + + if (u2DesiredPmkidCnt > MAX_NUM_SUPPORTED_PMKID) { + u2SupportedPmkidCnt = MAX_NUM_SUPPORTED_PMKID; + DBGLOG( + RSN, WARN, + "Support maximum PMKID Cnt = %d with desired PMKID Cnt = %d\n", + MAX_NUM_SUPPORTED_PMKID, u2DesiredPmkidCnt); + } else { + u2SupportedPmkidCnt = u2DesiredPmkidCnt; + } + + /* Parse PMKID List field */ + i = (u32)u2DesiredPmkidCnt * RSN_PMKID_LEN; + if (u4RemainRsnIeLen < (s32)i) { + DBGLOG( + RSN, TRACE, + "Fail to parse RSN IE in pairwise cipher suite list (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + if (u2SupportedPmkidCnt > 0) { + kalMemCopy(prRsnInfo->aucPmkidList, cp, + (u2SupportedPmkidCnt * RSN_PMKID_LEN)); + + DBGLOG(RSN, INFO, "== Dump cached PMKIDs ==\n"); + DBGLOG_MEM8(RSN, INFO, prRsnInfo->aucPmkidList, + (u2SupportedPmkidCnt * RSN_PMKID_LEN)); + } + cp += u2DesiredPmkidCnt * RSN_PMKID_LEN; + u4RemainRsnIeLen -= (s32)(u2DesiredPmkidCnt * RSN_PMKID_LEN); + + if (u4RemainRsnIeLen == 0) { + break; + } + + /* Parse Group Mgmt Cipher Suite field */ + if (u4RemainRsnIeLen < 4) { + DBGLOG(RSN, TRACE, + "Fail to parse RSN IE in GroupMgmtCipher (IELen: %d)\n", + prInfoElem->ucLength); + /* Continued to connect + * when PMKID List field is truncated. + */ + break; + } + WLAN_GET_FIELD_32(cp, &u4GroupMgmtSuite); + } while (false); + + /* Save the RSN information for the BSS. */ + prRsnInfo->ucElemId = ELEM_ID_RSN; + prRsnInfo->ucRsneLen = prInfoElem->ucLength; + prRsnInfo->u2Version = u2Version; + prRsnInfo->u4GroupKeyCipherSuite = u4GroupSuite; + prRsnInfo->u4GroupMgmtKeyCipherSuite = u4GroupMgmtSuite; + prRsnInfo->u2PmkidCnt = u2SupportedPmkidCnt; + + DBGLOG(RSN, LOUD, + "RSN: version %d, group mgmt key cipher suite %02x-%02x-%02x-%02x\n", + u2Version, (u8)(u4GroupMgmtSuite & 0x000000FF), + (u8)((u4GroupMgmtSuite >> 8) & 0x000000FF), + (u8)((u4GroupMgmtSuite >> 16) & 0x000000FF), + (u8)((u4GroupMgmtSuite >> 24) & 0x000000FF)); + + DBGLOG(RSN, LOUD, + "RSN: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", + u2Version, (u8)(u4GroupSuite & 0x000000FF), + (u8)((u4GroupSuite >> 8) & 0x000000FF), + (u8)((u4GroupSuite >> 16) & 0x000000FF), + (u8)((u4GroupSuite >> 24) & 0x000000FF)); + + if (pucPairSuite) { + /* The information about the pairwise key cipher suites is + * present. */ + if (u2PairSuiteCount > MAX_NUM_SUPPORTED_CIPHER_SUITES) { + u2PairSuiteCount = MAX_NUM_SUPPORTED_CIPHER_SUITES; + } + + prRsnInfo->u4PairwiseKeyCipherSuiteCount = (u32)u2PairSuiteCount; + + for (i = 0; i < (u32)u2PairSuiteCount; i++) { + WLAN_GET_FIELD_32(pucPairSuite, + &prRsnInfo->au4PairwiseKeyCipherSuite[i]); + pucPairSuite += 4; + + DBGLOG(RSN, LOUD, + "RSN: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", + (u8)i, + (u8)(prRsnInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), + (u8)((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 8) & + 0x000000FF), + (u8)((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 16) & + 0x000000FF), + (u8)((prRsnInfo->au4PairwiseKeyCipherSuite[i] >> 24) & + 0x000000FF)); + } + } else { + /* The information about the pairwise key cipher suites is not + * present. */ + /* Use the default chipher suite for RSN: CCMP. */ + prRsnInfo->u4PairwiseKeyCipherSuiteCount = 1; + prRsnInfo->au4PairwiseKeyCipherSuite[0] = RSN_CIPHER_SUITE_CCMP; + + DBGLOG( + RSN, LOUD, + "RSN: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", + (u8)(prRsnInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), + (u8)((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), + (u8)((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), + (u8)((prRsnInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF)); + } + + if (pucAuthSuite) { + /* The information about the authentication and key management + * suites */ + /* is present. */ + if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_AKM_SUITES) { + u2AuthSuiteCount = MAX_NUM_SUPPORTED_AKM_SUITES; + } + + prRsnInfo->u4AuthKeyMgtSuiteCount = (u32)u2AuthSuiteCount; + + for (i = 0; i < (u32)u2AuthSuiteCount; i++) { + WLAN_GET_FIELD_32(pucAuthSuite, &prRsnInfo->au4AuthKeyMgtSuite[i]); + pucAuthSuite += 4; + + DBGLOG(RSN, LOUD, "RSN: AKM suite [%d]: %02x-%02x-%02x-%02x\n", + (u8)i, (u8)(prRsnInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), + (u8)((prRsnInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), + (u8)((prRsnInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), + (u8)((prRsnInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF)); + } + } else { + /* The information about the authentication and key management + * suites */ + /* is not present. Use the default AKM suite for RSN. */ + prRsnInfo->u4AuthKeyMgtSuiteCount = 1; + prRsnInfo->au4AuthKeyMgtSuite[0] = RSN_AKM_SUITE_802_1X; + + DBGLOG(RSN, LOUD, "RSN: AKM suite: %02x-%02x-%02x-%02x (default)\n", + (u8)(prRsnInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), + (u8)((prRsnInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), + (u8)((prRsnInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), + (u8)((prRsnInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF)); + } + + prRsnInfo->u2RsnCap = u2Cap; + prRsnInfo->fgRsnCapPresent = true; + DBGLOG(RSN, LOUD, "RSN cap: 0x%04x\n", prRsnInfo->u2RsnCap); + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to parse WPA IE. + * + * \param[in] prInfoElem Pointer to the WPA IE. + * \param[out] prWpaInfo Pointer to the BSSDescription structure to store the + * WPA information from the given WPA IE. + * + * \retval true Succeeded. + * \retval false Failed. + */ +/*----------------------------------------------------------------------------*/ +u8 rsnParseWpaIE(IN P_ADAPTER_T prAdapter, IN P_WPA_INFO_ELEM_T prInfoElem, + OUT P_RSN_INFO_T prWpaInfo) +{ + u32 i; + s32 u4RemainWpaIeLen; + u16 u2Version; + u16 u2Cap = 0; + u32 u4GroupSuite = WPA_CIPHER_SUITE_TKIP; + u16 u2PairSuiteCount = 0; + u16 u2AuthSuiteCount = 0; + u8 *pucPairSuite = NULL; + u8 *pucAuthSuite = NULL; + u8 *cp; + u8 fgCapPresent = false; + + DEBUGFUNC("rsnParseWpaIE"); + + ASSERT(prInfoElem); + ASSERT(prWpaInfo); + + /* Verify the length of the WPA IE. */ + if (prInfoElem->ucLength < 6) { + DBGLOG(RSN, TRACE, "WPA IE length too short (length=%d)\n", + prInfoElem->ucLength); + return false; + } + + /* Check WPA version: currently, we only support version 1. */ + WLAN_GET_FIELD_16(&prInfoElem->u2Version, &u2Version); + if (u2Version != 1) { + DBGLOG(RSN, TRACE, "Unsupported WPA IE version: %d\n", u2Version); + return false; + } + + cp = (u8 *)&prInfoElem->u4GroupKeyCipherSuite; + u4RemainWpaIeLen = (s32)prInfoElem->ucLength - 6; + + do { + if (u4RemainWpaIeLen == 0) { + break; + } + + /* WPA_OUI : 4 + * Version : 2 + * GroupSuite : 4 + * PairwiseCount: 2 + * PairwiseSuite: 4 * pairSuiteCount + * AuthCount : 2 + * AuthSuite : 4 * authSuiteCount + * Cap : 2 + */ + + /* Parse the Group Key Cipher Suite field. */ + if (u4RemainWpaIeLen < 4) { + DBGLOG(RSN, TRACE, + "Fail to parse WPA IE in group cipher suite (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + WLAN_GET_FIELD_32(cp, &u4GroupSuite); + cp += 4; + u4RemainWpaIeLen -= 4; + + if (u4RemainWpaIeLen == 0) { + break; + } + + /* Parse the Pairwise Key Cipher Suite Count field. */ + if (u4RemainWpaIeLen < 2) { + DBGLOG( + RSN, TRACE, + "Fail to parse WPA IE in pairwise cipher suite count (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + WLAN_GET_FIELD_16(cp, &u2PairSuiteCount); + cp += 2; + u4RemainWpaIeLen -= 2; + + /* Parse the Pairwise Key Cipher Suite List field. */ + i = (u32)u2PairSuiteCount * 4; + if (u4RemainWpaIeLen < (s32)i) { + DBGLOG( + RSN, TRACE, + "Fail to parse WPA IE in pairwise cipher suite list (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + pucPairSuite = cp; + + cp += i; + u4RemainWpaIeLen -= (s32)i; + + if (u4RemainWpaIeLen == 0) { + break; + } + + /* Parse the Authentication and Key Management Cipher Suite + * Count field. */ + if (u4RemainWpaIeLen < 2) { + DBGLOG( + RSN, TRACE, + "Fail to parse WPA IE in auth & key mgt suite count (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + WLAN_GET_FIELD_16(cp, &u2AuthSuiteCount); + cp += 2; + u4RemainWpaIeLen -= 2; + + /* Parse the Authentication and Key Management Cipher Suite List + * field. */ + i = (u32)u2AuthSuiteCount * 4; + if (u4RemainWpaIeLen < (s32)i) { + DBGLOG( + RSN, TRACE, + "Fail to parse WPA IE in auth & key mgt suite list (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + pucAuthSuite = cp; + + cp += i; + u4RemainWpaIeLen -= (s32)i; + + if (u4RemainWpaIeLen == 0) { + break; + } + + /* Parse the WPA u2Capabilities field. */ + if (u4RemainWpaIeLen < 2) { + DBGLOG(RSN, TRACE, + "Fail to parse WPA IE in WPA capabilities (IE len: %d)\n", + prInfoElem->ucLength); + return false; + } + + fgCapPresent = true; + WLAN_GET_FIELD_16(cp, &u2Cap); + u4RemainWpaIeLen -= 2; + } while (false); + + /* Save the WPA information for the BSS. */ + + prWpaInfo->ucElemId = ELEM_ID_WPA; + + prWpaInfo->u2Version = u2Version; + + prWpaInfo->u4GroupKeyCipherSuite = u4GroupSuite; + + DBGLOG(RSN, LOUD, + "WPA: version %d, group key cipher suite %02x-%02x-%02x-%02x\n", + u2Version, (u8)(u4GroupSuite & 0x000000FF), + (u8)((u4GroupSuite >> 8) & 0x000000FF), + (u8)((u4GroupSuite >> 16) & 0x000000FF), + (u8)((u4GroupSuite >> 24) & 0x000000FF)); + + if (pucPairSuite) { + /* The information about the pairwise key cipher suites is + * present. */ + if (u2PairSuiteCount > MAX_NUM_SUPPORTED_CIPHER_SUITES) { + u2PairSuiteCount = MAX_NUM_SUPPORTED_CIPHER_SUITES; + } + + prWpaInfo->u4PairwiseKeyCipherSuiteCount = (u32)u2PairSuiteCount; + + for (i = 0; i < (u32)u2PairSuiteCount; i++) { + WLAN_GET_FIELD_32(pucPairSuite, + &prWpaInfo->au4PairwiseKeyCipherSuite[i]); + pucPairSuite += 4; + + DBGLOG(RSN, LOUD, + "WPA: pairwise key cipher suite [%d]: %02x-%02x-%02x-%02x\n", + (u8)i, + (u8)(prWpaInfo->au4PairwiseKeyCipherSuite[i] & 0x000000FF), + (u8)((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 8) & + 0x000000FF), + (u8)((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 16) & + 0x000000FF), + (u8)((prWpaInfo->au4PairwiseKeyCipherSuite[i] >> 24) & + 0x000000FF)); + } + } else { + /* The information about the pairwise key cipher suites is not + * present. */ + /* Use the default chipher suite for WPA: TKIP. */ + prWpaInfo->u4PairwiseKeyCipherSuiteCount = 1; + prWpaInfo->au4PairwiseKeyCipherSuite[0] = WPA_CIPHER_SUITE_TKIP; + + DBGLOG( + RSN, LOUD, + "WPA: pairwise key cipher suite: %02x-%02x-%02x-%02x (default)\n", + (u8)(prWpaInfo->au4PairwiseKeyCipherSuite[0] & 0x000000FF), + (u8)((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 8) & 0x000000FF), + (u8)((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 16) & 0x000000FF), + (u8)((prWpaInfo->au4PairwiseKeyCipherSuite[0] >> 24) & 0x000000FF)); + } + + if (pucAuthSuite) { + /* The information about the authentication and key management + * suites */ + /* is present. */ + if (u2AuthSuiteCount > MAX_NUM_SUPPORTED_AKM_SUITES) { + u2AuthSuiteCount = MAX_NUM_SUPPORTED_AKM_SUITES; + } + + prWpaInfo->u4AuthKeyMgtSuiteCount = (u32)u2AuthSuiteCount; + + for (i = 0; i < (u32)u2AuthSuiteCount; i++) { + WLAN_GET_FIELD_32(pucAuthSuite, &prWpaInfo->au4AuthKeyMgtSuite[i]); + pucAuthSuite += 4; + + DBGLOG(RSN, LOUD, "WPA: AKM suite [%d]: %02x-%02x-%02x-%02x\n", + (u8)i, (u8)(prWpaInfo->au4AuthKeyMgtSuite[i] & 0x000000FF), + (u8)((prWpaInfo->au4AuthKeyMgtSuite[i] >> 8) & 0x000000FF), + (u8)((prWpaInfo->au4AuthKeyMgtSuite[i] >> 16) & 0x000000FF), + (u8)((prWpaInfo->au4AuthKeyMgtSuite[i] >> 24) & 0x000000FF)); + } + } else { + /* The information about the authentication and key management + * suites */ + /* is not present. Use the default AKM suite for WPA. */ + prWpaInfo->u4AuthKeyMgtSuiteCount = 1; + prWpaInfo->au4AuthKeyMgtSuite[0] = WPA_AKM_SUITE_802_1X; + + DBGLOG(RSN, LOUD, "WPA: AKM suite: %02x-%02x-%02x-%02x (default)\n", + (u8)(prWpaInfo->au4AuthKeyMgtSuite[0] & 0x000000FF), + (u8)((prWpaInfo->au4AuthKeyMgtSuite[0] >> 8) & 0x000000FF), + (u8)((prWpaInfo->au4AuthKeyMgtSuite[0] >> 16) & 0x000000FF), + (u8)((prWpaInfo->au4AuthKeyMgtSuite[0] >> 24) & 0x000000FF)); + } + + if (fgCapPresent) { + prWpaInfo->fgRsnCapPresent = true; + prWpaInfo->u2RsnCap = u2Cap; + DBGLOG(RSN, LOUD, "WPA: RSN cap: 0x%04x\n", prWpaInfo->u2RsnCap); + } else { + prWpaInfo->fgRsnCapPresent = false; + prWpaInfo->u2RsnCap = 0; + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to search the desired pairwise + * cipher suite from the MIB Pairwise Cipher Suite + * configuration table. + * + * \param[in] u4Cipher The desired pairwise cipher suite to be searched + * \param[out] pu4Index Pointer to the index of the desired pairwise cipher in + * the table + * + * \retval true - The desired pairwise cipher suite is found in the table. + * \retval false - The desired pairwise cipher suite is not found in the + * table. + */ +/*----------------------------------------------------------------------------*/ +u8 rsnSearchSupportedCipher(IN P_ADAPTER_T prAdapter, IN u32 u4Cipher, + OUT u32 *pu4Index) +{ + u8 i; + P_DOT11_RSNA_CONFIG_PAIRWISE_CIPHERS_ENTRY prEntry; + + DEBUGFUNC("rsnSearchSupportedCipher"); + + ASSERT(pu4Index); + + for (i = 0; i < MAX_NUM_SUPPORTED_CIPHER_SUITES; i++) { + prEntry = &prAdapter->rMib.dot11RSNAConfigPairwiseCiphersTable[i]; + if (prEntry->dot11RSNAConfigPairwiseCipher == u4Cipher && + prEntry->dot11RSNAConfigPairwiseCipherEnabled) { + *pu4Index = i; + return true; + } + } + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Whether BSS RSN is matched from upper layer set. + * + * \param[in] prAdapter Pointer to the Adapter structure, BSS RSN Information + * + * \retval u8 + */ +/*----------------------------------------------------------------------------*/ +u8 rsnIsSuitableBSS(IN P_ADAPTER_T prAdapter, IN P_RSN_INFO_T prBssRsnInfo) +{ + u8 i = 0; + + DEBUGFUNC("rsnIsSuitableBSS"); + + do { + if ((prAdapter->rWifiVar.rConnSettings.rRsnInfo.u4GroupKeyCipherSuite & + 0x000000FF) != + GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite)) { + DBGLOG(RSN, TRACE, "Break by GroupKeyCipherSuite\n"); + break; + } + for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { + if (((prAdapter->rWifiVar.rConnSettings.rRsnInfo + .au4PairwiseKeyCipherSuite[0] & + 0x000000FF) != + GET_SELECTOR_TYPE( + prBssRsnInfo->au4PairwiseKeyCipherSuite[i])) && + (i == prBssRsnInfo->u4PairwiseKeyCipherSuiteCount - 1)) { + DBGLOG(RSN, TRACE, "Break by PairwiseKeyCipherSuite\n"); + break; + } + } + for (i = 0; i < prBssRsnInfo->u4AuthKeyMgtSuiteCount; i++) { + if (((prAdapter->rWifiVar.rConnSettings.rRsnInfo + .au4AuthKeyMgtSuite[0] & + 0x000000FF) != + GET_SELECTOR_TYPE(prBssRsnInfo->au4AuthKeyMgtSuite[0])) && + (i == prBssRsnInfo->u4AuthKeyMgtSuiteCount - 1)) { + DBGLOG(RSN, TRACE, "Break by AuthKeyMgtSuite\n"); + break; + } + } + return true; + } while (false); + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to search the desired + * authentication and key management (AKM) suite from the + * MIB Authentication and Key Management Suites table. + * + * \param[in] u4AkmSuite The desired AKM suite to be searched + * \param[out] pu4Index Pointer to the index of the desired AKM suite in the + * table + * + * \retval true The desired AKM suite is found in the table. + * \retval false The desired AKM suite is not found in the table. + * + * \note + */ +/*----------------------------------------------------------------------------*/ +u8 rsnSearchAKMSuite(IN P_ADAPTER_T prAdapter, IN u32 u4AkmSuite, + OUT u32 *pu4Index) +{ + u8 i; + P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry; + + DEBUGFUNC("rsnSearchAKMSuite"); + + ASSERT(pu4Index); + + for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { + prEntry = &prAdapter->rMib.dot11RSNAConfigAuthenticationSuitesTable[i]; + if (prEntry->dot11RSNAConfigAuthenticationSuite == u4AkmSuite && + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled) { + *pu4Index = i; + return true; + } + } + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to perform RSNA or TSN policy + * selection for a given BSS. + * + * \param[in] prBss Pointer to the BSS description + * + * \retval true - The RSNA/TSN policy selection for the given BSS is + * successful. The selected pairwise and group cipher suites + * are returned in the BSS description. + * \retval false - The RSNA/TSN policy selection for the given BSS is failed. + * The driver shall not attempt to join the given BSS. + * + * \note The Encrypt status matched score will save to bss for final ap select. + */ +/*----------------------------------------------------------------------------*/ +u8 rsnPerformPolicySelection(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss) +{ +#if CFG_SUPPORT_802_11W + s32 i; + u32 j; +#else + u32 i, j; +#endif + u8 fgSuiteSupported; + u32 u4PairwiseCipher = 0; + u32 u4GroupCipher = 0; + u32 u4AkmSuite = 0; + P_RSN_INFO_T prBssRsnInfo; + u8 ucBssIndex; + u8 fgIsWpsActive = (u8)false; + + DEBUGFUNC("rsnPerformPolicySelection"); + + ASSERT(prBss); + + DBGLOG(RSN, TRACE, "rsnPerformPolicySelection\n"); + /* Todo:: */ + ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex; + + prBss->u4RsnSelectedPairwiseCipher = 0; + prBss->u4RsnSelectedGroupCipher = 0; + prBss->u4RsnSelectedAKMSuite = 0; + prBss->ucEncLevel = 0; + +#if CFG_SUPPORT_802_11W + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = false; +#endif + +#if CFG_SUPPORT_WPS + fgIsWpsActive = kalWSCGetActiveState(prAdapter->prGlueInfo); + + /* CR1640, disable the AP select privacy check */ + if (fgIsWpsActive && + (prAdapter->rWifiVar.rConnSettings.eAuthMode < AUTH_MODE_WPA) && + (prAdapter->rWifiVar.rConnSettings.eOPMode == NET_TYPE_INFRA)) { + DBGLOG(RSN, INFO, "-- Skip the Protected BSS check\n"); + return true; + } +#endif + + /* Protection is not required in this BSS. */ + if ((prBss->u2CapInfo & CAP_INFO_PRIVACY) == 0) { + if (secEnabledInAis(prAdapter) == false) { + DBGLOG(RSN, INFO, "-- No Protected BSS\n"); + return true; + } + DBGLOG(RSN, INFO, "-- Protected BSS but No need\n"); + return false; + } + + /* Protection is required in this BSS. */ + if ((prBss->u2CapInfo & CAP_INFO_PRIVACY) != 0) { + if (secEnabledInAis(prAdapter) == false) { + DBGLOG(RSN, INFO, "-- Protected BSS\n"); + return false; + } + } + + if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA || + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK || + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_NONE) { + if (prBss->fgIEWPA) { + prBssRsnInfo = &prBss->rWPAInfo; + } else { + DBGLOG(RSN, INFO, "WPA Information Element does not exist.\n"); + return false; + } + } else if (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2 || + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_PSK +#if CFG_SUPPORT_SAE + || + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_SAE +#endif + ) { + if (prBss->fgIERSN) { + prBssRsnInfo = &prBss->rRSNInfo; + } else { + DBGLOG(RSN, INFO, "RSN Information Element does not exist.\n"); + return false; + } + } else if (prAdapter->rWifiVar.rConnSettings.eEncStatus != + ENUM_ENCRYPTION1_ENABLED) { + /* If the driver is configured to use WEP only, ignore this BSS. + */ + DBGLOG(RSN, INFO, "-- Not WEP-only legacy BSS\n"); + return false; + } else if (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION1_ENABLED) { + /* If the driver is configured to use WEP only, use this BSS. */ + DBGLOG(RSN, INFO, "-- WEP-only legacy BSS\n"); + return true; + } + + if (!rsnIsSuitableBSS(prAdapter, prBssRsnInfo)) { + DBGLOG(RSN, INFO, "RSN info check no matched\n"); + return false; + } + + if (prBssRsnInfo->u4PairwiseKeyCipherSuiteCount == 1 && + GET_SELECTOR_TYPE(prBssRsnInfo->au4PairwiseKeyCipherSuite[0]) == + CIPHER_SUITE_NONE) { + /* Since the pairwise cipher use the same cipher suite as the + * group cipher in the BSS, we check the group cipher suite + * against the current encryption status. + */ + fgSuiteSupported = false; + + switch (prBssRsnInfo->u4GroupKeyCipherSuite) { +#if CFG_SUPPORT_SUITB + case RSN_CIPHER_SUITE_GCMP_256: + if (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION4_ENABLED) { + fgSuiteSupported = true; + } + break; + +#endif + case WPA_CIPHER_SUITE_CCMP: + case RSN_CIPHER_SUITE_CCMP: + if (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION3_ENABLED) { + fgSuiteSupported = true; + } + break; + + case WPA_CIPHER_SUITE_TKIP: + case RSN_CIPHER_SUITE_TKIP: + if (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION2_ENABLED) { + fgSuiteSupported = true; + } + break; + + case WPA_CIPHER_SUITE_WEP40: + case WPA_CIPHER_SUITE_WEP104: + if (prAdapter->rWifiVar.rConnSettings.eEncStatus == + ENUM_ENCRYPTION1_ENABLED) { + fgSuiteSupported = true; + } + break; + } + + if (fgSuiteSupported) { + u4PairwiseCipher = WPA_CIPHER_SUITE_NONE; + u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; + } +#if DBG + else { + DBGLOG(RSN, TRACE, + "Inproper encryption status %d for group-key-only BSS\n", + prAdapter->rWifiVar.rConnSettings.eEncStatus); + } +#endif + } else { + fgSuiteSupported = false; + + DBGLOG(RSN, TRACE, "eEncStatus %d %lu 0x%lx\n", + prAdapter->rWifiVar.rConnSettings.eEncStatus, + prBssRsnInfo->u4PairwiseKeyCipherSuiteCount, + prBssRsnInfo->au4PairwiseKeyCipherSuite[0]); + /* Select pairwise/group ciphers */ + switch (prAdapter->rWifiVar.rConnSettings.eEncStatus) { +#if CFG_SUPPORT_SUITB + case ENUM_ENCRYPTION4_ENABLED: + for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { + /* TODO: WTBL cipher filed cannot 1-1 mapping + * to spec cipher suite number + */ + if (prBssRsnInfo->au4PairwiseKeyCipherSuite[i] == + RSN_CIPHER_SUITE_GCMP_256) { + u4PairwiseCipher = + prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; + } + } + u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; + break; + +#endif + case ENUM_ENCRYPTION3_ENABLED: + for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { + if (GET_SELECTOR_TYPE( + prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) == + CIPHER_SUITE_CCMP) { + u4PairwiseCipher = + prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; + } + } + u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; + break; + + case ENUM_ENCRYPTION2_ENABLED: + for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { + if (GET_SELECTOR_TYPE( + prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) == + CIPHER_SUITE_TKIP) { + u4PairwiseCipher = + prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; + } + } + if (GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == + CIPHER_SUITE_CCMP) { + DBGLOG(RSN, TRACE, "Cannot join CCMP BSS\n"); + } else { + u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; + } + break; + + case ENUM_ENCRYPTION1_ENABLED: + for (i = 0; i < prBssRsnInfo->u4PairwiseKeyCipherSuiteCount; i++) { + if (GET_SELECTOR_TYPE( + prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) == + CIPHER_SUITE_WEP40 || + GET_SELECTOR_TYPE( + prBssRsnInfo->au4PairwiseKeyCipherSuite[i]) == + CIPHER_SUITE_WEP104) { + u4PairwiseCipher = + prBssRsnInfo->au4PairwiseKeyCipherSuite[i]; + } + } + if (GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == + CIPHER_SUITE_CCMP || + GET_SELECTOR_TYPE(prBssRsnInfo->u4GroupKeyCipherSuite) == + CIPHER_SUITE_TKIP) { + DBGLOG(RSN, TRACE, "Cannot join CCMP/TKIP BSS\n"); + } else { + u4GroupCipher = prBssRsnInfo->u4GroupKeyCipherSuite; + } + break; + + default: + break; + } + } + + /* Exception handler */ + /* If we cannot find proper pairwise and group cipher suites to join the + */ + /* BSS, do not check the supported AKM suites. */ + if (u4PairwiseCipher == 0 || u4GroupCipher == 0) { + DBGLOG(RSN, TRACE, + "Failed to select pairwise/group cipher (0x%08lx/0x%08lx)\n", + u4PairwiseCipher, u4GroupCipher); + return false; + } +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && + (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + NETWORK_TYPE_P2P)) { + if (u4PairwiseCipher != RSN_CIPHER_SUITE_CCMP || + u4GroupCipher != RSN_CIPHER_SUITE_CCMP || + u4AkmSuite != RSN_AKM_SUITE_PSK) { + DBGLOG(RSN, TRACE, + "Failed to select pairwise/group cipher for P2P network " + "(0x%08lx/0x%08lx)\n", + u4PairwiseCipher, u4GroupCipher); + return false; + } + } +#endif + + /* Verify if selected pairwisse cipher is supported */ + fgSuiteSupported = + rsnSearchSupportedCipher(prAdapter, u4PairwiseCipher, &i); + + /* Verify if selected group cipher is supported */ + if (fgSuiteSupported) { + fgSuiteSupported = + rsnSearchSupportedCipher(prAdapter, u4GroupCipher, &i); + } + + if (!fgSuiteSupported) { + DBGLOG( + RSN, TRACE, + "Failed to support selected pairwise/group cipher (0x%08lx/0x%08lx)\n", + u4PairwiseCipher, u4GroupCipher); + return false; + } + + /* Select AKM */ + /* If the driver cannot support any authentication suites advertised in + * the given BSS, we fail to perform RSNA policy selection. + */ + /* Attempt to find any overlapping supported AKM suite. */ +#if CFG_SUPPORT_802_11W + if (i != 0) { + for (i = (prBssRsnInfo->u4AuthKeyMgtSuiteCount - 1); i >= 0; i--) { +#else + for (i = 0; i < prBssRsnInfo->u4AuthKeyMgtSuiteCount; i++) { +#endif + if (rsnSearchAKMSuite(prAdapter, + prBssRsnInfo->au4AuthKeyMgtSuite[i], &j)) { + u4AkmSuite = prBssRsnInfo->au4AuthKeyMgtSuite[i]; + break; + } + } +#if CFG_SUPPORT_802_11W + } +#endif + + if (u4AkmSuite == 0) { + DBGLOG(RSN, TRACE, "Cannot support any AKM suites\n"); + return false; + } + + DBGLOG(RSN, TRACE, + "Selected pairwise/group cipher: " + "%02x-%02x-%02x-%02x/%02x-%02x-%02x-%02x\n", + (u8)(u4PairwiseCipher & 0x000000FF), + (u8)((u4PairwiseCipher >> 8) & 0x000000FF), + (u8)((u4PairwiseCipher >> 16) & 0x000000FF), + (u8)((u4PairwiseCipher >> 24) & 0x000000FF), + (u8)(u4GroupCipher & 0x000000FF), + (u8)((u4GroupCipher >> 8) & 0x000000FF), + (u8)((u4GroupCipher >> 16) & 0x000000FF), + (u8)((u4GroupCipher >> 24) & 0x000000FF)); + + DBGLOG(RSN, TRACE, "Selected AKM suite: %02x-%02x-%02x-%02x\n", + (u8)(u4AkmSuite & 0x000000FF), (u8)((u4AkmSuite >> 8) & 0x000000FF), + (u8)((u4AkmSuite >> 16) & 0x000000FF), + (u8)((u4AkmSuite >> 24) & 0x000000FF)); + +#if CFG_SUPPORT_802_11W + DBGLOG(RSN, TRACE, "[MFP] MFP setting = %lu\n ", + kalGetMfpSetting(prAdapter->prGlueInfo)); + + if (kalGetMfpSetting(prAdapter->prGlueInfo) == RSN_AUTH_MFP_REQUIRED) { + if (!prBssRsnInfo->fgRsnCapPresent) { + DBGLOG(RSN, TRACE, + "[MFP] Skip RSN IE, No MFP Required Capability.\n"); + return false; + } else if (!(prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPC)) { + DBGLOG(RSN, TRACE, "[MFP] Skip RSN IE, No MFP Required\n"); + return false; + } + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = true; + } else if (kalGetMfpSetting(prAdapter->prGlueInfo) == + RSN_AUTH_MFP_OPTIONAL) { + if (prBssRsnInfo->u2RsnCap & (ELEM_WPA_CAP_MFPR | ELEM_WPA_CAP_MFPC)) { + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = true; + } + } else { + if (prBssRsnInfo->fgRsnCapPresent && + (prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPR)) { + DBGLOG(RSN, INFO, "[MFP] Try to join even MFP Required bit set\n"); + return false; + } + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection = false; + } + DBGLOG(RSN, TRACE, "[MFP] fgMgmtProtection = %d\n ", + prAdapter->rWifiVar.rAisSpecificBssInfo.fgMgmtProtection); + + prAdapter->rWifiVar.rAisSpecificBssInfo.fgAPApplyPmfReq = false; + if (prBssRsnInfo->fgRsnCapPresent && + (prBssRsnInfo->u2RsnCap & ELEM_WPA_CAP_MFPR)) { + prAdapter->rWifiVar.rAisSpecificBssInfo.fgAPApplyPmfReq = true; + } +#endif + + if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_CCMP) { + prBss->ucEncLevel = 3; +#if CFG_SUPPORT_SUITB + } else if (u4GroupCipher == RSN_CIPHER_SUITE_GCMP_256) { + prBss->ucEncLevel = 4; +#endif + } else if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_TKIP) { + prBss->ucEncLevel = 2; + } else if (GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_WEP40 || + GET_SELECTOR_TYPE(u4GroupCipher) == CIPHER_SUITE_WEP104) { + prBss->ucEncLevel = 1; + } else { + ASSERT(false); + } + prBss->u4RsnSelectedPairwiseCipher = u4PairwiseCipher; + prBss->u4RsnSelectedGroupCipher = u4GroupCipher; + prBss->u4RsnSelectedAKMSuite = u4AkmSuite; + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to generate WPA IE for beacon frame. + * + * \param[in] pucIeStartAddr Pointer to put the generated WPA IE. + * + * \return The append WPA-None IE length + * \note + * Called by: JOIN module, compose beacon IE + */ +/*----------------------------------------------------------------------------*/ +void rsnGenerateWpaNoneIE(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + u32 i; + P_WPA_INFO_ELEM_T prWpaIE; + u32 u4Suite; + u16 u2SuiteCount; + u8 *cp, *cp2; + u8 ucExpendedLen = 0; + u8 *pucBuffer; + u8 ucBssIndex; + + DEBUGFUNC("rsnGenerateWpaNoneIE"); + + ASSERT(prMsduInfo); + + if (prAdapter->rWifiVar.rConnSettings.eAuthMode != AUTH_MODE_WPA_NONE) { + return; + } + + ucBssIndex = prMsduInfo->ucBssIndex; + + if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType != + NETWORK_TYPE_AIS) { + return; + } + + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + prWpaIE = (P_WPA_INFO_ELEM_T)(pucBuffer); + + /* Start to construct a WPA IE. */ + /* Fill the Element ID field. */ + prWpaIE->ucElemId = ELEM_ID_WPA; + + /* Fill the OUI and OUI Type fields. */ + prWpaIE->aucOui[0] = 0x00; + prWpaIE->aucOui[1] = 0x50; + prWpaIE->aucOui[2] = 0xF2; + prWpaIE->ucOuiType = VENDOR_OUI_TYPE_WPA; + + /* Fill the Version field. */ + WLAN_SET_FIELD_16(&prWpaIE->u2Version, 1); /* version 1 */ + ucExpendedLen = 6; + + /* Fill the Pairwise Key Cipher Suite List field. */ + u2SuiteCount = 0; + cp = (u8 *)&prWpaIE->aucPairwiseKeyCipherSuite1[0]; + + if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_CCMP, &i)) { + u4Suite = WPA_CIPHER_SUITE_CCMP; + } else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_TKIP, &i)) { + u4Suite = WPA_CIPHER_SUITE_TKIP; + } else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP104, + &i)) { + u4Suite = WPA_CIPHER_SUITE_WEP104; + } else if (rsnSearchSupportedCipher(prAdapter, WPA_CIPHER_SUITE_WEP40, + &i)) { + u4Suite = WPA_CIPHER_SUITE_WEP40; + } else { + u4Suite = WPA_CIPHER_SUITE_TKIP; + } + + WLAN_SET_FIELD_32(cp, u4Suite); + u2SuiteCount++; + ucExpendedLen += 4; + cp += 4; + + /* Fill the Group Key Cipher Suite field as the same in pair-wise key. + */ + WLAN_SET_FIELD_32(&prWpaIE->u4GroupKeyCipherSuite, u4Suite); + ucExpendedLen += 4; + + /* Fill the Pairwise Key Cipher Suite Count field. */ + WLAN_SET_FIELD_16(&prWpaIE->u2PairwiseKeyCipherSuiteCount, u2SuiteCount); + ucExpendedLen += 2; + + cp2 = cp; + + /* Fill the Authentication and Key Management Suite List field. */ + u2SuiteCount = 0; + cp += 2; + + if (rsnSearchAKMSuite(prAdapter, WPA_AKM_SUITE_802_1X, &i)) { + u4Suite = WPA_AKM_SUITE_802_1X; + } else if (rsnSearchAKMSuite(prAdapter, WPA_AKM_SUITE_PSK, &i)) { + u4Suite = WPA_AKM_SUITE_PSK; + } else { + u4Suite = WPA_AKM_SUITE_NONE; + } + + /* This shall be the only available value for current implementation */ + ASSERT(u4Suite == WPA_AKM_SUITE_NONE); + + WLAN_SET_FIELD_32(cp, u4Suite); + u2SuiteCount++; + ucExpendedLen += 4; + cp += 4; + + /* Fill the Authentication and Key Management Suite Count field. */ + WLAN_SET_FIELD_16(cp2, u2SuiteCount); + ucExpendedLen += 2; + + /* Fill the Length field. */ + prWpaIE->ucLength = (u8)ucExpendedLen; + + /* Increment the total IE length for the Element ID and Length fields. + */ + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to generate WPA IE for + * associate request frame. + * + * \param[in] prCurrentBss The Selected BSS description + * + * \retval The append WPA IE length + * + * \note + * Called by: AIS module, Associate request + */ +/*----------------------------------------------------------------------------*/ +void rsnGenerateWPAIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + u8 *cp; + u8 *pucBuffer; + u8 ucBssIndex; + P_BSS_INFO_T prBssInfo; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo; + + DEBUGFUNC("rsnGenerateWPAIE"); + + ASSERT(prMsduInfo); + + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + ucBssIndex = prMsduInfo->ucBssIndex; + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + prP2pSpecificBssInfo = + prAdapter->rWifiVar.prP2pSpecificBssInfo[prBssInfo->u4PrivateData]; + + /* if (eNetworkId != NETWORK_TYPE_AIS_INDEX) */ + /* return; */ + +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered && + GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + NETWORK_TYPE_P2P && + kalP2PGetTkipCipher(prAdapter->prGlueInfo, + (u8)prBssInfo->u4PrivateData)) || + (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + NETWORK_TYPE_AIS && + (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA || + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK))) { +#else + if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + NETWORK_TYPE_AIS && + (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA || + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA_PSK)) { +#endif + if (prAdapter->fgIsP2PRegistered && prP2pSpecificBssInfo && + (prP2pSpecificBssInfo->u2WpaIeLen != 0)) { + kalMemCopy(pucBuffer, prP2pSpecificBssInfo->aucWpaIeBuffer, + prP2pSpecificBssInfo->u2WpaIeLen); + prMsduInfo->u2FrameLength += prP2pSpecificBssInfo->u2WpaIeLen; + return; + } + /* Construct a WPA IE for association request frame. */ + WPA_IE(pucBuffer)->ucElemId = ELEM_ID_WPA; + WPA_IE(pucBuffer)->ucLength = ELEM_ID_WPA_LEN_FIXED; + WPA_IE(pucBuffer)->aucOui[0] = 0x00; + WPA_IE(pucBuffer)->aucOui[1] = 0x50; + WPA_IE(pucBuffer)->aucOui[2] = 0xF2; + WPA_IE(pucBuffer)->ucOuiType = VENDOR_OUI_TYPE_WPA; + WLAN_SET_FIELD_16(&WPA_IE(pucBuffer)->u2Version, 1); + +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && + GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + NETWORK_TYPE_P2P) { + WLAN_SET_FIELD_32(&WPA_IE(pucBuffer)->u4GroupKeyCipherSuite, + WPA_CIPHER_SUITE_TKIP); + } else +#endif + WLAN_SET_FIELD_32( + &WPA_IE(pucBuffer)->u4GroupKeyCipherSuite, + prAdapter->prAisBssInfo->u4RsnSelectedGroupCipher); + + cp = (u8 *)&WPA_IE(pucBuffer)->aucPairwiseKeyCipherSuite1[0]; + + WLAN_SET_FIELD_16(&WPA_IE(pucBuffer)->u2PairwiseKeyCipherSuiteCount, 1); +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && + GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + NETWORK_TYPE_P2P) { + WLAN_SET_FIELD_32(cp, WPA_CIPHER_SUITE_TKIP); + } else +#endif + WLAN_SET_FIELD_32( + cp, prAdapter->prAisBssInfo->u4RsnSelectedPairwiseCipher); + cp += 4; + + WLAN_SET_FIELD_16(cp, 1); + cp += 2; +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered && + GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + NETWORK_TYPE_P2P) { + WLAN_SET_FIELD_32(cp, WPA_AKM_SUITE_PSK); + } else +#endif + WLAN_SET_FIELD_32(cp, + prAdapter->prAisBssInfo->u4RsnSelectedAKMSuite); + cp += 4; + + WPA_IE(pucBuffer)->ucLength = ELEM_ID_WPA_LEN_FIXED; + + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to generate RSN IE for + * associate request frame. + * + * \param[in] prMsduInfo The Selected BSS description + * + * \retval The append RSN IE length + * + * \note + * Called by: AIS module, P2P module, BOW module Associate request + */ +/*----------------------------------------------------------------------------*/ +void rsnGenerateRSNIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + u8 *cp; + /* u8 ucExpendedLen = 0; */ + u8 *pucBuffer; + u8 ucBssIndex; + P_BSS_INFO_T prBssInfo; + u32 u4GroupMgmt = 0; + P_CONNECTION_SETTINGS_T prConnSettings = NULL; + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + ASSERT(prConnSettings); + + DEBUGFUNC("rsnGenerateRSNIE"); + + ASSERT(prMsduInfo); + + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + /* Todo:: network id */ + ucBssIndex = prMsduInfo->ucBssIndex; + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + ASSERT(prBssInfo); + + if (((prAdapter->fgIsP2PRegistered) && + (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + NETWORK_TYPE_P2P) && + (kalP2PGetCcmpCipher(prAdapter->prGlueInfo, + (u8)prBssInfo->u4PrivateData))) || + + (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + NETWORK_TYPE_AIS /* prCurrentBss->fgIERSN */ + && + ((prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) || + (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_PSK) + + || (prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2_SAE) + + ))) { + /* Construct a RSN IE for association request frame. */ + RSN_IE(pucBuffer)->ucElemId = ELEM_ID_RSN; + RSN_IE(pucBuffer)->ucLength = prAdapter->prGlueInfo->rWpaInfo.ucRsneLen; + if (RSN_IE(pucBuffer)->ucLength < 2) { + if ((prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) || + (prBssInfo->eNetworkType == NETWORK_TYPE_P2P)) { + RSN_IE(pucBuffer)->ucLength = ELEM_ID_RSN_LEN_FIXED; + } else { + DBGLOG(RSN, WARN, + "Desired RSN IE from upper is too short (length=%d)\n", + RSN_IE(pucBuffer)->ucLength); + return; + } + } + + WLAN_SET_FIELD_16(&RSN_IE(pucBuffer)->u2Version, 1); /* Version + */ + WLAN_SET_FIELD_32(&RSN_IE(pucBuffer)->u4GroupKeyCipherSuite, + GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex) + ->u4RsnSelectedGroupCipher); /* Group + * key + * suite + */ + cp = (u8 *)&RSN_IE(pucBuffer)->aucPairwiseKeyCipherSuite1[0]; + WLAN_SET_FIELD_16(&RSN_IE(pucBuffer)->u2PairwiseKeyCipherSuiteCount, 1); + WLAN_SET_FIELD_32(cp, GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex) + ->u4RsnSelectedPairwiseCipher); + cp += 4; + WLAN_SET_FIELD_16(cp, 1); /* AKM suite count */ + cp += 2; + /* AKM suite */ + WLAN_SET_FIELD_32(cp, GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex) + ->u4RsnSelectedAKMSuite); + cp += 4; + + /* Capabilities */ + WLAN_SET_FIELD_16( + cp, + GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->u2RsnSelectedCapInfo); + DBGLOG( + RSN, TRACE, "Gen RSN IE = %x\n", + GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->u2RsnSelectedCapInfo); + +#if CFG_SUPPORT_802_11W + if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + NETWORK_TYPE_AIS) { + /* MFP Capabilities */ + if (kalGetRsnIeMfpCap(prAdapter->prGlueInfo) == + RSN_AUTH_MFP_REQUIRED) { + WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC | + ELEM_WPA_CAP_MFPR); /* Capabilities + */ + DBGLOG(RSN, TRACE, "RSN_AUTH_MFP - MFPC & MFPR\n"); + } else if (kalGetRsnIeMfpCap(prAdapter->prGlueInfo) == + RSN_AUTH_MFP_OPTIONAL) { + WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC); /* Capabilities + */ + DBGLOG(RSN, TRACE, "RSN_AUTH_MFP - MFPC\n"); + } else { + DBGLOG(RSN, TRACE, "!RSN_AUTH_MFP - No MFPC!\n"); + } + } else if ((GET_BSS_INFO_BY_INDEX(prAdapter, + ucBssIndex)->eNetworkType == + NETWORK_TYPE_P2P) && + (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex) + ->eCurrentOPMode == (u8)OP_MODE_ACCESS_POINT)) { + /* AP PMF */ + /* for AP mode, keep origin RSN IE content w/o update */ + } +#endif + + //if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + // NETWORK_TYPE_AIS) { + /* MFP Capabilities */ + // if (kalGetRsnIeMfpCap(prAdapter->prGlueInfo) == + // RSN_AUTH_MFP_REQUIRED) { + // WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC | ELEM_WPA_CAP_MFPR); + // DBGLOG(RSN, TRACE, "RSN_AUTH_MFP - MFPC & MFPR\n"); + // } else if (kalGetRsnIeMfpCap(prAdapter->prGlueInfo) == + // RSN_AUTH_MFP_OPTIONAL) { + // WLAN_SET_FIELD_16(cp, ELEM_WPA_CAP_MFPC); + // DBGLOG(RSN, TRACE, "RSN_AUTH_MFP - MFPC\n"); + // } else { + // DBGLOG(RSN, TRACE, "!RSN_AUTH_MFP- No MFPC!\n"); + // } + //} else if ((GET_BSS_INFO_BY_INDEX(prAdapter, + // ucBssIndex)->eNetworkType == + // NETWORK_TYPE_P2P) && + // (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex) + // ->eCurrentOPMode == (u8)OP_MODE_ACCESS_POINT)) { + /* AP PMF */ + /* for AP mode, keep origin RSN IE content w/o update */ + //} + + cp += 2; + + /*Fill PMKID and Group Management Cipher for AIS */ + if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + NETWORK_TYPE_AIS) { + /* Fill PMKID Count field */ + WLAN_SET_FIELD_16(cp, prConnSettings->rRsnInfo.u2PmkidCnt); + cp += 2; + + /* Fill PMKID List field */ + if (prConnSettings->rRsnInfo.u2PmkidCnt > 0) { + kalMemCopy( + cp, &prConnSettings->rRsnInfo.aucPmkidList, + (prConnSettings->rRsnInfo.u2PmkidCnt * RSN_PMKID_LEN)); + DBGLOG(RSN, INFO, "Dump PMDID when gen rsn ie & len:%d\n", + RSN_IE(pucBuffer)->ucLength); + DBGLOG_MEM8( + RSN, INFO, cp, + (prConnSettings->rRsnInfo.u2PmkidCnt * RSN_PMKID_LEN)); + } + + cp += (prConnSettings->rRsnInfo.u2PmkidCnt * RSN_PMKID_LEN); + +#if CFG_SUPPORT_802_11W + /* Fill Group Management Cipher field */ + u4GroupMgmt = prAdapter->prGlueInfo->rWpaInfo.u4CipherGroupMgmt; + WLAN_SET_FIELD_32(cp, u4GroupMgmt); +#endif + } + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Parse the given IE buffer and check if it is WFA IE and return Type + * and SubType for further process. + * + * \param[in] pucBuf Pointer to the buffer of WFA Information + * Element. \param[out] pucOuiType Pointer to the storage of OUI Type. + * \param[out] pu2SubTypeVersion Pointer to the storage of OUI SubType and + * Version. + * + * \retval true Parse IE ok + * \retval false Parse IE fail + */ +/*----------------------------------------------------------------------------*/ +u8 rsnParseCheckForWFAInfoElem(IN P_ADAPTER_T prAdapter, IN u8 *pucBuf, + OUT u8 *pucOuiType, OUT u16 *pu2SubTypeVersion) +{ + u8 aucWfaOui[] = VENDOR_OUI_WFA; + P_IE_WFA_T prWfaIE; + + ASSERT(pucBuf); + ASSERT(pucOuiType); + ASSERT(pu2SubTypeVersion); + prWfaIE = (P_IE_WFA_T)pucBuf; + + do { + if (IE_LEN(pucBuf) <= ELEM_MIN_LEN_WFA_OUI_TYPE_SUBTYPE) { + break; + } else if (prWfaIE->aucOui[0] != aucWfaOui[0] || + prWfaIE->aucOui[1] != aucWfaOui[1] || + prWfaIE->aucOui[2] != aucWfaOui[2]) { + break; + } + + *pucOuiType = prWfaIE->ucOuiType; + WLAN_GET_FIELD_16(&prWfaIE->aucOuiSubTypeVersion[0], pu2SubTypeVersion); + + return true; + } while (false); + + return false; +} + +#if CFG_SUPPORT_AAA +/*----------------------------------------------------------------------------*/ +/*! + * \brief Parse the given IE buffer and check if it is RSN IE with CCMP PSK + * + * \param[in] prAdapter Pointer to Adapter + * \param[in] prSwRfb Pointer to the rx buffer + * \param[in] pIE Pointer rthe buffer of Information + * Element. \param[out] prStatusCode Pointer to the return status code. + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void rsnParserCheckForRSNCCMPPSK(P_ADAPTER_T prAdapter, P_RSN_INFO_ELEM_T prIe, + P_STA_RECORD_T prStaRec, u16 *pu2StatusCode) +{ + RSN_INFO_T rRsnIe; + P_BSS_INFO_T prBssInfo; + u8 i; + u16 statusCode; + + ASSERT(prAdapter); + ASSERT(prIe); + ASSERT(prStaRec); + ASSERT(pu2StatusCode); + + *pu2StatusCode = STATUS_CODE_INVALID_INFO_ELEMENT; + + if (rsnParseRsnIE(prAdapter, prIe, &rRsnIe)) { + if ((rRsnIe.u4PairwiseKeyCipherSuiteCount != 1) || + (rRsnIe.au4PairwiseKeyCipherSuite[0] != RSN_CIPHER_SUITE_CCMP)) { + *pu2StatusCode = STATUS_CODE_INVALID_PAIRWISE_CIPHER; + return; + } + if (rRsnIe.u4GroupKeyCipherSuite != RSN_CIPHER_SUITE_CCMP) { + *pu2StatusCode = STATUS_CODE_INVALID_GROUP_CIPHER; + return; + } + if ((rRsnIe.u4AuthKeyMgtSuiteCount != 1) || + (rRsnIe.au4AuthKeyMgtSuite[0] != RSN_AKM_SUITE_PSK)) { + *pu2StatusCode = STATUS_CODE_INVALID_AKMP; + return; + } + + DBGLOG(RSN, TRACE, "RSN with CCMP-PSK\n"); + *pu2StatusCode = WLAN_STATUS_SUCCESS; + +#if CFG_SUPPORT_802_11W + /* AP PMF */ + /* 1st check: if already PMF connection, reject assoc req: error + * 30 ASSOC_REJECTED_TEMPORARILY */ + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + *pu2StatusCode = STATUS_CODE_ASSOC_REJECTED_TEMPORARILY; + return; + } + + /* if RSN capability not exist, just return */ + if (!rRsnIe.fgRsnCapPresent) { + *pu2StatusCode = WLAN_STATUS_SUCCESS; + return; + } + + prStaRec->rPmfCfg.fgMfpc = (rRsnIe.u2RsnCap & ELEM_WPA_CAP_MFPC) ? 1 : + 0; + prStaRec->rPmfCfg.fgMfpr = (rRsnIe.u2RsnCap & ELEM_WPA_CAP_MFPR) ? 1 : + 0; + + for (i = 0; i < rRsnIe.u4AuthKeyMgtSuiteCount; i++) { + if ((rRsnIe.au4AuthKeyMgtSuite[i] == RSN_AKM_SUITE_802_1X_SHA256) || + (rRsnIe.au4AuthKeyMgtSuite[i] == RSN_AKM_SUITE_PSK_SHA256)) { + DBGLOG(RSN, INFO, "STA SHA256 support\n"); + prStaRec->rPmfCfg.fgSha256 = true; + break; + } + } + + DBGLOG( + RSN, INFO, + "STA Assoc req mfpc:%d, mfpr:%d, sha256:%d, bssIndex:%d, applyPmf:%d\n", + prStaRec->rPmfCfg.fgMfpc, prStaRec->rPmfCfg.fgMfpr, + prStaRec->rPmfCfg.fgSha256, prStaRec->ucBssIndex, + prStaRec->rPmfCfg.fgApplyPmf); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + /* if PMF validation fail, return success as legacy association + */ + statusCode = rsnPmfCapableValidation(prAdapter, prBssInfo, prStaRec); + *pu2StatusCode = statusCode; +#endif + } +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to generate an authentication event to NDIS. + * + * \param[in] u4Flags Authentication event: \n + * PARAM_AUTH_REQUEST_REAUTH 0x01 \n + * PARAM_AUTH_REQUEST_KEYUPDATE 0x02 \n + * PARAM_AUTH_REQUEST_PAIRWISE_ERROR 0x06 \n + * PARAM_AUTH_REQUEST_GROUP_ERROR 0x0E \n + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void rsnGenMicErrorEvent(IN P_ADAPTER_T prAdapter, IN u8 fgFlags) +{ + P_PARAM_AUTH_EVENT_T prAuthEvent; + + DEBUGFUNC("rsnGenMicErrorEvent"); + + prAuthEvent = (P_PARAM_AUTH_EVENT_T)prAdapter->aucIndicationEventBuffer; + + /* Status type: Authentication Event */ + prAuthEvent->rStatus.eStatusType = ENUM_STATUS_TYPE_AUTHENTICATION; + + /* Authentication request */ + prAuthEvent->arRequest[0].u4Length = sizeof(PARAM_AUTH_REQUEST_T); + kalMemCopy((void *)prAuthEvent->arRequest[0].arBssid, + (void *)prAdapter->prAisBssInfo->aucBSSID, MAC_ADDR_LEN); + + if (fgFlags == true) { + prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_GROUP_ERROR; + } else { + prAuthEvent->arRequest[0].u4Flags = PARAM_AUTH_REQUEST_PAIRWISE_ERROR; + } + + kalIndicateStatusAndComplete( + prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (void *)prAuthEvent, + sizeof(PARAM_STATUS_INDICATION_T) + sizeof(PARAM_AUTH_REQUEST_T)); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to handle TKIP MIC failures. + * + * \param[in] adapter_p Pointer to the adapter object data area. + * \param[in] prSta Pointer to the STA which occur MIC Error + * \param[in] fgErrorKeyType type of error key + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void rsnTkipHandleMICFailure(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prSta, + IN u8 fgErrorKeyType) +{ + DEBUGFUNC("rsnTkipHandleMICFailure"); + + ASSERT(prAdapter); + + rsnGenMicErrorEvent(prAdapter, /* prSta, */ fgErrorKeyType); + + /* Generate authentication request event. */ + DBGLOG(RSN, INFO, "Generate TKIP MIC error event (type: 0%d)\n", + fgErrorKeyType); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is called to select a list of BSSID from + * the scan results for PMKID candidate list. + * + * \param[in] prBssDesc the BSS Desc at scan result list + * \param[out] pu4CandidateCount Pointer to the number of selected candidates. + * It is set to zero if no BSSID matches our + * requirement. + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void rsnSelectPmkidCandidateList(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prAisBssInfo; + + DEBUGFUNC("rsnSelectPmkidCandidateList"); + + ASSERT(prBssDesc); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + prAisBssInfo = prAdapter->prAisBssInfo; + + /* Search a BSS with the same SSID from the given BSS description set. + */ + /* DBGLOG(RSN, TRACE, ("Check scan result ["MACSTR"]\n", */ + /* MAC2STR(prBssDesc->aucBSSID))); */ + + if (UNEQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) { + DBGLOG(RSN, TRACE, "-- SSID not matched\n"); + return; + } + + rsnUpdatePmkidCandidateList(prAdapter, prBssDesc); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is called to select a list of BSSID from + * the scan results for PMKID candidate list. + * + * \param[in] prBssDesc the BSS DESC at scan result list + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void rsnUpdatePmkidCandidateList(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc) +{ + u32 i; + P_CONNECTION_SETTINGS_T prConnSettings; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("rsnUpdatePmkidCandidateList"); + + ASSERT(prBssDesc); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + if (UNEQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen)) { + DBGLOG(RSN, TRACE, "-- SSID not matched\n"); + return; + } + + for (i = 0; i < CFG_MAX_PMKID_CACHE; i++) { + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, + prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)) { + return; + } + } + + /* If the number of selected BSSID exceed MAX_NUM_PMKID_CACHE(16), + * then we only store MAX_NUM_PMKID_CACHE(16) in PMKID cache + */ + if ((prAisSpecBssInfo->u4PmkidCandicateCount + 1) > CFG_MAX_PMKID_CACHE) { + prAisSpecBssInfo->u4PmkidCandicateCount--; + } + + i = prAisSpecBssInfo->u4PmkidCandicateCount; + + COPY_MAC_ADDR((void *)prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, + (void *)prBssDesc->aucBSSID); + + if (prBssDesc->u2RsnCap & MASK_RSNIE_CAP_PREAUTH) { + prAisSpecBssInfo->arPmkidCandicate[i].u4PreAuthFlags = 1; + DBGLOG(RSN, TRACE, "Add " MACSTR " with pre-auth to candidate list\n", + MAC2STR(prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)); + } else { + prAisSpecBssInfo->arPmkidCandicate[i].u4PreAuthFlags = 0; + DBGLOG(RSN, TRACE, + "Add " MACSTR " without pre-auth to candidate list\n", + MAC2STR(prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)); + } + + prAisSpecBssInfo->u4PmkidCandicateCount++; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to search the desired entry in + * PMKID cache according to the BSSID + * + * \param[in] pucBssid Pointer to the BSSID + * \param[out] pu4EntryIndex Pointer to place the found entry index + * + * \retval true, if found one entry for specified BSSID + * \retval false, if not found + */ +/*----------------------------------------------------------------------------*/ +u8 rsnSearchPmkidEntry(IN P_ADAPTER_T prAdapter, IN u8 *pucBssid, + OUT u32 *pu4EntryIndex) +{ + u32 i; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + + DEBUGFUNC("rsnSearchPmkidEntry"); + + ASSERT(pucBssid); + ASSERT(pu4EntryIndex); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + if (prAisSpecBssInfo->u4PmkidCacheCount > CFG_MAX_PMKID_CACHE) { + return false; + } + + ASSERT(prAisSpecBssInfo->u4PmkidCacheCount <= CFG_MAX_PMKID_CACHE); + + /* Search for desired BSSID */ + for (i = 0; i < prAisSpecBssInfo->u4PmkidCacheCount; i++) { + if (!kalMemCmp(prAisSpecBssInfo->arPmkidCache[i].rBssidInfo.arBSSID, + pucBssid, MAC_ADDR_LEN)) { + break; + } + } + + /* If desired BSSID is found, then set the PMKID */ + if (i < prAisSpecBssInfo->u4PmkidCacheCount) { + *pu4EntryIndex = i; + + return true; + } + + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to check if there is difference + * between PMKID candicate list and PMKID cache. If there + * is new candicate that no cache entry is available, then + * add a new entry for the new candicate in the PMKID cache + * and set the PMKID indication flag to true. + * + * \retval true, if new member in the PMKID candicate list + * \retval FALSe, if no new member in the PMKID candicate list + */ +/*----------------------------------------------------------------------------*/ +u8 rsnCheckPmkidCandicate(IN P_ADAPTER_T prAdapter) +{ + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + u32 i; /* Index for PMKID candicate */ + u32 j; /* Indix for PMKID cache */ + u8 status = false; + + DEBUGFUNC("rsnCheckPmkidCandicate"); + + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + /* Check for each candicate */ + for (i = 0; i < prAisSpecBssInfo->u4PmkidCandicateCount; i++) { + for (j = 0; j < prAisSpecBssInfo->u4PmkidCacheCount; j++) { + if (!kalMemCmp(prAisSpecBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, + prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, + MAC_ADDR_LEN)) { + /* DBGLOG(RSN, TRACE, (MACSTR" at PMKID + * cache!!\n", + * MAC2STR(prAisSpecBssInfo->arPmkidCandicate[i].aucBssid))); + */ + break; + } + } + + /* No entry found in PMKID cache for the candicate, add new one + */ + if (j == prAisSpecBssInfo->u4PmkidCacheCount && + prAisSpecBssInfo->u4PmkidCacheCount < CFG_MAX_PMKID_CACHE) { + DBGLOG(RSN, TRACE, "Add " MACSTR " to PMKID cache!!\n", + MAC2STR(prAisSpecBssInfo->arPmkidCandicate[i].aucBssid)); + kalMemCopy((void *)prAisSpecBssInfo + ->arPmkidCache[prAisSpecBssInfo->u4PmkidCacheCount] + .rBssidInfo.arBSSID, + (void *)prAisSpecBssInfo->arPmkidCandicate[i].aucBssid, + MAC_ADDR_LEN); + prAisSpecBssInfo->arPmkidCache[prAisSpecBssInfo->u4PmkidCacheCount] + .fgPmkidExist = false; + prAisSpecBssInfo->u4PmkidCacheCount++; + + status = true; + } + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is called to wait a duration to indicate the pre-auth AP + * candicate + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void rsnIndicatePmkidCand(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr) +{ + DBGLOG(RSN, EVENT, "Security - Time to indicate the PMKID cand.\n"); + + /* If the authentication mode is WPA2 and indication PMKID flag + * is available, then we indicate the PMKID candidate list to NDIS and + * clear the flag, indicatePMKID + */ + + if (prAdapter->prAisBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED && + prAdapter->rWifiVar.rConnSettings.eAuthMode == AUTH_MODE_WPA2) { + rsnGeneratePmkidIndication(prAdapter); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to check the BSS Desc at scan result + * with pre-auth cap at wpa2 mode. If there + * is candicate that no cache entry is available, then + * add a new entry for the new candicate in the PMKID cache + * and set the PMKID indication flag to true. + * + * \param[in] prBss The BSS Desc at scan result + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void rsnCheckPmkidCache(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBss) +{ + P_BSS_INFO_T prAisBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + + DEBUGFUNC("rsnCheckPmkidCandicate"); + + ASSERT(prBss); + + prConnSettings = &prAdapter->rWifiVar.rConnSettings; + prAisBssInfo = prAdapter->prAisBssInfo; + prAisSpecBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + + if ((prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) && + (prConnSettings->eAuthMode == AUTH_MODE_WPA2)) { + rsnSelectPmkidCandidateList(prAdapter, prBss); + + /* Set indication flag of PMKID to true, and then + * connHandleNetworkConnection() */ + /* will indicate this later */ + if (rsnCheckPmkidCandicate(prAdapter)) { + DBGLOG(RSN, TRACE, + "Prepare a timer to indicate candidate PMKID Candidate\n"); + cnmTimerStopTimer(prAdapter, + &prAisSpecBssInfo->rPreauthenticationTimer); + cnmTimerStartTimer(prAdapter, + &prAisSpecBssInfo->rPreauthenticationTimer, + SEC_TO_MSEC(WAIT_TIME_IND_PMKID_CANDICATE_SEC)); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to generate an PMKID candidate list + * indication to NDIS. + * + * \param[in] prAdapter Pointer to the adapter object data area. + * \param[in] u4Flags PMKID candidate list event: + * PARAM_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01 + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void rsnGeneratePmkidIndication(IN P_ADAPTER_T prAdapter) +{ + P_PARAM_STATUS_INDICATION_T prStatusEvent; + P_PARAM_PMKID_CANDIDATE_LIST_T prPmkidEvent; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecificBssInfo; + u8 i, j = 0, count = 0; + u32 u4LenOfUsedBuffer; + + DEBUGFUNC("rsnGeneratePmkidIndication"); + + ASSERT(prAdapter); + + prStatusEvent = + (P_PARAM_STATUS_INDICATION_T)prAdapter->aucIndicationEventBuffer; + + /* Status type: PMKID Candidatelist Event */ + prStatusEvent->eStatusType = ENUM_STATUS_TYPE_CANDIDATE_LIST; + ASSERT(prStatusEvent); + + prPmkidEvent = + (P_PARAM_PMKID_CANDIDATE_LIST_T)(&prStatusEvent->eStatusType + 1); + ASSERT(prPmkidEvent); + + prAisSpecificBssInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prAisSpecificBssInfo); + + for (i = 0; i < prAisSpecificBssInfo->u4PmkidCandicateCount; i++) { + for (j = 0; j < prAisSpecificBssInfo->u4PmkidCacheCount; j++) { + if (EQUAL_MAC_ADDR( + prAisSpecificBssInfo->arPmkidCache[j].rBssidInfo.arBSSID, + prAisSpecificBssInfo->arPmkidCandicate[i].aucBssid) && + (prAisSpecificBssInfo->arPmkidCache[j].fgPmkidExist == true)) { + break; + } + } + if (count >= CFG_MAX_PMKID_CACHE) { + break; + } + + if (j == prAisSpecificBssInfo->u4PmkidCacheCount) { + kalMemCopy( + (void *)prPmkidEvent->arCandidateList[count].arBSSID, + (void *)prAisSpecificBssInfo->arPmkidCandicate[i].aucBssid, + PARAM_MAC_ADDR_LEN); + prPmkidEvent->arCandidateList[count].u4Flags = + prAisSpecificBssInfo->arPmkidCandicate[i].u4PreAuthFlags; + DBGLOG(RSN, TRACE, MACSTR " %lu\n", + MAC2STR(prPmkidEvent->arCandidateList[count].arBSSID), + prPmkidEvent->arCandidateList[count].u4Flags); + count++; + } + } + + /* PMKID Candidate List */ + prPmkidEvent->u4Version = 1; + prPmkidEvent->u4NumCandidates = count; + DBGLOG(RSN, TRACE, "rsnGeneratePmkidIndication #%lu\n", + prPmkidEvent->u4NumCandidates); + u4LenOfUsedBuffer = sizeof(ENUM_STATUS_TYPE_T) + (2 * sizeof(u32)) + + (count * sizeof(PARAM_PMKID_CANDIDATE_T)); + /* dumpMemory8((u8 *)prAdapter->aucIndicationEventBuffer, + * u4LenOfUsedBuffer); */ + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (void *)prAdapter->aucIndicationEventBuffer, + u4LenOfUsedBuffer); +} + +#if CFG_SUPPORT_WPS2 +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to generate WSC IE for + * associate request frame. + * + * \param[in] prCurrentBss The Selected BSS description + * + * \retval The append WSC IE length + * + * \note + * Called by: AIS module, Associate request + */ +/*----------------------------------------------------------------------------*/ +void rsnGenerateWSCIE(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + u8 *pucBuffer; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + if (prMsduInfo->ucBssIndex != prAdapter->prAisBssInfo->ucBssIndex) { + return; + } + + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + + /* ASSOC INFO IE ID: 221 :0xDD */ + if (prAdapter->prGlueInfo->u2WSCAssocInfoIELen) { + kalMemCopy(pucBuffer, &prAdapter->prGlueInfo->aucWSCAssocInfoIE, + prAdapter->prGlueInfo->u2WSCAssocInfoIELen); + prMsduInfo->u2FrameLength += prAdapter->prGlueInfo->u2WSCAssocInfoIELen; + } +} +#endif + +#if CFG_SUPPORT_802_11W + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to check if the Bip Key installed or not + * + * \param[in] + * prAdapter + * + * \return + * true + * false + */ +/*----------------------------------------------------------------------------*/ +u32 rsnCheckBipKeyInstalled(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec) +{ + /* caution: prStaRec might be null ! */ + if (prStaRec) { + if (GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex) + ->eNetworkType == (u8)NETWORK_TYPE_AIS) { + return prAdapter->rWifiVar.rAisSpecificBssInfo.fgBipKeyInstalled; + } else if ((GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex) + ->eNetworkType == NETWORK_TYPE_P2P) && + (GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex) + ->eCurrentOPMode == OP_MODE_ACCESS_POINT)) { + DBGLOG(RSN, INFO, "AP-STA PMF capable:%d\n", + prStaRec->rPmfCfg.fgApplyPmf); + return prStaRec->rPmfCfg.fgApplyPmf; + } else { + return false; + } + } else { + return false; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to check the Sa query timeout. + * + * + * \note + * Called by: AIS module, Handle by Sa Quert timeout + */ +/*----------------------------------------------------------------------------*/ +u8 rsnCheckSaQueryTimeout(IN P_ADAPTER_T prAdapter) +{ + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + u32 now; + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + GET_CURRENT_SYSTIME(&now); + + if (CHECK_FOR_TIMEOUT(now, prBssSpecInfo->u4SaQueryStart, + TU_TO_MSEC(SA_QUERY_RETRY_TIMEOUT))) { + DBGLOG(RSN, INFO, "association SA Query timed out\n"); + + prBssSpecInfo->ucSaQueryTimedOut = 1; + kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, + prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); + prBssSpecInfo->pucSaQueryTransId = NULL; + prBssSpecInfo->u4SaQueryCount = 0; + cnmTimerStopTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer); + + if (prAdapter->prAisBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED /* STA_STATE_3 == prStaRec->ucStaState */) + { + P_MSG_AIS_ABORT_T prAisAbortMsg; + + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + return 0; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_SAA_AIS_FSM_ABORT; + prAisAbortMsg->ucReasonOfDisconnect = + DISCONNECT_REASON_CODE_DISASSOCIATED; + prAisAbortMsg->fgDelayIndication = false; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prAisAbortMsg, + MSG_SEND_METHOD_BUF); + } + + return 1; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to start the 802.11w sa query timer. + * + * + * \note + * Called by: AIS module, Handle Rx mgmt request + */ +/*----------------------------------------------------------------------------*/ +void rsnStartSaQueryTimer(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr) +{ + P_BSS_INFO_T prBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + P_MSDU_INFO_T prMsduInfo; + P_ACTION_SA_QUERY_FRAME prTxFrame; + u16 u2PayloadLen; + u8 *pucTmp = NULL; + u8 ucTransId[ACTION_SA_QUERY_TR_ID_LEN]; + + prBssInfo = prAdapter->prAisBssInfo; + ASSERT(prBssInfo); + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + DBGLOG(RSN, INFO, "MFP: Start Sa Query\n"); + + if (prBssInfo->prStaRecOfAP == NULL) { + if (prBssSpecInfo->u4SaQueryCount > 0) { + rsnStopSaQuery(prAdapter); + } + DBGLOG(RSN, INFO, "MFP: unassociated AP!\n"); + return; + } + + if (prBssSpecInfo->u4SaQueryCount > 0 && + rsnCheckSaQueryTimeout(prAdapter)) { + DBGLOG(RSN, INFO, "MFP: u4SaQueryCount count =%lu\n", + prBssSpecInfo->u4SaQueryCount); + return; + } + + prMsduInfo = (P_MSDU_INFO_T)cnmMgtPktAlloc( + prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + + if (!prMsduInfo) { + return; + } + + prTxFrame = + (P_ACTION_SA_QUERY_FRAME)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + if (rsnCheckBipKeyInstalled(prAdapter, prBssInfo->prStaRecOfAP)) { + prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + } + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_SA_QUERY_ACTION; + prTxFrame->ucAction = ACTION_SA_QUERY_REQUEST; + + if (prBssSpecInfo->u4SaQueryCount == 0) { + GET_CURRENT_SYSTIME(&prBssSpecInfo->u4SaQueryStart); + } + + if (prBssSpecInfo->u4SaQueryCount) { + pucTmp = kalMemAlloc(prBssSpecInfo->u4SaQueryCount * + ACTION_SA_QUERY_TR_ID_LEN, + VIR_MEM_TYPE); + if (!pucTmp) { + DBGLOG(RSN, INFO, + "MFP: Fail to alloc tmp buffer for backup sa query id\n"); + cnmMgtPktFree(prAdapter, prMsduInfo); + return; + } + kalMemCopy(pucTmp, prBssSpecInfo->pucSaQueryTransId, + prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); + } + + kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, + prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); + + ucTransId[0] = (u8)(kalRandomNumber() & 0xFF); + ucTransId[1] = (u8)(kalRandomNumber() & 0xFF); + + kalMemCopy(prTxFrame->ucTransId, ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + + prBssSpecInfo->u4SaQueryCount++; + + prBssSpecInfo->pucSaQueryTransId = + kalMemAlloc(prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN, + VIR_MEM_TYPE); + if (!prBssSpecInfo->pucSaQueryTransId) { + kalMemFree(pucTmp, VIR_MEM_TYPE, + (prBssSpecInfo->u4SaQueryCount - 1) * + ACTION_SA_QUERY_TR_ID_LEN); + DBGLOG(RSN, INFO, "MFP: Fail to alloc buffer for sa query id list\n"); + cnmMgtPktFree(prAdapter, prMsduInfo); + return; + } + + if (pucTmp) { + kalMemCopy(prBssSpecInfo->pucSaQueryTransId, pucTmp, + (prBssSpecInfo->u4SaQueryCount - 1) * + ACTION_SA_QUERY_TR_ID_LEN); + kalMemCopy( + &prBssSpecInfo + ->pucSaQueryTransId[(prBssSpecInfo->u4SaQueryCount - 1) * + ACTION_SA_QUERY_TR_ID_LEN], + ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + kalMemFree(pucTmp, VIR_MEM_TYPE, + (prBssSpecInfo->u4SaQueryCount - 1) * + ACTION_SA_QUERY_TR_ID_LEN); + } else { + kalMemCopy(prBssSpecInfo->pucSaQueryTransId, ucTransId, + ACTION_SA_QUERY_TR_ID_LEN); + } + + u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN; + + /* 4 <3> Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prBssInfo->prStaRecOfAP->ucBssIndex, + prBssInfo->prStaRecOfAP->ucIndex, WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, NULL, + MSDU_RATE_MODE_AUTO); + + if (rsnCheckBipKeyInstalled(prAdapter, prBssInfo->prStaRecOfAP)) { + DBGLOG(RSN, INFO, "Set MSDU_OPT_PROTECTED_FRAME\n"); + nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, true); + } + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + DBGLOG(RSN, INFO, "Set SA Query timer %lu (%d Tu)\n", + prBssSpecInfo->u4SaQueryCount, SA_QUERY_TIMEOUT); + + cnmTimerStartTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer, + TU_TO_MSEC(SA_QUERY_TIMEOUT)); +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to start the 802.11w sa query. + * + * + * \note + * Called by: AIS module, Handle Rx mgmt request + */ +/*----------------------------------------------------------------------------*/ +void rsnStartSaQuery(IN P_ADAPTER_T prAdapter) +{ + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + DBGLOG(RSN, INFO, "prBssSpecInfo->u4SaQueryCount %d\n", + prBssSpecInfo->u4SaQueryCount); + + if (prBssSpecInfo->u4SaQueryCount == 0) { + rsnStartSaQueryTimer(prAdapter, (unsigned long)NULL); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to stop the 802.11w sa query. + * + * + * \note + * Called by: AIS module, Handle Rx mgmt request + */ +/*----------------------------------------------------------------------------*/ +void rsnStopSaQuery(IN P_ADAPTER_T prAdapter) +{ + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + cnmTimerStopTimer(prAdapter, &prBssSpecInfo->rSaQueryTimer); + if (prBssSpecInfo->pucSaQueryTransId) { + kalMemFree(prBssSpecInfo->pucSaQueryTransId, VIR_MEM_TYPE, + prBssSpecInfo->u4SaQueryCount * ACTION_SA_QUERY_TR_ID_LEN); + prBssSpecInfo->pucSaQueryTransId = NULL; + } + prBssSpecInfo->u4SaQueryCount = 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to process the 802.11w sa query action frame. + * + * + * \note + * Called by: AIS module, Handle Rx mgmt request + */ +/*----------------------------------------------------------------------------*/ +void rsnSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + P_ACTION_SA_QUERY_FRAME prRxFrame = NULL; + u16 u2PayloadLen; + P_STA_RECORD_T prStaRec; + P_ACTION_SA_QUERY_FRAME prTxFrame; + + prBssInfo = prAdapter->prAisBssInfo; + ASSERT(prBssInfo); + + if (!prSwRfb) { + return; + } + + prRxFrame = (P_ACTION_SA_QUERY_FRAME)prSwRfb->pvHeader; + if (!prRxFrame) { + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + if (!prStaRec) { /* Todo:: for not AIS check */ + return; + } + + DBGLOG(RSN, INFO, + "IEEE 802.11: Received SA Query Request from " MACSTR "\n", + MAC2STR(prStaRec->aucMacAddr)); + + DBGLOG_MEM8(RSN, INFO, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) == + PARAM_MEDIA_STATE_DISCONNECTED) { + DBGLOG( + RSN, INFO, + "IEEE 802.11: Ignore SA Query Request from unassociated STA " MACSTR + "\n", + MAC2STR(prStaRec->aucMacAddr)); + return; + } + + DBGLOG(RSN, INFO, "IEEE 802.11: Sending SA Query Response to " MACSTR "\n", + MAC2STR(prStaRec->aucMacAddr)); + + prMsduInfo = (P_MSDU_INFO_T)cnmMgtPktAlloc( + prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + + if (!prMsduInfo) { + return; + } + + prTxFrame = + (P_ACTION_SA_QUERY_FRAME)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + if (rsnCheckBipKeyInstalled(prAdapter, prBssInfo->prStaRecOfAP)) { + prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + } + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prBssInfo->aucBSSID); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_SA_QUERY_ACTION; + prTxFrame->ucAction = ACTION_SA_QUERY_RESPONSE; + + kalMemCopy(prTxFrame->ucTransId, prRxFrame->ucTransId, + ACTION_SA_QUERY_TR_ID_LEN); + + u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN; + + /* 4 <3> Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prBssInfo->prStaRecOfAP->ucBssIndex, + prBssInfo->prStaRecOfAP->ucIndex, WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, NULL, + MSDU_RATE_MODE_AUTO); + + if (rsnCheckBipKeyInstalled(prAdapter, prBssInfo->prStaRecOfAP)) { + DBGLOG(RSN, INFO, "Set MSDU_OPT_PROTECTED_FRAME\n"); + nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, true); + } + + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to process the 802.11w sa query action frame. + * + * + * \note + * Called by: AIS module, Handle Rx mgmt request + */ +/*----------------------------------------------------------------------------*/ +void rsnSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_AIS_SPECIFIC_BSS_INFO_T prBssSpecInfo; + P_ACTION_SA_QUERY_FRAME prRxFrame; + P_STA_RECORD_T prStaRec; + u32 i; + + prBssSpecInfo = &prAdapter->rWifiVar.rAisSpecificBssInfo; + ASSERT(prBssSpecInfo); + + prRxFrame = (P_ACTION_SA_QUERY_FRAME)prSwRfb->pvHeader; + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (prSwRfb->u2PacketLen < ACTION_SA_QUERY_TR_ID_LEN) { + DBGLOG(RSN, INFO, + "IEEE 802.11: Too short SA Query Action frame (len=%lu)\n", + (unsigned long)prSwRfb->u2PacketLen); + return; + } + + if (prRxFrame->ucAction == ACTION_SA_QUERY_REQUEST) { + rsnSaQueryRequest(prAdapter, prSwRfb); + return; + } + + if (prRxFrame->ucAction != ACTION_SA_QUERY_RESPONSE) { + DBGLOG(RSN, INFO, "IEEE 802.11: Unexpected SA Query Action %d\n", + prRxFrame->ucAction); + return; + } + + DBGLOG(RSN, INFO, + "IEEE 802.11: Received SA Query Response from " MACSTR "\n", + MAC2STR(prStaRec->aucMacAddr)); + + DBGLOG_MEM8(RSN, INFO, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + + /* MLME-SAQuery.confirm */ + + for (i = 0; i < prBssSpecInfo->u4SaQueryCount; i++) { + if (kalMemCmp(prBssSpecInfo->pucSaQueryTransId + + i * ACTION_SA_QUERY_TR_ID_LEN, + prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN) == 0) { + break; + } + } + + if (i >= prBssSpecInfo->u4SaQueryCount) { + DBGLOG( + RSN, INFO, + "IEEE 802.11: No matching SA Query transaction identifier found\n"); + return; + } + + DBGLOG(RSN, INFO, "Reply to pending SA Query received\n"); + + rsnStopSaQuery(prAdapter); +} +#endif // CFG_SUPPORT_802_11W + +#if CFG_SUPPORT_AAA +#define WPS_DEV_OUI_WFA 0x0050f204 +#define ATTR_RESPONSE_TYPE 0x103b + +#define ATTR_VERSION 0x104a +#define ATTR_VENDOR_EXT 0x1049 +#define WPS_VENDOR_ID_WFA 14122 + +void rsnGenerateWSCIEForAssocRsp(P_ADAPTER_T prAdapter, + P_MSDU_INFO_T prMsduInfo) +{ + P_WIFI_VAR_T prWifiVar = NULL; + P_BSS_INFO_T prP2pBssInfo = (P_BSS_INFO_T)NULL; + u16 u2IELen = 0; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + ASSERT(IS_NET_ACTIVE(prAdapter, prMsduInfo->ucBssIndex)); + + prWifiVar = &(prAdapter->rWifiVar); + ASSERT(prWifiVar); + + DBGLOG(RSN, TRACE, "WPS: Building WPS IE for (Re)Association Response"); + prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + + if (prP2pBssInfo->eNetworkType != NETWORK_TYPE_P2P) { + return; + } + + u2IELen = kalP2PCalWSC_IELen(prAdapter->prGlueInfo, 3, + (u8)prP2pBssInfo->u4PrivateData); + + kalP2PGenWSC_IE(prAdapter->prGlueInfo, 3, + (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength), + (u8)prP2pBssInfo->u4PrivateData); + prMsduInfo->u2FrameLength += (u16)kalP2PCalWSC_IELen( + prAdapter->prGlueInfo, 3, (u8)prP2pBssInfo->u4PrivateData); +} + +#endif + +#if CFG_SUPPORT_802_11W +/* AP PMF */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to validate setting if PMF connection capable + * or not If AP MFPC=1, and STA MFPC=1, we let this as PMF connection + * + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +u16 rsnPmfCapableValidation(IN P_ADAPTER_T prAdapter, IN P_BSS_INFO_T prBssInfo, + IN P_STA_RECORD_T prStaRec) +{ + u8 selfMfpc, selfMfpr, peerMfpc, peerMfpr; + + selfMfpc = prBssInfo->rApPmfCfg.fgMfpc; + selfMfpr = prBssInfo->rApPmfCfg.fgMfpr; + peerMfpc = prStaRec->rPmfCfg.fgMfpc; + peerMfpr = prStaRec->rPmfCfg.fgMfpr; + + DBGLOG(RSN, INFO, "AP mfpc:%d, mfpr:%d / STA mfpc:%d, mfpr:%d\n", selfMfpc, + selfMfpr, peerMfpc, peerMfpr); + + if ((selfMfpc == true) && (peerMfpc == false)) { + if ((selfMfpr == true) && (peerMfpr == false)) { + DBGLOG(RSN, ERROR, "PMF policy violation for case 4\n"); + return STATUS_CODE_ROBUST_MGMT_FRAME_POLICY_VIOLATION; + } + + if (peerMfpr == true) { + DBGLOG(RSN, ERROR, "PMF policy violation for case 7\n"); + return STATUS_CODE_ROBUST_MGMT_FRAME_POLICY_VIOLATION; + } + } + + if ((selfMfpc == true) && (peerMfpc == true)) { + DBGLOG(RSN, ERROR, "PMF Connection\n"); + prStaRec->rPmfCfg.fgApplyPmf = true; + } + + return STATUS_CODE_SUCCESSFUL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to generate TIMEOUT INTERVAL IE for association + * resp Add Timeout interval IE (56) when PMF invalid association + * + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void rsnPmfGenerateTimeoutIE(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + IE_TIMEOUT_INTERVAL_T *prTimeout; + P_STA_RECORD_T prStaRec = NULL; + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (!prStaRec) { + return; + } + + prTimeout = (IE_TIMEOUT_INTERVAL_T *)(((u8 *)prMsduInfo->prPacket) + + prMsduInfo->u2FrameLength); + + /* only when PMF connection, and association error code is 30 */ + if ((rsnCheckBipKeyInstalled(prAdapter, prStaRec) == true) && + (prStaRec->u2StatusCode == STATUS_CODE_ASSOC_REJECTED_TEMPORARILY)) { + DBGLOG(RSN, INFO, "rsnPmfGenerateTimeoutIE true\n"); + prTimeout->ucId = ELEM_ID_TIMEOUT_INTERVAL; + prTimeout->ucLength = ELEM_MAX_LEN_TIMEOUT_IE; + prTimeout->ucType = IE_TIMEOUT_INTERVAL_TYPE_ASSOC_COMEBACK; + prTimeout->u4Value = 1 << 10; + prMsduInfo->u2FrameLength += IE_SIZE(prTimeout); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to check the Sa query timeout. + * check if total retry time is greater than 1000ms + * + * \retval 1: retry max timeout. 0: not timeout + * \note + * Called by: AAA module, Handle by Sa Query timeout + */ +/*----------------------------------------------------------------------------*/ +u8 rsnApCheckSaQueryTimeout(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec) +{ + P_BSS_INFO_T prBssInfo; + u32 now; + + GET_CURRENT_SYSTIME(&now); + + if (CHECK_FOR_TIMEOUT(now, prStaRec->rPmfCfg.u4SAQueryStart, + TU_TO_MSEC(SA_QUERY_RETRY_TIMEOUT))) { + DBGLOG(RSN, INFO, "association SA Query timed out\n"); + + /* XXX PMF TODO how to report STA REC disconnect?? */ + /* when SAQ retry count timeout, clear this STA */ + prStaRec->rPmfCfg.ucSAQueryTimedOut = 1; + prStaRec->rPmfCfg.u2TransactionID = 0; + prStaRec->rPmfCfg.u4SAQueryCount = 0; + cnmTimerStopTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + /* refer to p2pRoleFsmRunEventRxDeauthentication*/ + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + if (bssRemoveClient(prAdapter, prBssInfo, prStaRec)) { + /* Indicate disconnect to Host. */ + p2pFuncDisconnect(prAdapter, prBssInfo, prStaRec, false, + REASON_CODE_DEAUTH_LEAVING_BSS, true); + /* Deactive BSS if PWR is IDLE and no peer */ + if (IS_NET_PWR_STATE_IDLE(prAdapter, prBssInfo->ucBssIndex) && + (bssGetClientCount(prAdapter, prBssInfo) == 0)) { + /* All Peer disconnected !! Stop BSS + * now!! */ + p2pFuncStopComplete(prAdapter, prBssInfo); + } + } + } + + return 1; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to start the 802.11w sa query timer. + * This routine is triggered every 201ms, and every time enter function, check + * max timeout + * + * \note + * Called by: AAA module, Handle TX SAQ request + */ +/*----------------------------------------------------------------------------*/ +void rsnApStartSaQueryTimer(IN P_ADAPTER_T prAdapter, + /* IN P_STA_RECORD_T prStaRec,*/ + IN unsigned long ulParamPtr) +{ + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)ulParamPtr; + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + P_ACTION_SA_QUERY_FRAME prTxFrame; + u16 u2PayloadLen; + + ASSERT(prStaRec); + + DBGLOG(RSN, INFO, "MFP: AP Start Sa Query timer\n"); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + if (prStaRec->rPmfCfg.u4SAQueryCount > 0 && + rsnApCheckSaQueryTimeout(prAdapter, prStaRec)) { + DBGLOG(RSN, INFO, "MFP: retry max timeout, u4SaQueryCount count =%lu\n", + prStaRec->rPmfCfg.u4SAQueryCount); + return; + } + + prMsduInfo = (P_MSDU_INFO_T)cnmMgtPktAlloc( + prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + + if (!prMsduInfo) { + return; + } + + prTxFrame = + (P_ACTION_SA_QUERY_FRAME)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + } + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucBSSID); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_SA_QUERY_ACTION; + prTxFrame->ucAction = ACTION_SA_QUERY_REQUEST; + + if (prStaRec->rPmfCfg.u4SAQueryCount == 0) { + GET_CURRENT_SYSTIME(&prStaRec->rPmfCfg.u4SAQueryStart); + } + + /* if retry, transcation id ++ */ + if (prStaRec->rPmfCfg.u4SAQueryCount) { + prStaRec->rPmfCfg.u2TransactionID++; + } else { + /* if first SAQ request, random pick transaction id */ + prStaRec->rPmfCfg.u2TransactionID = (u16)(kalRandomNumber() & 0xFFFF); + } + + DBGLOG(RSN, INFO, "SAQ transaction id:%d\n", + prStaRec->rPmfCfg.u2TransactionID); + + /* trnsform U16 to U8 array */ + prTxFrame->ucTransId[0] = + ((prStaRec->rPmfCfg.u2TransactionID & 0xff00) >> 8); + prTxFrame->ucTransId[1] = + ((prStaRec->rPmfCfg.u2TransactionID & 0x00ff) >> 0); + + prStaRec->rPmfCfg.u4SAQueryCount++; + + u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN; + + /* 4 <3> Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prStaRec->ucBssIndex, prStaRec->ucIndex, + WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, NULL, + MSDU_RATE_MODE_AUTO); + + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + DBGLOG(RSN, INFO, "SAQ Set MSDU_OPT_PROTECTED_FRAME\n"); + nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, true); + } + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); + + DBGLOG(RSN, INFO, "AP Set SA Query timer %lu (%d Tu)\n", + prStaRec->rPmfCfg.u4SAQueryCount, SA_QUERY_TIMEOUT); + + cnmTimerStartTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer, + TU_TO_MSEC(SA_QUERY_TIMEOUT)); +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to start the 802.11w TX SA query. + * + * + * \note + * Called by: AAA module, Handle Tx action frame request + */ +/*----------------------------------------------------------------------------*/ +void rsnApStartSaQuery(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + ASSERT(prStaRec); + + DBGLOG(RSN, INFO, "rsnApStartSaQuery\n"); + + if (prStaRec) { + cnmTimerStopTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer); + cnmTimerInitTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer, + (PFN_MGMT_TIMEOUT_FUNC)rsnApStartSaQueryTimer, + (unsigned long)prStaRec); + } + + if (prStaRec->rPmfCfg.u4SAQueryCount == 0) { + rsnApStartSaQueryTimer(prAdapter, (unsigned long)prStaRec); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to stop the 802.11w SA query. + * + * + * \note + * Called by: AAA module, stop TX SAQ if receive correct SAQ response + */ +/*----------------------------------------------------------------------------*/ +void rsnApStopSaQuery(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + ASSERT(prStaRec); + + cnmTimerStopTimer(prAdapter, &prStaRec->rPmfCfg.rSAQueryTimer); + prStaRec->rPmfCfg.u2TransactionID = 0; + prStaRec->rPmfCfg.u4SAQueryCount = 0; + prStaRec->rPmfCfg.ucSAQueryTimedOut = 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to process the 802.11w sa query action frame. + * + * + * \note + * Called by: AAA module, Handle Rx action request + */ +/*----------------------------------------------------------------------------*/ +void rsnApSaQueryRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + P_ACTION_SA_QUERY_FRAME prRxFrame = NULL; + u16 u2PayloadLen; + P_STA_RECORD_T prStaRec; + P_ACTION_SA_QUERY_FRAME prTxFrame; + + if (!prSwRfb) { + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + if (!prStaRec) { /* Todo:: for not AIS check */ + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + ASSERT(prBssInfo); + + prRxFrame = (P_ACTION_SA_QUERY_FRAME)prSwRfb->pvHeader; + if (!prRxFrame) { + return; + } + + DBGLOG(RSN, INFO, + "IEEE 802.11: AP Received SA Query Request from " MACSTR "\n", + MAC2STR(prStaRec->aucMacAddr)); + + DBGLOG_MEM8(RSN, INFO, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + + if (!rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + DBGLOG(RSN, INFO, + "IEEE 802.11: AP Ignore SA Query Request non-PMF STA " MACSTR + "\n", + MAC2STR(prStaRec->aucMacAddr)); + return; + } + + DBGLOG(RSN, INFO, "IEEE 802.11: Sending SA Query Response to " MACSTR "\n", + MAC2STR(prStaRec->aucMacAddr)); + + prMsduInfo = (P_MSDU_INFO_T)cnmMgtPktAlloc( + prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + + if (!prMsduInfo) { + return; + } + + /* drop cipher mismatch */ + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + if (HAL_RX_STATUS_IS_CIPHER_MISMATCH(prSwRfb->prRxStatus) || + HAL_RX_STATUS_IS_CLM_ERROR(prSwRfb->prRxStatus)) { + /* if cipher mismatch, or incorrect encrypt, just drop + */ + DBGLOG(RSN, ERROR, "drop SAQ req CM/CLM=1\n"); + return; + } + } + + prTxFrame = + (P_ACTION_SA_QUERY_FRAME)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD); + + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + prTxFrame->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + DBGLOG(RSN, INFO, "AP SAQ resp set FC PF bit\n"); + } + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucBSSID); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_SA_QUERY_ACTION; + prTxFrame->ucAction = ACTION_SA_QUERY_RESPONSE; + + kalMemCopy(prTxFrame->ucTransId, prRxFrame->ucTransId, + ACTION_SA_QUERY_TR_ID_LEN); + + u2PayloadLen = 2 + ACTION_SA_QUERY_TR_ID_LEN; + + /* 4 <3> Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prStaRec->ucBssIndex, prStaRec->ucIndex, + WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + u2PayloadLen, NULL, + MSDU_RATE_MODE_AUTO); + + if (rsnCheckBipKeyInstalled(prAdapter, prStaRec)) { + DBGLOG(RSN, INFO, "AP SAQ resp set MSDU_OPT_PROTECTED_FRAME\n"); + nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, true); + } + + /* 4 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to process the 802.11w sa query action frame. + * + * + * \note + * Called by: AAA module, Handle Rx action request + */ +/*----------------------------------------------------------------------------*/ +void rsnApSaQueryAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_ACTION_SA_QUERY_FRAME prRxFrame; + P_STA_RECORD_T prStaRec; + u16 u2SwapTrID; + + prRxFrame = (P_ACTION_SA_QUERY_FRAME)prSwRfb->pvHeader; + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + + if (!prStaRec) { + DBGLOG(RSN, WARN, "NULL prStaRec!\n"); + return; + } + + DBGLOG(RSN, TRACE, "AP PMF SAQ action enter from " MACSTR "\n", + MAC2STR(prStaRec->aucMacAddr)); + if (prSwRfb->u2PacketLen < ACTION_SA_QUERY_TR_ID_LEN) { + DBGLOG(RSN, INFO, + "IEEE 802.11: Too short SA Query Action frame (len=%lu)\n", + (unsigned long)prSwRfb->u2PacketLen); + return; + } + + if (prRxFrame->ucAction == ACTION_SA_QUERY_REQUEST) { + rsnApSaQueryRequest(prAdapter, prSwRfb); + return; + } + + if (prRxFrame->ucAction != ACTION_SA_QUERY_RESPONSE) { + DBGLOG(RSN, INFO, "IEEE 802.11: Unexpected SA Query Action %d\n", + prRxFrame->ucAction); + return; + } + + DBGLOG(RSN, INFO, + "IEEE 802.11: Received SA Query Response from " MACSTR "\n", + MAC2STR(prStaRec->aucMacAddr)); + + DBGLOG_MEM8(RSN, INFO, prRxFrame->ucTransId, ACTION_SA_QUERY_TR_ID_LEN); + + /* MLME-SAQuery.confirm */ + /* transform to network byte order */ + u2SwapTrID = htons(prStaRec->rPmfCfg.u2TransactionID); + if (kalMemCmp((u8 *)&u2SwapTrID, prRxFrame->ucTransId, + ACTION_SA_QUERY_TR_ID_LEN) == 0) { + DBGLOG(RSN, INFO, "AP Reply to SA Query received\n"); + rsnApStopSaQuery(prAdapter, prStaRec); + } else { + DBGLOG( + RSN, INFO, + "IEEE 802.11: AP No matching SA Query transaction identifier found\n"); + } +} + +#endif // CFG_SUPPORT_802_11W + +#if CFG_SUPPORT_H2E +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to generate RSNXE for + * associate request frame. + * + * \param[in] prAdapter The Selected BSS description + * \param[in] prMsduInfo MSDU packet buffer + * + * \retval N/A + * + * \note + * Called by: AIS module, Associate request + */ +/*----------------------------------------------------------------------------*/ +void rsnGenerateRSNXE(IN P_ADAPTER_T prAdapter, + IN OUT P_MSDU_INFO_T prMsduInfo) +{ + u8 *pucBuffer; + u8 ucLength; + P_CONNECTION_SETTINGS_T prConnSettings; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + ucLength = prConnSettings->rRsnXE.ucLength + 2; + + DBGLOG(RSN, INFO, "rsnGenerateRSNXE\n"); + + if (prConnSettings->rRsnXE.ucLength == 0) { + return; + } + + ASSERT(prMsduInfo); + + pucBuffer = (u8 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength); + + ASSERT(pucBuffer); + + /* if (eNetworkId != NETWORK_TYPE_AIS_INDEX) */ + /* return; */ + + kalMemCopy(pucBuffer, &(prConnSettings->rRsnXE), ucLength); + prMsduInfo->u2FrameLength += IE_SIZE(pucBuffer); + + DBGLOG_MEM8(RSN, INFO, pucBuffer, IE_SIZE(pucBuffer)); + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to calculate RSNXE length for + * associate request frame. + * + * \param[in] prAdapter Major data structure for driver operation + * \param[in] ucBssIndex unused for this function + * \param[in] prStaRec unused for this function + * + * \retval The append WPA IE length + * + * \note + * Called by: AIS module, Associate request + */ +/*----------------------------------------------------------------------------*/ +u32 rsnCalRSNXELen(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + P_STA_RECORD_T prStaRec) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + if (prConnSettings->rRsnXE.ucLength != 0) { + return prConnSettings->rRsnXE.ucLength + 2; + } + + return 0; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/saa_fsm.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/saa_fsm.c new file mode 100644 index 00000000000000..c21e06869eee4b --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/saa_fsm.c @@ -0,0 +1,1900 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "saa_fsm.c" + * \brief This file defines the FSM for SAA MODULE. + * + * This file defines the FSM for SAA MODULE. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +#if !DBG_DISABLE_ALL_LOG +static u8 *apucDebugAAState[AA_STATE_NUM] = { + (u8 *)DISP_STRING("AA_IDLE"), (u8 *)DISP_STRING("SAA_SEND_AUTH1"), + (u8 *)DISP_STRING("SAA_WAIT_AUTH2"), (u8 *)DISP_STRING("SAA_SEND_AUTH3"), + (u8 *)DISP_STRING("SAA_WAIT_AUTH4"), (u8 *)DISP_STRING("SAA_SEND_ASSOC1"), + (u8 *)DISP_STRING("SAA_WAIT_ASSOC2"), (u8 *)DISP_STRING("AAA_SEND_AUTH2"), + (u8 *)DISP_STRING("AAA_SEND_AUTH4"), (u8 *)DISP_STRING("AAA_SEND_ASSOC2"), + (u8 *)DISP_STRING("AA_RESOURCE") +}; +#endif +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* + * @brief prepare to send authentication or association frame + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void saaSendAuthAssoc(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + /* This function do the things like + * "case SAA_STATE_SEND_AUTH1/ASSOC1" in SAA FSM steps + */ + + u32 rStatus = WLAN_STATUS_FAILURE; + P_CONNECTION_SETTINGS_T prConnSettings = NULL; + u16 u2AuthTransSN = AUTH_TRANSACTION_SEQ_1; /* default for OPEN */ + P_BSS_DESC_T prBssDesc = NULL; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo = NULL; + PARAM_SSID_T rParamSsid; +#if CFG_SUPPORT_H2E + u16 u2AuthStatusCode = STATUS_CODE_RESERVED; +#endif + + ASSERT(prAdapter); + ASSERT(prStaRec); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + DBGLOG(SAA, INFO, "[SAA]saaSendAuthAssoc, StaState:%d\n", + prStaRec->ucStaState); + + if (prStaRec->ucTxAuthAssocRetryCount >= + prStaRec->ucTxAuthAssocRetryLimit) { + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = (prConnSettings->fgIsSendAssoc) ? + STATUS_CODE_ASSOC_TIMEOUT : + STATUS_CODE_AUTH_TIMEOUT; + + if (saaFsmSendEventJoinComplete(prAdapter, WLAN_STATUS_FAILURE, + prStaRec, + NULL) == WLAN_STATUS_RESOURCES) { + /* can set a timer and retry later */ + DBGLOG(SAA, WARN, + "[SAA]can't alloc msg for inform AIS join complete\n"); + } + } else { + prStaRec->ucTxAuthAssocRetryCount++; + /* Prepare to send authentication frame */ + if (!prConnSettings->fgIsSendAssoc) { + /* Fill authentication transaction sequence number + * depends on auth type + */ + if (((prAdapter->prGlueInfo->rWpaInfo.u4AuthAlg & AUTH_TYPE_SAE) || + (prAdapter->prGlueInfo->rWpaInfo.u4AuthAlg & + AUTH_TYPE_SHARED_KEY)) && + prConnSettings->ucAuthDataLen) { + kalMemCopy(&u2AuthTransSN, prConnSettings->aucAuthData, + AUTH_TRANSACTION_SEQENCE_NUM_FIELD_LEN); + DBGLOG(SAA, INFO, "[SAA]Get auth SN = %d from Conn Settings\n", + u2AuthTransSN); + } + +#if CFG_SUPPORT_H2E + if (prAdapter->prGlueInfo->rWpaInfo.u4AuthAlg & AUTH_TYPE_SAE) { + kalMemCopy(&u2AuthStatusCode, &prConnSettings->aucAuthData[2], + AUTH_STATUS_CODE_FIELD_LEN); + DBGLOG(SAA, INFO, + "[SAA]Get auth StatusCode=%d from Conn Settings\n", + u2AuthStatusCode); + } +#endif + + /* Update Station Record - Class 1 Flag */ + if (prStaRec->ucStaState != STA_STATE_1) { + DBGLOG(SAA, WARN, + "[SAA]Rx send auth CMD at unexpect state:%d\n", + prStaRec->ucStaState); + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + } +#if !CFG_SUPPORT_AAA + rStatus = authSendAuthFrame(prAdapter, prStaRec, u2AuthTransSN); +#else + rStatus = authSendAuthFrame(prAdapter, prStaRec, + prStaRec->ucBssIndex, NULL, + u2AuthTransSN, +#if CFG_SUPPORT_H2E + u2AuthStatusCode); +#else + STATUS_CODE_RESERVED); +#endif +#endif + prStaRec->eAuthAssocSent = u2AuthTransSN; + } else { /* Prepare to send association frame */ + /* Fill Cipher/AKM before sending association request, + * copy fro m AIS search step + */ + if (prConnSettings->ucSSIDLen) { + rParamSsid.u4SsidLen = prConnSettings->ucSSIDLen; + COPY_SSID(rParamSsid.aucSsid, rParamSsid.u4SsidLen, + prConnSettings->aucSSID, prConnSettings->ucSSIDLen); + prBssDesc = scanSearchBssDescByBssidAndSsid( + prAdapter, prStaRec->aucMacAddr, true, &rParamSsid); + DBGLOG(RSN, INFO, + "[RSN]saaSendAuthAssoc," + "prBssDesc[" MACSTR " ,%s] Searched by" + " BSSID[" MACSTR "] & SSID %s.\n", + MAC2STR(prBssDesc->aucBSSID), prBssDesc->aucSSID, + MAC2STR(prStaRec->aucMacAddr), prConnSettings->aucSSID); + } else { + prBssDesc = scanSearchBssDescByBssidAndChanNum( + prAdapter, prStaRec->aucMacAddr, true, + prConnSettings->ucChannelNum); + DBGLOG(RSN, INFO, + "[RSN]saaSendAuthAssoc," + "prBssDesc[" MACSTR " ,%s] Searched by" + " BSSID[" MACSTR "] & ChanNum %d.\n", + MAC2STR(prBssDesc->aucBSSID), prBssDesc->aucSSID, + MAC2STR(prStaRec->aucMacAddr), + prConnSettings->ucChannelNum); + } + + prAisSpecBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + if (rsnPerformPolicySelection(prAdapter, prBssDesc)) { + if (prAisSpecBssInfo->fgCounterMeasure) { + DBGLOG(RSN, WARN, "Skip whle at counter measure perid\n"); + } else { + DBGLOG(RSN, INFO, "Bss RSN matched!\n"); + prAdapter->prAisBssInfo->u4RsnSelectedGroupCipher = + prBssDesc->u4RsnSelectedGroupCipher; + prAdapter->prAisBssInfo->u4RsnSelectedPairwiseCipher = + prBssDesc->u4RsnSelectedPairwiseCipher; + prAdapter->prAisBssInfo->u4RsnSelectedAKMSuite = + prBssDesc->u4RsnSelectedAKMSuite; + } + } else { + DBGLOG(RSN, WARN, "Bss fail for RSN check\n"); + } + + if (prStaRec->ucStaState == STA_STATE_1) { + /* don't change to state2 for reassociation */ + /* Update Station Record - Class 2 Flag */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + } + + rStatus = assocSendReAssocReqFrame(prAdapter, prStaRec); + prStaRec->eAuthAssocSent = AA_SENT_ASSOC1; + } + + if (rStatus != WLAN_STATUS_SUCCESS) { + /* maybe can't alloc msdu info, retry after timeout */ + cnmTimerInitTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventTxReqTimeOut, + (unsigned long)prStaRec); + + cnmTimerStartTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(TX_AUTHENTICATION_RETRY_TIMEOUT_TU)); + } + } +} + +void saaSendAuthSeq3(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + u32 rStatus = WLAN_STATUS_FAILURE; + + ASSERT(prAdapter); + ASSERT(prStaRec); + + DBGLOG(SAA, INFO, "[SAA]send auth 3\n"); + + if (prStaRec->ucTxAuthAssocRetryCount >= + prStaRec->ucTxAuthAssocRetryLimit) { + /* Record the Status Code of Auth Request */ + prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; + } else { + prStaRec->ucTxAuthAssocRetryCount++; + +#if !CFG_SUPPORT_AAA + rStatus = + authSendAuthFrame(prAdapter, prStaRec, AUTH_TRANSACTION_SEQ_3); +#else + rStatus = authSendAuthFrame(prAdapter, prStaRec, prStaRec->ucBssIndex, + NULL, AUTH_TRANSACTION_SEQ_3, + STATUS_CODE_RESERVED); +#endif + + prStaRec->eAuthAssocSent = AA_SENT_AUTH3; + + if (rStatus != WLAN_STATUS_SUCCESS) { + cnmTimerInitTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventTxReqTimeOut, + (unsigned long)prStaRec); + + cnmTimerStartTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(TX_AUTHENTICATION_RETRY_TIMEOUT_TU)); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief The Core FSM engine of SAA Module. + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] eNextState The value of Next State + * @param[in] prRetainedSwRfb Pointer to the retained SW_RFB_T for JOIN + * Success + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void saaFsmSteps(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, + IN ENUM_AA_STATE_T eNextState, IN P_SW_RFB_T prRetainedSwRfb) +{ + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + ENUM_AA_STATE_T ePreviousState; + u8 fgIsTransition; + + ASSERT(prStaRec); + if (!prStaRec || g_u4HaltFlag) { + return; + } + + do { + DBGLOG(SAA, STATE, "[SAA]TRANSITION: [%s] -> [%s]\n", + apucDebugAAState[prStaRec->eAuthAssocState], + apucDebugAAState[eNextState]); + + ePreviousState = prStaRec->eAuthAssocState; + + /* NOTE(Kevin): This is the only place to change the + * eAuthAssocState(except initial) */ + prStaRec->eAuthAssocState = eNextState; + + fgIsTransition = (u8)false; + switch (prStaRec->eAuthAssocState) { + case AA_STATE_IDLE: + + if (ePreviousState != prStaRec->eAuthAssocState) { /* Only + * trigger + * this + * event + * once + */ + if (prRetainedSwRfb) { + if (saaFsmSendEventJoinComplete( + prAdapter, WLAN_STATUS_SUCCESS, prStaRec, + prRetainedSwRfb) == WLAN_STATUS_SUCCESS) { + /* ToDo:: Nothing */ + } else { + eNextState = AA_STATE_RESOURCE; + fgIsTransition = true; + } + } else { + if (saaFsmSendEventJoinComplete( + prAdapter, WLAN_STATUS_FAILURE, prStaRec, NULL) == + WLAN_STATUS_RESOURCES) { + eNextState = AA_STATE_RESOURCE; + fgIsTransition = true; + } + } + } + + /* Free allocated TCM memory */ + if (prStaRec->prChallengeText) { + cnmMemFree(prAdapter, prStaRec->prChallengeText); + prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T)NULL; + } + + break; + + case SAA_STATE_SEND_AUTH1: + + /* Do tasks in INIT STATE */ + if (prStaRec->ucTxAuthAssocRetryCount >= + prStaRec->ucTxAuthAssocRetryLimit) { + /* Record the Status Code of Authentication + * Request */ + prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; + + eNextState = AA_STATE_IDLE; + fgIsTransition = true; + } else { + prStaRec->ucTxAuthAssocRetryCount++; + + /* Update Station Record - Class 1 Flag */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + +#if !CFG_SUPPORT_AAA + rStatus = authSendAuthFrame(prAdapter, prStaRec, + AUTH_TRANSACTION_SEQ_1); +#else + rStatus = authSendAuthFrame(prAdapter, prStaRec, + prStaRec->ucBssIndex, NULL, + AUTH_TRANSACTION_SEQ_1, + STATUS_CODE_RESERVED); +#endif + if (rStatus != WLAN_STATUS_SUCCESS) { + cnmTimerInitTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventTxReqTimeOut, + (unsigned long)prStaRec); + + cnmTimerStartTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(TX_AUTHENTICATION_RETRY_TIMEOUT_TU)); + } + } + + break; + + case SAA_STATE_WAIT_AUTH2: + break; + + case SAA_STATE_SEND_AUTH3: + + /* Do tasks in INIT STATE */ + if (prStaRec->ucTxAuthAssocRetryCount >= + prStaRec->ucTxAuthAssocRetryLimit) { + /* Record the Status Code of Authentication + * Request */ + prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; + + eNextState = AA_STATE_IDLE; + fgIsTransition = true; + } else { + prStaRec->ucTxAuthAssocRetryCount++; + +#if !CFG_SUPPORT_AAA + rStatus = authSendAuthFrame(prAdapter, prStaRec, + AUTH_TRANSACTION_SEQ_3); +#else + rStatus = authSendAuthFrame(prAdapter, prStaRec, + prStaRec->ucBssIndex, NULL, + AUTH_TRANSACTION_SEQ_3, + STATUS_CODE_RESERVED); +#endif + if (rStatus != WLAN_STATUS_SUCCESS) { + cnmTimerInitTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventTxReqTimeOut, + (unsigned long)prStaRec); + + cnmTimerStartTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(TX_AUTHENTICATION_RETRY_TIMEOUT_TU)); + } + } + + break; + + case SAA_STATE_WAIT_AUTH4: + break; + + case SAA_STATE_SEND_ASSOC1: + /* Do tasks in INIT STATE */ + if (prStaRec->ucTxAuthAssocRetryCount >= + prStaRec->ucTxAuthAssocRetryLimit) { + /* Record the Status Code of Authentication + * Request */ + prStaRec->u2StatusCode = STATUS_CODE_ASSOC_TIMEOUT; + + eNextState = AA_STATE_IDLE; + fgIsTransition = true; + } else { + prStaRec->ucTxAuthAssocRetryCount++; + + rStatus = assocSendReAssocReqFrame(prAdapter, prStaRec); + if (rStatus != WLAN_STATUS_SUCCESS) { + cnmTimerInitTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventTxReqTimeOut, + (unsigned long)prStaRec); + + cnmTimerStartTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(TX_ASSOCIATION_RETRY_TIMEOUT_TU)); + } + } + + break; + + case SAA_STATE_WAIT_ASSOC2: + break; + + case AA_STATE_RESOURCE: + /* TODO(Kevin) Can setup a timer and send message later + */ + break; + + default: + DBGLOG(SAA, ERROR, "Unknown AA STATE\n"); + ASSERT(0); + break; + } + } while (fgIsTransition); + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will send Event to AIS/BOW/P2P + * + * @param[in] rJoinStatus To indicate JOIN success or failure. + * @param[in] prStaRec Pointer to the STA_RECORD_T + * @param[in] prSwRfb Pointer to the SW_RFB_T + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +saaFsmSendEventJoinComplete(IN P_ADAPTER_T prAdapter, + IN WLAN_STATUS rJoinStatus, + IN P_STA_RECORD_T prStaRec, IN P_SW_RFB_T prSwRfb) +{ + P_BSS_INFO_T prBssInfo; + + ASSERT(prStaRec); + if (!prStaRec) { + DBGLOG(SAA, ERROR, "[%s]prStaRec is NULL\n", __func__); + return WLAN_STATUS_INVALID_PACKET; + } + if (!prAdapter) { + DBGLOG(SAA, ERROR, "[%s]prAdapter is NULL\n", __func__); + return WLAN_STATUS_INVALID_PACKET; + } + + /* Store limitation about 40Mhz bandwidth capability during association + */ + if (prStaRec->ucBssIndex < BSS_INFO_NUM) { + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + if (prBssInfo != NULL) { + if (rJoinStatus == WLAN_STATUS_SUCCESS) { + prBssInfo->fg40mBwAllowed = prBssInfo->fgAssoc40mBwAllowed; + /* Initialize OpMode Channel Width change indicator */ + prBssInfo->fgIsOpChangeChannelWidth = false; + + // /* reset add key action */ + // prBssInfo->eKeyAction = SEC_TX_KEY_COMMAND; + } + prBssInfo->fgAssoc40mBwAllowed = false; + } + } + + /* For wlan0 (AP) + p2p0, don't check the prAisBssInfo for the P2P. */ +#if CFG_ENABLE_WIFI_DIRECT + if ((prAdapter->fgIsP2PRegistered) && (IS_STA_IN_P2P(prStaRec))) { + P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; + + prSaaFsmCompMsg = + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); + if (!prSaaFsmCompMsg) { + return WLAN_STATUS_RESOURCES; + } + + if (rJoinStatus == WLAN_STATUS_SUCCESS) { + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + } + + prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_P2P_JOIN_COMPLETE; + prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; + prSaaFsmCompMsg->rJoinStatus = rJoinStatus; + prSaaFsmCompMsg->prStaRec = prStaRec; + prSaaFsmCompMsg->prSwRfb = prSwRfb; + + /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prSaaFsmCompMsg, + MSG_SEND_METHOD_UNBUF); + + return WLAN_STATUS_SUCCESS; + } +#endif /* CFG_ENABLE_WIFI_DIRECT */ + if (!prAdapter->prAisBssInfo) { + DBGLOG(SAA, ERROR, "prAdapter->prAisBssInfo is NULL\n"); + return WLAN_STATUS_INVALID_PACKET; + } + if (prStaRec->ucBssIndex == prAdapter->prAisBssInfo->ucBssIndex) { + P_MSG_SAA_FSM_COMP_T prSaaFsmCompMsg; + + prSaaFsmCompMsg = + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, sizeof(MSG_SAA_FSM_COMP_T)); + if (!prSaaFsmCompMsg) { + return WLAN_STATUS_RESOURCES; + } + + if (rJoinStatus == WLAN_STATUS_SUCCESS) { + prStaRec->u2StatusCode = STATUS_CODE_SUCCESSFUL; + } + + prSaaFsmCompMsg->rMsgHdr.eMsgId = MID_SAA_AIS_JOIN_COMPLETE; + prSaaFsmCompMsg->ucSeqNum = prStaRec->ucAuthAssocReqSeqNum; + prSaaFsmCompMsg->rJoinStatus = rJoinStatus; + prSaaFsmCompMsg->prStaRec = prStaRec; + prSaaFsmCompMsg->prSwRfb = prSwRfb; + + /* NOTE(Kevin): Set to UNBUF for immediately JOIN complete */ + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prSaaFsmCompMsg, + MSG_SEND_METHOD_UNBUF); + + return WLAN_STATUS_SUCCESS; + } else { + DBGLOG(SAA, ERROR, "Invalid case in %s.\n", __func__); + return WLAN_STATUS_FAILURE; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will handle the Start Event to SAA FSM. + * + * @param[in] prMsgHdr Message of Join Request for a particular STA. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void saaFsmRunEventStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_SAA_FSM_START_T prSaaFsmStartMsg; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(prMsgHdr); + + prSaaFsmStartMsg = (P_MSG_SAA_FSM_START_T)prMsgHdr; + prStaRec = prSaaFsmStartMsg->prStaRec; + + if ((!prStaRec) || (prStaRec->fgIsInUse == false)) { + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + ASSERT(prStaRec); + + DBGLOG(SAA, LOUD, "EVENT-START: Trigger SAA FSM.\n"); + + /* record sequence number of request message */ + prStaRec->ucAuthAssocReqSeqNum = prSaaFsmStartMsg->ucSeqNum; + + cnmMemFree(prAdapter, prMsgHdr); + + /* 4 <1> Validation of SAA Start Event */ + if (!IS_AP_STA(prStaRec)) { + DBGLOG(SAA, ERROR, "EVENT-START: STA Type - %d was not supported.\n", + prStaRec->eStaType); + + /* Ignore the return value because don't care the prSwRfb */ + saaFsmSendEventJoinComplete(prAdapter, WLAN_STATUS_FAILURE, prStaRec, + NULL); + + return; + } + /* 4 <2> The previous JOIN process is not completed ? */ + if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { + DBGLOG(SAA, ERROR, "EVENT-START: Reentry of SAA Module.\n"); + prStaRec->eAuthAssocState = AA_STATE_IDLE; + } + /* 4 <3> Reset Status Code and Time */ + /* Update Station Record - Status/Reason Code */ + prStaRec->u2StatusCode = STATUS_CODE_UNSPECIFIED_FAILURE; + + /* Update the record join time. */ + GET_CURRENT_SYSTIME(&prStaRec->rLastJoinTime); + + prStaRec->ucTxAuthAssocRetryCount = 0; + + if (prStaRec->prChallengeText) { + cnmMemFree(prAdapter, prStaRec->prChallengeText); + prStaRec->prChallengeText = (P_IE_CHALLENGE_TEXT_T)NULL; + } + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + /* 4 <4> Init the sec fsm */ + /* secFsmInit(prAdapter, prStaRec); */ + + /* 4 <5> Reset the STA STATE */ + /* Update Station Record - Class 1 Flag */ + /* NOTE(Kevin): Moved to AIS FSM for Reconnect issue - + * We won't deactivate the same STA_RECORD_T and then activate it again + * for the case of reconnection. + */ + /* cnmStaRecChangeState(prStaRec, STA_STATE_1); */ + + /* 4 <6> Decide if this BSS 20/40M bandwidth is allowed */ + if (prStaRec->ucBssIndex < BSS_INFO_NUM) { + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11N) && + (prStaRec->ucPhyTypeSet & PHY_TYPE_SET_802_11N)) { + prBssInfo->fgAssoc40mBwAllowed = + cnmBss40mBwPermitted(prAdapter, prBssInfo->ucBssIndex); + } else { + prBssInfo->fgAssoc40mBwAllowed = false; + } + DBGLOG(RLM, TRACE, "STA 40mAllowed=%d\n", + prBssInfo->fgAssoc40mBwAllowed); + } + + if (!IS_STA_IN_P2P(prStaRec)) { + /* skip SAA FSM */ + prStaRec->eAuthAssocSent = AA_SENT_NONE; + saaSendAuthAssoc(prAdapter, prStaRec); + } else { + /* 4 <7> Trigger SAA FSM */ + if (prStaRec->ucStaState == STA_STATE_1) { + saaFsmSteps(prAdapter, prStaRec, SAA_STATE_SEND_AUTH1, + (P_SW_RFB_T)NULL); + } else if (prStaRec->ucStaState == STA_STATE_2 || + prStaRec->ucStaState == STA_STATE_3) { + saaFsmSteps(prAdapter, prStaRec, SAA_STATE_SEND_ASSOC1, + (P_SW_RFB_T)NULL); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will handle TxDone(Auth1/Auth3/AssocReq) Event of SAA + * FSM. + * + * @param[in] prMsduInfo Pointer to the MSDU_INFO_T. + * @param[in] rTxDoneStatus Return TX status of the Auth1/Auth3/AssocReq frame. + * + * @retval WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +saaFsmRunEventTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_STA_RECORD_T prStaRec; + ENUM_AA_STATE_T eNextState; + + ASSERT(prMsduInfo); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (!prStaRec) { + return WLAN_STATUS_INVALID_PACKET; + } + + ASSERT(prStaRec); + + DBGLOG(SAA, LOUD, "EVENT-TX DONE: Current Time = %d\n", kalGetTimeTick()); + + /* Trigger statistics log if Auth/Assoc Tx failed */ + if (rTxDoneStatus != TX_RESULT_SUCCESS) { + wlanTriggerStatsLog(prAdapter, prAdapter->rWifiVar.u4StatsLogDuration); + } + + if (!IS_STA_IN_P2P(prStaRec)) { + /* check the outgoing frame is matched with + * the last sent frame, ignore the unmatched txdone + */ + if ((prStaRec->eAuthAssocSent >= AA_SENT_AUTH1) && + (prStaRec->eAuthAssocSent <= AA_SENT_AUTH4)) { + if (authCheckTxAuthFrame(prAdapter, prMsduInfo, + prStaRec->eAuthAssocSent) != + WLAN_STATUS_SUCCESS) { + return WLAN_STATUS_SUCCESS; + } + } else if (prStaRec->eAuthAssocSent == AA_SENT_ASSOC1) { + if (assocCheckTxReAssocReqFrame(prAdapter, prMsduInfo) != + WLAN_STATUS_SUCCESS) { + return WLAN_STATUS_SUCCESS; + } + } else { + DBGLOG(SAA, WARN, "unexpected sent frame = %d\n", + prStaRec->eAuthAssocSent); + } + + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + if (rTxDoneStatus == TX_RESULT_SUCCESS) { + cnmTimerInitTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventRxRespTimeOut, + (unsigned long)prStaRec); + + if (prAdapter->prGlueInfo->rWpaInfo.u4AuthAlg & AUTH_TYPE_SAE) { + cnmTimerStartTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(DOT11_RSNA_SAE_RETRANS_PERIOD_TU)); + } else { + cnmTimerStartTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU)); + } + } else { /* Tx failed, do retry if possible */ + /* Add for support wep when enable wpa3 */ + if (prStaRec->eAuthAssocSent == AA_SENT_AUTH3) { + saaSendAuthSeq3(prAdapter, prStaRec); + } else { + saaSendAuthAssoc(prAdapter, prStaRec); + } + } + } else { + eNextState = prStaRec->eAuthAssocState; + + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_SEND_AUTH1: { + /* Strictly check the outgoing frame is matched with + * current AA STATE */ + if (authCheckTxAuthFrame(prAdapter, prMsduInfo, + AUTH_TRANSACTION_SEQ_1) != + WLAN_STATUS_SUCCESS) { + break; + } + + if (rTxDoneStatus == TX_RESULT_SUCCESS) { + eNextState = SAA_STATE_WAIT_AUTH2; + + cnmTimerStopTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer); + + cnmTimerInitTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventRxRespTimeOut, + (unsigned long)prStaRec); + + if (prAdapter->prGlueInfo->rWpaInfo.u4AuthAlg & AUTH_TYPE_SAE) { + cnmTimerStartTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(DOT11_RSNA_SAE_RETRANS_PERIOD_TU)); + } else { + cnmTimerStartTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU)); + } + } + + /* if TX was successful, change to next state. + * if TX was failed, do retry if possible. + */ + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T)NULL); + } break; + + case SAA_STATE_SEND_AUTH3: { + /* Strictly check the outgoing frame is matched with + * current JOIN STATE */ + if (authCheckTxAuthFrame(prAdapter, prMsduInfo, + AUTH_TRANSACTION_SEQ_3) != + WLAN_STATUS_SUCCESS) { + break; + } + + if (rTxDoneStatus == TX_RESULT_SUCCESS) { + eNextState = SAA_STATE_WAIT_AUTH4; + + cnmTimerStopTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer); + + cnmTimerInitTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventRxRespTimeOut, + (unsigned long)prStaRec); + + cnmTimerStartTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + TU_TO_MSEC(DOT11_AUTHENTICATION_RESPONSE_TIMEOUT_TU)); + } + + /* if TX was successful, change to next state. + * if TX was failed, do retry if possible. + */ + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T)NULL); + } break; + + case SAA_STATE_SEND_ASSOC1: { + /* Strictly check the outgoing frame is matched with + * current SAA STATE */ + if (assocCheckTxReAssocReqFrame(prAdapter, prMsduInfo) != + WLAN_STATUS_SUCCESS) { + break; + } + + if (rTxDoneStatus == TX_RESULT_SUCCESS) { + eNextState = SAA_STATE_WAIT_ASSOC2; + + cnmTimerStopTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer); + + cnmTimerInitTimer( + prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer, + (PFN_MGMT_TIMEOUT_FUNC)saaFsmRunEventRxRespTimeOut, + (unsigned long)prStaRec); + + cnmTimerStartTimer( + prAdapter, &(prStaRec->rTxReqDoneOrRxRespTimer), + TU_TO_MSEC(DOT11_ASSOCIATION_RESPONSE_TIMEOUT_TU)); + } + + /* if TX was successful, change to next state. + * if TX was failed, do retry if possible. + */ + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T)NULL); + } break; + + default: + break; /* Ignore other cases */ + } + } + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will send Tx Request Timeout Event to SAA FSM. + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void saaFsmRunEventTxReqTimeOut(IN P_ADAPTER_T prAdapter, + IN unsigned long plParamPtr) +{ + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)plParamPtr; + + ASSERT(prStaRec); + if (!prStaRec) { + return; + } + + DBGLOG(SAA, LOUD, "EVENT-TIMER: TX REQ TIMEOUT, Current Time = %d\n", + kalGetTimeTick()); + + /* Trigger statistics log if Auth/Assoc Tx timeout */ + wlanTriggerStatsLog(prAdapter, prAdapter->rWifiVar.u4StatsLogDuration); + if (!IS_STA_IN_P2P(prStaRec)) { + saaSendAuthAssoc(prAdapter, prStaRec); + } else { + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_SEND_AUTH1: + case SAA_STATE_SEND_AUTH3: + case SAA_STATE_SEND_ASSOC1: + saaFsmSteps(prAdapter, prStaRec, prStaRec->eAuthAssocState, + (P_SW_RFB_T)NULL); + break; + + default: + return; + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will send Rx Response Timeout Event to SAA FSM. + * + * @param[in] prStaRec Pointer to the STA_RECORD_T + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void saaFsmRunEventRxRespTimeOut(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr) +{ + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)ulParamPtr; + ENUM_AA_STATE_T eNextState; + DBGLOG(SAA, LOUD, "EVENT-TIMER: RX RESP TIMEOUT, Current Time = %d\n", + kalGetTimeTick()); + + ASSERT(prStaRec); + if (!prStaRec) { + return; + } + + if (!IS_STA_IN_P2P(prStaRec)) { + /* Retry the last sent frame if possible */ + if (prStaRec->ucStaState != STA_STATE_3) { + saaSendAuthAssoc(prAdapter, prStaRec); + } + } else { + eNextState = prStaRec->eAuthAssocState; + + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_WAIT_AUTH2: + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; + + /* Pull back to earlier state to do retry */ + eNextState = SAA_STATE_SEND_AUTH1; + break; + + case SAA_STATE_WAIT_AUTH4: + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_AUTH_TIMEOUT; + + /* Pull back to earlier state to do retry */ + eNextState = SAA_STATE_SEND_AUTH3; + break; + + case SAA_STATE_WAIT_ASSOC2: + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = STATUS_CODE_ASSOC_TIMEOUT; + + /* Pull back to earlier state to do retry */ + eNextState = SAA_STATE_SEND_ASSOC1; + break; + + default: + break; /* Ignore other cases */ + } + + if (eNextState != prStaRec->eAuthAssocState) { + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T)NULL); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will process the Rx Auth Response Frame and then + * trigger SAA FSM. + * + * @param[in] prSwRfb Pointer to the SW_RFB_T structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void saaFsmRunEventRxAuth(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_STA_RECORD_T prStaRec; + u16 u2StatusCode; + ENUM_AA_STATE_T eNextState; + u8 ucWlanIdx; + P_GLUE_INFO_T prGlueInfo = NULL; + P_WLAN_AUTH_FRAME_T prAuthFrame = (P_WLAN_AUTH_FRAME_T)NULL; + u8 *pFrameBuf = NULL; + u8 fgIsInterruptContext = false; + + ASSERT(prSwRfb); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ucWlanIdx = (u8)HAL_RX_STATUS_GET_WLAN_IDX(prSwRfb->prRxStatus); + prGlueInfo = prAdapter->prGlueInfo; + + ASSERT(prGlueInfo); + + /* We should have the corresponding Sta Record. */ + if (!prStaRec) { + DBGLOG(SAA, WARN, + "Received a AuthResp: wlanIdx[%d] w/o corresponding staRec\n", + ucWlanIdx); + return; + } + + if (!IS_AP_STA(prStaRec)) { + return; + } + + /* check received auth frame */ + if ((authCheckRxAuthFrameStatus(prAdapter, prSwRfb, + prStaRec->eAuthAssocSent, + &u2StatusCode) == WLAN_STATUS_SUCCESS) && + (!(IS_STA_IN_P2P(prStaRec)))) { + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = u2StatusCode; + + /*Report Rx auth frame to upper layer*/ + prAuthFrame = (P_WLAN_AUTH_FRAME_T)prSwRfb->pvHeader; + + DBGLOG(INIT, INFO, "Dump rx auth data\n"); + DBGLOG_MEM8(REQ, INFO, prAuthFrame, prSwRfb->u2PacketLen); + + /*add for WEP */ + if ((prAuthFrame->u2AuthAlgNum == AUTH_ALGORITHM_NUM_SHARED_KEY) && + (prAuthFrame->aucAuthData[0] == AUTH_TRANSACTION_SEQ_2)) { + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + authProcessRxAuth2_Auth4Frame(prAdapter, prSwRfb); + saaSendAuthSeq3(prAdapter, prStaRec); + return; + } + } else { + DBGLOG( + SAA, INFO, + "Report RX auth to upper layer with alg:%d, SN:%d, status:%d\n", + prAuthFrame->u2AuthAlgNum, prAuthFrame->aucAuthData[0], + prAuthFrame->aucAuthData[2]); + + if (in_interrupt()) { + pFrameBuf = kalMemAlloc(prSwRfb->u2PacketLen, PHY_MEM_TYPE); + fgIsInterruptContext = true; + } else { + pFrameBuf = kalMemAlloc(prSwRfb->u2PacketLen, VIR_MEM_TYPE); + fgIsInterruptContext = false; + } + + if (!pFrameBuf) { + DBGLOG(SAA, ERROR, "Alloc buffer for frame failed\n"); + return; + } + + kalMemCopy((void *)pFrameBuf, (void *)prAuthFrame, + prSwRfb->u2PacketLen); + kalWDevLockThread(prGlueInfo, prGlueInfo->prDevHandler, + CFG80211_RX_MLME_MGMT, pFrameBuf, + prSwRfb->u2PacketLen, NULL, 0, NULL, 0, + fgIsInterruptContext); + + DBGLOG(SAA, INFO, "notification of RX Authentication Done\n"); + } + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + if (u2StatusCode == STATUS_CODE_SUCCESSFUL || + (u2StatusCode == WLAN_STATUS_SAE_HASH_TO_ELEMENT)) { + authProcessRxAuth2_Auth4Frame(prAdapter, prSwRfb); + } else { + DBGLOG(SAA, INFO, + "Auth Req was rejected by [" MACSTR "], Status Code = %d\n", + MAC2STR(prStaRec->aucMacAddr), u2StatusCode); + + /* AIS retry JOIN or indicate JOIN FAILURE to upper + * layer*/ + if (saaFsmSendEventJoinComplete(prAdapter, WLAN_STATUS_FAILURE, + prStaRec, + NULL) == WLAN_STATUS_RESOURCES) { + /* can set a timer and retry later */ + DBGLOG(SAA, WARN, + "[SAA]can't alloc msg for inform AIS join complete\n"); + } + } + } else { + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_SEND_AUTH1: + case SAA_STATE_WAIT_AUTH2: + /* Check if the incoming frame is what we are waiting + * for */ + if (authCheckRxAuthFrameStatus( + prAdapter, prSwRfb, AUTH_TRANSACTION_SEQ_2, + &u2StatusCode) == WLAN_STATUS_SUCCESS) { + cnmTimerStopTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer); + + /* Record the Status Code of Authentication + * Request */ + prStaRec->u2StatusCode = u2StatusCode; + + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + authProcessRxAuth2_Auth4Frame(prAdapter, prSwRfb); + + if (prStaRec->ucAuthAlgNum == + (u8)AUTH_ALGORITHM_NUM_SHARED_KEY) { + eNextState = SAA_STATE_SEND_AUTH3; + } else { + /* Update Station Record - Class + * 2 Flag */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + + eNextState = SAA_STATE_SEND_ASSOC1; + } + } else { + DBGLOG(SAA, INFO, + "Auth Req was rejected by [" MACSTR + "], Status Code = %d\n", + MAC2STR(prStaRec->aucMacAddr), u2StatusCode); + + eNextState = AA_STATE_IDLE; + } + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T)NULL); + } + break; + + case SAA_STATE_SEND_AUTH3: + case SAA_STATE_WAIT_AUTH4: + /* Check if the incoming frame is what we are waiting + * for */ + if (authCheckRxAuthFrameStatus( + prAdapter, prSwRfb, AUTH_TRANSACTION_SEQ_4, + &u2StatusCode) == WLAN_STATUS_SUCCESS) { + cnmTimerStopTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer); + + /* Record the Status Code of Authentication + * Request */ + prStaRec->u2StatusCode = u2StatusCode; + + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + authProcessRxAuth2_Auth4Frame(prAdapter, + prSwRfb); /* Add for + * 802.11r + * handling + */ + + /* Update Station Record - Class 2 Flag + */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_2); + + eNextState = SAA_STATE_SEND_ASSOC1; + } else { + DBGLOG(SAA, INFO, + "Auth Req was rejected by [" MACSTR + "], Status Code = %d\n", + MAC2STR(prStaRec->aucMacAddr), u2StatusCode); + + eNextState = AA_STATE_IDLE; + } + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + + saaFsmSteps(prAdapter, prStaRec, eNextState, (P_SW_RFB_T)NULL); + } + break; + + default: + break; /* Ignore other cases */ + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will process the Rx (Re)Association Response Frame and + * then trigger SAA FSM. + * + * @param[in] prSwRfb Pointer to the SW_RFB_T structure. + * + * @retval WLAN_STATUS_SUCCESS if the status code was not success + * @retval WLAN_STATUS_BUFFER_RETAINED if the status code was success + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS saaFsmRunEventRxAssoc(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb) +{ + P_STA_RECORD_T prStaRec; + u16 u2StatusCode; + ENUM_AA_STATE_T eNextState; + P_SW_RFB_T prRetainedSwRfb = (P_SW_RFB_T)NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u8 ucWlanIdx; + P_GLUE_INFO_T prGlueInfo = NULL; + P_WLAN_ASSOC_RSP_FRAME_T prAssocRspFrame = NULL; + P_CONNECTION_SETTINGS_T prConnSettings = NULL; + + ASSERT(prSwRfb); + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ucWlanIdx = (u8)HAL_RX_STATUS_GET_WLAN_IDX(prSwRfb->prRxStatus); + prGlueInfo = prAdapter->prGlueInfo; + + ASSERT(prGlueInfo); + + prConnSettings = &prGlueInfo->prAdapter->rWifiVar.rConnSettings; + + DBGLOG(SAA, INFO, "RX Assoc Resp\n"); + + /* We should have the corresponding Sta Record. */ + if (!prStaRec) { + /* ASSERT(0); */ + DBGLOG(SAA, WARN, + "Received a AssocResp: wlanIdx[%d] w/o corresponding staRec\n", + ucWlanIdx); + return rStatus; + } + + if (!IS_AP_STA(prStaRec)) { + return rStatus; + } + + /* true if the incoming frame is what we are waiting for */ + if ((assocCheckRxReAssocRspFrameStatus(prAdapter, prSwRfb, &u2StatusCode) == + WLAN_STATUS_SUCCESS) && + (!(IS_STA_IN_P2P(prStaRec)))) { + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + /* Record the Status Code of Authentication Request */ + prStaRec->u2StatusCode = u2StatusCode; + + /*Report Rx assoc frame to upper layer*/ + prAssocRspFrame = (P_WLAN_ASSOC_RSP_FRAME_T)prSwRfb->pvHeader; + + /* The BSS from cfg80211_ops.assoc must give back to + * cfg80211_send_rx_assoc() or to cfg80211_assoc_timeout(). + * To ensure proper refcounting, new association requests + * while already associating must be rejected. + */ + DBGLOG(SAA, INFO, "Report RX Assoc to upper layer, %s\n", + prConnSettings->bss ? "DO IT" : "Oops"); + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_ASSOC_RESP, prAssocRspFrame, + prSwRfb->u2PacketLen); + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + + /* update RCPI */ + ASSERT(prSwRfb->prRxStatusGroup3); + prStaRec->ucRCPI = nicRxGetRcpiValueFromRxv(RCPI_MODE_WF0, prSwRfb); + + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + /* Update Station Record - Class 3 Flag */ + /* NOTE(Kevin): Moved to AIS FSM for roaming issue + * We should deactivate the struct STA_RECORD of + * previous AP before activate new one in Driver. + */ + /* cnmStaRecChangeState(prStaRec, STA_STATE_3); */ + /* Clear history. */ + prStaRec->ucJoinFailureCount = 0; + + if (saaFsmSendEventJoinComplete(prAdapter, WLAN_STATUS_SUCCESS, + prStaRec, + prSwRfb) == WLAN_STATUS_RESOURCES) { + /* can set a timer and retry later */ + DBGLOG(SAA, WARN, + "[SAA]can't alloc msg for inform AIS join complete\n"); + } + + rStatus = WLAN_STATUS_PENDING; + } else { + DBGLOG(SAA, INFO, + "Assoc Req was rejected by [" MACSTR "], Status Code = %d\n", + MAC2STR(prStaRec->aucMacAddr), u2StatusCode); + + if (saaFsmSendEventJoinComplete(prAdapter, WLAN_STATUS_FAILURE, + prStaRec, + NULL) == WLAN_STATUS_RESOURCES) { + /* can set a timer and retry later */ + DBGLOG(SAA, WARN, + "[SAA]can't alloc msg for inform AIS join complete\n"); + } + } + } else { + switch (prStaRec->eAuthAssocState) { + case SAA_STATE_SEND_ASSOC1: + case SAA_STATE_WAIT_ASSOC2: + /* true if the incoming frame is what we are waiting for + */ + if (assocCheckRxReAssocRspFrameStatus( + prAdapter, prSwRfb, &u2StatusCode) == WLAN_STATUS_SUCCESS) { + cnmTimerStopTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer); + + /* Record the Status Code of Authentication + * Request */ + prStaRec->u2StatusCode = u2StatusCode; + + if (u2StatusCode == STATUS_CODE_SUCCESSFUL) { + /* Update Station Record - Class 3 Flag + */ + /* NOTE(Kevin): Moved to AIS FSM for + * roaming issue - We should deactivate + * the STA_RECORD_T of previous AP + * before activate new one in Driver. + */ + /* cnmStaRecChangeState(prStaRec, + * STA_STATE_3); */ + + prStaRec->ucJoinFailureCount = 0; /* Clear + * history. + */ + + prRetainedSwRfb = prSwRfb; + rStatus = WLAN_STATUS_PENDING; + } else { + DBGLOG(SAA, INFO, + "Assoc Req was rejected by [" MACSTR + "], Status Code = %d\n", + MAC2STR(prStaRec->aucMacAddr), u2StatusCode); + } + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + + /* update RCPI */ + ASSERT(prSwRfb->prRxStatusGroup3); + prStaRec->ucRCPI = + nicRxGetRcpiValueFromRxv(RCPI_MODE_WF0, prSwRfb); + + eNextState = AA_STATE_IDLE; + + saaFsmSteps(prAdapter, prStaRec, eNextState, prRetainedSwRfb); + } + break; + + default: + break; /* Ignore other cases */ + } + } + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will check the incoming Deauth Frame. + * + * @param[in] prSwRfb Pointer to the SW_RFB_T structure. + * + * @retval WLAN_STATUS_SUCCESS Always not retain deauthentication frames + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS saaFsmRunEventRxDeauth(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb) +{ + P_STA_RECORD_T prStaRec; + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; + u8 ucWlanIdx; + u8 ucRoleIdx = 0; + u8 *pFrameBuf = NULL; + P_BSS_INFO_T prBssInfo = NULL; + u8 fgIsInterruptContext = false; + + ASSERT(prSwRfb); + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T)prSwRfb->pvHeader; + ucWlanIdx = (u8)HAL_RX_STATUS_GET_WLAN_IDX(prSwRfb->prRxStatus); + + DBGLOG(SAA, EVENT, + "Rx Deauth frame ,DA[" MACSTR "] SA[" MACSTR "] BSSID[" MACSTR + "] ReasonCode[0x%x]\n", + MAC2STR(prDeauthFrame->aucDestAddr), + MAC2STR(prDeauthFrame->aucSrcAddr), MAC2STR(prDeauthFrame->aucBSSID), + prDeauthFrame->u2ReasonCode); + + do { + /* We should have the corresponding Sta Record. */ + if (!prStaRec) { + DBGLOG(SAA, WARN, + "Received a Deauth: wlanIdx[%d] w/o corresponding staRec\n", + ucWlanIdx); + break; + } + + if (IS_STA_IN_AIS(prStaRec)) { + P_BSS_INFO_T prAisBssInfo; + + if (!IS_AP_STA(prStaRec)) { + break; + } + + prAisBssInfo = prAdapter->prAisBssInfo; + + if (prStaRec->ucStaState >= STA_STATE_1) { + cnmTimerStopTimer(prAdapter, + &prStaRec->rTxReqDoneOrRxRespTimer); + + /* Check if this is the AP we are associated or + * associating with */ + if (authProcessRxDeauthFrame(prSwRfb, prStaRec->aucMacAddr, + &prStaRec->u2ReasonCode) == + WLAN_STATUS_SUCCESS) { + P_AIS_SPECIFIC_BSS_INFO_T + prAisSpecBssInfo; + + prAisSpecBssInfo = + &(prAdapter->rWifiVar.rAisSpecificBssInfo); +#if CFG_SUPPORT_802_11W + DBGLOG( + RSN, INFO, + "QM RX MGT: Deauth frame, P=%d Sec=%d CM=%d BC=%d fc=%02x\n", + prAisSpecBssInfo->fgMgmtProtection, + HAL_RX_STATUS_GET_SEC_MODE(prSwRfb->prRxStatus), + HAL_RX_STATUS_IS_CIPHER_MISMATCH(prSwRfb->prRxStatus), + IS_BMCAST_MAC_ADDR(prDeauthFrame->aucDestAddr), + prDeauthFrame->u2FrameCtrl); + + if (prAisSpecBssInfo->fgMgmtProtection && + prStaRec->fgIsTxAllowed && + HAL_RX_STATUS_IS_CIPHER_MISMATCH(prSwRfb->prRxStatus) + /* HAL_RX_STATUS_GET_SEC_MODE(prSwRfb->prRxStatus) + * != CIPHER_SUITE_BIP */ + ) { + saaChkDeauthfrmParamHandler(prAdapter, prSwRfb, + prStaRec); + if (prStaRec->fgIsTxAllowed) { + DBGLOG(RSN, INFO, "ignore no sec deauth\n"); + } + return WLAN_STATUS_SUCCESS; + } +#endif + + DBGLOG(SAA, INFO, + "notification of RX deauthentication %d\n", + prSwRfb->u2PacketLen); + + if (in_interrupt()) { + pFrameBuf = + kalMemAlloc(prSwRfb->u2PacketLen, PHY_MEM_TYPE); + fgIsInterruptContext = true; + } else { + pFrameBuf = + kalMemAlloc(prSwRfb->u2PacketLen, VIR_MEM_TYPE); + fgIsInterruptContext = false; + } + + if (!pFrameBuf) { + DBGLOG(SAA, ERROR, "Alloc buffer for frame failed\n"); + return WLAN_STATUS_RESOURCES; + } + + kalMemCopy((void *)pFrameBuf, (void *)prDeauthFrame, + prSwRfb->u2PacketLen); + kalWDevLockThread(prAdapter->prGlueInfo, + prAdapter->prGlueInfo->prDevHandler, + CFG80211_RX_MLME_MGMT, pFrameBuf, + prSwRfb->u2PacketLen, NULL, 0, NULL, 0, + fgIsInterruptContext); + + DBGLOG(SAA, INFO, + "notification of RX deauthentication Done\n"); + saaSendDisconnectMsgHandler(prAdapter, prStaRec, + prAisBssInfo, FRM_DEAUTH); + } + } + } else if (prAdapter->fgIsP2PRegistered && IS_STA_IN_P2P(prStaRec)) { + DBGLOG(SAA, INFO, "notification of RX deauthentication %d\n", + prSwRfb->u2PacketLen); + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + ucRoleIdx = (u8)prBssInfo->u4PrivateData; + + if (in_interrupt()) { + pFrameBuf = kalMemAlloc(prSwRfb->u2PacketLen, PHY_MEM_TYPE); + fgIsInterruptContext = true; + } else { + pFrameBuf = kalMemAlloc(prSwRfb->u2PacketLen, VIR_MEM_TYPE); + fgIsInterruptContext = false; + } + + if (!pFrameBuf) { + DBGLOG(SAA, ERROR, "Alloc buffer for frame failed\n"); + return WLAN_STATUS_RESOURCES; + } + + kalMemCopy((void *)pFrameBuf, (void *)prDeauthFrame, + prSwRfb->u2PacketLen); + kalWDevLockThread( + prAdapter->prGlueInfo, + prAdapter->prGlueInfo->prP2PInfo[ucRoleIdx]->aprRoleHandler, + CFG80211_RX_MLME_MGMT, pFrameBuf, prSwRfb->u2PacketLen, NULL, 0, + NULL, 0, fgIsInterruptContext); + + DBGLOG(SAA, INFO, "notification of RX deauthentication Done\n"); + + p2pRoleFsmRunEventRxDeauthentication(prAdapter, prStaRec, prSwRfb); + } else { + ASSERT(0); + } + } while (false); + + return WLAN_STATUS_SUCCESS; +} + +/* for AOSP */ +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will check param of deauth frame and reson code for + * deauth + * + * @param[in] + * + * @retval + */ +/*----------------------------------------------------------------------------*/ + +void saaChkDeauthfrmParamHandler(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_STA_RECORD_T prStaRec) +{ + P_WLAN_DEAUTH_FRAME_T prDeauthFrame; + + do { + prDeauthFrame = (P_WLAN_DEAUTH_FRAME_T)prSwRfb->pvHeader; + if (!IS_BMCAST_MAC_ADDR(prDeauthFrame->aucDestAddr) && + (prStaRec->u2ReasonCode == REASON_CODE_CLASS_2_ERR || + prStaRec->u2ReasonCode == REASON_CODE_CLASS_3_ERR)) { + DBGLOG(RSN, INFO, "QM RX MGT: rsnStartSaQuery\n"); +#if CFG_SUPPORT_802_11W + /* MFP test plan 5.3.3.5 */ + rsnStartSaQuery(prAdapter); +#endif + } else { + DBGLOG(RSN, INFO, "RXM: Drop unprotected Mgmt frame\n"); + DBGLOG( + RSN, INFO, + "RXM: (MAC RX Done) RX (u2StatusFlag=0x%x) (ucKIdxSecMode=0x%x) " + "(ucWlanIdx=0x%x)\n", + prSwRfb->prRxStatus->u2StatusFlag, + prSwRfb->prRxStatus->ucTidSecMode, + prSwRfb->prRxStatus->ucWlanIdx); + } + } while (0); +} + +/* for AOSP */ +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will check and send disconnect message to AIS module + * + * @param[in] + * + * @retval + */ +/*----------------------------------------------------------------------------*/ +void saaSendDisconnectMsgHandler(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, + IN P_BSS_INFO_T prAisBssInfo, + IN ENUM_AA_FRM_TYPE_T eFrmType) +{ + do { + if (eFrmType == FRM_DEAUTH) { + if (prStaRec->ucStaState == STA_STATE_3) { + P_MSG_AIS_ABORT_T prAisAbortMsg; + + /* NOTE(Kevin): Change state immediately to + * avoid starvation of MSG buffer because of too + * many deauth frames before changing the STA + * state. + */ + cnmStaRecChangeState(prAdapter, prStaRec, STA_STATE_1); + + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + break; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_SAA_AIS_FSM_ABORT; + prAisAbortMsg->ucReasonOfDisconnect = + DISCONNECT_REASON_CODE_DEAUTHENTICATED; + prAisAbortMsg->fgDelayIndication = false; + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prAisAbortMsg, + MSG_SEND_METHOD_BUF); + } else { + prStaRec->ucTxAuthAssocRetryCount = 0; + /* 20210421 frog: STA STATE other than STATE_3, + * so should be JOIN_ABORT. */ + if (saaFsmSendEventJoinComplete( + prAdapter, WLAN_STATUS_JOIN_ABORT, prStaRec, NULL) == + WLAN_STATUS_RESOURCES) { + /* can set a timer and retry later */ + DBGLOG( + SAA, WARN, + "[SAA]can't alloc msg for inform AIS join complete\n"); + } + } + } else { /* FRM_DISASSOC */ + if (prStaRec->ucStaState == STA_STATE_3) { + P_MSG_AIS_ABORT_T prAisAbortMsg; + + prAisAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + if (!prAisAbortMsg) { + break; + } + + prAisAbortMsg->rMsgHdr.eMsgId = MID_SAA_AIS_FSM_ABORT; + prAisAbortMsg->ucReasonOfDisconnect = + DISCONNECT_REASON_CODE_DISASSOCIATED; + prAisAbortMsg->fgDelayIndication = false; + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prAisAbortMsg, + MSG_SEND_METHOD_BUF); + } else { + prStaRec->ucTxAuthAssocRetryCount = 0; + + /* 20210421 frog: STA STATE other than STATE_3, + * so should be JOIN_ABORT. */ + if (saaFsmSendEventJoinComplete( + prAdapter, WLAN_STATUS_JOIN_ABORT, prStaRec, NULL) == + WLAN_STATUS_RESOURCES) { + /* can set a timer and retry later */ + DBGLOG( + SAA, WARN, + "[SAA]can't alloc msg for inform AIS join complete\n"); + } + } + } + if (prAisBssInfo) { + prAisBssInfo->u2DeauthReason = prStaRec->u2ReasonCode; + } + } while (0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will check the incoming Disassociation Frame. + * + * @param[in] prSwRfb Pointer to the SW_RFB_T structure. + * + * @retval WLAN_STATUS_SUCCESS Always not retain disassociation frames + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS saaFsmRunEventRxDisassoc(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb) +{ + P_STA_RECORD_T prStaRec; + P_WLAN_DISASSOC_FRAME_T prDisassocFrame; + u8 ucWlanIdx; + struct wireless_dev *wdev = NULL; + P_BSS_INFO_T prBssInfo = NULL; + u8 ucRoleIdx = 0; + u8 *pFrameBuf = NULL; + u8 fgIsInterruptContext = false; + + ASSERT(prSwRfb); + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + prDisassocFrame = (P_WLAN_DISASSOC_FRAME_T)prSwRfb->pvHeader; + ucWlanIdx = (u8)HAL_RX_STATUS_GET_WLAN_IDX(prSwRfb->prRxStatus); + wdev = prAdapter->prGlueInfo->prDevHandler->ieee80211_ptr; + + DBGLOG(SAA, EVENT, + "Rx Disassoc frame from BSSID[" MACSTR "] DA[" MACSTR + "] ReasonCode[0x%x]\n", + MAC2STR(prDisassocFrame->aucBSSID), + MAC2STR(prDisassocFrame->aucDestAddr), + prDisassocFrame->u2ReasonCode); + + do { + /* We should have the corresponding Sta Record. */ + if (!prStaRec) { + DBGLOG( + SAA, WARN, + "Received a DisAssoc: wlanIdx[%d] w/o corresponding staRec\n", + ucWlanIdx); + break; + } + + if (IS_STA_IN_AIS(prStaRec)) { + P_BSS_INFO_T prAisBssInfo; + + if (!IS_AP_STA(prStaRec)) { + break; + } + + prAisBssInfo = prAdapter->prAisBssInfo; + + if (prStaRec->ucStaState > STA_STATE_1) { + /* Check if this is the AP we are associated or + * associating with */ + if (assocProcessRxDisassocFrame( + prAdapter, prSwRfb, prStaRec->aucMacAddr, + &prStaRec->u2ReasonCode) == WLAN_STATUS_SUCCESS) { + P_AIS_SPECIFIC_BSS_INFO_T + prAisSpecBssInfo; +#if CFG_SUPPORT_802_11W + prAisSpecBssInfo = + &(prAdapter->rWifiVar.rAisSpecificBssInfo); + + DBGLOG( + RSN, INFO, + "QM RX MGT: Disassoc frame, P=%d Sec=%d CM=%d BC=%d fc=%02x\n", + prAisSpecBssInfo->fgMgmtProtection, + HAL_RX_STATUS_GET_SEC_MODE(prSwRfb->prRxStatus), + HAL_RX_STATUS_IS_CIPHER_MISMATCH(prSwRfb->prRxStatus), + IS_BMCAST_MAC_ADDR(prDisassocFrame->aucDestAddr), + prDisassocFrame->u2FrameCtrl); + if (IS_STA_IN_AIS(prStaRec) && + prAisSpecBssInfo->fgMgmtProtection && + HAL_RX_STATUS_IS_CIPHER_MISMATCH(prSwRfb->prRxStatus) + /* HAL_RX_STATUS_GET_SEC_MODE(prSwRfb->prRxStatus) + * != CIPHER_SUITE_CCMP */ + ) { + /* prDisassocFrame = + * (P_WLAN_DISASSOC_FRAME_T) + * prSwRfb->pvHeader; */ + saaChkDisassocfrmParamHandler( + prAdapter, prDisassocFrame, prStaRec, prSwRfb); + return WLAN_STATUS_SUCCESS; + } +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0)) +#define CONNECTED_BSS(wdev) wdev->current_bss +#else +#define CONNECTED_BSS(wdev) wdev->connected +#endif + DBGLOG(SAA, INFO, "notification of RX disassociation %d\n", + prSwRfb->u2PacketLen); + if (CONNECTED_BSS(wdev)) { + if (in_interrupt()) { + pFrameBuf = + kalMemAlloc(prSwRfb->u2PacketLen, PHY_MEM_TYPE); + fgIsInterruptContext = true; + } else { + pFrameBuf = + kalMemAlloc(prSwRfb->u2PacketLen, VIR_MEM_TYPE); + fgIsInterruptContext = false; + } + + if (!pFrameBuf) { + DBGLOG(SAA, ERROR, + "Alloc buffer for frame failed\n"); + return WLAN_STATUS_RESOURCES; + } + + kalMemCopy((void *)pFrameBuf, (void *)prDisassocFrame, + prSwRfb->u2PacketLen); + kalWDevLockThread(prAdapter->prGlueInfo, + prAdapter->prGlueInfo->prDevHandler, + CFG80211_RX_MLME_MGMT, pFrameBuf, + prSwRfb->u2PacketLen, NULL, 0, NULL, + 0, fgIsInterruptContext); + } + DBGLOG(SAA, INFO, + "notification of RX disassociation Done\n"); + saaSendDisconnectMsgHandler(prAdapter, prStaRec, + prAisBssInfo, FRM_DISASSOC); + } + } + } else if (prAdapter->fgIsP2PRegistered && (IS_STA_IN_P2P(prStaRec))) { + DBGLOG(SAA, INFO, "notification of RX disassociation %d\n", + prSwRfb->u2PacketLen); + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + ucRoleIdx = (u8)prBssInfo->u4PrivateData; + wdev = prAdapter->prGlueInfo->prP2PInfo[ucRoleIdx] + ->prDevHandler->ieee80211_ptr; + if (CONNECTED_BSS(wdev)) { + if (in_interrupt()) { + pFrameBuf = kalMemAlloc(prSwRfb->u2PacketLen, PHY_MEM_TYPE); + fgIsInterruptContext = true; + } else { + pFrameBuf = kalMemAlloc(prSwRfb->u2PacketLen, VIR_MEM_TYPE); + fgIsInterruptContext = false; + } + + if (!pFrameBuf) { + DBGLOG(SAA, ERROR, "Alloc buffer for frame failed\n"); + return WLAN_STATUS_RESOURCES; + } + + kalMemCopy((void *)pFrameBuf, (void *)prDisassocFrame, + prSwRfb->u2PacketLen); + kalWDevLockThread( + prAdapter->prGlueInfo, + prAdapter->prGlueInfo->prP2PInfo[ucRoleIdx]->aprRoleHandler, + CFG80211_RX_MLME_MGMT, pFrameBuf, prSwRfb->u2PacketLen, + NULL, 0, NULL, 0, fgIsInterruptContext); + } + DBGLOG(SAA, INFO, "notification of RX disassociation Done\n"); + + p2pRoleFsmRunEventRxDisassociation(prAdapter, prStaRec, prSwRfb); + } else { + ASSERT(0); + } + } while (false); + + return WLAN_STATUS_SUCCESS; +} + +/* for AOSP */ +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will check param of Disassoc frame and reson code for + * Disassoc + * + * @param[in] + * + * @retval + */ +/*----------------------------------------------------------------------------*/ + +void saaChkDisassocfrmParamHandler(IN P_ADAPTER_T prAdapter, + IN P_WLAN_DISASSOC_FRAME_T prDisassocFrame, + IN P_STA_RECORD_T prStaRec, + IN P_SW_RFB_T prSwRfb) +{ + if (!IS_BMCAST_MAC_ADDR(prDisassocFrame->aucDestAddr) && + (prStaRec->u2ReasonCode == REASON_CODE_CLASS_2_ERR || + prStaRec->u2ReasonCode == REASON_CODE_CLASS_3_ERR)) { +#if CFG_SUPPORT_802_11W + /* MFP test plan 5.3.3.5 */ + DBGLOG(RSN, INFO, "QM RX MGT: rsnStartSaQuery\n"); + rsnStartSaQuery(prAdapter); +#endif + } else { + DBGLOG(RSN, INFO, "RXM: Drop unprotected Mgmt frame\n"); + DBGLOG(RSN, INFO, + "RXM: (MAC RX Done) RX (u2StatusFlag=0x%x) (ucKIdxSecMode=0x%x) " + "(ucWlanIdx=0x%x)\n", + prSwRfb->prRxStatus->u2StatusFlag, + prSwRfb->prRxStatus->ucTidSecMode, + prSwRfb->prRxStatus->ucWlanIdx); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will handle the Abort Event to SAA FSM. + * + * @param[in] prMsgHdr Message of Abort Request for a particular STA. + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void saaFsmRunEventAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_SAA_FSM_ABORT_T prSaaFsmAbortMsg; + P_STA_RECORD_T prStaRec; + + ASSERT(prMsgHdr); + + prSaaFsmAbortMsg = (P_MSG_SAA_FSM_ABORT_T)prMsgHdr; + prStaRec = prSaaFsmAbortMsg->prStaRec; + + ASSERT(prStaRec); + if (!prStaRec) { + cnmMemFree(prAdapter, prMsgHdr); + return; + } + + DBGLOG(SAA, LOUD, "EVENT-ABORT: Stop SAA FSM.\n"); + + cnmMemFree(prAdapter, prMsgHdr); + + /* Reset Send Auth/(Re)Assoc Frame Count */ + prStaRec->ucTxAuthAssocRetryCount = 0; + + /* Cancel JOIN relative Timer */ + cnmTimerStopTimer(prAdapter, &prStaRec->rTxReqDoneOrRxRespTimer); + + if (prStaRec->eAuthAssocState != AA_STATE_IDLE) { + DBGLOG(SAA, LOUD, "EVENT-ABORT: Previous Auth/Assoc State == %s.\n", + apucDebugAAState[prStaRec->eAuthAssocState]); + } + + /* Free this StaRec */ + cnmStaRecFree(prAdapter, prStaRec); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/scan.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/scan.c new file mode 100644 index 00000000000000..e44d61d6d86207 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/scan.c @@ -0,0 +1,2679 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "scan.c" + * \brief This file defines the scan profile and the processing function of + * scan result for SCAN Module. + * + * The SCAN Profile selection is part of SCAN MODULE and responsible for + * defining SCAN Parameters - e.g. MIN_CHANNEL_TIME, number of scan channels. In + * this file we also define the process of SCAN Result including adding, + * searching and removing SCAN record from the list. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define REPLICATED_BEACON_TIME_THRESHOLD (3000) +#define REPLICATED_BEACON_FRESH_PERIOD (10000) +#define REPLICATED_BEACON_STRENGTH_THRESHOLD (32) + +#define ROAMING_NO_SWING_RCPI_STEP (10) + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used by SCN to initialize its variables + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void scnInit(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_BSS_DESC_T prBSSDesc; + u8 *pucBSSBuff; + u32 i; +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP + P_ROAM_BSS_DESC_T prRoamBSSDesc; + u8 *pucRoamBSSBuff; +#endif + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + pucBSSBuff = &prScanInfo->aucScanBuffer[0]; +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP + pucRoamBSSBuff = &prScanInfo->aucScanRoamBuffer[0]; +#endif + + DBGLOG(SCN, INFO, "->scnInit()\n"); + + /* 4 <1> Reset STATE and Message List */ + prScanInfo->eCurrentState = SCAN_STATE_IDLE; + + prScanInfo->rLastScanCompletedTime = (u32)0; + + LINK_INITIALIZE(&prScanInfo->rPendingMsgList); + + /* 4 <2> Reset link list of BSS_DESC_T */ + kalMemZero((void *)pucBSSBuff, SCN_MAX_BUFFER_SIZE); +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP + kalMemZero((void *)pucRoamBSSBuff, SCN_ROAM_MAX_BUFFER_SIZE); +#endif + + LINK_INITIALIZE(&prScanInfo->rFreeBSSDescList); + LINK_INITIALIZE(&prScanInfo->rBSSDescList); +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP + LINK_INITIALIZE(&prScanInfo->rRoamFreeBSSDescList); + LINK_INITIALIZE(&prScanInfo->rRoamBSSDescList); +#endif + + for (i = 0; i < CFG_MAX_NUM_BSS_LIST; i++) { + prBSSDesc = (P_BSS_DESC_T)pucBSSBuff; + + LINK_INSERT_TAIL(&prScanInfo->rFreeBSSDescList, &prBSSDesc->rLinkEntry); + + pucBSSBuff += ALIGN_4(sizeof(BSS_DESC_T)); + } + /* Check if the memory allocation consist with this initialization + * function */ + ASSERT(((unsigned long)pucBSSBuff - + (unsigned long)&prScanInfo->aucScanBuffer[0]) == + SCN_MAX_BUFFER_SIZE); + +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP + for (i = 0; i < CFG_MAX_NUM_ROAM_BSS_LIST; i++) { + prRoamBSSDesc = (P_ROAM_BSS_DESC_T)pucRoamBSSBuff; + + LINK_INSERT_TAIL(&prScanInfo->rRoamFreeBSSDescList, + &prRoamBSSDesc->rLinkEntry); + + pucRoamBSSBuff += ALIGN_4(sizeof(ROAM_BSS_DESC_T)); + } + ASSERT(((unsigned long)pucRoamBSSBuff - + (unsigned long)&prScanInfo->aucScanRoamBuffer[0]) == + SCN_ROAM_MAX_BUFFER_SIZE); +#endif + /* reset freest channel information */ + prScanInfo->fgIsSparseChannelValid = false; + + /* reset NLO state */ + prScanInfo->fgNloScanning = false; +} + +void scnFreeAllPendingScanRquests(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_MSG_HDR_T prMsgHdr; + P_MSG_SCN_SCAN_REQ prScanReqMsg; + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + /* check for pending scanning requests */ + while (!LINK_IS_EMPTY(&(prScanInfo->rPendingMsgList))) { + /* load next message from pending list as scan parameters */ + LINK_REMOVE_HEAD(&(prScanInfo->rPendingMsgList), prMsgHdr, P_MSG_HDR_T); + if (prMsgHdr) { + prScanReqMsg = (P_MSG_SCN_SCAN_REQ)prMsgHdr; + DBGLOG(SCN, INFO, + "free scan request eMsgId[%d] ucSeqNum [%d] BSSID[%d]!!\n", + prMsgHdr->eMsgId, prScanReqMsg->ucSeqNum, + prScanReqMsg->ucBssIndex); + cnmMemFree(prAdapter, prMsgHdr); + } else { + /* should not deliver to this function */ + ASSERT(0); + } + /* switch to next state */ + } + + DBGLOG(SCN, INFO, "%s()\n", __func__); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used by SCN to uninitialize its variables + * + * @param (none) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void scnUninit(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + DBGLOG(SCN, INFO, "%s()\n", __func__); + + scnFreeAllPendingScanRquests(prAdapter); + + /* 4 <1> Reset STATE and Message List */ + prScanInfo->eCurrentState = SCAN_STATE_IDLE; + + prScanInfo->rLastScanCompletedTime = (u32)0; + + /* NOTE(Kevin): Check rPendingMsgList ? */ + + /* 4 <2> Reset link list of BSS_DESC_T */ + LINK_INITIALIZE(&prScanInfo->rFreeBSSDescList); + LINK_INITIALIZE(&prScanInfo->rBSSDescList); +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP + LINK_INITIALIZE(&prScanInfo->rRoamFreeBSSDescList); + LINK_INITIALIZE(&prScanInfo->rRoamBSSDescList); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Find the corresponding BSS Descriptor according to given BSSID + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] aucBSSID Given BSSID. + * + * @return Pointer to BSS Descriptor, if found. NULL, if not found + */ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T scanSearchBssDescByBssid(IN P_ADAPTER_T prAdapter, + IN u8 aucBSSID[]) +{ + return scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, false, NULL); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Find the corresponding BSS Descriptor according to given BSSID + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] aucBSSID Given BSSID. + * @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID + * with single BSSID cases) + * @param[in] prSsid Specified SSID + * + * @return Pointer to BSS Descriptor, if found. NULL, if not found + */ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchBssDescByBssidAndSsid(IN P_ADAPTER_T prAdapter, IN u8 aucBSSID[], + IN u8 fgCheckSsid, IN P_PARAM_SSID_T prSsid) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc; + P_BSS_DESC_T prDstBssDesc = (P_BSS_DESC_T)NULL; + + ASSERT(prAdapter); + ASSERT(aucBSSID); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prBSSDescList = &prScanInfo->rBSSDescList; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T){ + if (!(EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID))) { + continue; + } + if (fgCheckSsid == false || prSsid == NULL) { + return prBssDesc; + } + + if (EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prSsid->aucSsid, prSsid->u4SsidLen)) { + return prBssDesc; + } + if (prDstBssDesc == NULL && prBssDesc->fgIsHiddenSSID == true) { + prDstBssDesc = prBssDesc; + continue; + } + if (prBssDesc->eBSSType == BSS_TYPE_P2P_DEVICE) { + /* 20120206 frog: Equal BSSID but not SSID, + * SSID not hidden, SSID must be updated. + */ + COPY_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, prSsid->aucSsid, + (u8)(prSsid->u4SsidLen)); + return prBssDesc; + } + } + + return prDstBssDesc; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Find the corresponding BSS Descriptor + * according to given BSSID & ChanNum + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] aucBSSID Given BSSID. + * @param[in] fgCheckChanNum Need to check ChanNum or not. + * @param[in] ucChannelNum Specified Channel Num + * + * @return Pointer to BSS Descriptor, if found. NULL, if not found + */ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T scanSearchBssDescByBssidAndChanNum(IN P_ADAPTER_T prAdapter, + IN u8 aucBSSID[], + IN u8 fgCheckChanNum, + IN u8 ucChannelNum) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + + ASSERT(prAdapter); + ASSERT(aucBSSID); + ASSERT(ucChannelNum); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prBSSDescList = &prScanInfo->rBSSDescList; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T){ + if (!(EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID))) { + continue; + } + if (fgCheckChanNum == false || ucChannelNum == 0) { + return prBssDesc; + } + + if (prBssDesc->ucChannelNum == ucChannelNum) { + return prBssDesc; + } + } + + return prBssDesc; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Find the corresponding BSS Descriptor according to given Transmitter + * Address. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] aucSrcAddr Given Source Address(TA). + * + * @return Pointer to BSS Descriptor, if found. NULL, if not found + */ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T scanSearchBssDescByTA(IN P_ADAPTER_T prAdapter, + IN u8 aucSrcAddr[]) +{ + return scanSearchBssDescByTAAndSsid(prAdapter, aucSrcAddr, false, NULL); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Find the corresponding BSS Descriptor according to given Transmitter + * Address. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] aucSrcAddr Given Source Address(TA). + * @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID + * with single BSSID cases) + * @param[in] prSsid Specified SSID + * + * @return Pointer to BSS Descriptor, if found. NULL, if not found + */ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchBssDescByTAAndSsid(IN P_ADAPTER_T prAdapter, IN u8 aucSrcAddr[], + IN u8 fgCheckSsid, IN P_PARAM_SSID_T prSsid) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc; + P_BSS_DESC_T prDstBssDesc = (P_BSS_DESC_T)NULL; + + ASSERT(prAdapter); + ASSERT(aucSrcAddr); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prBSSDescList = &prScanInfo->rBSSDescList; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T){ + if (EQUAL_MAC_ADDR(prBssDesc->aucSrcAddr, aucSrcAddr)) { + if (fgCheckSsid == false || prSsid == NULL) { + return prBssDesc; + } + + if (EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prSsid->aucSsid, prSsid->u4SsidLen)) { + return prBssDesc; + } else if (prDstBssDesc == NULL && + prBssDesc->fgIsHiddenSSID == true) { + prDstBssDesc = prBssDesc; + } + } + } + + return prDstBssDesc; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Find the corresponding BSS Descriptor according to + * given eBSSType, BSSID and Transmitter Address + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] eBSSType BSS Type of incoming Beacon/ProbeResp frame. + * @param[in] aucBSSID Given BSSID of Beacon/ProbeResp frame. + * @param[in] aucSrcAddr Given source address (TA) of Beacon/ProbeResp frame. + * + * @return Pointer to BSS Descriptor, if found. NULL, if not found + */ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchExistingBssDesc(IN P_ADAPTER_T prAdapter, IN ENUM_BSS_TYPE_T eBSSType, + IN u8 aucBSSID[], IN u8 aucSrcAddr[]) +{ + return scanSearchExistingBssDescWithSsid(prAdapter, eBSSType, aucBSSID, + aucSrcAddr, false, NULL); +} + +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param + * + * @return + */ +/*----------------------------------------------------------------------------*/ +void scanRemoveRoamBssDescsByTime(IN P_ADAPTER_T prAdapter, + IN u32 u4RemoveTime) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prRoamBSSDescList; + P_LINK_T prRoamFreeBSSDescList; + P_ROAM_BSS_DESC_T prRoamBssDesc; + P_ROAM_BSS_DESC_T prRoamBSSDescNext; + u32 rCurrentTime; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prRoamBSSDescList = &prScanInfo->rRoamBSSDescList; + prRoamFreeBSSDescList = &prScanInfo->rRoamFreeBSSDescList; + + GET_CURRENT_SYSTIME(&rCurrentTime); + + LINK_FOR_EACH_ENTRY_SAFE(prRoamBssDesc, prRoamBSSDescNext, + prRoamBSSDescList, rLinkEntry, ROAM_BSS_DESC_T){ + if (CHECK_FOR_TIMEOUT(rCurrentTime, prRoamBssDesc->rUpdateTime, + SEC_TO_SYSTIME(u4RemoveTime))) { + LINK_REMOVE_KNOWN_ENTRY(prRoamBSSDescList, prRoamBssDesc); + LINK_INSERT_TAIL(prRoamFreeBSSDescList, &prRoamBssDesc->rLinkEntry); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param + * + * @return + */ +/*----------------------------------------------------------------------------*/ +P_ROAM_BSS_DESC_T +scanSearchRoamBssDescBySsid(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prRoamBSSDescList; + P_ROAM_BSS_DESC_T prRoamBssDesc; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prRoamBSSDescList = &prScanInfo->rRoamBSSDescList; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prRoamBssDesc, prRoamBSSDescList, rLinkEntry, + ROAM_BSS_DESC_T){ + if (EQUAL_SSID(prRoamBssDesc->aucSSID, prRoamBssDesc->ucSSIDLen, + prBssDesc->aucSSID, prBssDesc->ucSSIDLen)) { + return prRoamBssDesc; + } + } + + return NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param + * + * @return + */ +/*----------------------------------------------------------------------------*/ +P_ROAM_BSS_DESC_T scanAllocateRoamBssDesc(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prRoamFreeBSSDescList; + P_ROAM_BSS_DESC_T prRoamBssDesc = NULL; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prRoamFreeBSSDescList = &prScanInfo->rRoamFreeBSSDescList; + + LINK_REMOVE_HEAD(prRoamFreeBSSDescList, prRoamBssDesc, P_ROAM_BSS_DESC_T); + + if (prRoamBssDesc) { + P_LINK_T prRoamBSSDescList; + + kalMemZero(prRoamBssDesc, sizeof(ROAM_BSS_DESC_T)); + + prRoamBSSDescList = &prScanInfo->rRoamBSSDescList; + + LINK_INSERT_HEAD(prRoamBSSDescList, &prRoamBssDesc->rLinkEntry); + } + + return prRoamBssDesc; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param + * + * @return + */ +/*----------------------------------------------------------------------------*/ +void scanAddToRoamBssDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) +{ + P_ROAM_BSS_DESC_T prRoamBssDesc; + + prRoamBssDesc = scanSearchRoamBssDescBySsid(prAdapter, prBssDesc); + + if (prRoamBssDesc == NULL) { + u32 u4RemoveTime = REMOVE_TIMEOUT_TWO_DAY; + + do { + prRoamBssDesc = scanAllocateRoamBssDesc(prAdapter); + if (prRoamBssDesc) { + break; + } + scanRemoveRoamBssDescsByTime(prAdapter, u4RemoveTime); + u4RemoveTime = u4RemoveTime / 2; + } while (u4RemoveTime > 0); + + if (prRoamBssDesc != NULL) { + COPY_SSID(prRoamBssDesc->aucSSID, prRoamBssDesc->ucSSIDLen, + prBssDesc->aucSSID, prBssDesc->ucSSIDLen); + } + } + + if (prRoamBssDesc != NULL) { + GET_CURRENT_SYSTIME(&prRoamBssDesc->rUpdateTime); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param + * + * @return + */ +/*----------------------------------------------------------------------------*/ +void scanSearchBssDescOfRoamSsid(IN P_ADAPTER_T prAdapter) +{ +#define SSID_ONLY_EXIST_ONE_AP \ + 1 /* If only exist one same ssid AP, avoid unnecessary scan */ + + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc; + P_BSS_INFO_T prAisBssInfo; + u32 u4SameSSIDCount = 0; + + prAisBssInfo = prAdapter->prAisBssInfo; + + /* XXX: wlan0(AP mode) + p2p0 occurs exception. */ + if (prAisBssInfo == NULL) { + return; + } + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + + if (prAisBssInfo->eConnectionState != PARAM_MEDIA_STATE_CONNECTED) { + return; + } + + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T){ + if (EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen)) { + u4SameSSIDCount++; + if (u4SameSSIDCount > SSID_ONLY_EXIST_ONE_AP) { + scanAddToRoamBssDesc(prAdapter, prBssDesc); + break; + } + } + } +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Find the corresponding BSS Descriptor according to + * given eBSSType, BSSID and Transmitter Address + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] eBSSType BSS Type of incoming Beacon/ProbeResp frame. + * @param[in] aucBSSID Given BSSID of Beacon/ProbeResp frame. + * @param[in] aucSrcAddr Given source address (TA) of Beacon/ProbeResp frame. + * @param[in] fgCheckSsid Need to check SSID or not. (for multiple SSID with + * single BSSID cases) + * @param[in] prSsid Specified SSID + * + * @return Pointer to BSS Descriptor, if found. NULL, if not found + */ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T +scanSearchExistingBssDescWithSsid(IN P_ADAPTER_T prAdapter, + IN ENUM_BSS_TYPE_T eBSSType, IN u8 aucBSSID[], + IN u8 aucSrcAddr[], IN u8 fgCheckSsid, + IN P_PARAM_SSID_T prSsid) +{ + P_SCAN_INFO_T prScanInfo; + P_BSS_DESC_T prBssDesc, prIBSSBssDesc; + /* CASE III */ + P_LINK_T prBSSDescList; + P_LINK_T prFreeBSSDescList; + + ASSERT(prAdapter); + ASSERT(aucSrcAddr); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + if (eBSSType == BSS_TYPE_P2P_DEVICE) { + fgCheckSsid = false; + // No break; intentional fall-through + } else if (eBSSType == BSS_TYPE_INFRASTRUCTURE) { +#if CFG_SUPPORT_ROAMING_SKIP_ONE_AP + scanSearchBssDescOfRoamSsid(prAdapter); + // No break; intentional fall-through +#endif + } else if (eBSSType == BSS_TYPE_BOW_DEVICE) { + prBssDesc = scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, + fgCheckSsid, prSsid); + return prBssDesc; + } else if (eBSSType == BSS_TYPE_IBSS) { + prIBSSBssDesc = scanSearchBssDescByBssidAndSsid(prAdapter, aucBSSID, + fgCheckSsid, prSsid); + prBssDesc = scanSearchBssDescByTAAndSsid(prAdapter, aucSrcAddr, + fgCheckSsid, prSsid); + + if (prBssDesc) { + if ((!prIBSSBssDesc) || (prBssDesc == prIBSSBssDesc)) { + return prBssDesc; + } + + prBSSDescList = &prScanInfo->rBSSDescList; + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + + return prIBSSBssDesc; + } + + if (prIBSSBssDesc) { + return prIBSSBssDesc; + } + } else { + } + + return (P_BSS_DESC_T)NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief bypass BSS Descriptors from current list according to specific BSSID. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] aucBSSID Given BSSID. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +u8 scanByPassRemoveBssDesc(IN P_ADAPTER_T prAdapter, IN P_BSS_DESC_T prBssDesc) +{ + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDescScan; + P_BSS_DESC_T prBSSDescNext; + P_SCAN_INFO_T prScanInfo; + //P_SCAN_PARAM_T prScanParam; + //u8 ucIndex = 0; + u8 fgIsByPassRemove = false; + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + //prScanParam = &prScanInfo->rScanParam; + +#if 0 + for (ucIndex = 0; ucIndex < prScanParam->ucSSIDNum; ucIndex++) { + if (EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prScanParam->aucSpecifiedSSID[ucIndex], + prScanParam->ucSpecifiedSSIDLen[ucIndex])) { +#endif + LINK_FOR_EACH_ENTRY_SAFE(prBssDescScan, prBSSDescNext, prBSSDescList, rLinkEntry, BSS_DESC_T){ + if(EQUAL_SSID(MAC2STR(prBssDesc->aucBSSID), MAC_ADDR_LEN, MAC2STR(prBssDescScan), MAC_ADDR_LEN)) { + fgIsByPassRemove = true; + DBGLOG(INIT, INFO, "scanByPassRemoveBssDesc %s | %s\n", + prBssDesc->aucSSID, prBssDescScan->aucSSID /*prScanParam->aucSpecifiedSSID[ucIndex]*/); + break; + } + } + return fgIsByPassRemove; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Delete BSS Descriptors from current list according to given Remove + * Policy. + * + * @param[in] u4RemovePolicy Remove Policy. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void scanRemoveBssDescsByPolicy(IN P_ADAPTER_T prAdapter, + IN u32 u4RemovePolicy) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_LINK_T prFreeBSSDescList; + P_BSS_DESC_T prBssDesc; + + ASSERT(prAdapter); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + /* DBGLOG(SCN, TRACE, ("Before Remove - Number Of SCAN Result = %ld\n", + */ + /* prBSSDescList->u4NumElem)); */ + + if (u4RemovePolicy & SCN_RM_POLICY_TIMEOUT) { + P_BSS_DESC_T prBSSDescNext; + u32 rCurrentTime; + + GET_CURRENT_SYSTIME(&rCurrentTime); + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, + rLinkEntry, BSS_DESC_T){ + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && + (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { + /* Don't remove the one currently we are + * connected. */ + continue; + } + + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_SPECIFIC_SSID) && + scanByPassRemoveBssDesc(prAdapter, prBssDesc)) { + /* Don't remove the one currently we are looking + * for specifi SSID. */ + continue; + } + + if (CHECK_FOR_TIMEOUT( + rCurrentTime, prBssDesc->rUpdateTime, + SEC_TO_SYSTIME(SCN_BSS_DESC_REMOVE_TIMEOUT_SEC))) { + /* DBGLOG(SCN, TRACE, ("Remove TIMEOUT BSS + * DESC(%#x): MAC: "MACSTR", Current Time = + * %08lx, Update Time = %08lx\n", + */ + /* prBssDesc, MAC2STR(prBssDesc->aucBSSID), + * rCurrentTime, prBssDesc->rUpdateTime)); */ + + /* Remove this BSS Desc from the BSS Desc list + */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); + + /* Return this BSS Desc to the free BSS Desc + * list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + } + } + } + if (u4RemovePolicy & SCN_RM_POLICY_OLDEST_HIDDEN) { + P_BSS_DESC_T prBssDescOldest = (P_BSS_DESC_T)NULL; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T){ + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && + (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { + /* Don't remove the one currently we are + * connected. */ + continue; + } + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_SPECIFIC_SSID) && + scanByPassRemoveBssDesc(prAdapter, prBssDesc)) { + /* Don't remove the one currently we are looking + * for specifi SSID. */ + continue; + } + + if (!prBssDesc->fgIsHiddenSSID) { + continue; + } + + if (!prBssDescOldest) { /* 1st element */ + prBssDescOldest = prBssDesc; + continue; + } + + if (TIME_BEFORE(prBssDesc->rUpdateTime, + prBssDescOldest->rUpdateTime)) { + prBssDescOldest = prBssDesc; + } + } + + if (prBssDescOldest) { + /* DBGLOG(SCN, TRACE, + * ("Remove OLDEST HIDDEN BSS DESC(%#x): MAC: "MACSTR", + * Update Time = %08lx\n", + */ + /* prBssDescOldest, MAC2STR(prBssDescOldest->aucBSSID), + * prBssDescOldest->rUpdateTime)); */ + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDescOldest); + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDescOldest->rLinkEntry); + } + } + if (u4RemovePolicy & SCN_RM_POLICY_SMART_WEAKEST) { + P_BSS_DESC_T prBssDescWeakest = (P_BSS_DESC_T)NULL; + P_BSS_DESC_T prBssDescWeakestSameSSID = (P_BSS_DESC_T)NULL; + u32 u4SameSSIDCount = 0; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T){ + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && + (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { + /* Don't remove the one currently we are + * connected. */ + continue; + } + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_SPECIFIC_SSID) && + scanByPassRemoveBssDesc(prAdapter, prBssDesc)) { + /* Don't remove the one currently we are looking + * for specifi SSID. */ + continue; + } + + if ((!prBssDesc->fgIsHiddenSSID) && + (EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen))) { + u4SameSSIDCount++; + + if (!prBssDescWeakestSameSSID) { + prBssDescWeakestSameSSID = prBssDesc; + } else if (prBssDesc->ucRCPI < + prBssDescWeakestSameSSID->ucRCPI) { + prBssDescWeakestSameSSID = prBssDesc; + } + } + + if (!prBssDescWeakest) { /* 1st element */ + prBssDescWeakest = prBssDesc; + continue; + } + + if (prBssDesc->ucRCPI < prBssDescWeakest->ucRCPI) { + prBssDescWeakest = prBssDesc; + } + } + + if ((u4SameSSIDCount >= SCN_BSS_DESC_SAME_SSID_THRESHOLD) && + (prBssDescWeakestSameSSID)) { + prBssDescWeakest = prBssDescWeakestSameSSID; + } + + if (prBssDescWeakest) { + /* DBGLOG(SCN, TRACE, ("Remove WEAKEST BSS DESC(%#x): + * MAC: "MACSTR", Update Time = %08lx\n", */ + /* prBssDescOldest, MAC2STR(prBssDescOldest->aucBSSID), + * prBssDescOldest->rUpdateTime)); */ + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDescWeakest); + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDescWeakest->rLinkEntry); + } + } + if (u4RemovePolicy & SCN_RM_POLICY_ENTIRE) { + P_BSS_DESC_T prBSSDescNext; + + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, + rLinkEntry, BSS_DESC_T){ + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_CONNECTED) && + (prBssDesc->fgIsConnected || prBssDesc->fgIsConnecting)) { + /* Don't remove the one currently we are + * connected. */ + continue; + } + if ((u4RemovePolicy & SCN_RM_POLICY_EXCLUDE_SPECIFIC_SSID) && + scanByPassRemoveBssDesc(prAdapter, prBssDesc)) { + /* Don't remove the one currently we are looking + * for specifi SSID. */ + continue; + } + + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + } + } + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Delete BSS Descriptors from current list according to given BSSID. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] aucBSSID Given BSSID. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void scanRemoveBssDescByBssid(IN P_ADAPTER_T prAdapter, IN u8 aucBSSID[]) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_LINK_T prFreeBSSDescList; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + P_BSS_DESC_T prBSSDescNext; + + ASSERT(prAdapter); + ASSERT(aucBSSID); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + /* Check if such BSS Descriptor exists in a valid list */ + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, + rLinkEntry, BSS_DESC_T){ + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + + /* BSSID is not unique, so need to traverse whols + * link-list */ + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Delete BSS Descriptors from current list according to given band + * configuration + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] eBand Given band + * @param[in] ucBssIndex AIS - Remove IBSS/Infrastructure BSS + * BOW - Remove BOW BSS + * P2P - Remove P2P BSS + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void scanRemoveBssDescByBandAndNetwork(IN P_ADAPTER_T prAdapter, + IN ENUM_BAND_T eBand, IN u8 ucBssIndex) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_LINK_T prFreeBSSDescList; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + P_BSS_DESC_T prBSSDescNext; + u8 fgToRemove; + + ASSERT(prAdapter); + ASSERT(eBand <= BAND_NUM); + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + if (eBand == BAND_NULL) { + return; /* no need to do anything, keep all scan result */ + } + /* Check if such BSS Descriptor exists in a valid list */ + LINK_FOR_EACH_ENTRY_SAFE(prBssDesc, prBSSDescNext, prBSSDescList, + rLinkEntry, BSS_DESC_T){ + fgToRemove = false; + + if (prBssDesc->eBand == eBand) { + switch ( + GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType) { + case NETWORK_TYPE_AIS: + if ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) || + (prBssDesc->eBSSType == BSS_TYPE_IBSS)) { + fgToRemove = true; + } + break; + + case NETWORK_TYPE_P2P: + if (prBssDesc->eBSSType == BSS_TYPE_P2P_DEVICE) { + fgToRemove = true; + } + break; + + case NETWORK_TYPE_BOW: + if (prBssDesc->eBSSType == BSS_TYPE_BOW_DEVICE) { + fgToRemove = true; + } + break; + + default: + ASSERT(0); + break; + } + } + + if (fgToRemove == true) { + /* Remove this BSS Desc from the BSS Desc list */ + LINK_REMOVE_KNOWN_ENTRY(prBSSDescList, prBssDesc); + + /* Return this BSS Desc to the free BSS Desc list. */ + LINK_INSERT_TAIL(prFreeBSSDescList, &prBssDesc->rLinkEntry); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Clear the CONNECTION FLAG of a specified BSS Descriptor. + * + * @param[in] aucBSSID Given BSSID. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void scanRemoveConnFlagOfBssDescByBssid(IN P_ADAPTER_T prAdapter, + IN u8 aucBSSID[]) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + + ASSERT(prAdapter); + ASSERT(aucBSSID); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T){ + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, aucBSSID)) { + prBssDesc->fgIsConnected = false; + prBssDesc->fgIsConnecting = false; + + /* BSSID is not unique, so need to traverse whols + * link-list */ + } + } + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Allocate new BSS_DESC_T + * + * @param[in] prAdapter Pointer to the Adapter structure. + * + * @return Pointer to BSS Descriptor, if has free space. NULL, if has no + * space. + */ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T scanAllocateBssDesc(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_LINK_T prFreeBSSDescList; + P_BSS_DESC_T prBssDesc; + + ASSERT(prAdapter); + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prFreeBSSDescList = &prScanInfo->rFreeBSSDescList; + + LINK_REMOVE_HEAD(prFreeBSSDescList, prBssDesc, P_BSS_DESC_T); + + if (prBssDesc) { + P_LINK_T prBSSDescList; + + kalMemZero(prBssDesc, sizeof(BSS_DESC_T)); + +#if CFG_ENABLE_WIFI_DIRECT + LINK_INITIALIZE(&(prBssDesc->rP2pDeviceList)); + prBssDesc->fgIsP2PPresent = false; +#endif + + prBSSDescList = &prScanInfo->rBSSDescList; + + /* NOTE(Kevin): In current design, this new empty BSS_DESC_T + * will be inserted to BSSDescList immediately. + */ + LINK_INSERT_TAIL(prBSSDescList, &prBssDesc->rLinkEntry); + } + + return prBssDesc; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This API parses Beacon/ProbeResp frame and insert extracted BSS_DESC_T + * with IEs into prAdapter->rWifiVar.rScanInfo.aucScanBuffer + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prSwRfb Pointer to the receiving frame buffer. + * + * @return Pointer to BSS Descriptor + * NULL if the Beacon/ProbeResp frame is invalid + */ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T scanAddToBssDesc(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_BSS_DESC_T prBssDesc = NULL; + u16 u2CapInfo; + ENUM_BSS_TYPE_T eBSSType = BSS_TYPE_INFRASTRUCTURE; + + u8 *pucIE; + u16 u2IELength; + u16 u2Offset = 0; + + P_WLAN_BEACON_FRAME_T prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T)NULL; + P_IE_SSID_T prIeSsid = (P_IE_SSID_T)NULL; + P_IE_SUPPORTED_RATE_IOT_T prIeSupportedRate = + (P_IE_SUPPORTED_RATE_IOT_T)NULL; + P_IE_EXT_SUPPORTED_RATE_T prIeExtSupportedRate = + (P_IE_EXT_SUPPORTED_RATE_T)NULL; + u8 ucHwChannelNum = 0; + u8 ucIeDsChannelNum = 0; + u8 ucIeHtChannelNum = 0; + u8 fgIsValidSsid = false, fgEscape = false, fgIsCopy = false; + PARAM_SSID_T rSsid; + u64 u8Timestamp; + u8 fgIsNewBssDesc = false; + + u32 i; + u8 ucSSIDChar; + /* u8 * pucDumpIE; */ + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T)prSwRfb->pvHeader; + + WLAN_GET_FIELD_16(&prWlanBeaconFrame->u2CapInfo, &u2CapInfo); + WLAN_GET_FIELD_64(&prWlanBeaconFrame->au4Timestamp[0], &u8Timestamp); + + /* decide BSS type */ + switch (u2CapInfo & CAP_INFO_BSS_TYPE) { + case CAP_INFO_ESS: + /* It can also be Group Owner of P2P Group. */ + eBSSType = BSS_TYPE_INFRASTRUCTURE; + break; + + case CAP_INFO_IBSS: + eBSSType = BSS_TYPE_IBSS; + break; + + case 0: + /* The P2P Device shall set the ESS bit of the Capabilities + * field in the Probe Response fame to 0 and IBSS bit to 0. + * (3.1.2.1.1) + */ + eBSSType = BSS_TYPE_P2P_DEVICE; + break; + + default: + return NULL; + } + + /* 4 <1.1> Pre-parse SSID IE */ + pucIE = prWlanBeaconFrame->aucInfoElem; + u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (u16)OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]); + + IE_FOR_EACH(pucIE, u2IELength, u2Offset){ + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: + if (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID) { + ucSSIDChar = '\0'; + + /* D-Link DWL-900AP+ */ + if (IE_LEN(pucIE) == 0) { + fgIsValidSsid = false; + } + /* Cisco AP1230A - (IE_LEN(pucIE) == 1) && + * (SSID_IE(pucIE)->aucSSID[0] == '\0') */ + /* Linksys WRK54G/WL520g - (IE_LEN(pucIE) == n) + * && (SSID_IE(pucIE)->aucSSID[0~(n-1)] == '\0') + */ + else { + for (i = 0; i < IE_LEN(pucIE); i++) + ucSSIDChar |= SSID_IE(pucIE)->aucSSID[i]; + + if (ucSSIDChar) { + fgIsValidSsid = true; + } + } + + /* Update SSID to BSS Descriptor only if SSID is + * not hidden. */ + if (fgIsValidSsid == true) { + COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, + SSID_IE(pucIE)->aucSSID, + SSID_IE(pucIE)->ucLength); + } + } + fgEscape = true; + break; + + default: + break; + } + + if (fgEscape == true) { + break; + } + } + + /* 4 <1.2> Replace existing BSS_DESC_T or allocate a new one */ + prBssDesc = scanSearchExistingBssDescWithSsid( + prAdapter, eBSSType, (u8 *)prWlanBeaconFrame->aucBSSID, + (u8 *)prWlanBeaconFrame->aucSrcAddr, fgIsValidSsid, + fgIsValidSsid == true ? &rSsid : NULL); + + if (prBssDesc == (P_BSS_DESC_T)NULL) { + fgIsNewBssDesc = true; + + do { + /* 4 <1.2.1> First trial of allocation */ + prBssDesc = scanAllocateBssDesc(prAdapter); + if (prBssDesc) { + break; + } + /* 4 <1.2.2> Hidden is useless, remove the oldest hidden + * ssid. (for passive scan) */ + scanRemoveBssDescsByPolicy( + prAdapter, + (SCN_RM_POLICY_EXCLUDE_CONNECTED | SCN_RM_POLICY_OLDEST_HIDDEN | + SCN_RM_POLICY_TIMEOUT | SCN_RM_POLICY_EXCLUDE_SPECIFIC_SSID)); + + /* 4 <1.2.3> Second tail of allocation */ + prBssDesc = scanAllocateBssDesc(prAdapter); + if (prBssDesc) { + break; + } + /* 4 <1.2.4> Remove the weakest one */ + /* If there are more than half of BSS which has the same + * ssid as connection setting, remove the weakest one + * from them. Else remove the weakest one. + */ + scanRemoveBssDescsByPolicy(prAdapter, + (SCN_RM_POLICY_EXCLUDE_CONNECTED | + SCN_RM_POLICY_SMART_WEAKEST | + SCN_RM_POLICY_EXCLUDE_SPECIFIC_SSID)); + + /* 4 <1.2.5> reallocation */ + prBssDesc = scanAllocateBssDesc(prAdapter); + if (prBssDesc) { + break; + } + + // DBGLOG(SCN, WARN, "Allocate Bss Desc failed\n"); + + /* 4 <1.2.6> no space, should not happen */ + /* ASSERT(0); // still no space available ? */ + return NULL; + } while (false); + } else { + u32 rCurrentTime; + + /* WCXRP00000091 */ + /* if the received strength is much weaker than the original + * one, */ + /* ignore it due to it might be received on the folding + * frequency */ + + GET_CURRENT_SYSTIME(&rCurrentTime); + + ASSERT(prSwRfb->prRxStatusGroup3); + + if (prBssDesc->eBSSType != eBSSType) { + prBssDesc->eBSSType = eBSSType; + } else if (HAL_RX_STATUS_GET_CHNL_NUM(prSwRfb->prRxStatus) != + prBssDesc->ucChannelNum && + prBssDesc->ucRCPI > + nicRxGetRcpiValueFromRxv(RCPI_MODE_WF0, prSwRfb)) { + /* for signal strength is too much weaker and previous + * beacon is not stale */ + ASSERT(prSwRfb->prRxStatusGroup3); + if ((prBssDesc->ucRCPI - + nicRxGetRcpiValueFromRxv(RCPI_MODE_WF0, prSwRfb)) >= + REPLICATED_BEACON_STRENGTH_THRESHOLD && + rCurrentTime - prBssDesc->rUpdateTime <= + REPLICATED_BEACON_FRESH_PERIOD) { + return prBssDesc; + } + /* for received beacons too close in time domain */ + else if (rCurrentTime - prBssDesc->rUpdateTime <= + REPLICATED_BEACON_TIME_THRESHOLD) { + return prBssDesc; + } + } + + /* if Timestamp has been reset, re-generate BSS DESC 'cause AP + * should have reset itself */ + if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && + u8Timestamp < prBssDesc->u8TimeStamp.QuadPart) { + u8 fgIsConnected, fgIsConnecting; + + /* set flag for indicating this is a new BSS-DESC */ + fgIsNewBssDesc = true; + + /* backup 2 flags for APs which reset timestamp + * unexpectedly */ + fgIsConnected = prBssDesc->fgIsConnected; + fgIsConnecting = prBssDesc->fgIsConnecting; + scanRemoveBssDescByBssid(prAdapter, prBssDesc->aucBSSID); + + prBssDesc = scanAllocateBssDesc(prAdapter); + if (!prBssDesc) { + // DBGLOG(SCN, WARN, "Allocate Bss Desc failed\n"); + return NULL; + } + + /* restore */ + prBssDesc->fgIsConnected = fgIsConnected; + prBssDesc->fgIsConnecting = fgIsConnecting; + } + } + + /* 2021/04/18 frog: Only update IE when in scan state. */ + /* Driver would still RX BCN/Probe RSP under other state. */ + /* It would cause driver cache some scan result till next scan done. */ + if (scnFsmIsScanning(prAdapter)) { + /* 2018/04/17 frog: always update IE is not a good choice. */ + /* Because of not considering hidden BSS. */ + /* Hidden BSS Beacon v.s. hidden BSS probe response. */ + if ((prBssDesc->u2RawLength == 0) || (fgIsValidSsid)) { + prBssDesc->u2RawLength = prSwRfb->u2PacketLen; + if (prBssDesc->u2RawLength > CFG_RAW_BUFFER_SIZE) { + prBssDesc->u2RawLength = CFG_RAW_BUFFER_SIZE; + } + kalMemCopy(prBssDesc->aucRawBuf, prWlanBeaconFrame, + prBssDesc->u2RawLength); + fgIsCopy = true; + } + } else { + prBssDesc->u2RawLength = 0; + } + + /* NOTE: Keep consistency of Scan Record during JOIN process */ + if (fgIsNewBssDesc == false && prBssDesc->fgIsConnecting) { + return prBssDesc; + } + + /* 4 <2> Get information from Fixed Fields */ + prBssDesc->eBSSType = eBSSType; /* Update the latest BSS type + * information. */ + + COPY_MAC_ADDR(prBssDesc->aucSrcAddr, prWlanBeaconFrame->aucSrcAddr); + + COPY_MAC_ADDR(prBssDesc->aucBSSID, prWlanBeaconFrame->aucBSSID); + + prBssDesc->u8TimeStamp.QuadPart = u8Timestamp; + + WLAN_GET_FIELD_16(&prWlanBeaconFrame->u2BeaconInterval, + &prBssDesc->u2BeaconInterval); + + prBssDesc->u2CapInfo = u2CapInfo; + + /* 4 <2.1> Retrieve IEs for later parsing */ + u2IELength = (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (u16)OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]); + + if (fgIsCopy) { + prBssDesc->u2IELength = u2IELength; + + if (prBssDesc->u2IELength > CFG_IE_BUFFER_SIZE) { + prBssDesc->u2IELength = CFG_IE_BUFFER_SIZE; + prBssDesc->fgIsIEOverflow = true; + } else { + prBssDesc->fgIsIEOverflow = false; + } + + kalMemCopy(prBssDesc->aucIEBuf, prWlanBeaconFrame->aucInfoElem, + prBssDesc->u2IELength); + } + + /* 4 <2.2> reset prBssDesc variables in case that AP has been + * reconfigured */ + prBssDesc->fgIsERPPresent = false; + prBssDesc->fgIsHTPresent = false; + prBssDesc->fgIsVHTPresent = false; + prBssDesc->eSco = CHNL_EXT_SCN; + prBssDesc->fgIEWAPI = false; + prBssDesc->fgIERSN = false; + prBssDesc->fgIEWPA = false; + prBssDesc->eChannelWidth = CW_20_40MHZ; /*Reset VHT OP IE relative + * settings */ + prBssDesc->ucCenterFreqS1 = 0; + prBssDesc->ucCenterFreqS2 = 0; + + /* 4 <3.1> Full IE parsing on SW_RFB_T */ + pucIE = prWlanBeaconFrame->aucInfoElem; + /* pucDumpIE = pucIE; */ + + IE_FOR_EACH(pucIE, u2IELength, u2Offset){ + switch (IE_ID(pucIE)) { + case ELEM_ID_SSID: + if ((!prIeSsid) && /* NOTE(Kevin): for Atheros IOT #1 */ + (IE_LEN(pucIE) <= ELEM_MAX_LEN_SSID)) { + u8 fgIsHiddenSSID = false; + + ucSSIDChar = '\0'; + + prIeSsid = (P_IE_SSID_T)pucIE; + + /* D-Link DWL-900AP+ */ + if (IE_LEN(pucIE) == 0) { + fgIsHiddenSSID = true; + } + /* Cisco AP1230A - (IE_LEN(pucIE) == 1) && + * (SSID_IE(pucIE)->aucSSID[0] == '\0') */ + /* Linksys WRK54G/WL520g - (IE_LEN(pucIE) == n) + * && (SSID_IE(pucIE)->aucSSID[0~(n-1)] == '\0') + * = + */ + else { + for (i = 0; i < IE_LEN(pucIE); i++) + ucSSIDChar |= SSID_IE(pucIE)->aucSSID[i]; + + if (!ucSSIDChar) { + fgIsHiddenSSID = true; + } + } + + /* Update SSID to BSS Descriptor only if SSID is + * not hidden. */ + if (!fgIsHiddenSSID) { + COPY_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + SSID_IE(pucIE)->aucSSID, + SSID_IE(pucIE)->ucLength); + } + } + break; + + case ELEM_ID_SUP_RATES: + /* NOTE(Kevin): Buffalo WHR-G54S's supported rate set IE + * exceed 8. IE_LEN(pucIE) == 12, "1(B), 2(B), 5.5(B), + * 6(B), 9(B), 11(B), 12(B), 18(B), 24(B), 36(B), 48(B), + * 54(B)" + */ + /* TP-LINK will set extra and incorrect ie with + * ELEM_ID_SUP_RATES */ + if ((!prIeSupportedRate) && (IE_LEN(pucIE) <= RATE_NUM_SW)) { + prIeSupportedRate = SUP_RATES_IOT_IE(pucIE); + } + break; + + case ELEM_ID_DS_PARAM_SET: + if (IE_LEN(pucIE) == ELEM_MAX_LEN_DS_PARAMETER_SET) { + ucIeDsChannelNum = DS_PARAM_IE(pucIE)->ucCurrChnl; + } + break; + + case ELEM_ID_TIM: + if (IE_LEN(pucIE) <= ELEM_MAX_LEN_TIM) { + prBssDesc->ucDTIMPeriod = TIM_IE(pucIE)->ucDTIMPeriod; + } + break; + + case ELEM_ID_IBSS_PARAM_SET: + if (IE_LEN(pucIE) == ELEM_MAX_LEN_IBSS_PARAMETER_SET) { + prBssDesc->u2ATIMWindow = IBSS_PARAM_IE(pucIE)->u2ATIMWindow; + } + break; + + case ELEM_ID_ERP_INFO: + if (IE_LEN(pucIE) == ELEM_MAX_LEN_ERP) { + prBssDesc->fgIsERPPresent = true; + } + break; + + case ELEM_ID_EXTENDED_SUP_RATES: + if (!prIeExtSupportedRate) { + prIeExtSupportedRate = EXT_SUP_RATES_IE(pucIE); + } + break; + + case ELEM_ID_RSN: + if (rsnParseRsnIE(prAdapter, RSN_IE(pucIE), &prBssDesc->rRSNInfo)) { + prBssDesc->fgIERSN = true; + prBssDesc->u2RsnCap = prBssDesc->rRSNInfo.u2RsnCap; + if (prAdapter->rWifiVar.rConnSettings.eAuthMode == + AUTH_MODE_WPA2) { + rsnCheckPmkidCache(prAdapter, prBssDesc); + } + } + break; + + case ELEM_ID_HT_CAP: + prBssDesc->fgIsHTPresent = true; + break; + + case ELEM_ID_HT_OP: + if (IE_LEN(pucIE) != (sizeof(IE_HT_OP_T) - 2)) { + break; + } + + if ((((P_IE_HT_OP_T)pucIE)->ucInfo1 & HT_OP_INFO1_SCO) != + CHNL_EXT_RES) { + prBssDesc->eSco = + (ENUM_CHNL_EXT_T)(((P_IE_HT_OP_T)pucIE)->ucInfo1 & + HT_OP_INFO1_SCO); + } + ucIeHtChannelNum = ((P_IE_HT_OP_T)pucIE)->ucPrimaryChannel; + + break; + + case ELEM_ID_VHT_CAP: + prBssDesc->fgIsVHTPresent = true; +#if CFG_SUPPORT_BFEE + prBssDesc->ucVhtCapNumSoundingDimensions = + ((((P_IE_VHT_CAP_T)pucIE)->u4VhtCapInfo) & + VHT_CAP_INFO_NUMBER_OF_SOUNDING_DIMENSIONS) >> + VHT_CAP_INFO_NUMBER_OF_SOUNDING_DIMENSIONS_OFFSET; +#endif + break; + + case ELEM_ID_VHT_OP: + if (IE_LEN(pucIE) != (sizeof(IE_VHT_OP_T) - 2)) { + break; + } + + prBssDesc->eChannelWidth = + (ENUM_CHANNEL_WIDTH_T)(((P_IE_VHT_OP_T)pucIE) + ->ucVhtOperation[0]); + prBssDesc->ucCenterFreqS1 = + (ENUM_CHANNEL_WIDTH_T)(((P_IE_VHT_OP_T)pucIE) + ->ucVhtOperation[1]); + prBssDesc->ucCenterFreqS2 = + (ENUM_CHANNEL_WIDTH_T)(((P_IE_VHT_OP_T)pucIE) + ->ucVhtOperation[2]); + + /*add IEEE BW160 patch*/ + rlmModifyVhtBwPara(&prBssDesc->ucCenterFreqS1, + &prBssDesc->ucCenterFreqS2, + (u8 *)&prBssDesc->eChannelWidth); + + break; + + case ELEM_ID_VENDOR: /* ELEM_ID_P2P, ELEM_ID_WMM */ + { + u8 ucOuiType; + u16 u2SubTypeVersion; + + if (rsnParseCheckForWFAInfoElem(prAdapter, pucIE, &ucOuiType, + &u2SubTypeVersion)) { + if ((ucOuiType == VENDOR_OUI_TYPE_WPA) && + (u2SubTypeVersion == VERSION_WPA) && + (rsnParseWpaIE(prAdapter, WPA_IE(pucIE), + &prBssDesc->rWPAInfo))) { + prBssDesc->fgIEWPA = true; + } + } +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + if ((p2pFuncParseCheckForP2PInfoElem(prAdapter, pucIE, + &ucOuiType)) && + (ucOuiType == VENDOR_OUI_TYPE_P2P)) { + prBssDesc->fgIsP2PPresent = true; + } + } +#endif + } break; + +#if CFG_SUPPORT_802_11K + case ELEM_ID_RRM_ENABLED_CAP: + /* RRM Capability IE is always in length 5 bytes */ + kalMemZero(prBssDesc->aucRrmCap, sizeof(prBssDesc->aucRrmCap)); + kalMemCopy(prBssDesc->aucRrmCap, pucIE + 2, + sizeof(prBssDesc->aucRrmCap)); + break; +#endif + /* no default */ + } + } + + /* 4 <3.2> Save information from IEs - SSID */ + /* Update Flag of Hidden SSID for used in SEARCH STATE. */ + + /* NOTE(Kevin): in current driver, the ucSSIDLen == 0 represent + * all cases of hidden SSID. + * If the fgIsHiddenSSID == true, it means we didn't get the ProbeResp + * with valid SSID. + */ + if (prBssDesc->ucSSIDLen == 0) { + prBssDesc->fgIsHiddenSSID = true; + } else { + prBssDesc->fgIsHiddenSSID = false; + } + + /* 4 <3.3> Check rate information in related IEs. */ + if (prIeSupportedRate || prIeExtSupportedRate) { + rateGetRateSetFromIEs(prIeSupportedRate, prIeExtSupportedRate, + &prBssDesc->u2OperationalRateSet, + &prBssDesc->u2BSSBasicRateSet, + &prBssDesc->fgIsUnknownBssBasicRate); + } + + /* 4 <4> Update information from HIF RX Header */ + { + P_HW_MAC_RX_DESC_T prRxStatus; + u8 ucRxRCPI; + + prRxStatus = prSwRfb->prRxStatus; + ASSERT(prRxStatus); + + /* 4 <4.1> Get TSF comparison result */ + prBssDesc->fgIsLargerTSF = HAL_RX_STATUS_GET_TCL(prRxStatus); + + /* 4 <4.2> Get Band information */ + prBssDesc->eBand = HAL_RX_STATUS_GET_RF_BAND(prRxStatus); + + /* 4 <4.2> Get channel and RCPI information */ + ucHwChannelNum = HAL_RX_STATUS_GET_CHNL_NUM(prRxStatus); + + ASSERT(prSwRfb->prRxStatusGroup3); + ucRxRCPI = nicRxGetRcpiValueFromRxv(RCPI_MODE_WF0, prSwRfb); + if (prBssDesc->eBand == BAND_2G4) { + /* Update RCPI if in right channel */ + + if (ucIeDsChannelNum >= 1 && ucIeDsChannelNum <= 14) { + /* Receive Beacon/ProbeResp frame from adjacent + * channel. */ + if ((ucIeDsChannelNum == ucHwChannelNum) || + (ucRxRCPI > prBssDesc->ucRCPI)) { + prBssDesc->ucRCPI = ucRxRCPI; + } + /* trust channel information brought by IE */ + prBssDesc->ucChannelNum = ucIeDsChannelNum; + } else if (ucIeHtChannelNum >= 1 && ucIeHtChannelNum <= 14) { + /* Receive Beacon/ProbeResp frame from adjacent + * channel. */ + if ((ucIeHtChannelNum == ucHwChannelNum) || + (ucRxRCPI > prBssDesc->ucRCPI)) { + prBssDesc->ucRCPI = ucRxRCPI; + } + /* trust channel information brought by IE */ + prBssDesc->ucChannelNum = ucIeHtChannelNum; + } else { + prBssDesc->ucRCPI = ucRxRCPI; + + prBssDesc->ucChannelNum = ucHwChannelNum; + } + } + /* 5G Band */ + else { + if (ucIeHtChannelNum >= 1 && ucIeHtChannelNum < 200) { + /* Receive Beacon/ProbeResp frame from adjacent + * channel. */ + if ((ucIeHtChannelNum == ucHwChannelNum) || + (ucRxRCPI > prBssDesc->ucRCPI)) { + prBssDesc->ucRCPI = ucRxRCPI; + } + /* trust channel information brought by IE */ + prBssDesc->ucChannelNum = ucIeHtChannelNum; + } else { + /* Always update RCPI */ + prBssDesc->ucRCPI = ucRxRCPI; + + prBssDesc->ucChannelNum = ucHwChannelNum; + } + } + } + + /* 4 <5> Check IE information corret or not */ + if (!rlmDomainIsValidRfSetting( + prAdapter, prBssDesc->eBand, prBssDesc->ucChannelNum, + prBssDesc->eSco, prBssDesc->eChannelWidth, + prBssDesc->ucCenterFreqS1, prBssDesc->ucCenterFreqS2)) { + /* Dump IE Inforamtion */ + /* DBGLOG(RLM, WARN, "ScanAddToBssDesc IE Information\n"); */ + /* DBGLOG(RLM, WARN, "IE Length = %d\n", u2IELength); */ + /* DBGLOG_MEM8(RLM, WARN, pucDumpIE, u2IELength); */ + + /* Error Handling for Non-predicted IE - Fixed to set 20MHz */ + prBssDesc->eChannelWidth = CW_20_40MHZ; + prBssDesc->ucCenterFreqS1 = 0; + prBssDesc->ucCenterFreqS2 = 0; + prBssDesc->eSco = CHNL_EXT_SCN; + } + + /* 4 <6> PHY type setting */ + prBssDesc->ucPhyTypeSet = 0; + + if (prBssDesc->eBand == BAND_2G4) { + /* check if support 11n */ + if (prBssDesc->fgIsHTPresent) { + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + } + + /* if not 11n only */ + if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { + /* check if support 11g */ + if ((prBssDesc->u2OperationalRateSet & RATE_SET_OFDM) || + prBssDesc->fgIsERPPresent) { + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_ERP; + } + + /* if not 11g only */ + if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_OFDM)) { + /* check if support 11b */ + if ((prBssDesc->u2OperationalRateSet & RATE_SET_HR_DSSS)) { + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HR_DSSS; + } + } + } + } else { /* (BAND_5G == prBssDesc->eBande) */ + /* check if support 11n */ + if (prBssDesc->fgIsVHTPresent) { + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_VHT; + } + + if (prBssDesc->fgIsHTPresent) { + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_HT; + } + + /* if not 11n only */ + if (!(prBssDesc->u2BSSBasicRateSet & RATE_SET_BIT_HT_PHY)) { + /* Support 11a definitely */ + prBssDesc->ucPhyTypeSet |= PHY_TYPE_BIT_OFDM; + + /* ASSERT(!(prBssDesc->u2OperationalRateSet & + * RATE_SET_HR_DSSS)); */ + } + } + + /* 4 <7> Update BSS_DESC_T's Last Update TimeStamp. */ + GET_CURRENT_SYSTIME(&prBssDesc->rUpdateTime); + + return prBssDesc; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Convert the Beacon or ProbeResp Frame in SW_RFB_T to scan result for + * query + * + * @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. + * + * @retval WLAN_STATUS_SUCCESS It is a valid Scan Result and been sent to the + * host. + * @retval WLAN_STATUS_FAILURE It is not a valid Scan Result. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS scanAddScanResult(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prBssDesc, IN P_SW_RFB_T prSwRfb) +{ + P_SCAN_INFO_T prScanInfo; + u8 aucRatesEx[PARAM_MAX_LEN_RATES_EX]; + P_WLAN_BEACON_FRAME_T prWlanBeaconFrame; + PARAM_MAC_ADDRESS rMacAddr; + PARAM_SSID_T rSsid; + ENUM_PARAM_NETWORK_TYPE_T eNetworkType; + PARAM_802_11_CONFIG_T rConfiguration; + ENUM_PARAM_OP_MODE_T eOpMode; + u8 ucRateLen = 0; + u32 i; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + if (prBssDesc->eBand == BAND_2G4) { + if ((prBssDesc->u2OperationalRateSet & RATE_SET_OFDM) || + prBssDesc->fgIsERPPresent) { + eNetworkType = PARAM_NETWORK_TYPE_OFDM24; + } else { + eNetworkType = PARAM_NETWORK_TYPE_DS; + } + } else { + ASSERT(prBssDesc->eBand == BAND_5G); + eNetworkType = PARAM_NETWORK_TYPE_OFDM5; + } + + if (prBssDesc->eBSSType == BSS_TYPE_P2P_DEVICE) { + /* NOTE(Kevin): Not supported by WZC(TBD) */ + return WLAN_STATUS_FAILURE; + } + + prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T)prSwRfb->pvHeader; + COPY_MAC_ADDR(rMacAddr, prWlanBeaconFrame->aucBSSID); + COPY_SSID(rSsid.aucSsid, rSsid.u4SsidLen, prBssDesc->aucSSID, + prBssDesc->ucSSIDLen); + + rConfiguration.u4Length = sizeof(PARAM_802_11_CONFIG_T); + rConfiguration.u4BeaconPeriod = (u32)prWlanBeaconFrame->u2BeaconInterval; + rConfiguration.u4ATIMWindow = prBssDesc->u2ATIMWindow; + rConfiguration.u4DSConfig = nicChannelNum2Freq(prBssDesc->ucChannelNum); + rConfiguration.rFHConfig.u4Length = sizeof(PARAM_802_11_CONFIG_FH_T); + + rateGetDataRatesFromRateSet(prBssDesc->u2OperationalRateSet, 0, aucRatesEx, + &ucRateLen); + + /* NOTE(Kevin): Set unused entries, if any, at the end of the array to + * 0. from OID_802_11_BSSID_LIST + */ + for (i = ucRateLen; i < ARRAY_SIZE(aucRatesEx); i++) + aucRatesEx[i] = 0; + + switch (prBssDesc->eBSSType) { + case BSS_TYPE_IBSS: + eOpMode = NET_TYPE_IBSS; + break; + + case BSS_TYPE_INFRASTRUCTURE: + case BSS_TYPE_P2P_DEVICE: + case BSS_TYPE_BOW_DEVICE: + default: + eOpMode = NET_TYPE_INFRA; + break; + } + + DBGLOG(SCN, TRACE, "ind %s %d %d\n", prBssDesc->aucSSID, + prBssDesc->ucChannelNum, prBssDesc->ucRCPI); + + kalIndicateBssInfo(prAdapter->prGlueInfo, (u8 *)prSwRfb->pvHeader, + prSwRfb->u2PacketLen, prBssDesc->ucChannelNum, + RCPI_TO_dBm(prBssDesc->ucRCPI)); + + nicAddScanResult( + prAdapter, rMacAddr, &rSsid, + prWlanBeaconFrame->u2CapInfo & CAP_INFO_PRIVACY ? 1 : 0, + RCPI_TO_dBm(prBssDesc->ucRCPI), eNetworkType, &rConfiguration, eOpMode, + aucRatesEx, prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen, + (u8 *)((unsigned long)(prSwRfb->pvHeader) + WLAN_MAC_MGMT_HEADER_LEN)); + + return WLAN_STATUS_SUCCESS; +} + +u8 scanCheckBssIsLegal(IN P_ADAPTER_T prAdapter, P_BSS_DESC_T prBssDesc) +{ + u8 fgAddToScanResult = false; + ENUM_BAND_T eBand; + u8 ucChannel; + + ASSERT(prAdapter); + /* check the channel is in the legal doamin */ + if (rlmDomainIsLegalChannel(prAdapter, prBssDesc->eBand, + prBssDesc->ucChannelNum) == true) { + /* check ucChannelNum/eBand for adjacement channel filtering */ + if (cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel) == true && + (eBand != prBssDesc->eBand || + ucChannel != prBssDesc->ucChannelNum)) { + fgAddToScanResult = false; + } else { + fgAddToScanResult = true; + } + } + + return fgAddToScanResult; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Parse the content of given Beacon or ProbeResp Frame. + * + * @param[in] prSwRfb Pointer to the receiving SW_RFB_T structure. + * + * @retval WLAN_STATUS_SUCCESS if not report this SW_RFB_T to host + * @retval WLAN_STATUS_PENDING if report this SW_RFB_T to host as scan + * result + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS scanProcessBeaconAndProbeResp(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb) +{ + P_SCAN_INFO_T prScanInfo; + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_BSS_INFO_T prAisBssInfo; + P_WLAN_BEACON_FRAME_T prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T)NULL; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + /* 4 <0> Ignore invalid Beacon Frame */ + if ((prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) < + (TIMESTAMP_FIELD_LEN + BEACON_INTERVAL_FIELD_LEN + + CAP_INFO_FIELD_LEN)) { +#ifndef _lint + ASSERT(0); +#endif + return rStatus; + } + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prAisBssInfo = prAdapter->prAisBssInfo; + prWlanBeaconFrame = (P_WLAN_BEACON_FRAME_T)prSwRfb->pvHeader; + + /* 4 <1> Parse and add into BSS_DESC_T */ + prBssDesc = scanAddToBssDesc(prAdapter, prSwRfb); + + if (prBssDesc) { +#if CFG_SUPPORT_BEACON_CHANGE_DETECTION + /* 4 <1.1> Beacon Change Detection for Connected BSS */ + if ((prAisBssInfo != NULL) && + (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) && + ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE && + prConnSettings->eOPMode != NET_TYPE_IBSS) || + (prBssDesc->eBSSType == BSS_TYPE_IBSS && + prConnSettings->eOPMode != NET_TYPE_INFRA)) && + EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prAisBssInfo->aucBSSID) && + EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prAisBssInfo->aucSSID, prAisBssInfo->ucSSIDLen)) { + u8 fgNeedDisconnect = false; + + /* <1.1.2> check if supported rate differs */ + if (prAisBssInfo->u2OperationalRateSet != + prBssDesc->u2OperationalRateSet) { + fgNeedDisconnect = true; + } + + /* <1.1.3> beacon content change detected, disconnect + * immediately */ + if (fgNeedDisconnect == true) { + aisBssBeaconTimeout(prAdapter, 0); + } + } +#endif + /* 4 <1.1> Update AIS_BSS_INFO */ + if ((prAisBssInfo != NULL) && + (((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) && + (prConnSettings->eOPMode != NET_TYPE_IBSS)) || + (prBssDesc->eBSSType == BSS_TYPE_IBSS && + prConnSettings->eOPMode != NET_TYPE_INFRA))) { + if (prAisBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) { + /**not* checking prBssDesc->fgIsConnected + * anymore, due to Linksys AP uses " " as hidden + * SSID, and would have different BSS descriptor + */ + if ((!prAisBssInfo->ucDTIMPeriod) && + EQUAL_MAC_ADDR(prBssDesc->aucBSSID, + prAisBssInfo->aucBSSID) && + (prAisBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && + ((prWlanBeaconFrame->u2FrameCtrl & MASK_FRAME_TYPE) == + MAC_FRAME_BEACON)) { + prAisBssInfo->ucDTIMPeriod = prBssDesc->ucDTIMPeriod; + + /* sync with firmware for beacon + * information */ + nicPmIndicateBssConnected(prAdapter, + prAisBssInfo->ucBssIndex); + } + } +#if CFG_SUPPORT_ADHOC + if (EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen) && + (prBssDesc->eBSSType == BSS_TYPE_IBSS) && + (prAisBssInfo->eCurrentOPMode == OP_MODE_IBSS)) { + ASSERT(prSwRfb->prRxStatusGroup3); + + ibssProcessMatchedBeacon(prAdapter, prAisBssInfo, prBssDesc, + nicRxGetRcpiValueFromRxv(RCPI_MODE_WF0, + prSwRfb)); + } +#endif + } + + rlmProcessBcn( + prAdapter, prSwRfb, + ((P_WLAN_BEACON_FRAME_T)(prSwRfb->pvHeader))->aucInfoElem, + (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (u16)(OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]))); + + mqmProcessBcn( + prAdapter, prSwRfb, + ((P_WLAN_BEACON_FRAME_T)(prSwRfb->pvHeader))->aucInfoElem, + (prSwRfb->u2PacketLen - prSwRfb->u2HeaderLen) - + (u16)(OFFSET_OF(WLAN_BEACON_FRAME_BODY_T, aucInfoElem[0]))); + + /* 4 <3> Send SW_RFB_T to HIF when we perform SCAN for HOST */ + if (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE || + prBssDesc->eBSSType == BSS_TYPE_IBSS) { + /* for AIS, send to host */ + if (prConnSettings->fgIsScanReqIssued) { + u8 fgAddToScanResult; + + fgAddToScanResult = scanCheckBssIsLegal(prAdapter, prBssDesc); + + if (fgAddToScanResult == true) { + rStatus = scanAddScanResult(prAdapter, prBssDesc, prSwRfb); + } + } + } +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + scanP2pProcessBeaconAndProbeResp(prAdapter, prSwRfb, &rStatus, + prBssDesc, prWlanBeaconFrame); + } +#endif + } + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Search the Candidate of BSS Descriptor for JOIN(Infrastructure) or + * MERGE(AdHoc) according to current Connection Policy. + * + * \return Pointer to BSS Descriptor, if found. NULL, if not found + */ +/*----------------------------------------------------------------------------*/ +P_BSS_DESC_T scanSearchBssDescByPolicy(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + P_BSS_INFO_T prBssInfo; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; + P_SCAN_INFO_T prScanInfo; + P_LINK_T prBSSDescList; + P_BSS_DESC_T prBssDesc = (P_BSS_DESC_T)NULL; + P_BSS_DESC_T prPrimaryBssDesc = (P_BSS_DESC_T)NULL; + P_BSS_DESC_T prCandidateBssDesc = (P_BSS_DESC_T)NULL; + P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; + P_STA_RECORD_T prPrimaryStaRec; + P_STA_RECORD_T prCandidateStaRec = (P_STA_RECORD_T)NULL; + u32 rCurrentTime; + u8 fgIsFindFirst = (u8)false; + u8 fgIsFindBestRSSI = (u8)false; + u8 fgIsFixedChannel; + ENUM_BAND_T eBand; + u8 ucChannel; + P_BSS_INFO_T prAisBssInfo; + + ASSERT(prAdapter); + + prAisBssInfo = prAdapter->prAisBssInfo; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + prAisSpecBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prBSSDescList = &prScanInfo->rBSSDescList; + + GET_CURRENT_SYSTIME(&rCurrentTime); + + /* check for fixed channel operation */ + if (prBssInfo->eNetworkType == NETWORK_TYPE_AIS) { +#if CFG_SUPPORT_CHNL_CONFLICT_REVISE + fgIsFixedChannel = + cnmAisDetectP2PChannel(prAdapter, &eBand, &ucChannel); +#else + fgIsFixedChannel = + cnmAisInfraChannelFixed(prAdapter, &eBand, &ucChannel); +#endif + } else { + fgIsFixedChannel = false; + } + +#if DBG + if (prConnSettings->ucSSIDLen < ELEM_MAX_LEN_SSID) { + prConnSettings->aucSSID[prConnSettings->ucSSIDLen] = '\0'; + } +#endif + + DBGLOG(SCN, INFO, + "SEARCH: Num Of BSS_DESC_T = %d, Look for SSID: %s " + "prConnSettings->fgIsConnByBssidIssued %x " + "prConnSettings->eConnectionPolicy %x\n", + prBSSDescList->u4NumElem, prConnSettings->aucSSID, + prConnSettings->fgIsConnByBssidIssued, + prConnSettings->eConnectionPolicy); + + /* 4 <1> The outer loop to search for a candidate. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T){ + /* TODO(Kevin): Update Minimum Channel Load Information here */ + + DBGLOG(SCN, INFO, "SEARCH: [" MACSTR "], SSID:%s\n", + MAC2STR(prBssDesc->aucBSSID), prBssDesc->aucSSID); + + /* 4 <2> Check PHY Type and attributes */ + /* 4 <2.1> Check Unsupported BSS PHY Type */ + if (!(prBssDesc->ucPhyTypeSet & + (prAdapter->rWifiVar.ucAvailablePhyTypeSet))) { + DBGLOG(SCN, INFO, "SEARCH: Ignore unsupported ucPhyTypeSet = %x\n", + prBssDesc->ucPhyTypeSet); + continue; + } + /* 4 <2.2> Check if has unknown NonHT BSS Basic Rate Set. */ + if (prBssDesc->fgIsUnknownBssBasicRate) { + DBGLOG(SCN, LOUD, "SEARCH: Ignore Unknown Bss Basic Rate\n"); + continue; + } + /* 4 <2.3> Check if fixed operation cases should be aware */ + if (fgIsFixedChannel == true && + (prBssDesc->eBand != eBand || + prBssDesc->ucChannelNum != ucChannel)) { + DBGLOG(SCN, LOUD, + "SEARCH: Ignore BssBand[%d] != FixBand[%d] or BssCH[%d] != " + "FixCH[%d]\n", + prBssDesc->eBand, eBand, prBssDesc->ucChannelNum, ucChannel); + continue; + } + /* 4 <2.4> Check if the channel is legal under regulatory domain + */ + if (rlmDomainIsLegalChannel(prAdapter, prBssDesc->eBand, + prBssDesc->ucChannelNum) == false) { + DBGLOG(SCN, LOUD, "SEARCH: Ignore illegal CH Band[%d] CH[%d]\n", + prBssDesc->eBand, prBssDesc->ucChannelNum); + continue; + } + /* 4 <2.5> Check if this BSS_DESC_T is stale */ + if (CHECK_FOR_TIMEOUT(rCurrentTime, prBssDesc->rUpdateTime, + SEC_TO_SYSTIME(SCN_BSS_DESC_STALE_SEC))) { +#if CFG_SUPPORT_DBDC_TC6 + if (prAisBssInfo->fgReConnBypassScan && + EQUAL_MAC_ADDR(prConnSettings->aucBSSID, prBssDesc->aucBSSID) && + prAisBssInfo->eConnectionState == + PARAM_MEDIA_STATE_DISCONNECTED) { + prAisBssInfo->fgReConnBypassScan = 0; + DBGLOG(SCN, LOUD, + "SEARCH: Found target Bss but skip stale state for DBDC " + "reconnect\n"); + } else { +#endif + DBGLOG( + SCN, LOUD, + "SEARCH: Ignore stale Bss, CurrTime[%ld] BssUpdateTime[%ld]\n", + rCurrentTime, prBssDesc->rUpdateTime); + continue; +#if CFG_SUPPORT_DBDC_TC6 + } +#endif + } + /* 4 <3> Check if reach the excessive join retry limit */ + /* NOTE(Kevin): STA_RECORD_T is recorded by TA. */ + prStaRec = + cnmGetStaRecByAddress(prAdapter, ucBssIndex, prBssDesc->aucSrcAddr); + + if (prStaRec) { + /* NOTE(Kevin): + * The Status Code is the result of a Previous + * Connection Request, we use this as SCORE for choosing + * a proper candidate (Also used for compare see <6>) + * The Reason Code is an indication of the reason why AP + * reject us, we use this Code for "Reject" a SCAN + * result to become our candidate(Like a blacklist). + */ + + if (prStaRec->u2StatusCode != STATUS_CODE_SUCCESSFUL) { + /* NOTE(Kevin): greedy association - after + * timeout, we'll still try to associate to the + * AP whose STATUS of conection attempt was not + * success. We may also use (ucJoinFailureCount + * x JOIN_RETRY_INTERVAL_SEC) for time bound. + */ + if ((prStaRec->ucJoinFailureCount < + JOIN_MAX_RETRY_FAILURE_COUNT) || + (CHECK_FOR_TIMEOUT( + rCurrentTime, prStaRec->rLastJoinTime, + SEC_TO_SYSTIME(JOIN_RETRY_INTERVAL_SEC)))) { + /* NOTE(Kevin): Every + * JOIN_RETRY_INTERVAL_SEC interval, we + * can retry + * JOIN_MAX_RETRY_FAILURE_COUNT times. + */ + if (prStaRec->ucJoinFailureCount >= + JOIN_MAX_RETRY_FAILURE_COUNT) { + prStaRec->ucJoinFailureCount = 0; + } + DBGLOG( + SCN, INFO, + "SEARCH:Try to join BSS again,Status Code=%d(Curr=%ld/Last " + "Join=%ld)\n", + prStaRec->u2StatusCode, rCurrentTime, + prStaRec->rLastJoinTime); + } else { + DBGLOG( + SCN, INFO, + "SEARCH: Ignore BSS which reach maximum Join Retry Count = %d\n", + JOIN_MAX_RETRY_FAILURE_COUNT); + continue; + } + } + } + + /* 4 <4> Check for various NETWORK conditions */ + if (prBssInfo->eNetworkType == NETWORK_TYPE_AIS) { + /* 4 <4.1> Check BSS Type for the corresponding + * Operation Mode in Connection Setting */ + /* NOTE(Kevin): For NET_TYPE_AUTO_SWITCH, we will always + * pass following check. */ + if (((prConnSettings->eOPMode == NET_TYPE_INFRA) && + (prBssDesc->eBSSType != BSS_TYPE_INFRASTRUCTURE)) || + ((prConnSettings->eOPMode == NET_TYPE_IBSS || + prConnSettings->eOPMode == NET_TYPE_DEDICATED_IBSS) && + (prBssDesc->eBSSType != BSS_TYPE_IBSS))) { + DBGLOG(SCN, INFO, "SEARCH: Ignore eBSSType = %s\n", + ((prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE) ? + "INFRASTRUCTURE" : + "IBSS")); + continue; + } + /* 4 <4.2> Check AP's BSSID if OID_802_11_BSSID has been + * set. */ + if ((prConnSettings->fgIsConnByBssidIssued) && + (prBssDesc->eBSSType == BSS_TYPE_INFRASTRUCTURE)) { + if (UNEQUAL_MAC_ADDR(prConnSettings->aucBSSID, + prBssDesc->aucBSSID)) { + DBGLOG(SCN, INFO, + "SEARCH: Ignore due to BSSID was not matched!\n"); + continue; + } + } + + /* 4 <4.3> Check for AdHoc Mode */ + if (prBssDesc->eBSSType == BSS_TYPE_IBSS) { + u32 rCurrentTime; + + /* 4 <4.3.1> Check if this SCAN record has been + * updated recently for IBSS. */ + /* NOTE(Kevin): Because some STA may change its + * BSSID frequently after it create the IBSS - + * e.g. IPN2220, so we need to make sure we get + * the new one. For BSS, if the old record was + * matched, however it won't be able to pass the + * Join Process later. + */ + GET_CURRENT_SYSTIME(&rCurrentTime); + if (CHECK_FOR_TIMEOUT( + rCurrentTime, prBssDesc->rUpdateTime, + SEC_TO_SYSTIME(SCN_ADHOC_BSS_DESC_TIMEOUT_SEC))) { + DBGLOG( + SCN, LOUD, + "SEARCH: Skip old record of BSS Descriptor - BSSID:[" MACSTR + "]\n\n", + MAC2STR( + prBssDesc->aucBSSID)); + continue; + } + /* 4 <4.3.2> Check Peer's capability */ + if (ibssCheckCapabilityForAdHocMode(prAdapter, prBssDesc) == + WLAN_STATUS_FAILURE) { + DBGLOG( + SCN, INFO, + "SEARCH: Ignore BSS DESC MAC: " MACSTR + ", Capability is not supported for current AdHoc Mode.\n", + MAC2STR(prPrimaryBssDesc->aucBSSID)); + + continue; + } + + /* 4 <4.3.3> Compare TSF */ + if (prBssInfo->fgIsBeaconActivated && + UNEQUAL_MAC_ADDR(prBssInfo->aucBSSID, + prBssDesc->aucBSSID)) { + DBGLOG(SCN, LOUD, "SEARCH: prBssDesc->fgIsLargerTSF = %d\n", + prBssDesc->fgIsLargerTSF); + + if (!prBssDesc->fgIsLargerTSF) { + DBGLOG(SCN, INFO, + "SEARCH: Ignore BSS DESC MAC: [" MACSTR + "], Smaller TSF\n", + MAC2STR(prBssDesc->aucBSSID)); + continue; + } + } + } + } + + prPrimaryBssDesc = (P_BSS_DESC_T)NULL; + + /* 4 <6> Check current Connection Policy. */ + switch (prConnSettings->eConnectionPolicy) { + case CONNECT_BY_SSID_BEST_RSSI: + /* Choose Hidden SSID to join only if the + * `fgIsEnableJoin...` is true */ + if (prAdapter->rWifiVar.fgEnableJoinToHiddenSSID && + prBssDesc->fgIsHiddenSSID) { + /* NOTE(Kevin): following if () statement means + * that If Target is hidden, then we won't + * connect when user specify SSID_ANY policy. + */ + if (prConnSettings->ucSSIDLen) { + prPrimaryBssDesc = prBssDesc; + + fgIsFindBestRSSI = true; + } + } else if (EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen)) { + prPrimaryBssDesc = prBssDesc; + + fgIsFindBestRSSI = true; + DBGLOG(SCN, LOUD, + "SEARCH: Found BSS by SSID, [" MACSTR "], SSID:%s\n", + MAC2STR(prBssDesc->aucBSSID), prBssDesc->aucSSID); + } + break; + + case CONNECT_BY_SSID_ANY: + /* NOTE(Kevin): In this policy, we don't know the + * desired SSID from user, so we should exclude the + * Hidden SSID from scan list. And because we refuse to + * connect to Hidden SSID node at the beginning, so when + * the JOIN Module deal with a BSS_DESC_T which has + * fgIsHiddenSSID == true, then the Connection Settings + * must be valid without doubt. + */ + if (!prBssDesc->fgIsHiddenSSID) { + prPrimaryBssDesc = prBssDesc; + + fgIsFindFirst = true; + } + break; + + case CONNECT_BY_BSSID: + if (EQUAL_MAC_ADDR(prBssDesc->aucBSSID, prConnSettings->aucBSSID)) { + /* Make sure to match with SSID if supplied. + * Some dual band APs share a single BSSID among + * different BSSes. + */ + if ((prBssDesc->ucSSIDLen > 0 && + prConnSettings->ucSSIDLen > 0 && + EQUAL_SSID(prBssDesc->aucSSID, prBssDesc->ucSSIDLen, + prConnSettings->aucSSID, + prConnSettings->ucSSIDLen)) || + prConnSettings->ucSSIDLen == 0) { + if (prBssDesc->ucChannelNum == + prConnSettings->ucChannelNum) { + prPrimaryBssDesc = prBssDesc; + fgIsFindFirst = true; + } + } + } + break; + + default: + break; + } + + /* Primary Candidate was not found */ + if (prPrimaryBssDesc == NULL) { + continue; + } + + prPrimaryStaRec = prStaRec; + + /* 4 <8> Compare the Candidate and the Primary Scan Record. */ + if (!prCandidateBssDesc) { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + + /* 4 <8.1> Condition - Get the first matched one. */ + if (fgIsFindFirst) { + break; + } + } else { + /* 4 <6D> Condition - Visible SSID win Hidden SSID. */ + if (prCandidateBssDesc->fgIsHiddenSSID) { + if (!prPrimaryBssDesc->fgIsHiddenSSID) { + prCandidateBssDesc = prPrimaryBssDesc; /* The non + * Hidden SSID + * win. */ + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } else { + if (prPrimaryBssDesc->fgIsHiddenSSID) { + continue; + } + } + + /* 4 <6E> Condition - Choose the one with better + * RCPI(RSSI). */ + if (fgIsFindBestRSSI) { + /* TODO(Kevin): We shouldn't compare the actual + * value, we should allow some acceptable + * tolerance of some RSSI percentage here. + */ + DBGLOG(SCN, TRACE, + "Candidate [" MACSTR + "]: RCPI = %d, joinFailCnt=%d, Primary [" MACSTR + "]: RCPI = %d, joinFailCnt=%d\n", + MAC2STR(prCandidateBssDesc->aucBSSID), + prCandidateBssDesc->ucRCPI, + prCandidateBssDesc->ucJoinFailureCount, + MAC2STR(prPrimaryBssDesc->aucBSSID), + prPrimaryBssDesc->ucRCPI, + prPrimaryBssDesc->ucJoinFailureCount); + + ASSERT(!(prCandidateBssDesc->fgIsConnected && + prPrimaryBssDesc->fgIsConnected)); + if (prPrimaryBssDesc->ucJoinFailureCount > + SCN_BSS_JOIN_FAIL_THRESOLD) { + /* give a chance to do join if join fail + * before + * SCN_BSS_DECRASE_JOIN_FAIL_CNT_SEC + * seconds + */ + if (CHECK_FOR_TIMEOUT( + rCurrentTime, prBssDesc->rJoinFailTime, + SEC_TO_SYSTIME(SCN_BSS_JOIN_FAIL_CNT_RESET_SEC))) { + prBssDesc->ucJoinFailureCount -= + SCN_BSS_JOIN_FAIL_RESET_STEP; + DBGLOG(AIS, INFO, + "decrease join fail count for Bss " MACSTR + " to %u, timeout second %d\n", + MAC2STR(prBssDesc->aucBSSID), + prBssDesc->ucJoinFailureCount, + SCN_BSS_JOIN_FAIL_CNT_RESET_SEC); + } + } + /* NOTE: To prevent SWING, we do roaming only if + * target AP has at least 5dBm larger than us. + */ + if (prCandidateBssDesc->fgIsConnected) { + if ((prCandidateBssDesc->ucRCPI + + ROAMING_NO_SWING_RCPI_STEP <= + prPrimaryBssDesc->ucRCPI) && + prPrimaryBssDesc->ucJoinFailureCount <= + SCN_BSS_JOIN_FAIL_THRESOLD) { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } else if (prPrimaryBssDesc->fgIsConnected) { + if ((prCandidateBssDesc->ucRCPI < + prPrimaryBssDesc->ucRCPI + + ROAMING_NO_SWING_RCPI_STEP) || + (prCandidateBssDesc->ucJoinFailureCount > + SCN_BSS_JOIN_FAIL_THRESOLD)) { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } else if (prPrimaryBssDesc->ucJoinFailureCount > + SCN_BSS_JOIN_FAIL_THRESOLD) { + continue; + } else if (prCandidateBssDesc->ucJoinFailureCount > + SCN_BSS_JOIN_FAIL_THRESOLD || + prCandidateBssDesc->ucRCPI < + prPrimaryBssDesc->ucRCPI) { + prCandidateBssDesc = prPrimaryBssDesc; + prCandidateStaRec = prPrimaryStaRec; + continue; + } + } + } + } + + return prCandidateBssDesc; +} + +void scanReportBss2Cfg80211(IN P_ADAPTER_T prAdapter, + IN ENUM_BSS_TYPE_T eBSSType, + IN P_BSS_DESC_T SpecificprBssDesc) +{ + P_SCAN_INFO_T prScanInfo = NULL; + P_LINK_T prBSSDescList = NULL; + P_BSS_DESC_T prBssDesc = NULL; + RF_CHANNEL_INFO_T rChannelInfo; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + prBSSDescList = &prScanInfo->rBSSDescList; + + DBGLOG(SCN, TRACE, "scanReportBss2Cfg80211\n"); + + if (SpecificprBssDesc) { + { + /* check BSSID is legal channel */ + if (!scanCheckBssIsLegal(prAdapter, SpecificprBssDesc)) { + DBGLOG(SCN, TRACE, "Remove specific SSID[%s %d]\n", + SpecificprBssDesc->aucSSID, + SpecificprBssDesc->ucChannelNum); + return; + } + + DBGLOG(SCN, TRACE, "Report Specific SSID[%s]\n", + SpecificprBssDesc->aucSSID); + if (eBSSType == BSS_TYPE_INFRASTRUCTURE) { + kalIndicateBssInfo(prAdapter->prGlueInfo, + (u8 *)SpecificprBssDesc->aucRawBuf, + SpecificprBssDesc->u2RawLength, + SpecificprBssDesc->ucChannelNum, + RCPI_TO_dBm(SpecificprBssDesc->ucRCPI)); + } else { + rChannelInfo.ucChannelNum = SpecificprBssDesc->ucChannelNum; + rChannelInfo.eBand = SpecificprBssDesc->eBand; + kalP2PIndicateBssInfo(prAdapter->prGlueInfo, + (u8 *)SpecificprBssDesc->aucRawBuf, + SpecificprBssDesc->u2RawLength, + &rChannelInfo, + RCPI_TO_dBm(SpecificprBssDesc->ucRCPI)); + } + + SpecificprBssDesc->fgIsP2PReport = false; + } + } else { +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + /* Clear old ACS data (APNum, Dirtiness, ...) and initialize the + * ch number */ + kalMemZero(&(prAdapter->rWifiVar.rChnLoadInfo), + sizeof(prAdapter->rWifiVar.rChnLoadInfo)); + wlanInitChnLoadInfoChannelList(prAdapter); +#endif + + /* Search BSS Desc from current SCAN result list. */ + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T){ +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + /* Record channel loading with channel's AP number */ + u8 ucIdx = wlanGetChannelIndex(prBssDesc->ucChannelNum); + + if (ucIdx < MAX_CHN_NUM) { + prAdapter->rWifiVar.rChnLoadInfo.rEachChnLoad[ucIdx].u2APNum++; + } +#endif + + /* check BSSID is legal channel */ + if (!scanCheckBssIsLegal(prAdapter, prBssDesc)) { + DBGLOG(SCN, TRACE, "Remove SSID[%s %d]\n", prBssDesc->aucSSID, + prBssDesc->ucChannelNum); + continue; + } + + if ((prBssDesc->eBSSType == eBSSType) || + ((eBSSType == BSS_TYPE_P2P_DEVICE) && + (prBssDesc->fgIsP2PReport == true && + prAdapter->p2p_scan_report_all_bss))) { + DBGLOG(SCN, TRACE, "Report ALL SSID[%s %d]\n", + prBssDesc->aucSSID, prBssDesc->ucChannelNum); + + if (eBSSType == BSS_TYPE_INFRASTRUCTURE) { + if (prBssDesc->u2RawLength != 0) { + kalIndicateBssInfo(prAdapter->prGlueInfo, + (u8 *)prBssDesc->aucRawBuf, + prBssDesc->u2RawLength, + prBssDesc->ucChannelNum, + RCPI_TO_dBm(prBssDesc->ucRCPI)); + kalMemZero(prBssDesc->aucRawBuf, CFG_RAW_BUFFER_SIZE); + prBssDesc->u2RawLength = 0; + prBssDesc->fgIsP2PReport = false; + } + } else { + if ((prBssDesc->fgIsP2PReport == true && + prAdapter->p2p_scan_report_all_bss) && + prBssDesc->u2RawLength != 0) { + rChannelInfo.ucChannelNum = prBssDesc->ucChannelNum; + rChannelInfo.eBand = prBssDesc->eBand; + + kalP2PIndicateBssInfo(prAdapter->prGlueInfo, + (u8 *)prBssDesc->aucRawBuf, + prBssDesc->u2RawLength, + &rChannelInfo, + RCPI_TO_dBm(prBssDesc->ucRCPI)); + + /* do not clear it then we can + * pass the bss in Specific + * report */ + /* kalMemZero(prBssDesc->aucRawBuf,CFG_RAW_BUFFER_SIZE); + */ + + /* + * the BSS entry will not be + * cleared after scan done. So + * if we dont receive the BSS in + * next scan, we cannot pass it. + * We use u2RawLength for the + * purpose. + */ + /* prBssDesc->u2RawLength=0; */ + prBssDesc->fgIsP2PReport = false; + } + } + } else { + prBssDesc->u2RawLength = 0; + } + } +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + wlanCalculateAllChannelDirtiness(prAdapter); + wlanSortChannel(prAdapter); + + prAdapter->rWifiVar.rChnLoadInfo.fgDataReadyBit = true; +#endif + } +} + +void scanReportScanResultToAgps(P_ADAPTER_T prAdapter) +{ + P_LINK_T prBSSDescList = &prAdapter->rWifiVar.rScanInfo.rBSSDescList; + P_BSS_DESC_T prBssDesc = NULL; + P_AGPS_AP_LIST_T prAgpsApList = + kalMemAlloc(sizeof(AGPS_AP_LIST_T), VIR_MEM_TYPE); + P_AGPS_AP_INFO_T prAgpsInfo = &prAgpsApList->arApInfo[0]; + P_SCAN_INFO_T prScanInfo = &prAdapter->rWifiVar.rScanInfo; + u8 ucIndex = 0; + + LINK_FOR_EACH_ENTRY(prBssDesc, prBSSDescList, rLinkEntry, BSS_DESC_T){ + if (prBssDesc->rUpdateTime < prScanInfo->rLastScanCompletedTime) { + continue; + } + COPY_MAC_ADDR(prAgpsInfo->aucBSSID, prBssDesc->aucBSSID); + prAgpsInfo->ePhyType = AGPS_PHY_G; + prAgpsInfo->u2Channel = prBssDesc->ucChannelNum; + prAgpsInfo->i2ApRssi = RCPI_TO_dBm(prBssDesc->ucRCPI); + prAgpsInfo++; + ucIndex++; + if (ucIndex == SCN_AGPS_AP_LIST_MAX_NUM) { + break; + } + } + prAgpsApList->ucNum = ucIndex; + GET_CURRENT_SYSTIME(&prScanInfo->rLastScanCompletedTime); + /* DBGLOG(SCN, INFO, ("num of scan list:%d\n", ucIndex)); */ + kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_AP_LIST, + (u8 *)prAgpsApList, sizeof(AGPS_AP_LIST_T)); + kalMemFree(prAgpsApList, VIR_MEM_TYPE, sizeof(AGPS_AP_LIST_T)); +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/scan_fsm.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/scan_fsm.c new file mode 100644 index 00000000000000..ba8bf28a565479 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/scan_fsm.c @@ -0,0 +1,1113 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "scan_fsm.c" + * \brief This file defines the state transition function for SCAN FSM. + * + * The SCAN FSM is part of SCAN MODULE and responsible for performing basic + * SCAN behavior as metioned in IEEE 802.11 2007 11.1.3.1 & 11.1.3.2 . + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +u8 g_aucScanChannelNum[SCN_SCAN_DONE_PRINT_BUFFER_LENGTH]; +u8 g_aucScanChannelIdleTime[SCN_SCAN_DONE_PRINT_BUFFER_LENGTH]; +u8 g_aucScanChannelMDRDY[SCN_SCAN_DONE_PRINT_BUFFER_LENGTH]; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +#if !DBG_DISABLE_ALL_LOG +static u8 *apucDebugScanState[SCAN_STATE_NUM] = { + (u8 *)DISP_STRING("IDLE"), + (u8 *)DISP_STRING("SCANNING"), +}; +#endif + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void scnFsmSteps(IN P_ADAPTER_T prAdapter, IN ENUM_SCAN_STATE_T eNextState) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + P_MSG_HDR_T prMsgHdr; + + u8 fgIsTransition = (u8)false; + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + do { + // DBGLOG(SCN, STATE, "[SCAN]TRANSITION: [%s] -> [%s]\n", + // apucDebugScanState[prScanInfo->eCurrentState], + // apucDebugScanState[eNextState]); + + /* NOTE(Kevin): This is the only place to change the + * eCurrentState(except initial) */ + prScanInfo->eCurrentState = eNextState; + + fgIsTransition = (u8)false; + + switch (prScanInfo->eCurrentState) { + case SCAN_STATE_IDLE: + /* check for pending scanning requests */ + if (!LINK_IS_EMPTY(&(prScanInfo->rPendingMsgList))) { + /* load next message from pending list as scan + * parameters */ + LINK_REMOVE_HEAD(&(prScanInfo->rPendingMsgList), prMsgHdr, + P_MSG_HDR_T); + + if (prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ || + prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ || + prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ || + prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { + scnFsmHandleScanMsg(prAdapter, + (P_MSG_SCN_SCAN_REQ)prMsgHdr); + + eNextState = SCAN_STATE_SCANNING; + fgIsTransition = true; + } else if (prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ_V2 || + prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ_V2 || + prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ_V2 || + prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ_V2) { + scnFsmHandleScanMsgV2(prAdapter, + (P_MSG_SCN_SCAN_REQ_V2)prMsgHdr); + + eNextState = SCAN_STATE_SCANNING; + fgIsTransition = true; + } else { + /* should not happen */ + ASSERT(0); + } + + /* switch to next state */ + cnmMemFree(prAdapter, prMsgHdr); + } + break; + + case SCAN_STATE_SCANNING: + if (prScanParam->fgIsScanV2 == false) { + scnSendScanReq(prAdapter); + } else { + scnSendScanReqV2(prAdapter); + } + break; + + default: + ASSERT(0); + break; + } + } while (fgIsTransition); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Generate CMD_ID_SCAN_REQ command + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void scnSendScanReq(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + CMD_SCAN_REQ rCmdScanReq; + u32 i; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + /* send command packet for scan */ + kalMemZero(&rCmdScanReq, sizeof(CMD_SCAN_REQ)); + + rCmdScanReq.ucSeqNum = prScanParam->ucSeqNum; + rCmdScanReq.ucBssIndex = prScanParam->ucBssIndex; + rCmdScanReq.ucScanType = (u8)prScanParam->eScanType; + rCmdScanReq.ucSSIDType = prScanParam->ucSSIDType; + + if (prScanParam->ucSSIDNum == 1) { + COPY_SSID(rCmdScanReq.aucSSID, rCmdScanReq.ucSSIDLength, + prScanParam->aucSpecifiedSSID[0], + prScanParam->ucSpecifiedSSIDLen[0]); + } + + rCmdScanReq.ucChannelType = (u8)prScanParam->eScanChannel; + + if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + /* P2P would use: + * 1. Specified Listen Channel of passive scan for LISTEN state. + * 2. Specified Listen Channel of Target Device of active scan + * for SEARCH state. (Target != NULL) + */ + rCmdScanReq.ucChannelListNum = prScanParam->ucChannelListNum; + + for (i = 0; i < rCmdScanReq.ucChannelListNum; i++) { + rCmdScanReq.arChannelList[i].ucBand = + (u8)prScanParam->arChnlInfoList[i].eBand; + + rCmdScanReq.arChannelList[i].ucChannelNum = + (u8)prScanParam->arChnlInfoList[i].ucChannelNum; + } + } + + rCmdScanReq.u2ChannelDwellTime = prScanParam->u2ChannelDwellTime; + rCmdScanReq.u2TimeoutValue = prScanParam->u2TimeoutValue; + + if (prScanParam->u2IELen <= MAX_IE_LENGTH) { + rCmdScanReq.u2IELen = prScanParam->u2IELen; + } else { + rCmdScanReq.u2IELen = MAX_IE_LENGTH; + } + + if (prScanParam->u2IELen) { + kalMemCopy(rCmdScanReq.aucIE, prScanParam->aucIE, + sizeof(u8) * rCmdScanReq.u2IELen); + } + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SCAN_REQ, true, false, false, NULL, + NULL, + OFFSET_OF(CMD_SCAN_REQ, aucIE) + rCmdScanReq.u2IELen, + (u8 *)&rCmdScanReq, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Generate CMD_ID_SCAN_REQ_V2 command + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void scnSendScanReqV2(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + CMD_SCAN_REQ_V2 rCmdScanReq; + u32 i; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + /* send command packet for scan */ + kalMemZero(&rCmdScanReq, sizeof(CMD_SCAN_REQ_V2)); + + rCmdScanReq.ucSeqNum = prScanParam->ucSeqNum; + rCmdScanReq.ucBssIndex = prScanParam->ucBssIndex; + rCmdScanReq.ucScanType = (u8)prScanParam->eScanType; + rCmdScanReq.ucSSIDType = prScanParam->ucSSIDType; + rCmdScanReq.ucSSIDNum = prScanParam->ucSSIDNum; + + for (i = 0; i < prScanParam->ucSSIDNum; i++) { + COPY_SSID(rCmdScanReq.arSSID[i].aucSsid, + rCmdScanReq.arSSID[i].u4SsidLen, + prScanParam->aucSpecifiedSSID[i], + prScanParam->ucSpecifiedSSIDLen[i]); + } + + rCmdScanReq.u2ProbeDelayTime = (u8)prScanParam->u2ProbeDelayTime; + rCmdScanReq.ucChannelType = (u8)prScanParam->eScanChannel; + + if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + /* P2P would use: + * 1. Specified Listen Channel of passive scan for LISTEN state. + * 2. Specified Listen Channel of Target Device of active scan + * for SEARCH state. (Target != NULL) + */ + rCmdScanReq.ucChannelListNum = prScanParam->ucChannelListNum; + + for (i = 0; i < rCmdScanReq.ucChannelListNum; i++) { + rCmdScanReq.arChannelList[i].ucBand = + (u8)prScanParam->arChnlInfoList[i].eBand; + + rCmdScanReq.arChannelList[i].ucChannelNum = + (u8)prScanParam->arChnlInfoList[i].ucChannelNum; + } + } + + rCmdScanReq.u2ChannelDwellTime = prScanParam->u2ChannelDwellTime; + rCmdScanReq.u2TimeoutValue = prScanParam->u2TimeoutValue; + + if (prScanParam->u2IELen <= MAX_IE_LENGTH) { + rCmdScanReq.u2IELen = prScanParam->u2IELen; + } else { + rCmdScanReq.u2IELen = MAX_IE_LENGTH; + } + + if (prScanParam->u2IELen) { + kalMemCopy(rCmdScanReq.aucIE, prScanParam->aucIE, + sizeof(u8) * rCmdScanReq.u2IELen); + } + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SCAN_REQ_V2, true, false, false, NULL, + NULL, + OFFSET_OF(CMD_SCAN_REQ_V2, aucIE) + rCmdScanReq.u2IELen, + (u8 *)&rCmdScanReq, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void scnFsmMsgStart(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + + ASSERT(prMsgHdr); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + if (prScanInfo->eCurrentState == SCAN_STATE_IDLE) { + if (prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ || + prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ || + prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ || + prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { + scnFsmHandleScanMsg(prAdapter, (P_MSG_SCN_SCAN_REQ)prMsgHdr); + } else if (prMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ_V2 || + prMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ_V2 || + prMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ_V2 || + prMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ_V2) { + scnFsmHandleScanMsgV2(prAdapter, (P_MSG_SCN_SCAN_REQ_V2)prMsgHdr); + } else { + /* should not deliver to this function */ + ASSERT(0); + } + + cnmMemFree(prAdapter, prMsgHdr); + scnFsmSteps(prAdapter, SCAN_STATE_SCANNING); + } else { + LINK_INSERT_TAIL(&prScanInfo->rPendingMsgList, &prMsgHdr->rLinkEntry); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void scnFsmMsgAbort(IN P_ADAPTER_T prAdapter, IN P_MSG_HDR_T prMsgHdr) +{ + P_MSG_SCN_SCAN_CANCEL prScanCancel; + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + CMD_SCAN_CANCEL rCmdScanCancel; + + kalMemZero(&rCmdScanCancel, sizeof(CMD_SCAN_CANCEL)); + ASSERT(prMsgHdr); + + prScanCancel = (P_MSG_SCN_SCAN_CANCEL)prMsgHdr; + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + if (prScanInfo->eCurrentState != SCAN_STATE_IDLE) { + if (prScanCancel->ucSeqNum == prScanParam->ucSeqNum && + prScanCancel->ucBssIndex == prScanParam->ucBssIndex) { + ENUM_SCAN_STATUS eStatus = SCAN_STATUS_DONE; + /* send cancel message to firmware domain */ + rCmdScanCancel.ucSeqNum = prScanParam->ucSeqNum; + rCmdScanCancel.ucIsExtChannel = (u8)prScanCancel->fgIsChannelExt; + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SCAN_CANCEL, true, false, + false, NULL, NULL, sizeof(CMD_SCAN_CANCEL), + (u8 *)&rCmdScanCancel, NULL, 0); + + /* generate scan-done event for caller */ + if (prScanCancel->fgIsOidRequest) { + eStatus = SCAN_STATUS_CANCELLED; + } else { + eStatus = SCAN_STATUS_DONE; + } + scnFsmGenerateScanDoneMsg(prAdapter, prScanParam->ucSeqNum, + prScanParam->ucBssIndex, eStatus); + + /* switch to next pending scan */ + scnFsmSteps(prAdapter, SCAN_STATE_IDLE); + } else { + scnFsmRemovePendingMsg(prAdapter, prScanCancel->ucSeqNum, + prScanCancel->ucBssIndex); + } + } + + cnmMemFree(prAdapter, prMsgHdr); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Scan Message Parsing (Legacy) + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void scnFsmHandleScanMsg(IN P_ADAPTER_T prAdapter, + IN P_MSG_SCN_SCAN_REQ prScanReqMsg) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + u32 i; + + ASSERT(prAdapter); + ASSERT(prScanReqMsg); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + prScanParam->eScanType = prScanReqMsg->eScanType; + prScanParam->ucBssIndex = prScanReqMsg->ucBssIndex; + prScanParam->ucSSIDType = prScanReqMsg->ucSSIDType; + if (prScanParam->ucSSIDType & + (SCAN_REQ_SSID_SPECIFIED | SCAN_REQ_SSID_P2P_WILDCARD)) { + prScanParam->ucSSIDNum = 1; + + COPY_SSID(prScanParam->aucSpecifiedSSID[0], + prScanParam->ucSpecifiedSSIDLen[0], prScanReqMsg->aucSSID, + prScanReqMsg->ucSSIDLength); + + /* reset SSID length to zero for rest array entries */ + for (i = 1; i < SCN_SSID_MAX_NUM; i++) + prScanParam->ucSpecifiedSSIDLen[i] = 0; + } else { + prScanParam->ucSSIDNum = 0; + + for (i = 0; i < SCN_SSID_MAX_NUM; i++) + prScanParam->ucSpecifiedSSIDLen[i] = 0; + } + + prScanParam->u2ProbeDelayTime = 0; + prScanParam->eScanChannel = prScanReqMsg->eScanChannel; + if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + if (prScanReqMsg->ucChannelListNum <= MAXIMUM_OPERATION_CHANNEL_LIST) { + prScanParam->ucChannelListNum = prScanReqMsg->ucChannelListNum; + } else { + prScanParam->ucChannelListNum = MAXIMUM_OPERATION_CHANNEL_LIST; + } + + kalMemCopy(prScanParam->arChnlInfoList, prScanReqMsg->arChnlInfoList, + sizeof(RF_CHANNEL_INFO_T) * prScanParam->ucChannelListNum); + } + + if (prScanReqMsg->u2IELen <= MAX_IE_LENGTH) { + prScanParam->u2IELen = prScanReqMsg->u2IELen; + } else { + prScanParam->u2IELen = MAX_IE_LENGTH; + } + + if (prScanParam->u2IELen) { + kalMemCopy(prScanParam->aucIE, prScanReqMsg->aucIE, + prScanParam->u2IELen); + } + + prScanParam->u2ChannelDwellTime = prScanReqMsg->u2ChannelDwellTime; + prScanParam->u2TimeoutValue = prScanReqMsg->u2TimeoutValue; + prScanParam->ucSeqNum = prScanReqMsg->ucSeqNum; + + if (prScanReqMsg->rMsgHdr.eMsgId == MID_RLM_SCN_SCAN_REQ) { + prScanParam->fgIsObssScan = true; + } else { + prScanParam->fgIsObssScan = false; + } + + prScanParam->fgIsScanV2 = false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Scan Message Parsing - V2 with multiple SSID support + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void scnFsmHandleScanMsgV2(IN P_ADAPTER_T prAdapter, + IN P_MSG_SCN_SCAN_REQ_V2 prScanReqMsg) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + u32 i; + + ASSERT(prAdapter); + ASSERT(prScanReqMsg); + ASSERT(prScanReqMsg->ucSSIDNum <= SCN_SSID_MAX_NUM); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + prScanParam->eScanType = prScanReqMsg->eScanType; + prScanParam->ucBssIndex = prScanReqMsg->ucBssIndex; + prScanParam->ucSSIDType = prScanReqMsg->ucSSIDType; + prScanParam->ucSSIDNum = prScanReqMsg->ucSSIDNum; + + for (i = 0; i < prScanReqMsg->ucSSIDNum; i++) { + COPY_SSID(prScanParam->aucSpecifiedSSID[i], + prScanParam->ucSpecifiedSSIDLen[i], + prScanReqMsg->prSsid[i].aucSsid, + (u8)prScanReqMsg->prSsid[i].u4SsidLen); + } + + prScanParam->u2ProbeDelayTime = prScanReqMsg->u2ProbeDelay; + prScanParam->eScanChannel = prScanReqMsg->eScanChannel; + if (prScanParam->eScanChannel == SCAN_CHANNEL_SPECIFIED) { + if (prScanReqMsg->ucChannelListNum <= MAXIMUM_OPERATION_CHANNEL_LIST) { + prScanParam->ucChannelListNum = prScanReqMsg->ucChannelListNum; + } else { + prScanParam->ucChannelListNum = MAXIMUM_OPERATION_CHANNEL_LIST; + } + + kalMemCopy(prScanParam->arChnlInfoList, prScanReqMsg->arChnlInfoList, + sizeof(RF_CHANNEL_INFO_T) * prScanParam->ucChannelListNum); + } + + if (prScanReqMsg->u2IELen <= MAX_IE_LENGTH) { + prScanParam->u2IELen = prScanReqMsg->u2IELen; + } else { + prScanParam->u2IELen = MAX_IE_LENGTH; + } + + if (prScanParam->u2IELen) { + kalMemCopy(prScanParam->aucIE, prScanReqMsg->aucIE, + prScanParam->u2IELen); + } + + prScanParam->u2ChannelDwellTime = prScanReqMsg->u2ChannelDwellTime; + prScanParam->u2TimeoutValue = prScanReqMsg->u2TimeoutValue; + prScanParam->ucSeqNum = prScanReqMsg->ucSeqNum; + + if (prScanReqMsg->rMsgHdr.eMsgId == MID_RLM_SCN_SCAN_REQ) { + prScanParam->fgIsObssScan = true; + } else { + prScanParam->fgIsObssScan = false; + } + + prScanParam->fgIsScanV2 = true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Remove pending scan request + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void scnFsmRemovePendingMsg(IN P_ADAPTER_T prAdapter, IN u8 ucSeqNum, + IN u8 ucBssIndex) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + P_MSG_HDR_T prPendingMsgHdr, prPendingMsgHdrNext, prRemoveMsgHdr = NULL; + P_LINK_ENTRY_T prRemoveLinkEntry = NULL; + u8 fgIsRemovingScan = false; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + /* traverse through rPendingMsgList for removal */ + LINK_FOR_EACH_ENTRY_SAFE(prPendingMsgHdr, prPendingMsgHdrNext, + &(prScanInfo->rPendingMsgList), rLinkEntry, + MSG_HDR_T){ + if (prPendingMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ || + prPendingMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ || + prPendingMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ || + prPendingMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ) { + P_MSG_SCN_SCAN_REQ prScanReqMsg = + (P_MSG_SCN_SCAN_REQ)prPendingMsgHdr; + + if (ucSeqNum == prScanReqMsg->ucSeqNum && + ucBssIndex == prScanReqMsg->ucBssIndex) { + prRemoveLinkEntry = &(prScanReqMsg->rMsgHdr.rLinkEntry); + prRemoveMsgHdr = prPendingMsgHdr; + fgIsRemovingScan = true; + } + } else if (prPendingMsgHdr->eMsgId == MID_AIS_SCN_SCAN_REQ_V2 || + prPendingMsgHdr->eMsgId == MID_BOW_SCN_SCAN_REQ_V2 || + prPendingMsgHdr->eMsgId == MID_P2P_SCN_SCAN_REQ_V2 || + prPendingMsgHdr->eMsgId == MID_RLM_SCN_SCAN_REQ_V2) { + P_MSG_SCN_SCAN_REQ_V2 prScanReqMsgV2 = + (P_MSG_SCN_SCAN_REQ_V2)prPendingMsgHdr; + + if (ucSeqNum == prScanReqMsgV2->ucSeqNum && + ucBssIndex == prScanReqMsgV2->ucBssIndex) { + prRemoveLinkEntry = &(prScanReqMsgV2->rMsgHdr.rLinkEntry); + prRemoveMsgHdr = prPendingMsgHdr; + fgIsRemovingScan = true; + } + } + + if (prRemoveLinkEntry) { + if (fgIsRemovingScan == true) { + /* generate scan-done event for caller */ + scnFsmGenerateScanDoneMsg(prAdapter, ucSeqNum, ucBssIndex, + SCAN_STATUS_CANCELLED); + } + + /* remove from pending list */ + LINK_REMOVE_KNOWN_ENTRY(&(prScanInfo->rPendingMsgList), + prRemoveLinkEntry); + cnmMemFree(prAdapter, prRemoveMsgHdr); + + break; + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void scnEventScanDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_SCAN_DONE prScanDone, + u8 fgIsNewVersion) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + u32 u4ChCnt; + u32 u4PrintfIdx = 0; + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + kalMemZero(g_aucScanChannelNum, SCN_SCAN_DONE_PRINT_BUFFER_LENGTH); + kalMemZero(g_aucScanChannelIdleTime, SCN_SCAN_DONE_PRINT_BUFFER_LENGTH); + kalMemZero(g_aucScanChannelMDRDY, SCN_SCAN_DONE_PRINT_BUFFER_LENGTH); + + if (fgIsNewVersion) { + DBGLOG(SCN, INFO, + "scnEventScanDone Version%d!size of " + "ScanDone%d,ucCompleteChanCount[%d],ucCurrentState%d, " + "u4ScanDurBcnCnt[%lu]\n", + prScanDone->ucScanDoneVersion, sizeof(EVENT_SCAN_DONE), + prScanDone->ucCompleteChanCount, prScanDone->ucCurrentState, + prScanDone->u4ScanDurBcnCnt); + + if (prScanDone->ucCurrentState != FW_SCAN_STATE_SCAN_DONE) { + DBGLOG( + SCN, INFO, + "FW Scan timeout!generate ScanDone event at State%d complete chan " + "count%d ucChannelListNum%d\n", + prScanDone->ucCurrentState, prScanDone->ucCompleteChanCount, + prScanParam->ucChannelListNum); + } else { + DBGLOG(SCN, INFO, + " scnEventScanDone at FW_SCAN_STATE_SCAN_DONE state\n"); + } + } else { + DBGLOG(SCN, INFO, "Old scnEventScanDone Version\n"); + } + + /* buffer empty channel information */ + if (prScanParam->eScanChannel == SCAN_CHANNEL_FULL || + prScanParam->eScanChannel == SCAN_CHANNEL_2G4) { + if (prScanDone->ucSparseChannelValid) { + prScanInfo->fgIsSparseChannelValid = true; + prScanInfo->rSparseChannel.eBand = + (ENUM_BAND_T)prScanDone->rSparseChannel.ucBand; + prScanInfo->rSparseChannel.ucChannelNum = + prScanDone->rSparseChannel.ucChannelNum; + prScanInfo->ucSparseChannelArrayValidNum = + prScanDone->ucSparseChannelArrayValidNum; + DBGLOG(SCN, INFO, "Detected_Channel_Num = %d\n", + prScanInfo->ucSparseChannelArrayValidNum); + if (prScanInfo->ucSparseChannelArrayValidNum > 64) { + DBGLOG( + SCN, ERROR, + "%s ucSparseChannelArrayValidNum max. out of bound: %u > 64\n", + __func__, prScanInfo->ucSparseChannelArrayValidNum); + return; + } + + for (u4ChCnt = 0; + u4ChCnt < prScanInfo->ucSparseChannelArrayValidNum; + u4ChCnt++) { + prScanInfo->aucChannelNum[u4ChCnt] = + prScanDone->aucChannelNum[u4ChCnt]; + prScanInfo->au2ChannelIdleTime[u4ChCnt] = + prScanDone->au2ChannelIdleTime[u4ChCnt]; + prScanInfo->aucChannelMDRDYCnt[u4ChCnt] = + prScanDone->aucChannelMDRDYCnt[u4ChCnt]; + + if (u4PrintfIdx % 10 == 0 && u4PrintfIdx != 0) { + DBGLOG(SCN, INFO, "Channel : %s\n", g_aucScanChannelNum); + DBGLOG(SCN, INFO, "IdleTime : %s\n", + g_aucScanChannelIdleTime); + DBGLOG(SCN, INFO, "MdrdyCnt : %s\n", g_aucScanChannelMDRDY); + DBGLOG( + SCN, INFO, + "=============================================================" + "=====================\n"); + kalMemZero(g_aucScanChannelNum, + SCN_SCAN_DONE_PRINT_BUFFER_LENGTH); + kalMemZero(g_aucScanChannelIdleTime, + SCN_SCAN_DONE_PRINT_BUFFER_LENGTH); + kalMemZero(g_aucScanChannelMDRDY, + SCN_SCAN_DONE_PRINT_BUFFER_LENGTH); + u4PrintfIdx = 0; + } + kalSnprintf(g_aucScanChannelNum + u4PrintfIdx * 7, + sizeof(g_aucScanChannelNum) - u4PrintfIdx * 7, + "%7d", prScanInfo->aucChannelNum[u4ChCnt]); + kalSnprintf(g_aucScanChannelIdleTime + u4PrintfIdx * 7, + sizeof(g_aucScanChannelIdleTime) - u4PrintfIdx * 7, + "%7d", prScanInfo->au2ChannelIdleTime[u4ChCnt]); + kalSnprintf(g_aucScanChannelMDRDY + u4PrintfIdx * 7, + sizeof(g_aucScanChannelMDRDY) - u4PrintfIdx * 7, + "%7d", prScanInfo->aucChannelMDRDYCnt[u4ChCnt]); + u4PrintfIdx++; + } + + DBGLOG(SCN, INFO, "Channel : %s\n", g_aucScanChannelNum); + DBGLOG(SCN, INFO, "IdleTime : %s\n", g_aucScanChannelIdleTime); + DBGLOG(SCN, INFO, "MdrdyCnt : %s\n", g_aucScanChannelMDRDY); + } else { + prScanInfo->fgIsSparseChannelValid = false; + } + } + + if (prScanInfo->eCurrentState == SCAN_STATE_SCANNING && + prScanDone->ucSeqNum == prScanParam->ucSeqNum) { + /* generate scan-done event for caller */ + scnFsmGenerateScanDoneMsg(prAdapter, prScanParam->ucSeqNum, + prScanParam->ucBssIndex, SCAN_STATUS_DONE); + + /* switch to next pending scan */ + scnFsmSteps(prAdapter, SCAN_STATE_IDLE); + } else { + DBGLOG(SCN, INFO, + "Unexpected SCAN-DONE event: SeqNum = %d, Current State = %d\n", + prScanDone->ucSeqNum, prScanInfo->eCurrentState); + } +} /* end of scnEventScanDone */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void scnFsmGenerateScanDoneMsg(IN P_ADAPTER_T prAdapter, IN u8 ucSeqNum, + IN u8 ucBssIndex, + IN ENUM_SCAN_STATUS eScanStatus) +{ + P_SCAN_INFO_T prScanInfo; + P_SCAN_PARAM_T prScanParam; + P_MSG_SCN_SCAN_DONE prScanDoneMsg; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prScanParam = &prScanInfo->rScanParam; + + prScanDoneMsg = (P_MSG_SCN_SCAN_DONE)cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_SCN_SCAN_DONE)); + if (!prScanDoneMsg) { + ASSERT(0); /* Can't indicate SCAN FSM Complete */ + return; + } + + if (prScanParam->fgIsObssScan == true) { + prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_RLM_SCAN_DONE; + } else { + switch (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType) { + case NETWORK_TYPE_AIS: + prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_AIS_SCAN_DONE; + break; + + case NETWORK_TYPE_P2P: + prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_P2P_SCAN_DONE; + break; + + case NETWORK_TYPE_BOW: + prScanDoneMsg->rMsgHdr.eMsgId = MID_SCN_BOW_SCAN_DONE; + break; + + default: + DBGLOG(SCN, LOUD, "Unexpected Network Type: %d\n", + GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType); + ASSERT(0); + break; + } + } + + prScanDoneMsg->ucSeqNum = ucSeqNum; + prScanDoneMsg->ucBssIndex = ucBssIndex; + prScanDoneMsg->eScanStatus = eScanStatus; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prScanDoneMsg, + MSG_SEND_METHOD_BUF); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Query for most sparse channel + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u8 scnQuerySparseChannel(IN P_ADAPTER_T prAdapter, P_ENUM_BAND_T prSparseBand, + u8 *pucSparseChannel) +{ + P_SCAN_INFO_T prScanInfo; + + ASSERT(prAdapter); + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + if (prScanInfo->fgIsSparseChannelValid == true) { + if (prSparseBand) { + *prSparseBand = prScanInfo->rSparseChannel.eBand; + } + + if (pucSparseChannel) { + *pucSparseChannel = prScanInfo->rSparseChannel.ucChannelNum; + } + + return true; + } else { + return false; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Event handler for NLO done event + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void scnEventNloDone(IN P_ADAPTER_T prAdapter, IN P_EVENT_NLO_DONE_T prNloDone) +{ + P_SCAN_INFO_T prScanInfo; + P_NLO_PARAM_T prNloParam; + P_SCAN_PARAM_T prScanParam; + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prNloParam = &prScanInfo->rNloParam; + prScanParam = &prNloParam->rScanParam; + + if (prScanInfo->fgNloScanning == true && + prNloDone->ucSeqNum == prScanParam->ucSeqNum) { + DBGLOG(SCN, INFO, "scnEventNloDone reporting to uplayer\n"); + + kalSchedScanResults(prAdapter->prGlueInfo); + + if (prNloParam->fgStopAfterIndication == true) { + prScanInfo->fgNloScanning = false; + } + } else { + DBGLOG(SCN, INFO, + "Unexpected NLO-DONE event: SeqNum = %d, Current State = %d\n", + prNloDone->ucSeqNum, prScanInfo->eCurrentState); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief OID handler for starting scheduled scan + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u8 scnFsmSchedScanRequest(IN P_ADAPTER_T prAdapter, IN u8 ucSsidNum, + IN P_PARAM_SSID_T prSsid, IN u32 u4IeLength, + IN u8 *pucIe, IN u16 u2Interval) +{ + P_SCAN_INFO_T prScanInfo; + P_NLO_PARAM_T prNloParam; + P_SCAN_PARAM_T prScanParam; + P_CMD_NLO_REQ prCmdNloReq; + u32 i, j; + + ASSERT(prAdapter); + + DBGLOG(SCN, INFO, "scnFsmSchedScanRequest\n"); + + if (prAdapter->prAisBssInfo == NULL) { + return false; + } + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prNloParam = &prScanInfo->rNloParam; + prScanParam = &prNloParam->rScanParam; + + /* ASSERT(prScanInfo->fgNloScanning == false); */ + if (prScanInfo->fgNloScanning) { + DBGLOG(SCN, INFO, + "prScanInfo->fgNloScanning == false already scanning\n"); + return true; + } + + prScanInfo->fgNloScanning = true; + + /* 1. load parameters */ + prScanParam->ucSeqNum++; + prScanParam->ucBssIndex = prAdapter->prAisBssInfo->ucBssIndex; + prNloParam->fgStopAfterIndication = false; + prNloParam->ucFastScanIteration = 0; + + if (u2Interval < SCAN_NLO_DEFAULT_INTERVAL) { + u2Interval = SCAN_NLO_DEFAULT_INTERVAL; + DBGLOG(SCN, INFO, "force interval to SCAN_NLO_DEFAULT_INTERVAL\n"); + } + prAdapter->prAisBssInfo->fgIsPNOEnable = true; + + if (!IS_NET_ACTIVE(prAdapter, prAdapter->prAisBssInfo->ucBssIndex)) { + SET_NET_ACTIVE(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + DBGLOG(SCN, INFO, "ACTIVE AIS from INACTIVE to enable PNO\n"); + /* sync with firmware */ + nicActivateNetwork(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + } + prNloParam->u2FastScanPeriod = u2Interval; + prNloParam->u2SlowScanPeriod = u2Interval; + + if (ucSsidNum > CFG_SCAN_SSID_MAX_NUM) { + prScanParam->ucSSIDNum = CFG_SCAN_SSID_MAX_NUM; + } else { + prScanParam->ucSSIDNum = ucSsidNum; + } + + if (ucSsidNum > CFG_SCAN_SSID_MATCH_MAX_NUM) { + prNloParam->ucMatchSSIDNum = CFG_SCAN_SSID_MATCH_MAX_NUM; + } else { + prNloParam->ucMatchSSIDNum = ucSsidNum; + } + + for (i = 0; i < prNloParam->ucMatchSSIDNum; i++) { + if (i < CFG_SCAN_SSID_MAX_NUM) { + COPY_SSID(prScanParam->aucSpecifiedSSID[i], + prScanParam->ucSpecifiedSSIDLen[i], prSsid[i].aucSsid, + (u8)prSsid[i].u4SsidLen); + } + + COPY_SSID(prNloParam->aucMatchSSID[i], prNloParam->ucMatchSSIDLen[i], + prSsid[i].aucSsid, (u8)prSsid[i].u4SsidLen); + + /* for linux the Ciper,Auth Algo will be zero */ + prNloParam->aucCipherAlgo[i] = 0; + prNloParam->au2AuthAlgo[i] = 0; + + for (j = 0; j < SCN_NLO_NETWORK_CHANNEL_NUM; j++) + prNloParam->aucChannelHint[i][j] = 0; + } + + /* 2. prepare command for sending */ + prCmdNloReq = (P_CMD_NLO_REQ)cnmMemAlloc(prAdapter, RAM_TYPE_BUF, + sizeof(CMD_NLO_REQ) + u4IeLength); + + if (!prCmdNloReq) { + ASSERT(0); /* Can't initiate NLO operation */ + return false; + } + + /* 3. send command packet for NLO operation */ + kalMemZero(prCmdNloReq, sizeof(CMD_NLO_REQ)); + + prCmdNloReq->ucSeqNum = prScanParam->ucSeqNum; + prCmdNloReq->ucBssIndex = prScanParam->ucBssIndex; + prCmdNloReq->fgStopAfterIndication = prNloParam->fgStopAfterIndication; + prCmdNloReq->ucFastScanIteration = prNloParam->ucFastScanIteration; + prCmdNloReq->u2FastScanPeriod = prNloParam->u2FastScanPeriod; + prCmdNloReq->u2SlowScanPeriod = prNloParam->u2SlowScanPeriod; + prCmdNloReq->ucEntryNum = prNloParam->ucMatchSSIDNum; + + prCmdNloReq->ucFlag = SCAN_NLO_CHECK_SSID_ONLY; + DBGLOG(SCN, INFO, "LINUX only check SSID for PNO SCAN\n"); + + for (i = 0; i < prNloParam->ucMatchSSIDNum; i++) { + COPY_SSID(prCmdNloReq->arNetworkList[i].aucSSID, + prCmdNloReq->arNetworkList[i].ucSSIDLength, + prNloParam->aucMatchSSID[i], prNloParam->ucMatchSSIDLen[i]); + + prCmdNloReq->arNetworkList[i].ucCipherAlgo = + prNloParam->aucCipherAlgo[i]; + prCmdNloReq->arNetworkList[i].u2AuthAlgo = prNloParam->au2AuthAlgo[i]; + DBGLOG(SCN, INFO, "prCmdNloReq->arNetworkList[i].aucSSID %s\n", + prCmdNloReq->arNetworkList[i].aucSSID); + DBGLOG(SCN, INFO, "prCmdNloReq->arNetworkList[i].ucSSIDLength %d\n", + prCmdNloReq->arNetworkList[i].ucSSIDLength); + DBGLOG(SCN, INFO, "prCmdNloReq->arNetworkList[i].ucCipherAlgo %d\n", + prCmdNloReq->arNetworkList[i].ucCipherAlgo); + DBGLOG(SCN, INFO, "prCmdNloReq->arNetworkList[i].u2AuthAlgo %d\n", + prCmdNloReq->arNetworkList[i].u2AuthAlgo); + + for (j = 0; j < SCN_NLO_NETWORK_CHANNEL_NUM; j++) + prCmdNloReq->arNetworkList[i].ucNumChannelHint[j] = + prNloParam->aucChannelHint[i][j]; + } + + if (u4IeLength <= MAX_IE_LENGTH) { + prCmdNloReq->u2IELen = prScanParam->u2IELen; + } else { + prCmdNloReq->u2IELen = MAX_IE_LENGTH; + } + + if (u4IeLength) { + kalMemCopy(prScanParam->aucIE, pucIe, prCmdNloReq->u2IELen); + kalMemCopy(prCmdNloReq->aucIE, pucIe, prCmdNloReq->u2IELen); + } + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_NLO_REQ, true, false, true, + nicCmdEventSetCommon, nicOidCmdTimeoutCommon, + sizeof(CMD_NLO_REQ) + prCmdNloReq->u2IELen, + (u8 *)prCmdNloReq, NULL, 0); + + cnmMemFree(prAdapter, (void *)prCmdNloReq); + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief OID handler for stopping scheduled scan + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u8 scnFsmSchedScanStopRequest(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + P_NLO_PARAM_T prNloParam; + P_SCAN_PARAM_T prScanParam; + CMD_NLO_CANCEL rCmdNloCancel; + WLAN_STATUS rStatus; + + kalMemZero(&rCmdNloCancel, sizeof(CMD_NLO_CANCEL)); + ASSERT(prAdapter); + DBGLOG(SCN, INFO, "scnFsmSchedScanStopRequest\n"); + + if (prAdapter->prAisBssInfo == NULL) { + return false; + } + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + prNloParam = &prScanInfo->rNloParam; + prScanParam = &prNloParam->rScanParam; + + if (prAdapter->prAisBssInfo->fgIsNetRequestInActive && + prAdapter->prAisBssInfo->fgIsPNOEnable) { + UNSET_NET_ACTIVE(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + DBGLOG(SCN, INFO, "INACTIVE AIS from ACTIVE to DISABLE PNO\n"); + /* sync with firmware */ + nicDeactivateNetwork(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + } else { + DBGLOG(SCN, INFO, "fgIsNetRequestInActive %d, fgIsPNOEnable %d\n", + prAdapter->prAisBssInfo->fgIsNetRequestInActive, + prAdapter->prAisBssInfo->fgIsPNOEnable); + } + + prAdapter->prAisBssInfo->fgIsPNOEnable = false; + + /* send cancel message to firmware domain */ + rCmdNloCancel.ucSeqNum = prScanParam->ucSeqNum; + + rStatus = wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_NLO_CANCEL, true, false, + true, nicCmdEventSetStopSchedScan, + /* nicCmdEventSetCommon, */ + nicOidCmdTimeoutCommon, + sizeof(CMD_NLO_CANCEL), (u8 *)&rCmdNloCancel, + NULL, 0); + + prScanInfo->fgNloScanning = false; + if (rStatus != WLAN_STATUS_FAILURE) { + return true; + } else { + return false; + } +} + +u8 scnFsmIsScanning(IN P_ADAPTER_T prAdapter) +{ + P_SCAN_INFO_T prScanInfo; + + prScanInfo = &(prAdapter->rWifiVar.rScanInfo); + + return (prScanInfo->eCurrentState == SCAN_STATE_SCANNING) ? true : false; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/swcr.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/swcr.c new file mode 100644 index 00000000000000..d3dca7518be711 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/swcr.c @@ -0,0 +1,1392 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "swcr.c" + * \brief + * + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#include "swcr.h" + +#if CFG_SUPPORT_SWCR + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +u32 g_au4SwCr[SWCR_CR_NUM]; /*: 0: command other: data */ + +/* JB mDNS Filter*/ +u32 g_u4RXFilter; /* [31] 0: stop 1: start, [3] IPv6 [2] IPv4 */ + +static TIMER_T g_rSwcrDebugTimer; +static u8 g_fgSwcrDebugTimer = false; +static u32 g_u4SwcrDebugCheckTimeout; +static ENUM_SWCR_DBG_TYPE_T g_ucSwcrDebugCheckType; +static u32 g_u4SwcrDebugFrameDumpType; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +static const PFN_CMD_RW_T g_arSwCtrlCmd[] = { + swCtrlCmdCategory0, swCtrlCmdCategory1 +#if TEST_PS + , + testPsCmdCategory0, testPsCmdCategory1 +#endif +#if CFG_SUPPORT_802_11V +#if (CFG_SUPPORT_802_11V_TIMING_MEASUREMENT == 1) && (WNM_UNIT_TEST == 1) + , + testWNMCmdCategory0 +#endif +#endif +}; + +const PFN_SWCR_RW_T g_arSwCrModHandle[] = { swCtrlSwCr, NULL }; + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +enum { + SWCTRL_MAGIC, + SWCTRL_DEBUG, + SWCTRL_WIFI_VAR, + SWCTRL_ENABLE_INT, + SWCTRL_DISABLE_INT, + SWCTRL_TXM_INFO, + SWCTRL_RXM_INFO, + SWCTRL_DUMP_BSS, + SWCTRL_QM_INFO, + SWCTRL_DUMP_ALL_QUEUE_LEN, + SWCTRL_DUMP_MEM, + SWCTRL_TX_CTRL_INFO, + SWCTRL_DUMP_QUEUE, + SWCTRL_DUMP_QM_DBG_CNT, + SWCTRL_QM_DBG_CNT, + SWCTRL_RX_PKTS_DUMP, + SWCTRL_RX_FILTER, +#if CFG_INIT_ENABLE_PATTERN_FILTER_ARP + SWCTRL_RX_ARP_OFFLOAD, +#endif + SWCTRL_PS_DTIM_SKIP, + SWCTRL_ROAMING, + SWCTRL_CATA0_INDEX_NUM +}; + +enum { + SWCTRL_STA_INFO, + SWCTRL_DUMP_STA, + SWCTRL_STA_QUE_INFO, + SWCTRL_CATA1_INDEX_NUM +}; + +/* JB mDNS Filter*/ +#define RX_FILTER_START (1 << 31) +#define RX_FILTER_IPV4 (1 << 2) +#define RX_FILTER_IPV6 (1 << 3) +typedef enum _ENUM_SWCR_RX_FILTER_CMD_T { + SWCR_RX_FILTER_CMD_STOP = 0, + SWCR_RX_FILTER_CMD_START, + SWCR_RX_FILTER_CMD_ADD, + SWCR_RX_FILTER_CMD_REMOVE, + SWCR_RX_FILTER_NUM +} ENUM_SWCR_RX_FILTER_CMD_T; + +#if TEST_PS +enum { + TEST_PS_MAGIC, + TEST_PS_SETUP_BSS, + TEST_PS_ENABLE_BEACON, + TEST_PS_TRIGGER_BMC, + TEST_PS_SEND_NULL, + TEST_PS_BUFFER_BMC, + TEST_PS_UPDATE_BEACON, + TEST_PS_CATA0_INDEX_NUM +}; + +enum { + TEST_PS_STA_PS, + TEST_PS_STA_ENTER_PS, + TEST_PS_STA_EXIT_PS, + TEST_PS_STA_TRIGGER_PSPOLL, + TEST_PS_STA_TRIGGER_FRAME, + TEST_PS_CATA1_INDEX_NUM +}; +#endif + +#if CFG_SUPPORT_802_11V +#if WNM_UNIT_TEST +enum { + TEST_WNM_TIMING_MEAS, + TEST_WNM_CATA0_INDEX_NUM +}; +#endif +#endif + +#define _SWCTRL_MAGIC 0x66201642 + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ +void dumpQueue(P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + P_QUE_MGT_T prQM; + P_GLUE_INFO_T prGlueInfo; + u32 i; + u32 j; + + DEBUGFUNC("dumpQueue"); + + prTxCtrl = &prAdapter->rTxCtrl; + prQM = &prAdapter->rQM; + prGlueInfo = prAdapter->prGlueInfo; +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + for (i = TC0_INDEX; i <= TC5_INDEX; i++) { + DBGLOG(SW4, INFO, "TC %u\n", i); + DBGLOG(SW4, INFO, "Max %u Free %u\n", + prTxCtrl->rTc.au4MaxNumOfBuffer[i], + prTxCtrl->rTc.au4FreeBufferCount[i]); + + DBGLOG(SW4, + INFO, + "Average %u minReserved %u CurrentTcResource %u GuaranteedTcResource %u\n", + QM_GET_TX_QUEUE_LEN(prAdapter, i), + prQM->au4MinReservedTcResource[i], + prQM->au4CurrentTcResource[i], + prQM->au4GuaranteedTcResource[i]); + } +#endif + +#if QM_FORWARDING_FAIRNESS + for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) { + DBGLOG(SW4, INFO, "TC %u HeadStaIdx %u ForwardCount %u\n", i, + prQM->au4HeadStaRecIndex[i], + prQM->au4ResourceUsedCount[i]); + } +#endif + + DBGLOG(SW4, INFO, "BMC or unknown TxQueue Len %u\n", + prQM->arTxQueue[0].u4NumElem); + DBGLOG(SW4, INFO, "Pending %d\n", prGlueInfo->i4TxPendingFrameNum); + DBGLOG(SW4, INFO, "Pending Security %d\n", + prGlueInfo->i4TxPendingSecurityFrameNum); + + for (i = 0; i < 4; i++) { + for (j = 0; j < CFG_MAX_TXQ_NUM; j++) + DBGLOG(SW4, INFO, "Pending Q[%u][%u] %d\n", i, j, + prGlueInfo->ai4TxPendingFrameNumPerQueue[i][j]); + } + + DBGLOG(SW4, INFO, " rFreeSwRfbList %u\n", + prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem); + DBGLOG(SW4, INFO, " rReceivedRfbList %u\n", + prAdapter->rRxCtrl.rReceivedRfbList.u4NumElem); + DBGLOG(SW4, INFO, " rIndicatedRfbList %u\n", + prAdapter->rRxCtrl.rIndicatedRfbList.u4NumElem); + DBGLOG(SW4, INFO, " ucNumIndPacket %u\n", + prAdapter->rRxCtrl.ucNumIndPacket); + DBGLOG(SW4, INFO, " ucNumRetainedPacket %u\n", + prAdapter->rRxCtrl.ucNumRetainedPacket); +} + +void dumpSTA(P_ADAPTER_T prAdapter, P_STA_RECORD_T prStaRec) +{ + u8 ucWTEntry; + u32 i; + P_BSS_INFO_T prBssInfo; + + DEBUGFUNC("dumpSTA"); + + ASSERT(prStaRec); + ucWTEntry = prStaRec->ucWlanIndex; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + ASSERT(prBssInfo); + + DBGLOG(SW4, INFO, "Mac address: " MACSTR " Rcpi %u\n", + MAC2STR(prStaRec->aucMacAddr), prStaRec->ucRCPI); + + DBGLOG(SW4, + INFO, + "Idx %u Wtbl %u Used %u State %u Bss Phy 0x%x Sta DesiredPhy 0x%x\n", + prStaRec->ucIndex, + ucWTEntry, + prStaRec->fgIsInUse, + prStaRec->ucStaState, + prBssInfo->ucPhyTypeSet, + prStaRec->ucDesiredPhyTypeSet); + + DBGLOG(SW4, + INFO, + "Sta Operation 0x%x DesiredNontHtRateSet 0x%x Mcs 0x%x u2HtCapInfo 0x%x\n", + prStaRec->u2OperationalRateSet, + prStaRec->u2DesiredNonHTRateSet, + prStaRec->ucMcsSet, + prStaRec->u2HtCapInfo); + + for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) + if (prStaRec->aprTargetQueue[i]) { + DBGLOG(SW4, INFO, "TC %u Queue Len %u\n", i, + prStaRec->aprTargetQueue[i]->u4NumElem); + } + + DBGLOG(SW4, INFO, "BmpDeliveryAC %x\n", prStaRec->ucBmpDeliveryAC); + DBGLOG(SW4, INFO, "BmpTriggerAC %x\n", prStaRec->ucBmpTriggerAC); + DBGLOG(SW4, INFO, "UapsdSpSupproted %u\n", + prStaRec->fgIsUapsdSupported); + DBGLOG(SW4, INFO, "IsQoS %u\n", prStaRec->fgIsQoS); + DBGLOG(SW4, INFO, "AssocId %u\n", prStaRec->u2AssocId); + + DBGLOG(SW4, INFO, "fgIsInPS %u\n", prStaRec->fgIsInPS); + DBGLOG(SW4, INFO, "ucFreeQuota %u\n", prStaRec->ucFreeQuota); + DBGLOG(SW4, INFO, "ucFreeQuotaForDelivery %u\n", + prStaRec->ucFreeQuotaForDelivery); + DBGLOG(SW4, INFO, "ucFreeQuotaForNonDelivery %u\n", + prStaRec->ucFreeQuotaForNonDelivery); + + for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) { + if (prStaRec->aprRxReorderParamRefTbl[i]) { + DBGLOG(SW4, INFO, "RxReorder fgIsValid: %u\n", + prStaRec->aprRxReorderParamRefTbl[i]->fgIsValid); + DBGLOG(SW4, INFO, "RxReorder Tid: %u\n", + prStaRec->aprRxReorderParamRefTbl[i]->ucTid); + DBGLOG(SW4, INFO, "RxReorder rReOrderQue Len: %u\n", + prStaRec->aprRxReorderParamRefTbl[i] + ->rReOrderQue.u4NumElem); + DBGLOG(SW4, INFO, "RxReorder WinStart: %u\n", + prStaRec->aprRxReorderParamRefTbl[i]->u2WinStart); + DBGLOG(SW4, INFO, "RxReorder WinEnd: %u\n", + prStaRec->aprRxReorderParamRefTbl[i]->u2WinEnd); + DBGLOG(SW4, INFO, "RxReorder WinSize: %u\n", + prStaRec->aprRxReorderParamRefTbl[i]->u2WinSize); + } + } +} + +void dumpBss(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo) +{ + DBGLOG(SW4, INFO, "SSID %s\n", prBssInfo->aucSSID); + DBGLOG(SW4, INFO, "OWN " MACSTR "\n", + MAC2STR(prBssInfo->aucOwnMacAddr)); + DBGLOG(SW4, INFO, "BSSID " MACSTR "\n", MAC2STR(prBssInfo->aucBSSID)); + DBGLOG(SW4, INFO, "eNetworkType %u\n", prBssInfo->eNetworkType); + DBGLOG(SW4, INFO, "ucBssIndex %u\n", prBssInfo->ucBssIndex); + DBGLOG(SW4, INFO, "eConnectionState %u\n", prBssInfo->eConnectionState); + DBGLOG(SW4, INFO, "eCurrentOPMode %u\n", prBssInfo->eCurrentOPMode); + DBGLOG(SW4, INFO, "fgIsQBSS %u\n", prBssInfo->fgIsQBSS); + DBGLOG(SW4, INFO, "fgIsShortPreambleAllowed %u\n", + prBssInfo->fgIsShortPreambleAllowed); + DBGLOG(SW4, INFO, "fgUseShortPreamble %u\n", + prBssInfo->fgUseShortPreamble); + DBGLOG(SW4, INFO, "fgUseShortSlotTime %u\n", + prBssInfo->fgUseShortSlotTime); + DBGLOG(SW4, INFO, "ucNonHTBasicPhyType %x\n", + prBssInfo->ucNonHTBasicPhyType); + DBGLOG(SW4, INFO, "u2OperationalRateSet %x\n", + prBssInfo->u2OperationalRateSet); + DBGLOG(SW4, INFO, "u2BSSBasicRateSet %x\n", + prBssInfo->u2BSSBasicRateSet); + DBGLOG(SW4, INFO, "ucPhyTypeSet %x\n", prBssInfo->ucPhyTypeSet); + DBGLOG(SW4, INFO, "rStaRecOfClientList %d\n", + prBssInfo->rStaRecOfClientList.u4NumElem); + DBGLOG(SW4, INFO, "u2CapInfo %x\n", prBssInfo->u2CapInfo); + DBGLOG(SW4, INFO, "u2ATIMWindow %x\n", prBssInfo->u2ATIMWindow); + DBGLOG(SW4, INFO, "u2AssocId %x\n", prBssInfo->u2AssocId); + DBGLOG(SW4, INFO, "ucDTIMPeriod %x\n", prBssInfo->ucDTIMPeriod); + DBGLOG(SW4, INFO, "ucDTIMCount %x\n", prBssInfo->ucDTIMCount); + DBGLOG(SW4, INFO, "fgIsNetAbsent %x\n", prBssInfo->fgIsNetAbsent); + DBGLOG(SW4, INFO, "eBand %d\n", prBssInfo->eBand); + DBGLOG(SW4, INFO, "ucPrimaryChannel %d\n", prBssInfo->ucPrimaryChannel); + DBGLOG(SW4, INFO, "ucHtOpInfo1 %d\n", prBssInfo->ucHtOpInfo1); + DBGLOG(SW4, INFO, "ucHtOpInfo2 %d\n", prBssInfo->u2HtOpInfo2); + DBGLOG(SW4, INFO, "ucHtOpInfo3 %d\n", prBssInfo->u2HtOpInfo3); + DBGLOG(SW4, INFO, "fgErpProtectMode %d\n", prBssInfo->fgErpProtectMode); + DBGLOG(SW4, INFO, "eHtProtectMode %d\n", prBssInfo->eHtProtectMode); + DBGLOG(SW4, INFO, "eGfOperationMode %d\n", prBssInfo->eGfOperationMode); + DBGLOG(SW4, INFO, "eRifsOperationMode %d\n", + prBssInfo->eRifsOperationMode); + DBGLOG(SW4, INFO, "fgObssErpProtectMode %d\n", + prBssInfo->fgObssErpProtectMode); + DBGLOG(SW4, INFO, "eObssHtProtectMode %d\n", + prBssInfo->eObssHtProtectMode); + DBGLOG(SW4, INFO, "eObssGfProtectMode %d\n", + prBssInfo->eObssGfOperationMode); + DBGLOG(SW4, INFO, "fgObssRifsOperationMode %d\n", + prBssInfo->fgObssRifsOperationMode); + DBGLOG(SW4, INFO, "fgAssoc40mBwAllowed %d\n", + prBssInfo->fgAssoc40mBwAllowed); + DBGLOG(SW4, INFO, "fg40mBwAllowed %d\n", prBssInfo->fg40mBwAllowed); + DBGLOG(SW4, INFO, "eBssSCO %d\n", prBssInfo->eBssSCO); +} + +void swCtrlCmdCategory0(P_ADAPTER_T prAdapter, u8 ucCate, u8 ucAction, + u8 ucOpt0, u8 ucOpt1) +{ + u8 ucIndex, ucRead; + u32 i; + CMD_RX_PACKET_FILTER rSetRxPacketFilter; + + DEBUGFUNC("swCtrlCmdCategory0"); + + SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); + + i = 0; + + if (ucIndex >= SWCTRL_CATA0_INDEX_NUM) { + return; + } + + if (ucRead == SWCR_WRITE) { + switch (ucIndex) { + case SWCTRL_DEBUG: + break; + + case SWCTRL_WIFI_VAR: + break; + +#if QM_DEBUG_COUNTER + case SWCTRL_DUMP_QM_DBG_CNT: + for (i = 0; i < QM_DBG_CNT_NUM; i++) + prAdapter->rQM.au4QmDebugCounters[i] = 0; + break; + + case SWCTRL_QM_DBG_CNT: + if (ucOpt0 >= QM_DBG_CNT_NUM) { + DBGLOG(INIT, + ERROR, + "%s-SWCTRL_QM_DBG_CNT: ucOpt0:%d out of bound\n", + __func__, + ucOpt0); + return; + } + prAdapter->rQM.au4QmDebugCounters[ucOpt0] = + g_au4SwCr[1]; + break; + +#endif +#if CFG_RX_PKTS_DUMP + case SWCTRL_RX_PKTS_DUMP: + /* DBGLOG(SW4, INFO,("SWCTRL_RX_PKTS_DUMP: mask %x\n", + * g_au4SwCr[1])); */ + prAdapter->rRxCtrl.u4RxPktsDumpTypeMask = g_au4SwCr[1]; + break; + +#endif + case SWCTRL_RX_FILTER: { + u32 u4rxfilter; + u8 fgUpdate = false; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + if (ucOpt0 == SWCR_RX_FILTER_CMD_STOP) { + g_u4RXFilter &= ~(RX_FILTER_START); + prAdapter->u4OsPacketFilter &= + ~PARAM_PACKET_FILTER_MULTICAST; + u4rxfilter = prAdapter->u4OsPacketFilter; + fgUpdate = true; + } else if (ucOpt0 == SWCR_RX_FILTER_CMD_START) { + g_u4RXFilter |= (RX_FILTER_START); + + if ((g_u4RXFilter & RX_FILTER_IPV4) || + (g_u4RXFilter & RX_FILTER_IPV6)) { + prAdapter->u4OsPacketFilter |= + PARAM_PACKET_FILTER_MULTICAST; + } + u4rxfilter = prAdapter->u4OsPacketFilter; + fgUpdate = true; + } else if (ucOpt0 == SWCR_RX_FILTER_CMD_ADD) { + if (ucOpt1 < 31) { + g_u4RXFilter |= (1 << ucOpt1); + } + } else if (ucOpt0 == SWCR_RX_FILTER_CMD_REMOVE) { + if (ucOpt1 < 31) { + g_u4RXFilter &= ~(1 << ucOpt1); + } + } + + if (fgUpdate == true) { + kalMemZero(&rSetRxPacketFilter, + sizeof(rSetRxPacketFilter)); + rSetRxPacketFilter.u4RxPacketFilter = + u4rxfilter; + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_SET_RX_FILTER, /* ucCID */ + true, /* fgSetQuery */ + false, /* fgNeedResp */ + false, /* fgIsOid */ + NULL, /* pfCmdDoneHandler */ + NULL, /* pfCmdTimeoutHandler */ + sizeof(CMD_RX_PACKET_FILTER), /*u4SetQueryInfoLen*/ + (u8 *)&rSetRxPacketFilter, /*pucInfoBuffer*/ + NULL, /* pvSetQueryBuffer */ + 0 /* un4SetQueryBufferLen */ + ); + u4rxfilter = + rSetRxPacketFilter.u4RxPacketFilter; + } + /* DBGLOG(SW4, INFO,("SWCTRL_RX_FILTER: + * g_u4RXFilter %x ucOpt0 %x ucOpt1 %x fgUpdate %x + * u4rxfilter %x, rStatus %x\n", + */ + /* g_u4RXFilter, ucOpt0, ucOpt1, fgUpdate, u4rxfilter, + * rStatus)); */ + } break; + +#if CFG_INIT_ENABLE_PATTERN_FILTER_ARP + case SWCTRL_RX_ARP_OFFLOAD: { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + u32 u4SetInfoLen = 0; + u32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, + arAddress); + u32 u4NumIPv4 = 0, u4NumIPv6 = 0; + u32 i = 0; + u8 *pucBufIpAddr = NULL; + P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList = NULL; + P_PARAM_NETWORK_ADDRESS_IP prParamIpAddr = NULL; + u8 *pucIp = NULL; + /* u8 * pucIpv6 = NULL; */ + u32 bufSize = + u4Len + + (OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + + sizeof(PARAM_NETWORK_ADDRESS_IP)) * + 3; + P_PARAM_NETWORK_ADDRESS prParamNetAddr = NULL; + + /* <1> allocate IP address buffer */ + pucBufIpAddr = kalMemAlloc(bufSize, VIR_MEM_TYPE); + pucIp = kalMemAlloc(3 * 4, VIR_MEM_TYPE); /* TODO: + * replace 3 + * to macro */ + + prParamNetAddrList = + (P_PARAM_NETWORK_ADDRESS_LIST)pucBufIpAddr; + prParamNetAddr = prParamNetAddrList->arAddress; + /* <2> clear IP address buffer */ + kalMemZero(pucBufIpAddr, bufSize); + kalMemZero(pucIp, 3 * 4); + + /* <3> setup the number of IP address */ + if (ucOpt1 == 1) { + if (wlanGetIPV4Address(prAdapter->prGlueInfo, + pucIp, &u4NumIPv4) && + u4NumIPv4 > 3) { /* TODO: repleace 3 + * to macro */ + u4NumIPv4 = 3; + } + } else if (ucOpt1 == 0) { + u4NumIPv4 = u4NumIPv6 = 0; + } + DBGLOG(INIT, INFO, "u4Len:%d bufSize:%d u4NumIPv4:%d\n", + u4Len, bufSize, u4NumIPv4); + + prParamNetAddrList->u4AddressCount = + u4NumIPv6 + u4NumIPv4; + prParamNetAddrList->u2AddressType = + PARAM_PROTOCOL_ID_TCP_IP; + + for (i = 0; i < u4NumIPv4; i++) { + prParamNetAddr->u2AddressLength = + sizeof(PARAM_NETWORK_ADDRESS_IP); + prParamNetAddr->u2AddressType = + PARAM_PROTOCOL_ID_TCP_IP; + prParamIpAddr = + (P_PARAM_NETWORK_ADDRESS_IP) + prParamNetAddr->aucAddress; + kalMemCopy(&prParamIpAddr->in_addr, + pucIp + (i * 4), 4); + prParamNetAddr = + (P_PARAM_NETWORK_ADDRESS)((u32) + prParamNetAddr + + + OFFSET_OF( + PARAM_NETWORK_ADDRESS, + aucAddress) + + + sizeof( + PARAM_NETWORK_ADDRESS_IP)); + u4Len += OFFSET_OF(PARAM_NETWORK_ADDRESS, + aucAddress) + + sizeof(PARAM_NETWORK_ADDRESS_IP); + } + + ASSERT(u4Len <= bufSize); + + rStatus = wlanoidSetNetworkAddress( + prAdapter, (void *)prParamNetAddrList, u4Len, + &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, + "set HW packet filter fail 0x%1x\n", + rStatus); + } + + if (pucIp) { + kalMemFree(pucIp, VIR_MEM_TYPE, 3 * 4); /* TODO: + * replace + * 3 to + * marco + */ + } + if (pucBufIpAddr) { + kalMemFree(pucBufIpAddr, VIR_MEM_TYPE, bufSize); + } + } break; + +#endif + case SWCTRL_PS_DTIM_SKIP: + break; + + case SWCTRL_ROAMING: + break; + + default: + break; + } + } else { + switch (ucIndex) { + case SWCTRL_DEBUG: + break; + + case SWCTRL_MAGIC: + g_au4SwCr[1] = _SWCTRL_MAGIC; + break; + + case SWCTRL_QM_INFO: { + P_QUE_MGT_T prQM = &prAdapter->rQM; + + switch (ucOpt0) { + case 0: +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + if (ucOpt1 >= TC_NUM) { + DBGLOG(SW4, + WARN, + "%s-SWCTRL_QM_INFO(0): ucOpt1:%d out of bound\n", + __func__, + ucOpt1); + return; + } + g_au4SwCr[1] = (QM_GET_TX_QUEUE_LEN(prAdapter, + ucOpt1)); + g_au4SwCr[2] = + prQM->au4MinReservedTcResource[ucOpt1]; + g_au4SwCr[3] = + prQM->au4CurrentTcResource[ucOpt1]; + g_au4SwCr[4] = + prQM->au4GuaranteedTcResource[ucOpt1]; +#endif + break; + + case 1: +#if QM_FORWARDING_FAIRNESS +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + if (ucOpt1 >= TC_NUM) +#else + if (ucOpt1 >= NUM_OF_PER_STA_TX_QUEUES) +#endif + { + DBGLOG(SW4, + WARN, + "%s-SWCTRL_QM_INFO(1): ucOpt1:%d out of bound\n", + __func__, + ucOpt1); + return; + } + g_au4SwCr[1] = + prQM->au4ResourceUsedCount[ucOpt1]; + g_au4SwCr[2] = prQM->au4HeadStaRecIndex[ucOpt1]; +#endif + break; + + case 2: + if (ucOpt1 >= NUM_OF_PER_TYPE_TX_QUEUES) { + DBGLOG(SW4, + WARN, + "%s-SWCTRL_QM_INFO(2): ucOpt1:%d out of bound\n", + __func__, + ucOpt1); + return; + } + g_au4SwCr[1] = prQM->arTxQueue[ucOpt1] + .u4NumElem; /* only + * one + */ + + break; + } + } break; + + case SWCTRL_TX_CTRL_INFO: { + P_TX_CTRL_T prTxCtrl; + + prTxCtrl = &prAdapter->rTxCtrl; + switch (ucOpt0) { + case 0: + if (ucOpt1 >= TC_NUM) { + DBGLOG(SW4, + WARN, + "%s-SWCTRL_TX_CTRL_INFO(0): ucOpt1:%d out of bound\n", + __func__, + ucOpt1); + return; + } + g_au4SwCr[1] = + prAdapter->rTxCtrl.rTc + .au4FreeBufferCount[ucOpt1]; + g_au4SwCr[2] = + prAdapter->rTxCtrl.rTc + .au4MaxNumOfBuffer[ucOpt1]; + break; + } + } break; + + case SWCTRL_DUMP_QUEUE: + dumpQueue(prAdapter); + + break; + +#if QM_DEBUG_COUNTER + case SWCTRL_DUMP_QM_DBG_CNT: + for (i = 0; i < QM_DBG_CNT_NUM; i++) + DBGLOG(SW4, INFO, "QM:DBG %u %u\n", i, + prAdapter->rQM.au4QmDebugCounters[i]); + break; + + case SWCTRL_QM_DBG_CNT: + if (ucOpt0 >= QM_DBG_CNT_NUM) { + DBGLOG(INIT, + ERROR, + "%s-SWCTRL_QM_DBG_CNT: ucOpt0:%d out of bound\n", + __func__, + ucOpt0); + return; + } + g_au4SwCr[1] = + prAdapter->rQM.au4QmDebugCounters[ucOpt0]; + break; + +#endif + case SWCTRL_DUMP_BSS: { + if (ucOpt0 >= (HW_BSSID_NUM + 1)) { + DBGLOG(INIT, + ERROR, + "%s-SWCTRL_DUMP_BSS: ucOpt0:%d out of bound\n", + __func__, + ucOpt0); + return; + } + dumpBss(prAdapter, + GET_BSS_INFO_BY_INDEX(prAdapter, ucOpt0)); + } break; + + default: + break; + } + } +} + +void swCtrlCmdCategory1(P_ADAPTER_T prAdapter, u8 ucCate, u8 ucAction, + u8 ucOpt0, u8 ucOpt1) +{ + u8 ucIndex, ucRead; + u8 ucWTEntry; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("swCtrlCmdCategory1"); + + SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); + + if (ucOpt0 >= CFG_STA_REC_NUM) { + return; + } + + /* prStaRec = cnmGetStaRecByIndex (prAdapter, ucOpt0); */ + prStaRec = &prAdapter->arStaRec[ucOpt0]; + ucWTEntry = prStaRec->ucWlanIndex; + if (ucRead == SWCR_WRITE) { + /* ToDo:: Nothing */ + } else { + /* Read */ + switch (ucIndex) { + case SWCTRL_STA_QUE_INFO: { + if (ucOpt1 >= NUM_OF_PER_STA_TX_QUEUES) { + DBGLOG(SW4, + WARN, + "%s-SWCTRL_STA_QUE_INFO: ucOpt1:%d out of bound\n", + __func__, + ucOpt1); + return; + } + g_au4SwCr[1] = prStaRec->arTxQueue[ucOpt1].u4NumElem; + } break; + + case SWCTRL_STA_INFO: + switch (ucOpt1) { + case 0: + g_au4SwCr[1] = prStaRec->fgIsInPS; + break; + } + + break; + + case SWCTRL_DUMP_STA: { + dumpSTA(prAdapter, prStaRec); + } break; + + default: + + break; + } + } +} + +#if TEST_PS + +void testPsSendQoSNullFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec, IN u8 ucUP, + IN u8 ucBssIndex, IN u8 fgBMC, IN u8 fgIsBurstEnd, + IN u8 ucPacketType, IN u8 ucPsSessionID, + IN u8 fgSetEOSP) +{ + P_MSDU_INFO_T prMsduInfo; + u16 u2EstimatedFrameLen; + P_WLAN_MAC_HEADER_QOS_T prQoSNullFrame; + + DEBUGFUNC("testPsSendQoSNullFrame"); + DBGLOG(SW4, LOUD, "\n"); + + /* 4 <1> Allocate a PKT_INFO_T for Null Frame */ + /* Init with MGMT Header Length */ + u2EstimatedFrameLen = MAC_TX_RESERVED_FIELD + WLAN_MAC_HEADER_QOS_LEN; + + /* Allocate a MSDU_INFO_T */ + + prMsduInfo = cnmMgtPktAlloc(prAdapter, u2EstimatedFrameLen); + + if (prMsduInfo == NULL) { + DBGLOG(SW4, WARN, "No PKT_INFO_T for sending Null Frame.\n"); + return; + } + /* 4 <2> Compose Null frame in MSDU_INfO_T. */ + bssComposeQoSNullFrame(prAdapter, + (u8 *)((unsigned long)(prMsduInfo->prPacket) + + MAC_TX_RESERVED_FIELD), + prStaRec, ucUP, fgSetEOSP); + + TX_SET_MMPDU(prAdapter, prMsduInfo, ucBssIndex, prStaRec->ucIndex, + WLAN_MAC_HEADER_QOS_LEN, WLAN_MAC_HEADER_QOS_LEN, NULL, + MSDU_RATE_MODE_AUTO); + + prMsduInfo->ucUserPriority = ucUP; + prMsduInfo->ucPacketType = ucPacketType; + + prQoSNullFrame = (P_WLAN_MAC_HEADER_QOS_T)(( + u8 *)((unsigned long) + (prMsduInfo-> + prPacket) + + MAC_TX_RESERVED_FIELD)); + + if (fgBMC) { + prQoSNullFrame->aucAddr1[0] = 0xfd; + }else{ + prQoSNullFrame->aucAddr1[5] = 0xdd; + } + + /* 4 <4> Inform TXM to send this Null frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); +} + +void testPsSetupBss(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex) +{ + P_BSS_INFO_T prBssInfo; + u8 _aucZeroMacAddr[] = NULL_MAC_ADDR; + + DEBUGFUNC("testPsSetupBss()"); + DBGLOG(SW4, INFO, "index %d\n", ucBssIndex); + + if (!IS_BSS_INDEX_VALID(ucBssIndex)) { + DBGLOG(RLM, ERROR, "Invalid bssidx:%d\n", ucBssIndex); + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + /* 4 <1.2> Initiate PWR STATE */ + /* SET_NET_PWR_STATE_IDLE(prAdapter, ucNetworkTypeIndex); */ + + /* 4 <2> Initiate BSS_INFO_T - common part */ + BSS_INFO_INIT(prAdapter, prBssInfo); + + prBssInfo->eConnectionState = PARAM_MEDIA_STATE_DISCONNECTED; + prBssInfo->eConnectionStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; + prBssInfo->eCurrentOPMode = OP_MODE_ACCESS_POINT; + prBssInfo->fgIsNetActive = true; + prBssInfo->ucBssIndex = ucBssIndex; + prBssInfo->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_RESERVED; + + prBssInfo->ucPhyTypeSet = PHY_TYPE_SET_802_11BG; /* Depend on eBand */ + prBssInfo->ucConfigAdHocAPMode = AP_MODE_MIXED_11BG; /* Depend on + * eCurrentOPMode + * and ucPhyTypeSet + */ + prBssInfo->u2BSSBasicRateSet = RATE_SET_ERP; + prBssInfo->u2OperationalRateSet = RATE_SET_OFDM; + prBssInfo->fgErpProtectMode = false; + prBssInfo->fgIsQBSS = true; + + /* 4 <1.5> Setup MIB for current BSS */ + prBssInfo->u2BeaconInterval = 100; + prBssInfo->ucDTIMPeriod = DOT11_DTIM_PERIOD_DEFAULT; + prBssInfo->u2ATIMWindow = 0; + + prBssInfo->ucBeaconTimeoutCount = 0; + + bssInitForAP(prAdapter, prBssInfo, true); + + COPY_MAC_ADDR(prBssInfo->aucBSSID, _aucZeroMacAddr); + LINK_INITIALIZE(&prBssInfo->rStaRecOfClientList); + prBssInfo->fgIsBeaconActivated = true; + prBssInfo->u2HwDefaultFixedRateCode = RATE_CCK_1M_LONG; + + COPY_MAC_ADDR(prBssInfo->aucOwnMacAddr, + prAdapter->rWifiVar.aucMacAddress); + + /* 4 <3> Initiate BSS_INFO_T - private part */ + /* TODO */ + prBssInfo->eBand = BAND_2G4; + prBssInfo->ucPrimaryChannel = 1; + prBssInfo->prStaRecOfAP = (P_STA_RECORD_T)NULL; + + /* prBssInfo->fgErpProtectMode = eErpProectMode; */ + /* prBssInfo->eHtProtectMode = eHtProtectMode; */ + /* prBssInfo->eGfOperationMode = eGfOperationMode; */ + + /* 4 <4> Allocate MSDU_INFO_T for Beacon */ + prBssInfo->prBeacon = cnmMgtPktAlloc( + prAdapter, + OFFSET_OF(WLAN_BEACON_FRAME_T, aucInfoElem[0]) + MAX_IE_LENGTH); + + if (prBssInfo->prBeacon) { + prBssInfo->prBeacon->eSrc = TX_PACKET_MGMT; + prBssInfo->prBeacon->ucBssIndex = ucBssIndex; + } else { + DBGLOG(SW4, INFO, "prBeacon allocation fail\n"); + } + + prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC = + (u8)prAdapter->u4UapsdAcBmp; + prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC = + (u8)prAdapter->u4UapsdAcBmp; + prBssInfo->rPmProfSetupInfo.ucUapsdSp = (u8)prAdapter->u4MaxSpLen; + + DBGLOG(SW4, INFO, + "[2] ucBmpDeliveryAC:0x%x, ucBmpTriggerAC:0x%x, ucUapsdSp:0x%x", + prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC, + prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC, + prBssInfo->rPmProfSetupInfo.ucUapsdSp); +} + +void testPsCmdCategory0(P_ADAPTER_T prAdapter, u8 ucCate, u8 ucAction, + u8 ucOpt0, u8 ucOpt1) +{ + u8 ucIndex, ucRead; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("testPsCmdCategory0"); + SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); + + DBGLOG(SW4, LOUD, "Read %u Index %u\n", ucRead, ucIndex); + + prStaRec = cnmGetStaRecByIndex(prAdapter, 0); + + if (ucIndex >= TEST_PS_CATA0_INDEX_NUM) { + return; + } + + if (ucRead == SWCR_WRITE) { + switch (ucIndex) { + case TEST_PS_SETUP_BSS: + testPsSetupBss(prAdapter, ucOpt0); + break; + + case TEST_PS_ENABLE_BEACON: + break; + + case TEST_PS_TRIGGER_BMC: + /* txmForwardQueuedBmcPkts (ucOpt0); */ + break; + + case TEST_PS_SEND_NULL: { + testPsSendQoSNullFrame( + prAdapter, prStaRec, + (u8)(g_au4SwCr[1] & 0xFF), /* UP */ + ucOpt0, (u8)((g_au4SwCr[1] >> 8) & 0xFF), /* BMC + */ + (u8)((g_au4SwCr[1] >> 16) & 0xFF), /* BurstEnd + */ + (u8)((g_au4SwCr[1] >> 24) & 0xFF), /* Packet + * type */ + (u8)((g_au4SwCr[2]) & 0xFF), /* PS sesson ID 7: + * NOACK */ + false /* EOSP */ + ); + } break; + + case TEST_PS_BUFFER_BMC: + /* g_aprBssInfo[ucOpt0]->fgApToBufferBMC = (g_au4SwCr[1] + * & 0xFF); */ + break; + + case TEST_PS_UPDATE_BEACON: + bssUpdateBeaconContent(prAdapter, + ucOpt0 /*networktype */ ); + break; + + default: + break; + } + } else { + switch (ucIndex) { + case TEST_PS_MAGIC: + g_au4SwCr[1] = 0x88660011; + break; + } + } +} + +#endif + +#if TEST_PS + +void testPsCmdCategory1(P_ADAPTER_T prAdapter, u8 ucCate, u8 ucAction, + u8 ucOpt0, u8 ucOpt1) +{ + u8 ucIndex, ucRead; + u8 ucWTEntry; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("testPsCmdCategory1"); + + SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); + + if (ucOpt0 >= CFG_STA_REC_NUM) { + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, ucOpt0); + + if (!prStaRec) { + DBGLOG(SW4, INFO, "prStaRec is NULL, ucOpt0:%d\n", ucOpt0); + return; + } + + ucWTEntry = prStaRec->ucWlanIndex; + if (ucRead == SWCR_WRITE) { + switch (ucIndex) { + case TEST_PS_STA_PS: + prStaRec->fgIsInPS = (u8)(g_au4SwCr[1] & 0x1); + prStaRec->fgIsQoS = (u8)(g_au4SwCr[1] >> 8 & 0xFF); + prStaRec->fgIsUapsdSupported = + (u8)(g_au4SwCr[1] >> 16 & 0xFF); + prStaRec->ucBmpDeliveryAC = + (u8)(g_au4SwCr[1] >> 24 & 0xFF); + break; + } + } else { + /* Read */ + switch (ucIndex) { + default: + break; + } + } +} + +#endif + +#if CFG_SUPPORT_802_11V +#if (CFG_SUPPORT_802_11V_TIMING_MEASUREMENT == 1) && (WNM_UNIT_TEST == 1) +void testWNMCmdCategory0(P_ADAPTER_T prAdapter, u8 ucCate, u8 ucAction, + u8 ucOpt0, u8 ucOpt1) +{ + u8 ucIndex, ucRead; + P_STA_RECORD_T prStaRec; + + DEBUGFUNC("testWNMCmdCategory0"); + SWCR_GET_RW_INDEX(ucAction, ucRead, ucIndex); + + DBGLOG(SW4, INFO, "Read %u Index %u\n", ucRead, ucIndex); + + if (ucIndex >= TEST_WNM_CATA0_INDEX_NUM) { + return; + } + + if (ucRead == SWCR_WRITE) { + switch (ucIndex) { + case TEST_WNM_TIMING_MEAS: + wnmTimingMeasUnitTest1(prAdapter, ucOpt0); + break; + + default: + break; + } + } +} +#endif +#endif + +void swCtrlSwCr(P_ADAPTER_T prAdapter, u8 ucRead, u16 u2Addr, u32 *pu4Data) +{ + /* According other register STAIDX */ + u8 ucOffset; + + ucOffset = (u2Addr >> 2) & 0x3F; + + if (ucOffset >= SWCR_CR_NUM) { + return; + } + + if (ucRead == SWCR_WRITE) { + g_au4SwCr[ucOffset] = *pu4Data; + if (ucOffset == 0x0) { + /* Commmand [31:24]: Category */ + /* Commmand [23:23]: 1(W) 0(R) */ + /* Commmand [22:16]: Index */ + /* Commmand [15:08]: Option0 */ + /* Commmand [07:00]: Option1 */ + u8 ucCate; + u32 u4Cmd; + + u4Cmd = g_au4SwCr[0]; + ucCate = (u8)(u4Cmd >> 24); + if (ucCate < ARRAY_SIZE(g_arSwCtrlCmd)) { + if (g_arSwCtrlCmd[ucCate] != NULL) { + g_arSwCtrlCmd[ucCate]( + prAdapter, ucCate, + (u8)(u4Cmd >> 16 & 0xFF), + (u8)((u4Cmd >> 8) & 0xFF), + (u8)(u4Cmd & 0xFF)); + } + } + } + } else { + *pu4Data = g_au4SwCr[ucOffset]; + } +} + +void swCrReadWriteCmd(P_ADAPTER_T prAdapter, u8 ucRead, u16 u2Addr, + u32 *pu4Data) +{ + u8 ucMod; + + ucMod = u2Addr >> 8; + /* Address [15:8] MOD ID */ + /* Address [7:0] OFFSET */ + + DEBUGFUNC("swCrReadWriteCmd"); + DBGLOG(SW4, INFO, "%u addr 0x%x data 0x%x\n", ucRead, u2Addr, *pu4Data); + + if (ucMod < (ARRAY_SIZE(g_arSwCrModHandle))) { + if (g_arSwCrModHandle[ucMod] != NULL) { + g_arSwCrModHandle[ucMod](prAdapter, ucRead, u2Addr, + pu4Data); + } + } +} + +/* Debug Support */ +void swCrFrameCheckEnable(P_ADAPTER_T prAdapter, u32 u4DumpType) +{ + g_u4SwcrDebugFrameDumpType = u4DumpType; +#if CFG_RX_PKTS_DUMP + prAdapter->rRxCtrl.u4RxPktsDumpTypeMask = u4DumpType; +#endif +} + +void swCrDebugInit(P_ADAPTER_T prAdapter) +{ + /* frame dump */ + if (g_u4SwcrDebugFrameDumpType) { + swCrFrameCheckEnable(prAdapter, g_u4SwcrDebugFrameDumpType); + } + /* debug counter */ + g_fgSwcrDebugTimer = false; + + cnmTimerInitTimer(prAdapter, &g_rSwcrDebugTimer, + (PFN_MGMT_TIMEOUT_FUNC)swCrDebugCheckTimeout, + (unsigned long)NULL); + + if (g_u4SwcrDebugCheckTimeout) { + swCrDebugCheckEnable(prAdapter, true, g_ucSwcrDebugCheckType, + g_u4SwcrDebugCheckTimeout); + } +} + +void swCrDebugUninit(P_ADAPTER_T prAdapter) +{ + cnmTimerStopTimer(prAdapter, &g_rSwcrDebugTimer); + + g_fgSwcrDebugTimer = false; +} + +void swCrDebugCheckEnable(P_ADAPTER_T prAdapter, u8 fgIsEnable, u8 ucType, + u32 u4Timeout) +{ + if (fgIsEnable) { + g_ucSwcrDebugCheckType = ucType; + g_u4SwcrDebugCheckTimeout = u4Timeout; + if (g_fgSwcrDebugTimer == false) { + swCrDebugCheckTimeout(prAdapter, 0); + } + } else { + cnmTimerStopTimer(prAdapter, &g_rSwcrDebugTimer); + g_u4SwcrDebugCheckTimeout = 0; + } + + g_fgSwcrDebugTimer = fgIsEnable; +} + +void swCrDebugCheck(P_ADAPTER_T prAdapter, P_CMD_SW_DBG_CTRL_T prCmdSwCtrl) +{ + P_RX_CTRL_T prRxCtrl; + P_TX_CTRL_T prTxCtrl; + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + /* dump counters */ + if (prCmdSwCtrl) { + if (prCmdSwCtrl->u4Data == SWCR_DBG_TYPE_ALL) { + /* TX Counter from fw */ + DBGLOG(SW4, INFO, + "TX0\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n", + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_TX_BCN_CNT], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_TX_FAILED_CNT], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_TX_RETRY_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_TX_AGING_TIMEOUT_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_TX_PS_OVERFLOW_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_TX_MGNT_DROP_CNT], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_TX_ERROR_CNT]); + + /* TX Counter from drv */ + DBGLOG(SW4, INFO, + "TX1\n" + "%08x %08x %08x %08x\n", + (u32)TX_GET_CNT(prTxCtrl, TX_INACTIVE_BSS_DROP), + (u32)TX_GET_CNT(prTxCtrl, TX_INACTIVE_STA_DROP), + (u32)TX_GET_CNT(prTxCtrl, + TX_FORWARD_OVERFLOW_DROP), + (u32)TX_GET_CNT(prTxCtrl, TX_AP_BORADCAST_DROP)); + + /* RX Counter */ + DBGLOG(SW4, + INFO, + "RX0\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n", + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_CNT], + prCmdSwCtrl->u4DebugCnt[SWCR_DBG_ALL_RX_DROP_CNT], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_RX_DUP_DROP_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_RX_TYPE_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_RX_CLASS_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_RX_AMPDU_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_RX_STATUS_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_RX_FORMAT_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_RX_ICV_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_RX_KEY_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_RX_TKIP_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_RX_MIC_ERROR_DROP_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_RX_BIP_ERROR_DROP_CNT], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_RX_FCSERR_CNT], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_RX_FIFOFULL_CNT], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_RX_PFDROP_CNT]); + + DBGLOG(SW4, INFO, + "RX1\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n", + (u32)RX_GET_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT), + (u32)RX_GET_CNT(prRxCtrl, + RX_DATA_INDICATION_COUNT), + (u32)RX_GET_CNT(prRxCtrl, + RX_DATA_RETURNED_COUNT), + (u32)RX_GET_CNT(prRxCtrl, + RX_DATA_RETAINED_COUNT), + (u32)RX_GET_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT), + (u32)RX_GET_CNT(prRxCtrl, + RX_TYPE_ERR_DROP_COUNT), + (u32)RX_GET_CNT(prRxCtrl, + RX_CLASS_ERR_DROP_COUNT), + (u32)RX_GET_CNT(prRxCtrl, + RX_DST_NULL_DROP_COUNT)); + + DBGLOG(SW4, INFO, + "PWR\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n", + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_PWR_PS_POLL_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_PWR_TRIGGER_NULL_CNT], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_PWR_BCN_IND_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_PWR_BCN_TIMEOUT_CNT], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_PWR_PM_STATE0], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_PWR_PM_STATE1], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_PWR_CUR_PS_PROF0], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_PWR_CUR_PS_PROF1]); + + DBGLOG(SW4, INFO, + "ARM\n" + "%08x %08x %08x %08x\n" + "%08x %08x\n", + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_RATE], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_AR_STA0_BWGI], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_AR_STA0_RX_RATE_RCPI], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_ROAMING_ENABLE], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_ROAMING_ROAM_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_ROAMING_INT_CNT]); + + DBGLOG(SW4, INFO, + "BB\n" + "%08x %08x %08x %08x\n" + "%08x %08x %08x %08x\n", + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_BB_RX_MDRDY_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_BB_RX_FCSERR_CNT], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_BB_CCK_PD_CNT], + prCmdSwCtrl + ->u4DebugCnt[SWCR_DBG_ALL_BB_OFDM_PD_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_BB_CCK_SFDERR_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_BB_CCK_SIGERR_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_BB_OFDM_TAGERR_CNT], + prCmdSwCtrl->u4DebugCnt + [SWCR_DBG_ALL_BB_OFDM_SIGERR_CNT]); + } + } + /* start the next check */ + if (g_u4SwcrDebugCheckTimeout) { + cnmTimerStartTimer(prAdapter, &g_rSwcrDebugTimer, + g_u4SwcrDebugCheckTimeout * MSEC_PER_SEC); + } +} + +void swCrDebugCheckTimeout(IN P_ADAPTER_T prAdapter, unsigned long ulParamPtr) +{ + CMD_SW_DBG_CTRL_T rCmdSwCtrl; + WLAN_STATUS rStatus; + + kalMemZero(&rCmdSwCtrl, sizeof(CMD_SW_DBG_CTRL_T)); + rCmdSwCtrl.u4Id = (0xb000 << 16) + g_ucSwcrDebugCheckType; + rCmdSwCtrl.u4Data = 0; + rStatus = wlanSendSetQueryCmd( + prAdapter, /* prAdapter */ + CMD_ID_SW_DBG_CTRL, /* ucCID */ + false, /* fgSetQuery */ + true, /* fgNeedResp */ + false, /* fgIsOid */ + swCrDebugQuery, /* pfCmdDoneHandler */ + swCrDebugQueryTimeout, /* pfCmdTimeoutHandler + */ + sizeof(CMD_SW_DBG_CTRL_T), /* u4SetQueryInfoLen + */ + (u8 *)&rCmdSwCtrl, /* pucInfoBuffer */ + NULL, /* pvSetQueryBuffer */ + 0 /* u4SetQueryBufferLen */ + ); + + ASSERT(rStatus == WLAN_STATUS_PENDING); +} + +void swCrDebugQuery(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + ASSERT(prAdapter); + if (u4EventBufLen < sizeof(CMD_SW_DBG_CTRL_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", + __func__, u4EventBufLen, sizeof(CMD_SW_DBG_CTRL_T)); + return; + } + swCrDebugCheck(prAdapter, (P_CMD_SW_DBG_CTRL_T)(pucEventBuf)); +} + +void swCrDebugQueryTimeout(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + ASSERT(prAdapter); + + swCrDebugCheck(prAdapter, NULL); +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/tdls.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/tdls.c new file mode 100644 index 00000000000000..2e129bcad40e75 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/tdls.c @@ -0,0 +1,1831 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file tdls.c + * \brief This file includes IEEE802.11z TDLS support. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +#if CFG_SUPPORT_TDLS +#include "tdls.h" +#include "gl_cfg80211.h" +#include "queue.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* The list of valid data rates. */ +/* The list of valid data rates. */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +static u8 fgIsPtiTimeoutSkip = false; + +/******************************************************************************* + * P R I V A T E F U N C T I O N S + ******************************************************************************* + */ + +#define ELEM_ID_LINK_IDENTIFIER_LENGTH 16 + +#define TDLS_KEY_TIMEOUT_INTERVAL 43200 + +#define UNREACH_ABLE 25 +#define TDLS_REASON_CODE_UNREACHABLE 25 +#define TDLS_REASON_CODE_UNSPECIFIED 26 + +#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25 +#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26 + +u8 g_arTdlsLink[MAXNUM_TDLS_PEER] = { 0, 0, 0, 0 }; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to hadel TDLS link oper from nl80211. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] + * \param[in] + * \param[in] buf includes RSN IE + FT IE + Lifetimeout IE + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +u32 TdlsexLinkMgt(P_ADAPTER_T prAdapter, void *pvSetBuffer, u32 u4SetBufferLen, + u32 *pu4SetInfoLen) +{ + /* from supplicant -- wpa_supplicant_tdls_peer_addset() */ + + STA_RECORD_T *prStaRec; + P_BSS_INFO_T prBssInfo; + TDLS_CMD_LINK_MGT_T *prCmd; + + prCmd = (TDLS_CMD_LINK_MGT_T *)pvSetBuffer; + prBssInfo = prAdapter->prAisBssInfo; + + /* AIS only */ + if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + prStaRec = prBssInfo->prStaRecOfAP; + if (prStaRec == NULL) { + return 0; + } + } else { + return -EINVAL; + } + + switch (prCmd->ucActionCode) { + case TDLS_FRM_ACTION_DISCOVERY_REQ: + + if (TdlsDataFrameSend_DISCOVERY_REQ( + prAdapter, prStaRec, prCmd->aucPeer, + prCmd->ucActionCode, prCmd->ucDialogToken, + prCmd->u2StatusCode, (u8 *)(prCmd->aucSecBuf), + prCmd->u4SecBufLen) != TDLS_STATUS_SUCCESS) { + return -1; + } + + break; + + case TDLS_FRM_ACTION_SETUP_REQ: + + prStaRec = cnmGetTdlsPeerByAddress( + prAdapter, prAdapter->prAisBssInfo->ucBssIndex, + prCmd->aucPeer); + g_arTdlsLink[prStaRec->ucTdlsIndex] = 0; + if (TdlsDataFrameSend_SETUP_REQ( + prAdapter, prStaRec, prCmd->aucPeer, + prCmd->ucActionCode, prCmd->ucDialogToken, + prCmd->u2StatusCode, (u8 *)(prCmd->aucSecBuf), + prCmd->u4SecBufLen) != TDLS_STATUS_SUCCESS) { + return -1; + } + + break; + + case TDLS_FRM_ACTION_SETUP_RSP: + + /* fix sigma bug 5.2.4.2, 5.2.4.7, we sent Status code decline, + * but the sigma recogniezis it as scucess, and it will fail + */ + /* if(prCmd->u2StatusCode != 0) */ + if (prBssInfo->fgTdlsIsProhibited) { + return 0; + } + + if (TdlsDataFrameSend_SETUP_RSP( + prAdapter, prStaRec, prCmd->aucPeer, + prCmd->ucActionCode, prCmd->ucDialogToken, + prCmd->u2StatusCode, (u8 *)(prCmd->aucSecBuf), + prCmd->u4SecBufLen) != TDLS_STATUS_SUCCESS) { + return -1; + } + + break; + + case TDLS_FRM_ACTION_DISCOVERY_RSP: + + if (TdlsDataFrameSend_DISCOVERY_RSP( + prAdapter, prStaRec, prCmd->aucPeer, + prCmd->ucActionCode, prCmd->ucDialogToken, + prCmd->u2StatusCode, (u8 *)(prCmd->aucSecBuf), + prCmd->u4SecBufLen) != TDLS_STATUS_SUCCESS) { + return -1; + } + + break; + + case TDLS_FRM_ACTION_CONFIRM: + + if (TdlsDataFrameSend_CONFIRM( + prAdapter, prStaRec, prCmd->aucPeer, + prCmd->ucActionCode, prCmd->ucDialogToken, + prCmd->u2StatusCode, (u8 *)(prCmd->aucSecBuf), + prCmd->u4SecBufLen) != TDLS_STATUS_SUCCESS) { + return -1; + } + break; + + case TDLS_FRM_ACTION_TEARDOWN: + + prStaRec = cnmGetTdlsPeerByAddress( + prAdapter, prAdapter->prAisBssInfo->ucBssIndex, + prCmd->aucPeer); + if (prCmd->u2StatusCode == TDLS_REASON_CODE_UNREACHABLE) { + g_arTdlsLink[prStaRec->ucTdlsIndex] = 0; + } + + if (TdlsDataFrameSend_TearDown( + prAdapter, prStaRec, prCmd->aucPeer, + prCmd->ucActionCode, prCmd->ucDialogToken, + prCmd->u2StatusCode, (u8 *)(prCmd->aucSecBuf), + prCmd->u4SecBufLen) != TDLS_STATUS_SUCCESS) { + return -1; + } + break; + + default: + + return -EINVAL; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to hadel TDLS link mgt from nl80211. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] + * \param[in] + * \param[in] buf includes RSN IE + FT IE + Lifetimeout IE + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +u32 TdlsexLinkOper(P_ADAPTER_T prAdapter, void *pvSetBuffer, u32 u4SetBufferLen, + u32 *pu4SetInfoLen) +{ + /* from supplicant -- wpa_supplicant_tdls_peer_addset() */ + u16 i; + STA_RECORD_T *prStaRec; + + TDLS_CMD_LINK_OPER_T *prCmd; + + prCmd = (TDLS_CMD_LINK_OPER_T *)pvSetBuffer; + + switch (prCmd->oper) { + case TDLS_ENABLE_LINK: + + for (i = 0; i < MAXNUM_TDLS_PEER; i++) { + if (!g_arTdlsLink[i]) { + g_arTdlsLink[i] = 1; + prStaRec = cnmGetTdlsPeerByAddress( + prAdapter, + prAdapter->prAisBssInfo->ucBssIndex, + prCmd->aucPeerMac); + prStaRec->ucTdlsIndex = i; + break; + } + } + + break; + + case TDLS_DISABLE_LINK: + + prStaRec = cnmGetTdlsPeerByAddress( + prAdapter, prAdapter->prAisBssInfo->ucBssIndex, + prCmd->aucPeerMac); + + g_arTdlsLink[prStaRec->ucTdlsIndex] = 0; + if (IS_DLS_STA(prStaRec)) { + cnmStaRecFree(prAdapter, prStaRec); + } + + break; + + default: + return 0; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to append general IEs. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] + * + * \retval append length + */ +/*----------------------------------------------------------------------------*/ +u32 TdlsFrameGeneralIeAppend(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, + u8 *pPkt) +{ + GLUE_INFO_T *prGlueInfo; + BSS_INFO_T *prBssInfo; + PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; + u32 u4NonHTPhyType; + u16 u2SupportedRateSet; + u8 aucAllSupportedRates[RATE_NUM_SW] = { 0 }; /* 6628 RATE_NUM -> 6630 + * RATE_NUM_SW */ + u8 ucAllSupportedRatesLen; + u8 ucSupRatesLen; + u8 ucExtSupRatesLen; + u32 u4PktLen, u4IeLen; + + /* init */ + prGlueInfo = (GLUE_INFO_T *)prAdapter->prGlueInfo; + prBssInfo = prAdapter->prAisBssInfo; /* AIS only */ + + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + u4PktLen = 0; + + /* 3. Frame Formation - (5) Supported Rates element */ + /* use all sup rate we can support */ + u4NonHTPhyType = prStaRec->ucNonHTBasicPhyType; + u2SupportedRateSet = + rNonHTPhyAttributes[u4NonHTPhyType].u2SupportedRateSet; + rateGetDataRatesFromRateSet(u2SupportedRateSet, 0, aucAllSupportedRates, + &ucAllSupportedRatesLen); + + ucSupRatesLen = ((ucAllSupportedRatesLen > ELEM_MAX_LEN_SUP_RATES) ? + ELEM_MAX_LEN_SUP_RATES : + ucAllSupportedRatesLen); + + ucExtSupRatesLen = ucAllSupportedRatesLen - ucSupRatesLen; + + if (ucSupRatesLen) { + SUP_RATES_IE(pPkt)->ucId = ELEM_ID_SUP_RATES; + SUP_RATES_IE(pPkt)->ucLength = ucSupRatesLen; + kalMemCopy(SUP_RATES_IE(pPkt)->aucSupportedRates, + aucAllSupportedRates, ucSupRatesLen); + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } + + /* 3. Frame Formation - (7) Extended sup rates element */ + if (ucExtSupRatesLen) { + EXT_SUP_RATES_IE(pPkt)->ucId = ELEM_ID_EXTENDED_SUP_RATES; + EXT_SUP_RATES_IE(pPkt)->ucLength = ucExtSupRatesLen; + + kalMemCopy(EXT_SUP_RATES_IE(pPkt)->aucExtSupportedRates, + &aucAllSupportedRates[ucSupRatesLen], + ucExtSupRatesLen); + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } + + /* 3. Frame Formation - (8) Supported channels element */ + SUPPORTED_CHANNELS_IE(pPkt)->ucId = ELEM_ID_SUP_CHS; + SUPPORTED_CHANNELS_IE(pPkt)->ucLength = 2; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[0] = 1; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[1] = 13; + + if (prAdapter->fgEnable5GBand == true) { + SUPPORTED_CHANNELS_IE(pPkt)->ucLength = 10; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[2] = 36; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[3] = 4; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[4] = 52; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[5] = 4; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[6] = 149; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[7] = 4; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[8] = 165; + SUPPORTED_CHANNELS_IE(pPkt)->ucChannelNum[9] = 1; + } + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + + return u4PktLen; +} + +/******************************************************************************* + * P U B L I C F U N C T I O N S + ******************************************************************************* + */ + +/*! + * \brief This routine is called to transmit a TDLS data frame. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] + * \param[in] + * \param[in] buf includes RSN IE + FT IE + Lifetimeout IE + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +TdlsDataFrameSend_TearDown(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, + u8 *pPeerMac, u8 ucActionCode, u8 ucDialogToken, + u16 u2StatusCode, u8 *pAppendIe, u32 AppendIeLen) +{ + GLUE_INFO_T *prGlueInfo; + BSS_INFO_T *prBssInfo; + PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; + struct sk_buff *prMsduInfo; + u8 *pPkt; + u32 u4PktLen, u4IeLen; + u16 ReasonCode; + + /* allocate/init packet */ + prGlueInfo = (GLUE_INFO_T *)prAdapter->prGlueInfo; + prBssInfo = prAdapter->prAisBssInfo; /* AIS only */ + + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + u4PktLen = 0; + + prMsduInfo = kalPacketAlloc(prGlueInfo, 512, &pPkt); + if (prMsduInfo == NULL) { + return TDLS_STATUS_RESOURCES; + } + + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + kalPacketFree(prGlueInfo, prMsduInfo); + return TDLS_STATUS_FAIL; + } + + /* make up frame content */ + /* 1. 802.3 header */ + kalMemCopy(pPkt, pPeerMac, TDLS_FME_MAC_ADDR_LEN); + pPkt += TDLS_FME_MAC_ADDR_LEN; + kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); + pPkt += TDLS_FME_MAC_ADDR_LEN; + *(u16 *)pPkt = htons(TDLS_FRM_PROT_TYPE); + pPkt += 2; + u4PktLen += TDLS_FME_MAC_ADDR_LEN * 2 + 2; + + /* 2. payload type */ + *pPkt = TDLS_FRM_PAYLOAD_TYPE; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - (1) Category */ + *pPkt = TDLS_FRM_CATEGORY; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - (2) Action */ + *pPkt = ucActionCode; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - status code */ + + ReasonCode = u2StatusCode; + + kalMemCopy(pPkt, &ReasonCode, 2); + pPkt = pPkt + 2; + u4PktLen = u4PktLen + 2; + + if (pAppendIe != NULL) { + if ((ucActionCode != TDLS_FRM_ACTION_TEARDOWN) || + ((ucActionCode == TDLS_FRM_ACTION_TEARDOWN) && + (prStaRec != NULL))) { + kalMemCopy(pPkt, pAppendIe, AppendIeLen); + LR_TDLS_FME_FIELD_FILL(AppendIeLen); + } + } + + /* 7. Append Supported Operating Classes IE */ + if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { + /* Note: if we do not put the IE, Marvell STA will decline our + * TDLS setup request */ + u4IeLen = rlmDomainSupOperatingClassIeFill(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + } + + /* 3. Frame Formation - (16) Link identifier element */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18; + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, + 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, + prAdapter->rMyMacAddr, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, pPeerMac, 6); + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + + /* 5. Update packet length */ + prMsduInfo->len = u4PktLen; + + /* if(u2StatusCode == UNREACH_ABLE ){ */ + /* g_arTdlsLink[prStaRec->ucTdlsIndex] = false; */ + /* } */ + + /* 5. send the data frame */ + wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); + + return TDLS_STATUS_SUCCESS; +} + +/*! + * \brief This routine is called to transmit a TDLS data frame. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] + * \param[in] + * \param[in] buf includes RSN IE + FT IE + Lifetimeout IE + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS /* TDLS_STATUS */ +TdlsDataFrameSend_SETUP_REQ(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, + u8 *pPeerMac, u8 ucActionCode, u8 ucDialogToken, + u16 u2StatusCode, u8 *pAppendIe, u32 AppendIeLen) +{ + GLUE_INFO_T *prGlueInfo; + BSS_INFO_T *prBssInfo; + PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; + struct sk_buff *prMsduInfo; + u8 *pPkt; + u32 u4PktLen, u4IeLen; + u8 fg40mAllowed; + u16 u2CapInfo; + + /* allocate/init packet */ + prGlueInfo = (GLUE_INFO_T *)prAdapter->prGlueInfo; + prBssInfo = prAdapter->prAisBssInfo; /* AIS only */ + + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + u4PktLen = 0; + + prMsduInfo = kalPacketAlloc(prGlueInfo, 512, &pPkt); + if (prMsduInfo == NULL) { + return TDLS_STATUS_RESOURCES; + } + + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + kalPacketFree(prGlueInfo, prMsduInfo); + return TDLS_STATUS_FAIL; + } + + /* make up frame content */ + /* 1. 802.3 header */ + kalMemCopy(pPkt, pPeerMac, TDLS_FME_MAC_ADDR_LEN); + pPkt += TDLS_FME_MAC_ADDR_LEN; + kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); + pPkt += TDLS_FME_MAC_ADDR_LEN; + *(u16 *)pPkt = htons(TDLS_FRM_PROT_TYPE); + pPkt += 2; + u4PktLen += TDLS_FME_MAC_ADDR_LEN * 2 + 2; + + /* 2. payload type */ + *pPkt = TDLS_FRM_PAYLOAD_TYPE; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - (1) Category */ + *pPkt = TDLS_FRM_CATEGORY; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - (2) Action */ + *pPkt = ucActionCode; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - (3) Dialog token */ + *pPkt = ucDialogToken; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - (4) Capability */ + u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec); + WLAN_SET_FIELD_16(pPkt, u2CapInfo); + pPkt = pPkt + 2; + u4PktLen = u4PktLen + 2; + + /* 4. Append general IEs */ + u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + + /* 4. Append extra IEs */ + kalMemCopy(pPkt, pAppendIe, AppendIeLen); + pPkt += AppendIeLen; + u4PktLen += AppendIeLen; + + /* 3. Frame Formation - (10) Extended capabilities element */ + EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; + EXT_CAP_IE(pPkt)->ucLength = 5; + /* 0320 !! */ + EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ + EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ + EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ + EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0xFF; /* bit32 ~ bit39 */ + + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); + EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); + + /* EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; */ /* bit24 ~ bit31 */ + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + + /* HT capability IE append 0122 */ + HT_CAP_IE(pPkt)->ucId = ELEM_ID_HT_CAP; + HT_CAP_IE(pPkt)->ucLength = 26; + + /* 3. Frame Formation - (14) HT capabilities element */ + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11N)) { + /* TODO: prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode */ + if (cnmBss40mBwPermitted(prAdapter, prBssInfo->ucBssIndex)) { + fg40mAllowed = true; + }else{ + fg40mAllowed = false; + } + + /* Add HT IE */ /* try to reuse p2p path */ + u4IeLen = rlmFillHtCapIEByAdapter(prAdapter, prBssInfo, pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + /* 0320 !! check newest driver !!! */ + } + /* check */ + +#if CFG_SUPPORT_802_11W + /* 3. Frame Formation - (12) Timeout interval element (TPK Key Lifetime) + */ + TIMEOUT_INTERVAL_IE(pPkt)->ucId = ELEM_ID_TIMEOUT_INTERVAL; + TIMEOUT_INTERVAL_IE(pPkt)->ucLength = 5; + + TIMEOUT_INTERVAL_IE(pPkt)->ucType = + 2; /* IE_TIMEOUT_INTERVAL_TYPE_KEY_LIFETIME; + */ + TIMEOUT_INTERVAL_IE(pPkt)->u4Value = + TDLS_KEY_TIMEOUT_INTERVAL; /* htonl(prCmd->u4Timeout); + */ + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; +#endif + + if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { + /* + * bit0 = 1: The Information Request field is used to indicate + * that a transmitting STA is requesting the recipient to + * transmit a 20/40 BSS Coexistence Management frame with the + * transmitting STA as the recipient. bit1 = 0: The Forty MHz + * Intolerant field is set to 1 to prohibit an AP that receives + * this information or reports of this information from + * operating a 20/40 MHz BSS. + * bit2 = 0: The 20 MHz BSS Width Request field is set to 1 to + * prohibit a receiving AP from operating its BSS as a 20/40 MHz + * BSS. + */ + BSS_20_40_COEXIST_IE(pPkt)->ucId = + ELEM_ID_20_40_BSS_COEXISTENCE; + BSS_20_40_COEXIST_IE(pPkt)->ucLength = 1; + BSS_20_40_COEXIST_IE(pPkt)->ucData = 0x01; + LR_TDLS_FME_FIELD_FILL(3); + } + + if (pAppendIe != NULL) { + kalMemCopy(pPkt, pAppendIe, AppendIeLen); + LR_TDLS_FME_FIELD_FILL(AppendIeLen); + } + + /* 7. Append Supported Operating Classes IE */ + if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { + /* Note: if we do not put the IE, Marvell STA will decline our + * TDLS setup request */ + u4IeLen = rlmDomainSupOperatingClassIeFill(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + } + + /* 3. Frame Formation - (16) Link identifier element */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18; + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, + 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, + prAdapter->rMyMacAddr, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, pPeerMac, 6); + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + + /* 3. Frame Formation - (17) WMM Information element */ + + /* HT WMM IE append */ + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) { + /* Add WMM IE */ /* try to reuse p2p path */ + u4IeLen = mqmGenerateWmmInfoIEByStaRec(prAdapter, prBssInfo, + prStaRec, pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) { + u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, prBssInfo, + pPkt); + + LR_TDLS_FME_FIELD_FILL(u4IeLen); + } +#if CFG_SUPPORT_802_11AC + if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AC) { + /* Add VHT IE */ /* try to reuse p2p path */ + u4IeLen = rlmFillVhtCapIEByAdapter(prAdapter, prBssInfo, pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } +#endif + + /* 5. Update packet length */ + prMsduInfo->len = u4PktLen; + + DBGLOG(TDLS, INFO, "\n\n\n wlanHardStartXmit\n\n\n"); + + /* 5. send the data frame */ + wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); + /* wlanTx ??? */ + return TDLS_STATUS_SUCCESS; +} + +WLAN_STATUS +TdlsDataFrameSend_SETUP_RSP(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, + u8 *pPeerMac, u8 ucActionCode, u8 ucDialogToken, + u16 u2StatusCode, u8 *pAppendIe, u32 AppendIeLen) +{ + GLUE_INFO_T *prGlueInfo; + BSS_INFO_T *prBssInfo; + PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; + struct sk_buff *prMsduInfo; + u8 *pPkt; + u32 u4PktLen, u4IeLen; + u16 u2CapInfo; + u16 StatusCode; + u8 fg40mAllowed; + + /* allocate/init packet */ + prGlueInfo = (GLUE_INFO_T *)prAdapter->prGlueInfo; + prBssInfo = prAdapter->prAisBssInfo; /* AIS only */ + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + u4PktLen = 0; + + prMsduInfo = kalPacketAlloc(prGlueInfo, 512, &pPkt); + if (prMsduInfo == NULL) { + return TDLS_STATUS_RESOURCES; + } + + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + kalPacketFree(prGlueInfo, prMsduInfo); + return TDLS_STATUS_FAIL; + } + + /* make up frame content */ + /* 1. 802.3 header */ + kalMemCopy(pPkt, pPeerMac, TDLS_FME_MAC_ADDR_LEN); + pPkt += TDLS_FME_MAC_ADDR_LEN; + kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); + pPkt += TDLS_FME_MAC_ADDR_LEN; + *(u16 *)pPkt = htons(TDLS_FRM_PROT_TYPE); + pPkt += 2; + u4PktLen += TDLS_FME_MAC_ADDR_LEN * 2 + 2; + + /* 2. payload type */ + *pPkt = TDLS_FRM_PAYLOAD_TYPE; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - (1) Category */ + *pPkt = TDLS_FRM_CATEGORY; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - (2) Action */ + *pPkt = ucActionCode; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - status code */ + StatusCode = u2StatusCode; + kalMemCopy(pPkt, &StatusCode, 2); + pPkt = pPkt + 2; + u4PktLen = u4PktLen + 2; + + /* 3. Frame Formation - (3) Dialog token */ + *pPkt = ucDialogToken; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - (4) Capability */ + u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec); + WLAN_SET_FIELD_16(pPkt, u2CapInfo); + pPkt = pPkt + 2; + u4PktLen = u4PktLen + 2; + + /* 4. Append general IEs */ + u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + + /* 4. Append extra IEs */ + kalMemCopy(pPkt, pAppendIe, AppendIeLen); + pPkt += AppendIeLen; + u4PktLen += AppendIeLen; + + /* 3. Frame Formation - (10) Extended capabilities element */ + EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; + EXT_CAP_IE(pPkt)->ucLength = 5; + + EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ + EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ + EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ + EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0xFF; /* bit32 ~ bit39 */ + + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); + + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); + EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); + /* EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; */ /* bit24 ~ bit31 */ + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + + /* HT capability IE append */ + HT_CAP_IE(pPkt)->ucId = ELEM_ID_HT_CAP; + HT_CAP_IE(pPkt)->ucLength = 26; + + /* 3. Frame Formation - (14) HT capabilities element */ + if ((prAdapter->rWifiVar.ucAvailablePhyTypeSet & + PHY_TYPE_SET_802_11N)) { + /* TODO: prAdapter->rWifiVar.rConnSettings.uc5GBandwidthMode */ + if (cnmBss40mBwPermitted(prAdapter, prBssInfo->ucBssIndex)) { + fg40mAllowed = true; + }else{ + fg40mAllowed = false; + } + + /* Add HT IE */ /* try to reuse p2p path */ + u4IeLen = rlmFillHtCapIEByAdapter(prAdapter, prBssInfo, pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } + +#if CFG_SUPPORT_802_11W + /* 3. Frame Formation - (12) Timeout interval element (TPK Key Lifetime) + */ + TIMEOUT_INTERVAL_IE(pPkt)->ucId = ELEM_ID_TIMEOUT_INTERVAL; + TIMEOUT_INTERVAL_IE(pPkt)->ucLength = 5; + TIMEOUT_INTERVAL_IE(pPkt)->ucType = + 2; /* IE_TIMEOUT_INTERVAL_TYPE_KEY_LIFETIME; + */ + TIMEOUT_INTERVAL_IE(pPkt)->u4Value = + TDLS_KEY_TIMEOUT_INTERVAL; /* htonl(prCmd->u4Timeout); + */ + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; +#endif + + if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { + /* + * bit0 = 1: The Information Request field is used to indicate + * that a transmitting STA is requesting the recipient to + * transmit a 20/40 BSS Coexistence Management frame with the + * transmitting STA as the recipient. bit1 = 0: The Forty MHz + * Intolerant field is set to 1 to prohibit an AP that receives + * this information or reports of this information from + * operating a 20/40 MHz BSS. + * bit2 = 0: The 20 MHz BSS Width Request field is set to 1 to + * prohibit a receiving AP from operating its BSS as a 20/40 MHz + * BSS. + */ + BSS_20_40_COEXIST_IE(pPkt)->ucId = + ELEM_ID_20_40_BSS_COEXISTENCE; + BSS_20_40_COEXIST_IE(pPkt)->ucLength = 1; + BSS_20_40_COEXIST_IE(pPkt)->ucData = 0x01; + LR_TDLS_FME_FIELD_FILL(3); + } + + if (pAppendIe != NULL) { + if ((ucActionCode != TDLS_FRM_ACTION_TEARDOWN) || + ((ucActionCode == TDLS_FRM_ACTION_TEARDOWN))) { + kalMemCopy(pPkt, pAppendIe, AppendIeLen); + LR_TDLS_FME_FIELD_FILL(AppendIeLen); + } + } + + /* 7. Append Supported Operating Classes IE */ + if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { + /* Note: if we do not put the IE, Marvell STA will decline our + * TDLS setup request */ + u4IeLen = rlmDomainSupOperatingClassIeFill(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + } + + /* 3. Frame Formation - (16) Link identifier element */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18; + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, + 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, pPeerMac, + 6); /* prAdapter->rMyMacAddr */ + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, + prAdapter->rMyMacAddr, 6); /* pPeerMac */ + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + + /* HT WMM IE append */ + /* HT WMM IE append */ + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) { + /* Add WMM IE */ /* try to reuse p2p path */ + u4IeLen = mqmGenerateWmmInfoIEByStaRec(prAdapter, prBssInfo, + prStaRec, pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) { + u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, prBssInfo, + pPkt); + + LR_TDLS_FME_FIELD_FILL(u4IeLen); + } +#if CFG_SUPPORT_802_11AC + if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AC) { + /* Add VHT IE */ /* try to reuse p2p path */ + u4IeLen = rlmFillVhtCapIEByAdapter(prAdapter, prBssInfo, pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } +#endif + + /* 5. Update packet length */ + prMsduInfo->len = u4PktLen; + + /* 5. send the data frame */ + wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); + + return TDLS_STATUS_SUCCESS; +} + +WLAN_STATUS +TdlsDataFrameSend_CONFIRM(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, + u8 *pPeerMac, u8 ucActionCode, u8 ucDialogToken, + u16 u2StatusCode, u8 *pAppendIe, u32 AppendIeLen) +{ + GLUE_INFO_T *prGlueInfo; + BSS_INFO_T *prBssInfo; + PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; + struct sk_buff *prMsduInfo; + u8 *pPkt; + u32 u4PktLen, u4IeLen; + u16 StatusCode; + + /* allocate/init packet */ + prGlueInfo = (GLUE_INFO_T *)prAdapter->prGlueInfo; + prBssInfo = prAdapter->prAisBssInfo; /* AIS only */ + + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + u4PktLen = 0; + + prMsduInfo = kalPacketAlloc(prGlueInfo, 512, &pPkt); + if (prMsduInfo == NULL) { + return TDLS_STATUS_RESOURCES; + } + + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + kalPacketFree(prGlueInfo, prMsduInfo); + return TDLS_STATUS_FAIL; + } + + /* make up frame content */ + /* 1. 802.3 header */ + kalMemCopy(pPkt, pPeerMac, TDLS_FME_MAC_ADDR_LEN); + pPkt += TDLS_FME_MAC_ADDR_LEN; + kalMemCopy(pPkt, prAdapter->rMyMacAddr, TDLS_FME_MAC_ADDR_LEN); + pPkt += TDLS_FME_MAC_ADDR_LEN; + *(u16 *)pPkt = htons(TDLS_FRM_PROT_TYPE); + pPkt += 2; + u4PktLen += TDLS_FME_MAC_ADDR_LEN * 2 + 2; + + /* 2. payload type */ + *pPkt = TDLS_FRM_PAYLOAD_TYPE; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - (1) Category */ + *pPkt = TDLS_FRM_CATEGORY; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - (2) Action */ + *pPkt = ucActionCode; + pPkt++; + u4PktLen++; + + /* 3. Frame Formation - status code */ + + StatusCode = u2StatusCode; /* 0; //u2StatusCode; //ahiu 0224 */ + kalMemCopy(pPkt, &StatusCode, 2); + pPkt = pPkt + 2; + u4PktLen = u4PktLen + 2; + + /* 3. Frame Formation - (3) Dialog token */ + *pPkt = ucDialogToken; + pPkt++; + u4PktLen++; + + /* 4. Append extra IEs */ + kalMemCopy(pPkt, pAppendIe, AppendIeLen); + pPkt += AppendIeLen; + u4PktLen += AppendIeLen; + +#if CFG_SUPPORT_802_11W + /* 3. Frame Formation - (12) Timeout interval element (TPK Key Lifetime) + */ + TIMEOUT_INTERVAL_IE(pPkt)->ucId = ELEM_ID_TIMEOUT_INTERVAL; + TIMEOUT_INTERVAL_IE(pPkt)->ucLength = 5; + + TIMEOUT_INTERVAL_IE(pPkt)->ucType = 2; + TIMEOUT_INTERVAL_IE(pPkt)->u4Value = + TDLS_KEY_TIMEOUT_INTERVAL; /* htonl(prCmd->u4Timeout); + */ + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; +#endif + + if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { + /* + * bit0 = 1: The Information Request field is used to indicate + * that a transmitting STA is requesting the recipient to + * transmit a 20/40 BSS Coexistence Management frame with the + * transmitting STA as the recipient. bit1 = 0: The Forty MHz + * Intolerant field is set to 1 to prohibit an AP that receives + * this information or reports of this information from + * operating a 20/40 MHz BSS. + * bit2 = 0: The 20 MHz BSS Width Request field is set to 1 to + * prohibit a receiving AP from operating its BSS as a 20/40 MHz + * BSS. + */ + BSS_20_40_COEXIST_IE(pPkt)->ucId = + ELEM_ID_20_40_BSS_COEXISTENCE; + BSS_20_40_COEXIST_IE(pPkt)->ucLength = 1; + BSS_20_40_COEXIST_IE(pPkt)->ucData = 0x01; + LR_TDLS_FME_FIELD_FILL(3); + } + + if (pAppendIe != NULL) { + if ((ucActionCode != TDLS_FRM_ACTION_TEARDOWN) || + ((ucActionCode == TDLS_FRM_ACTION_TEARDOWN) && + (prStaRec != NULL))) { + kalMemCopy(pPkt, pAppendIe, AppendIeLen); + LR_TDLS_FME_FIELD_FILL(AppendIeLen); + } + } + + /* 7. Append Supported Operating Classes IE */ + if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { + /* Note: if we do not put the IE, Marvell STA will decline our + * TDLS setup request */ + u4IeLen = rlmDomainSupOperatingClassIeFill(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + } + + /* 3. Frame Formation - (16) Link identifier element */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18; + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, + 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, + prAdapter->rMyMacAddr, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, pPeerMac, 6); + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + + /* HT WMM IE append */ + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) { + /* Add WMM IE */ /* try to reuse p2p path */ + u4IeLen = mqmGenerateWmmInfoIEByStaRec(prAdapter, prBssInfo, + prStaRec, pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) { + u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, prBssInfo, + pPkt); + + LR_TDLS_FME_FIELD_FILL(u4IeLen); + } + + /* 5. Update packet length */ + prMsduInfo->len = u4PktLen; + + /* 5. send the data frame */ + wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); + + return TDLS_STATUS_SUCCESS; +} + +/* + * \brief This routine is called to transmit a TDLS data frame. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] + * \param[in] + * \param[in] buf includes RSN IE + FT IE + Lifetimeout IE + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS /* TDLS_STATUS */ +TdlsDataFrameSend_DISCOVERY_REQ(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, + u8 *pPeerMac, u8 ucActionCode, u8 ucDialogToken, + u16 u2StatusCode, u8 *pAppendIe, + u32 AppendIeLen) +{ + GLUE_INFO_T *prGlueInfo; + BSS_INFO_T *prBssInfo; + PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; + struct sk_buff *prMsduInfo; + MSDU_INFO_T *prMsduInfoMgmt; + u8 *pPkt, *pucInitiator, *pucResponder; + u32 u4PktLen, u4IeLen; + u16 u2CapInfo; + + prGlueInfo = (GLUE_INFO_T *)prAdapter->prGlueInfo; + + if (prStaRec != NULL) { + prBssInfo = prAdapter->prAisBssInfo; /* AIS only */ + }else { + return TDLS_STATUS_FAIL; + } + + /* allocate/init packet */ + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + u4PktLen = 0; + prMsduInfo = NULL; + prMsduInfoMgmt = NULL; + + /* make up frame content */ + if (ucActionCode != TDLS_FRM_ACTION_DISCOVERY_RSP) { + /* TODO: reduce 1600 to correct size */ + prMsduInfo = kalPacketAlloc(prGlueInfo, 512, &pPkt); + if (prMsduInfo == NULL) { + return TDLS_STATUS_RESOURCES; + } + + prMsduInfo->dev = prGlueInfo->prDevHandler; + if (prMsduInfo->dev == NULL) { + kalPacketFree(prGlueInfo, prMsduInfo); + return TDLS_STATUS_FAIL; + } + + /* 1. 802.3 header */ + kalMemCopy(pPkt, pPeerMac, TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(pPkt, prBssInfo->aucOwnMacAddr, + TDLS_FME_MAC_ADDR_LEN); + LR_TDLS_FME_FIELD_FILL(TDLS_FME_MAC_ADDR_LEN); + *(u16 *)pPkt = htons(TDLS_FRM_PROT_TYPE); + LR_TDLS_FME_FIELD_FILL(2); + + /* 2. payload type */ + *pPkt = TDLS_FRM_PAYLOAD_TYPE; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (1) Category */ + *pPkt = TDLS_FRM_CATEGORY; + LR_TDLS_FME_FIELD_FILL(1); + } else { + WLAN_MAC_HEADER_T *prHdr; + + prMsduInfoMgmt = (MSDU_INFO_T *)cnmMgtPktAlloc( + prAdapter, PUBLIC_ACTION_MAX_LEN); + if (prMsduInfoMgmt == NULL) { + return TDLS_STATUS_RESOURCES; + } + + pPkt = (u8 *)prMsduInfoMgmt->prPacket; + prHdr = (WLAN_MAC_HEADER_T *)pPkt; + + /* 1. 802.11 header */ + prHdr->u2FrameCtrl = MAC_FRAME_ACTION; + prHdr->u2DurationID = 0; + kalMemCopy(prHdr->aucAddr1, pPeerMac, TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(prHdr->aucAddr2, prBssInfo->aucOwnMacAddr, + TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(prHdr->aucAddr3, prBssInfo->aucBSSID, + TDLS_FME_MAC_ADDR_LEN); + prHdr->u2SeqCtrl = 0; + LR_TDLS_FME_FIELD_FILL(sizeof(WLAN_MAC_HEADER_T)); + + /* Frame Formation - (1) Category */ + *pPkt = CATEGORY_PUBLIC_ACTION; + LR_TDLS_FME_FIELD_FILL(1); + } + + /* 3. Frame Formation - (2) Action */ + *pPkt = ucActionCode; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - Status Code */ + switch (ucActionCode) { + case TDLS_FRM_ACTION_SETUP_RSP: + case TDLS_FRM_ACTION_CONFIRM: + case TDLS_FRM_ACTION_TEARDOWN: + WLAN_SET_FIELD_16(pPkt, u2StatusCode); + LR_TDLS_FME_FIELD_FILL(2); + break; + } + + /* 3. Frame Formation - (3) Dialog token */ + if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { + *pPkt = ucDialogToken; + LR_TDLS_FME_FIELD_FILL(1); + } + + /* Fill elements */ + if (ucActionCode != TDLS_FRM_ACTION_TEARDOWN) { + /* + * Capability + * Support Rates + * Extended Support Rates + * Supported Channels + * HT Capabilities + * WMM Information Element + * Extended Capabilities + * Link Identifier + * RSNIE + * FTIE + * Timeout Interval + */ + + if (ucActionCode != TDLS_FRM_ACTION_CONFIRM && + ucActionCode != TDLS_FRM_ACTION_DISCOVERY_REQ) { + /* 3. Frame Formation - (4) Capability: 0x31 0x04, + * privacy bit will be set */ + u2CapInfo = + assocBuildCapabilityInfo(prAdapter, prStaRec); + WLAN_SET_FIELD_16(pPkt, u2CapInfo); + LR_TDLS_FME_FIELD_FILL(2); + } + + if (ucActionCode != TDLS_FRM_ACTION_CONFIRM) { + /* 4. Append general IEs */ + /* + * TODO check HT: + * prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode + * must be CONFIG_BW_20_40M. + * TODO check HT: HT_CAP_INFO_40M_INTOLERANT must be + * clear if Tdls 20/40 is enabled. + */ + u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, + pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 5. Frame Formation - Extended capabilities element */ + EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; + EXT_CAP_IE(pPkt)->ucLength = 5; + + EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ + * bit7 */ + EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ + * bit15 */ + EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ + * bit23 */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ + * bit31 */ + EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ + * bit39 */ + + /* if (prCmd->ucExCap & TDLS_EX_CAP_PEER_UAPSD) */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); + /* if (prCmd->ucExCap & TDLS_EX_CAP_CHAN_SWITCH) */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); + /* if (prCmd->ucExCap & TDLS_EX_CAP_TDLS) */ + EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + } else { + /* 5. Frame Formation - WMM Information element */ + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) { + /* Add WMM IE */ /* try to reuse p2p path */ + u4IeLen = mqmGenerateWmmInfoIEByStaRec( + prAdapter, prBssInfo, prStaRec, pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } + } + } + + /* 6. Frame Formation - HT Operation element */ + /* u4IeLen = rlmFillHtOpIeBody(prBssInfo, pPkt); */ + /* LR_TDLS_FME_FIELD_FILL(u4IeLen); */ + + /* 7. Frame Formation - Link identifier element */ + /* Note: Link ID sequence must be correct; Or the calculated MIC will be + * error */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18; + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, + 6); + + switch (ucActionCode) { + case TDLS_FRM_ACTION_SETUP_REQ: + case TDLS_FRM_ACTION_CONFIRM: + case TDLS_FRM_ACTION_DISCOVERY_RSP: + default: + /* we are initiator */ + pucInitiator = prBssInfo->aucOwnMacAddr; + pucResponder = pPeerMac; + prStaRec->flgTdlsIsInitiator = true; + break; + + case TDLS_FRM_ACTION_SETUP_RSP: + /* peer is initiator */ + pucInitiator = pPeerMac; + pucResponder = prBssInfo->aucOwnMacAddr; + prStaRec->flgTdlsIsInitiator = false; + break; + + case TDLS_FRM_ACTION_TEARDOWN: + if (prStaRec->flgTdlsIsInitiator == true) { + /* we are initiator */ + pucInitiator = prBssInfo->aucOwnMacAddr; + pucResponder = pPeerMac; + } else { + /* peer is initiator */ + pucInitiator = pPeerMac; + pucResponder = prBssInfo->aucOwnMacAddr; + } + break; + } + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, pucInitiator, 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, pucResponder, 6); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 8. Append security IEs */ + if ((ucActionCode != TDLS_FRM_ACTION_TEARDOWN) && (pAppendIe != NULL)) { + kalMemCopy(pPkt, pAppendIe, AppendIeLen); + LR_TDLS_FME_FIELD_FILL(AppendIeLen); + } + + /* 10. send the data or management frame */ + if (ucActionCode != TDLS_FRM_ACTION_DISCOVERY_RSP) { + /* 9. Update packet length */ + prMsduInfo->len = u4PktLen; + + wlanHardStartXmit(prMsduInfo, prMsduInfo->dev); + } else { + prMsduInfoMgmt->ucPacketType = TX_PACKET_TYPE_MGMT; + prMsduInfoMgmt->ucStaRecIndex = + prBssInfo->prStaRecOfAP->ucIndex; + prMsduInfoMgmt->ucBssIndex = prBssInfo->ucBssIndex; + prMsduInfoMgmt->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfoMgmt->fgIs802_1x = false; + prMsduInfoMgmt->fgIs802_11 = true; + prMsduInfoMgmt->u2FrameLength = u4PktLen; + prMsduInfoMgmt->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfoMgmt->pfTxDoneHandler = NULL; + + /* Send them to HW queue */ + nicTxEnqueueMsdu(prAdapter, prMsduInfoMgmt); + } + + return TDLS_STATUS_SUCCESS; +} + +WLAN_STATUS +TdlsDataFrameSend_DISCOVERY_RSP(ADAPTER_T *prAdapter, STA_RECORD_T *prStaRec, + u8 *pPeerMac, u8 ucActionCode, u8 ucDialogToken, + u16 u2StatusCode, u8 *pAppendIe, + u32 AppendIeLen) +{ + GLUE_INFO_T *prGlueInfo; + BSS_INFO_T *prBssInfo; + PM_PROFILE_SETUP_INFO_T *prPmProfSetupInfo; + struct sk_buff *prMsduInfo; + MSDU_INFO_T *prMsduInfoMgmt; + u8 *pPkt, *pucInitiator, *pucResponder; + u32 u4PktLen, u4IeLen; + u16 u2CapInfo; + WLAN_MAC_HEADER_T *prHdr; + + prGlueInfo = (GLUE_INFO_T *)prAdapter->prGlueInfo; + + /* sanity check */ + if (prStaRec != NULL) { + prBssInfo = prAdapter->prAisBssInfo; /* AIS only */ + }else { + return TDLS_STATUS_FAIL; + } + + /* allocate/init packet */ + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + u4PktLen = 0; + prMsduInfo = NULL; + prMsduInfoMgmt = NULL; + + /* make up frame content */ + prMsduInfoMgmt = + (MSDU_INFO_T *)cnmMgtPktAlloc(prAdapter, PUBLIC_ACTION_MAX_LEN); + if (prMsduInfoMgmt == NULL) { + DBGLOG(TDLS, ERROR, + "cnmMgtPktAlloc for prMsduInfoMgmt failed!\n"); + return TDLS_STATUS_RESOURCES; + } + + pPkt = (u8 *)prMsduInfoMgmt->prPacket; + prHdr = (WLAN_MAC_HEADER_T *)pPkt; + + /* 1. 802.11 header */ + prHdr->u2FrameCtrl = MAC_FRAME_ACTION; + prHdr->u2DurationID = 0; + kalMemCopy(prHdr->aucAddr1, pPeerMac, TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(prHdr->aucAddr2, prBssInfo->aucOwnMacAddr, + TDLS_FME_MAC_ADDR_LEN); + kalMemCopy(prHdr->aucAddr3, prBssInfo->aucBSSID, TDLS_FME_MAC_ADDR_LEN); + prHdr->u2SeqCtrl = 0; + LR_TDLS_FME_FIELD_FILL(sizeof(WLAN_MAC_HEADER_T)); + + /* Frame Formation - (1) Category */ + *pPkt = CATEGORY_PUBLIC_ACTION; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (2) Action */ + *pPkt = ucActionCode; + LR_TDLS_FME_FIELD_FILL(1); + + /* 3. Frame Formation - (3) Dialog token */ + *pPkt = ucDialogToken; + LR_TDLS_FME_FIELD_FILL(1); + + /* Fill elements */ + /* + * Capability + * Support Rates + * Extended Support Rates + * Supported Channels + * HT Capabilities + * WMM Information Element + * Extended Capabilities + * Link Identifier + * RSNIE + * FTIE + * Timeout Interval + */ + /* 3. Frame Formation - (4) Capability: 0x31 0x04, privacy bit will be + * set */ + u2CapInfo = assocBuildCapabilityInfo(prAdapter, prStaRec); + WLAN_SET_FIELD_16(pPkt, u2CapInfo); + LR_TDLS_FME_FIELD_FILL(2); + + /* 4. Append general IEs */ + /* + * TODO check HT: prAdapter->rWifiVar.rConnSettings.uc2G4BandwidthMode + * must be CONFIG_BW_20_40M. + * TODO check HT: HT_CAP_INFO_40M_INTOLERANT must be clear if + * Tdls 20/40 is enabled. + */ + u4IeLen = TdlsFrameGeneralIeAppend(prAdapter, prStaRec, pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 5. Frame Formation - Extended capabilities element */ + EXT_CAP_IE(pPkt)->ucId = ELEM_ID_EXTENDED_CAP; + EXT_CAP_IE(pPkt)->ucLength = 5; + + EXT_CAP_IE(pPkt)->aucCapabilities[0] = 0x00; /* bit0 ~ bit7 */ + EXT_CAP_IE(pPkt)->aucCapabilities[1] = 0x00; /* bit8 ~ bit15 */ + EXT_CAP_IE(pPkt)->aucCapabilities[2] = 0x00; /* bit16 ~ bit23 */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] = 0x00; /* bit24 ~ bit31 */ + EXT_CAP_IE(pPkt)->aucCapabilities[4] = 0x00; /* bit32 ~ bit39 */ + + /* if (prCmd->ucExCap & TDLS_EX_CAP_PEER_UAPSD) */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((28 - 24)); + /* if (prCmd->ucExCap & TDLS_EX_CAP_CHAN_SWITCH) */ + EXT_CAP_IE(pPkt)->aucCapabilities[3] |= BIT((30 - 24)); + /* if (prCmd->ucExCap & TDLS_EX_CAP_TDLS) */ + EXT_CAP_IE(pPkt)->aucCapabilities[4] |= BIT((37 - 32)); + + u4IeLen = IE_SIZE(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 6. Frame Formation - HT Operation element */ + /* u4IeLen = rlmFillHtOpIeBody(prBssInfo, pPkt); */ + /* LR_TDLS_FME_FIELD_FILL(u4IeLen); */ + + /* 7. Frame Formation - Link identifier element */ + /* Note: Link ID sequence must be correct; Or the calculated MIC will be + * error */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18; + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, + 6); + + /* peer is initiator */ + pucInitiator = pPeerMac; + pucResponder = prBssInfo->aucOwnMacAddr; + + if (prStaRec != NULL) { + prStaRec->flgTdlsIsInitiator = false; + } + +#if CFG_SUPPORT_802_11W + /* 3. Frame Formation - (12) Timeout interval element (TPK Key Lifetime) + */ + TIMEOUT_INTERVAL_IE(pPkt)->ucId = ELEM_ID_TIMEOUT_INTERVAL; + TIMEOUT_INTERVAL_IE(pPkt)->ucLength = 5; + TIMEOUT_INTERVAL_IE(pPkt)->ucType = + 2; /* IE_TIMEOUT_INTERVAL_TYPE_KEY_LIFETIME; + */ + TIMEOUT_INTERVAL_IE(pPkt)->u4Value = + TDLS_KEY_TIMEOUT_INTERVAL; /* htonl(prCmd->u4Timeout); + */ + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; +#endif + + /* + * bit0 = 1: The Information Request field is used to indicate that a + * transmitting STA is requesting the recipient to transmit a 20/40 BSS + * Coexistence Management frame with the transmitting STA as the + * recipient. + * bit1 = 0: The Forty MHz Intolerant field is set to 1 to prohibit an + * AP that receives this information or reports of this information from + * operating a 20/40 MHz BSS. + * bit2 = 0: The 20 MHz BSS Width Request field is set to 1 to prohibit + * a receiving AP from operating its BSS as a 20/40 MHz BSS. + */ + BSS_20_40_COEXIST_IE(pPkt)->ucId = ELEM_ID_20_40_BSS_COEXISTENCE; + BSS_20_40_COEXIST_IE(pPkt)->ucLength = 1; + BSS_20_40_COEXIST_IE(pPkt)->ucData = 0x01; + LR_TDLS_FME_FIELD_FILL(3); + + if (pAppendIe != NULL) { + kalMemCopy(pPkt, pAppendIe, AppendIeLen); + LR_TDLS_FME_FIELD_FILL(AppendIeLen); + } + + /* 7. Append Supported Operating Classes IE */ + /* Note: if we do not put the IE, Marvell STA will decline our TDLS + * setup request */ + u4IeLen = rlmDomainSupOperatingClassIeFill(pPkt); + LR_TDLS_FME_FIELD_FILL(u4IeLen); + + /* 3. Frame Formation - (16) Link identifier element */ + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucId = ELEM_ID_LINK_IDENTIFIER; + TDLS_LINK_IDENTIFIER_IE(pPkt)->ucLength = 18; + + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aBSSID, prBssInfo->aucBSSID, + 6); + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aInitiator, pPeerMac, + 6); /* prAdapter->rMyMacAddr */ + kalMemCopy(TDLS_LINK_IDENTIFIER_IE(pPkt)->aResponder, + prAdapter->rMyMacAddr, 6); /* pPeerMac */ + + u4IeLen = IE_SIZE(pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + + /* HT WMM IE append */ + /* HT WMM IE append */ + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) { + /* Add WMM IE */ /* try to reuse p2p path */ + u4IeLen = mqmGenerateWmmInfoIEByStaRec(prAdapter, prBssInfo, + prStaRec, pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucQoS)) { + u4IeLen = mqmGenerateWmmParamIEByParam(prAdapter, prBssInfo, + pPkt); + + LR_TDLS_FME_FIELD_FILL(u4IeLen); + } +#if CFG_SUPPORT_802_11AC + if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_SET_802_11AC) { + /* Add VHT IE */ /* try to reuse p2p path */ + u4IeLen = rlmFillVhtCapIEByAdapter(prAdapter, prBssInfo, pPkt); + pPkt += u4IeLen; + u4PktLen += u4IeLen; + } +#endif + + /* 8. Append security IEs */ + if (pAppendIe != NULL) { + kalMemCopy(pPkt, pAppendIe, AppendIeLen); + LR_TDLS_FME_FIELD_FILL(AppendIeLen); + } + + prMsduInfoMgmt->ucPacketType = TX_PACKET_TYPE_MGMT; + prMsduInfoMgmt->ucStaRecIndex = prBssInfo->prStaRecOfAP->ucIndex; + prMsduInfoMgmt->ucBssIndex = prBssInfo->ucBssIndex; + prMsduInfoMgmt->ucMacHeaderLength = WLAN_MAC_MGMT_HEADER_LEN; + prMsduInfoMgmt->fgIs802_1x = false; + prMsduInfoMgmt->fgIs802_11 = true; + prMsduInfoMgmt->u2FrameLength = u4PktLen; + prMsduInfoMgmt->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfoMgmt->pfTxDoneHandler = NULL; + + /* Send them to HW queue */ + nicTxEnqueueMsdu(prAdapter, prMsduInfoMgmt); + + return TDLS_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to send a command to TDLS module. + * + * \param[in] prGlueInfo Pointer to the Adapter structure + * \param[in] prInBuf A pointer to the command string buffer + * \param[in] u4InBufLen The length of the buffer + * \param[out] None + * + * \retval None + */ +/*----------------------------------------------------------------------------*/ +void TdlsexEventHandle(GLUE_INFO_T *prGlueInfo, u8 *prInBuf, u32 u4InBufLen) +{ + u32 u4EventId; + + DBGLOG(TDLS, INFO, "TdlsexEventHandle\n"); + + /* sanity check */ + if ((prGlueInfo == NULL) || (prInBuf == NULL)) { + return; /* shall not be here */ + + } + /* handle */ + u4EventId = *(u32 *)prInBuf; + u4InBufLen -= 4; + + switch (u4EventId) { + case TDLS_HOST_EVENT_TEAR_DOWN: + DBGLOG(TDLS, INFO, "TDLS_HOST_EVENT_TEAR_DOWN\n"); + TdlsEventTearDown(prGlueInfo, prInBuf + 4, u4InBufLen); + break; + + case TDLS_HOST_EVENT_TX_DONE: + + break; + } +} + +/*----------------------------------------------------------------------------*/ +/*! \brief This routine is called to do tear down. + * + * \param[in] prGlueInfo Pointer to the Adapter structure + * \param[in] prInBuf A pointer to the command string buffer, from u4EventSubId + * \param[in] u4InBufLen The length of the buffer + * \param[out] None + * + * \retval None + * + */ +/*----------------------------------------------------------------------------*/ +void TdlsEventTearDown(GLUE_INFO_T *prGlueInfo, u8 *prInBuf, u32 u4InBufLen) +{ + STA_RECORD_T *prStaRec; + u16 u2ReasonCode; + u32 u4TearDownSubId; + u8 *pMac, aucZeroMac[6]; + + /* init */ + u4TearDownSubId = *(u32 *)prInBuf; + kalMemZero(aucZeroMac, sizeof(aucZeroMac)); + pMac = aucZeroMac; + + prStaRec = cnmGetStaRecByIndex(prGlueInfo->prAdapter, *(prInBuf + 4)); + if (prStaRec != NULL) { + pMac = prStaRec->aucMacAddr; + } + + /* handle */ + + /* sanity check */ + if (prStaRec == NULL) { + return; + } + + if (fgIsPtiTimeoutSkip == true) { + /* skip PTI timeout event */ + if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_TIMEOUT) { + return; + } + } + + if (u4TearDownSubId == TDLS_HOST_EVENT_TD_PTI_TIMEOUT) { + DBGLOG(TDLS, + INFO, + "TDLS_HOST_EVENT_TD_PTI_TIMEOUT TDLS_REASON_CODE_UNSPECIFIED\n"); + u2ReasonCode = TDLS_REASON_CODE_UNSPECIFIED; + + cfg80211_tdls_oper_request( + prGlueInfo->prDevHandler, prStaRec->aucMacAddr, + NL80211_TDLS_TEARDOWN, + WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE, GFP_ATOMIC); + } + + if (u4TearDownSubId == TDLS_HOST_EVENT_TD_AGE_TIMEOUT) { + DBGLOG(TDLS, + INFO, + "TDLS_HOST_EVENT_TD_AGE_TIMEOUT TDLS_REASON_CODE_UNREACHABLE\n"); + u2ReasonCode = TDLS_REASON_CODE_UNREACHABLE; + + cfg80211_tdls_oper_request( + prGlueInfo->prDevHandler, prStaRec->aucMacAddr, + NL80211_TDLS_TEARDOWN, + WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE, GFP_ATOMIC); + } + + /* + * modify the value when supplicant sends tear down to us in + * TdlsexMgmtCtrl(), not here we want to send tear down to AP (not peer) + * if PTI timeout or AGE timeout. + */ + + /* 16 Nov 21:49 2012 + * http://permalink.gmane.org/gmane.linux.kernel.wireless.general/99712 + */ +} + +void TdlsBssExtCapParse(P_STA_RECORD_T prStaRec, u8 *pucIE) +{ + u8 *pucIeExtCap; + + /* sanity check */ + if ((prStaRec == NULL) || (pucIE == NULL)) { + return; + } + + if (IE_ID(pucIE) != ELEM_ID_EXTENDED_CAP) { + return; + } + + /* + * from bit0 ~ + * bit 38: TDLS Prohibited + * The TDLS Prohibited subfield indicates whether the use of TDLS is + * prohibited. The field is set to 1 to indicate that TDLS is prohibited + * and to 0 to indicate that TDLS is allowed. + */ + if (IE_LEN(pucIE) < 5) { + return; /* we need 39/8 = 5 bytes */ + + } + /* init */ + prStaRec->fgTdlsIsProhibited = false; + prStaRec->fgTdlsIsChSwProhibited = false; + + /* parse */ + pucIeExtCap = pucIE + 2; + pucIeExtCap += 4; /* shift to the byte we care about */ + + if ((*pucIeExtCap) & BIT(38 - 32)) { + prStaRec->fgTdlsIsProhibited = true; + } + if ((*pucIeExtCap) & BIT(39 - 32)) { + prStaRec->fgTdlsIsChSwProhibited = true; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Generate CMD_ID_SET_TDLS_CH_SW command + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +TdlsSendChSwControlCmd(P_ADAPTER_T prAdapter, void *pvSetBuffer, + u32 u4SetBufferLen, u32 *pu4SetInfoLen) +{ + CMD_TDLS_CH_SW_T rCmdTdlsChSwCtrl; + + ASSERT(prAdapter); + + /* send command packet for scan */ + kalMemZero(&rCmdTdlsChSwCtrl, sizeof(CMD_TDLS_CH_SW_T)); + + rCmdTdlsChSwCtrl.fgIsTDLSChSwProhibit = + prAdapter->prAisBssInfo->fgTdlsIsChSwProhibited; + + wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_TDLS_CH_SW, true, false, + false, NULL, NULL, sizeof(CMD_TDLS_CH_SW_T), + (u8 *)&rCmdTdlsChSwCtrl, NULL, 0); + return TDLS_STATUS_SUCCESS; +} + +WLAN_STATUS +TdlsTxCtrl(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, u8 fgEnable) +{ + int i; + P_STA_RECORD_T prStaRec; + + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = &prAdapter->arStaRec[i]; + + if (prStaRec->eStaType != STA_TYPE_DLS_PEER) { + continue; + } + + if (prStaRec->fgIsInUse && + prStaRec->ucBssIndex == prBssInfo->ucBssIndex) { + qmSetStaRecTxAllowed(prAdapter, prStaRec, fgEnable); + DBGLOG(TDLS, EVENT, "TDLS STA[%d], TX ctrl=%d\n", i, + fgEnable); + } + } + + return TDLS_STATUS_SUCCESS; +} +#endif + +/* End of tdls.c */ diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/tkip_mic.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/tkip_mic.c new file mode 100644 index 00000000000000..1647862c036de2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/tkip_mic.c @@ -0,0 +1,545 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file tkip_sw.c + * \brief This file include the tkip encrypted / decrypted mic function. + */ +/******************************************************************************* + * Copyright (c) 2003-2004 Inprocomm, Inc. + * + * All rights reserved. Copying, compilation, modification, distribution + * or any other use whatsoever of this material is strictly prohibited + * except in accordance with a Software License Agreement with + * Inprocomm, Inc. + ******************************************************************************* + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define WLAN_MAC_MIC_LEN 8 /* length of TKIP and CCMP MIC field */ + +#define MK16_TKIP(x, y) (((u16)(x) << 8) | (u16)(y)) + +#define LO_8BITS(x) ((x) & 0x00ff) /* obtain low 8-bit from 16-bit value, OK */ +#define HI_8BITS(x) ((x) >> 8) /* obtain high 8-bit from 16-bit value, OK */ + +#define ROTR32(x, y) (((x) >> (y)) | ((x) << (32 - (y)))) +#define ROTL32(x, y) (((x) << (y)) | ((x) >> (32 - (y)))) +#define ROTR16(x, y) (((x) >> (y)) | ((x) << (16 - (y)))) +#define ROTL16(x, y) (((x) << (y)) | ((x) >> (16 - (y)))) + +#define XSWAP32(x) ((((x) & 0xFF00FF00) >> 8) | (((x) & 0x00FF00FF) << 8)) + +/* obtain 16-bit entries SBOX form two 8-bit entries SBOX1 and SBOX2 */ +#define SBOX(x) (tkipSBOX1[LO_8BITS(x)] ^ tkipSBOX2[HI_8BITS(x)]) + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +const u16 tkipSBOX1[256] = { + 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, 0x6050, + 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, 0x8F45, 0x1F9D, + 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, 0x41EC, 0xB367, 0x5FFD, + 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, + 0x6C5A, 0x7E41, 0xF502, 0x834F, 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, + 0xAB73, 0x6253, 0x2A3F, 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, + 0x0A0F, 0x2FB5, 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, + 0xEA9F, 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, + 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, 0xA6F5, + 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, 0xD4BE, 0x8D46, + 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, 0xBB6B, 0xC52A, 0x4FE5, + 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, 0x8ACF, 0xE910, 0x0406, 0xFE81, + 0xA0F0, 0x7844, 0x25BA, 0x4BE3, 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, + 0x21BC, 0x7048, 0xF104, 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, + 0xFD0E, 0xBF6D, 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, + 0x2E39, 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, + 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, 0x8CCA, + 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, 0xDB3B, 0x6456, + 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, 0x9F5D, 0xBD6E, 0x43EF, + 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, 0xD532, 0x8B43, 0x6E59, 0xDAB7, + 0x018C, 0xB164, 0x9CD2, 0x49E0, 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, + 0xF48E, 0x47E9, 0x1018, 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, + 0x73C7, 0x9751, 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, + 0x0F85, 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, + 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, 0xD938, + 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, 0x2DB6, 0x3C22, + 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, 0x038F, 0x59F8, 0x0980, + 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, 0x82C3, 0x29B0, 0x5A77, 0x1E11, + 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A +}; + +const u16 tkipSBOX2[256] = { + 0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491, 0x5060, + 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC, 0x458F, 0x9D1F, + 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB, 0xEC41, 0x67B3, 0xFD5F, + 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B, 0xC275, 0x1CE1, 0xAE3D, 0x6A4C, + 0x5A6C, 0x417E, 0x02F5, 0x4F83, 0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, + 0x73AB, 0x5362, 0x3F2A, 0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, + 0x0F0A, 0xB52F, 0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, + 0x9FEA, 0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B, + 0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713, 0xF5A6, + 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6, 0xBED4, 0x468D, + 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85, 0x6BBB, 0x2AC5, 0xE54F, + 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411, 0xCF8A, 0x10E9, 0x0604, 0x81FE, + 0xF0A0, 0x4478, 0xBA25, 0xE34B, 0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, + 0xBC21, 0x4870, 0x04F1, 0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, + 0x0EFD, 0x6DBF, 0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, + 0x392E, 0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6, + 0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B, 0xCA8C, + 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD, 0x3BDB, 0x5664, + 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8, 0x5D9F, 0x6EBD, 0xEF43, + 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2, 0x32D5, 0x438B, 0x596E, 0xB7DA, + 0x8C01, 0x64B1, 0xD29C, 0xE049, 0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, + 0x8EF4, 0xE947, 0x1810, 0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, + 0xC773, 0x5197, 0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, + 0x850F, 0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C, + 0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927, 0x38D9, + 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733, 0xB62D, 0x223C, + 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5, 0x8F03, 0xF859, 0x8009, + 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0, 0xC382, 0xB029, 0x775A, 0x111E, + 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C +}; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief TKIP Michael block function + * + * \param[in][out] pu4L - pointer to left value + * \param[in][out] pu4PR - pointer to right value + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void tkipMicB(IN OUT u32 *pu4L, IN OUT u32 *pu4R) +{ + ASSERT(pu4L); + ASSERT(pu4R); + + *pu4R = *pu4R ^ ROTL32(*pu4L, 17); /* r <- r ^ (l<<<17) */ + *pu4L = (*pu4L + *pu4R); /* l <- (l+r) mod 2^32 */ + *pu4R = *pu4R ^ XSWAP32(*pu4L); /* r <- r ^ XSWAP(l) */ + *pu4L = (*pu4L + *pu4R); /* l <- (l+r) mod 2^32 */ + *pu4R = *pu4R ^ ROTL32(*pu4L, 3); /* r <- r ^ (l<<<3) */ + *pu4L = (*pu4L + *pu4R); /* l <- (l+r) mod 2^32 */ + *pu4R = *pu4R ^ ROTR32(*pu4L, 2); /* r <- r ^ (l>>>2) */ + *pu4L = (*pu4L + *pu4R); /* l <- (l+r) mod 2^32 */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief TKIP Michael generation function + * + * \param[in] pucMickey Pointer to MIC key + * \param[in] pucData Pointer to message + * \param[in] u4DataLen Message length, in byte(s) + * \param[in] pucSa Pointer to source address SA + * \param[in] pucDa Pointer to destination address DA + * \param[in] ucPriority Priority of IEEE 802.11 traffic class + * \param[out] pucMic Pointer to 64-bit MIC + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void tkipMicGen(IN u8 *pucMickey, IN u8 *pucData, IN u32 u4DataLen, + IN u8 *pucSa, IN u8 *pucDa, IN u8 ucPriority, OUT u8 *pucMic) +{ + u32 i; + u32 l, r; + u32 au4Msg[3]; + + ASSERT(pucMickey); + ASSERT(pucData); + ASSERT(pucSa); + ASSERT(pucDa); + ASSERT(pucMic); + + WLAN_GET_FIELD_32(pucMickey, &l); + WLAN_GET_FIELD_32(pucMickey + 4, &r); + + /* Michael message processing for DA and SA. */ + WLAN_GET_FIELD_32(pucDa, &au4Msg[0]); + au4Msg[1] = ((u32)pucDa[4]) | ((u32)pucDa[5] << 8) | + ((u32)pucSa[0] << 16) | ((u32)pucSa[1] << 24); + WLAN_GET_FIELD_32(pucSa + 2, &au4Msg[2]); + + for (i = 0; i < 3; i++) { + l = l ^ au4Msg[i]; + tkipMicB(&l, &r); + } + + /* Michael message processing for priority. */ + au4Msg[0] = (u32)ucPriority; + + l = l ^ au4Msg[0]; + tkipMicB(&l, &r); + + /* Michael message processing for MSDU data playload except the last + * octets which cannot be partitioned into a 32-bit word. + */ + for (i = 0; i < (u32)u4DataLen / 4; i++) { + WLAN_GET_FIELD_32(pucData + i * 4, &au4Msg[0]); + l = l ^ au4Msg[0]; + tkipMicB(&l, &r); + } + + /* Michael message processing for the last uncomplete octets, if + * present, and the padding. + */ + switch (u4DataLen & 3) { + case 1: + au4Msg[0] = ((u32)pucData[u4DataLen - 1]) | 0x00005A00; + break; + + case 2: + au4Msg[0] = ((u32)pucData[u4DataLen - 2]) | + ((u32)pucData[u4DataLen - 1] << 8) | 0x005A0000; + break; + + case 3: + au4Msg[0] = ((u32)pucData[u4DataLen - 3]) | + ((u32)pucData[u4DataLen - 2] << 8) | + ((u32)pucData[u4DataLen - 1] << 16) | 0x5A000000; + break; + + default: + au4Msg[0] = 0x0000005A; + } + au4Msg[1] = 0; + for (i = 0; i < 2; i++) { + l = l ^ au4Msg[i]; + tkipMicB(&l, &r); + } + + /* return ( l, r ), i.e. MIC */ + WLAN_SET_FIELD_32(pucMic, l); + WLAN_SET_FIELD_32(pucMic + 4, r); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief this function decapsulate MSDU frame body( with MIC ) according + * to IEEE 802.11i TKIP sepcification. + * + * \param[in] prAdapter Pointer to the adapter object data area. + * \param[in] pucDa Pointer to destination address DA + * \param[in] pucSa Pointer to source address SA + * \param[in] ucPriority Priority of IEEE 802.11 traffic class + * \param[in] pucPayload Pointer to message + * \param[in] u2PayloadLen Message length, in byte(s) + * \param[out] pucMic Pointer to 64-bit MIC + * + * \retval NONE + */ +/*----------------------------------------------------------------------------*/ +void tkipMicEncapsulate(IN u8 *pucDa, IN u8 *pucSa, IN u8 ucPriority, + IN u16 u2PayloadLen, IN u8 *pucPayload, IN u8 *pucMic, + IN u8 *pucMicKey) +{ + u8 aucMic[8]; /* MIC' */ + + DEBUGFUNC("tkipSwMsduEncapsulate"); + + ASSERT(pucDa); + ASSERT(pucSa); + ASSERT(pucPayload); + ASSERT(pucMic); + ASSERT(pucMicKey); + + DBGLOG(RSN, LOUD, "MIC key %02x-%02x-%02x-%02x %02x-%02x-%02x-%02x\n", + pucMicKey[0], pucMicKey[1], pucMicKey[2], pucMicKey[3], + pucMicKey[4], pucMicKey[5], pucMicKey[6], pucMicKey[7]); + + tkipMicGen(pucMicKey, (u8 *)pucPayload, u2PayloadLen, pucSa, pucDa, + ucPriority, aucMic); + + kalMemCopy((u8 *)pucMic, &aucMic[0], WLAN_MAC_MIC_LEN); + + DBGLOG(RSN, LOUD, "Mic %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", + pucMic[0], pucMic[1], pucMic[2], pucMic[3], pucMic[4], pucMic[5], + pucMic[6], pucMic[7]); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function decapsulate MSDU frame body (with MIC) according + * to IEEE 802.11i TKIP sepcification. + * + * \param[in] prAdapter Pointer to the adapter object data area. + * \param[in] prMacHeader Pointer to frame MAC header + * \param[in] pucFrameBody Pointer to frame body + * \param[in] u4FrameBodyLen Length of frame body (in bytes), include + * length of ICV and MIC + * \param[in] pucMickey Pointer to MIC key + * \param[out] pu4ResultFrameBodyLen Pointer to put the result frame body + * length. + * + * \retval false(TKIP_MIC_ERR), if this MSDU is not decapsulatable, i.e. MIC + * verification is failure. + * true(TKIP_DECAPSULATE_SUCCESS), if this TKIP MSDU is decapsulated + * successfully, i.e. MIC verification is successful. + * + * \note 1 If return true, result frame body length + * is only equal to data payload legth, and the result frame + * body's format is MSDU + * 2. If return false, result frame body length is equal + * to data payload legth plus MIC and MIC', and the result + * frame body's format is: MSDU + MIC + */ +/*----------------------------------------------------------------------------*/ +u8 tkipMicDecapsulate(IN P_SW_RFB_T prSwRfb, IN u8 *pucMicKey) +{ + u8 *pucMic1; /* MIC */ + u8 aucMic2[8]; /* MIC' */ + u8 ucPriority; + u8 fgStatus; + u8 *pucSa, *pucDa; + /* u8 * pucMickey; */ + u8 *pucFrameBody; + u16 u2FrameBodyLen; + P_WLAN_MAC_HEADER_T prMacHeader; + + DEBUGFUNC("tkipMicDecapsulate"); + + ASSERT(prSwRfb); + ASSERT(pucMicKey); + + /* prRxStatus = prSwRfb->prRxStatus; */ + pucFrameBody = prSwRfb->pucPayload; + u2FrameBodyLen = prSwRfb->u2PayloadLength; + + /* if ((prRxStatus->ucKIdxSecMode & BITS(0,3)) != + * CIPHER_SUITE_TKIP_WO_MIC){ */ + /* return true; */ + /* } */ + + DBGLOG(RSN, LOUD, "Before TKIP MSDU Decapsulate:\n"); + DBGLOG(RSN, LOUD, "MIC key:\n"); + /* DBGLOG_MEM8(RSN, LOUD, pucMicKey, 8); */ + + prMacHeader = (P_WLAN_MAC_HEADER_T)prSwRfb->pvHeader; + ASSERT(prMacHeader); + + pucDa = prMacHeader->aucAddr1; + pucSa = prMacHeader->aucAddr3; + + switch (prMacHeader->u2FrameCtrl & MASK_TO_DS_FROM_DS) { + case 0: + pucDa = prMacHeader->aucAddr1; + pucSa = prMacHeader->aucAddr2; + break; + + case MASK_FC_FROM_DS: + pucDa = prMacHeader->aucAddr1; + pucSa = prMacHeader->aucAddr3; + break; + + default: + ASSERT((prMacHeader->u2FrameCtrl & MASK_FC_TO_DS) == 0); + return true; + } + + if (RXM_IS_QOS_DATA_FRAME(prSwRfb->u2FrameCtrl)) { + ucPriority = (u8)((((P_WLAN_MAC_HEADER_QOS_T)prSwRfb->pvHeader) + ->u2QosCtrl) & + MASK_QC_TID); + } else { + ucPriority = 0; + } + + /* generate MIC' */ + tkipMicGen(pucMicKey, pucFrameBody, u2FrameBodyLen - WLAN_MAC_MIC_LEN, + pucSa, pucDa, ucPriority, aucMic2); + + /* verify MIC and MIC' */ + pucMic1 = &pucFrameBody[u2FrameBodyLen - WLAN_MAC_MIC_LEN]; + if (pucMic1[0] == aucMic2[0] && pucMic1[1] == aucMic2[1] && + pucMic1[2] == aucMic2[2] && pucMic1[3] == aucMic2[3] && + pucMic1[4] == aucMic2[4] && pucMic1[5] == aucMic2[5] && + pucMic1[6] == aucMic2[6] && pucMic1[7] == aucMic2[7]) { + u2FrameBodyLen -= WLAN_MAC_MIC_LEN; + fgStatus = true; + } else { + fgStatus = false; + } + + /* DBGLOG(RSN, LOUD, ("TKIP MIC:\n")); */ + /* DBGLOG_MEM8(RSN, LOUD, pucMic1, 8); */ + /* DBGLOG(RSN, LOUD, ("TKIP MIC':\n")); */ + /* DBGLOG_MEM8(RSN, LOUD, aucMic2, 8); */ + + prSwRfb->u2PayloadLength = u2FrameBodyLen; + + DBGLOG(RSN, LOUD, "After TKIP MSDU Decapsulate:\n"); + DBGLOG(RSN, LOUD, "Frame body: (length = %u)\n", u2FrameBodyLen); + /* DBGLOG_MEM8(RSN, LOUD, pucFrameBody, u2FrameBodyLen); */ + + return fgStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function decapsulate MSDU frame body (with MIC) according + * to IEEE 802.11i TKIP sepcification. + * + * \param[in] prAdapter Pointer to the adapter object data area. + * \param[in] prMacHeader Pointer to frame MAC header + * \param[in] pucFrameBody Pointer to frame body + * \param[in] u4FrameBodyLen Length of frame body (in bytes), include + * length of ICV and MIC + * \param[in] pucMickey Pointer to MIC key + * \param[out] pu4ResultFrameBodyLen Pointer to put the result frame body + * length. + * + * \retval false(TKIP_MIC_ERR), if this MSDU is not decapsulatable, i.e. MIC + * verification is failure. + * true(TKIP_DECAPSULATE_SUCCESS), if this TKIP MSDU is decapsulated + * successfully, i.e. MIC verification is successful. + * + * \note 1 If return true, result frame body length + * is only equal to data payload legth, and the result frame + * body's format is MSDU + * 2. If return false, result frame body length is equal + * to data payload legth plus MIC and MIC', and the result + * frame body's format is: MSDU + MIC + */ +/*----------------------------------------------------------------------------*/ +u8 tkipMicDecapsulateInRxHdrTransMode(IN P_SW_RFB_T prSwRfb, IN u8 *pucMicKey) +{ + u8 *pucMic1; /* MIC */ + u8 aucMic2[8]; /* MIC' */ + u8 fgStatus = false; + /* u8 * pucMickey; */ + u8 *pucFrameBody; + u16 u2FrameBodyLen; + struct sk_buff *prSkb = NULL; + + DEBUGFUNC("tkipMicDecapsulateInRxHdrTransMode"); + + ASSERT(prSwRfb); + ASSERT(pucMicKey); + + /* prRxStatus = prSwRfb->prRxStatus; */ + pucFrameBody = prSwRfb->pucPayload; + u2FrameBodyLen = prSwRfb->u2PayloadLength; + + /* if ((prRxStatus->ucKIdxSecMode & BITS(0,3)) != + * CIPHER_SUITE_TKIP_WO_MIC){ */ + /* return true; */ + /* } */ + + DBGLOG(RSN, LOUD, "Before TKIP MSDU Decapsulate:\n"); + DBGLOG(RSN, LOUD, "MIC key:\n"); + /* DBGLOG_MEM8(RSN, LOUD, pucMicKey, 8); */ + + prSkb = dev_alloc_skb(u2FrameBodyLen + ETHERNET_HEADER_SZ * 4); + if (prSkb) { + /* copy to etherhdr + payload to skb data */ + kalMemCopy(prSkb->data, prSwRfb->pvHeader, + u2FrameBodyLen + ETHERNET_HEADER_SZ); + *(prSkb->data + 6) = ETH_LLC_DSAP_SNAP; + *(prSkb->data + 7) = ETH_LLC_SSAP_SNAP; + *(prSkb->data + 8) = ETH_LLC_CONTROL_UNNUMBERED_INFORMATION; + *(prSkb->data + 9) = 0x00; + *(prSkb->data + 10) = 0x00; + *(prSkb->data + 11) = 0x00; + *(prSkb->data + 12) = *(u8 *)(prSwRfb->pvHeader + 12); + *(prSkb->data + 13) = *(u8 *)(prSwRfb->pvHeader + 13); + + tkipMicGen(pucMicKey, prSkb->data + 6, + u2FrameBodyLen - WLAN_MAC_MIC_LEN + 8, + prSwRfb->pvHeader + 6, prSwRfb->pvHeader, + prSwRfb->ucTid, aucMic2); + + if (prSkb) { + kfree_skb((struct sk_buff *)prSkb); + } + } else { + DBGLOG(RX, ERROR, "MIC SW DEC1\n"); + return fgStatus; + } + + /* verify MIC and MIC' */ + pucMic1 = &pucFrameBody[u2FrameBodyLen - WLAN_MAC_MIC_LEN]; + if (pucMic1[0] == aucMic2[0] && pucMic1[1] == aucMic2[1] && + pucMic1[2] == aucMic2[2] && pucMic1[3] == aucMic2[3] && + pucMic1[4] == aucMic2[4] && pucMic1[5] == aucMic2[5] && + pucMic1[6] == aucMic2[6] && pucMic1[7] == aucMic2[7]) { + u2FrameBodyLen -= WLAN_MAC_MIC_LEN; + fgStatus = true; + } else { + fgStatus = false; + DBGLOG(RX, ERROR, "MIC SW DEC2\n"); + } + + /* DBGLOG(RSN, LOUD, ("TKIP MIC:\n")); */ + /* DBGLOG_MEM8(RSN, LOUD, pucMic1, 8); */ + /* DBGLOG(RSN, LOUD, ("TKIP MIC':\n")); */ + /* DBGLOG_MEM8(RSN, LOUD, aucMic2, 8); */ + + prSwRfb->u2PayloadLength = u2FrameBodyLen; + + DBGLOG(RSN, LOUD, "After TKIP MSDU Decapsulate:\n"); + DBGLOG(RSN, LOUD, "Frame body: (length = %u)\n", u2FrameBodyLen); + /* DBGLOG_MEM8(RSN, LOUD, pucFrameBody, u2FrameBodyLen); */ + + return fgStatus; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/wnm.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/wnm.c new file mode 100644 index 00000000000000..a40e3e1aeb8b45 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/mgmt/wnm.c @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "wnm.c" + * \brief This file includes the 802.11v default vale and functions. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define WNM_MAX_TOD_ERROR 0 +#define WNM_MAX_TOA_ERROR 0 +#define MICRO_TO_10NANO(x) ((x) * 100) +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT +static u8 ucTimingMeasToken; +#endif +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT +static u8 ucBtmMgtToken = 1; +#endif + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to process the 802.11v wnm category action + * frame. + * + * + * \note + * Called by: Handle Rx mgmt request + */ +/*----------------------------------------------------------------------------*/ +#if CFG_SUPPORT_802_11V +void wnmWNMAction(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_WLAN_ACTION_FRAME prRxFrame; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxFrame = (P_WLAN_ACTION_FRAME)prSwRfb->pvHeader; + + DBGLOG(WNM, TRACE, "WNM action frame: %d from " MACSTR "\n", + prRxFrame->ucAction, MAC2STR(prRxFrame->aucSrcAddr)); + + switch (prRxFrame->ucAction) { +#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT + case ACTION_WNM_TIMING_MEASUREMENT_REQUEST: + break; + +#endif +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + case ACTION_WNM_BSS_TRANSITION_MANAGEMENT_REQ: +#endif + default: + DBGLOG(WNM, INFO, + "WNM: action frame %d, try to send to supplicant\n", + prRxFrame->ucAction); + aisFuncValidateRxActionFrame(prAdapter, prSwRfb); + break; + } +} + +u8 wnmGetBtmToken(void) +{ + return ucBtmMgtToken++; +} + +static WLAN_STATUS wnmBTMQueryTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + DBGLOG(WNM, INFO, "BTM: Query Frame Tx Done, Status %d\n", + rTxDoneStatus); + return WLAN_STATUS_SUCCESS; +} + +static WLAN_STATUS wnmBTMResponseTxDone(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + P_BSS_TRANSITION_MGT_PARAM_T prBtm = + &prAdapter->rWifiVar.rAisSpecificBssInfo.rBTMParam; + P_AIS_FSM_INFO_T prAisFsmInfo = &prAdapter->rWifiVar.rAisFsmInfo; + + DBGLOG(WNM, INFO, "BTM: Response Frame Tx Done Status %d\n", + rTxDoneStatus); + if (prBtm->fgPendingResponse && + prAisFsmInfo->eCurrentState == AIS_STATE_SEARCH) { + prBtm->fgPendingResponse = false; + aisFsmSteps(prAdapter, AIS_STATE_REQ_CHANNEL_JOIN); + } + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will compose the BTM Response frame. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prStaRec Pointer to the STA_RECORD_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void wnmSendBTMResponseFrame(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec) +{ + P_MSDU_INFO_T prMsduInfo = NULL; + P_BSS_INFO_T prBssInfo = NULL; + P_ACTION_BTM_RSP_FRAME_T prTxFrame = NULL; + u16 u2PayloadLen = 0; + P_BSS_TRANSITION_MGT_PARAM_T prBtmParam = + &prAdapter->rWifiVar.rAisSpecificBssInfo.rBTMParam; + u8 *pucOptInfo = NULL; + + if (!prStaRec) { + DBGLOG(WNM, ERROR, "BTM: No station record found\n"); + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + ASSERT(prBssInfo); + + /* 1 Allocate MSDU Info */ + prMsduInfo = (P_MSDU_INFO_T)cnmMgtPktAlloc( + prAdapter, MAC_TX_RESERVED_FIELD + PUBLIC_ACTION_MAX_LEN); + if (!prMsduInfo) { + return; + } + + prTxFrame = + (P_ACTION_BTM_RSP_FRAME_T)((unsigned long)(prMsduInfo->prPacket) + + + MAC_TX_RESERVED_FIELD); + + /* 2 Compose The Mac Header. */ + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + + prTxFrame->ucCategory = CATEGORY_WNM_ACTION; + prTxFrame->ucAction = ACTION_WNM_BSS_TRANSITION_MANAGEMENT_RSP; + + /* 3 Compose the frame body's frame. */ + prTxFrame->ucDialogToken = prBtmParam->ucDialogToken; + prBtmParam->ucDialogToken = 0; /* reset dialog token */ + prTxFrame->ucStatusCode = prBtmParam->ucStatusCode; + prTxFrame->ucBssTermDelay = prBtmParam->ucTermDelay; + pucOptInfo = &prTxFrame->aucOptInfo[0]; + if (prBtmParam->ucStatusCode == BSS_TRANSITION_MGT_STATUS_ACCEPT) { + COPY_MAC_ADDR(pucOptInfo, prBtmParam->aucTargetBssid); + pucOptInfo += MAC_ADDR_LEN; + u2PayloadLen += MAC_ADDR_LEN; + } + if (prBtmParam->u2OurNeighborBssLen > 0) { + kalMemCopy(pucOptInfo, prBtmParam->pucOurNeighborBss, + prBtmParam->u2OurNeighborBssLen); + kalMemFree(prBtmParam->pucOurNeighborBss, VIR_MEM_TYPE, + prBtmParam->u2OurNeighborBssLen); + prBtmParam->u2OurNeighborBssLen = 0; + u2PayloadLen += prBtmParam->u2OurNeighborBssLen; + } + + /* 4 Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prStaRec->ucBssIndex, + prStaRec->ucIndex, WLAN_MAC_MGMT_HEADER_LEN, + OFFSET_OF(ACTION_BTM_RSP_FRAME_T, aucOptInfo) + + u2PayloadLen, + wnmBTMResponseTxDone, MSDU_RATE_MODE_AUTO); + + /* 5 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will compose the BTM Query frame. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] prStaRec Pointer to the STA_RECORD_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void wnmSendBTMQueryFrame(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + P_MSDU_INFO_T prMsduInfo = NULL; + P_BSS_INFO_T prBssInfo = NULL; + P_ACTION_BTM_QUERY_FRAME_T prTxFrame = NULL; + P_BSS_TRANSITION_MGT_PARAM_T prBtmParam = + &prAdapter->rWifiVar.rAisSpecificBssInfo.rBTMParam; + u16 u2FrameLen = 0; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + ASSERT(prBssInfo); + + /* 1 Allocate MSDU Info */ + prMsduInfo = cnmMgtPktAlloc(prAdapter, MAC_TX_RESERVED_FIELD + + PUBLIC_ACTION_MAX_LEN); + if (!prMsduInfo) { + return; + } + + prTxFrame = + (P_ACTION_BTM_QUERY_FRAME_T)((unsigned long)(prMsduInfo + ->prPacket) + + MAC_TX_RESERVED_FIELD); + + /* 2 Compose The Mac Header. */ + prTxFrame->u2FrameCtrl = MAC_FRAME_ACTION; + COPY_MAC_ADDR(prTxFrame->aucDestAddr, prStaRec->aucMacAddr); + COPY_MAC_ADDR(prTxFrame->aucSrcAddr, prBssInfo->aucOwnMacAddr); + COPY_MAC_ADDR(prTxFrame->aucBSSID, prBssInfo->aucBSSID); + prTxFrame->ucCategory = CATEGORY_WNM_ACTION; + prTxFrame->ucAction = ACTION_WNM_BSS_TRANSITION_MANAGEMENT_QUERY; + + u2FrameLen = OFFSET_OF(ACTION_NEIGHBOR_REPORT_FRAME_T, aucInfoElem); + + /* 3 Compose the frame body's frame. */ + prTxFrame->ucDialogToken = prBtmParam->ucDialogToken; + prTxFrame->ucQueryReason = prBtmParam->ucQueryReason; + + if (prBtmParam->u2OurNeighborBssLen > 0) { + kalMemCopy(prTxFrame->pucNeighborBss, + prBtmParam->pucOurNeighborBss, + prBtmParam->u2OurNeighborBssLen); + kalMemFree(prBtmParam->pucOurNeighborBss, VIR_MEM_TYPE, + prBtmParam->u2OurNeighborBssLen); + prBtmParam->u2OurNeighborBssLen = 0; + } + + /* 4 Update information of MSDU_INFO_T */ + TX_SET_MMPDU(prAdapter, prMsduInfo, prStaRec->ucBssIndex, + prStaRec->ucIndex, WLAN_MAC_MGMT_HEADER_LEN, + WLAN_MAC_MGMT_HEADER_LEN + 4 + + prBtmParam->u2OurNeighborBssLen, + wnmBTMQueryTxDone, MSDU_RATE_MODE_AUTO); + + /* 5 Enqueue the frame to send this action frame. */ + nicTxEnqueueMsdu(prAdapter, prMsduInfo); +} +/*----------------------------------------------------------------------------*/ +/*! + * + * \brief This routine is called to process the 802.11v BTM request. + * + * + * \note + * Handle Rx mgmt request + */ +/*----------------------------------------------------------------------------*/ +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT +void wnmRecvBTMRequest(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_ACTION_BTM_REQ_FRAME_T prRxFrame = NULL; + P_BSS_TRANSITION_MGT_PARAM_T prBtmParam = + &prAdapter->rWifiVar.rAisSpecificBssInfo.rBTMParam; + u8 *pucOptInfo = NULL; + u8 ucRequestMode = 0; + u16 u2TmpLen = 0; + P_MSG_AIS_BSS_TRANSITION_T prMsg = NULL; + enum WNM_AIS_BSS_TRANSITION eTransType = BSS_TRANSITION_NO_MORE_ACTION; + + prRxFrame = (P_ACTION_BTM_REQ_FRAME_T)prSwRfb->pvHeader; + if (!prRxFrame) { + return; + } + + if (prSwRfb->u2PacketLen < + OFFSET_OF(ACTION_BTM_REQ_FRAME_T, aucOptInfo)) { + DBGLOG(WNM, + WARN, + "BTM: Request frame length is less than a standard BTM frame\n"); + return; + } + prMsg = (P_MSG_AIS_BSS_TRANSITION_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_BSS_TRANSITION_T)); + if (!prMsg) { + DBGLOG(WNM, WARN, "BTM: Msg Hdr is NULL\n"); + return; + } + kalMemZero(prMsg, sizeof(*prMsg)); + prBtmParam->ucRequestMode = prRxFrame->ucRequestMode; + prMsg->ucToken = prRxFrame->ucDialogToken; + prBtmParam->u2DisassocTimer = prRxFrame->u2DisassocTimer; + prBtmParam->ucDialogToken = prRxFrame->ucDialogToken; + pucOptInfo = &prRxFrame->aucOptInfo[0]; + ucRequestMode = prBtmParam->ucRequestMode; + u2TmpLen = OFFSET_OF(ACTION_BTM_REQ_FRAME_T, aucOptInfo); + if (ucRequestMode & BTM_REQ_MODE_DISC_IMM) { + eTransType = BSS_TRANSITION_REQ_ROAMING; + } + if (ucRequestMode & BTM_REQ_MODE_BSS_TERM_INCLUDE) { + P_SUB_IE_BSS_TERM_DURATION_T prBssTermDuration = + (P_SUB_IE_BSS_TERM_DURATION_T)pucOptInfo; + + prBtmParam->u2TermDuration = prBssTermDuration->u2Duration; + kalMemCopy(prBtmParam->aucTermTsf, + prBssTermDuration->aucTermTsf, 8); + pucOptInfo += sizeof(*prBssTermDuration); + u2TmpLen += sizeof(*prBssTermDuration); + eTransType = BSS_TRANSITION_REQ_ROAMING; + } + if (ucRequestMode & BTM_REQ_MODE_ESS_DISC_IMM) { + kalMemCopy(prBtmParam->aucSessionURL, &pucOptInfo[1], + pucOptInfo[0]); + prBtmParam->ucSessionURLLen = pucOptInfo[0]; + u2TmpLen += pucOptInfo[0]; + pucOptInfo += pucOptInfo[0] + 1; + eTransType = BSS_TRANSITION_DISASSOC; + } + if (ucRequestMode & BTM_REQ_MODE_CAND_INCLUDED_BIT) { + if (!(ucRequestMode & BTM_REQ_MODE_ESS_DISC_IMM)) { + eTransType = BSS_TRANSITION_REQ_ROAMING; + } + if (prSwRfb->u2PacketLen > u2TmpLen) { + prMsg->u2CandListLen = prSwRfb->u2PacketLen - u2TmpLen; + prMsg->pucCandList = pucOptInfo; + prMsg->ucValidityInterval = + prRxFrame->ucValidityInterval; + } else { + DBGLOG(WNM, + WARN, + "BTM: Candidate Include bit is set, but no candidate list\n"); + } + } + + DBGLOG(WNM, INFO, + "BTM: Req %d, VInt %d, DiscTimer %d, Token %d, TransType %d\n", + prBtmParam->ucRequestMode, prRxFrame->ucValidityInterval, + prBtmParam->u2DisassocTimer, prMsg->ucToken, eTransType); + + prMsg->eTransitionType = eTransType; + prMsg->rMsgHdr.eMsgId = MID_WNM_AIS_BSS_TRANSITION; + /* if BTM Request is dest for broadcast, don't send BTM Response */ + if (kalMemCmp(prRxFrame->aucDestAddr, "\xff\xff\xff\xff\xff\xff", + MAC_ADDR_LEN)) { + prMsg->fgNeedResponse = true; + }else{ + prMsg->fgNeedResponse = false; + } + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsg, + MSG_SEND_METHOD_BUF); +} +#endif +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/cmd_buf.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/cmd_buf.c new file mode 100644 index 00000000000000..b63c45dea8da41 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/cmd_buf.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "cmd_buf.c" + * \brief This file contain the management function of internal Command + * Buffer for CMD_INFO_T. + * + * We'll convert the OID into Command Packet and then send to FW. Thus we need + * to copy the OID information to Command Buffer for following reasons. + * 1. The data structure of OID information may not equal to the data + * structure of Command, we cannot use the OID buffer directly. + * 2. If the Command was not generated by driver we also need a place to + * store the information. + * 3. Because the CMD is NOT FIFO when doing memory allocation (CMD will be + * generated from OID or interrupt handler), thus we'll use the Block style of + * Memory Allocation here. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to initial the MGMT memory pool for CMD Packet. + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void cmdBufInitialize(IN P_ADAPTER_T prAdapter) +{ + P_CMD_INFO_T prCmdInfo; + u32 i; + + ASSERT(prAdapter); + + QUEUE_INITIALIZE(&prAdapter->rFreeCmdList); + + for (i = 0; i < CFG_TX_MAX_CMD_PKT_NUM; i++) { + prCmdInfo = &prAdapter->arHifCmdDesc[i]; + QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, + &prCmdInfo->rQueEntry); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Allocate CMD_INFO_T from a free list and MGMT memory pool. + * + * @param[in] prAdapter Pointer to the Adapter structure. + * @param[in] u4Length Length of the frame buffer to allocate. + * + * @retval NULL Pointer to the valid CMD Packet handler + * @retval !NULL Fail to allocat CMD Packet + */ +/*----------------------------------------------------------------------------*/ +P_CMD_INFO_T cmdBufAllocateCmdInfo(IN P_ADAPTER_T prAdapter, IN u32 u4Length) +{ + P_CMD_INFO_T prCmdInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("cmdBufAllocateCmdInfo"); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + + if (prCmdInfo) { + /* Setup initial value in CMD_INFO_T */ + prCmdInfo->u2InfoBufLen = 0; + prCmdInfo->fgIsOid = false; + + if (u4Length) { + /* Start address of allocated memory */ + u4Length = TFCB_FRAME_PAD_TO_DW(u4Length); + + prCmdInfo->pucInfoBuffer = + cnmMemAlloc(prAdapter, RAM_TYPE_BUF, u4Length); + + if (prCmdInfo->pucInfoBuffer == NULL) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + SPIN_LOCK_CMD_RESOURCE); + QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, + &prCmdInfo->rQueEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, + SPIN_LOCK_CMD_RESOURCE); + + prCmdInfo = NULL; + } else { + kalMemZero(prCmdInfo->pucInfoBuffer, u4Length); + } + } else { + prCmdInfo->pucInfoBuffer = NULL; + } + } + + if (prCmdInfo) { + DBGLOG(MEM, LOUD, "CMD[0x%p] allocated! LEN[%04u], Rest[%u]\n", + prCmdInfo, u4Length, prAdapter->rFreeCmdList.u4NumElem); + } else { + DBGLOG(MEM, WARN, + "CMD allocation failed! LEN[%04u], Rest[%u]\n", u4Length, + prAdapter->rFreeCmdList.u4NumElem); + } + + return prCmdInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to free the CMD Packet to the MGMT memory pool. + * + * @param prAdapter Pointer to the Adapter structure. + * @param prCmdInfo CMD Packet handler + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void cmdBufFreeCmdInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("cmdBufFreeCmdInfo"); + + ASSERT(prAdapter); + + if (prCmdInfo) { + if (prCmdInfo->pucInfoBuffer) { + cnmMemFree(prAdapter, prCmdInfo->pucInfoBuffer); + prCmdInfo->pucInfoBuffer = NULL; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + QUEUE_INSERT_TAIL(&prAdapter->rFreeCmdList, + &prCmdInfo->rQueEntry); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); + } + + if (prCmdInfo) { + DBGLOG(MEM, LOUD, "CMD[0x%p] freed! Rest[%u]\n", prCmdInfo, + prAdapter->rFreeCmdList.u4NumElem); + } + + return; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic.c new file mode 100644 index 00000000000000..7c3282ed1743bb --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic.c @@ -0,0 +1,3747 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file nic.c + * \brief Functions that provide operation in NIC's (Network Interface Card) + * point of view. + * + * This file includes functions which unite multiple hal(Hardware) operations + * and also take the responsibility of Software Resource Management in order + * to keep the synchronization with Hardware Manipulation. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +const u8 aucPhyCfg2PhyTypeSet[PHY_CONFIG_NUM] = { + PHY_TYPE_SET_802_11ABG, /* PHY_CONFIG_802_11ABG */ + PHY_TYPE_SET_802_11BG, /* PHY_CONFIG_802_11BG */ + PHY_TYPE_SET_802_11G, /* PHY_CONFIG_802_11G */ + PHY_TYPE_SET_802_11A, /* PHY_CONFIG_802_11A */ + PHY_TYPE_SET_802_11B, /* PHY_CONFIG_802_11B */ + PHY_TYPE_SET_802_11ABGN, /* PHY_CONFIG_802_11ABGN */ + PHY_TYPE_SET_802_11BGN, /* PHY_CONFIG_802_11BGN */ + PHY_TYPE_SET_802_11AN, /* PHY_CONFIG_802_11AN */ + PHY_TYPE_SET_802_11GN, /* PHY_CONFIG_802_11GN */ + PHY_TYPE_SET_802_11AC, PHY_TYPE_SET_802_11ANAC, PHY_TYPE_SET_802_11ABGNAC +}; + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +static INT_EVENT_MAP_T arIntEventMapTable[] = { + { WHISR_ABNORMAL_INT, INT_EVENT_ABNORMAL }, + { WHISR_D2H_SW_INT, INT_EVENT_SW_INT }, + { WHISR_TX_DONE_INT, INT_EVENT_TX }, + { (WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT), INT_EVENT_RX } +}; + +static const u8 ucIntEventMapSize = + (sizeof(arIntEventMapTable) / sizeof(INT_EVENT_MAP_T)); + +static IST_EVENT_FUNCTION apfnEventFuncTable[] = { + nicProcessAbnormalInterrupt, /*!< INT_EVENT_ABNORMAL */ + nicProcessSoftwareInterrupt, /*!< INT_EVENT_SW_INT */ + nicProcessTxInterrupt, /*!< INT_EVENT_TX */ + nicProcessRxInterrupt, /*!< INT_EVENT_RX */ +}; + +ECO_INFO_T g_eco_info = { 0xFF }; +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/*! This macro is used to reduce coding errors inside nicAllocateAdapterMemory() + * and also enhance the readability. + */ +#define LOCAL_NIC_ALLOCATE_MEMORY(pucMem, u4Size, eMemType, pucComment) \ + { \ + DBGLOG(INIT, INFO, "Allocating %ld bytes for %s.\n", u4Size, \ + pucComment); \ + pucMem = (u8 *)kalMemAlloc(u4Size, eMemType); \ + if (pucMem == (u8 *)NULL) { \ + DBGLOG(INIT, ERROR, "Could not allocate %ld bytes for %s.\n", \ + u4Size, pucComment); \ + break; \ + } \ + ASSERT(((unsigned long)pucMem % 4) == 0); \ + DBGLOG(INIT, INFO, "Virtual Address = 0x%p for %s.\n", \ + (unsigned long)pucMem, pucComment); \ + } + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for the allocation of the data structures + * inside the Adapter structure, include: + * 1. SW_RFB_Ts + * 2. Common coalescing buffer for TX PATH. + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @retval WLAN_STATUS_SUCCESS - Has enough memory. + * @retval WLAN_STATUS_RESOURCES - Memory is not enough. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicAllocateAdapterMemory(IN P_ADAPTER_T prAdapter) +{ + WLAN_STATUS status = WLAN_STATUS_RESOURCES; + P_RX_CTRL_T prRxCtrl; + P_TX_CTRL_T prTxCtrl; + + DEBUGFUNC("nicAllocateAdapterMemory"); + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + prTxCtrl = &prAdapter->rTxCtrl; + + do { + /* 4 <0> Reset all Memory Handler */ +#if CFG_DBG_MGT_BUF + prAdapter->u4MemFreeDynamicCount = 0; + prAdapter->u4MemAllocDynamicCount = 0; +#endif + prAdapter->pucMgtBufCached = (u8 *)NULL; + prRxCtrl->pucRxCached = (u8 *)NULL; + + /* 4 <1> Memory for Management Memory Pool and CMD_INFO_T */ + /* Allocate memory for the CMD_INFO_T and its MGMT memory pool. + */ + prAdapter->u4MgtBufCachedSize = MGT_BUFFER_SIZE; + +#ifdef CFG_PREALLOC_MEMORY + prAdapter->pucMgtBufCached = preallocGetMem(MEM_ID_NIC_ADAPTER); +#else + LOCAL_NIC_ALLOCATE_MEMORY(prAdapter->pucMgtBufCached, + prAdapter->u4MgtBufCachedSize, PHY_MEM_TYPE, + "COMMON MGMT MEMORY POOL"); +#endif + + /* 4 <2> Memory for RX Descriptor */ + /* Initialize the number of rx buffers we will have in our + * queue. */ + /* <TODO> We may setup ucRxPacketDescriptors by GLUE Layer, and + * using this variable directly. + */ + /* Allocate memory for the SW receive structures. */ + prRxCtrl->u4RxCachedSize = + CFG_RX_MAX_PKT_NUM * ALIGN_4(sizeof(SW_RFB_T)); + + LOCAL_NIC_ALLOCATE_MEMORY(prRxCtrl->pucRxCached, + prRxCtrl->u4RxCachedSize, VIR_MEM_TYPE, + "SW_RFB_T"); + + /* 4 <3> Memory for TX DEscriptor */ + prTxCtrl->u4TxCachedSize = + CFG_TX_MAX_PKT_NUM * ALIGN_4(sizeof(MSDU_INFO_T)); + + LOCAL_NIC_ALLOCATE_MEMORY(prTxCtrl->pucTxCached, + prTxCtrl->u4TxCachedSize, VIR_MEM_TYPE, + "MSDU_INFO_T"); + + /* 4 <4> Memory for Common Coalescing Buffer */ + + /* Get valid buffer size based on config & host capability */ + prAdapter->u4CoalescingBufCachedSize = + halGetValidCoalescingBufSize(prAdapter); + + /* Allocate memory for the common coalescing buffer. */ +#ifdef CFG_PREALLOC_MEMORY + prAdapter->pucCoalescingBufCached = preallocGetMem(MEM_ID_IO_BUFFER); +#else + prAdapter->pucCoalescingBufCached = + kalAllocateIOBuffer(prAdapter->u4CoalescingBufCachedSize); +#endif + + if (prAdapter->pucCoalescingBufCached == NULL) { + DBGLOG(INIT, ERROR, + "Could not allocate %ld bytes for coalescing buffer.\n", + prAdapter->u4CoalescingBufCachedSize); + break; + } + + /* <5> Memory for HIF */ + if (halAllocateIOBuffer(prAdapter) != WLAN_STATUS_SUCCESS) { + break; + } + + status = WLAN_STATUS_SUCCESS; + } while (false); + + if (status != WLAN_STATUS_SUCCESS) { + nicReleaseAdapterMemory(prAdapter); + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for releasing the allocated memory by + * nicAllocatedAdapterMemory(). + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicReleaseAdapterMemory(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + P_RX_CTRL_T prRxCtrl; + u32 u4Idx; + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + /* 4 <5> Memory for HIF */ + halReleaseIOBuffer(prAdapter); + + /* 4 <4> Memory for Common Coalescing Buffer */ + if (prAdapter->pucCoalescingBufCached) { +#ifndef CFG_PREALLOC_MEMORY + kalReleaseIOBuffer((void *)prAdapter->pucCoalescingBufCached, + prAdapter->u4CoalescingBufCachedSize); +#endif + prAdapter->pucCoalescingBufCached = (u8 *)NULL; + } + + /* 4 <3> Memory for TX Descriptor */ + if (prTxCtrl->pucTxCached) { + kalMemFree((void *)prTxCtrl->pucTxCached, VIR_MEM_TYPE, + prTxCtrl->u4TxCachedSize); + prTxCtrl->pucTxCached = (u8 *)NULL; + } + /* 4 <2> Memory for RX Descriptor */ + if (prRxCtrl->pucRxCached) { + kalMemFree((void *)prRxCtrl->pucRxCached, VIR_MEM_TYPE, + prRxCtrl->u4RxCachedSize); + prRxCtrl->pucRxCached = (u8 *)NULL; + } + /* 4 <1> Memory for Management Memory Pool */ + if (prAdapter->pucMgtBufCached) { +#ifndef CFG_PREALLOC_MEMORY + kalMemFree((void *)prAdapter->pucMgtBufCached, PHY_MEM_TYPE, + prAdapter->u4MgtBufCachedSize); +#endif + prAdapter->pucMgtBufCached = (u8 *)NULL; + } + + /* Memory for TX Desc Template */ + for (u4Idx = 0; u4Idx < CFG_STA_REC_NUM; u4Idx++) + nicTxFreeDescTemplate(prAdapter, &prAdapter->arStaRec[u4Idx]); + +#if CFG_DBG_MGT_BUF + do { + u8 fgUnfreedMem = false; + P_BUF_INFO_T prBufInfo; + + /* Dynamic allocated memory from OS */ + if (prAdapter->u4MemFreeDynamicCount != + prAdapter->u4MemAllocDynamicCount) { + fgUnfreedMem = true; + } + + /* MSG buffer */ + prBufInfo = &prAdapter->rMsgBufInfo; + if (prBufInfo->u4AllocCount != + (prBufInfo->u4FreeCount + prBufInfo->u4AllocNullCount)) { + fgUnfreedMem = true; + } + + /* MGT buffer */ + prBufInfo = &prAdapter->rMgtBufInfo; + if (prBufInfo->u4AllocCount != + (prBufInfo->u4FreeCount + prBufInfo->u4AllocNullCount)) { + fgUnfreedMem = true; + } + + /* Check if all allocated memories are free */ + if (fgUnfreedMem) { + DBGLOG(MEM, ERROR, "Unequal memory alloc/free count!\n"); + + qmDumpQueueStatus(prAdapter, NULL, 0); + cnmDumpMemoryStatus(prAdapter, NULL, 0); + } + + if (!wlanIsChipNoAck(prAdapter)) { + /* Skip this ASSERT if chip is no ACK */ + ASSERT(prAdapter->u4MemFreeDynamicCount == + prAdapter->u4MemAllocDynamicCount); + } + } while (false); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief disable global interrupt + * + * @param prAdapter pointer to the Adapter handler + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicDisableInterrupt(IN P_ADAPTER_T prAdapter) +{ + halDisableInterrupt(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief enable global interrupt + * + * @param prAdapter pointer to the Adapter handler + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicEnableInterrupt(IN P_ADAPTER_T prAdapter) +{ + halEnableInterrupt(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief The function used to read interrupt status and then invoking + * dispatching procedure for the appropriate functions + * corresponding to specific interrupt bits + * + * @param prAdapter pointer to the Adapter handler + * + * @retval WLAN_STATUS_SUCCESS + * @retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicProcessIST(IN P_ADAPTER_T prAdapter) +{ + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + u32 u4IntStatus = 0; + u32 i; + + ASSERT(prAdapter); + + if (prAdapter->rAcpiState == ACPI_STATE_D3) { + DBGLOG( + REQ, WARN, + "Fail in set nicProcessIST! (Adapter not ready). ACPI=D%d, Radio=%d\n", + prAdapter->rAcpiState, prAdapter->fgIsRadioOff); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + for (i = 0; i < prAdapter->rWifiVar.u4HifIstLoopCount; i++) { + HAL_READ_INT_STATUS(prAdapter, &u4IntStatus); + /* DBGLOG(INIT, TRACE, ("u4IntStatus: 0x%x\n", u4IntStatus)); */ + + if (u4IntStatus == 0) { + if (i == 0) { + u4Status = WLAN_STATUS_NOT_INDICATING; + } + break; + } + + nicProcessIST_impl(prAdapter, u4IntStatus); + + /* Have to TX now. Skip RX polling ASAP */ + if (test_bit(GLUE_FLAG_HIF_TX_CMD_BIT, + &prAdapter->prGlueInfo->ulFlag) || + test_bit(GLUE_FLAG_HIF_TX_BIT, &prAdapter->prGlueInfo->ulFlag)) { + i *= 2; + } + } + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief The function used to dispatch the appropriate functions for specific + * interrupt bits + * + * @param prAdapter pointer to the Adapter handler + * u4IntStatus interrupt status bits + * + * @retval WLAN_STATUS_SUCCESS + * @retval WLAN_STATUS_ADAPTER_NOT_READY + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicProcessIST_impl(IN P_ADAPTER_T prAdapter, IN u32 u4IntStatus) +{ + u32 u4IntCount = 0; + P_INT_EVENT_MAP_T prIntEventMap = NULL; + + ASSERT(prAdapter); + + prAdapter->u4IntStatus = u4IntStatus; + + /* Process each of the interrupt status consequently */ + prIntEventMap = &arIntEventMapTable[0]; + for (u4IntCount = 0; u4IntCount < ucIntEventMapSize; + prIntEventMap++, u4IntCount++) { + if (prIntEventMap->u4Int & prAdapter->u4IntStatus) { + if (0 /*prIntEventMap->u4Event == INT_EVENT_RX && prAdapter->fgIsEnterD3ReqIssued == true*/) + { + /* ignore */ + } else if (apfnEventFuncTable[prIntEventMap->u4Event] != NULL) { + apfnEventFuncTable[prIntEventMap->u4Event](prAdapter); + } else { + DBGLOG( + INTR, WARN, + "Empty INTR handler! ISAR bit#: %ld, event:%lu, func: 0x%x\n", + prIntEventMap->u4Int, prIntEventMap->u4Event, + apfnEventFuncTable[prIntEventMap->u4Event]); + + ASSERT(0); /* to trap any NULL interrupt handler + */ + } + prAdapter->u4IntStatus &= ~prIntEventMap->u4Int; + } + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Verify the CHIP ID + * + * @param prAdapter a pointer to adapter private data structure. + * + * + * @retval true CHIP ID is the same as the setting compiled + * @retval false CHIP ID is different from the setting compiled + */ +/*----------------------------------------------------------------------------*/ +u8 nicVerifyChipID(IN P_ADAPTER_T prAdapter) +{ + return halVerifyChipID(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Initialize the MCR to the appropriate init value, and verify the init + * value + * + * @param prAdapter a pointer to adapter private data structure. + * + * @return - + */ +/*----------------------------------------------------------------------------*/ +void nicMCRInit(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + /* 4 <0> Initial value */ +} + +void nicHifInit(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Initialize the Adapter soft variable + * + * @param prAdapter pointer to the Adapter handler + * + * @return (none) + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicInitializeAdapter(IN P_ADAPTER_T prAdapter) +{ + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + + prAdapter->fgIsIntEnableWithLPOwnSet = false; + prAdapter->fgIsReadRevID = false; + +#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1) + prAdapter->fgIsBufferBinExtract = false; + + prAdapter->u4EfuseMacAddrOffset = DEFAULT_EFUSE_MACADDR_OFFSET; +#endif + + do { + if (!nicVerifyChipID(prAdapter)) { + u4Status = WLAN_STATUS_FAILURE; + break; + } + /* 4 <1> MCR init */ + nicMCRInit(prAdapter); + + HAL_HIF_INIT(prAdapter); + + /* 4 <2> init FW HIF */ + nicHifInit(prAdapter); + } while (false); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process rx interrupt. When the rx + * Interrupt is asserted, it means there are frames in queue. + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicProcessAbnormalInterrupt(IN P_ADAPTER_T prAdapter) +{ + u32 u4Value; + + HAL_MCR_RD(prAdapter, MCR_WASR, &u4Value); + DBGLOG(REQ, WARN, "MCR_WASR: 0x%lx\n", u4Value); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief . + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicProcessSoftwareInterrupt(IN P_ADAPTER_T prAdapter) +{ + halProcessSoftwareInterrupt(prAdapter); +} + +void nicSetSwIntr(IN P_ADAPTER_T prAdapter, IN u32 u4SwIntrBitmap) +{ + /* NOTE: + * SW interrupt in HW bit 16 is mapping to SW bit 0 (shift 16bit in HW + * transparancy) SW interrupt valid from b0~b15 + */ + ASSERT((u4SwIntrBitmap & BITS(0, 15)) == 0); + /* DBGLOG(INIT, TRACE, ("u4SwIntrBitmap: 0x%08x\n", u4SwIntrBitmap)); */ + + HAL_MCR_WR(prAdapter, MCR_WSICR, u4SwIntrBitmap); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This procedure is used to dequeue from prAdapter->rPendingCmdQueue + * with specified sequential number + * + * @param prAdapter Pointer of ADAPTER_T + * ucSeqNum Sequential Number + * + * @retval - P_CMD_INFO_T + */ +/*----------------------------------------------------------------------------*/ +P_CMD_INFO_T nicGetPendingCmdInfo(IN P_ADAPTER_T prAdapter, IN u8 ucSeqNum) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + prCmdQue = &prAdapter->rPendingCmdQueue; + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->ucCmdSeqNum == ucSeqNum) { + break; + } + + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + + prCmdInfo = NULL; + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + QUEUE_CONCATENATE_QUEUES(prCmdQue, prTempCmdQue); + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING); + + return prCmdInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This procedure is used to dequeue from + * prAdapter->rTxCtrl.rTxMgmtTxingQueue with specified sequential number + * + * @param prAdapter Pointer of ADAPTER_T + * ucSeqNum Sequential Number + * + * @retval - P_MSDU_INFO_T + */ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T nicGetPendingTxMsduInfo(IN P_ADAPTER_T prAdapter, + IN u8 ucWlanIndex, IN u8 ucPID) +{ + P_QUE_T prTxingQue; + QUE_T rTempQue; + P_QUE_T prTempQue = &rTempQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); + QUEUE_MOVE_ALL(prTempQue, prTxingQue); + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + + if ((prMsduInfo->ucPID == ucPID) && + (prMsduInfo->ucWlanIndex == ucWlanIndex)) { + break; + } + + QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); + + prMsduInfo = NULL; + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + } + QUEUE_CONCATENATE_QUEUES(prTxingQue, prTempQue); + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + if (prMsduInfo) { + DBGLOG(TX, TRACE, "Get Msdu WIDX:PID[%u:%u] SEQ[%u] from Pending Q\n", + prMsduInfo->ucWlanIndex, prMsduInfo->ucPID, + prMsduInfo->ucTxSeqNum); + } else { + DBGLOG(TX, WARN, + "Cannot get Target Msdu WIDX:PID[%u:%u] from Pending Q\n", + ucWlanIndex, ucPID); + } + + return prMsduInfo; +} + +void nicFreePendingTxMsduInfoByBssIdx(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex) +{ + P_QUE_T prTxingQue; + QUE_T rTempQue; + P_QUE_T prTempQue = &rTempQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_MSDU_INFO_T prMsduInfoListHead = (P_MSDU_INFO_T)NULL; + P_MSDU_INFO_T prMsduInfoListTail = (P_MSDU_INFO_T)NULL; + P_MSDU_INFO_T prMsduInfo = (P_MSDU_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + prTxingQue = &(prAdapter->rTxCtrl.rTxMgmtTxingQueue); + QUEUE_MOVE_ALL(prTempQue, prTxingQue); + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + + if (prMsduInfo->ucBssIndex == ucBssIndex) { + DBGLOG(TX, TRACE, + "%s: Get Msdu WIDX:PID[%u:%u] SEQ[%u] from Pending Q\n", + __func__, prMsduInfo->ucWlanIndex, prMsduInfo->ucPID, + prMsduInfo->ucTxSeqNum); + + if (prMsduInfoListHead == NULL) { + prMsduInfoListHead = prMsduInfoListTail = prMsduInfo; + } else { + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfoListTail, prMsduInfo); + prMsduInfoListTail = prMsduInfo; + } + } else { + QUEUE_INSERT_TAIL(prTxingQue, prQueueEntry); + + prMsduInfo = NULL; + } + + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, P_QUE_ENTRY_T); + } + QUEUE_CONCATENATE_QUEUES(prTxingQue, prTempQue); + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + /* free */ + if (prMsduInfoListHead) { + nicTxFreeMsduInfoPacket(prAdapter, prMsduInfoListHead); + nicTxReturnMsduInfo(prAdapter, prMsduInfoListHead); + } + + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This procedure is used to retrieve a CMD sequence number atomically + * + * @param prAdapter Pointer of ADAPTER_T + * + * @retval - u8 + */ +/*----------------------------------------------------------------------------*/ +u8 nicIncreaseCmdSeqNum(IN P_ADAPTER_T prAdapter) +{ + u8 ucRetval; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_SEQ_NUM); + + prAdapter->ucCmdSeqNum++; + ucRetval = prAdapter->ucCmdSeqNum; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_SEQ_NUM); + + return ucRetval; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This procedure is used to retrieve a TX sequence number atomically + * + * @param prAdapter Pointer of ADAPTER_T + * + * @retval - u8 + */ +/*----------------------------------------------------------------------------*/ +u8 nicIncreaseTxSeqNum(IN P_ADAPTER_T prAdapter) +{ + u8 ucRetval; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_SEQ_NUM); + + ucRetval = prAdapter->ucTxSeqNum; + + prAdapter->ucTxSeqNum++; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_SEQ_NUM); + + return ucRetval; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to handle + * media state change event + * + * @param + * + * @retval + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicMediaStateChange(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN P_EVENT_CONNECTION_STATUS prConnectionStatus) +{ + P_GLUE_INFO_T prGlueInfo; + + ASSERT(prAdapter); + prGlueInfo = prAdapter->prGlueInfo; + + switch (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType) { + case NETWORK_TYPE_AIS: + if (prConnectionStatus->ucMediaStatus == + PARAM_MEDIA_STATE_DISCONNECTED) { /* disconnected */ + if (kalGetMediaStateIndicated(prGlueInfo) != + PARAM_MEDIA_STATE_DISCONNECTED) { + kalIndicateStatusAndComplete( + prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + + prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); + } + + /* reset buffered link quality information */ + prAdapter->fgIsLinkQualityValid = false; + prAdapter->fgIsLinkRateValid = false; + } else if (prConnectionStatus->ucMediaStatus == + PARAM_MEDIA_STATE_CONNECTED) { /* connected */ + prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); + + /* fill information for association result */ + prAdapter->rWlanInfo.rCurrBssId.rSsid.u4SsidLen = + prConnectionStatus->ucSsidLen; + kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.rSsid.aucSsid, + prConnectionStatus->aucSsid, + prConnectionStatus->ucSsidLen); + kalMemCopy(prAdapter->rWlanInfo.rCurrBssId.arMacAddress, + prConnectionStatus->aucBssid, MAC_ADDR_LEN); + prAdapter->rWlanInfo.rCurrBssId.u4Privacy = + prConnectionStatus->ucEncryptStatus; /* @FIXME + */ + prAdapter->rWlanInfo.rCurrBssId.rRssi = 0; /* @FIXME */ + prAdapter->rWlanInfo.rCurrBssId.eNetworkTypeInUse = + PARAM_NETWORK_TYPE_AUTOMODE; /* @FIXME */ + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4BeaconPeriod = + prConnectionStatus->u2BeaconPeriod; + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4ATIMWindow = + prConnectionStatus->u2ATIMWindow; + prAdapter->rWlanInfo.rCurrBssId.rConfiguration.u4DSConfig = + prConnectionStatus->u4FreqInKHz; + prAdapter->rWlanInfo.ucNetworkType = + prConnectionStatus->ucNetworkType; + prAdapter->rWlanInfo.rCurrBssId.eOpMode = + (ENUM_PARAM_OP_MODE_T)prConnectionStatus->ucInfraMode; + + /* always indicate to OS according to MSDN + * (re-association/roaming) */ + if (kalGetMediaStateIndicated(prGlueInfo) != + PARAM_MEDIA_STATE_CONNECTED) { + kalIndicateStatusAndComplete( + prGlueInfo, WLAN_STATUS_MEDIA_CONNECT, NULL, 0); + } else { + /* connected -> connected : roaming ? */ + kalIndicateStatusAndComplete( + prGlueInfo, WLAN_STATUS_ROAM_OUT_FIND_BEST, NULL, 0); + } + } + break; + +#if CFG_ENABLE_WIFI_DIRECT + case NETWORK_TYPE_P2P: + break; + +#endif + default: + ASSERT(0); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to generate a join failure event to OS + * + * @param + * + * @retval + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicMediaJoinFailure(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN WLAN_STATUS rStatus) +{ + P_GLUE_INFO_T prGlueInfo; + + ASSERT(prAdapter); + prGlueInfo = prAdapter->prGlueInfo; + + switch (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType) { + case NETWORK_TYPE_AIS: + kalIndicateStatusAndComplete(prGlueInfo, rStatus, NULL, 0); + + break; + + case NETWORK_TYPE_BOW: + case NETWORK_TYPE_P2P: + default: + break; + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to convert between + * frequency and channel number + * + * @param u4ChannelNum + * + * @retval - Frequency in unit of KHz, 0 for invalid channel number + */ +/*----------------------------------------------------------------------------*/ +u32 nicChannelNum2Freq(u32 u4ChannelNum) +{ + u32 u4ChannelInMHz; + + if (u4ChannelNum >= 1 && u4ChannelNum <= 13) { + u4ChannelInMHz = 2412 + (u4ChannelNum - 1) * 5; + } else if (u4ChannelNum == 14) { + u4ChannelInMHz = 2484; + } else if (u4ChannelNum == 133) { + u4ChannelInMHz = 3665; /* 802.11y */ + } else if (u4ChannelNum == 137) { + u4ChannelInMHz = 3685; /* 802.11y */ + } else if ((u4ChannelNum >= 34 && u4ChannelNum <= 181) || + (u4ChannelNum == 16)) { + u4ChannelInMHz = 5000 + u4ChannelNum * 5; + } else if (u4ChannelNum >= 182 && u4ChannelNum <= 196) { + u4ChannelInMHz = 4000 + u4ChannelNum * 5; + } else if (u4ChannelNum == 201) { + u4ChannelInMHz = 2730; + } else if (u4ChannelNum == 202) { + u4ChannelInMHz = 2498; + } else { + u4ChannelInMHz = 0; + } + + return 1000 * u4ChannelInMHz; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to convert between + * frequency and channel number + * + * @param u4FreqInKHz + * + * @retval - Frequency Number, 0 for invalid freqency + */ +/*----------------------------------------------------------------------------*/ +u32 nicFreq2ChannelNum(u32 u4FreqInKHz) +{ + switch (u4FreqInKHz) { + case 2412000: + return 1; + + case 2417000: + return 2; + + case 2422000: + return 3; + + case 2427000: + return 4; + + case 2432000: + return 5; + + case 2437000: + return 6; + + case 2442000: + return 7; + + case 2447000: + return 8; + + case 2452000: + return 9; + + case 2457000: + return 10; + + case 2462000: + return 11; + + case 2467000: + return 12; + + case 2472000: + return 13; + + case 2484000: + return 14; + + case 3665000: + return 133; /* 802.11y */ + + case 3685000: + return 137; /* 802.11y */ + + case 4915000: + return 183; + + case 4920000: + return 184; + + case 4925000: + return 185; + + case 4930000: + return 186; + + case 4935000: + return 187; + + case 4940000: + return 188; + + case 4945000: + return 189; + + case 4960000: + return 192; + + case 4980000: + return 196; + + case 5170000: + return 34; + + case 5180000: + return 36; + + case 5190000: + return 38; + + case 5200000: + return 40; + + case 5210000: + return 42; + + case 5220000: + return 44; + + case 5230000: + return 46; + + case 5240000: + return 48; + + case 5250000: + return 50; + + case 5260000: + return 52; + + case 5270000: + return 54; + + case 5280000: + return 56; + + case 5290000: + return 58; + + case 5300000: + return 60; + + case 5310000: + return 62; + + case 5320000: + return 64; + + case 5500000: + return 100; + + case 5510000: + return 102; + + case 5520000: + return 104; + + case 5530000: + return 106; + + case 5540000: + return 108; + + case 5550000: + return 110; + + case 5560000: + return 112; + + case 5570000: + return 114; + + case 5580000: + return 116; + + case 5590000: + return 118; + + case 5600000: + return 120; + + case 5610000: + return 122; + + case 5620000: + return 124; + + case 5630000: + return 126; + + case 5640000: + return 128; + + case 5660000: + return 132; + + case 5670000: + return 134; + + case 5680000: + return 136; + + case 5690000: + return 138; + + case 5700000: + return 140; + + case 5710000: + return 142; + + case 5720000: + return 144; + + case 5745000: + return 149; + + case 5755000: + return 151; + + case 5765000: + return 153; + + case 5775000: + return 155; + + case 5785000: + return 157; + + case 5795000: + return 159; + + case 5805000: + return 161; + + case 5825000: + return 165; + + case 5845000: + return 169; + + case 5865000: + return 173; + + default: + DBGLOG(BSS, INFO, "Return Invalid Channelnum = 0.\n"); + return 0; + } +} + +u8 nicGetVhtS1(u8 ucPrimaryChannel, u8 ucBandwidth) +{ + /* find S1 (central channel 42, 58, 106, 122, and 155) */ + + if ((ucBandwidth == VHT_OP_CHANNEL_WIDTH_80) || + (ucBandwidth == VHT_OP_CHANNEL_WIDTH_80P80)) { + if (ucPrimaryChannel >= 36 && ucPrimaryChannel <= 48) { + return 42; + } else if (ucPrimaryChannel >= 52 && ucPrimaryChannel <= 64) { + return 58; + } else if (ucPrimaryChannel >= 100 && ucPrimaryChannel <= 112) { + return 106; + } else if (ucPrimaryChannel >= 116 && ucPrimaryChannel <= 128) { + return 122; + } else if (ucPrimaryChannel >= 132 && ucPrimaryChannel <= 144) { + return 138; + } else if (ucPrimaryChannel >= 149 && ucPrimaryChannel <= 161) { + return 155; + } + } else if (ucBandwidth == VHT_OP_CHANNEL_WIDTH_160) { + if (ucPrimaryChannel >= 36 && ucPrimaryChannel <= 64) { + return 50; + } else if (ucPrimaryChannel >= 100 && ucPrimaryChannel <= 128) { + return 114; + } + } else { + return 0; + } + + return 0; +} + +/* firmware command wrapper */ +/* NETWORK (WIFISYS) */ +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to activate WIFISYS for specified + * network + * + * @param prAdapter Pointer of ADAPTER_T + * eNetworkTypeIdx Index of network type + * + * @retval - + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicActivateNetwork(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex) +{ + CMD_BSS_ACTIVATE_CTRL rCmdActivateCtrl; + P_BSS_INFO_T prBssInfo; + /* const u8 aucZeroMacAddr[] = NULL_MAC_ADDR; */ + + ASSERT(prAdapter); + ASSERT(IS_BSS_INDEX_VALID(ucBssIndex)); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + prBssInfo->fg40mBwAllowed = false; + prBssInfo->fgAssoc40mBwAllowed = false; + + rCmdActivateCtrl.ucBssIndex = ucBssIndex; + rCmdActivateCtrl.ucActive = 1; + rCmdActivateCtrl.ucNetworkType = (u8)prBssInfo->eNetworkType; + rCmdActivateCtrl.ucOwnMacAddrIndex = prBssInfo->ucOwnMacIndex; + COPY_MAC_ADDR(rCmdActivateCtrl.aucBssMacAddr, prBssInfo->aucOwnMacAddr); + + prBssInfo->ucBMCWlanIndex = secPrivacySeekForBcEntry( + prAdapter, prBssInfo->ucBssIndex, prBssInfo->aucOwnMacAddr, + STA_REC_INDEX_NOT_FOUND, CIPHER_SUITE_NONE, 0xFF); + + prBssInfo->ucBMCWlanIndexSUsed[0] = true; + + rCmdActivateCtrl.ucBMCWlanIndex = prBssInfo->ucBMCWlanIndex; + + kalMemZero(&rCmdActivateCtrl.ucReserved, + sizeof(rCmdActivateCtrl.ucReserved)); + + DBGLOG(RSN, INFO, "[wlan index][Network]=%d activate=%d\n", ucBssIndex, 1); + DBGLOG(RSN, INFO, + "[wlan index][Network] OwnMac=" MACSTR " BSSID=" MACSTR + " BMCIndex = %d NetType=%d\n", + MAC2STR(prBssInfo->aucOwnMacAddr), MAC2STR(prBssInfo->aucBSSID), + prBssInfo->ucBMCWlanIndex, prBssInfo->eNetworkType); + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_BSS_ACTIVATE_CTRL, true, false, + false, NULL, NULL, sizeof(CMD_BSS_ACTIVATE_CTRL), + (u8 *)&rCmdActivateCtrl, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to deactivate WIFISYS for specified + * network + * + * @param prAdapter Pointer of ADAPTER_T + * eNetworkTypeIdx Index of network type + * + * @retval - + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicDeactivateNetwork(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex) +{ + WLAN_STATUS u4Status; + CMD_BSS_ACTIVATE_CTRL rCmdActivateCtrl; + P_BSS_INFO_T prBssInfo; + + ASSERT(prAdapter); + ASSERT(IS_BSS_INDEX_VALID(ucBssIndex)); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + kalMemZero(&rCmdActivateCtrl, sizeof(CMD_BSS_ACTIVATE_CTRL)); + + rCmdActivateCtrl.ucBssIndex = ucBssIndex; + rCmdActivateCtrl.ucActive = 0; + + DBGLOG(RSN, INFO, "[wlan index][Network]=%d activate=%d\n", ucBssIndex, 0); + DBGLOG(RSN, INFO, + "[wlan index][Network] OwnMac=" MACSTR " BSSID=" MACSTR + " BMCIndex = %d\n", + MAC2STR(prBssInfo->aucOwnMacAddr), MAC2STR(prBssInfo->aucBSSID), + prBssInfo->ucBMCWlanIndex); + + rCmdActivateCtrl.ucOwnMacAddrIndex = prBssInfo->ucOwnMacIndex; + /* 20170628, if deactive bssid, do not reset NetworkType, otherwise we + * cannot free bcn */ + rCmdActivateCtrl.ucNetworkType = (u8)prBssInfo->eNetworkType; + + u4Status = wlanSendSetQueryCmd(prAdapter, CMD_ID_BSS_ACTIVATE_CTRL, true, + false, false, NULL, NULL, + sizeof(CMD_BSS_ACTIVATE_CTRL), + (u8 *)&rCmdActivateCtrl, NULL, 0); + + secRemoveBssBcEntry(prAdapter, prBssInfo, false); + + /* 20190301 To free all the correlated StaRec, + * clients (StaRec) in BSS client list also need to be removed from list + */ + bssInitializeClientList(prAdapter, prBssInfo); + + /* free all correlated station records */ + cnmStaFreeAllStaByNetwork(prAdapter, ucBssIndex, STA_REC_EXCLUDE_NONE); + if (HAL_IS_TX_DIRECT(prAdapter)) { + nicTxDirectClearBssAbsentQ(prAdapter, ucBssIndex); + } else { + qmFreeAllByBssIdx(prAdapter, ucBssIndex); + } + nicFreePendingTxMsduInfoByBssIdx(prAdapter, ucBssIndex); + kalClearSecurityFramesByBssIdx(prAdapter->prGlueInfo, ucBssIndex); +#if (CFG_HW_WMM_BY_BSS == 1) + cnmFreeWmmIndex(prAdapter, prBssInfo); +#endif + return u4Status; +} + +/* BSS-INFO */ +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to sync bss info with firmware + * when a new BSS has been connected or disconnected + * + * @param prAdapter Pointer of ADAPTER_T + * ucBssIndex Index of BSS-INFO + * + * @retval - + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicUpdateBss(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex) +{ + WLAN_STATUS u4Status = WLAN_STATUS_NOT_ACCEPTED; + P_BSS_INFO_T prBssInfo; + CMD_SET_BSS_INFO rCmdSetBssInfo; + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; + + ASSERT(prAdapter); + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + + if ((prBssInfo->eDBDCBand != ENUM_BAND_0) && + (prBssInfo->eDBDCBand != ENUM_BAND_1)) { + if (prBssInfo->eBand == BAND_2G4) { + prBssInfo->eDBDCBand = ENUM_BAND_0; + } else if (prBssInfo->eBand == BAND_5G) { + prBssInfo->eDBDCBand = ENUM_BAND_1; + } else { + DBGLOG(BSS, ERROR, "Wrong eDBDCBand - [%u]\n", prBssInfo->eDBDCBand); + prBssInfo->eDBDCBand = ENUM_BAND_0; /* Work around : temp + * solution */ + /*ASSERT(0);*/ /* FATAL ERROR */ + } + } + + kalMemZero(&rCmdSetBssInfo, sizeof(CMD_SET_BSS_INFO)); + + rCmdSetBssInfo.ucBssIndex = ucBssIndex; + rCmdSetBssInfo.ucConnectionState = (u8)prBssInfo->eConnectionState; + rCmdSetBssInfo.ucCurrentOPMode = (u8)prBssInfo->eCurrentOPMode; + rCmdSetBssInfo.ucSSIDLen = (u8)prBssInfo->ucSSIDLen; + kalMemCopy(rCmdSetBssInfo.aucSSID, prBssInfo->aucSSID, + prBssInfo->ucSSIDLen); + COPY_MAC_ADDR(rCmdSetBssInfo.aucBSSID, prBssInfo->aucBSSID); + rCmdSetBssInfo.ucIsQBSS = (u8)prBssInfo->fgIsQBSS; + rCmdSetBssInfo.ucNonHTBasicPhyType = prBssInfo->ucNonHTBasicPhyType; + rCmdSetBssInfo.u2OperationalRateSet = prBssInfo->u2OperationalRateSet; + rCmdSetBssInfo.u2BSSBasicRateSet = prBssInfo->u2BSSBasicRateSet; + rCmdSetBssInfo.u2HwDefaultFixedRateCode = + prBssInfo->u2HwDefaultFixedRateCode; + rCmdSetBssInfo.ucPhyTypeSet = prBssInfo->ucPhyTypeSet; + rCmdSetBssInfo.u4PrivateData = prBssInfo->u4PrivateData; +#if CFG_SUPPORT_DBDC + rCmdSetBssInfo.ucDBDCBand = prBssInfo->eDBDCBand; +#endif + rCmdSetBssInfo.ucWmmSet = prBssInfo->ucWmmQueSet; + rCmdSetBssInfo.ucNss = prBssInfo->ucNss; + + if (prBssInfo->fgBcDefaultKeyExist) { + if (prBssInfo->wepkeyUsed[prBssInfo->ucBcDefaultKeyIdx] && + prBssInfo->wepkeyWlanIdx < NIC_TX_DEFAULT_WLAN_INDEX) { + rCmdSetBssInfo.ucBMCWlanIndex = prBssInfo->wepkeyWlanIdx; + } else if (prBssInfo->ucBMCWlanIndexSUsed[prBssInfo->ucBcDefaultKeyIdx]) + { + rCmdSetBssInfo.ucBMCWlanIndex = + prBssInfo->ucBMCWlanIndexS[prBssInfo->ucBcDefaultKeyIdx]; + } + } else { + rCmdSetBssInfo.ucBMCWlanIndex = prBssInfo->ucBMCWlanIndex; + } + DBGLOG(RSN, TRACE, "Update BSS BMC WlanIdx %u\n", + rCmdSetBssInfo.ucBMCWlanIndex); + +#ifdef CFG_ENABLE_WIFI_DIRECT + rCmdSetBssInfo.ucHiddenSsidMode = prBssInfo->eHiddenSsidType; +#endif + rlmFillSyncCmdParam(&rCmdSetBssInfo.rBssRlmParam, prBssInfo); + + rCmdSetBssInfo.ucWapiMode = (u8)false; + + if ((prAdapter->prAisBssInfo != NULL) && + (rCmdSetBssInfo.ucBssIndex == prAdapter->prAisBssInfo->ucBssIndex)) { + P_CONNECTION_SETTINGS_T prConnSettings = + &(prAdapter->rWifiVar.rConnSettings); + + rCmdSetBssInfo.ucAuthMode = (u8)prConnSettings->eAuthMode; + rCmdSetBssInfo.ucEncStatus = (u8)prConnSettings->eEncStatus; + rCmdSetBssInfo.ucWapiMode = (u8)prConnSettings->fgWapiMode; + rCmdSetBssInfo.ucDisconnectDetectTh = + prWifiVar->ucStaDisconnectDetectTh; + } else { +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { +#if CFG_SUPPORT_SUITB + if (kalP2PGetGcmp256Cipher(prAdapter->prGlueInfo, + (u8)prBssInfo->u4PrivateData)) { + rCmdSetBssInfo.ucAuthMode = (u8)AUTH_MODE_WPA2_PSK; + rCmdSetBssInfo.ucEncStatus = (u8)ENUM_ENCRYPTION4_ENABLED; + } else +#endif + if (kalP2PGetCcmpCipher(prAdapter->prGlueInfo, + (u8)prBssInfo->u4PrivateData)) { + rCmdSetBssInfo.ucAuthMode = (u8)AUTH_MODE_WPA2_PSK; + rCmdSetBssInfo.ucEncStatus = (u8)ENUM_ENCRYPTION3_ENABLED; + } else if (kalP2PGetTkipCipher(prAdapter->prGlueInfo, + (u8)prBssInfo->u4PrivateData)) { + rCmdSetBssInfo.ucAuthMode = (u8)AUTH_MODE_WPA_PSK; + rCmdSetBssInfo.ucEncStatus = (u8)ENUM_ENCRYPTION2_ENABLED; + } else if (kalP2PGetWepCipher(prAdapter->prGlueInfo, + (u8)prBssInfo->u4PrivateData)) { + rCmdSetBssInfo.ucAuthMode = (u8)AUTH_MODE_OPEN; + rCmdSetBssInfo.ucEncStatus = (u8)ENUM_ENCRYPTION1_ENABLED; + } else { + rCmdSetBssInfo.ucAuthMode = (u8)AUTH_MODE_OPEN; + rCmdSetBssInfo.ucEncStatus = (u8)ENUM_ENCRYPTION_DISABLED; + } + /* Need the probe response to detect the PBC overlap */ + rCmdSetBssInfo.ucIsApMode = p2pFuncIsAPMode( + prAdapter->rWifiVar.prP2PConnSettings[prBssInfo->u4PrivateData]); + + if (rCmdSetBssInfo.ucIsApMode) { + rCmdSetBssInfo.ucDisconnectDetectTh = + prWifiVar->ucApDisconnectDetectTh; + } else { + rCmdSetBssInfo.ucDisconnectDetectTh = + prWifiVar->ucP2pDisconnectDetectTh; + } + } +#else + rCmdSetBssInfo.ucAuthMode = (u8)AUTH_MODE_WPA2_PSK; + rCmdSetBssInfo.ucEncStatus = (u8)ENUM_ENCRYPTION3_KEY_ABSENT; +#endif + } + + if ((prAdapter->prAisBssInfo != NULL) && + (ucBssIndex == prAdapter->prAisBssInfo->ucBssIndex) && + (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && + (prBssInfo->prStaRecOfAP != NULL)) { + rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; + } +#if CFG_ENABLE_WIFI_DIRECT + else if ((prAdapter->fgIsP2PRegistered) && + (prBssInfo->eNetworkType == NETWORK_TYPE_P2P) && + (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) && + (prBssInfo->prStaRecOfAP != NULL)) { + rCmdSetBssInfo.ucStaRecIdxOfAP = prBssInfo->prStaRecOfAP->ucIndex; + } +#endif + + else { + rCmdSetBssInfo.ucStaRecIdxOfAP = STA_REC_INDEX_NOT_FOUND; + } + + DBGLOG(BSS, INFO, + "Update Bss[%u] ConnState[%u] OPmode[%u] BSSID[" MACSTR + "] AuthMode[%u] EncStatus[%u]\n", + ucBssIndex, prBssInfo->eConnectionState, prBssInfo->eCurrentOPMode, + MAC2STR(prBssInfo->aucBSSID), rCmdSetBssInfo.ucAuthMode, + rCmdSetBssInfo.ucEncStatus); + + u4Status = wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_BSS_INFO, true, false, + false, NULL, NULL, sizeof(CMD_SET_BSS_INFO), + (u8 *)&rCmdSetBssInfo, NULL, 0); + + /* if BSS-INFO is going to be disconnected state, free all correlated + * station records */ + if (prBssInfo->eConnectionState == PARAM_MEDIA_STATE_DISCONNECTED) { + /* clear client list */ + bssInitializeClientList(prAdapter, prBssInfo); + +#if DBG + DBGLOG(BSS, TRACE, "nicUpdateBss for disconnect state\n"); +#endif + /* free all correlated station records */ + cnmStaFreeAllStaByNetwork(prAdapter, ucBssIndex, STA_REC_EXCLUDE_NONE); + if (HAL_IS_TX_DIRECT(prAdapter)) { + nicTxDirectClearBssAbsentQ(prAdapter, ucBssIndex); + } else { + qmFreeAllByBssIdx(prAdapter, ucBssIndex); + } + kalClearSecurityFramesByBssIdx(prAdapter->prGlueInfo, ucBssIndex); + +#if CFG_SUPPORT_DBDC + cnmDbdcDisableDecision(prAdapter, ucBssIndex); +#endif + } + + return u4Status; +} + +/* BSS-INFO Indication (PM) */ +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to indicate PM that + * a BSS has been created. (for AdHoc / P2P-GO) + * + * @param prAdapter Pointer of ADAPTER_T + * ucBssIndex Index of BSS-INFO + * + * @retval - + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicPmIndicateBssCreated(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex) +{ + P_BSS_INFO_T prBssInfo; + CMD_INDICATE_PM_BSS_CREATED rCmdIndicatePmBssCreated; + + kalMemZero(&rCmdIndicatePmBssCreated, sizeof(CMD_INDICATE_PM_BSS_CREATED)); + + ASSERT(prAdapter); + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + rCmdIndicatePmBssCreated.ucBssIndex = ucBssIndex; + rCmdIndicatePmBssCreated.ucDtimPeriod = prBssInfo->ucDTIMPeriod; + rCmdIndicatePmBssCreated.u2BeaconInterval = prBssInfo->u2BeaconInterval; + rCmdIndicatePmBssCreated.u2AtimWindow = prBssInfo->u2ATIMWindow; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_INDICATE_PM_BSS_CREATED, true, + false, false, NULL, NULL, + sizeof(CMD_INDICATE_PM_BSS_CREATED), + (u8 *)&rCmdIndicatePmBssCreated, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to indicate PM that + * a BSS has been connected + * + * @param prAdapter Pointer of ADAPTER_T + * eNetworkTypeIdx Index of BSS-INFO + * + * @retval - + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicPmIndicateBssConnected(IN P_ADAPTER_T prAdapter, + IN u8 ucBssIndex) +{ + P_BSS_INFO_T prBssInfo; + CMD_INDICATE_PM_BSS_CONNECTED rCmdIndicatePmBssConnected; + + kalMemZero(&rCmdIndicatePmBssConnected, + sizeof(CMD_INDICATE_PM_BSS_CONNECTED)); + + ASSERT(prAdapter); + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + rCmdIndicatePmBssConnected.ucBssIndex = ucBssIndex; + rCmdIndicatePmBssConnected.ucDtimPeriod = prBssInfo->ucDTIMPeriod; + rCmdIndicatePmBssConnected.u2AssocId = prBssInfo->u2AssocId; + rCmdIndicatePmBssConnected.u2BeaconInterval = prBssInfo->u2BeaconInterval; + rCmdIndicatePmBssConnected.u2AtimWindow = prBssInfo->u2ATIMWindow; + + rCmdIndicatePmBssConnected.ucBmpDeliveryAC = + prBssInfo->rPmProfSetupInfo.ucBmpDeliveryAC; + rCmdIndicatePmBssConnected.ucBmpTriggerAC = + prBssInfo->rPmProfSetupInfo.ucBmpTriggerAC; + + /* DBGPRINTF("nicPmIndicateBssConnected: ucBmpDeliveryAC:0x%x, + * ucBmpTriggerAC:0x%x", */ + /* rCmdIndicatePmBssConnected.ucBmpDeliveryAC, */ + /* rCmdIndicatePmBssConnected.ucBmpTriggerAC); */ + + if ((GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + NETWORK_TYPE_AIS) +#if CFG_ENABLE_WIFI_DIRECT + || ((GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType == + NETWORK_TYPE_P2P) && + (prAdapter->fgIsP2PRegistered)) +#endif + ) { + if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + rCmdIndicatePmBssConnected.fgIsUapsdConnection = + (u8)prBssInfo->prStaRecOfAP->fgIsUapsdSupported; + } else { + rCmdIndicatePmBssConnected.fgIsUapsdConnection = 0; /* @FIXME */ + } + } else { + rCmdIndicatePmBssConnected.fgIsUapsdConnection = 0; + } + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_INDICATE_PM_BSS_CONNECTED, + true, false, false, NULL, NULL, + sizeof(CMD_INDICATE_PM_BSS_CONNECTED), + (u8 *)&rCmdIndicatePmBssConnected, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to indicate PM that + * a BSS has been disconnected + * + * @param prAdapter Pointer of ADAPTER_T + * ucBssIndex Index of BSS-INFO + * + * @retval - + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicPmIndicateBssAbort(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex) +{ + CMD_INDICATE_PM_BSS_ABORT rCmdIndicatePmBssAbort; + + kalMemZero(&rCmdIndicatePmBssAbort, sizeof(CMD_INDICATE_PM_BSS_ABORT)); + + ASSERT(prAdapter); + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + + rCmdIndicatePmBssAbort.ucBssIndex = ucBssIndex; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_INDICATE_PM_BSS_ABORT, true, + false, false, NULL, NULL, + sizeof(CMD_INDICATE_PM_BSS_ABORT), + (u8 *)&rCmdIndicatePmBssAbort, NULL, 0); +} + +WLAN_STATUS +nicConfigPowerSaveProfile(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN PARAM_POWER_MODE ePwrMode, IN u8 fgEnCmdEvent) +{ + DEBUGFUNC("nicConfigPowerSaveProfile"); + DBGLOG(INIT, TRACE, "ucBssIndex:%d, ePwrMode:%d, fgEnCmdEvent:%d\n", + ucBssIndex, ePwrMode, fgEnCmdEvent); + + ASSERT(prAdapter); + + if (ucBssIndex >= BSS_INFO_NUM) { + ASSERT(0); + return WLAN_STATUS_NOT_SUPPORTED; + } + + prAdapter->rWlanInfo.arPowerSaveMode[ucBssIndex].ucBssIndex = + ucBssIndex; + prAdapter->rWlanInfo.arPowerSaveMode[ucBssIndex].ucPsProfile = + (u8)ePwrMode; +#ifdef SUPPORT_PERIODIC_PS + /* Always given these two field should be fine for other PSP. */ + prAdapter->rWlanInfo.arPowerSaveMode[ucBssIndex].ucPspCAMInt = + prAdapter->rWifiVar.ucAwakePspCAMInt; + prAdapter->rWlanInfo.arPowerSaveMode[ucBssIndex].ucPspPSInt = + prAdapter->rWifiVar.ucAwakePspPSInt; +#endif + + return wlanSendSetQueryCmd( + prAdapter, CMD_ID_POWER_SAVE_MODE, true, false, true, + (fgEnCmdEvent ? nicCmdEventSetCommon : NULL), + (fgEnCmdEvent ? nicOidCmdTimeoutCommon : NULL), + sizeof(CMD_PS_PROFILE_T), + (u8 *)&(prAdapter->rWlanInfo.arPowerSaveMode[ucBssIndex]), NULL, + sizeof(PARAM_POWER_MODE)); +} + +WLAN_STATUS +nicConfigPowerSaveWowProfile(IN P_ADAPTER_T prAdapter, u8 ucBssIndex, + PARAM_POWER_MODE ePwrMode, u8 fgEnCmdEvent, + u8 fgSuspend) +{ + CMD_PS_PROFILE_T rPowerSaveMode; + + kalMemZero(&rPowerSaveMode, sizeof(CMD_PS_PROFILE_T)); + + if (fgSuspend) { + rPowerSaveMode.ucBssIndex = ucBssIndex; + rPowerSaveMode.ucPsProfile = ePwrMode; +#ifdef SUPPORT_PERIODIC_PS + rPowerSaveMode.ucPspCAMInt = prAdapter->rWifiVar.ucPspCAMInt; + rPowerSaveMode.ucPspPSInt = prAdapter->rWifiVar.ucPspPSInt; +#endif + } else { + /* if resume, restore power save profile */ + DBGLOG(HAL, STATE, "Resume wow power save idx:%d, mode:%d\n", + ucBssIndex, + prAdapter->rWlanInfo.arPowerSaveMode[ucBssIndex].ucPsProfile); + kalMemCopy(&rPowerSaveMode, + &(prAdapter->rWlanInfo.arPowerSaveMode[ucBssIndex]), + sizeof(rPowerSaveMode)); + } + + /* if suspend, config power save mode w/o update + * arPowerSaveMode[ucBssIndex] */ + return wlanSendSetQueryCmd(prAdapter, CMD_ID_POWER_SAVE_MODE, true, false, + true, + (fgEnCmdEvent ? nicCmdEventSetCommon : NULL), + (fgEnCmdEvent ? nicOidCmdTimeoutCommon : NULL), + sizeof(CMD_PS_PROFILE_T), (u8 *)&rPowerSaveMode, + NULL, sizeof(PARAM_POWER_MODE)); +} + +WLAN_STATUS nicEnterCtiaMode(IN P_ADAPTER_T prAdapter, u8 fgEnterCtia, + u8 fgEnCmdEvent) +{ + CMD_SW_DBG_CTRL_T rCmdSwCtrl; + /* CMD_ACCESS_REG rCmdAccessReg; */ + WLAN_STATUS rWlanStatus; + + kalMemZero(&rCmdSwCtrl, sizeof(CMD_SW_DBG_CTRL_T)); + + DEBUGFUNC("nicEnterCtiaMode"); + DBGLOG(INIT, TRACE, "nicEnterCtiaMode: %d\n", fgEnterCtia); + + ASSERT(prAdapter); + + rWlanStatus = WLAN_STATUS_SUCCESS; + + if (fgEnterCtia) { + /* 1. Disable On-Lin Scan */ + prAdapter->fgEnOnlineScan = false; + + /* 2. Disable FIFO FULL no ack */ + /* 3. Disable Roaming */ + /* 4. Disalbe auto tx power */ + rCmdSwCtrl.u4Id = 0xa0100003; + rCmdSwCtrl.u4Data = 0x0; + wlanSendSetQueryCmd(prAdapter, CMD_ID_SW_DBG_CTRL, true, false, false, + NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), + (u8 *)&rCmdSwCtrl, NULL, 0); + + /* 2. Keep at CAM mode */ + { + PARAM_POWER_MODE ePowerMode; + + prAdapter->u4CtiaPowerMode = 0; + prAdapter->fgEnCtiaPowerMode = true; + + ePowerMode = Param_PowerModeCAM; + rWlanStatus = nicConfigPowerSaveProfile( + prAdapter, prAdapter->prAisBssInfo->ucBssIndex, ePowerMode, + fgEnCmdEvent); + } + + /* 5. Disable Beacon Timeout Detection */ + prAdapter->fgDisBcnLostDetection = true; + } else { + /* 1. Enaable On-Lin Scan */ + prAdapter->fgEnOnlineScan = true; + + /* 2. Enable FIFO FULL no ack */ + /* 3. Enable Roaming */ + /* 4. Enable auto tx power */ + /* */ + + rCmdSwCtrl.u4Id = 0xa0100003; + rCmdSwCtrl.u4Data = 0x1; + wlanSendSetQueryCmd(prAdapter, CMD_ID_SW_DBG_CTRL, true, false, false, + NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), + (u8 *)&rCmdSwCtrl, NULL, 0); + + /* 2. Keep at Fast PS */ + { + PARAM_POWER_MODE ePowerMode; + + prAdapter->u4CtiaPowerMode = 2; + prAdapter->fgEnCtiaPowerMode = true; + + ePowerMode = Param_PowerModeFast_PSP; + rWlanStatus = nicConfigPowerSaveProfile( + prAdapter, prAdapter->prAisBssInfo->ucBssIndex, ePowerMode, + fgEnCmdEvent); + } + + /* 5. Enable Beacon Timeout Detection */ + prAdapter->fgDisBcnLostDetection = false; + } + + return rWlanStatus; +} + +WLAN_STATUS nicEnterTPTestMode(IN P_ADAPTER_T prAdapter, IN u8 ucFuncMask) +{ + CMD_SW_DBG_CTRL_T rCmdSwCtrl; + WLAN_STATUS rWlanStatus; + u8 ucBssIdx; + P_BSS_INFO_T prBssInfo; + + kalMemZero(&rCmdSwCtrl, sizeof(CMD_SW_DBG_CTRL_T)); + + ASSERT(prAdapter); + + rWlanStatus = WLAN_STATUS_SUCCESS; + + if (ucFuncMask) { + /* 1. Disable On-Lin Scan */ + if (ucFuncMask & TEST_MODE_DISABLE_ONLINE_SCAN) { + prAdapter->fgEnOnlineScan = false; + } + + /* 2. Disable Roaming */ + if (ucFuncMask & TEST_MODE_DISABLE_ROAMING) { + rCmdSwCtrl.u4Id = 0xa0210000; + rCmdSwCtrl.u4Data = 0x0; + wlanSendSetQueryCmd(prAdapter, CMD_ID_SW_DBG_CTRL, true, false, + false, NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), + (u8 *)&rCmdSwCtrl, NULL, 0); + } + /* 3. Keep at CAM mode */ + if (ucFuncMask & TEST_MODE_FIXED_CAM_MODE) { + for (ucBssIdx = 0; ucBssIdx < BSS_INFO_NUM; ucBssIdx++) { + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIdx); + if (prBssInfo->fgIsInUse && + (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE)) { + nicConfigPowerSaveProfile(prAdapter, ucBssIdx, + Param_PowerModeCAM, false); + } + } + } + + /* 4. Disable Beacon Timeout Detection */ + if (ucFuncMask & TEST_MODE_DISABLE_BCN_LOST_DET) { + prAdapter->fgDisBcnLostDetection = true; + } + } else { + /* 1. Enaable On-Lin Scan */ + prAdapter->fgEnOnlineScan = true; + + /* 2. Enable Roaming */ + rCmdSwCtrl.u4Id = 0xa0210000; + rCmdSwCtrl.u4Data = 0x1; + wlanSendSetQueryCmd(prAdapter, CMD_ID_SW_DBG_CTRL, true, false, false, + NULL, NULL, sizeof(CMD_SW_DBG_CTRL_T), + (u8 *)&rCmdSwCtrl, NULL, 0); + + /* 3. Keep at Fast PS */ + for (ucBssIdx = 0; ucBssIdx < BSS_INFO_NUM; ucBssIdx++) { + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIdx); + if (prBssInfo->fgIsInUse && + (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE)) { + nicConfigPowerSaveProfile(prAdapter, ucBssIdx, + Param_PowerModeFast_PSP, false); + } + } + + /* 4. Enable Beacon Timeout Detection */ + prAdapter->fgDisBcnLostDetection = false; + } + + return rWlanStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to indicate firmware domain + * for beacon generation parameters + * + * @param prAdapter Pointer of ADAPTER_T + * eIeUpdMethod, Update Method + * ucBssIndex Index of BSS-INFO + * u2Capability Capability + * aucIe Pointer to buffer of IEs + * u2IELen Length of IEs + * + * @retval - WLAN_STATUS_SUCCESS + * WLAN_STATUS_FAILURE + * WLAN_STATUS_PENDING + * WLAN_STATUS_INVALID_DATA + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdateBeaconIETemplate(IN P_ADAPTER_T prAdapter, + IN ENUM_IE_UPD_METHOD_T eIeUpdMethod, + IN u8 ucBssIndex, IN u16 u2Capability, IN u8 *aucIe, + IN u16 u2IELen) +{ + P_CMD_BEACON_TEMPLATE_UPDATE prCmdBcnUpdate; + u16 u2CmdBufLen = 0; + P_GLUE_INFO_T prGlueInfo; + P_CMD_INFO_T prCmdInfo; + P_WIFI_CMD_T prWifiCmd; + u8 ucCmdSeqNum; + + DEBUGFUNC("wlanUpdateBeaconIETemplate"); + DBGLOG(INIT, LOUD, "\n"); + + ASSERT(prAdapter); + prGlueInfo = prAdapter->prGlueInfo; + + if (u2IELen > MAX_IE_LENGTH) { + return WLAN_STATUS_INVALID_DATA; + } + + if (eIeUpdMethod == IE_UPD_METHOD_UPDATE_RANDOM || + eIeUpdMethod == IE_UPD_METHOD_UPDATE_ALL) { + u2CmdBufLen = OFFSET_OF(CMD_BEACON_TEMPLATE_UPDATE, aucIE) + u2IELen; + } else if (eIeUpdMethod == IE_UPD_METHOD_DELETE_ALL) { + u2CmdBufLen = OFFSET_OF(CMD_BEACON_TEMPLATE_UPDATE, u2IELen); + } else { + DBGLOG(INIT, ERROR, "Unknown IeUpdMethod.\n"); + return WLAN_STATUS_FAILURE; + } + + /* prepare command info */ + prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + u2CmdBufLen)); + if (!prCmdInfo) { + DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n"); + return WLAN_STATUS_FAILURE; + } + /* increase command sequence number */ + ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter); + DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum); + + /* Setup common CMD Info Packet */ + prCmdInfo->eCmdType = COMMAND_TYPE_NETWORK_IOCTL; + prCmdInfo->u2InfoBufLen = (u16)(CMD_HDR_SIZE + u2CmdBufLen); + prCmdInfo->pfCmdDoneHandler = NULL; /* @FIXME */ + prCmdInfo->pfCmdTimeoutHandler = NULL; /* @FIXME */ + prCmdInfo->fgIsOid = false; + prCmdInfo->ucCID = CMD_ID_UPDATE_BEACON_CONTENT; + prCmdInfo->fgSetQuery = true; + prCmdInfo->fgNeedResp = false; + prCmdInfo->ucCmdSeqNum = ucCmdSeqNum; + prCmdInfo->u4SetInfoLen = u2CmdBufLen; + prCmdInfo->pvInformationBuffer = NULL; + prCmdInfo->u4InformationBufferLength = 0; + + /* Setup WIFI_CMD_T (no payload) */ + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen; + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucCID = prCmdInfo->ucCID; + prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery; + prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum; + + prCmdBcnUpdate = (P_CMD_BEACON_TEMPLATE_UPDATE)(prWifiCmd->aucBuffer); + + /* fill beacon updating command */ + prCmdBcnUpdate->ucUpdateMethod = (u8)eIeUpdMethod; + prCmdBcnUpdate->ucBssIndex = ucBssIndex; + prCmdBcnUpdate->u2Capability = u2Capability; + prCmdBcnUpdate->u2IELen = u2IELen; + if (u2IELen > 0) { + kalMemCopy(prCmdBcnUpdate->aucIE, aucIe, u2IELen); + } + /* insert into prCmdQueue */ + kalEnqueueCommand(prGlueInfo, (P_QUE_ENTRY_T)prCmdInfo); + + /* wakeup txServiceThread later */ + GLUE_SET_EVENT(prGlueInfo); + return WLAN_STATUS_PENDING; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to initialization PHY related + * varaibles + * + * @param prAdapter Pointer of ADAPTER_T + * + * @retval none + */ +/*----------------------------------------------------------------------------*/ +void nicSetAvailablePhyTypeSet(IN P_ADAPTER_T prAdapter) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + + ASSERT(prAdapter); + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + + if (prConnSettings->eDesiredPhyConfig >= PHY_CONFIG_NUM) { + ASSERT(0); + return; + } + + prAdapter->rWifiVar.ucAvailablePhyTypeSet = + aucPhyCfg2PhyTypeSet[prConnSettings->eDesiredPhyConfig]; + + if (prAdapter->rWifiVar.ucAvailablePhyTypeSet & PHY_TYPE_BIT_ERP) { + prAdapter->rWifiVar.eNonHTBasicPhyType2G4 = PHY_TYPE_ERP_INDEX; + } + /* NOTE(Kevin): Because we don't have N only mode, TBD */ + else { /* if (ucNonHTPhyTypeSet & PHY_TYPE_HR_DSSS_INDEX) */ + prAdapter->rWifiVar.eNonHTBasicPhyType2G4 = PHY_TYPE_HR_DSSS_INDEX; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to update WMM Parms + * + * @param prAdapter Pointer of ADAPTER_T + * ucBssIndex Index of BSS-INFO + * + * @retval - + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicQmUpdateWmmParms(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex) +{ + P_BSS_INFO_T prBssInfo; + CMD_UPDATE_WMM_PARMS_T rCmdUpdateWmmParms; + + kalMemZero(&rCmdUpdateWmmParms, sizeof(CMD_UPDATE_WMM_PARMS_T)); + + ASSERT(prAdapter); + + DBGLOG(QM, INFO, "Update WMM parameters for BSS[%u]\n", ucBssIndex); + + DBGLOG(QM, EVENT, "sizeof(AC_QUE_PARMS_T): %d\n", sizeof(AC_QUE_PARMS_T)); + DBGLOG(QM, EVENT, "sizeof(CMD_UPDATE_WMM_PARMS): %d\n", + sizeof(CMD_UPDATE_WMM_PARMS_T)); + DBGLOG(QM, EVENT, "sizeof(WIFI_CMD_T): %d\n", sizeof(WIFI_CMD_T)); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + rCmdUpdateWmmParms.ucBssIndex = (u8)ucBssIndex; + kalMemCopy(&rCmdUpdateWmmParms.arACQueParms[0], &prBssInfo->arACQueParms[0], + (sizeof(AC_QUE_PARMS_T) * AC_NUM)); + + rCmdUpdateWmmParms.fgIsQBSS = prBssInfo->fgIsQBSS; + rCmdUpdateWmmParms.ucWmmSet = (u8)prBssInfo->ucWmmQueSet; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_UPDATE_WMM_PARMS, true, false, + false, NULL, NULL, + sizeof(CMD_UPDATE_WMM_PARMS_T), + (u8 *)&rCmdUpdateWmmParms, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to update TX power gain corresponding to + * each band/modulation combination + * + * @param prAdapter Pointer of ADAPTER_T + * prTxPwrParam Pointer of TX power parameters + * + * @retval WLAN_STATUS_PENDING + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicUpdateTxPower(IN P_ADAPTER_T prAdapter, + IN P_CMD_TX_PWR_T prTxPwrParam) +{ + DEBUGFUNC("nicUpdateTxPower"); + + ASSERT(prAdapter); + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_TX_PWR, true, false, false, + NULL, NULL, sizeof(CMD_TX_PWR_T), + (u8 *)prTxPwrParam, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to set auto tx power parameter + * + * @param prAdapter Pointer of ADAPTER_T + * prTxPwrParam Pointer of Auto TX power parameters + * + * @retval WLAN_STATUS_PENDING + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicSetAutoTxPower(IN P_ADAPTER_T prAdapter, + IN P_CMD_AUTO_POWER_PARAM_T prAutoPwrParam) +{ + DEBUGFUNC("nicSetAutoTxPower"); + + ASSERT(prAdapter); + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_AUTOPWR_CTRL, true, false, + false, NULL, NULL, + sizeof(CMD_AUTO_POWER_PARAM_T), + (u8 *)prAutoPwrParam, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to update TX power gain corresponding to + * each band/modulation combination + * + * @param prAdapter Pointer of ADAPTER_T + * prTxPwrParam Pointer of TX power parameters + * + * @retval WLAN_STATUS_PENDING + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicSetAutoTxPowerControl(IN P_ADAPTER_T prAdapter, + IN P_CMD_TX_PWR_T prTxPwrParam) +{ + DEBUGFUNC("nicUpdateTxPower"); + + ASSERT(prAdapter); + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_TX_PWR, true, false, false, + NULL, NULL, sizeof(CMD_TX_PWR_T), + (u8 *)prTxPwrParam, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to update power offset around 5GHz band + * + * @param prAdapter Pointer of ADAPTER_T + * pr5GPwrOffset Pointer of 5GHz power offset parameter + * + * @retval WLAN_STATUS_PENDING + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicUpdate5GOffset(IN P_ADAPTER_T prAdapter, + IN P_CMD_5G_PWR_OFFSET_T pr5GPwrOffset) +{ + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to update DPD calibration result + * + * @param prAdapter Pointer of ADAPTER_T + * pr5GPwrOffset Pointer of parameter for DPD calibration result + * + * @retval WLAN_STATUS_PENDING + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicUpdateDPD(IN P_ADAPTER_T prAdapter, + IN P_CMD_PWR_PARAM_T prDpdCalResult) +{ + DEBUGFUNC("nicUpdateDPD"); + + ASSERT(prAdapter); + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_PWR_PARAM, true, false, + false, NULL, NULL, sizeof(CMD_PWR_PARAM_T), + (u8 *)prDpdCalResult, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function starts system service such as timer and + * memory pools + * + * @param prAdapter Pointer of ADAPTER_T + * + * @retval none + */ +/*----------------------------------------------------------------------------*/ +void nicInitSystemService(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + /* <1> Initialize MGMT Memory pool and STA_REC */ + cnmMemInit(prAdapter); + cnmStaRecInit(prAdapter); + cmdBufInitialize(prAdapter); + + /* <2> Mailbox Initialization */ + mboxInitialize(prAdapter); + + /* <3> Timer Initialization */ + cnmTimerInitialize(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function reset some specific system service, + * such as STA-REC + * + * @param prAdapter Pointer of ADAPTER_T + * + * @retval none + */ +/*----------------------------------------------------------------------------*/ +void nicResetSystemService(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to update WMM Parms + * + * @param prAdapter Pointer of ADAPTER_T + * + * @retval none + */ +/*----------------------------------------------------------------------------*/ +void nicUninitSystemService(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + /* Timer Destruction */ + cnmTimerDestroy(prAdapter); + + /* Mailbox Destruction */ + mboxDestroy(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to update WMM Parms + * + * @param prAdapter Pointer of ADAPTER_T + * + * @retval none + */ +/*----------------------------------------------------------------------------*/ +void nicInitMGMT(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo) +{ + ASSERT(prAdapter); + + /* CNM Module - initialization */ + cnmInit(prAdapter); + + /* RLM Module - initialization */ + rlmFsmEventInit(prAdapter); + + /* SCN Module - initialization */ + scnInit(prAdapter); + + /* AIS Module - intiailization */ + aisFsmInit(prAdapter); + aisInitializeConnectionSettings(prAdapter, prRegInfo); + +#if CFG_SUPPORT_ROAMING + /* Roaming Module - intiailization */ + roamingFsmInit(prAdapter); +#endif + +#if CFG_SUPPORT_SWCR + swCrDebugInit(prAdapter); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to update WMM Parms + * + * @param prAdapter Pointer of ADAPTER_T + * + * @retval none + */ +/*----------------------------------------------------------------------------*/ +void nicUninitMGMT(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + +#if CFG_SUPPORT_SWCR + swCrDebugUninit(prAdapter); +#endif + +#if CFG_SUPPORT_ROAMING + /* Roaming Module - unintiailization */ + roamingFsmUninit(prAdapter); +#endif + + /* AIS Module - unintiailization */ + aisFsmUninit(prAdapter); + + /* SCN Module - unintiailization */ + scnUninit(prAdapter); + + /* RLM Module - uninitialization */ + rlmFsmEventUninit(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is invoked to buffer scan result + * + * @param prAdapter Pointer to the Adapter structure. + * @param rMacAddr BSSID + * @param prSsid Pointer to SSID + * @param u4Privacy Privacy settings (0: Open / 1: WEP/WPA/WPA2 + * enabled) + * @param rRssi Received Strength (-10 ~ -200 dBm) + * @param eNetworkType Network Type (a/b/g) + * @param prConfiguration Network Parameter + * @param eOpMode Infra/Ad-Hoc + * @param rSupportedRates Supported basic rates + * @param u2IELength IE Length + * @param pucIEBuf Pointer to Information Elements(IEs) + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicAddScanResult(IN P_ADAPTER_T prAdapter, IN PARAM_MAC_ADDRESS rMacAddr, + IN P_PARAM_SSID_T prSsid, IN u32 u4Privacy, + IN PARAM_RSSI rRssi, + IN ENUM_PARAM_NETWORK_TYPE_T eNetworkType, + IN P_PARAM_802_11_CONFIG_T prConfiguration, + IN ENUM_PARAM_OP_MODE_T eOpMode, + IN PARAM_RATES_EX rSupportedRates, IN u16 u2IELength, + IN u8 *pucIEBuf) +{ + u8 bReplace; + u32 i; + u32 u4IdxWeakest = 0; + PARAM_RSSI rWeakestRssi; + u32 u4BufferSize; + + ASSERT(prAdapter); + + rWeakestRssi = (PARAM_RSSI)INT_MAX; + u4BufferSize = ARRAY_SIZE(prAdapter->rWlanInfo.aucScanIEBuf); + + bReplace = false; + + /* decide to replace or add */ + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { + /* find weakest entry && not connected one */ + if (UNEQUAL_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, + prAdapter->rWlanInfo.rCurrBssId.arMacAddress) && + prAdapter->rWlanInfo.arScanResult[i].rRssi < rWeakestRssi) { + u4IdxWeakest = i; + rWeakestRssi = prAdapter->rWlanInfo.arScanResult[i].rRssi; + } + + if (prAdapter->rWlanInfo.arScanResult[i].eOpMode == eOpMode && + EQUAL_MAC_ADDR(&(prAdapter->rWlanInfo.arScanResult[i].arMacAddress), + rMacAddr) && + (EQUAL_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, + prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, + prSsid->aucSsid, prSsid->u4SsidLen) || + prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen == 0)) { + /* replace entry */ + bReplace = true; + + /* free IE buffer then zero */ + nicFreeScanResultIE(prAdapter, i); + kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + /* then fill buffer */ + prAdapter->rWlanInfo.arScanResult[i].u4Length = + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; + COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, + rMacAddr); + COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, + prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, + prSsid->aucSsid, prSsid->u4SsidLen); + prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; + prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; + prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = + eNetworkType; + kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), + prConfiguration, sizeof(PARAM_802_11_CONFIG_T)); + prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; + kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), + rSupportedRates, sizeof(PARAM_RATES_EX)); + prAdapter->rWlanInfo.arScanResult[i].u4IELength = (u32)u2IELength; + + /* IE - allocate buffer and update pointer */ + if (u2IELength > 0) { + if (ALIGN_4(u2IELength) + + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= + u4BufferSize) { + kalMemCopy(&(prAdapter->rWlanInfo + .aucScanIEBuf[prAdapter->rWlanInfo + .u4ScanIEBufferUsage]), + pucIEBuf, u2IELength); + + prAdapter->rWlanInfo.apucScanResultIEs[i] = + &(prAdapter->rWlanInfo.aucScanIEBuf + [prAdapter->rWlanInfo.u4ScanIEBufferUsage]); + + prAdapter->rWlanInfo.u4ScanIEBufferUsage += + ALIGN_4(u2IELength); + } else { + /* buffer is not enough */ + prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; + prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + } else { + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + + break; + } + } + + if (bReplace == false) { + if (prAdapter->rWlanInfo.u4ScanResultNum < (CFG_MAX_NUM_BSS_LIST - 1)) { + i = prAdapter->rWlanInfo.u4ScanResultNum; + + /* zero */ + kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + /* then fill buffer */ + prAdapter->rWlanInfo.arScanResult[i].u4Length = + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; + COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, + rMacAddr); + COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, + prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, + prSsid->aucSsid, prSsid->u4SsidLen); + prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; + prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; + prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = + eNetworkType; + kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), + prConfiguration, sizeof(PARAM_802_11_CONFIG_T)); + prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; + kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), + rSupportedRates, sizeof(PARAM_RATES_EX)); + prAdapter->rWlanInfo.arScanResult[i].u4IELength = (u32)u2IELength; + + /* IE - allocate buffer and update pointer */ + if (u2IELength > 0) { + if (ALIGN_4(u2IELength) + + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= + u4BufferSize) { + kalMemCopy(&(prAdapter->rWlanInfo + .aucScanIEBuf[prAdapter->rWlanInfo + .u4ScanIEBufferUsage]), + pucIEBuf, u2IELength); + + prAdapter->rWlanInfo.apucScanResultIEs[i] = + &(prAdapter->rWlanInfo.aucScanIEBuf + [prAdapter->rWlanInfo.u4ScanIEBufferUsage]); + + prAdapter->rWlanInfo.u4ScanIEBufferUsage += + ALIGN_4(u2IELength); + } else { + /* buffer is not enough */ + prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; + prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + } else { + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + + prAdapter->rWlanInfo.u4ScanResultNum++; + } else if (rWeakestRssi != (PARAM_RSSI)INT_MAX) { + /* replace weakest one */ + i = u4IdxWeakest; + + /* free IE buffer then zero */ + nicFreeScanResultIE(prAdapter, i); + kalMemZero(&(prAdapter->rWlanInfo.arScanResult[i]), + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs)); + + /* then fill buffer */ + prAdapter->rWlanInfo.arScanResult[i].u4Length = + OFFSET_OF(PARAM_BSSID_EX_T, aucIEs) + u2IELength; + COPY_MAC_ADDR(prAdapter->rWlanInfo.arScanResult[i].arMacAddress, + rMacAddr); + COPY_SSID(prAdapter->rWlanInfo.arScanResult[i].rSsid.aucSsid, + prAdapter->rWlanInfo.arScanResult[i].rSsid.u4SsidLen, + prSsid->aucSsid, prSsid->u4SsidLen); + prAdapter->rWlanInfo.arScanResult[i].u4Privacy = u4Privacy; + prAdapter->rWlanInfo.arScanResult[i].rRssi = rRssi; + prAdapter->rWlanInfo.arScanResult[i].eNetworkTypeInUse = + eNetworkType; + kalMemCopy(&(prAdapter->rWlanInfo.arScanResult[i].rConfiguration), + prConfiguration, sizeof(PARAM_802_11_CONFIG_T)); + prAdapter->rWlanInfo.arScanResult[i].eOpMode = eOpMode; + kalMemCopy((prAdapter->rWlanInfo.arScanResult[i].rSupportedRates), + rSupportedRates, sizeof(PARAM_RATES_EX)); + prAdapter->rWlanInfo.arScanResult[i].u4IELength = (u32)u2IELength; + + if (u2IELength > 0) { + /* IE - allocate buffer and update pointer */ + if (ALIGN_4(u2IELength) + + prAdapter->rWlanInfo.u4ScanIEBufferUsage <= + u4BufferSize) { + kalMemCopy(&(prAdapter->rWlanInfo + .aucScanIEBuf[prAdapter->rWlanInfo + .u4ScanIEBufferUsage]), + pucIEBuf, u2IELength); + + prAdapter->rWlanInfo.apucScanResultIEs[i] = + &(prAdapter->rWlanInfo.aucScanIEBuf + [prAdapter->rWlanInfo.u4ScanIEBufferUsage]); + + prAdapter->rWlanInfo.u4ScanIEBufferUsage += + ALIGN_4(u2IELength); + } else { + /* buffer is not enough */ + prAdapter->rWlanInfo.arScanResult[i].u4Length -= u2IELength; + prAdapter->rWlanInfo.arScanResult[i].u4IELength = 0; + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + } else { + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + } + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is invoked to free IE buffer for dedicated scan result + * + * @param prAdapter Pointer to the Adapter structure. + * @param u4Idx Index of Scan Result + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicFreeScanResultIE(IN P_ADAPTER_T prAdapter, IN u32 u4Idx) +{ + u32 i; + u8 *pucPivot, *pucMovePivot; + u32 u4MoveSize, u4FreeSize, u4ReserveSize; + + ASSERT(prAdapter); + ASSERT(u4Idx < CFG_MAX_NUM_BSS_LIST); + + if (prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength == 0 || + prAdapter->rWlanInfo.apucScanResultIEs[u4Idx] == NULL) { + return; + } + + u4FreeSize = ALIGN_4(prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength); + + pucPivot = prAdapter->rWlanInfo.apucScanResultIEs[u4Idx]; + pucMovePivot = + (u8 *)((unsigned long)(prAdapter->rWlanInfo.apucScanResultIEs[u4Idx]) + + u4FreeSize); + + u4ReserveSize = ((unsigned long)pucPivot) - + (unsigned long)(&(prAdapter->rWlanInfo.aucScanIEBuf[0])); + u4MoveSize = + prAdapter->rWlanInfo.u4ScanIEBufferUsage - u4ReserveSize - u4FreeSize; + + /* 1. rest of buffer to move forward */ + kalMemCopy(pucPivot, pucMovePivot, u4MoveSize); + + /* 1.1 modify pointers */ + for (i = 0; i < prAdapter->rWlanInfo.u4ScanResultNum; i++) { + if (i != u4Idx) { + if (prAdapter->rWlanInfo.apucScanResultIEs[i] >= pucMovePivot) { + prAdapter->rWlanInfo.apucScanResultIEs[i] = + (u8 *)((unsigned long)(prAdapter->rWlanInfo + .apucScanResultIEs[i]) - + u4FreeSize); + } + } + } + + /* 1.2 reset the freed one */ + prAdapter->rWlanInfo.arScanResult[u4Idx].u4IELength = 0; + prAdapter->rWlanInfo.apucScanResultIEs[i] = NULL; + + /* 2. reduce IE buffer usage */ + prAdapter->rWlanInfo.u4ScanIEBufferUsage -= u4FreeSize; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is to hack parameters for WLAN TABLE for + * fixed rate settings + * + * @param prAdapter Pointer to the Adapter structure. + * @param eRateSetting + * @param pu2DesiredNonHTRateSet, + * @param pu2BSSBasicRateSet, + * @param pucMcsSet + * @param pucSupMcs32 + * @param pu2HtCapInfo + * + * @return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicUpdateRateParams(IN P_ADAPTER_T prAdapter, + IN ENUM_REGISTRY_FIXED_RATE_T eRateSetting, + IN u8 *pucDesiredPhyTypeSet, IN u16 *pu2DesiredNonHTRateSet, + IN u16 *pu2BSSBasicRateSet, IN u8 *pucMcsSet, + IN u8 *pucSupMcs32, IN u16 *pu2HtCapInfo) +{ + ASSERT(prAdapter); + ASSERT(eRateSetting > FIXED_RATE_NONE && eRateSetting < FIXED_RATE_NUM); + + switch (prAdapter->rWifiVar.eRateSetting) { + case FIXED_RATE_1M: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_1M; + *pu2BSSBasicRateSet = RATE_SET_BIT_1M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_2M: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_2M; + *pu2BSSBasicRateSet = RATE_SET_BIT_2M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_5_5M: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_5_5M; + *pu2BSSBasicRateSet = RATE_SET_BIT_5_5M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_11M: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HR_DSSS; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_11M; + *pu2BSSBasicRateSet = RATE_SET_BIT_11M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_6M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_6M; + *pu2BSSBasicRateSet = RATE_SET_BIT_6M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_9M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_9M; + *pu2BSSBasicRateSet = RATE_SET_BIT_9M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_12M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_12M; + *pu2BSSBasicRateSet = RATE_SET_BIT_12M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_18M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_18M; + *pu2BSSBasicRateSet = RATE_SET_BIT_18M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_24M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_24M; + *pu2BSSBasicRateSet = RATE_SET_BIT_24M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_36M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_36M; + *pu2BSSBasicRateSet = RATE_SET_BIT_36M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_48M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_48M; + *pu2BSSBasicRateSet = RATE_SET_BIT_48M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_54M: + if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_ERP) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_ERP; + } else if ((*pucDesiredPhyTypeSet) & PHY_TYPE_BIT_OFDM) { + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_OFDM; + } + + *pu2DesiredNonHTRateSet = RATE_SET_BIT_54M; + *pu2BSSBasicRateSet = RATE_SET_BIT_54M; + *pucMcsSet = 0; + *pucSupMcs32 = 0; + *pu2HtCapInfo = 0; + break; + + case FIXED_RATE_MCS0_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS0_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= + ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS1_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS1_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= + ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS2_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS2_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= + ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS3_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS3_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= + ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS4_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS4_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= + ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS5_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS5_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= + ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS6_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS6_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= + ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS7_20M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS7_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= + ~(HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + break; + + case FIXED_RATE_MCS0_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS0_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS1_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS1_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS2_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS2_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS3_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS3_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS4_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS4_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS5_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS5_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS6_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS6_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS7_20M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS7_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SUP_CHNL_WIDTH | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SHORT_GI_20M; + break; + + case FIXED_RATE_MCS0_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS0_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS1_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS1_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS2_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS2_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS3_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS3_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS4_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS4_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS5_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS5_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS6_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS6_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS7_40M_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS7_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS32_800NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = 0; + *pucSupMcs32 = 1; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | + HT_CAP_INFO_SHORT_GI_40M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= HT_CAP_INFO_SUP_CHNL_WIDTH; + break; + + case FIXED_RATE_MCS0_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS0_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= + (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS1_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS1_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= + (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS2_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS2_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= + (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS3_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS3_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= + (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS4_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS4_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= + (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS5_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS5_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= + (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS6_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS6_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= + (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS7_40M_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = BIT(HT_RATE_MCS7_INDEX - 1); + *pucSupMcs32 = 0; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= + (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + case FIXED_RATE_MCS32_400NS: + *pucDesiredPhyTypeSet = PHY_TYPE_BIT_HT; + *pu2DesiredNonHTRateSet = RATE_SET_BIT_HT_PHY; + *pu2BSSBasicRateSet = RATE_SET_BIT_HT_PHY; + *pucMcsSet = 0; + *pucSupMcs32 = 1; + (*pu2HtCapInfo) &= ~(HT_CAP_INFO_SHORT_GI_20M | HT_CAP_INFO_HT_GF); + (*pu2HtCapInfo) |= + (HT_CAP_INFO_SUP_CHNL_WIDTH | HT_CAP_INFO_SHORT_GI_40M); + break; + + default: + ASSERT(0); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to write the register + * + * @param u4Address Register address + * u4Value the value to be written + * + * @retval WLAN_STATUS_SUCCESS + * WLAN_STATUS_FAILURE + */ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS nicWriteMcr(IN P_ADAPTER_T prAdapter, IN u32 u4Address, + IN u32 u4Value) +{ + CMD_ACCESS_REG rCmdAccessReg; + + rCmdAccessReg.u4Address = u4Address; + rCmdAccessReg.u4Data = u4Value; + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_ACCESS_REG, true, false, false, + NULL, NULL, sizeof(CMD_ACCESS_REG), + (u8 *)&rCmdAccessReg, NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to modify the auto rate parameters + * + * @param u4ArSysParam0 see description below + * u4ArSysParam1 + * u4ArSysParam2 + * u4ArSysParam3 + * + * + * @retval WLAN_STATUS_SUCCESS + * WLAN_STATUS_FAILURE + * + * @note + * ArSysParam0[0:3] -> auto rate version (0:disable 1:version1 2:version2) + * ArSysParam0[4:5]-> auto bw version (0:disable 1:version1 2:version2) + * ArSysParam0[6:7]-> auto gi version (0:disable 1:version1 2:version2) + * ArSysParam0[8:15]-> HT rate clear mask + * ArSysParam0[16:31]-> Legacy rate clear mask + * ArSysParam1[0:7]-> Auto Rate check weighting window + * ArSysParam1[8:15]-> Auto Rate v1 Force Rate down + * ArSysParam1[16:23]-> Auto Rate v1 PerH + * ArSysParam1[24:31]-> Auto Rate v1 PerL + * + * Examples + * ArSysParam0 = 1, + * Enable auto rate version 1 + * + * ArSysParam0 = 983041, + * Enable auto rate version 1 + * Remove CCK 1M, 2M, 5.5M, 11M + * + * ArSysParam0 = 786433 + * Enable auto rate version 1 + * Remove CCK 5.5M 11M + */ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS +nicRlmArUpdateParms(IN P_ADAPTER_T prAdapter, IN u32 u4ArSysParam0, + IN u32 u4ArSysParam1, IN u32 u4ArSysParam2, + IN u32 u4ArSysParam3) +{ + u8 ucArVer, ucAbwVer, ucAgiVer; + u16 u2HtClrMask; + u16 u2LegacyClrMask; + u8 ucArCheckWindow; + u8 ucArPerL; + u8 ucArPerH; + u8 ucArPerForceRateDownPer; + + ucArVer = (u8)(u4ArSysParam0 & BITS(0, 3)); + ucAbwVer = (u8)((u4ArSysParam0 & BITS(4, 5)) >> 4); + ucAgiVer = (u8)((u4ArSysParam0 & BITS(6, 7)) >> 6); + u2HtClrMask = (u16)((u4ArSysParam0 & BITS(8, 15)) >> 8); + u2LegacyClrMask = (u16)((u4ArSysParam0 & BITS(16, 31)) >> 16); + + ucArCheckWindow = (u8)(u4ArSysParam1 & BITS(0, 7)); + ucArPerForceRateDownPer = (u8)(((u4ArSysParam1 >> 8) & BITS(0, 7))); + ucArPerH = (u8)(((u4ArSysParam1 >> 16) & BITS(0, 7))); + ucArPerL = (u8)(((u4ArSysParam1 >> 24) & BITS(0, 7))); + + DBGLOG(INIT, INFO, "ArParam %ld %ld %ld %ld\n", u4ArSysParam0, + u4ArSysParam1, u4ArSysParam2, u4ArSysParam3); + DBGLOG(INIT, INFO, "ArVer %u AbwVer %u AgiVer %u\n", ucArVer, ucAbwVer, + ucAgiVer); + DBGLOG(INIT, INFO, "HtMask %x LegacyMask %x\n", u2HtClrMask, + u2LegacyClrMask); + DBGLOG(INIT, INFO, "CheckWin %u RateDownPer %u PerH %u PerL %u\n", + ucArCheckWindow, ucArPerForceRateDownPer, ucArPerH, ucArPerL); + +#define SWCR_DATA_ADDR(MOD, ADDR) (0x90000000 + (MOD << 8) + (ADDR)) +#define SWCR_DATA_CMD(CATE, WRITE, INDEX, OPT0, OPT1) \ + ((CATE << 24) | (WRITE << 23) | (INDEX << 16) | (OPT0 << 8) | OPT1) +#define SWCR_DATA0 0x0 +#define SWCR_DATA1 0x4 +#define SWCR_DATA2 0x8 +#define SWCR_DATA3 0xC +#define SWCR_DATA4 0x10 +#define SWCR_WRITE 1 +#define SWCR_READ 0 + + if (ucArVer > 0) { + /* dummy = WiFi.WriteMCR(&h90000104, &h00000001) */ + /* dummy = WiFi.WriteMCR(&h90000100, &h00850000) */ + + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), 1); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), + SWCR_DATA_CMD(0, SWCR_WRITE, 5, 0, 0)); + } else { + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), 0); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), + SWCR_DATA_CMD(0, SWCR_WRITE, 5, 0, 0)); + } + + /* ucArVer 0: none 1:PER 2:Rcpi */ + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), ucArVer); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), + SWCR_DATA_CMD(0, SWCR_WRITE, 7, 0, 0)); + + /* Candidate rate Ht mask */ + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), u2HtClrMask); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), + SWCR_DATA_CMD(0, SWCR_WRITE, 0x1c, 0, 0)); + + /* Candidate rate legacy mask */ + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA1), + u2LegacyClrMask); + nicWriteMcr(prAdapter, SWCR_DATA_ADDR(1 /*MOD*/, SWCR_DATA0), + SWCR_DATA_CMD(0, SWCR_WRITE, 0x1d, 0, 0)); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This utility function is used to enable roaming + * + * @param u4EnableRoaming + * + * + * @retval WLAN_STATUS_SUCCESS + * WLAN_STATUS_FAILURE + * + * @note + * u4EnableRoaming -> Enable Romaing + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicRoamingUpdateParams(IN P_ADAPTER_T prAdapter, + IN u32 u4EnableRoaming) +{ + P_CONNECTION_SETTINGS_T prConnSettings; + + prConnSettings = &(prAdapter->rWifiVar.rConnSettings); + prConnSettings->fgIsEnableRoaming = + ((u4EnableRoaming > 0) ? (true) : (false)); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to update Link Quality information + * + * @param prAdapter Pointer of Adapter Data Structure + * ucBssIndex + * prEventLinkQuality + * cRssi + * cLinkQuality + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void nicUpdateLinkQuality(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN P_EVENT_LINK_QUALITY_V2 prEventLinkQuality) +{ + s8 cRssi; + u16 u2AdjustRssi = 10; + + ASSERT(prAdapter); + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + ASSERT(prEventLinkQuality); + + switch (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType) { + case NETWORK_TYPE_AIS: + if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) { + /* check is to prevent RSSI to be updated by incorrect + * initial RSSI from hardware */ + /* buffer statistics for further query */ + if (prAdapter->fgIsLinkQualityValid == false || + (kalGetTimeTick() - prAdapter->rLinkQualityUpdateTime) > + CFG_LINK_QUALITY_VALID_PERIOD) { + /* ranged from (-128 ~ 30) in unit of dBm */ + cRssi = prEventLinkQuality->rLq[ucBssIndex].cRssi; + cRssi = (s8)(((s16)(cRssi) * u2AdjustRssi) / 10); + DBGLOG(RLM, INFO, "Rssi=%d, NewRssi=%d\n", + prEventLinkQuality->rLq[ucBssIndex].cRssi, cRssi); + nicUpdateRSSI(prAdapter, ucBssIndex, cRssi, + prEventLinkQuality->rLq[ucBssIndex].cLinkQuality); + } + + if (prAdapter->fgIsLinkRateValid == false || + (kalGetTimeTick() - prAdapter->rLinkRateUpdateTime) > + CFG_LINK_QUALITY_VALID_PERIOD) { + nicUpdateLinkSpeed( + prAdapter, ucBssIndex, + prEventLinkQuality->rLq[ucBssIndex].u2LinkSpeed); + } + } + break; + + default: + break; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to update RSSI and Link Quality information + * + * @param prAdapter Pointer of Adapter Data Structure + * ucBssIndex + * cRssi + * cLinkQuality + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void nicUpdateRSSI(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, IN s8 cRssi, + IN s8 cLinkQuality) +{ + ASSERT(prAdapter); + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + + switch (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType) { + case NETWORK_TYPE_AIS: + if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) { + prAdapter->fgIsLinkQualityValid = true; + prAdapter->rLinkQualityUpdateTime = kalGetTimeTick(); + + prAdapter->rLinkQuality.cRssi = cRssi; + prAdapter->rLinkQuality.cLinkQuality = cLinkQuality; + /* indicate to glue layer */ + kalUpdateRSSI(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_AIS_INDEX, + prAdapter->rLinkQuality.cRssi, + prAdapter->rLinkQuality.cLinkQuality); + } + + break; + +#if CFG_ENABLE_WIFI_DIRECT && CFG_SUPPORT_P2P_RSSI_QUERY + case NETWORK_TYPE_P2P: + prAdapter->fgIsP2pLinkQualityValid = true; + prAdapter->rP2pLinkQualityUpdateTime = kalGetTimeTick(); + + prAdapter->rP2pLinkQuality.cRssi = cRssi; + prAdapter->rP2pLinkQuality.cLinkQuality = cLinkQuality; + + kalUpdateRSSI(prAdapter->prGlueInfo, KAL_NETWORK_TYPE_P2P_INDEX, cRssi, + cLinkQuality); + break; + +#endif + default: + break; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to update Link Quality information + * + * @param prAdapter Pointer of Adapter Data Structure + * ucBssIndex + * prEventLinkQuality + * cRssi + * cLinkQuality + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void nicUpdateLinkSpeed(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, + IN u16 u2LinkSpeed) +{ + ASSERT(prAdapter); + ASSERT(ucBssIndex <= MAX_BSS_INDEX); + + switch (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eNetworkType) { + case NETWORK_TYPE_AIS: + if (GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex)->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) { + /* buffer statistics for further query */ + prAdapter->fgIsLinkRateValid = true; + prAdapter->rLinkRateUpdateTime = kalGetTimeTick(); + + prAdapter->rLinkQuality.u2LinkSpeed = u2LinkSpeed; + } + break; + + default: + break; + } +} + +#if CFG_SUPPORT_RDD_TEST_MODE +WLAN_STATUS nicUpdateRddTestMode(IN P_ADAPTER_T prAdapter, + IN P_CMD_RDD_CH_T prRddChParam) +{ + DEBUGFUNC("nicUpdateRddTestMode.\n"); + + ASSERT(prAdapter); + + /* aisFsmScanRequest(prAdapter, NULL); */ + + return wlanSendSetQueryCmd(prAdapter, CMD_ID_SET_RDD_CH, true, false, false, + NULL, NULL, sizeof(CMD_RDD_CH_T), + (u8 *)prRddChParam, NULL, 0); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to apply network address setting to + * both OS side and firmware domain + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return none + */ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS nicApplyNetworkAddress(IN P_ADAPTER_T prAdapter) +{ + u32 i; + + ASSERT(prAdapter); + + /* copy to adapter */ + COPY_MAC_ADDR(prAdapter->rMyMacAddr, prAdapter->rWifiVar.aucMacAddress); + + /* 4 <3> Update new MAC address to all 3 networks */ + COPY_MAC_ADDR(prAdapter->rWifiVar.aucDeviceAddress, prAdapter->rMyMacAddr); + prAdapter->rWifiVar.aucDeviceAddress[0] ^= MAC_ADDR_LOCAL_ADMIN; + + COPY_MAC_ADDR(prAdapter->rWifiVar.aucInterfaceAddress, + prAdapter->rMyMacAddr); + prAdapter->rWifiVar.aucInterfaceAddress[0] ^= MAC_ADDR_LOCAL_ADMIN; + +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + for (i = 0; i < BSS_INFO_NUM; i++) { + if (prAdapter->rWifiVar.arBssInfoPool[i].eNetworkType == + NETWORK_TYPE_P2P) { + COPY_MAC_ADDR( + prAdapter->rWifiVar.arBssInfoPool[i].aucOwnMacAddr, + prAdapter->rWifiVar.aucDeviceAddress); + } + } + } +#endif + +#if CFG_TEST_WIFI_DIRECT_GO + if (prAdapter->rWifiVar.prP2pFsmInfo->eCurrentState == P2P_STATE_IDLE) { + wlanEnableP2pFunction(prAdapter); + + wlanEnableATGO(prAdapter); + } +#endif + + kalUpdateMACAddress(prAdapter->prGlueInfo, + prAdapter->rWifiVar.aucMacAddress); + + return WLAN_STATUS_SUCCESS; +} + +u8 nicGetChipHwVer(void) +{ + return g_eco_info.ucHwVer; +} + +u8 nicGetChipSwVer(void) +{ + return g_eco_info.ucRomVer; +} + +u8 nicGetChipFactoryVer(void) +{ + return g_eco_info.ucFactoryVer; +} + +u8 nicSetChipHwVer(u8 value) +{ + g_eco_info.ucHwVer = value; + return 0; +} + +u8 nicSetChipSwVer(u8 value) +{ + g_eco_info.ucRomVer = value; + return 0; +} + +u8 nicSetChipFactoryVer(u8 value) +{ + g_eco_info.ucFactoryVer = value; + return 0; +} + +u8 nicGetChipEcoVer(IN P_ADAPTER_T prAdapter) +{ + P_ECO_INFO_T prEcoInfo; + u8 ucEcoVer; + u8 ucCurSwVer, ucCurHwVer, ucCurFactoryVer; + + ucCurSwVer = nicGetChipSwVer(); + ucCurHwVer = nicGetChipHwVer(); + ucCurFactoryVer = nicGetChipFactoryVer(); + + ucEcoVer = 0; + + while (true) { + /* Get ECO info from table */ + prEcoInfo = (P_ECO_INFO_T)&(prAdapter->chip_info->eco_info[ucEcoVer]); + + if ((prEcoInfo->ucRomVer == 0) && (prEcoInfo->ucHwVer == 0) && + (prEcoInfo->ucFactoryVer == 0)) { + /* End of table */ + break; + } + + if ((prEcoInfo->ucRomVer == ucCurSwVer) && + (prEcoInfo->ucHwVer == ucCurHwVer) && + (prEcoInfo->ucFactoryVer == ucCurFactoryVer)) { + break; + } + + ucEcoVer++; + } + return prAdapter->chip_info->eco_info[ucEcoVer].ucEcoVer; +} + +u8 nicIsEcoVerEqualTo(IN P_ADAPTER_T prAdapter, u8 ucEcoVer) +{ + if (ucEcoVer == prAdapter->chip_info->eco_ver) { + return true; + } else { + return false; + } +} + +u8 nicIsEcoVerEqualOrLaterTo(IN P_ADAPTER_T prAdapter, u8 ucEcoVer) +{ + if (ucEcoVer <= prAdapter->chip_info->eco_ver) { + return true; + } else { + return false; + } +} + +void nicSerStopTxRx(IN P_ADAPTER_T prAdapter) +{ + DBGLOG(NIC, WARN, "SER: Stop HIF Tx/Rx!\n"); + + prAdapter->ucSerState = SER_STOP_HOST_TX_RX; + + /* Force own to FW as ACK and stop HIF */ + prAdapter->fgWiFiInSleepyState = true; +} + +void nicSerStopTx(IN P_ADAPTER_T prAdapter) +{ + DBGLOG(NIC, WARN, "SER: Stop HIF Tx!\n"); + + prAdapter->ucSerState = SER_STOP_HOST_TX; +} + +void nicSerStartTxRx(IN P_ADAPTER_T prAdapter) +{ + DBGLOG(NIC, WARN, "SER: Start HIF T/R!\n"); + + halSerHifReset(prAdapter); + prAdapter->ucSerState = SER_IDLE_DONE; +} + +u8 nicSerIsWaitingReset(IN P_ADAPTER_T prAdapter) +{ + if (prAdapter->ucSerState == SER_STOP_HOST_TX_RX) { + return true; + } else { + return false; + } +} + +u8 nicSerIsTxStop(IN P_ADAPTER_T prAdapter) +{ + switch (prAdapter->ucSerState) { + case SER_STOP_HOST_TX: + case SER_STOP_HOST_TX_RX: + case SER_REINIT_HIF: + return true; + + case SER_IDLE_DONE: + default: + return false; + } +} + +u8 nicSerIsRxStop(IN P_ADAPTER_T prAdapter) +{ + switch (prAdapter->ucSerState) { + case SER_STOP_HOST_TX_RX: + case SER_REINIT_HIF: + return true; + + case SER_STOP_HOST_TX: + case SER_IDLE_DONE: + default: + return false; + } +} + +void nicDumpMsduInfo(IN P_MSDU_INFO_T prMsduInfo) +{ + struct sk_buff *prSkb; + + if (!prMsduInfo) { + DBGLOG(NIC, ERROR, "Invalid MsduInfo, skip dump."); + return; + } + + /* [1]prPacket(txd) [2]eSrc + * [3]ucUserPriority [4]ucTC + * [5]ucPacketType [6]ucStaRecIndex + * [7]ucBssIndex [8]ucWlanIndex + * [9]ucPacketFormat [10]fgIs802_1x + * [11]fgIs802_1x_NonProtected [12]fgIs802_11 + * [13]fgIs802_3 [14]fgIsVlanExists + * [15]u4Option [16]cPowerOffset + * [17]u2SwSN [18]ucRetryLimit + * [19]u4RemainingLifetime [20]ucControlFlag + * [21]ucRateMode [22]u4FixedRateOption + * [23]fgIsTXDTemplateValid [24]ucMacHeaderLength + * [25]ucLlcLength [26]u2FrameLength + * [27]aucEthDestAddr [28]u4PageCount + * [29]ucTxSeqNum [30]ucPID + * [31]ucWmmQueSet [32]pfTxDoneHandler + * [33]u4TxDoneTag [34]ucPktType + */ + +#define TEMP_LINE1 \ + "[1][%p], [2][%u], [3][%u], [4][%u], [5][%u], " \ + "[6][%u], [7][%u], [8][%u], [9][%u], [10][%u]\n" + +#define TEMP_LINE2 \ + "[11][%u], [12][%u], [13][%u], [14][%u], [15][%u], " \ + "[16][%d], [17][%u], [18][%u], [19][%u], [20][%u]\n" + +#define TEMP_LINE3 \ + "[21][%u], [22][%u], [23][%u], [24][%u], [25][%u], " \ + "[26][%u], [27][" MACSTR "], [28][%u], [29][%u], [30][%u]\n" + +#define TEMP_LINE4 "[31][%u], [32][%p], [33][%u], [34][%u]\n" + + DBGLOG(NIC, INFO, TEMP_LINE1, prMsduInfo->prPacket, prMsduInfo->eSrc, + prMsduInfo->ucUserPriority, prMsduInfo->ucTC, + prMsduInfo->ucPacketType, prMsduInfo->ucStaRecIndex, + prMsduInfo->ucBssIndex, prMsduInfo->ucWlanIndex, + prMsduInfo->ucPacketFormat, prMsduInfo->fgIs802_1x); + + DBGLOG(NIC, INFO, TEMP_LINE2, prMsduInfo->fgIs802_1x_NonProtected, + prMsduInfo->fgIs802_11, prMsduInfo->fgIs802_3, + prMsduInfo->fgIsVlanExists, prMsduInfo->u4Option, + prMsduInfo->cPowerOffset, prMsduInfo->u2SwSN, + prMsduInfo->ucRetryLimit, prMsduInfo->u4RemainingLifetime, + prMsduInfo->ucControlFlag); + + DBGLOG(NIC, INFO, TEMP_LINE3, prMsduInfo->ucRateMode, + prMsduInfo->u4FixedRateOption, prMsduInfo->fgIsTXDTemplateValid, + prMsduInfo->ucMacHeaderLength, prMsduInfo->ucLlcLength, + prMsduInfo->u2FrameLength, prMsduInfo->aucEthDestAddr, + prMsduInfo->u4PageCount, prMsduInfo->ucTxSeqNum, prMsduInfo->ucPID); + + DBGLOG(NIC, INFO, TEMP_LINE4, prMsduInfo->ucWmmQueSet, + prMsduInfo->pfTxDoneHandler, prMsduInfo->u4TxDoneTag, + prMsduInfo->ucPacketType); +#undef TEMP_LINE1 +#undef TEMP_LINE2 +#undef TEMP_LINE3 +#undef TEMP_LINE4 + + /* dump txd */ + if (prMsduInfo->ucPacketType == TX_PACKET_TYPE_DATA && + prMsduInfo->prPacket) { + prSkb = prMsduInfo->prPacket; + DBGLOG_MEM8(NIC, INFO, prSkb->data, 64); + } +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_cmd_event.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_cmd_event.c new file mode 100644 index 00000000000000..3dd839ebeb03c7 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_cmd_event.c @@ -0,0 +1,4075 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file nic_cmd_event.c + * \brief Callback functions for Command packets. + * + * Various Event packet handlers which will be setup in the callback function of + * a command packet. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#include "gl_ate_agent.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +const NIC_CAPABILITY_V2_REF_TABLE_T gNicCapabilityV2InfoTable[] = { + { TAG_CAP_TX_RESOURCE, nicCmdEventQueryNicTxResource }, + { TAG_CAP_TX_EFUSEADDRESS, nicCmdEventQueryNicEfuseAddr }, + { TAG_CAP_COEX_FEATURE, nicCmdEventQueryNicCoexFeature }, + { TAG_CAP_SINGLE_SKU, rlmDomainExtractSingleSkuInfoFromFirmware }, +#if CFG_TCP_IP_CHKSUM_OFFLOAD + { TAG_CAP_CSUM_OFFLOAD, nicCmdEventQueryNicCsumOffload }, +#endif + { TAG_CAP_EFUSE_OFFSET, nicCmdEventQueryEfuseOffset }, +}; + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D A T A + ******************************************************************************* + */ +void nicCmdEventQueryMcrRead(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_PARAM_CUSTOM_MCR_RW_STRUCT_T prMcrRdInfo; + P_GLUE_INFO_T prGlueInfo; + P_CMD_ACCESS_REG prCmdAccessReg; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + if (u4EventBufLen < sizeof(CMD_ACCESS_REG)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(CMD_ACCESS_REG)); + return; + } + prCmdAccessReg = (P_CMD_ACCESS_REG)(pucEventBuf); + + u4QueryInfoLen = sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T); + + prMcrRdInfo = + (P_PARAM_CUSTOM_MCR_RW_STRUCT_T)prCmdInfo->pvInformationBuffer; + prMcrRdInfo->u4McrOffset = prCmdAccessReg->u4Address; + prMcrRdInfo->u4McrData = prCmdAccessReg->u4Data; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } + + return; +} + +void nicCmdEventQueryCoexIso(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + + struct CMD_COEX_CTRL *prCmdCoexCtrl; + struct CMD_COEX_ISO_DETECT *prCmdCoexIsoDetect; + struct PARAM_COEX_CTRL *prCoexCtrl; + struct PARAM_COEX_ISO_DETECT *prCoexIsoDetect; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(struct CMD_COEX_CTRL)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(struct CMD_COEX_CTRL)); + return; + } + prCmdCoexCtrl = (struct CMD_COEX_CTRL *)(pucEventBuf); + u4QueryInfoLen = sizeof(struct PARAM_COEX_CTRL); + prCmdCoexIsoDetect = + (struct CMD_COEX_ISO_DETECT *)&prCmdCoexCtrl->aucBuffer[0]; + + prCoexCtrl = (struct PARAM_COEX_CTRL *)prCmdInfo->pvInformationBuffer; + prCoexIsoDetect = + (struct PARAM_COEX_ISO_DETECT *)&prCoexCtrl->aucBuffer[0]; + prCoexIsoDetect->u4IsoPath = prCmdCoexIsoDetect->u4IsoPath; + prCoexIsoDetect->u4Channel = prCmdCoexIsoDetect->u4Channel; + /*prCoexIsoDetect->u4Band = prCmdCoexIsoDetect->u4Band;*/ + prCoexIsoDetect->u4Isolation = prCmdCoexIsoDetect->u4Isolation; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +#if CFG_SUPPORT_QA_TOOL +void nicCmdEventQueryRxStatistics(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_PARAM_CUSTOM_ACCESS_RX_STAT prRxStatistics; + P_EVENT_ACCESS_RX_STAT prEventAccessRxStat; + u32 u4QueryInfoLen, i; + P_GLUE_INFO_T prGlueInfo; + u32 *prElement; + u32 u4Temp; + /* P_CMD_ACCESS_RX_STAT prCmdRxStat, prRxStat; */ + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + if (u4EventBufLen < sizeof(EVENT_ACCESS_RX_STAT)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_ACCESS_RX_STAT)); + return; + } + prEventAccessRxStat = (P_EVENT_ACCESS_RX_STAT)(pucEventBuf); + + prRxStatistics = + (P_PARAM_CUSTOM_ACCESS_RX_STAT)prCmdInfo->pvInformationBuffer; + prRxStatistics->u4SeqNum = prEventAccessRxStat->u4SeqNum; + prRxStatistics->u4TotalNum = prEventAccessRxStat->u4TotalNum; + + u4QueryInfoLen = sizeof(CMD_ACCESS_RX_STAT); + + if (prRxStatistics->u4SeqNum == u4RxStatSeqNum) { + prElement = &g_HqaRxStat.MAC_FCS_Err; + for (i = 0; i < HQA_RX_STATISTIC_NUM; i++) { + u4Temp = ntohl(prEventAccessRxStat->au4Buffer[i]); + kalMemCopy(prElement, &u4Temp, 4); + + if (i < (HQA_RX_STATISTIC_NUM - 1)) { + prElement++; + } + } + + g_HqaRxStat.AllMacMdrdy0 = ntohl(prEventAccessRxStat->au4Buffer[i]); + i++; + g_HqaRxStat.AllMacMdrdy1 = ntohl(prEventAccessRxStat->au4Buffer[i]); + /* i++; */ + /* g_HqaRxStat.AllFCSErr0 = + * ntohl(prEventAccessRxStat->au4Buffer[i]); */ + /* i++; */ + /* g_HqaRxStat.AllFCSErr1 = + * ntohl(prEventAccessRxStat->au4Buffer[i]); */ + } + + DBGLOG(INIT, ERROR, + "MT6632 : RX Statistics Test SeqNum = %d, TotalNum = %d\n", + (unsigned int)prEventAccessRxStat->u4SeqNum, + (unsigned int)prEventAccessRxStat->u4TotalNum); + + DBGLOG( + INIT, ERROR, + "MAC_FCS_ERR = %d, MAC_MDRDY = %d, MU_RX_CNT = %d, RX_FIFO_FULL = %d\n", + (unsigned int)prEventAccessRxStat->au4Buffer[0], + (unsigned int)prEventAccessRxStat->au4Buffer[1], + (unsigned int)prEventAccessRxStat->au4Buffer[65], + (unsigned int)prEventAccessRxStat->au4Buffer[22]); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +#if CFG_SUPPORT_TX_BF +void nicCmdEventPfmuDataRead(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + P_PFMU_DATA prEventPfmuDataRead = NULL; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + if (u4EventBufLen < sizeof(PFMU_DATA)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d", __func__, + u4EventBufLen, sizeof(PFMU_DATA)); + return; + } + prEventPfmuDataRead = (P_PFMU_DATA)(pucEventBuf); + + u4QueryInfoLen = sizeof(PFMU_DATA); + + g_rPfmuData = *prEventPfmuDataRead; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } + + DBGLOG(INIT, INFO, "=========== Before ===========\n"); + if (prEventPfmuDataRead != NULL) { + DBGLOG(INIT, INFO, "u2Phi11 = 0x%x\n", + prEventPfmuDataRead->rField.u2Phi11); + DBGLOG(INIT, INFO, "ucPsi21 = 0x%x\n", + prEventPfmuDataRead->rField.ucPsi21); + DBGLOG(INIT, INFO, "u2Phi21 = 0x%x\n", + prEventPfmuDataRead->rField.u2Phi21); + DBGLOG(INIT, INFO, "ucPsi31 = 0x%x\n", + prEventPfmuDataRead->rField.ucPsi31); + DBGLOG(INIT, INFO, "u2Phi31 = 0x%x\n", + prEventPfmuDataRead->rField.u2Phi31); + DBGLOG(INIT, INFO, "ucPsi41 = 0x%x\n", + prEventPfmuDataRead->rField.ucPsi41); + DBGLOG(INIT, INFO, "u2Phi22 = 0x%x\n", + prEventPfmuDataRead->rField.u2Phi22); + DBGLOG(INIT, INFO, "ucPsi32 = 0x%x\n", + prEventPfmuDataRead->rField.ucPsi32); + DBGLOG(INIT, INFO, "u2Phi32 = 0x%x\n", + prEventPfmuDataRead->rField.u2Phi32); + DBGLOG(INIT, INFO, "ucPsi42 = 0x%x\n", + prEventPfmuDataRead->rField.ucPsi42); + DBGLOG(INIT, INFO, "u2Phi33 = 0x%x\n", + prEventPfmuDataRead->rField.u2Phi33); + DBGLOG(INIT, INFO, "ucPsi43 = 0x%x\n", + prEventPfmuDataRead->rField.ucPsi43); + DBGLOG(INIT, INFO, "u2dSNR00 = 0x%x\n", + prEventPfmuDataRead->rField.u2dSNR00); + DBGLOG(INIT, INFO, "u2dSNR01 = 0x%x\n", + prEventPfmuDataRead->rField.u2dSNR01); + DBGLOG(INIT, INFO, "u2dSNR02 = 0x%x\n", + prEventPfmuDataRead->rField.u2dSNR02); + DBGLOG(INIT, INFO, "u2dSNR03 = 0x%x\n", + prEventPfmuDataRead->rField.u2dSNR03); + } +} + +void nicCmdEventPfmuTagRead(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_PFMU_TAG_READ_T prEventPfmuTagRead = NULL; + P_PARAM_CUSTOM_PFMU_TAG_READ_STRUCT_T prPfumTagRead = NULL; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + if (!pucEventBuf) { + DBGLOG(INIT, ERROR, "pucEventBuf is NULL.\n"); + return; + } + if (u4EventBufLen < sizeof(EVENT_PFMU_TAG_READ_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d", __func__, + u4EventBufLen, sizeof(EVENT_PFMU_TAG_READ_T)); + return; + } + if (!prCmdInfo->pvInformationBuffer) { + DBGLOG(INIT, ERROR, "prCmdInfo->pvInformationBuffer is NULL.\n"); + return; + } + /* 4 <2> Update information of OID */ + if (!prCmdInfo->fgIsOid) { + DBGLOG(INIT, ERROR, "cmd %u seq #%u not oid!", prCmdInfo->ucCID, + prCmdInfo->ucCmdSeqNum); + return; + } + prGlueInfo = prAdapter->prGlueInfo; + prEventPfmuTagRead = (P_EVENT_PFMU_TAG_READ_T)(pucEventBuf); + + prPfumTagRead = + (P_PARAM_CUSTOM_PFMU_TAG_READ_STRUCT_T)prCmdInfo->pvInformationBuffer; + + kalMemCopy(prPfumTagRead, prEventPfmuTagRead, + sizeof(EVENT_PFMU_TAG_READ_T)); + + u4QueryInfoLen = sizeof(CMD_TXBF_ACTION_T); + + g_rPfmuTag1 = prPfumTagRead->ru4TxBfPFMUTag1; + g_rPfmuTag2 = prPfumTagRead->ru4TxBfPFMUTag2; + + if (prCmdInfo->fgIsOid) { + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + prCmdInfo->fgIsOid = false; + } + + DBGLOG( + INIT, INFO, + "========================== (R)Tag1 info ==========================\n"); + + DBGLOG(INIT, INFO, + " Row data0 : %x, Row data1 : %x, Row data2 : %x, Row data3 : %x\n", + prEventPfmuTagRead->ru4TxBfPFMUTag1.au4RawData[0], + prEventPfmuTagRead->ru4TxBfPFMUTag1.au4RawData[1], + prEventPfmuTagRead->ru4TxBfPFMUTag1.au4RawData[2], + prEventPfmuTagRead->ru4TxBfPFMUTag1.au4RawData[3]); + DBGLOG(INIT, INFO, "ProfileID = %d Invalid status = %d\n", + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucProfileID, + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucInvalidProf); + DBGLOG(INIT, INFO, "0:iBF / 1:eBF = %d\n", + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucTxBf); + DBGLOG(INIT, INFO, "0:SU / 1:MU = %d\n", + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucSU_MU); + DBGLOG(INIT, INFO, "DBW(0/1/2/3 BW20/40/80/160NC) = %d\n", + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucDBW); + DBGLOG(INIT, INFO, "RMSD = %d\n", + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucRMSD); + DBGLOG(INIT, INFO, "Nrow = %d, Ncol = %d, Ng = %d, LM = %d\n", + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucNrow, + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucNcol, + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucNgroup, + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucLM); + DBGLOG( + INIT, INFO, "Mem1(%d, %d), Mem2(%d, %d), Mem3(%d, %d), Mem4(%d, %d)\n", + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucMemAddr1ColIdx, + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucMemAddr1RowIdx, + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucMemAddr2ColIdx, + (prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucMemAddr2RowIdx | + (prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucMemAddr2RowIdxMsb << 5)), + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucMemAddr3ColIdx, + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucMemAddr3RowIdx, + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucMemAddr4ColIdx, + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucMemAddr4RowIdx); + DBGLOG(INIT, INFO, + "SNR STS0=0x%x, SNR STS1=0x%x, SNR STS2=0x%x, SNR STS3=0x%x\n", + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucSNR_STS0, + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucSNR_STS1, + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucSNR_STS2, + prEventPfmuTagRead->ru4TxBfPFMUTag1.rField.ucSNR_STS3); + DBGLOG(INIT, INFO, + "===============================================================\n"); + + DBGLOG( + INIT, INFO, + "========================== (R)Tag2 info ==========================\n"); + DBGLOG(INIT, INFO, " Row data0 : %x, Row data1 : %x, Row data2 : %x\n", + prEventPfmuTagRead->ru4TxBfPFMUTag2.au4RawData[0], + prEventPfmuTagRead->ru4TxBfPFMUTag2.au4RawData[1], + prEventPfmuTagRead->ru4TxBfPFMUTag2.au4RawData[2]); + DBGLOG(INIT, INFO, "Smart Ant Cfg = %d\n", + prEventPfmuTagRead->ru4TxBfPFMUTag2.rField.u2SmartAnt); + DBGLOG(INIT, INFO, "SE index = %d\n", + prEventPfmuTagRead->ru4TxBfPFMUTag2.rField.ucSEIdx); + DBGLOG(INIT, INFO, "RMSD Threshold = %d\n", + prEventPfmuTagRead->ru4TxBfPFMUTag2.rField.ucRMSDThd); + DBGLOG(INIT, INFO, + "MCS TH L1SS = %d, S1SS = %d, L2SS = %d, S2SS = %d\n" + "L3SS = %d, S3SS = %d\n", + prEventPfmuTagRead->ru4TxBfPFMUTag2.rField.ucMCSThL1SS, + prEventPfmuTagRead->ru4TxBfPFMUTag2.rField.ucMCSThS1SS, + prEventPfmuTagRead->ru4TxBfPFMUTag2.rField.ucMCSThL2SS, + prEventPfmuTagRead->ru4TxBfPFMUTag2.rField.ucMCSThS2SS, + prEventPfmuTagRead->ru4TxBfPFMUTag2.rField.ucMCSThL3SS, + prEventPfmuTagRead->ru4TxBfPFMUTag2.rField.ucMCSThS3SS); + DBGLOG(INIT, INFO, "iBF lifetime limit(unit:4ms) = 0x%x\n", + prEventPfmuTagRead->ru4TxBfPFMUTag2.rField.uciBfTimeOut); + DBGLOG(INIT, INFO, "iBF desired DBW = %d\n 0/1/2/3 : BW20/40/80/160NC\n", + prEventPfmuTagRead->ru4TxBfPFMUTag2.rField.uciBfDBW); + DBGLOG(INIT, INFO, "iBF desired Ncol = %d\n 0/1/2 : Ncol = 1 ~ 3\n", + prEventPfmuTagRead->ru4TxBfPFMUTag2.rField.uciBfNcol); + DBGLOG(INIT, INFO, "iBF desired Nrow = %d\n 0/1/2/3 : Nrow = 1 ~ 4\n", + prEventPfmuTagRead->ru4TxBfPFMUTag2.rField.uciBfNrow); + DBGLOG(INIT, INFO, + "===============================================================\n"); +} + +#endif +#if CFG_SUPPORT_MU_MIMO +void nicCmdEventGetQd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_HQA_GET_QD prEventHqaGetQd; + u32 i; + + P_PARAM_CUSTOM_GET_QD_STRUCT_T prGetQd = NULL; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + if (!pucEventBuf) { + DBGLOG(INIT, ERROR, "pucEventBuf is NULL.\n"); + return; + } + if (u4EventBufLen < sizeof(EVENT_HQA_GET_QD)) { + DBGLOG(NIC, ERROR, "%s:Invalid event length: %d < %d", __func__, + u4EventBufLen, sizeof(EVENT_HQA_GET_QD)); + return; + } + if (!prCmdInfo->pvInformationBuffer) { + DBGLOG(INIT, ERROR, "prCmdInfo->pvInformationBuffer is NULL.\n"); + return; + } + /* 4 <2> Update information of OID */ + if (!prCmdInfo->fgIsOid) { + DBGLOG(INIT, ERROR, "cmd %u seq #%u not oid!\n", prCmdInfo->ucCID, + prCmdInfo->ucCmdSeqNum); + return; + } + prGlueInfo = prAdapter->prGlueInfo; + prEventHqaGetQd = (P_EVENT_HQA_GET_QD)(pucEventBuf); + + prGetQd = (P_PARAM_CUSTOM_GET_QD_STRUCT_T)prCmdInfo->pvInformationBuffer; + + kalMemCopy(prGetQd, prEventHqaGetQd, sizeof(EVENT_HQA_GET_QD)); + + u4QueryInfoLen = sizeof(CMD_MUMIMO_ACTION_T); + + /* g_rPfmuTag1 = prPfumTagRead->ru4TxBfPFMUTag1; */ + /* g_rPfmuTag2 = prPfumTagRead->ru4TxBfPFMUTag2; */ + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + + DBGLOG(INIT, INFO, " event id : %x\n", prGetQd->u4EventId); + for (i = 0; i < 14; i++) + DBGLOG(INIT, INFO, "au4RawData[%d]: %x\n", i, prGetQd->au4RawData[i]); +} + +void nicCmdEventGetCalcLq(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_HQA_GET_MU_CALC_LQ prEventHqaGetMuCalcLq; + u32 i, j; + + P_PARAM_CUSTOM_GET_MU_CALC_LQ_STRUCT_T prGetMuCalcLq = NULL; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + if (!pucEventBuf) { + DBGLOG(INIT, ERROR, "pucEventBuf is NULL.\n"); + return; + } + if (u4EventBufLen < sizeof(EVENT_HQA_GET_MU_CALC_LQ)) { + DBGLOG(NIC, ERROR, "%s:Invalid event length: %d < %d", __func__, + u4EventBufLen, sizeof(EVENT_HQA_GET_MU_CALC_LQ)); + return; + } + if (!prCmdInfo->pvInformationBuffer) { + DBGLOG(INIT, ERROR, "prCmdInfo->pvInformationBuffer is NULL.\n"); + return; + } + /* 4 <2> Update information of OID */ + if (!prCmdInfo->fgIsOid) { + DBGLOG(INIT, ERROR, "cmd %u seq #%u not oid!\n", prCmdInfo->ucCID, + prCmdInfo->ucCmdSeqNum); + return; + } + prGlueInfo = prAdapter->prGlueInfo; + prEventHqaGetMuCalcLq = (P_EVENT_HQA_GET_MU_CALC_LQ)(pucEventBuf); + + prGetMuCalcLq = + (P_PARAM_CUSTOM_GET_MU_CALC_LQ_STRUCT_T)prCmdInfo->pvInformationBuffer; + + kalMemCopy(prGetMuCalcLq, prEventHqaGetMuCalcLq, + sizeof(EVENT_HQA_GET_MU_CALC_LQ)); + + u4QueryInfoLen = sizeof(CMD_MUMIMO_ACTION_T); + + /* g_rPfmuTag1 = prPfumTagRead->ru4TxBfPFMUTag1; */ + /* g_rPfmuTag2 = prPfumTagRead->ru4TxBfPFMUTag2; */ + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + + DBGLOG(INIT, INFO, " event id : %x\n", prGetMuCalcLq->u4EventId); + for (i = 0; i < NUM_OF_USER; i++) + for (j = 0; j < NUM_OF_MODUL; j++) + DBGLOG(INIT, INFO, " lq_report[%d][%d]: %x\n", i, j, + prGetMuCalcLq->rEntry.lq_report[i][j]); +} + +void nicCmdEventGetCalcInitMcs(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_SHOW_GROUP_TBL_ENTRY prEventShowGroupTblEntry = NULL; + + P_PARAM_CUSTOM_SHOW_GROUP_TBL_ENTRY_STRUCT_T prShowGroupTbl; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + if (!pucEventBuf) { + DBGLOG(INIT, ERROR, "pucEventBuf is NULL.\n"); + return; + } + if (u4EventBufLen < sizeof(EVENT_SHOW_GROUP_TBL_ENTRY)) { + DBGLOG(NIC, ERROR, "%s:Invalid event length: %d < %d", __func__, + u4EventBufLen, sizeof(EVENT_SHOW_GROUP_TBL_ENTRY)); + return; + } + if (!prCmdInfo->pvInformationBuffer) { + DBGLOG(INIT, ERROR, "prCmdInfo->pvInformationBuffer is NULL.\n"); + return; + } + /* 4 <2> Update information of OID */ + if (!prCmdInfo->fgIsOid) { + DBGLOG(INIT, ERROR, "cmd %u seq #%u not oid!\n", prCmdInfo->ucCID, + prCmdInfo->ucCmdSeqNum); + return; + } + prGlueInfo = prAdapter->prGlueInfo; + prEventShowGroupTblEntry = (P_EVENT_SHOW_GROUP_TBL_ENTRY)(pucEventBuf); + + prShowGroupTbl = (P_PARAM_CUSTOM_SHOW_GROUP_TBL_ENTRY_STRUCT_T) + prCmdInfo->pvInformationBuffer; + + kalMemCopy(prShowGroupTbl, prEventShowGroupTblEntry, + sizeof(EVENT_SHOW_GROUP_TBL_ENTRY)); + + u4QueryInfoLen = sizeof(CMD_MUMIMO_ACTION_T); + + /* g_rPfmuTag1 = prPfumTagRead->ru4TxBfPFMUTag1; */ + /* g_rPfmuTag2 = prPfumTagRead->ru4TxBfPFMUTag2; */ + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + + DBGLOG(INIT, INFO, + "========================== (R)Group table info " + "==========================\n"); + DBGLOG(INIT, INFO, " event id : %x\n", prEventShowGroupTblEntry->u4EventId); + DBGLOG(INIT, INFO, "index = %x numUser = %x\n", + prEventShowGroupTblEntry->index, prEventShowGroupTblEntry->numUser); + DBGLOG(INIT, INFO, "BW = %x NS0/1/ = %x/%x\n", prEventShowGroupTblEntry->BW, + prEventShowGroupTblEntry->NS0, prEventShowGroupTblEntry->NS1); + DBGLOG(INIT, INFO, "PFIDUser0/1 = %x/%x\n", + prEventShowGroupTblEntry->PFIDUser0, + prEventShowGroupTblEntry->PFIDUser1); + DBGLOG(INIT, INFO, "fgIsShortGI = %x, fgIsUsed = %x, fgIsDisable = %x\n", + prEventShowGroupTblEntry->fgIsShortGI, + prEventShowGroupTblEntry->fgIsUsed, + prEventShowGroupTblEntry->fgIsDisable); + DBGLOG(INIT, INFO, "initMcsUser0/1 = %x/%x\n", + prEventShowGroupTblEntry->initMcsUser0, + prEventShowGroupTblEntry->initMcsUser1); + DBGLOG(INIT, INFO, "dMcsUser0: 0/1/ = %x/%x\n", + prEventShowGroupTblEntry->dMcsUser0, + prEventShowGroupTblEntry->dMcsUser1); +} +#endif +#endif + +void nicCmdEventQuerySwCtrlRead(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_PARAM_CUSTOM_SW_CTRL_STRUCT_T prSwCtrlInfo; + P_GLUE_INFO_T prGlueInfo; + P_CMD_SW_DBG_CTRL_T prCmdSwCtrl; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(CMD_SW_DBG_CTRL_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(CMD_SW_DBG_CTRL_T)); + return; + } + prCmdSwCtrl = (P_CMD_SW_DBG_CTRL_T)(pucEventBuf); + + u4QueryInfoLen = sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T); + + prSwCtrlInfo = + (P_PARAM_CUSTOM_SW_CTRL_STRUCT_T)prCmdInfo->pvInformationBuffer; + prSwCtrlInfo->u4Id = prCmdSwCtrl->u4Id; + prSwCtrlInfo->u4Data = prCmdSwCtrl->u4Data; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryChipConfig(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T prChipConfigInfo; + P_GLUE_INFO_T prGlueInfo; + P_CMD_CHIP_CONFIG_T prCmdChipConfig; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + if (u4EventBufLen < sizeof(CMD_CHIP_CONFIG_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(CMD_CHIP_CONFIG_T)); + return; + } + prCmdChipConfig = (P_CMD_CHIP_CONFIG_T)(pucEventBuf); + + u4QueryInfoLen = sizeof(PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T); + + if (prCmdInfo->u4InformationBufferLength < + sizeof(PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T)) { + DBGLOG( + REQ, INFO, + "Chip config u4InformationBufferLength %u is not valid (event)\n", + prCmdInfo->u4InformationBufferLength); + } + prChipConfigInfo = + (P_PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T)prCmdInfo->pvInformationBuffer; + prChipConfigInfo->ucRespType = prCmdChipConfig->ucRespType; + prChipConfigInfo->u2MsgSize = prCmdChipConfig->u2MsgSize; + DBGLOG(REQ, INFO, "%s: RespTyep %u\n", __func__, + prChipConfigInfo->ucRespType); + DBGLOG(REQ, INFO, "%s: u2MsgSize %u\n", __func__, + prChipConfigInfo->u2MsgSize); + + if (prChipConfigInfo->u2MsgSize > CHIP_CONFIG_RESP_SIZE) { + DBGLOG(REQ, WARN, "Chip config Msg Size %u is not valid (event)\n", + prChipConfigInfo->u2MsgSize); + prChipConfigInfo->u2MsgSize = CHIP_CONFIG_RESP_SIZE; + } + + kalMemCopy(prChipConfigInfo->aucCmd, prCmdChipConfig->aucCmd, + prChipConfigInfo->u2MsgSize); + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventSetCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, + prCmdInfo->u4InformationBufferLength, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventSetDisassociate(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_SUCCESS); + } + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); +} + +void nicCmdEventSetIpAddress(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u32 u4Count; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + u4Count = (prCmdInfo->u4SetInfoLen - + OFFSET_OF(CMD_SET_NETWORK_ADDRESS_LIST, arNetAddress)) / + sizeof(IPV4_NETWORK_ADDRESS); + + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, + OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress) + + u4Count * + (OFFSET_OF(PARAM_NETWORK_ADDRESS, aucAddress) + + sizeof(PARAM_NETWORK_ADDRESS_IP)), + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryRfTestATInfo(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_EVENT_TEST_STATUS prTestStatus, prQueryBuffer; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + if (u4EventBufLen < sizeof(EVENT_TEST_STATUS)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_TEST_STATUS)); + return; + } + prTestStatus = (P_EVENT_TEST_STATUS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prQueryBuffer = (P_EVENT_TEST_STATUS)prCmdInfo->pvInformationBuffer; + + kalMemCopy(prQueryBuffer, prTestStatus, sizeof(EVENT_TEST_STATUS)); + + u4QueryInfoLen = sizeof(EVENT_TEST_STATUS); + + /* Update Query Information Length */ + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryLinkQuality(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + PARAM_RSSI rRssi, *prRssi; + P_EVENT_LINK_QUALITY prLinkQuality; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_LINK_QUALITY)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_LINK_QUALITY)); + return; + } + prLinkQuality = (P_EVENT_LINK_QUALITY)pucEventBuf; + + rRssi = (PARAM_RSSI)prLinkQuality->cRssi; /* ranged from (-128 ~ 30) in + * unit of dBm */ + + if (prAdapter->prAisBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) { + if (rRssi > PARAM_WHQL_RSSI_MAX_DBM) { + rRssi = PARAM_WHQL_RSSI_MAX_DBM; + } else if (rRssi < PARAM_WHQL_RSSI_MIN_DBM) { + rRssi = PARAM_WHQL_RSSI_MIN_DBM; + } + } else { + rRssi = PARAM_WHQL_RSSI_MIN_DBM; + } + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + prRssi = (PARAM_RSSI *)prCmdInfo->pvInformationBuffer; + + kalMemCopy(prRssi, &rRssi, sizeof(PARAM_RSSI)); + u4QueryInfoLen = sizeof(PARAM_RSSI); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is in response of OID_GEN_LINK_SPEED query request + * + * @param prAdapter Pointer to the Adapter structure. + * @param prCmdInfo Pointer to the pending command info + * @param pucEventBuf + * + * @retval none + */ +/*----------------------------------------------------------------------------*/ +void nicCmdEventQueryLinkSpeed(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_EVENT_LINK_QUALITY prLinkQuality; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + u32 *pu4LinkSpeed; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_LINK_QUALITY)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_LINK_QUALITY)); + return; + } + prLinkQuality = (P_EVENT_LINK_QUALITY)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + pu4LinkSpeed = (u32 *)(prCmdInfo->pvInformationBuffer); + + *pu4LinkSpeed = prLinkQuality->u2LinkSpeed * 5000; + + u4QueryInfoLen = sizeof(u32); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryStatistics(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_PARAM_802_11_STATISTICS_STRUCT_T prStatistics; + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_STATISTICS)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STATISTICS)); + return; + } + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + u4QueryInfoLen = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics = + (P_PARAM_802_11_STATISTICS_STRUCT_T)prCmdInfo->pvInformationBuffer; + + prStatistics->u4Length = sizeof(PARAM_802_11_STATISTICS_STRUCT_T); + prStatistics->rTransmittedFragmentCount = + prEventStatistics->rTransmittedFragmentCount; + prStatistics->rMulticastTransmittedFrameCount = + prEventStatistics->rMulticastTransmittedFrameCount; + prStatistics->rFailedCount = prEventStatistics->rFailedCount; + prStatistics->rRetryCount = prEventStatistics->rRetryCount; + prStatistics->rMultipleRetryCount = + prEventStatistics->rMultipleRetryCount; + prStatistics->rRTSSuccessCount = prEventStatistics->rRTSSuccessCount; + prStatistics->rRTSFailureCount = prEventStatistics->rRTSFailureCount; + prStatistics->rACKFailureCount = prEventStatistics->rACKFailureCount; + prStatistics->rFrameDuplicateCount = + prEventStatistics->rFrameDuplicateCount; + prStatistics->rReceivedFragmentCount = + prEventStatistics->rReceivedFragmentCount; + prStatistics->rMulticastReceivedFrameCount = + prEventStatistics->rMulticastReceivedFrameCount; + prStatistics->rFCSErrorCount = prEventStatistics->rFCSErrorCount; + prStatistics->rTKIPLocalMICFailures.QuadPart = 0; + prStatistics->rTKIPICVErrors.QuadPart = 0; + prStatistics->rTKIPCounterMeasuresInvoked.QuadPart = 0; + prStatistics->rTKIPReplays.QuadPart = 0; + prStatistics->rCCMPFormatErrors.QuadPart = 0; + prStatistics->rCCMPReplays.QuadPart = 0; + prStatistics->rCCMPDecryptErrors.QuadPart = 0; + prStatistics->rFourWayHandshakeFailures.QuadPart = 0; + prStatistics->rWEPUndecryptableCount.QuadPart = 0; + prStatistics->rWEPICVErrorCount.QuadPart = 0; + prStatistics->rDecryptSuccessCount.QuadPart = 0; + prStatistics->rDecryptFailureCount.QuadPart = 0; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventEnterRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + /* [driver-land] */ + /* prAdapter->fgTestMode = true; */ + if (prAdapter->fgTestMode) { + prAdapter->fgTestMode = false; + } else { + prAdapter->fgTestMode = true; + } + + /* 0. always indicate disconnection */ + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != + PARAM_MEDIA_STATE_DISCONNECTED) { + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + } + /* 1. Remove pending TX */ + nicTxRelease(prAdapter, true); + + /* 1.1 clear pending Security / Management Frames */ + kalClearSecurityFrames(prAdapter->prGlueInfo); + kalClearMgmtFrames(prAdapter->prGlueInfo); + + /* 1.2 clear pending TX packet queued in glue layer */ + kalFlushPendingTxPackets(prAdapter->prGlueInfo); + + /* 2. Reset driver-domain FSMs */ + nicUninitMGMT(prAdapter); + + nicResetSystemService(prAdapter); + nicInitMGMT(prAdapter, NULL); + + /* 8. completion indication */ + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, WLAN_STATUS_SUCCESS); + } +#if CFG_SUPPORT_NVRAM + /* 9. load manufacture data */ + if (kalIsConfigurationExist(prAdapter->prGlueInfo) == true) { + wlanLoadManufactureData(prAdapter, + kalGetConfiguration(prAdapter->prGlueInfo)); + } else { + DBGLOG(REQ, INFO, "%s: load manufacture data fail\n", __func__); + } +#endif +} + +void nicCmdEventLeaveRfTest(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + /* 6. set driver-land variable */ + prAdapter->fgTestMode = false; + prAdapter->fgIcapMode = false; + + /* 7. completion indication */ + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, WLAN_STATUS_SUCCESS); + } + + /* 8. Indicate as disconnected */ + if (kalGetMediaStateIndicated(prAdapter->prGlueInfo) != + PARAM_MEDIA_STATE_DISCONNECTED) { + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0); + + prAdapter->rWlanInfo.u4SysTime = kalGetTimeTick(); + } +#if CFG_SUPPORT_NVRAM + /* 9. load manufacture data */ + if (kalIsConfigurationExist(prAdapter->prGlueInfo) == true) { + wlanLoadManufactureData(prAdapter, + kalGetConfiguration(prAdapter->prGlueInfo)); + } else { + DBGLOG(REQ, INFO, "%s: load manufacture data fail\n", __func__); + } +#endif + + /* 10. Override network address */ + wlanUpdateNetworkAddress(prAdapter); +} + +void nicCmdEventQueryMcastAddr(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_MAC_MCAST_ADDR prEventMacMcastAddr; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_MAC_MCAST_ADDR)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_MAC_MCAST_ADDR)); + return; + } + prEventMacMcastAddr = (P_EVENT_MAC_MCAST_ADDR)(pucEventBuf); + + u4QueryInfoLen = prEventMacMcastAddr->u4NumOfGroupAddr * MAC_ADDR_LEN; + + /* buffer length check */ + if (prCmdInfo->u4InformationBufferLength < u4QueryInfoLen) { + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_BUFFER_TOO_SHORT); + } else { + kalMemCopy(prCmdInfo->pvInformationBuffer, + prEventMacMcastAddr->arAddress, + prEventMacMcastAddr->u4NumOfGroupAddr * MAC_ADDR_LEN); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } + } +} + +void nicCmdEventQueryEepromRead(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T prEepromRdInfo; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_ACCESS_EEPROM prEventAccessEeprom; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + if (u4EventBufLen < sizeof(EVENT_ACCESS_EEPROM)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_ACCESS_EEPROM)); + return; + } + prEventAccessEeprom = (P_EVENT_ACCESS_EEPROM)(pucEventBuf); + + u4QueryInfoLen = sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T); + + prEepromRdInfo = + (P_PARAM_CUSTOM_EEPROM_RW_STRUCT_T)prCmdInfo->pvInformationBuffer; + prEepromRdInfo->ucEepromIndex = (u8)(prEventAccessEeprom->u2Offset); + prEepromRdInfo->u2EepromData = prEventAccessEeprom->u2Data; + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventSetMediaStreamMode(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + PARAM_MEDIA_STREAMING_INDICATION rParamMediaStreamIndication; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, + prCmdInfo->u4SetInfoLen, WLAN_STATUS_SUCCESS); + } + + rParamMediaStreamIndication.rStatus.eStatusType = + ENUM_STATUS_TYPE_MEDIA_STREAM_MODE; + rParamMediaStreamIndication.eMediaStreamMode = + prAdapter->rWlanInfo.eLinkAttr.ucMediaStreamMode == 0 ? + ENUM_MEDIA_STREAM_OFF : + ENUM_MEDIA_STREAM_ON; + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_MEDIA_SPECIFIC_INDICATION, + (void *)&rParamMediaStreamIndication, + sizeof(PARAM_MEDIA_STREAMING_INDICATION)); +} + +void nicCmdEventSetStopSchedScan(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + /* + * DBGLOG(SCN, INFO, "--->nicCmdEventSetStopSchedScan\n" )); + */ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + /* + * DBGLOG(SCN, INFO, "<--kalSchedScanStopped\n" ); + */ + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, + prCmdInfo->u4InformationBufferLength, + WLAN_STATUS_SUCCESS); + } + + DBGLOG( + SCN, INFO, + "nicCmdEventSetStopSchedScan OID done, release lock and send event to " + "uplayer\n"); + /*Due to dead lock issue, need to release the IO control before calling + * kernel APIs */ + kalSchedScanStopped(prAdapter->prGlueInfo); +} + +/* Statistics responder */ +void nicCmdEventQueryXmitOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + u32 *pu4Data; + u64 *pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_STATISTICS)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STATISTICS)); + return; + } + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(u32)) { + u4QueryInfoLen = sizeof(u32); + + pu4Data = (u32 *)prCmdInfo->pvInformationBuffer; + *pu4Data = + (u32)prEventStatistics->rTransmittedFragmentCount.QuadPart; + } else { + u4QueryInfoLen = sizeof(u64); + + pu8Data = (u64 *)prCmdInfo->pvInformationBuffer; + *pu8Data = prEventStatistics->rTransmittedFragmentCount.QuadPart; + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryRecvOk(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + u32 *pu4Data; + u64 *pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_STATISTICS)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STATISTICS)); + return; + } + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(u32)) { + u4QueryInfoLen = sizeof(u32); + + pu4Data = (u32 *)prCmdInfo->pvInformationBuffer; + *pu4Data = (u32)prEventStatistics->rReceivedFragmentCount.QuadPart; + } else { + u4QueryInfoLen = sizeof(u64); + + pu8Data = (u64 *)prCmdInfo->pvInformationBuffer; + *pu8Data = prEventStatistics->rReceivedFragmentCount.QuadPart; + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryXmitError(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + u32 *pu4Data; + u64 *pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_STATISTICS)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STATISTICS)); + return; + } + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(u32)) { + u4QueryInfoLen = sizeof(u32); + + pu4Data = (u32 *)prCmdInfo->pvInformationBuffer; + *pu4Data = (u32)prEventStatistics->rFailedCount.QuadPart; + } else { + u4QueryInfoLen = sizeof(u64); + + pu8Data = (u64 *)prCmdInfo->pvInformationBuffer; + *pu8Data = (u64)prEventStatistics->rFailedCount.QuadPart; + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryRecvError(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + u32 *pu4Data; + u64 *pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_STATISTICS)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STATISTICS)); + return; + } + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(u32)) { + u4QueryInfoLen = sizeof(u32); + + pu4Data = (u32 *)prCmdInfo->pvInformationBuffer; + *pu4Data = (u32)prEventStatistics->rFCSErrorCount.QuadPart; + /* @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT + * is not calculated */ + } else { + u4QueryInfoLen = sizeof(u64); + + pu8Data = (u64 *)prCmdInfo->pvInformationBuffer; + *pu8Data = prEventStatistics->rFCSErrorCount.QuadPart; + /* @FIXME, RX_ERROR_DROP_COUNT/RX_FIFO_FULL_DROP_COUNT + * is not calculated */ + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryRecvNoBuffer(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + u32 *pu4Data; + u64 *pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_STATISTICS)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STATISTICS)); + return; + } + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(u32)) { + u4QueryInfoLen = sizeof(u32); + + pu4Data = (u32 *)prCmdInfo->pvInformationBuffer; + *pu4Data = 0; /* @FIXME? */ + } else { + u4QueryInfoLen = sizeof(u64); + + pu8Data = (u64 *)prCmdInfo->pvInformationBuffer; + *pu8Data = 0; /* @FIXME? */ + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryRecvCrcError(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + u32 *pu4Data; + u64 *pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_STATISTICS)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STATISTICS)); + return; + } + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(u32)) { + u4QueryInfoLen = sizeof(u32); + + pu4Data = (u32 *)prCmdInfo->pvInformationBuffer; + *pu4Data = (u32)prEventStatistics->rFCSErrorCount.QuadPart; + } else { + u4QueryInfoLen = sizeof(u64); + + pu8Data = (u64 *)prCmdInfo->pvInformationBuffer; + *pu8Data = prEventStatistics->rFCSErrorCount.QuadPart; + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryRecvErrorAlignment(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + u32 *pu4Data; + u64 *pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_STATISTICS)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STATISTICS)); + return; + } + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(u32)) { + u4QueryInfoLen = sizeof(u32); + + pu4Data = (u32 *)prCmdInfo->pvInformationBuffer; + *pu4Data = (u32)0; /* @FIXME */ + } else { + u4QueryInfoLen = sizeof(u64); + + pu8Data = (u64 *)prCmdInfo->pvInformationBuffer; + *pu8Data = 0; /* @FIXME */ + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryXmitOneCollision(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + u32 *pu4Data; + u64 *pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_STATISTICS)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STATISTICS)); + return; + } + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(u32)) { + u4QueryInfoLen = sizeof(u32); + + pu4Data = (u32 *)prCmdInfo->pvInformationBuffer; + *pu4Data = (u32)(prEventStatistics->rMultipleRetryCount.QuadPart - + prEventStatistics->rRetryCount.QuadPart); + } else { + u4QueryInfoLen = sizeof(u64); + + pu8Data = (u64 *)prCmdInfo->pvInformationBuffer; + *pu8Data = (u64)(prEventStatistics->rMultipleRetryCount.QuadPart - + prEventStatistics->rRetryCount.QuadPart); + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryXmitMoreCollisions(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + u32 *pu4Data; + u64 *pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_STATISTICS)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STATISTICS)); + return; + } + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(u32)) { + u4QueryInfoLen = sizeof(u32); + + pu4Data = (u32 *)prCmdInfo->pvInformationBuffer; + *pu4Data = (u32)prEventStatistics->rMultipleRetryCount.QuadPart; + } else { + u4QueryInfoLen = sizeof(u64); + + pu8Data = (u64 *)prCmdInfo->pvInformationBuffer; + *pu8Data = (u64)prEventStatistics->rMultipleRetryCount.QuadPart; + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryXmitMaxCollisions(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_EVENT_STATISTICS prEventStatistics; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + u32 *pu4Data; + u64 *pu8Data; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_STATISTICS)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STATISTICS)); + return; + } + prEventStatistics = (P_EVENT_STATISTICS)pucEventBuf; + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + if (prCmdInfo->u4InformationBufferLength == sizeof(u32)) { + u4QueryInfoLen = sizeof(u32); + + pu4Data = (u32 *)prCmdInfo->pvInformationBuffer; + *pu4Data = (u32)prEventStatistics->rFailedCount.QuadPart; + } else { + u4QueryInfoLen = sizeof(u64); + + pu8Data = (u64 *)prCmdInfo->pvInformationBuffer; + *pu8Data = (u64)prEventStatistics->rFailedCount.QuadPart; + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called when command by OID/ioctl has been timeout + * + * @param prAdapter Pointer to the Adapter structure. + * @param prCmdInfo Pointer to the command information + * + * @return true + * false + */ +/*----------------------------------------------------------------------------*/ +void nicOidCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo) +{ + ASSERT(prAdapter); + + if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_FAILURE); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is a generic command timeout handler + * + * @param pfnOidHandler Pointer to the OID handler + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void nicCmdTimeoutCommon(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + ASSERT(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called when command for entering RF test has + * failed sending due to timeout (highly possibly by firmware crash) + * + * @param prAdapter Pointer to the Adapter structure. + * @param prCmdInfo Pointer to the command information + * + * @return none + * + */ +/*----------------------------------------------------------------------------*/ +void nicOidCmdEnterRFTestTimeout(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo) +{ + ASSERT(prAdapter); + + /* 1. Remove pending TX frames */ + nicTxRelease(prAdapter, true); + + /* 1.1 clear pending Security / Management Frames */ + kalClearSecurityFrames(prAdapter->prGlueInfo); + kalClearMgmtFrames(prAdapter->prGlueInfo); + + /* 1.2 clear pending TX packet queued in glue layer */ + kalFlushPendingTxPackets(prAdapter->prGlueInfo); + + /* 2. indicate for OID failure */ + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_FAILURE); +} + +#if CFG_SUPPORT_QA_TOOL +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called when received dump memory event packet. + * transfer the memory data to the IQ format data and write into file + * + * @param prIQAry Pointer to the array store I or Q data. + * prDataLen The return data length - bytes + * u4IQ 0: get I data + * 1 : get Q data + * + * @return -1: open file error + * + */ +/*----------------------------------------------------------------------------*/ +s32 GetIQData(s32 **prIQAry, u32 *prDataLen, u32 u4IQ, u32 u4GetWf1) +{ + u8 aucPath[50]; /* the path for iq data dump out */ + u8 aucData[50]; /* iq data in string format */ + u32 i = 0, j = 0, count = 0; + s32 ret = -1; + s32 rv; + struct file *file = NULL; + + *prIQAry = g_au4IQData; + + /* sprintf(aucPath, "/pattern.txt"); // CSD's Pattern */ + snprintf(aucPath, sizeof(aucPath), "/tmp/dump_out_%05ld_WF%d.txt", + (g_u2DumpIndex - 1), u4GetWf1); + if (kalCheckPath(aucPath) == -1) { + snprintf(aucPath, sizeof(aucPath), "/data/dump_out_%05ld_WF%d.txt", + (g_u2DumpIndex - 1), u4GetWf1); + } + + DBGLOG(INIT, INFO, "iCap Read Dump File dump_out_%05ld_WF%d.txt\n", + (g_u2DumpIndex - 1), u4GetWf1); + + file = kalFileOpen(aucPath, O_RDONLY, 0); + + if ((file != NULL) && !IS_ERR(file)) { + /* read 1K data per time */ + for (i = 0; i < RTN_IQ_DATA_LEN / sizeof(u32); + i++, g_au4Offset[u4GetWf1][u4IQ] += IQ_FILE_LINE_OFFSET) { + if (kalFileRead(file, g_au4Offset[u4GetWf1][u4IQ], aucData, + IQ_FILE_IQ_STR_LEN) == 0) { + break; + } + + count = 0; + + for (j = 0; j < 8; j++) + if (aucData[j] != ' ') { + aucData[count++] = aucData[j]; + } + + aucData[count] = '\0'; + + rv = kstrtoint(aucData, 0, &g_au4IQData[i]); /* transfer + * data + * format + * (string + * to int) + */ + } + *prDataLen = i * sizeof(u32); + kalFileClose(file); + ret = 0; + } + + DBGLOG(INIT, INFO, "MT6632 : QA_AGENT GetIQData prDataLen = %d\n", + *prDataLen); + DBGLOG(INIT, INFO, "MT6632 : QA_AGENT GetIQData i = %d\n", i); + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called when received dump memory event packet. + * transfer the memory data to the IQ format data and write into file + * + * @param prEventDumpMem Pointer to the event dump memory structure. + * + * @return 0: SUCCESS, -1: FAIL + * + */ +/*----------------------------------------------------------------------------*/ + +u32 TsfRawData2IqFmt(P_EVENT_DUMP_MEM_T prEventDumpMem) +{ + static u8 aucPathWF0[40]; /* the path for iq data dump out */ + static u8 aucPathWF1[40]; /* the path for iq data dump out */ + static u8 aucPathRAWWF0[40]; /* the path for iq data dump out */ + static u8 aucPathRAWWF1[40]; /* the path for iq data dump out */ + u8 *pucDataWF0 = NULL; /* the data write into file */ + u8 *pucDataWF1 = NULL; /* the data write into file */ + u8 *pucDataRAWWF0 = NULL; /* the data write into file */ + u8 *pucDataRAWWF1 = NULL; /* the data write into file */ + u32 u4SrcOffset; /* record the buffer offset */ + u32 u4FmtLen = 0; /* bus format length */ + u32 u4CpyLen = 0; + u32 u4RemainByte; + u32 u4DataWBufSize = 150; + u32 u4DataRAWWBufSize = 150; + u32 u4DataWLenF0 = 0; + u32 u4DataWLenF1 = 0; + u32 u4DataRAWWLenF0 = 0; + u32 u4DataRAWWLenF1 = 0; + + u8 fgAppend; + s32 u4Iqc160WF0Q0, u4Iqc160WF1I1; + + static u8 ucDstOffset; /* for alignment. bcs we send 2KB data per + * packet,*/ + /*the data will not align in 12 bytes case. */ + static u32 u4CurTimeTick; + + static ICAP_BUS_FMT icapBusData; + u32 *ptr; + + pucDataWF0 = kmalloc(u4DataWBufSize, GFP_KERNEL); + pucDataWF1 = kmalloc(u4DataWBufSize, GFP_KERNEL); + pucDataRAWWF0 = kmalloc(u4DataRAWWBufSize, GFP_KERNEL); + pucDataRAWWF1 = kmalloc(u4DataRAWWBufSize, GFP_KERNEL); + + if ((!pucDataWF0) || (!pucDataWF1) || (!pucDataRAWWF0) || + (!pucDataRAWWF1)) { + DBGLOG(INIT, ERROR, "kmalloc failed.\n"); + kfree(pucDataWF0); + kfree(pucDataWF1); + kfree(pucDataRAWWF0); + kfree(pucDataRAWWF1); + ASSERT(-1); + return -1; + } + + fgAppend = true; + if (prEventDumpMem->ucFragNum == 1) { + u4CurTimeTick = kalGetTimeTick(); + /* Store memory dump into sdcard, + * path /sdcard/dump_<current system tick>_<memory + * address>_<memory length>.hex + */ + + /*if blbist mkdir undre /data/blbist, the dump files wouls put + * on it */ + scnprintf(aucPathWF0, sizeof(aucPathWF0), "/tmp/dump_out_%05ld_WF0.txt", + g_u2DumpIndex); + scnprintf(aucPathWF1, sizeof(aucPathWF1), "/tmp/dump_out_%05ld_WF1.txt", + g_u2DumpIndex); + if (kalCheckPath(aucPathWF0) == -1) { + kalMemSet(aucPathWF0, 0x00, sizeof(aucPathWF0)); + scnprintf(aucPathWF0, sizeof(aucPathWF0), + "/data/dump_out_%05ld_WF0.txt", g_u2DumpIndex); + } else { + kalTrunkPath(aucPathWF0); + } + + if (kalCheckPath(aucPathWF1) == -1) { + kalMemSet(aucPathWF1, 0x00, sizeof(aucPathWF1)); + scnprintf(aucPathWF1, sizeof(aucPathWF1), + "/data/dump_out_%05ld_WF1.txt", g_u2DumpIndex); + } else { + kalTrunkPath(aucPathWF1); + } + + scnprintf(aucPathRAWWF0, sizeof(aucPathRAWWF0), + "/dump_RAW_%05ld_WF0.txt", g_u2DumpIndex); + scnprintf(aucPathRAWWF1, sizeof(aucPathRAWWF1), + "/dump_RAW_%05ld_WF1.txt", g_u2DumpIndex); + if (kalCheckPath(aucPathRAWWF0) == -1) { + kalMemSet(aucPathRAWWF0, 0x00, sizeof(aucPathRAWWF0)); + scnprintf(aucPathRAWWF0, sizeof(aucPathRAWWF0), + "/data/dump_RAW_%05ld_WF0.txt", g_u2DumpIndex); + } else { + kalTrunkPath(aucPathRAWWF0); + } + + if (kalCheckPath(aucPathRAWWF1) == -1) { + kalMemSet(aucPathRAWWF1, 0x00, sizeof(aucPathRAWWF1)); + scnprintf(aucPathRAWWF1, sizeof(aucPathRAWWF1), + "/data/dump_RAW_%05ld_WF1.txt", g_u2DumpIndex); + } else { + kalTrunkPath(aucPathRAWWF1); + } + + /* fgAppend = false; */ + } + + ptr = (u32 *)(&prEventDumpMem->aucBuffer[0]); + /*DBGLOG(INIT, INFO, ": ==> (prEventDumpMem = %08x %08x %08x)\n", + **(ptr), *(ptr + 4), *(ptr + 8));*/ + /*DBGLOG(INIT, INFO, ": ==> (prEventDumpMem->eIcapContent = %x)\n", + * prEventDumpMem->eIcapContent);*/ + + for (u4SrcOffset = 0, u4RemainByte = prEventDumpMem->u4Length; + u4RemainByte > 0;) { + u4FmtLen = (prEventDumpMem->eIcapContent == ICAP_CONTENT_SPECTRUM) ? + sizeof(SPECTRUM_BUS_FMT_T) : + sizeof(ICAP_BUS_FMT); + /* 4 bytes : 12 bytes */ + u4CpyLen = (u4RemainByte - u4FmtLen >= 0) ? u4FmtLen : u4RemainByte; + + if ((ucDstOffset + u4CpyLen) > sizeof(icapBusData)) { + DBGLOG( + INIT, ERROR, + "ucDstOffset(%u) + u4CpyLen(%u) exceed bound of icapBusData\n", + ucDstOffset, u4CpyLen); + kfree(pucDataWF0); + kfree(pucDataWF1); + kfree(pucDataRAWWF0); + kfree(pucDataRAWWF1); + ASSERT(-1); + return -1; + } + memcpy((u8 *)&icapBusData + ucDstOffset, + &prEventDumpMem->aucBuffer[0] + u4SrcOffset, u4CpyLen); + + if (prEventDumpMem->eIcapContent == ICAP_CONTENT_FIIQ || + prEventDumpMem->eIcapContent == ICAP_CONTENT_FDIQ) { + u4DataWLenF0 = scnprintf(pucDataWF0, u4DataWBufSize, "%8d,%8d\n", + icapBusData.rIqcBusData.u4Iqc0I, + icapBusData.rIqcBusData.u4Iqc0Q); + u4DataWLenF1 = scnprintf(pucDataWF1, u4DataWBufSize, "%8d,%8d\n", + icapBusData.rIqcBusData.u4Iqc1I, + icapBusData.rIqcBusData.u4Iqc1Q); + } else if (prEventDumpMem->eIcapContent - 1000 == ICAP_CONTENT_FIIQ || + prEventDumpMem->eIcapContent - 1000 == ICAP_CONTENT_FDIQ) { + u4Iqc160WF0Q0 = icapBusData.rIqc160BusData.u4Iqc0Q0P1 | + (icapBusData.rIqc160BusData.u4Iqc0Q0P2 << 8); + u4Iqc160WF1I1 = icapBusData.rIqc160BusData.u4Iqc1I1P1 | + (icapBusData.rIqc160BusData.u4Iqc1I1P2 << 4); + + u4DataWLenF0 = + scnprintf(pucDataWF0, u4DataWBufSize, "%8d,%8d\n%8d,%8d\n", + icapBusData.rIqc160BusData.u4Iqc0I0, u4Iqc160WF0Q0, + icapBusData.rIqc160BusData.u4Iqc0I1, + icapBusData.rIqc160BusData.u4Iqc0Q1); + + u4DataWLenF1 = + scnprintf(pucDataWF1, u4DataWBufSize, "%8d,%8d\n%8d,%8d\n", + icapBusData.rIqc160BusData.u4Iqc1I0, + icapBusData.rIqc160BusData.u4Iqc1Q0, u4Iqc160WF1I1, + icapBusData.rIqc160BusData.u4Iqc1Q1); + } else if (prEventDumpMem->eIcapContent == ICAP_CONTENT_SPECTRUM) { + u4DataWLenF0 = scnprintf(pucDataWF0, u4DataWBufSize, "%8d,%8d\n", + icapBusData.rSpectrumBusData.u4DcocI, + icapBusData.rSpectrumBusData.u4DcocQ); + } else if (prEventDumpMem->eIcapContent == ICAP_CONTENT_ADC) { + u4DataWLenF0 = scnprintf( + pucDataWF0, u4DataWBufSize, + "%8d,%8d\n%8d,%8d\n%8d,%8d\n%8d,%8d\n%8d,%8d\n%8d,%8d\n", + icapBusData.rPackedAdcBusData.u4AdcI0T0, + icapBusData.rPackedAdcBusData.u4AdcQ0T0, + icapBusData.rPackedAdcBusData.u4AdcI0T1, + icapBusData.rPackedAdcBusData.u4AdcQ0T1, + icapBusData.rPackedAdcBusData.u4AdcI0T2, + icapBusData.rPackedAdcBusData.u4AdcQ0T2, + icapBusData.rPackedAdcBusData.u4AdcI0T3, + icapBusData.rPackedAdcBusData.u4AdcQ0T3, + icapBusData.rPackedAdcBusData.u4AdcI0T4, + icapBusData.rPackedAdcBusData.u4AdcQ0T4, + icapBusData.rPackedAdcBusData.u4AdcI0T5, + icapBusData.rPackedAdcBusData.u4AdcQ0T5); + + u4DataWLenF1 = scnprintf( + pucDataWF1, u4DataWBufSize, + "%8d,%8d\n%8d,%8d\n%8d,%8d\n%8d,%8d\n%8d,%8d\n%8d,%8d\n", + icapBusData.rPackedAdcBusData.u4AdcI1T0, + icapBusData.rPackedAdcBusData.u4AdcQ1T0, + icapBusData.rPackedAdcBusData.u4AdcI1T1, + icapBusData.rPackedAdcBusData.u4AdcQ1T1, + icapBusData.rPackedAdcBusData.u4AdcI1T2, + icapBusData.rPackedAdcBusData.u4AdcQ1T2, + icapBusData.rPackedAdcBusData.u4AdcI1T3, + icapBusData.rPackedAdcBusData.u4AdcQ1T3, + icapBusData.rPackedAdcBusData.u4AdcI1T4, + icapBusData.rPackedAdcBusData.u4AdcQ1T4, + icapBusData.rPackedAdcBusData.u4AdcI1T5, + icapBusData.rPackedAdcBusData.u4AdcQ1T5); + } else if (prEventDumpMem->eIcapContent - 2000 == ICAP_CONTENT_ADC) { + u4DataWLenF0 = scnprintf(pucDataWF0, u4DataWBufSize, + "%8d,%8d\n%8d,%8d\n%8d,%8d\n", + icapBusData.rPackedAdcBusData.u4AdcI0T0, + icapBusData.rPackedAdcBusData.u4AdcQ0T0, + icapBusData.rPackedAdcBusData.u4AdcI0T1, + icapBusData.rPackedAdcBusData.u4AdcQ0T1, + icapBusData.rPackedAdcBusData.u4AdcI0T2, + icapBusData.rPackedAdcBusData.u4AdcQ0T2); + + u4DataWLenF1 = scnprintf(pucDataWF1, u4DataWBufSize, + "%8d,%8d\n%8d,%8d\n%8d,%8d\n", + icapBusData.rPackedAdcBusData.u4AdcI1T0, + icapBusData.rPackedAdcBusData.u4AdcQ1T0, + icapBusData.rPackedAdcBusData.u4AdcI1T1, + icapBusData.rPackedAdcBusData.u4AdcQ1T1, + icapBusData.rPackedAdcBusData.u4AdcI1T2, + icapBusData.rPackedAdcBusData.u4AdcQ1T2); + } else if (prEventDumpMem->eIcapContent == ICAP_CONTENT_TOAE) { + /* actually, this is DCOC. we take TOAE as DCOC */ + u4DataWLenF0 = scnprintf(pucDataWF0, u4DataWBufSize, "%8d,%8d\n", + icapBusData.rAdcBusData.u4Dcoc0I, + icapBusData.rAdcBusData.u4Dcoc0Q); + u4DataWLenF1 = scnprintf(pucDataWF1, u4DataWBufSize, "%8d,%8d\n", + icapBusData.rAdcBusData.u4Dcoc1I, + icapBusData.rAdcBusData.u4Dcoc1Q); + } + if (u4CpyLen == u4FmtLen) { /* the data format is complete */ + kalWriteToFile(aucPathWF0, fgAppend, pucDataWF0, u4DataWLenF0); + kalWriteToFile(aucPathWF1, fgAppend, pucDataWF1, u4DataWLenF1); + } + ptr = (u32 *)(&prEventDumpMem->aucBuffer[0] + u4SrcOffset); + u4DataRAWWLenF0 = scnprintf(pucDataRAWWF0, u4DataWBufSize, + "%08x%08x%08x\n", *(ptr + 2), *(ptr + 1), + *ptr); + kalWriteToFile(aucPathRAWWF0, fgAppend, pucDataRAWWF0, u4DataRAWWLenF0); + kalWriteToFile(aucPathRAWWF1, fgAppend, pucDataRAWWF1, u4DataRAWWLenF1); + + u4RemainByte -= u4CpyLen; + u4SrcOffset += u4CpyLen; /* shift offset */ + ucDstOffset = 0; /* only use ucDstOffset at first packet for + * align 2KB */ + } + /* if this is a last packet, we can't transfer the remain data. + * bcs we can't guarantee the data is complete align data format + */ + if (u4CpyLen != u4FmtLen) { /* the data format is complete */ + ucDstOffset = u4CpyLen; /* not align 2KB, keep the data and next + * packet data will append it */ + } + + kfree(pucDataWF0); + kfree(pucDataWF1); + kfree(pucDataRAWWF0); + kfree(pucDataRAWWF1); + + if (u4RemainByte < 0) { + ASSERT(-1); + return -1; + } + + return 0; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called to handle dump burst event + * + * @param prAdapter Pointer to the Adapter structure. + * @param prCmdInfo Pointer to the command information + * @param pucEventBuf Pointer to event buffer + * + * @return none + * + */ +/*----------------------------------------------------------------------------*/ + +void nicEventQueryMemDump(IN P_ADAPTER_T prAdapter, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_EVENT_DUMP_MEM_T prEventDumpMem; + static u8 aucPath[256] = { 0 }; // initialized all zeros + static u8 aucPath_done[300]; + static u32 u4CurTimeTick; + + ASSERT(prAdapter); + ASSERT(pucEventBuf); + + snprintf(aucPath, sizeof(aucPath), "/dump_%05ld.hex", g_u2DumpIndex); + + if (u4EventBufLen < sizeof(EVENT_DUMP_MEM_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_DUMP_MEM_T)); + return; + } + prEventDumpMem = (P_EVENT_DUMP_MEM_T)(pucEventBuf); + if (u4EventBufLen < sizeof(EVENT_DUMP_MEM_T) + prEventDumpMem->u4Length) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, + sizeof(EVENT_DUMP_MEM_T) + prEventDumpMem->u4Length); + return; + } + if (kalCheckPath(aucPath) == -1) { + kalMemSet(aucPath, 0x00, 256); + snprintf(aucPath, sizeof(aucPath), "/data/dump_%05ld.hex", + g_u2DumpIndex); + } + + if (prEventDumpMem->ucFragNum == 1) { + /* Store memory dump into sdcard, + * path /sdcard/dump_<current system tick>_<memory + * address>_<memory length>.hex + */ + u4CurTimeTick = kalGetTimeTick(); + + /*if blbist mkdir undre /data/blbist, the dump files wouls put + * on it */ + snprintf(aucPath, sizeof(aucPath), "/dump_%05ld.hex", g_u2DumpIndex); + if (kalCheckPath(aucPath) == -1) { + kalMemSet(aucPath, 0x00, 256); + snprintf(aucPath, sizeof(aucPath), "/data/dump_%05ld.hex", + g_u2DumpIndex); + } + + kalWriteToFile(aucPath, false, &prEventDumpMem->aucBuffer[0], + prEventDumpMem->u4Length); + } else { + /* Append current memory dump to the hex file */ + kalWriteToFile(aucPath, true, &prEventDumpMem->aucBuffer[0], + prEventDumpMem->u4Length); + } +#if CFG_SUPPORT_QA_TOOL + TsfRawData2IqFmt(prEventDumpMem); +#endif + DBGLOG(INIT, INFO, "iCap : ==> (u4RemainLength = %x, u4Address=%x )\n", + prEventDumpMem->u4RemainLength, prEventDumpMem->u4Address); + + if (prEventDumpMem->u4RemainLength == 0 || + prEventDumpMem->u4Address == 0xFFFFFFFF) { + /* The request is finished or firmware response a error */ + /* Reply time tick to iwpriv */ + + g_bIcapEnable = false; + g_bCaptureDone = true; + + snprintf(aucPath_done, sizeof(aucPath_done), "/file_dump_done.txt"); + if (kalCheckPath(aucPath_done) == -1) { + kalMemSet(aucPath_done, 0x00, 256); + snprintf(aucPath_done, sizeof(aucPath_done), + "/data/file_dump_done.txt"); + } + DBGLOG(INIT, INFO, ": ==> gen done_file\n"); + kalWriteToFile(aucPath_done, false, aucPath_done, sizeof(aucPath_done)); +#if CFG_SUPPORT_QA_TOOL + g_au4Offset[0][0] = 0; + g_au4Offset[0][1] = 9; + g_au4Offset[1][0] = 0; + g_au4Offset[1][1] = 9; +#endif + + g_u2DumpIndex++; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called when command for memory dump has + * replied a event. + * + * @param prAdapter Pointer to the Adapter structure. + * @param prCmdInfo Pointer to the command information + * @param pucEventBuf Pointer to event buffer + * + * @return none + * + */ +/*----------------------------------------------------------------------------*/ +void nicCmdEventQueryMemDump(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + P_EVENT_DUMP_MEM_T prEventDumpMem; + static u8 aucPath[256] = { 0 }; // initialized all zeros + /* static u8 aucPath_done[300]; */ + static u32 u4CurTimeTick; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (1) { + prGlueInfo = prAdapter->prGlueInfo; + if (u4EventBufLen < sizeof(EVENT_DUMP_MEM_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_DUMP_MEM_T)); + return; + } + prEventDumpMem = (P_EVENT_DUMP_MEM_T)(pucEventBuf); + if (u4EventBufLen < + sizeof(EVENT_DUMP_MEM_T) + prEventDumpMem->u4Length) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, + sizeof(EVENT_DUMP_MEM_T) + prEventDumpMem->u4Length); + return; + } + u4QueryInfoLen = sizeof(P_PARAM_CUSTOM_MEM_DUMP_STRUCT_T); + + /* Currently, only allow to dump max to 4K bytes (per command). + */ + if (prEventDumpMem->u4Length > MAX_MEMORY_DUMP_SIZE) { + DBGLOG(INIT, WARN, "SKIP DUMP FILE: Invalid u4Length (%d)\n", + prEventDumpMem->u4Length); + goto write_file_done; + } + + if (prEventDumpMem->ucFragNum == 1) { + /* Store memory dump into sdcard, + * path /sdcard/dump_<current system tick>_<memory + * address>_<memory length>.hex + */ + u4CurTimeTick = kalGetTimeTick(); + + /* PeiHsuan add for avoiding out of memory 20160801 */ + if (g_u2DumpIndex >= 20) { + g_u2DumpIndex = 0; + } + + /*if blbist mkdir undre /data/blbist, the dump files + * wouls put on it */ + snprintf(aucPath, sizeof(aucPath), "/dump_%05ld.hex", + g_u2DumpIndex); + if (kalCheckPath(aucPath) == -1) { + kalMemSet(aucPath, 0x00, 256); + snprintf(aucPath, sizeof(aucPath), "/data/dump_%05ld.hex", + g_u2DumpIndex); + } else { + kalTrunkPath(aucPath); + } + + DBGLOG(INIT, INFO, "iCap Create New Dump File dump_%05ld.hex\n", + g_u2DumpIndex); + + kalWriteToFile(aucPath, false, &prEventDumpMem->aucBuffer[0], + prEventDumpMem->u4Length); + } else { + if (kalCheckPath(aucPath) == -1) { + DBGLOG( + INIT, WARN, + "Dump file:%s invalid while receiving frag[%d] pkt (not 1st " + "frag), skip dumpping.\n", + aucPath, + prEventDumpMem->ucFragNum); + } else { + /* Append current memory dump to the hex file */ + kalWriteToFile(aucPath, true, &prEventDumpMem->aucBuffer[0], + prEventDumpMem->u4Length); + } + } +#if CFG_SUPPORT_QA_TOOL + TsfRawData2IqFmt(prEventDumpMem); +#endif +write_file_done: + if (prEventDumpMem->u4RemainLength == 0 || + prEventDumpMem->u4Address == 0xFFFFFFFF) { + /* The request is finished or firmware response a error + */ + /* Reply time tick to iwpriv */ + if (prCmdInfo->fgIsOid) { + /* the oid would be complete only in oid-trigger + * mode, that is no need to if the event-trigger + */ + if (g_bIcapEnable == false) { + *((u32 *)prCmdInfo->pvInformationBuffer) = u4CurTimeTick; + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, + u4QueryInfoLen, WLAN_STATUS_SUCCESS); + } + } + g_bIcapEnable = false; + g_bCaptureDone = true; + g_u2DumpIndex++; + } else { + } + } + + return; +} + +#if CFG_SUPPORT_BATCH_SCAN +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called when event for SUPPORT_BATCH_SCAN + * + * @param prAdapter Pointer to the Adapter structure. + * @param prCmdInfo Pointer to the command information + * @param pucEventBuf Pointer to the event buffer + * + * @return none + * + */ +/*----------------------------------------------------------------------------*/ +void nicCmdEventBatchScanResult(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_EVENT_BATCH_RESULT_T prEventBatchResult; + P_GLUE_INFO_T prGlueInfo; + + DBGLOG(SCN, TRACE, "nicCmdEventBatchScanResult"); + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_BATCH_RESULT_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_BATCH_RESULT_T)); + return; + } + prEventBatchResult = (P_EVENT_BATCH_RESULT_T)pucEventBuf; + + u4QueryInfoLen = sizeof(EVENT_BATCH_RESULT_T); + kalMemCopy(prCmdInfo->pvInformationBuffer, prEventBatchResult, + sizeof(EVENT_BATCH_RESULT_T)); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} +#endif + +#if CFG_SUPPORT_BUILD_DATE_CODE +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called when event for build date code information + * has been retrieved + * + * @param prAdapter Pointer to the Adapter structure. + * @param prCmdInfo Pointer to the command information + * @param pucEventBuf Pointer to the event buffer + * + * @return none + * + */ +/*----------------------------------------------------------------------------*/ +void nicCmdEventBuildDateCode(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_EVENT_BUILD_DATE_CODE prEvent; + P_GLUE_INFO_T prGlueInfo; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + + /* 4 <2> Update information of OID */ + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + if (u4EventBufLen < sizeof(EVENT_BUILD_DATE_CODE)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_BUILD_DATE_CODE)); + return; + } + prEvent = (P_EVENT_BUILD_DATE_CODE)pucEventBuf; + + u4QueryInfoLen = sizeof(u8) * 16; + kalMemCopy(prCmdInfo->pvInformationBuffer, prEvent->aucDateCode, + sizeof(u8) * 16); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called when event for query STA link status + * has been retrieved + * + * @param prAdapter Pointer to the Adapter structure. + * @param prCmdInfo Pointer to the command information + * @param pucEventBuf Pointer to the event buffer + * + * @return none + * + */ +/*----------------------------------------------------------------------------*/ +void nicCmdEventQueryStaStatistics(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_EVENT_STA_STATISTICS_T prEvent; + P_GLUE_INFO_T prGlueInfo; + P_PARAM_GET_STA_STATISTICS prStaStatistics; + ENUM_WMM_ACI_T eAci; + P_STA_RECORD_T prStaRec; + u8 ucDbdcIdx; + extern u32 g_au4RxMpduCnt[ENUM_BAND_NUM]; + extern u32 g_au4FcsError[ENUM_BAND_NUM]; + extern u32 g_au4RxFifoCnt[ENUM_BAND_NUM]; + extern u32 g_au4AmpduTxSfCnt[ENUM_BAND_NUM]; + extern u32 g_au4AmpduTxAckSfCnt[ENUM_BAND_NUM]; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + ASSERT(prCmdInfo->pvInformationBuffer); + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_STA_STATISTICS_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STA_STATISTICS_T)); + return; + } + prEvent = (P_EVENT_STA_STATISTICS_T)pucEventBuf; + prStaStatistics = + (P_PARAM_GET_STA_STATISTICS)prCmdInfo->pvInformationBuffer; + + u4QueryInfoLen = sizeof(PARAM_GET_STA_STATISTICS); + + /* Statistics from FW is valid */ + if (prEvent->u4Flags & BIT(0)) { + prStaStatistics->ucPer = prEvent->ucPer; + prStaStatistics->ucRcpi = prEvent->ucRcpi; + prStaStatistics->u4PhyMode = prEvent->u4PhyMode; + prStaStatistics->u2LinkSpeed = prEvent->u2LinkSpeed; + + prStaStatistics->u4TxFailCount = prEvent->u4TxFailCount; + prStaStatistics->u4TxLifeTimeoutCount = + prEvent->u4TxLifeTimeoutCount; + prStaStatistics->u4TransmitCount = prEvent->u4TransmitCount; + prStaStatistics->u4TransmitFailCount = prEvent->u4TransmitFailCount; + prStaStatistics->u4Rate1TxCnt = prEvent->u4Rate1TxCnt; + prStaStatistics->u4Rate1FailCnt = prEvent->u4Rate1FailCnt; + + prStaStatistics->ucTemperature = prEvent->ucTemperature; + prStaStatistics->ucSkipAr = prEvent->ucSkipAr; + prStaStatistics->ucArTableIdx = prEvent->ucArTableIdx; + prStaStatistics->ucRateEntryIdx = prEvent->ucRateEntryIdx; + prStaStatistics->ucRateEntryIdxPrev = prEvent->ucRateEntryIdxPrev; + prStaStatistics->ucTxSgiDetectPassCnt = + prEvent->ucTxSgiDetectPassCnt; + prStaStatistics->ucAvePer = prEvent->ucAvePer; + kalMemCopy(prStaStatistics->aucArRatePer, prEvent->aucArRatePer, + sizeof(prEvent->aucArRatePer)); + kalMemCopy(prStaStatistics->aucRateEntryIndex, + prEvent->aucRateEntryIndex, + sizeof(prEvent->aucRateEntryIndex)); + prStaStatistics->ucArStateCurr = prEvent->ucArStateCurr; + prStaStatistics->ucArStatePrev = prEvent->ucArStatePrev; + prStaStatistics->ucArActionType = prEvent->ucArActionType; + prStaStatistics->ucHighestRateCnt = prEvent->ucHighestRateCnt; + prStaStatistics->ucLowestRateCnt = prEvent->ucLowestRateCnt; + prStaStatistics->u2TrainUp = prEvent->u2TrainUp; + prStaStatistics->u2TrainDown = prEvent->u2TrainDown; + kalMemCopy(&prStaStatistics->rTxVector, &prEvent->rTxVector, + sizeof(prEvent->rTxVector)); + kalMemCopy(&prStaStatistics->rMibInfo, &prEvent->rMibInfo, + sizeof(prEvent->rMibInfo)); + for (ucDbdcIdx = 0; ucDbdcIdx < ENUM_BAND_NUM; ucDbdcIdx++) { + g_au4RxMpduCnt[ucDbdcIdx] += + prStaStatistics->rMibInfo[ucDbdcIdx].u4RxMpduCnt; + g_au4FcsError[ucDbdcIdx] += + prStaStatistics->rMibInfo[ucDbdcIdx].u4FcsError; + g_au4RxFifoCnt[ucDbdcIdx] += + prStaStatistics->rMibInfo[ucDbdcIdx].u4RxFifoFull; + g_au4AmpduTxSfCnt[ucDbdcIdx] += + prStaStatistics->rMibInfo[ucDbdcIdx].u4AmpduTxSfCnt; + g_au4AmpduTxAckSfCnt[ucDbdcIdx] += + prStaStatistics->rMibInfo[ucDbdcIdx].u4AmpduTxAckSfCnt; + } + prStaStatistics->fgIsForceTxStream = prEvent->fgIsForceTxStream; + prStaStatistics->fgIsForceSeOff = prEvent->fgIsForceSeOff; + + prStaRec = cnmGetStaRecByIndex(prAdapter, prEvent->ucStaRecIdx); + + if (prStaRec) { + /*link layer statistics */ + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + prStaStatistics->arLinkStatistics[eAci].u4TxFailMsdu = + prEvent->arLinkStatistics[eAci].u4TxFailMsdu; + prStaStatistics->arLinkStatistics[eAci].u4TxRetryMsdu = + prEvent->arLinkStatistics[eAci].u4TxRetryMsdu; + + /*for dump bss statistics */ + prStaRec->arLinkStatistics[eAci].u4TxFailMsdu = + prEvent->arLinkStatistics[eAci].u4TxFailMsdu; + prStaRec->arLinkStatistics[eAci].u4TxRetryMsdu = + prEvent->arLinkStatistics[eAci].u4TxRetryMsdu; + } + } + if (prEvent->u4TxCount) { + u32 u4TxDoneAirTimeMs = + USEC_TO_MSEC(prEvent->u4TxDoneAirTime * 32); + + prStaStatistics->u4TxAverageAirTime = + (u4TxDoneAirTimeMs / prEvent->u4TxCount); + } else { + prStaStatistics->u4TxAverageAirTime = 0; + } + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is called when event for query LTE safe channels + * has been retrieved + * + * @param prAdapter Pointer to the Adapter structure. + * @param prCmdInfo Pointer to the command information + * @param pucEventBuf Pointer to the event buffer + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void nicCmdEventQueryLteSafeChn(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_EVENT_LTE_SAFE_CHN_T prEvent; + P_GLUE_INFO_T prGlueInfo; + P_PARAM_GET_CHN_INFO prLteSafeChnInfo; + u8 ucIdx = 0; + + if ((prAdapter == NULL) || (prCmdInfo == NULL) || (pucEventBuf == NULL) || + (prCmdInfo->pvInformationBuffer == NULL)) { + ASSERT(false); + return; + } + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_LTE_SAFE_CHN_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_LTE_SAFE_CHN_T)); + return; + } + prEvent = (P_EVENT_LTE_SAFE_CHN_T)pucEventBuf; /* FW responsed + * data */ + + prLteSafeChnInfo = (P_PARAM_GET_CHN_INFO)prCmdInfo->pvInformationBuffer; + + u4QueryInfoLen = sizeof(PARAM_GET_CHN_INFO); + + /* Statistics from FW is valid */ + if (prEvent->u4Flags & BIT(0)) { + for (ucIdx = 0; ucIdx < NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_MAX; + ucIdx++) { + prLteSafeChnInfo->rLteSafeChnList.au4SafeChannelBitmask[ucIdx] = + prEvent->rLteSafeChn.au4SafeChannelBitmask[ucIdx]; + + DBGLOG(P2P, INFO, "[ACS]LTE safe channels[%d]=0x%08x\n", ucIdx, + prLteSafeChnInfo->rLteSafeChnList + .au4SafeChannelBitmask[ucIdx]); + } + } + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} +#endif + +void nicEventRddPulseDump(IN P_ADAPTER_T prAdapter, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u16 u2Idx, u2PulseCnt; + P_EVENT_WIFI_RDD_TEST_T prRddPulseEvent; + + ASSERT(prAdapter); + ASSERT(pucEventBuf); + if (u4EventBufLen < sizeof(EVENT_WIFI_RDD_TEST_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_WIFI_RDD_TEST_T)); + return; + } + prRddPulseEvent = (P_EVENT_WIFI_RDD_TEST_T)(pucEventBuf); + + u2PulseCnt = (prRddPulseEvent->u4FuncLength - RDD_EVENT_HDR_SIZE) / + RDD_ONEPLUSE_SIZE; + if (u4EventBufLen < + sizeof(EVENT_WIFI_RDD_TEST_T) + u2PulseCnt * RDD_ONEPLUSE_SIZE) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, + sizeof(EVENT_WIFI_RDD_TEST_T) + u2PulseCnt * RDD_ONEPLUSE_SIZE); + return; + } + + DBGLOG(INIT, INFO, "[RDD]0x%08x %08d[RDD%d]\n", prRddPulseEvent->u4Prefix, + prRddPulseEvent->u4Count, prRddPulseEvent->ucRddIdx); + + for (u2Idx = 0; u2Idx < u2PulseCnt; u2Idx++) { + DBGLOG(INIT, INFO, "[RDD]0x%02x%02x%02x%02x %02x%02x%02x%02x[RDD%d]\n", + prRddPulseEvent + ->aucBuffer[RDD_ONEPLUSE_SIZE * u2Idx + RDD_PULSE_OFFSET3], + prRddPulseEvent + ->aucBuffer[RDD_ONEPLUSE_SIZE * u2Idx + RDD_PULSE_OFFSET2], + prRddPulseEvent + ->aucBuffer[RDD_ONEPLUSE_SIZE * u2Idx + RDD_PULSE_OFFSET1], + prRddPulseEvent + ->aucBuffer[RDD_ONEPLUSE_SIZE * u2Idx + RDD_PULSE_OFFSET0], + prRddPulseEvent + ->aucBuffer[RDD_ONEPLUSE_SIZE * u2Idx + RDD_PULSE_OFFSET7], + prRddPulseEvent + ->aucBuffer[RDD_ONEPLUSE_SIZE * u2Idx + RDD_PULSE_OFFSET6], + prRddPulseEvent + ->aucBuffer[RDD_ONEPLUSE_SIZE * u2Idx + RDD_PULSE_OFFSET5], + prRddPulseEvent + ->aucBuffer[RDD_ONEPLUSE_SIZE * u2Idx + RDD_PULSE_OFFSET4], + prRddPulseEvent->ucRddIdx); + } + + DBGLOG(INIT, INFO, "[RDD]0x%08x %08x[RDD%d]\n", + prRddPulseEvent->u4SubBandRssi0, prRddPulseEvent->u4SubBandRssi1, + prRddPulseEvent->ucRddIdx); +} + +#if CFG_SUPPORT_ADVANCE_CONTROL +void nicCmdEventQueryAdvCtrl(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + u8 *query; + P_GLUE_INFO_T prGlueInfo; + u32 query_len; + P_CMD_ADV_CONFIG_HEADER_T hdr; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (!pucEventBuf) { + DBGLOG(REQ, ERROR, "pucEventBuf is null.\n"); + return; + } + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(CMD_ADV_CONFIG_HEADER_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(CMD_ADV_CONFIG_HEADER_T)); + return; + } + hdr = (P_CMD_ADV_CONFIG_HEADER_T)pucEventBuf; + DBGLOG(REQ, LOUD, "%s type %x len %d>\n", __func__, hdr->u2Type, + hdr->u2Len); + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + query_len = hdr->u2Len; + query = prCmdInfo->pvInformationBuffer; + if (query && (query_len == prCmdInfo->u4InformationBufferLength)) { + kalMemCopy(query, hdr, query_len); + } else { + DBGLOG(REQ, LOUD, "%s type %x, len %d != buflen %d>\n", __func__, + hdr->u2Type, hdr->u2Len, + prCmdInfo->u4InformationBufferLength); + } + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, query_len, + WLAN_STATUS_SUCCESS); + } +} +#endif + +#if CFG_SUPPORT_MSP +void nicCmdEventQueryWlanInfo(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_PARAM_HW_WLAN_INFO_T prWlanInfo; + P_EVENT_WLAN_INFO prEventWlanInfo; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_WLAN_INFO)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_WLAN_INFO)); + return; + } + prEventWlanInfo = (P_EVENT_WLAN_INFO)pucEventBuf; + + DBGLOG(RSN, INFO, "MT6632 : nicCmdEventQueryWlanInfo\n"); + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + u4QueryInfoLen = sizeof(PARAM_HW_WLAN_INFO_T); + prWlanInfo = (P_PARAM_HW_WLAN_INFO_T)prCmdInfo->pvInformationBuffer; + + /* prWlanInfo->u4Length = sizeof(PARAM_HW_WLAN_INFO_T); */ + if (prEventWlanInfo && prWlanInfo) { + kalMemCopy(&prWlanInfo->rWtblTxConfig, + &prEventWlanInfo->rWtblTxConfig, + sizeof(PARAM_TX_CONFIG_T)); + kalMemCopy(&prWlanInfo->rWtblSecConfig, + &prEventWlanInfo->rWtblSecConfig, + sizeof(PARAM_SEC_CONFIG_T)); + kalMemCopy(&prWlanInfo->rWtblKeyConfig, + &prEventWlanInfo->rWtblKeyConfig, + sizeof(PARAM_KEY_CONFIG_T)); + kalMemCopy(&prWlanInfo->rWtblRateInfo, + &prEventWlanInfo->rWtblRateInfo, + sizeof(PARAM_PEER_RATE_INFO_T)); + kalMemCopy(&prWlanInfo->rWtblBaConfig, + &prEventWlanInfo->rWtblBaConfig, + sizeof(PARAM_PEER_BA_CONFIG_T)); + kalMemCopy(&prWlanInfo->rWtblPeerCap, + &prEventWlanInfo->rWtblPeerCap, + sizeof(PARAM_PEER_CAP_T)); + kalMemCopy(&prWlanInfo->rWtblRxCounter, + &prEventWlanInfo->rWtblRxCounter, + sizeof(PARAM_PEER_RX_COUNTER_ALL_T)); + kalMemCopy(&prWlanInfo->rWtblTxCounter, + &prEventWlanInfo->rWtblTxCounter, + sizeof(PARAM_PEER_TX_COUNTER_ALL_T)); + } + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} + +void nicCmdEventQueryMibInfo(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_PARAM_HW_MIB_INFO_T prMibInfo; + P_EVENT_MIB_INFO prEventMibInfo; + P_GLUE_INFO_T prGlueInfo; + u32 u4QueryInfoLen; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + if (u4EventBufLen < sizeof(EVENT_MIB_INFO)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_MIB_INFO)); + return; + } + prEventMibInfo = (P_EVENT_MIB_INFO)pucEventBuf; + + DBGLOG(RSN, INFO, "MT6632 : nicCmdEventQueryMibInfo\n"); + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + + u4QueryInfoLen = sizeof(PARAM_HW_MIB_INFO_T); + prMibInfo = (P_PARAM_HW_MIB_INFO_T)prCmdInfo->pvInformationBuffer; + if (prEventMibInfo && prMibInfo) { + kalMemCopy(&prMibInfo->rHwMibCnt, &prEventMibInfo->rHwMibCnt, + sizeof(HW_MIB_COUNTER_T)); + kalMemCopy(&prMibInfo->rHwMib2Cnt, &prEventMibInfo->rHwMib2Cnt, + sizeof(HW_MIB2_COUNTER_T)); + kalMemCopy(&prMibInfo->rHwTxAmpduMts, + &prEventMibInfo->rHwTxAmpduMts, + sizeof(HW_TX_AMPDU_METRICS_T)); + } + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} +#endif + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +void nicCmdEventTxMcsInfo(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + struct EVENT_TX_MCS_INFO *prTxMcsEvent; + struct PARAM_TX_MCS_INFO *prTxMcsInfo; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + ASSERT(pucEventBuf); + ASSERT(prCmdInfo->pvInformationBuffer); + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + if (u4EventBufLen < sizeof(struct EVENT_TX_MCS_INFO)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(struct EVENT_TX_MCS_INFO)); + return; + } + prTxMcsEvent = (struct EVENT_TX_MCS_INFO *)pucEventBuf; + prTxMcsInfo = + (struct PARAM_TX_MCS_INFO *)prCmdInfo->pvInformationBuffer; + + u4QueryInfoLen = sizeof(struct EVENT_TX_MCS_INFO); + + kalMemCopy(prTxMcsInfo->au2TxRateCode, prTxMcsEvent->au2TxRateCode, + sizeof(prTxMcsEvent->au2TxRateCode)); + kalMemCopy(prTxMcsInfo->aucTxRatePer, prTxMcsEvent->aucTxRatePer, + sizeof(prTxMcsEvent->aucTxRatePer)); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} +#endif + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +WLAN_STATUS nicCmdEventQueryNicCsumOffload(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_NIC_CSUM_OFFLOAD_T prChecksumOffload = (P_NIC_CSUM_OFFLOAD_T)pucEventBuf; + if (u4EventBufLen < sizeof(NIC_CSUM_OFFLOAD_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(NIC_CSUM_OFFLOAD_T)); + return WLAN_STATUS_FAILURE; + } + prAdapter->fgIsSupportCsumOffload = + prChecksumOffload->ucIsSupportCsumOffload; + + DBGLOG(INIT, INFO, + "nicCmdEventQueryNicCsumOffload: ucIsSupportCsumOffload = %x\n", + prAdapter->fgIsSupportCsumOffload); + + return WLAN_STATUS_SUCCESS; +} +#endif + +WLAN_STATUS nicCmdEventQueryNicCoexFeature(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_NIC_COEX_FEATURE_T prCoexFeature = (P_NIC_COEX_FEATURE_T)pucEventBuf; + if (u4EventBufLen < sizeof(NIC_COEX_FEATURE_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(NIC_COEX_FEATURE_T)); + return WLAN_STATUS_FAILURE; + } + prAdapter->u4FddMode = prCoexFeature->u4FddMode; + + DBGLOG(INIT, INFO, "nicCmdEventQueryNicCoexFeature: u4FddMode = %x\n", + prAdapter->u4FddMode); + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS nicCmdEventQueryNicEfuseAddr(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_NIC_EFUSE_ADDRESS_T prTxResource = (P_NIC_EFUSE_ADDRESS_T)pucEventBuf; + if (u4EventBufLen < sizeof(NIC_EFUSE_ADDRESS_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(NIC_EFUSE_ADDRESS_T)); + return WLAN_STATUS_FAILURE; + } + prAdapter->u4EfuseStartAddress = prTxResource->u4EfuseStartAddress; + prAdapter->u4EfuseEndAddress = prTxResource->u4EfuseEndAddress; + + DBGLOG(INIT, STATE, + "nicCmdEventQueryNicEfuseAddr: u4EfuseStartAddress = %x\n", + prAdapter->u4EfuseStartAddress); + DBGLOG(INIT, STATE, + "nicCmdEventQueryNicEfuseAddr: u4EfuseEndAddress = %x\n", + prAdapter->u4EfuseEndAddress); + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS nicCmdEventQueryEfuseOffset(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + struct _NIC_EFUSE_OFFSET_T *prEfuseOffset = + (struct _NIC_EFUSE_OFFSET_T *)pucEventBuf; + if (u4EventBufLen < sizeof(struct _NIC_EFUSE_OFFSET_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(struct _NIC_EFUSE_OFFSET_T)); + return WLAN_STATUS_FAILURE; + } + if (prEfuseOffset->u4TotalItem > 0) { + prAdapter->u4EfuseMacAddrOffset = prEfuseOffset->u4WlanMacAddr; + } + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS nicCmdEventQueryNicTxResource(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, + IN u32 u4EventBufLen) +{ + P_NIC_TX_RESOURCE_T prTxResource = (P_NIC_TX_RESOURCE_T)pucEventBuf; + if (u4EventBufLen < sizeof(NIC_TX_RESOURCE_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(NIC_TX_RESOURCE_T)); + return WLAN_STATUS_FAILURE; + } + prAdapter->fgIsNicTxReousrceValid = true; + prAdapter->nicTxReousrce.u4McuTotalResource = + prTxResource->u4McuTotalResource; + prAdapter->nicTxReousrce.u4McuResourceUnit = + prTxResource->u4McuResourceUnit; + prAdapter->nicTxReousrce.u4LmacTotalResource = + prTxResource->u4LmacTotalResource; + prAdapter->nicTxReousrce.u4LmacResourceUnit = + prTxResource->u4LmacResourceUnit; + + DBGLOG(INIT, INFO, + "nicCmdEventQueryNicTxResource: u4McuTotalResource = %x\n", + prAdapter->nicTxReousrce.u4McuTotalResource); + DBGLOG(INIT, INFO, + "nicCmdEventQueryNicTxResource: u4McuResourceUnit = %x\n", + prAdapter->nicTxReousrce.u4McuResourceUnit); + DBGLOG(INIT, INFO, + "nicCmdEventQueryNicTxResource: u4LmacTotalResource = %x\n", + prAdapter->nicTxReousrce.u4LmacTotalResource); + DBGLOG(INIT, INFO, + "nicCmdEventQueryNicTxResource: u4LmacResourceUnit = %x\n", + prAdapter->nicTxReousrce.u4LmacResourceUnit); + + return WLAN_STATUS_SUCCESS; +} + +void nicCmdEventQueryNicCapabilityV2(IN P_ADAPTER_T prAdapter, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + P_EVENT_NIC_CAPABILITY_V2_T prEventNicV2 = + (P_EVENT_NIC_CAPABILITY_V2_T)pucEventBuf; + P_NIC_CAPABILITY_V2_ELEMENT prElement; + u32 tag_idx, table_idx, offset; + + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(EVENT_NIC_CAPABILITY_V2_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_NIC_CAPABILITY_V2_T)); + return; + } + + offset = 0; + + /* process each element */ + for (tag_idx = 0; tag_idx < prEventNicV2->u2TotalElementNum; tag_idx++) { + prElement = + (P_NIC_CAPABILITY_V2_ELEMENT)(prEventNicV2->aucBuffer + offset); + if (u4EventBufLen < offset + sizeof(NIC_CAPABILITY_V2_ELEMENT)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d (offset)\n", + __func__, u4EventBufLen, offset + + sizeof(NIC_CAPABILITY_V2_ELEMENT)); + return; + } + + for (table_idx = 0; table_idx < (sizeof(gNicCapabilityV2InfoTable) / + sizeof(NIC_CAPABILITY_V2_REF_TABLE_T)); + table_idx++) { + /* find the corresponding tag's handler */ + if (gNicCapabilityV2InfoTable[table_idx].tag_type == + prElement->tag_type) { + gNicCapabilityV2InfoTable[table_idx].hdlr( + prAdapter, prElement->aucbody, u4EventBufLen - offset); + break; + } + } + + /* move to the next tag */ + offset += prElement->body_len + sizeof(NIC_CAPABILITY_V2_ELEMENT); + } +} + +void nicEventLinkQuality(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_CMD_INFO_T prCmdInfo; + +#if CFG_ENABLE_WIFI_DIRECT && CFG_SUPPORT_P2P_RSSI_QUERY + if (prEvent->u2PacketLen == + EVENT_HDR_WITHOUT_RXD_SIZE + sizeof(EVENT_LINK_QUALITY_EX)) { + P_EVENT_LINK_QUALITY_EX prLqEx = + (P_EVENT_LINK_QUALITY_EX)(prEvent->aucBuffer); + if (u4EventBufLen < sizeof(EVENT_LINK_QUALITY_EX)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_LINK_QUALITY_EX)); + return; + } + if (prLqEx->ucIsLQ0Rdy) { + nicUpdateLinkQuality(prAdapter, 0, (P_EVENT_LINK_QUALITY)prLqEx); + } + if (prLqEx->ucIsLQ1Rdy) { + nicUpdateLinkQuality(prAdapter, 1, (P_EVENT_LINK_QUALITY)prLqEx); + } + } else { + if (u4EventBufLen < sizeof(EVENT_LINK_QUALITY)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_LINK_QUALITY)); + return; + } + /* For old FW, P2P may invoke link quality query, and make + * driver flag becone true. */ + DBGLOG(P2P, WARN, "Old FW version, not support P2P RSSI query.\n"); + + /* Must not use NETWORK_TYPE_P2P_INDEX, cause the structure is + * mismatch. */ + nicUpdateLinkQuality(prAdapter, 0, + (P_EVENT_LINK_QUALITY)(prEvent->aucBuffer)); + } +#else + /*only support ais query */ + { + u8 ucBssIndex; + P_BSS_INFO_T prBssInfo; + if (u4EventBufLen < sizeof(EVENT_LINK_QUALITY_V2)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_LINK_QUALITY_V2)); + return; + } + for (ucBssIndex = 0; ucBssIndex < BSS_INFO_NUM; ucBssIndex++) { + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + + if (prBssInfo->eNetworkType == NETWORK_TYPE_AIS && + prBssInfo->fgIsInUse) { + break; + } + } + + if (ucBssIndex >= BSS_INFO_NUM) { + ucBssIndex = 1; /* No hit(bss1 for default ais network) + */ + } + nicUpdateLinkQuality(prAdapter, ucBssIndex, + (P_EVENT_LINK_QUALITY_V2)(prEvent->aucBuffer)); + } +#endif + + /* command response handling */ + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, + prEvent->aucBuffer, u4EventBufLen); + } else if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_SUCCESS); + } + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } +} + +void nicEventLayer0ExtMagic(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_CMD_INFO_T prCmdInfo; + P_EVENT_ACCESS_EFUSE prEventEfuseAccess; + P_EVENT_EFUSE_FREE_BLOCK_T prEventGetFreeBlock; + P_EVENT_GET_TX_POWER_T prEventGetTXPower; + + if ((prEvent->ucExtenEID) == EXT_EVENT_ID_CMD_RESULT) { + u4QueryInfoLen = sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T); + + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + if ((prCmdInfo->fgIsOid) != 0) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, + u4QueryInfoLen, WLAN_STATUS_SUCCESS); + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + } + } else if ((prEvent->ucExtenEID) == EXT_EVENT_ID_CMD_EFUSE_ACCESS) { + if (u4EventBufLen < sizeof(EVENT_ACCESS_EFUSE)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_ACCESS_EFUSE)); + return; + } + u4QueryInfoLen = sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T); + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + prEventEfuseAccess = (P_EVENT_ACCESS_EFUSE)(prEvent->aucBuffer); + + /* Efuse block size 16 */ + kalMemCopy(prAdapter->aucEepromVaule, prEventEfuseAccess->aucData, 16); + + if (prCmdInfo != NULL) { + if ((prCmdInfo->fgIsOid) != 0) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, + u4QueryInfoLen, WLAN_STATUS_SUCCESS); + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + } + } else if ((prEvent->ucExtenEID) == EXT_EVENT_ID_EFUSE_FREE_BLOCK) { + if (u4EventBufLen < sizeof(EVENT_EFUSE_FREE_BLOCK_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_EFUSE_FREE_BLOCK_T)); + return; + } + u4QueryInfoLen = sizeof(PARAM_CUSTOM_EFUSE_FREE_BLOCK_T); + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + prEventGetFreeBlock = (P_EVENT_EFUSE_FREE_BLOCK_T)(prEvent->aucBuffer); + prAdapter->u4FreeBlockNum = prEventGetFreeBlock->u2FreeBlockNum; + + if (prCmdInfo != NULL) { + if ((prCmdInfo->fgIsOid) != 0) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, + u4QueryInfoLen, WLAN_STATUS_SUCCESS); + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + } + } else if ((prEvent->ucExtenEID) == EXT_EVENT_ID_GET_TX_POWER) { + if (u4EventBufLen < sizeof(EVENT_GET_TX_POWER_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_GET_TX_POWER_T)); + return; + } + u4QueryInfoLen = sizeof(PARAM_CUSTOM_GET_TX_POWER_T); + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + prEventGetTXPower = (P_EVENT_GET_TX_POWER_T)(prEvent->aucBuffer); + + prAdapter->u4GetTxPower = prEventGetTXPower->ucTx0TargetPower; + + if (prCmdInfo != NULL) { + if ((prCmdInfo->fgIsOid) != 0) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, + u4QueryInfoLen, WLAN_STATUS_SUCCESS); + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } + } + } +} + +void nicEventMicErrorInfo(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_EVENT_MIC_ERR_INFO prMicError; + /* P_PARAM_AUTH_EVENT_T prAuthEvent; */ + P_STA_RECORD_T prStaRec; + + DBGLOG(RSN, EVENT, "EVENT_ID_MIC_ERR_INFO\n"); + if (u4EventBufLen < sizeof(EVENT_MIC_ERR_INFO)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_MIC_ERR_INFO)); + return; + } + prMicError = (P_EVENT_MIC_ERR_INFO)(prEvent->aucBuffer); + prStaRec = + cnmGetStaRecByAddress(prAdapter, prAdapter->prAisBssInfo->ucBssIndex, + prAdapter->rWlanInfo.rCurrBssId.arMacAddress); + ASSERT(prStaRec); + + if (prStaRec) { + rsnTkipHandleMICFailure(prAdapter, prStaRec, (u8)prMicError->u4Flags); + } else { + DBGLOG(RSN, INFO, "No STA rec!!\n"); + } +} + +void nicEventScanDone(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + if (u4EventBufLen < sizeof(EVENT_SCAN_DONE)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_SCAN_DONE)); + return; + } + scnEventScanDone(prAdapter, (P_EVENT_SCAN_DONE)(prEvent->aucBuffer), true); +} + +void nicEventNloDone(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + DBGLOG(INIT, INFO, "EVENT_ID_NLO_DONE\n"); + if (u4EventBufLen < sizeof(EVENT_NLO_DONE_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_NLO_DONE_T)); + return; + } + scnEventNloDone(prAdapter, (P_EVENT_NLO_DONE_T)(prEvent->aucBuffer)); +#if CFG_SUPPORT_PNO + prAdapter->prAisBssInfo->fgIsPNOEnable = false; + if (prAdapter->prAisBssInfo->fgIsNetRequestInActive && + prAdapter->prAisBssInfo->fgIsPNOEnable) { + UNSET_NET_ACTIVE(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + DBGLOG(INIT, INFO, "INACTIVE AIS from ACTIVEto disable PNO\n"); + /* sync with firmware */ + nicDeactivateNetwork(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + } +#endif +} + +void nicEventSleepyNotify(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_EVENT_SLEEPY_INFO_T prEventSleepyNotify; + if (u4EventBufLen < sizeof(EVENT_SLEEPY_INFO_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_SLEEPY_INFO_T)); + return; + } + prEventSleepyNotify = (P_EVENT_SLEEPY_INFO_T)(prEvent->aucBuffer); + prAdapter->fgWiFiInSleepyState = (u8)(prEventSleepyNotify->ucSleepyState); + + if (prEventSleepyNotify->ucSleepyState) { + kalSetFwOwnEvent2Hif(prAdapter->prGlueInfo); + } +} + +void nicEventStatistics(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_CMD_INFO_T prCmdInfo; + + /* buffer statistics for further query */ + prAdapter->fgIsStatValid = true; + prAdapter->rStatUpdateTime = kalGetTimeTick(); + if (u4EventBufLen < sizeof(EVENT_STATISTICS)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STATISTICS)); + return; + } + kalMemCopy(&prAdapter->rStatStruct, prEvent->aucBuffer, + sizeof(EVENT_STATISTICS)); + + /* command response handling */ + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, + prEvent->aucBuffer, u4EventBufLen); + } else if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_SUCCESS); + } + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } +} +void nicEventWlanInfo(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_CMD_INFO_T prCmdInfo; + + /* buffer statistics for further query */ + prAdapter->fgIsStatValid = true; + prAdapter->rStatUpdateTime = kalGetTimeTick(); + if (u4EventBufLen < sizeof(EVENT_WLAN_INFO)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_WLAN_INFO)); + return; + } + kalMemCopy(&prAdapter->rEventWlanInfo, prEvent->aucBuffer, + sizeof(EVENT_WLAN_INFO)); + + DBGLOG(RSN, INFO, "EVENT_ID_WLAN_INFO"); + /* command response handling */ + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, + prEvent->aucBuffer, u4EventBufLen); + } else if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_SUCCESS); + } + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } +} + +void nicEventMibInfo(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_CMD_INFO_T prCmdInfo; + + /* buffer statistics for further query */ + prAdapter->fgIsStatValid = true; + prAdapter->rStatUpdateTime = kalGetTimeTick(); + + DBGLOG(RSN, INFO, "EVENT_ID_MIB_INFO"); + /* command response handling */ + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, + prEvent->aucBuffer, u4EventBufLen); + } else if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_SUCCESS); + } + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } +} + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +void nicEventTxMcsInfo(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_CMD_INFO_T prCmdInfo; + + DBGLOG(RSN, INFO, "EVENT_ID_TX_MCS_INFO"); + /* command response handling */ + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, + prEvent->aucBuffer, u4EventBufLen); + } else if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_SUCCESS); + } + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } +} +#endif + +void nicEventBeaconTimeout(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + DBGLOG(NIC, INFO, "EVENT_ID_BSS_BEACON_TIMEOUT\n"); + + if (prAdapter->fgDisBcnLostDetection == false) { + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T)NULL; + P_EVENT_BSS_BEACON_TIMEOUT_T prEventBssBeaconTimeout; + if (u4EventBufLen < sizeof(EVENT_BSS_BEACON_TIMEOUT_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_BSS_BEACON_TIMEOUT_T)); + return; + } + prEventBssBeaconTimeout = + (P_EVENT_BSS_BEACON_TIMEOUT_T)(prEvent->aucBuffer); + + if (prEventBssBeaconTimeout->ucBssIndex >= MAX_BSS_INDEX) { + return; + } + + DBGLOG(NIC, INFO, "Reason code: %d\n", + prEventBssBeaconTimeout->ucReasonCode); + + if (prEventBssBeaconTimeout->ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, "Invalid BssInfo index[%u], skip dump!\n", + prEventBssBeaconTimeout->ucBssIndex); + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, + prEventBssBeaconTimeout->ucBssIndex); + + prBssInfo->u2DeauthReason = prEventBssBeaconTimeout->ucReasonCode; + + if ((prAdapter->prAisBssInfo != NULL) && + (prEventBssBeaconTimeout->ucBssIndex == + prAdapter->prAisBssInfo->ucBssIndex)) { + if (!timerPendingTimer( + &prAdapter->rWifiVar.rAisFsmInfo.rBeaconLostTimer)) { + cnmTimerStartTimer( + prAdapter, + &prAdapter->rWifiVar.rAisFsmInfo.rBeaconLostTimer, + prAdapter->rWifiVar.ucWaitConnect * MSEC_PER_SEC); + } + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, + WLAN_STATUS_BEACON_TIMEOUT, NULL, 0); + } +#if CFG_ENABLE_WIFI_DIRECT + else if (prBssInfo->eNetworkType == NETWORK_TYPE_P2P) { + p2pRoleFsmRunEventBeaconTimeout(prAdapter, prBssInfo); + } +#endif + + else { + DBGLOG(RX, ERROR, + "EVENT_ID_BSS_BEACON_TIMEOUT: (ucBssIndex = %d)\n", + prEventBssBeaconTimeout->ucBssIndex); + } + } +} + +void nicEventUpdateNoaParams(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, IN u32 u4EventBufLen) +{ +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + P_EVENT_UPDATE_NOA_PARAMS_T prEventUpdateNoaParam; + if (u4EventBufLen < sizeof(EVENT_UPDATE_NOA_PARAMS_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_UPDATE_NOA_PARAMS_T)); + return; + } + prEventUpdateNoaParam = + (P_EVENT_UPDATE_NOA_PARAMS_T)(prEvent->aucBuffer); + if (prEventUpdateNoaParam->ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(NIC, ERROR, + "nicEventUpdateNoaParams: (ucBssIndex = %d) out-of-bound\n", + prEventUpdateNoaParam->ucBssIndex); + return; + } + if (GET_BSS_INFO_BY_INDEX(prAdapter, prEventUpdateNoaParam->ucBssIndex) + ->eNetworkType == NETWORK_TYPE_P2P) { + p2pProcessEvent_UpdateNOAParam(prAdapter, + prEventUpdateNoaParam->ucBssIndex, + prEventUpdateNoaParam); + } else { + ASSERT(0); + } + } +#else + ASSERT(0); +#endif +} + +void nicEventStaAgingTimeout(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, IN u32 u4EventBufLen) +{ + if (prAdapter->fgDisStaAgingTimeoutDetection == false) { + P_EVENT_STA_AGING_TIMEOUT_T prEventStaAgingTimeout; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo = (P_BSS_INFO_T)NULL; + if (u4EventBufLen < sizeof(EVENT_STA_AGING_TIMEOUT_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_STA_AGING_TIMEOUT_T)); + return; + } + prEventStaAgingTimeout = + (P_EVENT_STA_AGING_TIMEOUT_T)(prEvent->aucBuffer); + prStaRec = + cnmGetStaRecByIndex(prAdapter, prEventStaAgingTimeout->ucStaRecIdx); + if (prStaRec == NULL) { + return; + } + + DBGLOG(NIC, INFO, "EVENT_ID_STA_AGING_TIMEOUT %u " MACSTR "\n", + prEventStaAgingTimeout->ucStaRecIdx, + MAC2STR(prStaRec->aucMacAddr)); + + if (prStaRec->ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, "Invalid BssInfo index[%u], skip dump!\n", + prStaRec->ucBssIndex); + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + bssRemoveClient(prAdapter, prBssInfo, prStaRec); + + /* Call False Auth */ + if (prAdapter->fgIsP2PRegistered) { + p2pFuncDisconnect(prAdapter, prBssInfo, prStaRec, true, + REASON_CODE_DISASSOC_INACTIVITY, true); + } + } + /* gDisStaAgingTimeoutDetection */ +} + +void nicEventApObssStatus(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + if (u4EventBufLen < sizeof(EVENT_AP_OBSS_STATUS_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_AP_OBSS_STATUS_T)); + return; + } + rlmHandleObssStatusEventPkt( + prAdapter, (P_EVENT_AP_OBSS_STATUS_T)prEvent->aucBuffer); + } +#endif +} + +void nicEventRoamingStatus(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ +#if CFG_SUPPORT_ROAMING + P_CMD_ROAMING_TRANSIT_T prTransit; + if (u4EventBufLen < sizeof(CMD_ROAMING_TRANSIT_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(CMD_ROAMING_TRANSIT_T)); + return; + } + prTransit = (P_CMD_ROAMING_TRANSIT_T)(prEvent->aucBuffer); + + roamingFsmProcessEvent(prAdapter, prTransit); +#endif +} + +void nicEventSendDeauth(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + SW_RFB_T rSwRfb; + +#if DBG + P_WLAN_MAC_HEADER_T prWlanMacHeader; +#endif + if (u4EventBufLen < sizeof(WLAN_MAC_HEADER_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(WLAN_MAC_HEADER_T)); + return; + } +#if DBG + prWlanMacHeader = (P_WLAN_MAC_HEADER_T)&prEvent->aucBuffer[0]; + DBGLOG(RX, TRACE, "nicRx: aucAddr1: " MACSTR "\n", + MAC2STR(prWlanMacHeader->aucAddr1)); + DBGLOG(RX, TRACE, "nicRx: aucAddr2: " MACSTR "\n", + MAC2STR(prWlanMacHeader->aucAddr2)); +#endif + + /* receive packets without StaRec */ + rSwRfb.pvHeader = (P_WLAN_MAC_HEADER_T)&prEvent->aucBuffer[0]; + if (authSendDeauthFrame(prAdapter, NULL, NULL, &rSwRfb, + REASON_CODE_CLASS_3_ERR, + (PFN_TX_DONE_HANDLER)NULL) == WLAN_STATUS_SUCCESS) { + DBGLOG(RX, ERROR, "Send Deauth Class Error by FW Event\n"); + } +} + +void nicEventUpdateRddStatus(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, IN u32 u4EventBufLen) +{ +#if CFG_SUPPORT_RDD_TEST_MODE + P_EVENT_RDD_STATUS_T prEventRddStatus; + if (u4EventBufLen < sizeof(EVENT_RDD_STATUS_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_RDD_STATUS_T)); + return; + } + prEventRddStatus = (P_EVENT_RDD_STATUS_T)(prEvent->aucBuffer); + + prAdapter->ucRddStatus = prEventRddStatus->ucRddStatus; +#endif +} + +void nicEventUpdateBwcsStatus(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, IN u32 u4EventBufLen) +{ + P_PTA_IPC_T prEventBwcsStatus; + if (u4EventBufLen < sizeof(PTA_IPC_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(PTA_IPC_T)); + return; + } + prEventBwcsStatus = (P_PTA_IPC_T)(prEvent->aucBuffer); + +#if CFG_SUPPORT_BCM_BWCS_DEBUG + DBGLOG(RSN, EVENT, "BCM BWCS Event: %02x%02x%02x%02x\n", + prEventBwcsStatus->u.aucBTPParams[0], + prEventBwcsStatus->u.aucBTPParams[1], + prEventBwcsStatus->u.aucBTPParams[2], + prEventBwcsStatus->u.aucBTPParams[3]); +#endif + + kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_BWCS_UPDATE, + (void *)prEventBwcsStatus, sizeof(PTA_IPC_T)); +} + +void nicEventUpdateBcmDebug(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_PTA_IPC_T prEventBwcsStatus; + if (u4EventBufLen < sizeof(PTA_IPC_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(PTA_IPC_T)); + return; + } + prEventBwcsStatus = (P_PTA_IPC_T)(prEvent->aucBuffer); + +#if CFG_SUPPORT_BCM_BWCS_DEBUG + DBGLOG(RSN, EVENT, "BCM FW status: %02x%02x%02x%02x\n", + prEventBwcsStatus->u.aucBTPParams[0], + prEventBwcsStatus->u.aucBTPParams[1], + prEventBwcsStatus->u.aucBTPParams[2], + prEventBwcsStatus->u.aucBTPParams[3]); +#endif +} + +void nicEventAddPkeyDone(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_EVENT_ADD_KEY_DONE_INFO prAddKeyDone; + P_STA_RECORD_T prStaRec; + if (u4EventBufLen < sizeof(EVENT_ADD_KEY_DONE_INFO)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_ADD_KEY_DONE_INFO)); + return; + } + prAddKeyDone = (P_EVENT_ADD_KEY_DONE_INFO)(prEvent->aucBuffer); + + DBGLOG(RSN, INFO, "EVENT_ID_ADD_PKEY_DONE BSSIDX=%d " MACSTR "\n", + prAddKeyDone->ucBSSIndex, MAC2STR(prAddKeyDone->aucStaAddr)); + + prStaRec = cnmGetStaRecByAddress(prAdapter, prAddKeyDone->ucBSSIndex, + prAddKeyDone->aucStaAddr); + + if (prStaRec) { + DBGLOG(RSN, INFO, "STA " MACSTR " Add Key Done!!\n", + MAC2STR(prStaRec->aucMacAddr)); + prStaRec->fgIsTxKeyReady = true; + qmUpdateStaRec(prAdapter, prStaRec); + } +} + +void nicEventIcapDone(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_EVENT_ICAP_STATUS_T prEventIcapStatus; + PARAM_CUSTOM_MEM_DUMP_STRUCT_T rMemDumpInfo; + u32 u4QueryInfo; + if (u4EventBufLen < sizeof(EVENT_ICAP_STATUS_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_ICAP_STATUS_T)); + return; + } + prEventIcapStatus = (P_EVENT_ICAP_STATUS_T)(prEvent->aucBuffer); + + rMemDumpInfo.u4Address = prEventIcapStatus->u4StartAddress; + rMemDumpInfo.u4Length = prEventIcapStatus->u4IcapSieze; +#if CFG_SUPPORT_QA_TOOL + rMemDumpInfo.u4IcapContent = prEventIcapStatus->u4IcapContent; +#endif + + wlanoidQueryMemDump(prAdapter, &rMemDumpInfo, sizeof(rMemDumpInfo), + &u4QueryInfo); +} + +void nicEventDebugMsg(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_EVENT_DEBUG_MSG_T prEventDebugMsg; + u16 u2DebugMsgId; + u8 ucMsgType; + u8 ucFlags; + u32 u4Value; + u16 u2MsgSize; + u8 *pucMsg; + + if (u4EventBufLen < sizeof(EVENT_DEBUG_MSG_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_DEBUG_MSG_T)); + return; + } + prEventDebugMsg = (P_EVENT_DEBUG_MSG_T)(prEvent->aucBuffer); + + if (u4EventBufLen < + /*sizeof(EVENT_DEBUG_MSG_T) +*/ prEventDebugMsg->u2MsgSize /*- 1*/) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, + sizeof(EVENT_DEBUG_MSG_T) + prEventDebugMsg->u2MsgSize); + return; + } + u2DebugMsgId = prEventDebugMsg->u2DebugMsgId; + ucMsgType = prEventDebugMsg->ucMsgType; + ucFlags = prEventDebugMsg->ucFlags; + u4Value = prEventDebugMsg->u4Value; + u2MsgSize = prEventDebugMsg->u2MsgSize; + pucMsg = prEventDebugMsg->aucMsg; + + DBGLOG(SW4, TRACE, "DEBUG_MSG Id %u Type %u Fg 0x%x Val 0x%x Size %u\n", + u2DebugMsgId, ucMsgType, ucFlags, u4Value, u2MsgSize); + + if (u2MsgSize <= DEBUG_MSG_SIZE_MAX) { + if (ucMsgType >= DEBUG_MSG_TYPE_END) { + ucMsgType = DEBUG_MSG_TYPE_MEM32; + } + + if (ucMsgType == DEBUG_MSG_TYPE_ASCII) { + u8 *pucChr; + + pucMsg[u2MsgSize] = '\0'; + + /* skip newline */ + pucChr = kalStrChr(pucMsg, '\0'); + if (*(pucChr - 1) == '\n') { + *(pucChr - 1) = '\0'; + } + + DBGLOG(SW4, EVENT, "<FW>%s\n", pucMsg); + } else if (ucMsgType == DEBUG_MSG_TYPE_MEM8) { + DBGLOG(SW4, INFO, "<FW>Dump MEM8\n"); + DBGLOG_MEM8(SW4, INFO, pucMsg, u2MsgSize); + } else { + DBGLOG(SW4, INFO, "<FW>Dump MEM32\n"); + DBGLOG_MEM32(SW4, INFO, pucMsg, u2MsgSize); + } + } else { + DBGLOG(SW4, INFO, "Debug msg size %u is too large.\n", u2MsgSize); + } +} + +void nicEventTdls(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ +#if CFG_SUPPORT_TDLS + /* [TDLS Event Format] + * FW: FW_EVT_HDR + 8 + evt_payload + * Host: HOST_EVT_HDR + 8 + evt_payload + * EVENT_HDR_WITHOUT_RXD_SIZE = size(FW_EVT_HDR) + * prEvent->u2PacketLength = size(FW_EVT_HDR) + 8 + + * size(evt_payload) HOST_EVT_HDR = HDR_RXD + * (au4HwMacRxDesc) + size(FW_EVT_HDR) u4EventBufLen = + * should be 8+size(evt_payload) 8 = EVT_ID(4) + SUB_ID(4) + */ + if (u4EventBufLen < prEvent->u2PacketLength - EVENT_HDR_WITHOUT_RXD_SIZE) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, prEvent->u2PacketLength); + return; + } + if (prEvent->u2PacketLength - EVENT_HDR_WITHOUT_RXD_SIZE < 8) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: (%d < 8)\n", __func__, + prEvent->u2PacketLength - EVENT_HDR_WITHOUT_RXD_SIZE); + return; + } + TdlsexEventHandle(prAdapter->prGlueInfo, (u8 *)prEvent->aucBuffer, + (u32)(prEvent->u2PacketLength - 8)); +#endif +} + +void nicEventDumpMem(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_CMD_INFO_T prCmdInfo; + + DBGLOG(SW4, INFO, "%s: EVENT_ID_DUMP_MEM\n", __func__); + + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + DBGLOG(NIC, INFO, ": ==> 1\n"); + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, + prEvent->aucBuffer, u4EventBufLen); + } else if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_SUCCESS); + } + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } else { + /* Burst mode */ + DBGLOG(NIC, INFO, ": ==> 2\n"); + nicEventQueryMemDump(prAdapter, prEvent->aucBuffer, u4EventBufLen); + } +} + +void nicEventAssertDump(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ +#if CFG_ASSERT_DUMP + if (wlanIsChipRstRecEnabled(prAdapter)) { + wlanChipRstPreAct(prAdapter); + } + + if (prEvent->ucS2DIndex == S2D_INDEX_EVENT_N2H) { + if (!prAdapter->fgN9AssertDumpOngoing) { + DBGLOG(NIC, ERROR, "%s: EVENT_ID_ASSERT_DUMP\n", __func__); + DBGLOG(NIC, ERROR, "\n[DUMP_N9]====N9 ASSERT_DUMPSTART====\n"); + prAdapter->fgKeepPrintCoreDump = true; + if (kalOpenCorDumpFile(true) != WLAN_STATUS_SUCCESS) { + DBGLOG(NIC, ERROR, "kalOpenCorDumpFile fail\n"); + } else { + prAdapter->fgN9CorDumpFileOpend = true; + } + + prAdapter->fgN9AssertDumpOngoing = true; + } + if (prAdapter->fgN9AssertDumpOngoing) { + if (u4EventBufLen < 5 || + u4EventBufLen < + prEvent->u2PacketLength - EVENT_HDR_WITHOUT_RXD_SIZE) { + DBGLOG(NIC, ERROR, + "%s: Invalid event length: %d < %d (or < 5?)\n", + __func__, u4EventBufLen, + prEvent->u2PacketLength - EVENT_HDR_WITHOUT_RXD_SIZE); + return; + } + if (prAdapter->fgKeepPrintCoreDump) { + DBGLOG(NIC, ERROR, "[DUMP_N9]%s:\n", prEvent->aucBuffer); + } + if (!kalStrnCmp(prEvent->aucBuffer, ";more log added here", 5) || + !kalStrnCmp(prEvent->aucBuffer, ";[core dump start]", 5)) { + prAdapter->fgKeepPrintCoreDump = false; + } + + if (prAdapter->fgN9CorDumpFileOpend) { + if (kalWriteCorDumpFile(prEvent->aucBuffer, + prEvent->u2PacketLength - + EVENT_HDR_WITHOUT_RXD_SIZE, + true) != WLAN_STATUS_SUCCESS) { + DBGLOG(NIC, INFO, "kalWriteN9CorDumpFile fail\n"); + } + } + wlanCorDumpTimerReset(prAdapter, true); + } + } else { + /* prEvent->ucS2DIndex == S2D_INDEX_EVENT_C2H */ + if (!prAdapter->fgCr4AssertDumpOngoing) { + DBGLOG(NIC, ERROR, "%s: EVENT_ID_ASSERT_DUMP\n", __func__); + DBGLOG(NIC, ERROR, "\n[DUMP_Cr4]====CR4 ASSERT_DUMPSTART====\n"); + prAdapter->fgKeepPrintCoreDump = true; + if (kalOpenCorDumpFile(false) != WLAN_STATUS_SUCCESS) { + DBGLOG(NIC, ERROR, "kalOpenCorDumpFile fail\n"); + } else { + prAdapter->fgCr4CorDumpFileOpend = true; + } + + prAdapter->fgCr4AssertDumpOngoing = true; + } + if (prAdapter->fgCr4AssertDumpOngoing) { + if (prAdapter->fgKeepPrintCoreDump) { + DBGLOG(NIC, ERROR, "[DUMP_CR4]%s:\n", prEvent->aucBuffer); + } + if (!kalStrnCmp(prEvent->aucBuffer, ";more log added here", 5)) { + prAdapter->fgKeepPrintCoreDump = false; + } + + if (prAdapter->fgCr4CorDumpFileOpend) { + if (kalWriteCorDumpFile(prEvent->aucBuffer, + prEvent->u2PacketLength - + EVENT_HDR_WITHOUT_RXD_SIZE, + false) != WLAN_STATUS_SUCCESS) { + DBGLOG(NIC, ERROR, "kalWriteN9CorDumpFile fail\n"); + } + } + wlanCorDumpTimerReset(prAdapter, false); + } + } +#endif +} + +void nicEventRddSendPulse(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + DBGLOG(RLM, INFO, "%s: EVENT_ID_RDD_SEND_PULSE\n", __func__); + + nicEventRddPulseDump(prAdapter, prEvent->aucBuffer, u4EventBufLen); +} + +void nicEventUpdateCoexPhyrate(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, IN u32 u4EventBufLen) +{ + u8 i; + P_EVENT_UPDATE_COEX_PHYRATE_T prEventUpdateCoexPhyrate; + + DBGLOG(NIC, LOUD, "%s\n", __func__); + if (u4EventBufLen < sizeof(EVENT_UPDATE_COEX_PHYRATE_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(EVENT_UPDATE_COEX_PHYRATE_T)); + return; + } + prEventUpdateCoexPhyrate = + (P_EVENT_UPDATE_COEX_PHYRATE_T)(prEvent->aucBuffer); + + for (i = 0; i < (HW_BSSID_NUM + 1); i++) { + prAdapter->aprBssInfo[i]->u4CoexPhyRateLimit = + prEventUpdateCoexPhyrate->au4PhyRateLimit[i]; + DBGLOG(NIC, INFO, "Coex:BSS[%d]R:%d\n", i, + prAdapter->aprBssInfo[i]->u4CoexPhyRateLimit); + } +} + +#if (CFG_WOW_SUPPORT == 1) +void nicEventWakeUpReason(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + struct _EVENT_WAKEUP_REASON_INFO *prWakeUpReason; + P_GLUE_INFO_T prGlueInfo; + + DBGLOG(NIC, INFO, "nicEventWakeUpReason\n"); + prGlueInfo = prAdapter->prGlueInfo; + if (u4EventBufLen < sizeof(struct _EVENT_WAKEUP_REASON_INFO)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(struct _EVENT_WAKEUP_REASON_INFO)); + return; + } + /* Driver receives EVENT_ID_WOW_WAKEUP_REASON after firmware wake up + * host The possible Wakeup Reason define in FW as following 0: MAGIC + * PACKET 1: BITMAP 2: ARPNS 3: GTK_REKEY 4: COALESCING_FILTER 5: + * HW_GLOBAL_ENABLE 6: TCP_SYN PACKET 7: TDLS 8: DISCONNECT 9: + * IPV4_UDP PACKET 10: IPV4_TCP PACKET 11: IPV6_UDP PACKET 12: IPV6_TCP + * PACKET + */ + prWakeUpReason = (struct _EVENT_WAKEUP_REASON_INFO *)(prEvent->aucBuffer); + prGlueInfo->prAdapter->rWowCtrl.ucReason = prWakeUpReason->reason; + DBGLOG(NIC, INFO, "nicEventWakeUpReason:%d\n", + prGlueInfo->prAdapter->rWowCtrl.ucReason); +} +#endif + +void nicEventCSIData(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + struct EVENT_CSI_DATA_T *prCsiData; + + DBGLOG(NIC, INFO, "nicEventCSIData\n"); + + if (prAdapter->rCsiData.ucDataOutputted != 0) { + DBGLOG(NIC, INFO, + "Previous %s data is not outputted. Ignore this new data!\n", + (prAdapter->rCsiData.ucDataOutputted & BIT(0)) ? "Q" : "I"); + return; + } + if (u4EventBufLen < sizeof(struct EVENT_CSI_DATA_T)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(struct EVENT_CSI_DATA_T)); + return; + } + prCsiData = (struct EVENT_CSI_DATA_T *)(prEvent->aucBuffer); + prAdapter->rCsiData.ucDbdcIdx = prCsiData->ucDbdcIdx; + prAdapter->rCsiData.ucBw = prCsiData->ucBw; + prAdapter->rCsiData.bIsCck = prCsiData->bIsCck; + if (prCsiData->u2DataCount > 256) { + DBGLOG(NIC, WARN, "%s: u2DataCount (%d) is invalid! Need <= 256.\n", + __func__, prCsiData->u2DataCount); + return; + } + prAdapter->rCsiData.u2DataCount = prCsiData->u2DataCount; + kalMemZero(prAdapter->rCsiData.ac2IData, + sizeof(prAdapter->rCsiData.ac2IData)); + kalMemZero(prAdapter->rCsiData.ac2QData, + sizeof(prAdapter->rCsiData.ac2QData)); + kalMemCopy(prAdapter->rCsiData.ac2IData, prCsiData->ac2IData, + sizeof(prCsiData->ac2IData)); + + kalMemCopy(prAdapter->rCsiData.ac2QData, prCsiData->ac2QData, + sizeof(prCsiData->ac2QData)); +} + +#if CFG_SUPPORT_REPLAY_DETECTION +void nicCmdEventSetAddKey(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + P_WIFI_CMD_T prWifiCmd = NULL; + P_CMD_802_11_KEY prCmdKey = NULL; + struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL; + u8 ucBssIndex = 0; + P_BSS_INFO_T prBssInfo = NULL; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo->fgIsOid) { + /* Update Set Information Length */ + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, + prCmdInfo->u4InformationBufferLength, + WLAN_STATUS_SUCCESS); + } + + prWifiCmd = (P_WIFI_CMD_T)(prCmdInfo->pucInfoBuffer); + prCmdKey = (P_CMD_802_11_KEY)(prWifiCmd->aucBuffer); + ucBssIndex = prCmdKey->ucBssIdx; + + if (ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, "Invalid BssInfo index[%u], skip dump!\n", + ucBssIndex); + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + ASSERT(prBssInfo); + + prDetRplyInfo = &prBssInfo->rDetRplyInfo; + + if (pucEventBuf) { + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(WIFI_CMD_T) + sizeof(CMD_802_11_KEY)) { + DBGLOG(NIC, ERROR, "Invalid event length:%d < %d\n", u4EventBufLen, + sizeof(WIFI_CMD_T) + sizeof(CMD_802_11_KEY)); + return; + } + prWifiCmd = (P_WIFI_CMD_T)(pucEventBuf); + prCmdKey = (P_CMD_802_11_KEY)(prWifiCmd->aucBuffer); + if (!prCmdKey->ucKeyType) { + prDetRplyInfo->ucCurKeyId = prCmdKey->ucKeyId; + prDetRplyInfo->ucKeyType = prCmdKey->ucKeyType; + prDetRplyInfo->arReplayPNInfo[prCmdKey->ucKeyId].fgRekey = true; + prDetRplyInfo->arReplayPNInfo[prCmdKey->ucKeyId].fgFirstPkt = true; + DBGLOG(NIC, TRACE, "Keyid is %d, ucKeyType is %d\n", + prCmdKey->ucKeyId, prCmdKey->ucKeyType); + } + } +} + +void nicOidCmdTimeoutSetAddKey(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo) +{ + ASSERT(prAdapter); + + DBGLOG(NIC, WARN, "Wlan setaddkey timeout.\n"); + if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_FAILURE); + } +} + +void nicEventGetGtkDataSync(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_PARAM_GTK_REKEY_DATA prGtkData = NULL; + struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL; + P_BSS_INFO_T prBssInfo = NULL; + u8 ucCurKeyId; + if (u4EventBufLen < sizeof(PARAM_GTK_REKEY_DATA)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(PARAM_GTK_REKEY_DATA)); + return; + } + prGtkData = (P_PARAM_GTK_REKEY_DATA)(prEvent->aucBuffer); + + if (prAdapter->prAisBssInfo->ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(SW4, ERROR, "Invalid BssInfo index[%u], skip dump!\n", + prAdapter->prAisBssInfo->ucBssIndex); + return; + } + + prBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prAdapter->prAisBssInfo->ucBssIndex); + + prDetRplyInfo = &prBssInfo->rDetRplyInfo; + prDetRplyInfo->ucCurKeyId = prGtkData->ucCurKeyId; + ucCurKeyId = prDetRplyInfo->ucCurKeyId; + + if (ucCurKeyId >= 4) { + DBGLOG(RSN, WARN, "Invalid KeyId of PN: %d, out of bound.\n", + ucCurKeyId); + return; + } + kalMemZero(prDetRplyInfo->arReplayPNInfo[ucCurKeyId].auPN, + NL80211_REPLAY_CTR_LEN); + kalMemCopy(prDetRplyInfo->arReplayPNInfo[ucCurKeyId].auPN, + prGtkData->aucReplayCtr, 6); + + DBGLOG(RSN, INFO, "Get BC/MC PN update from fw.\n"); + DBGLOG_MEM8(RSN, INFO, (u8 *)prDetRplyInfo->arReplayPNInfo[ucCurKeyId].auPN, + NL80211_REPLAY_CTR_LEN); +} + +#endif + +#ifdef CFG_SUPPORT_ANT_DIV +void nicCmdEventAntDiv(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + P_GLUE_INFO_T prGlueInfo; + struct CMD_ANT_DIV_CTRL *prAntDivInfo; + u32 u4QueryInfoLen; + + if (prAdapter == NULL) { + DBGLOG(RSN, INFO, "prAdapter is null\n"); + return; + } + if (prCmdInfo == NULL) { + DBGLOG(RSN, INFO, "prCmdInfo is null\n"); + return; + } + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + u4QueryInfoLen = sizeof(struct CMD_ANT_DIV_CTRL); + prAntDivInfo = + (struct CMD_ANT_DIV_CTRL *)prCmdInfo->pvInformationBuffer; + + if (pucEventBuf && prAntDivInfo) { + if (u4EventBufLen < u4QueryInfoLen) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", + __func__, u4EventBufLen, u4QueryInfoLen); + return; + } + kalMemCopy(prAntDivInfo, pucEventBuf, u4QueryInfoLen); + } + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} +#endif + +#ifdef CFG_DUMP_TXPOWR_TABLE +void nicCmdEventGetTxPwrTbl(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + u32 u4QueryInfoLen; + P_GLUE_INFO_T prGlueInfo; + struct EVENT_GET_TXPWR_TBL *prTxPwrTblEvent = NULL; + struct PARAM_CMD_GET_TXPWR_TBL *prTxPwrTbl = NULL; + void *info_buf = NULL; + + if (!prAdapter) { + DBGLOG(NIC, ERROR, "NULL prAdapter!\n"); + return; + } + + if (!prCmdInfo) { + DBGLOG(NIC, ERROR, "NULL prCmdInfo!\n"); + return; + } + + if (!pucEventBuf || !prCmdInfo->pvInformationBuffer) { + if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_FAILURE); + } + + if (!pucEventBuf) { + DBGLOG(NIC, WARN, "NULL pucEventBuf!\n"); + } + + if (!prCmdInfo->pvInformationBuffer) { + DBGLOG(NIC, WARN, "NULL pvInformationBuffer!\n"); + } + return; + } + + if (prCmdInfo->fgIsOid) { + prGlueInfo = prAdapter->prGlueInfo; + info_buf = prCmdInfo->pvInformationBuffer; + // !IS_ALLOWED_CMD_IN_TEST_MODE(), skip check in test mode + if (prAdapter->fgTestMode == false && + u4EventBufLen < sizeof(struct EVENT_GET_TXPWR_TBL)) { + DBGLOG(NIC, ERROR, "%s: Invalid event length: %d < %d\n", __func__, + u4EventBufLen, sizeof(struct EVENT_GET_TXPWR_TBL)); + return; + } + prTxPwrTblEvent = (struct EVENT_GET_TXPWR_TBL *)pucEventBuf; + prTxPwrTbl = (struct PARAM_CMD_GET_TXPWR_TBL *)info_buf; + + u4QueryInfoLen = sizeof(struct PARAM_CMD_GET_TXPWR_TBL); + + prTxPwrTbl->ucCenterCh = prTxPwrTblEvent->ucCenterCh; + prTxPwrTbl->ucFeLoss = prTxPwrTblEvent->ucFeLoss; + + kalMemCopy(prTxPwrTbl->tx_pwr_tbl, prTxPwrTblEvent->tx_pwr_tbl, + sizeof(prTxPwrTblEvent->tx_pwr_tbl)); + + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, u4QueryInfoLen, + WLAN_STATUS_SUCCESS); + } +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_pwr_mgt.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_pwr_mgt.c new file mode 100644 index 00000000000000..1b9d073599f4cd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_pwr_mgt.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "nic_pwr_mgt.c" + * \brief In this file we define the STATE and EVENT for Power Management + * FSM. + * + * The SCAN FSM is responsible for performing SCAN behavior when the Arbiter + * enter ARB_STATE_SCAN. The STATE and EVENT for SCAN FSM are defined here with + * detail description. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ +void nicpmWakeUpWiFi(IN P_ADAPTER_T prAdapter) +{ + if (!nicVerifyChipID(prAdapter)) { + DBGLOG(INIT, ERROR, "Chip id verify error!\n"); + return; + } + HAL_WAKE_UP_WIFI(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to process the POWER ON procedure. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicpmSetFWOwn(IN P_ADAPTER_T prAdapter, IN u8 fgEnableGlobalInt) +{ + halSetFWOwn(prAdapter, fgEnableGlobalInt); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to process the POWER OFF procedure. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +u8 nicpmSetDriverOwn(IN P_ADAPTER_T prAdapter) +{ + return halSetDriverOwn(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to set ACPI power mode to D0. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +u8 nicpmSetAcpiPowerD0(IN P_ADAPTER_T prAdapter) +{ + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is used to set ACPI power mode to D3. + * + * @param prAdapter pointer to the Adapter handler + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +u8 nicpmSetAcpiPowerD3(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + return true; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_rate.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_rate.c new file mode 100644 index 00000000000000..4b590052e2465d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_rate.c @@ -0,0 +1,397 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ +/* +** +*/ + +/*! \file "nic_rate.c" + * \brief This file contains the transmission rate handling routines. + * + * This file contains the transmission rate handling routines for setting up + * ACK/CTS Rate, Highest Tx Rate, Lowest Tx Rate, Initial Tx Rate and do + * conversion between Rate Set and Data Rates. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +const u16 au2RateCCKLong[CCK_RATE_NUM] = { + RATE_CCK_1M_LONG, /* RATE_1M_INDEX = 0 */ + RATE_CCK_2M_LONG, /* RATE_2M_INDEX */ + RATE_CCK_5_5M_LONG, /* RATE_5_5M_INDEX */ + RATE_CCK_11M_LONG /* RATE_11M_INDEX */ +}; + +const u16 au2RateCCKShort[CCK_RATE_NUM] = { + RATE_CCK_1M_LONG, /* RATE_1M_INDEX = 0 */ + RATE_CCK_2M_SHORT, /* RATE_2M_INDEX */ + RATE_CCK_5_5M_SHORT, /* RATE_5_5M_INDEX */ + RATE_CCK_11M_SHORT /* RATE_11M_INDEX */ +}; + +const u16 au2RateOFDM[OFDM_RATE_NUM] = { + RATE_OFDM_6M, /* RATE_6M_INDEX */ + RATE_OFDM_9M, /* RATE_9M_INDEX */ + RATE_OFDM_12M, /* RATE_12M_INDEX */ + RATE_OFDM_18M, /* RATE_18M_INDEX */ + RATE_OFDM_24M, /* RATE_24M_INDEX */ + RATE_OFDM_36M, /* RATE_36M_INDEX */ + RATE_OFDM_48M, /* RATE_48M_INDEX */ + RATE_OFDM_54M /* RATE_54M_INDEX */ +}; + +const u16 au2RateHTMixed[HT_RATE_NUM] = { + RATE_MM_MCS_32, /* RATE_MCS32_INDEX, */ + RATE_MM_MCS_0, /* RATE_MCS0_INDEX, */ + RATE_MM_MCS_1, /* RATE_MCS1_INDEX, */ + RATE_MM_MCS_2, /* RATE_MCS2_INDEX, */ + RATE_MM_MCS_3, /* RATE_MCS3_INDEX, */ + RATE_MM_MCS_4, /* RATE_MCS4_INDEX, */ + RATE_MM_MCS_5, /* RATE_MCS5_INDEX, */ + RATE_MM_MCS_6, /* RATE_MCS6_INDEX, */ + RATE_MM_MCS_7 /* RATE_MCS7_INDEX, */ +}; + +const u16 au2RateHTGreenField[HT_RATE_NUM] = { + RATE_GF_MCS_32, /* RATE_MCS32_INDEX, */ + RATE_GF_MCS_0, /* RATE_MCS0_INDEX, */ + RATE_GF_MCS_1, /* RATE_MCS1_INDEX, */ + RATE_GF_MCS_2, /* RATE_MCS2_INDEX, */ + RATE_GF_MCS_3, /* RATE_MCS3_INDEX, */ + RATE_GF_MCS_4, /* RATE_MCS4_INDEX, */ + RATE_GF_MCS_5, /* RATE_MCS5_INDEX, */ + RATE_GF_MCS_6, /* RATE_MCS6_INDEX, */ + RATE_GF_MCS_7, /* RATE_MCS7_INDEX, */ +}; + +const u16 au2RateVHT[VHT_RATE_NUM] = { + RATE_VHT_MCS_0, /* RATE_MCS0_INDEX, */ + RATE_VHT_MCS_1, /* RATE_MCS1_INDEX, */ + RATE_VHT_MCS_2, /* RATE_MCS2_INDEX, */ + RATE_VHT_MCS_3, /* RATE_MCS3_INDEX, */ + RATE_VHT_MCS_4, /* RATE_MCS4_INDEX, */ + RATE_VHT_MCS_5, /* RATE_MCS5_INDEX, */ + RATE_VHT_MCS_6, /* RATE_MCS6_INDEX, */ + RATE_VHT_MCS_7, /* RATE_MCS7_INDEX, */ + RATE_VHT_MCS_8, /* RATE_MCS8_INDEX, */ + RATE_VHT_MCS_9 /* RATE_MCS9_INDEX, */ +}; + +/* in unit of 100kb/s */ +const EMU_MAC_RATE_INFO_T arMcsRate2PhyRate[] = { + /* Phy Rate Code, BW20, BW20 SGI, BW40, BW40 SGI, BW80, BW80 + * SGI, BW160, BW160 SGI */ + RATE_INFO(PHY_RATE_MCS0, 65, 72, 135, 150, 293, 325, 585, 650), + RATE_INFO(PHY_RATE_MCS1, 130, 144, 270, 300, 585, 650, 1170, 1300), + RATE_INFO(PHY_RATE_MCS2, 195, 217, 405, 450, 878, 975, 1755, 1950), + RATE_INFO(PHY_RATE_MCS3, 260, 289, 540, 600, 1170, 1300, 2340, 2600), + RATE_INFO(PHY_RATE_MCS4, 390, 433, 810, 900, 1755, 1950, 3510, 3900), + RATE_INFO(PHY_RATE_MCS5, 520, 578, 1080, 1200, 2340, 2600, 4680, 5200), + RATE_INFO(PHY_RATE_MCS6, 585, 650, 1215, 1350, 2633, 2925, 5265, 5850), + RATE_INFO(PHY_RATE_MCS7, 650, 722, 1350, 1500, 2925, 3250, 5850, 6500), + RATE_INFO(PHY_RATE_MCS8, 780, 867, 1620, 1800, 3510, 3900, 7020, 7800), + RATE_INFO(PHY_RATE_MCS9, 0, 0, 1800, 2000, 3900, 4333, 7800, 8667), + RATE_INFO(PHY_RATE_MCS32, 0, 0, 60, 67, 0, 0, 0, 0) +}; + +/* in uint of 500kb/s */ +const u8 aucHwRate2PhyRate[] = { + RATE_1M, /*1M long */ + RATE_2M, /*2M long */ + RATE_5_5M, /*5.5M long */ + RATE_11M, /*11M long */ + RATE_1M, /*1M short invalid */ + RATE_2M, /*2M short */ + RATE_5_5M, /*5.5M short */ + RATE_11M, /*11M short */ + RATE_48M, /*48M */ + RATE_24M, /*24M */ + RATE_12M, /*12M */ + RATE_6M, /*6M */ + RATE_54M, /*54M */ + RATE_36M, /*36M */ + RATE_18M, /*18M */ + RATE_9M /*9M */ +}; +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ +u32 nicGetPhyRateByMcsRate(IN u8 ucIdx, IN u8 ucBw, IN u8 ucGI) +{ + return arMcsRate2PhyRate[ucIdx].u4PhyRate[ucBw][ucGI]; +} + +u32 nicGetHwRateByPhyRate(IN u8 ucIdx) +{ + return aucHwRate2PhyRate[ucIdx]; /* uint : 500 kbps */ +} + +WLAN_STATUS +nicSwIndex2RateIndex(IN u8 ucRateSwIndex, OUT u8 *pucRateIndex, + OUT u8 *pucPreambleOption) +{ + ASSERT(pucRateIndex); + ASSERT(pucPreambleOption); + + if (ucRateSwIndex >= RATE_6M_SW_INDEX) { + *pucRateIndex = ucRateSwIndex - RATE_6M_SW_INDEX; + *pucPreambleOption = PREAMBLE_OFDM_MODE; + } else { + *pucRateIndex = ucRateSwIndex; + *pucPreambleOption = PREAMBLE_DEFAULT_LONG_NONE; + } + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS nicRateIndex2RateCode(IN u8 ucPreambleOption, IN u8 ucRateIndex, + OUT u16 *pu2RateCode) +{ + switch (ucPreambleOption) { + case PREAMBLE_DEFAULT_LONG_NONE: + if (ucRateIndex >= CCK_RATE_NUM) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu2RateCode = au2RateCCKLong[ucRateIndex]; + break; + + case PREAMBLE_OPTION_SHORT: + if (ucRateIndex >= CCK_RATE_NUM) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu2RateCode = au2RateCCKShort[ucRateIndex]; + break; + + case PREAMBLE_OFDM_MODE: + if (ucRateIndex >= OFDM_RATE_NUM) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu2RateCode = au2RateOFDM[ucRateIndex]; + break; + + case PREAMBLE_HT_MIXED_MODE: + if (ucRateIndex >= HT_RATE_NUM) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu2RateCode = au2RateHTMixed[ucRateIndex]; + break; + + case PREAMBLE_HT_GREEN_FIELD: + if (ucRateIndex >= HT_RATE_NUM) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu2RateCode = au2RateHTGreenField[ucRateIndex]; + break; + + case PREAMBLE_VHT_FIELD: + if (ucRateIndex >= VHT_RATE_NUM) { + return WLAN_STATUS_INVALID_DATA; + } + + *pu2RateCode = au2RateVHT[ucRateIndex]; + break; + + default: + return WLAN_STATUS_INVALID_DATA; + } + + return WLAN_STATUS_SUCCESS; +} + +u32 nicRateCode2PhyRate(IN u16 u2RateCode, IN u8 ucBandwidth, IN u8 ucGI, + IN u8 ucRateNss) +{ + u8 ucPhyRate; + u16 u2TxMode; + u32 u4PhyRateBy1SS, u4PhyRateIn100Kbps = 0; + + ucPhyRate = RATE_CODE_GET_PHY_RATE(u2RateCode); + u2TxMode = u2RateCode & RATE_TX_MODE_MASK; + ucRateNss = ucRateNss + AR_SS_1; /* change to be base=1 */ + + if ((u2TxMode == TX_MODE_HT_GF) || (u2TxMode == TX_MODE_HT_MM)) { + if (ucPhyRate > PHY_RATE_MCS7) { + u2RateCode = u2RateCode - HT_RATE_MCS7_INDEX; + }else{ + ucRateNss = AR_SS_1; + } + } else if ((u2TxMode == TX_MODE_OFDM) || (u2TxMode == TX_MODE_CCK)) { + ucRateNss = AR_SS_1; + } + DBGLOG(NIC, LOUD, "Coex:nicRateCode2PhyRate,RC:%x,B:%d,I:%d\n", + u2RateCode, ucBandwidth, ucGI); + + u4PhyRateBy1SS = nicRateCode2DataRate(u2RateCode, ucBandwidth, ucGI); + u4PhyRateIn100Kbps = u4PhyRateBy1SS * ucRateNss; + + DBGLOG(NIC, LOUD, "Coex:nicRateCode2PhyRate,1ss R:%d,PHY R:%d\n", + u4PhyRateBy1SS, u4PhyRateIn100Kbps); + + return u4PhyRateIn100Kbps; +} + +u32 nicRateCode2DataRate(IN u16 u2RateCode, IN u8 ucBandwidth, IN u8 ucGI) +{ + u8 ucPhyRate, ucIdx, ucBw = 0; + u32 u4PhyRateIn100Kbps = 0; + u16 u2TxMode; + + if ((ucBandwidth == FIX_BW_NO_FIXED) || (ucBandwidth == FIX_BW_20)) { + ucBw = MAC_BW_20; + }else if (ucBandwidth == FIX_BW_40) { + ucBw = MAC_BW_40; + }else if (ucBandwidth == FIX_BW_80) { + ucBw = MAC_BW_80; + }else if (ucBandwidth == FIX_BW_160) { + ucBw = MAC_BW_160; + } + + ucPhyRate = RATE_CODE_GET_PHY_RATE(u2RateCode); + u2TxMode = u2RateCode & RATE_TX_MODE_MASK; + /* Set MMSS parameter if HT/VHT rate */ + if ((u2TxMode == TX_MODE_HT_GF) || (u2TxMode == TX_MODE_HT_MM) || + (u2TxMode == TX_MODE_VHT)) { + /* No SGI Greenfield for 1T */ + /* Refer to section 20.3.11.11.6 of IEEE802.11-2012 */ + if (u2TxMode == TX_MODE_HT_GF) { + ucGI = MAC_GI_NORMAL; + } + + ucIdx = ucPhyRate; + + if (ucIdx == PHY_RATE_MCS32) { + ucIdx = 10; + } + + u4PhyRateIn100Kbps = nicGetPhyRateByMcsRate(ucIdx, ucBw, ucGI); + } else if ((u2TxMode == TX_MODE_OFDM) || (u2TxMode == TX_MODE_CCK)) { + u4PhyRateIn100Kbps = + (nicGetHwRateByPhyRate(ucPhyRate & BITS(0, 3))) * 5; + } else { + ASSERT(false); + } + return u4PhyRateIn100Kbps; +} + +u8 nicGetRateIndexFromRateSetWithLimit(IN u16 u2RateSet, IN u32 u4PhyRateLimit, + IN u8 fgGetLowest, + OUT u8 *pucRateSwIndex) +{ + u32 i; + u32 u4CurPhyRate, u4TarPhyRate, u4HighestPhyRate, u4LowestPhyRate; + u8 ucRateIndex, ucRatePreamble, ucTarRateSwIndex, ucHighestPhyRateSwIdx, + ucLowestPhyRateSwIdx; + u16 u2CurRateCode; + u32 u4Status; + + /* Set init value */ + if (fgGetLowest) { + u4TarPhyRate = 0xFFFFFFFF; + u4HighestPhyRate = 0; + ucHighestPhyRateSwIdx = RATE_NUM_SW; + } else { + u4TarPhyRate = 0; + u4LowestPhyRate = 0xFFFFFFFF; + ucLowestPhyRateSwIdx = RATE_NUM_SW; + } + + ucTarRateSwIndex = RATE_NUM_SW; + + /* Find SW rate index by limitation */ + for (i = RATE_1M_SW_INDEX; i <= RATE_54M_SW_INDEX; i++) { + if (u2RateSet & BIT(i)) { + /* Convert SW rate index to phy rate in 100kbps */ + nicSwIndex2RateIndex(i, &ucRateIndex, &ucRatePreamble); + u4Status = nicRateIndex2RateCode( + ucRatePreamble, ucRateIndex, &u2CurRateCode); + + if (u4Status != WLAN_STATUS_SUCCESS) { + continue; + } + + u4CurPhyRate = nicRateCode2DataRate( + u2CurRateCode, MAC_BW_20, MAC_GI_NORMAL); + + /* Compare */ + if (fgGetLowest) { + if (u4HighestPhyRate < u4CurPhyRate) { + u4HighestPhyRate = u4CurPhyRate; + ucHighestPhyRateSwIdx = i; + } + if ((u4CurPhyRate >= u4PhyRateLimit) && + (u4CurPhyRate <= u4TarPhyRate)) { + u4TarPhyRate = u4CurPhyRate; + ucTarRateSwIndex = i; + } + } else { + if (u4LowestPhyRate > u4CurPhyRate) { + u4LowestPhyRate = u4CurPhyRate; + ucLowestPhyRateSwIdx = i; + } + if ((u4CurPhyRate <= u4PhyRateLimit) && + (u4CurPhyRate >= u4TarPhyRate)) { + u4TarPhyRate = u4CurPhyRate; + ucTarRateSwIndex = i; + } + } + } + } + + /* Return target SW rate index */ + if (ucTarRateSwIndex < RATE_NUM_SW) { + *pucRateSwIndex = ucTarRateSwIndex; + } else { + if (fgGetLowest) { + *pucRateSwIndex = ucHighestPhyRateSwIdx; + }else{ + *pucRateSwIndex = ucLowestPhyRateSwIdx; + } + } + return true; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_rx.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_rx.c new file mode 100644 index 00000000000000..f40aa6e1d5f745 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_rx.c @@ -0,0 +1,2991 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file nic_rx.c + * \brief Functions that provide many rx-related functions + * + * This file includes the functions used to process RFB and dispatch RFBs to + * the appropriate related rx functions for protocols. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#include "que_mgt.h" + +#include <linux/limits.h> + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +#if CFG_MGMT_FRAME_HANDLING +static PROCESS_RX_MGT_FUNCTION apfnProcessRxMgtFrame[MAX_NUM_OF_FC_SUBTYPES] = { +#if CFG_SUPPORT_AAA + aaaFsmRunEventRxAssoc, /* subtype 0000: Association request */ +#else + NULL, /* subtype 0000: Association request */ +#endif + saaFsmRunEventRxAssoc, /* subtype 0001: Association response */ +#if CFG_SUPPORT_AAA + aaaFsmRunEventRxAssoc, /* subtype 0010: Reassociation request */ +#else + NULL, /* subtype 0010: Reassociation request */ +#endif + saaFsmRunEventRxAssoc, /* subtype 0011: Reassociation response */ +#if CFG_SUPPORT_ADHOC || CFG_ENABLE_WIFI_DIRECT + bssProcessProbeRequest, /* subtype 0100: Probe request */ +#else + NULL, /* subtype 0100: Probe request */ +#endif + scanProcessBeaconAndProbeResp, /* subtype 0101: Probe response */ + NULL, /* subtype 0110: reserved */ + NULL, /* subtype 0111: reserved */ + scanProcessBeaconAndProbeResp, /* subtype 1000: Beacon */ + NULL, /* subtype 1001: ATIM */ + saaFsmRunEventRxDisassoc, /* subtype 1010: Disassociation */ + authCheckRxAuthFrameTransSeq, /* subtype 1011: Authentication */ + saaFsmRunEventRxDeauth, /* subtype 1100: Deauthentication */ + nicRxProcessActionFrame, /* subtype 1101: Action */ + NULL, /* subtype 1110: reserved */ + NULL /* subtype 1111: reserved */ +}; +#endif + +static RX_EVENT_HANDLER_T arEventTable[] = { + { EVENT_ID_RX_ADDBA, qmHandleEventRxAddBa }, + { EVENT_ID_RX_DELBA, qmHandleEventRxDelBa }, + { EVENT_ID_CHECK_REORDER_BUBBLE, qmHandleEventCheckReorderBubble }, + { EVENT_ID_LINK_QUALITY, nicEventLinkQuality }, + { EVENT_ID_LAYER_0_EXT_MAGIC_NUM, nicEventLayer0ExtMagic }, + { EVENT_ID_MIC_ERR_INFO, nicEventMicErrorInfo }, + { EVENT_ID_SCAN_DONE, nicEventScanDone }, + { EVENT_ID_NLO_DONE, nicEventNloDone }, + { EVENT_ID_TX_DONE, nicTxProcessTxDoneEvent }, + { EVENT_ID_SLEEPY_INFO, nicEventSleepyNotify }, + { EVENT_ID_STATISTICS, nicEventStatistics }, + { EVENT_ID_WLAN_INFO, nicEventWlanInfo }, + { EVENT_ID_MIB_INFO, nicEventMibInfo }, +#if CFG_SUPPORT_LAST_SEC_MCS_INFO + { EVENT_ID_TX_MCS_INFO, nicEventTxMcsInfo }, +#endif + { EVENT_ID_CH_PRIVILEGE, cnmChMngrHandleChEvent }, + { EVENT_ID_BSS_ABSENCE_PRESENCE, qmHandleEventBssAbsencePresence }, + { EVENT_ID_STA_CHANGE_PS_MODE, qmHandleEventStaChangePsMode }, + { EVENT_ID_STA_UPDATE_FREE_QUOTA, qmHandleEventStaUpdateFreeQuota }, + { EVENT_ID_BSS_BEACON_TIMEOUT, nicEventBeaconTimeout }, + { EVENT_ID_UPDATE_NOA_PARAMS, nicEventUpdateNoaParams }, + { EVENT_ID_STA_AGING_TIMEOUT, nicEventStaAgingTimeout }, + { EVENT_ID_AP_OBSS_STATUS, nicEventApObssStatus }, + { EVENT_ID_ROAMING_STATUS, nicEventRoamingStatus }, + { EVENT_ID_SEND_DEAUTH, nicEventSendDeauth }, + { EVENT_ID_UPDATE_RDD_STATUS, nicEventUpdateRddStatus }, + { EVENT_ID_UPDATE_BWCS_STATUS, nicEventUpdateBwcsStatus }, + { EVENT_ID_UPDATE_BCM_DEBUG, nicEventUpdateBcmDebug }, + { EVENT_ID_ADD_PKEY_DONE, nicEventAddPkeyDone }, + { EVENT_ID_ICAP_DONE, nicEventIcapDone }, + { EVENT_ID_DEBUG_MSG, nicEventDebugMsg }, + { EVENT_ID_TDLS, nicEventTdls }, + { EVENT_ID_DUMP_MEM, nicEventDumpMem }, +#if CFG_ASSERT_DUMP + { EVENT_ID_ASSERT_DUMP, nicEventAssertDump }, +#endif + { EVENT_ID_RDD_SEND_PULSE, nicEventRddSendPulse }, +#if (CFG_SUPPORT_DFS_MASTER == 1) + { EVENT_ID_UPDATE_COEX_PHYRATE, nicEventUpdateCoexPhyrate }, + { EVENT_ID_RDD_REPORT, cnmRadarDetectEvent }, + { EVENT_ID_CSA_DONE, cnmCsaDoneEvent }, +#else + { EVENT_ID_UPDATE_COEX_PHYRATE, nicEventUpdateCoexPhyrate }, +#endif +#if (CFG_WOW_SUPPORT == 1) + { EVENT_ID_WOW_WAKEUP_REASON, nicEventWakeUpReason }, +#endif + { EVENT_ID_CSI_DATA, nicEventCSIData }, + +#if CFG_SUPPORT_REPLAY_DETECTION + { EVENT_ID_GET_GTK_REKEY_DATA, nicEventGetGtkDataSync }, +#endif +}; + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Initialize the RFBs + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicRxInitialize(IN P_ADAPTER_T prAdapter) +{ + P_RX_CTRL_T prRxCtrl; + u8 *pucMemHandle; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T)NULL; + u32 i; + + DEBUGFUNC("nicRxInitialize"); + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + + /* 4 <0> Clear allocated memory. */ + kalMemZero((void *)prRxCtrl->pucRxCached, prRxCtrl->u4RxCachedSize); + + /* 4 <1> Initialize the RFB lists */ + QUEUE_INITIALIZE(&prRxCtrl->rFreeSwRfbList); + QUEUE_INITIALIZE(&prRxCtrl->rReceivedRfbList); + QUEUE_INITIALIZE(&prRxCtrl->rIndicatedRfbList); + + pucMemHandle = prRxCtrl->pucRxCached; + for (i = CFG_RX_MAX_PKT_NUM; i != 0; i--) { + prSwRfb = (P_SW_RFB_T)pucMemHandle; + + if (nicRxSetupRFB(prAdapter, prSwRfb)) { + DBGLOG(RX, + ERROR, + "nicRxInitialize failed: Cannot allocate packet buffer for SwRfb!\n"); + return; + } + nicRxReturnRFB(prAdapter, prSwRfb); + + pucMemHandle += ALIGN_4(sizeof(SW_RFB_T)); + } + + ASSERT(prRxCtrl->rFreeSwRfbList.u4NumElem == CFG_RX_MAX_PKT_NUM); + /* Check if the memory allocation consist with this initialization + * function */ + ASSERT((u32)(pucMemHandle - prRxCtrl->pucRxCached) == + prRxCtrl->u4RxCachedSize); + + /* 4 <2> Clear all RX counters */ + RX_RESET_ALL_CNTS(prRxCtrl); + + prRxCtrl->pucRxCoalescingBufPtr = prAdapter->pucCoalescingBufCached; + +#if CFG_HIF_STATISTICS + prRxCtrl->u4TotalRxAccessNum = 0; + prRxCtrl->u4TotalRxPacketNum = 0; +#endif + +#if CFG_HIF_RX_STARVATION_WARNING + prRxCtrl->u4QueuedCnt = 0; + prRxCtrl->u4DequeuedCnt = 0; +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Uninitialize the RFBs + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicRxUninitialize(IN P_ADAPTER_T prAdapter) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T)NULL; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + nicRxFlush(prAdapter); + + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rReceivedRfbList, prSwRfb, + P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + if (prSwRfb) { + if (prSwRfb->pvPacket) { + kalPacketFree(prAdapter->prGlueInfo, + prSwRfb->pvPacket); + } + prSwRfb->pvPacket = NULL; + } else { + break; + } + } while (true); + + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, + P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + if (prSwRfb) { + if (prSwRfb->pvPacket) { + kalPacketFree(prAdapter->prGlueInfo, + prSwRfb->pvPacket); + } + prSwRfb->pvPacket = NULL; + } else { + break; + } + } while (true); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Fill RFB + * + * @param prAdapter pointer to the Adapter handler + * @param prSWRfb specify the RFB to receive rx data + * + * @return true: no logic check error, false: logic check error + * + */ +/*----------------------------------------------------------------------------*/ +u8 nicRxFillRFB(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) +{ + P_HW_MAC_RX_DESC_T prRxStatus; + + u32 u4PktLen = 0; + /* u32 u4MacHeaderLen; */ + u32 u4HeaderOffset; + u16 u2RxStatusOffset; + + DEBUGFUNC("nicRxFillRFB"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxStatus = prSwRfb->prRxStatus; + ASSERT(prRxStatus); + + u4PktLen = (u32)HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus); + if (u4PktLen < sizeof(HW_MAC_RX_DESC_T)) { + DBGLOG(RX, ERROR, "Logic Check Error - u4PktLen(%lu) < RXD.\n", + u4PktLen); + return false; + } + + u4HeaderOffset = (u32)(HAL_RX_STATUS_GET_HEADER_OFFSET(prRxStatus)); + /* u4MacHeaderLen = (u32)(HAL_RX_STATUS_GET_HEADER_LEN(prRxStatus)); */ + + /* DBGLOG(RX, TRACE, ("u4HeaderOffset = %d, u4MacHeaderLen = %d\n", */ + /* u4HeaderOffset, u4MacHeaderLen)); */ + u2RxStatusOffset = sizeof(HW_MAC_RX_DESC_T); + prSwRfb->ucGroupVLD = (u8)HAL_RX_STATUS_GET_GROUP_VLD(prRxStatus); + if (prSwRfb->ucGroupVLD & BIT(RX_GROUP_VLD_4)) { + prSwRfb->prRxStatusGroup4 = + (P_HW_MAC_RX_STS_GROUP_4_T)((u8 *)prRxStatus + + u2RxStatusOffset); + u2RxStatusOffset += sizeof(HW_MAC_RX_STS_GROUP_4_T); + + /* Fill out the TID and SSN */ + prSwRfb->ucTid = (u8)(HAL_RX_STATUS_GET_TID(prRxStatus)); + prSwRfb->u2SSN = HAL_RX_STATUS_GET_SEQFrag_NUM( + prSwRfb->prRxStatusGroup4) >> + RX_STATUS_SEQ_NUM_OFFSET; + } + if (prSwRfb->ucGroupVLD & BIT(RX_GROUP_VLD_1)) { + prSwRfb->prRxStatusGroup1 = + (P_HW_MAC_RX_STS_GROUP_1_T)((u8 *)prRxStatus + + u2RxStatusOffset); + u2RxStatusOffset += sizeof(HW_MAC_RX_STS_GROUP_1_T); + } + if (prSwRfb->ucGroupVLD & BIT(RX_GROUP_VLD_2)) { + prSwRfb->prRxStatusGroup2 = + (P_HW_MAC_RX_STS_GROUP_2_T)((u8 *)prRxStatus + + u2RxStatusOffset); + u2RxStatusOffset += sizeof(HW_MAC_RX_STS_GROUP_2_T); + } + if (prSwRfb->ucGroupVLD & BIT(RX_GROUP_VLD_3)) { + prSwRfb->prRxStatusGroup3 = + (P_HW_MAC_RX_STS_GROUP_3_T)((u8 *)prRxStatus + + u2RxStatusOffset); + u2RxStatusOffset += sizeof(HW_MAC_RX_STS_GROUP_3_T); + } + + if (u4PktLen < u2RxStatusOffset + u4HeaderOffset) { + DBGLOG(RX, ERROR, + "Logic Check Error - u4PktLen(%lu) < (%d + %d)\n", + u4PktLen, u2RxStatusOffset, u4HeaderOffset); + return false; + } + prSwRfb->u2RxStatusOffst = u2RxStatusOffset; + prSwRfb->pvHeader = + (u8 *)prRxStatus + u2RxStatusOffset + u4HeaderOffset; + prSwRfb->u2PacketLen = + (u16)(u4PktLen - (u2RxStatusOffset + u4HeaderOffset)); + prSwRfb->u2HeaderLen = (u16)HAL_RX_STATUS_GET_HEADER_LEN(prRxStatus); + if (u4PktLen < + u2RxStatusOffset + u4HeaderOffset + prSwRfb->u2HeaderLen) { + DBGLOG(RX, ERROR, + "Logic Check Error - u4PktLen(%lu) < (%d + %d + %d)\n", + u4PktLen, u2RxStatusOffset, u4HeaderOffset, + prSwRfb->u2HeaderLen); + return false; + } + prSwRfb->ucWlanIdx = (u8)HAL_RX_STATUS_GET_WLAN_IDX(prRxStatus); + prSwRfb->ucStaRecIdx = secGetStaIdxByWlanIdx( + prAdapter, (u8)HAL_RX_STATUS_GET_WLAN_IDX(prRxStatus)); + prSwRfb->prStaRec = + cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + prSwRfb->ucPayloadFormat = HAL_RX_STATUS_GET_PAYLOAD_FORMAT(prRxStatus); + prSwRfb->fgHdrTran = HAL_RX_STATUS_IS_HEADER_TRAN(prRxStatus); + prSwRfb->ucSecMode = HAL_RX_STATUS_GET_SEC_MODE(prRxStatus); + prSwRfb->ucTid = (u8)HAL_RX_STATUS_GET_TID(prRxStatus); + prSwRfb->ucHeaderOffset = HAL_RX_STATUS_GET_HEADER_OFFSET(prRxStatus); + prSwRfb->fgIsBC = HAL_RX_STATUS_IS_BC(prRxStatus); + prSwRfb->fgIsMC = HAL_RX_STATUS_IS_MC(prRxStatus); + + /* DBGLOG(RX, TRACE, ("Dump Rx packet, u2PacketLen = %d\n", + * prSwRfb->u2PacketLen)); */ + /* DBGLOG_MEM8(RX, TRACE, prSwRfb->pvHeader, prSwRfb->u2PacketLen); */ + + return true; +} + +#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 +/*----------------------------------------------------------------------------*/ +/*! + * @brief Fill checksum status in RFB + * + * @param prAdapter pointer to the Adapter handler + * @param prSWRfb the RFB to receive rx data + * @param u4TcpUdpIpCksStatus specify the Checksum status + * + * @return (none) + * + */ +/*----------------------------------------------------------------------------*/ +void nicRxFillChksumStatus(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb, + IN u32 u4TcpUdpIpCksStatus) +{ + ASSERT(prAdapter); + ASSERT(prSwRfb); + + if (prAdapter->u4CSUMFlags != CSUM_NOT_SUPPORTED) { + if (u4TcpUdpIpCksStatus & RX_CS_TYPE_IPv4) { /* IPv4 packet */ + prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_NONE; + if (u4TcpUdpIpCksStatus & RX_CS_STATUS_IP) { /* IP + * packet + * csum + * failed + */ + prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = + CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = + CSUM_RES_SUCCESS; + } + + if (u4TcpUdpIpCksStatus & RX_CS_TYPE_TCP) { /* TCP + * packet */ + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; + if (u4TcpUdpIpCksStatus & + RX_CS_STATUS_TCP) { /* TCP packet csum + * failed */ + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = + CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = + CSUM_RES_SUCCESS; + } + } else if (u4TcpUdpIpCksStatus & + RX_CS_TYPE_UDP) { /* UDP + * packet + */ + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; + if (u4TcpUdpIpCksStatus & + RX_CS_STATUS_UDP) { /* UDP packet csum + * failed */ + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = + CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = + CSUM_RES_SUCCESS; + } + } else { + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; + } + } else if (u4TcpUdpIpCksStatus & RX_CS_TYPE_IPv6) { /* IPv6 + * packet */ + prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_NONE; + prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_SUCCESS; + + if (u4TcpUdpIpCksStatus & RX_CS_TYPE_TCP) { /* TCP + * packet */ + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; + if (u4TcpUdpIpCksStatus & + RX_CS_STATUS_TCP) { /* TCP packet csum + * failed */ + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = + CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = + CSUM_RES_SUCCESS; + } + } else if (u4TcpUdpIpCksStatus & + RX_CS_TYPE_UDP) { /* UDP + * packet + */ + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; + if (u4TcpUdpIpCksStatus & + RX_CS_STATUS_UDP) { /* UDP packet csum + * failed */ + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = + CSUM_RES_FAILED; + } else { + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = + CSUM_RES_SUCCESS; + } + } else { + prSwRfb->aeCSUM[CSUM_TYPE_UDP] = CSUM_RES_NONE; + prSwRfb->aeCSUM[CSUM_TYPE_TCP] = CSUM_RES_NONE; + } + } else { + prSwRfb->aeCSUM[CSUM_TYPE_IPV4] = CSUM_RES_NONE; + prSwRfb->aeCSUM[CSUM_TYPE_IPV6] = CSUM_RES_NONE; + } + } +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief nicRxClearFrag() is used to clean all fragments in the fragment cache. + * + * \param[in] prAdapter pointer to the Adapter handler + * \param[in] prStaRec The fragment cache is stored under station record. + * + * @return (none) + * + */ +/*----------------------------------------------------------------------------*/ +void nicRxClearFrag(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + int j; + FRAG_INFO_T *prFragInfo; + + for (j = 0; j < MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS; j++) { + prFragInfo = &prStaRec->rFragInfo[j]; + + if (prFragInfo->pr1stFrag) { + nicRxReturnRFB(prAdapter, prFragInfo->pr1stFrag); + prFragInfo->pr1stFrag = (SW_RFB_T *)NULL; + } + } + + DBGLOG(RX, INFO, "%s\n", __func__); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief rxDefragMPDU() is used to defragment the incoming packets. + * + * \param[in] prSWRfb The RFB which is being processed. + * \param[in] u16 u2FrameCtrl + * + * \retval NOT NULL Receive the last fragment data + * \retval NULL Receive the fragment packet which is not the last + */ +/*----------------------------------------------------------------------------*/ +P_SW_RFB_T incRxDefragMPDU(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSWRfb, + OUT P_QUE_T prReturnedQue) +{ + P_SW_RFB_T prOutputSwRfb = (P_SW_RFB_T)NULL; +#if CFG_SUPPORT_FRAG_SUPPORT + P_RX_CTRL_T prRxCtrl; + P_FRAG_INFO_T prFragInfo; + u32 i = 0, j; + u16 u2SeqCtrl, u2FrameCtrl; + u16 u2SeqNo; + u8 ucFragNo; + u8 fgFirst = false; + u8 fgLast = false; + u32 rCurrentTime; + P_WLAN_MAC_HEADER_T prWlanHeader = NULL; + P_HW_MAC_RX_DESC_T prRxStatus = NULL; + P_HW_MAC_RX_STS_GROUP_4_T prRxStatusGroup4 = NULL; +#if CFG_SUPPORT_FRAG_ATTACK_DETECTION + u8 ucSecMode = CIPHER_SUITE_NONE; + u64 u8PN; +#endif + u16 u2Frag1FrameCtrl; + + DEBUGFUNC("nicRx: rxmDefragMPDU\n"); + + ASSERT(prSWRfb); + + prRxCtrl = &prAdapter->rRxCtrl; + + prRxStatus = prSWRfb->prRxStatus; + ASSERT(prRxStatus); + + if (HAL_RX_STATUS_IS_HEADER_TRAN(prRxStatus) == false) { + prWlanHeader = (P_WLAN_MAC_HEADER_T)prSWRfb->pvHeader; + prSWRfb->u2SequenceControl = prWlanHeader->u2SeqCtrl; + u2FrameCtrl = prWlanHeader->u2FrameCtrl; + } else { + prRxStatusGroup4 = prSWRfb->prRxStatusGroup4; + prSWRfb->u2SequenceControl = + HAL_RX_STATUS_GET_SEQFrag_NUM(prRxStatusGroup4); + u2FrameCtrl = + HAL_RX_STATUS_GET_FRAME_CTL_FIELD(prRxStatusGroup4); + } + u2SeqCtrl = prSWRfb->u2SequenceControl; + u2SeqNo = u2SeqCtrl >> MASK_SC_SEQ_NUM_OFFSET; + ucFragNo = (u8)(u2SeqCtrl & MASK_SC_FRAG_NUM); + prSWRfb->u2FrameCtrl = u2FrameCtrl; + + if (!(u2FrameCtrl & MASK_FC_MORE_FRAG)) { + /* The last fragment frame */ + if (ucFragNo) { + DBGLOG(RX, LOUD, "FC %04x M %04x SQ %04x\n", + u2FrameCtrl, (u2FrameCtrl & MASK_FC_MORE_FRAG), + u2SeqCtrl); + fgLast = true; + } + /* Non-fragment frame */ + else { + return prSWRfb; + } + } + /* The fragment frame except the last one */ + else { + if (ucFragNo == 0) { + DBGLOG(RX, LOUD, "FC %04x M %04x SQ %04x\n", + u2FrameCtrl, (u2FrameCtrl & MASK_FC_MORE_FRAG), + u2SeqCtrl); + fgFirst = true; + } else { + DBGLOG(RX, LOUD, "FC %04x M %04x SQ %04x\n", + u2FrameCtrl, (u2FrameCtrl & MASK_FC_MORE_FRAG), + u2SeqCtrl); + } + } + + GET_CURRENT_SYSTIME(&rCurrentTime); + +#if CFG_SUPPORT_FRAG_ATTACK_DETECTION + /* check cipher suite to set if we need to get PN */ + if (prSWRfb->ucSecMode == CIPHER_SUITE_TKIP || + prSWRfb->ucSecMode == CIPHER_SUITE_TKIP_WO_MIC || + prSWRfb->ucSecMode == CIPHER_SUITE_CCMP || + prSWRfb->ucSecMode == CIPHER_SUITE_CCMP_W_CCX || + prSWRfb->ucSecMode == CIPHER_SUITE_CCMP_256 || + prSWRfb->ucSecMode == CIPHER_SUITE_GCMP_128 || + prSWRfb->ucSecMode == CIPHER_SUITE_GCMP_256) { + ucSecMode = prSWRfb->ucSecMode; + if (!qmRxPNtoU64(prSWRfb->prRxStatusGroup1->aucPN, CCMPTSCPNNUM, + &u8PN)) { + DBGLOG(QM, ERROR, "PN2U64 failed\n"); + /* should not enter here, just fallback */ + ucSecMode = CIPHER_SUITE_NONE; + } + } +#endif + + for (j = 0; j < MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS; j++) { + prFragInfo = &prSWRfb->prStaRec->rFragInfo[j]; + if (prFragInfo->pr1stFrag) { + /* I. If the receive timer for the MSDU or MMPDU that is + * stored in the fragments queue exceeds + * dot11MaxReceiveLifetime, we discard the uncompleted + * fragments. II. If we didn't receive the last MPDU for + * a period, we use this function for remove frames. + */ + if (CHECK_FOR_EXPIRATION( + rCurrentTime, + prFragInfo->rReceiveLifetimeLimit)) { + /* cnmPktFree((P_PKT_INFO_T)prFragInfo->pr1stFrag, + * true); */ + prFragInfo->pr1stFrag->eDst = + RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL( + prReturnedQue, + (P_QUE_ENTRY_T)prFragInfo->pr1stFrag); + + prFragInfo->pr1stFrag = (P_SW_RFB_T)NULL; + } + } + } + + for (i = 0; i < MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS; i++) { + prFragInfo = &prSWRfb->prStaRec->rFragInfo[i]; + + if (fgFirst) { /* looking for timed-out frag buffer */ + if (prFragInfo->pr1stFrag == (P_SW_RFB_T)NULL) { /* find a + * free + * frag + * buffer + */ + break; + } + } else { /* looking for a buffer with desired next seqctrl */ + if (prFragInfo->pr1stFrag == (P_SW_RFB_T)NULL) { + continue; + } + + u2Frag1FrameCtrl = prFragInfo->pr1stFrag->u2FrameCtrl; + + if (RXM_IS_QOS_DATA_FRAME(u2FrameCtrl)) { + if (RXM_IS_QOS_DATA_FRAME(u2Frag1FrameCtrl)) { + if (u2SeqNo == prFragInfo->u2SeqNo +#if CFG_SUPPORT_FRAG_ATTACK_DETECTION + && + ucSecMode == prFragInfo->ucSecMode +#endif + ) { + break; + } + } + } else { + if (!RXM_IS_QOS_DATA_FRAME(u2Frag1FrameCtrl)) { + if (u2SeqNo == prFragInfo->u2SeqNo +#if CFG_SUPPORT_FRAG_ATTACK_DETECTION + && + ucSecMode == prFragInfo->ucSecMode +#endif + ) { + break; + } + } + } + } + } + + if (i >= MAX_NUM_CONCURRENT_FRAGMENTED_MSDUS) { + /* Can't find a proper FRAG_INFO_T. + * I. 1st Fragment MPDU, all of the FragInfo are exhausted + * II. 2nd ~ (n-1)th Fragment MPDU, can't find the right + * FragInfo for defragment. Because we won't process fragment + * frame outside this function, so we should free it right away. + */ + nicRxReturnRFB(prAdapter, prSWRfb); + + return (P_SW_RFB_T)NULL; + } + + if (prFragInfo->pr1stFrag != (SW_RFB_T *)NULL) { + /* check if the FragNo is cont. */ + if (ucFragNo != prFragInfo->ucNextFragNo +#if CFG_SUPPORT_FRAG_ATTACK_DETECTION + || ((ucSecMode != CIPHER_SUITE_NONE) && + (u8PN != prFragInfo->u8NextPN)) +#endif + ) { + DBGLOG(RX, INFO, "non-cont FragNo or PN, drop it."); + + DBGLOG(RX, + INFO, + "u2SeqNo = %04x, NextFragNo = %02x, FragNo = %02x\n", + prFragInfo->u2SeqNo, + prFragInfo->ucNextFragNo, + ucFragNo); + +#if CFG_SUPPORT_FRAG_ATTACK_DETECTION + if (ucSecMode != CIPHER_SUITE_NONE) { + DBGLOG(RX, + INFO, + "u2SeqNo = %04x, NextPN = %016x, PN = %016x\n", + prFragInfo->u2SeqNo, + prFragInfo->u8NextPN, + u8PN); + } +#endif + + /* discard fragments if FragNo is non-cont. */ + nicRxReturnRFB(prAdapter, prFragInfo->pr1stFrag); + prFragInfo->pr1stFrag = (SW_RFB_T *)NULL; + + nicRxReturnRFB(prAdapter, prSWRfb); + return (SW_RFB_T *)NULL; + } + } + + ASSERT(prFragInfo); + + /* retrieve Rx payload */ + prSWRfb->u2HeaderLen = HAL_RX_STATUS_GET_HEADER_LEN(prRxStatus); + prSWRfb->pucPayload = (u8 *)(((unsigned long)prSWRfb->pvHeader) + + prSWRfb->u2HeaderLen); + prSWRfb->u2PayloadLength = + (u16)(HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus) - + ((unsigned long)prSWRfb->pucPayload - + (unsigned long)prRxStatus)); + + if (fgFirst) { + DBGLOG(RX, LOUD, "rxDefragMPDU first\n"); + + SET_EXPIRATION_TIME( + prFragInfo->rReceiveLifetimeLimit, + TU_TO_SYSTIME(DOT11_RECEIVE_LIFETIME_TU_DEFAULT)); + + prFragInfo->pr1stFrag = prSWRfb; + + prFragInfo->pucNextFragStart = + (u8 *)prSWRfb->pucRecvBuff + + HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus); + + prFragInfo->u2SeqNo = u2SeqNo; + prFragInfo->ucNextFragNo = ucFragNo + 1; /* should be 1 */ + +#if CFG_SUPPORT_FRAG_ATTACK_DETECTION + prFragInfo->ucSecMode = ucSecMode; + if (prFragInfo->ucSecMode != CIPHER_SUITE_NONE) { + prFragInfo->u8NextPN = u8PN + 1; + }else{ + prFragInfo->u8NextPN = 0; + } +#endif + + DBGLOG(RX, + LOUD, + "First: SeqCtrl = %04x, SeqNo = %04x, NextFragNo = %02x\n", + u2SeqCtrl, + prFragInfo->u2SeqNo, + prFragInfo->ucNextFragNo); + + /* prSWRfb->fgFragmented = true; */ + /* whsu: todo for checksum */ + } else { + prFragInfo->pr1stFrag->prRxStatus->u2RxByteCount += + prSWRfb->u2PayloadLength; + + if (prFragInfo->pr1stFrag->prRxStatus->u2RxByteCount > + CFG_RX_MAX_PKT_SIZE) { + prFragInfo->pr1stFrag->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, + (P_QUE_ENTRY_T)prFragInfo->pr1stFrag); + + prFragInfo->pr1stFrag = (P_SW_RFB_T)NULL; + + nicRxReturnRFB(prAdapter, prSWRfb); + } else { + kalMemCopy(prFragInfo->pucNextFragStart, + prSWRfb->pucPayload, + prSWRfb->u2PayloadLength); + /* [6630] update rx byte count and packet length */ + prFragInfo->pr1stFrag->u2PacketLen += + prSWRfb->u2PayloadLength; + prFragInfo->pr1stFrag->u2PayloadLength += + prSWRfb->u2PayloadLength; + + if (fgLast) { /* The last one, free the buffer */ + DBGLOG(RX, LOUD, "Defrag: finished\n"); + + prOutputSwRfb = prFragInfo->pr1stFrag; + + prFragInfo->pr1stFrag = (P_SW_RFB_T)NULL; + } else { + DBGLOG(RX, LOUD, "Defrag: mid fraged\n"); + + prFragInfo->pucNextFragStart += + prSWRfb->u2PayloadLength; + + prFragInfo->ucNextFragNo++; + +#if CFG_SUPPORT_FRAG_ATTACK_DETECTION + if (prFragInfo->ucSecMode != + CIPHER_SUITE_NONE) { + /* PN in security protocol header */ + prFragInfo->u8NextPN++; + } +#endif + } + + nicRxReturnRFB(prAdapter, prSWRfb); + } + } + + /* DBGLOG_MEM8(RXM, INFO, */ + /* prFragInfo->pr1stFrag->pucPayload, */ + /* prFragInfo->pr1stFrag->u2PayloadLength); */ +#else + /* no CFG_SUPPORT_FRAG_SUPPORT, so just free it */ + nicRxReturnRFB(prAdapter, prSWRfb); +#endif + + return prOutputSwRfb; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Do duplicate detection + * + * @param prSwRfb Pointer to the RX packet + * + * @return true: a duplicate, false: not a duplicate + */ +/*----------------------------------------------------------------------------*/ +u8 nicRxIsDuplicateFrame(IN OUT P_SW_RFB_T prSwRfb) +{ + /* Non-QoS Unicast Data or Unicast MMPDU: SC Cache #4; + * QoS Unicast Data: SC Cache #0~3; + * Broadcast/Multicast: RetryBit == 0 + */ + u32 u4SeqCtrlCacheIdx; + u16 u2SequenceControl, u2FrameCtrl; + u8 fgIsDuplicate = false, fgIsAmsduSubframe = false; + P_WLAN_MAC_HEADER_T prWlanHeader = NULL; + P_HW_MAC_RX_DESC_T prRxStatus = NULL; + P_HW_MAC_RX_STS_GROUP_4_T prRxStatusGroup4 = NULL; + + DEBUGFUNC("nicRx: Enter rxmIsDuplicateFrame()\n"); + + ASSERT(prSwRfb); + + /* Situations in which the STC_REC is missing include: + * (1) Probe Request (2) (Re)Association Request (3) IBSS data frames + * (4) Probe Response + */ + if (!prSwRfb->prStaRec) { + return false; + } + + prRxStatus = prSwRfb->prRxStatus; + ASSERT(prRxStatus); + + fgIsAmsduSubframe = HAL_RX_STATUS_GET_PAYLOAD_FORMAT(prRxStatus); + if (HAL_RX_STATUS_IS_HEADER_TRAN(prRxStatus) == false) { + prWlanHeader = (P_WLAN_MAC_HEADER_T)prSwRfb->pvHeader; + u2SequenceControl = prWlanHeader->u2SeqCtrl; + u2FrameCtrl = prWlanHeader->u2FrameCtrl; + } else { + prRxStatusGroup4 = prSwRfb->prRxStatusGroup4; + u2SequenceControl = + HAL_RX_STATUS_GET_SEQFrag_NUM(prRxStatusGroup4); + u2FrameCtrl = + HAL_RX_STATUS_GET_FRAME_CTL_FIELD(prRxStatusGroup4); + } + prSwRfb->u2SequenceControl = u2SequenceControl; + + /* Case 1: Unicast QoS data */ + if (RXM_IS_QOS_DATA_FRAME(u2FrameCtrl)) { /* WLAN header shall exist + * when doing duplicate + * detection */ + if (prSwRfb->ucTid < CFG_RX_MAX_BA_TID_NUM && + prSwRfb->prStaRec->aprRxReorderParamRefTbl[prSwRfb->ucTid]) { + /* QoS data with an RX BA agreement + * Case 1: The packet is not an AMPDU subframe, so the + * RetryBit may be set to 1 (TBC). Case 2: The RX BA + * agreement was just established. Some enqueued packets + * may not be sent with aggregation. + */ + + DBGLOG(RX, LOUD, "RX: SC=0x%X (BA Entry present)\n", + u2SequenceControl); + + /* Update the SN cache in order to ensure the + * correctness of duplicate removal in case the BA + * agreement is deleted + */ + prSwRfb->prStaRec->au2CachedSeqCtrl[prSwRfb->ucTid] = + u2SequenceControl; + + /* HW scoreboard shall take care Case 1. Let the layer + * layer handle Case 2. */ + return false; /* Not a duplicate */ + } + + if (prSwRfb->prStaRec->ucDesiredPhyTypeSet & + (PHY_TYPE_BIT_HT | PHY_TYPE_BIT_VHT)) { + u4SeqCtrlCacheIdx = prSwRfb->ucTid; + } else { + if (prSwRfb->ucTid < 8) { /* UP = 0~7 */ + u4SeqCtrlCacheIdx = aucTid2ACI[prSwRfb->ucTid]; + } else { + DBGLOG(RX, + WARN, + "RXM: (Warning) Unknown QoS Data with TID=%d\n", + prSwRfb->ucTid); + + return true; /* Will be dropped */ + } + } + } + /* Case 2: Unicast non-QoS data or MMPDUs */ + else { + u4SeqCtrlCacheIdx = TID_NUM; + } + + /* If this is a retransmission */ + if (u2FrameCtrl & MASK_FC_RETRY) { + if (u2SequenceControl != + prSwRfb->prStaRec->au2CachedSeqCtrl[u4SeqCtrlCacheIdx]) { + prSwRfb->prStaRec->au2CachedSeqCtrl[u4SeqCtrlCacheIdx] = + u2SequenceControl; + if (fgIsAmsduSubframe == + RX_PAYLOAD_FORMAT_FIRST_SUB_AMSDU) { + prSwRfb->prStaRec->afgIsIgnoreAmsduDuplicate + [u4SeqCtrlCacheIdx] = true; + } + DBGLOG(RX, LOUD, "RXM: SC= 0x%X (Cache[%lu] updated)\n", + u2SequenceControl, u4SeqCtrlCacheIdx); + } else { + /* A duplicate. */ + if (prSwRfb->prStaRec->afgIsIgnoreAmsduDuplicate + [u4SeqCtrlCacheIdx]) { + if (fgIsAmsduSubframe == + RX_PAYLOAD_FORMAT_LAST_SUB_AMSDU) { + prSwRfb->prStaRec + ->afgIsIgnoreAmsduDuplicate + [u4SeqCtrlCacheIdx] = + false; + } + } else { + fgIsDuplicate = true; + DBGLOG(RX, LOUD, + "RXM: SC= 0x%X (Cache[%lu] duplicate)\n", + u2SequenceControl, u4SeqCtrlCacheIdx); + } + } + } + /* Not a retransmission */ + else { + prSwRfb->prStaRec->au2CachedSeqCtrl[u4SeqCtrlCacheIdx] = + u2SequenceControl; + prSwRfb->prStaRec->afgIsIgnoreAmsduDuplicate[u4SeqCtrlCacheIdx] + = + false; + + DBGLOG(RX, LOUD, "RXM: SC= 0x%X (Cache[%lu] updated)\n", + u2SequenceControl, u4SeqCtrlCacheIdx); + } + + return fgIsDuplicate; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process packet doesn't need to do buffer reordering + * + * @param prAdapter pointer to the Adapter handler + * @param prSWRfb the RFB to receive rx data + * + * @return (none) + * + */ +/*----------------------------------------------------------------------------*/ +void nicRxProcessPktWithoutReorder(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb) +{ + P_RX_CTRL_T prRxCtrl; + P_TX_CTRL_T prTxCtrl; + u32 u4CurrentRxBufferCount; + /* P_STA_RECORD_T prStaRec = (P_STA_RECORD_T)NULL; */ + + DEBUGFUNC("nicRxProcessPktWithoutReorder"); + /* DBGLOG(RX, TRACE, ("\n")); */ + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + u4CurrentRxBufferCount = prRxCtrl->rFreeSwRfbList.u4NumElem; + +#if CFG_ENABLE_PER_STA_STATISTICS + if (prSwRfb->prStaRec && + (prAdapter->rWifiVar.rWfdConfigureSettings.ucWfdEnable > 0)) { + prSwRfb->prStaRec->u4TotalRxPktsNumber++; + } +#endif + if (kalProcessRxPacket(prAdapter->prGlueInfo, prSwRfb->pvPacket, + prSwRfb->pvHeader, (u32)prSwRfb->u2PacketLen, + prSwRfb->aeCSUM) != WLAN_STATUS_SUCCESS) { + DBGLOG(RX, + ERROR, + "kalProcessRxPacket return value != WLAN_STATUS_SUCCESS\n"); + ASSERT(0); + + nicRxReturnRFB(prAdapter, prSwRfb); + return; + } + + if (HAL_IS_RX_DIRECT(prAdapter)) { + kalRxIndicateOnePkt(prAdapter->prGlueInfo, prSwRfb->pvPacket); + RX_ADD_CNT(prRxCtrl, RX_DATA_INDICATION_COUNT, 1); + } else { + KAL_SPIN_LOCK_DECLARATION(); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_TO_OS_QUE); + QUEUE_INSERT_TAIL(&(prAdapter->rRxQueue), + (P_QUE_ENTRY_T)GLUE_GET_PKT_QUEUE_ENTRY( + prSwRfb->pvPacket)); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_TO_OS_QUE); + + prRxCtrl->ucNumIndPacket++; + kalSetTxEvent2Rx(prAdapter->prGlueInfo); + } + + prSwRfb->pvPacket = NULL; + + /* Return RFB */ + if (!timerPendingTimer(&prAdapter->rPacketDelaySetupTimer)) { + if (nicRxSetupRFB(prAdapter, prSwRfb)) { + DBGLOG(RX, + WARN, + "Allocate SwRfb packet buf failed, Start ReturnIndicatedRfb Timer (%u)\n", + RX_RETURN_INDICATED_RFB_TIMEOUT_SEC); + cnmTimerStartTimer( + prAdapter, &prAdapter->rPacketDelaySetupTimer, + SEC_TO_MSEC( + RX_RETURN_INDICATED_RFB_TIMEOUT_SEC)); + } + } + nicRxReturnRFB(prAdapter, prSwRfb); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process forwarding data packet + * + * @param prAdapter pointer to the Adapter handler + * @param prSWRfb the RFB to receive rx data + * + * @return (none) + * + */ +/*----------------------------------------------------------------------------*/ +void nicRxProcessForwardPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_MSDU_INFO_T prMsduInfo, prRetMsduInfoList; + P_TX_CTRL_T prTxCtrl; + P_RX_CTRL_T prRxCtrl; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxProcessForwardPkt"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + prMsduInfo = cnmPktAlloc(prAdapter, 0); + + if (prMsduInfo && + kalProcessRxPacket(prAdapter->prGlueInfo, prSwRfb->pvPacket, + prSwRfb->pvHeader, (u32)prSwRfb->u2PacketLen, + prSwRfb->aeCSUM) == WLAN_STATUS_SUCCESS) { + /* parsing forward frame */ + wlanProcessTxFrame(prAdapter, + (P_NATIVE_PACKET)(prSwRfb->pvPacket)); + /* pack into MSDU_INFO_T */ + nicTxFillMsduInfo(prAdapter, prMsduInfo, + (P_NATIVE_PACKET)(prSwRfb->pvPacket)); + + prMsduInfo->eSrc = TX_PACKET_FORWARDING; + prMsduInfo->ucBssIndex = + secGetBssIdxByWlanIdx(prAdapter, prSwRfb->ucWlanIdx); + + /* release RX buffer (to rIndicatedRfbList) */ + prSwRfb->pvPacket = NULL; + nicRxReturnRFB(prAdapter, prSwRfb); + + /* Handle if prMsduInfo out of bss index range*/ + if (prMsduInfo->ucBssIndex > BSSID_NUM) { + DBGLOG(QM, INFO, "Invalid bssidx:%u\n", + prMsduInfo->ucBssIndex); + if (prMsduInfo->pfTxDoneHandler != NULL) { + prMsduInfo->pfTxDoneHandler( + prAdapter, prMsduInfo, + TX_RESULT_DROPPED_IN_DRIVER); + } + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + return; + } + + /* increase forward frame counter */ + GLUE_INC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); + + /* send into TX queue */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + prRetMsduInfoList = qmEnqueueTxPackets(prAdapter, prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + + if (prRetMsduInfoList != NULL) { /* TX queue refuses queuing the + * packet */ + nicTxFreeMsduInfoPacket(prAdapter, prRetMsduInfoList); + nicTxReturnMsduInfo(prAdapter, prRetMsduInfoList); + } + /* indicate service thread for sending */ + if (prTxCtrl->i4PendingFwdFrameCount > 0) { + kalSetEvent(prAdapter->prGlueInfo); + } + } else { /* no TX resource */ + DBGLOG(QM, INFO, "No Tx MSDU_INFO for forwarding frames\n"); + nicRxReturnRFB(prAdapter, prSwRfb); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process broadcast data packet for both host and forwarding + * + * @param prAdapter pointer to the Adapter handler + * @param prSWRfb the RFB to receive rx data + * + * @return (none) + * + */ +/*----------------------------------------------------------------------------*/ +void nicRxProcessGOBroadcastPkt(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb) +{ + P_SW_RFB_T prSwRfbDuplicated; + P_TX_CTRL_T prTxCtrl; + P_RX_CTRL_T prRxCtrl; + P_HW_MAC_RX_DESC_T prRxStatus; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxProcessGOBroadcastPkt"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prTxCtrl = &prAdapter->rTxCtrl; + prRxCtrl = &prAdapter->rRxCtrl; + + prRxStatus = prSwRfb->prRxStatus; + ASSERT(prRxStatus); + + ASSERT(CFG_NUM_OF_QM_RX_PKT_NUM >= 16); + + if (prRxCtrl->rFreeSwRfbList.u4NumElem >= + (CFG_RX_MAX_PKT_NUM - + (CFG_NUM_OF_QM_RX_PKT_NUM - 16 /* Reserved for others */ ))) { + /* 1. Duplicate SW_RFB_T */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfbDuplicated, + P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + + if (prSwRfbDuplicated) { + kalMemCopy(prSwRfbDuplicated->pucRecvBuff, + prSwRfb->pucRecvBuff, + ALIGN_4(prRxStatus->u2RxByteCount + + HIF_RX_HW_APPENDED_LEN)); + + prSwRfbDuplicated->ucPacketType = RX_PKT_TYPE_RX_DATA; + prSwRfbDuplicated->ucStaRecIdx = prSwRfb->ucStaRecIdx; + if (nicRxFillRFB(prAdapter, prSwRfbDuplicated) == + false) { + nicRxReturnRFB(prAdapter, prSwRfb); + return; + } + + /* 2. Modify eDst */ + prSwRfbDuplicated->eDst = RX_PKT_DESTINATION_FORWARD; + + /* 4. Forward */ + nicRxProcessForwardPkt(prAdapter, prSwRfbDuplicated); + } + } else { + DBGLOG(RX, + WARN, + "Stop to forward BMC packet due to less free Sw Rfb %lu\n", + prRxCtrl->rFreeSwRfbList.u4NumElem); + } + + /* 3. Indicate to host */ + prSwRfb->eDst = RX_PKT_DESTINATION_HOST; + nicRxProcessPktWithoutReorder(prAdapter, prSwRfb); +} + +#if CFG_SUPPORT_SNIFFER +void nicRxFillRadiotapMCS(IN OUT P_MONITOR_RADIOTAP_T prMonitorRadiotap, + IN P_HW_MAC_RX_STS_GROUP_3_T prRxStatusGroup3) +{ + u8 ucFrMode; + u8 ucShortGI; + u8 ucRxMode; + u8 ucLDPC; + u8 ucSTBC; + u8 ucNess; + + ucFrMode = (((prRxStatusGroup3)->u4RxVector[0] & RX_VT_FR_MODE_MASK) >> + RX_VT_FR_MODE_OFFSET); + /* VHTA1 B0-B1 */ + ucShortGI = ((prRxStatusGroup3)->u4RxVector[0] & RX_VT_SHORT_GI) ? + 1 : + 0; /* HT_shortgi */ + ucRxMode = (((prRxStatusGroup3)->u4RxVector[0] & RX_VT_RX_MODE_MASK) >> + RX_VT_RX_MODE_OFFSET); + ucLDPC = ((prRxStatusGroup3)->u4RxVector[0] & RX_VT_LDPC) ? + 1 : + 0; /* HT_adcode + */ + ucSTBC = (((prRxStatusGroup3)->u4RxVector[0] & RX_VT_STBC_MASK) >> + RX_VT_STBC_OFFSET); /* HT_stbc */ + ucNess = (((prRxStatusGroup3)->u4RxVector[0] & RX_VT_NESS_MASK) >> + RX_VT_NESS_OFFSET); /* HT_extltf */ + + prMonitorRadiotap->ucMcsKnown = + (BITS(0, 6) | (((ucNess & BIT(1)) >> 1) << 7)); + + prMonitorRadiotap->ucMcsFlags = + ((ucFrMode) | (ucShortGI << 2) | ((ucRxMode & BIT(0)) << 3) | + (ucLDPC << 4) | (ucSTBC << 5) | ((ucNess & BIT(0)) << 7)); + /* Bit[6:0] for 802.11n, mcs0 ~ mcs7 */ + prMonitorRadiotap->ucMcsMcs = + ((prRxStatusGroup3)->u4RxVector[0] & RX_VT_RX_RATE_MASK); +} + +void nicRxFillRadiotapVHT(IN OUT P_MONITOR_RADIOTAP_T prMonitorRadiotap, + IN P_HW_MAC_RX_STS_GROUP_3_T prRxStatusGroup3) +{ + u8 ucSTBC; + u8 ucTxopPsNotAllow; + u8 ucShortGI; + u8 ucNsym; + u8 ucLdpcExtraOfdmSym; + u8 ucBeamFormed; + u8 ucFrMode; + u8 ucNsts; + u8 ucMcs; + + prMonitorRadiotap->u2VhtKnown = RADIOTAP_VHT_ALL_KNOWN; + prMonitorRadiotap->u2VhtKnown &= ~RADIOTAP_VHT_SHORT_GI_NSYM_KNOWN; + + ucSTBC = (((prRxStatusGroup3)->u4RxVector[0] & RX_VT_STBC_MASK) >> + RX_VT_STBC_OFFSET); /* BIT[7]: VHTA1 B3 */ + ucTxopPsNotAllow = ((prRxStatusGroup3)->u4RxVector[0] & + RX_VT_TXOP_PS_NOT_ALLOWED) ? + 1 : + 0; /* VHTA1 B22 */ + /* + * ucNsym = ((prRxStatusGroup3)->u4RxVector[0] & RX_VT_SHORT_GI_NSYM) ? + * 1 : 0; //VHTA2 B1 + */ + ucNsym = 0; /* Invalid in MT6632*/ + ucShortGI = ((prRxStatusGroup3)->u4RxVector[0] & RX_VT_SHORT_GI) ? + 1 : + 0; /* VHTA2 B0 */ + ucLdpcExtraOfdmSym = ((prRxStatusGroup3)->u4RxVector[0] & + RX_VT_LDPC_EXTRA_OFDM_SYM) ? + 1 : + 0; /* VHTA2 B3 */ + ucBeamFormed = ((prRxStatusGroup3)->u4RxVector[0] & RX_VT_BEAMFORMED) ? + 1 : + 0; /* VHTA2 B8 */ + prMonitorRadiotap->ucVhtFlags = + ((ucSTBC) | (ucTxopPsNotAllow << 1) | (ucShortGI << 2) | + (ucNsym << 3) | (ucLdpcExtraOfdmSym << 4) | + (ucBeamFormed << 5)); + + ucFrMode = (((prRxStatusGroup3)->u4RxVector[0] & RX_VT_FR_MODE_MASK) >> + RX_VT_FR_MODE_OFFSET); + /* VHTA1 B0-B1 */ + switch (ucFrMode) { + case RX_VT_FR_MODE_20: + prMonitorRadiotap->ucVhtBandwidth = 0; + break; + + case RX_VT_FR_MODE_40: + prMonitorRadiotap->ucVhtBandwidth = 1; + break; + + case RX_VT_FR_MODE_80: + prMonitorRadiotap->ucVhtBandwidth = 4; + break; + + case RX_VT_FR_MODE_160: + prMonitorRadiotap->ucVhtBandwidth = 11; + break; + + default: + prMonitorRadiotap->ucVhtBandwidth = 0; + } + + /* Set to 0~7 for 1~8 space time streams */ + ucNsts = (((prRxStatusGroup3)->u4RxVector[1] & RX_VT_NSTS_MASK) >> + RX_VT_NSTS_OFFSET) + + 1; + /* VHTA1 B10-B12 */ + + /* Bit[3:0] for 802.11ac, mcs0 ~ mcs9 */ + ucMcs = ((prRxStatusGroup3)->u4RxVector[0] & RX_VT_RX_RATE_AC_MASK); + + prMonitorRadiotap->aucVhtMcsNss[0] = + ((ucMcs << 4) | (ucNsts - ucSTBC)); /* STBC = Nsts - Nss */ + + /* + * prMonitorRadiotap->ucVhtCoding = + * (((prRxStatusGroup3)->u4RxVector[0] & RX_VT_CODING_MASK) >> + * RX_VT_CODING_OFFSET); + */ + prMonitorRadiotap->ucVhtCoding = 0; /* Invalid in MT6632*/ + + /* VHTA2 B2-B3 */ + + prMonitorRadiotap->ucVhtGroupId = + (((((prRxStatusGroup3)->u4RxVector[1] & RX_VT_GROUPID_1_MASK) >> + RX_VT_GROUPID_1_OFFSET) + << 2) | + (((prRxStatusGroup3)->u4RxVector[0] & RX_VT_GROUPID_0_MASK) >> + RX_VT_GROUPID_0_OFFSET)); + /* VHTA1 B4-B9 */ + /* VHTA1 B13-B21 */ + prMonitorRadiotap->u2VhtPartialAid = + ((((prRxStatusGroup3)->u4RxVector[2] & RX_VT_AID_1_MASK) << 4) | + (((prRxStatusGroup3)->u4RxVector[1] & RX_VT_AID_0_MASK) >> + RX_VT_AID_0_OFFSET)); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process HIF monitor packet + * + * @param prAdapter pointer to the Adapter handler + * @param prSWRfb the RFB to receive rx data + * + * @return (none) + * + */ +/*----------------------------------------------------------------------------*/ +void nicRxProcessMonitorPacket(IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb) +{ + struct sk_buff *prSkb = NULL; + P_RX_CTRL_T prRxCtrl; + P_HW_MAC_RX_DESC_T prRxStatus; + P_HW_MAC_RX_STS_GROUP_2_T prRxStatusGroup2; + P_HW_MAC_RX_STS_GROUP_3_T prRxStatusGroup3; + MONITOR_RADIOTAP_T rMonitorRadiotap; + RADIOTAP_FIELD_VENDOR_T rRadiotapFieldVendor; + u8 *prVendorNsOffset; + u32 u4VendorNsLen; + u32 u4RadiotapLen; + u32 u4ItPresent; + u8 aucMtkOui[] = VENDOR_OUI_MTK; + u8 ucRxRate; + u8 ucRxMode; + u8 ucChanNum; + u8 ucMcs; + u8 ucFrMode; + u8 ucShortGI; + u32 u4PhyRate; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxProcessMonitorPacket"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxCtrl = &prAdapter->rRxCtrl; + + if (nicRxFillRFB(prAdapter, prSwRfb) == false) { + nicRxReturnRFB(prAdapter, prSwRfb); + return; + } + + /* can't parse radiotap info if no rx vector */ + if (((prSwRfb->ucGroupVLD & BIT(RX_GROUP_VLD_2)) == 0) || + ((prSwRfb->ucGroupVLD & BIT(RX_GROUP_VLD_3)) == 0)) { + nicRxReturnRFB(prAdapter, prSwRfb); + return; + } + + prRxStatus = prSwRfb->prRxStatus; + prRxStatusGroup2 = prSwRfb->prRxStatusGroup2; + prRxStatusGroup3 = prSwRfb->prRxStatusGroup3; + + /* Bit Number 30 Vendor Namespace */ + u4VendorNsLen = sizeof(RADIOTAP_FIELD_VENDOR_T); + rRadiotapFieldVendor.aucOUI[0] = aucMtkOui[0]; + rRadiotapFieldVendor.aucOUI[1] = aucMtkOui[1]; + rRadiotapFieldVendor.aucOUI[2] = aucMtkOui[2]; + rRadiotapFieldVendor.ucSubNamespace = 0; + rRadiotapFieldVendor.u2DataLen = u4VendorNsLen - 6; + /* VHTA1 B0-B1 */ + rRadiotapFieldVendor.ucData = + (((prRxStatusGroup3)->u4RxVector[0] & RX_VT_FR_MODE_MASK) >> + RX_VT_FR_MODE_OFFSET); + + ucRxMode = (((prRxStatusGroup3)->u4RxVector[0] & RX_VT_RX_MODE_MASK) >> + RX_VT_RX_MODE_OFFSET); + + if (ucRxMode == RX_VT_VHT_MODE) { + u4RadiotapLen = RADIOTAP_LEN_VHT; + u4ItPresent = RADIOTAP_FIELDS_VHT; + } else if ((ucRxMode == RX_VT_MIXED_MODE) || + (ucRxMode == RX_VT_GREEN_MODE)) { + u4RadiotapLen = RADIOTAP_LEN_HT; + u4ItPresent = RADIOTAP_FIELDS_HT; + } else { + u4RadiotapLen = RADIOTAP_LEN_LEGACY; + u4ItPresent = RADIOTAP_FIELDS_LEGACY; + } + + /* Radiotap Header & Bit Number 30 Vendor Namespace */ + prVendorNsOffset = (u8 *)&rMonitorRadiotap + u4RadiotapLen; + u4RadiotapLen += u4VendorNsLen; + kalMemSet(&rMonitorRadiotap, 0, sizeof(MONITOR_RADIOTAP_T)); + kalMemCopy(prVendorNsOffset, (u8 *)&rRadiotapFieldVendor, + u4VendorNsLen); + rMonitorRadiotap.u2ItLen = cpu_to_le16(u4RadiotapLen); + rMonitorRadiotap.u4ItPresent = u4ItPresent; + + /* Bit Number 0 TSFT */ + rMonitorRadiotap.u8MacTime = (prRxStatusGroup2->u4Timestamp); + + /* Bit Number 1 FLAGS */ + if (HAL_RX_STATUS_IS_FRAG(prRxStatus) == true) { + rMonitorRadiotap.ucFlags |= BIT(3); + } + + if (HAL_RX_STATUS_IS_FCS_ERROR(prRxStatus) == true) { + rMonitorRadiotap.ucFlags |= BIT(6); + } + + /* Bit Number 2 RATE */ + if ((ucRxMode == RX_VT_LEGACY_CCK) || (ucRxMode == RX_VT_LEGACY_OFDM)) { + /* Bit[2:0] for Legacy CCK, Bit[3:0] for Legacy OFDM */ + ucRxRate = ((prRxStatusGroup3)->u4RxVector[0] & BITS(0, 3)); + rMonitorRadiotap.ucRate = nicGetHwRateByPhyRate(ucRxRate); + } else { + ucMcs = ((prRxStatusGroup3)->u4RxVector[0] & + RX_VT_RX_RATE_AC_MASK); + /* VHTA1 B0-B1 */ + ucFrMode = (((prRxStatusGroup3)->u4RxVector[0] & + RX_VT_FR_MODE_MASK) >> + RX_VT_FR_MODE_OFFSET); + ucShortGI = + ((prRxStatusGroup3)->u4RxVector[0] & RX_VT_SHORT_GI) ? + 1 : + 0; /* VHTA2 B0 */ + + /* ucRate(500kbs) = u4PhyRate(100kbps) / 5, max ucRate = 0xFF */ + u4PhyRate = nicGetPhyRateByMcsRate(ucMcs, ucFrMode, ucShortGI); + if (u4PhyRate > 1275) { + rMonitorRadiotap.ucRate = 0xFF; + }else{ + rMonitorRadiotap.ucRate = u4PhyRate / 5; + } + } + + /* Bit Number 3 CHANNEL */ + if (ucRxMode == RX_VT_LEGACY_CCK) { + rMonitorRadiotap.u2ChFlags |= BIT(5); + }else{ /* OFDM */ + rMonitorRadiotap.u2ChFlags |= BIT(6); + } + + ucChanNum = HAL_RX_STATUS_GET_CHNL_NUM(prRxStatus); + if (HAL_RX_STATUS_GET_RF_BAND(prRxStatus) == BAND_2G4) { + rMonitorRadiotap.u2ChFlags |= BIT(7); + rMonitorRadiotap.u2ChFrequency = (ucChanNum * 5 + 2407); + } else { /* BAND_5G */ + rMonitorRadiotap.u2ChFlags |= BIT(8); + rMonitorRadiotap.u2ChFrequency = (ucChanNum * 5 + 5000); + } + + /* Bit Number 5 ANT SIGNAL */ + rMonitorRadiotap.ucAntennaSignal = + RCPI_TO_dBm(HAL_RX_STATUS_GET_RCPI0(prSwRfb->prRxStatusGroup3)); + + /* Bit Number 6 ANT NOISE */ + rMonitorRadiotap.ucAntennaNoise = + ((((prRxStatusGroup3)->u4RxVector[5] & RX_VT_NF0_MASK) >> 1) + + 128); + + /* Bit Number 11 ANT, Invalid for MT6632 and MT7615 */ + rMonitorRadiotap.ucAntenna = + ((prRxStatusGroup3)->u4RxVector[2] & RX_VT_SEL_ANT) ? 1 : 0; + + /* Bit Number 19 MCS */ + if ((u4ItPresent & RADIOTAP_FIELD_MCS)) { + nicRxFillRadiotapMCS(&rMonitorRadiotap, prRxStatusGroup3); + } + + /* Bit Number 20 AMPDU */ + if (HAL_RX_STATUS_IS_AMPDU_SUB_FRAME(prRxStatus)) { + if (HAL_RX_STATUS_GET_RXV_SEQ_NO(prRxStatus)) { + ++prRxCtrl->u4AmpduRefNum; + } + rMonitorRadiotap.u4AmpduRefNum = prRxCtrl->u4AmpduRefNum; + } + + /* Bit Number 21 VHT */ + if ((u4ItPresent & RADIOTAP_FIELD_VHT)) { + nicRxFillRadiotapVHT(&rMonitorRadiotap, prRxStatusGroup3); + } + + prSwRfb->pvHeader -= u4RadiotapLen; + kalMemCopy(prSwRfb->pvHeader, &rMonitorRadiotap, u4RadiotapLen); + + prSkb = (struct sk_buff *)(prSwRfb->pvPacket); + prSkb->data = (unsigned char *)(prSwRfb->pvHeader); + + skb_reset_tail_pointer(prSkb); + skb_trim(prSkb, 0); + skb_put(prSkb, (u4RadiotapLen + prSwRfb->u2PacketLen)); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_TO_OS_QUE); + QUEUE_INSERT_TAIL( + &(prAdapter->rRxQueue), + (P_QUE_ENTRY_T)GLUE_GET_PKT_QUEUE_ENTRY(prSwRfb->pvPacket)); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_TO_OS_QUE); + + prRxCtrl->ucNumIndPacket++; + kalSetTxEvent2Rx(prAdapter->prGlueInfo); + + prSwRfb->pvPacket = NULL; + /* Return RFB */ + if (nicRxSetupRFB(prAdapter, prSwRfb)) { + DBGLOG(RX, WARN, "Cannot allocate packet buffer for SwRfb!\n"); + if (!timerPendingTimer(&prAdapter->rPacketDelaySetupTimer)) { + DBGLOG(RX, WARN, + "Start ReturnIndicatedRfb Timer (%u)\n", + RX_RETURN_INDICATED_RFB_TIMEOUT_SEC); + cnmTimerStartTimer( + prAdapter, &prAdapter->rPacketDelaySetupTimer, + SEC_TO_MSEC( + RX_RETURN_INDICATED_RFB_TIMEOUT_SEC)); + } + } + nicRxReturnRFB(prAdapter, prSwRfb); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process HIF data packet + * + * @param prAdapter pointer to the Adapter handler + * @param prSWRfb the RFB to receive rx data + * + * @return (none) + * + */ +/*----------------------------------------------------------------------------*/ +void nicRxProcessDataPacket(IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prRetSwRfb, prNextSwRfb; + P_HW_MAC_RX_DESC_T prRxStatus; + u8 fgDrop; + struct chip_info *prChipInfo; + + DEBUGFUNC("nicRxProcessDataPacket"); + /* DBGLOG(INIT, TRACE, ("\n")); */ + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + fgDrop = false; + + prRxStatus = prSwRfb->prRxStatus; + prRxCtrl = &prAdapter->rRxCtrl; + prChipInfo = prAdapter->chip_info; + + /* Check AMPDU_nERR_Bitmap */ + prSwRfb->fgDataFrame = true; + prSwRfb->fgFragFrame = false; + prSwRfb->fgReorderBuffer = false; + + DBGLOG(RSN, INFO, "StatusFlag:0x%x\n", prRxStatus->u2StatusFlag); + + /* Get RXD in the beginning */ + if (nicRxFillRFB(prAdapter, prSwRfb) == false) { + nicRxReturnRFB(prAdapter, prSwRfb); + RX_INC_CNT(prRxCtrl, RX_CLASS_ERR_DROP_COUNT); + RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); + return; + } + + /* BA session */ + if ((prRxStatus->u2StatusFlag & RXS_DW2_AMPDU_nERR_BITMAP) == + RXS_DW2_AMPDU_nERR_VALUE) { + prSwRfb->fgReorderBuffer = true; + } + /* non BA session */ + else if ((prRxStatus->u2StatusFlag & RXS_DW2_RX_nERR_BITMAP) == + RXS_DW2_RX_nERR_VALUE) { + if ((prRxStatus->u2StatusFlag & RXS_DW2_RX_nDATA_BITMAP) == + RXS_DW2_RX_nDATA_VALUE) { + prSwRfb->fgDataFrame = false; + } + + if ((prRxStatus->u2StatusFlag & RXS_DW2_RX_FRAG_BITMAP) == + RXS_DW2_RX_FRAG_VALUE) { + prSwRfb->fgFragFrame = true; + } + } else if (HAL_RX_STATUS_IS_CIPHER_MISMATCH(prRxStatus)) { + fgDrop = true; + DBGLOG_RATELIMIT(RSN, EVENT, + "HAL_RX_STATUS_IS_CIPHER_MISMATCH\n"); + } else { + fgDrop = true; + + if (HAL_RX_STATUS_IS_DE_AMSDU_FAIL(prRxStatus)) { + DBGLOG_RATELIMIT(RSN, EVENT, "de-amsdu fail\n"); + } + + if (HAL_RX_STATUS_IS_ICV_ERROR(prRxStatus)) { + DBGLOG_RATELIMIT(RSN, EVENT, "icv error\n"); + } + + if (!HAL_RX_STATUS_IS_ICV_ERROR(prRxStatus) && + HAL_RX_STATUS_IS_TKIP_MIC_ERROR(prRxStatus)) { + P_STA_RECORD_T prStaRec; + + prStaRec = cnmGetStaRecByAddress( + prAdapter, prAdapter->prAisBssInfo->ucBssIndex, + prAdapter->rWlanInfo.rCurrBssId.arMacAddress); + if (prStaRec) { + DBGLOG_RATELIMIT(RSN, EVENT, "MIC_ERR_PKT\n"); + rsnTkipHandleMICFailure(prAdapter, prStaRec, 0); + } + } +#if UNIFIED_MAC_RX_FORMAT + else if (HAL_RX_STATUS_IS_LLC_MIS(prRxStatus) && + !HAL_RX_STATUS_IS_ERROR(prRxStatus) && + !FEAT_SUP_LLC_VLAN_RX(prChipInfo)) { + u16 *pu2EtherType; + + pu2EtherType = (u16 *)((u8 *)prSwRfb->pvHeader + + 2 * MAC_ADDR_LEN); + +#if CFG_SUPPORT_AMSDU_ATTACK_DETECTION + if (HAL_RX_STATUS_GET_PAYLOAD_FORMAT(prRxStatus) == + RX_PAYLOAD_FORMAT_FIRST_SUB_AMSDU) { + DBGLOG(RX, INFO, "LLC_MIS:%d, EthType:0x%x\n", + HAL_RX_STATUS_IS_LLC_MIS(prRxStatus), + pu2EtherType); + fgDrop = false; + } +#endif + + /* If ethernet type is VLAN, do not drop it. Pass up to + * driver process */ + if (prSwRfb->u2HeaderLen >= ETH_HLEN && + *pu2EtherType == NTOHS(ETH_P_VLAN)) { + fgDrop = false; + } + } +#else + else if (HAL_RX_STATUS_IS_LLC_MIS(prRxStatus)) { + DBGLOG_RATELIMIT(RSN, EVENT, ("LLC_MIS_ERR\n")); + fgDrop = false; /* Drop after send de-auth */ + } +#endif + } + + /* Drop plain text during security connection */ + if (HAL_RX_STATUS_IS_CIPHER_MISMATCH(prRxStatus) && + (prSwRfb->fgDataFrame == true)) { + u16 *pu2EtherType; + + pu2EtherType = + (u16 *)((u8 *)prSwRfb->pvHeader + 2 * MAC_ADDR_LEN); + + DBGLOG_RATELIMIT( + RSN, EVENT, + "HAL_RX_STATUS_IS_CIPHER_MISMATCH, htr:%d, HdrLen:%d\n", + HAL_RX_STATUS_IS_HEADER_TRAN(prRxStatus), + HAL_RX_STATUS_GET_HEADER_LEN(prRxStatus)); + + if (prSwRfb->u2HeaderLen >= ETH_HLEN && + (*pu2EtherType == NTOHS(ETH_P_1X))) { + fgDrop = false; + DBGLOG(RSN, INFO, "Don't drop eapol or wpi packet\n"); + } else { + fgDrop = true; + DBGLOG_RATELIMIT( + RSN, EVENT, + "Drop plain text during security connection\n"); + } + } + +#if CFG_SUPPORT_FRAG_ATTACK_DETECTION + /* Drop fragmented broadcast and multicast frame */ + if ((prSwRfb->fgIsBC | prSwRfb->fgIsMC) && + (prSwRfb->fgFragFrame == true)) { + fgDrop = true; + DBGLOG(RSN, INFO, "Drop fragmented broadcast and multicast\n"); + } +#endif + +#if CFG_KEY_ERROR_STATISTIC_RECOVERY + if ((prSwRfb->fgIsBC || prSwRfb->fgIsMC) && + (prSwRfb->fgDataFrame == true)) { + u8 ucBssIndex = secGetBssIdxByWlanIdx( + prAdapter, HAL_RX_STATUS_GET_WLAN_IDX(prRxStatus)); + P_BSS_INFO_T prBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if (prBssInfo && IS_BSS_AIS(prBssInfo)) { + u8 fgTriggerBCNTimeout = false; + + RX_INC_CNT(&prAdapter->rRxCtrl, RX_BMC_PKT_COUNT); + + if (HAL_RX_STATUS_IS_ICV_ERROR(prRxStatus)) { + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_BMC_KEY_ERROR_COUNT); + + DBGLOG_RATELIMIT( + RSN, + EVENT, + "BMC Data Packet(%llu) from AIS Wi-Fi interface with ICV error\n", + RX_GET_CNT(&prAdapter->rRxCtrl, + RX_BMC_KEY_ERROR_COUNT)); + + if (RX_GET_CNT(&prAdapter->rRxCtrl, + RX_BMC_KEY_ERROR_COUNT) == + prAdapter->rWifiVar.u4BmcKeyErrorTh) { + fgTriggerBCNTimeout = true; + } + } else if (HAL_RX_STATUS_IS_CIPHER_MISMATCH( + prRxStatus)) { + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_BMC_NO_KEY_COUNT); + + DBGLOG_RATELIMIT( + RSN, + EVENT, + "BMC Data Packet(%llu) from AIS Wi-Fi interface with Cipher Mismatch\n", + RX_GET_CNT(&prAdapter->rRxCtrl, + RX_BMC_NO_KEY_COUNT)); + + if (RX_GET_CNT(&prAdapter->rRxCtrl, + RX_BMC_NO_KEY_COUNT) == + prAdapter->rWifiVar.u4BmcKeyErrorTh) { + fgTriggerBCNTimeout = true; + } + } + + if ((fgTriggerBCNTimeout) && + (prAdapter->rWifiVar.u4BmcKeyErrorTh)) { + DBGLOG(QM, + EVENT, + "Trigger BCN timeout due to RX more than\n" + " %llu cipher mismatch BMC packets\n" + " %llu ICV error BMC packets\n", + RX_GET_CNT(&prAdapter->rRxCtrl, + RX_BMC_NO_KEY_COUNT), + RX_GET_CNT(&prAdapter->rRxCtrl, + RX_BMC_KEY_ERROR_COUNT)); + + prBssInfo->u2DeauthReason = + BEACON_TIMEOUT_REASON_DUE_2_BMC_ERR; + kalIndicateStatusAndComplete( + prAdapter->prGlueInfo, + WLAN_STATUS_BEACON_TIMEOUT, NULL, 0); + } + } + } +#endif + +#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 + if (prAdapter->fgIsSupportCsumOffload && fgDrop == false) { + u32 u4TcpUdpIpCksStatus; + u32 *pu4Temp; + + pu4Temp = (u32 *)prRxStatus; + u4TcpUdpIpCksStatus = + *(pu4Temp + (ALIGN_4(prRxStatus->u2RxByteCount) >> 2)); + nicRxFillChksumStatus(prAdapter, prSwRfb, u4TcpUdpIpCksStatus); + } +#endif + + /* if(secCheckClassError(prAdapter, prSwRfb, prStaRec) == true && */ + if (prAdapter->fgTestMode == false && fgDrop == false) { +#if CFG_HIF_RX_STARVATION_WARNING + prRxCtrl->u4QueuedCnt++; +#endif + GLUE_SET_PKT_BSS_IDX(prSwRfb->pvPacket, + secGetBssIdxByWlanIdx(prAdapter, + prSwRfb->ucWlanIdx)); + + prRetSwRfb = qmHandleRxPackets(prAdapter, prSwRfb); + if (prRetSwRfb != NULL) { + do { +#if CFG_SUPPORT_MSP + if (prRetSwRfb->ucGroupVLD & + BIT(RX_GROUP_VLD_3)) { + if (prRetSwRfb->ucStaRecIdx < + CFG_STA_REC_NUM) { + prAdapter + ->arStaRec[prRetSwRfb + ->ucStaRecIdx] + .u4RxVector0 = + HAL_RX_VECTOR_GET_RX_VECTOR + ( + prRetSwRfb + -> + prRxStatusGroup3, + 0); + + prAdapter + ->arStaRec[prRetSwRfb + ->ucStaRecIdx] + .u4RxVector1 = + HAL_RX_VECTOR_GET_RX_VECTOR + ( + prRetSwRfb + -> + prRxStatusGroup3, + 1); + + prAdapter + ->arStaRec[prRetSwRfb + ->ucStaRecIdx] + .u4RxVector2 = + HAL_RX_VECTOR_GET_RX_VECTOR + ( + prRetSwRfb + -> + prRxStatusGroup3, + 2); + + prAdapter + ->arStaRec[prRetSwRfb + ->ucStaRecIdx] + .u4RxVector3 = + HAL_RX_VECTOR_GET_RX_VECTOR + ( + prRetSwRfb + -> + prRxStatusGroup3, + 3); + + prAdapter + ->arStaRec[prRetSwRfb + ->ucStaRecIdx] + .u4RxVector4 = + HAL_RX_VECTOR_GET_RX_VECTOR + ( + prRetSwRfb + -> + prRxStatusGroup3, + 4); + } else { + DBGLOG(RX, + ERROR, + "invalid ucStaRecIdx %d\n", + prRetSwRfb->ucStaRecIdx); + } + } +#endif + /* save next first */ + prNextSwRfb = (P_SW_RFB_T)QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prRetSwRfb); + + switch (prRetSwRfb->eDst) { + case RX_PKT_DESTINATION_HOST: + nicRxProcessPktWithoutReorder( + prAdapter, prRetSwRfb); + break; + + case RX_PKT_DESTINATION_FORWARD: + nicRxProcessForwardPkt(prAdapter, + prRetSwRfb); + break; + + case RX_PKT_DESTINATION_HOST_WITH_FORWARD: + nicRxProcessGOBroadcastPkt(prAdapter, + prRetSwRfb); + break; + + case RX_PKT_DESTINATION_NULL: + nicRxReturnRFB(prAdapter, prRetSwRfb); + RX_INC_CNT(prRxCtrl, + RX_DST_NULL_DROP_COUNT); + RX_INC_CNT(prRxCtrl, + RX_DROP_TOTAL_COUNT); + break; + + default: + break; + } +#if CFG_HIF_RX_STARVATION_WARNING + prRxCtrl->u4DequeuedCnt++; +#endif + prRetSwRfb = prNextSwRfb; + } while (prRetSwRfb); + } + } else { + nicRxReturnRFB(prAdapter, prSwRfb); + RX_INC_CNT(prRxCtrl, RX_CLASS_ERR_DROP_COUNT); + RX_INC_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT); + } +} + +void nicRxProcessEventPacket(IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb) +{ + P_CMD_INFO_T prCmdInfo; + P_WIFI_EVENT_T prEvent; + u32 u4Idx, u4Size; + P_HW_MAC_RX_DESC_T prRxStatus; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxStatus = prSwRfb->prRxStatus; + ASSERT(prRxStatus); + + prSwRfb->u2PacketLen = HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus); + if (prSwRfb->u2PacketLen < sizeof(HW_MAC_RX_DESC_T)) { + DBGLOG(RX, ERROR, + "%s: Logic Check Error - u4PktLen(%lu) < RXD.\n", + __func__, prSwRfb->u2PacketLen); + return; + } + + prEvent = (P_WIFI_EVENT_T)prSwRfb->pucRecvBuff; + + if (prEvent->ucEID != EVENT_ID_DEBUG_MSG +#if CFG_ASSERT_DUMP + && prEvent->ucEID != EVENT_ID_ASSERT_DUMP +#endif + ) { + DBGLOG(NIC, INFO, "RX EVENT: ID[0x%02X] SEQ[%u] LEN[%u]\n", + prEvent->ucEID, prEvent->ucSeqNum, + prEvent->u2PacketLength); + } + if ((prEvent->u2PacketLength - EVENT_HDR_WITHOUT_RXD_SIZE) > + prSwRfb->u2PacketLen - sizeof(WIFI_EVENT_T)) { + DBGLOG(NIC, + ERROR, + "RX EVENT: ID[0x%02X] SEQ[%u], invalid payload LEN[%u] > %u\n", + prEvent->ucEID, + prEvent->ucSeqNum, + prEvent->u2PacketLength - EVENT_HDR_WITHOUT_RXD_SIZE, + prSwRfb->u2PacketLen - sizeof(WIFI_EVENT_T)); + goto done; + } + + /* Event handler table */ + u4Size = sizeof(arEventTable) / sizeof(RX_EVENT_HANDLER_T); + + for (u4Idx = 0; u4Idx < u4Size; u4Idx++) { + if (prEvent->ucEID == arEventTable[u4Idx].eEID) { + arEventTable[u4Idx].pfnHandler( + prAdapter, prEvent, + (prEvent->u2PacketLength - + EVENT_HDR_WITHOUT_RXD_SIZE)); + break; + } + } + + /* Event cannot be found in event handler table, use default action */ + if (u4Idx >= u4Size) { + prCmdInfo = nicGetPendingCmdInfo(prAdapter, prEvent->ucSeqNum); + + if (prCmdInfo != NULL) { + if (prCmdInfo->pfCmdDoneHandler) { + prCmdInfo->pfCmdDoneHandler( + prAdapter, prCmdInfo, + prEvent->aucBuffer, + (prEvent->u2PacketLength - + EVENT_HDR_WITHOUT_RXD_SIZE)); + } else if (prCmdInfo->fgIsOid) { + kalOidComplete(prAdapter->prGlueInfo, + prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_SUCCESS); + } + + /* return prCmdInfo */ + cmdBufFreeCmdInfo(prAdapter, prCmdInfo); + } else { + DBGLOG(RX, + WARN, + "UNHANDLED RX EVENT: ID[0x%02X] SEQ[%u] LEN[%u]\n", + prEvent->ucEID, + prEvent->ucSeqNum, + prEvent->u2PacketLength); + } + } +done: + /* Reset Chip NoAck flag */ + if (prAdapter->fgIsChipNoAck) { + DBGLOG(RX, WARN, "Got response from chip, clear NoAck flag!\n"); + WARN_ON(true); + } + prAdapter->ucOidTimeoutCount = 0; + prAdapter->fgIsChipNoAck = false; + + nicRxReturnRFB(prAdapter, prSwRfb); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief nicRxProcessMgmtPacket is used to dispatch management frames + * to corresponding modules + * + * @param prAdapter Pointer to the Adapter structure. + * @param prSWRfb the RFB to receive rx data + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicRxProcessMgmtPacket(IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb) +{ + u8 ucSubtype; +#if CFG_SUPPORT_802_11W + /* u8 fgMfgDrop = false; */ +#endif + ASSERT(prAdapter); + ASSERT(prSwRfb); + + if (nicRxFillRFB(prAdapter, prSwRfb) == false) { + nicRxReturnRFB(prAdapter, prSwRfb); + RX_INC_CNT(&prAdapter->rRxCtrl, RX_DROP_TOTAL_COUNT); + return; + } + + ucSubtype = (*(u8 *)(prSwRfb->pvHeader) & MASK_FC_SUBTYPE) >> + OFFSET_OF_FC_SUBTYPE; + +#if CFG_RX_PKTS_DUMP + { + P_WLAN_MAC_MGMT_HEADER_T prWlanMgmtHeader; + u16 u2TxFrameCtrl; + + u2TxFrameCtrl = (*(u8 *)(prSwRfb->pvHeader) & MASK_FRAME_TYPE); + if (prAdapter->rRxCtrl.u4RxPktsDumpTypeMask & + BIT(HIF_RX_PKT_TYPE_MANAGEMENT)) { + if (u2TxFrameCtrl == MAC_FRAME_BEACON || + u2TxFrameCtrl == MAC_FRAME_PROBE_RSP) { + prWlanMgmtHeader = + (P_WLAN_MAC_MGMT_HEADER_T)(prSwRfb-> + pvHeader); + + DBGLOG(SW4, + INFO, + "QM RX MGT: net %u sta idx %u wlan idx %u ssn %u ptype %u subtype %u 11 %u\n", + prSwRfb->prStaRec->ucBssIndex, + prSwRfb->ucStaRecIdx, + prSwRfb->ucWlanIdx, + prWlanMgmtHeader->u2SeqCtrl, + /* The new SN of the frame */ + prSwRfb->ucPacketType, + ucSubtype); + /* HIF_RX_HDR_GET_80211_FLAG(prHifRxHdr))); */ + + DBGLOG_MEM8(SW4, TRACE, (u8 *)prSwRfb->pvHeader, + prSwRfb->u2PacketLen); + } + } + } +#endif +#if CFG_SUPPORT_802_11W + if (HAL_RX_STATUS_IS_ICV_ERROR(prSwRfb->prRxStatus)) { + if (HAL_RX_STATUS_GET_SEC_MODE(prSwRfb->prRxStatus) == + CIPHER_SUITE_BIP) { + DBGLOG(RSN, INFO, "[MFP] RX with BIP ICV ERROR\n"); + }else{ + DBGLOG(RSN, INFO, "[MFP] RX with ICV ERROR\n"); + } + + nicRxReturnRFB(prAdapter, prSwRfb); + RX_INC_CNT(&prAdapter->rRxCtrl, RX_DROP_TOTAL_COUNT); + return; + } +#endif + + if (prAdapter->fgTestMode == false) { +#if CFG_MGMT_FRAME_HANDLING + if (apfnProcessRxMgtFrame[ucSubtype]) { + switch (apfnProcessRxMgtFrame[ucSubtype](prAdapter, + prSwRfb)) { + case WLAN_STATUS_PENDING: + return; + + case WLAN_STATUS_SUCCESS: + case WLAN_STATUS_FAILURE: + break; + + default: + DBGLOG(RX, + WARN, + "Unexpected MMPDU(0x%02X) returned with abnormal status\n", + ucSubtype); + break; + } + } +#endif + } + + nicRxReturnRFB(prAdapter, prSwRfb); +} + +void nicRxProcessMsduReport(IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb) +{ + nicRxReturnRFB(prAdapter, prSwRfb); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief nicProcessRFBs is used to process RFBs in the rReceivedRFBList queue. + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicRxProcessRFBs(IN P_ADAPTER_T prAdapter) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T)NULL; + QUE_T rTempRfbList; + P_QUE_T prTempRfbList = &rTempRfbList; + u32 u4RxLoopCount; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicRxProcessRFBs"); + + ASSERT(prAdapter); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + prRxCtrl->ucNumIndPacket = 0; + prRxCtrl->ucNumRetainedPacket = 0; + u4RxLoopCount = prAdapter->rWifiVar.u4TxRxLoopCount; + + QUEUE_INITIALIZE(prTempRfbList); + + while (u4RxLoopCount--) { + while (QUEUE_IS_NOT_EMPTY(&prRxCtrl->rReceivedRfbList)) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_MOVE_ALL(prTempRfbList, + &prRxCtrl->rReceivedRfbList); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + while (QUEUE_IS_NOT_EMPTY(prTempRfbList)) { + QUEUE_REMOVE_HEAD(prTempRfbList, prSwRfb, + P_SW_RFB_T); + + switch (prSwRfb->ucPacketType) { + case RX_PKT_TYPE_RX_DATA: +#if CFG_SUPPORT_SNIFFER + if (prAdapter->prGlueInfo + ->fgIsEnableMon && + HAL_IS_RX_DIRECT(prAdapter)) { + nicRxProcessMonitorPacket( + prAdapter, prSwRfb); + break; + } else if (prAdapter->prGlueInfo + ->fgIsEnableMon) { + nicRxProcessMonitorPacket( + prAdapter, prSwRfb); + break; + } +#endif + if (HAL_IS_RX_DIRECT(prAdapter)) { + nicRxProcessDataPacket( + prAdapter, prSwRfb); + } else { + nicRxProcessDataPacket( + prAdapter, prSwRfb); + } + break; + + case RX_PKT_TYPE_SW_DEFINED: + /* HIF_RX_PKT_TYPE_EVENT */ + if ((prSwRfb->prRxStatus->u2PktTYpe & + RXM_RXD_PKT_TYPE_SW_BITMAP) == + RXM_RXD_PKT_TYPE_SW_EVENT) { + nicRxProcessEventPacket( + prAdapter, prSwRfb); + } + /* case HIF_RX_PKT_TYPE_MANAGEMENT: */ + else if ((prSwRfb->prRxStatus->u2PktTYpe + & + RXM_RXD_PKT_TYPE_SW_BITMAP) == + RXM_RXD_PKT_TYPE_SW_FRAME) { + nicRxProcessMgmtPacket( + prAdapter, prSwRfb); + } else { + DBGLOG(RX, + ERROR, + "u2PktTYpe(0x%04X) is OUT OF DEF.!!!\n", + prSwRfb->prRxStatus + ->u2PktTYpe); + DBGLOG_MEM8( + RX, ERROR, + (u8 *)prSwRfb->pvHeader, + prSwRfb->u2PacketLen); + + /*ASSERT(0);*/ + nicRxReturnRFB(prAdapter, + prSwRfb); + RX_INC_CNT( + prRxCtrl, + RX_TYPE_ERR_DROP_COUNT); + RX_INC_CNT(prRxCtrl, + RX_DROP_TOTAL_COUNT); + } + break; + + case RX_PKT_TYPE_MSDU_REPORT: + nicRxProcessMsduReport(prAdapter, + prSwRfb); + break; + + /* case HIF_RX_PKT_TYPE_TX_LOOPBACK: */ + /* case HIF_RX_PKT_TYPE_MANAGEMENT: */ + case RX_PKT_TYPE_TX_STATUS: + case RX_PKT_TYPE_RX_VECTOR: + case RX_PKT_TYPE_TM_REPORT: + default: + nicRxReturnRFB(prAdapter, prSwRfb); + RX_INC_CNT(prRxCtrl, + RX_TYPE_ERR_DROP_COUNT); + RX_INC_CNT(prRxCtrl, + RX_DROP_TOTAL_COUNT); + DBGLOG(RX, ERROR, "ucPacketType = %d\n", + prSwRfb->ucPacketType); + break; + } + } + + if (prRxCtrl->ucNumIndPacket > 0) { + RX_ADD_CNT(prRxCtrl, RX_DATA_INDICATION_COUNT, + prRxCtrl->ucNumIndPacket); + RX_ADD_CNT(prRxCtrl, RX_DATA_RETAINED_COUNT, + prRxCtrl->ucNumRetainedPacket); + } + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Setup a RFB and allocate the os packet to the RFB + * + * @param prAdapter Pointer to the Adapter structure. + * @param prSwRfb Pointer to the RFB + * + * @retval WLAN_STATUS_SUCCESS + * @retval WLAN_STATUS_RESOURCES + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicRxSetupRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + void *pvPacket; + u8 *pucRecvBuff; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + if (!prSwRfb->pvPacket) { + kalMemZero(prSwRfb, sizeof(SW_RFB_T)); + pvPacket = kalPacketAlloc(prAdapter->prGlueInfo, + CFG_RX_MAX_PKT_SIZE, &pucRecvBuff); + if (pvPacket == NULL) { + return WLAN_STATUS_RESOURCES; + } + + prSwRfb->pvPacket = pvPacket; + prSwRfb->pucRecvBuff = (void *)pucRecvBuff; + } else { + kalMemZero( + ((u8 *)prSwRfb + OFFSET_OF(SW_RFB_T, prRxStatus)), + (sizeof(SW_RFB_T) - OFFSET_OF(SW_RFB_T, prRxStatus))); + } + + /* ToDo: remove prHifRxHdr */ + /* prSwRfb->prHifRxHdr = (P_HIF_RX_HEADER_T)(prSwRfb->pucRecvBuff); */ + prSwRfb->prRxStatus = (P_HW_MAC_RX_DESC_T)(prSwRfb->pucRecvBuff); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is called to put a RFB back onto the "RFB with Buffer" + * list or "RFB without buffer" list according to pvPacket. + * + * @param prAdapter Pointer to the Adapter structure. + * @param prSwRfb Pointer to the RFB + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicRxReturnRFB(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + P_RX_CTRL_T prRxCtrl; + P_QUE_ENTRY_T prQueEntry; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + prRxCtrl = &prAdapter->rRxCtrl; + prQueEntry = &prSwRfb->rQueEntry; + + ASSERT(prQueEntry); + + /* The processing on this RFB is done, so put it back on the tail of our + * list */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + + if (prSwRfb->pvPacket) { + /* Zero out the packet buffer between uses */ + kalMemZero( + ((u8 *)prSwRfb + OFFSET_OF(SW_RFB_T, prRxStatus)), + (sizeof(SW_RFB_T) - OFFSET_OF(SW_RFB_T, prRxStatus))); + prSwRfb->prRxStatus = + (P_HW_MAC_RX_DESC_T)(prSwRfb->pucRecvBuff); + + /* QUEUE_INSERT_TAIL */ + QUEUE_INSERT_TAIL(&prRxCtrl->rFreeSwRfbList, prQueEntry); + } else { + /* QUEUE_INSERT_TAIL */ + QUEUE_INSERT_TAIL(&prRxCtrl->rIndicatedRfbList, prQueEntry); + } + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + + /* Trigger Rx if there are free SwRfb */ + if (halIsPendingRx(prAdapter) && + (prRxCtrl->rFreeSwRfbList.u4NumElem > 0)) { + kalSetIntEvent(prAdapter->prGlueInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process rx interrupt. When the rx + * Interrupt is asserted, it means there are frames in queue. + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicProcessRxInterrupt(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + if (nicSerIsRxStop(prAdapter)) { + return; + } + + halProcessRxInterrupt(prAdapter); + + set_bit(GLUE_FLAG_RX_BIT, &(prAdapter->prGlueInfo->ulFlag)); + wake_up_interruptible(&(prAdapter->prGlueInfo->waitq)); + + return; +} + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +/*----------------------------------------------------------------------------*/ +/*! + * @brief Used to update IP/TCP/UDP checksum statistics of RX Module. + * + * @param prAdapter Pointer to the Adapter structure. + * @param aeCSUM The array of checksum result. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicRxUpdateCSUMStatistics(IN P_ADAPTER_T prAdapter, + IN const ENUM_CSUM_RESULT_T aeCSUM[]) +{ + P_RX_CTRL_T prRxCtrl; + + ASSERT(prAdapter); + ASSERT(aeCSUM); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_SUCCESS) || + (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_SUCCESS)) { + /* count success num */ + RX_INC_CNT(prRxCtrl, RX_CSUM_IP_SUCCESS_COUNT); + } else if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_FAILED) || + (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_FAILED)) { + RX_INC_CNT(prRxCtrl, RX_CSUM_IP_FAILED_COUNT); + } else if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_NONE) && + (aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_NONE)) { + RX_INC_CNT(prRxCtrl, RX_CSUM_UNKNOWN_L3_PKT_COUNT); + } else { + ASSERT(0); + } + + if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_SUCCESS) { + /* count success num */ + RX_INC_CNT(prRxCtrl, RX_CSUM_TCP_SUCCESS_COUNT); + } else if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_FAILED) { + RX_INC_CNT(prRxCtrl, RX_CSUM_TCP_FAILED_COUNT); + } else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_SUCCESS) { + RX_INC_CNT(prRxCtrl, RX_CSUM_UDP_SUCCESS_COUNT); + } else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_FAILED) { + RX_INC_CNT(prRxCtrl, RX_CSUM_UDP_FAILED_COUNT); + } else if ((aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_NONE) && + (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_NONE)) { + RX_INC_CNT(prRxCtrl, RX_CSUM_UNKNOWN_L4_PKT_COUNT); + } else { + ASSERT(0); + } +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to query current status of RX Module. + * + * @param prAdapter Pointer to the Adapter structure. + * @param pucBuffer Pointer to the message buffer. + * @param pu4Count Pointer to the buffer of message length count. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicRxQueryStatus(IN P_ADAPTER_T prAdapter, IN u8 *pucBuffer, + OUT u32 *pu4Count) +{ + P_RX_CTRL_T prRxCtrl; + u8 *pucCurrBuf = pucBuffer; + u32 u4CurrCount; + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + /* if (pucBuffer) {} */ /* For Windows, we'll print directly instead of + * sprintf() */ + ASSERT(pu4Count); + +#define SPRINTF_RX_QSTATUS(arg) \ + { \ + u4CurrCount = \ + scnprintf(pucCurrBuf, *pu4Count, PRINTF_ARG arg); \ + pucCurrBuf += (u8)u4CurrCount; \ + *pu4Count -= u4CurrCount; \ + } + + SPRINTF_RX_QSTATUS(("\n\nRX CTRL STATUS:")); + SPRINTF_RX_QSTATUS(("\n===============")); + SPRINTF_RX_QSTATUS(("\nFREE RFB w/i BUF LIST :%9ld", + prRxCtrl->rFreeSwRfbList.u4NumElem)); + SPRINTF_RX_QSTATUS(("\nFREE RFB w/o BUF LIST :%9ld", + prRxCtrl->rIndicatedRfbList.u4NumElem)); + SPRINTF_RX_QSTATUS(("\nRECEIVED RFB LIST :%9ld", + prRxCtrl->rReceivedRfbList.u4NumElem)); + + SPRINTF_RX_QSTATUS(("\n\n")); + + /**pu4Count = (u32)((u32)pucCurrBuf - (u32)pucBuffer); */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Clear RX related counters + * + * @param prAdapter Pointer of Adapter Data Structure + * + * @return - (none) + */ +/*----------------------------------------------------------------------------*/ +void nicRxClearStatistics(IN P_ADAPTER_T prAdapter) +{ + P_RX_CTRL_T prRxCtrl; + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + RX_RESET_ALL_CNTS(prRxCtrl); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to query current statistics of RX Module. + * + * @param prAdapter Pointer to the Adapter structure. + * @param pucBuffer Pointer to the message buffer. + * @param pu4Count Pointer to the buffer of message length count. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicRxQueryStatistics(IN P_ADAPTER_T prAdapter, IN u8 *pucBuffer, + OUT u32 *pu4Count) +{ + P_RX_CTRL_T prRxCtrl; + u8 *pucCurrBuf = pucBuffer; + u32 u4CurrCount; + + ASSERT(prAdapter); + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + /* if (pucBuffer) {} */ /* For Windows, we'll print directly instead of + * sprintf() */ + ASSERT(pu4Count); + +#define SPRINTF_RX_COUNTER(eCounter) \ + { \ + u4CurrCount = scnprintf( \ + pucCurrBuf, *pu4Count, "%-30s : %ld\n", #eCounter, \ + (u32)prRxCtrl->au8Statistics[eCounter]); \ + pucCurrBuf += (u8)u4CurrCount; \ + *pu4Count -= u4CurrCount; \ + } + + SPRINTF_RX_COUNTER(RX_MPDU_TOTAL_COUNT); + SPRINTF_RX_COUNTER(RX_SIZE_ERR_DROP_COUNT); + SPRINTF_RX_COUNTER(RX_DATA_INDICATION_COUNT); + SPRINTF_RX_COUNTER(RX_DATA_RETURNED_COUNT); + SPRINTF_RX_COUNTER(RX_DATA_RETAINED_COUNT); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD || CFG_TCP_IP_CHKSUM_OFFLOAD_NDIS_60 + SPRINTF_RX_COUNTER(RX_CSUM_TCP_FAILED_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_UDP_FAILED_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_IP_FAILED_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_TCP_SUCCESS_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_UDP_SUCCESS_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_IP_SUCCESS_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_UNKNOWN_L4_PKT_COUNT); + SPRINTF_RX_COUNTER(RX_CSUM_UNKNOWN_L3_PKT_COUNT); + SPRINTF_RX_COUNTER(RX_IP_V6_PKT_CCOUNT); +#endif + + /**pu4Count = (u32)(pucCurrBuf - pucBuffer); */ + + nicRxClearStatistics(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Read the Response data from data port + * + * @param prAdapter pointer to the Adapter handler + * @param pucRspBuffer pointer to the Response buffer + * + * @retval WLAN_STATUS_SUCCESS: Response packet has been read + * @retval WLAN_STATUS_FAILURE: Read Response packet timeout or error occurred + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +nicRxWaitResponse(IN P_ADAPTER_T prAdapter, IN u8 ucPortIdx, + OUT u8 *pucRspBuffer, IN u32 u4MaxRespBufferLen, + OUT u32 *pu4Length) +{ + P_WIFI_EVENT_T prEvent; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + u4Status = halRxWaitResponse(prAdapter, ucPortIdx, pucRspBuffer, + u4MaxRespBufferLen, pu4Length); + if (u4Status == WLAN_STATUS_SUCCESS) { + DBGLOG(RX, TRACE, "Dump Response buffer, length = 0x%lx\n", + *pu4Length); + DBGLOG_MEM8(RX, TRACE, pucRspBuffer, *pu4Length); + + prEvent = (P_WIFI_EVENT_T)pucRspBuffer; + DBGLOG(INIT, TRACE, "RX EVENT: ID[0x%02X] SEQ[%u] LEN[%u]\n", + prEvent->ucEID, prEvent->ucSeqNum, + prEvent->u2PacketLength); + } else { + DBGLOG(RX, ERROR, "halRxWaitResponse fail!\n"); + } + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Set filter to enable Promiscuous Mode + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicRxEnablePromiscuousMode(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Set filter to disable Promiscuous Mode + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicRxDisablePromiscuousMode(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief this function flushes all packets queued in reordering module + * + * @param prAdapter Pointer to the Adapter structure. + * + * @retval WLAN_STATUS_SUCCESS Flushed successfully + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicRxFlush(IN P_ADAPTER_T prAdapter) +{ + P_SW_RFB_T prSwRfb; + + ASSERT(prAdapter); + prSwRfb = qmFlushRxQueues(prAdapter); + if (prSwRfb != NULL) { + do { + P_SW_RFB_T prNextSwRfb; + + /* save next first */ + prNextSwRfb = (P_SW_RFB_T)QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prSwRfb); + + /* free */ + nicRxReturnRFB(prAdapter, prSwRfb); + + prSwRfb = prNextSwRfb; + } while (prSwRfb); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param + * + * @retval + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicRxProcessActionFrame(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb) +{ + P_WLAN_ACTION_FRAME prActFrame; + P_BSS_INFO_T prBssInfo = NULL; +#if CFG_SUPPORT_802_11W + u8 fgRobustAction = false; + P_AIS_SPECIFIC_BSS_INFO_T prAisSpecBssInfo; +#endif + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + DBGLOG(RSN, TRACE, "[Rx] nicRxProcessActionFrame\n"); + + if (prSwRfb->u2PacketLen < sizeof(WLAN_ACTION_FRAME) - 1) { + return WLAN_STATUS_INVALID_PACKET; + } + + prActFrame = (P_WLAN_ACTION_FRAME)prSwRfb->pvHeader; + + DBGLOG(RSN, INFO, "Action frame category=%d\n", prActFrame->ucCategory); + +#if CFG_SUPPORT_802_11W + if ((prActFrame->ucCategory <= + CATEGORY_PROTECTED_DUAL_OF_PUBLIC_ACTION && + prActFrame->ucCategory != CATEGORY_PUBLIC_ACTION && + prActFrame->ucCategory != CATEGORY_HT_ACTION) /* At 11W spec Code 7 + * is reserved */ + || (prActFrame->ucCategory == + CATEGORY_VENDOR_SPECIFIC_ACTION_PROTECTED)) { + fgRobustAction = true; + } + /* DBGLOG(RSN, TRACE, ("[Rx] fgRobustAction=%d\n", fgRobustAction)); */ + + if (fgRobustAction && prSwRfb->prStaRec && + GET_BSS_INFO_BY_INDEX(prAdapter, prSwRfb->prStaRec->ucBssIndex) + ->eNetworkType == NETWORK_TYPE_AIS) { + prAisSpecBssInfo = &(prAdapter->rWifiVar.rAisSpecificBssInfo); + + DBGLOG(RSN, INFO, "[Rx]RobustAction %x %x %x\n", + prSwRfb->prRxStatus->u2StatusFlag, + prSwRfb->prRxStatus->ucWlanIdx, + prSwRfb->prRxStatus->ucTidSecMode); + + if (prAisSpecBssInfo->fgMgmtProtection && + (!(prActFrame->u2FrameCtrl & MASK_FC_PROTECTED_FRAME) && + (HAL_RX_STATUS_GET_SEC_MODE(prSwRfb->prRxStatus) == + CIPHER_SUITE_CCMP))) { + DBGLOG(RSN, + INFO, + "[MFP] Not handle and drop un-protected robust action frame!!\n"); + return WLAN_STATUS_INVALID_PACKET; + } + } + /* DBGLOG(RSN, INFO, "[Rx] pre check done, handle cateory %d\n", + * prActFrame->ucCategory); */ +#endif + + if (prSwRfb->prStaRec) { + prBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, prSwRfb->prStaRec->ucBssIndex); + } + + switch (prActFrame->ucCategory) { + case CATEGORY_PUBLIC_ACTION: + if (prAdapter->prAisBssInfo && prSwRfb->prStaRec && + prSwRfb->prStaRec->ucBssIndex == + prAdapter->prAisBssInfo->ucBssIndex) { + aisFuncValidateRxActionFrame(prAdapter, prSwRfb); + } + + if (prAdapter->prAisBssInfo && + prAdapter->prAisBssInfo->ucBssIndex == + KAL_NETWORK_TYPE_AIS_INDEX) { + aisFuncValidateRxActionFrame(prAdapter, prSwRfb); + } +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + rlmProcessPublicAction(prAdapter, prSwRfb); + if (prBssInfo) { + p2pFuncValidateRxActionFrame( + prAdapter, prSwRfb, + (prBssInfo->ucBssIndex == + P2P_DEV_BSS_INDEX), + (u8)prBssInfo->u4PrivateData); + } else { + p2pFuncValidateRxActionFrame(prAdapter, prSwRfb, + true, 0); + } + } +#endif + break; + + case CATEGORY_HT_ACTION: + rlmProcessHtAction(prAdapter, prSwRfb); + break; + + case CATEGORY_VENDOR_SPECIFIC_ACTION: +#if CFG_ENABLE_WIFI_DIRECT + if (prAdapter->fgIsP2PRegistered) { + if (prBssInfo) { + p2pFuncValidateRxActionFrame( + prAdapter, prSwRfb, + (prBssInfo->ucBssIndex == + P2P_DEV_BSS_INDEX), + (u8)prBssInfo->u4PrivateData); + } else { + p2pFuncValidateRxActionFrame(prAdapter, prSwRfb, + true, 0); + } + } +#endif + break; + +#if CFG_SUPPORT_802_11W + case CATEGORY_SA_QUERY_ACTION: { + P_BSS_INFO_T prBssInfo; + + if (prSwRfb->prStaRec) { + prBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, prSwRfb->prStaRec->ucBssIndex); + ASSERT(prBssInfo); + if ((prBssInfo->eNetworkType == NETWORK_TYPE_AIS) && + prAdapter->rWifiVar.rAisSpecificBssInfo + .fgMgmtProtection /* Use MFP */ ) { + /* MFP test plan 5.3.3.4 */ + rsnSaQueryAction(prAdapter, prSwRfb); + } else if ((prBssInfo->eNetworkType == + NETWORK_TYPE_P2P) && + (prBssInfo->eCurrentOPMode == + OP_MODE_ACCESS_POINT)) { + /* AP PMF */ + DBGLOG(RSN, INFO, + "[Rx] nicRx AP PMF SAQ action\n"); + if (rsnCheckBipKeyInstalled( + prAdapter, prSwRfb->prStaRec)) { + /* MFP test plan 4.3.3.4 */ + rsnApSaQueryAction(prAdapter, prSwRfb); + } + } + } + } break; + +#endif +#if CFG_SUPPORT_802_11V + case CATEGORY_WNM_ACTION: { + if (prSwRfb->prStaRec && + GET_BSS_INFO_BY_INDEX(prAdapter, + prSwRfb->prStaRec->ucBssIndex) + ->eNetworkType == NETWORK_TYPE_AIS) { + DBGLOG(RX, INFO, "WNM action frame: %d\n", __LINE__); + wnmWNMAction(prAdapter, prSwRfb); + } else { + DBGLOG(RX, INFO, "WNM action frame: %d\n", __LINE__); + } + } break; +#endif + +#if CFG_SUPPORT_DFS + case CATEGORY_SPEC_MGT: { + if (prAdapter->fgEnable5GBand) { + DBGLOG(RLM, INFO, + "[Channel Switch]nicRxProcessActionFrame\n"); + rlmProcessSpecMgtAction(prAdapter, prSwRfb); + } + } break; +#endif + +#if CFG_SUPPORT_802_11AC + case CATEGORY_VHT_ACTION: + rlmProcessVhtAction(prAdapter, prSwRfb); + break; +#endif + +#if CFG_SUPPORT_802_11K + case CATEGORY_RM_ACTION: + switch (prActFrame->ucAction) { + case RM_ACTION_RM_REQUEST: + // rlmProcessRadioMeasurementRequest(prAdapter, + // prSwRfb); + break; + + case RM_ACTION_REIGHBOR_RESPONSE: + rlmProcessNeighborReportResponse(prAdapter, prActFrame, + prSwRfb->u2PacketLen); + break; + } + break; + +#endif + default: + break; + } /* end of switch case */ + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param + * + * @retval + */ +/*----------------------------------------------------------------------------*/ +u8 nicRxGetRcpiValueFromRxv(IN u8 ucRcpiMode, IN P_SW_RFB_T prSwRfb) +{ + u8 ucRcpi0, ucRcpi1; + u8 ucRcpiValue = 0; + u8 ucRxNum; + + ASSERT(prSwRfb); + + if (ucRcpiMode >= RCPI_MODE_NUM) { + DBGLOG(RX, + WARN, + "Rcpi Mode = %d is invalid for getting RCPI value from RXV\n", + ucRcpiMode); + return 0; + } + + ucRcpi0 = HAL_RX_STATUS_GET_RCPI0(prSwRfb->prRxStatusGroup3); + ucRcpi1 = HAL_RX_STATUS_GET_RCPI1(prSwRfb->prRxStatusGroup3); + ucRxNum = HAL_RX_STATUS_GET_RX_NUM(prSwRfb->prRxStatusGroup3); + + if (ucRxNum == 0) { + ucRcpiValue = ucRcpi0; /*0:1R, BBP always report RCPI0 at 1R + * mode*/ + } else if (ucRxNum == 1) { + switch (ucRcpiMode) { + case RCPI_MODE_WF0: + ucRcpiValue = ucRcpi0; + break; + + case RCPI_MODE_WF1: + ucRcpiValue = ucRcpi1; + break; + + case RCPI_MODE_WF2: + case RCPI_MODE_WF3: + DBGLOG(RX, + WARN, + "Rcpi Mode = %d is invalid for device with only 2 antenna\n", + ucRcpiMode); + break; + + case RCPI_MODE_AVG: /*Not recommended for CBW80+80*/ + ucRcpiValue = (ucRcpi0 + ucRcpi1) / 2; + break; + + case RCPI_MODE_MAX: + ucRcpiValue = (ucRcpi0 > ucRcpi1) ? (ucRcpi0) : + (ucRcpi1); + break; + + case RCPI_MODE_MIN: + ucRcpiValue = (ucRcpi0 < ucRcpi1) ? (ucRcpi0) : + (ucRcpi1); + break; + + default: + break; + } + } else { + DBGLOG(RX, + WARN, + "RX_NUM = %d is invalid for getting RCPI value from RXV\n", + ucRxNum); + return 0; + } + + return ucRcpiValue; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_tx.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_tx.c new file mode 100644 index 00000000000000..6599e3a82c2e51 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_tx.c @@ -0,0 +1,4578 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file nic_tx.c + * \brief Functions that provide TX operation in NIC Layer. + * + * This file provides TX functions which are responsible for both Hardware + * and Software Resource Management and keep their Synchronization. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#include "que_mgt.h" + +#ifdef UDP_SKT_WIFI +#include <linux/ftrace_event.h> +#endif + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +PFN_TX_DATA_DONE_CB g_pfTxDataDoneCb = nicTxMsduDoneCb; + +static const TX_RESOURCE_CONTROL_T arTcResourceControl[TC_NUM] = { + /* dest port index, dest queue index, HIF TX queue index */ + /* First HW queue */ + { PORT_INDEX_LMAC, MAC_TXQ_AC0_INDEX, HIF_TX_AC0_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC1_INDEX, HIF_TX_AC1_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC2_INDEX, HIF_TX_AC2_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC3_INDEX, HIF_TX_AC3_INDEX }, + { PORT_INDEX_MCU, MCU_Q1_INDEX, HIF_TX_CPU_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC1_INDEX, HIF_TX_AC1_INDEX }, + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + { PORT_INDEX_LMAC, MAC_TXQ_AC10_INDEX, HIF_TX_AC10_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC11_INDEX, HIF_TX_AC11_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC12_INDEX, HIF_TX_AC12_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC13_INDEX, HIF_TX_AC13_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC11_INDEX, HIF_TX_AC11_INDEX }, + + { PORT_INDEX_LMAC, MAC_TXQ_AC20_INDEX, HIF_TX_AC20_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC21_INDEX, HIF_TX_AC21_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC22_INDEX, HIF_TX_AC22_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC23_INDEX, HIF_TX_AC23_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC21_INDEX, HIF_TX_AC21_INDEX }, + + { PORT_INDEX_LMAC, MAC_TXQ_AC30_INDEX, HIF_TX_AC3X_INDEX }, +#endif + +#if NIC_TX_ENABLE_SECOND_HW_QUEUE + /* Second HW queue */ + { PORT_INDEX_LMAC, MAC_TXQ_AC10_INDEX, HIF_TX_AC10_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC11_INDEX, HIF_TX_AC11_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC12_INDEX, HIF_TX_AC12_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC13_INDEX, HIF_TX_AC13_INDEX }, + { PORT_INDEX_LMAC, MAC_TXQ_AC11_INDEX, HIF_TX_AC11_INDEX }, +#endif +}; + +/* Traffic settings per TC */ +static const TX_TC_TRAFFIC_SETTING_T arTcTrafficSettings[NET_TC_NUM] = { + /* Tx desc template format, Remaining Tx time, Retry + * count */ + /* For Data frame with StaRec, set Long Format to enable the following + * settings */ + { NIC_TX_DESC_LONG_FORMAT_LENGTH, NIC_TX_AC_BE_REMAINING_TX_TIME, + NIC_TX_DATA_DEFAULT_RETRY_COUNT_LIMIT }, + { NIC_TX_DESC_LONG_FORMAT_LENGTH, NIC_TX_AC_BK_REMAINING_TX_TIME, + NIC_TX_DATA_DEFAULT_RETRY_COUNT_LIMIT }, + { NIC_TX_DESC_LONG_FORMAT_LENGTH, NIC_TX_AC_VI_REMAINING_TX_TIME, + NIC_TX_DATA_DEFAULT_RETRY_COUNT_LIMIT }, + { NIC_TX_DESC_LONG_FORMAT_LENGTH, NIC_TX_AC_VO_REMAINING_TX_TIME, + NIC_TX_DATA_DEFAULT_RETRY_COUNT_LIMIT }, + + /* MGMT frame */ + { NIC_TX_DESC_LONG_FORMAT_LENGTH, NIC_TX_MGMT_REMAINING_TX_TIME, + NIC_TX_MGMT_DEFAULT_RETRY_COUNT_LIMIT }, + + /* non-StaRec frame (BMC, etc...) */ + { NIC_TX_DESC_LONG_FORMAT_LENGTH, TX_DESC_TX_TIME_NO_LIMIT, + NIC_TX_DATA_DEFAULT_RETRY_COUNT_LIMIT }, +}; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will initial all variables in regard to SW TX Queues and + * all free lists of MSDU_INFO_T and SW_TFCB_T. + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicTxInitialize(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + u8 *pucMemHandle; + P_MSDU_INFO_T prMsduInfo; + u32 i; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicTxInitialize"); + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + /* 4 <1> Initialization of Traffic Class Queue Parameters */ + nicTxResetResource(prAdapter); + + prTxCtrl->pucTxCoalescingBufPtr = prAdapter->pucCoalescingBufCached; + + prTxCtrl->u4WrIdx = 0; + + /* allocate MSDU_INFO_T and link it into rFreeMsduInfoList */ + QUEUE_INITIALIZE(&prTxCtrl->rFreeMsduInfoList); + + pucMemHandle = prTxCtrl->pucTxCached; + for (i = 0; i < CFG_TX_MAX_PKT_NUM; i++) { + prMsduInfo = (P_MSDU_INFO_T)pucMemHandle; + kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T)); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, + (P_QUE_ENTRY_T)prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + + pucMemHandle += ALIGN_4(sizeof(MSDU_INFO_T)); + } + + ASSERT(prTxCtrl->rFreeMsduInfoList.u4NumElem == CFG_TX_MAX_PKT_NUM); + /* Check if the memory allocation consist with this initialization + * function */ + ASSERT((u32)(pucMemHandle - prTxCtrl->pucTxCached) == + prTxCtrl->u4TxCachedSize); + + QUEUE_INITIALIZE(&prTxCtrl->rTxMgmtTxingQueue); + prTxCtrl->i4TxMgmtPendingNum = 0; + +#if CFG_HIF_STATISTICS + prTxCtrl->u4TotalTxAccessNum = 0; + prTxCtrl->u4TotalTxPacketNum = 0; +#endif + + prTxCtrl->i4PendingFwdFrameCount = 0; + + /* Assign init value */ + /* Tx sequence number */ + prAdapter->ucTxSeqNum = 0; + /* PID pool */ + for (i = 0; i < WTBL_SIZE; i++) + prAdapter->aucPidPool[i] = NIC_TX_DESC_DRIVER_PID_MIN; + + prTxCtrl->u4PageSize = NIC_TX_PAGE_SIZE; + + /* enable/disable TX resource control */ + prTxCtrl->fgIsTxResourceCtrl = NIC_TX_RESOURCE_CTRL; + + qmInit(prAdapter, halIsTxResourceControlEn(prAdapter)); + + TX_RESET_ALL_CNTS(prTxCtrl); +} + +u8 nicTxSanityCheckResource(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + u8 ucTC; + u32 ucTotalMaxResource = 0; + u32 ucTotalFreeResource = 0; + u8 fgError = false; + + if (prAdapter->rWifiVar.ucTxDbg & BIT(0)) { + prTxCtrl = &prAdapter->rTxCtrl; + + for (ucTC = TC0_INDEX; ucTC < TC_NUM; ucTC++) { + ucTotalMaxResource += + prTxCtrl->rTc.au4MaxNumOfPage[ucTC]; + ucTotalFreeResource += + prTxCtrl->rTc.au4FreePageCount[ucTC]; + + if (prTxCtrl->rTc.au4FreePageCount[ucTC] > + prTxCtrl->u4TotalPageNum) { + DBGLOG(TX, ERROR, "%s:%u\n error\n", __func__, + __LINE__); + fgError = true; + } + + if (prTxCtrl->rTc.au4MaxNumOfPage[ucTC] > + prTxCtrl->u4TotalPageNum) { + DBGLOG(TX, ERROR, "%s:%u\n error\n", __func__, + __LINE__); + fgError = true; + } + + if (prTxCtrl->rTc.au4FreePageCount[ucTC] > + prTxCtrl->rTc.au4MaxNumOfPage[ucTC]) { + DBGLOG(TX, ERROR, "%s:%u\n error\n", __func__, + __LINE__); + fgError = true; + } + } + + if (ucTotalMaxResource != prTxCtrl->u4TotalPageNum) { + DBGLOG(TX, ERROR, "%s:%u\n error\n", __func__, + __LINE__); + fgError = true; + } + + if (ucTotalMaxResource < ucTotalFreeResource) { + DBGLOG(TX, ERROR, "%s:%u\n error\n", __func__, + __LINE__); + fgError = true; + } + + if (ucTotalFreeResource > prTxCtrl->u4TotalPageNum) { + DBGLOG(TX, ERROR, "%s:%u\n error\n", __func__, + __LINE__); + fgError = true; + } + + if (fgError) { + DBGLOG(TX, ERROR, "Total resource[%u]\n", + prTxCtrl->u4TotalPageNum); + qmDumpQueueStatus(prAdapter, NULL, 0); + } + } + + return !fgError; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Driver maintain a variable that is synchronous with the usage of + * individual TC Buffer Count. This function will check if has enough TC Buffer + * for incoming packet and then update the value after promise to provide the + * resources. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] ucTC Specify the resource of TC + * + * \retval WLAN_STATUS_SUCCESS Resource is available and been assigned. + * \retval WLAN_STATUS_RESOURCES Resource is not available. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxAcquireResource(IN P_ADAPTER_T prAdapter, IN u8 ucTC, + IN u8 fgReqLock) +{ + P_TX_CTRL_T prTxCtrl; + P_TX_TCQ_STATUS_T prTc; + WLAN_STATUS u4Status = WLAN_STATUS_RESOURCES; + + KAL_SPIN_LOCK_DECLARATION(); + + /* enable/disable TX resource control */ + if (!prAdapter->rTxCtrl.fgIsTxResourceCtrl) { + return WLAN_STATUS_SUCCESS; + } + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + prTc = &prTxCtrl->rTc; + + if (fgReqLock) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + } + + if (prTc->au4FreePageCount[ucTC] >= 1) { + prTc->au4FreePageCount[ucTC] -= 1; + prTc->au4FreeBufferCount[ucTC] = (prTc->au4FreePageCount[ucTC] / + NIC_TX_MAX_PAGE_PER_FRAME); + + DBGLOG(TX, + LOUD, + "Acquire: TC%d AcquirePageCnt[%u] FreeBufferCnt[%u] FreePageCnt[%u]\n", + ucTC, + 1, + prTc->au4FreeBufferCount[ucTC], + prTc->au4FreePageCount[ucTC]); + + u4Status = WLAN_STATUS_SUCCESS; + } + + if (fgReqLock) { + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + } + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Driver maintain a variable that is synchronous with the usage of + * individual TC Buffer Count. This function will do polling if FW has return + * the resource. Used when driver start up before enable interrupt. + * + * @param prAdapter Pointer to the Adapter structure. + * @param ucTC Specify the resource of TC + * + * @retval WLAN_STATUS_SUCCESS Resource is available. + * @retval WLAN_STATUS_FAILURE Resource is not available. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxPollingResource(IN P_ADAPTER_T prAdapter, IN u8 ucTC) +{ + P_TX_CTRL_T prTxCtrl; + WLAN_STATUS u4Status = WLAN_STATUS_FAILURE; + s32 i = NIC_TX_RESOURCE_POLLING_TIMEOUT; + /*u32 au4WTSR[8];*/ + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + if (ucTC >= TC_NUM) { + return WLAN_STATUS_FAILURE; + } + + if (prTxCtrl->rTc.au4FreeBufferCount[ucTC] > 0) { + return WLAN_STATUS_SUCCESS; + } + + while (i-- > 0) { + u4Status = halTxPollingResource(prAdapter, ucTC); + if (u4Status == WLAN_STATUS_RESOURCES) { + kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC); + }else{ + break; + } + } + +#if DBG + { + s32 i4Times = NIC_TX_RESOURCE_POLLING_TIMEOUT - (i + 1); + + if (i4Times) { + DBGLOG(TX, TRACE, + "Polling MCR_WTSR delay %ld times, %ld msec\n", + i4Times, + (i4Times * NIC_TX_RESOURCE_POLLING_DELAY_MSEC)); + } + } +#endif + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Driver maintain a variable that is synchronous with the usage of + * individual TC Buffer Count. This function will release TC Buffer count + * according to the given TX_STATUS COUNTER after TX Done. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +u8 nicTxReleaseResource(IN P_ADAPTER_T prAdapter, IN u8 ucTc, + IN u32 u4PageCount, IN u8 fgReqLock) +{ + P_TX_TCQ_STATUS_T prTcqStatus; + u8 bStatus = false; + + KAL_SPIN_LOCK_DECLARATION(); + + /* enable/disable TX resource control */ + if (!prAdapter->rTxCtrl.fgIsTxResourceCtrl) { + return true; + } + + ASSERT(prAdapter); + prTcqStatus = &prAdapter->rTxCtrl.rTc; + + /* Return free Tc page count */ + if (fgReqLock) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + } + + prTcqStatus->au4FreePageCount[ucTc] += u4PageCount; + prTcqStatus->au4FreeBufferCount[ucTc] = + (prTcqStatus->au4FreePageCount[ucTc] / + NIC_TX_MAX_PAGE_PER_FRAME); + + if (fgReqLock) { + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + } + + bStatus = true; + + return bStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Driver maintain a variable that is synchronous with the usage of + * individual TC Buffer Count. This function will release TC Buffer count for + * resource allocated but un-Tx MSDU_INFO + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicTxReleaseMsduResource(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead) +{ + P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead, prNextMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + while (prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prMsduInfo); + + nicTxReleaseResource(prAdapter, prMsduInfo->ucTC, 1, false); + + prMsduInfo = prNextMsduInfo; + } + ; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Reset TC Buffer Count to initialized value + * + * \param[in] prAdapter Pointer to the Adapter structure. + * + * @return WLAN_STATUS_SUCCESS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxResetResource(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + u8 ucIdx; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("nicTxResetResource"); + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + /* Delta page count */ + kalMemZero(prTxCtrl->rTc.au4TxDonePageCount, + sizeof(prTxCtrl->rTc.au4TxDonePageCount)); + kalMemZero(prTxCtrl->rTc.au4PreUsedPageCount, + sizeof(prTxCtrl->rTc.au4PreUsedPageCount)); + + prTxCtrl->rTc.ucNextTcIdx = TC0_INDEX; + prTxCtrl->rTc.u4AvaliablePageCount = 0; + + DBGLOG(TX, TRACE, "Default TCQ free resource [%u %u %u %u %u %u]\n", + prAdapter->rWifiVar.au4TcPageCount[TC0_INDEX], + prAdapter->rWifiVar.au4TcPageCount[TC1_INDEX], + prAdapter->rWifiVar.au4TcPageCount[TC2_INDEX], + prAdapter->rWifiVar.au4TcPageCount[TC3_INDEX], + prAdapter->rWifiVar.au4TcPageCount[TC4_INDEX], + prAdapter->rWifiVar.au4TcPageCount[TC5_INDEX]); + + prAdapter->rTxCtrl.u4TotalPageNum = 0; + prAdapter->rTxCtrl.u4TotalTxRsvPageNum = 0; + + for (ucIdx = TC0_INDEX; ucIdx < TC_NUM; ucIdx++) { + /* Page Count */ + prTxCtrl->rTc.au4MaxNumOfPage[ucIdx] = + prAdapter->rWifiVar.au4TcPageCount[ucIdx]; + prTxCtrl->rTc.au4FreePageCount[ucIdx] = + prAdapter->rWifiVar.au4TcPageCount[ucIdx]; + + DBGLOG(TX, TRACE, "Set TC%u Default[%u] Max[%u] Free[%u]\n", + ucIdx, prAdapter->rWifiVar.au4TcPageCount[ucIdx], + prTxCtrl->rTc.au4MaxNumOfPage[ucIdx], + prTxCtrl->rTc.au4FreePageCount[ucIdx]); + + /* Buffer count */ + prTxCtrl->rTc.au4MaxNumOfBuffer[ucIdx] = + (prTxCtrl->rTc.au4MaxNumOfPage[ucIdx] / + NIC_TX_MAX_PAGE_PER_FRAME); + prTxCtrl->rTc.au4FreeBufferCount[ucIdx] = + (prTxCtrl->rTc.au4FreePageCount[ucIdx] / + NIC_TX_MAX_PAGE_PER_FRAME); + + DBGLOG(TX, TRACE, + "Set TC%u Default[%u] Buffer Max[%u] Free[%u]\n", ucIdx, + prAdapter->rWifiVar.au4TcPageCount[ucIdx], + prTxCtrl->rTc.au4MaxNumOfBuffer[ucIdx], + prTxCtrl->rTc.au4FreeBufferCount[ucIdx]); + + prAdapter->rTxCtrl.u4TotalPageNum += + prTxCtrl->rTc.au4MaxNumOfPage[ucIdx]; + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + DBGLOG(TX, + TRACE, + "Reset TCQ free resource to Page:Buf [%u:%u %u:%u %u:%u %u:%u %u:%u %u:%u ]\n", + prTxCtrl->rTc.au4FreePageCount[TC0_INDEX], + prTxCtrl->rTc.au4FreeBufferCount[TC0_INDEX], + prTxCtrl->rTc.au4FreePageCount[TC1_INDEX], + prTxCtrl->rTc.au4FreeBufferCount[TC1_INDEX], + prTxCtrl->rTc.au4FreePageCount[TC2_INDEX], + prTxCtrl->rTc.au4FreeBufferCount[TC2_INDEX], + prTxCtrl->rTc.au4FreePageCount[TC3_INDEX], + prTxCtrl->rTc.au4FreeBufferCount[TC3_INDEX], + prTxCtrl->rTc.au4FreePageCount[TC4_INDEX], + prTxCtrl->rTc.au4FreeBufferCount[TC4_INDEX], + prTxCtrl->rTc.au4FreePageCount[TC5_INDEX], + prTxCtrl->rTc.au4FreeBufferCount[TC5_INDEX]); + + DBGLOG(TX, + TRACE, + "Reset TCQ MAX resource to Page:Buf [%u:%u %u:%u %u:%u %u:%u %u:%u %u:%u]\n", + prTxCtrl->rTc.au4MaxNumOfPage[TC0_INDEX], + prTxCtrl->rTc.au4MaxNumOfBuffer[TC0_INDEX], + prTxCtrl->rTc.au4MaxNumOfPage[TC1_INDEX], + prTxCtrl->rTc.au4MaxNumOfBuffer[TC1_INDEX], + prTxCtrl->rTc.au4MaxNumOfPage[TC2_INDEX], + prTxCtrl->rTc.au4MaxNumOfBuffer[TC2_INDEX], + prTxCtrl->rTc.au4MaxNumOfPage[TC3_INDEX], + prTxCtrl->rTc.au4MaxNumOfBuffer[TC3_INDEX], + prTxCtrl->rTc.au4MaxNumOfPage[TC4_INDEX], + prTxCtrl->rTc.au4MaxNumOfBuffer[TC4_INDEX], + prTxCtrl->rTc.au4MaxNumOfPage[TC5_INDEX], + prTxCtrl->rTc.au4MaxNumOfBuffer[TC5_INDEX]); + + return WLAN_STATUS_SUCCESS; +} + +#if QM_FAST_TC_RESOURCE_CTRL +u32 nicTxGetAdjustableResourceCnt(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + u8 ucIdx; + u32 u4TotAdjCnt = 0; + u32 u4AdjCnt; + P_QUE_MGT_T prQm = NULL; + + prQm = &prAdapter->rQM; + prTxCtrl = &prAdapter->rTxCtrl; + + for (ucIdx = TC0_INDEX; ucIdx < TC_NUM; ucIdx++) { + if (ucIdx == TC4_INDEX) { + continue; + } + + if (prTxCtrl->rTc.au4FreeBufferCount[ucIdx] > + prQm->au4MinReservedTcResource[ucIdx]) { + u4AdjCnt = prTxCtrl->rTc.au4FreeBufferCount[ucIdx] - + prQm->au4MinReservedTcResource[ucIdx]; + } else { + u4AdjCnt = 0; + } + + u4TotAdjCnt += u4AdjCnt; + } + + return u4TotAdjCnt; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Driver maintain a variable that is synchronous with the usage of + * individual TC Buffer Count. This function will return the value for other + * component which needs this information for making decisions + * + * @param prAdapter Pointer to the Adapter structure. + * @param ucTC Specify the resource of TC + * + * @retval u8 The number of corresponding TC number + */ +/*----------------------------------------------------------------------------*/ +u16 nicTxGetResource(IN P_ADAPTER_T prAdapter, IN u8 ucTC) +{ + P_TX_CTRL_T prTxCtrl; + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + ASSERT(prTxCtrl); + + if (ucTC >= TC_NUM) { + return 0; + }else{ + return prTxCtrl->rTc.au4FreePageCount[ucTC]; + } +} + +u8 nicTxGetFrameResourceType(IN u8 eFrameType, IN P_MSDU_INFO_T prMsduInfo) +{ + u8 ucTC; + + switch (eFrameType) { + case FRAME_TYPE_802_1X: + ucTC = TC4_INDEX; + break; + + case FRAME_TYPE_MMPDU: + if (prMsduInfo) { + ucTC = prMsduInfo->ucTC; + }else{ + ucTC = TC4_INDEX; + } + break; + + default: + DBGLOG(INIT, WARN, "Undefined Frame Type(%u)\n", eFrameType); + ucTC = TC4_INDEX; + break; + } + + return ucTC; +} + +u8 nicTxGetCmdResourceType(IN P_CMD_INFO_T prCmdInfo) +{ + u8 ucTC; + + switch (prCmdInfo->eCmdType) { + case COMMAND_TYPE_NETWORK_IOCTL: + case COMMAND_TYPE_GENERAL_IOCTL: + ucTC = TC4_INDEX; + break; + + case COMMAND_TYPE_SECURITY_FRAME: + ucTC = nicTxGetFrameResourceType(FRAME_TYPE_802_1X, NULL); + break; + + case COMMAND_TYPE_MANAGEMENT_FRAME: + ucTC = nicTxGetFrameResourceType(FRAME_TYPE_MMPDU, + prCmdInfo->prMsduInfo); + break; + + default: + DBGLOG(INIT, WARN, "Undefined CMD Type(%u)\n", + prCmdInfo->eCmdType); + ucTC = TC4_INDEX; + break; + } + + return ucTC; +} + +u8 nicTxGetTxQByTc(IN P_ADAPTER_T prAdapter, IN u8 ucTc) +{ + return arTcResourceControl[ucTc].ucHifTxQIndex; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief In this function, we'll aggregate frame(PACKET_INFO_T) + * corresponding to HIF TX port + * + * @param prAdapter Pointer to the Adapter structure. + * @param prMsduInfoListHead a link list of P_MSDU_INFO_T + * + * @retval WLAN_STATUS_SUCCESS Bus access ok. + * @retval WLAN_STATUS_FAILURE Bus access fail. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxMsduInfoList(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead) +{ + P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; + QUE_T qDataPort0, qDataPort1; + P_QUE_T prDataPort0, prDataPort1; + WLAN_STATUS status; + + ASSERT(prAdapter); + ASSERT(prMsduInfoListHead); + + prMsduInfo = prMsduInfoListHead; + + prDataPort0 = &qDataPort0; + prDataPort1 = &qDataPort1; + + QUEUE_INITIALIZE(prDataPort0); + QUEUE_INITIALIZE(prDataPort1); + + /* Separate MSDU_INFO_T lists into 2 categories: for Port#0 & Port#1 */ + while (prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prMsduInfo); + + switch (prMsduInfo->ucTC) { + case TC0_INDEX: + case TC1_INDEX: + case TC2_INDEX: + case TC3_INDEX: + case TC5_INDEX: /* Broadcast/multicast data packets */ + QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo) = NULL; + QUEUE_INSERT_TAIL(prDataPort0, + (P_QUE_ENTRY_T)prMsduInfo); + status = nicTxAcquireResource(prAdapter, + prMsduInfo->ucTC, true); + ASSERT(status == WLAN_STATUS_SUCCESS); + + break; + + case TC4_INDEX: /* Management packets */ + QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo) = NULL; + QUEUE_INSERT_TAIL(prDataPort1, + (P_QUE_ENTRY_T)prMsduInfo); + + status = nicTxAcquireResource(prAdapter, + prMsduInfo->ucTC, true); + ASSERT(status == WLAN_STATUS_SUCCESS); + + break; + + default: + ASSERT(0); + break; + } + + prMsduInfo = prNextMsduInfo; + } + + if (prDataPort0->u4NumElem > 0) { + nicTxMsduQueue(prAdapter, 0, prDataPort0); + } + + if (prDataPort1->u4NumElem > 0) { + nicTxMsduQueue(prAdapter, 1, prDataPort1); + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief In this function, we'll drop invalid MsduInfo and + * dump some debug log + * + * @param prAdapter Pointer to the Adapter structure. + * @param prMsduInfo Pointer of the invalid MsduInfo + * + */ +/*----------------------------------------------------------------------------*/ +void nicTxDropInvalidMsduInfo(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + /* Dump mem for debugging */ + DBGLOG(TX, ERROR, "[B] Dump invalid prMsduInfo & StaRec.\n"); + nicDumpMsduInfo(prMsduInfo); + cnmDumpStaRec(prAdapter, prMsduInfo->ucStaRecIndex); + DBGLOG(TX, ERROR, "[E] Dump invalid prMsduInfo & StaRec.\n"); + + TX_INC_CNT(&prAdapter->rTxCtrl, TX_INVALID_MSDUINFO_COUNT); + if (prMsduInfo->ucPacketType == TX_PACKET_TYPE_DATA) { + if (prMsduInfo->pfTxDoneHandler) { + prMsduInfo->pfTxDoneHandler( + prAdapter, prMsduInfo, + TX_RESULT_DROPPED_IN_DRIVER); + } + } + + /* Remove next link */ + QM_TX_SET_NEXT_MSDU_INFO(prMsduInfo, NULL); + + /* Release Tx resource */ + nicTxReleaseResource(prAdapter, prMsduInfo->ucTC, 1, true); + nicTxFreePacket(prAdapter, prMsduInfo, true); + nicTxReturnMsduInfo(prAdapter, prMsduInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief In this function, we'll aggregate frame(PACKET_INFO_T) + * corresponding to HIF TX port + * + * @param prAdapter Pointer to the Adapter structure. + * @param prMsduInfoListHead a link list of P_MSDU_INFO_T + * + * @retval WLAN_STATUS_SUCCESS Bus access ok. + * @retval WLAN_STATUS_FAILURE Bus access fail. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxMsduInfoListMthread(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead) +{ +#if CFG_FIX_2_TX_PORT + P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; + QUE_T qDataPort0, qDataPort1; + P_QUE_T prDataPort0, prDataPort1; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prMsduInfoListHead); + + prMsduInfo = prMsduInfoListHead; + + prDataPort0 = &qDataPort0; + prDataPort1 = &qDataPort1; + + QUEUE_INITIALIZE(prDataPort0); + QUEUE_INITIALIZE(prDataPort1); + + /* Separate MSDU_INFO_T lists into 2 categories: for Port#0 & Port#1 */ + while (prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prMsduInfo); + + nicTxFillDataDesc(prAdapter, prMsduInfo); + + /* Drop invalid MsduInfo */ + if (unlikely(prMsduInfo->fgDrop)) { + nicTxDropInvalidMsduInfo(prAdapter, prMsduInfo); + prMsduInfo = prNextMsduInfo; + continue; + } + + switch (prMsduInfo->ucTC) { + case TC0_INDEX: + case TC1_INDEX: + case TC2_INDEX: + case TC3_INDEX: + case TC5_INDEX: /* Broadcast/multicast data packets */ + QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo) = NULL; + QUEUE_INSERT_TAIL(prDataPort0, + (P_QUE_ENTRY_T)prMsduInfo); + break; + + case TC4_INDEX: /* Management packets */ + QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo) = NULL; + QUEUE_INSERT_TAIL(prDataPort1, + (P_QUE_ENTRY_T)prMsduInfo); + break; + + default: + ASSERT(0); + break; + } + + nicTxFillDataDesc(prAdapter, prMsduInfo); + + prMsduInfo = prNextMsduInfo; + } + + if (prDataPort0->u4NumElem > 0 || prDataPort1->u4NumElem > 0) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); + QUEUE_CONCATENATE_QUEUES((&(prAdapter->rTxP0Queue)), + (prDataPort0)); + QUEUE_CONCATENATE_QUEUES((&(prAdapter->rTxP1Queue)), + (prDataPort1)); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); + + kalSetTxEvent2Hif(prAdapter->prGlueInfo); + } +#else + P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; + QUE_T qDataPort[TX_PORT_NUM]; + P_QUE_T prDataPort[TX_PORT_NUM]; + s32 i; + u8 fgSetTx2Hif = false; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prMsduInfoListHead); + + prMsduInfo = prMsduInfoListHead; + + for (i = 0; i < TX_PORT_NUM; i++) { + prDataPort[i] = &qDataPort[i]; + QUEUE_INITIALIZE(prDataPort[i]); + } + + /* Separate MSDU_INFO_T lists into 2 categories: for Port#0 & Port#1 */ + while (prMsduInfo) { + fgSetTx2Hif = true; + prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prMsduInfo); + + if (prMsduInfo->ucWmmQueSet != 0 /*DBDC_5G_WMM_INDEX*/) { + QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo) = NULL; + QUEUE_INSERT_TAIL(prDataPort[TX_2G_WMM_PORT_NUM], + (P_QUE_ENTRY_T)prMsduInfo); + } else { + if (prMsduInfo->ucTC >= 0 && + prMsduInfo->ucTC < TC_NUM) { + QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prMsduInfo) = NULL; + QUEUE_INSERT_TAIL(prDataPort[prMsduInfo->ucTC], + (P_QUE_ENTRY_T)prMsduInfo); + } else { + ASSERT(0); + } + } + nicTxFillDataDesc(prAdapter, prMsduInfo); + + /* Drop invalid MsduInfo */ + if (unlikely(prMsduInfo->fgDrop)) { + nicTxDropInvalidMsduInfo(prAdapter, prMsduInfo); + prMsduInfo = prNextMsduInfo; + continue; + } + + prMsduInfo = prNextMsduInfo; + } + + if (fgSetTx2Hif) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); + for (i = 0; i < TX_PORT_NUM; i++) + QUEUE_CONCATENATE_QUEUES((&(prAdapter->rTxPQueue[i])), + (prDataPort[i])); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); + kalSetTxEvent2Hif(prAdapter->prGlueInfo); + } +#endif + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief In this function, we'll write frame(PACKET_INFO_T) into HIF when apply + * multithread. + * + * @param prAdapter Pointer to the Adapter structure. + * + * @retval WLAN_STATUS_SUCCESS Bus access ok. + * @retval WLAN_STATUS_FAILURE Bus access fail. + */ +/*----------------------------------------------------------------------------*/ +u32 nicTxMsduQueueMthread(IN P_ADAPTER_T prAdapter) +{ +#if CFG_FIX_2_TX_PORT + QUE_T qDataPort0, qDataPort1; + P_QUE_T prDataPort0, prDataPort1; + u32 u4TxLoopCount; + + KAL_SPIN_LOCK_DECLARATION(); + + prDataPort0 = &qDataPort0; + prDataPort1 = &qDataPort1; + + QUEUE_INITIALIZE(prDataPort0); + QUEUE_INITIALIZE(prDataPort1); + + u4TxLoopCount = prAdapter->rWifiVar.u4HifTxloopCount; + + while (u4TxLoopCount--) { + while (QUEUE_IS_NOT_EMPTY(&(prAdapter->rTxP0Queue))) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); + QUEUE_MOVE_ALL(prDataPort0, &(prAdapter->rTxP0Queue)); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); + + nicTxMsduQueue(prAdapter, 0, prDataPort0); + + if (QUEUE_IS_NOT_EMPTY(prDataPort0)) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TX_PORT_QUE); + QUEUE_CONCATENATE_QUEUES_HEAD( + &(prAdapter->rTxP0Queue), prDataPort0); + KAL_RELEASE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TX_PORT_QUE); + + break; + } + } + + while (QUEUE_IS_NOT_EMPTY(&(prAdapter->rTxP1Queue))) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); + QUEUE_MOVE_ALL(prDataPort1, &(prAdapter->rTxP1Queue)); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); + + nicTxMsduQueue(prAdapter, 1, prDataPort1); + + if (QUEUE_IS_NOT_EMPTY(prDataPort1)) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TX_PORT_QUE); + QUEUE_CONCATENATE_QUEUES_HEAD( + &(prAdapter->rTxP1Queue), prDataPort1); + KAL_RELEASE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TX_PORT_QUE); + + break; + } + } + } +#else + u32 u4TxLoopCount; + QUE_T qDataPort[TX_PORT_NUM]; + P_QUE_T prDataPort[TX_PORT_NUM]; + s32 i; + + KAL_SPIN_LOCK_DECLARATION(); + + for (i = 0; i < TX_PORT_NUM; i++) { + prDataPort[i] = &qDataPort[i]; + QUEUE_INITIALIZE(prDataPort[i]); + } + + u4TxLoopCount = prAdapter->rWifiVar.u4HifTxloopCount; + + while (u4TxLoopCount--) { + for (i = TC_NUM; i >= 0; i--) { + while (QUEUE_IS_NOT_EMPTY(&(prAdapter->rTxPQueue[i]))) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TX_PORT_QUE); + QUEUE_MOVE_ALL(prDataPort[i], + &(prAdapter->rTxPQueue[i])); + KAL_RELEASE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TX_PORT_QUE); + + nicTxMsduQueue(prAdapter, 0, prDataPort[i]); + + if (QUEUE_IS_NOT_EMPTY(prDataPort[i])) { + KAL_ACQUIRE_SPIN_LOCK( + prAdapter, + SPIN_LOCK_TX_PORT_QUE); + QUEUE_CONCATENATE_QUEUES_HEAD( + &(prAdapter->rTxPQueue[i]), + prDataPort[i]); + KAL_RELEASE_SPIN_LOCK( + prAdapter, + SPIN_LOCK_TX_PORT_QUE); + + break; + } + } + } + } +#endif + return WLAN_STATUS_SUCCESS; +} + +u32 nicTxGetMsduPendingCnt(IN P_ADAPTER_T prAdapter) +{ +#if CFG_FIX_2_TX_PORT + return prAdapter->rTxP0Queue.u4NumElem + + prAdapter->rTxP1Queue.u4NumElem; + +#else + s32 i; + u32 retValue = 0; + + for (i = 0; i < TX_PORT_NUM; i++) + retValue += prAdapter->rTxPQueue[i].u4NumElem; + return retValue; + +#endif +} + +void nicTxComposeDescAppend(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + OUT u8 *prTxDescBuffer) +{ + P_HW_MAC_TX_DESC_APPEND_T prHwTxDescAppend; + + /* Fill TxD append */ + prHwTxDescAppend = (P_HW_MAC_TX_DESC_APPEND_T)prTxDescBuffer; + kalMemZero(prHwTxDescAppend, HW_MAC_TX_DESC_APPEND_T_LENGTH); + prHwTxDescAppend->u2PktFlags = HIT_PKT_FLAGS_CT_WITH_TXD; + prHwTxDescAppend->ucBssIndex = prMsduInfo->ucBssIndex; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief In this function, we'll compose the Tx descriptor of the MSDU. + * + * @param prAdapter Pointer to the Adapter structure. + * @param prMsduInfo Pointer to the Msdu info + * @param prTxDesc Pointer to the Tx descriptor buffer + * + * @retval void + */ +/*----------------------------------------------------------------------------*/ +void nicTxComposeDesc(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + IN u32 u4TxDescLength, IN u8 fgIsTemplate, + OUT u8 *prTxDescBuffer) +{ + P_HW_MAC_TX_DESC_T prTxDesc; + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + u8 ucEtherTypeOffsetInWord; + u32 u4TxDescAndPaddingLength; + u8 ucTarPort, ucTarQueue; +#if ((CFG_SISO_SW_DEVELOP == 1) || (CFG_SUPPORT_ANT_SELECT == 1)) + enum ENUM_WF_PATH_FAVOR_T eWfPathFavor; +#endif +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + u8 ucRefTc, ucWmm; +#endif + + prTxDesc = (P_HW_MAC_TX_DESC_T)prTxDescBuffer; + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + u4TxDescAndPaddingLength = u4TxDescLength + NIC_TX_DESC_PADDING_LENGTH; + + kalMemZero(prTxDesc, u4TxDescAndPaddingLength); + + /* Move to nicTxFillDesc */ + /* Tx byte count */ + /* HAL_MAC_TX_DESC_SET_TX_BYTE_COUNT(prTxDesc, ucTxDescAndPaddingLength + * + prMsduInfo->u2FrameLength); */ + + /* Ether-type offset */ + if (prMsduInfo->fgIs802_11) { + ucEtherTypeOffsetInWord = (NIC_TX_PSE_HEADER_LENGTH + + prMsduInfo->ucMacHeaderLength + + prMsduInfo->ucLlcLength) >> + 1; + } else { + ucEtherTypeOffsetInWord = ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + + NIC_TX_PSE_HEADER_LENGTH) >> + 1; + } + HAL_MAC_TX_DESC_SET_ETHER_TYPE_OFFSET(prTxDesc, + ucEtherTypeOffsetInWord); + + /* Port index / queue index */ + ucTarPort = arTcResourceControl[prMsduInfo->ucTC].ucDestPortIndex; + HAL_MAC_TX_DESC_SET_PORT_INDEX(prTxDesc, ucTarPort); + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + ucTarQueue = 0xFF; /*invalid number*/ + for (ucRefTc = 0; ucRefTc < WMM_AC_INDEX_NUM; ucRefTc++) { + /*try to find refTc*/ + ucWmm = nicTxGetWmmIdxByTc(prMsduInfo->ucTC); + if (arTcRemapTable[ucWmm][ucRefTc] == (prMsduInfo->ucTC)) { + ucTarQueue = + arTcResourceControl[ucRefTc].ucDestQueueIndex; + break; + } + } + if (ucTarQueue == 0xFF) { + DBGLOG(TX, WARN, "Cannot find refTc. (%d, %d))\n\n", + (prMsduInfo->ucTC), + nicTxGetWmmIdxByTc(prMsduInfo->ucTC)); + + /*whatever, go ahead*/ + ucTarQueue = + arTcResourceControl[prMsduInfo->ucTC].ucDestQueueIndex; + } +#else + ucTarQueue = arTcResourceControl[prMsduInfo->ucTC].ucDestQueueIndex; +#endif + + if (ucTarPort == PORT_INDEX_LMAC) { + ucTarQueue += (prBssInfo->ucWmmQueSet * WMM_AC_INDEX_NUM); + } + + HAL_MAC_TX_DESC_SET_QUEUE_INDEX(prTxDesc, ucTarQueue); + + /* BMC packet */ + if (prMsduInfo->ucStaRecIndex == STA_REC_INDEX_BMCAST) { + HAL_MAC_TX_DESC_SET_BMC(prTxDesc); + + /* Must set No ACK to mask retry bit in FC */ + HAL_MAC_TX_DESC_SET_NO_ACK(prTxDesc); +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + if (prAdapter->fgIsFixedMRate) { + /* Fixed M rate for choosing first unicast sta */ + DBGLOG(TX, LOUD, + "Force Mcast index to used Sta index\n"); + prMsduInfo->u4FixedRateOption = + prAdapter->rWifiVar.u4DataTxRateCode; + // nicTxSetPktFixedRateOption(prMsduInfo, + // prMsduInfo->u4FixedRateOption, FIX_BW_NO_FIXED, + // false, false); + DBGLOG(TX, + LOUD, + "nicTxFillDesc: multicast fixed rate : (%02x) \n", + prMsduInfo->u4FixedRateOption); + /* Update rate here if BMC force rate */ + HAL_MAC_TX_DESC_SET_DW(prTxDesc, 6, 1, + &prMsduInfo->u4FixedRateOption); + HAL_MAC_TX_DESC_SET_FIXED_RATE_MODE_TO_DESC(prTxDesc); + HAL_MAC_TX_DESC_SET_FIXED_RATE_ENABLE(prTxDesc); + } +#endif + } + + /* WLAN index */ + prMsduInfo->ucWlanIndex = nicTxGetWlanIdx( + prAdapter, prMsduInfo->ucBssIndex, prMsduInfo->ucStaRecIndex); + + HAL_MAC_TX_DESC_SET_WLAN_INDEX(prTxDesc, prMsduInfo->ucWlanIndex); + + /* Header format */ + if (prMsduInfo->fgIs802_11) { + HAL_MAC_TX_DESC_SET_HEADER_FORMAT( + prTxDesc, HEADER_FORMAT_802_11_NORMAL_MODE); + HAL_MAC_TX_DESC_SET_802_11_HEADER_LENGTH( + prTxDesc, (prMsduInfo->ucMacHeaderLength >> 1)); + } else { + HAL_MAC_TX_DESC_SET_HEADER_FORMAT(prTxDesc, + HEADER_FORMAT_NON_802_11); + HAL_MAC_TX_DESC_SET_ETHERNET_II(prTxDesc); + } + + /* Header Padding */ + HAL_MAC_TX_DESC_SET_HEADER_PADDING(prTxDesc, + NIC_TX_DESC_HEADER_PADDING_LENGTH); + + /* TID */ + HAL_MAC_TX_DESC_SET_TID(prTxDesc, prMsduInfo->ucUserPriority); + + /* Protection */ + if (secIsProtectedFrame(prAdapter, prMsduInfo, prStaRec)) { + /* Update Packet option, PF bit will be set in + * nicTxFillDescByPktOption() */ + if ((prStaRec && prStaRec->fgTransmitKeyExist) || + fgIsTemplate) { + nicTxConfigPktOption(prMsduInfo, + MSDU_OPT_PROTECTED_FRAME, true); + + if (prMsduInfo->fgIs802_1x_NonProtected) { + nicTxConfigPktOption(prMsduInfo, + MSDU_OPT_PROTECTED_FRAME, + false); + DBGLOG(RSN, LOUD, + "Pairwise EAPoL not protect!\n"); + } + } else if (prMsduInfo->ucStaRecIndex == + STA_REC_INDEX_BMCAST) { /* BMC packet */ + nicTxConfigPktOption(prMsduInfo, + MSDU_OPT_PROTECTED_FRAME, true); + DBGLOG(RSN, LOUD, "Protect BMC frame!\n"); + } + } +#if (UNIFIED_MAC_TX_FORMAT == 1) + /* Packet Format */ + if (prMsduInfo->eSrc == TX_PACKET_MGMT) { + HAL_MAC_TX_DESC_SET_PKT_FORMAT(prTxDesc, + TXD_PKT_FORMAT_COMMAND); + } +#endif + + /* Own MAC */ + HAL_MAC_TX_DESC_SET_OWN_MAC_INDEX(prTxDesc, prBssInfo->ucOwnMacIndex); + + if (u4TxDescLength == NIC_TX_DESC_SHORT_FORMAT_LENGTH) { + HAL_MAC_TX_DESC_SET_SHORT_FORMAT(prTxDesc); + + /* Update Packet option */ + nicTxFillDescByPktOption(prMsduInfo, prTxDesc); + + /* Short format, Skip DW 2~6 */ + return; + } + HAL_MAC_TX_DESC_SET_LONG_FORMAT(prTxDesc); + + /* Update Packet option */ + nicTxFillDescByPktOption(prMsduInfo, prTxDesc); + + nicTxFillDescByPktControl(prMsduInfo, prTxDesc); + + /* Type */ + if (prMsduInfo->fgIs802_11) { + P_WLAN_MAC_HEADER_T prWlanHeader = + (P_WLAN_MAC_HEADER_T)((unsigned long)(prMsduInfo + ->prPacket) + + MAC_TX_RESERVED_FIELD); + + HAL_MAC_TX_DESC_SET_TYPE( + prTxDesc, + (prWlanHeader->u2FrameCtrl & MASK_FC_TYPE) >> 2); + HAL_MAC_TX_DESC_SET_SUB_TYPE(prTxDesc, + (prWlanHeader->u2FrameCtrl & + MASK_FC_SUBTYPE) >> + OFFSET_OF_FC_SUBTYPE); + } + /* PID */ + if (prMsduInfo->pfTxDoneHandler) { + prMsduInfo->ucPID = + nicTxAssignPID(prAdapter, prMsduInfo->ucWlanIndex); + HAL_MAC_TX_DESC_SET_PID(prTxDesc, prMsduInfo->ucPID); + HAL_MAC_TX_DESC_SET_TXS_TO_MCU(prTxDesc); + } else if (prAdapter->rWifiVar.ucDataTxDone == 2) { + /* Log mode: only TxS to FW, no event to driver */ + HAL_MAC_TX_DESC_SET_PID(prTxDesc, NIC_TX_DESC_PID_RESERVED); + HAL_MAC_TX_DESC_SET_TXS_TO_MCU(prTxDesc); + } + + /* Remaining TX time */ + if (!(prMsduInfo->u4Option & MSDU_OPT_MANUAL_LIFE_TIME)) { +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + ucRefTc = aucTid2ACI[prMsduInfo->ucUserPriority]; + prMsduInfo->u4RemainingLifetime = + arTcTrafficSettings[ucRefTc].u4RemainingTxTime; +#else + prMsduInfo->u4RemainingLifetime = + arTcTrafficSettings[prMsduInfo->ucTC].u4RemainingTxTime; +#endif + } + + HAL_MAC_TX_DESC_SET_REMAINING_LIFE_TIME_IN_MS( + prTxDesc, prMsduInfo->u4RemainingLifetime); + + /* Tx count limit */ + if (!(prMsduInfo->u4Option & MSDU_OPT_MANUAL_RETRY_LIMIT)) { + /* Note: BMC packet retry limit is set to unlimited */ +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + ucRefTc = aucTid2ACI[prMsduInfo->ucUserPriority]; + prMsduInfo->ucRetryLimit = + arTcTrafficSettings[ucRefTc].ucTxCountLimit; +#else + prMsduInfo->ucRetryLimit = + arTcTrafficSettings[prMsduInfo->ucTC].ucTxCountLimit; +#endif + } + HAL_MAC_TX_DESC_SET_REMAINING_TX_COUNT(prTxDesc, + prMsduInfo->ucRetryLimit); + + /* Power Offset */ + HAL_MAC_TX_DESC_SET_POWER_OFFSET(prTxDesc, prMsduInfo->cPowerOffset); + + /* Fix rate */ + switch (prMsduInfo->ucRateMode) { + case MSDU_RATE_MODE_MANUAL_DESC: + HAL_MAC_TX_DESC_SET_DW(prTxDesc, 6, 1, + &prMsduInfo->u4FixedRateOption); +#if ((CFG_SISO_SW_DEVELOP == 1) || (CFG_SUPPORT_ANT_SELECT == 1)) + /* Update spatial extension index setting */ + eWfPathFavor = wlanGetAntPathType(prAdapter, ENUM_WF_NON_FAVOR, + prBssInfo->ucBssIndex); + HAL_MAC_TX_DESC_SET_SPE_IDX(prTxDesc, + wlanGetSpeIdx(prAdapter, + prBssInfo->ucBssIndex, + eWfPathFavor)); +#endif + HAL_MAC_TX_DESC_SET_FIXED_RATE_MODE_TO_DESC(prTxDesc); + HAL_MAC_TX_DESC_SET_FIXED_RATE_ENABLE(prTxDesc); + break; + + case MSDU_RATE_MODE_MANUAL_CR: + +#if ((CFG_SISO_SW_DEVELOP == 1) || (CFG_SUPPORT_ANT_SELECT == 1)) + /* Update spatial extension index setting */ + eWfPathFavor = wlanGetAntPathType(prAdapter, ENUM_WF_NON_FAVOR, + prBssInfo->ucBssIndex); + HAL_MAC_TX_DESC_SET_SPE_IDX(prTxDesc, + wlanGetSpeIdx(prAdapter, + prBssInfo->ucBssIndex, + eWfPathFavor)); +#endif + HAL_MAC_TX_DESC_SET_FIXED_RATE_MODE_TO_CR(prTxDesc); + HAL_MAC_TX_DESC_SET_FIXED_RATE_ENABLE(prTxDesc); + break; + + case MSDU_RATE_MODE_AUTO: + default: + break; + } + if (prMsduInfo->fgIs802_1x) { + if (prAdapter->fgIsTest1xTx == 2) { + DBGLOG(RSN, + STATE, + "%s: (fgIsTest1xTx == 2) test 1XTX frame stuck in queue\n", + __func__); + HAL_MAC_TX_DESC_SET_FR_RATE(prTxDesc, 0xff); + HAL_MAC_TX_DESC_SET_FIXED_RATE_MODE_TO_DESC(prTxDesc); + HAL_MAC_TX_DESC_SET_FIXED_RATE_ENABLE(prTxDesc); + } + } +} + +void nicTxComposeSecurityFrameDesc(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + OUT u8 *prTxDescBuffer, + OUT u8 *pucTxDescLength) +{ + P_HW_MAC_TX_DESC_T prTxDesc = (P_HW_MAC_TX_DESC_T)prTxDescBuffer; + u8 ucTxDescAndPaddingLength = + NIC_TX_DESC_LONG_FORMAT_LENGTH + NIC_TX_DESC_PADDING_LENGTH; + /* P_STA_RECORD_T prStaRec = cnmGetStaRecByIndex(prAdapter, + * prCmdInfo->ucStaRecIndex); */ + P_BSS_INFO_T prBssInfo; + u8 ucTid = 0; + u8 ucTempTC = TC4_INDEX; + P_NATIVE_PACKET prNativePacket; + u8 ucEtherTypeOffsetInWord; + P_MSDU_INFO_T prMsduInfo; + + prMsduInfo = prCmdInfo->prMsduInfo; + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + prNativePacket = prMsduInfo->prPacket; + + ASSERT(prNativePacket); + + kalMemZero(prTxDesc, ucTxDescAndPaddingLength); + + /* WLAN index */ + prMsduInfo->ucWlanIndex = nicTxGetWlanIdx( + prAdapter, prMsduInfo->ucBssIndex, prMsduInfo->ucStaRecIndex); + + /* UC to a connected peer */ + HAL_MAC_TX_DESC_SET_WLAN_INDEX(prTxDesc, prMsduInfo->ucWlanIndex); + /* Redirect Security frame to TID0 */ + /* ucTempTC = + * arNetwork2TcResource[prStaRec->ucBssIndex][aucTid2ACI[ucTid]]; */ + + /* Tx byte count */ + HAL_MAC_TX_DESC_SET_TX_BYTE_COUNT( + prTxDesc, ucTxDescAndPaddingLength + prCmdInfo->u2InfoBufLen); + + /* Ether-type offset */ + ucEtherTypeOffsetInWord = ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + + NIC_TX_PSE_HEADER_LENGTH) >> + 1; + HAL_MAC_TX_DESC_SET_ETHER_TYPE_OFFSET(prTxDesc, + ucEtherTypeOffsetInWord); + + /* Port index / queue index */ + HAL_MAC_TX_DESC_SET_PORT_INDEX( + prTxDesc, arTcResourceControl[ucTempTC].ucDestPortIndex); + HAL_MAC_TX_DESC_SET_QUEUE_INDEX( + prTxDesc, arTcResourceControl[ucTempTC].ucDestQueueIndex); + + /* Header format */ + HAL_MAC_TX_DESC_SET_HEADER_FORMAT(prTxDesc, HEADER_FORMAT_NON_802_11); + + /* Long Format */ + HAL_MAC_TX_DESC_SET_LONG_FORMAT(prTxDesc); + + /* Update Packet option */ + nicTxFillDescByPktOption(prMsduInfo, prTxDesc); + + if (!GLUE_TEST_PKT_FLAG(prNativePacket, ENUM_PKT_802_3)) { + /* Set EthernetII */ + HAL_MAC_TX_DESC_SET_ETHERNET_II(prTxDesc); + } + /* Header Padding */ + HAL_MAC_TX_DESC_SET_HEADER_PADDING(prTxDesc, + NIC_TX_DESC_HEADER_PADDING_LENGTH); + + /* TID */ + HAL_MAC_TX_DESC_SET_TID(prTxDesc, ucTid); + + /* Remaining TX time */ + HAL_MAC_TX_DESC_SET_REMAINING_LIFE_TIME_IN_MS( + prTxDesc, arTcTrafficSettings[ucTempTC].u4RemainingTxTime); + + /* Tx count limit */ + HAL_MAC_TX_DESC_SET_REMAINING_TX_COUNT( + prTxDesc, arTcTrafficSettings[ucTempTC].ucTxCountLimit); + + /* Set lowest BSS basic rate */ + HAL_MAC_TX_DESC_SET_FR_RATE(prTxDesc, + prBssInfo->u2HwDefaultFixedRateCode); + HAL_MAC_TX_DESC_SET_FIXED_RATE_MODE_TO_DESC(prTxDesc); + HAL_MAC_TX_DESC_SET_FIXED_RATE_ENABLE(prTxDesc); + + /* Packet Format */ + HAL_MAC_TX_DESC_SET_PKT_FORMAT(prTxDesc, TXD_PKT_FORMAT_COMMAND); + + /* Own MAC */ + HAL_MAC_TX_DESC_SET_OWN_MAC_INDEX(prTxDesc, prBssInfo->ucOwnMacIndex); + + /* PID */ + if (prMsduInfo->pfTxDoneHandler) { + prMsduInfo->ucPID = + nicTxAssignPID(prAdapter, prMsduInfo->ucWlanIndex); + HAL_MAC_TX_DESC_SET_PID(prTxDesc, prMsduInfo->ucPID); + HAL_MAC_TX_DESC_SET_TXS_TO_MCU(prTxDesc); + } + + if (pucTxDescLength) { + *pucTxDescLength = ucTxDescAndPaddingLength; + } +} + +u8 nicTxIsTXDTemplateAllowed(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, + IN P_STA_RECORD_T prStaRec) +{ + if (prMsduInfo->fgIsTXDTemplateValid) { + if (prMsduInfo->fgIs802_1x) { + return false; + } + + if (prMsduInfo->ucRateMode != MSDU_RATE_MODE_AUTO) { + return false; + } + + if (!prStaRec) { + return false; + } + + if (prMsduInfo->ucControlFlag) { + return false; + } + + if (prMsduInfo->pfTxDoneHandler) { + return false; + } + + if (prAdapter->rWifiVar.ucDataTxRateMode) { + return false; + } + + return true; + } + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief In this function, we'll compose the Tx descriptor of the MSDU. + * + * @param prAdapter Pointer to the Adapter structure. + * @param prMsduInfo Pointer to the Msdu info + * @param prTxDesc Pointer to the Tx descriptor buffer + * + * @retval void + */ +/*----------------------------------------------------------------------------*/ +void nicTxFillDesc(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + OUT u8 *prTxDescBuffer, OUT u32 *pu4TxDescLength) +{ + P_HW_MAC_TX_DESC_T prTxDesc = (P_HW_MAC_TX_DESC_T)prTxDescBuffer; + P_HW_MAC_TX_DESC_T prTxDescTemplate = NULL; + P_STA_RECORD_T prStaRec = + cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + u32 u4TxDescLength, u4TxDescAppendLength; +#if CFG_TCP_IP_CHKSUM_OFFLOAD + u8 ucChksumFlag = 0; +#endif + + /* This is to lock the process to preventing */ + /* nicTxFreeDescTemplate while Filling it */ + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_DESC); + + /* + *------------------------------------------------------------------------------ + * Fill up common fileds + *------------------------------------------------------------------------------ + */ + /* Decide TxD append length */ + if (prMsduInfo->ucPacketType == TX_PACKET_TYPE_DATA) { + u4TxDescAppendLength = HW_MAC_TX_DESC_APPEND_T_LENGTH; + }else{ + u4TxDescAppendLength = 0; + } + + /* Get TXD from pre-allocated template */ + if (nicTxIsTXDTemplateAllowed(prAdapter, prMsduInfo, prStaRec) && + prStaRec->aprTxDescTemplate[prMsduInfo->ucUserPriority]) { + prTxDescTemplate = + prStaRec->aprTxDescTemplate[prMsduInfo->ucUserPriority]; + + u4TxDescLength = NIC_TX_DESC_LONG_FORMAT_LENGTH; + + kalMemCopy(prTxDesc, prTxDescTemplate, + u4TxDescLength + u4TxDescAppendLength); + + /* Overwrite fields for EOSP or More data */ + nicTxFillDescByPktOption(prMsduInfo, prTxDesc); +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + /* Set no ack here and no enable BMC in Burst mode*/ + if (IS_BMCAST_MAC_ADDR(prMsduInfo->aucEthDestAddr)) { + /* Force mcast rate here */ + if (prAdapter->fgIsFixedMRate) { + prMsduInfo->u4FixedRateOption = + prAdapter->rWifiVar.u4DataTxRateCode; + // nicTxSetPktFixedRateOption(prMsduInfo, + // prMsduInfo->u4FixedRateOption, + // FIX_BW_NO_FIXED, false, false); + DBGLOG(QM, + LOUD, + "nicTxFillDesc: multicast fixed rate : (%02x) \n", + prMsduInfo->u4FixedRateOption); + /* Update rate here if BMC force rate */ + HAL_MAC_TX_DESC_SET_DW( + prTxDesc, 6, 1, + &prMsduInfo->u4FixedRateOption); + HAL_MAC_TX_DESC_SET_FIXED_RATE_MODE_TO_DESC( + prTxDesc); + HAL_MAC_TX_DESC_SET_FIXED_RATE_ENABLE(prTxDesc); + } + } +#endif + } + /* Compose TXD by Msdu info */ + else { + u4TxDescLength = NIC_TX_DESC_LONG_FORMAT_LENGTH; + nicTxComposeDesc(prAdapter, prMsduInfo, u4TxDescLength, false, + prTxDescBuffer); + + /* Compose TxD append */ + if (prMsduInfo->ucPacketType == TX_PACKET_TYPE_DATA) { + nicTxComposeDescAppend(prAdapter, prMsduInfo, + prTxDescBuffer + u4TxDescLength); + } + } + + /* + *------------------------------------------------------------------------------ + * Fill up remaining parts, per-packet variant fields + *------------------------------------------------------------------------------ + */ + /* Calculate Tx byte count */ + HAL_MAC_TX_DESC_SET_TX_BYTE_COUNT( + prTxDesc, u4TxDescLength + u4TxDescAppendLength + + prMsduInfo->u2FrameLength); + + /* Checksum offload */ +#if CFG_TCP_IP_CHKSUM_OFFLOAD + if (prAdapter->fgIsSupportCsumOffload && + prMsduInfo->eSrc == TX_PACKET_OS) { + if (prAdapter->u4CSUMFlags & + (CSUM_OFFLOAD_EN_TX_TCP | CSUM_OFFLOAD_EN_TX_UDP | + CSUM_OFFLOAD_EN_TX_IP)) { + ASSERT(prMsduInfo->prPacket); + kalQueryTxChksumOffloadParam(prMsduInfo->prPacket, + &ucChksumFlag); + if ((ucChksumFlag & TX_CS_IP_GEN)) { + HAL_MAC_TX_DESC_SET_IP_CHKSUM(prTxDesc); + } + if ((ucChksumFlag & TX_CS_TCP_UDP_GEN)) { + HAL_MAC_TX_DESC_SET_TCP_UDP_CHKSUM(prTxDesc); + } + } + } +#endif + + /* Set EtherType & VLAN for non 802.11 frame */ + if (!prMsduInfo->fgIs802_11) { + if (prMsduInfo->fgIs802_3) { + HAL_MAC_TX_DESC_UNSET_ETHERNET_II(prTxDesc); + } + if (prMsduInfo->fgIsVlanExists) { + HAL_MAC_TX_DESC_SET_VLAN(prTxDesc); + } + } + + if (pu4TxDescLength) { + *pu4TxDescLength = u4TxDescLength; + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_DESC); +} + +void nicTxFillDataDesc(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + u8 *pucOutputBuf; + + pucOutputBuf = skb_push((struct sk_buff *)prMsduInfo->prPacket, + NIC_TX_HEAD_ROOM); + + nicTxFillDesc(prAdapter, prMsduInfo, pucOutputBuf, NULL); +} + +void nicTxCopyDesc(IN P_ADAPTER_T prAdapter, IN u8 *pucTarTxDesc, + IN u8 *pucSrcTxDesc, OUT u8 *pucTxDescLength) +{ + u8 ucTxDescLength; + + if (HAL_MAC_TX_DESC_IS_LONG_FORMAT((P_HW_MAC_TX_DESC_T)pucSrcTxDesc)) { + ucTxDescLength = NIC_TX_DESC_LONG_FORMAT_LENGTH; + }else{ + ucTxDescLength = NIC_TX_DESC_SHORT_FORMAT_LENGTH; + } + + kalMemCopy(pucTarTxDesc, pucSrcTxDesc, ucTxDescLength); + + if (pucTxDescLength) { + *pucTxDescLength = ucTxDescLength; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief In this function, we'll generate Tx descriptor template for each TID. + * + * @param prAdapter Pointer to the Adapter structure. + * @param prStaRec Pointer to the StaRec structure. + * + * @retval void + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxGenerateDescTemplate(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec) +{ + u8 ucTid; + u8 ucTc; + u32 u4TxDescSize, u4TxDescAppendSize; + P_HW_MAC_TX_DESC_T prTxDesc; + P_MSDU_INFO_T prMsduInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + u8 ucRefTc; + P_BSS_INFO_T prBssInfo; +#endif + + ASSERT(prAdapter); + + /* Free previous template, first */ + /* nicTxFreeDescTemplate(prAdapter, prStaRec); */ + for (ucTid = 0; ucTid < TX_DESC_TID_NUM; ucTid++) + prStaRec->aprTxDescTemplate[ucTid] = NULL; + + prMsduInfo = cnmPktAlloc(prAdapter, 0); + + if (!prMsduInfo) { + return WLAN_STATUS_RESOURCES; + } + + /* Fill up MsduInfo template */ + prMsduInfo->eSrc = TX_PACKET_OS; + prMsduInfo->fgIs802_11 = false; + prMsduInfo->fgIs802_1x = false; + prMsduInfo->fgIs802_1x_NonProtected = false; + prMsduInfo->fgIs802_3 = false; + prMsduInfo->fgIsVlanExists = false; + prMsduInfo->pfTxDoneHandler = NULL; + prMsduInfo->prPacket = NULL; + prMsduInfo->u2FrameLength = 0; + prMsduInfo->u4Option = 0; + prMsduInfo->u4FixedRateOption = 0; + prMsduInfo->ucRateMode = MSDU_RATE_MODE_AUTO; + prMsduInfo->ucBssIndex = prStaRec->ucBssIndex; + prMsduInfo->ucPacketType = TX_PACKET_TYPE_DATA; + prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; + prMsduInfo->ucPID = NIC_TX_DESC_PID_RESERVED; + + u4TxDescSize = NIC_TX_DESC_LONG_FORMAT_LENGTH; + u4TxDescAppendSize = HW_MAC_TX_DESC_APPEND_T_LENGTH; + + DBGLOG(QM, INFO, "Generate TXD template for STA[%u] QoS[%u]\n", + prStaRec->ucIndex, prStaRec->fgIsQoS); + + /* Generate new template */ + if (prStaRec->fgIsQoS) { + /* For QoS STA, generate 8 TXD template (TID0~TID7) */ + for (ucTid = 0; ucTid < TX_DESC_TID_NUM; ucTid++) { + if (prAdapter->rWifiVar.ucTcRestrict < TC_NUM) { + ucTc = prAdapter->rWifiVar.ucTcRestrict; + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + ucRefTc = ucTc; +#endif + } else { + ucTc = + arNetwork2TcResource[prStaRec-> + ucBssIndex] + [aucTid2ACI[ucTid]]; + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + ucRefTc = ucTc; + + prBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, prStaRec->ucBssIndex); + ucTc = arTcRemapTable[prBssInfo->ucWmmQueSet] + [ucTc]; +#endif + } + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + u4TxDescSize = + arTcTrafficSettings[ucRefTc].u4TxDescLength; +#else + u4TxDescSize = arTcTrafficSettings[ucTc].u4TxDescLength; +#endif + + /* Include TxD append */ + prTxDesc = + kalMemAlloc(u4TxDescSize + u4TxDescAppendSize, + VIR_MEM_TYPE); + DBGLOG(QM, TRACE, "STA[%u] TID[%u] TxDTemp[0x%p]\n", + prStaRec->ucIndex, ucTid, prTxDesc); + if (!prTxDesc) { + rStatus = WLAN_STATUS_RESOURCES; + break; + } + + /* Update MsduInfo TID & TC */ + prMsduInfo->ucUserPriority = ucTid; + prMsduInfo->ucTC = ucTc; + + /* Compose Tx desc template */ + nicTxComposeDesc(prAdapter, prMsduInfo, u4TxDescSize, + true, (u8 *)prTxDesc); + + /* Fill TxD append */ + nicTxComposeDescAppend(prAdapter, prMsduInfo, + ((u8 *)prTxDesc + u4TxDescSize)); + + prStaRec->aprTxDescTemplate[ucTid] = prTxDesc; + } + } else { + /* For non-QoS STA, generate 1 TXD template (TID0) */ + do { + if (prAdapter->rWifiVar.ucTcRestrict < TC_NUM) { + ucTc = prAdapter->rWifiVar.ucTcRestrict; + } else { + /*get TC index*/ + ucTc = arNetwork2TcResource + [prStaRec->ucBssIndex] + [NET_TC_WMM_AC_BE_INDEX]; + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + prBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, prStaRec->ucBssIndex); + + ucTc = arTcRemapTable[prBssInfo->ucWmmQueSet] + [ucTc]; +#endif + } + + /* ucTxDescSize = + * arTcTrafficSettings[ucTc].ucTxDescLength; */ + u4TxDescSize = NIC_TX_DESC_LONG_FORMAT_LENGTH; + + prTxDesc = + kalMemAlloc(u4TxDescSize + u4TxDescAppendSize, + VIR_MEM_TYPE); + if (!prTxDesc) { + rStatus = WLAN_STATUS_RESOURCES; + break; + } + /* Update MsduInfo TID & TC */ + prMsduInfo->ucUserPriority = 0; + prMsduInfo->ucTC = ucTc; + + /* Compose Tx desc template */ + nicTxComposeDesc(prAdapter, prMsduInfo, u4TxDescSize, + true, (u8 *)prTxDesc); + + /* Fill TxD append */ + nicTxComposeDescAppend(prAdapter, prMsduInfo, + ((u8 *)prTxDesc + u4TxDescSize)); + + for (ucTid = 0; ucTid < TX_DESC_TID_NUM; ucTid++) { + prStaRec->aprTxDescTemplate[ucTid] = prTxDesc; + DBGLOG(QM, TRACE, + "TXD template: TID[%u] Ptr[0x%x]\n", + ucTid, (unsigned long)prTxDesc); + } + } while (false); + } + + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief In this function, we'll free Tx descriptor template for each TID. + * + * @param prAdapter Pointer to the Adapter structure. + * @param prStaRec Pointer to the StaRec structure. + * + * @retval void + */ +/*----------------------------------------------------------------------------*/ +#if KERNEL_VERSION(4, 19, 0) <= LINUX_VERSION_CODE +void nicTxFreeDescTemplate(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec) +{ + u8 ucTid; + u8 ucTxDescSizeList[TX_DESC_TID_NUM] = { 0 }; + P_HW_MAC_TX_DESC_T prTxDescList[TX_DESC_TID_NUM] = { NULL }; + + /* This is to lock the process to preventing */ + /* nicTxFreeDescTemplate while Filling it */ + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_DESC); + + DBGLOG(QM, INFO, "Free TXD template for STA[%u] QoS[%u]\n", + prStaRec->ucIndex, prStaRec->fgIsQoS); + + for (ucTid = 0; ucTid < TX_DESC_TID_NUM; ucTid++) { + prTxDescList[ucTid] = + (P_HW_MAC_TX_DESC_T)prStaRec->aprTxDescTemplate[ucTid]; + + if (prTxDescList[ucTid]) { + if (HAL_MAC_TX_DESC_IS_LONG_FORMAT( + prTxDescList[ucTid])) { + ucTxDescSizeList[ucTid] = + NIC_TX_DESC_LONG_FORMAT_LENGTH; + } else { + ucTxDescSizeList[ucTid] = + NIC_TX_DESC_SHORT_FORMAT_LENGTH; + } + + prStaRec->aprTxDescTemplate[ucTid] = NULL; + } + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_DESC); + + for (ucTid = 0; ucTid < TX_DESC_TID_NUM; ucTid++) { + if (ucTid > 0 && prTxDescList[ucTid] == prTxDescList[ucTid - 1]) { + break; + } + + if (prTxDescList[ucTid]) { + kalMemFree(prTxDescList[ucTid], VIR_MEM_TYPE, + ucTxDescSizeList[ucTid]); + } + } +} +#else +void nicTxFreeDescTemplate(IN P_ADAPTER_T prAdapter, + IN P_STA_RECORD_T prStaRec) +{ + u8 ucTid; + u8 ucTxDescSize; + P_HW_MAC_TX_DESC_T prTxDesc; + void *prFirstTxDesc; + /* This is to lock the process to preventing */ + /* nicTxFreeDescTemplate while Filling it */ + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_DESC); + DBGLOG(QM, INFO, "Free TXD template for STA[%u] QoS[%u]\n", + prStaRec->ucIndex, prStaRec->fgIsQoS); + + prFirstTxDesc = prStaRec->aprTxDescTemplate[0]; + for (ucTid = 0; ucTid < TX_DESC_TID_NUM; ucTid++) { + prTxDesc = + (P_HW_MAC_TX_DESC_T)prStaRec->aprTxDescTemplate[ucTid]; + if (prTxDesc) { + /* For non-QoS STA, all share 1 TXD template (TID0) */ + /* refer to nicTxGenerateDescTemplate */ + if (ucTid > 0 && prTxDesc == prFirstTxDesc) { + break; + } + + if (HAL_MAC_TX_DESC_IS_LONG_FORMAT(prTxDesc)) { + ucTxDescSize = NIC_TX_DESC_LONG_FORMAT_LENGTH; + }else{ + ucTxDescSize = NIC_TX_DESC_SHORT_FORMAT_LENGTH; + } + kalMemFree(prTxDesc, VIR_MEM_TYPE, ucTxDescSize); + prTxDesc = NULL; + } + } + + for (ucTid = 0; ucTid < TX_DESC_TID_NUM; ucTid++) + prStaRec->aprTxDescTemplate[ucTid] = NULL; + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_DESC); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Write data to device done + * + * \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. + * \param[in] prQue msdu info que to be free + * + * \retval true operation success + * \retval false operation fail + */ +/*----------------------------------------------------------------------------*/ +void nicTxMsduDoneCb(IN P_GLUE_INFO_T prGlueInfo, IN P_QUE_T prQue) +{ + P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; + QUE_T rFreeQueue; + P_QUE_T prFreeQueue; + /* P_NATIVE_PACKET prNativePacket; */ + P_TX_CTRL_T prTxCtrl; + P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + prFreeQueue = &rFreeQueue; + QUEUE_INITIALIZE(prFreeQueue); + + if (prQue && prQue->u4NumElem > 0) { + prMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_HEAD(prQue); + + while (prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY( + &prMsduInfo->rQueEntry); + + nicTxFreePacket(prAdapter, prMsduInfo, false); + + if (!prMsduInfo->pfTxDoneHandler) { + QUEUE_INSERT_TAIL(prFreeQueue, + (P_QUE_ENTRY_T)prMsduInfo); + } + + prMsduInfo = prNextMsduInfo; + } + nicTxReturnMsduInfo(prAdapter, + (P_MSDU_INFO_T)QUEUE_GET_HEAD(&rFreeQueue)); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief In this function, we'll write frame(PACKET_INFO_T) into HIF. + * + * @param prAdapter Pointer to the Adapter structure. + * @param ucPortIdx Port Number + * @param prQue a link list of P_MSDU_INFO_T + * + * @retval WLAN_STATUS_SUCCESS Bus access ok. + * @retval WLAN_STATUS_FAILURE Bus access fail. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxMsduQueue(IN P_ADAPTER_T prAdapter, u8 ucPortIdx, + P_QUE_T prQue) +{ + P_MSDU_INFO_T prMsduInfo; + P_TX_CTRL_T prTxCtrl; + + ASSERT(prAdapter); + ASSERT(prQue); + + prTxCtrl = &prAdapter->rTxCtrl; + +#if CFG_HIF_STATISTICS + prTxCtrl->u4TotalTxAccessNum++; + prTxCtrl->u4TotalTxPacketNum += prQue->u4NumElem; +#endif + + while (QUEUE_IS_NOT_EMPTY(prQue)) { + QUEUE_REMOVE_HEAD(prQue, prMsduInfo, P_MSDU_INFO_T); + + if (prMsduInfo->pfTxDoneHandler) { + KAL_SPIN_LOCK_DECLARATION(); + + /* Record native packet pointer for Tx done log */ + WLAN_GET_FIELD_32(&prMsduInfo->prPacket, + &prMsduInfo->u4TxDoneTag); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TXING_MGMT_LIST); + QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), + (P_QUE_ENTRY_T)prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TXING_MGMT_LIST); + } + HAL_WRITE_TX_DATA(prAdapter, prMsduInfo); + } + HAL_KICK_TX_DATA(prAdapter); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief In this function, we'll write Command(CMD_INFO_T) into HIF. + * + * @param prAdapter Pointer to the Adapter structure. + * @param prPacketInfo Pointer of CMD_INFO_T + * @param ucTC Specify the resource of TC + * + * @retval WLAN_STATUS_SUCCESS Bus access ok. + * @retval WLAN_STATUS_FAILURE Bus access fail. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, + IN u8 ucTC) +{ + P_WIFI_CMD_T prWifiCmd; + P_MSDU_INFO_T prMsduInfo; + P_TX_CTRL_T prTxCtrl; + struct sk_buff *skb; +#if CFG_MESON_G12A_PATCH + u32 ret = WLAN_STATUS_SUCCESS; +#endif + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prTxCtrl = &prAdapter->rTxCtrl; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { + prMsduInfo = prCmdInfo->prMsduInfo; + + prCmdInfo->pucTxd = prMsduInfo->aucTxDescBuffer; + if (HAL_MAC_TX_DESC_IS_LONG_FORMAT( + (P_HW_MAC_TX_DESC_T)prMsduInfo->aucTxDescBuffer)) { + + prCmdInfo->u4TxdLen = NIC_TX_DESC_LONG_FORMAT_LENGTH; + }else{ + prCmdInfo->u4TxdLen = NIC_TX_DESC_SHORT_FORMAT_LENGTH; + } + + skb = (struct sk_buff *)prMsduInfo->prPacket; + prCmdInfo->pucTxp = skb->data; + prCmdInfo->u4TxpLen = skb->len; + +#if CFG_MESON_G12A_PATCH + ret = HAL_WRITE_TX_CMD(prAdapter, prCmdInfo, ucTC); +#else + HAL_WRITE_TX_CMD(prAdapter, prCmdInfo, ucTC); +#endif + + prMsduInfo->prPacket = NULL; + + if (prMsduInfo->pfTxDoneHandler) { + /* DBGLOG(INIT, TRACE,("Wait Cmd TxSeqNum:%d\n", + * prMsduInfo->ucTxSeqNum)); */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TXING_MGMT_LIST); + QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), + (P_QUE_ENTRY_T)prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TXING_MGMT_LIST); + } else { + /* Only return MSDU_INFO */ + /* NativePacket will be freed at SEC frame CMD callback + */ + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + } + } else if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { + prMsduInfo = prCmdInfo->prMsduInfo; + + ASSERT(prMsduInfo->fgIs802_11 == true); + ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); + + prCmdInfo->pucTxd = prMsduInfo->aucTxDescBuffer; + if (HAL_MAC_TX_DESC_IS_LONG_FORMAT( + (P_HW_MAC_TX_DESC_T)prMsduInfo->aucTxDescBuffer)) { + + prCmdInfo->u4TxdLen = NIC_TX_DESC_LONG_FORMAT_LENGTH; + }else{ + prCmdInfo->u4TxdLen = NIC_TX_DESC_SHORT_FORMAT_LENGTH; + } + + prCmdInfo->pucTxp = prMsduInfo->prPacket; + prCmdInfo->u4TxpLen = prMsduInfo->u2FrameLength; + +#if CFG_MESON_G12A_PATCH + ret = HAL_WRITE_TX_CMD(prAdapter, prCmdInfo, ucTC); +#else + HAL_WRITE_TX_CMD(prAdapter, prCmdInfo, ucTC); +#endif + /* <4> Management Frame Post-Processing */ + GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); + + DBGLOG(INIT, + INFO, + "TX MGMT Frame: BSS[%u] WIDX:PID[%u:%u] SEQ[%u] STA[%u] RSP[%u]\n", + prMsduInfo->ucBssIndex, + prMsduInfo->ucWlanIndex, + prMsduInfo->ucPID, + prMsduInfo->ucTxSeqNum, + prMsduInfo->ucStaRecIndex, + prMsduInfo->pfTxDoneHandler ? true : false); + + if (prMsduInfo->pfTxDoneHandler) { + /* DBGLOG(INIT, TRACE,("Wait Cmd TxSeqNum:%d\n", + * prMsduInfo->ucTxSeqNum)); */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TXING_MGMT_LIST); + QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), + (P_QUE_ENTRY_T)prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TXING_MGMT_LIST); + } else { + cnmMgtPktFree(prAdapter, prMsduInfo); + } + } else { + P_PSE_CMD_HDR_T prPseCmdHdr; + + prWifiCmd = (P_WIFI_CMD_T)prCmdInfo->pucInfoBuffer; + + prPseCmdHdr = (P_PSE_CMD_HDR_T)(prCmdInfo->pucInfoBuffer); + prPseCmdHdr->u2Qidx = TXD_Q_IDX_MCU_RQ0; + prPseCmdHdr->u2Pidx = TXD_P_IDX_MCU; + prPseCmdHdr->u2Hf = TXD_HF_CMD; + prPseCmdHdr->u2Ft = TXD_FT_LONG_FORMAT; + prPseCmdHdr->u2PktFt = TXD_PKT_FT_CMD; + + prWifiCmd->u2Length = + prWifiCmd->u2TxByteCount - sizeof(PSE_CMD_HDR_T); + +#if (CFG_UMAC_GENERATION >= 0x20) + /* TODO ? */ + /* prWifiCmd->prPseCmd.u2TxByteCount = u2OverallBufferLength; */ + /* prWifiCmd->u2TxByteCount = u2OverallBufferLength - + * sizeof(PSE_CMD_HDR_T); */ +#else + prWifiCmd->u2TxByteCount = TFCB_FRAME_PAD_TO_DW( + (prCmdInfo->u2InfoBufLen) & + (u16)HIF_TX_HDR_TX_BYTE_COUNT_MASK); +#endif + prWifiCmd->u2PQ_ID = CMD_PQ_ID; + prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; + prWifiCmd->ucS2DIndex = S2D_INDEX_CMD_H2N_H2C; + prCmdInfo->pucTxd = prCmdInfo->pucInfoBuffer; + prCmdInfo->u4TxdLen = prCmdInfo->u2InfoBufLen; + prCmdInfo->pucTxp = NULL; + prCmdInfo->u4TxpLen = 0; + +#if CFG_MESON_G12A_PATCH + ret = HAL_WRITE_TX_CMD(prAdapter, prCmdInfo, ucTC); + DBGLOG(INIT, + TRACE, + "TX CMD: ID[0x%02X] SEQ[%u] SET[%u] LEN[%u] status[%x]\n", + prWifiCmd->ucCID, + prWifiCmd->ucSeqNum, + prWifiCmd->ucSetQuery, + prWifiCmd->u2Length, + ret); +#else + HAL_WRITE_TX_CMD(prAdapter, prCmdInfo, ucTC); + + DBGLOG(INIT, INFO, + "TX CMD: ID[0x%02X] SEQ[%u] SET[%u] LEN[%u]\n", + prWifiCmd->ucCID, prWifiCmd->ucSeqNum, + prWifiCmd->ucSetQuery, prWifiCmd->u2Length); +#endif + } + +#if CFG_MESON_G12A_PATCH + return ret; + +#else + return WLAN_STATUS_SUCCESS; + +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function will clean up all the pending frames in internal SW + * Queues by return the pending TX packet to the system. + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicTxRelease(IN P_ADAPTER_T prAdapter, IN u8 fgProcTxDoneHandler) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + + nicTxFlush(prAdapter); + + /* free MSDU_INFO_T from rTxMgmtMsduInfoList */ + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + QUEUE_REMOVE_HEAD(&prTxCtrl->rTxMgmtTxingQueue, prMsduInfo, + P_MSDU_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + if (prMsduInfo) { + DBGLOG(TX, + TRACE, + "%s: Get Msdu WIDX:PID[%u:%u] SEQ[%u] from Pending Q\n", + __func__, + prMsduInfo->ucWlanIndex, + prMsduInfo->ucPID, + prMsduInfo->ucTxSeqNum); + + /* invoke done handler */ + if (prMsduInfo->pfTxDoneHandler && + fgProcTxDoneHandler) { + prMsduInfo->pfTxDoneHandler( + prAdapter, prMsduInfo, + TX_RESULT_DROPPED_IN_DRIVER); + } + + nicTxFreeMsduInfoPacket(prAdapter, prMsduInfo); + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + } else { + break; + } + } while (true); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Process the TX Done interrupt and pull in more pending frames in SW + * Queues for transmission. + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicProcessTxInterrupt(IN P_ADAPTER_T prAdapter) +{ + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; + + halProcessTxInterrupt(prAdapter); + + /* Indicate Service Thread */ + if (kalGetTxPendingCmdCount(prAdapter->prGlueInfo) > 0 || + wlanGetTxPendingFrameCount(prAdapter) > 0) { + kalSetEvent(prAdapter->prGlueInfo); + } + + /* SER break point */ + if (nicSerIsTxStop(prAdapter)) { + /* Skip following Tx handling */ + return; + } + + /* TX Commands */ + if (kalGetTxPendingCmdCount(prAdapter->prGlueInfo)) { + wlanTxCmdMthread(prAdapter); + } + + /* Process TX data packet to HIF */ + if (nicTxGetMsduPendingCnt(prAdapter) >= prWifiVar->u4TxIntThCount) { + nicTxMsduQueueMthread(prAdapter); + } +} + +void nicTxFreePacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + IN u8 fgDrop) +{ + P_NATIVE_PACKET prNativePacket; + P_TX_CTRL_T prTxCtrl; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + + prNativePacket = prMsduInfo->prPacket; + + if (fgDrop) { + rStatus = WLAN_STATUS_FAILURE; + } + + if (prMsduInfo->eSrc == TX_PACKET_OS) { + if (prNativePacket) { + kalSendComplete(prAdapter->prGlueInfo, prNativePacket, + rStatus); + } + if (fgDrop) { + wlanUpdateTxStatistics(prAdapter, prMsduInfo, + true); /*get per-AC Tx drop + * packets */ + } + } else if (prMsduInfo->eSrc == TX_PACKET_MGMT) { + if (prMsduInfo->pfTxDoneHandler) { + prMsduInfo->pfTxDoneHandler( + prAdapter, prMsduInfo, + TX_RESULT_DROPPED_IN_DRIVER); + } + if (prNativePacket) { + cnmMemFree(prAdapter, prNativePacket); + } + } else if (prMsduInfo->eSrc == TX_PACKET_FORWARDING) { + GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief this function frees packet of P_MSDU_INFO_T linked-list + * + * @param prAdapter Pointer to the Adapter structure. + * @param prMsduInfoList a link list of P_MSDU_INFO_T + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicTxFreeMsduInfoPacket(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead) +{ + P_NATIVE_PACKET prNativePacket; + P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead; + P_TX_CTRL_T prTxCtrl; + + ASSERT(prAdapter); + ASSERT(prMsduInfoListHead); + + prTxCtrl = &prAdapter->rTxCtrl; + + while (prMsduInfo) { + prNativePacket = prMsduInfo->prPacket; + + nicTxFreePacket(prAdapter, prMsduInfo, true); + + prMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prMsduInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief this function returns P_MSDU_INFO_T of MsduInfoList to + * TxCtrl->rfreeMsduInfoList + * + * @param prAdapter Pointer to the Adapter structure. + * @param prMsduInfoList a link list of P_MSDU_INFO_T + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicTxReturnMsduInfo(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead, prNextMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + while (prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prMsduInfo); + + switch (prMsduInfo->eSrc) { + case TX_PACKET_FORWARDING: + wlanReturnPacket(prAdapter, prMsduInfo->prPacket); + break; + + case TX_PACKET_OS: + case TX_PACKET_OS_OID: + case TX_PACKET_MGMT: + default: + break; + } + + /* Reset MSDU_INFO fields */ + kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T)); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, + (P_QUE_ENTRY_T)prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + prMsduInfo = prNextMsduInfo; + } + ; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief this function fills packet information to P_MSDU_INFO_T + * + * @param prAdapter Pointer to the Adapter structure. + * @param prMsduInfo P_MSDU_INFO_T + * @param prPacket P_NATIVE_PACKET + * + * @retval true Success to extract information + * @retval false Fail to extract correct information + */ +/*----------------------------------------------------------------------------*/ +u8 nicTxFillMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + IN P_NATIVE_PACKET prPacket) +{ + P_GLUE_INFO_T prGlueInfo; + + ASSERT(prAdapter); + + kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T)); + + prGlueInfo = prAdapter->prGlueInfo; + ASSERT(prGlueInfo); + + kalGetEthDestAddr(prAdapter->prGlueInfo, prPacket, + prMsduInfo->aucEthDestAddr); + + prMsduInfo->prPacket = prPacket; + prMsduInfo->ucBssIndex = GLUE_GET_PKT_BSS_IDX(prPacket); + prMsduInfo->ucUserPriority = GLUE_GET_PKT_TID(prPacket); + prMsduInfo->ucMacHeaderLength = GLUE_GET_PKT_HEADER_LEN(prPacket); + prMsduInfo->u2FrameLength = (u16)GLUE_GET_PKT_FRAME_LEN(prPacket); + prMsduInfo->u4PageCount = 1; + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + if (IS_BMCAST_MAC_ADDR(prMsduInfo->aucEthDestAddr) && + prAdapter->fgIsMcastBurstMode) { + /* Force Multicast Burst mode set VI queue */ + prMsduInfo->ucUserPriority = NIC_TX_AC_VI_TID; // VI + } +#endif + if (GLUE_IS_PKT_FLAG_SET(prPacket)) { + prMsduInfo->fgIs802_1x = + GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_1X) ? true : + false; + prMsduInfo->fgIs802_1x_NonProtected = + GLUE_TEST_PKT_FLAG(prPacket, + ENUM_PKT_NON_PROTECTED_1X) ? + true : + false; + prMsduInfo->fgIs802_3 = + GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_802_3) ? true : + false; + prMsduInfo->fgIsVlanExists = + GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_VLAN_EXIST) ? + true : + false; + + if (GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_DHCP) && + prAdapter->rWifiVar.ucDhcpTxDone) { + prMsduInfo->pfTxDoneHandler = wlanDhcpTxDone; + } else if (GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_ARP) && + prAdapter->rWifiVar.ucArpTxDone) { + prMsduInfo->pfTxDoneHandler = wlanArpTxDone; + } else if (GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_1X)) { + prMsduInfo->pfTxDoneHandler = wlan1xTxDone; + nicTxSetPktLifeTime(prMsduInfo, 1500); + nicTxSetPktRetryLimit(prMsduInfo, + TX_DESC_TX_COUNT_NO_LIMIT); + } + + if (GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_DHCP) || + GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_ARP) || + GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_1X)) { + /* Set BSS/STA lowest basic rate */ + prMsduInfo->ucRateMode = MSDU_RATE_MODE_LOWEST_RATE; + + /* Set higher priority */ + prMsduInfo->ucUserPriority = NIC_TX_CRITICAL_DATA_TID; + } + } + + /* Add dummy Tx done */ + if ((prAdapter->rWifiVar.ucDataTxDone == 1) && + (prMsduInfo->pfTxDoneHandler == NULL)) { + prMsduInfo->pfTxDoneHandler = nicTxDummyTxDone; + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief this function update TCQ values by passing current status to + * txAdjustTcQuotas + * + * @param prAdapter Pointer to the Adapter structure. + * + * @retval WLAN_STATUS_SUCCESS Updated successfully + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxAdjustTcq(IN P_ADAPTER_T prAdapter) +{ + TX_TCQ_ADJUST_T rTcqAdjust; + P_TX_CTRL_T prTxCtrl; + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + qmAdjustTcQuotasMthread(prAdapter, &rTcqAdjust, &prTxCtrl->rTc); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief this function flushes all packets queued in STA/AC queue + * + * @param prAdapter Pointer to the Adapter structure. + * + * @retval WLAN_STATUS_SUCCESS Flushed successfully + */ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS nicTxFlush(IN P_ADAPTER_T prAdapter) +{ + P_MSDU_INFO_T prMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + + if (HAL_IS_TX_DIRECT(prAdapter)) { + nicTxDirectClearAllStaPsQ(prAdapter); + } else { + /* ask Per STA/AC queue to be fllushed and return all queued + * packets */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + prMsduInfo = qmFlushTxQueues(prAdapter); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + + if (prMsduInfo != NULL) { + nicTxFreeMsduInfoPacket(prAdapter, prMsduInfo); + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + } + } + + return WLAN_STATUS_SUCCESS; +} + +#if CFG_ENABLE_FW_DOWNLOAD +/*----------------------------------------------------------------------------*/ +/*! + * \brief In this function, we'll write Command(CMD_INFO_T) into HIF. + * However this function is used for INIT_CMD. + * + * In order to avoid further maintenance issues, these 2 functions are + * separated + * + * @param prAdapter Pointer to the Adapter structure. + * @param prPacketInfo Pointer of CMD_INFO_T + * @param ucTC Specify the resource of TC + * + * @retval WLAN_STATUS_SUCCESS Bus access ok. + * @retval WLAN_STATUS_FAILURE Bus access fail. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxInitCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) +{ + u16 u2OverallBufferLength; + u8 *pucOutputBuf = (u8 *)NULL; /* Pointer to Transmit Data Structure + * Frame */ + P_TX_CTRL_T prTxCtrl; + + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + prTxCtrl = &prAdapter->rTxCtrl; + pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; + u2OverallBufferLength = TFCB_FRAME_PAD_TO_DW( + (prCmdInfo->u2InfoBufLen) & (u16)HIF_TX_HDR_TX_BYTE_COUNT_MASK); + + /* <1> Copy CMD Header to command buffer (by using + * pucCoalescingBufCached) */ + kalMemCopy((void *)&pucOutputBuf[0], (void *)prCmdInfo->pucInfoBuffer, + prCmdInfo->u2InfoBufLen); + + ASSERT(u2OverallBufferLength <= prAdapter->u4CoalescingBufCachedSize); + + /* <2> Write frame to data port */ + HAL_WRITE_TX_PORT(prAdapter, NIC_TX_INIT_CMD_PORT, + (u32)u2OverallBufferLength, (u8 *)pucOutputBuf, + (u32)prAdapter->u4CoalescingBufCachedSize); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief In this function, we'll reset TX resource counter to initial value + * used in F/W download state + * + * @param prAdapter Pointer to the Adapter structure. + * + * @retval WLAN_STATUS_SUCCESS Reset is done successfully. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxInitResetResource(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; + u8 ucIdx; + + DEBUGFUNC("nicTxInitResetResource"); + + ASSERT(prAdapter); + prTxCtrl = &prAdapter->rTxCtrl; + + /* Delta page count */ + kalMemZero(prTxCtrl->rTc.au4TxDonePageCount, + sizeof(prTxCtrl->rTc.au4TxDonePageCount)); + kalMemZero(prTxCtrl->rTc.au4PreUsedPageCount, + sizeof(prTxCtrl->rTc.au4PreUsedPageCount)); + prTxCtrl->rTc.ucNextTcIdx = TC0_INDEX; + prTxCtrl->rTc.u4AvaliablePageCount = 0; + + /* Page count */ + prTxCtrl->rTc.au4MaxNumOfPage[TC0_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC0; + prTxCtrl->rTc.au4FreePageCount[TC0_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC0; + + prTxCtrl->rTc.au4MaxNumOfPage[TC1_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC1; + prTxCtrl->rTc.au4FreePageCount[TC1_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC1; + + prTxCtrl->rTc.au4MaxNumOfPage[TC2_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC2; + prTxCtrl->rTc.au4FreePageCount[TC2_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC2; + + prTxCtrl->rTc.au4MaxNumOfPage[TC3_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC3; + prTxCtrl->rTc.au4FreePageCount[TC3_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC3; + + prTxCtrl->rTc.au4MaxNumOfPage[TC4_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC4; + prTxCtrl->rTc.au4FreePageCount[TC4_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC4; + + prTxCtrl->rTc.au4MaxNumOfPage[TC5_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC5; + prTxCtrl->rTc.au4FreePageCount[TC5_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC5; + + /* Buffer count */ + for (ucIdx = TC0_INDEX; ucIdx < TC_NUM; ucIdx++) { + prTxCtrl->rTc.au4MaxNumOfBuffer[ucIdx] = + prTxCtrl->rTc.au4MaxNumOfPage[ucIdx] / + NIC_TX_MAX_PAGE_PER_FRAME; + prTxCtrl->rTc.au4FreeBufferCount[ucIdx] = + prTxCtrl->rTc.au4FreePageCount[ucIdx] / + NIC_TX_MAX_PAGE_PER_FRAME; + } + + return WLAN_STATUS_SUCCESS; +} + +#endif + +u8 nicTxProcessMngPacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + + if (prMsduInfo->eSrc != TX_PACKET_MGMT) { + return false; + } + + if (!prMsduInfo->prPacket) { + return false; + } + + if (!prMsduInfo->u2FrameLength) { + return false; + } + + if (!prMsduInfo->ucMacHeaderLength) { + return false; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + /* MMPDU: force stick to TC4 */ + prMsduInfo->ucTC = TC4_INDEX; + + /* No Tx descriptor template for MMPDU */ + prMsduInfo->fgIsTXDTemplateValid = false; + + /* Fixed Rate */ + if (prMsduInfo->ucRateMode == MSDU_RATE_MODE_AUTO) { + nicTxSetPktLowestFixedRate(prAdapter, prMsduInfo); + } + + nicTxFillDesc(prAdapter, prMsduInfo, prMsduInfo->aucTxDescBuffer, NULL); + return true; +} + +void nicTxProcessTxDoneEvent(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, IN u32 u4EventBufLen) +{ + P_EVENT_TX_DONE_T prTxDone; + P_MSDU_INFO_T prMsduInfo; +#if !DBG_DISABLE_ALL_LOG + u8 *apucBandwidt[4] = { (u8 *)"20", (u8 *)"40", (u8 *)"80", + (u8 *)"160/80+80" }; +#endif + if (u4EventBufLen < sizeof(EVENT_TX_DONE_T)) { + DBGLOG(INIT, ERROR, "%s: Invalid event length: %d < %d\n", + __func__, u4EventBufLen, sizeof(EVENT_TX_DONE_T)); + return; + } + prTxDone = (P_EVENT_TX_DONE_T)(prEvent->aucBuffer); + + if (prTxDone->ucFlag & BIT(TXS_WITH_ADVANCED_INFO)) { + /* Tx Done with advanced info */ + DBGLOG(NIC, + INFO, + "EVENT_ID_TX_DONE WIDX:PID[%u:%u] Status[%u] TID[%u] SN[%u] CNT[%u] RATE[0x%04x]\n", + prTxDone->ucWlanIndex, + prTxDone->ucPacketSeq, + prTxDone->ucStatus, + prTxDone->ucTid, + prTxDone->u2SequenceNumber, + prTxDone->ucTxCount, + prTxDone->u2TxRate); + + if (prTxDone->ucFlag & BIT(TXS_IS_EXIST)) { + u8 ucNss, ucStbc; + s8 icTxPwr; + + ucNss = (prTxDone->u2TxRate & TX_DESC_NSTS_MASK) >> + TX_DESC_NSTS_OFFSET; + ucNss += 1; + ucStbc = (prTxDone->u2TxRate & TX_DESC_STBC) ? true : + false; + + if (ucStbc) { + ucNss /= 2; + } + + DBGLOG(NIC, INFO, + "||BW[%s] NSS[%u] ArIdx[%u] RspRate[0x%02x]\n", + apucBandwidt[prTxDone->ucBandwidth], ucNss, + prTxDone->ucRateTableIdx, prTxDone->ucRspRate); + + icTxPwr = (s8)prTxDone->ucTxPower; + if (icTxPwr & BIT(6)) { + icTxPwr |= BIT(7); + } + + DBGLOG(NIC, + INFO, + "||AMPDU[%u] PS[%u] IBF[%u] EBF[%u] TxPwr[%d%sdBm] TSF[%u] TxDelay[%uus]\n", + prTxDone->u4AppliedFlag & + BIT(TX_FRAME_IN_AMPDU_FORMAT) ? + true : + false, + prTxDone->u4AppliedFlag & BIT(TX_FRAME_PS_BIT) ? + true : + false, + prTxDone->u4AppliedFlag & BIT(TX_FRAME_IMP_BF) ? + true : + false, + prTxDone->u4AppliedFlag & BIT(TX_FRAME_EXP_BF) ? + true : + false, + icTxPwr / 2, + icTxPwr & BIT(0) ? ".5" : "", + prTxDone->u4Timestamp, + prTxDone->u4TxDelay); + } + } else { + DBGLOG(NIC, INFO, + "EVENT_ID_TX_DONE WIDX:PID[%u:%u] Status[%u] SN[%u]\n", + prTxDone->ucWlanIndex, prTxDone->ucPacketSeq, + prTxDone->ucStatus, prTxDone->u2SequenceNumber); + } + + /* call related TX Done Handler */ + prMsduInfo = nicGetPendingTxMsduInfo(prAdapter, prTxDone->ucWlanIndex, + prTxDone->ucPacketSeq); + +#if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT + DBGLOG(NIC, TRACE, + "EVENT_ID_TX_DONE u4TimeStamp = %x u2AirDelay = %x\n", + prTxDone->au4Reserved1, prTxDone->au4Reserved2); + + wnmReportTimingMeas(prAdapter, prMsduInfo->ucStaRecIndex, + prTxDone->au4Reserved1, + prTxDone->au4Reserved1 + prTxDone->au4Reserved2); +#endif + + if (prMsduInfo) { + prMsduInfo->pfTxDoneHandler( + prAdapter, prMsduInfo, + (ENUM_TX_RESULT_CODE_T)(prTxDone->ucStatus)); + + if (prMsduInfo->eSrc == TX_PACKET_MGMT) { + if (prTxDone->ucStatus != TX_RESULT_SUCCESS) { + DBGLOG(NIC, + WARN, + "TX MGMT Frame Failed: WIDX:PID[%u:%u] Status[%u] SN[%u]\n", + prTxDone->ucWlanIndex, + prTxDone->ucPacketSeq, + prTxDone->ucStatus, + prTxDone->u2SequenceNumber); + } + + cnmMgtPktFree(prAdapter, prMsduInfo); + } else { + nicTxFreePacket(prAdapter, prMsduInfo, false); + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief this function enqueues MSDU_INFO_T into queue management, + * or command queue + * + * @param prAdapter Pointer to the Adapter structure. + * prMsduInfo Pointer to MSDU + * + * @retval WLAN_STATUS_SUCCESS Reset is done successfully. + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxEnqueueMsdu(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + P_TX_CTRL_T prTxCtrl; + P_MSDU_INFO_T prNextMsduInfo, prRetMsduInfo, prMsduInfoHead; + QUE_T qDataPort0, qDataPort1; + P_QUE_T prDataPort0, prDataPort1; + P_CMD_INFO_T prCmdInfo; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + + KAL_SPIN_LOCK_DECLARATION(); + +#if CFG_MESON_G12A_PATCH + if (prMsduInfo->u2FrameLength > 1514) { + DBGLOG(TX, ERROR, "TX: Frame length[%u] > 1514\n", + prMsduInfo->u2FrameLength); + return WLAN_STATUS_FAILURE; + } +#endif + + ASSERT(prAdapter); + ASSERT(prMsduInfo); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + prDataPort0 = &qDataPort0; + prDataPort1 = &qDataPort1; + + QUEUE_INITIALIZE(prDataPort0); + QUEUE_INITIALIZE(prDataPort1); + + /* check how many management frame are being queued */ + while (prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prMsduInfo); + + QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T)prMsduInfo) = NULL; + + if (prMsduInfo->eSrc == TX_PACKET_MGMT) { + if (nicTxProcessMngPacket(prAdapter, prMsduInfo)) { + /* Valid MGMT */ + QUEUE_INSERT_TAIL(prDataPort1, + (P_QUE_ENTRY_T)prMsduInfo); + } else { + /* Invalid MGMT */ + DBGLOG(TX, + WARN, + "Invalid MGMT[0x%p] BSS[%u] STA[%u],free it\n", + prMsduInfo, + prMsduInfo->ucBssIndex, + prMsduInfo->ucStaRecIndex); + + cnmMgtPktFree(prAdapter, prMsduInfo); + } + } else { + QUEUE_INSERT_TAIL(prDataPort0, + (P_QUE_ENTRY_T)prMsduInfo); + } + + prMsduInfo = prNextMsduInfo; + } + + if (prDataPort0->u4NumElem) { + /* send to QM */ + KAL_SPIN_LOCK_DECLARATION(); + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + prRetMsduInfo = qmEnqueueTxPackets( + prAdapter, (P_MSDU_INFO_T)QUEUE_GET_HEAD(prDataPort0)); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); + + /* post-process for dropped packets */ + if (prRetMsduInfo) { /* unable to enqueue */ + nicTxFreeMsduInfoPacket(prAdapter, prRetMsduInfo); + nicTxReturnMsduInfo(prAdapter, prRetMsduInfo); + } + } + + if (prDataPort1->u4NumElem) { + prMsduInfoHead = (P_MSDU_INFO_T)QUEUE_GET_HEAD(prDataPort1); + + if (nicTxGetFreeCmdCount(prAdapter) < + NIC_TX_CMD_INFO_RESERVED_COUNT) { + /* not enough descriptors for sending */ + u4Status = WLAN_STATUS_FAILURE; + + /* free all MSDUs */ + while (prMsduInfoHead) { + prNextMsduInfo = + (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY( + &prMsduInfoHead->rQueEntry); + + if (prMsduInfoHead->pfTxDoneHandler != NULL) { + prMsduInfoHead->pfTxDoneHandler( + prAdapter, prMsduInfoHead, + TX_RESULT_DROPPED_IN_DRIVER); + } + + cnmMgtPktFree(prAdapter, prMsduInfoHead); + + prMsduInfoHead = prNextMsduInfo; + } + } else { + /* send to command queue */ + while (prMsduInfoHead) { + prNextMsduInfo = + (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY( + &prMsduInfoHead->rQueEntry); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + SPIN_LOCK_CMD_RESOURCE); + QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, + prCmdInfo, P_CMD_INFO_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, + SPIN_LOCK_CMD_RESOURCE); + + if (prCmdInfo) { + GLUE_INC_REF_CNT( + prTxCtrl->i4TxMgmtPendingNum); + + kalMemZero(prCmdInfo, + sizeof(CMD_INFO_T)); + +#if CFG_ENABLE_PKT_LIFETIME_PROFILE + /* Tag MGMT enqueue time */ + GET_CURRENT_SYSTIME( + &prMsduInfoHead->rPktProfile + .rEnqueueTimestamp); +#endif + prCmdInfo->eCmdType = + COMMAND_TYPE_MANAGEMENT_FRAME; + prCmdInfo->u2InfoBufLen = + prMsduInfoHead->u2FrameLength; + prCmdInfo->pucInfoBuffer = NULL; + prCmdInfo->prMsduInfo = prMsduInfoHead; + prCmdInfo->pfCmdDoneHandler = NULL; + prCmdInfo->pfCmdTimeoutHandler = NULL; + prCmdInfo->fgIsOid = false; + prCmdInfo->fgSetQuery = true; + prCmdInfo->fgNeedResp = false; + prCmdInfo->ucCmdSeqNum = + prMsduInfoHead->ucTxSeqNum; + + DBGLOG(TX, + TRACE, + "%s: EN-Q MSDU[0x%p] SEQ[%u] BSS[%u] STA[%u] to CMD Q\n", + __func__, + prMsduInfoHead, + prMsduInfoHead->ucTxSeqNum, + prMsduInfoHead->ucBssIndex, + prMsduInfoHead->ucStaRecIndex); + + kalEnqueueCommand( + prAdapter->prGlueInfo, + (P_QUE_ENTRY_T)prCmdInfo); + } else { + /* Cmd free count is larger than + * expected, but allocation fail. */ + u4Status = WLAN_STATUS_FAILURE; + + if (prMsduInfoHead->pfTxDoneHandler != + NULL) { + prMsduInfoHead->pfTxDoneHandler( + prAdapter, + prMsduInfoHead, + TX_RESULT_DROPPED_IN_DRIVER); + } + + cnmMgtPktFree(prAdapter, + prMsduInfoHead); + } + + prMsduInfoHead = prNextMsduInfo; + } + } + } + + /* indicate service thread for sending */ + if (prTxCtrl->i4TxMgmtPendingNum > 0 || + kalGetTxPendingFrameCount(prAdapter->prGlueInfo) > 0) { + kalSetEvent(prAdapter->prGlueInfo); + } + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief this function returns WLAN index + * + * @param prAdapter Pointer to the Adapter structure. + * + * @retval + */ +/*----------------------------------------------------------------------------*/ +u8 nicTxGetWlanIdx(P_ADAPTER_T prAdapter, u8 ucBssIdx, u8 ucStaRecIdx) +{ + P_STA_RECORD_T prStaRec; + P_BSS_INFO_T prBssInfo; + u8 ucWlanIndex = NIC_TX_DEFAULT_WLAN_INDEX; + + prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIdx); + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIdx); + + if (prStaRec) { + ucWlanIndex = prStaRec->ucWlanIndex; + } else if ((ucStaRecIdx == STA_REC_INDEX_BMCAST) && + prBssInfo->fgIsInUse) { + if (prBssInfo->fgBcDefaultKeyExist) { + if (prBssInfo->wepkeyUsed[prBssInfo->ucBcDefaultKeyIdx] + && + prBssInfo->wepkeyWlanIdx < + NIC_TX_DEFAULT_WLAN_INDEX) { + ucWlanIndex = prBssInfo->wepkeyWlanIdx; + } else if (prBssInfo->ucBMCWlanIndexSUsed + [prBssInfo->ucBcDefaultKeyIdx]) { + ucWlanIndex = + prBssInfo->ucBMCWlanIndexS + [prBssInfo->ucBcDefaultKeyIdx]; + } + } else { + ucWlanIndex = prBssInfo->ucBMCWlanIndex; + } + } + + if (ucWlanIndex >= WTBL_SIZE) { + DBGLOG(TX, + WARN, + "%s: Unexpected WIDX[%u] BSS[%u] STA[%u], set WIDX to default value[%u]\n", + ucWlanIndex, + ucBssIdx, + ucStaRecIdx, + NIC_TX_DEFAULT_WLAN_INDEX); + + ucWlanIndex = NIC_TX_DEFAULT_WLAN_INDEX; + } + + return ucWlanIndex; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * @param prAdapter Pointer to the Adapter structure. + * + * @retval + */ +/*----------------------------------------------------------------------------*/ +u8 nicTxIsMgmtResourceEnough(IN P_ADAPTER_T prAdapter) +{ + if (nicTxGetFreeCmdCount(prAdapter) > (CFG_TX_MAX_CMD_PKT_NUM / 2)) { + return true; + }else{ + return false; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief this function returns available count in command queue + * + * @param prAdapter Pointer to the Adapter structure. + * + * @retval + */ +/*----------------------------------------------------------------------------*/ +u32 nicTxGetFreeCmdCount(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + return prAdapter->rFreeCmdList.u4NumElem; +} + +void nicTxSetMngPacket(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo, + u8 ucBssIndex, u8 ucStaRecIndex, u8 ucMacHeaderLength, + u16 u2FrameLength, PFN_TX_DONE_HANDLER pfTxDoneHandler, + u8 ucRateMode) +{ + ASSERT(prMsduInfo); + + prMsduInfo->ucBssIndex = ucBssIndex; + prMsduInfo->ucStaRecIndex = ucStaRecIndex; + prMsduInfo->ucMacHeaderLength = ucMacHeaderLength; + prMsduInfo->u2FrameLength = u2FrameLength; + prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; + prMsduInfo->ucRateMode = ucRateMode; + + /* Reset default value for MMPDU */ + prMsduInfo->fgIs802_11 = true; + prMsduInfo->fgIs802_1x = false; + prMsduInfo->fgIs802_1x_NonProtected = true; /*For data frame only, no + * sense for management + * frame*/ + prMsduInfo->u4FixedRateOption = 0; + prMsduInfo->cPowerOffset = 0; + prMsduInfo->u4Option = 0; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->ucPID = NIC_TX_DESC_PID_RESERVED; + prMsduInfo->ucPacketType = TX_PACKET_TYPE_MGMT; + prMsduInfo->ucUserPriority = 0; + prMsduInfo->eSrc = TX_PACKET_MGMT; +} + +void nicTxSetDataPacket(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo, + u8 ucBssIndex, u8 ucStaRecIndex, u8 ucMacHeaderLength, + u16 u2FrameLength, PFN_TX_DONE_HANDLER pfTxDoneHandler, + u8 ucRateMode, ENUM_TX_PACKET_SRC_T eSrc, u8 ucTID, + u8 fgIs802_11Frame, u8 fgIs1xFrame) +{ + ASSERT(prMsduInfo); + + prMsduInfo->ucBssIndex = ucBssIndex; + prMsduInfo->ucStaRecIndex = ucStaRecIndex; + prMsduInfo->ucMacHeaderLength = ucMacHeaderLength; + prMsduInfo->u2FrameLength = u2FrameLength; + prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; + prMsduInfo->ucRateMode = ucRateMode; + prMsduInfo->ucUserPriority = ucTID; + prMsduInfo->fgIs802_11 = fgIs802_11Frame; + prMsduInfo->eSrc = eSrc; + prMsduInfo->fgIs802_1x = fgIs1xFrame; + + /* Reset default value for data packet */ + prMsduInfo->u4FixedRateOption = 0; + prMsduInfo->cPowerOffset = 0; + prMsduInfo->u4Option = 0; + prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); + prMsduInfo->ucPID = NIC_TX_DESC_PID_RESERVED; + prMsduInfo->ucPacketType = TX_PACKET_TYPE_DATA; +} + +void nicTxFillDescByPktOption(P_MSDU_INFO_T prMsduInfo, + P_HW_MAC_TX_DESC_T prTxDesc) +{ + u32 u4PktOption = prMsduInfo->u4Option; + u8 fgIsLongFormat; + u8 fgProtected = false; + + /* Skip this function if no options is set */ + if (!u4PktOption) { + return; + } + + fgIsLongFormat = HAL_MAC_TX_DESC_IS_LONG_FORMAT(prTxDesc); + + /* Fields in DW0 and DW1 (Short Format) */ + if (u4PktOption & MSDU_OPT_NO_ACK) { + HAL_MAC_TX_DESC_SET_NO_ACK(prTxDesc); + } + + if (u4PktOption & MSDU_OPT_PROTECTED_FRAME) { + /* DBGLOG(RSN, INFO, "MSDU_OPT_PROTECTED_FRAME\n"); */ + HAL_MAC_TX_DESC_SET_PROTECTION(prTxDesc); + fgProtected = true; + } + + switch (HAL_MAC_TX_DESC_GET_HEADER_FORMAT(prTxDesc)) { + case HEADER_FORMAT_802_11_ENHANCE_MODE: + if (u4PktOption & MSDU_OPT_EOSP) { + HAL_MAC_TX_DESC_SET_EOSP(prTxDesc); + } + + if (u4PktOption & MSDU_OPT_AMSDU) { + HAL_MAC_TX_DESC_SET_AMSDU(prTxDesc); + } + break; + + case HEADER_FORMAT_NON_802_11: + if (u4PktOption & MSDU_OPT_EOSP) { + HAL_MAC_TX_DESC_SET_EOSP(prTxDesc); + } + + if (u4PktOption & MSDU_OPT_MORE_DATA) { + HAL_MAC_TX_DESC_SET_MORE_DATA(prTxDesc); + } + + if (u4PktOption & MSDU_OPT_REMOVE_VLAN) { + HAL_MAC_TX_DESC_SET_REMOVE_VLAN(prTxDesc); + } + break; + + case HEADER_FORMAT_802_11_NORMAL_MODE: + if (fgProtected && prMsduInfo->prPacket) { + P_WLAN_MAC_HEADER_T prWlanHeader = + (P_WLAN_MAC_HEADER_T)((unsigned long)(prMsduInfo + ->prPacket) + + + MAC_TX_RESERVED_FIELD); + + prWlanHeader->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; + } + break; + + default: + break; + } + + if (!fgIsLongFormat) { + return; + } + + /* Fields in DW2~6 (Long Format) */ + if (u4PktOption & MSDU_OPT_NO_AGGREGATE) { + HAL_MAC_TX_DESC_SET_BA_DISABLE(prTxDesc); + } + + if (u4PktOption & MSDU_OPT_TIMING_MEASURE) { + HAL_MAC_TX_DESC_SET_TIMING_MEASUREMENT(prTxDesc); + } + + if (u4PktOption & MSDU_OPT_NDP) { + HAL_MAC_TX_DESC_SET_NDP(prTxDesc); + } + + if (u4PktOption & MSDU_OPT_NDPA) { + HAL_MAC_TX_DESC_SET_NDPA(prTxDesc); + } + + if (u4PktOption & MSDU_OPT_SOUNDING) { + HAL_MAC_TX_DESC_SET_SOUNDING_FRAME(prTxDesc); + } + + if (u4PktOption & MSDU_OPT_FORCE_RTS) { + HAL_MAC_TX_DESC_SET_FORCE_RTS_CTS(prTxDesc); + } + + if (u4PktOption & MSDU_OPT_BIP) { + HAL_MAC_TX_DESC_SET_BIP(prTxDesc); + } + + /* SW field */ + if (u4PktOption & MSDU_OPT_SW_DURATION) { + HAL_MAC_TX_DESC_SET_DURATION_CONTROL_BY_SW(prTxDesc); + } + + if (u4PktOption & MSDU_OPT_SW_PS_BIT) { + HAL_MAC_TX_DESC_SET_SW_PM_CONTROL(prTxDesc); + } + + if (u4PktOption & MSDU_OPT_SW_HTC) { + HAL_MAC_TX_DESC_SET_HTC_EXIST(prTxDesc); + } + + if (u4PktOption & MSDU_OPT_MANUAL_SN) { + HAL_MAC_TX_DESC_SET_TXD_SN_VALID(prTxDesc); + HAL_MAC_TX_DESC_SET_SEQUENCE_NUMBER(prTxDesc, + prMsduInfo->u2SwSN); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Extra configuration for Tx packet + * + * @retval + */ +/*----------------------------------------------------------------------------*/ +void nicTxConfigPktOption(P_MSDU_INFO_T prMsduInfo, u32 u4OptionMask, + u8 fgSetOption) +{ + if (fgSetOption) { + prMsduInfo->u4Option |= u4OptionMask; + }else{ + prMsduInfo->u4Option &= ~u4OptionMask; + } +} + +void nicTxFillDescByPktControl(P_MSDU_INFO_T prMsduInfo, + P_HW_MAC_TX_DESC_T prTxDesc) +{ + u8 ucPktControl = prMsduInfo->ucControlFlag; + u8 ucSwReserved; + + /* Skip this function if no options is set */ + if (!ucPktControl) { + return; + } + + if (HAL_MAC_TX_DESC_IS_LONG_FORMAT(prTxDesc)) { + ucSwReserved = HAL_MAC_TX_DESC_GET_SW_RESERVED(prTxDesc); + + if (ucPktControl & MSDU_CONTROL_FLAG_FORCE_TX) { + ucSwReserved |= MSDU_CONTROL_FLAG_FORCE_TX; + } + + HAL_MAC_TX_DESC_SET_SW_RESERVED(prTxDesc, ucSwReserved); + } +} + +void nicTxConfigPktControlFlag(P_MSDU_INFO_T prMsduInfo, u8 ucControlFlagMask, + u8 fgSetFlag) +{ + /* Set control flag */ + if (fgSetFlag) { + prMsduInfo->ucControlFlag |= ucControlFlagMask; + } else { + prMsduInfo->ucControlFlag &= ~ucControlFlagMask; /* Clear + * control flag + */ + } +} + +void nicTxSetPktLifeTime(P_MSDU_INFO_T prMsduInfo, u32 u4TxLifeTimeInMs) +{ + prMsduInfo->u4RemainingLifetime = u4TxLifeTimeInMs; + prMsduInfo->u4Option |= MSDU_OPT_MANUAL_LIFE_TIME; +} + +void nicTxSetPktRetryLimit(P_MSDU_INFO_T prMsduInfo, u8 ucRetryLimit) +{ + prMsduInfo->ucRetryLimit = ucRetryLimit; + prMsduInfo->u4Option |= MSDU_OPT_MANUAL_RETRY_LIMIT; +} + +void nicTxSetPktPowerOffset(P_MSDU_INFO_T prMsduInfo, s8 cPowerOffset) +{ + prMsduInfo->cPowerOffset = cPowerOffset; + prMsduInfo->u4Option |= MSDU_OPT_MANUAL_POWER_OFFSET; +} + +void nicTxSetPktSequenceNumber(P_MSDU_INFO_T prMsduInfo, u16 u2SN) +{ + prMsduInfo->u2SwSN = u2SN; + prMsduInfo->u4Option |= MSDU_OPT_MANUAL_SN; +} + +void nicTxSetPktMacTxQue(P_MSDU_INFO_T prMsduInfo, u8 ucMacTxQue) +{ + u8 ucTcIdx; + + for (ucTcIdx = TC0_INDEX; ucTcIdx < TC_NUM; ucTcIdx++) + if (arTcResourceControl[ucTcIdx].ucDestQueueIndex == ucMacTxQue) { + break; + } + + if (ucTcIdx < TC_NUM) { + prMsduInfo->ucTC = ucTcIdx; + prMsduInfo->u4Option |= MSDU_OPT_MANUAL_TX_QUE; + } +} + +void nicTxSetPktFixedRateOptionFull(P_MSDU_INFO_T prMsduInfo, u16 u2RateCode, + u8 ucBandwidth, u8 fgShortGI, u8 fgLDPC, + u8 fgDynamicBwRts, u8 fgBeamforming, + u8 ucAntennaIndex) +{ + HW_MAC_TX_DESC_T rTxDesc; + P_HW_MAC_TX_DESC_T prTxDesc = &rTxDesc; + + kalMemZero(prTxDesc, NIC_TX_DESC_LONG_FORMAT_LENGTH); + + /* Follow the format of Tx descriptor DW 6 */ + HAL_MAC_TX_DESC_SET_FR_RATE(prTxDesc, u2RateCode); + + if (ucBandwidth) { + HAL_MAC_TX_DESC_SET_FR_BW(prTxDesc, ucBandwidth); + } + + if (fgBeamforming) { + HAL_MAC_TX_DESC_SET_FR_BF(prTxDesc); + } + + if (fgShortGI) { + HAL_MAC_TX_DESC_SET_FR_SHORT_GI(prTxDesc); + } + + if (fgLDPC) { + HAL_MAC_TX_DESC_SET_FR_LDPC(prTxDesc); + } + + if (fgDynamicBwRts) { + HAL_MAC_TX_DESC_SET_FR_DYNAMIC_BW_RTS(prTxDesc); + } + + HAL_MAC_TX_DESC_SET_FR_ANTENNA_ID(prTxDesc, ucAntennaIndex); + + /* Write back to RateOption of MSDU_INFO */ + HAL_MAC_TX_DESC_GET_DW(prTxDesc, 6, 1, &prMsduInfo->u4FixedRateOption); + + prMsduInfo->ucRateMode = MSDU_RATE_MODE_MANUAL_DESC; +} + +void nicTxSetPktFixedRateOption(P_MSDU_INFO_T prMsduInfo, u16 u2RateCode, + u8 ucBandwidth, u8 fgShortGI, + u8 fgDynamicBwRts) +{ + HW_MAC_TX_DESC_T rTxDesc; + P_HW_MAC_TX_DESC_T prTxDesc = &rTxDesc; + + kalMemZero(prTxDesc, NIC_TX_DESC_LONG_FORMAT_LENGTH); + + /* Follow the format of Tx descriptor DW 6 */ + HAL_MAC_TX_DESC_SET_FR_RATE(prTxDesc, u2RateCode); + + if (ucBandwidth) { + HAL_MAC_TX_DESC_SET_FR_BW(prTxDesc, ucBandwidth); + } + + if (fgShortGI) { + HAL_MAC_TX_DESC_SET_FR_SHORT_GI(prTxDesc); + } + + if (fgDynamicBwRts) { + HAL_MAC_TX_DESC_SET_FR_DYNAMIC_BW_RTS(prTxDesc); + } + + /* Write back to RateOption of MSDU_INFO */ + HAL_MAC_TX_DESC_GET_DW(prTxDesc, 6, 1, &prMsduInfo->u4FixedRateOption); + + prMsduInfo->ucRateMode = MSDU_RATE_MODE_MANUAL_DESC; +} + +void nicTxSetPktLowestFixedRate(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + P_STA_RECORD_T prStaRec = + cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + u8 ucRateSwIndex, ucRateIndex, ucRatePreamble; + u16 u2RateCode, u2RateCodeLimit, u2OperationalRateSet; + u32 u4CurrentPhyRate, u4Status; + + /* Not to use TxD template for fixed rate */ + prMsduInfo->fgIsTXDTemplateValid = false; + + /* Fixed Rate */ + prMsduInfo->ucRateMode = MSDU_RATE_MODE_MANUAL_DESC; + + if (prStaRec) { + u2RateCode = prStaRec->u2HwDefaultFixedRateCode; + u2OperationalRateSet = prStaRec->u2OperationalRateSet; + } else { + u2RateCode = prBssInfo->u2HwDefaultFixedRateCode; + u2OperationalRateSet = prBssInfo->u2OperationalRateSet; + } + + /* CoexPhyRateLimit is 0 means phy rate is unlimited */ + if (prBssInfo->u4CoexPhyRateLimit != 0) { + u4CurrentPhyRate = nicRateCode2PhyRate( + u2RateCode, FIX_BW_NO_FIXED, MAC_GI_NORMAL, AR_SS_NULL); + + if (prBssInfo->u4CoexPhyRateLimit > u4CurrentPhyRate) { + nicGetRateIndexFromRateSetWithLimit( + u2OperationalRateSet, + prBssInfo->u4CoexPhyRateLimit, true, + &ucRateSwIndex); + + /* Convert SW rate index to rate code */ + nicSwIndex2RateIndex(ucRateSwIndex, &ucRateIndex, + &ucRatePreamble); + u4Status = nicRateIndex2RateCode( + ucRatePreamble, ucRateIndex, &u2RateCodeLimit); + if (u4Status == WLAN_STATUS_SUCCESS) { + /* Replace by limitation rate */ + u2RateCode = u2RateCodeLimit; + DBGLOG(NIC, + INFO, + "Coex RatePreamble=%d, R_SW_IDX:%d, R_CODE:0x%x\n", + ucRatePreamble, + ucRateIndex, + u2RateCode); + } + } + } + nicTxSetPktFixedRateOption(prMsduInfo, u2RateCode, FIX_BW_NO_FIXED, + false, false); +} + +void nicTxSetPktMoreData(P_MSDU_INFO_T prCurrentMsduInfo, u8 fgSetMoreDataBit) +{ + P_WLAN_MAC_HEADER_T prWlanMacHeader = NULL; + + if (prCurrentMsduInfo->fgIs802_11) { + prWlanMacHeader = + (P_WLAN_MAC_HEADER_T)(((u8 *)(prCurrentMsduInfo + ->prPacket)) + + MAC_TX_RESERVED_FIELD); + } + + if (fgSetMoreDataBit) { + if (!prCurrentMsduInfo->fgIs802_11) { + prCurrentMsduInfo->u4Option |= MSDU_OPT_MORE_DATA; + }else{ + prWlanMacHeader->u2FrameCtrl |= MASK_FC_MORE_DATA; + } + } else { + if (!prCurrentMsduInfo->fgIs802_11) { + prCurrentMsduInfo->u4Option &= ~MSDU_OPT_MORE_DATA; + }else{ + prWlanMacHeader->u2FrameCtrl &= ~MASK_FC_MORE_DATA; + } + } +} + +u8 nicTxAssignPID(IN P_ADAPTER_T prAdapter, IN u8 ucWlanIndex) +{ + u8 ucRetval; + u8 *pucPidPool; + + ASSERT(prAdapter); + + pucPidPool = &prAdapter->aucPidPool[ucWlanIndex]; + + ucRetval = *pucPidPool; + + /* Driver side Tx Sequence number: 1~127 */ + (*pucPidPool)++; + + if (*pucPidPool > NIC_TX_DESC_DRIVER_PID_MAX) { + *pucPidPool = NIC_TX_DESC_DRIVER_PID_MIN; + } + + return ucRetval; +} + +void nicTxSetPktEOSP(P_MSDU_INFO_T prCurrentMsduInfo, u8 fgSetEOSPBit) +{ + P_WLAN_MAC_HEADER_QOS_T prWlanMacHeader = NULL; + u8 fgWriteToDesc = true; + + if (prCurrentMsduInfo->fgIs802_11) { + prWlanMacHeader = + (P_WLAN_MAC_HEADER_QOS_T)(((u8 *)(prCurrentMsduInfo + ->prPacket)) + + MAC_TX_RESERVED_FIELD); + fgWriteToDesc = false; + } + + if (fgSetEOSPBit) { + if (fgWriteToDesc) { + prCurrentMsduInfo->u4Option |= MSDU_OPT_EOSP; + }else{ + prWlanMacHeader->u2QosCtrl |= MASK_QC_EOSP; + } + } else { + if (fgWriteToDesc) { + prCurrentMsduInfo->u4Option &= ~MSDU_OPT_EOSP; + }else{ + prWlanMacHeader->u2QosCtrl &= ~MASK_QC_EOSP; + } + } +} + +WLAN_STATUS +nicTxDummyTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) +{ + DBGLOG(TX, TRACE, "Msdu WIDX:PID[%u:%u] SEQ[%u] Tx Status[%u]\n", + prMsduInfo->ucWlanIndex, prMsduInfo->ucPID, + prMsduInfo->ucTxSeqNum, rTxDoneStatus); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Update BSS Tx Params + * + * @param prStaRec The peer + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicTxUpdateBssDefaultRate(P_BSS_INFO_T prBssInfo) +{ + u8 ucLowestBasicRateIndex; + + prBssInfo->u2HwDefaultFixedRateCode = RATE_OFDM_6M; + + /* 4 <1> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ + if (rateGetLowestRateIndexFromRateSet(prBssInfo->u2BSSBasicRateSet, + &ucLowestBasicRateIndex)) { + nicRateIndex2RateCode(PREAMBLE_DEFAULT_LONG_NONE, + ucLowestBasicRateIndex, + &prBssInfo->u2HwDefaultFixedRateCode); + } else { + switch (prBssInfo->ucNonHTBasicPhyType) { + case PHY_TYPE_ERP_INDEX: + case PHY_TYPE_OFDM_INDEX: + prBssInfo->u2HwDefaultFixedRateCode = RATE_OFDM_6M; + break; + + default: + prBssInfo->u2HwDefaultFixedRateCode = RATE_CCK_1M_LONG; + break; + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Update StaRec Tx parameters + * + * @param prStaRec The peer + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicTxUpdateStaRecDefaultRate(P_STA_RECORD_T prStaRec) +{ + u8 ucLowestBasicRateIndex; + + prStaRec->u2HwDefaultFixedRateCode = RATE_OFDM_6M; + + /* 4 <1> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ + if (rateGetLowestRateIndexFromRateSet(prStaRec->u2BSSBasicRateSet, + &ucLowestBasicRateIndex)) { + nicRateIndex2RateCode(PREAMBLE_DEFAULT_LONG_NONE, + ucLowestBasicRateIndex, + &prStaRec->u2HwDefaultFixedRateCode); + } else { + if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11B) { + prStaRec->u2HwDefaultFixedRateCode = RATE_CCK_1M_LONG; + }else if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11G) { + prStaRec->u2HwDefaultFixedRateCode = RATE_OFDM_6M; + }else if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11A) { + prStaRec->u2HwDefaultFixedRateCode = RATE_OFDM_6M; + }else if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11N) { + prStaRec->u2HwDefaultFixedRateCode = RATE_MM_MCS_0; + } + } +} + +/* TX Direct functions : BEGIN */ + +/*----------------------------------------------------------------------------*/ +/* + * \brief This function is to start rTxDirectHifTimer to try to send out packets + * in rStaPsQueue[], rBssAbsentQueue[], rTxDirectHifQueue[]. + * + * \param[in] prAdapter Pointer of Adapter + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void nicTxDirectStartCheckQTimer(IN P_ADAPTER_T prAdapter) +{ + mod_timer(&prAdapter->rTxDirectHifTimer, jiffies + 1); +} + +void nicTxDirectClearSkbQ(IN P_ADAPTER_T prAdapter) +{ + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + struct sk_buff *prSkb; + + while (true) { + spin_lock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); + prSkb = skb_dequeue(&prAdapter->rTxDirectSkbQueue); + spin_unlock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); + if (prSkb == NULL) { + break; + } + + kalSendComplete(prGlueInfo, prSkb, WLAN_STATUS_NOT_ACCEPTED); + } +} + +void nicTxDirectClearHifQ(IN P_ADAPTER_T prAdapter) +{ + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + u8 ucHifTc = 0; + QUE_T rNeedToFreeQue; + P_QUE_T prNeedToFreeQue = &rNeedToFreeQue; + + QUEUE_INITIALIZE(prNeedToFreeQue); + + for (ucHifTc = 0; ucHifTc < TX_PORT_NUM; ucHifTc++) { + if (QUEUE_IS_NOT_EMPTY( + &prAdapter->rTxDirectHifQueue[ucHifTc])) { + spin_lock_bh( + &prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); + QUEUE_MOVE_ALL(prNeedToFreeQue, + &prAdapter->rTxDirectHifQueue[ucHifTc]); + spin_unlock_bh( + &prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); + + wlanProcessQueuedMsduInfo( + prAdapter, + (P_MSDU_INFO_T)QUEUE_GET_HEAD(prNeedToFreeQue)); + } + } +} + +void nicTxDirectClearStaPsQ(IN P_ADAPTER_T prAdapter, u8 ucStaRecIndex) +{ + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + QUE_T rNeedToFreeQue; + P_QUE_T prNeedToFreeQue = &rNeedToFreeQue; + + QUEUE_INITIALIZE(prNeedToFreeQue); + + if (QUEUE_IS_NOT_EMPTY(&prAdapter->rStaPsQueue[ucStaRecIndex])) { + spin_lock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); + QUEUE_MOVE_ALL(prNeedToFreeQue, + &prAdapter->rStaPsQueue[ucStaRecIndex]); + spin_unlock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); + + wlanProcessQueuedMsduInfo( + prAdapter, + (P_MSDU_INFO_T)QUEUE_GET_HEAD(prNeedToFreeQue)); + } +} + +void nicTxDirectClearBssAbsentQ(IN P_ADAPTER_T prAdapter, u8 ucBssIndex) +{ + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + QUE_T rNeedToFreeQue; + P_QUE_T prNeedToFreeQue = &rNeedToFreeQue; + + QUEUE_INITIALIZE(prNeedToFreeQue); + + if (QUEUE_IS_NOT_EMPTY(&prAdapter->rBssAbsentQueue[ucBssIndex])) { + spin_lock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); + QUEUE_MOVE_ALL(prNeedToFreeQue, + &prAdapter->rBssAbsentQueue[ucBssIndex]); + spin_unlock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); + + wlanProcessQueuedMsduInfo( + prAdapter, + (P_MSDU_INFO_T)QUEUE_GET_HEAD(prNeedToFreeQue)); + } +} + +void nicTxDirectClearAllStaPsQ(IN P_ADAPTER_T prAdapter) +{ + u8 ucStaRecIndex; + u32 u4StaPsBitmap; + + u4StaPsBitmap = prAdapter->u4StaPsBitmap; + if (!u4StaPsBitmap) { + return; + } + + for (ucStaRecIndex = 0; ucStaRecIndex < CFG_STA_REC_NUM; + ++ucStaRecIndex) { + if (QUEUE_IS_NOT_EMPTY( + &prAdapter->rStaPsQueue[ucStaRecIndex])) { + nicTxDirectClearStaPsQ(prAdapter, ucStaRecIndex); + u4StaPsBitmap &= ~BIT(ucStaRecIndex); + } + if (u4StaPsBitmap == 0) { + break; + } + } +} + +/*----------------------------------------------------------------------------*/ +/* + * \brief This function is to check the StaRec is in Ps or not, + * and store MsduInfo(s) or sent MsduInfo(s) to the next stage + * respectively. + * + * \param[in] prAdapter Pointer of Adapter + * \param[in] ucStaRecIndex Indictate which StaRec to be checked + * \param[in] prQue Pointer of MsduInfo queue which to be processed + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +static void nicTxDirectCheckStaPsQ(IN P_ADAPTER_T prAdapter, u8 ucStaRecIndex, + P_QUE_T prQue) +{ + P_STA_RECORD_T prStaRec; /* The current focused STA */ + P_MSDU_INFO_T prMsduInfo = + (P_MSDU_INFO_T)QUEUE_GET_HEAD(prQue); /* For checking if new + * coming 1x frame. */ + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + u8 fgReturnStaPsQ = false; + + if (ucStaRecIndex >= CFG_STA_REC_NUM) { + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIndex); + if (!prStaRec) { + DBGLOG(TX, WARN, "prStaRec is NULL!\n"); + return; + } + + if ((!prMsduInfo) || (!prMsduInfo->fgIs802_1x)) { + /* No new coming frame or non-1x frame would start from + * rStaPsQueue. */ + QUEUE_CONCATENATE_QUEUES(&prAdapter->rStaPsQueue[ucStaRecIndex], + prQue); + QUEUE_REMOVE_HEAD(&prAdapter->rStaPsQueue[ucStaRecIndex], + prQueueEntry, P_QUE_ENTRY_T); + } else { + /* New coming 1x frame has higher priority than packets in + * rStaPsQueue. */ + QUEUE_REMOVE_HEAD(prQue, prQueueEntry, P_QUE_ENTRY_T); + } + + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + + if (prMsduInfo == NULL) { + DBGLOG(TX, INFO, "prMsduInfo empty\n"); + return; + } + + if ((prStaRec->fgIsInPS) || + ((!prStaRec->fgIsTxAllowed) && (!prMsduInfo->fgIs802_1x))) { + /* Buffer packet if: + * 1. STA is under PS mode or + * 2. Non 1x frame not allowed to TX. (E.X.: Key invalid. + * Station record state incorrect) + */ + KAL_SPIN_LOCK_DECLARATION(); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + DBGLOG(TX, INFO, "fgIsInPS!\n"); + while (1) { + if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported && + (prStaRec->ucBmpTriggerAC & + BIT(prMsduInfo->ucTC))) { + if (prStaRec->ucFreeQuotaForDelivery > 0) { + prStaRec->ucFreeQuotaForDelivery--; + QUEUE_INSERT_TAIL( + prQue, + (P_QUE_ENTRY_T)prMsduInfo); + } else { + fgReturnStaPsQ = true; + break; + } + } else { + if (prStaRec->ucFreeQuotaForNonDelivery > 0) { + prStaRec->ucFreeQuotaForNonDelivery--; + QUEUE_INSERT_TAIL( + prQue, + (P_QUE_ENTRY_T)prMsduInfo); + } else { + fgReturnStaPsQ = true; + break; + } + } + if (QUEUE_IS_NOT_EMPTY( + &prAdapter->rStaPsQueue[ucStaRecIndex])) { + QUEUE_REMOVE_HEAD( + &prAdapter->rStaPsQueue[ucStaRecIndex], + prQueueEntry, P_QUE_ENTRY_T); + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + } else { + break; + } + } + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + if (fgReturnStaPsQ) { + QUEUE_INSERT_HEAD( + &prAdapter->rStaPsQueue[ucStaRecIndex], + (P_QUE_ENTRY_T)prMsduInfo); + prAdapter->u4StaPsBitmap |= BIT(ucStaRecIndex); + return; + } + } else if (prMsduInfo->fgIs802_1x) { + /* For 1x frame, STA not is PS case, we only TX 1x frame, not + * the whole queue. */ + QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T)prMsduInfo); + /* Leave the bitmap, it might be cleared in next round of check. + */ + return; + } else { + QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T)prMsduInfo); + if (QUEUE_IS_NOT_EMPTY( + &prAdapter->rStaPsQueue[ucStaRecIndex])) { + QUEUE_CONCATENATE_QUEUES( + prQue, &prAdapter->rStaPsQueue[ucStaRecIndex]); + } + } + prAdapter->u4StaPsBitmap &= ~BIT(ucStaRecIndex); +} + +/*----------------------------------------------------------------------------*/ +/* + * \brief This function is to check the Bss is net absent or not, + * and store MsduInfo(s) or sent MsduInfo(s) to the next stage + * respectively. + * + * \param[in] prAdapter Pointer of Adapter + * \param[in] ucBssIndex Indictate which Bss to be checked + * \param[in] prQue Pointer of MsduInfo queue which to be processed + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +static void nicTxDirectCheckBssAbsentQ(IN P_ADAPTER_T prAdapter, u8 ucBssIndex, + P_QUE_T prQue) +{ + P_BSS_INFO_T prBssInfo; + P_MSDU_INFO_T prMsduInfo; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + u8 fgReturnBssAbsentQ = false; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + QUEUE_CONCATENATE_QUEUES(&prAdapter->rBssAbsentQueue[ucBssIndex], + prQue); + QUEUE_REMOVE_HEAD(&prAdapter->rBssAbsentQueue[ucBssIndex], prQueueEntry, + P_QUE_ENTRY_T); + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + + if (prMsduInfo == NULL) { + DBGLOG(TX, INFO, "prMsduInfo empty\n"); + return; + } + + if (prBssInfo->fgIsNetAbsent) { + KAL_SPIN_LOCK_DECLARATION(); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + DBGLOG(TX, INFO, "fgIsNetAbsent!\n"); + while (1) { + if (prBssInfo->ucBssFreeQuota > 0) { + prBssInfo->ucBssFreeQuota--; + QUEUE_INSERT_TAIL(prQue, + (P_QUE_ENTRY_T)prMsduInfo); + DBGLOG(TX, INFO, + "fgIsNetAbsent Quota Availalbe\n"); + } else { + fgReturnBssAbsentQ = true; + DBGLOG(TX, INFO, "fgIsNetAbsent NoQuota\n"); + break; + } + if (QUEUE_IS_NOT_EMPTY( + &prAdapter->rBssAbsentQueue[ucBssIndex])) { + QUEUE_REMOVE_HEAD( + &prAdapter->rBssAbsentQueue[ucBssIndex], + prQueueEntry, P_QUE_ENTRY_T); + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + } else { + break; + } + } + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + if (fgReturnBssAbsentQ) { + QUEUE_INSERT_HEAD( + &prAdapter->rBssAbsentQueue[ucBssIndex], + (P_QUE_ENTRY_T)prMsduInfo); + prAdapter->u4BssAbsentBitmap |= BIT(ucBssIndex); + return; + } + } else { + if (prAdapter->u4BssAbsentBitmap) { + DBGLOG(TX, INFO, "fgIsNetAbsent END!\n"); + } + QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T)prMsduInfo); + if (QUEUE_IS_NOT_EMPTY( + &prAdapter->rBssAbsentQueue[ucBssIndex])) { + QUEUE_CONCATENATE_QUEUES( + prQue, &prAdapter->rBssAbsentQueue[ucBssIndex]); + } + } + prAdapter->u4BssAbsentBitmap &= ~BIT(ucBssIndex); +} + +/*----------------------------------------------------------------------------*/ +/* + * \brief Get Tc for hif port mapping. + * + * \param[in] prMsduInfo Pointer of the MsduInfo + * + * \retval Tc which maps to hif port. + */ +/*----------------------------------------------------------------------------*/ +static u8 nicTxDirectGetHifTc(P_MSDU_INFO_T prMsduInfo) +{ + u8 ucHifTc = 0; + + if (prMsduInfo->ucWmmQueSet != 0 /*DBDC_5G_WMM_INDEX*/) { + ucHifTc = TX_2G_WMM_PORT_NUM; + } else { + if (prMsduInfo->ucTC >= 0 && prMsduInfo->ucTC < TC_NUM) { + ucHifTc = prMsduInfo->ucTC; + }else{ + ASSERT(0); + } + } + return ucHifTc; +} + +/*----------------------------------------------------------------------------*/ +/* + * \brief This function is called by nicTxDirectStartXmit() and + * nicTxDirectTimerCheckHifQ(). It is the main function to send skb out on HIF + * bus. + * + * \param[in] prSkb Pointer of the sk_buff to be sent + * \param[in] prMsduInfo Pointer of the MsduInfo + * \param[in] prAdapter Pointer of Adapter + * \param[in] ucCheckTc Indictate which Tc HifQ to be checked + * \param[in] ucStaRecIndex Indictate which StaPsQ to be checked + * \param[in] ucBssIndex Indictate which BssAbsentQ to be checked + * + * \retval WLAN_STATUS + */ +/*----------------------------------------------------------------------------*/ +static WLAN_STATUS nicTxDirectStartXmitMain(struct sk_buff *prSkb, + P_MSDU_INFO_T prMsduInfo, + P_ADAPTER_T prAdapter, u8 ucCheckTc, + u8 ucStaRecIndex, u8 ucBssIndex) +{ + P_STA_RECORD_T prStaRec; /* The current focused STA */ + P_BSS_INFO_T prBssInfo; + u8 ucTC = 0, ucHifTc = 0; + P_QUE_T prTxQue; + u8 fgDropPacket = false; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + QUE_T rProcessingQue; + P_QUE_T prProcessingQue = &rProcessingQue; + + QUEUE_INITIALIZE(prProcessingQue); + + if (prSkb) { + nicTxFillMsduInfo(prAdapter, prMsduInfo, prSkb); + + /* Tx profiling */ + wlanTxProfilingTagMsdu(prAdapter, prMsduInfo, + TX_PROF_TAG_DRV_ENQUE); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, + prMsduInfo->ucBssIndex); + + if (!prBssInfo) { + /* No BSS_INFO or No STA_REC */ + fgDropPacket = true; + } else if (IS_BSS_ACTIVE(prBssInfo)) { + /* BSS active */ + fgDropPacket = false; + } else { + /* BSS inactive */ + fgDropPacket = true; + } + + if (fgDropPacket) { + DBGLOG(QM, TRACE, + "Drop the Packet for inactive Bss %u\n", + prMsduInfo->ucBssIndex); + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_31); + TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP); + + wlanProcessQueuedMsduInfo(prAdapter, prMsduInfo); + return WLAN_STATUS_FAILURE; + } + + qmDetermineStaRecIndex(prAdapter, prMsduInfo); + + wlanUpdateTxStatistics(prAdapter, prMsduInfo, false); /*get + * per-AC + * Tx + * packets + */ + + switch (prMsduInfo->ucStaRecIndex) { + case STA_REC_INDEX_BMCAST: + ucTC = arNetwork2TcResource[prMsduInfo->ucBssIndex] + [NET_TC_BMC_INDEX]; + + /* Always set BMC packet retry limit to unlimited */ + if (!(prMsduInfo->u4Option & + MSDU_OPT_MANUAL_RETRY_LIMIT)) { + nicTxSetPktRetryLimit( + prMsduInfo, TX_DESC_TX_COUNT_NO_LIMIT); + } + + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_23); + break; + + case STA_REC_INDEX_NOT_FOUND: + /* Drop packet if no STA_REC is found */ + DBGLOG(QM, TRACE, "Drop the Packet for no STA_REC\n"); + + TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_STA_DROP); + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_24); + wlanProcessQueuedMsduInfo(prAdapter, prMsduInfo); + return WLAN_STATUS_FAILURE; + + default: + prTxQue = qmDetermineStaTxQueue(prAdapter, prMsduInfo, + &ucTC); + break; /*default */ + } /* switch (prMsduInfo->ucStaRecIndex) */ + + prMsduInfo->ucTC = ucTC; + prMsduInfo->ucWmmQueSet = prBssInfo->ucWmmQueSet; /* to record + * WMM Set */ + + /* Check the Tx descriptor template is valid */ + qmSetTxPacketDescTemplate(prAdapter, prMsduInfo); + + /* Set Tx rate */ + switch (prAdapter->rWifiVar.ucDataTxRateMode) { + case DATA_RATE_MODE_BSS_LOWEST: + nicTxSetPktLowestFixedRate(prAdapter, prMsduInfo); + break; + + case DATA_RATE_MODE_MANUAL: + prMsduInfo->u4FixedRateOption = + prAdapter->rWifiVar.u4DataTxRateCode; + + prMsduInfo->ucRateMode = MSDU_RATE_MODE_MANUAL_DESC; + break; + + case DATA_RATE_MODE_AUTO: + default: + if (prMsduInfo->ucRateMode == + MSDU_RATE_MODE_LOWEST_RATE) { + nicTxSetPktLowestFixedRate(prAdapter, + prMsduInfo); + } + break; + } + + nicTxFillDataDesc(prAdapter, prMsduInfo); + + /* Drop invalid MsduInfo */ + if (unlikely(prMsduInfo->fgDrop)) { + nicTxDropInvalidMsduInfo(prAdapter, prMsduInfo); + return WLAN_STATUS_FAILURE; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, + prMsduInfo->ucStaRecIndex); + + QUEUE_INSERT_TAIL(prProcessingQue, (P_QUE_ENTRY_T)prMsduInfo); + + /* Power-save STA handling */ + nicTxDirectCheckStaPsQ(prAdapter, prMsduInfo->ucStaRecIndex, + prProcessingQue); + + /* Absent BSS handling */ + nicTxDirectCheckBssAbsentQ(prAdapter, prMsduInfo->ucBssIndex, + prProcessingQue); + + if (QUEUE_IS_EMPTY(prProcessingQue)) { + return WLAN_STATUS_SUCCESS; + } + + if (prProcessingQue->u4NumElem != 1) { + while (1) { + QUEUE_REMOVE_HEAD(prProcessingQue, prQueueEntry, + P_QUE_ENTRY_T); + if (prQueueEntry == NULL) { + break; + } + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + ucHifTc = nicTxDirectGetHifTc(prMsduInfo); + QUEUE_INSERT_TAIL( + &prAdapter->rTxDirectHifQueue[ucHifTc], + (P_QUE_ENTRY_T)prMsduInfo); + } + nicTxDirectStartCheckQTimer(prAdapter); + return WLAN_STATUS_SUCCESS; + } + + QUEUE_REMOVE_HEAD(prProcessingQue, prQueueEntry, P_QUE_ENTRY_T); + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + ucHifTc = nicTxDirectGetHifTc(prMsduInfo); + + if (QUEUE_IS_NOT_EMPTY( + &prAdapter->rTxDirectHifQueue[ucHifTc])) { + QUEUE_INSERT_TAIL( + &prAdapter->rTxDirectHifQueue[ucHifTc], + (P_QUE_ENTRY_T)prMsduInfo); + QUEUE_REMOVE_HEAD( + &prAdapter->rTxDirectHifQueue[ucHifTc], + prQueueEntry, P_QUE_ENTRY_T); + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + } + } else { + if (ucStaRecIndex != 0xff || ucBssIndex != 0xff) { + /* Power-save STA handling */ + if (ucStaRecIndex != 0xff) { + nicTxDirectCheckStaPsQ(prAdapter, ucStaRecIndex, + prProcessingQue); + } + + /* Absent BSS handling */ + if (ucBssIndex != 0xff) { + nicTxDirectCheckBssAbsentQ( + prAdapter, ucBssIndex, prProcessingQue); + } + + if (QUEUE_IS_EMPTY(prProcessingQue)) { + return WLAN_STATUS_SUCCESS; + } + + if (prProcessingQue->u4NumElem != 1) { + while (1) { + QUEUE_REMOVE_HEAD(prProcessingQue, + prQueueEntry, + P_QUE_ENTRY_T); + if (prQueueEntry == NULL) { + break; + } + prMsduInfo = + (P_MSDU_INFO_T)prQueueEntry; + ucHifTc = + nicTxDirectGetHifTc(prMsduInfo); + QUEUE_INSERT_TAIL( + &prAdapter->rTxDirectHifQueue + [ucHifTc], + (P_QUE_ENTRY_T)prMsduInfo); + } + nicTxDirectStartCheckQTimer(prAdapter); + return WLAN_STATUS_SUCCESS; + } + + QUEUE_REMOVE_HEAD(prProcessingQue, prQueueEntry, + P_QUE_ENTRY_T); + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + ucHifTc = nicTxDirectGetHifTc(prMsduInfo); + } else { + if (ucCheckTc != 0xff) { + ucHifTc = ucCheckTc; + } + + if (QUEUE_IS_EMPTY( + &prAdapter->rTxDirectHifQueue[ucHifTc])) { + DBGLOG(TX, INFO, + "ERROR: no rTxDirectHifQueue (%u)\n", + ucHifTc); + return WLAN_STATUS_FAILURE; + } + QUEUE_REMOVE_HEAD( + &prAdapter->rTxDirectHifQueue[ucHifTc], + prQueueEntry, P_QUE_ENTRY_T); + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + } + } + + while (1) { + if (prMsduInfo->pfTxDoneHandler) { + KAL_SPIN_LOCK_DECLARATION(); + + /* Record native packet pointer for Tx done log */ + WLAN_GET_FIELD_32(&prMsduInfo->prPacket, + &prMsduInfo->u4TxDoneTag); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TXING_MGMT_LIST); + QUEUE_INSERT_TAIL( + &(prAdapter->rTxCtrl.rTxMgmtTxingQueue), + (P_QUE_ENTRY_T)prMsduInfo); + KAL_RELEASE_SPIN_LOCK(prAdapter, + SPIN_LOCK_TXING_MGMT_LIST); + } + HAL_WRITE_TX_DATA(prAdapter, prMsduInfo); + + if (QUEUE_IS_NOT_EMPTY( + &prAdapter->rTxDirectHifQueue[ucHifTc])) { + QUEUE_REMOVE_HEAD( + &prAdapter->rTxDirectHifQueue[ucHifTc], + prQueueEntry, P_QUE_ENTRY_T); + prMsduInfo = (P_MSDU_INFO_T)prQueueEntry; + } else { + break; + } + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/* + * \brief This function is the timeout function of timer rTxDirectSkbTimer. + * The purpose is to check if rTxDirectSkbQueue has any skb to be sent. + * + * \param[in] data Pointer of GlueInfo + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +#if KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE +void nicTxDirectTimerCheckSkbQ(struct timer_list *timer) +#else +void nicTxDirectTimerCheckSkbQ(unsigned long data) +#endif +{ +#if KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE + struct _ADAPTER_T *prAdapter = + from_timer(prAdapter, timer, rTxDirectSkbTimer); + struct _GLUE_INFO_T *prGlueInfo = prAdapter->prGlueInfo; +#else + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)data; + P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; +#endif + + if (skb_queue_len(&prAdapter->rTxDirectSkbQueue)) { + nicTxDirectStartXmit(NULL, prGlueInfo); + }else{ + DBGLOG(TX, INFO, "fgHasNoMsdu false\n"); + } +} + +/*----------------------------------------------------------------------------*/ +/* + * \brief This function is the timeout function of timer rTxDirectHifTimer. + * The purpose is to check if rStaPsQueue, rBssAbsentQueue, and + * rTxDirectHifQueue has any MsduInfo to be sent. + * + * \param[in] data Pointer of GlueInfo + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +#if KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE +void nicTxDirectTimerCheckHifQ(struct timer_list *timer) +#else +void nicTxDirectTimerCheckHifQ(unsigned long data) +#endif +{ +#if KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE + struct _ADAPTER_T *prAdapter = + from_timer(prAdapter, timer, rTxDirectHifTimer); + struct _GLUE_INFO_T *prGlueInfo = prAdapter->prGlueInfo; +#else + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)data; + P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; +#endif + u8 ucHifTc = 0; + u32 u4StaPsBitmap, u4BssAbsentBitmap; + u8 ucStaRecIndex, ucBssIndex; + + spin_lock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); + + u4StaPsBitmap = prAdapter->u4StaPsBitmap; + u4BssAbsentBitmap = prAdapter->u4BssAbsentBitmap; + + if (u4StaPsBitmap) { + for (ucStaRecIndex = 0; ucStaRecIndex < CFG_STA_REC_NUM; + ++ucStaRecIndex) { + if (QUEUE_IS_NOT_EMPTY( + &prAdapter->rStaPsQueue[ucStaRecIndex])) { + nicTxDirectStartXmitMain(NULL, NULL, prAdapter, + 0xff, ucStaRecIndex, + 0xff); + u4StaPsBitmap &= ~BIT(ucStaRecIndex); + DBGLOG(TX, INFO, "ucStaRecIndex: %u\n", + ucStaRecIndex); + } + if (u4StaPsBitmap == 0) { + break; + } + } + } + + if (u4BssAbsentBitmap) { + for (ucBssIndex = 0; ucBssIndex < HW_BSSID_NUM + 1; + ++ucBssIndex) { + if (QUEUE_IS_NOT_EMPTY( + &prAdapter->rBssAbsentQueue[ucBssIndex])) { + nicTxDirectStartXmitMain(NULL, NULL, prAdapter, + 0xff, 0xff, + ucBssIndex); + u4BssAbsentBitmap &= ~BIT(ucBssIndex); + DBGLOG(TX, INFO, "ucBssIndex: %u\n", + ucBssIndex); + } + if (u4BssAbsentBitmap == 0) { + break; + } + } + } + + for (ucHifTc = 0; ucHifTc < TX_PORT_NUM; ucHifTc++) + if (QUEUE_IS_NOT_EMPTY( + &prAdapter->rTxDirectHifQueue[ucHifTc])) { + nicTxDirectStartXmitMain(NULL, NULL, prAdapter, ucHifTc, + 0xff, 0xff); + } + + spin_unlock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); +} + +/*----------------------------------------------------------------------------*/ +/* + * \brief This function is have to called by kalHardStartXmit(). The purpose is + * to let as many as possible TX processing in softirq instead of in + * kernel thread to reduce TX CPU usage. + * NOTE: Currently only USB interface can use this function. + * + * \param[in] prSkb Pointer of the sk_buff to be sent + * \param[in] prGlueInfo Pointer of prGlueInfo + * + * \retval WLAN_STATUS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS nicTxDirectStartXmit(struct sk_buff *prSkb, + P_GLUE_INFO_T prGlueInfo) +{ + P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; + P_MSDU_INFO_T prMsduInfo; + WLAN_STATUS ret = WLAN_STATUS_SUCCESS; + + spin_lock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); + + if (prSkb) { + prMsduInfo = cnmPktAlloc(prAdapter, 0); + + if (prMsduInfo == NULL) { + DBGLOG(TX, INFO, "cnmPktAlloc NULL\n"); + skb_queue_tail(&prAdapter->rTxDirectSkbQueue, prSkb); + + ret = WLAN_STATUS_SUCCESS; + goto end; + } + if (skb_queue_len(&prAdapter->rTxDirectSkbQueue)) { + skb_queue_tail(&prAdapter->rTxDirectSkbQueue, prSkb); + prSkb = skb_dequeue(&prAdapter->rTxDirectSkbQueue); + } + } else { + prMsduInfo = cnmPktAlloc(prAdapter, 0); + if (prMsduInfo != NULL) { + prSkb = skb_dequeue(&prAdapter->rTxDirectSkbQueue); + if (prSkb == NULL) { + DBGLOG(TX, INFO, + "ERROR: no rTxDirectSkbQueue\n"); + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + ret = WLAN_STATUS_FAILURE; + goto end; + } + } else { + ret = WLAN_STATUS_FAILURE; + goto end; + } + } + + while (1) { + nicTxDirectStartXmitMain(prSkb, prMsduInfo, prAdapter, 0xff, + 0xff, 0xff); + prSkb = skb_dequeue(&prAdapter->rTxDirectSkbQueue); + if (prSkb != NULL) { + prMsduInfo = cnmPktAlloc(prAdapter, 0); + if (prMsduInfo == NULL) { + skb_queue_head(&prAdapter->rTxDirectSkbQueue, + prSkb); + break; + } + } else { + break; + } + } + +end: + if (skb_queue_len(&prAdapter->rTxDirectSkbQueue)) { + mod_timer(&prAdapter->rTxDirectSkbTimer, + jiffies + TX_DIRECT_CHECK_INTERVAL); + } + spin_unlock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); + return ret; +} +/* TX Direct functions : END */ + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) +u8 nicTxGetWmmIdxByTc(u8 ucTC) +{ + u8 ucAc; + + /*get wmm set idex*/ + ucAc = arTcResourceControl[ucTC].ucDestQueueIndex; + return ucAc / WMM_AC_INDEX_NUM; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_umac.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_umac.c new file mode 100644 index 00000000000000..cd349cb00e8689 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/nic_umac.c @@ -0,0 +1,357 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file nic_umac.c + * \brief Functions that used for debug UMAC + * + * This file includes the functions used do umac debug + * + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#include "que_mgt.h" + +#include <linux/limits.h> + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef struct _UMAC_PG_INFO_AND_RESERVE_CNT_CR_OFFSET_MAP_T { + u8 ucGroupID; + u32 u4PgReservePageCntRegOffset; + u32 u4PgInfoRegOffset; +} UMAC_PG_INFO_AND_RESERVE_CNT_CR_OFFSET_MAP_T, +*P_UMAC_PG_INFO_AND_RESERVE_CNT_CR_OFFSET_MAP_T; + +typedef struct _UMAC_PG_MAX_MIN_QUOTA_SET_T { + u8 ucPageGroupID; + u16 u2MaxPageQuota; + u16 u2MinPageQuota; +} UMAC_PG_MAX_MIN_QUOTA_SET_T, *P_UMAC_PG_MAX_MIN_QUOTA_SET_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +const UMAC_PG_INFO_AND_RESERVE_CNT_CR_OFFSET_MAP_T + g_arPlePgInfoAndReserveCrOffsetMap[] = { + { UMAC_PG_HIF0_GROUP_0, + UMAC_PG_HIF0_GROUP(UMAC_PLE_CFG_POOL_INDEX), + UMAC_HIF0_PG_INFO(UMAC_PLE_CFG_POOL_INDEX) }, + { UMAC_PG_HIF0_GROUP_0, + UMAC_PG_HIF0_GROUP(UMAC_PLE_CFG_POOL_INDEX), + UMAC_HIF0_PG_INFO(UMAC_PLE_CFG_POOL_INDEX) }, + { UMAC_PG_CPU_GROUP_2, + UMAC_PG_CPU_GROUP(UMAC_PLE_CFG_POOL_INDEX), + UMAC_CPU_PG_INFO(UMAC_PLE_CFG_POOL_INDEX) }, +}; + +const UMAC_PG_INFO_AND_RESERVE_CNT_CR_OFFSET_MAP_T + g_arPsePgInfoAndReserveCrOffsetMap[] = { + { UMAC_PG_HIF0_GROUP_0, + UMAC_PG_HIF0_GROUP(UMAC_PSE_CFG_POOL_INDEX), + UMAC_HIF0_PG_INFO(UMAC_PSE_CFG_POOL_INDEX) }, + { UMAC_PG_HIF1_GROUP_1, + UMAC_PG_HIF1_GROUP(UMAC_PSE_CFG_POOL_INDEX), + UMAC_HIF1_PG_INFO(UMAC_PSE_CFG_POOL_INDEX) }, + { UMAC_PG_CPU_GROUP_2, + UMAC_PG_CPU_GROUP(UMAC_PSE_CFG_POOL_INDEX), + UMAC_CPU_PG_INFO(UMAC_PSE_CFG_POOL_INDEX) }, + { UMAC_PG_LMAC0_GROUP_3, + UMAC_PG_LMAC0_GROUP(UMAC_PSE_CFG_POOL_INDEX), + UMAC_LMAC0_PG_INFO(UMAC_PSE_CFG_POOL_INDEX) }, + { UMAC_PG_LMAC1_GROUP_4, + UMAC_PG_LMAC1_GROUP(UMAC_PSE_CFG_POOL_INDEX), + UMAC_LMAC1_PG_INFO(UMAC_PSE_CFG_POOL_INDEX) }, + { UMAC_PG_LMAC2_GROUP_5, + UMAC_PG_LMAC2_GROUP(UMAC_PSE_CFG_POOL_INDEX), + UMAC_LMAC2_PG_INFO(UMAC_PSE_CFG_POOL_INDEX) }, + { UMAC_PG_PLE_GROUP_6, + UMAC_PG_PLE_GROUP(UMAC_PSE_CFG_POOL_INDEX), + UMAC_PLE_PG_INFO(UMAC_PSE_CFG_POOL_INDEX) }, +}; + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief halUmacWrapSourcePortSanityCheck: + * + * @param IN u8 fgPsePleFlag, + * IN u8 ucPageGroupID + * @return true/false + */ +/*----------------------------------------------------------------------------*/ + +OUT u8 halUmacWrapSourcePortSanityCheck(IN u8 fgPsePleFlag, + IN u8 ucPageGroupID) +{ + if (fgPsePleFlag == UMAC_PSE_CFG_POOL_INDEX) { + if (ucPageGroupID > UMAC_PG_PLE_GROUP_6) { + return false; + } + } else if (fgPsePleFlag == UMAC_PLE_CFG_POOL_INDEX) { + if ((ucPageGroupID != UMAC_PG_HIF0_GROUP_0) && + (ucPageGroupID != UMAC_PG_CPU_GROUP_2)) { + return false; + } + } else { + return false; + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief halUmacWrapRsvPgCnt: + * + * @param IN P_ADAPTER_T prAdapter + * IN u8 fgPsePleFlag, + * IN u8 ucPageGroupID + * @return u16 + */ +/*----------------------------------------------------------------------------*/ + +OUT u16 halUmacWrapRsvPgCnt(IN P_ADAPTER_T prAdapter, IN u8 fgPsePleFlag, + IN u8 ucPageGroupID) +{ + u32 u4RegAddr = 0; + u32 u4Value = 0; + + if (halUmacWrapSourcePortSanityCheck(fgPsePleFlag, ucPageGroupID) == + false) { + return UMAC_FID_FAULT; + } + + if (fgPsePleFlag == UMAC_PSE_CFG_POOL_INDEX) { + u4RegAddr = g_arPsePgInfoAndReserveCrOffsetMap[ucPageGroupID] + .u4PgInfoRegOffset; + } else if (fgPsePleFlag == UMAC_PLE_CFG_POOL_INDEX) { + u4RegAddr = g_arPlePgInfoAndReserveCrOffsetMap[ucPageGroupID] + .u4PgInfoRegOffset; + } + + HAL_MCR_RD(prAdapter, u4RegAddr, &u4Value); + + return (u16)(u4Value & BITS(0, 11)); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief halUmacWrapSrcPgCnt: + * + * @param IN P_ADAPTER_T prAdapter + * IN u8 fgPsePleFlag, + * IN u8 ucPageGroupID + * @return u16 + */ +/*----------------------------------------------------------------------------*/ + +OUT u16 halUmacWrapSrcPgCnt(IN P_ADAPTER_T prAdapter, IN u8 fgPsePleFlag, + IN u8 ucPageGroupID) +{ + u32 u4RegAddr = 0; + u32 u4Value = 0; + + if (halUmacWrapSourcePortSanityCheck(fgPsePleFlag, ucPageGroupID) == + false) { + return UMAC_FID_FAULT; + } + + if (fgPsePleFlag == UMAC_PSE_CFG_POOL_INDEX) { + u4RegAddr = g_arPsePgInfoAndReserveCrOffsetMap[ucPageGroupID] + .u4PgInfoRegOffset; + } else if (fgPsePleFlag == UMAC_PLE_CFG_POOL_INDEX) { + u4RegAddr = g_arPlePgInfoAndReserveCrOffsetMap[ucPageGroupID] + .u4PgInfoRegOffset; + } + + HAL_MCR_RD(prAdapter, u4RegAddr, &u4Value); + + return (u16)((u4Value & BITS(16, 27)) >> 16); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief halUmacPbufCtrlTotalPageNum: + * + * @param IN P_ADAPTER_T prAdapter + * IN u8 fgPsePleFlag, + * @return u16 + */ +/*----------------------------------------------------------------------------*/ + +OUT u16 halUmacPbufCtrlTotalPageNum(IN P_ADAPTER_T prAdapter, + IN u16 fgPsePleFlag) +{ + u32 u4Value = 0; + + HAL_MCR_RD(prAdapter, UMAC_PBUF_CTRL(fgPsePleFlag), &u4Value); + + return (u16)(u4Value & UMAC_PBUF_CTRL_TOTAL_PAGE_NUM_MASK); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief halUmacWrapFrePageCnt: + * + * @param IN P_ADAPTER_T prAdapter + * IN u8 fgPsePleFlag, + * @return u16 + */ +/*----------------------------------------------------------------------------*/ + +OUT u16 halUmacWrapFrePageCnt(IN P_ADAPTER_T prAdapter, IN u8 fgPsePleFlag) +{ + u32 u4Value = 0; + + HAL_MCR_RD(prAdapter, UMAC_FREEPG_CNT(fgPsePleFlag), &u4Value); + return (u4Value & UMAC_FREEPG_CNT_FREEPAGE_CNT_MASK) >> + UMAC_FREEPG_CNT_FREEPAGE_CNT_OFFSET; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief halUmacWrapFfaCnt: + * + * @param IN P_ADAPTER_T prAdapter + * IN u8 fgPsePleFlag, + * @return u16 + */ +/*----------------------------------------------------------------------------*/ + +OUT u16 halUmacWrapFfaCnt(IN P_ADAPTER_T prAdapter, IN u8 fgPsePleFlag) +{ + u32 u4Value = 0; + + HAL_MCR_RD(prAdapter, UMAC_FREEPG_CNT(fgPsePleFlag), &u4Value); + return (u4Value & UMAC_FREEPG_CNT_FFA_CNT_MASK) >> + UMAC_FREEPG_CNT_FFA_CNT_OFFSET; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief halUmacInfoGetMiscStatus: + * + * @param IN P_ADAPTER_T prAdapter + * IN P_UMAC_STAT2_GET_T pUmacStat2Get, + * @return u16 + */ +/*----------------------------------------------------------------------------*/ + +OUT u8 halUmacInfoGetMiscStatus(IN P_ADAPTER_T prAdapter, + IN P_UMAC_STAT2_GET_T pUmacStat2Get) +{ + pUmacStat2Get->u2PleRevPgHif0Group0 = halUmacWrapRsvPgCnt( + prAdapter, UMAC_PLE_CFG_POOL_INDEX, UMAC_PG_HIF0_GROUP_0); + + pUmacStat2Get->u2PleRevPgCpuGroup2 = halUmacWrapRsvPgCnt( + prAdapter, UMAC_PLE_CFG_POOL_INDEX, UMAC_PG_CPU_GROUP_2); + + pUmacStat2Get->u2PseRevPgHif0Group0 = halUmacWrapRsvPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_HIF0_GROUP_0); + + pUmacStat2Get->u2PseRevPgHif1Group1 = halUmacWrapRsvPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_HIF1_GROUP_1); + + pUmacStat2Get->u2PseRevPgCpuGroup2 = halUmacWrapRsvPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_CPU_GROUP_2); + + pUmacStat2Get->u2PseRevPgLmac0Group3 = halUmacWrapRsvPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_LMAC0_GROUP_3); + + pUmacStat2Get->u2PseRevPgLmac1Group4 = halUmacWrapRsvPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_LMAC1_GROUP_4); + + pUmacStat2Get->u2PseRevPgLmac2Group5 = halUmacWrapRsvPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_LMAC2_GROUP_5); + + pUmacStat2Get->u2PseRevPgPleGroup6 = halUmacWrapRsvPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_PLE_GROUP_6); + + pUmacStat2Get->u2PleSrvPgHif0Group0 = halUmacWrapSrcPgCnt( + prAdapter, UMAC_PLE_CFG_POOL_INDEX, UMAC_PG_HIF0_GROUP_0); + + pUmacStat2Get->u2PleSrvPgCpuGroup2 = halUmacWrapSrcPgCnt( + prAdapter, UMAC_PLE_CFG_POOL_INDEX, UMAC_PG_CPU_GROUP_2); + + pUmacStat2Get->u2PseSrvPgHif0Group0 = halUmacWrapSrcPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_HIF0_GROUP_0); + + pUmacStat2Get->u2PseSrvPgHif1Group1 = halUmacWrapSrcPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_HIF1_GROUP_1); + + pUmacStat2Get->u2PseSrvPgCpuGroup2 = halUmacWrapSrcPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_CPU_GROUP_2); + + pUmacStat2Get->u2PseSrvPgLmac0Group3 = halUmacWrapSrcPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_LMAC0_GROUP_3); + + pUmacStat2Get->u2PseSrvPgLmac1Group4 = halUmacWrapSrcPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_LMAC1_GROUP_4); + + pUmacStat2Get->u2PseSrvPgLmac2Group5 = halUmacWrapSrcPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_LMAC2_GROUP_5); + + pUmacStat2Get->u2PseSrvPgPleGroup6 = halUmacWrapSrcPgCnt( + prAdapter, UMAC_PSE_CFG_POOL_INDEX, UMAC_PG_PLE_GROUP_6); + + pUmacStat2Get->u2PleTotalPageNum = + halUmacPbufCtrlTotalPageNum(prAdapter, UMAC_PLE_CFG_POOL_INDEX); + + pUmacStat2Get->u2PseTotalPageNum = + halUmacPbufCtrlTotalPageNum(prAdapter, UMAC_PSE_CFG_POOL_INDEX); + + pUmacStat2Get->u2PleFreePageNum = + halUmacWrapFrePageCnt(prAdapter, UMAC_PLE_CFG_POOL_INDEX); + + pUmacStat2Get->u2PseFreePageNum = + halUmacWrapFrePageCnt(prAdapter, UMAC_PSE_CFG_POOL_INDEX); + + pUmacStat2Get->u2PleFfaNum = + halUmacWrapFfaCnt(prAdapter, UMAC_PLE_CFG_POOL_INDEX); + + pUmacStat2Get->u2PseFfaNum = + halUmacWrapFfaCnt(prAdapter, UMAC_PSE_CFG_POOL_INDEX); + + return true; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/p2p_nic.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/p2p_nic.c new file mode 100644 index 00000000000000..cdb7414541d59c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/p2p_nic.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file p2p_nic.c + * \brief Wi-Fi Direct Functions that provide operation in NIC's (Network + * Interface Card) point of view. + * + * This file includes functions which unite multiple hal(Hardware) operations + * and also take the responsibility of Software Resource Management in order + * to keep the synchronization with Hardware Manipulation. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief When Probe Rsp & Beacon frame is received and decide a P2P device, + * this function will be invoked to buffer scan result + * + * @param prAdapter Pointer to the Adapter structure. + * @param prEventScanResult Pointer of EVENT_SCAN_RESULT_T. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void nicRxAddP2pDevice(IN P_ADAPTER_T prAdapter, + IN P_EVENT_P2P_DEV_DISCOVER_RESULT_T prP2pResult, + IN u8 *pucRxIEBuf, IN u16 u2RxIELength) +{ + P_P2P_INFO_T prP2pInfo = (P_P2P_INFO_T)NULL; + P_EVENT_P2P_DEV_DISCOVER_RESULT_T prTargetResult = + (P_EVENT_P2P_DEV_DISCOVER_RESULT_T)NULL; + u32 u4Idx = 0; + u8 bUpdate = false; + + u8 *pucIeBuf = (u8 *)NULL; + u16 u2IELength = 0; + u8 zeroMac[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + + ASSERT(prAdapter); + + prP2pInfo = prAdapter->prP2pInfo; + + for (u4Idx = 0; u4Idx < prP2pInfo->u4DeviceNum; u4Idx++) { + prTargetResult = &prP2pInfo->arP2pDiscoverResult[u4Idx]; + + if (EQUAL_MAC_ADDR(prTargetResult->aucDeviceAddr, + prP2pResult->aucDeviceAddr)) { + bUpdate = true; + + /* Backup OLD buffer result. */ + pucIeBuf = prTargetResult->pucIeBuf; + u2IELength = prTargetResult->u2IELength; + + /* Update Device Info. */ + /* zero */ + kalMemZero(prTargetResult, + sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); + + /* then buffer */ + kalMemCopy(prTargetResult, (void *)prP2pResult, + sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); + + /* See if new IE length is longer or not. */ + if ((u2RxIELength > u2IELength) && (u2IELength != 0)) { + /* Buffer is not enough. */ + u2RxIELength = u2IELength; + } else if ((u2IELength == 0) && (u2RxIELength != 0)) { + /* RX new IE buf. */ + ASSERT(pucIeBuf == NULL); + pucIeBuf = prP2pInfo->pucCurrIePtr; + + if (((unsigned long)prP2pInfo->pucCurrIePtr + + (unsigned long)u2RxIELength) > + (unsigned long)&prP2pInfo->aucCommIePool + [CFG_MAX_COMMON_IE_BUF_LEN]) { + /* Common Buffer is no enough. */ + u2RxIELength = + (u16)((unsigned long)&prP2pInfo->aucCommIePool + [CFG_MAX_COMMON_IE_BUF_LEN] - + (unsigned long)prP2pInfo + ->pucCurrIePtr); + } + + /* Step to next buffer address. */ + prP2pInfo->pucCurrIePtr = + (u8 *)((unsigned long) + prP2pInfo->pucCurrIePtr + + (unsigned long)u2RxIELength); + } + + /* Restore buffer pointer. */ + prTargetResult->pucIeBuf = pucIeBuf; + + if (pucRxIEBuf) { + /* If new received IE is available. + * Replace the old one & update new IE length. + */ + kalMemCopy(pucIeBuf, pucRxIEBuf, u2RxIELength); + prTargetResult->u2IELength = u2RxIELength; + } else { + /* There is no new IE information, keep the old + * one. */ + prTargetResult->u2IELength = u2IELength; + } + } + } + + if (!bUpdate) { + /* We would flush the whole scan result after each scan request + * is issued. If P2P device is too many, it may over the scan + * list. + */ + if ((u4Idx < CFG_MAX_NUM_BSS_LIST) && + (UNEQUAL_MAC_ADDR(zeroMac, prP2pResult->aucDeviceAddr))) { + prTargetResult = &prP2pInfo->arP2pDiscoverResult[u4Idx]; + + /* zero */ + kalMemZero(prTargetResult, + sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); + + /* then buffer */ + kalMemCopy(prTargetResult, (void *)prP2pResult, + sizeof(EVENT_P2P_DEV_DISCOVER_RESULT_T)); + + /** + * printk("DVC FND %d " MACSTR", " MACSTR "\n", + * prP2pInfo->u4DeviceNum, MAC2STR(prP2pResult->aucDeviceAddr), + * MAC2STR(prTargetResult->aucDeviceAddr)); + */ + + if (u2RxIELength) { + prTargetResult->pucIeBuf = + prP2pInfo->pucCurrIePtr; + + if (((unsigned long)prP2pInfo->pucCurrIePtr + + (unsigned long)u2RxIELength) > + (unsigned long)&prP2pInfo->aucCommIePool + [CFG_MAX_COMMON_IE_BUF_LEN]) { + /* Common Buffer is no enough. */ + u2IELength = + (u16)((unsigned long)&prP2pInfo->aucCommIePool + [CFG_MAX_COMMON_IE_BUF_LEN] - + (unsigned long)prP2pInfo + ->pucCurrIePtr); + } else { + u2IELength = u2RxIELength; + } + + prP2pInfo->pucCurrIePtr = + (u8 *)((unsigned long)prP2pInfo + ->pucCurrIePtr + + (unsigned long)u2IELength); + + kalMemCopy((void *)prTargetResult->pucIeBuf, + (void *)pucRxIEBuf, + (u32)u2IELength); + prTargetResult->u2IELength = u2IELength; + } else { + prTargetResult->pucIeBuf = NULL; + prTargetResult->u2IELength = 0; + } + + prP2pInfo->u4DeviceNum++; + } else { + /* TODO: Fixme to replace an old one. (?) */ + ASSERT(false); + } + } +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/que_mgt.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/que_mgt.c new file mode 100644 index 00000000000000..2205e1ca3c5df5 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/nic/que_mgt.c @@ -0,0 +1,7151 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "que_mgt.c" + * \brief TX/RX queues management + * + * The main tasks of queue management include TC-based HIF TX flow control, + * adaptive TC quota adjustment, HIF TX grant scheduling, Power-Save + * forwarding control, RX packet reordering, and RX BA agreement management. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#include "queue.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +u32 g_arMissTimeout[CFG_STA_REC_NUM][CFG_RX_MAX_BA_TID_NUM]; + +const u8 aucTid2ACI[TX_DESC_TID_NUM] = { + WMM_AC_BE_INDEX, /* TID0 */ + WMM_AC_BK_INDEX, /* TID1 */ + WMM_AC_BK_INDEX, /* TID2 */ + WMM_AC_BE_INDEX, /* TID3 */ + WMM_AC_VI_INDEX, /* TID4 */ + WMM_AC_VI_INDEX, /* TID5 */ + WMM_AC_VO_INDEX, /* TID6 */ + WMM_AC_VO_INDEX /* TID7 */ +}; + +const u8 aucACI2TxQIdx[WMM_AC_INDEX_NUM] = { + TX_QUEUE_INDEX_AC1, /* WMM_AC_BE_INDEX */ + TX_QUEUE_INDEX_AC0, /* WMM_AC_BK_INDEX */ + TX_QUEUE_INDEX_AC2, /* WMM_AC_VI_INDEX */ + TX_QUEUE_INDEX_AC3 /* WMM_AC_VO_INDEX */ +}; + +const u8 *apucACI2Str[WMM_AC_INDEX_NUM] = { "BE", "BK", "VI", "VO" }; + +u8 arNetwork2TcResource[HW_BSSID_NUM + 1][NET_TC_NUM] = { + /* HW Queue Set 1 */ + /* AC_BE, AC_BK, AC_VI, AC_VO, MGMT, BMC */ + { TC1_INDEX, TC0_INDEX, TC2_INDEX, TC3_INDEX, TC4_INDEX, + BMC_TC_INDEX }, /* AIS */ + { TC1_INDEX, TC0_INDEX, TC2_INDEX, TC3_INDEX, TC4_INDEX, + BMC_TC_INDEX }, /* P2P/BoW */ + { TC1_INDEX, TC0_INDEX, TC2_INDEX, TC3_INDEX, TC4_INDEX, + BMC_TC_INDEX }, /* P2P/BoW */ + { TC1_INDEX, TC0_INDEX, TC2_INDEX, TC3_INDEX, TC4_INDEX, + BMC_TC_INDEX }, /* P2P/BoW */ + { TC1_INDEX, TC0_INDEX, TC2_INDEX, TC3_INDEX, TC4_INDEX, + BMC_TC_INDEX }, /* P2P_DEV */ + + /* HW Queue Set 2 */ + /* {TC7_INDEX, TC6_INDEX, TC8_INDEX, TC9_INDEX, TC4_INDEX, TC10_INDEX}, + */ +}; + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) +/* tx resource for multilpe wmm looks up this remap table */ +#define TC_NUM_PER_WMM WMM_AC_INDEX_NUM +const u8 arTcRemapTable[HW_WMM_NUM][TC_NUM_PER_WMM] = { + { TC0_INDEX, TC1_INDEX, TC2_INDEX, TC3_INDEX }, /*wmm: 0*/ + { TC6_INDEX, TC7_INDEX, TC8_INDEX, TC9_INDEX }, /*wmm: 1*/ + { TC11_INDEX, TC12_INDEX, TC13_INDEX, TC14_INDEX }, /*wmm: 2*/ + { TC16_INDEX, TC16_INDEX, TC16_INDEX, TC16_INDEX } /*wmm: 3*/ +}; +#endif + +const u8 aucWmmAC2TcResourceSet1[WMM_AC_INDEX_NUM] = { TC1_INDEX, TC0_INDEX, + TC2_INDEX, TC3_INDEX }; + +#if NIC_TX_ENABLE_SECOND_HW_QUEUE +const u8 aucWmmAC2TcResourceSet2[WMM_AC_INDEX_NUM] = { TC7_INDEX, TC6_INDEX, + TC8_INDEX, TC9_INDEX }; +#endif +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#if CFG_RX_REORDERING_ENABLED +#define qmHandleRxPackets_AOSP_1 \ + do { \ + /* ToDo[6630]: duplicate removal */ \ + if (!fgIsBMC && nicRxIsDuplicateFrame(prCurrSwRfb) == true) { \ + DBGLOG(QM, TRACE, "Duplicated packet is detected\n"); \ + RX_INC_CNT(&prAdapter->rRxCtrl, \ + RX_DUPICATE_DROP_COUNT); \ + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; \ + } \ + /* ToDo[6630]: defragmentation */ \ + if (prCurrSwRfb->fgFragFrame) { \ + prCurrSwRfb = incRxDefragMPDU(prAdapter, prCurrSwRfb, \ + prReturnedQue); \ + if (prCurrSwRfb) { \ + prRxStatus = prCurrSwRfb->prRxStatus; \ + DBGLOG(QM, TRACE, \ + "defragmentation RxStatus=%x\n", \ + prRxStatus); \ + } \ + } \ + if (prCurrSwRfb) { \ + fgMicErr = false; \ + if (HAL_RX_STATUS_GET_SEC_MODE(prRxStatus) == \ + CIPHER_SUITE_TKIP_WO_MIC) { \ + if (prCurrSwRfb->prStaRec) { \ + u8 ucBssIndex; \ + P_BSS_INFO_T prBssInfo = NULL; \ + u8 *pucMicKey = NULL; \ + ucBssIndex = prCurrSwRfb->prStaRec \ + ->ucBssIndex; \ + ASSERT(ucBssIndex < BSS_INFO_NUM); \ + prBssInfo = GET_BSS_INFO_BY_INDEX( \ + prAdapter, ucBssIndex); \ + ASSERT(prBssInfo); \ + if (prBssInfo->eCurrentOPMode == \ + OP_MODE_INFRASTRUCTURE) { \ + pucMicKey = &( \ + prAdapter->rWifiVar \ + .rAisSpecificBssInfo \ + .aucRxMicKey \ + [0]); \ + prCurrSwRfb->ucTid = \ + (u8)( \ + HAL_RX_STATUS_GET_TID \ + ( \ + prRxStatus)); \ + } else { \ + ASSERT(false); \ + /* pucMicKey = \ + * &prCurrSwRfb->prStaRec->aucRxMicKey[0]; \ + */ \ + } \ + /* SW TKIP MIC verify, adopt new \ + * function call for MIC calculation \ + */ \ + /* TODO:[6630] Need to Check Header \ + * Translation Case */ \ + if (pucMicKey == NULL) { \ + DBGLOG(RX, \ + ERROR, \ + "Mark NULL the Packet for TKIP Key Error\n"); \ + fgMicErr = true; \ + } else if ( \ + tkipMicDecapsulateInRxHdrTransMode \ + ( \ + prCurrSwRfb, \ + pucMicKey) == \ + false) { \ + fgMicErr = true; \ + } \ + } \ + if (fgMicErr) { \ + /* bypass tkip frag */ \ + if (!prCurrSwRfb->fgFragFrame) { \ + DBGLOG(RX, \ + ERROR, \ + "Mark NULL the Packet for TKIP Mic Error\n"); \ + RX_INC_CNT( \ + &prAdapter->rRxCtrl, \ + RX_MIC_ERROR_DROP_COUNT); \ + prCurrSwRfb->eDst = \ + RX_PKT_DESTINATION_NULL; \ + } \ + } \ + } \ + QUEUE_INSERT_TAIL(prReturnedQue, \ + (P_QUE_ENTRY_T)prCurrSwRfb); \ + } \ + } while (0) +#endif + +#define RX_DIRECT_REORDER_LOCK(pad, dbg) \ + do { \ + P_GLUE_INFO_T _glue = pad->prGlueInfo; \ + if (!HAL_IS_RX_DIRECT(pad) || !_glue) \ + break; \ + if (dbg) \ + DBGLOG(QM, EVENT, "RX_DIRECT_REORDER_LOCK %d\n", \ + __LINE__); \ + spin_lock_bh(&_glue->rSpinLock[SPIN_LOCK_RX_DIRECT_REORDER]); \ + } while (0) + +#define RX_DIRECT_REORDER_UNLOCK(pad, dbg) \ + do { \ + P_GLUE_INFO_T _glue = pad->prGlueInfo; \ + if (!HAL_IS_RX_DIRECT(pad) || !_glue) \ + break; \ + if (dbg) \ + DBGLOG(QM, EVENT, "RX_DIRECT_REORDER_UNLOCK %u\n", \ + __LINE__); \ + spin_unlock_bh( \ + &_glue->rSpinLock[SPIN_LOCK_RX_DIRECT_REORDER]); \ + } while (0) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Init Queue Management for TX + * + * \param[in] (none) + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmInit(IN P_ADAPTER_T prAdapter, IN u8 isTxResrouceControlEn) +{ + u32 u4Idx; +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + u32 u4TotalMinReservedTcResource = 0; + u32 u4TotalTcResource = 0; + u32 u4TotalGurantedTcResource = 0; +#endif + + P_QUE_MGT_T prQM = &prAdapter->rQM; + + /* DbgPrint("QM: Enter qmInit()\n"); */ + + /* 4 <2> Initialize other TX queues (queues not in STA_RECs) */ + for (u4Idx = 0; u4Idx < NUM_OF_PER_TYPE_TX_QUEUES; u4Idx++) + QUEUE_INITIALIZE(&(prQM->arTxQueue[u4Idx])); + + /* 4 <3> Initialize the RX BA table and RX queues */ + /* Initialize the RX Reordering Parameters and Queues */ + for (u4Idx = 0; u4Idx < CFG_NUM_OF_RX_BA_AGREEMENTS; u4Idx++) { + prQM->arRxBaTable[u4Idx].fgIsValid = false; + QUEUE_INITIALIZE(&(prQM->arRxBaTable[u4Idx].rReOrderQue)); + prQM->arRxBaTable[u4Idx].u2WinStart = 0xFFFF; + prQM->arRxBaTable[u4Idx].u2WinEnd = 0xFFFF; + + prQM->arRxBaTable[u4Idx].fgIsWaitingForPktWithSsn = false; + prQM->arRxBaTable[u4Idx].fgHasBubble = false; +#if CFG_SUPPORT_RX_AMSDU + /* RX reorder for one MSDU in AMSDU issue */ + prQM->arRxBaTable[u4Idx].u8LastAmsduSubIdx = + RX_PAYLOAD_FORMAT_MSDU; + prQM->arRxBaTable[u4Idx].fgAmsduNeedLastFrame = false; + prQM->arRxBaTable[u4Idx].fgIsAmsduDuplicated = false; +#endif + prQM->arRxBaTable[u4Idx].fgFirstSnToWinStart = false; + cnmTimerInitTimer( + prAdapter, + &(prQM->arRxBaTable[u4Idx].rReorderBubbleTimer), + (PFN_MGMT_TIMEOUT_FUNC)qmHandleReorderBubbleTimeout, + (unsigned long)(&prQM->arRxBaTable[u4Idx])); + } + prQM->ucRxBaCount = 0; + + kalMemSet(&g_arMissTimeout, 0, sizeof(g_arMissTimeout)); + + prQM->fgIsTxResrouceControlEn = isTxResrouceControlEn; + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + /* 4 <4> Initialize TC resource control variables */ + for (u4Idx = 0; u4Idx < TC_NUM; u4Idx++) + prQM->au4AverageQueLen[u4Idx] = 0; + + ASSERT(prQM->u4TimeToAdjustTcResource && prQM->u4TimeToUpdateQueLen); + + for (u4Idx = 0; u4Idx < TC_NUM; u4Idx++) { + prQM->au4CurrentTcResource[u4Idx] = + prAdapter->rTxCtrl.rTc.au4MaxNumOfBuffer[u4Idx]; + + if (u4Idx != TC4_INDEX) { + u4TotalTcResource += prQM->au4CurrentTcResource[u4Idx]; + u4TotalGurantedTcResource += + prQM->au4GuaranteedTcResource[u4Idx]; + u4TotalMinReservedTcResource += + prQM->au4MinReservedTcResource[u4Idx]; + } + } + + /* Sanity Check */ + if (u4TotalMinReservedTcResource > u4TotalTcResource) { + kalMemZero(prQM->au4MinReservedTcResource, + sizeof(prQM->au4MinReservedTcResource)); + } + + if (u4TotalGurantedTcResource > u4TotalTcResource) { + kalMemZero(prQM->au4GuaranteedTcResource, + sizeof(prQM->au4GuaranteedTcResource)); + } + + u4TotalGurantedTcResource = 0; + + /* Initialize Residual TC resource */ + for (u4Idx = 0; u4Idx < TC_NUM; u4Idx++) { + if (prQM->au4GuaranteedTcResource[u4Idx] < + prQM->au4MinReservedTcResource[u4Idx]) { + prQM->au4GuaranteedTcResource[u4Idx] = + prQM->au4MinReservedTcResource[u4Idx]; + } + + if (u4Idx != TC4_INDEX) { + u4TotalGurantedTcResource += + prQM->au4GuaranteedTcResource[u4Idx]; + } + } + + prQM->u4ResidualTcResource = + u4TotalTcResource - u4TotalGurantedTcResource; + + prQM->fgTcResourcePostAnnealing = false; + +#if QM_FAST_TC_RESOURCE_CTRL + prQM->fgTcResourceFastReaction = false; +#endif +#endif + +#if QM_TEST_MODE + prQM->u4PktCount = 0; + +#if QM_TEST_FAIR_FORWARDING + prQM->u4CurrentStaRecIndexToEnqueue = 0; + { + u8 aucMacAddr[MAC_ADDR_LEN]; + P_STA_RECORD_T prStaRec; + + /* Irrelevant in case this STA is an AIS AP (see + * qmDetermineStaRecIndex()) */ + aucMacAddr[0] = 0x11; + aucMacAddr[1] = 0x22; + aucMacAddr[2] = 0xAA; + aucMacAddr[3] = 0xBB; + aucMacAddr[4] = 0xCC; + aucMacAddr[5] = 0xDD; + + prStaRec = &prAdapter->arStaRec[1]; + ASSERT(prStaRec); + + prStaRec->fgIsValid = true; + prStaRec->fgIsQoS = true; + prStaRec->fgIsInPS = false; + prStaRec->ucNetTypeIndex = NETWORK_TYPE_AIS_INDEX; + COPY_MAC_ADDR((prStaRec)->aucMacAddr, aucMacAddr); + } +#endif +#endif + +#if QM_FORWARDING_FAIRNESS + for (u4Idx = 0; u4Idx < NUM_OF_PER_STA_TX_QUEUES; u4Idx++) { + prQM->au4ResourceUsedCount[u4Idx] = 0; + prQM->au4HeadStaRecIndex[u4Idx] = 0; + } + + prQM->u4GlobalResourceUsedCount = 0; +#endif + + prQM->u4TxAllowedStaCount = 0; + + prQM->rLastTxPktDumpTime = (u32)kalGetTimeTick(); +} + +#if QM_TEST_MODE +void qmTestCases(IN P_ADAPTER_T prAdapter) +{ + P_QUE_MGT_T prQM = &prAdapter->rQM; + + DbgPrint("QM: ** TEST MODE **\n"); + + if (QM_TEST_STA_REC_DETERMINATION) { + if (prAdapter->arStaRec[0].fgIsValid) { + prAdapter->arStaRec[0].fgIsValid = false; + DbgPrint("QM: (Test) Deactivate STA_REC[0]\n"); + } else { + prAdapter->arStaRec[0].fgIsValid = true; + DbgPrint("QM: (Test) Activate STA_REC[0]\n"); + } + } + + if (QM_TEST_STA_REC_DEACTIVATION) { + /* Note that QM_STA_REC_HARD_CODING shall be set to 1 for this + * test */ + + if (prAdapter->arStaRec[0].fgIsValid) { + DbgPrint("QM: (Test) Deactivate STA_REC[0]\n"); + qmDeactivateStaRec(prAdapter, &prAdapter->arStaRec[0]); + } else { + u8 aucMacAddr[MAC_ADDR_LEN]; + + /* Irrelevant in case this STA is an AIS AP (see + * qmDetermineStaRecIndex()) */ + aucMacAddr[0] = 0x11; + aucMacAddr[1] = 0x22; + aucMacAddr[2] = 0xAA; + aucMacAddr[3] = 0xBB; + aucMacAddr[4] = 0xCC; + aucMacAddr[5] = 0xDD; + + DbgPrint("QM: (Test) Activate STA_REC[0]\n"); + qmActivateStaRec(prAdapter, /* Adapter pointer */ + 0, /* STA_REC index from FW */ + true, /* fgIsQoS */ + NETWORK_TYPE_AIS_INDEX, /* Network type + */ + true, /* fgIsAp */ + aucMacAddr /* MAC address */ + ); + } + } + + if (QM_TEST_FAIR_FORWARDING) { + if (prAdapter->arStaRec[1].fgIsValid) { + prQM->u4CurrentStaRecIndexToEnqueue++; + prQM->u4CurrentStaRecIndexToEnqueue %= 2; + DbgPrint("QM: (Test) Switch to STA_REC[%ld]\n", + prQM->u4CurrentStaRecIndexToEnqueue); + } + } +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Update a STA_REC + * + * \param[in] prAdapter Pointer to the Adapter instance + * \param[in] prStaRec The pointer of the STA_REC + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmUpdateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + P_BSS_INFO_T prBssInfo; + u8 fgIsTxAllowed = false; + + if (!prStaRec) { + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + /* 4 <1> Ensure STA is valid */ + if (prStaRec->fgIsValid) { + /* 4 <2.1> STA/BSS is protected */ + if (secIsProtectedBss(prAdapter, prBssInfo)) { + if (prStaRec->fgIsTxKeyReady) { + fgIsTxAllowed = true; + } else { + fgIsTxAllowed = false; + } + } + /* 4 <2.2> OPEN security */ + else { + fgIsTxAllowed = true; + } + } + /* 4 <x> Update StaRec */ + qmSetStaRecTxAllowed(prAdapter, prStaRec, fgIsTxAllowed); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Activate a STA_REC + * + * \param[in] prAdapter Pointer to the Adapter instance + * \param[in] prStaRec The pointer of the STA_REC + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmActivateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + /* 4 <1> Deactivate first */ + if (!prStaRec) { + return; + } + + if (prStaRec->fgIsValid) { /* The STA_REC has been activated */ + DBGLOG(QM, + WARN, + "QM: (WARNING) Activating a STA_REC which has been activated\n"); + DBGLOG(QM, + WARN, + "QM: (WARNING) Deactivating a STA_REC before re-activating\n"); + qmDeactivateStaRec(prAdapter, prStaRec); /* To flush TX/RX + * queues and del RX BA + * agreements */ + } + /* 4 <2> Activate the STA_REC */ + /* Reset buffer count */ + prStaRec->ucFreeQuota = 0; + prStaRec->ucFreeQuotaForDelivery = 0; + prStaRec->ucFreeQuotaForNonDelivery = 0; + + /* Init the STA_REC */ + prStaRec->fgIsValid = true; + prStaRec->fgIsInPS = false; + + /* Default setting of TX/RX AMPDU */ + prStaRec->fgTxAmpduEn = + IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucAmpduTx); + prStaRec->fgRxAmpduEn = + IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucAmpduRx); + + nicTxGenerateDescTemplate(prAdapter, prStaRec); + + qmUpdateStaRec(prAdapter, prStaRec); + + DBGLOG(QM, STATE, "QM: +STA[%ld]\n", (u32)prStaRec->ucIndex); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Deactivate a STA_REC + * + * \param[in] prAdapter Pointer to the Adapter instance + * \param[in] u4StaRecIdx The index of the STA_REC + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmDeactivateStaRec(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) +{ + u32 i; + + if (!prStaRec) { + return; + } + + /* 4 <1> Flush TX queues */ + if (HAL_IS_TX_DIRECT(prAdapter)) { + nicTxDirectClearStaPsQ(prAdapter, prStaRec->ucIndex); + } else { + P_MSDU_INFO_T prFlushedTxPacketList = NULL; + + prFlushedTxPacketList = + qmFlushStaTxQueues(prAdapter, prStaRec->ucIndex); + + if (prFlushedTxPacketList) { + wlanProcessQueuedMsduInfo(prAdapter, + prFlushedTxPacketList); + } + } + + /* 4 <2> Flush RX queues and delete RX BA agreements */ + for (i = 0; i < CFG_RX_MAX_BA_TID_NUM; i++) + /* Delete the RX BA entry with TID = i */ + qmDelRxBaEntry(prAdapter, prStaRec->ucIndex, (u8)i, false); + + /* clear fragment cache when reconnect, reassoc, disconnect */ + nicRxClearFrag(prAdapter, prStaRec); + + /* 4 <3> Deactivate the STA_REC */ + prStaRec->fgIsValid = false; + prStaRec->fgIsInPS = false; + prStaRec->fgIsTxKeyReady = false; + + /* Reset buffer count */ + prStaRec->ucFreeQuota = 0; + prStaRec->ucFreeQuotaForDelivery = 0; + prStaRec->ucFreeQuotaForNonDelivery = 0; + + nicTxFreeDescTemplate(prAdapter, prStaRec); + + qmUpdateStaRec(prAdapter, prStaRec); + + DBGLOG(QM, INFO, "QM: -STA[%u]\n", prStaRec->ucIndex); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Deactivate a STA_REC + * + * \param[in] prAdapter Pointer to the Adapter instance + * \param[in] ucBssIndex The index of the BSS + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmFreeAllByBssIdx(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex) +{ + P_QUE_MGT_T prQM; + P_QUE_T prQue; + QUE_T rNeedToFreeQue; + QUE_T rTempQue; + P_QUE_T prNeedToFreeQue; + P_QUE_T prTempQue; + P_MSDU_INFO_T prMsduInfo; + + prQM = &prAdapter->rQM; + prQue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; + + QUEUE_INITIALIZE(&rNeedToFreeQue); + QUEUE_INITIALIZE(&rTempQue); + + prNeedToFreeQue = &rNeedToFreeQue; + prTempQue = &rTempQue; + + QUEUE_MOVE_ALL(prTempQue, prQue); + + QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T); + while (prMsduInfo) { + if (prMsduInfo->ucBssIndex == ucBssIndex) { + /* QUEUE_INSERT_TAIL */ + QUEUE_INSERT_TAIL(prNeedToFreeQue, + (P_QUE_ENTRY_T)prMsduInfo); + } else { + /* QUEUE_INSERT_TAIL */ + QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T)prMsduInfo); + } + + QUEUE_REMOVE_HEAD(prTempQue, prMsduInfo, P_MSDU_INFO_T); + } + if (QUEUE_IS_NOT_EMPTY(prNeedToFreeQue)) { + wlanProcessQueuedMsduInfo( + prAdapter, + (P_MSDU_INFO_T)QUEUE_GET_HEAD(prNeedToFreeQue)); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Flush all TX queues + * + * \param[in] (none) + * + * \return The flushed packets (in a list of MSDU_INFOs) + */ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T qmFlushTxQueues(IN P_ADAPTER_T prAdapter) +{ + u8 ucStaArrayIdx; + u8 ucQueArrayIdx; + + P_QUE_MGT_T prQM = &prAdapter->rQM; + + QUE_T rTempQue; + P_QUE_T prTempQue = &rTempQue; + P_QUE_T prQue; + + DBGLOG(QM, TRACE, "QM: Enter qmFlushTxQueues()\n"); + + QUEUE_INITIALIZE(prTempQue); + + /* Concatenate all MSDU_INFOs in per-STA queues */ + for (ucStaArrayIdx = 0; ucStaArrayIdx < CFG_STA_REC_NUM; + ucStaArrayIdx++) { + for (ucQueArrayIdx = 0; + ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; + ucQueArrayIdx++) { + prQue = &(prAdapter->arStaRec[ucStaArrayIdx] + .arPendingTxQueue[ucQueArrayIdx]); + QUEUE_CONCATENATE_QUEUES(prTempQue, prQue); + prQue = &(prAdapter->arStaRec[ucStaArrayIdx] + .arTxQueue[ucQueArrayIdx]); + QUEUE_CONCATENATE_QUEUES(prTempQue, prQue); + } + } + + /* Flush per-Type queues */ + for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_TYPE_TX_QUEUES; + ucQueArrayIdx++) { + prQue = &(prQM->arTxQueue[ucQueArrayIdx]); + QUEUE_CONCATENATE_QUEUES(prTempQue, prQue); + } + + return (P_MSDU_INFO_T)QUEUE_GET_HEAD(prTempQue); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Flush TX packets for a particular STA + * + * \param[in] u4StaRecIdx STA_REC index + * + * \return The flushed packets (in a list of MSDU_INFOs) + */ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T qmFlushStaTxQueues(IN P_ADAPTER_T prAdapter, IN u32 u4StaRecIdx) +{ + u8 ucQueArrayIdx; + P_STA_RECORD_T prStaRec; + P_QUE_T prQue; + QUE_T rTempQue; + P_QUE_T prTempQue = &rTempQue; + + DBGLOG(QM, TRACE, "QM: Enter qmFlushStaTxQueues(%ld)\n", u4StaRecIdx); + + ASSERT(u4StaRecIdx < CFG_STA_REC_NUM); + + prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; + ASSERT(prStaRec); + + QUEUE_INITIALIZE(prTempQue); + + /* Concatenate all MSDU_INFOs in TX queues of this STA_REC */ + for (ucQueArrayIdx = 0; ucQueArrayIdx < NUM_OF_PER_STA_TX_QUEUES; + ucQueArrayIdx++) { + prQue = &(prStaRec->arPendingTxQueue[ucQueArrayIdx]); + QUEUE_CONCATENATE_QUEUES(prTempQue, prQue); + prQue = &(prStaRec->arTxQueue[ucQueArrayIdx]); + QUEUE_CONCATENATE_QUEUES(prTempQue, prQue); + } + + return (P_MSDU_INFO_T)QUEUE_GET_HEAD(prTempQue); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Flush RX packets + * + * \param[in] (none) + * + * \return The flushed packets (in a list of SW_RFBs) + */ +/*----------------------------------------------------------------------------*/ +P_SW_RFB_T qmFlushRxQueues(IN P_ADAPTER_T prAdapter) +{ + u32 i; + P_SW_RFB_T prSwRfbListHead; + P_SW_RFB_T prSwRfbListTail; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + prSwRfbListHead = prSwRfbListTail = NULL; + + DBGLOG(QM, TRACE, "QM: Enter qmFlushRxQueues()\n"); + + RX_DIRECT_REORDER_LOCK(prAdapter, 0); + for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { + if (QUEUE_IS_NOT_EMPTY(&(prQM->arRxBaTable[i].rReOrderQue))) { + if (!prSwRfbListHead) { + /* The first MSDU_INFO is found */ + prSwRfbListHead = (P_SW_RFB_T)QUEUE_GET_HEAD( + &(prQM->arRxBaTable[i].rReOrderQue)); + prSwRfbListTail = (P_SW_RFB_T)QUEUE_GET_TAIL( + &(prQM->arRxBaTable[i].rReOrderQue)); + } else { + /* Concatenate the MSDU_INFO list with the + * existing list */ + QM_TX_SET_NEXT_MSDU_INFO( + prSwRfbListTail, + QUEUE_GET_HEAD( + &(prQM->arRxBaTable[i] + .rReOrderQue))); + + prSwRfbListTail = (P_SW_RFB_T)QUEUE_GET_TAIL( + &(prQM->arRxBaTable[i].rReOrderQue)); + } + + QUEUE_INITIALIZE(&(prQM->arRxBaTable[i].rReOrderQue)); + if (QM_RX_GET_NEXT_SW_RFB(prSwRfbListTail)) { + DBGLOG(QM, + ERROR, + "QM: non-null tail->next at arRxBaTable[%u]\n", + i); + } + } else { + continue; + } + } + RX_DIRECT_REORDER_UNLOCK(prAdapter, 0); + + if (prSwRfbListTail) { + /* Terminate the MSDU_INFO list with a NULL pointer */ + QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL); + } + return prSwRfbListHead; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Flush RX packets with respect to a particular STA + * + * \param[in] u4StaRecIdx STA_REC index + * \param[in] u4Tid TID + * + * \return The flushed packets (in a list of SW_RFBs) + */ +/*----------------------------------------------------------------------------*/ +P_SW_RFB_T qmFlushStaRxQueue(IN P_ADAPTER_T prAdapter, IN u32 u4StaRecIdx, + IN u32 u4Tid) +{ + /* u32 i; */ + P_SW_RFB_T prSwRfbListHead = NULL; + P_SW_RFB_T prSwRfbListTail = NULL; + P_RX_BA_ENTRY_T prReorderQueParm = NULL; + P_STA_RECORD_T prStaRec = NULL; + + DBGLOG(QM, TRACE, "QM: Enter qmFlushStaRxQueues(%ld)\n", u4StaRecIdx); + + prSwRfbListHead = prSwRfbListTail = NULL; + + prStaRec = &prAdapter->arStaRec[u4StaRecIdx]; + ASSERT(prStaRec); + + /* Obtain the RX BA Entry pointer */ + if (u4Tid < CFG_RX_MAX_BA_TID_NUM) { + prReorderQueParm = ((prStaRec->aprRxReorderParamRefTbl)[u4Tid]); + } + + /* Note: For each queued packet, prCurrSwRfb->eDst equals + * RX_PKT_DESTINATION_HOST */ + if (prReorderQueParm) { + RX_DIRECT_REORDER_LOCK(prAdapter, 0); + if (QUEUE_IS_NOT_EMPTY(&(prReorderQueParm->rReOrderQue))) { + prSwRfbListHead = (P_SW_RFB_T)QUEUE_GET_HEAD( + &(prReorderQueParm->rReOrderQue)); + prSwRfbListTail = (P_SW_RFB_T)QUEUE_GET_TAIL( + &(prReorderQueParm->rReOrderQue)); + + QUEUE_INITIALIZE(&(prReorderQueParm->rReOrderQue)); + } + RX_DIRECT_REORDER_UNLOCK(prAdapter, 0); + } + + if (prSwRfbListTail) { + if (QM_RX_GET_NEXT_SW_RFB(prSwRfbListTail)) { + DBGLOG(QM, ERROR, + "QM: non-empty tail->next at STA %u TID %u\n", + u4StaRecIdx, u4Tid); + } + + /* Terminate the MSDU_INFO list with a NULL pointer */ + QM_TX_SET_NEXT_SW_RFB(prSwRfbListTail, NULL); + } + return prSwRfbListHead; +} + +P_QUE_T qmDetermineStaTxQueue(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo, OUT u8 *pucTC) +{ + P_QUE_T prTxQue = NULL; + P_STA_RECORD_T prStaRec; + ENUM_WMM_ACI_T eAci = WMM_AC_BE_INDEX; + u8 fgCheckACMAgain; + u8 ucTC, ucQueIdx = WMM_AC_BE_INDEX; + P_BSS_INFO_T prBssInfo; + u8 aucNextUP[WMM_AC_INDEX_NUM] = { + 1 /* BEtoBK */, 1 /* na */, 0 /* VItoBE */, 4 /* VOtoVI */ + }; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, + prMsduInfo->ucStaRecIndex); + + if (!prStaRec) { + DBGLOG(QM, ERROR, "prStaRec is null.\n"); + return NULL; + } + if (prMsduInfo->ucUserPriority < 8) { + QM_DBG_CNT_INC(&prAdapter->rQM, + prMsduInfo->ucUserPriority + 15); + /* QM_DBG_CNT_15 */ /* QM_DBG_CNT_16 */ + /* QM_DBG_CNT_17 */ /* QM_DBG_CNT_18 */ + /* QM_DBG_CNT_19 */ /* QM_DBG_CNT_20 */ + /* QM_DBG_CNT_21 */ /* QM_DBG_CNT_22 */ + } + + eAci = WMM_AC_BE_INDEX; + do { + fgCheckACMAgain = false; + if (prStaRec->fgIsQoS) { + if (prMsduInfo->ucUserPriority < TX_DESC_TID_NUM) { + eAci = aucTid2ACI[prMsduInfo->ucUserPriority]; + ucQueIdx = aucACI2TxQIdx[eAci]; + ucTC = arNetwork2TcResource + [prMsduInfo->ucBssIndex][eAci]; + } else { + ucQueIdx = TX_QUEUE_INDEX_AC1; + ucTC = TC1_INDEX; + eAci = WMM_AC_BE_INDEX; + DBGLOG(QM, WARN, + "Packet TID is not in [0~7]\n"); + ASSERT(0); + } + if ((prBssInfo->arACQueParms[eAci].ucIsACMSet) && + (eAci != WMM_AC_BK_INDEX)) { + prMsduInfo->ucUserPriority = aucNextUP[eAci]; + fgCheckACMAgain = true; + } + } else { + ucQueIdx = TX_QUEUE_INDEX_NON_QOS; + ucTC = arNetwork2TcResource[prMsduInfo->ucBssIndex] + [NET_TC_WMM_AC_BE_INDEX]; + } + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + /* remap a new TC number + * based on original TC number and its wmm_set number + */ + ucTC = arTcRemapTable[prBssInfo->ucWmmQueSet][ucTC]; +#endif + + if (prAdapter->rWifiVar.ucTcRestrict < TC_NUM) { + ucTC = prAdapter->rWifiVar.ucTcRestrict; + ucQueIdx = ucTC; + } + } while (fgCheckACMAgain); + + if (ucQueIdx >= NUM_OF_PER_STA_TX_QUEUES) { + DBGLOG(QM, ERROR, + "ucQueIdx = %u, needs 0~3 to avoid out-of-bounds.\n", + ucQueIdx); + return NULL; + } + if (prStaRec->fgIsTxAllowed) { + /* non protected BSS or protected BSS with key set */ + prTxQue = prStaRec->aprTargetQueue[ucQueIdx]; + } else if (secIsProtectedBss(prAdapter, prBssInfo) && + prMsduInfo->fgIs802_1x && + prMsduInfo->fgIs802_1x_NonProtected) { + /* protected BSS without key set */ + /* Tx pairwise EAPOL 1x packet (non-protected frame) */ + prTxQue = &prStaRec->arTxQueue[ucQueIdx]; + } else { + /* protected BSS without key set */ + /* Enqueue protected frame into pending queue */ + prTxQue = prStaRec->aprTargetQueue[ucQueIdx]; + } +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + DBGLOG(HIF_WMM_ENHANCE, LOUD, "Tc = %u, StaRec[%d], Sta_QIdx = %u.\n", + ucTC, prMsduInfo->ucStaRecIndex, ucQueIdx); +#endif + + *pucTC = ucTC; + + return prTxQue; +} + +void qmSetTxPacketDescTemplate(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + P_STA_RECORD_T prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX( + prAdapter, prMsduInfo->ucStaRecIndex); + + /* Check the Tx descriptor template is valid */ + if (prStaRec && + prStaRec->aprTxDescTemplate[prMsduInfo->ucUserPriority]) { + prMsduInfo->fgIsTXDTemplateValid = true; + } else { + if (prStaRec) { + DBGLOG(QM, + TRACE, + "Cannot get TXD template for STA[%u] QoS[%u] MSDU UP[%u]\n", + prStaRec->ucIndex, + prStaRec->fgIsQoS, + prMsduInfo->ucUserPriority); + } + prMsduInfo->fgIsTXDTemplateValid = false; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief : To StaRec, function to stop TX + * + * \param[in] : + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void qmSetStaRecTxAllowed(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, + IN u8 fgIsTxAllowed) +{ + u8 ucIdx; + P_QUE_T prSrcQ, prDstQ; + + /* Update Tx queue */ + for (ucIdx = 0; ucIdx < NUM_OF_PER_STA_TX_QUEUES; ucIdx++) { + if (fgIsTxAllowed) { + prSrcQ = &prStaRec->arPendingTxQueue[ucIdx]; + prDstQ = &prStaRec->arTxQueue[ucIdx]; + QUEUE_CONCATENATE_QUEUES(prDstQ, prSrcQ); + } else { + prSrcQ = &prStaRec->arTxQueue[ucIdx]; + prDstQ = &prStaRec->arPendingTxQueue[ucIdx]; + QUEUE_CONCATENATE_QUEUES_HEAD(prDstQ, prSrcQ); + } + + prStaRec->aprTargetQueue[ucIdx] = prDstQ; + } + + if (prStaRec->fgIsTxAllowed != fgIsTxAllowed) { + if (fgIsTxAllowed) { + prAdapter->rQM.u4TxAllowedStaCount++; + }else{ + prAdapter->rQM.u4TxAllowedStaCount--; + } + } + prStaRec->fgIsTxAllowed = fgIsTxAllowed; + + DBGLOG(QM, EVENT, "Set Sta[%u] TxAllowed[%u] %s TxQ\n", + prStaRec->ucIndex, fgIsTxAllowed, + fgIsTxAllowed ? "normal" : "pending"); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Enqueue TX packets + * + * \param[in] prMsduInfoListHead Pointer to the list of TX packets + * + * \return The freed packets, which are not enqueued + */ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T qmEnqueueTxPackets(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfoListHead) +{ + P_MSDU_INFO_T prMsduInfoReleaseList; + P_MSDU_INFO_T prCurrentMsduInfo; + P_MSDU_INFO_T prNextMsduInfo; + + P_QUE_T prTxQue; + QUE_T rNotEnqueuedQue; + + u8 ucTC; + P_QUE_MGT_T prQM = &prAdapter->rQM; + P_BSS_INFO_T prBssInfo; + u8 fgDropPacket; +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + u8 ucRefTC, ucWmm; +#endif + + DBGLOG(QM, LOUD, "Enter qmEnqueueTxPackets\n"); + + ASSERT(prMsduInfoListHead); + + prMsduInfoReleaseList = NULL; + prCurrentMsduInfo = NULL; + QUEUE_INITIALIZE(&rNotEnqueuedQue); + prNextMsduInfo = prMsduInfoListHead; + + do { + prCurrentMsduInfo = prNextMsduInfo; + prNextMsduInfo = QM_TX_GET_NEXT_MSDU_INFO(prCurrentMsduInfo); + ucTC = TC1_INDEX; + + /* 4 <0> Sanity check of BSS_INFO */ + prBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, prCurrentMsduInfo->ucBssIndex); + + if (!prBssInfo) { + /* No BSS_INFO */ + fgDropPacket = true; + } else if (IS_BSS_ACTIVE(prBssInfo)) { + /* BSS active */ + fgDropPacket = false; + } else { + /* BSS inactive */ + fgDropPacket = true; + } + + if (!fgDropPacket) { + /* 4 <1> Lookup the STA_REC index */ + /* The ucStaRecIndex will be set in this function */ + qmDetermineStaRecIndex(prAdapter, prCurrentMsduInfo); + + wlanUpdateTxStatistics(prAdapter, prCurrentMsduInfo, + false); /*get per-AC Tx packets + */ + + DBGLOG(QM, LOUD, "Enqueue MSDU by StaRec[%u]!\n", + prCurrentMsduInfo->ucStaRecIndex); + + switch (prCurrentMsduInfo->ucStaRecIndex) { + case STA_REC_INDEX_BMCAST: +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + prTxQue = + &prQM->arTxQueue[prCurrentMsduInfo + ->ucBssIndex]; +#else + prTxQue = + &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; +#endif + ucTC = arNetwork2TcResource[prCurrentMsduInfo + ->ucBssIndex] + [NET_TC_BMC_INDEX]; + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + ucWmm = prCurrentMsduInfo->ucBssIndex; + ucRefTC = + arNetwork2TcResource[ucWmm] + [NET_TC_BMC_INDEX]; + + ucWmm = prBssInfo->ucWmmQueSet; + prTxQue = &prQM->arTxQueue[ucWmm]; + ucTC = arTcRemapTable[ucWmm][ucRefTC]; +#endif + DBGLOG(QM, LOUD, "Enqueue MSDU TC is [%u]!\n", + ucTC); + + /* Always set BMC packet retry limit to + * unlimited */ + if (!(prCurrentMsduInfo->u4Option & + MSDU_OPT_MANUAL_RETRY_LIMIT)) { + nicTxSetPktRetryLimit( + prCurrentMsduInfo, + TX_DESC_TX_COUNT_NO_LIMIT); + } + + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_23); + break; + + case STA_REC_INDEX_NOT_FOUND: + /* Drop packet if no STA_REC is found */ + DBGLOG(QM, TRACE, + "Drop the Packet for no STA_REC\n"); + + prTxQue = &rNotEnqueuedQue; + + TX_INC_CNT(&prAdapter->rTxCtrl, + TX_INACTIVE_STA_DROP); + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_24); + break; + + default: + prTxQue = qmDetermineStaTxQueue( + prAdapter, prCurrentMsduInfo, &ucTC); + break; /*default */ + } /* switch (prCurrentMsduInfo->ucStaRecIndex) */ + + if (prCurrentMsduInfo->eSrc == TX_PACKET_FORWARDING) { + DBGLOG(QM, TRACE, + "Forward Pkt to STA[%u] BSS[%u]\n", + prCurrentMsduInfo->ucStaRecIndex, + prCurrentMsduInfo->ucBssIndex); + + if (prTxQue->u4NumElem >= + prQM->u4MaxForwardBufferCount) { + DBGLOG(QM, + INFO, + "Drop the Packet for full Tx queue (forwarding) Bss %u\n", + prCurrentMsduInfo->ucBssIndex); + prTxQue = &rNotEnqueuedQue; + TX_INC_CNT(&prAdapter->rTxCtrl, + TX_FORWARD_OVERFLOW_DROP); + } + } + } else { + DBGLOG(QM, TRACE, + "Drop the Packet for inactive Bss %u\n", + prCurrentMsduInfo->ucBssIndex); + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_31); + prTxQue = &rNotEnqueuedQue; + TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP); + } + + /* 4 <3> Fill the MSDU_INFO for constructing HIF TX header */ + /* Note that the BSS Index and STA_REC index are determined in + * qmDetermineStaRecIndex(prCurrentMsduInfo). + */ + prCurrentMsduInfo->ucTC = ucTC; + + /* Check the Tx descriptor template is valid */ + qmSetTxPacketDescTemplate(prAdapter, prCurrentMsduInfo); + + /* Set Tx rate */ + switch (prAdapter->rWifiVar.ucDataTxRateMode) { + case DATA_RATE_MODE_BSS_LOWEST: + nicTxSetPktLowestFixedRate(prAdapter, + prCurrentMsduInfo); + break; + + case DATA_RATE_MODE_MANUAL: + prCurrentMsduInfo->u4FixedRateOption = + prAdapter->rWifiVar.u4DataTxRateCode; + + prCurrentMsduInfo->ucRateMode = + MSDU_RATE_MODE_MANUAL_DESC; + break; + + case DATA_RATE_MODE_AUTO: + default: + if (prCurrentMsduInfo->ucRateMode == + MSDU_RATE_MODE_LOWEST_RATE) { + nicTxSetPktLowestFixedRate(prAdapter, + prCurrentMsduInfo); + } + break; + } + + /* 4 <4> Enqueue the packet */ + QUEUE_INSERT_TAIL(prTxQue, (P_QUE_ENTRY_T)prCurrentMsduInfo); + +#if QM_FAST_TC_RESOURCE_CTRL && QM_ADAPTIVE_TC_RESOURCE_CTRL + if (prTxQue != &rNotEnqueuedQue) { + /* Check and trigger fast TC resource adjustment for + * queued packets */ + qmCheckForFastTcResourceCtrl(prAdapter, ucTC); + } +#endif + +#if QM_TEST_MODE + if (++prQM->u4PktCount == QM_TEST_TRIGGER_TX_COUNT) { + prQM->u4PktCount = 0; + qmTestCases(prAdapter); + } +#endif + + DBGLOG(QM, LOUD, "Current queue length = %u\n", + prTxQue->u4NumElem); + } while (prNextMsduInfo); + + if (QUEUE_IS_NOT_EMPTY(&rNotEnqueuedQue)) { + QM_TX_SET_NEXT_MSDU_INFO( + (P_MSDU_INFO_T)QUEUE_GET_TAIL(&rNotEnqueuedQue), NULL); + prMsduInfoReleaseList = + (P_MSDU_INFO_T)QUEUE_GET_HEAD(&rNotEnqueuedQue); + } +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + /* 4 <x> Update TC resource control related variables */ + /* Keep track of the queue length */ + qmDoAdaptiveTcResourceCtrl(prAdapter); +#endif + + return prMsduInfoReleaseList; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Determine the STA_REC index for a packet + * + * \param[in] prMsduInfo Pointer to the packet + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmDetermineStaRecIndex(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + u32 i; + + P_STA_RECORD_T prTempStaRec; + P_BSS_INFO_T prBssInfo; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + prTempStaRec = NULL; + + ASSERT(prMsduInfo); + + DBGLOG(QM, LOUD, "Msdu BSS Idx[%u] OpMode[%u] StaRecOfApExist[%u]\n", + prMsduInfo->ucBssIndex, prBssInfo->eCurrentOPMode, + prBssInfo->prStaRecOfAP ? true : false); + + switch (prBssInfo->eCurrentOPMode) { + case OP_MODE_IBSS: + case OP_MODE_ACCESS_POINT: + /* 4 <1> DA = BMCAST */ + if (IS_BMCAST_MAC_ADDR(prMsduInfo->aucEthDestAddr)) { + { + prMsduInfo->ucStaRecIndex = + STA_REC_INDEX_BMCAST; + DBGLOG(QM, LOUD, "TX with DA = BMCAST\n"); + return; + } + } + break; + + /* Infra Client/GC */ + case OP_MODE_INFRASTRUCTURE: + case OP_MODE_BOW: + if (prBssInfo->prStaRecOfAP) { +#if CFG_SUPPORT_TDLS + prTempStaRec = cnmGetTdlsPeerByAddress( + prAdapter, prBssInfo->ucBssIndex, + prMsduInfo->aucEthDestAddr); + if (IS_DLS_STA(prTempStaRec) && + prTempStaRec->ucStaState == STA_STATE_3) { + if (g_arTdlsLink[prTempStaRec->ucTdlsIndex]) { + prMsduInfo->ucStaRecIndex = + prTempStaRec->ucIndex; + return; + } + } +#endif + /* 4 <2> Check if an AP STA is present */ + prTempStaRec = prBssInfo->prStaRecOfAP; + + DBGLOG(QM, + LOUD, + "StaOfAp Idx[%u] WIDX[%u] Valid[%u] TxAllowed[%u] InUse[%u] Type[%u]\n", + prTempStaRec->ucIndex, + prTempStaRec->ucWlanIndex, + prTempStaRec->fgIsValid, + prTempStaRec->fgIsTxAllowed, + prTempStaRec->fgIsInUse, + prTempStaRec->eStaType); + + if (prTempStaRec->fgIsInUse) { + prMsduInfo->ucStaRecIndex = + prTempStaRec->ucIndex; + DBGLOG(QM, LOUD, "TX with AP_STA[%u]\n", + prTempStaRec->ucIndex); + return; + } + } + break; + + case OP_MODE_P2P_DEVICE: + break; + + default: + break; + } + + /* 4 <3> Not BMCAST, No AP --> Compare DA (i.e., to see whether this is + * a unicast frame to a client) */ + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prTempStaRec = &(prAdapter->arStaRec[i]); + if (prTempStaRec->fgIsInUse) { + if (EQUAL_MAC_ADDR(prTempStaRec->aucMacAddr, + prMsduInfo->aucEthDestAddr)) { + prMsduInfo->ucStaRecIndex = + prTempStaRec->ucIndex; + DBGLOG(QM, LOUD, "TX with STA[%u]\n", + prTempStaRec->ucIndex); + return; + } + } + } + + /* 4 <4> No STA found, Not BMCAST --> Indicate NOT_FOUND to FW */ + prMsduInfo->ucStaRecIndex = STA_REC_INDEX_NOT_FOUND; + DBGLOG(QM, LOUD, "QM: TX with STA_REC_INDEX_NOT_FOUND\n"); + +#if (QM_TEST_MODE && QM_TEST_FAIR_FORWARDING) + prMsduInfo->ucStaRecIndex = (u8)prQM->u4CurrentStaRecIndexToEnqueue; +#endif +} + +P_STA_RECORD_T qmDetermineStaToBeDequeued(IN P_ADAPTER_T prAdapter, + IN u32 u4StartStaRecIndex) +{ + return NULL; +} + +P_QUE_T qmDequeueStaTxPackets(IN P_ADAPTER_T prAdapter) +{ + return NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Dequeue TX packets from a STA_REC for a particular TC + * + * \param[out] prQue The queue to put the dequeued packets + * \param[in] ucTC The TC index (TC0_INDEX to TC5_INDEX) + * \param[in] ucMaxNum The maximum amount of dequeued packets + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +u32 qmDequeueTxPacketsFromPerStaQueues(IN P_ADAPTER_T prAdapter, + OUT P_QUE_T prQue, IN u8 ucTC, + IN u32 u4CurrentQuota, + IN u32 u4TotalQuota) +{ + u32 ucLoop; /* Loop for */ + + u32 u4CurStaIndex = 0; + u32 u4CurStaUsedResource = 0; + + P_STA_RECORD_T prStaRec; /* The current focused STA */ + P_BSS_INFO_T prBssInfo; /* The Bss for current focused STA */ + P_QUE_T prCurrQueue; /* The current TX queue to dequeue */ + P_MSDU_INFO_T prDequeuedPkt; /* The dequeued packet */ + + u32 u4CurStaForwardFrameCount; /* To remember the total forwarded + * packets for a STA */ + u32 u4MaxForwardFrameCountLimit; /* The maximum number of packets a STA + * can forward */ + u32 u4AvaliableResource; /* The TX resource amount */ + u32 u4MaxResourceLimit; + + u8 fgEndThisRound; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + u8 *pucPsStaFreeQuota; +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + u8 ucWmmIdx, ucFlagHit, ucAcIdx, ucAcIdxVldCnt, ucStaLoopCnt; + u8 ucDebugTc; +#endif + + /* Sanity Check */ + if (!u4CurrentQuota) { + DBGLOG(TX, LOUD, + "(Fairness) Skip TC = %u due to u4CurrentQuota = 0\n", + ucTC); + return u4CurrentQuota; + } + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + /* check all active peer has one VO mapping to TC3_INDEX + * based on aucTid2ACI & arNetwork2TcResource + * TID6/7 => WMM_AC_VO_INDEX => TC3_INDEX + */ + /* + * Jungle specific Unicast for audio distribution + */ + if (ucTC == TC3_INDEX && prAdapter->fgIsUcastBurstMode) { + u32 i; + u32 u4TxCheckPeer = 0, u4ActivePeer = 0; + u32 u4CurrTime = 0, u4ArrivalTime = 0; + u8 fgTxTimeout = false; + + u4CurrTime = (u32)kalGetTimeTick(); + for (i = 0; i < CFG_STA_REC_NUM; i++) { + prStaRec = (P_STA_RECORD_T)&prAdapter->arStaRec[i]; + prCurrQueue = &prStaRec->arTxQueue[ucTC]; + // Let's use In Use StaRec at this stage + if (prStaRec->fgIsInUse) { + /* + * if (prStaRec->fgIsInUse && + * prStaRec->ucBssIndex == P2P_DEV_BSS_INDEX + * && prStaRec->fgIsTxAllowed == true) { + */ + u4ActivePeer |= BIT(i); // record active peer + if (QUEUE_IS_NOT_EMPTY(prCurrQueue)) { + u4TxCheckPeer |= BIT(i); // record + // active and + // has pkt peer + prDequeuedPkt = + (P_MSDU_INFO_T)QUEUE_GET_HEAD( + prCurrQueue); + u4ArrivalTime = + GLUE_GET_PKT_ARRIVAL_TIME( + prDequeuedPkt->prPacket); + + /* check timeout */ + if ((u4CurrTime > u4ArrivalTime) && + ((u4CurrTime - u4ArrivalTime) > + prAdapter->ucUnicastBurstTimeout)) { + + fgTxTimeout = true; + }else if (u4CurrTime < u4ArrivalTime && + ((u4CurrTime + + (0xFFFFFFFF - + u4ArrivalTime)) > + prAdapter + ->ucUnicastBurstTimeout)) { + fgTxTimeout = true; + } + } + DBGLOG(TX, + ERROR, + "[Act:0x%x/TxChk:0x%x] u4ArrivalTime:%d u4CurrTime:%d\n", + u4ActivePeer, + u4TxCheckPeer, + u4ArrivalTime, + u4CurrTime); + } + } + if ((u4TxCheckPeer != u4ActivePeer) && !fgTxTimeout) { + DBGLOG(TX, + ERROR, + "[UC buffering!]u4TxCheckPeer:0x%x u4ActivePeer:0x%x fgTxTimeout=%d", + u4TxCheckPeer, + u4ActivePeer, + fgTxTimeout); + return 0; + } + } +#endif + + /* 4 <1> Assign init value */ + u4AvaliableResource = u4CurrentQuota; + u4MaxResourceLimit = u4TotalQuota; + +#if QM_FORWARDING_FAIRNESS + u4CurStaIndex = prQM->au4HeadStaRecIndex[ucTC]; + u4CurStaUsedResource = prQM->au4ResourceUsedCount[ucTC]; +#endif + + fgEndThisRound = false; + ucLoop = 0; + u4CurStaForwardFrameCount = 0; + + DBGLOG(QM, LOUD, "(Fairness) TC[%u] Init Head STA[%u] Resource[%u]\n", + ucTC, u4CurStaIndex, u4AvaliableResource); + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + if (u4CurStaIndex >= CFG_STA_REC_NUM) { + DBGLOG(QM, ERROR, "Invalid StaRecIdx.\n"); + return u4CurrentQuota; + } + + ucDebugTc = ucTC; + + if (ucTC == TC16_INDEX) { + /*wmm 3: AC0-AC3 maps to TC16*/ + ucStaLoopCnt = NUM_OF_PER_STA_TX_QUEUES; + ucWmmIdx = MAX_HW_WMM_INDEX; + ucTC = 0; + } else { + /*general way: one TC index maps to one AC index*/ + ucStaLoopCnt = 1; + + /*get wmm set idex*/ + ucWmmIdx = nicTxGetWmmIdxByTc(ucTC); + + /*translate TC into ac index of STA queue*/ + ucFlagHit = 0; + for (ucAcIdx = 0; ucAcIdx < TC_NUM_PER_WMM; ucAcIdx++) { + if (arTcRemapTable[ucWmmIdx][ucAcIdx] == ucTC) { + ucFlagHit = 1; + break; + } + } + + if (ucFlagHit == 0) { + /*not found*/ + DBGLOG(HIF_WMM_ENHANCE, + ERROR, + "Cannot find corresponding STA AC index. (%d, %d)\n", + ucWmmIdx, + ucTC); + return u4CurrentQuota; + } + + /*update real STA AC index*/ + ucTC = ucAcIdx; + } + DBGLOG(HIF_WMM_ENHANCE, LOUD, "Tc[%d], ucWmmIdx[%d] Ac[%d]\n", + ucDebugTc, ucWmmIdx, ucTC); + + if (ucTC >= NUM_OF_PER_STA_TX_QUEUES) { + DBGLOG(HIF_WMM_ENHANCE, ERROR, + "Invalid STA AC index. (%d, %d)\n", ucWmmIdx, ucTC); + + return u4CurrentQuota; + } +#endif + + /* 4 <2> Traverse STA array from Head STA */ + /* From STA[x] to STA[x+1] to STA[x+2] to ... to STA[x] */ + while (ucLoop < CFG_STA_REC_NUM) { + prStaRec = &prAdapter->arStaRec[u4CurStaIndex]; + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + /*assign loop count for the STA*/ + ucAcIdxVldCnt = ucStaLoopCnt; +#endif + + prCurrQueue = &prStaRec->arTxQueue[ucTC]; +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + if (prStaRec->fgIsInUse == false) { + goto NEXT; + } + + prBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + if (!prBssInfo) { + goto NEXT; + } + + if (prBssInfo->ucWmmQueSet != ucWmmIdx) { + goto NEXT; + } + + DBGLOG(HIF_WMM_ENHANCE, LOUD, + "Loop StaRec. Sta [%d], wmmSet [%d]\n", u4CurStaIndex, + prBssInfo->ucWmmQueSet); + + while (ucAcIdxVldCnt) { + ucAcIdxVldCnt -= 1; + + if (!ucAcIdxVldCnt) { + /*normal way. One TC maps to one AC*/ + /*use final decided ucTc above*/ + } else { + /* wmm_3 case. Loop 4 times for this STA*/ + /*AC3 --> AC2 --> AC1 --> AC0*/ + prCurrQueue = + &prStaRec->arTxQueue[ucAcIdxVldCnt]; + } + + if (!prCurrQueue) { + goto NEXT; + } +#endif + + /* 4 <2.1> Find a Tx allowed STA */ + /* Only Data frame will be queued in */ + /* if (prStaRec->fgIsTxAllowed) { */ + if (QUEUE_IS_NOT_EMPTY(prCurrQueue)) { + prBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, prStaRec->ucBssIndex); + + /* prCurrQueue = &prStaRec->aprTxQueue[ucTC]; */ + prDequeuedPkt = NULL; + pucPsStaFreeQuota = NULL; + /* Set default forward count limit to unlimited + */ + u4MaxForwardFrameCountLimit = + QM_STA_FORWARD_COUNT_UNLIMITED; + + /* 4 <2.2> Update forward frame/page count limit + * for this STA */ + /* AP mode: STA in PS buffer handling */ + if (prStaRec->fgIsInPS) { + if (prStaRec->fgIsQoS && + prStaRec->fgIsUapsdSupported && + (prStaRec->ucBmpTriggerAC & + BIT(ucTC))) { + u4MaxForwardFrameCountLimit = + prStaRec->ucFreeQuotaForDelivery; + pucPsStaFreeQuota = + &prStaRec-> + ucFreeQuotaForDelivery; + } else { + /* ASSERT(prStaRec->ucFreeQuotaForDelivery + * == 0); */ + u4MaxForwardFrameCountLimit = + prStaRec-> + ucFreeQuotaForNonDelivery; + pucPsStaFreeQuota = + &prStaRec-> + ucFreeQuotaForNonDelivery; + } + } + + /* fgIsInPS */ + /* Absent BSS handling */ + if (prBssInfo->fgIsNetAbsent) { + if (u4MaxForwardFrameCountLimit > + prBssInfo->ucBssFreeQuota) { + u4MaxForwardFrameCountLimit = + prBssInfo + ->ucBssFreeQuota; + } + } + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + /*remove DBDC quota hard rule restriction*/ +#else +#if CFG_SUPPORT_DBDC + if (prAdapter->rWifiVar.fgDbDcModeEn) { + u4MaxResourceLimit = gmGetDequeueQuota( + prAdapter, prStaRec, prBssInfo, + u4TotalQuota); + } +#endif +#endif + + /* 4 <2.3> Dequeue packet */ + /* Three cases to break: (1) No resource (2) No + * packets (3) Fairness */ + while (!QUEUE_IS_EMPTY(prCurrQueue)) { + prDequeuedPkt = + (P_MSDU_INFO_T)QUEUE_GET_HEAD( + prCurrQueue); + + if ((u4CurStaForwardFrameCount >= + u4MaxForwardFrameCountLimit) || + (u4CurStaUsedResource >= + u4MaxResourceLimit)) { + /* Exceeds Limit */ + + break; + } else if (prDequeuedPkt->u4PageCount > + u4AvaliableResource) { + /* Available Resource is not + * enough */ + if (!(prAdapter->rWifiVar + .ucAlwaysResetUsedRes & + BIT(0))) { + fgEndThisRound = true; + } + break; + } + /* Available to be Tx */ + + QUEUE_REMOVE_HEAD(prCurrQueue, + prDequeuedPkt, + P_MSDU_INFO_T); + + if (!QUEUE_IS_EMPTY(prCurrQueue)) { + /* XXX: check all queues for STA + */ + prDequeuedPkt + ->ucPsForwardingType = + PS_FORWARDING_MORE_DATA_ENABLED; + } + prDequeuedPkt->ucWmmQueSet = + prBssInfo->ucWmmQueSet; /* to + * record + * WMM + * Set + */ + QUEUE_INSERT_TAIL( + prQue, + (P_QUE_ENTRY_T)prDequeuedPkt); + + u4AvaliableResource -= + prDequeuedPkt->u4PageCount; + u4CurStaUsedResource += + prDequeuedPkt->u4PageCount; + u4CurStaForwardFrameCount++; +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + DBGLOG(HIF_WMM_ENHANCE, LOUD, + "Real DeQ: u4AvaliableResource = %d\n", + u4AvaliableResource); +#endif + } + + /* AP mode: Update STA in PS Free quota */ + if (prStaRec->fgIsInPS && pucPsStaFreeQuota) { + if ((*pucPsStaFreeQuota) >= + u4CurStaForwardFrameCount) { + (*pucPsStaFreeQuota) -= + u4CurStaForwardFrameCount; + } else { + (*pucPsStaFreeQuota) = 0; + } + } + + if (prBssInfo->fgIsNetAbsent) { + if (prBssInfo->ucBssFreeQuota >= + u4CurStaForwardFrameCount) { + prBssInfo->ucBssFreeQuota -= + u4CurStaForwardFrameCount; + } else { + prBssInfo->ucBssFreeQuota = 0; + } + } + } + + if (fgEndThisRound) { + /* End this round */ + break; + } + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + } + if (fgEndThisRound) { + /* End both WMM and STArec round */ + break; + } +#endif + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) +NEXT: +#endif + + /* Prepare for next STA */ + ucLoop++; + u4CurStaIndex++; + u4CurStaIndex %= CFG_STA_REC_NUM; + u4CurStaUsedResource = 0; + u4CurStaForwardFrameCount = 0; + } + + /* 4 <3> Store Head Sta information to QM */ + /* No need to count used resource if thers is only one STA */ + if ((prQM->u4TxAllowedStaCount == 1) || + (prAdapter->rWifiVar.ucAlwaysResetUsedRes & BIT(1))) { + u4CurStaUsedResource = 0; + } + +#if QM_FORWARDING_FAIRNESS + prQM->au4HeadStaRecIndex[ucTC] = u4CurStaIndex; + prQM->au4ResourceUsedCount[ucTC] = u4CurStaUsedResource; +#endif + + DBGLOG(QM, LOUD, + "(Fairness) TC[%u] Scheduled Head STA[%u] Left Resource[%u]\n", + ucTC, u4CurStaIndex, u4AvaliableResource); + + return u4AvaliableResource; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Dequeue TX packets from a per-Type-based Queue for a particular TC + * + * \param[out] prQue The queue to put the dequeued packets + * \param[in] ucTC The TC index (Shall always be TC5_INDEX) + * \param[in] ucMaxNum The maximum amount of available resource + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmDequeueTxPacketsFromPerTypeQueues(IN P_ADAPTER_T prAdapter, + OUT P_QUE_T prQue, IN u8 ucTC, + IN u32 u4CurrentQuota, + IN u32 u4TotalQuota) +{ + u32 u4AvaliableResource, u4LeftResource; + u32 u4MaxResourceLimit; + u32 u4TotalUsedResource = 0; + P_QUE_MGT_T prQM; + PFN_DEQUEUE_FUNCTION pfnDeQFunc[2]; + u8 fgChangeDeQFunc = true; + u8 fgGlobalQueFirst = true; + + DBGLOG(QM, LOUD, "Enter %s (TC = %d, quota = %u)\n", __func__, ucTC, + u4CurrentQuota); +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + DBGLOG(HIF_WMM_ENHANCE, LOUD, "-->TC = %d, quota = %u\n", ucTC, + u4CurrentQuota); +#endif + + /* Broadcast/Multicast data packets */ + if ((u4CurrentQuota == 0)) { + return; + } + + prQM = &prAdapter->rQM; + + u4AvaliableResource = u4CurrentQuota; + u4MaxResourceLimit = u4TotalQuota; +#if QM_FORWARDING_FAIRNESS + u4TotalUsedResource = prQM->u4GlobalResourceUsedCount; + fgGlobalQueFirst = prQM->fgGlobalQFirst; +#endif + + /* Dequeue function selection */ + if (fgGlobalQueFirst /*will toggle*/ ) { + pfnDeQFunc[0] = qmDequeueTxPacketsFromGlobalQueue; + pfnDeQFunc[1] = qmDequeueTxPacketsFromPerStaQueues; + } else { + pfnDeQFunc[0] = qmDequeueTxPacketsFromPerStaQueues; + pfnDeQFunc[1] = qmDequeueTxPacketsFromGlobalQueue; + } + + /* 1st dequeue function */ + u4LeftResource = + pfnDeQFunc[0](prAdapter, prQue, ucTC, u4AvaliableResource, + (u4MaxResourceLimit - u4TotalUsedResource)); + + /* dequeue function comsumes no resource, change */ + if ((u4LeftResource >= u4AvaliableResource) && + (u4AvaliableResource >= NIC_TX_MAX_PAGE_PER_FRAME)) { + fgChangeDeQFunc = true; + } else { + u4TotalUsedResource += (u4AvaliableResource - u4LeftResource); + /* Used resource exceeds limit, change */ + if (u4TotalUsedResource >= u4MaxResourceLimit) { + fgChangeDeQFunc = true; + } + } + + if (fgChangeDeQFunc) { + fgGlobalQueFirst = !fgGlobalQueFirst; + u4TotalUsedResource = 0; + } + + /* 2nd dequeue function */ + u4LeftResource = pfnDeQFunc[1](prAdapter, prQue, ucTC, u4LeftResource, + u4MaxResourceLimit); + +#if QM_FORWARDING_FAIRNESS + prQM->fgGlobalQFirst = fgGlobalQueFirst; + prQM->u4GlobalResourceUsedCount = u4TotalUsedResource; +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Dequeue TX packets from a QM global Queue for a particular TC + * + * \param[out] prQue The queue to put the dequeued packets + * \param[in] ucTC The TC index (Shall always be TC5_INDEX) + * \param[in] ucMaxNum The maximum amount of available resource + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +u32 qmDequeueTxPacketsFromGlobalQueue(IN P_ADAPTER_T prAdapter, + OUT P_QUE_T prQue, IN u8 ucTC, + IN u32 u4CurrentQuota, + IN u32 u4TotalQuota) +{ + P_BSS_INFO_T prBssInfo; + P_QUE_T prCurrQueue; + u32 u4AvaliableResource; + P_MSDU_INFO_T prDequeuedPkt; + P_MSDU_INFO_T prBurstEndPkt; + QUE_T rMergeQue; + P_QUE_T prMergeQue; + P_QUE_MGT_T prQM; +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + u8 ucWmmSet, i; +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + u8 ucBmcTcIdx; +#endif +#endif + + DBGLOG(QM, LOUD, "Enter %s (TC = %d, quota = %u)\n", __func__, ucTC, + u4CurrentQuota); + + /* Broadcast/Multicast data packets */ + if (u4CurrentQuota == 0) { + return u4CurrentQuota; + } + + prQM = &prAdapter->rQM; + + /* 4 <1> Determine the queue */ +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + /*check if it is a TC that supports BCM_IDX too.*/ + ucWmmSet = 0xFF; + for (i = 0; i < HW_WMM_NUM; i++) { +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + ucBmcTcIdx = qmFuncGetBmcTcIdx(0); + if (ucTC == arTcRemapTable[i][ucBmcTcIdx]) +#else + if (ucTC == arTcRemapTable[i][BMC_TC_INDEX]) +#endif + { + ucWmmSet = i; + break; + } + } + if (ucWmmSet >= HW_WMM_NUM) { + /*not TC also supportting BCM_IDX*/ + return u4CurrentQuota; + } +#endif +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + /*get BCM data queue*/ + prCurrQueue = &prQM->arTxQueue[ucWmmSet]; +#else + prCurrQueue = &prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST]; +#endif + u4AvaliableResource = u4CurrentQuota; + prDequeuedPkt = NULL; + prBurstEndPkt = NULL; + + QUEUE_INITIALIZE(&rMergeQue); + prMergeQue = &rMergeQue; + + /* 4 <2> Dequeue packets */ + while (!QUEUE_IS_EMPTY(prCurrQueue)) { + prDequeuedPkt = (P_MSDU_INFO_T)QUEUE_GET_HEAD(prCurrQueue); + if (prDequeuedPkt->u4PageCount > u4AvaliableResource) { + break; + } + + QUEUE_REMOVE_HEAD(prCurrQueue, prDequeuedPkt, P_MSDU_INFO_T); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, + prDequeuedPkt->ucBssIndex); + + if (IS_BSS_ACTIVE(prBssInfo)) { + if (!prBssInfo->fgIsNetAbsent) { + prDequeuedPkt->ucWmmQueSet = + prBssInfo->ucWmmQueSet; /* to record WMM + * Set */ + QUEUE_INSERT_TAIL(prQue, + (P_QUE_ENTRY_T)prDequeuedPkt); + prBurstEndPkt = prDequeuedPkt; + u4AvaliableResource -= + prDequeuedPkt->u4PageCount; + QM_DBG_CNT_INC(prQM, QM_DBG_CNT_26); + } else { + QUEUE_INSERT_TAIL(prMergeQue, + (P_QUE_ENTRY_T)prDequeuedPkt); + } + } else { + QM_TX_SET_NEXT_MSDU_INFO(prDequeuedPkt, NULL); + wlanProcessQueuedMsduInfo(prAdapter, prDequeuedPkt); + } + } + + if (QUEUE_IS_NOT_EMPTY(prMergeQue)) { + QUEUE_CONCATENATE_QUEUES(prMergeQue, prCurrQueue); + QUEUE_MOVE_ALL(prCurrQueue, prMergeQue); + QM_TX_SET_NEXT_MSDU_INFO( + (P_MSDU_INFO_T)QUEUE_GET_TAIL(prCurrQueue), NULL); + } + + return u4AvaliableResource; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Dequeue TX packets to send to HIF TX + * + * \param[in] prTcqStatus Info about the maximum amount of dequeued packets + * + * \return The list of dequeued TX packets + */ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T qmDequeueTxPackets(IN P_ADAPTER_T prAdapter, + IN P_TX_TCQ_STATUS_T prTcqStatus) +{ + s32 i; + P_MSDU_INFO_T prReturnedPacketListHead; + QUE_T rReturnedQue; + u32 u4MaxQuotaLimit; +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + u8 ucBmcTcIdx; +#endif +#endif + + DBGLOG(QM, LOUD, "Enter qmDequeueTxPackets\n"); + + QUEUE_INITIALIZE(&rReturnedQue); + + prReturnedPacketListHead = NULL; + + /* TC0 to TC3: AC0~AC3 (commands packets are not handled by QM) */ +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + for (i = TC0_INDEX; i < TC_NUM; i++) { + if ((i == TC4_INDEX) || (i == TC5_INDEX) || (i == TC10_INDEX) || + (i == TC15_INDEX)) { + /*ignore TC4: command, TC5/TC10/TC15: not use*/ + continue; + } +#else + for (i = TC3_INDEX; i >= TC0_INDEX; i--) { +#endif + DBGLOG(QM, LOUD, "Dequeue packets from Per-STA queue[%u]\n", i); + + /* If only one STA is Tx allowed, no need to restrict Max quota + */ + if (prAdapter->rWifiVar.u4MaxTxDeQLimit) { + u4MaxQuotaLimit = prAdapter->rWifiVar.u4MaxTxDeQLimit; + } else if (prAdapter->rQM.u4TxAllowedStaCount == 1) { + u4MaxQuotaLimit = QM_STA_FORWARD_COUNT_UNLIMITED; + } else { + u4MaxQuotaLimit = (u32)prTcqStatus->au4MaxNumOfPage[i]; + } + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + ucBmcTcIdx = qmFuncGetBmcTcIdx(0); + + if ((i == ucBmcTcIdx) || (i == arTcRemapTable[1][ucBmcTcIdx]) || + (i == arTcRemapTable[2][ucBmcTcIdx]) || + (i == arTcRemapTable[3][ucBmcTcIdx])) +#else + if ((i == BMC_TC_INDEX) || + (i == arTcRemapTable[1][BMC_TC_INDEX]) || + (i == arTcRemapTable[2][BMC_TC_INDEX]) || + (i == arTcRemapTable[3][BMC_TC_INDEX])) +#endif +#else +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + /* Due to dynamic BMC TC index feature. + * Replace this MACRO to a true TC index which BMC would use. + * + * Always get TcIdx from WmmSet0 as there is only one WmmSet + * when Tx Wmm Res Enhancement is disabled + */ + if (i == qmFuncGetBmcTcIdx(0)) +#else + if (i == BMC_TC_INDEX) +#endif +#endif + { + qmDequeueTxPacketsFromPerTypeQueues( + prAdapter, &rReturnedQue, (u8)i, + prTcqStatus->au4FreePageCount[i], + u4MaxQuotaLimit); + } else { + qmDequeueTxPacketsFromPerStaQueues( + prAdapter, &rReturnedQue, (u8)i, + prTcqStatus->au4FreePageCount[i], + u4MaxQuotaLimit); + } + + /* The aggregate number of dequeued packets */ + DBGLOG(QM, LOUD, "DQA)[%u](%lu)\n", i, rReturnedQue.u4NumElem); + } + + if (QUEUE_IS_NOT_EMPTY(&rReturnedQue)) { + prReturnedPacketListHead = + (P_MSDU_INFO_T)QUEUE_GET_HEAD(&rReturnedQue); + QM_TX_SET_NEXT_MSDU_INFO( + (P_MSDU_INFO_T)QUEUE_GET_TAIL(&rReturnedQue), NULL); + } + + return prReturnedPacketListHead; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Dequeue TX packets to send to HIF TX + * + * \param[in] prTcqStatus Info about the maximum amount of dequeued packets + * + * \return The list of dequeued TX packets + */ +/*----------------------------------------------------------------------------*/ +P_MSDU_INFO_T qmDequeueTxPacketsMthread(IN P_ADAPTER_T prAdapter, + IN P_TX_TCQ_STATUS_T prTcqStatus) +{ + /* s32 i; */ + P_MSDU_INFO_T prReturnedPacketListHead; + /* QUE_T rReturnedQue; */ + /* u32 u4MaxQuotaLimit; */ + P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; + + KAL_SPIN_LOCK_DECLARATION(); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + prReturnedPacketListHead = qmDequeueTxPackets(prAdapter, prTcqStatus); + + /* require the resource first to prevent from unsync */ + prMsduInfo = prReturnedPacketListHead; + while (prMsduInfo) { + prNextMsduInfo = (P_MSDU_INFO_T)QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prMsduInfo); + nicTxAcquireResource(prAdapter, prMsduInfo->ucTC, false); + prMsduInfo = prNextMsduInfo; + } + + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + return prReturnedPacketListHead; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adjust the TC quotas according to traffic demands + * + * \param[out] prTcqAdjust The resulting adjustment + * \param[in] prTcqStatus Info about the current TC quotas and counters + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +u8 qmAdjustTcQuotasMthread(IN P_ADAPTER_T prAdapter, + OUT P_TX_TCQ_ADJUST_T prTcqAdjust, + IN P_TX_TCQ_STATUS_T prTcqStatus) +{ +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + u32 i; + P_QUE_MGT_T prQM = &prAdapter->rQM; +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + s8 j; + u8 startTc; + P_TX_CTRL_T prTxCtrl; +#endif + + KAL_SPIN_LOCK_DECLARATION(); + + /* Must initialize */ + for (i = 0; i < QM_ACTIVE_TC_NUM; i++) + prTcqAdjust->ai4Variation[i] = 0; + + /* 4 <1> If TC resource is not just adjusted, exit directly */ + if (!prQM->fgTcResourcePostAnnealing) { + return false; + } + /* 4 <2> Adjust TcqStatus according to the updated + * prQM->au4CurrentTcResource */ + else { + s32 i4TotalExtraQuota = 0; + s32 ai4ExtraQuota[QM_ACTIVE_TC_NUM]; + u8 fgResourceRedistributed = true; + + /* Must initialize */ + for (i = 0; i < TC_NUM; i++) + prTcqAdjust->ai4Variation[i] = 0; + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + /* Obtain the free-to-distribute resource */ + for (i = 0; i < QM_ACTIVE_TC_NUM; i++) { + ai4ExtraQuota[i] = + (s32)prTcqStatus->au4MaxNumOfBuffer[i] - + (s32)prQM->au4CurrentTcResource[i]; + + if (ai4ExtraQuota[i] > 0) { /* The resource shall be + * reallocated to other TCs + */ + if (ai4ExtraQuota[i] > + prTcqStatus->au4FreeBufferCount[i]) { + ai4ExtraQuota[i] = + prTcqStatus + ->au4FreeBufferCount[i]; + fgResourceRedistributed = false; + } + + i4TotalExtraQuota += ai4ExtraQuota[i]; + prTcqAdjust->ai4Variation[i] = + (-ai4ExtraQuota[i]); + } + } + + /* Distribute quotas to TCs which need extra resource according + * to prQM->au4CurrentTcResource */ +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + /*start from VO*/ + startTc = arTcRemapTable[prTxCtrl->rTc.ucNextHifWmmIdx][3]; + + /*update next index*/ + prTxCtrl->rTc.ucNextHifWmmIdx++; + prTxCtrl->rTc.ucNextHifWmmIdx %= HIF_WMM_SET_NUM; + + for (j = QM_ACTIVE_TC_NUM; j > 0; j--) { + i = (startTc + j) % QM_ACTIVE_TC_NUM; + + if (i >= QM_ACTIVE_TC_NUM) { + return false; + } + +#else + for (i = 0; i < QM_ACTIVE_TC_NUM; i++) { +#endif + + if (ai4ExtraQuota[i] < 0) { + if ((-ai4ExtraQuota[i]) > i4TotalExtraQuota) { + ai4ExtraQuota[i] = (-i4TotalExtraQuota); + fgResourceRedistributed = false; + } + + i4TotalExtraQuota += ai4ExtraQuota[i]; + prTcqAdjust->ai4Variation[i] = + (-ai4ExtraQuota[i]); + } + } + + /* In case some TC is waiting for TX Done, continue to adjust TC + * quotas upon TX Done */ + prQM->fgTcResourcePostAnnealing = (!fgResourceRedistributed); + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + /* Fix TC9 AVQ=9x but qmDoAdaptiveTcResourceCtrl() + * is not called, + * resulting in TC9 has no resource to transmit + */ + if (prQM->fgTcResourceFastReaction) { + prQM->fgTcResourcePostAnnealing = false; + prQM->u4TimeToAdjustTcResource = 1; + } +#endif + + for (i = 0; i < TC_NUM; i++) { + prTcqStatus->au4FreePageCount[i] += + (prTcqAdjust->ai4Variation[i] * + NIC_TX_MAX_PAGE_PER_FRAME); + prTcqStatus->au4MaxNumOfPage[i] += + (prTcqAdjust->ai4Variation[i] * + NIC_TX_MAX_PAGE_PER_FRAME); + + prTcqStatus->au4FreeBufferCount[i] += + prTcqAdjust->ai4Variation[i]; + prTcqStatus->au4MaxNumOfBuffer[i] += + prTcqAdjust->ai4Variation[i]; + + ASSERT(prTcqStatus->au4FreeBufferCount[i] >= 0); + ASSERT(prTcqStatus->au4MaxNumOfBuffer[i] >= 0); + } + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + { + DBGLOG(HIF_WMM_ENHANCE, LOUD, "Adjust Quota"); + for (i = 0; i < TC_NUM; i++) { + DBGLOG(HIF_WMM_ENHANCE, LOUD, + "Adjust Quota: [TC%u]=%u, (Var=%d)\n", i, + prTcqStatus->au4FreeBufferCount[i], + prTcqAdjust->ai4Variation[i]); + } + } +#endif + +#if QM_FAST_TC_RESOURCE_CTRL + prQM->fgTcResourceFastReaction = false; +#endif + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + } + + return true; + +#else + return false; + +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adjust the TC quotas according to traffic demands + * + * \param[out] prTcqAdjust The resulting adjustment + * \param[in] prTcqStatus Info about the current TC quotas and counters + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +u8 qmAdjustTcQuotas(IN P_ADAPTER_T prAdapter, OUT P_TX_TCQ_ADJUST_T prTcqAdjust, + IN P_TX_TCQ_STATUS_T prTcqStatus) +{ +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + u32 i; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + /* Must initialize */ + for (i = 0; i < QM_ACTIVE_TC_NUM; i++) + prTcqAdjust->ai4Variation[i] = 0; + + /* 4 <1> If TC resource is not just adjusted, exit directly */ + if (!prQM->fgTcResourcePostAnnealing) { + return false; + } + /* 4 <2> Adjust TcqStatus according to the updated + * prQM->au4CurrentTcResource */ + else { + s32 i4TotalExtraQuota = 0; + s32 ai4ExtraQuota[QM_ACTIVE_TC_NUM]; + u8 fgResourceRedistributed = true; + + /* Obtain the free-to-distribute resource */ + for (i = 0; i < QM_ACTIVE_TC_NUM; i++) { + ai4ExtraQuota[i] = + (s32)prTcqStatus->au4MaxNumOfBuffer[i] - + (s32)prQM->au4CurrentTcResource[i]; + + if (ai4ExtraQuota[i] > 0) { /* The resource shall be + * reallocated to other TCs + */ + if (ai4ExtraQuota[i] > + prTcqStatus->au4FreeBufferCount[i]) { + ai4ExtraQuota[i] = + prTcqStatus + ->au4FreeBufferCount[i]; + fgResourceRedistributed = false; + } + + i4TotalExtraQuota += ai4ExtraQuota[i]; + prTcqAdjust->ai4Variation[i] = + (-ai4ExtraQuota[i]); + } + } + + /* Distribute quotas to TCs which need extra resource according + * to prQM->au4CurrentTcResource */ + for (i = 0; i < QM_ACTIVE_TC_NUM; i++) { + if (ai4ExtraQuota[i] < 0) { + if ((-ai4ExtraQuota[i]) > i4TotalExtraQuota) { + ai4ExtraQuota[i] = (-i4TotalExtraQuota); + fgResourceRedistributed = false; + } + + i4TotalExtraQuota += ai4ExtraQuota[i]; + prTcqAdjust->ai4Variation[i] = + (-ai4ExtraQuota[i]); + } + } + + /* In case some TC is waiting for TX Done, continue to adjust TC + * quotas upon TX Done */ + prQM->fgTcResourcePostAnnealing = (!fgResourceRedistributed); + +#if QM_FAST_TC_RESOURCE_CTRL + prQM->fgTcResourceFastReaction = false; +#endif + +#if QM_PRINT_TC_RESOURCE_CTRL + DBGLOG(QM, + LOUD, + "QM: Curr Quota [0]=%u [1]=%u [2]=%u [3]=%u [4]=%u [5]=%u\n", + prTcqStatus->au4FreeBufferCount[0], + prTcqStatus->au4FreeBufferCount[1], + prTcqStatus->au4FreeBufferCount[2], + prTcqStatus->au4FreeBufferCount[3], + prTcqStatus->au4FreeBufferCount[4], + prTcqStatus->au4FreeBufferCount[5]); +#endif + } + + return true; + +#else + return false; + +#endif +} + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL +/*----------------------------------------------------------------------------*/ +/*! + * \brief Update the average TX queue length for the TC resource control + * mechanism + * + * \param (none) + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) +void qmCalAveQLen(P_QUE_MGT_T prQM, u8 u4Tc, u32 u4CurrQueLen) +{ + if (prQM->au4AverageQueLen[u4Tc] == 0) { + prQM->au4AverageQueLen[u4Tc] = + (u4CurrQueLen << prQM->u4QueLenMovingAverage); + } else { + prQM->au4AverageQueLen[u4Tc] -= (prQM->au4AverageQueLen[u4Tc] >> + prQM->u4QueLenMovingAverage); + + prQM->au4AverageQueLen[u4Tc] += (u4CurrQueLen); + } + + DBGLOG(HIF_WMM_ENHANCE, LOUD, + "TC[%u], u4CurrQueLen = %u, avQLen = %u\n", u4Tc, u4CurrQueLen, + prQM->au4AverageQueLen[u4Tc]); +} +#endif + +void qmUpdateAverageTxQueLen(IN P_ADAPTER_T prAdapter) +{ + s32 u4Tc, u4StaRecIdx; + P_STA_RECORD_T prStaRec; + P_QUE_MGT_T prQM = &prAdapter->rQM; + P_BSS_INFO_T prBssInfo; +#if (HIF_TX_RSRC_WMM_ENHANCE == 0) + s32 u4CurrQueLen; +#endif +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + u32 arStaQNum[TC_NUM] = { 0 }, ucBcmCnt; + u8 ucWmmSet = 0; + + /* 1. Collect stations' each queue length*/ + /*based on AC q index to search all STA_TxQ*/ + for (u4Tc = 0; u4Tc < NUM_OF_PER_STA_TX_QUEUES; u4Tc++) { + /*Per STA search for a specific AC*/ + for (u4StaRecIdx = 0; u4StaRecIdx < CFG_STA_REC_NUM; + u4StaRecIdx++) { + prStaRec = cnmGetStaRecByIndex(prAdapter, u4StaRecIdx); + if (prStaRec) { + prBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, prStaRec->ucBssIndex); + + /* If the STA is activated, + * get the queue length + */ + ucWmmSet = prBssInfo->ucWmmQueSet; + ucWmmSet = arTcRemapTable[ucWmmSet][u4Tc]; + + if ((prStaRec->fgIsValid) && + (!prBssInfo->fgIsNetAbsent)) { + arStaQNum[ucWmmSet] += + prStaRec->arTxQueue[u4Tc] + .u4NumElem; + } + } + } + } + + /* 2. Add BCM_IDX queue length for each wmm set + * and Update total queue length + */ + for (u4Tc = 0; u4Tc < TC_NUM; u4Tc++) { + ucBcmCnt = 0; + for (ucWmmSet = 0; ucWmmSet < HW_WMM_NUM; ucWmmSet++) { + if (u4Tc == arTcRemapTable[ucWmmSet][BMC_TC_INDEX]) { + /*BCM_IDX*/ + ucBcmCnt = prQM->arTxQueue[ucWmmSet].u4NumElem; + break; + } + } + + /*Update total queue length for each TC*/ + qmCalAveQLen(prQM, u4Tc, ucBcmCnt + arStaQNum[u4Tc]); + } +#else + /* 4 <1> Update the queue lengths for TC0 to TC3 (skip TC4) and TC5 */ + for (u4Tc = 0; u4Tc < QM_ACTIVE_TC_NUM; u4Tc++) { + u4CurrQueLen = 0; + + /* Calculate per-STA queue length */ + if (u4Tc < NUM_OF_PER_STA_TX_QUEUES) { + for (u4StaRecIdx = 0; u4StaRecIdx < CFG_STA_REC_NUM; + u4StaRecIdx++) { + prStaRec = cnmGetStaRecByIndex(prAdapter, + u4StaRecIdx); + if (prStaRec) { + prBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, + prStaRec->ucBssIndex); + + /* If the STA is activated, get the + * queue length */ + if ((prStaRec->fgIsValid) && + (!prBssInfo->fgIsNetAbsent)) { + u4CurrQueLen += + (prStaRec->arTxQueue[ + u4Tc] + .u4NumElem); + } + } + } + } + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + /* Due to dynamic BMC TC index feature. + * Replace this MACRO to a true TC index which BMC would use. + * + * Always get TcIdx from WmmSet0 as there is only one WmmSet + * when Tx Wmm Res Enhancement is disabled + */ + if (u4Tc == qmFuncGetBmcTcIdx(0)) { +#else + if (u4Tc == BMC_TC_INDEX) { +#endif + /* Update the queue length for (BMCAST) */ + u4CurrQueLen += + prQM->arTxQueue[TX_QUEUE_INDEX_BMCAST].u4NumElem; + } + + if (prQM->au4AverageQueLen[u4Tc] == 0) { + prQM->au4AverageQueLen[u4Tc] = + (u4CurrQueLen << prQM->u4QueLenMovingAverage); + } else { + prQM->au4AverageQueLen[u4Tc] -= + (prQM->au4AverageQueLen[u4Tc] >> + prQM->u4QueLenMovingAverage); + prQM->au4AverageQueLen[u4Tc] += (u4CurrQueLen); + } + } +#endif +} + +void qmAllocateResidualTcResource(IN P_ADAPTER_T prAdapter, + IN s32 *ai4TcResDemand, + IN u32 *pu4ResidualResource, + IN u32 *pu4ShareCount) +{ + P_QUE_MGT_T prQM = &prAdapter->rQM; + u32 u4Share = 0; + u32 u4TcIdx; + u8 ucIdx; +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + u32 au4AdjTc[] = { TC3_INDEX, TC2_INDEX, TC1_INDEX, TC0_INDEX }; +#else + u32 au4AdjTc[] = { TC3_INDEX, TC2_INDEX, TC5_INDEX, TC1_INDEX, + TC0_INDEX }; +#endif + u32 u4AdjTcSize = (sizeof(au4AdjTc) / sizeof(u32)); + u32 u4ResidualResource = *pu4ResidualResource; + u32 u4ShareCount = *pu4ShareCount; +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + u8 ucHifWmmSet, ucRealTc; +#endif + + /* If there is no resource left, exit directly */ + if (u4ResidualResource == 0) { + return; + } + + /* This shall not happen */ + if (u4ShareCount == 0) { + prQM->au4CurrentTcResource[TC1_INDEX] += u4ResidualResource; + DBGLOG(QM, ERROR, "QM: (Error) u4ShareCount = 0\n"); + return; + } + + /* Share the residual resource evenly */ + u4Share = (u4ResidualResource / u4ShareCount); + if (u4Share) { + for (u4TcIdx = 0; u4TcIdx < QM_ACTIVE_TC_NUM; u4TcIdx++) { + /* Skip TC4 (not adjustable) */ + if (u4TcIdx == TC4_INDEX) { + continue; + } + + if (ai4TcResDemand[u4TcIdx] > 0) { + if (ai4TcResDemand[u4TcIdx] > u4Share) { + prQM->au4CurrentTcResource[u4TcIdx] += + u4Share; + u4ResidualResource -= u4Share; + ai4TcResDemand[u4TcIdx] -= u4Share; + } else { + prQM->au4CurrentTcResource[u4TcIdx] += + ai4TcResDemand[u4TcIdx]; + u4ResidualResource -= + ai4TcResDemand[u4TcIdx]; + ai4TcResDemand[u4TcIdx] = 0; + u4ShareCount--; + } + } + } + } + + /* By priority, + * allocate the left resource that is not divisible by u4Share + */ + ucIdx = 0; + while (u4ResidualResource) { + u4TcIdx = au4AdjTc[ucIdx]; +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + for (ucHifWmmSet = 0; ucHifWmmSet < HIF_WMM_SET_NUM; + ucHifWmmSet++) { + ucRealTc = arTcRemapTable[ucHifWmmSet][u4TcIdx]; + + if (ai4TcResDemand[ucRealTc]) { + prQM->au4CurrentTcResource[ucRealTc]++; + u4ResidualResource--; + ai4TcResDemand[ucRealTc]--; + + if (ai4TcResDemand[ucRealTc] == 0) { + u4ShareCount--; + } + } +#else + if (ai4TcResDemand[u4TcIdx]) { + prQM->au4CurrentTcResource[u4TcIdx]++; + u4ResidualResource--; + ai4TcResDemand[u4TcIdx]--; + + if (ai4TcResDemand[u4TcIdx] == 0) { + u4ShareCount--; + } + } +#endif + if (u4ShareCount <= 0) { + break; + } +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + } + + if (u4ShareCount == 0) { + /*break from while loop*/ + break; + } +#endif + + ucIdx++; + ucIdx %= u4AdjTcSize; + } + + /* Allocate the left resource */ + prQM->au4CurrentTcResource[TC3_INDEX] += u4ResidualResource; + + *pu4ResidualResource = u4ResidualResource; + *pu4ShareCount = u4ShareCount; + } + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Assign TX resource for each TC according to TX queue length and + * current assignment + * + * \param (none) + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ + void qmReassignTcResource(IN P_ADAPTER_T prAdapter) + { + s32 i4TotalResourceDemand = 0; + u32 u4ResidualResource = 0; + u32 u4TcIdx; + s32 ai4TcResDemand[QM_ACTIVE_TC_NUM]; + u32 u4ShareCount = 0; + u32 u4Share = 0; + P_QUE_MGT_T prQM = &prAdapter->rQM; + u32 u4ActiveTcCount = 0; + u32 u4LastActiveTcIdx = TC3_INDEX; + + /* Note: After the new assignment is obtained, set + * prQM->fgTcResourcePostAnnealing to true to start the TC-quota + * adjusting procedure, which will be invoked upon every TX Done + */ + + /* 4 <1> Determine the demands */ + /* Determine the amount of extra resource to fulfill all of the demands + */ + for (u4TcIdx = 0; u4TcIdx < QM_ACTIVE_TC_NUM; u4TcIdx++) { + /* Skip TC4, which is not adjustable */ + if (u4TcIdx == TC4_INDEX) { + continue; + } + + /* Define: extra_demand = que_length + min_reserved_quota - + * current_quota */ + ai4TcResDemand[u4TcIdx] = + ((s32)(QM_GET_TX_QUEUE_LEN(prAdapter, u4TcIdx) + + prQM->au4MinReservedTcResource[u4TcIdx]) + - + (s32)prQM->au4CurrentTcResource[u4TcIdx]); + + DBGLOG(QM, + TRACE, + "TC[%u] Demend=%d, Qlen=%u, MinRsrv=%u, Current=%u\n", + u4TcIdx, + ai4TcResDemand[u4TcIdx], + QM_GET_TX_QUEUE_LEN(prAdapter, u4TcIdx), + prQM->au4MinReservedTcResource[u4TcIdx], + prQM->au4CurrentTcResource[u4TcIdx]); + + /* If there are queued packets, allocate extra resource for the + * TC (for TCP consideration) */ + if (QM_GET_TX_QUEUE_LEN(prAdapter, u4TcIdx)) { + ai4TcResDemand[u4TcIdx] += + prQM->u4ExtraReservedTcResource; + u4ActiveTcCount++; + } + + i4TotalResourceDemand += ai4TcResDemand[u4TcIdx]; + } + + /* 4 <2> Case 1: Demand <= Total Resource */ + if (i4TotalResourceDemand <= 0) { + /* 4 <2.1> Calculate the residual resource evenly */ + if (u4ActiveTcCount == 0) { + u4ShareCount = (QM_ACTIVE_TC_NUM - 1); /* excluding TC4 + */ + } else { + u4ShareCount = u4ActiveTcCount; + } + u4ResidualResource = (u32)(-i4TotalResourceDemand); + u4Share = (u4ResidualResource / u4ShareCount); + + /* 4 <2.2> Satisfy every TC and share the residual resource + * evenly */ + for (u4TcIdx = 0; u4TcIdx < QM_ACTIVE_TC_NUM; + u4TcIdx++) { + /* Skip TC4 (not adjustable) */ + if (u4TcIdx == TC4_INDEX) { + continue; + } + + prQM->au4CurrentTcResource[u4TcIdx] += + ai4TcResDemand[u4TcIdx]; + + /* Every TC is fully satisfied */ + ai4TcResDemand[u4TcIdx] = 0; + + /* The left resource will be allocated */ + if (QM_GET_TX_QUEUE_LEN(prAdapter, u4TcIdx) || + (u4ActiveTcCount == 0)) { + prQM->au4CurrentTcResource[u4TcIdx] += + u4Share; + u4ResidualResource -= u4Share; + u4LastActiveTcIdx = u4TcIdx; + } + } + + /* 4 <2.3> Allocate the left resource to last active TC */ + prQM->au4CurrentTcResource[u4LastActiveTcIdx] += + (u4ResidualResource); + } + /* 4 <3> Case 2: Demand > Total Resource --> Guarantee a minimum amount + * of resource for each TC */ + else { + u4ShareCount = 0; + u4ResidualResource = prQM->u4ResidualTcResource; + + /* 4 <3.1> Allocated resouce amount = minimum of (guaranteed, + * total demand) */ + for (u4TcIdx = 0; u4TcIdx < QM_ACTIVE_TC_NUM; + u4TcIdx++) { + /* Skip TC4 (not adjustable) */ + if (u4TcIdx == TC4_INDEX) { + continue; + } + + /* The demand can be fulfilled with the guaranteed + * resource amount */ + if ((prQM->au4CurrentTcResource[u4TcIdx] + + ai4TcResDemand[u4TcIdx]) <= + prQM->au4GuaranteedTcResource[u4TcIdx]) { + prQM->au4CurrentTcResource[u4TcIdx] += + ai4TcResDemand[u4TcIdx]; + u4ResidualResource += + (prQM->au4GuaranteedTcResource[ + u4TcIdx] - + prQM->au4CurrentTcResource[ + u4TcIdx]); + ai4TcResDemand[u4TcIdx] = 0; + } + /* The demand can not be fulfilled with the guaranteed + * resource amount */ + else { + ai4TcResDemand[u4TcIdx] -= + (prQM->au4GuaranteedTcResource[ + u4TcIdx] - + prQM->au4CurrentTcResource[ + u4TcIdx]); + + prQM->au4CurrentTcResource[u4TcIdx] = + prQM->au4GuaranteedTcResource[ + u4TcIdx]; + u4ShareCount++; + } + } + + /* 4 <3.2> Allocate the residual resource */ + qmAllocateResidualTcResource(prAdapter, ai4TcResDemand, + &u4ResidualResource, + &u4ShareCount); + } + + prQM->fgTcResourcePostAnnealing = true; + +#if QM_PRINT_TC_RESOURCE_CTRL + /* Debug print */ + DBGLOG(QM, + INFO, + "QM: TC[0-5] Rsc adjust to [%03u:%03u:%03u:%03u:%03u:%03u]\n", + prQM->au4CurrentTcResource[0], + prQM->au4CurrentTcResource[1], + prQM->au4CurrentTcResource[2], + prQM->au4CurrentTcResource[3], + prQM->au4CurrentTcResource[4], + prQM->au4CurrentTcResource[5]); + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + DBGLOG(QM, + INFO, + "QM: TC[6-10] Rsc adjust to [%03u:%03u:%03u:%03u:%03u]\n", + prQM->au4CurrentTcResource[6], + prQM->au4CurrentTcResource[7], + prQM->au4CurrentTcResource[8], + prQM->au4CurrentTcResource[9], + prQM->au4CurrentTcResource[10]); + + DBGLOG(QM, + INFO, + "QM: TC[11-16] Rsc adjust to [%03u:%03u:%03u:%03u:%03u:%03u]\n", + prQM->au4CurrentTcResource[11], + prQM->au4CurrentTcResource[12], + prQM->au4CurrentTcResource[13], + prQM->au4CurrentTcResource[14], + prQM->au4CurrentTcResource[15], + prQM->au4CurrentTcResource[16]); +#endif +#endif + } + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Adjust TX resource for each TC according to TX queue length and + * current assignment + * + * \param (none) + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ + void qmDoAdaptiveTcResourceCtrl(IN P_ADAPTER_T prAdapter) + { + P_QUE_MGT_T prQM = &prAdapter->rQM; + + /* 4 <0> Check to update queue length or not */ + if (--prQM->u4TimeToUpdateQueLen) { + return; + } + + /* 4 <1> Update TC queue length */ + prQM->u4TimeToUpdateQueLen = QM_INIT_TIME_TO_UPDATE_QUE_LEN; + qmUpdateAverageTxQueLen(prAdapter); + + /* 4 <2> Adjust TC resource assignment */ + /* Check whether it is time to adjust the TC resource assignment */ + if (--prQM->u4TimeToAdjustTcResource == 0) { + /* The last assignment has not been completely applied */ + if (prQM->fgTcResourcePostAnnealing) { + /* Upon the next qmUpdateAverageTxQueLen function call, + * do this check again */ + prQM->u4TimeToAdjustTcResource = 1; + } + /* The last assignment has been applied */ + else { + prQM->u4TimeToAdjustTcResource = + QM_INIT_TIME_TO_ADJUST_TC_RSC; + qmReassignTcResource(prAdapter); +#if QM_FAST_TC_RESOURCE_CTRL + if (prQM->fgTcResourceFastReaction) { + prQM->fgTcResourceFastReaction = false; + nicTxAdjustTcq(prAdapter); + } +#endif + } + } + + /* Debug */ +#if QM_PRINT_TC_RESOURCE_CTRL + do { + u32 u4Tc; + + for (u4Tc = 0; u4Tc < QM_ACTIVE_TC_NUM; u4Tc++) { + if (QM_GET_TX_QUEUE_LEN(prAdapter, + u4Tc) >= 100) { + DBGLOG(QM, + LOUD, + "QM: QueLen [%ld %ld %ld %ld %ld %ld]\n", + QM_GET_TX_QUEUE_LEN(prAdapter, + 0), + QM_GET_TX_QUEUE_LEN(prAdapter, + 1), + QM_GET_TX_QUEUE_LEN(prAdapter, + 2), + QM_GET_TX_QUEUE_LEN(prAdapter, + 3), + QM_GET_TX_QUEUE_LEN(prAdapter, + 4), + QM_GET_TX_QUEUE_LEN(prAdapter, + 5)); + break; + } + } + } while (false); +#endif + } + +#if QM_FAST_TC_RESOURCE_CTRL + void qmCheckForFastTcResourceCtrl(IN P_ADAPTER_T prAdapter, IN u8 ucTc) + { + P_QUE_MGT_T prQM = &prAdapter->rQM; + u8 fgTrigger = false; + + /* Trigger TC resource adjustment if there is a requirement coming for a + * empty TC */ + if (!prAdapter->rTxCtrl.rTc.au4FreeBufferCount[ucTc]) { + if (!prQM->au4CurrentTcResource[ucTc] || + nicTxGetAdjustableResourceCnt(prAdapter)) { + fgTrigger = true; + } + } + + if (fgTrigger) { + prQM->u4TimeToUpdateQueLen = 1; + prQM->u4TimeToAdjustTcResource = 1; + prQM->fgTcResourceFastReaction = true; + + DBGLOG(QM, + LOUD, + "Trigger TC Resource adjustment for TC[%u]\n", + ucTc); + } + } +#endif + +#endif + +u32 gmGetDequeueQuota(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, + IN P_BSS_INFO_T prBssInfo, IN u32 u4TotalQuota) +{ + u32 u4Weight = 100; + u32 u4Quota; + + P_QUE_MGT_T prQM = &prAdapter->rQM; + + if ((prAdapter->rWifiVar.uDeQuePercentEnable == false) || + (prQM->fgIsTxResrouceControlEn == false)) { + return u4TotalQuota; + } + + if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_BIT_VHT) { + if (prBssInfo->ucVhtChannelWidth > VHT_OP_CHANNEL_WIDTH_20_40) { + /* BW80 NSS1 rate: MCS9 433 Mbps */ + u4Weight = prAdapter->rWifiVar.u4DeQuePercentVHT80Nss1; + } else if (prBssInfo->eBssSCO != CHNL_EXT_SCN) { + /* BW40 NSS1 Max rate: 200 Mbps */ + u4Weight = prAdapter->rWifiVar.u4DeQuePercentVHT40Nss1; + } else { + /* BW20 NSS1 Max rate: 72.2Mbps (MCS8 86.7Mbps) */ + u4Weight = prAdapter->rWifiVar.u4DeQuePercentVHT20Nss1; + } + } else if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_BIT_HT) { + if (prBssInfo->ucHtOpInfo1 & HT_OP_INFO1_STA_CHNL_WIDTH) { + /* BW40 NSS1 Max rate: 150 Mbps (MCS9 200Mbps)*/ + u4Weight = prAdapter->rWifiVar.u4DeQuePercentHT40Nss1; + } else { + /* BW20 NSS1 Max rate: 72.2Mbps (MCS8 86.7Mbps)*/ + u4Weight = prAdapter->rWifiVar.u4DeQuePercentHT20Nss1; + } + } + + u4Quota = u4TotalQuota * u4Weight / 100; + + if (u4Quota > u4TotalQuota || u4Quota <= 0) { + return u4TotalQuota; + } + + return u4Quota; +} + +/*----------------------------------------------------------------------------*/ +/* RX-Related Queue Management */ +/*----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------------*/ +/*! + * \brief Init Queue Management for RX + * + * \param[in] (none) + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmInitRxQueues(IN P_ADAPTER_T prAdapter) +{ + /* DbgPrint("QM: Enter qmInitRxQueues()\n"); */ + /* TODO */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Handle RX packets (buffer reordering) + * + * \param[in] prSwRfbListHead The list of RX packets + * + * \return The list of packets which are not buffered for reordering + */ +/*----------------------------------------------------------------------------*/ +P_SW_RFB_T qmHandleRxPackets(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfbListHead) +{ +#if CFG_RX_REORDERING_ENABLED + /* u32 i; */ + P_SW_RFB_T prCurrSwRfb; + P_SW_RFB_T prNextSwRfb; + P_HW_MAC_RX_DESC_T prRxStatus; + QUE_T rReturnedQue; + P_QUE_T prReturnedQue; + u8 *pucEthDestAddr; + u8 fgIsBMC, fgIsHTran; + u8 fgMicErr; +#if CFG_SUPPORT_REPLAY_DETECTION + u8 ucBssIndexRly = 0; + P_BSS_INFO_T prBssInfoRly = NULL; +#endif + + /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */ + + DEBUGFUNC("qmHandleRxPackets"); + + ASSERT(prSwRfbListHead); + + prReturnedQue = &rReturnedQue; + + QUEUE_INITIALIZE(prReturnedQue); + prNextSwRfb = prSwRfbListHead; + + do { + prCurrSwRfb = prNextSwRfb; + prNextSwRfb = QM_RX_GET_NEXT_SW_RFB(prCurrSwRfb); + + /* prHifRxHdr = prCurrSwRfb->prHifRxHdr; // TODO: (Tehuang) Use + * macro to obtain the pointer */ + prRxStatus = prCurrSwRfb->prRxStatus; + + /* TODO: (Tehuang) Check if relaying */ + prCurrSwRfb->eDst = RX_PKT_DESTINATION_HOST; + + /* Decide the Destination */ +#if CFG_RX_PKTS_DUMP + if (prAdapter->rRxCtrl.u4RxPktsDumpTypeMask & + BIT(HIF_RX_PKT_TYPE_DATA)) { + DBGLOG(SW4, INFO, + "QM RX DATA: sta idx %u wlan idx %u ssn:%u\n", + prCurrSwRfb->ucStaRecIdx, prRxStatus->ucWlanIdx, + prCurrSwRfb->u2SSN); + DBGLOG(SW4, INFO, + "QM RX DATA: tid %u ptype %u reorder %u\n", + HAL_RX_STATUS_GET_TID(prRxStatus), + prCurrSwRfb->ucPacketType, + prCurrSwRfb->fgReorderBuffer); + + DBGLOG_MEM8(SW4, TRACE, (u8 *)prCurrSwRfb->pvHeader, + prCurrSwRfb->u2PacketLen); + } +#endif + + fgIsBMC = HAL_RX_STATUS_IS_BC(prRxStatus) | + HAL_RX_STATUS_IS_MC(prRxStatus); + fgIsHTran = false; + if (HAL_RX_STATUS_GET_HEADER_TRAN(prRxStatus) == true) { + u8 ucBssIndex; + P_BSS_INFO_T prBssInfo; + u8 aucTaAddr[MAC_ADDR_LEN]; + + fgIsHTran = true; + pucEthDestAddr = prCurrSwRfb->pvHeader; + + if (prCurrSwRfb->prStaRec == NULL) { + /* Workaround WTBL Issue */ + if (prCurrSwRfb->prRxStatusGroup4 == NULL) { + DBGLOG_MEM8( + SW4, TRACE, + (u8 *)prCurrSwRfb->prRxStatus, + prCurrSwRfb->prRxStatus + ->u2RxByteCount); + ASSERT(0); + } + HAL_RX_STATUS_GET_TA( + prCurrSwRfb->prRxStatusGroup4, + aucTaAddr); + prCurrSwRfb->ucStaRecIdx = + secLookupStaRecIndexFromTA(prAdapter, + aucTaAddr); + if (prCurrSwRfb->ucStaRecIdx < + CFG_STA_REC_NUM) { + prCurrSwRfb->prStaRec = + cnmGetStaRecByIndex( + prAdapter, + prCurrSwRfb + ->ucStaRecIdx); + DBGLOG(QM, + TRACE, + "Re-search the staRec = %d, mac = " + MACSTR + ", byteCnt= %d\n", + prCurrSwRfb->ucStaRecIdx, + MAC2STR(aucTaAddr), + prRxStatus->u2RxByteCount); + } + + if (prCurrSwRfb->prStaRec == NULL) { + DBGLOG(QM, + TRACE, + "Mark NULL Packet,StaRec=NULL,wlanIdx:%d,but via Header Translation\n", + prRxStatus->ucWlanIdx); + /* DBGLOG_MEM8(SW4, TRACE, (u8 + **)prRxStatus, + * prRxStatus->u2RxByteCount); */ + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_NO_STA_DROP_COUNT); + prCurrSwRfb->eDst = + RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL( + prReturnedQue, + (P_QUE_ENTRY_T)prCurrSwRfb); + continue; + } + + prCurrSwRfb->ucWlanIdx = + prCurrSwRfb->prStaRec->ucWlanIndex; + GLUE_SET_PKT_BSS_IDX( + prCurrSwRfb->pvPacket, + secGetBssIdxByWlanIdx( + prAdapter, + prCurrSwRfb->ucWlanIdx)); + } + /* ASSERT(prAdapter->rWifiVar.arWtbl[prCurrSwRfb->ucWlanIdx].ucUsed); + */ + if (prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem > + (CFG_RX_MAX_PKT_NUM - + CFG_NUM_OF_QM_RX_PKT_NUM) || + true) { + ucBssIndex = prCurrSwRfb->prStaRec->ucBssIndex; + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, + ucBssIndex); + /* DBGLOG_MEM8(QM, TRACE,prCurrSwRfb->pvHeader, + * 16); */ + /* */ + + /* if ((OP_MODE_ACCESS_POINT != + * prBssInfo->eCurrentOPMode)) { */ + /* fgIsBMC = HAL_RX_STATUS_IS_BC(prRxStatus) | + * HAL_RX_STATUS_IS_MC(prRxStatus); */ + /* } */ + + if (!IS_BSS_ACTIVE(prBssInfo)) { + DBGLOG(QM, + TRACE, + "Mark NULL the Packet for inactive Bss %u\n", + ucBssIndex); + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_INACTIVE_BSS_DROP_COUNT); + prCurrSwRfb->eDst = + RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL( + prReturnedQue, + (P_QUE_ENTRY_T)prCurrSwRfb); + continue; + } + + if (prBssInfo->eCurrentOPMode == + OP_MODE_ACCESS_POINT) { + if (IS_BMCAST_MAC_ADDR( + pucEthDestAddr)) { + prCurrSwRfb->eDst = + RX_PKT_DESTINATION_HOST_WITH_FORWARD; + } else if (secLookupStaRecIndexFromTA( + prAdapter, + pucEthDestAddr) != + STA_REC_INDEX_NOT_FOUND) { + prCurrSwRfb->eDst = + RX_PKT_DESTINATION_FORWARD; + /* TODO : need to check the dst + * mac is valid */ + /* If src mac is invalid, the + * packet will be freed in fw */ + } + } + } else { + /* Dont not occupy other SW RFB */ + DBGLOG(QM, + TRACE, + "Mark NULL the Packet for less Free Sw Rfb\n"); + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_LESS_SW_RFB_DROP_COUNT); + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, + (P_QUE_ENTRY_T)prCurrSwRfb); + continue; + } + } +#if CFG_KEY_ERROR_STATISTIC_RECOVERY + else { + u16 u2AisFrameCtrl = 0; + P_WLAN_MAC_HEADER_T prWlanHeader = NULL; + P_BSS_INFO_T prAisBssInfo = NULL; + u8 fgIsProtected = false; + + prAisBssInfo = prAdapter->prAisBssInfo; + + prWlanHeader = + (P_WLAN_MAC_HEADER_T)prCurrSwRfb->pvHeader; + u2AisFrameCtrl = prWlanHeader->u2FrameCtrl; + fgIsProtected = + (u2AisFrameCtrl & MASK_FC_PROTECTED_FRAME) ? + true : + false; + + if (prAisBssInfo) { + if ((prAisBssInfo->prStaRecOfAP) && + (prAisBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) && + EQUAL_MAC_ADDR(prWlanHeader->aucAddr2, + prAisBssInfo->aucBSSID) && + fgIsBMC && fgIsProtected && + (prCurrSwRfb->ucWlanIdx == + WTBL_RESERVED_ENTRY)) { + DBGLOG_RATELIMIT( + QM, + EVENT, + "RXD Trans: FrameCtrl=0x%02x GVLD=0x%x, StaRecIdx=%d, WlanIdx=%d PktLen=%d, Protected=%s\n", + u2AisFrameCtrl, + prCurrSwRfb->ucGroupVLD, + prCurrSwRfb->ucStaRecIdx, + prCurrSwRfb->ucWlanIdx, + prCurrSwRfb->u2PacketLen, + fgIsProtected ? "true" : + "false"); + + DBGLOG_MEM8( + QM, WARN, + (u8 *)prCurrSwRfb->pvHeader, + (prCurrSwRfb->u2PacketLen > + 64) ? + 64 : + prCurrSwRfb + ->u2PacketLen); + + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_BMC_NO_KEY_COUNT); + + if (RX_GET_CNT(&prAdapter->rRxCtrl, + RX_BMC_NO_KEY_COUNT) == + prAdapter->rWifiVar.u4BmcKeyErrorTh) { + DBGLOG(QM, + EVENT, + "Trigger BCN timeout due to RX more than" + " %llu encrypted BMC packets\n", + RX_GET_CNT( + &prAdapter-> + rRxCtrl, + RX_BMC_NO_KEY_COUNT)); + + prAisBssInfo->u2DeauthReason = + BEACON_TIMEOUT_REASON_DUE_2_BMC_ERR; + + kalIndicateStatusAndComplete( + prAdapter->prGlueInfo, + WLAN_STATUS_BEACON_TIMEOUT, + NULL, + 0); + } + } + } + } +#endif + + /* Todo:: Move the data class error check here */ + +#if CFG_SUPPORT_REPLAY_DETECTION + if (prCurrSwRfb->prStaRec) { + ucBssIndexRly = prCurrSwRfb->prStaRec->ucBssIndex; + prBssInfoRly = + GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndexRly); + if (!IS_BSS_ACTIVE(prBssInfoRly)) { + DBGLOG(QM, + INFO, + "Mark NULL the Packet for inactive Bss %u\n", + ucBssIndexRly); + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, + (P_QUE_ENTRY_T)prCurrSwRfb); + continue; + } + if (fgIsBMC && prBssInfoRly && + (IS_BSS_AIS(prBssInfoRly) || + IS_BSS_P2P(prBssInfoRly)) && + qmHandleRxReplay(prAdapter, prCurrSwRfb)) { + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, + (P_QUE_ENTRY_T)prCurrSwRfb); + continue; + } + } +#endif + +#if CFG_SUPPORT_AMSDU_ATTACK_DETECTION + if (prCurrSwRfb->fgDataFrame && prCurrSwRfb->prStaRec && + qmAmsduAttackDetection(prAdapter, prCurrSwRfb)) { + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + DBGLOG(QM, INFO, "drop AMSDU attack packet SN:%d\n", + prCurrSwRfb->u2SSN); + } +#endif + +#if CFG_SUPPORT_FAKE_EAPOL_DETECTION + if (prCurrSwRfb->fgDataFrame && prCurrSwRfb->prStaRec && + qmDetectRxInvalidEAPOL(prAdapter, prCurrSwRfb)) { + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, + (P_QUE_ENTRY_T)prCurrSwRfb); + DBGLOG(QM, INFO, "Drop by EAPOL filter\n"); + continue; + } +#endif + + if (prCurrSwRfb->fgReorderBuffer && !fgIsBMC && fgIsHTran) { + /* If this packet should dropped or indicated to the + * host immediately, it should be enqueued into the + * rReturnedQue with specific flags. If this packet + * should be buffered for reordering, it should be + * enqueued into the reordering queue in the STA_REC + * rather than into the rReturnedQue. + */ + qmProcessPktWithReordering(prAdapter, prCurrSwRfb, + prReturnedQue); + } else if (prCurrSwRfb->fgDataFrame) { + /* Check Class Error */ + if (secCheckClassError(prAdapter, prCurrSwRfb, + prCurrSwRfb->prStaRec) == true) { + P_RX_BA_ENTRY_T prReorderQueParm = NULL; + + /* Invalid BA aggrement */ + if (fgIsHTran) { + u16 u2FrameCtrl = 0; + + u2FrameCtrl = + HAL_RX_STATUS_GET_FRAME_CTL_FIELD + ( + prCurrSwRfb + ->prRxStatusGroup4); + /* Check FC type, if DATA, then + * no-reordering */ + if ((u2FrameCtrl & MASK_FRAME_TYPE) == + MAC_FRAME_DATA || + (prCurrSwRfb->ucTid >= + CFG_RX_MAX_BA_TID_NUM)) { + DBGLOG(QM, + TRACE, + "FC [0x%04X], no-reordering...\n", + u2FrameCtrl); + } else { + if (prCurrSwRfb->ucTid >= + CFG_RX_MAX_BA_TID_NUM) { + DBGLOG(QM, + WARN, + "Invalid prCurrSwRfb->ucTid [%u] > %d\n", + prCurrSwRfb + ->ucTid, + CFG_RX_MAX_BA_TID_NUM); + RX_INC_CNT( + &prAdapter-> + rRxCtrl, + RX_SIZE_ERR_DROP_COUNT); + prCurrSwRfb->eDst = + RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL( + prReturnedQue, + (P_QUE_ENTRY_T) + prCurrSwRfb); + continue; + } + prReorderQueParm = + ((prCurrSwRfb->prStaRec + -> + aprRxReorderParamRefTbl) + [prCurrSwRfb + ->ucTid]); + } + } + + if (prReorderQueParm && + prReorderQueParm->fgIsValid && !fgIsBMC) { + qmProcessPktWithReordering( + prAdapter, prCurrSwRfb, + prReturnedQue); + } else { + qmHandleRxPackets_AOSP_1; + } + } else { + DBGLOG(QM, TRACE, + "Mark NULL the Packet for class error\n"); + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_CLASS_ERR_DROP_COUNT); + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, + (P_QUE_ENTRY_T)prCurrSwRfb); + } + } else { + P_WLAN_MAC_HEADER_T prWlanMacHeader; + + ASSERT(prCurrSwRfb->pvHeader); + + prWlanMacHeader = + (P_WLAN_MAC_HEADER_T)prCurrSwRfb->pvHeader; + prCurrSwRfb->eDst = RX_PKT_DESTINATION_NULL; + + switch (prWlanMacHeader->u2FrameCtrl & + MASK_FRAME_TYPE) { + /* BAR frame */ + case MAC_FRAME_BLOCK_ACK_REQ: + qmProcessBarFrame(prAdapter, prCurrSwRfb, + prReturnedQue); + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_BAR_DROP_COUNT); + break; + + default: + DBGLOG(QM, + TRACE, + "Mark NULL the Packet for non-interesting type\n"); + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_NO_INTEREST_DROP_COUNT); + QUEUE_INSERT_TAIL(prReturnedQue, + (P_QUE_ENTRY_T)prCurrSwRfb); + break; + } + } + } while (prNextSwRfb); + + /* The returned list of SW_RFBs must end with a NULL pointer */ + if (QUEUE_IS_NOT_EMPTY(prReturnedQue)) { + QM_TX_SET_NEXT_MSDU_INFO( + (P_SW_RFB_T)QUEUE_GET_TAIL(prReturnedQue), NULL); + } + + return (P_SW_RFB_T)QUEUE_GET_HEAD(prReturnedQue); + +#else + /* DbgPrint("QM: Enter qmHandleRxPackets()\n"); */ + return prSwRfbListHead; + +#endif +} + +#if CFG_SUPPORT_FAKE_EAPOL_DETECTION +/*----------------------------------------------------------------------------*/ +/*! + * \brief qmDetectRxInvalidEAPOL() is used for fake EAPOL checking. + * + * \param[in] prSwRfb The RFB which is being processed. + * + * \return true when we need to drop it + */ +/*----------------------------------------------------------------------------*/ +u8 qmDetectRxInvalidEAPOL(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + u8 *pucPkt = NULL; + u8 ucBssIndex; + BSS_INFO_T *prBssInfo; + u16 u2EtherType = 0; + u8 fgDrop = false; + P_STA_RECORD_T prStaRec; + u8 *pucPaylod = NULL; + u16 u2FrameCtrl; + WLAN_MAC_HEADER_T *prWlanHeader = NULL; + u8 *pucDaAddr = NULL; + u8 jj, fgFound = false; + P_STA_RECORD_T prTmpStaRec; + + if (!prSwRfb) { + DBGLOG(QM, WARN, "qmDetectRxInvalidEAPOL NULL\n"); + return false; + } + + if (prSwRfb->u2PacketLen <= ETHER_HEADER_LEN) { + return false; + } + + /* check if sta rec exist*/ + if (!prSwRfb->prStaRec) { + DBGLOG(QM, WARN, "Drop: sta rec not found\n"); + return true; + } + + pucPkt = prSwRfb->pvHeader; + if (!pucPkt) { + return false; + } + + prStaRec = prSwRfb->prStaRec; + + ucBssIndex = prSwRfb->prStaRec->ucBssIndex; + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + if (!prBssInfo) { + DBGLOG(QM, WARN, "prBssInfo NULL\n"); + return false; + } + + if (prSwRfb->fgHdrTran) { + u2FrameCtrl = HAL_RX_STATUS_GET_FRAME_CTL_FIELD( + prSwRfb->prRxStatusGroup4); + + u2EtherType = (pucPkt[ETH_TYPE_LEN_OFFSET] << 8) | + (pucPkt[ETH_TYPE_LEN_OFFSET + 1]); + } else { + prWlanHeader = (WLAN_MAC_HEADER_T *)prSwRfb->pvHeader; + u2FrameCtrl = prWlanHeader->u2FrameCtrl; + pucPaylod = prSwRfb->pvHeader + prSwRfb->u2HeaderLen; + + if (prSwRfb->ucHeaderOffset) { + /* HW 4-byte align */ + pucPaylod += 2; + } + + pucPaylod += LLC_LEN; + u2EtherType = (pucPaylod[ETH_TYPE_LEN_OFFSET] << 8) | + (pucPaylod[ETH_TYPE_LEN_OFFSET + 1]); + + /* if fragment middle/end, NO eth type so set 0 */ + if (prSwRfb->fgFragFrame) { + if (!RXM_IS_MORE_DATA(u2FrameCtrl)) { + u2EtherType = 0x0; + } + } + } + + DBGLOG(RX, INFO, "EtherType:0x%x\n", u2EtherType); + + /* if it's already drop by other feature, ignore here */ + if (prSwRfb->eDst == RX_PKT_DESTINATION_NULL) { + return false; + } + + if (prBssInfo->eCurrentOPMode == OP_MODE_ACCESS_POINT) { + if (u2EtherType != ETH_P_1X) { + return false; + } + + /* AP: check if EAPOL DA match any case */ + if (prSwRfb->fgHdrTran) { + pucDaAddr = prSwRfb->pvHeader; + + DBGLOG(RSN, INFO, " DA:" MACSTR " BSSID:" MACSTR "\n", + MAC2STR(pucDaAddr), + MAC2STR(prBssInfo->aucBSSID)); + } else { + /* check A3 as DA*/ + pucDaAddr = prWlanHeader->aucAddr3; + DBGLOG(RSN, INFO, " A3:" MACSTR "\n", + MAC2STR(pucDaAddr)); + } + + if (EQUAL_MAC_ADDR(pucDaAddr, prBssInfo->aucBSSID)) { + /* DA is me */ + return false; + } + + /* check if DA match any starec */ + for (jj = 0; jj < CFG_STA_REC_NUM; jj++) { + prTmpStaRec = cnmGetStaRecByIndex(prAdapter, jj); + if (prTmpStaRec) { + if (EQUAL_MAC_ADDR(pucDaAddr, + prTmpStaRec->aucMacAddr)) { + fgFound = true; + break; + } + } + } + + if (fgFound) { + /* DA in sta rec */ + fgDrop = false; + } else { + DBGLOG(QM, INFO, "DA sta rec not found\n"); + fgDrop = true; + } + + /* if eapol-forward, check if add key */ + if ((prSwRfb->eDst == RX_PKT_DESTINATION_HOST_WITH_FORWARD || + prSwRfb->eDst == RX_PKT_DESTINATION_FORWARD)) { + /* fgIsTxKeyReady is set by nicEventAddPkeyDone */ + if (prStaRec->fgIsTxKeyReady != true) { + DBGLOG(QM, INFO, "Drop AP:TxKeyReady false\n"); + fgDrop = true; + } + } + } else if (prBssInfo->eCurrentOPMode == OP_MODE_INFRASTRUCTURE) { + /* Do not drop EAPOL */ + if (u2EtherType == ETH_P_1X) { + return false; + } + + /* 1. Drop packet if sta rec not found. + * This might be cause by wtbl index mismatch + * 2. Drop packet if not finish add key + * fgIsTxKeyReady is set by nicEventAddPkeyDone + */ + if (secIsProtectedBss(prAdapter, prBssInfo)) { + if (prStaRec->fgIsTxKeyReady != true) { + DBGLOG(QM, + INFO, + "fgIsTxKeyReady false for non-open connection\n"); + fgDrop = true; + } + } else { + if (prStaRec->fgIsTxAllowed != true) { + DBGLOG(QM, + INFO, + "fgIsTxAllowed false for open connection\n"); + fgDrop = true; + } + } + } + + + return fgDrop; +} +#endif + +#if CFG_SUPPORT_AMSDU_ATTACK_DETECTION +/*----------------------------------------------------------------------------*/ +/*! + * \brief AMSDU Attack Detection + * + * \param[in] prSwRfb The RX packet to process + * + * \return true when we find an amsdu attack + */ +/*----------------------------------------------------------------------------*/ +u8 qmAmsduAttackDetection(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb) +{ + u8 fgDrop = false; + u8 aucTaAddr[MAC_ADDR_LEN]; + u8 *pucTaAddr = NULL, *pucRaAddr = NULL; + u8 *pucSaAddr = NULL, *pucDaAddr = NULL; + u8 *pucAmsduAddr = NULL, *pucCmpAddr = NULL; + u8 ucBssIndex = 0; + BSS_INFO_T *prBssInfo = NULL; + STA_RECORD_T *prStaRec = NULL; + u16 u2FrameCtrl, u2SSN; + WLAN_MAC_HEADER_T *prWlanHeader = NULL; + u8 ucTid; + u8 *pucPaylod = NULL; + + DEBUGFUNC("qmAmsduAttackDetection"); + + /* error handle: drop this packet */ + if (!prSwRfb) { + return true; + } + + prStaRec = prSwRfb->prStaRec; + /* error handle: drop this packet */ + if (!prStaRec) { + return true; + } + + /* Discard the A-MSDU subframe that is too short */ + if (prSwRfb->u2PacketLen < ETH_HLEN) { + return false; + } + + /* 802.11 header TA */ + if (prSwRfb->fgHdrTran) { + u2SSN = HAL_RX_STATUS_GET_SEQFrag_NUM( + prSwRfb->prRxStatusGroup4) >> + RX_STATUS_SEQ_NUM_OFFSET; + u2FrameCtrl = HAL_RX_STATUS_GET_FRAME_CTL_FIELD( + prSwRfb->prRxStatusGroup4); + HAL_RX_STATUS_GET_TA(prSwRfb->prRxStatusGroup4, aucTaAddr); + pucTaAddr = &aucTaAddr[0]; + pucDaAddr = prSwRfb->pvHeader; + pucSaAddr = prSwRfb->pvHeader + MAC_ADDR_LEN; + } else { + prWlanHeader = (WLAN_MAC_HEADER_T *)prSwRfb->pvHeader; + u2SSN = prWlanHeader->u2SeqCtrl >> MASK_SC_SEQ_NUM_OFFSET; + u2FrameCtrl = prWlanHeader->u2FrameCtrl; + pucTaAddr = prWlanHeader->aucAddr2; + + pucPaylod = prSwRfb->pvHeader + prSwRfb->u2HeaderLen; + if (prSwRfb->ucHeaderOffset) { + /* HW 4-byte align */ + pucPaylod += 2; + } + pucDaAddr = pucPaylod; + pucSaAddr = pucPaylod + MAC_ADDR_LEN; + } + + /* record SSN */ + prSwRfb->u2SSN = u2SSN; + + /* 802.11 header RA */ + ucBssIndex = prSwRfb->prStaRec->ucBssIndex; + if (!IS_BSS_INDEX_VALID(ucBssIndex)) { + DBGLOG(QM, ERROR, "%s:%d invalid ucBssIndex\n", __func__, + __LINE__); + return true; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + pucRaAddr = &prBssInfo->aucOwnMacAddr[0]; + + if (RXM_IS_QOS_DATA_FRAME(u2FrameCtrl)) { + ucTid = prSwRfb->ucTid; + } else { + /* for non-qos data, use TID_NUM as tid */ + ucTid = TID_NUM; + } + + if (prSwRfb->ucPayloadFormat == RX_PAYLOAD_FORMAT_MSDU) { + return false; + } else if (prSwRfb->ucPayloadFormat == + RX_PAYLOAD_FORMAT_FIRST_SUB_AMSDU) { + if (RXM_IS_FROM_DS(u2FrameCtrl)) { + /* FromDS: A-MSDU DA must match 802.11 header RA */ + pucCmpAddr = pucDaAddr; + pucAmsduAddr = pucRaAddr; + } else if (RXM_IS_TO_DS(u2FrameCtrl)) { + /* ToDS: A-MSDU SA must match 802.11 header TA */ + pucCmpAddr = pucSaAddr; + pucAmsduAddr = pucTaAddr; + } + + if (UNEQUAL_MAC_ADDR(pucCmpAddr, pucAmsduAddr)) { + /* mark to drop amsdu with same SeqNo */ + fgDrop = true; + } + + DBGLOG(QM, INFO, "QM: FromDS:%d ToDS:%d TID:%u SN:%u PF:%u\n", + RXM_IS_FROM_DS(u2FrameCtrl), RXM_IS_TO_DS(u2FrameCtrl), + ucTid, u2SSN, prSwRfb->ucPayloadFormat); + + DBGLOG(QM, INFO, + " TA:" MACSTR " RA:" MACSTR " DA:" MACSTR " SA:" MACSTR + " Drop:%d\n", + MAC2STR(pucTaAddr), MAC2STR(pucRaAddr), + MAC2STR(pucDaAddr), MAC2STR(pucSaAddr), fgDrop); + + prStaRec->afgIsAmsduInvalid[ucTid] = fgDrop; + prStaRec->au2AmsduInvalidSN[ucTid] = u2SSN; + } else { + /* drop it if find an asmdu attack in station record */ + if (prStaRec->afgIsAmsduInvalid[ucTid] == true && + prStaRec->au2AmsduInvalidSN[ucTid] == u2SSN) { + fgDrop = true; + DBGLOG(QM, INFO, + "QM: AMSDU Attack TID:%u SN:%u PF:%u\n", ucTid, + u2SSN, prSwRfb->ucPayloadFormat); + } + + /* reset flag when find last subframe */ + if (prSwRfb->ucPayloadFormat == + RX_PAYLOAD_FORMAT_LAST_SUB_AMSDU) { + prStaRec->afgIsAmsduInvalid[ucTid] = false; + prStaRec->au2AmsduInvalidSN[ucTid] = 0XFFFF; + } + } + + return fgDrop; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Reorder the received packet + * + * \param[in] prSwRfb The RX packet to process + * \param[out] prReturnedQue The queue for indicating packets + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmProcessPktWithReordering(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + OUT P_QUE_T prReturnedQue) +{ + P_STA_RECORD_T prStaRec; + P_HW_MAC_RX_DESC_T prRxStatus; + P_HW_MAC_RX_STS_GROUP_4_T prRxStatusGroup4 = NULL; + P_RX_BA_ENTRY_T prReorderQueParm = NULL; + + /* P_SW_RFB_T prReorderedSwRfb; */ +#if CFG_SUPPORT_RX_AMSDU + u8 u8AmsduSubframeIdx; + u32 u4SeqNo; +#endif + DEBUGFUNC("qmProcessPktWithReordering"); + + ASSERT(prSwRfb); + ASSERT(prReturnedQue); + ASSERT(prSwRfb->prRxStatus); + + /* Incorrect STA_REC index */ + if (prSwRfb->ucStaRecIdx >= CFG_STA_REC_NUM) { + RX_INC_CNT(&prAdapter->rRxCtrl, RX_NO_STA_DROP_COUNT); + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T)prSwRfb); + DBGLOG(QM, WARN, + "Reordering for a NULL STA_REC, ucStaRecIdx = %d\n", + prSwRfb->ucStaRecIdx); + authSendDeauthFrame(prAdapter, NULL, NULL, prSwRfb, + REASON_CODE_CLASS_3_ERR, + (PFN_TX_DONE_HANDLER)NULL); + /* ASSERT(0); */ + return; + } + + /* Check whether the STA_REC is activated */ + prStaRec = prSwRfb->prStaRec; + ASSERT(prStaRec); + + prRxStatus = prSwRfb->prRxStatus; + /* prSwRfb->eDst = RX_PKT_DESTINATION_HOST; */ + + RX_INC_CNT(&prAdapter->rRxCtrl, RX_DATA_REORDER_TOTAL_COUINT); + + /* Check whether the BA agreement exists */ + if (prSwRfb->ucTid < CFG_RX_MAX_BA_TID_NUM) { + prReorderQueParm = + ((prStaRec->aprRxReorderParamRefTbl)[prSwRfb->ucTid]); + } + if (!prReorderQueParm || !(prReorderQueParm->fgIsValid)) { + /* TODO: (Tehuang) Handle the Host-FW sync issue. */ + // prSwRfb->eDst = RX_PKT_DESTINATION_HOST; + QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T)prSwRfb); + DBGLOG(QM, TRACE, "Reordering for a NULL ReorderQueParm\n"); + return; + } + + prRxStatusGroup4 = prSwRfb->prRxStatusGroup4; + if (prRxStatusGroup4 == NULL) { + DBGLOG(QM, ERROR, "prRxStatusGroup4 is NULL !!!\n"); + DBGLOG(QM, ERROR, "prSwRfb->pvHeader is 0x%p !!!\n", + (u32 *)prSwRfb->pvHeader); + DBGLOG(QM, ERROR, "prSwRfb->u2PacketLen is %d !!!\n", + prSwRfb->u2PacketLen); + DBGLOG(QM, ERROR, + "========= START TO DUMP prSwRfb =========\n"); + DBGLOG_MEM8(QM, ERROR, prSwRfb->pvHeader, prSwRfb->u2PacketLen); + DBGLOG(QM, ERROR, "========= END OF DUMP prSwRfb =========\n"); + ASSERT(prRxStatusGroup4); + } + +#if CFG_SUPPORT_RX_AMSDU + /* RX reorder for one MSDU in AMSDU issue */ + /* QUEUE_INITIALIZE(&prSwRfb->rAmsduQue); */ + + u8AmsduSubframeIdx = HAL_RX_STATUS_GET_PAYLOAD_FORMAT(prRxStatus); + + /* prMpduSwRfb = prReorderQueParm->prMpduSwRfb; */ + u4SeqNo = (u32)prSwRfb->u2SSN; + + switch (u8AmsduSubframeIdx) { + case RX_PAYLOAD_FORMAT_FIRST_SUB_AMSDU: + if (prReorderQueParm->fgAmsduNeedLastFrame) { + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_DATA_AMSDU_MISS_COUNT); + prReorderQueParm->fgAmsduNeedLastFrame = false; + } + RX_INC_CNT(&prAdapter->rRxCtrl, RX_DATA_MSDU_IN_AMSDU_COUNT); + RX_INC_CNT(&prAdapter->rRxCtrl, RX_DATA_AMSDU_COUNT); + break; + + case RX_PAYLOAD_FORMAT_MIDDLE_SUB_AMSDU: + prReorderQueParm->fgAmsduNeedLastFrame = true; + RX_INC_CNT(&prAdapter->rRxCtrl, RX_DATA_MSDU_IN_AMSDU_COUNT); + if (prReorderQueParm->u4SeqNo != u4SeqNo) { + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_DATA_AMSDU_MISS_COUNT); + RX_INC_CNT(&prAdapter->rRxCtrl, RX_DATA_AMSDU_COUNT); + } + break; + + case RX_PAYLOAD_FORMAT_LAST_SUB_AMSDU: + prReorderQueParm->fgAmsduNeedLastFrame = false; + RX_INC_CNT(&prAdapter->rRxCtrl, RX_DATA_MSDU_IN_AMSDU_COUNT); + if (prReorderQueParm->u4SeqNo != u4SeqNo) { + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_DATA_AMSDU_MISS_COUNT); + RX_INC_CNT(&prAdapter->rRxCtrl, RX_DATA_AMSDU_COUNT); + } + break; + + case RX_PAYLOAD_FORMAT_MSDU: + if (prReorderQueParm->fgAmsduNeedLastFrame) { + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_DATA_AMSDU_MISS_COUNT); + prReorderQueParm->fgAmsduNeedLastFrame = false; + } + break; + + default: + break; + } + + prReorderQueParm->u4SeqNo = u4SeqNo; +#endif + + RX_DIRECT_REORDER_LOCK(prAdapter, 0); + /* After resuming, WinStart and WinEnd are obsolete and unsync + * with AP's SN. So assign the SN of first packet to WinStart + * as "Fall Within" case. + */ + if (prReorderQueParm->fgFirstSnToWinStart) { + DBGLOG(QM, INFO, + "[%u] First resumed SN(%u) reset Window{%u,%u}\n", + prSwRfb->ucTid, prSwRfb->u2SSN, + prReorderQueParm->u2WinStart, + prReorderQueParm->u2WinEnd); + + prReorderQueParm->u2WinStart = prSwRfb->u2SSN; + prReorderQueParm->u2WinEnd = + ((prReorderQueParm->u2WinStart) + + (prReorderQueParm->u2WinSize) - 1) % + MAX_SEQ_NO_COUNT; + prReorderQueParm->fgFirstSnToWinStart = false; + } + + /* Insert reorder packet */ + qmInsertReorderPkt(prAdapter, prSwRfb, prReorderQueParm, prReturnedQue); + RX_DIRECT_REORDER_UNLOCK(prAdapter, 0); +} + +void qmProcessBarFrame(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + OUT P_QUE_T prReturnedQue) +{ + P_STA_RECORD_T prStaRec; + P_HW_MAC_RX_DESC_T prRxStatus; + P_RX_BA_ENTRY_T prReorderQueParm; + P_CTRL_BAR_FRAME_T prBarCtrlFrame; + + u32 u4SSN; + u32 u4WinStart; + u32 u4WinEnd; + + ASSERT(prSwRfb); + ASSERT(prReturnedQue); + ASSERT(prSwRfb->prRxStatus); + ASSERT(prSwRfb->pvHeader); + + prRxStatus = prSwRfb->prRxStatus; + + prBarCtrlFrame = (P_CTRL_BAR_FRAME_T)prSwRfb->pvHeader; + + prSwRfb->ucTid = (*((u16 *)((u8 *)prBarCtrlFrame + + CTRL_BAR_BAR_CONTROL_OFFSET))) >> + BAR_CONTROL_TID_INFO_OFFSET; + prSwRfb->u2SSN = (*((u16 *)((u8 *)prBarCtrlFrame + + CTRL_BAR_BAR_INFORMATION_OFFSET))) >> + OFFSET_BAR_SSC_SN; + + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T)prSwRfb); + + /* Incorrect STA_REC index */ + prSwRfb->ucStaRecIdx = secLookupStaRecIndexFromTA( + prAdapter, prBarCtrlFrame->aucSrcAddr); + if (prSwRfb->ucStaRecIdx >= CFG_STA_REC_NUM) { + DBGLOG(QM, + WARN, + "QM: (Warning) BAR for a NULL STA_REC, ucStaRecIdx = %d\n", + prSwRfb->ucStaRecIdx); + /* ASSERT(0); */ + return; + } + + /* Check whether the STA_REC is activated */ + prSwRfb->prStaRec = + cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + prStaRec = prSwRfb->prStaRec; + if (prStaRec == NULL) { + /* ASSERT(prStaRec); */ + return; + } + + /* Check index out of bound */ + if (prSwRfb->ucTid >= CFG_RX_MAX_BA_TID_NUM) { + DBGLOG(QM, WARN, + "QM: (Warning) index out of bound: ucTid = %d\n", + prSwRfb->ucTid); + /* ASSERT(0); */ + return; + } + + /* Check index out of bound */ + if (prSwRfb->ucTid >= CFG_RX_MAX_BA_TID_NUM) { + DBGLOG(QM, WARN, + "QM: (Warning) index out of bound: ucTid = %d\n", + prSwRfb->ucTid); + return; + } + + /* Check whether the BA agreement exists */ + prReorderQueParm = prStaRec->aprRxReorderParamRefTbl[prSwRfb->ucTid]; + if (!prReorderQueParm) { + /* TODO: (Tehuang) Handle the Host-FW sync issue. */ + DBGLOG(QM, WARN, + "QM: (Warning) BAR for a NULL ReorderQueParm\n"); + /* ASSERT(0); */ + return; + } + + RX_DIRECT_REORDER_LOCK(prAdapter, 0); + + u4SSN = (u32)(prSwRfb->u2SSN); + u4WinStart = (u32)(prReorderQueParm->u2WinStart); + u4WinEnd = (u32)(prReorderQueParm->u2WinEnd); + + if (qmCompareSnIsLessThan(u4WinStart, u4SSN)) { + prReorderQueParm->u2WinStart = (u16)u4SSN; + prReorderQueParm->u2WinEnd = + ((prReorderQueParm->u2WinStart) + + (prReorderQueParm->u2WinSize) - 1) % + MAX_SEQ_NO_COUNT; +#if CFG_SUPPORT_RX_AMSDU + /* RX reorder for one MSDU in AMSDU issue */ + prReorderQueParm->u8LastAmsduSubIdx = RX_PAYLOAD_FORMAT_MSDU; +#endif + DBGLOG(QM, TRACE, "QM:(BAR)[%d](%ld){%d,%d}\n", prSwRfb->ucTid, + u4SSN, prReorderQueParm->u2WinStart, + prReorderQueParm->u2WinEnd); + qmPopOutDueToFallAhead(prAdapter, prReorderQueParm, + prReturnedQue); + } else { + DBGLOG(QM, TRACE, "QM:(BAR)(%d)(%ld){%ld,%ld}\n", + prSwRfb->ucTid, u4SSN, u4WinStart, u4WinEnd); + } + RX_DIRECT_REORDER_UNLOCK(prAdapter, 0); +} + +void qmInsertReorderPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue) +{ + u32 u4SeqNo; + u32 u4WinStart; + u32 u4WinEnd; + + /* Start to reorder packets */ + u4SeqNo = (u32)(prSwRfb->u2SSN); + u4WinStart = (u32)(prReorderQueParm->u2WinStart); + u4WinEnd = (u32)(prReorderQueParm->u2WinEnd); + + /* Debug */ + DBGLOG(QM, LOUD, "QM:(R)[%d](%ld){%ld,%ld}\n", prSwRfb->ucTid, u4SeqNo, + u4WinStart, u4WinEnd); + + /* Case 1: Fall within */ + if /* 0 - start - sn - end - 4095 */ + (((u4WinStart <= u4SeqNo) && (u4SeqNo <= u4WinEnd)) + /* 0 - end - start - sn - 4095 */ + || ((u4WinEnd < u4WinStart) && (u4WinStart <= u4SeqNo)) + /* 0 - sn - end - start - 4095 */ + || ((u4SeqNo <= u4WinEnd) && (u4WinEnd < u4WinStart))) { + qmInsertFallWithinReorderPkt(prAdapter, prSwRfb, + prReorderQueParm, prReturnedQue); + +#if QM_RX_WIN_SSN_AUTO_ADVANCING + if (prReorderQueParm->fgIsWaitingForPktWithSsn) { + /* Let the first received packet pass the reorder check + */ + DBGLOG(QM, LOUD, "QM:(A)[%d](%ld){%ld,%ld}\n", + prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); + + prReorderQueParm->u2WinStart = (u16)u4SeqNo; + prReorderQueParm->u2WinEnd = + ((prReorderQueParm->u2WinStart) + + (prReorderQueParm->u2WinSize) - 1) % + MAX_SEQ_NO_COUNT; + prReorderQueParm->fgIsWaitingForPktWithSsn = false; +#if CFG_SUPPORT_RX_AMSDU + /* RX reorder for one MSDU in AMSDU issue */ + prReorderQueParm->u8LastAmsduSubIdx = + RX_PAYLOAD_FORMAT_MSDU; +#endif + } +#endif + + qmPopOutDueToFallWithin(prAdapter, prReorderQueParm, + prReturnedQue); + RX_RESET_CNT(&prAdapter->rRxCtrl, + RX_DATA_REORDER_BEHIND_CONTINUOUS_COUNT); + } + /* Case 2: Fall ahead */ + else if + /* 0 - start - end - sn - (start+2048) - 4095 */ + (((u4WinStart < u4WinEnd) && (u4WinEnd < u4SeqNo) && + (u4SeqNo < (u4WinStart + HALF_SEQ_NO_COUNT))) + /* 0 - sn - (start+2048) - start - end - 4095 */ + || ((u4SeqNo < u4WinStart) && (u4WinStart < u4WinEnd) && + ((u4SeqNo + MAX_SEQ_NO_COUNT) < + (u4WinStart + HALF_SEQ_NO_COUNT))) + /* 0 - end - sn - (start+2048) - start - 4095 */ + || ((u4WinEnd < u4SeqNo) && (u4SeqNo < u4WinStart) && + ((u4SeqNo + MAX_SEQ_NO_COUNT) < + (u4WinStart + HALF_SEQ_NO_COUNT)))) { + u16 u2Delta, u2BeforeWinEnd; + u32 u4BeforeCount, u4MissingCount; + +#if QM_RX_WIN_SSN_AUTO_ADVANCING + if (prReorderQueParm->fgIsWaitingForPktWithSsn) { + prReorderQueParm->fgIsWaitingForPktWithSsn = false; + } +#endif + + qmInsertFallAheadReorderPkt(prAdapter, prSwRfb, + prReorderQueParm, prReturnedQue); + + u2BeforeWinEnd = prReorderQueParm->u2WinEnd; + + /* Advance the window after inserting a new tail */ + prReorderQueParm->u2WinEnd = (u16)u4SeqNo; + prReorderQueParm->u2WinStart = (((prReorderQueParm->u2WinEnd) - + (prReorderQueParm->u2WinSize) + + MAX_SEQ_NO_COUNT + 1) % + MAX_SEQ_NO_COUNT); +#if CFG_SUPPORT_RX_AMSDU + /* RX reorder for one MSDU in AMSDU issue */ + prReorderQueParm->u8LastAmsduSubIdx = RX_PAYLOAD_FORMAT_MSDU; +#endif + u4BeforeCount = prReorderQueParm->rReOrderQue.u4NumElem; + qmPopOutDueToFallAhead(prAdapter, prReorderQueParm, + prReturnedQue); + + if (prReorderQueParm->u2WinEnd >= u2BeforeWinEnd) { + u2Delta = prReorderQueParm->u2WinEnd - u2BeforeWinEnd; + } else { + u2Delta = MAX_SEQ_NO_COUNT - + (u2BeforeWinEnd - prReorderQueParm->u2WinEnd); + } + + u4MissingCount = + u2Delta - (u4BeforeCount - + prReorderQueParm->rReOrderQue.u4NumElem); + + RX_ADD_CNT(&prAdapter->rRxCtrl, RX_DATA_REORDER_MISS_COUNT, + u4MissingCount); + RX_RESET_CNT(&prAdapter->rRxCtrl, + RX_DATA_REORDER_BEHIND_CONTINUOUS_COUNT); + } + /* Case 3: Fall behind */ + else { + u64 u8BehindContCount; +#if QM_RX_WIN_SSN_AUTO_ADVANCING && QM_RX_INIT_FALL_BEHIND_PASS + if (prReorderQueParm->fgIsWaitingForPktWithSsn) { + DBGLOG(QM, LOUD, "QM:(P)[%u](%u){%u,%u}\n", + prSwRfb->ucTid, u4SeqNo, u4WinStart, u4WinEnd); + qmPopOutReorderPkt(prAdapter, prSwRfb, prReturnedQue, + RX_DATA_REORDER_BEHIND_COUNT); + return; + } +#endif + + /* An erroneous packet */ + DBGLOG(QM, LOUD, "QM:(D)[%u](%u){%u,%u}\n", prSwRfb->ucTid, + u4SeqNo, u4WinStart, u4WinEnd); + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + qmPopOutReorderPkt(prAdapter, prSwRfb, prReturnedQue, + RX_DATA_REORDER_BEHIND_COUNT); + + /* Record how many continuous behind packets */ + RX_INC_CNT(&prAdapter->rRxCtrl, + RX_DATA_REORDER_BEHIND_CONTINUOUS_COUNT); + u8BehindContCount = + RX_GET_CNT(&prAdapter->rRxCtrl, + RX_DATA_REORDER_BEHIND_CONTINUOUS_COUNT); + /* Print warning message every times of threshold */ + if (u8BehindContCount % RX_BEHIND_CONTINUOUS_THRESHOLD == 0) { + DBGLOG(QM, WARN, "Drop %llu cont. behind packets\n", + u8BehindContCount); + } + + return; + } +} + +void qmInsertFallWithinReorderPkt(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue) +{ + P_SW_RFB_T prExaminedQueuedSwRfb; + P_QUE_T prReorderQue; + P_HW_MAC_RX_DESC_T prRxStatus; + u8 u8AmsduSubframeIdx; /* RX reorder for one MSDU in AMSDU issue */ + + ASSERT(prSwRfb); + ASSERT(prReorderQueParm); + ASSERT(prReturnedQue); + + prReorderQue = &(prReorderQueParm->rReOrderQue); + prExaminedQueuedSwRfb = (P_SW_RFB_T)QUEUE_GET_HEAD(prReorderQue); + + prRxStatus = prSwRfb->prRxStatus; + u8AmsduSubframeIdx = HAL_RX_STATUS_GET_PAYLOAD_FORMAT(prRxStatus); + + /* There are no packets queued in the Reorder Queue */ + if (prExaminedQueuedSwRfb == NULL) { + ((P_QUE_ENTRY_T)prSwRfb)->prPrev = NULL; + ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL; + prReorderQue->prHead = (P_QUE_ENTRY_T)prSwRfb; + prReorderQue->prTail = (P_QUE_ENTRY_T)prSwRfb; + prReorderQue->u4NumElem++; + } + /* Determine the insert position */ + else { + do { + /* Case 1: Terminate. A duplicate packet */ + if (((prExaminedQueuedSwRfb->u2SSN) == + (prSwRfb->u2SSN))) { +#if CFG_SUPPORT_RX_AMSDU + /* RX reorder for one MSDU in AMSDU issue */ + /* if middle or last and first is not + * duplicated, not a duplicat packet */ + if (!prReorderQueParm->fgIsAmsduDuplicated && + (u8AmsduSubframeIdx == + RX_PAYLOAD_FORMAT_MIDDLE_SUB_AMSDU || + u8AmsduSubframeIdx == + RX_PAYLOAD_FORMAT_LAST_SUB_AMSDU)) { + prExaminedQueuedSwRfb = + (P_SW_RFB_T)(((P_QUE_ENTRY_T) + prExaminedQueuedSwRfb) + ->prNext); + while (prExaminedQueuedSwRfb && + ((prExaminedQueuedSwRfb->u2SSN) + == + (prSwRfb->u2SSN))) + prExaminedQueuedSwRfb = + (P_SW_RFB_T)((( + P_QUE_ENTRY_T) + prExaminedQueuedSwRfb) + ->prNext); + + break; + } + /* if first is duplicated, drop subsequent + * middle and last frames */ + if (u8AmsduSubframeIdx == + RX_PAYLOAD_FORMAT_FIRST_SUB_AMSDU) { + prReorderQueParm->fgIsAmsduDuplicated = + true; + } +#endif + prSwRfb->eDst = RX_PKT_DESTINATION_NULL; + qmPopOutReorderPkt(prAdapter, prSwRfb, + prReturnedQue, + RX_DUPICATE_DROP_COUNT); + return; + } + /* Case 2: Terminate. The insert point is found */ + else if (qmCompareSnIsLessThan( + (prSwRfb->u2SSN), + (prExaminedQueuedSwRfb->u2SSN))) { + break; + } + /* Case 3: Insert point not found. Check the next SW_RFB + * in the Reorder Queue */ + else { + prExaminedQueuedSwRfb = + (P_SW_RFB_T)(((P_QUE_ENTRY_T) + prExaminedQueuedSwRfb) + ->prNext); + } + } while (prExaminedQueuedSwRfb); +#if CFG_SUPPORT_RX_AMSDU + prReorderQueParm->fgIsAmsduDuplicated = false; +#endif + /* Update the Reorder Queue Parameters according to the found + * insert position */ + if (prExaminedQueuedSwRfb == NULL) { + /* The received packet shall be placed at the tail */ + ((P_QUE_ENTRY_T)prSwRfb)->prPrev = prReorderQue->prTail; + ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL; + (prReorderQue->prTail)->prNext = + (P_QUE_ENTRY_T)(prSwRfb); + prReorderQue->prTail = (P_QUE_ENTRY_T)(prSwRfb); + } else { + ((P_QUE_ENTRY_T)prSwRfb)->prPrev = + ((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prPrev; + ((P_QUE_ENTRY_T)prSwRfb)->prNext = + (P_QUE_ENTRY_T)prExaminedQueuedSwRfb; + if (((P_QUE_ENTRY_T)prExaminedQueuedSwRfb) == + (prReorderQue->prHead)) { + /* The received packet will become the head */ + prReorderQue->prHead = (P_QUE_ENTRY_T)prSwRfb; + } else { + (((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prPrev) + ->prNext = (P_QUE_ENTRY_T)prSwRfb; + } + ((P_QUE_ENTRY_T)prExaminedQueuedSwRfb)->prPrev = + (P_QUE_ENTRY_T)prSwRfb; + } + + prReorderQue->u4NumElem++; + } +} + +void qmInsertFallAheadReorderPkt(IN P_ADAPTER_T prAdapter, + IN P_SW_RFB_T prSwRfb, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue) +{ + P_QUE_T prReorderQue; + + ASSERT(prSwRfb); + ASSERT(prReorderQueParm); + ASSERT(prReturnedQue); +#if CFG_SUPPORT_RX_AMSDU + /* RX reorder for one MSDU in AMSDU issue */ + prReorderQueParm->fgIsAmsduDuplicated = false; +#endif + prReorderQue = &(prReorderQueParm->rReOrderQue); + + /* There are no packets queued in the Reorder Queue */ + if (QUEUE_IS_EMPTY(prReorderQue)) { + ((P_QUE_ENTRY_T)prSwRfb)->prPrev = NULL; + ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL; + prReorderQue->prHead = (P_QUE_ENTRY_T)prSwRfb; + } else { + ((P_QUE_ENTRY_T)prSwRfb)->prPrev = prReorderQue->prTail; + ((P_QUE_ENTRY_T)prSwRfb)->prNext = NULL; + (prReorderQue->prTail)->prNext = (P_QUE_ENTRY_T)(prSwRfb); + } + prReorderQue->prTail = (P_QUE_ENTRY_T)prSwRfb; + prReorderQue->u4NumElem++; +} + +void qmPopOutReorderPkt(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + OUT P_QUE_T prReturnedQue, + IN ENUM_RX_STATISTIC_COUNTER_T eRxCounter) +{ + u32 u4PktCnt = 0; + /* RX reorder for one MSDU in AMSDU issue */ + + u4PktCnt++; + QUEUE_INSERT_TAIL(prReturnedQue, (P_QUE_ENTRY_T)prSwRfb); + + RX_ADD_CNT(&prAdapter->rRxCtrl, eRxCounter, u4PktCnt); +} + +void qmPopOutDueToFallWithin(IN P_ADAPTER_T prAdapter, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue) +{ + P_SW_RFB_T prReorderedSwRfb; + P_QUE_T prReorderQue; + u8 fgDequeuHead, fgMissing; + u32 rCurrentTime, *prMissTimeout; + P_HW_MAC_RX_DESC_T prRxStatus; + u8 fgIsAmsduSubframe; /* RX reorder for one MSDU in AMSDU issue */ + + prReorderQue = &(prReorderQueParm->rReOrderQue); + + fgMissing = false; + rCurrentTime = 0; + prMissTimeout = &g_arMissTimeout[prReorderQueParm->ucStaRecIdx] + [prReorderQueParm->ucTid]; + if (*prMissTimeout) { + fgMissing = true; + GET_CURRENT_SYSTIME(&rCurrentTime); + } + + /* Check whether any packet can be indicated to the higher layer */ + while (true) { + if (QUEUE_IS_EMPTY(prReorderQue)) { + break; + } + + /* Always examine the head packet */ + prReorderedSwRfb = (P_SW_RFB_T)QUEUE_GET_HEAD(prReorderQue); + fgDequeuHead = false; + + /* RX reorder for one MSDU in AMSDU issue */ + prRxStatus = prReorderedSwRfb->prRxStatus; + fgIsAmsduSubframe = + HAL_RX_STATUS_GET_PAYLOAD_FORMAT(prRxStatus); +#if CFG_SUPPORT_RX_AMSDU + /* If SN + 1 come and last frame is first or middle, update + * winstart */ + if ((qmCompareSnIsLessThan((prReorderQueParm->u2WinStart), + (prReorderedSwRfb->u2SSN))) && + (prReorderQueParm->u4SeqNo != + prReorderQueParm->u2WinStart)) { + if (prReorderQueParm->u8LastAmsduSubIdx == + RX_PAYLOAD_FORMAT_FIRST_SUB_AMSDU || + prReorderQueParm->u8LastAmsduSubIdx == + RX_PAYLOAD_FORMAT_MIDDLE_SUB_AMSDU) { + prReorderQueParm->u2WinStart = + (((prReorderQueParm->u2WinStart) + 1) % + MAX_SEQ_NO_COUNT); + prReorderQueParm->u8LastAmsduSubIdx = + RX_PAYLOAD_FORMAT_MSDU; + } + } +#endif + /* SN == WinStart, so the head packet shall be indicated + * (advance the window) */ + if ((prReorderedSwRfb->u2SSN) == + (prReorderQueParm->u2WinStart)) { + fgDequeuHead = true; + /* RX reorder for one MSDU in AMSDU issue */ + /* if last frame, winstart++. Otherwise, keep winstart + */ + if (fgIsAmsduSubframe == + RX_PAYLOAD_FORMAT_LAST_SUB_AMSDU || + fgIsAmsduSubframe == RX_PAYLOAD_FORMAT_MSDU) { + prReorderQueParm->u2WinStart = + (((prReorderedSwRfb->u2SSN) + 1) % + MAX_SEQ_NO_COUNT); + } +#if CFG_SUPPORT_RX_AMSDU + prReorderQueParm->u8LastAmsduSubIdx = fgIsAmsduSubframe; +#endif + } + /* SN > WinStart, break to update WinEnd */ + else { + /* Start bubble timer */ + if (!prReorderQueParm->fgHasBubble) { + cnmTimerStartTimer( + prAdapter, + &(prReorderQueParm->rReorderBubbleTimer), + QM_RX_BA_ENTRY_MISS_TIMEOUT_MS); + prReorderQueParm->fgHasBubble = true; + prReorderQueParm->u2FirstBubbleSn = + prReorderQueParm->u2WinStart; + + DBGLOG(QM, + TRACE, + "QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n", + prReorderQueParm->ucStaRecIdx, + prReorderedSwRfb->ucTid, + prReorderQueParm->u2FirstBubbleSn, + prReorderQueParm->u2WinStart, + prReorderQueParm->u2WinEnd); + } + + if (fgMissing && + CHECK_FOR_TIMEOUT( + rCurrentTime, *prMissTimeout, + MSEC_TO_SYSTIME( + QM_RX_BA_ENTRY_MISS_TIMEOUT_MS))) { + DBGLOG(QM, TRACE, + "QM:RX BA Timout Next Tid %d SSN %d\n", + prReorderQueParm->ucTid, + prReorderedSwRfb->u2SSN); + fgDequeuHead = true; + prReorderQueParm->u2WinStart = + (((prReorderedSwRfb->u2SSN) + 1) % + MAX_SEQ_NO_COUNT); +#if CFG_SUPPORT_RX_AMSDU + /* RX reorder for one MSDU in AMSDU issue */ + prReorderQueParm->u8LastAmsduSubIdx = + RX_PAYLOAD_FORMAT_MSDU; +#endif + fgMissing = false; + } else { + break; + } + } + + /* Dequeue the head packet */ + if (fgDequeuHead) { + if (((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext == NULL) { + prReorderQue->prHead = NULL; + prReorderQue->prTail = NULL; + } else { + prReorderQue->prHead = + ((P_QUE_ENTRY_T)prReorderedSwRfb) + ->prNext; + (((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext) + ->prPrev = NULL; + } + prReorderQue->u4NumElem--; + DBGLOG(QM, LOUD, "QM: [%d] %d (%d)\n", + prReorderQueParm->ucTid, + prReorderedSwRfb->u2PacketLen, + prReorderedSwRfb->u2SSN); + qmPopOutReorderPkt(prAdapter, prReorderedSwRfb, + prReturnedQue, + RX_DATA_REORDER_WITHIN_COUNT); + } + } + + if (QUEUE_IS_EMPTY(prReorderQue)) { + *prMissTimeout = 0; + } else { + if (fgMissing == false) { + GET_CURRENT_SYSTIME(prMissTimeout); + } + } + + /* After WinStart has been determined, update the WinEnd */ + prReorderQueParm->u2WinEnd = (((prReorderQueParm->u2WinStart) + + (prReorderQueParm->u2WinSize) - 1) % + MAX_SEQ_NO_COUNT); +} + +void qmPopOutDueToFallAhead(IN P_ADAPTER_T prAdapter, + IN P_RX_BA_ENTRY_T prReorderQueParm, + OUT P_QUE_T prReturnedQue) +{ + P_SW_RFB_T prReorderedSwRfb; + P_QUE_T prReorderQue; + u8 fgDequeuHead; + P_HW_MAC_RX_DESC_T prRxStatus; + u8 fgIsAmsduSubframe; /* RX reorder for one MSDU in AMSDU issue */ + + prReorderQue = &(prReorderQueParm->rReOrderQue); + + /* Check whether any packet can be indicated to the higher layer */ + while (true) { + if (QUEUE_IS_EMPTY(prReorderQue)) { + break; + } + + /* Always examine the head packet */ + prReorderedSwRfb = (P_SW_RFB_T)QUEUE_GET_HEAD(prReorderQue); + fgDequeuHead = false; + + /* RX reorder for one MSDU in AMSDU issue */ + prRxStatus = prReorderedSwRfb->prRxStatus; + fgIsAmsduSubframe = + HAL_RX_STATUS_GET_PAYLOAD_FORMAT(prRxStatus); +#if CFG_SUPPORT_RX_AMSDU + /* If SN + 1 come and last frame is first or middle, update + * winstart */ + if ((qmCompareSnIsLessThan((prReorderQueParm->u2WinStart), + (prReorderedSwRfb->u2SSN))) && + (prReorderQueParm->u4SeqNo != + prReorderQueParm->u2WinStart)) { + if (prReorderQueParm->u8LastAmsduSubIdx == + RX_PAYLOAD_FORMAT_FIRST_SUB_AMSDU || + prReorderQueParm->u8LastAmsduSubIdx == + RX_PAYLOAD_FORMAT_MIDDLE_SUB_AMSDU) { + prReorderQueParm->u2WinStart = + (((prReorderQueParm->u2WinStart) + 1) % + MAX_SEQ_NO_COUNT); + prReorderQueParm->u8LastAmsduSubIdx = + RX_PAYLOAD_FORMAT_MSDU; + } + } +#endif + /* SN == WinStart, so the head packet shall be indicated + * (advance the window) */ + if ((prReorderedSwRfb->u2SSN) == + (prReorderQueParm->u2WinStart)) { + fgDequeuHead = true; + /* RX reorder for one MSDU in AMSDU issue */ + /* if last frame, winstart++. Otherwise, keep winstart + */ + if (fgIsAmsduSubframe == + RX_PAYLOAD_FORMAT_LAST_SUB_AMSDU || + fgIsAmsduSubframe == RX_PAYLOAD_FORMAT_MSDU) { + prReorderQueParm->u2WinStart = + (((prReorderedSwRfb->u2SSN) + 1) % + MAX_SEQ_NO_COUNT); + } +#if CFG_SUPPORT_RX_AMSDU + prReorderQueParm->u8LastAmsduSubIdx = fgIsAmsduSubframe; +#endif + } + /* SN < WinStart, so the head packet shall be indicated (do not + * advance the window) */ + else if (qmCompareSnIsLessThan( + (u32)(prReorderedSwRfb->u2SSN), + (u32)(prReorderQueParm->u2WinStart))) { + fgDequeuHead = true; + } + /* SN > WinStart, break to update WinEnd */ + else { + /* Start bubble timer */ + if (!prReorderQueParm->fgHasBubble) { + cnmTimerStartTimer( + prAdapter, + &(prReorderQueParm->rReorderBubbleTimer), + QM_RX_BA_ENTRY_MISS_TIMEOUT_MS); + prReorderQueParm->fgHasBubble = true; + prReorderQueParm->u2FirstBubbleSn = + prReorderQueParm->u2WinStart; + + DBGLOG(QM, + TRACE, + "QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n", + prReorderQueParm->ucStaRecIdx, + prReorderedSwRfb->ucTid, + prReorderQueParm->u2FirstBubbleSn, + prReorderQueParm->u2WinStart, + prReorderQueParm->u2WinEnd); + } + break; + } + + /* Dequeue the head packet */ + if (fgDequeuHead) { + if (((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext == NULL) { + prReorderQue->prHead = NULL; + prReorderQue->prTail = NULL; + } else { + prReorderQue->prHead = + ((P_QUE_ENTRY_T)prReorderedSwRfb) + ->prNext; + (((P_QUE_ENTRY_T)prReorderedSwRfb)->prNext) + ->prPrev = NULL; + } + prReorderQue->u4NumElem--; + DBGLOG(QM, TRACE, "QM: [%d] %d (%d)\n", + prReorderQueParm->ucTid, + prReorderedSwRfb->u2PacketLen, + prReorderedSwRfb->u2SSN); + + qmPopOutReorderPkt(prAdapter, prReorderedSwRfb, + prReturnedQue, + RX_DATA_REORDER_AHEAD_COUNT); + } + } + + /* After WinStart has been determined, update the WinEnd */ + prReorderQueParm->u2WinEnd = (((prReorderQueParm->u2WinStart) + + (prReorderQueParm->u2WinSize) - 1) % + MAX_SEQ_NO_COUNT); +} + +void qmHandleReorderBubbleTimeout(IN P_ADAPTER_T prAdapter, + IN unsigned long ulParamPtr) +{ + P_RX_BA_ENTRY_T prReorderQueParm = (P_RX_BA_ENTRY_T)ulParamPtr; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T)NULL; + P_WIFI_EVENT_T prEvent = NULL; + P_EVENT_CHECK_REORDER_BUBBLE_T prCheckReorderEvent; + + KAL_SPIN_LOCK_DECLARATION(); + + if (!prReorderQueParm->fgIsValid) { + DBGLOG(QM, + TRACE, + "QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n", + prReorderQueParm->ucStaRecIdx, + prReorderQueParm->ucTid); + return; + } + + if (!prReorderQueParm->fgHasBubble) { + DBGLOG(QM, + TRACE, + "QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n", + prReorderQueParm->ucStaRecIdx, + prReorderQueParm->ucTid); + return; + } + + DBGLOG(QM, TRACE, "QM:(Bub Timeout) STA[%u] TID[%u] BubSN[%u]\n", + prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid, + prReorderQueParm->u2FirstBubbleSn); + + /* Generate a self-inited event to Rx path */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + QUEUE_REMOVE_HEAD(&prAdapter->rRxCtrl.rFreeSwRfbList, prSwRfb, + P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + + if (prSwRfb) { + prEvent = (P_WIFI_EVENT_T)(prSwRfb->pucRecvBuff); + prEvent->ucEID = EVENT_ID_CHECK_REORDER_BUBBLE; + prEvent->ucSeqNum = 0; + prEvent->u2PacketLength = sizeof(WIFI_EVENT_T) + + sizeof(EVENT_CHECK_REORDER_BUBBLE_T); + + prCheckReorderEvent = + (P_EVENT_CHECK_REORDER_BUBBLE_T)prEvent->aucBuffer; + prCheckReorderEvent->ucStaRecIdx = + prReorderQueParm->ucStaRecIdx; + prCheckReorderEvent->ucTid = prReorderQueParm->ucTid; + + prSwRfb->ucPacketType = RX_PKT_TYPE_SW_DEFINED; + prSwRfb->prRxStatus->u2PktTYpe = RXM_RXD_PKT_TYPE_SW_EVENT; + prSwRfb->prRxStatus->u2RxByteCount = + prEvent->u2PacketLength + sizeof(HW_MAC_RX_DESC_T); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_INSERT_TAIL(&prAdapter->rRxCtrl.rReceivedRfbList, + &prSwRfb->rQueEntry); + RX_INC_CNT(&prAdapter->rRxCtrl, RX_MPDU_TOTAL_COUNT); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + DBGLOG(QM, LOUD, "QM:(Bub Check Event Sent) STA[%u] TID[%u]\n", + prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid); + + nicRxProcessRFBs(prAdapter); + + DBGLOG(QM, LOUD, + "QM:(Bub Check Event Handled) STA[%u] TID[%u]\n", + prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid); + } else { + DBGLOG(QM, + TRACE, + "QM:(Bub Check Cancel) STA[%u] TID[%u], Bub check event alloc failed\n", + prReorderQueParm->ucStaRecIdx, + prReorderQueParm->ucTid); + + cnmTimerStartTimer(prAdapter, + &(prReorderQueParm->rReorderBubbleTimer), + QM_RX_BA_ENTRY_MISS_TIMEOUT_MS); + + DBGLOG(QM, + TRACE, + "QM:(Bub Timer Restart) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n", + prReorderQueParm->ucStaRecIdx, + prReorderQueParm->ucTid, + prReorderQueParm->u2FirstBubbleSn, + prReorderQueParm->u2WinStart, + prReorderQueParm->u2WinEnd); + } +} + +void qmHandleEventCheckReorderBubble(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_EVENT_CHECK_REORDER_BUBBLE_T prCheckReorderEvent; + P_RX_BA_ENTRY_T prReorderQueParm; + P_QUE_T prReorderQue; + QUE_T rReturnedQue; + P_QUE_T prReturnedQue = &rReturnedQue; + P_SW_RFB_T prReorderedSwRfb, prSwRfb; + u32 *prMissTimeout; + + if (u4EventBufLen < sizeof(EVENT_CHECK_REORDER_BUBBLE_T)) { + DBGLOG(QM, ERROR, "%s: Invalid event length: %d < %d\n", + __func__, u4EventBufLen, + sizeof(EVENT_CHECK_REORDER_BUBBLE_T)); + return; + } + + prCheckReorderEvent = + (P_EVENT_CHECK_REORDER_BUBBLE_T)(prEvent->aucBuffer); + + QUEUE_INITIALIZE(prReturnedQue); + + /* Get target Rx BA entry */ + prReorderQueParm = qmLookupRxBaEntry(prAdapter, + prCheckReorderEvent->ucStaRecIdx, + prCheckReorderEvent->ucTid); + + /* Sanity Check */ + if (!prReorderQueParm) { + DBGLOG(QM, + TRACE, + "QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n", + prCheckReorderEvent->ucStaRecIdx, + prCheckReorderEvent->ucTid); + return; + } + + if (!prReorderQueParm->fgIsValid) { + DBGLOG(QM, + TRACE, + "QM:(Bub Check Cancel) STA[%u] TID[%u], No Rx BA entry\n", + prReorderQueParm->ucStaRecIdx, + prReorderQueParm->ucTid); + return; + } + + if (!prReorderQueParm->fgHasBubble) { + DBGLOG(QM, + TRACE, + "QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n", + prReorderQueParm->ucStaRecIdx, + prReorderQueParm->ucTid); + return; + } + + prReorderQue = &(prReorderQueParm->rReOrderQue); + + RX_DIRECT_REORDER_LOCK(prAdapter, 0); + + if (QUEUE_IS_EMPTY(prReorderQue)) { + prReorderQueParm->fgHasBubble = false; + + DBGLOG(QM, + TRACE, + "QM:(Bub Check Cancel) STA[%u] TID[%u], Bubble has been filled\n", + prReorderQueParm->ucStaRecIdx, + prReorderQueParm->ucTid); + RX_DIRECT_REORDER_UNLOCK(prAdapter, 0); + return; + } + + DBGLOG(QM, TRACE, "QM:(Bub Check Event Got) STA[%u] TID[%u]\n", + prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid); + + /* Expected bubble timeout => pop out packets before win_end */ + if (prReorderQueParm->u2FirstBubbleSn == prReorderQueParm->u2WinStart) { + prReorderedSwRfb = (P_SW_RFB_T)QUEUE_GET_TAIL(prReorderQue); + + prReorderQueParm->u2WinStart = prReorderedSwRfb->u2SSN + 1; + prReorderQueParm->u2WinEnd = + ((prReorderQueParm->u2WinStart) + + (prReorderQueParm->u2WinSize) - 1) % + MAX_SEQ_NO_COUNT; +#if CFG_SUPPORT_RX_AMSDU + prReorderQueParm->u8LastAmsduSubIdx = RX_PAYLOAD_FORMAT_MSDU; +#endif + qmPopOutDueToFallAhead(prAdapter, prReorderQueParm, + prReturnedQue); + + DBGLOG(QM, TRACE, + "QM:(Bub Flush) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n", + prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid, + prReorderQueParm->u2FirstBubbleSn, + prReorderQueParm->u2WinStart, + prReorderQueParm->u2WinEnd); + + prReorderQueParm->fgHasBubble = false; + RX_DIRECT_REORDER_UNLOCK(prAdapter, 0); + + /* process prReturnedQue after unlock prReturnedQue */ + if (QUEUE_IS_NOT_EMPTY(prReturnedQue)) { + P_QUE_ENTRY_T prTail = QUEUE_GET_TAIL(prReturnedQue); + + QM_RX_SET_NEXT_SW_RFB((P_SW_RFB_T)prTail, NULL); + + prSwRfb = (P_SW_RFB_T)QUEUE_GET_HEAD(prReturnedQue); + while (prSwRfb) { + DBGLOG(QM, + TRACE, + "QM:(Bub Flush) STA[%u] TID[%u] Pop Out SN[%u]\n", + prReorderQueParm->ucStaRecIdx, + prReorderQueParm->ucTid, + prSwRfb->u2SSN); + + prSwRfb = (P_SW_RFB_T)QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prSwRfb); + } + + wlanProcessQueuedSwRfb( + prAdapter, + (P_SW_RFB_T)QUEUE_GET_HEAD(prReturnedQue)); + } else { + DBGLOG(QM, + TRACE, + "QM:(Bub Flush) STA[%u] TID[%u] Pop Out 0 packet\n", + prReorderQueParm->ucStaRecIdx, + prReorderQueParm->ucTid); + } + } + /* First bubble has been filled but others exist */ + else { + prReorderQueParm->u2FirstBubbleSn = + prReorderQueParm->u2WinStart; + + DBGLOG(QM, TRACE, + "QM:(Bub Timer) STA[%u] TID[%u] BubSN[%u] Win{%d, %d}\n", + prReorderQueParm->ucStaRecIdx, prReorderQueParm->ucTid, + prReorderQueParm->u2FirstBubbleSn, + prReorderQueParm->u2WinStart, + prReorderQueParm->u2WinEnd); + + RX_DIRECT_REORDER_UNLOCK(prAdapter, 0); + + cnmTimerStartTimer(prAdapter, + &(prReorderQueParm->rReorderBubbleTimer), + QM_RX_BA_ENTRY_MISS_TIMEOUT_MS); + } + + prMissTimeout = &g_arMissTimeout[prReorderQueParm->ucStaRecIdx] + [prReorderQueParm->ucTid]; + if (QUEUE_IS_EMPTY(prReorderQue)) { + DBGLOG(QM, TRACE, + "QM:(Bub Check) Reset prMissTimeout to zero\n"); + *prMissTimeout = 0; + } else { + DBGLOG(QM, TRACE, + "QM:(Bub Check) Reset prMissTimeout to current time\n"); + GET_CURRENT_SYSTIME(prMissTimeout); + } +} + +u8 qmCompareSnIsLessThan(IN u32 u4SnLess, IN u32 u4SnGreater) +{ + /* 0 <---> SnLess <--(gap>2048)--> SnGreater : SnLess > SnGreater */ + if ((u4SnLess + HALF_SEQ_NO_COUNT) <= u4SnGreater) { /* Shall be <= */ + return false; + } + /* 0 <---> SnGreater <--(gap>2048)--> SnLess : SnLess < SnGreater */ + else if ((u4SnGreater + HALF_SEQ_NO_COUNT) < u4SnLess) { + return true; + } + /* 0 <---> SnGreater <--(gap<2048)--> SnLess : SnLess > SnGreater */ + /* 0 <---> SnLess <--(gap<2048)--> SnGreater : SnLess < SnGreater */ + else{ + return u4SnLess < u4SnGreater; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Handle Mailbox RX messages + * + * \param[in] prMailboxRxMsg The received Mailbox message from the FW + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmHandleMailboxRxMessage(IN MAILBOX_MSG_T prMailboxRxMsg) +{ + /* DbgPrint("QM: Enter qmHandleMailboxRxMessage()\n"); */ + /* TODO */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Handle ADD RX BA Event from the FW + * + * \param[in] prAdapter Adapter pointer + * \param[in] prEvent The event packet from the FW + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmHandleEventRxAddBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_EVENT_RX_ADDBA_T prEventRxAddBa; + P_STA_RECORD_T prStaRec; + u32 u4Tid; + u32 u4WinSize; + + DBGLOG(QM, INFO, "QM:Event +RxBa\n"); + if (u4EventBufLen < sizeof(EVENT_RX_ADDBA_T)) { + DBGLOG(QM, ERROR, "%s: Invalid event length: %d < %d\n", + __func__, u4EventBufLen, sizeof(EVENT_RX_ADDBA_T)); + return; + } + prEventRxAddBa = (P_EVENT_RX_ADDBA_T)(prEvent->aucBuffer); + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, + prEventRxAddBa->ucStaRecIdx); + + if (!prStaRec) { + /* Invalid STA_REC index, discard the event packet */ + /* ASSERT(0); */ + DBGLOG(QM, INFO, + "QM: (Warning) RX ADDBA Event for a NULL STA_REC\n"); + return; + } + + u4Tid = (((prEventRxAddBa->u2BAParameterSet) & BA_PARAM_SET_TID_MASK) >> + BA_PARAM_SET_TID_MASK_OFFSET); + + u4WinSize = (((prEventRxAddBa->u2BAParameterSet) & + BA_PARAM_SET_BUFFER_SIZE_MASK) >> + BA_PARAM_SET_BUFFER_SIZE_MASK_OFFSET); + + if (!qmAddRxBaEntry(prAdapter, prStaRec->ucIndex, (u8)u4Tid, + (prEventRxAddBa->u2BAStartSeqCtrl >> + OFFSET_BAR_SSC_SN), + (u16)u4WinSize)) { + /* FW shall ensure the availabiilty of the free-to-use BA entry + */ + DBGLOG(QM, ERROR, "QM: (Error) qmAddRxBaEntry() failure\n"); + ASSERT(0); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Handle DEL RX BA Event from the FW + * + * \param[in] prAdapter Adapter pointer + * \param[in] prEvent The event packet from the FW + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmHandleEventRxDelBa(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_EVENT_RX_DELBA_T prEventRxDelBa; + P_STA_RECORD_T prStaRec; + + if (u4EventBufLen < sizeof(EVENT_RX_DELBA_T)) { + DBGLOG(QM, ERROR, "%s: Invalid event length: %d < %d\n", + __func__, u4EventBufLen, sizeof(EVENT_RX_DELBA_T)); + return; + } + prEventRxDelBa = (P_EVENT_RX_DELBA_T)(prEvent->aucBuffer); + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, + prEventRxDelBa->ucStaRecIdx); + + if (!prStaRec) { + return; + } + + qmDelRxBaEntry(prAdapter, prStaRec->ucIndex, prEventRxDelBa->ucTid, + true); +} + +P_RX_BA_ENTRY_T qmLookupRxBaEntry(IN P_ADAPTER_T prAdapter, u8 ucStaRecIdx, + u8 ucTid) +{ + int i; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + /* DbgPrint("QM: Enter qmLookupRxBaEntry()\n"); */ + + for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { + if (prQM->arRxBaTable[i].fgIsValid) { + if ((prQM->arRxBaTable[i].ucStaRecIdx == ucStaRecIdx) && + (prQM->arRxBaTable[i].ucTid == ucTid)) { + return &prQM->arRxBaTable[i]; + } + } + } + return NULL; +} + +u8 qmAddRxBaEntry(IN P_ADAPTER_T prAdapter, IN u8 ucStaRecIdx, IN u8 ucTid, + IN u16 u2WinStart, IN u16 u2WinSize) +{ + int i; + P_RX_BA_ENTRY_T prRxBaEntry = NULL; + P_STA_RECORD_T prStaRec; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + ASSERT(ucStaRecIdx < CFG_STA_REC_NUM); + + if (ucStaRecIdx >= CFG_STA_REC_NUM || ucTid >= CFG_RX_MAX_BA_TID_NUM) { + /* Invalid STA_REC index, discard the event packet */ + DBGLOG(QM, + WARN, + "QM: (WARNING) RX ADDBA Event for a invalid ucStaRecIdx = %d, ucTID=%d\n", + ucStaRecIdx, + ucTid); + return false; + } + + prStaRec = &prAdapter->arStaRec[ucStaRecIdx]; + ASSERT(prStaRec); + + /* if(!(prStaRec->fgIsValid)){ */ + /* DbgPrint("QM: (WARNING) Invalid STA when adding an RX BA\n"); */ + /* return false; */ + /* } */ + + /* 4 <1> Delete before adding */ + /* Remove the BA entry for the same (STA, TID) tuple if it exists */ + if (qmLookupRxBaEntry(prAdapter, ucStaRecIdx, ucTid)) { + qmDelRxBaEntry(prAdapter, ucStaRecIdx, ucTid, + true); /* prQM->ucRxBaCount-- + */ + } + /* 4 <2> Add a new BA entry */ + /* No available entry to store the BA agreement info. Retrun false. */ + if (prQM->ucRxBaCount >= CFG_NUM_OF_RX_BA_AGREEMENTS) { + DBGLOG(QM, ERROR, + "QM: **failure** (limited resource, ucRxBaCount=%d)\n", + prQM->ucRxBaCount); + return false; + } + /* Find the free-to-use BA entry */ + for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) { + if (!prQM->arRxBaTable[i].fgIsValid) { + prRxBaEntry = &(prQM->arRxBaTable[i]); + prQM->ucRxBaCount++; + DBGLOG(QM, LOUD, "QM: ucRxBaCount=%d\n", + prQM->ucRxBaCount); + break; + } + } + + /* If a free-to-use entry is found, configure it and associate it with + * the STA_REC */ + u2WinSize += CFG_RX_BA_INC_SIZE; + if (prRxBaEntry) { + prRxBaEntry->ucStaRecIdx = ucStaRecIdx; + prRxBaEntry->ucTid = ucTid; + prRxBaEntry->u2WinStart = u2WinStart; + prRxBaEntry->u2WinSize = u2WinSize; + prRxBaEntry->u2WinEnd = + ((u2WinStart + u2WinSize - 1) % MAX_SEQ_NO_COUNT); +#if CFG_SUPPORT_RX_AMSDU + /* RX reorder for one MSDU in AMSDU issue */ + prRxBaEntry->u8LastAmsduSubIdx = RX_PAYLOAD_FORMAT_MSDU; + prRxBaEntry->fgAmsduNeedLastFrame = false; + prRxBaEntry->fgIsAmsduDuplicated = false; +#endif + prRxBaEntry->fgIsValid = true; + prRxBaEntry->fgIsWaitingForPktWithSsn = true; + prRxBaEntry->fgHasBubble = false; + + g_arMissTimeout[ucStaRecIdx][ucTid] = 0; + + DBGLOG(QM, + INFO, + "QM: +RxBA(STA=%d TID=%d WinStart=%d WinEnd=%d WinSize=%d)\n", + ucStaRecIdx, + ucTid, + prRxBaEntry->u2WinStart, + prRxBaEntry->u2WinEnd, + prRxBaEntry->u2WinSize); + + /* Update the BA entry reference table for per-packet lookup */ + prStaRec->aprRxReorderParamRefTbl[ucTid] = prRxBaEntry; + } else { + /* This shall not happen because FW should keep track of the + * usage of RX BA entries */ + DBGLOG(QM, ERROR, "QM: **AddBA Error** (ucRxBaCount=%d)\n", + prQM->ucRxBaCount); + return false; + } + + return true; +} + +void qmDelRxBaEntry(IN P_ADAPTER_T prAdapter, IN u8 ucStaRecIdx, IN u8 ucTid, + IN u8 fgFlushToHost) +{ + P_RX_BA_ENTRY_T prRxBaEntry = NULL; + P_STA_RECORD_T prStaRec; + P_SW_RFB_T prFlushedPacketList = NULL; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + ASSERT(ucStaRecIdx < CFG_STA_REC_NUM); + + prStaRec = &prAdapter->arStaRec[ucStaRecIdx]; + ASSERT(prStaRec); + + if (ucTid >= CFG_RX_MAX_BA_TID_NUM) { + DBGLOG(QM, WARN, "QM: ucTid invalid: %d in %s)\n", ucTid, + __func__); + return; + } + /* Remove the BA entry for the same (STA, TID) tuple if it exists */ + if (ucTid < CFG_RX_MAX_BA_TID_NUM) { + prRxBaEntry = prStaRec->aprRxReorderParamRefTbl[ucTid]; + } + + if (prRxBaEntry) { + prFlushedPacketList = + qmFlushStaRxQueue(prAdapter, ucStaRecIdx, ucTid); + + if (prFlushedPacketList) { + if (fgFlushToHost) { + wlanProcessQueuedSwRfb(prAdapter, + prFlushedPacketList); + } else { + P_SW_RFB_T prSwRfb; + P_SW_RFB_T prNextSwRfb; + + prSwRfb = prFlushedPacketList; + + do { + prNextSwRfb = (P_SW_RFB_T) + QUEUE_GET_NEXT_ENTRY( + (P_QUE_ENTRY_T)prSwRfb); + nicRxReturnRFB(prAdapter, prSwRfb); + prSwRfb = prNextSwRfb; + } while (prSwRfb); + } + } + + if (prRxBaEntry->fgHasBubble) { + DBGLOG(QM, TRACE, + "QM:(Bub Check Cancel) STA[%u] TID[%u], DELBA\n", + prRxBaEntry->ucStaRecIdx, prRxBaEntry->ucTid); + + cnmTimerStopTimer(prAdapter, + &prRxBaEntry->rReorderBubbleTimer); + prRxBaEntry->fgHasBubble = false; + } +#if ((QM_TEST_MODE == 0) && (QM_TEST_STA_REC_DEACTIVATION == 0)) + /* Update RX BA entry state. Note that RX queue flush is not + * done here */ + prRxBaEntry->fgIsValid = false; + prQM->ucRxBaCount--; + + /* Update STA RX BA table */ + prStaRec->aprRxReorderParamRefTbl[ucTid] = NULL; +#endif + + DBGLOG(QM, INFO, "QM: -RxBA(STA=%d,TID=%d)\n", ucStaRecIdx, + ucTid); + } + + /* Debug */ +#if CFG_HIF_RX_STARVATION_WARNING + { + P_RX_CTRL_T prRxCtrl; + + prRxCtrl = &prAdapter->rRxCtrl; + DBGLOG(QM, TRACE, + "QM: (RX DEBUG) Enqueued: %d / Dequeued: %d\n", + prRxCtrl->u4QueuedCnt, prRxCtrl->u4DequeuedCnt); + } +#endif +} + +void mqmParseAssocReqWmmIe(IN P_ADAPTER_T prAdapter, IN u8 *pucIE, + IN P_STA_RECORD_T prStaRec) +{ + P_IE_WMM_INFO_T prIeWmmInfo; + u8 ucQosInfo; + u8 ucQosInfoAC; + u8 ucBmpAC; + u8 aucWfaOui[] = VENDOR_OUI_WFA; + + if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && + (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) { + switch (WMM_IE_OUI_SUBTYPE(pucIE)) { + case VENDOR_OUI_SUBTYPE_WMM_INFO: + if (IE_LEN(pucIE) != 7) { + break; /* WMM Info IE with a wrong length */ + + } + prStaRec->fgIsQoS = true; + prStaRec->fgIsWmmSupported = true; + + prIeWmmInfo = (P_IE_WMM_INFO_T)pucIE; + ucQosInfo = prIeWmmInfo->ucQosInfo; + ucQosInfoAC = ucQosInfo & BITS(0, 3); + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucUapsd)) { + prStaRec->fgIsUapsdSupported = + (ucQosInfoAC) ? true : false; + } else { + prStaRec->fgIsUapsdSupported = false; + } + + ucBmpAC = 0; + + if (ucQosInfoAC & WMM_QOS_INFO_VO_UAPSD) { + ucBmpAC |= BIT(ACI_VO); + } + + if (ucQosInfoAC & WMM_QOS_INFO_VI_UAPSD) { + ucBmpAC |= BIT(ACI_VI); + } + + if (ucQosInfoAC & WMM_QOS_INFO_BE_UAPSD) { + ucBmpAC |= BIT(ACI_BE); + } + + if (ucQosInfoAC & WMM_QOS_INFO_BK_UAPSD) { + ucBmpAC |= BIT(ACI_BK); + } + prStaRec->ucBmpTriggerAC = prStaRec->ucBmpDeliveryAC = + ucBmpAC; + prStaRec->ucUapsdSp = + (ucQosInfo & WMM_QOS_INFO_MAX_SP_LEN_MASK) >> 5; + break; + + default: + /* Other WMM QoS IEs. Ignore any */ + break; + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To process WMM related IEs in ASSOC_RSP + * + * \param[in] prAdapter Adapter pointer + * \param[in] prSwRfb The received frame + * \param[in] pucIE The pointer to the first IE in the frame + * \param[in] u2IELength The total length of IEs in the frame + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void mqmProcessAssocReq(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + IN u8 *pucIE, IN u16 u2IELength) +{ + P_STA_RECORD_T prStaRec; + u16 u2Offset; + u8 *pucIEStart; + u32 u4Flags; + + DEBUGFUNC("mqmProcessAssocReq"); + + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if (prStaRec == NULL) { + return; + } + + prStaRec->fgIsQoS = false; + prStaRec->fgIsWmmSupported = prStaRec->fgIsUapsdSupported = false; + + pucIEStart = pucIE; + + /* If the device does not support QoS or if WMM is not supported by the + * peer, exit. */ + if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) { + return; + } + /* Determine whether QoS is enabled with the association */ + else { + prStaRec->u4Flags = 0; + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_VENDOR: + mqmParseAssocReqWmmIe(prAdapter, pucIE, + prStaRec); + +#if CFG_SUPPORT_MTK_SYNERGY + if (rlmParseCheckMTKOuiIE(prAdapter, pucIE, + &u4Flags)) { + prStaRec->u4Flags = u4Flags; + } +#endif + + break; + + case ELEM_ID_HT_CAP: + /* Some client won't put the WMM IE if client is + * 802.11n */ + if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) { + prStaRec->fgIsQoS = true; + } + break; + + default: + break; + } + } + + DBGLOG(QM, TRACE, "MQM: Assoc_Req Parsing (QoS Enabled=%d)\n", + prStaRec->fgIsQoS); + } +} + +void mqmParseAssocRspWmmIe(IN u8 *pucIE, IN P_STA_RECORD_T prStaRec) +{ + u8 aucWfaOui[] = VENDOR_OUI_WFA; + + if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && + (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) { + switch (WMM_IE_OUI_SUBTYPE(pucIE)) { + case VENDOR_OUI_SUBTYPE_WMM_PARAM: + if (IE_LEN(pucIE) != 24) { + break; /* WMM Info IE with a wrong length */ + } + prStaRec->fgIsQoS = true; + break; + + case VENDOR_OUI_SUBTYPE_WMM_INFO: + if (IE_LEN(pucIE) != 7) { + break; /* WMM Info IE with a wrong length */ + } + prStaRec->fgIsQoS = true; + break; + + default: + /* Other WMM QoS IEs. Ignore any */ + break; + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To process WMM related IEs in ASSOC_RSP + * + * \param[in] prAdapter Adapter pointer + * \param[in] prSwRfb The received frame + * \param[in] pucIE The pointer to the first IE in the frame + * \param[in] u2IELength The total length of IEs in the frame + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void mqmProcessAssocRsp(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + IN u8 *pucIE, IN u16 u2IELength) +{ + P_STA_RECORD_T prStaRec; + u16 u2Offset; + u8 *pucIEStart; + u32 u4Flags; + + DEBUGFUNC("mqmProcessAssocRsp"); + + ASSERT(prSwRfb); + ASSERT(pucIE); + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + ASSERT(prStaRec); + + if (prStaRec == NULL) { + return; + } + + prStaRec->fgIsQoS = false; + + pucIEStart = pucIE; + + DBGLOG(QM, TRACE, "QM: (fgIsWmmSupported=%d, fgSupportQoS=%d)\n", + prStaRec->fgIsWmmSupported, prAdapter->rWifiVar.ucQoS); + + /* If the device does not support QoS or if WMM is not supported by the + * peer, exit. */ + /* if((!prAdapter->rWifiVar.fgSupportQoS) || + * (!prStaRec->fgIsWmmSupported)) */ + if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) { + return; + } + /* Determine whether QoS is enabled with the association */ + else { + prStaRec->u4Flags = 0; + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_VENDOR: + /* Process WMM related IE */ + mqmParseAssocRspWmmIe(pucIE, prStaRec); + +#if CFG_SUPPORT_MTK_SYNERGY + if (rlmParseCheckMTKOuiIE(prAdapter, pucIE, + &u4Flags)) { + prStaRec->u4Flags = u4Flags; + } +#endif + + break; + + case ELEM_ID_HT_CAP: + /* Some AP won't put the WMM IE if client is + * 802.11n */ + if (IE_LEN(pucIE) == (sizeof(IE_HT_CAP_T) - 2)) { + prStaRec->fgIsQoS = true; + } + break; + + default: + break; + } + } + + /* Parse AC parameters and write to HW CRs */ + if ((prStaRec->fgIsQoS) && + (prStaRec->eStaType == STA_TYPE_LEGACY_AP)) { + mqmParseEdcaParameters(prAdapter, prSwRfb, pucIEStart, + u2IELength, true); + } + + DBGLOG(QM, TRACE, "MQM: Assoc_Rsp Parsing (QoS Enabled=%d)\n", + prStaRec->fgIsQoS); + if (prStaRec->fgIsWmmSupported) { + nicQmUpdateWmmParms(prAdapter, prStaRec->ucBssIndex); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void mqmProcessBcn(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + IN u8 *pucIE, IN u16 u2IELength) +{ + P_BSS_INFO_T prBssInfo; + u8 fgNewParameter; + u8 i; + + ASSERT(prAdapter); + ASSERT(prSwRfb); + ASSERT(pucIE); + + DBGLOG(QM, TRACE, "Enter %s\n", __func__); + + fgNewParameter = false; + + for (i = 0; i < BSS_INFO_NUM; i++) { + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, i); + + if (IS_BSS_ACTIVE(prBssInfo)) { + if (prBssInfo->eCurrentOPMode == + OP_MODE_INFRASTRUCTURE && + prBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) { + /* P2P client or AIS infra STA */ + if (EQUAL_MAC_ADDR( + prBssInfo->aucBSSID, + ((P_WLAN_MAC_MGMT_HEADER_T)(prSwRfb + -> + pvHeader)) + ->aucBSSID)) { + fgNewParameter = mqmParseEdcaParameters( + prAdapter, prSwRfb, pucIE, + u2IELength, false); + } + } + + /* Appy new parameters if necessary */ + if (fgNewParameter) { + /* DBGLOG(QM, INFO, ("Update EDCA parameter for + * BSS[%u]\n", prBssInfo->ucBssIndex)); */ + nicQmUpdateWmmParms(prAdapter, + prBssInfo->ucBssIndex); + fgNewParameter = false; + } + } + } +} + +u8 mqmUpdateEdcaParameters(IN P_BSS_INFO_T prBssInfo, IN u8 *pucIE, + IN u8 fgForceOverride) +{ + P_AC_QUE_PARMS_T prAcQueParams; + P_IE_WMM_PARAM_T prIeWmmParam; + ENUM_WMM_ACI_T eAci; + u8 fgNewParameter = false; + + do { + if (IE_LEN(pucIE) != 24) { + break; /* WMM Param IE with a wrong length */ + + } + prIeWmmParam = (P_IE_WMM_PARAM_T)pucIE; + + /* Check the Parameter Set Count to determine whether EDCA + * parameters have been changed */ + if (!fgForceOverride) { + if (mqmCompareEdcaParameters(prIeWmmParam, prBssInfo)) { + fgNewParameter = false; + break; + } + } + + fgNewParameter = true; + /* Update Parameter Set Count */ + prBssInfo->ucWmmParamSetCount = + (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT); + /* Update EDCA parameters */ + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + prAcQueParams = &prBssInfo->arACQueParms[eAci]; + mqmFillAcQueParam(prIeWmmParam, eAci, prAcQueParams); + DBGLOG(QM, + INFO, + "BSS[%u]: eAci[%d] ACM[%d] Aifsn[%d] CWmin/max[%d/%d] TxopLimit[%d] NewParameter[%d]\n", + prBssInfo->ucBssIndex, + eAci, + prAcQueParams->ucIsACMSet, + prAcQueParams->u2Aifsn, + prAcQueParams->u2CWmin, + prAcQueParams->u2CWmax, + prAcQueParams->u2TxopLimit, + fgNewParameter); + } + } while (false); + + return fgNewParameter; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To parse WMM Parameter IE (in BCN or Assoc_Rsp) + * + * \param[in] prAdapter Adapter pointer + * \param[in] prSwRfb The received frame + * \param[in] pucIE The pointer to the first IE in the frame + * \param[in] u2IELength The total length of IEs in the frame + * \param[in] fgForceOverride true: If EDCA parameters are found, always set + * to HW CRs. + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u8 mqmParseEdcaParameters(IN P_ADAPTER_T prAdapter, IN P_SW_RFB_T prSwRfb, + IN u8 *pucIE, IN u16 u2IELength, + IN u8 fgForceOverride) +{ + P_STA_RECORD_T prStaRec; + u16 u2Offset; + u8 aucWfaOui[] = VENDOR_OUI_WFA; + P_BSS_INFO_T prBssInfo; + u8 fgNewParameter = false; + + DEBUGFUNC("mqmParseEdcaParameters"); + + if (!prSwRfb) { + return false; + } + + if (!pucIE) { + return false; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prSwRfb->ucStaRecIdx); + /* ASSERT(prStaRec); */ + + if (prStaRec == NULL) { + return false; + } + + DBGLOG(QM, TRACE, "QM: (fgIsWmmSupported=%d, fgIsQoS=%d)\n", + prStaRec->fgIsWmmSupported, prStaRec->fgIsQoS); + + if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS) || + (!prStaRec->fgIsWmmSupported) || (!prStaRec->fgIsQoS)) { + return false; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + /* Goal: Obtain the EDCA parameters */ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_WMM: + if (!((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && + (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3)))) { + break; + } + + switch (WMM_IE_OUI_SUBTYPE(pucIE)) { + case VENDOR_OUI_SUBTYPE_WMM_PARAM: + fgNewParameter = mqmUpdateEdcaParameters( + prBssInfo, pucIE, fgForceOverride); + break; + + default: + /* Other WMM QoS IEs. Ignore */ + break; + } + + /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... + * (not cared) */ + break; + + default: + break; + } + } + + return fgNewParameter; +} + +u8 mqmCompareEdcaParameters(IN P_IE_WMM_PARAM_T prIeWmmParam, + IN P_BSS_INFO_T prBssInfo) +{ + P_AC_QUE_PARMS_T prAcQueParams; + P_WMM_AC_PARAM_T prWmmAcParams; + ENUM_WMM_ACI_T eAci; + + /* return false; */ + + /* Check Set Count */ + if (prBssInfo->ucWmmParamSetCount != + (prIeWmmParam->ucQosInfo & WMM_QOS_INFO_PARAM_SET_CNT)) { + return false; + } + + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + prAcQueParams = &prBssInfo->arACQueParms[eAci]; + prWmmAcParams = &prIeWmmParam->arAcParam[eAci]; + + /* ACM */ + if (prAcQueParams->ucIsACMSet != + ((prWmmAcParams->ucAciAifsn & WMM_ACIAIFSN_ACM) ? true : + false)) { + return false; + } + + /* AIFSN */ + if (prAcQueParams->u2Aifsn != + (prWmmAcParams->ucAciAifsn & WMM_ACIAIFSN_AIFSN)) { + return false; + } + + /* CW Max */ + if (prAcQueParams->u2CWmax != + (BIT((prWmmAcParams->ucEcw & WMM_ECW_WMAX_MASK) >> + WMM_ECW_WMAX_OFFSET) - + 1)) { + return false; + } + + /* CW Min */ + if (prAcQueParams->u2CWmin != + (BIT(prWmmAcParams->ucEcw & WMM_ECW_WMIN_MASK) - 1)) { + return false; + } + + if (prAcQueParams->u2TxopLimit != prWmmAcParams->u2TxopLimit) { + return false; + } + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is used for parsing EDCA parameters specified in the WMM + * Parameter IE + * + * \param[in] prAdapter Adapter pointer + * \param[in] prIeWmmParam The pointer to the WMM Parameter IE + * \param[in] u4AcOffset The offset specifying the AC queue for parsing + * \param[in] prHwAcParams The parameter structure used to configure the + * HW CRs + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void mqmFillAcQueParam(IN P_IE_WMM_PARAM_T prIeWmmParam, IN u32 u4AcOffset, + OUT P_AC_QUE_PARMS_T prAcQueParams) +{ + P_WMM_AC_PARAM_T prAcParam = &prIeWmmParam->arAcParam[u4AcOffset]; + + prAcQueParams->ucIsACMSet = + (prAcParam->ucAciAifsn & WMM_ACIAIFSN_ACM) ? true : false; + + prAcQueParams->u2Aifsn = (prAcParam->ucAciAifsn & WMM_ACIAIFSN_AIFSN); + + prAcQueParams->u2CWmax = BIT((prAcParam->ucEcw & WMM_ECW_WMAX_MASK) >> + WMM_ECW_WMAX_OFFSET) - + 1; + + prAcQueParams->u2CWmin = BIT(prAcParam->ucEcw & WMM_ECW_WMIN_MASK) - 1; + + WLAN_GET_FIELD_16(&prAcParam->u2TxopLimit, &prAcQueParams->u2TxopLimit); + + prAcQueParams->ucGuradTime = TXM_DEFAULT_FLUSH_QUEUE_GUARD_TIME; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To parse WMM/11n related IEs in scan results (only for AP peers) + * + * \param[in] prAdapter Adapter pointer + * \param[in] prScanResult The scan result which shall be parsed to obtain + * needed info \param[out] prStaRec The obtained info is stored in the + * STA_REC + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void mqmProcessScanResult(IN P_ADAPTER_T prAdapter, + IN P_BSS_DESC_T prScanResult, + OUT P_STA_RECORD_T prStaRec) +{ + u8 *pucIE; + u16 u2IELength; + u16 u2Offset; + u8 aucWfaOui[] = VENDOR_OUI_WFA; + u8 fgIsHtVht; + + DEBUGFUNC("mqmProcessScanResult"); + + ASSERT(prScanResult); + ASSERT(prStaRec); + + /* Reset the flag before parsing */ + prStaRec->fgIsWmmSupported = false; + prStaRec->fgIsUapsdSupported = false; + prStaRec->fgIsQoS = false; + + fgIsHtVht = false; + + if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) { + return; + } + + u2IELength = prScanResult->u2IELength; + pucIE = prScanResult->aucIEBuf; + + /* <1> Determine whether the peer supports WMM/QoS and UAPSDU */ + IE_FOR_EACH(pucIE, u2IELength, u2Offset) { + switch (IE_ID(pucIE)) { + case ELEM_ID_EXTENDED_CAP: +#if CFG_SUPPORT_TDLS + TdlsBssExtCapParse(prStaRec, pucIE); +#endif +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + prStaRec->fgSupportBTM = + !!((*(u32 *)(pucIE + 2)) & + BIT(ELEM_EXT_CAP_BSS_TRANSITION_BIT)); +#endif + break; + + case ELEM_ID_WMM: + if ((WMM_IE_OUI_TYPE(pucIE) == VENDOR_OUI_TYPE_WMM) && + (!kalMemCmp(WMM_IE_OUI(pucIE), aucWfaOui, 3))) { + switch (WMM_IE_OUI_SUBTYPE(pucIE)) { + case VENDOR_OUI_SUBTYPE_WMM_PARAM: + if (IE_LEN(pucIE) != 24) { + break; /* WMM Param IE with a + * wrong length */ + + } + prStaRec->fgIsWmmSupported = true; + prStaRec->fgIsUapsdSupported = + (((((P_IE_WMM_PARAM_T)pucIE) + ->ucQosInfo) & + WMM_QOS_INFO_UAPSD) ? + true : + false); + break; + + case VENDOR_OUI_SUBTYPE_WMM_INFO: + if (IE_LEN(pucIE) != 7) { + break; /* WMM Info IE with a + * wrong length */ + + } + prStaRec->fgIsWmmSupported = true; + prStaRec->fgIsUapsdSupported = + (((((P_IE_WMM_INFO_T)pucIE) + ->ucQosInfo) & + WMM_QOS_INFO_UAPSD) ? + true : + false); + break; + + default: + /* A WMM QoS IE that doesn't matter. + * Ignore it. */ + break; + } + } + /* else: VENDOR_OUI_TYPE_WPA, VENDOR_OUI_TYPE_WPS, ... + * (not cared) */ + + break; + + default: + /* A WMM IE that doesn't matter. Ignore it. */ + break; + } + } + + /* <1> Determine QoS */ + if (prStaRec->ucDesiredPhyTypeSet & + (PHY_TYPE_SET_802_11N | PHY_TYPE_SET_802_11AC)) { + fgIsHtVht = true; + } + + if (fgIsHtVht || prStaRec->fgIsWmmSupported) { + prStaRec->fgIsQoS = true; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Generate the WMM Info IE by Param + * + * \param[in] prAdapter Adapter pointer + * @param prMsduInfo The TX MMPDU + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +u32 mqmFillWmmInfoIE(u8 *pucOutBuf, u8 fgSupportUAPSD, u8 ucBmpDeliveryAC, + u8 ucBmpTriggerAC, u8 ucUapsdSp) +{ + P_IE_WMM_INFO_T prIeWmmInfo; + u32 ucUapsd[] = { WMM_QOS_INFO_BE_UAPSD, WMM_QOS_INFO_BK_UAPSD, + WMM_QOS_INFO_VI_UAPSD, WMM_QOS_INFO_VO_UAPSD }; + u8 aucWfaOui[] = VENDOR_OUI_WFA; + + ASSERT(pucOutBuf); + + prIeWmmInfo = (P_IE_WMM_INFO_T)pucOutBuf; + + prIeWmmInfo->ucId = ELEM_ID_WMM; + prIeWmmInfo->ucLength = ELEM_MAX_LEN_WMM_INFO; + + /* WMM-2.2.1 WMM Information Element Field Values */ + prIeWmmInfo->aucOui[0] = aucWfaOui[0]; + prIeWmmInfo->aucOui[1] = aucWfaOui[1]; + prIeWmmInfo->aucOui[2] = aucWfaOui[2]; + prIeWmmInfo->ucOuiType = VENDOR_OUI_TYPE_WMM; + prIeWmmInfo->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_INFO; + + prIeWmmInfo->ucVersion = VERSION_WMM; + prIeWmmInfo->ucQosInfo = 0; + + /* UAPSD initial queue configurations (delivery and trigger enabled) */ + if (fgSupportUAPSD) { + u8 ucQosInfo = 0; + u8 i; + + /* Static U-APSD setting */ + for (i = ACI_BE; i <= ACI_VO; i++) + if (ucBmpDeliveryAC & ucBmpTriggerAC & BIT(i)) { + ucQosInfo |= (u8)ucUapsd[i]; + } + + if (ucBmpDeliveryAC & ucBmpTriggerAC) { + switch (ucUapsdSp) { + case WMM_MAX_SP_LENGTH_ALL: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_ALL; + break; + + case WMM_MAX_SP_LENGTH_2: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; + break; + + case WMM_MAX_SP_LENGTH_4: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_4; + break; + + case WMM_MAX_SP_LENGTH_6: + ucQosInfo |= WMM_QOS_INFO_MAX_SP_6; + break; + + default: + DBGLOG(QM, INFO, "MQM: Incorrect SP length\n"); + ucQosInfo |= WMM_QOS_INFO_MAX_SP_2; + break; + } + } + prIeWmmInfo->ucQosInfo = ucQosInfo; + } + + /* Increment the total IE length for the Element ID and Length fields. + */ + return IE_SIZE(prIeWmmInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Generate the WMM Info IE + * + * \param[in] prAdapter Adapter pointer + * @param prMsduInfo The TX MMPDU + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +u32 mqmGenerateWmmInfoIEByStaRec(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + P_STA_RECORD_T prStaRec, u8 *pucOutBuf) +{ + P_PM_PROFILE_SETUP_INFO_T prPmProfSetupInfo; + u8 fgSupportUapsd; + + ASSERT(pucOutBuf); + + /* In case QoS is not turned off, exit directly */ + if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) { + return 0; + } + + if (prStaRec == NULL) { + return 0; + } + + if (!prStaRec->fgIsWmmSupported) { + return 0; + } + + prPmProfSetupInfo = &prBssInfo->rPmProfSetupInfo; + + fgSupportUapsd = (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucUapsd) && + prStaRec->fgIsUapsdSupported); + + return mqmFillWmmInfoIE(pucOutBuf, fgSupportUapsd, + prPmProfSetupInfo->ucBmpDeliveryAC, + prPmProfSetupInfo->ucBmpTriggerAC, + prPmProfSetupInfo->ucUapsdSp); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Generate the WMM Info IE + * + * \param[in] prAdapter Adapter pointer + * @param prMsduInfo The TX MMPDU + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void mqmGenerateWmmInfoIE(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + u32 u4Length; + + DEBUGFUNC("mqmGenerateWmmInfoIE"); + + ASSERT(prMsduInfo); + + /* In case QoS is not turned off, exit directly */ + if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) { + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + ASSERT(prStaRec); + + if (prStaRec == NULL) { + return; + } + + if (!prStaRec->fgIsWmmSupported) { + return; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prStaRec->ucBssIndex); + + u4Length = mqmGenerateWmmInfoIEByStaRec( + prAdapter, prBssInfo, prStaRec, + ((u8 *)prMsduInfo->prPacket + prMsduInfo->u2FrameLength)); + + prMsduInfo->u2FrameLength += u4Length; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Generate the WMM Param IE + * + * \param[in] prAdapter Adapter pointer + * @param prMsduInfo The TX MMPDU + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void mqmGenerateWmmParamIE(IN P_ADAPTER_T prAdapter, + IN P_MSDU_INFO_T prMsduInfo) +{ + P_IE_WMM_PARAM_T prIeWmmParam; + + u8 aucWfaOui[] = VENDOR_OUI_WFA; + + u8 aucACI[] = { WMM_ACI_AC_BE, WMM_ACI_AC_BK, WMM_ACI_AC_VI, + WMM_ACI_AC_VO }; + + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + ENUM_WMM_ACI_T eAci; + P_WMM_AC_PARAM_T prAcParam; + + DEBUGFUNC("mqmGenerateWmmParamIE"); + DBGLOG(QM, LOUD, "\n"); + + ASSERT(prMsduInfo); + + /* In case QoS is not turned off, exit directly */ + if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) { + return; + } + + prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); + + if (prStaRec) { + if (!prStaRec->fgIsQoS) { + return; + } + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); + + if (!prBssInfo->fgIsQBSS) { + return; + } + + prIeWmmParam = (P_IE_WMM_PARAM_T)((u8 *)prMsduInfo->prPacket + + prMsduInfo->u2FrameLength); + + prIeWmmParam->ucId = ELEM_ID_WMM; + prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM; + + /* WMM-2.2.1 WMM Information Element Field Values */ + prIeWmmParam->aucOui[0] = aucWfaOui[0]; + prIeWmmParam->aucOui[1] = aucWfaOui[1]; + prIeWmmParam->aucOui[2] = aucWfaOui[2]; + prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM; + prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM; + + prIeWmmParam->ucVersion = VERSION_WMM; + prIeWmmParam->ucQosInfo = + (prBssInfo->ucWmmParamSetCount & WMM_QOS_INFO_PARAM_SET_CNT); + + /* UAPSD initial queue configurations (delivery and trigger enabled) */ + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucUapsd)) { + prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD; + } + + /* EDCA parameter */ + + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + prAcParam = &prIeWmmParam->arAcParam[eAci]; + + /* DBGLOG(QM, LOUD, ("MQM: eAci=%d, ACM = %d, Aifsn = %d, CWmin + * = %d, CWmax = %d, TxopLimit = %d\n", */ + /* eAci,prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet , */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */ + + /* ACI */ + prAcParam->ucAciAifsn = aucACI[eAci]; + /* ACM */ + if (prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet) { + prAcParam->ucAciAifsn |= WMM_ACIAIFSN_ACM; + } + /* AIFSN */ + prAcParam->ucAciAifsn |= + (prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn & + WMM_ACIAIFSN_AIFSN); + + /* ECW Min */ + prAcParam->ucEcw = (prBssInfo->aucCWminLog2ForBcast[eAci] & + WMM_ECW_WMIN_MASK); + /* ECW Max */ + prAcParam->ucEcw |= ((prBssInfo->aucCWmaxLog2ForBcast[eAci] + << WMM_ECW_WMAX_OFFSET) & + WMM_ECW_WMAX_MASK); + + /* Txop limit */ + WLAN_SET_FIELD_16( + &prAcParam->u2TxopLimit, + prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit); + } + + /* Increment the total IE length for the Element ID and Length fields. + */ + prMsduInfo->u2FrameLength += IE_SIZE(prIeWmmParam); +} + +#if CFG_SUPPORT_TDLS +/*----------------------------------------------------------------------------*/ +/*! + * @brief Generate the WMM Param IE + * + * \param[in] prAdapter Adapter pointer + * @param prMsduInfo The TX MMPDU + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +u32 mqmGenerateWmmParamIEByParam(P_ADAPTER_T prAdapter, P_BSS_INFO_T prBssInfo, + u8 *pOutBuf) +{ + P_IE_WMM_PARAM_T prIeWmmParam; + + u8 aucWfaOui[] = VENDOR_OUI_WFA; + + u8 aucACI[] = { WMM_ACI_AC_BE, WMM_ACI_AC_BK, WMM_ACI_AC_VI, + WMM_ACI_AC_VO }; + + P_AC_QUE_PARMS_T prACQueParms; + u8 auCWminLog2ForBcast[WMM_AC_INDEX_NUM] = { 4 /*BE*/, 4 /*BK*/, + 3 /*VO*/, 2 /*VI*/ }; + u8 auCWmaxLog2ForBcast[WMM_AC_INDEX_NUM] = { 10, 10, 4, 3 }; + u8 auAifsForBcast[WMM_AC_INDEX_NUM] = { 3, 7, 2, 2 }; + u8 auTxopForBcast[WMM_AC_INDEX_NUM] = { 0, 0, 94, 47 }; /* If the AP is + * OFDM */ + + ENUM_WMM_ACI_T eAci; + P_WMM_AC_PARAM_T prAcParam; + + DEBUGFUNC("mqmGenerateWmmParamIE"); + DBGLOG(QM, LOUD, "\n"); + + ASSERT(pOutBuf); + + /* In case QoS is not turned off, exit directly */ + if (IS_FEATURE_DISABLED(prAdapter->rWifiVar.ucQoS)) { + return WLAN_STATUS_SUCCESS; + } + + if (!prBssInfo->fgIsQBSS) { + return WLAN_STATUS_SUCCESS; + } + + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.fgTdlsBufferSTASleep)) { + prACQueParms = prBssInfo->arACQueParmsForBcast; + + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + prACQueParms[eAci].ucIsACMSet = false; + prACQueParms[eAci].u2Aifsn = auAifsForBcast[eAci]; + prACQueParms[eAci].u2CWmin = + BIT(auCWminLog2ForBcast[eAci]) - 1; + prACQueParms[eAci].u2CWmax = + BIT(auCWmaxLog2ForBcast[eAci]) - 1; + prACQueParms[eAci].u2TxopLimit = auTxopForBcast[eAci]; + + /* used to send WMM IE */ + prBssInfo->aucCWminLog2ForBcast[eAci] = + auCWminLog2ForBcast[eAci]; + prBssInfo->aucCWmaxLog2ForBcast[eAci] = + auCWmaxLog2ForBcast[eAci]; + + /* DBGLOG(TDLS, INFO, "eAci = %d, ACM = %d, Aifsn = %d, + * CWmin = %d, CWmax = %d, TxopLimit = %d\n", eAci, + * prACQueParms[eAci].ucIsACMSet, + * prACQueParms[eAci].u2Aifsn, + * prACQueParms[eAci].u2CWmin, + * prACQueParms[eAci].u2CWmax, + * prACQueParms[eAci].u2TxopLimit); + */ + } + } + + prIeWmmParam = (P_IE_WMM_PARAM_T)pOutBuf; + + prIeWmmParam->ucId = ELEM_ID_WMM; + prIeWmmParam->ucLength = ELEM_MAX_LEN_WMM_PARAM; + + /* WMM-2.2.1 WMM Information Element Field Values */ + prIeWmmParam->aucOui[0] = aucWfaOui[0]; + prIeWmmParam->aucOui[1] = aucWfaOui[1]; + prIeWmmParam->aucOui[2] = aucWfaOui[2]; + prIeWmmParam->ucOuiType = VENDOR_OUI_TYPE_WMM; + prIeWmmParam->ucOuiSubtype = VENDOR_OUI_SUBTYPE_WMM_PARAM; + + prIeWmmParam->ucVersion = VERSION_WMM; + /* STAUT Buffer STA, also sleeps (optional) + * The STAUT sends a TDLS Setup/Response/Confirm Frame, to STA 2, via + * the AP, with all four AC flags set to 1 in QoS Info Field + */ + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.fgTdlsBufferSTASleep)) { + prIeWmmParam->ucQosInfo = (0x0F & WMM_QOS_INFO_PARAM_SET_CNT); + } else { + prIeWmmParam->ucQosInfo = (prBssInfo->ucWmmParamSetCount & + WMM_QOS_INFO_PARAM_SET_CNT); + } + + /* UAPSD initial queue configurations (delivery and trigger enabled) */ + if (IS_FEATURE_ENABLED(prAdapter->rWifiVar.ucUapsd)) { + prIeWmmParam->ucQosInfo |= WMM_QOS_INFO_UAPSD; + } + + /* EDCA parameter */ + + for (eAci = 0; eAci < WMM_AC_INDEX_NUM; eAci++) { + prAcParam = &prIeWmmParam->arAcParam[eAci]; + + /* DBGLOG(QM, LOUD, ("MQM: eAci=%d, ACM = %d, Aifsn = %d, CWmin + * = %d, CWmax = %d, TxopLimit = %d\n", */ + /* eAci,prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet , */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn, */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmin, */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2CWmax, */ + /* prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit)); */ + + /* ACI */ + prAcParam->ucAciAifsn = aucACI[eAci]; + /* ACM */ + if (prBssInfo->arACQueParmsForBcast[eAci].ucIsACMSet) { + prAcParam->ucAciAifsn |= WMM_ACIAIFSN_ACM; + } + /* AIFSN */ + prAcParam->ucAciAifsn |= + (prBssInfo->arACQueParmsForBcast[eAci].u2Aifsn & + WMM_ACIAIFSN_AIFSN); + + /* ECW Min */ + prAcParam->ucEcw = (prBssInfo->aucCWminLog2ForBcast[eAci] & + WMM_ECW_WMIN_MASK); + /* ECW Max */ + prAcParam->ucEcw |= ((prBssInfo->aucCWmaxLog2ForBcast[eAci] + << WMM_ECW_WMAX_OFFSET) & + WMM_ECW_WMAX_MASK); + + /* Txop limit */ + WLAN_SET_FIELD_16( + &prAcParam->u2TxopLimit, + prBssInfo->arACQueParmsForBcast[eAci].u2TxopLimit); + } + + /* Increment the total IE length for the Element ID and Length fields. + */ + return IE_SIZE(prIeWmmParam); +} + +#endif + +u8 isProbeResponse(IN P_MSDU_INFO_T prMgmtTxMsdu) +{ + P_WLAN_MAC_HEADER_T prWlanHdr = (P_WLAN_MAC_HEADER_T)NULL; + + prWlanHdr = + (P_WLAN_MAC_HEADER_T)((unsigned long)prMgmtTxMsdu->prPacket + + MAC_TX_RESERVED_FIELD); + + return (prWlanHdr->u2FrameCtrl & MASK_FRAME_TYPE) == + MAC_FRAME_PROBE_RSP ? + true : + false; +} + +ENUM_FRAME_ACTION_T +qmGetFrameAction(IN P_ADAPTER_T prAdapter, IN u8 ucBssIndex, IN u8 ucStaRecIdx, + IN P_MSDU_INFO_T prMsduInfo, + IN ENUM_FRAME_TYPE_IN_CMD_Q_T eFrameType, + IN u16 u2FrameLength) +{ + ENUM_FRAME_ACTION_T eFrameAction = FRAME_ACTION_TX_PKT; + P_BSS_INFO_T prBssInfo; + P_STA_RECORD_T prStaRec; + u8 ucTC = nicTxGetFrameResourceType(eFrameType, prMsduInfo); + u16 u2FreeResource = nicTxGetResource(prAdapter, ucTC); + u8 ucReqResource; + P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; + + DEBUGFUNC("qmGetFrameAction"); + + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX(prAdapter, ucStaRecIdx); + + do { + /* 4 <1> Tx, if FORCE_TX is set */ + if (prMsduInfo) { + if (prMsduInfo->ucControlFlag & + MSDU_CONTROL_FLAG_FORCE_TX) { + eFrameAction = FRAME_ACTION_TX_PKT; + break; + } + } + /* 4 <2> Drop, if BSS is inactive */ + if (!IS_BSS_ACTIVE(prBssInfo)) { + DBGLOG(QM, TRACE, + "Drop packets (BSS[%u] is INACTIVE)\n", + prBssInfo->ucBssIndex); + eFrameAction = FRAME_ACTION_DROP_PKT; + break; + } + + /* 4 <3> Queue, if BSS is absent, drop probe response */ + if (prBssInfo->fgIsNetAbsent) { + if (prMsduInfo && isProbeResponse(prMsduInfo)) { + DBGLOG(TX, TRACE, + "Drop probe response (BSS[%u] Absent)\n", + prBssInfo->ucBssIndex); + + eFrameAction = FRAME_ACTION_DROP_PKT; + } else { + DBGLOG(TX, TRACE, + "Queue packets (BSS[%u] Absent)\n", + prBssInfo->ucBssIndex); + eFrameAction = FRAME_ACTION_QUEUE_PKT; + } + break; + } + + /* 4 <4> Check based on StaRec */ + if (prStaRec) { + /* 4 <4.1> Drop, if StaRec is not in use */ + if (!prStaRec->fgIsInUse) { + DBGLOG(QM, TRACE, + "Drop packets (Sta[%u] not in USE)\n", + prStaRec->ucIndex); + eFrameAction = FRAME_ACTION_DROP_PKT; + break; + } + /* 4 <4.2> Sta in PS */ + if (prStaRec->fgIsInPS) { + ucReqResource = 1 + + prWifiVar->ucCmdRsvResource + + QM_MGMT_QUEUED_THRESHOLD; + + /* 4 <4.2.1> Tx, if resource is enough */ + if (u2FreeResource > ucReqResource) { + eFrameAction = FRAME_ACTION_TX_PKT; + break; + } + /* 4 <4.2.2> Queue, if resource is not enough */ + else { + DBGLOG(QM, + INFO, + "Queue packets (Sta[%u] in PS)\n", + prStaRec->ucIndex); + eFrameAction = FRAME_ACTION_QUEUE_PKT; + break; + } + } + } + } while (false); + + /* <5> Resource CHECK! */ + /* <5.1> Reserve resource for CMD & 1X */ + if (eFrameType == FRAME_TYPE_MMPDU) { + ucReqResource = 1 + prWifiVar->ucCmdRsvResource; + + if (u2FreeResource < ucReqResource) { + eFrameAction = FRAME_ACTION_QUEUE_PKT; + DBGLOG(QM, + INFO, + "Queue MGMT (MSDU[0x%p] Req/Rsv/Free[%u/%u/%u])\n", + prMsduInfo, + 1, + prWifiVar->ucCmdRsvResource, + u2FreeResource); + } + + /* <6> Timeout check! */ +#if CFG_ENABLE_PKT_LIFETIME_PROFILE + if ((eFrameAction == FRAME_ACTION_QUEUE_PKT) && prMsduInfo) { + u32 rCurrentTime, rEnqTime; + + GET_CURRENT_SYSTIME(&rCurrentTime); + rEnqTime = prMsduInfo->rPktProfile.rEnqueueTimestamp; + + if (CHECK_FOR_TIMEOUT( + rCurrentTime, rEnqTime, + MSEC_TO_SYSTIME( + prWifiVar->u4MgmtQueueDelayTimeout))) { + eFrameAction = FRAME_ACTION_DROP_PKT; + DBGLOG(QM, INFO, + "Drop MGMT (MSDU[0x%p] timeout[%ums])\n", + prMsduInfo, + prWifiVar->u4MgmtQueueDelayTimeout); + } + } +#endif + } + + return eFrameAction; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Handle BSS change operation Event from the FW + * + * \param[in] prAdapter Adapter pointer + * \param[in] prEvent The event packet from the FW + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmHandleEventBssAbsencePresence(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_EVENT_BSS_ABSENCE_PRESENCE_T prEventBssStatus; + P_BSS_INFO_T prBssInfo; + u8 fgIsNetAbsentOld; + if (u4EventBufLen < sizeof(EVENT_BSS_ABSENCE_PRESENCE_T)) { + DBGLOG(INIT, ERROR, "%s: Invalid event length: %d < %d\n", + __func__, u4EventBufLen, + sizeof(EVENT_BSS_ABSENCE_PRESENCE_T)); + return; + } + prEventBssStatus = (P_EVENT_BSS_ABSENCE_PRESENCE_T)(prEvent->aucBuffer); + if (prEventBssStatus->ucBssIndex > MAX_BSS_INDEX) { + DBGLOG(QM, + ERROR, + "qmHandleEventBssAbsencePresence: (ucBssIndex = %d) out-of-bound\n", + prEventBssStatus->ucBssIndex); + return; + } + prBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prEventBssStatus->ucBssIndex); + fgIsNetAbsentOld = prBssInfo->fgIsNetAbsent; + prBssInfo->fgIsNetAbsent = prEventBssStatus->ucIsAbsent; + prBssInfo->ucBssFreeQuota = prEventBssStatus->ucBssFreeQuota; + + /* DBGLOG(QM, TRACE, ("qmHandleEventBssAbsencePresence (ucNetTypeIdx=%d, + * fgIsAbsent=%d, FreeQuota=%d)\n", */ + /* prEventBssStatus->ucNetTypeIdx, prBssInfo->fgIsNetAbsent, + * prBssInfo->ucBssFreeQuota)); */ + + DBGLOG(QM, INFO, "NAF=%d,%d,%d, CH[%d], BN[%d]\n", + prEventBssStatus->ucBssIndex, prBssInfo->fgIsNetAbsent, + prBssInfo->ucBssFreeQuota, prBssInfo->ucPrimaryChannel, + prBssInfo->eDBDCBand); + + if (!prBssInfo->fgIsNetAbsent) { + /* ToDo:: QM_DBG_CNT_INC */ + QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_27); + } else { + /* ToDo:: QM_DBG_CNT_INC */ + QM_DBG_CNT_INC(&(prAdapter->rQM), QM_DBG_CNT_28); + } + /* From Absent to Present */ + if ((fgIsNetAbsentOld) && (!prBssInfo->fgIsNetAbsent)) { + if (HAL_IS_TX_DIRECT(prAdapter)) { + nicTxDirectStartCheckQTimer(prAdapter); + }else{ + kalSetEvent(prAdapter->prGlueInfo); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Handle STA change PS mode Event from the FW + * + * \param[in] prAdapter Adapter pointer + * \param[in] prEvent The event packet from the FW + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmHandleEventStaChangePsMode(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_EVENT_STA_CHANGE_PS_MODE_T prEventStaChangePsMode; + P_STA_RECORD_T prStaRec; + u8 fgIsInPSOld; + + /* DbgPrint("QM:Event -RxBa\n"); */ + if (u4EventBufLen < sizeof(EVENT_STA_CHANGE_PS_MODE_T)) { + DBGLOG(INIT, ERROR, "%s: Invalid event length: %d < %d\n", + __func__, u4EventBufLen, + sizeof(EVENT_STA_CHANGE_PS_MODE_T)); + return; + } + prEventStaChangePsMode = + (P_EVENT_STA_CHANGE_PS_MODE_T)(prEvent->aucBuffer); + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX( + prAdapter, prEventStaChangePsMode->ucStaRecIdx); + /* ASSERT(prStaRec); */ + + if (prStaRec) { + fgIsInPSOld = prStaRec->fgIsInPS; + prStaRec->fgIsInPS = prEventStaChangePsMode->ucIsInPs; + + qmUpdateFreeQuota(prAdapter, prStaRec, + prEventStaChangePsMode->ucUpdateMode, + prEventStaChangePsMode->ucFreeQuota); + + /* DBGLOG(QM, TRACE, ("qmHandleEventStaChangePsMode + * (ucStaRecIdx=%d, fgIsInPs=%d)\n", */ + /* prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS)); */ + + DBGLOG(QM, INFO, "PS=%d,%d\n", + prEventStaChangePsMode->ucStaRecIdx, prStaRec->fgIsInPS); + + /* From PS to Awake */ + if ((fgIsInPSOld) && (!prStaRec->fgIsInPS)) { + if (HAL_IS_TX_DIRECT(prAdapter)) { + nicTxDirectStartCheckQTimer(prAdapter); + }else{ + kalSetEvent(prAdapter->prGlueInfo); + } + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Update STA free quota Event from FW + * + * \param[in] prAdapter Adapter pointer + * \param[in] prEvent The event packet from the FW + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmHandleEventStaUpdateFreeQuota(IN P_ADAPTER_T prAdapter, + IN P_WIFI_EVENT_T prEvent, + IN u32 u4EventBufLen) +{ + P_EVENT_STA_UPDATE_FREE_QUOTA_T prEventStaUpdateFreeQuota; + P_STA_RECORD_T prStaRec; + if (u4EventBufLen < sizeof(EVENT_STA_UPDATE_FREE_QUOTA_T)) { + DBGLOG(INIT, ERROR, "%s: Invalid event length: %d < %d\n", + __func__, u4EventBufLen, + sizeof(EVENT_STA_UPDATE_FREE_QUOTA_T)); + return; + } + prEventStaUpdateFreeQuota = + (P_EVENT_STA_UPDATE_FREE_QUOTA_T)(prEvent->aucBuffer); + prStaRec = QM_GET_STA_REC_PTR_FROM_INDEX( + prAdapter, prEventStaUpdateFreeQuota->ucStaRecIdx); + /* 2013/08/30 + * Station Record possible been freed. + */ + /* ASSERT(prStaRec); */ + + if (prStaRec) { + if (prStaRec->fgIsInPS) { + qmUpdateFreeQuota( + prAdapter, prStaRec, + prEventStaUpdateFreeQuota->ucUpdateMode, + prEventStaUpdateFreeQuota->ucFreeQuota); + + if (HAL_IS_TX_DIRECT(prAdapter)) { + nicTxDirectStartCheckQTimer(prAdapter); + }else{ + kalSetEvent(prAdapter->prGlueInfo); + } + } + + DBGLOG(QM, TRACE, "UFQ=%d,%d,%d\n", + prEventStaUpdateFreeQuota->ucStaRecIdx, + prEventStaUpdateFreeQuota->ucUpdateMode, + prEventStaUpdateFreeQuota->ucFreeQuota); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Update STA free quota + * + * \param[in] prStaRec the STA + * \param[in] ucUpdateMode the method to update free quota + * \param[in] ucFreeQuota the value for update + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void qmUpdateFreeQuota(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec, + IN u8 ucUpdateMode, IN u8 ucFreeQuota) +{ + u8 ucFreeQuotaForNonDelivery; + u8 ucFreeQuotaForDelivery; + + ASSERT(prStaRec); + DBGLOG(QM, LOUD, + "qmUpdateFreeQuota orig ucFreeQuota=%d Mode %u New %u\n", + prStaRec->ucFreeQuota, ucUpdateMode, ucFreeQuota); + + if (!prStaRec->fgIsInPS) { + return; + } + + switch (ucUpdateMode) { + case FREE_QUOTA_UPDATE_MODE_INIT: + case FREE_QUOTA_UPDATE_MODE_OVERWRITE: + prStaRec->ucFreeQuota = ucFreeQuota; + break; + + case FREE_QUOTA_UPDATE_MODE_INCREASE: + prStaRec->ucFreeQuota += ucFreeQuota; + break; + + case FREE_QUOTA_UPDATE_MODE_DECREASE: + prStaRec->ucFreeQuota -= ucFreeQuota; + break; + + default: + ASSERT(0); + } + + DBGLOG(QM, LOUD, "qmUpdateFreeQuota new ucFreeQuota=%d)\n", + prStaRec->ucFreeQuota); + + ucFreeQuota = prStaRec->ucFreeQuota; + + ucFreeQuotaForNonDelivery = 0; + ucFreeQuotaForDelivery = 0; + + if (ucFreeQuota > 0) { + if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported + /* && prAdapter->rWifiVar.fgSupportQoS */ + /* && prAdapter->rWifiVar.fgSupportUAPSD */) { + /* XXX We should assign quota to + * aucFreeQuotaPerQueue[NUM_OF_PER_STA_TX_QUEUES] */ + + if (prStaRec->ucFreeQuotaForNonDelivery > 0 && + prStaRec->ucFreeQuotaForDelivery > 0) { + ucFreeQuotaForNonDelivery = ucFreeQuota >> 1; + ucFreeQuotaForDelivery = + ucFreeQuota - ucFreeQuotaForNonDelivery; + } else if (prStaRec->ucFreeQuotaForNonDelivery == 0 && + prStaRec->ucFreeQuotaForDelivery == 0) { + ucFreeQuotaForNonDelivery = ucFreeQuota >> 1; + ucFreeQuotaForDelivery = + ucFreeQuota - ucFreeQuotaForNonDelivery; + } else if (prStaRec->ucFreeQuotaForNonDelivery > 0) { + /* NonDelivery is not busy */ + if (ucFreeQuota >= 3) { + ucFreeQuotaForNonDelivery = 2; + ucFreeQuotaForDelivery = + ucFreeQuota - + ucFreeQuotaForNonDelivery; + } else { + ucFreeQuotaForDelivery = ucFreeQuota; + ucFreeQuotaForNonDelivery = 0; + } + } else if (prStaRec->ucFreeQuotaForDelivery > 0) { + /* Delivery is not busy */ + if (ucFreeQuota >= 3) { + ucFreeQuotaForDelivery = 2; + ucFreeQuotaForNonDelivery = + ucFreeQuota - + ucFreeQuotaForDelivery; + } else { + ucFreeQuotaForNonDelivery = ucFreeQuota; + ucFreeQuotaForDelivery = 0; + } + } + } else { + /* !prStaRec->fgIsUapsdSupported */ + ucFreeQuotaForNonDelivery = ucFreeQuota; + ucFreeQuotaForDelivery = 0; + } + } + /* ucFreeQuota > 0 */ + prStaRec->ucFreeQuotaForDelivery = ucFreeQuotaForDelivery; + prStaRec->ucFreeQuotaForNonDelivery = ucFreeQuotaForNonDelivery; + + DBGLOG(QM, LOUD, + "new QuotaForDelivery = %d QuotaForNonDelivery = %d\n", + prStaRec->ucFreeQuotaForDelivery, + prStaRec->ucFreeQuotaForNonDelivery); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Return the reorder queued RX packets + * + * \param[in] (none) + * + * \return The number of queued RX packets + */ +/*----------------------------------------------------------------------------*/ +u32 qmGetRxReorderQueuedBufferCount(IN P_ADAPTER_T prAdapter) +{ + u32 i, u4Total; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + u4Total = 0; + /* XXX The summation may impact the performance */ + for (i = 0; i < CFG_NUM_OF_RX_BA_AGREEMENTS; i++) + u4Total += prQM->arRxBaTable[i].rReOrderQue.u4NumElem; + ASSERT(u4Total <= (CFG_NUM_OF_QM_RX_PKT_NUM * 2)); + return u4Total; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Dump current queue status + * + * \param[in] (none) + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +u32 qmDumpQueueStatus(IN P_ADAPTER_T prAdapter, IN u8 *pucBuf, IN u32 u4Max) +{ + P_TX_CTRL_T prTxCtrl; + P_QUE_MGT_T prQM; + P_GLUE_INFO_T prGlueInfo; + u32 i, u4TotalBufferCount, u4TotalPageCount; + u32 u4CurBufferCount, u4CurPageCount; + u32 u4Len = 0; + u32 u4TotalGlobalQueLen = 0; + + DEBUGFUNC(("%s", __func__)); + + prTxCtrl = &prAdapter->rTxCtrl; + prQM = &prAdapter->rQM; + prGlueInfo = prAdapter->prGlueInfo; + u4TotalBufferCount = 0; + u4TotalPageCount = 0; + u4CurBufferCount = 0; + u4CurPageCount = 0; + + LOGBUF(pucBuf, u4Max, u4Len, "\n"); + LOGBUF(pucBuf, u4Max, u4Len, "------<Dump QUEUE Status>------\n"); + + for (i = TC0_INDEX; i < TC_NUM; i++) { + LOGBUF(pucBuf, + u4Max, + u4Len, + "TC%u ResCount: Max[%02u/%03u] Free[%02u/%03u] PreUsed[%03u]\n", + i, + prTxCtrl->rTc.au4MaxNumOfBuffer[i], + prTxCtrl->rTc.au4MaxNumOfPage[i], + prTxCtrl->rTc.au4FreeBufferCount[i], + prTxCtrl->rTc.au4FreePageCount[i], + prTxCtrl->rTc.au4PreUsedPageCount[i]); + + u4TotalBufferCount += prTxCtrl->rTc.au4MaxNumOfBuffer[i]; + u4TotalPageCount += prTxCtrl->rTc.au4MaxNumOfPage[i]; + u4CurBufferCount += prTxCtrl->rTc.au4FreeBufferCount[i]; + u4CurPageCount += prTxCtrl->rTc.au4FreePageCount[i]; + } + + LOGBUF(pucBuf, u4Max, u4Len, + "ToT ResCount: Max[%02u/%03u] Free[%02u/%03u]\n", + u4TotalBufferCount, u4TotalPageCount, u4CurBufferCount, + u4CurPageCount); + + LOGBUF(pucBuf, u4Max, u4Len, "---------------------------------\n"); + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL + for (i = TC0_INDEX; i < TC_NUM; i++) { + LOGBUF(pucBuf, + u4Max, + u4Len, + "TC%u AvgQLen[%04u] minRsv[%02u] CurTcRes[%02u] GrtdTcRes[%02u]\n", + i, + QM_GET_TX_QUEUE_LEN(prAdapter, i), + prQM->au4MinReservedTcResource[i], + prQM->au4CurrentTcResource[i], + prQM->au4GuaranteedTcResource[i]); + } + + LOGBUF(pucBuf, u4Max, u4Len, "Resource Residual[%u] ExtraRsv[%u]\n", + prQM->u4ResidualTcResource, prQM->u4ExtraReservedTcResource); + LOGBUF(pucBuf, u4Max, u4Len, + "QueLenMovingAvg[%u] Time2AdjResource[%u] Time2UpdateQLen[%u]\n", + prQM->u4QueLenMovingAverage, prQM->u4TimeToAdjustTcResource, + prQM->u4TimeToUpdateQueLen); +#endif + + DBGLOG(SW4, INFO, "---------------------------------\n"); + +#if QM_FORWARDING_FAIRNESS + for (i = 0; i < NUM_OF_PER_STA_TX_QUEUES; i++) { + LOGBUF(pucBuf, u4Max, u4Len, + "TC%u HeadSta[%u] ResourceUsedCount[%u]\n", i, + prQM->au4HeadStaRecIndex[i], + prQM->au4ResourceUsedCount[i]); + } +#endif + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + for (i = 0; i < NUM_OF_PER_TYPE_TX_QUEUES; i++) { + LOGBUF(pucBuf, u4Max, u4Len, "Global TxQueue %d Len[%u]\n", i, + prQM->arTxQueue[i].u4NumElem); + u4TotalGlobalQueLen += prQM->arTxQueue[i].u4NumElem; + } +#else + u4TotalGlobalQueLen = prQM->arTxQueue[0].u4NumElem; +#endif + + LOGBUF(pucBuf, u4Max, u4Len, "BMC or unknown TxQueue Len[%u]\n", + u4TotalGlobalQueLen); + LOGBUF(pucBuf, u4Max, u4Len, + "Pending QLen Normal[%u] Sec[%u] Cmd[%u]\n", + GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum), + GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum), + GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingCmdNum)); + + for (i = 0; i < HW_BSSID_NUM; i++) { + LOGBUF(pucBuf, u4Max, u4Len, + "Pending BSS[%u] QLen[%u:%u:%u:%u]\n", i, + prGlueInfo->ai4TxPendingFrameNumPerQueue[i][0], + prGlueInfo->ai4TxPendingFrameNumPerQueue[i][1], + prGlueInfo->ai4TxPendingFrameNumPerQueue[i][2], + prGlueInfo->ai4TxPendingFrameNumPerQueue[i][3]); + } + + LOGBUF(pucBuf, u4Max, u4Len, "Pending FWD CNT[%d]\n", + prTxCtrl->i4PendingFwdFrameCount); + LOGBUF(pucBuf, u4Max, u4Len, "Pending MGMT CNT[%d]\n", + prTxCtrl->i4TxMgmtPendingNum); + + LOGBUF(pucBuf, u4Max, u4Len, "---------------------------------\n"); + + LOGBUF(pucBuf, u4Max, u4Len, "Total RFB[%u]\n", CFG_RX_MAX_PKT_NUM); + LOGBUF(pucBuf, u4Max, u4Len, "rFreeSwRfbList[%u]\n", + prAdapter->rRxCtrl.rFreeSwRfbList.u4NumElem); + LOGBUF(pucBuf, u4Max, u4Len, "rReceivedRfbList[%u]\n", + prAdapter->rRxCtrl.rReceivedRfbList.u4NumElem); + LOGBUF(pucBuf, u4Max, u4Len, "rIndicatedRfbList[%u]\n", + prAdapter->rRxCtrl.rIndicatedRfbList.u4NumElem); + LOGBUF(pucBuf, u4Max, u4Len, "ucNumIndPacket[%u]\n", + prAdapter->rRxCtrl.ucNumIndPacket); + LOGBUF(pucBuf, u4Max, u4Len, "ucNumRetainedPacket[%u]\n", + prAdapter->rRxCtrl.ucNumRetainedPacket); + + LOGBUF(pucBuf, u4Max, u4Len, "---------------------------------\n"); + LOGBUF(pucBuf, u4Max, u4Len, "CMD: Free[%u/%u] Cmd[%u] ToTx[%u]\n", + prAdapter->rFreeCmdList.u4NumElem, CFG_TX_MAX_CMD_PKT_NUM, + prAdapter->rPendingCmdQueue.u4NumElem, + prGlueInfo->rCmdQueue.u4NumElem); + LOGBUF(pucBuf, u4Max, u4Len, "MSDU: Free[%u/%u] Pending[%u] Done[%u]\n", + prAdapter->rTxCtrl.rFreeMsduInfoList.u4NumElem, + CFG_TX_MAX_PKT_NUM, + prAdapter->rTxCtrl.rTxMgmtTxingQueue.u4NumElem, + prAdapter->rTxDataDoneQueue.u4NumElem); + + LOGBUF(pucBuf, u4Max, u4Len, "---------------------------------\n"); + + return u4Len; +} + +#if QM_ADAPTIVE_TC_RESOURCE_CTRL +void qmResetTcControlResource(IN P_ADAPTER_T prAdapter) +{ + u32 u4Idx; + u32 u4TotalMinReservedTcResource = 0; + u32 u4TotalTcResource = 0; + u32 u4TotalGurantedTcResource = 0; + P_QUE_MGT_T prQM = &prAdapter->rQM; + + /* Initialize TC resource control variables */ + for (u4Idx = 0; u4Idx < TC_NUM; u4Idx++) + prQM->au4AverageQueLen[u4Idx] = 0; + + ASSERT(prQM->u4TimeToAdjustTcResource && prQM->u4TimeToUpdateQueLen); + + for (u4Idx = 0; u4Idx < TC_NUM; u4Idx++) { + prQM->au4CurrentTcResource[u4Idx] = + prAdapter->rTxCtrl.rTc.au4MaxNumOfBuffer[u4Idx]; + + if (u4Idx != TC4_INDEX) { + u4TotalTcResource += prQM->au4CurrentTcResource[u4Idx]; + u4TotalGurantedTcResource += + prQM->au4GuaranteedTcResource[u4Idx]; + u4TotalMinReservedTcResource += + prQM->au4MinReservedTcResource[u4Idx]; + } + } + + /* Sanity Check */ + if (u4TotalMinReservedTcResource > u4TotalTcResource) { + kalMemZero(prQM->au4MinReservedTcResource, + sizeof(prQM->au4MinReservedTcResource)); + } + + if (u4TotalGurantedTcResource > u4TotalTcResource) { + kalMemZero(prQM->au4GuaranteedTcResource, + sizeof(prQM->au4GuaranteedTcResource)); + } + + u4TotalGurantedTcResource = 0; + + /* Initialize Residual TC resource */ + for (u4Idx = 0; u4Idx < TC_NUM; u4Idx++) { + if (prQM->au4GuaranteedTcResource[u4Idx] < + prQM->au4MinReservedTcResource[u4Idx]) { + prQM->au4GuaranteedTcResource[u4Idx] = + prQM->au4MinReservedTcResource[u4Idx]; + } + + if (u4Idx != TC4_INDEX) { + u4TotalGurantedTcResource += + prQM->au4GuaranteedTcResource[u4Idx]; + } + } + + prQM->u4ResidualTcResource = + u4TotalTcResource - u4TotalGurantedTcResource; +} +#endif + +#if CFG_SUPPORT_REPLAY_DETECTION +/* To change PN number to UINT64 */ +#define CCMPTSCPNNUM 6 +u8 qmRxPNtoU64(u8 *pucPN, u8 uPNNum, u64 *pu8Rets) +{ + u8 ucCount = 0; + u64 u8Data = 0; + u64 ucTmp = 0; + + if (!pu8Rets) { + DBGLOG(QM, ERROR, "Please input valid pu8Rets\n"); + return false; + } + + if (uPNNum > CCMPTSCPNNUM) { + DBGLOG(QM, ERROR, "Please input valid uPNNum:%d\n", uPNNum); + return false; + } + + *pu8Rets = 0; + for (; ucCount < uPNNum; ucCount++) { + ucTmp = pucPN[ucCount]; + u8Data = ucTmp << 8 * ucCount; + *pu8Rets += u8Data; + } + return true; +} + +/* To check PN/TSC between RxStatus and local record. return true if PNS is not + * bigger than PNT */ +u8 qmRxDetectReplay(u8 *pucPNS, u8 *pucPNT) +{ + u64 u8RxNum = 0; + u64 u8LocalRec = 0; + + if (!pucPNS || !pucPNT) { + DBGLOG(QM, ERROR, "Please input valid PNS:%p and PNT:%p\n", + pucPNS, pucPNT); + return true; + } + + if (!qmRxPNtoU64(pucPNS, CCMPTSCPNNUM, &u8RxNum) || + !qmRxPNtoU64(pucPNT, CCMPTSCPNNUM, &u8LocalRec)) { + DBGLOG(QM, ERROR, "PN2U64 failed\n"); + return true; + } + /* PN overflow ? */ + + return !(u8RxNum > u8LocalRec); +} + +/* TO filter broadcast and multicast data packet replay issue. */ +u8 qmHandleRxReplay(P_ADAPTER_T prAdapter, P_SW_RFB_T prSwRfb) +{ + u8 *pucPN = NULL; + u8 ucKeyID = 0; /* 0~4 */ + u8 ucSecMode = CIPHER_SUITE_NONE; /* CIPHER_SUITE_NONE~CIPHER_SUITE_GCMP + */ + P_GLUE_INFO_T prGlueInfo = NULL; + P_GL_WPA_INFO_T prWpaInfo = NULL; + struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL; + P_HW_MAC_RX_DESC_T prRxStatus = NULL; + u8 ucBssIndex = 0; + P_BSS_INFO_T prBssInfo = NULL; + u8 ucCheckZeroPN; + u8 i; + + if (!prAdapter) { + return true; + } + + if (prSwRfb->u2PacketLen <= ETHER_HEADER_LEN) { + return true; + } + + ucBssIndex = prSwRfb->prStaRec->ucBssIndex; + prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); + + ASSERT(prBssInfo); + + prGlueInfo = prAdapter->prGlueInfo; + prWpaInfo = &prGlueInfo->rWpaInfo; + + if (!(prSwRfb->ucGroupVLD & BIT(RX_GROUP_VLD_1))) { + return false; + } + + /* BMC only need check CCMP and TKIP Cipher suite */ + prRxStatus = prSwRfb->prRxStatus; + ucSecMode = HAL_RX_STATUS_GET_SEC_MODE(prRxStatus); + if (ucSecMode != CIPHER_SUITE_CCMP && ucSecMode != CIPHER_SUITE_TKIP) { + DBGLOG(QM, + TRACE, + "SecMode: %d and CipherGroup: %d, no need check replay\n", + ucSecMode, + prWpaInfo->u4CipherGroup); + return false; + } + + ucKeyID = HAL_RX_STATUS_GET_KEY_ID(prRxStatus); + if (ucKeyID >= MAX_KEY_NUM) { + DBGLOG(QM, ERROR, "KeyID: %d error\n", ucKeyID); + return true; + } + + prDetRplyInfo = &prBssInfo->rDetRplyInfo; + + pucPN = prSwRfb->prRxStatusGroup1->aucPN; + DBGLOG(QM, + TRACE, + "BC packet 0x%x:0x%x:0x%x:0x%x:0x%x:0x%x--0x%x:0x%x:0x%x:0x%x:0x%x:0x%x\n", + pucPN[0], + pucPN[1], + pucPN[2], + pucPN[3], + pucPN[4], + pucPN[5], + prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[0], + prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[1], + prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[2], + prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[3], + prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[4], + prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN[5]); + + if (prDetRplyInfo->fgKeyRscFresh == true) { + /* PN non-fresh setting */ + prDetRplyInfo->fgKeyRscFresh = false; + ucCheckZeroPN = 0; + + for (i = 0; i < 8; i++) + if (prSwRfb->prRxStatusGroup1->aucPN[i] == 0x0) { + ucCheckZeroPN++; + } + + /* for AP start PN from 0, bypass PN check and update */ + if (ucCheckZeroPN == 8) { + DBGLOG(QM, WARN, "Fresh BC_PN with AP PN=0\n"); + return false; + } + } + + if (qmRxDetectReplay(pucPN, + prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN)) { + DBGLOG(QM, WARN, "Drop BC replay packet!\n"); + return true; + } + + HAL_RX_STATUS_GET_PN(prSwRfb->prRxStatusGroup1, + prDetRplyInfo->arReplayPNInfo[ucKeyID].auPN); + + return false; +} + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT +void qmFuncChangeBmcTcIdx(u8 ucAc) +{ + u8 i; + for (i = 0; i < (MAX_BSSID_NUM); i++) { + arNetwork2TcResource[i][NET_TC_BMC_INDEX] = ucAc; + DBGLOG(QM, STATE, "Change WmmSet%d BMC TC Index to: %d\n", i, + arNetwork2TcResource[i][NET_TC_BMC_INDEX]); + } + return; +} + +u8 qmFuncGetBmcTcIdx(u8 ucWmmIdx) +{ + return arNetwork2TcResource[ucWmmIdx][NET_TC_BMC_INDEX]; +} +#endif +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_ate_agent.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_ate_agent.c new file mode 100644 index 00000000000000..ad3da39cebfecd --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_ate_agent.c @@ -0,0 +1,2854 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ +/* + * Module Name: + * gl_ate_agent.c + */ +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#if CFG_SUPPORT_QA_TOOL +#include "gl_wext.h" +#include "gl_cfg80211.h" +#include "gl_ate_agent.h" +#include "gl_hook_api.h" +#include "gl_qa_agent.h" + +#include <uapi/linux/nl80211.h> + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#if CFG_SUPPORT_TX_BF +PFMU_PROFILE_TAG1 g_rPfmuTag1; +PFMU_PROFILE_TAG2 g_rPfmuTag2; +PFMU_DATA g_rPfmuData; +#endif + +typedef struct _ATE_PRIV_CMD { + u8 *name; + int (*set_proc)(struct net_device *prNetDev, u8 *prInBuf); +} ATE_PRIV_CMD, *P_ATE_PRIV_CMD; + +ATE_PRIV_CMD rAtePrivCmdTable[] = { + { "ResetCounter", Set_ResetStatCounter_Proc }, + { "ATE", SetATE }, + { "ATEDA", SetATEDa }, + { "ATESA", SetATESa }, + { "ATECHANNEL", SetATEChannel }, + { "ATETXPOW0", SetATETxPower0 }, + { "ATETXGI", SetATETxGi }, + { "ATETXBW", SetATETxBw }, + { "ATETXLEN", SetATETxLength }, + { "ATETXCNT", SetATETxCount }, + { "ATETXMCS", SetATETxMcs }, + { "ATETXMODE", SetATETxMode }, + { "ATEIPG", SetATEIpg }, +#if CFG_SUPPORT_TX_BF + { "TxBfProfileTagHelp", Set_TxBfProfileTag_Help }, + { "TxBfProfileTagInValid", Set_TxBfProfileTag_InValid }, + { "TxBfProfileTagPfmuIdx", Set_TxBfProfileTag_PfmuIdx }, + { "TxBfProfileTagBfType", Set_TxBfProfileTag_BfType }, + { "TxBfProfileTagBw", Set_TxBfProfileTag_DBW }, + { "TxBfProfileTagSuMu", Set_TxBfProfileTag_SuMu }, + { "TxBfProfileTagMemAlloc", Set_TxBfProfileTag_Mem }, + { "TxBfProfileTagMatrix", Set_TxBfProfileTag_Matrix }, + { "TxBfProfileTagSnr", Set_TxBfProfileTag_SNR }, + { "TxBfProfileTagSmtAnt", Set_TxBfProfileTag_SmartAnt }, + { "TxBfProfileTagSeIdx", Set_TxBfProfileTag_SeIdx }, + { "TxBfProfileTagRmsdThrd", Set_TxBfProfileTag_RmsdThrd }, + { "TxBfProfileTagMcsThrd", Set_TxBfProfileTag_McsThrd }, + { "TxBfProfileTagTimeOut", Set_TxBfProfileTag_TimeOut }, + { "TxBfProfileTagDesiredBw", Set_TxBfProfileTag_DesiredBW }, + { "TxBfProfileTagDesiredNc", Set_TxBfProfileTag_DesiredNc }, + { "TxBfProfileTagDesiredNr", Set_TxBfProfileTag_DesiredNr }, + { "TxBfProfileTagRead", Set_TxBfProfileTagRead }, + { "TxBfProfileTagWrite", Set_TxBfProfileTagWrite }, + { "TxBfProfileDataRead", Set_TxBfProfileDataRead }, + { "TxBfProfileDataWrite", Set_TxBfProfileDataWrite }, + { "TxBfProfilePnRead", Set_TxBfProfilePnRead }, + { "TxBfProfilePnWrite", Set_TxBfProfilePnWrite }, + { "TxBfSounding", Set_Trigger_Sounding_Proc }, + { "TxBfSoundingStop", Set_Stop_Sounding_Proc }, + { "TxBfTxApply", Set_TxBfTxApply }, + { "TxBfManualAssoc", Set_TxBfManualAssoc }, + { "TxBfPfmuMemAlloc", Set_TxBfPfmuMemAlloc }, + { "TxBfPfmuMemRelease", Set_TxBfPfmuMemRelease }, + { "StaRecCmmUpdate", Set_StaRecCmmUpdate }, + { "StaRecBfUpdate", Set_StaRecBfUpdate }, + { "DevInfoUpdate", Set_DevInfoUpdate }, + { "BssInfoUpdate", Set_BssInfoUpdate }, +#if CFG_SUPPORT_MU_MIMO + { "MUGetInitMCS", Set_MUGetInitMCS }, + { "MUCalInitMCS", Set_MUCalInitMCS }, + { "MUCalLQ", Set_MUCalLQ }, + { "MUGetLQ", Set_MUGetLQ }, + { "MUSetSNROffset", Set_MUSetSNROffset }, + { "MUSetZeroNss", Set_MUSetZeroNss }, + { "MUSetSpeedUpLQ", Set_MUSetSpeedUpLQ }, + { "MUSetMUTable", Set_MUSetMUTable }, + { "MUSetGroup", Set_MUSetGroup }, + { "MUGetQD", Set_MUGetQD }, + { "MUSetEnable", Set_MUSetEnable }, + { "MUSetGID_UP", Set_MUSetGID_UP }, + { "MUTriggerTx", Set_MUTriggerTx }, +#endif +#endif + + { "WriteEfuse", WriteEfuse }, + { "TxPower", SetTxTargetPower }, +#if (CFG_SUPPORT_DFS_MASTER == 1) + { "RDDReport", SetRddReport }, + { "ByPassCac", SetByPassCac }, + { "RadarDetectMode", SetRadarDetectMode }, +#endif + + { + NULL, + } +}; + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Reset RX Statistic Counters. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +int Set_ResetStatCounter_Proc(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 i4Status; + + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv Set_ResetStatCounter_Proc\n"); + + i4Status = MT_ATEResetTXRXCounter(prNetDev); + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set Start Test Mode / Stop Test Mode / + * Start TX / Stop TX / Start RX / Stop RX. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetATE(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 i4Status; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv SetATE\n"); + + if (!strcmp(prInBuf, "ATESTART")) { + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv SetATE - ATESTART\n"); + i4Status = MT_ATEStart(prNetDev, prInBuf); + } else if (!strcmp(prInBuf, "ICAPSTART")) { + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv SetATE - ICAPSTART\n"); + i4Status = MT_ICAPStart(prNetDev, prInBuf); + } else if (!strcmp(prInBuf, "ATESTOP")) { + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv SetATE - ATESTOP\n"); + i4Status = MT_ATEStop(prNetDev, prInBuf); + } else if (!strcmp(prInBuf, "TXFRAME")) { + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv SetATE - TXFRAME\n"); + i4Status = MT_ATEStartTX(prNetDev, prInBuf); + } else if (!strcmp(prInBuf, "TXSTOP")) { + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv SetATE - TXSTOP\n"); + i4Status = MT_ATEStopTX(prNetDev, prInBuf); + } else if (!strcmp(prInBuf, "RXFRAME")) { + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv SetATE - RXFRAME\n"); + i4Status = MT_ATEStartRX(prNetDev, prInBuf); + } else if (!strcmp(prInBuf, "RXSTOP")) { + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv SetATE - RXSTOP\n"); + i4Status = MT_ATEStopRX(prNetDev, prInBuf); + } else { + return -EINVAL; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set TX Destination Address. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetATEDa(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 i4Status = 0; + u32 addr[MAC_ADDR_LEN]; + u8 addr2[MAC_ADDR_LEN]; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 : ATE_AGENT iwpriv SetDa\n"); + /* xx:xx:xx:xx:xx:xx */ + rv = sscanf(prInBuf, "%x:%x:%x:%x:%x:%x", &addr[0], &addr[1], &addr[2], + &addr[3], &addr[4], &addr[5]); + if (rv == 6) { + DBGLOG(RFTEST, + ERROR, + "MT6632 : ATE_AGENT iwpriv SetATEDa Sa:%02x:%02x:%02x:%02x:%02x:%02x\n", + addr[0], + addr[1], + addr[2], + addr[3], + addr[4], + addr[5]); + + addr2[0] = (u8)addr[0]; + addr2[1] = (u8)addr[1]; + addr2[2] = (u8)addr[2]; + addr2[3] = (u8)addr[3]; + addr2[4] = (u8)addr[4]; + addr2[5] = (u8)addr[5]; + + i4Status = MT_ATESetMACAddress( + prNetDev, RF_AT_FUNCID_SET_MAC_ADDRESS, addr2); + } else { + return -EINVAL; + } + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set TX Source Address. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetATESa(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 i4Status = 0; + u32 addr[MAC_ADDR_LEN]; + u8 addr2[MAC_ADDR_LEN]; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 : ATE_AGENT iwpriv SetSa\n"); + /* xx:xx:xx:xx:xx:xx */ + rv = sscanf(prInBuf, "%x:%x:%x:%x:%x:%x", &addr[0], &addr[1], &addr[2], + &addr[3], &addr[4], &addr[5]); + if (rv == 6) { + DBGLOG(RFTEST, + ERROR, + "MT6632 : ATE_AGENT iwpriv SetATESa Sa:%02x:%02x:%02x:%02x:%02x:%02x\n", + addr[0], + addr[1], + addr[2], + addr[3], + addr[4], + addr[5]); + + addr2[0] = (u8)addr[0]; + addr2[1] = (u8)addr[1]; + addr2[2] = (u8)addr[2]; + addr2[3] = (u8)addr[3]; + addr2[4] = (u8)addr[4]; + addr2[5] = (u8)addr[5]; + + i4Status = MT_ATESetMACAddress(prNetDev, RF_AT_FUNCID_SET_TA, + addr2); + } else { + return -EINVAL; + } + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set Channel Frequency. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetATEChannel(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 i4SetFreq = 0; + s32 i4Status, i4SetChan = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv SetChannel\n"); + + rv = kstrtoint(prInBuf, 0, &i4SetChan); + if (rv == 0) { + i4SetFreq = nicChannelNum2Freq(i4SetChan); + i4Status = MT_ATESetChannel(prNetDev, 0, i4SetFreq); + } else { + return -EINVAL; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set TX WF0 Power. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetATETxPower0(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 i4SetTxPower0 = 0; + s32 i4Status; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv SetTxPower0\n"); + + rv = kstrtoint(prInBuf, 0, &i4SetTxPower0); + if (rv == 0) { + i4Status = MT_ATESetTxPower0(prNetDev, i4SetTxPower0); + }else{ + return -EINVAL; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set TX Guard Interval. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetATETxGi(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 i4SetTxGi = 0; + s32 i4Status; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv SetTxGi\n"); + + rv = kstrtoint(prInBuf, 0, &i4SetTxGi); + if (rv == 0) { + i4Status = MT_ATESetTxGi(prNetDev, i4SetTxGi); + }else{ + return -EINVAL; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set TX System Bandwidth. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetATETxBw(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 i4SetSystemBW = 0; + s32 i4Status; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv SetSystemBW\n"); + + rv = kstrtoint(prInBuf, 0, &i4SetSystemBW); + if (rv == 0) { + i4Status = MT_ATESetSystemBW(prNetDev, i4SetSystemBW); + }else{ + return -EINVAL; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set TX Mode (Preamble). + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetATETxMode(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 i4SetTxMode = 0; + s32 i4Status; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv SetTxMode\n"); + + rv = kstrtoint(prInBuf, 0, &i4SetTxMode); + if (rv == 0) { + i4Status = MT_ATESetPreamble(prNetDev, i4SetTxMode); + }else{ + return -EINVAL; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set TX Length. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetATETxLength(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 i4SetTxLength = 0; + s32 i4Status; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv SetTxLength\n"); + + rv = kstrtoint(prInBuf, 0, &i4SetTxLength); + if (rv == 0) { + i4Status = MT_ATESetTxLength(prNetDev, i4SetTxLength); + }else{ + return -EINVAL; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set TX Count. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetATETxCount(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 i4SetTxCount = 0; + s32 i4Status; + s32 rv; + u8 addr[MAC_ADDR_LEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv SetTxCount\n"); + + rv = kstrtoint(prInBuf, 0, &i4SetTxCount); + if (rv == 0) { + i4Status = MT_ATESetTxCount(prNetDev, i4SetTxCount); + }else{ + return -EINVAL; + } + + i4Status = MT_ATESetMACAddress(prNetDev, RF_AT_FUNCID_SET_MAC_ADDRESS, + addr); + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set TX Rate. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetATETxMcs(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 i4SetTxMcs = 0; + s32 i4Status; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv SetTxMcs\n"); + + rv = kstrtoint(prInBuf, 0, &i4SetTxMcs); + if (rv == 0) { + i4Status = MT_ATESetRate(prNetDev, i4SetTxMcs); + }else{ + return -EINVAL; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set Inter-Packet Guard Interval. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetATEIpg(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 i4SetTxIPG = 0; + s32 i4Status; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv SetIpg\n"); + + rv = kstrtoint(prInBuf, 0, &i4SetTxIPG); + if (rv == 0) { + i4Status = MT_ATESetTxIPG(prNetDev, i4SetTxIPG); + }else{ + return -EINVAL; + } + + return i4Status; +} + +#if CFG_SUPPORT_TX_BF +int Set_TxBfProfileTag_Help(struct net_device *prNetDev, u8 *prInBuf) +{ + DBGLOG(RFTEST, + ERROR, + "========================================================================================================================\n" + "TxBfProfile Tag1 setting example :\n" + "iwpriv ra0 set TxBfProfileTagPfmuIdx =xx\n" + "iwpriv ra0 set TxBfProfileTagBfType =xx (0: iBF; 1: eBF)\n" + "iwpriv ra0 set TxBfProfileTagBw =xx (0/1/2/3 : BW20/40/80/160NC)\n" + "iwpriv ra0 set TxBfProfileTagSuMu =xx (0:SU, 1:MU)\n" + "iwpriv ra0 set TxBfProfileTagInvalid =xx (0: valid, 1: invalid)\n" + "iwpriv ra0 set TxBfProfileTagMemAlloc =xx:xx:xx:xx:xx:xx:xx:xx (mem_row, mem_col), ..\n" + "iwpriv ra0 set TxBfProfileTagMatrix =nrow:nol:ng:LM\n" + "iwpriv ra0 set TxBfProfileTagSnr =SNR_STS0:SNR_STS1:SNR_STS2:SNR_STS3\n" + "\n\n" + "TxBfProfile Tag2 setting example :\n" + "iwpriv ra0 set TxBfProfileTagSmtAnt =xx (11:0)\n" + "iwpriv ra0 set TxBfProfileTagSeIdx =xx\n" + "iwpriv ra0 set TxBfProfileTagRmsdThrd =xx\n" + "iwpriv ra0 set TxBfProfileTagMcsThrd =xx:xx:xx:xx:xx:xx (MCS TH L1SS:S1SS:L2SS:....)\n" + "iwpriv ra0 set TxBfProfileTagTimeOut =xx\n" + "iwpriv ra0 set TxBfProfileTagDesiredBw=xx (0/1/2/3 : BW20/40/80/160NC)\n" + "iwpriv ra0 set TxBfProfileTagDesiredNc=xx\n" + "iwpriv ra0 set TxBfProfileTagDesiredNr=xx\n" + "\n\n" + "Read TxBf profile Tag :\n" + "iwpriv ra0 set TxBfProfileTagRead =xx (PFMU ID)\n" + "\n" + "Write TxBf profile Tag :\n" + "iwpriv ra0 set TxBfProfileTagWrite =xx (PFMU ID)\n" + "When you use one of relative CMD to update one of tag parameters, you should call TxBfProfileTagWrite to update Tag\n" + "\n\n" + "Read TxBf profile Data :\n" + "iwpriv ra0 set TxBfProfileDataRead =xx (PFMU ID)\n" + "\n" + "Write TxBf profile Data :\n" + "iwpriv ra0 set TxBfProfileDataWrite =BW :subcarrier:phi11:psi2l:Phi21:Psi31:Phi31:Psi41:Phi22:Psi32:Phi32:Psi42:Phi33:Psi43\n" + "iwpriv ra0 set TxBfProfileDataWriteAll=Profile ID : BW (BW : 0x00 (20M) , 0x01 (40M), 0x02 (80M), 0x3 (160M)\n" + "When you use CMD TxBfProfileDataWrite to update profile data per subcarrier, you should call TxBfProfileDataWriteAll to update all of\n" + "subcarrier's profile data.\n\n" + "Read TxBf profile PN :\n" + "iwpriv ra0 set TxBfProfilePnRead =xx (PFMU ID)\n" + "\n" + "Write TxBf profile PN :\n" + "iwpriv ra0 set TxBfProfilePnWrite =Profile ID:BW:1STS_Tx0:1STS_Tx1:1STS_Tx2:1STS_Tx3:2STS_Tx0:2STS_Tx1:2STS_Tx2:2STS_Tx3:3STS_Tx1:3STS_Tx2:3STS_Tx3\n" + "========================================================================================================================\n"); + return 0; +} + +int Set_TxBfProfileTag_InValid(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 ucInValid; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_InValid\n"); + + rv = kstrtoint(prInBuf, 0, &ucInValid); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileTag_InValid prInBuf = %s, ucInValid = %d\n", + prInBuf, + ucInValid); + i4Status = TxBfProfileTag_InValid(prNetDev, &g_rPfmuTag1, + ucInValid); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_PfmuIdx(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 ucProfileIdx; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_PfmuIdx\n"); + + rv = kstrtoint(prInBuf, 0, &ucProfileIdx); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileTag_PfmuIdx prInBuf = %s, ucProfileIdx = %d\n", + prInBuf, + ucProfileIdx); + i4Status = TxBfProfileTag_PfmuIdx(prNetDev, &g_rPfmuTag1, + ucProfileIdx); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_BfType(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 ucBFType; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_BfType\n"); + + rv = kstrtoint(prInBuf, 0, &ucBFType); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileTag_BfType prInBuf = %s, ucBFType = %d\n", + prInBuf, + ucBFType); + i4Status = TxBfProfileTag_TxBfType(prNetDev, &g_rPfmuTag1, + ucBFType); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_DBW(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 ucBW; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_DBW\n"); + + rv = kstrtoint(prInBuf, 0, &ucBW); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileTag_DBW prInBuf = %s, ucBW = %d\n", + prInBuf, + ucBW); + i4Status = TxBfProfileTag_DBW(prNetDev, &g_rPfmuTag1, ucBW); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_SuMu(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 ucSuMu; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_SuMu\n"); + + rv = kstrtoint(prInBuf, 0, &ucSuMu); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileTag_SuMu prInBuf = %s, ucSuMu = %d\n", + prInBuf, + ucSuMu); + i4Status = TxBfProfileTag_SuMu(prNetDev, &g_rPfmuTag1, ucSuMu); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_Mem(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 aucInput[8]; + s32 i4Status = 0; + u8 aucMemAddrColIdx[4], aucMemAddrRowIdx[4]; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_Mem\n"); + + rv = sscanf(prInBuf, "%d:%d:%d:%d:%d:%d:%d:%d", &aucInput[0], + &aucInput[1], &aucInput[2], &aucInput[3], &aucInput[4], + &aucInput[5], &aucInput[6], &aucInput[7]); + /* mem col0:row0:col1:row1:col2:row2:col3:row3 */ + if (rv == 8) { + DBGLOG(RFTEST, + ERROR, + "MT6632 : ATE_AGENT iwpriv Set_TxBfProfileTag_Mem aucInput:%d:%d:%d:%d:%d:%d:%d:%d\n", + aucInput[0], + aucInput[1], + aucInput[2], + aucInput[3], + aucInput[4], + aucInput[5], + aucInput[6], + aucInput[7]); + + aucMemAddrColIdx[0] = (u8)aucInput[0]; + aucMemAddrRowIdx[0] = (u8)aucInput[1]; + aucMemAddrColIdx[1] = (u8)aucInput[2]; + aucMemAddrRowIdx[1] = (u8)aucInput[3]; + aucMemAddrColIdx[2] = (u8)aucInput[4]; + aucMemAddrRowIdx[2] = (u8)aucInput[5]; + aucMemAddrColIdx[3] = (u8)aucInput[6]; + aucMemAddrRowIdx[3] = (u8)aucInput[7]; + + i4Status = TxBfProfileTag_Mem(prNetDev, &g_rPfmuTag1, + aucMemAddrColIdx, + aucMemAddrRowIdx); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_Matrix(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 aucInput[6]; + u8 ucNrow, ucNcol, ucNgroup, ucLM, ucCodeBook, ucHtcExist; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_Matrix\n"); + + rv = sscanf(prInBuf, "%d:%d:%d:%d:%d:%d", &aucInput[0], &aucInput[1], + &aucInput[2], &aucInput[3], &aucInput[4], &aucInput[5]); + /* nrow:nol:ng:LM:CodeBook:HtcExist */ + if (rv == 6) { + DBGLOG(RFTEST, + ERROR, + "MT6632 : ATE_AGENT iwpriv Set_TxBfProfileTag_Matrix aucInput:%d:%d:%d:%d:%d:%d\n", + aucInput[0], + aucInput[1], + aucInput[2], + aucInput[3], + aucInput[4], + aucInput[5]); + ucNrow = (u8)aucInput[0]; + ucNcol = (u8)aucInput[1]; + ucNgroup = (u8)aucInput[2]; + ucLM = (u8)aucInput[3]; + ucCodeBook = (u8)aucInput[4]; + ucHtcExist = (u8)aucInput[5]; + + i4Status = TxBfProfileTag_Matrix(prNetDev, &g_rPfmuTag1, ucNrow, + ucNcol, ucNgroup, ucLM, + ucCodeBook, ucHtcExist); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_SNR(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 aucInput[4]; + u8 ucSNR_STS0, ucSNR_STS1, ucSNR_STS2, ucSNR_STS3; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_SNR\n"); + + rv = sscanf(prInBuf, "%d:%d:%d:%d", &aucInput[0], &aucInput[1], + &aucInput[2], &aucInput[3]); + if (rv == 4) { + DBGLOG(RFTEST, + ERROR, + "MT6632 : ATE_AGENT iwpriv Set_TxBfProfileTag_SNR aucInput:%d:%d:%d:%d\n", + aucInput[0], + aucInput[1], + aucInput[2], + aucInput[3]); + + ucSNR_STS0 = (u8)aucInput[0]; + ucSNR_STS1 = (u8)aucInput[1]; + ucSNR_STS2 = (u8)aucInput[2]; + ucSNR_STS3 = (u8)aucInput[3]; + + i4Status = TxBfProfileTag_SNR(prNetDev, &g_rPfmuTag1, + ucSNR_STS0, ucSNR_STS1, + ucSNR_STS2, ucSNR_STS3); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_SmartAnt(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 i4Status = 0; + u32 ucSmartAnt; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_SmartAnt\n"); + + rv = kstrtoint(prInBuf, 0, &ucSmartAnt); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileTag_SmartAnt prInBuf = %s, ucSmartAnt = %d\n", + prInBuf, + ucSmartAnt); + i4Status = TxBfProfileTag_SmtAnt(prNetDev, &g_rPfmuTag2, + ucSmartAnt); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_SeIdx(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 i4Status = 0; + u32 ucSeIdx; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_SeIdx\n"); + + rv = kstrtoint(prInBuf, 0, &ucSeIdx); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 TxBfProfileTag_SeIdx prInBuf = %s, ucSeIdx = %d\n", + prInBuf, + ucSeIdx); + i4Status = + TxBfProfileTag_SeIdx(prNetDev, &g_rPfmuTag2, ucSeIdx); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_RmsdThrd(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 i4Status = 0; + u32 ucRmsdThrd; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_RmsdThrd\n"); + + rv = kstrtoint(prInBuf, 0, &ucRmsdThrd); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileTag_RmsdThrd prInBuf = %s, ucRmsdThrd = %d\n", + prInBuf, + ucRmsdThrd); + i4Status = TxBfProfileTag_RmsdThd(prNetDev, &g_rPfmuTag2, + ucRmsdThrd); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_McsThrd(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 aucInput[6]; + u8 ucMcsLss[3], ucMcsSss[3]; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_McsThrd\n"); + + rv = sscanf(prInBuf, "%d:%d:%d:%d:%d:%d", &aucInput[0], &aucInput[1], + &aucInput[2], &aucInput[3], &aucInput[4], &aucInput[5]); + if (rv == 6) { + DBGLOG(RFTEST, + ERROR, + "MT6632 : ATE_AGENT iwpriv Set_TxBfProfileTag_McsThrd aucInput:%d:%d:%d:%d:%d:%d\n", + aucInput[0], + aucInput[1], + aucInput[2], + aucInput[3], + aucInput[4], + aucInput[5]); + + ucMcsLss[0] = (u8)aucInput[0]; + ucMcsSss[0] = (u8)aucInput[1]; + ucMcsLss[1] = (u8)aucInput[2]; + ucMcsSss[1] = (u8)aucInput[3]; + ucMcsLss[2] = (u8)aucInput[4]; + ucMcsSss[2] = (u8)aucInput[5]; + + i4Status = TxBfProfileTag_McsThd(prNetDev, &g_rPfmuTag2, + ucMcsLss, ucMcsSss); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_TimeOut(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 ucTimeOut; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_TimeOut\n"); + + rv = kstrtouint(prInBuf, 0, &ucTimeOut); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileTag_TimeOut prInBuf = %s, ucTimeOut = %d\n", + prInBuf, + ucTimeOut); + i4Status = TxBfProfileTag_TimeOut(prNetDev, &g_rPfmuTag2, + ucTimeOut); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_DesiredBW(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 ucDesiredBW; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_DesiredBW\n"); + + rv = kstrtoint(prInBuf, 0, &ucDesiredBW); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileTag_DesiredBW prInBuf = %s, ucDesiredBW = %d\n", + prInBuf, + ucDesiredBW); + i4Status = TxBfProfileTag_DesiredBW(prNetDev, &g_rPfmuTag2, + ucDesiredBW); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_DesiredNc(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 ucDesiredNc; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_DesiredNc\n"); + + rv = kstrtoint(prInBuf, 0, &ucDesiredNc); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileTag_DesiredNc prInBuf = %s, ucDesiredNc = %d\n", + prInBuf, + ucDesiredNc); + i4Status = TxBfProfileTag_DesiredNc(prNetDev, &g_rPfmuTag2, + ucDesiredNc); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTag_DesiredNr(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 ucDesiredNr; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTag_DesiredNr\n"); + + rv = kstrtoint(prInBuf, 0, &ucDesiredNr); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileTag_DesiredNr prInBuf = %s, ucDesiredNr = %d\n", + prInBuf, + ucDesiredNr); + i4Status = TxBfProfileTag_DesiredNr(prNetDev, &g_rPfmuTag2, + ucDesiredNr); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTagWrite(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 profileIdx; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTagWrite\n"); + + rv = kstrtoint(prInBuf, 0, &profileIdx); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileTagWrite prInBuf = %s, profileIdx = %d\n", + prInBuf, + profileIdx); + i4Status = TxBfProfileTagWrite(prNetDev, &g_rPfmuTag1, + &g_rPfmuTag2, profileIdx); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileTagRead(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 profileIdx, fgBFer; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileTagRead\n"); + + rv = sscanf(prInBuf, "%d:%d", &profileIdx, &fgBFer); + if (rv == 2) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileTagRead prInBuf = %s, profileIdx = %d, fgBFer = %d\n", + prInBuf, + profileIdx, + fgBFer); + i4Status = TxBfProfileTagRead(prNetDev, profileIdx, fgBFer); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileDataRead(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 profileIdx, fgBFer, subcarrierIdxMsb, subcarrierIdxLsb; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfileDataRead\n"); + + rv = sscanf(prInBuf, "%d:%d:%x:%x", &profileIdx, &fgBFer, + &subcarrierIdxMsb, &subcarrierIdxLsb); + if (rv == 4) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfileDataRead prInBuf = %s, profileIdx = %d, fgBFer = %d, subcarrierIdxMsb:%x, subcarrierIdxLsb:%x\n", + prInBuf, + profileIdx, + fgBFer, + subcarrierIdxMsb, + subcarrierIdxLsb); + i4Status = TxBfProfileDataRead(prNetDev, profileIdx, fgBFer, + subcarrierIdxMsb, + subcarrierIdxLsb); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfileDataWrite(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4ProfileIdx; + u32 u4SubcarrierIdx; + u32 au4Phi[6]; + u32 au4Psi[6]; + u32 au4DSnr[4]; + u16 au2Phi[6]; + u8 aucPsi[6]; + u8 aucDSnr[4]; + u32 i; + s32 rv; + + s32 i4Status = 0; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 TxBfProfileDataWrite\n"); + + rv = sscanf(prInBuf, + "%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x", + &u4ProfileIdx, &u4SubcarrierIdx, &au4Phi[0], &au4Psi[0], + &au4Phi[1], &au4Psi[1], &au4Phi[2], &au4Psi[2], &au4Phi[3], + &au4Psi[3], &au4Phi[4], &au4Psi[4], &au4Phi[5], &au4Psi[5], + &au4DSnr[0], &au4DSnr[1], &au4DSnr[2], &au4DSnr[3]); + + if (rv == 18) { + DBGLOG(RFTEST, + ERROR, + "MT6632 TxBfProfileDataWrite prInBuf = %s, u4ProfileIdx = %x, u4SubcarrierIdx = %x, au4Phi[0]:%x, au4Phi[1]:%x, au4Phi[2]:%x, au4Phi[3]:%x, au4Phi[4]:%x, au4Phi[5]:%x, au4Psi[0]:%x, au4Psi[1]:%x, au4Psi[2]:%x, au4Psi[3]:%x, au4Psi[4]:%x, au4Psi[5]:%x,au4DSnr[0]:%x, au4DSnr[1]:%x, au4DSnr[2]:%x, au4DSnr[3]:%x\n", + prInBuf, + u4ProfileIdx, + u4SubcarrierIdx, + au4Phi[0], + au4Phi[1], + au4Phi[2], + au4Phi[3], + au4Phi[4], + au4Phi[5], + au4Psi[0], + au4Psi[1], + au4Psi[2], + au4Psi[3], + au4Psi[4], + au4Psi[5], + au4DSnr[0], + au4DSnr[1], + au4DSnr[2], + au4DSnr[3]); + for (i = 0; i < 6; i++) { + au2Phi[i] = au4Phi[i]; + aucPsi[i] = au4Psi[i]; + } + for (i = 0; i < 4; i++) + aucDSnr[i] = au4DSnr[i]; + + i4Status = TxBfProfileDataWrite(prNetDev, u4ProfileIdx, + u4SubcarrierIdx, au2Phi, aucPsi, + aucDSnr); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfilePnRead(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 profileIdx; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_TxBfProfilePnRead\n"); + + rv = kstrtoint(prInBuf, 0, &profileIdx); + if (rv == 0) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_TxBfProfilePnRead prInBuf = %s, profileIdx = %d\n", + prInBuf, + profileIdx); + i4Status = TxBfProfilePnRead(prNetDev, profileIdx); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfProfilePnWrite(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 ucProfileIdx; + u16 u2bw; + u16 au2XSTS[12]; + s32 rv; + + s32 i4Status = 0; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 TxBfProfilePnWrite\n"); + + rv = sscanf(prInBuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &ucProfileIdx, &u2bw, &au2XSTS[0], &au2XSTS[1], &au2XSTS[2], + &au2XSTS[3], &au2XSTS[4], &au2XSTS[5], &au2XSTS[6], + &au2XSTS[7], &au2XSTS[8], &au2XSTS[9], &au2XSTS[10], + &au2XSTS[11]); + if (rv == 14) { + DBGLOG(RFTEST, + ERROR, + "MT6632 TxBfProfilePnWrite prInBuf = %s, ucProfileIdx = %d, u2bw = %dau2XSTS[0]:%d, au2XSTS[1]:%d, au2XSTS[2]:%d, au2XSTS[3]:%d, au2XSTS[4]:%d, au2XSTS[5]:%d, au2XSTS[6]:%d, au2XSTS[7]:%d, au2XSTS[8]:%d, au2XSTS[9]:%d, au2XSTS[10]:%d, au2XSTS[11]:%d\n", + ucProfileIdx, + u2bw, + au2XSTS[0], + au2XSTS[1], + au2XSTS[2], + au2XSTS[3], + au2XSTS[4], + au2XSTS[5], + au2XSTS[6], + au2XSTS[7], + au2XSTS[8], + au2XSTS[9], + au2XSTS[10], + au2XSTS[11]); + i4Status = TxBfProfilePnWrite(prNetDev, ucProfileIdx, u2bw, + au2XSTS); + } else { + return -EINVAL; + } + + return i4Status; +} + +/* Su_Mu:NumSta:SndInterval:WLan0:WLan1:WLan2:WLan3 */ +int Set_Trigger_Sounding_Proc(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 ucSuMu, ucNumSta, ucSndInterval, ucWLan0, ucWLan1, ucWLan2, ucWLan3; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_Trigger_Sounding_Proc\n"); + + rv = sscanf(prInBuf, "%x:%x:%x:%x:%x:%x:%x", &ucSuMu, &ucNumSta, + &ucSndInterval, &ucWLan0, &ucWLan1, &ucWLan2, &ucWLan3); + if (rv == 7) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_Trigger_Sounding_Proc prInBuf = %s, ucSuMu = %d, ucNumSta = %d, ucSndInterval = %d, ucWLan0 = %d, ucWLan1 = %d, ucWLan2:%d, ucWLan3:%d\n", + ucSuMu, + ucNumSta, + ucSndInterval, + ucWLan0, + ucWLan1, + ucWLan2, + ucWLan3); + i4Status = TxBfSounding(prNetDev, ucSuMu, ucNumSta, + ucSndInterval, ucWLan0, ucWLan1, + ucWLan2, ucWLan3); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_Stop_Sounding_Proc(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 i4Status = 0; + + DBGLOG(RFTEST, ERROR, "MT6632 Set_Stop_Sounding_Proc\n"); + + i4Status = TxBfSoundingStop(prNetDev); + + return i4Status; +} + +int Set_TxBfTxApply(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4WlanId, u4ETxBf, u4ITxBf, u4MuTxBf; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 TxBfTxApply\n"); + + rv = sscanf(prInBuf, "%d:%d:%d:%d", &u4WlanId, &u4ETxBf, &u4ITxBf, + &u4MuTxBf); + if (rv == 4) { + DBGLOG(RFTEST, + ERROR, + "MT6632 TxBfTxApply prInBuf = %s, u4WlanId = %d, u4ETxBf = %d, u4ITxBf = %d, u4MuTxBf = %d\n", + prInBuf, + u4WlanId, + u4ETxBf, + u4ITxBf, + u4MuTxBf); + i4Status = TxBfTxApply(prNetDev, u4WlanId, u4ETxBf, u4ITxBf, + u4MuTxBf); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfManualAssoc(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 au4Mac[MAC_ADDR_LEN]; + s32 u4Type, u4Wtbl, u4Ownmac, u4PhyMode, u4Bw, u4Nss, u4PfmuId, u4Mode, + u4Marate, u4SpeIdx, ucaid, u4Rv; + s8 aucMac[MAC_ADDR_LEN]; + s32 i4Status = 0; + s32 i = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 TxBfManualAssoc\n"); + + rv = sscanf(prInBuf, + "%x:%x:%x:%x:%x:%x:%x:%d:%x:%x:%x:%x:%d:%x:%x:%x:%d:%x", + &au4Mac[0], &au4Mac[1], &au4Mac[2], &au4Mac[3], &au4Mac[4], + &au4Mac[5], &u4Type, &u4Wtbl, &u4Ownmac, &u4PhyMode, &u4Bw, + &u4Nss, &u4PfmuId, &u4Mode, &u4Marate, &u4SpeIdx, &ucaid, + &u4Rv); + if (rv == 18) { + DBGLOG(RFTEST, + ERROR, + "MT6632 TxBfManualAssoc au4Mac[0] = %x, au4Mac[1] = %x, au4Mac[2] = %xau4Mac[3] = %x, au4Mac[4] = %x, au4Mac[5] = %x, u4Type = %x, u4Wtbl = %d, u4Ownmac = %x, u4PhyMode = %x u4Bw = %x, u4Nss = %x, u4PfmuId = %d, u4Mode = %x, u4Marate = %x, u4SpeIdx = %d, ucaid = %d, u4Rv = %x", + au4Mac[0], + au4Mac[1], + au4Mac[2], + au4Mac[3], + au4Mac[4], + au4Mac[5], + u4Type, + u4Wtbl, + u4Ownmac, + u4PhyMode, + u4Bw, + u4Nss, + u4PfmuId, + u4Mode, + u4Marate, + u4SpeIdx, + ucaid, + u4Rv); + for (i = 0; i < MAC_ADDR_LEN; i++) + aucMac[i] = au4Mac[i]; + + i4Status = TxBfManualAssoc(prNetDev, aucMac, u4Type, u4Wtbl, + u4Ownmac, u4Mode, u4Bw, u4Nss, + u4PfmuId, u4Marate, u4SpeIdx, ucaid, + u4Rv); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfPfmuMemAlloc(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 ucSuMuMode, ucWlanIdx; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 TxBfPfmuMemAlloc\n"); + + rv = sscanf(prInBuf, "%d:%d", &ucSuMuMode, &ucWlanIdx); + if (rv == 2) { + DBGLOG(RFTEST, + ERROR, + "MT6632 TxBfPfmuMemAlloc ucSuMuMode = %d, ucWlanIdx = %d", + ucSuMuMode, + ucWlanIdx); + i4Status = TxBfPfmuMemAlloc(prNetDev, ucSuMuMode, ucWlanIdx); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_TxBfPfmuMemRelease(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 ucWlanId; + s32 i4Status = 0; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 TxBfPfmuMemRelease\n"); + + rv = kstrtoint(prInBuf, 0, &ucWlanId); + if (rv == 0) { + DBGLOG(RFTEST, ERROR, "MT6632 TxBfPfmuMemRelease ucWlanId = %d", + ucWlanId); + i4Status = TxBfPfmuMemRelease(prNetDev, ucWlanId); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_DevInfoUpdate(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4OwnMacIdx, fgBand; + u32 OwnMacAddr[MAC_ADDR_LEN]; + u8 aucMacAddr[MAC_ADDR_LEN]; + s32 i4Status = 0; + u32 i; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 DevInfoUpdate\n"); + + rv = sscanf(prInBuf, "%d:%x:%x:%x:%x:%x:%x:%d", &u4OwnMacIdx, + &OwnMacAddr[0], &OwnMacAddr[1], &OwnMacAddr[2], + &OwnMacAddr[3], &OwnMacAddr[4], &OwnMacAddr[5], &fgBand); + if (rv == 8) { + DBGLOG(RFTEST, + ERROR, + "MT6632 DevInfoUpdate prInBuf = %s, u4OwnMacIdx = %x, fgBand = %x,OwnMacAddr[0]:%x, OwnMacAddr[1]:%x, OwnMacAddr[2]:%x, OwnMacAddr[3]:%x, OwnMacAddr[4]:%x, OwnMacAddr[5]:%x,", + prInBuf, + u4OwnMacIdx, + fgBand, + OwnMacAddr[0], + OwnMacAddr[1], + OwnMacAddr[2], + OwnMacAddr[3], + OwnMacAddr[4], + OwnMacAddr[5]); + for (i = 0; i < MAC_ADDR_LEN; i++) + aucMacAddr[i] = OwnMacAddr[i]; + + i4Status = DevInfoUpdate(prNetDev, u4OwnMacIdx, fgBand, + aucMacAddr); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_BssInfoUpdate(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4OwnMacIdx, u4BssIdx; + u32 au4BssId[MAC_ADDR_LEN]; + u8 aucBssId[MAC_ADDR_LEN]; + s32 i4Status = 0; + u32 i; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 BssInfoUpdate\n"); + + rv = sscanf(prInBuf, "%d:%d:%x:%x:%x:%x:%x:%x", &u4OwnMacIdx, &u4BssIdx, + &au4BssId[0], &au4BssId[1], &au4BssId[2], &au4BssId[3], + &au4BssId[4], &au4BssId[5]); + if (rv == 8) { + DBGLOG(RFTEST, + ERROR, + "MT6632 BssInfoUpdate prInBuf = %s, u4OwnMacIdx = %x, u4BssIdx = %x,au4BssId[0]:%x, au4BssId[1]:%x, au4BssId[2]:%x, au4BssId[3]:%x, au4BssId[4]:%x, au4BssId[5]:%x,", + prInBuf, + u4OwnMacIdx, + u4BssIdx, + au4BssId[0], + au4BssId[1], + au4BssId[2], + au4BssId[3], + au4BssId[4], + au4BssId[5]); + for (i = 0; i < MAC_ADDR_LEN; i++) + aucBssId[i] = au4BssId[i]; + + i4Status = BssInfoUpdate(prNetDev, u4OwnMacIdx, u4BssIdx, + aucBssId); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_StaRecCmmUpdate(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4WlanId, u4BssId, u4Aid; + u32 au4MacAddr[MAC_ADDR_LEN]; + u8 aucMacAddr[MAC_ADDR_LEN]; + s32 i4Status = 0; + u32 i; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_StaRecCmmUpdate\n"); + + rv = sscanf(prInBuf, "%x:%x:%x:%x:%x:%x:%x:%x:%x", &u4WlanId, &u4BssId, + &u4Aid, &au4MacAddr[0], &au4MacAddr[1], &au4MacAddr[2], + &au4MacAddr[3], &au4MacAddr[4], &au4MacAddr[5]); + if (rv == 9) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_StaRecCmmUpdate prInBuf = %s, u4WlanId = %x, u4BssId = %x, u4Aid = %x,aucMacAddr[0]:%x, aucMacAddr[1]:%x, aucMacAddr[2]:%x, aucMacAddr[3]:%x, aucMacAddr[4]:%x, aucMacAddr[5]:%x,", + prInBuf, + u4WlanId, + u4BssId, + u4Aid, + au4MacAddr[0], + au4MacAddr[1], + au4MacAddr[2], + au4MacAddr[3], + au4MacAddr[4], + au4MacAddr[5]); + for (i = 0; i < MAC_ADDR_LEN; i++) + aucMacAddr[i] = au4MacAddr[i]; + + i4Status = StaRecCmmUpdate(prNetDev, u4WlanId, u4BssId, u4Aid, + aucMacAddr); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_StaRecBfUpdate(struct net_device *prNetDev, u8 *prInBuf) +{ + STA_REC_BF_UPD_ARGUMENT rStaRecBfUpdArg; + u8 aucMemRow[4], aucMemCol[4]; + s32 i4Status = 0; + u32 i; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_StaRecBfUpdate\n"); + + rv = sscanf( + prInBuf, + "%x:%x:%x:%x:%x:%d:%d:%d:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x", + &rStaRecBfUpdArg.u4WlanId, + &rStaRecBfUpdArg.u4BssId, + &rStaRecBfUpdArg.u4PfmuId, + &rStaRecBfUpdArg.u4SuMu, + &rStaRecBfUpdArg.u4eTxBfCap, + &rStaRecBfUpdArg.u4NdpaRate, + &rStaRecBfUpdArg.u4NdpRate, + &rStaRecBfUpdArg.u4ReptPollRate, + &rStaRecBfUpdArg.u4TxMode, + &rStaRecBfUpdArg.u4Nc, + &rStaRecBfUpdArg.u4Nr, + &rStaRecBfUpdArg.u4Bw, + &rStaRecBfUpdArg.u4SpeIdx, + &rStaRecBfUpdArg.u4TotalMemReq, + &rStaRecBfUpdArg.u4MemReq20M, + &rStaRecBfUpdArg.au4MemRow[0], + &rStaRecBfUpdArg.au4MemCol[0], + &rStaRecBfUpdArg.au4MemRow[1], + &rStaRecBfUpdArg.au4MemCol[1], + &rStaRecBfUpdArg.au4MemRow[2], + &rStaRecBfUpdArg.au4MemCol[2], + &rStaRecBfUpdArg.au4MemRow[3], + &rStaRecBfUpdArg.au4MemCol[3]); + if (rv == 23) { + /* + * DBGLOG(RFTEST, ERROR, + *"MT6632 Set_StaRecBfUpdate prInBuf = %s, u4WlanId = %x, + * u4BssId = %x, u4Aid = %x, aucMacAddr[0]:%x, aucMacAddr[1]:%x, + * aucMacAddr[2]:%x, aucMacAddr[3]:%x, aucMacAddr[4]:%x, + * aucMacAddr[5]:%x", + * prInBuf, u4OwnMacIdx, u4BssIdx, u4Aid, + * aucMacAddr[0], aucMacAddr[1], aucMacAddr[2], aucMacAddr[3], + * aucMacAddr[4], aucMacAddr[5]); + */ + for (i = 0; i < 4; i++) { + aucMemRow[i] = rStaRecBfUpdArg.au4MemRow[i]; + aucMemCol[i] = rStaRecBfUpdArg.au4MemCol[i]; + } + i4Status = StaRecBfUpdate(prNetDev, rStaRecBfUpdArg, aucMemRow, + aucMemCol); + } else { + return -EINVAL; + } + + return i4Status; +} + +#if CFG_SUPPORT_MU_MIMO +int Set_MUGetInitMCS(struct net_device *prNetDev, u8 *prInBuf) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T rMuMimoActionInfo; + s32 i4Status = 0; + u32 u4BufLen = 0; + + u32 u4groupIdx; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_MUGetInitMCS\n"); + + kalMemZero(&rMuMimoActionInfo, sizeof(rMuMimoActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rv = kstrtouint(prInBuf, 0, &u4groupIdx); + if (rv == 0) { + DBGLOG(RFTEST, ERROR, "MT6632 Test\n"); + DBGLOG(RFTEST, ERROR, + "MT6632 Set_MUGetInitMCS prInBuf = %s, u4groupIdx = %x", + prInBuf, u4groupIdx); + + rMuMimoActionInfo.ucMuMimoCategory = MU_GET_CALC_INIT_MCS; + rMuMimoActionInfo.unMuMimoParam.rMuGetCalcInitMcs.ucgroupIdx = + u4groupIdx; + + i4Status = kalIoctl(prGlueInfo, wlanoidMuMimoAction, + &rMuMimoActionInfo, + sizeof(rMuMimoActionInfo), true, true, true, + &u4BufLen); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_MUCalInitMCS(struct net_device *prNetDev, u8 *prInBuf) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T rMuMimoActionInfo; + s32 i4Status = 0; + u32 u4BufLen = 0; + + u32 u4NumOfUser, u4Bandwidth, u4NssOfUser0, u4NssOfUser1, + u4PfMuIdOfUser0, u4PfMuIdOfUser1, u4NumOfTxer, u4SpeIndex, + u4GroupIndex; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_MUCalInitMCS\n"); + + kalMemZero(&rMuMimoActionInfo, sizeof(rMuMimoActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rv = sscanf(prInBuf, "%x:%x:%x:%x:%x:%x:%x:%x:%x", &u4NumOfUser, + &u4Bandwidth, &u4NssOfUser0, &u4NssOfUser1, + &u4PfMuIdOfUser0, &u4PfMuIdOfUser1, &u4NumOfTxer, + &u4SpeIndex, &u4GroupIndex); + if (rv == 9) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_MUCalInitMCS prInBuf = %s, u4NumOfUser = %x, u4Bandwidth = %x, u4NssOfUser0 = %x, u4NssOfUser1 = %x, u4PfMuIdOfUser0 = %x, u4PfMuIdOfUser1 = %x, u4NumOfTxer = %x, u4SpeIndex = %x, u4GroupIndex = %x", + prInBuf, + u4NumOfUser, + u4Bandwidth, + u4NssOfUser0, + u4NssOfUser1, + u4PfMuIdOfUser0, + u4PfMuIdOfUser1, + u4NumOfTxer, + u4SpeIndex, + u4GroupIndex); + + rMuMimoActionInfo.ucMuMimoCategory = MU_SET_CALC_INIT_MCS; + rMuMimoActionInfo.unMuMimoParam.rMuSetInitMcs.ucNumOfUser = + u4NumOfUser; + rMuMimoActionInfo.unMuMimoParam.rMuSetInitMcs.ucBandwidth = + u4Bandwidth; + rMuMimoActionInfo.unMuMimoParam.rMuSetInitMcs.ucNssOfUser0 = + u4NssOfUser0; + rMuMimoActionInfo.unMuMimoParam.rMuSetInitMcs.ucNssOfUser1 = + u4NssOfUser1; + rMuMimoActionInfo.unMuMimoParam.rMuSetInitMcs.ucPfMuIdOfUser0 = + u4PfMuIdOfUser0; + rMuMimoActionInfo.unMuMimoParam.rMuSetInitMcs.ucPfMuIdOfUser1 = + u4PfMuIdOfUser1; + rMuMimoActionInfo.unMuMimoParam.rMuSetInitMcs.ucNumOfTxer = + u4NumOfTxer; + rMuMimoActionInfo.unMuMimoParam.rMuSetInitMcs.ucSpeIndex = + u4SpeIndex; + rMuMimoActionInfo.unMuMimoParam.rMuSetInitMcs.u4GroupIndex = + u4GroupIndex; + + i4Status = kalIoctl(prGlueInfo, wlanoidMuMimoAction, + &rMuMimoActionInfo, + sizeof(rMuMimoActionInfo), false, false, + true, &u4BufLen); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_MUCalLQ(struct net_device *prNetDev, u8 *prInBuf) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T rMuMimoActionInfo; + s32 i4Status = 0; + u32 u4BufLen = 0; + + u32 u4NumOfUser, u4Bandwidth, u4NssOfUser0, u4NssOfUser1, + u4PfMuIdOfUser0, u4PfMuIdOfUser1, u4NumOfTxer, u4SpeIndex, + u4GroupIndex; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_MUCalLQ\n"); + + kalMemZero(&rMuMimoActionInfo, sizeof(rMuMimoActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rv = sscanf(prInBuf, "%x:%x:%x:%x:%x:%x:%x:%x:%x:%x", &u4NumOfUser, + &u4Bandwidth, &u4NssOfUser0, &u4NssOfUser1, + &u4PfMuIdOfUser0, &u4PfMuIdOfUser1, &u4NumOfTxer, + &u4SpeIndex, &u4GroupIndex); + if (rv == 9) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_MUCalLQ prInBuf = %s, u4NumOfUser = %x, u4Bandwidth = %x, u4NssOfUser0 = %x, u4NssOfUser1 = %x, u4PfMuIdOfUser0 = %x, u4PfMuIdOfUser1 = %x, u4NumOfTxer = %x, u4SpeIndex = %x, u4GroupIndex = %x", + prInBuf, + u4NumOfUser, + u4Bandwidth, + u4NssOfUser0, + u4NssOfUser1, + u4PfMuIdOfUser0, + u4PfMuIdOfUser1, + u4NumOfTxer, + u4SpeIndex, + u4GroupIndex); + + rMuMimoActionInfo.ucMuMimoCategory = MU_HQA_SET_CALC_LQ; + /* rMuMimoActionInfo.unMuMimoParam.rMuSetCalcLq.ucType = u4Type; + */ + rMuMimoActionInfo.unMuMimoParam.rMuSetCalcLq.ucNumOfUser = + u4NumOfUser; + rMuMimoActionInfo.unMuMimoParam.rMuSetCalcLq.ucBandwidth = + u4Bandwidth; + rMuMimoActionInfo.unMuMimoParam.rMuSetCalcLq.ucNssOfUser0 = + u4NssOfUser0; + rMuMimoActionInfo.unMuMimoParam.rMuSetCalcLq.ucNssOfUser1 = + u4NssOfUser1; + rMuMimoActionInfo.unMuMimoParam.rMuSetCalcLq.ucPfMuIdOfUser0 = + u4PfMuIdOfUser0; + rMuMimoActionInfo.unMuMimoParam.rMuSetCalcLq.ucPfMuIdOfUser1 = + u4PfMuIdOfUser1; + rMuMimoActionInfo.unMuMimoParam.rMuSetCalcLq.ucNumOfTxer = + u4NumOfTxer; + rMuMimoActionInfo.unMuMimoParam.rMuSetCalcLq.ucSpeIndex = + u4SpeIndex; + rMuMimoActionInfo.unMuMimoParam.rMuSetCalcLq.u4GroupIndex = + u4GroupIndex; + + i4Status = kalIoctl(prGlueInfo, wlanoidMuMimoAction, + &rMuMimoActionInfo, + sizeof(rMuMimoActionInfo), false, false, + true, &u4BufLen); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_MUGetLQ(struct net_device *prNetDev, u8 *prInBuf) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T rMuMimoActionInfo; + s32 i4Status = 0; + /* u32 u4Type; */ + u32 u4BufLen = 0; + + DBGLOG(RFTEST, ERROR, "MT6632 Set_MUGetLQ\n"); + + kalMemZero(&rMuMimoActionInfo, sizeof(rMuMimoActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + /* if (sscanf(prInBuf, "%x", &u4Type) == 1) */ + /* { */ + /* DBGLOG(RFTEST, ERROR, "MT6632 Set_MUGetLQ prInBuf = %s, u4Type = %x", + * prInBuf, u4Type); */ + + rMuMimoActionInfo.ucMuMimoCategory = MU_HQA_GET_CALC_LQ; + /* rMuMimoActionInfo.unMuMimoParam.rMuGetLq.ucType = u4Type; */ + + i4Status = kalIoctl(prGlueInfo, wlanoidMuMimoAction, &rMuMimoActionInfo, + sizeof(rMuMimoActionInfo), true, true, true, + &u4BufLen); + /* } */ + /* else */ + /* { */ + /* return -EINVAL; */ + /* } */ + + return i4Status; +} + +int Set_MUSetSNROffset(struct net_device *prNetDev, u8 *prInBuf) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T rMuMimoActionInfo; + s32 i4Status = 0; + u32 u4BufLen = 0; + + u32 u4Val; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_MUSetSNROffset\n"); + + kalMemZero(&rMuMimoActionInfo, sizeof(rMuMimoActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rv = kstrtoint(prInBuf, 0, &u4Val); + if (rv == 0) { + DBGLOG(RFTEST, ERROR, + "MT6632 Set_MUSetSNROffset prInBuf = %s, u4Val = %x", + prInBuf, u4Val); + + rMuMimoActionInfo.ucMuMimoCategory = MU_HQA_SET_SNR_OFFSET; + rMuMimoActionInfo.unMuMimoParam.rMuSetSnrOffset.ucVal = u4Val; + + i4Status = kalIoctl(prGlueInfo, wlanoidMuMimoAction, + &rMuMimoActionInfo, + sizeof(rMuMimoActionInfo), false, false, + true, &u4BufLen); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_MUSetZeroNss(struct net_device *prNetDev, u8 *prInBuf) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T rMuMimoActionInfo; + s32 i4Status = 0; + u32 u4BufLen = 0; + + u32 u4Val; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_MUSetZeroNss\n"); + + kalMemZero(&rMuMimoActionInfo, sizeof(rMuMimoActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rv = kstrtouint(prInBuf, 0, &u4Val); + if (rv == 0) { + DBGLOG(RFTEST, ERROR, + "MT6632 Set_MUSetZeroNss prInBuf = %s, u4Val = %x", + prInBuf, u4Val); + + rMuMimoActionInfo.ucMuMimoCategory = MU_HQA_SET_ZERO_NSS; + rMuMimoActionInfo.unMuMimoParam.rMuSetZeroNss.ucVal = u4Val; + + i4Status = kalIoctl(prGlueInfo, wlanoidMuMimoAction, + &rMuMimoActionInfo, + sizeof(rMuMimoActionInfo), false, false, + true, &u4BufLen); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_MUSetSpeedUpLQ(struct net_device *prNetDev, u8 *prInBuf) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T rMuMimoActionInfo; + s32 i4Status = 0; + u32 u4BufLen = 0; + + u32 u4Val; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_MUSetSpeedUpLQ\n"); + + kalMemZero(&rMuMimoActionInfo, sizeof(rMuMimoActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rv = kstrtouint(prInBuf, 0, &u4Val); + if (rv == 0) { + DBGLOG(RFTEST, ERROR, + "MT6632 Set_MUSetSpeedUpLQ prInBuf = %s, u4Val = %x", + prInBuf, u4Val); + + rMuMimoActionInfo.ucMuMimoCategory = MU_HQA_SET_SPEED_UP_LQ; + rMuMimoActionInfo.unMuMimoParam.rMuSpeedUpLq.u4Val = u4Val; + + i4Status = kalIoctl(prGlueInfo, wlanoidMuMimoAction, + &rMuMimoActionInfo, + sizeof(rMuMimoActionInfo), false, false, + true, &u4BufLen); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_MUSetMUTable(struct net_device *prNetDev, u8 *prTable) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T rMuMimoActionInfo; + s32 i4Status = 0; + u32 u4BufLen = 0; + /*u32 i; + * u32 u4Type, u4Length; + */ + + DBGLOG(RFTEST, ERROR, "MT6632 Set_MUSetMUTable\n"); + + kalMemZero(&rMuMimoActionInfo, sizeof(rMuMimoActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + /* if (sscanf(prInBuf, "%x:%x", &u4Type, &u4Length) == 2) */ + /* { */ + /* DBGLOG(RFTEST, ERROR, "MT6632 Set_MUSetMUTable prInBuf = %s, */ + /* u4Type = %x, u4Length = %x", prInBuf, u4Type, u4Length); */ + + rMuMimoActionInfo.ucMuMimoCategory = MU_HQA_SET_MU_TABLE; + /* rMuMimoActionInfo.unMuMimoParam.rMuSetMuTable.u2Type = u4Type; */ + /* rMuMimoActionInfo.unMuMimoParam.rMuSetMuTable.u4Length = u4Length; */ + + /* for ( i = 0 ; i < NUM_MUT_NR_NUM * NUM_MUT_FEC * NUM_MUT_MCS * + * NUM_MUT_INDEX ; i++) */ + /* { */ + memcpy(rMuMimoActionInfo.unMuMimoParam.rMuSetMuTable.aucMetricTable, + prTable, + NUM_MUT_NR_NUM * NUM_MUT_FEC * NUM_MUT_MCS * NUM_MUT_INDEX); + /* } */ + + i4Status = kalIoctl(prGlueInfo, wlanoidMuMimoAction, &rMuMimoActionInfo, + sizeof(rMuMimoActionInfo), false, false, true, + &u4BufLen); + /* } */ + /* else */ + /* { */ + /* return -EINVAL; */ + /* } */ + + return i4Status; +} + +int Set_MUSetGroup(struct net_device *prNetDev, u8 *prInBuf) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T rMuMimoActionInfo; + s32 i4Status = 0; + u32 u4BufLen = 0; + u32 i = 0; + + u32 aucUser0MacAddr[PARAM_MAC_ADDR_LEN], + aucUser1MacAddr[PARAM_MAC_ADDR_LEN]; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_MUSetGroup\n"); + + kalMemZero(&rMuMimoActionInfo, sizeof(rMuMimoActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (sscanf(prInBuf, + "%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x", + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4GroupIndex, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4NumOfUser, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User0Ldpc, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User1Ldpc, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4ShortGI, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4Bw, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User0Nss, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User1Nss, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4GroupId, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User0UP, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User1UP, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User0MuPfId, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User1MuPfId, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User0InitMCS, + &rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User1InitMCS, + &aucUser0MacAddr[0], + &aucUser0MacAddr[1], + &aucUser0MacAddr[2], + &aucUser0MacAddr[3], + &aucUser0MacAddr[4], + &aucUser0MacAddr[5], + &aucUser1MacAddr[0], + &aucUser1MacAddr[1], + &aucUser1MacAddr[2], + &aucUser1MacAddr[3], + &aucUser1MacAddr[4], + &aucUser1MacAddr[5]) == 27) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_MUSetGroup prInBuf = %s,u4GroupIndex = %d, u4NumOfUser = %d, u4User0Ldpc = %d, u4User1Ldpc = %d, u4ShortGI = %d, u4Bw = %d, u4User0Nss = %d, u4User1Nss = %d, u4GroupId = %d, u4User0UP = %d, u4User1UP = %d, u4User0MuPfId = %d, u4User1MuPfId = %d, u4User0InitMCS = %d, u4User1InitMCS = %d,aucUser0MacAddr[0] = %x, aucUser0MacAddr[1] = %x, aucUser0MacAddr[2] = %x, aucUser0MacAddr[3] = %x, aucUser0MacAddr[4] = %x, aucUser0MacAddr[5] = %x,aucUser1MacAddr[0] = %x, aucUser1MacAddr[1] = %x, aucUser1MacAddr[2] = %x, aucUser1MacAddr[3] = %x, aucUser1MacAddr[4] = %x, aucUser1MacAddr[5] = %x,", + prInBuf, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4GroupIndex, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4NumOfUser, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User0Ldpc, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User1Ldpc, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4ShortGI, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4Bw, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User0Nss, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User1Nss, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4GroupId, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User0UP, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User1UP, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User0MuPfId, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup.u4User1MuPfId, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup + .u4User0InitMCS, + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup + .u4User1InitMCS, + aucUser0MacAddr[0], + aucUser0MacAddr[1], + aucUser0MacAddr[2], + aucUser0MacAddr[3], + aucUser0MacAddr[4], + aucUser0MacAddr[5], + aucUser1MacAddr[0], + aucUser1MacAddr[1], + aucUser1MacAddr[2], + aucUser1MacAddr[3], + aucUser1MacAddr[4], + aucUser1MacAddr[5]); + + rMuMimoActionInfo.ucMuMimoCategory = MU_HQA_SET_GROUP; + for (i = 0; i < PARAM_MAC_ADDR_LEN; i++) { + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup + .aucUser0MacAddr[i] = aucUser0MacAddr[i]; + rMuMimoActionInfo.unMuMimoParam.rMuSetGroup + .aucUser1MacAddr[i] = aucUser1MacAddr[i]; + } + + i4Status = kalIoctl(prGlueInfo, wlanoidMuMimoAction, + &rMuMimoActionInfo, + sizeof(rMuMimoActionInfo), false, false, + true, &u4BufLen); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_MUGetQD(struct net_device *prNetDev, u8 *prInBuf) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T rMuMimoActionInfo; + s32 i4Status = 0; + u32 u4BufLen = 0; + + u32 u4SubcarrierIndex, u4Length; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_MUGetQD\n"); + + kalMemZero(&rMuMimoActionInfo, sizeof(rMuMimoActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (sscanf(prInBuf, "%x:%x", &u4SubcarrierIndex, &u4Length) == 2) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_MUGetQD prInBuf = %s, u4SubcarrierIndex = %x, u4Length = %x", + prInBuf, + u4SubcarrierIndex, + u4Length); + + rMuMimoActionInfo.ucMuMimoCategory = MU_HQA_GET_QD; + rMuMimoActionInfo.unMuMimoParam.rMuGetQd.ucSubcarrierIndex = + u4SubcarrierIndex; + /* rMuMimoActionInfo.unMuMimoParam.rMuGetQd.u4Length = u4Length; + */ + /* rMuMimoActionInfo.unMuMimoParam.rMuGetQd.ucgroupIdx = + * ucgroupIdx; */ + + i4Status = kalIoctl(prGlueInfo, wlanoidMuMimoAction, + &rMuMimoActionInfo, + sizeof(rMuMimoActionInfo), true, true, true, + &u4BufLen); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_MUSetEnable(struct net_device *prNetDev, u8 *prInBuf) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T rMuMimoActionInfo; + s32 i4Status = 0; + u32 u4BufLen = 0; + + u32 u4Val; + s32 rv; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_MUSetEnable\n"); + + kalMemZero(&rMuMimoActionInfo, sizeof(rMuMimoActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rv = kstrtouint(prInBuf, 0, &u4Val); + if (rv == 0) { + DBGLOG(RFTEST, ERROR, + "MT6632 Set_MUSetEnable prInBuf = %s, u4Val = %x", + prInBuf, u4Val); + + rMuMimoActionInfo.ucMuMimoCategory = MU_HQA_SET_ENABLE; + rMuMimoActionInfo.unMuMimoParam.rMuSetEnable.ucVal = u4Val; + + i4Status = kalIoctl(prGlueInfo, wlanoidMuMimoAction, + &rMuMimoActionInfo, + sizeof(rMuMimoActionInfo), false, false, + true, &u4BufLen); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_MUSetGID_UP(struct net_device *prNetDev, u8 *prInBuf) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T rMuMimoActionInfo; + s32 i4Status = 0; + u32 u4BufLen = 0; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_MUSetGID_UP\n"); + + kalMemZero(&rMuMimoActionInfo, sizeof(rMuMimoActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (sscanf(prInBuf, "%x:%x:%x:%x:%x:%x", + &rMuMimoActionInfo.unMuMimoParam.rMuSetGidUp.au4Gid[0], + &rMuMimoActionInfo.unMuMimoParam.rMuSetGidUp.au4Gid[1], + &rMuMimoActionInfo.unMuMimoParam.rMuSetGidUp.au4Up[0], + &rMuMimoActionInfo.unMuMimoParam.rMuSetGidUp.au4Up[1], + &rMuMimoActionInfo.unMuMimoParam.rMuSetGidUp.au4Up[2], + &rMuMimoActionInfo.unMuMimoParam.rMuSetGidUp.au4Up[3]) == + 6) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_MUSetGID_UP prInBuf = %s, au4Gid[0] = %x, au4Gid[1] = %x, au4Up[0] = %x, au4Up[1] = %x, au4Up[2] = %x, au4Up[3] = %x", + prInBuf, + rMuMimoActionInfo.unMuMimoParam.rMuSetGidUp.au4Gid[0], + rMuMimoActionInfo.unMuMimoParam.rMuSetGidUp.au4Gid[1], + rMuMimoActionInfo.unMuMimoParam.rMuSetGidUp.au4Up[0], + rMuMimoActionInfo.unMuMimoParam.rMuSetGidUp.au4Up[1], + rMuMimoActionInfo.unMuMimoParam.rMuSetGidUp.au4Up[2], + rMuMimoActionInfo.unMuMimoParam.rMuSetGidUp.au4Up[3]); + + rMuMimoActionInfo.ucMuMimoCategory = MU_HQA_SET_STA_PARAM; + + i4Status = kalIoctl(prGlueInfo, wlanoidMuMimoAction, + &rMuMimoActionInfo, + sizeof(rMuMimoActionInfo), false, false, + true, &u4BufLen); + } else { + return -EINVAL; + } + + return i4Status; +} + +int Set_MUTriggerTx(struct net_device *prNetDev, u8 *prInBuf) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MUMIMO_ACTION_STRUCT_T rMuMimoActionInfo; + s32 i4Status = 0; + u32 u4BufLen = 0; + u32 i, j; + + u32 u4IsRandomPattern, u4MsduPayloadLength0, u4MsduPayloadLength1, + u4MuPacketCount, u4NumOfSTAs; + u32 au4MacAddrs[2][6]; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(RFTEST, ERROR, "MT6632 Set_MUTriggerTx\n"); + + kalMemZero(&rMuMimoActionInfo, sizeof(rMuMimoActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (sscanf(prInBuf, + "%d:%x:%x:%x:%d:%d:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x", + &u4IsRandomPattern, &u4MsduPayloadLength0, + &u4MsduPayloadLength1, &u4MuPacketCount, &u4NumOfSTAs, + &au4MacAddrs[0][0], &au4MacAddrs[0][1], &au4MacAddrs[0][2], + &au4MacAddrs[0][3], &au4MacAddrs[0][4], &au4MacAddrs[0][5], + &au4MacAddrs[1][0], &au4MacAddrs[1][1], &au4MacAddrs[1][2], + &au4MacAddrs[1][3], &au4MacAddrs[1][4], + &au4MacAddrs[1][5]) == 17) { + DBGLOG(RFTEST, + ERROR, + "MT6632 Set_MUTriggerTx prInBuf = %s, u4IsRandomPattern = %x, u4MsduPayloadLength0 = %x, u4MsduPayloadLength1 = %x, u4MuPacketCount = %x, u4NumOfSTAs = %x, au4MacAddrs[0][0] = %x, au4MacAddrs[0][1] = %x, au4MacAddrs[0][2] = %x, au4MacAddrs[0][3] = %x, au4MacAddrs[0][4] = %x, au4MacAddrs[0][5] = %x,au4MacAddrs[1][0] = %x, au4MacAddrs[1][1] = %x, au4MacAddrs[1][2] = %x, au4MacAddrs[1][3] = %x, au4MacAddrs[1][4] = %x, au4MacAddrs[1][5] = %x", + prInBuf, + u4IsRandomPattern, + u4MsduPayloadLength0, + u4MsduPayloadLength1, + u4MuPacketCount, + u4NumOfSTAs, + au4MacAddrs[0][0], + au4MacAddrs[0][1], + au4MacAddrs[0][2], + au4MacAddrs[0][3], + au4MacAddrs[0][4], + au4MacAddrs[0][5], + au4MacAddrs[1][0], + au4MacAddrs[1][1], + au4MacAddrs[1][2], + au4MacAddrs[1][3], + au4MacAddrs[1][4], + au4MacAddrs[1][5]); + + rMuMimoActionInfo.ucMuMimoCategory = MU_SET_TRIGGER_MU_TX; + rMuMimoActionInfo.unMuMimoParam.rMuTriggerMuTx + .fgIsRandomPattern = u4IsRandomPattern; + rMuMimoActionInfo.unMuMimoParam.rMuTriggerMuTx + .u4MsduPayloadLength0 = u4MsduPayloadLength0; + rMuMimoActionInfo.unMuMimoParam.rMuTriggerMuTx + .u4MsduPayloadLength1 = u4MsduPayloadLength1; + rMuMimoActionInfo.unMuMimoParam.rMuTriggerMuTx.u4MuPacketCount = + u4MuPacketCount; + rMuMimoActionInfo.unMuMimoParam.rMuTriggerMuTx.u4NumOfSTAs = + u4NumOfSTAs; + + for (i = 0; i < 2; i++) { + for (j = 0; j < PARAM_MAC_ADDR_LEN; j++) + rMuMimoActionInfo.unMuMimoParam.rMuTriggerMuTx + .aucMacAddrs[i][j] = au4MacAddrs[i][j]; + } + + i4Status = kalIoctl(prGlueInfo, wlanoidMuMimoAction, + &rMuMimoActionInfo, + sizeof(rMuMimoActionInfo), false, false, + true, &u4BufLen); + } else { + return -EINVAL; + } + + return i4Status; +} +#endif +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Write Efuse. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int WriteEfuse(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 i4Status; + s32 rv; + u32 addr[2]; + u16 addr2[2]; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv WriteEfuse, buf: %s\n", + prInBuf); + + rv = sscanf(prInBuf, "%x:%x", &addr[0], &addr[1]); + + DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv WriteEfuse, prInBuf: %s\n", + prInBuf); + DBGLOG(INIT, ERROR, "MT6632 : ATE_AGENT iwpriv WriteEfuse :%02x:%02x\n", + addr[0], addr[1]); + + addr2[0] = (u16)addr[0]; + addr2[1] = (u16)addr[1]; + + if (rv == 2) { + i4Status = MT_ATEWriteEfuse(prNetDev, addr2[0], addr2[1]); + }else{ + return -EINVAL; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set Tx Power. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetTxTargetPower(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 i4Status; + s32 rv; + int addr; + u8 addr2; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv Set Tx Target Power, buf: %s\n", + prInBuf); + + /* rv = sscanf(prInBuf, "%u", &addr);*/ + rv = kstrtoint(prInBuf, 0, &addr); + + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv Set Tx Target Power, prInBuf: %s\n", + prInBuf); + DBGLOG(INIT, ERROR, + "MT6632 : ATE_AGENT iwpriv Set Tx Target Power :%02x\n", addr); + + addr2 = (u8)addr; + + if (rv == 0) { + i4Status = MT_ATESetTxTargetPower(prNetDev, addr2); + }else{ + return -EINVAL; + } + + return i4Status; +} + +#if (CFG_SUPPORT_DFS_MASTER == 1) +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set RDD Report + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetRddReport(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 i4Status; + s32 rv; + int dbdcIdx; + u8 ucDbdcIdx; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, "MT6632 : ATE_AGENT iwpriv Set RDD Report, buf: %s\n", + prInBuf); + + /* rv = sscanf(prInBuf, "%u", &addr);*/ + rv = kstrtoint(prInBuf, 0, &dbdcIdx); + + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv Set RDD Report, prInBuf: %s\n", + prInBuf); + DBGLOG(INIT, ERROR, + "MT6632 : ATE_AGENT iwpriv Set RDD Report : Band %d\n", dbdcIdx); + + if (p2pFuncGetDfsState() == DFS_STATE_INACTIVE || + p2pFuncGetDfsState() == DFS_STATE_DETECTED) { + DBGLOG(REQ, + ERROR, + "RDD Report is not supported in this DFS state (inactive or deteted)\n"); + return WLAN_STATUS_NOT_SUPPORTED; + } + + if (dbdcIdx != 0 && dbdcIdx != 1) { + DBGLOG(REQ, ERROR, + "RDD index is not \"0\" or \"1\", Invalid data\n"); + return WLAN_STATUS_INVALID_DATA; + } + + ucDbdcIdx = (u8)dbdcIdx; + + if (rv == 0) { + i4Status = MT_ATESetRddReport(prNetDev, ucDbdcIdx); + }else{ + return -EINVAL; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set By Pass CAC. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetByPassCac(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 i4Status; + s32 rv; + s32 i4ByPassCacTime; + u32 u4ByPassCacTime; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv Set By Pass Cac, buf: %s\n", prInBuf); + + rv = kstrtoint(prInBuf, 0, &i4ByPassCacTime); + + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv Set By Pass Cac, prInBuf: %s\n", + prInBuf); + DBGLOG(INIT, ERROR, + "MT6632 : ATE_AGENT iwpriv Set By Pass Cac : %dsec\n", + i4ByPassCacTime); + + if (i4ByPassCacTime < 0) { + DBGLOG(REQ, ERROR, "Cac time < 0, Invalid data\n"); + return WLAN_STATUS_INVALID_DATA; + } + + u4ByPassCacTime = (u32)i4ByPassCacTime; + + p2pFuncEnableManualCac(); + + if (rv == 0) { + i4Status = p2pFuncSetDriverCacTime(u4ByPassCacTime); + }else{ + return -EINVAL; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to Set Radar Detect Mode. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int SetRadarDetectMode(struct net_device *prNetDev, u8 *prInBuf) +{ + s32 i4Status; + s32 rv; + int radarDetectMode; + u8 ucRadarDetectMode; + + if (prInBuf == NULL) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv Set Radar Detect Mode, buf: %s\n", + prInBuf); + + rv = kstrtoint(prInBuf, 0, &radarDetectMode); + + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv Set Radar Detect Mode, prInBuf: %s\n", + prInBuf); + DBGLOG(INIT, + ERROR, + "MT6632 : ATE_AGENT iwpriv Set Radar Detect Mode : %d\n", + radarDetectMode); + + if (p2pFuncGetDfsState() == DFS_STATE_INACTIVE || + p2pFuncGetDfsState() == DFS_STATE_DETECTED) { + DBGLOG(REQ, + ERROR, + "RDD Report is not supported in this DFS state (inactive or deteted)\n"); + return WLAN_STATUS_NOT_SUPPORTED; + } + + if (radarDetectMode != 0 && radarDetectMode != 1) { + DBGLOG(REQ, ERROR, + "Radar Detect Mode is not \"0\" or \"1\", Invalid data\n"); + return WLAN_STATUS_INVALID_DATA; + } + + ucRadarDetectMode = (u8)radarDetectMode; + + p2pFuncSetRadarDetectMode(ucRadarDetectMode); + + if (rv == 0) { + i4Status = + MT_ATESetRadarDetectMode(prNetDev, ucRadarDetectMode); + } else { + return -EINVAL; + } + + return i4Status; +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to search the corresponding ATE agent + * function. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf A pointer to the command string buffer + * \param[in] u4InBufLen The length of the buffer + * \param[out] None + * + * \retval 0 On success. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +int AteCmdSetHandle(struct net_device *prNetDev, u8 *prInBuf, u32 u4InBufLen) +{ + u8 *this_char, *value; + P_ATE_PRIV_CMD prAtePrivCmd; + s32 i4Status = 0; + + if (prInBuf == NULL) { + return -EINVAL; + } + + while ((this_char = strsep((char **)&prInBuf, ",")) != NULL) { + if (!*this_char) { + continue; + } + DBGLOG(RFTEST, ERROR, + "MT6632 : ATE_AGENT iwpriv this_char = %s\n", this_char); + DBGLOG(RFTEST, INFO, + "MT6632 : ATE_AGENT iwpriv this_char = %s\n", this_char); + + value = strchr(this_char, '='); + if (value != NULL) { + *value++ = 0; + } + + DBGLOG(REQ, INFO, + "MT6632 : ATE_AGENT iwpriv cmd = %s, value = %s\n", + this_char, value); + + for (prAtePrivCmd = rAtePrivCmdTable; prAtePrivCmd->name; + prAtePrivCmd++) { + if (!strcmp(this_char, prAtePrivCmd->name)) { + /*false:Set private failed then return Invalid + * argument */ + if (prAtePrivCmd->set_proc(prNetDev, value) != + 0) { + i4Status = -EINVAL; + } + break; /*Exit for loop. */ + } + } + + if (prAtePrivCmd->name == NULL) { /*Not found argument */ + i4Status = -EINVAL; + break; + } + } + return i4Status; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_cfg80211.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_cfg80211.c new file mode 100644 index 00000000000000..2019a066f62e79 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_cfg80211.c @@ -0,0 +1,5718 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_cfg80211.c + * \brief Main routines for supporintg MT6620 cfg80211 control interface + * + * This file contains the support routines of Linux driver for MediaTek Inc. + * 802.11 Wireless LAN Adapters. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "gl_os.h" +#include "debug.h" +#include "wlan_lib.h" +#include "gl_wext.h" +#include "precomp.h" +#include <linux/can/netlink.h> +#include <net/netlink.h> +#include <net/cfg80211.h> +#include "gl_cfg80211.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for change STA type between + * 1. Infrastructure Client (Non-AP STA) + * 2. Ad-Hoc IBSS + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE +int mtk_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, + enum nl80211_iftype type, + struct vif_params *params) +#else +int mtk_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +#endif +{ + P_GLUE_INFO_T prGlueInfo = NULL; + ENUM_PARAM_OP_MODE_T eOpMode; +#if !DBG_DISABLE_ALL_LOG + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen; +#endif + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + if (type == NL80211_IFTYPE_STATION) { + eOpMode = NET_TYPE_INFRA; + } else if (type == NL80211_IFTYPE_ADHOC) { + eOpMode = NET_TYPE_IBSS; + } else { + return -EINVAL; + } + +#if !DBG_DISABLE_ALL_LOG + rStatus = kalIoctl(prGlueInfo, wlanoidSetInfrastructureMode, &eOpMode, + sizeof(eOpMode), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set infrastructure mode error:%lx\n", rStatus); + } +#endif + + /* reset wpa info */ + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4KeyMgmt = 0; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; +#if CFG_SUPPORT_802_11W + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; + prGlueInfo->rWpaInfo.ucRSNMfpCap = 0; + prGlueInfo->rWpaInfo.u4CipherGroupMgmt = IW_AUTH_CIPHER_NONE; +#endif + + ndev->ieee80211_ptr->iftype = type; + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for adding key + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + int link_id, +#endif + u8 key_index, bool pairwise, const u8 *mac_addr, + struct key_params *params) +{ + PARAM_KEY_T rKey; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + s32 i4Rslt = -EINVAL; + u32 u4BufLen = 0; + u8 tmp1[8], tmp2[8]; +#if CFG_SUPPORT_REPLAY_DETECTION + P_BSS_INFO_T prBssInfo = NULL; + struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL; + u8 ucCheckZeroKey = 0; + u8 i = 0; +#endif + + const u8 aucBCAddr[] = BC_MAC_ADDR; + /* const u8 aucZeroMacAddr[] = NULL_MAC_ADDR; */ + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + +#if DBG + DBGLOG(RSN, INFO, "mtk_cfg80211_add_key\n"); + if (mac_addr) { + DBGLOG(RSN, INFO, "keyIdx = %d pairwise = %d mac = " MACSTR "\n", + key_index, pairwise, MAC2STR(mac_addr)); + } else { + DBGLOG(RSN, INFO, "keyIdx = %d pairwise = %d null mac\n", key_index, + pairwise); + } + DBGLOG(RSN, INFO, "Cipher = %x\n", params->cipher); + DBGLOG_MEM8(RSN, INFO, params->key, params->key_len); +#endif + + kalMemZero(&rKey, sizeof(PARAM_KEY_T)); + + rKey.u4KeyIndex = key_index; + + if (params->cipher) { + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + rKey.ucCipher = CIPHER_SUITE_WEP40; + break; + + case WLAN_CIPHER_SUITE_WEP104: + rKey.ucCipher = CIPHER_SUITE_WEP104; + break; + + case WLAN_CIPHER_SUITE_TKIP: + rKey.ucCipher = CIPHER_SUITE_TKIP; + break; + + case WLAN_CIPHER_SUITE_CCMP: + rKey.ucCipher = CIPHER_SUITE_CCMP; + break; + + case WLAN_CIPHER_SUITE_SMS4: + rKey.ucCipher = CIPHER_SUITE_WPI; + break; + + case WLAN_CIPHER_SUITE_AES_CMAC: + rKey.ucCipher = CIPHER_SUITE_BIP; + break; + + default: + ASSERT(false); + } + } + + if (pairwise) { + ASSERT(mac_addr); + rKey.u4KeyIndex |= BIT(31); + rKey.u4KeyIndex |= BIT(30); + COPY_MAC_ADDR(rKey.arBSSID, mac_addr); + + /* reset KCK, KEK, EAPOL Replay counter */ + kalMemZero(prGlueInfo->rWpaInfo.aucKek, NL80211_KEK_LEN); + kalMemZero(prGlueInfo->rWpaInfo.aucKck, NL80211_KCK_LEN); + kalMemZero(prGlueInfo->rWpaInfo.aucReplayCtr, NL80211_REPLAY_CTR_LEN); + } else { /* Group key */ + COPY_MAC_ADDR(rKey.arBSSID, aucBCAddr); +#if CFG_KEY_ERROR_STATISTIC_RECOVERY + RX_RESET_CNT(&prGlueInfo->prAdapter->rRxCtrl, RX_BMC_NO_KEY_COUNT); + RX_RESET_CNT(&prGlueInfo->prAdapter->rRxCtrl, RX_BMC_KEY_ERROR_COUNT); + RX_RESET_CNT(&prGlueInfo->prAdapter->rRxCtrl, RX_BMC_PKT_COUNT); +#endif + } + + if (params->key) { +#if CFG_SUPPORT_REPLAY_DETECTION + for (i = 0; i < params->key_len; i++) + if (params->key[i] == 0x00) { + ucCheckZeroKey++; + } + + if (ucCheckZeroKey == params->key_len) { + return 0; + } + +#endif + + if (params->key_len > sizeof(rKey.aucKeyMaterial)) { + return -EINVAL; + } + + kalMemCopy(rKey.aucKeyMaterial, params->key, params->key_len); + if (rKey.ucCipher == CIPHER_SUITE_TKIP) { + kalMemCopy(tmp1, ¶ms->key[16], 8); + kalMemCopy(tmp2, ¶ms->key[24], 8); + kalMemCopy(&rKey.aucKeyMaterial[16], tmp2, 8); + kalMemCopy(&rKey.aucKeyMaterial[24], tmp1, 8); + } + } + + rKey.ucBssIdx = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + + rKey.u4KeyLength = params->key_len; + rKey.u4Length = ((unsigned long)&(((P_PARAM_KEY_T)0)->aucKeyMaterial)) + + rKey.u4KeyLength; + +#if CFG_SUPPORT_REPLAY_DETECTION + prBssInfo = GET_BSS_INFO_BY_INDEX( + prGlueInfo->prAdapter, prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + + prDetRplyInfo = &prBssInfo->rDetRplyInfo; + + if ((!pairwise) && ((params->cipher == WLAN_CIPHER_SUITE_TKIP) || + (params->cipher == WLAN_CIPHER_SUITE_CCMP))) { + if ((prDetRplyInfo->ucCurKeyId == key_index) && + (!kalMemCmp(prDetRplyInfo->aucKeyMaterial, params->key, + params->key_len))) { + DBGLOG(RSN, TRACE, "M3/G1, KeyID and KeyValue equal.\n"); + DBGLOG(RSN, TRACE, + "hit group key reinstall case, so no update BC/MC PN.\n"); + } else { + kalMemCopy(prDetRplyInfo->arReplayPNInfo[key_index].auPN, + params->seq, params->seq_len); + prDetRplyInfo->ucCurKeyId = key_index; + prDetRplyInfo->u4KeyLength = params->key_len; + kalMemCopy(prDetRplyInfo->aucKeyMaterial, params->key, + params->key_len); + } + + prDetRplyInfo->fgKeyRscFresh = true; + } +#endif + + rStatus = kalIoctl(prGlueInfo, wlanoidSetAddKey, &rKey, rKey.u4Length, + false, false, true, &u4BufLen); + + if (rStatus == WLAN_STATUS_SUCCESS) { + i4Rslt = 0; + } + + return i4Rslt; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for getting key for specified STA + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + int link_id, +#endif + u8 key_index, bool pairwise, const u8 *mac_addr, + void *cookie, + void (*callback)(void *cookie, struct key_params *)) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + DBGLOG(INIT, INFO, "--> %s()\n", __func__); + + /* not implemented */ + + return -EINVAL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for removing key for specified STA + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + int link_id, +#endif + u8 key_index, bool pairwise, const u8 *mac_addr) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4Rslt = -EINVAL; + u8 ucBssIndex = 0; + u32 waitRet = 0; + P_BSS_INFO_T prBssInfo; + PARAM_REMOVE_KEY_T rRemoveKey; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + +#if DBG + DBGLOG(RSN, TRACE, "mtk_cfg80211_del_key\n"); + if (mac_addr) { + DBGLOG(RSN, TRACE, "keyIdx = %d pairwise = %d mac = " MACSTR "\n", + key_index, pairwise, MAC2STR(mac_addr)); + } else { + DBGLOG(RSN, TRACE, "keyIdx = %d pairwise = %d null mac\n", key_index, + pairwise); + } +#endif + + kalMemZero(&rRemoveKey, sizeof(PARAM_REMOVE_KEY_T)); + rRemoveKey.u4KeyIndex = key_index; + rRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); + if (mac_addr) { + COPY_MAC_ADDR(rRemoveKey.arBSSID, mac_addr); + rRemoveKey.u4KeyIndex |= BIT(30); + } + if ((prGlueInfo->prAdapter == NULL) || + (prGlueInfo->prAdapter->prAisBssInfo == NULL)) { + return i4Rslt; + } + + rRemoveKey.ucBssIdx = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, ucBssIndex); + +#if CFG_SUPPORT_802_11W + /* if encrypted deauth frame is in process, pending remove key */ + if (IS_BSS_INDEX_AIS(prGlueInfo->prAdapter, ucBssIndex) && + prBssInfo->encryptedDeauthIsInProcess == true) { + waitRet = wait_for_completion_timeout(&prBssInfo->rDeauthComp, + MSEC_TO_JIFFIES(1000)); + if (!waitRet) { + DBGLOG(RSN, INFO, "timeout\n"); + prBssInfo->encryptedDeauthIsInProcess = false; + } else { + DBGLOG(RSN, INFO, "complete\n"); + } + } +#endif + + rStatus = kalIoctl(prGlueInfo, wlanoidSetRemoveKey, &rRemoveKey, + rRemoveKey.u4Length, false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(RSN, WARN, "remove key error:%lx\n", rStatus); + } else { + i4Rslt = 0; + } + + return i4Rslt; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for setting default key on an interface + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + int link_id, +#endif + u8 key_index, bool unicast, bool multicast) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_DEFAULT_KEY_T rDefaultKey; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + s32 i4Rst = -EINVAL; + u32 u4BufLen = 0; + u8 fgDef = false, fgMgtDef = false; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + /* For STA, should wep set the default key !! */ +#if DBG + DBGLOG(RSN, INFO, "mtk_cfg80211_set_default_key\n"); + DBGLOG(RSN, INFO, "keyIdx = %d unicast = %d multicast = %d\n", key_index, + unicast, multicast); +#endif + + rDefaultKey.ucKeyID = key_index; + rDefaultKey.ucUnicast = unicast; + rDefaultKey.ucMulticast = multicast; + if (rDefaultKey.ucUnicast && !rDefaultKey.ucMulticast) { + return WLAN_STATUS_SUCCESS; + } + + if (rDefaultKey.ucUnicast && rDefaultKey.ucMulticast) { + fgDef = true; + } + + if (!rDefaultKey.ucUnicast && rDefaultKey.ucMulticast) { + fgMgtDef = true; + } + + rDefaultKey.ucBssIdx = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetDefaultKey, &rDefaultKey, + sizeof(PARAM_DEFAULT_KEY_T), false, false, true, + &u4BufLen); + if (rStatus == WLAN_STATUS_SUCCESS) { + i4Rst = 0; + } + + return i4Rst; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for getting station information such as + * RSSI + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_info *sinfo) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + PARAM_MAC_ADDRESS arBssid; + u32 u4BufLen, u4Rate; + s32 i4Rssi; + PARAM_GET_STA_STATISTICS rQueryStaStatistics; + u32 u4TotalError; + struct net_device_stats *prDevStats; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + kalMemZero(arBssid, MAC_ADDR_LEN); + wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, &arBssid[0], + sizeof(arBssid), &u4BufLen); + + /* 1. check input MAC address */ + /* On Android O, this might be wlan0 address */ + if (UNEQUAL_MAC_ADDR(arBssid, mac) && + UNEQUAL_MAC_ADDR(prGlueInfo->prAdapter->rWifiVar.aucMacAddress, mac)) { + /* wrong MAC address */ + DBGLOG(REQ, WARN, + "incorrect BSSID: [" MACSTR "] currently connected BSSID[" MACSTR + "]\n", + MAC2STR(mac), MAC2STR(arBssid)); + + return -ENOENT; + } + + /* 2. fill TX rate */ + if (prGlueInfo->eParamMediaStateIndicated != PARAM_MEDIA_STATE_CONNECTED) { + /* not connected */ + DBGLOG(REQ, WARN, "not yet connected\n"); + } else { + rStatus = kalIoctl(prGlueInfo, wlanoidQueryLinkSpeed, &u4Rate, + sizeof(u4Rate), true, false, false, &u4BufLen); + + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); + + if ((rStatus != WLAN_STATUS_SUCCESS) || (u4Rate == 0)) { + /* + * DBGLOG(REQ, WARN, "unable to retrieve link + * speed\n")); + */ + DBGLOG(REQ, WARN, "last link speed\n"); + sinfo->txrate.legacy = prGlueInfo->u4LinkSpeedCache; + } else { + /* + * sinfo->filled |= STATION_INFO_TX_BITRATE; + */ + sinfo->txrate.legacy = u4Rate / 1000; /* convert from + * 100bps to + * 100kbps */ + prGlueInfo->u4LinkSpeedCache = u4Rate / 1000; + } + } + + /* 3. fill RSSI */ + if (prGlueInfo->eParamMediaStateIndicated != PARAM_MEDIA_STATE_CONNECTED) { + /* not connected */ + DBGLOG(REQ, WARN, "not yet connected\n"); + } else { + rStatus = kalIoctl(prGlueInfo, wlanoidQueryRssi, &i4Rssi, + sizeof(i4Rssi), true, false, false, &u4BufLen); + + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + + if ((rStatus != WLAN_STATUS_SUCCESS) || + (i4Rssi == PARAM_WHQL_RSSI_MIN_DBM) || + (i4Rssi == PARAM_WHQL_RSSI_MAX_DBM)) { + DBGLOG(REQ, WARN, "last rssi\n"); + sinfo->signal = prGlueInfo->i4RssiCache; + } else { + sinfo->signal = i4Rssi; /* dBm */ + prGlueInfo->i4RssiCache = i4Rssi; + } + } + + /* Get statistics from net_dev */ + prDevStats = (struct net_device_stats *)kalGetStats(ndev); + + if (prDevStats) { + /* 4. fill RX_PACKETS */ + sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS); + + sinfo->rx_packets = prDevStats->rx_packets; + + /* 5. fill TX_PACKETS */ + sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS); + + sinfo->tx_packets = prDevStats->tx_packets; + + /* 6. fill TX_FAILED */ + kalMemZero(&rQueryStaStatistics, sizeof(rQueryStaStatistics)); + COPY_MAC_ADDR(rQueryStaStatistics.aucMacAddr, arBssid); + rQueryStaStatistics.ucReadClear = true; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryStaStatistics, + &rQueryStaStatistics, sizeof(rQueryStaStatistics), + true, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, + "unable to retrieve link speed,status code = %d\n", rStatus); + } else { + DBGLOG(REQ, INFO, + "BSSID: [" MACSTR "] TxFailCount %d LifeTimeOut %d\n", + MAC2STR(arBssid), rQueryStaStatistics.u4TxFailCount, + rQueryStaStatistics.u4TxLifeTimeoutCount); + + u4TotalError = rQueryStaStatistics.u4TxFailCount + + rQueryStaStatistics.u4TxLifeTimeoutCount; + prDevStats->tx_errors += u4TotalError; + } + sinfo->filled |= BIT(NL80211_STA_INFO_TX_FAILED); + sinfo->tx_failed = prDevStats->tx_errors; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for getting statistics for Link layer + * statistics + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*------------------------------------------------------------------------*/ +int mtk_cfg80211_get_link_statistics(struct wiphy *wiphy, + struct net_device *ndev, u8 *mac, + struct station_info *sinfo) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + PARAM_MAC_ADDRESS arBssid; + u32 u4BufLen; + s32 i4Rssi; + PARAM_GET_STA_STATISTICS rQueryStaStatistics; + PARAM_GET_BSS_STATISTICS rQueryBssStatistics; + struct net_device_stats *prDevStats; + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = + (P_NETDEV_PRIVATE_GLUE_INFO)NULL; + u8 ucBssIndex; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + kalMemZero(arBssid, MAC_ADDR_LEN); + wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, &arBssid[0], + sizeof(arBssid), &u4BufLen); + + /* 1. check BSSID */ + if (UNEQUAL_MAC_ADDR(arBssid, mac)) { + /* wrong MAC address */ + DBGLOG(REQ, WARN, + "incorrect BSSID: [" MACSTR "] currently connected BSSID[" MACSTR + "]\n", + MAC2STR(mac), MAC2STR(arBssid)); + return -ENOENT; + } + + /* 2. fill RSSI */ + if (prGlueInfo->eParamMediaStateIndicated != PARAM_MEDIA_STATE_CONNECTED) { + /* not connected */ + DBGLOG(REQ, WARN, "not yet connected\n"); + } else { + rStatus = kalIoctl(prGlueInfo, wlanoidQueryRssi, &i4Rssi, + sizeof(i4Rssi), true, false, false, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "unable to retrieve rssi\n"); + } + } + + /* Get statistics from net_dev */ + prDevStats = (struct net_device_stats *)kalGetStats(ndev); + + /*3. get link layer statistics from Driver and FW */ + if (prDevStats) { + /* 3.1 get per-STA link statistics */ + kalMemZero(&rQueryStaStatistics, sizeof(rQueryStaStatistics)); + COPY_MAC_ADDR(rQueryStaStatistics.aucMacAddr, arBssid); + rQueryStaStatistics.ucLlsReadClear = false; /* dont clear for + * get BSS statistic + */ + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryStaStatistics, + &rQueryStaStatistics, sizeof(rQueryStaStatistics), + true, false, true, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "unable to retrieve per-STA link statistics\n"); + } + + /*3.2 get per-BSS link statistics */ + if (rStatus == WLAN_STATUS_SUCCESS) { + /* get Bss Index from ndev */ + prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(ndev); + ASSERT(prNetDevPrivate->prGlueInfo == prGlueInfo); + ucBssIndex = prNetDevPrivate->ucBssIdx; + + kalMemZero(&rQueryBssStatistics, sizeof(rQueryBssStatistics)); + rQueryBssStatistics.ucBssIndex = ucBssIndex; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryBssStatistics, + &rQueryBssStatistics, + sizeof(rQueryBssStatistics), true, false, true, + &u4BufLen); + } else { + DBGLOG(REQ, WARN, "unable to retrieve per-BSS link statistics\n"); + } + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to do a scan + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + u32 i, u4BufLen; + PARAM_SCAN_REQUEST_ADV_T rScanRequest; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + kalMemZero(&rScanRequest, sizeof(rScanRequest)); + + /* check if there is any pending scan/sched_scan not yet finished */ + if (prGlueInfo->prScanRequest != NULL) { + return -EBUSY; + } + + if (request->n_ssids == 0) { + rScanRequest.u4SsidNum = 0; + } else if (request->n_ssids <= SCN_SSID_MAX_NUM) { + rScanRequest.u4SsidNum = request->n_ssids; + + for (i = 0; i < request->n_ssids; i++) { + COPY_SSID(rScanRequest.rSsid[i].aucSsid, + rScanRequest.rSsid[i].u4SsidLen, request->ssids[i].ssid, + request->ssids[i].ssid_len); + } + } else { + return -EINVAL; + } + + rScanRequest.u4IELength = request->ie_len; + if (request->ie_len > 0) { + rScanRequest.pucIE = (u8 *)(request->ie); + } + +#if CFG_SCAN_CHANNEL_SPECIFIED + DBGLOG(REQ, WARN, "scan channel num = %d\n", request->n_channels); + + if (request->n_channels > MAXIMUM_OPERATION_CHANNEL_LIST) { + DBGLOG(REQ, WARN, + "scan channel num (%d) exceeds %d, do a full scan instead\n", + request->n_channels, MAXIMUM_OPERATION_CHANNEL_LIST); + rScanRequest.ucChannelListNum = 0; + } else { + rScanRequest.ucChannelListNum = request->n_channels; + for (i = 0; i < request->n_channels; i++) { + rScanRequest.arChnlInfoList[i].eBand = + kalCfg80211ToMtkBand(request->channels[i]->band); + rScanRequest.arChnlInfoList[i].u4CenterFreq1 = + request->channels[i]->center_freq; + rScanRequest.arChnlInfoList[i].u4CenterFreq2 = 0; + rScanRequest.arChnlInfoList[i].u2PriChnlFreq = + request->channels[i]->center_freq; +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0) + rScanRequest.arChnlInfoList[i].ucChnlBw = request->scan_width; +#else + rScanRequest.arChnlInfoList[i].ucChnlBw = 0; +#endif + rScanRequest.arChnlInfoList[i].ucChannelNum = + ieee80211_frequency_to_channel( + request->channels[i]->center_freq); + } + } +#endif + + /* 2018/04/18 frog: The point should be ready before doing IOCTL. */ + prGlueInfo->prScanRequest = request; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetBssidListScanAdv, &rScanRequest, + sizeof(PARAM_SCAN_REQUEST_ADV_T), false, false, false, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "scan error:%lx\n", rStatus); + /* 2018/04/18 frog: Remove pointer if IOCTL fail. */ + prGlueInfo->prScanRequest = NULL; + + return -EINVAL; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for abort an ongoing scan. The driver + * shall indicate the status of the scan through cfg80211_scan_done() + * + * @param wiphy - pointer of wireless hardware description + * wdev - pointer of wireless device state + * + */ +/*----------------------------------------------------------------------------*/ +void mtk_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + u32 u4SetInfoLen = 0; + WLAN_STATUS rStatus; + P_GLUE_INFO_T prGlueInfo = NULL; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, wlanoidAbortScan, NULL, 1, false, false, + true, &u4SetInfoLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "wlanoidAbortScan fail 0x%x\n", rStatus); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting auth to + * the ESS with the specified parameters + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_auth(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_auth_request *req) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u32 rStatus; + u32 u4BufLen; + PARAM_CONNECT_T rNewSsid; + ENUM_PARAM_OP_MODE_T eOpMode; + u8 wepBuf[48]; + P_CONNECTION_SETTINGS_T prConnSettings = NULL; +#if CFG_SUPPORT_REPLAY_DETECTION + P_BSS_INFO_T prBssInfo = NULL; + struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL; +#endif + P_PARAM_WEP_T prWepKey; + /*Is auth parameter needed to be updated to AIS.*/ + u8 fgNewAuthParam = false; + P_STA_RECORD_T prStaRec = NULL; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + +#if KERNEL_VERSION(4, 9, 113) >= CFG80211_VERSION_CODE + if (req->sae_data_len != 0) { + DBGLOG(REQ, INFO, "[wlan] mtk_cfg80211_auth %p %zu\n", req->sae_data, + req->sae_data_len); + } +#else + if (req->auth_data_len != 0) { + DBGLOG(REQ, INFO, "[wlan] mtk_cfg80211_auth %p %zu\n", req->auth_data, + req->auth_data_len); + } +#endif + DBGLOG(REQ, STATE, "auth to BSS [" MACSTR "]\n", + MAC2STR((u8 *)req->bss->bssid)); + DBGLOG(REQ, STATE, "auth_type:%d\n", req->auth_type); + + prConnSettings = &prGlueInfo->prAdapter->rWifiVar.rConnSettings; + + /* <1>Set OP mode */ + if (prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode > + NET_TYPE_AUTO_SWITCH) { + eOpMode = NET_TYPE_AUTO_SWITCH; + } else { + eOpMode = prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetInfrastructureMode, &eOpMode, + sizeof(eOpMode), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "wlanoidSetInfrastructureMode fail 0x%x\n", rStatus); + return -EFAULT; + } + + /*<2> Set Auth data */ + prConnSettings->ucAuthDataLen = 0; +#if KERNEL_VERSION(4, 9, 113) >= CFG80211_VERSION_CODE + if (req->sae_data_len != 0) { + if (req->sae_data_len > AUTH_DATA_MAX_LEN) { + DBGLOG(INIT, WARN, "request auth with unexpected length:%d\n", + req->sae_data_len); + return -EFAULT; + } + + kalMemCopy(prConnSettings->aucAuthData, req->sae_data, + req->sae_data_len); + prConnSettings->ucAuthDataLen = req->sae_data_len; + + DBGLOG(INIT, INFO, "Dump auth data in connectSettings, auth len:%d\n", + prConnSettings->ucAuthDataLen); + DBGLOG_MEM8(REQ, INFO, prConnSettings->aucAuthData, req->sae_data_len); + } +#else + if (req->auth_data_len != 0) { + if (req->auth_data_len > AUTH_DATA_MAX_LEN) { + DBGLOG(INIT, WARN, "request auth with unexpected length:%d\n", + req->auth_data_len); + return -EFAULT; + } + + kalMemCopy(prConnSettings->aucAuthData, req->auth_data, + req->auth_data_len); + prConnSettings->ucAuthDataLen = req->auth_data_len; + + DBGLOG(INIT, INFO, "Dump auth data in connectSettings, auth len:%d\n", + prConnSettings->ucAuthDataLen); + DBGLOG_MEM8(REQ, INFO, prConnSettings->aucAuthData, req->auth_data_len); + } +#endif + /*<2> Set ChannelNum */ + if (req->bss->channel->center_freq) { + prConnSettings->ucChannelNum = + nicFreq2ChannelNum(req->bss->channel->center_freq * 1000); + DBGLOG(RSN, INFO, "set prConnSettings->ucChannelNum:%d\n", + prConnSettings->ucChannelNum); + } else { + prConnSettings->ucChannelNum = 0; + DBGLOG(RSN, INFO, "req->bss->channel->center_freq is NULL.\n"); + } + +#if CFG_SUPPORT_REPLAY_DETECTION + /* reset Detect replay information */ + prBssInfo = GET_BSS_INFO_BY_INDEX( + prGlueInfo->prAdapter, prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + + prDetRplyInfo = &prBssInfo->rDetRplyInfo; + + kalMemZero(prDetRplyInfo, sizeof(struct SEC_DETECT_REPLAY_INFO)); +#endif + + switch (req->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + if (!(prGlueInfo->rWpaInfo.u4AuthAlg & AUTH_TYPE_OPEN_SYSTEM)) { + fgNewAuthParam = true; + } + prGlueInfo->rWpaInfo.u4AuthAlg = AUTH_TYPE_OPEN_SYSTEM; + break; + + case NL80211_AUTHTYPE_SHARED_KEY: + if (!(prGlueInfo->rWpaInfo.u4AuthAlg & AUTH_TYPE_SHARED_KEY)) { + fgNewAuthParam = true; + } + prGlueInfo->rWpaInfo.u4AuthAlg = AUTH_TYPE_SHARED_KEY; + break; + + case NL80211_AUTHTYPE_SAE: + if (!(prGlueInfo->rWpaInfo.u4AuthAlg & AUTH_TYPE_SAE)) { + fgNewAuthParam = true; + } + prGlueInfo->rWpaInfo.u4AuthAlg = AUTH_TYPE_SAE; + break; + + default: + DBGLOG(REQ, WARN, + "Auth type: %ld not support, use default OPEN system\n", + req->auth_type); + prGlueInfo->rWpaInfo.u4AuthAlg = AUTH_TYPE_OPEN_SYSTEM; + break; + } + DBGLOG(REQ, INFO, "Auth Algorithm : %ld\n", prGlueInfo->rWpaInfo.u4AuthAlg); + + if (req->key_len != 0) { + /* NL80211 only set the Tx wep key while connect, + * the max 4 wep key set prior via add key cmd + */ + + if (!(prGlueInfo->rWpaInfo.u4AuthAlg & AUTH_TYPE_SHARED_KEY)) { + DBGLOG(REQ, WARN, "Auth Algorithm : %ld with wep key\n", + prGlueInfo->rWpaInfo.u4AuthAlg); + } + + prWepKey = (P_PARAM_WEP_T)wepBuf; + + kalMemZero(prWepKey, sizeof(PARAM_WEP_T)); + prWepKey->u4Length = + OFFSET_OF(PARAM_WEP_T, aucKeyMaterial) + req->key_len; + prWepKey->u4KeyLength = (u32)req->key_len; + prWepKey->u4KeyIndex = (u32)req->key_idx; + prWepKey->u4KeyIndex |= IS_TRANSMIT_KEY; + if (prWepKey->u4KeyLength > MAX_KEY_LEN) { + DBGLOG(REQ, WARN, "Too long key length (%u)\n", + prWepKey->u4KeyLength); + return -EINVAL; + } + kalMemCopy(prWepKey->aucKeyMaterial, req->key, prWepKey->u4KeyLength); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetAddWep, prWepKey, + prWepKey->u4Length, false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "wlanoidSetAddWep fail 0x%x\n", rStatus); + return -EFAULT; + } + } + kalMemZero(&rNewSsid, sizeof(PARAM_CONNECT_T)); + rNewSsid.pucBssid = (u8 *)req->bss->bssid; + + if (!EQUAL_MAC_ADDR(prConnSettings->aucBSSID, req->bss->bssid)) { + fgNewAuthParam = true; + } + +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + DBGLOG(REQ, WARN, "req IE len %d, ssid %.*s, ssid_len %d\n", + req->bss->ies->len, SSID_IE(req->bss->ies->data)->ucLength, + SSID_IE(req->bss->ies->data)->aucSSID, + SSID_IE(req->bss->ies->data)->ucLength); + if (req->bss->ies->len != 0 && IE_ID(req->bss->ies->data) == ELEM_ID_SSID) { + rNewSsid.pucSsid = SSID_IE(req->bss->ies->data)->aucSSID; + rNewSsid.u4SsidLen = SSID_IE(req->bss->ies->data)->ucLength; + } +#endif + /* rNewSsid.pucSsid = (u8 *)sme->ssid;*/ + /* rNewSsid.u4SsidLen = sme->ssid_len;*/ + + DBGLOG(REQ, STATE, "auth to BSS [" MACSTR "],UpperReq [" MACSTR "]\n", + MAC2STR(rNewSsid.pucBssid), MAC2STR((u8 *)req->bss->bssid)); + + prConnSettings->fgIsSendAssoc = false; + if (!prConnSettings->fgIsConnInitialized || fgNewAuthParam) { + /* [TODO] to consider if bssid/auth_alg changed + * (need to update to AIS) + */ + if (!prConnSettings->fgIsConnInitialized && fgNewAuthParam) { + DBGLOG(REQ, INFO, "auth param update\n"); + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetConnect, (void *)&rNewSsid, + sizeof(PARAM_CONNECT_T), false, false, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set SSID:%x\n", rStatus); + return -EINVAL; + } + } else { + /* skip join initial flow + * when it has been completed with the same auth parameters + */ + prStaRec = cnmGetStaRecByAddress( + prGlueInfo->prAdapter, + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex, rNewSsid.pucBssid); + if (prStaRec) { + saaSendAuthAssoc(prGlueInfo->prAdapter, prStaRec); + DBGLOG(REQ, STATE, "Send auth \n"); + } else { + DBGLOG(REQ, WARN, "can't send auth since can't find StaRec\n"); + } + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to connect to + * the ESS with the specified parameters + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_connect_params *sme) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + u32 u4BufLen; + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + ENUM_PARAM_AUTH_MODE_T eAuthMode; + u32 cipher; + PARAM_CONNECT_T rNewSsid; + u8 fgCarryWPSIE = false; + ENUM_PARAM_OP_MODE_T eOpMode; + u8 wepBuf[48]; + u32 i, u4AkmSuite = 0; + P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry; +#if CFG_SUPPORT_REPLAY_DETECTION + P_BSS_INFO_T prBssInfo = NULL; + struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL; +#endif + + if (sme->channel) { + /* Prevents NULL pointer dereference if sme->channel is NULL */ + DBGLOG(REQ, WARN, "BSSID[" MACSTR "] channel[%d]\n", + MAC2STR(sme->bssid), sme->channel->center_freq); + } else { + DBGLOG(REQ, WARN, "BSSID[" MACSTR "] \n", MAC2STR(sme->bssid)); + } + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + if (prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode > + NET_TYPE_AUTO_SWITCH) { + eOpMode = NET_TYPE_AUTO_SWITCH; + } else { + eOpMode = prGlueInfo->prAdapter->rWifiVar.rConnSettings.eOPMode; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetInfrastructureMode, &eOpMode, + sizeof(eOpMode), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "wlanoidSetInfrastructureMode fail 0x%lx\n", + rStatus); + return -EFAULT; + } + + /* after set operation mode, key table are cleared */ + + /* reset wpa info */ + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4KeyMgmt = 0; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; + prGlueInfo->rWpaInfo.fgPrivacyInvoke = false; + +#if CFG_SUPPORT_REPLAY_DETECTION + /* reset Detect replay information */ + prBssInfo = GET_BSS_INFO_BY_INDEX( + prGlueInfo->prAdapter, prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + + prDetRplyInfo = &prBssInfo->rDetRplyInfo; + kalMemZero(prDetRplyInfo, sizeof(struct SEC_DETECT_REPLAY_INFO)); +#endif + +#if CFG_SUPPORT_802_11W + prGlueInfo->rWpaInfo.u4CipherGroupMgmt = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.ucRSNMfpCap = RSN_AUTH_MFP_DISABLED; + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; + switch (sme->mfp) { + case NL80211_MFP_NO: + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; + break; + + case NL80211_MFP_REQUIRED: + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_REQUIRED; + break; + + default: + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; + break; + } + /* DBGLOG(SCN, INFO, ("MFP=%d\n", prGlueInfo->rWpaInfo.u4Mfp)); */ +#endif + + if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) { + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_WPA; + } else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) { + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_WPA2; + } else { + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + } + + switch (sme->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; + break; + + case NL80211_AUTHTYPE_SHARED_KEY: + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY; + break; + + default: + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM | + IW_AUTH_ALG_SHARED_KEY; + break; + } + + if (sme->crypto.n_ciphers_pairwise) { + DBGLOG(RSN, INFO, "[wlan] cipher pairwise (%x)\n", + sme->crypto.ciphers_pairwise[0]); + + prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo + .au4PairwiseKeyCipherSuite[0] = sme->crypto.ciphers_pairwise[0]; + switch (sme->crypto.ciphers_pairwise[0]) { + case WLAN_CIPHER_SUITE_WEP40: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP40; + break; + + case WLAN_CIPHER_SUITE_WEP104: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104; + break; + + case WLAN_CIPHER_SUITE_TKIP: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_TKIP; + break; + + case WLAN_CIPHER_SUITE_CCMP: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_CCMP; + break; + + case WLAN_CIPHER_SUITE_AES_CMAC: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_CCMP; + break; + +#if CFG_SUPPORT_SUITB + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_GCMP256; + break; + + case WLAN_CIPHER_SUITE_GCMP_256: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_GCMP256; + break; + +#endif + default: + DBGLOG(REQ, WARN, "invalid cipher pairwise (%d)\n", + sme->crypto.ciphers_pairwise[0]); + return -EINVAL; + } + } + + if (sme->crypto.cipher_group) { + prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo + .u4GroupKeyCipherSuite = sme->crypto.cipher_group; + switch (sme->crypto.cipher_group) { + case WLAN_CIPHER_SUITE_WEP40: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP40; + break; + + case WLAN_CIPHER_SUITE_WEP104: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104; + break; + + case WLAN_CIPHER_SUITE_TKIP: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_TKIP; + break; + + case WLAN_CIPHER_SUITE_CCMP: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_CCMP; + break; + + case WLAN_CIPHER_SUITE_AES_CMAC: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_CCMP; + break; + +#if CFG_SUPPORT_SUITB + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_GCMP256; + break; + + case WLAN_CIPHER_SUITE_GCMP_256: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_GCMP256; + break; + + case WLAN_CIPHER_SUITE_NO_GROUP_ADDR: + break; + +#endif + default: + DBGLOG(REQ, WARN, "invalid cipher group (%d)\n", + sme->crypto.cipher_group); + return -EINVAL; + } + } + + /* DBGLOG(SCN, INFO, ("akm_suites=%x\n", sme->crypto.akm_suites[0])); */ + if (sme->crypto.n_akm_suites) { + prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo + .au4AuthKeyMgtSuite[0] = sme->crypto.akm_suites[0]; + if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + eAuthMode = AUTH_MODE_WPA; + u4AkmSuite = WPA_AKM_SUITE_802_1X; + break; + + case WLAN_AKM_SUITE_PSK: + eAuthMode = AUTH_MODE_WPA_PSK; + u4AkmSuite = WPA_AKM_SUITE_PSK; + break; + + default: + DBGLOG(REQ, WARN, "invalid Akm Suite (%d)\n", + sme->crypto.akm_suites[0]); + return -EINVAL; + } + } else if (prGlueInfo->rWpaInfo.u4WpaVersion == + IW_AUTH_WPA_VERSION_WPA2) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + eAuthMode = AUTH_MODE_WPA2; + u4AkmSuite = RSN_AKM_SUITE_802_1X; + break; + + case WLAN_AKM_SUITE_FT_PSK: + case WLAN_AKM_SUITE_PSK: + eAuthMode = AUTH_MODE_WPA2_PSK; + u4AkmSuite = RSN_AKM_SUITE_PSK; + break; + +#if CFG_SUPPORT_802_11W + /* Notice:: Need kernel patch!! */ + case WLAN_AKM_SUITE_8021X_SHA256: + eAuthMode = AUTH_MODE_WPA2; + u4AkmSuite = RSN_AKM_SUITE_802_1X_SHA256; + break; + + case WLAN_AKM_SUITE_PSK_SHA256: + eAuthMode = AUTH_MODE_WPA2_PSK; + u4AkmSuite = RSN_AKM_SUITE_PSK_SHA256; + break; + +#endif +#if CFG_SUPPORT_SUITB + case WLAN_AKM_SUITE_8021X_SUITE_B: + eAuthMode = AUTH_MODE_WPA2_PSK; + u4AkmSuite = RSN_AKM_SUITE_8021X_SUITE_B_192; + break; + + case WLAN_AKM_SUITE_8021X_SUITE_B_192: + eAuthMode = AUTH_MODE_WPA2_PSK; + u4AkmSuite = RSN_AKM_SUITE_8021X_SUITE_B_192; + break; + +#endif +#if CFG_SUPPORT_OWE + case WLAN_AKM_SUITE_OWE: + eAuthMode = AUTH_MODE_WPA2_PSK; + u4AkmSuite = RSN_AKM_SUITE_OWE; + break; + +#endif + default: + DBGLOG(REQ, WARN, "invalid Akm Suite (%d)\n", + sme->crypto.akm_suites[0]); + return -EINVAL; + } + } + } + + if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { + eAuthMode = + (prGlueInfo->rWpaInfo.u4AuthAlg == IW_AUTH_ALG_OPEN_SYSTEM) ? + AUTH_MODE_OPEN : + AUTH_MODE_AUTO_SWITCH; + } + + prGlueInfo->rWpaInfo.fgPrivacyInvoke = sme->privacy; + prGlueInfo->fgWpsActive = false; + + if (sme->ie && sme->ie_len > 0) { + WLAN_STATUS rStatus; + u32 u4BufLen; + u8 *prDesiredIE = NULL; + u8 *pucIEStart = (u8 *)sme->ie; + +#if CFG_SUPPORT_WPS2 + if (wextSrchDesiredWPSIE(pucIEStart, sme->ie_len, 0xDD, + (u8 **)&prDesiredIE)) { + prGlueInfo->fgWpsActive = true; + fgCarryWPSIE = true; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetWSCAssocInfo, prDesiredIE, + IE_SIZE(prDesiredIE), false, false, false, + &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(SEC, WARN, "[WSC] set WSC assoc info error:%lx\n", + rStatus); + } + } +#endif + + if (wextSrchDesiredWPAIE(pucIEStart, sme->ie_len, 0x30, + (u8 **)&prDesiredIE)) { + RSN_INFO_T rRsnInfo; + + if (rsnParseRsnIE(prGlueInfo->prAdapter, + (P_RSN_INFO_ELEM_T)prDesiredIE, &rRsnInfo)) { +#if CFG_SUPPORT_802_11W + /* Fill RSNE MFP Cap */ + if (rRsnInfo.u2RsnCap & ELEM_WPA_CAP_MFPC) { + prGlueInfo->rWpaInfo.u4CipherGroupMgmt = + rRsnInfo.u4GroupMgmtKeyCipherSuite; + prGlueInfo->rWpaInfo.ucRSNMfpCap = RSN_AUTH_MFP_OPTIONAL; + if (rRsnInfo.u2RsnCap & ELEM_WPA_CAP_MFPR) { + prGlueInfo->rWpaInfo.ucRSNMfpCap = + RSN_AUTH_MFP_REQUIRED; + } + } else { + prGlueInfo->rWpaInfo.ucRSNMfpCap = RSN_AUTH_MFP_DISABLED; + } +#endif + } + } + } + + /* clear WSC Assoc IE buffer in case WPS IE is not detected */ + if (fgCarryWPSIE == false) { + kalMemZero(&prGlueInfo->aucWSCAssocInfoIE, 200); + prGlueInfo->u2WSCAssocInfoIELen = 0; + } + + /*Fill WPA info - mfp setting */ + /* Must put after paring RSNE from upper layer + * for prGlueInfo->rWpaInfo.ucRSNMfpCap assignment + */ +#if CFG_SUPPORT_802_11W + switch (sme->mfp) { + case NL80211_MFP_NO: + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; + /* Change Mfp parameter from DISABLED to OPTIONAL + * if upper layer set MFPC = 1 in RSNE + * since upper layer can't bring MFP OPTIONAL information + * to driver by sme->mfp + */ + if (prGlueInfo->rWpaInfo.ucRSNMfpCap == RSN_AUTH_MFP_OPTIONAL) { + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_OPTIONAL; + } else if (prGlueInfo->rWpaInfo.ucRSNMfpCap == RSN_AUTH_MFP_REQUIRED) { + DBGLOG(REQ, ERROR, "param(DISABLED) conflict with cap(REQUIRED)\n"); + } + break; + + case NL80211_MFP_REQUIRED: + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_REQUIRED; + break; + + default: + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; + break; + } +#endif + + rStatus = kalIoctl(prGlueInfo, wlanoidSetAuthMode, &eAuthMode, + sizeof(eAuthMode), false, false, false, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set auth mode error:%lx\n", rStatus); + } + + /* Enable the specific AKM suite only. */ + for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { + prEntry = &prGlueInfo->prAdapter->rMib + .dot11RSNAConfigAuthenticationSuitesTable[i]; + + if (prEntry->dot11RSNAConfigAuthenticationSuite == u4AkmSuite) { + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = true; + } else { + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = false; + } + } + + cipher = prGlueInfo->rWpaInfo.u4CipherGroup | + prGlueInfo->rWpaInfo.u4CipherPairwise; + + if (1 /* prGlueInfo->rWpaInfo.fgPrivacyInvoke */) { +#if CFG_SUPPORT_SUITB + if (cipher & IW_AUTH_CIPHER_GCMP256) { + eEncStatus = ENUM_ENCRYPTION4_ENABLED; + } else +#endif + if (cipher & IW_AUTH_CIPHER_CCMP) { + eEncStatus = ENUM_ENCRYPTION3_ENABLED; + } else if (cipher & IW_AUTH_CIPHER_TKIP) { + eEncStatus = ENUM_ENCRYPTION2_ENABLED; + } else if (cipher & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + } else if (cipher & IW_AUTH_CIPHER_NONE) { + if (prGlueInfo->rWpaInfo.fgPrivacyInvoke) { + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + } else { + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } + } else { + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } + } else { + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetEncryptionStatus, &eEncStatus, + sizeof(eEncStatus), false, false, false, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set encryption mode error:%lx\n", rStatus); + } + + if (sme->key_len != 0 && + prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { + /* NL80211 only set the Tx wep key while connect, the max 4 wep + * key set prior via add key cmd */ + P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T)wepBuf; + + kalMemZero(prWepKey, sizeof(PARAM_WEP_T)); + prWepKey->u4Length = + OFFSET_OF(PARAM_WEP_T, aucKeyMaterial) + sme->key_len; + prWepKey->u4KeyLength = (u32)sme->key_len; + prWepKey->u4KeyIndex = (u32)sme->key_idx; + prWepKey->u4KeyIndex |= IS_TRANSMIT_KEY; + if (prWepKey->u4KeyLength > MAX_KEY_LEN) { + DBGLOG(REQ, WARN, "Too long key length (%lu)\n", + prWepKey->u4KeyLength); + + return -EINVAL; + } + kalMemCopy(prWepKey->aucKeyMaterial, sme->key, prWepKey->u4KeyLength); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetAddWep, prWepKey, + prWepKey->u4Length, false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "wlanoidSetAddWep fail 0x%lx\n", rStatus); + + return -EFAULT; + } + } + + rNewSsid.u4CenterFreq = sme->channel ? sme->channel->center_freq : 0; + rNewSsid.pucBssid = (u8 *)sme->bssid; + rNewSsid.pucSsid = (u8 *)sme->ssid; + rNewSsid.u4SsidLen = sme->ssid_len; + rStatus = kalIoctl(prGlueInfo, wlanoidSetConnect, (void *)&rNewSsid, + sizeof(PARAM_CONNECT_T), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set SSID:%x\n", rStatus); + + return -EINVAL; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to disconnect from + * currently connected ESS + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, + u16 reason_code) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen; + + DBGLOG(REQ, WARN, "reason code[%d]\n", reason_code); + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; + + if (prAdapter->rWifiVar.rConnSettings.fgIsConnInitialized != true) { + P_MSG_AIS_ABORT_T prAbortMsg = NULL; + + DBGLOG(REQ, INFO, "Device still negotiating link. Dispatching explicit MSG_AIS_ABORT_T.\n"); + + prAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + + if (prAbortMsg == NULL) { + DBGLOG(REQ, ERROR, "Failed to allocate memory structure for AIS Abort Message\n"); + return -ENOMEM; + } + + prAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_ABORT; + + prAbortMsg->ucReasonOfDisconnect = 4; + prAbortMsg->fgDelayIndication = false; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prAbortMsg, MSG_SEND_METHOD_BUF); + + rStatus = WLAN_STATUS_SUCCESS; + } else { + rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, false, false, true, &u4BufLen); + } + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "disassociate error:%lx\n", rStatus); + return -EFAULT; + } + + //cfg80211_disconnected(ndev, reason_code, NULL, 0, true, GFP_KERNEL); + + DBGLOG(REQ, INFO, "mtk_cfg80211_disconnect: Disconnection successfully reported upstream.\n"); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to deauth from + * currently connected ESS + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_deauth(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_deauth_request *req) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u32 rStatus; + u32 u4BufLen; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + DBGLOG(REQ, STATE, "mtk_cfg80211_deauth\n"); + + kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_JOIN_ABORT, NULL, 0); + + P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; + + if (prAdapter->rWifiVar.rConnSettings.fgIsConnInitialized != true) { + P_MSG_AIS_ABORT_T prAbortMsg = NULL; + + DBGLOG(REQ, INFO, "Device in negotiation phase during Deauth. Dispatching Mailbox Abort.\n"); + + prAbortMsg = (P_MSG_AIS_ABORT_T)cnmMemAlloc( + prAdapter, RAM_TYPE_MSG, sizeof(MSG_AIS_ABORT_T)); + + if (prAbortMsg == NULL) { + DBGLOG(REQ, ERROR, "Failed to allocate memory structure for Deauth Abort Message\n"); + return -ENOMEM; + } + + prAbortMsg->rMsgHdr.eMsgId = MID_OID_AIS_FSM_ABORT; + prAbortMsg->ucReasonOfDisconnect = DISCONNECT_REASON_CODE_DEAUTHENTICATED; + prAbortMsg->fgDelayIndication = false; + + mboxSendMsg(prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prAbortMsg, MSG_SEND_METHOD_BUF); + + rStatus = WLAN_STATUS_SUCCESS; + } else { + rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, false, false, true, &u4BufLen); + } + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "disassociate error:%x\n", rStatus); + return -EFAULT; + } + + return 0; +} + +int mtk_cfg80211_disassoc(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_disassoc_request *req) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + u32 rStatus; + u32 u4BufLen; + + ASSERT(wiphy); + + prGlueInfo = *((P_GLUE_INFO_T *)wiphy_priv(wiphy)); + ASSERT(prGlueInfo); + + DBGLOG(REQ, STATE, "mtk_cfg80211_disassoc.\n"); + + kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_JOIN_ABORT, NULL, 0); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, false, + false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "disassociate error:%x\n", rStatus); + return -EFAULT; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to join an IBSS group + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_ibss_params *params) +{ + PARAM_SSID_T rNewSsid; + P_GLUE_INFO_T prGlueInfo = NULL; + u32 u4ChnlFreq; /* Store channel or frequency information */ + u32 u4BufLen = 0, u4SsidLen = 0; + WLAN_STATUS rStatus; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + /* set channel */ + if (params->channel_fixed) { + u4ChnlFreq = params->chandef.center_freq1; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetFrequency, &u4ChnlFreq, + sizeof(u4ChnlFreq), false, false, false, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + } + + /* set SSID */ + u4SsidLen = (params->ssid_len > PARAM_MAX_LEN_SSID) ? PARAM_MAX_LEN_SSID : + params->ssid_len; + kalMemCopy(rNewSsid.aucSsid, params->ssid, u4SsidLen); + rStatus = kalIoctl(prGlueInfo, wlanoidSetSsid, (void *)&rNewSsid, + sizeof(PARAM_SSID_T), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set SSID:%lx\n", rStatus); + return -EFAULT; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to leave from IBSS group + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + u32 u4BufLen; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, false, + false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "disassociate error:%lx\n", rStatus); + return -EFAULT; + } + + return 0; +} + +#ifdef SUPPORT_ENFORCE_PWR_MODE +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to configure + * WLAN power managemenet + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, + bool enabled, int timeout) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + u32 u4BufLen; + PARAM_POWER_MODE_T rPowerMode; + PARAM_POWER_MODE eEnforcePowerMode = Param_PowerModeMax; + P_BSS_INFO_T prBssInfo = NULL; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + if (!prGlueInfo) { + return -EFAULT; + } + + if (!prGlueInfo->prAdapter->prAisBssInfo) { + return -EFAULT; + } + + prBssInfo = prGlueInfo->prAdapter->prAisBssInfo; + + if (enabled) { + if (timeout == -1) { + rPowerMode.ePowerMode = Param_PowerModeFast_PSP; + } else { + rPowerMode.ePowerMode = Param_PowerModeMAX_PSP; + } + } else { + rPowerMode.ePowerMode = Param_PowerModeCAM; + } + + rPowerMode.ucBssIdx = prBssInfo->ucBssIndex; + + if (prBssInfo->ePowerModeFromUser != rPowerMode.ePowerMode) { + /* 1. Store user's PS mode, it is used for wlanSuspendPmHandle() + * when WoW is disabled + * 2. Store user's PS mode for restoring when we do not enforce + * power mode anymore + */ + DBGLOG(INIT, STATE, "Store user's PS mode:%d\n", rPowerMode.ePowerMode); + prBssInfo->ePowerModeFromUser = rPowerMode.ePowerMode; + } + + /* Configured in wifi.cfg to keep CAM during activity */ + if (prGlueInfo->prAdapter->rWifiVar.ucWlanSetCamDuringAct) { + /* Keep CAM before wlan suspends */ + rPowerMode.ePowerMode = Param_PowerModeCAM; + } + + if ((prBssInfo->eBand == BAND_2G4) && + (prGlueInfo->prAdapter->rWifiVar.ucEnforce2G < Param_PowerModeMax)) { + eEnforcePowerMode = + (PARAM_POWER_MODE)prGlueInfo->prAdapter->rWifiVar.ucEnforce2G; + } else if ((prBssInfo->eBand == BAND_5G) && + (prGlueInfo->prAdapter->rWifiVar.ucEnforce5G < + Param_PowerModeMax)) { + eEnforcePowerMode = + (PARAM_POWER_MODE)prGlueInfo->prAdapter->rWifiVar.ucEnforce5G; + } + + if (eEnforcePowerMode < Param_PowerModeMax) { + rPowerMode.ePowerMode = eEnforcePowerMode; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile, + &rPowerMode, sizeof(PARAM_POWER_MODE_T), false, false, + true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set_power_mgmt error:%lx\n", rStatus); + return -EFAULT; + } + + return 0; +} +#else +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to configure + * WLAN power managemenet + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, + bool enabled, int timeout) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + u32 u4BufLen; + PARAM_POWER_MODE_T rPowerMode; + PARAM_POWER_MODE eEnforcePowerMode; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + if (!prGlueInfo) { + return -EFAULT; + } + + if (!prGlueInfo->prAdapter->prAisBssInfo) { + return -EFAULT; + } + + if (enabled && ((prGlueInfo->prAdapter->prAisBssInfo->eBand == BAND_5G) || + (!prGlueInfo->prAdapter->rWifiVar.ucEnforceCAM2G))) { + if (timeout == -1) { + rPowerMode.ePowerMode = Param_PowerModeFast_PSP; + } else { + rPowerMode.ePowerMode = Param_PowerModeMAX_PSP; + } + } else { + rPowerMode.ePowerMode = Param_PowerModeCAM; + } + + rPowerMode.ucBssIdx = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + + if ((prGlueInfo->prAdapter->prAisBssInfo->ePowerModeFromUser != + rPowerMode.ePowerMode) && + (prGlueInfo->prAdapter->rWifiVar.ucWlanSetCamDuringAct || + prGlueInfo->prAdapter->rWifiVar.ucEnforcePSMode < + Param_PowerModeMax)) { + /* 1. Store user's PS mode, it is used for wlanSuspendPmHandle() + * when WoW is disabled + * 2. Store user's PS mode for restoring when we do not enforce + * power mode anymore + */ + DBGLOG(INIT, STATE, "Set CAM and store user's PS mode:%d\n", + rPowerMode.ePowerMode); + prGlueInfo->prAdapter->prAisBssInfo->ePowerModeFromUser = + rPowerMode.ePowerMode; + } + + /* Configured in wifi.cfg to keep CAM during activity */ + if (prGlueInfo->prAdapter->rWifiVar.ucWlanSetCamDuringAct) { + /* Keep CAM before wlan suspends */ + rPowerMode.ePowerMode = Param_PowerModeCAM; + } + + eEnforcePowerMode = + (PARAM_POWER_MODE)prGlueInfo->prAdapter->rWifiVar.ucEnforcePSMode; + + if (eEnforcePowerMode < Param_PowerModeMax) { + rPowerMode.ePowerMode = eEnforcePowerMode; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile, + &rPowerMode, sizeof(PARAM_POWER_MODE_T), false, false, + true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set_power_mgmt error:%lx\n", rStatus); + return -EFAULT; + } + + return 0; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to cache + * a PMKID for a BSSID + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_pmksa *pmksa) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + u32 u4BufLen; + P_PARAM_PMKID_T prPmkid; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + prPmkid = (P_PARAM_PMKID_T)kalMemAlloc(8 + sizeof(PARAM_BSSID_INFO_T), + VIR_MEM_TYPE); + if (!prPmkid) { + DBGLOG(INIT, INFO, "Can not alloc memory for IW_PMKSA_ADD\n"); + return -ENOMEM; + } + + prPmkid->u4Length = 8 + sizeof(PARAM_BSSID_INFO_T); + prPmkid->u4BSSIDInfoCount = 1; + kalMemCopy(prPmkid->arBSSIDInfo->arBSSID, pmksa->bssid, 6); + kalMemCopy(prPmkid->arBSSIDInfo->arPMKID, pmksa->pmkid, IW_PMKID_LEN); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetPmkid, prPmkid, + sizeof(PARAM_PMKID_T), false, false, false, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "add pmkid error:%lx\n", rStatus); + } + kalMemFree(prPmkid, VIR_MEM_TYPE, 8 + sizeof(PARAM_BSSID_INFO_T)); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to remove + * a cached PMKID for a BSSID + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_pmksa *pmksa) +{ + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to flush + * all cached PMKID + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + u32 u4BufLen; + P_PARAM_PMKID_T prPmkid; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + prPmkid = (P_PARAM_PMKID_T)kalMemAlloc(8, VIR_MEM_TYPE); + if (!prPmkid) { + DBGLOG(INIT, INFO, "Can not alloc memory for IW_PMKSA_FLUSH\n"); + return -ENOMEM; + } + + prPmkid->u4Length = 8; + prPmkid->u4BSSIDInfoCount = 0; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetPmkid, prPmkid, + sizeof(PARAM_PMKID_T), false, false, false, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "flush pmkid error:%lx\n", rStatus); + } + kalMemFree(prPmkid, VIR_MEM_TYPE, 8); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for setting the rekey data + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_gtk_rekey_data *data) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u32 u4BufLen; + P_PARAM_GTK_REKEY_DATA prGtkData; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + s32 i4Rslt = -EINVAL; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + /* if disable offload, we store key data here, and enable rekey offload + * when enter wow */ + if (!prGlueInfo->prAdapter->rWifiVar.ucEapolOffload) { + kalMemZero(prGlueInfo->rWpaInfo.aucKek, NL80211_KEK_LEN); + kalMemZero(prGlueInfo->rWpaInfo.aucKck, NL80211_KCK_LEN); + kalMemZero(prGlueInfo->rWpaInfo.aucReplayCtr, NL80211_REPLAY_CTR_LEN); + kalMemCopy(prGlueInfo->rWpaInfo.aucKek, data->kek, NL80211_KEK_LEN); + kalMemCopy(prGlueInfo->rWpaInfo.aucKck, data->kck, NL80211_KCK_LEN); + kalMemCopy(prGlueInfo->rWpaInfo.aucReplayCtr, data->replay_ctr, + NL80211_REPLAY_CTR_LEN); + + return 0; + } + + prGtkData = (P_PARAM_GTK_REKEY_DATA)kalMemAlloc( + sizeof(PARAM_GTK_REKEY_DATA), VIR_MEM_TYPE); + + if (!prGtkData) { + return WLAN_STATUS_SUCCESS; + } + + DBGLOG(RSN, INFO, "cfg80211_set_rekey_data size( %d)\n", sizeof(*data)); + + DBGLOG(RSN, INFO, "kek\n"); + DBGLOG_MEM8(PF, ERROR, (u8 *)data->kek, NL80211_KEK_LEN); + DBGLOG(RSN, INFO, "kck\n"); + DBGLOG_MEM8(PF, ERROR, (u8 *)data->kck, NL80211_KCK_LEN); + DBGLOG(RSN, INFO, "replay count\n"); + DBGLOG_MEM8(PF, ERROR, (u8 *)data->replay_ctr, NL80211_REPLAY_CTR_LEN); + + kalMemCopy(prGtkData->aucKek, data->kek, NL80211_KEK_LEN); + kalMemCopy(prGtkData->aucKck, data->kck, NL80211_KCK_LEN); + kalMemCopy(prGtkData->aucReplayCtr, data->replay_ctr, + NL80211_REPLAY_CTR_LEN); + + prGtkData->ucBssIndex = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + + prGtkData->u4Proto = NL80211_WPA_VERSION_2; + if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) { + prGtkData->u4Proto = NL80211_WPA_VERSION_1; + } + + if (prGlueInfo->rWpaInfo.u4CipherPairwise == IW_AUTH_CIPHER_TKIP) { + prGtkData->u4PairwiseCipher = BIT(3); + } else if (prGlueInfo->rWpaInfo.u4CipherPairwise == IW_AUTH_CIPHER_CCMP) { + prGtkData->u4PairwiseCipher = BIT(4); + } else { + kalMemFree(prGtkData, VIR_MEM_TYPE, sizeof(PARAM_GTK_REKEY_DATA)); + return WLAN_STATUS_SUCCESS; + } + + if (prGlueInfo->rWpaInfo.u4CipherGroup == IW_AUTH_CIPHER_TKIP) { + prGtkData->u4GroupCipher = BIT(3); + } else if (prGlueInfo->rWpaInfo.u4CipherGroup == IW_AUTH_CIPHER_CCMP) { + prGtkData->u4GroupCipher = BIT(4); + } else { + kalMemFree(prGtkData, VIR_MEM_TYPE, sizeof(PARAM_GTK_REKEY_DATA)); + return WLAN_STATUS_SUCCESS; + } + + prGtkData->u4KeyMgmt = prGlueInfo->rWpaInfo.u4KeyMgmt; + prGtkData->u4MgmtGroupCipher = 0; + + prGtkData->ucRekeyMode = GTK_REKEY_CMD_MODE_OFFLOAD_ON; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetGtkRekeyData, prGtkData, + sizeof(PARAM_GTK_REKEY_DATA), false, false, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "set GTK rekey data error:%lx\n", rStatus); + } else { + i4Rslt = 0; + } + + kalMemFree(prGtkData, VIR_MEM_TYPE, sizeof(PARAM_GTK_REKEY_DATA)); + + return i4Rslt; +} + +void mtk_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy, + IN struct wireless_dev *wdev, + IN u16 frame_type, IN bool reg) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + + do { + DBGLOG(INIT, TRACE, "mtk_cfg80211_mgmt_frame_register\n"); + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + switch (frame_type) { + case MAC_FRAME_PROBE_REQ: + if (reg) { + prGlueInfo->u4OsMgmtFrameFilter |= + PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(INIT, TRACE, "Open packet filer probe request\n"); + } else { + prGlueInfo->u4OsMgmtFrameFilter &= + ~PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(INIT, TRACE, "Close packet filer probe request\n"); + } + break; + + case MAC_FRAME_ACTION: + if (reg) { + prGlueInfo->u4OsMgmtFrameFilter |= + PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(INIT, TRACE, "Open packet filer action frame.\n"); + } else { + prGlueInfo->u4OsMgmtFrameFilter &= + ~PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(INIT, TRACE, "Close packet filer action frame.\n"); + } + break; + + default: + DBGLOG(INIT, TRACE, "unsupported frame type:%x\n", frame_type); + break; + } + + if (prGlueInfo->prAdapter != NULL) { + set_bit(GLUE_FLAG_FRAME_FILTER_AIS_BIT, &prGlueInfo->ulFlag); + + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + + if (in_interrupt()) { + DBGLOG(INIT, TRACE, "It is in interrupt level\n"); + } + } + } while (false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to stay on a + * specified channel + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Rslt = -EINVAL; + P_MSG_REMAIN_ON_CHANNEL_T prMsgChnlReq = (P_MSG_REMAIN_ON_CHANNEL_T)NULL; + + do { + if ((wiphy == NULL) || (wdev == NULL) || (chan == NULL) || + (cookie == NULL)) { + break; + } + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + DBGLOG(INIT, INFO, "--> %s()\n", __func__); + + *cookie = prGlueInfo->u8Cookie++; + + prMsgChnlReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_REMAIN_ON_CHANNEL_T)); + + if (prMsgChnlReq == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + prMsgChnlReq->rMsgHdr.eMsgId = MID_MNY_AIS_REMAIN_ON_CHANNEL; + prMsgChnlReq->u8Cookie = *cookie; + prMsgChnlReq->u4DurationMs = duration; + + prMsgChnlReq->ucChannelNum = + nicFreq2ChannelNum(chan->center_freq * 1000); + + switch (chan->band) { + case NL80211_BAND_2GHZ: + prMsgChnlReq->eBand = BAND_2G4; + break; + + case NL80211_BAND_5GHZ: + prMsgChnlReq->eBand = BAND_5G; + break; + + default: + prMsgChnlReq->eBand = BAND_2G4; + break; + } + + prMsgChnlReq->eSco = CHNL_EXT_SCN; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsgChnlReq, + MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (false); + + return i4Rslt; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to cancel staying + * on a specified channel + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Rslt = -EINVAL; + P_MSG_CANCEL_REMAIN_ON_CHANNEL_T prMsgChnlAbort = + (P_MSG_CANCEL_REMAIN_ON_CHANNEL_T)NULL; + + do { + if ((wiphy == NULL) || (wdev == NULL)) { + break; + } + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + prMsgChnlAbort = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_CANCEL_REMAIN_ON_CHANNEL_T)); + + if (prMsgChnlAbort == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + prMsgChnlAbort->rMsgHdr.eMsgId = MID_MNY_AIS_CANCEL_REMAIN_ON_CHANNEL; + prMsgChnlAbort->u8Cookie = cookie; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prMsgChnlAbort, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (false); + + return i4Rslt; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to send a management frame + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Rslt = -EINVAL; + P_MSG_MGMT_TX_REQUEST_T prMsgTxReq = (P_MSG_MGMT_TX_REQUEST_T)NULL; + P_MSDU_INFO_T prMgmtFrame = (P_MSDU_INFO_T)NULL; + u8 *pucFrameBuf = (u8 *)NULL; + + do { + if ((wiphy == NULL) || (wdev == NULL) || (params == 0) || + (cookie == NULL)) { + break; + } + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + *cookie = prGlueInfo->u8Cookie++; + + /* Channel & Channel Type & Wait time are ignored. */ + prMsgTxReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_MGMT_TX_REQUEST_T)); + + if (prMsgTxReq == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + prMsgTxReq->fgNoneCckRate = false; + prMsgTxReq->fgIsWaitRsp = true; + + prMgmtFrame = cnmMgtPktAlloc( + prGlueInfo->prAdapter, (u32)(params->len + MAC_TX_RESERVED_FIELD)); + prMsgTxReq->prMgmtMsduInfo = prMgmtFrame; + if (prMsgTxReq->prMgmtMsduInfo == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + prMsgTxReq->u8Cookie = *cookie; + prMsgTxReq->rMsgHdr.eMsgId = MID_MNY_AIS_MGMT_TX; + + pucFrameBuf = (u8 *)((unsigned long)prMgmtFrame->prPacket + + MAC_TX_RESERVED_FIELD); + + kalMemCopy(pucFrameBuf, params->buf, params->len); + + prMgmtFrame->u2FrameLength = params->len; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsgTxReq, + MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (false); + + if ((i4Rslt != 0) && (prMsgTxReq != NULL)) { + if (prMsgTxReq->prMgmtMsduInfo != NULL) { + cnmMgtPktFree(prGlueInfo->prAdapter, prMsgTxReq->prMgmtMsduInfo); + } + + cnmMemFree(prGlueInfo->prAdapter, prMsgTxReq); + } + + return i4Rslt; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for requesting to cancel the wait time + * from transmitting a management frame on another channel + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, u64 cookie) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + DBGLOG(INIT, INFO, "--> %s()\n", __func__); + + /* not implemented */ + + return -EINVAL; +} + +#ifdef CONFIG_NL80211_TESTMODE + +int mtk_cfg80211_testmode_get_sta_statistics(IN struct wiphy *wiphy, + IN void *data, IN int len, + IN P_GLUE_INFO_T prGlueInfo) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen; + u32 u4LinkScore; + u32 u4TotalError; + u32 u4TxExceedThresholdCount; + u32 u4TxTotalCount; + + P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS prParams = NULL; + PARAM_GET_STA_STATISTICS rQueryStaStatistics; + struct sk_buff *skb; + + ASSERT(wiphy); + ASSERT(prGlueInfo); + + if (len < sizeof(struct _NL80211_DRIVER_GET_STA_STATISTICS_PARAMS)) { + DBGLOG(QM, ERROR, "len [%d] is invalid!\n", len); + return -EINVAL; + } + + if (data && len) { + prParams = (P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS)data; + } + + /*if (!prParams->aucMacAddr) { + DBGLOG(QM, ERROR, "%s MAC Address is NULL\n", __func__); + return -EINVAL; + }*/ + + skb = cfg80211_testmode_alloc_reply_skb( + wiphy, sizeof(PARAM_GET_STA_STATISTICS) + 1); + + if (!skb) { + DBGLOG(QM, ERROR, "%s allocate skb failed:%lx\n", __func__, rStatus); + return -ENOMEM; + } + + kalMemZero(&rQueryStaStatistics, sizeof(rQueryStaStatistics)); + COPY_MAC_ADDR(rQueryStaStatistics.aucMacAddr, prParams->aucMacAddr); + rQueryStaStatistics.ucReadClear = true; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryStaStatistics, + &rQueryStaStatistics, sizeof(rQueryStaStatistics), true, + false, true, &u4BufLen); + + /* Calcute Link Score */ + u4TxExceedThresholdCount = rQueryStaStatistics.u4TxExceedThresholdCount; + u4TxTotalCount = rQueryStaStatistics.u4TxTotalCount; + u4TotalError = rQueryStaStatistics.u4TxFailCount + + rQueryStaStatistics.u4TxLifeTimeoutCount; + + /* u4LinkScore 10~100 , ExceedThreshold ratio 0~90 only */ + /* u4LinkScore 0~9 , Drop packet ratio 0~9 and all packets exceed + * threshold */ + if (u4TxTotalCount) { + if (u4TxExceedThresholdCount <= u4TxTotalCount) { + u4LinkScore = + (90 - ((u4TxExceedThresholdCount * 90) / u4TxTotalCount)); + } else { + u4LinkScore = 0; + } + } else { + u4LinkScore = 90; + } + + u4LinkScore += 10; + + if (u4LinkScore == 10) { + if (u4TotalError <= u4TxTotalCount) { + u4LinkScore = (10 - ((u4TotalError * 10) / u4TxTotalCount)); + } else { + u4LinkScore = 0; + } + } + + if (u4LinkScore > 100) { + u4LinkScore = 100; + } + + { + u8 __tmp = 0; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_INVALID, + sizeof(u8), &__tmp) < 0)) { + goto nla_put_failure; + } + } + { + u8 __tmp = NL80211_DRIVER_TESTMODE_VERSION; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_VERSION, + sizeof(u8), &__tmp) < 0)) { + goto nla_put_failure; + } + } + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_MAC, MAC_ADDR_LEN, + prParams->aucMacAddr) < 0)) { + goto nla_put_failure; + } + { + u8 __tmp = u4LinkScore; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE, + sizeof(u8), &__tmp) < 0)) { + goto nla_put_failure; + } + } + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_MAC, MAC_ADDR_LEN, + prParams->aucMacAddr) < 0)) { + goto nla_put_failure; + } + { + u32 __tmp = rQueryStaStatistics.u4Flag; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_FLAG, + sizeof(u32), &__tmp) < 0)) { + goto nla_put_failure; + } + } + + /* FW part STA link status */ + { + u8 __tmp = rQueryStaStatistics.ucPer; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_PER, + sizeof(u8), &__tmp) < 0)) { + goto nla_put_failure; + } + } + { + u8 __tmp = rQueryStaStatistics.ucRcpi; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_RSSI, + sizeof(u8), &__tmp) < 0)) { + goto nla_put_failure; + } + } + { + u32 __tmp = rQueryStaStatistics.u4PhyMode; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_PHY_MODE, + sizeof(u32), &__tmp) < 0)) { + goto nla_put_failure; + } + } + { + u16 __tmp = rQueryStaStatistics.u2LinkSpeed; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TX_RATE, + sizeof(u16), &__tmp) < 0)) { + goto nla_put_failure; + } + } + { + u32 __tmp = rQueryStaStatistics.u4TxFailCount; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT, + sizeof(u32), &__tmp) < 0)) { + goto nla_put_failure; + } + } + { + u32 __tmp = rQueryStaStatistics.u4TxLifeTimeoutCount; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT, + sizeof(u32), &__tmp) < 0)) { + goto nla_put_failure; + } + } + { + u32 __tmp = rQueryStaStatistics.u4TxAverageAirTime; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME, + sizeof(u32), &__tmp) < 0)) { + goto nla_put_failure; + } + } + + /* Driver part link status */ + { + u32 __tmp = rQueryStaStatistics.u4TxTotalCount; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT, + sizeof(u32), &__tmp) < 0)) { + goto nla_put_failure; + } + } + { + u32 __tmp = rQueryStaStatistics.u4TxExceedThresholdCount; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT, + sizeof(u32), &__tmp) < 0)) { + goto nla_put_failure; + } + } + { + u32 __tmp = rQueryStaStatistics.u4TxAverageProcessTime; + + if (unlikely(nla_put(skb, + NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME, + sizeof(u32), &__tmp) < 0)) { + goto nla_put_failure; + } + } + + /* Network counter */ + if (unlikely(nla_put(skb, + NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY, + sizeof(rQueryStaStatistics.au4TcResourceEmptyCount), + rQueryStaStatistics.au4TcResourceEmptyCount) < 0)) { + goto nla_put_failure; + } + + /* Sta queue length */ + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY, + sizeof(rQueryStaStatistics.au4TcQueLen), + rQueryStaStatistics.au4TcQueLen) < 0)) { + goto nla_put_failure; + } + + /* Global QM counter */ + if (unlikely(nla_put(skb, + NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY, + sizeof(rQueryStaStatistics.au4TcAverageQueLen), + rQueryStaStatistics.au4TcAverageQueLen) < 0)) { + goto nla_put_failure; + } + + if (unlikely(nla_put(skb, + NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY, + sizeof(rQueryStaStatistics.au4TcCurrentQueLen), + rQueryStaStatistics.au4TcCurrentQueLen) < 0)) { + goto nla_put_failure; + } + + /* Reserved field */ + if (unlikely(nla_put(skb, NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY, + sizeof(rQueryStaStatistics.au4Reserved), + rQueryStaStatistics.au4Reserved) < 0)) { + goto nla_put_failure; + } + + return cfg80211_testmode_reply(skb); + +nla_put_failure: + /* nal_put_skb_fail */ + kfree_skb(skb); + return -EFAULT; +} + +int mtk_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, + IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_SW_CMD_PARAMS prParams = + (P_NL80211_DRIVER_SW_CMD_PARAMS)NULL; + WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; + int fgIsValid = 0; + u32 u4SetInfoLen = 0; + + ASSERT(wiphy); + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + DBGLOG(INIT, INFO, "--> %s()\n", __func__); + + if (len < sizeof(struct _NL80211_DRIVER_SW_CMD_PARAMS)) { + DBGLOG(REQ, ERROR, "len [%d] is invalid!\n", len); + return -EINVAL; + } + if (data && len) { + prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS)data; + } + + if (prParams) { + if (prParams->set == 1) { + rstatus = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC)wlanoidSetSwCtrlWrite, + &prParams->adr, (u32)8, false, false, true, + &u4SetInfoLen); + } + } + + if (rstatus != WLAN_STATUS_SUCCESS) { + fgIsValid = -EFAULT; + } + + return fgIsValid; +} + +static int mtk_wlan_cfg_testmode_cmd(struct wiphy *wiphy, void *data, int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_TEST_MODE_PARAMS prParams = NULL; + s32 i4Status; + + ASSERT(wiphy); + DBGLOG(INIT, INFO, "-->%s()\n", __func__); + + if (len < sizeof(struct _NL80211_DRIVER_TEST_MODE_PARAMS)) { + DBGLOG(REQ, ERROR, "len [%d] is invalid!\n", len); + return -EINVAL; + } + if (!data || !len) { + DBGLOG(REQ, ERROR, "mtk_cfg80211_testmode_cmd null data\n"); + return -EINVAL; + } + + if (!wiphy) { + DBGLOG(REQ, ERROR, "mtk_cfg80211_testmode_cmd null wiphy\n"); + return -EINVAL; + } + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + prParams = (P_NL80211_DRIVER_TEST_MODE_PARAMS)data; + + /* Clear the version byte */ + prParams->index = prParams->index & ~BITS(24, 31); + + switch (prParams->index) { + case TESTMODE_CMD_ID_SW_CMD: /* SW cmd */ + i4Status = mtk_cfg80211_testmode_sw_cmd(wiphy, data, len); + break; + + case 0x10: + i4Status = mtk_cfg80211_testmode_get_sta_statistics(wiphy, data, len, + prGlueInfo); + break; + + case TESTMODE_CMD_ID_STR_CMD: + i4Status = mtk_cfg80211_process_str_cmd( + prGlueInfo, (u8 *)(prParams + 1), len - sizeof(*prParams)); + break; + + default: + i4Status = -EINVAL; + break; + } + + if (i4Status != 0) { + DBGLOG(REQ, TRACE, "prParams->index=%d, status=%d\n", prParams->index, + i4Status); + } + + return i4Status; +} + +int mtk_cfg80211_testmode_cmd(struct wiphy *wiphy, struct wireless_dev *wdev, + void *data, int len) +{ + ASSERT(wdev); + return mtk_wlan_cfg_testmode_cmd(wiphy, data, len); +} +#endif + +int mtk_cfg80211_sched_scan_start(IN struct wiphy *wiphy, + IN struct net_device *ndev, + IN struct cfg80211_sched_scan_request *request) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + u32 i, u4BufLen; + P_PARAM_SCHED_SCAN_REQUEST prSchedScanRequest; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + /* check if there is any pending scan/sched_scan not yet finished */ + if (prGlueInfo->prScanRequest != NULL || + prGlueInfo->prSchedScanRequest != NULL) { + DBGLOG(SCN, INFO, + "(prGlueInfo->prScanRequest != NULL || " + "prGlueInfo->prSchedScanRequest != NULL)\n"); + return -EBUSY; + } else if (request == NULL || + request->n_match_sets > CFG_SCAN_SSID_MATCH_MAX_NUM) { + DBGLOG(SCN, INFO, + "(request == NULL || request->n_match_sets > " + "CFG_SCAN_SSID_MATCH_MAX_NUM)\n"); + /* invalid scheduled scan request */ + return -EINVAL; + } else if (!request->n_ssids || !request->n_match_sets) { + /* invalid scheduled scan request */ + return -EINVAL; + } + + prSchedScanRequest = (P_PARAM_SCHED_SCAN_REQUEST)kalMemAlloc( + sizeof(PARAM_SCHED_SCAN_REQUEST), VIR_MEM_TYPE); + if (prSchedScanRequest == NULL) { + DBGLOG(SCN, INFO, "(prSchedScanRequest == NULL) kalMemAlloc fail\n"); + return -ENOMEM; + } + + prSchedScanRequest->u4SsidNum = request->n_match_sets; + for (i = 0; i < request->n_match_sets; i++) { + if (request->match_sets == + NULL /* || &(request->match_sets[i]) == NULL >> this comparation are always false(?) */) + { + prSchedScanRequest->arSsid[i].u4SsidLen = 0; + } else { + COPY_SSID(prSchedScanRequest->arSsid[i].aucSsid, + prSchedScanRequest->arSsid[i].u4SsidLen, + request->match_sets[i].ssid.ssid, + request->match_sets[i].ssid.ssid_len); + } + } + + prSchedScanRequest->u4IELength = request->ie_len; + if (request->ie_len > 0) { + prSchedScanRequest->pucIE = (u8 *)(request->ie); + } + + prSchedScanRequest->u2ScanInterval = (u16)(request->scan_plans->interval); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetStartSchedScan, prSchedScanRequest, + sizeof(PARAM_SCHED_SCAN_REQUEST), false, false, true, + &u4BufLen); + + kalMemFree(prSchedScanRequest, VIR_MEM_TYPE, + sizeof(PARAM_SCHED_SCAN_REQUEST)); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "scheduled scan error:%lx\n", rStatus); + return -EINVAL; + } + + prGlueInfo->prSchedScanRequest = request; + + return 0; +} + +int mtk_cfg80211_sched_scan_stop(IN struct wiphy *wiphy, + IN struct net_device *ndev, IN u64 reqid) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + u32 u4BufLen; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + /* check if there is any pending scan/sched_scan not yet finished */ + if (prGlueInfo->prSchedScanRequest == NULL) { + return -EBUSY; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetStopSchedScan, NULL, 0, false, + false, true, &u4BufLen); + + if (rStatus == WLAN_STATUS_FAILURE) { + DBGLOG(REQ, WARN, "scheduled scan error:%lx\n", rStatus); + return -EINVAL; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for handling association request + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_assoc(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_assoc_request *req) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 arBssid[PARAM_MAC_ADDR_LEN]; + u32 rStatus; + u32 u4BufLen; + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + ENUM_PARAM_AUTH_MODE_T eAuthMode; + u32 cipher; + u32 i, u4AkmSuite; + P_DOT11_RSNA_CONFIG_AUTHENTICATION_SUITES_ENTRY prEntry; + P_CONNECTION_SETTINGS_T prConnSettings = NULL; + u8 *prDesiredIE = NULL; + u8 *pucIEStart = NULL; + RSN_INFO_T rRsnInfo; + u8 fgCarryRsnxe = false; + P_STA_RECORD_T prStaRec = NULL; + u8 fgCarryWPSIE = false; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + kalMemZero(arBssid, MAC_ADDR_LEN); + wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, &arBssid[0], + sizeof(arBssid), &u4BufLen); + + prConnSettings = &prGlueInfo->prAdapter->rWifiVar.rConnSettings; + + /* [todo]temp use for indicate rx assoc resp, may need to be modified */ + + /* The BSS from cfg80211_ops.assoc must give back to + * cfg80211_send_rx_assoc() or to cfg80211_assoc_timeout(). + * To ensure proper refcounting, new association requests + * while already associating must be rejected. + */ + if (prConnSettings->bss) { + DBGLOG(REQ, WARN, "Still referencing to another cfg80211_bss.\n"); + DBGLOG(REQ, WARN, + "Previous auth/assoc handshake not terminate correctly\n"); + return -ENOENT; + } + + cfg80211_ref_bss(wiphy, req->bss); + prConnSettings->bss = req->bss; + + DBGLOG(REQ, INFO, "mtk_cfg80211_assoc, media state:%d\n", + prGlueInfo->eParamMediaStateIndicated); + + kalMemZero(arBssid, MAC_ADDR_LEN); + if (prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED) { + wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, + &arBssid[0], sizeof(arBssid), &u4BufLen); + +#if !CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + /* 1. check BSSID */ + if (UNEQUAL_MAC_ADDR(arBssid, req->bss->bssid)) { + /* wrong MAC address */ + DBGLOG(REQ, WARN, + "incorrect BSSID: [" MACSTR + "] currently connected BSSID[" MACSTR "]\n", + MAC2STR(req->bss->bssid), MAC2STR(arBssid)); + return -ENOENT; + } +#endif + } + + /* <1> Reset WPA info */ + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4KeyMgmt = 0; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; +#if CFG_SUPPORT_802_11W + prGlueInfo->rWpaInfo.u4CipherGroupMgmt = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; + prGlueInfo->rWpaInfo.ucRSNMfpCap = RSN_AUTH_MFP_DISABLED; + //prGlueInfo->rWpaInfo.ucRSNMfpCap = RSN_AUTH_MFP_DISABLED; +#endif + + /* 2.Fill WPA version */ + if (req->crypto.wpa_versions & NL80211_WPA_VERSION_1) { + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_WPA; + } else if (req->crypto.wpa_versions & NL80211_WPA_VERSION_2) { + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_WPA2; + } else { + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + } + DBGLOG(REQ, INFO, "wpa ver=%d\n", prGlueInfo->rWpaInfo.u4WpaVersion); + + /* 3.Fill pairwise cipher suite */ + if (req->crypto.n_ciphers_pairwise) { + DBGLOG(RSN, INFO, "[wlan] cipher pairwise (%x)\n", + req->crypto.ciphers_pairwise[0]); + + prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo + .au4PairwiseKeyCipherSuite[0] = req->crypto.ciphers_pairwise[0]; + switch (req->crypto.ciphers_pairwise[0]) { + case WLAN_CIPHER_SUITE_WEP40: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP40; + break; + + case WLAN_CIPHER_SUITE_WEP104: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104; + break; + + case WLAN_CIPHER_SUITE_TKIP: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_TKIP; + break; + + case WLAN_CIPHER_SUITE_CCMP: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_CCMP; + break; + + case WLAN_CIPHER_SUITE_AES_CMAC: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_CCMP; + break; + + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_GCMP256; + break; + + case WLAN_CIPHER_SUITE_GCMP_256: + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_GCMP256; + break; + + default: + DBGLOG(REQ, WARN, "invalid cipher pairwise (%d)\n", + req->crypto.ciphers_pairwise[0]); + return -EINVAL; + } + } + + /* 4. Fill group cipher suite */ + if (req->crypto.cipher_group) { + DBGLOG(RSN, INFO, "[wlan] cipher group (%x)\n", + req->crypto.cipher_group); + prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo + .u4GroupKeyCipherSuite = req->crypto.cipher_group; + switch (req->crypto.cipher_group) { + case WLAN_CIPHER_SUITE_WEP40: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP40; + break; + + case WLAN_CIPHER_SUITE_WEP104: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104; + break; + + case WLAN_CIPHER_SUITE_TKIP: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_TKIP; + break; + + case WLAN_CIPHER_SUITE_CCMP: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_CCMP; + break; + + case WLAN_CIPHER_SUITE_AES_CMAC: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_CCMP; + break; + + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_GCMP256; + break; + + case WLAN_CIPHER_SUITE_GCMP_256: + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_GCMP256; + break; + + case WLAN_CIPHER_SUITE_NO_GROUP_ADDR: + break; + + default: + DBGLOG(REQ, WARN, "invalid cipher group (%d)\n", + req->crypto.cipher_group); + return -EINVAL; + } + } + + /* 5. Fill encryption status */ + cipher = prGlueInfo->rWpaInfo.u4CipherGroup | + prGlueInfo->rWpaInfo.u4CipherPairwise; + if (1 /* prGlueInfo->rWpaInfo.fgPrivacyInvoke */) { + if (cipher & IW_AUTH_CIPHER_CCMP) { + eEncStatus = ENUM_ENCRYPTION3_ENABLED; +#if CFG_SUPPORT_SUITB + } else if (cipher & IW_AUTH_CIPHER_GCMP256) { + eEncStatus = ENUM_ENCRYPTION4_ENABLED; +#endif + } else if (cipher & IW_AUTH_CIPHER_TKIP) { + eEncStatus = ENUM_ENCRYPTION2_ENABLED; + } else if (cipher & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + } else if (cipher & IW_AUTH_CIPHER_NONE) { + if (prGlueInfo->rWpaInfo.fgPrivacyInvoke) { + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + } else { + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } + } else { + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } + } else { + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetEncryptionStatus, &eEncStatus, + sizeof(eEncStatus), false, false, false, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set encryption mode error:%x\n", rStatus); + } + + /* 6. Fill AKM suites */ + u4AkmSuite = 0; + eAuthMode = 0; + DBGLOG(REQ, INFO, "request numbers of Akm Suite:%d\n", + req->crypto.n_akm_suites); + for (i = 0; i < req->crypto.n_akm_suites; i++) + DBGLOG(REQ, INFO, "request Akm Suite[%d]:%d\n", i, + req->crypto.akm_suites[i]); + + if (req->crypto.n_akm_suites) { + prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo + .au4AuthKeyMgtSuite[0] = req->crypto.akm_suites[0]; + DBGLOG(REQ, INFO, "Akm Suite:%d\n", req->crypto.akm_suites[0]); + + if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_WPA) { + switch (req->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + eAuthMode = AUTH_MODE_WPA; + u4AkmSuite = WPA_AKM_SUITE_802_1X; + break; + + case WLAN_AKM_SUITE_PSK: + eAuthMode = AUTH_MODE_WPA_PSK; + u4AkmSuite = WPA_AKM_SUITE_PSK; + break; + + default: + DBGLOG(REQ, WARN, "invalid Akm Suite (%08x)\n", + req->crypto.akm_suites[0]); + return -EINVAL; + } + } else if (prGlueInfo->rWpaInfo.u4WpaVersion == + IW_AUTH_WPA_VERSION_WPA2) { + switch (req->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + eAuthMode = AUTH_MODE_WPA2; + u4AkmSuite = RSN_AKM_SUITE_802_1X; + break; + + case WLAN_AKM_SUITE_FT_PSK: + case WLAN_AKM_SUITE_PSK: + eAuthMode = AUTH_MODE_WPA2_PSK; + u4AkmSuite = RSN_AKM_SUITE_PSK; + break; + +#if CFG_SUPPORT_802_11W + /* Notice:: Need kernel patch!! */ + case WLAN_AKM_SUITE_8021X_SHA256: + eAuthMode = AUTH_MODE_WPA2; + u4AkmSuite = RSN_AKM_SUITE_802_1X_SHA256; + break; + + case WLAN_AKM_SUITE_PSK_SHA256: + eAuthMode = AUTH_MODE_WPA2_PSK; + u4AkmSuite = RSN_AKM_SUITE_PSK_SHA256; + break; + +#endif + case WLAN_AKM_SUITE_8021X_SUITE_B: + eAuthMode = AUTH_MODE_WPA2_PSK; + u4AkmSuite = RSN_AKM_SUITE_8021X_SUITE_B_192; + break; + + case WLAN_AKM_SUITE_8021X_SUITE_B_192: + eAuthMode = AUTH_MODE_WPA2_PSK; + u4AkmSuite = RSN_AKM_SUITE_8021X_SUITE_B_192; + break; + +#if CFG_SUPPORT_SAE + /* Need to add in WPA also? */ + case WLAN_AKM_SUITE_SAE: + eAuthMode = AUTH_MODE_WPA2_SAE; + u4AkmSuite = RSN_AKM_SUITE_SAE; + break; + +#endif +#if CFG_SUPPORT_OWE + case WLAN_AKM_SUITE_OWE: + eAuthMode = AUTH_MODE_WPA2_PSK; + u4AkmSuite = RSN_AKM_SUITE_OWE; + break; + +#endif + default: + DBGLOG(REQ, WARN, "invalid Akm Suite (%08x)\n", + req->crypto.akm_suites[0]); + return -EINVAL; + } + } + } + + if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { + eAuthMode = + (prGlueInfo->rWpaInfo.u4AuthAlg == IW_AUTH_ALG_OPEN_SYSTEM) ? + AUTH_MODE_OPEN : + AUTH_MODE_AUTO_SWITCH; + } + + DBGLOG(REQ, STATE, "set auth mode:%d, akm suite:0x%x\n", eAuthMode, + u4AkmSuite); + + /* 6.1 Set auth mode*/ + rStatus = kalIoctl(prGlueInfo, wlanoidSetAuthMode, &eAuthMode, + sizeof(eAuthMode), false, false, false, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set auth mode error:%x\n", rStatus); + } + + /* 6.2 Enable the specific AKM suite only. */ + for (i = 0; i < MAX_NUM_SUPPORTED_AKM_SUITES; i++) { + prEntry = &prGlueInfo->prAdapter->rMib + .dot11RSNAConfigAuthenticationSuitesTable[i]; + + if (prEntry->dot11RSNAConfigAuthenticationSuite == u4AkmSuite) { + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = true; + DBGLOG(REQ, INFO, "match AuthenticationSuite = 0x%x", u4AkmSuite); + } else { + prEntry->dot11RSNAConfigAuthenticationSuiteEnabled = false; + } + } + + /* 7. Parsing desired ie from upper layer */ + prGlueInfo->fgWpsActive = false; + + if (req->ie && req->ie_len > 0) { + pucIEStart = (u8 *)req->ie; + if (wextSrchDesiredWPSIE(pucIEStart, req->ie_len, 0xDD, + (u8 **)&prDesiredIE)) { + prGlueInfo->fgWpsActive = true; + fgCarryWPSIE = true; + rStatus = kalIoctl(prGlueInfo, wlanoidSetWSCAssocInfo, prDesiredIE, + IE_SIZE(prDesiredIE), false, false, false, + &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(SEC, WARN, "[WSC] set WSC assoc info error:%x\n", + rStatus); + } + } + + if (wextSrchDesiredWPAIE(pucIEStart, req->ie_len, 0x30, + (u8 **)&prDesiredIE)) { + if (rsnParseRsnIE(prGlueInfo->prAdapter, + (P_RSN_INFO_ELEM_T)prDesiredIE, &rRsnInfo)) { +#if CFG_SUPPORT_802_11W + /* Fill RSNE MFP Cap */ + if (rRsnInfo.u2RsnCap & ELEM_WPA_CAP_MFPC) { + prGlueInfo->rWpaInfo.u4CipherGroupMgmt = + rRsnInfo.u4GroupMgmtKeyCipherSuite; + prGlueInfo->rWpaInfo.ucRSNMfpCap = RSN_AUTH_MFP_OPTIONAL; + if (rRsnInfo.u2RsnCap & ELEM_WPA_CAP_MFPR) { + prGlueInfo->rWpaInfo.ucRSNMfpCap = + RSN_AUTH_MFP_REQUIRED; + } + } else { + prGlueInfo->rWpaInfo.ucRSNMfpCap = RSN_AUTH_MFP_DISABLED; + } +#endif + + prGlueInfo->rWpaInfo.ucRsneLen = rRsnInfo.ucRsneLen; + + /* Fill RSNE PMKID Count and List */ + prConnSettings->rRsnInfo.u2PmkidCnt = rRsnInfo.u2PmkidCnt; + if (rRsnInfo.u2PmkidCnt > 0) { + kalMemCopy(prConnSettings->rRsnInfo.aucPmkidList, + rRsnInfo.aucPmkidList, + (rRsnInfo.u2PmkidCnt * RSN_PMKID_LEN)); + } + } + } + + /* Gen OWE IE */ + if (wextSrchDesiredWPAIE(pucIEStart, req->ie_len, 0xff, + (u8 **)&prDesiredIE)) { + u8 ucLength = (*(prDesiredIE + 1) + 2); + + kalMemCopy(&prGlueInfo->prAdapter->rWifiVar.rConnSettings.rOweInfo, + prDesiredIE, ucLength); + + DBGLOG(REQ, INFO, "DUMP OWE INFO, EID %x length %x\n", *prDesiredIE, + ucLength); + DBGLOG_MEM8(REQ, INFO, + &prGlueInfo->prAdapter->rWifiVar.rConnSettings.rOweInfo, + ucLength); + } else { + kalMemSet(&prGlueInfo->prAdapter->rWifiVar.rConnSettings.rOweInfo, + 0, sizeof(struct OWE_INFO_T)); + } + + /* Gen RSNXE */ + if (wextSrchDesiredWPAIE(pucIEStart, req->ie_len, 0xf4, + (u8 **)&prDesiredIE)) { + u16 u2Length = (*(prDesiredIE + 1) + 2); + + if (u2Length <= sizeof(prConnSettings->rRsnXE)) { + kalMemCopy(&prConnSettings->rRsnXE, prDesiredIE, u2Length); + fgCarryRsnxe = true; + + DBGLOG(REQ, INFO, "DUMP RSNXE, EID %x length %x\n", + *prDesiredIE, u2Length); + DBGLOG_MEM8(REQ, INFO, &prConnSettings->rRsnXE, u2Length); + } else { + DBGLOG(RSN, ERROR, "RSNXE length exceeds 2\n"); + } + } + + if (fgCarryRsnxe == false) { + kalMemSet(&prConnSettings->rRsnXE, 0, sizeof(struct RSNXE)); + } + + /* clear WSC Assoc IE buffer in case WPS IE is not detected */ + if (fgCarryWPSIE == false) { + kalMemZero(&prGlueInfo->aucWSCAssocInfoIE, 200); + prGlueInfo->u2WSCAssocInfoIELen = 0; + } + } + /* Fill WPA info - mfp setting */ + /* Must put after paring RSNE from upper layer + * for prGlueInfo->rWpaInfo.ucRSNMfpCap assignment + */ + +#if CFG_SUPPORT_802_11W + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; + if (req->use_mfp) { + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_REQUIRED; + } else { + /* Change Mfp parameter from DISABLED to OPTIONAL + * if upper layer set MFPC = 1 in RSNE + * since upper layer can't bring MFP OPTIONAL information + * to driver by sme->mfp + */ + if (prGlueInfo->rWpaInfo.ucRSNMfpCap == RSN_AUTH_MFP_OPTIONAL) { + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_OPTIONAL; + } else if (prGlueInfo->rWpaInfo.ucRSNMfpCap == RSN_AUTH_MFP_REQUIRED) { + DBGLOG(REQ, WARN, + "mfp parameter(DISABLED) conflict with mfp cap(REQUIRED)\n"); + } + } +#endif + + prConnSettings->fgIsSendAssoc = true; + if (!prConnSettings->fgIsConnInitialized) { + DBGLOG(REQ, WARN, "Send assoc without connection initialized first\n"); + rStatus = kalIoctl(prGlueInfo, wlanoidSetBssid, (void *)req->bss->bssid, + MAC_ADDR_LEN, false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "set BSSID:%x\n", rStatus); + return -EINVAL; + } + } else { /* skip join initial flow when it has been completed*/ + prStaRec = cnmGetStaRecByAddress( + prGlueInfo->prAdapter, + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex, req->bss->bssid); + + if (prStaRec) { + saaSendAuthAssoc(prGlueInfo->prAdapter, prStaRec); + DBGLOG(REQ, STATE, "Send assoc.\n"); + } else { + DBGLOG(REQ, WARN, "can't send assoc since can't find StaRec\n"); + } + } + + return 0; +} + +#if CFG_SUPPORT_NFC_BEAM_PLUS + +int mtk_cfg80211_testmode_get_scan_done(IN struct wiphy *wiphy, IN void *data, + IN int len, + IN P_GLUE_INFO_T prGlueInfo) +{ +#define NL80211_TESTMODE_P2P_SCANDONE_INVALID 0 +#define NL80211_TESTMODE_P2P_SCANDONE_STATUS 1 + +#ifdef CONFIG_NL80211_TESTMODE +#if !DBG_DISABLE_ALL_LOG + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; +#endif + s32 i4Status = -EINVAL, READY_TO_BEAM = 0; + + struct sk_buff *skb = NULL; + + ASSERT(wiphy); + ASSERT(prGlueInfo); + + skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(u32)); + + /* READY_TO_BEAM = */ + /* (u32)(prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone) + */ + /* &(!prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsScanRequest); + */ + READY_TO_BEAM = 1; + /* DBGLOG(QM, TRACE, */ + /* ("NFC:GOInitialDone[%d] and P2PScanning[%d]\n", */ + /* prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsGOInitialDone, + */ + /* prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->rScanReqInfo.fgIsScanRequest)); + */ + + if (!skb) { + DBGLOG(QM, TRACE, "%s allocate skb failed:%lx\n", __func__, rStatus); + return -ENOMEM; + } + { + u8 __tmp = 0; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_P2P_SCANDONE_INVALID, + sizeof(u8), &__tmp) < 0)) { + kfree_skb(skb); + goto nla_put_failure; + } + } + { + u32 __tmp = READY_TO_BEAM; + + if (unlikely(nla_put(skb, NL80211_TESTMODE_P2P_SCANDONE_STATUS, + sizeof(u32), &__tmp) < 0)) { + kfree_skb(skb); + goto nla_put_failure; + } + } + + i4Status = cfg80211_testmode_reply(skb); + +nla_put_failure: + return i4Status; + +#else + DBGLOG(QM, WARN, "CONFIG_NL80211_TESTMODE not enabled\n"); + return -EINVAL; + +#endif +} + +#endif + +#if CFG_SUPPORT_TDLS + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for changing a station information + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, + struct station_parameters *params) +{ + /* return 0; */ + + /* from supplicant -- wpa_supplicant_tdls_peer_addset() */ + P_GLUE_INFO_T prGlueInfo = NULL; + CMD_PEER_UPDATE_T rCmdUpdate; + WLAN_STATUS rStatus; + u32 u4BufLen, u4Temp; + u8 *u4Rates; + ADAPTER_T *prAdapter; + P_BSS_INFO_T prAisBssInfo; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + /* make up command */ + + prAdapter = prGlueInfo->prAdapter; + prAisBssInfo = prAdapter->prAisBssInfo; + + if (params == NULL) { + return 0; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0)) + u4Rates = params->supported_rates; + u4Temp = params->supported_rates_len; +#else + u4Rates = (u8 *) params->link_sta_params.supported_rates; + u4Temp = params->link_sta_params.supported_rates_len; +#endif + + if (u4Rates == NULL) { + return 0; + } + + /* init */ + kalMemZero(&rCmdUpdate, sizeof(rCmdUpdate)); + kalMemCopy(rCmdUpdate.aucPeerMac, mac, 6); + + if (u4Temp > CMD_PEER_UPDATE_SUP_RATE_MAX) { + u4Temp = CMD_PEER_UPDATE_SUP_RATE_MAX; + } + + kalMemCopy(rCmdUpdate.aucSupRate, u4Rates, u4Temp); + rCmdUpdate.u2SupRateLen = u4Temp; + + /* + * In supplicant, only recognize WLAN_EID_QOS 46, not 0xDD WMM + * So force to support UAPSD here. + */ + rCmdUpdate.UapsdBitmap = 0x0F; /*params->uapsd_queues; */ + rCmdUpdate.UapsdMaxSp = 0; /*params->max_sp; */ + + rCmdUpdate.u2Capability = params->capability; + + if (params->ext_capab != NULL) { + u4Temp = params->ext_capab_len; + if (u4Temp > CMD_PEER_UPDATE_EXT_CAP_MAXLEN) { + u4Temp = CMD_PEER_UPDATE_EXT_CAP_MAXLEN; + } + kalMemCopy(rCmdUpdate.aucExtCap, params->ext_capab, u4Temp); + rCmdUpdate.u2ExtCapLen = u4Temp; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0)) +#define HT_CAPA params->ht_capa +#define VHT_CAPA params->vht_capa +#else +#define HT_CAPA params->link_sta_params.ht_capa +#define VHT_CAPA params->link_sta_params.vht_capa +#endif + + if (HT_CAPA != NULL) { + rCmdUpdate.rHtCap.u2CapInfo = HT_CAPA->cap_info; + rCmdUpdate.rHtCap.ucAmpduParamsInfo = HT_CAPA->ampdu_params_info; + rCmdUpdate.rHtCap.u2ExtHtCapInfo = HT_CAPA->extended_ht_cap_info; + rCmdUpdate.rHtCap.u4TxBfCapInfo = HT_CAPA->tx_BF_cap_info; + rCmdUpdate.rHtCap.ucAntennaSelInfo = HT_CAPA->antenna_selection_info; + kalMemCopy(rCmdUpdate.rHtCap.rMCS.arRxMask, HT_CAPA->mcs.rx_mask, + sizeof(rCmdUpdate.rHtCap.rMCS.arRxMask)); + + rCmdUpdate.rHtCap.rMCS.u2RxHighest = HT_CAPA->mcs.rx_highest; + rCmdUpdate.rHtCap.rMCS.ucTxParams = HT_CAPA->mcs.tx_params; + rCmdUpdate.fgIsSupHt = true; + } + /* vht */ + + if (VHT_CAPA != NULL) { + rCmdUpdate.rVHtCap.u4CapInfo = VHT_CAPA->vht_cap_info; + rCmdUpdate.rVHtCap.rVMCS.u2RxMcsMap = VHT_CAPA->supp_mcs.rx_mcs_map; + rCmdUpdate.rVHtCap.rVMCS.u2RxHighest = VHT_CAPA->supp_mcs.rx_highest; + rCmdUpdate.rVHtCap.rVMCS.u2TxMcsMap = VHT_CAPA->supp_mcs.tx_mcs_map; + rCmdUpdate.rVHtCap.rVMCS.u2TxHighest = VHT_CAPA->supp_mcs.tx_highest; + rCmdUpdate.fgIsSupVht = true; + } + + /* update a TDLS peer record */ + /* sanity check */ + if ((params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) { + rCmdUpdate.eStaType = STA_TYPE_DLS_PEER; + } + rStatus = kalIoctl(prGlueInfo, cnmPeerUpdate, &rCmdUpdate, + sizeof(CMD_PEER_UPDATE_T), false, false, false, + /* false, //6628 -> 6630 fgIsP2pOid-> x */ + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EINVAL; + } + + /* for Ch Sw AP prohibit case */ + if (prAisBssInfo->fgTdlsIsChSwProhibited) { + /* disable TDLS ch sw function */ + + rStatus = kalIoctl(prGlueInfo, TdlsSendChSwControlCmd, + &TdlsSendChSwControlCmd, sizeof(CMD_TDLS_CH_SW_T), + false, false, false, + /* false, //6628 -> 6630 fgIsP2pOid-> x */ + &u4BufLen); + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for adding a station information + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_add_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_parameters *params) +{ + /* return 0; */ + + /* from supplicant -- wpa_supplicant_tdls_peer_addset() */ + P_GLUE_INFO_T prGlueInfo = NULL; + CMD_PEER_ADD_T rCmdCreate; + ADAPTER_T *prAdapter; + WLAN_STATUS rStatus; + u32 u4BufLen; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + /* make up command */ + + prAdapter = prGlueInfo->prAdapter; + + /* init */ + kalMemZero(&rCmdCreate, sizeof(rCmdCreate)); + kalMemCopy(rCmdCreate.aucPeerMac, mac, 6); + + /* create a TDLS peer record */ + if ((params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))) { + rCmdCreate.eStaType = STA_TYPE_DLS_PEER; + rStatus = kalIoctl(prGlueInfo, cnmPeerAdd, &rCmdCreate, + sizeof(CMD_PEER_ADD_T), false, false, false, + /* false, //6628 -> 6630 fgIsP2pOid-> x + */ + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EINVAL; + } + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for deleting a station information + * + * @param + * + * @retval 0: successful + * others: failure + * + * @other + * must implement if you have add_station(). + */ +/*----------------------------------------------------------------------------*/ +static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +int mtk_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params) +{ + /* fgIsTDLSlinkEnable = 0; */ + + /* return 0; */ + /* from supplicant -- wpa_supplicant_tdls_peer_addset() */ + + const u8 *mac = params->mac ? params->mac : bcast_addr; + P_GLUE_INFO_T prGlueInfo = NULL; + ADAPTER_T *prAdapter; + STA_RECORD_T *prStaRec; + u8 deleteMac[MAC_ADDR_LEN]; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + + /* For kernel 3.18 modification, we trasfer to local buff to query sta + */ + memset(deleteMac, 0, MAC_ADDR_LEN); + memcpy(deleteMac, mac, MAC_ADDR_LEN); + + prStaRec = cnmGetStaRecByAddress( + prAdapter, (u8)prAdapter->prAisBssInfo->ucBssIndex, deleteMac); + + if (prStaRec != NULL) { + cnmStaRecFree(prAdapter, prStaRec); + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to transmit a TDLS data frame from nl80211. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] + * \param[in] + * \param[in] buf includes RSN IE + FT IE + Lifetimeout IE + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, +#if (CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)) + int link_id, +#endif + u8 action_code, u8 dialog_token, u16 status_code, + u32 peer_capability, bool initiator, const u8 *buf, + size_t len) +{ + GLUE_INFO_T *prGlueInfo; + TDLS_CMD_LINK_MGT_T rCmdMgt; + u32 u4BufLen; + + /* sanity check */ + if ((wiphy == NULL) || (peer == NULL) || (buf == NULL)) { + return -EINVAL; + } + + /* init */ + prGlueInfo = (GLUE_INFO_T *)wiphy_priv(wiphy); + if (prGlueInfo == NULL) { + return -EINVAL; + } + + kalMemZero(&rCmdMgt, sizeof(rCmdMgt)); + + rCmdMgt.u2StatusCode = status_code; + rCmdMgt.u4SecBufLen = len; + rCmdMgt.ucDialogToken = dialog_token; + rCmdMgt.ucActionCode = action_code; + kalMemCopy(&(rCmdMgt.aucPeer), peer, 6); + + if (len > TDLS_SEC_BUF_LENGTH) { + DBGLOG(REQ, WARN, "%s:len > TDLS_SEC_BUF_LENGTH\n", __func__); + return -EINVAL; + } + + kalMemCopy(&(rCmdMgt.aucSecBuf), buf, len); + + kalIoctl(prGlueInfo, TdlsexLinkMgt, &rCmdMgt, sizeof(TDLS_CMD_LINK_MGT_T), + false, false, false, + /* false, //6628 -> 6630 fgIsP2pOid-> x */ + &u4BufLen); + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to hadel TDLS link from nl80211. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * \param[in] + * \param[in] + * \param[in] buf includes RSN IE + FT IE + Lifetimeout IE + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_LENGTH + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, enum nl80211_tdls_operation oper) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u32 u4BufLen; + ADAPTER_T *prAdapter; + TDLS_CMD_LINK_OPER_T rCmdOper; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + prAdapter = prGlueInfo->prAdapter; + + kalMemZero(&rCmdOper, sizeof(rCmdOper)); + kalMemCopy(rCmdOper.aucPeerMac, peer, 6); + + rCmdOper.oper = (ENUM_TDLS_LINK_OPER) oper; + + kalIoctl(prGlueInfo, TdlsexLinkOper, &rCmdOper, + sizeof(TDLS_CMD_LINK_OPER_T), false, false, false, + /* false, //6628 -> 6630 fgIsP2pOid-> x */ + &u4BufLen); + return 0; +} + +#endif + +s32 mtk_cfg80211_process_str_cmd(P_GLUE_INFO_T prGlueInfo, u8 *cmd, s32 len) +{ + u32 rStatus = WLAN_STATUS_SUCCESS; + +#if CFG_SUPPORT_802_11K || CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + u32 u4SetInfoLen = 0; +#endif + +#if CFG_SUPPORT_802_11K + if (strnicmp(cmd, "NEIGHBOR-REQUEST", 16) == 0) { + u8 *pucSSID = NULL; + u32 u4SSIDLen = 0; + + if (len > 16 && (strnicmp(cmd + 16, " SSID=", 6) == 0)) { + pucSSID = cmd + 22; + u4SSIDLen = len - 22; + DBGLOG(REQ, ERROR, "cmd=%s, ssid len %u, ssid=%s\n", cmd, u4SSIDLen, + pucSSID); + } + rStatus = kalIoctl(prGlueInfo, wlanoidSendNeighborRequest, + (void *)pucSSID, u4SSIDLen, false, false, true, + &u4SetInfoLen); + } else { + return -EOPNOTSUPP; + } +#endif + +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + if (strnicmp(cmd, "BSS-TRANSITION-QUERY", 20) == 0) { + u8 *pucReason = NULL; + + if (len > 20 && (strnicmp(cmd + 20, " reason=", 8) == 0)) { + pucReason = cmd + 28; + } + rStatus = kalIoctl(prGlueInfo, wlanoidSendBTMQuery, (void *)pucReason, + 1, false, false, true, &u4SetInfoLen); + } else { + return -EOPNOTSUPP; + } +#endif + + if (rStatus == WLAN_STATUS_SUCCESS) { + return 0; + } + + return -EINVAL; +} + +#if !(CFG_BUILT_IN_DRIVER) +bool is_world_regdom(char *alpha2) +{ + if (!alpha2) { + return false; + } + + return (alpha2[0] == '0') && (alpha2[1] == '0'); +} +#endif + +enum regd_state regd_state_machine(IN struct regulatory_request *pRequest) +{ + switch (pRequest->initiator) { + case NL80211_REGDOM_SET_BY_USER: + DBGLOG(RLM, INFO, "regd_state_machine: SET_BY_USER\n"); + + return rlmDomainStateTransition(REGD_STATE_SET_COUNTRY_USER, pRequest); + + case NL80211_REGDOM_SET_BY_DRIVER: + DBGLOG(RLM, INFO, "regd_state_machine: SET_BY_DRIVER\n"); + + return rlmDomainStateTransition(REGD_STATE_SET_COUNTRY_DRIVER, + pRequest); + + case NL80211_REGDOM_SET_BY_CORE: + DBGLOG(RLM, INFO, "regd_state_machine: SET_BY_CORE\n"); + + return rlmDomainStateTransition(REGD_STATE_SET_WW_CORE, pRequest); + + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + DBGLOG(RLM, WARN, "regd_state_machine: SET_BY_COUNTRY_IE\n"); + + /* Received Country Information Element in a beacon frame. */ + return rlmDomainStateTransition(REGD_STATE_SET_COUNTRY_IE, pRequest); + + default: + return rlmDomainStateTransition(REGD_STATE_INVALID, pRequest); + } +} + +void mtk_apply_custom_regulatory(IN struct wiphy *pWiphy, + IN const struct ieee80211_regdomain *pRegdom) +{ + u32 band_idx, ch_idx; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + + DBGLOG(RLM, INFO, "%s()\n", __func__); + + /* to reset cha->flags*/ + for (band_idx = 0; band_idx < NUM_NL80211_BANDS; band_idx++) { + sband = pWiphy->bands[band_idx]; + if (!sband) { + continue; + } + + for (ch_idx = 0; ch_idx < sband->n_channels; ch_idx++) { + chan = &sband->channels[ch_idx]; + + /*reset chan->flags*/ + chan->flags = 0; + } + } + + /* update to kernel */ + wiphy_apply_custom_regulatory(pWiphy, pRegdom); +} + +void mtk_reg_notify(IN struct wiphy *pWiphy, + IN struct regulatory_request *pRequest) +{ + P_GLUE_INFO_T prGlueInfo; + P_ADAPTER_T prAdapter; + enum regd_state old_state; + + if (!pWiphy) { + DBGLOG(RLM, ERROR, "%s(): pWiphy = NULL.\n", __func__); + return; + } + + if (g_u4HaltFlag) { + DBGLOG(RLM, WARN, "wlan is halt, skip reg callback\n"); + return; + } + + /* + * Magic flow for driver to send inband command after kernel's calling + * reg_notifier callback + */ + if (!pRequest) { + /*triggered by our driver in wlan initial process.*/ + + if (rlmDomainIsCtrlStateEqualTo(REGD_STATE_INIT)) { + if (rlmDomainIsUsingLocalRegDomainDataBase()) { + DBGLOG(RLM, WARN, "County Code is not assigned. Use default WW.\n"); + goto DOMAIN_SEND_CMD; + } else { + DBGLOG(RLM, ERROR, "Invalid REG state happened. state = 0x%x\n", + rlmDomainGetCtrlState()); + return; + } + } else if ((rlmDomainIsCtrlStateEqualTo(REGD_STATE_SET_WW_CORE)) || + (rlmDomainIsCtrlStateEqualTo(REGD_STATE_SET_COUNTRY_USER)) || + (rlmDomainIsCtrlStateEqualTo( + REGD_STATE_SET_COUNTRY_DRIVER))) { + goto DOMAIN_SEND_CMD; + } else { + DBGLOG(RLM, ERROR, "Invalid REG state happened. state = 0x%x\n", + rlmDomainGetCtrlState()); + return; + } + } + + /* + * Ignore the CORE's WW setting when using local data base of regulatory + * rules + */ + if ((pRequest->initiator == NL80211_REGDOM_SET_BY_CORE) && + (pWiphy->regulatory_flags & REGULATORY_CUSTOM_REG)) { + return; /*Ignore the CORE's WW setting*/ + } + /* + * State machine transition + */ + DBGLOG(RLM, INFO, "request->alpha2=%s, initiator=%x, intersect=%d\n", + pRequest->alpha2, pRequest->initiator, pRequest->intersect); + + old_state = rlmDomainGetCtrlState(); + regd_state_machine(pRequest); + + if (rlmDomainGetCtrlState() == old_state) { + if ((old_state == REGD_STATE_SET_COUNTRY_USER) && + (!(rlmDomainIsSameCountryCode(pRequest->alpha2, + sizeof(pRequest->alpha2))))) { + DBGLOG(RLM, INFO, "Set by user to NEW country code\n"); + } else if (old_state != REGD_STATE_SET_COUNTRY_DRIVER) { + /* Change to same state or same country, ignore */ + return; + } + } else if (rlmDomainIsCtrlStateEqualTo(REGD_STATE_INVALID)) { + DBGLOG(RLM, ERROR, "\n%s():\n---> WARNING. Transit to invalid state.\n", + __func__); + DBGLOG(RLM, ERROR, "---> WARNING.\n "); + rlmDomainAssert(0); + } + + /* + * Set country code + */ + if (pRequest->initiator != NL80211_REGDOM_SET_BY_DRIVER) { + rlmDomainSetCountryCode(pRequest->alpha2, sizeof(pRequest->alpha2)); + } else { + /*SET_BY_DRIVER*/ + + if (rlmDomainIsEfuseUsed()) { + if (!rlmDomainIsUsingLocalRegDomainDataBase()) { + DBGLOG( + RLM, WARN, + "[WARNING!!!] Local DB must be used if country code from efuse.\n"); + } + } else { + /* iwpriv case */ + if (rlmDomainIsUsingLocalRegDomainDataBase()) { + /*iwpriv set country but local data base*/ + u32 country_code = rlmDomainGetTempCountryCode(); + + rlmDomainSetCountryCode((char *)&country_code, + sizeof(country_code)); + } else { + /*iwpriv set country but query CRDA*/ + rlmDomainSetCountryCode(pRequest->alpha2, + sizeof(pRequest->alpha2)); + } + } + } + + rlmDomainSetDfsRegion(pRequest->dfs_region); + +DOMAIN_SEND_CMD: + DBGLOG(RLM, INFO, "g_mtk_regd_control.alpha2 = 0x%x\n", + rlmDomainGetCountryCode()); + + /* + * Check if using customized regulatory rule + */ + if (rlmDomainIsUsingLocalRegDomainDataBase() && + rlmDomainIsEfuseUsed()) { + const struct ieee80211_regdomain *pRegdom; + u32 country_code = rlmDomainGetCountryCode(); + char alpha2[4]; + + /*fetch regulatory rules from local data base*/ + alpha2[0] = country_code & 0xFF; + alpha2[1] = (country_code >> 8) & 0xFF; + alpha2[2] = (country_code >> 16) & 0xFF; + alpha2[3] = (country_code >> 24) & 0xFF; + + pRegdom = rlmDomainSearchRegdomainFromLocalDataBase(alpha2); + if (!pRegdom) { + DBGLOG( + RLM, INFO, + "%s(): Error, Cannot find the correct RegDomain. country = %s\n", + __func__, rlmDomainGetCountryCode()); + + rlmDomainAssert(0); + return; + } + + mtk_apply_custom_regulatory(pWiphy, pRegdom); + } + + /* + * Always use the wlan GlueInfo as parameter. + */ + prGlueInfo = rlmDomainGetGlueInfo(); + if (!prGlueInfo) { + DBGLOG(RLM, INFO, "prGlueInfo is NULL!\n"); + return; /*interface is not up yet.*/ + } + prAdapter = prGlueInfo->prAdapter; + if (!prAdapter) { + DBGLOG(RLM, INFO, "prAdapter is NULL!\n"); + return; /*interface is not up yet.*/ + } + /* + * Awlays use wlan0's base wiphy pointer to update reg notifier. + * Because only one reg state machine is handled. + */ + if (pWiphy != priv_to_wiphy(prAdapter->prGlueInfo)) { + pWiphy = priv_to_wiphy(prAdapter->prGlueInfo); + DBGLOG(RLM, INFO, "Use base wiphy to update (p=0x%x)\n", + priv_to_wiphy(prAdapter->prGlueInfo)); + } + + /* + * Parsing channels + */ + rlmDomainParsingChannel(pWiphy); /*real regd update*/ + + /* + * Check if firmawre support single sku + */ + if (!regd_is_single_sku_en()) { + return; /*no need to send information to firmware due to + * firmware is not supported*/ + } + /* + * Send commands to firmware + */ + prAdapter->rWifiVar.rConnSettings.u2CountryCode = + (u16)rlmDomainGetCountryCode(); + rlmDomainSendCmd(prAdapter, false); +} + +void cfg80211_regd_set_wiphy(IN struct wiphy *prWiphy) +{ + /* + * register callback + */ + prWiphy->reg_notifier = mtk_reg_notify; + + /* + * clear REGULATORY_CUSTOM_REG flag + */ + prWiphy->regulatory_flags &= ~(REGULATORY_CUSTOM_REG); + + /*ignore the hint from IE*/ + prWiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; + +#ifdef CFG_SUPPORT_DISABLE_BCN_HINTS + prWiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS; +#endif + + /* + * set REGULATORY_CUSTOM_REG flag + */ +#if (CFG_SUPPORT_SINGLE_SKU_LOCAL_DB == 1) + prWiphy->regulatory_flags |= (REGULATORY_CUSTOM_REG); + + /* assigned a defautl one */ + if (rlmDomainGetLocalDefaultRegd()) { + wiphy_apply_custom_regulatory(prWiphy, rlmDomainGetLocalDefaultRegd()); + } +#endif + + /* + * Initialize regd control information + */ + rlmDomainResetCtrlInfo(false); +} + +/* + * Use these commands to control the enable and disable of WoWLAN. + * iw phy0 wowlan disable + * iw phy0 wowlan enable any + */ +void mtk_cfg80211_set_wakeup(struct wiphy *wiphy, bool enabled) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + DBGLOG(REQ, WARN, "%s\n", enabled ? "enabled" : "disalbed"); + + if (prGlueInfo && prGlueInfo->prAdapter) { + prGlueInfo->prAdapter->rWowCtrl.fgWowEnable = enabled; + } else { + DBGLOG(REQ, WARN, "not applied (%p, %p)\n", prGlueInfo, + prGlueInfo ? prGlueInfo->prAdapter : NULL); + } +} + +int mtk_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow) +{ + P_GLUE_INFO_T prGlueInfo; + ADAPTER_T *prAdapter; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + DBGLOG(REQ, INFO, "CFG80211 suspend CB\n"); + if (!wlanGetGlueInfo()) { + DBGLOG(REQ, ERROR, "NIC does not exist!\n"); + return 0; + } + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + prAdapter->fgIsCfg80211SuspendCalled = true; + + DBGLOG(REQ, WARN, "Wow:%d, WowEnable:%d, state:%d\n", + prGlueInfo->prAdapter->rWifiVar.ucWow, + prGlueInfo->prAdapter->rWowCtrl.fgWowEnable, + kalGetMediaStateIndicated(prGlueInfo)); + + rStatus = wlanSuspendLinkDown(prGlueInfo); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "cfg 80211 suspend fail!\n"); + return -EINVAL; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief cfg80211 resume callback, will be invoked in wiphy_resume. + * + * @param wiphy: pointer to wiphy + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_cfg80211_resume(struct wiphy *wiphy) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 rStatus, u4InfoLen; + + DBGLOG(REQ, TRACE, "mtk_cfg80211_resume\n"); + + WIPHY_PRIV(wiphy, prGlueInfo); + if (prGlueInfo) { + prAdapter = prGlueInfo->prAdapter; + } + if (prAdapter == NULL) { + goto end; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidIndicateBssInfo, (void *)NULL, 0, + false, false, false, &u4InfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "ScanResultLog error:%x\n", rStatus); + } +end: + return 0; +} + +#if CFG_ENABLE_UNIFY_WIPHY +/*----------------------------------------------------------------------------*/ +/*! + * @brief Check the net device is P2P net device (P2P GO/GC, AP), or not. + * + * @param prGlueInfo : the driver private data + * ndev : the net device + * + * @retval 0: AIS device (STA/IBSS) + * 1: P2P GO/GC, AP + */ +/*----------------------------------------------------------------------------*/ +int mtk_IsP2PNetDevice(P_GLUE_INFO_T prGlueInfo, struct net_device *ndev) +{ + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = NULL; + int iftype = 0; + int ret = 1; + + if (ndev == NULL) { + DBGLOG(REQ, WARN, "ndev is NULL\n"); + return -1; + } + + prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(ndev); + iftype = ndev->ieee80211_ptr->iftype; + + /* P2P device/GO/GC always return 1 */ + if (prNetDevPrivate->ucIsP2p == true) { + ret = 1; + }else if (iftype == NL80211_IFTYPE_STATION) { + ret = 0; + }else if (iftype == NL80211_IFTYPE_ADHOC) { + ret = 0; + } + + DBGLOG(REQ, INFO, "cfg path select = %d\n", ret); + return ret; +} +/*----------------------------------------------------------------------------*/ +/*! + * @brief Initialize the AIS related FSM and data. + * + * @param prGlueInfo : the driver private data + * ndev : the net device + * ucBssIdx : the AIS BSS index adssigned by the driver (wlanProbe) + * + * @retval 0 + * + */ +/*----------------------------------------------------------------------------*/ +int mtk_init_sta_role(P_ADAPTER_T prAdapter, struct net_device *ndev) +{ + P_NETDEV_PRIVATE_GLUE_INFO prNdevPriv = NULL; + + if ((prAdapter == NULL) || (ndev == NULL)) { + return -1; + } + + /* uninit AIS FSM */ + aisFsmInit(prAdapter); + +#if CFG_SUPPORT_ROAMING + /* Roaming Module - unintiailization */ + roamingFsmInit(prAdapter); +#endif /* CFG_SUPPORT_ROAMING */ + + ndev->netdev_ops = wlanGetNdevOps(); + ndev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; + kal_eth_hw_addr_set(ndev, prAdapter->rMyMacAddr); + + /* set the ndev's ucBssIdx to the AIS BSS index */ + prNdevPriv = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(ndev); + prNdevPriv->ucBssIdx = prAdapter->prAisBssInfo->ucBssIndex; + return 0; +} +/*----------------------------------------------------------------------------*/ +/*! + * @brief Uninitialize the AIS related FSM and data. + * + * @param prAdapter : the driver private data + * + * @retval 0 + * + */ +/*----------------------------------------------------------------------------*/ +int mtk_uninit_sta_role(P_ADAPTER_T prAdapter, struct net_device *ndev) +{ + P_NETDEV_PRIVATE_GLUE_INFO prNdevPriv = NULL; + + if ((prAdapter == NULL) || (ndev == NULL)) { + return -1; + } + +#if CFG_SUPPORT_ROAMING + /* Roaming Module - unintiailization */ + roamingFsmUninit(prAdapter); +#endif /* CFG_SUPPORT_ROAMING */ + + /* uninit AIS FSM */ + aisFsmUninit(prAdapter); + + /* set the ucBssIdx to the illegal value */ + prNdevPriv = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(ndev); + prNdevPriv->ucBssIdx = 0xff; + return 0; +} +/*----------------------------------------------------------------------------*/ +/*! + * @brief Initialize the AP (P2P) related FSM and data. + * + * @param prGlueInfo : the driver private data + * ndev : net device + * + * @retval 0 : success + * others : can't alloc and setup the AP FSM & data + * + */ +/*----------------------------------------------------------------------------*/ +int mtk_init_ap_role(P_GLUE_INFO_T prGlueInfo, struct net_device *ndev) +{ + int u4Idx = 0; + P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; + + for (u4Idx = 0; u4Idx < KAL_P2P_NUM; u4Idx++) + if (gprP2pRoleWdev[u4Idx] == NULL) { + break; + } + + if (u4Idx >= KAL_P2P_NUM) { + DBGLOG(INIT, ERROR, "There is no free gprP2pRoleWdev.\n"); + return -ENOMEM; + } + + if ((u4Idx == 0) || (prAdapter == NULL) || + (prAdapter->rP2PNetRegState != ENUM_NET_REG_STATE_REGISTERED)) { + DBGLOG(INIT, ERROR, "The wlan0 can't set to AP without p2p0\n"); + /* System will crash, if p2p0 isn't existing. */ + return -EFAULT; + } + + /* reference from the glRegisterP2P() */ + gprP2pRoleWdev[u4Idx] = ndev->ieee80211_ptr; + + if (glSetupP2P(prGlueInfo, gprP2pRoleWdev[u4Idx], ndev, u4Idx, true)) { + gprP2pRoleWdev[u4Idx] = NULL; + return -EFAULT; + } + + prGlueInfo->prAdapter->prP2pInfo->u4DeviceNum++; + + /* reference from p2pNetRegister() */ + /* The ndev doesn't need register_netdev, only reassign the gPrP2pDev.*/ + gPrP2pDev[u4Idx] = ndev; + + return 0; +} +/*----------------------------------------------------------------------------*/ +/*! + * @brief Unnitialize the AP (P2P) related FSM and data. + * + * @param prGlueInfo : the driver private data + * ndev : net device + * + * @retval 0 : success + * others : can't find the AP information by the ndev + * + */ +/*----------------------------------------------------------------------------*/ +int mtk_uninit_ap_role(P_GLUE_INFO_T prGlueInfo, struct net_device *ndev) +{ + unsigned char u4Idx; + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, ndev, &u4Idx) != 0) { + DBGLOG(INIT, WARN, "can't find the matched dev to uninit AP\n"); + return -EFAULT; + } + + glUnregisterP2P(prGlueInfo, u4Idx); + + gPrP2pDev[u4Idx] = NULL; + gprP2pRoleWdev[u4Idx] = NULL; + + return 0; +} + +#if (CFG_SUPPORT_DFS_MASTER == 1) +int mtk_cfg_start_radar_detection(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, + unsigned int cac_time_ms +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) + , int link_id +#endif + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + uint8_t state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) { + // DBGLOG(REQ, WARN, "STA doesn't support this function\n"); + return -EFAULT; + } + + return mtk_p2p_cfg80211_start_radar_detection(wiphy, + dev, chandef, cac_time_ms +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) + , link_id +#endif + ); +} + +int mtk_cfg_channel_switch(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_csa_settings *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + uint8_t state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) { + // DBGLOG(REQ, WARN, "STA doesn't support this function\n"); + return -EFAULT; + } + + return mtk_p2p_cfg80211_channel_switch(wiphy, dev, params); +} +#endif + +struct wireless_dev *mtk_cfg_add_iface(struct wiphy *wiphy, const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + struct vif_params *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return ERR_PTR(-EFAULT); + } + + + /* TODO: error handele for the non-P2P interface */ +#if (CFG_ENABLE_WIFI_DIRECT_CFG_80211 == 0) + DBGLOG(REQ, WARN, "P2P is not supported\n"); + return ERR_PTR(-EINVAL); +#else /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */ + + return mtk_p2p_cfg80211_add_iface(wiphy, name, name_assign_type, type, + params); + +#endif /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */ +} +int mtk_cfg_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + /* TODO: error handele for the non-P2P interface */ +#if (CFG_ENABLE_WIFI_DIRECT_CFG_80211 == 0) + DBGLOG(REQ, WARN, "P2P is not supported\n"); + return -EINVAL; +#else /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */ + return mtk_p2p_cfg80211_del_iface(wiphy, wdev); +#endif /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */ +} + + +int mtk_cfg_change_iface(struct wiphy *wiphy, struct net_device *ndev, + enum nl80211_iftype type, + struct vif_params *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + P_NETDEV_PRIVATE_GLUE_INFO prNetdevPriv = NULL; + P_P2P_INFO_T prP2pInfo = NULL; + struct cfg80211_scan_request *prScanRequest = NULL; + u8 state = 0; + + GLUE_SPIN_LOCK_DECLARATION(); + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + ASSERT(prGlueInfo); + + DBGLOG(P2P, INFO, "ndev=%p, new type=%d\n", ndev, type); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (!ndev) { + DBGLOG(REQ, WARN, "ndev is NULL\n"); + return -EINVAL; + } + + prNetdevPriv = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(ndev); + +#if (CFG_ENABLE_WIFI_DIRECT_CFG_80211) + /* P2P Interfcace */ + if (prNetdevPriv->ucIsP2p == true) { + return mtk_p2p_cfg80211_change_iface(wiphy, ndev, type, params); + } +#endif /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */ + + prAdapter = prGlueInfo->prAdapter; + + if (ndev->ieee80211_ptr->iftype == type) { + DBGLOG(REQ, INFO, "ndev type is not changed (%d)\n", type); + return 0; + } + + netif_carrier_off(ndev); + /* stop ap will stop all queue, and kalIndicateStatusAndComplete only do + * netif_carrier_on. So that, the following STA can't send 4-way M2 to + * AP. + */ + netif_tx_stop_all_queues(ndev); + + /* flush scan */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if ((prGlueInfo->prScanRequest != NULL) && + (prGlueInfo->prScanRequest->wdev == ndev->ieee80211_ptr)) { + prScanRequest = prGlueInfo->prScanRequest; + if (prScanRequest) { + kalCfg80211ScanDone(prScanRequest, true); + } + prGlueInfo->prScanRequest = NULL; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + /* expect that only AP & STA will be handled here (excluding IBSS) */ + if (type == NL80211_IFTYPE_AP) { + /* STA mode change to AP mode */ + prP2pInfo = prAdapter->prP2pInfo; + + if (prP2pInfo == NULL) { + DBGLOG(INIT, ERROR, "prP2pInfo is NULL\n"); + return -EFAULT; + } + + if (prP2pInfo->u4DeviceNum >= KAL_P2P_NUM) { + DBGLOG(INIT, ERROR, "resource invalid, u4DeviceNum=%d\n", + prP2pInfo->u4DeviceNum); + return -EFAULT; + } + + mtk_uninit_sta_role(prAdapter, ndev); + + if (mtk_init_ap_role(prGlueInfo, ndev) != 0) { + DBGLOG(INIT, ERROR, "mtk_init_ap_role FAILED\n"); + /* Only AP/P2P resource has the failure case. */ + /* So, just re-init AIS. */ + mtk_init_sta_role(prAdapter, ndev); + return -EFAULT; + } + } else { + /* AP mode change to STA mode */ + if (mtk_uninit_ap_role(prGlueInfo, ndev) != 0) { + DBGLOG(INIT, ERROR, "mtk_uninit_ap_role FAILED\n"); + return -EFAULT; + } + + mtk_init_sta_role(prAdapter, ndev); + /* continue the mtk_cfg80211_change_iface() process */ + mtk_cfg80211_change_iface(wiphy, ndev, type, params); + } + + return 0; +} + +int mtk_cfg_add_key(struct wiphy *wiphy, struct net_device *ndev, + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + int link_id, +#endif + u8 key_index, + bool pairwise, const u8 *mac_addr, + struct key_params *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + return mtk_p2p_cfg80211_add_key(wiphy, ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + 0, +#endif + key_index, pairwise, + mac_addr, params); + } + /* STA Mode */ + return mtk_cfg80211_add_key(wiphy, ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + 0, +#endif + key_index, pairwise, mac_addr, + params); +} + + +int mtk_cfg_get_key(struct wiphy *wiphy, struct net_device *ndev, + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + int link_id, +#endif + u8 key_index, + bool pairwise, const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, struct key_params *)) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + return mtk_p2p_cfg80211_get_key(wiphy, ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + link_id, +#endif + key_index, pairwise, + mac_addr, cookie, callback); + } + /* STA Mode */ + return mtk_cfg80211_get_key(wiphy, ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + link_id, +#endif + key_index, pairwise, mac_addr, + cookie, callback); +} + + +int mtk_cfg_del_key(struct wiphy *wiphy, struct net_device *ndev, + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + int link_id, +#endif + u8 key_index, + bool pairwise, const u8 *mac_addr) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + return mtk_p2p_cfg80211_del_key(wiphy, ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + link_id, +#endif + key_index, pairwise, + mac_addr); + } + /* STA Mode */ + return mtk_cfg80211_del_key(wiphy, ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + link_id, +#endif + key_index, pairwise, mac_addr); +} + +int mtk_cfg_set_default_key(struct wiphy *wiphy, struct net_device *ndev, + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + int link_id, +#endif + u8 key_index, bool unicast, bool multicast) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + return mtk_p2p_cfg80211_set_default_key(wiphy, ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + link_id, +#endif + key_index, unicast, + multicast); + } + /* STA Mode */ + return mtk_cfg80211_set_default_key(wiphy, ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) + link_id, +#endif + key_index, unicast, + multicast); +} + +#if KERNEL_VERSION(6, 1, 0) <= CFG80211_VERSION_CODE +int mtk_cfg_set_default_mgmt_key(struct wiphy *wiphy, + struct net_device *ndev, int link_id, + u8 key_index) +#else +int mtk_cfg_set_default_mgmt_key(struct wiphy *wiphy, + struct net_device *ndev, u8 key_index) +#endif +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + return mtk_p2p_cfg80211_set_mgmt_key(wiphy, ndev, link_id, key_index); +#else + return mtk_p2p_cfg80211_set_mgmt_key(wiphy, ndev, key_index); +#endif + } + /* STA Mode */ + DBGLOG(REQ, WARN, "STA don't support this function\n"); + return -EFAULT; +} + + +int mtk_cfg_get_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_info *sinfo) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + return mtk_p2p_cfg80211_get_station(wiphy, ndev, mac, sinfo); + } + + /* STA Mode */ + return mtk_cfg80211_get_station(wiphy, ndev, mac, sinfo); +} + +#if CFG_SUPPORT_TDLS +int mtk_cfg_change_station(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *mac, struct station_parameters *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + DBGLOG(REQ, WARN, "P2P/AP don't support this function\n"); + return -EFAULT; + } + /* STA Mode */ + return mtk_cfg80211_change_station(wiphy, ndev, mac, + params); +} + +int mtk_cfg_add_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_parameters *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + DBGLOG(REQ, WARN, "P2P/AP don't support this function\n"); + return -EFAULT; + } + /* STA Mode */ + return mtk_cfg80211_add_station(wiphy, ndev, mac, params); +} + + +int mtk_cfg_tdls_oper(struct wiphy *wiphy, struct net_device *ndev, + const u8 *peer, enum nl80211_tdls_operation oper) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + DBGLOG(REQ, WARN, "P2P/AP don't support this function\n"); + return -EFAULT; + } + /* STA Mode */ + return mtk_cfg80211_tdls_oper(wiphy, ndev, peer, oper); +} + +int mtk_cfg_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, +#if (CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)) + int link_id, +#endif + u8 action_code, u8 dialog_token, + u16 status_code, u32 peer_capability, bool initiator, + const u8 *buf, size_t len + ) +{ + GLUE_INFO_T *prGlueInfo; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, dev) > 0) { + DBGLOG(REQ, WARN, "P2P/AP don't support this function\n"); + return -EFAULT; + } + + return mtk_cfg80211_tdls_mgmt(wiphy, dev, peer, +#if (CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)) + link_id, +#endif + action_code, dialog_token, + status_code, peer_capability, initiator, buf, + len); + +} +#endif /* CFG_SUPPORT_TDLS */ + + +int mtk_cfg_del_station(struct wiphy *wiphy, struct net_device *ndev, + struct station_del_parameters *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + return mtk_p2p_cfg80211_del_station(wiphy, ndev, params); + } + /* STA Mode */ +#if CFG_SUPPORT_TDLS + return mtk_cfg80211_del_station(wiphy, ndev, params); +#else /* CFG_SUPPORT_TDLS == 0 */ + /* AIS only support this function when CFG_SUPPORT_TDLS */ + return -EFAULT; +#endif /* CFG_SUPPORT_TDLS */ +} + +int mtk_cfg_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, request->wdev->netdev) > 0) { + return mtk_p2p_cfg80211_scan(wiphy, request); + } + + /* STA Mode */ + return mtk_cfg80211_scan(wiphy, request); +} + +void mtk_cfg_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) > 0) { + mtk_p2p_cfg80211_abort_scan(wiphy, wdev); + } + /* STA Mode */ + mtk_cfg80211_abort_scan(wiphy, wdev); +} + +int mtk_cfg_sched_scan_start(IN struct wiphy *wiphy, + IN struct net_device *ndev, + IN struct cfg80211_sched_scan_request *request) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + DBGLOG(REQ, WARN, "P2P/AP don't support this function\n"); + return -EFAULT; + } + + return mtk_cfg80211_sched_scan_start(wiphy, ndev, request); + +} + + +int mtk_cfg_sched_scan_stop(IN struct wiphy *wiphy, + IN struct net_device *ndev, + IN u64 reqid) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + DBGLOG(REQ, WARN, "P2P/AP don't support this function\n"); + return -EFAULT; + } + + return mtk_cfg80211_sched_scan_stop(wiphy, ndev, reqid); +} + +int mtk_cfg_connect(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_connect_params *sme) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + return mtk_p2p_cfg80211_connect(wiphy, ndev, sme); + } + /* STA Mode */ + return mtk_cfg80211_connect(wiphy, ndev, sme); +} + +int mtk_cfg_disconnect(struct wiphy *wiphy, struct net_device *ndev, + u16 reason_code) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + return mtk_p2p_cfg80211_disconnect(wiphy, ndev, reason_code); + } + /* STA Mode */ + return mtk_cfg80211_disconnect(wiphy, ndev, reason_code); +} + +int mtk_cfg_join_ibss(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_ibss_params *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + return mtk_p2p_cfg80211_join_ibss(wiphy, ndev, params); + } + /* STA Mode */ + return mtk_cfg80211_join_ibss(wiphy, ndev, params); +} + +int mtk_cfg_leave_ibss(struct wiphy *wiphy, + struct net_device *ndev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + return mtk_p2p_cfg80211_leave_ibss(wiphy, ndev); + } + /* STA Mode */ + return mtk_cfg80211_leave_ibss(wiphy, ndev); +} + +int mtk_cfg_set_power_mgmt(struct wiphy *wiphy, + struct net_device *ndev, + bool enabled, int timeout) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + return mtk_p2p_cfg80211_set_power_mgmt(wiphy, ndev, + enabled, timeout); + } + /* STA Mode */ + return mtk_cfg80211_set_power_mgmt(wiphy, ndev, enabled, + timeout); +} + +int mtk_cfg_set_pmksa(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_pmksa *pmksa) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + DBGLOG(REQ, WARN, "P2P/AP don't support this function\n"); + return -EFAULT; + } + + return mtk_cfg80211_set_pmksa(wiphy, ndev, pmksa); +} + +int mtk_cfg_del_pmksa(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_pmksa *pmksa) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + DBGLOG(REQ, WARN, "P2P/AP don't support this function\n"); + return -EFAULT; + } + + return mtk_cfg80211_del_pmksa(wiphy, ndev, pmksa); +} + +int mtk_cfg_flush_pmksa(struct wiphy *wiphy, + struct net_device *ndev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + DBGLOG(REQ, WARN, "P2P/AP don't support this function\n"); + return -EFAULT; + } + + return mtk_cfg80211_flush_pmksa(wiphy, ndev); +} + +#if CONFIG_SUPPORT_GTK_REKEY +int mtk_cfg_set_rekey_data(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_gtk_rekey_data *data) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, dev) > 0) { + DBGLOG(REQ, WARN, "P2P/AP don't support this function\n"); + return -EFAULT; + } + + return mtk_cfg80211_set_rekey_data(wiphy, dev, data); +} +#endif /* CONFIG_SUPPORT_GTK_REKEY */ + +int mtk_cfg_suspend(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return 0; + } + + /* TODO: AP/P2P do not support this function, should take that case. */ + return mtk_cfg80211_suspend(wiphy, wow); +} + +int mtk_cfg_resume(struct wiphy *wiphy) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return 0; + } + + /* TODO: AP/P2P do not support this function, should take that case. */ + return mtk_cfg80211_resume(wiphy); +} + +int mtk_cfg_auth(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_auth_request *req) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if ((!prGlueInfo) || (prGlueInfo->u4ReadyFlag == 0)) { + DBGLOG(REQ, WARN, "driver is not ready\n"); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + return mtk_p2p_cfg80211_auth(wiphy, ndev, req); + } + + /* STA Mode */ + return mtk_cfg80211_auth(wiphy, ndev, req); +} + +int mtk_cfg_assoc(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_assoc_request *req) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, ndev) > 0) { + return mtk_p2p_cfg80211_assoc(wiphy, ndev, req); + } + + /* STA Mode */ + return mtk_cfg80211_assoc(wiphy, ndev, req); +} + +int mtk_cfg_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) > 0) { + return mtk_p2p_cfg80211_remain_on_channel(wiphy, wdev, chan, + duration, cookie); + } + /* STA Mode */ + return mtk_cfg80211_remain_on_channel(wiphy, wdev, chan, + duration, cookie); +} + +int mtk_cfg_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, u64 cookie) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) > 0) { + return mtk_p2p_cfg80211_cancel_remain_on_channel(wiphy, + wdev, + cookie); + } + /* STA Mode */ + return mtk_cfg80211_cancel_remain_on_channel(wiphy, wdev, + cookie); +} + +int mtk_cfg_mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) > 0) { + return mtk_p2p_cfg80211_mgmt_tx(wiphy, wdev, params, + cookie); + } + /* STA Mode */ + return mtk_cfg80211_mgmt_tx(wiphy, wdev, params, cookie); + +} + +#if KERNEL_VERSION(5, 8, 0) > CFG80211_VERSION_CODE +void mtk_cfg_mgmt_frame_register(struct wiphy *wiphy, + struct wireless_dev *wdev, + u16 frame_type, bool reg) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) > 0) { + mtk_p2p_cfg80211_mgmt_frame_register(wiphy, wdev, + frame_type, + reg); + } else { + mtk_cfg80211_mgmt_frame_register(wiphy, wdev, frame_type, + reg); + } +} + +#else +void mtk_cfg_mgmt_frame_update(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct mgmt_frame_regs *upd) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u_int8_t fgIsP2pNetDevice = false; + u32 *pu4PacketFilter = NULL; + + if ((wiphy == NULL) || (wdev == NULL) || (upd == NULL)) { + DBGLOG(INIT, TRACE, "Invalidate params\n"); + return; + } + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + if ((!prGlueInfo) || (prGlueInfo->u4ReadyFlag == 0)) { + DBGLOG(REQ, WARN, "driver is not ready\n"); + return; + } + fgIsP2pNetDevice = mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev); + DBGLOG(INIT, TRACE, + "netdev(0x%p) update management frame filter: 0x%08x\n", + wdev->netdev, upd->interface_stypes); + + if (fgIsP2pNetDevice) { + u8 ucRoleIdx = 0; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = + (P_P2P_ROLE_FSM_INFO_T)NULL; + if (prGlueInfo->prP2PInfo[0]->prDevHandler == + wdev->netdev) { + pu4PacketFilter = + &prGlueInfo->prP2PDevInfo + ->u4OsMgmtFrameFilter; + /* Reset filters*/ + *pu4PacketFilter = 0; + } else { + if (mtk_Netdev_To_RoleIdx(prGlueInfo, + wdev->netdev, &ucRoleIdx) < 0) { + DBGLOG(P2P, WARN, + "wireless dev match fail!\n"); + return; + } + /* Non P2P device*/ + if (ucRoleIdx >= KAL_P2P_NUM) { + DBGLOG(P2P, WARN, + "Invalid RoleIdx %u\n", + ucRoleIdx); + return; + } + DBGLOG(P2P, TRACE, + "Open packet filer RoleIdx %u\n", + ucRoleIdx); + prP2pRoleFsmInfo = + prGlueInfo->prAdapter->rWifiVar + .aprP2pRoleFsmInfo[ucRoleIdx]; + pu4PacketFilter = &prP2pRoleFsmInfo + ->u4P2pPacketFilter; + *pu4PacketFilter = + PARAM_PACKET_FILTER_SUPPORTED; + } + } else { + pu4PacketFilter = &prGlueInfo->u4OsMgmtFrameFilter; + *pu4PacketFilter = 0; + } + // if (upd->interface_stypes & MASK_MAC_FRAME_PROBE_REQ) { + // *pu4PacketFilter |= PARAM_PACKET_FILTER_PROBE_REQ; + // } + // if (upd->interface_stypes & MASK_MAC_FRAME_ACTION) { + // *pu4PacketFilter |= PARAM_PACKET_FILTER_ACTION_FRAME; + // } + set_bit(fgIsP2pNetDevice ? + GLUE_FLAG_FRAME_FILTER_BIT : + GLUE_FLAG_FRAME_FILTER_AIS_BIT, + &prGlueInfo->ulFlag); + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + +} +#endif + +#if (CFG_ENABLE_WIFI_DIRECT_CFG_80211 != 0) +int mtk_cfg_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) { + // DBGLOG(REQ, WARN, "STA doesn't support this function\n"); + return -EFAULT; + } + + return mtk_p2p_cfg80211_change_bss(wiphy, dev, params); +} + +int mtk_cfg_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) <= 0) { + // DBGLOG(REQ, WARN, "STA doesn't support this function\n"); + return -EFAULT; + } + + return mtk_p2p_cfg80211_mgmt_tx_cancel_wait(wiphy, wdev, + cookie); +} + +int mtk_cfg_deauth(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_deauth_request *req) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + int ret = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, dev) > 0) { + ret = mtk_p2p_cfg80211_deauth(wiphy, dev, req); + }else{ + ret = mtk_cfg80211_deauth(wiphy, dev, req); + } + + return ret; +} + +int mtk_cfg_disassoc(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_disassoc_request *req) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) { + // DBGLOG(REQ, WARN, "STA doesn't support this function\n"); + return -EFAULT; + } + + return mtk_p2p_cfg80211_disassoc(wiphy, dev, req); +} + +int mtk_cfg_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *settings) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) { + // DBGLOG(REQ, WARN, "STA doesn't support this function\n"); + return -EFAULT; + } + + return mtk_p2p_cfg80211_start_ap(wiphy, dev, settings); +} + +int mtk_cfg_change_beacon(struct wiphy *wiphy, + struct net_device *dev, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0)) + struct cfg80211_beacon_data *info +#else + struct cfg80211_ap_update *info +#endif + ) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) { + // DBGLOG(REQ, WARN, "STA doesn't support this function\n"); + return -EFAULT; + } + + return mtk_p2p_cfg80211_change_beacon(wiphy, dev, info); +} + +#if KERNEL_VERSION(6, 0, 0) <= CFG80211_VERSION_CODE +int mtk_cfg_stop_ap(struct wiphy *wiphy, + struct net_device *dev, + unsigned int link_id) +#else +int mtk_cfg_stop_ap(struct wiphy *wiphy, + struct net_device *dev) +#endif +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) { + // DBGLOG(REQ, WARN, "STA doesn't support this function\n"); + return -EFAULT; + } +#if KERNEL_VERSION(6, 0, 0) <= CFG80211_VERSION_CODE + return mtk_p2p_cfg80211_stop_ap(wiphy, dev, link_id); +#else + return mtk_p2p_cfg80211_stop_ap(wiphy, dev); +#endif +} + +int mtk_cfg_set_wiphy_params(struct wiphy *wiphy, + u32 changed) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + /* TODO: AIS not support this function */ + return mtk_p2p_cfg80211_set_wiphy_params(wiphy, changed); +} + +int mtk_cfg_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *dev, +#if KERNEL_VERSION(6, 0, 0) <= CFG80211_VERSION_CODE + unsigned int link_id, +#endif + const u8 *peer, + const struct cfg80211_bitrate_mask *mask) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, dev) <= 0) { + // DBGLOG(REQ, WARN, "STA doesn't support this function\n"); + return -EFAULT; + } + +#if KERNEL_VERSION(6, 0, 0) <= CFG80211_VERSION_CODE + return mtk_p2p_cfg80211_set_bitrate_mask(wiphy, dev, link_id, + peer, mask); +#else + return mtk_p2p_cfg80211_set_bitrate_mask(wiphy, dev, peer, + mask); +#endif +} + +int mtk_cfg_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, int mbm) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) <= 0) { + // DBGLOG(REQ, WARN, "STA doesn't support this function\n"); + return -EFAULT; + } + + return mtk_p2p_cfg80211_set_txpower(wiphy, wdev, type, mbm); +} + +int mtk_cfg_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + unsigned int link_id, + int *dbm) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 state = 0; + + prGlueInfo = (P_GLUE_INFO_T )wiphy_priv(wiphy); + + if (!halIsHifStateReady(prGlueInfo->prAdapter, &state)) { + DBGLOG(REQ, WARN, "driver is not ready, state:%d\n", state); + return -EFAULT; + } + + if (mtk_IsP2PNetDevice(prGlueInfo, wdev->netdev) <= 0) { + DBGLOG_RATELIMIT(REQ, WARN, + "STA doesn't support this function\n"); + return -EFAULT; + } + + return mtk_p2p_cfg80211_get_txpower(wiphy, wdev, link_id, dbm); +} +#endif /* (CFG_ENABLE_WIFI_DIRECT_CFG_80211 != 0) */ +#endif /* CFG_ENABLE_UNIFY_WIPHY */ diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_hook_api.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_hook_api.c new file mode 100644 index 00000000000000..013aa629da14a2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_hook_api.c @@ -0,0 +1,3862 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ +/* + * Module Name: + * gl_ate_agent.c + */ +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#if CFG_SUPPORT_QA_TOOL +#include "gl_wext.h" +#include "gl_cfg80211.h" +#include "gl_ate_agent.h" +#include "gl_qa_agent.h" +#include "gl_hook_api.h" + +#include <uapi/linux/nl80211.h> + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +enum { + ATE_LOG_RXV = 1, + ATE_LOG_RDD, + ATE_LOG_RE_CAL, + ATE_LOG_TYPE_NUM, + ATE_LOG_RXINFO, + ATE_LOG_TXDUMP, + ATE_LOG_TEST, +}; + +enum { + ATE_LOG_OFF, + ATE_LOG_ON, + ATE_LOG_DUMP, + ATE_LOG_CTRL_NUM, +}; + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Enter Test Mode. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEStart(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetATE = %s\n", prInBuf); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetTestMode, /* pfnOidHandler */ + NULL, /* pvInfoBuf */ + 0, /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Enter ICAP Mode. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ICAPStart(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetATE = %s\n", prInBuf); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetTestIcapMode, /* pfnOidHandler */ + NULL, /* pvInfoBuf */ + 0, /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Abort Test Mode. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEStop(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetATE = %s\n", prInBuf); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAbortTestMode, /* pfnOidHandler */ + NULL, /* pvInfoBuf */ + 0, /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Start auto Tx test in packet format and the driver will + * enter auto Tx test mode. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEStartTX(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetATE = %s\n", prInBuf); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_COMMAND; + rRfATInfo.u4FuncData = RF_AT_COMMAND_STARTTX; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Stop TX/RX test action if the driver is in any test + * mode. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEStopTX(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetATE = %s\n", prInBuf); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_COMMAND; + rRfATInfo.u4FuncData = RF_AT_COMMAND_STOPTEST; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Start auto Rx test and the driver will enter auto Rx + * test mode. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEStartRX(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetATE = %s\n", prInBuf); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_COMMAND; + rRfATInfo.u4FuncData = RF_AT_COMMAND_STARTRX; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Stop TX/RX test action if the driver is in any test + * mode. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prInBuf + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEStopRX(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetATE = %s\n", prInBuf); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_COMMAND; + rRfATInfo.u4FuncData = RF_AT_COMMAND_STOPTEST; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Channel Frequency. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4SetFreq Center frequency in unit of KHz + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetChannel(struct net_device *prNetDev, u32 u4SXIdx, u32 u4SetFreq) +{ + u32 u4BufLen = 0; + u32 i4SetChan; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + i4SetChan = nicFreq2ChannelNum(u4SetFreq); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetChannel=%d, Freq=%d\n", + i4SetChan, u4SetFreq); + + if (u4SetFreq == 0) { + return -EINVAL; + } + + if (u4SXIdx == 0) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_CHNL_FREQ; + rRfATInfo.u4FuncData = u4SetFreq; + } else { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_CHNL_FREQ | BIT(16); + rRfATInfo.u4FuncData = u4SetFreq; + } + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Preamble. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4Mode depends on Rate. 0--> normal, 1--> CCK short preamble, 2: + * 11n MM, 3: 11n GF 4: 11ac VHT \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetPreamble(struct net_device *prNetDev, u32 u4Mode) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetPreamble=%d\n", u4Mode); + + if (u4Mode > 4) { + return -EINVAL; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_PREAMBLE; + rRfATInfo.u4FuncData = u4Mode; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Channel Bandwidth. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4BW Choose Channel Bandwidth 0: 20 / 1: 40 / 2: 80 / 3: 160 + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetSystemBW(struct net_device *prNetDev, u32 u4BW) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 u4BWMapping = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetSystemBW=%d\n", u4BW); + + if (u4BW > 6) { + return -EINVAL; + } + + /* BW Mapping in QA Tool + * 0: BW20 + * 1: BW40 + * 2: BW80 + * 3: BW10 + * 4: BW5 + * 5: BW160C + * 6: BW160NC + */ + /* BW Mapping in MT6632 FW + * 0: BW20 + * 1: BW40 + * 2: BW80 + * 3: BW160C + * 4: BW160NC + * 5: BW5 + * 6: BW10 + */ + if (u4BW == 0) { + u4BWMapping = 0; + }else if (u4BW == 1) { + u4BWMapping = 1; + }else if (u4BW == 2) { + u4BWMapping = 2; + }else if (u4BW == 3) { + u4BWMapping = 6; + }else if (u4BW == 4) { + u4BWMapping = 5; + }else if (u4BW == 5) { + u4BWMapping = 3; + }else if (u4BW == 6) { + u4BWMapping = 4; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_CBW; + rRfATInfo.u4FuncData = u4BWMapping; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set TX Length. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4TxLength Packet length (MPDU) + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetTxLength(struct net_device *prNetDev, u32 u4TxLength) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetTxLength=%d\n", + u4TxLength); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_PKTLEN; + rRfATInfo.u4FuncData = u4TxLength; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set TX Count. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4TxCount Total packet count to send. 0 : unlimited, until stopped + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetTxCount(struct net_device *prNetDev, u32 u4TxCount) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetTxCount=%d\n", u4TxCount); + + if (u4TxCount < 0) { + return -EINVAL; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_PKTCNT; + rRfATInfo.u4FuncData = u4TxCount; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set TX Inter-Packet Guard. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4TxIPG In unit of us. The min value is 19us and max value is + * 2314us. \ It will be round-up to (19+9n) us. + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetTxIPG(struct net_device *prNetDev, u32 u4TxIPG) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetTxIPG=%d\n", u4TxIPG); + + if (u4TxIPG > 2314 || u4TxIPG < 19) { + return -EINVAL; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_PKTINTERVAL; + rRfATInfo.u4FuncData = u4TxIPG; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set WF0 TX Power. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4TxPower0 Tx Gain of RF. The value is signed absolute power + * (2's complement representation) in unit of 0.5 dBm. + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetTxPower0(struct net_device *prNetDev, u32 u4TxPower0) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetTxPower0=0x%02x\n", + u4TxPower0); + + if (u4TxPower0 > 0x3F) { + u4TxPower0 += 128; + DBGLOG(RFTEST, INFO, + "MT6632 : QA_ATE_HOOK Negative Power =0x%02x\n", + u4TxPower0); + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_POWER; + rRfATInfo.u4FuncData = u4TxPower0; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Per Packet BW. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4BW 0: 20 / 1: 40 / 2: 80 / 3: 160 + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetPerPacketBW(struct net_device *prNetDev, u32 u4BW) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 u4BWMapping = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetPerPacketBW=%d\n", u4BW); + + if (u4BW > 6) { + return -EINVAL; + } + + /* BW Mapping in QA Tool + * 0: BW20 + * 1: BW40 + * 2: BW80 + * 3: BW10 + * 4: BW5 + * 5: BW160C + * 6: BW160NC + */ + /* BW Mapping in MT6632 FW + * 0: BW20 + * 1: BW40 + * 2: BW80 + * 3: BW160C + * 4: BW160NC + * 5: BW5 + * 6: BW10 + */ + if (u4BW == 0) { + u4BWMapping = 0; + }else if (u4BW == 1) { + u4BWMapping = 1; + }else if (u4BW == 2) { + u4BWMapping = 2; + }else if (u4BW == 3) { + u4BWMapping = 6; + }else if (u4BW == 4) { + u4BWMapping = 5; + }else if (u4BW == 5) { + u4BWMapping = 3; + }else if (u4BW == 6) { + u4BWMapping = 4; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_DBW; + rRfATInfo.u4FuncData = u4BWMapping; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Primary Channel Setting. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4PrimaryCh The range is from 0~7 + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEPrimarySetting(struct net_device *prNetDev, u32 u4PrimaryCh) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK PrimarySetting=%d\n", + u4PrimaryCh); + + if (u4PrimaryCh > 7) { + return -EINVAL; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_PRIMARY_CH; + rRfATInfo.u4FuncData = u4PrimaryCh; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set TX Guard Interval. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4SetTxGi 0: Normal GI, 1: Short GI + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetTxGi(struct net_device *prNetDev, u32 u4SetTxGi) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetTxGi=%d\n", u4SetTxGi); + + if (u4SetTxGi != 0 && u4SetTxGi != 1) { + return -EINVAL; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_GI; + rRfATInfo.u4FuncData = u4SetTxGi; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set TX Path. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4Tx_path 0: All Tx, 1: WF0, 2: WF1, 3: WF0+WF1 + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetTxPath(struct net_device *prNetDev, u32 u4Tx_path) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK u4Tx_path=%d\n", u4Tx_path); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_TX_PATH; + rRfATInfo.u4FuncData = u4Tx_path; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set TX Payload Fix/Random. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4Stbc 0: Disable , 1 : Enable + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetTxPayLoad(struct net_device *prNetDev, u32 u4Gen_payload_rule, + u8 ucPayload) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK rule=%d, len =0x%x\n", + u4Gen_payload_rule, ucPayload); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_PAYLOAD; + rRfATInfo.u4FuncData = ((u4Gen_payload_rule << 16) | ucPayload); + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set TX STBC. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4Stbc 0: Disable , 1 : Enable + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetTxSTBC(struct net_device *prNetDev, u32 u4Stbc) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK u4Stbc=%d\n", u4Stbc); + + if (u4Stbc > 1) { + return -EINVAL; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_STBC; + rRfATInfo.u4FuncData = u4Stbc; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set TX Nss. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4Nss 1/2 + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetTxVhtNss(struct net_device *prNetDev, u32 u4VhtNss) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK u4Nss=%d\n", u4VhtNss); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_NSS; + rRfATInfo.u4FuncData = u4VhtNss; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Rate. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4Rate Rate + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetRate(struct net_device *prNetDev, u32 u4Rate) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetRate=0x%08lx\n", u4Rate); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_RATE; + rRfATInfo.u4FuncData = u4Rate; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Encode Mode. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4Ldpc 0: BCC / 1: LDPC + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetEncodeMode(struct net_device *prNetDev, u32 u4Ldpc) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetEncodeMode=%d\n", u4Ldpc); + + if (u4Ldpc != 0 && u4Ldpc != 1) { + return -EINVAL; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_ENCODE_MODE; + rRfATInfo.u4FuncData = u4Ldpc; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set iBF Enable. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4iBF 0: disable / 1: enable + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetiBFEnable(struct net_device *prNetDev, u32 u4iBF) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetiBFEnable=%d\n", u4iBF); + + if (u4iBF != 0 && u4iBF != 1) { + return -EINVAL; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_IBF_ENABLE; + rRfATInfo.u4FuncData = u4iBF; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set eBF Enable. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4eBF 0: disable / 1: enable + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESeteBFEnable(struct net_device *prNetDev, u32 u4eBF) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SeteBFEnable=%d\n", u4eBF); + + if (u4eBF != 0 && u4eBF != 1) { + return -EINVAL; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_EBF_ENABLE; + rRfATInfo.u4FuncData = u4eBF; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set MAC Address. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4Type Address type + * \param[in] ucAddr Address ready to set + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetMACAddress(struct net_device *prNetDev, u32 u4Type, u8 *ucAddr) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, + ERROR, + "MT6632 : QA_ATE_HOOK SetMACAddress Type = %d, Addr = %02x:%02x:%02x:%02x:%02x:%02x\n", + u4Type, + ucAddr[0], + ucAddr[1], + ucAddr[2], + ucAddr[3], + ucAddr[4], + ucAddr[5]); + + rRfATInfo.u4FuncIndex = u4Type; + memcpy(&rRfATInfo.u4FuncData, ucAddr, 4); + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + rRfATInfo.u4FuncIndex = u4Type | BIT(18); + memset(&rRfATInfo.u4FuncData, 0, sizeof(rRfATInfo.u4FuncData)); + memcpy(&rRfATInfo.u4FuncData, ucAddr + 4, 2); + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for RX Vector Dump. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4Type + * \param[in] u4On_off + * \param[in] u4Size + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATELogOnOff(struct net_device *prNetDev, u32 u4Type, u32 u4On_off, + u32 u4Size) +{ + s32 i4Status = 0, i, i4TargetLength = 0, i4MaxDumpRXVCnt = 500; + u32 u4BufLen = 0, rxv; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATELogOnOff\n"); + + switch (u4Type) { + case ATE_LOG_RXV: + DBGLOG(RFTEST, INFO, + "MT6632 : QA_ATE_HOOK MT_ATELogOnOff : ATE_LOG_RXV\n\n"); + break; + + case ATE_LOG_RDD: + DBGLOG(RFTEST, INFO, + "MT6632 : QA_ATE_HOOK MT_ATELogOnOff : ATE_LOG_RDD\n\n"); + break; + + case ATE_LOG_RE_CAL: + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_ATE_HOOK MT_ATELogOnOff : ATE_LOG_RE_CAL\n\n"); + break; + + case ATE_LOG_RXINFO: + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_ATE_HOOK MT_ATELogOnOff : ATE_LOG_RXINFO\n\n"); + break; + + case ATE_LOG_TXDUMP: + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_ATE_HOOK MT_ATELogOnOff : ATE_LOG_TXDUMP\n\n"); + break; + + case ATE_LOG_TEST: + DBGLOG(RFTEST, INFO, + "MT6632 : QA_ATE_HOOK MT_ATELogOnOff : ATE_LOG_TEST\n\n"); + break; + + default: + DBGLOG(RFTEST, INFO, + "MT6632 : QA_ATE_HOOK log type %d not supported\n\n", + u4Type); + } + + if ((u4On_off == ATE_LOG_DUMP) && (u4Type == ATE_LOG_RXV)) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_RESULT_INFO; + rRfATInfo.u4FuncData = RF_AT_FUNCID_RXV_DUMP; + + i4Status = kalIoctl(prGlueInfo, wlanoidRftestQueryAutoTest, + &rRfATInfo, sizeof(rRfATInfo), true, true, + true, &u4BufLen); + + if (i4Status == 0) { + i4TargetLength = rRfATInfo.u4FuncData * 36; + DBGLOG(RFTEST, + ERROR, + "MT6632 : QA_ATE_HOOK Get RX Vector Total size = %d\n", + i4TargetLength); + + if (i4TargetLength >= (i4MaxDumpRXVCnt * 36)) { + i4TargetLength = (i4MaxDumpRXVCnt * 36); + } + } else { + DBGLOG(RFTEST, + ERROR, + "MT6632 : QA_ATE_HOOK Get RX Vector Total Size Error!!!!\n\n"); + } + + TOOL_PRINTLOG(RFTEST, ERROR, "[LOG DUMP START]\n"); + + for (i = 0; i < i4TargetLength; i += 4) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_RXV_DUMP; + rRfATInfo.u4FuncData = i; + + i4Status = kalIoctl(prGlueInfo, + wlanoidRftestQueryAutoTest, + &rRfATInfo, sizeof(rRfATInfo), true, + true, true, &u4BufLen); + + if (i4Status == 0) { + rxv = rRfATInfo.u4FuncData; + + if (i % 36 == 0) { + TOOL_PRINTLOG( + RFTEST, ERROR, + "\%[RXV DUMP START][%d]\n", + (i / 36) + 1); + } + + TOOL_PRINTLOG(RFTEST, ERROR, "[RXVD%d]%08x\n", + ((i % 36) / 4) + 1, rxv); + + if (((i % 36) / 4) + 1 == 9) { + TOOL_PRINTLOG(RFTEST, ERROR, + "[RXV DUMP END]\n"); + } + } + } + + TOOL_PRINTLOG(RFTEST, ERROR, "[LOG DUMP END]\n"); + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Reset Counter. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEResetTXRXCounter(struct net_device *prNetDev) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATEResetTXRXCounter\n"); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_RESETTXRXCOUNTER; + rRfATInfo.u4FuncData = 0; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set DBDC Band Index. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4BandIdx Band Index Number ready to set + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetDBDCBandIndex(struct net_device *prNetDev, u32 u4BandIdx) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATESetDBDCBandIndex\n"); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_DBDC_BAND_IDX; + rRfATInfo.u4FuncData = u4BandIdx; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Band. (2G or 5G) + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] i4Band Band to set + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetBand(struct net_device *prNetDev, s32 i4Band) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATESetBand\n"); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_BAND; + rRfATInfo.u4FuncData = i4Band; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Tx Tone Type. (2G or 5G) + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] i4ToneType Set Single or Two Tone. + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetTxToneType(struct net_device *prNetDev, s32 i4ToneType) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATESetTxToneType\n"); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_TONE_TYPE; + rRfATInfo.u4FuncData = i4ToneType; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Tx Tone Frequency. (DC/5M/10M/20M/40M) + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] i4ToneFreq Set Tx Tone Frequency. + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetTxToneBW(struct net_device *prNetDev, s32 i4ToneFreq) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATESetTxToneBW\n"); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_TONE_BW; + rRfATInfo.u4FuncData = i4ToneFreq; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Tx Tone DC Offset. (DC Offset I / DC Offset Q) + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] i4DcOffsetI Set Tx Tone DC Offset I. + * \param[in] i4DcOffsetQ Set Tx Tone DC Offset Q. + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetTxToneDCOffset(struct net_device *prNetDev, s32 i4DcOffsetI, + s32 i4DcOffsetQ) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATESetTxToneDCOffset\n"); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_TONE_DC_OFFSET; + rRfATInfo.u4FuncData = i4DcOffsetQ << 16 | i4DcOffsetI; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Tx Tone Power. (RF and Digital) + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] i4AntIndex + * \param[in] i4RF_Power + * \param[in] i4Digi_Power + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetDBDCTxTonePower(struct net_device *prNetDev, s32 i4AntIndex, + s32 i4RF_Power, s32 i4Digi_Power) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATESetDBDCTxTonePower\n"); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_TONE_RF_GAIN; + rRfATInfo.u4FuncData = i4AntIndex << 16 | i4RF_Power; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_TONE_DIGITAL_GAIN; + rRfATInfo.u4FuncData = i4AntIndex << 16 | i4Digi_Power; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Start Tx Tone. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] i4Control Start or Stop TX Tone. + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEDBDCTxTone(struct net_device *prNetDev, s32 i4Control) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATEDBDCTxTone\n"); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (i4Control) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_COMMAND; + rRfATInfo.u4FuncData = RF_AT_COMMAND_SINGLE_TONE; + } else { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_COMMAND; + rRfATInfo.u4FuncData = RF_AT_COMMAND_STOPTEST; + } + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set TX Mac Header. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u4BandIdx Band Index Number ready to set + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetMacHeader(struct net_device *prNetDev, u32 u4FrameCtrl, + u32 u4DurationID, u32 u4SeqCtrl) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATESetMacHeader\n"); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_MAC_HEADER; + rRfATInfo.u4FuncData = u4FrameCtrl || (u4DurationID << 16); + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_SEQ_CTRL; + rRfATInfo.u4FuncData = u4SeqCtrl; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for IRR Set ADC. (RF_AT_FUNCID_SET_ADC) + * + * \param[in] prNetDev Pointer to the Net Device + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATE_IRRSetADC(struct net_device *prNetDev, u32 u4WFIdx, u32 u4ChFreq, + u32 u4BW, u32 u4Sx, u32 u4Band, u32 u4RunType, + u32 u4FType) +{ + u32 u4BufLen = 0, i = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 au4Param[7]; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATE_IRRSetADC\n"); + + if (u4BW == 3 || u4BW == 4 || u4BW > 5) { + return -EINVAL; + } + + if (u4BW == 5) { /* For BW160, UI will pass "5" */ + u4BW = 3; + } + + au4Param[0] = u4ChFreq; + au4Param[1] = u4WFIdx; + au4Param[2] = u4BW; + au4Param[3] = u4Sx; + au4Param[4] = u4Band; + au4Param[5] = u4RunType; + au4Param[6] = u4FType; + + for (i = 0; i < 8; i++) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_ADC | (i << 16); + if (i < 7) { + rRfATInfo.u4FuncData = au4Param[i]; + }else{ + rRfATInfo.u4FuncData = 0; + } + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler + */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for IRR Set RX Gain. (RF_AT_FUNCID_SET_RX_GAIN) + * + * \param[in] prNetDev Pointer to the Net Device + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATE_IRRSetRxGain(struct net_device *prNetDev, u32 u4PgaLpfg, u32 u4Lna, + u32 u4Band, u32 u4WF_inx, u32 u4Rfdgc) +{ + u32 u4BufLen = 0, i = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 au4Param[5]; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATE_IRRSetRxGain\n"); + + au4Param[0] = u4PgaLpfg; + au4Param[1] = u4Lna; + au4Param[2] = u4Band; + au4Param[3] = u4WF_inx; + au4Param[4] = u4Rfdgc; + + for (i = 0; i < 6; i++) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_RX_GAIN | (i << 16); + if (i < 5) { + rRfATInfo.u4FuncData = au4Param[i]; + }else{ + rRfATInfo.u4FuncData = 0; + } + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler + */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for IRR Set TTG. (RF_AT_FUNCID_SET_TTG) + * + * \param[in] prNetDev Pointer to the Net Device + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATE_IRRSetTTG(struct net_device *prNetDev, u32 u4TTGPwrIdx, u32 u4ChFreq, + u32 u4FIToneFreq, u32 u4Band) +{ + u32 u4BufLen = 0, i = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 au4Param[4]; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATE_IRRSetTTG\n"); + + au4Param[0] = u4ChFreq; + au4Param[1] = u4FIToneFreq; + au4Param[2] = u4TTGPwrIdx; + au4Param[3] = u4Band; + + for (i = 0; i < 5; i++) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_TTG | (i << 16); + if (i < 4) { + rRfATInfo.u4FuncData = au4Param[i]; + }else{ + rRfATInfo.u4FuncData = 0; + } + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler + */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for IRR Set TTG On/Off. (RF_AT_FUNCID_TTG_ON_OFF) + * + * \param[in] prNetDev Pointer to the Net Device + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATE_IRRSetTrunOnTTG(struct net_device *prNetDev, u32 u4TTGOnOff, + u32 u4Band, u32 u4WF_inx) +{ + u32 u4BufLen = 0, i = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 au4Param[3]; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATE_IRRSetTrunOnTTG\n"); + + au4Param[0] = u4TTGOnOff; + au4Param[1] = u4Band; + au4Param[2] = u4WF_inx; + + for (i = 0; i < 4; i++) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_TTG_ON_OFF | (i << 16); + if (i < 3) { + rRfATInfo.u4FuncData = au4Param[i]; + }else{ + rRfATInfo.u4FuncData = 0; + } + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler + */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for IRR Set TTG On/Off. + * + * \param[in] prNetDev Pointer to the Net Device + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATE_TMRSetting(struct net_device *prNetDev, u32 u4Setting, u32 u4Version, + u32 u4MPThres, u32 u4MPIter) +{ + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATE_TMRSetting\n"); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_TMR_ROLE; + rRfATInfo.u4FuncData = u4Setting; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_TMR_MODULE; + rRfATInfo.u4FuncData = u4Version; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_TMR_DBM; + rRfATInfo.u4FuncData = u4MPThres; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_TMR_ITER; + rRfATInfo.u4FuncData = u4MPIter; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for MPS Setting. (Set Seq Data) + * + * \param[in] prNetDev Pointer to the Net Device + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEMPSSetSeqData(struct net_device *prNetDev, u32 u4TestNum, u32 *pu4Phy, + u32 u4Band) +{ + u32 u4BufLen = 0, i; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATEMPSSetSeqData\n"); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_MPS_SIZE; + rRfATInfo.u4FuncData = u4TestNum; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + for (i = 0; i < u4TestNum; i++) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_MPS_SEQ_DATA | + (i << 16); + rRfATInfo.u4FuncData = pu4Phy[i]; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler + */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for MPS Setting. (Set Payload Length) + * + * \param[in] prNetDev Pointer to the Net Device + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEMPSSetPayloadLength(struct net_device *prNetDev, u32 u4TestNum, + u32 *pu4Length, u32 u4Band) +{ + u32 u4BufLen = 0, i; + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_ATE_HOOK MT_ATEMPSSetPayloadLength\n"); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + for (i = 0; i < u4TestNum; i++) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_MPS_PAYLOAD_LEN | + (i << 16); + rRfATInfo.u4FuncData = pu4Length[i]; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler + */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for MPS Setting. (Set Packet Count) + * + * \param[in] prNetDev Pointer to the Net Device + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEMPSSetPacketCount(struct net_device *prNetDev, u32 u4TestNum, + u32 *pu4PktCnt, u32 u4Band) +{ + u32 u4BufLen = 0, i; + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATEMPSSetPacketCount\n"); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + for (i = 0; i < u4TestNum; i++) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_MPS_PKT_CNT | + (i << 16); + rRfATInfo.u4FuncData = pu4PktCnt[i]; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler + */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for MPS Setting. (Set Power Gain) + * + * \param[in] prNetDev Pointer to the Net Device + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEMPSSetPowerGain(struct net_device *prNetDev, u32 u4TestNum, + u32 *pu4PwrGain, u32 u4Band) +{ + u32 u4BufLen = 0, i; + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATEMPSSetPowerGain\n"); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + for (i = 0; i < u4TestNum; i++) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_MPS_PWR_GAIN | + (i << 16); + rRfATInfo.u4FuncData = pu4PwrGain[i]; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler + */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for MPS Setting. (Set NSS) + * + * \param[in] prNetDev Pointer to the Net Device + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEMPSSetNss(struct net_device *prNetDev, u32 u4TestNum, u32 *pu4Nss, + u32 u4Band) +{ + u32 u4BufLen = 0, i; + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATEMPSSetNss\n"); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + for (i = 0; i < u4TestNum; i++) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_MPS_NSS | (i << 16); + rRfATInfo.u4FuncData = pu4Nss[i]; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler + */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for MPS Setting. (Set NSS) + * + * \param[in] prNetDev Pointer to the Net Device + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEMPSSetPerpacketBW(struct net_device *prNetDev, u32 u4TestNum, + u32 *pu4PerPktBW, u32 u4Band) +{ + u32 u4BufLen = 0, i; + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK MT_ATEMPSSetPerpacketBW\n"); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + for (i = 0; i < u4TestNum; i++) { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_MPS_PACKAGE_BW | + (i << 16); + rRfATInfo.u4FuncData = pu4PerPktBW[i]; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler + */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Start RDD. + * + * \param[in] prNetDev Pointer to the Net Device + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATERDDStart(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4BufLen = 0; + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetATE = %s\n", prInBuf); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_COMMAND; + rRfATInfo.u4FuncData = RF_AT_COMMAND_RDD; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Stop RDD. + * + * \param[in] prNetDev Pointer to the Net Device + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATERDDStop(struct net_device *prNetDev, u8 *prInBuf) +{ + u32 u4BufLen = 0; + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_ATE_HOOK SetATE = %s\n", prInBuf); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_COMMAND; + rRfATInfo.u4FuncData = RF_AT_COMMAND_RDD_OFF; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Write Efuse. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u2Offset Efuse offset + * \param[in] u2Content Efuse content + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATEWriteEfuse(struct net_device *prNetDev, u16 u2Offset, u16 u2Content) +{ + u32 u4BufLen = 0; + PARAM_CUSTOM_ACCESS_EFUSE_T rAccessEfuseInfoRead, rAccessEfuseInfoWrite; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS i4Status = WLAN_STATUS_SUCCESS; + u8 u4Index = 0, u4Loop = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + kalMemSet(&rAccessEfuseInfoRead, 0, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)); + kalMemSet(&rAccessEfuseInfoWrite, 0, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)); + + /* Read */ + DBGLOG(INIT, INFO, "MT6632 : QA_AGENT HQA_WriteBulkEEPROM Read\n"); + kalMemSet(&rAccessEfuseInfoRead, 0, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)); + rAccessEfuseInfoRead.u4Address = + (u2Offset / EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE; + i4Status = kalIoctl(prGlueInfo, wlanoidQueryProcessAccessEfuseRead, + &rAccessEfuseInfoRead, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), true, true, + true, &u4BufLen); + + /* Write */ + kalMemSet(&rAccessEfuseInfoWrite, 0, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)); + u4Index = u2Offset % EFUSE_BLOCK_SIZE; + + if (u4Index > EFUSE_BLOCK_SIZE - 2) { + return -EINVAL; + } + + prGlueInfo->prAdapter->aucEepromVaule[u4Index] = u2Content; + prGlueInfo->prAdapter->aucEepromVaule[u4Index + 1] = u2Content >> 8 & + 0xff; + + kalMemCopy(rAccessEfuseInfoWrite.aucData, + prGlueInfo->prAdapter->aucEepromVaule, 16); + + for (u4Loop = 0; u4Loop < (EFUSE_BLOCK_SIZE); u4Loop++) { + DBGLOG(INIT, + INFO, + "MT6632 : QA_AGENT aucEepromVaule u4Loop=%d u4Value=%x\n", + u4Loop, + prGlueInfo->prAdapter->aucEepromVaule[u4Loop]); + + DBGLOG(INIT, + INFO, + "MT6632 : QA_AGENT rAccessEfuseInfoWrite.aucData u4Loop=%d u4Value=%x\n", + u4Loop, + rAccessEfuseInfoWrite.aucData[u4Loop]); + } + + rAccessEfuseInfoWrite.u4Address = + (u2Offset / EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE; + + i4Status = kalIoctl(prGlueInfo, wlanoidQueryProcessAccessEfuseWrite, + &rAccessEfuseInfoWrite, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), false, true, + true, &u4BufLen); + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Tx Target Power. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] u2TxTargetPower TxTarget Power + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetTxTargetPower(struct net_device *prNetDev, u8 ucTxTargetPower) +{ + u32 u4BufLen = 0; + PARAM_CUSTOM_SET_TX_TARGET_POWER_T rSetTxTargetPwr; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS i4Status = WLAN_STATUS_SUCCESS; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + kalMemSet(&rSetTxTargetPwr, 0, + sizeof(PARAM_CUSTOM_SET_TX_TARGET_POWER_T)); + + /* Set Target Power Base */ + DBGLOG(INIT, INFO, "MT6632 : QA_AGENT Set Tx Target Power= %x dbm\n", + ucTxTargetPower); + rSetTxTargetPwr.ucTxTargetPwr = ucTxTargetPower; + + i4Status = kalIoctl(prGlueInfo, wlanoidQuerySetTxTargetPower, + &rSetTxTargetPwr, + sizeof(PARAM_CUSTOM_SET_TX_TARGET_POWER_T), false, + false, true, &u4BufLen); + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +#if (CFG_SUPPORT_DFS_MASTER == 1) +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Rdd Report. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] ucDbdcIdx Dbdc Index + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetRddReport(struct net_device *prNetDev, u8 ucDbdcIdx) +{ + u32 u4BufLen = 0; + PARAM_CUSTOM_SET_RDD_REPORT_T rSetRddReport; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS i4Status = WLAN_STATUS_SUCCESS; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + kalMemSet(&rSetRddReport, 0, sizeof(PARAM_CUSTOM_SET_RDD_REPORT_T)); + + /* Set Rdd Report */ + DBGLOG(INIT, INFO, "MT6632 : QA_AGENT Set RDD Report - Band: %d\n", + ucDbdcIdx); + rSetRddReport.ucDbdcIdx = ucDbdcIdx; + + i4Status = kalIoctl(prGlueInfo, wlanoidQuerySetRddReport, + &rSetRddReport, + sizeof(PARAM_CUSTOM_SET_RDD_REPORT_T), false, false, + true, &u4BufLen); + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Hook API for Set Radar Detect Mode. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] ucRadarDetectMode Radar Detect Mode + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If kalIoctl return nonzero. + * \retval -EINVAL If invalid argument. + */ +/*----------------------------------------------------------------------------*/ +s32 MT_ATESetRadarDetectMode(struct net_device *prNetDev, u8 ucRadarDetectMode) +{ + u32 u4BufLen = 0; + struct PARAM_CUSTOM_SET_RADAR_DETECT_MODE rSetRadarDetectMode; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS i4Status = WLAN_STATUS_SUCCESS; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + kalMemSet(&rSetRadarDetectMode, 0, + sizeof(struct PARAM_CUSTOM_SET_RADAR_DETECT_MODE)); + + /* Set Rdd Report */ + DBGLOG(INIT, INFO, "MT6632 : QA_AGENT Set Radar Detect Mode: %d\n", + ucRadarDetectMode); + rSetRadarDetectMode.ucRadarDetectMode = ucRadarDetectMode; + + i4Status = kalIoctl(prGlueInfo, wlanoidQuerySetRadarDetectMode, + &rSetRadarDetectMode, + sizeof(struct PARAM_CUSTOM_SET_RADAR_DETECT_MODE), + false, false, true, &u4BufLen); + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return i4Status; +} + +#endif + +#if CFG_SUPPORT_TX_BF +s32 TxBfProfileTag_InValid(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, u8 ucInValid) +{ + s32 i4Status = 0; + + prPfmuTag1->rField.ucInvalidProf = ucInValid; + + return i4Status; +} + +s32 TxBfProfileTag_PfmuIdx(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, u8 ucProfileIdx) +{ + s32 i4Status = 0; + + prPfmuTag1->rField.ucProfileID = ucProfileIdx; + + return i4Status; +} + +s32 TxBfProfileTag_TxBfType(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, u8 ucBFType) +{ + s32 i4Status = 0; + + prPfmuTag1->rField.ucTxBf = ucBFType; + + return i4Status; +} + +s32 TxBfProfileTag_DBW(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, u8 ucBW) +{ + s32 i4Status = 0; + + prPfmuTag1->rField.ucDBW = ucBW; + + return i4Status; +} + +s32 TxBfProfileTag_SuMu(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, u8 ucSuMu) +{ + s32 i4Status = 0; + + prPfmuTag1->rField.ucSU_MU = ucSuMu; + + return i4Status; +} + +s32 TxBfProfileTag_Mem(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, u8 *aucMemAddrColIdx, + u8 *aucMemAddrRowIdx) +{ + s32 i4Status = 0; + + prPfmuTag1->rField.ucMemAddr1ColIdx = aucMemAddrColIdx[0]; + prPfmuTag1->rField.ucMemAddr1RowIdx = aucMemAddrRowIdx[0]; + prPfmuTag1->rField.ucMemAddr2ColIdx = aucMemAddrColIdx[1]; + prPfmuTag1->rField.ucMemAddr2RowIdx = aucMemAddrRowIdx[1] & 0x1F; + prPfmuTag1->rField.ucMemAddr2RowIdxMsb = aucMemAddrRowIdx[1] >> 5; + prPfmuTag1->rField.ucMemAddr3ColIdx = aucMemAddrColIdx[2]; + prPfmuTag1->rField.ucMemAddr3RowIdx = aucMemAddrRowIdx[2]; + prPfmuTag1->rField.ucMemAddr4ColIdx = aucMemAddrColIdx[3]; + prPfmuTag1->rField.ucMemAddr4RowIdx = aucMemAddrRowIdx[3]; + + return i4Status; +} + +s32 TxBfProfileTag_Matrix(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, u8 ucNrow, u8 ucNcol, + u8 ucNgroup, u8 ucLM, u8 ucCodeBook, u8 ucHtcExist) +{ + s32 i4Status = 0; + + prPfmuTag1->rField.ucNrow = ucNrow; + prPfmuTag1->rField.ucNcol = ucNcol; + prPfmuTag1->rField.ucNgroup = ucNgroup; + prPfmuTag1->rField.ucLM = ucLM; + prPfmuTag1->rField.ucCodeBook = ucCodeBook; + prPfmuTag1->rField.ucHtcExist = ucHtcExist; + + return i4Status; +} + +s32 TxBfProfileTag_SNR(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, u8 ucSNR_STS0, + u8 ucSNR_STS1, u8 ucSNR_STS2, u8 ucSNR_STS3) +{ + s32 i4Status = 0; + + prPfmuTag1->rField.ucSNR_STS0 = ucSNR_STS0; + prPfmuTag1->rField.ucSNR_STS1 = ucSNR_STS1; + prPfmuTag1->rField.ucSNR_STS2 = ucSNR_STS2; + prPfmuTag1->rField.ucSNR_STS3 = ucSNR_STS3; + + return i4Status; +} + +s32 TxBfProfileTag_SmtAnt(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, u8 ucSmartAnt) +{ + s32 i4Status = 0; + + prPfmuTag2->rField.u2SmartAnt = ucSmartAnt; + + return i4Status; +} + +s32 TxBfProfileTag_SeIdx(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, u8 ucSeIdx) +{ + s32 i4Status = 0; + + prPfmuTag2->rField.ucSEIdx = ucSeIdx; + + return i4Status; +} + +s32 TxBfProfileTag_RmsdThd(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, u8 ucRmsdThrd) +{ + s32 i4Status = 0; + + prPfmuTag2->rField.ucRMSDThd = ucRmsdThrd; + + return i4Status; +} + +s32 TxBfProfileTag_McsThd(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, u8 *pMCSThLSS, + u8 *pMCSThSSS) +{ + s32 i4Status = 0; + + prPfmuTag2->rField.ucMCSThL1SS = pMCSThLSS[0]; + prPfmuTag2->rField.ucMCSThS1SS = pMCSThSSS[0]; + prPfmuTag2->rField.ucMCSThL2SS = pMCSThLSS[1]; + prPfmuTag2->rField.ucMCSThS2SS = pMCSThSSS[1]; + prPfmuTag2->rField.ucMCSThL3SS = pMCSThLSS[2]; + prPfmuTag2->rField.ucMCSThS3SS = pMCSThSSS[2]; + + return i4Status; +} + +s32 TxBfProfileTag_TimeOut(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, u8 ucTimeOut) +{ + s32 i4Status = 0; + + prPfmuTag2->rField.uciBfTimeOut = ucTimeOut; + + return i4Status; +} + +s32 TxBfProfileTag_DesiredBW(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, u8 ucDesiredBW) +{ + s32 i4Status = 0; + + prPfmuTag2->rField.uciBfDBW = ucDesiredBW; + + return i4Status; +} + +s32 TxBfProfileTag_DesiredNc(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, u8 ucDesiredNc) +{ + s32 i4Status = 0; + + prPfmuTag2->rField.uciBfNcol = ucDesiredNc; + + return i4Status; +} + +s32 TxBfProfileTag_DesiredNr(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, u8 ucDesiredNr) +{ + s32 i4Status = 0; + + prPfmuTag2->rField.uciBfNrow = ucDesiredNr; + + return i4Status; +} + +s32 TxBfProfileTagWrite(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, + P_PFMU_PROFILE_TAG2 prPfmuTag2, u8 profileIdx) +{ + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + PARAM_CUSTOM_TXBF_ACTION_STRUCT_T rTxBfActionInfo; + + kalMemZero(&rTxBfActionInfo, sizeof(rTxBfActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(RFTEST, ERROR, "MT6632 prPfmuTag1 : au4RawData[0] = 0x%08x\n", + prPfmuTag1->au4RawData[0]); + DBGLOG(RFTEST, ERROR, "MT6632 prPfmuTag1 : au4RawData[1] = 0x%08x\n", + prPfmuTag1->au4RawData[1]); + DBGLOG(RFTEST, ERROR, "MT6632 prPfmuTag1 : au4RawData[2] = 0x%08x\n", + prPfmuTag1->au4RawData[2]); + DBGLOG(RFTEST, ERROR, "MT6632 prPfmuTag1 : au4RawData[3] = 0x%08x\n", + prPfmuTag1->au4RawData[3]); + + DBGLOG(RFTEST, ERROR, "MT6632 prPfmuTag2 : au4RawData[0] = 0x%08x\n", + prPfmuTag2->au4RawData[0]); + DBGLOG(RFTEST, ERROR, "MT6632 prPfmuTag2 : au4RawData[1] = 0x%08x\n", + prPfmuTag2->au4RawData[1]); + DBGLOG(RFTEST, ERROR, "MT6632 prPfmuTag2 : au4RawData[2] = 0x%08x\n", + prPfmuTag2->au4RawData[2]); + + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucProfileID= %d\n", + prPfmuTag1->rField.ucProfileID); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucTxBf= %d\n", + prPfmuTag1->rField.ucTxBf); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucDBW= %d\n", + prPfmuTag1->rField.ucDBW); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucSU_MU= %d\n", + prPfmuTag1->rField.ucSU_MU); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucInvalidProf= %d\n", + prPfmuTag1->rField.ucInvalidProf); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucRMSD= %d\n", + prPfmuTag1->rField.ucRMSD); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucMemAddr1ColIdx= %d\n", + prPfmuTag1->rField.ucMemAddr1ColIdx); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucMemAddr1RowIdx= %d\n", + prPfmuTag1->rField.ucMemAddr1RowIdx); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucMemAddr2ColIdx= %d\n", + prPfmuTag1->rField.ucMemAddr2ColIdx); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucMemAddr2RowIdx= %d\n", + prPfmuTag1->rField.ucMemAddr2RowIdx); + DBGLOG(RFTEST, + ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucMemAddr2RowIdxMsb= %d\n", + prPfmuTag1->rField.ucMemAddr2RowIdxMsb); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucMemAddr3ColIdx= %d\n", + prPfmuTag1->rField.ucMemAddr3ColIdx); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucMemAddr3RowIdx= %d\n", + prPfmuTag1->rField.ucMemAddr3RowIdx); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucMemAddr4ColIdx= %d\n", + prPfmuTag1->rField.ucMemAddr4ColIdx); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucMemAddr4RowIdx= %d\n", + prPfmuTag1->rField.ucMemAddr4RowIdx); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucReserved= %d\n", + prPfmuTag1->rField.ucReserved); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucNrow= %d\n", + prPfmuTag1->rField.ucNrow); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucNcol= %d\n", + prPfmuTag1->rField.ucNcol); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucNgroup= %d\n", + prPfmuTag1->rField.ucNgroup); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucLM= %d\n", + prPfmuTag1->rField.ucLM); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucCodeBook= %d\n", + prPfmuTag1->rField.ucCodeBook); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucHtcExist= %d\n", + prPfmuTag1->rField.ucHtcExist); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucReserved1= %d\n", + prPfmuTag1->rField.ucReserved1); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucSNR_STS0= %d\n", + prPfmuTag1->rField.ucSNR_STS0); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucSNR_STS1= %d\n", + prPfmuTag1->rField.ucSNR_STS1); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucSNR_STS2= %d\n", + prPfmuTag1->rField.ucSNR_STS2); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucSNR_STS3= %d\n", + prPfmuTag1->rField.ucSNR_STS3); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag1 : prPfmuTag1->rField.ucIBfLnaIdx= %d\n", + prPfmuTag1->rField.ucIBfLnaIdx); + + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.u2SmartAnt = %d\n", + prPfmuTag2->rField.u2SmartAnt); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.ucReserved0 = %d\n", + prPfmuTag2->rField.ucReserved0); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.ucSEIdx = %d\n", + prPfmuTag2->rField.ucSEIdx); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.ucRMSDThd = %d\n", + prPfmuTag2->rField.ucRMSDThd); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.ucReserved1 = %d\n", + prPfmuTag2->rField.ucReserved1); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.ucMCSThL1SS = %d\n", + prPfmuTag2->rField.ucMCSThL1SS); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.ucMCSThS1SS = %d\n", + prPfmuTag2->rField.ucMCSThS1SS); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.ucMCSThL2SS = %d\n", + prPfmuTag2->rField.ucMCSThL2SS); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.ucMCSThS2SS = %d\n", + prPfmuTag2->rField.ucMCSThS2SS); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.ucMCSThL3SS = %d\n", + prPfmuTag2->rField.ucMCSThL3SS); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.ucMCSThS3SS = %d\n", + prPfmuTag2->rField.ucMCSThS3SS); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.uciBfTimeOut = %d\n", + prPfmuTag2->rField.uciBfTimeOut); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.ucReserved2 = %d\n", + prPfmuTag2->rField.ucReserved2); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.ucReserved3 = %d\n", + prPfmuTag2->rField.ucReserved3); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.ucReserved4 = %d\n", + prPfmuTag2->rField.ucReserved4); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.uciBfDBW = %d\n", + prPfmuTag2->rField.uciBfDBW); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.uciBfNcol = %d\n", + prPfmuTag2->rField.uciBfNcol); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.uciBfNrow = %d\n", + prPfmuTag2->rField.uciBfNrow); + DBGLOG(RFTEST, ERROR, + "MT6632 prPfmuTag2 : prPfmuTag2->rField.u2Reserved5 = %d\n", + prPfmuTag2->rField.u2Reserved5); + + rTxBfActionInfo.rProfileTagWrite.ucTxBfCategory = BF_PFMU_TAG_WRITE; + rTxBfActionInfo.rProfileTagWrite.ucPfmuId = profileIdx; + memcpy(&rTxBfActionInfo.rProfileTagWrite.ucBuffer, prPfmuTag1, + sizeof(PFMU_PROFILE_TAG1)); + memcpy(&rTxBfActionInfo.rProfileTagWrite.ucBuffer[16], prPfmuTag2, + sizeof(PFMU_PROFILE_TAG2)); + + i4Status = kalIoctl(prGlueInfo, wlanoidTxBfAction, &rTxBfActionInfo, + sizeof(rTxBfActionInfo), false, false, true, + &u4BufLen); + + return i4Status; +} + +s32 TxBfProfileTagRead(struct net_device *prNetDev, u8 profileIdx, u8 fgBFer) +{ + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + PARAM_CUSTOM_TXBF_ACTION_STRUCT_T rTxBfActionInfo; + + kalMemZero(&rTxBfActionInfo, sizeof(rTxBfActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileTagRead : profileIdx = 0x%08x\n", profileIdx); + DBGLOG(RFTEST, ERROR, "MT6632 TxBfProfileTagRead : fgBFer = 0x%08x\n", + fgBFer); + + rTxBfActionInfo.rProfileTagRead.ucTxBfCategory = BF_PFMU_TAG_READ; + rTxBfActionInfo.rProfileTagRead.ucProfileIdx = profileIdx; + rTxBfActionInfo.rProfileTagRead.fgBfer = fgBFer; + + i4Status = kalIoctl(prGlueInfo, wlanoidTxBfAction, &rTxBfActionInfo, + sizeof(rTxBfActionInfo), true, true, true, + &u4BufLen); + + return i4Status; +} + +s32 StaRecCmmUpdate(struct net_device *prNetDev, u8 ucWlanId, u8 ucBssId, + u8 u4Aid, u8 aucMacAddr[MAC_ADDR_LEN]) +{ + CMD_STAREC_COMMON_T rStaRecCmm; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + s32 i4Status = 0; + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + kalMemZero(&rStaRecCmm, sizeof(CMD_STAREC_COMMON_T)); + /* Tag assignment */ + rStaRecCmm.u2Tag = STA_REC_BASIC; + rStaRecCmm.u2Length = sizeof(CMD_STAREC_COMMON_T); + + /* content */ + kalMemCopy(rStaRecCmm.aucPeerMacAddr, aucMacAddr, MAC_ADDR_LEN); + rStaRecCmm.ucConnectionState = true; + rStaRecCmm.u2AID = u4Aid; + rStaRecCmm.u2Reserve1 = ucWlanId; + + DBGLOG(RFTEST, ERROR, "ucWlanId = 0x%08x\n", ucWlanId); + + i4Status = kalIoctl(prGlueInfo, wlanoidStaRecUpdate, &rStaRecCmm, + sizeof(CMD_STAREC_COMMON_T), false, false, true, + &u4BufLen); + + return i4Status; +} + +s32 StaRecBfUpdate(struct net_device *prNetDev, + STA_REC_BF_UPD_ARGUMENT rStaRecBfUpdArg, u8 aucMemRow[4], + u8 aucMemCol[4]) +{ + CMD_STAREC_BF rStaRecBF; + /* PARAM_CUSTOM_STA_REC_UPD_STRUCT_T rStaRecUpdateInfo = {0}; */ + /* P_STA_RECORD_T prStaRec; */ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + s32 i4Status = 0; + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + kalMemZero(&rStaRecBF, sizeof(CMD_STAREC_BF)); + /* Tag assignment */ + rStaRecBF.u2Tag = STA_REC_BF; + rStaRecBF.u2Length = sizeof(CMD_STAREC_BF); + rStaRecBF.ucReserved[0] = rStaRecBfUpdArg.u4BssId; + rStaRecBF.ucReserved[1] = rStaRecBfUpdArg.u4WlanId; + /* content */ + rStaRecBF.rTxBfPfmuInfo.u2PfmuId = rStaRecBfUpdArg.u4PfmuId; + rStaRecBF.rTxBfPfmuInfo.ucTotMemRequire = rStaRecBfUpdArg.u4TotalMemReq; + rStaRecBF.rTxBfPfmuInfo.ucMemRequire20M = rStaRecBfUpdArg.u4MemReq20M; + rStaRecBF.rTxBfPfmuInfo.ucMemRow0 = aucMemRow[0]; + rStaRecBF.rTxBfPfmuInfo.ucMemCol0 = aucMemCol[0]; + rStaRecBF.rTxBfPfmuInfo.ucMemRow1 = aucMemRow[1]; + rStaRecBF.rTxBfPfmuInfo.ucMemCol1 = aucMemCol[1]; + rStaRecBF.rTxBfPfmuInfo.ucMemRow2 = aucMemRow[2]; + rStaRecBF.rTxBfPfmuInfo.ucMemCol2 = aucMemCol[2]; + rStaRecBF.rTxBfPfmuInfo.ucMemRow3 = aucMemRow[3]; + rStaRecBF.rTxBfPfmuInfo.ucMemCol3 = aucMemCol[3]; + /* 0 : SU, 1 : MU */ + rStaRecBF.rTxBfPfmuInfo.fgSU_MU = rStaRecBfUpdArg.u4SuMu; + /* 0: iBF, 1: eBF */ + rStaRecBF.rTxBfPfmuInfo.fgETxBfCap = rStaRecBfUpdArg.u4eTxBfCap; + /* 0: legacy, 1: OFDM, 2: HT, 4: VHT */ + rStaRecBF.rTxBfPfmuInfo.ucSoundingPhy = 1; + rStaRecBF.rTxBfPfmuInfo.ucNdpaRate = rStaRecBfUpdArg.u4NdpaRate; + rStaRecBF.rTxBfPfmuInfo.ucNdpRate = rStaRecBfUpdArg.u4NdpRate; + rStaRecBF.rTxBfPfmuInfo.ucReptPollRate = rStaRecBfUpdArg.u4ReptPollRate; + /* 0: legacy, 1: OFDM, 2: HT, 4: VHT */ + rStaRecBF.rTxBfPfmuInfo.ucTxMode = rStaRecBfUpdArg.u4TxMode; + rStaRecBF.rTxBfPfmuInfo.ucNc = rStaRecBfUpdArg.u4Nc; + rStaRecBF.rTxBfPfmuInfo.ucNr = rStaRecBfUpdArg.u4Nr; + /* 0 : 20M, 1 : 40M, 2 : 80M, 3 : 80 + 80M */ + rStaRecBF.rTxBfPfmuInfo.ucCBW = rStaRecBfUpdArg.u4Bw; + rStaRecBF.rTxBfPfmuInfo.ucSEIdx = rStaRecBfUpdArg.u4SpeIdx; + /* Default setting */ + rStaRecBF.rTxBfPfmuInfo.u2SmartAnt = 0; + rStaRecBF.rTxBfPfmuInfo.uciBfTimeOut = 0; + rStaRecBF.rTxBfPfmuInfo.uciBfDBW = 0; + rStaRecBF.rTxBfPfmuInfo.uciBfNcol = 0; + rStaRecBF.rTxBfPfmuInfo.uciBfNrow = 0; + + i4Status = kalIoctl(prGlueInfo, wlanoidStaRecBFUpdate, &rStaRecBF, + sizeof(CMD_STAREC_BF), false, false, true, + &u4BufLen); + + return i4Status; +} + +s32 DevInfoUpdate(struct net_device *prNetDev, u8 ucOwnMacIdx, u8 fgBand, + u8 aucMacAddr[MAC_ADDR_LEN]) +{ + CMD_DEVINFO_ACTIVE_T rDevInfo; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + s32 i4Status = 0; + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + kalMemZero(&rDevInfo, sizeof(CMD_DEVINFO_ACTIVE_T)); + /* Tag assignment */ + rDevInfo.u2Tag = DEV_INFO_ACTIVE; + rDevInfo.u2Length = sizeof(CMD_DEVINFO_ACTIVE_T); + /* content */ + kalMemCopy(rDevInfo.aucOwnMacAddr, aucMacAddr, MAC_ADDR_LEN); + rDevInfo.ucActive = true; + rDevInfo.ucBandNum = 0; + rDevInfo.aucReserve[0] = ucOwnMacIdx; + + i4Status = kalIoctl(prGlueInfo, wlanoidDevInfoActive, &rDevInfo, + sizeof(CMD_DEVINFO_ACTIVE_T), false, false, true, + &u4BufLen); + + return i4Status; +} + +s32 BssInfoUpdate(struct net_device *prNetDev, u8 ucOwnMacIdx, u8 ucBssIdx, + u8 ucBssId[MAC_ADDR_LEN]) +{ + CMD_BSSINFO_BASIC_T rBssInfo; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + s32 i4Status = 0; + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + kalMemZero(&rBssInfo, sizeof(CMD_BSSINFO_BASIC_T)); + /* Tag assignment */ + rBssInfo.u2Tag = BSS_INFO_BASIC; + rBssInfo.u2Length = sizeof(CMD_BSSINFO_BASIC_T); + /* content */ + kalMemCopy(rBssInfo.aucBSSID, ucBssId, MAC_ADDR_LEN); + rBssInfo.ucBcMcWlanidx = ucBssIdx; + rBssInfo.ucActive = true; + rBssInfo.u4NetworkType = NETWORK_TYPE_AIS; + rBssInfo.u2BcnInterval = 100; + rBssInfo.ucDtimPeriod = 1; + + i4Status = kalIoctl(prGlueInfo, wlanoidBssInfoBasic, &rBssInfo, + sizeof(CMD_BSSINFO_BASIC_T), false, false, true, + &u4BufLen); + + return i4Status; +} + +s32 TxBfProfileDataRead(struct net_device *prNetDev, u8 profileIdx, u8 fgBFer, + u8 ucSubCarrIdxMsb, u8 ucSubCarrIdxLsb) +{ + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + PARAM_CUSTOM_TXBF_ACTION_STRUCT_T rTxBfActionInfo; + + kalMemZero(&rTxBfActionInfo, sizeof(rTxBfActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataRead : ucPfmuIdx = 0x%08x\n", profileIdx); + DBGLOG(RFTEST, ERROR, "MT6632 TxBfProfileDataRead : fgBFer = 0x%08x\n", + fgBFer); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataRead : ucSubCarrIdxMsb = 0x%08x\n", + ucSubCarrIdxMsb); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataRead : ucSubCarrIdxLsb = 0x%08x\n", + ucSubCarrIdxLsb); + + rTxBfActionInfo.rProfileDataRead.ucTxBfCategory = BF_PROFILE_READ; + rTxBfActionInfo.rProfileDataRead.ucPfmuIdx = profileIdx; + rTxBfActionInfo.rProfileDataRead.fgBFer = fgBFer; + rTxBfActionInfo.rProfileDataRead.ucSubCarrIdxMsb = ucSubCarrIdxMsb; + rTxBfActionInfo.rProfileDataRead.ucSubCarrIdxLsb = ucSubCarrIdxLsb; + + i4Status = kalIoctl(prGlueInfo, wlanoidTxBfAction, &rTxBfActionInfo, + sizeof(rTxBfActionInfo), true, true, true, + &u4BufLen); + + return i4Status; +} + +s32 TxBfProfileDataWrite(struct net_device *prNetDev, u8 profileIdx, + u16 u2SubCarrIdx, u16 au2Phi[6], u8 aucPsi[6], + u8 aucDSnr[4]) +{ + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + PARAM_CUSTOM_TXBF_ACTION_STRUCT_T rTxBfActionInfo; + + kalMemZero(&rTxBfActionInfo, sizeof(rTxBfActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : ucPfmuIdx = 0x%08x\n", + profileIdx); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : u2SubCarrIdx = 0x%08x\n", + u2SubCarrIdx); + + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : au2Phi[0] = 0x%08x\n", au2Phi[0]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : au2Phi[1] = 0x%08x\n", au2Phi[1]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : au2Phi[2] = 0x%08x\n", au2Phi[2]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : au2Phi[3] = 0x%08x\n", au2Phi[3]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : au2Phi[4] = 0x%08x\n", au2Phi[4]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : au2Phi[5] = 0x%08x\n", au2Phi[5]); + + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : aucPsi[0] = 0x%08x\n", aucPsi[0]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : aucPsi[1] = 0x%08x\n", aucPsi[1]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : aucPsi[2] = 0x%08x\n", aucPsi[2]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : aucPsi[3] = 0x%08x\n", aucPsi[3]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : aucPsi[4] = 0x%08x\n", aucPsi[4]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : aucPsi[5] = 0x%08x\n", aucPsi[5]); + + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : aucDSnr[0] = 0x%x\n", aucDSnr[0]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : aucDSnr[1] = 0x%x\n", aucDSnr[1]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : aucDSnr[2] = 0x%x\n", aucDSnr[2]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfileDataWrite : aucDSnr[3] = 0x%x\n", aucDSnr[3]); + + rTxBfActionInfo.rProfileDataWrite.ucTxBfCategory = BF_PROFILE_WRITE; + rTxBfActionInfo.rProfileDataWrite.ucPfmuIdx = profileIdx; + rTxBfActionInfo.rProfileDataWrite.u2SubCarrIdxLsb = u2SubCarrIdx; + rTxBfActionInfo.rProfileDataWrite.u2SubCarrIdxMsb = u2SubCarrIdx >> 8; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.u2Phi11 = + au2Phi[0]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.u2Phi21 = + au2Phi[1]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.u2Phi31 = + au2Phi[2]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.u2Phi22 = + au2Phi[3]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.u2Phi32 = + au2Phi[4]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.u2Phi33 = + au2Phi[5]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.ucPsi21 = + aucPsi[0]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.ucPsi31 = + aucPsi[1]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.ucPsi41 = + aucPsi[2]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.ucPsi32 = + aucPsi[3]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.ucPsi42 = + aucPsi[4]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.ucPsi43 = + aucPsi[5]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.u2dSNR00 = + aucDSnr[0]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.u2dSNR01 = + aucDSnr[1]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.u2dSNR02 = + aucDSnr[2]; + rTxBfActionInfo.rProfileDataWrite.rTxBfPfmuData.rField.u2dSNR03 = + aucDSnr[3]; + + i4Status = kalIoctl(prGlueInfo, wlanoidTxBfAction, &rTxBfActionInfo, + sizeof(rTxBfActionInfo), false, false, true, + &u4BufLen); + + return i4Status; +} + +s32 TxBfProfilePnRead(struct net_device *prNetDev, u8 profileIdx) +{ + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + PARAM_CUSTOM_TXBF_ACTION_STRUCT_T rTxBfActionInfo; + + kalMemZero(&rTxBfActionInfo, sizeof(rTxBfActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(RFTEST, ERROR, "MT6632 TxBfProfilePnRead : ucPfmuIdx = 0x%08x\n", + profileIdx); + + rTxBfActionInfo.rProfilePnRead.ucTxBfCategory = BF_PN_READ; + rTxBfActionInfo.rProfilePnRead.ucPfmuIdx = profileIdx; + + i4Status = kalIoctl(prGlueInfo, wlanoidTxBfAction, &rTxBfActionInfo, + sizeof(rTxBfActionInfo), false, false, true, + &u4BufLen); + + return i4Status; +} + +s32 TxBfProfilePnWrite(struct net_device *prNetDev, u8 profileIdx, u16 u2bw, + u16 au2XSTS[12]) +{ + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + PARAM_CUSTOM_TXBF_ACTION_STRUCT_T rTxBfActionInfo; + + kalMemZero(&rTxBfActionInfo, sizeof(rTxBfActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfilePnWrite : ucPfmuIdx = 0x%08x\n", profileIdx); + DBGLOG(RFTEST, ERROR, "MT6632 TxBfProfilePnWrite : u2bw = 0x%08x\n", + u2bw); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfilePnWrite : au2XSTS[0] = 0x%08x\n", au2XSTS[0]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfilePnWrite : au2XSTS[1] = 0x%08x\n", au2XSTS[1]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfilePnWrite : au2XSTS[2] = 0x%08x\n", au2XSTS[2]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfilePnWrite : au2XSTS[3] = 0x%08x\n", au2XSTS[3]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfilePnWrite : au2XSTS[4] = 0x%08x\n", au2XSTS[4]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfilePnWrite : au2XSTS[5] = 0x%08x\n", au2XSTS[5]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfilePnWrite : au2XSTS[6] = 0x%08x\n", au2XSTS[6]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfilePnWrite : au2XSTS[7] = 0x%08x\n", au2XSTS[7]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfilePnWrite : au2XSTS[8] = 0x%08x\n", au2XSTS[8]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfilePnWrite : au2XSTS[9] = 0x%08x\n", au2XSTS[9]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfilePnWrite : au2XSTS[10] = 0x%08x\n", + au2XSTS[10]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfProfilePnWrite : au2XSTS[11] = 0x%08x\n", + au2XSTS[11]); + + rTxBfActionInfo.rProfilePnWrite.ucTxBfCategory = BF_PN_WRITE; + rTxBfActionInfo.rProfilePnWrite.ucPfmuIdx = profileIdx; + rTxBfActionInfo.rProfilePnWrite.u2bw = u2bw; + memcpy(&rTxBfActionInfo.rProfilePnWrite.ucBuf[0], &au2XSTS[0], + sizeof(u16) * 12); + + i4Status = kalIoctl(prGlueInfo, wlanoidTxBfAction, &rTxBfActionInfo, + sizeof(rTxBfActionInfo), false, false, true, + &u4BufLen); + + return i4Status; +} + +s32 TxBfSounding(struct net_device *prNetDev, u8 ucSuMu, /* 0/1/2/3 */ + u8 ucNumSta, /* 00~04 */ + u8 ucSndInterval, /* 00~FF */ + u8 ucWLan0, /* 00~7F */ + u8 ucWLan1, /* 00~7F */ + u8 ucWLan2, /* 00~7F */ + + u8 ucWLan3 /* 00~7F */ + ) +{ + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + PARAM_CUSTOM_TXBF_ACTION_STRUCT_T rTxBfActionInfo; + + kalMemZero(&rTxBfActionInfo, sizeof(rTxBfActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(RFTEST, ERROR, "MT6632 TxBfSounding : ucSuMu = 0x%08x\n", + ucSuMu); + DBGLOG(RFTEST, ERROR, "MT6632 TxBfSounding : ucNumSta = 0x%08x\n", + ucNumSta); + DBGLOG(RFTEST, ERROR, "MT6632 TxBfSounding : ucSndInterval = 0x%08x\n", + ucSndInterval); + DBGLOG(RFTEST, ERROR, "MT6632 TxBfSounding : ucWLan0 = 0x%08x\n", + ucWLan0); + DBGLOG(RFTEST, ERROR, "MT6632 TxBfSounding : ucWLan1 = 0x%08x\n", + ucWLan1); + DBGLOG(RFTEST, ERROR, "MT6632 TxBfSounding : ucWLan2 = 0x%08x\n", + ucWLan2); + DBGLOG(RFTEST, ERROR, "MT6632 TxBfSounding : ucWLan3 = 0x%08x\n", + ucWLan3); + + switch (ucSuMu) { + case MU_SOUNDING: + + case MU_PERIODIC_SOUNDING: + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfMuSndPeriodicTriggerCtrl.ucCmdCategoryID = + BF_SOUNDING_ON; + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfMuSndPeriodicTriggerCtrl.ucSuMuSndMode = + ucSuMu; + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfMuSndPeriodicTriggerCtrl.ucStaNum = + ucNumSta; + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfMuSndPeriodicTriggerCtrl + .u4SoundingInterval = ucSndInterval; + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfMuSndPeriodicTriggerCtrl.ucWlanId[0] = + ucWLan0; + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfMuSndPeriodicTriggerCtrl.ucWlanId[1] = + ucWLan1; + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfMuSndPeriodicTriggerCtrl.ucWlanId[2] = + ucWLan2; + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfMuSndPeriodicTriggerCtrl.ucWlanId[3] = + ucWLan3; + break; + + case SU_SOUNDING: + case SU_PERIODIC_SOUNDING: + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfSndPeriodicTriggerCtrl.ucCmdCategoryID = + BF_SOUNDING_ON; + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfSndPeriodicTriggerCtrl.ucSuMuSndMode = + ucSuMu; + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfSndPeriodicTriggerCtrl.u4SoundingInterval = + ucSndInterval; + rTxBfActionInfo.rTxBfSoundingStart.rTxBfSounding + .rExtCmdExtBfSndPeriodicTriggerCtrl.ucWlanIdx = ucWLan0; + break; + + default: + break; + } + + i4Status = kalIoctl(prGlueInfo, wlanoidTxBfAction, &rTxBfActionInfo, + sizeof(rTxBfActionInfo), false, false, true, + &u4BufLen); + + return i4Status; +} + +s32 TxBfSoundingStop(struct net_device *prNetDev) +{ + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + PARAM_CUSTOM_TXBF_ACTION_STRUCT_T rTxBfActionInfo; + + kalMemZero(&rTxBfActionInfo, sizeof(rTxBfActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(RFTEST, ERROR, "MT6632 TxBfSoundingStop\n"); + + rTxBfActionInfo.rTxBfSoundingStop.ucTxBfCategory = BF_SOUNDING_OFF; + rTxBfActionInfo.rTxBfSoundingStop.ucSndgStop = 1; + + i4Status = kalIoctl(prGlueInfo, wlanoidTxBfAction, &rTxBfActionInfo, + sizeof(rTxBfActionInfo), false, false, true, + &u4BufLen); + + return i4Status; +} + +s32 TxBfTxApply(struct net_device *prNetDev, u8 ucWlanId, u8 fgETxBf, + u8 fgITxBf, u8 fgMuTxBf) +{ + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + PARAM_CUSTOM_TXBF_ACTION_STRUCT_T rTxBfActionInfo; + + kalMemZero(&rTxBfActionInfo, sizeof(rTxBfActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(RFTEST, + ERROR, + "MT6632 TxBfTxApply : ucWlanId = 0x%08x, fgETxBf = 0x%08x,fgITxBf = 0x%08x,fgMuTxBf = 0x%08x\n", + ucWlanId, + fgETxBf, + fgITxBf, + fgMuTxBf); + + rTxBfActionInfo.rTxBfTxApply.ucTxBfCategory = BF_DATA_PACKET_APPLY; + rTxBfActionInfo.rTxBfTxApply.ucWlanId = ucWlanId; + rTxBfActionInfo.rTxBfTxApply.fgETxBf = fgETxBf; + rTxBfActionInfo.rTxBfTxApply.fgITxBf = fgITxBf; + rTxBfActionInfo.rTxBfTxApply.fgMuTxBf = fgMuTxBf; + + i4Status = kalIoctl(prGlueInfo, wlanoidTxBfAction, &rTxBfActionInfo, + sizeof(rTxBfActionInfo), false, false, true, + &u4BufLen); + + return i4Status; +} + +s32 TxBfPfmuMemAlloc(struct net_device *prNetDev, u8 ucSuMuMode, u8 ucWlanIdx) +{ + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + PARAM_CUSTOM_TXBF_ACTION_STRUCT_T rTxBfActionInfo; + + kalMemZero(&rTxBfActionInfo, sizeof(rTxBfActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(RFTEST, + ERROR, + "MT6632 TxBfPfmuMemAlloc : ucSuMuMode = 0x%08x, ucWlanIdx = 0x%08x\n", + ucSuMuMode, + ucWlanIdx); + + rTxBfActionInfo.rTxBfPfmuMemAlloc.ucTxBfCategory = BF_PFMU_MEM_ALLOCATE; + rTxBfActionInfo.rTxBfPfmuMemAlloc.ucSuMuMode = ucSuMuMode; + rTxBfActionInfo.rTxBfPfmuMemAlloc.ucWlanIdx = ucWlanIdx; + + i4Status = kalIoctl(prGlueInfo, wlanoidTxBfAction, &rTxBfActionInfo, + sizeof(rTxBfActionInfo), false, false, true, + &u4BufLen); + + return i4Status; +} + +s32 TxBfPfmuMemRelease(struct net_device *prNetDev, u8 ucWlanId) +{ + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + PARAM_CUSTOM_TXBF_ACTION_STRUCT_T rTxBfActionInfo; + + kalMemZero(&rTxBfActionInfo, sizeof(rTxBfActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(RFTEST, ERROR, "MT6632 TxBfPfmuMemRelease : ucWlanId = 0x%08x\n", + ucWlanId); + + rTxBfActionInfo.rTxBfPfmuMemRls.ucTxBfCategory = BF_PFMU_MEM_RELEASE; + rTxBfActionInfo.rTxBfPfmuMemRls.ucWlanId = ucWlanId; + + i4Status = kalIoctl(prGlueInfo, wlanoidTxBfAction, &rTxBfActionInfo, + sizeof(rTxBfActionInfo), false, false, true, + &u4BufLen); + + return i4Status; +} + +s32 TxBfBssInfoUpdate(struct net_device *prNetDev, u8 ucOwnMacIdx, u8 ucBssIdx, u8 ucBssId[MAC_ADDR_LEN]) +{ + s32 i4Status = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + /* u32 u4BufLen = 0; */ + PARAM_CUSTOM_TXBF_ACTION_STRUCT_T rTxBfActionInfo; + P_BSS_INFO_T prBssInfo; + + kalMemZero(&rTxBfActionInfo, sizeof(rTxBfActionInfo)); + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfBssInfoUpdate : ucOwnMacIdx = 0x%08x\n", + ucOwnMacIdx); + DBGLOG(RFTEST, ERROR, "MT6632 TxBfBssInfoUpdate : ucBssIdx = 0x%08x\n", + ucBssIdx); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfBssInfoUpdate : ucBssId[0] = 0x%08x\n", ucBssId[0]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfBssInfoUpdate : ucBssId[1] = 0x%08x\n", ucBssId[1]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfBssInfoUpdate : ucBssId[2] = 0x%08x\n", ucBssId[2]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfBssInfoUpdate : ucBssId[3] = 0x%08x\n", ucBssId[3]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfBssInfoUpdate : ucBssId[4] = 0x%08x\n", ucBssId[4]); + DBGLOG(RFTEST, ERROR, + "MT6632 TxBfBssInfoUpdate : ucBssId[5] = 0x%08x\n", ucBssId[5]); + + prBssInfo = prAdapter->aprBssInfo[ucBssIdx]; + + if (!prBssInfo) { + return WLAN_STATUS_FAILURE; + } + + prBssInfo->ucOwnMacIndex = ucOwnMacIdx; + memcpy(&prBssInfo->aucBSSID, ucBssId, MAC_ADDR_LEN); + + nicUpdateBss(prAdapter, prBssInfo->ucBssIndex); + + return i4Status; +} + +/* iwpriv ra0 set assoc=[mac:hh:hh:hh:hh:hh:hh]-[wtbl:dd]- + *[ownmac:dd]-[type:xx]-[mode:mmm]-[bw:dd]-[nss:ss]-[maxrate:kkk_dd] + */ +s32 TxBfManualAssoc(struct net_device *prNetDev, u8 aucMac[MAC_ADDR_LEN], + u8 ucType, + /* no use */ + u8 ucWtbl, u8 ucOwnmac, u8 ucMode, u8 ucBw, u8 ucNss, + u8 ucPfmuId, u8 ucMarate, u8 ucSpeIdx, u8 ucRca2, u8 ucRv) +{ + CMD_MANUAL_ASSOC_STRUCT_T rManualAssoc; + /* P_STA_RECORD_T prStaRec; */ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + s32 i4Status = 0; + /* u8 ucNsts; + * u32 i; + */ + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + kalMemZero(&rManualAssoc, sizeof(CMD_MANUAL_ASSOC_STRUCT_T)); + /* Tag assignment */ + rManualAssoc.u2Tag = STA_REC_MAUNAL_ASSOC; + rManualAssoc.u2Length = sizeof(CMD_MANUAL_ASSOC_STRUCT_T); + /* content */ + kalMemCopy(rManualAssoc.aucMac, aucMac, MAC_ADDR_LEN); + rManualAssoc.ucType = ucType; + rManualAssoc.ucWtbl = ucWtbl; + rManualAssoc.ucOwnmac = ucOwnmac; + rManualAssoc.ucMode = ucMode; + rManualAssoc.ucBw = ucBw; + rManualAssoc.ucNss = ucNss; + rManualAssoc.ucPfmuId = ucPfmuId; + rManualAssoc.ucMarate = ucMarate; + rManualAssoc.ucSpeIdx = ucSpeIdx; + rManualAssoc.ucaid = ucRca2; + + i4Status = kalIoctl(prGlueInfo, wlanoidManualAssoc, &rManualAssoc, + sizeof(CMD_MANUAL_ASSOC_STRUCT_T), false, false, + true, &u4BufLen); + + return i4Status; +} + +#endif +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_init.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_init.c new file mode 100644 index 00000000000000..3aa02fa8776c27 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_init.c @@ -0,0 +1,3355 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_init.c + * \brief Main routines of Linux driver + * + * This file contains the main routines of Linux driver for MediaTek Inc. + * 802.11 Wireless LAN Adapters. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include <linux/platform_device.h> +#include <linux/reboot.h> + +#include "gl_os.h" +#include "debug.h" +#include "wlan_lib.h" +#include "gl_wext.h" +#include "gl_cfg80211.h" +#include "precomp.h" +#include "gl_kal.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +struct semaphore g_halt_sem; +int g_u4HaltFlag; +struct wireless_dev *gprWdev; +struct completion rWaitForResetComp; +struct completion *prWaitForResetComp = NULL; + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* Tasklet mechanism is like buttom-half in Linux. We just want to + * send a signal to OS for interrupt defer processing. All resources + * are NOT allowed reentry, so txPacket, ISR-DPC and ioctl must avoid preempty. + */ +typedef struct _WLANDEV_INFO_T { + struct net_device *prDev; +} WLANDEV_INFO_T, *P_WLANDEV_INFO_T; + +struct delayed_work wdev_lock_workq; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +#define DRIVER_NAME "mt76x8_wifi_sdio" + +MODULE_AUTHOR("Mediatek Ltd."); +MODULE_AUTHOR("Yogi Hermawan"); +MODULE_DESCRIPTION("Mediatek MT7668S (SDIO) Wireleses Driver"); +MODULE_VERSION(NIC_DRIVER_VERSION_STRING); +MODULE_LICENSE("Dual BSD/GPL"); + +#ifdef CFG_DRIVER_INF_NAME_CHANGE +char *gprifnamesta = ""; +char *gprifnamep2p = ""; +char *gprifnameap = ""; +module_param_named(sta, gprifnamesta, charp, 0); +module_param_named(p2p, gprifnamep2p, charp, 0); +module_param_named(ap, gprifnameap, charp, 0); +#endif + +/* NIC interface name */ +#define NIC_INF_NAME "phy0-sta%d" + +#ifdef CFG_DRIVER_INF_NAME_CHANGE +/* Kernel IFNAMESIZ is 16, we use 5 in case some protocol might auto gen + * interface name, */ +/* in that case, the interface name might have risk of over kernel's IFNAMESIZ + */ +#define CUSTOM_IFNAMESIZ 5 +#endif + +#if CFG_SUPPORT_SNIFFER +#define NIC_MONITOR_INF_NAME "radiotap%d" +#endif + +u8 aucDebugModule[DBG_MODULE_NUM]; + +/* 4 2007/06/26, mikewu, now we don't use this, we just fix the number of wlan + * device to 1 */ +static WLANDEV_INFO_T arWlanDevInfo[CFG_MAX_WLAN_DEVICES] = { { 0 } }; + +static u32 u4WlanDevNum; /* How many NICs coexist now */ + +/**20150205 added work queue for sched_scan to avoid cfg80211 stop schedule scan + * dead loack**/ +struct delayed_work sched_workq; + +#define CFG_WIFI_FILENAME "wifi.cfg" + +#define CFG_EEPRM_FILENAME "EEPROM" +#define FILE_NAME_MAX 64 + +#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1) +static u8 *apucEepromName[] = { (u8 *)CFG_EEPRM_FILENAME "_MT", NULL }; +#endif + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +#define CHAN2G(_idx, _freq) \ + { \ + .band = NL80211_BAND_2GHZ, .center_freq = (_freq), .hw_value = (_idx), \ + .max_power = 30, \ + } + +#define CHAN5G(_idx, _freq) \ + { \ + .band = NL80211_BAND_5GHZ, .center_freq = (_freq), .hw_value = (_idx), \ + .max_power = 30, \ + } + +#define CCK_RATE(_idx, _rate) \ + { \ + .bitrate = _rate, .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ + .hw_value = (_idx), .hw_value_short = (4 + _idx), \ + } + +#define OFDM_RATE(_idx, _rate) \ + { \ + .bitrate = _rate, .hw_value = (_idx), .hw_value_short = (_idx), \ + } + +static struct ieee80211_channel mtk_2ghz_channels[] = { + CHAN2G(1, 2412), CHAN2G(2, 2417), CHAN2G(3, 2422), CHAN2G(4, 2427), + CHAN2G(5, 2432), CHAN2G(6, 2437), CHAN2G(7, 2442), CHAN2G(8, 2447), + CHAN2G(9, 2452), CHAN2G(10, 2457), CHAN2G(11, 2462), CHAN2G(12, 2467), + CHAN2G(13, 2472), CHAN2G(14, 2484), +}; + +static struct ieee80211_channel mtk_5ghz_channels[] = { + CHAN5G(36, 5180), CHAN5G(40, 5200), CHAN5G(44, 5220), CHAN5G(48, 5240), + + CHAN5G(52, 5260), CHAN5G(56, 5280), CHAN5G(60, 5300), CHAN5G(64, 5320), + + CHAN5G(100, 5500), CHAN5G(104, 5520), CHAN5G(108, 5540), CHAN5G(112, 5560), + CHAN5G(116, 5580), CHAN5G(120, 5600), CHAN5G(124, 5620), CHAN5G(128, 5640), + CHAN5G(132, 5660), CHAN5G(136, 5680), CHAN5G(140, 5700), CHAN5G(144, 5720), + + CHAN5G(149, 5745), CHAN5G(153, 5765), CHAN5G(157, 5785), CHAN5G(161, 5805), + CHAN5G(165, 5825), CHAN5G(169, 5845), CHAN5G(173, 5865), CHAN5G(177, 5885), +}; + +static struct ieee80211_rate mtk_rates[] = { + CCK_RATE(0, 10), CCK_RATE(1, 20), CCK_RATE(2, 55), + CCK_RATE(3, 110), OFDM_RATE(11, 60), OFDM_RATE(15, 90), + OFDM_RATE(10, 120), OFDM_RATE(14, 180), OFDM_RATE(9, 240), + OFDM_RATE(13, 360), OFDM_RATE(8, 480), OFDM_RATE(12, 540), +}; + +#define mtk_a_rates (mtk_rates + 4) +#define mtk_a_rates_size (ARRAY_SIZE(mtk_rates) - 4) +#define mtk_g_rates (mtk_rates + 0) +#define mtk_g_rates_size (ARRAY_SIZE(mtk_rates) - 0) + +#define WLAN_MCS_INFO \ + { \ + .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .rx_highest = 0, \ + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ + } + +#define WLAN_VHT_MCS_INFO \ + { \ + .rx_mcs_map = 0xFFFA, .rx_highest = cpu_to_le16(867), \ + .tx_mcs_map = 0xFFFA, .tx_highest = cpu_to_le16(867), \ + } + +#define WLAN_HT_CAP \ + { \ + .ht_supported = true, \ + .cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_SM_PS | \ + IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \ + IEEE80211_HT_CAP_SGI_40, \ + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, \ + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, .mcs = WLAN_MCS_INFO, \ + } + +#define WLAN_VHT_CAP \ + { \ + .vht_supported = true, \ + .cap = IEEE80211_VHT_CAP_RXLDPC | \ + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK | \ + IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 | \ + IEEE80211_VHT_CAP_RXLDPC | IEEE80211_VHT_CAP_SHORT_GI_80 | \ + IEEE80211_VHT_CAP_TXSTBC | \ + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | \ + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE, \ + .vht_mcs = WLAN_VHT_MCS_INFO, \ + } + +/* public for both Legacy Wi-Fi / P2P access */ +struct ieee80211_supported_band mtk_band_2ghz = { + .band = NL80211_BAND_2GHZ, + .channels = mtk_2ghz_channels, + .n_channels = ARRAY_SIZE(mtk_2ghz_channels), + .bitrates = mtk_g_rates, + .n_bitrates = mtk_g_rates_size, + .ht_cap = WLAN_HT_CAP, +}; + +/* public for both Legacy Wi-Fi / P2P access */ +struct ieee80211_supported_band mtk_band_5ghz = { + .band = NL80211_BAND_5GHZ, + .channels = mtk_5ghz_channels, + .n_channels = ARRAY_SIZE(mtk_5ghz_channels), + .bitrates = mtk_a_rates, + .n_bitrates = mtk_a_rates_size, + .ht_cap = WLAN_HT_CAP, + .vht_cap = WLAN_VHT_CAP, +}; + +const u32 mtk_cipher_suites[5] = { + /* keep WEP first, it may be removed below */ + WLAN_CIPHER_SUITE_WEP40, WLAN_CIPHER_SUITE_WEP104, WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + + /* keep last -- depends on hw flags! */ + WLAN_CIPHER_SUITE_AES_CMAC +}; + +#if (CFG_ENABLE_UNIFY_WIPHY == 0) +static struct cfg80211_ops mtk_wlan_ops = { + .change_virtual_intf = mtk_cfg80211_change_iface, + .add_key = mtk_cfg80211_add_key, + .get_key = mtk_cfg80211_get_key, + .del_key = mtk_cfg80211_del_key, + .set_default_key = mtk_cfg80211_set_default_key, + .get_station = mtk_cfg80211_get_station, + .change_station = mtk_cfg80211_change_station, + .add_station = mtk_cfg80211_add_station, + .del_station = mtk_cfg80211_del_station, + .scan = mtk_cfg80211_scan, + .abort_scan = mtk_cfg80211_abort_scan, + .connect = mtk_cfg80211_connect, + .deauth = mtk_cfg80211_deauth, + .disassoc = mtk_cfg80211_disassoc, + .disconnect = mtk_cfg80211_disconnect, + .join_ibss = mtk_cfg80211_join_ibss, + .leave_ibss = mtk_cfg80211_leave_ibss, + .set_power_mgmt = mtk_cfg80211_set_power_mgmt, + .set_pmksa = mtk_cfg80211_set_pmksa, + .del_pmksa = mtk_cfg80211_del_pmksa, + .flush_pmksa = mtk_cfg80211_flush_pmksa, + .set_rekey_data = mtk_cfg80211_set_rekey_data, + .set_wakeup = mtk_cfg80211_set_wakeup, + .suspend = mtk_cfg80211_suspend, + .resume = mtk_cfg80211_resume, + .auth = mtk_cfg80211_auth, + .assoc = mtk_cfg80211_assoc, + .remain_on_channel = mtk_cfg80211_remain_on_channel, + .cancel_remain_on_channel = mtk_cfg80211_cancel_remain_on_channel, + .mgmt_tx = mtk_cfg80211_mgmt_tx, +#if KERNEL_VERSION(5, 8, 0) >= CFG80211_VERSION_CODE + .mgmt_frame_register = mtk_cfg80211_mgmt_frame_register, +#endif + .tdls_oper = mtk_cfg80211_tdls_oper, + .tdls_mgmt = mtk_cfg80211_tdls_mgmt, +#ifdef CONFIG_NL80211_TESTMODE + .testmode_cmd = mtk_cfg80211_testmode_cmd, +#endif +}; + +#else /* CFG_ENABLE_UNIFY_WIPHY */ +static struct cfg80211_ops mtk_cfg_ops = { + .add_virtual_intf = mtk_cfg_add_iface, + .del_virtual_intf = mtk_cfg_del_iface, + .change_virtual_intf = mtk_cfg_change_iface, + .add_key = mtk_cfg_add_key, + .get_key = mtk_cfg_get_key, + .del_key = mtk_cfg_del_key, + .set_default_mgmt_key = mtk_cfg_set_default_mgmt_key, + .set_default_key = mtk_cfg_set_default_key, + .get_station = mtk_cfg_get_station, +#if CFG_SUPPORT_TDLS + .change_station = mtk_cfg_change_station, + .add_station = mtk_cfg_add_station, + .tdls_oper = mtk_cfg_tdls_oper, + .tdls_mgmt = mtk_cfg_tdls_mgmt, +#endif + .del_station = mtk_cfg_del_station, /* AP/P2P use this function */ + .scan = mtk_cfg_scan, + .abort_scan = mtk_cfg_abort_scan, + + .sched_scan_start = mtk_cfg_sched_scan_start, + .sched_scan_stop = mtk_cfg_sched_scan_stop, + +#if 0 // !CFG_SUPPORT_CFG80211_AUTH + .connect = mtk_cfg80211_connect, + .disconnect = mtk_cfg80211_disconnect, +#endif + .deauth = mtk_cfg_deauth, + .join_ibss = mtk_cfg_join_ibss, + .leave_ibss = mtk_cfg_leave_ibss, + .set_power_mgmt = mtk_cfg_set_power_mgmt, + .set_pmksa = mtk_cfg_set_pmksa, + .del_pmksa = mtk_cfg_del_pmksa, + .flush_pmksa = mtk_cfg_flush_pmksa, +#if CONFIG_SUPPORT_GTK_REKEY + .set_rekey_data = mtk_cfg_set_rekey_data, +#endif + .suspend = mtk_cfg_suspend, + .resume = mtk_cfg_resume, + .auth = mtk_cfg_auth, + .assoc = mtk_cfg_assoc, + + /* Action Frame TX/RX */ + .remain_on_channel = mtk_cfg_remain_on_channel, + .cancel_remain_on_channel = mtk_cfg_cancel_remain_on_channel, + .mgmt_tx = mtk_cfg_mgmt_tx, + /* .mgmt_tx_cancel_wait = mtk_cfg80211_mgmt_tx_cancel_wait, */ +#if KERNEL_VERSION(5, 8, 0) <= CFG80211_VERSION_CODE + .update_mgmt_frame_registrations = mtk_cfg_mgmt_frame_update, +#else + .mgmt_frame_register = mtk_cfg_mgmt_frame_register, +#endif + +#if (CFG_SUPPORT_DFS_MASTER == 1) + .start_radar_detection = mtk_cfg_start_radar_detection, + .channel_switch = mtk_cfg_channel_switch, +#endif + +#if (CFG_ENABLE_WIFI_DIRECT_CFG_80211 != 0) + .change_bss = mtk_cfg_change_bss, + .mgmt_tx_cancel_wait = mtk_cfg_mgmt_tx_cancel_wait, + .deauth = mtk_cfg_deauth, + .disassoc = mtk_cfg_disassoc, + .start_ap = mtk_cfg_start_ap, + .change_beacon = mtk_cfg_change_beacon, + .stop_ap = mtk_cfg_stop_ap, + .set_wiphy_params = mtk_cfg_set_wiphy_params, + .set_bitrate_mask = mtk_cfg_set_bitrate_mask, + .set_tx_power = mtk_cfg_set_txpower, + .get_tx_power = mtk_cfg_get_txpower, +#endif + // .update_ft_ies = mtk_cfg80211_update_ft_ies, +}; +#endif /* CFG_ENABLE_UNIFY_WIPHY */ + +/* There isn't a lot of sense in it, but you can transmit anything you like */ +static const struct ieee80211_txrx_stypes + mtk_cfg80211_ais_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_ADHOC] = + { /**/ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_STATION] = + { /**/ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_BEACON >> 4) + }, + [NL80211_IFTYPE_AP] = + { /**/ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_AP_VLAN] = + { /* copy AP */ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = + { /**/ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_GO] = { /**/ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + } +}; + +#ifdef CONFIG_PM +static const struct wiphy_wowlan_support mtk_wlan_wowlan_support = { + .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_ANY, +}; +#endif + +#ifdef STA_P2P_MCC +static const struct ieee80211_iface_limit iface_limits_mcc[] = { + { .max = 2, + .types = (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_P2P_CLIENT)) } +}; + +static const struct ieee80211_iface_combination + iface_comb_mcc[] = { /**/ + { + .limits = iface_limits_mcc, + .n_limits = ARRAY_SIZE(iface_limits_mcc), + .max_interfaces = 2, + .num_different_channels = 2, + .beacon_int_infra_match = false, + } +}; + +#endif + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#if KERNEL_VERSION(5, 2, 0) <= LINUX_VERSION_CODE +u16 wlanSelectQueue(struct net_device *dev, struct sk_buff *skb, + struct net_device *sb_dev) +#elif KERNEL_VERSION(4, 19, 0) <= LINUX_VERSION_CODE +u16 wlanSelectQueue(struct net_device *dev, struct sk_buff *skb, + struct net_device *sb_dev, select_queue_fallback_t fallback) +#else +u16 wlanSelectQueue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback) +#endif +{ + return mtk_wlan_ndev_select_queue(skb); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Load NVRAM data and translate it into REG_INFO_T + * + * \param[in] prGlueInfo Pointer to P_GLUE_INFO_T + * \param[out] prRegInfo Pointer to P_REG_INFO_T + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static void glLoadNvram(IN P_GLUE_INFO_T prGlueInfo, + OUT P_REG_INFO_T prRegInfo) +{ + u32 i, j; + u8 aucTmp[2]; + u8 *pucDest; + + ASSERT(prGlueInfo); + ASSERT(prRegInfo); + + if ((!prGlueInfo) || (!prRegInfo)) { + return; + } + + if (kalCfgDataRead16(prGlueInfo, + sizeof(WIFI_CFG_PARAM_STRUCT) - sizeof(u16), + (u16 *)aucTmp) == true) { + prGlueInfo->fgNvramAvailable = true; + + /* load MAC Address */ + for (i = 0; i < PARAM_MAC_ADDR_LEN; i += sizeof(u16)) { + kalCfgDataRead16( + prGlueInfo, OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucMacAddress) + i, + (u16 *)(((u8 *)prRegInfo->aucMacAddr) + i)); + } + + /* load country code */ + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucCountryCode[0]), + (u16 *)aucTmp); + + /* cast to wide characters */ + prRegInfo->au2CountryCode[0] = (u16)aucTmp[0]; + prRegInfo->au2CountryCode[1] = (u16)aucTmp[1]; + + /* load default normal TX power */ + for (i = 0; i < sizeof(TX_PWR_PARAM_T); i += sizeof(u16)) { + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, rTxPwr) + i, + (u16 *)(((u8 *)&(prRegInfo->rTxPwr)) + i)); + } + + /* load feature flags */ + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucTxPwrValid), + (u16 *)aucTmp); + prRegInfo->ucTxPwrValid = aucTmp[0]; + prRegInfo->ucSupport5GBand = aucTmp[1]; + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, uc2G4BwFixed20M), + (u16 *)aucTmp); + prRegInfo->uc2G4BwFixed20M = aucTmp[0]; + prRegInfo->uc5GBwFixed20M = aucTmp[1]; + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucEnable5GBand), + (u16 *)aucTmp); + prRegInfo->ucEnable5GBand = aucTmp[0]; + prRegInfo->ucRxDiversity = aucTmp[1]; + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, + fgRssiCompensationVaildbit), + (u16 *)aucTmp); + prRegInfo->ucRssiPathCompasationUsed = aucTmp[0]; + prRegInfo->ucGpsDesense = aucTmp[1]; + +#if CFG_SUPPORT_NVRAM_5G + /* load EFUSE overriding part */ + for (i = 0; i < sizeof(prRegInfo->aucEFUSE); i += sizeof(u16)) { + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, EfuseMapping) + i, + (u16 *)(((u8 *)&(prRegInfo->aucEFUSE)) + i)); + } + + prRegInfo->prOldEfuseMapping = + (P_NEW_EFUSE_MAPPING2NVRAM_T)&prRegInfo->aucEFUSE; +#else + /* load EFUSE overriding part */ + for (i = 0; i < sizeof(prRegInfo->aucEFUSE); i += sizeof(u16)) { + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, aucEFUSE) + i, + (u16 *)(((u8 *)&(prRegInfo->aucEFUSE)) + i)); + } +#endif + + /* load band edge tx power control */ + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, fg2G4BandEdgePwrUsed), + (u16 *)aucTmp); + prRegInfo->fg2G4BandEdgePwrUsed = (u8)aucTmp[0]; + if (aucTmp[0]) { + prRegInfo->cBandEdgeMaxPwrCCK = (s8)aucTmp[1]; + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, + cBandEdgeMaxPwrOFDM20), + (u16 *)aucTmp); + prRegInfo->cBandEdgeMaxPwrOFDM20 = (s8)aucTmp[0]; + prRegInfo->cBandEdgeMaxPwrOFDM40 = (s8)aucTmp[1]; + } + + /* load regulation subbands */ + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, ucRegChannelListMap), + (u16 *)aucTmp); + prRegInfo->eRegChannelListMap = (ENUM_REG_CH_MAP_T)aucTmp[0]; + prRegInfo->ucRegChannelListIndex = aucTmp[1]; + + if (prRegInfo->eRegChannelListMap == REG_CH_MAP_CUSTOMIZED) { + for (i = 0; i < MAX_SUBBAND_NUM; i++) { + pucDest = (u8 *)&prRegInfo->rDomainInfo.rSubBand[i]; + for (j = 0; j < 6; j += sizeof(u16)) { + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, + aucRegSubbandInfo) + + (i * 6 + j), + (u16 *)aucTmp); + + *pucDest++ = aucTmp[0]; + *pucDest++ = aucTmp[1]; + } + } + } + + /* load rssiPathCompensation */ + for (i = 0; i < sizeof(RSSI_PATH_COMPASATION_T); i += sizeof(u16)) { + kalCfgDataRead16( + prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, rRssiPathCompensation) + i, + (u16 *)(((u8 *)&(prRegInfo->rRssiPathCompasation)) + i)); + } + + /* load full NVRAM */ + for (i = 0; i < sizeof(WIFI_CFG_PARAM_STRUCT); i += sizeof(u16)) { + kalCfgDataRead16( + prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part1OwnVersion) + i, + (u16 *)(((u8 *)&(prRegInfo->aucNvram)) + i)); + } + prRegInfo->prNvramSettings = + (P_WIFI_CFG_PARAM_STRUCT)&prRegInfo->aucNvram; + } else { + DBGLOG(INIT, INFO, "glLoadNvram fail\n"); + prGlueInfo->fgNvramAvailable = false; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Release prDev from wlandev_array and free tasklet object related to + * it. + * + * \param[in] prDev Pointer to struct net_device + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static void wlanClearDevIdx(struct net_device *prDev) +{ + int i; + + ASSERT(prDev); + + for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) { + if (arWlanDevInfo[i].prDev == prDev) { + arWlanDevInfo[i].prDev = NULL; + u4WlanDevNum--; + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Allocate an unique interface index, net_device::ifindex member for + * this wlan device. Store the net_device in wlandev_array, and initialize + * tasklet object related to it. + * + * \param[in] prDev Pointer to struct net_device + * + * \retval >= 0 The device number. + * \retval -1 Fail to get index. + */ +/*----------------------------------------------------------------------------*/ +static int wlanGetDevIdx(struct net_device *prDev) +{ + int i; + + ASSERT(prDev); + + for (i = 0; i < CFG_MAX_WLAN_DEVICES; i++) { + if (arWlanDevInfo[i].prDev == (struct net_device *)NULL) { + /* Reserve 2 bytes space to store one digit of + * device number and NULL terminator. + */ + arWlanDevInfo[i].prDev = prDev; + u4WlanDevNum++; + return i; + } + } + + return -1; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A method of struct net_device, a primary SOCKET interface to configure + * the interface lively. Handle an ioctl call on one of our devices. + * Everything Linux ioctl specific is done here. Then we pass the + * contents of the ifr->data to the request message handler. + * + * \param[in] prDev Linux kernel netdevice + * + * \param[in] prIFReq Our private ioctl request structure, typed for the + * generic struct ifreq so we can use ptr to function + * + * \param[in] cmd Command ID + * + * \retval WLAN_STATUS_SUCCESS The IOCTL command is executed successfully. + * \retval OTHER The execution of IOCTL command is failed. + */ +/*----------------------------------------------------------------------------*/ +int wlanDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + int ret = 0; + + /* Verify input parameters for the following functions */ + ASSERT(prDev && prIfReq); + if (!prDev || !prIfReq) { + DBGLOG(INIT, ERROR, "Invalid input data\n"); + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + if (!prGlueInfo) { + DBGLOG(INIT, ERROR, "prGlueInfo is NULL\n"); + return -EFAULT; + } + + if (prGlueInfo->u4ReadyFlag == 0) { + DBGLOG(INIT, ERROR, "Adapter is not ready\n"); + return -EINVAL; + } + + if ((i4Cmd >= SIOCIWFIRST) && (i4Cmd < SIOCIWFIRSTPRIV)) { + /* 0x8B00 ~ 0x8BDF, wireless extension region */ + ret = wext_support_ioctl(prDev, prIfReq, i4Cmd); + } else if ((i4Cmd >= SIOCIWFIRSTPRIV) && (i4Cmd < SIOCIWLASTPRIV)) { + /* 0x8BE0 ~ 0x8BFF, private ioctl region */ + ret = priv_support_ioctl(prDev, prIfReq, i4Cmd); + } else if (i4Cmd == SIOCDEVPRIVATE + 1) { +#ifdef CFG_ANDROID_AOSP_PRIV_CMD + ret = android_private_support_driver_cmd(prDev, prIfReq, i4Cmd); +#else + ret = priv_support_driver_cmd(prDev, prIfReq, i4Cmd); +#endif + } else { + DBGLOG(INIT, WARN, "Unexpected ioctl command: 0x%04x\n", i4Cmd); + ret = -EOPNOTSUPP; + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Export wlan GLUE_INFO_T pointer to p2p module + * + * \param[in] prGlueInfo Pointer to P_GLUE_INFO_T + * + * \return true: get GlueInfo pointer successfully + * false: wlan is not started yet + */ +/*---------------------------------------------------------------------------*/ +P_GLUE_INFO_T wlanGetGlueInfo(void) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + if (u4WlanDevNum == 0) { + return NULL; + } + + prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; + if (prDev == NULL) { + return NULL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + + return prGlueInfo; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is to set multicast list and set rx mode. + * + * \param[in] prDev Pointer to struct net_device + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ + +static struct delayed_work workq; +struct net_device *gPrDev; + +static void wlanSetMulticastList(struct net_device *prDev) +{ + /* Allow to receive all multicast for WOW */ + DBGLOG(INIT, INFO, "wlanSetMulticastList\n"); + prDev->flags |= (IFF_MULTICAST | IFF_ALLMULTI); + gPrDev = prDev; + schedule_delayed_work(&workq, 0); +} + +/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange + * another workqueue for sleeping. We don't want to block + * main_thread, so we can't let tx_thread to do this + */ +static void wlanSetMulticastListWorkQueue(struct work_struct *work) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u32 u4PacketFilter = 0; + u32 u4SetInfoLen; + struct net_device *prDev = gPrDev; + + down(&g_halt_sem); + if (g_u4HaltFlag) { + up(&g_halt_sem); + return; + } + + prGlueInfo = (prDev != NULL) ? *((P_GLUE_INFO_T *)netdev_priv(prDev)) : + NULL; + ASSERT(prDev); + ASSERT(prGlueInfo); + if (!prDev || !prGlueInfo) { + DBGLOG(INIT, WARN, + "abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, + prGlueInfo); + up(&g_halt_sem); + return; + } + + DBGLOG(INIT, INFO, "wlanSetMulticastListWorkQueue prDev->flags:0x%x\n", + prDev->flags); + + if (prDev->flags & IFF_PROMISC) { + u4PacketFilter |= PARAM_PACKET_FILTER_PROMISCUOUS; + } + + if (prDev->flags & IFF_BROADCAST) { + u4PacketFilter |= PARAM_PACKET_FILTER_BROADCAST; + } + + if (prDev->flags & IFF_MULTICAST) { + if ((prDev->flags & IFF_ALLMULTI) || + (netdev_mc_count(prDev) > MAX_NUM_GROUP_ADDR)) { + u4PacketFilter |= PARAM_PACKET_FILTER_ALL_MULTICAST; + } else { + u4PacketFilter |= PARAM_PACKET_FILTER_MULTICAST; + } + } + + up(&g_halt_sem); + + if (kalIoctl(prGlueInfo, wlanoidSetCurrentPacketFilter, &u4PacketFilter, + sizeof(u4PacketFilter), false, false, true, + &u4SetInfoLen) != WLAN_STATUS_SUCCESS) { + return; + } + + if (u4PacketFilter & PARAM_PACKET_FILTER_MULTICAST) { + /* Prepare multicast address list */ + struct netdev_hw_addr *ha; + u8 *prMCAddrList = NULL; + u32 i = 0; + + down(&g_halt_sem); + if (g_u4HaltFlag) { + up(&g_halt_sem); + return; + } + + prMCAddrList = kalMemAlloc(MAX_NUM_GROUP_ADDR * ETH_ALEN, VIR_MEM_TYPE); + + netdev_for_each_mc_addr(ha, prDev) { + if (i < MAX_NUM_GROUP_ADDR) { + kalMemCopy((prMCAddrList + i * ETH_ALEN), GET_ADDR(ha), + ETH_ALEN); + i++; + } + } + + up(&g_halt_sem); + + kalIoctl(prGlueInfo, wlanoidSetMulticastList, prMCAddrList, + (i * ETH_ALEN), false, false, true, &u4SetInfoLen); + + kalMemFree(prMCAddrList, VIR_MEM_TYPE, MAX_NUM_GROUP_ADDR * ETH_ALEN); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To indicate scheduled scan has been stopped + * + * \param[in] + * prGlueInfo + * + * \return + * None + */ +/*----------------------------------------------------------------------------*/ +void wlanSchedScanStoppedWorkQueue(struct work_struct *work) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + struct net_device *prDev = gPrDev; + + DBGLOG(SCN, INFO, "wlanSchedScanStoppedWorkQueue\n"); + prGlueInfo = (prDev != NULL) ? *((P_GLUE_INFO_T *)netdev_priv(prDev)) : + NULL; + if (!prGlueInfo) { + DBGLOG(SCN, INFO, "prGlueInfo == NULL unexpected\n"); + return; + } + + /* 2. indication to cfg80211 */ + /* 20150205 change cfg80211_sched_scan_stopped to work queue due to + * sched_scan_mtx dead lock issue */ +#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE + cfg80211_sched_scan_stopped(priv_to_wiphy(prGlueInfo), + prGlueInfo->prSchedScanRequest->reqid); +#else + cfg80211_sched_scan_stopped(priv_to_wiphy(prGlueInfo)); +#endif + DBGLOG( + SCN, INFO, + "cfg80211_sched_scan_stopped event send done WorkQueue thread return " + "from wlanSchedScanStoppedWorkQueue\n"); + return; +} + +void wlanSchedWDevLockWorkQueue(struct work_struct *work) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 7, 0)) + struct cfg80211_rx_assoc_resp_data resp = { + .uapsd_queues = -1, + }; +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + struct cfg80211_rx_assoc_resp resp = { + .uapsd_queues = -1, + }; +#endif + QUE_T rTempQue; + P_GLUE_INFO_T prGlueInfo = NULL; + struct net_device *prDev = gPrDev; + P_PARAM_WDEV_LOCK_THREAD_T prParamWDevLock = NULL; + P_QUE_T prTempQue = &rTempQue; + + GLUE_SPIN_LOCK_DECLARATION(); + QUEUE_INITIALIZE(prTempQue); + + DBGLOG(REQ, INFO, "wlanSchedWDevLockWorkQueue\n"); + prGlueInfo = (prDev != NULL) ? *((P_GLUE_INFO_T *)netdev_priv(prDev)) : + NULL; + if (!prGlueInfo) { + DBGLOG(REQ, ERROR, "prGlueInfo == NULL unexpected\n"); + return; + } + + if (prGlueInfo->u4ReadyFlag == 0) { + DBGLOG(REQ, ERROR, "Adapter is not ready\n"); + return; + } + + while (QUEUE_IS_NOT_EMPTY(&prGlueInfo->prAdapter->rWDevLockQueue)) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_WDEV_LOCK); + QUEUE_MOVE_ALL(prTempQue, &prGlueInfo->prAdapter->rWDevLockQueue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_WDEV_LOCK); + + while (QUEUE_IS_NOT_EMPTY(prTempQue)) { + QUEUE_REMOVE_HEAD(prTempQue, prParamWDevLock, + P_PARAM_WDEV_LOCK_THREAD_T); + + if (prParamWDevLock == NULL) { + break; + } + + kalAcquireWDevMutex(prParamWDevLock->pDev); + switch (prParamWDevLock->fn) { + case CFG80211_RX_ASSOC_RESP: +#if (KERNEL_VERSION(6, 0, 0) <= CFG80211_VERSION_CODE) + resp.links[0].bss = prParamWDevLock->pBss; + resp.buf = prParamWDevLock->pFrameBuf; + resp.len = prParamWDevLock->frameLen; + resp.req_ies = prParamWDevLock->req_ies; + resp.req_ies_len = prParamWDevLock->req_ies_len; + + cfg80211_rx_assoc_resp(prParamWDevLock->pDev, &resp); +#elif (KERNEL_VERSION(5, 1, 0) <= CFG80211_VERSION_CODE) + cfg80211_rx_assoc_resp( + prParamWDevLock->pDev, prParamWDevLock->pBss, + prParamWDevLock->pFrameBuf, prParamWDevLock->frameLen, + prParamWDevLock->uapsd_queues, prParamWDevLock->req_ies, + prParamWDevLock->req_ies_len); +#else + cfg80211_rx_assoc_resp(prParamWDevLock->pDev, + prParamWDevLock->pBss, + prParamWDevLock->pFrameBuf, + prParamWDevLock->frameLen, + prParamWDevLock->uapsd_queues); +#endif + break; + + case CFG80211_RX_MLME_MGMT: + cfg80211_rx_mlme_mgmt(prParamWDevLock->pDev, + prParamWDevLock->pFrameBuf, + prParamWDevLock->frameLen); + break; + + case CFG80211_TX_MLME_MGMT: +#if (KERNEL_VERSION(5, 11, 0) <= CFG80211_VERSION_CODE) + cfg80211_tx_mlme_mgmt(prParamWDevLock->pDev, + prParamWDevLock->pFrameBuf, + prParamWDevLock->frameLen, false); +#else + cfg80211_tx_mlme_mgmt(prParamWDevLock->pDev, + prParamWDevLock->pFrameBuf, + prParamWDevLock->frameLen); +#endif + break; + + case CFG80211_ASSOC_TIMEOUT: +#if (KERNEL_VERSION(6, 0, 0) <= CFG80211_VERSION_CODE) + struct cfg80211_assoc_failure data = { + .timeout = true, + .bss[0] = prParamWDevLock->pBss, + }; + cfg80211_assoc_failure(prParamWDevLock->pDev, &data); +#else + cfg80211_assoc_timeout(prParamWDevLock->pDev, + prParamWDevLock->pBss); +#endif + break; + } + + kalReleaseWDevMutex(prParamWDevLock->pDev); + + if (prParamWDevLock->pFrameBuf) { + DBGLOG(REQ, TRACE, "Free pFrameBuf 0x%x\n", + prParamWDevLock->pFrameBuf); + if (prParamWDevLock->fgIsInterruptContext) { + kalMemFree(prParamWDevLock->pFrameBuf, PHY_MEM_TYPE, + prParamWDevLock->frameLen); + } else { + kalMemFree(prParamWDevLock->pFrameBuf, VIR_MEM_TYPE, + prParamWDevLock->frameLen); + } + + prParamWDevLock->pFrameBuf = NULL; + } + + DBGLOG(REQ, TRACE, "Release cfg80211_bss\n"); + if (prParamWDevLock->pBss) { + cfg80211_put_bss(priv_to_wiphy(prGlueInfo), + prParamWDevLock->pBss); + } + + DBGLOG(REQ, TRACE, "Free prParamWDevLock- 0x%x\n", prParamWDevLock); + + if (prParamWDevLock->fgIsInterruptContext) { + kalMemFree(prParamWDevLock, PHY_MEM_TYPE, + sizeof(PARAM_WDEV_LOCK_THREAD_T)); + } else { + kalMemFree(prParamWDevLock, VIR_MEM_TYPE, + sizeof(PARAM_WDEV_LOCK_THREAD_T)); + } + } + } + return; +} + +/* FIXME: Since we cannot sleep in the wlanSetMulticastList, we arrange + * another workqueue for sleeping. We don't want to block + * main_thread, so we can't let tx_thread to do this + */ +void p2pSetMulticastListWorkQueueWrapper(P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + if (!prGlueInfo) { + DBGLOG(INIT, WARN, "abnormal dev or skb: prGlueInfo(0x%p)\n", + prGlueInfo); + return; + } + + if (prGlueInfo->prAdapter->fgIsP2PRegistered) { + mtk_p2p_wext_set_Multicastlist(prGlueInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/* + * \brief This function is TX entry point of NET DEVICE. + * + * \param[in] prSkb Pointer of the sk_buff to be sent + * \param[in] prDev Pointer to struct net_device + * + * \retval NETDEV_TX_OK - on success. + * \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. + */ +/*----------------------------------------------------------------------------*/ +int wlanHardStartXmit(struct sk_buff *prSkb, struct net_device *prDev) +{ + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = + (P_NETDEV_PRIVATE_GLUE_INFO)NULL; + P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + u8 ucBssIndex; + + ASSERT(prSkb); + ASSERT(prDev); + ASSERT(prGlueInfo); + + prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(prDev); + ASSERT(prNetDevPrivate->prGlueInfo == prGlueInfo); + ucBssIndex = prNetDevPrivate->ucBssIdx; + + kalResetPacket(prGlueInfo, (P_NATIVE_PACKET)prSkb); + + if (kalHardStartXmit(prSkb, prDev, prGlueInfo, ucBssIndex) == + WLAN_STATUS_SUCCESS) { + /* Successfully enqueue to Tx queue */ + /* Successfully enqueue to Tx queue */ + } + + /* For Linux, we'll always return OK FLAG, because we'll free this skb + * by ourself */ + return NETDEV_TX_OK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A method of struct net_device, to get the network interface + * statistical information. + * + * Whenever an application needs to get statistics for the interface, this + * method is called. This happens, for example, when ifconfig or netstat -i is + * run. + * + * \param[in] prDev Pointer to struct net_device. + * + * \return net_device_stats buffer pointer. + */ +/*----------------------------------------------------------------------------*/ +struct net_device_stats *wlanGetStats(IN struct net_device *prDev) +{ + return (struct net_device_stats *)kalGetStats(prDev); +} + +void wlanDebugInit(void) +{ + u8 i; + /* Set the initial debug level of each module */ +#if DBG + for (i = 0; i < DBG_MODULE_NUM; i++) + aucDebugModule[i] = DBG_CLASS_MASK; /* enable all */ +#else +#ifdef CFG_DEFAULT_DBG_LEVEL + for (i = 0; i < DBG_MODULE_NUM; i++) + aucDebugModule[i] = CFG_DEFAULT_DBG_LEVEL | DBG_CLASS_INFO; + + /* aucDebugModule[DBG_QM_IDX] &= + * ~(DBG_CLASS_EVENT | DBG_CLASS_INFO | DBG_CLASS_WARN); + * aucDebugModule[DBG_RSN_IDX] &= + * ~(DBG_CLASS_EVENT | DBG_CLASS_INFO | DBG_CLASS_WARN); */ + +#else + for (i = 0; i < DBG_MODULE_NUM; i++) + aucDebugModule[i] = DBG_CLASS_ERROR | DBG_CLASS_WARN | DBG_CLASS_STATE | + DBG_CLASS_EVENT | DBG_CLASS_INFO; + aucDebugModule[DBG_TX_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_INFO); + aucDebugModule[DBG_RX_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_INFO); + aucDebugModule[DBG_REQ_IDX] &= ~(DBG_CLASS_EVENT | DBG_CLASS_INFO); + aucDebugModule[DBG_INTR_IDX] = 0; + aucDebugModule[DBG_MEM_IDX] = DBG_CLASS_ERROR | DBG_CLASS_WARN; + aucDebugModule[DBG_REQ_IDX] = DBG_CLASS_MASK; +#endif +#endif + + DBGLOG(INIT, INFO, "Reset ALL DBG module log level to DEFAULT!\n"); +} + +WLAN_STATUS wlanSetDebugLevel(IN u32 u4DbgIdx, IN u32 u4DbgMask) +{ + u32 u4Idx; + WLAN_STATUS fgStatus = WLAN_STATUS_SUCCESS; + + if (u4DbgIdx == DBG_ALL_MODULE_IDX) { + for (u4Idx = 0; u4Idx < DBG_MODULE_NUM; u4Idx++) + aucDebugModule[u4Idx] = (u8)u4DbgMask; + DBGLOG(INIT, INFO, "Set ALL DBG module log level to [0x%02x]\n", + u4DbgMask); + } else if (u4DbgIdx < DBG_MODULE_NUM) { + aucDebugModule[u4DbgIdx] = (u8)u4DbgMask; + DBGLOG(INIT, INFO, "Set DBG module[%u] log level to [0x%02x]\n", + u4DbgIdx, u4DbgMask); + } else { + fgStatus = WLAN_STATUS_FAILURE; + } + + return fgStatus; +} + +WLAN_STATUS wlanGetDebugLevel(IN u32 u4DbgIdx, OUT u32 *pu4DbgMask) +{ + if (u4DbgIdx < DBG_MODULE_NUM) { + *pu4DbgMask = aucDebugModule[u4DbgIdx]; + return WLAN_STATUS_SUCCESS; + } + + return WLAN_STATUS_FAILURE; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for prDev->init + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution of wlanInit succeeds. + * \retval -ENXIO No such device. + */ +/*----------------------------------------------------------------------------*/ +static int wlanInit(struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + if (!prDev) { + return -ENXIO; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + + INIT_DELAYED_WORK(&workq, wlanSetMulticastListWorkQueue); + INIT_DELAYED_WORK(&wdev_lock_workq, wlanSchedWDevLockWorkQueue); + INIT_DELAYED_WORK(&sched_workq, wlanSchedScanStoppedWorkQueue); + /* 20150205 work queue for sched_scan */ + +/* 20161024 init wow port setting */ +#if CFG_WOW_SUPPORT + kalWowInit(prGlueInfo); +#endif + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A method of struct net_device, to set the randomized mac address + * + * This method is called before Wifi Framework requests a new conenction with + * enabled feature "Connected Random Mac". + * + * \param[in] ndev Pointer to struct net_device. + * \param[in] addr Randomized Mac address passed from WIFI framework. + * + * \return int. + */ +/*----------------------------------------------------------------------------*/ +static int wlanSetMacAddress(struct net_device *ndev, void *addr) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + struct sockaddr *sa = NULL; + struct wireless_dev *wdev = NULL; + + DBGLOG(INIT, STATE, "[%s]\n", __func__); + /********************************************************************** + * Check if kernel passes valid data to us * + ********************************************************************** + */ + if (!ndev || !addr) { + DBGLOG(INIT, ERROR, "Set macaddr with ndev(%d) and addr(%d)\n", + (ndev == NULL) ? 0 : 1, (addr == NULL) ? 0 : 1); + return WLAN_STATUS_INVALID_DATA; + } + + sa = (struct sockaddr *)addr; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(ndev)); + prAdapter = prGlueInfo->prAdapter; + + if (!is_valid_ether_addr(sa->sa_data)) { + DBGLOG(INIT, ERROR, "Rejecting completely invalid MAC address\n"); + return WLAN_STATUS_INVALID_DATA; + } + + /********************************************************************** + * Block mac address changing if this setting is not for connection * + ********************************************************************** + */ + if (is_local_ether_addr(sa->sa_data)) { + wdev = ndev->ieee80211_ptr; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0)) + if (wdev->ssid_len > 0 || (wdev->current_bss)) { + DBGLOG(INIT, ERROR, + "Reject macaddr change due to ssid_len(%d) & bss(%d)\n", + wdev->ssid_len, (wdev->current_bss == NULL) ? 0 : 1); + return WLAN_STATUS_NOT_ACCEPTED; + } +#else + if (wdev->connected || + prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo.eCurrentState == AIS_STATE_LOOKING_FOR || + prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo.eCurrentState == AIS_STATE_REQ_CHANNEL_JOIN || + prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo.eCurrentState == AIS_STATE_JOIN) { + DBGLOG(INIT, ERROR, "Reject macaddr change due to connected(%d)\n", + wdev->connected); + return WLAN_STATUS_NOT_ACCEPTED; + } +#endif + } + + /********************************************************************** + * 1. Change OwnMacAddr which will be updated to FW through * + * rlmActivateNetwork later. * + * 2. Change dev_addr stored in kernel to notify framework that the * + * mac addr has been changed and what the new value is. * + ********************************************************************** + */ + //sa = (struct sockaddr *)addr; + //prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(ndev)); + //prAdapter = prGlueInfo->prAdapter; + + COPY_MAC_ADDR(prAdapter->prAisBssInfo->aucBSSID, sa->sa_data); +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + COPY_MAC_ADDR(prGlueInfo->prDevHandler->dev_addr, sa->sa_data); +#else + dev_addr_set(prGlueInfo->prDevHandler, sa->sa_data); +#endif + + /********************************************************************** + * 3. Set the MTU to 1408 for G12A patch * + ********************************************************************** + */ +#if CFG_MESON_G12A_PATCH + prGlueInfo->prDevHandler->mtu = 1408; +#endif + DBGLOG(INIT, STATE, "Set connect random macaddr to " MACSTR ".\n", + MAC2STR(prAdapter->prAisBssInfo->aucBSSID)); + + return WLAN_STATUS_SUCCESS; +} + +/*n---------------------------------------------------------------------------*/ +/*! + * \brief A function for prDev->open + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution of wlanOpen succeeds. + * \retval < 0 The execution of wlanOpen failed. + */ +/*----------------------------------------------------------------------------*/ +static int wlanOpen(struct net_device *prDev) +{ + ASSERT(prDev); + + netif_tx_start_all_queues(prDev); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for prDev->stop + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution of wlanStop succeeds. + * \retval < 0 The execution of wlanStop failed. + */ +/*----------------------------------------------------------------------------*/ +static int wlanStop(struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + struct cfg80211_scan_request *prScanRequest = NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + + if ((!prGlueInfo) || (prGlueInfo->u4ReadyFlag == 0)) { + DBGLOG(INIT, WARN, "driver is not ready\n"); + } else { + /* CFG80211 down, report to kernel directly and run normal + * scan abort procedure + */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if (prGlueInfo->prScanRequest) { + DBGLOG(INIT, INFO, "wlanStop abort scan!\n"); + kalCfg80211ScanDone(prGlueInfo->prScanRequest, true); + aisFsmStateAbort_SCAN(prGlueInfo->prAdapter); + prScanRequest = prGlueInfo->prScanRequest; + prGlueInfo->prScanRequest = NULL; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + } + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + /* zero clear old acs information */ + kalMemZero(&(prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo), + sizeof(prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo)); +#endif + + netif_tx_stop_all_queues(prDev); + + return 0; +} + +#if CFG_SUPPORT_SNIFFER +static int wlanMonOpen(struct net_device *prDev) +{ + ASSERT(prDev); + + netif_tx_start_all_queues(prDev); + + return 0; +} + +static int wlanMonStop(struct net_device *prDev) +{ + ASSERT(prDev); + + netif_tx_stop_all_queues(prDev); + + return 0; +} + +static const struct net_device_ops wlan_mon_netdev_ops = { + .ndo_open = wlanMonOpen, + .ndo_stop = wlanMonStop, +}; + +void wlanMonWorkHandler(struct work_struct *work) +{ + P_GLUE_INFO_T prGlueInfo; + + prGlueInfo = container_of(work, GLUE_INFO_T, monWork); + + if (prGlueInfo->fgIsEnableMon) { + if (prGlueInfo->prMonDevHandler) { + return; + } + + prGlueInfo->prMonDevHandler = alloc_netdev_mq( + sizeof(NETDEV_PRIVATE_GLUE_INFO), NIC_MONITOR_INF_NAME, + NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM); + + if (prGlueInfo->prMonDevHandler == NULL) { + DBGLOG( + INIT, ERROR, + "wlanMonWorkHandler: Allocated prMonDevHandler context FAIL.\n"); + return; + } + + ((P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(prGlueInfo->prMonDevHandler)) + ->prGlueInfo = prGlueInfo; + prGlueInfo->prMonDevHandler->type = ARPHRD_IEEE80211_RADIOTAP; + prGlueInfo->prMonDevHandler->netdev_ops = &wlan_mon_netdev_ops; + netif_carrier_off(prGlueInfo->prMonDevHandler); + netif_tx_stop_all_queues(prGlueInfo->prMonDevHandler); + kalResetStats(prGlueInfo->prMonDevHandler); + + if (register_netdev(prGlueInfo->prMonDevHandler) < 0) { + DBGLOG( + INIT, ERROR, + "wlanMonWorkHandler: Registered prMonDevHandler context FAIL.\n"); + free_netdev(prGlueInfo->prMonDevHandler); + prGlueInfo->prMonDevHandler = NULL; + } + DBGLOG( + INIT, INFO, + "wlanMonWorkHandler: Registered prMonDevHandler context DONE.\n"); + } else { + if (prGlueInfo->prMonDevHandler) { + unregister_netdev(prGlueInfo->prMonDevHandler); + prGlueInfo->prMonDevHandler = NULL; + DBGLOG( + INIT, INFO, + "wlanMonWorkHandler: unRegistered prMonDevHandler context DONE.\n"); + } + } +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Update Channel table for cfg80211 for Wi-Fi Direct based on current + * country code + * + * \param[in] prGlueInfo Pointer to glue info + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void wlanUpdateChannelTable(P_GLUE_INFO_T prGlueInfo) +{ + u8 i, j; + u8 ucNumOfChannel; + RF_CHANNEL_INFO_T aucChannelList[ARRAY_SIZE(mtk_2ghz_channels) + + ARRAY_SIZE(mtk_5ghz_channels)]; + + /* 1. Disable all channels */ + for (i = 0; i < ARRAY_SIZE(mtk_2ghz_channels); i++) { + mtk_2ghz_channels[i].flags |= IEEE80211_CHAN_DISABLED; + mtk_2ghz_channels[i].orig_flags |= IEEE80211_CHAN_DISABLED; + } + + for (i = 0; i < ARRAY_SIZE(mtk_5ghz_channels); i++) { + mtk_5ghz_channels[i].flags |= IEEE80211_CHAN_DISABLED; + mtk_5ghz_channels[i].orig_flags |= IEEE80211_CHAN_DISABLED; + } + + /* 2. Get current domain channel list */ + rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_NULL, false, + ARRAY_SIZE(mtk_2ghz_channels) + + ARRAY_SIZE(mtk_5ghz_channels), + &ucNumOfChannel, aucChannelList); + + /* 3. Enable specific channel based on domain channel list */ + for (i = 0; i < ucNumOfChannel; i++) { + switch (aucChannelList[i].eBand) { + case BAND_2G4: + for (j = 0; j < ARRAY_SIZE(mtk_2ghz_channels); j++) { + if (mtk_2ghz_channels[j].hw_value == + aucChannelList[i].ucChannelNum) { + mtk_2ghz_channels[j].flags &= ~IEEE80211_CHAN_DISABLED; + mtk_2ghz_channels[j].orig_flags &= ~IEEE80211_CHAN_DISABLED; + break; + } + } + break; + + case BAND_5G: + for (j = 0; j < ARRAY_SIZE(mtk_5ghz_channels); j++) { + if (mtk_5ghz_channels[j].hw_value == + aucChannelList[i].ucChannelNum) { + mtk_5ghz_channels[j].flags &= ~IEEE80211_CHAN_DISABLED; + mtk_5ghz_channels[j].orig_flags &= ~IEEE80211_CHAN_DISABLED; + break; + } + } + break; + + default: + DBGLOG(INIT, WARN, "Unknown band %d\n", aucChannelList[i].eBand); + break; + } + } +} +#if CFG_SUPPORT_SAP_DFS_CHANNEL +void wlanUpdateDfsChannelTable(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucChannel) +{ + u8 i, j; + u8 ucNumOfChannel; + RF_CHANNEL_INFO_T aucChannelList[ARRAY_SIZE(mtk_5ghz_channels)]; + + DBGLOG(INIT, TRACE, "ucChannel %u.\n", ucChannel); + + /* 1. Get current domain DFS channel list */ + rlmDomainGetDfsChnls(prGlueInfo->prAdapter, ARRAY_SIZE(mtk_5ghz_channels), + &ucNumOfChannel, aucChannelList); + + /* 2. Enable specific channel based on domain channel list */ + for (i = 0; i < ucNumOfChannel; i++) { + for (j = 0; j < ARRAY_SIZE(mtk_5ghz_channels); j++) { + if (aucChannelList[i].ucChannelNum != + mtk_5ghz_channels[j].hw_value) { + continue; + } + + if (aucChannelList[i].ucChannelNum == ucChannel) { + mtk_5ghz_channels[j].dfs_state = NL80211_DFS_AVAILABLE; + mtk_5ghz_channels[j].flags &= ~IEEE80211_CHAN_RADAR; + mtk_5ghz_channels[j].orig_flags &= ~IEEE80211_CHAN_RADAR; + DBGLOG(INIT, STATE, "ch (%d), force NL80211_DFS_AVAILABLE.\n", + ucChannel); + } else { + mtk_5ghz_channels[j].dfs_state = NL80211_DFS_USABLE; + mtk_5ghz_channels[j].flags |= IEEE80211_CHAN_RADAR; + mtk_5ghz_channels[j].orig_flags |= IEEE80211_CHAN_RADAR; + DBGLOG(INIT, TRACE, "ch (%d), force NL80211_DFS_USABLE.\n", + aucChannelList[i].ucChannelNum); + } + } + } +} +#endif +/*----------------------------------------------------------------------------*/ +/*! + * \brief Register the device to the kernel and return the index. + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution of wlanNetRegister succeeds. + * \retval < 0 The execution of wlanNetRegister failed. + */ +/*----------------------------------------------------------------------------*/ +static s32 wlanNetRegister(struct wireless_dev *prWdev) +{ + P_GLUE_INFO_T prGlueInfo; + s32 i4DevIdx = -1; + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = + (P_NETDEV_PRIVATE_GLUE_INFO)NULL; + + ASSERT(prWdev); + + do { + if (!prWdev) { + break; + } + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(prWdev->wiphy); + i4DevIdx = wlanGetDevIdx(prWdev->netdev); + if (i4DevIdx < 0) { + DBGLOG(INIT, ERROR, "net_device number exceeds!\n"); + break; + } + + if (register_netdev(prWdev->netdev) < 0) { + DBGLOG(INIT, ERROR, "Register net_device failed\n"); + wlanClearDevIdx(prWdev->netdev); + i4DevIdx = -1; + } + prNetDevPrivate = + (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(prGlueInfo->prDevHandler); + ASSERT(prNetDevPrivate->prGlueInfo == prGlueInfo); + prNetDevPrivate->ucBssIdx = + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; +#if CFG_ENABLE_UNIFY_WIPHY + prNetDevPrivate->ucIsP2p = false; +#endif + wlanBindBssIdxToNetInterface( + prGlueInfo, prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex, + (void *)prWdev->netdev); + + if (i4DevIdx != -1) { + prGlueInfo->fgIsRegistered = true; + } + } while (false); + + return i4DevIdx; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Unregister the device from the kernel + * + * \param[in] prWdev Pointer to struct net_device. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static void wlanNetUnregister(struct wireless_dev *prWdev) +{ + P_GLUE_INFO_T prGlueInfo; + + if (!prWdev) { + DBGLOG(INIT, ERROR, "wlanNetUnregister: The device context is NULL\n"); + return; + } + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(prWdev->wiphy); + + wlanClearDevIdx(prWdev->netdev); + unregister_netdev(prWdev->netdev); + + /* FIXME: Why not free_netdev()? */ + prGlueInfo->fgIsRegistered = false; + +#if CFG_SUPPORT_SNIFFER + if (prGlueInfo->prMonDevHandler) { + unregister_netdev(prGlueInfo->prMonDevHandler); + prGlueInfo->prMonDevHandler = NULL; + } + prGlueInfo->fgIsEnableMon = false; +#endif +} + +static const struct net_device_ops wlan_netdev_ops = { + .ndo_open = wlanOpen, + .ndo_stop = wlanStop, + .ndo_set_rx_mode = wlanSetMulticastList, + .ndo_get_stats = wlanGetStats, + .ndo_do_ioctl = wlanDoIOCTL, + .ndo_start_xmit = wlanHardStartXmit, + .ndo_init = wlanInit, + .ndo_select_queue = wlanSelectQueue, + //.ndo_set_mac_address = wlanSetMacAddress +}; + +#if CFG_ENABLE_UNIFY_WIPHY +const struct net_device_ops *wlanGetNdevOps(void) +{ + return &wlan_netdev_ops; +} +#endif + +static void wlanCreateWirelessDevice(void) +{ + struct wiphy *prWiphy = NULL; + struct wireless_dev *prWdev = NULL; + + /* 4 <1.1> Create wireless_dev */ + prWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!prWdev) { + DBGLOG(INIT, ERROR, + "Allocating memory to wireless_dev context failed\n"); + return; + } + /* 4 <1.2> Create wiphy */ +#if CFG_ENABLE_UNIFY_WIPHY + prWiphy = wiphy_new(&mtk_cfg_ops, sizeof(GLUE_INFO_T)); +#else + prWiphy = wiphy_new(&mtk_wlan_ops, sizeof(GLUE_INFO_T)); +#endif + + if (!prWiphy) { + DBGLOG(INIT, ERROR, "Allocating memory to wiphy device failed\n"); + goto free_wdev; + } + /* 4 <1.3> configure wireless_dev & wiphy */ + prWdev->iftype = NL80211_IFTYPE_STATION; + prWiphy->iface_combinations = p_mtk_iface_combinations_sta; + prWiphy->n_iface_combinations = mtk_iface_combinations_sta_num; + prWiphy->max_scan_ssids = CFG_SCAN_SSID_MAX_NUM; + prWiphy->max_scan_ie_len = 512; + prWiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_ADHOC); + prWiphy->bands[NL80211_BAND_2GHZ] = &mtk_band_2ghz; + prWiphy->bands[NL80211_BAND_5GHZ] = &mtk_band_5ghz; + prWiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + prWiphy->cipher_suites = (const u32 *)mtk_cipher_suites; + prWiphy->n_cipher_suites = ARRAY_SIZE(mtk_cipher_suites); + + /* CFG80211_VERSION_CODE >= 3.3 */ + prWiphy->flags = WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + + /* CFG80211_VERSION_CODE >= 3.2 */ +#if (CFG_SUPPORT_ROAMING == 1) + prWiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; +#endif + + prWiphy->regulatory_flags = REGULATORY_CUSTOM_REG; +#if (CFG_SUPPORT_DFS_MASTER == 1) + prWiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; +#endif + +#if CFG_SUPPORT_SAE + prWiphy->features |= NL80211_FEATURE_SAE; +#endif + + cfg80211_regd_set_wiphy(prWiphy); + +#if (CFG_SUPPORT_TDLS == 1) + TDLSEX_WIPHY_FLAGS_INIT(prWiphy->flags); +#endif + prWiphy->max_remain_on_channel_duration = 5000; + prWiphy->mgmt_stypes = mtk_cfg80211_ais_default_mgmt_stypes; + + /* 4 <1.4> wowlan support */ +#ifdef CONFIG_PM + prWiphy->wowlan = &mtk_wlan_wowlan_support; +#endif + +#ifdef CONFIG_CFG80211_WEXT + /* 4 <1.5> Use wireless extension to replace IOCTL */ +#if CFG_ENABLE_UNIFY_WIPHY + prWiphy->wext = NULL; +#else + prWiphy->wext = &wext_handler_def; +#endif +#endif + +#ifdef STA_P2P_MCC + prWiphy->iface_combinations = iface_comb_mcc; + prWiphy->n_iface_combinations = ARRAY_SIZE(iface_comb_mcc); + DBGLOG(INIT, INFO, "The num_different_channels is %d\n", + iface_comb_mcc[0].num_different_channels); +#endif + +#if CFG_ENABLE_UNIFY_WIPHY + prWiphy->iface_combinations = p_mtk_iface_combinations_p2p; + prWiphy->n_iface_combinations = mtk_iface_combinations_p2p_num; + prWiphy->interface_modes |= + BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_STATION); + prWiphy->software_iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); + prWiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAVE_AP_SME; + prWiphy->ap_sme_capa = 1; +#endif + + if (wiphy_register(prWiphy) < 0) { + DBGLOG(INIT, ERROR, "wiphy_register error\n"); + goto free_wiphy; + } + prWdev->wiphy = prWiphy; + gprWdev = prWdev; + DBGLOG(INIT, INFO, "create wireless device success\n"); + return; + +free_wiphy: + wiphy_free(prWiphy); +free_wdev: + kfree(prWdev); +} + +#if (CFG_ENABLE_UNIFY_WIPHY == 0) +static void wlanDestroyWirelessDevice(void) +{ + set_wiphy_dev(gprWdev->wiphy, NULL); + wiphy_unregister(gprWdev->wiphy); + wiphy_free(gprWdev->wiphy); + kfree(gprWdev); + gprWdev = NULL; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Destroy all wdev (including the P2P device), and unregister wiphy + * + * \param (none) + * + * \return (none) + * + */ +/*----------------------------------------------------------------------------*/ +#if CFG_ENABLE_UNIFY_WIPHY +static void wlanDestroyAllWdev(void) +{ + struct wiphy *wiphy = NULL; + int i = 0; + /* There is only one wiphy, avoid the double free the wiphy */ +#if CFG_ENABLE_WIFI_DIRECT + /* free P2P wdev */ + for (i = 0; i < KAL_P2P_NUM; i++) { + if (gprP2pRoleWdev[i] == NULL) { + continue; + } + if (gprP2pRoleWdev[i] == gprWdev) { /* This is AIS/AP Interface */ + continue; + } + if (gprP2pRoleWdev[i] == gprP2pWdev) { /* handle later */ + continue; + } + wiphy = gprP2pRoleWdev[i]->wiphy; + kfree(gprP2pRoleWdev[i]); + gprP2pRoleWdev[i] = NULL; + } + if (gprP2pWdev != NULL) { + /* In initWlan(), the gprP2pRoleWdev[0] is created & + * (gprP2pWdev = gprP2pRoleWdev[0]). + * But in the mtk_p2p_cfg80211_add_iface alloc new prWdev, + * and gprP2pRoleWdev[0]=prWdev. + * For (gprP2pWdev != gprP2pRoleWdev[0]), we must free + * gprP2pWdev & take care double free case. + */ + wiphy = gprP2pWdev->wiphy; + kfree(gprP2pWdev); + gprP2pWdev = NULL; + } +#endif + /* free AIS wdev */ + if (gprWdev) { + wiphy = gprWdev->wiphy; + kfree(gprWdev); + gprWdev = NULL; + } + /* unregister & free wiphy */ + if (wiphy) { + /* set_wiphy_dev(wiphy, NULL): set the wiphy->dev->parent = NULL + * The trunk-ce1 does this, but the trunk seems not. + */ + /* set_wiphy_dev(wiphy, NULL); */ + wiphy_unregister(wiphy); + wiphy_free(wiphy); + } +} +#endif /* CFG_ENABLE_UNIFY_WIPHY */ + +struct wireless_dev *wlanGetWirelessDevice(void) +{ + return gprWdev; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A method for creating Linux NET4 struct net_device object and the + * private data(prGlueInfo and prAdapter). Setup the IO address to the + * HIF. Assign the function pointer to the net_device object + * + * \param[in] pvData Memory address for the device + * + * \retval Not null The wireless_dev object. + * \retval NULL Fail to create wireless_dev object + */ +/*----------------------------------------------------------------------------*/ +static struct lock_class_key rSpinKey[SPIN_LOCK_NUM]; +static struct wireless_dev *wlanNetCreate(void *pvData, void *pvDriverData) +{ + struct wireless_dev *prWdev = gprWdev; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 i; + struct device *prDev; + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = + (P_NETDEV_PRIVATE_GLUE_INFO)NULL; + u8 *prInfName = NULL; +#if CFG_ENABLE_UNIFY_WIPHY + struct wiphy *prWiphy = NULL; +#endif + + if (prWdev == NULL) { + DBGLOG(INIT, ERROR, "No wireless dev exist, abort power on\n"); + return NULL; + } + +#if CFG_ENABLE_UNIFY_WIPHY + /* The gprWdev is created at initWlan() and isn't reset when the + * disconnection occur. That cause some issue. + */ + prWiphy = prWdev->wiphy; + memset(prWdev, 0, sizeof(struct wireless_dev)); + prWdev->wiphy = prWiphy; + prWdev->iftype = NL80211_IFTYPE_STATION; +#if (CFG_SUPPORT_SINGLE_SKU == 1) + /* XXX: ref from cfg80211_regd_set_wiphy(). + * The error case: Sometimes after unplug/plug usb, the wlan0 STA can't + * scan correctly (FW doesn't do scan). The usb_probe message: + * "mtk_reg_notify:(RLM ERROR) Invalid REG state happened. state = 0x6". + */ + rlmDomainResetCtrlInfo(true); +#endif +#endif + + /* 4 <1.3> co-relate wiphy & prDev */ + glGetDev(pvData, &prDev); + if (!prDev) { + DBGLOG(INIT, ERROR, "unable to get struct dev for wlan\n"); + } + set_wiphy_dev(prWdev->wiphy, prDev); + + /* 4 <2> Create Glue structure */ + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(prWdev->wiphy); + kalMemZero(prGlueInfo, sizeof(GLUE_INFO_T)); + + /* 4 <2.1> Create Adapter structure */ + prAdapter = (P_ADAPTER_T)wlanAdapterCreate(prGlueInfo); + + if (!prAdapter) { + DBGLOG(INIT, ERROR, "Allocating memory to adapter failed\n"); + goto netcreate_err; + } + + prAdapter->chip_info = ((struct hif_driver_data *)pvDriverData)->chip_info; + prGlueInfo->prAdapter = prAdapter; + + /* 4 <3> Initialize Glue structure */ + /* 4 <3.1> Create net device */ + +#ifdef CFG_DRIVER_INF_NAME_CHANGE + if (kalStrLen(gprifnamesta) > 0) { + prInfName = kalStrCat(gprifnamesta, "%d"); + DBGLOG(INIT, WARN, "Station ifname customized, use %s\n", prInfName); + } else +#endif + prInfName = NIC_INF_NAME; + + prGlueInfo->prDevHandler = alloc_netdev_mq(sizeof(NETDEV_PRIVATE_GLUE_INFO), + prInfName, NET_NAME_PREDICTABLE, + ether_setup, CFG_MAX_TXQ_NUM); + + if (!prGlueInfo->prDevHandler) { + DBGLOG(INIT, ERROR, "Allocating memory to net_device context failed\n"); + goto netcreate_err; + } + DBGLOG(INIT, INFO, "net_device prDev(0x%p) allocated\n", + prGlueInfo->prDevHandler); + + /* 4 <3.1.1> Initialize net device varaiables */ + + prNetDevPrivate = + (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(prGlueInfo->prDevHandler); + prNetDevPrivate->prGlueInfo = prGlueInfo; + + prGlueInfo->prDevHandler->needed_headroom += NIC_TX_HEAD_ROOM; + prGlueInfo->prDevHandler->netdev_ops = &wlan_netdev_ops; +#ifdef CONFIG_WIRELESS_EXT + prGlueInfo->prDevHandler->wireless_handlers = &wext_handler_def; +#endif + netif_carrier_off(prGlueInfo->prDevHandler); + netif_tx_stop_all_queues(prGlueInfo->prDevHandler); + kalResetStats(prGlueInfo->prDevHandler); + +#if CFG_SUPPORT_SNIFFER + INIT_WORK(&(prGlueInfo->monWork), wlanMonWorkHandler); +#endif + + /* 4 <3.1.2> co-relate with wiphy bi-directionally */ + prGlueInfo->prDevHandler->ieee80211_ptr = prWdev; + + prWdev->netdev = prGlueInfo->prDevHandler; + + /* 4 <3.1.3> co-relate net device & prDev */ + SET_NETDEV_DEV(prGlueInfo->prDevHandler, wiphy_dev(prWdev->wiphy)); + + /* 4 <3.1.4> set device to glue */ + prGlueInfo->prDev = prDev; + + /* 4 <3.2> Initialize glue variables */ + prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; + prGlueInfo->ePowerState = ParamDeviceStateD0; + prGlueInfo->fgIsRegistered = false; + prGlueInfo->prScanRequest = NULL; + prGlueInfo->prSchedScanRequest = NULL; + + init_completion(&prGlueInfo->rScanComp); + init_completion(&prGlueInfo->rHaltComp); + init_completion(&prGlueInfo->rPendComp); + init_completion(&prGlueInfo->rHifHaltComp); + init_completion(&prGlueInfo->rRxHaltComp); + + /* initialize timer for OID timeout checker */ + kalOsTimerInitialize(prGlueInfo, kalTimeoutHandler); + + for (i = 0; i < SPIN_LOCK_NUM; i++) { + spin_lock_init(&prGlueInfo->rSpinLock[i]); + lockdep_set_class(&prGlueInfo->rSpinLock[i], &rSpinKey[i]); + } + + for (i = 0; i < MUTEX_NUM; i++) + mutex_init(&prGlueInfo->arMutex[i]); + + /* initialize semaphore for ioctl */ + sema_init(&prGlueInfo->ioctl_sem, 1); + +#if CFG_SUPPORT_SDIO_READ_WRITE_PATTERN + /* initialize SDIO read-write pattern control */ + prGlueInfo->fgEnSdioTestPattern = false; + prGlueInfo->fgIsSdioTestInitialized = false; +#endif + + /* initialize semaphore for halt control */ + sema_init(&g_halt_sem, 1); + + /* 4 <8> Init Queues */ + init_waitqueue_head(&prGlueInfo->waitq); + QUEUE_INITIALIZE(&prGlueInfo->rCmdQueue); + prGlueInfo->i4TxPendingCmdNum = 0; + QUEUE_INITIALIZE(&prGlueInfo->rTxQueue); + glSetHifInfo(prGlueInfo, (unsigned long)pvData); + + /* main_thread is created in this function */ + init_waitqueue_head(&prGlueInfo->waitq_rx); + init_waitqueue_head(&prGlueInfo->waitq_hif); + + prGlueInfo->u4TxThreadPid = 0xffffffff; + prGlueInfo->u4RxThreadPid = 0xffffffff; + prGlueInfo->u4HifThreadPid = 0xffffffff; + + return prWdev; + +netcreate_err: + if (prAdapter != NULL) { + wlanAdapterDestroy(prAdapter); + prAdapter = NULL; + } + + if (prGlueInfo->prDevHandler != NULL) { + free_netdev(prGlueInfo->prDevHandler); + prGlueInfo->prDevHandler = NULL; + } + + return prWdev; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Destroying the struct net_device object and the private data. + * + * \param[in] prWdev Pointer to struct wireless_dev. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +static void wlanNetDestroy(struct wireless_dev *prWdev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prWdev); + + if (!prWdev) { + DBGLOG(INIT, ERROR, "The device context is NULL\n"); + return; + } + + /* prGlueInfo is allocated with net_device */ + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(prWdev->wiphy); + ASSERT(prGlueInfo); + + /* destroy kal OS timer */ + kalCancelTimer(prGlueInfo); + + glClearHifInfo(prGlueInfo); + + wlanAdapterDestroy(prGlueInfo->prAdapter); + prGlueInfo->prAdapter = NULL; + + /* Free net_device and private data, which are allocated by + * alloc_netdev(). + */ + free_netdev(prWdev->netdev); +} + +void wlanSetSuspendMode(P_GLUE_INFO_T prGlueInfo, u8 fgEnable) +{ + struct net_device *prDev = NULL; + + if (!prGlueInfo) { + return; + } + + prDev = prGlueInfo->prDevHandler; + if (!prDev) { + return; + } + +#if CFG_STR_DHCP_RENEW_OFFLOAD + wlanSetDhcpOffloadInfo(prGlueInfo, prDev, fgEnable); +#endif + + kalSetNetAddressFromInterface(prGlueInfo, prDev, fgEnable); + wlanNotifyFwSuspend(prGlueInfo, prDev, fgEnable); +} + +#if CFG_ENABLE_EARLY_SUSPEND +static struct early_suspend wlan_early_suspend_desc = { + .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN, +}; + +static void wlan_early_suspend(struct early_suspend *h) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + /* 4 <1> Sanity Check */ + if ((u4WlanDevNum == 0) && (u4WlanDevNum > CFG_MAX_WLAN_DEVICES)) { + DBGLOG(INIT, ERROR, "wlanLateResume u4WlanDevNum==0 invalid!!\n"); + return; + } + + prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; + if (!prDev) { + return; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + if (!prGlueInfo) { + return; + } + + DBGLOG(INIT, INFO, "********<%s>********\n", __func__); + + if (prGlueInfo->fgIsInSuspendMode == true) { + DBGLOG(INIT, INFO, "%s: Already in suspend mode, SKIP!\n", __func__); + return; + } + + prGlueInfo->fgIsInSuspendMode = true; + + wlanSetSuspendMode(prGlueInfo, true); + p2pSetSuspendMode(prGlueInfo, true); +} + +static void wlan_late_resume(struct early_suspend *h) +{ + struct net_device *prDev = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + /* 4 <1> Sanity Check */ + if ((u4WlanDevNum == 0) && (u4WlanDevNum > CFG_MAX_WLAN_DEVICES)) { + DBGLOG(INIT, ERROR, "wlanLateResume u4WlanDevNum==0 invalid!!\n"); + return; + } + + prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; + if (!prDev) { + return; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + if (!prGlueInfo) { + return; + } + + DBGLOG(INIT, INFO, "********<%s>********\n", __func__); + + if (prGlueInfo->fgIsInSuspendMode == false) { + DBGLOG(INIT, INFO, "%s: Not in suspend mode, SKIP!\n", __func__); + return; + } + + prGlueInfo->fgIsInSuspendMode = false; + + /* 4 <2> Set suspend mode for each network */ + wlanSetSuspendMode(prGlueInfo, false); + p2pSetSuspendMode(prGlueInfo, false); +} +#endif + +int set_p2p_mode_handler(struct net_device *netdev, + PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode) +{ + P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(netdev)); + PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + u8 ret = false; + + rSetP2P.u4Enable = p2pmode.u4Enable; + rSetP2P.u4Mode = p2pmode.u4Mode; + + if (!rSetP2P.u4Enable) { + p2pNetUnregister(prGlueInfo, false); + } + + if (((rSetP2P.u4Mode == RUNNING_DUAL_AP_MODE) || + (rSetP2P.u4Mode == RUNNING_P2P_AP_MODE)) && + (gprP2pRoleWdev[1] == NULL) && (rSetP2P.u4Enable)) { + glP2pCreateWirelessDevice(prGlueInfo); + ASSERT(gprP2pRoleWdev[1] != NULL); + } + + rWlanStatus = kalIoctl(prGlueInfo, wlanoidSetP2pMode, (void *)&rSetP2P, + sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T), false, false, + true, &u4BufLen); + + DBGLOG(INIT, INFO, "set_p2p_mode_handler ret = 0x%08lx\n", + (u32)rWlanStatus); + + if ((rSetP2P.u4Enable) && (prGlueInfo->prAdapter->fgIsP2PRegistered)) { + ret = p2pNetRegister(prGlueInfo, false); + } + +#if 0 + if (ret == true) { + return 0; + }else{ + return -1; + } + +#else + return 0; + +#endif +} + +#if CFG_SUPPORT_EASY_DEBUG +/*----------------------------------------------------------------------------*/ +/*! + * \brief parse config from wifi.cfg + * + * \param[in] prAdapter + * + * \retval void + */ +/*----------------------------------------------------------------------------*/ +void wlanGetParseConfig(P_ADAPTER_T prAdapter) +{ + s32 ret; + u8 *pucConfigBuf; + u32 u4ConfigReadLen; + + wlanCfgInit(prAdapter, NULL, 0, 0); + pucConfigBuf = (u8 *)kalMemAlloc(WLAN_CFG_FILE_BUF_SIZE, VIR_MEM_TYPE); + kalMemZero(pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE); + u4ConfigReadLen = 0; + if (pucConfigBuf) { + ret = kalRequestFirmware("wifi.cfg", pucConfigBuf, + WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen, + prAdapter->prGlueInfo->prDev); + if (ret) { + DBGLOG(INIT, ERROR, "Failed to get wifi.cfg to parse"); + } + + if (pucConfigBuf[0] != '\0' && u4ConfigReadLen > 0) { + wlanCfgParse(prAdapter, pucConfigBuf, u4ConfigReadLen, true); + } + + kalMemFree(pucConfigBuf, VIR_MEM_TYPE, WLAN_CFG_FILE_BUF_SIZE); + } +} + +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief get config from wifi.cfg + * + * \param[in] prAdapter + * + * \retval void + */ +/*----------------------------------------------------------------------------*/ +void wlanGetConfig(P_ADAPTER_T prAdapter) +{ + s32 ret; + u8 *pucConfigBuf; + u32 u4ConfigReadLen; + + wlanCfgInit(prAdapter, NULL, 0, 0); + pucConfigBuf = (u8 *)kalMemAlloc(WLAN_CFG_FILE_BUF_SIZE, VIR_MEM_TYPE); + kalMemZero(pucConfigBuf, WLAN_CFG_FILE_BUF_SIZE); + u4ConfigReadLen = 0; + if (pucConfigBuf) { + ret = kalRequestFirmware("wifi.cfg", pucConfigBuf, + WLAN_CFG_FILE_BUF_SIZE, &u4ConfigReadLen, + prAdapter->prGlueInfo->prDev); + if (ret) { + DBGLOG(INIT, ERROR, "Failed to get wifi.cfg"); + } + + if (pucConfigBuf[0] != '\0' && u4ConfigReadLen > 0) { + wlanCfgInit(prAdapter, pucConfigBuf, u4ConfigReadLen, 0); + } + + kalMemFree(pucConfigBuf, VIR_MEM_TYPE, WLAN_CFG_FILE_BUF_SIZE); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief this extract buffer bin EEPROB_MTxxxx.bin to temp buffer + * + * \param[in] prAdapter + * + * \retval WLAN_STATUS_SUCCESS Success + * \retval WLAN_STATUS_FAILURE Failed + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanExtractBufferBin(P_ADAPTER_T prAdapter) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u32 u4ContentLen; + u8 *pucConfigBuf = NULL; + struct chip_info *prChipInfo; + u32 chip_id; + u8 aucEeprom[32]; + WLAN_STATUS retWlanStat = WLAN_STATUS_FAILURE; + + DBGLOG(INIT, INFO, "Start Efuse Buffer Mode step0\n"); + DBGLOG(INIT, INFO, "ucEfuseBUfferModeCal is %x\n", + prAdapter->rWifiVar.ucEfuseBufferModeCal); + + prChipInfo = prAdapter->chip_info; + chip_id = prChipInfo->chip_id; + prGlueInfo = prAdapter->prGlueInfo; + + if (prGlueInfo == NULL || prGlueInfo->prDev == NULL) { + goto label_exit; + } + + DBGLOG(INIT, INFO, "Start Efuse Buffer Mode step1\n"); + + /* allocate memory for buffer mode info */ + if ((prAdapter->rWifiVar.ucEfuseBufferModeCal == LOAD_EEPROM_BIN) && + (prAdapter->fgIsBufferBinExtract == false)) { + DBGLOG(INIT, INFO, "Start Efuse Buffer Mode step2\n"); + /* Only in buffer mode need to access bin file */ + /* 1 <1> Load bin file*/ + pucConfigBuf = (u8 *)kalMemAlloc(MAX_EEPROM_BUFFER_SIZE, VIR_MEM_TYPE); + if (pucConfigBuf == NULL) { + goto label_exit; + } + + kalMemZero(pucConfigBuf, MAX_EEPROM_BUFFER_SIZE); + + /* 1 <2> Construct EEPROM binary name */ + kalMemZero(aucEeprom, sizeof(aucEeprom)); + + snprintf(aucEeprom, 32, "%s%x.bin", apucEepromName[0], chip_id); + + /* 1 <3> Request buffer bin */ + if (kalRequestFirmware(aucEeprom, pucConfigBuf, MAX_EEPROM_BUFFER_SIZE, + &u4ContentLen, prGlueInfo->prDev) == 0) { + DBGLOG(INIT, INFO, "request file done\n"); + } else { + DBGLOG(INIT, INFO, "can't find file\n"); + kalMemFree(pucConfigBuf, VIR_MEM_TYPE, MAX_EEPROM_BUFFER_SIZE); + goto label_exit; + } + + /* Update contents in local table */ + kalMemCopy(uacEEPROMImage, pucConfigBuf, MAX_EEPROM_BUFFER_SIZE); + + /* Free buffer */ + kalMemFree(pucConfigBuf, VIR_MEM_TYPE, MAX_EEPROM_BUFFER_SIZE); + + DBGLOG(INIT, INFO, "Start Efuse Buffer Mode step3\n"); + prAdapter->fgIsBufferBinExtract = true; + } + + retWlanStat = WLAN_STATUS_SUCCESS; + +label_exit: + + return retWlanStat; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief this function send buffer bin EEPROB_MTxxxx.bin to FW. + * + * \param[in] prAdapter + * + * \retval WLAN_STATUS_SUCCESS Success + * \retval WLAN_STATUS_FAILURE Failed + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS wlanDownloadBufferBin(P_ADAPTER_T prAdapter) +{ + P_GLUE_INFO_T prGlueInfo = NULL; +#if (CFG_FW_Report_Efuse_Address) + u16 u2InitAddr = prAdapter->u4EfuseStartAddress; +#else + u16 u2InitAddr = EFUSE_CONTENT_BUFFER_START; +#endif + u32 u4BufLen = 0; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + PARAM_CUSTOM_EFUSE_BUFFER_MODE_T *prSetEfuseBufModeInfo = NULL; + u32 u4ContentLen; + struct chip_info *prChipInfo; + u32 chip_id; + WLAN_STATUS retWlanStat = WLAN_STATUS_FAILURE; + s32 i4OidTimeout = -1; + +#if CFG_EFUSE_AUTO_MODE_SUPPORT + u32 u4Efuse_addr = 0; + u8 u4Index = 0; + PARAM_CUSTOM_ACCESS_EFUSE_T rAccessEfuseInfo; +#endif + + DBGLOG(INIT, INFO, "Start Efuse Buffer Mode ..\n"); + DBGLOG(INIT, INFO, "ucEfuseBUfferModeCal is %x\n", + prAdapter->rWifiVar.ucEfuseBufferModeCal); + + prChipInfo = prAdapter->chip_info; + chip_id = prChipInfo->chip_id; + prGlueInfo = prAdapter->prGlueInfo; + + if (prGlueInfo == NULL || prGlueInfo->prDev == NULL) { + goto label_exit; + } + + /* allocate memory for buffer mode info */ + prSetEfuseBufModeInfo = (PARAM_CUSTOM_EFUSE_BUFFER_MODE_T *)kalMemAlloc( + sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T), VIR_MEM_TYPE); + if (prSetEfuseBufModeInfo == NULL) { + goto label_exit; + } + kalMemZero(prSetEfuseBufModeInfo, sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T)); + +#if CFG_EFUSE_AUTO_MODE_SUPPORT + if (prAdapter->rWifiVar.ucEfuseBufferModeCal == LOAD_AUTO) { + kalMemSet(&rAccessEfuseInfo, 0, sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)); + rAccessEfuseInfo.u4Address = + (u4Efuse_addr / EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE; + u4Index = u4Efuse_addr % EFUSE_BLOCK_SIZE; + rStatus = kalIoctl(prGlueInfo, wlanoidQueryProcessAccessEfuseRead, + &rAccessEfuseInfo, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), true, true, + true, &u4BufLen); + if (prGlueInfo->prAdapter->aucEepromVaule[1] == EFUSE_AUTO_CHEK) { + prAdapter->rWifiVar.ucEfuseBufferModeCal = LOAD_EFUSE; + DBGLOG(INIT, STATE, "[EFUSE AUTO] EFUSE Mode\n"); + } else { + prAdapter->rWifiVar.ucEfuseBufferModeCal = LOAD_EEPROM_BIN; + DBGLOG(INIT, STATE, "[EFUSE AUTO] Buffer Mode\n"); + } + } +#endif + + if (prAdapter->rWifiVar.ucEfuseBufferModeCal == LOAD_EEPROM_BIN) { + /* Buffer mode */ + /* Only in buffer mode need to access bin file */ + if (wlanExtractBufferBin(prAdapter) != WLAN_STATUS_SUCCESS) { + goto label_exit; + } + + /* copy to the command buffer */ +#if (CFG_FW_Report_Efuse_Address) + u4ContentLen = (prAdapter->u4EfuseEndAddress) - + (prAdapter->u4EfuseStartAddress) + 1; +#else + u4ContentLen = EFUSE_CONTENT_BUFFER_SIZE; +#endif + if (u4ContentLen > MAX_EEPROM_BUFFER_SIZE) { + goto label_exit; + } + kalMemCopy(prSetEfuseBufModeInfo->aBinContent, + &uacEEPROMImage[u2InitAddr], u4ContentLen); + + prSetEfuseBufModeInfo->ucSourceMode = 1; + } else { + /* eFuse mode */ + /* Only need to tell FW the content from, contents are + * directly from efuse */ + prSetEfuseBufModeInfo->ucSourceMode = 0; + } + prSetEfuseBufModeInfo->ucCmdType = + 0x1 | (prAdapter->rWifiVar.ucCalTimingCtrl << 4); + prSetEfuseBufModeInfo->ucCount = 0xFF; /* ucCmdType 1 don't care + * the ucCount */ + + if (!prAdapter->rWifiVar.ucCalTimingCtrl) { + /* Full channel RF-cal mode. Need 6000ms */ + i4OidTimeout = 6000; + } + + rStatus = kalIoctlTimeout(prGlueInfo, wlanoidSetEfusBufferMode, + (void *)prSetEfuseBufModeInfo, + sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T), false, + true, true, i4OidTimeout, &u4BufLen); + + retWlanStat = WLAN_STATUS_SUCCESS; + +label_exit: + + /* free memory */ + if (prSetEfuseBufModeInfo != NULL) { + kalMemFree(prSetEfuseBufModeInfo, VIR_MEM_TYPE, + sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T)); + } + + return retWlanStat; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Wlan probe function. This function probes and initializes the device. + * + * \param[in] pvData data passed by bus driver init function + * sdio bus driver handle + * + * \retval 0 Success + * \retval negative value Failed + */ +/*----------------------------------------------------------------------------*/ +s32 wlanProbe(struct sdio_func *pvData, void *pvDriverData) +{ + enum ENUM_PROBE_FAIL_REASON { + BUS_INIT_FAIL, + NET_CREATE_FAIL, + BUS_SET_IRQ_FAIL, + ADAPTER_START_FAIL, + NET_REGISTER_FAIL, + PROC_INIT_FAIL, + FAIL_MET_INIT_PROCFS, + FAIL_REASON_NUM + } eFailReason; + + struct wireless_dev *prWdev = NULL; + P_WLANDEV_INFO_T prWlandevInfo = NULL; + s32 i4DevIdx = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4Status = 0; + u8 i, bRet = false; + P_REG_INFO_T prRegInfo; + +#if CFG_SUPPORT_REPLAY_DETECTION + u8 ucRpyDetectOffload; +#endif + + eFailReason = FAIL_REASON_NUM; + do { + /* 4 <1> Initialize the IO port of the interface */ + /* GeorgeKuo: pData has different meaning for _HIF_XXX: + * bus driver handle + */ + + DBGLOG(INIT, STATE, "enter wlanProbe\n"); + + bRet = glBusInit(pvData); + + /* Cannot get IO address from interface */ + if (bRet == false) { + DBGLOG(INIT, ERROR, "wlanProbe: glBusInit() fail\n"); + i4Status = -EIO; + eFailReason = BUS_INIT_FAIL; + break; + } + + /* 4 <2> Create network device, Adapter, KalInfo, + * prDevHandler(netdev) */ + prWdev = wlanNetCreate(pvData, pvDriverData); + if (prWdev == NULL) { + DBGLOG(INIT, ERROR, + "wlanProbe: No memory for dev and its private\n"); + i4Status = -ENOMEM; + eFailReason = NET_CREATE_FAIL; + break; + } + + DBGLOG(INIT, STATE, "wlanNetCreate done\n"); + + /* 4 <2.5> Set the ioaddr to HIF Info */ + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(prWdev->wiphy); + if (prGlueInfo == NULL) { + DBGLOG(INIT, ERROR, "wlanProbe: get wiphy_priv() fail\n"); + return -1; + } + + gPrDev = prGlueInfo->prDevHandler; + + /* 4 <4> Setup IRQ */ + prWlandevInfo = &arWlanDevInfo[i4DevIdx]; + + i4Status = glBusSetIrq(prWdev->netdev, NULL, prGlueInfo); + + if (i4Status != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "wlanProbe: Set IRQ error\n"); + eFailReason = BUS_SET_IRQ_FAIL; + return -1; + } + + prGlueInfo->i4DevIdx = i4DevIdx; + + prAdapter = prGlueInfo->prAdapter; + + prGlueInfo->u4ReadyFlag = 0; + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + prAdapter->fgIsSupportCsumOffload = false; + prAdapter->u4CSUMFlags = CSUM_OFFLOAD_EN_ALL; +#endif + +#if CFG_SUPPORT_CFG_FILE + wlanGetConfig(prAdapter); +#endif + /* Default support 2.4/5G MIMO */ + prAdapter->rWifiFemCfg.u2WifiPath = + (WLAN_FLAG_2G4_WF0 | WLAN_FLAG_5G_WF0 | WLAN_FLAG_2G4_WF1 | + WLAN_FLAG_5G_WF1); + + DBGLOG(INIT, INFO, "WifiPath Init=0x%x\n", + prAdapter->rWifiFemCfg.u2WifiPath); + + /* 4 <5> Start Device */ + prRegInfo = &prGlueInfo->rRegInfo; + + /* P_REG_INFO_T prRegInfo = (P_REG_INFO_T) + * kmalloc(sizeof(REG_INFO_T), GFP_KERNEL); */ + kalMemSet(prRegInfo, 0, sizeof(REG_INFO_T)); + + /* Trigger the action of switching Pwr state to drv_own */ + prAdapter->fgIsFwOwn = true; + + nicpmWakeUpWiFi(prAdapter); + + /* Load NVRAM content to REG_INFO_T */ + glLoadNvram(prGlueInfo, prRegInfo); + + prRegInfo->u4PowerMode = CFG_INIT_POWER_SAVE_PROF; + + /* The Init value of u4WpaVersion/u4AuthAlg shall be + * DISABLE/OPEN, not zero! */ + /* The Init value of u4CipherGroup/u4CipherPairwise shall be + * NONE, not zero! */ + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; + + /*tasklet_init(&prGlueInfo->rRxTask, NULL, + (unsigned long)prGlueInfo); + tasklet_init(&prGlueInfo->rTxCompleteTask, NULL, + (unsigned long)prGlueInfo);*/ + + prGlueInfo->main_thread = NULL; + + DBGLOG(INIT, STATE, "wlanAdapterStart\n"); + if (wlanAdapterStart(prAdapter, prRegInfo) != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "%s: Init adapter failed!\n", + __func__); + i4Status = -EIO; + return -1; + } + + if (i4Status < 0) { + break; + } + + if (HAL_IS_TX_DIRECT(prAdapter)) { + if (!prAdapter->fgTxDirectInited) { + skb_queue_head_init(&prAdapter->rTxDirectSkbQueue); +#if KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE + timer_setup(&prAdapter->rTxDirectSkbTimer, + nicTxDirectTimerCheckSkbQ, 0); + timer_setup(&prAdapter->rTxDirectHifTimer, + nicTxDirectTimerCheckHifQ, 0); +#else + init_timer(&prAdapter->rTxDirectSkbTimer); + prAdapter->rTxDirectSkbTimer.data = (unsigned long)prGlueInfo; + prAdapter->rTxDirectSkbTimer.function = + nicTxDirectTimerCheckSkbQ; + + init_timer(&prAdapter->rTxDirectHifTimer); + prAdapter->rTxDirectHifTimer.data = (unsigned long)prGlueInfo; + prAdapter->rTxDirectHifTimer.function = + nicTxDirectTimerCheckHifQ; +#endif + + prAdapter->fgTxDirectInited = true; + } + } + + /* kfree(prRegInfo); */ + if (i4Status < 0) { + eFailReason = ADAPTER_START_FAIL; + break; + } + + DBGLOG(INIT, STATE, "starting wlan threads ...\n"); + INIT_WORK(&prGlueInfo->rTxMsduFreeWork, kalFreeTxMsduWorker); + INIT_DELAYED_WORK(&prGlueInfo->rRxPktDeAggWork, halDeAggRxPktWorker); + + prGlueInfo->main_thread = kthread_run( + main_thread, prGlueInfo->prDevHandler, "mt7668s_main_thread"); + prGlueInfo->hif_thread = kthread_run( + hif_thread, prGlueInfo->prDevHandler, "mt7668s_hif_thread"); + prGlueInfo->rx_thread = kthread_run(rx_thread, prGlueInfo->prDevHandler, + "mt7668s_rx_thread"); + + if (prGlueInfo->prAdapter->rWifiVar.ucThreadPriority > 0) { + const struct sched_param param = { + .sched_priority = + prGlueInfo->prAdapter->rWifiVar.ucThreadPriority + }; + int ret; + ret = kal_sched_set( + prGlueInfo->main_thread, + prGlueInfo->prAdapter->rWifiVar.ucThreadScheduling, ¶m, + prGlueInfo->prAdapter->rWifiVar.cThreadNice); + if (ret) { + return ret; + } + + ret = kal_sched_set( + prGlueInfo->hif_thread, + prGlueInfo->prAdapter->rWifiVar.ucThreadScheduling, ¶m, + prGlueInfo->prAdapter->rWifiVar.cThreadNice); + if (ret) { + return ret; + } + + ret = kal_sched_set( + prGlueInfo->rx_thread, + prGlueInfo->prAdapter->rWifiVar.ucThreadScheduling, ¶m, + prGlueInfo->prAdapter->rWifiVar.cThreadNice); + if (ret) { + return ret; + } + + DBGLOG(INIT, INFO, "Set pri = %d, sched = %d\n", + prGlueInfo->prAdapter->rWifiVar.ucThreadPriority, + prGlueInfo->prAdapter->rWifiVar.ucThreadScheduling); + } + + /* Disable 5G band for AIS */ + if (prAdapter->fgEnable5GBand == false) { + prWdev->wiphy->bands[NL80211_BAND_5GHZ] = NULL; + } + + g_u4HaltFlag = 0; + +#if CFG_SUPPORT_BUFFER_MODE +#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1) + if (wlanDownloadBufferBin(prAdapter) != WLAN_STATUS_SUCCESS) { + i4Status = -EIO; + DBGLOG(INIT, ERROR, "wlanProbe: wlanDownloadBufferBin() failed\n"); + break; + } +#endif +#endif + + /* send regulatory information to firmware */ + rlmDomainSendInfoToFirmware(prGlueInfo->prAdapter); + + /* set MAC address */ + { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + struct sockaddr MacAddr; + u32 u4SetInfoLen = 0; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryCurrentAddr, + &MacAddr.sa_data, PARAM_MAC_ADDR_LEN, true, true, + true, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, WARN, "set MAC addr fail 0x%lx go to probe fail\n", + rStatus); + // prGlueInfo->u4ReadyFlag = 0; + i4Status = -ENXIO; + break; + } else { +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + kalMemCopy(prGlueInfo->prDevHandler->dev_addr, &MacAddr.sa_data, + ETH_ALEN); +#else + dev_addr_set(prGlueInfo->prDevHandler, + prAdapter->rWifiVar.aucMacAddress); +#endif + kalMemCopy(prGlueInfo->prDevHandler->perm_addr, + prGlueInfo->prDevHandler->dev_addr, ETH_ALEN); +#if CFG_MESON_G12A_PATCH + prGlueInfo->prDevHandler->mtu = 1408; +#endif + + /* card is (yhpgi: not) ready */ + // prGlueInfo->u4ReadyFlag = 1; +#if CFG_SHOW_MACADDR_SOURCE + DBGLOG(INIT, INFO, "MAC address: " MACSTR, + MAC2STR(&MacAddr.sa_data)); +#endif + } + } + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + /* set HW checksum offload */ + if (prAdapter->fgIsSupportCsumOffload) { + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + u32 u4CSUMFlags = CSUM_OFFLOAD_EN_ALL; + u32 u4SetInfoLen = 0; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetCSUMOffload, + (void *)&u4CSUMFlags, sizeof(u32), false, false, + true, &u4SetInfoLen); + + if (rStatus == WLAN_STATUS_SUCCESS) { + prGlueInfo->prDevHandler->features = + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; + } else { + DBGLOG(INIT, WARN, + "set HW checksum offload fail 0x%lx go to probe fail\n", + rStatus); + prAdapter->fgIsSupportCsumOffload = false; + i4Status = -ENXIO; + break; + } + } +#endif + + DBGLOG(INIT, STATE, "wlanNetRegister\n"); + /* 4 <3> Register the card */ + i4DevIdx = wlanNetRegister(prWdev); + if (i4DevIdx < 0) { + i4Status = -ENXIO; + eFailReason = NET_REGISTER_FAIL; + DBGLOG( + INIT, ERROR, + "wlanProbe: Cannot register the net_device context to the kernel\n"); + break; + } + /* 4 <4> Register early suspend callback */ +#if CFG_ENABLE_EARLY_SUSPEND + glRegisterEarlySuspend(&wlan_early_suspend_desc, wlan_early_suspend, + wlan_late_resume); +#endif + + /* 4 <5> Register Notifier callback */ + wlanRegisterNotifier(); + + /* 4 <6> Initialize /proc filesystem */ +#if WLAN_INCLUDE_PROC + DBGLOG(INIT, STATE, "procCreateFsEntry\n"); + i4Status = procCreateFsEntry(prGlueInfo); + if (i4Status < 0) { + DBGLOG(INIT, ERROR, "wlanProbe: init procfs failed\n"); + break; + } +#endif + +#if CFG_MET_PACKET_TRACE_SUPPORT + kalMetInit(prGlueInfo); +#endif + +#if (CFG_ENABLE_WIFI_DIRECT) + if (prAdapter->rWifiVar.u4RegP2pIfAtProbe) { + PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; + + rSetP2P.u4Enable = 1; + +#ifdef CFG_DRIVER_INITIAL_RUNNING_MODE + rSetP2P.u4Mode = CFG_DRIVER_INITIAL_RUNNING_MODE; +#else + rSetP2P.u4Mode = RUNNING_P2P_MODE; +#endif + if (set_p2p_mode_handler(prWdev->netdev, rSetP2P) == 0) { + DBGLOG(INIT, STATE, "%s: p2p device registered\n", __func__); + } else { + DBGLOG(INIT, ERROR, "%s: Failed to register p2p device\n", + __func__); +#if 0 + i4Status = -ENXIO; + break; +#endif + } + } +#endif + + /* Configure 5G band for registered wiphy */ + if (prAdapter->fgEnable5GBand) { + prWdev->wiphy->bands[NL80211_BAND_5GHZ] = &mtk_band_5ghz; + } else { + prWdev->wiphy->bands[NL80211_BAND_5GHZ] = NULL; + } + + for (i = 0; i < KAL_P2P_NUM; i++) { + if (gprP2pRoleWdev[i] == NULL) { + continue; + } + + if (prAdapter->fgEnable5GBand) { + gprP2pRoleWdev[i]->wiphy->bands[NL80211_BAND_5GHZ] = + &mtk_band_5ghz; + } else { + gprP2pRoleWdev[i]->wiphy->bands[NL80211_BAND_5GHZ] = NULL; + } + } + } while (false); + + if (i4Status == 0) { + kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_ON, NULL, 0); + +#if CFG_SUPPORT_EASY_DEBUG + /* move before reading file + * wlanLoadDefaultCustomerSetting(prAdapter); + */ + + DBGLOG(INIT, STATE, "wlanFeatureToFw\n"); + wlanFeatureToFw(prGlueInfo->prAdapter); +#endif + wlanCfgSetSwCtrl(prGlueInfo->prAdapter); + wlanCfgSetChip(prGlueInfo->prAdapter); + wlanCfgSetCountryCode(prGlueInfo->prAdapter); + +#if CFG_SUPPORT_ANT_SELECT + /* update some info needed before connected */ + wlanUpdateExtInfo(prGlueInfo->prAdapter); +#endif + +#if CFG_SUPPORT_RSSI_COMP + wlanUpdateRssiComp(prGlueInfo->prAdapter); +#endif + +#if (CFG_MET_PACKET_TRACE_SUPPORT == 1) + DBGLOG(INIT, TRACE, "init MET procfs...\n"); + i4Status = kalMetInitProcfs(prGlueInfo); + if (i4Status < 0) { + DBGLOG(INIT, ERROR, "wlanProbe: init MET procfs failed\n"); + } +#endif + +#if CFG_SUPPORT_REPLAY_DETECTION + ucRpyDetectOffload = prAdapter->rWifiVar.ucRpyDetectOffload; + + if (ucRpyDetectOffload == FEATURE_ENABLED) { + DBGLOG(INIT, STATE, "CMD - Enable Replay Detection offload\n"); + wlanSuspendRekeyOffload(prAdapter->prGlueInfo, + GTK_REKEY_CMD_MODE_RPY_OFFLOAD_ON); + } else { + DBGLOG(INIT, STATE, "CMD - Disable Replay Detection offload\n"); + wlanSuspendRekeyOffload(prAdapter->prGlueInfo, + GTK_REKEY_CMD_MODE_RPY_OFFLOAD_OFF); + } +#endif + DBGLOG(INIT, STATE, "wlanProbe: probe success\n"); + set_bit(GLUE_FLAG_ADAPT_RDY_BIT, &prGlueInfo->ulFlag); + + /* card is ready */ + prGlueInfo->u4ReadyFlag = 1; + } else { + DBGLOG(INIT, ERROR, "wlanProbe: probe failed, reason:%d\n", + eFailReason); + switch (eFailReason) { + case FAIL_MET_INIT_PROCFS: + kalMetRemoveProcfs(prGlueInfo); + /* FALLTHRU */ + case PROC_INIT_FAIL: + wlanNetUnregister(prWdev); + /* FALLTHRU */ + case NET_REGISTER_FAIL: + set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag); + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + /* wait main thread stops */ + wait_for_completion_interruptible(&prGlueInfo->rHaltComp); + wlanAdapterStop(prAdapter); + /* fallthrough */ + case ADAPTER_START_FAIL: + glBusFreeIrq(prWdev->netdev, + *((P_GLUE_INFO_T *)netdev_priv(prWdev->netdev))); + /* fallthrough */ + case BUS_SET_IRQ_FAIL: + wlanNetDestroy(prWdev); + /* prGlueInfo->prAdapter is released in + * wlanNetDestroy + */ + /* Set NULL value for local prAdapter as well */ + prAdapter = NULL; + break; + case NET_CREATE_FAIL: + break; + case BUS_INIT_FAIL: + break; + default: + break; + } + } + + if (prWaitForResetComp) { + complete(prWaitForResetComp); + prWaitForResetComp = NULL; + } + + wlanRegisterRebootNotifier(); + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A method to stop driver operation and release all resources. Following + * this call, no frame should go up or down through this interface. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void wlanRemove(void) +{ + struct net_device *prDev = NULL; + P_WLANDEV_INFO_T prWlandevInfo = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u8 fgResult = false; + /* waitForResetCompInit is set to 0 during kernel module initialization + * and change to 1 only once at the 1st time wlanRemove() call in the + * module lifetime. This ensures prWaitForResetComp is initialized with + * init_completion() and all the subsequent calls will use + * reinit_completion() to reinit + */ + static u8 waitForResetCompInit = 0; + + DBGLOG(INIT, STATE, "Remove wlan!\n"); + + prWaitForResetComp = &rWaitForResetComp; + if (waitForResetCompInit) { + reinit_completion(prWaitForResetComp); + } else { + init_completion(prWaitForResetComp); + waitForResetCompInit = 1; + } + + /* 4 <0> Sanity check */ + ASSERT(u4WlanDevNum <= CFG_MAX_WLAN_DEVICES); + if (u4WlanDevNum == 0) { + DBGLOG(INIT, ERROR, "0 == u4WlanDevNum\n"); + return; + } + + if (u4WlanDevNum > 0 && u4WlanDevNum <= CFG_MAX_WLAN_DEVICES) { + prDev = arWlanDevInfo[u4WlanDevNum - 1].prDev; + prWlandevInfo = &arWlanDevInfo[u4WlanDevNum - 1]; + } + + ASSERT(prDev); + if (prDev == NULL) { + DBGLOG(INIT, ERROR, "NULL == prDev\n"); + return; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + ASSERT(prGlueInfo); + if (prGlueInfo == NULL) { + DBGLOG(INIT, ERROR, "NULL == prGlueInfo\n"); + free_netdev(prDev); + return; + } + + prGlueInfo->u4ReadyFlag = 0; + prAdapter = prGlueInfo->prAdapter; + + if (prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED) { + cfg80211_disconnected(prGlueInfo->prDevHandler, 0, NULL, 0, true, + GFP_KERNEL); + kalMsleep(500); + } + + DBGLOG(INIT, STATE, "flush workq\n"); + + flush_delayed_work(&workq); + flush_delayed_work(&wdev_lock_workq); + flush_delayed_work(&sched_workq); + + rtnl_lock(); + clear_bit(GLUE_FLAG_ADAPT_RDY_BIT, &prGlueInfo->ulFlag); + rtnl_unlock(); + + down(&g_halt_sem); + g_u4HaltFlag = 1; + up(&g_halt_sem); + + set_bit(GLUE_FLAG_HALT_BIT, &prGlueInfo->ulFlag); + + DBGLOG(INIT, STATE, "wlan thread stopping\n"); + + wake_up_interruptible(&prGlueInfo->waitq_hif); + wait_for_completion_interruptible_timeout(&prGlueInfo->rHifHaltComp, + SEC_TO_SYSTIME(15)); + wake_up_interruptible(&prGlueInfo->waitq_rx); + wait_for_completion_interruptible_timeout(&prGlueInfo->rRxHaltComp, + SEC_TO_SYSTIME(15)); + + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + /* wait main thread stops */ + wait_for_completion_interruptible_timeout(&prGlueInfo->rHaltComp, + SEC_TO_SYSTIME(15)); + + /* Stop works */ + flush_work(&prGlueInfo->rTxMsduFreeWork); + cancel_delayed_work_sync(&prGlueInfo->rRxPktDeAggWork); + + DBGLOG(INIT, STATE, "wlan thread stopped\n"); + + /* prGlueInfo->rHifInfo.main_thread = NULL; */ + prGlueInfo->main_thread = NULL; + prGlueInfo->hif_thread = NULL; + prGlueInfo->rx_thread = NULL; + + prGlueInfo->u4TxThreadPid = 0xffffffff; + prGlueInfo->u4HifThreadPid = 0xffffffff; + + if (HAL_IS_TX_DIRECT(prAdapter)) { + if (prAdapter->fgTxDirectInited) { + timer_delete_sync(&prAdapter->rTxDirectSkbTimer); + timer_delete_sync(&prAdapter->rTxDirectHifTimer); + } + } + + kalMemSet(&(prGlueInfo->prAdapter->rWlanInfo), 0, sizeof(WLAN_INFO_T)); + +#if CFG_ENABLE_WIFI_DIRECT + if (prGlueInfo->prAdapter->fgIsP2PRegistered) { + DBGLOG(INIT, STATE, "p2pNetUnregister...\n"); + p2pNetUnregister(prGlueInfo, false); + DBGLOG(INIT, STATE, "p2pRemove...\n"); + /*p2pRemove must before wlanAdapterStop */ + p2pRemove(prGlueInfo); + } +#endif + + /* 4 <3> Remove /proc filesystem. */ +#if WLAN_INCLUDE_PROC + procRemoveProcfs(); +#endif + +#if (CFG_MET_PACKET_TRACE_SUPPORT == 1) + kalMetRemoveProcfs(prGlueInfo); +#endif + + /* 4 <4> wlanAdapterStop */ + kalIndicateAgpsNotify(prAdapter, AGPS_EVENT_WLAN_OFF, NULL, 0); + + DBGLOG(INIT, STATE, "call wlanAdapterStop\n"); + wlanAdapterStop(prAdapter); + DBGLOG(INIT, INFO, "Number of Stalled Packets = %d\n", + GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum)); + + HAL_LP_OWN_SET(prAdapter, &fgResult); + DBGLOG(INIT, STATE, "HAL_LP_OWN_SET(%d)\n", fgResult); + + /* 4 <x> Stopping handling interrupt and free IRQ */ + glBusFreeIrq(prDev, prGlueInfo); + + DBGLOG(INIT, STATE, "call wlanNetUnregister\n"); + /* 4 <6> Unregister the card */ + wlanNetUnregister(prDev->ieee80211_ptr); + + DBGLOG(INIT, STATE, "call wlanNetDestroy\n"); + /* 4 <7> Destroy the device */ + wlanNetDestroy(prDev->ieee80211_ptr); + prDev = NULL; + + /* tasklet_kill(&prGlueInfo->rTxCompleteTask); + * tasklet_kill(&prGlueInfo->rRxTask); */ + + /* 4 <8> Unregister early suspend callback */ +#if CFG_ENABLE_EARLY_SUSPEND + DBGLOG(INIT, STATE, "call glUnregisterEarlySuspend\n"); + glUnregisterEarlySuspend(&wlan_early_suspend_desc); +#endif + + gprWdev->netdev = NULL; + + /* 4 <9> Unregister notifier callback */ + wlanUnregisterNotifier(); + + DBGLOG(INIT, STATE, "Remove wlan done\n"); +} + +static int mt76x8_wireless_init(void) +{ + int ret = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + + DBGLOG(INIT, STATE, "Initialize wireless Device\n"); + + /* memory pre-allocation */ +#if CFG_PRE_ALLOCATION_IO_BUFFER + kalInitIOBuffer(true); +#else + kalInitIOBuffer(false); +#endif + +#if WLAN_INCLUDE_PROC + procInitFs(); +#endif + + wlanCreateWirelessDevice(); + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(gprWdev->wiphy); + if (gprWdev) { + /* P2PDev and P2PRole[0] share the same Wdev */ + if (glP2pCreateWirelessDevice(prGlueInfo) == true) { + gprP2pWdev = gprP2pRoleWdev[0]; + } + } + + ret = ((glRegisterBus(wlanProbe, wlanRemove) == WLAN_STATUS_SUCCESS) ? + 0 : + -EIO); + + if (ret == -EIO) { + kalUninitIOBuffer(); + return ret; + } + + return ret; +} + +static void mt76x8_wireless_exit(void) +{ + DBGLOG(INIT, STATE, "wireless Device exit\n"); + + glUnregisterBus(wlanRemove); + /* free pre-allocated memory */ + kalUninitIOBuffer(); +#if CFG_ENABLE_UNIFY_WIPHY + wlanDestroyAllWdev(); +#else + wlanDestroyWirelessDevice(); + glP2pDestroyWirelessDevice(); +#endif +#if WLAN_INCLUDE_PROC + procUninitProcFs(); +#endif + wlanUnregisterRebootNotifier(); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Driver entry point when the driver is configured as a Linux Module, + * and is called once at module load time, by the user-level modutils + * application: insmod or modprobe. + * + * \retval 0 Success + */ +/*----------------------------------------------------------------------------*/ +/* 1 Module Entry Point */ +static int initWlan(void) +{ + int ret = 0; + +#ifdef CFG_DRIVER_INF_NAME_CHANGE + if (kalStrLen(gprifnamesta) > CUSTOM_IFNAMESIZ || + kalStrLen(gprifnamep2p) > CUSTOM_IFNAMESIZ || + kalStrLen(gprifnameap) > CUSTOM_IFNAMESIZ) { + DBGLOG(INIT, ERROR, "custom infname len illegal > %d\n", + CUSTOM_IFNAMESIZ); + return -EINVAL; + } +#endif + + wlanDebugInit(); + DBGLOG(INIT, STATE, "initWlan..\n"); + + mt76x8_wireless_init(); + DBGLOG(INIT, STATE, "initWlan end\n"); + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Driver exit point when the driver as a Linux Module is removed. Called + * at module unload time, by the user level modutils application: rmmod. + * This is our last chance to clean up after ourselves. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +/* 1 Module Leave Point */ +static void exitWlan(void) +{ + DBGLOG(INIT, STATE, "exitWlan\n"); + + if (prWaitForResetComp) { + wait_for_completion_interruptible_timeout(prWaitForResetComp, + SEC_TO_SYSTIME(5)); + } + + mt76x8_wireless_exit(); + DBGLOG(INIT, STATE, "exitWlan end\n"); +} + +static int mt7668s_reboot_notify(struct notifier_block *nb, unsigned long event, + void *unused) +{ + if (event == SYS_DOWN || event == SYS_RESTART || event == SYS_POWER_OFF) { + DBGLOG(HAL, STATE, + "Power down is detected. Cleaning MT7668S WiFi driver...\n"); + + glUnregisterBus(wlanRemove); + /* free pre-allocated memory */ + kalUninitIOBuffer(); +#if CFG_ENABLE_UNIFY_WIPHY + wlanDestroyAllWdev(); +#else + wlanDestroyWirelessDevice(); + glP2pDestroyWirelessDevice(); +#endif +#if WLAN_INCLUDE_PROC + procUninitProcFs(); +#endif + + DBGLOG(HAL, STATE, "Cleaning MT7668S WiFi driver Finish!\n"); + } + return 0; +} + +static struct notifier_block mt7668s_reboot_notifier = { + .notifier_call = mt7668s_reboot_notify, + .next = NULL, + .priority = __INT_MAX__, +}; + +void wlanRegisterRebootNotifier(void) +{ + register_reboot_notifier(&mt7668s_reboot_notifier); +} + +void wlanUnregisterRebootNotifier(void) +{ + unregister_reboot_notifier(&mt7668s_reboot_notifier); +} + +module_init(initWlan); +module_exit(exitWlan); diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_kal.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_kal.c new file mode 100644 index 00000000000000..86b7a617c1f311 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_kal.c @@ -0,0 +1,5930 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_kal.c + * \brief GLUE Layer will export the required procedures here for internal + * driver stack. + * + * This file contains all routines which are exported from GLUE Layer to + * internal driver stack. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include <linux/ctype.h> +#include <net/netlink.h> + +#include "gl_os.h" +#include "gl_kal.h" +#include "gl_wext.h" +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define FILE_NAME_MAX \ + CFG_FW_NAME_MAX_LEN /* the maximum length of a file name */ +#define FILE_NAME_TOTAL 8 /* the maximum number of all possible file name */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +#if DBG +int allocatedMemSize; +#endif + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +static void *pvIoBuffer; +static u32 pvIoBufferSize; +static u32 pvIoBufferUsage; + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#if CFG_ENABLE_FW_DOWNLOAD + +#define KUIDT_VALUE(v) (v.val) +#define KGIDT_VALUE(v) (v.val) + +const struct firmware *fw_entry; + +/* Default */ +static u8 *apucFwName[] = { (u8 *)CFG_FW_FILENAME "_MT", NULL }; + +static u8 *apucCr4FwName[] = { (u8 *)CFG_CR4_FW_FILENAME "_" HIF_NAME "_MT", + (u8 *)CFG_CR4_FW_FILENAME "_MT", NULL }; + +static u8 *apucPatchName[] = { (u8 *)"mt6632_patch_e1_hdr.bin", + (u8 *)"mt7666_patch_e1_hdr.bin", NULL }; + +#if !DBG_DISABLE_ALL_LOG +static u8 **appucFwNameTable[] = { apucFwName }; +#endif +#if CFG_ASSERT_DUMP +/* Core dump debug usage */ + +u8 *apucCorDumpN9FileName = "/tmp/FW_DUMP_N9"; +u8 *apucCorDumpCr4FileName = "/tmp/FW_DUMP_Cr4"; +#endif +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is provided by GLUE Layer for internal driver stack to + * open firmware image in kernel space + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * + * \retval WLAN_STATUS_SUCCESS. + * \retval WLAN_STATUS_FAILURE. + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS kalFirmwareOpen(IN P_GLUE_INFO_T prGlueInfo, IN u8 **apucNameTable) +{ + u8 ucNameIdx; + /* u8 ** apucNameTable; */ +#if !DBG_DISABLE_ALL_LOG + u8 ucMaxEcoVer = (sizeof(appucFwNameTable) / sizeof(u8 * *)); + u8 ucCurEcoVer = wlanGetEcoVersion(prGlueInfo->prAdapter); +#endif + u8 fgResult = false; + int ret; + + /* Try to open FW binary */ + for (ucNameIdx = 0; apucNameTable[ucNameIdx]; ucNameIdx++) { + /* + * Driver support request_firmware() to get files + * Android path: "/etc/firmware", "/vendor/firmware", + * "/firmware/image" Linux path: "/lib/firmware", + * "/lib/firmware/update" + */ + ret = REQUEST_FIRMWARE(&fw_entry, apucNameTable[ucNameIdx], + prGlueInfo->prDev); + + if (ret) { + DBGLOG(INIT, TRACE, + "Request FW image: %s failed, errno[%d]\n", + apucNameTable[ucNameIdx], fgResult); + RELEASE_FIRMWARE(fw_entry); + continue; + } else { + DBGLOG(INIT, TRACE, "Request FW image: %s done\n", + apucNameTable[ucNameIdx]); + fgResult = true; + break; + } + } + + /* Check result */ + if (!fgResult) { + goto error_open; + } + + return WLAN_STATUS_SUCCESS; + +error_open: + DBGLOG(INIT, ERROR, + "Request FW image failed! Cur/Max ECO Ver[E%u/E%u]\n", + ucCurEcoVer, ucMaxEcoVer); + + return WLAN_STATUS_FAILURE; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is provided by GLUE Layer for internal driver stack to + * release firmware image in kernel space + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * + * \retval WLAN_STATUS_SUCCESS. + * \retval WLAN_STATUS_FAILURE. + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS kalFirmwareClose(IN P_GLUE_INFO_T prGlueInfo) +{ + RELEASE_FIRMWARE(fw_entry); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is provided by GLUE Layer for internal driver stack to + * load firmware image in kernel space + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * + * \retval WLAN_STATUS_SUCCESS. + * \retval WLAN_STATUS_FAILURE. + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS kalFirmwareLoad(IN P_GLUE_INFO_T prGlueInfo, OUT void *prBuf, + IN u32 u4Offset, OUT u32 *pu4Size) +{ + ASSERT(prGlueInfo); + ASSERT(pu4Size); + ASSERT(prBuf); + + if ((fw_entry == NULL) || (fw_entry->size == 0) || + (fw_entry->data == NULL)) { + goto error_read; + } else { + memcpy(prBuf, fw_entry->data, fw_entry->size); + *pu4Size = fw_entry->size; + } + + return WLAN_STATUS_SUCCESS; + +error_read: + return WLAN_STATUS_FAILURE; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is provided by GLUE Layer for internal driver stack to + * query firmware image size in kernel space + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * + * \retval WLAN_STATUS_SUCCESS. + * \retval WLAN_STATUS_FAILURE. + * + */ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS kalFirmwareSize(IN P_GLUE_INFO_T prGlueInfo, OUT u32 *pu4Size) +{ + ASSERT(prGlueInfo); + ASSERT(pu4Size); + + *pu4Size = fw_entry->size; + + return WLAN_STATUS_SUCCESS; +} + +void kalConstructDefaultFirmwarePrio(P_GLUE_INFO_T prGlueInfo, + u8 **apucNameTable, u8 **apucName, + u8 *pucNameIdx, u8 ucMaxNameIdx) +{ + struct chip_info *prChipInfo = prGlueInfo->prAdapter->chip_info; + u32 chip_id = prChipInfo->chip_id; + u8 sub_idx = 0; + + for (sub_idx = 0; apucNameTable[sub_idx]; sub_idx++) { + if ((*pucNameIdx + 3) < ucMaxNameIdx) { + /* Type 1. WIFI_RAM_CODE_MTxxxx_Ex */ + snprintf(*(apucName + (*pucNameIdx)), FILE_NAME_MAX, + "%s%x_E%u", apucNameTable[sub_idx], chip_id, + wlanGetEcoVersion(prGlueInfo->prAdapter)); + (*pucNameIdx) += 1; + + /* Type 2. WIFI_RAM_CODE_MTxxxx_Ex.bin */ + snprintf(*(apucName + (*pucNameIdx)), FILE_NAME_MAX, + "%s%x_E%u.bin", apucNameTable[sub_idx], + chip_id, + wlanGetEcoVersion(prGlueInfo->prAdapter)); + (*pucNameIdx) += 1; + + /* Type 3. WIFI_RAM_CODE_MTxxxx */ + snprintf(*(apucName + (*pucNameIdx)), FILE_NAME_MAX, + "%s%x", apucNameTable[sub_idx], chip_id); + (*pucNameIdx) += 1; + + /* Type 4. WIFI_RAM_CODE_MTxxxx.bin */ + snprintf(*(apucName + (*pucNameIdx)), FILE_NAME_MAX, + "%s%x.bin", apucNameTable[sub_idx], chip_id); + (*pucNameIdx) += 1; + } else { + /* the table is not large enough */ + DBGLOG(INIT, + ERROR, + "kalFirmwareImageMapping >> file name array is not enough.\n"); + ASSERT(0); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to load firmware image + * + * \param pvGlueInfo Pointer of GLUE Data Structure + * \param ppvMapFileBuf Pointer of pointer to memory-mapped firmware image + * \param pu4FileLength File length and memory mapped length as well + * + * \retval Map File Handle, used for unammping + */ +/*----------------------------------------------------------------------------*/ + +void *kalFirmwareImageMapping(IN P_GLUE_INFO_T prGlueInfo, + OUT void **ppvMapFileBuf, OUT u32 *pu4FileLength, + IN ENUM_IMG_DL_IDX_T eDlIdx) +{ + u8 **apucNameTable = NULL; + u8 *apucName[FILE_NAME_TOTAL + 1]; /* extra +1, for the purpose of + * detecting the end of the array */ + u8 idx = 0, max_idx, ucRomVer = 0, + aucNameBody[FILE_NAME_TOTAL][FILE_NAME_MAX], sub_idx = 0; + struct chip_info *prChipInfo = prGlueInfo->prAdapter->chip_info; + u32 chip_id = prChipInfo->chip_id; + + DEBUGFUNC("kalFirmwareImageMapping"); + + ASSERT(prGlueInfo); + ASSERT(ppvMapFileBuf); + ASSERT(pu4FileLength); + + *ppvMapFileBuf = NULL; + *pu4FileLength = 0; + + do { + /* <0.0> Get FW name prefix table */ + switch (eDlIdx) { + case IMG_DL_IDX_N9_FW: + apucNameTable = apucFwName; + break; + + case IMG_DL_IDX_CR4_FW: + apucNameTable = apucCr4FwName; + break; + + case IMG_DL_IDX_PATCH: + apucNameTable = apucPatchName; + break; + + default: + ASSERT(0); + break; + } + + /* <0.2> Construct FW name */ + memset(apucName, 0, sizeof(apucName)); + + /* magic number 1: reservation for detection + * of the end of the array + */ + max_idx = (sizeof(apucName) / sizeof(u8 *)) - 1; + + idx = 0; + apucName[idx] = (u8 *)(aucNameBody + idx); + + if (eDlIdx == IMG_DL_IDX_PATCH) { + /* construct the file name for patch */ + + /* mtxxxx_patch_ex_hdr.bin*/ + ucRomVer = wlanGetRomVersion(prGlueInfo->prAdapter) + 1; + snprintf(apucName[idx], FILE_NAME_MAX, + "mt%x_patch_e%u_hdr.bin", chip_id, ucRomVer); + + idx += 1; + } else { + for (sub_idx = 0; sub_idx < max_idx; sub_idx++) + apucName[sub_idx] = + (u8 *)(aucNameBody + sub_idx); + + if (prChipInfo->constructFirmwarePrio) { + prChipInfo->constructFirmwarePrio( + prGlueInfo, apucNameTable, apucName, + &idx, max_idx); + } else { + kalConstructDefaultFirmwarePrio(prGlueInfo, + apucNameTable, + apucName, &idx, + max_idx); + } + } + + /* let the last pointer point to NULL + * so that we can detect the end of the array in + * kalFirmwareOpen(). + */ + apucName[idx] = NULL; + + apucNameTable = apucName; + + /* <1> Open firmware */ + if (kalFirmwareOpen(prGlueInfo, apucNameTable) != + WLAN_STATUS_SUCCESS) { + break; + } + { + u32 u4FwSize = 0; + void *prFwBuffer = NULL; + /* <2> Query firmare size */ + kalFirmwareSize(prGlueInfo, &u4FwSize); + /* <3> Use vmalloc for allocating large memory trunk */ + prFwBuffer = vmalloc(ALIGN_4(u4FwSize)); + /* <4> Load image binary into buffer */ + if (kalFirmwareLoad(prGlueInfo, prFwBuffer, 0, + &u4FwSize) != WLAN_STATUS_SUCCESS) { + vfree(prFwBuffer); + kalFirmwareClose(prGlueInfo); + break; + } + /* <5> write back info */ + *pu4FileLength = u4FwSize; + *ppvMapFileBuf = prFwBuffer; + + return prFwBuffer; + } + } while (false); + + return NULL; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to unload firmware image mapped memory + * + * \param pvGlueInfo Pointer of GLUE Data Structure + * \param pvFwHandle Pointer to mapping handle + * \param pvMapFileBuf Pointer to memory-mapped firmware image + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ + +void kalFirmwareImageUnmapping(IN P_GLUE_INFO_T prGlueInfo, IN void *prFwHandle, + IN void *pvMapFileBuf) +{ + DEBUGFUNC("kalFirmwareImageUnmapping"); + + ASSERT(prGlueInfo); + + /* pvMapFileBuf might be NULL when file doesn't exist */ + if (pvMapFileBuf) { + vfree(pvMapFileBuf); + } + + kalFirmwareClose(prGlueInfo); +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is provided by GLUE Layer for internal driver stack to + * acquire OS SPIN_LOCK. + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * \param[in] rLockCategory Specify which SPIN_LOCK + * \param[out] pu4Flags Pointer of a variable for saving IRQ flags + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void kalAcquireSpinLock(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, + OUT unsigned long *plFlags) +{ + unsigned long ulFlags = 0; + + ASSERT(prGlueInfo); + ASSERT(plFlags); + + if (rLockCategory < SPIN_LOCK_NUM) { + //DBGLOG(INIT, LOUD, "SPIN_LOCK[%u] Try to acquire\n", + // rLockCategory); +#if CFG_USE_SPIN_LOCK_BOTTOM_HALF + spin_lock_bh(&prGlueInfo->rSpinLock[rLockCategory]); +#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ + spin_lock_irqsave(&prGlueInfo->rSpinLock[rLockCategory], + ulFlags); +#endif + + *plFlags = ulFlags; + + //DBGLOG(INIT, LOUD, "SPIN_LOCK[%u] Acquired\n", rLockCategory); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is provided by GLUE Layer for internal driver stack to + * release OS SPIN_LOCK. + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * \param[in] rLockCategory Specify which SPIN_LOCK + * \param[in] u4Flags Saved IRQ flags + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void kalReleaseSpinLock(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, + IN unsigned long ulFlags) +{ + ASSERT(prGlueInfo); + + if (rLockCategory < SPIN_LOCK_NUM) { +#if CFG_USE_SPIN_LOCK_BOTTOM_HALF + spin_unlock_bh(&prGlueInfo->rSpinLock[rLockCategory]); +#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ + spin_unlock_irqrestore(&prGlueInfo->rSpinLock[rLockCategory], + ulFlags); +#endif + //DBGLOG(INIT, LOUD, "SPIN_UNLOCK[%u]\n", rLockCategory); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is provided by GLUE Layer for internal driver stack to + * acquire OS MUTEX. + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * \param[in] rMutexCategory Specify which MUTEX + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void kalAcquireMutex(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_MUTEX_CATEGORY_E rMutexCategory) +{ + ASSERT(prGlueInfo); + + if (rMutexCategory < MUTEX_NUM) { + DBGLOG(INIT, TRACE, "MUTEX_LOCK[%u] Try to acquire\n", + rMutexCategory); + mutex_lock(&prGlueInfo->arMutex[rMutexCategory]); + DBGLOG(INIT, TRACE, "MUTEX_LOCK[%u] Acquired\n", + rMutexCategory); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is provided by GLUE Layer for internal driver stack to + * release OS MUTEX. + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * \param[in] rMutexCategory Specify which MUTEX + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void kalReleaseMutex(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_MUTEX_CATEGORY_E rMutexCategory) +{ + ASSERT(prGlueInfo); + + if (rMutexCategory < MUTEX_NUM) { + mutex_unlock(&prGlueInfo->arMutex[rMutexCategory]); + DBGLOG(INIT, TRACE, "MUTEX_UNLOCK[%u]\n", rMutexCategory); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is provided by GLUE Layer for internal driver stack to + * acquire OS MUTEX for wdev. + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void kalAcquireWDevMutex(IN struct net_device *pDev) +{ + ASSERT(pDev); + + /* for user build */ + if (pDev == NULL) { + return; + } + + DBGLOG(INIT, TEMP, "WDEV_LOCK Try to acquire\n"); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0) + mutex_lock(&(pDev->ieee80211_ptr)->mtx); +#else + wiphy_lock(pDev->ieee80211_ptr->wiphy); +#endif + DBGLOG(INIT, TEMP, "WDEV_LOCK Acquired\n"); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is provided by GLUE Layer for internal driver stack to + * release OS MUTEXfor wdev. + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void kalReleaseWDevMutex(IN struct net_device *pDev) +{ + ASSERT(pDev); + + /* for user build */ + if (pDev == NULL) { + return; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0) + mutex_unlock(&(pDev->ieee80211_ptr)->mtx); +#else + wiphy_unlock(pDev->ieee80211_ptr->wiphy); +#endif + DBGLOG(INIT, TEMP, "WDEV_UNLOCK\n"); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is provided by GLUE Layer for internal driver stack to + * update current MAC address. + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * \param[in] pucMacAddr Pointer of current MAC address + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void kalUpdateMACAddress(IN P_GLUE_INFO_T prGlueInfo, IN u8 *pucMacAddr) +{ + ASSERT(prGlueInfo); + ASSERT(pucMacAddr); + + if (UNEQUAL_MAC_ADDR(prGlueInfo->prDevHandler->dev_addr, pucMacAddr)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + memcpy(prGlueInfo->prDevHandler->dev_addr, pucMacAddr, + PARAM_MAC_ADDR_LEN); +#else + dev_addr_set(prGlueInfo->prDevHandler, pucMacAddr); +#endif +#if CFG_MESON_G12A_PATCH + prGlueInfo->prDevHandler->mtu = 1408; +#endif + } +} + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +/*----------------------------------------------------------------------------*/ +/*! + * \brief To query the packet information for offload related parameters. + * + * \param[in] pvPacket Pointer to the packet descriptor. + * \param[in] pucFlag Points to the offload related parameter. + * + * \return (none) + * + */ +/*----------------------------------------------------------------------------*/ +void kalQueryTxChksumOffloadParam(IN void *pvPacket, OUT u8 *pucFlag) +{ + struct sk_buff *skb = (struct sk_buff *)pvPacket; + u8 ucFlag = 0; + + ASSERT(pvPacket); + ASSERT(pucFlag); + + if (skb->ip_summed == CHECKSUM_PARTIAL) { +#if DBG + /* Kevin: do double check, we can remove this part in Normal + * Driver. Because we register NIC feature with NETIF_F_IP_CSUM + * for MT5912B MAC, so we'll process IP packet only. + */ + if (skb->protocol != htons(ETH_P_IP)) { + } else +#endif + ucFlag |= (TX_CS_IP_GEN | TX_CS_TCP_UDP_GEN); + } + + *pucFlag = ucFlag; +} + +/* 4 2007/10/8, mikewu, this is rewritten by Mike */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief To update the checksum offload status to the packet to be indicated to + * OS. + * + * \param[in] pvPacket Pointer to the packet descriptor. + * \param[in] pucFlag Points to the offload related parameter. + * + * \return (none) + * + */ +/*----------------------------------------------------------------------------*/ +void kalUpdateRxCSUMOffloadParam(IN void *pvPacket, + IN ENUM_CSUM_RESULT_T aeCSUM[]) +{ + struct sk_buff *skb = (struct sk_buff *)pvPacket; + + ASSERT(pvPacket); + + if ((aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_SUCCESS || + aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_SUCCESS) && + ((aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_SUCCESS) || + (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_SUCCESS))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else { + skb->ip_summed = CHECKSUM_NONE; +#if DBG + if (aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_NONE && + aeCSUM[CSUM_TYPE_IPV6] == CSUM_RES_NONE) { + DBGLOG(RX, TRACE, "RX: \"non-IPv4/IPv6\" Packet\n"); + }else if (aeCSUM[CSUM_TYPE_IPV4] == CSUM_RES_FAILED) { + DBGLOG(RX, TRACE, "RX: \"bad IP Checksum\" Packet\n"); + }else if (aeCSUM[CSUM_TYPE_TCP] == CSUM_RES_FAILED) { + DBGLOG(RX, TRACE, "RX: \"bad TCP Checksum\" Packet\n"); + }else if (aeCSUM[CSUM_TYPE_UDP] == CSUM_RES_FAILED) { + DBGLOG(RX, TRACE, "RX: \"bad UDP Checksum\" Packet\n"); + } +#endif + } +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is called to free packet allocated from kalPacketAlloc. + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * \param[in] pvPacket Pointer of the packet descriptor + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void kalPacketFree(IN P_GLUE_INFO_T prGlueInfo, IN void *pvPacket) +{ + dev_kfree_skb((struct sk_buff *)pvPacket); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Only handles driver own creating packet (coalescing buffer). + * + * \param prGlueInfo Pointer of GLUE Data Structure + * \param u4Size Pointer of Packet Handle + * \param ppucData Status Code for OS upper layer + * + * \return NULL: Failed to allocate skb, Not NULL get skb + */ +/*----------------------------------------------------------------------------*/ +void *kalPacketAlloc(IN P_GLUE_INFO_T prGlueInfo, IN u32 u4Size, + OUT u8 **ppucData) +{ + struct sk_buff *prSkb; + + if (in_interrupt()) { + prSkb = __dev_alloc_skb(u4Size + NIC_TX_HEAD_ROOM, + GFP_ATOMIC | __GFP_NOWARN | + __GFP_NORETRY); + } else { + prSkb = __dev_alloc_skb(u4Size + NIC_TX_HEAD_ROOM, + GFP_KERNEL | __GFP_NORETRY); + } + + if (prSkb) { + skb_reserve(prSkb, NIC_TX_HEAD_ROOM); + + *ppucData = (u8 *)(prSkb->data); + + /* DBGLOG(TDLS, INFO, "kalPacketAlloc, skb head[0x%x] data[0x%x] + * tail[0x%x] end[0x%x]\n", prSkb->head, prSkb->data, + * prSkb->tail, prSkb->end); + */ + + kalResetPacket(prGlueInfo, (P_NATIVE_PACKET)prSkb); + } +#if DBG + { + u32 *pu4Head = (u32 *)&prSkb->cb[0]; + *pu4Head = (u32)prSkb->head; + DBGLOG(RX, TRACE, "prSkb->head = %#lx, prSkb->cb = %#lx\n", + (u32)prSkb->head, *pu4Head); + } +#endif + return (void *)prSkb; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Process the received packet for indicating to OS. + * + * \param[in] prGlueInfo Pointer to the Adapter structure. + * \param[in] pvPacket Pointer of the packet descriptor + * \param[in] pucPacketStart The starting address of the buffer of Rx packet. + * \param[in] u4PacketLen The packet length. + * \param[in] pfgIsRetain Is the packet to be retained. + * \param[in] aerCSUM The result of TCP/ IP checksum offload. + * + * \retval WLAN_STATUS_SUCCESS. + * \retval WLAN_STATUS_FAILURE. + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +kalProcessRxPacket(IN P_GLUE_INFO_T prGlueInfo, IN void *pvPacket, + IN u8 *pucPacketStart, IN u32 u4PacketLen, + IN ENUM_CSUM_RESULT_T aerCSUM[]) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + struct sk_buff *skb = (struct sk_buff *)pvPacket; + + skb->data = (unsigned char *)pucPacketStart; + + /* Reset skb */ + skb_reset_tail_pointer(skb); + skb_trim(skb, 0); + + /* Put data */ + skb_put(skb, u4PacketLen); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + if (prGlueInfo->prAdapter->fgIsSupportCsumOffload) { + kalUpdateRxCSUMOffloadParam(skb, aerCSUM); + } +#endif + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To indicate an array of received packets is available for higher + * level protocol uses. + * + * \param[in] prGlueInfo Pointer to the Adapter structure. + * \param[in] apvPkts The packet array to be indicated + * \param[in] ucPktNum The number of packets to be indicated + * + * \retval true Success. + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS kalRxIndicatePkts(IN P_GLUE_INFO_T prGlueInfo, IN void *apvPkts[], + IN u8 ucPktNum) +{ + u8 ucIdx = 0; + + ASSERT(prGlueInfo); + ASSERT(apvPkts); + + for (ucIdx = 0; ucIdx < ucPktNum; ucIdx++) + kalRxIndicateOnePkt(prGlueInfo, apvPkts[ucIdx]); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To indicate one received packets is available for higher + * level protocol uses. + * + * \param[in] prGlueInfo Pointer to the Adapter structure. + * \param[in] pvPkt The packet to be indicated + * + * \retval true Success. + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS kalRxIndicateOnePkt(IN P_GLUE_INFO_T prGlueInfo, IN void *pvPkt) +{ + struct net_device *prNetDev = prGlueInfo->prDevHandler; + struct sk_buff *prSkb = NULL; + struct chip_info *prChipInfo; + + ASSERT(prGlueInfo); + ASSERT(pvPkt); + + prSkb = pvPkt; + prChipInfo = prGlueInfo->prAdapter->chip_info; + + prNetDev = (struct net_device *)wlanGetNetInterfaceByBssIdx( + prGlueInfo, GLUE_GET_PKT_BSS_IDX(prSkb)); + if (!prNetDev) { + prNetDev = prGlueInfo->prDevHandler; + } +#if CFG_SUPPORT_SNIFFER + if (prGlueInfo->fgIsEnableMon) { + prNetDev = prGlueInfo->prMonDevHandler; + } +#endif + prNetDev->stats.rx_bytes += prSkb->len; + prNetDev->stats.rx_packets++; + +#if KERNEL_VERSION(4, 11, 0) > CFG80211_VERSION_CODE + prNetDev->last_rx = jiffies; +#endif +#if CFG_SUPPORT_SNIFFER + if (prGlueInfo->fgIsEnableMon) { + skb_reset_mac_header(prSkb); + prSkb->ip_summed = CHECKSUM_UNNECESSARY; + prSkb->pkt_type = PACKET_OTHERHOST; + prSkb->protocol = htons(ETH_P_802_2); + } else { + prSkb->protocol = eth_type_trans(prSkb, prNetDev); + } +#else + prSkb->protocol = eth_type_trans(prSkb, prNetDev); +#endif + prSkb->dev = prNetDev; + /* DBGLOG_MEM32(RX, TRACE, (u32 *)prSkb->data, prSkb->len); */ + /* DBGLOG(RX, EVENT, ("kalRxIndicatePkts len = %d\n", prSkb->len)); */ + if (prSkb->tail > prSkb->end) { + DBGLOG(RX, + ERROR, + "kalRxIndicateOnePkt [prSkb = 0x%p][prSkb->len = %d][prSkb->protocol = 0x%02X] %p,%p\n", + (u8 *)prSkb, + prSkb->len, + prSkb->protocol, + prSkb->tail, + prSkb->end); + DBGLOG_MEM32(RX, ERROR, (u32 *)prSkb->data, prSkb->len); + } + + if (prSkb->protocol == NTOHS(ETH_P_8021Q) && + !FEAT_SUP_LLC_VLAN_RX(prChipInfo)) { + /* + * DA-MAC + SA-MAC + 0x8100 was removed in eth_type_trans() + * pkt format here is TCI(2-bytes) + Len(2-btyes) + + * payload-type(2-bytes) + payload Remove "Len" field inserted + * by RX VLAN header translation Note: TCI+payload-type is a + * standard 8021Q header + * + * This format update is based on RX VLAN HW header + * translation. If the setting was changed, you may need to + * change rules here as well. + */ + const u8 vlan_skb_mem_move = 2; + + /* Remove "Len" and shift data pointer 2 bytes */ + kalMemCopy(prSkb->data + vlan_skb_mem_move, prSkb->data, + vlan_skb_mem_move); + skb_pull_rcsum(prSkb, vlan_skb_mem_move); + + /* Have to update MAC header properly. Otherwise, wrong MACs + * woud be passed up */ + kalMemMove(prSkb->data - ETH_HLEN, + prSkb->data - ETH_HLEN - vlan_skb_mem_move, + ETH_HLEN); + prSkb->mac_header += vlan_skb_mem_move; + + skb_reset_network_header(prSkb); + skb_reset_transport_header(prSkb); + kal_skb_reset_mac_len(prSkb); + } + + if (prSkb->protocol == HTONS(ETH_P_1X)) { + DBGLOG(RSN, WARN, "Rx EAPOL Frame [Len: %d]\n", prSkb->len); + } + +#if (KERNEL_VERSION(5, 18, 0) >= CFG80211_VERSION_CODE) + if (!in_interrupt()) { + netif_rx_ni(prSkb); /* only in non-interrupt context */ + }else{ + netif_rx(prSkb); + } +#else + netif_rx(prSkb); +#endif + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Called by driver to indicate event to upper layer, for example, the + * wpa supplicant or wireless tools. + * + * \param[in] pvAdapter Pointer to the adapter descriptor. + * \param[in] eStatus Indicated status. + * \param[in] pvBuf Indicated message buffer. + * \param[in] u4BufLen Indicated message buffer size. + * + * \return (none) + * + */ +/*----------------------------------------------------------------------------*/ +void kalIndicateStatusAndComplete(IN P_GLUE_INFO_T prGlueInfo, + IN WLAN_STATUS eStatus, IN void *pvBuf, + IN u32 u4BufLen) +{ + u32 bufLen; + P_PARAM_STATUS_INDICATION_T pStatus = + (P_PARAM_STATUS_INDICATION_T)pvBuf; + P_PARAM_AUTH_EVENT_T pAuth = (P_PARAM_AUTH_EVENT_T)pStatus; + P_PARAM_PMKID_CANDIDATE_LIST_T pPmkid = + (P_PARAM_PMKID_CANDIDATE_LIST_T)(pStatus + 1); + PARAM_MAC_ADDRESS arBssid; + struct cfg80211_scan_request *prScanRequest = NULL; + PARAM_SSID_T ssid; + struct ieee80211_channel *prChannel = NULL; + struct cfg80211_bss *bss; + u8 ucChannelNum; + P_BSS_DESC_T prBssDesc = NULL; + gfp_t flags = GFP_KERNEL; + + GLUE_SPIN_LOCK_DECLARATION(); + + kalMemZero(arBssid, MAC_ADDR_LEN); + + ASSERT(prGlueInfo); + + switch (eStatus) { + case WLAN_STATUS_ROAM_OUT_FIND_BEST: + case WLAN_STATUS_MEDIA_CONNECT: + + if (eStatus == WLAN_STATUS_MEDIA_CONNECT || eStatus == WLAN_STATUS_ROAM_OUT_FIND_BEST) { + if (prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED) { + DBGLOG(INIT, INFO, "FENCE DROP: Suppressing duplicate concurrent connect token.\n"); + return; + } + prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_CONNECTED; + } + + /* indicate assoc event */ + wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, + &arBssid[0], sizeof(arBssid), &bufLen); + wext_indicate_wext_event(prGlueInfo, SIOCGIWAP, arBssid, bufLen); + + DBGLOG(INIT, INFO, "Skip report CONNECTED when using supplicant SME\n"); + + /* Extract your over-the-air information elements */ + prBssDesc = ((P_AIS_FSM_INFO_T)(&(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo)))->prTargetBssDesc; + + if (prGlueInfo->prAdapter->prAisBssInfo != NULL) { + u8 ucTargetBssIdx = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + P_STA_RECORD_T prStaRec = cnmGetStaRecByAddress(prGlueInfo->prAdapter, ucTargetBssIdx, arBssid); + + if (prStaRec != NULL) { + cnmStaRecChangeState(prGlueInfo->prAdapter, prStaRec, STA_STATE_3); + qmSetStaRecTxAllowed(prGlueInfo->prAdapter, prStaRec, true); + prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo.eCurrentState = AIS_STATE_NORMAL_TR; + } + } + + /* switch netif on */ + netif_carrier_on(prGlueInfo->prDevHandler); + + if (prBssDesc != NULL && prBssDesc->u2IELength > 0) { + DBGLOG(INIT, INFO, "Syncing true Association IEs (%d bytes) to unblock 4-way encryption.\n", + prBssDesc->u2IELength); + + cfg80211_connect_result( + prGlueInfo->prDevHandler, + arBssid, + prBssDesc->aucIEBuf, // Feed the true over-the-air Request IEs + prBssDesc->u2IELength, + NULL, 0, // Response IEs can safely pass as empty + WLAN_STATUS_SUCCESS, + GFP_KERNEL + ); + } else + cfg80211_connect_result(prGlueInfo->prDevHandler, arBssid, NULL, 0, NULL, 0, WLAN_STATUS_SUCCESS, GFP_KERNEL); + return; + + do { + /* print message on console */ + wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQuerySsid, &ssid, + sizeof(ssid), &bufLen); + + ssid.aucSsid[(ssid.u4SsidLen >= PARAM_MAX_LEN_SSID) ? + (PARAM_MAX_LEN_SSID - 1) : + ssid.u4SsidLen] = '\0'; + DBGLOG(INIT, INFO, + "[wifi] %s netif_carrier_on [ssid:%s " MACSTR + "]\n", + prGlueInfo->prDevHandler->name, ssid.aucSsid, + MAC2STR(arBssid)); + } while (0); + + if (prGlueInfo->fgIsRegistered == true) { + /* retrieve channel */ + ucChannelNum = wlanGetChannelNumberByNetwork( + prGlueInfo->prAdapter, + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + if (ucChannelNum <= 14) { + prChannel = ieee80211_get_channel( + priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency( + ucChannelNum, + NL80211_BAND_2GHZ)); + } else { + prChannel = ieee80211_get_channel( + priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency( + ucChannelNum, + NL80211_BAND_5GHZ)); + } + + bss = cfg80211_get_bss(priv_to_wiphy(prGlueInfo), + prChannel, arBssid, ssid.aucSsid, + ssid.u4SsidLen, + IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_ANY); + if (bss == NULL) { +#if (BUILD_DBG_MSG == 1) + DBGLOG(INIT, + EVENT, + "Cannot get BSS from cfg80211 [ssid:%s]\n", + ssid.aucSsid); +#endif + /* create BSS on-the-fly */ + prBssDesc = + ((P_AIS_FSM_INFO_T)(&( + prGlueInfo-> + prAdapter-> + rWifiVar + .rAisFsmInfo))) + ->prTargetBssDesc; + + if (prChannel && prBssDesc != NULL) { + bss = cfg80211_inform_bss( + priv_to_wiphy(prGlueInfo), + prChannel, + CFG80211_BSS_FTYPE_PRESP, + arBssid, 0, /* TSF */ + prBssDesc->u2CapInfo, + prBssDesc->u2BeaconInterval, /* beacon + * interval */ + prBssDesc->aucIEBuf, /* IE */ + prBssDesc->u2IELength, /* IE + * Length + */ + RCPI_TO_dBm(prBssDesc->ucRCPI) * + 100, /* MBM */ + GFP_KERNEL); + } +#if (BUILD_DBG_MSG == 1) + if (bss == NULL) { + DBGLOG(INIT, + EVENT, + "cfg80211_inform_bss still failed\n"); + } +#endif + } + /* CFG80211 Indication */ + if (eStatus == WLAN_STATUS_ROAM_OUT_FIND_BEST) { + struct ieee80211_channel *prChannel = NULL; + u8 ucChannelNum = wlanGetChannelNumberByNetwork( + prGlueInfo->prAdapter, + prGlueInfo->prAdapter->prAisBssInfo + ->ucBssIndex); +#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE + struct cfg80211_roam_info rRoamInfo = {}; +#endif + if (ucChannelNum <= 14) { + prChannel = ieee80211_get_channel( + priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency( + ucChannelNum, + NL80211_BAND_2GHZ)); + } else { + prChannel = ieee80211_get_channel( + priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency( + ucChannelNum, + NL80211_BAND_5GHZ)); + } + +#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE + rRoamInfo.links[0].channel = prChannel; + rRoamInfo.links[0].bss = bss; + rRoamInfo.links[0].bssid = arBssid; + rRoamInfo.req_ie = prGlueInfo->aucReqIe; + rRoamInfo.req_ie_len = + prGlueInfo->u4RspIeLength; +#if ((KERNEL_VERSION(4, 13, 0) <= CFG80211_VERSION_CODE) && \ + (KERNEL_VERSION(4, 14, \ + 0) >= CFG80211_VERSION_CODE)) + rRoamInfo.authorized = false; +#endif + cfg80211_roamed(prGlueInfo->prDevHandler, + &rRoamInfo, GFP_KERNEL); +#else + cfg80211_roamed(prGlueInfo->prDevHandler, + prChannel, arBssid, + prGlueInfo->aucReqIe, + prGlueInfo->u4ReqIeLength, + prGlueInfo->aucRspIe, + prGlueInfo->u4RspIeLength, + GFP_KERNEL); +#endif + } + + /*20180418 frog: we get the bss, we need put it back. */ + if (bss) { + cfg80211_put_bss(priv_to_wiphy(prGlueInfo), + bss); + } + } + + break; + + case WLAN_STATUS_MEDIA_DISCONNECT: + case WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY: + /* indicate disassoc event */ + wext_indicate_wext_event(prGlueInfo, SIOCGIWAP, NULL, 0); + /* For CR 90 and CR99, While supplicant do reassociate, driver + * will do netif_carrier_off first, after associated success, at + * joinComplete(), do netif_carier_on, but for unknown reason, + * the supplicant 1x pkt will not called the driver + * hardStartXmit, for template workaround these bugs, add this + * compiling flag + */ + /* switch netif off */ + + if (prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_DISCONNECTED) { + DBGLOG(INIT, INFO, "FENCE DROP: Suppressing redundant trailing disconnect notification.\n"); + return; + } + + DBGLOG(INIT, INFO, "[wifi] %s netif_carrier_off\n", + prGlueInfo->prDevHandler->name); + + if (prGlueInfo->prAdapter->fgIsChipAssert) { + flags = GFP_ATOMIC; + } + + netif_carrier_off(prGlueInfo->prDevHandler); + + /* Report T/RX deauth/disassociation frame */ + DBGLOG(INIT, INFO, + "Skip report DISCONNECTED when using supplicant SME\n"); + + prGlueInfo->eParamMediaStateIndicated = + PARAM_MEDIA_STATE_DISCONNECTED; + + DBGLOG(INIT, INFO, "Reporting definitive DISCONNECTED event upstream to cfg80211.\n"); + + cfg80211_disconnected(prGlueInfo->prDevHandler, 3, NULL, 0, (eStatus == WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY) ? true : false, flags); + break; + + case WLAN_STATUS_SCAN_COMPLETE: + /* indicate scan complete event */ + wext_indicate_wext_event(prGlueInfo, SIOCGIWSCAN, NULL, 0); + + /* 1. reset first for newly incoming request */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if (prGlueInfo->prScanRequest != NULL) { + prScanRequest = prGlueInfo->prScanRequest; + prGlueInfo->prScanRequest = NULL; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + /* 2. then CFG80211 Indication */ + if (prScanRequest) { + kalCfg80211ScanDone(prScanRequest, false); + } + + break; + + case WLAN_STATUS_MEDIA_SPECIFIC_INDICATION: + if (pStatus) { + switch (pStatus->eStatusType) { + case ENUM_STATUS_TYPE_AUTHENTICATION: + /* + * printk(KERN_NOTICE + * "ENUM_STATUS_TYPE_AUTHENTICATION: L(%ld) [" + * MACSTR "] F:%lx\n", pAuth->Request[0].Length, + * MAC2STR(pAuth->Request[0].Bssid), + * pAuth->Request[0].Flags); + */ + /* indicate (UC/GC) MIC ERROR event only */ + if ((pAuth->arRequest[0].u4Flags == + PARAM_AUTH_REQUEST_PAIRWISE_ERROR) || + (pAuth->arRequest[0].u4Flags == + PARAM_AUTH_REQUEST_GROUP_ERROR)) { + cfg80211_michael_mic_failure( + prGlueInfo->prDevHandler, NULL, + (pAuth->arRequest[0].u4Flags == + PARAM_AUTH_REQUEST_PAIRWISE_ERROR) + ? + NL80211_KEYTYPE_PAIRWISE : + NL80211_KEYTYPE_GROUP, + 0, NULL, GFP_KERNEL); + wext_indicate_wext_event( + prGlueInfo, + IWEVMICHAELMICFAILURE, + (unsigned char *)&pAuth + ->arRequest[0], + pAuth->arRequest[0].u4Length); + } + break; + + case ENUM_STATUS_TYPE_CANDIDATE_LIST: + /* + * printk(KERN_NOTICE + * "Param_StatusType_PMKID_CandidateList: + * Ver(%ld) Num(%ld)\n", pPmkid->u2Version, + * pPmkid->u4NumCandidates); + * if (pPmkid->u4NumCandidates > 0) { + * printk(KERN_NOTICE "candidate[" MACSTR "] + * preAuth Flag:%lx\n", + * MAC2STR(pPmkid->arCandidateList[0].rBSSID), + * pPmkid->arCandidateList[0].fgFlags); + * } + */ + { + u32 i; + + for (i = 0; i < pPmkid->u4NumCandidates; + i++) { + wext_indicate_wext_event( + prGlueInfo, + IWEVPMKIDCAND, + (unsigned char *)&pPmkid + ->arCandidateList + [i], + pPmkid->u4NumCandidates); + } + } + break; + + default: + /* case ENUM_STATUS_TYPE_MEDIA_STREAM_MODE */ + /* + * printk(KERN_NOTICE "unknown media specific + * indication type:%x\n", pStatus->StatusType); + */ + break; + } + } else { + /* + * printk(KERN_WARNING "media specific indication + * buffer NULL\n"); + */ + } + break; + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS + case WLAN_STATUS_BWCS_UPDATE: { + wext_indicate_wext_event(prGlueInfo, IWEVCUSTOM, pvBuf, + sizeof(PTA_IPC_T)); + } + + break; + +#endif + case WLAN_STATUS_JOIN_TIMEOUT: + case WLAN_STATUS_JOIN_ABORT: { + P_BSS_DESC_T prBssDesc = prGlueInfo->prAdapter->rWifiVar + .rAisFsmInfo.prTargetBssDesc; + P_CONNECTION_SETTINGS_T prConnSettings = + &prGlueInfo->prAdapter->rWifiVar.rConnSettings; + DBGLOG(INIT, INFO, + "Skip report CONNECTED when using supplicant SME\n"); + + prGlueInfo->eParamMediaStateIndicated = PARAM_MEDIA_STATE_DISCONNECTED; + + if (prConnSettings->bss) { + kalWDevLockThread(prGlueInfo, prGlueInfo->prDevHandler, + CFG80211_ASSOC_TIMEOUT, + NULL, 0, prConnSettings->bss, 0, NULL, + 0, false); + + cfg80211_put_bss(priv_to_wiphy(prGlueInfo), + prConnSettings->bss); + prConnSettings->bss = NULL; + } + //return; + + if (prBssDesc) { + COPY_MAC_ADDR(arBssid, prBssDesc->aucBSSID); + } +#if 0 + cfg80211_connect_result(prGlueInfo->prDevHandler, arBssid, + prGlueInfo->aucReqIe, + prGlueInfo->u4ReqIeLength, + prGlueInfo->aucRspIe, + prGlueInfo->u4RspIeLength, + WLAN_STATUS_AUTH_TIMEOUT, GFP_KERNEL); +#endif + cfg80211_connect_result( + prGlueInfo->prDevHandler, + arBssid, + NULL, 0, // Clear Request IEs + NULL, 0, // Clear Response IEs + WLAN_STATUS_AUTH_TIMEOUT, // Inform kernel of the authentication failure + GFP_KERNEL + ); + } + return; + + case WLAN_STATUS_BEACON_TIMEOUT: + cfg80211_cqm_beacon_loss_notify(prGlueInfo->prDevHandler, + GFP_KERNEL); + break; + + case WLAN_STATUS_ASSOC_RESP: { + P_CONNECTION_SETTINGS_T prConnSettings = + &prGlueInfo->prAdapter->rWifiVar.rConnSettings; + + DBGLOG(INIT, INFO, + "Report ASSOC response frame when using supplicant SME\n"); + + if (prConnSettings->bss) { + u8 *prFrameBuf = NULL; + u8 fgIsInterruptContext = false; + + if (in_interrupt()) { + prFrameBuf = + kalMemAlloc(u4BufLen, PHY_MEM_TYPE); + fgIsInterruptContext = true; + } else { + prFrameBuf = + kalMemAlloc(u4BufLen, VIR_MEM_TYPE); + fgIsInterruptContext = false; + } + + if (!prFrameBuf) { + DBGLOG(INIT, ERROR, + "Alloc buffer for frame failed\n"); + return; + } + + kalMemCopy((void *)prFrameBuf, (void *)pvBuf, u4BufLen); + + kalWDevLockThread(prGlueInfo, prGlueInfo->prDevHandler, + CFG80211_RX_ASSOC_RESP, prFrameBuf, + u4BufLen, prConnSettings->bss, 0, + NULL, 0, fgIsInterruptContext); + + cfg80211_put_bss(priv_to_wiphy(prGlueInfo), + prConnSettings->bss); + + prConnSettings->bss = NULL; + } else { + DBGLOG(SAA, WARN, + "Rx Assoc Resp without specific BSS\n"); + } + break; + } + + default: + break; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to update the (re)association request + * information to the structure used to query and set + * OID_802_11_ASSOCIATION_INFORMATION. + * + * \param[in] prGlueInfo Pointer to the Glue structure. + * \param[in] pucFrameBody Pointer to the frame body of the last (Re)Association + * Request frame from the AP. + * \param[in] u4FrameBodyLen The length of the frame body of the last + * (Re)Association Request frame. + * \param[in] fgReassocRequest true, if it is a Reassociation Request frame. + * + * \return (none) + * + */ +/*----------------------------------------------------------------------------*/ +void kalUpdateReAssocReqInfo(IN P_GLUE_INFO_T prGlueInfo, + IN u8 *pucFrameBody, + IN u32 u4FrameBodyLen, IN u8 fgReassocRequest) +{ + u8 *cp; + + ASSERT(prGlueInfo); + + /* reset */ + prGlueInfo->u4ReqIeLength = 0; + + if (fgReassocRequest) { + if (u4FrameBodyLen < 15) { + /* + * printk(KERN_WARNING "frameBodyLen too short:%ld\n", + * frameBodyLen); + */ + return; + } + } else { + if (u4FrameBodyLen < 9) { + /* + * printk(KERN_WARNING "frameBodyLen too short:%ld\n", + * frameBodyLen); + */ + return; + } + } + + cp = pucFrameBody; + + if (fgReassocRequest) { + /* Capability information field 2 */ + /* Listen interval field 2 */ + /* Current AP address 6 */ + cp += 10; + u4FrameBodyLen -= 10; + } else { + /* Capability information field 2 */ + /* Listen interval field 2 */ + cp += 4; + u4FrameBodyLen -= 4; + } + + wext_indicate_wext_event(prGlueInfo, IWEVASSOCREQIE, cp, + u4FrameBodyLen); + + if (u4FrameBodyLen <= CFG_CFG80211_IE_BUF_LEN) { + prGlueInfo->u4ReqIeLength = u4FrameBodyLen; + kalMemCopy(prGlueInfo->aucReqIe, cp, u4FrameBodyLen); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is called to update the (re)association + * response information to the structure used to reply with + * cfg80211_connect_result + * + * @param prGlueInfo Pointer to adapter descriptor + * @param pucFrameBody Pointer to the frame body of the last (Re)Association + * Response frame from the AP + * @param u4FrameBodyLen The length of the frame body of the last + * (Re)Association Response frame + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void kalUpdateReAssocRspInfo(IN P_GLUE_INFO_T prGlueInfo, + IN u8 *pucFrameBody, + IN u32 u4FrameBodyLen) +{ + u32 u4IEOffset = 6; /* cap_info, status_code & assoc_id */ + u32 u4IELength = u4FrameBodyLen - u4IEOffset; + + ASSERT(prGlueInfo); + + /* reset */ + prGlueInfo->u4RspIeLength = 0; + + if (u4IELength <= CFG_CFG80211_IE_BUF_LEN) { + prGlueInfo->u4RspIeLength = u4IELength; + kalMemCopy(prGlueInfo->aucRspIe, pucFrameBody + u4IEOffset, + u4IELength); + } +} + +void kalResetPacket(IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket) +{ + struct sk_buff *prSkb = (struct sk_buff *)prPacket; + + /* Reset cb */ + kalMemZero(prSkb->cb, sizeof(prSkb->cb)); +} + +/*----------------------------------------------------------------------------*/ +/* + * \brief This function is to check the pairwise eapol and wapi 1x. + * + * \param[in] prPacket Pointer to struct net_device + * + * \retval WLAN_STATUS + */ +/*----------------------------------------------------------------------------*/ +u8 kalIsPairwiseEapolPacket(IN P_NATIVE_PACKET prPacket) +{ + struct sk_buff *prSkb = (struct sk_buff *)prPacket; + u8 *pucPacket = (u8 *)prSkb->data; + u16 u2EthType = 0; + u16 u2KeyInfo = 0; + + WLAN_GET_FIELD_BE16(&pucPacket[ETHER_HEADER_LEN - ETHER_TYPE_LEN], + &u2EthType); + + if (u2EthType != ETH_P_1X) { + return false; + } + + u2KeyInfo = pucPacket[5 + ETHER_HEADER_LEN] << 8 | + pucPacket[6 + ETHER_HEADER_LEN]; + + /* BIT3 is pairwise key bit, and check SM is 0. it means this is 4-way + * handshake frame */ + DBGLOG(RSN, INFO, "u2KeyInfo=%d\n", u2KeyInfo); + if ((u2KeyInfo & BIT(3)) && !(u2KeyInfo & BIT(13))) { + return true; + } + + return false; +} + +/*----------------------------------------------------------------------------*/ +/* + * \brief This function is TX entry point of NET DEVICE. + * + * \param[in] prSkb Pointer of the sk_buff to be sent + * \param[in] prDev Pointer to struct net_device + * \param[in] prGlueInfo Pointer of prGlueInfo + * \param[in] ucBssIndex BSS index of this net device + * + * \retval WLAN_STATUS + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +kalHardStartXmit(struct sk_buff *prOrgSkb, IN struct net_device *prDev, + P_GLUE_INFO_T prGlueInfo, u8 ucBssIndex) +{ + P_QUE_ENTRY_T prQueueEntry = NULL; + P_QUE_T prTxQueue = NULL; + u16 u2QueueIdx = 0; + u32 u4MaxTxPendingNum = prGlueInfo->prAdapter->rWifiVar.u4NetifStopTh; + struct sk_buff *prSkbNew = NULL; + struct sk_buff *prSkb = NULL; + + ASSERT(prOrgSkb); + ASSERT(prGlueInfo); + +#if CFG_MESON_G12A_PATCH + if (prOrgSkb->len > 1500) { + DBGLOG(INIT, INFO, "Packet is too BIG! [%d]\n", prOrgSkb->len); + } +#endif + + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + DBGLOG(INIT, INFO, "GLUE_FLAG_HALT skip tx\n"); + dev_kfree_skb(prOrgSkb); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + if (prGlueInfo->prAdapter->fgIsEnableLpdvt) { + DBGLOG(INIT, INFO, "LPDVT enable, skip this frame\n"); + dev_kfree_skb(prOrgSkb); + return WLAN_STATUS_NOT_ACCEPTED; + } + + if (skb_headroom(prOrgSkb) < NIC_TX_HEAD_ROOM) { + prSkbNew = skb_realloc_headroom(prOrgSkb, NIC_TX_HEAD_ROOM); + ASSERT(prSkbNew); + prSkb = prSkbNew; + dev_kfree_skb(prOrgSkb); + } else { + prSkb = prOrgSkb; + } + + prQueueEntry = (P_QUE_ENTRY_T)GLUE_GET_PKT_QUEUE_ENTRY(prSkb); + prTxQueue = &prGlueInfo->rTxQueue; + + GLUE_SET_PKT_BSS_IDX(prSkb, ucBssIndex); + + /* Parsing frame info */ + if (!wlanProcessTxFrame(prGlueInfo->prAdapter, + (P_NATIVE_PACKET)prSkb)) { + /* Cannot extract packet */ + DBGLOG(INIT, INFO, "Cannot extract content, skip this frame\n"); + dev_kfree_skb(prSkb); + return WLAN_STATUS_INVALID_PACKET; + } + + /* Tx profiling */ + wlanTxProfilingTagPacket(prGlueInfo->prAdapter, (P_NATIVE_PACKET)prSkb, + TX_PROF_TAG_OS_TO_DRV); + + /* Handle normal data frame */ + u2QueueIdx = skb_get_queue_mapping(prSkb); + + if (u2QueueIdx >= CFG_MAX_TXQ_NUM) { + DBGLOG(INIT, INFO, "Incorrect queue index, skip this frame\n"); + dev_kfree_skb(prSkb); + return WLAN_STATUS_INVALID_PACKET; + } + + if (!HAL_IS_TX_DIRECT(prGlueInfo->prAdapter)) { + GLUE_SPIN_LOCK_DECLARATION(); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_INSERT_TAIL(prTxQueue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + } + + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); + GLUE_INC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex] + [u2QueueIdx]); + + /* + * WMM flow control + * 1. To enlarge threshold for WMM certification, WMM phase two may hit + * netif_stop_subquene Which may cause test case fail due to high + * priority packets are not enough. + * 2. Dynamic control threshold for AC queue. + * If there is high priority traffic, decrease low priority + * threshold. If these is low priority traffic, increase high priority + * threshold. Else, remians the original threshold. + */ + if (prGlueInfo->prAdapter->rWifiVar.ucTpTestMode == + ENUM_TP_TEST_MODE_SIGMA_AC_N_PMF) { + P_BSS_INFO_T prWmmBssInfo = + prGlueInfo->prAdapter->aprBssInfo[ucBssIndex]; + + if ((u2QueueIdx < 3) && + (GLUE_GET_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue + [ucBssIndex][u2QueueIdx + 1]) > + CFG_CERT_WMM_MAX_TX_PENDING)) { + /* + * Use au8Statistics[RX_SIZE_ERR_DROP_COUNT] to track RX + * traffic in certification. + */ + if ((prWmmBssInfo->eCurrentOPMode == + OP_MODE_ACCESS_POINT) && + ((prDev->stats.rx_packets - + (prGlueInfo->prAdapter->rRxCtrl + .au8Statistics[RX_SIZE_ERR_DROP_COUNT])) > + CFG_CERT_WMM_MAX_RX_NUM)) { + u4MaxTxPendingNum = + CFG_CERT_WMM_LOW_STOP_TX_WITH_RX; + } else { + u4MaxTxPendingNum = + CFG_CERT_WMM_LOW_STOP_TX_WO_RX; + } + } else if ((u2QueueIdx > 0) && + (GLUE_GET_REF_CNT( + prGlueInfo->ai4TxPendingFrameNumPerQueue + [ucBssIndex][u2QueueIdx - 1]) > + CFG_CERT_WMM_MAX_TX_PENDING)) { + /* + * Use au8Statistics[RX_SIZE_ERR_DROP_COUNT] to track RX + * traffic in certification. + */ + if ((prWmmBssInfo->eCurrentOPMode == + OP_MODE_ACCESS_POINT) && + ((prDev->stats.rx_packets - + (prGlueInfo->prAdapter->rRxCtrl + .au8Statistics[RX_SIZE_ERR_DROP_COUNT])) > + CFG_CERT_WMM_MAX_RX_NUM)) { + u4MaxTxPendingNum = + CFG_CERT_WMM_HIGH_STOP_TX_WITH_RX; + } else { + u4MaxTxPendingNum = + CFG_CERT_WMM_HIGH_STOP_TX_WO_RX; + } + } else { + u4MaxTxPendingNum = + prGlueInfo->prAdapter->rWifiVar.u4NetifStopTh; + } + } + + if (GLUE_GET_REF_CNT( + prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex] + [u2QueueIdx]) >= + u4MaxTxPendingNum) { + netif_stop_subqueue(prDev, u2QueueIdx); + + DBGLOG(TX, + TRACE, + "Stop subqueue for BSS[%u] QIDX[%u] PKT_LEN[%u] TOT_CNT[%ld] PER-Q_CNT[%ld]\n", + ucBssIndex, + u2QueueIdx, + prSkb->len, + GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum), + GLUE_GET_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue + [ucBssIndex][u2QueueIdx])); + + /* Re-use au8Statistics[RX_SIZE_ERR_DROP_COUNT] buffer to track + * RX traffic in certification */ + if (prGlueInfo->prAdapter->rWifiVar.ucTpTestMode == + ENUM_TP_TEST_MODE_SIGMA_AC_N_PMF) { + prGlueInfo->prAdapter->rRxCtrl + .au8Statistics[RX_SIZE_ERR_DROP_COUNT] = + prDev->stats.rx_packets; + } + } + + /* Update NetDev statisitcs */ + prDev->stats.tx_bytes += prSkb->len; + prDev->stats.tx_packets++; + + DBGLOG(TX, + LOUD, + "Enqueue frame for BSS[%u] QIDX[%u] PKT_LEN[%u] TOT_CNT[%ld] PER-Q_CNT[%ld]\n", + ucBssIndex, + u2QueueIdx, + prSkb->len, + GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum), + GLUE_GET_REF_CNT( + prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex] + [u2QueueIdx])); + + if (HAL_IS_TX_DIRECT(prGlueInfo->prAdapter)) { + return nicTxDirectStartXmit(prSkb, prGlueInfo); + } + + kalSetEvent(prGlueInfo); + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS kalResetStats(IN struct net_device *prDev) +{ + DBGLOG(QM, INFO, "Reset NetDev[0x%p] statistics\n", prDev); + + kalMemZero(kalGetStats(prDev), sizeof(struct net_device_stats)); + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A method of struct net_device, to get the network interface + * statistical information. + * + * Whenever an application needs to get statistics for the interface, this + * method is called. This happens, for example, when ifconfig or netstat -i is + * run. + * + * \param[in] prDev Pointer to struct net_device. + * + * \return net_device_stats buffer pointer. + */ +/*----------------------------------------------------------------------------*/ +void *kalGetStats(IN struct net_device *prDev) +{ + return (void *)&prDev->stats; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Notify OS with SendComplete event of the specific packet. Linux should + * free packets here. + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * \param[in] pvPacket Pointer of Packet Handle + * \param[in] status Status Code for OS upper layer + * + * \return - + */ +/*----------------------------------------------------------------------------*/ +void kalSendCompleteAndAwakeQueue(IN P_GLUE_INFO_T prGlueInfo, + IN void *pvPacket) +{ + struct net_device *prDev = NULL; + struct sk_buff *prSkb = NULL; + u16 u2QueueIdx = 0; + u8 ucBssIndex = 0; + u8 fgIsValidDevice = true; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(pvPacket); + /* ASSERT(prGlueInfo->i4TxPendingFrameNum); */ + + prSkb = (struct sk_buff *)pvPacket; + u2QueueIdx = skb_get_queue_mapping(prSkb); + ASSERT(u2QueueIdx < CFG_MAX_TXQ_NUM); + + ucBssIndex = GLUE_GET_PKT_BSS_IDX(pvPacket); + + GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingFrameNum); + GLUE_DEC_REF_CNT(prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex] + [u2QueueIdx]); + + DBGLOG(TX, + LOUD, + "Release frame for BSS[%u] QIDX[%u] PKT_LEN[%u] TOT_CNT[%ld] PER-Q_CNT[%ld]\n", + ucBssIndex, + u2QueueIdx, + prSkb->len, + GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum), + GLUE_GET_REF_CNT( + prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex] + [u2QueueIdx])); + + prDev = prSkb->dev; + + ASSERT(prDev); + +#if CFG_ENABLE_WIFI_DIRECT + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + { + P_BSS_INFO_T prBssInfo = GET_BSS_INFO_BY_INDEX( + prGlueInfo->prAdapter, ucBssIndex); + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + struct net_device *prNetdevice = NULL; + + /* in case packet was sent after P2P device is unregistered or + * the net_device was be free */ + if (prBssInfo->eNetworkType == NETWORK_TYPE_P2P) { + if (prGlueInfo->prAdapter->fgIsP2PRegistered == false) { + fgIsValidDevice = false; + } else { + ASSERT(prBssInfo->u4PrivateData < KAL_P2P_NUM); + prGlueP2pInfo = + prGlueInfo->prP2PInfo + [prBssInfo->u4PrivateData]; + if (prGlueP2pInfo) { + prNetdevice = + prGlueP2pInfo->aprRoleHandler; + /* The net_device may be free */ + if ((prDev != prNetdevice) && + (prDev != + prGlueP2pInfo->prDevHandler)) { + fgIsValidDevice = false; + DBGLOG(TX, + LOUD, + "kalSendCompleteAndAwakeQueue net device deleted! ucBssIndex = %u\n", + ucBssIndex); + } + } + } + } + } +#endif + + if (fgIsValidDevice == true) { + u32 u4StartTh = prGlueInfo->prAdapter->rWifiVar.u4NetifStartTh; + + if (netif_subqueue_stopped(prDev, prSkb) && + prGlueInfo->ai4TxPendingFrameNumPerQueue[ucBssIndex] + [u2QueueIdx] <= + u4StartTh) { + netif_wake_subqueue(prDev, u2QueueIdx); + DBGLOG(TX, + TRACE, + "WakeUp Queue BSS[%u] QIDX[%u] PKT_LEN[%u] TOT_CNT[%ld] PER-Q_CNT[%ld]\n", + ucBssIndex, + u2QueueIdx, + prSkb->len, + GLUE_GET_REF_CNT( + prGlueInfo->i4TxPendingFrameNum), + GLUE_GET_REF_CNT( + prGlueInfo->ai4TxPendingFrameNumPerQueue + [ucBssIndex][u2QueueIdx])); + } + } + +#if CFG_ENABLE_WIFI_DIRECT + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); +#endif + + dev_kfree_skb_any((struct sk_buff *)pvPacket); + + DBGLOG(TX, LOUD, "----- pending frame %d -----\n", + prGlueInfo->i4TxPendingFrameNum); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Copy Mac Address setting from registry. It's All Zeros in Linux. + * + * \param[in] prAdapter Pointer to the Adapter structure + * + * \param[out] paucMacAddr Pointer to the Mac Address buffer + * + * \retval WLAN_STATUS_SUCCESS + * + * \note + */ +/*----------------------------------------------------------------------------*/ +void kalQueryRegistryMacAddr(IN P_GLUE_INFO_T prGlueInfo, + OUT u8 *paucMacAddr) +{ + u8 aucZeroMac[MAC_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 } + + DEBUGFUNC("kalQueryRegistryMacAddr"); + + ASSERT(prGlueInfo); + ASSERT(paucMacAddr); + + kalMemCopy((void *)paucMacAddr, (void *)aucZeroMac, MAC_ADDR_LEN); +} + +#if CFG_SUPPORT_EXT_CONFIG +/*----------------------------------------------------------------------------*/ +/*! + * \brief Read external configuration, ex. NVRAM or file + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u32 kalReadExtCfg(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + /* External data is given from user space by ioctl or /proc, not read by + * driver. + */ + if (prGlueInfo->u4ExtCfgLength != 0) { + DBGLOG(INIT, TRACE, "Read external configuration data -- OK\n"); + } else { + DBGLOG(INIT, TRACE, + "Read external configuration data -- fail\n"); + } + + return prGlueInfo->u4ExtCfgLength; +} +#endif + +u8 kalIPv4FrameClassifier(IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket, IN u8 *pucIpHdr, + OUT P_TX_PACKET_INFO prTxPktInfo) +{ + u8 ucIpVersion; + /* u16 u2IpId; */ + + /* IPv4 version check */ + ucIpVersion = (pucIpHdr[0] & IP_VERSION_MASK) >> IP_VERSION_OFFSET; + if (ucIpVersion != IP_VERSION_4) { + DBGLOG(INIT, WARN, "Invalid IPv4 packet version: %u\n", + ucIpVersion); + return false; + } + /* WLAN_GET_FIELD_16(&pucIpHdr[IPV4_HDR_IP_IDENTIFICATION_OFFSET], + * &u2IpId); */ + + if (pucIpHdr[IPV4_HDR_IP_PROTOCOL_OFFSET] == IP_PROTOCOL_UDP) { + struct sk_buff *prSkb = (struct sk_buff *)prPacket; + u32 u4PacketLen = prSkb->len; + u8 ucIHL = (pucIpHdr[0] & 0xF) * 4; /* IHL unit: DW = 4bytes */ + u8 *pucUdpHdr = &pucIpHdr[ucIHL]; + u16 u2DstPort; + /* u16 u2SrcPort; */ + + /* DBGLOG_MEM8(INIT, INFO, pucUdpHdr, 256); */ + DBGLOG(INIT, INFO, "IP header parsed, ucIHL: %u\n", ucIHL); + + /* UDP packet should have 8 byte header at least */ + if ((ETHER_HEADER_LEN + ucIHL + UDP_HDR_LEN) > u4PacketLen) { + DBGLOG(INIT, + WARN, + "Invalid UDP packet, should include 8 bytes header at least, packet length too small: %u < %u\n", + u4PacketLen, + ETHER_HEADER_LEN + ucIHL + UDP_HDR_LEN); + return false; + } + + /* Get UDP DST port */ + WLAN_GET_FIELD_BE16(&pucUdpHdr[UDP_HDR_DST_PORT_OFFSET], + &u2DstPort); + + /* DBGLOG(INIT, INFO, ("UDP DST[%u]\n", u2DstPort)); */ + + /* Get UDP SRC port */ + /* WLAN_GET_FIELD_BE16(&pucUdpHdr[UDP_HDR_SRC_PORT_OFFSET], + * &u2SrcPort); */ + + /* BOOTP/DHCP protocol */ + if ((u2DstPort == IP_PORT_BOOTP_SERVER) || + (u2DstPort == IP_PORT_BOOTP_CLIENT)) { + P_BOOTP_PROTOCOL_T prBootp = + (P_BOOTP_PROTOCOL_T)&pucUdpHdr[UDP_HDR_LEN]; + + u32 u4DhcpMagicCode; + + if ((ETHER_HEADER_LEN + ucIHL + UDP_HDR_LEN + + sizeof(BOOTP_PROTOCOL_T) + sizeof(u32)) > + u4PacketLen) { + DBGLOG(INIT, + WARN, + "Invalid bootp packet w/ DHCP magic code, packet length too small: %u < %u\n", + u4PacketLen, + ETHER_HEADER_LEN + ucIHL + UDP_HDR_LEN + + sizeof(BOOTP_PROTOCOL_T) + + sizeof(u32)); + return false; + } + + WLAN_GET_FIELD_BE32(&prBootp->aucOptions[0], + &u4DhcpMagicCode); + + if (u4DhcpMagicCode == DHCP_MAGIC_NUMBER) { + u32 u4Xid; + + WLAN_GET_FIELD_BE32(&prBootp->u4TransId, + &u4Xid); + + DBGLOG(SW4, + INFO, + "DHCP PKT[0x%p] XID[0x%08x] OPT[%u] TYPE[%u]\n", + prPacket, + u4Xid, + prBootp->aucOptions[4], + prBootp->aucOptions[6]); + + prTxPktInfo->u2Flag |= BIT(ENUM_PKT_DHCP); + } + } + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This inline function is to extract some packet information, including + * user priority, packet length, destination address, 802.1x and BT over + * Wi-Fi or not. + * + * @param prGlueInfo Pointer to the glue structure + * @param prPacket Packet descriptor + * @param prTxPktInfo Extracted packet info + * + * @retval true Success to extract information + * @retval false Fail to extract correct information + */ +/*----------------------------------------------------------------------------*/ +u8 kalQoSFrameClassifierAndPacketInfo(IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket, + OUT P_TX_PACKET_INFO prTxPktInfo) +{ + u32 u4PacketLen; + u16 u2EtherTypeLen; + struct sk_buff *prSkb = (struct sk_buff *)prPacket; + u8 *aucLookAheadBuf = NULL; + u8 ucEthTypeLenOffset = ETHER_HEADER_LEN - ETHER_TYPE_LEN; + u8 *pucNextProtocol = NULL; + u16 u2KeyInfo = 0; + u8 ucEAPoLKey = 0; + u8 ucEapOffset = ETHER_HEADER_LEN; + + u4PacketLen = prSkb->len; + + if (u4PacketLen < ETHER_HEADER_LEN) { + DBGLOG(INIT, WARN, "Invalid Ether packet length: %lu\n", + u4PacketLen); + return false; + } + + aucLookAheadBuf = prSkb->data; + + /* Reset Packet Info */ + kalMemZero(prTxPktInfo, sizeof(TX_PACKET_INFO)); + + /* 4 <0> Obtain Ether Type/Len */ + WLAN_GET_FIELD_BE16(&aucLookAheadBuf[ucEthTypeLenOffset], + &u2EtherTypeLen); + + /* 4 <1> Skip 802.1Q header (VLAN Tagging) */ + if (u2EtherTypeLen == ETH_P_VLAN) { + prTxPktInfo->u2Flag |= BIT(ENUM_PKT_VLAN_EXIST); + ucEthTypeLenOffset += ETH_802_1Q_HEADER_LEN; + if (u4PacketLen < ucEthTypeLenOffset + sizeof(u16)) { + DBGLOG(INIT, WARN, + "Invalid Ether packet length: %lu < %lu\n", + u4PacketLen, ucEthTypeLenOffset + sizeof(u16)); + return false; + } + WLAN_GET_FIELD_BE16(&aucLookAheadBuf[ucEthTypeLenOffset], + &u2EtherTypeLen); + } + /* 4 <2> Obtain next protocol pointer */ + pucNextProtocol = &aucLookAheadBuf[ucEthTypeLenOffset + ETHER_TYPE_LEN]; + + /* 4 <3> Handle ethernet format */ + switch (u2EtherTypeLen) { + /* IPv4 */ + case ETH_P_IPV4: + /* IPv4 header length check */ + if (u4PacketLen < + (ucEthTypeLenOffset + ETHER_TYPE_LEN + IPV4_HDR_LEN)) { + DBGLOG(INIT, WARN, "Invalid IPv4 packet length: %lu\n", + u4PacketLen); + /* Supplicant trying to TX keep alive NULL frame. + * This behavior would cause some AP issue. + */ + return false; + } + + kalIPv4FrameClassifier(prGlueInfo, prPacket, pucNextProtocol, + prTxPktInfo); + break; + + case ETH_P_ARP: { + u16 u2ArpOp; + + WLAN_GET_FIELD_BE16(&pucNextProtocol[ARP_OPERATION_OFFSET], + &u2ArpOp); + + DBGLOG(SW4, INFO, + "ARP %s PKT[0x%p] TAR MAC/IP[" MACSTR "]/[" IPV4STR + "]\n", + u2ArpOp == ARP_OPERATION_REQUEST ? "REQ" : "RSP", + prPacket, + MAC2STR(&pucNextProtocol[ARP_TARGET_MAC_OFFSET]), + IPV4TOSTR(&pucNextProtocol[ARP_TARGET_IP_OFFSET])); + + prTxPktInfo->u2Flag |= BIT(ENUM_PKT_ARP); + } break; + + case ETH_P_1X: + case ETH_P_PRE_1X: + prTxPktInfo->u2Flag |= BIT(ENUM_PKT_1X); + DBGLOG(RSN, INFO, "T1x like normal data, PKT[0x%p]\n", + prPacket); + + if (u2EtherTypeLen == ETH_P_1X) { + /* Leave EAP to check */ + ucEAPoLKey = aucLookAheadBuf[1 + ucEapOffset]; + if (ucEAPoLKey != ETH_EAPOL_KEY) { + prTxPktInfo->u2Flag |= + BIT(ENUM_PKT_NON_PROTECTED_1X); + } else { + WLAN_GET_FIELD_BE16( + &aucLookAheadBuf[5 + ucEapOffset], + &u2KeyInfo); + /* BIT3 is pairwise key bit */ + DBGLOG(RSN, + WARN, + "Tx EAPOL Frame [Len: %d] [KeyInfo: %d]\n", + u4PacketLen, + u2KeyInfo); + if (u2KeyInfo & BIT(3)) { + prTxPktInfo->u2Flag |= + BIT(ENUM_PKT_NON_PROTECTED_1X); + } + } + } + break; + + default: + /* 4 <4> Handle 802.3 format if LEN <= 1500 */ + if (u2EtherTypeLen <= ETH_802_3_MAX_LEN) { + prTxPktInfo->u2Flag |= BIT(ENUM_PKT_802_3); + } + break; + } + + /* 4 <4.1> Check for PAL (BT over Wi-Fi) */ + /* Move to kalBowFrameClassifier */ + + /* 4 <5> Return the value of Priority Parameter. */ + /* prSkb->priority is assigned by Linux wireless utility + * function(cfg80211_classify8021d) */ + /* at net_dev selection callback (ndo_select_queue) */ + prTxPktInfo->ucPriorityParam = prSkb->priority; + + /* 4 <6> Retrieve Packet Information - DA */ + /* Packet Length/ Destination Address */ + prTxPktInfo->u4PacketLen = u4PacketLen; + + kalMemCopy(prTxPktInfo->aucEthDestAddr, aucLookAheadBuf, + PARAM_MAC_ADDR_LEN); + + return true; +} + +u8 kalGetEthDestAddr(IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket, + OUT u8 *pucEthDestAddr) +{ + struct sk_buff *prSkb = (struct sk_buff *)prPacket; + u8 *aucLookAheadBuf = NULL; + + /* Sanity Check */ + if (!prPacket || !prGlueInfo) { + return false; + } + + aucLookAheadBuf = prSkb->data; + + kalMemCopy(pucEthDestAddr, aucLookAheadBuf, PARAM_MAC_ADDR_LEN); + + return true; +} + +void kalOidComplete(IN P_GLUE_INFO_T prGlueInfo, IN u8 fgSetQuery, + IN u32 u4SetQueryInfoLen, IN WLAN_STATUS rOidStatus) +{ + P_GL_IO_REQ_T prIoReq = NULL; + + ASSERT(prGlueInfo); + /* remove timeout check timer */ + wlanoidClearTimeoutCheck(prGlueInfo->prAdapter); + + prGlueInfo->rPendStatus = rOidStatus; + + prIoReq = &(prGlueInfo->OidEntry); + + /* Not submit req yet, or submit fail, no need to complete */ + if (prIoReq->rStatus == WLAN_STATUS_FAILURE) { + DBGLOG(INIT, WARN, "Ignore invalid OID complete\n"); + return; + } + + prGlueInfo->u4OidCompleteFlag = 1; + /* complete ONLY if there are waiters */ + if (!completion_done(&prGlueInfo->rPendComp)) { + complete(&prGlueInfo->rPendComp); + } else { + DBGLOG(INIT, WARN, "SKIP multiple OID complete!\n"); + /* WARN_ON(true); */ + } + + if (rOidStatus == WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, TRACE, "Complete OID, status:success\n"); + }else{ + DBGLOG(INIT, WARN, "Complete OID, status:0x%08x\n", rOidStatus); + } + + /* else let it timeout on kalIoctl entry */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to transfer linux ioctl to OID, and we + * need to specify the behavior of the OID by ourself + * + * @param prGlueInfo Pointer to the glue structure + * @param pvInfoBuf Data buffer + * @param u4InfoBufLen Data buffer length + * @param fgRead Is this a read OID + * @param fgWaitResp does this OID need to wait for values + * @param fgCmd does this OID compose command packet + * @param pu4QryInfoLen The data length of the return values + * + * @retval true Success to extract information + * @retval false Fail to extract correct information + */ +/*----------------------------------------------------------------------------*/ + +/* todo: enqueue the i/o requests for multiple processes access */ +/* */ +/* currently, return -1 */ +/* */ + +/* static GL_IO_REQ_T OidEntry; */ + +WLAN_STATUS +kalIoctl(IN P_GLUE_INFO_T prGlueInfo, IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN void *pvInfoBuf, IN u32 u4InfoBufLen, IN u8 fgRead, + IN u8 fgWaitResp, IN u8 fgCmd, OUT u32 *pu4QryInfoLen) +{ + return kalIoctlTimeout(prGlueInfo, pfnOidHandler, pvInfoBuf, + u4InfoBufLen, fgRead, fgWaitResp, fgCmd, -1, + pu4QryInfoLen); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is used to transfer linux ioctl to OID, and we + * need to specify the behavior of the OID by ourself + * + * @param prGlueInfo Pointer to the glue structure + * @param pvInfoBuf Data buffer + * @param u4InfoBufLen Data buffer length + * @param fgRead Is this a read OID + * @param fgWaitResp does this OID need to wait for values + * @param fgCmd does this OID compose command packet + * @param i4OidTimeout timeout for this OID + * @param pu4QryInfoLen The data length of the return values + * + * @retval true Success to extract information + * @retval false Fail to extract correct information + */ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS +kalIoctlTimeout(IN P_GLUE_INFO_T prGlueInfo, + IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN void *pvInfoBuf, + IN u32 u4InfoBufLen, IN u8 fgRead, IN u8 fgWaitResp, + IN u8 fgCmd, IN s32 i4OidTimeout, OUT u32 *pu4QryInfoLen) +{ + P_GL_IO_REQ_T prIoReq = NULL; + WLAN_STATUS ret = WLAN_STATUS_SUCCESS; +#if CFG_IOCTL_WAIT_FOR_COMPLETION_TIMEOUT + unsigned long ret2 = 0; + u32 completion_timeout = 0; +#endif + + if (wlanIsChipAssert(prGlueInfo->prAdapter)) { + return WLAN_STATUS_SUCCESS; + } + + /* GLUE_SPIN_LOCK_DECLARATION(); */ + ASSERT(prGlueInfo); + + /* <1> Check if driver is halt */ + /* if (prGlueInfo->u4Flag & GLUE_FLAG_HALT) { */ + /* return WLAN_STATUS_ADAPTER_NOT_READY; */ + /* } */ + + + if (down_interruptible(&g_halt_sem)) { + DBGLOG(INIT, INFO, "Halt semaphore is down.\n"); + return WLAN_STATUS_FAILURE; + } + + if (g_u4HaltFlag) { + up(&g_halt_sem); + DBGLOG(INIT, INFO, "Halt flag is true.\n"); + return WLAN_STATUS_ADAPTER_NOT_READY; + } + + if (down_interruptible(&prGlueInfo->ioctl_sem)) { + up(&g_halt_sem); + DBGLOG(INIT, INFO, "Ioctl semaphore is down.\n"); + return WLAN_STATUS_FAILURE; + } + + /* <2> TODO: thread-safe */ + + /* <3> point to the OidEntry of Glue layer */ + + prIoReq = &(prGlueInfo->OidEntry); + + ASSERT(prIoReq); + + /* <4> Compose the I/O request */ + prIoReq->prAdapter = prGlueInfo->prAdapter; + prIoReq->pfnOidHandler = pfnOidHandler; + prIoReq->pvInfoBuf = pvInfoBuf; + prIoReq->u4InfoBufLen = u4InfoBufLen; + prIoReq->pu4QryInfoLen = pu4QryInfoLen; + prIoReq->fgRead = fgRead; + prIoReq->fgWaitResp = fgWaitResp; + prIoReq->rStatus = WLAN_STATUS_FAILURE; + + if (i4OidTimeout >= 0 && + i4OidTimeout <= WLAN_OID_TIMEOUT_THRESHOLD_MAX) { + prIoReq->u4Timeout = (u32)i4OidTimeout; + }else{ + prIoReq->u4Timeout = WLAN_OID_TIMEOUT_THRESHOLD; + } + + /* <5> Reset the status of pending OID */ + prGlueInfo->rPendStatus = WLAN_STATUS_FAILURE; + /* prGlueInfo->u4TimeoutFlag = 0; */ + prGlueInfo->u4OidCompleteFlag = 0; + + /* <6> Check if we use the command queue */ + prIoReq->u4Flag = fgCmd; + + /* <7> schedule the OID bit + * Use memory barrier to ensure OidEntry is written done and then set + * bit. + */ + smp_mb(); + set_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->ulFlag); + + /* <8> Wake up main thread to handle kick start the I/O request. + * Use memory barrier to ensure set bit is done and then wake up main + * thread. + */ + smp_mb(); + wake_up_interruptible(&prGlueInfo->waitq); + + /* <9> Block and wait for event or timeout, current the timeout is 2 + * secs */ +#if CFG_IOCTL_WAIT_FOR_COMPLETION_TIMEOUT + /* set completion timeout to be oid timeout + 1 sec for thread switching + * and main_thread processing delay so that this + * wait_for_completion_timeout() will not overkill the case where + * main_thread actually is just busy working + */ + completion_timeout = prIoReq->u4Timeout + 1000; + + DBGLOG(INIT, WARN, "CHECK 1\n"); + + ret2 = wait_for_completion_timeout(&prGlueInfo->rPendComp, + MSEC_TO_JIFFIES(completion_timeout)); + + DBGLOG(INIT, WARN, "CHECK 2\n"); + + if (ret2 == 0) { + DBGLOG(INIT, ERROR, "exceed %d ms, force timeout\n", + completion_timeout); + ret = WLAN_STATUS_FAILURE; + } else +#else + wait_for_completion(&prGlueInfo->rPendComp); +#endif + { + /* Case 1: No timeout. */ + /* if return WLAN_STATUS_PENDING, the status of cmd is stored in + * prGlueInfo */ + if (prIoReq->rStatus == WLAN_STATUS_PENDING) { + ret = prGlueInfo->rPendStatus; + }else{ + ret = prIoReq->rStatus; + } + } + + /* <10> Clear bit for error handling */ + clear_bit(GLUE_FLAG_OID_BIT, &prGlueInfo->ulFlag); + + up(&prGlueInfo->ioctl_sem); + up(&g_halt_sem); + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to clear all pending security frames + * + * \param prGlueInfo Pointer of GLUE Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void kalClearSecurityFrames(IN P_GLUE_INFO_T prGlueInfo) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + QUE_T rReturnCmdQue; + P_QUE_T prReturnCmdQue = &rReturnCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + QUEUE_INITIALIZE(prReturnCmdQue); + /* Clear pending security frames in prGlueInfo->rCmdQueue */ + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { + if (prCmdInfo->pfCmdTimeoutHandler) { + prCmdInfo->pfCmdTimeoutHandler( + prGlueInfo->prAdapter, prCmdInfo); + } else { + wlanReleaseCommand(prGlueInfo->prAdapter, + prCmdInfo, + TX_RESULT_QUEUE_CLEARANCE); + } + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingCmdNum); + } else { + QUEUE_INSERT_TAIL(prReturnCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_CONCATENATE_QUEUES_HEAD(prCmdQue, prReturnCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to clear pending security frames + * belongs to dedicated network type + * + * \param prGlueInfo Pointer of GLUE Data Structure + * \param eNetworkTypeIdx Network Type Index + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void kalClearSecurityFramesByBssIdx(IN P_GLUE_INFO_T prGlueInfo, + IN u8 ucBssIndex) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + QUE_T rReturnCmdQue; + P_QUE_T prReturnCmdQue = &rReturnCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + P_MSDU_INFO_T prMsduInfo; + u8 fgFree; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + QUEUE_INITIALIZE(prReturnCmdQue); + /* Clear pending security frames in prGlueInfo->rCmdQueue */ + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + prMsduInfo = prCmdInfo->prMsduInfo; + fgFree = false; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME && + prMsduInfo) { + if (prMsduInfo->ucBssIndex == ucBssIndex) { + fgFree = true; + } + } + + if (fgFree) { + if (prCmdInfo->pfCmdTimeoutHandler) { + prCmdInfo->pfCmdTimeoutHandler( + prGlueInfo->prAdapter, prCmdInfo); + } else { + wlanReleaseCommand(prGlueInfo->prAdapter, + prCmdInfo, + TX_RESULT_QUEUE_CLEARANCE); + } + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingCmdNum); + } else { + QUEUE_INSERT_TAIL(prReturnCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_CONCATENATE_QUEUES_HEAD(prCmdQue, prReturnCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to clear all pending management frames + * + * \param prGlueInfo Pointer of GLUE Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void kalClearMgmtFrames(IN P_GLUE_INFO_T prGlueInfo) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + QUE_T rReturnCmdQue; + P_QUE_T prReturnCmdQue = &rReturnCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + QUEUE_INITIALIZE(prReturnCmdQue); + /* Clear pending management frames in prGlueInfo->rCmdQueue */ + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { + wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo, + TX_RESULT_QUEUE_CLEARANCE); + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingCmdNum); + } else { + QUEUE_INSERT_TAIL(prReturnCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_CONCATENATE_QUEUES_HEAD(prCmdQue, prReturnCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to clear all pending management frames + * belongs to dedicated network type + * \param prGlueInfo Pointer of GLUE Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void kalClearMgmtFramesByBssIdx(IN P_GLUE_INFO_T prGlueInfo, + IN u8 ucBssIndex) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + QUE_T rReturnCmdQue; + P_QUE_T prReturnCmdQue = &rReturnCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + P_MSDU_INFO_T prMsduInfo; + u8 fgFree; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + QUEUE_INITIALIZE(prReturnCmdQue); + /* Clear pending management frames in prGlueInfo->rCmdQueue */ + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + prMsduInfo = prCmdInfo->prMsduInfo; + fgFree = false; + + if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME && + prMsduInfo) { + if (prMsduInfo->ucBssIndex == ucBssIndex) { + fgFree = true; + } + } + + if (fgFree) { + wlanReleaseCommand(prGlueInfo->prAdapter, prCmdInfo, + TX_RESULT_QUEUE_CLEARANCE); + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingCmdNum); + } else { + QUEUE_INSERT_TAIL(prReturnCmdQue, prQueueEntry); + } + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_CONCATENATE_QUEUES_HEAD(prCmdQue, prReturnCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to clear all commands in command queue + * \param prGlueInfo Pointer of GLUE Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void kalClearCommandQueue(IN P_GLUE_INFO_T prGlueInfo, + IN u8 fgIsNeedHandler) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + QUE_T rReturnCmdQue; + P_QUE_T prReturnCmdQue = &rReturnCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + QUEUE_INITIALIZE(prReturnCmdQue); + + /* Clear ALL in prGlueInfo->rCmdQueue */ + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + if (prCmdInfo->pfCmdTimeoutHandler) { + prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, + prCmdInfo); + } else { + wlanReleaseCommandEx(prGlueInfo->prAdapter, prCmdInfo, + TX_RESULT_QUEUE_CLEARANCE, + fgIsNeedHandler); + } + + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingCmdNum); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } +} + +u32 kalProcessTxPacket(P_GLUE_INFO_T prGlueInfo, struct sk_buff *prSkb) +{ + u32 u4Status = WLAN_STATUS_SUCCESS; + + if (prSkb == NULL) { + DBGLOG(INIT, WARN, "prSkb == NULL in tx\n"); + return u4Status; + } + + /* Handle security frame */ + if (0 /* GLUE_TEST_PKT_FLAG(prSkb, ENUM_PKT_1X) */ + /* No more sending via cmd */) { + if (wlanProcessSecurityFrame(prGlueInfo->prAdapter, + (P_NATIVE_PACKET)prSkb)) { + u4Status = WLAN_STATUS_SUCCESS; + GLUE_INC_REF_CNT( + prGlueInfo->i4TxPendingSecurityFrameNum); + } else { + u4Status = WLAN_STATUS_RESOURCES; + } + } + /* Handle normal frame */ + else { + u4Status = wlanEnqueueTxPacket(prGlueInfo->prAdapter, + (P_NATIVE_PACKET)prSkb); + } + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to process Tx request to main_thread + * + * \param prGlueInfo Pointer of GLUE Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void kalProcessTxReq(P_GLUE_INFO_T prGlueInfo, u8 *pfgNeedHwAccess) +{ + P_QUE_T prCmdQue = NULL; + P_QUE_T prTxQueue = NULL; + QUE_T rTempQue; + P_QUE_T prTempQue = &rTempQue; + QUE_T rTempReturnQue; + P_QUE_T prTempReturnQue = &rTempReturnQue; + P_QUE_ENTRY_T prQueueEntry = NULL; + u32 u4Status; + u32 u4CmdCount = 0; + u32 u4TxLoopCount; + + /* for spin lock acquire and release */ + GLUE_SPIN_LOCK_DECLARATION(); + + prTxQueue = &prGlueInfo->rTxQueue; + prCmdQue = &prGlueInfo->rCmdQueue; + + QUEUE_INITIALIZE(prTempQue); + QUEUE_INITIALIZE(prTempReturnQue); + + u4TxLoopCount = prGlueInfo->prAdapter->rWifiVar.u4TxFromOsLoopCount; + + /* Process Mailbox Messages */ + wlanProcessMboxMessage(prGlueInfo->prAdapter); + + /* Process CMD request */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + u4CmdCount = prCmdQue->u4NumElem; + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + if (u4CmdCount > 0) { + wlanProcessCommandQueue(prGlueInfo->prAdapter, prCmdQue); + } + + while (u4TxLoopCount--) { + while (QUEUE_IS_NOT_EMPTY(prTxQueue)) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_MOVE_ALL(prTempQue, prTxQueue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + + /* Handle Packet Tx */ + while (QUEUE_IS_NOT_EMPTY(prTempQue)) { + QUEUE_REMOVE_HEAD(prTempQue, prQueueEntry, + P_QUE_ENTRY_T); + + if (prQueueEntry == NULL) { + break; + } + + u4Status = kalProcessTxPacket( + prGlueInfo, + (struct sk_buff *) + GLUE_GET_PKT_DESCRIPTOR( + prQueueEntry)); + + /* Enqueue packet back into TxQueue if resource + * is not enough */ + if (u4Status == WLAN_STATUS_RESOURCES) { + QUEUE_INSERT_TAIL(prTempReturnQue, + prQueueEntry); + break; + } + if (u4Status == WLAN_STATUS_PENDING) { + QUEUE_INSERT_HEAD(prTempReturnQue, + prQueueEntry); + break; + } + } + + if (wlanGetTxPendingFrameCount(prGlueInfo->prAdapter) > + 0) { + wlanTxPendingPackets(prGlueInfo->prAdapter, + pfgNeedHwAccess); + } + + /* Enqueue packet back into TxQueue if resource is not + * enough */ + if (QUEUE_IS_NOT_EMPTY(prTempReturnQue)) { + QUEUE_CONCATENATE_QUEUES(prTempReturnQue, + prTempQue); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, + SPIN_LOCK_TX_QUE); + QUEUE_CONCATENATE_QUEUES_HEAD(prTxQueue, + prTempReturnQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, + SPIN_LOCK_TX_QUE); + + break; + } + } + + if (wlanGetTxPendingFrameCount(prGlueInfo->prAdapter) > 0) { + wlanTxPendingPackets(prGlueInfo->prAdapter, + pfgNeedHwAccess); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief + * + * @param data data pointer to private data of hif_thread + * + * @retval If the function succeeds, the return value is 0. + * Otherwise, an error code is returned. + * + */ +/*----------------------------------------------------------------------------*/ + +int hif_thread(void *data) +{ + struct net_device *dev = data; + P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(dev)); + int ret = 0; + + DBGLOG(INIT, INFO, "%s:%u starts running...\n", + KAL_GET_CURRENT_THREAD_NAME(), KAL_GET_CURRENT_THREAD_ID()); + + prGlueInfo->u4HifThreadPid = KAL_GET_CURRENT_THREAD_ID(); + + set_user_nice(current, prGlueInfo->prAdapter->rWifiVar.cThreadNice); + + while (true) { + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + DBGLOG(INIT, INFO, "hif_thread should stop now...\n"); + break; + } + + /* + * sleep on waitqueue if no events occurred. Event contain (1) + * GLUE_FLAG_INT (2) GLUE_FLAG_OID (3) GLUE_FLAG_TXREQ (4) + * GLUE_FLAG_HALT + * + */ + do { + ret = wait_event_interruptible( + prGlueInfo->waitq_hif, + ((prGlueInfo->ulFlag & GLUE_FLAG_HIF_PROCESS) != + 0)); + } while (ret != 0); + + wlanAcquirePowerControl(prGlueInfo->prAdapter); + + /* Handle Interrupt */ + if (test_and_clear_bit(GLUE_FLAG_INT_BIT, + &prGlueInfo->ulFlag)) { + /* the Wi-Fi interrupt is already disabled in mmc + * thread, so we set the flag only to enable the + * interrupt later + */ + prGlueInfo->prAdapter->fgIsIntEnable = false; + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + /* Should stop now... skip pending interrupt */ + DBGLOG(INIT, INFO, + "ignore pending interrupt\n"); + } else { + /* DBGLOG(INIT, INFO, ("HIF Interrupt!\n")); */ + wlanIST(prGlueInfo->prAdapter); + } + } + + /* Skip Tx request if SER is operating */ + if (!nicSerIsTxStop(prGlueInfo->prAdapter)) { + /* TX Commands */ + if (test_and_clear_bit(GLUE_FLAG_HIF_TX_CMD_BIT, + &prGlueInfo->ulFlag)) { + wlanTxCmdMthread(prGlueInfo->prAdapter); + } + + /* Process TX data packet to HIF */ + if (test_and_clear_bit(GLUE_FLAG_HIF_TX_BIT, + &prGlueInfo->ulFlag)) { + nicTxMsduQueueMthread(prGlueInfo->prAdapter); + } + } + + /* Read chip status when chip no response */ + if (test_and_clear_bit(GLUE_FLAG_HIF_PRT_HIF_DBG_INFO_BIT, + &prGlueInfo->ulFlag)) { + halPrintHifDbgInfo(prGlueInfo->prAdapter); + } + + /* Set FW own */ + if (test_and_clear_bit(GLUE_FLAG_HIF_FW_OWN_BIT, + &prGlueInfo->ulFlag)) { + prGlueInfo->prAdapter->fgWiFiInSleepyState = true; + } + + /* Release to FW own */ + wlanReleasePowerControl(prGlueInfo->prAdapter); + } + + complete(&prGlueInfo->rHifHaltComp); + + DBGLOG(INIT, INFO, "%s:%u stopped!\n", KAL_GET_CURRENT_THREAD_NAME(), + KAL_GET_CURRENT_THREAD_ID()); + + return 0; +} + +int rx_thread(void *data) +{ + struct net_device *dev = data; + P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(dev)); + + QUE_T rTempRxQue; + P_QUE_T prTempRxQue = NULL; + P_QUE_ENTRY_T prQueueEntry = NULL; + + int ret = 0; + + u32 u4LoopCount; + + /* for spin lock acquire and release */ + KAL_SPIN_LOCK_DECLARATION(); + + DBGLOG(INIT, INFO, "%s:%u starts running...\n", + KAL_GET_CURRENT_THREAD_NAME(), KAL_GET_CURRENT_THREAD_ID()); + + prGlueInfo->u4RxThreadPid = KAL_GET_CURRENT_THREAD_ID(); + + set_user_nice(current, prGlueInfo->prAdapter->rWifiVar.cThreadNice); + + prTempRxQue = &rTempRxQue; + + while (true) { + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + DBGLOG(INIT, INFO, "rx_thread should stop now...\n"); + break; + } + + /* + * sleep on waitqueue if no events occurred. + */ + do { + ret = wait_event_interruptible( + prGlueInfo->waitq_rx, + ((prGlueInfo->ulFlag & GLUE_FLAG_RX_PROCESS) != + 0)); + } while (ret != 0); + + if (test_and_clear_bit(GLUE_FLAG_RX_TO_OS_BIT, + &prGlueInfo->ulFlag)) { + u4LoopCount = + prGlueInfo->prAdapter->rWifiVar.u4Rx2OsLoopCount; + + while (u4LoopCount--) { + while (QUEUE_IS_NOT_EMPTY( + &prGlueInfo->prAdapter->rRxQueue)) { + QUEUE_INITIALIZE(prTempRxQue); + + GLUE_ACQUIRE_SPIN_LOCK( + prGlueInfo, + SPIN_LOCK_RX_TO_OS_QUE); + QUEUE_MOVE_ALL(prTempRxQue, + &prGlueInfo->prAdapter + ->rRxQueue); + GLUE_RELEASE_SPIN_LOCK( + prGlueInfo, + SPIN_LOCK_RX_TO_OS_QUE); + + while (QUEUE_IS_NOT_EMPTY( + prTempRxQue)) { + QUEUE_REMOVE_HEAD( + prTempRxQue, + prQueueEntry, + P_QUE_ENTRY_T); + kalRxIndicateOnePkt( + prGlueInfo, + (void *) + GLUE_GET_PKT_DESCRIPTOR( + prQueueEntry)); + } + } + } + } + } + + complete(&prGlueInfo->rRxHaltComp); + + DBGLOG(INIT, INFO, "%s:%u stopped!\n", KAL_GET_CURRENT_THREAD_NAME(), + KAL_GET_CURRENT_THREAD_ID()); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This function is a kernel thread function for handling command packets + * Tx requests and interrupt events + * + * @param data data pointer to private data of main_thread + * + * @retval If the function succeeds, the return value is 0. + * Otherwise, an error code is returned. + * + */ +/*----------------------------------------------------------------------------*/ + +int main_thread(void *data) +{ + struct net_device *dev = data; + P_GLUE_INFO_T prGlueInfo = ((P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(dev))->prGlueInfo; + P_GL_IO_REQ_T prIoReq = NULL; + int ret = 0; + u8 fgNeedHwAccess = false; + + prGlueInfo->u4TxThreadPid = KAL_GET_CURRENT_THREAD_ID(); + + current->flags |= PF_NOFREEZE; + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prAdapter); + set_user_nice(current, prGlueInfo->prAdapter->rWifiVar.cThreadNice); + + DBGLOG(INIT, INFO, "%s:%u starts running...\n", + KAL_GET_CURRENT_THREAD_NAME(), KAL_GET_CURRENT_THREAD_ID()); + + while (true) { + /*run p2p multicast list work. */ + if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, + &prGlueInfo->ulFlag)) { + p2pSetMulticastListWorkQueueWrapper(prGlueInfo); + } + + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + DBGLOG(INIT, INFO, "%s should stop now...\n", + KAL_GET_CURRENT_THREAD_NAME()); + break; + } + + /* + * sleep on waitqueue if no events occurred. Event contain (1) + * GLUE_FLAG_INT (2) GLUE_FLAG_OID (3) GLUE_FLAG_TXREQ (4) + * GLUE_FLAG_HALT + * + */ + do { + ret = wait_event_interruptible( + prGlueInfo->waitq, ((prGlueInfo->ulFlag & + GLUE_FLAG_MAIN_PROCESS) != 0)); + } while (ret != 0); + +#if CFG_ENABLE_WIFI_DIRECT + /*run p2p multicast list work. */ + if (test_and_clear_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, + &prGlueInfo->ulFlag)) { + p2pSetMulticastListWorkQueueWrapper(prGlueInfo); + } + + if (test_and_clear_bit(GLUE_FLAG_FRAME_FILTER_BIT, + &prGlueInfo->ulFlag)) { + p2pFuncUpdateMgmtFrameRegister( + prGlueInfo->prAdapter, + prGlueInfo->prP2PDevInfo->u4OsMgmtFrameFilter); + } +#endif + if (test_and_clear_bit(GLUE_FLAG_FRAME_FILTER_AIS_BIT, + &prGlueInfo->ulFlag)) { + P_AIS_FSM_INFO_T prAisFsmInfo = (P_AIS_FSM_INFO_T)NULL; + + prAisFsmInfo = + &(prGlueInfo->prAdapter->rWifiVar.rAisFsmInfo); +#if CFG_SUPPORT_PER_BSS_FILTER + if (prAisFsmInfo->u4AisPacketFilter ^ + prGlueInfo->u4OsMgmtFrameFilter) { + /* Filter setings changed. */ + CMD_RX_PACKET_FILTER rSetRxPacketFilter; + u32 u4OsFilter = 0; + prAisFsmInfo->u4AisPacketFilter = + prGlueInfo->u4OsMgmtFrameFilter; + + kalMemZero(&rSetRxPacketFilter, + sizeof(rSetRxPacketFilter)); + + /* For not impact original functionality. */ + rSetRxPacketFilter.u4RxPacketFilter = + prGlueInfo->prAdapter->u4OsPacketFilter; + + if (prGlueInfo->prAdapter->prAisBssInfo) { + rSetRxPacketFilter.ucIsPerBssFilter = + true; + rSetRxPacketFilter.ucBssIndex = + prGlueInfo->prAdapter + ->prAisBssInfo + ->ucBssIndex; + rSetRxPacketFilter.u4BssMgmtFilter = + prAisFsmInfo->u4AisPacketFilter; + + wlanSendSetQueryCmd( + prGlueInfo->prAdapter, + CMD_ID_SET_RX_FILTER, true, + false, false, + nicCmdEventSetCommon, + nicOidCmdTimeoutCommon, + sizeof(CMD_RX_PACKET_FILTER), + (u8 *)&rSetRxPacketFilter, + &u4OsFilter, + sizeof(u4OsFilter)); + } + } +#else + prAisFsmInfo->u4AisPacketFilter = + prGlueInfo->u4OsMgmtFrameFilter; +#endif + } + + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + DBGLOG(INIT, INFO, "%s should stop now...\n", + KAL_GET_CURRENT_THREAD_NAME()); + break; + } + + fgNeedHwAccess = false; + +#if CFG_SUPPORT_SDIO_READ_WRITE_PATTERN + if (prGlueInfo->fgEnSdioTestPattern == true) { + if (fgNeedHwAccess == false) { + fgNeedHwAccess = true; + + wlanAcquirePowerControl(prGlueInfo->prAdapter); + } + + if (prGlueInfo->fgIsSdioTestInitialized == false) { + /* enable PRBS mode */ + kalDevRegWrite(prGlueInfo, MCR_WTMCR, + 0x00080002); + prGlueInfo->fgIsSdioTestInitialized = true; + } + + if (prGlueInfo->fgSdioReadWriteMode == true) { + /* read test */ + kalDevPortRead( + prGlueInfo, MCR_WTMDR, 256, + prGlueInfo->aucSdioTestBuffer, + sizeof(prGlueInfo->aucSdioTestBuffer)); + } else { + /* write test */ + kalDevPortWrite( + prGlueInfo, MCR_WTMDR, 172, + prGlueInfo->aucSdioTestBuffer, + sizeof(prGlueInfo->aucSdioTestBuffer)); + } + } +#endif + + /* transfer ioctl to OID request */ + do { + if (test_and_clear_bit(GLUE_FLAG_OID_BIT, + &prGlueInfo->ulFlag)) { + /* get current prIoReq */ + prIoReq = &(prGlueInfo->OidEntry); + if (prIoReq->fgRead == false) { + prIoReq->rStatus = wlanSetInformation( + prIoReq->prAdapter, + prIoReq->pfnOidHandler, + prIoReq->pvInfoBuf, + prIoReq->u4InfoBufLen, + prIoReq->pu4QryInfoLen); + } else { + prIoReq->rStatus = wlanQueryInformation( + prIoReq->prAdapter, + prIoReq->pfnOidHandler, + prIoReq->pvInfoBuf, + prIoReq->u4InfoBufLen, + prIoReq->pu4QryInfoLen); + } + + if (prIoReq->rStatus != WLAN_STATUS_PENDING) { + /* complete ONLY if there are waiters */ + if (!completion_done(&prGlueInfo->rPendComp)) { + complete(&prGlueInfo->rPendComp); + } else { + DBGLOG(INIT, + WARN, + "SKIP multiple OID complete!\n"); + } + } else { + wlanoidTimeoutCheck( + prGlueInfo->prAdapter, + prIoReq->pfnOidHandler, + prIoReq->u4Timeout); + } + } + } while (false); + + /* + * + * if TX request, clear the TXREQ flag. TXREQ set by + * kalSetEvent/GlueSetEvent indicates the following requests + * occur + * + */ + + if (test_and_clear_bit(GLUE_FLAG_TXREQ_BIT, + &prGlueInfo->ulFlag)) { + kalProcessTxReq(prGlueInfo, &fgNeedHwAccess); + } + /* Process RX */ + if (test_and_clear_bit(GLUE_FLAG_RX_BIT, &prGlueInfo->ulFlag)) { + nicRxProcessRFBs(prGlueInfo->prAdapter); + } + if (test_and_clear_bit(GLUE_FLAG_TX_CMD_DONE_BIT, + &prGlueInfo->ulFlag)) { + wlanTxCmdDoneMthread(prGlueInfo->prAdapter); + } + /* handle cnmTimer time out */ + if (test_and_clear_bit(GLUE_FLAG_TIMEOUT_BIT, + &prGlueInfo->ulFlag)) { + wlanTimerTimeoutCheck(prGlueInfo->prAdapter); + } +#if CFG_SUPPORT_SDIO_READ_WRITE_PATTERN + if (prGlueInfo->fgEnSdioTestPattern == true) { + kalSetEvent(prGlueInfo); + } +#endif + } + + /* flush the pending TX packets */ + if (GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum) > 0) { + kalFlushPendingTxPackets(prGlueInfo); + } + + /* flush pending security frames */ + if (GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum) > 0) { + kalClearSecurityFrames(prGlueInfo); + } + + /* remove pending oid */ + wlanReleasePendingOid(prGlueInfo->prAdapter, 0); + + complete(&prGlueInfo->rHaltComp); + + DBGLOG(INIT, INFO, "%s:%u stopped!\n", KAL_GET_CURRENT_THREAD_NAME(), + KAL_GET_CURRENT_THREAD_ID()); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to check if card is removed + * + * \param pvGlueInfo Pointer of GLUE Data Structure + * + * \retval true: card is removed + * false: card is still attached + */ +/*----------------------------------------------------------------------------*/ +u8 kalIsCardRemoved(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return false; + /* Linux MMC doesn't have removal notification yet */ +} + +#ifdef CONFIG_IDME +#define IDME_MACADDR "/proc/idme/mac_addr" +static int idme_get_mac_addr(unsigned char *mac_addr, size_t addr_len) +{ + unsigned char buf[IFHWADDRLEN * 2 + 1] = { "" }, str[3] = { "" }; + int i, mac[IFHWADDRLEN]; + mm_segment_t old_fs; + struct file *f; + size_t len; + + if (!mac_addr || addr_len < IFHWADDRLEN) { + DBGLOG(INIT, ERROR, "invalid mac_addr ptr or buf\n"); + return -1; + } + + f = filp_open(IDME_MACADDR, O_RDONLY, 0); + if (IS_ERR(f)) { + DBGLOG(INIT, ERROR, "can't open mac addr file\n"); + return -1; + } + + old_fs = get_fs(); +#if KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE + set_fs(KERNEL_DS); +#else + set_fs(get_ds()); +#endif + f->f_op->read(f, buf, IFHWADDRLEN * 2, &f->f_pos); + filp_close(f, NULL); + set_fs(old_fs); + + if (strlen(buf) != IFHWADDRLEN * 2) { + goto bailout; + } + + for (i = 0; i < IFHWADDRLEN; i++) { + str[0] = buf[i * 2]; + str[1] = buf[i * 2 + 1]; + if (!isxdigit(str[0]) || !isxdigit(str[1])) { + goto bailout; + } + len = sscanf(str, "%02x", &mac[i]); + if (len != 1) { + goto bailout; + } + } + for (i = 0; i < IFHWADDRLEN; i++) + mac_addr[i] = (unsigned char)mac[i]; + return 0; + +bailout: + DBGLOG(INIT, ERROR, "wrong mac addr %02x %02x\n", buf[0], buf[1]); + return -1; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to send command to firmware for overriding + * netweork address + * + * \param pvGlueInfo Pointer of GLUE Data Structure + * + * \retval true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 kalRetrieveNetworkAddress(IN P_GLUE_INFO_T prGlueInfo, + IN OUT PARAM_MAC_ADDRESS *prMacAddr) +{ + P_ADAPTER_T prAdapter; + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + + /* Get MAC address override from wlan feature option */ + prGlueInfo->fgIsMacAddrOverride = prAdapter->rWifiVar.ucMacAddrOverride; + + wlanHwAddrToBin(prAdapter->rWifiVar.aucMacAddrStr, + prGlueInfo->rMacAddrOverride); + +#ifdef CONFIG_IDME + if (prMacAddr && 0 == idme_get_mac_addr((unsigned char *)prMacAddr, + sizeof(PARAM_MAC_ADDRESS))) { + DBGLOG(INIT, INFO, "use IDME mac addr\n"); + return true; + } +#endif + + if (prGlueInfo->fgIsMacAddrOverride == false) { + u32 i; + u8 fgIsReadError = false; + +#if !defined(CONFIG_X86) + for (i = 0; i < MAC_ADDR_LEN; i += 2) { + if (kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, + aucMacAddress) + + i, + (u16 *)(((u8 *)prMacAddr) + i)) == + false) { + fgIsReadError = true; + break; + } + } +#else + /* x86 Linux doesn't need to override network address so far */ + /*return false;*/ + /*Modify for Linux PC support NVRAM Setting*/ + for (i = 0; i < MAC_ADDR_LEN; i += 2) { + if (kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, + aucMacAddress) + + i, + (u16 *)(((u8 *)prMacAddr) + i)) == + false) { + fgIsReadError = true; + break; + } + } +#endif + +#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 1) + /* retrieve buffer mode efuse */ + if (prAdapter->rWifiVar.ucEfuseBufferModeCal == + LOAD_EEPROM_BIN) { + if (wlanExtractBufferBin(prAdapter) == + WLAN_STATUS_SUCCESS) { + u32 u4BinOffset = + prAdapter->u4EfuseMacAddrOffset; + + /* Update MAC address */ + kalMemCopy(prMacAddr, + &uacEEPROMImage[u4BinOffset], + MAC_ADDR_LEN); + fgIsReadError = false; + } else { + fgIsReadError = true; + } + } +#endif + /* return retrieve result */ + if (fgIsReadError == true) { + return false; + }else{ + return true; + } + } else { + COPY_MAC_ADDR(prMacAddr, prGlueInfo->rMacAddrOverride); + + return true; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to flush pending TX packets in glue layer + * + * \param pvGlueInfo Pointer of GLUE Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void kalFlushPendingTxPackets(IN P_GLUE_INFO_T prGlueInfo) +{ + P_QUE_T prTxQue; + P_QUE_ENTRY_T prQueueEntry; + void *prPacket; +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK + P_QUE_T prTxLookBackQue; +#endif + ASSERT(prGlueInfo); + + prTxQue = &(prGlueInfo->rTxQueue); + + if (GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum) == 0) { + return; + } + + if (HAL_IS_TX_DIRECT()) { + nicTxDirectClearSkbQ(prGlueInfo->prAdapter); + } else { + GLUE_SPIN_LOCK_DECLARATION(); + + while (true) { + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + QUEUE_REMOVE_HEAD(prTxQue, prQueueEntry, P_QUE_ENTRY_T); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_QUE); + + if (prQueueEntry == NULL) { + break; + } + + prPacket = GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); + + kalSendComplete(prGlueInfo, prPacket, + WLAN_STATUS_NOT_ACCEPTED); + } + } + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK + /* Flush out look back queu */ + prTxLookBackQue = &(prGlueInfo->rTxLookBackQueue); + while (true) { + GLUE_SPIN_LOCK_DECLARATION(); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + QUEUE_REMOVE_HEAD(prTxLookBackQue, prQueueEntry, P_QUE_ENTRY_T); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + + if (prQueueEntry == NULL) { + break; + } + + prPacket = GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); + dev_kfree_skb(prPacket); + } +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is get indicated media state + * + * \param pvGlueInfo Pointer of GLUE Data Structure + * + * \retval + */ +/*----------------------------------------------------------------------------*/ +ENUM_PARAM_MEDIA_STATE_T kalGetMediaStateIndicated( + IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->eParamMediaStateIndicated; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to set indicated media state + * + * \param pvGlueInfo Pointer of GLUE Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void kalSetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_PARAM_MEDIA_STATE_T + eParamMediaStateIndicate) +{ + ASSERT(prGlueInfo); + + prGlueInfo->eParamMediaStateIndicated = eParamMediaStateIndicate; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to clear pending OID staying in command queue + * + * \param prGlueInfo Pointer of GLUE Data Structure + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void kalOidCmdClearance(IN P_GLUE_INFO_T prGlueInfo) +{ + P_QUE_T prCmdQue; + QUE_T rTempCmdQue; + P_QUE_T prTempCmdQue = &rTempCmdQue; + QUE_T rReturnCmdQue; + P_QUE_T prReturnCmdQue = &rReturnCmdQue; + P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T)NULL; + P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T)NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + QUEUE_INITIALIZE(prReturnCmdQue); + + prCmdQue = &prGlueInfo->rCmdQueue; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + while (prQueueEntry) { + if (((P_CMD_INFO_T)prQueueEntry)->fgIsOid) { + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + break; + } + QUEUE_INSERT_TAIL(prReturnCmdQue, prQueueEntry); + QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T); + } + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_CONCATENATE_QUEUES_HEAD(prCmdQue, prReturnCmdQue); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + + if (prCmdInfo) { + if (prCmdInfo->pfCmdTimeoutHandler) { + prCmdInfo->pfCmdTimeoutHandler(prGlueInfo->prAdapter, + prCmdInfo); + } else { + kalOidComplete(prGlueInfo, prCmdInfo->fgSetQuery, 0, + WLAN_STATUS_NOT_ACCEPTED); + } + + prGlueInfo->u4OidCompleteFlag = 1; + cmdBufFreeCmdInfo(prGlueInfo->prAdapter, prCmdInfo); + GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingCmdNum); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to insert command into prCmdQueue + * + * \param prGlueInfo Pointer of GLUE Data Structure + * prQueueEntry Pointer of queue entry to be inserted + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void kalEnqueueCommand(IN P_GLUE_INFO_T prGlueInfo, + IN P_QUE_ENTRY_T prQueueEntry) +{ + P_QUE_T prCmdQue; + P_CMD_INFO_T prCmdInfo; + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + ASSERT(prQueueEntry); + + prCmdQue = &prGlueInfo->rCmdQueue; + + prCmdInfo = (P_CMD_INFO_T)prQueueEntry; + + DBGLOG(INIT, INFO, "EN-Q CMD TYPE[%u] ID[0x%02X] SEQ[%u] to CMD Q\n", + prCmdInfo->eCmdType, prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); + QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry); + GLUE_INC_REF_CNT(prGlueInfo->i4TxPendingCmdNum); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_CMD_QUE); +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Handle EVENT_ID_ASSOC_INFO event packet by indicating to OS with + * proper information + * + * @param pvGlueInfo Pointer of GLUE Data Structure + * @param prAssocInfo Pointer of EVENT_ID_ASSOC_INFO Packet + * + * @return none + */ +/*----------------------------------------------------------------------------*/ +void kalHandleAssocInfo(IN P_GLUE_INFO_T prGlueInfo, + IN P_EVENT_ASSOC_INFO prAssocInfo) +{ + /* to do */ +} + +/*----------------------------------------------------------------------------*/ +/*! +** @brief Notify OS with SendComplete event of the specific packet. Linux should +** free packets here. +** +** @param pvGlueInfo Pointer of GLUE Data Structure +** @param pvPacket Pointer of Packet Handle +** @param status Status Code for OS upper layer +** +** @return none +*/ +/*----------------------------------------------------------------------------*/ + +/* / Todo */ +void kalSecurityFrameSendComplete(IN P_GLUE_INFO_T prGlueInfo, + IN void *pvPacket, + IN WLAN_STATUS rStatus) +{ + ASSERT(pvPacket); + + /* dev_kfree_skb((struct sk_buff *) pvPacket); */ + kalSendCompleteAndAwakeQueue(prGlueInfo, pvPacket); + GLUE_DEC_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); +} + +u32 kalGetTxPendingFrameCount(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return (u32)(GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum)); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to retrieve the number of pending commands + * (including MMPDU, 802.1X and command packets) + * + * \param prGlueInfo Pointer of GLUE Data Structure + * + * \retval + */ +/*----------------------------------------------------------------------------*/ +u32 kalGetTxPendingCmdCount(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return (u32)GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingCmdNum); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Timer Initialization Procedure + * + * \param[in] prGlueInfo Pointer to GLUE Data Structure + * \param[in] prTimerHandler Pointer to timer handling function, whose only + * argument is "prAdapter" + * + * \retval none + * + */ +/*----------------------------------------------------------------------------*/ + +/* static struct timer_list tickfn; */ + +void kalOsTimerInitialize(IN P_GLUE_INFO_T prGlueInfo, + IN void *prTimerHandler) +{ + ASSERT(prGlueInfo); + +#if KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE + timer_setup(&(prGlueInfo->tickfn), prTimerHandler, 0); +#else + init_timer(&(prGlueInfo->tickfn)); + prGlueInfo->tickfn.function = prTimerHandler; + prGlueInfo->tickfn.data = (unsigned long)prGlueInfo; +#endif +} + +/* Todo */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set the time to do the time out check. + * + * \param[in] prGlueInfo Pointer to GLUE Data Structure + * \param[in] rInterval Time out interval from current time. + * + * \retval true Success. + */ +/*----------------------------------------------------------------------------*/ +u8 kalSetTimer(IN P_GLUE_INFO_T prGlueInfo, IN u32 u4Interval) +{ + ASSERT(prGlueInfo); + + if (HAL_IS_RX_DIRECT(prGlueInfo->prAdapter)) { + mod_timer(&prGlueInfo->tickfn, + jiffies + u4Interval * HZ / MSEC_PER_SEC); + } else { + timer_delete_sync(&(prGlueInfo->tickfn)); + + prGlueInfo->tickfn.expires = + jiffies + u4Interval * HZ / MSEC_PER_SEC; + add_timer(&(prGlueInfo->tickfn)); + } + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to cancel + * + * \param[in] prGlueInfo Pointer to GLUE Data Structure + * + * \retval true : Timer has been canceled + * FALAE : Timer doens't exist + */ +/*----------------------------------------------------------------------------*/ +u8 kalCancelTimer(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + clear_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->ulFlag); + + if (timer_delete_sync(&(prGlueInfo->tickfn)) >= 0) { + return true; + }else{ + return false; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is a callback function for scanning done + * + * \param[in] prGlueInfo Pointer to GLUE Data Structure + * + * \retval none + * + */ +/*----------------------------------------------------------------------------*/ +void kalScanDone(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN WLAN_STATUS status) +{ + ASSERT(prGlueInfo); + + scanReportBss2Cfg80211(prGlueInfo->prAdapter, BSS_TYPE_INFRASTRUCTURE, + NULL); + + /* check for system configuration for generating error message on scan + * list */ + wlanCheckSystemConfiguration(prGlueInfo->prAdapter); + + kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, + NULL, 0); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to generate a random number + * + * \param none + * + * \retval u32 + */ +/*----------------------------------------------------------------------------*/ +u32 kalRandomNumber(void) +{ + u32 number = 0; + + get_random_bytes(&number, 4); + + return number; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief command timeout call-back function + * + * \param[in] prGlueInfo Pointer to the GLUE data structure. + * + * \retval (none) + */ +/*----------------------------------------------------------------------------*/ +#if KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE +void kalTimeoutHandler(struct timer_list *timer) +#else +void kalTimeoutHandler(unsigned long arg) +#endif +{ +#if KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE + P_GLUE_INFO_T prGlueInfo = from_timer(prGlueInfo, timer, tickfn); +#else + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)arg; +#endif + + ASSERT(prGlueInfo); + + /* Notify tx thread for timeout event */ + set_bit(GLUE_FLAG_TIMEOUT_BIT, &prGlueInfo->ulFlag); + wake_up_interruptible(&prGlueInfo->waitq); +} + +void kalSetEvent(P_GLUE_INFO_T pr) +{ + set_bit(GLUE_FLAG_TXREQ_BIT, &pr->ulFlag); + wake_up_interruptible(&pr->waitq); +} + +void kalSetIntEvent(P_GLUE_INFO_T pr) +{ + set_bit(GLUE_FLAG_INT_BIT, &pr->ulFlag); + + /* when we got interrupt, we wake up servie thread */ + wake_up_interruptible(&pr->waitq_hif); +} + +void kalSetTxEvent2Hif(P_GLUE_INFO_T pr) +{ + if (!pr->hif_thread) { + return; + } + + set_bit(GLUE_FLAG_HIF_TX_BIT, &pr->ulFlag); + wake_up_interruptible(&pr->waitq_hif); +} + +void kalSetFwOwnEvent2Hif(P_GLUE_INFO_T pr) +{ + if (!pr->hif_thread) { + return; + } + + set_bit(GLUE_FLAG_HIF_FW_OWN_BIT, &pr->ulFlag); + wake_up_interruptible(&pr->waitq_hif); +} + +void kalSetTxEvent2Rx(P_GLUE_INFO_T pr) +{ + if (!pr->rx_thread) { + return; + } + + set_bit(GLUE_FLAG_RX_TO_OS_BIT, &pr->ulFlag); + wake_up_interruptible(&pr->waitq_rx); +} + +void kalSetTxCmdEvent2Hif(P_GLUE_INFO_T pr) +{ + if (!pr->hif_thread) { + return; + } + + set_bit(GLUE_FLAG_HIF_TX_CMD_BIT, &pr->ulFlag); + wake_up_interruptible(&pr->waitq_hif); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to check if configuration file (NVRAM/Registry) exists + * + * \param[in] + * prGlueInfo + * + * \return + * true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 kalIsConfigurationExist(IN P_GLUE_INFO_T prGlueInfo) +{ +#if !defined(CONFIG_X86) + ASSERT(prGlueInfo); + + return prGlueInfo->fgNvramAvailable; + +#else + /* there is no configuration data for x86-linux */ + /*return false;*/ + + /*Modify for Linux PC support NVRAM Setting*/ + return prGlueInfo->fgNvramAvailable; + +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to retrieve Registry information + * + * \param[in] + * prGlueInfo + * + * \return + * Pointer of REG_INFO_T + */ +/*----------------------------------------------------------------------------*/ +P_REG_INFO_T kalGetConfiguration(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return &(prGlueInfo->rRegInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to retrieve version information of corresponding configuration file + * + * \param[in] + * prGlueInfo + * + * \param[out] + * pu2Part1CfgOwnVersion + * pu2Part1CfgPeerVersion + * pu2Part2CfgOwnVersion + * pu2Part2CfgPeerVersion + * + * \return + * NONE + */ +/*----------------------------------------------------------------------------*/ +void kalGetConfigurationVersion(IN P_GLUE_INFO_T prGlueInfo, + OUT u16 *pu2Part1CfgOwnVersion, + OUT u16 *pu2Part1CfgPeerVersion, + OUT u16 *pu2Part2CfgOwnVersion, + OUT u16 *pu2Part2CfgPeerVersion) +{ + ASSERT(prGlueInfo); + + ASSERT(pu2Part1CfgOwnVersion); + ASSERT(pu2Part1CfgPeerVersion); + ASSERT(pu2Part2CfgOwnVersion); + ASSERT(pu2Part2CfgPeerVersion); + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part1OwnVersion), + pu2Part1CfgOwnVersion); + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part1PeerVersion), + pu2Part1CfgPeerVersion); + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2OwnVersion), + pu2Part2CfgOwnVersion); + + kalCfgDataRead16(prGlueInfo, + OFFSET_OF(WIFI_CFG_PARAM_STRUCT, u2Part2PeerVersion), + pu2Part2CfgPeerVersion); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to check if the WPS is active or not + * + * \param[in] + * prGlueInfo + * + * \return + * true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 kalWSCGetActiveState(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->fgWpsActive; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief update RSSI and LinkQuality to GLUE layer + * + * \param[in] + * prGlueInfo + * eNetTypeIdx + * cRssi + * cLinkQuality + * + * \return + * None + */ +/*----------------------------------------------------------------------------*/ +void kalUpdateRSSI(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN s8 cRssi, + IN s8 cLinkQuality) +{ + struct iw_statistics *pStats = (struct iw_statistics *)NULL; + + ASSERT(prGlueInfo); + + switch (eNetTypeIdx) { + case KAL_NETWORK_TYPE_AIS_INDEX: + pStats = (struct iw_statistics *)(&(prGlueInfo->rIwStats)); + break; + +#if CFG_ENABLE_WIFI_DIRECT +#if CFG_SUPPORT_P2P_RSSI_QUERY + case KAL_NETWORK_TYPE_P2P_INDEX: + pStats = (struct iw_statistics *)(&(prGlueInfo->rP2pIwStats)); + break; + +#endif +#endif + default: + break; + } + + if (pStats) { + pStats->qual.qual = cLinkQuality; + pStats->qual.noise = 0; + pStats->qual.updated = IW_QUAL_QUAL_UPDATED | + IW_QUAL_NOISE_UPDATED; + pStats->qual.level = 0x100 + cRssi; + pStats->qual.updated |= IW_QUAL_LEVEL_UPDATED; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Pre-allocate I/O buffer + * + * \param[in] + * none + * + * \return + * true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 kalInitIOBuffer(u8 is_pre_alloc) +{ + u32 u4Size; + + /* not pre-allocation for all memory usage */ + if (!is_pre_alloc) { + pvIoBuffer = NULL; + return false; + } + + /* pre-allocation for all memory usage */ + if (HIF_TX_COALESCING_BUFFER_SIZE > HIF_RX_COALESCING_BUFFER_SIZE) { + u4Size = HIF_TX_COALESCING_BUFFER_SIZE; + }else{ + u4Size = HIF_RX_COALESCING_BUFFER_SIZE; + } + + u4Size += HIF_EXTRA_IO_BUFFER_SIZE; + + pvIoBuffer = kmalloc(u4Size, GFP_KERNEL); + if (pvIoBuffer) { + pvIoBufferSize = u4Size; + pvIoBufferUsage = 0; + + return true; + } + + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Free pre-allocated I/O buffer + * + * \param[in] + * none + * + * \return + * none + */ +/*----------------------------------------------------------------------------*/ +void kalUninitIOBuffer(void) +{ + kfree(pvIoBuffer); + + pvIoBuffer = (void *)NULL; + pvIoBufferSize = 0; + pvIoBufferUsage = 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Dispatch pre-allocated I/O buffer + * + * \param[in] + * u4AllocSize + * + * \return + * void * for pointer of pre-allocated I/O buffer + */ +/*----------------------------------------------------------------------------*/ +void *kalAllocateIOBuffer(IN u32 u4AllocSize) +{ + void *ret = (void *)NULL; + + if (pvIoBuffer) { + if (u4AllocSize <= (pvIoBufferSize - pvIoBufferUsage)) { + ret = (void *)&(((u8 *)(pvIoBuffer))[pvIoBufferUsage]); + pvIoBufferUsage += u4AllocSize; + } + } else { + /* fault tolerance */ + ret = (void *)kalMemAlloc(u4AllocSize, PHY_MEM_TYPE); + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Release all dispatched I/O buffer + * + * \param[in] + * none + * + * \return + * none + */ +/*----------------------------------------------------------------------------*/ +void kalReleaseIOBuffer(IN void *pvAddr, IN u32 u4Size) +{ + if (pvIoBuffer) { + pvIoBufferUsage -= u4Size; + } else { + /* fault tolerance */ + kalMemFree(pvAddr, PHY_MEM_TYPE, u4Size); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] prAdapter Pointer of ADAPTER_T + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void kalGetChannelList(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_BAND_T eSpecificBand, IN u8 ucMaxChannelNum, + IN u8 *pucNumOfChannel, + IN P_RF_CHANNEL_INFO_T paucChannelList) +{ + rlmDomainGetChnlList(prGlueInfo->prAdapter, eSpecificBand, false, + ucMaxChannelNum, pucNumOfChannel, paucChannelList); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] prAdapter Pointer of ADAPTER_T + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +u8 kalIsAPmode(IN P_GLUE_INFO_T prGlueInfo) +{ + return false; +} + +#if CFG_SUPPORT_802_11W +/*----------------------------------------------------------------------------*/ +/*! + * \brief to check if the MFP is active or not + * + * \param[in] + * prGlueInfo + * + * \return + * true + * false + */ +/*----------------------------------------------------------------------------*/ +u32 kalGetMfpSetting(IN P_GLUE_INFO_T prGlueInfo) +{ + u32 u4RsnMfp = RSN_AUTH_MFP_DISABLED; + + ASSERT(prGlueInfo); + + switch (prGlueInfo->rWpaInfo.u4Mfp) { + case IW_AUTH_MFP_DISABLED: + u4RsnMfp = RSN_AUTH_MFP_DISABLED; + break; + + case IW_AUTH_MFP_OPTIONAL: + u4RsnMfp = RSN_AUTH_MFP_OPTIONAL; + break; + + case IW_AUTH_MFP_REQUIRED: + u4RsnMfp = RSN_AUTH_MFP_REQUIRED; + break; + + default: + u4RsnMfp = RSN_AUTH_MFP_DISABLED; + break; + } + + return u4RsnMfp; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to check if the RSN IE CAP setting from supplicant + * + * \param[in] + * prGlueInfo + * + * \return + * true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 kalGetRsnIeMfpCap(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->rWpaInfo.ucRSNMfpCap; +} +#endif + +struct file *kalFileOpen(const char *path, int flags, int rights) +{ + struct file *filp = NULL; +#ifdef set_fs + mm_segment_t oldfs; +#endif + int err = 0; + +#ifdef set_fs + oldfs = get_fs(); + set_fs(KERNEL_DS); +#endif + filp = filp_open(path, flags, rights); + +#ifdef set_fs + set_fs(oldfs); +#endif + if (IS_ERR(filp)) { + err = PTR_ERR(filp); + return NULL; + } + return filp; +} + +void kalFileClose(struct file *file) +{ + filp_close(file, NULL); +} + +u32 kalFileRead(struct file *file, unsigned long long offset, + unsigned char *data, unsigned int size) +{ +#if KERNEL_VERSION(4, 14, 0) <= CFG80211_VERSION_CODE + return kernel_read(file, data, size, (loff_t *)&offset); + +#else + mm_segment_t oldfs; + int ret; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + ret = vfs_read(file, data, size, &offset); + + set_fs(oldfs); + return ret; + +#endif +} + +u32 kalFileWrite(struct file *file, unsigned long long offset, + unsigned char *data, unsigned int size) +{ +#if KERNEL_VERSION(4, 14, 0) <= CFG80211_VERSION_CODE + return kernel_write(file, data, size, (loff_t *)&offset); + +#else + mm_segment_t oldfs; + int ret; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + ret = vfs_write(file, data, size, &offset); + + set_fs(oldfs); + return ret; + +#endif +} + +u32 kalWriteToFile(const u8 *pucPath, u8 fgDoAppend, u8 *pucData, + u32 u4Size) +{ + struct file *file = NULL; + u32 ret = 0; /* size been written */ + u32 u4Flags = 0; + + if (fgDoAppend) { + u4Flags = O_APPEND; + } + + file = kalFileOpen(pucPath, O_WRONLY | O_CREAT | u4Flags, S_IRWXU); + if (file) { + ret = kalFileWrite(file, 0, pucData, u4Size); + kalFileClose(file); + } + + return ret; +} + +s32 kalReadToFile(const u8 *pucPath, u8 *pucData, u32 u4Size, + u32 *pu4ReadSize) +{ + struct file *file = NULL; + s32 ret = -1; + u32 u4ReadSize = 0; + + DBGLOG(INIT, INFO, "kalReadToFile() path %s\n", pucPath); + + file = kalFileOpen(pucPath, O_RDONLY, 0); + + if ((file != NULL) && !IS_ERR(file)) { + u4ReadSize = kalFileRead(file, 0, pucData, u4Size); + kalFileClose(file); + if (pu4ReadSize) { + *pu4ReadSize = u4ReadSize; + } + ret = 0; + } + return ret; +} + +u32 kalCheckPath(const u8 *pucPath) +{ + struct file *file = NULL; + u32 u4Flags = 0; + + file = kalFileOpen(pucPath, O_WRONLY | O_CREAT | u4Flags, S_IRWXU); + if (!file) { + return -1; + } + + kalFileClose(file); + return 1; +} + +u32 kalTrunkPath(const u8 *pucPath) +{ + struct file *file = NULL; + u32 u4Flags = O_TRUNC; + + file = kalFileOpen(pucPath, O_WRONLY | O_CREAT | u4Flags, S_IRWXU); + if (!file) { + return -1; + } + + kalFileClose(file); + return 1; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief read request firmware file binary to pucData + * + * \param[in] pucPath file name + * \param[out] pucData Request file output buffer + * \param[in] u4Size read size + * \param[out] pu4ReadSize real read size + * \param[in] dev + * + * \return + * 0 success + * >0 fail + */ +/*----------------------------------------------------------------------------*/ +s32 kalRequestFirmware(const u8 *pucPath, u8 *pucData, u32 u4Size, + u32 *pu4ReadSize, struct device *dev) +{ + const struct firmware *fw; + int ret = 0; + + /* + * Driver support request_firmware() to get files + * Android path: "/etc/firmware", "/vendor/firmware", "/firmware/image" + * Linux path: "/lib/firmware", "/lib/firmware/update" + */ + ret = REQUEST_FIRMWARE(&fw, pucPath, dev); + + if (ret != 0) { + DBGLOG(INIT, INFO, "kalRequestFirmware %s Fail, errno[%d]!!\n", + pucPath, ret); + pucData = NULL; + *pu4ReadSize = 0; + release_firmware(fw); + return ret; + } + + DBGLOG(INIT, INFO, "kalRequestFirmware(): %s OK\n", pucPath); + + if (fw->size < u4Size) { + u4Size = fw->size; + } + + memcpy(pucData, fw->data, u4Size); + if (pu4ReadSize) { + *pu4ReadSize = u4Size; + } + + release_firmware(fw); + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To indicate BSS-INFO to NL80211 as scanning result + * + * \param[in] + * prGlueInfo + * pucBeaconProbeResp + * u4FrameLen + * + * + * + * \return + * none + */ +/*----------------------------------------------------------------------------*/ +void kalIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, + IN u8 *pucBeaconProbeResp, + IN u32 u4FrameLen, IN u8 ucChannelNum, + IN s32 i4SignalStrength) +{ + struct wiphy *wiphy; + struct ieee80211_channel *prChannel = NULL; + + ASSERT(prGlueInfo); + wiphy = priv_to_wiphy(prGlueInfo); + + /* search through channel entries */ + if (ucChannelNum <= 14) { + prChannel = ieee80211_get_channel( + wiphy, ieee80211_channel_to_frequency( + ucChannelNum, NL80211_BAND_2GHZ)); + } else { + prChannel = ieee80211_get_channel( + wiphy, ieee80211_channel_to_frequency( + ucChannelNum, NL80211_BAND_5GHZ)); + } + + if (prChannel != NULL && prGlueInfo->fgIsRegistered == true) { + struct cfg80211_bss *bss; +#if CFG_SUPPORT_TSF_USING_BOOTTIME + struct ieee80211_mgmt *prMgmtFrame = + (struct ieee80211_mgmt *)pucBeaconProbeResp; + + prMgmtFrame->u.beacon.timestamp = kalGetBootTime(); +#endif + + /* indicate to NL80211 subsystem */ + bss = cfg80211_inform_bss_frame( + wiphy, prChannel, + (struct ieee80211_mgmt *)pucBeaconProbeResp, u4FrameLen, + i4SignalStrength * 100, GFP_KERNEL); + + if (!bss) { + DBGLOG(REQ, + WARN, + "cfg80211_inform_bss_frame() returned with NULL\n"); + } else { + cfg80211_put_bss(wiphy, bss); + } + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To indicate channel ready + * + * \param[in] + * prGlueInfo + * + * \return + * none + */ +/*----------------------------------------------------------------------------*/ +void kalReadyOnChannel(IN P_GLUE_INFO_T prGlueInfo, IN u64 u8Cookie, + IN ENUM_BAND_T eBand, IN ENUM_CHNL_EXT_T eSco, + IN u8 ucChannelNum, IN u32 u4DurationMs) +{ + struct ieee80211_channel *prChannel = NULL; + enum nl80211_channel_type rChannelType; + + /* ucChannelNum = wlanGetChannelNumberByNetwork(prGlueInfo->prAdapter, + * NETWORK_TYPE_AIS_INDEX); */ + + if (prGlueInfo->fgIsRegistered == true) { + if (ucChannelNum <= 14) { + prChannel = ieee80211_get_channel( + priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency( + ucChannelNum, NL80211_BAND_2GHZ)); + } else { + prChannel = ieee80211_get_channel( + priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency( + ucChannelNum, NL80211_BAND_5GHZ)); + } + + if (!prChannel) { + DBGLOG(INIT, ERROR, "ieee80211_get_channel fail!\n"); + return; + } + + switch (eSco) { + case CHNL_EXT_SCN: + rChannelType = NL80211_CHAN_NO_HT; + break; + + case CHNL_EXT_SCA: + rChannelType = NL80211_CHAN_HT40MINUS; + break; + + case CHNL_EXT_SCB: + rChannelType = NL80211_CHAN_HT40PLUS; + break; + + case CHNL_EXT_RES: + default: + rChannelType = NL80211_CHAN_HT20; + break; + } + + cfg80211_ready_on_channel( + prGlueInfo->prDevHandler->ieee80211_ptr, u8Cookie, + prChannel, u4DurationMs, GFP_KERNEL); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To indicate channel expiration + * + * \param[in] + * prGlueInfo + * + * \return + * none + */ +/*----------------------------------------------------------------------------*/ +void kalRemainOnChannelExpired(IN P_GLUE_INFO_T prGlueInfo, IN u64 u8Cookie, + IN ENUM_BAND_T eBand, + IN ENUM_CHNL_EXT_T eSco, + IN u8 ucChannelNum) +{ + struct ieee80211_channel *prChannel = NULL; + enum nl80211_channel_type rChannelType; + + ucChannelNum = wlanGetChannelNumberByNetwork( + prGlueInfo->prAdapter, + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex); + + if (prGlueInfo->fgIsRegistered == true) { + if (ucChannelNum <= 14) { + prChannel = ieee80211_get_channel( + priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency( + ucChannelNum, NL80211_BAND_2GHZ)); + } else { + prChannel = ieee80211_get_channel( + priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency( + ucChannelNum, NL80211_BAND_5GHZ)); + } + + if (!prChannel) { + DBGLOG(INIT, ERROR, "ieee80211_get_channel fail!\n"); + return; + } + + switch (eSco) { + case CHNL_EXT_SCN: + rChannelType = NL80211_CHAN_NO_HT; + break; + + case CHNL_EXT_SCA: + rChannelType = NL80211_CHAN_HT40MINUS; + break; + + case CHNL_EXT_SCB: + rChannelType = NL80211_CHAN_HT40PLUS; + break; + + case CHNL_EXT_RES: + default: + rChannelType = NL80211_CHAN_HT20; + break; + } + + cfg80211_remain_on_channel_expired( + prGlueInfo->prDevHandler->ieee80211_ptr, u8Cookie, + prChannel, GFP_KERNEL); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To indicate Mgmt tx status + * + * \param[in] + * prGlueInfo + * + * \return + * none + */ +/*----------------------------------------------------------------------------*/ +void kalIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, IN u64 u8Cookie, + IN u8 fgIsAck, IN u8 *pucFrameBuf, + IN u32 u4FrameLen) +{ + do { + if ((prGlueInfo == NULL) || (pucFrameBuf == NULL) || + (u4FrameLen == 0)) { + DBGLOG(AIS, TRACE, + "Unexpected pointer PARAM. 0x%lx, 0x%lx, %ld.", + prGlueInfo, pucFrameBuf, u4FrameLen); + ASSERT(false); + break; + } + + cfg80211_mgmt_tx_status(prGlueInfo->prDevHandler->ieee80211_ptr, + u8Cookie, pucFrameBuf, u4FrameLen, + fgIsAck, GFP_KERNEL); + } while (false); +} + +void kalIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, + IN P_SW_RFB_T prSwRfb) +{ + s32 i4Freq = 0; + u8 ucChnlNum = 0; + + do { + if ((prGlueInfo == NULL) || (prSwRfb == NULL)) { + ASSERT(false); + break; + } + + ucChnlNum = (u8)HAL_RX_STATUS_GET_CHNL_NUM(prSwRfb->prRxStatus); + i4Freq = nicChannelNum2Freq(ucChnlNum) / 1000; + + cfg80211_rx_mgmt(prGlueInfo->prDevHandler->ieee80211_ptr, + i4Freq, /* in MHz */ + RCPI_TO_dBm((u8)nicRxGetRcpiValueFromRxv( + RCPI_MODE_WF0, prSwRfb)), + prSwRfb->pvHeader, prSwRfb->u2PacketLen, + NL80211_RXMGMT_FLAG_ANSWERED); + } while (false); +} + +#if CFG_SUPPORT_SDIO_READ_WRITE_PATTERN +/*----------------------------------------------------------------------------*/ +/*! + * \brief To configure SDIO test pattern mode + * + * \param[in] + * prGlueInfo + * fgEn + * fgRead + * + * \return + * true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 kalSetSdioTestPattern(IN P_GLUE_INFO_T prGlueInfo, IN u8 fgEn, + IN u8 fgRead) +{ + const u8 aucPattern[] = { + 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, + 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, + 0x80, 0x7f, 0x7f, 0x7f, 0x40, 0x40, 0x40, 0xbf, 0x40, 0x40, + 0x40, 0xbf, 0xbf, 0xbf, 0x40, 0xbf, 0xbf, 0xbf, 0x20, 0x20, + 0x20, 0xdf, 0x20, 0x20, 0x20, 0xdf, 0xdf, 0xdf, 0x20, 0xdf, + 0xdf, 0xdf, 0x10, 0x10, 0x10, 0xef, 0x10, 0x10, 0x10, 0xef, + 0xef, 0xef, 0x10, 0xef, 0xef, 0xef, 0x08, 0x08, 0x08, 0xf7, + 0x08, 0x08, 0x08, 0xf7, 0xf7, 0xf7, 0x08, 0xf7, 0xf7, 0xf7, + 0x04, 0x04, 0x04, 0xfb, 0x04, 0x04, 0x04, 0xfb, 0xfb, 0xfb, + 0x04, 0xfb, 0xfb, 0xfb, 0x02, 0x02, 0x02, 0xfd, 0x02, 0x02, + 0x02, 0xfd, 0xfd, 0xfd, 0x02, 0xfd, 0xfd, 0xfd, 0x01, 0x01, + 0x01, 0xfe, 0x01, 0x01, 0x01, 0xfe, 0xfe, 0xfe, 0x01, 0xfe, + 0xfe, 0xfe, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0xff + }; + u32 i; + + ASSERT(prGlueInfo); + + /* access to MCR_WTMCR to engage PRBS mode */ + prGlueInfo->fgEnSdioTestPattern = fgEn; + prGlueInfo->fgSdioReadWriteMode = fgRead; + + if (fgRead == false) { + /* fill buffer for data to be written */ + for (i = 0; i < sizeof(aucPattern); i++) + prGlueInfo->aucSdioTestBuffer[i] = aucPattern[i]; + } + + return true; +} +#endif + +#if (CFG_MET_PACKET_TRACE_SUPPORT == 1) +#define PROC_MET_PROF_CTRL "met_ctrl" +#define PROC_MET_PROF_PORT "met_port" + +struct proc_dir_entry *pMetProcDir; +void *pMetGlobalData = NULL; + +#endif +/*----------------------------------------------------------------------------*/ +/*! + * \brief To indicate scheduled scan results are avilable + * + * \param[in] + * prGlueInfo + * + * \return + * None + */ +/*----------------------------------------------------------------------------*/ +void kalSchedScanResults(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + +#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE + cfg80211_sched_scan_results(priv_to_wiphy(prGlueInfo), + prGlueInfo->prSchedScanRequest->reqid); +#else + cfg80211_sched_scan_results(priv_to_wiphy(prGlueInfo)); +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To indicate scheduled scan has been stopped + * + * \param[in] + * prGlueInfo + * + * \return + * None + */ +/*----------------------------------------------------------------------------*/ +void kalSchedScanStopped(IN P_GLUE_INFO_T prGlueInfo) +{ + /* DBGLOG(SCN, INFO, ("-->kalSchedScanStopped\n" )); */ + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + /* 1. reset first for newly incoming request */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if (prGlueInfo->prSchedScanRequest != NULL) { + prGlueInfo->prSchedScanRequest = NULL; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + DBGLOG(SCN, INFO, "cfg80211_sched_scan_stopped send event\n"); + + /* 2. indication to cfg80211 */ + /* 20150205 change cfg80211_sched_scan_stopped to work queue to use K + * thread to send event instead of Tx thread due to sched_scan_mtx dead + * lock issue by Tx thread serves oid cmds and send event in the same + * time + */ + DBGLOG(SCN, INFO, "start work queue to send event\n"); + schedule_delayed_work(&sched_workq, 0); + DBGLOG(SCN, INFO, "main_thread return from kalSchedScanStoppped\n"); +} + +void kalWDevLockThread(IN P_GLUE_INFO_T prGlueInfo, + IN struct net_device *pDev, + IN enum ENUM_CFG80211_WDEV_LOCK_FUNC fn, + IN u8 *pFrameBuf, IN size_t frameLen, + IN struct cfg80211_bss *pBss, IN s32 uapsd_queues, + const u8 *req_ies, size_t req_ies_len, + IN u8 fgIsInterruptContext) +{ + P_PARAM_WDEV_LOCK_THREAD_T pParamWDevLock = NULL; + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prGlueInfo); + + DBGLOG(REQ, INFO, "kalWDevLockThread\n"); + + if (in_interrupt() && fgIsInterruptContext) { + DBGLOG(REQ, + STATE, + "pParamWDevLock is allocated as PHY_MEM_TYPE in intr context\n"); + pParamWDevLock = (P_PARAM_WDEV_LOCK_THREAD_T)kalMemAlloc( + sizeof(PARAM_WDEV_LOCK_THREAD_T), PHY_MEM_TYPE); + } else { + pParamWDevLock = (P_PARAM_WDEV_LOCK_THREAD_T)kalMemAlloc( + sizeof(PARAM_WDEV_LOCK_THREAD_T), VIR_MEM_TYPE); + } + + if (pParamWDevLock == NULL) { + DBGLOG(REQ, ERROR, "pParamWDevLock Alloc Failed\n"); + return; + } + + pParamWDevLock->pDev = pDev; + pParamWDevLock->fn = fn; + pParamWDevLock->pFrameBuf = pFrameBuf; + pParamWDevLock->frameLen = frameLen; + pParamWDevLock->req_ies = req_ies; + pParamWDevLock->req_ies_len = req_ies_len; + pParamWDevLock->fgIsInterruptContext = fgIsInterruptContext; + if (pBss) { + cfg80211_ref_bss(priv_to_wiphy(prGlueInfo), pBss); + pParamWDevLock->pBss = pBss; + } else { + pParamWDevLock->pBss = NULL; + } + pParamWDevLock->uapsd_queues = uapsd_queues; + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_WDEV_LOCK); + QUEUE_INSERT_TAIL(&prGlueInfo->prAdapter->rWDevLockQueue, + &pParamWDevLock->rQueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_WDEV_LOCK); + + if (!schedule_delayed_work(&wdev_lock_workq, 0)) { + DBGLOG(REQ, INFO, "work is already in wdev_lock_workq\n"); + } +} + +u8 kalGetIPv4Address(IN struct net_device *prDev, IN u32 u4MaxNumOfAddr, + OUT u8 *pucIpv4Addrs, OUT u32 *pu4NumOfIpv4Addr) +{ + u32 u4NumIPv4 = 0; + u32 u4AddrLen = IPV4_ADDR_LEN; + struct in_ifaddr *prIfa; + + /* 4 <1> Sanity check of netDevice */ + if (!prDev || !(prDev->ip_ptr) || + !((struct in_device *)(prDev->ip_ptr))->ifa_list) { + DBGLOG(INIT, INFO, + "IPv4 address is not available for dev(0x%p)\n", prDev); + + *pu4NumOfIpv4Addr = 0; + return false; + } + + prIfa = ((struct in_device *)(prDev->ip_ptr))->ifa_list; + + /* 4 <2> copy the IPv4 address */ + while ((u4NumIPv4 < u4MaxNumOfAddr) && prIfa) { + kalMemCopy(&pucIpv4Addrs[u4NumIPv4 * u4AddrLen], + &prIfa->ifa_local, u4AddrLen); + prIfa = prIfa->ifa_next; + + DBGLOG(INIT, INFO, "IPv4 addr [%u][" IPV4STR "]\n", u4NumIPv4, + IPV4TOSTR(&pucIpv4Addrs[u4NumIPv4 * u4AddrLen])); + + u4NumIPv4++; + } + + *pu4NumOfIpv4Addr = u4NumIPv4; + + return true; +} + +#if IS_ENABLED(CONFIG_IPV6) +u8 kalGetIPv6Address(IN struct net_device *prDev, IN u32 u4MaxNumOfAddr, + OUT u8 *pucIpv6Addrs, OUT u32 *pu4NumOfIpv6Addr) +{ + u32 u4NumIPv6 = 0; + u32 u4AddrLen = IPV6_ADDR_LEN; + struct inet6_ifaddr *prIfa; + + /* 4 <1> Sanity check of netDevice */ + if (!prDev || !(prDev->ip6_ptr)) { + DBGLOG(INIT, INFO, + "IPv6 address is not available for dev(0x%p)\n", prDev); + + *pu4NumOfIpv6Addr = 0; + return false; + } + + /* 4 <2> copy the IPv6 address */ + LIST_FOR_EACH_IPV6_ADDR(prIfa, prDev->ip6_ptr) { + kalMemCopy(&pucIpv6Addrs[u4NumIPv6 * u4AddrLen], &prIfa->addr, + u4AddrLen); + + DBGLOG(INIT, INFO, "IPv6 addr [%u][" IPV6STR "]\n", u4NumIPv6, + IPV6TOSTR(&pucIpv6Addrs[u4NumIPv6 * u4AddrLen])); + + if ((u4NumIPv6 + 1) >= u4MaxNumOfAddr) { + break; + } + u4NumIPv6++; + } + + *pu4NumOfIpv6Addr = u4NumIPv6; + + return true; +} +#endif + +void kalSetNetAddress(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucBssIdx, + IN u8 *pucIPv4Addr, IN u32 u4NumIPv4Addr, + IN u8 *pucIPv6Addr, IN u32 u4NumIPv6Addr) +{ + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + u32 u4SetInfoLen = 0; + u32 u4Len = OFFSET_OF(PARAM_NETWORK_ADDRESS_LIST, arAddress); + P_PARAM_NETWORK_ADDRESS_LIST prParamNetAddrList; + P_PARAM_NETWORK_ADDRESS prParamNetAddr; + u32 i, u4AddrLen; + + DBGLOG(INIT, INFO, "Set network address for BSS[%u]\n", ucBssIdx); + + /* 4 <1> Calculate buffer size */ + /* IPv4 */ + u4Len += (((sizeof(PARAM_NETWORK_ADDRESS) - 1) + IPV4_ADDR_LEN) * + u4NumIPv4Addr); + /* IPv6 */ + u4Len += (((sizeof(PARAM_NETWORK_ADDRESS) - 1) + IPV6_ADDR_LEN) * + u4NumIPv6Addr); + + /* 4 <2> Allocate buffer */ + prParamNetAddrList = + (P_PARAM_NETWORK_ADDRESS_LIST)kalMemAlloc(u4Len, VIR_MEM_TYPE); + + if (!prParamNetAddrList) { + DBGLOG(INIT, + WARN, + "Fail to alloc buffer for setting BSS[%u] network address!\n", + ucBssIdx); + return; + } + /* 4 <3> Fill up network address */ + prParamNetAddrList->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + prParamNetAddrList->u4AddressCount = 0; + prParamNetAddrList->ucBssIdx = ucBssIdx; + + /* 4 <3.1> Fill up IPv4 address */ + u4AddrLen = IPV4_ADDR_LEN; + prParamNetAddr = prParamNetAddrList->arAddress; + for (i = 0; i < u4NumIPv4Addr; i++) { + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + prParamNetAddr->u2AddressLength = u4AddrLen; + kalMemCopy(prParamNetAddr->aucAddress, + &pucIPv4Addr[i * u4AddrLen], u4AddrLen); + + prParamNetAddr = + (P_PARAM_NETWORK_ADDRESS)((unsigned long)prParamNetAddr + + + (unsigned long)(u4AddrLen + + OFFSET_OF( + PARAM_NETWORK_ADDRESS, + aucAddress))); + } + prParamNetAddrList->u4AddressCount += u4NumIPv4Addr; + + /* 4 <3.2> Fill up IPv6 address */ + u4AddrLen = IPV6_ADDR_LEN; + for (i = 0; i < u4NumIPv6Addr; i++) { + prParamNetAddr->u2AddressType = PARAM_PROTOCOL_ID_TCP_IP; + prParamNetAddr->u2AddressLength = u4AddrLen; + kalMemCopy(prParamNetAddr->aucAddress, + &pucIPv6Addr[i * u4AddrLen], u4AddrLen); + + prParamNetAddr = + (P_PARAM_NETWORK_ADDRESS)((unsigned long)prParamNetAddr + + + (unsigned long)(u4AddrLen + + OFFSET_OF( + PARAM_NETWORK_ADDRESS, + aucAddress))); + } + prParamNetAddrList->u4AddressCount += u4NumIPv6Addr; + + /* 4 <4> IOCTL to main_thread */ + rStatus = kalIoctl(prGlueInfo, wlanoidSetNetworkAddress, + (void *)prParamNetAddrList, u4Len, false, false, + true, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "%s: Fail to set network address\n", + __func__); + } + + kalMemFree(prParamNetAddrList, VIR_MEM_TYPE, u4Len); +} + +void kalSetNetAddressFromInterface(IN P_GLUE_INFO_T prGlueInfo, + IN struct net_device *prDev, + IN u8 fgSet) +{ + u32 u4NumIPv4, u4NumIPv6; + u8 pucIPv4Addr[IPV4_ADDR_LEN * CFG_PF_ARP_NS_MAX_NUM], + pucIPv6Addr[IPV6_ADDR_LEN * CFG_PF_ARP_NS_MAX_NUM]; + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = + (P_NETDEV_PRIVATE_GLUE_INFO)NULL; + + prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(prDev); + + if (prNetDevPrivate->prGlueInfo != prGlueInfo) { + DBGLOG(REQ, WARN, "%s: unexpected prGlueInfo(0x%p)!\n", + __func__, prNetDevPrivate->prGlueInfo); + } + + u4NumIPv4 = 0; + u4NumIPv6 = 0; + + if (fgSet) { + kalGetIPv4Address(prDev, CFG_PF_ARP_NS_MAX_NUM, pucIPv4Addr, + &u4NumIPv4); + kalGetIPv6Address(prDev, CFG_PF_ARP_NS_MAX_NUM, pucIPv6Addr, + &u4NumIPv6); + } + + if (u4NumIPv4 + u4NumIPv6 > CFG_PF_ARP_NS_MAX_NUM) { + if (u4NumIPv4 >= CFG_PF_ARP_NS_MAX_NUM) { + u4NumIPv4 = CFG_PF_ARP_NS_MAX_NUM; + u4NumIPv6 = 0; + } else { + u4NumIPv6 = CFG_PF_ARP_NS_MAX_NUM - u4NumIPv4; + } + } + + kalSetNetAddress(prGlueInfo, prNetDevPrivate->ucBssIdx, pucIPv4Addr, + u4NumIPv4, pucIPv6Addr, u4NumIPv6); +} + +#if CFG_MET_PACKET_TRACE_SUPPORT + +u8 kalMetCheckProfilingPacket(IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket) +{ + u32 u4PacketLen; + u16 u2EtherTypeLen; + struct sk_buff *prSkb = (struct sk_buff *)prPacket; + u8 *aucLookAheadBuf = NULL; + u8 ucEthTypeLenOffset = ETHER_HEADER_LEN - ETHER_TYPE_LEN; + u8 *pucNextProtocol = NULL; + + u4PacketLen = prSkb->len; + + if (u4PacketLen < ETHER_HEADER_LEN) { + DBGLOG(INIT, WARN, "Invalid Ether packet length: %lu\n", + u4PacketLen); + return false; + } + + aucLookAheadBuf = prSkb->data; + + /* 4 <0> Obtain Ether Type/Len */ + WLAN_GET_FIELD_BE16(&aucLookAheadBuf[ucEthTypeLenOffset], + &u2EtherTypeLen); + + /* 4 <1> Skip 802.1Q header (VLAN Tagging) */ + if (u2EtherTypeLen == ETH_P_VLAN) { + ucEthTypeLenOffset += ETH_802_1Q_HEADER_LEN; + WLAN_GET_FIELD_BE16(&aucLookAheadBuf[ucEthTypeLenOffset], + &u2EtherTypeLen); + } + /* 4 <2> Obtain next protocol pointer */ + pucNextProtocol = &aucLookAheadBuf[ucEthTypeLenOffset + ETHER_TYPE_LEN]; + + /* 4 <3> Handle ethernet format */ + switch (u2EtherTypeLen) { + /* IPv4 */ + case ETH_P_IPV4: { + u8 *pucIpHdr = pucNextProtocol; + u8 ucIpVersion; + + /* IPv4 header length check */ + if (u4PacketLen < + (ucEthTypeLenOffset + ETHER_TYPE_LEN + IPV4_HDR_LEN)) { + DBGLOG(INIT, WARN, "Invalid IPv4 packet length: %lu\n", + u4PacketLen); + return false; + } + + /* IPv4 version check */ + ucIpVersion = (pucIpHdr[0] & IP_VERSION_MASK) >> + IP_VERSION_OFFSET; + if (ucIpVersion != IP_VERSION_4) { + DBGLOG(INIT, WARN, "Invalid IPv4 packet version: %u\n", + ucIpVersion); + return false; + } + + if (pucIpHdr[IPV4_HDR_IP_PROTOCOL_OFFSET] == IP_PROTOCOL_UDP) { + u8 *pucUdpHdr = &pucIpHdr[IPV4_HDR_LEN]; + u16 u2UdpDstPort; + u16 u2UdpSrcPort; + + /* Get UDP DST port */ + WLAN_GET_FIELD_BE16(&pucUdpHdr[UDP_HDR_DST_PORT_OFFSET], + &u2UdpDstPort); + + /* Get UDP SRC port */ + WLAN_GET_FIELD_BE16(&pucUdpHdr[UDP_HDR_SRC_PORT_OFFSET], + &u2UdpSrcPort); + + if (u2UdpSrcPort == prGlueInfo->u2MetUdpPort) { + u16 u2IpId; + + /* Store IP ID for Tag */ + WLAN_GET_FIELD_BE16( + &pucIpHdr[ + IPV4_HDR_IP_IDENTIFICATION_OFFSET], + &u2IpId); + GLUE_SET_PKT_IP_ID(prPacket, u2IpId); + + return true; + } + } + } break; + + default: + break; + } + + return false; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0)) +static unsigned long __read_mostly tracing_mark_write_addr; + +static int __mt_find_tracing_mark_write_symbol_fn(void *prData, + const char *pcNameBuf, + struct module *prModule, + unsigned long ulAddress) +{ + if (strcmp(pcNameBuf, "tracing_mark_write") == 0) { + tracing_mark_write_addr = ulAddress; + return 1; + } + return 0; +} +#endif + +static inline void __mt_update_tracing_mark_write_addr(void) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 7, 0)) + if (unlikely(tracing_mark_write_addr == 0)) { + kallsyms_on_each_symbol(__mt_find_tracing_mark_write_symbol_fn, + NULL); + } +#endif +} + +void kalMetTagPacket(IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket, + IN ENUM_TX_PROFILING_TAG_T eTag) +{ + if (!prGlueInfo->fgMetProfilingEn) { + return; + } + + switch (eTag) { + case TX_PROF_TAG_OS_TO_DRV: + if (kalMetCheckProfilingPacket(prGlueInfo, prPacket)) { + /* trace_printk("S|%d|%s|%d\n", current->pid, + * "WIFI-CHIP", GLUE_GET_PKT_IP_ID(prPacket)); */ + __mt_update_tracing_mark_write_addr(); + + GLUE_SET_PKT_FLAG_PROF_MET(prPacket); + } + break; + + case TX_PROF_TAG_DRV_TX_DONE: + if (GLUE_GET_PKT_IS_PROF_MET(prPacket)) { + __mt_update_tracing_mark_write_addr(); + } + break; + + case TX_PROF_TAG_MAC_TX_DONE: + break; + + default: + break; + } +} + +void kalMetInit(IN P_GLUE_INFO_T prGlueInfo) +{ + prGlueInfo->fgMetProfilingEn = false; + prGlueInfo->u2MetUdpPort = 0; +} + +static ssize_t kalMetCtrlWriteProcfs(struct file *file, + const char __user *buffer, + size_t count, + loff_t *off) +{ + char acBuf[128 + 1]; /* + 1 for "\0" */ + u32 u4CopySize; + int u8MetProfEnable; + + IN P_GLUE_INFO_T prGlueInfo; + + u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : + (sizeof(acBuf) - 1); + if (copy_from_user(acBuf, buffer, u4CopySize)) { + DBGLOG(INIT, ERROR, "error of copy from user\n"); + return -EFAULT; + } + acBuf[u4CopySize] = '\0'; + + if (sscanf(acBuf, " %d", &u8MetProfEnable) == 1) { + DBGLOG(INIT, INFO, "MET_PROF: Write MET PROC Enable=%d\n", + u8MetProfEnable); + } + if (pMetGlobalData != NULL) { + prGlueInfo = (P_GLUE_INFO_T)pMetGlobalData; + prGlueInfo->fgMetProfilingEn = (u8)u8MetProfEnable; + } + return count; +} + +static ssize_t kalMetPortWriteProcfs(struct file *file, + const char __user *buffer, + size_t count, + loff_t *off) +{ + char acBuf[128 + 1]; /* + 1 for "\0" */ + u32 u4CopySize; + int u16MetUdpPort; + + IN P_GLUE_INFO_T prGlueInfo; + + u4CopySize = (count < (sizeof(acBuf) - 1)) ? count : + (sizeof(acBuf) - 1); + if (copy_from_user(acBuf, buffer, u4CopySize)) { + DBGLOG(INIT, ERROR, "error of copy from user\n"); + return -EFAULT; + } + acBuf[u4CopySize] = '\0'; + + if (sscanf(acBuf, " %d", &u16MetUdpPort) == 1) { + DBGLOG(INIT, INFO, "MET_PROF: Write MET PROC UDP_PORT=%d\n", + u16MetUdpPort); + } + if (pMetGlobalData != NULL) { + prGlueInfo = (P_GLUE_INFO_T)pMetGlobalData; + prGlueInfo->u2MetUdpPort = (u16)u16MetUdpPort; + } + return count; +} + +#if KERNEL_VERSION(5, 6, 0) <= LINUX_VERSION_CODE +const struct proc_ops rMetProcCtrlFops = { .proc_write = + kalMetCtrlWriteProcfs }; + +const struct proc_ops rMetProcPortFops = { .proc_write = + kalMetPortWriteProcfs }; +#else +const struct file_operations rMetProcCtrlFops = { + .write = kalMetCtrlWriteProcfs +}; + +const struct file_operations rMetProcPortFops = { + .write = kalMetPortWriteProcfs +}; +#endif + +int kalMetInitProcfs(IN P_GLUE_INFO_T prGlueInfo) +{ + /* struct proc_dir_entry *pMetProcDir; */ + if (init_net.proc_net == (struct proc_dir_entry *)NULL) { + DBGLOG(INIT, INFO, "init proc fs fail: proc_net == NULL\n"); + return -ENOENT; + } + /* + * Directory: Root (/proc/net/wlan0) + * For dual driver design, we should setup wlan dynamically + */ + pMetProcDir = + proc_mkdir(prGlueInfo->prDevHandler->name, init_net.proc_net); + + if (pMetProcDir == NULL) { + return -ENOENT; + } + + /* + * /proc/net/wlan0 + * |-- met_ctrl (PROC_MET_PROF_CTRL) + */ + /* proc_create(PROC_MET_PROF_CTRL, 0x0644, pMetProcDir, &rMetProcFops); + */ + proc_create(PROC_MET_PROF_CTRL, 0, pMetProcDir, &rMetProcCtrlFops); + proc_create(PROC_MET_PROF_PORT, 0, pMetProcDir, &rMetProcPortFops); + + pMetGlobalData = (void *)prGlueInfo; + + return 0; +} + +int kalMetRemoveProcfs(IN P_GLUE_INFO_T prGlueInfo) +{ + if (init_net.proc_net == (struct proc_dir_entry *)NULL) { + DBGLOG(INIT, WARN, "remove proc fs fail: proc_net == NULL\n"); + return -ENOENT; + } + + if (pMetGlobalData == NULL) { + DBGLOG(INIT, WARN, + "Skip MET remove Procfs due to init was not done\n"); + return 0; + } + + remove_proc_entry(PROC_MET_PROF_CTRL, pMetProcDir); + remove_proc_entry(PROC_MET_PROF_PORT, pMetProcDir); + /* remove root directory (proc/net/wlan0) */ + remove_proc_entry(prGlueInfo->prDevHandler->name, init_net.proc_net); + + /* clear MetGlobalData */ + pMetGlobalData = NULL; + + return 0; +} +#endif + +u8 kalIndicateAgpsNotify(P_ADAPTER_T prAdapter, u8 cmd, u8 *data, + u16 dataLen) +{ +#ifdef CONFIG_NL80211_TESTMODE + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + struct sk_buff *skb = cfg80211_testmode_alloc_event_skb( + priv_to_wiphy(prGlueInfo), dataLen, GFP_KERNEL); + + /* DBGLOG(CCX, INFO, ("WLAN_STATUS_AGPS_NOTIFY, cmd=%d\n", cmd)); */ + if (unlikely(nla_put(skb, MTK_ATTR_AGPS_CMD, sizeof(cmd), &cmd) < 0)) { + goto nla_put_failure; + } + if (dataLen > 0 && data && + unlikely(nla_put(skb, MTK_ATTR_AGPS_DATA, dataLen, data) < 0)) { + goto nla_put_failure; + } + if (unlikely(nla_put(skb, MTK_ATTR_AGPS_IFINDEX, sizeof(u32), + &prGlueInfo->prDevHandler->ifindex) < 0)) { + goto nla_put_failure; + } + /* currently, the ifname maybe wlan0, p2p0, so the maximum name length + * will be 5 bytes */ + if (unlikely(nla_put(skb, MTK_ATTR_AGPS_IFNAME, 5, + prGlueInfo->prDevHandler->name) < 0)) { + goto nla_put_failure; + } + + cfg80211_testmode_event(skb, GFP_KERNEL); + return true; + +nla_put_failure: + kfree_skb(skb); + return false; + +#else + return false; + +#endif +} + +u64 kalGetBootTime(void) +{ +#if KERNEL_VERSION(4, 20, 0) <= LINUX_VERSION_CODE + struct timespec64 ts; +#else + struct timespec ts; +#endif + u64 bootTime = 0; + +#if KERNEL_VERSION(4, 20, 0) <= LINUX_VERSION_CODE + ktime_get_boottime_ts64(&ts); +#elif KERNEL_VERSION(2, 6, 39) <= LINUX_VERSION_CODE + get_monotonic_boottime(&ts); +#else + ts = ktime_to_timespec(ktime_get()); +#endif + + bootTime = ts.tv_sec; + bootTime *= USEC_PER_SEC; + bootTime += ts.tv_nsec / NSEC_PER_USEC; + return bootTime; +} + +#if CFG_ASSERT_DUMP +WLAN_STATUS kalOpenCorDumpFile(u8 fgIsN9) +{ + /* Move open-op to kalWriteCorDumpFile(). Empty files only */ + u32 ret; + u8 *apucFileName; + + if (fgIsN9) { + apucFileName = apucCorDumpN9FileName; + }else{ + apucFileName = apucCorDumpCr4FileName; + } + + ret = kalTrunkPath(apucFileName); + + return (ret >= 0) ? WLAN_STATUS_SUCCESS : WLAN_STATUS_FAILURE; +} + +WLAN_STATUS kalWriteCorDumpFile(u8 *pucBuffer, u16 u2Size, u8 fgIsN9) +{ + u32 ret; + u8 *apucFileName; + + DBGLOG(INIT, WARN, "kalWriteCorDumpFile undo...\n"); + return WLAN_STATUS_SUCCESS; + + if (fgIsN9) { + apucFileName = apucCorDumpN9FileName; + }else{ + apucFileName = apucCorDumpCr4FileName; + } + + ret = kalWriteToFile(apucFileName, true, pucBuffer, u2Size); + + return (ret >= 0) ? WLAN_STATUS_SUCCESS : WLAN_STATUS_FAILURE; +} + +WLAN_STATUS kalCloseCorDumpFile(u8 fgIsN9) +{ + /* Move close-op to kalWriteCorDumpFile(). Do nothing here */ + + return WLAN_STATUS_SUCCESS; +} +#endif + +#if CFG_WOW_SUPPORT +void kalWowInit(IN P_GLUE_INFO_T prGlueInfo) +{ + kalMemZero(&prGlueInfo->prAdapter->rWowCtrl.stWowPort, + sizeof(WOW_PORT_T)); + prGlueInfo->prAdapter->rWowCtrl.ucReason = INVALID_WOW_WAKE_UP_REASON; +} + +void kalWowCmdEventSetCb(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen) +{ + ASSERT(prAdapter); + ASSERT(prCmdInfo); + + if (prCmdInfo->ucCID == CMD_ID_SET_PF_CAPABILITY) { + DBGLOG(INIT, STATE, "CMD_ID_SET_PF_CAPABILITY cmd submitted\n"); + prAdapter->fgSetPfCapabilityDone = true; + } + + if (prCmdInfo->ucCID == CMD_ID_SET_WOWLAN) { + DBGLOG(INIT, STATE, "CMD_ID_SET_WOWLAN cmd submitted\n"); + prAdapter->fgSetWowDone = true; + } +} + +void kalWowProcess(IN P_GLUE_INFO_T prGlueInfo, u8 enable) +{ + CMD_WOWLAN_PARAM_T rCmdWowlanParam; + CMD_PACKET_FILTER_CAP_T rCmdPacket_Filter_Cap; + CMD_FW_LOG_2_HOST_CTRL_T rFwLog2HostCtrl; + P_WOW_CTRL_T pWOW_CTRL = &prGlueInfo->prAdapter->rWowCtrl; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 ii, u4BufLen, wait = 0; + + kalMemZero(&rCmdWowlanParam, sizeof(CMD_WOWLAN_PARAM_T)); + kalMemZero(&rFwLog2HostCtrl, sizeof(rFwLog2HostCtrl)); + kalMemZero(&rCmdPacket_Filter_Cap, sizeof(CMD_PACKET_FILTER_CAP_T)); + + prGlueInfo->prAdapter->fgSetPfCapabilityDone = false; + prGlueInfo->prAdapter->fgSetWowDone = false; + + DBGLOG(PF, INFO, + "PF, pAd AIS ucBssIndex=%d, ucOwnMacIndex=%d, band=%d\n", + prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex, + prGlueInfo->prAdapter->prAisBssInfo->ucOwnMacIndex, + prGlueInfo->prAdapter->prAisBssInfo->eDBDCBand); + + DBGLOG(PF, INFO, "profile wow=%d, GpioInterval=%d\n", + prGlueInfo->prAdapter->rWifiVar.ucWow, + prGlueInfo->prAdapter->rWowCtrl.astWakeHif[0].u4GpioInterval); + + /* Kernel log timestamp correction */ + if (prGlueInfo->prAdapter->rWifiVar.ucN9Log2HostCtrl > 0) { + rFwLog2HostCtrl.ucMcuDest = 0; + rFwLog2HostCtrl.ucFwLog2HostCtrl = + prGlueInfo->prAdapter->rWifiVar.ucN9Log2HostCtrl; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetFwLog2Host, + &rFwLog2HostCtrl, + sizeof(CMD_FW_LOG_2_HOST_CTRL_T), true, true, + true, &u4BufLen); + } + + /* add band info */ + rCmdWowlanParam.ucDbdcBand = + (u8)prGlueInfo->prAdapter->prAisBssInfo->eDBDCBand; + + rCmdPacket_Filter_Cap.packet_cap_type |= PACKETF_CAP_TYPE_MAGIC; + /* 20160627 Bennett: if receive BMC magic, PF search by bssid index, + * which is different with OM index */ + /* After discussion, enable all bssid bits */ + /* rCmdPacket_Filter_Cap.ucBssid |= + * BIT(prGlueInfo->prAdapter->prAisBssInfo->ucOwnMacIndex); */ + rCmdPacket_Filter_Cap.ucBssid |= BITS(0, 3); + + if (enable) { + rCmdPacket_Filter_Cap.usEnableBits |= PACKETF_CAP_TYPE_MAGIC; + }else{ + rCmdPacket_Filter_Cap.usEnableBits &= ~PACKETF_CAP_TYPE_MAGIC; + } + + rStatus = wlanSendSetQueryCmd(prGlueInfo->prAdapter, + CMD_ID_SET_PF_CAPABILITY, true, false, + false, kalWowCmdEventSetCb, + nicOidCmdTimeoutCommon, + sizeof(CMD_PACKET_FILTER_CAP_T), + (u8 *)&rCmdPacket_Filter_Cap, NULL, 0); + + /* ARP and DHCP offload */ + wlanSetSuspendMode(prGlueInfo, enable); + /* p2pSetSuspendMode(prGlueInfo, true); */ + + /* wake up reason reset to default only when enter wow mode */ + if (enable) { + pWOW_CTRL->ucReason = INVALID_WOW_WAKE_UP_REASON; + } + /* Let WOW enable/disable as last command, so we can back/restore DMA + * classify filter in FW */ + rCmdWowlanParam.ucScenarioID = pWOW_CTRL->ucScenarioId; + rCmdWowlanParam.ucBlockCount = pWOW_CTRL->ucBlockCount; + kalMemCopy(&rCmdWowlanParam.astWakeHif[0], &pWOW_CTRL->astWakeHif[0], + sizeof(WOW_WAKE_HIF_T)); + + /* copy UDP/TCP port setting */ + kalMemCopy(&rCmdWowlanParam.stWowPort, + &prGlueInfo->prAdapter->rWowCtrl.stWowPort, + sizeof(WOW_PORT_T)); + + DBGLOG(PF, INFO, + "Cmd: IPV4/UDP=%d, IPV4/TCP=%d, IPV6/UDP=%d, IPV6/TCP=%d\n", + rCmdWowlanParam.stWowPort.ucIPv4UdpPortCnt, + rCmdWowlanParam.stWowPort.ucIPv4TcpPortCnt, + rCmdWowlanParam.stWowPort.ucIPv6UdpPortCnt, + rCmdWowlanParam.stWowPort.ucIPv6TcpPortCnt); + + for (ii = 0; ii < rCmdWowlanParam.stWowPort.ucIPv4UdpPortCnt; ii++) + DBGLOG(PF, INFO, "IPV4/UDP port[%d]=%d\n", ii, + rCmdWowlanParam.stWowPort.ausIPv4UdpPort[ii]); + + for (ii = 0; ii < rCmdWowlanParam.stWowPort.ucIPv4TcpPortCnt; ii++) + DBGLOG(PF, INFO, "IPV4/TCP port[%d]=%d\n", ii, + rCmdWowlanParam.stWowPort.ausIPv4TcpPort[ii]); + + for (ii = 0; ii < rCmdWowlanParam.stWowPort.ucIPv6UdpPortCnt; ii++) + DBGLOG(PF, INFO, "IPV6/UDP port[%d]=%d\n", ii, + rCmdWowlanParam.stWowPort.ausIPv6UdpPort[ii]); + + for (ii = 0; ii < rCmdWowlanParam.stWowPort.ucIPv6TcpPortCnt; ii++) + DBGLOG(PF, INFO, "IPV6/TCP port[%d]=%d\n", ii, + rCmdWowlanParam.stWowPort.ausIPv6TcpPort[ii]); + + /* GPIO parameter is necessary in suspend/resume */ + if (enable == 1) { + rCmdWowlanParam.ucCmd = PM_WOWLAN_REQ_START; + rCmdWowlanParam.ucDetectType = + WOWLAN_DETECT_TYPE_MAGIC | + WOWLAN_DETECT_TYPE_ONLY_PHONE_SUSPEND; + rCmdWowlanParam.u2FilterFlag = + WOWLAN_FF_DROP_ALL | WOWLAN_FF_SEND_MAGIC_TO_HOST | + WOWLAN_FF_ALLOW_1X | WOWLAN_FF_ALLOW_ARP_REQ2ME; + } else { + rCmdWowlanParam.ucCmd = PM_WOWLAN_REQ_STOP; + } + + rStatus = wlanSendSetQueryCmd(prGlueInfo->prAdapter, CMD_ID_SET_WOWLAN, + true, false, false, kalWowCmdEventSetCb, + nicOidCmdTimeoutCommon, + sizeof(CMD_WOWLAN_PARAM_T), + (u8 *)&rCmdWowlanParam, NULL, 0); + + while (1) { + kalMsleep(5); + + if (wait > 100) { + DBGLOG(INIT, ERROR, "WoW process timeout\n\n"); + break; + } + if ((prGlueInfo->prAdapter->fgSetPfCapabilityDone == true) && + (prGlueInfo->prAdapter->fgSetWowDone == true)) { + DBGLOG(INIT, STATE, "WoW process done\n\n"); + break; + } + wait++; + } +} +#endif + +void kalFreeTxMsduWorker(struct work_struct *work) +{ + P_GLUE_INFO_T prGlueInfo; + P_ADAPTER_T prAdapter; + QUE_T rTmpQue; + P_QUE_T prTmpQue = &rTmpQue; + P_MSDU_INFO_T prMsduInfo; + + if (g_u4HaltFlag) { + return; + } + + prGlueInfo = ENTRY_OF(work, GLUE_INFO_T, rTxMsduFreeWork); + prAdapter = prGlueInfo->prAdapter; + + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + return; + } + + KAL_ACQUIRE_MUTEX(prAdapter, MUTEX_TX_DATA_DONE_QUE); + QUEUE_MOVE_ALL(prTmpQue, &prAdapter->rTxDataDoneQueue); + KAL_RELEASE_MUTEX(prAdapter, MUTEX_TX_DATA_DONE_QUE); + + while (QUEUE_IS_NOT_EMPTY(prTmpQue)) { + QUEUE_REMOVE_HEAD(prTmpQue, prMsduInfo, P_MSDU_INFO_T); + + nicTxFreePacket(prAdapter, prMsduInfo, false); + nicTxReturnMsduInfo(prAdapter, prMsduInfo); + } +} + +void kalFreeTxMsdu(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo) +{ + KAL_ACQUIRE_MUTEX(prAdapter, MUTEX_TX_DATA_DONE_QUE); + QUEUE_INSERT_TAIL(&prAdapter->rTxDataDoneQueue, + (P_QUE_ENTRY_T)prMsduInfo); + KAL_RELEASE_MUTEX(prAdapter, MUTEX_TX_DATA_DONE_QUE); + + schedule_work(&prAdapter->prGlueInfo->rTxMsduFreeWork); +} + +#if CFG_SUPPORT_DFS +void kalIndicateChannelSwitch(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_CHNL_EXT_T eSco, IN u8 ucChannelNum) +{ + struct cfg80211_chan_def chandef; + struct ieee80211_channel *prChannel = NULL; + enum nl80211_channel_type rChannelType; + + if (ucChannelNum <= 14) { + prChannel = ieee80211_get_channel( + priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency(ucChannelNum, + NL80211_BAND_2GHZ)); + } else { + prChannel = ieee80211_get_channel( + priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency(ucChannelNum, + NL80211_BAND_5GHZ)); + } + + if (!prChannel) { + DBGLOG(REQ, ERROR, "ieee80211_get_channel fail!\n"); + return; + } + + switch (eSco) { + case CHNL_EXT_SCN: + rChannelType = NL80211_CHAN_NO_HT; + break; + + case CHNL_EXT_SCA: + rChannelType = NL80211_CHAN_HT40MINUS; + break; + + case CHNL_EXT_SCB: + rChannelType = NL80211_CHAN_HT40PLUS; + break; + + case CHNL_EXT_RES: + default: + rChannelType = NL80211_CHAN_HT20; + break; + } + + DBGLOG(REQ, STATE, "DFS channel switch to %d\n", ucChannelNum); + + cfg80211_chandef_create(&chandef, prChannel, rChannelType); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 2)) + cfg80211_ch_switch_notify(prGlueInfo->prDevHandler, &chandef); +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)) + cfg80211_ch_switch_notify(prGlueInfo->prDevHandler, &chandef, 0); +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(6, 9, 0)) + cfg80211_ch_switch_notify(prGlueInfo->prDevHandler, &chandef, 0, 0); +#else + cfg80211_ch_switch_notify(prGlueInfo->prDevHandler, &chandef, 0); +#endif +} +#endif + +int kal_sched_set(struct task_struct *p, int policy, + const struct sched_param *param, int nice) +{ + if (p == NULL || &(p->static_prio) < (int *)p) { + return -1; + } + +#if KERNEL_VERSION(5, 9, 0) <= LINUX_VERSION_CODE + struct sched_attr attr = { + .sched_policy = policy, + .sched_priority = param->sched_priority, + .sched_nice = nice, + }; + + if (policy == SCHED_NORMAL) { + sched_set_normal(p, nice); + }else if (policy == SCHED_FIFO) { + sched_set_fifo(p); + }else{ + sched_set_fifo_low(p); + } + + sched_setattr_nocheck(p, &attr); +#else + sched_setscheduler(p, policy, param); +#endif + + return 0; +} + +WLAN_STATUS kalUpdateBssChannel(IN P_GLUE_INFO_T prGlueInfo, + IN u8 aucSSID[], + IN u8 ucSsidLength, IN u8 aucBSSID[], + IN u8 ucChannelNum) +{ + WLAN_STATUS rStatus = WLAN_STATUS_NOT_ACCEPTED; + struct cfg80211_bss *bss = NULL; + struct ieee80211_channel *prChannel = NULL; + + if (ucChannelNum <= 14) { + prChannel = ieee80211_get_channel( + priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency(ucChannelNum, + NL80211_BAND_2GHZ)); + } else { + prChannel = ieee80211_get_channel( + priv_to_wiphy(prGlueInfo), + ieee80211_channel_to_frequency(ucChannelNum, + NL80211_BAND_5GHZ)); + } + + bss = cfg80211_get_bss(priv_to_wiphy(prGlueInfo), NULL, /* channel */ + aucBSSID, aucSSID, /* ssid */ + (u32)ucSsidLength, /* ssid length */ + IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); + + if (bss) { + if (prChannel) { + bss->channel = prChannel; + rStatus = WLAN_STATUS_SUCCESS; + } + cfg80211_put_bss(priv_to_wiphy(prGlueInfo), bss); + } + + return rStatus; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_p2p.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_p2p.c new file mode 100644 index 00000000000000..14f415cfa9aa93 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_p2p.c @@ -0,0 +1,2313 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_p2p.c + * \brief Main routines of Linux driver interface for Wi-Fi Direct + * + * This file contains the main routines of Linux driver for MediaTek Inc. + * 802.11 Wireless LAN Adapters. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include <linux/poll.h> + +#include <linux/kmod.h> + +#include "gl_os.h" +#include "debug.h" +#include "wlan_lib.h" +#include "gl_wext.h" + +/* #include <net/cfg80211.h> */ +#include "gl_p2p_ioctl.h" + +#include "precomp.h" +#include "gl_cfg80211.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define ARGV_MAX_NUM (4) + +/*For CFG80211 - wiphy parameters*/ +#define MAX_SCAN_LIST_NUM (1) +#define MAX_SCAN_IE_LEN (512) + +#if (CFG_SUPPORT_DFS_MASTER == 1) +#define MAX_CSA_COUNTER 10 +#endif + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK +#define MAX_LOOK_BACK_NUN (3) +#endif +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +struct net_device *g_P2pPrDev; +struct wireless_dev *gprP2pWdev; +struct wireless_dev *gprP2pRoleWdev[KAL_P2P_NUM]; +struct net_device *gPrP2pDev[KAL_P2P_NUM]; + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + +#if (CFG_ENABLE_UNIFY_WIPHY == 0) +static struct cfg80211_ops mtk_p2p_ops = { + .add_virtual_intf = mtk_p2p_cfg80211_add_iface, + .change_virtual_intf = mtk_p2p_cfg80211_change_iface, /* 1 st */ + .del_virtual_intf = mtk_p2p_cfg80211_del_iface, + .change_bss = mtk_p2p_cfg80211_change_bss, + .scan = mtk_p2p_cfg80211_scan, + .abort_scan = mtk_p2p_cfg80211_abort_scan, + .remain_on_channel = mtk_p2p_cfg80211_remain_on_channel, + .cancel_remain_on_channel = mtk_p2p_cfg80211_cancel_remain_on_channel, + .mgmt_tx = mtk_p2p_cfg80211_mgmt_tx, + .mgmt_tx_cancel_wait = mtk_p2p_cfg80211_mgmt_tx_cancel_wait, + .connect = mtk_p2p_cfg80211_connect, + .disconnect = mtk_p2p_cfg80211_disconnect, + .deauth = mtk_p2p_cfg80211_deauth, + .disassoc = mtk_p2p_cfg80211_disassoc, + .start_ap = mtk_p2p_cfg80211_start_ap, + .change_beacon = mtk_p2p_cfg80211_change_beacon, + .stop_ap = mtk_p2p_cfg80211_stop_ap, + .set_wiphy_params = mtk_p2p_cfg80211_set_wiphy_params, + .del_station = mtk_p2p_cfg80211_del_station, + .set_bitrate_mask = mtk_p2p_cfg80211_set_bitrate_mask, +#if KERNEL_VERSION(5, 8, 0) >= CFG80211_VERSION_CODE + .mgmt_frame_register = mtk_p2p_cfg80211_mgmt_frame_register, +#endif + .get_station = mtk_p2p_cfg80211_get_station, + .add_key = mtk_p2p_cfg80211_add_key, + .get_key = mtk_p2p_cfg80211_get_key, + .del_key = mtk_p2p_cfg80211_del_key, + .set_default_key = mtk_p2p_cfg80211_set_default_key, + .set_default_mgmt_key = mtk_p2p_cfg80211_set_mgmt_key, + .join_ibss = mtk_p2p_cfg80211_join_ibss, + .leave_ibss = mtk_p2p_cfg80211_leave_ibss, + .set_tx_power = mtk_p2p_cfg80211_set_txpower, + .get_tx_power = mtk_p2p_cfg80211_get_txpower, + .set_power_mgmt = mtk_p2p_cfg80211_set_power_mgmt, + .start_radar_detection = mtk_p2p_cfg80211_start_radar_detection, + .channel_switch = mtk_p2p_cfg80211_channel_switch, +#ifdef CONFIG_NL80211_TESTMODE + .testmode_cmd = mtk_p2p_cfg80211_testmode_cmd, +#endif +}; + +/* There isn't a lot of sense in it, but you can transmit anything you like */ +static const struct ieee80211_txrx_stypes + mtk_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_ADHOC] = + { /**/ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_STATION] = + { /**/ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_AP] = + { /**/ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_AP_VLAN] = + { /* copy AP */ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = + { /**/ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_GO] = { /**/ + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4) + } +}; + +#endif +#endif + +static const struct iw_priv_args rP2PIwPrivTable[] = { + { IOCTL_GET_DRIVER, IW_PRIV_TYPE_CHAR | 2000, IW_PRIV_TYPE_CHAR | 2000, + "driver" }, +}; + +#ifdef CONFIG_PM +static const struct wiphy_wowlan_support mtk_p2p_wowlan_support = { + .flags = WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_ANY, +}; +#endif + +static const struct ieee80211_iface_limit mtk_p2p_sta_go_limits[] = { + { + .max = 3, + .types = BIT(NL80211_IFTYPE_STATION), + }, + + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT), + }, +}; + +static const struct ieee80211_iface_combination mtk_iface_combinations_sta[] = { + { +#ifdef CFG_NUM_DIFFERENT_CHANNELS_STA + .num_different_channels = CFG_NUM_DIFFERENT_CHANNELS_STA, +#else + .num_different_channels = 2, +#endif + .max_interfaces = 3, + .limits = mtk_p2p_sta_go_limits, + .n_limits = 1, /* include p2p */ + }, +}; + +static const struct ieee80211_iface_combination mtk_iface_combinations_p2p[] = { + { +#ifdef CFG_NUM_DIFFERENT_CHANNELS_P2P + .num_different_channels = CFG_NUM_DIFFERENT_CHANNELS_P2P, +#else + .num_different_channels = 2, +#endif + .max_interfaces = 3, + .limits = mtk_p2p_sta_go_limits, + .n_limits = ARRAY_SIZE(mtk_p2p_sta_go_limits), /* include p2p */ + }, +}; + +const struct ieee80211_iface_combination *p_mtk_iface_combinations_sta = + mtk_iface_combinations_sta; +const s32 mtk_iface_combinations_sta_num = + ARRAY_SIZE(mtk_iface_combinations_sta); + +const struct ieee80211_iface_combination *p_mtk_iface_combinations_p2p = + mtk_iface_combinations_p2p; +const s32 mtk_iface_combinations_p2p_num = + ARRAY_SIZE(mtk_iface_combinations_p2p); + +#ifdef STA_P2P_MCC +static const struct ieee80211_iface_limit p2p_iface_limits_mcc[] = { + { .max = 2, + .types = (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_GO)) } +}; + +static const struct ieee80211_iface_combination + p2p_iface_comb_mcc[] = { /**/ + { + .limits = p2p_iface_limits_mcc, + .n_limits = ARRAY_SIZE(p2p_iface_limits_mcc), + .max_interfaces = 2, + .num_different_channels = 2, + .beacon_int_infra_match = false, + } +}; +#endif + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/* Net Device Hooks */ +static int p2pOpen(IN struct net_device *prDev); + +static int p2pStop(IN struct net_device *prDev); + +static struct net_device_stats *p2pGetStats(IN struct net_device *prDev); + +static void p2pSetMulticastList(IN struct net_device *prDev); + +static int p2pHardStartXmit(IN struct sk_buff *prSkb, + IN struct net_device *prDev); + +static int p2pSetMACAddress(IN struct net_device *prDev, void *addr); + +static int p2pDoIOCTL(struct net_device *prDev, struct ifreq *prIFReq, + int i4Cmd); + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for prDev->init + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution of wlanInit succeeds. + * \retval -ENXIO No such device. + */ +/*----------------------------------------------------------------------------*/ +static int p2pInit(struct net_device *prDev) +{ + if (!prDev) { + return -ENXIO; + } + + return 0; +} + +const struct net_device_ops p2p_netdev_ops = { + .ndo_open = p2pOpen, + .ndo_stop = p2pStop, + .ndo_set_mac_address = p2pSetMACAddress, + .ndo_set_rx_mode = p2pSetMulticastList, + .ndo_get_stats = p2pGetStats, + .ndo_do_ioctl = p2pDoIOCTL, + .ndo_start_xmit = p2pHardStartXmit, + .ndo_select_queue = wlanSelectQueue, + .ndo_init = p2pInit, +}; + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Allocate memory for P2P_INFO, GL_P2P_INFO, P2P_CONNECTION_SETTINGS + * P2P_SPECIFIC_BSS_INFO, P2P_FSM_INFO + * + * \param[in] prGlueInfo Pointer to glue info + * + * \return true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 p2PAllocInfo(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucIdex) +{ + P_ADAPTER_T prAdapter = NULL; + P_WIFI_VAR_T prWifiVar = NULL; + /* u32 u4Idx = 0; */ + + ASSERT(prGlueInfo); + if (!prGlueInfo) { + DBGLOG(P2P, ERROR, "prGlueInfo error\n"); + return false; + } + + prAdapter = prGlueInfo->prAdapter; + prWifiVar = &(prAdapter->rWifiVar); + + ASSERT(prAdapter); + ASSERT(prWifiVar); + + do { + if (prGlueInfo->prP2PInfo[ucIdex] == NULL) { + /*alloc memory for p2p info */ +#if CFG_ENABLE_UNIFY_WIPHY + prGlueInfo->prP2PInfo[ucIdex] = + kalMemAlloc(sizeof(GL_P2P_INFO_T), VIR_MEM_TYPE); + if (prGlueInfo->prP2PDevInfo == NULL) { + prGlueInfo->prP2PDevInfo = + kalMemAlloc(sizeof(GL_P2P_DEV_INFO_T), VIR_MEM_TYPE); + if (prGlueInfo->prP2PDevInfo) { + kalMemZero(prGlueInfo->prP2PDevInfo, + sizeof(GL_P2P_DEV_INFO_T)); + } + } + if (prAdapter->prP2pInfo == NULL) { + prAdapter->prP2pInfo = + kalMemAlloc(sizeof(P2P_INFO_T), VIR_MEM_TYPE); + if (prAdapter->prP2pInfo) { + kalMemZero(prAdapter->prP2pInfo, sizeof(P2P_INFO_T)); + } + } + if (prWifiVar->prP2pDevFsmInfo == NULL) { + /* Don't only create P2P device for ucIdex 0. + * Avoid the exception that mtk_init_ap_role + * called without p2p0. + */ + prWifiVar->prP2pDevFsmInfo = + kalMemAlloc(sizeof(P2P_DEV_FSM_INFO_T), VIR_MEM_TYPE); + if (prWifiVar->prP2pDevFsmInfo) { + kalMemZero(prWifiVar->prP2pDevFsmInfo, + sizeof(P2P_DEV_FSM_INFO_T)); + } + } +#else /* (CFG_ENABLE_UNIFY_WIPHY == 0) */ + prGlueInfo->prP2PInfo[ucIdex] = + kalMemAlloc(sizeof(GL_P2P_INFO_T), VIR_MEM_TYPE); + + if (ucIdex == 0) { + /*printk("[CHECK!]p2PAllocInfo : Alloc Common + * part only first interface\n");*/ + prGlueInfo->prP2PDevInfo = + kalMemAlloc(sizeof(GL_P2P_DEV_INFO_T), VIR_MEM_TYPE); + prAdapter->prP2pInfo = + kalMemAlloc(sizeof(P2P_INFO_T), VIR_MEM_TYPE); + prWifiVar->prP2pDevFsmInfo = + kalMemAlloc(sizeof(P2P_DEV_FSM_INFO_T), VIR_MEM_TYPE); + } +#endif /* CFG_ENABLE_UNIFY_WIPHY */ + + prWifiVar->prP2PConnSettings[ucIdex] = + kalMemAlloc(sizeof(P2P_CONNECTION_SETTINGS_T), VIR_MEM_TYPE); + prWifiVar->prP2pSpecificBssInfo[ucIdex] = + kalMemAlloc(sizeof(P2P_SPECIFIC_BSS_INFO_T), VIR_MEM_TYPE); + + prWifiVar->prP2pQueryStaStatistics[ucIdex] = + kalMemAlloc(sizeof(PARAM_GET_STA_STATISTICS), VIR_MEM_TYPE); + } else { + ASSERT(prAdapter->prP2pInfo != NULL); + ASSERT(prWifiVar->prP2PConnSettings[ucIdex] != NULL); + /* ASSERT(prWifiVar->prP2pFsmInfo != NULL); */ + ASSERT(prWifiVar->prP2pSpecificBssInfo[ucIdex] != NULL); + } + + /*MUST set memory to 0 */ + kalMemZero(prGlueInfo->prP2PInfo[ucIdex], sizeof(GL_P2P_INFO_T)); +#if (CFG_ENABLE_UNIFY_WIPHY == 0) + if (ucIdex == 0) { + kalMemZero(prGlueInfo->prP2PDevInfo, sizeof(GL_P2P_DEV_INFO_T)); + kalMemZero(prAdapter->prP2pInfo, sizeof(P2P_INFO_T)); + kalMemZero(prWifiVar->prP2pDevFsmInfo, sizeof(P2P_DEV_FSM_INFO_T)); + } +#endif + kalMemZero(prWifiVar->prP2PConnSettings[ucIdex], + sizeof(P2P_CONNECTION_SETTINGS_T)); + /* kalMemZero(prWifiVar->prP2pFsmInfo, sizeof(P2P_FSM_INFO_T)); + */ + kalMemZero(prWifiVar->prP2pSpecificBssInfo[ucIdex], + sizeof(P2P_SPECIFIC_BSS_INFO_T)); + + if (prWifiVar->prP2pQueryStaStatistics[ucIdex]) { + kalMemZero(prWifiVar->prP2pQueryStaStatistics[ucIdex], + sizeof(PARAM_GET_STA_STATISTICS)); + } + } while (false); + + if (!prGlueInfo->prP2PDevInfo) { + DBGLOG(P2P, ERROR, "prP2PDevInfo error\n"); + } else { + DBGLOG(P2P, INFO, "prP2PDevInfo ok\n"); + } + + if (!prGlueInfo->prP2PInfo[ucIdex]) { + DBGLOG(P2P, ERROR, "prP2PInfo error\n"); + } else { + DBGLOG(P2P, INFO, "prP2PInfo ok\n"); + } + + /* chk if alloc successful or not */ + if (prGlueInfo->prP2PInfo[ucIdex] && prGlueInfo->prP2PDevInfo && + prAdapter->prP2pInfo && prWifiVar->prP2PConnSettings[ucIdex] && + /* prWifiVar->prP2pFsmInfo && */ + prWifiVar->prP2pSpecificBssInfo[ucIdex]) { + return true; + } + + DBGLOG(P2P, ERROR, "[fail!]p2PAllocInfo :fail\n"); + + if (prWifiVar->prP2pSpecificBssInfo[ucIdex]) { + kalMemFree(prWifiVar->prP2pSpecificBssInfo[ucIdex], VIR_MEM_TYPE, + sizeof(P2P_SPECIFIC_BSS_INFO_T)); + + prWifiVar->prP2pSpecificBssInfo[ucIdex] = NULL; + } + + if (prWifiVar->prP2pQueryStaStatistics[ucIdex]) { + kalMemFree(prWifiVar->prP2pQueryStaStatistics[ucIdex], VIR_MEM_TYPE, + sizeof(P_PARAM_GET_STA_STATISTICS)); + + prWifiVar->prP2pQueryStaStatistics[ucIdex] = NULL; + } + + /* if (prWifiVar->prP2pFsmInfo) { */ + /* kalMemFree(prWifiVar->prP2pFsmInfo, VIR_MEM_TYPE, + * sizeof(P2P_FSM_INFO_T)); */ + + /* prWifiVar->prP2pFsmInfo = NULL; */ + /* } */ + + if (prWifiVar->prP2PConnSettings[ucIdex]) { + kalMemFree(prWifiVar->prP2PConnSettings[ucIdex], VIR_MEM_TYPE, + sizeof(P2P_CONNECTION_SETTINGS_T)); + + prWifiVar->prP2PConnSettings[ucIdex] = NULL; + } + if (prGlueInfo->prP2PDevInfo) { + kalMemFree(prGlueInfo->prP2PDevInfo, VIR_MEM_TYPE, + sizeof(GL_P2P_DEV_INFO_T)); + + prGlueInfo->prP2PDevInfo = NULL; + } + if (prGlueInfo->prP2PInfo[ucIdex]) { + kalMemFree(prGlueInfo->prP2PInfo[ucIdex], VIR_MEM_TYPE, + sizeof(GL_P2P_INFO_T)); + + prGlueInfo->prP2PInfo[ucIdex] = NULL; + } + if (prAdapter->prP2pInfo) { + kalMemFree(prAdapter->prP2pInfo, VIR_MEM_TYPE, sizeof(P2P_INFO_T)); + + prAdapter->prP2pInfo = NULL; + } + return false; +} + +static void p2pFreeMemSafe(P_GLUE_INFO_T prGlueInfo, void **pprMemInfo, + u32 size) +{ + void *prTmpMemInfo = NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + prTmpMemInfo = *pprMemInfo; + *pprMemInfo = NULL; + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + kalMemFree(prTmpMemInfo, VIR_MEM_TYPE, size); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Free memory for P2P_INFO, GL_P2P_INFO, P2P_CONNECTION_SETTINGS + * P2P_SPECIFIC_BSS_INFO, P2P_FSM_INFO + * + * \param[in] prGlueInfo Pointer to glue info + * [in] ucIdx The BSS with the idx will be freed. + * "ucIdx == 0xff" will free all BSSs. + * Only has meaning for "CFG_ENABLE_UNIFY_WIPHY == 1" + * \return true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 p2PFreeInfo(P_GLUE_INFO_T prGlueInfo, u8 ucIdx) +#if CFG_ENABLE_UNIFY_WIPHY +{ + P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; + ASSERT(prGlueInfo); + ASSERT(prAdapter); + if (ucIdx >= KAL_P2P_NUM) { + DBGLOG(P2P, ERROR, "ucIdx=%d is invalid\n", ucIdx); + return false; + } + /* TODO: how can I sure that the specific P2P device can be freed? + * The original check is that prGlueInfo->prAdapter->fgIsP2PRegistered. + */ + if (prGlueInfo->prP2PInfo[ucIdx] != NULL) { + kalMemFree(prAdapter->rWifiVar.prP2PConnSettings[ucIdx], VIR_MEM_TYPE, + sizeof(P2P_CONNECTION_SETTINGS_T)); + prAdapter->rWifiVar.prP2PConnSettings[ucIdx] = NULL; + kalMemFree(prAdapter->rWifiVar.prP2pSpecificBssInfo[ucIdx], + VIR_MEM_TYPE, sizeof(P2P_SPECIFIC_BSS_INFO_T)); + prAdapter->rWifiVar.prP2pSpecificBssInfo[ucIdx] = NULL; + kalMemFree(prGlueInfo->prP2PInfo[ucIdx], VIR_MEM_TYPE, + sizeof(GL_P2P_INFO_T)); + prGlueInfo->prP2PInfo[ucIdx] = NULL; + prAdapter->prP2pInfo->u4DeviceNum--; + } + if (prAdapter->prP2pInfo->u4DeviceNum == 0) { + /* all prP2PInfo are freed, and free the general part now */ + if (prAdapter->prP2pInfo) { + kalMemFree(prAdapter->prP2pInfo, VIR_MEM_TYPE, sizeof(P2P_INFO_T)); + prAdapter->prP2pInfo = NULL; + } + if (prGlueInfo->prP2PDevInfo) { + kalMemFree(prGlueInfo->prP2PDevInfo, VIR_MEM_TYPE, + sizeof(GL_P2P_DEV_INFO_T)); + prGlueInfo->prP2PDevInfo = NULL; + } + if (prAdapter->rWifiVar.prP2pDevFsmInfo) { + kalMemFree(prAdapter->rWifiVar.prP2pDevFsmInfo, VIR_MEM_TYPE, + sizeof(P2P_DEV_FSM_INFO_T)); + prAdapter->rWifiVar.prP2pDevFsmInfo = NULL; + } + /*Reomve p2p bss scan list */ + scanRemoveAllP2pBssDesc(prAdapter); + } + return true; +} +#else /* (CFG_ENABLE_UNIFY_WIPHY == 0) */ +{ + u8 i; + P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; + P_WIFI_VAR_T prWifiVar; + + ASSERT(prGlueInfo); + ASSERT(prAdapter); + + /* Expect that prAdapter->prP2pInfo must be existing. */ + if (prAdapter->prP2pInfo == NULL) { + DBGLOG(P2P, ERROR, "prAdapter->prP2pInfo is NULL\n"); + return false; + } + + prWifiVar = &prAdapter->rWifiVar; + + /* TODO: how can I sure that the specific P2P device can be freed? + * The original check is that prGlueInfo->prAdapter->fgIsP2PRegistered. + * For one wiphy feature, this func may be called without + * (fgIsP2PRegistered == false) condition. + */ + for (i = 0; i < KAL_P2P_NUM; i++) { /* clear all for now */ + if (prGlueInfo->prP2PInfo[i] != NULL) { + p2pFreeMemSafe(prGlueInfo, + (void **)&prWifiVar->prP2PConnSettings[i], + sizeof(P2P_CONNECTION_SETTINGS_T)); + + p2pFreeMemSafe(prGlueInfo, + (void **)&prWifiVar->prP2pSpecificBssInfo[i], + sizeof(P2P_SPECIFIC_BSS_INFO_T)); + + p2pFreeMemSafe(prGlueInfo, (void **)&prGlueInfo->prP2PInfo[i], + sizeof(GL_P2P_INFO_T)); + prAdapter->prP2pInfo->u4DeviceNum--; + } + + if (prAdapter->prP2pInfo->u4DeviceNum == i) { + p2pFreeMemSafe(prGlueInfo, (void **)&prAdapter->prP2pInfo, + sizeof(P2P_INFO_T)); + + if (prGlueInfo->prP2PDevInfo) { + p2pFreeMemSafe(prGlueInfo, (void **)&prGlueInfo->prP2PDevInfo, + sizeof(GL_P2P_DEV_INFO_T)); + } + if (prAdapter->rWifiVar.prP2pDevFsmInfo) { + p2pFreeMemSafe(prGlueInfo, (void **)&prWifiVar->prP2pDevFsmInfo, + sizeof(P2P_DEV_FSM_INFO_T)); + } + + p2pFreeMemSafe(prGlueInfo, + (void **)&prWifiVar->prP2pQueryStaStatistics, + sizeof(P2P_CONNECTION_SETTINGS_T)); + + scanRemoveAllP2pBssDesc(prAdapter); + } + } + + return true; +} +#endif + +u8 p2pNetRegister(P_GLUE_INFO_T prGlueInfo, u8 fgIsRtnlLockAcquired) +{ + u8 fgDoRegister = false; + u8 fgRollbackRtnlLock = false; + u8 ret = false; + P_ADAPTER_T prAdapter = NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + prAdapter = prGlueInfo->prAdapter; + + ASSERT(prGlueInfo); + ASSERT(prAdapter); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if (prAdapter->rP2PNetRegState == ENUM_NET_REG_STATE_UNREGISTERED && + prAdapter->rP2PRegState == ENUM_P2P_REG_STATE_REGISTERED) { + prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_REGISTERING; + fgDoRegister = true; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + if (!fgDoRegister) { + return true; + } + + if (fgIsRtnlLockAcquired && rtnl_is_locked()) { + fgRollbackRtnlLock = true; + rtnl_unlock(); + } + + /* net device initialize */ + netif_carrier_off(prGlueInfo->prP2PInfo[0]->prDevHandler); + netif_tx_stop_all_queues(prGlueInfo->prP2PInfo[0]->prDevHandler); + + /* register for net device */ + if (register_netdev(prGlueInfo->prP2PInfo[0]->prDevHandler) < 0) { + DBGLOG(INIT, WARN, "unable to register netdevice for p2p[0]\n"); + + free_netdev(prGlueInfo->prP2PInfo[0]->prDevHandler); + + ret = false; + } else { + prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_REGISTERED; + gPrP2pDev[0] = prGlueInfo->prP2PInfo[0]->prDevHandler; +#if 0 + prGlueInfo->prP2PInfo[0]->fgIsNetDevRegistered = true; +#endif + ret = true; + } + + if (prAdapter->prP2pInfo->u4DeviceNum == KAL_P2P_NUM) { + /* net device initialize */ + netif_carrier_off(prGlueInfo->prP2PInfo[1]->prDevHandler); + netif_tx_stop_all_queues(prGlueInfo->prP2PInfo[1]->prDevHandler); + + /* register for net device */ + if (register_netdev(prGlueInfo->prP2PInfo[1]->prDevHandler) < 0) { + DBGLOG(INIT, WARN, "unable to register netdevice for p2p[1]\n"); + + free_netdev(prGlueInfo->prP2PInfo[1]->prDevHandler); + + ret = false; + } else { + prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_REGISTERED; + gPrP2pDev[1] = prGlueInfo->prP2PInfo[1]->prDevHandler; +#if 0 + DBGLOG(P2P, STATE, "P2P 2nd NetDev registered\n"); + prGlueInfo->prP2PInfo[1]->fgIsNetDevRegistered = true; +#else + ret = true; +#endif + } + + DBGLOG(P2P, INFO, "P2P 2nd interface work\n"); + } + if (fgRollbackRtnlLock) { + rtnl_lock(); + } + + return ret; +} + +u8 p2pNetUnregister(P_GLUE_INFO_T prGlueInfo, u8 fgIsRtnlLockAcquired) +{ + u8 fgDoUnregister = false; + u8 fgRollbackRtnlLock = false; + u8 ucRoleIdx; + struct net_device *prRoleDev = NULL; + int iftype = 0; + P_BSS_INFO_T prP2pBssInfo = NULL; + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPriv = NULL; + P_ADAPTER_T prAdapter = NULL; +#if CFG_ENABLE_UNIFY_WIPHY + P_GL_P2P_INFO_T prP2PInfo = NULL; +#endif + + GLUE_SPIN_LOCK_DECLARATION(); + + prAdapter = prGlueInfo->prAdapter; + + ASSERT(prGlueInfo); + ASSERT(prAdapter); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if (prAdapter->rP2PNetRegState == ENUM_NET_REG_STATE_REGISTERED && + prAdapter->rP2PRegState == ENUM_P2P_REG_STATE_REGISTERED) { + prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERING; + fgDoUnregister = true; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + if (!fgDoUnregister) { + return true; + } + +#if CFG_ENABLE_UNIFY_WIPHY + if (fgIsRtnlLockAcquired && rtnl_is_locked()) { + fgRollbackRtnlLock = true; + } + for (ucRoleIdx = 0; ucRoleIdx < KAL_P2P_NUM; ucRoleIdx++) { + prP2PInfo = prGlueInfo->prP2PInfo[ucRoleIdx]; + if (prP2PInfo == NULL) { + continue; + } + /* don't unregister the dev that share with the AIS */ + if (prP2PInfo->prDevHandler == gprWdev->netdev) { + continue; + } + prRoleDev = prP2PInfo->aprRoleHandler; + if (prRoleDev != NULL) { + /* info cfg80211 disconnect */ + prNetDevPriv = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(prRoleDev); + iftype = prRoleDev->ieee80211_ptr->iftype; + prP2pBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prNetDevPriv->ucBssIdx); + /* FIXME: The p2pRoleFsmUninit may call the + * cfg80211_disconnected. + * p2pRemove()->glUnregisterP2P->p2pRoleFsmUninit(), + * it may be too late. + */ + if ((prP2pBssInfo != NULL) && + (prP2pBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) && + ((iftype == NL80211_IFTYPE_P2P_CLIENT) || + (iftype == NL80211_IFTYPE_STATION))) { + cfg80211_disconnected(prRoleDev, 0, NULL, 0, true, GFP_KERNEL); + } + if (prRoleDev != prP2PInfo->prDevHandler) { + if (netif_carrier_ok(prRoleDev)) { + netif_carrier_off(prRoleDev); + } + netif_tx_stop_all_queues(prRoleDev); + } + } + if (netif_carrier_ok(prP2PInfo->prDevHandler)) { + netif_carrier_off(prP2PInfo->prDevHandler); + } + netif_tx_stop_all_queues(prP2PInfo->prDevHandler); + if (fgRollbackRtnlLock) { + rtnl_unlock(); + } + /* Here are functions which need rtnl_lock */ + if ((prRoleDev) && (prP2PInfo->prDevHandler != prRoleDev)) { + DBGLOG(INIT, INFO, "unregister p2p[%d]\n", ucRoleIdx); + unregister_netdev(prRoleDev); + /* This ndev is created in mtk_p2p_cfg80211_add_iface(), + * and unregister_netdev will also free the ndev. + */ + } + DBGLOG(INIT, INFO, "unregister p2pdev[%d]\n", ucRoleIdx); + unregister_netdev(prP2PInfo->prDevHandler); + if (fgRollbackRtnlLock) { + rtnl_lock(); + } + } +#else /* CFG_ENABLE_UNIFY_WIPHY */ + + /* prepare for removal */ + if (prGlueInfo->prP2PInfo[0]->prDevHandler != + prGlueInfo->prP2PInfo[0]->aprRoleHandler) { + prRoleDev = prGlueInfo->prP2PInfo[0]->aprRoleHandler; + + if (prRoleDev != NULL) { + /* info cfg80211 disconnect */ + prNetDevPriv = (NETDEV_PRIVATE_GLUE_INFO *)netdev_priv(prRoleDev); + iftype = prRoleDev->ieee80211_ptr->iftype; + prP2pBssInfo = + GET_BSS_INFO_BY_INDEX(prAdapter, prNetDevPriv->ucBssIdx); + + /* p2pRoleFsmUninit may call cfg80211_disconnected. + * p2pRemove()->glUnregisterP2P->p2pRoleFsmUninit(), + * and it may be too late to call cfg80211_disconnected + * there + */ + + if ((prP2pBssInfo != NULL) && + (prP2pBssInfo->eConnectionState == + PARAM_MEDIA_STATE_CONNECTED) && + ((iftype == NL80211_IFTYPE_P2P_CLIENT) || + (iftype == NL80211_IFTYPE_STATION))) { + cfg80211_disconnected(prRoleDev, 0, NULL, 0, true, GFP_KERNEL); + } + } + + if (netif_carrier_ok(prGlueInfo->prP2PInfo[0]->aprRoleHandler)) { + netif_carrier_off(prGlueInfo->prP2PInfo[0]->aprRoleHandler); + } + + netif_tx_stop_all_queues(prGlueInfo->prP2PInfo[0]->aprRoleHandler); + } + + if (netif_carrier_ok(prGlueInfo->prP2PInfo[0]->prDevHandler)) { + netif_carrier_off(prGlueInfo->prP2PInfo[0]->prDevHandler); + } + + netif_tx_stop_all_queues(prGlueInfo->prP2PInfo[0]->prDevHandler); + + if (fgIsRtnlLockAcquired && rtnl_is_locked()) { + fgRollbackRtnlLock = true; + rtnl_unlock(); + } + /* Here are functions which need rtnl_lock */ + if (prGlueInfo->prP2PInfo[0]->prDevHandler != + prGlueInfo->prP2PInfo[0]->aprRoleHandler) { + DBGLOG(INIT, INFO, "unregister p2p[0]\n"); + unregister_netdev(prGlueInfo->prP2PInfo[0]->aprRoleHandler); + } +#if 0 + if (prGlueInfo->prP2PInfo[0]->fgIsNetDevRegistered == true) { + prGlueInfo->prP2PInfo[0]->fgIsNetDevRegistered = false; +#endif + DBGLOG(INIT, INFO, "unregister p2pdev[0]\n"); + unregister_netdev(prGlueInfo->prP2PInfo[0]->prDevHandler); +#if 0 +} +#endif + + /* unregister the netdev and index > 0 */ + if (prAdapter->prP2pInfo->u4DeviceNum >= 2) { + for (ucRoleIdx = 1; ucRoleIdx < BSS_P2P_NUM; ucRoleIdx++) { + /* prepare for removal */ + if (netif_carrier_ok( + prGlueInfo->prP2PInfo[ucRoleIdx]->prDevHandler)) { + netif_carrier_off( + prGlueInfo->prP2PInfo[ucRoleIdx]->prDevHandler); + } + + netif_tx_stop_all_queues( + prGlueInfo->prP2PInfo[ucRoleIdx]->prDevHandler); + + if (fgIsRtnlLockAcquired && rtnl_is_locked()) { + fgRollbackRtnlLock = true; + rtnl_unlock(); + } + /* Here are functions which need rtnl_lock */ +#if 0 + if (prGlueInfo->prP2PInfo[ucRoleIdx] + ->fgIsNetDevRegistered == true) { + prGlueInfo->prP2PInfo[ucRoleIdx] + ->fgIsNetDevRegistered = false; + DBGLOG(INIT, INFO, "unregister p2pdev[%d]\n", + ucRoleIdx); +#endif + unregister_netdev(prGlueInfo->prP2PInfo[ucRoleIdx]->prDevHandler); +#if 0 + } +#endif + } + } + + if (fgRollbackRtnlLock) { + rtnl_lock(); + } + +#endif /* CFG_ENABLE_UNIFY_WIPHY */ + + prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERED; + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Setup the P2P device information + * + * \param[in] prGlueInfo Pointer to glue info + * [in] prP2pWdev Pointer to the wireless device + * [in] prP2pDev Pointer to the net device + * [in] u4Idx The P2P Role index (max : (KAL_P2P_NUM-1)) + * [in] fgIsApMode Indicate that this device is AP Role or not + * + * \return 0 Success + * -1 Failure + */ +/*----------------------------------------------------------------------------*/ +#if CFG_ENABLE_UNIFY_WIPHY +int glSetupP2P(P_GLUE_INFO_T prGlueInfo, struct wireless_dev *prP2pWdev, + struct net_device *prP2pDev, int u4Idx, u8 fgIsApMode) +{ + P_ADAPTER_T prAdapter = NULL; + P_GL_P2P_INFO_T prP2PInfo = NULL; + P_GL_HIF_INFO_T prHif = NULL; + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPriv = NULL; + struct chip_info *prChipInfo = NULL; + DBGLOG(INIT, INFO, "setup the p2p dev\n"); + prHif = &prGlueInfo->rHifInfo; + prAdapter = prGlueInfo->prAdapter; + if ((prGlueInfo == NULL) || (prAdapter == NULL) || (prHif == NULL) || + (prP2pWdev == NULL) || (prP2pWdev->wiphy == NULL) || + (prP2pDev == NULL)) { + DBGLOG(INIT, ERROR, "parameter is NULL!!\n"); + return -1; + } + /* FIXME: check KAL_P2P_NUM in trunk? */ + if (u4Idx >= KAL_P2P_NUM) { + DBGLOG(INIT, ERROR, "u4Idx(%d) is out of range!!\n", u4Idx); + return -1; + } + prChipInfo = prAdapter->chip_info; + /*0. allocate p2pinfo */ + if (!p2PAllocInfo(prGlueInfo, u4Idx)) { + DBGLOG(INIT, WARN, "Allocate memory for p2p FAILED\n"); + ASSERT(0); + return -1; + } + prP2PInfo = prGlueInfo->prP2PInfo[u4Idx]; +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + /* fill wiphy parameters */ + prP2PInfo->prWdev = prP2pWdev; + if (!prAdapter->fgEnable5GBand) { + prP2pWdev->wiphy->bands[BAND_5G] = NULL; + } +#endif /* CFG_ENABLE_WIFI_DIRECT_CFG_80211 */ + /* setup netdev */ + /* Point to shared glue structure */ + prNetDevPriv = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(prP2pDev); + prNetDevPriv->prGlueInfo = prGlueInfo; + /* set ucIsP2p for P2P function device */ + if (fgIsApMode == true) { + prP2pWdev->iftype = NL80211_IFTYPE_AP; + prNetDevPriv->ucIsP2p = false; + } else { + prP2pWdev->iftype = NL80211_IFTYPE_P2P_CLIENT; + prNetDevPriv->ucIsP2p = true; + } + /* register callback functions */ + + prP2pDev->needed_headroom += + NIC_TX_DESC_AND_PADDING_LENGTH + + 44 /* yhpgi: prChipInfo->txd_append_size */; + + prP2pDev->netdev_ops = &p2p_netdev_ops; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) + prP2PInfo->prDevHandler->wireless_handlers = &mtk_p2p_wext_handler_def; +#endif + // #if defined(_HIF_SDIO) + // #if (MTK_WCN_HIF_SDIO == 0) + SET_NETDEV_DEV(prP2pDev, &(prHif->func->dev)); +// #endif +// #endif +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + prP2pDev->ieee80211_ptr = prP2pWdev; + prP2pWdev->netdev = prP2pDev; +#endif +#if CFG_TCP_IP_CHKSUM_OFFLOAD + /* set HW checksum offload */ + if (prAdapter->fgIsSupportCsumOffload) { + prP2pDev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM; + } +#endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ + kalResetStats(prP2pDev); + /* finish */ + /* bind netdev pointer to netdev index */ + prP2PInfo->prDevHandler = prP2pDev; + /* XXX: All the P2P/AP devices do p2pDevFsmInit in the original code */ + wlanBindBssIdxToNetInterface(prGlueInfo, p2pDevFsmInit(prAdapter), + (void *)prP2PInfo->prDevHandler); + prP2PInfo->aprRoleHandler = prP2PInfo->prDevHandler; + DBGLOG(P2P, INFO, "check prDevHandler = %p\n", prP2PInfo->prDevHandler); + DBGLOG(P2P, INFO, "aprRoleHandler = %p\n", prP2PInfo->aprRoleHandler); + prNetDevPriv->ucBssIdx = p2pRoleFsmInit(prAdapter, u4Idx); + /* Currently wpasupplicant can't support create interface. */ + /* so initial the corresponding data structure here. */ + wlanBindBssIdxToNetInterface(prGlueInfo, prNetDevPriv->ucBssIdx, + (void *)prP2PInfo->aprRoleHandler); + /* bind netdev pointer to netdev index */ +#if 0 + wlanBindNetInterface(prGlueInfo, NET_DEV_P2P_IDX, + (void *)prGlueInfo->prP2PInfo->prDevHandler); +#endif + /* setup running mode */ + p2pFuncInitConnectionSettings( + prAdapter, prAdapter->rWifiVar.prP2PConnSettings[u4Idx], fgIsApMode); + return 0; +} +#endif /* CFG_ENABLE_UNIFY_WIPHY */ + +/*---------------------------------------------------------------------------*/ +/*! + * \brief Register for cfg80211 for Wi-Fi Direct + * + * \param[in] prGlueInfo Pointer to glue info + * + * \return true + * false + */ +/*---------------------------------------------------------------------------*/ +u8 glRegisterP2P(P_GLUE_INFO_T prGlueInfo, const char *prDevName, + const char *prDevName2, u8 ucApMode) +{ + P_ADAPTER_T prAdapter = NULL; + PARAM_MAC_ADDRESS rMacAddr; + u8 fgIsApMode = false; + u8 ucRegisterNum = 1, i = 0; + struct wireless_dev *prP2pWdev = NULL; +#if CFG_ENABLE_UNIFY_WIPHY + struct net_device *prP2pDev = NULL; + struct wiphy *prWiphy = NULL; +#else /* (CFG_ENABLE_UNIFY_WIPHY == 0) */ + P_GL_HIF_INFO_T prHif = NULL; + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPriv = NULL; +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + struct device *prDev; +#endif +#endif + const char *prSetDevName; + + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + +#if CFG_ENABLE_UNIFY_WIPHY + if ((ucApMode == RUNNING_DUAL_AP_MODE) || + (ucApMode == RUNNING_P2P_AP_MODE)) { + ucRegisterNum = 2; + glP2pCreateWirelessDevice(prGlueInfo); + } + do { + if (ucApMode == RUNNING_P2P_AP_MODE) { + if (i == 0) { + prSetDevName = prDevName; + fgIsApMode = false; + } else { + prSetDevName = prDevName2; + fgIsApMode = true; + } + } else { + /* RUNNING_AP_MODE + * RUNNING_DUAL_AP_MODE + * RUNNING_P2P_MODE + */ + prSetDevName = prDevName; + if (ucApMode == RUNNING_P2P_MODE) { + fgIsApMode = false; + }else{ + fgIsApMode = true; + } + } + if (!gprP2pRoleWdev[i]) { + DBGLOG(P2P, ERROR, "gprP2pRoleWdev[%d] is NULL\n", i); + return false; + } + prP2pWdev = gprP2pRoleWdev[i]; + DBGLOG(INIT, INFO, "glRegisterP2P(%d)\n", i); + /* Reset prP2pWdev for the issue that the prP2pWdev doesn't + * reset when the usb unplug/plug. + */ + prWiphy = prP2pWdev->wiphy; + memset(prP2pWdev, 0, sizeof(struct wireless_dev)); + prP2pWdev->wiphy = prWiphy; + /* allocate netdev */ + + prP2pDev = alloc_netdev_mq(sizeof(NETDEV_PRIVATE_GLUE_INFO), + prSetDevName, NET_NAME_PREDICTABLE, + ether_setup, CFG_MAX_TXQ_NUM); + + if (!prP2pDev) { + DBGLOG(INIT, WARN, "unable to allocate ndev for p2p\n"); + goto err_alloc_netdev; + } + /* fill hardware address */ + COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); + rMacAddr[0] |= 0x2; + /* change to local administrated address */ + rMacAddr[0] ^= i << 2; + +#if CFG_MESON_G12A_PATCH + prP2pDev->mtu = 1408; +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0) + dev_addr_set(prP2pDev, rMacAddr); +#else + kalMemCopy(prP2pDev->dev_addr, rMacAddr, ETH_ALEN); +#endif + kalMemCopy(prP2pDev->perm_addr, prP2pDev->dev_addr, ETH_ALEN); + if (glSetupP2P(prGlueInfo, prP2pWdev, prP2pDev, i, fgIsApMode) != 0) { + DBGLOG(INIT, WARN, "glSetupP2P FAILED\n"); + free_netdev(prP2pDev); + return false; + } + i++; + /* prP2pInfo is alloc at glSetupP2P()->p2PAllocInfo() */ + prAdapter->prP2pInfo->u4DeviceNum++; + /* set p2p net device register state */ + /* p2pNetRegister() will check prAdapter->rP2PNetRegState. */ + prAdapter->rP2PNetRegState = ENUM_NET_REG_STATE_UNREGISTERED; + } while (i < ucRegisterNum); +#else /* (CFG_ENABLE_UNIFY_WIPHY == 0) */ + + prHif = &prGlueInfo->rHifInfo; + ASSERT(prHif); + + if ((ucApMode == RUNNING_AP_MODE) || (ucApMode == RUNNING_DUAL_AP_MODE || + (ucApMode == RUNNING_P2P_AP_MODE))) { + fgIsApMode = true; + if ((ucApMode == RUNNING_DUAL_AP_MODE) || + (ucApMode == RUNNING_P2P_AP_MODE)) { + ucRegisterNum = 2; + if (gprP2pRoleWdev[1] == NULL) { + /* Create device only when not created before. */ + DBGLOG( + P2P, ERROR, + "Might encounter deadlock creating wireless device here\n"); + glP2pCreateWirelessDevice(prGlueInfo); + /* There would be risk encouter deadlock here. */ + } + } + } + prSetDevName = prDevName; + + do { + if ((ucApMode == RUNNING_P2P_AP_MODE) && (i == 0)) { + prSetDevName = prDevName; + fgIsApMode = false; + } else if ((ucApMode == RUNNING_P2P_AP_MODE) && (i == 1)) { + prSetDevName = prDevName2; + fgIsApMode = true; + } +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + if (!gprP2pRoleWdev[i]) { + DBGLOG(P2P, ERROR, "gl_p2p, wireless device is not exist\n"); + return false; + } +#endif + prP2pWdev = gprP2pRoleWdev[i]; + DBGLOG(INIT, INFO, "glRegisterP2P(%d), fgIsApMode(%d)\n", i, + fgIsApMode); + /*0. allocate p2pinfo */ + if (!p2PAllocInfo(prGlueInfo, i)) { + DBGLOG(INIT, WARN, "Allocate memory for p2p FAILED\n"); + ASSERT(0); + return false; + } +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + /* 1.1 fill wiphy parameters */ + glGetHifDev(prHif, &prDev); + if (!prDev) { + DBGLOG(INIT, INFO, "unable to get struct dev for p2p\n"); + } + + prGlueInfo->prP2PInfo[i]->prWdev = prP2pWdev; + /*prGlueInfo->prP2PInfo[i]->prRoleWdev[0] = prP2pWdev;*/ + /* TH3 + * multiple + * P2P + */ + + ASSERT(prP2pWdev); + ASSERT(prP2pWdev->wiphy); + ASSERT(prDev); + ASSERT(prGlueInfo->prAdapter); + + set_wiphy_dev(prP2pWdev->wiphy, prDev); + + if (!prGlueInfo->prAdapter->fgEnable5GBand) { + prP2pWdev->wiphy->bands[BAND_5G] = NULL; + } + + /* 2.2 wdev initialization */ + if (fgIsApMode) { + prP2pWdev->iftype = NL80211_IFTYPE_AP; + } else { + prP2pWdev->iftype = NL80211_IFTYPE_P2P_CLIENT; + } +#endif + + /* 3. allocate netdev */ + prGlueInfo->prP2PInfo[i]->prDevHandler = + alloc_netdev_mq(sizeof(NETDEV_PRIVATE_GLUE_INFO), prSetDevName, + NET_NAME_PREDICTABLE, ether_setup, CFG_MAX_TXQ_NUM); + + if (!prGlueInfo->prP2PInfo[i]->prDevHandler) { + DBGLOG(INIT, WARN, "unable to allocate netdevice for p2p\n"); + + goto err_alloc_netdev; + } + + /* 4. setup netdev */ + /* 4.1 Point to shared glue structure */ + /**((P_GLUE_INFO_T *) + * netdev_priv(prGlueInfo->prP2PInfo->prDevHandler)) = + * prGlueInfo; */ + prNetDevPriv = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv( + prGlueInfo->prP2PInfo[i]->prDevHandler); + prNetDevPriv->prGlueInfo = prGlueInfo; + + /* 4.2 fill hardware address */ + COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); + rMacAddr[0] |= 0x2; + rMacAddr[0] ^= i << 2; /* change to local administrated address + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + kalMemCopy(prGlueInfo->prP2PInfo[i]->prDevHandler->dev_addr, rMacAddr, + ETH_ALEN); +#else + dev_addr_set(prGlueInfo->prP2PInfo[i]->prDevHandler, rMacAddr); +#endif + + kalMemCopy(prGlueInfo->prP2PInfo[i]->prDevHandler->perm_addr, + prGlueInfo->prP2PInfo[i]->prDevHandler->dev_addr, ETH_ALEN); +#if CFG_MESON_G12A_PATCH + prGlueInfo->prP2PInfo[i]->prDevHandler->mtu = 1408; +#endif + + /* 4.3 register callback functions */ + prGlueInfo->prP2PInfo[i]->prDevHandler->needed_headroom += + NIC_TX_HEAD_ROOM; + prGlueInfo->prP2PInfo[i]->prDevHandler->netdev_ops = &p2p_netdev_ops; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)) + prGlueInfo->prP2PInfo->prDevHandler->wireless_handlers = + &mtk_p2p_wext_handler_def; +#endif + + SET_NETDEV_DEV(prGlueInfo->prP2PInfo[i]->prDevHandler, + &(prHif->func->dev)); + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + prGlueInfo->prP2PInfo[i]->prDevHandler->ieee80211_ptr = prP2pWdev; + prP2pWdev->netdev = prGlueInfo->prP2PInfo[i]->prDevHandler; +#endif + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + /* set HW checksum offload */ + if (prAdapter->fgIsSupportCsumOffload) { + prGlueInfo->prP2PInfo[i]->prDevHandler->features = + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; + } +#endif + + kalResetStats(prGlueInfo->prP2PInfo[i]->prDevHandler); + + /* 8. set p2p net device register state */ + prGlueInfo->prAdapter->rP2PNetRegState = + ENUM_NET_REG_STATE_UNREGISTERED; + + /* 9. setup running mode */ + /* prGlueInfo->prAdapter->rWifiVar.prP2pFsmInfo->fgIsApMode = + * fgIsApMode; */ + + /* 10. finish */ + /* 13. bind netdev pointer to netdev index */ + wlanBindBssIdxToNetInterface( + prGlueInfo, p2pDevFsmInit(prAdapter), + (void *)prGlueInfo->prP2PInfo[i]->prDevHandler); + + prGlueInfo->prP2PInfo[i]->aprRoleHandler = + prGlueInfo->prP2PInfo[i]->prDevHandler; + + DBGLOG(P2P, INFO, "check prDevHandler = %p\n", + prGlueInfo->prP2PInfo[i]->prDevHandler); + DBGLOG(P2P, INFO, "aprRoleHandler = %p\n", + prGlueInfo->prP2PInfo[i]->aprRoleHandler); + + prNetDevPriv->ucBssIdx = p2pRoleFsmInit(prAdapter, i); + /* 11. Currently wpasupplicant can't support create interface. + */ + /* so initial the corresponding data structure here. */ + wlanBindBssIdxToNetInterface( + prGlueInfo, prNetDevPriv->ucBssIdx, + (void *)prGlueInfo->prP2PInfo[i]->aprRoleHandler); + + /* 13. bind netdev pointer to netdev index */ + /* wlanBindNetInterface(prGlueInfo, NET_DEV_P2P_IDX, (void + **)prGlueInfo->prP2PInfo->prDevHandler); */ + + /* 12. setup running mode */ + p2pFuncInitConnectionSettings( + prAdapter, prAdapter->rWifiVar.prP2PConnSettings[i], fgIsApMode); + + /* Active network too early would cause HW not able to sleep. + * Defer the network active time. + */ + /* nicActivateNetwork(prAdapter, NETWORK_TYPE_P2P_INDEX); */ + + i++; + } while (i < ucRegisterNum); + + if ((ucApMode == RUNNING_DUAL_AP_MODE) || + (ucApMode == RUNNING_P2P_AP_MODE)) { + prGlueInfo->prAdapter->prP2pInfo->u4DeviceNum = 2; + } else { + prGlueInfo->prAdapter->prP2pInfo->u4DeviceNum = 1; + } + +#endif /* CFG_ENABLE_UNIFY_WIPHY */ + return true; + +err_alloc_netdev: + return false; +} + +#if CFG_ENABLE_UNIFY_WIPHY +u8 glP2pCreateWirelessDevice(P_GLUE_INFO_T prGlueInfo) +{ + struct wiphy *prWiphy = gprWdev->wiphy; + struct wireless_dev *prWdev = NULL; + u8 i = 0; + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + if (!prWiphy) { + DBGLOG(P2P, ERROR, "unable to allocate wiphy for p2p\n"); + return false; + } + for (i = 0; i < KAL_P2P_NUM; i++) + if (!gprP2pRoleWdev[i]) { + break; + } + if (i >= KAL_P2P_NUM) { + DBGLOG(INIT, WARN, "fail to register wiphy to driver\n"); + return false; + } + prWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!prWdev) { + DBGLOG(P2P, ERROR, "allocate p2p wdev fail, no memory\n"); + return false; + } + /* set priv as pointer to glue structure */ + prWdev->wiphy = prWiphy; + gprP2pRoleWdev[i] = prWdev; + DBGLOG(INIT, INFO, "glP2pCreateWirelessDevice (%x)\n", + gprP2pRoleWdev[i]->wiphy); + return true; +#else + return false; +#endif +} +#else /* (CFG_ENABLE_UNIFY_WIPHY == 0) */ +u8 glP2pCreateWirelessDevice(P_GLUE_INFO_T prGlueInfo) +{ + struct wiphy *prWiphy = NULL; + struct wireless_dev *prWdev = NULL; + u8 i = 0; + u32 band_idx, ch_idx; + struct ieee80211_supported_band *sband = NULL; + struct ieee80211_channel *chan = NULL; + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + prWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!prWdev) { + DBGLOG(P2P, ERROR, "allocate p2p wireless device fail, no memory\n"); + return false; + } + /* 1. allocate WIPHY */ + prWiphy = wiphy_new(&mtk_p2p_ops, sizeof(P_GLUE_INFO_T)); + if (!prWiphy) { + DBGLOG(P2P, ERROR, "unable to allocate wiphy for p2p\n"); + goto free_wdev; + } + + prWiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_STATION); + + prWiphy->software_iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); + + prWiphy->iface_combinations = p_mtk_iface_combinations_p2p; + prWiphy->n_iface_combinations = mtk_iface_combinations_p2p_num; + + prWiphy->bands[NL80211_BAND_2GHZ] = &mtk_band_2ghz; + prWiphy->bands[NL80211_BAND_5GHZ] = &mtk_band_5ghz; + + /* + * Clear flags in ieee80211_channel before p2p registers to resolve + * overriding flags issue. For example, when country is changed to US, + * both WW and US flags are applied. The issue flow is: + * + * 1. Register wlan wiphy (wiphy_register()@core.c) + * chan->orig_flags = chan->flags = 0 + * 2. Apply WW regdomain (handle_channel()@reg.c): + * chan->flags = chan->orig_flags|reg_channel_flags = + * 0|WW_channel_flags + * 3. Register p2p wiphy: + * chan->orig_flags = chan->flags = WW channel flags + * 4. Apply US regdomain: + * chan->flags = chan->orig_flags|reg_channel_flags + * = WW_channel_flags|US_channel_flags + * (Unexpected! It includes WW flags) + */ + + for (band_idx = 0; band_idx < NUM_NL80211_BANDS; band_idx++) { + sband = prWiphy->bands[band_idx]; + if (!sband) { + continue; + } + for (ch_idx = 0; ch_idx < sband->n_channels; ch_idx++) { + chan = &sband->channels[ch_idx]; + chan->flags = 0; + } + } + + prWiphy->mgmt_stypes = mtk_cfg80211_default_mgmt_stypes; + prWiphy->max_remain_on_channel_duration = 5000; + prWiphy->n_cipher_suites = 5; + prWiphy->cipher_suites = mtk_cipher_suites; + prWiphy->flags = WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | WIPHY_FLAG_HAVE_AP_SME | + WIPHY_FLAG_HAS_CHANNEL_SWITCH; + prWiphy->max_num_csa_counters = MAX_CSA_COUNTER; + prWiphy->ap_sme_capa = 1; + prWiphy->max_scan_ssids = MAX_SCAN_LIST_NUM; + prWiphy->max_scan_ie_len = MAX_SCAN_IE_LEN; + prWiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + prWiphy->iface_combinations = p2p_iface_comb_mcc; + prWiphy->n_iface_combinations = ARRAY_SIZE(p2p_iface_comb_mcc); + prWiphy->max_num_csa_counters = 2; + + prWiphy->regulatory_flags = REGULATORY_CUSTOM_REG; + cfg80211_regd_set_wiphy(prWiphy); + + /* 2.1 set priv as pointer to glue structure */ + *((P_GLUE_INFO_T *)wiphy_priv(prWiphy)) = prGlueInfo; + /* Here are functions which need rtnl_lock */ + if (wiphy_register(prWiphy) < 0) { + DBGLOG(INIT, WARN, "fail to register wiphy for p2p\n"); + goto free_wiphy; + } + prWdev->wiphy = prWiphy; + + for (i = 0; i < KAL_P2P_NUM; i++) { + if (!gprP2pRoleWdev[i]) { + gprP2pRoleWdev[i] = prWdev; + DBGLOG(INIT, INFO, "glP2pCreateWirelessDevice (%x)\n", + gprP2pRoleWdev[i]->wiphy); + break; + } + } + + if (i == KAL_P2P_NUM) { + DBGLOG(INIT, WARN, "fail to register wiphy to driver\n"); + goto free_wiphy; + } + + return true; + +free_wiphy: + wiphy_free(prWiphy); +free_wdev: + kfree(prWdev); +#endif + return false; +} +#endif /* CFG_ENABLE_UNIFY_WIPHY */ + +#if (CFG_ENABLE_UNIFY_WIPHY == 0) +void glP2pDestroyWirelessDevice(void) +{ + int i = 0; + + set_wiphy_dev(gprP2pWdev->wiphy, NULL); + + wiphy_unregister(gprP2pWdev->wiphy); + wiphy_free(gprP2pWdev->wiphy); + kfree(gprP2pWdev); + + for (i = 0; i < KAL_P2P_NUM; i++) { + if (gprP2pRoleWdev[i] == NULL) { + continue; + } + + if (i != 0) { /* The P2P is always in index 0 and shares Wiphy + * with P2PWdev */ + DBGLOG(INIT, INFO, "glP2pDestroyWirelessDevice (%p)\n", + gprP2pRoleWdev[i]->wiphy); + set_wiphy_dev(gprP2pRoleWdev[i]->wiphy, NULL); + wiphy_unregister(gprP2pRoleWdev[i]->wiphy); + wiphy_free(gprP2pRoleWdev[i]->wiphy); + } + if (gprP2pRoleWdev[i] && (gprP2pWdev != gprP2pRoleWdev[i])) { + kfree(gprP2pRoleWdev[i]); + } + gprP2pRoleWdev[i] = NULL; + } + + gprP2pWdev = NULL; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Unregister Net Device for Wi-Fi Direct + * + * \param[in] prGlueInfo Pointer to glue info + * [in] ucIdx The BSS with the idx will be freed. + * "ucIdx == 0xff" will free all BSSs. + * Only has meaning for "CFG_ENABLE_UNIFY_WIPHY == 1" + * + * \return true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 glUnregisterP2P(P_GLUE_INFO_T prGlueInfo, u8 ucIdx) +#if CFG_ENABLE_UNIFY_WIPHY +{ + u8 ucRoleIdx; + P_ADAPTER_T prAdapter; + P_GL_P2P_INFO_T prP2PInfo = NULL; + int i4Start = 0, i4End = 0; + ASSERT(prGlueInfo); + if (ucIdx == 0xff) { + i4Start = 0; + i4End = BSS_P2P_NUM; + } else if (ucIdx < BSS_P2P_NUM) { + i4Start = ucIdx; + i4End = ucIdx + 1; + } else { + DBGLOG(INIT, WARN, "The ucIdx (%d) is a wrong value\n", ucIdx); + return false; + } + prAdapter = prGlueInfo->prAdapter; + /* 4 <1> Uninit P2P dev FSM */ + /* Uninit P2P device FSM */ + /* only do p2pDevFsmUninit, when unregister all P2P device */ + if (ucIdx == 0xff) { + p2pDevFsmUninit(prAdapter); + } + /* 4 <2> Uninit P2P role FSM */ + for (ucRoleIdx = i4Start; ucRoleIdx < i4End; ucRoleIdx++) { + if (P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, ucRoleIdx)) { + /* FIXME: The cfg80211_XXX() is following the + * p2pRoleFsmUninit() sub-progress. + * ex: The cfg80211_del_sta() is called in the + * kalP2PGOStationUpdate(). + * But the netdev had be unregistered at + * p2pNetUnregister(). EXCEPTION!! + */ + p2pRoleFsmUninit(prGlueInfo->prAdapter, ucRoleIdx); + } + } + /* 4 <3> Free Wiphy & netdev */ + for (ucRoleIdx = i4Start; ucRoleIdx < i4End; ucRoleIdx++) { + prP2PInfo = prGlueInfo->prP2PInfo[ucRoleIdx]; + if (prP2PInfo == NULL) { + continue; + } + /* For P2P interfaces, prDevHandler points to the net_device of + * p2p0 interface. And aprRoleHandler points to the net_device + * of p2p virtual interface (i.e., p2p1) when it was created. + * And when p2p virtual interface is deleted, aprRoleHandler + * will change to point to prDevHandler. Hence, when + * aprRoleHandler & prDevHandler are pointing to different + * addresses, it means vif p2p1 exists. Otherwise it means p2p1 + * was already deleted. + */ + if ((prP2PInfo->aprRoleHandler != NULL) && + (prP2PInfo->aprRoleHandler != prP2PInfo->prDevHandler)) { + /* This device is added by the P2P, and use + * ndev->destructor to free. The p2pDevFsmUninit() use + * prP2PInfo->aprRoleHandler to do some check. + */ + prP2PInfo->aprRoleHandler = NULL; + DBGLOG(P2P, INFO, "aprRoleHandler idx %d set NULL\n", ucRoleIdx); + /* XXX: reference from mtk_p2p_cfg80211_del_iface */ + gprP2pRoleWdev[ucRoleIdx] = gprP2pWdev; + } + if (prP2PInfo->prDevHandler) { + /* don't free the dev that share with the AIS */ + if (prP2PInfo->prDevHandler == gprWdev->netdev) { + gprP2pRoleWdev[ucRoleIdx] = NULL; + } else { + free_netdev(prP2PInfo->prDevHandler); + } + prP2PInfo->prDevHandler = NULL; + } + /* 4 <4> Free P2P internal memory */ + if (!p2PFreeInfo(prGlueInfo, ucRoleIdx)) { + /* false: (fgIsP2PRegistered!=false)||(ucRoleIdx err) */ + DBGLOG(INIT, ERROR, "p2PFreeInfo FAILED\n"); + ASSERT(0); + return false; + } + } + return true; +} /* end of glUnregisterP2P() */ +#else /* (CFG_ENABLE_UNIFY_WIPHY == 0) */ +{ + u8 ucRoleIdx; + P_ADAPTER_T prAdapter; + P_GL_P2P_INFO_T prP2PInfo; + + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + + /* 4 <1> Uninit P2P dev FSM */ + /* Uninit P2P device FSM */ + p2pDevFsmUninit(prAdapter); + + /* 4 <2> Uninit P2P role FSM */ + for (ucRoleIdx = 0; ucRoleIdx < BSS_P2P_NUM; ucRoleIdx++) + if (P2P_ROLE_INDEX_2_ROLE_FSM_INFO(prAdapter, ucRoleIdx)) { + p2pRoleFsmUninit(prGlueInfo->prAdapter, ucRoleIdx); + } + + /* 4 <3> Free Wiphy & netdev */ + for (ucRoleIdx = 0; ucRoleIdx < BSS_P2P_NUM; ucRoleIdx++) { + prP2PInfo = prGlueInfo->prP2PInfo[ucRoleIdx]; + + if (prP2PInfo == NULL) { + continue; + } + /* For P2P interfaces, prDevHandler points to the net_device of + * p2p0 interface. */ + /* And aprRoleHandler points to the net_device of p2p virtual + * interface (i.e., p2p1) */ + /* when it was created. And when p2p virtual interface is + * deleted, aprRoleHandler will */ + /* change to point to prDevHandler. Hence, when aprRoleHandler & + * prDevHandler are pointing */ + /* to different addresses, it means vif p2p1 exists. Otherwise + * it means p2p1 was */ + /* already deleted. */ + if ((prP2PInfo->aprRoleHandler != NULL) && + (prP2PInfo->aprRoleHandler != prP2PInfo->prDevHandler)) { + /* This device is added by the P2P, and use + * ndev->destructor to free. */ + prP2PInfo->aprRoleHandler = NULL; + DBGLOG(P2P, INFO, "aprRoleHandler idx %d set NULL\n", ucRoleIdx); + } + + if (prP2PInfo->prDevHandler) { + free_netdev(prP2PInfo->prDevHandler); + prP2PInfo->prDevHandler = NULL; + } + } + + /* 4 <4> Free P2P internal memory */ + if (!p2PFreeInfo(prGlueInfo, 0xff)) { + DBGLOG(INIT, WARN, "Free memory for p2p FAILED\n"); + ASSERT(0); + return false; + } + + return true; +} +#endif /* CFG_ENABLE_UNIFY_WIPHY */ + +/* Net Device Hooks */ +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for net_device open (ifup) + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution succeeds. + * \retval < 0 The execution failed. + */ +/*----------------------------------------------------------------------------*/ +static int p2pOpen(IN struct net_device *prDev) +{ + ASSERT(prDev); + + /* 2. carrier on & start TX queue */ + /*DFS todo 20161220_DFS*/ +#if (CFG_SUPPORT_DFS_MASTER == 1) + if (prDev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP) { + netif_carrier_on(prDev); + netif_tx_start_all_queues(prDev); + } +#else + netif_carrier_on(prDev); + netif_tx_start_all_queues(prDev); +#endif + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A function for net_device stop (ifdown) + * + * \param[in] prDev Pointer to struct net_device. + * + * \retval 0 The execution succeeds. + * \retval < 0 The execution failed. + */ +/*----------------------------------------------------------------------------*/ +static int p2pStop(IN struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + P_GL_P2P_DEV_INFO_T prP2pGlueDevInfo = (P_GL_P2P_DEV_INFO_T)NULL; +#if (CFG_ENABLE_UNIFY_WIPHY == 0) + u8 ucRoleIdx = 0; + struct net_device *prTargetDev = NULL; +#endif + struct cfg80211_scan_request *prScanRequest = NULL; + /* P_MSG_P2P_FUNCTION_SWITCH_T prFuncSwitch; */ + + GLUE_SPIN_LOCK_DECLARATION(); + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* XXX: The p2pStop may be triggered after the wlanRemove. */ + /* And prGlueInfo->prP2PDevInfo is freed in p2PFreeInfo. */ + if (!prAdapter->fgIsP2PRegistered) { + return -EFAULT; + } + + prP2pGlueDevInfo = prGlueInfo->prP2PDevInfo; + ASSERT(prP2pGlueDevInfo); + + /* 0. Do the scan done and set parameter to abort if the scan pending */ +#if (CFG_ENABLE_UNIFY_WIPHY == 0) + /* Default : P2P dev */ + prTargetDev = prGlueInfo->prP2PInfo[0]->prDevHandler; + if (mtk_Netdev_To_RoleIdx(prGlueInfo, prDev, &ucRoleIdx) != 0) { + prTargetDev = prGlueInfo->prP2PInfo[ucRoleIdx]->aprRoleHandler; + } +#endif + /*DBGLOG(INIT, INFO, "p2pStop and ucRoleIdx = %u\n", ucRoleIdx);*/ + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if ((prP2pGlueDevInfo->prScanRequest != NULL) && +#if CFG_ENABLE_UNIFY_WIPHY + (prP2pGlueDevInfo->prScanRequest->wdev == prDev->ieee80211_ptr) +#else + (prP2pGlueDevInfo->prScanRequest->wdev == prTargetDev->ieee80211_ptr) +#endif + ) { + prScanRequest = prP2pGlueDevInfo->prScanRequest; + prP2pGlueDevInfo->prScanRequest = NULL; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + if (prScanRequest) { + DBGLOG(INIT, INFO, "p2pStop and abort scan!!\n"); + kalCfg80211ScanDone(prScanRequest, true); + } + + /* 1. stop TX queue */ + netif_tx_stop_all_queues(prDev); + + /* 3. stop queue and turn off carrier */ + /*prGlueInfo->prP2PInfo[0]->eState = PARAM_MEDIA_STATE_DISCONNECTED;*/ /* TH3 + multiple + P2P + */ + + netif_tx_stop_all_queues(prDev); + if (netif_carrier_ok(prDev)) { + netif_carrier_off(prDev); + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A method of struct net_device, to get the network interface + * statistical information. + * + * Whenever an application needs to get statistics for the interface, this + * method is called. This happens, for example, when ifconfig or netstat -i is + * run. + * + * \param[in] prDev Pointer to struct net_device. + * + * \return net_device_stats buffer pointer. + */ +/*----------------------------------------------------------------------------*/ +struct net_device_stats *p2pGetStats(IN struct net_device *prDev) +{ + return (struct net_device_stats *)kalGetStats(prDev); +} + +static void p2pSetMulticastList(IN struct net_device *prDev) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + + prGlueInfo = (prDev != NULL) ? *((P_GLUE_INFO_T *)netdev_priv(prDev)) : + NULL; + + ASSERT(prDev); + ASSERT(prGlueInfo); + if (!prDev || !prGlueInfo) { + DBGLOG(INIT, WARN, + " abnormal dev or skb: prDev(0x%p), prGlueInfo(0x%p)\n", prDev, + prGlueInfo); + return; + } + + g_P2pPrDev = prDev; + + /* 4 Mark HALT, notify main thread to finish current job */ + set_bit(GLUE_FLAG_SUB_MOD_MULTICAST_BIT, &prGlueInfo->ulFlag); + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is to set multicast list and set rx mode. + * + * \param[in] prDev Pointer to struct net_device + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void mtk_p2p_wext_set_Multicastlist(P_GLUE_INFO_T prGlueInfo) +{ + u32 u4SetInfoLen = 0; + u32 u4McCount; + struct net_device *prDev; + + ASSERT(prGlueInfo); + if (!prGlueInfo) { + DBGLOG(INIT, WARN, " abnormal skb: prGlueInfo(0x%p)\n", prGlueInfo); + return; + } + + KAL_ACQUIRE_MUTEX(prGlueInfo->prAdapter, MUTEX_DEL_P2P_VIF); + prDev = g_P2pPrDev; + + if (!prDev) { + DBGLOG(INIT, WARN, + " abnormal dev: prDev(0x%p) or netdev has been freed\n", prDev); + KAL_RELEASE_MUTEX(prGlueInfo->prAdapter, MUTEX_DEL_P2P_VIF); + return; + } + + if (prDev->flags & IFF_PROMISC) { + prGlueInfo->prP2PDevInfo->u4PacketFilter |= + PARAM_PACKET_FILTER_PROMISCUOUS; + } + + if (prDev->flags & IFF_BROADCAST) { + prGlueInfo->prP2PDevInfo->u4PacketFilter |= + PARAM_PACKET_FILTER_BROADCAST; + } + u4McCount = netdev_mc_count(prDev); + + if (prDev->flags & IFF_MULTICAST) { + if ((prDev->flags & IFF_ALLMULTI) || (u4McCount > MAX_NUM_GROUP_ADDR)) { + prGlueInfo->prP2PDevInfo->u4PacketFilter |= + PARAM_PACKET_FILTER_ALL_MULTICAST; + } else { + prGlueInfo->prP2PDevInfo->u4PacketFilter |= + PARAM_PACKET_FILTER_MULTICAST; + } + } + + if (prGlueInfo->prP2PDevInfo->u4PacketFilter & + PARAM_PACKET_FILTER_MULTICAST) { + /* Prepare multicast address list */ + struct netdev_hw_addr *ha; + u32 i = 0; + + netdev_for_each_mc_addr(ha, prDev) { + if (i < MAX_NUM_GROUP_ADDR) { + COPY_MAC_ADDR(&(prGlueInfo->prP2PDevInfo->aucMCAddrList[i]), + GET_ADDR(ha)); + i++; + } + } + + DBGLOG(P2P, TRACE, "SEt Multicast Address List\n"); + + if (i >= MAX_NUM_GROUP_ADDR) { + KAL_RELEASE_MUTEX(prGlueInfo->prAdapter, MUTEX_DEL_P2P_VIF); + return; + } + + wlanoidSetP2PMulticastList( + prGlueInfo->prAdapter, + &(prGlueInfo->prP2PDevInfo->aucMCAddrList[0]), (i * ETH_ALEN), + &u4SetInfoLen); + } + + KAL_RELEASE_MUTEX(prGlueInfo->prAdapter, MUTEX_DEL_P2P_VIF); +} + +/*----------------------------------------------------------------------------*/ +/*! +** \brief This function is TX entry point of NET DEVICE. +** +** \param[in] prSkb Pointer of the sk_buff to be sent +** \param[in] prDev Pointer to struct net_device +** +** \retval NETDEV_TX_OK - on success. +** \retval NETDEV_TX_BUSY - on failure, packet will be discarded by upper layer. +*/ +/*----------------------------------------------------------------------------*/ +int p2pHardStartXmit(IN struct sk_buff *prSkb, IN struct net_device *prDev) +{ + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = + (P_NETDEV_PRIVATE_GLUE_INFO)NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + u8 ucBssIndex; +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + P_ADAPTER_T prAdapter = NULL; + u8 aucEthDestAddr[PARAM_MAC_ADDR_LEN]; +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK + u8 i = 0; + struct sk_buff *prSkbLb = NULL; + struct sk_buff *prSkbkick = NULL; + P_QUE_T prTxLookBackQueue = NULL; +#endif +#endif + + ASSERT(prSkb); + ASSERT(prDev); + + prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(prDev); + prGlueInfo = prNetDevPrivate->prGlueInfo; + ucBssIndex = prNetDevPrivate->ucBssIdx; + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + prAdapter = prGlueInfo->prAdapter; + // Get dest Addr + kalGetEthDestAddr(prGlueInfo, (P_NATIVE_PACKET)prSkb, aucEthDestAddr); + if (prAdapter->ucDupMcastPacketNum > 0) { + struct sk_buff *prSkbDup = NULL; + u8 i = 0; + // TODO: We take care both BCast and MCast at this stage + DBGLOG(P2P, TRACE, "Duplicated %d MCast packets\n", + prAdapter->ucDupMcastPacketNum); + if (IS_BMCAST_MAC_ADDR(aucEthDestAddr)) { + for (i = 0; i < prAdapter->ucDupMcastPacketNum; i++) { + prSkbDup = skb_copy(prSkb, GFP_ATOMIC); + kalResetPacket(prGlueInfo, (P_NATIVE_PACKET)prSkbDup); +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK + if (i == 0) { + // Set first packet of duplicated packet + // flag + GLUE_SET_PKT_FLAG((P_NATIVE_PACKET)prSkbDup, + ENUM_PKT_FIRST_DUP); + } +#endif + kalHardStartXmit(prSkbDup, prDev, prGlueInfo, ucBssIndex); + } + } + } +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK + if (prAdapter->fgIsLookBackMode && IS_BMCAST_MAC_ADDR(aucEthDestAddr)) { + P_QUE_ENTRY_T prQueueEntry = NULL; + struct iphdr *ip_header; + GLUE_SPIN_LOCK_DECLARATION(); + + ip_header = (struct iphdr *)skb_network_header(prSkb); + // DBGLOG(INIT, ERROR, "The TOS is : %02x\n", ip_header->tos); + if ((ip_header->tos != prAdapter->ucAudioTOS) || + prAdapter->ucAudioTOS == 0) { + /* Not expect packet, just send and return */ + kalResetPacket(prGlueInfo, (P_NATIVE_PACKET)prSkb); + kalHardStartXmit(prSkb, prDev, prGlueInfo, ucBssIndex); + return NETDEV_TX_OK; + } + + prTxLookBackQueue = &prGlueInfo->rTxLookBackQueue; + prSkbLb = skb_copy(prSkb, GFP_ATOMIC); + kalResetPacket(prGlueInfo, (P_NATIVE_PACKET)prSkbLb); + + /* set tag on first packet */ + /* add latest one in tail */ + prQueueEntry = (P_QUE_ENTRY_T)GLUE_GET_PKT_QUEUE_ENTRY(prSkbLb); + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + QUEUE_INSERT_TAIL(prTxLookBackQueue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + + DBGLOG(INIT, LOUD, "LB ADD: %p LB list size %d\n", prSkbLb, + QUEUE_GET_SIZE(prTxLookBackQueue)); + + if (QUEUE_GET_SIZE(prTxLookBackQueue) == 1) { + /* Not expect packet, just send and return */ + DBGLOG(INIT, ERROR, "first packet, just send out %d\n", prSkbLb); + kalResetPacket(prGlueInfo, (P_NATIVE_PACKET)prSkb); + kalHardStartXmit(prSkb, prDev, prGlueInfo, ucBssIndex); + return NETDEV_TX_OK; + } else if (QUEUE_GET_SIZE(prTxLookBackQueue) == 2) { + prSkbkick = NULL; + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + /* get packet from look-back queue then kick */ + QUEUE_REMOVE_HEAD(prTxLookBackQueue, prQueueEntry, P_QUE_ENTRY_T); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + prSkbLb = (struct sk_buff *)GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); + /* fill lookback sequence here */ + ip_header = (struct iphdr *)skb_network_header(prSkbLb); + ip_header->tos |= BIT(1); + prSkbkick = skb_copy(prSkbLb, GFP_ATOMIC); + /* re-queue the packet for next look-back */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + QUEUE_INSERT_HEAD(prTxLookBackQueue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + /* proccess packet if Skbkick != NULL */ + if (prSkbkick) { + /* send the look-back packet */ + kalResetPacket(prGlueInfo, (P_NATIVE_PACKET)prSkbkick); + kalHardStartXmit(prSkbkick, prDev, prGlueInfo, ucBssIndex); + DBGLOG(INIT, LOUD, "[%d] LB kick/requeue: %p\n", i, prSkbLb); + } + kalResetPacket(prGlueInfo, (P_NATIVE_PACKET)prSkb); + kalHardStartXmit(prSkb, prDev, prGlueInfo, ucBssIndex); + return NETDEV_TX_OK; + } else if (QUEUE_GET_SIZE(prTxLookBackQueue) == 3) { + for (i = 0; i < QUEUE_GET_SIZE(prTxLookBackQueue); i++) { + prSkbkick = NULL; + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + /* get packet from look-back queue then kick */ + QUEUE_REMOVE_HEAD(prTxLookBackQueue, prQueueEntry, + P_QUE_ENTRY_T); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + prSkbLb = + (struct sk_buff *)GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); + /* fill lookback sequence here */ + ip_header = (struct iphdr *)skb_network_header(prSkbLb); + /* switch tag to be 0xaa,0xbb,0xcc,0xdd */ + /* Tagging packet number for our propritry usage + * Rx side will recover the tag + */ + switch (i) { + case 0: + ip_header->tos |= BIT(2); + prSkbkick = skb_copy(prSkbLb, GFP_ATOMIC); + break; + + case 1: + ip_header->tos |= BIT(1); + prSkbkick = skb_copy(prSkbLb, GFP_ATOMIC); + break; + } + ; + /* re-queue the packet for next look-back */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + QUEUE_INSERT_TAIL(prTxLookBackQueue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + /* proccess packet if Skbkick != NULL */ + if (prSkbkick) { + /* send the look-back packet */ + kalResetPacket(prGlueInfo, (P_NATIVE_PACKET)prSkbkick); + kalHardStartXmit(prSkbkick, prDev, prGlueInfo, ucBssIndex); + DBGLOG(INIT, LOUD, "[%d] LB kick/requeue: %p\n", i, + prSkbLb); + } + } + kalResetPacket(prGlueInfo, (P_NATIVE_PACKET)prSkb); + kalHardStartXmit(prSkb, prDev, prGlueInfo, ucBssIndex); + return NETDEV_TX_OK; + } + + /* kick look-back */ + for (i = 0; i <= MAX_LOOK_BACK_NUN; i++) { + prSkbkick = NULL; + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + /* get packet from look-back queue then kick */ + QUEUE_REMOVE_HEAD(prTxLookBackQueue, prQueueEntry, P_QUE_ENTRY_T); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + prSkbLb = (struct sk_buff *)GLUE_GET_PKT_DESCRIPTOR(prQueueEntry); + /* fill lookback sequence here */ + ip_header = (struct iphdr *)skb_network_header(prSkbLb); + /* switch tag to be 0xaa,0xbb,0xcc,0xdd */ + /* Tagging packet number for our propritry usage + * Rx side will recover the tag + */ + switch (i) { + case 0: + ip_header->tos |= BITS(0, 1); + break; + + case 1: + ip_header->tos |= BIT(2); + break; + + case 2: + ip_header->tos |= BIT(1); + break; + } + ; + + /* packet from driver all be kicked out after + * MAX_LOOK_BACK_NUM - 1 transmit MAX_LOOK_BACK_NUM of + * packet in total + */ + if (i < MAX_LOOK_BACK_NUN) { + prSkbkick = skb_copy(prSkbLb, GFP_ATOMIC); + } + /* re-queue the packet for next look-back */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + QUEUE_INSERT_TAIL(prTxLookBackQueue, prQueueEntry); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + + /* proccess packet if Skbkick != NULL */ + if (prSkbkick) { + /* send the look-back packet */ + kalResetPacket(prGlueInfo, (P_NATIVE_PACKET)prSkbkick); + ip_header = (struct iphdr *)skb_network_header(prSkbkick); + if (i == 0) { + // Set first packet of duplicated packet + // flag for HIF Agg + GLUE_SET_PKT_FLAG((P_NATIVE_PACKET)prSkbkick, + ENUM_PKT_FIRST_DUP); + DBGLOG(INIT, LOUD, + "Flag before Set ENUM_PKT_FIRST_DUP %04x \n", + GLUE_IS_PKT_FLAG_SET((P_NATIVE_PACKET)prSkbkick)); + } + kalHardStartXmit(prSkbkick, prDev, prGlueInfo, ucBssIndex); + DBGLOG(INIT, LOUD, "[%d] LB kick/requeue: %p\n", i, prSkbLb); + } + DBGLOG(INIT, LOUD, "The TOS in queue is : %02x\n", ip_header->tos); + } + /* check if too much packet in lookback queue */ + prQueueEntry = NULL; + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + if (QUEUE_GET_SIZE(prTxLookBackQueue) > MAX_LOOK_BACK_NUN) { + QUEUE_REMOVE_HEAD(prTxLookBackQueue, prQueueEntry, P_QUE_ENTRY_T); + DBGLOG(INIT, LOUD, "LB Remove: %p\n", + (struct sk_buff *)GLUE_GET_PKT_DESCRIPTOR(prQueueEntry)); + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_TX_LB_QUE); + if (prQueueEntry) { + dev_kfree_skb( + (struct sk_buff *)GLUE_GET_PKT_DESCRIPTOR(prQueueEntry)); + } + ip_header = (struct iphdr *)skb_network_header(prSkb); + DBGLOG(INIT, LOUD, "The TOS in new packet is : %02x\n", ip_header->tos); + } +#endif +#endif + kalResetPacket(prGlueInfo, (P_NATIVE_PACKET)prSkb); + kalHardStartXmit(prSkb, prDev, prGlueInfo, ucBssIndex); + return NETDEV_TX_OK; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A method of struct net_device, a primary SOCKET interface to configure + * the interface lively. Handle an ioctl call on one of our devices. + * Everything Linux ioctl specific is done here. Then we pass the + * contents of the ifr->data to the request message handler. + * + * \param[in] prDev Linux kernel netdevice + * + * \param[in] prIFReq Our private ioctl request structure, typed for the + * generic struct ifreq so we can use ptr to function + * + * \param[in] cmd Command ID + * + * \retval WLAN_STATUS_SUCCESS The IOCTL command is executed successfully. + * \retval OTHER The execution of IOCTL command is failed. + */ +/*----------------------------------------------------------------------------*/ + +int p2pDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + int ret = 0; + /* char *prExtraBuf = NULL; */ + /* u32 u4ExtraSize = 0; */ + struct iwreq *prIwReq = (struct iwreq *)prIfReq; + struct iw_request_info rIwReqInfo; + /* fill rIwReqInfo */ + rIwReqInfo.cmd = (__u16)i4Cmd; + rIwReqInfo.flags = 0; + + ASSERT(prDev && prIfReq); + + DBGLOG(P2P, INFO, "p2pDoIOCTL In %x %x\n", i4Cmd, SIOCDEVPRIVATE); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + if (!prGlueInfo) { + DBGLOG(P2P, ERROR, "prGlueInfo is NULL\n"); + return -EFAULT; + } + + if (prGlueInfo->u4ReadyFlag == 0) { + DBGLOG(P2P, ERROR, "Adapter is not ready\n"); + return -EINVAL; + } + + if (i4Cmd == IOCTL_GET_DRIVER) { + ret = priv_support_driver_cmd(prDev, prIfReq, i4Cmd); + } else if (i4Cmd == SIOCGIWPRIV) { + ret = mtk_p2p_wext_get_priv(prDev, &rIwReqInfo, &(prIwReq->u), NULL); + } +#ifdef CFG_ANDROID_AOSP_PRIV_CMD + else if (i4Cmd == SIOCDEVPRIVATE + 1) { + ret = android_private_support_driver_cmd(prDev, prIfReq, i4Cmd); + } +#endif + else { + DBGLOG(INIT, INFO, "Unexpected ioctl command: 0x%04x\n", i4Cmd); + ret = -1; + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To override p2p interface address + * + * \param[in] prDev Net device requested. + * \param[in] addr Pointer to address + * + * \retval 0 For success. + * \retval -E2BIG For user's buffer size is too small. + * \retval -EFAULT For fail. + * + */ +/*----------------------------------------------------------------------------*/ +int p2pSetMACAddress(IN struct net_device *prDev, void *addr) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + ASSERT(prGlueInfo); + + prAdapter = prGlueInfo->prAdapter; + ASSERT(prAdapter); + + /* @FIXME */ + return eth_mac_addr(prDev, addr); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To report the private supported IOCTLs table to user space. + * + * \param[in] prDev Net device requested. + * \param[out] prIfReq Pointer to ifreq structure, content is copied back to + * user space buffer in gl_iwpriv_table. + * + * \retval 0 For success. + * \retval -E2BIG For user's buffer size is too small. + * \retval -EFAULT For fail. + * + */ +/*----------------------------------------------------------------------------*/ +int mtk_p2p_wext_get_priv(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, IN OUT char *extra) +{ + struct iw_point *prData = (struct iw_point *)&wrqu->data; + u16 u2BufferSize = 0; + + ASSERT(prDev); + + u2BufferSize = prData->length; + + /* update our private table size */ + prData->length = + (__u16)sizeof(rP2PIwPrivTable) / sizeof(struct iw_priv_args); + + if (u2BufferSize < prData->length) { + return -E2BIG; + } + + if (prData->length) { + if (copy_to_user(prData->pointer, rP2PIwPrivTable, + sizeof(rP2PIwPrivTable))) { + return -EFAULT; + } + } + + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_p2p_cfg80211.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_p2p_cfg80211.c new file mode 100644 index 00000000000000..50e44593f90d8d --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_p2p_cfg80211.c @@ -0,0 +1,3877 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_p2p_cfg80211.c + * \brief Main routines of Linux driver interface for Wi-Fi Direct + * using cfg80211 interface + * + * This file contains the main routines of Linux driver for MediaTek Inc. + * 802.11 Wireless LAN Adapters. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "config.h" + +#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_WIFI_DIRECT_CFG_80211 +#include <linux/kernel.h> +#include <linux/netdevice.h> +#include <linux/wireless.h> +#include <linux/ieee80211.h> +#include <net/cfg80211.h> + +#include "precomp.h" +#include "gl_cfg80211.h" +#include "gl_p2p_os.h" + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wformat" +#endif + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#if CFG_ENABLE_UNIFY_WIPHY +#define P2P_WIPHY_PRIV(_wiphy, _priv) \ + (_priv = (P_GLUE_INFO_T)wiphy_priv(_wiphy)) +#else +#define P2P_WIPHY_PRIV(_wiphy, _priv) \ + (_priv = *((P_GLUE_INFO_T *)wiphy_priv(_wiphy))) +#endif + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ +u8 mtk_p2p_cfg80211func_channel_sco_switch( + IN enum nl80211_channel_type channel_type, IN P_ENUM_CHNL_EXT_T prChnlSco) +{ + u8 fgIsValid = false; + + do { + if (prChnlSco) { + switch (channel_type) { + case NL80211_CHAN_NO_HT: + *prChnlSco = CHNL_EXT_SCN; + break; + + case NL80211_CHAN_HT20: + *prChnlSco = CHNL_EXT_SCN; + break; + + case NL80211_CHAN_HT40MINUS: + *prChnlSco = CHNL_EXT_SCA; + break; + + case NL80211_CHAN_HT40PLUS: + *prChnlSco = CHNL_EXT_SCB; + break; + + default: + ASSERT(false); + *prChnlSco = CHNL_EXT_SCN; + break; + } + } + + fgIsValid = true; + } while (false); + + return fgIsValid; +} + +u8 mtk_p2p_cfg80211func_channel_format_switch( + IN struct cfg80211_chan_def *channel_def, + IN struct ieee80211_channel *channel, IN P_RF_CHANNEL_INFO_T prRfChnlInfo) +{ + u8 fgIsValid = false; + + do { + if (channel == NULL) { + break; + } + + if (prRfChnlInfo) { + prRfChnlInfo->ucChannelNum = + nicFreq2ChannelNum(channel->center_freq * 1000); + + switch (channel->band) { + case NL80211_BAND_2GHZ: + prRfChnlInfo->eBand = BAND_2G4; + break; + + case NL80211_BAND_5GHZ: + prRfChnlInfo->eBand = BAND_5G; + break; + + default: + prRfChnlInfo->eBand = BAND_2G4; + break; + } + } + + if (channel_def && prRfChnlInfo) { + switch (channel_def->width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + prRfChnlInfo->ucChnlBw = MAX_BW_20MHZ; + break; + + case NL80211_CHAN_WIDTH_40: + prRfChnlInfo->ucChnlBw = MAX_BW_40MHZ; + break; + + case NL80211_CHAN_WIDTH_80: + prRfChnlInfo->ucChnlBw = MAX_BW_80MHZ; + break; + + case NL80211_CHAN_WIDTH_80P80: + prRfChnlInfo->ucChnlBw = MAX_BW_80_80_MHZ; + break; + + case NL80211_CHAN_WIDTH_160: + prRfChnlInfo->ucChnlBw = MAX_BW_160MHZ; + break; + + default: + prRfChnlInfo->ucChnlBw = MAX_BW_20MHZ; + break; + } + prRfChnlInfo->u2PriChnlFreq = channel->center_freq; + prRfChnlInfo->u4CenterFreq1 = channel_def->center_freq1; + prRfChnlInfo->u4CenterFreq2 = channel_def->center_freq2; + +#if (CFG_SUPPORT_DFS_MASTER == 1) + prRfChnlInfo->u4ChnlDfsState = channel->dfs_state; +#endif + } + + fgIsValid = true; + } while (false); + + return fgIsValid; +} + +/* mtk_p2p_cfg80211func_channel_format_switch */ + +s32 mtk_Netdev_To_RoleIdx(P_GLUE_INFO_T prGlueInfo, struct net_device *ndev, + u8 *pucRoleIdx) +{ + s32 i4Ret = -1; + u32 u4Idx = 0; + + if ((pucRoleIdx == NULL) || (ndev == NULL)) { + return i4Ret; + } + + if (prGlueInfo == NULL || prGlueInfo->prAdapter == NULL || + prGlueInfo->prAdapter->prP2pInfo == NULL) { + DBGLOG(INIT, ERROR, "prGlueInfo || prAdapter || prP2pInfo == NULL\n"); + return i4Ret; + } + + /* The prP2PInfo[0] may be removed and prP2PInfo[1] is existing + * under cfg80211 operation. So that check all KAL_P2P_NUM not only + * prGlueInfo->prAdapter->prP2pInfo->u4DeviceNum. + */ + for (u4Idx = 0; u4Idx < KAL_P2P_NUM; u4Idx++) { + if ((prGlueInfo->prP2PInfo[u4Idx] != NULL) && + (prGlueInfo->prP2PInfo[u4Idx]->aprRoleHandler != NULL) && + (prGlueInfo->prP2PInfo[u4Idx]->aprRoleHandler == ndev)) { + *pucRoleIdx = (u8)u4Idx; + i4Ret = 0; + } + } + + return i4Ret; +} + +static void mtk_vif_destructor(struct net_device *dev) +{ + struct wireless_dev *prWdev = ERR_PTR(-ENOMEM); + u32 u4Idx = 0; + + DBGLOG(P2P, INFO, "mtk_vif_destructor\n"); + if (dev) { + prWdev = dev->ieee80211_ptr; + free_netdev(dev); + /* Expect that the gprP2pWdev isn't freed here */ + if ((prWdev) && (prWdev != gprP2pWdev)) { + /* Role[i] and Dev share the same wdev by default */ + for (u4Idx = 0; u4Idx < KAL_P2P_NUM; u4Idx++) { + if (prWdev != gprP2pRoleWdev[u4Idx]) { + continue; + } + /* In the initWlan gprP2pRoleWdev[0] is equal to + * gprP2pWdev. And other gprP2pRoleWdev[] should + * be NULL, if the 2nd P2P dev isn't created. + */ + if (u4Idx == 0) { + gprP2pRoleWdev[u4Idx] = gprP2pWdev; + } else { + gprP2pRoleWdev[u4Idx] = NULL; + } + break; + } + kfree(prWdev); + } + } +} + +#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE +struct wireless_dev *mtk_p2p_cfg80211_add_iface(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + struct vif_params *params) +#else +struct wireless_dev *mtk_p2p_cfg80211_add_iface( + struct wiphy *wiphy, const char *name, unsigned char name_assign_type, + enum nl80211_iftype type, u32 *flags, struct vif_params *params) +#endif +{ + /* 2 TODO: Fit kernel 3.10 modification */ + P_ADAPTER_T prAdapter; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + struct net_device *prNewNetDevice = NULL; + u32 u4Idx = 0; + P_GL_P2P_INFO_T prP2pInfo = (P_GL_P2P_INFO_T)NULL; + P_GL_HIF_INFO_T prHif = NULL; + P_MSG_P2P_SWITCH_OP_MODE_T prSwitchModeMsg = + (P_MSG_P2P_SWITCH_OP_MODE_T)NULL; + struct wireless_dev *prWdev = ERR_PTR(-ENOMEM); + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPriv = (P_NETDEV_PRIVATE_GLUE_INFO)NULL; + PARAM_MAC_ADDRESS rMacAddr; + P_MSG_P2P_ACTIVE_DEV_BSS_T prMsgActiveBss = + (P_MSG_P2P_ACTIVE_DEV_BSS_T)NULL; + + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_add_iface\n"); + + do { + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (prGlueInfo == NULL) { + break; + } + + prAdapter = prGlueInfo->prAdapter; + + for (u4Idx = 0; u4Idx < KAL_P2P_NUM; u4Idx++) { + prP2pInfo = prGlueInfo->prP2PInfo[u4Idx]; + /* Expect that only create the new dev with the p2p0 */ + if (prP2pInfo == NULL) { + continue; + } + if (prP2pInfo->aprRoleHandler == prP2pInfo->prDevHandler) { + break; + } + if (prP2pInfo->aprRoleHandler == NULL) { + p2pRoleFsmInit(prGlueInfo->prAdapter, u4Idx); + break; + } + } + + if (u4Idx == KAL_P2P_NUM) { + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_add_iface u4Idx=%d\n", u4Idx); + + prP2pInfo = prGlueInfo->prP2PInfo[u4Idx]; + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_add_iface name = %s\n", name); + + prNewNetDevice = alloc_netdev_mq(sizeof(NETDEV_PRIVATE_GLUE_INFO), name, + NET_NAME_PREDICTABLE, ether_setup, + CFG_MAX_TXQ_NUM); + + if (prNewNetDevice == NULL) { + DBGLOG(P2P, TRACE, "alloc_netdev_mq fail\n"); + break; + } + prP2pInfo->aprRoleHandler = prNewNetDevice; + + *((P_GLUE_INFO_T *)netdev_priv(prNewNetDevice)) = prGlueInfo; + + prNewNetDevice->needed_headroom += NIC_TX_HEAD_ROOM; + prNewNetDevice->netdev_ops = &p2p_netdev_ops; + + prHif = &prGlueInfo->rHifInfo; + ASSERT(prHif); + + SET_NETDEV_DEV(prNewNetDevice, &(prHif->func->dev)); + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + prWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!prWdev) { + DBGLOG(P2P, ERROR, + "allocate p2p wireless device fail, no memory\n"); +#if CFG_ENABLE_UNIFY_WIPHY + free_netdev(prP2pInfo->aprRoleHandler); + prP2pInfo->aprRoleHandler = NULL; +#else + prWdev = ERR_PTR(-ENOMEM); + free_netdev(prP2pInfo->aprRoleHandler); + prP2pInfo->aprRoleHandler = NULL; +#endif + break; + } + kalMemCopy(prWdev, gprP2pWdev, sizeof(struct wireless_dev)); + prWdev->netdev = prNewNetDevice; + prWdev->iftype = type; + prNewNetDevice->ieee80211_ptr = prWdev; + + /* register destructor function for virtual interface */ +#if KERNEL_VERSION(4, 11, 0) <= CFG80211_VERSION_CODE + prNewNetDevice->priv_destructor = mtk_vif_destructor; +#else + prNewNetDevice->destructor = mtk_vif_destructor; +#endif + + gprP2pRoleWdev[u4Idx] = prWdev; + /*prP2pInfo->prRoleWdev[0] = prWdev;*/ /* TH3 multiple P2P */ +#endif + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + /* set HW checksum offload */ + if (prAdapter->fgIsSupportCsumOffload) { + prNewNetDevice->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM; + } +#endif + + kalResetStats(prNewNetDevice); + + /* register for net device */ +#if KERNEL_VERSION(5, 12, 0) <= CFG80211_VERSION_CODE + if (cfg80211_register_netdevice(prP2pInfo->aprRoleHandler) < 0) { +#else + if (register_netdevice(prP2pInfo->aprRoleHandler) < 0) { +#endif + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_add_iface 456\n"); + DBGLOG(INIT, WARN, "unable to register netdevice for p2p\n"); + kfree(prWdev); + prWdev = ERR_PTR(-ENOMEM); + free_netdev(prP2pInfo->aprRoleHandler); + +#if CFG_ENABLE_UNIFY_WIPHY + kfree(prWdev); + prP2pInfo->aprRoleHandler = NULL; +#endif + + prP2pInfo->aprRoleHandler = NULL; + break; + } else { + DBGLOG(P2P, TRACE, "register_netdev OK, iftype:%d\n", + prNewNetDevice->ieee80211_ptr->iftype); + prGlueInfo->prAdapter->rP2PNetRegState = + ENUM_NET_REG_STATE_REGISTERED; + + netif_carrier_off(prP2pInfo->aprRoleHandler); + netif_tx_stop_all_queues(prP2pInfo->aprRoleHandler); + } + prP2pRoleFsmInfo = prAdapter->rWifiVar.aprP2pRoleFsmInfo[u4Idx]; + + /* 13. bind netdev pointer to netdev index */ + wlanBindBssIdxToNetInterface(prGlueInfo, prP2pRoleFsmInfo->ucBssIndex, + (void *)prP2pInfo->aprRoleHandler); + prNetDevPriv = + (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(prP2pInfo->aprRoleHandler); + prNetDevPriv->prGlueInfo = prGlueInfo; + prNetDevPriv->ucBssIdx = prP2pRoleFsmInfo->ucBssIndex; + +#if CFG_ENABLE_UNIFY_WIPHY + /* Expect that only P2P device uses the cfg80211_add_iface */ + prNetDevPriv->ucIsP2p = true; +#endif + /* 4.2 fill hardware address */ + COPY_MAC_ADDR(rMacAddr, prAdapter->rMyMacAddr); + if (prGlueInfo->prAdapter->rWifiVar.ucP2pShareMacAddr && + (type == NL80211_IFTYPE_P2P_CLIENT || + type == NL80211_IFTYPE_P2P_GO)) { + rMacAddr[0] = gPrP2pDev[0]->dev_addr[0]; + } else { + rMacAddr[0] |= 0x2; /* change to local administrated + * address */ + if (u4Idx > 0) { + rMacAddr[0] ^= u4Idx << 2; + } else { + rMacAddr[0] ^= prGlueInfo->prAdapter->prP2pInfo->u4DeviceNum + << 2; + } + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0) + kalMemCopy(prNewNetDevice->dev_addr, rMacAddr, ETH_ALEN); +#else + dev_addr_set(prNewNetDevice, rMacAddr); +#endif + kalMemCopy(prNewNetDevice->perm_addr, rMacAddr, ETH_ALEN); +#if CFG_MESON_G12A_PATCH + prNewNetDevice->mtu = 1408; +#endif + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_add_iface ucBssIdx=%d\n", + prNetDevPriv->ucBssIdx); + + /* Switch OP MOde. */ + prSwitchModeMsg = (P_MSG_P2P_SWITCH_OP_MODE_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_SWITCH_OP_MODE_T)); + + if (prSwitchModeMsg == NULL) { + ASSERT(false); + DBGLOG(INIT, WARN, "unable to alloc msg\n"); + kfree(prWdev); + prWdev = ERR_PTR(-ENOMEM); + free_netdev(prGlueInfo->prP2PInfo[u4Idx]->aprRoleHandler); +#if CFG_ENABLE_UNIFY_WIPHY + // kfree(prWdev); + prP2pInfo->aprRoleHandler = NULL; +#endif + prGlueInfo->prP2PInfo[u4Idx]->aprRoleHandler = NULL; + break; + } else { + prSwitchModeMsg->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + prSwitchModeMsg->ucRoleIdx = 0; + switch (type) { + case NL80211_IFTYPE_P2P_CLIENT: + DBGLOG(P2P, TRACE, "NL80211_IFTYPE_P2P_CLIENT.\n"); + prSwitchModeMsg->eOpMode = OP_MODE_INFRASTRUCTURE; + kalP2PSetRole(prGlueInfo, 1, u4Idx); + break; + + case NL80211_IFTYPE_STATION: + DBGLOG(P2P, TRACE, "NL80211_IFTYPE_STATION.\n"); + prSwitchModeMsg->eOpMode = OP_MODE_INFRASTRUCTURE; + kalP2PSetRole(prGlueInfo, 1, u4Idx); + break; + + case NL80211_IFTYPE_AP: + DBGLOG(P2P, TRACE, "NL80211_IFTYPE_AP.\n"); + prSwitchModeMsg->eOpMode = OP_MODE_ACCESS_POINT; + kalP2PSetRole(prGlueInfo, 2, u4Idx); + break; + + case NL80211_IFTYPE_P2P_GO: + DBGLOG(P2P, TRACE, "NL80211_IFTYPE_P2P_GO not AP.\n"); + prSwitchModeMsg->eOpMode = OP_MODE_ACCESS_POINT; + kalP2PSetRole(prGlueInfo, 2, u4Idx); + break; + + default: + DBGLOG(P2P, TRACE, "Other type :%d .\n", type); + prSwitchModeMsg->eOpMode = OP_MODE_P2P_DEVICE; + kalP2PSetRole(prGlueInfo, 0, u4Idx); + break; + } + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prSwitchModeMsg, MSG_SEND_METHOD_BUF); + } + + /* Send Msg to DevFsm and active P2P dev BSS */ + prMsgActiveBss = (P_MSG_P2P_ACTIVE_DEV_BSS_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_ACTIVE_DEV_BSS_T)); + +#if CFG_ENABLE_UNIFY_WIPHY + if (prMsgActiveBss == NULL) { + DBGLOG(INIT, WARN, "unable to alloc prMsgActiveBss\n"); + kfree(prWdev); + free_netdev(prP2pInfo->aprRoleHandler); + prP2pInfo->aprRoleHandler = NULL; + /* FIMXE: What is the error handler? + * The gprP2pRoleWdev[0] is default as gprP2pWdev. + */ + gprP2pRoleWdev[u4Idx] = gprP2pWdev; + break; + } +#else + if (prMsgActiveBss == NULL) { + ASSERT(false); + DBGLOG(INIT, WARN, "unable to alloc msg\n"); + kfree(prWdev); + prWdev = ERR_PTR(-ENOMEM); + free_netdev(prGlueInfo->prP2PInfo[u4Idx]->aprRoleHandler); + prGlueInfo->prP2PInfo[u4Idx]->aprRoleHandler = NULL; + break; + } +#endif + + prMsgActiveBss->rMsgHdr.eMsgId = MID_MNY_P2P_ACTIVE_BSS; + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prMsgActiveBss, MSG_SEND_METHOD_BUF); + } while (false); + + return prWdev; +} + +int mtk_p2p_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + P_MSG_P2P_DEL_IFACE_T prP2pDelIfaceMsg = (P_MSG_P2P_DEL_IFACE_T)NULL; + P_ADAPTER_T prAdapter; + P_GL_P2P_INFO_T prP2pInfo = (P_GL_P2P_INFO_T)NULL; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_GL_P2P_DEV_INFO_T prP2pGlueDevInfo = (P_GL_P2P_DEV_INFO_T)NULL; + struct net_device *UnregRoleHander = (struct net_device *)NULL; + unsigned char ucBssIdx = 0; + P_BSS_INFO_T prP2pBssInfo = NULL; +#if CFG_ENABLE_UNIFY_WIPHY + struct cfg80211_scan_request *prScanRequest = NULL; +#endif + GLUE_SPIN_LOCK_DECLARATION(); + + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_del_iface\n"); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + if (prGlueInfo == NULL) { + return -EINVAL; + } + + prAdapter = prGlueInfo->prAdapter; + prP2pInfo = prGlueInfo->prP2PInfo[0]; + prP2pGlueDevInfo = prGlueInfo->prP2PDevInfo; + + if ((prP2pInfo == NULL) || (prP2pInfo->aprRoleHandler == NULL) || + (prP2pInfo->aprRoleHandler == prP2pInfo->prDevHandler)) { + /* This iface isn't added. */ + return -EINVAL; + } + + KAL_ACQUIRE_MUTEX(prAdapter, MUTEX_DEL_INF); + + prP2pRoleFsmInfo = prAdapter->rWifiVar.aprP2pRoleFsmInfo[0]; + if (prP2pRoleFsmInfo == NULL) { + KAL_RELEASE_MUTEX(prAdapter, MUTEX_DEL_INF); + return -EINVAL; + } + ucBssIdx = prP2pRoleFsmInfo->ucBssIndex; + wlanBindBssIdxToNetInterface(prGlueInfo, ucBssIdx, + (void *)prGlueInfo->prP2PInfo[0]->prDevHandler); + + UnregRoleHander = prP2pInfo->aprRoleHandler; + + /* fix that the kernel warning occures when the GC is connected */ + prP2pBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIdx); + if ((prP2pBssInfo != NULL) && + (prP2pBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) && + (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { + cfg80211_disconnected(UnregRoleHander, 0, NULL, 0, true, GFP_KERNEL); + } + /* Wait for kalSendCompleteAndAwakeQueue() complete */ + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + prP2pInfo->aprRoleHandler = prP2pInfo->prDevHandler; + +#if CFG_ENABLE_UNIFY_WIPHY + prScanRequest = prP2pGlueDevInfo->prScanRequest; + if ((prScanRequest != NULL) && + (prScanRequest->wdev == UnregRoleHander->ieee80211_ptr)) { + prP2pGlueDevInfo->prScanRequest = NULL; + } +#endif + + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + /* Check the Scan request is pending and we abort it before delete + * interface */ + +#if CFG_ENABLE_UNIFY_WIPHY + if (prScanRequest) { + kalCfg80211ScanDone(prScanRequest, true); + } +#else + + if (prP2pGlueDevInfo->prScanRequest != NULL) { + /* Check the wdev with backup scan req due to */ + /* the kernel will free this request by error handling */ + if (prP2pGlueDevInfo->rBackupScanRequest.wdev == + UnregRoleHander->ieee80211_ptr) { + kalCfg80211ScanDone(&(prP2pGlueDevInfo->rBackupScanRequest), true); + /* clear the request to avoid the Role FSM calls the + * scan_done again */ + prP2pGlueDevInfo->prScanRequest = NULL; + } + } +#endif + + /* prepare for removal */ + if (netif_carrier_ok(UnregRoleHander)) { + netif_carrier_off(UnregRoleHander); + } + + netif_tx_stop_all_queues(UnregRoleHander); + + /* Here are functions which need rtnl_lock */ +#if KERNEL_VERSION(5, 12, 0) <= CFG80211_VERSION_CODE + cfg80211_unregister_netdevice(UnregRoleHander); +#else + unregister_netdevice(UnregRoleHander); +#endif + + /* free is called at destructor */ + /* free_netdev(UnregRoleHander); */ + +#if CFG_ENABLE_UNIFY_WIPHY + /* Role[0] and Dev share the same wireless dev */ + gprP2pRoleWdev[0] = gprP2pWdev; +#endif + + KAL_RELEASE_MUTEX(prAdapter, MUTEX_DEL_INF); + + prP2pDelIfaceMsg = (P_MSG_P2P_DEL_IFACE_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_DEL_IFACE_T)); + + if (prP2pDelIfaceMsg == NULL) { + ASSERT(false); + DBGLOG(INIT, WARN, "unable to alloc msg\n"); + } else { + prP2pDelIfaceMsg->rMsgHdr.eMsgId = MID_MNY_P2P_DEL_IFACE; + prP2pDelIfaceMsg->ucRoleIdx = 0; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prP2pDelIfaceMsg, MSG_SEND_METHOD_BUF); + } + + return 0; +} + +int mtk_p2p_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index, bool pairwise, const u8 *mac_addr, + struct key_params *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Rslt = -EINVAL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + P2P_PARAM_KEY_T rKey; + u8 ucRoleIdx = 0; + const u8 aucBCAddr[] = BC_MAC_ADDR; + /* const u8 aucZeroMacAddr[] = NULL_MAC_ADDR; */ +#if CFG_SUPPORT_REPLAY_DETECTION + P_BSS_INFO_T prBssInfo = NULL; + struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL; + u8 ucCheckZeroKey = 0; + u8 i = 0; +#endif + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, ndev, &ucRoleIdx) != 0) { + return -EINVAL; + } + +#if DBG + DBGLOG(RSN, TRACE, "mtk_p2p_cfg80211_add_key\n"); + if (mac_addr) { + DBGLOG(RSN, INFO, "keyIdx = %d pairwise = %d mac = " MACSTR "\n", + key_index, pairwise, MAC2STR(mac_addr)); + } else { + DBGLOG(RSN, INFO, "keyIdx = %d pairwise = %d null mac\n", key_index, + pairwise); + } + DBGLOG(RSN, TRACE, "Cipher = %x\n", params->cipher); + DBGLOG_MEM8(RSN, TRACE, params->key, params->key_len); +#endif + + /* Todo:: By Cipher to set the key */ + + kalMemZero(&rKey, sizeof(P2P_PARAM_KEY_T)); + + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &rKey.ucBssIdx) != + WLAN_STATUS_SUCCESS) { + return -EINVAL; + } + + rKey.u4KeyIndex = key_index; + + if (params->cipher) { + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + rKey.ucCipher = CIPHER_SUITE_WEP40; + break; + + case WLAN_CIPHER_SUITE_WEP104: + rKey.ucCipher = CIPHER_SUITE_WEP104; + break; + + case WLAN_CIPHER_SUITE_TKIP: + rKey.ucCipher = CIPHER_SUITE_TKIP; + break; + + case WLAN_CIPHER_SUITE_CCMP: + rKey.ucCipher = CIPHER_SUITE_CCMP; + break; + + case WLAN_CIPHER_SUITE_SMS4: + rKey.ucCipher = CIPHER_SUITE_WPI; + break; + + case WLAN_CIPHER_SUITE_AES_CMAC: + rKey.ucCipher = CIPHER_SUITE_BIP; + break; + + default: + ASSERT(false); + } + } + + /* For BC addr case: ex: AP mode, driver_nl80211 will not have mac_addr + */ + if (pairwise) { + rKey.u4KeyIndex |= BIT(31); /* Tx */ + rKey.u4KeyIndex |= BIT(30); /* Pairwise */ + COPY_MAC_ADDR(rKey.arBSSID, mac_addr); + } else { + COPY_MAC_ADDR(rKey.arBSSID, aucBCAddr); + } + + /* Check if add key under AP mode */ + if (kalP2PGetRole(prGlueInfo, ucRoleIdx) == 2) { + rKey.u4KeyIndex |= BIT(28); /* authenticator */ + } +#if CFG_SUPPORT_REPLAY_DETECTION + if (params->key) { + for (i = 0; i < params->key_len; i++) + if (params->key[i] == 0x00) { + ucCheckZeroKey++; + } + + if (ucCheckZeroKey == params->key_len) { + return 0; + } + } +#endif + + if (params->key) { + kalMemCopy(rKey.aucKeyMaterial, params->key, params->key_len); + } + rKey.u4KeyLength = params->key_len; + rKey.u4Length = ((unsigned long)&(((P_P2P_PARAM_KEY_T)0)->aucKeyMaterial)) + + rKey.u4KeyLength; + +#if CFG_SUPPORT_REPLAY_DETECTION + prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, rKey.ucBssIdx); + + prDetRplyInfo = &prBssInfo->rDetRplyInfo; + + if ((!pairwise) && ((params->cipher == WLAN_CIPHER_SUITE_TKIP) || + (params->cipher == WLAN_CIPHER_SUITE_CCMP))) { + if ((prDetRplyInfo->ucCurKeyId == key_index) && + (!kalMemCmp(prDetRplyInfo->aucKeyMaterial, params->key, + params->key_len))) { + DBGLOG(RSN, TRACE, "M3/G1, KeyID and KeyValue equal.\n"); + DBGLOG(RSN, TRACE, + "hit group key reinstall case, so no update BC/MC PN.\n"); + } else { + kalMemCopy(prDetRplyInfo->arReplayPNInfo[key_index].auPN, + params->seq, params->seq_len); + prDetRplyInfo->ucCurKeyId = key_index; + prDetRplyInfo->u4KeyLength = params->key_len; + kalMemCopy(prDetRplyInfo->aucKeyMaterial, params->key, + params->key_len); + } + + prDetRplyInfo->fgKeyRscFresh = true; + } +#endif + + rStatus = kalIoctl(prGlueInfo, wlanoidSetAddKey, &rKey, rKey.u4Length, + false, false, true, &u4BufLen); + if (rStatus == WLAN_STATUS_SUCCESS) { + i4Rslt = 0; + } + + return i4Rslt; +} + +int mtk_p2p_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index, bool pairwise, const u8 *mac_addr, + void *cookie, + void (*callback)(void *cookie, + struct key_params *)) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + /* not implemented yet */ + + return -EINVAL; +} + +int mtk_p2p_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index, bool pairwise, const u8 *mac_addr) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_REMOVE_KEY_T rRemoveKey; + s32 i4Rslt = -EINVAL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + u8 ucRoleIdx = 0; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, ndev, &ucRoleIdx) < 0) { + return -EINVAL; + } + +#if DBG + DBGLOG(RSN, TRACE, "mtk_p2p_cfg80211_del_key\n"); + if (mac_addr) { + DBGLOG(RSN, TRACE, "keyIdx = %d pairwise = %d mac = " MACSTR "\n", + key_index, pairwise, MAC2STR(mac_addr)); + } else { + DBGLOG(RSN, TRACE, "keyIdx = %d pairwise = %d null mac\n", key_index, + pairwise); + } +#endif + + kalMemZero(&rRemoveKey, sizeof(PARAM_REMOVE_KEY_T)); + + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, + &rRemoveKey.ucBssIdx) != WLAN_STATUS_SUCCESS) { + return -EINVAL; + } + + if (mac_addr) { + COPY_MAC_ADDR(rRemoveKey.arBSSID, mac_addr); + } + rRemoveKey.u4KeyIndex = key_index; + rRemoveKey.u4Length = sizeof(PARAM_REMOVE_KEY_T); + if (mac_addr) { + COPY_MAC_ADDR(rRemoveKey.arBSSID, mac_addr); + rRemoveKey.u4KeyIndex |= BIT(30); + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetRemoveKey, &rRemoveKey, + rRemoveKey.u4Length, false, false, true, &u4BufLen); + + if (rStatus == WLAN_STATUS_SUCCESS) { + i4Rslt = 0; + } + + return i4Rslt; +} + +int mtk_p2p_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *netdev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index, bool unicast, + bool multicast) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_DEFAULT_KEY_T rDefaultKey; + u8 ucRoleIdx = 0; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + s32 i4Rst = -EINVAL; + u32 u4BufLen = 0; + u8 fgDef = false, fgMgtDef = false; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, netdev, &ucRoleIdx) != 0) { + return -EINVAL; + } + +#if DBG + DBGLOG(RSN, TRACE, "mtk_p2p_cfg80211_set_default_key\n"); + DBGLOG(RSN, TRACE, "keyIdx = %d unicast = %d multicast = %d\n", key_index, + unicast, multicast); +#endif + + /* For wep case, this set the key for tx */ + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, + &rDefaultKey.ucBssIdx) != WLAN_STATUS_SUCCESS) { + return -EINVAL; + } + + rDefaultKey.ucKeyID = key_index; + rDefaultKey.ucUnicast = unicast; + rDefaultKey.ucMulticast = multicast; + if (rDefaultKey.ucUnicast && !rDefaultKey.ucMulticast) { + return WLAN_STATUS_SUCCESS; + } + + if (rDefaultKey.ucUnicast && rDefaultKey.ucMulticast) { + fgDef = true; + } + + if (!rDefaultKey.ucUnicast && rDefaultKey.ucMulticast) { + fgMgtDef = true; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetDefaultKey, &rDefaultKey, + sizeof(PARAM_DEFAULT_KEY_T), false, false, true, + &u4BufLen); + + if (rStatus == WLAN_STATUS_SUCCESS) { + i4Rst = 0; + } + + return i4Rst; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief This routine is responsible for setting the default mgmt key index + * + * @param + * + * @retval 0: successful + * others: failure + */ +/*----------------------------------------------------------------------------*/ +int mtk_p2p_cfg80211_set_mgmt_key(struct wiphy *wiphy, struct net_device *dev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index) +{ + DBGLOG(RSN, INFO, "mtk_p2p_cfg80211_set_mgmt_key, kid:%d\n", key_index); + + return 0; +} + +int mtk_p2p_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, + const u8 *mac, struct station_info *sinfo) +{ + s32 i4RetRslt = -EINVAL; + u8 ucRoleIdx = 0; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T)NULL; + P2P_STATION_INFO_T rP2pStaInfo; + s32 i4Rssi = 0; + u8 ucBssIdx = 0; + u32 u4Rate = 0; + P_BSS_INFO_T prBssInfo; + P_PARAM_GET_STA_STATISTICS prQuery; + + ASSERT(wiphy); + + do { + if ((wiphy == NULL) || (ndev == NULL) || (sinfo == NULL) || + (mac == NULL)) { + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_get_station\n"); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, ndev, &ucRoleIdx) != 0) { + return -EINVAL; + } + + prP2pGlueInfo = prGlueInfo->prP2PInfo[ucRoleIdx]; + + /* Get station information. */ + /* 1. Inactive time? */ + p2pFuncGetStationInfo(prGlueInfo->prAdapter, (u8 *)mac, &rP2pStaInfo); + + /* Inactive time. */ + sinfo->filled |= BIT(NL80211_STA_INFO_INACTIVE_TIME); + sinfo->inactive_time = rP2pStaInfo.u4InactiveTime; + sinfo->generation = prP2pGlueInfo->i4Generation; + + /* 2. fill TX rate */ + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &ucBssIdx) != + WLAN_STATUS_SUCCESS) { + return -EINVAL; + } + prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, ucBssIdx); + if (!prBssInfo) { + DBGLOG(P2P, WARN, "bss is not active\n"); + return -EINVAL; + } + if (prBssInfo->eConnectionState != PARAM_MEDIA_STATE_CONNECTED) { + /* not connected */ + DBGLOG(P2P, WARN, "not yet connected\n"); + return 0; + } + + prQuery = + prGlueInfo->prAdapter->rWifiVar.prP2pQueryStaStatistics[ucRoleIdx]; + if (prQuery) { + u4Rate = prQuery->u2LinkSpeed * 5000; + i4Rssi = RCPI_TO_dBm(prQuery->ucRcpi); + } + + sinfo->txrate.legacy = u4Rate / 1000; + sinfo->signal = i4Rssi; + + DBGLOG(P2P, INFO, "ucRoleIdx = %d, rate = %u, signal = %d\n", ucRoleIdx, + sinfo->txrate.legacy, sinfo->signal); + + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE); + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); + + i4RetRslt = 0; + } while (false); + + return i4RetRslt; +} + +int mtk_p2p_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T)NULL; + P_GL_P2P_DEV_INFO_T prP2pGlueDevInfo = (P_GL_P2P_DEV_INFO_T)NULL; + P_MSG_P2P_SCAN_REQUEST_T prMsgScanRequest = (P_MSG_P2P_SCAN_REQUEST_T)NULL; + u32 u4MsgSize = 0, u4Idx = 0; + u32 rStatus, u4SetInfoLen = 0; + s32 i4RetRslt = -EINVAL; + P_RF_CHANNEL_INFO_T prRfChannelInfo = (P_RF_CHANNEL_INFO_T)NULL; + P_P2P_SSID_STRUCT_T prSsidStruct = (P_P2P_SSID_STRUCT_T)NULL; + struct ieee80211_channel *prChannel = NULL; + struct cfg80211_ssid *prSsid = NULL; + u8 ucBssIdx = 0; + u8 fgIsFullChanScan = false; + + /* [---------Channel---------] + * [---------SSID---------][---------IE---------] */ + + do { + if ((wiphy == NULL) || (request == NULL)) { + break; + } + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (wlanIsChipAssert(prGlueInfo->prAdapter)) { + break; + } + + prP2pGlueInfo = prGlueInfo->prP2PInfo[0]; + prP2pGlueDevInfo = prGlueInfo->prP2PDevInfo; + + if ((prP2pGlueInfo == NULL) || (prP2pGlueDevInfo == NULL)) { + ASSERT(false); + break; + } + + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_scan.\n"); + + if (prP2pGlueDevInfo->prScanRequest != NULL) { + /* There have been a scan request on-going processing. + */ + DBGLOG(P2P, TRACE, + "There have been a scan request on-going processing.\n"); + break; + } + + prP2pGlueDevInfo->prScanRequest = request; + + /* Should find out why the n_channels so many? */ + if (request->n_channels > MAXIMUM_OPERATION_CHANNEL_LIST) { + request->n_channels = MAXIMUM_OPERATION_CHANNEL_LIST; + fgIsFullChanScan = true; + DBGLOG(P2P, TRACE, "Channel list exceed the maximun support.\n"); + } + /* TODO: */ + /* Find a way to distinct DEV port scan & ROLE port scan. + */ + ucBssIdx = P2P_DEV_BSS_INDEX; + DBGLOG(P2P, TRACE, "Device Port Scan.\n"); + + u4MsgSize = sizeof(MSG_P2P_SCAN_REQUEST_T) + + (request->n_channels * sizeof(RF_CHANNEL_INFO_T)) + + (request->n_ssids * sizeof(PARAM_SSID_T)) + request->ie_len; + + prMsgScanRequest = + cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, u4MsgSize); + + if (prMsgScanRequest == NULL) { + ASSERT(false); + i4RetRslt = -ENOMEM; + break; + } + + DBGLOG(P2P, TRACE, "Generating scan request message.\n"); + + prMsgScanRequest->rMsgHdr.eMsgId = MID_MNY_P2P_DEVICE_DISCOVERY; + prMsgScanRequest->eScanType = SCAN_TYPE_ACTIVE_SCAN; + prMsgScanRequest->ucBssIdx = ucBssIdx; + + DBGLOG(P2P, INFO, "Requesting channel number:%d.\n", + request->n_channels); + + for (u4Idx = 0; u4Idx < request->n_channels; u4Idx++) { + /* Translate Freq from MHz to channel number. */ + prRfChannelInfo = &(prMsgScanRequest->arChannelListInfo[u4Idx]); + prChannel = request->channels[u4Idx]; + + prRfChannelInfo->ucChannelNum = + nicFreq2ChannelNum(prChannel->center_freq * 1000); + DBGLOG(P2P, TRACE, "Scanning Channel:%d, freq: %d\n", + prRfChannelInfo->ucChannelNum, prChannel->center_freq); + switch (prChannel->band) { + case NL80211_BAND_2GHZ: + prRfChannelInfo->eBand = BAND_2G4; + break; + + case NL80211_BAND_5GHZ: + prRfChannelInfo->eBand = BAND_5G; + break; + + default: + DBGLOG(P2P, TRACE, "UNKNOWN Band info from supplicant\n"); + prRfChannelInfo->eBand = BAND_NULL; + break; + } + + /* Iteration. */ + prRfChannelInfo++; + } + prMsgScanRequest->u4NumChannel = request->n_channels; + if (fgIsFullChanScan) { + prMsgScanRequest->u4NumChannel = SCN_P2P_FULL_SCAN_PARAM; + DBGLOG(P2P, INFO, + "request->n_channels = SCN_P2P_FULL_SCAN_PARAM\n"); + } + DBGLOG(P2P, TRACE, "Finish channel list.\n"); + + /* SSID */ + prSsid = request->ssids; + prSsidStruct = (P_P2P_SSID_STRUCT_T)prRfChannelInfo; + if (request->n_ssids) { + ASSERT( + (unsigned long)prSsidStruct == + (unsigned long)&(prMsgScanRequest->arChannelListInfo[u4Idx])); + prMsgScanRequest->prSSID = prSsidStruct; + } + + for (u4Idx = 0; u4Idx < request->n_ssids; u4Idx++) { + COPY_SSID(prSsidStruct->aucSsid, prSsidStruct->ucSsidLen, + request->ssids->ssid, request->ssids->ssid_len); + + prSsidStruct++; + prSsid++; + } + + prMsgScanRequest->i4SsidNum = request->n_ssids; + + DBGLOG(P2P, TRACE, "Finish SSID list:%d.\n", request->n_ssids); + + /* IE BUFFERS */ + prMsgScanRequest->pucIEBuf = (u8 *)prSsidStruct; + if (request->ie_len) { + kalMemCopy(prMsgScanRequest->pucIEBuf, request->ie, + request->ie_len); + prMsgScanRequest->u4IELen = request->ie_len; + } else { + prMsgScanRequest->u4IELen = 0; + } + + DBGLOG(P2P, TRACE, "Finish IE Buffer.\n"); + + /* Abort previous scan */ + rStatus = kalIoctl(prGlueInfo, wlanoidAbortP2pScan, &ucBssIdx, + sizeof(ucBssIdx), false, false, true, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "mtk_p2p_cfg80211_scan abort scan fail 0x%x\n", + rStatus); + } + + prP2pGlueDevInfo->prScanRequest = request; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prMsgScanRequest, MSG_SEND_METHOD_BUF); + +#if 0 + /* Backup scan request structure */ + /* The purpose of this backup is due to the kernel free the scan + * req */ + /* when the wpa supplicant down the iface before down, and it + * will */ + /* free the original scan request structure */ + /* In this case, the scan resoure could be locked by kernel, and + */ + /* driver needs this work around to clear the state */ + kalMemCopy(&(prP2pGlueDevInfo->rBackupScanRequest), request, + sizeof(struct cfg80211_scan_request)); +#endif + + i4RetRslt = 0; + } while (false); + + return i4RetRslt; +} + +void mtk_p2p_cfg80211_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + u32 u4SetInfoLen = 0; + u32 u4Value = 0; + u32 rStatus; + P_GLUE_INFO_T prGlueInfo = NULL; + + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_abort_scan\n"); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + rStatus = kalIoctl(prGlueInfo, wlanoidAbortP2pScan, &u4Value, + sizeof(u4Value), false, false, true, &u4SetInfoLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "mtk_p2p_cfg80211_abort_scan fail 0x%x\n", rStatus); + } +} + +int mtk_p2p_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + s32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = NULL; + + do { + if (wiphy == NULL) { + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_wiphy_params\n"); + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (changed & WIPHY_PARAM_RETRY_SHORT) { + /* TODO: */ + DBGLOG(P2P, TRACE, "The RETRY short param is changed.\n"); + } + + if (changed & WIPHY_PARAM_RETRY_LONG) { + /* TODO: */ + DBGLOG(P2P, TRACE, "The RETRY long param is changed.\n"); + } + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + /* TODO: */ + DBGLOG(P2P, TRACE, + "The RETRY fragmentation threshold is changed.\n"); + } + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + /* TODO: */ + DBGLOG(P2P, TRACE, "The RETRY RTS threshold is changed.\n"); + } + + if (changed & WIPHY_PARAM_COVERAGE_CLASS) { + /* TODO: */ + DBGLOG(P2P, TRACE, "The coverage class is changed???\n"); + } + + i4Rslt = 0; + } while (false); + + return i4Rslt; +} + +int mtk_p2p_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + /* not implemented yet */ + + return -EINVAL; +} + +int mtk_p2p_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + /* not implemented yet */ + + return -EINVAL; +} + +int mtk_p2p_cfg80211_set_txpower(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, int mbm) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + /* not implemented yet */ + + return -EINVAL; +} + +int mtk_p2p_cfg80211_get_txpower(struct wiphy *wiphy, struct wireless_dev *wdev, unsigned int link_id, int *dbm) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + /* not implemented yet */ + + return -EINVAL; +} + +int mtk_p2p_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *ndev, bool enabled, + int timeout) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_POWER_MODE ePowerMode; + PARAM_POWER_MODE_T rPowerMode; + u32 u4Leng; + u8 ucRoleIdx; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (enabled) { + ePowerMode = Param_PowerModeFast_PSP; + } else { + ePowerMode = Param_PowerModeCAM; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_power_mgmt ps=%d.\n", enabled); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, ndev, &ucRoleIdx) != 0) { + return -EINVAL; + } + + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, + &rPowerMode.ucBssIdx) != WLAN_STATUS_SUCCESS) { + return -EINVAL; + } + + rPowerMode.ePowerMode = ePowerMode; + + /* p2p_set_power_save */ + kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile, &rPowerMode, + sizeof(rPowerMode), false, false, true, &u4Leng); + + return 0; +} + +/* &&&&&&&&&&&&&&&&&&&&&&&&&& Add for ICS Wi-Fi Direct Support. + * &&&&&&&&&&&&&&&&&&&&&&& */ +int mtk_p2p_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ap_settings *settings) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + s32 i4Rslt = -EINVAL; + P_MSG_P2P_BEACON_UPDATE_T prP2pBcnUpdateMsg = + (P_MSG_P2P_BEACON_UPDATE_T)NULL; + P_MSG_P2P_START_AP_T prP2pStartAPMsg = (P_MSG_P2P_START_AP_T)NULL; + u8 *pucBuffer = (u8 *)NULL; + u8 ucRoleIdx = 0; + struct cfg80211_chan_def *chandef; + RF_CHANNEL_INFO_T rRfChnlInfo; + + /* RF_CHANNEL_INFO_T rRfChnlInfo; */ + /* P_IE_SSID_T prSsidIE = (P_IE_SSID_T)NULL; */ + + do { + if ((wiphy == NULL) || (settings == NULL)) { + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_start_ap.\n"); + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + +#if (CFG_SUPPORT_DFS_MASTER == 1) + /*DFS todo 20161220_DFS*/ + netif_carrier_on(dev); + netif_tx_start_all_queues(dev); +#endif + + chandef = &settings->chandef; + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0) { + break; + } + + if (chandef) { + mtk_p2p_cfg80211func_channel_format_switch(chandef, chandef->chan, + &rRfChnlInfo); + + DBGLOG( + P2P, INFO, + "=============== role(%d) b=%d f=%d w=%d s1=%d s2=%d ============ \n", + ucRoleIdx, chandef->chan->band, chandef->chan->center_freq, + chandef->width, chandef->center_freq1, chandef->center_freq2); + + /* Follow the channel info from wifi.cfg prior to + * hostapd.conf */ + { + P_ADAPTER_T prAdapter = (P_ADAPTER_T)NULL; + P_WIFI_VAR_T prWifiVar = (P_WIFI_VAR_T)NULL; + + prAdapter = prGlueInfo->prAdapter; + prWifiVar = &prAdapter->rWifiVar; + + if ((prWifiVar->ucApChannel != 0) && + (prWifiVar->ucApChnlDefFromCfg != 0) && + (prWifiVar->ucApChannel != rRfChnlInfo.ucChannelNum)) { + rRfChnlInfo.ucChannelNum = prWifiVar->ucApChannel; + rRfChnlInfo.eBand = + (rRfChnlInfo.ucChannelNum <= 14) ? BAND_2G4 : BAND_5G; + /* [TODO][20160829]If we will set SCO by + * nl80211_channel_type afterward, to + * check if we need to modify SCO by + * wifi.cfg here + */ + } + } + + p2pFuncSetChannel(prGlueInfo->prAdapter, ucRoleIdx, &rRfChnlInfo); + } else { + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_start_ap. !!! no CH def!!!\n"); + } + + prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, + (sizeof(MSG_P2P_BEACON_UPDATE_T) + settings->beacon.head_len + + settings->beacon.tail_len + settings->beacon.assocresp_ies_len)); + + if (prP2pBcnUpdateMsg == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + prP2pBcnUpdateMsg->ucRoleIndex = ucRoleIdx; + prP2pBcnUpdateMsg->rMsgHdr.eMsgId = MID_MNY_P2P_BEACON_UPDATE; + pucBuffer = prP2pBcnUpdateMsg->aucBuffer; + DBGLOG(P2P, STATE, "mtk_p2p_cfg80211_start_ap.(role %d)\n", ucRoleIdx); + +#if (CFG_SUPPORT_DFS_MASTER == 1) + if (p2pFuncGetDfsState() == DFS_STATE_DETECTED) { + p2pFuncSetDfsState(DFS_STATE_INACTIVE); + } +#endif + if (settings->beacon.head_len != 0) { + kalMemCopy(pucBuffer, settings->beacon.head, + settings->beacon.head_len); + + prP2pBcnUpdateMsg->u4BcnHdrLen = settings->beacon.head_len; + + prP2pBcnUpdateMsg->pucBcnHdr = pucBuffer; + + pucBuffer += settings->beacon.head_len; + } else { + prP2pBcnUpdateMsg->u4BcnHdrLen = 0; + + prP2pBcnUpdateMsg->pucBcnHdr = NULL; + } + + if (settings->beacon.tail_len != 0) { + u8 ucLen = settings->beacon.tail_len; + + prP2pBcnUpdateMsg->pucBcnBody = pucBuffer; + kalMemCopy(pucBuffer, settings->beacon.tail, + settings->beacon.tail_len); + + prP2pBcnUpdateMsg->u4BcnBodyLen = ucLen; + + pucBuffer += settings->beacon.tail_len; + } else { + prP2pBcnUpdateMsg->u4BcnBodyLen = 0; + + prP2pBcnUpdateMsg->pucBcnBody = NULL; + } + + if ((settings->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP40) || + (settings->crypto.cipher_group == WLAN_CIPHER_SUITE_WEP104)) { + prP2pBcnUpdateMsg->fgIsWepCipher = true; + } else { + prP2pBcnUpdateMsg->fgIsWepCipher = false; + } + + if (settings->beacon.assocresp_ies_len != 0 && + settings->beacon.assocresp_ies != NULL) { + prP2pBcnUpdateMsg->pucAssocRespIE = pucBuffer; + kalMemCopy(pucBuffer, settings->beacon.assocresp_ies, + settings->beacon.assocresp_ies_len); + prP2pBcnUpdateMsg->u4AssocRespLen = + settings->beacon.assocresp_ies_len; + } else { + prP2pBcnUpdateMsg->u4AssocRespLen = 0; + prP2pBcnUpdateMsg->pucAssocRespIE = NULL; + } + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prP2pBcnUpdateMsg, MSG_SEND_METHOD_BUF); + + prP2pStartAPMsg = (P_MSG_P2P_START_AP_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_START_AP_T)); + + if (prP2pStartAPMsg == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + prP2pStartAPMsg->rMsgHdr.eMsgId = MID_MNY_P2P_START_AP; + + prP2pStartAPMsg->fgIsPrivacy = settings->privacy; + + prP2pStartAPMsg->u4BcnInterval = settings->beacon_interval; + + prP2pStartAPMsg->u4DtimPeriod = settings->dtim_period; + + /* Copy NO SSID. */ + prP2pStartAPMsg->ucHiddenSsidType = settings->hidden_ssid; + + prP2pStartAPMsg->ucRoleIdx = ucRoleIdx; + + kalP2PSetRole(prGlueInfo, 2, ucRoleIdx); + + COPY_SSID(prP2pStartAPMsg->aucSsid, prP2pStartAPMsg->u2SsidLen, + settings->ssid, settings->ssid_len); + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prP2pStartAPMsg, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (false); + + return i4Rslt; + + /* /////////////////////// */ + /** + * struct cfg80211_ap_settings - AP configuration + * + * Used to configure an AP interface. + * + * @beacon: beacon data + * @beacon_interval: beacon interval + * @dtim_period: DTIM period + * @ssid: SSID to be used in the BSS (note: may be %NULL if not provided + * from user space) + * @ssid_len: length of @ssid + * @hidden_ssid: whether to hide the SSID in Beacon/Probe Response + * frames + * @crypto: crypto settings + * @privacy: the BSS uses privacy + * @auth_type: Authentication type (algorithm) + * @inactivity_timeout: time in seconds to determine station's + * inactivity. + */ + /* struct cfg80211_ap_settings { */ + /* struct cfg80211_beacon_data beacon; */ + /* */ + /* int beacon_interval, dtim_period; */ + /* const u8 *ssid; */ + /* size_t ssid_len; */ + /* enum nl80211_hidden_ssid hidden_ssid; */ + /* struct cfg80211_crypto_settings crypto; */ + /* bool privacy; */ + /* enum nl80211_auth_type auth_type; */ + /* int inactivity_timeout; */ + /* }; */ + /* ////////////////// */ +} + +#if (CFG_SUPPORT_DFS_MASTER == 1) + +static int mtk_p2p_cfg80211_start_radar_detection_impl( + struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_chan_def *chandef, unsigned int cac_time_ms) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + s32 i4Rslt = -EINVAL; + P_MSG_P2P_DFS_CAC_T prP2pDfsCacMsg = (P_MSG_P2P_DFS_CAC_T)NULL; + u8 ucRoleIdx = 0; + RF_CHANNEL_INFO_T rRfChnlInfo; + + do { + if ((wiphy == NULL) || (chandef == NULL)) { + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_start_radar_detection.\n"); + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0) { + break; + } + + if (prGlueInfo->prP2PInfo[ucRoleIdx]->chandef == NULL) { + prGlueInfo->prP2PInfo[ucRoleIdx]->chandef = + (struct cfg80211_chan_def *)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_BUF, + sizeof(struct cfg80211_chan_def)); + + prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->chan = + (struct ieee80211_channel *)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_BUF, + sizeof(struct ieee80211_channel)); + } + + /* Copy chan def to local buffer*/ + prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->center_freq1 = + chandef->center_freq1; + prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->center_freq2 = + chandef->center_freq2; + prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->width = chandef->width; + memcpy(prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->chan, chandef->chan, + sizeof(struct ieee80211_channel)); + prGlueInfo->prP2PInfo[ucRoleIdx]->cac_time_ms = cac_time_ms; + + mtk_p2p_cfg80211func_channel_format_switch(chandef, chandef->chan, + &rRfChnlInfo); + + p2pFuncSetChannel(prGlueInfo->prAdapter, ucRoleIdx, &rRfChnlInfo); + + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_start_radar_detection.(role %d)\n", + ucRoleIdx); + + p2pFuncSetDfsState(DFS_STATE_INACTIVE); + + prP2pDfsCacMsg = (P_MSG_P2P_DFS_CAC_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(*prP2pDfsCacMsg)); + + if (prP2pDfsCacMsg == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + prP2pDfsCacMsg->rMsgHdr.eMsgId = MID_MNY_P2P_DFS_CAC; + + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + case NL80211_CHAN_WIDTH_40: + prP2pDfsCacMsg->eChannelWidth = CW_20_40MHZ; + break; + + case NL80211_CHAN_WIDTH_80: + prP2pDfsCacMsg->eChannelWidth = CW_80MHZ; + break; + + case NL80211_CHAN_WIDTH_80P80: + prP2pDfsCacMsg->eChannelWidth = CW_80P80MHZ; + break; + + default: + DBGLOG( + P2P, ERROR, + "mtk_p2p_cfg80211_start_radar_detection. !!!Bandwidth do not " + "support!!!\n"); + ASSERT(false); + break; + } + + prP2pDfsCacMsg->ucRoleIdx = ucRoleIdx; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prP2pDfsCacMsg, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (false); + + return i4Rslt; +} + +int mtk_p2p_cfg80211_start_radar_detection(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, + unsigned int cac_time_ms +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) + , + int link_id +#endif + ) +{ + return mtk_p2p_cfg80211_start_radar_detection_impl(wiphy, dev, chandef, + cac_time_ms); +} + +int mtk_p2p_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_csa_settings *params) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + s32 i4Rslt = -EINVAL; + P_MSG_P2P_BEACON_UPDATE_T prP2pBcnUpdateMsg = + (P_MSG_P2P_BEACON_UPDATE_T)NULL; + P_MSG_P2P_SET_NEW_CHANNEL_T prP2pSetNewChannelMsg = + (P_MSG_P2P_SET_NEW_CHANNEL_T)NULL; + u8 *pucBuffer = (u8 *)NULL; + u8 ucRoleIdx = 0; + RF_CHANNEL_INFO_T rRfChnlInfo; + P_BSS_INFO_T prBssInfo; + u8 ucBssIndex; + u32 u4Len; + + do { + if ((wiphy == NULL) || (params == NULL)) { + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_channel_switch.\n"); + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0) { + break; + } + + /*DFS todo 20161220_DFS*/ + netif_carrier_on(dev); + netif_tx_start_all_queues(dev); + + if (prGlueInfo->prP2PInfo[ucRoleIdx]->chandef == NULL) { + prGlueInfo->prP2PInfo[ucRoleIdx]->chandef = + (struct cfg80211_chan_def *)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_BUF, + sizeof(struct cfg80211_chan_def)); + + prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->chan = + (struct ieee80211_channel *)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_BUF, + sizeof(struct ieee80211_channel)); + } + /* Copy chan def to local buffer*/ + prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->center_freq1 = + params->chandef.center_freq1; + prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->center_freq2 = + params->chandef.center_freq2; + prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->width = + params->chandef.width; + memcpy(prGlueInfo->prP2PInfo[ucRoleIdx]->chandef->chan, + params->chandef.chan, sizeof(struct ieee80211_channel)); + + mtk_p2p_cfg80211func_channel_format_switch( + ¶ms->chandef, params->chandef.chan, &rRfChnlInfo); + + p2pFuncSetChannel(prGlueInfo->prAdapter, ucRoleIdx, &rRfChnlInfo); + + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_channel_switch.(role %d)\n", + ucRoleIdx); + + p2pFuncSetDfsState(DFS_STATE_INACTIVE); + + /* Set CSA IE parameters */ + prGlueInfo->prAdapter->rWifiVar.fgCsaInProgress = true; + prGlueInfo->prAdapter->rWifiVar.ucChannelSwitchMode = 1; + prGlueInfo->prAdapter->rWifiVar.ucNewChannelNumber = + nicFreq2ChannelNum(params->chandef.chan->center_freq * 1000); + prGlueInfo->prAdapter->rWifiVar.ucChannelSwitchCount = params->count; + + /* Set new channel parameters */ + prP2pSetNewChannelMsg = (P_MSG_P2P_SET_NEW_CHANNEL_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(*prP2pSetNewChannelMsg)); + + if (prP2pSetNewChannelMsg == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + prP2pSetNewChannelMsg->rMsgHdr.eMsgId = MID_MNY_P2P_SET_NEW_CHANNEL; + + switch (params->chandef.width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + case NL80211_CHAN_WIDTH_40: + prP2pSetNewChannelMsg->eChannelWidth = CW_20_40MHZ; + break; + + case NL80211_CHAN_WIDTH_80: + prP2pSetNewChannelMsg->eChannelWidth = CW_80MHZ; + break; + + case NL80211_CHAN_WIDTH_80P80: + prP2pSetNewChannelMsg->eChannelWidth = CW_80P80MHZ; + break; + + default: + DBGLOG( + P2P, ERROR, + "mtk_p2p_cfg80211_channel_switch. !!!Bandwidth do not support!!!\n"); + ASSERT(false); + break; + } + + prP2pSetNewChannelMsg->ucRoleIdx = ucRoleIdx; + + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, + &ucBssIndex) != WLAN_STATUS_SUCCESS) { + DBGLOG(P2P, ERROR, "Get bss index fail by role(%d)\n", ucRoleIdx); + break; + } else { + DBGLOG(P2P, INFO, + "mtk_p2p_cfg80211_channel_switch: Get BssIdx:%d\n", + ucBssIndex); + + prBssInfo = + GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, ucBssIndex); + +#if CFG_SUPPORT_DBDC_TC6 + if (prBssInfo && IS_BSS_P2P(prBssInfo) && + p2pFuncIsAPMode( + prGlueInfo->prAdapter->rWifiVar + .prP2PConnSettings[prBssInfo->u4PrivateData]) && + IS_NET_PWR_STATE_ACTIVE(prGlueInfo->prAdapter, + prBssInfo->ucBssIndex)) { + prP2pSetNewChannelMsg->ucBssIndex = ucBssIndex; + } else { + DBGLOG(P2P, ERROR, "Bss is not in AP mode or not active\n"); + break; + } +#else + if (prBssInfo && prBssInfo->fgIsDfsActive) { + /* Only support switching to DFS Active BSS + * which has been CAC done */ + DBGLOG( + P2P, INFO, + "mtk_p2p_cfg80211_channel_switch: DFS Active BssIdx:%d\n", + ucBssIndex); + prP2pSetNewChannelMsg->ucBssIndex = ucBssIndex; + } else { + DBGLOG(P2P, ERROR, "Bss is not DFS Active\n"); + break; + } +#endif + } + + DBGLOG(P2P, STATE, + "mtk_p2p_cfg80211_channel_switch: SetNewChnl BssIdx:%d\n", + ucBssIndex); + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prP2pSetNewChannelMsg, MSG_SEND_METHOD_BUF); + + /* Update beacon */ + if ((params->beacon_csa.head_len != 0) || + (params->beacon_csa.tail_len != 0)) { + u4Len = sizeof(MSG_P2P_BEACON_UPDATE_T) + + params->beacon_csa.head_len + params->beacon_csa.tail_len; + prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, u4Len); + + if (prP2pBcnUpdateMsg == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + kalMemZero(prP2pBcnUpdateMsg, u4Len); + + prP2pBcnUpdateMsg->ucRoleIndex = ucRoleIdx; + prP2pBcnUpdateMsg->rMsgHdr.eMsgId = MID_MNY_P2P_BEACON_UPDATE; + pucBuffer = prP2pBcnUpdateMsg->aucBuffer; + + if (params->beacon_csa.head_len != 0) { + kalMemCopy(pucBuffer, params->beacon_csa.head, + params->beacon_csa.head_len); + + prP2pBcnUpdateMsg->u4BcnHdrLen = params->beacon_csa.head_len; + + prP2pBcnUpdateMsg->pucBcnHdr = pucBuffer; + + pucBuffer = (u8 *)((unsigned long)pucBuffer + + (unsigned long)params->beacon_csa.head_len); + } else { + prP2pBcnUpdateMsg->u4BcnHdrLen = 0; + + prP2pBcnUpdateMsg->pucBcnHdr = NULL; + } + + if (params->beacon_csa.tail_len != 0) { + u8 ucLen = params->beacon_csa.tail_len; + + prP2pBcnUpdateMsg->pucBcnBody = pucBuffer; + kalMemCopy(pucBuffer, params->beacon_csa.tail, + params->beacon_csa.tail_len); + + prP2pBcnUpdateMsg->u4BcnBodyLen = ucLen; + } else { + prP2pBcnUpdateMsg->u4BcnBodyLen = 0; + prP2pBcnUpdateMsg->pucBcnBody = NULL; + } + + kalP2PSetRole(prGlueInfo, 2, ucRoleIdx); + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prP2pBcnUpdateMsg, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; /* Return Success */ + } + } while (false); + + return i4Rslt; +} + +#endif + +int mtk_p2p_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *dev, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0)) + struct cfg80211_beacon_data *info +#else + struct cfg80211_ap_update *info +#endif + ) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0)) + struct cfg80211_beacon_data *beacon = info; +#else + struct cfg80211_beacon_data *beacon = &info->beacon; +#endif + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + s32 i4Rslt = -EINVAL; + P_MSG_P2P_BEACON_UPDATE_T prP2pBcnUpdateMsg = + (P_MSG_P2P_BEACON_UPDATE_T)NULL; + u8 *pucBuffer = (u8 *)NULL; + u8 ucRoleIdx = 0; + u32 u4Len = 0; + + do { + if ((wiphy == NULL) || (beacon == NULL)) { + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_change_beacon.\n"); + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0) { + break; + } + + if ((beacon->head_len != 0) || (beacon->tail_len != 0)) { + u4Len = sizeof(MSG_P2P_BEACON_UPDATE_T) + beacon->head_len + + beacon->tail_len + beacon->assocresp_ies_len; + + prP2pBcnUpdateMsg = (P_MSG_P2P_BEACON_UPDATE_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, u4Len); + + if (prP2pBcnUpdateMsg == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + kalMemZero(prP2pBcnUpdateMsg, u4Len); + + prP2pBcnUpdateMsg->ucRoleIndex = ucRoleIdx; + prP2pBcnUpdateMsg->rMsgHdr.eMsgId = MID_MNY_P2P_BEACON_UPDATE; + pucBuffer = prP2pBcnUpdateMsg->aucBuffer; + + if (beacon->head_len != 0) { + kalMemCopy(pucBuffer, beacon->head, beacon->head_len); + + prP2pBcnUpdateMsg->u4BcnHdrLen = beacon->head_len; + + prP2pBcnUpdateMsg->pucBcnHdr = pucBuffer; + + pucBuffer += beacon->head_len; + } else { + prP2pBcnUpdateMsg->u4BcnHdrLen = 0; + + prP2pBcnUpdateMsg->pucBcnHdr = NULL; + } + + if (beacon->tail_len != 0) { + u8 ucLen = beacon->tail_len; + + prP2pBcnUpdateMsg->pucBcnBody = pucBuffer; + kalMemCopy(pucBuffer, beacon->tail, beacon->tail_len); + + prP2pBcnUpdateMsg->u4BcnBodyLen = ucLen; + + pucBuffer += beacon->tail_len; + } else { + prP2pBcnUpdateMsg->u4BcnBodyLen = 0; + prP2pBcnUpdateMsg->pucBcnBody = NULL; + } + + if (beacon->assocresp_ies_len != 0 && + beacon->assocresp_ies != NULL) { + prP2pBcnUpdateMsg->pucAssocRespIE = pucBuffer; + kalMemCopy(pucBuffer, beacon->assocresp_ies, + beacon->assocresp_ies_len); + prP2pBcnUpdateMsg->u4AssocRespLen = beacon->assocresp_ies_len; + } else { + prP2pBcnUpdateMsg->u4AssocRespLen = 0; + prP2pBcnUpdateMsg->pucAssocRespIE = NULL; + } + + kalP2PSetRole(prGlueInfo, 2, ucRoleIdx); + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prP2pBcnUpdateMsg, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; /* Return Success */ + } + + /* TODO: Probe Rsp, Assoc Rsp, Beacon IE update. */ + + /* ////////////////////////// */ + /** + * struct cfg80211_beacon_data - beacon data + * @head: head portion of beacon (before TIM IE) + * or %NULL if not changed + * @tail: tail portion of beacon (after TIM IE) + * or %NULL if not changed + * @head_len: length of @head + * @tail_len: length of @tail + * @beacon_ies: extra information element(s) to add into Beacon + * frames or %NULL + * @beacon_ies_len: length of beacon_ies in octets + * @proberesp_ies: extra information element(s) to add into + * Probe Response frames or %NULL + * @proberesp_ies_len: length of proberesp_ies in octets + * @assocresp_ies: extra information element(s) to add into + * (Re)Association Response frames or %NULL + * @assocresp_ies_len: length of assocresp_ies in octets + * @probe_resp_len: length of probe response template + * (@probe_resp) + * @probe_resp: probe response template (AP mode only) + */ + /* struct cfg80211_beacon_data { */ + /* const u8 *head, *tail; */ + /* const u8 *beacon_ies; */ + /* const u8 *proberesp_ies; */ + /* const u8 *assocresp_ies; */ + /* const u8 *probe_resp; */ + + /* size_t head_len, tail_len; */ + /* size_t beacon_ies_len; */ + /* size_t proberesp_ies_len; */ + /* size_t assocresp_ies_len; */ + /* size_t probe_resp_len; */ + /* }; */ + + /* ////////////////////////// */ + } while (false); + + return i4Rslt; +} + +int mtk_p2p_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + ,unsigned int link_id +#endif + ) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + s32 i4Rslt = -EINVAL; + P_MSG_P2P_SWITCH_OP_MODE_T prP2pSwitchMode = + (P_MSG_P2P_SWITCH_OP_MODE_T)NULL; + u8 ucRoleIdx = 0; + + do { + if (wiphy == NULL) { + break; + } + + DBGLOG(P2P, STATE, "mtk_p2p_cfg80211_stop_ap.\n"); + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + +#if (CFG_SUPPORT_DFS_MASTER == 1) + if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP) { + netif_carrier_off(dev); + netif_tx_stop_all_queues(dev); + } +#endif + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0) { + break; + } + /* Switch OP MOde. */ + prP2pSwitchMode = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_SWITCH_OP_MODE_T)); + + if (prP2pSwitchMode == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + prP2pSwitchMode->rMsgHdr.eMsgId = MID_MNY_P2P_STOP_AP; + prP2pSwitchMode->ucRoleIdx = ucRoleIdx; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prP2pSwitchMode, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (false); + + return i4Rslt; +} + +/* TODO: */ +int mtk_p2p_cfg80211_deauth(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_deauth_request *req) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + /* not implemented yet */ + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_deauth.\n"); + + return -EINVAL; +} + +/* TODO: */ +int mtk_p2p_cfg80211_disassoc(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_disassoc_request *req) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_disassoc.\n"); + + /* not implemented yet */ + + return -EINVAL; +} + +int mtk_p2p_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie) +{ + s32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + P_GL_P2P_DEV_INFO_T prGlueP2pDevInfo = (P_GL_P2P_DEV_INFO_T)NULL; + P_MSG_P2P_CHNL_REQUEST_T prMsgChnlReq = (P_MSG_P2P_CHNL_REQUEST_T)NULL; + + DBGLOG(P2P, STATE, "mtk_p2p_cfg80211_remain_on_channel\n"); + + do { + if ((wiphy == NULL) || + /* (dev == NULL) || */ + (chan == NULL) || (cookie == NULL)) { + break; + } + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + prGlueP2pDevInfo = prGlueInfo->prP2PDevInfo; + + *cookie = prGlueP2pDevInfo->u8Cookie++; + + prMsgChnlReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_CHNL_REQUEST_T)); + + if (prMsgChnlReq == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_remain_on_channel:%d\n", + (s32) * cookie); + + prMsgChnlReq->rMsgHdr.eMsgId = MID_MNY_P2P_CHNL_REQ; + prMsgChnlReq->u8Cookie = *cookie; + prMsgChnlReq->u4Duration = duration; + prMsgChnlReq->eChnlReqType = CH_REQ_TYPE_P2P_LISTEN; + + mtk_p2p_cfg80211func_channel_format_switch(NULL, chan, + &prMsgChnlReq->rChannelInfo); + mtk_p2p_cfg80211func_channel_sco_switch(NL80211_CHAN_NO_HT, + &prMsgChnlReq->eChnlSco); + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsgChnlReq, + MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (false); + + return i4Rslt; +} + +/* mtk_p2p_cfg80211_remain_on_channel */ + +int mtk_p2p_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + s32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + P_MSG_P2P_CHNL_ABORT_T prMsgChnlAbort = (P_MSG_P2P_CHNL_ABORT_T)NULL; + + do { + if ((wiphy == NULL) /* || (dev == NULL) */) { + break; + } + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + prGlueP2pInfo = prGlueInfo->prP2PInfo[0]; + + prMsgChnlAbort = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_CHNL_ABORT_T)); + + if (prMsgChnlAbort == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_cancel_remain_on_channel%d\n", + (s32)cookie); + + prMsgChnlAbort->rMsgHdr.eMsgId = MID_MNY_P2P_CHNL_ABORT; + prMsgChnlAbort->u8Cookie = cookie; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prMsgChnlAbort, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (false); + + return i4Rslt; +} + +int mtk_p2p_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie) +{ + struct net_device *dev = NULL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + s32 i4Rslt = -EINVAL; + P_MSG_P2P_MGMT_TX_REQUEST_T prMsgTxReq = (P_MSG_P2P_MGMT_TX_REQUEST_T)NULL; + P_MSDU_INFO_T prMgmtFrame = (P_MSDU_INFO_T)NULL; + u8 *pucFrameBuf = (u8 *)NULL; + u64 *pu8GlCookie = (u64 *)NULL; + u8 ucRoleIdx = 0, ucBssIdx = 0; + + do { + if ((wiphy == NULL) || (wdev == NULL) || (params == 0) || + (cookie == NULL)) { + break; + } + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + /* The owner of this function please check following line*/ + prGlueP2pInfo = (P_GL_P2P_INFO_T)prGlueInfo->prP2PInfo; + + dev = wdev->netdev; + + /* The owner of this function please check following line*/ + if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0) { + /* Device Interface. */ + ucBssIdx = P2P_DEV_BSS_INDEX; + } else { + ASSERT(ucRoleIdx < KAL_P2P_NUM); + /* Role Interface. */ + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, + &ucBssIdx) != WLAN_STATUS_SUCCESS) { + /* Can't find BSS index. */ + break; + } + } + /* The owner of this function please check following line*/ + *cookie = prGlueInfo->u8Cookie++; + + /* Channel & Channel Type & Wait time are ignored. */ + prMsgTxReq = cnmMemAlloc(prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_MGMT_TX_REQUEST_T)); + + if (prMsgTxReq == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + if (params->offchan) { + DBGLOG(P2P, TRACE, " Off channel true\n"); + prMsgTxReq->fgIsOffChannel = true; + + mtk_p2p_cfg80211func_channel_format_switch( + NULL, params->chan, &prMsgTxReq->rChannelInfo); + mtk_p2p_cfg80211func_channel_sco_switch(NL80211_CHAN_NO_HT, + &prMsgTxReq->eChnlExt); + } else { + prMsgTxReq->fgIsOffChannel = false; + } + + if (params->no_cck) { + prMsgTxReq->fgNoneCckRate = true; + } else { + prMsgTxReq->fgNoneCckRate = false; + } + + if (params->dont_wait_for_ack) { + prMsgTxReq->fgIsWaitRsp = false; + } else { + prMsgTxReq->fgIsWaitRsp = true; + } + prMgmtFrame = cnmMgtPktAlloc( + prGlueInfo->prAdapter, + (s32)(params->len + sizeof(u64) + MAC_TX_RESERVED_FIELD)); + prMsgTxReq->prMgmtMsduInfo = prMgmtFrame; + if (prMsgTxReq->prMgmtMsduInfo == NULL) { + /* ASSERT(false); */ + i4Rslt = -ENOMEM; + break; + } + + prMsgTxReq->u8Cookie = *cookie; + prMsgTxReq->rMsgHdr.eMsgId = MID_MNY_P2P_MGMT_TX; + prMsgTxReq->ucBssIdx = ucBssIdx; + + pucFrameBuf = (u8 *)((unsigned long)prMgmtFrame->prPacket + + MAC_TX_RESERVED_FIELD); + + pu8GlCookie = + (u64 *)((unsigned long)prMgmtFrame->prPacket + + (unsigned long)params->len + MAC_TX_RESERVED_FIELD); + + kalMemCopy(pucFrameBuf, params->buf, params->len); + + *pu8GlCookie = *cookie; + + prMgmtFrame->u2FrameLength = params->len; + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prMsgTxReq, + MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (false); + + if ((i4Rslt != 0) && (prMsgTxReq != NULL)) { + if (prMsgTxReq->prMgmtMsduInfo != NULL) { + cnmMgtPktFree(prGlueInfo->prAdapter, prMsgTxReq->prMgmtMsduInfo); + } + + cnmMemFree(prGlueInfo->prAdapter, prMsgTxReq); + } + + return i4Rslt; +} + +int mtk_p2p_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, u64 cookie) +{ + s32 i4Rslt = -EINVAL; + + return i4Rslt; +} + +int mtk_p2p_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev, + struct bss_parameters *params) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + s32 i4Rslt = -EINVAL; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + switch (params->use_cts_prot) { + case -1: + DBGLOG(P2P, TRACE, "CTS protection no change\n"); + break; + + case 0: + DBGLOG(P2P, TRACE, "CTS protection disable.\n"); + break; + + case 1: + DBGLOG(P2P, TRACE, "CTS protection enable\n"); + break; + + default: + DBGLOG(P2P, TRACE, "CTS protection unknown\n"); + break; + } + + switch (params->use_short_preamble) { + case -1: + DBGLOG(P2P, TRACE, "Short prreamble no change\n"); + break; + + case 0: + DBGLOG(P2P, TRACE, "Short prreamble disable.\n"); + break; + + case 1: + DBGLOG(P2P, TRACE, "Short prreamble enable\n"); + break; + + default: + DBGLOG(P2P, TRACE, "Short prreamble unknown\n"); + break; + } + + i4Rslt = 0; + + return i4Rslt; +} + +static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, + struct station_del_parameters *params) +{ + const u8 *mac = params->mac ? params->mac : bcast_addr; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + s32 i4Rslt = -EINVAL; + P_MSG_P2P_CONNECTION_ABORT_T prDisconnectMsg = + (P_MSG_P2P_CONNECTION_ABORT_T)NULL; + u8 aucBcMac[] = BC_MAC_ADDR; + u8 ucRoleIdx = 0; + u8 ucBssIdx = 0; + u32 waitRet = 0; + P_BSS_INFO_T prBssInfo = NULL; + P_STA_RECORD_T prCurrStaRec = NULL; + + do { + if ((wiphy == NULL) || (dev == NULL)) { + break; + } + + if (mac == NULL) { + mac = aucBcMac; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_del_station.\n"); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0) { + break; + } + /* prDisconnectMsg = + * (P_MSG_P2P_CONNECTION_ABORT_T)kalMemAlloc(sizeof(MSG_P2P_CONNECTION_ABORT_T), + * VIR_MEM_TYPE); + */ + + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &ucBssIdx) != + WLAN_STATUS_SUCCESS) { + break; + } + + prDisconnectMsg = (P_MSG_P2P_CONNECTION_ABORT_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_CONNECTION_ABORT_T)); + + if (prDisconnectMsg == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + prDisconnectMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; + prDisconnectMsg->ucRoleIdx = ucRoleIdx; + COPY_MAC_ADDR(prDisconnectMsg->aucTargetID, mac); + prDisconnectMsg->u2ReasonCode = REASON_CODE_UNSPECIFIED; + prDisconnectMsg->fgSendDeauth = true; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, ucBssIdx); + prCurrStaRec = bssGetClientByMac(prGlueInfo->prAdapter, prBssInfo, + prDisconnectMsg->aucTargetID); + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prDisconnectMsg, MSG_SEND_METHOD_BUF); + +#if CFG_SUPPORT_802_11W + /* if encrypted deauth frame + * is in process, pending remove key + */ + if (prBssInfo && prCurrStaRec && IS_BSS_APGO(prBssInfo) && + (prBssInfo->u4RsnSelectedAKMSuite == RSN_AKM_SUITE_SAE)) { + reinit_completion(&prBssInfo->rDeauthComp); + DBGLOG(P2P, INFO, "Start deauth wait\n"); + waitRet = wait_for_completion_timeout(&prBssInfo->rDeauthComp, + MSEC_TO_JIFFIES(1000)); + if (!waitRet) { + DBGLOG(RSN, INFO, "timeout\n"); + prBssInfo->encryptedDeauthIsInProcess = false; + } else { + DBGLOG(RSN, INFO, "complete\n"); + } + } +#endif + i4Rslt = 0; + } while (false); + + return i4Rslt; +} + +int mtk_p2p_cfg80211_auth(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_auth_request *req) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = NULL; + struct cfg80211_connect_params connect; + struct cfg80211_connect_params *sme = &connect; + const struct cfg80211_bss_ies *ies; + const u8 *ssidie = NULL; + u8 ssid_len = 0; + u8 ucRoleIdx = 0; + + DBGLOG(REQ, INFO, + "auth to BSS [" MACSTR "]\n", + MAC2STR((u8 *)req->bss->bssid)); + DBGLOG(REQ, INFO, "auth_type:%d\n", req->auth_type); + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + memset(&connect, 0, sizeof(connect)); + sme->bssid = req->bss->bssid; + if (mtk_Netdev_To_RoleIdx(prGlueInfo, ndev, + &ucRoleIdx) < 0) { + return -EINVAL; + } + + DBGLOG(REQ, INFO, "ucRoleIndex = %d\n", ucRoleIdx); + + prP2pConnSettings = prGlueInfo->prAdapter-> + rWifiVar.prP2PConnSettings[ucRoleIdx]; + + ies = rcu_access_pointer(req->bss->ies); + if (!ies) { + return false; + } + + ssidie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); + if (!ssidie) { + return false; + } + + ssid_len = ssidie[1]; + sme->ssid = ssidie + 2; + sme->ssid_len = ssid_len; + // yhpgi + // COPY_SSID(prP2pConnSettings->aucSSID, prP2pConnSettings->ucSSIDLen, + // sme->ssid, sme->ssid_len); + // prP2pConnSettings->fgIsSendAssoc = false; + + DBGLOG(REQ, INFO, "ssid_len %d ssid %s\n", sme->ssid_len, sme->ssid); + + return mtk_p2p_cfg80211_connect(wiphy, ndev, sme); +} + +int mtk_p2p_cfg80211_assoc(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_assoc_request *req) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u8 ucRoleIdx = 0; + P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = NULL; + P_STA_RECORD_T prStaRec = NULL; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = + (P_P2P_ROLE_FSM_INFO_T)NULL; + P_P2P_CONNECTION_REQ_INFO_T prConnReqInfo = + (P_P2P_CONNECTION_REQ_INFO_T)NULL; + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + ASSERT(prGlueInfo); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, ndev, + &ucRoleIdx) < 0) { + return -EINVAL; + } + + prP2pConnSettings = prGlueInfo->prAdapter-> + rWifiVar.prP2PConnSettings[ucRoleIdx]; + + /* [todo]temp use for indicate rx assoc resp, may need to be modified */ + /* The BSS from cfg80211_ops.assoc must give back to + * cfg80211_send_rx_assoc() or to cfg80211_assoc_timeout(). + * To ensure proper refcounting, + * new association requests while already associating + * must be rejected. + * yhpgi + */ + // if (prP2pConnSettings->bss) + // return -ENOENT; + // prP2pConnSettings->bss = req->bss; + + DBGLOG(REQ, INFO, "ucRoleIndex = %d\n", ucRoleIdx); + + /*[TODO]may to check if assoc parameters change as cfg80211_auth*/ + // prP2pConnSettings->fgIsSendAssoc = true; + /* skip join initial flow when it has been completed*/ + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO( + prGlueInfo->prAdapter, + ucRoleIdx); + prStaRec = prP2pRoleFsmInfo->rJoinInfo.prTargetStaRec; + prConnReqInfo = &(prP2pRoleFsmInfo->rConnReqInfo); + kalMemCopy(prConnReqInfo->aucIEBuf, + req->ie, req->ie_len); + prConnReqInfo->u4BufLength = req->ie_len; + + /* set crypto */ + kalP2PSetCipher(prGlueInfo, IW_AUTH_CIPHER_NONE, + ucRoleIdx); + DBGLOG(REQ, INFO, + "n_ciphers_pairwise %d, ciphers_pairwise[0] %#x\n", + req->crypto.n_ciphers_pairwise, + req->crypto.ciphers_pairwise[0]); + + if (req->crypto.n_ciphers_pairwise) { + switch (req->crypto.ciphers_pairwise[0]) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + kalP2PSetCipher(prGlueInfo, + IW_AUTH_CIPHER_WEP40, + ucRoleIdx); + break; + case WLAN_CIPHER_SUITE_TKIP: + kalP2PSetCipher(prGlueInfo, + IW_AUTH_CIPHER_TKIP, + ucRoleIdx); + break; + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_AES_CMAC: + kalP2PSetCipher(prGlueInfo, + IW_AUTH_CIPHER_CCMP, + ucRoleIdx); + break; + default: + DBGLOG(REQ, WARN, + "invalid cipher pairwise (%d)\n", + req->crypto.ciphers_pairwise[0]); + /* do cfg80211_put_bss before return */ + goto error_cleanup_bss; + } + } + + if (req->crypto.cipher_group) { + u32 u4Group = IW_AUTH_CIPHER_NONE; + + DBGLOG(RSN, INFO, "[P2P] cipher group (%x) for role %d\n", + req->crypto.cipher_group, ucRoleIdx); + + // Store group suite directly into the structural P2P array + prGlueInfo->prAdapter->rWifiVar.rConnSettings.rRsnInfo + .u4GroupKeyCipherSuite = req->crypto.cipher_group; + + switch (req->crypto.cipher_group) { + case WLAN_CIPHER_SUITE_WEP40: u4Group = IW_AUTH_CIPHER_WEP40; break; + case WLAN_CIPHER_SUITE_WEP104: u4Group = IW_AUTH_CIPHER_WEP104; break; + case WLAN_CIPHER_SUITE_TKIP: u4Group = IW_AUTH_CIPHER_TKIP; break; + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_AES_CMAC: u4Group = IW_AUTH_CIPHER_CCMP; break; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + case WLAN_CIPHER_SUITE_GCMP_256: u4Group = IW_AUTH_CIPHER_GCMP256; break; + case WLAN_CIPHER_SUITE_NO_GROUP_ADDR: break; + default: + DBGLOG(REQ, WARN, "invalid P2P cipher group (%d)\n", req->crypto.cipher_group); + goto error_cleanup_bss; + } + + /* Update the hardware engine variable directly. + * Depending on your MediaTek branch layout, this requires assigning + * to rWpaInfo or triggering an internal update command. */ + prGlueInfo->rWpaInfo.u4CipherGroup = u4Group; + } + + /* end */ + + if (prStaRec) { + saaSendAuthAssoc(prGlueInfo->prAdapter, prStaRec); + }else{ + DBGLOG(REQ, WARN, + "can't send auth since can't find StaRec\n"); + } + + return 0; + +error_cleanup_bss: + if (prGlueInfo->prAdapter->rWifiVar.rConnSettings.bss) { + cfg80211_put_bss(wiphy, prGlueInfo->prAdapter->rWifiVar.rConnSettings.bss); + prGlueInfo->prAdapter->rWifiVar.rConnSettings.bss = NULL; + } + cfg80211_connect_result(ndev, req->bss->bssid, NULL, 0, NULL, 0, + WLAN_STATUS_CIPHER_SUITE_REJECTED, GFP_KERNEL); + return -EINVAL; // Return the error code to the kernel +} + +int mtk_p2p_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + s32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_MSG_P2P_CONNECTION_REQUEST_T prConnReqMsg = + (P_MSG_P2P_CONNECTION_REQUEST_T)NULL; + u8 ucRoleIdx = 0; +#if CFG_SUPPORT_REPLAY_DETECTION + u8 ucBssIndex = 0; + P_BSS_INFO_T prBssInfo = NULL; + struct SEC_DETECT_REPLAY_INFO *prDetRplyInfo = NULL; +#endif + + do { + if ((wiphy == NULL) || (dev == NULL) || (sme == NULL)) { + break; + } + + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_connect.\n"); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0) { + break; + } + + prConnReqMsg = (P_MSG_P2P_CONNECTION_REQUEST_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, + (sizeof(MSG_P2P_CONNECTION_REQUEST_T) + sme->ie_len)); + + if (prConnReqMsg == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + prConnReqMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_REQ; + prConnReqMsg->ucRoleIdx = ucRoleIdx; + + COPY_SSID(prConnReqMsg->rSsid.aucSsid, prConnReqMsg->rSsid.ucSsidLen, + sme->ssid, sme->ssid_len); + + COPY_MAC_ADDR(prConnReqMsg->aucBssid, sme->bssid); + COPY_MAC_ADDR(prConnReqMsg->aucSrcMacAddr, dev->dev_addr); + + DBGLOG(P2P, TRACE, "Assoc Req IE Buffer Length:%d\n", sme->ie_len); + kalMemCopy(prConnReqMsg->aucIEBuf, sme->ie, sme->ie_len); + prConnReqMsg->u4IELen = sme->ie_len; + + kalP2PSetCipher(prGlueInfo, IW_AUTH_CIPHER_NONE, ucRoleIdx); + + if (sme->crypto.n_ciphers_pairwise) { + switch (sme->crypto.ciphers_pairwise[0]) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + kalP2PSetCipher(prGlueInfo, IW_AUTH_CIPHER_WEP40, ucRoleIdx); + break; + + case WLAN_CIPHER_SUITE_TKIP: + kalP2PSetCipher(prGlueInfo, IW_AUTH_CIPHER_TKIP, ucRoleIdx); + break; + + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_AES_CMAC: + kalP2PSetCipher(prGlueInfo, IW_AUTH_CIPHER_CCMP, ucRoleIdx); + break; + + default: + DBGLOG(REQ, WARN, "invalid cipher pairwise (%d)\n", + sme->crypto.ciphers_pairwise[0]); + return -EINVAL; + } + } + + mtk_p2p_cfg80211func_channel_format_switch(NULL, sme->channel, + &prConnReqMsg->rChannelInfo); + mtk_p2p_cfg80211func_channel_sco_switch(NL80211_CHAN_NO_HT, + &prConnReqMsg->eChnlSco); + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prConnReqMsg, + MSG_SEND_METHOD_BUF); + +#if CFG_SUPPORT_REPLAY_DETECTION + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, + &ucBssIndex) != WLAN_STATUS_SUCCESS) { + return -EINVAL; + } + + prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, ucBssIndex); + ASSERT(prBssInfo); + prDetRplyInfo = &prBssInfo->rDetRplyInfo; + kalMemZero(prDetRplyInfo, sizeof(struct SEC_DETECT_REPLAY_INFO)); +#endif + + i4Rslt = 0; + } while (false); + + return i4Rslt; +} + +#if 0 +int mtk_p2p_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + s32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_MSG_P2P_CONNECTION_ABORT_T prDisconnMsg = + (P_MSG_P2P_CONNECTION_ABORT_T)NULL; + u8 aucBCAddr[] = BC_MAC_ADDR; + u8 ucRoleIdx = 0; + + do { + if ((wiphy == NULL) || (dev == NULL)) { + break; + } + + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_disconnect.\n"); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0) { + break; + } + /* prDisconnMsg = + * (P_MSG_P2P_CONNECTION_ABORT_T)kalMemAlloc(sizeof(P_MSG_P2P_CONNECTION_ABORT_T), + * VIR_MEM_TYPE); + */ + prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_CONNECTION_ABORT_T)); + + if (prDisconnMsg == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + prDisconnMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; + prDisconnMsg->ucRoleIdx = ucRoleIdx; + prDisconnMsg->u2ReasonCode = reason_code; + prDisconnMsg->fgSendDeauth = true; + COPY_MAC_ADDR(prDisconnMsg->aucTargetID, aucBCAddr); + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prDisconnMsg, + MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (false); + + return i4Rslt; +} +#endif + +int mtk_p2p_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u16 reason_code) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_MSG_P2P_CONNECTION_ABORT_T prDisconnMsg = NULL; + P_CONNECTION_SETTINGS_T prP2pConnSettings = NULL; + u8 aucBCAddr[] = BC_MAC_ADDR; + u8 ucRoleIdx = 0; + + if (!wiphy || !dev) { + return -EINVAL; + } + + prGlueInfo = (P_GLUE_INFO_T)wiphy_priv(wiphy); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0) { + return -EINVAL; + } + + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_disconnect (Explicit Mailbox): Role %d\n", ucRoleIdx); + prP2pConnSettings = &prGlueInfo->prAdapter->rWifiVar.rConnSettings; + + prDisconnMsg = (P_MSG_P2P_CONNECTION_ABORT_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(MSG_P2P_CONNECTION_ABORT_T)); + + if (prDisconnMsg == NULL) { + ASSERT(false); + return -ENOMEM; + } + + prDisconnMsg->rMsgHdr.eMsgId = MID_MNY_P2P_CONNECTION_ABORT; + prDisconnMsg->ucRoleIdx = ucRoleIdx; + prDisconnMsg->u2ReasonCode = reason_code; + prDisconnMsg->fgSendDeauth = true; + COPY_MAC_ADDR(prDisconnMsg->aucTargetID, aucBCAddr); + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, (P_MSG_HDR_T)prDisconnMsg, MSG_SEND_METHOD_BUF); + + if (prP2pConnSettings && prP2pConnSettings->bss) { + cfg80211_put_bss(wiphy, prP2pConnSettings->bss); + prP2pConnSettings->bss = NULL; + } + prP2pConnSettings->fgIsSendAssoc = false; + + cfg80211_disconnected(dev, reason_code, NULL, 0, true, GFP_KERNEL); + + return 0; +} + +#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE +int mtk_p2p_cfg80211_change_iface(IN struct wiphy *wiphy, + IN struct net_device *ndev, + IN enum nl80211_iftype type, + IN struct vif_params *params) +#else +int mtk_p2p_cfg80211_change_iface(IN struct wiphy *wiphy, + IN struct net_device *ndev, + IN enum nl80211_iftype type, IN u32 *flags, + IN struct vif_params *params) +#endif +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + s32 i4Rslt = -EINVAL; + P_MSG_P2P_SWITCH_OP_MODE_T prSwitchModeMsg = + (P_MSG_P2P_SWITCH_OP_MODE_T)NULL; + u8 ucRoleIdx = 0; + + do { + if ((wiphy == NULL) || (ndev == NULL)) { + DBGLOG(P2P, ERROR, "wiphy=%x, ndev=%x.\n", wiphy, ndev); + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_change_iface.\n"); + + if (ndev->ieee80211_ptr) { + ndev->ieee80211_ptr->iftype = type; + } + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (prGlueInfo == NULL) { + DBGLOG(INIT, WARN, "prGlueInfo is NULL\n"); + return -EFAULT; + } + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, ndev, &ucRoleIdx) != 0) { + DBGLOG(P2P, TRACE, + "Device Interface no need to change interface type.\n"); + return 0; + } + /* Switch OP MOde. */ + prSwitchModeMsg = (P_MSG_P2P_SWITCH_OP_MODE_T)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, + sizeof(MSG_P2P_SWITCH_OP_MODE_T)); + + if (prSwitchModeMsg == NULL) { + ASSERT(false); + i4Rslt = -ENOMEM; + break; + } + + prSwitchModeMsg->rMsgHdr.eMsgId = MID_MNY_P2P_FUN_SWITCH; + prSwitchModeMsg->ucRoleIdx = ucRoleIdx; + + switch (type) { + case NL80211_IFTYPE_P2P_CLIENT: + DBGLOG(P2P, TRACE, "NL80211_IFTYPE_P2P_CLIENT.\n"); + prSwitchModeMsg->eOpMode = OP_MODE_INFRASTRUCTURE; + kalP2PSetRole(prGlueInfo, 1, ucRoleIdx); + break; + + case NL80211_IFTYPE_STATION: + DBGLOG(P2P, TRACE, "NL80211_IFTYPE_STATION.\n"); + prSwitchModeMsg->eOpMode = OP_MODE_INFRASTRUCTURE; + kalP2PSetRole(prGlueInfo, 1, ucRoleIdx); + break; + + case NL80211_IFTYPE_AP: + DBGLOG(P2P, TRACE, "NL80211_IFTYPE_AP.\n"); + prSwitchModeMsg->eOpMode = OP_MODE_ACCESS_POINT; + kalP2PSetRole(prGlueInfo, 2, ucRoleIdx); + break; + + case NL80211_IFTYPE_P2P_GO: + DBGLOG(P2P, TRACE, "NL80211_IFTYPE_P2P_GO not AP.\n"); + prSwitchModeMsg->eOpMode = OP_MODE_ACCESS_POINT; + kalP2PSetRole(prGlueInfo, 2, ucRoleIdx); + break; + + default: + DBGLOG(P2P, TRACE, "Other type :%d .\n", type); + prSwitchModeMsg->eOpMode = OP_MODE_P2P_DEVICE; + kalP2PSetRole(prGlueInfo, 0, ucRoleIdx); + break; + } + + mboxSendMsg(prGlueInfo->prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prSwitchModeMsg, MSG_SEND_METHOD_BUF); + + i4Rslt = 0; + } while (false); + + return i4Rslt; +} + +int mtk_p2p_cfg80211_set_channel(IN struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + s32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + struct net_device *dev = (struct net_device *)NULL; + RF_CHANNEL_INFO_T rRfChnlInfo; + u8 ucRoleIdx = 0; + + if ((wiphy == NULL) || (chandef == NULL)) { + return i4Rslt; + } + + dev = (struct net_device *)wiphy_dev(wiphy); + + do { + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_set_channel.\n"); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + mtk_p2p_cfg80211func_channel_format_switch(chandef, chandef->chan, + &rRfChnlInfo); + + if (mtk_Netdev_To_RoleIdx(prGlueInfo, dev, &ucRoleIdx) < 0) { + break; + } + + p2pFuncSetChannel(prGlueInfo->prAdapter, ucRoleIdx, &rRfChnlInfo); + + i4Rslt = 0; + } while (false); + + return i4Rslt; +} + +/* mtk_p2p_cfg80211_set_channel */ + +int mtk_p2p_cfg80211_set_bitrate_mask( + IN struct wiphy *wiphy, IN struct net_device *dev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + unsigned int link_id, +#endif + IN const u8 *peer, IN const struct cfg80211_bitrate_mask *mask) +{ + s32 i4Rslt = -EINVAL; + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + + do { + if ((wiphy == NULL) || (dev == NULL) || (mask == NULL)) { + break; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_set_bitrate_mask\n"); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + /* TODO: Set bitrate mask of the peer? */ + + i4Rslt = 0; + } while (false); + + return i4Rslt; +} + +void mtk_p2p_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy, + struct wireless_dev *wdev, + IN u16 frame_type, IN bool reg) +{ + P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)NULL; + u8 ucRoleIdx = 0; + u32 *pu4P2pPacketFilter = NULL; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + + if (g_u4HaltFlag) { + DBGLOG(RLM, WARN, "wlan is halt, skip reg callback\n"); + return; + } + + do { + if ((wiphy == NULL) || (wdev == NULL)) { + break; + } + + DBGLOG(P2P, TRACE, "[%s] mtk_p2p_cfg80211_mgmt_frame_register\n", + wdev->netdev->name); + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + /* since p2p device share the aprRoleHandler so needs to check + * DevHandler 1st */ + if (prGlueInfo->prP2PInfo[0]->prDevHandler == wdev->netdev) { + /* P2P device*/ + pu4P2pPacketFilter = &prGlueInfo->prP2PDevInfo->u4OsMgmtFrameFilter; + } else { + if (mtk_Netdev_To_RoleIdx(prGlueInfo, wdev->netdev, &ucRoleIdx) < + 0) { + /* P2P device*/ + DBGLOG( + P2P, WARN, + "mtk_p2p_cfg80211_mgmt_frame_register wireless dev match fail!\n"); + break; + } else { + /* Non P2P device*/ + ASSERT(ucRoleIdx < KAL_P2P_NUM); + DBGLOG(P2P, TRACE, "Open packet filer RoleIdx %u\n", ucRoleIdx); + prP2pRoleFsmInfo = + prGlueInfo->prAdapter->rWifiVar.aprP2pRoleFsmInfo[ucRoleIdx]; + pu4P2pPacketFilter = &prP2pRoleFsmInfo->u4P2pPacketFilter; + } + } + switch (frame_type) { + case MAC_FRAME_PROBE_REQ: + if (reg) { + *pu4P2pPacketFilter |= PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(P2P, TRACE, "Open packet filer probe request\n"); + } else { + *pu4P2pPacketFilter &= ~PARAM_PACKET_FILTER_PROBE_REQ; + DBGLOG(P2P, TRACE, "Close packet filer probe request\n"); + } + break; + + case MAC_FRAME_ACTION: + if (reg) { + *pu4P2pPacketFilter |= PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(P2P, TRACE, "Open packet filer action frame.\n"); + } else { + *pu4P2pPacketFilter &= ~PARAM_PACKET_FILTER_ACTION_FRAME; + DBGLOG(P2P, TRACE, "Close packet filer action frame.\n"); + } + break; + + default: + DBGLOG(P2P, ERROR, "unsupported frame type:%x\n", frame_type); + break; + } + + set_bit(GLUE_FLAG_FRAME_FILTER_BIT, &prGlueInfo->ulFlag); + + /* wake up main thread */ + wake_up_interruptible(&prGlueInfo->waitq); + + if (in_interrupt()) { + DBGLOG(P2P, TRACE, "It is in interrupt level\n"); + } + } while (false); +} + +#ifdef CONFIG_NL80211_TESTMODE + +int mtk_p2p_cfg80211_testmode_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, void *data, + int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_TEST_PARAMS prParams = (P_NL80211_DRIVER_TEST_PARAMS)NULL; + s32 i4Status = -EINVAL; + + ASSERT(wiphy); + ASSERT(wdev); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + DBGLOG(P2P, INFO, "mtk_p2p_cfg80211_testmode_cmd\n"); + + if (len < sizeof(NL80211_DRIVER_TEST_PARAMS)) { + DBGLOG(P2P, WARN, "len [%d] is invalid!\n", len); + return -EINVAL; + } + + if (data && len) { + prParams = (P_NL80211_DRIVER_TEST_PARAMS)data; + } else { + DBGLOG(P2P, ERROR, "mtk_p2p_cfg80211_testmode_cmd, data is NULL\n"); + return i4Status; + } + if (prParams->index >> 24 == 0x01) { + /* New version */ + prParams->index = prParams->index & ~BITS(24, 31); + } else { + /* Old version */ + mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd(wiphy, data, len); + i4Status = 0; + return i4Status; + } + + /* Clear the version byte */ + prParams->index = prParams->index & ~BITS(24, 31); + + if (prParams) { + switch (prParams->index) { + case 1: /* P2P Simga */ +#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION + { + P_NL80211_DRIVER_SW_CMD_PARAMS prParamsCmd; + + prParamsCmd = (P_NL80211_DRIVER_SW_CMD_PARAMS)data; + + if ((prParamsCmd->adr & 0xffff0000) == 0xffff0000) { + i4Status = mtk_p2p_cfg80211_testmode_sw_cmd(wiphy, data, len); + break; + } + } +#endif + i4Status = + mtk_p2p_cfg80211_testmode_p2p_sigma_cmd(wiphy, data, len); + break; + + case 2: /* WFD */ +#if CFG_SUPPORT_WFD + /* use normal driver command wifi_display */ + /* i4Status = + * mtk_p2p_cfg80211_testmode_wfd_update_cmd(wiphy, data, + * len); */ +#endif + break; + + case 3: /* Hotspot Client Management */ +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER + i4Status = mtk_p2p_cfg80211_testmode_hotspot_block_list_cmd( + wiphy, data, len); +#endif + break; + + case 0x10: + i4Status = mtk_cfg80211_testmode_get_sta_statistics( + wiphy, data, len, prGlueInfo); + break; + +#if CFG_SUPPORT_NFC_BEAM_PLUS + case 0x11: /*NFC Beam + Indication */ + if (data && len) { + P_NL80211_DRIVER_SET_NFC_PARAMS prParams = + (P_NL80211_DRIVER_SET_NFC_PARAMS)data; + + DBGLOG(P2P, INFO, "NFC: BEAM[%d]\n", prParams->NFC_Enable); + } + break; + + case 0x12: /*NFC Beam + Indication */ + DBGLOG(P2P, INFO, "NFC: Polling\n"); + i4Status = mtk_cfg80211_testmode_get_scan_done(wiphy, data, len, + prGlueInfo); + break; + +#endif +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + case 0x30: + i4Status = + mtk_p2p_cfg80211_testmode_get_best_channel(wiphy, data, len); + break; +#endif + + default: + i4Status = -EINVAL; + break; + } + } + + return i4Status; +} + +int mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd(IN struct wiphy *wiphy, + IN void *data, IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + NL80211_DRIVER_TEST_PRE_PARAMS rParams; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = + (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + /* P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = + * (P_P2P_CONNECTION_SETTINGS_T)NULL; */ + u32 index_mode; + u32 index; + s32 value; + int status = 0; + u32 u4Leng; + u8 ucBssIdx; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + kalMemZero(&rParams, sizeof(NL80211_DRIVER_TEST_PRE_PARAMS)); + + prP2pSpecificBssInfo = + prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo[0]; + /* prP2pConnSettings = + * prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; */ + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_cmd\n"); + + if (data && len) { + memcpy(&rParams, data, len); + } + + DBGLOG(P2P, TRACE, "NL80211_ATTR_TESTDATA,idx_mode=%d idx=%d value=%lu\n", + (s16)rParams.idx_mode, (s16)rParams.idx, rParams.value); + + index_mode = rParams.idx_mode; + index = rParams.idx; + value = rParams.value; + + /* 3 FIX ME: Add p2p role index selection */ + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, 0, &ucBssIdx) != + WLAN_STATUS_SUCCESS) { + return -EINVAL; + } + + switch (index) { + case 0: /* Listen CH */ + break; + + case 1: /* P2p mode */ + break; + + case 4: /* Noa duration */ + prP2pSpecificBssInfo->rNoaParam.u4NoaDurationMs = value; + /* only to apply setting when setting NOA count */ + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char + **)&prP2pSpecificBssInfo->rNoaParam); */ + break; + + case 5: /* Noa interval */ + prP2pSpecificBssInfo->rNoaParam.u4NoaIntervalMs = value; + /* only to apply setting when setting NOA count */ + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char + **)&prP2pSpecificBssInfo->rNoaParam); */ + break; + + case 6: /* Noa count */ + prP2pSpecificBssInfo->rNoaParam.u4NoaCount = value; + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char + **)&prP2pSpecificBssInfo->rNoaParam); */ + break; + + case 100: /* Oper CH */ + /* 20110920 - frog: User configurations are placed in + * ConnSettings. */ + /* prP2pConnSettings->ucOperatingChnl = value; */ + break; + + case 101: /* Local config Method, for P2P SDK */ + /* prP2pConnSettings->u2LocalConfigMethod = value; */ + break; + + case 102: /* Sigma P2p reset */ + /* kalMemZero(prP2pConnSettings->aucTargetDevAddr, + * MAC_ADDR_LEN); */ + /* prP2pConnSettings->eConnectionPolicy = + * ENUM_P2P_CONNECTION_POLICY_AUTO; */ + /* p2pFsmUninit(prGlueInfo->prAdapter); */ + /* p2pFsmInit(prGlueInfo->prAdapter); */ + break; + + case 103: /* WPS MODE */ + kalP2PSetWscMode(prGlueInfo, value); + break; + + case 104: /* P2p send persence, duration */ + break; + + case 105: /* P2p send persence, interval */ + break; + + case 106: /* P2P set sleep */ + { + PARAM_POWER_MODE_T rPowerMode; + + rPowerMode.ePowerMode = Param_PowerModeMAX_PSP; + rPowerMode.ucBssIdx = ucBssIdx; + + kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile, &rPowerMode, + sizeof(rPowerMode), false, false, true, &u4Leng); + } break; + + case 107: /* P2P set opps, CTWindowl */ + prP2pSpecificBssInfo->rOppPsParam.u4CTwindowMs = value; + /* status = mtk_p2p_wext_set_oppps_param(prDev, info, wrqu, + * (char *)&prP2pSpecificBssInfo->rOppPsParam); + */ + break; + + case 108: /* p2p_set_power_save */ + { + PARAM_POWER_MODE_T rPowerMode; + + rPowerMode.ePowerMode = value; + rPowerMode.ucBssIdx = ucBssIdx; + + kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile, &rPowerMode, + sizeof(rPowerMode), false, false, true, &u4Leng); + } break; + + default: + break; + } + + return status; +} + +int mtk_p2p_cfg80211_testmode_p2p_sigma_cmd(IN struct wiphy *wiphy, + IN void *data, IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_P2P_SIGMA_PARAMS prParams = + (P_NL80211_DRIVER_P2P_SIGMA_PARAMS)NULL; + P_P2P_SPECIFIC_BSS_INFO_T prP2pSpecificBssInfo = + (P_P2P_SPECIFIC_BSS_INFO_T)NULL; + /* P_P2P_CONNECTION_SETTINGS_T prP2pConnSettings = + * (P_P2P_CONNECTION_SETTINGS_T)NULL; */ + u32 index; + s32 value; + int status = 0; + u32 u4Leng; + u8 ucBssIdx; + u32 i; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + prP2pSpecificBssInfo = + prGlueInfo->prAdapter->rWifiVar.prP2pSpecificBssInfo[0]; + /* prP2pConnSettings = + * prGlueInfo->prAdapter->rWifiVar.prP2PConnSettings; */ + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_p2p_sigma_cmd\n"); + + if (len < sizeof(NL80211_DRIVER_P2P_SIGMA_PARAMS)) { + DBGLOG(P2P, WARN, "len [%d] is invalid!\n", len); + return -EINVAL; + } + + if (data && len) { + prParams = (P_NL80211_DRIVER_P2P_SIGMA_PARAMS)data; + } + + index = (s32)prParams->idx; + value = (s32)prParams->value; + + DBGLOG(P2P, TRACE, "NL80211_ATTR_TESTDATA, idx=%lu value=%lu\n", + (s32)prParams->idx, (s32)prParams->value); + + /* 3 FIX ME: Add p2p role index selection */ + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, 0, &ucBssIdx) != + WLAN_STATUS_SUCCESS) { + return -EINVAL; + } + + switch (index) { + case 0: /* Listen CH */ + break; + + case 1: /* P2p mode */ + break; + + case 4: /* Noa duration */ + prP2pSpecificBssInfo->rNoaParam.u4NoaDurationMs = value; + /* only to apply setting when setting NOA count */ + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char + **)&prP2pSpecificBssInfo->rNoaParam); */ + break; + + case 5: /* Noa interval */ + prP2pSpecificBssInfo->rNoaParam.u4NoaIntervalMs = value; + /* only to apply setting when setting NOA count */ + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char + **)&prP2pSpecificBssInfo->rNoaParam); */ + break; + + case 6: /* Noa count */ + prP2pSpecificBssInfo->rNoaParam.u4NoaCount = value; + /* status = mtk_p2p_wext_set_noa_param(prDev, info, wrqu, (char + **)&prP2pSpecificBssInfo->rNoaParam); */ + break; + + case 100: /* Oper CH */ + /* 20110920 - frog: User configurations are placed in + * ConnSettings. */ + /* prP2pConnSettings->ucOperatingChnl = value; */ + break; + + case 101: /* Local config Method, for P2P SDK */ + /* prP2pConnSettings->u2LocalConfigMethod = value; */ + break; + + case 102: /* Sigma P2p reset */ + /* kalMemZero(prP2pConnSettings->aucTargetDevAddr, + * MAC_ADDR_LEN); */ + /* prP2pConnSettings->eConnectionPolicy = + * ENUM_P2P_CONNECTION_POLICY_AUTO; */ + break; + + case 103: /* WPS MODE */ + kalP2PSetWscMode(prGlueInfo, value); + break; + + case 104: /* P2p send persence, duration */ + break; + + case 105: /* P2p send persence, interval */ + break; + + case 106: /* P2P set sleep */ + { + PARAM_POWER_MODE_T rPowerMode; + + rPowerMode.ePowerMode = Param_PowerModeMAX_PSP; + rPowerMode.ucBssIdx = ucBssIdx; + + kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile, &rPowerMode, + sizeof(rPowerMode), false, false, true, &u4Leng); + } break; + + case 107: /* P2P set opps, CTWindowl */ + prP2pSpecificBssInfo->rOppPsParam.u4CTwindowMs = value; + /* status = mtk_p2p_wext_set_oppps_param(prDev, info, wrqu, + * (char *)&prP2pSpecificBssInfo->rOppPsParam); + */ + break; + + case 108: /* p2p_set_power_save */ + { + PARAM_POWER_MODE_T rPowerMode; + + rPowerMode.ePowerMode = value; + rPowerMode.ucBssIdx = ucBssIdx; + + kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile, &rPowerMode, + sizeof(rPowerMode), false, false, true, &u4Leng); + } break; + + case 109: /* Max Clients */ +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER + for (i = 0; i < KAL_P2P_NUM; i++) + kalP2PSetMaxClients(prGlueInfo, value, i); +#endif + break; + + case 110: /* Hotspot WPS mode */ +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER + kalIoctl(prGlueInfo, wlanoidSetP2pWPSmode, &value, sizeof(value), false, + false, true, &u4Leng); +#endif + break; + + default: + break; + } + + return status; +} + +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER + +int mtk_p2p_cfg80211_testmode_hotspot_block_list_cmd(IN struct wiphy *wiphy, + IN void *data, IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_hotspot_block_PARAMS prParams = + (P_NL80211_DRIVER_hotspot_block_PARAMS)NULL; + int fgIsValid = 0; + u32 i; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + if (len < sizeof(NL80211_DRIVER_hotspot_block_PARAMS)) { + DBGLOG(P2P, WARN, "len [%d] is invalid!\n", len); + return -EINVAL; + } + + if (data && len) { + prParams = (P_NL80211_DRIVER_hotspot_block_PARAMS)data; + } + + DBGLOG(P2P, TRACE, "mtk_p2p_cfg80211_testmode_hotspot_block_list_cmd\n"); + + for (i = 0; i < KAL_P2P_NUM; i++) + fgIsValid |= kalP2PSetBlackList(prGlueInfo, prParams->aucBssid, + prParams->ucblocked, i); + + return fgIsValid; +} + +#endif + +int mtk_p2p_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, IN void *data, + IN int len) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_NL80211_DRIVER_SW_CMD_PARAMS prParams = + (P_NL80211_DRIVER_SW_CMD_PARAMS)NULL; + WLAN_STATUS rstatus = WLAN_STATUS_SUCCESS; + int fgIsValid = 0; + u32 u4SetInfoLen = 0; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + + DBGLOG(P2P, TRACE, "--> %s()\n", __func__); + + if (len < sizeof(struct _NL80211_DRIVER_SW_CMD_PARAMS)) { + rstatus = WLAN_STATUS_INVALID_LENGTH; + } else if (!data) { + rstatus = WLAN_STATUS_INVALID_DATA; + } else { + prParams = (P_NL80211_DRIVER_SW_CMD_PARAMS)data; + if (prParams->set == 1) { + rstatus = kalIoctl(prGlueInfo, + (PFN_OID_HANDLER_FUNC)wlanoidSetSwCtrlWrite, + &prParams->adr, (u32)8, false, false, true, + &u4SetInfoLen); + } + } + + if (rstatus != WLAN_STATUS_SUCCESS) { + fgIsValid = -EFAULT; + } + + return fgIsValid; +} + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +int mtk_p2p_cfg80211_testmode_get_best_channel(IN struct wiphy *wiphy, + IN void *data, IN int len) +{ + struct sk_buff *skb; + + u8 fgIsReady = false; + + P_GLUE_INFO_T prGlueInfo = NULL; + RF_CHANNEL_INFO_T aucChannelList[MAX_2G_BAND_CHN_NUM]; + u8 ucNumOfChannel, i, ucIdx; + u16 u2APNumScore = 0, u2UpThreshold = 0, u2LowThreshold = 0, ucInnerIdx = 0; + u32 u4BufLen, u4LteSafeChnBitMask_2G = 0; + u32 u4AcsChnReport[5]; + + P_PARAM_GET_CHN_INFO prGetChnLoad, prQueryLteChn; + PARAM_PREFER_CHN_INFO rPreferChannel = { 0, 0xFFFF, 0 }; + PARAM_PREFER_CHN_INFO arChannelDirtyScore_2G[MAX_2G_BAND_CHN_NUM]; + + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + ASSERT(wiphy); + + P2P_WIPHY_PRIV(wiphy, prGlueInfo); + if (!prGlueInfo) { + DBGLOG(P2P, ERROR, "No glue info\n"); + return -EFAULT; + } + + /* Prepare reply skb buffer */ + skb = cfg80211_testmode_alloc_reply_skb(wiphy, sizeof(u4AcsChnReport)); + if (!skb) { + DBGLOG(P2P, ERROR, "Allocate skb failed\n"); + return -ENOMEM; + } + + kalMemZero(u4AcsChnReport, sizeof(u4AcsChnReport)); + + fgIsReady = prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo.fgDataReadyBit; + if (fgIsReady == false) { + goto acs_report; + } + + /* + * 1. Get 2.4G Band channel list in current regulatory domain + */ + rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_2G4, true, + MAX_2G_BAND_CHN_NUM, &ucNumOfChannel, aucChannelList); + + /* + * 2. Calculate each channel's dirty score + */ + prGetChnLoad = &(prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo); + + for (i = 0; i < ucNumOfChannel; i++) { + ucIdx = aucChannelList[i].ucChannelNum - 1; + + /* Current channel's dirty score */ + u2APNumScore = prGetChnLoad->rEachChnLoad[ucIdx].u2APNum * + CHN_DIRTY_WEIGHT_UPPERBOUND; + u2LowThreshold = u2UpThreshold = 3; + + if (ucIdx < 3) { + u2LowThreshold = ucIdx; + u2UpThreshold = 3; + } else if (ucIdx >= (ucNumOfChannel - 3)) { + u2LowThreshold = 3; + u2UpThreshold = ucNumOfChannel - (ucIdx + 1); + } + + /* Lower channel's dirty score */ + for (ucInnerIdx = 0; ucInnerIdx < u2LowThreshold; ucInnerIdx++) { + u2APNumScore += + (prGetChnLoad->rEachChnLoad[ucIdx - ucInnerIdx - 1].u2APNum * + (CHN_DIRTY_WEIGHT_UPPERBOUND - 1 - ucInnerIdx)); + } + + /* Upper channel's dirty score */ + for (ucInnerIdx = 0; ucInnerIdx < u2UpThreshold; ucInnerIdx++) { + u2APNumScore += + (prGetChnLoad->rEachChnLoad[ucIdx + ucInnerIdx + 1].u2APNum * + (CHN_DIRTY_WEIGHT_UPPERBOUND - 1 - ucInnerIdx)); + } + + arChannelDirtyScore_2G[i].ucChannel = aucChannelList[i].ucChannelNum; + arChannelDirtyScore_2G[i].u2APNumScore = u2APNumScore; + + DBGLOG(P2P, INFO, "[ACS]channel=%d, AP num=%d, score=%d\n", + aucChannelList[i].ucChannelNum, + prGetChnLoad->rEachChnLoad[ucIdx].u2APNum, u2APNumScore); + } + + /* + * 3. Query LTE safe channels + */ + prQueryLteChn = kalMemAlloc(sizeof(PARAM_GET_CHN_INFO), VIR_MEM_TYPE); + if (prQueryLteChn == NULL) { + DBGLOG(P2P, ERROR, "Alloc prQueryLteChn failed\n"); + /* Continue anyway */ + } else { + kalMemZero(prQueryLteChn, sizeof(PARAM_GET_CHN_INFO)); + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryLteSafeChannel, + prQueryLteChn, sizeof(PARAM_GET_CHN_INFO), true, + false, true, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(P2P, ERROR, "Query LTE safe channels failed\n"); + /* Continue anyway */ + } + + u4LteSafeChnBitMask_2G = + prQueryLteChn->rLteSafeChnList.au4SafeChannelBitmask + [NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_2G_BASE_1 - 1]; + if (!u4LteSafeChnBitMask_2G) { + DBGLOG(P2P, WARN, " Can't get any 2G4 safe channel from fw!?\n"); + u4LteSafeChnBitMask_2G = BITS(1, 14); + } + + kalMemFree(prQueryLteChn, VIR_MEM_TYPE, sizeof(PARAM_GET_CHN_INFO)); + } + + /* 4. Find out the best channel, skip LTE unsafe channels */ + for (i = 0; i < ucNumOfChannel; i++) { + if (!(u4LteSafeChnBitMask_2G & + BIT(arChannelDirtyScore_2G[i].ucChannel))) { + continue; + } + + if (rPreferChannel.u2APNumScore >= + arChannelDirtyScore_2G[i].u2APNumScore) { + rPreferChannel.ucChannel = arChannelDirtyScore_2G[i].ucChannel; + rPreferChannel.u2APNumScore = + arChannelDirtyScore_2G[i].u2APNumScore; + } + } + + u4AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_2G_BASE_1 - 1] = + fgIsReady ? BIT(31) : 0; + if (rPreferChannel.ucChannel > 0) { + u4AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_2G_BASE_1 - 1] |= + BIT(rPreferChannel.ucChannel - 1); + } + + /* ToDo: Support 5G Channel Selection */ + +acs_report: + if (unlikely( + nla_put_u32( + skb, NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_2G_BASE_1, + u4AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_2G_BASE_1 - + 1]) < 0)) { + goto nla_put_failure; + } + + if (unlikely( + nla_put_u32( + skb, NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_36, + u4AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_36 - + 1]) < 0)) { + goto nla_put_failure; + } + + if (unlikely( + nla_put_u32( + skb, NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_52, + u4AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_52 - + 1]) < 0)) { + goto nla_put_failure; + } + + if (unlikely( + nla_put_u32( + skb, NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_100, + u4AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_100 + - + 1]) < 0)) { + goto nla_put_failure; + } + + if (unlikely( + nla_put_u32( + skb, NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_149, + u4AcsChnReport[NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_149 + - + 1]) < 0)) { + goto nla_put_failure; + } + + DBGLOG(P2P, INFO, "[ACS]Relpy u4AcsChnReport[2G_BASE_1]=0x%08x\n", + u4AcsChnReport[0]); + + return cfg80211_testmode_reply(skb); + +nla_put_failure: + kfree_skb(skb); + return -EMSGSIZE; +} +#endif +#endif + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_p2p_init.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_p2p_init.c new file mode 100644 index 00000000000000..d6eacd5332fe63 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_p2p_init.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_p2p_init.c + * \brief init and exit routines of Linux driver interface for Wi-Fi Direct + * + * This file contains the main routines of Linux driver for MediaTek Inc. + * 802.11 Wireless LAN Adapters. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define P2P_INF_NAME "p2p%d" +#define AP_INF_NAME "phy0-ap%d" + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +static u8 *ifname = P2P_INF_NAME; +static u8 *ifname2 = P2P_INF_NAME; +static u16 mode = RUNNING_P2P_MODE; + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ +void p2pSetSuspendMode(P_GLUE_INFO_T prGlueInfo, u8 fgEnable) +{ + struct net_device *prDev = NULL; + + if (!prGlueInfo) { + return; + } + + if (!prGlueInfo->prAdapter->fgIsP2PRegistered || + (prGlueInfo->prAdapter->rP2PNetRegState != + ENUM_NET_REG_STATE_REGISTERED)) { + DBGLOG(INIT, INFO, "%s: P2P is not enabled, SKIP!\n", __func__); + return; + } + + prDev = prGlueInfo->prP2PInfo[0]->prDevHandler; + if (!prDev) { + DBGLOG(INIT, INFO, "%s: P2P dev is not available, SKIP!\n", __func__); + return; + } + + kalSetNetAddressFromInterface(prGlueInfo, prDev, fgEnable); + wlanNotifyFwSuspend(prGlueInfo, prDev, fgEnable); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * run p2p init procedure, glue register p2p and set p2p registered flag + * + * \retval 1 Success + */ +/*----------------------------------------------------------------------------*/ +u8 p2pLaunch(P_GLUE_INFO_T prGlueInfo) +{ + P_ADAPTER_T prAdapter = NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + prAdapter = prGlueInfo->prAdapter; + + ASSERT(prGlueInfo); + ASSERT(prAdapter); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + if (prAdapter->rP2PRegState != ENUM_P2P_REG_STATE_UNREGISTERED) { + DBGLOG(P2P, INFO, "skip launch, p2p_state=%d, net_state=%d\n", + prAdapter->rP2PRegState, prAdapter->rP2PNetRegState); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + return false; + } + + prAdapter->rP2PRegState = ENUM_P2P_REG_STATE_REGISTERING; + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + if (!glRegisterP2P(prGlueInfo, ifname, ifname2, mode)) { + DBGLOG(P2P, ERROR, "Launch failed\n"); + prAdapter->rP2PRegState = ENUM_P2P_REG_STATE_UNREGISTERED; + return false; + } + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + prAdapter->fgIsP2PRegistered = true; + prAdapter->p2p_scan_report_all_bss = CFG_P2P_SCAN_REPORT_ALL_BSS; + prAdapter->rP2PRegState = ENUM_P2P_REG_STATE_REGISTERED; + DBGLOG(P2P, INFO, "Launch success, fgIsP2PRegistered true\n"); + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + return true; +} + +void p2pSetMode(IN u8 ucAPMode) +{ + u8 *prAPInfName = AP_INF_NAME; + u8 *prP2PInfName = P2P_INF_NAME; + +#ifdef CFG_DRIVER_INF_NAME_CHANGE + if (kalStrLen(gprifnamep2p) > 0) { + prP2PInfName = kalStrCat(gprifnamep2p, "%d"); + DBGLOG(INIT, WARN, "P2P ifname customized, use %s\n", prP2PInfName); + } + + if (kalStrLen(gprifnameap) > 0) { + prAPInfName = kalStrCat(gprifnameap, "%d"); + DBGLOG(INIT, WARN, "AP ifname customized, use %s\n", prAPInfName); + } +#endif + + switch (ucAPMode) { + case 0: + mode = RUNNING_P2P_MODE; + ifname = prP2PInfName; + break; + + case 1: + mode = RUNNING_AP_MODE; + ifname = prAPInfName; + break; + + case 2: + mode = RUNNING_DUAL_AP_MODE; + ifname = prAPInfName; + break; + + case 3: + mode = RUNNING_P2P_AP_MODE; + ifname = prP2PInfName; + ifname2 = prAPInfName; + break; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * run p2p exit procedure, glue unregister p2p and set p2p registered flag + * + * \retval 1 Success + */ +/*----------------------------------------------------------------------------*/ +u8 p2pRemove(P_GLUE_INFO_T prGlueInfo) +{ + P_ADAPTER_T prAdapter = NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + prAdapter = prGlueInfo->prAdapter; + + ASSERT(prGlueInfo); + ASSERT(prAdapter); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + g_P2pPrDev = NULL; + + if (prAdapter->rP2PRegState != ENUM_P2P_REG_STATE_REGISTERED || + prAdapter->rP2PNetRegState != ENUM_NET_REG_STATE_UNREGISTERED) { + DBGLOG(P2P, INFO, "skip remove, p2p_state=%d, net_state=%d\n", + prAdapter->rP2PRegState, prAdapter->rP2PNetRegState); + return false; + } + + prAdapter->rP2PRegState = ENUM_P2P_REG_STATE_UNREGISTERING; + prAdapter->p2p_scan_report_all_bss = false; + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + glUnregisterP2P(prGlueInfo, 0xff); + + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + prAdapter->rP2PRegState = ENUM_P2P_REG_STATE_UNREGISTERED; + prAdapter->fgIsP2PRegistered = false; + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + return true; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_p2p_kal.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_p2p_kal.c new file mode 100644 index 00000000000000..539a0178ace187 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_p2p_kal.c @@ -0,0 +1,1271 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_p2p_kal.c + * \brief + * + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "net/cfg80211.h" +#include "precomp.h" +#include "gl_wext.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +struct ieee80211_channel * +kalP2pFuncGetChannelEntry(IN P_GL_P2P_INFO_T prP2pInfo, + IN P_RF_CHANNEL_INFO_T prChannelInfo); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to update the assoc req to p2p + * + * \param[in] + * prGlueInfo + * pucFrameBody + * u4FrameBodyLen + * fgReassocRequest + * \return + * none + */ +/*----------------------------------------------------------------------------*/ +void kalP2PUpdateAssocInfo(IN P_GLUE_INFO_T prGlueInfo, IN u8 *pucFrameBody, + IN u32 u4FrameBodyLen, IN u8 fgReassocRequest, + IN u8 ucBssIndex) +{ + P_BSS_INFO_T prBssInfo; + union iwreq_data wrqu; + unsigned char *pucExtraInfo = NULL; + unsigned char *pucDesiredIE = NULL; + /* unsigned char aucExtraInfoBuf[200]; */ + u8 *cp; + struct net_device *prNetdevice = (struct net_device *)NULL; + + memset(&wrqu, 0, sizeof(wrqu)); + + if (fgReassocRequest) { + if (u4FrameBodyLen < 15) { + /* + * printk(KERN_WARNING "frameBodyLen too short:%ld\n", + * frameBodyLen); + */ + return; + } + } else { + if (u4FrameBodyLen < 9) { + /* + * printk(KERN_WARNING "frameBodyLen too short:%ld\n", + * frameBodyLen); + */ + return; + } + } + + cp = pucFrameBody; + + if (fgReassocRequest) { + /* Capability information field 2 */ + /* Listen interval field 2 */ + /* Current AP address 6 */ + cp += 10; + u4FrameBodyLen -= 10; + } else { + /* Capability information field 2 */ + /* Listen interval field 2 */ + cp += 4; + u4FrameBodyLen -= 4; + } + + /* do supplicant a favor, parse to the start of WPA/RSN IE */ + if (wextSrchDesiredWPSIE(cp, u4FrameBodyLen, 0xDD, &pucDesiredIE)) { + /* WPS IE found */ + } else if (wextSrchDesiredWPAIE(cp, u4FrameBodyLen, 0x30, &pucDesiredIE)) { + /* RSN IE found */ + } else if (wextSrchDesiredWPAIE(cp, u4FrameBodyLen, 0xDD, &pucDesiredIE)) { + /* WPA IE found */ + } else { + /* no WPA/RSN IE found, skip this event */ + return; + } + + /* IWEVASSOCREQIE, indicate binary string */ + pucExtraInfo = pucDesiredIE; + wrqu.data.length = pucDesiredIE[1] + 2; + + prBssInfo = GET_BSS_INFO_BY_INDEX(prGlueInfo->prAdapter, ucBssIndex); + + if (ucBssIndex == P2P_DEV_BSS_INDEX) { + prNetdevice = + prGlueInfo->prP2PInfo[prBssInfo->u4PrivateData]->prDevHandler; + } else { + prNetdevice = + prGlueInfo->prP2PInfo[prBssInfo->u4PrivateData]->aprRoleHandler; + } + + /* Send event to user space */ + wireless_send_event(prNetdevice, IWEVASSOCREQIE, &wrqu, pucExtraInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to retrieve Bluetooth-over-Wi-Fi role + * + * \param[in] + * prGlueInfo + * + * \return + * 0: P2P Device + * 1: Group Client + * 2: Group Owner + */ +/*----------------------------------------------------------------------------*/ +u8 kalP2PGetRole(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIdx) +{ + ASSERT(prGlueInfo); + + return prGlueInfo->prP2PInfo[ucRoleIdx]->ucRole; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to set Wi-Fi Direct role + * + * \param[in] + * prGlueInfo + * ucResult + * 0: successful + * 1: error + * ucRole + * 0: P2P Device + * 1: Group Client + * 2: Group Owner + * + * \return + * none + */ +/*----------------------------------------------------------------------------*/ +void kalP2PSetRole(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRole, IN u8 ucRoleIdx) +{ + ASSERT(prGlueInfo); + ASSERT(ucRole <= 2); + + prGlueInfo->prP2PInfo[ucRoleIdx]->ucRole = ucRole; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to set the cipher for p2p + * + * \param[in] + * prGlueInfo + * u4Cipher + * + * \return + * none + */ +/*----------------------------------------------------------------------------*/ +void kalP2PSetCipher(IN P_GLUE_INFO_T prGlueInfo, IN u32 u4Cipher, + IN u8 ucRoleIdx) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo[ucRoleIdx]); + + /* It can be WEP40 (used to identify cipher is WEP), TKIP and CCMP */ + prGlueInfo->prP2PInfo[ucRoleIdx]->u4CipherPairwise = u4Cipher; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to get the cipher, return false for security is none + * + * \param[in] + * prGlueInfo + * + * \return + * true: cipher is ccmp + * false: cipher is none + */ +/*----------------------------------------------------------------------------*/ +u8 kalP2PGetCipher(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIdx) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo[ucRoleIdx]); + + if (prGlueInfo->prP2PInfo[ucRoleIdx]->u4CipherPairwise == + IW_AUTH_CIPHER_CCMP) { + return true; + } + + if (prGlueInfo->prP2PInfo[ucRoleIdx]->u4CipherPairwise == + IW_AUTH_CIPHER_TKIP) { + return true; + } + + if (prGlueInfo->prP2PInfo[ucRoleIdx]->u4CipherPairwise == + IW_AUTH_CIPHER_WEP40) { + return true; + } + + return false; +} + +u8 kalP2PGetWepCipher(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIdx) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo[ucRoleIdx]); + + if (prGlueInfo->prP2PInfo[ucRoleIdx]->u4CipherPairwise == + IW_AUTH_CIPHER_WEP40) { + return true; + } + + if (prGlueInfo->prP2PInfo[ucRoleIdx]->u4CipherPairwise == + IW_AUTH_CIPHER_WEP104) { + return true; + } + + return false; +} + +#if CFG_SUPPORT_SUITB +u8 kalP2PGetGcmp256Cipher(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIdx) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo[ucRoleIdx]); + + if (prGlueInfo->prP2PInfo[ucRoleIdx]->u4CipherPairwise == + IW_AUTH_CIPHER_GCMP256) { + return true; + } + + return false; +} +#endif + +u8 kalP2PGetCcmpCipher(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIdx) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo[ucRoleIdx]); + + if (prGlueInfo->prP2PInfo[ucRoleIdx]->u4CipherPairwise == + IW_AUTH_CIPHER_CCMP) { + return true; + } + + if (prGlueInfo->prP2PInfo[ucRoleIdx]->u4CipherPairwise == + IW_AUTH_CIPHER_TKIP) { + return false; + } + + return false; +} + +u8 kalP2PGetTkipCipher(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIdx) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo[ucRoleIdx]); + + if (prGlueInfo->prP2PInfo[ucRoleIdx]->u4CipherPairwise == + IW_AUTH_CIPHER_CCMP) { + return false; + } + + if (prGlueInfo->prP2PInfo[ucRoleIdx]->u4CipherPairwise == + IW_AUTH_CIPHER_TKIP) { + return true; + } + + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to set the status of WSC + * + * \param[in] + * prGlueInfo + * + * \return + */ +/*----------------------------------------------------------------------------*/ +void kalP2PSetWscMode(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucWscMode) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PDevInfo); + + prGlueInfo->prP2PDevInfo->ucWSCRunning = ucWscMode; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to get the status of WSC + * + * \param[in] + * prGlueInfo + * + * \return + */ +/*----------------------------------------------------------------------------*/ +u8 kalP2PGetWscMode(IN P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PDevInfo); + + return prGlueInfo->prP2PDevInfo->ucWSCRunning; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to get the wsc ie length + * + * \param[in] + * prGlueInfo + * ucType : 0 for beacon, 1 for probe req, 2 for probe resp + * + * \return + * The WSC IE length + */ +/*----------------------------------------------------------------------------*/ +u16 kalP2PCalWSC_IELen(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucType, + IN u8 ucRoleIdx) +{ + ASSERT(prGlueInfo); + + ASSERT(ucType < 4); + + return prGlueInfo->prP2PInfo[ucRoleIdx]->u2WSCIELen[ucType]; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to copy the wsc ie setting from p2p supplicant + * + * \param[in] + * prGlueInfo + * + * \return + * The WPS IE length + */ +/*----------------------------------------------------------------------------*/ +void kalP2PGenWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucType, + IN u8 *pucBuffer, IN u8 ucRoleIdx) +{ + P_GL_P2P_INFO_T prGlP2pInfo = (P_GL_P2P_INFO_T)NULL; + + do { + if ((prGlueInfo == NULL) || (ucType >= 4) || (pucBuffer == NULL)) { + break; + } + + prGlP2pInfo = prGlueInfo->prP2PInfo[ucRoleIdx]; + + kalMemCopy(pucBuffer, prGlP2pInfo->aucWSCIE[ucType], + prGlP2pInfo->u2WSCIELen[ucType]); + } while (false); +} + +void kalP2PUpdateWSC_IE(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucType, + IN u8 *pucBuffer, IN u16 u2BufferLength, + IN u8 ucRoleIdx) +{ + P_GL_P2P_INFO_T prGlP2pInfo = (P_GL_P2P_INFO_T)NULL; + + do { + if ((prGlueInfo == NULL) || (ucType >= 4) || + ((u2BufferLength > 0) && (pucBuffer == NULL))) { + break; + } + + if (u2BufferLength > 400) { + DBGLOG( + P2P, ERROR, + "Buffer length is not enough, GLUE only 400 bytes but %d received\n", + u2BufferLength); + ASSERT(false); + break; + } + + prGlP2pInfo = prGlueInfo->prP2PInfo[ucRoleIdx]; + + kalMemCopy(prGlP2pInfo->aucWSCIE[ucType], pucBuffer, u2BufferLength); + + prGlP2pInfo->u2WSCIELen[ucType] = u2BufferLength; + } while (false); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Indicate an event to supplicant for Service Discovery request from + * other device. + * + * \param[in] prGlueInfo Pointer of GLUE_INFO_T + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void kalP2PIndicateSDRequest(IN P_GLUE_INFO_T prGlueInfo, + IN PARAM_MAC_ADDRESS rPeerAddr, IN u8 ucSeqNum) +{ + union iwreq_data evt; + u8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SD_REQ %d", ucSeqNum); + evt.data.length = strlen(aucBuffer); + + /* indicate IWEVP2PSDREQ event */ + wireless_send_event(prGlueInfo->prP2PInfo[0]->prDevHandler, IWEVCUSTOM, + &evt, aucBuffer); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Indicate an event to supplicant for Service Discovery response + * from other device. + * + * \param[in] prGlueInfo Pointer of GLUE_INFO_T + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void kalP2PIndicateSDResponse(IN P_GLUE_INFO_T prGlueInfo, + IN PARAM_MAC_ADDRESS rPeerAddr, IN u8 ucSeqNum) +{ + union iwreq_data evt; + u8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SD_RESP %d", ucSeqNum); + evt.data.length = strlen(aucBuffer); + + /* indicate IWEVP2PSDREQ event */ + wireless_send_event(prGlueInfo->prP2PInfo[0]->prDevHandler, IWEVCUSTOM, + &evt, aucBuffer); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Indicate an event to supplicant for Service Discovery TX Done + * from other device. + * + * \param[in] prGlueInfo Pointer of GLUE_INFO_T + * \param[in] ucSeqNum Sequence number of the frame + * \param[in] ucStatus Status code for TX + * + * \retval none + */ +/*----------------------------------------------------------------------------*/ +void kalP2PIndicateTXDone(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucSeqNum, + IN u8 ucStatus) +{ + union iwreq_data evt; + u8 aucBuffer[IW_CUSTOM_MAX]; + + ASSERT(prGlueInfo); + + memset(&evt, 0, sizeof(evt)); + + snprintf(aucBuffer, IW_CUSTOM_MAX - 1, "P2P_SD_XMITTED: %d %d", ucSeqNum, + ucStatus); + evt.data.length = strlen(aucBuffer); + + /* indicate IWEVP2PSDREQ event */ + wireless_send_event(prGlueInfo->prP2PInfo[0]->prDevHandler, IWEVCUSTOM, + &evt, aucBuffer); +} + +struct net_device *kalP2PGetDevHdlr(P_GLUE_INFO_T prGlueInfo) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo[0]); + return prGlueInfo->prP2PInfo[0]->prDevHandler; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * + * \param[in] prAdapter Pointer of ADAPTER_T + * + * \return none + */ +/*----------------------------------------------------------------------------*/ +void kalGetChnlList(IN P_GLUE_INFO_T prGlueInfo, IN ENUM_BAND_T eSpecificBand, + IN u8 ucMaxChannelNum, IN u8 *pucNumOfChannel, + IN P_RF_CHANNEL_INFO_T paucChannelList) +{ + rlmDomainGetChnlList(prGlueInfo->prAdapter, eSpecificBand, false, + ucMaxChannelNum, pucNumOfChannel, paucChannelList); +} + +/* ////////////////////////////////////ICS + * SUPPORT////////////////////////////////////// */ +void kalP2PIndicateChannelReady(IN P_GLUE_INFO_T prGlueInfo, IN u64 u8SeqNum, + IN u32 u4ChannelNum, IN ENUM_BAND_T eBand, + IN ENUM_CHNL_EXT_T eSco, IN u32 u4Duration) +{ + struct ieee80211_channel *prIEEE80211ChnlStruct = + (struct ieee80211_channel *)NULL; + RF_CHANNEL_INFO_T rChannelInfo; + enum nl80211_channel_type eChnlType = NL80211_CHAN_NO_HT; + + do { + if (prGlueInfo == NULL) { + break; + } + + kalMemZero(&rChannelInfo, sizeof(RF_CHANNEL_INFO_T)); + + rChannelInfo.ucChannelNum = u4ChannelNum; + rChannelInfo.eBand = eBand; + + prIEEE80211ChnlStruct = + kalP2pFuncGetChannelEntry(prGlueInfo->prP2PInfo[0], &rChannelInfo); + + kalP2pFuncGetChannelType(eSco, &eChnlType); + + cfg80211_ready_on_channel( + prGlueInfo->prP2PInfo[0]->prWdev, /* struct + * wireless_dev, */ + u8SeqNum, /* u64 cookie, */ + prIEEE80211ChnlStruct, /* struct ieee80211_channel * + * chan, */ + u4Duration, /* unsigned int duration, */ + GFP_KERNEL); + /* gfp_t gfp */ /* allocation flags */ + } while (false); +} + +void kalP2PIndicateChannelExpired(IN P_GLUE_INFO_T prGlueInfo, IN u64 u8SeqNum, + IN u32 u4ChannelNum, IN ENUM_BAND_T eBand, + IN ENUM_CHNL_EXT_T eSco) +{ + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + struct ieee80211_channel *prIEEE80211ChnlStruct = + (struct ieee80211_channel *)NULL; + enum nl80211_channel_type eChnlType = NL80211_CHAN_NO_HT; + RF_CHANNEL_INFO_T rRfChannelInfo; + + do { + if (prGlueInfo == NULL) { + ASSERT(false); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo[0]; + + if (prGlueP2pInfo == NULL) { + ASSERT(false); + break; + } + + DBGLOG(P2P, TRACE, "kalP2PIndicateChannelExpired\n"); + + rRfChannelInfo.eBand = eBand; + rRfChannelInfo.ucChannelNum = u4ChannelNum; + + prIEEE80211ChnlStruct = + kalP2pFuncGetChannelEntry(prGlueP2pInfo, &rRfChannelInfo); + + kalP2pFuncGetChannelType(eSco, &eChnlType); + + cfg80211_remain_on_channel_expired( + prGlueP2pInfo->prWdev, /* struct wireless_dev, */ + u8SeqNum, prIEEE80211ChnlStruct, GFP_KERNEL); + } while (false); +} + +void kalP2PIndicateScanDone(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIndex, + IN u8 fgIsAbort) +{ + P_GL_P2P_DEV_INFO_T prP2pGlueDevInfo = (P_GL_P2P_DEV_INFO_T)NULL; + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + struct cfg80211_scan_request *prScanRequest = NULL; + + GLUE_SPIN_LOCK_DECLARATION(); + + do { + if (prGlueInfo == NULL) { + ASSERT(false); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo[0]; + prP2pGlueDevInfo = prGlueInfo->prP2PDevInfo; + + if ((prGlueP2pInfo == NULL) || (prP2pGlueDevInfo == NULL)) { + ASSERT(false); + break; + } + + DBGLOG(INIT, INFO, "[p2p] scan complete %p\n", + prP2pGlueDevInfo->prScanRequest); + + KAL_ACQUIRE_MUTEX(prGlueInfo->prAdapter, MUTEX_DEL_INF); + GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + if (prP2pGlueDevInfo->prScanRequest != NULL) { + prScanRequest = prP2pGlueDevInfo->prScanRequest; + prP2pGlueDevInfo->prScanRequest = NULL; + } + GLUE_RELEASE_SPIN_LOCK(prGlueInfo, SPIN_LOCK_NET_DEV); + + if ((prScanRequest != NULL) && + (prGlueInfo->prAdapter->fgIsP2PRegistered == true)) { + /* report all queued beacon/probe response frames to + * upper layer */ + scanReportBss2Cfg80211(prGlueInfo->prAdapter, BSS_TYPE_P2P_DEVICE, + NULL); + + DBGLOG(INIT, INFO, "DBG:p2p_cfg_scan_done\n"); + kalCfg80211ScanDone(prScanRequest, fgIsAbort); + } + KAL_RELEASE_MUTEX(prGlueInfo->prAdapter, MUTEX_DEL_INF); + } while (false); +} + +void kalP2PIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, IN u8 *pucFrameBuf, + IN u32 u4BufLen, + IN P_RF_CHANNEL_INFO_T prChannelInfo, + IN s32 i4SignalStrength) +{ + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + struct ieee80211_channel *prChannelEntry = (struct ieee80211_channel *)NULL; + struct ieee80211_mgmt *prBcnProbeRspFrame = + (struct ieee80211_mgmt *)pucFrameBuf; + struct cfg80211_bss *prCfg80211Bss = (struct cfg80211_bss *)NULL; + + do { + if ((prGlueInfo == NULL) || (pucFrameBuf == NULL) || + (prChannelInfo == NULL)) { + ASSERT(false); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo[0]; + + if (prGlueP2pInfo == NULL) { + ASSERT(false); + break; + } + + prChannelEntry = + kalP2pFuncGetChannelEntry(prGlueP2pInfo, prChannelInfo); + + if (prChannelEntry == NULL) { + DBGLOG(P2P, TRACE, "Unknown channel info\n"); + break; + } + + /* rChannelInfo.center_freq = + * nicChannelNum2Freq((u32)prChannelInfo->ucChannelNum) / 1000; + */ + + prCfg80211Bss = cfg80211_inform_bss_frame( + prGlueP2pInfo->prWdev->wiphy, /* struct wiphy * wiphy, + */ + prChannelEntry, prBcnProbeRspFrame, u4BufLen, i4SignalStrength, + GFP_KERNEL); + + /* Return this structure. */ + cfg80211_put_bss(prGlueP2pInfo->prWdev->wiphy, prCfg80211Bss); + } while (false); + + return; +} + +void kalP2PIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, + IN P_MSDU_INFO_T prMsduInfo, IN u8 fgIsAck) +{ + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + u64 *pu8GlCookie = (u64 *)NULL; + struct net_device *prNetdevice = (struct net_device *)NULL; + + do { + if ((prGlueInfo == NULL) || (prMsduInfo == NULL)) { + DBGLOG(P2P, WARN, "Unexpected pointer PARAM. 0x%lx, 0x%lx.\n", + prGlueInfo, prMsduInfo); + ASSERT(false); + break; + } + + pu8GlCookie = (u64 *)((unsigned long)prMsduInfo->prPacket + + (unsigned long)prMsduInfo->u2FrameLength + + MAC_TX_RESERVED_FIELD); + + if (prMsduInfo->ucBssIndex == P2P_DEV_BSS_INDEX) { + prGlueP2pInfo = prGlueInfo->prP2PInfo[0]; + + if (prGlueP2pInfo == NULL) { + return; + } + + prNetdevice = prGlueP2pInfo->prDevHandler; + } else { + P_BSS_INFO_T prP2pBssInfo = GET_BSS_INFO_BY_INDEX( + prGlueInfo->prAdapter, prMsduInfo->ucBssIndex); + prGlueP2pInfo = prGlueInfo->prP2PInfo[prP2pBssInfo->u4PrivateData]; + + if (prGlueP2pInfo == NULL) { + return; + } + + prNetdevice = prGlueP2pInfo->aprRoleHandler; + } + + cfg80211_mgmt_tx_status( + prNetdevice->ieee80211_ptr, /* struct net_device * dev, + */ + *pu8GlCookie, + (u8 *)((unsigned long)prMsduInfo->prPacket + MAC_TX_RESERVED_FIELD), + prMsduInfo->u2FrameLength, fgIsAck, GFP_KERNEL); + } while (false); +} + +void kalP2PIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, + IN P_SW_RFB_T prSwRfb, IN u8 fgIsDevInterface, + IN u8 ucRoleIdx) +{ +#define DBG_P2P_MGMT_FRAME_INDICATION 1 + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + s32 i4Freq = 0; + u8 ucChnlNum = 0; +#if DBG_P2P_MGMT_FRAME_INDICATION + P_WLAN_MAC_HEADER_T prWlanHeader = (P_WLAN_MAC_HEADER_T)NULL; +#endif + struct net_device *prNetdevice = (struct net_device *)NULL; + + do { + if ((prGlueInfo == NULL) || (prSwRfb == NULL)) { + ASSERT(false); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo[ucRoleIdx]; + + /* ToDo[6630]: Get the following by channel freq */ + /* HAL_RX_STATUS_GET_CHAN_FREQ( prSwRfb->prRxStatus) */ + /* ucChnlNum = prSwRfb->prHifRxHdr->ucHwChannelNum; */ + + ucChnlNum = HAL_RX_STATUS_GET_CHNL_NUM(prSwRfb->prRxStatus); + +#if DBG_P2P_MGMT_FRAME_INDICATION + prWlanHeader = (P_WLAN_MAC_HEADER_T)prSwRfb->pvHeader; + + switch (prWlanHeader->u2FrameCtrl) { + case MAC_FRAME_PROBE_REQ: + DBGLOG(P2P, TRACE, "RX Probe Req at channel %d ", ucChnlNum); + break; + + case MAC_FRAME_PROBE_RSP: + DBGLOG(P2P, TRACE, "RX Probe Rsp at channel %d ", ucChnlNum); + break; + + case MAC_FRAME_ACTION: + DBGLOG(P2P, TRACE, "RX Action frame at channel %d ", ucChnlNum); + p2pFuncClassifyAction(prSwRfb); + break; + + default: + DBGLOG(P2P, TRACE, "RX Packet:%d at channel %d ", + prWlanHeader->u2FrameCtrl, ucChnlNum); + break; + } + + DBGLOG(P2P, TRACE, "from: " MACSTR "\n", + MAC2STR(prWlanHeader->aucAddr2)); +#endif + i4Freq = nicChannelNum2Freq(ucChnlNum) / 1000; + + if (fgIsDevInterface) { + prNetdevice = prGlueP2pInfo->prDevHandler; + } else { + prNetdevice = prGlueP2pInfo->aprRoleHandler; + } + + cfg80211_rx_mgmt( + prNetdevice->ieee80211_ptr, /* struct + * net_device * + * dev, */ + i4Freq, + RCPI_TO_dBm(nicRxGetRcpiValueFromRxv(RCPI_MODE_WF0, prSwRfb)), + prSwRfb->pvHeader, prSwRfb->u2PacketLen, + NL80211_RXMGMT_FLAG_ANSWERED); + } while (false); +} + +void kalP2PGCIndicateConnectionStatus( + IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIndex, + IN P_P2P_CONNECTION_REQ_INFO_T prP2pConnInfo, IN u8 *pucRxIEBuf, + IN u16 u2RxIELen, IN u16 u2StatusReason, IN WLAN_STATUS eStatus) +{ + P_GL_P2P_INFO_T prGlueP2pInfo = (P_GL_P2P_INFO_T)NULL; + + do { + if (prGlueInfo == NULL) { + ASSERT(false); + break; + } + + prGlueP2pInfo = prGlueInfo->prP2PInfo[ucRoleIndex]; + + /* This exception occurs at wlanRemove. */ + if ((prGlueP2pInfo == NULL) || + (prGlueP2pInfo->aprRoleHandler == NULL) || + (prGlueInfo->prAdapter->rP2PNetRegState != + ENUM_NET_REG_STATE_REGISTERED) || + ((prGlueInfo->ulFlag & GLUE_FLAG_HALT) == 1)) { + break; + } + + if (prP2pConnInfo) { + /* switch netif on */ + netif_carrier_on(prGlueP2pInfo->aprRoleHandler); + + cfg80211_connect_result(prGlueP2pInfo->aprRoleHandler, + /* struct net_device * dev, */ + prP2pConnInfo->aucBssid, + prP2pConnInfo->aucIEBuf, + prP2pConnInfo->u4BufLength, pucRxIEBuf, + u2RxIELen, u2StatusReason, GFP_KERNEL); + /* gfp_t gfp */ /* allocation flags */ + + prP2pConnInfo->eConnRequest = P2P_CONNECTION_TYPE_IDLE; + } else { + DBGLOG(INIT, INFO, + "indicate disconnection event to kernel, reason=%d, " + "locally_generated=%d\n", + u2StatusReason, + eStatus == WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY); + /* Disconnect, what if u2StatusReason == 0? */ + cfg80211_disconnected( + prGlueP2pInfo->aprRoleHandler, + /* struct net_device * dev, */ + u2StatusReason, pucRxIEBuf, u2RxIELen, + eStatus == WLAN_STATUS_MEDIA_DISCONNECT_LOCALLY, GFP_KERNEL); + } + } while (false); +} + +void kalP2PGOStationUpdate(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIndex, + IN P_STA_RECORD_T prCliStaRec, IN u8 fgIsNew) +{ + P_GL_P2P_INFO_T prP2pGlueInfo = (P_GL_P2P_INFO_T)NULL; + + do { + if ((prGlueInfo == NULL) || (prCliStaRec == NULL) || + (ucRoleIndex >= 2)) { + break; + } + + prP2pGlueInfo = prGlueInfo->prP2PInfo[ucRoleIndex]; + + if ((prP2pGlueInfo == NULL) || + (prP2pGlueInfo->aprRoleHandler == NULL)) { + /* This case may occur when the usb is unplugged */ + break; + } + + if (fgIsNew) { + struct station_info rStationInfo; + + kalMemZero(&rStationInfo, sizeof(rStationInfo)); + + rStationInfo.generation = ++prP2pGlueInfo->i4Generation; + rStationInfo.assoc_req_ies = prCliStaRec->pucAssocReqIe; + rStationInfo.assoc_req_ies_len = prCliStaRec->u2AssocReqIeLen; + + cfg80211_new_sta(prP2pGlueInfo->aprRoleHandler, + /* struct net_device * dev, */ + prCliStaRec->aucMacAddr, &rStationInfo, + GFP_KERNEL); + } else { + ++prP2pGlueInfo->i4Generation; + + /* The exception occurs at wlanRemove */ + if ((prP2pGlueInfo != NULL) && + (prP2pGlueInfo->aprRoleHandler != NULL) && + (prGlueInfo->prAdapter->rP2PNetRegState == + ENUM_NET_REG_STATE_REGISTERED) && + ((prGlueInfo->ulFlag & GLUE_FLAG_HALT) == 0)) { + cfg80211_del_sta(prP2pGlueInfo->aprRoleHandler, + prCliStaRec->aucMacAddr, GFP_KERNEL); + } + } + } while (false); + + return; +} + +#if (CFG_SUPPORT_DFS_MASTER == 1) +void kalP2PRddDetectUpdate(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIndex) +{ + DBGLOG(INIT, INFO, "Radar Detection event\n"); + + do { + if (prGlueInfo == NULL) { + ASSERT(false); + break; + } + + if (prGlueInfo->prP2PInfo[ucRoleIndex]->chandef == NULL) { + ASSERT(false); + break; + } + + /* cac start disable for next cac slot if enable in dfs channel + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) + prGlueInfo->prP2PInfo[ucRoleIndex]->prWdev->links[0].cac_started = + false; +#else + prGlueInfo->prP2PInfo[ucRoleIndex]->prWdev->cac_started = false; +#endif + DBGLOG(INIT, INFO, "kalP2PRddDetectUpdate: Update to OS\n"); + cfg80211_radar_event(prGlueInfo->prP2PInfo[ucRoleIndex]->prWdev->wiphy, + prGlueInfo->prP2PInfo[ucRoleIndex]->chandef, + GFP_KERNEL); + DBGLOG(INIT, INFO, "kalP2PRddDetectUpdate: Update to OS Done\n"); + + /* NL80211 event should send to p2p group netdevice. + * Otherwise wpa_supplicant wouldn't perform beacon update. + * Hostapd case: prDevHandler same with aprRoleHandler + * P2P GO case: p2p0=>prDevHandler, p2p-xxx-x=> aprRoleHandler + */ + netif_carrier_off(prGlueInfo->prP2PInfo[ucRoleIndex]->aprRoleHandler); + netif_tx_stop_all_queues( + prGlueInfo->prP2PInfo[ucRoleIndex]->aprRoleHandler); + + if (prGlueInfo->prP2PInfo[ucRoleIndex]->chandef->chan) { + cnmMemFree(prGlueInfo->prAdapter, + prGlueInfo->prP2PInfo[ucRoleIndex]->chandef->chan); + } + + prGlueInfo->prP2PInfo[ucRoleIndex]->chandef->chan = NULL; + + if (prGlueInfo->prP2PInfo[ucRoleIndex]->chandef) { + cnmMemFree(prGlueInfo->prAdapter, + prGlueInfo->prP2PInfo[ucRoleIndex]->chandef); + } + + prGlueInfo->prP2PInfo[ucRoleIndex]->chandef = NULL; + } while (false); +} + +void kalP2PCacFinishedUpdate(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIndex) +{ + DBGLOG(INIT, INFO, "CAC Finished event\n"); + + if (prGlueInfo == NULL) { + return; + } + + if (prGlueInfo->prP2PInfo[ucRoleIndex]->chandef == NULL) { + return; + } + + /* NL80211 event should send to p2p group netdevice. + * Otherwise wpa_supplicant wouldn't perform beacon update. + * Hostapd case: prDevHandler same with aprRoleHandler + * P2P GO case: p2p0=>prDevHandler, p2p-xxx-x=> aprRoleHandler + */ + DBGLOG(INIT, INFO, "kalP2PCacFinishedUpdate: Update to OS\n"); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) + cfg80211_cac_event(prGlueInfo->prP2PInfo[ucRoleIndex]->prDevHandler, + prGlueInfo->prP2PInfo[ucRoleIndex]->chandef, + NL80211_RADAR_CAC_FINISHED, GFP_KERNEL, 0); +#else + cfg80211_cac_event(prGlueInfo->prP2PInfo[ucRoleIndex]->aprRoleHandler, + prGlueInfo->prP2PInfo[ucRoleIndex]->chandef, + NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); +#endif + + DBGLOG(INIT, INFO, "kalP2PCacFinishedUpdate: Update to OS Done\n"); +} +#endif + +u8 kalP2pFuncGetChannelType(IN ENUM_CHNL_EXT_T rChnlSco, + OUT enum nl80211_channel_type *channel_type) +{ + u8 fgIsValid = false; + + do { + if (channel_type) { + switch (rChnlSco) { + case CHNL_EXT_SCN: + *channel_type = NL80211_CHAN_NO_HT; + break; + + case CHNL_EXT_SCA: + *channel_type = NL80211_CHAN_HT40MINUS; + break; + + case CHNL_EXT_SCB: + *channel_type = NL80211_CHAN_HT40PLUS; + break; + + default: + ASSERT(false); + *channel_type = NL80211_CHAN_NO_HT; + break; + } + } + + fgIsValid = true; + } while (false); + + return fgIsValid; +} + +struct ieee80211_channel * +kalP2pFuncGetChannelEntry(IN P_GL_P2P_INFO_T prP2pInfo, + IN P_RF_CHANNEL_INFO_T prChannelInfo) +{ + struct ieee80211_channel *prTargetChannelEntry = + (struct ieee80211_channel *)NULL; + struct wiphy *wiphy = (struct wiphy *)NULL; + u32 u4TblSize = 0, u4Idx = 0; + + if ((prP2pInfo == NULL) || (prChannelInfo == NULL)) { + return NULL; + } + + wiphy = prP2pInfo->prWdev->wiphy; + + do { + switch (prChannelInfo->eBand) { + case BAND_2G4: + prTargetChannelEntry = wiphy->bands[NL80211_BAND_2GHZ]->channels; + u4TblSize = wiphy->bands[NL80211_BAND_2GHZ]->n_channels; + break; + + case BAND_5G: + prTargetChannelEntry = wiphy->bands[NL80211_BAND_5GHZ]->channels; + u4TblSize = wiphy->bands[NL80211_BAND_5GHZ]->n_channels; + break; + + default: + break; + } + + if (prTargetChannelEntry == NULL) { + break; + } + + for (u4Idx = 0; u4Idx < u4TblSize; u4Idx++, prTargetChannelEntry++) { + if (prTargetChannelEntry->hw_value == prChannelInfo->ucChannelNum) { + break; + } + } + + if (u4Idx == u4TblSize) { + prTargetChannelEntry = NULL; + break; + } + } while (false); + + return prTargetChannelEntry; +} + +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to set the block list of Hotspot + * + * \param[in] + * prGlueInfo + * + * \return + */ +/*----------------------------------------------------------------------------*/ +u8 kalP2PSetBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid, + IN u8 fgIsblock, IN u8 ucRoleIndex) +{ + u8 aucNullAddr[] = NULL_MAC_ADDR; + u8 fgIsValid = false; + u32 i; + + ASSERT(prGlueInfo); + /*ASSERT(prGlueInfo->prP2PInfo[ucRoleIndex]);*/ + + /*if only one ap mode register, prGlueInfo->prP2PInfo[1] would be null*/ + if (!prGlueInfo->prP2PInfo[ucRoleIndex]) { + return fgIsValid; + } + + if (fgIsblock) { + for (i = 0; i < P2P_MAXIMUM_CLIENT_COUNT; i++) { + if (UNEQUAL_MAC_ADDR(rbssid, aucNullAddr)) { + if (UNEQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo[ucRoleIndex] + ->aucblackMACList[i]), + rbssid)) { + if (EQUAL_MAC_ADDR(&(prGlueInfo->prP2PInfo[ucRoleIndex] + ->aucblackMACList[i]), + aucNullAddr)) { + COPY_MAC_ADDR(&(prGlueInfo->prP2PInfo[ucRoleIndex] + ->aucblackMACList[i]), + rbssid); + fgIsValid = false; + return fgIsValid; + } + } + } + } + } else { + for (i = 0; i < P2P_MAXIMUM_CLIENT_COUNT; i++) { + if (EQUAL_MAC_ADDR( + &(prGlueInfo->prP2PInfo[ucRoleIndex]->aucblackMACList[i]), + rbssid)) { + COPY_MAC_ADDR( + &(prGlueInfo->prP2PInfo[ucRoleIndex]->aucblackMACList[i]), + aucNullAddr); + fgIsValid = false; + return fgIsValid; + } + } + } + + return fgIsValid; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to compare the black list of Hotspot + * + * \param[in] + * prGlueInfo + * + * \return + */ +/*----------------------------------------------------------------------------*/ +u8 kalP2PCmpBlackList(IN P_GLUE_INFO_T prGlueInfo, IN PARAM_MAC_ADDRESS rbssid, + IN u8 ucRoleIndex) +{ + u8 aucNullAddr[] = NULL_MAC_ADDR; + u8 fgIsExsit = false; + u32 i; + + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo[ucRoleIndex]); + + for (i = 0; i < P2P_MAXIMUM_CLIENT_COUNT; i++) { + if (UNEQUAL_MAC_ADDR(rbssid, aucNullAddr)) { + if (EQUAL_MAC_ADDR( + &(prGlueInfo->prP2PInfo[ucRoleIndex]->aucblackMACList[i]), + rbssid)) { + fgIsExsit = true; + return fgIsExsit; + } + } + } + + return fgIsExsit; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to return the max clients of Hotspot + * + * \param[in] + * prGlueInfo + * + * \return + */ +/*----------------------------------------------------------------------------*/ +void kalP2PSetMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN u32 u4MaxClient, + IN u8 ucRoleIndex) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo[ucRoleIndex]); + + if (u4MaxClient == 0 || prGlueInfo->prP2PInfo[ucRoleIndex]->ucMaxClients >= + P2P_MAXIMUM_CLIENT_COUNT) { + prGlueInfo->prP2PInfo[ucRoleIndex]->ucMaxClients = + P2P_MAXIMUM_CLIENT_COUNT; + } else { + prGlueInfo->prP2PInfo[ucRoleIndex]->ucMaxClients = u4MaxClient; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief to return the max clients of Hotspot + * + * \param[in] + * prGlueInfo + * + * \return + */ +/*----------------------------------------------------------------------------*/ +u8 kalP2PMaxClients(IN P_GLUE_INFO_T prGlueInfo, IN u32 u4NumClient, + IN u8 ucRoleIndex) +{ + ASSERT(prGlueInfo); + ASSERT(prGlueInfo->prP2PInfo[ucRoleIndex]); + + if (prGlueInfo->prP2PInfo[ucRoleIndex]->ucMaxClients) { + if ((u8)u4NumClient > + prGlueInfo->prP2PInfo[ucRoleIndex]->ucMaxClients) { + return true; + } else { + return false; + } + } + + return false; +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_proc.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_proc.c new file mode 100644 index 00000000000000..86c68f22f91bd9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_proc.c @@ -0,0 +1,1255 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "gl_proc.c" + * \brief This file defines the interface which can interact with users in + * /proc fs. + * + * Detail description. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#include "gl_os.h" +#include "gl_kal.h" +#include "debug.h" +#include "wlan_lib.h" +#include "debug.h" +#include "wlan_oid.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define PROC_MAX_BUF_SIZE 3000 +#define PROC_MCR_ACCESS "mcr" + +#define PROC_ROOT_NAME "wlan" + +#if CFG_SUPPORT_DEBUG_FS +#define PROC_COUNTRY "country" +#endif +#define PROC_DRV_STATUS "status" +#define PROC_RX_STATISTICS "rx_statistics" +#define PROC_TX_STATISTICS "tx_statistics" +#define PROC_DBG_LEVEL_NAME "dbg_level" +#define PROC_DRIVER_CMD "driver" +#define PROC_CFG "cfg" +#define PROC_EFUSE_DUMP "efuse_dump" +#ifdef CFG_DUMP_TXPOWR_TABLE +#define PROC_GET_TXPWR_TBL "get_txpwr_tbl" +#endif + +#define PROC_MCR_ACCESS_MAX_USER_INPUT_LEN 20 +#define PROC_RX_STATISTICS_MAX_USER_INPUT_LEN 10 +#define PROC_TX_STATISTICS_MAX_USER_INPUT_LEN 10 +#define PROC_DBG_LEVEL_MAX_USER_INPUT_LEN 20 +#define PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN 30 +#define PROC_UID_SHELL 2000 +#define PROC_GID_WIFI 1010 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +static P_GLUE_INFO_T g_prGlueInfo_proc; +static u32 u4McrOffset; +static struct proc_dir_entry *gprProcRoot; +static u8 aucDbModuleName[][PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN] = { + "INIT", "HAL", "INTR", "REQ", "TX", "RX", "RFTEST", "EMU", "SW1", + "SW2", "SW3", "SW4", "HEM", "AIS", "RLM", "MEM", "CNM", "RSN", + "BSS", "SCN", "SAA", "AAA", "P2P", "QM", "SEC", "BOW", "WAPI", + "ROAMING", "TDLS", "PF", "OID", "NIC", "WNM" +}; + +/* This u32 is only for DriverCmdRead/Write, should not be used by other + * function */ +static s32 g_i4NextDriverReadLen; +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ +static ssize_t procDbgLevelRead(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + u8 *pucProcBuf = kalMemZAlloc(PROC_MAX_BUF_SIZE, VIR_MEM_TYPE); + u8 *temp = pucProcBuf; + u32 u4CopySize = 0; + u16 i; + u16 u2ModuleNum = 0; + s32 i4Pos = 0; + s32 i4Ret = 0; + + /* if *f_ops>0, we should return 0 to make cat command exit */ + if (*f_pos > 0 || buf == NULL || pucProcBuf == NULL) { + i4Ret = 0; + goto freeBuf; + } + + i4Pos = scnprintf( + temp, (PROC_MAX_BUF_SIZE - i4Pos), + "\nERROR|WARN|STATE|EVENT|TRACE|INFO|LOUD|TEMP\n" + "bit0 |bit1|bit2 |bit3 |bit4 |bit5|bit6|bit7\n\n" + "Debug Module\tIndex\tLevel\tDebug Module\tIndex\tLevel\n\n"); + + u2ModuleNum = + (sizeof(aucDbModuleName) / PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN) & + 0xfe; + for (i = 0; i < u2ModuleNum; i += 2) + i4Pos += scnprintf( + (temp + i4Pos), + (PROC_MAX_BUF_SIZE - i4Pos), + "DBG_%s_IDX\t(0x%02x):\t0x%02x\tDBG_%s_IDX\t(0x%02x):\t0x%02x\n", + &aucDbModuleName[i][0], + i, + aucDebugModule[i], + &aucDbModuleName[i + 1][0], + i + 1, + aucDebugModule[i + 1]); + + if ((sizeof(aucDbModuleName) / PROC_DBG_LEVEL_MAX_DISPLAY_STR_LEN) & + 0x1) { + i4Pos += scnprintf((temp + i4Pos), (PROC_MAX_BUF_SIZE - i4Pos), + "DBG_%s_IDX\t(0x%02x):\t0x%02x\n", + &aucDbModuleName[u2ModuleNum][0], + u2ModuleNum, aucDebugModule[u2ModuleNum]); + } + + u4CopySize = i4Pos; + if (u4CopySize > count) { + u4CopySize = count; + } + if (copy_to_user(buf, pucProcBuf, u4CopySize)) { + DBGLOG(INIT, ERROR, "copy to user failed\n"); + i4Ret = -EFAULT; + goto freeBuf; + } + + *f_pos += u4CopySize; + i4Ret = u4CopySize; +freeBuf: + if (pucProcBuf) { + kalMemFree(pucProcBuf, VIR_MEM_TYPE, PROC_MAX_BUF_SIZE); + } + return i4Ret; +} + +#if WLAN_INCLUDE_PROC +#if CFG_SUPPORT_EASY_DEBUG + +static void *procEfuseDump_start(struct seq_file *s, loff_t *pos) +{ + static unsigned long counter; + + if (*pos == 0) { + counter = *pos; /* read file init */ + + } + if (counter >= EFUSE_ADDR_MAX) { + return NULL; + } + + return &counter; +} +static void *procEfuseDump_next(struct seq_file *s, void *v, loff_t *pos) +{ + unsigned long *tmp_v = (unsigned long *)v; + + (*tmp_v) += EFUSE_BLOCK_SIZE; + + if (*tmp_v >= EFUSE_ADDR_MAX) { + return NULL; + } + + return tmp_v; +} +static void procEfuseDump_stop(struct seq_file *s, void *v) +{ + /* nothing to do, we use a static value in start() */ +} +static int procEfuseDump_show(struct seq_file *s, void *v) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + P_GLUE_INFO_T prGlueInfo; + u32 idx_addr, idx_value; + PARAM_CUSTOM_ACCESS_EFUSE_T rAccessEfuseInfo = {}; + + prGlueInfo = g_prGlueInfo_proc; + +#if (CFG_EEPROM_PAGE_ACCESS == 1) + idx_addr = *(loff_t *)v; + rAccessEfuseInfo.u4Address = + (idx_addr / EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryProcessAccessEfuseRead, + &rAccessEfuseInfo, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), true, true, + true, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + seq_printf(s, "efuse read fail (0x%03X)\n", + rAccessEfuseInfo.u4Address); + return 0; + } + + for (idx_value = 0; idx_value < EFUSE_BLOCK_SIZE; idx_value++) + seq_printf(s, "0x%03X=0x%02X\n", + rAccessEfuseInfo.u4Address + idx_value, + prGlueInfo->prAdapter->aucEepromVaule[idx_value]); + return 0; + +#else + seq_puts(s, "efuse ops is invalid\n"); + return -EPERM; /* return negative value to stop read process */ + +#endif +} +static int procEfuseDumpOpen(struct inode *inode, struct file *file) +{ + static const struct seq_operations procEfuseDump_ops = { + .start = procEfuseDump_start, + .next = procEfuseDump_next, + .stop = procEfuseDump_stop, + .show = procEfuseDump_show + }; + + return seq_open(file, &procEfuseDump_ops); +} + +static ssize_t procCfgRead(struct file *filp, char __user *buf, size_t count, + loff_t *f_pos) +{ + u8 *pucProcBuf = kalMemZAlloc(PROC_MAX_BUF_SIZE, VIR_MEM_TYPE); + u8 *temp = pucProcBuf; + u32 u4CopySize = 0; + u16 i; + s32 i4Pos = 0; + s32 i4Ret = 0; + +#define BUFFER_RESERVE_BYTE 50 + + P_GLUE_INFO_T prGlueInfo; + + P_WLAN_CFG_ENTRY_T prWlanCfgEntry; + P_ADAPTER_T prAdapter; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(gPrDev)); + + if (!prGlueInfo) { + DBGLOG(INIT, ERROR, "procCfgRead prGlueInfo is NULL\n"); + i4Ret = 0; + goto freeBuf; + } + + prAdapter = prGlueInfo->prAdapter; + + if (!prAdapter) { + DBGLOG(INIT, ERROR, "procCfgRead prAdapter is NULL\n"); + i4Ret = 0; + goto freeBuf; + } + + /* if *f_ops>0, we should return 0 to make cat command exit */ + if (*f_pos > 0 || buf == NULL || pucProcBuf == NULL) { + i4Ret = 0; + goto freeBuf; + } + + i4Pos = scnprintf(temp, (PROC_MAX_BUF_SIZE - i4Pos), + "\nDUMP CONFIGURATION :\n" + "<KEY|VALUE> OR <D:KEY|VALUE>\n" + "'D': driver part current setting\n" + "===================================\n"); + + for (i = 0; i < WLAN_CFG_ENTRY_NUM_MAX; i++) { + prWlanCfgEntry = wlanCfgGetEntryByIndex(prAdapter, i, 0); + + if ((!prWlanCfgEntry) || (prWlanCfgEntry->aucKey[0] == '\0')) { + break; + } + + i4Pos += scnprintf((temp + i4Pos), (PROC_MAX_BUF_SIZE - i4Pos), + "%s|%s\n", prWlanCfgEntry->aucKey, + prWlanCfgEntry->aucValue); + + if (i4Pos > (PROC_MAX_BUF_SIZE - BUFFER_RESERVE_BYTE)) { + break; + } + } + + for (i = 0; i < WLAN_CFG_REC_ENTRY_NUM_MAX; i++) { + prWlanCfgEntry = wlanCfgGetEntryByIndex(prAdapter, i, 1); + + if ((!prWlanCfgEntry) || (prWlanCfgEntry->aucKey[0] == '\0')) { + break; + } + + i4Pos += scnprintf((temp + i4Pos), (PROC_MAX_BUF_SIZE - i4Pos), + "D:%s|%s\n", prWlanCfgEntry->aucKey, + prWlanCfgEntry->aucValue); + + if (i4Pos > (PROC_MAX_BUF_SIZE - BUFFER_RESERVE_BYTE)) { + break; + } + } + + u4CopySize = i4Pos; + if (u4CopySize > count) { + u4CopySize = count; + } + if (copy_to_user(buf, pucProcBuf, u4CopySize)) { + DBGLOG(INIT, ERROR, "copy to user failed\n"); + i4Ret = -EFAULT; + goto freeBuf; + } + + *f_pos += u4CopySize; + i4Ret = u4CopySize; +freeBuf: + if (pucProcBuf) { + kalMemFree(pucProcBuf, VIR_MEM_TYPE, PROC_MAX_BUF_SIZE); + } + return i4Ret; +} + +static ssize_t procCfgWrite(struct file *file, const char __user *buffer, + size_t count, loff_t *data) +{ + u8 *pucProcBuf = kalMemZAlloc(PROC_MAX_BUF_SIZE, VIR_MEM_TYPE); + s32 u4CopySize = PROC_MAX_BUF_SIZE; + P_GLUE_INFO_T prGlueInfo; + u8 *pucTmp; + s32 i4Pos = 0; + s32 i4Ret = 0; + + if (count <= 0) { + DBGLOG(INIT, ERROR, "Wrong buffer size\n"); + i4Ret = -EFAULT; + goto freeBuf; + } + + if (buffer == NULL || pucProcBuf == NULL) { + i4Ret = 0; + goto freeBuf; + } + + pucTmp = pucProcBuf; + i4Pos = scnprintf(pucTmp, PROC_MAX_BUF_SIZE, "%s ", "set_cfg"); + pucTmp += i4Pos; + u4CopySize -= i4Pos; + + u4CopySize = (count < u4CopySize) ? count : (u4CopySize - 1); + + if ((u4CopySize < 0) || (copy_from_user(pucTmp, buffer, u4CopySize))) { + DBGLOG(INIT, ERROR, "error of copy from user\n"); + i4Ret = -EFAULT; + goto freeBuf; + } + pucProcBuf[u4CopySize + 8] = '\0'; + + prGlueInfo = g_prGlueInfo_proc; + /* if g_i4NextDriverReadLen >0, + * the content for next DriverCmdRead will be in : pucProcBuf with + * length : g_i4NextDriverReadLen + */ + g_i4NextDriverReadLen = priv_driver_set_cfg( + prGlueInfo->prDevHandler, pucProcBuf, kalStrLen(pucProcBuf)); + + i4Ret = u4CopySize; +freeBuf: + if (pucProcBuf) { + kalMemFree(pucProcBuf, VIR_MEM_TYPE, PROC_MAX_BUF_SIZE); + } + return i4Ret; +} + +static ssize_t procDriverCmdRead(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + return 0; +} + +static ssize_t procDriverCmdWrite(struct file *file, const char __user *buffer, + size_t count, loff_t *data) +{ + u8 *pucProcBuf = kalMemZAlloc(PROC_MAX_BUF_SIZE, VIR_MEM_TYPE); + u32 u4CopySize = PROC_MAX_BUF_SIZE; + P_GLUE_INFO_T prGlueInfo = g_prGlueInfo_proc; + s32 i4Ret = 0; + + if (buffer == NULL || pucProcBuf == NULL || prGlueInfo == NULL) { + i4Ret = 0; + goto freeBuf; + } + + u4CopySize = (count < u4CopySize) ? count : (u4CopySize - 1); + + if (copy_from_user(pucProcBuf, buffer, u4CopySize)) { + DBGLOG(INIT, ERROR, "error of copy from user\n"); + i4Ret = -EFAULT; + goto freeBuf; + } + pucProcBuf[u4CopySize] = '\0'; + + if (kalStrLen(pucProcBuf) > 0) { + priv_driver_cmds(prGlueInfo->prDevHandler, pucProcBuf, + kalStrLen(pucProcBuf)); + } + + i4Ret = u4CopySize; +freeBuf: + if (pucProcBuf) { + kalMemFree(pucProcBuf, VIR_MEM_TYPE, PROC_MAX_BUF_SIZE); + } + return i4Ret; +} + +#endif +#endif + +static ssize_t procDbgLevelWrite(struct file *file, const char __user *buffer, + size_t count, loff_t *data) +{ + u32 u4NewDbgModule, u4NewDbgLevel; + u8 *pucProcBuf = kalMemZAlloc(PROC_MAX_BUF_SIZE, VIR_MEM_TYPE); + u8 *temp = NULL; + u32 u4CopySize = PROC_MAX_BUF_SIZE; + s32 i4Ret = 0; + + if (buffer == NULL || pucProcBuf == NULL) { + i4Ret = 0; + goto freeBuf; + } + + temp = pucProcBuf; + u4CopySize = (count < u4CopySize) ? count : (u4CopySize - 1); + + if (copy_from_user(pucProcBuf, buffer, u4CopySize)) { + DBGLOG(INIT, ERROR, "error of copy from user\n"); + i4Ret = -EFAULT; + goto freeBuf; + } + pucProcBuf[u4CopySize] = '\0'; + + while (temp) { + if (sscanf(temp, "0x%x:0x%x", &u4NewDbgModule, + &u4NewDbgLevel) != 2) { + DBGLOG(INIT, + ERROR, + "debug module and debug level should be one byte in length\n"); + break; + } + if (u4NewDbgModule == 0xFF) { + u8 i = 0; + + for (; i < DBG_MODULE_NUM; i++) + aucDebugModule[i] = u4NewDbgLevel & + DBG_CLASS_MASK; + + break; + } + if (u4NewDbgModule >= DBG_MODULE_NUM) { + DBGLOG(INIT, ERROR, + "debug module index should less than %d\n", + DBG_MODULE_NUM); + break; + } + aucDebugModule[u4NewDbgModule] = u4NewDbgLevel & DBG_CLASS_MASK; + temp = kalStrChr(temp, ','); + if (!temp) { + break; + } + temp++; /* skip ',' */ + } + + i4Ret = u4CopySize; +freeBuf: + if (pucProcBuf) { + kalMemFree(pucProcBuf, VIR_MEM_TYPE, PROC_MAX_BUF_SIZE); + } + return i4Ret; +} + +#ifdef CFG_DUMP_TXPOWR_TABLE +#define TXPWR_TABLE_ENTRY(_siso_mcs, _cdd_mcs, _mimo_mcs, _idx) \ + { \ + .mcs[STREAM_SISO] = _siso_mcs, .mcs[STREAM_CDD] = _cdd_mcs, \ + .mcs[STREAM_MIMO] = _mimo_mcs, .idx = (_idx), \ + } + +static struct txpwr_table_entry dsss[] = { + TXPWR_TABLE_ENTRY("DSSS1", "", "", PWR_DSSS_CCK), + TXPWR_TABLE_ENTRY("DSSS2", "", "", PWR_DSSS_CCK), + TXPWR_TABLE_ENTRY("CCK5", "", "", PWR_DSSS_BPKS), + TXPWR_TABLE_ENTRY("CCK11", "", "", PWR_DSSS_BPKS), +}; + +static struct txpwr_table_entry ofdm[] = { + TXPWR_TABLE_ENTRY("OFDM6", "OFDM6", "", PWR_OFDM_BPSK), + TXPWR_TABLE_ENTRY("OFDM9", "OFDM9", "", PWR_OFDM_BPSK), + TXPWR_TABLE_ENTRY("OFDM12", "OFDM12", "", PWR_OFDM_QPSK), + TXPWR_TABLE_ENTRY("OFDM18", "OFDM18", "", PWR_OFDM_QPSK), + TXPWR_TABLE_ENTRY("OFDM24", "OFDM24", "", PWR_OFDM_16QAM), + TXPWR_TABLE_ENTRY("OFDM36", "OFDM36", "", PWR_OFDM_16QAM), + TXPWR_TABLE_ENTRY("OFDM48", "OFDM48", "", PWR_OFDM_48Mbps), + TXPWR_TABLE_ENTRY("OFDM54", "OFDM54", "", PWR_OFDM_54Mbps), +}; + +static struct txpwr_table_entry ht[] = { + TXPWR_TABLE_ENTRY("MCS0", "MCS0", "MCS8", PWR_HT_BPSK), + TXPWR_TABLE_ENTRY("MCS1", "MCS1", "MCS9", PWR_HT_QPSK), + TXPWR_TABLE_ENTRY("MCS2", "MCS2", "MCS10", PWR_HT_QPSK), + TXPWR_TABLE_ENTRY("MCS3", "MCS3", "MCS11", PWR_HT_16QAM), + TXPWR_TABLE_ENTRY("MCS4", "MCS4", "MCS12", PWR_HT_16QAM), + TXPWR_TABLE_ENTRY("MCS5", "MCS5", "MCS13", PWR_HT_MCS5), + TXPWR_TABLE_ENTRY("MCS6", "MCS6", "MCS14", PWR_HT_MCS6), + TXPWR_TABLE_ENTRY("MCS7", "MCS7", "MCS15", PWR_HT_MCS7), +}; + +static struct txpwr_table_entry vht[] = { + TXPWR_TABLE_ENTRY("MCS0", "MCS0", "MCS0", PWR_VHT20_BPSK), + TXPWR_TABLE_ENTRY("MCS1", "MCS1", "MCS1", PWR_VHT20_QPSK), + TXPWR_TABLE_ENTRY("MCS2", "MCS2", "MCS2", PWR_VHT20_QPSK), + TXPWR_TABLE_ENTRY("MCS3", "MCS3", "MCS3", PWR_VHT20_16QAM), + TXPWR_TABLE_ENTRY("MCS4", "MCS4", "MCS4", PWR_VHT20_16QAM), + TXPWR_TABLE_ENTRY("MCS5", "MCS5", "MCS5", PWR_VHT20_64QAM), + TXPWR_TABLE_ENTRY("MCS6", "MCS6", "MCS6", PWR_VHT20_64QAM), + TXPWR_TABLE_ENTRY("MCS7", "MCS7", "MCS7", PWR_VHT20_MCS7), + TXPWR_TABLE_ENTRY("MCS8", "MCS8", "MCS8", PWR_VHT20_MCS8), + TXPWR_TABLE_ENTRY("MCS9", "MCS9", "MCS9", PWR_VHT20_MCS9), +}; + +static struct txpwr_table txpwr_tables[] = { + { "Legacy", dsss, ARRAY_SIZE(dsss) }, { "11g", ofdm, ARRAY_SIZE(ofdm) }, + { "11a", ofdm, ARRAY_SIZE(ofdm) }, { "HT20", ht, ARRAY_SIZE(ht) }, + { "HT40", ht, ARRAY_SIZE(ht) }, { "VHT20", vht, ARRAY_SIZE(vht) }, + { "VHT40", vht, ARRAY_SIZE(vht) }, { "VHT80", vht, ARRAY_SIZE(vht) }, +}; + +#define TMP_SZ (512) +#define CDD_PWR_OFFSET (6) +#define TXPWR_DUMP_SZ (8192) +static void print_txpwr_tbl(struct txpwr_table *txpwr_tbl, unsigned char ch, + unsigned char fe_loss, unsigned char *tx_pwr[], + char pwr_offset[], char *stream_buf[], + unsigned int stream_pos[]) +{ + struct txpwr_table_entry *tmp_tbl = txpwr_tbl->tables; + unsigned int idx, pwr_idx, stream_idx; + signed char pwr[TXPWR_TBL_NUM] = { 0 }, tmp_pwr = 0; + char prefix[5], tmp[4]; + char *buf = NULL; + unsigned int *pos = NULL; + int i; + + for (i = 0; i < txpwr_tbl->n_tables; i++) { + idx = tmp_tbl[i].idx; + + for (pwr_idx = 0; pwr_idx < TXPWR_TBL_NUM; pwr_idx++) { + if (!tx_pwr[pwr_idx]) { + DBGLOG(REQ, WARN, "Power table[%d] is NULL\n", + pwr_idx); + return; + } + pwr[pwr_idx] = + tx_pwr[pwr_idx][idx] + pwr_offset[pwr_idx]; + pwr[pwr_idx] = (pwr[pwr_idx] > MAX_TX_POWER) ? + MAX_TX_POWER : + pwr[pwr_idx]; + } + + for (stream_idx = 0; stream_idx < STREAM_NUM; stream_idx++) { + buf = stream_buf[stream_idx]; + pos = &stream_pos[stream_idx]; + + if (tmp_tbl[i].mcs[stream_idx][0] == '\0') { + continue; + } + + switch (stream_idx) { + case STREAM_SISO: + kalStrnCpy(prefix, "siso", sizeof(prefix)); + break; + + case STREAM_CDD: + kalStrnCpy(prefix, "cdd", sizeof(prefix)); + break; + + case STREAM_MIMO: + kalStrnCpy(prefix, "mimo", sizeof(prefix)); + break; + } + + *pos += kalScnprintf(buf + *pos, TMP_SZ - *pos, + "%s, %d, %s, %s, ", prefix, ch, + txpwr_tbl->phy_mode, + tmp_tbl[i].mcs[stream_idx]); + + for (pwr_idx = 0; pwr_idx < TXPWR_TBL_NUM; pwr_idx++) { + tmp_pwr = pwr[pwr_idx]; + + tmp_pwr = (tmp_pwr > 0) ? tmp_pwr : 0; + + if (pwr_idx + 1 == TXPWR_TBL_NUM) { + kalStrnCpy(tmp, "\n", sizeof(tmp)); + }else{ + kalStrnCpy(tmp, ", ", sizeof(tmp)); + } + *pos += kalScnprintf(buf + *pos, TMP_SZ - *pos, + "%d.%d%s", tmp_pwr / 2, + tmp_pwr % 2 * 5, tmp); + + /* print power limit with front-end loss */ + if (pwr_idx == LIMIT_TBL) { + tmp_pwr += fe_loss; + tmp_pwr = (tmp_pwr > MAX_TX_POWER) ? + MAX_TX_POWER : + tmp_pwr; + *pos += kalScnprintf( + buf + *pos, TMP_SZ - *pos, + "%d.%d%s", tmp_pwr / 2, + tmp_pwr % 2 * 5, tmp); + } + } + } + } +} + +char *g_txpwr_tbl_read_buffer = NULL; +unsigned int g_txpwr_tbl_read_residual = 0; + +static ssize_t procGetTxpwrTblRead(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + P_BSS_INFO_T prBssInfo = NULL; + unsigned char ucBssIndex; + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = NULL; + WLAN_STATUS status; + struct PARAM_CMD_GET_TXPWR_TBL pwr_tbl; + struct POWER_LIMIT *tx_pwr_tbl = pwr_tbl.tx_pwr_tbl; + char *buffer; + unsigned int pos = 0, buf_len = TXPWR_DUMP_SZ, oid_len; + unsigned char i, j; + char *stream_buf[STREAM_NUM] = { NULL }; + unsigned int stream_pos[STREAM_NUM] = { 0 }; + unsigned char *tx_pwr[TXPWR_TBL_NUM] = { NULL }; + char pwr_offset[TXPWR_TBL_NUM] = { 0 }; + unsigned char offset = 0; + int ret; + + if (*f_pos > 0) { /* re-entry */ + pos = g_txpwr_tbl_read_residual; + buffer = g_txpwr_tbl_read_buffer; + goto next_entry; + } + + prGlueInfo = g_prGlueInfo_proc; + if (!prGlueInfo) { + return -EFAULT; + } + + prAdapter = prGlueInfo->prAdapter; + prNetDevPrivate = (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(gPrDev); + if (prNetDevPrivate->prGlueInfo != prGlueInfo) { + return -EFAULT; + } + + ucBssIndex = prNetDevPrivate->ucBssIdx; + prBssInfo = prAdapter->aprBssInfo[ucBssIndex]; + if (!prBssInfo) { + return -EFAULT; + } + + kalMemZero(&pwr_tbl, sizeof(pwr_tbl)); + +#if CFG_SUPPORT_DBDC + if (prAdapter->rWifiVar.fgDbDcModeEn) { + pwr_tbl.ucDbdcIdx = prBssInfo->eDBDCBand; + } else +#endif + pwr_tbl.ucDbdcIdx = ENUM_BAND_0; + + + status = kalIoctl(prGlueInfo, wlanoidGetTxPwrTbl, &pwr_tbl, + sizeof(pwr_tbl), true, false, true, &oid_len); + + if (status != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "Query Tx Power Table fail\n"); + return -EINVAL; + } + + buffer = (char *)kalMemAlloc(buf_len, VIR_MEM_TYPE); + if (!buffer) { + return -ENOMEM; + } + + g_txpwr_tbl_read_buffer = buffer; + + for (i = 0; i < STREAM_NUM; i++) { + stream_buf[i] = (char *)kalMemAlloc(TMP_SZ, VIR_MEM_TYPE); + if (!stream_buf[i]) { + ret = -ENOMEM; + goto out; + } + } + + pos = kalScnprintf(buffer, buf_len, "\n%s", + "spatial_stream, channel, bw, modulation, "); + pos += kalScnprintf( + buffer + pos, buf_len - pos, "%s", + "regulatory_limit, regulatory_limit_with_fe_loss, "); + pos += kalScnprintf(buffer + pos, buf_len - pos, "%s\n", + "board_limit, target_power"); + + for (i = 0; i < ARRAY_SIZE(txpwr_tables); i++) { + for (j = 0; j < STREAM_NUM; j++) { + kalMemZero(stream_buf[j], TMP_SZ); + stream_pos[j] = 0; + } + + for (j = 0; j < TXPWR_TBL_NUM; j++) { + tx_pwr[j] = NULL; + pwr_offset[j] = 0; + } + + switch (i) { + case DSSS: + if (pwr_tbl.ucCenterCh > 14) { + continue; + } + for (j = 0; j < TXPWR_TBL_NUM; j++) + tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_dsss; + break; + + case OFDM_24G: + if (pwr_tbl.ucCenterCh > 14) { + continue; + } + for (j = 0; j < TXPWR_TBL_NUM; j++) + tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_ofdm; + break; + + case OFDM_5G: + if (pwr_tbl.ucCenterCh <= 14) { + continue; + } + for (j = 0; j < TXPWR_TBL_NUM; j++) + tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_ofdm; + break; + + case HT20: + for (j = 0; j < TXPWR_TBL_NUM; j++) + tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_ht20; + break; + + case HT40: + for (j = 0; j < TXPWR_TBL_NUM; j++) + tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_ht40; + break; + + case VHT20: + if (pwr_tbl.ucCenterCh <= 14) { + continue; + } + for (j = 0; j < TXPWR_TBL_NUM; j++) + tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_vht20; + break; + + case VHT40: + case VHT80: + if (pwr_tbl.ucCenterCh <= 14) { + continue; + } + offset = (i == VHT40) ? PWR_Vht40_OFFSET : + PWR_Vht80_OFFSET; + for (j = 0; j < TXPWR_TBL_NUM; j++) { + tx_pwr[j] = tx_pwr_tbl[j].tx_pwr_vht20; + pwr_offset[j] = + tx_pwr_tbl[j].tx_pwr_vht_OFST[offset]; + /* Covert 7bit 2'complement value to 8bit */ + pwr_offset[j] |= + (pwr_offset[j] & BIT(6)) ? BIT(7) : 0; + } + break; + + default: + break; + } + + print_txpwr_tbl(&txpwr_tables[i], pwr_tbl.ucCenterCh, + pwr_tbl.ucFeLoss, tx_pwr, pwr_offset, + stream_buf, stream_pos); + + for (j = 0; j < STREAM_NUM; j++) + pos += kalScnprintf(buffer + pos, buf_len - pos, "%s", + stream_buf[j]); + } + g_txpwr_tbl_read_residual = pos; + +next_entry: + if (pos > count) { + pos = count; + } + if (copy_to_user(buf, buffer, pos)) { + DBGLOG(INIT, ERROR, "copy to user failed\n"); + ret = -EFAULT; + goto out; + } + g_txpwr_tbl_read_buffer += pos; + g_txpwr_tbl_read_residual -= pos; + *f_pos += pos; + ret = pos; +out: + if (ret == 0 || ret == -ENOMEM) { + for (i = 0; i < STREAM_NUM; i++) + if (stream_buf[i]) { + kalMemFree(stream_buf[i], VIR_MEM_TYPE, TMP_SZ); + } + if (buffer) { + kalMemFree(buffer, VIR_MEM_TYPE, buf_len); + } + g_txpwr_tbl_read_buffer = NULL; + g_txpwr_tbl_read_residual = 0; + } + return ret; +} +#endif + +#if KERNEL_VERSION(5, 6, 0) <= LINUX_VERSION_CODE +static const struct proc_ops dbglevel_ops = { + .proc_read = procDbgLevelRead, + .proc_write = procDbgLevelWrite, +}; + +#if WLAN_INCLUDE_PROC +#if CFG_SUPPORT_EASY_DEBUG +static const struct proc_ops efusedump_ops = { + .proc_open = procEfuseDumpOpen, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = seq_release, +}; + +static const struct proc_ops drivercmd_ops = { + .proc_read = procDriverCmdRead, + .proc_write = procDriverCmdWrite, +}; + +static const struct proc_ops cfg_ops = { + .proc_read = procCfgRead, + .proc_write = procCfgWrite, +}; +#endif +#endif + +#ifdef CFG_DUMP_TXPOWR_TABLE +static const struct proc_ops get_txpwr_tbl_ops = { + .proc_read = procGetTxpwrTblRead, +}; +#endif +#else + +static const struct file_operations dbglevel_ops = { + .owner = THIS_MODULE, + .read = procDbgLevelRead, + .write = procDbgLevelWrite, +}; + +#if WLAN_INCLUDE_PROC +#if CFG_SUPPORT_EASY_DEBUG + +static const struct file_operations efusedump_ops = { + .owner = THIS_MODULE, + .open = procEfuseDumpOpen, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static const struct file_operations drivercmd_ops = { + .owner = THIS_MODULE, + .read = procDriverCmdRead, + .write = procDriverCmdWrite, +}; + +static const struct file_operations cfg_ops = { + .owner = THIS_MODULE, + .read = procCfgRead, + .write = procCfgWrite, +}; +#endif +#endif + +#ifdef CFG_DUMP_TXPOWR_TABLE +static const struct file_operations get_txpwr_tbl_ops = { + .owner = THIS_MODULE, + .read = procGetTxpwrTblRead, +}; +#endif +#endif + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief The PROC function for reading MCR register to User Space, the offset + * of the MCR is specified in u4McrOffset. + * + * \param[in] page Buffer provided by kernel. + * \param[in out] start Start Address to read(3 methods). + * \param[in] off Offset. + * \param[in] count Allowable number to read. + * \param[out] eof End of File indication. + * \param[in] data Pointer to the private data structure. + * + * \return number of characters print to the buffer from User Space. + */ +/*----------------------------------------------------------------------------*/ +static ssize_t procMCRRead(struct file *filp, char __user *buf, size_t count, + loff_t *f_pos) +{ + u8 *pucProcBuf = kalMemZAlloc(PROC_MAX_BUF_SIZE, VIR_MEM_TYPE); + P_GLUE_INFO_T prGlueInfo; + PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; + u32 u4BufLen; + u32 u4CopySize = 0; + u8 *temp = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + s32 i4Ret = 0; + + /*if *f_ops>0, we should return 0 to make cat command exit*/ + if (*f_pos > 0 || buf == NULL || pucProcBuf == NULL) { + i4Ret = 0; + goto freeBuf; + } + + temp = pucProcBuf; + prGlueInfo = g_prGlueInfo_proc; + + rMcrInfo.u4McrOffset = u4McrOffset; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryMcrRead, (void *)&rMcrInfo, + sizeof(rMcrInfo), true, true, true, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, ERROR, "[%s] kalIoctl failed\n", __func__); + i4Ret = -EFAULT; + goto freeBuf; + } + + u4CopySize = scnprintf(temp, PROC_MAX_BUF_SIZE - kalStrLen(pucProcBuf), + "MCR (0x%08xh): 0x%08x\n", rMcrInfo.u4McrOffset, + rMcrInfo.u4McrData); + + if (u4CopySize > count) { + u4CopySize = count; + } + + if (copy_to_user(buf, pucProcBuf, u4CopySize)) { + DBGLOG(INIT, ERROR, "copy to user failed\n"); + i4Ret = -EFAULT; + goto freeBuf; + } + + *f_pos += u4CopySize; + i4Ret = u4CopySize; +freeBuf: + if (pucProcBuf) { + kalMemFree(pucProcBuf, VIR_MEM_TYPE, PROC_MAX_BUF_SIZE); + } + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief The PROC function for writing MCR register to HW or update u4McrOffset + * for reading MCR later. + * + * \param[in] file pointer to file. + * \param[in] buffer Buffer from user space. + * \param[in] count Number of characters to write + * \param[in] data Pointer to the private data structure. + * + * \return number of characters write from User Space. + */ +/*----------------------------------------------------------------------------*/ +static ssize_t procMCRWrite(struct file *file, const char __user *buffer, + size_t count, loff_t *data) +{ + P_GLUE_INFO_T prGlueInfo; + char acBuf[PROC_MCR_ACCESS_MAX_USER_INPUT_LEN + 1]; /* + 1 for "\0" */ + u32 u4CopySize = 0; + PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; + u32 u4BufLen; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + int num = 0; + + ASSERT(data); + + u4CopySize = (count < sizeof(acBuf)) ? count : (sizeof(acBuf) - 1); + if (copy_from_user(acBuf, buffer, u4CopySize)) { + DBGLOG(INIT, ERROR, "error of copy from user\n"); + return -EFAULT; + } + acBuf[u4CopySize] = '\0'; + + num = sscanf(acBuf, "0x%x 0x%x", &rMcrInfo.u4McrOffset, + &rMcrInfo.u4McrData); + switch (num) { + case 2: + /* NOTE: Sometimes we want to test if bus will still be ok, + * after accessing the MCR which is not align to DW boundary. + */ + /* if (IS_ALIGN_4(rMcrInfo.u4McrOffset)) */ + { + prGlueInfo = g_prGlueInfo_proc; + u4McrOffset = rMcrInfo.u4McrOffset; + + /* rMcrInfo.u4McrOffset, rMcrInfo.u4McrData); */ + + rStatus = kalIoctl(prGlueInfo, wlanoidSetMcrWrite, + (void *)&rMcrInfo, sizeof(rMcrInfo), + false, false, true, &u4BufLen); + } + break; + + case 1: + /* if (IS_ALIGN_4(rMcrInfo.u4McrOffset)) */ + { + u4McrOffset = rMcrInfo.u4McrOffset; + } + break; + + default: + break; + } + + return u4CopySize; +} + +#if KERNEL_VERSION(5, 6, 0) <= LINUX_VERSION_CODE +static const struct proc_ops mcr_ops = { + .proc_read = procMCRRead, + .proc_write = procMCRWrite, +}; +#else +static const struct file_operations mcr_ops = { + .owner = THIS_MODULE, + .read = procMCRRead, + .write = procMCRWrite, +}; +#endif + +#if CFG_SUPPORT_DEBUG_FS +static ssize_t procCountryRead(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + u8 *pucProcBuf = kalMemZAlloc(PROC_MAX_BUF_SIZE, VIR_MEM_TYPE); + u32 u4CopySize; + u32 country = 0; + s32 i4Ret = 0; + + /* if *f_pos > 0, it means has read successed last time, don't try again + */ + if (*f_pos > 0 || buf == NULL || pucProcBuf == NULL) { + i4Ret = 0; + goto freeBuf; + } + if (!regd_is_single_sku_en()) { + kalStrCpy(pucProcBuf, + "Country Code is controlled by Local DB\n"); + } + + country = rlmDomainGetCountryCode(); + + if (country) { + kalSprintf(pucProcBuf, "Current Country Code: %s\n", &country); + }else{ + kalStrCpy(pucProcBuf, "Current Country Code: NULL\n"); + } + + u4CopySize = kalStrLen(pucProcBuf); + + if (u4CopySize > count) { + u4CopySize = count; + } + + if (copy_to_user(buf, pucProcBuf, u4CopySize)) { + DBGLOG(INIT, ERROR, "copy to user failed\n"); + i4Ret = -EFAULT; + goto freeBuf; + } + *f_pos += u4CopySize; + i4Ret = u4CopySize; +freeBuf: + if (pucProcBuf) { + kalMemFree(pucProcBuf, VIR_MEM_TYPE, PROC_MAX_BUF_SIZE); + } + return i4Ret; +} + +#if KERNEL_VERSION(5, 6, 0) <= LINUX_VERSION_CODE +static const struct proc_ops country_ops = { + .proc_read = procCountryRead, +}; +#else +static const struct file_operations country_ops = { + .owner = THIS_MODULE, + .read = procCountryRead, +}; +#endif +#endif + +s32 procInitFs(void) +{ + g_i4NextDriverReadLen = 0; + + if (init_net.proc_net == (struct proc_dir_entry *)NULL) { + DBGLOG(INIT, ERROR, "init proc fs fail: proc_net == NULL\n"); + return -ENOENT; + } + + /* + * Directory: Root (/proc/net/wlan0) + */ + + gprProcRoot = proc_mkdir(PROC_ROOT_NAME, init_net.proc_net); + if (!gprProcRoot) { + DBGLOG(INIT, ERROR, "gprProcRoot == NULL\n"); + return -ENOENT; + } + proc_set_user(gprProcRoot, KUIDT_INIT(PROC_UID_SHELL), + KGIDT_INIT(PROC_GID_WIFI)); + + return 0; +} + +s32 procUninitProcFs(void) +{ + remove_proc_subtree(PROC_ROOT_NAME, init_net.proc_net); + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function clean up a PROC fs created by procInitProcfs(). + * + * \param[in] prDev Pointer to the struct net_device. + * \param[in] pucDevName Pointer to the name of net_device. + * + * \return N/A + */ +/*----------------------------------------------------------------------------*/ +s32 procRemoveProcfs(void) +{ + remove_proc_entry(PROC_MCR_ACCESS, gprProcRoot); + remove_proc_entry(PROC_DRIVER_CMD, gprProcRoot); + remove_proc_entry(PROC_DBG_LEVEL_NAME, gprProcRoot); + remove_proc_entry(PROC_CFG, gprProcRoot); + remove_proc_entry(PROC_EFUSE_DUMP, gprProcRoot); +#ifdef CFG_DUMP_TXPOWR_TABLE + remove_proc_entry(PROC_GET_TXPWR_TBL, gprProcRoot); +#endif +#if CFG_SUPPORT_DEBUG_FS + remove_proc_entry(PROC_COUNTRY, gprProcRoot); +#endif + + return 0; +} + +s32 procCreateFsEntry(P_GLUE_INFO_T prGlueInfo) +{ + struct proc_dir_entry *prEntry; + + DBGLOG(INIT, INFO, "[%s]\n", __func__); + g_prGlueInfo_proc = prGlueInfo; + + prEntry = proc_create(PROC_MCR_ACCESS, 0664, gprProcRoot, &mcr_ops); + if (prEntry == NULL) { + DBGLOG(INIT, ERROR, "Unable to create /proc entry\n\r"); + return -1; + } +#if CFG_SUPPORT_DEBUG_FS + prEntry = proc_create(PROC_COUNTRY, 0664, gprProcRoot, &country_ops); + if (prEntry == NULL) { + DBGLOG(INIT, ERROR, "Unable to create /proc entry\n\r"); + return -1; + } +#endif +#if WLAN_INCLUDE_PROC +#if CFG_SUPPORT_EASY_DEBUG + prEntry = + proc_create(PROC_DRIVER_CMD, 0664, gprProcRoot, &drivercmd_ops); + if (prEntry == NULL) { + DBGLOG(INIT, ERROR, + "Unable to create /proc entry for driver command\n\r"); + return -1; + } + + prEntry = proc_create(PROC_CFG, 0664, gprProcRoot, &cfg_ops); + if (prEntry == NULL) { + DBGLOG(INIT, ERROR, + "Unable to create /proc entry for driver command\n\r"); + return -1; + } + + prEntry = + proc_create(PROC_EFUSE_DUMP, 0664, gprProcRoot, &efusedump_ops); + if (prEntry == NULL) { + DBGLOG(INIT, ERROR, "Unable to create /proc entry efuse\n\r"); + return -1; + } +#endif +#endif + +#ifdef CFG_DUMP_TXPOWR_TABLE + prEntry = proc_create(PROC_GET_TXPWR_TBL, 0664, gprProcRoot, + &get_txpwr_tbl_ops); + if (prEntry == NULL) { + DBGLOG(INIT, ERROR, "Unable to create /proc entry efuse\n\r"); + return -1; + } +#endif + + prEntry = proc_create(PROC_DBG_LEVEL_NAME, 0664, gprProcRoot, + &dbglevel_ops); + if (prEntry == NULL) { + DBGLOG(INIT, ERROR, + "Unable to create /proc entry dbgLevel\n\r"); + return -1; + } + + return 0; +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_qa_agent.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_qa_agent.c new file mode 100644 index 00000000000000..ef296dc0db831f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_qa_agent.c @@ -0,0 +1,8517 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ +/* + * Module Name: + * gl_ate_agent.c + */ +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#if (CFG_SUPPORT_QA_TOOL == 1) +#include "gl_wext.h" +#include "gl_cfg80211.h" +#include "gl_ate_agent.h" +#include "gl_qa_agent.h" +#include "gl_hook_api.h" +#include <uapi/linux/nl80211.h> + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +PARAM_RX_STAT_T g_HqaRxStat; +u32 u4RxStatSeqNum; +u8 g_DBDCEnable = false; +/* For SA Buffer Mode Temp Solution */ +u8 g_BufferDownload = false; +u32 u4EepromMode = 4; +u32 g_u4Chip_ID; +u8 g_ucEepromCurrentMode = EFUSE_MODE; + +#if CFG_SUPPORT_BUFFER_MODE +u8 uacEEPROMImage[MAX_EEPROM_BUFFER_SIZE] = { + /* 0x000 ~ 0x00F */ + 0xAE, 0x86, 0x06, 0x00, 0x18, 0x0D, 0x00, 0x00, 0xC0, 0x1F, 0xBD, 0x81, + 0x3F, 0x01, 0x19, 0x00, + /* 0x010 ~ 0x01F */ + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, + /* 0x020 ~ 0x02F */ + 0x80, 0x02, 0x00, 0x00, 0x32, 0x66, 0xC3, 0x14, 0x32, 0x66, 0xC3, 0x14, + 0x03, 0x22, 0xFF, 0xFF, + /* 0x030 ~ 0x03F */ + 0x23, 0x04, 0x0D, 0xF2, 0x8F, 0x02, 0x00, 0x80, 0x0A, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x040 ~ 0x04F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x40, 0x00, 0x00, + /* 0x050 ~ 0x05F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x08, + /* 0x060 ~ 0x06F */ + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x08, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x08, + /* 0x070 ~ 0x07F */ + 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x080 ~ 0x08F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x090 ~ 0x09F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x0A0 ~ 0x0AF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x0B0 ~ 0x0BF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x10, 0x10, 0x28, + 0x00, 0x00, 0x00, 0x00, + /* 0x0C0 ~ 0x0CF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x0D0 ~ 0x0DF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x0E0 ~ 0x0EF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x0F0 ~ 0x0FF */ + 0x0E, 0x05, 0x06, 0x06, 0x06, 0x0F, 0x00, 0x00, 0x0E, 0x05, 0x06, 0x05, + 0x05, 0x09, 0xFF, 0x00, + /* 0x100 ~ 0x10F */ + 0x12, 0x34, 0x56, 0x78, 0x2C, 0x2C, 0x28, 0x28, 0x28, 0x26, 0x26, 0x28, + 0x28, 0x28, 0x26, 0xFF, + /* 0x110 ~ 0x11F */ + 0x26, 0x25, 0x28, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x27, 0x27, 0x25, + /* 0x120 ~ 0x12F */ + 0x25, 0x25, 0x25, 0x25, 0x23, 0x23, 0x23, 0x21, 0x00, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x00, + /* 0x130 ~ 0x13F */ + 0x40, 0x40, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, + /* 0x140 ~ 0x14F */ + 0x25, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x150 ~ 0x15F */ + 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xD0, + 0xD0, 0xD0, 0xD0, 0xD0, + /* 0x160 ~ 0x16F */ + 0xD0, 0xD0, 0xD0, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x170 ~ 0x17F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC2, 0xC4, 0xC5, 0xC8, + /* 0x180 ~ 0x18F */ + 0x00, 0x26, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x190 ~ 0x19F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x1A0 ~ 0x1AF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0xD0, 0xD0, 0x0E, 0x05, 0x06, + 0x05, 0x09, 0x0E, 0x00, + /* 0x1B0 ~ 0x1BF */ + 0x05, 0x06, 0x05, 0x05, 0x09, 0x00, 0x00, 0x00, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, + /* 0x1C0 ~ 0x1CF */ + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x00, 0x00, + /* 0x1D0 ~ 0x1DF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x1E0 ~ 0x1EF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x1F0 ~ 0x1FF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x200 ~ 0x20F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x210 ~ 0x21F */ + 0x48, 0xF5, 0x27, 0x49, 0x48, 0xF5, 0x57, 0x12, 0x4B, 0x71, 0x80, 0x50, + 0x91, 0xF6, 0x87, 0x50, + /* 0x220 ~ 0x22F */ + 0x7D, 0x29, 0x09, 0x42, 0x7D, 0x29, 0x41, 0x44, 0x7D, 0x29, 0x41, 0x3C, + 0x7D, 0x29, 0x31, 0x4D, + /* 0x230 ~ 0x23F */ + 0x49, 0x71, 0x24, 0x49, 0x49, 0x71, 0x54, 0x12, 0x4B, 0x71, 0x80, 0x50, + 0x91, 0xF6, 0x87, 0x50, + /* 0x240 ~ 0x24F */ + 0x7D, 0x29, 0x09, 0x42, 0x7D, 0x29, 0x41, 0x04, 0x7D, 0x29, 0x41, 0x04, + 0x7D, 0x29, 0x01, 0x40, + /* 0x250 ~ 0x25F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x260 ~ 0x26F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x270 ~ 0x27F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x280 ~ 0x28F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x290 ~ 0x29F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x2A0 ~ 0x2AF */ + 0x7D, 0x29, 0xC9, 0x16, 0x7D, 0x29, 0xC9, 0x16, 0x44, 0x22, 0x32, 0x15, + 0xEE, 0xEE, 0xEE, 0x08, + /* 0x2B0 ~ 0x2BF */ + 0x78, 0x90, 0x79, 0x1C, 0x78, 0x90, 0x79, 0x1C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x2C0 ~ 0x2CF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x2D0 ~ 0x2DF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x2E0 ~ 0x2EF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x2F0 ~ 0x2FF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x300 ~ 0x30F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x310 ~ 0x31F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x42, + 0x10, 0x42, 0x08, 0x21, + /* 0x320 ~ 0x32F */ + 0x10, 0x42, 0x08, 0x21, 0x10, 0x42, 0x08, 0x21, 0x10, 0x42, 0x08, 0x21, + 0x10, 0x42, 0x08, 0x21, + /* 0x330 ~ 0x33F */ + 0x10, 0x42, 0x08, 0x21, 0x10, 0x42, 0x08, 0x21, 0x10, 0x42, 0x08, 0x21, + 0x10, 0x42, 0x08, 0x21, + /* 0x340 ~ 0x34F */ + 0x10, 0x42, 0x08, 0x21, 0x10, 0x42, 0x08, 0x21, 0x10, 0x42, 0x08, 0x21, + 0x10, 0x42, 0x08, 0x01, + /* 0x350 ~ 0x35F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x360 ~ 0x36F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x370 ~ 0x37F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x380 ~ 0x38F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x390 ~ 0x39F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x3A0 ~ 0x3AF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x3B0 ~ 0x3BF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x3C0 ~ 0x3CF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x3D0 ~ 0x3DF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x3E0 ~ 0x3EF */ + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, + /* 0x3F0 ~ 0x3FF */ + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, + /* 0x400 ~ 0x40F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x410 ~ 0x41F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x420 ~ 0x42F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x430 ~ 0x43F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x440 ~ 0x44F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x450 ~ 0x45F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x460 ~ 0x46F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x470 ~ 0x47F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x480 ~ 0x48F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x490 ~ 0x49F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* 0x4A0 ~ 0x4AF */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Response ACK to QA Tool DLL. + * + * \param[in] HqaCmdFrame Ethernet Frame Format respond to QA Tool DLL + * \param[in] prIwReqData + * \param[in] i4Length Length of Ethernet Frame data field + * \param[in] i4Status Status to respond + * \param[out] None + * + * \retval 0 On success. + * \retval -EFAULT If copy_to_user fail + */ +/*----------------------------------------------------------------------------*/ +static s32 ResponseToQA(HQA_CMD_FRAME *HqaCmdFrame, + IN union iwreq_data *prIwReqData, s32 i4Length, + s32 i4Status) +{ + HqaCmdFrame->Length = ntohs((i4Length)); + + i4Status = ntohs((i4Status)); + memcpy(HqaCmdFrame->Data, &i4Status, 2); + + prIwReqData->data.length = + sizeof((HqaCmdFrame)->MagicNo) + sizeof((HqaCmdFrame)->Type) + + sizeof((HqaCmdFrame)->Id) + sizeof((HqaCmdFrame)->Length) + + sizeof((HqaCmdFrame)->Sequence) + ntohs((HqaCmdFrame)->Length); + + if (copy_to_user(prIwReqData->data.pointer, (u8 *)(HqaCmdFrame), + prIwReqData->data.length)) { + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT copy_to_user() fail in %s\n", + __func__); + return -EFAULT; + } + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA command(0x%04x)[Magic number(0x%08x)] is done\n", + ntohs(HqaCmdFrame->Id), + ntohl(HqaCmdFrame->MagicNo)); + + return 0; +} + +static s32 ToDoFunction(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT ToDoFunction\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Open Adapter (called when QA Tool UI Open). + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_OpenAdapter(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_OpenAdapter\n"); + + i4Ret = MT_ATEStart(prNetDev, "ATESTART"); + + /* For SA Buffer Mode Temp Solution */ + g_BufferDownload = false; + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Close Adapter (called when QA Tool UI Close). + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_CloseAdapter(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_CloseAdapter\n"); + + i4Ret = MT_ATEStop(prNetDev, "ATESTOP"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Start TX. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_StartTx(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 TxCount; + u16 TxLength; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StartTx\n"); + + memcpy((u8 *)&TxCount, HqaCmdFrame->Data + 4 * 0, 4); + TxCount = ntohl(TxCount); + memcpy((u8 *)&TxLength, HqaCmdFrame->Data + 4 * 1, 2); + TxLength = ntohs(TxLength); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StartTx TxCount = %d\n", + TxCount); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StartTx TxLength = %d\n", + TxLength); + + i4Ret = MT_ATESetTxCount(prNetDev, TxCount); + i4Ret = MT_ATESetTxLength(prNetDev, (u32)TxLength); + i4Ret = MT_ATEStartTX(prNetDev, "TXFRAME"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +/* 1 todo not support yet */ +static s32 HQA_StartTxExt(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StartTxExt\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Start Continuous TX. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +/* 1 todo not support yet */ +static s32 HQA_StartTxContiTx(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StartTxContiTx\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +/* 1 todo not support yets */ +static s32 HQA_StartTxCarrier(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StartTxCarrier\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Start RX (Legacy function). + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_StartRx(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StartRx\n"); + + MT_ATESetDBDCBandIndex(prNetDev, 0); + MT_ATEStartRX(prNetDev, "RXFRAME"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Stop TX (Legacy function). + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_StopTx(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StopTx\n"); + + MT_ATESetDBDCBandIndex(prNetDev, 0); + MT_ATEStopRX(prNetDev, "RXSTOP"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Stop Continuous TX. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_StopContiTx(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StopContiTx\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_StopTxCarrier(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StopTxCarrier\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Stop RX (Legacy function). + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_StopRx(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StopRx\n"); + + MT_ATESetDBDCBandIndex(prNetDev, 0); + MT_ATEStopRX(prNetDev, "RXSTOP"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set TX Path. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetTxPath(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetTxPath\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set RX Path. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetRxPath(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + /* s16 Value = 0; + * P_GLUE_INFO_T prGlueInfo = NULL; + * PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + * u32 u4BufLen = 0; + */ + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetRxPath\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set TX Inter-Packet Guard. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetTxIPG(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Aifs = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetTxIPG\n"); + + memcpy(&u4Aifs, HqaCmdFrame->Data + 4 * 0, 4); + u4Aifs = ntohs(u4Aifs); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetTxIPG u4Aifs : %d\n", + u4Aifs); + + MT_ATESetTxIPG(prNetDev, u4Aifs); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set TX Power0 (Legacy Function). + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetTxPower0(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetTxPower0\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set TX Power1. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HAQ_SetTxPower1(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HAQ_SetTxPower1\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetTxPowerExt(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Power = 0; + u32 u4Channel = 0; + u32 u4Dbdc_idx = 0; + u32 u4Band_idx = 0; + u32 u4Ant_idx = 0; + + memcpy(&u4Power, HqaCmdFrame->Data + 4 * 0, 4); + u4Power = ntohl(u4Power); + memcpy(&u4Dbdc_idx, HqaCmdFrame->Data + 4 * 1, 4); + u4Dbdc_idx = ntohl(u4Dbdc_idx); + memcpy(&u4Channel, HqaCmdFrame->Data + 4 * 2, 4); + u4Channel = ntohl(u4Channel); + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 * 3, 4); + u4Band_idx = ntohl(u4Band_idx); + memcpy(&u4Ant_idx, HqaCmdFrame->Data + 4 * 4, 4); + u4Ant_idx = ntohl(u4Ant_idx); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetTxPowerExt u4Power : %d\n", u4Power); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetTxPowerExt u4Dbdc_idx : %d\n", + u4Dbdc_idx); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetTxPowerExt u4Channel : %d\n", + u4Channel); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetTxPowerExt u4Band_idx : %d\n", + u4Band_idx); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetTxPowerExt u4Ant_idx : %d\n", + u4Ant_idx); + + MT_ATESetDBDCBandIndex(prNetDev, u4Dbdc_idx); + MT_ATESetTxPower0(prNetDev, u4Power); + /* u4Freq = nicChannelNum2Freq(u4Channel); */ + /* i4Ret = MT_ATESetChannel(prNetDev, 0, u4Freq); */ + /* MT_ATESetBand(prNetDev, u4Band_idx); */ + /* Antenna?? */ + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetOnOff(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetOnOff\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Antenna Selection. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_AntennaSel(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_AntennaSel\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_FWPacketCMD_ClockSwitchDisable(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_FWPacketCMD_ClockSwitchDisable\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +static HQA_CMD_HANDLER HQA_CMD_SET0[] = { + /* cmd id start from 0x1000 */ + HQA_OpenAdapter, /* 0x1000 */ + HQA_CloseAdapter, /* 0x1001 */ + HQA_StartTx, /* 0x1002 */ + HQA_StartTxExt, /* 0x1003 */ + HQA_StartTxContiTx, /* 0x1004 */ + HQA_StartTxCarrier, /* 0x1005 */ + HQA_StartRx, /* 0x1006 */ + HQA_StopTx, /* 0x1007 */ + HQA_StopContiTx, /* 0x1008 */ + HQA_StopTxCarrier, /* 0x1009 */ + HQA_StopRx, /* 0x100A */ + HQA_SetTxPath, /* 0x100B */ + HQA_SetRxPath, /* 0x100C */ + HQA_SetTxIPG, /* 0x100D */ + HQA_SetTxPower0, /* 0x100E */ + HAQ_SetTxPower1, /* 0x100F */ + ToDoFunction, /* 0x1010 */ + HQA_SetTxPowerExt, /* 0x1011 */ + HQA_SetOnOff, /* 0x1012 */ + HQA_AntennaSel, /* 0x1013 */ + HQA_FWPacketCMD_ClockSwitchDisable, /* 0x1014 */ +}; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set Channel Frequency (Legacy Function). + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetChannel(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + u32 i4SetFreq = 0, i4SetChan = 0; + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetChannel\n"); + + memcpy((u8 *)&i4SetChan, HqaCmdFrame->Data, 4); + i4SetChan = ntohl(i4SetChan); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetChannel Channel = %d\n", + i4SetChan); + + i4SetFreq = nicChannelNum2Freq(i4SetChan); + i4Ret = MT_ATESetChannel(prNetDev, 0, i4SetFreq); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set Preamble (Legacy Function). + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetPreamble(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Mode = 0; + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetPreamble\n"); + + memcpy((u8 *)&i4Mode, HqaCmdFrame->Data, 4); + i4Mode = ntohl(i4Mode); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetPreamble Mode = %d\n", + i4Mode); + + i4Ret = MT_ATESetPreamble(prNetDev, i4Mode); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set Rate (Legacy Function). + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetRate(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + /* s32 i4Value = 0; */ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetRate\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set Nss. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetNss(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetNss\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set System BW (Legacy Function). + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetSystemBW(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + u32 i4BW; + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetSystemBW\n"); + + memcpy((u8 *)&i4BW, HqaCmdFrame->Data, 4); + i4BW = ntohl(i4BW); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetSystemBW BW = %d\n", + i4BW); + + i4Ret = MT_ATESetSystemBW(prNetDev, i4BW); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set Data BW (Legacy Function). + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetPerPktBW(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Perpkt_bw; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetPerPktBW\n"); + + memcpy((u8 *)&u4Perpkt_bw, HqaCmdFrame->Data, 4); + u4Perpkt_bw = ntohl(u4Perpkt_bw); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetPerPktBW u4Perpkt_bw = %d\n", + u4Perpkt_bw); + + i4Ret = MT_ATESetPerPacketBW(prNetDev, u4Perpkt_bw); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set Primary BW. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetPrimaryBW(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Pri_sel = 0; + + memcpy(&u4Pri_sel, HqaCmdFrame->Data, 4); + u4Pri_sel = ntohl(u4Pri_sel); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetPrimaryBW u4Pri_sel : %d\n", + u4Pri_sel); + + i4Ret = MT_ATEPrimarySetting(prNetDev, u4Pri_sel); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set Frequency Offset. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetFreqOffset(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4FreqOffset = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 u4BufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + memcpy(&u4FreqOffset, HqaCmdFrame->Data, 4); + u4FreqOffset = ntohl(u4FreqOffset); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetFreqOffset u4FreqOffset : %d\n", + u4FreqOffset); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_FRWQ_OFFSET; + rRfATInfo.u4FuncData = (u32)u4FreqOffset; + + i4Ret = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Ret != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetAutoResponder(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetAutoResponder\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetTssiOnOff(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetTssiOnOff\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +/* 1 todo not support yet */ + +static s32 +HQA_SetRxHighLowTemperatureCompensation(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetRxHighLowTemperatureCompensation\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_LowPower(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_LowPower\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +static HQA_CMD_HANDLER HQA_CMD_SET1[] = { + /* cmd id start from 0x1100 */ + HQA_SetChannel, /* 0x1100 */ + HQA_SetPreamble, /* 0x1101 */ + HQA_SetRate, /* 0x1102 */ + HQA_SetNss, /* 0x1103 */ + HQA_SetSystemBW, /* 0x1104 */ + HQA_SetPerPktBW, /* 0x1105 */ + HQA_SetPrimaryBW, /* 0x1106 */ + HQA_SetFreqOffset, /* 0x1107 */ + HQA_SetAutoResponder, /* 0x1108 */ + HQA_SetTssiOnOff, /* 0x1109 */ + HQA_SetRxHighLowTemperatureCompensation, /* 0x110A */ + HQA_LowPower, /* 0x110B */ +}; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Reset TRX Counter + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_ResetTxRxCounter(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + u32 i4Status; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_ResetTxRxCounter\n"); + + i4Status = MT_ATEResetTXRXCounter(prNetDev); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Status); + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetStatistics(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetStatistics\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetRxOKData(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetRxOKData\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetRxOKOther(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetRxOKOther\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetRxAllPktCount(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetRxAllPktCount\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetTxTransmitted(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetTxTransmitted\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetHwCounter(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetHwCounter\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_CalibrationOperation(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_CalibrationOperation\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_CalibrationBypassExt(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Status = 0; + u32 u4Item = 0; + u32 u4Band_idx = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 u4BufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + memcpy(&u4Item, HqaCmdFrame->Data, 4); + u4Item = ntohl(u4Item); + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4, 4); + u4Band_idx = ntohl(u4Band_idx); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_CalibrationBypassExt u4Item : 0x%08x\n", + u4Item); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_CalibrationBypassExt u4Band_idx : %d\n", + u4Band_idx); + + MT_ATESetDBDCBandIndex(prNetDev, u4Band_idx); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_BYPASS_CAL_STEP; + rRfATInfo.u4FuncData = u4Item; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Status); + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetRXVectorIdx(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 band_idx = 0; + u32 Group_1 = 0, Group_2 = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 u4BufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + memcpy(&band_idx, HqaCmdFrame->Data + 4 * 0, 4); + band_idx = ntohl(band_idx); + memcpy(&Group_1, HqaCmdFrame->Data + 4 * 1, 4); + Group_1 = ntohl(Group_1); + memcpy(&Group_2, HqaCmdFrame->Data + 4 * 2, 4); + Group_2 = ntohl(Group_2); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetRXVectorIdx band_idx : %d\n", + band_idx); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetRXVectorIdx Group_1 : %d\n", Group_1); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetRXVectorIdx Group_2 : %d\n", Group_2); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_RXV_INDEX; + rRfATInfo.u4FuncData = (u32)(Group_1); + rRfATInfo.u4FuncData |= (u32)(Group_2 << 8); + rRfATInfo.u4FuncData |= (u32)(band_idx << 16); + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_SetRXVectorIdx rRfATInfo.u4FuncData : 0x%08x\n", + rRfATInfo.u4FuncData); + + i4Ret = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Ret != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set FAGC Rssi Path + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetFAGCRssiPath(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4band_idx = 0; + u32 u4FAGC_Path = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 u4BufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + memcpy(&u4band_idx, HqaCmdFrame->Data + 4 * 0, 4); + u4band_idx = ntohl(u4band_idx); + memcpy(&u4FAGC_Path, HqaCmdFrame->Data + 4 * 1, 4); + u4FAGC_Path = ntohl(u4FAGC_Path); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetFAGCRssiPath u4band_idx : %d\n", + u4band_idx); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetFAGCRssiPath u4FAGC_Path : %d\n", + u4FAGC_Path); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_FAGC_RSSI_PATH; + rRfATInfo.u4FuncData = + (u32)((u4band_idx << 16) || (u4FAGC_Path & BITS(0, 15))); + + i4Ret = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Ret != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +static HQA_CMD_HANDLER HQA_CMD_SET2[] = { + /* cmd id start from 0x1200 */ + HQA_ResetTxRxCounter, /* 0x1200 */ + HQA_GetStatistics, /* 0x1201 */ + HQA_GetRxOKData, /* 0x1202 */ + HQA_GetRxOKOther, /* 0x1203 */ + HQA_GetRxAllPktCount, /* 0x1204 */ + HQA_GetTxTransmitted, /* 0x1205 */ + HQA_GetHwCounter, /* 0x1206 */ + HQA_CalibrationOperation, /* 0x1207 */ + HQA_CalibrationBypassExt, /* 0x1208 */ + HQA_SetRXVectorIdx, /* 0x1209 */ + HQA_SetFAGCRssiPath, /* 0x120A */ +}; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For MAC CR Read. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_MacBbpRegRead(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + u32 u4Offset, u4Value; + s32 i4Status; + u32 u4BufLen = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MacBbpRegRead\n"); + + memcpy(&u4Offset, HqaCmdFrame->Data, 4); + u4Offset = ntohl(u4Offset); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MacBbpRegRead Offset = 0x%08lx\n", + u4Offset); + + rMcrInfo.u4McrOffset = u4Offset; + rMcrInfo.u4McrData = 0; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + i4Status = kalIoctl(prGlueInfo, wlanoidQueryMcrRead, &rMcrInfo, + sizeof(rMcrInfo), true, true, true, &u4BufLen); + + if (i4Status == 0) { + u4Value = rMcrInfo.u4McrData; + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT Address = 0x%08lx, Result = 0x%08lx\n", + u4Offset, + u4Value); + + u4Value = ntohl(u4Value); + memcpy(HqaCmdFrame->Data + 2, &u4Value, 4); + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Status); + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For MAC CR Write. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_MacBbpRegWrite(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + /* s32 i4Ret = 0; */ + u32 u4Offset, u4Value; + s32 i4Status = 0; + u32 u4BufLen = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MacBbpRegWrite\n"); + + memcpy(&u4Offset, HqaCmdFrame->Data, 4); + memcpy(&u4Value, HqaCmdFrame->Data + 4, 4); + + u4Offset = ntohl(u4Offset); + u4Value = ntohl(u4Value); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MacBbpRegWrite Offset = 0x%08lx\n", + u4Offset); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MacBbpRegWrite Value = 0x%08lx\n", + u4Value); + + rMcrInfo.u4McrOffset = u4Offset; + rMcrInfo.u4McrData = u4Value; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + i4Status = kalIoctl(prGlueInfo, wlanoidSetMcrWrite, &rMcrInfo, + sizeof(rMcrInfo), false, false, true, &u4BufLen); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Status); + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Read Bulk MAC CR. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_MACBbpRegBulkRead(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + u32 u4Index, u4Offset, u4Value; + u16 u2Len; + s32 i4Status = 0; + u32 u4BufLen = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MACBbpRegBulkRead\n"); + + memcpy(&u4Offset, HqaCmdFrame->Data, 4); + u4Offset = ntohl(u4Offset); + memcpy(&u2Len, HqaCmdFrame->Data + 4, 2); + u2Len = ntohs(u2Len); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MACBbpRegBulkRead Offset = 0x%08lx\n", + u4Offset); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MACBbpRegBulkRead Len = 0x%08lx\n", + u2Len); + + for (u4Index = 0; u4Index < u2Len; u4Index++) { + rMcrInfo.u4McrOffset = u4Offset + u4Index * 4; + rMcrInfo.u4McrData = 0; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + i4Status = kalIoctl(prGlueInfo, wlanoidQueryMcrRead, &rMcrInfo, + sizeof(rMcrInfo), true, true, true, + &u4BufLen); + + if (i4Status == 0) { + u4Value = rMcrInfo.u4McrData; + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT Address = 0x%08lx, Result = 0x%08lx\n", + u4Offset + u4Index * 4, + u4Value); + + u4Value = ntohl(u4Value); + if (2 + (u4Index * 4) + 4 > sizeof(HqaCmdFrame->Data)) { + DBGLOG(RFTEST, + ERROR, + "%s : memcpy data overflow, offset=%lu, ignored.\n", + __func__, + 2 + (u4Index * 4) + 4); + break; + } + memcpy(HqaCmdFrame->Data + 2 + (u4Index * 4), &u4Value, + 4); + } + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2 + (u2Len * 4), i4Status); + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Read Bulk RF CR. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_RfRegBulkRead(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + u32 u4Index, u4WfSel, u4Offset, u4Length, u4Value; + s32 i4Status = 0; + u32 u4BufLen = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_RfRegBulkRead\n"); + + memcpy(&u4WfSel, HqaCmdFrame->Data, 4); + u4WfSel = ntohl(u4WfSel); + memcpy(&u4Offset, HqaCmdFrame->Data + 4, 4); + u4Offset = ntohl(u4Offset); + memcpy(&u4Length, HqaCmdFrame->Data + 8, 4); + u4Length = ntohl(u4Length); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_RfRegBulkRead WfSel = %d\n", u4WfSel); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_RfRegBulkRead Offset = 0x%08lx\n", + u4Offset); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_RfRegBulkRead Length = %d\n", u4Length); + + if (u4WfSel == 0) { + u4Offset = u4Offset | 0x99900000; + }else if (u4WfSel == 1) { + u4Offset = u4Offset | 0x99910000; + } + + if ((2 + (u4Length * 4)) > sizeof(HqaCmdFrame->Data) || + (u4Length >> 30) != 0) { + /* avoid integer overflow by checking u4Length * 4: checking + * whether 2 MSB is 0*/ + i4Status = WLAN_STATUS_INVALID_LENGTH; + return i4Status; + } + + for (u4Index = 0; u4Index < u4Length; u4Index++) { + rMcrInfo.u4McrOffset = u4Offset + u4Index * 4; + rMcrInfo.u4McrData = 0; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + i4Status = kalIoctl(prGlueInfo, wlanoidQueryMcrRead, &rMcrInfo, + sizeof(rMcrInfo), true, true, true, + &u4BufLen); + + if (i4Status == 0) { + u4Value = rMcrInfo.u4McrData; + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT Address = 0x%08lx, Result = 0x%08lx\n", + u4Offset + u4Index * 4, + u4Value); + + u4Value = ntohl(u4Value); + if (2 + (u4Index * 4) + 4 > sizeof(HqaCmdFrame->Data)) { + DBGLOG(RFTEST, + ERROR, + "%s : memcpy data overflow, offset=%lu, ignored.\n", + __func__, + 2 + (u4Index * 4) + 4); + break; + } + memcpy(HqaCmdFrame->Data + 2 + (u4Index * 4), &u4Value, + 4); + } + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2 + (u4Length * 4), i4Status); + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Write RF CR. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_RfRegBulkWrite(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + u32 u4WfSel, u4Offset, u4Length, u4Value; + s32 i4Status; + u32 u4BufLen = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_RfRegBulkWrite\n"); + + memcpy(&u4WfSel, HqaCmdFrame->Data, 4); + u4WfSel = ntohl(u4WfSel); + memcpy(&u4Offset, HqaCmdFrame->Data + 4, 4); + u4Offset = ntohl(u4Offset); + memcpy(&u4Length, HqaCmdFrame->Data + 8, 4); + u4Length = ntohl(u4Length); + memcpy(&u4Value, HqaCmdFrame->Data + 12, 4); + u4Value = ntohl(u4Value); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_RfRegBulkWrite WfSel = %d\n", u4WfSel); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_RfRegBulkWrite Offset = 0x%08lx\n", + u4Offset); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_RfRegBulkWrite Length = %d\n", u4Length); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_RfRegBulkWrite Value = 0x%08lx\n", + u4Value); + + if (u4WfSel == 0) { + u4Offset = u4Offset | 0x99900000; + }else if (u4WfSel == 1) { + u4Offset = u4Offset | 0x99910000; + } + + rMcrInfo.u4McrOffset = u4Offset; + rMcrInfo.u4McrData = u4Value; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + i4Status = kalIoctl(prGlueInfo, wlanoidSetMcrWrite, &rMcrInfo, + sizeof(rMcrInfo), false, false, true, &u4BufLen); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Status); + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_ReadEEPROM(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + u16 Offset; + u16 Len; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + +#if (CFG_EEPROM_PAGE_ACCESS == 1) + u32 u4BufLen = 0; + u8 u4Index = 0; + u16 u4Value = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_ACCESS_EFUSE_T rAccessEfuseInfo; +#endif + + DBGLOG(INIT, INFO, "MT6632 : QA_AGENT HQA_ReadEEPROM\n"); + + memcpy(&Offset, HqaCmdFrame->Data + 2 * 0, 2); + Offset = ntohs(Offset); + memcpy(&Len, HqaCmdFrame->Data + 2 * 1, 2); + Len = ntohs(Len); + + /* HQA_ReadEEPROM read size only 16 bytes is used */ + if (Len > EFUSE_BLOCK_SIZE) { + DBGLOG(INIT, ERROR, + "QA_AGENT HQA_ReadEEPROM Len : %d not supported\n", Len); + return WLAN_STATUS_FAILURE; + } + +#if (CFG_EEPROM_PAGE_ACCESS == 1) + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + kalMemSet(&rAccessEfuseInfo, 0, sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)); + + rAccessEfuseInfo.u4Address = + (Offset / EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryProcessAccessEfuseRead, + &rAccessEfuseInfo, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), true, true, + true, &u4BufLen); + + u4Index = Offset % EFUSE_BLOCK_SIZE; + if (u4Index <= 14) { + u4Value = (prGlueInfo->prAdapter->aucEepromVaule[u4Index]) | + (prGlueInfo->prAdapter->aucEepromVaule[u4Index + 1] + << 8); + } + + /* isVaild = pResult->u4Valid; */ + + if (rStatus == WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, + "MT6632 : QA_AGENT HQA_ReadEEPROM u4Value = %x\n", + u4Value); + + u4Value = ntohl(u4Value); + memcpy(HqaCmdFrame->Data + 2, &u4Value, sizeof(u4Value)); + } +#endif + + ResponseToQA(HqaCmdFrame, prIwReqData, 4, rStatus); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_WriteEEPROM(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + +#if (CFG_EEPROM_PAGE_ACCESS == 1) + u16 u4WriteData = 0; + u32 u4BufLen = 0; + u8 u4Index = 0; + u16 Offset; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_ACCESS_EFUSE_T rAccessEfuseInfoWrite; + + memcpy(&Offset, HqaCmdFrame->Data + 2 * 0, 2); + Offset = ntohs(Offset); + memcpy(&u4WriteData, HqaCmdFrame->Data + 2 * 1, 2); + u4WriteData = ntohs(u4WriteData); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + /* Write */ + DBGLOG(INIT, INFO, "HQA_WriteEEPROM : QA_AGENT HQA_WriteEEPROM\n"); + kalMemSet(&rAccessEfuseInfoWrite, 0, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)); + u4Index = Offset % EFUSE_BLOCK_SIZE; + + if (prGlueInfo->prAdapter->rWifiVar.ucEfuseBufferModeCal == + LOAD_EEPROM_BIN) { + if (Offset >= MAX_EEPROM_BUFFER_SIZE - 1) { + DBGLOG(INIT, ERROR, + "HQA_WriteEEPROM : eeprom Offset error\n"); + return -EINVAL; + } + uacEEPROMImage[Offset] = u4WriteData & 0xff; + uacEEPROMImage[Offset + 1] = u4WriteData >> 8 & 0xff; + } else { + if (u4Index >= EFUSE_BLOCK_SIZE - 1) { + DBGLOG(INIT, ERROR, + "HQA_WriteEEPROM : eeprom Offset error\n"); + return -EINVAL; + } + + prGlueInfo->prAdapter->aucEepromVaule[u4Index] = + u4WriteData & 0xff; /* Note: u4WriteData is u16 */ + prGlueInfo->prAdapter->aucEepromVaule[u4Index + 1] = + u4WriteData >> 8 & 0xff; + + kalMemCopy(rAccessEfuseInfoWrite.aucData, + prGlueInfo->prAdapter->aucEepromVaule, 16); + rAccessEfuseInfoWrite.u4Address = + (Offset / EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE; + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryProcessAccessEfuseWrite, + &rAccessEfuseInfoWrite, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), false, + false, true, &u4BufLen); + } +#endif + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_ReadBulkEEPROM(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u16 Offset; + u16 Len; +#if (CFG_EEPROM_PAGE_ACCESS == 1) + PARAM_CUSTOM_ACCESS_EFUSE_T rAccessEfuseInfo; + u32 u4BufLen = 0; + u8 u4Loop = 0; + u32 u4TotalOffset = 0; + + u16 Buffer; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u8 tmp = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + kalMemSet(&rAccessEfuseInfo, 0, sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)); +#endif + + DBGLOG(INIT, INFO, "MT6632 : QA_AGENT HQA_ReadBulkEEPROM\n"); + + memcpy(&Offset, HqaCmdFrame->Data + 2 * 0, 2); + Offset = ntohs(Offset); + if (Offset > (MAX_EEPROM_BUFFER_SIZE - 1)) { + DBGLOG(INIT, ERROR, "%s Offset : %d out of range (0x%x)\n", + __func__, Offset, MAX_EEPROM_BUFFER_SIZE); + return WLAN_STATUS_FAILURE; + } + + memcpy(&Len, HqaCmdFrame->Data + 2 * 1, 2); + Len = ntohs(Len); + /* for bulk read, only 16 bytes is used */ + if (Len > EFUSE_BLOCK_SIZE) { + DBGLOG(INIT, ERROR, + "QA_AGENT HQA_ReadBulkEEPROM Len : %d not supported\n", + Len); + return WLAN_STATUS_FAILURE; + } + tmp = Offset; + DBGLOG(INIT, INFO, "MT6632 : QA_AGENT HQA_ReadBulkEEPROM Offset : %d\n", + Offset); + DBGLOG(INIT, INFO, "MT6632 : QA_AGENT HQA_ReadBulkEEPROM Len : %d\n", + Len); + +#if (CFG_EEPROM_PAGE_ACCESS == 1) + rAccessEfuseInfo.u4Address = + (Offset / EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE; + + DBGLOG(INIT, INFO, + "MT6632 : QA_AGENT HQA_ReadBulkEEPROM Address : %d\n", + rAccessEfuseInfo.u4Address); + + if (g_ucEepromCurrentMode == EFUSE_MODE) { + /* Read from Efuse */ + DBGLOG(INIT, INFO, + "MT6632 : QA_AGENT HQA_ReadBulkEEPROM Efuse Mode\n"); + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryProcessAccessEfuseRead, + &rAccessEfuseInfo, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), + true, + true, + true, + &u4BufLen); + + if (rStatus == WLAN_STATUS_FAILURE) { + DBGLOG(INIT, INFO, + "MT6632 : QA_AGENT HQA_ReadBulkEEPROM kal fail\n"); + } + + Offset = Offset % EFUSE_BLOCK_SIZE; + + for (u4Loop = 0; u4Loop < Len; u4Loop += 2) { + u4TotalOffset = Offset + u4Loop; + if (u4TotalOffset >= EFUSE_BLOCK_SIZE - 1) { + DBGLOG(RFTEST, + ERROR, + "%s : memcpy data overflow, offset=%lu, ignored.\n", + __func__, + Offset + u4TotalOffset + 2); + break; + } + memcpy(&Buffer, + prGlueInfo->prAdapter->aucEepromVaule + + u4TotalOffset, + 2); + Buffer = ntohs(Buffer); + DBGLOG(INIT, INFO, + "MT6632 :From Efuse u4Loop=%d Buffer=%x\n", + u4Loop, Buffer); + if (2 + u4Loop + 2 > sizeof(HqaCmdFrame->Data)) { + DBGLOG(RFTEST, + ERROR, + "%s : memcpy data overflow, offset=%lu, ignored.\n", + __func__, + 2 + u4Loop + 2); + break; + } + memcpy(HqaCmdFrame->Data + 2 + u4Loop, &Buffer, 2); + } + } else { /* Read from EEPROM */ + for (u4Loop = 0; u4Loop < Len; u4Loop += 2) { + u4TotalOffset = Offset + u4Loop; + if (u4TotalOffset >= MAX_EEPROM_BUFFER_SIZE - 1) { + DBGLOG(RFTEST, + ERROR, + "%s : memcpy data overflow, offset=%lu, ignored.\n", + __func__, + u4TotalOffset + 2); + break; + } + memcpy(&Buffer, uacEEPROMImage + u4TotalOffset, 2); + Buffer = ntohs(Buffer); + if (2 + u4Loop + 2 > sizeof(HqaCmdFrame->Data)) { + DBGLOG(RFTEST, + ERROR, + "%s : memcpy data overflow, offset=%lu, ignored.\n", + __func__, + 2 + u4Loop + 2); + break; + } + memcpy(HqaCmdFrame->Data + 2 + u4Loop, &Buffer, 2); + DBGLOG(INIT, + INFO, + "MT6632 : QA_AGENT HQA_ReadBulkEEPROM u4Loop=%d u4Value=%x\n", + u4Loop, + uacEEPROMImage[u4TotalOffset]); + } + } +#endif + + ResponseToQA(HqaCmdFrame, prIwReqData, 2 + Len, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_WriteBulkEEPROM(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u16 Offset; + u16 Len; + P_ADAPTER_T prAdapter = NULL; + + u32 u4BufLen = 0; + PARAM_CUSTOM_ACCESS_EFUSE_T rAccessEfuseInfoRead, rAccessEfuseInfoWrite; + u16 *Buffer = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u8 u4Loop = 0, u4Index = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + kalMemSet(&rAccessEfuseInfoRead, 0, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)); + kalMemSet(&rAccessEfuseInfoWrite, 0, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)); + + DBGLOG(INIT, INFO, "MT6632 : QA_AGENT HQA_WriteBulkEEPROM\n"); + + memcpy(&Offset, HqaCmdFrame->Data + 2 * 0, 2); + Offset = ntohs(Offset); + + memcpy(&Len, HqaCmdFrame->Data + 2 * 1, 2); + Len = ntohs(Len); + + if (Len > EFUSE_BLOCK_SIZE) { + DBGLOG(INIT, ERROR, "Invalid efuse Length: %x\n", Len); + return -EINVAL; + } + if (Offset + Len > MAX_EEPROM_BUFFER_SIZE) { + DBGLOG(INIT, ERROR, + "Invalid efuse Offset address: %x, Len: %lu\n", Offset, + Len); + return -EINVAL; + } + + DBGLOG(INIT, INFO, + "MT6632 : QA_AGENT HQA_WriteBulkEEPROM Offset : %x\n", Offset); + DBGLOG(INIT, INFO, "MT6632 : QA_AGENT HQA_WriteBulkEEPROM Len : %d\n", + Len); + + /* Support Delay Calibraiton */ + Buffer = kmalloc(sizeof(u8) * (EFUSE_BLOCK_SIZE), GFP_KERNEL); + if (!Buffer) { + return -ENOMEM; + } + + kalMemSet(Buffer, 0, sizeof(u8) * (EFUSE_BLOCK_SIZE)); + + kalMemCopy((u8 *)Buffer, (u8 *)HqaCmdFrame->Data + 4, Len); + + if (g_ucEepromCurrentMode == BUFFER_BIN_MODE) { + /* EEPROM */ + DBGLOG(INIT, INFO, "Direct EEPROM buffer, offset=%x, len=%x\n", + Offset, Len); + + if (Len > 2) { + for (u4Loop = 0; u4Loop < EFUSE_BLOCK_SIZE / 2; + u4Loop++) { + Buffer[u4Loop] = ntohs(Buffer[u4Loop]); + uacEEPROMImage[Offset] = Buffer[u4Loop] & 0xff; + uacEEPROMImage[Offset + 1] = + Buffer[u4Loop] >> 8 & 0xff; + Offset += 2; + } + } else { + *Buffer = ntohs(*Buffer); + uacEEPROMImage[Offset] = *Buffer & 0xff; + uacEEPROMImage[Offset + 1] = *Buffer >> 8 & 0xff; + } + } else if (g_ucEepromCurrentMode == EFUSE_MODE) { + /* EFUSE */ + /* Read */ + DBGLOG(INIT, INFO, + "MT6632 : QA_AGENT HQA_WriteBulkEEPROM Read\n"); + kalMemSet(&rAccessEfuseInfoRead, 0, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)); + rAccessEfuseInfoRead.u4Address = + (Offset / EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE; + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryProcessAccessEfuseRead, + &rAccessEfuseInfoRead, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), true, + true, true, &u4BufLen); + + /* Write */ + kalMemSet(&rAccessEfuseInfoWrite, 0, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)); + + if (Len > 2) { + for (u4Loop = 0; u4Loop < 8; u4Loop++) + Buffer[u4Loop] = ntohs(Buffer[u4Loop]); + memcpy(rAccessEfuseInfoWrite.aucData, Buffer, 16); + } else { + u4Index = Offset % EFUSE_BLOCK_SIZE; + DBGLOG(INIT, + INFO, + "MT6632:QA_AGENT HQA_WriteBulkEEPROM Wr,u4Index=%x\n", + u4Index); + + if (u4Index >= EFUSE_BLOCK_SIZE - 1) { + DBGLOG(INIT, ERROR, + "MT6632 : efuse Offset error\n"); + i4Ret = -EINVAL; + goto exit; + } + + *Buffer = ntohs(*Buffer); + DBGLOG(INIT, INFO, + "MT6632 : Buffer[0]=%x, Buffer[0]&0xff=%x\n", + Buffer[0], Buffer[0] & 0xff); + DBGLOG(INIT, INFO, + "MT6632 : Buffer[0] >> 8 & 0xff=%x\n", + Buffer[0] >> 8 & 0xff); + + prGlueInfo->prAdapter->aucEepromVaule[u4Index] = + *Buffer & 0xff; + prGlueInfo->prAdapter->aucEepromVaule[u4Index + 1] = + *Buffer >> 8 & 0xff; + kalMemCopy(rAccessEfuseInfoWrite.aucData, + prGlueInfo->prAdapter->aucEepromVaule, 16); + } + + rAccessEfuseInfoWrite.u4Address = + (Offset / EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE; + for (u4Loop = 0; u4Loop < (EFUSE_BLOCK_SIZE); u4Loop++) + DBGLOG(INIT, INFO, "MT6632 : Loop=%d aucData=%x\n", + u4Loop, rAccessEfuseInfoWrite.aucData[u4Loop]); + + DBGLOG(INIT, INFO, "Going for e-Fuse\n"); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryProcessAccessEfuseWrite, + &rAccessEfuseInfoWrite, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), false, + true, true, &u4BufLen); + } else { + DBGLOG(INIT, INFO, "Invalid ID!!\n"); + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2 + Len, i4Ret); + +exit: + kfree(Buffer); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_CheckEfuseMode(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 Value = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_CheckEfuseMode\n"); + + /* Value: 0:eeprom mode, 1:eFuse mode */ + Value = ntohl(Value); + memcpy(HqaCmdFrame->Data + 2, &(Value), sizeof(Value)); + + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetFreeEfuseBlock(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0, u4FreeBlockCount = 0; + +#if (CFG_EEPROM_PAGE_ACCESS == 1) + PARAM_CUSTOM_EFUSE_FREE_BLOCK_T rEfuseFreeBlock; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + P_GLUE_INFO_T prGlueInfo = NULL; +#endif + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(INIT, INFO, "MT6632 : QA_AGENT HQA_GetFreeEfuseBlock\n"); + +#if (CFG_EEPROM_PAGE_ACCESS == 1) + kalMemSet(&rEfuseFreeBlock, 0, sizeof(PARAM_CUSTOM_EFUSE_FREE_BLOCK_T)); + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryEfuseFreeBlock, + &rEfuseFreeBlock, + sizeof(PARAM_CUSTOM_EFUSE_FREE_BLOCK_T), true, true, + true, &u4BufLen); + + u4FreeBlockCount = prGlueInfo->prAdapter->u4FreeBlockNum; + u4FreeBlockCount = ntohl(u4FreeBlockCount); + kalMemCopy(HqaCmdFrame->Data + 2, &u4FreeBlockCount, 4); +#endif + + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetEfuseBlockNr(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetEfuseBlockNr\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_WriteEFuseFromBuffer(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_WriteEFuseFromBuffer\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetTxPower(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Channel = 0, u4Band = 0, u4Ch_Band = 0, u4TxTargetPower = 0; + /* u32 u4EfuseAddr = 0, u4Power = 0; */ + +#if (CFG_EEPROM_PAGE_ACCESS == 1) + PARAM_CUSTOM_GET_TX_POWER_T rGetTxPower; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + P_GLUE_INFO_T prGlueInfo = NULL; +#endif + + memcpy(&u4Channel, HqaCmdFrame->Data + 4 * 0, 4); + u4Channel = ntohl(u4Channel); + memcpy(&u4Band, HqaCmdFrame->Data + 4 * 1, 4); + u4Band = ntohl(u4Band); + memcpy(&u4Ch_Band, HqaCmdFrame->Data + 4 * 2, 4); + u4Ch_Band = ntohl(u4Ch_Band); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_GetTxPower u4Channel : %d\n", u4Channel); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetTxPower u4Band : %d\n", + u4Band); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_GetTxPower u4Ch_Band : %d\n", u4Ch_Band); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + kalMemSet(&rGetTxPower, 0, sizeof(PARAM_CUSTOM_GET_TX_POWER_T)); + + rGetTxPower.ucCenterChannel = u4Channel; + rGetTxPower.ucBand = u4Band; + rGetTxPower.ucDbdcIdx = u4Ch_Band; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryGetTxPower, &rGetTxPower, + sizeof(PARAM_CUSTOM_GET_TX_POWER_T), true, true, + true, &u4BufLen); + + u4TxTargetPower = prGlueInfo->prAdapter->u4GetTxPower; + u4TxTargetPower = ntohl(u4TxTargetPower); + kalMemCopy(HqaCmdFrame->Data + 6, &u4TxTargetPower, 4); + + ResponseToQA(HqaCmdFrame, prIwReqData, 10, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetCfgOnOff(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 Type, Enable, Band; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 u4BufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + memcpy(&Type, HqaCmdFrame->Data + 4 * 0, 4); + Type = ntohl(Type); + memcpy(&Enable, HqaCmdFrame->Data + 4 * 1, 4); + Enable = ntohl(Enable); + memcpy(&Band, HqaCmdFrame->Data + 4 * 2, 4); + Band = ntohl(Band); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetCfgOnOff Type : %d\n", + Type); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetCfgOnOff Enable : %d\n", + Enable); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetCfgOnOff Band : %d\n", + Band); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_TSSI; + rRfATInfo.u4FuncData = 0; + + if (Band == 0 && Enable == 1) { + rRfATInfo.u4FuncData |= BIT(0); + }else if (Band == 1 && Enable == 1) { + rRfATInfo.u4FuncData |= BIT(1); + } + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetFreqOffset(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4FreqOffset = 0; + u32 u4BufLen = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_GET_FREQ_OFFSET; + rRfATInfo.u4FuncData = 0; + + i4Ret = kalIoctl(prGlueInfo, wlanoidRftestQueryAutoTest, &rRfATInfo, + sizeof(rRfATInfo), true, true, true, &u4BufLen); + + if (i4Ret == 0) { + u4FreqOffset = rRfATInfo.u4FuncData; + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_GetFreqOffset u4FreqOffset = %d\n", + u4FreqOffset); + + u4FreqOffset = ntohl(u4FreqOffset); + memcpy(HqaCmdFrame->Data + 2, &u4FreqOffset, + sizeof(u4FreqOffset)); + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_DBDCTXTone(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + s32 i4BandIdx = 0, i4Control = 0, i4AntIndex = 0, i4ToneType = 0, + i4ToneFreq = 0; + s32 i4DcOffsetI = 0, i4DcOffsetQ = 0, i4Band = 0, i4RF_Power = 0, + i4Digi_Power = 0; + + memcpy(&i4BandIdx, HqaCmdFrame->Data + 4 * 0, 4); /* DBDC Band Index : + * Band0, Band1 */ + i4BandIdx = ntohl(i4BandIdx); + memcpy(&i4Control, HqaCmdFrame->Data + 4 * 1, 4); /* Control TX Tone + * Start and Stop */ + i4Control = ntohl(i4Control); + memcpy(&i4AntIndex, HqaCmdFrame->Data + 4 * 2, 4); /* Select TX Antenna + */ + i4AntIndex = ntohl(i4AntIndex); + memcpy(&i4ToneType, HqaCmdFrame->Data + 4 * 3, 4); /* ToneType : Single + * or Two */ + i4ToneType = ntohl(i4ToneType); + memcpy(&i4ToneFreq, HqaCmdFrame->Data + 4 * 4, 4); /* ToneFreq: + * DC/5M/10M/20M/40M + */ + i4ToneFreq = ntohl(i4ToneFreq); + memcpy(&i4DcOffsetI, HqaCmdFrame->Data + 4 * 5, 4); /* DC Offset I : + * -512~1535 */ + i4DcOffsetI = ntohl(i4DcOffsetI); + memcpy(&i4DcOffsetQ, HqaCmdFrame->Data + 4 * 6, 4); /* DC Offset Q : + * -512~1535 */ + i4DcOffsetQ = ntohl(i4DcOffsetQ); + memcpy(&i4Band, HqaCmdFrame->Data + 4 * 7, 4); /* Band : 2.4G/5G */ + i4Band = ntohl(i4Band); + memcpy(&i4RF_Power, HqaCmdFrame->Data + 4 * 8, 4); /* RF_Power: (1db) + * 0~15 */ + i4RF_Power = ntohl(i4RF_Power); + memcpy(&i4Digi_Power, HqaCmdFrame->Data + 4 * 9, 4); /* Digi_Power: + * (0.25db) -32~31 + */ + i4Digi_Power = ntohl(i4Digi_Power); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCTXTone BandIdx = 0x%08lx\n", + i4BandIdx); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCTXTone Control = 0x%08lx\n", + i4Control); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCTXTone AntIndex = 0x%08lx\n", + i4AntIndex); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCTXTone ToneType = 0x%08lx\n", + i4ToneType); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCTXTone ToneFreq = 0x%08lx\n", + i4ToneFreq); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCTXTone DcOffsetI = 0x%08lx\n", + i4DcOffsetI); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCTXTone DcOffsetQ = 0x%08lx\n", + i4DcOffsetQ); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCTXTone Band = 0x%08lx\n", i4Band); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCTXTone RF_Power = 0x%08lx\n", + i4RF_Power); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCTXTone Digi_Power = 0x%08lx\n", + i4Digi_Power); + + /* + * Select TX Antenna + * RF_Power: (1db) 0~15 + * Digi_Power: (0.25db) -32~31 + */ + MT_ATESetDBDCTxTonePower(prNetDev, i4AntIndex, i4RF_Power, + i4Digi_Power); + + /* DBDC Band Index : Band0, Band1 */ + MT_ATESetDBDCBandIndex(prNetDev, i4BandIdx); + + if (i4Control) { + /* Band : 2.4G/5G */ + MT_ATESetBand(prNetDev, i4Band); + + /* ToneType : Single or Two */ + MT_ATESetTxToneType(prNetDev, i4ToneType); + + /* ToneFreq: DC/5M/10M/20M/40M */ + MT_ATESetTxToneBW(prNetDev, i4ToneFreq); + + /* DC Offset I, DC Offset Q */ + MT_ATESetTxToneDCOffset(prNetDev, i4DcOffsetI, i4DcOffsetQ); + + /* Control TX Tone Start and Stop */ + MT_ATEDBDCTxTone(prNetDev, i4Control); + } else { + /* Control TX Tone Start and Stop */ + MT_ATEDBDCTxTone(prNetDev, i4Control); + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_DBDCContinuousTX(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Band = 0, u4Control = 0, u4AntMask = 0, u4Phymode = 0, u4BW = 0; + u32 u4Pri_Ch = 0, u4Rate = 0, u4Central_Ch = 0, u4TxfdMode = 0, + u4Freq = 0; + u32 u4BufLen = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + memcpy(&u4Band, HqaCmdFrame->Data + 4 * 0, 4); + u4Band = ntohl(u4Band); + memcpy(&u4Control, HqaCmdFrame->Data + 4 * 1, 4); + u4Control = ntohl(u4Control); + memcpy(&u4AntMask, HqaCmdFrame->Data + 4 * 2, 4); + u4AntMask = ntohl(u4AntMask); + memcpy(&u4Phymode, HqaCmdFrame->Data + 4 * 3, 4); + u4Phymode = ntohl(u4Phymode); + memcpy(&u4BW, HqaCmdFrame->Data + 4 * 4, 4); + u4BW = ntohl(u4BW); + memcpy(&u4Pri_Ch, HqaCmdFrame->Data + 4 * 5, 4); + u4Pri_Ch = ntohl(u4Pri_Ch); + memcpy(&u4Rate, HqaCmdFrame->Data + 4 * 6, 4); + u4Rate = ntohl(u4Rate); + memcpy(&u4Central_Ch, HqaCmdFrame->Data + 4 * 7, 4); + u4Central_Ch = ntohl(u4Central_Ch); + memcpy(&u4TxfdMode, HqaCmdFrame->Data + 4 * 8, 4); + u4TxfdMode = ntohl(u4TxfdMode); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCContinuousTX u4Band : %d\n", + u4Band); /* ok */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCContinuousTX u4Control : %d\n", + u4Control); /* ok */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCContinuousTX u4AntMask : %d\n", + u4AntMask); /* ok */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCContinuousTX u4Phymode : %d\n", + u4Phymode); /* ok */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCContinuousTX u4BW : %d\n", + u4BW); /* ok */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCContinuousTX u4Pri_Ch : %d\n", + u4Pri_Ch); /* ok */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCContinuousTX u4Rate : %d\n", + u4Rate); /* ok */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCContinuousTX u4Central_Ch : %d\n", + u4Central_Ch); /* ok */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DBDCContinuousTX u4TxfdMode : %d\n", + u4TxfdMode); /* ok */ + + if (u4Control) { + MT_ATESetDBDCBandIndex(prNetDev, u4Band); + u4Freq = nicChannelNum2Freq(u4Central_Ch); + MT_ATESetChannel(prNetDev, 0, u4Freq); + MT_ATEPrimarySetting(prNetDev, u4Pri_Ch); + + if (u4Phymode == 1) { + u4Phymode = 0; + u4Rate += 4; + } else if ((u4Phymode == 0) && + ((u4Rate == 9) || (u4Rate == 10) || + (u4Rate == 11))) { + u4Phymode = 1; + } + MT_ATESetPreamble(prNetDev, u4Phymode); + + if (u4Phymode == 0) { + u4Rate |= 0x00000000; + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT CCK/OFDM (normal preamble) rate : %d\n", + u4Rate); + + MT_ATESetRate(prNetDev, u4Rate); + } else if (u4Phymode == 1) { + if (u4Rate == 9) { + u4Rate = 1; + }else if (u4Rate == 10) { + u4Rate = 2; + }else if (u4Rate == 11) { + u4Rate = 3; + } + u4Rate |= 0x00000000; + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT CCK (short preamble) rate : %d\n", + u4Rate); + + MT_ATESetRate(prNetDev, u4Rate); + } else if (u4Phymode >= 2 && u4Phymode <= 4) { + u4Rate |= 0x80000000; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HT/VHT rate : %d\n", u4Rate); + + MT_ATESetRate(prNetDev, u4Rate); + } + + MT_ATESetSystemBW(prNetDev, u4BW); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_CW_MODE; + rRfATInfo.u4FuncData = u4TxfdMode; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_ANTMASK; + rRfATInfo.u4FuncData = u4AntMask; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_COMMAND; + rRfATInfo.u4FuncData = RF_AT_COMMAND_CW; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + } else { + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_COMMAND; + rRfATInfo.u4FuncData = RF_AT_COMMAND_STOPTEST; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetRXFilterPktLen(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Band = 0, u4Control = 0, u4RxPktlen = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 u4BufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + memcpy(&u4Band, HqaCmdFrame->Data + 4 * 0, 4); + u4Band = ntohl(u4Band); + memcpy(&u4Control, HqaCmdFrame->Data + 4 * 1, 4); + u4Control = ntohl(u4Control); + memcpy(&u4RxPktlen, HqaCmdFrame->Data + 4 * 2, 4); + u4RxPktlen = ntohl(u4RxPktlen); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetRXFilterPktLen Band : %d\n", u4Band); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetRXFilterPktLen Control : %d\n", + u4Control); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetRXFilterPktLen RxPktlen : %d\n", + u4RxPktlen); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_RX_FILTER_PKT_LEN; + rRfATInfo.u4FuncData = (u32)(u4RxPktlen & BITS(0, 23)); + rRfATInfo.u4FuncData |= (u32)(u4Band << 24); + + if (u4Control == 1) { + rRfATInfo.u4FuncData |= BIT(30); + }else{ + rRfATInfo.u4FuncData &= ~BIT(30); + } + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_SetRXFilterPktLen rRfATInfo.u4FuncData : 0x%08x\n", + rRfATInfo.u4FuncData); + + i4Ret = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Ret != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetTXInfo(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + u32 u4Txed_band0 = 0; + u32 u4Txed_band1 = 0; + s32 i4Status; + u32 u4BufLen = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetTXInfo\n"); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_TXED_COUNT; + rRfATInfo.u4FuncData = 0; + + i4Status = kalIoctl(prGlueInfo, wlanoidRftestQueryAutoTest, &rRfATInfo, + sizeof(rRfATInfo), true, true, true, &u4BufLen); + + if (i4Status == 0) { + u4Txed_band0 = rRfATInfo.u4FuncData; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT u4Txed_band0 packet count = %d\n", + u4Txed_band0); + + u4Txed_band0 = ntohl(u4Txed_band0); + memcpy(HqaCmdFrame->Data + 2, &u4Txed_band0, + sizeof(u4Txed_band0)); + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_TXED_COUNT; + rRfATInfo.u4FuncIndex |= BIT(8); + rRfATInfo.u4FuncData = 0; + + i4Status = kalIoctl(prGlueInfo, wlanoidRftestQueryAutoTest, &rRfATInfo, + sizeof(rRfATInfo), true, true, true, &u4BufLen); + + if (i4Status == 0) { + u4Txed_band1 = rRfATInfo.u4FuncData; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT u4Txed_band1 packet count = %d\n", + u4Txed_band1); + + u4Txed_band1 = ntohl(u4Txed_band1); + memcpy(HqaCmdFrame->Data + 2 + 4, &u4Txed_band1, + sizeof(u4Txed_band1)); + } + + ResponseToQA(HqaCmdFrame, prIwReqData, + 2 + sizeof(u4Txed_band0) + sizeof(u4Txed_band1), i4Status); + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetCfgOnOff(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetCfgOnOff\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetBufferBin(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 Ret = 0; + u32 data = 0; + + kalMemCopy(&data, HqaCmdFrame->Data, sizeof(data)); + data = ntohl(data); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetBufferBin data=%x\n", + data); + + if (data == BUFFER_BIN_MODE) { + /*Buffer mode*/ + g_ucEepromCurrentMode = BUFFER_BIN_MODE; + } else if (data == EFUSE_MODE) { + /*Efuse mode */ + g_ucEepromCurrentMode = EFUSE_MODE; + } else { + DBGLOG(RFTEST, INFO, "Invalid data!!\n"); + } + + DBGLOG(RFTEST, INFO, "MT6632 : ucEepromCurrentMode=%x\n", + g_ucEepromCurrentMode); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, Ret); + return Ret; +} + +static HQA_CMD_HANDLER HQA_CMD_SET3[] = { + /* cmd id start from 0x1300 */ + HQA_MacBbpRegRead, /* 0x1300 */ + HQA_MacBbpRegWrite, /* 0x1301 */ + HQA_MACBbpRegBulkRead, /* 0x1302 */ + HQA_RfRegBulkRead, /* 0x1303 */ + HQA_RfRegBulkWrite, /* 0x1304 */ + HQA_ReadEEPROM, /* 0x1305 */ + HQA_WriteEEPROM, /* 0x1306 */ + HQA_ReadBulkEEPROM, /* 0x1307 */ + HQA_WriteBulkEEPROM, /* 0x1308 */ + HQA_CheckEfuseMode, /* 0x1309 */ + HQA_GetFreeEfuseBlock, /* 0x130A */ + HQA_GetEfuseBlockNr, /* 0x130B */ + HQA_WriteEFuseFromBuffer, /* 0x130C */ + HQA_GetTxPower, /* 0x130D */ + HQA_SetCfgOnOff, /* 0x130E */ + HQA_GetFreqOffset, /* 0x130F */ + HQA_DBDCTXTone, /* 0x1310 */ + HQA_DBDCContinuousTX, /* 0x1311 */ + HQA_SetRXFilterPktLen, /* 0x1312 */ + HQA_GetTXInfo, /* 0x1313 */ + HQA_GetCfgOnOff, /* 0x1314 */ + NULL, /* 0x1315 */ + HQA_SetBufferBin, /* 0x1316 */ +}; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_ReadTempReferenceValue(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_ReadTempReferenceValue\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Get Thermal Value. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetThermalValue(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + u32 u4Value; + u32 u4BufLen = 0; + s32 i4Status; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_TEMP_SENSOR; + rRfATInfo.u4FuncData = 0; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + i4Status = kalIoctl(prGlueInfo, wlanoidRftestQueryAutoTest, &rRfATInfo, + sizeof(rRfATInfo), true, true, true, &u4BufLen); + + if (i4Status == 0) { + u4Value = rRfATInfo.u4FuncData; + u4Value = u4Value >> 16; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_GetThermalValue Value = %d\n", + u4Value); + + u4Value = ntohl(u4Value); + memcpy(HqaCmdFrame->Data + 2, &u4Value, 4); + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Status); + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetSideBandOption(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetSideBandOption\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +static HQA_CMD_HANDLER HQA_CMD_SET4[] = { + /* cmd id start from 0x1400 */ + HQA_ReadTempReferenceValue, /* 0x1400 */ + HQA_GetThermalValue, /* 0x1401 */ + HQA_SetSideBandOption, /* 0x1402 */ +}; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetFWInfo(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetFWInfo\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_StartContinousTx(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StartContinousTx\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetSTBC(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetSTBC\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Set short GI. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetShortGI(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4ShortGi; + + memcpy(&u4ShortGi, HqaCmdFrame->Data, 4); + u4ShortGi = ntohl(u4ShortGi); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetShortGI u4ShortGi = %d\n", u4ShortGi); + + i4Ret = MT_ATESetTxGi(prNetDev, u4ShortGi); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetDPD(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetDPD\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Get Rx Statistics. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetRxStatisticsAll(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + u32 u4BufLen = 0; + PARAM_CUSTOM_ACCESS_RX_STAT rRxStatisticsTest; + + /* memset(&g_HqaRxStat, 0, sizeof(PARAM_RX_STAT_T)); */ + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetRxStatisticsAll\n"); + + rRxStatisticsTest.u4SeqNum = u4RxStatSeqNum; + rRxStatisticsTest.u4TotalNum = HQA_RX_STATISTIC_NUM + 6; + + i4Ret = kalIoctl(prGlueInfo, wlanoidQueryRxStatistics, + &rRxStatisticsTest, sizeof(rRxStatisticsTest), true, + true, true, &u4BufLen); + + /* ASSERT(rRxStatisticsTest.u4SeqNum == u4RxStatSeqNum); */ + + u4RxStatSeqNum++; + + memcpy(HqaCmdFrame->Data + 2, &(g_HqaRxStat), sizeof(PARAM_RX_STAT_T)); + ResponseToQA(HqaCmdFrame, prIwReqData, (2 + sizeof(PARAM_RX_STAT_T)), + i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_StartContiTxTone(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StartContiTxTone\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_StopContiTxTone(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StopContiTxTone\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_CalibrationTestMode(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Mode = 0; + u32 u4IcapLen = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_CalibrationTestMode\n"); + + memcpy(&u4Mode, HqaCmdFrame->Data + 4 * 0, 4); + u4Mode = ntohl(u4Mode); + memcpy(&u4IcapLen, HqaCmdFrame->Data + 4 * 1, 4); + u4IcapLen = ntohl(u4IcapLen); + + if (u4Mode == 2) { + i4Ret = MT_ICAPStart(prNetDev, "ICAPSTART"); + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_DoCalibrationTestItem(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Status = 0; + u32 u4Item = 0; + u32 u4Band_idx = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 u4BufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + memcpy(&u4Item, HqaCmdFrame->Data, 4); + u4Item = ntohl(u4Item); + + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4, 4); + u4Band_idx = ntohl(u4Band_idx); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DoCalibrationTestItem item : 0x%08x\n", + u4Item); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DoCalibrationTestItem band_idx : %d\n", + u4Band_idx); + + MT_ATESetDBDCBandIndex(prNetDev, u4Band_idx); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_RECAL_CAL_STEP; + rRfATInfo.u4FuncData = u4Item; + + i4Status = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Status); + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_eFusePhysicalWrite(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_eFusePhysicalWrite\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_eFusePhysicalRead(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_eFusePhysicalRead\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_eFuseLogicalRead(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_eFuseLogicalRead\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_eFuseLogicalWrite(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_eFuseLogicalWrite\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_TMRSetting(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Setting; + u32 u4Version; + u32 u4MPThres; + u32 u4MPIter; + + memcpy(&u4Setting, HqaCmdFrame->Data + 4 * 0, 4); + u4Setting = ntohl(u4Setting); + memcpy(&u4Version, HqaCmdFrame->Data + 4 * 1, 4); + u4Version = ntohl(u4Version); + memcpy(&u4MPThres, HqaCmdFrame->Data + 4 * 2, 4); + u4MPThres = ntohl(u4MPThres); + memcpy(&u4MPIter, HqaCmdFrame->Data + 4 * 3, 4); + u4MPIter = ntohl(u4MPIter); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_TMRSetting u4Setting : %d\n", u4Setting); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_TMRSetting u4Version : %d\n", u4Version); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_TMRSetting u4MPThres : %d\n", u4MPThres); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TMRSetting u4MPIter : %d\n", + u4MPIter); + + i4Ret = MT_ATE_TMRSetting(prNetDev, u4Setting, u4Version, u4MPThres, + u4MPIter); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetRxSNR(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetRxSNR\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_WriteBufferDone(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u16 u2InitAddr; + u32 Value; + /* u32 i = 0, j = 0; + * u32 u4BufLen = 0; + */ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + /* PARAM_CUSTOM_EFUSE_BUFFER_MODE_T rSetEfuseBufModeInfo; */ + PARAM_CUSTOM_EFUSE_BUFFER_MODE_T *prSetEfuseBufModeInfo = NULL; + u8 *pucConfigBuf = NULL; + u32 u4ContentLen; + u32 u4BufLen = 0; + P_ADAPTER_T prAdapter = NULL; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + +#if (CFG_FW_Report_Efuse_Address) + u2InitAddr = prAdapter->u4EfuseStartAddress; +#else + u2InitAddr = EFUSE_CONTENT_BUFFER_START; +#endif + + memcpy(&Value, HqaCmdFrame->Data + 4 * 0, 4); + Value = ntohl(Value); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_WriteBufferDone Value : %d\n", Value); + + u4EepromMode = Value; + + /* allocate memory for buffer mode info */ + prSetEfuseBufModeInfo = (PARAM_CUSTOM_EFUSE_BUFFER_MODE_T *)kalMemAlloc( + sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T), VIR_MEM_TYPE); + if (prSetEfuseBufModeInfo == NULL) { + goto label_exit; + } + kalMemZero(prSetEfuseBufModeInfo, + sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T)); + + /* copy to the command buffer */ +#if (CFG_FW_Report_Efuse_Address) + u4ContentLen = (prAdapter->u4EfuseEndAddress) - + (prAdapter->u4EfuseStartAddress) + 1; +#else + u4ContentLen = EFUSE_CONTENT_BUFFER_SIZE; +#endif + if (u4ContentLen > MAX_EEPROM_BUFFER_SIZE) { + goto label_exit; + } + kalMemCopy(prSetEfuseBufModeInfo->aBinContent, + &uacEEPROMImage[u2InitAddr], u4ContentLen); + + prSetEfuseBufModeInfo->ucSourceMode = Value; + + prSetEfuseBufModeInfo->ucCmdType = + 0x1 | (prAdapter->rWifiVar.ucCalTimingCtrl << 4); + prSetEfuseBufModeInfo->ucCount = 0xFF; /* ucCmdType 1 don't care the + * ucCount */ + + rStatus = kalIoctl(prGlueInfo, wlanoidSetEfusBufferMode, + (void *)prSetEfuseBufModeInfo, + sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T), false, + true, true, &u4BufLen); + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + +label_exit: + + /* free memory */ + if (prSetEfuseBufModeInfo != NULL) { + kalMemFree(prSetEfuseBufModeInfo, VIR_MEM_TYPE, + sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T)); + } + + if (pucConfigBuf != NULL) { + kalMemFree(pucConfigBuf, VIR_MEM_TYPE, MAX_EEPROM_BUFFER_SIZE); + } + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_FFT(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_FFT\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetTxTonePower(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetTxTonePower\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetChipID(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4ChipId; + struct chip_info *prChipInfo; + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + /* u32 u4BufLen = 0; + * PARAM_CUSTOM_MCR_RW_STRUCT_T rMcrInfo; + */ + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_GetChipID\n"); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + prChipInfo = prAdapter->chip_info; + g_u4Chip_ID = prChipInfo->chip_id; + u4ChipId = g_u4Chip_ID; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_GetChipID ChipId = 0x%08lx\n", u4ChipId); + + u4ChipId = ntohl(u4ChipId); + memcpy(HqaCmdFrame->Data + 2, &u4ChipId, 4); + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_MPSSetSeqData(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 *mps_setting = NULL; + u32 u4Band_idx = 0; + u32 u4Offset = 0; + u32 u4Len = 0; + u32 i = 0; + u32 u4Value = 0; + u32 u4Mode = 0; + u32 u4TxPath = 0; + u32 u4Mcs = 0; + + u4Len = ntohs(HqaCmdFrame->Length) / sizeof(u32) - 1; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MPSSetSeqData u4Len : %d\n", + u4Len); + + mps_setting = kmalloc(sizeof(u32) * (u4Len), GFP_KERNEL); + + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 * 0, 4); + u4Band_idx = ntohl(u4Band_idx); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MPSSetSeqData u4Band_idx : %d\n", + u4Band_idx); + + for (i = 0; i < u4Len; i++) { + u4Offset = 4 + 4 * i; + if (u4Offset + 4 > sizeof(HqaCmdFrame->Data)) { /* Reserved at + * least 4 byte + * availbale data + */ + break; + } + memcpy(&u4Value, HqaCmdFrame->Data + 4 + 4 * i, 4); + u4Value = ntohl(u4Value); + + u4Mode = (u4Value & BITS(24, 27)) >> 24; + u4TxPath = (u4Value & BITS(8, 23)) >> 8; + u4Mcs = (u4Value & BITS(0, 7)); + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_MPSSetSeqData mps_setting Case %d (Mode : %d / TX Path : %d / MCS : %d)\n", + i, + u4Mode, + u4TxPath, + u4Mcs); + + if (u4Mode == 1) { + u4Mode = 0; + u4Mcs += 4; + } else if ((u4Mode == 0) && + ((u4Mcs == 9) || (u4Mcs == 10) || (u4Mcs == 11))) { + u4Mode = 1; + } + + if (u4Mode == 0) { + u4Mcs |= 0x00000000; + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT CCK/OFDM (normal preamble) rate : %d\n", + u4Mcs); + } else if (u4Mode == 1) { + if (u4Mcs == 9) { + u4Mcs = 1; + }else if (u4Mcs == 10) { + u4Mcs = 2; + }else if (u4Mcs == 11) { + u4Mcs = 3; + } + u4Mcs |= 0x00000000; + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT CCK (short preamble) rate : %d\n", + u4Mcs); + } else if (u4Mode >= 2 && u4Mode <= 4) { + u4Mcs |= 0x80000000; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HT/VHT rate : %d\n", u4Mcs); + } + + mps_setting[i] = (u4Mcs) | (u4TxPath << 8) | (u4Mode << 24); + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_MPSSetSeqData mps_setting Case %d (Mode : %d / TX Path : %d / MCS : %d)\n", + i, + (mps_setting[i] & BITS(24, 27)) >> 24, + (mps_setting[i] & BITS(8, 23)) >> 8, + (mps_setting[i] & BITS(0, 7))); + } + + i4Ret = MT_ATEMPSSetSeqData(prNetDev, u4Len, mps_setting, u4Band_idx); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(mps_setting); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_MPSSetPayloadLength(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 *mps_setting = NULL; + u32 u4Band_idx = 0; + u32 u4Offset = 0; + u32 u4Len = 0; + u32 i = 0; + u32 u4Value = 0; + + u4Len = ntohs(HqaCmdFrame->Length) / sizeof(u32) - 1; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MPSSetPayloadLength u4Len : %d\n", u4Len); + + mps_setting = kmalloc(sizeof(u32) * (u4Len), GFP_KERNEL); + + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 * 0, 4); + u4Band_idx = ntohl(u4Band_idx); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MPSSetPayloadLength u4Band_idx : %d\n", + u4Band_idx); + + for (i = 0; i < u4Len; i++) { + u4Offset = 4 + 4 * i; + if (u4Offset + 4 > sizeof(HqaCmdFrame->Data)) { /* Reserved at + * least 4 byte + * availbale data + */ + break; + } + memcpy(&u4Value, HqaCmdFrame->Data + 4 + 4 * i, 4); + mps_setting[i] = ntohl(u4Value); + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_MPSSetPayloadLength mps_setting Case %d (Payload Length : %d)\n", + i, + mps_setting[i]); + } + + i4Ret = MT_ATEMPSSetPayloadLength(prNetDev, u4Len, mps_setting, + u4Band_idx); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(mps_setting); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_MPSSetPacketCount(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 *mps_setting = NULL; + u32 u4Band_idx = 0; + u32 u4Offset = 0; + u32 u4Len = 0; + u32 i = 0; + u32 u4Value = 0; + + u4Len = ntohs(HqaCmdFrame->Length) / sizeof(u32) - 1; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MPSSetPacketCount u4Len : %d\n", u4Len); + + mps_setting = kmalloc(sizeof(u32) * (u4Len), GFP_KERNEL); + + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 * 0, 4); + u4Band_idx = ntohl(u4Band_idx); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MPSSetPacketCount u4Band_idx : %d\n", + u4Band_idx); + + for (i = 0; i < u4Len; i++) { + u4Offset = 4 + 4 * i; + if (u4Offset + 4 > sizeof(HqaCmdFrame->Data)) { /* Reserved at + * least 4 byte + * availbale data + */ + break; + } + memcpy(&u4Value, HqaCmdFrame->Data + 4 + 4 * i, 4); + mps_setting[i] = ntohl(u4Value); + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_MPSSetPacketCount mps_setting Case %d (Packet Count : %d)\n", + i, + mps_setting[i]); + } + + i4Ret = MT_ATEMPSSetPacketCount(prNetDev, u4Len, mps_setting, + u4Band_idx); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(mps_setting); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_MPSSetPowerGain(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 *mps_setting = NULL; + u32 u4Band_idx = 0; + u32 u4Offset = 0; + u32 u4Len = 0; + u32 i = 0; + u32 u4Value = 0; + + u4Len = ntohs(HqaCmdFrame->Length) / sizeof(u32) - 1; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MPSSetPowerGain u4Len : %d\n", u4Len); + + mps_setting = kmalloc(sizeof(u32) * (u4Len), GFP_KERNEL); + + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 * 0, 4); + u4Band_idx = ntohl(u4Band_idx); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MPSSetPowerGain u4Band_idx : %d\n", + u4Band_idx); + + for (i = 0; i < u4Len; i++) { + u4Offset = 4 + 4 * i; + if (u4Offset + 4 > sizeof(HqaCmdFrame->Data)) { /* Reserved at + * least 4 byte + * availbale data + */ + break; + } + memcpy(&u4Value, HqaCmdFrame->Data + 4 + 4 * i, 4); + mps_setting[i] = ntohl(u4Value); + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_MPSSetPowerGain mps_setting Case %d (Power : %d)\n", + i, + mps_setting[i]); + } + + i4Ret = MT_ATEMPSSetPowerGain(prNetDev, u4Len, mps_setting, u4Band_idx); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(mps_setting); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_MPSStart(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Band_idx = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MPSStart\n"); + + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 * 0, 4); + u4Band_idx = ntohl(u4Band_idx); + + MT_ATESetDBDCBandIndex(prNetDev, u4Band_idx); + MT_ATEStartTX(prNetDev, "TXFRAME"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_MPSStop(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Band_idx = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MPSStop\n"); + + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 * 0, 4); + u4Band_idx = ntohl(u4Band_idx); + + /* To Do : MPS Stop for Specific Band. */ + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_MPSSetNss(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 *mps_setting = NULL; + u32 u4Band_idx = 0; + u32 u4Offset = 0; + u32 u4Len = 0; + u32 i = 0; + u32 u4Value = 0; + + u4Len = ntohs(HqaCmdFrame->Length) / sizeof(u32) - 1; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MPSSetNss u4Len : %d\n", + u4Len); + + mps_setting = kmalloc(sizeof(u32) * (u4Len), GFP_KERNEL); + + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 * 0, 4); + u4Band_idx = ntohl(u4Band_idx); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MPSSetNss u4Band_idx : %d\n", u4Band_idx); + + for (i = 0; i < u4Len; i++) { + u4Offset = 4 + 4 * i; + if (u4Offset + 4 > sizeof(HqaCmdFrame->Data)) { /* Reserved at + * least 4 byte + * availbale data + */ + break; + } + memcpy(&u4Value, HqaCmdFrame->Data + 4 + 4 * i, 4); + mps_setting[i] = ntohl(u4Value); + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_MPSSetNss mps_setting Case %d (Nss : %d)\n", + i, + mps_setting[i]); + } + + i4Ret = MT_ATEMPSSetNss(prNetDev, u4Len, mps_setting, u4Band_idx); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(mps_setting); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_MPSSetPerpacketBW(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 *mps_setting = NULL; + u32 u4Band_idx = 0; + u32 u4Offset = 0; + u32 u4Len = 0; + u32 i = 0; + u32 u4Value = 0; + + u4Len = ntohs(HqaCmdFrame->Length) / sizeof(u32) - 1; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MPSSetPerpacketBW u4Len : %d\n", u4Len); + + mps_setting = kmalloc(sizeof(u32) * (u4Len), GFP_KERNEL); + + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 * 0, 4); + u4Band_idx = ntohl(u4Band_idx); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_MPSSetPerpacketBW u4Band_idx : %d\n", + u4Band_idx); + + for (i = 0; i < u4Len; i++) { + u4Offset = 4 + 4 * i; + if (u4Offset + 4 > sizeof(HqaCmdFrame->Data)) { /* Reserved at + * least 4 byte + * availbale data + */ + break; + } + memcpy(&u4Value, HqaCmdFrame->Data + 4 + 4 * i, 4); + mps_setting[i] = ntohl(u4Value); + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_MPSSetPerpacketBW mps_setting Case %d (BW : %d)\n", + i, + mps_setting[i]); + } + + i4Ret = MT_ATEMPSSetPerpacketBW(prNetDev, u4Len, mps_setting, + u4Band_idx); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(mps_setting); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetAIFS(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 SlotTime = 0; + u32 SifsTime = 0; + + memcpy(&SlotTime, HqaCmdFrame->Data + 4 * 0, 4); + SlotTime = ntohl(SlotTime); + memcpy(&SifsTime, HqaCmdFrame->Data + 4 * 1, 4); + SifsTime = ntohl(SifsTime); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetAIFS SlotTime = %d\n", + SlotTime); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_SetAIFS SifsTime = %d\n", + SifsTime); + + i4Ret = MT_ATESetTxIPG(prNetDev, SifsTime); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_CheckEfuseModeType(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 Value = u4EepromMode; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_CheckEfuseModeType\n"); + + /* + * Value: + * 1 -> efuse Mode + * 2 -> flash Mode + * 3 -> eeprom Mode + * 4 -> bin Mode + */ + Value = ntohl(Value); + memcpy(HqaCmdFrame->Data + 2, &(Value), sizeof(Value)); + + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_CheckEfuseNativeModeType(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_CheckEfuseNativeModeType\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_SetBandMode(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Band_mode = 0; + u32 u4Band_type = 0; + + memcpy((u8 *)&u4Band_mode, HqaCmdFrame->Data + 4 * 0, 4); + u4Band_mode = ntohl(u4Band_mode); + memcpy((u8 *)&u4Band_type, HqaCmdFrame->Data + 4 * 1, 4); + u4Band_type = ntohl(u4Band_type); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetBandMode u4Band_mode : %d\n", + u4Band_mode); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_SetBandMode u4Band_type : %d\n", + u4Band_type); + + if (u4Band_mode == 2) { + g_DBDCEnable = true; + }else if (u4Band_mode == 1) { + g_DBDCEnable = false; + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_GetBandMode(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Band_mode = 0; + u32 u4Band_idx = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 u4BufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + memcpy((u8 *)&u4Band_idx, HqaCmdFrame->Data, 4); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_GetBandMode u4Band_idx : %d\n", + u4Band_idx); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_DBDC_ENABLE; + if (g_DBDCEnable) { + rRfATInfo.u4FuncData = 1; + }else{ + rRfATInfo.u4FuncData = 0; + } + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_GetBandMode g_DBDCEnable = %d\n", + g_DBDCEnable); + + i4Ret = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Ret != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + if (u4Band_idx == 0) { + u4Band_mode = 3; + } else { + if (g_DBDCEnable) { + u4Band_mode = 3; + }else{ + u4Band_mode = 0; + } + } + + u4Band_mode = ntohl(u4Band_mode); + + memcpy(HqaCmdFrame->Data + 2, &(u4Band_mode), sizeof(u4Band_mode)); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2 + sizeof(u4Band_mode), i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_RDDStartExt(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_RDDStartExt\n"); + + DBGLOG(RFTEST, INFO, "[RDD DUMP START]\n"); + + i4Ret = MT_ATERDDStart(prNetDev, "RDDSTART"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_RDDStopExt(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_RDDStopExt\n"); + + i4Ret = MT_ATERDDStop(prNetDev, "RDDSTOP"); + + DBGLOG(RFTEST, INFO, "[RDD DUMP END]\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_BssInfoUpdate(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 OwnMacIdx = 0, BssIdx = 0; + u8 ucAddr1[MAC_ADDR_LEN]; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + memcpy(&OwnMacIdx, HqaCmdFrame->Data + 4 * 0, 4); + OwnMacIdx = ntohl(OwnMacIdx); + memcpy(&BssIdx, HqaCmdFrame->Data + 4 * 1, 4); + BssIdx = ntohl(BssIdx); + memcpy(ucAddr1, HqaCmdFrame->Data + 4 * 2, 6); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_BssInfoUpdate OwnMacIdx : %d\n", + OwnMacIdx); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_BssInfoUpdate BssIdx : %d\n", BssIdx); + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_BssInfoUpdate addr1:%02x:%02x:%02x:%02x:%02x:%02x\n", + ucAddr1[0], + ucAddr1[1], + ucAddr1[2], + ucAddr1[3], + ucAddr1[4], + ucAddr1[5]); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + OwnMacIdx, BssIdx, ucAddr1[0], ucAddr1[1], ucAddr1[2], + ucAddr1[3], ucAddr1[4], ucAddr1[5]); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_BssInfoUpdate(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_DevInfoUpdate(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 Band = 0, OwnMacIdx = 0; + u8 ucAddr1[MAC_ADDR_LEN]; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + memcpy(&Band, HqaCmdFrame->Data + 4 * 0, 4); + Band = ntohl(Band); + memcpy(&OwnMacIdx, HqaCmdFrame->Data + 4 * 1, 4); + OwnMacIdx = ntohl(OwnMacIdx); + memcpy(ucAddr1, HqaCmdFrame->Data + 4 * 2, 6); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_DevInfoUpdate Band : %d\n", + Band); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_DevInfoUpdate OwnMacIdx : %d\n", + OwnMacIdx); + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_DevInfoUpdate addr1:%02x:%02x:%02x:%02x:%02x:%02x\n", + ucAddr1[0], + ucAddr1[1], + ucAddr1[2], + ucAddr1[3], + ucAddr1[4], + ucAddr1[5]); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + OwnMacIdx, ucAddr1[0], ucAddr1[1], ucAddr1[2], ucAddr1[3], + ucAddr1[4], ucAddr1[5], Band); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_DevInfoUpdate(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_LogOnOff(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Band_idx = 0; + u32 u4Log_type = 0; + u32 u4Log_ctrl = 0; + u32 u4Log_size = 200; + + memcpy(&u4Band_idx, HqaCmdFrame->Data, 4); + u4Band_idx = ntohl(u4Band_idx); + memcpy(&u4Log_type, HqaCmdFrame->Data + 4, 4); + u4Log_type = ntohl(u4Log_type); + memcpy(&u4Log_ctrl, HqaCmdFrame->Data + 4 + 4, 4); + u4Log_ctrl = ntohl(u4Log_ctrl); + memcpy(&u4Log_size, HqaCmdFrame->Data + 4 + 4 + 4, 4); + u4Log_size = ntohl(u4Log_size); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_LogOnOff band_idx : %d\n", + u4Band_idx); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_LogOnOff log_type : %d\n", + u4Log_type); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_LogOnOff log_ctrl : %d\n", + u4Log_ctrl); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_LogOnOff log_size : %d\n", + u4Log_size); + + i4Ret = MT_ATELogOnOff(prNetDev, u4Log_type, u4Log_ctrl, u4Log_size); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +static HQA_CMD_HANDLER HQA_CMD_SET5[] = { + /* cmd id start from 0x1500 */ + HQA_GetFWInfo, /* 0x1500 */ + HQA_StartContinousTx, /* 0x1501 */ + HQA_SetSTBC, /* 0x1502 */ + HQA_SetShortGI, /* 0x1503 */ + HQA_SetDPD, /* 0x1504 */ + HQA_SetTssiOnOff, /* 0x1505 */ + HQA_GetRxStatisticsAll, /* 0x1506 */ + HQA_StartContiTxTone, /* 0x1507 */ + HQA_StopContiTxTone, /* 0x1508 */ + HQA_CalibrationTestMode, /* 0x1509 */ + HQA_DoCalibrationTestItem, /* 0x150A */ + HQA_eFusePhysicalWrite, /* 0x150B */ + HQA_eFusePhysicalRead, /* 0x150C */ + HQA_eFuseLogicalRead, /* 0x150D */ + HQA_eFuseLogicalWrite, /* 0x150E */ + HQA_TMRSetting, /* 0x150F */ + HQA_GetRxSNR, /* 0x1510 */ + HQA_WriteBufferDone, /* 0x1511 */ + HQA_FFT, /* 0x1512 */ + HQA_SetTxTonePower, /* 0x1513 */ + HQA_GetChipID, /* 0x1514 */ + HQA_MPSSetSeqData, /* 0x1515 */ + HQA_MPSSetPayloadLength, /* 0x1516 */ + HQA_MPSSetPacketCount, /* 0x1517 */ + HQA_MPSSetPowerGain, /* 0x1518 */ + HQA_MPSStart, /* 0x1519 */ + HQA_MPSStop, /* 0x151A */ + ToDoFunction, /* 0x151B */ + ToDoFunction, /* 0x151C */ + ToDoFunction, /* 0x151D */ + ToDoFunction, /* 0x151E */ + ToDoFunction, /* 0x151F */ + ToDoFunction, /* 0x1520 */ + HQA_SetAIFS, /* 0x1521 */ + HQA_CheckEfuseModeType, /* 0x1522 */ + HQA_CheckEfuseNativeModeType, /* 0x1523 */ + ToDoFunction, /* 0x1524 */ + ToDoFunction, /* 0x1525 */ + ToDoFunction, /* 0x1526 */ + ToDoFunction, /* 0x1527 */ + ToDoFunction, /* 0x1528 */ + ToDoFunction, /* 0x1529 */ + ToDoFunction, /* 0x152A */ + ToDoFunction, /* 0x152B */ + HQA_SetBandMode, /* 0x152C */ + HQA_GetBandMode, /* 0x152D */ + HQA_RDDStartExt, /* 0x152E */ + HQA_RDDStopExt, /* 0x152F */ + ToDoFunction, /* 0x1530 */ + HQA_BssInfoUpdate, /* 0x1531 */ + HQA_DevInfoUpdate, /* 0x1532 */ + HQA_LogOnOff, /* 0x1533 */ + ToDoFunction, /* 0x1534 */ + ToDoFunction, /* 0x1535 */ + HQA_MPSSetNss, /* 0x1536 */ + HQA_MPSSetPerpacketBW, /* 0x1537 */ +}; + +#if CFG_SUPPORT_TX_BF +static s32 HQA_TxBfProfileTagInValid(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 invalid = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(invalid), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagInValid\n"); + + memcpy(&invalid, HqaCmdFrame->Data, 4); + invalid = ntohl(invalid); + + kalMemSet(prInBuf, 0, sizeof(invalid)); + kalSprintf(prInBuf, "%u", invalid); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_InValid(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagPfmuIdx(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 pfmuidx = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(pfmuidx), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagPfmuIdx\n"); + + memcpy(&pfmuidx, HqaCmdFrame->Data, 4); + pfmuidx = ntohl(pfmuidx); + + kalMemSet(prInBuf, 0, sizeof(pfmuidx)); + kalSprintf(prInBuf, "%u", pfmuidx); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_PfmuIdx(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagBfType(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 bftype = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(bftype), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagBfType\n"); + + memcpy(&bftype, HqaCmdFrame->Data, 4); + bftype = ntohl(bftype); + + kalMemSet(prInBuf, 0, sizeof(bftype)); + kalSprintf(prInBuf, "%u", bftype); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_BfType(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagBw(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 tag_bw = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(tag_bw), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagBw\n"); + + memcpy(&tag_bw, HqaCmdFrame->Data, 4); + tag_bw = ntohl(tag_bw); + + kalMemSet(prInBuf, 0, sizeof(tag_bw)); + kalSprintf(prInBuf, "%u", tag_bw); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_DBW(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagSuMu(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 su_mu = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(su_mu), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagSuMu\n"); + + memcpy(&su_mu, HqaCmdFrame->Data, 4); + su_mu = ntohl(su_mu); + + kalMemSet(prInBuf, 0, sizeof(su_mu)); + kalSprintf(prInBuf, "%u", su_mu); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_SuMu(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagMemAlloc(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 col_idx0, row_idx0, col_idx1, row_idx1; + u32 col_idx2, row_idx2, col_idx3, row_idx3; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagMemAlloc\n"); + + memcpy(&col_idx0, HqaCmdFrame->Data + 4 * 0, 4); + col_idx0 = ntohl(col_idx0); + memcpy(&row_idx0, HqaCmdFrame->Data + 4 * 1, 4); + row_idx0 = ntohl(row_idx0); + memcpy(&col_idx1, HqaCmdFrame->Data + 4 * 2, 4); + col_idx1 = ntohl(col_idx1); + memcpy(&row_idx1, HqaCmdFrame->Data + 4 * 3, 4); + row_idx1 = ntohl(row_idx1); + memcpy(&col_idx2, HqaCmdFrame->Data + 4 * 4, 4); + col_idx2 = ntohl(col_idx2); + memcpy(&row_idx2, HqaCmdFrame->Data + 4 * 5, 4); + row_idx2 = ntohl(row_idx2); + memcpy(&col_idx3, HqaCmdFrame->Data + 4 * 6, 4); + col_idx3 = ntohl(col_idx3); + memcpy(&row_idx3, HqaCmdFrame->Data + 4 * 7, 4); + row_idx3 = ntohl(row_idx3); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", col_idx0, + row_idx0, col_idx1, row_idx1, col_idx2, row_idx2, col_idx3, + row_idx3); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_Mem(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagMatrix(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 nrow, ncol, ngroup, LM, code_book, htc_exist; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagMatrix\n"); + + memcpy(&nrow, HqaCmdFrame->Data + 4 * 0, 4); + nrow = ntohl(nrow); + memcpy(&ncol, HqaCmdFrame->Data + 4 * 1, 4); + ncol = ntohl(ncol); + memcpy(&ngroup, HqaCmdFrame->Data + 4 * 2, 4); + ngroup = ntohl(ngroup); + memcpy(&LM, HqaCmdFrame->Data + 4 * 3, 4); + LM = ntohl(LM); + memcpy(&code_book, HqaCmdFrame->Data + 4 * 4, 4); + code_book = ntohl(code_book); + memcpy(&htc_exist, HqaCmdFrame->Data + 4 * 5, 4); + htc_exist = ntohl(htc_exist); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x:%02x:%02x:%02x:%02x", nrow, ncol, ngroup, + LM, code_book, htc_exist); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_Matrix(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagSnr(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 snr_sts0, snr_sts1, snr_sts2, snr_sts3; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagSnr\n"); + + memcpy(&snr_sts0, HqaCmdFrame->Data + 4 * 0, 4); + snr_sts0 = ntohl(snr_sts0); + memcpy(&snr_sts1, HqaCmdFrame->Data + 4 * 1, 4); + snr_sts1 = ntohl(snr_sts1); + memcpy(&snr_sts2, HqaCmdFrame->Data + 4 * 2, 4); + snr_sts2 = ntohl(snr_sts2); + memcpy(&snr_sts3, HqaCmdFrame->Data + 4 * 3, 4); + snr_sts3 = ntohl(snr_sts3); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x:%02x:%02x", snr_sts0, snr_sts1, snr_sts2, + snr_sts3); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_SNR(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagSmtAnt(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 smt_ant = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(smt_ant), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagSmtAnt\n"); + + memcpy(&smt_ant, HqaCmdFrame->Data + 4 * 0, 4); + smt_ant = ntohl(smt_ant); + + kalMemSet(prInBuf, 0, sizeof(smt_ant)); + kalSprintf(prInBuf, "%u", smt_ant); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_SmartAnt(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagSeIdx(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 se_idx = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(se_idx), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagSeIdx\n"); + + memcpy(&se_idx, HqaCmdFrame->Data + 4 * 0, 4); + se_idx = ntohl(se_idx); + + kalMemSet(prInBuf, 0, sizeof(se_idx)); + kalSprintf(prInBuf, "%u", se_idx); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_SeIdx(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagRmsdThrd(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 rmsd_thrd = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(rmsd_thrd), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagRmsdThrd\n"); + + memcpy(&rmsd_thrd, HqaCmdFrame->Data + 4 * 0, 4); + rmsd_thrd = ntohl(rmsd_thrd); + + kalMemSet(prInBuf, 0, sizeof(rmsd_thrd)); + kalSprintf(prInBuf, "%u", rmsd_thrd); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_RmsdThrd(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagMcsThrd(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 mcs_lss0, mcs_sss0, mcs_lss1, mcs_sss1, mcs_lss2, mcs_sss2; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagMcsThrd\n"); + + memcpy(&mcs_lss0, HqaCmdFrame->Data + 4 * 0, 4); + mcs_lss0 = ntohl(mcs_lss0); + memcpy(&mcs_sss0, HqaCmdFrame->Data + 4 * 1, 4); + mcs_sss0 = ntohl(mcs_sss0); + memcpy(&mcs_lss1, HqaCmdFrame->Data + 4 * 2, 4); + mcs_lss1 = ntohl(mcs_lss1); + memcpy(&mcs_sss1, HqaCmdFrame->Data + 4 * 3, 4); + mcs_sss1 = ntohl(mcs_sss1); + memcpy(&mcs_lss2, HqaCmdFrame->Data + 4 * 4, 4); + mcs_lss2 = ntohl(mcs_lss2); + memcpy(&mcs_sss2, HqaCmdFrame->Data + 4 * 5, 4); + mcs_sss2 = ntohl(mcs_sss2); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x:%02x:%02x:%02x:%02x", mcs_lss0, mcs_sss0, + mcs_lss1, mcs_sss1, mcs_lss2, mcs_sss2); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_McsThrd(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagTimeOut(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 bf_tout = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(bf_tout), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagTimeOut\n"); + + memcpy(&bf_tout, HqaCmdFrame->Data + 4 * 0, 4); + bf_tout = ntohl(bf_tout); + + kalMemSet(prInBuf, 0, sizeof(bf_tout)); + kalSprintf(prInBuf, "%x", bf_tout); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_TimeOut(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagDesiredBw(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 desire_bw = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(desire_bw), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagDesiredBw\n"); + + memcpy(&desire_bw, HqaCmdFrame->Data + 4 * 0, 4); + desire_bw = ntohl(desire_bw); + + kalMemSet(prInBuf, 0, sizeof(desire_bw)); + kalSprintf(prInBuf, "%u", desire_bw); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_DesiredBW(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagDesiredNc(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 desire_nc = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(desire_nc), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagDesiredNc\n"); + + memcpy(&desire_nc, HqaCmdFrame->Data + 4 * 0, 4); + desire_nc = ntohl(desire_nc); + + kalMemSet(prInBuf, 0, sizeof(desire_nc)); + kalSprintf(prInBuf, "%u", desire_nc); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_DesiredNc(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagDesiredNr(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 desire_nr = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(desire_nr), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagDesiredNr\n"); + + memcpy(&desire_nr, HqaCmdFrame->Data + 4 * 0, 4); + desire_nr = ntohl(desire_nr); + + kalMemSet(prInBuf, 0, sizeof(desire_nr)); + kalSprintf(prInBuf, "%u", desire_nr); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTag_DesiredNr(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagWrite(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 idx = 0; /* WLAN_IDX */ + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(idx), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagWrite\n"); + + memcpy(&idx, HqaCmdFrame->Data + 4 * 0, 4); + idx = ntohl(idx); + + kalMemSet(prInBuf, 0, sizeof(idx)); + kalSprintf(prInBuf, "%u", idx); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTagWrite(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TxBfProfileTagRead(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 idx = 0, isBFer = 0; + u8 *prInBuf; + PFMU_PROFILE_TAG1 rPfmuTag1; + PFMU_PROFILE_TAG2 rPfmuTag2; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfProfileTagRead\n"); + + memcpy(&idx, HqaCmdFrame->Data + 4 * 0, 4); + idx = ntohl(idx); + memcpy(&isBFer, HqaCmdFrame->Data + 4 * 1, 4); + isBFer = ntohl(isBFer); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x", idx, isBFer); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileTagRead(prNetDev, prInBuf); + + rPfmuTag1.au4RawData[0] = ntohl(g_rPfmuTag1.au4RawData[0]); + rPfmuTag1.au4RawData[1] = ntohl(g_rPfmuTag1.au4RawData[1]); + rPfmuTag1.au4RawData[2] = ntohl(g_rPfmuTag1.au4RawData[2]); + rPfmuTag1.au4RawData[3] = ntohl(g_rPfmuTag1.au4RawData[3]); + + rPfmuTag2.au4RawData[0] = ntohl(g_rPfmuTag2.au4RawData[0]); + rPfmuTag2.au4RawData[1] = ntohl(g_rPfmuTag2.au4RawData[1]); + rPfmuTag2.au4RawData[2] = ntohl(g_rPfmuTag2.au4RawData[2]); + + memcpy(HqaCmdFrame->Data + 2, &rPfmuTag1, sizeof(PFMU_PROFILE_TAG1)); + memcpy(HqaCmdFrame->Data + 2 + sizeof(PFMU_PROFILE_TAG1), &rPfmuTag2, + sizeof(PFMU_PROFILE_TAG2)); + + ResponseToQA(HqaCmdFrame, prIwReqData, + 2 + sizeof(PFMU_PROFILE_TAG1) + sizeof(PFMU_PROFILE_TAG2), + i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_StaRecCmmUpdate(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 wlan_idx, bss_idx, aid; + u8 mac[MAC_ADDR_LEN]; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StaRecCmmUpdate\n"); + + memcpy(&wlan_idx, HqaCmdFrame->Data + 4 * 0, 4); + wlan_idx = ntohl(wlan_idx); + memcpy(&bss_idx, HqaCmdFrame->Data + 4 * 1, 4); + bss_idx = ntohl(bss_idx); + memcpy(&aid, HqaCmdFrame->Data + 4 * 2, 4); + aid = ntohl(aid); + + memcpy(mac, HqaCmdFrame->Data + 4 * 3, 6); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + wlan_idx, bss_idx, aid, mac[0], mac[1], mac[2], mac[3], + mac[4], mac[5]); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_StaRecCmmUpdate(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_StaRecBfUpdate(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 wlan_idx, bss_idx, PfmuId, su_mu, etxbf_cap, ndpa_rate, ndp_rate; + u32 report_poll_rate, tx_mode, nc, nr, cbw, spe_idx, tot_mem_req; + u32 mem_req_20m, mem_row0, mem_col0, mem_row1, mem_col1; + u32 mem_row2, mem_col2, mem_row3, mem_col3; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_StaRecBfUpdate\n"); + + memcpy(&wlan_idx, HqaCmdFrame->Data + 4 * 0, 4); + wlan_idx = ntohl(wlan_idx); + memcpy(&bss_idx, HqaCmdFrame->Data + 4 * 1, 4); + bss_idx = ntohl(bss_idx); + memcpy(&PfmuId, HqaCmdFrame->Data + 4 * 2, 4); + PfmuId = ntohl(PfmuId); + memcpy(&su_mu, HqaCmdFrame->Data + 4 * 3, 4); + su_mu = ntohl(su_mu); + memcpy(&etxbf_cap, HqaCmdFrame->Data + 4 * 4, 4); + etxbf_cap = ntohl(etxbf_cap); + memcpy(&ndpa_rate, HqaCmdFrame->Data + 4 * 5, 4); + ndpa_rate = ntohl(ndpa_rate); + memcpy(&ndp_rate, HqaCmdFrame->Data + 4 * 6, 4); + ndp_rate = ntohl(ndp_rate); + memcpy(&report_poll_rate, HqaCmdFrame->Data + 4 * 7, 4); + report_poll_rate = ntohl(report_poll_rate); + memcpy(&tx_mode, HqaCmdFrame->Data + 4 * 8, 4); + tx_mode = ntohl(tx_mode); + memcpy(&nc, HqaCmdFrame->Data + 4 * 9, 4); + nc = ntohl(nc); + memcpy(&nr, HqaCmdFrame->Data + 4 * 10, 4); + nr = ntohl(nr); + memcpy(&cbw, HqaCmdFrame->Data + 4 * 11, 4); + cbw = ntohl(cbw); + memcpy(&spe_idx, HqaCmdFrame->Data + 4 * 12, 4); + spe_idx = ntohl(spe_idx); + memcpy(&tot_mem_req, HqaCmdFrame->Data + 4 * 13, 4); + tot_mem_req = ntohl(tot_mem_req); + memcpy(&mem_req_20m, HqaCmdFrame->Data + 4 * 14, 4); + mem_req_20m = ntohl(mem_req_20m); + memcpy(&mem_row0, HqaCmdFrame->Data + 4 * 15, 4); + mem_row0 = ntohl(mem_row0); + memcpy(&mem_col0, HqaCmdFrame->Data + 4 * 16, 4); + mem_col0 = ntohl(mem_col0); + memcpy(&mem_row1, HqaCmdFrame->Data + 4 * 17, 4); + mem_row1 = ntohl(mem_row1); + memcpy(&mem_col1, HqaCmdFrame->Data + 4 * 18, 4); + mem_col1 = ntohl(mem_col1); + memcpy(&mem_row2, HqaCmdFrame->Data + 4 * 19, 4); + mem_row2 = ntohl(mem_row2); + memcpy(&mem_col2, HqaCmdFrame->Data + 4 * 20, 4); + mem_col2 = ntohl(mem_col2); + memcpy(&mem_row3, HqaCmdFrame->Data + 4 * 21, 4); + mem_row3 = ntohl(mem_row3); + memcpy(&mem_col3, HqaCmdFrame->Data + 4 * 22, 4); + mem_col3 = ntohl(mem_col3); + + /* For Tool wrong memory row and col num 20160501 */ + if (PfmuId == 0) { + mem_row0 = 0; + mem_col0 = 0; + mem_row1 = 1; + mem_col1 = 0; + mem_row2 = 2; + mem_col2 = 0; + mem_row3 = 3; + mem_col3 = 0; + } else if (PfmuId == 1) { + mem_row0 = 0; + mem_col0 = 2; + mem_row1 = 1; + mem_col1 = 2; + mem_row2 = 2; + mem_col2 = 2; + mem_row3 = 3; + mem_col3 = 2; + } + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf( + prInBuf, + "%02x:%02x:%02x:%02x:%02x:%02d:%02d:%02d:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + wlan_idx, + bss_idx, + PfmuId, + su_mu, + etxbf_cap, + ndpa_rate, + ndp_rate, + report_poll_rate, + tx_mode, + nc, + nr, + cbw, + spe_idx, + tot_mem_req, + mem_req_20m, + mem_row0, + mem_col0, + mem_row1, + mem_col1, + mem_row2, + mem_col2, + mem_row3, + mem_col3); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_StaRecBfUpdate(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_BFProfileDataRead(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 idx = 0, fgBFer = 0, subcarrIdx = 0, subcarr_start = 0, + subcarr_end = 0; + u32 NumOfsub = 0; + u32 offset = 0; + u8 *SubIdx = NULL; + u8 *prInBuf; + PFMU_DATA rPfmuData; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_BFProfileDataRead\n"); + + memcpy(&idx, HqaCmdFrame->Data + 4 * 0, 4); + idx = ntohl(idx); + memcpy(&fgBFer, HqaCmdFrame->Data + 4 * 1, 4); + fgBFer = ntohl(fgBFer); + memcpy(&subcarr_start, HqaCmdFrame->Data + 4 * 2, 4); + subcarr_start = ntohl(subcarr_start); + memcpy(&subcarr_end, HqaCmdFrame->Data + 4 * 3, 4); + subcarr_end = ntohl(subcarr_end); + + if (subcarr_end == (u32)0xffffffff) { /* avoid endless loop */ + DBGLOG(RFTEST, ERROR, "%s : subcarr_end(%lu) invalid.\n", + __func__, subcarr_end); + goto reply; + } + + NumOfsub = subcarr_end - subcarr_start + 1; + NumOfsub = ntohl(NumOfsub); + + memcpy(HqaCmdFrame->Data + 2, &NumOfsub, sizeof(NumOfsub)); + offset += sizeof(NumOfsub); + + for (subcarrIdx = subcarr_start; subcarrIdx <= subcarr_end; + subcarrIdx++) { + SubIdx = (u8 *)&subcarrIdx; + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x:%02x:%02x", idx, fgBFer, + SubIdx[1], SubIdx[0]); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileDataRead(prNetDev, prInBuf); + + rPfmuData.au4RawData[0] = ntohl(g_rPfmuData.au4RawData[0]); + rPfmuData.au4RawData[1] = ntohl(g_rPfmuData.au4RawData[1]); + rPfmuData.au4RawData[2] = ntohl(g_rPfmuData.au4RawData[2]); + rPfmuData.au4RawData[3] = ntohl(g_rPfmuData.au4RawData[3]); + rPfmuData.au4RawData[4] = ntohl(g_rPfmuData.au4RawData[4]); + + if (offset + 2 + sizeof(rPfmuData) > + sizeof(HqaCmdFrame->Data)) { + DBGLOG(RFTEST, + WARN, + "%s : offset(%lu) overflow, raw data read may not complete.\n", + __func__, + offset + 2 + sizeof(rPfmuData)); + break; + } + memcpy(HqaCmdFrame->Data + 2 + offset, &rPfmuData, + sizeof(rPfmuData)); + offset += sizeof(rPfmuData); + } + +reply: + ResponseToQA(HqaCmdFrame, prIwReqData, 2 + offset, i4Ret); + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_BFProfileDataWrite(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 pfmuid, subcarrier, phi11, psi21, phi21, psi31, phi31, psi41; + u32 phi22, psi32, phi32, psi42, phi33, psi43, snr00, snr01, snr02, + snr03; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_BFProfileDataWrite\n"); + + memcpy(&pfmuid, HqaCmdFrame->Data + 4 * 0, 4); + pfmuid = ntohl(pfmuid); + memcpy(&subcarrier, HqaCmdFrame->Data + 4 * 1, 4); + subcarrier = ntohl(subcarrier); + memcpy(&phi11, HqaCmdFrame->Data + 4 * 2, 4); + phi11 = ntohl(phi11); + memcpy(&psi21, HqaCmdFrame->Data + 4 * 3, 4); + psi21 = ntohl(psi21); + memcpy(&phi21, HqaCmdFrame->Data + 4 * 4, 4); + phi21 = ntohl(phi21); + memcpy(&psi31, HqaCmdFrame->Data + 4 * 5, 4); + psi31 = ntohl(psi31); + memcpy(&phi31, HqaCmdFrame->Data + 4 * 6, 4); + phi31 = ntohl(phi31); + memcpy(&psi41, HqaCmdFrame->Data + 4 * 7, 4); + psi41 = ntohl(psi41); + memcpy(&phi22, HqaCmdFrame->Data + 4 * 8, 4); + phi22 = ntohl(phi22); + memcpy(&psi32, HqaCmdFrame->Data + 4 * 9, 4); + psi32 = ntohl(psi32); + memcpy(&phi32, HqaCmdFrame->Data + 4 * 10, 4); + phi32 = ntohl(phi32); + memcpy(&psi42, HqaCmdFrame->Data + 4 * 11, 4); + psi42 = ntohl(psi42); + memcpy(&phi33, HqaCmdFrame->Data + 4 * 12, 4); + phi33 = ntohl(phi33); + memcpy(&psi43, HqaCmdFrame->Data + 4 * 13, 4); + psi43 = ntohl(psi43); + memcpy(&snr00, HqaCmdFrame->Data + 4 * 14, 4); + snr00 = ntohl(snr00); + memcpy(&snr01, HqaCmdFrame->Data + 4 * 15, 4); + snr01 = ntohl(snr01); + memcpy(&snr02, HqaCmdFrame->Data + 4 * 16, 4); + snr02 = ntohl(snr02); + memcpy(&snr03, HqaCmdFrame->Data + 4 * 17, 4); + snr03 = ntohl(snr03); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf( + prInBuf, + "%02x:%03x:%03x:%02x:%03x:%02x:%03x:%02x:%03x:%02x:%03x:%02x:%03x:%02x:%02x:%02x:%02x:%02x", + pfmuid, + subcarrier, + phi11, + psi21, + phi21, + psi31, + phi31, + psi41, + phi22, + psi32, + phi32, + psi42, + phi33, + psi43, + snr00, + snr01, + snr02, + snr03); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfProfileDataWrite(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_BFSounding(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 su_mu, mu_num, snd_interval, wlan_id0; + u32 wlan_id1, wlan_id2, wlan_id3, band_idx; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_BFSounding\n"); + + memcpy(&su_mu, HqaCmdFrame->Data + 4 * 0, 4); + su_mu = ntohl(su_mu); + memcpy(&mu_num, HqaCmdFrame->Data + 4 * 1, 4); + mu_num = ntohl(mu_num); + memcpy(&snd_interval, HqaCmdFrame->Data + 4 * 2, 4); + snd_interval = ntohl(snd_interval); + memcpy(&wlan_id0, HqaCmdFrame->Data + 4 * 3, 4); + wlan_id0 = ntohl(wlan_id0); + memcpy(&wlan_id1, HqaCmdFrame->Data + 4 * 4, 4); + wlan_id1 = ntohl(wlan_id1); + memcpy(&wlan_id2, HqaCmdFrame->Data + 4 * 5, 4); + wlan_id2 = ntohl(wlan_id2); + memcpy(&wlan_id3, HqaCmdFrame->Data + 4 * 6, 4); + wlan_id3 = ntohl(wlan_id3); + memcpy(&band_idx, HqaCmdFrame->Data + 4 * 7, 4); + band_idx = ntohl(band_idx); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x", su_mu, mu_num, + snd_interval, wlan_id0, wlan_id1, wlan_id2, wlan_id3); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_Trigger_Sounding_Proc(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_TXBFSoundingStop(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TXBFSoundingStop\n"); + + i4Ret = Set_Stop_Sounding_Proc(prNetDev, NULL); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +static s32 HQA_TXBFProfileDataWriteAllExt(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +static s32 HQA_TxBfTxApply(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 eBF_enable = 0; + u32 iBF_enable = 0; + u32 wlan_id = 0; + u32 MuTx_enable = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_TxBfTxApply\n"); + + memcpy(&eBF_enable, HqaCmdFrame->Data + 4 * 0, 4); + eBF_enable = ntohl(eBF_enable); + memcpy(&iBF_enable, HqaCmdFrame->Data + 4 * 1, 4); + iBF_enable = ntohl(iBF_enable); + memcpy(&wlan_id, HqaCmdFrame->Data + 4 * 2, 4); + wlan_id = ntohl(wlan_id); + memcpy(&MuTx_enable, HqaCmdFrame->Data + 4 * 3, 4); + MuTx_enable = ntohl(MuTx_enable); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x:%02x:%02x", wlan_id, eBF_enable, + iBF_enable, MuTx_enable); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfTxApply(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_ManualAssoc(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 type; + u32 wtbl_idx; + u32 ownmac_idx; + u32 phymode; + u32 bw; + u32 pfmuid; + u32 marate_mode; + u32 marate_mcs; + u32 spe_idx; + u32 aid; + u8 ucAddr1[MAC_ADDR_LEN]; + u32 nss = 1; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_ManualAssoc\n"); + + memcpy(&type, HqaCmdFrame->Data + 4 * 0, 4); + type = ntohl(type); + memcpy(&wtbl_idx, HqaCmdFrame->Data + 4 * 1, 4); + wtbl_idx = ntohl(wtbl_idx); + memcpy(&ownmac_idx, HqaCmdFrame->Data + 4 * 2, 4); + ownmac_idx = ntohl(ownmac_idx); + memcpy(&phymode, HqaCmdFrame->Data + 4 * 3, 4); + phymode = ntohl(phymode); + memcpy(&bw, HqaCmdFrame->Data + 4 * 4, 4); + bw = ntohl(bw); + memcpy(&pfmuid, HqaCmdFrame->Data + 4 * 5, 4); + pfmuid = ntohl(pfmuid); + memcpy(&marate_mode, HqaCmdFrame->Data + 4 * 6, 4); + marate_mode = ntohl(marate_mode); + memcpy(&marate_mcs, HqaCmdFrame->Data + 4 * 7, 4); + marate_mcs = ntohl(marate_mcs); + memcpy(&spe_idx, HqaCmdFrame->Data + 4 * 8, 4); + spe_idx = ntohl(spe_idx); + memcpy(&aid, HqaCmdFrame->Data + 4 * 9, 4); + aid = ntohl(aid); + memcpy(ucAddr1, HqaCmdFrame->Data + 4 * 10, 6); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf( + prInBuf, + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + ucAddr1[0], + ucAddr1[1], + ucAddr1[2], + ucAddr1[3], + ucAddr1[4], + ucAddr1[5], + type, + wtbl_idx, + ownmac_idx, + phymode, + bw, + nss, + pfmuid, + marate_mode, + marate_mcs, + spe_idx, + aid, + 0); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_TxBfManualAssoc(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static HQA_CMD_HANDLER HQA_TXBF_CMDS[] = { + HQA_TxBfProfileTagInValid, /* 0x1540 */ + HQA_TxBfProfileTagPfmuIdx, /* 0x1541 */ + HQA_TxBfProfileTagBfType, /* 0x1542 */ + HQA_TxBfProfileTagBw, /* 0x1543 */ + HQA_TxBfProfileTagSuMu, /* 0x1544 */ + HQA_TxBfProfileTagMemAlloc, /* 0x1545 */ + HQA_TxBfProfileTagMatrix, /* 0x1546 */ + HQA_TxBfProfileTagSnr, /* 0x1547 */ + HQA_TxBfProfileTagSmtAnt, /* 0x1548 */ + HQA_TxBfProfileTagSeIdx, /* 0x1549 */ + HQA_TxBfProfileTagRmsdThrd, /* 0x154A */ + HQA_TxBfProfileTagMcsThrd, /* 0x154B */ + HQA_TxBfProfileTagTimeOut, /* 0x154C */ + HQA_TxBfProfileTagDesiredBw, /* 0x154D */ + HQA_TxBfProfileTagDesiredNc, /* 0x154E */ + HQA_TxBfProfileTagDesiredNr, /* 0x154F */ + HQA_TxBfProfileTagWrite, /* 0x1550 */ + HQA_TxBfProfileTagRead, /* 0x1551 */ + HQA_StaRecCmmUpdate, /* 0x1552 */ + HQA_StaRecBfUpdate, /* 0x1553 */ + HQA_BFProfileDataRead, /* 0x1554 */ + HQA_BFProfileDataWrite, /* 0x1555 */ + HQA_BFSounding, /* 0x1556 */ + HQA_TXBFSoundingStop, /* 0x1557 */ + HQA_TXBFProfileDataWriteAllExt, /* 0x1558 */ + HQA_TxBfTxApply, /* 0x1559 */ + HQA_ManualAssoc, /* 0x155A */ +}; + +#if CFG_SUPPORT_MU_MIMO +static s32 HQA_MUGetInitMCS(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Gid = 0; + u32 u4User0InitMCS = 0; + u32 u4User1InitMCS = 0; + u32 u4User2InitMCS = 0; + u32 u4User3InitMCS = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MUGetInitMCS\n"); + + memcpy(&u4Gid, HqaCmdFrame->Data, 4); + u4Gid = ntohl(u4Gid); + + kalMemSet(prInBuf, 0, sizeof(u4Gid)); + kalSprintf(prInBuf, "%u", u4Gid); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_MUGetInitMCS(prNetDev, prInBuf); + + u4User0InitMCS = ntohl(u4User0InitMCS); + u4User1InitMCS = ntohl(u4User1InitMCS); + u4User2InitMCS = ntohl(u4User2InitMCS); + u4User3InitMCS = ntohl(u4User3InitMCS); + + memcpy(HqaCmdFrame->Data + 2, &u4User0InitMCS, sizeof(u32)); + memcpy(HqaCmdFrame->Data + 2 + 1 * sizeof(u32), &u4User1InitMCS, + sizeof(u32)); + memcpy(HqaCmdFrame->Data + 2 + 2 * sizeof(u32), &u4User2InitMCS, + sizeof(u32)); + memcpy(HqaCmdFrame->Data + 2 + 3 * sizeof(u32), &u4User3InitMCS, + sizeof(u32)); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_MUCalInitMCS(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Num_of_user; + u32 u4Bandwidth; + u32 u4Nss_of_user0; + u32 u4Nss_of_user1; + u32 u4Nss_of_user2; + u32 u4Nss_of_user3; + u32 u4Pf_mu_id_of_user0; + u32 u4Pf_mu_id_of_user1; + u32 u4Pf_mu_id_of_user2; + u32 u4Pf_mu_id_of_user3; + u32 u4Num_of_txer; /* number of antenna */ + u32 u4Spe_index; + u32 u4Group_index; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MUCalInitMCS\n"); + + memcpy(&u4Num_of_user, HqaCmdFrame->Data + 4 * 0, 4); + u4Num_of_user = ntohl(u4Num_of_user); + memcpy(&u4Bandwidth, HqaCmdFrame->Data + 4 * 1, 4); + u4Bandwidth = ntohl(u4Bandwidth); + memcpy(&u4Nss_of_user0, HqaCmdFrame->Data + 4 * 2, 4); + u4Nss_of_user0 = ntohl(u4Nss_of_user0); + memcpy(&u4Nss_of_user1, HqaCmdFrame->Data + 4 * 3, 4); + u4Nss_of_user1 = ntohl(u4Nss_of_user1); + memcpy(&u4Nss_of_user2, HqaCmdFrame->Data + 4 * 4, 4); + u4Nss_of_user2 = ntohl(u4Nss_of_user2); + memcpy(&u4Nss_of_user3, HqaCmdFrame->Data + 4 * 5, 4); + u4Nss_of_user3 = ntohl(u4Nss_of_user3); + memcpy(&u4Pf_mu_id_of_user0, HqaCmdFrame->Data + 4 * 6, 4); + u4Pf_mu_id_of_user0 = ntohl(u4Pf_mu_id_of_user0); + memcpy(&u4Pf_mu_id_of_user1, HqaCmdFrame->Data + 4 * 7, 4); + u4Pf_mu_id_of_user1 = ntohl(u4Pf_mu_id_of_user1); + memcpy(&u4Pf_mu_id_of_user2, HqaCmdFrame->Data + 4 * 8, 4); + u4Pf_mu_id_of_user2 = ntohl(u4Pf_mu_id_of_user2); + memcpy(&u4Pf_mu_id_of_user3, HqaCmdFrame->Data + 4 * 9, 4); + u4Pf_mu_id_of_user3 = ntohl(u4Pf_mu_id_of_user3); + memcpy(&u4Num_of_txer, HqaCmdFrame->Data + 4 * 10, 4); + u4Num_of_txer = ntohl(u4Num_of_txer); + memcpy(&u4Spe_index, HqaCmdFrame->Data + 4 * 11, 4); + u4Spe_index = ntohl(u4Spe_index); + memcpy(&u4Group_index, HqaCmdFrame->Data + 4 * 12, 4); + u4Group_index = ntohl(u4Group_index); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + u4Num_of_user, u4Bandwidth, u4Nss_of_user0, u4Nss_of_user1, + u4Pf_mu_id_of_user0, u4Pf_mu_id_of_user1, u4Num_of_txer, + u4Spe_index, u4Group_index); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_MUCalInitMCS(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_MUCalLQ(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Type = 0; + u32 u4Num_of_user; + u32 u4Bandwidth; + u32 u4Nss_of_user0; + u32 u4Nss_of_user1; + u32 u4Nss_of_user2; + u32 u4Nss_of_user3; + u32 u4Pf_mu_id_of_user0; + u32 u4Pf_mu_id_of_user1; + u32 u4Pf_mu_id_of_user2; + u32 u4Pf_mu_id_of_user3; + u32 u4Num_of_txer; /* number of antenna */ + u32 u4Spe_index; + u32 u4Group_index; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MUCalLQ\n"); + + memcpy(&u4Type, HqaCmdFrame->Data + 4 * 0, 4); + u4Type = ntohl(u4Type); + memcpy(&u4Num_of_user, HqaCmdFrame->Data + 4 * 1, 4); + u4Num_of_user = ntohl(u4Num_of_user); + memcpy(&u4Bandwidth, HqaCmdFrame->Data + 4 * 2, 4); + u4Bandwidth = ntohl(u4Bandwidth); + memcpy(&u4Nss_of_user0, HqaCmdFrame->Data + 4 * 3, 4); + u4Nss_of_user0 = ntohl(u4Nss_of_user0); + memcpy(&u4Nss_of_user1, HqaCmdFrame->Data + 4 * 4, 4); + u4Nss_of_user1 = ntohl(u4Nss_of_user1); + memcpy(&u4Nss_of_user2, HqaCmdFrame->Data + 4 * 5, 4); + u4Nss_of_user2 = ntohl(u4Nss_of_user2); + memcpy(&u4Nss_of_user3, HqaCmdFrame->Data + 4 * 6, 4); + u4Nss_of_user3 = ntohl(u4Nss_of_user3); + memcpy(&u4Pf_mu_id_of_user0, HqaCmdFrame->Data + 4 * 7, 4); + u4Pf_mu_id_of_user0 = ntohl(u4Pf_mu_id_of_user0); + memcpy(&u4Pf_mu_id_of_user1, HqaCmdFrame->Data + 4 * 8, 4); + u4Pf_mu_id_of_user1 = ntohl(u4Pf_mu_id_of_user1); + memcpy(&u4Pf_mu_id_of_user2, HqaCmdFrame->Data + 4 * 9, 4); + u4Pf_mu_id_of_user2 = ntohl(u4Pf_mu_id_of_user2); + memcpy(&u4Pf_mu_id_of_user3, HqaCmdFrame->Data + 4 * 10, 4); + u4Pf_mu_id_of_user3 = ntohl(u4Pf_mu_id_of_user3); + memcpy(&u4Num_of_txer, HqaCmdFrame->Data + 4 * 11, 4); + u4Num_of_txer = ntohl(u4Num_of_txer); + memcpy(&u4Spe_index, HqaCmdFrame->Data + 4 * 12, 4); + u4Spe_index = ntohl(u4Spe_index); + memcpy(&u4Group_index, HqaCmdFrame->Data + 4 * 13, 4); + u4Group_index = ntohl(u4Group_index); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + u4Num_of_user, u4Bandwidth, u4Nss_of_user0, u4Nss_of_user1, + u4Pf_mu_id_of_user0, u4Pf_mu_id_of_user1, u4Num_of_txer, + u4Spe_index, u4Group_index); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_MUCalLQ(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_MUGetLQ(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 i; + u8 u4LqReport[NUM_OF_USER * NUM_OF_MODUL]; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MUGetLQ\n"); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + kalMemSet(u4LqReport, 0, (NUM_OF_USER * NUM_OF_MODUL)); + + i4Ret = Set_MUGetLQ(prNetDev, prInBuf); + + for (i = 0; i < NUM_OF_USER * NUM_OF_MODUL; i++) { + u4LqReport[i] = ntohl(u4LqReport[i]); + memcpy(HqaCmdFrame->Data + 2 + i * sizeof(u32), &u4LqReport[i], + sizeof(u32)); + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_MUSetSNROffset(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Offset = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MUSetSNROffset\n"); + + memcpy(&u4Offset, HqaCmdFrame->Data + 4 * 0, 4); + u4Offset = ntohl(u4Offset); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x", u4Offset); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_MUSetSNROffset(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_MUSetZeroNss(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Zero_nss = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MUSetZeroNss\n"); + + memcpy(&u4Zero_nss, HqaCmdFrame->Data + 4 * 0, 4); + u4Zero_nss = ntohl(u4Zero_nss); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x", u4Zero_nss); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_MUSetZeroNss(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_MUSetSpeedUpLQ(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4SpeedUpLq = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MUSetSpeedUpLQ\n"); + + memcpy(&u4SpeedUpLq, HqaCmdFrame->Data + 4 * 0, 4); + u4SpeedUpLq = ntohl(u4SpeedUpLq); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x", u4SpeedUpLq); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_MUSetSpeedUpLQ(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_MUSetMUTable(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u8 *prTable; + u16 u2Len = 0; + u32 u4SuMu = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MUSetMUTable\n"); + + memcpy(&u4SuMu, HqaCmdFrame->Data + 4 * 0, 4); + u4SuMu = ntohl(u4SuMu); + + u2Len = ntohl(HqaCmdFrame->Length) - sizeof(u4SuMu); + if (u2Len > sizeof(HqaCmdFrame->Data) - 4) { + DBGLOG(RFTEST, ERROR, "%s : Invalid u2Len(%d).\n", __func__, + u2Len); + i4Ret = WLAN_STATUS_FAILURE; + goto error0; + } + prTable = kmalloc_array(u2Len, sizeof(u8), GFP_KERNEL); + if (!prTable) { + DBGLOG(RFTEST, ERROR, "%s : prTable allocate failed.\n", + __func__); + i4Ret = WLAN_STATUS_FAILURE; + goto error0; + } + memcpy(prTable, HqaCmdFrame->Data + 4, u2Len); + i4Ret = Set_MUSetMUTable(prNetDev, prTable); + kfree(prTable); + +error0: + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +static s32 HQA_MUSetGroup(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4GroupIndex, u4NumOfUser, u4User0Ldpc, u4User1Ldpc, u4User2Ldpc, + u4User3Ldpc; + u32 u4ShortGI, u4Bw, u4User0Nss, u4User1Nss, u4User2Nss, u4User3Nss; + u32 u4GroupId, u4User0UP, u4User1UP, u4User2UP, u4User3UP; + u32 u4User0MuPfId, u4User1MuPfId, u4User2MuPfId, u4User3MuPfId; + u32 u4User0InitMCS, u4User1InitMCS, u4User2InitMCS, u4User3InitMCS; + u8 ucAddr1[MAC_ADDR_LEN], ucAddr2[MAC_ADDR_LEN], ucAddr3[MAC_ADDR_LEN], + ucAddr4[MAC_ADDR_LEN]; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MUSetGroup\n"); + + memcpy(&u4GroupIndex, HqaCmdFrame->Data + 4 * 0, 4); + u4GroupIndex = ntohl(u4GroupIndex); + memcpy(&u4NumOfUser, HqaCmdFrame->Data + 4 * 1, 4); + u4NumOfUser = ntohl(u4NumOfUser); + memcpy(&u4User0Ldpc, HqaCmdFrame->Data + 4 * 2, 4); + u4User0Ldpc = ntohl(u4User0Ldpc); + memcpy(&u4User1Ldpc, HqaCmdFrame->Data + 4 * 3, 4); + u4User1Ldpc = ntohl(u4User1Ldpc); + memcpy(&u4User2Ldpc, HqaCmdFrame->Data + 4 * 4, 4); + u4User2Ldpc = ntohl(u4User2Ldpc); + memcpy(&u4User3Ldpc, HqaCmdFrame->Data + 4 * 5, 4); + u4User3Ldpc = ntohl(u4User3Ldpc); + memcpy(&u4ShortGI, HqaCmdFrame->Data + 4 * 6, 4); + u4ShortGI = ntohl(u4ShortGI); + memcpy(&u4Bw, HqaCmdFrame->Data + 4 * 7, 4); + u4Bw = ntohl(u4Bw); + memcpy(&u4User0Nss, HqaCmdFrame->Data + 4 * 8, 4); + u4User0Nss = ntohl(u4User0Nss); + memcpy(&u4User1Nss, HqaCmdFrame->Data + 4 * 9, 4); + u4User1Nss = ntohl(u4User1Nss); + memcpy(&u4User2Nss, HqaCmdFrame->Data + 4 * 10, 4); + u4User2Nss = ntohl(u4User2Nss); + memcpy(&u4User3Nss, HqaCmdFrame->Data + 4 * 11, 4); + u4User3Nss = ntohl(u4User3Nss); + memcpy(&u4GroupId, HqaCmdFrame->Data + 4 * 12, 4); + u4GroupId = ntohl(u4GroupId); + memcpy(&u4User0UP, HqaCmdFrame->Data + 4 * 13, 4); + u4User0UP = ntohl(u4User0UP); + memcpy(&u4User1UP, HqaCmdFrame->Data + 4 * 14, 4); + u4User1UP = ntohl(u4User1UP); + memcpy(&u4User2UP, HqaCmdFrame->Data + 4 * 15, 4); + u4User2UP = ntohl(u4User2UP); + memcpy(&u4User3UP, HqaCmdFrame->Data + 4 * 16, 4); + u4User3UP = ntohl(u4User3UP); + memcpy(&u4User0MuPfId, HqaCmdFrame->Data + 4 * 17, 4); + u4User0MuPfId = ntohl(u4User0MuPfId); + memcpy(&u4User1MuPfId, HqaCmdFrame->Data + 4 * 18, 4); + u4User1MuPfId = ntohl(u4User1MuPfId); + memcpy(&u4User2MuPfId, HqaCmdFrame->Data + 4 * 19, 4); + u4User2MuPfId = ntohl(u4User2MuPfId); + memcpy(&u4User3MuPfId, HqaCmdFrame->Data + 4 * 20, 4); + u4User3MuPfId = ntohl(u4User3MuPfId); + memcpy(&u4User0InitMCS, HqaCmdFrame->Data + 4 * 21, 4); + u4User0InitMCS = ntohl(u4User0InitMCS); + memcpy(&u4User1InitMCS, HqaCmdFrame->Data + 4 * 22, 4); + u4User1InitMCS = ntohl(u4User1InitMCS); + memcpy(&u4User2InitMCS, HqaCmdFrame->Data + 4 * 23, 4); + u4User2InitMCS = ntohl(u4User2InitMCS); + memcpy(&u4User3InitMCS, HqaCmdFrame->Data + 4 * 24, 4); + u4User3InitMCS = ntohl(u4User3InitMCS); + + memcpy(ucAddr1, HqaCmdFrame->Data + 4 * 25, 6); + memcpy(ucAddr2, HqaCmdFrame->Data + 4 * 25 + 6 * 1, 6); + memcpy(ucAddr3, HqaCmdFrame->Data + 4 * 25 + 6 * 2, 6); + memcpy(ucAddr4, HqaCmdFrame->Data + 4 * 25 + 6 * 3, 6); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf( + prInBuf, + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + u4GroupIndex, + u4NumOfUser, + u4User0Ldpc, + u4User1Ldpc, + u4ShortGI, + u4Bw, + u4User0Nss, + u4User1Nss, + u4GroupId, + u4User0UP, + u4User1UP, + u4User0MuPfId, + u4User1MuPfId, + u4User0InitMCS, + u4User1InitMCS, + ucAddr1[0], + ucAddr1[1], + ucAddr1[2], + ucAddr1[3], + ucAddr1[4], + ucAddr1[5], + ucAddr2[0], + ucAddr2[1], + ucAddr2[2], + ucAddr2[3], + ucAddr2[4], + ucAddr2[5]); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_MUSetGroup(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_MUGetQD(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4SubIdx = 0; + + /* TODO */ + u32 u4User0InitMCS = 0; + u32 u4User1InitMCS = 0; + u32 u4User2InitMCS = 0; + u32 u4User3InitMCS = 0; + + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MUGetQD\n"); + + memcpy(&u4SubIdx, HqaCmdFrame->Data, 4); + u4SubIdx = ntohl(u4SubIdx); + + kalMemSet(prInBuf, 0, sizeof(u4SubIdx)); + kalSprintf(prInBuf, "%u", u4SubIdx); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_MUGetQD(prNetDev, prInBuf); + + /* TODO */ + u4User0InitMCS = ntohl(u4User0InitMCS); + u4User1InitMCS = ntohl(u4User1InitMCS); + u4User2InitMCS = ntohl(u4User2InitMCS); + u4User3InitMCS = ntohl(u4User3InitMCS); + + memcpy(HqaCmdFrame->Data + 2, &u4User0InitMCS, sizeof(u32)); + memcpy(HqaCmdFrame->Data + 2 + 1 * sizeof(u32), &u4User1InitMCS, + sizeof(u32)); + memcpy(HqaCmdFrame->Data + 2 + 2 * sizeof(u32), &u4User2InitMCS, + sizeof(u32)); + memcpy(HqaCmdFrame->Data + 2 + 3 * sizeof(u32), &u4User3InitMCS, + sizeof(u32)); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_MUSetEnable(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Enable = 0; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MUSetEnable\n"); + + memcpy(&u4Enable, HqaCmdFrame->Data + 4 * 0, 4); + u4Enable = ntohl(u4Enable); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x", u4Enable); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_MUSetEnable(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_MUSetGID_UP(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 au4Gid[2]; + u32 au4Up[4]; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MUSetGID_UP\n"); + + memcpy(&au4Gid[0], HqaCmdFrame->Data + 4 * 0, 4); + au4Gid[0] = ntohl(au4Gid[0]); + memcpy(&au4Gid[1], HqaCmdFrame->Data + 4 * 1, 4); + au4Gid[1] = ntohl(au4Gid[1]); + memcpy(&au4Up[0], HqaCmdFrame->Data + 4 * 2, 4); + au4Up[0] = ntohl(au4Up[0]); + memcpy(&au4Up[1], HqaCmdFrame->Data + 4 * 3, 4); + au4Up[1] = ntohl(au4Up[1]); + memcpy(&au4Up[2], HqaCmdFrame->Data + 4 * 4, 4); + au4Up[2] = ntohl(au4Up[2]); + memcpy(&au4Up[3], HqaCmdFrame->Data + 4 * 5, 4); + au4Up[3] = ntohl(au4Up[3]); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf(prInBuf, "%02x:%02x:%02x:%02x:%02x:%02x", au4Gid[0], + au4Gid[1], au4Up[0], au4Up[1], au4Up[2], au4Up[3]); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_MUSetGID_UP(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static s32 HQA_MUTriggerTx(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4BandIdx, u4IsRandomPattern; + u32 u4MsduPayloadLength0, u4MsduPayloadLength1, u4MsduPayloadLength2, + u4MsduPayloadLength3; + u32 u4MuPacketCount, u4NumOfSTAs; + u8 ucAddr1[MAC_ADDR_LEN], ucAddr2[MAC_ADDR_LEN], ucAddr3[MAC_ADDR_LEN], + ucAddr4[MAC_ADDR_LEN]; + u8 *prInBuf; + + prInBuf = kmalloc(sizeof(u8) * (HQA_BF_STR_SIZE), GFP_KERNEL); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_MUTriggerTx\n"); + + memcpy(&u4BandIdx, HqaCmdFrame->Data + 4 * 0, 4); + u4BandIdx = ntohl(u4BandIdx); + memcpy(&u4IsRandomPattern, HqaCmdFrame->Data + 4 * 1, 4); + u4IsRandomPattern = ntohl(u4IsRandomPattern); + memcpy(&u4MsduPayloadLength0, HqaCmdFrame->Data + 4 * 2, 4); + u4MsduPayloadLength0 = ntohl(u4MsduPayloadLength0); + memcpy(&u4MsduPayloadLength1, HqaCmdFrame->Data + 4 * 3, 4); + u4MsduPayloadLength1 = ntohl(u4MsduPayloadLength1); + memcpy(&u4MsduPayloadLength2, HqaCmdFrame->Data + 4 * 4, 4); + u4MsduPayloadLength2 = ntohl(u4MsduPayloadLength2); + memcpy(&u4MsduPayloadLength3, HqaCmdFrame->Data + 4 * 5, 4); + u4MsduPayloadLength3 = ntohl(u4MsduPayloadLength3); + memcpy(&u4MuPacketCount, HqaCmdFrame->Data + 4 * 6, 4); + u4MuPacketCount = ntohl(u4MuPacketCount); + memcpy(&u4NumOfSTAs, HqaCmdFrame->Data + 4 * 7, 4); + u4NumOfSTAs = ntohl(u4NumOfSTAs); + memcpy(ucAddr1, HqaCmdFrame->Data + 4 * 8, 6); + memcpy(ucAddr2, HqaCmdFrame->Data + 4 * 8 + 6 * 1, 6); + memcpy(ucAddr3, HqaCmdFrame->Data + 4 * 8 + 6 * 2, 6); + memcpy(ucAddr4, HqaCmdFrame->Data + 4 * 8 + 6 * 3, 6); + + kalMemSet(prInBuf, 0, sizeof(u8) * (HQA_BF_STR_SIZE)); + kalSprintf( + prInBuf, + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + u4IsRandomPattern, + u4MsduPayloadLength0, + u4MsduPayloadLength1, + u4MuPacketCount, + u4NumOfSTAs, + ucAddr1[0], + ucAddr1[1], + ucAddr1[2], + ucAddr1[3], + ucAddr1[4], + ucAddr1[5], + ucAddr2[0], + ucAddr2[1], + ucAddr2[2], + ucAddr2[3], + ucAddr2[4], + ucAddr2[5]); + + DBGLOG(RFTEST, ERROR, "MT6632 prInBuf = %s\n", prInBuf); + + i4Ret = Set_MUTriggerTx(prNetDev, prInBuf); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + kfree(prInBuf); + + return i4Ret; +} + +static HQA_CMD_HANDLER HQA_TXMU_CMDS[] = { + HQA_MUGetInitMCS, /* 0x1560 */ + HQA_MUCalInitMCS, /* 0x1561 */ + HQA_MUCalLQ, /* 0x1562 */ + HQA_MUGetLQ, /* 0x1563 */ + HQA_MUSetSNROffset, /* 0x1564 */ + HQA_MUSetZeroNss, /* 0x1565 */ + HQA_MUSetSpeedUpLQ, /* 0x1566 */ + HQA_MUSetMUTable, /* 0x1567 */ + HQA_MUSetGroup, /* 0x1568 */ + HQA_MUGetQD, /* 0x1569 */ + HQA_MUSetEnable, /* 0x156A */ + HQA_MUSetGID_UP, /* 0x156B */ + HQA_MUTriggerTx, /* 0x156C */ +}; +#endif +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For ICAP + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 HQA_CapWiFiSpectrum(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 u4BufLen = 0; + u32 u4Control = 0; + u32 u4Trigger = 0; + u32 u4RingCapEn = 0; + u32 u4TriggerEvent = 0; + u32 u4CaptureNode = 0; + u32 u4CaptureLen = 0; + u32 u4CapStopCycle = 0; + u32 u4BW = 0; + /* u32 u4MacTriggerEvent = 0; */ /* Temp unused */ + /* u32 u4TriggerMac = 0; */ /* Temp unused */ + u32 u4WFNum; + u32 u4IQ; + u32 u4TempLen = 0; + u32 u4DataLen; + s32 i = 0, i4Ret = 0; + s32 *prIQAry; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + memcpy((u8 *)&u4Control, HqaCmdFrame->Data + 4 * 0, 4); + u4Control = ntohl(u4Control); + memcpy((u8 *)&u4Trigger, HqaCmdFrame->Data + 4 * 1, 4); + u4Trigger = ntohl(u4Trigger); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_CapWiFiSpectrum u4Control = %d\n", + u4Control); + + if (u4Control == 1 && u4Trigger == 1) { + memcpy((u8 *)&u4RingCapEn, HqaCmdFrame->Data + 4 * 2, 4); + u4RingCapEn = ntohl(u4RingCapEn); + memcpy((u8 *)&u4TriggerEvent, HqaCmdFrame->Data + 4 * 3, 4); + u4TriggerEvent = ntohl(u4TriggerEvent); + memcpy((u8 *)&u4CaptureNode, HqaCmdFrame->Data + 4 * 4, 4); + u4CaptureNode = ntohl(u4CaptureNode); + memcpy((u8 *)&u4CaptureLen, HqaCmdFrame->Data + 4 * 5, 4); + u4CaptureLen = ntohl(u4CaptureLen); + memcpy((u8 *)&u4CapStopCycle, HqaCmdFrame->Data + 4 * 6, 4); + u4CapStopCycle = ntohl(u4CapStopCycle); + memcpy((u8 *)&u4BW, HqaCmdFrame->Data + 4 * 7, 4); + u4BW = ntohl(u4BW); + + /* AT Command #1, Trigger always = 1 */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_CapWiFiSpectrum u4Trigger = %d\n", + u4Trigger); + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_CapWiFiSpectrum u4RingCapEn = %d\n", + u4RingCapEn); + /* AT Command #81 */ + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_CapWiFiSpectrum u4TriggerEvent = %d\n", + u4TriggerEvent); + /* AT Command #80 */ + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_CapWiFiSpectrum u4CaptureNode = %d\n", + u4CaptureNode); + /* AT Command #83 */ + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_CapWiFiSpectrum u4CaptureLen = %d\n", + u4CaptureLen); + /* AT Command #84 */ + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_CapWiFiSpectrum u4CapStopCycle = %d\n", + u4CapStopCycle); + /* AT Command #71 */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_CapWiFiSpectrum u4BW = %d\n", + u4BW); + + /* iwpriv wlan205 set_test_cmd 75 0 (J mode Setting) */ + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_J_MODE; + rRfATInfo.u4FuncData = 0; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + /* iwpriv wlan205 set_test_cmd 71 0 (Channel Bandwidth) */ + if (u4BW == 4) { + u4BW = 3; + }else if (u4BW == 3) { + u4BW = 4; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_CBW; + rRfATInfo.u4FuncData = u4BW; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + /* iwpriv wlan205 set_test_cmd 24 0 (ADC clock mode) */ + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_ADC_CLK_MODE; + rRfATInfo.u4FuncData = 0; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + /* iwpriv wlan205 set_test_cmd 84 18000 (Internal Capture + * Trigger Offset) */ + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_ICAP_TRIGGER_OFFSET; + rRfATInfo.u4FuncData = u4CapStopCycle; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + if (u4CaptureLen == 0) { + u4CaptureLen = 196615; /* 24000; */ + } + /* iwpriv wlan205 set_test_cmd 83 24576 (Internal Capture + * Size) */ + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_ICAP_SIZE; + rRfATInfo.u4FuncData = u4CaptureLen; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + /* iwpriv wlan205 set_test_cmd 80 0 (Internal Capture Content) + */ + if (u4CaptureNode == 0x6) { + u4CaptureNode = 0x10000006; + }else if (u4CaptureNode == 0x8) { + u4CaptureNode = 0x49; + }else if (u4CaptureNode == 0x9) { + u4CaptureNode = 0x48; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_ICAP_CONTENT; + rRfATInfo.u4FuncData = u4CaptureNode; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + /* iwpriv wlan205 set_test_cmd 81 0 (Internal Capture Trigger + * mode) */ + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_ICAP_MODE; + rRfATInfo.u4FuncData = u4TriggerEvent; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_ICAP_RING; + rRfATInfo.u4FuncData = u4RingCapEn; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + /* iwpriv wlan205 set_test_cmd 1 13 */ + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_COMMAND; + rRfATInfo.u4FuncData = RF_AT_COMMAND_CH_SWITCH_FOR_ICAP; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + /* iwpriv wlan205 set_test_cmd 1 11 */ + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_COMMAND; + rRfATInfo.u4FuncData = RF_AT_COMMAND_ICAP; + + rStatus = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + } else if (u4Control == 2) { + if (g_bCaptureDone) { + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_CapWiFiSpectrum Done!!!!!!!!!!!!!!!!!\n"); + i4Ret = 0; + /* Query whether ICAP Done */ + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + } else { + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT HQA_CapWiFiSpectrum Wait!!!!!!!!!!!!!!!!!\n"); + i4Ret = 1; + /* Query whether ICAP Done */ + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + } + } else if (u4Control == 3) { + memcpy((u8 *)&u4WFNum, HqaCmdFrame->Data + 4 * 1, 4); + u4WFNum = ntohl(u4WFNum); + memcpy((u8 *)&u4IQ, HqaCmdFrame->Data + 4 * 2, 4); + u4IQ = ntohl(u4IQ); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_CapWiFiSpectrum u4WFNum = %d\n", + u4WFNum); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_CapWiFiSpectrum u4IQ = %d\n", + u4IQ); + + if (u4WFNum <= 1) { + u4DataLen = 0; + GetIQData(&prIQAry, &u4DataLen, u4IQ, u4WFNum); + u4TempLen = u4DataLen; + u4DataLen /= 4; + + u4Control = ntohl(u4Control); + memcpy(HqaCmdFrame->Data + 2 + 4 * 0, (u8 *)&u4Control, + sizeof(u4Control)); + u4WFNum = ntohl(u4WFNum); + memcpy(HqaCmdFrame->Data + 2 + 4 * 1, (u8 *)&u4WFNum, + sizeof(u4WFNum)); + u4IQ = ntohl(u4IQ); + memcpy(HqaCmdFrame->Data + 2 + 4 * 2, (u8 *)&u4IQ, + sizeof(u4IQ)); + u4DataLen = ntohl(u4DataLen); + memcpy(HqaCmdFrame->Data + 2 + 4 * 3, (u8 *)&u4DataLen, + sizeof(u4DataLen)); + + for (i = 0; i < u4TempLen / sizeof(u32); i++) + prIQAry[i] = ntohl(prIQAry[i]); + + memcpy(HqaCmdFrame->Data + 2 + 4 * 4, (u8 *)&prIQAry[0], + u4TempLen); + } else { + u4TempLen = 0; + } + + /* Get IQ Data and transmit them to UI DLL */ + ResponseToQA(HqaCmdFrame, prIwReqData, 2 + 4 * 4 + u4TempLen, + i4Ret); + } else { + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + } + return rStatus; +} + +static HQA_CMD_HANDLER HQA_ICAP_CMDS[] = { + HQA_CapWiFiSpectrum, /* 0x1580 */ +}; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 hqa_set_channel_ext(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Ext_id = 0; + u32 u4Param_num = 0; + u32 u4Band_idx = 0; + u32 u4Central_ch0 = 0; + u32 u4Central_ch1 = 0; + u32 u4Sys_bw = 0; + u32 u4Perpkt_bw = 0; + u32 u4Pri_sel = 0; + u32 u4Reason = 0; + u32 u4Ch_band = 0; + u32 u4SetFreq = 0; + + memcpy(&u4Ext_id, HqaCmdFrame->Data + 4 * 0, 4); + u4Ext_id = ntohl(u4Ext_id); + memcpy(&u4Param_num, HqaCmdFrame->Data + 4 * 1, 4); + u4Param_num = ntohl(u4Param_num); + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 * 2, 4); + u4Band_idx = ntohl(u4Band_idx); + memcpy(&u4Central_ch0, HqaCmdFrame->Data + 4 * 3, 4); + u4Central_ch0 = ntohl(u4Central_ch0); + memcpy(&u4Central_ch1, HqaCmdFrame->Data + 4 * 4, 4); + u4Central_ch1 = ntohl(u4Central_ch1); + memcpy(&u4Sys_bw, HqaCmdFrame->Data + 4 * 5, 4); + u4Sys_bw = ntohl(u4Sys_bw); + memcpy(&u4Perpkt_bw, HqaCmdFrame->Data + 4 * 6, 4); + u4Perpkt_bw = ntohl(u4Perpkt_bw); + memcpy(&u4Pri_sel, HqaCmdFrame->Data + 4 * 7, 4); + u4Pri_sel = ntohl(u4Pri_sel); + memcpy(&u4Reason, HqaCmdFrame->Data + 4 * 8, 4); + u4Reason = ntohl(u4Reason); + memcpy(&u4Ch_band, HqaCmdFrame->Data + 4 * 9, 4); + u4Ch_band = ntohl(u4Ch_band); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_channel_ext ext_id : %d\n", u4Ext_id); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_channel_ext param_num : %d\n", + u4Param_num); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_channel_ext band_idx : %d\n", + u4Band_idx); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_channel_ext central_ch0 : %d\n", + u4Central_ch0); + /* for BW80+80 */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_channel_ext central_ch1 : %d\n", + u4Central_ch1); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_channel_ext sys_bw : %d\n", u4Sys_bw); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_channel_ext perpkt_bw : %d\n", + u4Perpkt_bw); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_channel_ext pri_sel : %d\n", + u4Pri_sel); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_channel_ext reason : %d\n", u4Reason); + /* 0:2.4G 1:5G */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_channel_ext ch_band : %d\n", + u4Ch_band); + + /* BW Mapping in QA Tool + * 0: BW20 + * 1: BW40 + * 2: BW80 + * 3: BW10 + * 4: BW5 + * 5: BW160C + * 6: BW160NC + */ + /* BW Mapping in MT6632 FW + * 0: BW20 + * 1: BW40 + * 2: BW80 + * 3: BW160C + * 4: BW160NC + * 5: BW5 + * 6: BW10 + */ + /* For POR Cal Setting - 20160601 */ + if ((u4Central_ch0 == u4Central_ch1) && (u4Sys_bw == 6) && + (u4Perpkt_bw == 6)) { + DBGLOG(RFTEST, INFO, "MT6632 : Wrong Setting for POR Cal\n"); + goto exit; + } + + MT_ATESetDBDCBandIndex(prNetDev, u4Band_idx); + if ((u4Central_ch0 >= 7 && u4Central_ch0 <= 16) && u4Ch_band == 1) { + /*Ch7 - Ch12, 5G (5035-5060)*/ + u4SetFreq = 1000 * (5000 + u4Central_ch0 * 5); + } else if (u4Central_ch0 == 6 && u4Ch_band == 1) { + u4SetFreq = 1000 * 5032; + } else { + u4SetFreq = nicChannelNum2Freq(u4Central_ch0); + } + MT_ATESetChannel(prNetDev, 0, u4SetFreq); + + if (u4Sys_bw == 6) { + u4SetFreq = nicChannelNum2Freq(u4Central_ch1); + MT_ATESetChannel(prNetDev, 1, u4SetFreq); + } + + MT_ATESetSystemBW(prNetDev, u4Sys_bw); + + /* For POR Cal Setting - 20160601 */ + if ((u4Sys_bw == 6) && (u4Perpkt_bw == 6)) { + MT_ATESetPerPacketBW(prNetDev, 5); + }else{ + MT_ATESetPerPacketBW(prNetDev, u4Perpkt_bw); + } + + MT_ATEPrimarySetting(prNetDev, u4Pri_sel); + /* PeiHsuan Memo : No Set Reason ? */ + MT_ATESetBand(prNetDev, u4Ch_band); + +exit: + u4Ext_id = ntohl(u4Ext_id); + memcpy(HqaCmdFrame->Data + 2, (u8 *)&u4Ext_id, sizeof(u4Ext_id)); + + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Ret); + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 hqa_set_txcontent_ext(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Len = 0; + u32 u4Ext_id = 0; + u32 u4Param_num = 0; + u32 u4Band_idx = 0; + u32 u4FC = 0; + u32 u4Dur = 0; + u32 u4Seq = 0; + u32 u4Gen_payload_rule = 0; + u32 u4Txlen = 0; + u32 u4Payload_len = 0; + u8 ucAddr1[MAC_ADDR_LEN]; + u8 ucAddr2[MAC_ADDR_LEN]; + u8 ucAddr3[MAC_ADDR_LEN]; + u32 ucPayload = 0; + + u4Len = ntohs(HqaCmdFrame->Length); + + memcpy(&u4Ext_id, HqaCmdFrame->Data + 4 * 0, 4); + u4Ext_id = ntohl(u4Ext_id); + memcpy(&u4Param_num, HqaCmdFrame->Data + 4 * 1, 4); + u4Param_num = ntohl(u4Param_num); + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 * 2, 4); + u4Band_idx = ntohl(u4Band_idx); + memcpy(&u4FC, HqaCmdFrame->Data + 4 * 3, 4); + u4FC = ntohl(u4FC); + memcpy(&u4Dur, HqaCmdFrame->Data + 4 * 4, 4); + u4Dur = ntohl(u4Dur); + memcpy(&u4Seq, HqaCmdFrame->Data + 4 * 5, 4); + u4Seq = ntohl(u4Seq); + memcpy(&u4Gen_payload_rule, HqaCmdFrame->Data + 4 * 6, 4); + u4Gen_payload_rule = ntohl(u4Gen_payload_rule); + memcpy(&u4Txlen, HqaCmdFrame->Data + 4 * 7, 4); + u4Txlen = ntohl(u4Txlen); + memcpy(&u4Payload_len, HqaCmdFrame->Data + 4 * 8, 4); + u4Payload_len = ntohl(u4Payload_len); + memcpy(ucAddr1, HqaCmdFrame->Data + 4 * 9, 6); + memcpy(ucAddr2, HqaCmdFrame->Data + 4 * 9 + 6 * 1, 6); + memcpy(ucAddr3, HqaCmdFrame->Data + 4 * 9 + 6 * 2, 6); + memcpy(&ucPayload, HqaCmdFrame->Data + 4 * 9 + 6 * 3, 1); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_txcontent_ext ext_id : %d\n", + u4Ext_id); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_txcontent_ext param_num : %d\n", + u4Param_num); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_txcontent_ext band_idx : %d\n", + u4Band_idx); + /* Frame Control...0800 : Beacon */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_txcontent_ext FC : 0x%x\n", u4FC); + /* Duration....NAV */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_txcontent_ext dur : 0x%x\n", u4Dur); + /* Sequence Control */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_txcontent_ext seq : 0x%x\n", u4Seq); + /* Normal:0,Repeat:1,Random:2 */ + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT hqa_set_txcontent_ext gen_payload_rule : %d\n", + u4Gen_payload_rule); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_txcontent_ext txlen : %d\n", u4Txlen); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_set_txcontent_ext payload_len : %d\n", + u4Payload_len); + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT hqa_set_txcontent_ext addr1:%02x:%02x:%02x:%02x:%02x:%02x\n", + ucAddr1[0], + ucAddr1[1], + ucAddr1[2], + ucAddr1[3], + ucAddr1[4], + ucAddr1[5]); + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT hqa_set_txcontent_ext addr2:%02x:%02x:%02x:%02x:%02x:%02x\n", + ucAddr2[0], + ucAddr2[1], + ucAddr2[2], + ucAddr2[3], + ucAddr2[4], + ucAddr2[5]); + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT hqa_set_txcontent_ext addr3:%02x:%02x:%02x:%02x:%02x:%02x\n", + ucAddr3[0], + ucAddr3[1], + ucAddr3[2], + ucAddr3[3], + ucAddr3[4], + ucAddr3[5]); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_start_tx_ext payload : 0x%x\n", + ucPayload); + + MT_ATESetDBDCBandIndex(prNetDev, u4Band_idx); + MT_ATESetMacHeader(prNetDev, u4FC, u4Dur, u4Seq); + MT_ATESetTxPayLoad(prNetDev, u4Gen_payload_rule, ucPayload); + MT_ATESetTxLength(prNetDev, u4Txlen); + MT_ATESetMACAddress(prNetDev, RF_AT_FUNCID_SET_MAC_ADDRESS, ucAddr1); + MT_ATESetMACAddress(prNetDev, RF_AT_FUNCID_SET_TA, ucAddr2); + /* PeiHsuan Memo : No Set Addr3 */ + + u4Ext_id = ntohl(u4Ext_id); + memcpy(HqaCmdFrame->Data + 2, (u8 *)&u4Ext_id, sizeof(u4Ext_id)); + ResponseToQA(HqaCmdFrame, prIwReqData, 2 + sizeof(u4Ext_id), i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 hqa_start_tx_ext(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Ext_id = 0; + u32 u4Param_num = 0; + u32 u4Band_idx = 0; + u32 u4Pkt_cnt = 0; + u32 u4Phymode = 0; + u32 u4Rate = 0; + u32 u4Pwr = 0; + u32 u4Stbc = 0; + u32 u4Ldpc = 0; + u32 u4iBF = 0; + u32 u4eBF = 0; + u32 u4Wlan_id = 0; + u32 u4Aifs = 0; + u32 u4Gi = 0; + u32 u4Tx_path = 0; + u32 u4Nss = 0; + + memcpy(&u4Ext_id, HqaCmdFrame->Data + 4 * 0, 4); + u4Ext_id = ntohl(u4Ext_id); + memcpy(&u4Param_num, HqaCmdFrame->Data + 4 * 1, 4); + u4Param_num = ntohl(u4Param_num); + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 * 2, 4); + u4Band_idx = ntohl(u4Band_idx); + memcpy(&u4Pkt_cnt, HqaCmdFrame->Data + 4 * 3, 4); + u4Pkt_cnt = ntohl(u4Pkt_cnt); + memcpy(&u4Phymode, HqaCmdFrame->Data + 4 * 4, 4); + u4Phymode = ntohl(u4Phymode); + memcpy(&u4Rate, HqaCmdFrame->Data + 4 * 5, 4); + u4Rate = ntohl(u4Rate); + memcpy(&u4Pwr, HqaCmdFrame->Data + 4 * 6, 4); + u4Pwr = ntohl(u4Pwr); + memcpy(&u4Stbc, HqaCmdFrame->Data + 4 * 7, 4); + u4Stbc = ntohl(u4Stbc); + memcpy(&u4Ldpc, HqaCmdFrame->Data + 4 * 8, 4); + u4Ldpc = ntohl(u4Ldpc); + memcpy(&u4iBF, HqaCmdFrame->Data + 4 * 9, 4); + u4iBF = ntohl(u4iBF); + memcpy(&u4eBF, HqaCmdFrame->Data + 4 * 10, 4); + u4eBF = ntohl(u4eBF); + memcpy(&u4Wlan_id, HqaCmdFrame->Data + 4 * 11, 4); + u4Wlan_id = ntohl(u4Wlan_id); + memcpy(&u4Aifs, HqaCmdFrame->Data + 4 * 12, 4); + u4Aifs = ntohl(u4Aifs); + memcpy(&u4Gi, HqaCmdFrame->Data + 4 * 13, 4); + u4Gi = ntohl(u4Gi); + memcpy(&u4Tx_path, HqaCmdFrame->Data + 4 * 14, 4); + u4Tx_path = ntohl(u4Tx_path); + memcpy(&u4Nss, HqaCmdFrame->Data + 4 * 15, 4); + u4Nss = ntohl(u4Nss); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_start_tx_ext ext_id : %d\n", + u4Ext_id); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_start_tx_ext param_num : %d\n", + u4Param_num); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_start_tx_ext band_idx : %d\n", + u4Band_idx); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_start_tx_ext pkt_cnt : %d\n", u4Pkt_cnt); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_start_tx_ext phymode : %d\n", u4Phymode); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_start_tx_ext rate : %d\n", + u4Rate); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_start_tx_ext pwr : %d\n", + u4Pwr); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_start_tx_ext stbc : %d\n", + u4Stbc); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_start_tx_ext ldpc : %d\n", + u4Ldpc); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_start_tx_ext ibf : %d\n", + u4iBF); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_start_tx_ext ebf : %d\n", + u4eBF); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_start_tx_ext wlan_id : %d\n", u4Wlan_id); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_start_tx_ext aifs : %d\n", + u4Aifs); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_start_tx_ext gi : %d\n", + u4Gi); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_start_tx_ext tx_path : %d\n", u4Tx_path); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_start_tx_ext nss : %d\n", + u4Nss); + + MT_ATESetDBDCBandIndex(prNetDev, u4Band_idx); + MT_ATESetTxCount(prNetDev, u4Pkt_cnt); + + if (u4Phymode == 1) { + u4Phymode = 0; + u4Rate += 4; + } else if ((u4Phymode == 0) && + ((u4Rate == 9) || (u4Rate == 10) || (u4Rate == 11))) { + u4Phymode = 1; + } + MT_ATESetPreamble(prNetDev, u4Phymode); + + if (u4Phymode == 0) { + u4Rate |= 0x00000000; + + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT CCK/OFDM (normal preamble) rate : %d\n", + u4Rate); + + MT_ATESetRate(prNetDev, u4Rate); + } else if (u4Phymode == 1) { + if (u4Rate == 9) { + u4Rate = 1; + }else if (u4Rate == 10) { + u4Rate = 2; + }else if (u4Rate == 11) { + u4Rate = 3; + } + u4Rate |= 0x00000000; + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT CCK (short preamble) rate : %d\n", + u4Rate); + + MT_ATESetRate(prNetDev, u4Rate); + } else if (u4Phymode >= 2 && u4Phymode <= 4) { + u4Rate |= 0x80000000; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HT/VHT rate : %d\n", + u4Rate); + + MT_ATESetRate(prNetDev, u4Rate); + } + + MT_ATESetTxPower0(prNetDev, u4Pwr); + MT_ATESetTxSTBC(prNetDev, u4Stbc); + MT_ATESetEncodeMode(prNetDev, u4Ldpc); + MT_ATESetiBFEnable(prNetDev, u4iBF); + MT_ATESeteBFEnable(prNetDev, u4eBF); + /* PeiHsuan Memo : No Set Wlan ID */ + MT_ATESetTxIPG(prNetDev, u4Aifs); + MT_ATESetTxGi(prNetDev, u4Gi); + MT_ATESetTxVhtNss(prNetDev, u4Nss); + MT_ATESetTxPath(prNetDev, u4Tx_path); + MT_ATEStartTX(prNetDev, "TXFRAME"); + + u4Ext_id = ntohl(u4Ext_id); + memcpy(HqaCmdFrame->Data + 2, (u8 *)&u4Ext_id, sizeof(u4Ext_id)); + ResponseToQA(HqaCmdFrame, prIwReqData, 2 + sizeof(u4Ext_id), i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 hqa_start_rx_ext(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Ext_id = 0; + u32 u4Param_num = 0; + u32 u4Band_idx = 0; + u32 u4Rx_path = 0; + u8 ucOwn_mac[MAC_ADDR_LEN]; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + u32 u4BufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + memcpy(&u4Ext_id, HqaCmdFrame->Data, 4); + u4Ext_id = ntohl(u4Ext_id); + memcpy(&u4Param_num, HqaCmdFrame->Data + 4, 4); + u4Param_num = ntohl(u4Param_num); + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 + 4, 4); + u4Band_idx = ntohl(u4Band_idx); + memcpy(ucOwn_mac, HqaCmdFrame->Data + 4 + 4 + 4, 6); + memcpy(&u4Rx_path, HqaCmdFrame->Data + 4 + 4 + 4 + 6, 4); + u4Rx_path = ntohl(u4Rx_path); + + memset(&g_HqaRxStat, 0, sizeof(PARAM_RX_STAT_T)); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_start_rx_ext ext_id : %d\n", + u4Ext_id); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_start_rx_ext param_num : %d\n", + u4Param_num); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_start_rx_ext band_idx : %d\n", + u4Band_idx); + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT hqa_start_rx_ext own_mac:%02x:%02x:%02x:%02x:%02x:%02x\n", + ucOwn_mac[0], + ucOwn_mac[1], + ucOwn_mac[2], + ucOwn_mac[3], + ucOwn_mac[4], + ucOwn_mac[5]); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_start_rx_ext rx_path : 0x%x\n", + u4Rx_path); + + u4RxStatSeqNum = 0; + + MT_ATESetDBDCBandIndex(prNetDev, u4Band_idx); + + rRfATInfo.u4FuncIndex = RF_AT_FUNCID_SET_RX_PATH; + rRfATInfo.u4FuncData = u4Rx_path << 16 | u4Band_idx; + + i4Ret = kalIoctl(prGlueInfo, /* prGlueInfo */ + wlanoidRftestSetAutoTest, /* pfnOidHandler */ + &rRfATInfo, /* pvInfoBuf */ + sizeof(rRfATInfo), /* u4InfoBufLen */ + false, /* fgRead */ + false, /* fgWaitResp */ + true, /* fgCmd */ + &u4BufLen); /* pu4QryInfoLen */ + + if (i4Ret != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + /* PeiHsuan Memo : No Set Own MAC Address */ + MT_ATEStartRX(prNetDev, "RXFRAME"); + + u4Ext_id = ntohl(u4Ext_id); + memcpy(HqaCmdFrame->Data + 2, (u8 *)&u4Ext_id, sizeof(u4Ext_id)); + ResponseToQA(HqaCmdFrame, prIwReqData, 2 + sizeof(u4Ext_id), i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 hqa_stop_tx_ext(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Ext_id = 0; + u32 u4Param_num = 0; + u32 u4Band_idx = 0; + + memcpy(&u4Ext_id, HqaCmdFrame->Data, 4); + u4Ext_id = ntohl(u4Ext_id); + memcpy(&u4Param_num, HqaCmdFrame->Data + 4, 4); + u4Param_num = ntohl(u4Param_num); + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 + 4, 4); + u4Band_idx = ntohl(u4Band_idx); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_stop_tx_ext ext_id : %d\n", + u4Ext_id); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_stop_tx_ext param_num : %d\n", + u4Param_num); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_stop_tx_ext band_idx : %d\n", u4Band_idx); + + MT_ATESetDBDCBandIndex(prNetDev, u4Band_idx); + MT_ATEStopTX(prNetDev, "TXSTOP"); + + u4Ext_id = ntohl(u4Ext_id); + memcpy(HqaCmdFrame->Data + 2, (u8 *)&u4Ext_id, sizeof(u4Ext_id)); + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Ret); + + return i4Ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 hqa_stop_rx_ext(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Ext_id = 0; + u32 u4Param_num = 0; + u32 u4Band_idx = 0; + + memcpy(&u4Ext_id, HqaCmdFrame->Data, 4); + u4Ext_id = ntohl(u4Ext_id); + memcpy(&u4Param_num, HqaCmdFrame->Data + 4, 4); + u4Param_num = ntohl(u4Param_num); + memcpy(&u4Band_idx, HqaCmdFrame->Data + 4 + 4, 4); + u4Band_idx = ntohl(u4Band_idx); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_stop_rx_ext ext_id : %d\n", + u4Ext_id); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_stop_rx_ext param_num : %d\n", + u4Param_num); + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT hqa_stop_rx_ext band_idx : %d\n", u4Band_idx); + + MT_ATESetDBDCBandIndex(prNetDev, u4Band_idx); + MT_ATEStopRX(prNetDev, "RXSTOP"); + + u4Ext_id = ntohl(u4Ext_id); + memcpy(HqaCmdFrame->Data + 2, (u8 *)&u4Ext_id, sizeof(u4Ext_id)); + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Ret); + + return i4Ret; +} + +static s32 HQA_iBFInit(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_iBFInit\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +static s32 HQA_iBFSetValue(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_iBFSetValue\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +static s32 HQA_iBFGetStatus(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_iBFGetStatus\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +static s32 HQA_iBFChanProfUpdate(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_iBFChanProfUpdate\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +static s32 HQA_iBFProfileRead(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_iBFProfileRead\n"); + + ResponseToQA(HqaCmdFrame, prIwReqData, 2, i4Ret); + + return i4Ret; +} + +static s32 HQA_IRRSetADC(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4WFIdx; + u32 u4ChFreq; + u32 u4BW; + u32 u4Sx; + u32 u4Band; + u32 u4Ext_id; + u32 u4RunType; + u32 u4FType; + + memcpy(&u4Ext_id, HqaCmdFrame->Data + 4 * 0, 4); + u4Ext_id = ntohl(u4Ext_id); + memcpy(&u4WFIdx, HqaCmdFrame->Data + 4 * 1, 4); + u4WFIdx = ntohl(u4WFIdx); + memcpy(&u4ChFreq, HqaCmdFrame->Data + 4 * 2, 4); + u4ChFreq = ntohl(u4ChFreq); + memcpy(&u4BW, HqaCmdFrame->Data + 4 * 3, 4); + u4BW = ntohl(u4BW); + memcpy(&u4Sx, HqaCmdFrame->Data + 4 * 4, 4); + u4Sx = ntohl(u4Sx); + memcpy(&u4Band, HqaCmdFrame->Data + 4 * 5, 4); + u4Band = ntohl(u4Band); + memcpy(&u4RunType, HqaCmdFrame->Data + 4 * 6, 4); + u4RunType = ntohl(u4RunType); + memcpy(&u4FType, HqaCmdFrame->Data + 4 * 7, 4); + u4FType = ntohl(u4FType); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetADC ext_id : %d\n", + u4Ext_id); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetADC u4WFIdx : %d\n", + u4WFIdx); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetADC u4ChFreq : %d\n", + u4ChFreq); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetADC u4BW : %d\n", + u4BW); + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetADC u4Sx : %d\n", + u4Sx); /* SX : 0, 2 */ + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetADC u4Band : %d\n", + u4Band); + /* RunType : 0 -> QA, 1 -> ATE */ + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetADC u4RunType : %d\n", + u4RunType); + /* FType : 0 -> FI, 1 -> FD */ + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetADC u4FType : %d\n", + u4FType); + + i4Ret = MT_ATE_IRRSetADC(prNetDev, u4WFIdx, u4ChFreq, u4BW, u4Sx, + u4Band, u4RunType, u4FType); + + u4Ext_id = ntohl(u4Ext_id); + memcpy(HqaCmdFrame->Data + 2, (u8 *)&u4Ext_id, sizeof(u4Ext_id)); + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Ret); + + return i4Ret; +} + +static s32 HQA_IRRSetRxGain(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4PgaLpfg; + u32 u4Lna; + u32 u4Band; + u32 u4WF_inx; + u32 u4Rfdgc; + u32 u4Ext_id; + + memcpy(&u4Ext_id, HqaCmdFrame->Data + 4 * 0, 4); + u4Ext_id = ntohl(u4Ext_id); + memcpy(&u4PgaLpfg, HqaCmdFrame->Data + 4 * 1, 4); + u4PgaLpfg = ntohl(u4PgaLpfg); + memcpy(&u4Lna, HqaCmdFrame->Data + 4 * 2, 4); + u4Lna = ntohl(u4Lna); + memcpy(&u4Band, HqaCmdFrame->Data + 4 * 3, 4); + u4Band = ntohl(u4Band); + memcpy(&u4WF_inx, HqaCmdFrame->Data + 4 * 4, 4); + u4WF_inx = ntohl(u4WF_inx); + memcpy(&u4Rfdgc, HqaCmdFrame->Data + 4 * 5, 4); + u4Rfdgc = ntohl(u4Rfdgc); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetRxGain ext_id : %d\n", + u4Ext_id); + /* PGA is for MT663, LPFG is for MT7615 */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_IRRSetRxGain u4PgaLpfg : %d\n", + u4PgaLpfg); + /* 5 : UH, 4 : H, 3 : M, 2 : L, 1 : UL */ + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetRxGain u4Lna : %d\n", + u4Lna); + /* DBDC band0 or band1 */ + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetRxGain u4Band : %d\n", + u4Band); + /* (each bit for each WF) */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_IRRSetRxGain u4WF_inx : 0x%x\n", + u4WF_inx); + /* only for MT6632 */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_IRRSetRxGain u4Rfdgc : %d\n", u4Rfdgc); + + i4Ret = MT_ATE_IRRSetRxGain(prNetDev, u4PgaLpfg, u4Lna, u4Band, + u4WF_inx, u4Rfdgc); + + u4Ext_id = ntohl(u4Ext_id); + memcpy(HqaCmdFrame->Data + 2, (u8 *)&u4Ext_id, sizeof(u4Ext_id)); + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Ret); + + return i4Ret; +} + +static s32 HQA_IRRSetTTG(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Ext_id; + u32 u4TTGPwrIdx; + u32 u4ChFreq; + u32 u4FIToneFreq; + u32 u4Band; + + memcpy(&u4Ext_id, HqaCmdFrame->Data + 4 * 0, 4); + u4Ext_id = ntohl(u4Ext_id); + memcpy(&u4TTGPwrIdx, HqaCmdFrame->Data + 4 * 1, 4); + u4TTGPwrIdx = ntohl(u4TTGPwrIdx); + memcpy(&u4ChFreq, HqaCmdFrame->Data + 4 * 2, 4); + u4ChFreq = ntohl(u4ChFreq); + memcpy(&u4FIToneFreq, HqaCmdFrame->Data + 4 * 3, 4); + u4FIToneFreq = ntohl(u4FIToneFreq); + memcpy(&u4Band, HqaCmdFrame->Data + 4 * 4, 4); + u4Band = ntohl(u4Band); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetTTG ext_id : %d\n", + u4Ext_id); + /* TTG Power Index: Power index value 0~15 */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_IRRSetTTG u4TTGPwrIdx : %d\n", + u4TTGPwrIdx); + /* Ch Freq: channel frequency value */ + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetTTG u4ChFreq : %d\n", + u4ChFreq); + /* FI Tone Freq(float): driver calculate TTG Freq(TTG Freq = Ch_freq + + * FI tone freq) */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_IRRSetTTG u4FIToneFreq : %d\n", + u4FIToneFreq); + /* Band: DBDC band0 or band1 */ + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT HQA_IRRSetTTG u4Band : %d\n", + u4Band); + + i4Ret = MT_ATE_IRRSetTTG(prNetDev, u4TTGPwrIdx, u4ChFreq, u4FIToneFreq, + u4Band); + + u4Ext_id = ntohl(u4Ext_id); + memcpy(HqaCmdFrame->Data + 2, (u8 *)&u4Ext_id, sizeof(u4Ext_id)); + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Ret); + + return i4Ret; +} + +static s32 HQA_IRRSetTrunOnTTG(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + u32 u4Ext_id; + u32 u4TTGOnOff; + u32 u4Band; + u32 u4WF_inx = 0; + + memcpy(&u4Ext_id, HqaCmdFrame->Data + 4 * 0, 4); + u4Ext_id = ntohl(u4Ext_id); + memcpy(&u4TTGOnOff, HqaCmdFrame->Data + 4 * 1, 4); + u4TTGOnOff = ntohl(u4TTGOnOff); + memcpy(&u4Band, HqaCmdFrame->Data + 4 * 2, 4); + u4Band = ntohl(u4Band); + + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_IRRSetTrunOnTTG ext_id : %d\n", u4Ext_id); + /* TTG on/off: 0:off, 1: on */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_IRRSetTrunOnTTG u4TTGOnOff : %d\n", + u4TTGOnOff); + /* Band: DBDC band0 or band1 */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_IRRSetTrunOnTTG u4Band : %d\n", u4Band); + /* (each bit for each WF) */ + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT HQA_IRRSetTrunOnTTG u4WF_inx : %d\n", + u4WF_inx); + + i4Ret = MT_ATE_IRRSetTrunOnTTG(prNetDev, u4TTGOnOff, u4Band, u4WF_inx); + + u4Ext_id = ntohl(u4Ext_id); + memcpy(HqaCmdFrame->Data + 2, (u8 *)&u4Ext_id, sizeof(u4Ext_id)); + ResponseToQA(HqaCmdFrame, prIwReqData, 6, i4Ret); + + return i4Ret; +} + +static HQA_CMD_HANDLER hqa_ext_cmd_set[] = { + NULL, + hqa_set_channel_ext, /* 0x00000001 */ + hqa_set_txcontent_ext, /* 0x00000002 */ + hqa_start_tx_ext, /* 0x00000003 */ + hqa_start_rx_ext, /* 0x00000004 */ + hqa_stop_tx_ext, /* 0x00000005 */ + hqa_stop_rx_ext, /* 0x00000006 */ + HQA_iBFInit, /* 0x00000007 */ + HQA_iBFSetValue, /* 0x00000008 */ + HQA_iBFGetStatus, /* 0x00000009 */ + HQA_iBFChanProfUpdate, /* 0x0000000A */ + HQA_iBFProfileRead, /* 0x0000000B */ + ToDoFunction, /* 0x0000000C */ + ToDoFunction, /* 0x0000000D */ + ToDoFunction, /* 0x0000000E */ + ToDoFunction, /* 0x0000000F */ + ToDoFunction, /* 0x00000010 */ + ToDoFunction, /* 0x00000011 */ + ToDoFunction, /* 0x00000012 */ + ToDoFunction, /* 0x00000013 */ + ToDoFunction, /* 0x00000014 */ + ToDoFunction, /* 0x00000015 */ + ToDoFunction, /* 0x00000016 */ + ToDoFunction, /* 0x00000017 */ + ToDoFunction, /* 0x00000018 */ + ToDoFunction, /* 0x00000019 */ + ToDoFunction, /* 0x0000001A */ + ToDoFunction, /* 0x0000001B */ + ToDoFunction, /* 0x0000001C */ + ToDoFunction, /* 0x0000001D */ + ToDoFunction, /* 0x0000001E */ + ToDoFunction, /* 0x0000001F */ + HQA_IRRSetADC, /* 0x00000020 */ + HQA_IRRSetRxGain, /* 0x00000021 */ + HQA_IRRSetTTG, /* 0x00000022 */ + HQA_IRRSetTrunOnTTG, /* 0x00000023 */ +}; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Extension Commands (For MT7615). + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +static s32 hqa_ext_cmds(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Ret = 0; + s32 i4Idx = 0; + + memmove((u8 *)&i4Idx, (u8 *)&HqaCmdFrame->Data, 4); + i4Idx = ntohl(i4Idx); + + DBGLOG(RFTEST, INFO, "MT6632 : QA_AGENT hqa_ext_cmds index : %d\n", + i4Idx); + + if (i4Idx < (sizeof(hqa_ext_cmd_set) / sizeof(HQA_CMD_HANDLER))) { + if (hqa_ext_cmd_set[i4Idx] != NULL) { + i4Ret = (*hqa_ext_cmd_set[i4Idx])(prNetDev, prIwReqData, + HqaCmdFrame); + } else { + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT hqa_ext_cmds cmd idx %d is NULL : %d\n", + i4Idx); + } + } else { + DBGLOG(RFTEST, + INFO, + "MT6632 : QA_AGENT hqa_ext_cmds cmd idx %d is not supported : %d\n", + i4Idx); + } + + return i4Ret; +} + +static HQA_CMD_HANDLER HQA_CMD_SET6[] = { + /* cmd id start from 0x1600 */ + hqa_ext_cmds, /* 0x1600 */ +}; + +static HQA_CMD_TABLE HQA_CMD_TABLES[] = { + { + HQA_CMD_SET0, + sizeof(HQA_CMD_SET0) / sizeof(HQA_CMD_HANDLER), + 0x1000, + }, + { + HQA_CMD_SET1, + sizeof(HQA_CMD_SET1) / sizeof(HQA_CMD_HANDLER), + 0x1100, + }, + { + HQA_CMD_SET2, + sizeof(HQA_CMD_SET2) / sizeof(HQA_CMD_HANDLER), + 0x1200, + }, + { + HQA_CMD_SET3, + sizeof(HQA_CMD_SET3) / sizeof(HQA_CMD_HANDLER), + 0x1300, + }, + { + HQA_CMD_SET4, + sizeof(HQA_CMD_SET4) / sizeof(HQA_CMD_HANDLER), + 0x1400, + }, + { + HQA_CMD_SET5, + sizeof(HQA_CMD_SET5) / sizeof(HQA_CMD_HANDLER), + 0x1500, + }, +#if CFG_SUPPORT_TX_BF + { + HQA_TXBF_CMDS, + sizeof(HQA_TXBF_CMDS) / sizeof(HQA_CMD_HANDLER), + 0x1540, + }, +#if CFG_SUPPORT_MU_MIMO + { + HQA_TXMU_CMDS, + sizeof(HQA_TXMU_CMDS) / sizeof(HQA_CMD_HANDLER), + 0x1560, + }, +#endif +#endif + { + HQA_ICAP_CMDS, + sizeof(HQA_ICAP_CMDS) / sizeof(HQA_CMD_HANDLER), + 0x1580, + }, + { + HQA_CMD_SET6, + sizeof(HQA_CMD_SET6) / sizeof(HQA_CMD_HANDLER), + 0x1600, + }, +}; + +/*----------------------------------------------------------------------------*/ +/*! + * \brief QA Agent For Handle Ethernet command by Command Idx. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqData + * \param[in] HqaCmdFrame Ethernet Frame Format receive from QA Tool DLL + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +int HQA_CMDHandler(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame) +{ + s32 i4Status = 0; + u32 u4CmdId; + u32 u4TableIndex = 0; + + u4CmdId = ntohs(HqaCmdFrame->Id); + + while (u4TableIndex < + (sizeof(HQA_CMD_TABLES) / sizeof(HQA_CMD_TABLE))) { + int CmdIndex = 0; + + CmdIndex = u4CmdId - HQA_CMD_TABLES[u4TableIndex].CmdOffset; + if ((CmdIndex >= 0) && + (CmdIndex < HQA_CMD_TABLES[u4TableIndex].CmdSetSize)) { + HQA_CMD_HANDLER *pCmdSet; + + pCmdSet = HQA_CMD_TABLES[u4TableIndex].CmdSet; + + if (pCmdSet[CmdIndex] != NULL) { + i4Status = (*pCmdSet[CmdIndex])( + prNetDev, prIwReqData, HqaCmdFrame); + } + break; + } + u4TableIndex++; + } + + return i4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Ioctl entry from ATE Daemon. + * + * \param[in] prNetDev Pointer to the Net Device + * \param[in] prIwReqInfo + * \param[in] prIwReqData + * \param[in] pcExtra + * \param[out] None + * + * \retval 0 On success. + */ +/*----------------------------------------------------------------------------*/ +int priv_qa_agent(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN char *pcExtra) +{ + s32 i4Status = 0; + HQA_CMD_FRAME *HqaCmdFrame; + u32 u4ATEMagicNum, u4ATEId, u4ATEData; + + HqaCmdFrame = kmalloc(sizeof(*HqaCmdFrame), GFP_KERNEL); + + if (!HqaCmdFrame) { + i4Status = -ENOMEM; + goto ERROR0; + } + + memset(HqaCmdFrame, 0, sizeof(*HqaCmdFrame)); + + if (!prIwReqData || prIwReqData->data.length == 0 || + prIwReqData->data.length > sizeof(*HqaCmdFrame)) { + DBGLOG(RFTEST, WARN, "%s: Invalid length:%d > %d\n", __func__, + prIwReqData->data.length, sizeof(*HqaCmdFrame)); + i4Status = -EFAULT; + goto ERROR1; + } + + if (copy_from_user(HqaCmdFrame, prIwReqData->data.pointer, + prIwReqData->data.length)) { + i4Status = -EFAULT; + goto ERROR1; + } + + u4ATEMagicNum = ntohl(HqaCmdFrame->MagicNo); + u4ATEId = ntohs(HqaCmdFrame->Id); + memcpy((u8 *)&u4ATEData, HqaCmdFrame->Data, 4); + u4ATEData = ntohl(u4ATEData); + + switch (u4ATEMagicNum) { + case HQA_CMD_MAGIC_NO: + i4Status = HQA_CMDHandler(prNetDev, prIwReqData, HqaCmdFrame); + break; + + default: + i4Status = -EINVAL; + DBGLOG(RFTEST, INFO, + "MT6632 : QA_AGENT ATEMagicNum Error!!!\n"); + break; + } + +ERROR1: + kfree(HqaCmdFrame); +ERROR0: + return i4Status; +} + +int priv_set_eeprom_mode(IN u32 u4Mode) +{ + if ((u4Mode != EFUSE_MODE) && (u4Mode != BUFFER_BIN_MODE)) { + return -EINVAL; + } + + g_ucEepromCurrentMode = u4Mode; + return 0; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_wext.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_wext.c new file mode 100644 index 00000000000000..802c5d625bd263 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_wext.c @@ -0,0 +1,3725 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_wext.c + * \brief ioctl() (mostly Linux Wireless Extensions) routines for STA + * driver. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "gl_os.h" + +#include "config.h" +#include "wlan_oid.h" + +#include "gl_wext.h" +#include "gl_wext_priv.h" + +#include "precomp.h" + +/* compatibility to wireless extensions */ +#ifdef WIRELESS_EXT + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +const long channel_freq[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; + +#define NUM_CHANNELS (ARRAY_SIZE(channel_freq)) +#define MAX_SSID_LEN 32 +#define KEY_BUF_SIZE 100 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/* NOTE: name in iwpriv_args only have 16 bytes */ +static const struct iw_priv_args rIwPrivTable[] = { + { IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" }, + { IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" }, + { IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "" }, + { IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, "" }, + { IOCTL_SET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "" }, + + { IOCTL_GET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" }, + { IOCTL_GET_INT, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" }, + + { IOCTL_SET_INTS, IW_PRIV_TYPE_INT | 4, 0, "" }, + { IOCTL_GET_INT, 0, IW_PRIV_TYPE_INT | 50, "" }, + + /* added for set_oid and get_oid */ + { IOCTL_SET_STRUCT, IW_PRIV_TYPE_CHAR | sizeof(NDIS_TRANSPORT_STRUCT), + 0, "" }, + { IOCTL_GET_STRUCT, 0, + IW_PRIV_TYPE_CHAR | sizeof(NDIS_TRANSPORT_STRUCT), "" }, + + { IOCTL_GET_DRIVER, IW_PRIV_TYPE_CHAR | IW_PRIV_BUF_SIZE, + IW_PRIV_TYPE_CHAR | IW_PRIV_BUF_SIZE, "driver" }, + +#if CFG_SUPPORT_QA_TOOL + /* added for ATE iwpriv Command */ + { IOCTL_QA_TOOL_DAEMON, IW_PRIV_TYPE_BYTE | sizeof(HQA_CMD_FRAME), 0, + "" }, + { IOCTL_IWPRIV_ATE, IW_PRIV_TYPE_CHAR | 2000, 0, "" }, +#endif + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + { PRIV_CMD_CSUM_OFFLOAD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "set_tcp_csum" }, +#endif + + { PRIV_CMD_POWER_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "set_power_mode" }, + { PRIV_CMD_POWER_MODE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_power_mode" }, + + { PRIV_CMD_WMM_PS, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, + "set_wmm_ps" }, + + { PRIV_CMD_TEST_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "set_test_mode" }, + { PRIV_CMD_TEST_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, + "set_test_cmd" }, + { PRIV_CMD_TEST_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_test_result" }, +#if CFG_SUPPORT_PRIV_MCR_RW + { PRIV_CMD_ACCESS_MCR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, + "set_mcr" }, + { PRIV_CMD_ACCESS_MCR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_mcr" }, +#endif + +#if CFG_SUPPORT_QA_TOOL + { PRIV_QACMD_SET, IW_PRIV_TYPE_CHAR | 2000, 0, "set" }, +#endif + + { PRIV_CMD_SW_CTRL, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, + "set_sw_ctrl" }, + { PRIV_CMD_SW_CTRL, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_sw_ctrl" }, + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS + { PRIV_CUSTOM_BWCS_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "set_bwcs" }, + /* GET STRUCT sub-ioctls commands */ + { PRIV_CUSTOM_BWCS_CMD, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_bwcs" }, +#endif + + /* SET STRUCT sub-ioctls commands */ + { PRIV_CMD_OID, 256, 0, "set_oid" }, + /* GET STRUCT sub-ioctls commands */ + { PRIV_CMD_OID, 0, 256, "get_oid" }, + + { PRIV_CMD_BAND_CONFIG, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "set_band" }, + { PRIV_CMD_BAND_CONFIG, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_band" }, + + { PRIV_CMD_SET_TX_POWER, IW_PRIV_TYPE_INT | 4, 0, "set_txpower" }, + { PRIV_CMD_GET_CH_LIST, 0, IW_PRIV_TYPE_INT | 50, "get_ch_list" }, + { PRIV_CMD_DUMP_MEM, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_mem" }, + +#if CFG_ENABLE_WIFI_DIRECT + { PRIV_CMD_P2P_MODE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, + "set_p2p_mode" }, +#endif + { PRIV_CMD_MET_PROFILING, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, + "set_met_prof" }, +}; + +static const iw_handler rIwPrivHandler[] = { + [IOCTL_SET_INT - SIOCIWFIRSTPRIV] = priv_set_int, + [IOCTL_GET_INT - SIOCIWFIRSTPRIV] = priv_get_int, + [IOCTL_SET_ADDRESS - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_GET_ADDRESS - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_SET_STR - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_GET_STR - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_SET_KEY - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_GET_KEY - SIOCIWFIRSTPRIV] = NULL, + [IOCTL_SET_STRUCT_FOR_EM - SIOCIWFIRSTPRIV] = priv_set_struct, + [IOCTL_SET_INTS - SIOCIWFIRSTPRIV] = priv_set_ints, + [IOCTL_GET_INTS - SIOCIWFIRSTPRIV] = priv_get_ints, + [IOCTL_GET_DRIVER - SIOCIWFIRSTPRIV] = priv_set_driver, + +#if CFG_SUPPORT_QA_TOOL + [IOCTL_QA_TOOL_DAEMON - SIOCIWFIRSTPRIV] = priv_qa_agent, + [IOCTL_IWPRIV_ATE - SIOCIWFIRSTPRIV] = priv_ate_set +#endif +}; + +const struct iw_handler_def wext_handler_def = { + .num_standard = 0, +#if defined(CONFIG_WEXT_PRIV) || LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32) + .num_private = (__u16)sizeof(rIwPrivHandler) / sizeof(iw_handler), + .num_private_args = + (__u16)sizeof(rIwPrivTable) / sizeof(struct iw_priv_args), +#endif + .standard = (iw_handler *)NULL, +#if defined(CONFIG_WEXT_PRIV) || LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32) + .private = rIwPrivHandler, + .private_args = rIwPrivTable, +#endif + .get_wireless_stats = wext_get_wireless_stats, +}; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +static void wext_support_ioctl_SIOCSIWGENIE(IN P_GLUE_INFO_T prGlueInfo, + IN char *prExtraBuf, + IN u32 u4ExtraSize); + +static void wext_support_ioctl_SIOCSIWPMKSA_Action(IN struct net_device *prDev, + IN char *prExtraBuf, + IN int ioMode, + OUT int *ret); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 12, 0) +void MAP_CHANNEL_ID_TO_KHZ(u32 ch, u32 khz) +{ + switch (ch) { + case 1: + khz = 2412000; + break; + + case 2: + khz = 2417000; + break; + + case 3: + khz = 2422000; + break; + + case 4: + khz = 2427000; + break; + + case 5: + khz = 2432000; + break; + + case 6: + khz = 2437000; + break; + + case 7: + khz = 2442000; + break; + + case 8: + khz = 2447000; + break; + + case 9: + khz = 2452000; + break; + + case 10: + khz = 2457000; + break; + + case 11: + khz = 2462000; + break; + + case 12: + khz = 2467000; + break; + + case 13: + khz = 2472000; + break; + + case 14: + khz = 2484000; + break; + + case 36: /* UNII */ + khz = 5180000; + break; + + case 40: /* UNII */ + khz = 5200000; + break; + + case 44: + khz = 5220000; + break; + + case 48: + khz = 5240000; + break; + + case 52: + khz = 5260000; + break; + + case 56: + khz = 5280000; + break; + + case 60: + khz = 5300000; + break; + + case 64: + khz = 5320000; + break; + + case 149: + khz = 5745000; + break; + + case 153: + khz = 5765000; + break; + + case 157: + khz = 5785000; + break; + + case 161: /* UNII */ + khz = 5805000; + break; + + case 165: /* UNII */ + khz = 5825000; + break; + + case 100: /* HiperLAN2 */ + khz = 5500000; + break; + + case 104: /* HiperLAN2 */ + khz = 5520000; + break; + + case 108: /* HiperLAN2 */ + khz = 5540000; + break; + + case 112: /* HiperLAN2 */ + khz = 5560000; + break; + + case 116: /* HiperLAN2 */ + khz = 5580000; + break; + + case 120: /* HiperLAN2 */ + khz = 5600000; + break; + + case 124: /* HiperLAN2 */ + khz = 5620000; + break; + + case 128: /* HiperLAN2 */ + khz = 5640000; + break; + + case 132: /* HiperLAN2 */ + khz = 5660000; + break; + + case 136: /* HiperLAN2 */ + khz = 5680000; + break; + + case 140: /* HiperLAN2 */ + khz = 5700000; + break; + + case 34: /* Japan MMAC */ + khz = 5170000; + break; + + case 38: /* Japan MMAC */ + khz = 5190000; + break; + + case 42: /* Japan MMAC */ + khz = 5210000; + break; + + case 46: /* Japan MMAC */ + khz = 5230000; + break; + + case 184: /* Japan */ + khz = 4920000; + break; + + case 188: /* Japan */ + khz = 4940000; + break; + + case 192: /* Japan */ + khz = 4960000; + break; + + case 196: /* Japan */ + khz = 4980000; + break; + + case 208: /* Japan, means J08 */ + khz = 5040000; + break; + + case 212: /* Japan, means J12 */ + khz = 5060000; + break; + + case 216: /* Japan, means J16 */ + khz = 5080000; + break; + + default: + khz = 2412000; + break; + } +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Find the desired WPA/RSN Information Element according to + * desiredElemID. + * + * \param[in] pucIEStart IE starting address. + * \param[in] i4TotalIeLen Total length of all the IE. + * \param[in] ucDesiredElemId Desired element ID. + * \param[out] ppucDesiredIE Pointer to the desired IE. + * + * \retval true Find the desired IE. + * \retval false Desired IE not found. + * + * \note + */ +/*----------------------------------------------------------------------------*/ +u8 wextSrchDesiredWPAIE(IN u8 *pucIEStart, IN s32 i4TotalIeLen, + IN u8 ucDesiredElemId, OUT u8 **ppucDesiredIE) +{ + s32 i4InfoElemLen; + + ASSERT(pucIEStart); + ASSERT(ppucDesiredIE); + + while (i4TotalIeLen >= 2) { + i4InfoElemLen = (s32)pucIEStart[1] + 2; + + if (pucIEStart[0] == ucDesiredElemId && + i4InfoElemLen <= i4TotalIeLen) { + if (ucDesiredElemId != 0xDD) { + /* Non 0xDD, OK! */ + *ppucDesiredIE = &pucIEStart[0]; + return true; + } /* EID == 0xDD, check WPA IE */ + if (pucIEStart[1] >= 4) { + if (memcmp(&pucIEStart[2], "\x00\x50\xf2\x01", + 4) == 0) { + *ppucDesiredIE = &pucIEStart[0]; + return true; + } + } /* check WPA IE length */ + /* check EID == 0xDD */ + } + + /* check desired EID */ + /* Select next information element. */ + i4TotalIeLen -= i4InfoElemLen; + pucIEStart += i4InfoElemLen; + } + + return false; +} + +#if CFG_SUPPORT_WPS +/*----------------------------------------------------------------------------*/ +/*! + * \brief Find the desired WPS Information Element according to desiredElemID. + * + * \param[in] pucIEStart IE starting address. + * \param[in] i4TotalIeLen Total length of all the IE. + * \param[in] ucDesiredElemId Desired element ID. + * \param[out] ppucDesiredIE Pointer to the desired IE. + * + * \retval true Find the desired IE. + * \retval false Desired IE not found. + * + * \note + */ +/*----------------------------------------------------------------------------*/ +u8 wextSrchDesiredWPSIE(IN u8 *pucIEStart, IN s32 i4TotalIeLen, + IN u8 ucDesiredElemId, OUT u8 **ppucDesiredIE) +{ + s32 i4InfoElemLen; + + ASSERT(pucIEStart); + ASSERT(ppucDesiredIE); + + while (i4TotalIeLen >= 2) { + i4InfoElemLen = (s32)pucIEStart[1] + 2; + + if (pucIEStart[0] == ucDesiredElemId && + i4InfoElemLen <= i4TotalIeLen) { + if (ucDesiredElemId != 0xDD) { + /* Non 0xDD, OK! */ + *ppucDesiredIE = &pucIEStart[0]; + return true; + } + /* EID == 0xDD, check WPS IE */ + if (pucIEStart[1] >= 4) { + if (memcmp(&pucIEStart[2], "\x00\x50\xf2\x04", + 4) == 0) { + *ppucDesiredIE = &pucIEStart[0]; + return true; + } + } /* check WPS IE length */ + /* check EID == 0xDD */ + } + + /* check desired EID */ + /* Select next information element. */ + i4TotalIeLen -= i4InfoElemLen; + pucIEStart += i4InfoElemLen; + } + + return false; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Get the name of the protocol used on the air. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[out] pcName Buffer to store protocol name string + * \param[in] pcExtra NULL. + * + * \retval 0 For success. + * + * \note If netif_carrier_ok, protocol name is returned; + * otherwise, "disconnected" is returned. + */ +/*----------------------------------------------------------------------------*/ +static int wext_get_name(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, OUT char *pcName, + IN char *pcExtra) +{ + ENUM_PARAM_NETWORK_TYPE_T eNetWorkType; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pcName); + if (GLUE_CHK_PR2(prNetDev, pcName) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (netif_carrier_ok(prNetDev)) { + rStatus = kalIoctl(prGlueInfo, wlanoidQueryNetworkTypeInUse, + &eNetWorkType, sizeof(eNetWorkType), true, + false, false, &u4BufLen); + + switch (eNetWorkType) { + case PARAM_NETWORK_TYPE_DS: + strncpy(pcName, "IEEE 802.11b", + sizeof(((struct iwreq *)0)->u.name)); + break; + + case PARAM_NETWORK_TYPE_OFDM24: + strncpy(pcName, "IEEE 802.11bgn", + sizeof(((struct iwreq *)0)->u.name)); + break; + + case PARAM_NETWORK_TYPE_AUTOMODE: + case PARAM_NETWORK_TYPE_OFDM5: + strncpy(pcName, "IEEE 802.11abgn", + sizeof(((struct iwreq *)0)->u.name)); + break; + + case PARAM_NETWORK_TYPE_FH: + default: + strncpy(pcName, "IEEE 802.11", + sizeof(((struct iwreq *)0)->u.name)); + break; + } + } else { + strncpy(pcName, "Disconnected", + sizeof(((struct iwreq *)0)->u.name)); + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To set the operating channel in the wireless device. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL + * \param[in] prFreq Buffer to store frequency information + * \param[in] pcExtra NULL + * + * \retval 0 For success. + * \retval -EOPNOTSUPP If infrastructure mode is not NET NET_TYPE_IBSS. + * \retval -EINVAL Invalid channel frequency. + * + * \note If infrastructure mode is IBSS, new channel frequency is set to device. + * The range of channel number depends on different regulatory domain. + */ +/*----------------------------------------------------------------------------*/ +static int wext_set_freq(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN struct iw_freq *prIwFreq, IN char *pcExtra) +{ + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To get the operating channel in the wireless device. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[out] prFreq Buffer to store frequency information. + * \param[in] pcExtra NULL. + * + * \retval 0 If netif_carrier_ok. + * \retval -ENOTCONN Otherwise + * + * \note If netif_carrier_ok, channel frequency information is stored in pFreq. + */ +/*----------------------------------------------------------------------------*/ +static int wext_get_freq(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_freq *prIwFreq, IN char *pcExtra) +{ + u32 u4Channel = 0; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prIwFreq); + if (GLUE_CHK_PR2(prNetDev, prIwFreq) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + /* GeorgeKuo: TODO skip checking in IBSS mode */ + if (!netif_carrier_ok(prNetDev)) { + return -ENOTCONN; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryFrequency, &u4Channel, + sizeof(u4Channel), true, false, false, &u4BufLen); + + prIwFreq->m = (int)u4Channel; /* freq in KHz */ + prIwFreq->e = 3; + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To set operating mode. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[in] pu4Mode Pointer to new operation mode. + * \param[in] pcExtra NULL. + * + * \retval 0 For success. + * \retval -EOPNOTSUPP If new mode is not supported. + * + * \note Device will run in new operation mode if it is valid. + */ +/*----------------------------------------------------------------------------*/ +static int wext_set_mode(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN unsigned int *pu4Mode, IN char *pcExtra) +{ + ENUM_PARAM_OP_MODE_T eOpMode; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pu4Mode); + if (GLUE_CHK_PR2(prNetDev, pu4Mode) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + switch (*pu4Mode) { + case IW_MODE_AUTO: + eOpMode = NET_TYPE_AUTO_SWITCH; + break; + + case IW_MODE_ADHOC: + eOpMode = NET_TYPE_IBSS; + break; + + case IW_MODE_INFRA: + eOpMode = NET_TYPE_INFRA; + break; + + default: + DBGLOG(INIT, INFO, "%s(): Set UNSUPPORTED Mode = %d.\n", + __func__, *pu4Mode); + return -EOPNOTSUPP; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetInfrastructureMode, &eOpMode, + sizeof(eOpMode), false, false, true, &u4BufLen); + + /* after set operation mode, key table are cleared */ + + /* reset wpa info */ + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4KeyMgmt = 0; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; +#if CFG_SUPPORT_802_11W + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; +#endif + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To get operating mode. + * + * \param[in] prNetDev Net device requested. + * \param[in] prIwReqInfo NULL. + * \param[out] pu4Mode Buffer to store operating mode information. + * \param[in] pcExtra NULL. + * + * \retval 0 If data is valid. + * \retval -EINVAL Otherwise. + * + * \note If netif_carrier_ok, operating mode information is stored in pu4Mode. + */ +/*----------------------------------------------------------------------------*/ +static int wext_get_mode(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + OUT unsigned int *pu4Mode, IN char *pcExtra) +{ + ENUM_PARAM_OP_MODE_T eOpMode; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pu4Mode); + if (GLUE_CHK_PR2(prNetDev, pu4Mode) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryInfrastructureMode, &eOpMode, + sizeof(eOpMode), true, false, false, &u4BufLen); + + switch (eOpMode) { + case NET_TYPE_IBSS: + *pu4Mode = IW_MODE_ADHOC; + break; + + case NET_TYPE_INFRA: + *pu4Mode = IW_MODE_INFRA; + break; + + case NET_TYPE_AUTO_SWITCH: + *pu4Mode = IW_MODE_AUTO; + break; + + default: + DBGLOG(INIT, INFO, "%s(): Get UNKNOWN Mode.\n", __func__); + return -EINVAL; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To get the valid range for each configurable STA setting value. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[in] prData Pointer to iw_point structure, not used. + * \param[out] pcExtra Pointer to buffer which is allocated by caller of this + * function, wext_support_ioctl() or ioctl_standard_call() + * in wireless.c. + * + * \retval 0 If data is valid. + * + * \note The extra buffer (pcExtra) is filled with information from driver. + */ +/*----------------------------------------------------------------------------*/ +static int wext_get_range(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_point *prData, OUT char *pcExtra) +{ + struct iw_range *prRange = NULL; + PARAM_RATES_EX aucSuppRate = { 0 }; /* data buffers */ + int i = 0; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pcExtra); + if (GLUE_CHK_PR2(prNetDev, pcExtra) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + prRange = (struct iw_range *)pcExtra; + + memset(prRange, 0, sizeof(*prRange)); + prRange->throughput = 20000000; /* 20Mbps */ + prRange->min_nwid = 0; /* not used */ + prRange->max_nwid = 0; /* not used */ + + /* scan_capa not implemented */ + + /* event_capa[6]: kernel + driver capabilities */ + prRange->event_capa[0] = + (IW_EVENT_CAPA_K_0 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | + IW_EVENT_CAPA_MASK(SIOCGIWSCAN) + /* can't display meaningful string in iwlist + * | IW_EVENT_CAPA_MASK(SIOCGIWTXPOW) + * | IW_EVENT_CAPA_MASK(IWEVMICHAELMICFAILURE) + * | IW_EVENT_CAPA_MASK(IWEVASSOCREQIE) + * | IW_EVENT_CAPA_MASK(IWEVPMKIDCAND) + */ + ); + prRange->event_capa[1] = IW_EVENT_CAPA_K_1; + + /* report 2.4G channel and frequency only */ + prRange->num_channels = (__u16)NUM_CHANNELS; + prRange->num_frequency = (__u8)NUM_CHANNELS; + for (i = 0; i < NUM_CHANNELS; i++) { + /* iwlib takes this number as channel number */ + prRange->freq[i].i = i + 1; + prRange->freq[i].m = channel_freq[i]; + prRange->freq[i].e = 6; /* Values in table in MHz */ + } + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySupportedRates, &aucSuppRate, + sizeof(aucSuppRate), true, false, false, &u4BufLen); + + for (i = 0; i < IW_MAX_BITRATES && i < PARAM_MAX_LEN_RATES_EX; i++) { + if (aucSuppRate[i] == 0) { + break; + } + prRange->bitrate[i] = + (aucSuppRate[i] & 0x7F) * 500000; /* 0.5Mbps + */ + } + prRange->num_bitrates = i; + + prRange->min_rts = 0; + prRange->max_rts = 2347; + prRange->min_frag = 256; + prRange->max_frag = 2346; + + prRange->min_pmp = 0; /* power management by driver */ + prRange->max_pmp = 0; /* power management by driver */ + prRange->min_pmt = 0; /* power management by driver */ + prRange->max_pmt = 0; /* power management by driver */ + prRange->pmp_flags = IW_POWER_RELATIVE; /* pm default flag */ + prRange->pmt_flags = IW_POWER_ON; /* pm timeout flag */ + prRange->pm_capa = IW_POWER_ON; /* power management by driver */ + + prRange->encoding_size[0] = 5; /* wep40 */ + prRange->encoding_size[1] = 16; /* tkip */ + prRange->encoding_size[2] = 16; /* ckip */ + prRange->encoding_size[3] = 16; /* ccmp */ + prRange->encoding_size[4] = 13; /* wep104 */ + prRange->encoding_size[5] = 16; /* wep128 */ + prRange->num_encoding_sizes = 6; + prRange->max_encoding_tokens = 6; /* token? */ + +#if WIRELESS_EXT < 17 + prRange->txpower_capa = 0x0002; /* IW_TXPOW_RELATIVE */ +#else + prRange->txpower_capa = IW_TXPOW_RELATIVE; +#endif + prRange->num_txpower = 5; + prRange->txpower[0] = 0; /* minimum */ + prRange->txpower[1] = 25; /* 25% */ + prRange->txpower[2] = 50; /* 50% */ + prRange->txpower[3] = 100; /* 100% */ + + prRange->we_version_compiled = WIRELESS_EXT; + prRange->we_version_source = WIRELESS_EXT; + + prRange->retry_capa = IW_RETRY_LIMIT; + prRange->retry_flags = IW_RETRY_LIMIT; + prRange->min_retry = 7; + prRange->max_retry = 7; + prRange->r_time_flags = IW_RETRY_ON; + prRange->min_r_time = 0; + prRange->max_r_time = 0; + + /* signal strength and link quality */ + /* Just define range here, reporting value moved to wext_get_stats() */ + prRange->sensitivity = -83; /* fixed value */ + prRange->max_qual.qual = 100; /* max 100% */ + prRange->max_qual.level = (__u8)(0x100 - 0); /* max 0 dbm */ + prRange->max_qual.noise = (__u8)(0x100 - 0); /* max 0 dbm */ + + /* enc_capa */ +#if WIRELESS_EXT > 17 + prRange->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; +#endif + + /* min_pms; Minimal PM saving */ + /* max_pms; Maximal PM saving */ + /* pms_flags; How to decode max/min PM saving */ + + /* modul_capa; IW_MODUL_* bit field */ + /* bitrate_capa; Types of bitrates supported */ + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To set BSSID of AP to connect. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[in] prAddr Pointer to struct sockaddr structure containing AP's BSSID. + * \param[in] pcExtra NULL. + * + * \retval 0 For success. + * + * \note Desired AP's BSSID is set to driver. + */ +/*----------------------------------------------------------------------------*/ +static int wext_set_ap(IN struct net_device *prDev, + IN struct iw_request_info *prIwrInfo, + IN struct sockaddr *prAddr, IN char *pcExtra) +{ + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To get AP MAC address. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[out] prAddr Pointer to struct sockaddr structure storing AP's BSSID. + * \param[in] pcExtra NULL. + * + * \retval 0 If netif_carrier_ok. + * \retval -ENOTCONN Otherwise. + * + * \note If netif_carrier_ok, AP's mac address is stored in pAddr->sa_data. + */ +/*----------------------------------------------------------------------------*/ +static int wext_get_ap(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct sockaddr *prAddr, IN char *pcExtra) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prAddr); + if (GLUE_CHK_PR2(prNetDev, prAddr) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + /* if (!netif_carrier_ok(prNetDev)) { */ + /* return -ENOTCONN; */ + /* } */ + + if (prGlueInfo->eParamMediaStateIndicated == + PARAM_MEDIA_STATE_DISCONNECTED) { + memset(prAddr, 0, sizeof(*prAddr)); + return 0; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryBssid, prAddr->sa_data, + ETH_ALEN, true, false, false, &u4BufLen); + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To set mlme operation request. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[in] prData Pointer of iw_point header. + * \param[in] pcExtra Pointer to iw_mlme structure mlme request information. + * + * \retval 0 For success. + * \retval -EOPNOTSUPP unsupported IW_MLME_ command. + * \retval -EINVAL Set MLME Fail, different bssid. + * + * \note Driver will start mlme operation if valid. + */ +/*----------------------------------------------------------------------------*/ +static int wext_set_mlme(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_point *prData, IN char *pcExtra) +{ + struct iw_mlme *prMlme = NULL; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(pcExtra); + if (GLUE_CHK_PR2(prNetDev, pcExtra) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + prMlme = (struct iw_mlme *)pcExtra; + if (prMlme->cmd == IW_MLME_DEAUTH || prMlme->cmd == IW_MLME_DISASSOC) { + if (!netif_carrier_ok(prNetDev)) { + DBGLOG(INIT, + INFO, + "[wifi] Set MLME Deauth/Disassoc, but netif_carrier_off\n"); + return 0; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, + false, false, true, &u4BufLen); + return 0; + } + DBGLOG(INIT, INFO, "[wifi] unsupported IW_MLME_ command :%d\n", + prMlme->cmd); + return -EOPNOTSUPP; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To issue scan request. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[in] prData NULL. + * \param[in] pcExtra NULL. + * + * \retval 0 For success. + * \retval -EFAULT Tx power is off. + * + * \note Device will start scanning. + */ +/*----------------------------------------------------------------------------*/ +static int wext_set_scan(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN union iwreq_data *prData, IN char *pcExtra) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + int essid_len = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_DEV(prNetDev) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + +#if WIRELESS_EXT > 17 + /* retrieve SSID */ + if (prData) { + essid_len = ((struct iw_scan_req *)(((struct iw_point *)prData) + ->pointer)) + ->essid_len; + } +#endif + + init_completion(&prGlueInfo->rScanComp); + + /* TODO: parse flags and issue different scan requests? */ + + rStatus = kalIoctl(prGlueInfo, wlanoidSetBssidListScan, pcExtra, + essid_len, false, false, false, &u4BufLen); + + /* wait_for_completion_interruptible_timeout(&prGlueInfo->rScanComp, 2 * + * KAL_HZ); */ + /* kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, + * NULL, 0); */ + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To write the ie to buffer + * + */ +/*----------------------------------------------------------------------------*/ +static inline int snprintf_hex(char *buf, size_t buf_size, const u8 *data, + size_t len) +{ + size_t i; + char *pos = buf, *end = buf + buf_size; + int ret; + + if (buf_size == 0) { + return 0; + } + + for (i = 0; i < len; i++) { + ret = snprintf(pos, end - pos, "%02x", data[i]); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return pos - buf; + } + pos += ret; + } + end[-1] = '\0'; + return pos - buf; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To get scan results, transform results from driver's format to WE's. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[out] prData Pointer to iw_point structure, pData->length is the size + * of pcExtra buffer before used, and is updated after filling scan results. + * \param[out] pcExtra Pointer to buffer which is allocated by caller of this + * function, wext_support_ioctl() or ioctl_standard_call() + * in wireless.c. + * + * \retval 0 For success. + * \retval -ENOMEM If dynamic memory allocation fail. + * \retval -E2BIG Invalid length. + * + * \note Scan results is filled into pcExtra buffer, data size is updated in + * pData->length. + */ +/*----------------------------------------------------------------------------*/ +static int wext_get_scan(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN OUT struct iw_point *prData, IN char *pcExtra) +{ + u32 i = 0; + u32 j = 0; + P_PARAM_BSSID_LIST_EX_T prList = NULL; + P_PARAM_BSSID_EX_T prBss = NULL; + P_PARAM_VARIABLE_IE_T prDesiredIE = NULL; + struct iw_event iwEvent; /* local iw_event buffer */ + + /* write pointer of extra buffer */ + char *pcCur = NULL; + /* pointer to the end of last full entry in extra buffer */ + char *pcValidEntryEnd = NULL; + char *pcEnd = NULL; /* end of extra buffer */ + + u32 u4AllocBufLen = 0; + + /* arrange rate information */ + u32 u4HighestRate = 0; + char aucRatesBuf[64]; + u32 u4BufIndex; + + /* return value */ + int ret = 0; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prData); + ASSERT(pcExtra); + if (GLUE_CHK_PR3(prNetDev, prData, pcExtra) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + /* Initialize local variables */ + pcCur = pcExtra; + pcValidEntryEnd = pcExtra; + pcEnd = pcExtra + prData->length; /* end of extra buffer */ + + /* Allocate another query buffer with the same size of extra buffer */ + u4AllocBufLen = prData->length; + if (u4AllocBufLen < sizeof(PARAM_BSSID_LIST_EX_T)) { + DBGLOG(INIT, WARN, "[wifi] invalid input length:%d < %d\n", + prData->length, sizeof(PARAM_BSSID_LIST_EX_T)); + return -EINVAL; + } + prList = kalMemAlloc(u4AllocBufLen, VIR_MEM_TYPE); + if (prList == NULL) { + DBGLOG(INIT, INFO, "[wifi] no memory for scan list:%d\n", + prData->length); + ret = -ENOMEM; + goto error; + } + prList->u4NumberOfItems = 0; + + /* wait scan done */ + + /* wait_for_completion_interruptible_timeout(&prGlueInfo->rScanComp, 4 * + * KAL_HZ); */ + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryBssidList, prList, + u4AllocBufLen, true, false, false, &u4BufLen); + + if (rStatus == WLAN_STATUS_INVALID_LENGTH) { + /* Buffer length is not large enough. */ + +#if WIRELESS_EXT >= 17 + /* This feature is supported in WE-17 or above, limited by + * iwlist. + ** Return -E2BIG and iwlist will request again with a larger + * buffer. + */ + ret = -E2BIG; + /* Update length to give application a hint on result length */ + prData->length = (__u16)u4BufLen; + goto error; +#else + /* Realloc a larger query buffer here, but don't write too much + * to extra + ** buffer when filling it later. + */ + kalMemFree(prList, VIR_MEM_TYPE, u4AllocBufLen); + + u4AllocBufLen = u4BufLen; + prList = kalMemAlloc(u4AllocBufLen, VIR_MEM_TYPE); + if (prList == NULL) { + DBGLOG(INIT, INFO, + "[wifi] no memory for larger scan list :%ld\n", + u4BufLen); + ret = -ENOMEM; + goto error; + } + prList->NumberOfItems = 0; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryBssidList, prList, + u4AllocBufLen, true, false, false, + &u4BufLen); + + if (rStatus == WLAN_STATUS_INVALID_LENGTH) { + DBGLOG(INIT, INFO, "[wifi] larger buf:%d result:%ld\n", + u4AllocBufLen, u4BufLen); + ret = -E2BIG; + prData->length = (__u16)u4BufLen; + goto error; + } +#endif + } + + if (prList->u4NumberOfItems > CFG_MAX_NUM_BSS_LIST) { + DBGLOG(INIT, INFO, "[wifi] strange scan result count:%ld\n", + prList->u4NumberOfItems); + goto error; + } + + /* Copy required data from pList to pcExtra */ + prBss = &prList->arBssid[0]; /* set to the first entry */ + for (i = 0; i < prList->u4NumberOfItems; ++i) { + kalMemSet(&iwEvent, 0, sizeof(iwEvent)); + /* BSSID */ + iwEvent.cmd = SIOCGIWAP; + iwEvent.len = IW_EV_ADDR_LEN; + if ((pcCur + iwEvent.len) > pcEnd) { + break; + } + iwEvent.u.ap_addr.sa_family = ARPHRD_ETHER; + kalMemCopy(iwEvent.u.ap_addr.sa_data, prBss->arMacAddress, + ETH_ALEN); + memcpy(pcCur, &iwEvent, IW_EV_ADDR_LEN); + pcCur += IW_EV_ADDR_LEN; + + /* SSID */ + iwEvent.cmd = SIOCGIWESSID; + /* Modification to user space pointer(essid.pointer) is not + * needed. */ + iwEvent.u.essid.length = (__u16)prBss->rSsid.u4SsidLen; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.essid.length; + + if ((pcCur + iwEvent.len) > pcEnd) { + break; + } + iwEvent.u.essid.flags = 1; + iwEvent.u.essid.pointer = NULL; + +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, iwEvent.len); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prBss->rSsid.aucSsid, + iwEvent.u.essid.length); + pcCur += iwEvent.len; + /* Frequency */ + iwEvent.cmd = SIOCGIWFREQ; + iwEvent.len = IW_EV_FREQ_LEN; + if ((pcCur + iwEvent.len) > pcEnd) { + break; + } + iwEvent.u.freq.m = prBss->rConfiguration.u4DSConfig; + iwEvent.u.freq.e = 3; /* (in KHz) */ + iwEvent.u.freq.i = 0; + memcpy(pcCur, &iwEvent, IW_EV_FREQ_LEN); + pcCur += IW_EV_FREQ_LEN; + + /* Operation Mode */ + iwEvent.cmd = SIOCGIWMODE; + iwEvent.len = IW_EV_UINT_LEN; + if ((pcCur + iwEvent.len) > pcEnd) { + break; + } + if (prBss->eOpMode == NET_TYPE_IBSS) { + iwEvent.u.mode = IW_MODE_ADHOC; + }else if (prBss->eOpMode == NET_TYPE_INFRA) { + iwEvent.u.mode = IW_MODE_INFRA; + }else{ + iwEvent.u.mode = IW_MODE_AUTO; + } + memcpy(pcCur, &iwEvent, IW_EV_UINT_LEN); + pcCur += IW_EV_UINT_LEN; + + /* Quality */ + iwEvent.cmd = IWEVQUAL; + iwEvent.len = IW_EV_QUAL_LEN; + if ((pcCur + iwEvent.len) > pcEnd) { + break; + } + iwEvent.u.qual.qual = 0; /* Quality not available now */ + /* -100 < Rssi < -10, normalized by adding 0x100 */ + iwEvent.u.qual.level = 0x100 + prBss->rRssi; + iwEvent.u.qual.noise = 0; /* Noise not available now */ + iwEvent.u.qual.updated = IW_QUAL_QUAL_INVALID | + IW_QUAL_LEVEL_UPDATED | + IW_QUAL_NOISE_INVALID; + memcpy(pcCur, &iwEvent, IW_EV_QUAL_LEN); + pcCur += IW_EV_QUAL_LEN; + + /* Security Mode */ + iwEvent.cmd = SIOCGIWENCODE; + iwEvent.len = IW_EV_POINT_LEN; + if ((pcCur + iwEvent.len) > pcEnd) { + break; + } + iwEvent.u.data.pointer = NULL; + iwEvent.u.data.flags = 0; + iwEvent.u.data.length = 0; + if (!prBss->u4Privacy) { + iwEvent.u.data.flags |= IW_ENCODE_DISABLED; + } +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + pcCur += IW_EV_POINT_LEN; + + /* rearrange rate information */ + u4BufIndex = sprintf(aucRatesBuf, "Rates (Mb/s):"); + u4HighestRate = 0; + for (j = 0; j < PARAM_MAX_LEN_RATES_EX; ++j) { + u8 curRate = prBss->rSupportedRates[j] & 0x7F; + + if (curRate == 0) { + break; + } + + if (curRate > u4HighestRate) { + u4HighestRate = curRate; + } + + if (curRate == RATE_5_5M) { + u4BufIndex += sprintf(aucRatesBuf + u4BufIndex, + " 5.5"); + } else { + u4BufIndex += sprintf(aucRatesBuf + u4BufIndex, + " %d", curRate / 2); + } +#if DBG + if (u4BufIndex > sizeof(aucRatesBuf)) { + break; + } +#endif + } + /* Report Highest Rates */ + iwEvent.cmd = SIOCGIWRATE; + iwEvent.len = IW_EV_PARAM_LEN; + if ((pcCur + iwEvent.len) > pcEnd) { + break; + } + iwEvent.u.bitrate.value = u4HighestRate * 500000; + iwEvent.u.bitrate.fixed = 0; + iwEvent.u.bitrate.disabled = 0; + iwEvent.u.bitrate.flags = 0; + memcpy(pcCur, &iwEvent, iwEvent.len); + pcCur += iwEvent.len; + +#if WIRELESS_EXT >= 15 /* IWEVCUSTOM is available in WE-15 or above */ + /* Report Residual Rates */ + iwEvent.cmd = IWEVCUSTOM; + iwEvent.u.data.length = u4BufIndex; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) { + break; + } + iwEvent.u.data.flags = 0; +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, aucRatesBuf, u4BufIndex); + pcCur += iwEvent.len; +#endif + + if (wextSrchDesiredWPAIE( + &prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], + prBss->u4IELength - sizeof(PARAM_FIXED_IEs), 0xDD, + (u8 **)&prDesiredIE)) { + iwEvent.cmd = IWEVGENIE; + iwEvent.u.data.flags = 1; + iwEvent.u.data.length = + 2 + (__u16)prDesiredIE->ucLength; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) { + break; + } +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, + 2 + prDesiredIE->ucLength); + pcCur += iwEvent.len; + } +#if CFG_SUPPORT_WPS /* search WPS IE (0xDD, 221, OUI: 0x0050f204 ) */ + if (wextSrchDesiredWPSIE( + &prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], + prBss->u4IELength - sizeof(PARAM_FIXED_IEs), 0xDD, + (u8 **)&prDesiredIE)) { + iwEvent.cmd = IWEVGENIE; + iwEvent.u.data.flags = 1; + iwEvent.u.data.length = + 2 + (__u16)prDesiredIE->ucLength; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) { + break; + } +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, + 2 + prDesiredIE->ucLength); + pcCur += iwEvent.len; + } +#endif + + /* Search RSN IE (0x30, 48). pBss->IEs starts from timestamp. */ + /* pBss->IEs starts from timestamp */ + if (wextSrchDesiredWPAIE( + &prBss->aucIEs[sizeof(PARAM_FIXED_IEs)], + prBss->u4IELength - sizeof(PARAM_FIXED_IEs), 0x30, + (u8 **)&prDesiredIE)) { + iwEvent.cmd = IWEVGENIE; + iwEvent.u.data.flags = 1; + iwEvent.u.data.length = + 2 + (__u16)prDesiredIE->ucLength; + iwEvent.len = IW_EV_POINT_LEN + iwEvent.u.data.length; + if ((pcCur + iwEvent.len) > pcEnd) { + break; + } +#if WIRELESS_EXT <= 18 + memcpy(pcCur, &iwEvent, IW_EV_POINT_LEN); +#else + memcpy(pcCur, &iwEvent, IW_EV_LCP_LEN); + memcpy(pcCur + IW_EV_LCP_LEN, &iwEvent.u.data.length, + sizeof(struct iw_point) - IW_EV_POINT_OFF); +#endif + memcpy(pcCur + IW_EV_POINT_LEN, prDesiredIE, + 2 + prDesiredIE->ucLength); + pcCur += iwEvent.len; + } + + /* Complete an entry. Update end of valid entry */ + pcValidEntryEnd = pcCur; + /* Extract next bss */ + prBss = (P_PARAM_BSSID_EX_T)((char *)prBss + prBss->u4Length); + } + + /* Update valid data length for caller function and upper layer + * applications. + */ + prData->length = (pcValidEntryEnd - pcExtra); + + /* kalIndicateStatusAndComplete(prGlueInfo, WLAN_STATUS_SCAN_COMPLETE, + * NULL, 0); */ + +error: + /* free local query buffer */ + if (prList) { + kalMemFree(prList, VIR_MEM_TYPE, u4AllocBufLen); + } + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To set desired network name ESSID. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[in] prEssid Pointer of iw_point header. + * \param[in] pcExtra Pointer to buffer srtoring essid string. + * + * \retval 0 If netif_carrier_ok. + * \retval -E2BIG Essid string length is too big. + * \retval -EINVAL pcExtra is null pointer. + * \retval -EFAULT Driver fail to set new essid. + * + * \note If string length is ok, device will try connecting to the new network. + */ +/*----------------------------------------------------------------------------*/ +static int wext_set_essid(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_point *prEssid, IN char *pcExtra) +{ + PARAM_SSID_T rNewSsid; + u32 cipher; + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + ENUM_PARAM_AUTH_MODE_T eAuthMode; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEssid); + ASSERT(pcExtra); + if (GLUE_CHK_PR3(prNetDev, prEssid, pcExtra) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (prEssid->length > IW_ESSID_MAX_SIZE) { + return -E2BIG; + } + + /* set auth mode */ + if (prGlueInfo->rWpaInfo.u4WpaVersion == IW_AUTH_WPA_VERSION_DISABLED) { + eAuthMode = (prGlueInfo->rWpaInfo.u4AuthAlg == + IW_AUTH_ALG_OPEN_SYSTEM) ? + AUTH_MODE_OPEN : + AUTH_MODE_AUTO_SWITCH; + } else { + /* set auth mode */ + switch (prGlueInfo->rWpaInfo.u4KeyMgmt) { + case IW_AUTH_KEY_MGMT_802_1X: + eAuthMode = (prGlueInfo->rWpaInfo.u4WpaVersion == + IW_AUTH_WPA_VERSION_WPA) ? + AUTH_MODE_WPA : + AUTH_MODE_WPA2; + + break; + + case IW_AUTH_KEY_MGMT_PSK: + eAuthMode = (prGlueInfo->rWpaInfo.u4WpaVersion == + IW_AUTH_WPA_VERSION_WPA) ? + AUTH_MODE_WPA_PSK : + AUTH_MODE_WPA2_PSK; + + break; + +#if CFG_SUPPORT_802_11W + case IW_AUTH_KEY_MGMT_802_1X_SHA256: + eAuthMode = AUTH_MODE_WPA2; + break; + + case IW_AUTH_KEY_MGMT_PSK_SHA256: + eAuthMode = AUTH_MODE_WPA2_PSK; + break; + +#endif + default: + + /* prGlueInfo->rWpaInfo.u4KeyMgmt); */ + eAuthMode = AUTH_MODE_AUTO_SWITCH; + break; + } + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetAuthMode, &eAuthMode, + sizeof(eAuthMode), false, false, false, &u4BufLen); + + /* set encryption status */ + cipher = prGlueInfo->rWpaInfo.u4CipherGroup | + prGlueInfo->rWpaInfo.u4CipherPairwise; + if (cipher & IW_AUTH_CIPHER_CCMP) { + eEncStatus = ENUM_ENCRYPTION3_ENABLED; + } else if (cipher & IW_AUTH_CIPHER_TKIP) { + eEncStatus = ENUM_ENCRYPTION2_ENABLED; + } else if (cipher & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + } else if (cipher & IW_AUTH_CIPHER_NONE) { + if (prGlueInfo->rWpaInfo.fgPrivacyInvoke) { + eEncStatus = ENUM_ENCRYPTION1_ENABLED; + }else{ + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } + } else { + eEncStatus = ENUM_ENCRYPTION_DISABLED; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetEncryptionStatus, &eEncStatus, + sizeof(eEncStatus), false, false, false, &u4BufLen); + +#if WIRELESS_EXT < 21 + /* GeorgeKuo: a length error bug exists in (WE < 21) cases, kernel + * before + ** 2.6.19. Cut the trailing '\0'. + */ + rNewSsid.u4SsidLen = (prEssid->length) ? prEssid->length - 1 : 0; +#else + rNewSsid.u4SsidLen = prEssid->length; +#endif + kalMemCopy(rNewSsid.aucSsid, pcExtra, rNewSsid.u4SsidLen); + + /* + * rNewSsid.aucSsid[rNewSsid.u4SsidLen] = '\0'; + * printk("set ssid(%lu): %s\n", rNewSsid.u4SsidLen, rNewSsid.aucSsid); + */ + + if (kalIoctl(prGlueInfo, wlanoidSetSsid, (void *)&rNewSsid, + sizeof(PARAM_SSID_T), false, false, true, + &u4BufLen) != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To get current network name ESSID. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[in] prEssid Pointer to iw_point structure containing essid + * information. \param[out] pcExtra Pointer to buffer srtoring essid string. + * + * \retval 0 If netif_carrier_ok. + * \retval -ENOTCONN Otherwise. + * + * \note If netif_carrier_ok, network essid is stored in pcExtra. + */ +/*----------------------------------------------------------------------------*/ +/* static PARAM_SSID_T ssid; */ +static int wext_get_essid(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_point *prEssid, OUT char *pcExtra) +{ + /* PARAM_SSID_T ssid; */ + + P_PARAM_SSID_T prSsid; + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEssid); + ASSERT(pcExtra); + + if (GLUE_CHK_PR3(prNetDev, prEssid, pcExtra) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + /* if (!netif_carrier_ok(prNetDev)) { */ + /* return -ENOTCONN; */ + /* } */ + + prSsid = kalMemAlloc(sizeof(PARAM_SSID_T), VIR_MEM_TYPE); + + if (!prSsid) { + return -ENOMEM; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySsid, prSsid, + sizeof(PARAM_SSID_T), true, false, false, &u4BufLen); + + if ((rStatus == WLAN_STATUS_SUCCESS) && + (prSsid->u4SsidLen <= MAX_SSID_LEN)) { + kalMemCopy(pcExtra, prSsid->aucSsid, prSsid->u4SsidLen); + prEssid->length = prSsid->u4SsidLen; + prEssid->flags = 1; + } + + kalMemFree(prSsid, VIR_MEM_TYPE, sizeof(PARAM_SSID_T)); + + return rStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To get current tx bit rate. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[out] prRate Pointer to iw_param structure to store current tx rate. + * \param[in] pcExtra NULL. + * + * \retval 0 If netif_carrier_ok. + * \retval -ENOTCONN Otherwise. + * + * \note If netif_carrier_ok, current tx rate is stored in pRate. + */ +/*----------------------------------------------------------------------------*/ +static int wext_get_rate(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_param *prRate, IN char *pcExtra) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + u32 u4Rate = 0; + + ASSERT(prNetDev); + ASSERT(prRate); + if (GLUE_CHK_PR2(prNetDev, prRate) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (!netif_carrier_ok(prNetDev)) { + return -ENOTCONN; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryLinkSpeed, &u4Rate, + sizeof(u4Rate), true, false, false, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + prRate->value = u4Rate * 100; /* u4Rate is in unit of 100bps */ + prRate->fixed = 0; + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To set RTS/CTS theshold. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[in] prRts Pointer to iw_param structure containing rts threshold. + * \param[in] pcExtra NULL. + * + * \retval 0 For success. + * \retval -EINVAL Given value is out of range. + * + * \note If given value is valid, device will follow the new setting. + */ +/*----------------------------------------------------------------------------*/ +static int wext_set_rts(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_param *prRts, IN char *pcExtra) +{ + PARAM_RTS_THRESHOLD u4RtsThresh; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prRts); + if (GLUE_CHK_PR2(prNetDev, prRts) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (prRts->value < 0 || prRts->value > 2347) { + return -EINVAL; + } + + if (prRts->disabled == 1) { + u4RtsThresh = 2347; + }else{ + u4RtsThresh = (PARAM_RTS_THRESHOLD)prRts->value; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetRtsThreshold, &u4RtsThresh, + sizeof(u4RtsThresh), false, false, false, &u4BufLen); + + prRts->value = (typeof(prRts->value))u4RtsThresh; + prRts->disabled = (prRts->value > 2347) ? 1 : 0; + prRts->fixed = 1; + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To get RTS/CTS theshold. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[out] prRts Pointer to iw_param structure containing rts threshold. + * \param[in] pcExtra NULL. + * + * \retval 0 Success. + * + * \note RTS threshold is stored in pRts. + */ +/*----------------------------------------------------------------------------*/ +static int wext_get_rts(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_param *prRts, IN char *pcExtra) +{ + PARAM_RTS_THRESHOLD u4RtsThresh; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prRts); + if (GLUE_CHK_PR2(prNetDev, prRts) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryRtsThreshold, &u4RtsThresh, + sizeof(u4RtsThresh), true, false, false, &u4BufLen); + + prRts->value = (typeof(prRts->value))u4RtsThresh; + prRts->disabled = (prRts->value > 2347 || prRts->value < 0) ? 1 : 0; + prRts->fixed = 1; + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To get fragmentation threshold. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[out] prFrag Pointer to iw_param structure containing frag threshold. + * \param[in] pcExtra NULL. + * + * \retval 0 Success. + * + * \note RTS threshold is stored in pFrag. Fragmentation is disabled. + */ +/*----------------------------------------------------------------------------*/ +static int wext_get_frag(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_param *prFrag, IN char *pcExtra) +{ + ASSERT(prFrag); + + prFrag->value = 2346; + prFrag->fixed = 1; + prFrag->disabled = 1; + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To set TX power, or enable/disable the radio. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[in] prTxPow Pointer to iw_param structure containing tx power setting. + * \param[in] pcExtra NULL. + * + * \retval 0 Success. + * + * \note Tx power is stored in pTxPow. iwconfig wlan0 txpow on/off are used + * to enable/disable the radio. + */ +/*----------------------------------------------------------------------------*/ + +static int wext_set_txpow(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_param *prTxPow, IN char *pcExtra) +{ + int ret = 0; + /* PARAM_DEVICE_POWER_STATE ePowerState; */ + ENUM_ACPI_STATE_T ePowerState; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prTxPow); + if (GLUE_CHK_PR2(prNetDev, prTxPow) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (prTxPow->disabled) { + /* <1> disconnect */ + rStatus = kalIoctl(prGlueInfo, wlanoidSetDisassociate, NULL, 0, + false, false, true, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + /* ToDo:: DBGLOG */ + DBGLOG(INIT, INFO, "######set disassoc failed\n"); + } else { + DBGLOG(INIT, INFO, "######set assoc ok\n"); + } + /* <2> mark to power state flag */ + ePowerState = ACPI_STATE_D0; + DBGLOG(INIT, INFO, "set to acpi d3(0)\n"); + wlanSetAcpiState(prGlueInfo->prAdapter, ePowerState); + } else { + ePowerState = ACPI_STATE_D0; + DBGLOG(INIT, INFO, "set to acpi d0\n"); + wlanSetAcpiState(prGlueInfo->prAdapter, ePowerState); + } + + prGlueInfo->ePowerState = ParamDeviceStateD0; + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To get TX power. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[out] prTxPow Pointer to iw_param structure containing tx power + * setting. \param[in] pcExtra NULL. + * + * \retval 0 Success. + * + * \note Tx power is stored in pTxPow. + */ +/*----------------------------------------------------------------------------*/ +static int wext_get_txpow(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_param *prTxPow, IN char *pcExtra) +{ + /* PARAM_DEVICE_POWER_STATE ePowerState; */ + + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prNetDev); + ASSERT(prTxPow); + if (GLUE_CHK_PR2(prNetDev, prTxPow) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + /* GeorgeKuo: wlanoidQueryAcpiDevicePowerState() reports capability, not + * current state. Use GLUE_INFO_T to store state. + */ + /* ePowerState = prGlueInfo->ePowerState; */ + + /* TxPow parameters: Fixed at relative 100% */ +#if WIRELESS_EXT < 17 + prTxPow->flags = 0x0002; /* IW_TXPOW_RELATIVE */ +#else + prTxPow->flags = IW_TXPOW_RELATIVE; +#endif + prTxPow->value = 100; + prTxPow->fixed = 1; + /* prTxPow->disabled = (ePowerState != ParamDeviceStateD3) ? false : + * true; */ + prTxPow->disabled = true; + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To get encryption cipher and key. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[out] prEnc Pointer to iw_point structure containing securiry + * information. \param[in] pcExtra Buffer to store key content. + * + * \retval 0 Success. + * + * \note Securiry information is stored in pEnc except key content. + */ +/*----------------------------------------------------------------------------*/ +static int wext_get_encode(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_point *prEnc, IN char *pcExtra) +{ + /* ENUM_ENCRYPTION_STATUS_T eEncMode; */ + ENUM_PARAM_ENCRYPTION_STATUS_T eEncMode; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEnc); + if (GLUE_CHK_PR2(prNetDev, prEnc) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryEncryptionStatus, &eEncMode, + sizeof(eEncMode), true, false, false, &u4BufLen); + + switch (eEncMode) { + case ENUM_WEP_DISABLED: + prEnc->flags = IW_ENCODE_DISABLED; + break; + + case ENUM_WEP_ENABLED: + prEnc->flags = IW_ENCODE_ENABLED; + break; + + case ENUM_WEP_KEY_ABSENT: + prEnc->flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + break; + + default: + prEnc->flags = IW_ENCODE_ENABLED; + break; + } + + /* Cipher, Key Content, Key ID can't be queried */ + prEnc->flags |= IW_ENCODE_NOKEY; + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To set encryption cipher and key. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[in] prEnc Pointer to iw_point structure containing securiry + * information. \param[in] pcExtra Pointer to key string buffer. + * + * \retval 0 Success. + * \retval -EINVAL Key ID error for WEP. + * \retval -EFAULT Setting parameters to driver fail. + * \retval -EOPNOTSUPP Key size not supported. + * + * \note Securiry information is stored in pEnc. + */ +/*----------------------------------------------------------------------------*/ +static int wext_set_encode(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_point *prEnc, IN char *pcExtra) +{ + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + ENUM_PARAM_AUTH_MODE_T eAuthMode; + /* u8 wepBuf[48]; */ + u8 wepBuf[48]; + P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T)wepBuf; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + ASSERT(prEnc); + ASSERT(pcExtra); + if (GLUE_CHK_PR3(prNetDev, prEnc, pcExtra) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + /* reset to default mode */ + prGlueInfo->rWpaInfo.u4WpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + prGlueInfo->rWpaInfo.u4KeyMgmt = 0; + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_NONE; + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_OPEN_SYSTEM; +#if CFG_SUPPORT_802_11W + prGlueInfo->rWpaInfo.u4Mfp = IW_AUTH_MFP_DISABLED; +#endif + + /* iwconfig wlan0 key off */ + if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) { + eAuthMode = AUTH_MODE_OPEN; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetAuthMode, &eAuthMode, + sizeof(eAuthMode), false, false, false, + &u4BufLen); + + eEncStatus = ENUM_ENCRYPTION_DISABLED; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetEncryptionStatus, + &eEncStatus, sizeof(eEncStatus), false, + false, false, &u4BufLen); + + return 0; + } + + /* iwconfig wlan0 key 0123456789 */ + /* iwconfig wlan0 key s:abcde */ + /* iwconfig wlan0 key 0123456789 [1] */ + /* iwconfig wlan0 key 01234567890123456789012345 [1] */ + /* check key size for WEP */ + if (prEnc->length == 5 || prEnc->length == 13 || prEnc->length == 16) { + /* prepare PARAM_WEP key structure */ + prWepKey->u4KeyIndex = + (prEnc->flags & IW_ENCODE_INDEX) ? + (prEnc->flags & IW_ENCODE_INDEX) - 1 : + 0; + if (prWepKey->u4KeyIndex > 3) { + /* key id is out of range */ + return -EINVAL; + } + prWepKey->u4KeyIndex |= 0x80000000; + prWepKey->u4Length = 12 + prEnc->length; + prWepKey->u4KeyLength = prEnc->length; + kalMemCopy(prWepKey->aucKeyMaterial, pcExtra, prEnc->length); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetAddWep, prWepKey, + prWepKey->u4Length, false, false, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "wlanoidSetAddWep fail 0x%lx\n", + rStatus); + return -EFAULT; + } + + /* change to auto switch */ + prGlueInfo->rWpaInfo.u4AuthAlg = IW_AUTH_ALG_SHARED_KEY | + IW_AUTH_ALG_OPEN_SYSTEM; + eAuthMode = AUTH_MODE_AUTO_SWITCH; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetAuthMode, &eAuthMode, + sizeof(eAuthMode), false, false, false, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + prGlueInfo->rWpaInfo.u4CipherPairwise = IW_AUTH_CIPHER_WEP104 | + IW_AUTH_CIPHER_WEP40; + prGlueInfo->rWpaInfo.u4CipherGroup = IW_AUTH_CIPHER_WEP104 | + IW_AUTH_CIPHER_WEP40; + + eEncStatus = ENUM_WEP_ENABLED; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetEncryptionStatus, + &eEncStatus, + sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T), + false, false, false, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return 0; + } + + return -EOPNOTSUPP; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To set power management. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[in] prPower Pointer to iw_param structure containing tx power setting. + * \param[in] pcExtra NULL. + * + * \retval 0 Success. + * + * \note New Power Management Mode is set to driver. + */ +/*----------------------------------------------------------------------------*/ +static int wext_set_power(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_param *prPower, IN char *pcExtra) +{ + PARAM_POWER_MODE ePowerMode; + s32 i4PowerValue; + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + PARAM_POWER_MODE_T rPowerMode; + + ASSERT(prNetDev); + ASSERT(prPower); + if (GLUE_CHK_PR2(prNetDev, prPower) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (!prGlueInfo) { + return -EFAULT; + } + + if (!prGlueInfo->prAdapter->prAisBssInfo) { + return -EFAULT; + } + + /* prPower->value, prPower->disabled, prPower->flags); */ + + if (prPower->disabled) { + ePowerMode = Param_PowerModeCAM; + } else { + i4PowerValue = prPower->value; +#if WIRELESS_EXT < 21 + i4PowerValue /= 1000000; +#endif + if (i4PowerValue == 0) { + ePowerMode = Param_PowerModeCAM; + } else if (i4PowerValue == 1) { + ePowerMode = Param_PowerModeMAX_PSP; + } else if (i4PowerValue == 2) { + ePowerMode = Param_PowerModeFast_PSP; +#ifdef SUPPORT_PERIODIC_PS + } else if (i4PowerValue == 3) { + ePowerMode = Param_PowerModePeriodic_PSP; +#endif + } else { + DBGLOG(INIT, + INFO, + "%s(): unsupported power management mode value = %d.\n", + __func__, + prPower->value); + + return -EINVAL; + } + } + + rPowerMode.ePowerMode = ePowerMode; + rPowerMode.ucBssIdx = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + + rStatus = kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile, + &rPowerMode, sizeof(PARAM_POWER_MODE_T), false, + false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To get power management. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[out] prPower Pointer to iw_param structure containing tx power + * setting. \param[in] pcExtra NULL. + * + * \retval 0 Success. + * + * \note Power management mode is stored in pTxPow->value. + */ +/*----------------------------------------------------------------------------*/ +static int wext_get_power(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + OUT struct iw_param *prPower, IN char *pcExtra) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + PARAM_POWER_MODE ePowerMode = Param_PowerModeCAM; + + ASSERT(prNetDev); + ASSERT(prPower); + if (GLUE_CHK_PR2(prNetDev, prPower) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + rStatus = wlanQueryInformation(prGlueInfo->prAdapter, + wlanoidQuery802dot11PowerSaveProfile, + &ePowerMode, sizeof(ePowerMode), + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + prPower->value = 0; + prPower->disabled = 1; + + if (Param_PowerModeCAM == ePowerMode) { + prPower->value = 0; + prPower->disabled = 1; + } else if (Param_PowerModeMAX_PSP == ePowerMode) { + prPower->value = 1; + prPower->disabled = 0; + } else if (Param_PowerModeFast_PSP == ePowerMode) { + prPower->value = 2; + prPower->disabled = 0; + } + + prPower->flags = IW_POWER_PERIOD | IW_POWER_RELATIVE; +#if WIRELESS_EXT < 21 + prPower->value *= 1000000; +#endif + + /* prPower->value, prPower->disabled, prPower->flags); */ + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To set authentication parameters. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[in] rpAuth Pointer to iw_param structure containing authentication + * information. \param[in] pcExtra Pointer to key string buffer. + * + * \retval 0 Success. + * \retval -EINVAL Key ID error for WEP. + * \retval -EFAULT Setting parameters to driver fail. + * \retval -EOPNOTSUPP Key size not supported. + * + * \note Securiry information is stored in pEnc. + */ +/*----------------------------------------------------------------------------*/ +static int wext_set_auth(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_param *prAuth, IN char *pcExtra) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prNetDev); + ASSERT(prAuth); + if (GLUE_CHK_PR2(prNetDev, prAuth) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + /* Save information to glue info and process later when ssid is set. */ + switch (prAuth->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + prGlueInfo->rWpaInfo.u4WpaVersion = prAuth->value; + break; + + case IW_AUTH_CIPHER_PAIRWISE: + prGlueInfo->rWpaInfo.u4CipherPairwise = prAuth->value; + break; + + case IW_AUTH_CIPHER_GROUP: + prGlueInfo->rWpaInfo.u4CipherGroup = prAuth->value; + break; + + case IW_AUTH_KEY_MGMT: + prGlueInfo->rWpaInfo.u4KeyMgmt = prAuth->value; + + if (prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_WPS) { + prGlueInfo->fgWpsActive = true; + }else{ + prGlueInfo->fgWpsActive = false; + } + break; + + case IW_AUTH_80211_AUTH_ALG: + prGlueInfo->rWpaInfo.u4AuthAlg = prAuth->value; + break; + + case IW_AUTH_PRIVACY_INVOKED: + prGlueInfo->rWpaInfo.fgPrivacyInvoke = prAuth->value; + break; + +#if CFG_SUPPORT_802_11W + case IW_AUTH_MFP: + + prGlueInfo->rWpaInfo.u4Mfp = prAuth->value; + break; +#endif + + default: + /* + * printk(KERN_INFO "[wifi] unsupported IW_AUTH_INDEX :%d\n", + * prAuth->flags); + */ + break; + } + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To set encryption cipher and key. + * + * \param[in] prDev Net device requested. + * \param[in] prIwrInfo NULL. + * \param[in] prEnc Pointer to iw_point structure containing securiry + * information. \param[in] pcExtra Pointer to key string buffer. + * + * \retval 0 Success. + * \retval -EINVAL Key ID error for WEP. + * \retval -EFAULT Setting parameters to driver fail. + * \retval -EOPNOTSUPP Key size not supported. + * + * \note Securiry information is stored in pEnc. + */ +/*----------------------------------------------------------------------------*/ +static int wext_set_encode_ext(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwrInfo, + IN struct iw_point *prEnc, IN char *pcExtra) +{ + u8 wepBuf[48]; + P_PARAM_WEP_T prWepKey = (P_PARAM_WEP_T)wepBuf; + + u8 *keyStructBuf; + P_PARAM_REMOVE_KEY_T prRemoveKey; + P_PARAM_KEY_T prKey; + + struct iw_encode_ext *prIWEncExt = (struct iw_encode_ext *)pcExtra; + + ENUM_PARAM_ENCRYPTION_STATUS_T eEncStatus; + ENUM_PARAM_AUTH_MODE_T eAuthMode; + /* ENUM_PARAM_OP_MODE_T eOpMode = NET_TYPE_AUTO_SWITCH; */ + + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + int ret = 0; + + ASSERT(prNetDev); + ASSERT(prEnc); + if (GLUE_CHK_PR3(prNetDev, prEnc, pcExtra) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + keyStructBuf = kalMemAlloc(KEY_BUF_SIZE, VIR_MEM_TYPE); + if (keyStructBuf == NULL) { + DBGLOG(REQ, ERROR, "Alloc key buffer fail\n"); + return -ENOMEM; + } + kalMemSet(keyStructBuf, 0, KEY_BUF_SIZE); + + { + if ((prEnc->flags & IW_ENCODE_MODE) == IW_ENCODE_DISABLED) { + prRemoveKey = (P_PARAM_REMOVE_KEY_T)keyStructBuf; + /* Reset flag to prevent the unexpected operation */ + prRemoveKey->ucCtrlFlag = 0; + prRemoveKey->u4Length = sizeof(*prRemoveKey); + memcpy(prRemoveKey->arBSSID, prIWEncExt->addr.sa_data, + 6); + /* + * printk("IW_ENCODE_DISABLED: ID:%d, Addr:[" MACSTR + * "]\n", prRemoveKey->KeyIndex, + * MAC2STR(prRemoveKey->BSSID)); + */ + + rStatus = kalIoctl(prGlueInfo, wlanoidSetRemoveKey, + prRemoveKey, prRemoveKey->u4Length, + false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "remove key error:%lx\n", + rStatus); + } + ret = 0; + goto freeBuf; + } + /* return 0; */ + + switch (prIWEncExt->alg) { + case IW_ENCODE_ALG_NONE: + break; + + case IW_ENCODE_ALG_WEP: + /* iwconfig wlan0 key 0123456789 */ + /* iwconfig wlan0 key s:abcde */ + /* iwconfig wlan0 key 0123456789 [1] */ + /* iwconfig wlan0 key 01234567890123456789012345 [1] */ + /* check key size for WEP */ + if (prIWEncExt->key_len == 5 || + prIWEncExt->key_len == 13 || + prIWEncExt->key_len == 16) { + /* prepare PARAM_WEP key structure */ + prWepKey->u4KeyIndex = + (prEnc->flags & IW_ENCODE_INDEX) ? + (prEnc->flags & + IW_ENCODE_INDEX) - + 1 : + 0; + if (prWepKey->u4KeyIndex > 3) { + /* key id is out of range */ + ret = -EINVAL; + goto freeBuf; + } + prWepKey->u4KeyIndex |= 0x80000000; + prWepKey->u4Length = 12 + prIWEncExt->key_len; + prWepKey->u4KeyLength = prIWEncExt->key_len; + /* kalMemCopy(prWepKey->aucKeyMaterial, pcExtra, + * prIWEncExt->key_len); */ + kalMemCopy(prWepKey->aucKeyMaterial, + prIWEncExt->key, + prIWEncExt->key_len); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetAddWep, + prWepKey, prWepKey->u4Length, + false, false, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, + "wlanoidSetAddWep fail 0x%lx\n", + rStatus); + ret = -EFAULT; + goto freeBuf; + } + + /* change to auto switch */ + prGlueInfo->rWpaInfo.u4AuthAlg = + IW_AUTH_ALG_SHARED_KEY | + IW_AUTH_ALG_OPEN_SYSTEM; + eAuthMode = AUTH_MODE_AUTO_SWITCH; + + rStatus = kalIoctl(prGlueInfo, + wlanoidSetAuthMode, + &eAuthMode, + sizeof(eAuthMode), false, + false, false, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, + INFO, + "wlanoidSetAuthMode fail 0x%lx\n", + rStatus); + ret = -EFAULT; + goto freeBuf; + } + + prGlueInfo->rWpaInfo.u4CipherPairwise = + IW_AUTH_CIPHER_WEP104 | + IW_AUTH_CIPHER_WEP40; + prGlueInfo->rWpaInfo.u4CipherGroup = + IW_AUTH_CIPHER_WEP104 | + IW_AUTH_CIPHER_WEP40; + + eEncStatus = ENUM_WEP_ENABLED; + + rStatus = kalIoctl( + prGlueInfo, wlanoidSetEncryptionStatus, + &eEncStatus, + sizeof(ENUM_PARAM_ENCRYPTION_STATUS_T), + false, false, false, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, + INFO, + "wlanoidSetEncryptionStatus fail 0x%lx\n", + rStatus); + ret = -EFAULT; + goto freeBuf; + } + } else { + DBGLOG(INIT, INFO, "key length %x\n", + prIWEncExt->key_len); + DBGLOG(INIT, INFO, "key error\n"); + } + + break; + + case IW_ENCODE_ALG_TKIP: + case IW_ENCODE_ALG_CCMP: +#if CFG_SUPPORT_802_11W + case IW_ENCODE_ALG_AES_CMAC: +#endif + { + prKey = (P_PARAM_KEY_T)keyStructBuf; + /* KeyID */ + prKey->u4KeyIndex = + (prEnc->flags & IW_ENCODE_INDEX) ? + (prEnc->flags & IW_ENCODE_INDEX) - 1 : + 0; +#if CFG_SUPPORT_802_11W + if (prKey->u4KeyIndex > 5) { +#else + if (prKey->u4KeyIndex > 3) { +#endif + DBGLOG(INIT, INFO, "key index error:0x%lx\n", + prKey->u4KeyIndex); + /* key id is out of range */ + ret = -EINVAL; + goto freeBuf; + } + + /* bit(31) and bit(30) are shared by pKey and pRemoveKey + */ + /* Tx Key Bit(31) */ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + prKey->u4KeyIndex |= 0x1UL << 31; + } + + /* Pairwise Key Bit(30) */ + if (prIWEncExt->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + /* group key */ + } else { + /* pairwise key */ + prKey->u4KeyIndex |= 0x1UL << 30; + } + } + /* Rx SC Bit(29) */ + if (prIWEncExt->ext_flags & + IW_ENCODE_EXT_RX_SEQ_VALID) { + prKey->u4KeyIndex |= 0x1UL << 29; + memcpy(&prKey->rKeyRSC, prIWEncExt->rx_seq, + IW_ENCODE_SEQ_MAX_SIZE); + } + + /* BSSID */ + memcpy(prKey->arBSSID, prIWEncExt->addr.sa_data, 6); + + /* switch tx/rx MIC key for sta */ + if (prIWEncExt->alg == IW_ENCODE_ALG_TKIP && + prIWEncExt->key_len == 32) { + memcpy(prKey->aucKeyMaterial, prIWEncExt->key, + 16); + memcpy(((u8 *)prKey->aucKeyMaterial) + 16, + prIWEncExt->key + 24, 8); + memcpy((prKey->aucKeyMaterial) + 24, + prIWEncExt->key + 16, 8); + } else { + /* aucKeyMaterial is defined as a 32-elements + * array */ + if (prIWEncExt->key_len > 32) { + DBGLOG(REQ, + ERROR, + "prIWEncExt->key_len: %d is too long!\n", + prIWEncExt->key_len); + ret = -EFAULT; + goto freeBuf; + } + memcpy(prKey->aucKeyMaterial, prIWEncExt->key, + prIWEncExt->key_len); + } + + prKey->u4KeyLength = prIWEncExt->key_len; + prKey->u4Length = + ((unsigned long)&( + ((P_PARAM_KEY_T)0)->aucKeyMaterial)) + + prKey->u4KeyLength; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetAddKey, prKey, + prKey->u4Length, false, false, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "add key error:%lx\n", + rStatus); + ret = -EFAULT; + goto freeBuf; + } + break; + } + } + + ret = 0; + +freeBuf: + if (keyStructBuf) { + kalMemFree(keyStructBuf, VIR_MEM_TYPE, KEY_BUF_SIZE); + } + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Set country code + * + * \param[in] prNetDev Net device requested. + * \param[in] prData iwreq.u.data carries country code value. + * + * \retval 0 For success. + * \retval -EEFAULT For fail. + * + * \note Country code is stored and channel list is updated based on current + * country domain. + */ +/*----------------------------------------------------------------------------*/ +static int wext_set_country(IN struct net_device *prNetDev, + IN struct iw_point *prData) +{ + P_GLUE_INFO_T prGlueInfo; + WLAN_STATUS rStatus; + u32 u4BufLen; + u8 aucCountry[2]; + + ASSERT(prNetDev); + + /* prData->pointer should be like "COUNTRY US", "COUNTRY EU" + * and "COUNTRY JP" + */ + if (GLUE_CHK_PR2(prNetDev, prData) == false || !prData->pointer || + prData->length < 10) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + aucCountry[0] = *((u8 *)prData->pointer + 8); + aucCountry[1] = *((u8 *)prData->pointer + 9); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetCountryCode, &aucCountry[0], 2, + false, false, true, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "Set country code error: %x\n", rStatus); + return -EFAULT; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To report the iw private args table to user space. + * + * \param[in] prNetDev Net device requested. + * \param[out] prData iwreq.u.data to carry the private args table. + * + * \retval 0 For success. + * \retval -E2BIG For user's buffer size is too small. + * \retval -EFAULT For fail. + * + */ +/*----------------------------------------------------------------------------*/ +int wext_get_priv(IN struct net_device *prNetDev, OUT struct iw_point *prData) +{ + u16 u2BufferSize = prData->length; + + /* Update our private args table size */ + prData->length = (__u16)sizeof(rIwPrivTable); + if (u2BufferSize < prData->length) { + return -E2BIG; + } + + if (prData->length) { + if (copy_to_user(prData->pointer, rIwPrivTable, + sizeof(rIwPrivTable))) { + return -EFAULT; + } + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief ioctl() (Linux Wireless Extensions) routines + * + * \param[in] prDev Net device requested. + * \param[in] ifr The ifreq structure for seeting the wireless extension. + * \param[in] i4Cmd The wireless extension ioctl command. + * + * \retval zero On success. + * \retval -EOPNOTSUPP If the cmd is not supported. + * \retval -EFAULT If copy_to_user goes wrong. + * \retval -EINVAL If any value's out of range. + * + * \note + */ +/*----------------------------------------------------------------------------*/ +int wext_support_ioctl(IN struct net_device *prDev, IN struct ifreq *prIfReq, + IN int i4Cmd) +{ + /* prIfReq is verified in the caller function wlanDoIOCTL() */ + struct iwreq *iwr = (struct iwreq *)prIfReq; + struct iw_request_info rIwReqInfo; + int ret = 0; + char *prExtraBuf = NULL; + u32 u4ExtraSize = 0; + + /* prDev is verified in the caller function wlanDoIOCTL() */ + + /* Prepare the call */ + rIwReqInfo.cmd = (__u16)i4Cmd; + rIwReqInfo.flags = 0; + + switch (i4Cmd) { + case SIOCGIWNAME: /* 0x8B01, get wireless protocol name */ + ret = wext_get_name(prDev, &rIwReqInfo, (char *)&iwr->u.name, + NULL); + break; + + /* case SIOCSIWNWID: 0x8B02, deprecated */ + /* case SIOCGIWNWID: 0x8B03, deprecated */ + + case SIOCSIWFREQ: /* 0x8B04, set channel */ + ret = wext_set_freq(prDev, NULL, &iwr->u.freq, NULL); + break; + + case SIOCGIWFREQ: /* 0x8B05, get channel */ + ret = wext_get_freq(prDev, NULL, &iwr->u.freq, NULL); + break; + + case SIOCSIWMODE: /* 0x8B06, set operation mode */ + ret = wext_set_mode(prDev, NULL, &iwr->u.mode, NULL); + /* ret = 0; */ + break; + + case SIOCGIWMODE: /* 0x8B07, get operation mode */ + ret = wext_get_mode(prDev, NULL, &iwr->u.mode, NULL); + break; + + /* case SIOCSIWSENS: 0x8B08, unsupported */ + /* case SIOCGIWSENS: 0x8B09, unsupported */ + + /* case SIOCSIWRANGE: 0x8B0A, unused */ + case SIOCGIWRANGE: /* 0x8B0B, get range of parameters */ + if (iwr->u.data.pointer != NULL) { + /* Buffer size should be large enough */ + if (iwr->u.data.length < sizeof(struct iw_range)) { + ret = -E2BIG; + break; + } + + prExtraBuf = kalMemAlloc(sizeof(struct iw_range), + VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + /* reset all fields */ + memset(prExtraBuf, 0, sizeof(struct iw_range)); + iwr->u.data.length = sizeof(struct iw_range); + + ret = wext_get_range(prDev, NULL, &iwr->u.data, + prExtraBuf); + /* Push up to the caller */ + if (copy_to_user(iwr->u.data.pointer, prExtraBuf, + iwr->u.data.length)) { + ret = -EFAULT; + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, + sizeof(struct iw_range)); + prExtraBuf = NULL; + } else { + ret = -EINVAL; + } + break; + + case SIOCSIWPRIV: /* 0x8B0C, set country code */ + ret = wext_set_country(prDev, &iwr->u.data); + break; + + case SIOCGIWPRIV: /* 0x8B0D, get private args table */ + ret = wext_get_priv(prDev, &iwr->u.data); + break; + + /* caes SIOCSIWSTATS: 0x8B0E, unused */ + /* case SIOCGIWSTATS: + * get statistics, intercepted by wireless_process_ioctl() in + * wireless.c, redirected to dev_iwstats(), + * dev->get_wireless_stats(). + */ + /* case SIOCSIWSPY: 0x8B10, unsupported */ + /* case SIOCGIWSPY: 0x8B11, unsupported */ + /* case SIOCSIWTHRSPY: 0x8B12, unsupported */ + /* case SIOCGIWTHRSPY: 0x8B13, unsupported */ + + case SIOCSIWAP: /* 0x8B14, set access point MAC addresses (BSSID) */ + if (iwr->u.ap_addr.sa_data[0] == 0 && + iwr->u.ap_addr.sa_data[1] == 0 && + iwr->u.ap_addr.sa_data[2] == 0 && + iwr->u.ap_addr.sa_data[3] == 0 && + iwr->u.ap_addr.sa_data[4] == 0 && + iwr->u.ap_addr.sa_data[5] == 0) { + /* WPA Supplicant will set 000000000000 in + ** wpa_driver_wext_deinit(), do nothing here or disassoc + * again? + */ + ret = 0; + break; + } + ret = wext_set_ap(prDev, NULL, &iwr->u.ap_addr, NULL); + break; + + case SIOCGIWAP: /* 0x8B15, get access point MAC addresses (BSSID) */ + ret = wext_get_ap(prDev, NULL, &iwr->u.ap_addr, NULL); + break; + + case SIOCSIWMLME: /* 0x8B16, request MLME operation */ + /* Fixed length structure */ + if (iwr->u.data.length != sizeof(struct iw_mlme)) { + DBGLOG(INIT, INFO, "MLME buffer strange:%d\n", + iwr->u.data.length); + ret = -EINVAL; + break; + } + + if (!iwr->u.data.pointer) { + ret = -EINVAL; + break; + } + + prExtraBuf = kalMemAlloc(sizeof(struct iw_mlme), VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, iwr->u.data.pointer, + sizeof(struct iw_mlme))) { + ret = -EFAULT; + } else { + ret = wext_set_mlme(prDev, NULL, &(iwr->u.data), + prExtraBuf); + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, sizeof(struct iw_mlme)); + prExtraBuf = NULL; + break; + + /* case SIOCGIWAPLIST: 0x8B17, deprecated */ + case SIOCSIWSCAN: /* 0x8B18, scan request */ + if (iwr->u.data.pointer == NULL) { + ret = wext_set_scan(prDev, NULL, NULL, NULL); + } +#if WIRELESS_EXT > 17 + else if (iwr->u.data.length == sizeof(struct iw_scan_req)) { + struct iw_scan_req *req; + + prExtraBuf = kalMemAlloc(MAX_SSID_LEN, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + req = (struct iw_scan_req *)(iwr->u.data.pointer); + + if (req->essid_len > MAX_SSID_LEN) { + ret = -EFAULT; + } else if (kalMemCopy(prExtraBuf, req->essid, + req->essid_len)) { + ret = -EFAULT; + } else { + ret = wext_set_scan( + prDev, NULL, + (union iwreq_data *)&(iwr->u.data), + prExtraBuf); + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, MAX_SSID_LEN); + prExtraBuf = NULL; + } +#endif + else { + ret = -EINVAL; + } + break; + + case SIOCGIWSCAN: /* 0x8B19, get scan results */ + if (!iwr->u.data.pointer || !iwr->u.essid.pointer) { + ret = -EINVAL; + break; + } + + u4ExtraSize = iwr->u.data.length; + /* allocate the same size of kernel buffer to store scan + * results. */ + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + /* iwr->u.data.length may be updated by wext_get_scan() */ + ret = wext_get_scan(prDev, NULL, &iwr->u.data, prExtraBuf); + if (ret != 0) { + if (ret == -E2BIG) { + DBGLOG(INIT, INFO, + "[wifi] wext_get_scan -E2BIG\n"); + } + } else { + /* check updated length is valid */ + ASSERT(iwr->u.data.length <= u4ExtraSize); + if (iwr->u.data.length > u4ExtraSize) { + DBGLOG(INIT, + INFO, + "Updated result length is larger than allocated (%d > %ld)\n", + iwr->u.data.length, + u4ExtraSize); + iwr->u.data.length = u4ExtraSize; + } + + if (copy_to_user(iwr->u.data.pointer, prExtraBuf, + iwr->u.data.length)) { + ret = -EFAULT; + } + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + + break; + + case SIOCSIWESSID: /* 0x8B1A, set SSID (network name) */ + if (iwr->u.essid.length > IW_ESSID_MAX_SIZE) { + ret = -E2BIG; + break; + } + if (!iwr->u.essid.pointer) { + ret = -EINVAL; + break; + } + + prExtraBuf = kalMemAlloc(IW_ESSID_MAX_SIZE + 4, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, iwr->u.essid.pointer, + iwr->u.essid.length)) { + ret = -EFAULT; + } else { + /* Add trailing '\0' for printk */ + /* prExtraBuf[iwr->u.essid.length] = 0; */ + + ret = wext_set_essid(prDev, NULL, &iwr->u.essid, + prExtraBuf); + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, IW_ESSID_MAX_SIZE + 4); + prExtraBuf = NULL; + break; + + case SIOCGIWESSID: /* 0x8B1B, get SSID */ + if (!iwr->u.essid.pointer) { + ret = -EINVAL; + break; + } + + if (iwr->u.essid.length != IW_ESSID_MAX_SIZE && + iwr->u.essid.length != IW_ESSID_MAX_SIZE + 1) { + DBGLOG(INIT, INFO, + "[wifi] iwr->u.essid.length:%d error\n", + iwr->u.essid.length); + ret = -E2BIG; /* let caller try larger buffer */ + break; + } + + prExtraBuf = kalMemAlloc(IW_ESSID_MAX_SIZE + 1, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + /* iwr->u.essid.length is updated by wext_get_essid() */ + + ret = wext_get_essid(prDev, NULL, &iwr->u.essid, prExtraBuf); + if (ret == 0) { + if (copy_to_user(iwr->u.essid.pointer, prExtraBuf, + iwr->u.essid.length)) { + ret = -EFAULT; + } + } + + kalMemFree(prExtraBuf, VIR_MEM_TYPE, IW_ESSID_MAX_SIZE + 1); + prExtraBuf = NULL; + + break; + + /* case SIOCSIWNICKN: 0x8B1C, not supported */ + /* case SIOCGIWNICKN: 0x8B1D, not supported */ + + case SIOCSIWRATE: /* 0x8B20, set default bit rate (bps) */ + /* ret = wext_set_rate(prDev, &rIwReqInfo, &iwr->u.bitrate, + * NULL); */ + break; + + case SIOCGIWRATE: /* 0x8B21, get current bit rate (bps) */ + ret = wext_get_rate(prDev, NULL, &iwr->u.bitrate, NULL); + break; + + case SIOCSIWRTS: /* 0x8B22, set rts/cts threshold */ + ret = wext_set_rts(prDev, NULL, &iwr->u.rts, NULL); + break; + + case SIOCGIWRTS: /* 0x8B23, get rts/cts threshold */ + ret = wext_get_rts(prDev, NULL, &iwr->u.rts, NULL); + break; + + /* case SIOCSIWFRAG: 0x8B24, unsupported */ + case SIOCGIWFRAG: /* 0x8B25, get frag threshold */ + ret = wext_get_frag(prDev, NULL, &iwr->u.frag, NULL); + break; + + case SIOCSIWTXPOW: /* 0x8B26, set relative tx power (in %) */ + ret = wext_set_txpow(prDev, NULL, &iwr->u.txpower, NULL); + break; + + case SIOCGIWTXPOW: /* 0x8B27, get relative tx power (in %) */ + ret = wext_get_txpow(prDev, NULL, &iwr->u.txpower, NULL); + break; + + /* case SIOCSIWRETRY: 0x8B28, unsupported */ + /* case SIOCGIWRETRY: 0x8B29, unsupported */ + + case SIOCSIWENCODE: /* 0x8B2A, set encoding token & mode */ + /* Only DISABLED case has NULL pointer and length == 0 */ + if (iwr->u.encoding.pointer) { + if (iwr->u.encoding.length > 16) { + ret = -E2BIG; + break; + } + + u4ExtraSize = iwr->u.encoding.length; + if (u4ExtraSize < sizeof(struct iw_encode_ext)) { + ret = -EINVAL; + break; + } + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, iwr->u.encoding.pointer, + iwr->u.encoding.length)) { + ret = -EFAULT; + } + } else if (iwr->u.encoding.length != 0) { + ret = -EINVAL; + break; + } + + if (ret == 0) { + ret = wext_set_encode(prDev, NULL, &iwr->u.encoding, + prExtraBuf); + } + + if (prExtraBuf) { + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + } + break; + + case SIOCGIWENCODE: /* 0x8B2B, get encoding token & mode */ + /* check pointer */ + ret = wext_get_encode(prDev, NULL, &iwr->u.encoding, NULL); + break; + + case SIOCSIWPOWER: /* 0x8B2C, set power management */ + ret = wext_set_power(prDev, NULL, &iwr->u.power, NULL); + break; + + case SIOCGIWPOWER: /* 0x8B2D, get power management */ + ret = wext_get_power(prDev, NULL, &iwr->u.power, NULL); + break; + +#if WIRELESS_EXT > 17 + case SIOCSIWGENIE: /* 0x8B30, set gen ie */ + if (iwr->u.data.pointer) { + P_GLUE_INFO_T prGlueInfo = + *((P_GLUE_INFO_T *)netdev_priv(prDev)); + + if (1 /* wlanQueryWapiMode(prGlueInfo->prAdapter) */ ) { + /*aucWSCAssocInfoIE max size */ + if (iwr->u.data.length > 200) { + ret = -EINVAL; + break; + } + + u4ExtraSize = iwr->u.data.length; + if (u4ExtraSize) { + prExtraBuf = kalMemAlloc(u4ExtraSize, + VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + if (copy_from_user(prExtraBuf, + iwr->u.data.pointer, + iwr->u.data.length)) { + ret = -EFAULT; + } else { + wext_support_ioctl_SIOCSIWGENIE( + prGlueInfo, prExtraBuf, + u4ExtraSize); + } + kalMemFree(prExtraBuf, VIR_MEM_TYPE, + u4ExtraSize); + prExtraBuf = NULL; + } + } + } + break; + + case SIOCGIWGENIE: /* 0x8B31, get gen ie, unused */ + break; +#endif + + case SIOCSIWAUTH: /* 0x8B32, set auth mode params */ + ret = wext_set_auth(prDev, NULL, &iwr->u.param, NULL); + break; + + /* case SIOCGIWAUTH: 0x8B33, unused? */ + case SIOCSIWENCODEEXT: /* 0x8B34, set extended encoding token & mode */ + if (iwr->u.encoding.pointer) { + u4ExtraSize = iwr->u.encoding.length; + + /* check here was less than < before, but changed to != + * lest malicious big length according to driver code, + * max key len is only 32, so check that too. + */ + if (u4ExtraSize < sizeof(struct iw_encode_ext) || + u4ExtraSize > sizeof(struct iw_encode_ext) + 32) { + ret = -EINVAL; + break; + } + + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, iwr->u.encoding.pointer, + u4ExtraSize)) { + ret = -EFAULT; + } + } else if (iwr->u.encoding.length != 0) { + ret = -EINVAL; + break; + } + + if (ret == 0) { + ret = wext_set_encode_ext(prDev, NULL, &iwr->u.encoding, + prExtraBuf); + } + + if (prExtraBuf) { + kalMemFree(prExtraBuf, VIR_MEM_TYPE, u4ExtraSize); + prExtraBuf = NULL; + } + break; + + /* case SIOCGIWENCODEEXT: 0x8B35, unused? */ + + case SIOCSIWPMKSA: /* 0x8B36, pmksa cache operation */ + if (iwr->u.data.pointer) { + /* Fixed length structure */ + if (iwr->u.data.length != sizeof(struct iw_pmksa)) { + ret = -EINVAL; + break; + } + + u4ExtraSize = sizeof(struct iw_pmksa); + prExtraBuf = kalMemAlloc(u4ExtraSize, VIR_MEM_TYPE); + if (!prExtraBuf) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(prExtraBuf, iwr->u.data.pointer, + sizeof(struct iw_pmksa))) { + ret = -EFAULT; + } else { + switch (((struct iw_pmksa *)prExtraBuf)->cmd) { + case IW_PMKSA_ADD: + /* + * printk(KERN_INFO "IW_PMKSA_ADD [" + * MACSTR "]\n", MAC2STR(((struct + * iw_pmksa + **)pExtraBuf)->bssid.sa_data)); + */ + { + wext_support_ioctl_SIOCSIWPMKSA_Action( + prDev, prExtraBuf, + IW_PMKSA_ADD, &ret); + } + break; + + case IW_PMKSA_REMOVE: + /* + * printk(KERN_INFO "IW_PMKSA_REMOVE [" + * MACSTR "]\n", MAC2STR(((struct + * iw_pmksa *)buf)->bssid.sa_data)); + */ + break; + + case IW_PMKSA_FLUSH: + /* + * printk(KERN_INFO + * "IW_PMKSA_FLUSH\n"); + */ + { + wext_support_ioctl_SIOCSIWPMKSA_Action( + prDev, prExtraBuf, + IW_PMKSA_FLUSH, &ret); + } + break; + + default: + DBGLOG(INIT, INFO, + "UNKNOWN iw_pmksa command:%d\n", + ((struct iw_pmksa *)prExtraBuf) + ->cmd); + ret = -EFAULT; + break; + } + } + + if (prExtraBuf) { + kalMemFree(prExtraBuf, VIR_MEM_TYPE, + u4ExtraSize); + prExtraBuf = NULL; + } + } else if (iwr->u.data.length != 0) { + ret = -EINVAL; + break; + } + + break; + + default: + + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static void wext_support_ioctl_SIOCSIWGENIE(IN P_GLUE_INFO_T prGlueInfo, + IN char *prExtraBuf, + IN u32 u4ExtraSize) +{ + WLAN_STATUS rStatus; + u32 u4BufLen; + +#if CFG_SUPPORT_WPS2 + u8 *prDesiredIE = NULL; + + if (wextSrchDesiredWPSIE(prExtraBuf, u4ExtraSize, 0xDD, + (u8 **)&prDesiredIE)) { + rStatus = kalIoctl(prGlueInfo, wlanoidSetWSCAssocInfo, + prDesiredIE, IE_SIZE(prDesiredIE), false, + false, true, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + /* do nothing */ + } + } +#endif +} + +static void wext_support_ioctl_SIOCSIWPMKSA_Action(IN struct net_device *prDev, + IN char *prExtraBuf, + IN int ioMode, OUT int *ret) +{ + P_GLUE_INFO_T prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + WLAN_STATUS rStatus; + u32 u4BufLen; + P_PARAM_PMKID_T prPmkid; + + switch (ioMode) { + case IW_PMKSA_ADD: + prPmkid = (P_PARAM_PMKID_T)kalMemAlloc( + 8 + sizeof(PARAM_BSSID_INFO_T), VIR_MEM_TYPE); + if (!prPmkid) { + DBGLOG(INIT, INFO, + "Can not alloc memory for IW_PMKSA_ADD\n"); + *ret = -ENOMEM; + break; + } + + prPmkid->u4Length = 8 + sizeof(PARAM_BSSID_INFO_T); + prPmkid->u4BSSIDInfoCount = 1; + kalMemCopy(prPmkid->arBSSIDInfo->arBSSID, + ((struct iw_pmksa *)prExtraBuf)->bssid.sa_data, 6); + kalMemCopy(prPmkid->arBSSIDInfo->arPMKID, + ((struct iw_pmksa *)prExtraBuf)->pmkid, + IW_PMKID_LEN); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetPmkid, prPmkid, + sizeof(PARAM_PMKID_T), false, false, true, + &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "add pmkid error:%lx\n", rStatus); + } + + kalMemFree(prPmkid, VIR_MEM_TYPE, + 8 + sizeof(PARAM_BSSID_INFO_T)); + break; + + case IW_PMKSA_FLUSH: + prPmkid = (P_PARAM_PMKID_T)kalMemAlloc(8, VIR_MEM_TYPE); + if (!prPmkid) { + DBGLOG(INIT, INFO, + "Can not alloc memory for IW_PMKSA_FLUSH\n"); + *ret = -ENOMEM; + break; + } + + prPmkid->u4Length = 8; + prPmkid->u4BSSIDInfoCount = 0; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetPmkid, prPmkid, + sizeof(PARAM_PMKID_T), false, false, true, + &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(INIT, INFO, "flush pmkid error:%lx\n", rStatus); + } + + kalMemFree(prPmkid, VIR_MEM_TYPE, 8); + break; + + default: + break; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief To send an event (RAW socket pacekt) to user process actively. + * + * \param[in] prGlueInfo Glue layer info. + * \param[in] u4cmd Which event command we want to indicate to user process. + * \param[in] pData Data buffer to be indicated. + * \param[in] dataLen Available data size in pData. + * + * \return (none) + * + * \note Event is indicated to upper layer if cmd is supported and data is + * valid. Using of kernel symbol wireless_send_event(), which is defined in + * <net/iw_handler.h> after WE-14 (2.4.20). + */ +/*----------------------------------------------------------------------------*/ +void wext_indicate_wext_event(IN P_GLUE_INFO_T prGlueInfo, + IN unsigned int u4Cmd, IN unsigned char *pucData, + IN unsigned int u4dataLen) +{ + union iwreq_data wrqu; + unsigned char *pucExtraInfo = NULL; +#if WIRELESS_EXT >= 15 + unsigned char *pucDesiredIE = NULL; + unsigned char aucExtraInfoBuf[200]; +#endif +#if WIRELESS_EXT < 18 + int len; + int ret; + int i; +#endif + + memset(&wrqu, 0, sizeof(wrqu)); + + switch (u4Cmd) { + case SIOCGIWSCAN: + complete_all(&prGlueInfo->rScanComp); + break; + + case SIOCGIWAP: + if (pucData) { + kalMemCopy(&wrqu.ap_addr.sa_data, pucData, ETH_ALEN); + }else{ + eth_zero_addr((u8 *)&wrqu.ap_addr.sa_data); + } + + break; + + case IWEVASSOCREQIE: +#if WIRELESS_EXT < 15 + /* under WE-15, no suitable Event can be used */ + goto skip_indicate_event; +#else + /* do supplicant a favor, parse to the start of WPA/RSN IE */ + if (wextSrchDesiredWPAIE(pucData, u4dataLen, 0x30, + &pucDesiredIE)) { + /* RSN IE found */ + /* RSN IE found */ + } else if (wextSrchDesiredWPAIE(pucData, u4dataLen, 0xDD, + &pucDesiredIE)) { + /* WPA IE found */ + /* WPA IE found */ + } else { + /* no WPA/RSN IE found, skip this event */ + goto skip_indicate_event; + } + +#if WIRELESS_EXT < 18 + /* under WE-18, only IWEVCUSTOM can be used */ + u4Cmd = IWEVCUSTOM; + pucExtraInfo = aucExtraInfoBuf; + len = sizeof(aucExtraInfoBuf); + ret = sprintf(pucExtraInfo, "ASSOCINFO(ReqIEs="); + if (ret < 0) { + DBGLOG(INIT, ERROR, "%s:%d:sprintf return %d\n", + __FUNCTION__, __LINE__, ret); + goto skip_indicate_event; + } + len -= ret; + pucExtraInfo += ret; + + /* translate binary string to hex string, requirement of + * IWEVCUSTOM */ + + if (((pucDesiredIE[1] + 2) * 2) > (len - 1)) { + DBGLOG(INIT, INFO, + "size of pucDesiredIE[1] exceeds buffer size\n"); + goto skip_indicate_event; + } + + for (i = 0; i < pucDesiredIE[1] + 2; ++i) { + ret = snprintf(pucExtraInfo, len, "%02x", + pucDesiredIE[i]); + if (ret < 0) { + DBGLOG(INIT, ERROR, + "%s:%d:snprintf return %d\n", + __FUNCTION__, __LINE__, ret); + goto skip_indicate_event; + } + len -= ret; + pucExtraInfo += ret; + } + pucExtraInfo = aucExtraInfoBuf; + wrqu.data.length = 17 + (pucDesiredIE[1] + 2) * 2; +#else + /* IWEVASSOCREQIE, indicate binary string */ + pucExtraInfo = pucDesiredIE; + wrqu.data.length = pucDesiredIE[1] + 2; +#endif +#endif + break; + + case IWEVMICHAELMICFAILURE: +#if WIRELESS_EXT < 15 + /* under WE-15, no suitable Event can be used */ + goto skip_indicate_event; +#else + if (pucData) { + s32 i4BufLen = 0; + P_PARAM_AUTH_REQUEST_T pAuthReq = + (P_PARAM_AUTH_REQUEST_T)pucData; + /* under WE-18, only IWEVCUSTOM can be used */ + u4Cmd = IWEVCUSTOM; + pucExtraInfo = aucExtraInfoBuf; + + i4BufLen = + scnprintf(pucExtraInfo, sizeof(aucExtraInfoBuf), + "MLME-MICHAELMICFAILURE.indication "); + + i4BufLen += scnprintf( + (pucExtraInfo + i4BufLen), + (sizeof(aucExtraInfoBuf) - i4BufLen), "%s", + (pAuthReq->u4Flags == + PARAM_AUTH_REQUEST_GROUP_ERROR) ? + "groupcast " : + "unicast "); + + wrqu.data.length = i4BufLen; + pucExtraInfo = aucExtraInfoBuf; + } +#endif + break; + + case IWEVPMKIDCAND: + if (prGlueInfo->rWpaInfo.u4WpaVersion == + IW_AUTH_WPA_VERSION_WPA2 && + prGlueInfo->rWpaInfo.u4KeyMgmt == IW_AUTH_KEY_MGMT_802_1X) { + /* only used in WPA2 */ +#if WIRELESS_EXT >= 18 + P_PARAM_PMKID_CANDIDATE_T prPmkidCand = + (P_PARAM_PMKID_CANDIDATE_T)pucData; + + struct iw_pmkid_cand rPmkidCand; + + pucExtraInfo = aucExtraInfoBuf; + + rPmkidCand.flags = prPmkidCand->u4Flags; + rPmkidCand.index = 0; + kalMemCopy(rPmkidCand.bssid.sa_data, + prPmkidCand->arBSSID, 6); + + kalMemCopy(pucExtraInfo, (u8 *)&rPmkidCand, + sizeof(struct iw_pmkid_cand)); + wrqu.data.length = sizeof(struct iw_pmkid_cand); + + /* pmkid canadidate list is supported after WE-18 */ + /* indicate struct iw_pmkid_cand */ +#else + + goto skip_indicate_event; +#endif + } else { + goto skip_indicate_event; + } + break; + + case IWEVCUSTOM: + u4Cmd = IWEVCUSTOM; + pucExtraInfo = aucExtraInfoBuf; + kalMemCopy(pucExtraInfo, pucData, sizeof(PTA_IPC_T)); + wrqu.data.length = sizeof(PTA_IPC_T); + break; + + default: + + goto skip_indicate_event; + } + + /* Send event to user space */ + wireless_send_event(prGlueInfo->prDevHandler, u4Cmd, &wrqu, + pucExtraInfo); + +skip_indicate_event: + return; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief A method of struct net_device, to get the network interface + * statistical information. + * + * Whenever an application needs to get statistics for the interface, this + * method is called. This happens, for example, when ifconfig or netstat -i is + * run. + * + * \param[in] pDev Pointer to struct net_device. + * + * \return net_device_stats buffer pointer. + * + */ +/*----------------------------------------------------------------------------*/ +struct iw_statistics *wext_get_wireless_stats(struct net_device *prDev) +{ + WLAN_STATUS rStatus = WLAN_STATUS_FAILURE; + P_GLUE_INFO_T prGlueInfo = NULL; + struct iw_statistics *pStats = NULL; + s32 i4Rssi; + u32 bufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + goto stat_out; + } + + pStats = (struct iw_statistics *)(&(prGlueInfo->rIwStats)); + + if (!prDev || !netif_carrier_ok(prDev)) { + /* network not connected */ + goto stat_out; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryRssi, &i4Rssi, + sizeof(i4Rssi), true, true, true, &bufLen); + +stat_out: + return pStats; +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_wext_priv.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_wext_priv.c new file mode 100644 index 00000000000000..da28c65a4e8b59 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/gl_wext_priv.c @@ -0,0 +1,16751 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_wext_priv.c + * \brief This file includes private ioctl support. + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" +#include "gl_os.h" +#include "gl_wext_priv.h" + +#if CFG_SUPPORT_QA_TOOL +#include "gl_ate_agent.h" +#include "gl_qa_agent.h" +#endif + +#if CFG_ENABLE_WIFI_DIRECT +#include "gl_p2p_os.h" +#endif + +/* + * #if CFG_SUPPORT_QA_TOOL + * extern u16 g_u2DumpIndex; + * #endif + */ + +#if (CFG_SUPPORT_DFS_MASTER == 1) +#include "gl_hook_api.h" +#endif + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define NUM_SUPPORTED_OIDS (sizeof(arWlanOidReqTable) / \ + sizeof(WLAN_REQ_ENTRY)) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +static int priv_get_ndis(IN struct net_device *prNetDev, + IN NDIS_TRANSPORT_STRUCT *prNdisReq, + OUT u32 *pu4OutputLen); + +static int priv_set_ndis(IN struct net_device *prNetDev, + IN NDIS_TRANSPORT_STRUCT *prNdisReq, + OUT u32 *pu4OutputLen); + +static u8 reqSearchSupportedOidEntry(IN u32 rOid, + OUT P_WLAN_REQ_ENTRY *ppWlanReqEntry); + +static WLAN_STATUS reqExtSetAcpiDevicePowerState(IN P_GLUE_INFO_T prGlueInfo, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen); + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +static u8 aucOidBuf[4096] = { 0 }; + +/* OID processing table */ +/* Order is important here because the OIDs should be in order of + * increasing value for binary searching. + */ +static WLAN_REQ_ENTRY arWlanOidReqTable[] = { + /* Ethernet Operational Characteristics */ + { OID_802_3_CURRENT_ADDRESS, DISP_STRING("OID_802_3_CURRENT_ADDRESS"), + true, true, ENUM_OID_DRIVER_CORE, 6, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryCurrentAddr, NULL }, + + /* OID_802_3_MULTICAST_LIST */ + /* OID_802_3_MAXIMUM_LIST_SIZE */ + /* Ethernet Statistics */ + + /* NDIS 802.11 Wireless LAN OIDs */ + { OID_802_11_SUPPORTED_RATES, DISP_STRING("OID_802_11_SUPPORTED_RATES"), + true, false, ENUM_OID_DRIVER_CORE, sizeof(PARAM_RATES_EX), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQuerySupportedRates, NULL }, + /* + * {OID_802_11_CONFIGURATION, + * DISP_STRING("OID_802_11_CONFIGURATION"), + * true, true, ENUM_OID_GLUE_EXTENSION, sizeof(PARAM_802_11_CONFIG_T), + * (PFN_OID_HANDLER_FUNC_REQ)reqExtQueryConfiguration, + * (PFN_OID_HANDLER_FUNC_REQ)reqExtSetConfiguration}, + */ + { OID_PNP_SET_POWER, DISP_STRING("OID_PNP_SET_POWER"), true, false, + ENUM_OID_GLUE_EXTENSION, sizeof(PARAM_DEVICE_POWER_STATE), NULL, + (PFN_OID_HANDLER_FUNC_REQ)reqExtSetAcpiDevicePowerState }, + + /* Custom OIDs */ + { OID_CUSTOM_OID_INTERFACE_VERSION, + DISP_STRING("OID_CUSTOM_OID_INTERFACE_VERSION"), true, false, + ENUM_OID_DRIVER_CORE, 4, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryOidInterfaceVersion, NULL }, + + { OID_CUSTOM_MCR_RW, DISP_STRING("OID_CUSTOM_MCR_RW"), true, true, + ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_MCR_RW_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryMcrRead, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetMcrWrite }, + + { OID_CUSTOM_EEPROM_RW, DISP_STRING("OID_CUSTOM_EEPROM_RW"), true, true, + ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_EEPROM_RW_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryEepromRead, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetEepromWrite }, + + { OID_CUSTOM_SW_CTRL, DISP_STRING("OID_CUSTOM_SW_CTRL"), true, true, + ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQuerySwCtrlRead, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetSwCtrlWrite }, + + { OID_CUSTOM_MEM_DUMP, DISP_STRING("OID_CUSTOM_MEM_DUMP"), true, true, + ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_MEM_DUMP_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryMemDump, NULL }, + + { OID_CUSTOM_TEST_MODE, DISP_STRING("OID_CUSTOM_TEST_MODE"), false, + false, ENUM_OID_DRIVER_CORE, 0, NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidRftestSetTestMode }, + + { OID_CUSTOM_ABORT_TEST_MODE, DISP_STRING("OID_CUSTOM_ABORT_TEST_MODE"), + false, false, ENUM_OID_DRIVER_CORE, 0, NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidRftestSetAbortTestMode }, + { OID_CUSTOM_MTK_WIFI_TEST, DISP_STRING("OID_CUSTOM_MTK_WIFI_TEST"), + true, true, ENUM_OID_DRIVER_CORE, + sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidRftestQueryAutoTest, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidRftestSetAutoTest }, + { OID_CUSTOM_TEST_ICAP_MODE, DISP_STRING("OID_CUSTOM_TEST_ICAP_MODE"), + false, false, ENUM_OID_DRIVER_CORE, 0, NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidRftestSetTestIcapMode }, + +/* OID_CUSTOM_EMULATION_VERSION_CONTROL */ + +/* BWCS */ +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS + { OID_CUSTOM_BWCS_CMD, DISP_STRING("OID_CUSTOM_BWCS_CMD"), false, false, + ENUM_OID_DRIVER_CORE, sizeof(PTA_IPC_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryBT, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetBT }, +#endif + + { OID_CUSTOM_MTK_NVRAM_RW, DISP_STRING("OID_CUSTOM_MTK_NVRAM_RW"), true, + true, ENUM_OID_DRIVER_CORE, sizeof(PARAM_CUSTOM_NVRAM_RW_STRUCT_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryNvramRead, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetNvramWrite }, + + { OID_CUSTOM_CFG_SRC_TYPE, DISP_STRING("OID_CUSTOM_CFG_SRC_TYPE"), + false, false, ENUM_OID_DRIVER_CORE, sizeof(ENUM_CFG_SRC_TYPE_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryCfgSrcType, NULL }, + + { OID_CUSTOM_EEPROM_TYPE, DISP_STRING("OID_CUSTOM_EEPROM_TYPE"), false, + false, ENUM_OID_DRIVER_CORE, sizeof(ENUM_EEPROM_TYPE_T), + (PFN_OID_HANDLER_FUNC_REQ)wlanoidQueryEepromType, NULL }, + +#if CFG_SUPPORT_WPS2 + { OID_802_11_WSC_ASSOC_INFO, DISP_STRING("OID_802_11_WSC_ASSOC_INFO"), + false, false, ENUM_OID_DRIVER_CORE, 0, NULL, + (PFN_OID_HANDLER_FUNC_REQ)wlanoidSetWSCAssocInfo }, +#endif +}; + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Dispatching function for private ioctl region (SIOCIWFIRSTPRIV ~ + * SIOCIWLASTPRIV). + * + * \param[in] prNetDev Net device requested. + * \param[in] prIfReq Pointer to ifreq structure. + * \param[in] i4Cmd Command ID between SIOCIWFIRSTPRIV and SIOCIWLASTPRIV. + * + * \retval 0 for success. + * \retval -EOPNOTSUPP If cmd is not supported. + * \retval -EFAULT For fail. + * + */ +/*----------------------------------------------------------------------------*/ +int priv_support_ioctl(IN struct net_device *prNetDev, + IN OUT struct ifreq *prIfReq, IN int i4Cmd) +{ + /* prIfReq is verified in the caller function wlanDoIOCTL() */ + struct iwreq *prIwReq = (struct iwreq *)prIfReq; + struct iw_request_info rIwReqInfo; + + /* prNetDev is verified in the caller function wlanDoIOCTL() */ + + /* Prepare the call */ + rIwReqInfo.cmd = (__u16)i4Cmd; + rIwReqInfo.flags = 0; + + switch (i4Cmd) { + case IOCTL_SET_INT: + /* NOTE(Kevin): 1/3 INT Type <= IFNAMSIZ, so we don't need + * copy_from/to_user() */ + return priv_set_int(prNetDev, &rIwReqInfo, &(prIwReq->u), + (char *)&(prIwReq->u)); + + case IOCTL_GET_INT: + /* NOTE(Kevin): 1/3 INT Type <= IFNAMSIZ, so we don't need + * copy_from/to_user() */ + return priv_get_int(prNetDev, &rIwReqInfo, &(prIwReq->u), + (char *)&(prIwReq->u)); + + case IOCTL_SET_STRUCT: + /* case IOCTL_SET_STRUCT_FOR_EM: Engineer Mode not need in FOS + */ + return priv_set_struct(prNetDev, &rIwReqInfo, &prIwReq->u, + (char *)&(prIwReq->u)); + + case IOCTL_GET_STRUCT: + return priv_get_struct(prNetDev, &rIwReqInfo, &prIwReq->u, + (char *)&(prIwReq->u)); + +#if (CFG_SUPPORT_QA_TOOL) + case IOCTL_QA_TOOL_DAEMON: + return priv_qa_agent(prNetDev, &rIwReqInfo, &(prIwReq->u), + (char *)&(prIwReq->u)); + +#endif + + case IOCTL_GET_STR: + + default: + return -EOPNOTSUPP; + } /* end of switch */ +} + +#if CFG_SUPPORT_BATCH_SCAN + +EVENT_BATCH_RESULT_T g_rEventBatchResult[CFG_BATCH_MAX_MSCAN]; + +u32 batchChannelNum2Freq(u32 u4ChannelNum) +{ + u32 u4ChannelInMHz; + + if (u4ChannelNum >= 1 && u4ChannelNum <= 13) { + u4ChannelInMHz = 2412 + (u4ChannelNum - 1) * 5; + }else if (u4ChannelNum == 14) { + u4ChannelInMHz = 2484; + }else if (u4ChannelNum == 133) { + u4ChannelInMHz = 3665; /* 802.11y */ + }else if (u4ChannelNum == 137) { + u4ChannelInMHz = 3685; /* 802.11y */ + }else if (u4ChannelNum >= 34 && u4ChannelNum <= 165) { + u4ChannelInMHz = 5000 + u4ChannelNum * 5; + }else if (u4ChannelNum >= 183 && u4ChannelNum <= 196) { + u4ChannelInMHz = 4000 + u4ChannelNum * 5; + }else{ + u4ChannelInMHz = 0; + } + + return u4ChannelInMHz; +} + +#define TMP_TEXT_LEN_S 40 +#define TMP_TEXT_LEN_L 60 +static u8 text1[TMP_TEXT_LEN_S], text2[TMP_TEXT_LEN_L], + text3[TMP_TEXT_LEN_L]; /* A safe len */ + +WLAN_STATUS +batchConvertResult(IN P_EVENT_BATCH_RESULT_T prEventBatchResult, + OUT void *pvBuffer, IN u32 u4MaxBufferLen, + OUT u32 *pu4RetLen) +{ + s8 *p = pvBuffer; + s8 ssid[ELEM_MAX_LEN_SSID + 1]; + s32 nsize, nsize1, nsize2, nsize3, scancount; + s32 i, j, nleft; + u32 freq; + + P_EVENT_BATCH_RESULT_ENTRY_T prEntry; + P_EVENT_BATCH_RESULT_T pBr; + + nsize = 0; + nleft = u4MaxBufferLen; + + pBr = prEventBatchResult; + scancount = 0; + for (j = 0; j < CFG_BATCH_MAX_MSCAN; j++) { + scancount += pBr->ucScanCount; + pBr++; + } + + nsize1 = scnprintf(text1, TMP_TEXT_LEN_S, + "scancount=%ld\nnextcount=%ld\n", scancount, + scancount); + if (nsize1 < nleft) { + nsize1 = scnprintf(p, nleft, "%s", text1); + p += nsize1; + nleft -= nsize1; + } else { + goto short_buf; + } + + pBr = prEventBatchResult; + for (j = 0; j < CFG_BATCH_MAX_MSCAN; j++) { + DBGLOG(SCN, TRACE, "convert mscan = %d, apcount=%d, nleft=%d\n", + j, pBr->ucScanCount, nleft); + + if (pBr->ucScanCount == 0) { + pBr++; + continue; + } + + nleft -= 5; /* -5 for "####\n" */ + + /* We only support one round scan result now. */ + nsize1 = scnprintf(text1, TMP_TEXT_LEN_S, "apcount=%d\n", + pBr->ucScanCount); + if (nsize1 < nleft) { + nsize1 = scnprintf(p, nleft, "%s", text1); + p += nsize1; + nleft -= nsize1; + } else { + goto short_buf; + } + + for (i = 0; i < pBr->ucScanCount; i++) { + prEntry = &pBr->arBatchResult[i]; + + nsize1 = scnprintf(text1, TMP_TEXT_LEN_S, + "bssid=" MACSTR "\n", + MAC2STR(prEntry->aucBssid)); + kalMemCopy(ssid, prEntry->aucSSID, + (prEntry->ucSSIDLen < ELEM_MAX_LEN_SSID ? + prEntry->ucSSIDLen : + ELEM_MAX_LEN_SSID)); + ssid[(prEntry->ucSSIDLen < (ELEM_MAX_LEN_SSID - 1) ? + prEntry->ucSSIDLen : + (ELEM_MAX_LEN_SSID - 1))] = '\0'; + nsize2 = scnprintf(text2, TMP_TEXT_LEN_L, "ssid=%s\n", + ssid); + + freq = batchChannelNum2Freq(prEntry->ucFreq); + nsize3 = scnprintf( + text3, + TMP_TEXT_LEN_L, + "freq=%lu\nlevel=%d\ndist=%lu\ndistSd=%lu\n====\n", + freq, + prEntry->cRssi, + prEntry->u4Dist, + prEntry->u4Distsd); + + nsize = nsize1 + nsize2 + nsize3; + if (nsize < nleft) { + kalStrnCpy(p, text1, TMP_TEXT_LEN_S); + p += nsize1; + + kalStrnCpy(p, text2, TMP_TEXT_LEN_L); + p += nsize2; + + kalStrnCpy(p, text3, TMP_TEXT_LEN_L); + p += nsize3; + + nleft -= nsize; + } else { + DBGLOG(SCN, TRACE, + "Warning: Early break! (%d)\n", i); + break; /* discard following entries, TODO: + * apcount? */ + } + } + + nsize1 = kalSnprintf(text1, TMP_TEXT_LEN_S, "%s", "####\n"); + if (nsize1 < nleft) { + nsize1 = scnprintf(p, nleft, "%s", text1); + p += nsize1; + nleft -= nsize1; + } else { + goto short_buf; + } + + pBr++; + } + + nsize1 = scnprintf(text1, TMP_TEXT_LEN_S, "%s", "----\n"); + if (nsize1 < nleft) { + scnprintf(p, nleft, "%s", text1); + }else{ + goto short_buf; + } + + *pu4RetLen = u4MaxBufferLen - nleft; + DBGLOG(SCN, TRACE, "total len = %d (max len = %d)\n", *pu4RetLen, + u4MaxBufferLen); + + return WLAN_STATUS_SUCCESS; + +short_buf: + DBGLOG(SCN, TRACE, "Short buffer issue! %d > %d, %s\n", + u4MaxBufferLen + (nsize - nleft), u4MaxBufferLen, pvBuffer); + return WLAN_STATUS_INVALID_LENGTH; +} +#endif + +void parseNoiseHistogramReport(s32 *i4BytesWritten, s8 *pcCommand, + int *i4TotalLen, + IN struct CMD_NOISE_HISTOGRAM_REPORT *cmd) +{ + if (cmd->ucAction == CMD_NOISE_HISTOGRAM_GET) { + *i4BytesWritten += snprintf(pcCommand + *i4BytesWritten, + *i4TotalLen - *i4BytesWritten, + "\nWF0 Noise IPI"); +#if CFG_IPI_2CHAIN_SUPPORT + } else if (cmd->ucAction == CMD_NOISE_HISTOGRAM_GET2) { + *i4BytesWritten += snprintf(pcCommand + *i4BytesWritten, + *i4TotalLen - *i4BytesWritten, + "\nWF1 Noise IPI"); +#endif + } + *i4BytesWritten += snprintf(pcCommand + *i4BytesWritten, + *i4TotalLen - *i4BytesWritten, + "\n Power > -55: %10d", cmd->u4IPI10); + *i4BytesWritten += snprintf(pcCommand + *i4BytesWritten, + *i4TotalLen - *i4BytesWritten, + "\n-55 >= Power > -60: %10d", cmd->u4IPI9); + *i4BytesWritten += snprintf(pcCommand + *i4BytesWritten, + *i4TotalLen - *i4BytesWritten, + "\n-60 >= Power > -65: %10d", cmd->u4IPI8); + *i4BytesWritten += snprintf(pcCommand + *i4BytesWritten, + *i4TotalLen - *i4BytesWritten, + "\n-65 >= Power > -70: %10d", cmd->u4IPI7); + *i4BytesWritten += snprintf(pcCommand + *i4BytesWritten, + *i4TotalLen - *i4BytesWritten, + "\n-70 >= Power > -75: %10d", cmd->u4IPI6); + *i4BytesWritten += snprintf(pcCommand + *i4BytesWritten, + *i4TotalLen - *i4BytesWritten, + "\n-75 >= Power > -80: %10d", cmd->u4IPI5); + *i4BytesWritten += snprintf(pcCommand + *i4BytesWritten, + *i4TotalLen - *i4BytesWritten, + "\n-80 >= Power > -83: %10d", cmd->u4IPI4); + *i4BytesWritten += snprintf(pcCommand + *i4BytesWritten, + *i4TotalLen - *i4BytesWritten, + "\n-83 >= Power > -86: %10d", cmd->u4IPI3); + *i4BytesWritten += snprintf(pcCommand + *i4BytesWritten, + *i4TotalLen - *i4BytesWritten, + "\n-86 >= Power > -89: %10d", cmd->u4IPI2); + *i4BytesWritten += snprintf(pcCommand + *i4BytesWritten, + *i4TotalLen - *i4BytesWritten, + "\n-89 >= Power > -92: %10d", cmd->u4IPI1); + *i4BytesWritten += snprintf(pcCommand + *i4BytesWritten, + *i4TotalLen - *i4BytesWritten, + "\n-92 >= Power : %10d", cmd->u4IPI0); +} +/*----------------------------------------------------------------------------*/ +/*! + * \brief Private ioctl set int handler. + * + * \param[in] prNetDev Net device requested. + * \param[in] prIwReqInfo Pointer to iwreq structure. + * \param[in] prIwReqData The ioctl data structure, use the field of + * sub-command. \param[in] pcExtra The buffer with input value + * + * \retval 0 For success. + * \retval -EOPNOTSUPP If cmd is not supported. + * \retval -EINVAL If a value is out of range. + * + */ +/*----------------------------------------------------------------------------*/ +int priv_set_int(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN char *pcExtra) +{ + u32 u4SubCmd; + u32 *pu4IntBuf; + P_NDIS_TRANSPORT_STRUCT prNdisReq; + P_GLUE_INFO_T prGlueInfo; + u32 u4BufLen = 0; + int status = 0; + P_PTA_IPC_T prPtaIpc; + + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + + if (GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (!test_bit(GLUE_FLAG_ADAPT_RDY_BIT, &prGlueInfo->ulFlag)) { + DBGLOG(REQ, INFO, "adapter is not ready\n"); + return -EIO; + } + + u4SubCmd = (u32)prIwReqData->mode; + pu4IntBuf = (u32 *)pcExtra; + + switch (u4SubCmd) { + case PRIV_CMD_TEST_MODE: + + prNdisReq = (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0]; + + if (pu4IntBuf[1] == PRIV_CMD_TEST_MAGIC_KEY) { + prNdisReq->ndisOidCmd = OID_CUSTOM_TEST_MODE; + } else if (pu4IntBuf[1] == 0) { + prNdisReq->ndisOidCmd = OID_CUSTOM_ABORT_TEST_MODE; + } else if (pu4IntBuf[1] == PRIV_CMD_TEST_MAGIC_KEY_ICAP) { + prNdisReq->ndisOidCmd = OID_CUSTOM_TEST_ICAP_MODE; + } else { + status = 0; + break; + } + prNdisReq->inNdisOidlength = 0; + prNdisReq->outNdisOidLength = 0; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; + + case PRIV_CMD_TEST_CMD: + + prNdisReq = (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0]; + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MTK_WIFI_TEST; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; + +#if CFG_SUPPORT_PRIV_MCR_RW + case PRIV_CMD_ACCESS_MCR: + + prNdisReq = (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0]; + + if (!prGlueInfo->fgMcrAccessAllowed) { + if (pu4IntBuf[1] == PRIV_CMD_TEST_MAGIC_KEY && + pu4IntBuf[2] == PRIV_CMD_TEST_MAGIC_KEY) { + prGlueInfo->fgMcrAccessAllowed = true; + } + status = 0; + break; + } + + if (pu4IntBuf[1] == PRIV_CMD_TEST_MAGIC_KEY && + pu4IntBuf[2] == PRIV_CMD_TEST_MAGIC_KEY) { + status = 0; + break; + } + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MCR_RW; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; +#endif + + case PRIV_CMD_SW_CTRL: + + prNdisReq = (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0]; + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; + +#if CFG_TCP_IP_CHKSUM_OFFLOAD + case PRIV_CMD_CSUM_OFFLOAD: { + u32 u4CSUMFlags; + + if (pu4IntBuf[1] == 1) { + u4CSUMFlags = CSUM_OFFLOAD_EN_ALL; + }else if (pu4IntBuf[1] == 0) { + u4CSUMFlags = 0; + }else{ + return -EINVAL; + } + + if (kalIoctl(prGlueInfo, wlanoidSetCSUMOffload, + (void *)&u4CSUMFlags, sizeof(u32), false, false, + true, &u4BufLen) == WLAN_STATUS_SUCCESS) { + if (pu4IntBuf[1] == 1) { + prNetDev->features |= NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM; + } else if (pu4IntBuf[1] == 0) { + prNetDev->features &= + ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM); + } + } + } break; +#endif + + case PRIV_CMD_POWER_MODE: { + PARAM_POWER_MODE_T rPowerMode; + + P_BSS_INFO_T prBssInfo = prGlueInfo->prAdapter->prAisBssInfo; + + if (!prBssInfo) { + break; + } + + rPowerMode.ePowerMode = (PARAM_POWER_MODE)pu4IntBuf[1]; + rPowerMode.ucBssIdx = prBssInfo->ucBssIndex; + + /* pu4IntBuf[0] is used as input SubCmd */ + kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile, + &rPowerMode, sizeof(PARAM_POWER_MODE_T), false, false, + true, &u4BufLen); + } break; + + case PRIV_CMD_WMM_PS: { + PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T rWmmPsTest; + + rWmmPsTest.bmfgApsdEnAc = (u8)pu4IntBuf[1]; + rWmmPsTest.ucIsEnterPsAtOnce = (u8)pu4IntBuf[2]; + rWmmPsTest.ucIsDisableUcTrigger = (u8)pu4IntBuf[3]; + rWmmPsTest.reserved = 0; + + kalIoctl(prGlueInfo, wlanoidSetWiFiWmmPsTest, + (void *)&rWmmPsTest, + sizeof(PARAM_CUSTOM_WMM_PS_TEST_STRUCT_T), false, + false, true, &u4BufLen); + } break; + + case PRIV_CUSTOM_BWCS_CMD: + + DBGLOG(REQ, INFO, + "pu4IntBuf[1] = %x, size of PTA_IPC_T = %d.\n", + pu4IntBuf[1], sizeof(PARAM_PTA_IPC_T)); + + prPtaIpc = (P_PTA_IPC_T)aucOidBuf; + prPtaIpc->u.aucBTPParams[0] = (u8)(pu4IntBuf[1] >> 24); + prPtaIpc->u.aucBTPParams[1] = (u8)(pu4IntBuf[1] >> 16); + prPtaIpc->u.aucBTPParams[2] = (u8)(pu4IntBuf[1] >> 8); + prPtaIpc->u.aucBTPParams[3] = (u8)(pu4IntBuf[1]); + + DBGLOG(REQ, + INFO, + "BCM BWCS CMD : PRIV_CUSTOM_BWCS_CMD : aucBTPParams[0] = %02x, aucBTPParams[1] = %02x.\n", + prPtaIpc->u.aucBTPParams[0], + prPtaIpc->u.aucBTPParams[1]); + DBGLOG(REQ, + INFO, + "BCM BWCS CMD : PRIV_CUSTOM_BWCS_CMD : aucBTPParams[2] = %02x, aucBTPParams[3] = %02x.\n", + prPtaIpc->u.aucBTPParams[2], + prPtaIpc->u.aucBTPParams[3]); + + status = wlanoidSetBT(prGlueInfo->prAdapter, + (void *)&aucOidBuf[0], + sizeof(PARAM_PTA_IPC_T), &u4BufLen); + + if (status != WLAN_STATUS_SUCCESS) { + status = -EFAULT; + } + + break; + + case PRIV_CMD_BAND_CONFIG: { + DBGLOG(INIT, INFO, "CMD set_band = %lu\n", (u32)pu4IntBuf[1]); + } break; + +#if CFG_ENABLE_WIFI_DIRECT + case PRIV_CMD_P2P_MODE: { + PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; + WLAN_STATUS rWlanStatus = WLAN_STATUS_SUCCESS; + + rSetP2P.u4Enable = pu4IntBuf[1]; + rSetP2P.u4Mode = pu4IntBuf[2]; + + if (!rSetP2P.u4Enable) { + p2pNetUnregister(prGlueInfo, true); + } + + if (((rSetP2P.u4Mode == RUNNING_DUAL_AP_MODE) || + (rSetP2P.u4Mode == RUNNING_P2P_AP_MODE)) && + (gprP2pRoleWdev[1] == NULL) && (rSetP2P.u4Enable)) { + glP2pCreateWirelessDevice(prGlueInfo); + ASSERT(gprP2pRoleWdev[1] != NULL); + } + + /* pu4IntBuf[0] is used as input SubCmd */ + rWlanStatus = kalIoctl(prGlueInfo, wlanoidSetP2pMode, + (void *)&rSetP2P, + sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T), + false, false, true, &u4BufLen); + + if ((rSetP2P.u4Enable) && + (rWlanStatus == WLAN_STATUS_SUCCESS)) { + if (p2pNetRegister(prGlueInfo, true) == false) { + DBGLOG(INIT, ERROR, "p2pNetRegister failed\n"); + } + } + } break; +#endif + +#if (CFG_MET_PACKET_TRACE_SUPPORT == 1) + case PRIV_CMD_MET_PROFILING: { + /* PARAM_CUSTOM_WFD_DEBUG_STRUCT_T rWfdDebugModeInfo; */ + /* rWfdDebugModeInfo.ucWFDDebugMode=(u8)pu4IntBuf[1]; */ + /* rWfdDebugModeInfo.u2SNPeriod=(u16)pu4IntBuf[2]; */ + /* DBGLOG(REQ, INFO, ("WFD Debug Mode:%d Period:%d\n", + * rWfdDebugModeInfo.ucWFDDebugMode, + * rWfdDebugModeInfo.u2SNPeriod)); + */ + prGlueInfo->fgMetProfilingEn = (u8)pu4IntBuf[1]; + prGlueInfo->u2MetUdpPort = (u16)pu4IntBuf[2]; + /* DBGLOG(INIT, INFO, ("MET_PROF: Enable=%d UDP_PORT=%d\n", + * prGlueInfo->fgMetProfilingEn, prGlueInfo->u2MetUdpPort); + */ + } break; +#endif + + default: + return -EOPNOTSUPP; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Private ioctl get int handler. + * + * \param[in] pDev Net device requested. + * \param[out] pIwReq Pointer to iwreq structure. + * \param[in] prIwReqData The ioctl req structure, use the field of sub-command. + * \param[out] pcExtra The buffer with put the return value + * + * \retval 0 For success. + * \retval -EOPNOTSUPP If cmd is not supported. + * \retval -EFAULT For fail. + * + */ +/*----------------------------------------------------------------------------*/ +int priv_get_int(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + u32 u4SubCmd; + u32 *pu4IntBuf; + P_GLUE_INFO_T prGlueInfo; + u32 u4BufLen = 0; + int status = 0; + P_NDIS_TRANSPORT_STRUCT prNdisReq; + s32 ch[MAX_CHN_NUM]; + + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + if (GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (!test_bit(GLUE_FLAG_ADAPT_RDY_BIT, &prGlueInfo->ulFlag)) { + DBGLOG(REQ, INFO, "adapter is not ready\n"); + return -EIO; + } + + u4SubCmd = (u32)prIwReqData->mode; + pu4IntBuf = (u32 *)pcExtra; + + switch (u4SubCmd) { + case PRIV_CMD_TEST_CMD: + + prNdisReq = (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0]; + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MTK_WIFI_TEST; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) { + prIwReqData->mode = + *(u32 *)&prNdisReq->ndisOidContent[4]; + /* + * if (copy_to_user(prIwReqData->data.pointer, + * &prNdisReq->ndisOidContent[4], 4)) { + * printk(KERN_NOTICE "priv_get_int() copy_to_user + * oidBuf fail(3)\n"); return -EFAULT; + * } + */ + } + return status; + +#if CFG_SUPPORT_PRIV_MCR_RW + case PRIV_CMD_ACCESS_MCR: + + prNdisReq = (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0]; + + if (!prGlueInfo->fgMcrAccessAllowed) { + status = 0; + return status; + } + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MCR_RW; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) { + prIwReqData->mode = + *(u32 *)&prNdisReq->ndisOidContent[4]; + } + return status; + +#endif + + case PRIV_CMD_DUMP_MEM: + prNdisReq = (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0]; + + if (!prGlueInfo->fgMcrAccessAllowed || + !capable(CAP_NET_ADMIN)) { + DBGLOG(REQ, WARN, "Access Denied\n"); + status = 0; + return status; + } + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_MEM_DUMP; + prNdisReq->inNdisOidlength = + sizeof(PARAM_CUSTOM_MEM_DUMP_STRUCT_T); + prNdisReq->outNdisOidLength = + sizeof(PARAM_CUSTOM_MEM_DUMP_STRUCT_T); + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) { + prIwReqData->mode = + *(u32 *)&prNdisReq->ndisOidContent[0]; + } + return status; + + case PRIV_CMD_SW_CTRL: + + prNdisReq = (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0]; + + kalMemCopy(&prNdisReq->ndisOidContent[0], &pu4IntBuf[1], 8); + + prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) { + prIwReqData->mode = + *(u32 *)&prNdisReq->ndisOidContent[4]; + } + return status; + + case PRIV_CMD_BAND_CONFIG: + DBGLOG(INIT, INFO, "CMD get_band=\n"); + prIwReqData->mode = 0; + return status; + + default: + break; + } + + u4SubCmd = (u32)prIwReqData->data.flags; + + switch (u4SubCmd) { + case PRIV_CMD_GET_CH_LIST: { + u16 j = 0; + u8 NumOfChannel = MAX_CHN_NUM; + u8 ucMaxChannelNum = MAX_CHN_NUM; + RF_CHANNEL_INFO_T aucChannelList[MAX_CHN_NUM]; + + DBGLOG(RLM, INFO, "Domain: Query Channel List.\n"); + kalMemZero(aucChannelList, + sizeof(RF_CHANNEL_INFO_T) * MAX_CHN_NUM); + kalGetChannelList(prGlueInfo, BAND_NULL, ucMaxChannelNum, + &NumOfChannel, aucChannelList); + if (NumOfChannel > MAX_CHN_NUM) { + NumOfChannel = MAX_CHN_NUM; + } + + /* kalIsAPmode() always returns false => remove it to avoid + * security issue: */ + /* Leak kernel stack data + * to userland */ + for (j = 0; j < NumOfChannel; j++) + ch[j] = (s32)aucChannelList[j].ucChannelNum; + + prIwReqData->data.length = j; + if (copy_to_user(prIwReqData->data.pointer, ch, + NumOfChannel * sizeof(s32))) { + return -EFAULT; + }else{ + return status; + } + } + + default: + return -EOPNOTSUPP; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Private ioctl set int array handler. + * + * \param[in] prNetDev Net device requested. + * \param[in] prIwReqInfo Pointer to iwreq structure. + * \param[in] prIwReqData The ioctl data structure, use the field of + * sub-command. \param[in] pcExtra The buffer with input value + * + * \retval 0 For success. + * \retval -EOPNOTSUPP If cmd is not supported. + * \retval -EINVAL If a value is out of range. + * + */ +/*----------------------------------------------------------------------------*/ +int priv_set_ints(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN char *pcExtra) +{ + u32 u4SubCmd, u4BufLen, u4CmdLen; + P_GLUE_INFO_T prGlueInfo; + int status = 0; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_SET_TXPWR_CTRL_T prTxpwr; + u16 i = 0; + s32 setting[4] = { 0 }; + + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + + if (GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (!test_bit(GLUE_FLAG_ADAPT_RDY_BIT, &prGlueInfo->ulFlag)) { + DBGLOG(REQ, INFO, "adapter is not ready\n"); + return -EIO; + } + + u4SubCmd = (u32)prIwReqData->data.flags; + u4CmdLen = prIwReqData->data.length; + + switch (u4SubCmd) { + case PRIV_CMD_SET_TX_POWER: { + if (u4CmdLen > 4) { + return -EINVAL; + } + + if (copy_from_user(setting, prIwReqData->data.pointer, + u4CmdLen)) { + return -EFAULT; + } + + prTxpwr = &prGlueInfo->rTxPwr; + if (setting[0] == 0 && + prIwReqData->data.length == 4 /* argc num */ ) { + /* 0 (All networks), 1 (legacy STA), 2 (Hotspot AP), 3 + * (P2P), 4 (BT over Wi-Fi) */ + if (setting[1] == 1 || setting[1] == 0) { + if (setting[2] == 0 || setting[2] == 1) { + prTxpwr->c2GLegacyStaPwrOffset = + setting[3]; + } + if (setting[2] == 0 || setting[2] == 2) { + prTxpwr->c5GLegacyStaPwrOffset = + setting[3]; + } + } + if (setting[1] == 2 || setting[1] == 0) { + if (setting[2] == 0 || setting[2] == 1) { + prTxpwr->c2GHotspotPwrOffset = + setting[3]; + } + if (setting[2] == 0 || setting[2] == 2) { + prTxpwr->c5GHotspotPwrOffset = + setting[3]; + } + } + if (setting[1] == 3 || setting[1] == 0) { + if (setting[2] == 0 || setting[2] == 1) { + prTxpwr->c2GP2pPwrOffset = setting[3]; + } + if (setting[2] == 0 || setting[2] == 2) { + prTxpwr->c5GP2pPwrOffset = setting[3]; + } + } + if (setting[1] == 4 || setting[1] == 0) { + if (setting[2] == 0 || setting[2] == 1) { + prTxpwr->c2GBowPwrOffset = setting[3]; + } + if (setting[2] == 0 || setting[2] == 2) { + prTxpwr->c5GBowPwrOffset = setting[3]; + } + } + } else if (setting[0] == 1 && prIwReqData->data.length == 2) { + prTxpwr->ucConcurrencePolicy = setting[1]; + } else if (setting[0] == 2 && prIwReqData->data.length == 3) { + if (setting[1] == 0) { + for (i = 0; i < 14; i++) + prTxpwr->acTxPwrLimit2G[i] = setting[2]; + } else if (setting[1] <= 14) { + prTxpwr->acTxPwrLimit2G[setting[1] - 1] = + setting[2]; + } + } else if (setting[0] == 3 && prIwReqData->data.length == 3) { + if (setting[1] == 0) { + for (i = 0; i < 4; i++) + prTxpwr->acTxPwrLimit5G[i] = setting[2]; + } else if (setting[1] <= 4) { + prTxpwr->acTxPwrLimit5G[setting[1] - 1] = + setting[2]; + } + } else if (setting[0] == 4 && prIwReqData->data.length == 2) { + if (setting[1] == 0) { + wlanDefTxPowerCfg(prGlueInfo->prAdapter); + } + rStatus = kalIoctl(prGlueInfo, wlanoidSetTxPower, + prTxpwr, sizeof(SET_TXPWR_CTRL_T), + false, false, true, &u4BufLen); + } else { + return -EFAULT; + } + } + return status; + + default: + break; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Private ioctl get int array handler. + * + * \param[in] pDev Net device requested. + * \param[out] pIwReq Pointer to iwreq structure. + * \param[in] prIwReqData The ioctl req structure, use the field of sub-command. + * \param[out] pcExtra The buffer with put the return value + * + * \retval 0 For success. + * \retval -EOPNOTSUPP If cmd is not supported. + * \retval -EFAULT For fail. + * + */ +/*----------------------------------------------------------------------------*/ +int priv_get_ints(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + u32 u4SubCmd; + P_GLUE_INFO_T prGlueInfo; + int status = 0; + s32 ch[MAX_CHN_NUM]; + + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + if (GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (!test_bit(GLUE_FLAG_ADAPT_RDY_BIT, &prGlueInfo->ulFlag)) { + DBGLOG(REQ, INFO, "adapter is not ready\n"); + return -EIO; + } + + u4SubCmd = (u32)prIwReqData->data.flags; + + switch (u4SubCmd) { + case PRIV_CMD_GET_CH_LIST: { + u16 i; + u8 NumOfChannel = MAX_CHN_NUM; + u8 ucMaxChannelNum = MAX_CHN_NUM; + RF_CHANNEL_INFO_T aucChannelList[MAX_CHN_NUM]; + + kalMemZero(aucChannelList, + sizeof(RF_CHANNEL_INFO_T) * MAX_CHN_NUM); + kalGetChannelList(prGlueInfo, BAND_NULL, ucMaxChannelNum, + &NumOfChannel, aucChannelList); + if (NumOfChannel > MAX_CHN_NUM) { + NumOfChannel = MAX_CHN_NUM; + } + + for (i = 0; i < NumOfChannel; i++) + ch[i] = (s32)aucChannelList[i].ucChannelNum; + + prIwReqData->data.length = NumOfChannel; + if (copy_to_user(prIwReqData->data.pointer, ch, + NumOfChannel * sizeof(s32))) { + return -EFAULT; + }else{ + return status; + } + } + + default: + break; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Private ioctl set structure handler. + * + * \param[in] pDev Net device requested. + * \param[in] prIwReqData Pointer to iwreq_data structure. + * + * \retval 0 For success. + * \retval -EOPNOTSUPP If cmd is not supported. + * \retval -EINVAL If a value is out of range. + * + */ +/*----------------------------------------------------------------------------*/ +int priv_set_struct(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN char *pcExtra) +{ + u32 u4SubCmd = 0; + int status = 0; + /* WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; */ + u32 u4CmdLen = 0; + P_NDIS_TRANSPORT_STRUCT prNdisReq; + + P_GLUE_INFO_T prGlueInfo = NULL; + u32 u4BufLen = 0; + + ASSERT(prNetDev); + /* ASSERT(prIwReqInfo); */ + ASSERT(prIwReqData); + /* ASSERT(pcExtra); */ + + kalMemZero(&aucOidBuf[0], sizeof(aucOidBuf)); + + if (GLUE_CHK_PR2(prNetDev, prIwReqData) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (!test_bit(GLUE_FLAG_ADAPT_RDY_BIT, &prGlueInfo->ulFlag)) { + DBGLOG(REQ, INFO, "adapter is not ready\n"); + return -EIO; + } + + u4SubCmd = (u32)prIwReqData->data.flags; + switch (u4SubCmd) { + case PRIV_CUSTOM_BWCS_CMD: + u4CmdLen = prIwReqData->data.length * sizeof(u32); + ASSERT(sizeof(PARAM_PTA_IPC_T) >= u4CmdLen); + if (sizeof(PARAM_PTA_IPC_T) < u4CmdLen) { + return -EFAULT; + } + +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG + DBGLOG(REQ, + INFO, + "ucCmdLen = %d, size of PTA_IPC_T = %d, prIwReqData->data = 0x%x.\n", + u4CmdLen, + sizeof(PARAM_PTA_IPC_T), + prIwReqData->data); + + DBGLOG(REQ, + INFO, + "priv_set_struct(): prIwReqInfo->cmd(0x%X), u4SubCmd(%ld)\n", + prIwReqInfo->cmd, + u4SubCmd); + DBGLOG(REQ, INFO, "*pcExtra = 0x%x\n", *pcExtra); +#endif + + if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, + u4CmdLen)) { + status = -EFAULT; /* return -EFAULT; */ + break; + } +#if CFG_SUPPORT_BCM && CFG_SUPPORT_BCM_BWCS && CFG_SUPPORT_BCM_BWCS_DEBUG + DBGLOG(REQ, INFO, + "priv_set_struct(): BWCS CMD = %02x%02x%02x%02x\n", + aucOidBuf[2], aucOidBuf[3], aucOidBuf[4], aucOidBuf[5]); +#endif + status = wlanoidSetBT(prGlueInfo->prAdapter, + (void *)&aucOidBuf[0], u4CmdLen, + &u4BufLen); + + if (status != WLAN_STATUS_SUCCESS) { + status = -EFAULT; + } + + break; + +#if CFG_SUPPORT_WPS2 + case PRIV_CMD_WSC_PROBE_REQ: { + if (prIwReqData->data.length > 500) { + status = -EINVAL; + break; + } + + /* retrieve IE for Probe Request */ + if (prIwReqData->data.length > 0) { + if (copy_from_user(prGlueInfo->aucWSCIE, + prIwReqData->data.pointer, + prIwReqData->data.length)) { + status = -EFAULT; + break; + } + prGlueInfo->u2WSCIELen = prIwReqData->data.length; + } else { + prGlueInfo->u2WSCIELen = 0; + } + } break; + +#endif + case PRIV_CMD_OID: + if (prIwReqData->data.length > 4096) { + status = -EINVAL; + break; + } + if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, + prIwReqData->data.length)) { + status = -EFAULT; + break; + } + if (!kalMemCmp(&aucOidBuf[0], pcExtra, + prIwReqData->data.length)) { + /* ToDo:: DBGLOG */ + DBGLOG(REQ, INFO, "pcExtra buffer is valid\n"); + } else { + DBGLOG(REQ, INFO, "pcExtra 0x%p\n", pcExtra); + } + /* Execute this OID */ + status = priv_set_ndis(prNetDev, + (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0], + &u4BufLen); + /* Copy result to user space */ + ((P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0])->outNdisOidLength = + u4BufLen; + + if (copy_to_user(prIwReqData->data.pointer, &aucOidBuf[0], + OFFSET_OF(NDIS_TRANSPORT_STRUCT, + ndisOidContent))) { + DBGLOG(REQ, INFO, "copy_to_user oidBuf fail\n"); + status = -EFAULT; + } + + break; + + case PRIV_CMD_SW_CTRL: + if (prIwReqData->data.length > + (sizeof(aucOidBuf) - + OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent))) { + DBGLOG(REQ, INFO, + "priv_get_struct() exceeds length limit\n"); + return -EFAULT; + } + + prNdisReq = (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0]; + + /* if (copy_from_user(&prNdisReq->ndisOidContent[0], + * prIwReqData->data.pointer, prIwReqData->data.length)) { + */ + /* Coverity uanble to detect real size of ndisOidContent, + * it's 4096 bytes instead of 16 bytes + */ + if (copy_from_user(&aucOidBuf[OFFSET_OF(NDIS_TRANSPORT_STRUCT, + ndisOidContent)], + prIwReqData->data.pointer, + prIwReqData->data.length)) { + status = -EFAULT; + break; + } + prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + /* Execute this OID */ + status = priv_set_ndis(prNetDev, prNdisReq, &u4BufLen); + break; + + default: + return -EOPNOTSUPP; + } + + return status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Private ioctl get struct handler. + * + * \param[in] pDev Net device requested. + * \param[out] pIwReq Pointer to iwreq structure. + * \param[in] cmd Private sub-command. + * + * \retval 0 For success. + * \retval -EFAULT If copy from user space buffer fail. + * \retval -EOPNOTSUPP Parameter "cmd" not recognized. + * + */ +/*----------------------------------------------------------------------------*/ +int priv_get_struct(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + u32 u4SubCmd = 0; + P_NDIS_TRANSPORT_STRUCT prNdisReq = NULL; + + P_GLUE_INFO_T prGlueInfo = NULL; + u32 u4BufLen = 0; + u32 *pu4IntBuf = NULL; + u8 *prDest = NULL; + int status = 0; + + kalMemZero(&aucOidBuf[0], sizeof(aucOidBuf)); + + ASSERT(prNetDev); + ASSERT(prIwReqData); + if (!prNetDev || !prIwReqData) { + DBGLOG(REQ, INFO, + "priv_get_struct(): invalid param(0x%p, 0x%p)\n", + prNetDev, prIwReqData); + return -EINVAL; + } + + u4SubCmd = (u32)prIwReqData->data.flags; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + DBGLOG(REQ, INFO, + "priv_get_struct(): invalid prGlueInfo(0x%p, 0x%p)\n", + prNetDev, *((P_GLUE_INFO_T *)netdev_priv(prNetDev))); + return -EINVAL; + } + + if (!test_bit(GLUE_FLAG_ADAPT_RDY_BIT, &prGlueInfo->ulFlag)) { + DBGLOG(REQ, + INFO, + "adapter is not ready\n"); + return -EIO; + } + + memset(aucOidBuf, 0, sizeof(aucOidBuf)); + + switch (u4SubCmd) { + case PRIV_CMD_OID: + if (copy_from_user(&aucOidBuf[0], prIwReqData->data.pointer, + sizeof(NDIS_TRANSPORT_STRUCT))) { + DBGLOG(REQ, INFO, + "priv_get_struct() copy_from_user oidBuf fail\n"); + return -EFAULT; + } + + prNdisReq = (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0]; + if (priv_get_ndis(prNetDev, prNdisReq, &u4BufLen) == 0) { + prNdisReq->outNdisOidLength = u4BufLen; + kalMemCopy(pcExtra, prNdisReq, + u4BufLen + sizeof(NDIS_TRANSPORT_STRUCT) - + sizeof(prNdisReq->ndisOidContent)); + if (copy_to_user( + prIwReqData->data.pointer, &aucOidBuf[0], + u4BufLen + sizeof(NDIS_TRANSPORT_STRUCT) - + sizeof(prNdisReq->ndisOidContent))) { + DBGLOG(REQ, + INFO, + "priv_get_struct() copy_to_user oidBuf fail(1)\n"); + return -EFAULT; + } + return 0; + } + prNdisReq->outNdisOidLength = u4BufLen; + if (copy_to_user(prIwReqData->data.pointer, &aucOidBuf[0], + OFFSET_OF(NDIS_TRANSPORT_STRUCT, + ndisOidContent))) { + DBGLOG(REQ, INFO, + "priv_get_struct() copy_to_user oidBuf fail(2)\n"); + } + return -EFAULT; + + case PRIV_CMD_SW_CTRL: + pu4IntBuf = (u32 *)prIwReqData->data.pointer; + prNdisReq = (P_NDIS_TRANSPORT_STRUCT)&aucOidBuf[0]; + prDest = (u8 *)&aucOidBuf[OFFSET_OF(NDIS_TRANSPORT_STRUCT, + ndisOidContent)]; + + if (prIwReqData->data.length > + (sizeof(aucOidBuf) - + OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent))) { + DBGLOG(REQ, INFO, + "priv_get_struct() exceeds length limit\n"); + return -EFAULT; + } + + if (copy_from_user(prDest, prIwReqData->data.pointer, + prIwReqData->data.length)) { + DBGLOG(REQ, INFO, + "priv_get_struct() copy_from_user oidBuf fail\n"); + return -EFAULT; + } + + prNdisReq->ndisOidCmd = OID_CUSTOM_SW_CTRL; + prNdisReq->inNdisOidlength = 8; + prNdisReq->outNdisOidLength = 8; + + status = priv_get_ndis(prNetDev, prNdisReq, &u4BufLen); + if (status == 0) { + prNdisReq->outNdisOidLength = u4BufLen; + + if (copy_to_user(prIwReqData->data.pointer, + &prNdisReq->ndisOidContent[4], 4)) { + DBGLOG(REQ, + INFO, + "priv_get_struct() copy_to_user oidBuf fail(2)\n"); + } + } + return 0; + + default: + DBGLOG(REQ, WARN, "get struct cmd:0x%lx\n", u4SubCmd); + return -EOPNOTSUPP; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief The routine handles a set operation for a single OID. + * + * \param[in] pDev Net device requested. + * \param[in] ndisReq Ndis request OID information copy from user. + * \param[out] outputLen_p If the call is successful, returns the number of + * bytes written into the query buffer. If the + * call failed due to invalid length of the query + * buffer, returns the amount of storage needed.. + * + * \retval 0 On success. + * \retval -EOPNOTSUPP If cmd is not supported. + * + */ +/*----------------------------------------------------------------------------*/ +static int priv_set_ndis(IN struct net_device *prNetDev, + IN NDIS_TRANSPORT_STRUCT *prNdisReq, + OUT u32 *pu4OutputLen) +{ + P_WLAN_REQ_ENTRY prWlanReqEntry = NULL; + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + u32 u4SetInfoLen = 0; + + ASSERT(prNetDev); + ASSERT(prNdisReq); + ASSERT(pu4OutputLen); + + if (!prNetDev || !prNdisReq || !pu4OutputLen) { + DBGLOG(REQ, INFO, + "priv_set_ndis(): invalid param(0x%p, 0x%p, 0x%p)\n", + prNetDev, prNdisReq, pu4OutputLen); + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + DBGLOG(REQ, INFO, + "priv_set_ndis(): invalid prGlueInfo(0x%p, 0x%p)\n", + prNetDev, *((P_GLUE_INFO_T *)netdev_priv(prNetDev))); + return -EINVAL; + } + + if (reqSearchSupportedOidEntry(prNdisReq->ndisOidCmd, + &prWlanReqEntry) == false) { + /* WARNLOG(("Set OID: 0x%08lx (unknown)\n", + * prNdisReq->ndisOidCmd)); */ + return -EOPNOTSUPP; + } + + if (prWlanReqEntry->pfOidSetHandler == NULL) { + /* WARNLOG(("Set %s: Null set handler\n", + * prWlanReqEntry->pucOidName)); */ + return -EOPNOTSUPP; + } + + if (prWlanReqEntry->fgSetBufLenChecking) { + if (prNdisReq->inNdisOidlength != + prWlanReqEntry->u4InfoBufLen) { + DBGLOG(REQ, + WARN, + "Set %s: Invalid length (current=%ld, needed=%ld)\n", + prWlanReqEntry->pucOidName, + prNdisReq->inNdisOidlength, + prWlanReqEntry->u4InfoBufLen); + + *pu4OutputLen = prWlanReqEntry->u4InfoBufLen; + return -EINVAL; + } + } else { + if (prNdisReq->inNdisOidlength > + (sizeof(aucOidBuf) - + OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent))) { + DBGLOG(REQ, INFO, "exceeds length limit\n"); + return -EINVAL; + } + } + + if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_ONLY) { + /* GLUE sw info only */ + status = prWlanReqEntry->pfOidSetHandler( + prGlueInfo, prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, &u4SetInfoLen); + } else if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_EXTENSION) { + /* multiple sw operations */ + status = prWlanReqEntry->pfOidSetHandler( + prGlueInfo, prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, &u4SetInfoLen); + } else if (prWlanReqEntry->eOidMethod == ENUM_OID_DRIVER_CORE) { + /* driver core */ + + status = kalIoctl( + prGlueInfo, + (PFN_OID_HANDLER_FUNC)prWlanReqEntry->pfOidSetHandler, + prNdisReq->ndisOidContent, prNdisReq->inNdisOidlength, + false, false, true, &u4SetInfoLen); + } else { + DBGLOG(REQ, INFO, + "priv_set_ndis(): unsupported OID method:0x%x\n", + prWlanReqEntry->eOidMethod); + return -EOPNOTSUPP; + } + + *pu4OutputLen = u4SetInfoLen; + + switch (status) { + case WLAN_STATUS_SUCCESS: + break; + + case WLAN_STATUS_INVALID_LENGTH: + /* WARNLOG(("Set %s: Invalid length (current=%ld, + * needed=%ld)\n", */ + /* prWlanReqEntry->pucOidName, */ + /* prNdisReq->inNdisOidlength, */ + /* u4SetInfoLen)); */ + break; + } + + if (status != WLAN_STATUS_SUCCESS) { + return -EFAULT; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief The routine handles a query operation for a single OID. Basically we + * return information about the current state of the OID in question. + * + * \param[in] pDev Net device requested. + * \param[in] ndisReq Ndis request OID information copy from user. + * \param[out] outputLen_p If the call is successful, returns the number of + * bytes written into the query buffer. If the + * call failed due to invalid length of the query + * buffer, returns the amount of storage needed.. + * + * \retval 0 On success. + * \retval -EOPNOTSUPP If cmd is not supported. + * \retval -EINVAL invalid input parameters + * + */ +/*----------------------------------------------------------------------------*/ +static int priv_get_ndis(IN struct net_device *prNetDev, + IN NDIS_TRANSPORT_STRUCT *prNdisReq, + OUT u32 *pu4OutputLen) +{ + P_WLAN_REQ_ENTRY prWlanReqEntry = NULL; + u32 u4BufLen = 0; + WLAN_STATUS status = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prNetDev); + ASSERT(prNdisReq); + ASSERT(pu4OutputLen); + + if (!prNetDev || !prNdisReq || !pu4OutputLen) { + DBGLOG(REQ, INFO, + "priv_get_ndis(): invalid param(0x%p, 0x%p, 0x%p)\n", + prNetDev, prNdisReq, pu4OutputLen); + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + DBGLOG(REQ, INFO, + "priv_get_ndis(): invalid prGlueInfo(0x%p, 0x%p)\n", + prNetDev, *((P_GLUE_INFO_T *)netdev_priv(prNetDev))); + return -EINVAL; + } + + if (reqSearchSupportedOidEntry(prNdisReq->ndisOidCmd, + &prWlanReqEntry) == false) { + /* WARNLOG(("Query OID: 0x%08lx (unknown)\n", + * prNdisReq->ndisOidCmd)); */ + return -EOPNOTSUPP; + } + + if (prWlanReqEntry->pfOidQueryHandler == NULL) { + /* WARNLOG(("Query %s: Null query handler\n", + * prWlanReqEntry->pucOidName)); */ + return -EOPNOTSUPP; + } + + if (prWlanReqEntry->fgQryBufLenChecking) { + if (prNdisReq->inNdisOidlength < prWlanReqEntry->u4InfoBufLen) { + /* Not enough room in InformationBuffer. Punt */ + /* WARNLOG(("Query %s: Buffer too short (current=%ld, + * needed=%ld)\n", */ + /* prWlanReqEntry->pucOidName, */ + /* prNdisReq->inNdisOidlength, */ + /* prWlanReqEntry->u4InfoBufLen)); */ + + *pu4OutputLen = prWlanReqEntry->u4InfoBufLen; + + status = WLAN_STATUS_INVALID_LENGTH; + return -EINVAL; + } + } else { + if (prNdisReq->inNdisOidlength > + (sizeof(aucOidBuf) - + OFFSET_OF(NDIS_TRANSPORT_STRUCT, ndisOidContent))) { + DBGLOG(REQ, INFO, "exceeds length limit\n"); + return -EINVAL; + } + } + + if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_ONLY) { + /* GLUE sw info only */ + status = prWlanReqEntry->pfOidQueryHandler( + prGlueInfo, prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, &u4BufLen); + } else if (prWlanReqEntry->eOidMethod == ENUM_OID_GLUE_EXTENSION) { + /* multiple sw operations */ + status = prWlanReqEntry->pfOidQueryHandler( + prGlueInfo, prNdisReq->ndisOidContent, + prNdisReq->inNdisOidlength, &u4BufLen); + } else if (prWlanReqEntry->eOidMethod == ENUM_OID_DRIVER_CORE) { + /* driver core */ + + status = kalIoctl( + prGlueInfo, + (PFN_OID_HANDLER_FUNC)prWlanReqEntry->pfOidQueryHandler, + prNdisReq->ndisOidContent, prNdisReq->inNdisOidlength, + true, true, true, &u4BufLen); + } else { + DBGLOG(REQ, INFO, + "priv_set_ndis(): unsupported OID method:0x%x\n", + prWlanReqEntry->eOidMethod); + return -EOPNOTSUPP; + } + + *pu4OutputLen = u4BufLen; + + switch (status) { + case WLAN_STATUS_SUCCESS: + break; + + case WLAN_STATUS_INVALID_LENGTH: + /* WARNLOG(("Set %s: Invalid length (current=%ld, + * needed=%ld)\n", */ + /* prWlanReqEntry->pucOidName, */ + /* prNdisReq->inNdisOidlength, */ + /* u4BufLen)); */ + break; + } + + if (status != WLAN_STATUS_SUCCESS) { + return -EOPNOTSUPP; + } + + return 0; +} + +#if CFG_SUPPORT_QA_TOOL +/*----------------------------------------------------------------------------*/ +/*! + * \brief The routine handles ATE set operation. + * + * \param[in] pDev Net device requested. + * \param[in] prIwReqInfo pointer to iwreq structure. + * \param[in] prIwReqData The ioctl data structure, use the field of + * sub-command. \param[in] pcExtra the buffer with input value. + * + * \retval 0 On success. + * \retval -EOPNOTSUPP If cmd is not supported. + * \retval -EFAULT If copy from user space buffer fail. + * + */ +/*----------------------------------------------------------------------------*/ +int priv_ate_set(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN char *pcExtra) +{ + P_GLUE_INFO_T GlueInfo; + s32 i4Status; + u8 *InBuf; + /* u8 *addr_str, *value_str; */ + u32 InBufLen; + u32 u4SubCmd; + /* u8 isWrite = 0; + * u32 u4BufLen = 0; + * P_NDIS_TRANSPORT_STRUCT prNdisReq; + * u32 pu4IntBuf[2]; + */ + + /* sanity check */ + ASSERT(prNetDev); + ASSERT(prIwReqInfo); + ASSERT(prIwReqData); + ASSERT(pcExtra); + + /* init */ + DBGLOG(REQ, INFO, "priv_set_string (%s)(%d)\n", + (u8 *)prIwReqData->data.pointer, (s32)prIwReqData->data.length); + + if (GLUE_CHK_PR3(prNetDev, prIwReqData, pcExtra) == false) { + return -EINVAL; + } + + GlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (!test_bit(GLUE_FLAG_ADAPT_RDY_BIT, &GlueInfo->ulFlag)) { + DBGLOG(REQ, INFO, "adapter is not ready\n"); + return -EIO; + } + + u4SubCmd = (u32)prIwReqData->data.flags; + + DBGLOG(REQ, INFO, "MT6632 : priv_ate_set u4SubCmd = %d\n", u4SubCmd); + + switch (u4SubCmd) { + case PRIV_QACMD_SET: + DBGLOG(REQ, INFO, "MT6632 : priv_ate_set PRIV_QACMD_SET\n"); + InBuf = aucOidBuf; + InBufLen = prIwReqData->data.length; + i4Status = 0; + + if (copy_from_user(InBuf, prIwReqData->data.pointer, + prIwReqData->data.length)) { + return -EFAULT; + } + + i4Status = AteCmdSetHandle(prNetDev, InBuf, InBufLen); + break; + + default: + return -EOPNOTSUPP; + } + return 0; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to search desired OID. + * + * \param rOid[in] Desired NDIS_OID + * \param ppWlanReqEntry[out] Found registered OID entry + * + * \retval true: Matched OID is found + * \retval false: No matched OID is found + */ +/*----------------------------------------------------------------------------*/ +static u8 reqSearchSupportedOidEntry(IN u32 rOid, + OUT P_WLAN_REQ_ENTRY *ppWlanReqEntry) +{ + s32 i, j, k; + + i = 0; + j = NUM_SUPPORTED_OIDS - 1; + + while (i <= j) { + k = (i + j) / 2; + + if (rOid == arWlanOidReqTable[k].rOid) { + *ppWlanReqEntry = &arWlanOidReqTable[k]; + return true; + } else if (rOid < arWlanOidReqTable[k].rOid) { + j = k - 1; + } else { + i = k + 1; + } + } + + return false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Private ioctl driver handler. + * + * \param[in] pDev Net device requested. + * \param[out] pIwReq Pointer to iwreq structure. + * \param[in] cmd Private sub-command. + * + * \retval 0 For success. + * \retval -EFAULT If copy from user space buffer fail. + * \retval -EOPNOTSUPP Parameter "cmd" not recognized. + * + */ +/*----------------------------------------------------------------------------*/ +int priv_set_driver(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, IN OUT char *pcExtra) +{ + u32 u4SubCmd = 0; + u16 u2Cmd = 0; + + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4BytesWritten = 0; + + ASSERT(prNetDev); + ASSERT(prIwReqData); + if (!prNetDev || !prIwReqData) { + DBGLOG(REQ, INFO, + "priv_set_driver(): invalid param(0x%p, 0x%p)\n", + prNetDev, prIwReqData); + return -EINVAL; + } + + u2Cmd = prIwReqInfo->cmd; + DBGLOG(REQ, INFO, "prIwReqInfo->cmd %u\n", u2Cmd); + + u4SubCmd = (u32)prIwReqData->data.flags; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + ASSERT(prGlueInfo); + if (!prGlueInfo) { + DBGLOG(REQ, INFO, + "priv_set_driver(): invalid prGlueInfo(0x%p, 0x%p)\n", + prNetDev, *((P_GLUE_INFO_T *)netdev_priv(prNetDev))); + return -EINVAL; + } + + if (!test_bit(GLUE_FLAG_ADAPT_RDY_BIT, &prGlueInfo->ulFlag)) { + DBGLOG(REQ, INFO, "adapter is not ready\n"); + return -EIO; + } + + /* trick,hack in ./net/wireless/wext-priv.c ioctl_private_iw_point */ + /* because the cmd number is odd (get), the input string will not be + * copy_to_user */ + + DBGLOG(REQ, INFO, "prIwReqData->data.length %u\n", + prIwReqData->data.length); + + /* Use GET type becauase large data by iwpriv. */ + + ASSERT(IW_IS_GET(u2Cmd)); + if (prIwReqData->data.length != 0) { +#if KERNEL_VERSION(5, 0, 0) <= LINUX_VERSION_CODE + if (!access_ok(prIwReqData->data.pointer, + prIwReqData->data.length)) { +#else + if (!access_ok(VERIFY_READ, prIwReqData->data.pointer, + prIwReqData->data.length)) { +#endif + DBGLOG(REQ, INFO, + "%s access_ok Read fail written = %d\n", + __func__, i4BytesWritten); + return -EFAULT; + } + + if (prIwReqData->data.length >= IW_PRIV_BUF_SIZE) { + return -EFAULT; + } + + if (copy_from_user(pcExtra, prIwReqData->data.pointer, + prIwReqData->data.length)) { + DBGLOG(REQ, INFO, + "%s copy_form_user fail written = %d\n", + __func__, prIwReqData->data.length); + return -EFAULT; + } + } + + if (pcExtra) { + DBGLOG(REQ, INFO, "pcExtra %s\n", pcExtra); + /* Please check max length in rIwPrivTable */ + DBGLOG(REQ, INFO, "%s prIwReqData->data.length = %d\n", + __func__, prIwReqData->data.length); + i4BytesWritten = priv_driver_cmds( + prNetDev, pcExtra, 2000 /*prIwReqData->data.length */ ); + DBGLOG(REQ, INFO, "%s i4BytesWritten = %d\n", __func__, + i4BytesWritten); + } + + DBGLOG(REQ, INFO, "pcExtra done\n"); + + if (i4BytesWritten > 0) { + if (i4BytesWritten > IW_PRIV_BUF_SIZE) { + i4BytesWritten = IW_PRIV_BUF_SIZE; + } + prIwReqData->data.length = i4BytesWritten; /* the iwpriv will + * use the length */ + } else if (i4BytesWritten == 0) { + prIwReqData->data.length = i4BytesWritten; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is called to set beacon detection function enable/disable + * state This is mainly designed for usage under BT inquiry state (disable + * function). + * + * \param[in] pvAdapter Pointer to the Adapter structure + * \param[in] pvSetBuffer A pointer to the buffer that holds the data to be set + * \param[in] u4SetBufferLen The length of the set buffer + * \param[out] pu4SetInfoLen If the call is successful, returns the number of + * bytes read from the set buffer. If the call failed due to invalid length of + * the set buffer, returns the amount of storage needed. + * + * \retval WLAN_STATUS_SUCCESS + * \retval WLAN_STATUS_INVALID_DATA If new setting value is wrong. + * \retval WLAN_STATUS_INVALID_LENGTH + * + */ +/*----------------------------------------------------------------------------*/ +static WLAN_STATUS reqExtSetAcpiDevicePowerState(IN P_GLUE_INFO_T prGlueInfo, + IN void *pvSetBuffer, + IN u32 u4SetBufferLen, + OUT u32 *pu4SetInfoLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + ASSERT(prGlueInfo); + ASSERT(pvSetBuffer); + ASSERT(pu4SetInfoLen); + + /* WIFI is enabled, when ACPI is D0 (ParamDeviceStateD0 = 1). And vice + * versa */ + + /* rStatus = wlanSetInformation(prGlueInfo->prAdapter, */ + /* wlanoidSetAcpiDevicePowerState, */ + /* pvSetBuffer, */ + /* u4SetBufferLen, */ + /* pu4SetInfoLen); */ + return rStatus; +} + +#define CMD_START "START" +#define CMD_STOP "STOP" +#define CMD_SCAN_ACTIVE "SCAN-ACTIVE" +#define CMD_SCAN_PASSIVE "SCAN-PASSIVE" +#define CMD_RSSI "RSSI" +#define CMD_LINKSPEED "LINKSPEED" +#define CMD_RXFILTER_START "RXFILTER-START" +#define CMD_RXFILTER_STOP "RXFILTER-STOP" +#define CMD_RXFILTER_ADD "RXFILTER-ADD" +#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE" +#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START" +#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" +#define CMD_BTCOEXMODE "BTCOEXMODE" +#define CMD_SETSUSPENDOPT "SETSUSPENDOPT" +#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" +#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" +#define CMD_SETFWPATH "SETFWPATH" +#define CMD_SETBAND "SETBAND" +#define CMD_GETBAND "GETBAND" +#define CMD_AP_START "AP_START" + +#if CFG_SUPPORT_QA_TOOL +#define CMD_GET_RX_STATISTICS "GET_RX_STATISTICS" +#endif +#define CMD_GET_STAT "GET_STAT" +#define CMD_GET_BSS_STATISTICS "GET_BSS_STATISTICS" +#define CMD_GET_STA_STATISTICS "GET_STA_STATISTICS" +#define CMD_GET_WTBL_INFO "GET_WTBL" +#define CMD_GET_MIB_INFO "GET_MIB" +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +#define CMD_GET_MCS_INFO "GET_MCS_INFO" +#endif +#define CMD_GET_STA_INFO "GET_STA" +#define CMD_GET_MAGIC_PKT_INFO "GET_MAGIC_PKT_INFO" +#define CMD_SET_FW_LOG "SET_FWLOG" +#define CMD_GET_QUE_INFO "GET_QUE" +#define CMD_GET_MEM_INFO "GET_MEM" +#define CMD_GET_HIF_INFO "GET_HIF" +#define CMD_GET_STA_KEEP_CNT "KEEPCOUNTER" +#define CMD_STAT_RESET_CNT "RESETCOUNTER" +#define CMD_STAT_NOISE_SEL "NOISESELECT" +#define CMD_STAT_GROUP_SEL "GROUP" +#if CFG_SUPPORT_DBDC_TC6 +#define CMD_CSA "CSA" +#endif +#define CMD_SET_TXPOWER "SET_TXPOWER" +#define CMD_COUNTRY "COUNTRY" +#define CMD_GET_COUNTRY "GET_COUNTRY" +#define CMD_GET_CHANNELS "GET_CHANNELS" +#define CMD_GET_AP_CHANNELS "GET_AP_CHANNELS" +#define CMD_P2P_SET_NOA "P2P_SET_NOA" +#define CMD_P2P_GET_NOA "P2P_GET_NOA" +#define CMD_P2P_SET_PS "P2P_SET_PS" +#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" +#define CMD_SETROAMMODE "SETROAMMODE" +#define CMD_MIRACAST "MIRACAST" + +#ifdef CFG_SUPPORT_ADJUST_MCC_STAY_TIME +#define CMD_MCCTIME "MCCTIME" +#endif + +#if (CFG_SUPPORT_DFS_MASTER == 1) +#define CMD_SHOW_DFS_STATE "SHOW_DFS_STATE" +#define CMD_SHOW_DFS_abd123_PARAM "SHOW_DFS_abd123_PARAM" +#define CMD_SHOW_DFS_HELP "SHOW_DFS_HELP" +#define CMD_SHOW_DFS_CAC_TIME "SHOW_DFS_CAC_TIME" +#define CMD_SET_RDD_REPORT "SET_RDD_REPORT" +//#define CMD_SET_BYPASS_CAC "SET_BYPASS_CAC" +#define CMD_SET_abd123_DETECT_MODE "SET_abd123_DETECT_MODE" +#define CMD_CLEAN_DFS_abd123_PARAM "CLEAN_DFS_abd123_PARAM" +#endif + +#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR" +#define CMD_PNOSETUP_SET "PNOSETUP " +#define CMD_PNOENABLE_SET "PNOFORCE" +#define CMD_PNODEBUG_SET "PNODEBUG" +#define CMD_WLS_BATCHING "WLS_BATCHING" + +#define CMD_OKC_SET_PMK "SET_PMK" +#define CMD_OKC_ENABLE "OKC_ENABLE" + +#define CMD_SETMONITOR "MONITOR" +#define CMD_SETBUFMODE "BUFFER_MODE" +#define CMD_SETEEPROM_MODE "EEPROM_MODE" + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +#define CMD_GET_CH_RANK_LIST "GET_CH_RANK_LIST" +#define CMD_GET_CH_DIRTINESS "GET_CH_DIRTINESS" +#endif + +#define CMD_EFUSE "EFUSE" + +/* miracast related definition */ +#define MIRACAST_MODE_OFF 0 +#define MIRACAST_MODE_SOURCE 1 +#define MIRACAST_MODE_SINK 2 + +#ifndef MIRACAST_AMPDU_SIZE +#define MIRACAST_AMPDU_SIZE 8 +#endif + +#ifndef MIRACAST_MCHAN_ALGO +#define MIRACAST_MCHAN_ALGO 1 +#endif + +#ifndef MIRACAST_MCHAN_BW +#define MIRACAST_MCHAN_BW 25 +#endif + +#define CMD_BAND_AUTO 0 +#define CMD_BAND_5G 1 +#define CMD_BAND_2G 2 +#define CMD_BAND_ALL 3 + +/* Mediatek private command */ +#define CMD_SET_MCR "SET_MCR" +#define CMD_GET_MCR "GET_MCR" +#define CMD_SET_DRV_MCR "SET_DRV_MCR" +#define CMD_GET_DRV_MCR "GET_DRV_MCR" +#define CMD_SET_SW_CTRL "SET_SW_CTRL" +#define CMD_GET_SW_CTRL "GET_SW_CTRL" +#define CMD_SET_CFG "SET_CFG" +#define CMD_GET_CFG "GET_CFG" +#define CMD_SET_CHIP "SET_CHIP" +#define CMD_GET_CHIP "GET_CHIP" +#define CMD_SET_DBG_LEVEL "SET_DBG_LEVEL" +#define CMD_GET_DBG_LEVEL "GET_DBG_LEVEL" +#define PRIV_CMD_SIZE 2000 +#define CMD_SET_FIXED_RATE "FixedRate" + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT +#define CMD_SET_FIXED_MRATE "FixedMRate" +#define CMD_SET_DUP_MPACKET "SET_DupMPacket" +#define CMD_GET_DUP_MRACKET "GET_DupMPacket" +#define CMD_SET_MCAST_BURST "SET_McastBurst" +#define CMD_GET_MCAST_BURST "GET_McastBurst" +#define CMD_SET_TXOP_TIME "SET_TXOP" +#define CMD_GET_TXOP_TIME "GET_TXOP" +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK +#define CMD_SET_LOOK_BACK_MODE "SET_LOOKBACK" +#define CMD_GET_LOOK_BACK_MODE "GET_LOOKBACK" +#endif +#define CMD_SET_11MC_TYPE "SET_11MC_TYPE" +#define CMD_GET_11MC_TYPE "GET_11MC_TYPE" +#define CMD_SET_UNICAST_BURST "SET_UNICAST_BURST" +#define CMD_GET_UNICAST_BURST "GET_UNICAST_BURST" +#define CMD_SET_UNICAST_BURST_TIMEOUT "SET_UNICAST_BURST_TIMEOUT" +#define CMD_GET_UNICAST_BURST_TIMEOUT "GET_UNICAST_BURST_TIMEOUT" +#define CMD_SET_MRM_CLIENT "SET_MRM_CLIENT" +#define CMD_GET_MRM_CLIENT "GET_MRM_CLIENT" +#define CMD_SET_AUDIO_TOS "SET_AUDIO_TOS" +#define CMD_GET_AUDIO_TOS "GET_AUDIO_TOS" +#endif + +#define CMD_GET_VERSION "VER" +#define CMD_SET_TEST_MODE "SET_TEST_MODE" +#define CMD_SET_TEST_CMD "SET_TEST_CMD" +#define CMD_GET_TEST_RESULT "GET_TEST_RESULT" +#define CMD_GET_STA_STAT "STAT" +#define CMD_GET_STA_STAT2 "STAT2" +#define CMD_GET_STA_RX_STAT "RX_STAT" +#define CMD_SET_ACL_POLICY "SET_ACL_POLICY" +#define CMD_ADD_ACL_ENTRY "ADD_ACL_ENTRY" +#define CMD_DEL_ACL_ENTRY "DEL_ACL_ENTRY" +#define CMD_SHOW_ACL_ENTRY "SHOW_ACL_ENTRY" +#define CMD_CLEAR_ACL_ENTRY "CLEAR_ACL_ENTRY" +#define CMD_GET_CURR_AR_RATE "GET_CURR_AR_RATE" +#define CMD_COEX_CONTROL "COEX_CONTROL" +#define CMD_SET_CSI "SET_CSI" +#define CMD_GET_CSI "GET_CSI" + +#if CFG_WOW_SUPPORT +#define CMD_WOW_START "WOW_START" +#define CMD_SET_WOW_ENABLE "SET_WOW_ENABLE" +#define CMD_SET_WOW_PAR "SET_WOW_PAR" +#define CMD_SET_WOW_UDP "SET_WOW_UDP" +#define CMD_SET_WOW_TCP "SET_WOW_TCP" +#define CMD_GET_WOW_PORT "GET_WOW_PORT" +#define CMD_GET_WOW_REASON "GET_WOW_REASON" +#endif + +#if CFG_STR_DHCP_RENEW_OFFLOAD +#define CMD_SET_DHCP_INFO "SET_DHCP" +#endif + +#define CMD_SET_ADV_PWS "SET_ADV_PWS" +#define CMD_SET_MDTIM "SET_MDTIM" +#define CMD_SET_LISTEN_DTIM_INTERVAL "SET_LISTEN_DTIM_INTERVAL" + +#define CMD_SET_DBDC "SET_DBDC" + +#define CMD_SET_P2P_PS "SET_P2P_PS" +#define CMD_SET_P2P_NOA "SET_P2P_NOA" + +#define CMD_GET_CNM_INFO "GET_CNM" +#define CMD_GET_DSLP_CNT "GET_DSLEEP_CNT" + +#ifdef CFG_SUPPORT_ANT_DIV +#define CMD_SET_ANT_DIV "ANT_DIV_SET" +#define CMD_GET_ANT_DIV "ANT_DIV_GET" +#define CMD_DETC_ANT_DIV "ANT_DIV_DETC" +#define CMD_SWH_ANT_DIV "ANT_DIV_SWH" + +#define CMD_SET_ANT_DIV_ARG_NUM 2 +#define CMD_GET_ANT_DIV_ARG_NUM 1 +#define CMD_DETC_ANT_DIV_ARG_NUM 1 +#define CMD_SWH_ANT_DIV_ARG_NUM 1 + +#endif + +#define CMD_SEND_BEACONTIMEOUT "SEND_BEACONTIMEOUT" + +#define CMD_GET_DISCONNECT_REASON "GET_DISCONNECT_REASON" +#define DISCONNECT_REASON_BASE 1000 + +static u8 g_ucMiracastMode = MIRACAST_MODE_OFF; + +typedef struct cmd_tlv { + char prefix; + char version; + char subver; + char reserved; +} cmd_tlv_t; + +typedef struct priv_driver_cmd_s { + char *buf; + int used_len; + int total_len; +} priv_driver_cmd_t; + +#ifdef CFG_ANDROID_AOSP_PRIV_CMD +struct android_wifi_priv_cmd { + char *buf; + int used_len; + int total_len; +}; +#endif + +int priv_driver_get_dbg_level(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u32 u4DbgIdx = 0, u4DbgMask = 0; + u8 fgIsCmdAccept = false; + s32 u4Ret = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= 2) { + /* u4DbgIdx = kalStrtoul(apcArgv[1], NULL, 0); */ + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4DbgIdx); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse apcArgv error u4Ret=%d\n", + u4Ret); + return -1; + } + if (wlanGetDebugLevel(u4DbgIdx, &u4DbgMask) == + WLAN_STATUS_SUCCESS) { + fgIsCmdAccept = true; + i4BytesWritten = snprintf( + pcCommand, i4TotalLen, + "Get DBG module[%lu] log level => [0x%02x]!", + u4DbgIdx, (u8)u4DbgMask); + } + } + + if (!fgIsCmdAccept) { + i4BytesWritten = snprintf(pcCommand, i4TotalLen, + "Get DBG module log level failed!"); + } + + return i4BytesWritten; +} + +#if CFG_SUPPORT_QA_TOOL +#if CFG_SUPPORT_BUFFER_MODE +static int priv_driver_set_eeprom_mode(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + s32 i4Argc = 0; + s32 i4BytesWritten = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u32 arg = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + if (i4Argc >= 2) { + rStatus = kalkStrtou32(apcArgv[1], 0, &arg); + if (rStatus) { + DBGLOG(REQ, LOUD, "parse apcArgv error rStatus=%d\n", + rStatus); + return -1; + } + + rStatus = priv_set_eeprom_mode(arg); + if (rStatus) { + DBGLOG(REQ, LOUD, "priv_set_eeprom_mode rStatus=%d\n", + rStatus); + return -1; + } + + i4BytesWritten = snprintf( + pcCommand, i4TotalLen, "Switch eeprom source as %s", + (arg == EFUSE_MODE) ? "Efuse" : "Buffer Bin"); + } + + return i4BytesWritten; +} +static int priv_driver_set_efuse_buffer_mode(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4Argc = 0; + s32 i4BytesWritten = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + PARAM_CUSTOM_EFUSE_BUFFER_MODE_T *prSetEfuseBufModeInfo = NULL; +#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 0) + BIN_CONTENT_T *pBinContent; + int i = 0; +#endif + u8 *pucConfigBuf = NULL; + u32 u4ConfigReadLen; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + pucConfigBuf = (u8 *)kalMemAlloc(2048, VIR_MEM_TYPE); + + if (!pucConfigBuf) { + DBGLOG(INIT, INFO, "allocate memory for pucConfigBuf failed\n"); + i4BytesWritten = -1; + goto out; + } + kalMemZero(pucConfigBuf, 2048); + u4ConfigReadLen = 0; + + if (kalReadToFile("/MT6632_eFuse_usage_table.xlsm.bin", pucConfigBuf, + 2048, &u4ConfigReadLen) == 0) { + /* ToDo:: Nothing */ + } else { + DBGLOG(INIT, INFO, "can't find file\n"); + i4BytesWritten = -1; + goto out; + } + + /* pucConfigBuf */ + prSetEfuseBufModeInfo = (PARAM_CUSTOM_EFUSE_BUFFER_MODE_T *)kalMemAlloc( + sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T), VIR_MEM_TYPE); + if (prSetEfuseBufModeInfo == NULL) { + DBGLOG(INIT, INFO, + "allocate memory for prSetEfuseBufModeInfo failed\n"); + i4BytesWritten = -1; + goto out; + } + kalMemZero(prSetEfuseBufModeInfo, + sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T)); + + prSetEfuseBufModeInfo->ucSourceMode = 1; + prSetEfuseBufModeInfo->ucCount = (u8)EFUSE_CONTENT_SIZE; + +#if (CFG_EFUSE_BUFFER_MODE_DELAY_CAL == 0) + pBinContent = (BIN_CONTENT_T *)prSetEfuseBufModeInfo->aBinContent; + for (i = 0; i < EFUSE_CONTENT_SIZE; i++) { + pBinContent->u2Addr = i; + pBinContent->ucValue = *(pucConfigBuf + i); + + pBinContent++; + } + + for (i = 0; i < 20; i++) + DBGLOG(INIT, INFO, "%x\n", + prSetEfuseBufModeInfo->aBinContent[i].ucValue); +#endif + + rStatus = kalIoctl(prGlueInfo, wlanoidSetEfusBufferMode, + prSetEfuseBufModeInfo, + sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T), false, + false, true, &u4BufLen); + + i4BytesWritten = + snprintf(pcCommand, i4TotalLen, "set buffer mode %s", + (rStatus == WLAN_STATUS_SUCCESS) ? "success" : "fail"); +out: + if (pucConfigBuf) { + kalMemFree(pucConfigBuf, VIR_MEM_TYPE, 2048); + } + + if (prSetEfuseBufModeInfo) { + kalMemFree(prSetEfuseBufModeInfo, VIR_MEM_TYPE, + sizeof(PARAM_CUSTOM_EFUSE_BUFFER_MODE_T)); + } + + return i4BytesWritten; +} +#endif + +static int priv_driver_get_rx_statistics(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 u4Ret = 0; + PARAM_CUSTOM_ACCESS_RX_STAT rRxStatisticsTest; + + kalMemZero(&rRxStatisticsTest, sizeof(PARAM_CUSTOM_ACCESS_RX_STAT)); + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + DBGLOG(INIT, ERROR, "MT6632 : priv_driver_get_rx_statistics\n"); + + if (i4Argc >= 2) { + u4Ret = kalkStrtou32(apcArgv[1], 0, + &(rRxStatisticsTest.u4SeqNum)); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse apcArgv error u4Ret=%d\n", + u4Ret); + return -1; + } + + rRxStatisticsTest.u4TotalNum = sizeof(PARAM_RX_STAT_T) / 4; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryRxStatistics, + &rRxStatisticsTest, + sizeof(rRxStatisticsTest), true, true, true, + &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + } + + return i4BytesWritten; +} +#endif + +#if CFG_SUPPORT_MSP + +static int priv_driver_get_sta_statistics(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 i4ArgNum = 3; + PARAM_GET_STA_STATISTICS rQueryStaStatistics; + PARAM_RSSI rRssi; + u16 u2LinkSpeed; + u32 u4Per; + + ASSERT(prNetDev); + + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + kalMemZero(&rQueryStaStatistics, sizeof(rQueryStaStatistics)); + rQueryStaStatistics.ucReadClear = true; + + if (i4Argc >= i4ArgNum) { + if (strnicmp(apcArgv[1], CMD_GET_STA_KEEP_CNT, + strlen(CMD_GET_STA_KEEP_CNT)) == 0) { + if (wlanHwAddrToBin( + apcArgv[2], + &rQueryStaStatistics.aucMacAddr[0]) < 0) { + DBGLOG(REQ, WARN, + "%s: MAC addr Argv[2] convert failed\n", + __func__); + return -1; + } + rQueryStaStatistics.ucReadClear = false; + } else if (strnicmp(apcArgv[2], CMD_GET_STA_KEEP_CNT, + strlen(CMD_GET_STA_KEEP_CNT)) == 0) { + if (wlanHwAddrToBin( + apcArgv[1], + &rQueryStaStatistics.aucMacAddr[0]) < 0) { + DBGLOG(REQ, WARN, + "%s: MAC addr Argv[1] convert failed\n", + __func__); + return -1; + } + rQueryStaStatistics.ucReadClear = false; + } + } else { + /* Get AIS AP address for no argument */ + if (prGlueInfo->prAdapter->prAisBssInfo->prStaRecOfAP) { + COPY_MAC_ADDR(rQueryStaStatistics.aucMacAddr, + prGlueInfo->prAdapter->prAisBssInfo + ->prStaRecOfAP->aucMacAddr); + DBGLOG(RSN, INFO, "use ais ap " MACSTR "\n", + MAC2STR(prGlueInfo->prAdapter->prAisBssInfo + ->prStaRecOfAP->aucMacAddr)); + } else { + DBGLOG(RSN, INFO, "not connect to ais ap %x\n", + prGlueInfo->prAdapter->prAisBssInfo + ->prStaRecOfAP); + i4BytesWritten = kalScnprintf(pcCommand, i4TotalLen, + "%s", + "\n\nNo STA Stat:\n"); + return i4BytesWritten; + } + + if (i4Argc == 2) { + if (strnicmp(apcArgv[1], CMD_GET_STA_KEEP_CNT, + strlen(CMD_GET_STA_KEEP_CNT)) == 0) { + rQueryStaStatistics.ucReadClear = false; + } + } + } + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryStaStatistics, + &rQueryStaStatistics, sizeof(rQueryStaStatistics), + true, false, true, &u4BufLen); + + if (rStatus == WLAN_STATUS_SUCCESS) { + rRssi = RCPI_TO_dBm(rQueryStaStatistics.ucRcpi); + u2LinkSpeed = rQueryStaStatistics.u2LinkSpeed == 0 ? + 0 : + rQueryStaStatistics.u2LinkSpeed / 2; + + i4BytesWritten = kalScnprintf(pcCommand, i4TotalLen, "%s", + "\n\nSTA Stat:\n"); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "Tx total cnt = %ld\n", + rQueryStaStatistics.u4TransmitCount); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "Tx success = %ld\n", + rQueryStaStatistics.u4TransmitCount - + rQueryStaStatistics.u4TransmitFailCount); + + u4Per = rQueryStaStatistics.u4TransmitCount == 0 ? + 0 : + (1000 * + (rQueryStaStatistics.u4TransmitFailCount)) / + rQueryStaStatistics.u4TransmitCount; + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "Tx fail count = %ld, PER=%ld.%1ld%%\n", + rQueryStaStatistics.u4TransmitFailCount, u4Per / 10, + u4Per % 10); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "RSSI = %d\n", rRssi); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "LinkSpeed = %d\n", u2LinkSpeed); + } else { + i4BytesWritten = kalScnprintf(pcCommand, i4TotalLen, "%s", + "\n\nNo STA Stat:\n"); + } + + return i4BytesWritten; +} + +static int priv_driver_get_bss_statistics(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus; + PARAM_MAC_ADDRESS arBssid; + u32 u4BufLen; + s32 i4Rssi; + PARAM_GET_BSS_STATISTICS rQueryBssStatistics; + P_NETDEV_PRIVATE_GLUE_INFO prNetDevPrivate = + (P_NETDEV_PRIVATE_GLUE_INFO)NULL; + u8 ucBssIndex; + s32 i4BytesWritten = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + ASSERT(prGlueInfo); + + kalMemZero(arBssid, MAC_ADDR_LEN); + wlanQueryInformation(prGlueInfo->prAdapter, wlanoidQueryBssid, + &arBssid[0], sizeof(arBssid), &u4BufLen); + + /* 2. fill RSSI */ + if (prGlueInfo->eParamMediaStateIndicated != + PARAM_MEDIA_STATE_CONNECTED) { + /* not connected */ + DBGLOG(REQ, WARN, "not yet connected\n"); + return WLAN_STATUS_SUCCESS; + } + rStatus = kalIoctl(prGlueInfo, wlanoidQueryRssi, &i4Rssi, + sizeof(i4Rssi), true, false, false, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "unable to retrieve rssi\n"); + } + + /* 3 get per-BSS link statistics */ + if (rStatus == WLAN_STATUS_SUCCESS) { + /* get Bss Index from ndev */ + prNetDevPrivate = + (P_NETDEV_PRIVATE_GLUE_INFO)netdev_priv(prNetDev); + ASSERT(prNetDevPrivate->prGlueInfo == prGlueInfo); + ucBssIndex = prNetDevPrivate->ucBssIdx; + + kalMemZero(&rQueryBssStatistics, sizeof(rQueryBssStatistics)); + rQueryBssStatistics.ucBssIndex = ucBssIndex; + + rQueryBssStatistics.ucReadClear = true; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryBssStatistics, + &rQueryBssStatistics, + sizeof(rQueryBssStatistics), true, false, + true, &u4BufLen); + + if (rStatus == WLAN_STATUS_SUCCESS) { + i4BytesWritten = kalScnprintf(pcCommand, i4TotalLen, + "%s", "\n\nStat:\n"); + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", + "CurrentTemperature = -\n"); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "Tx success = %ld\n", + rQueryBssStatistics.u4TransmitCount - + rQueryBssStatistics.u4TransmitFailCount); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "Tx fail count = %ld\n", + rQueryBssStatistics.u4TransmitFailCount); + } + } else { + DBGLOG(REQ, WARN, + "unable to retrieve per-BSS link statistics\n"); + } + + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand); + + return i4BytesWritten; +} + +#define HW_TX_RATE_TO_MODE(_x) (((_x) & (0x7 << 6)) >> 6) +#define HW_TX_RATE_TO_MCS(_x, _mode) ((_x) & (0x3f)) +#define HW_TX_RATE_TO_NSS(_x) (((_x) & (0x3 << 9)) >> 9) +#define HW_TX_RATE_TO_STBC(_x) (((_x) & (0x1 << 11)) >> 11) + +#define TX_VECTOR_GET_TX_RATE(_txv) (((_txv)->u4TxVector1) & BITS(0, 6)) +#define TX_VECTOR_GET_TX_LDPC(_txv) ((((_txv)->u4TxVector1) >> 7) & BIT(0)) +#define TX_VECTOR_GET_TX_STBC(_txv) ((((_txv)->u4TxVector1) >> 8) & BITS(0, \ + 1)) +#define TX_VECTOR_GET_TX_FRMODE(_txv) \ + ((((_txv)->u4TxVector1) >> 10) & BITS(0, 1)) +#define TX_VECTOR_GET_TX_MODE(_txv) ((((_txv)->u4TxVector1) >> \ + 12) & BITS(0, \ + 2)) +#define TX_VECTOR_GET_TX_NSTS(_txv) ((((_txv)->u4TxVector1) >> \ + 21) & BITS(0, \ + 1)) +#define TX_VECTOR_GET_TX_PWR(_txv) ((((_txv)->u4TxVector1) >> \ + 24) & BITS(0, \ + 6)) +#define TX_VECTOR_GET_BF_EN(_txv) ((((_txv)->u4TxVector2) >> \ + 31) & BIT(0)) +#define TX_VECTOR_GET_DYN_BW(_txv) ((((_txv)->u4TxVector4) >> \ + 31) & BIT(0)) +#define TX_VECTOR_GET_NO_SOUNDING(_txv) ((((_txv)->u4TxVector4) >> \ + 28) & BIT(0)) +#define TX_VECTOR_GET_TX_SGI(_txv) ((((_txv)->u4TxVector4) >> \ + 27) & BIT(0)) + +#define TX_RATE_MODE_CCK 0 +#define TX_RATE_MODE_OFDM 1 +#define TX_RATE_MODE_HTMIX 2 +#define TX_RATE_MODE_HTGF 3 +#define TX_RATE_MODE_VHT 4 +#define MAX_TX_MODE 5 + +static char *HW_TX_MODE_STR[] = { "CCK", "OFDM", "MM", "GF", "VHT", "N/A" }; +static char *HW_TX_RATE_CCK_STR[] = { "1M", "2M", "5.5M", "11M", "N/A" }; +static char *HW_TX_RATE_OFDM_STR[] = { "6M", "9M", "12M", "18M", "24M", + "36M", "48M", "54M", "N/A" }; +static char *HW_TX_RATE_BW[] = { "BW20", "BW40", "BW80", "BW160/BW8080", + "N/A" }; +enum { + RATE_TBL_B = 0, + RATE_TBL_G, + RATE_TBL_N, + RATE_TBL_N_2SS, + RATE_TBL_AC, + RATE_TBL_AC_2SS, + RATE_TBL_MAX +}; + +static char *RATE_TBLE[] = { + [RATE_TBL_B] = "B", [RATE_TBL_G] = "G", + [RATE_TBL_N] = "N", [RATE_TBL_N_2SS] = "N_2SS", + [RATE_TBL_AC] = "AC", [RATE_TBL_AC_2SS] = "AC_2SS", + [RATE_TBL_MAX] = "N/A" +}; + +#define BW_20 0 +#define BW_40 1 +#define BW_80 2 +#define BW_160 3 +#define BW_10 4 +#define BW_5 6 +#define BW_8080 7 +#define BW_ALL 0xFF + +static char *hw_rate_ofdm_str(u16 ofdm_idx) +{ + switch (ofdm_idx) { + case 11: /* 6M */ + return HW_TX_RATE_OFDM_STR[0]; + + case 15: /* 9M */ + return HW_TX_RATE_OFDM_STR[1]; + + case 10: /* 12M */ + return HW_TX_RATE_OFDM_STR[2]; + + case 14: /* 18M */ + return HW_TX_RATE_OFDM_STR[3]; + + case 9: /* 24M */ + return HW_TX_RATE_OFDM_STR[4]; + + case 13: /* 36M */ + return HW_TX_RATE_OFDM_STR[5]; + + case 8: /* 48M */ + return HW_TX_RATE_OFDM_STR[6]; + + case 12: /* 54M */ + return HW_TX_RATE_OFDM_STR[7]; + + default: + return HW_TX_RATE_OFDM_STR[8]; + } +} + +static u8 priv_driver_get_sgi_info(IN P_PARAM_PEER_CAP_T prWtblPeerCap) +{ + if (!prWtblPeerCap) { + return false; + } + + switch (prWtblPeerCap->ucFrequencyCapability) { + case BW_20: + return prWtblPeerCap->fgG2; + + case BW_40: + return prWtblPeerCap->fgG4; + + case BW_80: + return prWtblPeerCap->fgG8; + + case BW_160: + return prWtblPeerCap->fgG16; + + default: + return false; + } +} + +static u8 priv_driver_get_ldpc_info(IN P_PARAM_TX_CONFIG_T prWtblTxConfig) +{ + if (!prWtblTxConfig) { + return false; + } + + if (prWtblTxConfig->fgIsVHT) { + return prWtblTxConfig->fgVhtLDPC; + }else{ + return prWtblTxConfig->fgLDPC; + } +} + +s32 priv_driver_rate_to_string(IN char *pcCommand, IN int i4TotalLen, u8 TxRx, + P_PARAM_HW_WLAN_INFO_T prHwWlanInfo) +{ + u8 i, txmode, rate, stbc; + u8 nss; + s32 i4BytesWritten = 0; + + for (i = 0; i < AUTO_RATE_NUM; i++) { + txmode = HW_TX_RATE_TO_MODE( + prHwWlanInfo->rWtblRateInfo.au2RateCode[i]); + if (txmode >= MAX_TX_MODE) { + txmode = MAX_TX_MODE; + } + rate = HW_TX_RATE_TO_MCS( + prHwWlanInfo->rWtblRateInfo.au2RateCode[i], txmode); + nss = HW_TX_RATE_TO_NSS( + prHwWlanInfo->rWtblRateInfo.au2RateCode[i]) + + 1; + stbc = HW_TX_RATE_TO_STBC( + prHwWlanInfo->rWtblRateInfo.au2RateCode[i]); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tRate index[%d] ", i); + + if (prHwWlanInfo->rWtblRateInfo.ucRateIdx == i) { + if (TxRx == 0) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", + "[Last RX Rate] "); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", + "[Last TX Rate] "); + } + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", " "); + } + + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s, ", + rate < 4 ? HW_TX_RATE_CCK_STR[rate] : + HW_TX_RATE_CCK_STR[4]); + } else if (txmode == TX_RATE_MODE_OFDM) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", hw_rate_ofdm_str(rate)); + } else { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "NSS%d_MCS%d, ", nss, rate); + } + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s, ", + HW_TX_RATE_BW[prHwWlanInfo->rWtblPeerCap + .ucFrequencyCapability]); + + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", rate < 4 ? "LP" : "SP"); + } else if (txmode == TX_RATE_MODE_OFDM) { + ; + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s, ", + priv_driver_get_sgi_info( + &prHwWlanInfo->rWtblPeerCap) == 0 ? + "LGI" : + "SGI"); + } + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s%s %s\n", HW_TX_MODE_STR[txmode], + stbc ? "STBC" : " ", + priv_driver_get_ldpc_info( + &prHwWlanInfo->rWtblTxConfig) == 0 ? + "BCC" : + "LDPC"); + } + + return i4BytesWritten; +} + +static s32 +priv_driver_dump_helper_wtbl_info(IN char *pcCommand, IN int i4TotalLen, + P_PARAM_HW_WLAN_INFO_T prHwWlanInfo) +{ + u8 i; + s32 i4BytesWritten = 0; + + ASSERT(pcCommand); + + i4BytesWritten = + kalScnprintf(pcCommand, i4TotalLen, "%s", "\n\nwtbl:\n"); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "Dump WTBL info of WLAN_IDX = %d\n", + prHwWlanInfo->u4Index); + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "\tAddr=" MACSTR "\n", + MAC2STR(prHwWlanInfo->rWtblTxConfig.aucPA)); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tMUAR_Idx = %d\n", + prHwWlanInfo->rWtblSecConfig.ucMUARIdx); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\trc_a1/rc_a2:%d/%d\n", + prHwWlanInfo->rWtblSecConfig.fgRCA1, + prHwWlanInfo->rWtblSecConfig.fgRCA2); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tKID:%d/RCID:%d/RKV:%d/RV:%d/IKV:%d/WPI_FLAG:%d\n", + prHwWlanInfo->rWtblSecConfig.ucKeyID, + prHwWlanInfo->rWtblSecConfig.fgRCID, + prHwWlanInfo->rWtblSecConfig.fgRKV, + prHwWlanInfo->rWtblSecConfig.fgRV, + prHwWlanInfo->rWtblSecConfig.fgIKV, + prHwWlanInfo->rWtblSecConfig.fgEvenPN); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", + "\tGID_SU:NA"); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tsw/DIS_RHTR:%d/%d\n", prHwWlanInfo->rWtblTxConfig.fgSW, + prHwWlanInfo->rWtblTxConfig.fgDisRxHdrTran); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tHT/VHT/HT-LDPC/VHT-LDPC/DYN_BW/MMSS:%d/%d/%d/%d/%d/%d\n", + prHwWlanInfo->rWtblTxConfig.fgIsHT, + prHwWlanInfo->rWtblTxConfig.fgIsVHT, + prHwWlanInfo->rWtblTxConfig.fgLDPC, + prHwWlanInfo->rWtblTxConfig.fgVhtLDPC, + prHwWlanInfo->rWtblTxConfig.fgDynBw, + prHwWlanInfo->rWtblPeerCap.ucMMSS); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tFCAP/G2/G4/G8/G16/CBRN:%d/%d/%d/%d/%d/%d\n", + prHwWlanInfo->rWtblPeerCap.ucFrequencyCapability, + prHwWlanInfo->rWtblPeerCap.fgG2, + prHwWlanInfo->rWtblPeerCap.fgG4, + prHwWlanInfo->rWtblPeerCap.fgG8, + prHwWlanInfo->rWtblPeerCap.fgG16, + prHwWlanInfo->rWtblPeerCap.ucChangeBWAfterRateN); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tHT-TxBF(tibf/tebf):%d/%d, VHT-TxBF(tibf/tebf):%d/%d, PFMU_IDX=%d\n", + prHwWlanInfo->rWtblTxConfig.fgTIBF, + prHwWlanInfo->rWtblTxConfig.fgTEBF, + prHwWlanInfo->rWtblTxConfig.fgVhtTIBF, + prHwWlanInfo->rWtblTxConfig.fgVhtTEBF, + prHwWlanInfo->rWtblTxConfig.ucPFMUIdx); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", + "\tSPE_IDX=NA\n"); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tBA Enable:0x%x, BAFail Enable:%d\n", + prHwWlanInfo->rWtblBaConfig.ucBaEn, + prHwWlanInfo->rWtblTxConfig.fgBAFEn); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tQoS Enable:%d\n", + prHwWlanInfo->rWtblTxConfig.fgIsQoS); + if (prHwWlanInfo->rWtblTxConfig.fgIsQoS) { + for (i = 0; i < 8; i += 2) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\t\tBA WinSize: TID 0 - %d, TID 1 - %d\n", + (prHwWlanInfo->rWtblBaConfig.u4BaWinSize >> + (i * 3)) & + BITS(0, 2), + (prHwWlanInfo->rWtblBaConfig.u4BaWinSize >> + ((i + 1) * 3)) & + BITS(0, 2)); + } + } + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tpartial_aid:%d\n", prHwWlanInfo->rWtblTxConfig.u2PartialAID); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\twpi_even:%d\n", + prHwWlanInfo->rWtblSecConfig.fgEvenPN); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tAAD_OM/CipherSuit:%d/%d\n", + prHwWlanInfo->rWtblTxConfig.fgAADOM, + prHwWlanInfo->rWtblSecConfig.ucCipherSuit); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\taf:%d\n", prHwWlanInfo->rWtblPeerCap.ucAmpduFactor); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\trdg_ba:%d/rdg capability:%d\n", + prHwWlanInfo->rWtblTxConfig.fgRdgBA, + prHwWlanInfo->rWtblTxConfig.fgRDG); + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "\tcipher_suit:%d\n", + prHwWlanInfo->rWtblSecConfig.ucCipherSuit); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tFromDS:%d\n", + prHwWlanInfo->rWtblTxConfig.fgIsFromDS); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tToDS:%d\n", + prHwWlanInfo->rWtblTxConfig.fgIsToDS); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRSSI = %d %d %d %d\n", + RCPI_TO_dBm(prHwWlanInfo->rWtblRxCounter.ucRxRcpi0), + RCPI_TO_dBm(prHwWlanInfo->rWtblRxCounter.ucRxRcpi1), + RCPI_TO_dBm(prHwWlanInfo->rWtblRxCounter.ucRxRcpi2), + RCPI_TO_dBm(prHwWlanInfo->rWtblRxCounter.ucRxRcpi3)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", + "\tRate Info\n"); + + i4BytesWritten += priv_driver_rate_to_string( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, 1, + prHwWlanInfo); + + return i4BytesWritten; +} + +static int priv_driver_get_wtbl_info(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s32 u4Ret = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + P_PARAM_HW_WLAN_INFO_T prHwWlanInfo; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + /* DBGLOG(RSN, INFO, "MT6632 : priv_driver_get_wtbl_info\n"); */ + + prHwWlanInfo = (P_PARAM_HW_WLAN_INFO_T)kalMemAlloc( + sizeof(PARAM_HW_WLAN_INFO_T), VIR_MEM_TYPE); + if (!prHwWlanInfo) { + return -1; + } + + kalMemZero(prHwWlanInfo, sizeof(PARAM_HW_WLAN_INFO_T)); + + if (i4Argc >= 2) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &prHwWlanInfo->u4Index); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse apcArgv error u4Ret=%d\n", + u4Ret); + return -1; + } + + DBGLOG(REQ, INFO, "MT6632 : index = %d\n", + prHwWlanInfo->u4Index); + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryWlanInfo, + prHwWlanInfo, sizeof(PARAM_HW_WLAN_INFO_T), + true, true, true, &u4BufLen); + + DBGLOG(REQ, INFO, "rStatus %u u4BufLen = %d\n", rStatus, + u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + kalMemFree(prHwWlanInfo, VIR_MEM_TYPE, + sizeof(PARAM_HW_WLAN_INFO_T)); + return -1; + } + i4BytesWritten = priv_driver_dump_helper_wtbl_info( + pcCommand, i4TotalLen, prHwWlanInfo); + } + + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand); + + kalMemFree(prHwWlanInfo, VIR_MEM_TYPE, sizeof(PARAM_HW_WLAN_INFO_T)); + + return i4BytesWritten; +} + +static int priv_driver_get_sta_info(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u8 aucMacAddr[MAC_ADDR_LEN]; + u8 ucWlanIndex; + u8 *pucMacAddr = NULL; + P_PARAM_HW_WLAN_INFO_T prHwWlanInfo = NULL; + PARAM_GET_STA_STATISTICS rQueryStaStatistics; + PARAM_RSSI rRssi; + u16 u2LinkSpeed; + u32 u4Per; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + kalMemZero(&rQueryStaStatistics, sizeof(rQueryStaStatistics)); + rQueryStaStatistics.ucReadClear = true; + + /* DBGLOG(RSN, INFO, "MT6632 : priv_driver_get_sta_info\n"); */ + if (i4Argc >= 3) { + if (strnicmp(apcArgv[1], CMD_GET_STA_KEEP_CNT, + strlen(CMD_GET_STA_KEEP_CNT)) == 0) { + if (wlanHwAddrToBin(apcArgv[2], &aucMacAddr[0]) < 0) { + DBGLOG(REQ, WARN, + "%s: MAC addr Argv[2] convert failed\n", + __func__); + return -1; + } + rQueryStaStatistics.ucReadClear = false; + } else if (strnicmp(apcArgv[2], CMD_GET_STA_KEEP_CNT, + strlen(CMD_GET_STA_KEEP_CNT)) == 0) { + if (wlanHwAddrToBin(apcArgv[1], &aucMacAddr[0]) < 0) { + DBGLOG(REQ, WARN, + "%s: MAC addr Argv[1] convert failed\n", + __func__); + return -1; + } + rQueryStaStatistics.ucReadClear = false; + } + + if (!wlanGetWlanIdxByAddress(prGlueInfo->prAdapter, + &aucMacAddr[0], &ucWlanIndex)) { + return i4BytesWritten; + } + } else { + /* Get AIS AP address for no argument */ + if (prGlueInfo->prAdapter->prAisBssInfo->prStaRecOfAP) { + ucWlanIndex = prGlueInfo->prAdapter->prAisBssInfo + ->prStaRecOfAP->ucWlanIndex; + } else if (!wlanGetWlanIdxByAddress(prGlueInfo->prAdapter, NULL, + &ucWlanIndex)) { /* try get + * a peer + */ + return i4BytesWritten; + } + + if (i4Argc == 2) { + if (strnicmp(apcArgv[1], CMD_GET_STA_KEEP_CNT, + strlen(CMD_GET_STA_KEEP_CNT)) == 0) { + rQueryStaStatistics.ucReadClear = false; + } + } + } + + prHwWlanInfo = (P_PARAM_HW_WLAN_INFO_T)kalMemAlloc( + sizeof(PARAM_HW_WLAN_INFO_T), VIR_MEM_TYPE); + + if (!prHwWlanInfo) { + DBGLOG(REQ, ERROR, "alloc memory for prHwWlanInfo failed!\n"); + i4BytesWritten = -1; + goto out; + } + kalMemZero(prHwWlanInfo, sizeof(PARAM_HW_WLAN_INFO_T)); + prHwWlanInfo->u4Index = ucWlanIndex; + + DBGLOG(REQ, INFO, "MT6632 : index = %d i4TotalLen = %d\n", + prHwWlanInfo->u4Index, i4TotalLen); + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryWlanInfo, prHwWlanInfo, + sizeof(PARAM_HW_WLAN_INFO_T), true, true, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "query prHwWlanInfo failed!\n"); + goto out; + } + + i4BytesWritten = priv_driver_dump_helper_wtbl_info( + pcCommand, i4TotalLen, prHwWlanInfo); + + pucMacAddr = + wlanGetStaAddrByWlanIdx(prGlueInfo->prAdapter, ucWlanIndex); + if (pucMacAddr) { + COPY_MAC_ADDR(rQueryStaStatistics.aucMacAddr, pucMacAddr); + /* i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + * i4TotalLen - i4BytesWritten, + * "\tAddr="MACSTR"\n", + * MAC2STR(rQueryStaStatistics.aucMacAddr)); + */ + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryStaStatistics, + &rQueryStaStatistics, + sizeof(rQueryStaStatistics), true, false, + true, &u4BufLen); + + if (rStatus == WLAN_STATUS_SUCCESS) { + rRssi = RCPI_TO_dBm(rQueryStaStatistics.ucRcpi); + u2LinkSpeed = + rQueryStaStatistics.u2LinkSpeed == 0 ? + 0 : + rQueryStaStatistics.u2LinkSpeed / 2; + + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", + "\n\nSTA Stat:\n"); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "Tx total cnt = %ld\n", + rQueryStaStatistics.u4TransmitCount); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "Tx success = %ld\n", + rQueryStaStatistics.u4TransmitCount - + rQueryStaStatistics.u4TransmitFailCount); + + u4Per = rQueryStaStatistics.u4TransmitCount == 0 ? + 0 : + (1000 * + (rQueryStaStatistics + .u4TransmitFailCount)) / + rQueryStaStatistics + .u4TransmitCount; + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "Tx fail count = %ld, PER=%ld.%1ld%%\n", + rQueryStaStatistics.u4TransmitFailCount, + u4Per / 10, u4Per % 10); + + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "RSSI = %d\n", rRssi); + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "LinkSpeed = %d\n", u2LinkSpeed); + } + } + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand); + +out: + if (prHwWlanInfo) { + kalMemFree(prHwWlanInfo, VIR_MEM_TYPE, + sizeof(PARAM_HW_WLAN_INFO_T)); + } + + return i4BytesWritten; +} + +static int priv_driver_get_mib_info(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + u8 i; + u32 u4Per; + s32 u4Ret = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + P_PARAM_HW_MIB_INFO_T prHwMibInfo; + P_RX_CTRL_T prRxCtrl; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + prRxCtrl = &prGlueInfo->prAdapter->rRxCtrl; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + DBGLOG(REQ, INFO, "MT6632 : priv_driver_get_mib_info\n"); + + prHwMibInfo = (P_PARAM_HW_MIB_INFO_T)kalMemAlloc( + sizeof(PARAM_HW_MIB_INFO_T), VIR_MEM_TYPE); + if (!prHwMibInfo) { + return -1; + } + + kalMemZero(prHwMibInfo, sizeof(PARAM_HW_MIB_INFO_T)); + + if (i4Argc == 1) { + prHwMibInfo->u4Index = 0; + } + + if (i4Argc >= 2) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &prHwMibInfo->u4Index); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse apcArgv error u4Ret=%d\n", + u4Ret); + return -1; + } + } + + DBGLOG(REQ, INFO, "MT6632 : index = %d\n", prHwMibInfo->u4Index); + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryMibInfo, prHwMibInfo, + sizeof(PARAM_HW_MIB_INFO_T), true, true, true, + &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + kalMemFree(prHwMibInfo, VIR_MEM_TYPE, + sizeof(PARAM_HW_MIB_INFO_T)); + return -1; + } + + if (prHwMibInfo->u4Index < 2) { + i4BytesWritten = kalScnprintf(pcCommand, i4TotalLen, "%s", + "\n\nmib state:\n"); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "Dump MIB info of IDX = %d\n", + prHwMibInfo->u4Index); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s", + "===Rx Related Counters===\n"); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx with CRC=%ld\n", + prHwMibInfo->rHwMibCnt.u4RxFcsErrCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx drop due to out of resource=%ld\n", + prHwMibInfo->rHwMibCnt.u4RxFifoFullCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx Mpdu=%ld\n", prHwMibInfo->rHwMibCnt.u4RxMpduCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx AMpdu=%ld\n", + prHwMibInfo->rHwMibCnt.u4RxAMPDUCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx PF Drop=%ld\n", + prHwMibInfo->rHwMibCnt.u4PFDropCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx Len Mismatch=%ld\n", + prHwMibInfo->rHwMibCnt.u4RxLenMismatchCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx data indicate total=%llu\n", + RX_GET_CNT(prRxCtrl, RX_DATA_INDICATION_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx data retain total=%llu\n", + RX_GET_CNT(prRxCtrl, RX_DATA_RETAINED_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx drop by SW total=%llu\n", + RX_GET_CNT(prRxCtrl, RX_DROP_TOTAL_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx reorder miss=%llu\n", + RX_GET_CNT(prRxCtrl, RX_DATA_REORDER_MISS_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx reorder within=%llu\n", + RX_GET_CNT(prRxCtrl, RX_DATA_REORDER_WITHIN_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx reorder ahead=%llu\n", + RX_GET_CNT(prRxCtrl, RX_DATA_REORDER_AHEAD_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx reorder behind=%llu\n", + RX_GET_CNT(prRxCtrl, RX_DATA_REORDER_BEHIND_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx reorder behind continuous=%llu\n", + RX_GET_CNT(prRxCtrl, + RX_DATA_REORDER_BEHIND_CONTINUOUS_COUNT)); + + do { + u32 u4AmsduCntx100 = 0; + + if (RX_GET_CNT(prRxCtrl, RX_DATA_AMSDU_COUNT)) { + u4AmsduCntx100 = (u32)div64_u64( + RX_GET_CNT(prRxCtrl, + RX_DATA_MSDU_IN_AMSDU_COUNT) + * + 100, + RX_GET_CNT(prRxCtrl, + RX_DATA_AMSDU_COUNT)); + } + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tRx avg MSDU in AMSDU=%1ld.%02ld\n", + u4AmsduCntx100 / 100, u4AmsduCntx100 % 100); + } while (false); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx total MSDU in AMSDU=%llu\n", + RX_GET_CNT(prRxCtrl, RX_DATA_MSDU_IN_AMSDU_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx AMSDU=%llu\n", + RX_GET_CNT(prRxCtrl, RX_DATA_AMSDU_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx AMSDU miss=%llu\n", + RX_GET_CNT(prRxCtrl, RX_DATA_AMSDU_MISS_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx no StaRec drop=%llu\n", + RX_GET_CNT(prRxCtrl, RX_NO_STA_DROP_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx inactive BSS drop=%llu\n", + RX_GET_CNT(prRxCtrl, RX_INACTIVE_BSS_DROP_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx HS20 drop=%llu\n", + RX_GET_CNT(prRxCtrl, RX_HS20_DROP_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx low SwRfb drop=%llu\n", + RX_GET_CNT(prRxCtrl, RX_LESS_SW_RFB_DROP_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx dupicate drop=%llu\n", + RX_GET_CNT(prRxCtrl, RX_DUPICATE_DROP_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx MIC err drop=%llu\n", + RX_GET_CNT(prRxCtrl, RX_MIC_ERROR_DROP_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx BAR handle=%llu\n", + RX_GET_CNT(prRxCtrl, RX_BAR_DROP_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx non-interest drop=%llu\n", + RX_GET_CNT(prRxCtrl, RX_NO_INTEREST_DROP_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx type err drop=%llu\n", + RX_GET_CNT(prRxCtrl, RX_TYPE_ERR_DROP_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx class err drop=%llu\n", + RX_GET_CNT(prRxCtrl, RX_CLASS_ERR_DROP_COUNT)); +#if CFG_KEY_ERROR_STATISTIC_RECOVERY + i4BytesWritten += kalSnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx BMC cipher mismatch=%llu\n", + RX_GET_CNT(prRxCtrl, RX_BMC_NO_KEY_COUNT)); + i4BytesWritten += kalSnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx BMC ICV error=%llu\n", + RX_GET_CNT(prRxCtrl, RX_BMC_KEY_ERROR_COUNT)); + i4BytesWritten += kalSnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx BMC Pkt=%llu\n", + RX_GET_CNT(prRxCtrl, RX_BMC_PKT_COUNT)); +#endif + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s", "===Phy/Timing Related Counters===\n"); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tChannelIdleCnt=%ld\n", + prHwMibInfo->rHwMibCnt.u4ChannelIdleCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tCCA_NAV_Tx_Time=%ld\n", + prHwMibInfo->rHwMibCnt.u4CcaNavTx); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tRx_MDRDY_CNT=%ld\n", + prHwMibInfo->rHwMibCnt.u4MdrdyCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tCCK_MDRDY=%ld, OFDM_MDRDY=0x%lx, OFDM_GREEN_MDRDY=0x%lx\n", + prHwMibInfo->rHwMibCnt.u4CCKMdrdyCnt, + prHwMibInfo->rHwMibCnt.u4OFDMLGMixMdrdy, + prHwMibInfo->rHwMibCnt.u4OFDMGreenMdrdy); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tPrim CCA Time=%ld\n", + prHwMibInfo->rHwMibCnt.u4PCcaTime); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tSec CCA Time=%ld\n", + prHwMibInfo->rHwMibCnt.u4SCcaTime); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tPrim ED Time=%ld\n", + prHwMibInfo->rHwMibCnt.u4PEDTime); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s", "===Tx Related Counters(Generic)===\n"); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tBeaconTxCnt=%ld\n", + prHwMibInfo->rHwMibCnt.u4BeaconTxCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tTx 40MHz Cnt=%ld\n", + prHwMibInfo->rHwMib2Cnt.u4Tx40MHzCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tTx 80MHz Cnt=%ld\n", + prHwMibInfo->rHwMib2Cnt.u4Tx80MHzCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tTx 160MHz Cnt=%ld\n", + prHwMibInfo->rHwMib2Cnt.u4Tx160MHzCnt); + for (i = 0; i < BSSID_NUM; i++) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\t===BSSID[%d] Related Counters===\n", i); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tBA Miss Cnt=%ld\n", + prHwMibInfo->rHwMibCnt.au4BaMissedCnt[i]); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tRTS Tx Cnt=%ld\n", + prHwMibInfo->rHwMibCnt.au4RtsTxCnt[i]); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tFrame Retry Cnt=%ld\n", + prHwMibInfo->rHwMibCnt.au4FrameRetryCnt[i]); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tFrame Retry 2 Cnt=%ld\n", + prHwMibInfo->rHwMibCnt.au4FrameRetry2Cnt[i]); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tRTS Retry Cnt=%ld\n", + prHwMibInfo->rHwMibCnt.au4RtsRetryCnt[i]); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tAck Failed Cnt=%ld\n", + prHwMibInfo->rHwMibCnt.au4AckFailedCnt[i]); + } + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s", "===AMPDU Related Counters===\n"); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tTx AMPDU_Pkt_Cnt=%ld\n", + prHwMibInfo->rHwTxAmpduMts.u2TxAmpduCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tTx AMPDU_MPDU_Pkt_Cnt=%ld\n", + prHwMibInfo->rHwTxAmpduMts.u4TxSfCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tAMPDU SuccessCnt=%ld\n", + prHwMibInfo->rHwTxAmpduMts.u4TxAckSfCnt); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tAMPDU Tx success = %ld\n", + prHwMibInfo->rHwTxAmpduMts.u4TxAckSfCnt); + + u4Per = prHwMibInfo->rHwTxAmpduMts.u4TxSfCnt == 0 ? + 0 : + (1000 * + (prHwMibInfo->rHwTxAmpduMts.u4TxSfCnt - + prHwMibInfo->rHwTxAmpduMts.u4TxAckSfCnt)) / + prHwMibInfo->rHwTxAmpduMts.u4TxSfCnt; + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tAMPDU Tx fail count = %ld, PER=%ld.%1ld%%\n", + prHwMibInfo->rHwTxAmpduMts.u4TxSfCnt - + prHwMibInfo->rHwTxAmpduMts.u4TxAckSfCnt, + u4Per / 10, u4Per % 10); + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s", "\tTx Agg\n"); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s", + "\tRange: 1 2~5 6~15 16~22 23~33 34~49 50~57 58~64\n"); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\t\t%d \t%d \t%d \t%d \t%d \t%d \t%d \t%d\n", + prHwMibInfo->rHwTxAmpduMts.u2TxRange1AmpduCnt, + prHwMibInfo->rHwTxAmpduMts.u2TxRange2AmpduCnt, + prHwMibInfo->rHwTxAmpduMts.u2TxRange3AmpduCnt, + prHwMibInfo->rHwTxAmpduMts.u2TxRange4AmpduCnt, + prHwMibInfo->rHwTxAmpduMts.u2TxRange5AmpduCnt, + prHwMibInfo->rHwTxAmpduMts.u2TxRange6AmpduCnt, + prHwMibInfo->rHwTxAmpduMts.u2TxRange7AmpduCnt, + prHwMibInfo->rHwTxAmpduMts.u2TxRange8AmpduCnt); + } else { + i4BytesWritten = kalScnprintf(pcCommand, i4TotalLen, "%s", + "\nClear All Statistics\n"); + } + + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand); + + kalMemFree(prHwMibInfo, VIR_MEM_TYPE, sizeof(PARAM_HW_MIB_INFO_T)); + + nicRxClearStatistics(prGlueInfo->prAdapter); + + return i4BytesWritten; +} + +/* Private Coex Ctrl Subcmd for Isolation Detection */ +static int priv_driver_iso_detect(IN P_GLUE_INFO_T prGlueInfo, + IN struct CMD_COEX_CTRL *prCmdCoexCtrl, + IN signed char *argv[]) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + u32 u4Ret = 0; + + struct CMD_COEX_ISO_DETECT rCmdCoexIsoDetect; + + rCmdCoexIsoDetect.u4Isolation = 0; + kalMemZero(&rCmdCoexIsoDetect, sizeof(struct CMD_COEX_ISO_DETECT)); + + u4Ret = kalkStrtou32(argv[2], 0, &(rCmdCoexIsoDetect.u4IsoPath)); + if (u4Ret) { + DBGLOG(REQ, + LOUD, + " -priv_driver_coex_iso_detect - Parse Iso Path failed u4Ret=%d\n", + u4Ret); + return -1; + } + + u4Ret = kalkStrtou32(argv[3], 0, &(rCmdCoexIsoDetect.u4Channel)); + if (u4Ret) { + DBGLOG(REQ, + LOUD, + " -priv_driver_coex_iso_detect - Parse channel failed u4Ret = %d\n", + u4Ret); + return -1; + } + + /* Copy Memory */ + kalMemCopy(prCmdCoexCtrl->aucBuffer, &rCmdCoexIsoDetect, + sizeof(struct CMD_COEX_ISO_DETECT)); + + /* Ioctl Isolation Detect */ + rStatus = kalIoctl(prGlueInfo, wlanoidQueryCoexIso, prCmdCoexCtrl, + sizeof(struct CMD_COEX_CTRL), true, true, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + /* If all pass, return u4Ret to 0 */ + return u4Ret; +} + +/* Private Command for Coex Ctrl */ +static int priv_driver_coex_ctrl(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s32 i4ArgNum = 2; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u32 u4Ret = 0; + enum ENUM_COEX_CTRL_CMD CoexCtrlCmd; + struct CMD_COEX_CTRL rCmdCoexCtrl; + + kalMemZero(&rCmdCoexCtrl, sizeof(struct CMD_COEX_CTRL)); + + ASSERT(prNetDev); + + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + /* Prevent Kernel Panic, set default i4ArgNum to 2 */ + if (i4Argc >= i4ArgNum) { + /* Parse Coex SubCmd */ + u4Ret = kalkStrtou32(apcArgv[1], 0, &rCmdCoexCtrl.u4SubCmd); + if (u4Ret) { + return -1; + } + + CoexCtrlCmd = (enum ENUM_COEX_CTRL_CMD)rCmdCoexCtrl.u4SubCmd; + + switch (CoexCtrlCmd) { + /* Isolation Detection */ + case ENUM_COEX_CTRL_ISO_DETECT: { + s32 i4SubArgNum = 4; + /* Safely dereference "argv[3]".*/ + if (i4Argc >= i4SubArgNum) { + struct CMD_COEX_ISO_DETECT *prCmdCoexIsoDetect; + + /* Isolation Detection Method */ + u4Ret = priv_driver_iso_detect( + prGlueInfo, &rCmdCoexCtrl, apcArgv); + if (u4Ret) { + return -1; + } + + /* Get Isolation value */ + prCmdCoexIsoDetect = + (struct CMD_COEX_ISO_DETECT *) + rCmdCoexCtrl.aucBuffer; + + /* Set Return i4BytesWritten Value */ + i4BytesWritten = snprintf( + pcCommand, i4TotalLen, "%d", + prCmdCoexIsoDetect->u4Isolation); + DBGLOG(REQ, INFO, "Isolation: %d\n", + prCmdCoexIsoDetect->u4Isolation); + } + break; + } + + /* Default Coex Cmd */ + default: + break; + } + } + return i4BytesWritten; +} + +static int priv_driver_set_fw_log(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u32 u4McuDest = 0; + u32 u4LogType = 0; +#if CFG_SUPPORT_FW_DBG_LEVEL_CTRL + u32 ucFwLogLevel = FW_DBG_LEVEL_DONT_SET; +#endif + P_CMD_FW_LOG_2_HOST_CTRL_T prFwLog2HostCtrl = NULL; + u32 u4Ret = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RSN, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + DBGLOG(RSN, INFO, "MT6632 : priv_driver_set_fw_log\n"); + + prFwLog2HostCtrl = (P_CMD_FW_LOG_2_HOST_CTRL_T)kalMemAlloc( + sizeof(CMD_FW_LOG_2_HOST_CTRL_T), VIR_MEM_TYPE); + if (!prFwLog2HostCtrl) { + DBGLOG(REQ, ERROR, + "allocate memory for prFwLog2HostCtrl failed\n"); + i4BytesWritten = -1; + goto out; + } + kalMemZero(prFwLog2HostCtrl, sizeof(CMD_FW_LOG_2_HOST_CTRL_T)); + +#if CFG_SUPPORT_FW_DBG_LEVEL_CTRL + if ((i4Argc != 3) && (i4Argc != 4)) { + DBGLOG(REQ, ERROR, "argc %i must be 3 or 4\n", i4Argc); + i4BytesWritten = -1; + goto out; + } +#else + if (i4Argc != 3) { + DBGLOG(REQ, ERROR, "argc %i is not equal to 3\n", i4Argc); + i4BytesWritten = -1; + goto out; + } +#endif + + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4McuDest); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse u4McuDest error u4Ret=%d\n", u4Ret); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[2], 0, &u4LogType); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse u4LogType error u4Ret=%d\n", u4Ret); + return -1; + } + +#if CFG_SUPPORT_FW_DBG_LEVEL_CTRL + if (i4Argc == 4) { + u4Ret = kalkStrtou32(apcArgv[3], 0, &ucFwLogLevel); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucFwLogLevel error u4Ret=%d\n", + u4Ret); + return -1; + } + } + prFwLog2HostCtrl->ucFwLogLevel = (u8)ucFwLogLevel; +#endif + + prFwLog2HostCtrl->ucMcuDest = (u8)u4McuDest; + prFwLog2HostCtrl->ucFwLog2HostCtrl = (u8)u4LogType; + + if (prFwLog2HostCtrl->ucMcuDest == 0) { + prGlueInfo->prAdapter->rWifiVar.ucN9Log2HostCtrl = + prFwLog2HostCtrl->ucFwLog2HostCtrl; + } else if (prFwLog2HostCtrl->ucMcuDest == 1) { + prGlueInfo->prAdapter->rWifiVar.ucCR4Log2HostCtrl = + prFwLog2HostCtrl->ucFwLog2HostCtrl; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetFwLog2Host, prFwLog2HostCtrl, + sizeof(CMD_FW_LOG_2_HOST_CTRL_T), true, true, true, + &u4BufLen); + + DBGLOG(REQ, INFO, "%s: command result is %s (%d %d)\n", __func__, + pcCommand, u4McuDest, u4LogType); + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "send fw log to host cmd failed\n"); + i4BytesWritten = -1; + goto out; + } + +out: + if (prFwLog2HostCtrl) { + kalMemFree(prFwLog2HostCtrl, VIR_MEM_TYPE, + sizeof(CMD_FW_LOG_2_HOST_CTRL_T)); + } + + return i4BytesWritten; +} +#endif + +static int priv_driver_get_magic_pkt_info(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + CMD_GET_MAGIC_PKT_INFO_T *cmd = NULL; + u8 fgWaitResp = true; + u8 fgRead = true; + + ASSERT(prNetDev); + + DBGLOG(REQ, INFO, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, INFO, "argc is %i\n", i4Argc); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (!prGlueInfo) { + goto get_info_invalid; + } + + cmd = (CMD_GET_MAGIC_PKT_INFO_T *)kalMemAlloc(sizeof(*cmd), + VIR_MEM_TYPE); + + if (!cmd) { + goto get_info_invalid; + } + + if (i4Argc > 1) { + goto get_info_invalid; + } + + memset(cmd, 0, sizeof(*cmd)); + cmd->u2Type = CMD_GET_MAGIC_PKT_INFO_TYPE; + cmd->u2Len = sizeof(*cmd); + + rStatus = kalIoctl(prGlueInfo, wlanoidAdvCtrl, cmd, sizeof(*cmd), + fgWaitResp, fgRead, true, &u4BufLen); + + if ((rStatus != WLAN_STATUS_SUCCESS) && + (rStatus != WLAN_STATUS_PENDING)) { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\ncommand failed %x", rStatus); + } else { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nMagicPacket_Rx count = %d", + cmd->u4MagicPktCntTotal); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nPullLowGpio_Wakeup count = %d", + cmd->u4GpioPullLowCntTotal); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nPullHighGpio_Wakeup count = %d", + cmd->u4GpioPullHighCntTotal); + } + +get_info_invalid: + if (cmd) { + kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd)); + } + return i4BytesWritten; +} + +static int priv_driver_get_mcr(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u32 u4Ret; + s32 i4ArgNum = 2; + CMD_ACCESS_REG rCmdAccessReg; + + kalMemZero(&rCmdAccessReg, sizeof(CMD_ACCESS_REG)); + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= i4ArgNum) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &(rCmdAccessReg.u4Address)); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "parse get_mcr error (Address) u4Ret=%d\n", + u4Ret); + return -1; + } + + /* rCmdAccessReg.u4Address = kalStrtoul(apcArgv[1], NULL, 0); */ + rCmdAccessReg.u4Data = 0; + + DBGLOG(REQ, LOUD, "address is %x\n", rCmdAccessReg.u4Address); + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryMcrRead, + &rCmdAccessReg, sizeof(rCmdAccessReg), true, + true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + i4BytesWritten = snprintf(pcCommand, i4TotalLen, "0x%08x", + (unsigned int)rCmdAccessReg.u4Data); + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, + pcCommand); + } + + return i4BytesWritten; +} + +int priv_driver_set_mcr(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Ret; + s32 i4ArgNum = 3; + CMD_ACCESS_REG rCmdAccessReg; + + kalMemZero(&rCmdAccessReg, sizeof(CMD_ACCESS_REG)); + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= i4ArgNum) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &(rCmdAccessReg.u4Address)); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "parse get_mcr error (Address) u4Ret=%d\n", + u4Ret); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[2], 0, &(rCmdAccessReg.u4Data)); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "parse get_mcr error (Data) u4Ret=%d\n", u4Ret); + return -1; + } + + /* rCmdAccessReg.u4Address = kalStrtoul(apcArgv[1], NULL, 0); */ + /* rCmdAccessReg.u4Data = kalStrtoul(apcArgv[2], NULL, 0); */ + + rStatus = kalIoctl(prGlueInfo, wlanoidSetMcrWrite, + &rCmdAccessReg, sizeof(rCmdAccessReg), false, + false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + } + + return i4BytesWritten; +} + +static int priv_driver_set_test_mode(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u32 u4Ret; + s32 i4ArgNum = 2, u4MagicKey = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= i4ArgNum) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &(u4MagicKey)); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse Magic Key error u4Ret=%d\n", + u4Ret); + return -1; + } + + DBGLOG(REQ, LOUD, "The Set Test Mode Magic Key is %d\n", + u4MagicKey); + + if (u4MagicKey == PRIV_CMD_TEST_MAGIC_KEY) { + rStatus = kalIoctl(prGlueInfo, wlanoidRftestSetTestMode, + NULL, 0, false, false, true, + &u4BufLen); + } else if (u4MagicKey == 0) { + rStatus = kalIoctl(prGlueInfo, + wlanoidRftestSetAbortTestMode, NULL, + 0, false, false, true, &u4BufLen); + } + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + } + + return i4BytesWritten; +} + +static int priv_driver_set_test_cmd(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u32 u4Ret; + s32 i4ArgNum = 3; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + kalMemZero(&rRfATInfo, sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T)); + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= i4ArgNum) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &(rRfATInfo.u4FuncIndex)); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "Parse Test CMD Index error u4Ret=%d\n", u4Ret); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[2], 0, &(rRfATInfo.u4FuncData)); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "Parse Test CMD Data error u4Ret=%d\n", u4Ret); + return -1; + } + + DBGLOG(REQ, LOUD, + "Set Test CMD FuncIndex = %d, FuncData = %d\n", + rRfATInfo.u4FuncIndex, rRfATInfo.u4FuncData); + + rStatus = kalIoctl(prGlueInfo, wlanoidRftestSetAutoTest, + &rRfATInfo, sizeof(rRfATInfo), false, false, + true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + } + + return i4BytesWritten; +} + +static int priv_driver_get_test_result(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u32 u4Ret; + u32 u4Data = 0; + s32 i4ArgNum = 3; + PARAM_MTK_WIFI_TEST_STRUCT_T rRfATInfo; + + kalMemZero(&rRfATInfo, sizeof(PARAM_MTK_WIFI_TEST_STRUCT_T)); + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= i4ArgNum) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &(rRfATInfo.u4FuncIndex)); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "Parse Test CMD Index error u4Ret=%d\n", u4Ret); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[2], 0, &(rRfATInfo.u4FuncData)); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "Parse Test CMD Data error u4Ret=%d\n", u4Ret); + return -1; + } + + DBGLOG(REQ, LOUD, + "Get Test CMD FuncIndex = %d, FuncData = %d\n", + rRfATInfo.u4FuncIndex, rRfATInfo.u4FuncData); + + rStatus = kalIoctl(prGlueInfo, wlanoidRftestQueryAutoTest, + &rRfATInfo, sizeof(rRfATInfo), true, true, + true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + u4Data = (unsigned int)rRfATInfo.u4FuncData; + i4BytesWritten = snprintf(pcCommand, i4TotalLen, "%d[0x%08x]", + u4Data, u4Data); + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, + pcCommand); + } + + return i4BytesWritten; +} + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +s32 priv_driver_last_sec_mcs_info(IN P_ADAPTER_T prAdapter, IN char *pcCommand, + IN int i4TotalLen, + P_PARAM_HW_WLAN_INFO_T prHwWlanInfo, + struct PARAM_TX_MCS_INFO *prTxMcsInfo) +{ + u8 i, j, txmode, rate, stbc; + u8 nsts; + s32 i4BytesWritten = 0; + u32 au4RxVect0Que[MCS_INFO_SAMPLE_CNT], + au4RxVect1Que[MCS_INFO_SAMPLE_CNT]; + u8 ucStaIdx = prTxMcsInfo->ucStaIndex; + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nTx MCS:\n"); + + for (i = 0; i < MCS_INFO_SAMPLE_CNT; i++) { + u8 tmpPerSum = 0, cnt = 0; + u16 tmpRateCode = 0xFFFF; + + if (prTxMcsInfo->au2TxRateCode[i] == 0xFFFF) { + continue; + } + + if (tmpRateCode == 0xFFFF) { + tmpRateCode = prTxMcsInfo->au2TxRateCode[i]; + } + + txmode = HW_TX_RATE_TO_MODE(prTxMcsInfo->au2TxRateCode[i]); + if (txmode >= MAX_TX_MODE) { + txmode = MAX_TX_MODE; + } + rate = HW_TX_RATE_TO_MCS(prTxMcsInfo->au2TxRateCode[i], txmode); + nsts = HW_TX_RATE_TO_NSS(prTxMcsInfo->au2TxRateCode[i]) + 1; + stbc = HW_TX_RATE_TO_STBC(prTxMcsInfo->au2TxRateCode[i]); + + for (j = 0; j < MCS_INFO_SAMPLE_CNT; j++) { + if (tmpRateCode == prTxMcsInfo->au2TxRateCode[j]) { + tmpPerSum += prTxMcsInfo->aucTxRatePer[j]; + cnt++; + prTxMcsInfo->au2TxRateCode[j] = 0xFFFF; + } + } + + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, " %s, ", + HW_TX_RATE_CCK_STR[rate & 0x3]); + } else if (txmode == TX_RATE_MODE_OFDM) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + " %s, ", hw_rate_ofdm_str(rate)); + } else if ((txmode == TX_RATE_MODE_HTMIX) || + (txmode == TX_RATE_MODE_HTGF)) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, " MCS%d, ", rate); + } else { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + " NSS%d_MCS%d, ", nsts, rate); + } + + if ((txmode == TX_RATE_MODE_CCK) || + (txmode == TX_RATE_MODE_OFDM)) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", HW_TX_RATE_BW[0]); + } else if (i > + prHwWlanInfo->rWtblPeerCap.ucChangeBWAfterRateN) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", + prHwWlanInfo->rWtblPeerCap.ucFrequencyCapability + < + 4 ? + (prHwWlanInfo->rWtblPeerCap + .ucFrequencyCapability > + BW_20 ? + HW_TX_RATE_BW + [prHwWlanInfo + ->rWtblPeerCap + .ucFrequencyCapability - + 1] : + HW_TX_RATE_BW + [prHwWlanInfo + ->rWtblPeerCap + .ucFrequencyCapability]) : + HW_TX_RATE_BW[4]); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", + prHwWlanInfo->rWtblPeerCap.ucFrequencyCapability + < + 4 ? + HW_TX_RATE_BW + [prHwWlanInfo->rWtblPeerCap + .ucFrequencyCapability] : + HW_TX_RATE_BW[4]); + } + + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", rate < 4 ? "LP" : "SP"); + } else if (txmode == TX_RATE_MODE_OFDM) { + ; + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s, ", + priv_driver_get_sgi_info( + &prHwWlanInfo->rWtblPeerCap) == 0 ? + "LGI" : + "SGI"); + } + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s%s%s [PER: %02d%%]\t", + txmode < 5 ? HW_TX_MODE_STR[txmode] : HW_TX_MODE_STR[5], + stbc ? ", STBC, " : ", ", + ((priv_driver_get_ldpc_info( + &prHwWlanInfo->rWtblTxConfig) == 0) || + (txmode == TX_RATE_MODE_CCK) || + (txmode == TX_RATE_MODE_OFDM)) ? + "BCC" : + "LDPC", + tmpPerSum / cnt); + + for (j = 0; j < cnt; j++) + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "*"); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n"); + } + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nRx MCS:\n"); + + kalMemCopy(au4RxVect0Que, prAdapter->arStaRec[ucStaIdx].au4RxVect0Que, + sizeof(au4RxVect0Que)); + kalMemCopy(au4RxVect1Que, prAdapter->arStaRec[ucStaIdx].au4RxVect1Que, + sizeof(au4RxVect1Que)); + + for (i = 0; i < MCS_INFO_SAMPLE_CNT; i++) { + u8 cnt = 0; + u32 u4RxVector0 = 0xFFFFFFFF; + u32 txmode, rate, frmode, sgi, nsts, ldpc, stbc, groupid, mu; +#define RX_MCS_INFO_MASK BITS(0, 17) + + if (au4RxVect0Que[i] == 0xFFFFFFFF) { + continue; + } + + if (u4RxVector0 == 0xFFFFFFFF) { + u4RxVector0 = au4RxVect0Que[i]; + } + + txmode = (au4RxVect0Que[i] & RX_VT_RX_MODE_MASK) >> + RX_VT_RX_MODE_OFFSET; + rate = (au4RxVect0Que[i] & RX_VT_RX_RATE_MASK) >> + RX_VT_RX_RATE_OFFSET; + frmode = (au4RxVect0Que[i] & RX_VT_FR_MODE_MASK) >> + RX_VT_FR_MODE_OFFSET; + nsts = ((au4RxVect1Que[i] & RX_VT_NSTS_MASK) >> + RX_VT_NSTS_OFFSET); + stbc = (au4RxVect0Que[i] & RX_VT_STBC_MASK) >> + RX_VT_STBC_OFFSET; + sgi = au4RxVect0Que[i] & RX_VT_SHORT_GI; + ldpc = au4RxVect0Que[i] & RX_VT_LDPC; + groupid = (au4RxVect1Que[i] & RX_VT_GROUP_ID_MASK) >> + RX_VT_GROUP_ID_OFFSET; + + for (j = 0; j < MCS_INFO_SAMPLE_CNT; j++) { + if ((u4RxVector0 & RX_MCS_INFO_MASK) == + (au4RxVect0Que[j] & RX_MCS_INFO_MASK)) { + au4RxVect0Que[j] = 0xFFFFFFFF; + cnt++; + } + } + + if (groupid && groupid != 63) { + mu = 1; + } else { + mu = 0; + nsts += 1; + } + + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, " %s, ", + rate < 4 ? HW_TX_RATE_CCK_STR[rate] : + HW_TX_RATE_CCK_STR[4]); + } else if (txmode == TX_RATE_MODE_OFDM) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + " %s, ", hw_rate_ofdm_str(rate)); + } else if ((txmode == TX_RATE_MODE_HTMIX) || + (txmode == TX_RATE_MODE_HTGF)) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, " MCS%d, ", rate); + } else { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + " NSS%d_MCS%d, ", nsts, rate); + } + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s, ", + frmode < 4 ? HW_TX_RATE_BW[frmode] : HW_TX_RATE_BW[4]); + + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", rate < 4 ? "LP" : "SP"); + } else if (txmode == TX_RATE_MODE_OFDM) { + ; + } else { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s,", + sgi == 0 ? "LGI" : "SGI"); + } + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s", + stbc == 0 ? " " : " STBC, "); + + if (mu) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, %s, %s (%d)\t", + txmode < 5 ? HW_TX_MODE_STR[txmode] : + HW_TX_MODE_STR[5], + ldpc == 0 ? "BCC" : "LDPC", "MU", groupid); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s, %s\t", + txmode < 5 ? HW_TX_MODE_STR[txmode] : + HW_TX_MODE_STR[5], + ldpc == 0 ? "BCC" : "LDPC"); + } + + for (j = 0; j < cnt; j++) + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "*"); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n"); + } + + return i4BytesWritten; +} +#endif + +s32 priv_driver_tx_rate_info(IN char *pcCommand, IN int i4TotalLen, + u8 fgDumpAll, P_PARAM_HW_WLAN_INFO_T prHwWlanInfo, + P_PARAM_GET_STA_STATISTICS prQueryStaStatistics) +{ + u8 i, txmode, rate, stbc; + u8 nsts; + s32 i4BytesWritten = 0; + + for (i = 0; i < AUTO_RATE_NUM; i++) { + txmode = HW_TX_RATE_TO_MODE( + prHwWlanInfo->rWtblRateInfo.au2RateCode[i]); + if (txmode >= MAX_TX_MODE) { + txmode = MAX_TX_MODE; + } + rate = HW_TX_RATE_TO_MCS( + prHwWlanInfo->rWtblRateInfo.au2RateCode[i], txmode); + nsts = HW_TX_RATE_TO_NSS( + prHwWlanInfo->rWtblRateInfo.au2RateCode[i]) + + 1; + stbc = HW_TX_RATE_TO_STBC( + prHwWlanInfo->rWtblRateInfo.au2RateCode[i]); + + if (fgDumpAll) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "Rate index - %d ", i); + + if (prHwWlanInfo->rWtblRateInfo.ucRateIdx == i) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", + "--> "); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", " "); + } + } + + if (!fgDumpAll) { + if (prHwWlanInfo->rWtblRateInfo.ucRateIdx != i) { + continue; + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%-20s%s", + "AR TX Rate", " = "); + } + } + + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s, ", + HW_TX_RATE_CCK_STR[rate & 0x3]); + } else if (txmode == TX_RATE_MODE_OFDM) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", hw_rate_ofdm_str(rate)); + } else if ((txmode == TX_RATE_MODE_HTMIX) || + (txmode == TX_RATE_MODE_HTGF)) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "MCS%d, ", rate); + } else { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "NSS%d_MCS%d, ", nsts, rate); + } + + if (prQueryStaStatistics->ucSkipAr) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", + prHwWlanInfo->rWtblPeerCap.ucFrequencyCapability + < + 4 ? + HW_TX_RATE_BW + [prHwWlanInfo->rWtblPeerCap + .ucFrequencyCapability] : + HW_TX_RATE_BW[4]); + } else { + if ((txmode == TX_RATE_MODE_CCK) || + (txmode == TX_RATE_MODE_OFDM)) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s, ", + HW_TX_RATE_BW[0]); + } else if (i > prHwWlanInfo->rWtblPeerCap + .ucChangeBWAfterRateN) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s, ", + prHwWlanInfo->rWtblPeerCap + .ucFrequencyCapability < + 4 ? + (prHwWlanInfo->rWtblPeerCap + .ucFrequencyCapability > + BW_20 ? + HW_TX_RATE_BW + [prHwWlanInfo + ->rWtblPeerCap + .ucFrequencyCapability - + 1] : + HW_TX_RATE_BW + [prHwWlanInfo + ->rWtblPeerCap + .ucFrequencyCapability]) : + HW_TX_RATE_BW[4]); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s, ", + prHwWlanInfo->rWtblPeerCap + .ucFrequencyCapability < + 4 ? + HW_TX_RATE_BW + [prHwWlanInfo + ->rWtblPeerCap + .ucFrequencyCapability] : + HW_TX_RATE_BW[4]); + } + } + + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", rate < 4 ? "LP" : "SP"); + } else if (txmode == TX_RATE_MODE_OFDM) { + ; + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s, ", + priv_driver_get_sgi_info( + &prHwWlanInfo->rWtblPeerCap) == 0 ? + "LGI" : + "SGI"); + } + + if (prQueryStaStatistics->ucSkipAr) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s%s%s\n", + txmode < 5 ? HW_TX_MODE_STR[txmode] : + HW_TX_MODE_STR[5], + stbc ? ", STBC, " : ", ", + priv_driver_get_ldpc_info( + &prHwWlanInfo->rWtblTxConfig) == 0 ? + "BCC" : + "LDPC"); + } else if (prQueryStaStatistics->aucArRatePer + [prQueryStaStatistics->aucRateEntryIndex[i]] == + 0xFF) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s%s%s (--)\n", + txmode < 5 ? HW_TX_MODE_STR[txmode] : + HW_TX_MODE_STR[5], + stbc ? ", STBC, " : ", ", + ((priv_driver_get_ldpc_info( + &prHwWlanInfo->rWtblTxConfig) == 0) || + (txmode == TX_RATE_MODE_CCK) || + (txmode == TX_RATE_MODE_OFDM)) ? + "BCC" : + "LDPC"); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s%s%s (%d)\n", + txmode < 5 ? HW_TX_MODE_STR[txmode] : + HW_TX_MODE_STR[5], + stbc ? ", STBC, " : ", ", + ((priv_driver_get_ldpc_info( + &prHwWlanInfo->rWtblTxConfig) == 0) || + (txmode == TX_RATE_MODE_CCK) || + (txmode == TX_RATE_MODE_OFDM)) ? + "BCC" : + "LDPC", + prQueryStaStatistics->aucArRatePer + [prQueryStaStatistics + ->aucRateEntryIndex[i]]); + } + + if (!fgDumpAll) { + break; + } + } + + return i4BytesWritten; +} + +s32 priv_driver_last_rx_rssi(P_ADAPTER_T prAdapter, IN char *pcCommand, + IN int i4TotalLen, IN u8 ucWlanIdx) +{ + s32 i4RSSI0 = 0, i4RSSI1 = 0, i4RSSI2 = 0, i4RSSI3; + s32 i4BytesWritten = 0; + u32 u4RxVector3 = 0; + u8 ucStaIdx; +#if CFG_SUPPORT_RSSI_COMP + P_BSS_INFO_T prBssInfo; +#endif + + if (wlanGetStaIdxByWlanIdx(prAdapter, ucWlanIdx, &ucStaIdx) == + WLAN_STATUS_SUCCESS) { + u4RxVector3 = prAdapter->arStaRec[ucStaIdx].u4RxVector3; + DBGLOG(REQ, LOUD, "****** RX Vector3 = 0x%08x ******\n", + u4RxVector3); + } else { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s", "Last RX RSSI", + " = NOT SUPPORT"); + return i4BytesWritten; + } + + i4RSSI0 = RCPI_TO_dBm((u4RxVector3 & RX_VT_RCPI0_MASK) >> + RX_VT_RCPI0_OFFSET); + i4RSSI1 = RCPI_TO_dBm((u4RxVector3 & RX_VT_RCPI1_MASK) >> + RX_VT_RCPI1_OFFSET); + +#if CFG_SUPPORT_RSSI_COMP + prBssInfo = GET_BSS_INFO_BY_INDEX( + prAdapter, prAdapter->arStaRec[ucStaIdx].ucBssIndex); + if (prBssInfo->eBand == BAND_2G4) { + i4RSSI0 += prAdapter->rWifiVar.rRssiPathCompasation + .c2GRssiCompensation; + i4RSSI1 += prAdapter->rWifiVar.rRssiPathCompasation + .c2GRssiCompensation; + } else { + i4RSSI0 += prAdapter->rWifiVar.rRssiPathCompasation + .c5GRssiCompensation; + i4RSSI1 += prAdapter->rWifiVar.rRssiPathCompasation + .c5GRssiCompensation; + } +#endif + if (prAdapter->rWifiVar.ucNSS > 2) { + i4RSSI2 = RCPI_TO_dBm((u4RxVector3 & RX_VT_RCPI2_MASK) >> + RX_VT_RCPI2_OFFSET); + i4RSSI3 = RCPI_TO_dBm((u4RxVector3 & RX_VT_RCPI3_MASK) >> + RX_VT_RCPI3_OFFSET); +#if CFG_SUPPORT_RSSI_COMP + if (prBssInfo->eBand == BAND_2G4) { + i4RSSI2 += prAdapter->rWifiVar.rRssiPathCompasation + .c2GRssiCompensation; + i4RSSI3 += prAdapter->rWifiVar.rRssiPathCompasation + .c2GRssiCompensation; + } else { + i4RSSI2 += prAdapter->rWifiVar.rRssiPathCompasation + .c5GRssiCompensation; + i4RSSI3 += prAdapter->rWifiVar.rRssiPathCompasation + .c5GRssiCompensation; + } +#endif + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%d %d %d %d\n", "Last RX Data RSSI", " = ", + i4RSSI0, i4RSSI1, i4RSSI2, i4RSSI3); + } else { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d %d\n", + "Last RX Data RSSI", " = ", + i4RSSI0, i4RSSI1); + } + + return i4BytesWritten; +} + +s32 priv_driver_rx_rate_info(P_ADAPTER_T prAdapter, IN char *pcCommand, + IN int i4TotalLen, IN u8 ucWlanIdx) +{ + u32 txmode, rate, frmode, sgi, nsts, ldpc, stbc, groupid, mu; + s32 i4BytesWritten = 0; + u32 u4RxVector0 = 0, u4RxVector1 = 0; + u8 ucStaIdx; + + if (wlanGetStaIdxByWlanIdx(prAdapter, ucWlanIdx, &ucStaIdx) == + WLAN_STATUS_SUCCESS) { + u4RxVector0 = prAdapter->arStaRec[ucStaIdx].u4RxVector0; + u4RxVector1 = prAdapter->arStaRec[ucStaIdx].u4RxVector1; + DBGLOG(REQ, LOUD, "****** RX Vector0 = 0x%08x ******\n", + u4RxVector0); + DBGLOG(REQ, LOUD, "****** RX Vector1 = 0x%08x ******\n", + u4RxVector1); + } else { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s", "Last RX Rate", + " = NOT SUPPORT"); + return i4BytesWritten; + } + + txmode = (u4RxVector0 & RX_VT_RX_MODE_MASK) >> RX_VT_RX_MODE_OFFSET; + rate = (u4RxVector0 & RX_VT_RX_RATE_MASK) >> RX_VT_RX_RATE_OFFSET; + frmode = (u4RxVector0 & RX_VT_FR_MODE_MASK) >> RX_VT_FR_MODE_OFFSET; + nsts = ((u4RxVector1 & RX_VT_NSTS_MASK) >> RX_VT_NSTS_OFFSET); + stbc = (u4RxVector0 & RX_VT_STBC_MASK) >> RX_VT_STBC_OFFSET; + sgi = u4RxVector0 & RX_VT_SHORT_GI; + ldpc = u4RxVector0 & RX_VT_LDPC; + groupid = (u4RxVector1 & RX_VT_GROUP_ID_MASK) >> RX_VT_GROUP_ID_OFFSET; + + if (groupid && groupid != 63) { + mu = 1; + } else { + mu = 0; + nsts += 1; + } + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%-20s%s", + "Last RX Rate", " = "); + + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s, ", + rate < 4 ? HW_TX_RATE_CCK_STR[rate] : + HW_TX_RATE_CCK_STR[4]); + } else if (txmode == TX_RATE_MODE_OFDM) { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", hw_rate_ofdm_str(rate)); + } else if ((txmode == TX_RATE_MODE_HTMIX) || + (txmode == TX_RATE_MODE_HTGF)) { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "MCS%d, ", rate); + } else { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "NSS%d_MCS%d, ", nsts, rate); + } + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, "%s, ", + frmode < 4 ? HW_TX_RATE_BW[frmode] : HW_TX_RATE_BW[4]); + + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", rate < 4 ? "LP" : "SP"); + } else if (txmode == TX_RATE_MODE_OFDM) { + ; + } else { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s,", sgi == 0 ? "LGI" : "SGI"); + } + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", + stbc == 0 ? " " : " STBC, "); + + if (mu) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s, %s, %s (%d)\n", + txmode < 5 ? HW_TX_MODE_STR[txmode] : HW_TX_MODE_STR[5], + ldpc == 0 ? "BCC" : "LDPC", "MU", groupid); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s, %s\n", + txmode < 5 ? HW_TX_MODE_STR[txmode] : HW_TX_MODE_STR[5], + ldpc == 0 ? "BCC" : "LDPC"); + } + + return i4BytesWritten; +} + +s32 priv_driver_tx_vector_info(IN char *pcCommand, IN int i4TotalLen, + IN P_TX_VECTOR_BBP_LATCH_T prTxV) +{ + u8 rate, txmode, frmode, sgi, ldpc, nsts, stbc, txpwr; + s32 i4BytesWritten = 0; + + rate = TX_VECTOR_GET_TX_RATE(prTxV); + txmode = TX_VECTOR_GET_TX_MODE(prTxV); + frmode = TX_VECTOR_GET_TX_FRMODE(prTxV); + nsts = TX_VECTOR_GET_TX_NSTS(prTxV) + 1; + sgi = TX_VECTOR_GET_TX_SGI(prTxV); + ldpc = TX_VECTOR_GET_TX_LDPC(prTxV); + stbc = TX_VECTOR_GET_TX_STBC(prTxV); + txpwr = TX_VECTOR_GET_TX_PWR(prTxV); + + if (prTxV->u4TxVector1 == 0xFFFFFFFF) { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", "Last TX Rate", + " = ", "N/A"); + } else { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s", "Last TX Rate", + " = "); + + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s, ", + rate < 4 ? HW_TX_RATE_CCK_STR[rate] : + HW_TX_RATE_CCK_STR[4]); + } else if (txmode == TX_RATE_MODE_OFDM) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", hw_rate_ofdm_str(rate)); + } else if ((txmode == TX_RATE_MODE_HTMIX) || + (txmode == TX_RATE_MODE_HTGF)) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "MCS%d, ", rate); + } else { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "NSS%d_MCS%d, ", nsts, rate); + } + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s, ", + frmode < 4 ? HW_TX_RATE_BW[frmode] : HW_TX_RATE_BW[4]); + + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", rate < 4 ? "LP" : "SP"); + } else if (txmode == TX_RATE_MODE_OFDM) { + ; + } else { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s, ", sgi == 0 ? "LGI" : "SGI"); + } + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s%s%s\n", + txmode < 5 ? HW_TX_MODE_STR[txmode] : HW_TX_MODE_STR[5], + stbc ? ", STBC, " : ", ", ldpc == 0 ? "BCC" : "LDPC"); + } + + return i4BytesWritten; +} + +static s32 +priv_driver_dump_stat_info(P_ADAPTER_T prAdapter, IN char *pcCommand, + IN int i4TotalLen, + P_PARAM_HW_WLAN_INFO_T prHwWlanInfo, + P_PARAM_GET_STA_STATISTICS prQueryStaStatistics, + u8 fgResetCnt, u32 u4StatGroup) +{ + s32 i4BytesWritten = 0; + PARAM_RSSI rRssi = 0; + u16 u2LinkSpeed; + u32 u4Per, u4RxPer[ENUM_BAND_NUM], u4AmpduPer[ENUM_BAND_NUM], + u4InstantPer; + u8 ucDbdcIdx, ucStaIdx, ucNss; + u8 ucSkipAr; + static u32 u4TotalTxCnt, u4TotalFailCnt; + static u32 u4Rate1TxCnt, u4Rate1FailCnt; + static u32 au4RxMpduCnt[ENUM_BAND_NUM] = { 0 }; + static u32 au4FcsError[ENUM_BAND_NUM] = { 0 }; + static u32 au4RxFifoCnt[ENUM_BAND_NUM] = { 0 }; + static u32 au4AmpduTxSfCnt[ENUM_BAND_NUM] = { 0 }; + static u32 au4AmpduTxAckSfCnt[ENUM_BAND_NUM] = { 0 }; + extern u32 g_au4RxMpduCnt[ENUM_BAND_NUM]; + extern u32 g_au4FcsError[ENUM_BAND_NUM]; + extern u32 g_au4RxFifoCnt[ENUM_BAND_NUM]; + extern u32 g_au4AmpduTxSfCnt[ENUM_BAND_NUM]; + extern u32 g_au4AmpduTxAckSfCnt[ENUM_BAND_NUM]; + P_RX_CTRL_T prRxCtrl; + u32 u4InstantRxPer[ENUM_BAND_NUM]; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + s16 i2Wf0AvgPwr; + s16 i2Wf1AvgPwr; + u32 u4BufLen = 0; + + ucSkipAr = prQueryStaStatistics->ucSkipAr; + prRxCtrl = &prAdapter->rRxCtrl; + ucNss = prAdapter->rWifiVar.ucNSS; + + if (ucSkipAr) { + u4TotalTxCnt += prHwWlanInfo->rWtblTxCounter.u2CurBwTxCnt + + prHwWlanInfo->rWtblTxCounter.u2OtherBwTxCnt; + u4TotalFailCnt += prHwWlanInfo->rWtblTxCounter.u2CurBwFailCnt + + prHwWlanInfo->rWtblTxCounter.u2OtherBwFailCnt; + u4Rate1TxCnt += prHwWlanInfo->rWtblTxCounter.u2Rate1TxCnt; + u4Rate1FailCnt += prHwWlanInfo->rWtblTxCounter.u2Rate1FailCnt; + } + + if (ucSkipAr) { + u4Per = (prHwWlanInfo->rWtblTxCounter.u2Rate1TxCnt == 0) ? + (0) : + (1000 * u4Rate1FailCnt / u4Rate1TxCnt); + + u4InstantPer = + (prHwWlanInfo->rWtblTxCounter.u2Rate1TxCnt == 0) ? + (0) : + (1000 * + (prHwWlanInfo->rWtblTxCounter.u2Rate1FailCnt) / + (prHwWlanInfo->rWtblTxCounter.u2Rate1TxCnt)); + } else { + u4Per = (prQueryStaStatistics->u4Rate1TxCnt == 0) ? + (0) : + (1000 * (prQueryStaStatistics->u4Rate1FailCnt) / + (prQueryStaStatistics->u4Rate1TxCnt)); + + u4InstantPer = (prQueryStaStatistics->ucPer == 0) ? + (0) : + (prQueryStaStatistics->ucPer); + } + + for (ucDbdcIdx = 0; ucDbdcIdx < ENUM_BAND_NUM; ucDbdcIdx++) { + au4RxMpduCnt[ucDbdcIdx] += g_au4RxMpduCnt[ucDbdcIdx]; + au4FcsError[ucDbdcIdx] += g_au4FcsError[ucDbdcIdx]; + au4RxFifoCnt[ucDbdcIdx] += g_au4RxFifoCnt[ucDbdcIdx]; + au4AmpduTxSfCnt[ucDbdcIdx] += g_au4AmpduTxSfCnt[ucDbdcIdx]; + au4AmpduTxAckSfCnt[ucDbdcIdx] += + g_au4AmpduTxAckSfCnt[ucDbdcIdx]; + g_au4RxMpduCnt[ucDbdcIdx] = 0; + g_au4FcsError[ucDbdcIdx] = 0; + g_au4RxFifoCnt[ucDbdcIdx] = 0; + g_au4AmpduTxSfCnt[ucDbdcIdx] = 0; + g_au4AmpduTxAckSfCnt[ucDbdcIdx] = 0; + + u4RxPer[ucDbdcIdx] = ((au4RxMpduCnt[ucDbdcIdx] + + au4FcsError[ucDbdcIdx]) == 0) ? + (0) : + (1000 * au4FcsError[ucDbdcIdx] / + (au4RxMpduCnt[ucDbdcIdx] + + au4FcsError[ucDbdcIdx])); + + u4AmpduPer[ucDbdcIdx] = + (au4AmpduTxSfCnt[ucDbdcIdx] == 0) ? + (0) : + (1000 * + (au4AmpduTxSfCnt[ucDbdcIdx] - + au4AmpduTxAckSfCnt[ucDbdcIdx]) / + au4AmpduTxSfCnt[ucDbdcIdx]); + + u4InstantRxPer[ucDbdcIdx] = + ((prQueryStaStatistics->rMibInfo[ucDbdcIdx].u4RxMpduCnt + + + prQueryStaStatistics->rMibInfo[ucDbdcIdx] + .u4FcsError) == 0) ? + (0) : + (1000 * + prQueryStaStatistics->rMibInfo[ucDbdcIdx] + .u4FcsError / + (prQueryStaStatistics->rMibInfo[ucDbdcIdx] + .u4RxMpduCnt + + prQueryStaStatistics->rMibInfo[ucDbdcIdx] + .u4FcsError)); + } + + /* get Beacon RSSI */ + rStatus = kalIoctl(prAdapter->prGlueInfo, wlanoidQueryRssi, &rRssi, + sizeof(rRssi), true, false, false, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, WARN, "unable to retrieve rssi\n"); + } + + u2LinkSpeed = (prQueryStaStatistics->u2LinkSpeed == 0) ? + 0 : + prQueryStaStatistics->u2LinkSpeed / 2; + + /* =========== Group 0x0001 =========== */ + if (u4StatGroup & 0x0001) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s", "\n----- STA Stat (Group 0x01) -----\n"); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "CurrTemperature", " = ", + prQueryStaStatistics->ucTemperature); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Tx Total cnt", " = ", + ucSkipAr ? (u4TotalTxCnt) : + (prQueryStaStatistics->u4TransmitCount)); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Tx Fail Cnt", " = ", + ucSkipAr ? (u4TotalFailCnt) : + (prQueryStaStatistics->u4TransmitFailCount)); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Rate1 Tx Cnt", " = ", + ucSkipAr ? (u4Rate1TxCnt) : + (prQueryStaStatistics->u4Rate1TxCnt)); + + if (ucSkipAr) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d, PER = %d.%1d%%, instant PER = %d.%1d%%\n", + "Rate1 Fail Cnt", + " = ", + u4Rate1FailCnt, + u4Per / 10, + u4Per % 10, + u4InstantPer / 10, + u4InstantPer % 10); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d, PER = %d.%1d%%, instant PER = %d%%\n", + "Rate1 Fail Cnt", + " = ", + prQueryStaStatistics->u4Rate1FailCnt, + u4Per / 10, + u4Per % 10, + u4InstantPer); + } + + if ((ucSkipAr) && (fgResetCnt)) { + u4TotalTxCnt = 0; + u4TotalFailCnt = 0; + u4Rate1TxCnt = 0; + u4Rate1FailCnt = 0; + } + } + + /* =========== Group 0x0002 =========== */ + if (u4StatGroup & 0x0002) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s", "----- MIB Info (Group 0x02) -----\n"); + +#if CFG_SUPPORT_DBDC + if (!prAdapter->rWifiVar.fgDbDcModeEn) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%-20s%s%d\n", + "RX Success", " = ", au4RxMpduCnt[ENUM_BAND_0]); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d, PER = %d.%1d%%, instant PER = %d.%1d%%\n", + "RX with CRC", + " = ", + au4FcsError[ENUM_BAND_0], + u4RxPer[ENUM_BAND_0] / 10, + u4RxPer[ENUM_BAND_0] % 10, + u4InstantRxPer[ENUM_BAND_0] / 10, + u4InstantRxPer[ENUM_BAND_0] % 10); + + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "RX drop FIFO full", + " = ", au4RxFifoCnt[ENUM_BAND_0]); + } else { +#endif + for (ucDbdcIdx = 0; ucDbdcIdx < ENUM_BAND_NUM; + ucDbdcIdx++) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "[DBDC_%d] :\n", ucDbdcIdx); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "RX Success", " = ", + au4RxMpduCnt[ucDbdcIdx]); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d, PER = %d.%1d%%, instant PER = %d.%1d%%\n", + "RX with CRC", + " = ", + au4FcsError[ucDbdcIdx], + u4RxPer[ucDbdcIdx] / 10, + u4RxPer[ucDbdcIdx] % 10, + u4InstantRxPer[ucDbdcIdx] / 10, + u4InstantRxPer[ucDbdcIdx] % 10); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "RX drop FIFO full", + " = ", au4RxFifoCnt[ucDbdcIdx]); + } +#if CFG_SUPPORT_DBDC + } +#endif + + if (fgResetCnt) { + kalMemZero(au4RxMpduCnt, sizeof(au4RxMpduCnt)); + kalMemZero(au4FcsError, sizeof(au4RxMpduCnt)); + kalMemZero(au4RxFifoCnt, sizeof(au4RxMpduCnt)); + kalMemZero(au4AmpduTxSfCnt, sizeof(au4RxMpduCnt)); + kalMemZero(au4AmpduTxAckSfCnt, sizeof(au4RxMpduCnt)); + } + } + + /* =========== Group 0x0004 =========== */ + if (u4StatGroup & 0x0004) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s", "----- Last Rx Info (Group 0x04) -----\n"); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = CMD_SW_DBGCTL_ADVCTL_GET_ID + 1; + + rStatus = kalIoctl(prAdapter->prGlueInfo, + wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, + &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u, rSwCtrlInfo.u4Data 0x%x\n", + rStatus, rSwCtrlInfo.u4Data); + if (rStatus == WLAN_STATUS_SUCCESS) { + i2Wf0AvgPwr = rSwCtrlInfo.u4Data & 0xFFFF; + i2Wf1AvgPwr = (rSwCtrlInfo.u4Data >> 16) & 0xFFFF; + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%-20s%s%d %d\n", + "NOISE", " = ", i2Wf0AvgPwr, i2Wf1AvgPwr); + } + + /* Last RX Rate */ + i4BytesWritten += priv_driver_rx_rate_info( + prAdapter, pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + (u8)(prHwWlanInfo->u4Index)); + + /* Last RX RSSI */ + i4BytesWritten += priv_driver_last_rx_rssi( + prAdapter, pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + (u8)(prHwWlanInfo->u4Index)); + + /* Last RX Resp RSSI */ + if (ucNss > 2) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d %d %d %d\n", "Tx Response RSSI", + " = ", + RCPI_TO_dBm( + prHwWlanInfo->rWtblRxCounter.ucRxRcpi0), + RCPI_TO_dBm( + prHwWlanInfo->rWtblRxCounter.ucRxRcpi1), + RCPI_TO_dBm( + prHwWlanInfo->rWtblRxCounter.ucRxRcpi2), + RCPI_TO_dBm( + prHwWlanInfo->rWtblRxCounter.ucRxRcpi3)); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%-20s%s%d %d\n", + "Tx Response RSSI", " = ", + RCPI_TO_dBm( + prHwWlanInfo->rWtblRxCounter.ucRxRcpi0), + RCPI_TO_dBm( + prHwWlanInfo->rWtblRxCounter.ucRxRcpi1)); + } + + /* Last Beacon RSSI */ + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Beacon RSSI", + " = ", rRssi); + } + + /* =========== Group 0x0008 =========== */ + if (u4StatGroup & 0x0008) { + /* TxV */ + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s", "----- Last TX Info (Group 0x08) -----\n"); + +#if CFG_SUPPORT_DBDC + if (!prAdapter->rWifiVar.fgDbDcModeEn) { + i4BytesWritten += priv_driver_tx_vector_info( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + &prQueryStaStatistics->rTxVector[ENUM_BAND_0]); + + if (prQueryStaStatistics->rTxVector[ENUM_BAND_0] + .u4TxVector1 == 0xFFFFFFFF) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", "Chip Out TX Power", + " = ", "N/A"); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%ld.%1ld dBm\n", + "Chip Out TX Power", " = ", + TX_VECTOR_GET_TX_PWR( + &prQueryStaStatistics->rTxVector + [ENUM_BAND_0]) >> + 1, + 5 * (TX_VECTOR_GET_TX_PWR( + &prQueryStaStatistics-> + rTxVector + [ENUM_BAND_0]) % + 2)); + } + } else { +#endif + for (ucDbdcIdx = 0; ucDbdcIdx < ENUM_BAND_NUM; + ucDbdcIdx++) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "[DBDC_%d] :\n", ucDbdcIdx); + + i4BytesWritten += priv_driver_tx_vector_info( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + &prQueryStaStatistics + ->rTxVector[ucDbdcIdx]); + + if (prQueryStaStatistics->rTxVector[ucDbdcIdx] + .u4TxVector1 == 0xFFFFFFFF) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", + "Chip Out TX Power", " = ", + "N/A"); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%ld.%1ld dBm\n", + "ChipOut TX Power", " = ", + TX_VECTOR_GET_TX_PWR( + &prQueryStaStatistics-> + rTxVector + [ucDbdcIdx]) >> + 1, + 5 * (TX_VECTOR_GET_TX_PWR( + & + prQueryStaStatistics + ->rTxVector + [ucDbdcIdx]) % + 2)); + } + } +#if CFG_SUPPORT_DBDC + } +#endif + } + + /* =========== Group 0x0010 =========== */ + if (u4StatGroup & 0x0010) { + /* RX Reorder */ + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s", "------ RX Reorder (Group 0x10) -----\n"); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%llu\n", "Rx reorder miss", " = ", + RX_GET_CNT(prRxCtrl, RX_DATA_REORDER_MISS_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%llu\n", "Rx reorder within", " = ", + RX_GET_CNT(prRxCtrl, RX_DATA_REORDER_WITHIN_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%llu\n", "Rx reorder ahead", " = ", + RX_GET_CNT(prRxCtrl, RX_DATA_REORDER_AHEAD_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%llu\n", "Rx reorder behind", " = ", + RX_GET_CNT(prRxCtrl, RX_DATA_REORDER_BEHIND_COUNT)); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%llu\n", "Rx reorder behind continuous", " = ", + RX_GET_CNT(prRxCtrl, + RX_DATA_REORDER_BEHIND_CONTINUOUS_COUNT)); + } + + /* =========== Group 0x0020 =========== */ + if (u4StatGroup & 0x0020) { + /* AR info */ + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s", "------ AR Info (Group 0x20) -----\n"); + + /* Last TX Rate */ + i4BytesWritten += priv_driver_tx_rate_info( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + false, prHwWlanInfo, prQueryStaStatistics); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "LinkSpeed", + " = ", u2LinkSpeed); + + if (!prQueryStaStatistics->ucSkipAr) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%-20s%s%s\n", + "RateTable", " = ", + prQueryStaStatistics->ucArTableIdx < + RATE_TBL_MAX ? + RATE_TBLE[prQueryStaStatistics + ->ucArTableIdx] : + RATE_TBLE[RATE_TBL_MAX]); + + if (wlanGetStaIdxByWlanIdx( + prAdapter, (u8)(prHwWlanInfo->u4Index), + &ucStaIdx) == WLAN_STATUS_SUCCESS) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "2G Support 256QAM TX", + " = ", + (prAdapter->arStaRec[ucStaIdx].u4Flags & + MTK_SYNERGY_CAP_SUPPORT_24G_MCS89) ? + 1 : + 0); + } + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%-20s%s%d%%\n", + "Rate1 instantPer", " = ", u4InstantPer); + + if (prQueryStaStatistics->ucAvePer == 0xFF) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", "Train Down", " = ", + "N/A"); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", "Train Up", " = ", + "N/A"); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d -> %d\n", "Train Down", + " = ", + (prQueryStaStatistics->u2TrainDown) & + BITS(0, 7), + ((prQueryStaStatistics->u2TrainDown) >> + 8) & BITS(0, 7)); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d -> %d\n", "Train Up", " = ", + (prQueryStaStatistics->u2TrainUp) & + BITS(0, 7), + ((prQueryStaStatistics->u2TrainUp) >> + 8) & BITS(0, 7)); + } + + if (prQueryStaStatistics->fgIsForceTxStream == 0) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", "Force Tx Stream", " = ", + "N/A"); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Force Tx Stream", " = ", + prQueryStaStatistics->fgIsForceTxStream); + } + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%-20s%s%d\n", + "Force SE off", " = ", + prQueryStaStatistics->fgIsForceSeOff); + } + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "CBRN", " = ", + prHwWlanInfo->rWtblPeerCap.ucChangeBWAfterRateN); + + /* Rate1~Rate8 */ + i4BytesWritten += priv_driver_tx_rate_info( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + true, prHwWlanInfo, prQueryStaStatistics); + } + + /* =========== Group 0x0040 =========== */ + if (u4StatGroup & 0x0040) { + /* Tx Agg */ + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s", "------ TX AGG (Group 0x40) -----\n"); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-12s%s", + "Range:", "1 2~5 6~15 16~22 23~33 34~49 50~57 58~64\n"); + + for (ucDbdcIdx = 0; ucDbdcIdx < ENUM_BAND_NUM; ucDbdcIdx++) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "DBDC%d:", ucDbdcIdx); + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%7d%8d%9d%9d%9d%9d%9d%9d\n", + prQueryStaStatistics->rMibInfo[ucDbdcIdx] + .u2TxRange1AmpduCnt, + prQueryStaStatistics->rMibInfo[ucDbdcIdx] + .u2TxRange2AmpduCnt, + prQueryStaStatistics->rMibInfo[ucDbdcIdx] + .u2TxRange3AmpduCnt, + prQueryStaStatistics->rMibInfo[ucDbdcIdx] + .u2TxRange4AmpduCnt, + prQueryStaStatistics->rMibInfo[ucDbdcIdx] + .u2TxRange5AmpduCnt, + prQueryStaStatistics->rMibInfo[ucDbdcIdx] + .u2TxRange6AmpduCnt, + prQueryStaStatistics->rMibInfo[ucDbdcIdx] + .u2TxRange7AmpduCnt, + prQueryStaStatistics->rMibInfo[ucDbdcIdx] + .u2TxRange8AmpduCnt); + } + } + + return i4BytesWritten; +} + +static int priv_driver_get_sta_stat(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0, u4Ret, u4StatGroup = 0xFFFFFFFF; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u8 aucMacAddr[MAC_ADDR_LEN]; + u8 ucWlanIndex; + u8 *pucMacAddr = NULL; + P_PARAM_HW_WLAN_INFO_T prHwWlanInfo = NULL; + P_PARAM_GET_STA_STATISTICS prQueryStaStatistics = NULL; + u8 fgResetCnt = false; + u8 fgRxCCSel = false; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= 3) { + if (strnicmp(apcArgv[1], CMD_STAT_GROUP_SEL, + strlen(CMD_STAT_GROUP_SEL)) == 0) { + u4Ret = kalkStrtou32(apcArgv[2], 0, &(u4StatGroup)); + if (u4Ret) { + DBGLOG(REQ, + LOUD, + "parse get_mcr error (Address) u4Ret=%d\n", + u4Ret); + return -1; + } + + if (u4StatGroup == 0) { + u4StatGroup = 0xFFFFFFFF; + } + + if (prGlueInfo->prAdapter->prAisBssInfo->prStaRecOfAP) { + ucWlanIndex = + prGlueInfo->prAdapter->prAisBssInfo + ->prStaRecOfAP->ucWlanIndex; + } else if (!wlanGetWlanIdxByAddress( + prGlueInfo->prAdapter, NULL, + &ucWlanIndex)) { + DBGLOG(REQ, + INFO, + "Can't find the wlan index of MAC addr %pM!\n", + aucMacAddr); + goto out; + } + } else { + if (strnicmp(apcArgv[1], CMD_STAT_RESET_CNT, + strlen(CMD_STAT_RESET_CNT)) == 0) { + if (wlanHwAddrToBin(apcArgv[2], + &aucMacAddr[0]) < 0) { + DBGLOG(REQ, + WARN, + "%s: MAC addr Argv[2] convert failed\n", + __func__); + return -1; + } + fgResetCnt = true; + } else if (strnicmp(apcArgv[2], CMD_STAT_RESET_CNT, + strlen(CMD_STAT_RESET_CNT)) == 0) { + if (wlanHwAddrToBin(apcArgv[1], + &aucMacAddr[0]) < 0) { + DBGLOG(REQ, + WARN, + "%s: MAC addr Argv[1] convert failed\n", + __func__); + return -1; + } + fgResetCnt = true; + } else { + if (wlanHwAddrToBin(apcArgv[1], + &aucMacAddr[0]) < 0) { + DBGLOG(REQ, + WARN, + "%s: MAC addr Argv[1] convert failed\n", + __func__); + return -1; + } + fgResetCnt = false; + } + + if (!wlanGetWlanIdxByAddress(prGlueInfo->prAdapter, + &aucMacAddr[0], + &ucWlanIndex)) { + DBGLOG(REQ, + INFO, + "Can't find the wlan index of MAC addr %pM!\n", + aucMacAddr); + goto out; + } + } + } else { + /* Get AIS AP address for no argument */ + if (prGlueInfo->prAdapter->prAisBssInfo->prStaRecOfAP) { + ucWlanIndex = prGlueInfo->prAdapter->prAisBssInfo + ->prStaRecOfAP->ucWlanIndex; + } else if (!wlanGetWlanIdxByAddress(prGlueInfo->prAdapter, NULL, + &ucWlanIndex)) { + DBGLOG(REQ, INFO, "No connected peer found!\n"); + goto out; + } + + if (i4Argc == 2) { + if (strnicmp(apcArgv[1], CMD_STAT_RESET_CNT, + strlen(CMD_STAT_RESET_CNT)) == 0) { + fgResetCnt = true; + }else if (strnicmp(apcArgv[1], CMD_STAT_NOISE_SEL, + strlen(CMD_STAT_NOISE_SEL)) == 0) { + fgRxCCSel = true; + } + } + } + + prHwWlanInfo = (P_PARAM_HW_WLAN_INFO_T)kalMemAlloc( + sizeof(PARAM_HW_WLAN_INFO_T), VIR_MEM_TYPE); + if (!prHwWlanInfo) { + DBGLOG(REQ, ERROR, + "Allocate memory for prHwWlanInfo failed!\n"); + i4BytesWritten = -1; + goto out; + } + kalMemZero(prHwWlanInfo, sizeof(PARAM_HW_WLAN_INFO_T)); + + prHwWlanInfo->u4Index = ucWlanIndex; + if (fgRxCCSel == true) { + prHwWlanInfo->rWtblRxCounter.fgRxCCSel = true; + }else{ + prHwWlanInfo->rWtblRxCounter.fgRxCCSel = false; + } + + DBGLOG(REQ, INFO, "MT6632 : index = %d i4TotalLen = %d\n", + prHwWlanInfo->u4Index, i4TotalLen); + + /* Get WTBL info */ + rStatus = kalIoctl(prGlueInfo, wlanoidQueryWlanInfo, prHwWlanInfo, + sizeof(PARAM_HW_WLAN_INFO_T), true, true, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "Query prHwWlanInfo failed!\n"); + i4BytesWritten = -1; + goto out; + } + + /* Get Statistics info */ + prQueryStaStatistics = (P_PARAM_GET_STA_STATISTICS)kalMemAlloc( + sizeof(PARAM_GET_STA_STATISTICS), VIR_MEM_TYPE); + if (!prQueryStaStatistics) { + DBGLOG(REQ, ERROR, + "Allocate memory for prQueryStaStatistics failed!\n"); + i4BytesWritten = -1; + goto out; + } + + prQueryStaStatistics->ucResetCounter = fgResetCnt; + + pucMacAddr = + wlanGetStaAddrByWlanIdx(prGlueInfo->prAdapter, ucWlanIndex); + + if (!pucMacAddr) { + DBGLOG(REQ, ERROR, + "Couldn't find the MAC addr of WlanIndex %d!\n", + ucWlanIndex); + i4BytesWritten = -1; + goto out; + } + + COPY_MAC_ADDR(prQueryStaStatistics->aucMacAddr, pucMacAddr); + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryStaStatistics, + prQueryStaStatistics, + sizeof(PARAM_GET_STA_STATISTICS), true, true, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "Query prQueryStaStatistics failed!\n"); + i4BytesWritten = -1; + goto out; + } + + if (pucMacAddr) { + i4BytesWritten = priv_driver_dump_stat_info( + prAdapter, pcCommand, i4TotalLen, prHwWlanInfo, + prQueryStaStatistics, fgResetCnt, u4StatGroup); + } + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand); + +out: + if (prHwWlanInfo) { + kalMemFree(prHwWlanInfo, VIR_MEM_TYPE, + sizeof(PARAM_HW_WLAN_INFO_T)); + } + + if (prQueryStaStatistics) { + kalMemFree(prQueryStaStatistics, VIR_MEM_TYPE, + sizeof(PARAM_GET_STA_STATISTICS)); + } + + if (fgResetCnt) { + nicRxClearStatistics(prGlueInfo->prAdapter); + } + + return i4BytesWritten; +} + +static s32 +priv_driver_dump_stat2_info(P_ADAPTER_T prAdapter, IN char *pcCommand, + IN int i4TotalLen, + P_UMAC_STAT2_GET_T prUmacStat2GetInfo, + P_PARAM_GET_DRV_STATISTICS prQueryDrvStatistics) +{ + s32 i4BytesWritten = 0; + u16 u2PleTotalRevPage = 0; + u16 u2PleTotalSrcPage = 0; + u16 u2PseTotalRevPage = 0; + u16 u2PseTotalSrcPage = 0; + + u2PleTotalRevPage = prUmacStat2GetInfo->u2PleRevPgHif0Group0 + + prUmacStat2GetInfo->u2PleRevPgCpuGroup2; + + u2PleTotalSrcPage = prUmacStat2GetInfo->u2PleSrvPgHif0Group0 + + prUmacStat2GetInfo->u2PleSrvPgCpuGroup2; + + u2PseTotalRevPage = prUmacStat2GetInfo->u2PseRevPgHif0Group0 + + prUmacStat2GetInfo->u2PseRevPgHif1Group1 + + prUmacStat2GetInfo->u2PseRevPgCpuGroup2 + + prUmacStat2GetInfo->u2PseRevPgLmac0Group3 + + prUmacStat2GetInfo->u2PseRevPgLmac1Group4 + + prUmacStat2GetInfo->u2PseRevPgLmac2Group5 + + prUmacStat2GetInfo->u2PseRevPgPleGroup6; + + u2PseTotalSrcPage = prUmacStat2GetInfo->u2PseSrvPgHif0Group0 + + prUmacStat2GetInfo->u2PseSrvPgHif1Group1 + + prUmacStat2GetInfo->u2PseSrvPgCpuGroup2 + + prUmacStat2GetInfo->u2PseSrvPgLmac0Group3 + + prUmacStat2GetInfo->u2PseSrvPgLmac1Group4 + + prUmacStat2GetInfo->u2PseSrvPgLmac2Group5 + + prUmacStat2GetInfo->u2PseSrvPgPleGroup6; + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", + "\n----- Stat2 Info -----\n"); + + /* Rev Page number Info. */ + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, "%s", + "\n----- PLE Reservation Page Info. -----\n"); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Ple Hif0 Group0 RevPage", " = ", + prUmacStat2GetInfo->u2PleRevPgHif0Group0); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Ple Cpu Group2 RevPage", + " = ", + prUmacStat2GetInfo->u2PleRevPgCpuGroup2); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Ple Total RevPage", + " = ", u2PleTotalRevPage); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, "%s", + "\n----- PLE Source Page Info. ----------\n"); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Ple Hif0 Group0 SrcPage", " = ", + prUmacStat2GetInfo->u2PleSrvPgHif0Group0); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Ple Cpu Group2 SrcPage", + " = ", + prUmacStat2GetInfo->u2PleSrvPgCpuGroup2); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Ple Total SrcPage", + " = ", u2PleTotalSrcPage); + + /* umac MISC Info. */ + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, "%s", + "\n----- PLE Misc Info. -----------------\n"); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "ple Total Page Number", + " = ", + prUmacStat2GetInfo->u2PleTotalPageNum); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "ple Free Page Number", + " = ", + prUmacStat2GetInfo->u2PleFreePageNum); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "ple FFA Page Number", + " = ", prUmacStat2GetInfo->u2PleFfaNum); + + /* PSE Info. */ + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, "%s", + "\n----- PSE Reservation Page Info. -----\n"); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Hif0 Group0 RevPage", " = ", + prUmacStat2GetInfo->u2PseRevPgHif0Group0); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Hif1 Group1 RevPage", " = ", + prUmacStat2GetInfo->u2PseRevPgHif1Group1); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Cpu Group2 RevPage", + " = ", + prUmacStat2GetInfo->u2PseRevPgCpuGroup2); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Lmac0 Group3 RevPage", " = ", + prUmacStat2GetInfo->u2PseRevPgLmac0Group3); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Lmac1 Group4 RevPage", " = ", + prUmacStat2GetInfo->u2PseRevPgLmac1Group4); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Lmac2 Group5 RevPage", " = ", + prUmacStat2GetInfo->u2PseRevPgLmac2Group5); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Ple Group6 RevPage", + " = ", + prUmacStat2GetInfo->u2PseRevPgPleGroup6); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Total RevPage", + " = ", u2PseTotalRevPage); + + /* PSE Info. */ + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, "%s", + "\n----- PSE Source Page Info. ----------\n"); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Hif0 Group0 SrcPage", " = ", + prUmacStat2GetInfo->u2PseSrvPgHif0Group0); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Hif1 Group1 SrcPage", " = ", + prUmacStat2GetInfo->u2PseSrvPgHif1Group1); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Cpu Group2 SrcPage", + " = ", + prUmacStat2GetInfo->u2PseSrvPgCpuGroup2); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Lmac0 Group3 SrcPage", " = ", + prUmacStat2GetInfo->u2PseSrvPgLmac0Group3); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Lmac1 Group4 SrcPage", " = ", + prUmacStat2GetInfo->u2PseSrvPgLmac1Group4); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Lmac2 Group5 SrcPage", " = ", + prUmacStat2GetInfo->u2PseSrvPgLmac2Group5); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Ple Group6 SrcPage", + " = ", + prUmacStat2GetInfo->u2PseSrvPgPleGroup6); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pse Total SrcPage", + " = ", u2PseTotalSrcPage); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, "%s", + "\n----- PSE Misc Info. -----------------\n"); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "pse Total Page Number", + " = ", + prUmacStat2GetInfo->u2PseTotalPageNum); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "pse Free Page Number", + " = ", + prUmacStat2GetInfo->u2PseFreePageNum); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "pse FFA Page Number", + " = ", prUmacStat2GetInfo->u2PseFfaNum); + + /* driver info */ + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, "%s", + "\n\n----- DRV Stat -----------------------\n\n"); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pending Data", " = ", + prQueryDrvStatistics->i4TxPendingFrameNum); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Pending Sec", " = ", + prQueryDrvStatistics->i4TxPendingSecurityFrameNum); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Tx Pending For-pkt Number", " = ", + prQueryDrvStatistics->i4PendingFwdFrameCount); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", + "MsduInfo Available Number", " = ", + prQueryDrvStatistics->u4MsduNumElem); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "MgmtTxRing Pending Number", " = ", + prQueryDrvStatistics->u4TxMgmtTxringQueueNumElem); + + /* Driver Rx Info. */ + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Rx Free Sw Rfb Number", " = ", + prQueryDrvStatistics->u4RxFreeSwRfbMsduNumElem); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Rx Received Sw Rfb Number", " = ", + prQueryDrvStatistics->u4RxReceivedRfbNumElem); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-26s%s%d\n", "Rx Indicated Sw Rfb Number", " = ", + prQueryDrvStatistics->u4RxIndicatedNumElem); + + return i4BytesWritten; +} + +static int priv_driver_get_sta_stat2(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + s32 i4BytesWritten = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4ArgNum = 1; + P_UMAC_STAT2_GET_T prUmacStat2GetInfo = NULL; + P_PARAM_GET_DRV_STATISTICS prQueryDrvStatistics = NULL; + P_QUE_T prQueList, prTxMgmtTxRingQueList; + P_RX_CTRL_T prRxCtrl; + + KAL_SPIN_LOCK_DECLARATION(); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc < i4ArgNum) { + return -1; + } + + prQueList = &prAdapter->rTxCtrl.rFreeMsduInfoList; + + prTxMgmtTxRingQueList = &prAdapter->rTxCtrl.rTxMgmtTxingQueue; + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + /* to do for UMAC Dump */ + prUmacStat2GetInfo = (P_UMAC_STAT2_GET_T)kalMemAlloc( + sizeof(UMAC_STAT2_GET_T), VIR_MEM_TYPE); + if (!prUmacStat2GetInfo) { + DBGLOG(REQ, ERROR, + "allocate memory for prUmacStat2GetInfo failed\n"); + i4BytesWritten = -1; + goto out; + } + + halUmacInfoGetMiscStatus(prAdapter, prUmacStat2GetInfo); + + /* Get Driver stat info */ + prQueryDrvStatistics = (P_PARAM_GET_DRV_STATISTICS)kalMemAlloc( + sizeof(PARAM_GET_DRV_STATISTICS), VIR_MEM_TYPE); + if (!prQueryDrvStatistics) { + DBGLOG(REQ, ERROR, + "allocate memory for prQueryDrvStatistics failed\n"); + i4BytesWritten = -1; + goto out; + } + + prQueryDrvStatistics->i4TxPendingFrameNum = + (u32)GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingFrameNum); + prQueryDrvStatistics->i4TxPendingSecurityFrameNum = + (u32)GLUE_GET_REF_CNT(prGlueInfo->i4TxPendingSecurityFrameNum); + + prQueryDrvStatistics->i4PendingFwdFrameCount = + prAdapter->rTxCtrl.i4PendingFwdFrameCount; + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + prQueryDrvStatistics->u4MsduNumElem = prQueList->u4NumElem; + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + prQueryDrvStatistics->u4TxMgmtTxringQueueNumElem = + prTxMgmtTxRingQueList->u4NumElem; + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + prQueryDrvStatistics->u4RxFreeSwRfbMsduNumElem = + prRxCtrl->rFreeSwRfbList.u4NumElem; + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + prQueryDrvStatistics->u4RxReceivedRfbNumElem = + prRxCtrl->rReceivedRfbList.u4NumElem; + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + prQueryDrvStatistics->u4RxIndicatedNumElem = + prRxCtrl->rIndicatedRfbList.u4NumElem; + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + + i4BytesWritten = priv_driver_dump_stat2_info(prAdapter, pcCommand, + i4TotalLen, + prUmacStat2GetInfo, + prQueryDrvStatistics); + +out: + if (prUmacStat2GetInfo) { + kalMemFree(prUmacStat2GetInfo, VIR_MEM_TYPE, + sizeof(UMAC_STAT2_GET_T)); + } + if (prQueryDrvStatistics) { + kalMemFree(prQueryDrvStatistics, VIR_MEM_TYPE, + sizeof(PARAM_GET_DRV_STATISTICS)); + } + + return i4BytesWritten; +} + +static s32 priv_driver_dump_rx_stat_info(P_ADAPTER_T prAdapter, + IN char *pcCommand, IN int i4TotalLen, + IN u8 fgResetCnt) +{ + s32 i4BytesWritten = 0; + u32 u4RxVector0 = 0, u4RxVector2 = 0, u4RxVector3 = 0, u4RxVector4 = 0; + u8 ucStaIdx, ucWlanIndex, cbw; + u8 fgWlanIdxFound = true, fgSkipRxV = false; + u32 u4FAGCRssiWBR0, u4FAGCRssiIBR0; + u32 u4Value, u4Foe, foe_const; + static u32 au4MacMdrdy[ENUM_BAND_NUM] = { 0 }; + static u32 au4FcsError[ENUM_BAND_NUM] = { 0 }; + static u32 au4OutOfResource[ENUM_BAND_NUM] = { 0 }; + static u32 au4LengthMismatch[ENUM_BAND_NUM] = { 0 }; + + au4MacMdrdy[ENUM_BAND_0] += htonl(g_HqaRxStat.MAC_Mdrdy); + au4MacMdrdy[ENUM_BAND_1] += htonl(g_HqaRxStat.MAC_Mdrdy1); + au4FcsError[ENUM_BAND_0] += htonl(g_HqaRxStat.MAC_FCS_Err); + au4FcsError[ENUM_BAND_1] += htonl(g_HqaRxStat.MAC_FCS_Err1); + au4OutOfResource[ENUM_BAND_0] += htonl(g_HqaRxStat.OutOfResource); + au4OutOfResource[ENUM_BAND_1] += htonl(g_HqaRxStat.OutOfResource1); + au4LengthMismatch[ENUM_BAND_0] += + htonl(g_HqaRxStat.LengthMismatchCount_B0); + au4LengthMismatch[ENUM_BAND_1] += + htonl(g_HqaRxStat.LengthMismatchCount_B1); + + if (fgResetCnt) { + kalMemZero(au4MacMdrdy, sizeof(au4MacMdrdy)); + kalMemZero(au4FcsError, sizeof(au4FcsError)); + kalMemZero(au4OutOfResource, sizeof(au4OutOfResource)); + kalMemZero(au4LengthMismatch, sizeof(au4LengthMismatch)); + } + + if (prAdapter->prAisBssInfo->prStaRecOfAP) { + ucWlanIndex = + prAdapter->prAisBssInfo->prStaRecOfAP->ucWlanIndex; + } else if (!wlanGetWlanIdxByAddress(prAdapter, NULL, &ucWlanIndex)) { + fgWlanIdxFound = false; + } + + if (fgWlanIdxFound) { + if (wlanGetStaIdxByWlanIdx(prAdapter, ucWlanIndex, &ucStaIdx) == + WLAN_STATUS_SUCCESS) { + u4RxVector0 = prAdapter->arStaRec[ucStaIdx].u4RxVector0; + u4RxVector2 = prAdapter->arStaRec[ucStaIdx].u4RxVector2; + u4RxVector3 = prAdapter->arStaRec[ucStaIdx].u4RxVector3; + u4RxVector4 = prAdapter->arStaRec[ucStaIdx].u4RxVector4; + } else { + fgSkipRxV = true; + } + } else { + fgSkipRxV = true; + } + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", + "\n\nRX Stat:\n"); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "MAC Mdrdy0", " = ", + au4MacMdrdy[ENUM_BAND_0]); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "MAC Mdrdy1", " = ", + au4MacMdrdy[ENUM_BAND_1]); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "FCS Err0", " = ", + au4FcsError[ENUM_BAND_0]); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "FCS Err1", " = ", + au4FcsError[ENUM_BAND_1]); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "CCK PD Cnt B0", " = ", + htonl(g_HqaRxStat.CCK_PD)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "CCK PD Cnt B1", " = ", + htonl(g_HqaRxStat.CCK_PD_Band1)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "CCK SIG Err B0", " = ", + htonl(g_HqaRxStat.CCK_SIG_Err)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "CCK SIG Err B1", " = ", + htonl(g_HqaRxStat.CCK_SIG_Err_Band1)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "OFDM PD Cnt B0", " = ", + htonl(g_HqaRxStat.OFDM_PD)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "OFDM PD Cnt B1", " = ", + htonl(g_HqaRxStat.OFDM_PD_Band1)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "OFDM TAG Error", " = ", + htonl(g_HqaRxStat.OFDM_TAG_Err)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "CCK SFD Err B0", " = ", + htonl(g_HqaRxStat.CCK_SFD_Err)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "CCK SFD Err B1", " = ", + htonl(g_HqaRxStat.CCK_SFD_Err_Band1)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "OFDM SIG Err B0", " = ", + htonl(g_HqaRxStat.OFDM_SIG_Err)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "OFDM SIG Err B1", " = ", + htonl(g_HqaRxStat.OFDM_SIG_Err_Band1)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "CCK FCS Err B0", " = ", + htonl(g_HqaRxStat.FCSErr_CCK)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "CCK FCS Err B1", " = ", + htonl(g_HqaRxStat.CCK_FCS_Err_Band1)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "OFDM FCS Err B0", " = ", + htonl(g_HqaRxStat.FCSErr_OFDM)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "OFDM FCS Err B1", " = ", + htonl(g_HqaRxStat.OFDM_FCS_Err_Band1)); + + if (!fgSkipRxV) { + u4FAGCRssiIBR0 = (u4RxVector2 & BITS(16, 23)) >> 16; + u4FAGCRssiWBR0 = (u4RxVector2 & BITS(24, 31)) >> 24; + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "FAGC RSSI W", " = ", + (u4FAGCRssiWBR0 >= 128) ? (u4FAGCRssiWBR0 - 256) : + (u4FAGCRssiWBR0)); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "FAGC RSSI I", " = ", + (u4FAGCRssiIBR0 >= 128) ? (u4FAGCRssiIBR0 - 256) : + (u4FAGCRssiIBR0)); + } else { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", "FAGC RSSI W", + " = ", "N/A"); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", "FAGC RSSI I", + " = ", "N/A"); + } + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "CCK MDRDY B0", " = ", + htonl(g_HqaRxStat.PhyMdrdyCCK)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "CCK MDRDY B1", " = ", + htonl(g_HqaRxStat.PHY_CCK_MDRDY_Band1)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "OFDM MDRDY B0", " = ", + htonl(g_HqaRxStat.PhyMdrdyOFDM)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "OFDM MDRDY B1", " = ", + htonl(g_HqaRxStat.PHY_OFDM_MDRDY_Band1)); + + if (!fgSkipRxV) { + u4Value = (u4RxVector0 & BITS(12, 14)) >> 12; + if (u4Value == 0) { + u4Foe = (((u4RxVector4 & BITS(7, 31)) >> 7) & 0x7ff); + u4Foe = (u4Foe * 1000) >> 11; + } else { + cbw = ((u4RxVector0 & BITS(15, 16)) >> 15); + foe_const = ((1 << (cbw + 1)) & 0xf) * 10000; + u4Foe = (((u4RxVector4 & BITS(7, 31)) >> 7) & 0xfff); + u4Foe = (u4Foe * foe_const) >> 15; + } + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Freq Offset From RX", " = ", u4Foe); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "RX SNR (dB)", " = ", + ((u4RxVector4 & BITS(26, 31)) >> 26) - 16); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "RCPI RX0", " = ", + u4RxVector3 & BITS(0, 7)); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "RCPI RX1", " = ", + (u4RxVector3 & BITS(8, 15)) >> 8); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "RCPI RX2", " = ", + ((u4RxVector3 & BITS(16, 23)) >> 16) == 0xFF ? + (0) : + ((u4RxVector3 & BITS(16, 23)) >> 16)); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "RCPI RX3", " = ", + ((u4RxVector3 & BITS(24, 31)) >> 24) == 0xFF ? + (0) : + ((u4RxVector3 & BITS(24, 31)) >> 24)); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", "Freq Offset From RX", " = ", "N/A"); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", "RX SNR (dB)", + " = ", "N/A"); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", "RCPI RX0", " = ", + "N/A"); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", "RCPI RX1", " = ", + "N/A"); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", "RCPI RX2", " = ", + "N/A"); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%s\n", "RCPI RX3", " = ", + "N/A"); + } + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Inst RSSI IB R0", " = ", + htonl(g_HqaRxStat.InstRssiIBR0)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Inst RSSI WB R0", " = ", + htonl(g_HqaRxStat.InstRssiWBR0)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Inst RSSI IB R1", " = ", + htonl(g_HqaRxStat.InstRssiIBR1)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Inst RSSI WB R1", " = ", + htonl(g_HqaRxStat.InstRssiWBR1)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Inst RSSI IB R2", " = ", + htonl(g_HqaRxStat.InstRssiIBR2)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Inst RSSI WB R2", " = ", + htonl(g_HqaRxStat.InstRssiWBR2)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Inst RSSI IB R3", " = ", + htonl(g_HqaRxStat.InstRssiIBR3)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Inst RSSI WB R3", " = ", + htonl(g_HqaRxStat.InstRssiWBR3)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "ACI Hit Lower", " = ", + htonl(g_HqaRxStat.ACIHitLower)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "ACI Hit Higher", " = ", + htonl(g_HqaRxStat.ACIHitUpper)); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "OutOf Resource Pkt0", + " = ", au4OutOfResource[ENUM_BAND_0]); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "OutOf Resource Pkt1", + " = ", au4OutOfResource[ENUM_BAND_1]); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Len Mismatch Cnt B0", + " = ", au4LengthMismatch[ENUM_BAND_0]); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%-20s%s%d\n", "Len Mismatch Cnt B1", + " = ", au4LengthMismatch[ENUM_BAND_1]); + + return i4BytesWritten; +} + +static int priv_driver_show_rx_stat(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + P_PARAM_CUSTOM_ACCESS_RX_STAT prRxStatisticsTest; + u8 fgResetCnt = false; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + u32 u4Id = 0x99980000; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + DBGLOG(INIT, ERROR, "MT6632 : priv_driver_show_rx_stat\n"); + + if (i4Argc >= 2) { + if (strnicmp(apcArgv[1], CMD_STAT_RESET_CNT, + strlen(CMD_STAT_RESET_CNT)) == 0) { + fgResetCnt = true; + } + } + + if (i4Argc >= 1) { + if (fgResetCnt) { + rSwCtrlInfo.u4Id = u4Id; + rSwCtrlInfo.u4Data = 0; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, + &rSwCtrlInfo, sizeof(rSwCtrlInfo), + false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + } + + prRxStatisticsTest = (P_PARAM_CUSTOM_ACCESS_RX_STAT)kalMemAlloc( + sizeof(PARAM_CUSTOM_ACCESS_RX_STAT), VIR_MEM_TYPE); + if (!prRxStatisticsTest) { + return -1; + } + + prRxStatisticsTest->u4SeqNum = u4RxStatSeqNum; + prRxStatisticsTest->u4TotalNum = sizeof(PARAM_RX_STAT_T) / 4; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryRxStatistics, + prRxStatisticsTest, + sizeof(PARAM_CUSTOM_ACCESS_RX_STAT), true, + true, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + kalMemFree(prRxStatisticsTest, VIR_MEM_TYPE, + sizeof(PARAM_CUSTOM_ACCESS_RX_STAT)); + return -1; + } + + i4BytesWritten = priv_driver_dump_rx_stat_info( + prAdapter, pcCommand, i4TotalLen, fgResetCnt); + + kalMemFree(prRxStatisticsTest, VIR_MEM_TYPE, + sizeof(PARAM_CUSTOM_ACCESS_RX_STAT)); + } + + return i4BytesWritten; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Handle command to get current Tx rate from rate table and respond + * string buffer. Example: VHT-2SS-BW80-SGI-MCS7 + * + * \param[in] net_device Pointer to the Adapter structure. + * \param[out] pcCommand Pointer to the command buffer to respond. + * \param[in] i4TotalLen The length of buffer. + * + * \retval Length of response buffer + */ +/*----------------------------------------------------------------------------*/ +static int priv_driver_get_sta_curr_ar_rate(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + u8 ucWlanIndex = 0; + u8 *pucMacAddr = NULL; + u8 idx, txmode, rate; + P_PARAM_GET_STA_STATISTICS prQueryStaStatistics = NULL; + P_PARAM_HW_WLAN_INFO_T prHwWlanInfo = NULL; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -EINVAL; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + /* Get AIS AP address for no argument */ + if (prAdapter->prAisBssInfo->prStaRecOfAP) { + ucWlanIndex = + prAdapter->prAisBssInfo->prStaRecOfAP->ucWlanIndex; + } else if (!wlanGetWlanIdxByAddress(prAdapter, NULL, &ucWlanIndex)) { + return i4BytesWritten; + } + + pucMacAddr = wlanGetStaAddrByWlanIdx(prAdapter, ucWlanIndex); + if (!pucMacAddr) { + DBGLOG(REQ, WARN, "%s: MAC address is invalid!\n", __func__); + return -EFAULT; + } + /* Get WTBL info */ + prHwWlanInfo = (P_PARAM_HW_WLAN_INFO_T)kalMemAlloc( + sizeof(PARAM_HW_WLAN_INFO_T), VIR_MEM_TYPE); + if (!prHwWlanInfo) { + return -ENOMEM; + } + + kalMemZero(prHwWlanInfo, sizeof(PARAM_HW_WLAN_INFO_T)); + prHwWlanInfo->u4Index = ucWlanIndex; + rStatus = kalIoctl(prGlueInfo, wlanoidQueryWlanInfo, prHwWlanInfo, + sizeof(PARAM_HW_WLAN_INFO_T), true, true, true, + &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + i4BytesWritten = -EFAULT; + goto out_get_curr_ar_rate; + } + + prQueryStaStatistics = (P_PARAM_GET_STA_STATISTICS)kalMemAlloc( + sizeof(PARAM_GET_STA_STATISTICS), VIR_MEM_TYPE); + if (!prQueryStaStatistics) { + i4BytesWritten = -ENOMEM; + goto out_get_curr_ar_rate; + } + + /* Get Statistics info */ + COPY_MAC_ADDR(prQueryStaStatistics->aucMacAddr, pucMacAddr); + rStatus = kalIoctl(prGlueInfo, wlanoidQueryStaStatistics, + prQueryStaStatistics, + sizeof(PARAM_GET_STA_STATISTICS), true, true, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + i4BytesWritten = -EFAULT; + goto out_get_curr_ar_rate; + } + + idx = prHwWlanInfo->rWtblRateInfo.ucRateIdx; + if (idx >= AUTO_RATE_NUM) { + DBGLOG(REQ, WARN, "%s: Rate index is incorrect (%d)\n", + __func__, idx); + i4BytesWritten = -EFAULT; + goto out_get_curr_ar_rate; + } + txmode = HW_TX_RATE_TO_MODE( + prHwWlanInfo->rWtblRateInfo.au2RateCode[idx]); + if (txmode >= MAX_TX_MODE) { + txmode = MAX_TX_MODE; + } + rate = HW_TX_RATE_TO_MCS(prHwWlanInfo->rWtblRateInfo.au2RateCode[idx], + txmode); + + /* Mode: [CCK | OFDM | HT | VHT] */ + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "CCK-"); + } else if (txmode == TX_RATE_MODE_OFDM) { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "OFDM-"); + } else if (txmode == TX_RATE_MODE_HTGF || + txmode == TX_RATE_MODE_HTMIX) { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "HT-"); + } else { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "VHT-"); + } + /* Spatial Streams: [1SS | 2SS | N/A] */ + if (prQueryStaStatistics->ucArTableIdx == RATE_TBL_N_2SS || + prQueryStaStatistics->ucArTableIdx == RATE_TBL_AC_2SS) { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "2SS-"); + } else if (prQueryStaStatistics->ucArTableIdx == RATE_TBL_N || + prQueryStaStatistics->ucArTableIdx == RATE_TBL_AC) { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "1SS-"); + } else { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "N/A-"); + } + + /* BW mode: [BW20 | BW40 | BW80 | BW160/BW8080] */ + if ((txmode == TX_RATE_MODE_CCK) || (txmode == TX_RATE_MODE_OFDM)) { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s-", HW_TX_RATE_BW[0]); + } else if (idx > prHwWlanInfo->rWtblPeerCap.ucChangeBWAfterRateN) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s-", + prHwWlanInfo->rWtblPeerCap.ucFrequencyCapability < 4 ? + (prHwWlanInfo->rWtblPeerCap + .ucFrequencyCapability > + BW_20 ? + HW_TX_RATE_BW + [prHwWlanInfo->rWtblPeerCap + .ucFrequencyCapability - + 1] : + HW_TX_RATE_BW + [prHwWlanInfo->rWtblPeerCap + .ucFrequencyCapability]) : + HW_TX_RATE_BW[4]); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "%s-", + prHwWlanInfo->rWtblPeerCap.ucFrequencyCapability < 4 ? + HW_TX_RATE_BW[prHwWlanInfo->rWtblPeerCap + .ucFrequencyCapability] : + HW_TX_RATE_BW[4]); + } + /* GI mode: [LGI | SGI | X] */ + if (txmode == TX_RATE_MODE_CCK || txmode == TX_RATE_MODE_OFDM) { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "N/A-"); + } else { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s-", + priv_driver_get_sgi_info( + &prHwWlanInfo->rWtblPeerCap) == 0 ? + "LGI" : + "SGI"); + } + /* Rate index: [1M | 2M | 5.5M | 11M | + * 6M | 9M | 12M | 18M | 24M | 36M | 48M | 54M | + * MCS# ] + */ + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "%s", + rate < 4 ? HW_TX_RATE_CCK_STR[rate] : + HW_TX_RATE_CCK_STR[4]); + } else if (txmode == TX_RATE_MODE_OFDM) { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s", hw_rate_ofdm_str(rate)); + } else { + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "MCS%d", rate); + } + +out_get_curr_ar_rate: + if (prHwWlanInfo) { + kalMemFree(prHwWlanInfo, VIR_MEM_TYPE, + sizeof(PARAM_HW_WLAN_INFO_T)); + } + if (prQueryStaStatistics) { + kalMemFree(prQueryStaStatistics, VIR_MEM_TYPE, + sizeof(PARAM_GET_STA_STATISTICS)); + } + + return i4BytesWritten; +} + +/*----------------------------------------------------------------------------*/ +/* + * @ The function will set policy of ACL. + * 0: disable ACL + * 1: enable accept list + * 2: enable deny list + * example: iwpriv p2p0 driver "set_acl_policy 1" + */ +/*----------------------------------------------------------------------------*/ +static int priv_driver_set_acl_policy(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + P_BSS_INFO_T prBssInfo = NULL; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4Argc = 0, i4BytesWritten = 0, i4Ret = 0, i4Policy = 0; + u8 ucRoleIdx = 0, ucBssIdx = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + /* get Bss Index from ndev */ + if (mtk_Netdev_To_RoleIdx(prGlueInfo, prNetDev, &ucRoleIdx) != 0) { + return -1; + } + + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &ucBssIdx) != + WLAN_STATUS_SUCCESS) { + return -1; + } + + prBssInfo = prAdapter->aprBssInfo[ucBssIdx]; + + DBGLOG(REQ, LOUD, "ucRoleIdx %hhu ucBssIdx %hhu\n", ucRoleIdx, + ucBssIdx); + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc < 2) { + return -1; + } + + i4Ret = kalkStrtou32(apcArgv[1], 0, &i4Policy); + if (i4Ret) { + DBGLOG(REQ, ERROR, "integer format error i4Ret=%d\n", i4Ret); + return -1; + } + + switch (i4Policy) { + case PARAM_CUSTOM_ACL_POLICY_DISABLE: + case PARAM_CUSTOM_ACL_POLICY_ACCEPT: + case PARAM_CUSTOM_ACL_POLICY_DENY: + prBssInfo->rACL.ePolicy = i4Policy; + break; + + default: /*Invalid argument */ + DBGLOG(REQ, ERROR, "Invalid ACL Policy=%d\n", i4Policy); + return -1; + } + + DBGLOG(REQ, TRACE, "ucBssIdx[%hhu] ACL Policy=%d\n", ucBssIdx, + prBssInfo->rACL.ePolicy); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "ucBssIdx[%hhu] ACL Policy=%d\n", + ucBssIdx, prBssInfo->rACL.ePolicy); + + /* check if the change in ACL affects any existent association */ + if (prBssInfo->rACL.ePolicy != PARAM_CUSTOM_ACL_POLICY_DISABLE) { + p2pRoleUpdateACLEntry(prAdapter, ucBssIdx); + } + + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand); + + return i4BytesWritten; +} + +static s32 priv_driver_inspect_mac_addr(IN char *pcMacAddr) +{ + s32 i = 0; + + if (pcMacAddr == NULL) { + return -1; + } + + for (i = 0; i < 17; i++) { + if ((i % 3 != 2) && (!kalIsXdigit(pcMacAddr[i]))) { + DBGLOG(REQ, ERROR, "[%c] is not hex digit\n", + pcMacAddr[i]); + return -1; + } + if ((i % 3 == 2) && (pcMacAddr[i] != ':')) { + DBGLOG(REQ, ERROR, "[%c]separate symbol is error\n", + pcMacAddr[i]); + return -1; + } + } + + if (pcMacAddr[17] != '\0') { + DBGLOG(REQ, ERROR, "no null-terminated character\n"); + return -1; + } + + return 0; +} + +/*----------------------------------------------------------------------------*/ +/* + * @ The function will add entry to ACL for accept or deny list. + * example: iwpriv p2p0 driver "add_acl_entry 01:02:03:04:05:06" + */ +/*----------------------------------------------------------------------------*/ +static int priv_driver_add_acl_entry(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + P_BSS_INFO_T prBssInfo = NULL; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u8 aucMacAddr[MAC_ADDR_LEN] = { 0 }; + s32 i = 0, i4Argc = 0, i4BytesWritten = 0, i4Ret = 0; + u8 ucRoleIdx = 0, ucBssIdx = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + /* get Bss Index from ndev */ + if (mtk_Netdev_To_RoleIdx(prGlueInfo, prNetDev, &ucRoleIdx) != 0) { + return -1; + } + + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &ucBssIdx) != + WLAN_STATUS_SUCCESS) { + return -1; + } + + prBssInfo = prAdapter->aprBssInfo[ucBssIdx]; + + DBGLOG(REQ, LOUD, "ucRoleIdx %hhu ucBssIdx %hhu\n", ucRoleIdx, + ucBssIdx); + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc < 2) { + return -1; + } + + i4Ret = priv_driver_inspect_mac_addr(apcArgv[1]); + if (i4Ret) { + DBGLOG(REQ, ERROR, "inspect mac format error u4Ret=%d\n", + i4Ret); + return -1; + } + + i4Ret = sscanf(apcArgv[1], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &aucMacAddr[0], &aucMacAddr[1], &aucMacAddr[2], + &aucMacAddr[3], &aucMacAddr[4], &aucMacAddr[5]); + + if (i4Ret != MAC_ADDR_LEN) { + DBGLOG(REQ, ERROR, "sscanf mac format fail u4Ret=%d\n", i4Ret); + return -1; + } + + for (i = 0; i <= prBssInfo->rACL.u4Num; i++) { + if (memcmp(prBssInfo->rACL.rEntry[i].aucAddr, &aucMacAddr, + MAC_ADDR_LEN) == 0) { + DBGLOG(REQ, ERROR, + "add this mac [" MACSTR "] is duplicate.\n", + MAC2STR(aucMacAddr)); + return -1; + } + } + + if ((i < 1) || (i > MAX_NUMBER_OF_ACL)) { + DBGLOG(REQ, ERROR, "idx[%d] error or ACL is full.\n", i); + return -1; + } + + memcpy(prBssInfo->rACL.rEntry[i - 1].aucAddr, &aucMacAddr, + MAC_ADDR_LEN); + prBssInfo->rACL.u4Num = i; + DBGLOG(REQ, TRACE, "add mac addr [" MACSTR "] to ACL(%d).\n", + MAC2STR(prBssInfo->rACL.rEntry[i - 1].aucAddr), i); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "add mac addr [" MACSTR "] to ACL(%d)\n", + MAC2STR(prBssInfo->rACL.rEntry[i - 1].aucAddr), i); + + /* Check if the change in ACL affects any existent association. */ + if (prBssInfo->rACL.ePolicy == PARAM_CUSTOM_ACL_POLICY_DENY) { + p2pRoleUpdateACLEntry(prAdapter, ucBssIdx); + } + + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand); + + return i4BytesWritten; +} + +/*----------------------------------------------------------------------------*/ +/* + * @ The function will delete entry to ACL for accept or deny list. + * example: iwpriv p2p0 driver "add_del_entry 01:02:03:04:05:06" + */ +/*----------------------------------------------------------------------------*/ +static int priv_driver_del_acl_entry(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + P_BSS_INFO_T prBssInfo = NULL; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u8 aucMacAddr[MAC_ADDR_LEN] = { 0 }; + s32 i = 0, j = 0, i4Argc = 0, i4BytesWritten = 0, i4Ret = 0; + u8 ucRoleIdx = 0, ucBssIdx = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + /* get Bss Index from ndev */ + if (mtk_Netdev_To_RoleIdx(prGlueInfo, prNetDev, &ucRoleIdx) != 0) { + return -1; + } + + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &ucBssIdx) != + WLAN_STATUS_SUCCESS) { + return -1; + } + + prBssInfo = prAdapter->aprBssInfo[ucBssIdx]; + + DBGLOG(REQ, LOUD, "ucRoleIdx %hhu ucBssIdx %hhu\n", ucRoleIdx, + ucBssIdx); + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc < 2) { + return -1; + } + + i4Ret = priv_driver_inspect_mac_addr(apcArgv[1]); + if (i4Ret) { + DBGLOG(REQ, ERROR, "inspect mac format error u4Ret=%d\n", + i4Ret); + return -1; + } + + i4Ret = sscanf(apcArgv[1], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &aucMacAddr[0], &aucMacAddr[1], &aucMacAddr[2], + &aucMacAddr[3], &aucMacAddr[4], &aucMacAddr[5]); + + if (i4Ret != MAC_ADDR_LEN) { + DBGLOG(REQ, ERROR, "sscanf mac format fail u4Ret=%d\n", i4Ret); + return -1; + } + + for (i = 0; i < prBssInfo->rACL.u4Num; i++) { + if (memcmp(prBssInfo->rACL.rEntry[i].aucAddr, &aucMacAddr, + MAC_ADDR_LEN) == 0) { + memset(&prBssInfo->rACL.rEntry[i], 0x00, + sizeof(PARAM_CUSTOM_ACL_ENTRY)); + DBGLOG(REQ, TRACE, "delete this mac [" MACSTR "]\n", + MAC2STR(aucMacAddr)); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "delete this mac [" MACSTR "] from ACL(%d)\n", + MAC2STR(aucMacAddr), i + 1); + break; + } + } + + if ((prBssInfo->rACL.u4Num == 0) || (i == MAX_NUMBER_OF_ACL)) { + DBGLOG(REQ, ERROR, "delete entry fail, num of entries=%d\n", i); + return -1; + } + + for (j = i + 1; j < prBssInfo->rACL.u4Num; j++) + memcpy(prBssInfo->rACL.rEntry[j - 1].aucAddr, + prBssInfo->rACL.rEntry[j].aucAddr, MAC_ADDR_LEN); + + prBssInfo->rACL.u4Num = j - 1; + memset(prBssInfo->rACL.rEntry[j - 1].aucAddr, 0x00, MAC_ADDR_LEN); + + /* check if the change in ACL affects any existent association */ + if (prBssInfo->rACL.ePolicy == PARAM_CUSTOM_ACL_POLICY_ACCEPT) { + p2pRoleUpdateACLEntry(prAdapter, ucBssIdx); + } + + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand); + + return i4BytesWritten; +} + +/*----------------------------------------------------------------------------*/ +/* + * @ The function will show all entries to ACL for accept or deny list. + * example: iwpriv p2p0 driver "show_acl_entry" + */ +/*----------------------------------------------------------------------------*/ +static int priv_driver_show_acl_entry(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + P_BSS_INFO_T prBssInfo = NULL; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i = 0, i4Argc = 0, i4BytesWritten = 0; + u8 ucRoleIdx = 0, ucBssIdx = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + /* get Bss Index from ndev */ + if (mtk_Netdev_To_RoleIdx(prGlueInfo, prNetDev, &ucRoleIdx) != 0) { + return -1; + } + + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &ucBssIdx) != + WLAN_STATUS_SUCCESS) { + return -1; + } + + prBssInfo = prAdapter->aprBssInfo[ucBssIdx]; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + DBGLOG(REQ, TRACE, "ACL Policy = %d\n", prBssInfo->rACL.ePolicy); + DBGLOG(REQ, TRACE, "Total ACLs = %d\n", prBssInfo->rACL.u4Num); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "ACL Policy = %d, Total ACLs = %d\n", + prBssInfo->rACL.ePolicy, + prBssInfo->rACL.u4Num); + + for (i = 0; i < prBssInfo->rACL.u4Num; i++) { + DBGLOG(REQ, TRACE, "ACL(%d): [" MACSTR "]\n", i + 1, + MAC2STR(prBssInfo->rACL.rEntry[i].aucAddr)); + + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "ACL(%d): [" MACSTR "]\n", i + 1, + MAC2STR(prBssInfo->rACL.rEntry[i].aucAddr)); + } + + return i4BytesWritten; +} + +/*----------------------------------------------------------------------------*/ +/* + * @ The function will clear all entries to ACL for accept or deny list. + * example: iwpriv p2p0 driver "clear_acl_entry" + */ +/*----------------------------------------------------------------------------*/ +static int priv_driver_clear_acl_entry(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + P_BSS_INFO_T prBssInfo = NULL; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4Argc = 0, i4BytesWritten = 0; + u8 ucRoleIdx = 0, ucBssIdx = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + /* get Bss Index from ndev */ + if (mtk_Netdev_To_RoleIdx(prGlueInfo, prNetDev, &ucRoleIdx) != 0) { + return -1; + } + + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, &ucBssIdx) != + WLAN_STATUS_SUCCESS) { + return -1; + } + + prBssInfo = prAdapter->aprBssInfo[ucBssIdx]; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (prBssInfo->rACL.u4Num) { + memset(&prBssInfo->rACL.rEntry[0], 0x00, + sizeof(PARAM_CUSTOM_ACL_ENTRY) * MAC_ADDR_LEN); + prBssInfo->rACL.u4Num = 0; + } + + DBGLOG(REQ, TRACE, "ACL Policy = %d\n", prBssInfo->rACL.ePolicy); + DBGLOG(REQ, TRACE, "Total ACLs = %d\n", prBssInfo->rACL.u4Num); + + i4BytesWritten += kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "ACL Policy = %d, Total ACLs = %d\n", + prBssInfo->rACL.ePolicy, + prBssInfo->rACL.u4Num); + + /* check if the change in ACL affects any existent association */ + if (prBssInfo->rACL.ePolicy == PARAM_CUSTOM_ACL_POLICY_ACCEPT) { + p2pRoleUpdateACLEntry(prAdapter, ucBssIdx); + } + + return i4BytesWritten; +} + +static int priv_driver_get_drv_mcr(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u32 u4Ret; + /* s32 i4ArgNum_with_ant_sel = 3; */ /* Add Antenna Selection Input */ + s32 i4ArgNum = 2; + + CMD_ACCESS_REG rCmdAccessReg; + + kalMemZero(&rCmdAccessReg, sizeof(CMD_ACCESS_REG)); + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= i4ArgNum) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &(rCmdAccessReg.u4Address)); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "parse get_drv_mcr error (Address) u4Ret=%d\n", + u4Ret); + return -1; + } + + /* rCmdAccessReg.u4Address = kalStrtoul(apcArgv[1], NULL, 0); */ + rCmdAccessReg.u4Data = 0; + + DBGLOG(REQ, LOUD, "address is %x\n", rCmdAccessReg.u4Address); + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryDrvMcrRead, + &rCmdAccessReg, sizeof(rCmdAccessReg), true, + true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + i4BytesWritten = snprintf(pcCommand, i4TotalLen, "0x%08x", + (unsigned int)rCmdAccessReg.u4Data); + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, + pcCommand); + } + + return i4BytesWritten; +} + +int priv_driver_set_drv_mcr(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Ret; + /* s32 i4ArgNum_with_ant_sel = 4; */ /* Add Antenna Selection Input */ + s32 i4ArgNum = 3; + + CMD_ACCESS_REG rCmdAccessReg; + + kalMemZero(&rCmdAccessReg, sizeof(CMD_ACCESS_REG)); + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= i4ArgNum) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &(rCmdAccessReg.u4Address)); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "parse get_drv_mcr error (Address) u4Ret=%d\n", + u4Ret); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[2], 0, &(rCmdAccessReg.u4Data)); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "parse get_drv_mcr error (Data) u4Ret=%d\n", + u4Ret); + return -1; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetDrvMcrWrite, + &rCmdAccessReg, sizeof(rCmdAccessReg), false, + false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + } + + return i4BytesWritten; +} + +static int priv_driver_get_sw_ctrl(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 u4Ret = 0; + + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + kalMemZero(&rSwCtrlInfo, sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T)); + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= 2) { + /* rSwCtrlInfo.u4Id = kalStrtoul(apcArgv[1], NULL, 0); */ + rSwCtrlInfo.u4Data = 0; + u4Ret = kalkStrtou32(apcArgv[1], 0, &(rSwCtrlInfo.u4Id)); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse rSwCtrlInfo error u4Ret=%d\n", + u4Ret); + return -1; + } + + DBGLOG(REQ, LOUD, "id is %x\n", rSwCtrlInfo.u4Id); + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, + &rSwCtrlInfo, sizeof(rSwCtrlInfo), true, + true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + i4BytesWritten = snprintf(pcCommand, i4TotalLen, "0x%08x", + (unsigned int)rSwCtrlInfo.u4Data); + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, + pcCommand); + } + + return i4BytesWritten; +} + +int priv_driver_set_sw_ctrl(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 u4Ret = 0; + + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + kalMemZero(&rSwCtrlInfo, sizeof(PARAM_CUSTOM_SW_CTRL_STRUCT_T)); + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= 3) { + /* rSwCtrlInfo.u4Id = kalStrtoul(apcArgv[1], NULL, 0); + * rSwCtrlInfo.u4Data = kalStrtoul(apcArgv[2], NULL, 0); + */ + u4Ret = kalkStrtou32(apcArgv[1], 0, &(rSwCtrlInfo.u4Id)); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse rSwCtrlInfo error u4Ret=%d\n", + u4Ret); + return -1; + } + u4Ret = kalkStrtou32(apcArgv[2], 0, &(rSwCtrlInfo.u4Data)); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse rSwCtrlInfo error u4Ret=%d\n", + u4Ret); + return -1; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, + &rSwCtrlInfo, sizeof(rSwCtrlInfo), false, + false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + } + + return i4BytesWritten; +} + +int priv_driver_set_fixed_rate(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + /* s32 u4Ret = 0; */ + u32 u4WCID = 0; + u32 u4Mode = 0, u4Bw = 0, u4Mcs = 0, u4VhtNss = 0; + u32 u4SGI = 0, u4Preamble = 0, u4STBC = 0, u4LDPC = 0, u4SpeEn = 0; + s32 i4Recv = 0; + s8 *this_char = NULL; + u32 u4Id = 0xa0610000; + u32 u4Data = 0x80000000; + u32 u4Id2 = 0xa0600000; + u8 u4Nsts = 1; + u8 fgStatus = true; + + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + if (i4Argc == 0) { + DBGLOG(REQ, ERROR, "%s: invalid argc=0\n", __func__); + return -1; + } + DBGLOG(REQ, LOUD, "argc is %d, apcArgv[0] = %s\n\n", i4Argc, *apcArgv); + + this_char = kalStrStr(*apcArgv, "="); + + if (!this_char) { + return -1; + } + + this_char++; + + DBGLOG(REQ, LOUD, "string = %s\n", this_char); + + if (strnicmp(this_char, "auto", strlen("auto")) == 0) { + i4Recv = 1; + } else { + i4Recv = sscanf(this_char, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d", + &(u4WCID), &(u4Mode), &(u4Bw), &(u4Mcs), + &(u4VhtNss), &(u4SGI), &(u4Preamble), &(u4STBC), + &(u4LDPC), &(u4SpeEn)); + + DBGLOG(REQ, LOUD, "u4WCID=%d\nu4Mode=%d\nu4Bw=%d\n", u4WCID, + u4Mode, u4Bw); + DBGLOG(REQ, LOUD, "u4Mcs=%d\nu4VhtNss=%d\nu4SGI=%d\n", u4Mcs, + u4VhtNss, u4SGI); + DBGLOG(REQ, LOUD, "u4Preamble=%d\nu4STBC=%d\n", u4Preamble, + u4STBC); + DBGLOG(REQ, LOUD, "u4LDPC=%d\nu4SpeEn=%d\n", u4LDPC, u4SpeEn); + } + + if (i4Recv == 1) { + rSwCtrlInfo.u4Id = u4Id2; + rSwCtrlInfo.u4Data = 0; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, + &rSwCtrlInfo, sizeof(rSwCtrlInfo), false, + false, true, &u4BufLen); + } else if (i4Recv == 10) { + rSwCtrlInfo.u4Id = u4Id; + rSwCtrlInfo.u4Data = u4Data; + + if (u4SGI) { + rSwCtrlInfo.u4Data |= BIT(30); + } + if (u4LDPC) { + rSwCtrlInfo.u4Data |= BIT(29); + } + if (u4SpeEn) { + rSwCtrlInfo.u4Data |= BIT(28); + } + if (u4STBC) { + rSwCtrlInfo.u4Data |= BIT(11); + } + + if (u4Bw <= 3) { + rSwCtrlInfo.u4Data |= ((u4Bw << 26) & BITS(26, 27)); + } else { + fgStatus = false; + DBGLOG(INIT, ERROR, + "Wrong BW! BW20=0, BW40=1, BW80=2,BW160=3\n"); + } + if (u4Mode <= 4) { + rSwCtrlInfo.u4Data |= ((u4Mode << 6) & BITS(6, 8)); + + switch (u4Mode) { + case 0: + if (u4Mcs <= 3) { + rSwCtrlInfo.u4Data |= u4Mcs; + } else { + fgStatus = false; + DBGLOG(INIT, ERROR, + "CCK mode but wrong MCS!\n"); + } + + if (u4Preamble) { + rSwCtrlInfo.u4Data |= BIT(2); + }else{ + rSwCtrlInfo.u4Data &= ~BIT(2); + } + + break; + + case 1: + switch (u4Mcs) { + case 0: + /* 6'b001011 */ + rSwCtrlInfo.u4Data |= 11; + break; + + case 1: + /* 6'b001111 */ + rSwCtrlInfo.u4Data |= 15; + break; + + case 2: + /* 6'b001010 */ + rSwCtrlInfo.u4Data |= 10; + break; + + case 3: + /* 6'b001110 */ + rSwCtrlInfo.u4Data |= 14; + break; + + case 4: + /* 6'b001001 */ + rSwCtrlInfo.u4Data |= 9; + break; + + case 5: + /* 6'b001101 */ + rSwCtrlInfo.u4Data |= 13; + break; + + case 6: + /* 6'b001000 */ + rSwCtrlInfo.u4Data |= 8; + break; + + case 7: + /* 6'b001100 */ + rSwCtrlInfo.u4Data |= 12; + break; + + default: + fgStatus = false; + DBGLOG(INIT, ERROR, + "OFDM mode but wrong MCS!\n"); + break; + } + break; + + case 2: + case 3: + if (u4Mcs <= 32) { + rSwCtrlInfo.u4Data |= u4Mcs; + } else { + fgStatus = false; + DBGLOG(INIT, ERROR, + "HT mode but wrong MCS!\n"); + } + + if (u4Mcs != 32) { + u4Nsts += (u4Mcs >> 3); + if (u4STBC && (u4Nsts == 1)) { + u4Nsts++; + } + } + break; + + case 4: + if (u4Mcs <= 9) { + rSwCtrlInfo.u4Data |= u4Mcs; + } else { + fgStatus = false; + DBGLOG(INIT, ERROR, + "VHT mode but wrong MCS!\n"); + } + if (u4STBC && (u4VhtNss == 1)) { + u4Nsts++; + }else{ + u4Nsts = u4VhtNss; + } + break; + + default: + break; + } + } else { + fgStatus = false; + DBGLOG(INIT, + ERROR, + "Wrong TxMode! CCK=0, OFDM=1, HT=2, GF=3, VHT=4\n"); + } + + rSwCtrlInfo.u4Data |= (((u4Nsts - 1) << 9) & BITS(9, 10)); + + if (fgStatus) { + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, + &rSwCtrlInfo, sizeof(rSwCtrlInfo), + false, false, true, &u4BufLen); + } + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + } else { + DBGLOG(INIT, ERROR, "iwpriv wlanXX driver FixedRate=Option\n"); + DBGLOG(INIT, + ERROR, + "Option:[WCID]-[Mode]-[BW]-[MCS]-[VhtNss]-[SGI]-[Preamble]-[STBC]-[LDPC]-[SPE_EN]\n"); + DBGLOG(INIT, ERROR, "[WCID]Wireless Client ID\n"); + DBGLOG(INIT, ERROR, "[Mode]CCK=0, OFDM=1, HT=2, GF=3, VHT=4\n"); + DBGLOG(INIT, ERROR, "[BW]BW20=0, BW40=1, BW80=2,BW160=3\n"); + DBGLOG(INIT, ERROR, + "[MCS]CCK=0~3, OFDM=0~7, HT=0~32, VHT=0~9\n"); + DBGLOG(INIT, ERROR, "[VhtNss]VHT=1~4, Other=ignore\n"); + DBGLOG(INIT, ERROR, "[Preamble]Long=0, Other=Short\n"); + } + + return i4BytesWritten; +} + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT +int priv_driver_set_fixed_mrate(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + /* s32 u4Ret = 0; */ + u32 u4WCID = 0; + u32 u4Mode = 0, u4Bw = 0, u4Mcs = 0, u4VhtNss = 0; + u32 u4SGI = 0, u4Preamble = 0, u4STBC = 0, u4LDPC = 0, u4SpeEn = 0; + s32 i4Recv = 0; + s8 *this_char = NULL; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %d, apcArgv[0] = %s\n\n", i4Argc, *apcArgv); + + this_char = kalStrStr(*apcArgv, "="); + + if (!this_char) { + return -1; + } + + this_char++; + DBGLOG(REQ, LOUD, "string = %s\n", this_char); + + if (strnicmp(this_char, "auto", strlen("auto")) == 0) { + i4Recv = 1; + } else { + i4Recv = sscanf(this_char, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d", + &(u4WCID), &(u4Mode), &(u4Bw), &(u4Mcs), + &(u4VhtNss), &(u4SGI), &(u4Preamble), &(u4STBC), + &(u4LDPC), &(u4SpeEn)); + + DBGLOG(REQ, LOUD, "u4WCID=%d\nu4Mode=%d\nu4Bw=%d\n", u4WCID, + u4Mode, u4Bw); + DBGLOG(REQ, LOUD, "u4Mcs=%d\nu4VhtNss=%d\nu4SGI=%d\n", u4Mcs, + u4VhtNss, u4SGI); + DBGLOG(REQ, LOUD, "u4Preamble=%d\nu4STBC=%d\n", u4Preamble, + u4STBC); + DBGLOG(REQ, LOUD, "u4LDPC=%d\nu4SpeEn=%d\n", u4LDPC, u4SpeEn); + } + + if (i4Recv == 1) { + /* Recovery Mrate */ + prAdapter->fgIsFixedMRate = false; + } else if (i4Recv == 10) { + u16 u2FixedRateCode; + u8 ucRatePreamble, ucRateIndex; + MSDU_INFO_T rMsduInfo; + + kalMemZero(&rMsduInfo, sizeof(MSDU_INFO_T)); + + switch (u4Mode) { + case 0: + if (u4Preamble) { + ucRatePreamble = PREAMBLE_OPTION_SHORT; + }else{ + ucRatePreamble = PREAMBLE_DEFAULT_LONG_NONE; + } + + if (u4Mcs > RATE_11M_INDEX) { + ucRateIndex = RATE_11M_INDEX; + }else{ + ucRateIndex = (u8)u4Mcs; + } + break; + + case 1: + ucRatePreamble = PREAMBLE_OFDM_MODE; + if (u4Mcs > RATE_54M_INDEX) { + ucRateIndex = RATE_54M_INDEX; + }else{ + ucRateIndex = (u8)u4Mcs; + } + break; + + case 2: + ucRatePreamble = PREAMBLE_HT_MIXED_MODE; + + if ((u4Mcs >= 0) && (u4Mcs <= 7)) { + ucRateIndex = (u8)u4Mcs + HT_RATE_MCS0_INDEX; + } else if (u4Mcs == 32) { + ucRateIndex = HT_RATE_MCS32_INDEX; + } else { + ucRateIndex = HT_RATE_MCS7_INDEX; + } + break; + + case 3: + ucRatePreamble = PREAMBLE_HT_GREEN_FIELD; + + if ((u4Mcs >= 0) && (u4Mcs <= 7)) { + ucRateIndex = (u8)u4Mcs + HT_RATE_MCS0_INDEX; + } else if (u4Mcs == 32) { + ucRateIndex = HT_RATE_MCS32_INDEX; + } else { + ucRateIndex = HT_RATE_MCS7_INDEX; + } + break; + + case 4: + ucRatePreamble = PREAMBLE_VHT_FIELD; + if (u4Mcs > VHT_RATE_MCS9_INDEX) { + ucRateIndex = VHT_RATE_MCS9_INDEX; + }else{ + ucRateIndex = (u8)u4Mcs; + } + break; + + default: + DBGLOG(INIT, ERROR, "Unknown data rate mode\n"); + DBGLOG(INIT, ERROR, + " [Mode]CCK=0, OFDM=1, HT=2, GF=3, VHT=4\n"); + return -1; + + break; + } + + nicRateIndex2RateCode(ucRatePreamble, ucRateIndex, + &u2FixedRateCode); + + nicTxSetPktFixedRateOption(&rMsduInfo, u2FixedRateCode, + FIX_BW_NO_FIXED, + (u4SGI) ? true : false, false); + + prAdapter->rWifiVar.u4DataTxRateCode = + rMsduInfo.u4FixedRateOption; + /* Recovery Enable fix Mrate */ + prAdapter->fgIsFixedMRate = true; + } else { + DBGLOG(INIT, ERROR, "iwpriv wlanXX driver FixedMRate=Option\n"); + DBGLOG(INIT, + ERROR, + "Option:[WCID]-[Mode]-[BW]-[MCS]-[VhtNss]-[SGI]-[Preamble]-[STBC]-[LDPC]-[SPE_EN]\n"); + // DBGLOG(INIT, ERROR, "[WCID]Wireless Client ID\n"); + DBGLOG(INIT, ERROR, "[WCID] ** any number ** don't care\n"); + DBGLOG(INIT, ERROR, "[Mode]CCK=0, OFDM=1, HT=2, GF=3, VHT=4\n"); + DBGLOG(INIT, ERROR, "[BW] ** any number ** don't care\n"); + // DBGLOG(INIT, ERROR, "[BW]BW20=0, BW40=1, BW80=2,BW160=3\n"); + DBGLOG(INIT, ERROR, + "[MCS]CCK=0~3, OFDM=0~7, HT=0~32, VHT=0~9\n"); + // DBGLOG(INIT, ERROR, "[VhtNss]VHT=1~4, Other=ignore\n"); + DBGLOG(INIT, ERROR, "[VhtNss] ** any number ** don't care\n"); + DBGLOG(INIT, ERROR, "[Preamble]Long=0, Other=Short\n"); + DBGLOG(INIT, ERROR, "[STBC] ** any number ** don't care\n"); + DBGLOG(INIT, ERROR, "[LDPC] ** any number ** don't care\n"); + DBGLOG(INIT, ERROR, "[SPE_EN] ** any number ** don't care\n"); + } + return i4BytesWritten; +} + +int priv_driver_set_dup_mpacket(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + u32 u4Ret = 0; + u8 ucDupMPktNum = 0; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucDupMPktNum); + + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse DupMPkt number error u4Ret=%d\n", + u4Ret); + return i4BytesWritten; + } + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK + if (prAdapter->fgIsLookBackMode == true) { + i4BytesWritten = snprintf( + pcCommand, + i4TotalLen, + "Dulpicated packets return, Look Back Mode is enabled (0x%04x) \n", + (unsigned int)prAdapter->fgIsLookBackMode); + return i4BytesWritten; + } +#endif + + DBGLOG(PF, INFO, "Duplicate Multicast number %d\n", ucDupMPktNum); + + prAdapter->ucDupMcastPacketNum = ucDupMPktNum; + return i4BytesWritten; +} +int priv_driver_get_dup_mpacket(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4BytesWritten = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + i4BytesWritten = snprintf(pcCommand, i4TotalLen, + "duplicated packet number : 0x%04x", + (unsigned int)prAdapter->ucDupMcastPacketNum); + return i4BytesWritten; +} + +int priv_driver_set_mcast_burst(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + u32 u4Ret = 0; + u8 ucMCastBrust = 0; + u8 ucAc = TC2_INDEX; + PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T rChipConfigInfo; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + kalMemZero(&rChipConfigInfo, sizeof(rChipConfigInfo)); + + DBGLOG(REQ, INFO, "command is %s\n", pcCommand); + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + if (i4Argc < 2) { + DBGLOG(REQ, ERROR, + "Set_Mcastburst [0|1] [AC_IDX:0~3 default:2]\n"); + return -EFAULT; + } + + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucMCastBrust); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse mcast McastMode error u4Ret=%d\n", + u4Ret); + return i4BytesWritten; + } + + if (i4Argc == 3) { + u4Ret = kalkStrtou8(apcArgv[2], 0, &ucAc); + } + + DBGLOG(REQ, STATE, "Multicast Burst Mode %d\n", ucMCastBrust); + + if (!prAdapter->fgIsMcastBurstMode && !ucMCastBrust) { + DBGLOG(REQ, WARN, + "Multicast Burst Mode(%d) has already been disabled\n", + prAdapter->fgIsMcastBurstMode); + return 0; + } + + if (ucMCastBrust > 0) { + prAdapter->fgIsMcastBurstMode = true; + qmFuncChangeBmcTcIdx((ucAc < TC4_INDEX) ? (ucAc) : (TC2_INDEX)); + DBGLOG(REQ, STATE, "Multicast Burst AC Index %d\n", + ((ucAc < TC4_INDEX) ? (ucAc) : (TC2_INDEX))); + } else { + prAdapter->fgIsMcastBurstMode = false; + qmFuncChangeBmcTcIdx(BMC_TC_INDEX); + DBGLOG(REQ, STATE, + "Multicast Burst back to default AC Index:%d\n", + BMC_TC_INDEX); + } + + /* Adding McastBurstEn */ + rChipConfigInfo.ucType = CHIP_CONFIG_TYPE_WO_RESPONSE; + i4BytesWritten = kalScnprintf(rChipConfigInfo.aucCmd, + CHIP_CONFIG_RESP_SIZE, "McastBurst %d\n", + prAdapter->fgIsMcastBurstMode); + + if (i4BytesWritten > 0) { + rChipConfigInfo.u2MsgSize = (u16)i4BytesWritten; + kalIoctl(prGlueInfo, wlanoidSetChipConfig, &rChipConfigInfo, + sizeof(rChipConfigInfo), false, false, true, &u4Ret); + } + + return 0; +} +int priv_driver_get_mcast_burst(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4BytesWritten = 0; +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + u8 i; +#endif + + DBGLOG(REQ, LOUD, "get mcast burst\n"); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + i4BytesWritten = snprintf(pcCommand, i4TotalLen, "MBurstMode: 0x%01x ", + (unsigned int)prAdapter->fgIsMcastBurstMode); +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + for (i = 0; i < MAX_BSSID_NUM; i++) { + i4BytesWritten += kalSnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "WmmSetIdx:%d TC_IDX:%d\n", i, + arTcRemapTable[i][qmFuncGetBmcTcIdx(i)]); + } +#endif + return i4BytesWritten; +} +int priv_driver_set_txop(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + u32 u4Ret = 0; + u16 u2TXOPPeriod = 0; + CMD_ACCESS_REG rCmdAccessReg; + u32 u4BufLen = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + u4Ret = kalkStrtou16(apcArgv[1], 0, &u2TXOPPeriod); + + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse txop period error u4Ret=%d\n", u4Ret); + return i4BytesWritten; + } + + DBGLOG(REQ, LOUD, "The setting TXOP period (u2TXOPPeriod) is 0x%04x\n", + u2TXOPPeriod); + + // The maxmium of TXOP + if (u2TXOPPeriod >= 0x68) { + prAdapter->u4TXOPPeriod = 0x0068; + } else { + prAdapter->u4TXOPPeriod = u2TXOPPeriod; + } + prAdapter->u4TXOPPeriod |= (prAdapter->u4TXOPPeriod << 16); + + DBGLOG(REQ, ERROR, "The setting TXOP period (u4TXOPPeriod) is 0x%08x\n", + prAdapter->u4TXOPPeriod); + + // Write down to register + rCmdAccessReg.u4Data = prAdapter->u4TXOPPeriod; + + /* Set TXOP for extenad setting 3.3ms */ + rCmdAccessReg.u4Address = 0x820f4010; + rStatus = kalIoctl(prGlueInfo, wlanoidSetDrvMcrWrite, &rCmdAccessReg, + sizeof(rCmdAccessReg), false, false, true, + &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + DBGLOG(REQ, LOUD, "TXOP Add: 0x%08x value: 0x%08x\n", + rCmdAccessReg.u4Address, rCmdAccessReg.u4Data); + + rCmdAccessReg.u4Address = 0x820f4014; + rStatus = kalIoctl(prGlueInfo, wlanoidSetDrvMcrWrite, &rCmdAccessReg, + sizeof(rCmdAccessReg), false, false, true, + &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + DBGLOG(REQ, LOUD, "TXOP Add: 0x%08x value: 0x%08x\n", + rCmdAccessReg.u4Address, rCmdAccessReg.u4Data); + + rCmdAccessReg.u4Address = 0x820f4018; + rStatus = kalIoctl(prGlueInfo, wlanoidSetDrvMcrWrite, &rCmdAccessReg, + sizeof(rCmdAccessReg), false, false, true, + &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + DBGLOG(REQ, LOUD, "TXOP Add: 0x%08x value: 0x%08x\n", + rCmdAccessReg.u4Address, rCmdAccessReg.u4Data); + + rCmdAccessReg.u4Address = 0x820f401c; + rStatus = kalIoctl(prGlueInfo, wlanoidSetDrvMcrWrite, &rCmdAccessReg, + sizeof(rCmdAccessReg), false, false, true, + &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + DBGLOG(REQ, LOUD, "TXOP Add: 0x%08x value: 0x%08x\n", + rCmdAccessReg.u4Address, rCmdAccessReg.u4Data); + + /* Set TXOP for extenad setting 3.3ms */ + rCmdAccessReg.u4Address = 0x820f4060; + rStatus = kalIoctl(prGlueInfo, wlanoidSetDrvMcrWrite, &rCmdAccessReg, + sizeof(rCmdAccessReg), false, false, true, + &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + DBGLOG(REQ, LOUD, "TXOP Add: 0x%08x value: 0x%08x\n", + rCmdAccessReg.u4Address, rCmdAccessReg.u4Data); + + rCmdAccessReg.u4Address = 0x820f4064; + rStatus = kalIoctl(prGlueInfo, wlanoidSetDrvMcrWrite, &rCmdAccessReg, + sizeof(rCmdAccessReg), false, false, true, + &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + DBGLOG(REQ, LOUD, "TXOP Add: 0x%08x value: 0x%08x\n", + rCmdAccessReg.u4Address, rCmdAccessReg.u4Data); + + rCmdAccessReg.u4Address = 0x820f4068; + rStatus = kalIoctl(prGlueInfo, wlanoidSetDrvMcrWrite, &rCmdAccessReg, + sizeof(rCmdAccessReg), false, false, true, + &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + DBGLOG(REQ, LOUD, "TXOP Add: 0x%08x value: 0x%08x\n", + rCmdAccessReg.u4Address, rCmdAccessReg.u4Data); + + rCmdAccessReg.u4Address = 0x820f406c; + rStatus = kalIoctl(prGlueInfo, wlanoidSetDrvMcrWrite, &rCmdAccessReg, + sizeof(rCmdAccessReg), false, false, true, + &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + DBGLOG(REQ, LOUD, "TXOP Add: 0x%08x value: 0x%08x\n", + rCmdAccessReg.u4Address, rCmdAccessReg.u4Data); + + return i4BytesWritten; +} +int priv_driver_get_txop(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4BytesWritten = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + i4BytesWritten = + snprintf(pcCommand, i4TotalLen, + "TXOP Period: 0x%04x, it shuold be between 0~0x0068\n", + (unsigned int)(prAdapter->u4TXOPPeriod >> 16)); + return i4BytesWritten; +} + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK +int priv_driver_set_look_back(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + u32 u4Ret = 0; + u8 ucLookBackMode = 0; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucLookBackMode); + + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse Look Back error u4Ret=%d\n", u4Ret); + return i4BytesWritten; + } + + DBGLOG(PF, INFO, "Look Back Mode %d\n", ucLookBackMode); + + if (prAdapter->ucDupMcastPacketNum > 0) { + i4BytesWritten = snprintf( + pcCommand, + i4TotalLen, + "Look Back Mode return, Duplicate Num is not 0 (0x%04x) \n", + (unsigned int)prAdapter->ucDupMcastPacketNum); + return i4BytesWritten; + } + + if (ucLookBackMode > 0) { + prAdapter->fgIsLookBackMode = true; + } else { + prAdapter->fgIsLookBackMode = false; + } + + return i4BytesWritten; +} +int priv_driver_get_look_back(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4BytesWritten = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + i4BytesWritten = snprintf(pcCommand, i4TotalLen, + "Look Back Mode: 0x%04x", + (unsigned int)prAdapter->fgIsLookBackMode); + return i4BytesWritten; +} +#endif +int priv_driver_set_11mc_type(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + u32 u4Ret = 0; + u8 uc11mcType = 0; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + u4Ret = kalkStrtou8(apcArgv[1], 0, &uc11mcType); + + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse 11mc type error u4Ret=%d\n", u4Ret); + return i4BytesWritten; + } + + DBGLOG(PF, ERROR, "Look Back Mode %d\n", uc11mcType); + + /* We define currnet support packet type + * 0 -> disable packet parsing + * 1 -> icmp + * 2 -> multicast + * 3 -> TOS : ip header 0x20 + */ + prAdapter->uc11mcSupportType = uc11mcType; + i4BytesWritten = snprintf(pcCommand, i4TotalLen, + "11MC Support Type (0x%02x) \n", + (unsigned int)prAdapter->uc11mcSupportType); + + return i4BytesWritten; +} +int priv_driver_get_11mc_type(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4BytesWritten = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + i4BytesWritten = snprintf(pcCommand, i4TotalLen, + "11mc support type: 0x%02x", + (unsigned int)prAdapter->uc11mcSupportType); + return i4BytesWritten; +} + +int priv_driver_set_unicast_burst(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + u32 u4Ret = 0; + u8 ucUcastBurst = 0; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucUcastBurst); + + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse Unicast burst mode error u4Ret=%d\n", + u4Ret); + return i4BytesWritten; + } + + DBGLOG(PF, INFO, "Unicast Burst Mode %d\n", ucUcastBurst); + + if (ucUcastBurst > 0) { + prAdapter->fgIsUcastBurstMode = true; + prAdapter->ucUnicastBurstTimeout = 10; + } else { + prAdapter->fgIsUcastBurstMode = false; + prAdapter->ucUnicastBurstTimeout = 0; + } + + return i4BytesWritten; +} +int priv_driver_get_unicast_burst(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4BytesWritten = 0; + printk("get unicast burst mode\n"); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + i4BytesWritten = snprintf(pcCommand, i4TotalLen, + "Unicast Burst Mode: 0x%04x", + (unsigned int)prAdapter->fgIsUcastBurstMode); + return i4BytesWritten; +} + +int priv_driver_set_unicast_burst_timeout(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + u32 u4Ret = 0; + u8 ucUnicastBrustTimeout = 0; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucUnicastBrustTimeout); + + if (u4Ret) { + DBGLOG(REQ, LOUD, "Unicast BurstMode Timeout = %d\n", u4Ret); + return i4BytesWritten; + } + + DBGLOG(PF, ERROR, "Unicast BurstMode Timeout %d\n", + ucUnicastBrustTimeout); + + prAdapter->ucUnicastBurstTimeout = ucUnicastBrustTimeout; + i4BytesWritten = snprintf( + pcCommand, i4TotalLen, "Set Unicast Burst Timeout (%d) ms \n", + (unsigned int)prAdapter->ucUnicastBurstTimeout); + + return i4BytesWritten; +} +int priv_driver_get_unicast_burst_timeout(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4BytesWritten = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + i4BytesWritten = + snprintf(pcCommand, i4TotalLen, "Unicast Burst Timeout: %d ms", + (unsigned int)prAdapter->ucUnicastBurstTimeout); + return i4BytesWritten; +} + +int priv_driver_set_mrm_clinet(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + u32 u4Ret = 0; + u8 ucMRMClientMode = 0; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucMRMClientMode); + + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse MRM client mode error u4Ret=%d\n", + u4Ret); + return i4BytesWritten; + } + + DBGLOG(PF, INFO, "Unicast Burst Mode %d\n", ucMRMClientMode); + + if (ucMRMClientMode > 0) { + prAdapter->rWifiVar.ucTpTestMode = ENUM_TP_TEST_MODE_AUDIO_MRM; + /* update MRM client mode */ + DBGLOG(REQ, ERROR, "Enable MRM Client Mode %d\n", + prAdapter->rWifiVar.ucTpTestMode); + /* clean all the setting before start to set new mode*/ + nicEnterTPTestMode(prAdapter, TEST_MODE_NONE); + /* Update new setting before to new mode*/ + nicEnterTPTestMode(prAdapter, TEST_MODE_AUDIO_MRM); + } else { + prAdapter->rWifiVar.ucTpTestMode = ENUM_TP_TEST_MODE_NORMAL; + nicEnterTPTestMode(prAdapter, TEST_MODE_NONE); + } + + i4BytesWritten = snprintf(pcCommand, i4TotalLen, + "Set MRM Clinet mode (%d) to TP mode (%d)\n", + ucMRMClientMode, + prAdapter->rWifiVar.ucTpTestMode); + + return i4BytesWritten; +} + +int priv_driver_get_mrm_client(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4BytesWritten = 0; + u8 ucMRMClient = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + if (prAdapter->rWifiVar.ucTpTestMode == ENUM_TP_TEST_MODE_AUDIO_MRM) { + ucMRMClient = true; + } + + i4BytesWritten = snprintf(pcCommand, i4TotalLen, + "Get MRM Clinet mode (%d) & TP mode (%d)\n", + ucMRMClient, + prAdapter->rWifiVar.ucTpTestMode); + return i4BytesWritten; +} + +int priv_driver_set_audio_tos(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + u32 u4Ret = 0; + u8 ucAudioTOS = 0; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucAudioTOS); + + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse Audio TOS type error u4Ret=%d\n", + u4Ret); + return i4BytesWritten; + } + + DBGLOG(REQ, ERROR, "Specific Audio TOS %02x\n", ucAudioTOS); + + prAdapter->ucAudioTOS = ucAudioTOS; + i4BytesWritten = snprintf(pcCommand, i4TotalLen, + "Specific Audio TOS (0x%02x) \n", + (unsigned int)prAdapter->ucAudioTOS); + + return i4BytesWritten; +} +int priv_driver_get_audio_tos(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4BytesWritten = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + i4BytesWritten = snprintf(pcCommand, i4TotalLen, + "Specific Audio TOS: 0x%02x", + (unsigned int)prAdapter->ucAudioTOS); + return i4BytesWritten; +} +#endif + +int priv_driver_set_cfg(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + + PARAM_CUSTOM_KEY_CFG_STRUCT_T rKeyCfgInfo; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + prAdapter = prGlueInfo->prAdapter; + + kalMemZero(&rKeyCfgInfo, sizeof(rKeyCfgInfo)); + + if (i4Argc >= 3) { + s8 ucTmp[WLAN_CFG_VALUE_LEN_MAX]; + u8 *pucCurrBuf = ucTmp; + u8 i = 0; + s32 i4TmpBufLen = 0; + + kalMemZero(ucTmp, WLAN_CFG_VALUE_LEN_MAX); + + if (i4Argc == 3) { + /*no space for it, driver can't accept space in the end + * of the line*/ + /*ToDo: skip the space when parsing*/ + scnprintf(pucCurrBuf, sizeof(ucTmp), "%s", apcArgv[2]); + } else { + for (i = 2; i < i4Argc; i++) + i4TmpBufLen += + scnprintf((pucCurrBuf + i4TmpBufLen), + (sizeof(ucTmp) - i4TmpBufLen), + "%s", apcArgv[i]); + } + + DBGLOG(INIT, WARN, "Update to driver temp buffer as [%s]\n", + ucTmp); + + /* wlanCfgSet(prAdapter, apcArgv[1], apcArgv[2], 0); */ + /* Call by wlanoid because the set_cfg will trigger callback */ + kalStrnCpy(rKeyCfgInfo.aucKey, apcArgv[1], + WLAN_CFG_KEY_LEN_MAX - 1); + rKeyCfgInfo.aucKey[WLAN_CFG_KEY_LEN_MAX - 1] = '\0'; + kalStrnCpy(rKeyCfgInfo.aucValue, ucTmp, + WLAN_CFG_KEY_LEN_MAX - 1); + rKeyCfgInfo.aucValue[WLAN_CFG_KEY_LEN_MAX - 1] = '\0'; + rStatus = kalIoctl(prGlueInfo, wlanoidSetKeyCfg, &rKeyCfgInfo, + sizeof(rKeyCfgInfo), false, false, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + } + + return i4BytesWritten; +} /* priv_driver_set_cfg */ + +int priv_driver_get_cfg(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s8 aucValue[WLAN_CFG_VALUE_LEN_MAX]; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + prAdapter = prGlueInfo->prAdapter; + + if (i4Argc >= 2) { + /* by wlanoid ? */ + if (wlanCfgGet(prAdapter, apcArgv[1], aucValue, "", 0) == + WLAN_STATUS_SUCCESS) { + kalStrnCpy(pcCommand, aucValue, + WLAN_CFG_VALUE_LEN_MAX - 1); + pcCommand[WLAN_CFG_KEY_LEN_MAX - 1] = '\0'; + i4BytesWritten = kalStrnLen(pcCommand, + WLAN_CFG_VALUE_LEN_MAX - 1); + } + } + + return i4BytesWritten; +} /* priv_driver_get_cfg */ + +int priv_driver_set_chip_config(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + u32 u4CmdLen = 0; + u32 u4PrefixLen = 0; + /* s32 i4Argc = 0; */ + /* s8 * apcArgv[WLAN_CFG_ARGV_MAX] = {0}; */ + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + char *pcTmpCommand; + u32 u4StrLen; + + PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T rChipConfigInfo; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + /* wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); */ + /* DBGLOG(REQ, LOUD,("argc is %i\n",i4Argc)); */ + /* */ + + u4StrLen = kalStrLen(pcCommand); + pcTmpCommand = (char *)kalMemAlloc(u4StrLen + 1, VIR_MEM_TYPE); + + if (!pcTmpCommand) { + DBGLOG(REQ, ERROR, "TmpCmd : Memory alloc failed\n"); + return -1; + } + + kalStrnCpy(pcTmpCommand, pcCommand, u4StrLen); + pcTmpCommand[u4StrLen] = '\0'; + + wlanCfgParseArgument(pcTmpCommand, &i4Argc, apcArgv); + + /* KeepFullPower Enable cmd is blocked when entering suspend mode */ + if ((i4Argc == 3) && (apcArgv[0] != NULL) && (apcArgv[1] != NULL) && + (apcArgv[2] != NULL)) { + if ((kalStrnCmp("KeepFullPwr", apcArgv[1], 11) == 0) && + (kalStrnCmp("1", apcArgv[2], 1) == 0) && + (prGlueInfo->prAdapter->u4IsKeepFullPwrBitmap & + BLOCK_KEEP_FULL_PWR)) { + DBGLOG(REQ, STATE, + "KeepFullPower Enable Command is blocked\n"); + kalMemFree(pcTmpCommand, VIR_MEM_TYPE, u4StrLen + 1); + return 0; + } + } + + kalMemFree(pcTmpCommand, VIR_MEM_TYPE, u4StrLen + 1); + + u4CmdLen = kalStrnLen(pcCommand, i4TotalLen); + u4PrefixLen = kalStrLen(CMD_SET_CHIP) + 1 /*space */; + + kalMemZero(&rChipConfigInfo, sizeof(rChipConfigInfo)); + + /* if(i4Argc >= 2) { */ + if (u4CmdLen > u4PrefixLen) { + rChipConfigInfo.ucType = CHIP_CONFIG_TYPE_WO_RESPONSE; + /* rChipConfigInfo.u2MsgSize = + * kalStrnLen(apcArgv[1],CHIP_CONFIG_RESP_SIZE); */ + rChipConfigInfo.u2MsgSize = u4CmdLen - u4PrefixLen; + /* kalStrnCpy(rChipConfigInfo.aucCmd,apcArgv[1],CHIP_CONFIG_RESP_SIZE); + */ + kalStrnCpy(rChipConfigInfo.aucCmd, pcCommand + u4PrefixLen, + CHIP_CONFIG_RESP_SIZE - 1); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetChipConfig, + &rChipConfigInfo, sizeof(rChipConfigInfo), + false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, INFO, "%s: kalIoctl ret=%d\n", __func__, + rStatus); + i4BytesWritten = -1; + } + } + + return i4BytesWritten; +} /* priv_driver_set_chip_config */ + +void priv_driver_get_chip_config_16(u8 *pucStartAddr, u32 u4Length, u32 u4Line, + int i4TotalLen, s32 i4BytesWritten, + char *pcCommand) +{ + while (u4Length >= 16) { + if (i4TotalLen > i4BytesWritten) { + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%04lx %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x\n", + u4Line, + pucStartAddr[0], + pucStartAddr[1], + pucStartAddr[2], + pucStartAddr[3], + pucStartAddr[4], + pucStartAddr[5], + pucStartAddr[6], + pucStartAddr[7], + pucStartAddr[8], + pucStartAddr[9], + pucStartAddr[10], + pucStartAddr[11], + pucStartAddr[12], + pucStartAddr[13], + pucStartAddr[14], + pucStartAddr[15]); + } + + pucStartAddr += 16; + u4Length -= 16; + u4Line += 16; + } +} + +void priv_driver_get_chip_config_4(u32 *pu4StartAddr, u32 u4Length, u32 u4Line, + int i4TotalLen, s32 i4BytesWritten, + char *pcCommand) +{ + while (u4Length >= 16) { + if (i4TotalLen > i4BytesWritten) { + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%04lx %08lx %08lx %08lx %08lx\n", u4Line, + pu4StartAddr[0], pu4StartAddr[1], + pu4StartAddr[2], pu4StartAddr[3]); + } + + pu4StartAddr += 4; + u4Length -= 16; + u4Line += 4; + } +} + +int priv_driver_get_chip_config(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4BytesWritten = 0; + u32 u4BufLen = 0; + u32 u2MsgSize = 0; + u32 u4CmdLen = 0; + u32 u4PrefixLen = 0; + /* s32 i4Argc = 0; */ + /* s8 * apcArgv[WLAN_CFG_ARGV_MAX]; */ + + PARAM_CUSTOM_CHIP_CONFIG_STRUCT_T rChipConfigInfo; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + /* wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); */ + /* DBGLOG(REQ, LOUD,("argc is %i\n",i4Argc)); */ + + u4CmdLen = kalStrnLen(pcCommand, i4TotalLen); + u4PrefixLen = kalStrLen(CMD_GET_CHIP) + 1 /*space */; + + /* if(i4Argc >= 2) { */ + if (u4CmdLen > u4PrefixLen) { + rChipConfigInfo.ucType = CHIP_CONFIG_TYPE_ASCII; + /* rChipConfigInfo.u2MsgSize = + * kalStrnLen(apcArgv[1],CHIP_CONFIG_RESP_SIZE); */ + rChipConfigInfo.u2MsgSize = u4CmdLen - u4PrefixLen; + /* kalStrnCpy(rChipConfigInfo.aucCmd,apcArgv[1],CHIP_CONFIG_RESP_SIZE); + */ + kalStrnCpy(rChipConfigInfo.aucCmd, pcCommand + u4PrefixLen, + CHIP_CONFIG_RESP_SIZE - 1); + rStatus = kalIoctl(prGlueInfo, wlanoidQueryChipConfig, + &rChipConfigInfo, sizeof(rChipConfigInfo), + true, true, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, INFO, "%s: kalIoctl ret=%d\n", __func__, + rStatus); + return -1; + } + + /* Check respType */ + u2MsgSize = rChipConfigInfo.u2MsgSize; + DBGLOG(REQ, INFO, "%s: RespTyep %u\n", __func__, + rChipConfigInfo.ucRespType); + DBGLOG(REQ, INFO, "%s: u2MsgSize %u\n", __func__, + rChipConfigInfo.u2MsgSize); + + if (u2MsgSize > sizeof(rChipConfigInfo.aucCmd)) { + DBGLOG(REQ, INFO, "%s: u2MsgSize error ret=%u\n", + __func__, rChipConfigInfo.u2MsgSize); + return -1; + } + + if (u2MsgSize > 0) { + if (rChipConfigInfo.ucRespType == + CHIP_CONFIG_TYPE_ASCII) { + i4BytesWritten = snprintf( + pcCommand + i4BytesWritten, i4TotalLen, + "%s", rChipConfigInfo.aucCmd); + } else { + u32 u4Length; + u32 u4Line; + + if (rChipConfigInfo.ucRespType == + CHIP_CONFIG_TYPE_MEM8) { + u8 *pucStartAddr = NULL; + + pucStartAddr = + (u8 *)rChipConfigInfo.aucCmd; + /* align 16 bytes because one print line + * is 16 bytes */ + u4Length = (((u2MsgSize + 15) >> 4)) + << 4; + u4Line = 0; + priv_driver_get_chip_config_16( + pucStartAddr, u4Length, u4Line, + i4TotalLen, i4BytesWritten, + pcCommand); + } else { + u32 *pu4StartAddr = NULL; + + pu4StartAddr = + (u32 *)rChipConfigInfo.aucCmd; + /* align 16 bytes because one print line + * is 16 bytes */ + u4Length = (((u2MsgSize + 15) >> 4)) + << 4; + u4Line = 0; + + if (IS_ALIGN_4((unsigned long) + pu4StartAddr)) { + priv_driver_get_chip_config_4( + pu4StartAddr, u4Length, + u4Line, i4TotalLen, + i4BytesWritten, + pcCommand); + } else { + DBGLOG(REQ, + INFO, + "%s: rChipConfigInfo.aucCmd is not 4 bytes alignment %p\n", + __func__, + rChipConfigInfo.aucCmd); + } + } /* ChipConfigInfo.ucRespType */ + } + } + /* u2MsgSize > 0 */ + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, + pcCommand); + } + /* i4Argc */ + return i4BytesWritten; +} /* priv_driver_get_chip_config */ + +int priv_driver_set_ap_start(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + PARAM_CUSTOM_P2P_SET_STRUCT_T rSetP2P; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Ret; + s32 i4ArgNum = 2; + + kalMemZero(&rSetP2P, sizeof(PARAM_CUSTOM_P2P_SET_STRUCT_T)); + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= i4ArgNum) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &(rSetP2P.u4Mode)); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "parse ap-start error (u4Enable) u4Ret=%d\n", + u4Ret); + return -1; + } + + if (rSetP2P.u4Mode >= RUNNING_P2P_MODE_NUM) { + rSetP2P.u4Mode = 0; + rSetP2P.u4Enable = 0; + } else { + rSetP2P.u4Enable = 1; + } + + if (set_p2p_mode_handler(prNetDev, rSetP2P) != 0) { + DBGLOG(REQ, ERROR, "set_p2p_mode_handler falied\n"); + } + } + + return 0; +} + +int priv_driver_get_linkspeed(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + u32 u4Rate = 0; + u32 u4LinkSpeed = 0; + s32 i4BytesWritten = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (!netif_carrier_ok(prNetDev)) { + return -1; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryLinkSpeed, &u4Rate, + sizeof(u4Rate), true, true, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + u4LinkSpeed = u4Rate * 100; + i4BytesWritten = snprintf(pcCommand, i4TotalLen, "LinkSpeed %u", + (unsigned int)u4LinkSpeed); + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand); + return i4BytesWritten; +} + +int priv_driver_set_band(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Argc = 0; + u32 ucBand = 0; + u8 ucBssIndex; + ENUM_BAND_T eBand = BAND_NULL; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 u4Ret = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + prAdapter = prGlueInfo->prAdapter; + if (i4Argc >= 2) { + /* ucBand = kalStrtoul(apcArgv[1], NULL, 0); */ + u4Ret = kalkStrtou32(apcArgv[1], 0, &ucBand); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucBand error u4Ret=%d\n", + u4Ret); + return -1; + } + + ucBssIndex = wlanGetAisBssIndex(prGlueInfo->prAdapter); + eBand = BAND_NULL; + if (ucBand == CMD_BAND_5G) { + eBand = BAND_5G; + }else if (ucBand == CMD_BAND_2G) { + eBand = BAND_2G4; + } + prAdapter->aePreferBand[ucBssIndex] = eBand; + /* XXX call wlanSetPreferBandByNetwork directly in different + * thread */ + /* wlanSetPreferBandByNetwork (prAdapter, eBand, ucBssIndex); */ + } + + return 0; +} + +int priv_driver_set_txpower(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + P_SET_TXPWR_CTRL_T prTxpwr; + u16 i; + s32 u4Ret = 0; + s32 ai4Setting[4]; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + prTxpwr = &prGlueInfo->rTxPwr; + + if (i4Argc >= 3 && i4Argc <= 5) { + for (i = 0; i < (i4Argc - 1); i++) { + /* ai4Setting[i] = kalStrtol(apcArgv[i + 1], NULL, 0); + */ + u4Ret = kalkStrtos32(apcArgv[i + 1], 0, + &(ai4Setting[i])); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "parse apcArgv error u4Ret=%d\n", u4Ret); + } + } + } else { + DBGLOG(REQ, INFO, "set_txpower wrong argc : %d\n", i4Argc); + return -1; + } + + /* + * ai4Setting[0] + * 0 : Set TX power offset for specific network + * 1 : Set TX power offset policy when multiple networks are in the + * same channel 2 : Set TX power limit for specific channel in 2.4GHz + * band 3 : Set TX power limit of specific sub-band in 5GHz band 4 : + * Enable or reset setting + */ + if (ai4Setting[0] == 0 && (i4Argc - 1) == 4 /* argc num */ ) { + /* ai4Setting[1] : 0 (All networks), 1 (legacy STA), 2 (Hotspot + * AP), 3 (P2P), 4 (BT over Wi-Fi) */ + /* ai4Setting[2] : 0 (All bands),1 (2.4G), 2 (5G) */ + /* ai4Setting[3] : -30 ~ 20 in unit of 0.5dBm (default: 0) */ + if (ai4Setting[1] == 1 || ai4Setting[1] == 0) { + if (ai4Setting[2] == 0 || ai4Setting[2] == 1) { + prTxpwr->c2GLegacyStaPwrOffset = ai4Setting[3]; + } + if (ai4Setting[2] == 0 || ai4Setting[2] == 2) { + prTxpwr->c5GLegacyStaPwrOffset = ai4Setting[3]; + } + } + if (ai4Setting[1] == 2 || ai4Setting[1] == 0) { + if (ai4Setting[2] == 0 || ai4Setting[2] == 1) { + prTxpwr->c2GHotspotPwrOffset = ai4Setting[3]; + } + if (ai4Setting[2] == 0 || ai4Setting[2] == 2) { + prTxpwr->c5GHotspotPwrOffset = ai4Setting[3]; + } + } + if (ai4Setting[1] == 3 || ai4Setting[1] == 0) { + if (ai4Setting[2] == 0 || ai4Setting[2] == 1) { + prTxpwr->c2GP2pPwrOffset = ai4Setting[3]; + } + if (ai4Setting[2] == 0 || ai4Setting[2] == 2) { + prTxpwr->c5GP2pPwrOffset = ai4Setting[3]; + } + } + if (ai4Setting[1] == 4 || ai4Setting[1] == 0) { + if (ai4Setting[2] == 0 || ai4Setting[2] == 1) { + prTxpwr->c2GBowPwrOffset = ai4Setting[3]; + } + if (ai4Setting[2] == 0 || ai4Setting[2] == 2) { + prTxpwr->c5GBowPwrOffset = ai4Setting[3]; + } + } + } else if (ai4Setting[0] == 1 && (i4Argc - 1) == 2) { + /* ai4Setting[1] : 0 (highest power is used) (default), 1 + * (lowest power is used) */ + prTxpwr->ucConcurrencePolicy = ai4Setting[1]; + } else if (ai4Setting[0] == 2 && (i4Argc - 1) == 3) { + /* ai4Setting[1] : 0 (all channels in 2.4G), 1~14 */ + /* ai4Setting[2] : 10 ~ 46 in unit of 0.5dBm (default: 46) */ + if (ai4Setting[1] == 0) { + for (i = 0; i < 14; i++) + prTxpwr->acTxPwrLimit2G[i] = ai4Setting[2]; + } else if (ai4Setting[1] <= 14) { + prTxpwr->acTxPwrLimit2G[ai4Setting[1] - 1] = + ai4Setting[2]; + } + } else if (ai4Setting[0] == 3 && (i4Argc - 1) == 3) { + /* ai4Setting[1] : 0 (all sub-bands in 5G), + * 1 (5000 ~ 5250MHz), + * 2 (5255 ~ 5350MHz), + * 3 (5355 ~ 5725MHz), + * 4 (5730 ~ 5825MHz) + */ + /* ai4Setting[2] : 10 ~ 46 in unit of 0.5dBm (default: 46) */ + if (ai4Setting[1] == 0) { + for (i = 0; i < 4; i++) + prTxpwr->acTxPwrLimit5G[i] = ai4Setting[2]; + } else if (ai4Setting[1] <= 4) { + prTxpwr->acTxPwrLimit5G[ai4Setting[1] - 1] = + ai4Setting[2]; + } + } else if (ai4Setting[0] == 4 && (i4Argc - 1) == 2) { + /* ai4Setting[1] : 1 (enable), 0 (reset and disable) */ + if (ai4Setting[1] == 0) { + wlanDefTxPowerCfg(prGlueInfo->prAdapter); + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetTxPower, prTxpwr, + sizeof(SET_TXPWR_CTRL_T), false, false, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + } else { + return -EFAULT; + } + + return 0; +} +#if CFG_SUPPORT_DBDC_TC6 +int priv_driver_set_csa(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 ch_num = 0; + s32 u4Ret = 0; + P_P2P_ROLE_FSM_INFO_T prP2pRoleFsmInfo = (P_P2P_ROLE_FSM_INFO_T)NULL; + P_BSS_INFO_T prBssInfo; + u32 i4BytesWritten = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, INFO, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, INFO, "argc is %i\n", i4Argc); + + prBssInfo = cnmGetp2pSapBssInfo(prGlueInfo->prAdapter); + if (prBssInfo == NULL) { + return -1; + } + + prP2pRoleFsmInfo = P2P_ROLE_INDEX_2_ROLE_FSM_INFO( + prGlueInfo->prAdapter, prBssInfo->u4PrivateData); + + if (i4Argc >= 2) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &ch_num); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ch_num error u4Ret=%d\n", + u4Ret); + return -1; + } + + u4Ret = cnmIdcCsaReq(prGlueInfo->prAdapter, ch_num, + prP2pRoleFsmInfo->ucRoleIndex); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "P2P role:%d send CSA\n", prP2pRoleFsmInfo->ucRoleIndex); + DBGLOG(REQ, INFO, "u4Ret is %d\n", u4Ret); + } else { + DBGLOG(REQ, INFO, "Input insufficent\n"); + } + + return i4BytesWritten; +} +#endif +int priv_driver_set_country(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u8 aucCountry[2]; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + if (i4Argc < 2) { + DBGLOG(REQ, WARN, "%s: argc is %d, need >=2\n", __func__, + i4Argc); + return -1; + } + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (regd_is_single_sku_en()) { + u8 aucCountry_code[4] = { 0, 0, 0, 0 }; + u8 i, count; + + /* command like "COUNTRY US", "COUNTRY US1" and "COUNTRY US01" + */ + count = kalStrnLen(apcArgv[1], sizeof(aucCountry_code)); + for (i = 0; i < count; i++) + aucCountry_code[i] = apcArgv[1][i]; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetCountryCode, + &aucCountry_code[0], count, false, false, + true, &u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + return 0; + } + + /* command like "COUNTRY US", "COUNTRY EU" and "COUNTRY JP" */ + aucCountry[0] = apcArgv[1][0]; + aucCountry[1] = apcArgv[1][1]; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetCountryCode, &aucCountry[0], 2, + false, false, true, &u4BufLen); + + return 0; +} + +int priv_driver_get_country(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u32 i4BytesWritten = 0; + u32 country = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (!regd_is_single_sku_en()) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "Not Supported."); + return i4BytesWritten; + } + + country = rlmDomainGetCountryCode(); + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nCountry Code: \"%s\" (0x%x)", &country, country); + + return i4BytesWritten; +} + +int priv_driver_get_channels(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + u32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; +#if (CFG_SUPPORT_SINGLE_SKU == 1) + u32 ch_idx, start_idx, end_idx; + struct channel *pCh; + u32 ch_num = 0; + u8 maxbw = 160; + u32 u4Ret = 0; +#endif + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (!regd_is_single_sku_en()) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "Not Supported."); + return i4BytesWritten; + } + +#if (CFG_SUPPORT_SINGLE_SKU == 1) + /** + * Usage: iwpriv wlan0 driver "get_channels [2g |5g |ch_num]" + **/ + if (i4Argc >= 2 && (apcArgv[1][0] == '2') && (apcArgv[1][1] == 'g')) { + start_idx = 0; + end_idx = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ); + } else if (i4Argc >= 2 && (apcArgv[1][0] == '5') && + (apcArgv[1][1] == 'g')) { + start_idx = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ); + end_idx = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ) + + rlmDomainGetActiveChannelCount(NL80211_BAND_5GHZ); + } else { + start_idx = 0; + end_idx = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ) + + rlmDomainGetActiveChannelCount(NL80211_BAND_5GHZ); + if (i4Argc >= 2) { + /* Dump only specified channel */ + u4Ret = kalkStrtou32(apcArgv[1], 0, &ch_num); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "parse ch_num error u4Ret=%d\n", u4Ret); + return -1; + } + } + } + + if (regd_is_single_sku_en()) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "\n"); + + for (ch_idx = start_idx; ch_idx < end_idx; ch_idx++) { + pCh = (rlmDomainGetActiveChannels() + ch_idx); + + if (ch_num && (ch_num != pCh->chNum)) { + continue; /*show specific channel information*/ + + } + /* Channel number */ + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "CH-%d:", pCh->chNum); + /* Active/Passive */ + if (pCh->flags & IEEE80211_CHAN_NO_IR) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "NO_IR "); + } else { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + " ACTIVE"); + } + /* Max BW */ + if ((pCh->flags & IEEE80211_CHAN_NO_160MHZ) == + IEEE80211_CHAN_NO_160MHZ) { + maxbw = 80; + } + if ((pCh->flags & IEEE80211_CHAN_NO_80MHZ) == + IEEE80211_CHAN_NO_80MHZ) { + maxbw = 40; + } + if ((pCh->flags & IEEE80211_CHAN_NO_HT40) == + IEEE80211_CHAN_NO_HT40) { + maxbw = 20; + } + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + " BW_%dMHz", maxbw); + /* Channel flags */ + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + " (flags=0x%x)\n", pCh->flags); + } + } +#endif + + return i4BytesWritten; +} + +int priv_driver_get_ap_channels(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + u32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; +#if (CFG_SUPPORT_SINGLE_SKU == 1) + u32 ch_idx, start_idx, end_idx; + struct channel *pCh; + u32 ch_num = 0; + u8 maxbw = 160; + u32 u4Ret = 0; +#endif + P_ADAPTER_T prAdapter = NULL; + P_WIFI_VAR_T prWifiVar = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + prAdapter = prGlueInfo->prAdapter; + prWifiVar = &prAdapter->rWifiVar; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (!regd_is_single_sku_en()) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "Not Supported."); + return i4BytesWritten; + } + +#if (CFG_SUPPORT_SINGLE_SKU == 1) + /** + * Usage: iwpriv wlan0 driver "get_channels [2g |5g |ch_num]" + **/ + if (i4Argc >= 2 && (apcArgv[1][0] == '2') && (apcArgv[1][1] == 'g')) { + start_idx = 0; + end_idx = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ); + } else if (i4Argc >= 2 && (apcArgv[1][0] == '5') && + (apcArgv[1][1] == 'g')) { + start_idx = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ); + end_idx = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ) + + rlmDomainGetActiveChannelCount(NL80211_BAND_5GHZ); + } else { + start_idx = 0; + end_idx = rlmDomainGetActiveChannelCount(NL80211_BAND_2GHZ) + + rlmDomainGetActiveChannelCount(NL80211_BAND_5GHZ); + if (i4Argc >= 2) { + /* Dump only specified channel */ + u4Ret = kalkStrtou32(apcArgv[1], 0, &ch_num); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "parse ucBand error u4Ret=%d\n", u4Ret); + return -1; + } + } + } + + if (regd_is_single_sku_en()) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "\n"); + + for (ch_idx = start_idx; ch_idx < end_idx; ch_idx++) { + u8 ApMaxbw = 0; + + pCh = (rlmDomainGetActiveChannels() + ch_idx); + + if (ch_num && (ch_num != pCh->chNum)) { + continue; /*show specific channel information*/ + + } + /* Channel number */ + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "CH-%d:", pCh->chNum); + /* Active/Passive */ + if (pCh->flags & IEEE80211_CHAN_NO_IR) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + " NO_IR"); + } else { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + " ACTIVE"); + } + /* Max BW */ + if ((pCh->flags & IEEE80211_CHAN_NO_160MHZ) == + IEEE80211_CHAN_NO_160MHZ) { + maxbw = 80; + } + if ((pCh->flags & IEEE80211_CHAN_NO_80MHZ) == + IEEE80211_CHAN_NO_80MHZ) { + maxbw = 40; + } + if ((pCh->flags & IEEE80211_CHAN_NO_HT40) == + IEEE80211_CHAN_NO_HT40) { + maxbw = 20; + } + + // Checking 2G BW setting + if (pCh->chNum < 13) { + switch (prWifiVar->ucAp2gBandwidth) { + case MAX_BW_40MHZ: + ApMaxbw = 40; + break; + + case MAX_BW_20MHZ: + ApMaxbw = 20; + break; + + default: + ApMaxbw = 40; + break; + } + } else { + switch (prWifiVar->ucAp5gBandwidth) { + case MAX_BW_80MHZ: + ApMaxbw = 80; + break; + + case MAX_BW_40MHZ: + ApMaxbw = 40; + break; + + case MAX_BW_20MHZ: + ApMaxbw = 20; + break; + + default: + ApMaxbw = 80; + break; + } + } + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + " BW_%dMHz", + ((maxbw <= ApMaxbw) ? (maxbw) : (ApMaxbw))); + /* Channel flags */ + LOGBUF(pcCommand, + i4TotalLen, + i4BytesWritten, + " (flags=0x%x)\n", + pCh->flags); + } + } +#endif + + return i4BytesWritten; +} + +#if (CFG_SUPPORT_DFS_MASTER == 1) +int priv_driver_show_dfs_state(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "\nDFS State: \"%s\"", + p2pFuncShowDfsState()); + + return i4BytesWritten; +} + +int priv_driver_show_dfs_abd123_param(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + u8 ucCnt = 0; + struct P2P_RADAR_INFO *prP2pabd123Info = NULL; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + prP2pabd123Info = (struct P2P_RADAR_INFO *)cnmMemAlloc( + prGlueInfo->prAdapter, RAM_TYPE_MSG, sizeof(*prP2pabd123Info)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + p2pFuncGetRadarInfo(prP2pabd123Info); + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "\nRDD idx: %d\n", + prP2pabd123Info->ucRddIdx); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nLong Pulse detected: %d\n", prP2pabd123Info->ucLongDetected); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nPeriodic Pulse detected: %d\n", + prP2pabd123Info->ucPeriodicDetected); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "\nLPB Num: %d\n", + prP2pabd123Info->ucLPBNum); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "\nPPB Num: %d\n", + prP2pabd123Info->ucPPBNum); + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n==========================="); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nLong Pulse Buffer Contents:\n"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\npulse_time pulse_width PRI\n"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "\n%-10d %-11d -\n", + prP2pabd123Info->arLpbContent[ucCnt].u4LongStartTime, + prP2pabd123Info->arLpbContent[ucCnt].u2LongPulseWidth); + for (ucCnt = 1; ucCnt < prP2pabd123Info->ucLPBNum; ucCnt++) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n%-10d %-11d %d\n", + prP2pabd123Info->arLpbContent[ucCnt].u4LongStartTime, + prP2pabd123Info->arLpbContent[ucCnt].u2LongPulseWidth, + (prP2pabd123Info->arLpbContent[ucCnt].u4LongStartTime - + prP2pabd123Info->arLpbContent[ucCnt - 1] + .u4LongStartTime) * + 2 / 5); + } + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "\nLPB Period Valid: %d", + prP2pabd123Info->ucLPBPeriodValid); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nLPB Period Valid: %d\n", prP2pabd123Info->ucLPBWidthValid); + + ucCnt = 0; + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n==========================="); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nPeriod Pulse Buffer Contents:\n"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\npulse_time pulse_width PRI\n"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "\n%-10d %-11d -\n", + prP2pabd123Info->arPpbContent[ucCnt].u4PeriodicStartTime, + prP2pabd123Info->arPpbContent[ucCnt].u2PeriodicPulseWidth); + for (ucCnt = 1; ucCnt < prP2pabd123Info->ucPPBNum; ucCnt++) { + LOGBUF(pcCommand, + i4TotalLen, + i4BytesWritten, + "\n%-10d %-11d %d\n", + prP2pabd123Info->arPpbContent[ucCnt].u4PeriodicStartTime, + prP2pabd123Info->arPpbContent[ucCnt].u2PeriodicPulseWidth, + (prP2pabd123Info->arPpbContent[ucCnt].u4PeriodicStartTime + - + prP2pabd123Info->arPpbContent[ucCnt - 1] + .u4PeriodicStartTime) * + 2 / 5); + } + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nPRI Count M1 TH: %d; PRI Count M1: %d", + prP2pabd123Info->ucPRICountM1TH, prP2pabd123Info->ucPRICountM1); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nPRI Count M2 TH: %d; PRI Count M2: %d", + prP2pabd123Info->ucPRICountM2TH, prP2pabd123Info->ucPRICountM2); + + cnmMemFree(prGlueInfo->prAdapter, prP2pabd123Info); + + return i4BytesWritten; +} + +int priv_driver_show_dfs_help(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n--iwpriv wlanX driver \"show_dfs_state\"\n"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nINACTIVE: RDD disable or temporary RDD disable"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nCHECKING: During CAC time"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nACTIVE : In-serive monitoring"); + LOGBUF(pcCommand, + i4TotalLen, + i4BytesWritten, + "\nDETECTED: Has detected abd123 but hasn't moved to new channel\n"); + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n--iwpriv wlanX driver \"show_dfs_abd123_param\"\n"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nShow the latest pulse information\n"); + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n--iwpriv wlanX driver \"show_dfs_cac_time\"\n"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nShow the remaining time of CAC\n"); + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n--iwpriv wlanX set ByPassCac=yy\n"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nValue yy: set the time of CAC\n"); + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n--iwpriv wlanX set RDDReport=yy\n"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nValue yy is \"0\" or \"1\""); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n\"0\": Emulate RDD0 manual abd123 event"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n\"1\": Emulate RDD1 manual abd123 event\n"); + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n--iwpriv wlanX set abd123DetectMode=yy\n"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nValue yy is \"0\" or \"1\""); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n\"0\": Switch channel when abd123 detected (default)"); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n\"1\": Do not switch channel when abd123 detected"); + + return i4BytesWritten; +} + +int priv_driver_show_dfs_cac_time(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (p2pFuncGetDfsState() != DFS_STATE_CHECKING) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nNot in CAC period"); + return i4BytesWritten; + } + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nRemaining time of CAC: %dsec", p2pFuncGetCacRemainingTime()); + + return i4BytesWritten; +} + +int priv_driver_set_rdd_report(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + // u32 u4Ret; + s32 i4ArgNum = 2; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= i4ArgNum) { + SetRddReport(prNetDev, apcArgv[1]); + } + + return 0; +} + +int priv_driver_clean_dfs_abd123_param(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4BytesWritten = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + p2pFuncRadarInfoInit(); + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nClean up abd123 param\n"); + return i4BytesWritten; +} + +int priv_driver_set_abd123_detect_mode(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Ret; + s32 i4ArgNum = 2; + u8 ucabd123DetectMode; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= i4ArgNum) { + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucabd123DetectMode); + if (u4Ret) { + DBGLOG(REQ, LOUD, + "parse abd123 detect mode error - u4Ret=%d\n", + u4Ret); + return -1; + } + if (p2pFuncGetDfsState() == DFS_STATE_INACTIVE || + p2pFuncGetDfsState() == DFS_STATE_DETECTED) { + DBGLOG(REQ, + ERROR, + "RDD Report is not supported in this DFS state (inactive or deteted)\n"); + return -1; + } + + if (ucabd123DetectMode != 0 && ucabd123DetectMode != 1) { + DBGLOG(REQ, + ERROR, + "abd123 Detect Mode is not \"0\" or \"1\", Invalid data\n"); + return -1; + } + + p2pFuncSetRadarDetectMode(ucabd123DetectMode); + + if (MT_ATESetRadarDetectMode(prNetDev, ucabd123DetectMode) != 0) { + return -1; + } + } + + return 0; +} + +#endif +#ifdef CFG_SUPPORT_ADJUST_MCC_STAY_TIME +int priv_driver_set_mcc_time(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Argc = 0; + u32 i4BytesWritten = 0; + u32 ucLinkType = 0; /* 0 for AIS and 1 for P2P */ + u32 ucStayTime = 0; /* In unit of us */ + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 i4Ret = 0; + + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + prAdapter = prGlueInfo->prAdapter; + if (i4Argc != 3) { + goto out; + } + + i4Ret = kalkStrtou32(apcArgv[1], 0, &ucLinkType); + if (i4Ret) { + DBGLOG(REQ, LOUD, "parse ucLinkType error i4Ret=%d\n", i4Ret); + goto out; + } + i4Ret = kalkStrtou32(apcArgv[2], 0, &ucStayTime); + if (i4Ret) { + DBGLOG(REQ, LOUD, "parse ucStayTime error i4Ret=%d\n", i4Ret); + goto out; + } + if (ucLinkType == NETWORK_TYPE_AIS) { + snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mccTime 0 %d", + ucStayTime); + } else if (ucLinkType == NETWORK_TYPE_P2P) { + snprintf(pcCommand, i4TotalLen, CMD_SET_CHIP " mccTime 1 %d", + ucStayTime); + } else { + DBGLOG(REQ, LOUD, "Wrong network type %i\n", ucLinkType); + i4BytesWritten = -1; + goto out; + } + priv_driver_set_chip_config(prNetDev, pcCommand, i4TotalLen); +out: + return i4BytesWritten; +} +#endif +int priv_driver_set_miracast(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_ADAPTER_T prAdapter = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + u32 i4BytesWritten = 0; + /* WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; */ + /* u32 u4BufLen = 0; */ + s32 i4Argc = 0; + u32 ucMode = 0; + P_WFD_CFG_SETTINGS_T prWfdCfgSettings = (P_WFD_CFG_SETTINGS_T)NULL; + P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T prMsgWfdCfgUpdate = + (P_MSG_WFD_CONFIG_SETTINGS_CHANGED_T)NULL; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + s32 u4Ret = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + prAdapter = prGlueInfo->prAdapter; + if (i4Argc >= 2) { + /* ucMode = kalStrtoul(apcArgv[1], NULL, 0); */ + u4Ret = kalkStrtou32(apcArgv[1], 0, &ucMode); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucMode error u4Ret=%d\n", + u4Ret); + return -1; + } + + if (g_ucMiracastMode == (u8)ucMode) { + /* XXX: continue or skip */ + /* XXX: continue or skip */ + } + + g_ucMiracastMode = (u8)ucMode; + prMsgWfdCfgUpdate = + cnmMemAlloc(prAdapter, RAM_TYPE_MSG, + sizeof(MSG_WFD_CONFIG_SETTINGS_CHANGED_T)); + + if (prMsgWfdCfgUpdate != NULL) { + prWfdCfgSettings = + &(prAdapter->rWifiVar.rWfdConfigureSettings); + prMsgWfdCfgUpdate->rMsgHdr.eMsgId = + MID_MNY_P2P_WFD_CFG_UPDATE; + prMsgWfdCfgUpdate->prWfdCfgSettings = prWfdCfgSettings; + + if (ucMode == MIRACAST_MODE_OFF) { + prWfdCfgSettings->ucWfdEnable = 0; + snprintf(pcCommand, i4TotalLen, + CMD_SET_CHIP " mira 0"); + } else if (ucMode == MIRACAST_MODE_SOURCE) { + prWfdCfgSettings->ucWfdEnable = 1; + snprintf(pcCommand, i4TotalLen, + CMD_SET_CHIP " mira 1"); + } else if (ucMode == MIRACAST_MODE_SINK) { + prWfdCfgSettings->ucWfdEnable = 2; + snprintf(pcCommand, i4TotalLen, + CMD_SET_CHIP " mira 2"); + } else { + prWfdCfgSettings->ucWfdEnable = 0; + snprintf(pcCommand, i4TotalLen, + CMD_SET_CHIP " mira 0"); + } + + mboxSendMsg(prAdapter, MBOX_ID_0, + (P_MSG_HDR_T)prMsgWfdCfgUpdate, + MSG_SEND_METHOD_BUF); + + priv_driver_set_chip_config(prNetDev, pcCommand, + i4TotalLen); + } else { + ASSERT(false); + i4BytesWritten = -1; + } + } + + /* i4Argc */ + return i4BytesWritten; +} + +#if CFG_WOW_SUPPORT +static int priv_driver_set_wow(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_WOW_CTRL_T pWOW_CTRL = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Ret = 0; + u32 Enable = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + pWOW_CTRL = &prGlueInfo->prAdapter->rWowCtrl; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + if (i4Argc < 2) { + DBGLOG(REQ, WARN, "%s: argc is %d, need >=2\n", __func__, + i4Argc); + return -1; + } + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + u4Ret = kalkStrtou32(apcArgv[1], 0, &Enable); + + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse bEnable error u4Ret=%d\n", u4Ret); + return -1; + } + + DBGLOG(INIT, INFO, "CMD set_wow_enable = %d\n", Enable); + DBGLOG(INIT, INFO, "Scenario ID %d\n", pWOW_CTRL->ucScenarioId); + DBGLOG(INIT, INFO, "ucBlockCount %d\n", pWOW_CTRL->ucBlockCount); + DBGLOG(INIT, INFO, "interface %d\n", + pWOW_CTRL->astWakeHif[0].ucWakeupHif); + DBGLOG(INIT, INFO, "gpio_pin %d\n", pWOW_CTRL->astWakeHif[0].ucGpioPin); + DBGLOG(INIT, INFO, "gpio_level 0x%x\n", + pWOW_CTRL->astWakeHif[0].ucTriggerLvl); + DBGLOG(INIT, INFO, "gpio_timer %d\n", + pWOW_CTRL->astWakeHif[0].u4GpioInterval); + kalWowProcess(prGlueInfo, Enable); + + return 0; +} + +static int priv_driver_set_wow_enable(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_WOW_CTRL_T pWOW_CTRL = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Ret = 0; + u8 ucEnable = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + pWOW_CTRL = &prGlueInfo->prAdapter->rWowCtrl; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + if (i4Argc < 2) { + DBGLOG(REQ, WARN, "%s: argc is %d, need >=2\n", __func__, + i4Argc); + return -1; + } + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= 2) { + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucEnable); + + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse bEnable error u4Ret=%d\n", + u4Ret); + } + + pWOW_CTRL->fgWowEnable = ucEnable; + + DBGLOG(PF, INFO, "WOW enable %d\n", pWOW_CTRL->fgWowEnable); + + return 0; + } else { + return -1; + } +} + +static int priv_driver_set_wow_par(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_WOW_CTRL_T pWOW_CTRL = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 u4Ret = 0; + u8 ucWakeupHif = 0, GpioPin = 0, ucGpioLevel = 0, ucBlockCount, + ucScenario = 0; + u32 u4GpioTimer = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + pWOW_CTRL = &prGlueInfo->prAdapter->rWowCtrl; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= 7) { + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucWakeupHif); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucWakeupHif error u4Ret=%d\n", + u4Ret); + } + pWOW_CTRL->astWakeHif[0].ucWakeupHif = ucWakeupHif; + + u4Ret = kalkStrtou8(apcArgv[2], 0, &GpioPin); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse GpioPin error u4Ret=%d\n", + u4Ret); + } + pWOW_CTRL->astWakeHif[0].ucGpioPin = GpioPin; + + u4Ret = kalkStrtou8(apcArgv[3], 0, &ucGpioLevel); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse Gpio level error u4Ret=%d\n", + u4Ret); + } + pWOW_CTRL->astWakeHif[0].ucTriggerLvl = ucGpioLevel; + + u4Ret = kalkStrtou32(apcArgv[4], 0, &u4GpioTimer); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse u4GpioTimer error u4Ret=%d\n", + u4Ret); + return -1; + } + + pWOW_CTRL->astWakeHif[0].u4GpioInterval = u4GpioTimer; + + u4Ret = kalkStrtou8(apcArgv[5], 0, &ucScenario); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucScenario error u4Ret=%d\n", + u4Ret); + } + pWOW_CTRL->ucScenarioId = ucScenario; + + u4Ret = kalkStrtou8(apcArgv[6], 0, &ucBlockCount); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucBlockCnt error u4Ret=%d\n", + u4Ret); + } + pWOW_CTRL->ucBlockCount = ucBlockCount; + + DBGLOG(INIT, INFO, "gpio_scenario%d\n", + pWOW_CTRL->ucScenarioId); + DBGLOG(INIT, INFO, "interface %d\n", + pWOW_CTRL->astWakeHif[0].ucWakeupHif); + DBGLOG(INIT, INFO, "gpio_pin %d\n", + pWOW_CTRL->astWakeHif[0].ucGpioPin); + DBGLOG(INIT, INFO, "gpio_level %d\n", + pWOW_CTRL->astWakeHif[0].ucTriggerLvl); + DBGLOG(INIT, INFO, "gpio_timer %d\n", + pWOW_CTRL->astWakeHif[0].u4GpioInterval); + + return 0; + } else { + return -1; + } +} + +static int priv_driver_set_wow_udpport(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_WOW_CTRL_T pWOW_CTRL = NULL; + s32 i4Argc = 0; + s8 *apcPortArgv[WLAN_CFG_ARGV_MAX_LONG] = { 0 }; /* to input 20 port */ + s32 u4Ret = 0, ii; + u8 ucVer, ucCount; + u16 u2Port = 0; + u16 *pausPortArry; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + pWOW_CTRL = &prGlueInfo->prAdapter->rWowCtrl; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgumentLong(pcCommand, &i4Argc, apcPortArgv); + DBGLOG(REQ, WARN, "argc is %i\n", i4Argc); + + /* example: set_wow_udp 0 5353,8080 (set) */ + /* example: set_wow_udp 1 (clear) */ + + if (i4Argc >= 3) { + /* Pick Max */ + ucCount = ((i4Argc - 2) > MAX_TCP_UDP_PORT) ? MAX_TCP_UDP_PORT : + (i4Argc - 2); + DBGLOG(PF, INFO, "UDP ucCount=%d\n", ucCount); + + u4Ret = kalkStrtou8(apcPortArgv[1], 0, &ucVer); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucWakeupHif error u4Ret=%d\n", + u4Ret); + return -1; + } + + /* IPv4/IPv6 */ + DBGLOG(PF, INFO, "ucVer=%d\n", ucVer); + if (ucVer == 0) { + pWOW_CTRL->stWowPort.ucIPv4UdpPortCnt = ucCount; + pausPortArry = pWOW_CTRL->stWowPort.ausIPv4UdpPort; + } else { + pWOW_CTRL->stWowPort.ucIPv6UdpPortCnt = ucCount; + pausPortArry = pWOW_CTRL->stWowPort.ausIPv6UdpPort; + } + + /* Port */ + for (ii = 0; ii < ucCount; ii++) { + u4Ret = kalkStrtou16(apcPortArgv[ii + 2], 0, &u2Port); + if (u4Ret) { + DBGLOG(PF, ERROR, + "parse u2Port error u4Ret=%d\n", u4Ret); + return -1; + } + + pausPortArry[ii] = u2Port; + DBGLOG(PF, INFO, "ucPort=%d, idx=%d\n", u2Port, ii); + } + + return 0; + } else if (i4Argc == 2) { + u4Ret = kalkStrtou8(apcPortArgv[1], 0, &ucVer); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucWakeupHif error u4Ret=%d\n", + u4Ret); + return -1; + } + + if (ucVer == 0) { + kalMemZero(prGlueInfo->prAdapter->rWowCtrl.stWowPort + .ausIPv4UdpPort, + sizeof(u16) * MAX_TCP_UDP_PORT); + prGlueInfo->prAdapter->rWowCtrl.stWowPort + .ucIPv4UdpPortCnt = 0; + } else { + kalMemZero(prGlueInfo->prAdapter->rWowCtrl.stWowPort + .ausIPv6UdpPort, + sizeof(u16) * MAX_TCP_UDP_PORT); + prGlueInfo->prAdapter->rWowCtrl.stWowPort + .ucIPv6UdpPortCnt = 0; + } + + return 0; + } else { + return -1; + } +} + +static int priv_driver_set_wow_tcpport(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_WOW_CTRL_T pWOW_CTRL = NULL; + s32 i4Argc = 0; + s8 *apcPortArgv[WLAN_CFG_ARGV_MAX_LONG] = { 0 }; /* to input 20 port */ + s32 u4Ret = 0, ii; + u8 ucVer, ucCount; + u16 u2Port = 0; + u16 *pausPortArry; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + pWOW_CTRL = &prGlueInfo->prAdapter->rWowCtrl; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgumentLong(pcCommand, &i4Argc, apcPortArgv); + DBGLOG(REQ, WARN, "argc is %i\n", i4Argc); + + /* example: set_wow_tcp 0 5353,8080 (Set) */ + /* example: set_wow_tcp 1 (clear) */ + + if (i4Argc >= 3) { + /* Pick Max */ + ucCount = ((i4Argc - 2) > MAX_TCP_UDP_PORT) ? MAX_TCP_UDP_PORT : + (i4Argc - 2); + DBGLOG(PF, INFO, "TCP ucCount=%d\n", ucCount); + + u4Ret = kalkStrtou8(apcPortArgv[1], 0, &ucVer); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucWakeupHif error u4Ret=%d\n", + u4Ret); + return -1; + } + + /* IPv4/IPv6 */ + DBGLOG(PF, INFO, "Ver=%d\n", ucVer); + if (ucVer == 0) { + pWOW_CTRL->stWowPort.ucIPv4TcpPortCnt = ucCount; + pausPortArry = pWOW_CTRL->stWowPort.ausIPv4TcpPort; + } else { + pWOW_CTRL->stWowPort.ucIPv6TcpPortCnt = ucCount; + pausPortArry = pWOW_CTRL->stWowPort.ausIPv6TcpPort; + } + + /* Port */ + for (ii = 0; ii < ucCount; ii++) { + u4Ret = kalkStrtou16(apcPortArgv[ii + 2], 0, &u2Port); + if (u4Ret) { + DBGLOG(PF, ERROR, + "parse u2Port error u4Ret=%d\n", u4Ret); + return -1; + } + + pausPortArry[ii] = u2Port; + DBGLOG(PF, INFO, "ucPort=%d, idx=%d\n", u2Port, ii); + } + + return 0; + } else if (i4Argc == 2) { + u4Ret = kalkStrtou8(apcPortArgv[1], 0, &ucVer); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucWakeupHif error u4Ret=%d\n", + u4Ret); + return -1; + } + + if (ucVer == 0) { + kalMemZero(prGlueInfo->prAdapter->rWowCtrl.stWowPort + .ausIPv4UdpPort, + sizeof(u16) * MAX_TCP_UDP_PORT); + prGlueInfo->prAdapter->rWowCtrl.stWowPort + .ucIPv4UdpPortCnt = 0; + } else { + kalMemZero(prGlueInfo->prAdapter->rWowCtrl.stWowPort + .ausIPv6UdpPort, + sizeof(u16) * MAX_TCP_UDP_PORT); + prGlueInfo->prAdapter->rWowCtrl.stWowPort + .ucIPv6UdpPortCnt = 0; + } + + return 0; + } else { + return -1; + } +} + +static int priv_driver_get_wow_port(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_WOW_CTRL_T pWOW_CTRL = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 u4Ret = 0, ii; + u8 ucVer, ucProto; + u16 ucCount; + u16 *pausPortArry; +#if !DBG_DISABLE_ALL_LOG + s8 *aucIp[2] = { "IPv4", "IPv6" }; + s8 *aucProto[2] = { "UDP", "TCP" }; +#endif + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + pWOW_CTRL = &prGlueInfo->prAdapter->rWowCtrl; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + /* example: get_wow_port 0 0 (ipv4-udp) */ + /* example: get_wow_port 0 1 (ipv4-tcp) */ + /* example: get_wow_port 1 0 (ipv6-udp) */ + /* example: get_wow_port 1 1 (ipv6-tcp) */ + + if (i4Argc >= 3) { + /* 0=IPv4, 1=IPv6 */ + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucVer); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse argc[1] error u4Ret=%d\n", + u4Ret); + } + + /* 0=UDP, 1=TCP */ + u4Ret = kalkStrtou8(apcArgv[2], 0, &ucProto); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse argc[2] error u4Ret=%d\n", + u4Ret); + } + + if (ucVer > 1) { + ucVer = 0; + } + + if (ucProto > 1) { + ucProto = 0; + } + + if (ucVer == 0) { + if (ucProto == 0) { + /* IPv4/UDP */ + ucCount = pWOW_CTRL->stWowPort.ucIPv4UdpPortCnt; + pausPortArry = + pWOW_CTRL->stWowPort.ausIPv4UdpPort; + } else { + /* IPv4/TCP */ + ucCount = pWOW_CTRL->stWowPort.ucIPv4TcpPortCnt; + pausPortArry = + pWOW_CTRL->stWowPort.ausIPv4TcpPort; + } + } else { + if (ucProto == 0) { + /* IPv6/UDP */ + ucCount = pWOW_CTRL->stWowPort.ucIPv6UdpPortCnt; + pausPortArry = + pWOW_CTRL->stWowPort.ausIPv6UdpPort; + } else { + /* IPv6/TCP */ + ucCount = pWOW_CTRL->stWowPort.ucIPv6TcpPortCnt; + pausPortArry = + pWOW_CTRL->stWowPort.ausIPv6TcpPort; + } + } + + /* Dunp Port */ + for (ii = 0; ii < ucCount; ii++) + DBGLOG(PF, INFO, "ucPort=%d, idx=%d\n", + pausPortArry[ii], ii); + + DBGLOG(PF, INFO, "[%s/%s] count:%d\n", aucIp[ucVer], + aucProto[ucProto], ucCount); + + return 0; + } else { + return -1; + } +} + +static int priv_driver_get_wow_reason(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Argc = 0; + s32 i4BytesWritten = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + P_WOW_CTRL_T pWOW_CTRL = NULL; + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + pWOW_CTRL = &prGlueInfo->prAdapter->rWowCtrl; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (pWOW_CTRL->ucReason != INVALID_WOW_WAKE_UP_REASON) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\nwakeup_reason:%d", pWOW_CTRL->ucReason); + } + + return i4BytesWritten; +} +#endif + +#if CFG_STR_DHCP_RENEW_OFFLOAD +static int priv_driver_set_dhcp_info(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_BSS_INFO_T prBssInfo; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u8 aucIpAddr[4]; + u8 i = 0; + u8 fgIsIpInvalid = false; + u32 u4Ret = 0; + u32 u4RenewIntv = 0, u4Value = 0; + u8 ucLength = 0, ucNum = 0; + s8 *pcTmp, *pcStart; + s8 CurrChar; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + DBGLOG(REQ, LOUD, "MT7668 : priv_driver_set_dhcp_info\n"); + + if (i4Argc != 3) { + DBGLOG(REQ, ERROR, "argc %i is not equal to 3\n", i4Argc); + goto out; + } + + pcStart = apcArgv[1]; + pcTmp = pcStart; + ucLength = strlen(apcArgv[1]); + + while (i < 4) { + u4Value = 0; + + while (1) { + CurrChar = *pcTmp; + + pcTmp++; + + if (pcTmp > (pcStart + ucLength)) { + if (ucNum != 3 && !isdigit(CurrChar)) { + DBGLOG(REQ, WARN, "Invalid: Num=%d\n", + ucNum + 1); + fgIsIpInvalid = true; + } + break; + } else if (CurrChar >= '0' && CurrChar <= '9') { + u4Value *= 10; + u4Value += CurrChar - '0'; + } else if (i < 3 && CurrChar == '.') { + ucNum++; + break; + } else { + if (i != 3 || !isdigit(CurrChar)) { + DBGLOG(REQ, WARN, "Invalid\n"); + fgIsIpInvalid = true; + } + break; + } + } + + if (u4Value >= 256) { + DBGLOG(REQ, WARN, "Number is larger than 255\n"); + fgIsIpInvalid = true; + break; + } + + aucIpAddr[i] = (u8)u4Value; + i++; + } + + if (fgIsIpInvalid) { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "Dhcp Server IP is invalid"); + return i4BytesWritten; + } + + u4Ret = kalkStrtou32(apcArgv[2], 0, &u4RenewIntv); + if (u4Ret) { + DBGLOG(REQ, WARN, "parse u4LogType error u4Ret=%d\n", u4Ret); + goto out; + } + + /* TODO: Only support AIS for now */ + prBssInfo = prGlueInfo->prAdapter->prAisBssInfo; + + if ((prBssInfo->eConnectionState == PARAM_MEDIA_STATE_CONNECTED) && + (prBssInfo->fgIsNetActive)) { + if (u4RenewIntv != 0) { + prBssInfo->fgIsDhcpAcked = true; + prBssInfo->u4DhcpRenewIntv = u4RenewIntv; + + for (i = 0; i < 4; i++) + prBssInfo->aucDhcpServerIpAddr[i] = + aucIpAddr[i]; + + DBGLOG(REQ, + EVENT, + "Store DHCP Renew info: ServerIP= %d.%d.%d.%d ,RenewIntv= %d seconds\n", + prBssInfo->aucDhcpServerIpAddr[0], + prBssInfo->aucDhcpServerIpAddr[1], + prBssInfo->aucDhcpServerIpAddr[2], + prBssInfo->aucDhcpServerIpAddr[3], + prBssInfo->u4DhcpRenewIntv); + } else { + /* disable dhcp offload if lease time is set to 0 */ + prBssInfo->fgIsDhcpAcked = false; + prBssInfo->u4DhcpRenewIntv = 0; + kalMemZero(prBssInfo->aucDhcpServerIpAddr, + sizeof(prBssInfo->aucDhcpServerIpAddr)); + DBGLOG(REQ, EVENT, "Disable Dhcp Offload during STR\n"); + } + } else { + DBGLOG(REQ, ERROR, "Cannot set_dhcp when disconnected\n"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "set_dhcp failed due to wifi is disconnected"); + return i4BytesWritten; + } + + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "set_dhcp success"); + return i4BytesWritten; + +out: + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "format:set_dhcp [Dhcp Server IP] [Renew interval]"); + return i4BytesWritten; +} +#endif + +static int priv_driver_set_adv_pws(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Ret = 0; + u8 ucAdvPws = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + if (i4Argc < 2) { + DBGLOG(REQ, WARN, "%s: argc is %d, need >=2\n", __func__, + i4Argc); + return -1; + } + if (i4Argc >= 2) { + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucAdvPws); + + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse bEnable error u4Ret=%d\n", + u4Ret); + } + + prGlueInfo->prAdapter->rWifiVar.ucAdvPws = ucAdvPws; + + DBGLOG(INIT, INFO, "AdvPws:%d\n", + &prGlueInfo->prAdapter->rWifiVar.ucAdvPws); + + return 0; + } else { + return -1; + } +} + +static int priv_driver_set_mdtim(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Ret = 0; + u8 ucMultiDtim = 0, ucVer; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + /* iwpriv wlan0 driver "set_mdtim 1 3 */ + if (i4Argc >= 3) { + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucVer); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse apcArgv1 error u4Ret=%d\n", + u4Ret); + return -1; + } + + u4Ret = kalkStrtou8(apcArgv[2], 0, &ucMultiDtim); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse apcArgv2 error u4Ret=%d\n", + u4Ret); + return -1; + } + + if (ucVer == 0) { + prGlueInfo->prAdapter->rWifiVar.ucWowOnMdtim = + ucMultiDtim; + DBGLOG(REQ, INFO, "WOW On MDTIM:%d\n", + &prGlueInfo->prAdapter->rWifiVar.ucWowOnMdtim); + } else { + prGlueInfo->prAdapter->rWifiVar.ucWowOffMdtim = + ucMultiDtim; + DBGLOG(REQ, INFO, "WOW Off MDTIM:%d\n", + &prGlueInfo->prAdapter->rWifiVar.ucWowOffMdtim); + } + } + + return 0; +} + +static int priv_driver_set_listen_dtim_interval(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Ret = 0; + u8 ucInterval = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + /* iwpriv wlan0 driver "set_listen_dtim_interval x */ + if (i4Argc >= 2) { + u4Ret = kalkStrtou8(apcArgv[1], 0, &ucInterval); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse apcArgv1 error u4Ret=%d\n", + u4Ret); + return -1; + } + + prGlueInfo->prAdapter->rWifiVar.ucListenDtimInterval = + ucInterval; + DBGLOG(REQ, INFO, "Listen Interval(DTIM) :%d\n", + &prGlueInfo->prAdapter->rWifiVar.ucListenDtimInterval); + } + + return 0; +} + +int priv_driver_set_suspend_mode(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u8 fgEnable; + u32 u4Enable = false; + s32 u4Ret = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc >= 2) { + /* fgEnable = (kalStrtoul(apcArgv[1], NULL, 0) == 1) ? true : + * false; */ + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4Enable); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse u4Enable error u4Ret=%d\n", + u4Ret); + return -1; + } + + if (u4Enable == 1) { + fgEnable = true; + }else{ + fgEnable = false; + } + + DBGLOG(REQ, INFO, "%s: Set suspend mode [%u]\n", __func__, + fgEnable); + + if (prGlueInfo->fgIsInSuspendMode == fgEnable) { + DBGLOG(REQ, INFO, + "%s: Already in suspend mode, SKIP!\n", + __func__); + return 0; + } + + prGlueInfo->fgIsInSuspendMode = fgEnable; + + wlanSetSuspendMode(prGlueInfo, fgEnable); + p2pSetSuspendMode(prGlueInfo, fgEnable); + } + + return 0; +} + +#if CFG_SUPPORT_SNIFFER +int priv_driver_set_monitor(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4Argc = 0; + s32 i4BytesWritten = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + PARAM_CUSTOM_MONITOR_SET_STRUCT_T rMonitorSetInfo; + u8 ucEnable = 0; + u8 ucPriChannel = 0; + u8 ucChannelWidth = 0; + u8 ucExt = 0; + u8 ucSco = 0; + u8 ucChannelS1 = 0; + u8 ucChannelS2 = 0; + u8 fgIsLegalChannel = false; + u8 fgError = false; + u8 fgEnable = false; + ENUM_BAND_T eBand = BAND_NULL; + u32 u4Parse = 0; + s32 u4Ret = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + if (i4Argc >= 5) { + /* ucEnable = (u8) (kalStrtoul(apcArgv[1], NULL, 0)); + * ucPriChannel = (u8) (kalStrtoul(apcArgv[2], NULL, 0)); + * ucChannelWidth = (u8) (kalStrtoul(apcArgv[3], NULL, 0)); + * ucExt = (u8) (kalStrtoul(apcArgv[4], NULL, 0)); + */ + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4Parse); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse apcArgv error u4Ret=%d\n", + u4Ret); + return -1; + } + + ucEnable = (u8)u4Parse; + u4Ret = kalkStrtou32(apcArgv[2], 0, &u4Parse); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse apcArgv error u4Ret=%d\n", + u4Ret); + return -1; + } + + ucPriChannel = (u8)u4Parse; + u4Ret = kalkStrtou32(apcArgv[3], 0, &u4Parse); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse apcArgv error u4Ret=%d\n", + u4Ret); + return -1; + } + + ucChannelWidth = (u8)u4Parse; + u4Ret = kalkStrtou32(apcArgv[4], 0, &u4Parse); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse apcArgv error u4Ret=%d\n", + u4Ret); + return -1; + } + + ucExt = (u8)u4Parse; + + eBand = (ucPriChannel <= 14) ? BAND_2G4 : BAND_5G; + fgIsLegalChannel = + rlmDomainIsLegalChannel(prAdapter, eBand, ucPriChannel); + + if (fgIsLegalChannel == false) { + i4BytesWritten = snprintf(pcCommand, i4TotalLen, + "Illegal primary channel %d", + ucPriChannel); + return i4BytesWritten; + } + + switch (ucChannelWidth) { + case 160: + ucChannelWidth = (u8)CW_160MHZ; + ucSco = (u8)CHNL_EXT_SCN; + + if (ucPriChannel >= 36 && ucPriChannel <= 64) { + ucChannelS2 = 50; + }else if (ucPriChannel >= 100 && ucPriChannel <= 128) { + ucChannelS2 = 114; + }else{ + fgError = true; + } + break; + + case 80: + ucChannelWidth = (u8)CW_80MHZ; + ucSco = (u8)CHNL_EXT_SCN; + + if (ucPriChannel >= 36 && ucPriChannel <= 48) { + ucChannelS1 = 42; + }else if (ucPriChannel >= 52 && ucPriChannel <= 64) { + ucChannelS1 = 58; + }else if (ucPriChannel >= 100 && ucPriChannel <= 112) { + ucChannelS1 = 106; + }else if (ucPriChannel >= 116 && ucPriChannel <= 128) { + ucChannelS1 = 122; + }else if (ucPriChannel >= 132 && ucPriChannel <= 144) { + ucChannelS1 = 138; + }else if (ucPriChannel >= 149 && ucPriChannel <= 161) { + ucChannelS1 = 155; + }else{ + fgError = true; + } + break; + + case 40: + ucChannelWidth = (u8)CW_20_40MHZ; + ucSco = (ucExt) ? (u8)CHNL_EXT_SCA : (u8)CHNL_EXT_SCB; + break; + + case 20: + ucChannelWidth = (u8)CW_20_40MHZ; + ucSco = (u8)CHNL_EXT_SCN; + break; + + default: + fgError = true; + break; + } + + if (fgError) { + i4BytesWritten = snprintf( + pcCommand, i4TotalLen, + "Invalid primary channel %d with bandwidth %d", + ucPriChannel, ucChannelWidth); + return i4BytesWritten; + } + + fgEnable = (ucEnable) ? true : false; + + if (prGlueInfo->fgIsEnableMon != fgEnable) { + prGlueInfo->fgIsEnableMon = fgEnable; + schedule_work(&prGlueInfo->monWork); + } + + kalMemZero(&rMonitorSetInfo, sizeof(rMonitorSetInfo)); + + rMonitorSetInfo.ucEnable = ucEnable; + rMonitorSetInfo.ucPriChannel = ucPriChannel; + rMonitorSetInfo.ucSco = ucSco; + rMonitorSetInfo.ucChannelWidth = ucChannelWidth; + rMonitorSetInfo.ucChannelS1 = ucChannelS1; + rMonitorSetInfo.ucChannelS2 = ucChannelS2; + + rStatus = kalIoctl(prGlueInfo, wlanoidSetMonitor, + &rMonitorSetInfo, sizeof(rMonitorSetInfo), + false, false, true, &u4BufLen); + + i4BytesWritten = snprintf( + pcCommand, i4TotalLen, "set monitor config %s", + (rStatus == WLAN_STATUS_SUCCESS) ? "success" : "fail"); + + return i4BytesWritten; + } + + i4BytesWritten = + snprintf(pcCommand, i4TotalLen, + "monitor [Enable][PriChannel][ChannelWidth][Sco]"); + + return i4BytesWritten; +} +#endif + +static int priv_driver_get_version(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter; + s32 i4BytesWritten = 0; + u32 u4Offset = 0; + P_WIFI_VER_INFO_T prVerInfo; + tailer_format_t *prTailer; + u8 aucBuf[32], aucDate[32]; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + prVerInfo = &prAdapter->rVerInfo; + + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "\nChip ROM ver [%u]\n", + prAdapter->chip_info->eco_ver); + + wlanPrintVersion(prAdapter); + + kalStrnCpy(aucBuf, prVerInfo->aucFwBranchInfo, 4); + aucBuf[4] = '\0'; + kalStrnCpy(aucDate, prVerInfo->aucFwDateCode, 16); + aucDate[16] = '\0'; + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "\nN9 FW version %s-%u.%u.%u[DEC] (%s)\n", aucBuf, + (prVerInfo->u2FwOwnVersion >> 8), + (prVerInfo->u2FwOwnVersion & BITS(0, 7)), + prVerInfo->ucFwBuildNumber, aucDate); +#if CFG_SUPPORT_COMPRESSION_FW_OPTION + if (prVerInfo->fgIsN9CompressedFW) { + tailer_format_t_2 *prTailer; + + prTailer = &prVerInfo->rN9Compressedtailer; + kalMemCopy(aucBuf, prTailer->ram_version, 10); + aucBuf[10] = '\0'; + u4Offset += + snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "N9 tailer version %s (%s) info %u:E%u\n", + aucBuf, prTailer->ram_built_date, + prTailer->chip_info, prTailer->eco_code + 1); + } else { + prTailer = &prVerInfo->rN9tailer; + kalMemCopy(aucBuf, prTailer->ram_version, 10); + aucBuf[10] = '\0'; + u4Offset += + snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "N9 tailer version %s (%s) info %u:E%u\n", + aucBuf, prTailer->ram_built_date, + prTailer->chip_info, prTailer->eco_code + 1); + } + if (prVerInfo->fgIsCR4CompressedFW) { + tailer_format_t_2 *prTailer; + + prTailer = &prVerInfo->rCR4Compressedtailer; + kalMemCopy(aucBuf, prTailer->ram_version, 10); + aucBuf[10] = '\0'; + u4Offset += + snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "CR4 tailer version %s (%s) info %u:E%u\n", + aucBuf, prTailer->ram_built_date, + prTailer->chip_info, prTailer->eco_code + 1); + } else { + prTailer = &prVerInfo->rCR4tailer; + kalMemCopy(aucBuf, prTailer->ram_version, 10); + aucBuf[10] = '\0'; + u4Offset += + snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "CR4 tailer version %s (%s) info %u:E%u\n", + aucBuf, prTailer->ram_built_date, + prTailer->chip_info, prTailer->eco_code + 1); + } +#else + prTailer = &prVerInfo->rN9tailer; + kalMemCopy(aucBuf, prTailer->ram_version, 10); + aucBuf[10] = '\0'; + kalMemCopy(aucDate, prTailer->ram_built_date, + sizeof(prTailer->ram_built_date)); + aucDate[sizeof(prTailer->ram_built_date)] = '\0'; + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "N9 tailer version %s (%s) info %u:E%u\n", aucBuf, + aucDate, prTailer->chip_info, + prTailer->eco_code + 1); + + prTailer = &prVerInfo->rCR4tailer; + kalMemCopy(aucBuf, prTailer->ram_version, 10); + aucBuf[10] = '\0'; + kalMemCopy(aucDate, prTailer->ram_built_date, + sizeof(prTailer->ram_built_date)); + aucDate[sizeof(prTailer->ram_built_date)] = '\0'; + u4Offset += snprintf(pcCommand + u4Offset, + i4TotalLen - u4Offset, + "CR4 tailer version %s (%s) info %u:E%u\n", + aucBuf, + aucDate, + prTailer->chip_info, + prTailer->eco_code + 1); +#endif + if (!prVerInfo->fgPatchIsDlByDrv) { + u4Offset += snprintf( + pcCommand + u4Offset, i4TotalLen - u4Offset, + "Patch is not downloaded by driver, read patch binary\n"); + wlanGetPatchInfo(prAdapter); + } + + kalStrnCpy(aucBuf, prVerInfo->rPatchHeader.aucPlatform, 4); + aucBuf[4] = '\0'; + kalStrnCpy(aucDate, prVerInfo->rPatchHeader.aucBuildDate, 16); + aucDate[16] = '\0'; + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "Patch platform %s version 0x%04X %s\n", aucBuf, + prVerInfo->rPatchHeader.u4PatchVersion, aucDate); + + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "WiFi Driver Version " NIC_DRIVER_VERSION_STRING + "\n"); + + i4BytesWritten = (s32)u4Offset; + + return i4BytesWritten; +} + +#if CFG_SUPPORT_DBDC +int priv_driver_set_dbdc(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + + u32 u4Ret, u4Parse = 0; + + u8 ucDBDCEnable; + /*u8 ucBssIndex;*/ + /*P_BSS_INFO_T prBssInfo;*/ + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (prGlueInfo->prAdapter->rWifiVar.ucDbdcMode != DBDC_MODE_DYNAMIC) { + DBGLOG(REQ, LOUD, + "Current DBDC mode %u cannot enable/disable DBDC!!\n", + prGlueInfo->prAdapter->rWifiVar.ucDbdcMode); + return -1; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + if (i4Argc == 2) { + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4Parse); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse apcArgv error u4Ret=%d\n", + u4Ret); + return -1; + } + + ucDBDCEnable = (u8)u4Parse; + if ((!prGlueInfo->prAdapter->rWifiVar.fgDbDcModeEn && + !ucDBDCEnable) || + (prGlueInfo->prAdapter->rWifiVar.fgDbDcModeEn && + ucDBDCEnable)) { + return i4BytesWritten; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetDbdcEnable, + &ucDBDCEnable, 1, false, false, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + } else { + DBGLOG(INIT, ERROR, "iwpriv wlanXX driver SET_DBDC <enable>\n"); + DBGLOG(INIT, ERROR, "<enable> 1: enable. 0: disable.\n"); + } + + return i4BytesWritten; +} +#endif + +#if CFG_SUPPORT_BATCH_SCAN +#define CMD_BATCH_SET "WLS_BATCHING SET" +#define CMD_BATCH_GET "WLS_BATCHING GET" +#define CMD_BATCH_STOP "WLS_BATCHING STOP" +#endif + +static int priv_driver_get_que_info(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + return qmDumpQueueStatus(prGlueInfo->prAdapter, pcCommand, i4TotalLen); +} + +static int priv_driver_get_mem_info(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + return cnmDumpMemoryStatus(prGlueInfo->prAdapter, pcCommand, + i4TotalLen); +} + +static int priv_driver_get_hif_info(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + return halDumpHifStatus(prGlueInfo->prAdapter, pcCommand, i4TotalLen); +} + +int priv_driver_set_p2p_ps(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Ret; + s32 i4Parameter; + PARAM_CUSTOM_OPPPS_PARAM_STRUCT_T rOpppsParamInfo; + u8 ucRoleIdx = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + if (i4Argc >= 3) { + /* get Bss Index from ndev */ + if (mtk_Netdev_To_RoleIdx(prGlueInfo, prNetDev, &ucRoleIdx) != + 0) { + return -1; + } + + if (p2pFuncRoleToBssIdx(prGlueInfo->prAdapter, ucRoleIdx, + &rOpppsParamInfo.ucBssIdx) != + WLAN_STATUS_SUCCESS) { + return -1; + } + + DBGLOG(REQ, LOUD, "priv_driver_set_p2p_ps bss Idx %u\n", + rOpppsParamInfo.ucBssIdx); + + u4Ret = kalkStrtos32(apcArgv[1], 0, &i4Parameter); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse apcArgv[1] error u4Ret=%d\n", + u4Ret); + } + + if (i4Parameter >= 1) { + rOpppsParamInfo.ucLegcyPS = 1; + }else{ + rOpppsParamInfo.ucLegcyPS = 0; + } + + u4Ret = kalkStrtos32(apcArgv[2], 0, &i4Parameter); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse apcArgv[2] error u4Ret=%d\n", + u4Ret); + } + + if (i4Parameter >= 1) { + rOpppsParamInfo.ucOppPs = 1; + }else{ + rOpppsParamInfo.ucOppPs = 0; + } + + u4Ret = kalkStrtos32(apcArgv[3], 0, &i4Parameter); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse apcArgv[2] error u4Ret=%d\n", + u4Ret); + } + + if (rOpppsParamInfo.ucOppPs) { + rOpppsParamInfo.u4CTwindowMs = (u32)i4Parameter; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSetOppPsParam, + &rOpppsParamInfo, sizeof(rOpppsParamInfo), + false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + } else { + DBGLOG(INIT, + ERROR, + "ERR, iwpriv wlanXX driver SET_P2P_PS <legacy ps> <Oppps> <CTW>\n"); + } + + return i4BytesWritten; +} + +#if CFG_SUPPORT_LAST_SEC_MCS_INFO +static int priv_driver_get_mcs_info(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0, i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + P_PARAM_HW_WLAN_INFO_T prHwWlanInfo = NULL; + struct PARAM_TX_MCS_INFO *prTxMcsInfo = NULL; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (prGlueInfo->prAdapter->rRxMcsInfoTimer.pfMgmtTimeOutFunc == NULL) { + cnmTimerInitTimer( + prGlueInfo->prAdapter, + &prGlueInfo->prAdapter->rRxMcsInfoTimer, + (PFN_MGMT_TIMEOUT_FUNC)aisRxMcsCollectionTimeout, + (unsigned long)NULL); + } + + if (i4Argc >= 2) { + if (strnicmp(apcArgv[1], "START", strlen("START")) == 0) { + cnmTimerStartTimer( + prGlueInfo->prAdapter, + &prGlueInfo->prAdapter->rRxMcsInfoTimer, 100); + prGlueInfo->prAdapter->fgIsMcsInfoValid = true; + + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nStart the MCS Info Function\n"); + return i4BytesWritten; + } else if (strnicmp(apcArgv[1], "STOP", strlen("STOP")) == 0) { + cnmTimerStopTimer( + prGlueInfo->prAdapter, + &prGlueInfo->prAdapter->rRxMcsInfoTimer); + prGlueInfo->prAdapter->fgIsMcsInfoValid = false; + + i4BytesWritten += + kalScnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nStop the MCS Info Function\n"); + return i4BytesWritten; + } + } + + if (prGlueInfo->prAdapter->fgIsMcsInfoValid != true) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nUse GET_MCS_INFO [START/STOP] to control the MCS Info Function\n"); + return i4BytesWritten; + } + + prHwWlanInfo = (P_PARAM_HW_WLAN_INFO_T)kalMemAlloc( + sizeof(PARAM_HW_WLAN_INFO_T), VIR_MEM_TYPE); + if (!prHwWlanInfo) { + return -1; + } + + kalMemZero(prHwWlanInfo, sizeof(PARAM_HW_WLAN_INFO_T)); + + /* TODO: frog 20180518: Glue layer no need to know HW wlan idx + * information. Glue layer only know AIS network. But + * wlanoidQueryWlanInfo is used by other APIs and can get WTBL info by + * providing wlan index. Method I: Use an IOCTL to get AIS wlan index + * first. then do WTBL IOCTL query afterward. Method II: If wlan index + * is not specified(RESERVED ENTRY). Driver get WLAN index of the AIS + * network by default. So that it won't impact other existing feature. + */ + prHwWlanInfo->u4Index = WTBL_RESERVED_ENTRY; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryWlanInfo, prHwWlanInfo, + sizeof(PARAM_HW_WLAN_INFO_T), true, true, true, + &u4BufLen); + + DBGLOG(REQ, INFO, "rStatus %u u4BufLen = %d\n", rStatus, u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + goto out; + } + + prTxMcsInfo = (struct PARAM_TX_MCS_INFO *)kalMemAlloc( + sizeof(struct PARAM_TX_MCS_INFO), VIR_MEM_TYPE); + if (!prTxMcsInfo) { + goto out; + } + + /* TODO: frog 20180518: Let the function wlanoidTxMcsInfo decide the + * station record. Currently it is hard coded for ony AIS network. + * Target STA is a connected AP. If we want make this function more + * common and general, we need define new parameters. + */ + rStatus = kalIoctl(prGlueInfo, wlanoidTxMcsInfo, prTxMcsInfo, + sizeof(struct PARAM_TX_MCS_INFO), true, true, true, + &u4BufLen); + + DBGLOG(REQ, INFO, "rStatus %u u4BufLen = %d\n", rStatus, u4BufLen); + if (rStatus != WLAN_STATUS_SUCCESS) { + goto out; + } + + i4BytesWritten = priv_driver_last_sec_mcs_info(prGlueInfo->prAdapter, + pcCommand, i4TotalLen, + prHwWlanInfo, + prTxMcsInfo); + + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand); + +out: + if (prHwWlanInfo) { + kalMemFree(prHwWlanInfo, VIR_MEM_TYPE, + sizeof(PARAM_HW_WLAN_INFO_T)); + } + if (prTxMcsInfo) { + kalMemFree(prTxMcsInfo, VIR_MEM_TYPE, + sizeof(struct PARAM_TX_MCS_INFO)); + } + + return i4BytesWritten; +} +#endif + +static int priv_driver_get_deep_sleep_cnt(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + CNM_STATUS_T rCnmStatus; + u32 *pu4Ptr; + u32 u4Offset = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = 0xb0100000; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + pu4Ptr = (u32 *)&rCnmStatus; + *pu4Ptr = rSwCtrlInfo.u4Data; + + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "Deep Sleep Cnt %d\n", rSwCtrlInfo.u4Data); + + i4BytesWritten = (s32)u4Offset; + + return i4BytesWritten; +} + +static int priv_driver_get_cnm_info(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + CNM_STATUS_T rCnmStatus; + u32 *pu4Ptr; + P_CNM_CH_LIST_T prChList; + u32 u4Offset = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = 0xb0000000; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + pu4Ptr = (u32 *)&rCnmStatus; + *pu4Ptr = rSwCtrlInfo.u4Data; + + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "DBDC is %s, %u CHs in BAND0, %u CHs in BAND1\n", + rCnmStatus.fgDbDcModeEn ? "ON" : "OFF", + rCnmStatus.ucChNumB0, rCnmStatus.ucChNumB1); + + if (rCnmStatus.ucChNumB0 > 0) { + rSwCtrlInfo.u4Id = 0xb0010000; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, + &rSwCtrlInfo, sizeof(rSwCtrlInfo), true, + true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + prChList = (P_CNM_CH_LIST_T)&rSwCtrlInfo.u4Data; + + u4Offset += snprintf(pcCommand + u4Offset, + i4TotalLen - u4Offset, + "BAND0 channels : %u %u %u\n", + prChList->ucChNum[0], prChList->ucChNum[1], + prChList->ucChNum[2]); + } + if (rCnmStatus.ucChNumB1 > 0) { + rSwCtrlInfo.u4Id = 0xb0010001; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, + &rSwCtrlInfo, sizeof(rSwCtrlInfo), true, + true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + prChList = (P_CNM_CH_LIST_T)&rSwCtrlInfo.u4Data; + + u4Offset += snprintf(pcCommand + u4Offset, + i4TotalLen - u4Offset, + "BAND1 channels : %u %u %u\n", + prChList->ucChNum[0], prChList->ucChNum[1], + prChList->ucChNum[2]); + } + + i4BytesWritten = (s32)u4Offset; + + return i4BytesWritten; +} + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +static int priv_driver_get_ch_rank_list(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + u32 i4BytesWritten = 0; + s8 ucIdx = 0, ucIdx2 = 0, ucChannelNum = 0, ucNumOf2gChannel = 0, + ucNumOf5gChannel = 0; + P_PARAM_GET_CHN_INFO prChnLoadInfo = NULL; + RF_CHANNEL_INFO_T *prChannelList = NULL, + auc2gChannelList[MAX_2G_BAND_CHN_NUM], + auc5gChannelList[MAX_5G_BAND_CHN_NUM]; + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prChnLoadInfo = &(prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo); + kalMemZero(pcCommand, i4TotalLen); + + rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_2G4, true, + MAX_2G_BAND_CHN_NUM, &ucNumOf2gChannel, + auc2gChannelList); + rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_5G, true, + MAX_5G_BAND_CHN_NUM, &ucNumOf5gChannel, + auc5gChannelList); + + for (ucIdx = 0; ucIdx < MAX_CHN_NUM; ucIdx++) { + if (prChnLoadInfo->rChnRankList[ucIdx].ucChannel > 14) { + prChannelList = auc5gChannelList; + ucChannelNum = ucNumOf5gChannel; + } else { + prChannelList = auc2gChannelList; + ucChannelNum = ucNumOf2gChannel; + } + + for (ucIdx2 = 0; ucIdx2 < ucChannelNum; ucIdx2++) { + if (prChnLoadInfo->rChnRankList[ucIdx].ucChannel == + prChannelList[ucIdx2].ucChannelNum) { + pcCommand[i4BytesWritten++] = + prChnLoadInfo->rChnRankList[ucIdx] + .ucChannel; + DBGLOG(SCN, TRACE, "ch %u, dirtiness %d\n", + prChnLoadInfo->rChnRankList[ucIdx] + .ucChannel, + prChnLoadInfo->rChnRankList[ucIdx] + .u4Dirtiness); + break; + } + } + } + + return i4BytesWritten; +} + +static int priv_driver_get_ch_dirtiness(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s8 cIdx = 0; + u8 ucNumOf2gChannel = 0; + u8 ucNumOf5gChannel = 0; + u32 i4BytesWritten = 0; + P_PARAM_GET_CHN_INFO prChnLoadInfo = NULL; + RF_CHANNEL_INFO_T ar2gChannelList[MAX_2G_BAND_CHN_NUM]; + RF_CHANNEL_INFO_T ar5gChannelList[MAX_5G_BAND_CHN_NUM]; + + ASSERT(prNetDev); + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prChnLoadInfo = &(prGlueInfo->prAdapter->rWifiVar.rChnLoadInfo); + kalMemZero(pcCommand, i4TotalLen); + + rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_2G4, true, + MAX_2G_BAND_CHN_NUM, &ucNumOf2gChannel, + ar2gChannelList); + rlmDomainGetChnlList(prGlueInfo->prAdapter, BAND_5G, true, + MAX_5G_BAND_CHN_NUM, &ucNumOf5gChannel, + ar5gChannelList); + + for (cIdx = 0; cIdx < MAX_CHN_NUM; cIdx++) { + s8 cIdx2 = 0; + u8 ucChannelNum = 0; + u32 u4Offset = 0; + RF_CHANNEL_INFO_T *prChannelList = NULL; + + if (prChnLoadInfo->rChnRankList[cIdx].ucChannel > 14) { + prChannelList = ar5gChannelList; + ucChannelNum = ucNumOf5gChannel; + } else { + prChannelList = ar2gChannelList; + ucChannelNum = ucNumOf2gChannel; + } + + for (cIdx2 = 0; cIdx2 < ucChannelNum; cIdx2++) { + if (prChnLoadInfo->rChnRankList[cIdx].ucChannel == + prChannelList[cIdx2].ucChannelNum) { + u4Offset = kalSnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nch %03u -> dirtiness %lu", + prChnLoadInfo->rChnRankList[cIdx] + .ucChannel, + prChnLoadInfo->rChnRankList[cIdx] + .u4Dirtiness); + i4BytesWritten += u4Offset; + break; + } + + if (i4BytesWritten >= i4TotalLen) { + return i4BytesWritten; + } + } + } + + return i4BytesWritten; +} +#endif + +static int priv_driver_efuse_ops(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + enum EFUSE_OP_MODE { + EFUSE_READ, + EFUSE_WRITE, + EFUSE_FREE, + EFUSE_INVALID, + }; + u8 ucOpMode = EFUSE_INVALID; + u8 ucOpChar; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u32 u4Ret; + s32 i4Parameter; + u32 u4Efuse_addr = 0; + u8 ucEfuse_value = 0; + +#if (CFG_EEPROM_PAGE_ACCESS == 1) + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4Offset = 0; + u32 u4BufLen = 0; + u8 u4Index = 0; + P_GLUE_INFO_T prGlueInfo = NULL; + PARAM_CUSTOM_ACCESS_EFUSE_T rAccessEfuseInfo; +#endif + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + /* Sanity check */ + if (i4Argc < 2) { + goto efuse_op_invalid; + } + + ucOpChar = (u8)apcArgv[1][0]; + if ((i4Argc == 3) && (ucOpChar == 'r' || ucOpChar == 'R')) { + ucOpMode = EFUSE_READ; + }else if ((i4Argc == 4) && (ucOpChar == 'w' || ucOpChar == 'W')) { + ucOpMode = EFUSE_WRITE; + }else if ((ucOpChar == 'f' || ucOpChar == 'F')) { + ucOpMode = EFUSE_FREE; + } + + /* Print out help if input format is wrong */ + if (ucOpMode == EFUSE_INVALID) { + goto efuse_op_invalid; + } + + /* convert address */ + if (ucOpMode == EFUSE_READ || ucOpMode == EFUSE_WRITE) { + u4Ret = kalkStrtos32(apcArgv[2], 16, &i4Parameter); + u4Efuse_addr = (u32)i4Parameter; + } + + /* convert value */ + if (ucOpMode == EFUSE_WRITE) { + u4Ret = kalkStrtos32(apcArgv[3], 16, &i4Parameter); + ucEfuse_value = (u8)i4Parameter; + } + + /* Start operation */ +#if (CFG_EEPROM_PAGE_ACCESS == 1) + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + kalMemSet(&rAccessEfuseInfo, 0, sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T)); + rAccessEfuseInfo.u4Address = + (u4Efuse_addr / EFUSE_BLOCK_SIZE) * EFUSE_BLOCK_SIZE; + u4Index = u4Efuse_addr % EFUSE_BLOCK_SIZE; + + if (ucOpMode == EFUSE_READ) { + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryProcessAccessEfuseRead, + &rAccessEfuseInfo, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), true, + true, true, &u4BufLen); + + if (rStatus == WLAN_STATUS_SUCCESS) { + u4Offset += snprintf( + pcCommand + u4Offset, i4TotalLen - u4Offset, + "Read success 0x%X = 0x%X\n", u4Efuse_addr, + prGlueInfo->prAdapter->aucEepromVaule[u4Index]); + } + } else if (ucOpMode == EFUSE_WRITE) { + prGlueInfo->prAdapter->aucEepromVaule[u4Index] = ucEfuse_value; + + kalMemCopy(rAccessEfuseInfo.aucData, + prGlueInfo->prAdapter->aucEepromVaule, 16); + + rStatus = kalIoctl(prGlueInfo, + wlanoidQueryProcessAccessEfuseWrite, + &rAccessEfuseInfo, + sizeof(PARAM_CUSTOM_ACCESS_EFUSE_T), false, + false, true, &u4BufLen); + if (rStatus == WLAN_STATUS_SUCCESS) { + u4Offset += snprintf(pcCommand + u4Offset, + i4TotalLen - u4Offset, + "Write success 0x%X = 0x%X\n", + u4Efuse_addr, ucEfuse_value); + } + } else if (ucOpMode == EFUSE_FREE) { + PARAM_CUSTOM_EFUSE_FREE_BLOCK_T rEfuseFreeBlock = {}; + + rStatus = kalIoctl(prGlueInfo, wlanoidQueryEfuseFreeBlock, + &rEfuseFreeBlock, + sizeof(PARAM_CUSTOM_EFUSE_FREE_BLOCK_T), + true, true, true, &u4BufLen); + if (rStatus == WLAN_STATUS_SUCCESS) { + u4Offset += snprintf( + pcCommand + u4Offset, i4TotalLen - u4Offset, + "Free block size 0x%X\n", + prGlueInfo->prAdapter->u4FreeBlockNum); + } + } +#else + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "efuse ops is invalid\n"); +#endif + + return (s32)u4Offset; + +efuse_op_invalid: + + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "\nHelp menu\n"); + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "\tRead:\t\"efuse read addr_hex\"\n"); + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "\tWrite:\t\"efuse write addr_hex val_hex\"\n"); + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "\tFree Blocks:\t\"efuse free\"\n"); + return (s32)u4Offset; +} + +#if CFG_SUPPORT_ADVANCE_CONTROL +static int priv_driver_set_noise(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 u4Ret = 0; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_SET_ID + CMD_ADVCTL_NOISE_ID; + u32 u4Sel = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + rSwCtrlInfo.u4Id = u4Id; + + if (i4Argc <= 1) { + DBGLOG(REQ, ERROR, "Argc(%d) ERR: SET_NOISE <Sel>\n", i4Argc); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4Sel); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error u4Ret=%d\n", u4Ret); + return -1; + } + + rSwCtrlInfo.u4Data = u4Sel << 30; + DBGLOG(REQ, LOUD, "u4Sel=%d u4Data=0x%x,\n", u4Sel, rSwCtrlInfo.u4Data); + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} + +static int priv_driver_get_noise(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_NOISE_ID; + u32 u4Offset = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + s16 u2Wf0AvgPwr, u2Wf1AvgPwr; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = u4Id; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + u2Wf0AvgPwr = rSwCtrlInfo.u4Data & 0xFFFF; + u2Wf1AvgPwr = (rSwCtrlInfo.u4Data >> 16) & 0xFFFF; + + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "Noise Idle Avg. Power: WF0:%ddB WF1:%ddB\n", + u2Wf0AvgPwr, u2Wf1AvgPwr); + + i4BytesWritten = (s32)u4Offset; + + return i4BytesWritten; +} + +#ifdef CFG_SUPPORT_ADMINCTRL +static int priv_driver_admin_ctrl_config(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + struct CMD_ADMIN_CTRL_CONFIG *cmd = NULL; + struct ADMIN_CTRL_PARAM *content = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + P_GLUE_INFO_T prGlueInfo; + s32 i4BytesWritten = 0; + u32 u4BufLen = 0; + s32 i4Argc = 0; + s32 u4Ret = 0; + s32 i = 0; + u16 u2Val = 0; + u8 arAdminTbl[ADMIN_CTRL_TBL_ENTRY_NUM] = { 0 }; + u8 ucVal = 0; + u8 fgWaitResp = false; + u8 txmode, rate; + u8 nss; + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (!prGlueInfo) { + goto admin_ctrl_invalid; + } + + cmd = (struct CMD_ADMIN_CTRL_CONFIG *)kalMemAlloc(sizeof(*cmd), + VIR_MEM_TYPE); + if (!cmd) { + goto admin_ctrl_invalid; + } + + if ((i4Argc > 14) || (i4Argc < 2)) { + goto admin_ctrl_invalid; + } + + memset(cmd, 0, sizeof(*cmd)); + content = &cmd->content; + cmd->u2Type = CMD_ADMINCTRL_CONFIG_TYPE; + cmd->u2Len = sizeof(*cmd); + /* get command */ + if (strnicmp(apcArgv[1], "AUTO", strlen("AUTO")) == 0) { + if (i4Argc != 2) { + goto admin_ctrl_invalid; + } + cmd->u2Type |= CMD_ADV_CONTROL_SET; + cmd->u2Action = ADMIN_CTRL_SET_MODE; + content->u2eMode = ADMIN_CTRL_MODE_AUTO; + } else if (strnicmp(apcArgv[1], "DISABLE", strlen("DISABLE")) == 0) { + if (i4Argc != 2) { + goto admin_ctrl_invalid; + } + cmd->u2Type |= CMD_ADV_CONTROL_SET; + cmd->u2Action = ADMIN_CTRL_SET_MODE; + content->u2eMode = ADMIN_CTRL_MODE_DIS; + } else if (strnicmp(apcArgv[1], "MAN", strlen("MAN")) == 0) { + if (i4Argc != 3) { + goto admin_ctrl_invalid; + } + + cmd->u2Type |= CMD_ADV_CONTROL_SET; + cmd->u2Action = ADMIN_CTRL_SET_MODE; + u4Ret = kalkStrtou16(apcArgv[2], 0, &u2Val); + + if ((u2Val > ADMIN_CTRL_MAX_PERCENTAGE) || u4Ret) { + goto admin_ctrl_invalid; + } + content->u2eMode = ADMIN_CTRL_MODE_MAN; + content->u2ForceAdminTime = u2Val; + } else if (strnicmp(apcArgv[1], "RESET", strlen("RESET")) == 0) { + if (i4Argc != 2) { + goto admin_ctrl_invalid; + } + + cmd->u2Type |= CMD_ADV_CONTROL_SET; + cmd->u2Action = ADMIN_CTRL_SET_MODE; + content->u2eMode = ADMIN_CTRL_MODE_RESET; + } else if (strnicmp(apcArgv[1], "ADMIN_BASE", strlen("ADMIN_BASE")) == + 0) { + if (i4Argc != 3) { + goto admin_ctrl_invalid; + } + cmd->u2Type |= CMD_ADV_CONTROL_SET; + cmd->u2Action = ADMIN_CTRL_SET_BASE; + u4Ret = kalkStrtou16(apcArgv[2], 0, &u2Val); + + if ((!u2Val) || u4Ret) { + goto admin_ctrl_invalid; + } + content->u2AdminCtrlBase = u2Val; + } else if (strnicmp(apcArgv[1], "TBL1", strlen("TBL1")) == 0) { + if (i4Argc != 8) { + goto admin_ctrl_invalid; + } + cmd->u2Type |= CMD_ADV_CONTROL_SET; + cmd->u2Action = ADMIN_CTRL_SET_TBL1; + for (i = 0; i < ADMIN_CTRL_TBL_ENTRY_NUM; i++) { + u4Ret = kalkStrtou8(apcArgv[i + 2], 0, &ucVal); + arAdminTbl[i] = ucVal; + if (u4Ret) { + goto admin_ctrl_invalid; + } + } + memcpy(content->aucAdminTbl1, arAdminTbl, + sizeof(*content->aucAdminTbl1) * + ADMIN_CTRL_TBL_ENTRY_NUM); + } else if (strnicmp(apcArgv[1], "TBL2", strlen("TBL2")) == 0) { + if (i4Argc != 8) { + goto admin_ctrl_invalid; + } + cmd->u2Type |= CMD_ADV_CONTROL_SET; + cmd->u2Action = ADMIN_CTRL_SET_TBL2; + for (i = 0; i < ADMIN_CTRL_TBL_ENTRY_NUM; i++) { + u4Ret = kalkStrtou8(apcArgv[i + 2], 0, &ucVal); + arAdminTbl[i] = ucVal; + if (u4Ret) { + goto admin_ctrl_invalid; + } + } + memcpy(content->aucAdminTbl2, arAdminTbl, + sizeof(*content->aucAdminTbl2) * + ADMIN_CTRL_TBL_ENTRY_NUM); + } else if (strnicmp(apcArgv[1], "TBL3", strlen("TBL3")) == 0) { + if (i4Argc != 8) { + goto admin_ctrl_invalid; + } + cmd->u2Type |= CMD_ADV_CONTROL_SET; + cmd->u2Action = ADMIN_CTRL_SET_TBL3; + for (i = 0; i < ADMIN_CTRL_TBL_ENTRY_NUM; i++) { + u4Ret = kalkStrtou8(apcArgv[i + 2], 0, &ucVal); + arAdminTbl[i] = ucVal; + if (u4Ret) { + goto admin_ctrl_invalid; + } + } + memcpy(content->aucAdminTbl3, arAdminTbl, + sizeof(*content->aucAdminTbl3) * + ADMIN_CTRL_TBL_ENTRY_NUM); + } else if (strnicmp(apcArgv[1], "METHOD1", strlen("METHOD1")) == 0) { + if (i4Argc != 3) { + goto admin_ctrl_invalid; + } + cmd->u2Type |= CMD_ADV_CONTROL_SET; + cmd->u2Action = ADMIN_CTRL_SET_METHOD; + u4Ret = kalkStrtou8(apcArgv[i + 2], 0, &ucVal); + if (u4Ret) { + goto admin_ctrl_invalid; + } + if (ucVal) { + cmd->content.ucAdminStatus |= ADMIN_METHOD1_ENABLED; + } + } else if (strnicmp(apcArgv[1], "METHOD2", strlen("METHOD2")) == 0) { + if (i4Argc != 3) { + goto admin_ctrl_invalid; + } + cmd->u2Type |= CMD_ADV_CONTROL_SET; + cmd->u2Action = ADMIN_CTRL_SET_METHOD; + u4Ret = kalkStrtou8(apcArgv[i + 2], 0, &ucVal); + if (u4Ret) { + goto admin_ctrl_invalid; + } + if (ucVal) { + cmd->content.ucAdminStatus |= ADMIN_METHOD2_ENABLED; + } + } else if (strnicmp(apcArgv[1], "GET", strlen("GET")) == 0) { + fgWaitResp = true; + } else { + goto admin_ctrl_invalid; + } + + DBGLOG(REQ, INFO, "%s(%s) action %x wait_resp %x\n", __func__, + pcCommand, cmd->u2Action, fgWaitResp); + + rStatus = kalIoctl(prGlueInfo, wlanoidAdvCtrl, cmd, sizeof(*cmd), true, + true, true, &u4BufLen); + + if ((rStatus != WLAN_STATUS_SUCCESS) && + (rStatus != WLAN_STATUS_PENDING)) { + i4BytesWritten += scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\ncommand failed %x", rStatus); + } else if (!(cmd->u2Type & CMD_ADV_CONTROL_SET)) { + /* print info if its get command */ + i4BytesWritten += scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nAdmission Ctrl Info:"); + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nStatus[0x%x]: %s", content->ucAdminStatus, + (content->ucAdminStatus & ADMIN_LINK_2G) ? + "2.4G connected" : + (content->ucAdminStatus & ADMIN_LINK_OTHER) ? + "5G connected" : + "Disconnected"); + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tAdminCtrl: %s", + (content->ucAdminStatus & ADMIN_ENABLED) ? "Enabled" : + "Disabled"); + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\tPer-Packet RW enabled: %s", + (content->ucAdminStatus & ADMIN_PER_PKT_ENABLED) ? + "Enabled" : + "Disabled"); + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nperiod %uus, %% %u%%, mode:%u(0:dis,1:auto,2:man)", + content->u2AdminCtrlBase, content->u2CurAdminTime, + content->u2eMode); + if (content->u2eMode == ADMIN_CTRL_MODE_MAN) { + i4BytesWritten += scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + " force_admin_%%: %u%%", + content->u2ForceAdminTime); + } + if (content->ucAdminThermalLimit < 100) { + i4BytesWritten += + scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nLimited %% from thermal: %u%%", + content->ucAdminThermalLimit); + } + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nBT Info[%x]:", content->u4CoexMode); + i4BytesWritten += scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, " %s", + (content->u4CoexMode & + BT_PROF_LINK_CONNECTED) ? + "Connected" : + "None"); + if (content->u4CoexMode & BT_PROF_LINK_CONNECTED) { + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, ", %s", + (content->u4CoexMode & BT_PROF_A2DP_SRC) ? + "A2DP SRC" : + (content->u4CoexMode & BT_PROF_A2DP_SINK) ? + "A2DP SINK" : + "short-term Profile"); + } + + if (content->ucAdminStatus & ADMIN_LINK_2G) { + i4BytesWritten += scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nInstant Rate Tbl:"); + for (i = 0; i < AUTO_RATE_NUM; i++) { + i4BytesWritten += + scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nRate[%d]: ", i + 1); + txmode = HW_TX_RATE_TO_MODE( + content->au2RateCode[i]); + if (txmode >= MAX_TX_MODE) { + txmode = MAX_TX_MODE; + } + rate = HW_TX_RATE_TO_MCS( + content->au2RateCode[i], txmode); + nss = HW_TX_RATE_TO_NSS( + content->au2RateCode[i]) + + 1; + if (txmode == TX_RATE_MODE_CCK) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s", + HW_TX_RATE_CCK_STR[rate & 0x3]); + } else if (txmode == TX_RATE_MODE_OFDM) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "%s", hw_rate_ofdm_str(rate)); + } else if ((txmode == TX_RATE_MODE_HTMIX) || + (txmode == TX_RATE_MODE_HTGF)) { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "MCS%d", rate); + } else { + i4BytesWritten += kalScnprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "NSS%d_MCS%d", nss, rate); + } + } + } + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nTBL_#:\tCCK%%\tOFDM%%\tBPSK%%\tQPSK%%"); + i4BytesWritten += scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\tQAM16%%\tQAM64%%"); + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nTbl1:\t%d%%\t%d%%\t%d%%\t%d%%\t%d%%\t%d%%", + content->aucAdminTbl1[0], content->aucAdminTbl1[1], + content->aucAdminTbl1[2], content->aucAdminTbl1[3], + content->aucAdminTbl1[4], content->aucAdminTbl1[5]); + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nTbl2:\t%d%%\t%d%%\t%d%%\t%d%%\t%d%%\t%d%%", + content->aucAdminTbl2[0], content->aucAdminTbl2[1], + content->aucAdminTbl2[2], content->aucAdminTbl2[3], + content->aucAdminTbl2[4], content->aucAdminTbl2[5]); + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nTbl3:\t%d%%\t%d%%\t%d%%\t%d%%\t%d%%\t%d%%", + content->aucAdminTbl3[0], content->aucAdminTbl3[1], + content->aucAdminTbl3[2], content->aucAdminTbl3[3], + content->aucAdminTbl3[4], content->aucAdminTbl3[5]); + i4BytesWritten += scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nLast Pick Tbl: Tbl%d", + content->ucLastChosenTbl); + } else { + i4BytesWritten += scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\ncommand sent %x", rStatus); + } + + if (cmd) { + kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd)); + } + + return i4BytesWritten; + +admin_ctrl_invalid: + if (cmd) { + kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd)); + } + i4BytesWritten += scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nformat:adminctrl "); + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "[auto|disable|man $admin_time|admin_base $admin_base|get]"); + i4BytesWritten += scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nformat:adminctrl "); + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "[tbl1 $CCK%% $OFDM%% $BPSK%% $QPSK%% $QAM_16%% $QAM_64%%]"); + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n$admin_time: need < 100, which means 100%%"); + i4BytesWritten += scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n$admin_base: admin base in us"); + return i4BytesWritten; +} +#endif + +static int priv_driver_get_traffic_report(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo; + s32 i4BytesWritten = 0; + u32 u4BufLen = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + struct CMD_GET_TRAFFIC_REPORT *cmd = NULL; + u8 ucBand = ENUM_BAND_0; + u16 u2Val = 0; + u8 ucVal = 0; + s32 u4Ret = 0; + u8 fgWaitResp = false; + u8 fgRead = false; + u8 fgGetDbg = false; + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (!prGlueInfo) { + goto get_report_invalid; + } + + cmd = (struct CMD_GET_TRAFFIC_REPORT *)kalMemAlloc(sizeof(*cmd), + VIR_MEM_TYPE); + if (!cmd) { + goto get_report_invalid; + } + + if ((i4Argc > 4) || (i4Argc < 2)) { + goto get_report_invalid; + } + + memset(cmd, 0, sizeof(*cmd)); + + cmd->u2Type = CMD_GET_REPORT_TYPE; + cmd->u2Len = sizeof(*cmd); + cmd->ucBand = ucBand; + + if (strnicmp(apcArgv[1], "ENABLE", strlen("ENABLE")) == 0) { + /* TrafficReport Enable cmd is blocked when entering suspend + * mode */ + if (prGlueInfo->prAdapter->u4IsKeepFullPwrBitmap & + BLOCK_KEEP_FULL_PWR) { + DBGLOG(REQ, STATE, + "TrafficReport Enable Command is blocked\n"); + goto get_report_invalid; + } + prGlueInfo->prAdapter->u4IsKeepFullPwrBitmap |= + KEEP_FULL_PWR_TRAFFIC_REPORT_BIT; + cmd->ucAction = CMD_GET_REPORT_ENABLE; + cmd->u2Type |= CMD_ADV_CONTROL_SET; + } else if (strnicmp(apcArgv[1], "DISABLE", strlen("DISABLE")) == 0) { + prGlueInfo->prAdapter->u4IsKeepFullPwrBitmap &= + ~KEEP_FULL_PWR_TRAFFIC_REPORT_BIT; + cmd->ucAction = CMD_GET_REPORT_DISABLE; + cmd->u2Type |= CMD_ADV_CONTROL_SET; + } else if (strnicmp(apcArgv[1], "RESET", strlen("RESET")) == 0) { + cmd->ucAction = CMD_GET_REPORT_RESET; + cmd->u2Type |= CMD_ADV_CONTROL_SET; + } else if ((strnicmp(apcArgv[1], "GET", strlen("GET")) == 0) || + (strnicmp(apcArgv[1], "GETDBG", strlen("GETDBG")) == 0)) { + cmd->ucAction = CMD_GET_REPORT_GET; + fgWaitResp = true; + fgRead = true; + if ((i4Argc == 4) && + (strnicmp(apcArgv[2], "BAND", strlen("BAND")) == 0)) { + u4Ret = kalkStrtou8(apcArgv[3], 0, &ucVal); + cmd->ucBand = ucVal; + } + if (strnicmp(apcArgv[1], "GETDBG", strlen("GETDBG")) == 0) { + fgGetDbg = true; + } + } else if ((strnicmp(apcArgv[1], "SAMPLEPOINTS", + strlen("SAMPLEPOINTS")) == 0) && + (i4Argc == 3)) { + u4Ret = kalkStrtou16(apcArgv[2], 0, &u2Val); + cmd->u2SamplePoints = u2Val; + cmd->u2Type |= CMD_ADV_CONTROL_SET; + cmd->ucAction = CMD_SET_REPORT_SAMPLE_POINT; + } else if ((strnicmp(apcArgv[1], "TXTHRES", strlen("TXTHRES")) == 0) && + (i4Argc == 3)) { + u4Ret = kalkStrtou8(apcArgv[2], 0, &ucVal); + /* valid val range is from 0 - 100% */ + if (ucVal > 100) { + ucVal = 100; + } + cmd->ucTxThres = ucVal; + cmd->u2Type |= CMD_ADV_CONTROL_SET; + cmd->ucAction = CMD_SET_REPORT_TXTHRES; + } else if ((strnicmp(apcArgv[1], "RXTHRES", strlen("RXTHRES")) == 0) && + (i4Argc == 3)) { + u4Ret = kalkStrtou8(apcArgv[2], 0, &ucVal); + /* valid val range is from 0 - 100% */ + if (ucVal > 100) { + ucVal = 100; + } + cmd->ucRxThres = ucVal; + cmd->u2Type |= CMD_ADV_CONTROL_SET; + cmd->ucAction = CMD_SET_REPORT_RXTHRES; + } else { + goto get_report_invalid; + } + + DBGLOG(REQ, LOUD, "%s(%s) action %x band %x wait_resp %x\n", __func__, + pcCommand, cmd->ucAction, ucBand, fgWaitResp); + + rStatus = kalIoctl(prGlueInfo, wlanoidAdvCtrl, cmd, sizeof(*cmd), true, + true, true, &u4BufLen); + + if ((rStatus != WLAN_STATUS_SUCCESS) && + (rStatus != WLAN_STATUS_PENDING)) { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\ncommand failed %x", rStatus); + } else if (cmd->ucAction == CMD_GET_REPORT_GET) { + int persentage = 0; + int sample_dur = cmd->u4FetchEd - cmd->u4FetchSt; + + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nCCK false detect cnt: %d", + (cmd->u4FalseCCA >> EVENT_REPORT_CCK_FCCA) & + EVENT_REPORT_CCK_FCCA_FEILD); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nOFDM false detect cnt: %d", + (cmd->u4FalseCCA >> EVENT_REPORT_OFDM_FCCA) & + EVENT_REPORT_OFDM_FCCA_FEILD); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nCCK Sig CRC cnt: %d", + (cmd->u4HdrCRC >> EVENT_REPORT_CCK_SIGERR) & + EVENT_REPORT_CCK_SIGERR_FEILD); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nOFDM Sig CRC cnt: %d", + (cmd->u4HdrCRC >> EVENT_REPORT_OFDM_SIGERR) & + EVENT_REPORT_OFDM_SIGERR_FEILD); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nBand%d Info:", cmd->ucBand); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n\tSample every %u ms with %u points", + cmd->u4TimerDur, cmd->u2SamplePoints); + if (fgGetDbg) { + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + " from systime %u - %u total_dur %u us f_cost %u us t_drift %d ms", + cmd->u4FetchSt, + cmd->u4FetchEd, + sample_dur, + cmd->u4FetchCost, + cmd->TimerDrift); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n\tbusy-RMAC %u us, idle-TMAC %u us, t_total %u", + cmd->u4ChBusy, + cmd->u4ChIdle, + cmd->u4ChBusy + cmd->u4ChIdle); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n\theavy tx threshold %u%% rx threshold %u%%", + cmd->ucTxThres, cmd->ucRxThres); + } + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n\tch_busy %u us, ch_idle %u us, total_period %u us", + sample_dur - cmd->u4ChIdle, cmd->u4ChIdle, sample_dur); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n\tmy_tx_time: %u us", + cmd->u4TxAirTime); + if (cmd->u4FetchEd - cmd->u4FetchSt) { + persentage = cmd->u4TxAirTime / (sample_dur / 1000); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + ", tx utility: %d.%1d%%", + persentage / 10, + persentage % 10); + } + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n\tmy_data_rx_time (no BMC data): %u us", + cmd->u4RxAirTime); + if (cmd->u4FetchEd - cmd->u4FetchSt) { + persentage = cmd->u4RxAirTime / (sample_dur / 1000); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + ", rx utility: %d.%1d%%", + persentage / 10, + persentage % 10); + } + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n\tTotal packet transmitted: %u", + cmd->u4PktSent); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n\tTotal tx ok packet: %u", + cmd->u4PktSent - cmd->u4PktTxfailed); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n\tTotal tx failed packet: %u", + cmd->u4PktTxfailed); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n\tTotal tx retried packet: %u", + cmd->u4PktRetried); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n\tTotal rx mpdu: %u", + cmd->u4RxMPDU); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n\tTotal rx fcs: %u", + cmd->u4RxFcs); + } else { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\ncommand sent %x", rStatus); + } + + if (cmd) { + kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd)); + } + + return i4BytesWritten; + +get_report_invalid: + if (cmd) { + kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd)); + } + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nformat:get_report [enable|disable|get|reset]"); + return i4BytesWritten; +} + +static int priv_driver_pta_config(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo; + s32 i4BytesWritten = 0; + u32 u4BufLen = 0; + s32 i4Argc = 0; + u32 u4Val = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + P_CMD_PTA_CONFIG_T cmd = NULL; + s32 u4Ret = 0; + s32 i = 0; + + DBGLOG(REQ, LOUD, "%s(%s)>\n", __func__, pcCommand); + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + if (i4Argc < 2) { + goto set_pta_invalid; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (!prGlueInfo) { + goto set_pta_invalid; + } + + cmd = (P_CMD_PTA_CONFIG_T)kalMemAlloc(sizeof(*cmd), VIR_MEM_TYPE); + if (!cmd) { + goto set_pta_invalid; + } + + memset(cmd, 0, sizeof(*cmd)); + cmd->u2Type = CMD_PTA_CONFIG_TYPE; + cmd->u2Len = sizeof(*cmd); + /* set command + parameter must be even number */ + if ((strnicmp(apcArgv[1], "SET", strlen("SET")) == 0) && + (i4Argc >= 4) && !(i4Argc & 1)) { + cmd->u2Type |= CMD_ADV_CONTROL_SET; + for (i = 2; i < i4Argc; i += 2) { + u4Ret = kalkStrtou32(apcArgv[i + 1], 0, &u4Val); + if (u4Ret) { + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nparsing err(%d) %s %s", u4Ret, + apcArgv[i], apcArgv[i + 1]); + goto set_pta_invalid; + } + + DBGLOG(REQ, LOUD, "arg[%d] %s %s (0x%x)\n", i, + apcArgv[i], apcArgv[i + 1], u4Val); + if (strnicmp(apcArgv[i], "ENABLE", strlen("ENABLE")) == + 0) { + cmd->u4ConfigMask |= CMD_PTA_CONFIG_PTA; + if (u4Val) { + cmd->u4PtaConfig |= + CMD_PTA_CONFIG_PTA_EN; + } + } else if (strnicmp(apcArgv[i], "TXDATA", + strlen("TXDATA")) == 0) { + cmd->u4ConfigMask |= CMD_PTA_CONFIG_TXDATA_TAG; + cmd->u4TxDataTag = u4Val; + } else if (strnicmp(apcArgv[i], "RXDATAACK", + strlen("RXDATAACK")) == 0) { + cmd->u4ConfigMask |= + CMD_PTA_CONFIG_RXDATAACK_TAG; + cmd->u4RxDataAckTag = u4Val; + } else if (strnicmp(apcArgv[i], "RXDATA", + strlen("RXDATA")) == 0) { + cmd->u4ConfigMask |= CMD_PTA_CONFIG_RX_NSW_TAG; + cmd->u4RxNswTag = u4Val; + } else if (strnicmp(apcArgv[i], "TXACK", + strlen("TXACK")) == 0) { + cmd->u4ConfigMask |= CMD_PTA_CONFIG_TXACK_TAG; + cmd->u4TxAckTag = u4Val; + } else if (strnicmp(apcArgv[i], "PROTTAG", + strlen("PROTTAG")) == 0) { + cmd->u4ConfigMask |= + CMD_PTA_CONFIG_TXPROTFRAME_TAG; + cmd->u4ConfigMask |= + CMD_PTA_CONFIG_RXPROTFRAMEACK_TAG; + cmd->u4TxProtFrameTag = u4Val; + cmd->u4RxProtFrameAckTag = u4Val; + } else if (strnicmp(apcArgv[i], "TXBMC", + strlen("TXBMC")) == 0) { + cmd->u4ConfigMask |= CMD_PTA_CONFIG_TX_BMC_TAG; + cmd->u4TxBMCTag = u4Val; + } else if (strnicmp(apcArgv[i], "TXBCN", + strlen("TXBCN")) == 0) { + cmd->u4ConfigMask |= CMD_PTA_CONFIG_TX_BCN_TAG; + cmd->u4TxBCNTag = u4Val; + } else if (strnicmp(apcArgv[i], "RXBCN", + strlen("RXBCN")) == 0) { + cmd->u4ConfigMask |= CMD_PTA_CONFIG_RX_SP_TAG; + cmd->u4RxSPTag = u4Val; + } else if (strnicmp(apcArgv[i], "TXMGMT", + strlen("TXMGMT")) == 0) { + cmd->u4ConfigMask |= CMD_PTA_CONFIG_TX_MGMT_TAG; + cmd->u4TxMgmtTag = u4Val; + } else if (strnicmp(apcArgv[i], "RXMGMTACK", + strlen("RXMGMTACK")) == 0) { + cmd->u4ConfigMask |= + CMD_PTA_CONFIG_RXMGMTACK_TAG; + cmd->u4RxMgmtAckTag = u4Val; + } else if (strnicmp(apcArgv[i], "STATENABLE", + strlen("STATENABLE")) == 0) { + cmd->u4ConfigMask |= CMD_PTA_CONFIG_PTA_STAT; + if (!u4Val) { + cmd->u4PtaConfig &= + ~CMD_PTA_CONFIG_PTA_STAT_EN; + } else { + cmd->u4PtaConfig |= + CMD_PTA_CONFIG_PTA_STAT_EN; + } + } else if (strnicmp(apcArgv[i], "STATRESET", + strlen("STATRESET")) == 0) { + cmd->u4ConfigMask |= + CMD_PTA_CONFIG_PTA_STAT_RESET; + } else if (strnicmp(apcArgv[i], + "COMM_ACT_BT_WF0_INBAND", + strlen("COMM_ACT_BT_WF0_INBAND")) == + 0) { + cmd->u4ConfigMask |= + CMD_PTA_CONFIG_COMM_ACT_BT_WF0_INBAND; + cmd->u4CommActBtWf0Inband = u4Val; + } else if (strnicmp(apcArgv[i], + "COMM_ACT_BT_WF0_OUTBAND", + strlen( + "COMM_ACT_BT_WF0_OUTBAND")) + == + 0) { + cmd->u4ConfigMask |= + CMD_PTA_CONFIG_COMM_ACT_BT_WF0_OUTBAND; + cmd->u4CommActBtWf0Outband = u4Val; + } else if (strnicmp(apcArgv[i], + "COMM_ACT_BT_WF1_INBAND", + strlen("COMM_ACT_BT_WF1_INBAND")) == + 0) { + cmd->u4ConfigMask |= + CMD_PTA_CONFIG_COMM_ACT_BT_WF1_INBAND; + cmd->u4CommActBtWf1Inband = u4Val; + } else if (strnicmp(apcArgv[i], + "COMM_ACT_BT_WF1_OUTBAND", + strlen( + "COMM_ACT_BT_WF1_OUTBAND")) + == + 0) { + cmd->u4ConfigMask |= + CMD_PTA_CONFIG_COMM_ACT_BT_WF1_OUTBAND; + cmd->u4CommActBtWf1Outband = u4Val; + } else { + i4BytesWritten += + snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nunknown parameter %s %s", + apcArgv[i], apcArgv[i + 1]); + goto set_pta_invalid; + } + } + + rStatus = wlanSendSetQueryCmd(prGlueInfo->prAdapter, + CMD_ID_ADV_CONTROL, true, false, + false, NULL, NULL, sizeof(*cmd), + (u8 *)cmd, NULL, 0); + } else if (strnicmp(apcArgv[1], "GET", strlen("GET")) == 0) { + rStatus = kalIoctl(prGlueInfo, wlanoidAdvCtrl, cmd, + sizeof(*cmd), true, true, true, &u4BufLen); + } else { + goto set_pta_invalid; + } + + if ((rStatus != WLAN_STATUS_SUCCESS) && + (rStatus != WLAN_STATUS_PENDING)) { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\ncommand failed %x", rStatus); + } else if (!(cmd->u2Type & CMD_ADV_CONTROL_SET)) { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nCoex mode: %s", + (cmd->u4CoexMode) ? "FDD" : "TDD"); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nPTA status:"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n module enable %x wifi %x bt %x wifi arb %x", + (cmd->u4PtaConfig >> EVENT_CONFIG_PTA_OFFSET) & + EVENT_CONFIG_PTA_FEILD, + (cmd->u4PtaConfig >> EVENT_CONFIG_PTA_WIFI_OFFSET) & + EVENT_CONFIG_PTA_WIFI_FEILD, + (cmd->u4PtaConfig >> EVENT_CONFIG_PTA_BT_OFFSET) & + EVENT_CONFIG_PTA_BT_FEILD, + (cmd->u4PtaConfig >> EVENT_CONFIG_PTA_ARB_OFFSET) & + EVENT_CONFIG_PTA_ARB_FEILD); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nPriority stat:"); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n txData %d", cmd->u4TxDataTag); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n rxDataAck %d", + cmd->u4RxDataAckTag); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n rxData %d", cmd->u4RxNswTag); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n txAck %d", cmd->u4TxAckTag); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n txBmc %d", cmd->u4TxBMCTag); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n txBcn %d", cmd->u4TxBCNTag); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n txMgmt %d", cmd->u4TxMgmtTag); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n rxMgmtAck %d", + cmd->u4RxMgmtAckTag); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n rxBcn %d", cmd->u4RxSPTag); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n prottag %d", + cmd->u4TxProtFrameTag); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nLast fetched grant stat:"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n wifi grant %x txreq %x rxreq %x pritag %x", + (cmd->u4GrantStat >> EVENT_CONFIG_WIFI_GRANT_OFFSET) & + EVENT_CONFIG_WIFI_GRANT_FEILD, + (cmd->u4GrantStat >> EVENT_CONFIG_WIFI_TXREQ_OFFSET) & + EVENT_CONFIG_WIFI_TXREQ_FEILD, + (cmd->u4GrantStat >> EVENT_CONFIG_WIFI_RXREQ_OFFSET) & + EVENT_CONFIG_WIFI_RXREQ_FEILD, + (cmd->u4GrantStat >> EVENT_CONFIG_WIFI_PRI_OFFSET) & + EVENT_CONFIG_WIFI_PRI_FEILD); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n bt grant %x txreq %x rxreq %x pritag %x", + (cmd->u4GrantStat >> EVENT_CONFIG_BT_GRANT_OFFSET) & + EVENT_CONFIG_BT_GRANT_FEILD, + (cmd->u4GrantStat >> EVENT_CONFIG_BT_TXREQ_OFFSET) & + EVENT_CONFIG_BT_TXREQ_FEILD, + (cmd->u4GrantStat >> EVENT_CONFIG_BT_RXREQ_OFFSET) & + EVENT_CONFIG_BT_RXREQ_FEILD, + (cmd->u4GrantStat >> EVENT_CONFIG_BT_PRI_OFFSET) & + EVENT_CONFIG_BT_PRI_FEILD); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nPTA stat:"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n wf0 txreq_cnt %d txgrant_cnt %d txabort_cnt %d", + (cmd->u4PtaWF0TxCnt >> EVENT_PTA_WFTRX_CNT_OFFSET) & + EVENT_PTA_WFTRX_CNT_FEILD, + (cmd->u4PtaWF0TxCnt >> + EVENT_PTA_WFTRX_GRANT_CNT_OFFSET) & + EVENT_PTA_WFTRX_GRANT_CNT_FEILD, + (cmd->u4PtaWF0AbtCnt >> EVENT_PTA_TX_ABT_CNT_OFFSET) & + EVENT_PTA_TX_ABT_CNT_FEILD); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n wf0 rxreq_cnt %d rxgrant_cnt %d rxabort_cnt %d", + (cmd->u4PtaWF0RxCnt >> EVENT_PTA_WFTRX_CNT_OFFSET) & + EVENT_PTA_WFTRX_CNT_FEILD, + (cmd->u4PtaWF0RxCnt >> + EVENT_PTA_WFTRX_GRANT_CNT_OFFSET) & + EVENT_PTA_WFTRX_GRANT_CNT_FEILD, + (cmd->u4PtaWF0AbtCnt >> EVENT_PTA_RX_ABT_CNT_OFFSET) & + EVENT_PTA_RX_ABT_CNT_FEILD); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n wf1 txreq_cnt %d txgrant_cnt %d txabort_cnt %d", + (cmd->u4PtaWF1TxCnt >> EVENT_PTA_WFTRX_CNT_OFFSET) & + EVENT_PTA_WFTRX_CNT_FEILD, + (cmd->u4PtaWF1TxCnt >> + EVENT_PTA_WFTRX_GRANT_CNT_OFFSET) & + EVENT_PTA_WFTRX_GRANT_CNT_FEILD, + (cmd->u4PtaWF1AbtCnt >> EVENT_PTA_TX_ABT_CNT_OFFSET) & + EVENT_PTA_TX_ABT_CNT_FEILD); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n wf1 rxreq_cnt %d rxgrant_cnt %d rxabort_cnt %d", + (cmd->u4PtaWF1RxCnt >> EVENT_PTA_WFTRX_CNT_OFFSET) & + EVENT_PTA_WFTRX_CNT_FEILD, + (cmd->u4PtaWF1RxCnt >> + EVENT_PTA_WFTRX_GRANT_CNT_OFFSET) & + EVENT_PTA_WFTRX_GRANT_CNT_FEILD, + (cmd->u4PtaWF1AbtCnt >> EVENT_PTA_RX_ABT_CNT_OFFSET) & + EVENT_PTA_RX_ABT_CNT_FEILD); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n bt txreq_cnt %d txgrant_cnt %d txabort_cnt %d", + (cmd->u4PtaBTTxCnt >> EVENT_PTA_BTTRX_CNT_OFFSET) & + EVENT_PTA_BTTRX_CNT_FEILD, + (cmd->u4PtaBTTxCnt >> + EVENT_PTA_BTTRX_GRANT_CNT_OFFSET) & + EVENT_PTA_BTTRX_GRANT_CNT_FEILD, + (cmd->u4PtaBTAbtCnt >> EVENT_PTA_TX_ABT_CNT_OFFSET) & + EVENT_PTA_TX_ABT_CNT_FEILD); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n bt rxreq_cnt %d rxgrant_cnt %d rxabort_cnt %d", + (cmd->u4PtaBTRxCnt >> EVENT_PTA_BTTRX_CNT_OFFSET) & + EVENT_PTA_BTTRX_CNT_FEILD, + (cmd->u4PtaBTRxCnt >> + EVENT_PTA_BTTRX_GRANT_CNT_OFFSET) & + EVENT_PTA_BTTRX_GRANT_CNT_FEILD, + (cmd->u4PtaBTAbtCnt >> EVENT_PTA_RX_ABT_CNT_OFFSET) & + EVENT_PTA_RX_ABT_CNT_FEILD); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nCommon action stat (1:allow, 0:not allow):"); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n inband arb mode"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_TX vs WF0_RX[b0]: %d", + (cmd->u4CommActBtWf0Inband & BIT(0)) >> 0); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_RX vs WF0_TX[b1]: %d", + (cmd->u4CommActBtWf0Inband & BIT(1)) >> 1); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_RX vs WF0_RX[b2]: %d", + (cmd->u4CommActBtWf0Inband & BIT(2)) >> 2); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_TX vs WF0_TX[b3]: %d\n", + (cmd->u4CommActBtWf0Inband & BIT(3)) >> 3); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_TX vs WF1_RX[b0]: %d", + (cmd->u4CommActBtWf1Inband & BIT(0)) >> 0); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_RX vs WF1_TX[b1]: %d", + (cmd->u4CommActBtWf1Inband & BIT(1)) >> 1); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_RX vs WF1_RX[b2]: %d", + (cmd->u4CommActBtWf1Inband & BIT(2)) >> 2); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_TX vs WF1_TX[b3]: %d\n", + (cmd->u4CommActBtWf1Inband & BIT(3)) >> 3); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n outband arb mode"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_TX vs WF0_RX[b0]: %d", + (cmd->u4CommActBtWf0Outband & BIT(0)) >> 0); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_RX vs WF0_TX[b1]: %d", + (cmd->u4CommActBtWf0Outband & BIT(1)) >> 1); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_RX vs WF0_RX[b2]: %d", + (cmd->u4CommActBtWf0Outband & BIT(2)) >> 2); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_TX vs WF0_TX[b3]: %d\n", + (cmd->u4CommActBtWf0Outband & BIT(3)) >> 3); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_TX vs WF1_RX[b0]: %d", + (cmd->u4CommActBtWf1Outband & BIT(0)) >> 0); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_RX vs WF1_TX[b1]: %d", + (cmd->u4CommActBtWf1Outband & BIT(1)) >> 1); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_RX vs WF1_RX[b2]: %d", + (cmd->u4CommActBtWf1Outband & BIT(2)) >> 2); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n BT_TX vs WF1_TX[b3]: %d\n", + (cmd->u4CommActBtWf1Outband & BIT(3)) >> 3); + } else { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\ncommand sent %x", rStatus); + } + + if (cmd) { + kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd)); + } + + return i4BytesWritten; + +set_pta_invalid: + if (cmd) { + kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd)); + } + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nformat:pta_config set [enable 1|0][txdata val][rxdataack val]"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n\t[rxdata val][txack val][txbmc val][txbcn val][rxbcn val]"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n\t[txmgmt val][rxmgmtack val][prottag val]"); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n\t[statenable 1|0][statreset 1]"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n\t[comm_act_bt_wf0_inband val][comm_act_bt_wf1_inband val]"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n\t[comm_act_bt_wf0_outband val][comm_act_bt_wf1_outband val]"); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n [enable val]: enable PTA(1) or not(0)"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [txtag val<0~15>]: priority tag for tx ac0-ac3"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [rxdataack val<0~15>]: priority tag for rx ac0-ac3 ack"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [rxdata val<0~15>]: priority tag for rx data"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [txack val<0~15>]: priority tag for tx ack"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [txbmc val<0~15>]: priority tag for tx bmc packet"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [txbcn val<0~15>]: priority tag for tx beacon"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [rxbcn val<0~15>]: priority tag for rx beacon"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [prottag val<0~15>]: priority tag for Protection frame"); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nformat(%d):pta_config get", i4Argc); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n [comm_act_bt_wf0_inband val<0~15>]: bt&wf0 inband common action"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n [comm_act_bt_wf1_inband val<0~15>]: bt&wf1 inband common action"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n [comm_act_bt_wf0_outband val<0~15>]: bt&wf0 outband common action"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n [comm_act_bt_wf1_outband val<0~15>]: bt&wf1 outband common action"); + return i4BytesWritten; +} + +#ifdef CFG_SUPPORT_EXT_PTA_DEBUG_COMMAND +static int priv_driver_ext_pta_config(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + P_CMD_EXT_PTA_CONFIG_T cmd = NULL; + s32 i4BytesWritten = 0; + u32 u4Val = 0; + s32 u4Ret = 0; + s32 i = 0; + u32 u4BufLen = 0; + u32 u4TotalReqCnt = 0; + + DBGLOG(REQ, LOUD, "%s(%s)>\n", __func__, pcCommand); + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + if (i4Argc < 2) { + goto set_ext_pta_invalid; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (!prGlueInfo) { + goto set_ext_pta_invalid; + } + + cmd = (P_CMD_EXT_PTA_CONFIG_T)kalMemAlloc(sizeof(*cmd), VIR_MEM_TYPE); + if (!cmd) { + goto set_ext_pta_invalid; + } + + memset(cmd, 0, sizeof(*cmd)); + cmd->u2Type = CMD_EXT_PTA_CONFIG_TYPE; + cmd->u2Len = sizeof(*cmd); + + if ((strnicmp(apcArgv[1], "SET", strlen("SET")) == 0) && + (i4Argc >= 4) && !(i4Argc & 1)) { + cmd->u2Type |= CMD_ADV_CONTROL_SET; + + /* parsing parameters (data value) */ + for (i = 2; i < i4Argc; i += 2) { + /* value field */ + u4Ret = kalkStrtou32(apcArgv[i + 1], 0, &u4Val); + if (u4Ret) { + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nparsing err(%d) %s %s", u4Ret, + apcArgv[i], apcArgv[i + 1]); + goto set_ext_pta_invalid; + } + + DBGLOG(REQ, LOUD, "arg[%d] %s %s (0x%x)\n", i, + apcArgv[i], apcArgv[i + 1], u4Val); + + /* data field*/ + if (strnicmp(apcArgv[i], "ENABLE", strlen("ENABLE")) == + 0) { + cmd->u4ConfigMask |= CMD_EXT_PTA_CONFIG_EXT_PTA; + cmd->u4ExtPtaConfig = u4Val; + } else if (strnicmp(apcArgv[i], "LOTX", + strlen("LOTX")) == 0) { + cmd->u4ConfigMask |= + CMD_EXT_PTA_CONFIG_LO_TX_TAG; + cmd->u4ZbLoTxTag = u4Val; + } else if (strnicmp(apcArgv[i], "HITX", + strlen("HITX")) == 0) { + cmd->u4ConfigMask |= + CMD_EXT_PTA_CONFIG_HI_TX_TAG; + cmd->u4ZbHiTxTag = u4Val; + } else if (strnicmp(apcArgv[i], "LORX", + strlen("LORX")) == 0) { + cmd->u4ConfigMask |= + CMD_EXT_PTA_CONFIG_LO_RX_TAG; + cmd->u4ZbLoRxTag = u4Val; + } else if (strnicmp(apcArgv[i], "HIRX", + strlen("HIRX")) == 0) { + cmd->u4ConfigMask |= + CMD_EXT_PTA_CONFIG_HI_RX_TAG; + cmd->u4ZbHiRxTag = u4Val; + } else if (strnicmp(apcArgv[i], "COMM_ACT_ZB_BT_UNSAFE", + strlen("COMM_ACT_ZB_BT_UNSAFE")) == + 0) { + cmd->u4ConfigMask |= + CMD_EXT_PTA_CONFIG_COMM_ACT_ZB_BT_UNSAFE; + cmd->u4CommActZbBtUnsafe = u4Val; + } else if (strnicmp(apcArgv[i], "COMM_ACT_ZB_BT_HSF", + strlen("COMM_ACT_ZB_BT_HSF")) == + 0) { + cmd->u4ConfigMask |= + CMD_EXT_PTA_CONFIG_COMM_ACT_ZB_BT_HSF; + cmd->u4CommActZbBtHsf = u4Val; + } else if (strnicmp(apcArgv[i], + "COMM_ACT_ZB_WF0_UNSAFE", + strlen("COMM_ACT_ZB_WF0_UNSAFE")) == + 0) { + cmd->u4ConfigMask |= + CMD_EXT_PTA_CONFIG_COMM_ACT_ZB_WF0_UNSAFE; + cmd->u4CommActZbWf0Unsafe = u4Val; + } else if (strnicmp(apcArgv[i], "COMM_ACT_ZB_WF0_HSF", + strlen("COMM_ACT_ZB_WF0_HSF")) == + 0) { + cmd->u4ConfigMask |= + CMD_EXT_PTA_CONFIG_COMM_ACT_ZB_WF0_HSF; + cmd->u4CommActZbWf0Hsf = u4Val; + } else if (strnicmp(apcArgv[i], + "COMM_ACT_ZB_WF1_UNSAFE", + strlen("COMM_ACT_ZB_WF1_UNSAFE")) == + 0) { + cmd->u4ConfigMask |= + CMD_EXT_PTA_CONFIG_COMM_ACT_ZB_WF1_UNSAFE; + cmd->u4CommActZbWf1Unsafe = u4Val; + } else if (strnicmp(apcArgv[i], "COMM_ACT_ZB_WF1_HSF", + strlen("COMM_ACT_ZB_WF1_HSF")) == + 0) { + cmd->u4ConfigMask |= + CMD_EXT_PTA_CONFIG_COMM_ACT_ZB_WF1_HSF; + cmd->u4CommActZbWf1Hsf = u4Val; + } else { + i4BytesWritten += + snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nunknown parameter %s %s", + apcArgv[i], apcArgv[i + 1]); + goto set_ext_pta_invalid; + } + } + + /* send to FW */ + rStatus = wlanSendSetQueryCmd(prGlueInfo->prAdapter, + CMD_ID_ADV_CONTROL, true, false, + false, NULL, NULL, sizeof(*cmd), + (u8 *)cmd, NULL, 0); + } else if (strnicmp(apcArgv[1], "GET", strlen("GET")) == 0) { + rStatus = kalIoctl(prGlueInfo, wlanoidAdvCtrl, cmd, + sizeof(*cmd), true, true, true, &u4BufLen); + } else { + goto set_ext_pta_invalid; + } + + if ((rStatus != WLAN_STATUS_SUCCESS) && + (rStatus != WLAN_STATUS_PENDING)) { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\ncommand failed %x", rStatus); + } else if (!(cmd->u2Type & CMD_ADV_CONTROL_SET)) { + u4TotalReqCnt = cmd->u4ZbLoTxReqCnt + cmd->u4ZbHiTxReqCnt + + cmd->u4ZbLoRxReqCnt + cmd->u4ZbHiRxReqCnt; + + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nPriority stat:"); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n ZB Lo TX : %d", + cmd->u4ZbLoTxTag); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n ZB Hi TX : %d", + cmd->u4ZbHiTxTag); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n ZB Lo RX : %d", + cmd->u4ZbLoRxTag); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n ZB Hi RX : %d", + cmd->u4ZbHiRxTag); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nCommon action stat (1:allow, 0:not allow):"); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n Unsafe arb mode"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n ZB_TX vs BT_RX[b0]: %d", + (cmd->u4CommActZbBtUnsafe & BIT(0)) >> 0); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n ZB_RX vs BT_TX[b1]: %d", + (cmd->u4CommActZbBtUnsafe & BIT(1)) >> 1); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n ZB_RX vs BT_RX[b2]: %d", + (cmd->u4CommActZbBtUnsafe & BIT(2)) >> 2); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n ZB_TX vs BT_TX[b3]: %d\n", + (cmd->u4CommActZbBtUnsafe & BIT(3)) >> 3); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF0_TX vs ZB_RX[b0]: %d", + (cmd->u4CommActZbWf0Unsafe & BIT(0)) >> 0); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF0_RX vs ZB_TX[b1]: %d", + (cmd->u4CommActZbWf0Unsafe & BIT(1)) >> 1); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF0_RX vs ZB_RX[b2]: %d", + (cmd->u4CommActZbWf0Unsafe & BIT(2)) >> 2); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF0_TX vs ZB_TX[b3]: %d\n", + (cmd->u4CommActZbWf0Unsafe & BIT(3)) >> 3); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF1_TX vs ZB_RX[b0]: %d", + (cmd->u4CommActZbWf1Unsafe & BIT(0)) >> 0); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF1_RX vs ZB_TX[b1]: %d", + (cmd->u4CommActZbWf1Unsafe & BIT(1)) >> 1); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF1_RX vs ZB_RX[b2]: %d", + (cmd->u4CommActZbWf1Unsafe & BIT(2)) >> 2); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF1_TX vs ZB_TX[b3]: %d\n", + (cmd->u4CommActZbWf1Unsafe & BIT(3)) >> 3); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n half-safe arb mode"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n ZB_TX vs BT_RX[b0]: %d", + (cmd->u4CommActZbBtHsf & BIT(0)) >> 0); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n ZB_RX vs BT_TX[b1]: %d", + (cmd->u4CommActZbBtHsf & BIT(1)) >> 1); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n ZB_RX vs BT_RX[b2]: %d", + (cmd->u4CommActZbBtHsf & BIT(2)) >> 2); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n ZB_TX vs BT_TX[b3]: %d\n", + (cmd->u4CommActZbBtHsf & BIT(3)) >> 3); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF0_TX vs ZB_RX[b0]: %d", + (cmd->u4CommActZbWf0Hsf & BIT(0)) >> 0); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF0_RX vs ZB_TX[b1]: %d", + (cmd->u4CommActZbWf0Hsf & BIT(1)) >> 1); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF0_RX vs ZB_RX[b2]: %d", + (cmd->u4CommActZbWf0Hsf & BIT(2)) >> 2); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF0_TX vs ZB_TX[b3]: %d\n", + (cmd->u4CommActZbWf0Hsf & BIT(3)) >> 3); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF1_TX vs ZB_RX[b0]: %d", + (cmd->u4CommActZbWf1Hsf & BIT(0)) >> 0); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF1_RX vs ZB_TX[b1]: %d", + (cmd->u4CommActZbWf1Hsf & BIT(1)) >> 1); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF1_RX vs ZB_RX[b2]: %d", + (cmd->u4CommActZbWf1Hsf & BIT(2)) >> 2); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n WF1_TX vs ZB_TX[b3]: %d", + (cmd->u4CommActZbWf1Hsf & BIT(3)) >> 3); + + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nCounter stat:"); + if (cmd->u4ConfigMask & CMD_EXT_PTA_CONFIG_EXT_PTA) { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n Grant cnt: %d", + cmd->u4ZbGntCnt); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n Abort cnt: %d", + cmd->u4ZbAbtCnt); + i4BytesWritten += + snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n Denied cnt: %d", + u4TotalReqCnt - cmd->u4ZbGntCnt); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n Lo tx req cnt: %d", + cmd->u4ZbLoTxReqCnt); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n Hi tx req cnt: %d", + cmd->u4ZbHiTxReqCnt); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n Lo rx req cnt: %d", + cmd->u4ZbLoRxReqCnt); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n Hi rx req cnt: %d", + cmd->u4ZbHiRxReqCnt); + } else { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n Don't support"); + } + } else { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\ncommand sent %x", rStatus); + } + + if (cmd) { + kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd)); + } + + return i4BytesWritten; + +set_ext_pta_invalid: + if (cmd) { + kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd)); + } + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nformat:ext_pta_config set [enable 1|0][lotx val][hitx val]"); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n\t[lorx val][hirx val]"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n\t[comm_act_zb_bt_unsafe val][comm_act_zb_bt_hsf val]"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n\t[comm_act_zb_wf0_unsafe val][comm_act_zb_wf0_hsf val]"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n\t[comm_act_zb_wf1_unsafe val][comm_act_zb_wf1_hsf val]"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [enable val]: enable EXT PTA(1) or not(0)"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [lotx val<0~15>]: priority tag for lo tx"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [hitx val<0~15>]: priority tag for hi tx"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [lorx val<0~15>]: priority tag for lo rx"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [hirx val<0~15>]: priority tag for lo tx"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n [comm_act_zb_bt_unsafe val<0~15>]: zb&bt unsafe common action"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [comm_act_zb_bt_hsf val<0~15>]: zb&bt hsf common action"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n [comm_act_zb_wf0_unsafe val<0~15>]: zb&wf0 unsafe common action"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [comm_act_zb_wf0_hsf val<0~15>]: zb&wf0 hsf common action"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n [comm_act_zb_wf1_unsafe val<0~15>]: zb&wf1 unsafe common action"); + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n [comm_act_zb_wf1_hsf val<0~15>]: zb&wf1 hsf common action"); + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nformat(%d):pta_config get", i4Argc); + return i4BytesWritten; +} +#endif +static int priv_driver_set_pop(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 u4Ret = 0; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_SET_ID + CMD_ADVCTL_POP_ID; + u32 u4Sel = 0, u4CckTh = 0, u4OfdmTh = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + rSwCtrlInfo.u4Id = u4Id; + + if (i4Argc <= 3) { + DBGLOG(REQ, ERROR, + "Argc(%d) ERR: SET_POP <Sel> <CCK TH> <OFDM TH>\n", + i4Argc); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4Sel); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error u4Ret=%d\n", u4Ret); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[2], 0, &u4CckTh); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error u4Ret=%d\n", u4Ret); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[3], 0, &u4OfdmTh); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error u4Ret=%d\n", u4Ret); + return -1; + } + + rSwCtrlInfo.u4Data = (u4CckTh | (u4OfdmTh << 8) | (u4Sel << 30)); + DBGLOG(REQ, LOUD, "u4Sel=%d u4CckTh=%d u4OfdmTh=%d, u4Data=0x%x,\n", + u4Sel, u4CckTh, u4OfdmTh, rSwCtrlInfo.u4Data); + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} + +static int priv_driver_get_pop(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_POP_ID; + u32 u4Offset = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + u32 u4CckTh = 0, u4OfdmTh = 0; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = u4Id; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + u4CckTh = rSwCtrlInfo.u4Data & 0xFF; + u4OfdmTh = (rSwCtrlInfo.u4Data >> 8) & 0xFF; + + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "PoP: CckTh:%ddB OfdmTh:%ddB\n", u4CckTh, + u4OfdmTh); + + i4BytesWritten = (s32)u4Offset; + + return i4BytesWritten; +} + +static int priv_driver_set_ed(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 i4Ret = 0; + s32 i4EdVal[2] = { 0 }; + u32 u4Sel = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + if (prAdapter == NULL) { + DBGLOG(REQ, LOUD, "Adapter is NULL!\n"); + return -1; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc <= 3) { + DBGLOG(REQ, + ERROR, + "Argc(%d) ERR: SET_ED <Sel> <2.4G EDCCA(-49~-81dBm)> <5G EDCCA(-49~-81dBm)>\n", + i4Argc); + return -1; + } + + i4Ret = kalkStrtou32(apcArgv[1], 0, &u4Sel); + if (i4Ret) { + DBGLOG(REQ, ERROR, "parse error i4Ret=%d\n", i4Ret); + return -1; + } + + i4Ret = kalkStrtos32(apcArgv[2], 0, &i4EdVal[0]); + if (i4Ret) { + DBGLOG(REQ, ERROR, "parse i4EdVal(2.4G) error i4Ret=%d\n", + i4Ret); + } + i4Ret = kalkStrtos32(apcArgv[3], 0, &i4EdVal[1]); + if (i4Ret) { + DBGLOG(REQ, ERROR, "parse i4EdVal(5G) error u4Ret=%d\n", i4Ret); + } + + rStatus = wlanSetEd(prAdapter, i4EdVal[0], i4EdVal[1], u4Sel); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} + +static int priv_driver_get_ed(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_ED_ID; + u32 u4Offset = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + s8 iEdVal[2] = { 0 }; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = u4Id; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + iEdVal[0] = rSwCtrlInfo.u4Data & 0xFF; + iEdVal[1] = (rSwCtrlInfo.u4Data >> 16) & 0xFF; + + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "ED: 2.4G(%ddB), 5G(%ddB)\n", iEdVal[0], + iEdVal[1]); + + i4BytesWritten = (s32)u4Offset; + + return i4BytesWritten; +} + +static int priv_driver_set_pd(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 u4Ret = 0; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_SET_ID + CMD_ADVCTL_PD_ID; + u32 u4Sel = 0; + s32 u4CckTh = 0, u4OfdmTh = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + rSwCtrlInfo.u4Id = u4Id; + + if (i4Argc <= 1) { + DBGLOG(REQ, ERROR, + "Argc(%d) ERR: SET_PD <Sel> [CCK TH] [OFDM TH]\n", + i4Argc); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4Sel); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error u4Ret=%d\n", u4Ret); + return -1; + } + + if (u4Sel == 1) { + if (i4Argc <= 3) { + DBGLOG(REQ, ERROR, + "Argc(%d) ERR: SET_PD 1 <CCK TH> <OFDM CH>\n", + i4Argc); + return -1; + } + u4Ret = kalkStrtos32(apcArgv[2], 0, &u4CckTh); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error u4Ret=%d\n", + u4Ret); + } + u4Ret = kalkStrtos32(apcArgv[3], 0, &u4OfdmTh); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error u4Ret=%d\n", + u4Ret); + } + } + + rSwCtrlInfo.u4Data = ((u4OfdmTh & 0xFFFF) | ((u4CckTh & 0xFF) << 16) | + (u4Sel << 30)); + DBGLOG(REQ, LOUD, "u4Sel=%d u4OfdmTh=%d, u4CckTh=%d, u4Data=0x%x,\n", + u4Sel, u4OfdmTh, u4CckTh, rSwCtrlInfo.u4Data); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} + +static int priv_driver_get_pd(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_PD_ID; + u32 u4Offset = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + s8 u4CckTh = 0, u4OfdmTh = 0; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = u4Id; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + u4CckTh = rSwCtrlInfo.u4Data & 0xFF; + u4OfdmTh = (rSwCtrlInfo.u4Data >> 8) & 0xFF; + + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "PD: CckTh:%ddB OfdmTh:%ddB\n", u4CckTh, u4OfdmTh); + + i4BytesWritten = (s32)u4Offset; + + return i4BytesWritten; +} + +static int priv_cmd_not_support(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + DBGLOG(REQ, WARN, "not support priv command: %s\n", pcCommand); + + return -EOPNOTSUPP; +} + +static int priv_driver_set_maxrfgain(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 u4Ret = 0; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_SET_ID + CMD_ADVCTL_MAX_RFGAIN_ID; + u32 u4Sel = 0; + s32 u4Wf0Gain = 0, u4Wf1Gain = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + rSwCtrlInfo.u4Id = u4Id; + + if (i4Argc <= 1) { + DBGLOG(REQ, ERROR, + "Argc(%d) ERR: SET_RFGAIN <Sel> <WF0 Gain> <WF1 Gain>\n", + i4Argc); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4Sel); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error u4Ret=%d\n", u4Ret); + return -1; + } + + if (u4Sel == 1) { + if (i4Argc <= 3) { + DBGLOG(REQ, + ERROR, + "Argc(%d) ERR: SET_RFGAIN 1 <WF0 Gain> <WF1 Gain>\n", + i4Argc); + return -1; + } + u4Ret = kalkStrtos32(apcArgv[2], 0, &u4Wf0Gain); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error u4Ret=%d\n", + u4Ret); + } + u4Ret = kalkStrtos32(apcArgv[3], 0, &u4Wf1Gain); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error u4Ret=%d\n", + u4Ret); + } + } + + rSwCtrlInfo.u4Data = ((u4Wf0Gain & 0xFF) | ((u4Wf1Gain & 0xFF) << 8) | + (u4Sel << 31)); + DBGLOG(REQ, LOUD, "u4Sel=%d u4Wf0Gain=%d, u4Wf1Gain=%d, u4Data=0x%x,\n", + u4Sel, u4Wf0Gain, u4Wf1Gain, rSwCtrlInfo.u4Data); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} + +static int priv_driver_get_maxrfgain(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_MAX_RFGAIN_ID; + u32 u4Offset = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + u8 u4Wf0Gain = 0, u4Wf1Gain = 0; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = u4Id; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + u4Wf0Gain = rSwCtrlInfo.u4Data & 0xFF; + u4Wf1Gain = (rSwCtrlInfo.u4Data >> 8) & 0xFF; + + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "Max RFGain: WF0:%ddB WF1:%ddB\n", u4Wf0Gain, + u4Wf1Gain); + + i4BytesWritten = (s32)u4Offset; + + return i4BytesWritten; +} + +static int priv_driver_noise_histogram(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + P_GLUE_INFO_T prGlueInfo; + s32 i4BytesWritten = 0; + u32 u4BufLen = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + struct CMD_NOISE_HISTOGRAM_REPORT *cmd = NULL; + + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (!prGlueInfo) { + goto noise_histogram_invalid; + } + + cmd = (struct CMD_NOISE_HISTOGRAM_REPORT *)kalMemAlloc(sizeof(*cmd), + VIR_MEM_TYPE); + if (!cmd) { + goto noise_histogram_invalid; + } + + if ((i4Argc > 4) || (i4Argc < 2)) { + goto noise_histogram_invalid; + } + + memset(cmd, 0, sizeof(*cmd)); + + cmd->u2Type = CMD_NOISE_HISTOGRAM_TYPE; + cmd->u2Len = sizeof(*cmd); + + if (strnicmp(apcArgv[1], "ENABLE", strlen("ENABLE")) == 0) { + /* NoiseHistogram Enable cmd is blocked when entering suspend + * mode */ + if (prGlueInfo->prAdapter->u4IsKeepFullPwrBitmap & + BLOCK_KEEP_FULL_PWR) { + DBGLOG(REQ, STATE, + "NoiseHistogram Enable Command is blocked\n"); + goto noise_histogram_invalid; + } + prGlueInfo->prAdapter->u4IsKeepFullPwrBitmap |= + KEEP_FULL_PWR_NOISE_HISTOGRAM_BIT; + cmd->ucAction = CMD_NOISE_HISTOGRAM_ENABLE; + cmd->u2Type |= CMD_ADV_CONTROL_SET; + } else if (strnicmp(apcArgv[1], "DISABLE", strlen("DISABLE")) == 0) { + prGlueInfo->prAdapter->u4IsKeepFullPwrBitmap &= + ~KEEP_FULL_PWR_NOISE_HISTOGRAM_BIT; + cmd->ucAction = CMD_NOISE_HISTOGRAM_DISABLE; + cmd->u2Type |= CMD_ADV_CONTROL_SET; + } else if (strnicmp(apcArgv[1], "RESET", strlen("RESET")) == 0) { + cmd->ucAction = CMD_NOISE_HISTOGRAM_RESET; + cmd->u2Type |= CMD_ADV_CONTROL_SET; +#if CFG_IPI_2CHAIN_SUPPORT + } else if (strnicmp(apcArgv[1], "GET2", strlen("GET2")) == 0) { + /* + * For getting backward compatibility + * to original format for default chain + */ + cmd->u2Type = CMD_NOISE_HISTOGRAM_TYPE2; + cmd->ucAction = CMD_NOISE_HISTOGRAM_GET; + rStatus = kalIoctl(prGlueInfo, wlanoidAdvCtrl, cmd, + sizeof(*cmd), true, true, true, &u4BufLen); + if (rStatus == WLAN_STATUS_SUCCESS) { + parseNoiseHistogramReport(&i4BytesWritten, pcCommand, + &i4TotalLen, cmd); + } + + cmd->ucAction = CMD_NOISE_HISTOGRAM_GET2; +#endif + } else if (strnicmp(apcArgv[1], "GET", strlen("GET")) == 0) { + cmd->ucAction = CMD_NOISE_HISTOGRAM_GET; + } else { + goto noise_histogram_invalid; + } + + DBGLOG(REQ, LOUD, "%s(%s) action %x\n", __func__, pcCommand, + cmd->ucAction); + + rStatus = kalIoctl(prGlueInfo, wlanoidAdvCtrl, cmd, sizeof(*cmd), true, + true, true, &u4BufLen); + + if (rStatus == WLAN_STATUS_NOT_SUPPORTED) { + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nThis fw version does not support priv command: %s\n", + pcCommand); + } else if ((rStatus != WLAN_STATUS_SUCCESS) && + (rStatus != WLAN_STATUS_PENDING)) { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\ncommand failed %x", rStatus); + } else if (cmd->ucAction == CMD_NOISE_HISTOGRAM_GET +#if CFG_IPI_2CHAIN_SUPPORT + || cmd->ucAction == CMD_NOISE_HISTOGRAM_GET2 +#endif + ) { + parseNoiseHistogramReport(&i4BytesWritten, pcCommand, + &i4TotalLen, cmd); + } else { + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\ncommand sent %x", rStatus); + } + + if (cmd) { + kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd)); + } + + return i4BytesWritten; + +noise_histogram_invalid: + if (cmd) { + kalMemFree(cmd, VIR_MEM_TYPE, sizeof(*cmd)); + } + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nformat:get_report [enable|disable|get|reset]"); + return i4BytesWritten; +} + +static int priv_driver_set_adm_ctrl(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 u4Ret = 0; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_SET_ID + CMD_ADVCTL_ADM_CTRL_ID; + u32 u4Enable = 0, u4TimeRatio = 100, u4AdmBase = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + rSwCtrlInfo.u4Id = u4Id; + + if ((i4Argc > 4) || (i4Argc < 2)) { + DBGLOG(REQ, ERROR, "Argc(%d) ERR: set_admission_ctrl\n", + i4Argc); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4Enable); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse u4Enable error u4Ret=%d\n", u4Ret); + return -1; + } + + if (i4Argc > 2) { + /* u4AdmTime default is 100% */ + u4Ret = kalkStrtos32(apcArgv[2], 0, &u4TimeRatio); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse u4AdmTime error u4Ret=%d\n", + u4Ret); + } + } + + if (i4Argc > 3) { + u4Ret = kalkStrtos32(apcArgv[3], 0, &u4AdmBase); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse u4AdmBase error u4Ret=%d\n", + u4Ret); + } + } + + rSwCtrlInfo.u4Data = + ((u4AdmBase & 0xFFFF) | ((u4TimeRatio & 0xFF) << 16) | + ((u4Enable & 0xFF) << 24)); + DBGLOG(REQ, LOUD, + "u4Enable=%d u4AdmTime=%d, u4AdmBase=%d, u4Data=0x%x,\n", + u4Enable, u4TimeRatio, u4AdmBase, rSwCtrlInfo.u4Data); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} + +#if CFG_ENABLE_PS_INTV_CTRL +static int priv_driver_set_act_intv(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 i4Ret = 0; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_SET_ID + CMD_ADVCTL_ACT_INTV_ID; + u16 ucSwitchInterval, ucMeasureInterval; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + rSwCtrlInfo.u4Id = u4Id; + + if (i4Argc != 3) { + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nformat:set_act_intv <SwitchIntv> <MeasureIntv>"); + return i4BytesWritten; + } + + i4Ret = kalkStrtou16(apcArgv[1], 0, &ucSwitchInterval); + if (i4Ret) { + DBGLOG(REQ, ERROR, "parse BSSIndex error i4Ret=%d\n", i4Ret); + } + + i4Ret = kalkStrtou16(apcArgv[2], 0, &ucMeasureInterval); + if (i4Ret) { + DBGLOG(REQ, ERROR, "parse SwitchInterval error i4Ret=%d\n", + i4Ret); + } + + if (ucSwitchInterval < 10 || ucSwitchInterval > 65535) { + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n<SwitchInterval> range is 10 to 65535"); + return i4BytesWritten; + } + if (ucMeasureInterval < 10 || ucMeasureInterval > 65535) { + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\n<MeasureInterval> range is 10 to 65535"); + return i4BytesWritten; + } + + rSwCtrlInfo.u4Data = (ucSwitchInterval | (ucMeasureInterval << 16)); + DBGLOG(REQ, LOUD, "SwitchIntv=%d, MeasureIntv=%d u4Data=0x%x,\n", + ucSwitchInterval, ucMeasureInterval, rSwCtrlInfo.u4Data); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} +#endif + +#if CFG_ENABLE_1RPD_MMPS_CTRL +static int priv_driver_set_1rpd(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 u4Ret = 0; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_SET_ID + CMD_ADVCTL_1RPD; + u32 u4Enable = false; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Id = u4Id; + + if (i4Argc <= 1) { + DBGLOG(REQ, ERROR, "Argc(%d) ERR: SET_1RPD <Sel>\n", i4Argc); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4Enable); + + if (u4Ret) { + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nCommand failed, invalid parameter"); + return i4BytesWritten; + } + + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "\nSet 1RPD %d", + u4Enable); + + rSwCtrlInfo.u4Data = u4Enable; + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} + +static int priv_driver_get_1rpd(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_1RPD; + u32 u4Sel = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = u4Id; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + u4Sel = rSwCtrlInfo.u4Data & 0xFF; + + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\n1RPD status: %d", u4Sel); + + return i4BytesWritten; +} +static int priv_driver_set_mmps(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 u4Ret = 0; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_SET_ID + CMD_ADVCTL_MMPS; + u32 u4Enable = false; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Id = u4Id; + + if (i4Argc <= 1) { + DBGLOG(REQ, ERROR, "Argc(%d) ERR: SET_NOISE <Sel>\n", i4Argc); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4Enable); + + if (u4Ret) { + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nCommand failed, invalid parameter"); + return i4BytesWritten; + } + + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, "\nSet MMPS %d", + u4Enable); + + rSwCtrlInfo.u4Data = u4Enable; + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} + +static int priv_driver_get_mmps(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_MMPS; + u32 u4Sel = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = u4Id; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + u4Sel = rSwCtrlInfo.u4Data & 0xFF; + + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nMMPS status: %d", u4Sel); + + return i4BytesWritten; +} +#endif +#if CFG_ENABLE_DEWEIGHTING_CTRL +static int priv_driver_set_deweighting_th(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 u4Ret = 0; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_SET_ID + CMD_ADVCTL_DEWEIGHTING_TH_ID; + u32 u4Sel = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Id = u4Id; + + if (i4Argc <= 1) { + DBGLOG(REQ, ERROR, "Argc(%d) ERR: SET_NOISE <Sel>\n", i4Argc); + return -1; + } + + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4Sel); + + if (u4Ret) { + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nCommand failed, threshold range is 0 to 15"); + return i4BytesWritten; + } + + if ((u4Sel < 0) || (u4Sel > 15)) { + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nCommand failed, threshold range is 0 to 15"); + return i4BytesWritten; + } + + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nSetting noise difference threshold %d", + u4Sel); + + rSwCtrlInfo.u4Data = u4Sel << 16; + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} + +static int priv_driver_get_deweighting_th(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_DEWEIGHTING_TH_ID; + u32 u4Sel = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = u4Id; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + u4Sel = (rSwCtrlInfo.u4Data >> 16) & 0xFF; + + i4BytesWritten += snprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nNoise difference threshold is %d", u4Sel); + + return i4BytesWritten; +} + +static int priv_driver_get_deweighting_noise(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = + CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_DEWEIGHTING_NOISE_ID; + s8 u2Wf0AvgNoise = 0, u2Wf1AvgNoise = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = u4Id; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + u2Wf1AvgNoise = rSwCtrlInfo.u4Data & 0xFF; + u2Wf0AvgNoise = (rSwCtrlInfo.u4Data >> 16) & 0xFF; + + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nDeweighting Average noise, WF0 = %d, WF1 = %d", + u2Wf0AvgNoise, u2Wf1AvgNoise); + + return i4BytesWritten; +} + +static int priv_driver_get_deweighting_weight(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = + CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_DEWEIGHTING_WEIGHT_ID; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + u8 ucWF0OfdmSetpt, ucWF0CckSetpt, ucWF1OfdmSetpt, ucWF1CckSetpt; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = u4Id; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + ucWF1CckSetpt = rSwCtrlInfo.u4Data & 0xFF; + ucWF1OfdmSetpt = (rSwCtrlInfo.u4Data >> 8) & 0xFF; + ucWF0CckSetpt = (rSwCtrlInfo.u4Data >> 16) & 0xFF; + ucWF0OfdmSetpt = (rSwCtrlInfo.u4Data >> 24) & 0xFF; + + i4BytesWritten += snprintf( + pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nDeweighting weight, WF0 ofdm=%02X cck=%02X, WF1 ofdm=%02X cck=%02X", + ucWF0OfdmSetpt, + ucWF0CckSetpt, + ucWF1OfdmSetpt, + ucWF1CckSetpt); + + return i4BytesWritten; +} +#endif +#if CFG_RX_SINGLE_CHAIN_SUPPORT +static int priv_driver_set_rxchain(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 u4Ret = 0; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_SET_ID + CMD_ADVCTL_RXC_ID; + u32 u4Sel = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + P_ADAPTER_T prAdapter = NULL; + u32 u4Offset = 0; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + rSwCtrlInfo.u4Id = u4Id; + + if (i4Argc <= 1) { + u4Offset += snprintf( + pcCommand + u4Offset, i4TotalLen - u4Offset, + "SET RX CHAIN: Fail!(%d) SET_RXC <Sel: 0/1/2>\n", + i4Argc); + goto out; + } + + /* not connected */ + /* if (prGlueInfo->eParamMediaStateIndicated != + * PARAM_MEDIA_STATE_CONNECTED) { + * u4Offset += snprintf(pcCommand + u4Offset, + * i4TotalLen - u4Offset, + * "SET RX CHAIN: Fail! not connected\n"); + * goto out; + * } + */ + + /* if (prAdapter->rWifiVar.ucNSS > 1 || + * prAdapter->rWifiVar.ucSpeIdxCtrl == 2) { + * u4Offset += snprintf(pcCommand + u4Offset, + * i4TotalLen - u4Offset, + * "SET RX CHAIN: Fail!NSS =%d & + * SpeIdxCtrl =%d wrong setting\n", + * prAdapter->rWifiVar.ucNSS, + * prAdapter->rWifiVar.ucSpeIdxCtrl); + * goto out; + * } + */ + + u4Ret = kalkStrtou32(apcArgv[1], 0, &u4Sel); + if (u4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error u4Ret=%d\n", u4Ret); + return -1; + } + if (u4Sel < 0 || u4Sel > 2) { + u4Offset += snprintf(pcCommand + u4Offset, + i4TotalLen - u4Offset, + "SET RX CHAIN:Fail!(%d) not equal 0/1/2\n", + u4Sel); + goto out; + } + /* else if (u4Sel != prAdapter->rWifiVar.ucSpeIdxCtrl) { + * u4Offset += snprintf(pcCommand + u4Offset, + * i4TotalLen - u4Offset, + * "SET RX CHAIN:Fail!(%d) + * not equal to SpeIdxCtrl(%d)\n", + * u4Sel, prAdapter->rWifiVar.ucSpeIdxCtrl); + * goto out; + * } + */ + + rSwCtrlInfo.u4Data = u4Sel; + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + u4Offset += + snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "SET RX CHAIN: kalIoctl fail (%d)\n", rStatus); + + goto out; + } else { + u4Offset += snprintf( + pcCommand + u4Offset, i4TotalLen - u4Offset, + "SET RX CHAIN: %d (0: WF0 1:WF1 2:WF0+WF1)Success\n", + u4Sel); + } +out: + i4BytesWritten = (s32)u4Offset; + + return i4BytesWritten; +} + +static int priv_driver_get_rxchain(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_RXC_ID; + u32 u4Offset = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + u8 ucRxChain; + P_ADAPTER_T prAdapter = NULL; + + ASSERT(prNetDev); + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + /*not connected*/ + /*if (prGlueInfo->eParamMediaStateIndicated != + * PARAM_MEDIA_STATE_CONNECTED) { + * u4Offset += snprintf(pcCommand + u4Offset, + * i4TotalLen - u4Offset, + * "GET RX CHAIN: Fail! not yet connected\n"); + * goto out; + * } + */ + + /*if (prAdapter->rWifiVar.ucNSS > 1 || + * prAdapter->rWifiVar.ucSpeIdxCtrl == 2) { + * u4Offset += snprintf(pcCommand + u4Offset, + * i4TotalLen - u4Offset, + * "GET RX CHAIN: Fail! NSS=%d (Need <2) + * SpeIdxCtrl=%d (Need <2) \n", + * prAdapter->rWifiVar.ucNSS, + * prAdapter->rWifiVar.ucSpeIdxCtrl); + * goto out; + * } + */ + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = u4Id; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + ucRxChain = (rSwCtrlInfo.u4Data) & 0xFF; + + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "GET RX CHAIN: %d (0: WF0 1:WF1 2:WF0+WF1)\n", + ucRxChain); + + /*out:*/ + i4BytesWritten = (s32)u4Offset; + + return i4BytesWritten; +} +#endif + +static int priv_driver_set_bcn_th(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 i4Ret = 0; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_SET_ID + CMD_ADVCTL_BCN_TH_ID; + u8 ucAdhoc, ucInfra, ucWithbt; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + rSwCtrlInfo.u4Id = u4Id; + + if (i4Argc != 4) { + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nformat:set_bcn_th <adhoc> <infra> <withbt>"); + return i4BytesWritten; + } + + i4Ret = kalkStrtou8(apcArgv[1], 0, &ucAdhoc); + if (i4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error i4Ret=%d\n", i4Ret); + } + i4Ret = kalkStrtou8(apcArgv[2], 0, &ucInfra); + if (i4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error i4Ret=%d\n", i4Ret); + } + i4Ret = kalkStrtou8(apcArgv[3], 0, &ucWithbt); + if (i4Ret) { + DBGLOG(REQ, ERROR, "parse rSwCtrlInfo error i4Ret=%d\n", i4Ret); + } + + rSwCtrlInfo.u4Data = (ucAdhoc | (ucInfra << 8) | (ucWithbt << 16)); + DBGLOG(REQ, LOUD, "u4Withbt=%d u4Infra=%d, u4Withbt=%d u4Data=0x%x,\n", + ucAdhoc, ucInfra, ucWithbt, rSwCtrlInfo.u4Data); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} + +static int priv_driver_get_bcn_th(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_BCN_TH_ID; + u8 ucAdhoc, ucInfra, ucWithbt; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc != 1) { + i4BytesWritten += scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nformat:get_bcn_th"); + return i4BytesWritten; + } + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = u4Id; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + ucAdhoc = rSwCtrlInfo.u4Data & 0xFF; + ucInfra = (rSwCtrlInfo.u4Data >> 8) & 0xFF; + ucWithbt = (rSwCtrlInfo.u4Data >> 16) & 0xFF; + + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, + "\nBeacon loss threshold: ADHOC:%d, INFRA:%d, With BT:%d\n", + ucAdhoc, ucInfra, ucWithbt); + + return i4BytesWritten; +} + +static int priv_driver_get_bcntimeout_num(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_BCNTIMOUT_NUM_ID; + u32 u4Offset = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + u32 u4BcnTimeoutNum = 0; + + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + if (!prGlueInfo->prAdapter->prAisBssInfo) { + return -EFAULT; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + rSwCtrlInfo.u4Id = u4Id; + DBGLOG(REQ, LOUD, "BssIndex=%d\n", rSwCtrlInfo.u4Data); + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + u4BcnTimeoutNum = rSwCtrlInfo.u4Data; + + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "Beacon Timeout Number: %d\n", u4BcnTimeoutNum); + + i4BytesWritten = (s32)u4Offset; + + return i4BytesWritten; +} + +static int priv_driver_set_every_tbtt(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_SET_ID + CMD_ADVCTL_EVERY_TBTT_ID; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + s32 i4Ret = 0; + u32 u4EveryTbtt[2] = { 0 }; + + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + if (prAdapter == NULL) { + DBGLOG(REQ, LOUD, "Adapter is NULL!\n"); + return -1; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc <= 2) { + DBGLOG(REQ, + ERROR, + "Argc(%d) ERR: SET_EVERY_TBTT <2G sel:0/1> <5G sel: 0/1>\n", + i4Argc); + return -1; + } + + i4Ret = kalkStrtou32(apcArgv[1], 0, &u4EveryTbtt[0]); + if (i4Ret) { + DBGLOG(REQ, ERROR, "parse error i4Ret=%d\n", i4Ret); + return -1; + } + + i4Ret = kalkStrtou32(apcArgv[2], 0, &u4EveryTbtt[1]); + if (i4Ret) { + DBGLOG(REQ, ERROR, "parse error i4Ret=%d\n", i4Ret); + return -1; + } + + if ((u4EveryTbtt[0] != 0 && u4EveryTbtt[0] != 1) || + (u4EveryTbtt[1] != 0 && u4EveryTbtt[1] != 1)) { + DBGLOG(REQ, + ERROR, + "ERR val=%d,%d: SET_EVERY_TBTT <2G sel:0/1> <5G sel: 0/1>\n", + u4EveryTbtt[0], + u4EveryTbtt[1]); + return -1; + } + + rSwCtrlInfo.u4Id = u4Id; + rSwCtrlInfo.u4Data = ((u4EveryTbtt[0] & 0xFF) << 16) | + (u4EveryTbtt[1] & 0xFF); + + rStatus = kalIoctl(prGlueInfo, wlanoidSetSwCtrlWrite, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), false, false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} + +static int priv_driver_get_every_tbtt(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + u32 u4Id = CMD_SW_DBGCTL_ADVCTL_GET_ID + CMD_ADVCTL_EVERY_TBTT_ID; + u32 u4Offset = 0; + PARAM_CUSTOM_SW_CTRL_STRUCT_T rSwCtrlInfo; + u8 bEveryTbtt[2] = { 0 }; + + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + rSwCtrlInfo.u4Data = 0; + rSwCtrlInfo.u4Id = u4Id; + + rStatus = kalIoctl(prGlueInfo, wlanoidQuerySwCtrlRead, &rSwCtrlInfo, + sizeof(rSwCtrlInfo), true, true, true, &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + bEveryTbtt[0] = (rSwCtrlInfo.u4Data >> 16) & 0xFF; + bEveryTbtt[1] = rSwCtrlInfo.u4Data & 0xFF; + + u4Offset += snprintf(pcCommand + u4Offset, i4TotalLen - u4Offset, + "Get every TBTT settings: 2G[%d], 5G[%d]\n", + bEveryTbtt[0], bEveryTbtt[1]); + + i4BytesWritten = (s32)u4Offset; + + return i4BytesWritten; +} +#endif + +static int priv_driver_set_csi(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + struct CMD_CSI_CONTROL_T *prCSICtrl = NULL; + u32 u4Ret = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + DBGLOG(RSN, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + DBGLOG(RSN, INFO, "priv_driver_csi_control\n"); + + prCSICtrl = (struct CMD_CSI_CONTROL_T *)kalMemAlloc( + sizeof(struct CMD_CSI_CONTROL_T), VIR_MEM_TYPE); + if (!prCSICtrl) { + DBGLOG(REQ, ERROR, "allocate memory for prCSICtrl failed\n"); + i4BytesWritten = -1; + goto out; + } + kalMemZero(prCSICtrl, sizeof(struct CMD_CSI_CONTROL_T)); + + if (i4Argc != 2 && i4Argc != 5) { + DBGLOG(REQ, ERROR, "argc %i is invalid\n", i4Argc); + i4BytesWritten = -1; + goto out; + } + + u4Ret = kalkStrtou8(apcArgv[1], 0, &(prCSICtrl->ucMode)); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucMode error u4Ret=%d\n", u4Ret); + goto out; + } + + if (prCSICtrl->ucMode > 1) { + DBGLOG(REQ, LOUD, "Invalid ucMode %d, should be 0 or 1\n", + prCSICtrl->ucMode); + } + + if (prCSICtrl->ucMode == CSI_CONTROL_MODE_STOP) { + goto send_cmd; + } + + prCSICtrl->ucBand = ENUM_BAND_0; + prCSICtrl->ucRole = RTT_ROLE_SENDING; + + u4Ret = kalkStrtou8(apcArgv[2], 0, &(prCSICtrl->ucWf)); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucWf error u4Ret=%d\n", u4Ret); + goto out; + } + + if (prCSICtrl->ucWf > 1) { + DBGLOG(REQ, LOUD, "Invalid ucWf %u, should be 0 or 1\n", + prCSICtrl->ucWf); + goto out; + } + + u4Ret = kalkStrtou8(apcArgv[3], 0, &(prCSICtrl->ucFrameTypeIndex)); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucFrameTypeIndex error u4Ret=%d\n", + u4Ret); + goto out; + } + + if (prCSICtrl->ucFrameTypeIndex > 3) { + DBGLOG(REQ, LOUD, + "Invalid ucFrameTypeIndex %u, should be 0 ~ 3\n", + prCSICtrl->ucFrameTypeIndex); + goto out; + } + + u4Ret = kalkStrtou8(apcArgv[4], 0, &(prCSICtrl->ucFrameType)); + if (u4Ret) { + DBGLOG(REQ, LOUD, "parse ucFrameType error u4Ret=%d\n", u4Ret); + goto out; + } + + if (prCSICtrl->ucFrameType != 0) { + DBGLOG(REQ, LOUD, + "Invalid ucFrameType %u, only support 0(beacon)\n", + prCSICtrl->ucFrameType); + goto out; + } + +send_cmd: + rStatus = kalIoctl(prGlueInfo, wlanoidSetCSIControl, prCSICtrl, + sizeof(struct CMD_CSI_CONTROL_T), true, true, true, + &u4BufLen); + + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, pcCommand); + DBGLOG(REQ, + INFO, + "mode %d, band %d, role %d, frame type idx %d, frame type idx %d", + prCSICtrl->ucMode, + prCSICtrl->ucBand, + prCSICtrl->ucRole, + prCSICtrl->ucFrameType, + prCSICtrl->ucFrameTypeIndex); + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "send CSI control cmd failed\n"); + i4BytesWritten = -1; + } + +out: + if (prCSICtrl) { + kalMemFree(prCSICtrl, VIR_MEM_TYPE, + sizeof(struct CMD_CSI_CONTROL_T)); + } + + return i4BytesWritten; +} + +static int priv_driver_get_csi(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4BytesWritten = 0; + P_ADAPTER_T prAdapter = NULL; + u8 ucBw = 20; + u16 i = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u8 ucDataType = 0; + s16 *pri2Data = NULL; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + prAdapter = prGlueInfo->prAdapter; + + if (prAdapter == NULL) { + DBGLOG(REQ, LOUD, "Adapter is NULL!\n"); + return -1; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc != 2 || kalkStrtou8(apcArgv[1], 0, &ucDataType) || + ucDataType > 1) { + LOGBUF(pcCommand, + i4TotalLen, + i4BytesWritten, + "0 or 1 should be given as the parameter to output I or Q data!\n"); + goto out; + } + + if (prAdapter->rCsiData.u2DataCount == 0) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "No CSI Data\n"); + goto out; + } + + if (prAdapter->rCsiData.ucBw == 0) { + ucBw = 20; + }else if (prAdapter->rCsiData.ucBw == 1) { + ucBw = 40; + }else if (prAdapter->rCsiData.ucBw == 2) { + ucBw = 80; + } + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "\nCSI Data:\n"); + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "BW: %d\n", ucBw); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "isCck: %d\n", + prAdapter->rCsiData.bIsCck); + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "data count: %d\n", + prAdapter->rCsiData.u2DataCount); + + if (ucDataType == 0) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "I data:\n"); + pri2Data = prAdapter->rCsiData.ac2IData; + prAdapter->rCsiData.ucDataOutputted |= BIT(0); + } else { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "Q data:\n"); + pri2Data = prAdapter->rCsiData.ac2QData; + prAdapter->rCsiData.ucDataOutputted |= BIT(1); + } + + for (i = 0; i < prAdapter->rCsiData.u2DataCount; i++) { + if ((i % 16) == 0) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "\n"); + } + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "%d ", + pri2Data[i]); + } + + if (prAdapter->rCsiData.ucDataOutputted == 0x3) { + prAdapter->rCsiData.u2DataCount = 0; + /* clean this indate I/Q data indicates that I & Q data are all + * outputted, we can start to receive the new IQ data + */ + prAdapter->rCsiData.ucDataOutputted = 0; + } + +out: + return i4BytesWritten; +} + +#ifdef CFG_SUPPORT_ANT_DIV +static int priv_driver_ant_diversity_config(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX]; + u32 u4Ret; + u8 fgRead = false; + u8 fgWaitResp = false; + struct CMD_ANT_DIV_CTRL rAntDivInfo; + + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -EFAULT; + } + + DBGLOG(REQ, INFO, "priv_driver_ant_diversity_config()\n"); + kalMemZero(&rAntDivInfo, sizeof(struct CMD_ANT_DIV_CTRL)); + + rAntDivInfo.ucAction = 0; + rAntDivInfo.ucAntId = 0; + rAntDivInfo.ucRcpi = 0; + rAntDivInfo.ucState = 0; + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (i4Argc == 0) { + DBGLOG(REQ, INFO, "ANT_DIV Argc = %d\n", i4Argc); + return -EFAULT; + } + if (strnicmp(apcArgv[0], CMD_GET_ANT_DIV, strlen(CMD_GET_ANT_DIV)) == + 0) { + if (i4Argc < CMD_GET_ANT_DIV_ARG_NUM) { + DBGLOG(REQ, INFO, + "GET_ANT_DIV arg num=%d, must be %d\n", i4Argc, + CMD_GET_ANT_DIV_ARG_NUM); + return -EFAULT; + } + rAntDivInfo.ucAction = ANT_DIV_CMD_GET_ANT; + fgRead = true; + fgWaitResp = true; + } else if (strnicmp(apcArgv[0], CMD_DETC_ANT_DIV, + strlen(CMD_DETC_ANT_DIV)) == 0) { + if (i4Argc < CMD_DETC_ANT_DIV_ARG_NUM) { + DBGLOG(REQ, INFO, + "DECT_ANT_DIV arg num=%d, must be %d\n", i4Argc, + CMD_DETC_ANT_DIV_ARG_NUM); + return -EFAULT; + } + + rAntDivInfo.ucAction = ANT_DIV_CMD_DETC; + fgRead = true; + fgWaitResp = true; + } else if (strnicmp(apcArgv[0], CMD_SWH_ANT_DIV, + strlen(CMD_SWH_ANT_DIV)) == 0) { + if (i4Argc < CMD_SWH_ANT_DIV_ARG_NUM) { + DBGLOG(REQ, INFO, + "SWH_ANT_DIV arg num=%d, must be %d\n", i4Argc, + CMD_SWH_ANT_DIV_ARG_NUM); + return -EFAULT; + } + + rAntDivInfo.ucAction = ANT_DIV_CMD_SWH; + fgRead = true; + fgWaitResp = true; + } else if (strnicmp(apcArgv[0], CMD_SET_ANT_DIV, + strlen(CMD_SET_ANT_DIV)) == 0) { + if (i4Argc < CMD_SET_ANT_DIV_ARG_NUM) { + DBGLOG(REQ, INFO, + "SET_ANT_DIV arg num=%d, must be %d\n", i4Argc, + CMD_SET_ANT_DIV_ARG_NUM); + return -EFAULT; + } + + rAntDivInfo.ucAction = ANT_DIV_CMD_SET_ANT; + fgRead = false; + fgWaitResp = false; + u4Ret = kalkStrtou8(apcArgv[1], 0, &(rAntDivInfo.ucAntId)); + if (u4Ret || ((rAntDivInfo.ucAntId != 1) && + (rAntDivInfo.ucAntId != 2))) { + DBGLOG(REQ, INFO, + "Parse ANT Index error Ret=%d, AntId =%d\n", + u4Ret, rAntDivInfo.ucAntId); + return -EFAULT; + } + } else { + DBGLOG(REQ, INFO, "ANT DIV subcmd(%s) error !\n", apcArgv[0]); + return -EFAULT; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidAntDivCfg, &rAntDivInfo, + sizeof(rAntDivInfo), fgRead, fgWaitResp, true, + &u4BufLen); + + DBGLOG(REQ, LOUD, "rStatus %u\n", rStatus); + if (rStatus != WLAN_STATUS_SUCCESS) { + return -1; + } + + if (fgWaitResp) { + DBGLOG(REQ, LOUD, + "[ANT-DIV] priv_driver_ant_diversity_config\n"); + DBGLOG(REQ, LOUD, "[ANT-DIV] action=%d\n", + rAntDivInfo.ucAction); + DBGLOG(REQ, LOUD, "[ANT-DIV] ucState=%d\n", + rAntDivInfo.ucState); + + switch (rAntDivInfo.ucAction) { + case ANT_DIV_CMD_GET_ANT: + i4BytesWritten = scnprintf(pcCommand, i4TotalLen, "%d", + rAntDivInfo.ucState); + break; + + case ANT_DIV_CMD_DETC: + if (rAntDivInfo.ucState == ANT_DIV_SUCCESS) { + /* rcpi to rssi */ + DBGLOG(REQ, LOUD, + "[ANT-DIV] ucRcpi=%d rssi=%d\n", + rAntDivInfo.ucRcpi, + RCPI_TO_dBm(rAntDivInfo.ucRcpi)); + i4BytesWritten = scnprintf( + pcCommand, i4TotalLen, "%d", + RCPI_TO_dBm(rAntDivInfo.ucRcpi)); + } else { + i4BytesWritten = scnprintf(pcCommand, + i4TotalLen, "%d", + rAntDivInfo.ucState); + } + break; + + case ANT_DIV_CMD_SWH: + i4BytesWritten = scnprintf(pcCommand, i4TotalLen, "%d", + rAntDivInfo.ucState); + break; + + default: + DBGLOG(REQ, ERROR, "[ANT-DIV][WARN] ucAction=%d\n", + rAntDivInfo.ucAction); + i4BytesWritten = + scnprintf(pcCommand, i4TotalLen, "fail"); + break; + } + + DBGLOG(REQ, INFO, "%s: command result is %s\n", __func__, + pcCommand); + } + + return i4BytesWritten; +} +#endif + +static int priv_driver_enforce_power_mode(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 i4Ret = 0; + u16 u2EnforcePowerMode; +#ifdef SUPPORT_ENFORCE_PWR_MODE + P_BSS_INFO_T prAisBssInfo; +#endif + PARAM_POWER_MODE_T rPowerMode; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + if ((i4Argc != 2) && (i4Argc != 3)) { + i4BytesWritten += scnprintf( + pcCommand + i4BytesWritten, i4TotalLen - i4BytesWritten, +#ifdef SUPPORT_PERIODIC_PS + "\nformat:enforce_power_mode [0|1|2|3|4] [band]" +#else + "\nformat:enforce_power_mode [0|1|2|3]" +#endif + ); + return i4BytesWritten; + } + + i4Ret = kalkStrtou16(apcArgv[1], 0, &u2EnforcePowerMode); + if (i4Ret) { + DBGLOG(REQ, ERROR, "parse enforce_power_mode error i4Ret=%d\n", + i4Ret); + } + +#ifdef SUPPORT_ENFORCE_PWR_MODE + if (u2EnforcePowerMode > Param_PowerModeMax) { + return -EINVAL; + } + +#endif + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (!prGlueInfo) { + return -EFAULT; + } + + if (!prGlueInfo->prAdapter->prAisBssInfo) { + return -EFAULT; + } + + rPowerMode.ucBssIdx = prGlueInfo->prAdapter->prAisBssInfo->ucBssIndex; + rPowerMode.ePowerMode = (PARAM_POWER_MODE)u2EnforcePowerMode; +#ifdef SUPPORT_ENFORCE_PWR_MODE + prAisBssInfo = prGlueInfo->prAdapter->prAisBssInfo; + + if (i4Argc == 3) { + u16 band; + i4Ret = kalkStrtou16(apcArgv[2], 0, &band); + if (i4Ret) { + DBGLOG(REQ, ERROR, "parse band error i4Ret=%d\n", + i4Ret); + return -EFAULT; + } + + if (band == BAND_2G4) { + DBGLOG(REQ, EVENT, "enforce power mode 2G %d\n", + u2EnforcePowerMode); + prGlueInfo->prAdapter->rWifiVar.ucEnforce2G = + u2EnforcePowerMode; + } else if (band == BAND_5G) { + DBGLOG(REQ, EVENT, "enforce power mode 5G %d\n", + u2EnforcePowerMode); + prGlueInfo->prAdapter->rWifiVar.ucEnforce5G = + u2EnforcePowerMode; + } else { + DBGLOG(REQ, ERROR, "wrong band\n"); + return -EINVAL; + } + + if (prAisBssInfo->eBand != band) { + DBGLOG(REQ, ERROR, + "mismatched band, saved but without apply\n"); + return 0; + } + } else { // for both 2.4G and 5G band + prGlueInfo->prAdapter->rWifiVar.ucEnforce2G = + u2EnforcePowerMode; + prGlueInfo->prAdapter->rWifiVar.ucEnforce5G = + u2EnforcePowerMode; + } +#else + prGlueInfo->prAdapter->rWifiVar.ucEnforcePSMode = rPowerMode.ePowerMode; +#endif + + // Restore Android's power mode setting if we do not enforce power mode. + if (rPowerMode.ePowerMode >= Param_PowerModeMax && + prGlueInfo->prAdapter->prAisBssInfo->ePowerModeFromUser < + Param_PowerModeMax) { + rPowerMode.ePowerMode = + prGlueInfo->prAdapter->prAisBssInfo->ePowerModeFromUser; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSet802dot11PowerSaveProfile, + &rPowerMode, sizeof(PARAM_POWER_MODE_T), false, + false, true, &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} + +static int priv_driver_get_power_mode(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; +#ifdef SUPPORT_ENFORCE_PWR_MODE + P_BSS_INFO_T prBssInfo = NULL; +#endif + + s32 i4BytesWritten = 0; + u16 u2EnforcePowerMode; + u16 ePowerModeFromUser; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (!prGlueInfo) { + return -EFAULT; + } + + prAdapter = prGlueInfo->prAdapter; + if (!prAdapter || !prAdapter->prAisBssInfo) { + return -EFAULT; + } + +#ifdef SUPPORT_ENFORCE_PWR_MODE + prBssInfo = prAdapter->prAisBssInfo; + ePowerModeFromUser = prBssInfo->ePowerModeFromUser; + if (prBssInfo->eBand == BAND_2G4) { + u2EnforcePowerMode = prAdapter->rWifiVar.ucEnforce2G; + } else if (prBssInfo->eBand == BAND_5G) { + u2EnforcePowerMode = prAdapter->rWifiVar.ucEnforce5G; + } else { + DBGLOG(REQ, ERROR, "prAisBssInfo->eBand unknonwn:%d\n", + prBssInfo->eBand); + return -EFAULT; + } +#else + u2EnforcePowerMode = prAdapter->rWifiVar.ucEnforcePSMode; + ePowerModeFromUser = prAdapter->prAisBssInfo->ePowerModeFromUser; +#endif + if (u2EnforcePowerMode < Param_PowerModeMax) { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n enforce power mode %d\n", u2EnforcePowerMode); + } else { + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + "\n enforce power mode: disabled\n"); + } + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, + " system power mode: %d\n", ePowerModeFromUser); + + return i4BytesWritten; +} + +static int priv_driver_send_beacon_timeout(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + + prAdapter = prGlueInfo->prAdapter; + if (!prAdapter || !prAdapter->prAisBssInfo) { + return -EFAULT; + } + + /* A testing reason code for disconnect reason get. */ + prAdapter->prAisBssInfo->u2DeauthReason = 100; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + if (prGlueInfo->eParamMediaStateIndicated == + PARAM_MEDIA_STATE_CONNECTED) { + kalIndicateStatusAndComplete( + prGlueInfo, WLAN_STATUS_BEACON_TIMEOUT, NULL, 0); + } + + return 0; +} + +static int priv_driver_get_disconnect_reason(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + s32 i4BytesWritten = 0, temp; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + + ASSERT(prNetDev); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (!prGlueInfo) { + return -EFAULT; + } + + prAdapter = prGlueInfo->prAdapter; + if (!prAdapter || !prAdapter->prAisBssInfo) { + return -EFAULT; + } + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + DBGLOG(REQ, LOUD, "argc is %i\n", i4Argc); + + temp = prAdapter->prAisBssInfo->u2DeauthReason + DISCONNECT_REASON_BASE; + memset(pcCommand, 0x00, i4TotalLen); + memcpy(pcCommand, &temp, sizeof(s32)); + i4BytesWritten += sizeof(s32); + DBGLOG(REQ, INFO, "i4BytesWritten=%d ucBcnTimeoutReason=0x%x\n", + i4BytesWritten, *(s32 *)pcCommand); + return i4BytesWritten; +} + +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT +static int priv_driver_bss_transition_query(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + u8 *pucQueryReason = NULL; + + if (strnicmp(pcCommand, "BSS-TRANSITION-QUERY", 20) == 0) { + if (strnicmp(pcCommand + 20, " reason=", 8) == 0) { + pucQueryReason = pcCommand + 28; + DBGLOG(REQ, INFO, + "BSS-TRANSITION-QUERY, pucQueryReason=%s\n", + pucQueryReason); + } else { + DBGLOG(REQ, + ERROR, + "Incorrect format, please specify reason code after reason=\n"); + return -EFAULT; + } + } else { + DBGLOG(REQ, ERROR, "BSS-TRANSITION-QUERY command format error"); + return -EFAULT; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (!prGlueInfo) { + return -EFAULT; + } + + if (!prGlueInfo->prAdapter->prAisBssInfo) { + return -EFAULT; + } + + rStatus = kalIoctl(prGlueInfo, wlanoidSendBTMQuery, pucQueryReason, + sizeof(pucQueryReason), false, false, true, + &u4BufLen); + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + + return i4BytesWritten; +} +#endif + +static int priv_driver_get_1xtx_status(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + P_ADAPTER_T prAdapter = NULL; + + s32 i4BytesWritten = 0; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (!prGlueInfo) { + return -EFAULT; + } + + prAdapter = prGlueInfo->prAdapter; + if (!prAdapter || !prAdapter->prAisBssInfo) { + return -EFAULT; + } + + LOGBUF(pcCommand, i4TotalLen, i4BytesWritten, "%d\n", + prAdapter->r1xTxDoneStatus); + + return i4BytesWritten; +} + +static int priv_driver_test_1xtx_status(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4BytesWritten = 0; + s32 i4Argc = 0; + s8 *apcArgv[WLAN_CFG_ARGV_MAX] = { 0 }; + s32 i4Ret = 0; + u8 ucTest1xTxStatus; + P_ADAPTER_T prAdapter = NULL; + + DBGLOG(REQ, LOUD, "command is %s\n", pcCommand); + wlanCfgParseArgument(pcCommand, &i4Argc, apcArgv); + + DBGLOG(REQ, ERROR, "i4Argc is %d\n", i4Argc); + if (i4Argc != 2) { + i4BytesWritten += scnprintf(pcCommand + i4BytesWritten, + i4TotalLen - i4BytesWritten, + "\nformat:test_1xtx_status [0|1]"); + return i4BytesWritten; + } + + i4Ret = kalkStrtou8(apcArgv[1], 0, &ucTest1xTxStatus); + if (i4Ret) { + DBGLOG(REQ, ERROR, "parse test_1xtx_status error i4Ret=%d\n", + i4Ret); + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (!prGlueInfo) { + return -EFAULT; + } + + prAdapter = prGlueInfo->prAdapter; + if (!prAdapter || !prAdapter->prAisBssInfo) { + return -EFAULT; + } + + prAdapter->fgIsTest1xTx = ucTest1xTxStatus; + DBGLOG(REQ, STATE, "set fgIsTest1xTx %d\n", prAdapter->fgIsTest1xTx); + + return i4BytesWritten; +} + +#if CFG_SUPPORT_802_11K + +static int priv_driver_neighbor_request(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + u32 u4BufLen = 0; + s32 i4BytesWritten = 0; + u8 *pucSSID = NULL; + + if (strnicmp(pcCommand, "NEIGHBOR-REQUEST", 16) == 0) { + if (strnicmp(pcCommand + 16, " SSID=", 6) == 0) { + pucSSID = pcCommand + 22; + DBGLOG(REQ, INFO, "NEIGHBOR-REQUEST, ssid=%s\n", + pucSSID); + } else { + DBGLOG(REQ, + ERROR, + "Incorrect format, please specify ssid after ssid=\n"); + return -EFAULT; + } + } else { + DBGLOG(REQ, ERROR, "NEIGHBOR-REQUEST command format error\n"); + return -EFAULT; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (!prGlueInfo) { + return -EFAULT; + } + + if (!prGlueInfo->prAdapter->prAisBssInfo) { + return -EFAULT; + } + + if (pucSSID == NULL) { + rStatus = kalIoctl(prGlueInfo, wlanoidSendNeighborRequest, NULL, + 0, false, false, true, &u4BufLen); + } else { + rStatus = kalIoctl(prGlueInfo, wlanoidSendNeighborRequest, + pucSSID, kalStrLen(pucSSID), false, false, + true, &u4BufLen); + } + + if (rStatus != WLAN_STATUS_SUCCESS) { + DBGLOG(REQ, ERROR, "ERR: kalIoctl fail (%d)\n", rStatus); + return -1; + } + return i4BytesWritten; +} +#endif + +s32 priv_driver_cmds(IN struct net_device *prNetDev, IN s8 *pcCommand, + IN s32 i4TotalLen) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + s32 i4BytesWritten = 0; + + if (GLUE_CHK_PR2(prNetDev, pcCommand) == false) { + return -1; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (strnicmp(pcCommand, CMD_RSSI, strlen(CMD_RSSI)) == 0) { + /* i4BytesWritten = + * wl_android_get_rssi(net, command, i4TotalLen); + */ + } else if (strnicmp(pcCommand, CMD_AP_START, strlen(CMD_AP_START)) == + 0) { + i4BytesWritten = priv_driver_set_ap_start(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == + 0) { + i4BytesWritten = priv_driver_get_linkspeed(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_PNOSSIDCLR_SET, + strlen(CMD_PNOSSIDCLR_SET)) == 0) { + /* ToDo:: Nothing */ + } else if (strnicmp(pcCommand, CMD_PNOSETUP_SET, + strlen(CMD_PNOSETUP_SET)) == 0) { + /* ToDo:: Nothing */ + } else if (strnicmp(pcCommand, CMD_RXFILTER_START, + strlen(CMD_RXFILTER_START)) == 0) { + /* ToDo:: Nothing */ + } else if (strnicmp(pcCommand, CMD_RXFILTER_STOP, + strlen(CMD_RXFILTER_STOP)) == 0) { + } else if (strnicmp(pcCommand, CMD_SET_AP_WPS_P2P_IE, + strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) { + /* ToDo:: Nothing */ + } else if (strnicmp(pcCommand, CMD_RXFILTER_ADD, + strlen(CMD_RXFILTER_ADD)) == 0) { + /* ToDo:: Nothing */ + } else if (strnicmp(pcCommand, CMD_PNOENABLE_SET, + strlen(CMD_PNOENABLE_SET)) == 0) { + /* ToDo:: Nothing */ + } else if (strnicmp(pcCommand, CMD_BTCOEXSCAN_STOP, + strlen(CMD_BTCOEXSCAN_STOP)) == 0) { + /* ToDo:: Nothing */ + } else if (strnicmp(pcCommand, CMD_SETSUSPENDOPT, + strlen(CMD_SETSUSPENDOPT)) == 0) { + /* i4BytesWritten = wl_android_set_suspendopt(net, pcCommand, + * i4TotalLen); */ + } else if (strnicmp(pcCommand, CMD_SETSUSPENDMODE, + strlen(CMD_SETSUSPENDMODE)) == 0) { + i4BytesWritten = priv_driver_set_suspend_mode( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { + i4BytesWritten = + priv_driver_set_band(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) { + /* i4BytesWritten = wl_android_get_band(net, pcCommand, + * i4TotalLen); */ + } else if (strnicmp(pcCommand, CMD_SET_TXPOWER, + strlen(CMD_SET_TXPOWER)) == 0) { + i4BytesWritten = priv_driver_set_txpower(prNetDev, pcCommand, + i4TotalLen); +#if CFG_SUPPORT_DBDC_TC6 + } else if (strnicmp(pcCommand, CMD_CSA, strlen(CMD_CSA)) == 0) { + i4BytesWritten = + priv_driver_set_csa(prNetDev, pcCommand, i4TotalLen); +#endif + } else if (strnicmp(pcCommand, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) { + i4BytesWritten = priv_driver_set_country(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_COUNTRY, + strlen(CMD_GET_COUNTRY)) == 0) { + i4BytesWritten = priv_driver_get_country(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_CHANNELS, + strlen(CMD_GET_CHANNELS)) == 0) { + i4BytesWritten = priv_driver_get_channels(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_AP_CHANNELS, + strlen(CMD_GET_AP_CHANNELS)) == 0) { + i4BytesWritten = priv_driver_get_ap_channels( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_MIRACAST, strlen(CMD_MIRACAST)) == + 0) { + i4BytesWritten = priv_driver_set_miracast(prNetDev, pcCommand, + i4TotalLen); + } + /* Mediatek private command */ + else if (strnicmp(pcCommand, CMD_SET_SW_CTRL, + strlen(CMD_SET_SW_CTRL)) == 0) { + i4BytesWritten = priv_driver_set_sw_ctrl(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_FIXED_RATE, + strlen(CMD_SET_FIXED_RATE)) == 0) { + i4BytesWritten = priv_driver_set_fixed_rate(prNetDev, pcCommand, + i4TotalLen); + } +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + else if (strnicmp(pcCommand, CMD_SET_FIXED_MRATE, + strlen(CMD_SET_FIXED_MRATE)) == 0) { + i4BytesWritten = priv_driver_set_fixed_mrate( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_DUP_MPACKET, + strlen(CMD_SET_DUP_MPACKET)) == 0) { + i4BytesWritten = priv_driver_set_dup_mpacket( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_DUP_MRACKET, + strlen(CMD_SET_DUP_MPACKET)) == 0) { + i4BytesWritten = priv_driver_get_dup_mpacket( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_MCAST_BURST, + strlen(CMD_SET_MCAST_BURST)) == 0) { + i4BytesWritten = priv_driver_set_mcast_burst( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_MCAST_BURST, + strlen(CMD_GET_MCAST_BURST)) == 0) { + i4BytesWritten = priv_driver_get_mcast_burst( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_TXOP_TIME, + strlen(CMD_SET_TXOP_TIME)) == 0) { + i4BytesWritten = + priv_driver_set_txop(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_TXOP_TIME, + strlen(CMD_GET_TXOP_TIME)) == 0) { + i4BytesWritten = + priv_driver_get_txop(prNetDev, pcCommand, i4TotalLen); +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK + } else if (strnicmp(pcCommand, CMD_SET_LOOK_BACK_MODE, + strlen(CMD_SET_LOOK_BACK_MODE)) == 0) { + i4BytesWritten = priv_driver_set_look_back(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_LOOK_BACK_MODE, + strlen(CMD_GET_LOOK_BACK_MODE)) == 0) { + i4BytesWritten = priv_driver_get_look_back(prNetDev, pcCommand, + i4TotalLen); +#endif + } else if (strnicmp(pcCommand, CMD_SET_11MC_TYPE, + strlen(CMD_SET_11MC_TYPE)) == 0) { + i4BytesWritten = priv_driver_set_11mc_type(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_11MC_TYPE, + strlen(CMD_SET_11MC_TYPE)) == 0) { + i4BytesWritten = priv_driver_get_11mc_type(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_UNICAST_BURST_TIMEOUT, + strlen(CMD_SET_UNICAST_BURST_TIMEOUT)) == 0) { + i4BytesWritten = priv_driver_set_unicast_burst_timeout( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_UNICAST_BURST_TIMEOUT, + strlen(CMD_GET_UNICAST_BURST_TIMEOUT)) == 0) { + i4BytesWritten = priv_driver_get_unicast_burst_timeout( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_UNICAST_BURST, + strlen(CMD_SET_UNICAST_BURST)) == 0) { + i4BytesWritten = priv_driver_set_unicast_burst( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_UNICAST_BURST, + strlen(CMD_GET_UNICAST_BURST)) == 0) { + i4BytesWritten = priv_driver_get_unicast_burst( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_MRM_CLIENT, + strlen(CMD_SET_MRM_CLIENT)) == 0) { + i4BytesWritten = priv_driver_set_mrm_clinet(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_MRM_CLIENT, + strlen(CMD_GET_MRM_CLIENT)) == 0) { + i4BytesWritten = priv_driver_get_mrm_client(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_AUDIO_TOS, + strlen(CMD_SET_AUDIO_TOS)) == 0) { + i4BytesWritten = priv_driver_set_audio_tos(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_AUDIO_TOS, + strlen(CMD_GET_AUDIO_TOS)) == 0) { + i4BytesWritten = priv_driver_get_audio_tos(prNetDev, pcCommand, + i4TotalLen); + } +#endif + else if (strnicmp(pcCommand, CMD_GET_SW_CTRL, + strlen(CMD_GET_SW_CTRL)) == 0) { + i4BytesWritten = priv_driver_get_sw_ctrl(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_MCR, strlen(CMD_SET_MCR)) == 0) { + i4BytesWritten = + priv_driver_set_mcr(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_MCR, strlen(CMD_GET_MCR)) == 0) { + i4BytesWritten = + priv_driver_get_mcr(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_DRV_MCR, + strlen(CMD_SET_DRV_MCR)) == 0) { + i4BytesWritten = priv_driver_set_drv_mcr(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_DRV_MCR, + strlen(CMD_GET_DRV_MCR)) == 0) { + i4BytesWritten = priv_driver_get_drv_mcr(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_TEST_MODE, + strlen(CMD_SET_TEST_MODE)) == 0) { + i4BytesWritten = priv_driver_set_test_mode(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_TEST_CMD, + strlen(CMD_SET_TEST_CMD)) == 0) { + i4BytesWritten = priv_driver_set_test_cmd(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_TEST_RESULT, + strlen(CMD_GET_TEST_RESULT)) == 0) { + i4BytesWritten = priv_driver_get_test_result( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_STA_STAT2, + strlen(CMD_GET_STA_STAT2)) == 0) { + i4BytesWritten = priv_driver_get_sta_stat2(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_STA_STAT, + strlen(CMD_GET_STA_STAT)) == 0) { + i4BytesWritten = priv_driver_get_sta_stat(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_CURR_AR_RATE, + strlen(CMD_GET_CURR_AR_RATE)) == 0) { + i4BytesWritten = priv_driver_get_sta_curr_ar_rate( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_STA_RX_STAT, + strlen(CMD_GET_STA_RX_STAT)) == 0) { + i4BytesWritten = priv_driver_show_rx_stat(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_ACL_POLICY, + strlen(CMD_SET_ACL_POLICY)) == 0) { + i4BytesWritten = priv_driver_set_acl_policy(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_ADD_ACL_ENTRY, + strlen(CMD_ADD_ACL_ENTRY)) == 0) { + i4BytesWritten = priv_driver_add_acl_entry(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_DEL_ACL_ENTRY, + strlen(CMD_DEL_ACL_ENTRY)) == 0) { + i4BytesWritten = priv_driver_del_acl_entry(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SHOW_ACL_ENTRY, + strlen(CMD_SHOW_ACL_ENTRY)) == 0) { + i4BytesWritten = priv_driver_show_acl_entry(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_CLEAR_ACL_ENTRY, + strlen(CMD_CLEAR_ACL_ENTRY)) == 0) { + i4BytesWritten = priv_driver_clear_acl_entry( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_COEX_CONTROL, + strlen(CMD_COEX_CONTROL)) == 0) { + i4BytesWritten = + priv_driver_coex_ctrl(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_CSI, strlen(CMD_SET_CSI)) == 0) { + i4BytesWritten = + priv_driver_set_csi(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_CSI, strlen(CMD_GET_CSI)) == 0) { + i4BytesWritten = + priv_driver_get_csi(prNetDev, pcCommand, i4TotalLen); + } +#if (CFG_SUPPORT_DFS_MASTER == 1) + else if (strnicmp(pcCommand, CMD_SHOW_DFS_STATE, + strlen(CMD_SHOW_DFS_STATE)) == 0) { + i4BytesWritten = priv_driver_show_dfs_state(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SHOW_DFS_abd123_PARAM, + strlen(CMD_SHOW_DFS_abd123_PARAM)) == 0) { + i4BytesWritten = priv_driver_show_dfs_abd123_param( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SHOW_DFS_HELP, + strlen(CMD_SHOW_DFS_HELP)) == 0) { + i4BytesWritten = priv_driver_show_dfs_help(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SHOW_DFS_CAC_TIME, + strlen(CMD_SHOW_DFS_CAC_TIME)) == 0) { + i4BytesWritten = priv_driver_show_dfs_cac_time( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_RDD_REPORT, + strlen(CMD_SET_RDD_REPORT)) == 0) { + i4BytesWritten = priv_driver_set_rdd_report(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_CLEAN_DFS_abd123_PARAM, + strlen(CMD_CLEAN_DFS_abd123_PARAM)) == 0) { + i4BytesWritten = priv_driver_clean_dfs_abd123_param( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_abd123_DETECT_MODE, + strlen(CMD_SET_abd123_DETECT_MODE)) == 0) { + i4BytesWritten = priv_driver_set_abd123_detect_mode( + prNetDev, pcCommand, i4TotalLen); + } +#endif + +#if CFG_WOW_SUPPORT + else if (strnicmp(pcCommand, CMD_WOW_START, strlen(CMD_WOW_START)) == + 0) { + i4BytesWritten = + priv_driver_set_wow(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_WOW_ENABLE, + strlen(CMD_SET_WOW_ENABLE)) == 0) { + i4BytesWritten = priv_driver_set_wow_enable(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_WOW_PAR, + strlen(CMD_SET_WOW_PAR)) == 0) { + i4BytesWritten = priv_driver_set_wow_par(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_WOW_UDP, + strlen(CMD_SET_WOW_UDP)) == 0) { + i4BytesWritten = priv_driver_set_wow_udpport( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_WOW_TCP, + strlen(CMD_SET_WOW_TCP)) == 0) { + i4BytesWritten = priv_driver_set_wow_tcpport( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_WOW_PORT, + strlen(CMD_GET_WOW_PORT)) == 0) { + i4BytesWritten = priv_driver_get_wow_port(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_WOW_REASON, + strlen(CMD_GET_WOW_REASON)) == 0) { + i4BytesWritten = priv_driver_get_wow_reason(prNetDev, pcCommand, + i4TotalLen); + } +#endif +#if CFG_STR_DHCP_RENEW_OFFLOAD + else if (strnicmp(pcCommand, CMD_SET_DHCP_INFO, + strlen(CMD_SET_DHCP_INFO)) == 0) { + i4BytesWritten = priv_driver_set_dhcp_info(prNetDev, pcCommand, + i4TotalLen); + } +#endif + else if (strnicmp(pcCommand, CMD_SET_ADV_PWS, + strlen(CMD_SET_ADV_PWS)) == 0) { + i4BytesWritten = priv_driver_set_adv_pws(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_MDTIM, strlen(CMD_SET_MDTIM)) == + 0) { + i4BytesWritten = + priv_driver_set_mdtim(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_LISTEN_DTIM_INTERVAL, + strlen(CMD_SET_LISTEN_DTIM_INTERVAL)) == 0) { + i4BytesWritten = priv_driver_set_listen_dtim_interval( + prNetDev, pcCommand, i4TotalLen); + } +#if CFG_SUPPORT_QA_TOOL + else if (strnicmp(pcCommand, CMD_GET_RX_STATISTICS, + strlen(CMD_GET_RX_STATISTICS)) == 0) { + i4BytesWritten = priv_driver_get_rx_statistics( + prNetDev, pcCommand, i4TotalLen); + } +#if CFG_SUPPORT_BUFFER_MODE + else if (strnicmp(pcCommand, CMD_SETBUFMODE, strlen(CMD_SETBUFMODE)) == + 0) { + i4BytesWritten = priv_driver_set_efuse_buffer_mode( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SETEEPROM_MODE, + strlen(CMD_SETEEPROM_MODE)) == 0) { + i4BytesWritten = priv_driver_set_eeprom_mode( + prNetDev, pcCommand, i4TotalLen); + } +#endif +#endif +#if CFG_SUPPORT_MSP + else if (strnicmp(pcCommand, CMD_GET_STA_STATISTICS, + strlen(CMD_GET_STA_STATISTICS)) == 0) { + i4BytesWritten = priv_driver_get_sta_statistics( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_BSS_STATISTICS, + strlen(CMD_GET_BSS_STATISTICS)) == 0) { + i4BytesWritten = priv_driver_get_bss_statistics( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_STA_INFO, + strlen(CMD_GET_STA_INFO)) == 0) { + i4BytesWritten = priv_driver_get_sta_info(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_WTBL_INFO, + strlen(CMD_GET_WTBL_INFO)) == 0) { + i4BytesWritten = priv_driver_get_wtbl_info(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_MIB_INFO, + strlen(CMD_GET_MIB_INFO)) == 0) { + i4BytesWritten = priv_driver_get_mib_info(prNetDev, pcCommand, + i4TotalLen); + } +#if CFG_SUPPORT_LAST_SEC_MCS_INFO + else if (strnicmp(pcCommand, CMD_GET_MCS_INFO, + strlen(CMD_GET_MCS_INFO)) == 0) { + i4BytesWritten = priv_driver_get_mcs_info(prNetDev, pcCommand, + i4TotalLen); + } +#endif + else if (strnicmp(pcCommand, CMD_SET_FW_LOG, strlen(CMD_SET_FW_LOG)) == + 0) { + i4BytesWritten = + priv_driver_set_fw_log(prNetDev, pcCommand, i4TotalLen); + } +#endif + else if (strnicmp(pcCommand, CMD_GET_MAGIC_PKT_INFO, + strlen(CMD_GET_MAGIC_PKT_INFO)) == 0) { + i4BytesWritten = priv_driver_get_magic_pkt_info( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_CFG, strlen(CMD_SET_CFG)) == 0) { + i4BytesWritten = + priv_driver_set_cfg(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_CFG, strlen(CMD_GET_CFG)) == 0) { + i4BytesWritten = + priv_driver_get_cfg(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_CHIP, strlen(CMD_SET_CHIP)) == + 0) { + i4BytesWritten = priv_driver_set_chip_config( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_CHIP, strlen(CMD_GET_CHIP)) == + 0) { + i4BytesWritten = priv_driver_get_chip_config( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_VERSION, + strlen(CMD_GET_VERSION)) == 0) { + i4BytesWritten = priv_driver_get_version(prNetDev, pcCommand, + i4TotalLen); +#if CFG_SUPPORT_DBDC + } else if (strnicmp(pcCommand, CMD_SET_DBDC, strlen(CMD_SET_DBDC)) == + 0) { + i4BytesWritten = + priv_driver_set_dbdc(prNetDev, pcCommand, i4TotalLen); +#endif +#if CFG_SUPPORT_BATCH_SCAN + } else if (strnicmp(pcCommand, CMD_BATCH_SET, strlen(CMD_BATCH_SET)) == + 0) { + kalIoctl(prGlueInfo, wlanoidSetBatchScanReq, (void *)pcCommand, + i4TotalLen, false, false, true, &i4BytesWritten); + } else if (strnicmp(pcCommand, CMD_BATCH_GET, strlen(CMD_BATCH_GET)) == + 0) { + /* strcpy(pcCommand, "BATCH SCAN DATA FROM FIRMWARE"); */ + /* i4BytesWritten = strlen("BATCH SCAN DATA FROM FIRMWARE") + 1; + */ + /* i4BytesWritten = priv_driver_get_linkspeed (prNetDev, + * pcCommand, i4TotalLen); */ + + u32 u4BufLen; + int i; + /* int rlen=0; */ + + for (i = 0; i < CFG_BATCH_MAX_MSCAN; i++) { + g_rEventBatchResult[i].ucScanCount = i + 1; /* for get + * which + * mscan */ + kalIoctl(prGlueInfo, wlanoidQueryBatchScanResult, + (void *)&g_rEventBatchResult[i], + sizeof(EVENT_BATCH_RESULT_T), true, true, true, + &u4BufLen); + } + + batchConvertResult(&g_rEventBatchResult[0], pcCommand, + i4TotalLen, &i4BytesWritten); + + /* Dump for debug */ + /* print_hex_dump(KERN_INFO, + * "BATCH", DUMP_PREFIX_ADDRESS, 16, 1, pcCommand, + * i4BytesWritten, true); + */ + } else if (strnicmp(pcCommand, CMD_BATCH_STOP, + strlen(CMD_BATCH_STOP)) == 0) { + kalIoctl(prGlueInfo, wlanoidSetBatchScanReq, (void *)pcCommand, + i4TotalLen, false, false, true, &i4BytesWritten); +#endif + } +#if CFG_SUPPORT_SNIFFER + else if (strnicmp(pcCommand, CMD_SETMONITOR, strlen(CMD_SETMONITOR)) == + 0) { + i4BytesWritten = priv_driver_set_monitor(prNetDev, pcCommand, + i4TotalLen); + } +#endif + else if (strnicmp(pcCommand, CMD_GET_QUE_INFO, + strlen(CMD_GET_QUE_INFO)) == 0) { + i4BytesWritten = priv_driver_get_que_info(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_MEM_INFO, + strlen(CMD_GET_MEM_INFO)) == 0) { + i4BytesWritten = priv_driver_get_mem_info(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_HIF_INFO, + strlen(CMD_GET_HIF_INFO)) == 0) { + i4BytesWritten = priv_driver_get_hif_info(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_P2P_PS, + strlen(CMD_SET_P2P_PS)) == 0) { + i4BytesWritten = + priv_driver_set_p2p_ps(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_CNM_INFO, + strlen(CMD_GET_CNM_INFO)) == 0) { + i4BytesWritten = priv_driver_get_cnm_info(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_DSLP_CNT, + strlen(CMD_GET_DSLP_CNT)) == 0) { + i4BytesWritten = priv_driver_get_deep_sleep_cnt( + prNetDev, pcCommand, i4TotalLen); + } +#if CFG_AUTO_CHANNEL_SEL_SUPPORT + else if (strnicmp(pcCommand, CMD_GET_CH_RANK_LIST, + strlen(CMD_GET_CH_RANK_LIST)) == 0) { + i4BytesWritten = priv_driver_get_ch_rank_list( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_CH_DIRTINESS, + strlen(CMD_GET_CH_DIRTINESS)) == 0) { + i4BytesWritten = priv_driver_get_ch_dirtiness( + prNetDev, pcCommand, i4TotalLen); + } +#endif + else if (strnicmp(pcCommand, CMD_EFUSE, sizeof(CMD_EFUSE) - 1) == 0) { + i4BytesWritten = + priv_driver_efuse_ops(prNetDev, pcCommand, i4TotalLen); + } +#if CFG_SUPPORT_ADVANCE_CONTROL + else if (strnicmp(pcCommand, CMD_SET_NOISE, strlen(CMD_SET_NOISE)) == + 0) { + i4BytesWritten = + priv_driver_set_noise(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_NOISE, strlen(CMD_GET_NOISE)) == + 0) { + i4BytesWritten = + priv_driver_get_noise(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_PTA_CONFIG, + strlen(CMD_PTA_CONFIG)) == 0) { + i4BytesWritten = + priv_driver_pta_config(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_TRAFFIC_REPORT, + strlen(CMD_TRAFFIC_REPORT)) == 0) { + i4BytesWritten = priv_driver_get_traffic_report( + prNetDev, pcCommand, i4TotalLen); + } +#ifdef CFG_SUPPORT_EXT_PTA_DEBUG_COMMAND + else if (strnicmp(pcCommand, CMD_EXT_PTA_CONFIG, + strlen(CMD_EXT_PTA_CONFIG)) == 0) { + i4BytesWritten = priv_driver_ext_pta_config(prNetDev, pcCommand, + i4TotalLen); + } +#endif +#ifdef CFG_SUPPORT_ADMINCTRL + else if (strnicmp(pcCommand, CMD_ADMINCTRL_CONFIG, + strlen(CMD_ADMINCTRL_CONFIG)) == 0) { + i4BytesWritten = priv_driver_admin_ctrl_config( + prNetDev, pcCommand, i4TotalLen); + } +#endif + else if (strnicmp(pcCommand, CMD_SET_POP, strlen(CMD_SET_POP)) == 0) { + i4BytesWritten = + priv_driver_set_pop(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_POP, strlen(CMD_GET_POP)) == 0) { + i4BytesWritten = + priv_driver_get_pop(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_ED, strlen(CMD_SET_ED)) == 0) { + i4BytesWritten = + priv_driver_set_ed(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_ED, strlen(CMD_GET_ED)) == 0) { + i4BytesWritten = + priv_driver_get_ed(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_PD, strlen(CMD_SET_PD)) == 0) { + i4BytesWritten = + priv_driver_set_pd(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_PD, strlen(CMD_GET_PD)) == 0) { + i4BytesWritten = + priv_driver_get_pd(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_MAX_RFGAIN, + strlen(CMD_SET_MAX_RFGAIN)) == 0) { + i4BytesWritten = priv_driver_set_maxrfgain(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_MAX_RFGAIN, + strlen(CMD_GET_MAX_RFGAIN)) == 0) { + i4BytesWritten = priv_driver_get_maxrfgain(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_NOISE_HISTOGRAM, + strlen(CMD_NOISE_HISTOGRAM)) == 0) { + i4BytesWritten = priv_driver_noise_histogram( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_ADM_CTRL, + strlen(CMD_SET_ADM_CTRL)) == 0) { + i4BytesWritten = priv_driver_set_adm_ctrl(prNetDev, pcCommand, + i4TotalLen); + } +#if CFG_RX_SINGLE_CHAIN_SUPPORT + else if (strnicmp(pcCommand, CMD_SET_RXC, strlen(CMD_SET_RXC)) == 0) { + i4BytesWritten = priv_driver_set_rxchain(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_RXC, strlen(CMD_GET_RXC)) == 0) { + i4BytesWritten = priv_driver_get_rxchain(prNetDev, pcCommand, + i4TotalLen); + } +#endif + else if (strnicmp(pcCommand, CMD_SET_BCN_TH, strlen(CMD_SET_BCN_TH)) == + 0) { + i4BytesWritten = + priv_driver_set_bcn_th(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_BCN_TH, + strlen(CMD_GET_BCN_TH)) == 0) { + i4BytesWritten = + priv_driver_get_bcn_th(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_BCNTIMEOUT_NUM, + strlen(CMD_GET_BCNTIMEOUT_NUM)) == 0) { + i4BytesWritten = priv_driver_get_bcntimeout_num( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_EVERY_TBTT, + strlen(CMD_SET_EVERY_TBTT)) == 0) { + i4BytesWritten = priv_driver_set_every_tbtt(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_EVERY_TBTT, + strlen(CMD_GET_EVERY_TBTT)) == 0) { + i4BytesWritten = priv_driver_get_every_tbtt(prNetDev, pcCommand, + i4TotalLen); + } +#endif +#if CFG_ENABLE_PS_INTV_CTRL + else if (strnicmp(pcCommand, CMD_SET_ACT_INTV, + strlen(CMD_SET_ACT_INTV)) == 0) { + i4BytesWritten = priv_driver_set_act_intv(prNetDev, pcCommand, + i4TotalLen); + } +#endif +#if CFG_ENABLE_1RPD_MMPS_CTRL + else if (strnicmp(pcCommand, CMD_SET_1RPD, strlen(CMD_SET_1RPD)) == 0) { + i4BytesWritten = + priv_driver_set_1rpd(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_1RPD, strlen(CMD_GET_1RPD)) == + 0) { + i4BytesWritten = + priv_driver_get_1rpd(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_MMPS, strlen(CMD_SET_MMPS)) == + 0) { + i4BytesWritten = + priv_driver_set_mmps(prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_MMPS, strlen(CMD_GET_MMPS)) == + 0) { + i4BytesWritten = + priv_driver_get_mmps(prNetDev, pcCommand, i4TotalLen); + } +#endif +#if CFG_ENABLE_DEWEIGHTING_CTRL + else if (strnicmp(pcCommand, CMD_SET_DEWEIGHTING_TH, + strlen(CMD_SET_DEWEIGHTING_TH)) == 0) { + i4BytesWritten = priv_driver_set_deweighting_th( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_DEWEIGHTING_TH, + strlen(CMD_GET_DEWEIGHTING_TH)) == 0) { + i4BytesWritten = priv_driver_get_deweighting_th( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_DEWEIGHTING_NOISE, + strlen(CMD_GET_DEWEIGHTING_NOISE)) == 0) { + i4BytesWritten = priv_driver_get_deweighting_noise( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_DEWEIGHTING_WEIGHT, + strlen(CMD_GET_DEWEIGHTING_WEIGHT)) == 0) { + i4BytesWritten = priv_driver_get_deweighting_weight( + prNetDev, pcCommand, i4TotalLen); + } +#endif + +#ifdef CFG_SUPPORT_ADJUST_MCC_STAY_TIME + else if (strnicmp(pcCommand, CMD_MCCTIME, strlen(CMD_MCCTIME)) == 0) { + i4BytesWritten = priv_driver_set_mcc_time(prNetDev, pcCommand, + i4TotalLen); + } +#endif +#ifdef CFG_SUPPORT_ANT_DIV + else if (strnicmp(pcCommand, CMD_GET_ANT_DIV, + strlen(CMD_GET_ANT_DIV)) == 0) { + i4BytesWritten = priv_driver_ant_diversity_config( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_DETC_ANT_DIV, + strlen(CMD_DETC_ANT_DIV)) == 0) { + i4BytesWritten = priv_driver_ant_diversity_config( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SWH_ANT_DIV, + strlen(CMD_SWH_ANT_DIV)) == 0) { + i4BytesWritten = priv_driver_ant_diversity_config( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SET_ANT_DIV, + strlen(CMD_SET_ANT_DIV)) == 0) { + i4BytesWritten = priv_driver_ant_diversity_config( + prNetDev, pcCommand, i4TotalLen); + } +#endif + else if (strnicmp(pcCommand, CMD_ENFORCE_POWER_MODE, + strlen(CMD_ENFORCE_POWER_MODE)) == 0) { + i4BytesWritten = priv_driver_enforce_power_mode( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_POWER_MODE, + strlen(CMD_GET_POWER_MODE)) == 0) { + i4BytesWritten = priv_driver_get_power_mode(prNetDev, pcCommand, + i4TotalLen); + } else if (strnicmp(pcCommand, CMD_SEND_BEACONTIMEOUT, + strlen(CMD_SEND_BEACONTIMEOUT)) == 0) { + i4BytesWritten = priv_driver_send_beacon_timeout( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_DISCONNECT_REASON, + strlen(CMD_GET_DISCONNECT_REASON)) == 0) { + i4BytesWritten = priv_driver_get_disconnect_reason( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_GET_1XTX_STATUS, + strlen(CMD_GET_1XTX_STATUS)) == 0) { + i4BytesWritten = priv_driver_get_1xtx_status( + prNetDev, pcCommand, i4TotalLen); + } else if (strnicmp(pcCommand, CMD_TEST_1XTX_STATUS, + strlen(CMD_TEST_1XTX_STATUS)) == 0) { + i4BytesWritten = priv_driver_test_1xtx_status( + prNetDev, pcCommand, i4TotalLen); + } +#if CFG_SUPPORT_802_11K + else if (strnicmp(pcCommand, CMD_NEIGHBOR_REQUEST, + strlen(CMD_NEIGHBOR_REQUEST)) == 0) { + i4BytesWritten = priv_driver_neighbor_request( + prNetDev, pcCommand, i4TotalLen); + } +#endif +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT + else if (strnicmp(pcCommand, CMD_BSS_TRANSITION_QUERY, + strlen(CMD_BSS_TRANSITION_QUERY)) == 0) { + i4BytesWritten = priv_driver_bss_transition_query( + prNetDev, pcCommand, i4TotalLen); + } else if (kalStrStr(pcCommand, "-IT ")) { + i4BytesWritten = kalIoctl(prGlueInfo, wlanoidPktProcessIT, + (void *)pcCommand, i4TotalLen, false, + false, false, &i4BytesWritten); + } +#endif + else { + i4BytesWritten = + priv_cmd_not_support(prNetDev, pcCommand, i4TotalLen); + } + + if (i4BytesWritten >= 0) { + if ((i4BytesWritten == 0) && (i4TotalLen > 0)) { + /* reset the command buffer */ + pcCommand[0] = '\0'; + } + + if (i4BytesWritten >= i4TotalLen) { + DBGLOG(REQ, INFO, + "%s: i4BytesWritten %d > i4TotalLen < %d\n", + __func__, i4BytesWritten, i4TotalLen); + i4BytesWritten = i4TotalLen; + } else { + pcCommand[i4BytesWritten] = '\0'; + i4BytesWritten++; + } + } + + return i4BytesWritten; +} + +int priv_support_driver_cmd(IN struct net_device *prNetDev, + IN OUT struct ifreq *prReq, IN int i4Cmd) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + int ret = 0; + char *pcCommand = NULL; + priv_driver_cmd_t *priv_cmd = NULL; + int i4BytesWritten = 0; + int i4TotalLen = 0; + struct iwreq *wrqin = (struct iwreq *)prReq; + + if (!prReq->ifr_data) { + ret = -EINVAL; + goto exit; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prNetDev)); + if (!prGlueInfo) { + DBGLOG(REQ, WARN, "No glue info\n"); + ret = -EFAULT; + goto exit; + } + if (prGlueInfo->u4ReadyFlag == 0) { + ret = -EINVAL; + goto exit; + } + + priv_cmd = kzalloc(sizeof(priv_driver_cmd_t), GFP_KERNEL); + if (!priv_cmd) { + DBGLOG(REQ, WARN, "%s, alloc mem failed\n", __func__); + return -ENOMEM; + } + + if (copy_from_user(priv_cmd->buf, prReq->ifr_data, PRIV_CMD_SIZE)) { + DBGLOG(REQ, INFO, "%s: copy_from_user fail\n", __func__); + ret = -EFAULT; + goto exit; + } + + priv_cmd->total_len = wrqin->u.data.length; + + i4TotalLen = priv_cmd->total_len; + + if (i4TotalLen <= 0) { + ret = -EINVAL; + DBGLOG(REQ, INFO, "%s: i4TotalLen invalid %x %x %s\n", __func__, + i4TotalLen, priv_cmd->used_len, priv_cmd->buf); + goto exit; + } + priv_cmd->buf[PRIV_CMD_SIZE - 1] = '\0'; + pcCommand = priv_cmd->buf; + + DBGLOG(REQ, INFO, "%s: driver cmd \"%s\" on %s\n", __func__, pcCommand, + prReq->ifr_name); + + i4BytesWritten = priv_driver_cmds(prNetDev, pcCommand, PRIV_CMD_SIZE); + + if (i4BytesWritten < 0) { + DBGLOG(REQ, INFO, "%s: command %s Written is %d\n", __func__, + pcCommand, i4BytesWritten); + if (i4TotalLen >= 3) { + snprintf(pcCommand, 3, "OK"); + i4BytesWritten = strlen("OK"); + } + } + + if (copy_to_user(prReq->ifr_data, priv_cmd->buf, PRIV_CMD_SIZE)) { + DBGLOG(REQ, INFO, "%s: copy_to_user fail\n", __func__); + ret = -EFAULT; + goto exit; + } + + if (i4BytesWritten > 0) { + if (i4BytesWritten > PRIV_CMD_SIZE) { + i4BytesWritten = PRIV_CMD_SIZE; + } + wrqin->u.data.length = i4BytesWritten; /* the iwpriv will use + * the length */ + } else if (i4BytesWritten == 0) { + wrqin->u.data.length = i4BytesWritten; + } + +exit: + kfree(priv_cmd); + + return ret; +} + +#ifdef CFG_ANDROID_AOSP_PRIV_CMD +int android_private_support_driver_cmd(IN struct net_device *prNetDev, + IN OUT struct ifreq *prReq, + IN int i4Cmd) +{ + struct android_wifi_priv_cmd priv_cmd; + char *command = NULL; + int ret = 0, bytes_written = 0; + + if (!prReq->ifr_data) { + return -EINVAL; + } + + if (copy_from_user(&priv_cmd, prReq->ifr_data, sizeof(priv_cmd))) { + return -EFAULT; + } + + if (priv_cmd.total_len <= 0 || priv_cmd.total_len > PRIV_CMD_SIZE) { + return -EINVAL; + } + + command = kzalloc(priv_cmd.total_len, GFP_KERNEL); + if (!command) { + DBGLOG(REQ, WARN, "%s, alloc mem failed\n", __func__); + return -ENOMEM; + } + + if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) { + ret = -EFAULT; + goto FREE; + } + + bytes_written = priv_driver_cmds(prNetDev, command, priv_cmd.total_len); + + if (bytes_written >= 0) { + /* priv_cmd in but no response */ + if ((bytes_written == 0) && (priv_cmd.total_len > 0)) { + command[0] = '\0'; + } + + if (bytes_written >= priv_cmd.total_len) { + bytes_written = priv_cmd.total_len; + }else{ + bytes_written++; + } + + priv_cmd.used_len = bytes_written; + + if (copy_to_user(priv_cmd.buf, command, bytes_written)) { + ret = -EFAULT; + } + } else { + ret = bytes_written; + } + +FREE: + kfree(command); + + return ret; +} +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/hal_api.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/hal_api.c new file mode 100644 index 00000000000000..f88088f4da018a --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/hal_api.c @@ -0,0 +1,2452 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ +/****************************************************************************** +*[File] hif_api.c +*[Version] v1.0 +*[Revision Date] 2015-09-08 +*[Author] +*[Description] +* The program provides SDIO HIF APIs +*[Copyright] +* Copyright (C) 2015 MediaTek Incorporation. All Rights Reserved. +******************************************************************************/ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "precomp.h" + +#include <linux/mmc/card.h> +#include <linux/mmc/host.h> +#include <linux/mmc/sdio.h> +#include <linux/mmc/sdio_func.h> /* sdio_readl(), etc */ +#include <linux/mmc/sdio_ids.h> + +#include <linux/mm.h> +#ifndef CONFIG_X86 +#include <asm/memory.h> +#endif + +#include "reg.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define RX_RESPONSE_TIMEOUT (15000) + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Verify the CHIP ID + * + * @param prAdapter a pointer to adapter private data structure. + * + * + * @retval true CHIP ID is the same as the setting compiled + * @retval false CHIP ID is different from the setting compiled + */ +/*----------------------------------------------------------------------------*/ +u8 halVerifyChipID(IN P_ADAPTER_T prAdapter) +{ + u32 u4CIR = 0; + struct chip_info *prChipInfo; + + ASSERT(prAdapter); + + if (prAdapter->fgIsReadRevID) { + return true; + } + + HAL_MCR_RD(prAdapter, MCR_WCIR, &u4CIR); + + DBGLOG(INIT, TRACE, "Chip ID: 0x%lx\n", u4CIR & WCIR_CHIP_ID); + DBGLOG(INIT, TRACE, "Revision ID: 0x%lx\n", + ((u4CIR & WCIR_REVISION_ID) >> 16)); + + prChipInfo = prAdapter->chip_info; + + if ((u4CIR & WCIR_CHIP_ID) != prChipInfo->chip_id) { + return false; + } + + prAdapter->ucRevID = (u8)(((u4CIR & WCIR_REVISION_ID) >> 16) & 0xF); + prAdapter->fgIsReadRevID = true; + + return true; +} + +WLAN_STATUS +halRxWaitResponse(IN P_ADAPTER_T prAdapter, IN u8 ucPortIdx, + OUT u8 *pucRspBuffer, IN u32 u4MaxRespBufferLen, + OUT u32 *pu4Length) +{ + u32 u4Value = 0, u4PktLen = 0, i = 0, u4CpyLen; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + u32 u4Time, u4Current; + P_RX_CTRL_T prRxCtrl; + + DEBUGFUNC("halRxWaitResponse"); + + ASSERT(prAdapter); + ASSERT(pucRspBuffer); + + prRxCtrl = &prAdapter->rRxCtrl; + + u4Time = (u32)kalGetTimeTick(); + + do { + HAL_MCR_RD(prAdapter, MCR_WHISR, &u4Value); + if (!(u4Value & (WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT))) { + /* timeout exceeding check */ + u4Current = (u32)kalGetTimeTick(); + + if ((u4Current > u4Time) && + ((u4Current - u4Time) > RX_RESPONSE_TIMEOUT)) { + DBGLOG(RX, ERROR, "Timeout! %d - %d = %d\n", + u4Current, u4Time, (u4Current - u4Time)); + return WLAN_STATUS_FAILURE; + } else if (u4Current < u4Time && + ((u4Current + (0xFFFFFFFF - u4Time)) > + RX_RESPONSE_TIMEOUT)) { + DBGLOG(RX, ERROR, "Timeout! %d - %d = %d\n", + u4Current, u4Time, + (u4Current + (0xFFFFFFFF - u4Time))); + return WLAN_STATUS_FAILURE; + } + /* Response packet is not ready */ + kalUdelay(50); + + continue; + } + + /* Read the packet length */ + HAL_MCR_RD(prAdapter, MCR_WRPLR, &u4Value); + + if ((u4Value & 0xFFFF) != 0) { + u4PktLen = u4Value & 0xFFFF; + i = 0; + } else { + u4PktLen = (u4Value >> 16) & 0xFFFF; + i = 1; + } + + if (u4PktLen == 0) { + DBGLOG(RX, ERROR, "Packet length is 0!!\n"); + return WLAN_STATUS_FAILURE; + } else { +#if (CFG_ENABLE_READ_EXTRA_4_BYTES == 1) +#if CFG_SDIO_RX_AGG + /* decide copy length */ + if (u4PktLen > u4MaxRespBufferLen) { + u4CpyLen = u4MaxRespBufferLen; + DBGLOG(RX, ERROR, + "Packet length is larger than buffer size!!\n"); + } else { + u4CpyLen = u4PktLen; + } + + /* read from SDIO to tmp. buffer */ + HAL_PORT_RD(prAdapter, i == 0 ? MCR_WRDR0 : MCR_WRDR1, + ALIGN_4(u4PktLen + 4), + prRxCtrl->pucRxCoalescingBufPtr, + HIF_RX_COALESCING_BUFFER_SIZE); + + /* copy to destination buffer */ + kalMemCopy(pucRspBuffer, + prRxCtrl->pucRxCoalescingBufPtr, u4CpyLen); + + /* update valid buffer count */ + u4PktLen = u4CpyLen; +#else +#error "Please turn on RX coalescing" +#endif +#else + HAL_PORT_RD(prAdapter, i == 0 ? MCR_WRDR0 : MCR_WRDR1, + u4PktLen, pucRspBuffer, u4MaxRespBufferLen); +#endif + *pu4Length = u4PktLen; + break; + } + } while (true); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief enable global interrupt + * + * @param prAdapter pointer to the Adapter handler + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void halEnableInterrupt(IN P_ADAPTER_T prAdapter) +{ + u8 fgIsIntEnableCache, fgIsPendingInt; + + ASSERT(prAdapter); + fgIsIntEnableCache = prAdapter->fgIsIntEnable; + /* Not to enable interrupt if there is pending interrupt */ + fgIsPendingInt = prAdapter->prGlueInfo->rHifInfo.fgIsPendingInt; + + if (!fgIsPendingInt) { + prAdapter->fgIsIntEnable = true; /* NOTE(Kevin): It must be + * placed before MCR GINT + * write. */ + } + /* If need enable INT and also set LPOwn at the same time. */ + if (prAdapter->fgIsIntEnableWithLPOwnSet) { + prAdapter->fgIsIntEnableWithLPOwnSet = false; /* NOTE(Kevin): + * It's better to + * place it before + * MCR GINT write. + */ + /* If INT was enabled, only set LPOwn */ + if (fgIsIntEnableCache) { + HAL_MCR_WR(prAdapter, MCR_WHLPCR, + WHLPCR_FW_OWN_REQ_SET); + prAdapter->fgIsFwOwn = true; + } + /* If INT was not enabled, enable it and also set LPOwn now */ + else if (!fgIsPendingInt) { + HAL_MCR_WR(prAdapter, MCR_WHLPCR, + WHLPCR_FW_OWN_REQ_SET | WHLPCR_INT_EN_SET); + prAdapter->fgIsFwOwn = true; + } + } + /* If INT was not enabled, enable it now */ + else if (!fgIsIntEnableCache && !fgIsPendingInt) { + HAL_BYTE_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_SET); + } + + if (fgIsPendingInt) { + kalSetIntEvent(prAdapter->prGlueInfo); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief disable global interrupt + * + * @param prAdapter pointer to the Adapter handler + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void halDisableInterrupt(IN P_ADAPTER_T prAdapter) +{ + ASSERT(prAdapter); + + HAL_BYTE_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_CLR); + + prAdapter->fgIsIntEnable = false; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to process the POWER OFF procedure. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +u8 halSetDriverOwn(IN P_ADAPTER_T prAdapter) +{ + u8 fgStatus = true; + u32 i, u4CurrTick = 0; + u8 fgTimeout; + u8 fgResult; + u8 fgReady = false; + + ASSERT(prAdapter); + + GLUE_INC_REF_CNT(prAdapter->u4PwrCtrlBlockCnt); + + if (prAdapter->fgIsFwOwn == false) { + return fgStatus; + } + + DBGLOG(INIT, INFO, "DRIVER OWN\n"); + + u4CurrTick = kalGetTimeTick(); + i = 0; + + glWakeupSdio(prAdapter->prGlueInfo); + + while (1) { + HAL_LP_OWN_RD(prAdapter, &fgResult); + + if (TIME_BEFORE(kalGetTimeTick(), u4CurrTick)) { /* To prevent + * timer + * wraparound + */ + fgTimeout = ((kalGetTimeTick() + (~u4CurrTick)) > + LP_OWN_BACK_TOTAL_DELAY_MS) ? + true : + false; + } else { + fgTimeout = ((kalGetTimeTick() - u4CurrTick) > + LP_OWN_BACK_TOTAL_DELAY_MS) ? + true : + false; + } + + if (fgResult) { + prAdapter->fgIsFwOwn = false; + prAdapter->u4OwnFailedCount = 0; + prAdapter->u4OwnFailedLogCount = 0; + + if (nicSerIsWaitingReset(prAdapter)) { + /* SER is done, start Tx/Rx */ + nicSerStartTxRx(prAdapter); + } + break; + } else if ((i > LP_OWN_BACK_FAILED_RETRY_CNT) && + (kalIsCardRemoved(prAdapter->prGlueInfo) || + fgIsBusAccessFailed || fgTimeout || + wlanIsChipNoAck(prAdapter))) { +#if CFG_SUPPORT_LOW_POWER_DEBUG + /* For driver own back fail debug, get current PC value + */ + halPrintMailbox(prAdapter); + halPollDbgCr(prAdapter, + LP_OWN_BACK_FAILED_DBGCR_POLL_ROUND); +#endif + if ((prAdapter->u4OwnFailedCount == 0) || + CHECK_FOR_TIMEOUT( + u4CurrTick, + prAdapter->rLastOwnFailedLogTime, + MSEC_TO_SYSTIME( + LP_OWN_BACK_FAILED_LOG_SKIP_MS))) { + DBGLOG(INIT, + ERROR, + "LP cannot be own back, Timeout[%u](%ums), BusAccessError[%u]", + fgTimeout, + kalGetTimeTick() - u4CurrTick, + fgIsBusAccessFailed); + + DBGLOG(INIT, + INFO, + "Skip LP own back failed log for next %ums\n", + LP_OWN_BACK_FAILED_LOG_SKIP_MS); + + prAdapter->u4OwnFailedLogCount++; + if (prAdapter->u4OwnFailedLogCount > + LP_OWN_BACK_FAILED_RESET_CNT) { + /* Trigger RESET */ + } + GET_CURRENT_SYSTIME( + &prAdapter->rLastOwnFailedLogTime); + } + + prAdapter->u4OwnFailedCount++; + fgStatus = false; + break; + } + + if (i == 0) { + /* Software get LP ownership - only one time. + * Suppose one CLR_LP_OWN will trigger firmware to + * return the hif_own. If not, there is something wrong + * in chipset. + */ + HAL_LP_OWN_CLR(prAdapter, &fgResult); + } + + /* Delay for LP engine to complete its operation. */ + kalMsleep(LP_OWN_BACK_LOOP_DELAY_MS); + i++; + } + + /* For Low power Test */ + /* 1. Driver need to polling until CR4 ready, then could do normal Tx/Rx + */ + /* 2. Send a dummy command to change data path to store-forward mode */ + + if (prAdapter->fgIsFwDownloaded) { + u4CurrTick = kalGetTimeTick(); + while (1) { + HAL_WIFI_FUNC_READY_CHECK( + prAdapter, WIFI_FUNC_READY_BITS, &fgReady); + + if (TIME_BEFORE(kalGetTimeTick(), u4CurrTick)) { /* To + * prevent + * timer + * wraparound + */ + fgTimeout = + ((kalGetTimeTick() + (~u4CurrTick)) > + LP_OWN_BACK_TOTAL_DELAY_MS) ? + true : + false; + } else { + fgTimeout = ((kalGetTimeTick() - u4CurrTick) > + LP_OWN_BACK_TOTAL_DELAY_MS) ? + true : + false; + } + + if (fgReady) { + break; + } else if (kalIsCardRemoved(prAdapter->prGlueInfo) || + fgIsBusAccessFailed || fgTimeout || + wlanIsChipNoAck(prAdapter)) { +#if CFG_SUPPORT_LOW_POWER_DEBUG + /* For driver own back fail debug, get current + * PC value */ + halPrintMailbox(prAdapter); + halPollDbgCr( + prAdapter, + LP_OWN_BACK_FAILED_DBGCR_POLL_ROUND); +#endif + + DBGLOG(INIT, INFO, + "Skip waiting CR4 ready for next %ums\n", + LP_OWN_BACK_FAILED_LOG_SKIP_MS); + fgStatus = false; + + if (fgTimeout) { + /* Trigger RESET */ + } + + break; + } + /* Delay for CR4 to complete its operation. */ + kalMsleep(LP_OWN_BACK_LOOP_DELAY_MS); + } + + HAL_MCR_RD(prAdapter, MCR_D2HRM1R, &i); + if (i == 0x77889901) { + /* fgIsWakeupFromDeepSleep */ + wlanSendDummyCmd(prAdapter, false); + + /* Workaround for dummy command which is not count in Tx + * done count */ + prAdapter->prGlueInfo->rHifInfo + .au4PendingTxDoneCount[TC4_INDEX]--; + } + } + + return fgStatus; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This routine is used to process the POWER ON procedure. + * + * \param[in] pvAdapter Pointer to the Adapter structure. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void halSetFWOwn(IN P_ADAPTER_T prAdapter, IN u8 fgEnableGlobalInt) +{ + u8 fgResult; + + ASSERT(prAdapter); + + ASSERT(prAdapter->u4PwrCtrlBlockCnt != 0); + /* Decrease Block to Enter Low Power Semaphore count */ + GLUE_DEC_REF_CNT(prAdapter->u4PwrCtrlBlockCnt); + + if (prAdapter->u4PwrCtrlBlockCnt != 0) { + return; + } + + if (prAdapter->fgForceFwOwn == false) { + if (prAdapter->fgWiFiInSleepyState == false) { + return; + } + } + + if (prAdapter->fgIsFwOwn == true) { + return; + } + + if ((nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) && + !nicSerIsWaitingReset(prAdapter)) { + DBGLOG(INIT, INFO, "FW OWN Skipped due to pending INT\n"); + /* pending interrupts */ + return; + } + + if (fgEnableGlobalInt) { + prAdapter->fgIsIntEnableWithLPOwnSet = true; + } else { + HAL_LP_OWN_SET(prAdapter, &fgResult); + + if (fgResult) { + /* if set firmware own not successful (possibly pending + * interrupts), */ + /* indicate an own clear event */ + HAL_LP_OWN_CLR(prAdapter, &fgResult); + + return; + } + + prAdapter->fgIsFwOwn = true; + + DBGLOG(INIT, INFO, "FW OWN\n"); + } +} + +void halWakeUpWiFi(IN P_ADAPTER_T prAdapter) +{ + u8 fgResult; + + ASSERT(prAdapter); + + HAL_LP_OWN_RD(prAdapter, &fgResult); + + if (fgResult) { + prAdapter->fgIsFwOwn = false; + }else{ + HAL_LP_OWN_CLR(prAdapter, &fgResult); + } + +#if CFG_SUPPORT_LOW_POWER_DEBUG + /* Polling MCU programming counter */ + halPollDbgCr(prAdapter, LP_DBGCR_POLL_ROUND); +#endif +} + +void halDevInit(IN P_ADAPTER_T prAdapter) +{ + u32 u4Value = 0; + + ASSERT(prAdapter); + +#if CFG_SDIO_INTR_ENHANCE + /* 4 <1> Check STATUS Buffer is DW alignment. */ + ASSERT(IS_ALIGN_4((unsigned long)&prAdapter->prGlueInfo->rHifInfo + .prSDIOCtrl->u4WHISR)); + + /* 4 <2> Setup STATUS count. */ + { + HAL_MCR_RD(prAdapter, MCR_WHCR, &u4Value); + + /* 4 <2.1> Setup the number of maximum RX length to be report */ + u4Value &= ~(WHCR_MAX_HIF_RX_LEN_NUM); + u4Value |= ((SDIO_MAXIMUM_RX_LEN_NUM + << WHCR_OFFSET_MAX_HIF_RX_LEN_NUM)); + + /* 4 <2.2> Setup RX enhancement mode */ +#if CFG_SDIO_RX_ENHANCE + u4Value |= WHCR_RX_ENHANCE_MODE_EN; +#else + u4Value &= ~WHCR_RX_ENHANCE_MODE_EN; +#endif + + HAL_MCR_WR(prAdapter, MCR_WHCR, u4Value); + } +#endif + + HAL_MCR_WR(prAdapter, MCR_WHIER, WHIER_DEFAULT); + + HAL_CFG_MAX_HIF_RX_LEN_NUM(prAdapter, HIF_RX_MAX_AGG_NUM); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Driver maintain a variable that is synchronous with the usage of + * individual TC Buffer Count. This function will calculate TC page count + * according to the given TX_STATUS COUNTER after TX Done. + * + * \param[in] prAdapter Pointer to the Adapter structure. + * \param[in] au2TxRlsCnt array of TX STATUS + * \param[in] au2FreeTcResource array of free & available resource + * count + * + * @return true there are available resource to release + * @return false no available resource to release + */ +/*----------------------------------------------------------------------------*/ +u8 halTxCalculateResource(IN P_ADAPTER_T prAdapter, IN u16 *au2TxRlsCnt, + OUT u16 *au2FreeTcResource) +{ + P_TX_TCQ_STATUS_T prTcqStatus; + u8 bStatus = false; + u8 ucTcIdx; + u32 u4TotalTxDoneCnt = 0; + u32 u4TotalExtraTxDone = 0; + u32 au4UsedCnt[TC_NUM]; + u32 au4ExtraTxDone[TC_NUM]; + + u32 *au4TxDoneCnt; + u32 *au4PreUsedCnt; + u32 u4AvaliableCnt; + u8 fgEnExtraTxDone; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + prTcqStatus = &prAdapter->rTxCtrl.rTc; + + au4TxDoneCnt = prTcqStatus->au4TxDonePageCount; + au4PreUsedCnt = prTcqStatus->au4PreUsedPageCount; + u4AvaliableCnt = prTcqStatus->u4AvaliablePageCount; + fgEnExtraTxDone = prAdapter->rWifiVar.ucExtraTxDone; + + /* Get used page count */ + if (fgEnExtraTxDone) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + for (ucTcIdx = TC0_INDEX; ucTcIdx < TC_NUM; ucTcIdx++) { + au4UsedCnt[ucTcIdx] = + prTcqStatus->au4MaxNumOfPage[ucTcIdx] - + prTcqStatus->au4FreePageCount[ucTcIdx]; + } + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + } + + /* Get Tx done & available page count */ + u4AvaliableCnt += au2TxRlsCnt[HIF_TX_FFA_INDEX]; + for (ucTcIdx = TC0_INDEX; ucTcIdx < TC_NUM; ucTcIdx++) { + /* Get Tx done count from Tx interrupt status */ + au4TxDoneCnt[ucTcIdx] += + au2TxRlsCnt[nicTxGetTxQByTc(prAdapter, ucTcIdx)]; + + /* Get available EXTRA Tx done */ + if (fgEnExtraTxDone) { + /* Release Tx done if there are pre-used resource */ + if (au4TxDoneCnt[ucTcIdx] >= au4PreUsedCnt[ucTcIdx]) { + au4TxDoneCnt[ucTcIdx] -= au4PreUsedCnt[ucTcIdx]; + au4PreUsedCnt[ucTcIdx] = 0; + } else { + au4PreUsedCnt[ucTcIdx] -= au4TxDoneCnt[ucTcIdx]; + au4TxDoneCnt[ucTcIdx] = 0; + } + + /* Calculate extra Tx done to share rest FFA resource */ + if (au4TxDoneCnt[ucTcIdx] >= au4UsedCnt[ucTcIdx]) { + au4TxDoneCnt[ucTcIdx] = au4UsedCnt[ucTcIdx]; + au4ExtraTxDone[ucTcIdx] = 0; + } else { + au4ExtraTxDone[ucTcIdx] = au4UsedCnt[ucTcIdx] - + au4TxDoneCnt[ucTcIdx]; + } + u4TotalExtraTxDone += au4ExtraTxDone[ucTcIdx]; + } + + u4TotalTxDoneCnt += au4TxDoneCnt[ucTcIdx]; + } + + DBGLOG(TX, TRACE, "TxDone result, FFA[%u] AC[%u:%u:%u:%u] CPU[%u]\n", + au2TxRlsCnt[HIF_TX_FFA_INDEX], au2TxRlsCnt[HIF_TX_AC0_INDEX], + au2TxRlsCnt[HIF_TX_AC1_INDEX], au2TxRlsCnt[HIF_TX_AC2_INDEX], + au2TxRlsCnt[HIF_TX_AC3_INDEX], au2TxRlsCnt[HIF_TX_CPU_INDEX]); + + DBGLOG(TX, TRACE, "TxDone Page count, TC[%u:%u:%u:%u:%u:%u]\n", + au4TxDoneCnt[TC0_INDEX], au4TxDoneCnt[TC1_INDEX], + au4TxDoneCnt[TC2_INDEX], au4TxDoneCnt[TC3_INDEX], + au4TxDoneCnt[TC4_INDEX], au4TxDoneCnt[TC5_INDEX]); + + /* Calculate free Tc page count */ + if (u4AvaliableCnt && u4TotalTxDoneCnt) { + /* Distribute resource by Tx done counter */ + if (u4AvaliableCnt >= u4TotalTxDoneCnt) { + /* Fulfill all TC resource */ + kalMemCopy(au2FreeTcResource, + prTcqStatus->au4TxDonePageCount, + sizeof(prTcqStatus->au4TxDonePageCount)); + + kalMemZero(prTcqStatus->au4TxDonePageCount, + sizeof(prTcqStatus->au4TxDonePageCount)); + + u4AvaliableCnt -= u4TotalTxDoneCnt; + } else { + /* Round-robin distribute resource */ + ucTcIdx = prTcqStatus->ucNextTcIdx; + while (u4AvaliableCnt) { + /* Enough resource, fulfill this TC */ + if (u4AvaliableCnt >= au4TxDoneCnt[ucTcIdx]) { + au2FreeTcResource[ucTcIdx] = + au4TxDoneCnt[ucTcIdx]; + u4AvaliableCnt -= au4TxDoneCnt[ucTcIdx]; + au4TxDoneCnt[ucTcIdx] = 0; + + /* Round-robin get next TC */ + ucTcIdx++; + ucTcIdx %= TC_NUM; + } + /* no more resource, distribute rest of resource + * to this TC */ + else { + au2FreeTcResource[ucTcIdx] = + u4AvaliableCnt; + au4TxDoneCnt[ucTcIdx] -= u4AvaliableCnt; + u4AvaliableCnt = 0; + } + } + prTcqStatus->ucNextTcIdx = ucTcIdx; + } + bStatus = true; + } + + if (u4AvaliableCnt && u4TotalExtraTxDone && fgEnExtraTxDone) { + /* Distribute resource by EXTRA Tx done counter */ + if (u4AvaliableCnt >= u4TotalExtraTxDone) { + for (ucTcIdx = TC0_INDEX; ucTcIdx < TC_NUM; ucTcIdx++) { + au2FreeTcResource[ucTcIdx] += + au4ExtraTxDone[ucTcIdx]; + au4PreUsedCnt[ucTcIdx] += + au4ExtraTxDone[ucTcIdx]; + au4ExtraTxDone[ucTcIdx] = 0; + } + + u4AvaliableCnt -= u4TotalExtraTxDone; + } else { + /* Round-robin distribute resource */ + ucTcIdx = prTcqStatus->ucNextTcIdx; + while (u4AvaliableCnt) { + /* Enough resource, fulfill this TC */ + if (u4AvaliableCnt >= au4ExtraTxDone[ucTcIdx]) { + au2FreeTcResource[ucTcIdx] += + au4ExtraTxDone[ucTcIdx]; + au4PreUsedCnt[ucTcIdx] += + au4ExtraTxDone[ucTcIdx]; + u4AvaliableCnt -= + au4ExtraTxDone[ucTcIdx]; + au4ExtraTxDone[ucTcIdx] = 0; + + /* Round-robin get next TC */ + ucTcIdx++; + ucTcIdx %= TC_NUM; + } + /* no more resource, distribute rest of resource + * to this TC */ + else { + au2FreeTcResource[ucTcIdx] += + u4AvaliableCnt; + au4PreUsedCnt[ucTcIdx] += + u4AvaliableCnt; + au4ExtraTxDone[ucTcIdx] -= + u4AvaliableCnt; + u4AvaliableCnt = 0; + } + } + prTcqStatus->ucNextTcIdx = ucTcIdx; + } + bStatus = true; + } + + prTcqStatus->u4AvaliablePageCount = u4AvaliableCnt; + + return bStatus; +} +u8 halTxReleaseResource(IN P_ADAPTER_T prAdapter, IN u16 *au2TxRlsCnt) +{ + P_TX_TCQ_STATUS_T prTcqStatus; + u8 bStatus = false; + u32 i; + P_SDIO_STAT_COUNTER_T prStatCnt; + u16 au2TxDoneCnt[HIF_TX_NUM] = { 0 }; + u16 u2ReturnCnt; + + KAL_SPIN_LOCK_DECLARATION(); + + ASSERT(prAdapter); + prTcqStatus = &prAdapter->rTxCtrl.rTc; + prStatCnt = &prAdapter->prGlueInfo->rHifInfo.rStatCounter; + + /* Update Free Tc resource counter */ + for (i = HIF_TX_AC0_INDEX; i <= HIF_TX_AC23_INDEX; i++) { +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + au2TxDoneCnt[i] = au2TxRlsCnt[i]; +#else + au2TxDoneCnt[i % WMM_AC_INDEX_NUM] += au2TxRlsCnt[i]; +#endif + } + au2TxDoneCnt[HIF_TX_CPU_INDEX] = au2TxRlsCnt[HIF_TX_CPU_INDEX]; + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + /*wmm_3: P2P_DEV*/ + au2TxDoneCnt[HIF_TX_AC3X_INDEX] = au2TxRlsCnt[HIF_TX_AC3X_INDEX]; +#endif + + /* Return free Tc page count */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + for (i = TC0_INDEX; i < TC_NUM; i++) { + if ((i == TC5_INDEX) || (i == TC10_INDEX) || + (i == TC15_INDEX)) { + /*bypass TC5/TC10/TC15, due to not use*/ + continue; + } +#else + for (i = TC0_INDEX; i < TC5_INDEX; i++) { +#endif + u2ReturnCnt = au2TxDoneCnt[nicTxGetTxQByTc(prAdapter, i)]; + nicTxReleaseResource(prAdapter, i, u2ReturnCnt, false); + prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[i] -= + u2ReturnCnt; + } + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + bStatus = true; + + /* Update Statistic counter */ + prStatCnt->u4TxDonePendingPktCnt += nicTxGetMsduPendingCnt(prAdapter); + prStatCnt->u4TxDoneIntTotCnt++; + + for (i = HIF_TX_AC0_INDEX; i < HIF_TX_NUM; i++) { + if (au2TxRlsCnt[i]) { + prStatCnt->u4TxDoneCnt[i] += au2TxRlsCnt[i]; + prStatCnt->u4TxDoneIntCnt[i]++; + } + } + + if (!nicTxSanityCheckResource(prAdapter)) { + DBGLOG(TX, ERROR, + "Tx Done INT result, FFA[%u] AC[%u:%u:%u:%u] CPU[%u]\n", + au2TxRlsCnt[HIF_TX_FFA_INDEX], + au2TxRlsCnt[HIF_TX_AC0_INDEX], + au2TxRlsCnt[HIF_TX_AC1_INDEX], + au2TxRlsCnt[HIF_TX_AC2_INDEX], + au2TxRlsCnt[HIF_TX_AC3_INDEX], + au2TxRlsCnt[HIF_TX_CPU_INDEX]); +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + DBGLOG(TX, ERROR, "Tx Done INT result, AC[%u:%u:%u:%u]\n", + au2TxRlsCnt[HIF_TX_AC10_INDEX], + au2TxRlsCnt[HIF_TX_AC11_INDEX], + au2TxRlsCnt[HIF_TX_AC12_INDEX], + au2TxRlsCnt[HIF_TX_AC13_INDEX]); + + DBGLOG(TX, ERROR, "Tx Done INT result_2, AC[%u:%u:%u:%u:%u]\n", + au2TxRlsCnt[HIF_TX_AC20_INDEX], + au2TxRlsCnt[HIF_TX_AC21_INDEX], + au2TxRlsCnt[HIF_TX_AC22_INDEX], + au2TxRlsCnt[HIF_TX_AC23_INDEX], + au2TxRlsCnt[HIF_TX_AC3X_INDEX]); +#endif + } + + return bStatus; +} + +WLAN_STATUS halTxPollingResource(IN P_ADAPTER_T prAdapter, IN u8 ucTC) +{ + P_TX_CTRL_T prTxCtrl; + WLAN_STATUS u4Status = WLAN_STATUS_RESOURCES; + u32 au4WTSR[8]; + P_GL_HIF_INFO_T prHifInfo; + + prHifInfo = &prAdapter->prGlueInfo->rHifInfo; + + prTxCtrl = &prAdapter->rTxCtrl; + + if (prHifInfo->fgIsPendingInt && + (prHifInfo->prSDIOCtrl->u4WHISR & WHISR_TX_DONE_INT)) { + /* Get Tx done resource from pending interrupt status */ + kalMemCopy(au4WTSR, &prHifInfo->prSDIOCtrl->rTxInfo, + sizeof(u32) * 8); + + /* Clear pending Tx done interrupt */ + prHifInfo->prSDIOCtrl->u4WHISR &= ~WHISR_TX_DONE_INT; + } else { + HAL_READ_TX_RELEASED_COUNT(prAdapter, au4WTSR); + } + + if (kalIsCardRemoved(prAdapter->prGlueInfo) == true || + fgIsBusAccessFailed == true) { + u4Status = WLAN_STATUS_FAILURE; + } else if (halTxReleaseResource(prAdapter, (u16 *)au4WTSR)) { + if (prTxCtrl->rTc.au4FreeBufferCount[ucTC] > 0) { + u4Status = WLAN_STATUS_SUCCESS; + } + } + + return u4Status; +} + +void halTxInterruptSanityCheck(IN P_ADAPTER_T prAdapter, IN u16 *au2TxRlsCnt) +{ + u8 ucIdx; + u8 fgError = false; + + if (prAdapter->rWifiVar.ucTxDbg & BIT(1)) { + for (ucIdx = HIF_TX_AC0_INDEX; ucIdx < HIF_TX_NUM; ucIdx++) { + if (au2TxRlsCnt[ucIdx] > + prAdapter->rTxCtrl.u4TotalPageNum) { + fgError = true; + } + } + + if (fgError) { + DBGLOG(TX, + ERROR, + "Tx Done INT result, FFA[%u] AC[%u:%u:%u:%u] CPU[%u]\n", + au2TxRlsCnt[HIF_TX_FFA_INDEX], + au2TxRlsCnt[HIF_TX_AC0_INDEX], + au2TxRlsCnt[HIF_TX_AC1_INDEX], + au2TxRlsCnt[HIF_TX_AC2_INDEX], + au2TxRlsCnt[HIF_TX_AC3_INDEX], + au2TxRlsCnt[HIF_TX_CPU_INDEX]); + } + } +} + +#if CFG_SDIO_INTR_ENHANCE +void halProcessEnhanceInterruptStatus(IN P_ADAPTER_T prAdapter) +{ + P_SDIO_CTRL_T prSDIOCtrl = prAdapter->prGlueInfo->rHifInfo.prSDIOCtrl; + + /* Set Tx done interrupt if there are Tx done count */ + if ((prSDIOCtrl->u4WHISR & WHISR_TX_DONE_INT) == 0 && + (prSDIOCtrl->rTxInfo.au4WTSR[0] | prSDIOCtrl->rTxInfo.au4WTSR[1] | + prSDIOCtrl->rTxInfo.au4WTSR[2] | prSDIOCtrl->rTxInfo.au4WTSR[3] | + prSDIOCtrl->rTxInfo.au4WTSR[4] | prSDIOCtrl->rTxInfo.au4WTSR[5] | + prSDIOCtrl->rTxInfo.au4WTSR[6] | prSDIOCtrl->rTxInfo.au4WTSR[7])) { + prSDIOCtrl->u4WHISR |= WHISR_TX_DONE_INT; + } + + /* Set SW ASSERT INFO interrupt if there are pending mail box */ + if (((prSDIOCtrl->u4WHISR & WHISR_D2H_SW_ASSERT_INFO_INT) == 0) && + HAL_GET_MAILBOX_READ_CLEAR(prAdapter) && + (prSDIOCtrl->u4RcvMailbox0 || prSDIOCtrl->u4RcvMailbox1)) { + prSDIOCtrl->u4WHISR |= WHISR_D2H_SW_ASSERT_INFO_INT; + } +} +#endif + +void halProcessTxInterrupt(IN P_ADAPTER_T prAdapter) +{ + P_TX_CTRL_T prTxCtrl; +#if CFG_SDIO_INTR_ENHANCE + P_SDIO_CTRL_T prSDIOCtrl; +#else + u32 au4TxCount[2]; +#endif + SDIO_TIME_INTERVAL_DEC(); + + ASSERT(prAdapter); + + prTxCtrl = &prAdapter->rTxCtrl; + ASSERT(prTxCtrl); + + SDIO_REC_TIME_START(); + + /* Get the TX STATUS */ +#if CFG_SDIO_INTR_ENHANCE + prSDIOCtrl = prAdapter->prGlueInfo->rHifInfo.prSDIOCtrl; +#if DBG + /* DBGLOG_MEM8(RX, TRACE, (u8 *)prSDIOCtrl, sizeof(SDIO_CTRL_T)); */ +#endif + + halTxInterruptSanityCheck(prAdapter, (u16 *)&prSDIOCtrl->rTxInfo); + halTxReleaseResource(prAdapter, (u16 *)&prSDIOCtrl->rTxInfo); + kalMemZero(&prSDIOCtrl->rTxInfo, sizeof(prSDIOCtrl->rTxInfo)); +#else + HAL_MCR_RD(prAdapter, MCR_WTSR0, &au4TxCount[0]); + HAL_MCR_RD(prAdapter, MCR_WTSR1, &au4TxCount[1]); + DBGLOG(EMU, TRACE, "MCR_WTSR0: 0x%x, MCR_WTSR1: 0x%x\n", au4TxCount[0], + au4TxCount[1]); + + halTxReleaseResource(prAdapter, (u8 *)au4TxCount); +#endif + + nicTxAdjustTcq(prAdapter); + + SDIO_REC_TIME_END(); + SDIO_ADD_TIME_INTERVAL( + prAdapter->prGlueInfo->rHifInfo.rStatCounter.u4TxDoneIntTime); +} + +#if !CFG_SDIO_INTR_ENHANCE +/*----------------------------------------------------------------------------*/ +/*! + * @brief Read the rx data from data port and setup RFB + * + * @param prAdapter pointer to the Adapter handler + * @param prSWRfb the RFB to receive rx data + * + * @retval WLAN_STATUS_SUCCESS: SUCCESS + * @retval WLAN_STATUS_FAILURE: FAILURE + * + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS halRxReadBuffer(IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb) +{ + P_RX_CTRL_T prRxCtrl; + u8 *pucBuf; + P_HW_MAC_RX_DESC_T prRxStatus; + u32 u4PktLen = 0, u4ReadBytes; + WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; + u8 fgResult = true; + u32 u4RegValue; + u32 rxNum; + + DEBUGFUNC("halRxReadBuffer"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + pucBuf = prSwRfb->pucRecvBuff; + prRxStatus = prSwRfb->prRxStatus; + + ASSERT(prRxStatus); + ASSERT(pucBuf); + DBGLOG(RX, TRACE, "pucBuf= 0x%x, prRxStatus= 0x%x\n", pucBuf, + prRxStatus); + + do { + /* Read the RFB DW length and packet length */ + HAL_MCR_RD(prAdapter, MCR_WRPLR, &u4RegValue); + if (!fgResult) { + DBGLOG(RX, ERROR, "Read RX Packet Lentgh Error\n"); + return WLAN_STATUS_FAILURE; + } + /* 20091021 move the line to get the HIF RX header (for RX0/1) + */ + if (u4RegValue == 0) { + DBGLOG(RX, ERROR, "No RX packet\n"); + return WLAN_STATUS_FAILURE; + } + + u4PktLen = u4RegValue & BITS(0, 15); + if (u4PktLen != 0) { + rxNum = 0; + } else { + rxNum = 1; + u4PktLen = (u4RegValue & BITS(16, 31)) >> 16; + } + + DBGLOG(RX, TRACE, "RX%d: u4PktLen = %d\n", rxNum, u4PktLen); + + /* 4 <4> Read Entire RFB and packet, include HW appended DW + * (Checksum Status) */ + u4ReadBytes = ALIGN_4(u4PktLen) + 4; + HAL_READ_RX_PORT(prAdapter, rxNum, u4ReadBytes, pucBuf, + CFG_RX_MAX_PKT_SIZE); + + /* 20091021 move the line to get the HIF RX header */ + /* u4PktLen = (u32)prHifRxHdr->u2PacketLen; */ + if (u4PktLen != + (u32)HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus)) { + DBGLOG(RX, + ERROR, + "Read u4PktLen = %d, prHifRxHdr->u2PacketLen: %d\n", + u4PktLen, + HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus)); +#if DBG + DBGLOG_MEM8(RX, TRACE, (u8 *)prRxStatus, + (HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus) > + 4096) ? + 4096 : + prRxStatus->u2RxByteCount); +#endif + ASSERT(0); + } + /* u4PktLen is byte unit, not inlude HW appended DW */ + + prSwRfb->ucPacketType = + (u8)HAL_RX_STATUS_GET_PKT_TYPE(prRxStatus); + DBGLOG(RX, TRACE, "ucPacketType = %d\n", prSwRfb->ucPacketType); + + prSwRfb->ucStaRecIdx = secGetStaIdxByWlanIdx( + prAdapter, (u8)HAL_RX_STATUS_GET_WLAN_IDX(prRxStatus)); + + /* fgResult will be updated in MACRO */ + if (!fgResult) { + return WLAN_STATUS_FAILURE; + } + + DBGLOG(RX, TRACE, "Dump RX buffer, length = 0x%x\n", + u4ReadBytes); + DBGLOG_MEM8(RX, TRACE, pucBuf, u4ReadBytes); + } while (false); + + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Read frames from the data port, fill RFB + * and put each frame into the rReceivedRFBList queue. + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void halRxSDIOReceiveRFBs(IN P_ADAPTER_T prAdapter) +{ + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T)NULL; + P_HW_MAC_RX_DESC_T prRxStatus; + u32 u4HwAppendDW; + u32 *pu4Temp; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("halRxSDIOReceiveRFBs"); + + ASSERT(prAdapter); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + do { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, + P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + + if (!prSwRfb) { + DBGLOG(RX, TRACE, "No More RFB\n"); + break; + } + /* need to consider */ + if (halRxReadBuffer(prAdapter, prSwRfb) == + WLAN_STATUS_FAILURE) { + DBGLOG(RX, TRACE, "halRxFillRFB failed\n"); + nicRxReturnRFB(prAdapter, prSwRfb); + break; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, + &prSwRfb->rQueEntry); + RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + prRxStatus = prSwRfb->prRxStatus; + ASSERT(prRxStatus); + + pu4Temp = (u32 *)prRxStatus; + u4HwAppendDW = + *(pu4Temp + (ALIGN_4(prRxStatus->u2RxByteCount) >> 2)); + DBGLOG(RX, TRACE, "u4HwAppendDW = 0x%x\n", u4HwAppendDW); + DBGLOG(RX, TRACE, "u2PacketLen = 0x%x\n", + HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus)); + } while (false); +} + +#else +/*----------------------------------------------------------------------------*/ +/*! + * @brief Read frames from the data port, fill RFB + * and put each frame into the rReceivedRFBList queue. + * + * @param prAdapter Pointer to the Adapter structure. + * @param u4DataPort Specify which port to read + * @param u2RxLength Specify to the the rx packet length in Byte. + * @param prSwRfb the RFB to receive rx data. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ + +WLAN_STATUS +halRxEnhanceReadBuffer(IN P_ADAPTER_T prAdapter, IN u32 u4DataPort, + IN u16 u2RxLength, IN OUT P_SW_RFB_T prSwRfb) +{ + P_RX_CTRL_T prRxCtrl; + u8 *pucBuf; + P_HW_MAC_RX_DESC_T prRxStatus; + u32 u4PktLen = 0; + WLAN_STATUS u4Status = WLAN_STATUS_FAILURE; + u8 fgResult = true; + + DEBUGFUNC("halRxEnhanceReadBuffer"); + + ASSERT(prAdapter); + ASSERT(prSwRfb); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + pucBuf = prSwRfb->pucRecvBuff; + ASSERT(pucBuf); + + prRxStatus = prSwRfb->prRxStatus; + ASSERT(prRxStatus); + + /* DBGLOG(RX, TRACE, ("u2RxLength = %d\n", u2RxLength)); */ + + do { + /* 4 <1> Read RFB frame from MCR_WRDR0, include HW appended DW + */ + HAL_READ_RX_PORT(prAdapter, u4DataPort, + ALIGN_4(u2RxLength + HIF_RX_HW_APPENDED_LEN), + pucBuf, CFG_RX_MAX_PKT_SIZE); + + if (!fgResult) { + DBGLOG(RX, ERROR, "Read RX Packet Lentgh Error\n"); + break; + } + + u4PktLen = (u32)(HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus)); + /* DBGLOG(RX, TRACE, ("u4PktLen = %d\n", u4PktLen)); */ + + prSwRfb->ucPacketType = + (u8)HAL_RX_STATUS_GET_PKT_TYPE(prRxStatus); + /* DBGLOG(RX, TRACE, ("ucPacketType = %d\n", + * prSwRfb->ucPacketType)); */ + + prSwRfb->ucStaRecIdx = secGetStaIdxByWlanIdx( + prAdapter, (u8)HAL_RX_STATUS_GET_WLAN_IDX(prRxStatus)); + + /* 4 <2> if the RFB dw size or packet size is zero */ + if (u4PktLen == 0) { + DBGLOG(RX, ERROR, "Packet Length = %lu\n", u4PktLen); + ASSERT(0); + break; + } + /* 4 <3> if the packet is too large or too small */ + /* ToDo[6630]: adjust CFG_RX_MAX_PKT_SIZE */ + if ((u4PktLen > CFG_RX_MAX_PKT_SIZE) || + (u4PktLen < sizeof(HW_MAC_RX_DESC_T))) { + DBGLOG(RX, TRACE, "Read RX Packet Lentgh Error (%lu)\n", + u4PktLen); + ASSERT(0); + break; + } + + u4Status = WLAN_STATUS_SUCCESS; + } while (false); + + DBGLOG_MEM8(RX, TRACE, pucBuf, + ALIGN_4(u2RxLength + HIF_RX_HW_APPENDED_LEN)); + return u4Status; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Read frames from the data port for SDIO + * I/F, fill RFB and put each frame into the rReceivedRFBList queue. + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void halRxSDIOEnhanceReceiveRFBs(IN P_ADAPTER_T prAdapter) +{ + P_SDIO_CTRL_T prSDIOCtrl; + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T)NULL; + u32 i, rxNum; + u16 u2RxPktNum, u2RxLength = 0, u2Tmp = 0; + + KAL_SPIN_LOCK_DECLARATION(); + + DEBUGFUNC("halRxSDIOEnhanceReceiveRFBs"); + + ASSERT(prAdapter); + + prSDIOCtrl = prAdapter->prGlueInfo->rHifInfo.prSDIOCtrl; + ASSERT(prSDIOCtrl); + + prRxCtrl = &prAdapter->rRxCtrl; + ASSERT(prRxCtrl); + + for (rxNum = 0; rxNum < 2; rxNum++) { + u2RxPktNum = (rxNum == 0 ? + prSDIOCtrl->rRxInfo.u.u2NumValidRx0Len : + prSDIOCtrl->rRxInfo.u.u2NumValidRx1Len); + + if (u2RxPktNum == 0) { + continue; + } + + for (i = 0; i < u2RxPktNum; i++) { + if (rxNum == 0) { + /* HAL_READ_RX_LENGTH */ + HAL_READ_RX_LENGTH(prAdapter, &u2RxLength, + &u2Tmp); + } else if (rxNum == 1) { + /* HAL_READ_RX_LENGTH */ + HAL_READ_RX_LENGTH(prAdapter, &u2Tmp, + &u2RxLength); + } + + if (!u2RxLength) { + break; + } + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, + P_SW_RFB_T); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + + if (!prSwRfb) { + DBGLOG(RX, TRACE, "No More RFB\n"); + break; + } + ASSERT(prSwRfb); + + if (halRxEnhanceReadBuffer(prAdapter, rxNum, u2RxLength, + prSwRfb) == + WLAN_STATUS_FAILURE) { + DBGLOG(RX, TRACE, + "nicRxEnhanceRxReadBuffer failed\n"); + nicRxReturnRFB(prAdapter, prSwRfb); + break; + } + /* prSDIOCtrl->au4RxLength[i] = 0; */ + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, + &prSwRfb->rQueEntry); + RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + } + } + + prSDIOCtrl->rRxInfo.u.u2NumValidRx0Len = 0; + prSDIOCtrl->rRxInfo.u.u2NumValidRx1Len = 0; +} + +#endif + +#if CFG_SDIO_RX_AGG +/*----------------------------------------------------------------------------*/ +/*! + * @brief Read frames from the data port for SDIO with Rx aggregation enabled + * I/F, fill RFB and put each frame into the rReceivedRFBList queue. + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (none) + */ +/*----------------------------------------------------------------------------*/ +void halRxSDIOAggReceiveRFBs(IN P_ADAPTER_T prAdapter) +{ + P_ENHANCE_MODE_DATA_STRUCT_T prEnhDataStr; + P_RX_CTRL_T prRxCtrl; + u32 u4RxLength; + u32 i, rxNum; + u32 u4RxAggCount = 0, u4RxAggLength = 0; + u32 u4RxAvailAggLen; +#if CFG_SDIO_RX_ENHANCE + u8 *pucSrcAddr; +#endif + u16 u2RxPktNum; + P_GL_HIF_INFO_T prHifInfo; + P_SDIO_RX_COALESCING_BUF_T prRxBuf; + u8 fgNoFreeBuf = false; + + SDIO_TIME_INTERVAL_DEC(); + + DEBUGFUNC("halRxSDIOAggReceiveRFBs"); + + ASSERT(prAdapter); + + prRxCtrl = &prAdapter->rRxCtrl; + prHifInfo = &prAdapter->prGlueInfo->rHifInfo; + prEnhDataStr = prHifInfo->prSDIOCtrl; + + if (prEnhDataStr->rRxInfo.u.u2NumValidRx0Len == 0 && + prEnhDataStr->rRxInfo.u.u2NumValidRx1Len == 0) { + return; + } + + for (rxNum = 0; rxNum < 2; rxNum++) { + u2RxPktNum = (rxNum == 0 ? + prEnhDataStr->rRxInfo.u.u2NumValidRx0Len : + prEnhDataStr->rRxInfo.u.u2NumValidRx1Len); + + /* if this assertion happened, it is most likely a F/W bug */ + ASSERT(u2RxPktNum <= HIF_RX_MAX_AGG_NUM); + + if (u2RxPktNum > HIF_RX_MAX_AGG_NUM) { + continue; + } + + if (u2RxPktNum == 0) { + continue; + } + +#if CFG_HIF_STATISTICS + prRxCtrl->u4TotalRxAccessNum++; + prRxCtrl->u4TotalRxPacketNum += u2RxPktNum; +#endif + + mutex_lock(&prHifInfo->rRxFreeBufQueMutex); + fgNoFreeBuf = QUEUE_IS_EMPTY(&prHifInfo->rRxFreeBufQueue); + mutex_unlock(&prHifInfo->rRxFreeBufQueMutex); + + if (fgNoFreeBuf) { + DBGLOG(RX, TRACE, "[%s] No free Rx buffer\n", __func__); + prHifInfo->rStatCounter.u4RxBufUnderFlowCnt++; + + if (prAdapter->prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + QUE_T rTempQue; + P_QUE_T prTempQue = &rTempQue; + + /* During halt state, move all pending Rx buffer + * to free queue */ + mutex_lock(&prHifInfo->rRxDeAggQueMutex); + QUEUE_MOVE_ALL(prTempQue, + &prHifInfo->rRxDeAggQueue); + mutex_unlock(&prHifInfo->rRxDeAggQueMutex); + + mutex_lock(&prHifInfo->rRxFreeBufQueMutex); + QUEUE_CONCATENATE_QUEUES( + &prHifInfo->rRxFreeBufQueue, prTempQue); + mutex_unlock(&prHifInfo->rRxFreeBufQueMutex); + } + + continue; + } + + u4RxAvailAggLen = HIF_RX_COALESCING_BUFFER_SIZE; +#if CFG_SDIO_RX_ENHANCE + u4RxAvailAggLen -= (sizeof(ENHANCE_MODE_DATA_STRUCT_T) + + HIF_RX_ENHANCE_MODE_PAD_LEN); +#endif + u4RxAggCount = 0; + + for (i = 0; i < u2RxPktNum; i++) { + u4RxLength = (rxNum == 0 ? (u32)prEnhDataStr->rRxInfo.u + .au2Rx0Len[i] : + (u32)prEnhDataStr->rRxInfo.u + .au2Rx1Len[i]); + + if (!u4RxLength) { + ASSERT(0); + DBGLOG(RX, ERROR, "[%s] RxLength == 0\n", + __func__); + break; + } + + if (ALIGN_4(u4RxLength + HIF_RX_HW_APPENDED_LEN) < + u4RxAvailAggLen) { + u4RxAvailAggLen -= ALIGN_4( + u4RxLength + HIF_RX_HW_APPENDED_LEN); + u4RxAggCount++; + } else { + /* CFG_RX_COALESCING_BUFFER_SIZE is not large + * enough */ + DBGLOG(RX, + ERROR, + "[%s] Request_len(%d) >= Available_len(%d)\n", + __func__, + (ALIGN_4(u4RxLength + + HIF_RX_HW_APPENDED_LEN)), + u4RxAvailAggLen); + ASSERT(0); + break; + } + } + + mutex_lock(&prHifInfo->rRxFreeBufQueMutex); + QUEUE_REMOVE_HEAD(&prHifInfo->rRxFreeBufQueue, prRxBuf, + P_SDIO_RX_COALESCING_BUF_T); + mutex_unlock(&prHifInfo->rRxFreeBufQueMutex); + + prRxBuf->u4PktCount = u4RxAggCount; + + u4RxAggLength = + (HIF_RX_COALESCING_BUFFER_SIZE - u4RxAvailAggLen); + + SDIO_REC_TIME_START(); + HAL_READ_RX_PORT(prAdapter, rxNum, u4RxAggLength, + prRxBuf->pvRxCoalescingBuf, + HIF_RX_COALESCING_BUFFER_SIZE); + SDIO_REC_TIME_END(); + SDIO_ADD_TIME_INTERVAL(prHifInfo->rStatCounter.u4PortReadTime); + +#if CFG_SDIO_RX_ENHANCE + pucSrcAddr = prRxBuf->pvRxCoalescingBuf + u4RxAggLength - + sizeof(ENHANCE_MODE_DATA_STRUCT_T); + kalMemCopy(prHifInfo->prSDIOCtrl, pucSrcAddr, + sizeof(ENHANCE_MODE_DATA_STRUCT_T)); + + halProcessEnhanceInterruptStatus(prAdapter); + + if (prHifInfo->prSDIOCtrl->u4WHISR) { + /* Interrupt status without Rx done */ + /* Mask Rx done interrupt to avoid recurrsion */ + u32 u4IntStatus = + prHifInfo->prSDIOCtrl->u4WHISR & + (~(WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT)); + + if ((rxNum == 0) && + prEnhDataStr->rRxInfo.u.u2NumValidRx1Len && + u4IntStatus) { + /* Handle interrupt here if there are pending Rx + * port1 */ + + nicProcessIST_impl(prAdapter, u4IntStatus); + } else { + prAdapter->prGlueInfo->rHifInfo.fgIsPendingInt = + true; + } + } +#endif + halDeAggRxPkt(prAdapter, prRxBuf); + + /* Update statistic counter */ + prHifInfo->rStatCounter.u4PktReadCnt[rxNum] += u4RxAggCount; + prHifInfo->rStatCounter.u4PortReadCnt[rxNum]++; + } +} +#endif + +void halProcessRxInterrupt(IN P_ADAPTER_T prAdapter) +{ +#if CFG_MESON_G12A_PATCH + halRxSDIOEnhanceReceiveRFBs(prAdapter); +#else +#if CFG_SDIO_INTR_ENHANCE +#if CFG_SDIO_RX_AGG + halRxSDIOAggReceiveRFBs(prAdapter); +#else + halRxSDIOEnhanceReceiveRFBs(prAdapter); +#endif +#else + halRxSDIOReceiveRFBs(prAdapter); +#endif +#endif +} + +u32 halDumpHifStatus(IN P_ADAPTER_T prAdapter, IN u8 *pucBuf, IN u32 u4Max) +{ + P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; + P_GL_HIF_INFO_T prHifInfo = &prGlueInfo->rHifInfo; + P_SDIO_STAT_COUNTER_T prStatCnt = &prHifInfo->rStatCounter; + u32 u4Len = 0; + + /* Print out counter */ + LOGBUF(pucBuf, u4Max, u4Len, "\n"); + LOGBUF(pucBuf, u4Max, u4Len, "------<Dump SDIO Status>------\n"); + + LOGBUF(pucBuf, + u4Max, + u4Len, + "Coalescing buffer size[%u] Rx Cnt[%u/%u] DeAgg[%u] UF Cnt[%u]\n", + prAdapter->u4CoalescingBufCachedSize, + prHifInfo->rRxFreeBufQueue.u4NumElem, + HIF_RX_COALESCING_BUF_COUNT, + prHifInfo->rRxDeAggQueue.u4NumElem, + prStatCnt->u4RxBufUnderFlowCnt); + + LOGBUF(pucBuf, u4Max, u4Len, + "Pkt cnt Tx[%u] RxP0[%u] RxP1[%u] Tx/Rx ratio[%u.%u]\n", + prStatCnt->u4DataPktWriteCnt, prStatCnt->u4PktReadCnt[0], + prStatCnt->u4PktReadCnt[1], + DIV2INT(prStatCnt->u4DataPktWriteCnt, + prStatCnt->u4PktReadCnt[0]), + DIV2DEC(prStatCnt->u4DataPktWriteCnt, + prStatCnt->u4PktReadCnt[0])); + + LOGBUF(pucBuf, u4Max, u4Len, + "Tx pkt/wt[%u.%u] pkt/kick[%u.%u] cmd/wt[%u.%u]\n", + DIV2INT(prStatCnt->u4DataPktWriteCnt, + prStatCnt->u4DataPortWriteCnt), + DIV2DEC(prStatCnt->u4DataPktWriteCnt, + prStatCnt->u4DataPortWriteCnt), + DIV2INT(prStatCnt->u4DataPktWriteCnt, + prStatCnt->u4DataPortKickCnt), + DIV2DEC(prStatCnt->u4DataPktWriteCnt, + prStatCnt->u4DataPortKickCnt), + DIV2INT(prStatCnt->u4CmdPktWriteCnt, + prStatCnt->u4CmdPortWriteCnt), + DIV2DEC(prStatCnt->u4CmdPktWriteCnt, + prStatCnt->u4CmdPortWriteCnt)); + + LOGBUF(pucBuf, u4Max, u4Len, "Rx P0 pkt/rd[%u.%u] P1 pkt/rd[%u.%u]\n", + DIV2INT(prStatCnt->u4PktReadCnt[0], prStatCnt->u4PortReadCnt[0]), + DIV2DEC(prStatCnt->u4PktReadCnt[0], prStatCnt->u4PortReadCnt[0]), + DIV2INT(prStatCnt->u4PktReadCnt[1], prStatCnt->u4PortReadCnt[1]), + DIV2DEC(prStatCnt->u4PktReadCnt[1], + prStatCnt->u4PortReadCnt[1])); + + LOGBUF(pucBuf, u4Max, u4Len, + "Tx done pending cnt TC00~05[%u, %u, %u, %u, %u, %u]\n", + prHifInfo->au4PendingTxDoneCount[TC0_INDEX], + prHifInfo->au4PendingTxDoneCount[TC1_INDEX], + prHifInfo->au4PendingTxDoneCount[TC2_INDEX], + prHifInfo->au4PendingTxDoneCount[TC3_INDEX], + prHifInfo->au4PendingTxDoneCount[TC4_INDEX], + prHifInfo->au4PendingTxDoneCount[TC5_INDEX]); + + LOGBUF(pucBuf, u4Max, u4Len, "Tx done counter/int:\n"); + LOGBUF(pucBuf, u4Max, u4Len, "AC00~03[%u.%u, %u.%u, %u.%u, %u.%u]\n", + DIV2INT(prStatCnt->u4TxDoneCnt[0], prStatCnt->u4TxDoneIntCnt[0]), + DIV2DEC(prStatCnt->u4TxDoneCnt[0], prStatCnt->u4TxDoneIntCnt[0]), + DIV2INT(prStatCnt->u4TxDoneCnt[1], prStatCnt->u4TxDoneIntCnt[1]), + DIV2DEC(prStatCnt->u4TxDoneCnt[1], prStatCnt->u4TxDoneIntCnt[1]), + DIV2INT(prStatCnt->u4TxDoneCnt[2], prStatCnt->u4TxDoneIntCnt[2]), + DIV2DEC(prStatCnt->u4TxDoneCnt[2], prStatCnt->u4TxDoneIntCnt[2]), + DIV2INT(prStatCnt->u4TxDoneCnt[3], prStatCnt->u4TxDoneIntCnt[3]), + DIV2DEC(prStatCnt->u4TxDoneCnt[3], + prStatCnt->u4TxDoneIntCnt[3])); + + LOGBUF(pucBuf, u4Max, u4Len, "AC10~13[%u.%u, %u.%u, %u.%u, %u.%u]\n", + DIV2INT(prStatCnt->u4TxDoneCnt[4], prStatCnt->u4TxDoneIntCnt[4]), + DIV2DEC(prStatCnt->u4TxDoneCnt[4], prStatCnt->u4TxDoneIntCnt[4]), + DIV2INT(prStatCnt->u4TxDoneCnt[5], prStatCnt->u4TxDoneIntCnt[5]), + DIV2DEC(prStatCnt->u4TxDoneCnt[5], prStatCnt->u4TxDoneIntCnt[5]), + DIV2INT(prStatCnt->u4TxDoneCnt[6], prStatCnt->u4TxDoneIntCnt[6]), + DIV2DEC(prStatCnt->u4TxDoneCnt[5], prStatCnt->u4TxDoneIntCnt[5]), + DIV2INT(prStatCnt->u4TxDoneCnt[7], prStatCnt->u4TxDoneIntCnt[7]), + DIV2DEC(prStatCnt->u4TxDoneCnt[7], + prStatCnt->u4TxDoneIntCnt[7])); + + LOGBUF(pucBuf, u4Max, u4Len, + "AC20~23[%u.%u, %u.%u, %u.%u, %u.%u] FFA,CPU[%u.%u, %u.%u]\n", + DIV2INT(prStatCnt->u4TxDoneCnt[8], prStatCnt->u4TxDoneIntCnt[8]), + DIV2DEC(prStatCnt->u4TxDoneCnt[8], prStatCnt->u4TxDoneIntCnt[8]), + DIV2INT(prStatCnt->u4TxDoneCnt[9], prStatCnt->u4TxDoneIntCnt[9]), + DIV2DEC(prStatCnt->u4TxDoneCnt[9], prStatCnt->u4TxDoneIntCnt[9]), + DIV2INT(prStatCnt->u4TxDoneCnt[10], + prStatCnt->u4TxDoneIntCnt[10]), + DIV2DEC(prStatCnt->u4TxDoneCnt[10], + prStatCnt->u4TxDoneIntCnt[10]), + DIV2INT(prStatCnt->u4TxDoneCnt[11], + prStatCnt->u4TxDoneIntCnt[11]), + DIV2DEC(prStatCnt->u4TxDoneCnt[11], + prStatCnt->u4TxDoneIntCnt[11]), + DIV2INT(prStatCnt->u4TxDoneCnt[14], + prStatCnt->u4TxDoneIntCnt[14]), + DIV2DEC(prStatCnt->u4TxDoneCnt[14], + prStatCnt->u4TxDoneIntCnt[14]), + DIV2INT(prStatCnt->u4TxDoneCnt[15], + prStatCnt->u4TxDoneIntCnt[15]), + DIV2DEC(prStatCnt->u4TxDoneCnt[15], + prStatCnt->u4TxDoneIntCnt[15])); + + LOGBUF(pucBuf, u4Max, u4Len, + "Pending pkt/int[%u.%u] kick/int[%u.%u] rx_enh/sts[%u.%u]\n", + DIV2INT(prStatCnt->u4TxDonePendingPktCnt, + prStatCnt->u4TxDoneIntTotCnt), + DIV2DEC(prStatCnt->u4TxDonePendingPktCnt, + prStatCnt->u4TxDoneIntTotCnt), + DIV2INT(prStatCnt->u4DataPortKickCnt, + prStatCnt->u4TxDoneIntTotCnt), + DIV2DEC(prStatCnt->u4DataPortKickCnt, + prStatCnt->u4TxDoneIntTotCnt), + DIV2INT((prStatCnt->u4IntCnt - prStatCnt->u4IntReadCnt), + prStatCnt->u4IntCnt), + DIV2DEC((prStatCnt->u4IntCnt - prStatCnt->u4IntReadCnt), + prStatCnt->u4IntCnt)); + +#if CFG_SDIO_TIMING_PROFILING + LOGBUF(pucBuf, u4Max, u4Len, "Tx cp_t/pkt[%u.%uus] free/pkt[%u.%uus]\n", + DIV2INT(prStatCnt->u4TxDataCpTime, prStatCnt->u4DataPktWriteCnt), + DIV2DEC(prStatCnt->u4TxDataCpTime, prStatCnt->u4DataPktWriteCnt), + DIV2INT(prStatCnt->u4TxDataFreeTime, + prStatCnt->u4DataPktWriteCnt), + DIV2DEC(prStatCnt->u4TxDataFreeTime, + prStatCnt->u4DataPktWriteCnt)); + + LOGBUF(pucBuf, u4Max, u4Len, + "Rx P0 cp_t/pkt[%u.%uus] avg read[%u.%uus]\n", + DIV2INT(prStatCnt->u4RxDataCpTime, prStatCnt->u4PktReadCnt[0]), + DIV2DEC(prStatCnt->u4RxDataCpTime, prStatCnt->u4PktReadCnt[0]), + DIV2INT(prStatCnt->u4PortReadTime, prStatCnt->u4PortReadCnt[0]), + DIV2DEC(prStatCnt->u4PortReadTime, prStatCnt->u4PortReadCnt[0])); + + LOGBUF(pucBuf, u4Max, u4Len, + "INT rd_sts/sts[%u.%uus] tx_sts/sts[%u.%uus]\n", + DIV2INT(prStatCnt->u4IntReadTime, prStatCnt->u4IntReadCnt), + DIV2DEC(prStatCnt->u4IntReadTime, prStatCnt->u4IntReadCnt), + DIV2INT(prStatCnt->u4TxDoneIntTime, + prStatCnt->u4TxDoneIntTotCnt), + DIV2DEC(prStatCnt->u4TxDoneIntTime, + prStatCnt->u4TxDoneIntTotCnt)); +#endif + + LOGBUF(pucBuf, u4Max, u4Len, "---------------------------------\n"); + + /* Reset statistic counter */ + kalMemZero(prStatCnt, sizeof(SDIO_STAT_COUNTER_T)); + + return u4Len; +} + +#if (CFG_SDIO_ACCESS_N9_REGISTER_BY_MAILBOX == 1) +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * This routine is used to get the value of N9 register + * by SDIO SW interrupt and mailbox. + * + * \param[in] + * pvAdapter: Pointer to the Adapter structure. + * addr: the interested address to be read + * prresult: to stored the value of the addr + * + * \return + * the error of the reading operation + */ +/*----------------------------------------------------------------------------*/ + +u8 halReadN9RegisterByMailBox(IN P_ADAPTER_T prAdapter, IN u32 addr, + IN u32 *prresult) +{ + u32 ori_whlpcr, temp, counter = 0; + u8 err = true, stop = false; + + /* use polling mode */ + HAL_MCR_RD(prAdapter, MCR_WHLPCR, &ori_whlpcr); /* backup the original + * setting of W_INT_EN + */ + ori_whlpcr &= WHLPCR_INT_EN_SET; + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_CLR); /* disabel + * interrupt */ + + /* progrqm h2d mailbox0 as interested register address */ + HAL_MCR_WR(prAdapter, MCR_H2DSM0R, addr); + + /* set h2d interrupt to notify firmware (bit16) */ + HAL_MCR_WR(prAdapter, MCR_WSICR, SDIO_MAILBOX_FUNC_READ_REG_IDX); + + /* polling interrupt status for the returned result */ + while (!stop) { + HAL_MCR_RD(prAdapter, MCR_WHISR, &temp); /* read clear mode */ + if (temp & SDIO_MAILBOX_FUNC_READ_REG_IDX) { + /* get the result */ + + /* read d2h mailbox0 for interested register address */ + HAL_MCR_RD(prAdapter, MCR_D2HRM0R, &temp); + if (temp == addr) { + /* read d2h mailbox1 for the value of the + * register */ + HAL_MCR_RD(prAdapter, MCR_D2HRM1R, prresult); + err = false; + } else { + DBGLOG(HAL, + ERROR, + "halReadN9RegisterByMailBox >> interested address is not correct.\n"); + } + stop = true; + } else { + counter++; + + if (counter > 300000) { + DBGLOG(HAL, + ERROR, + "halReadN9RegisterByMailBox >> get response failure.\n"); + ASSERT(0); + break; + } + } + } + + HAL_MCR_WR(prAdapter, MCR_WHLPCR, ori_whlpcr); /* restore the W_INT_EN + */ + + return err; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief + * This routine is used to write the value of N9 register by SDIO SW + * interrupt and mailbox. + * + * \param[in] + * pvAdapter: Pointer to the Adapter structure. + * addr: the interested address to be write + * value: the value to write into the addr + * + * \return + * the error of the write operation + */ +/*----------------------------------------------------------------------------*/ + +u8 halWriteN9RegisterByMailBox(IN P_ADAPTER_T prAdapter, IN u32 addr, + IN u32 value) +{ + u32 ori_whlpcr, temp, counter = 0; + u8 err = true, stop = false; + + /* use polling mode */ + HAL_MCR_RD(prAdapter, MCR_WHLPCR, &ori_whlpcr); /* backup the original + * setting of W_INT_EN + */ + ori_whlpcr &= WHLPCR_INT_EN_SET; + HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_CLR); /* disabel + * interrupt */ + + /* progrqm h2d mailbox0 as interested register address */ + HAL_MCR_WR(prAdapter, MCR_H2DSM0R, addr); + + /* progrqm h2d mailbox1 as the value to write */ + HAL_MCR_WR(prAdapter, MCR_H2DSM1R, value); + + /* set h2d interrupt to notify firmware (bit17) */ + HAL_MCR_WR(prAdapter, MCR_WSICR, SDIO_MAILBOX_FUNC_WRITE_REG_IDX); + + /* polling interrupt status for the returned result */ + while (!stop) { + HAL_MCR_RD(prAdapter, MCR_WHISR, &temp); /* read clear mode */ + + if (temp & SDIO_MAILBOX_FUNC_WRITE_REG_IDX) { + /* get the result */ + + /* read d2h mailbox0 for interested register address */ + HAL_MCR_RD(prAdapter, MCR_D2HRM0R, &temp); + if (temp == addr) { + err = false; + } else { + DBGLOG(HAL, ERROR, + "halWriteN9RegisterByMailBox >> "); + DBGLOG(HAL, ERROR, + "interested address is not correct.\n"); + } + stop = true; + } else { + counter++; + + if (counter > 300000) { + DBGLOG(HAL, + ERROR, + "halWriteN9RegisterByMailBox >> get response failure.\n"); + ASSERT(0); + break; + } + } + } + + HAL_MCR_WR(prAdapter, MCR_WHLPCR, ori_whlpcr); /* restore the W_INT_EN + */ + + return err; +} +#endif + +u8 halIsPendingRx(IN P_ADAPTER_T prAdapter) +{ + return false; +} + +u32 halGetValidCoalescingBufSize(IN P_ADAPTER_T prAdapter) +{ + P_GL_HIF_INFO_T prHifInfo; + u32 u4BufSize; + + struct sdio_func *prSdioFunc; + u32 u4RuntimeMaxBuf; + + prHifInfo = &prAdapter->prGlueInfo->rHifInfo; + + if (HIF_TX_COALESCING_BUFFER_SIZE > HIF_RX_COALESCING_BUFFER_SIZE) { + u4BufSize = HIF_TX_COALESCING_BUFFER_SIZE; + }else{ + u4BufSize = HIF_RX_COALESCING_BUFFER_SIZE; + } + + prSdioFunc = prHifInfo->func; + + /* Check host capability */ + /* 1. Should less than host-max_req_size */ + if (u4BufSize > prSdioFunc->card->host->max_req_size) { + u4BufSize = prSdioFunc->card->host->max_req_size; + } + + /* 2. Should less than runtime-blksize * host-blk_count */ + u4RuntimeMaxBuf = + prSdioFunc->cur_blksize * prSdioFunc->card->host->max_blk_count; + if (u4BufSize > u4RuntimeMaxBuf) { + u4BufSize = u4RuntimeMaxBuf; + } + + DBGLOG(INIT, TRACE, + "\n" + "Final buf : 0x%X\n" + "Default TX buf : 0x%X\n" + "Default RX buf : 0x%X\n" + "Host caps -\n" + "max_req_size : 0x%X\n" + "max_seg_size : 0x%X\n" + "max_segs : 0x%X\n" + "max_blk_size : 0x%X\n" + "max_blk_count : 0x%X\n" + "Runtime -\n" + "cur_blksize : 0x%X\n", + u4BufSize, HIF_TX_COALESCING_BUFFER_SIZE, + HIF_RX_COALESCING_BUFFER_SIZE, + prSdioFunc->card->host->max_req_size, + prSdioFunc->card->host->max_seg_size, + prSdioFunc->card->host->max_segs, + prSdioFunc->card->host->max_blk_size, + prSdioFunc->card->host->max_blk_count, prSdioFunc->cur_blksize); + + return u4BufSize; +} + +WLAN_STATUS halAllocateIOBuffer(IN P_ADAPTER_T prAdapter) +{ + P_GL_HIF_INFO_T prHifInfo; + u8 ucIdx; + P_SDIO_RX_COALESCING_BUF_T prRxBuf; + + prHifInfo = &prAdapter->prGlueInfo->rHifInfo; + + /* 4 <5> Memory for enhanced interrupt response */ +#ifdef CFG_PREALLOC_MEMORY + prHifInfo->prSDIOCtrl = (P_SDIO_CTRL_T)preallocGetMem(MEM_ID_IO_CTRL); +#else + prHifInfo->prSDIOCtrl = (P_SDIO_CTRL_T)kalAllocateIOBuffer( + sizeof(ENHANCE_MODE_DATA_STRUCT_T)); +#endif + if (prHifInfo->prSDIOCtrl == NULL) { + DBGLOG(HAL, ERROR, + "Could not allocate %d bytes for interrupt response.\n", + sizeof(ENHANCE_MODE_DATA_STRUCT_T)); + + return WLAN_STATUS_RESOURCES; + } + + /* Alloc coalescing buffer */ + for (ucIdx = 0; ucIdx < HIF_RX_COALESCING_BUF_COUNT; ucIdx++) { + prRxBuf = &prHifInfo->rRxCoalesingBuf[ucIdx]; + + prRxBuf->u4PktCount = 0; + + prRxBuf->u4BufSize = HIF_RX_COALESCING_BUFFER_SIZE; +#ifdef CFG_PREALLOC_MEMORY + prRxBuf->pvRxCoalescingBuf = preallocGetMem(MEM_ID_RX_DATA); +#else + prRxBuf->pvRxCoalescingBuf = + kalAllocateIOBuffer(prRxBuf->u4BufSize); +#endif + if (!prRxBuf->pvRxCoalescingBuf) { + DBGLOG(HAL, ERROR, "Rx coalescing alloc failed!\n"); + continue; + } + QUEUE_INSERT_TAIL(&prHifInfo->rRxFreeBufQueue, + &prRxBuf->rQueEntry); + } + + return WLAN_STATUS_SUCCESS; +} + +WLAN_STATUS halReleaseIOBuffer(IN P_ADAPTER_T prAdapter) +{ + P_GL_HIF_INFO_T prHifInfo; + u8 ucIdx; + P_SDIO_RX_COALESCING_BUF_T prRxBuf; + + prHifInfo = &prAdapter->prGlueInfo->rHifInfo; + + /* Release coalescing buffer */ + for (ucIdx = 0; ucIdx < HIF_RX_COALESCING_BUF_COUNT; ucIdx++) { + prRxBuf = &prHifInfo->rRxCoalesingBuf[ucIdx]; +#ifndef CFG_PREALLOC_MEMORY + kalReleaseIOBuffer(prRxBuf->pvRxCoalescingBuf, + prRxBuf->u4BufSize); +#endif + prRxBuf->pvRxCoalescingBuf = NULL; + } + + /* 4 <5> Memory for enhanced interrupt response */ + if (prHifInfo->prSDIOCtrl) { +#ifndef CFG_PREALLOC_MEMORY + kalReleaseIOBuffer((void *)prHifInfo->prSDIOCtrl, + sizeof(ENHANCE_MODE_DATA_STRUCT_T)); +#endif + prHifInfo->prSDIOCtrl = (P_SDIO_CTRL_T)NULL; + } + + return WLAN_STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief dump firmware Assert message + * + * \param[in] + * prAdapter + * + * \return + * true + * false + */ +/*----------------------------------------------------------------------------*/ +void halPrintFirmwareAssertInfo(IN P_ADAPTER_T prAdapter) +{ + u32 u4MailBox0, u4MailBox1; + u32 line = 0; + u8 aucAssertFile[7]; + /* u32 u4ChipId; */ + +#if CFG_SDIO_INTR_ENHANCE + u4MailBox0 = prAdapter->prGlueInfo->rHifInfo.prSDIOCtrl->u4RcvMailbox0; + u4MailBox1 = prAdapter->prGlueInfo->rHifInfo.prSDIOCtrl->u4RcvMailbox1; +#else + halGetMailbox(prAdapter, 0, &u4MailBox0); + halGetMailbox(prAdapter, 1, &u4MailBox1); +#endif + + line = u4MailBox0 & 0x0000FFFF; + + u4MailBox0 = ((u4MailBox0 >> 16) & 0x0000FFFF); + + kalMemCopy(&aucAssertFile[0], &u4MailBox0, 2); + kalMemCopy(&aucAssertFile[2], &u4MailBox1, 4); + + aucAssertFile[6] = '\0'; + + LOG_FUNC("[%s][wifi][Firmware] Assert at \"%s\" #%ld\n\n", NIC_NAME, + aucAssertFile, line); +} + +void halPrintMailbox(IN P_ADAPTER_T prAdapter) +{ + u32 u4MailBoxStatus0, u4MailBoxStatus1; + + halGetMailbox(prAdapter, 0, &u4MailBoxStatus0); + halGetMailbox(prAdapter, 1, &u4MailBoxStatus1); + DBGLOG(INIT, INFO, "MailBox Status = 0x%08X, 0x%08X\n", + u4MailBoxStatus0, u4MailBoxStatus1); +} + +void halProcessSoftwareInterrupt(IN P_ADAPTER_T prAdapter) +{ + u32 u4IntrBits; + + ASSERT(prAdapter); + + u4IntrBits = prAdapter->u4IntStatus & BITS(8, 31); + + if ((u4IntrBits & WHISR_D2H_SW_ASSERT_INFO_INT) != 0) { + halPrintFirmwareAssertInfo(prAdapter); + } + + if (u4IntrBits & WHISR_D2H_WKUP_BY_RX_PACKET) { + DBGLOG(RX, INFO, "Wake up by Rx\n"); + } + + if (u4IntrBits & WHISR_D2H_SW_RD_MAILBOX_INT) { + halPrintMailbox(prAdapter); + } + + if (u4IntrBits & SER_SDIO_N9_HOST_STOP_TX_OP) { + halPrintMailbox(prAdapter); + /* Stop HIF Tx operation */ + nicSerStopTx(prAdapter); + } + + if (u4IntrBits & SER_SDIO_N9_HOST_STOP_TX_RX_OP) { + halPrintMailbox(prAdapter); + /* Stop HIF Tx/Rx operation */ + nicSerStopTxRx(prAdapter); + } + + if ((u4IntrBits & ~WHISR_D2H_WKUP_BY_RX_PACKET) != 0) { + DBGLOG(SW4, WARN, "u4IntrBits: 0x%lx\n", u4IntrBits); + } +} + +void halPutMailbox(IN P_ADAPTER_T prAdapter, IN u32 u4MailboxNum, + IN u32 u4Data) +{ + switch (u4MailboxNum) { + case 0: + HAL_MCR_WR(prAdapter, MCR_H2DSM0R, u4Data); + break; + + case 1: + HAL_MCR_WR(prAdapter, MCR_H2DSM1R, u4Data); + break; + + default: + ASSERT(0); + } +} + +void halGetMailbox(IN P_ADAPTER_T prAdapter, IN u32 u4MailboxNum, + OUT u32 *pu4Data) +{ + switch (u4MailboxNum) { + case 0: + HAL_MCR_RD(prAdapter, MCR_D2HRM0R, pu4Data); + break; + + case 1: + HAL_MCR_RD(prAdapter, MCR_D2HRM1R, pu4Data); + break; + + default: + ASSERT(0); + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief process one prRxBuf. If there is not enough free SW_RFB, queue prRxBuf + * back to rRxDeAggQue and schedule work again. + * + * @param prAdapter pointer to the Adapter handler, prRxBuf received buffer + * + * @return True if reschedule otherwise False + */ +/*----------------------------------------------------------------------------*/ +u8 halDeAggRxPktProc(P_ADAPTER_T prAdapter, P_SDIO_RX_COALESCING_BUF_T prRxBuf) +{ + P_GL_HIF_INFO_T prHifInfo; + P_RX_CTRL_T prRxCtrl; + P_SW_RFB_T prSwRfb = (P_SW_RFB_T)NULL; + u8 *pucSrcAddr; + u16 u2PktLength; + u32 i, u4Offset; + u8 fgReschedule = false; + + QUE_T rTempFreeRfbList, rTempRxRfbList; + P_QUE_T prTempFreeRfbList = &rTempFreeRfbList; + P_QUE_T prTempRxRfbList = &rTempRxRfbList; + + KAL_SPIN_LOCK_DECLARATION(); + SDIO_TIME_INTERVAL_DEC(); + + prRxCtrl = &prAdapter->rRxCtrl; + prHifInfo = &prAdapter->prGlueInfo->rHifInfo; + + QUEUE_INITIALIZE(prTempFreeRfbList); + QUEUE_INITIALIZE(prTempRxRfbList); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + if (prRxCtrl->rFreeSwRfbList.u4NumElem < prRxBuf->u4PktCount) { + fgReschedule = true; + } else { + /* Get enough free SW_RFB to be Rx */ + for (i = 0; i < prRxBuf->u4PktCount; i++) { + QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, + P_SW_RFB_T); + QUEUE_INSERT_TAIL(prTempFreeRfbList, + &prSwRfb->rQueEntry); + } + fgReschedule = false; + } + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + + if (fgReschedule) { + mutex_lock(&prHifInfo->rRxDeAggQueMutex); + QUEUE_INSERT_HEAD(&prHifInfo->rRxDeAggQueue, + (P_QUE_ENTRY_T)prRxBuf); + mutex_unlock(&prHifInfo->rRxDeAggQueMutex); + + /* Reschedule this work */ + if ((prAdapter->prGlueInfo->ulFlag & GLUE_FLAG_HALT) == 0) { + schedule_delayed_work( + &prAdapter->prGlueInfo->rRxPktDeAggWork, 0); + } + + return fgReschedule; + } + + pucSrcAddr = prRxBuf->pvRxCoalescingBuf; + u4Offset = 0; + SDIO_REC_TIME_START(); + for (i = 0; i < prRxBuf->u4PktCount; i++) { + u2PktLength = HAL_RX_STATUS_GET_RX_BYTE_CNT( + (P_HW_MAC_RX_DESC_T)pucSrcAddr); + + QUEUE_REMOVE_HEAD(prTempFreeRfbList, prSwRfb, P_SW_RFB_T); + if (ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN) > + CFG_RX_MAX_PKT_SIZE) { + DBGLOG(RX, + ERROR, + "%s: coalescing packet length(%d) too large, will overflow swRfb.\n", + __func__, + u2PktLength); + break; + } + u4Offset += ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN); + if (u4Offset > HIF_RX_COALESCING_BUFFER_SIZE) { + DBGLOG(RX, + ERROR, + "%s: coalescing buffer read: offset(%u), out of bound\n", + __func__, + u4Offset); + break; + } + kalMemCopy(prSwRfb->pucRecvBuff, pucSrcAddr, + ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN)); + + prSwRfb->ucPacketType = + (u8)HAL_RX_STATUS_GET_PKT_TYPE(prSwRfb->prRxStatus); + + QUEUE_INSERT_TAIL(prTempRxRfbList, &prSwRfb->rQueEntry); + + pucSrcAddr += ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN); + } + SDIO_REC_TIME_END(); + SDIO_ADD_TIME_INTERVAL(prHifInfo->rStatCounter.u4RxDataCpTime); + + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + RX_ADD_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT, prTempRxRfbList->u4NumElem); + QUEUE_CONCATENATE_QUEUES(&prRxCtrl->rReceivedRfbList, prTempRxRfbList); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); + + /* Wake up Rx handling thread */ + set_bit(GLUE_FLAG_RX_BIT, &(prAdapter->prGlueInfo->ulFlag)); + wake_up_interruptible(&(prAdapter->prGlueInfo->waitq)); + + if (prTempFreeRfbList->u4NumElem) { + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + QUEUE_CONCATENATE_QUEUES(&prRxCtrl->rFreeSwRfbList, + prTempFreeRfbList); + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); + } + + prRxBuf->u4PktCount = 0; + mutex_lock(&prHifInfo->rRxFreeBufQueMutex); + QUEUE_INSERT_TAIL(&prHifInfo->rRxFreeBufQueue, (P_QUE_ENTRY_T)prRxBuf); + mutex_unlock(&prHifInfo->rRxFreeBufQueMutex); + + return fgReschedule; +} + +void halDeAggRxPktWorker(struct work_struct *work) +{ + P_GLUE_INFO_T prGlueInfo; + P_GL_HIF_INFO_T prHifInfo; + P_ADAPTER_T prAdapter; + P_SDIO_RX_COALESCING_BUF_T prRxBuf; + P_RX_CTRL_T prRxCtrl; + u8 bRescheduled = false; + + if (g_u4HaltFlag) { + return; + } + + prGlueInfo = ENTRY_OF(work, GLUE_INFO_T, rRxPktDeAggWork); + prHifInfo = &prGlueInfo->rHifInfo; + prAdapter = prGlueInfo->prAdapter; + + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + return; + } + + prRxCtrl = &prAdapter->rRxCtrl; + prHifInfo = &prAdapter->prGlueInfo->rHifInfo; + + mutex_lock(&prHifInfo->rRxDeAggQueMutex); + QUEUE_REMOVE_HEAD(&prHifInfo->rRxDeAggQueue, prRxBuf, + P_SDIO_RX_COALESCING_BUF_T); + mutex_unlock(&prHifInfo->rRxDeAggQueMutex); + + while (prRxBuf) { + bRescheduled = halDeAggRxPktProc(prAdapter, prRxBuf); + + if (bRescheduled) { + DBGLOG(RX, WARN, + "halDeAggRxPktProc return rescheduled\n"); + return; + } + + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + return; + } + + mutex_lock(&prHifInfo->rRxDeAggQueMutex); + QUEUE_REMOVE_HEAD(&prHifInfo->rRxDeAggQueue, prRxBuf, + P_SDIO_RX_COALESCING_BUF_T); + mutex_unlock(&prHifInfo->rRxDeAggQueMutex); + } +} + +void halDeAggRxPkt(P_ADAPTER_T prAdapter, P_SDIO_RX_COALESCING_BUF_T prRxBuf) +{ + P_GL_HIF_INFO_T prHifInfo; + prHifInfo = &prAdapter->prGlueInfo->rHifInfo; + + /* Avoid to schedule DeAggWorker during uninit flow */ + if (prAdapter->prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + mutex_lock(&prHifInfo->rRxFreeBufQueMutex); + QUEUE_INSERT_TAIL(&prHifInfo->rRxFreeBufQueue, + (P_QUE_ENTRY_T)prRxBuf); + mutex_unlock(&prHifInfo->rRxFreeBufQueMutex); + + return; + } + +#if CFG_SDIO_RX_AGG_TASKLET + mutex_lock(&prHifInfo->rRxDeAggQueMutex); + QUEUE_INSERT_TAIL(&prHifInfo->rRxDeAggQueue, (P_QUE_ENTRY_T)prRxBuf); + mutex_unlock(&prHifInfo->rRxDeAggQueMutex); + + schedule_delayed_work(&prAdapter->prGlueInfo->rRxPktDeAggWork, 0); +#else + if (QUEUE_IS_NOT_EMPTY(&prHifInfo->rRxDeAggQueue)) { + mutex_lock(&prHifInfo->rRxDeAggQueMutex); + QUEUE_INSERT_TAIL(&prHifInfo->rRxDeAggQueue, + (P_QUE_ENTRY_T)prRxBuf); + QUEUE_REMOVE_HEAD(&prHifInfo->rRxDeAggQueue, prRxBuf, + P_SDIO_RX_COALESCING_BUF_T); + mutex_unlock(&prHifInfo->rRxDeAggQueMutex); + } + + halDeAggRxPktProc(prAdapter, prRxBuf); +#endif +} + +/* Hif power off wifi */ +WLAN_STATUS halHifPowerOffWifi(IN P_ADAPTER_T prAdapter) +{ + WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; + + if (prAdapter->rAcpiState == ACPI_STATE_D0 && + !wlanIsChipNoAck(prAdapter) && + !kalIsCardRemoved(prAdapter->prGlueInfo)) { + /* 0. Disable interrupt, this can be done without Driver own */ + nicDisableInterrupt(prAdapter); + + ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter); + + /* 1. Set CMD to FW to tell WIFI to stop (enter power off state) + */ + if (prAdapter->fgIsFwOwn == false && + wlanSendNicPowerCtrlCmd(prAdapter, 1) == + WLAN_STATUS_SUCCESS) { + u32 i; + /* 2. Clear pending interrupt */ + i = 0; + while (i < CFG_IST_LOOP_COUNT && + nicProcessIST(prAdapter) != + WLAN_STATUS_NOT_INDICATING) + i++; + ; + + /* 3. Wait til RDY bit has been cleaerd */ + rStatus = wlanCheckWifiFunc(prAdapter, false); + } +#if !CFG_ENABLE_FULL_PM + /* 4. Set Onwership to F/W */ + nicpmSetFWOwn(prAdapter, false); +#endif + +#if CFG_FORCE_RESET_UNDER_BUS_ERROR + if (HAL_TEST_FLAG(prAdapter, ADAPTER_FLAG_HW_ERR) == true) { + /* force acquire firmware own */ + kalDevRegWrite(prAdapter->prGlueInfo, MCR_WHLPCR, + WHLPCR_FW_OWN_REQ_CLR); + + /* delay for 10ms */ + kalMdelay(10); + + /* force firmware reset via software interrupt */ + kalDevRegWrite(prAdapter->prGlueInfo, MCR_WSICR, + WSICR_H2D_SW_INT_SET); + + /* force release firmware own */ + kalDevRegWrite(prAdapter->prGlueInfo, MCR_WHLPCR, + WHLPCR_FW_OWN_REQ_SET); + } +#endif + + RECLAIM_POWER_CONTROL_TO_PM(prAdapter, false); + } + return rStatus; +} + +void halPollDbgCr(IN P_ADAPTER_T prAdapter, IN u32 u4LoopCount) +{ + u32 u4Data = 0; + u32 u4Loop = 0; + + for (u4Loop = 0; u4Loop < u4LoopCount; u4Loop++) { + HAL_MCR_RD(prAdapter, MCR_SWPCDBGR, &u4Data); + DBGLOG(INIT, INFO, "SWPCDBGR 0x%08X\n", u4Data); + } +} + +void halSerHifReset(IN P_ADAPTER_T prAdapter) +{ + P_GL_HIF_INFO_T prHifInfo = &prAdapter->prGlueInfo->rHifInfo; + u32 i; + + KAL_SPIN_LOCK_DECLARATION(); + + /* Restore Tx resource */ + KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + for (i = TC0_INDEX; i < TC_NUM; i++) { +#else + for (i = TC0_INDEX; i <= TC5_INDEX; i++) { +#endif + nicTxReleaseResource(prAdapter, i, + prHifInfo->au4PendingTxDoneCount[i], + false); + prHifInfo->au4PendingTxDoneCount[i] = 0; + } + KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); + + /* Clear interrupt status from Rx interrupt enhance mode */ + prHifInfo->fgIsPendingInt = false; + kalMemZero(prHifInfo->prSDIOCtrl, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); +} + +void halPrintHifDbgInfo(IN P_ADAPTER_T prAdapter) +{ + halPrintMailbox(prAdapter); + halPollDbgCr(prAdapter, LP_OWN_BACK_FAILED_DBGCR_POLL_ROUND); +} + +u8 halIsTxResourceControlEn(IN P_ADAPTER_T prAdapter) +{ + return true; +} + +void halTxResourceResetHwTQCounter(IN P_ADAPTER_T prAdapter) +{ + u32 *pu4WHISR = NULL; + u16 au2TxCount[16]; + + pu4WHISR = (u32 *)kalMemAlloc(sizeof(u32), PHY_MEM_TYPE); + if (!pu4WHISR) { + DBGLOG(INIT, ERROR, "Allocate pu4WHISR fail\n"); + return; + } + + HAL_READ_INTR_STATUS(prAdapter, sizeof(u32), (u8 *)pu4WHISR); + if (HAL_IS_TX_DONE_INTR(*pu4WHISR)) { + HAL_READ_TX_RELEASED_COUNT(prAdapter, au2TxCount); + } + + if (pu4WHISR) { + kalMemFree(pu4WHISR, PHY_MEM_TYPE, sizeof(u32)); + } +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_ate_agent.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_ate_agent.h new file mode 100644 index 00000000000000..f7949b7cca7fd0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_ate_agent.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_ate_agent.h + * \brief This file includes private ioctl support. + */ + +#ifndef _GL_ATE_AGENT_H +#define _GL_ATE_AGENT_H +#if CFG_SUPPORT_QA_TOOL +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +extern u32 u4RxStatSeqNum; + +#if CFG_SUPPORT_TX_BF +extern PFMU_PROFILE_TAG1 g_rPfmuTag1; +extern PFMU_PROFILE_TAG2 g_rPfmuTag2; +extern PFMU_DATA g_rPfmuData; +#endif +extern u8 g_bCaptureDone; + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef struct _STA_REC_BF_UPD_ARGUMENT { + u32 u4WlanId; + u32 u4BssId; + u32 u4PfmuId; + u32 u4SuMu; + u32 u4eTxBfCap; + u32 u4NdpaRate; + u32 u4NdpRate; + u32 u4ReptPollRate; + u32 u4TxMode; + u32 u4Nc; + u32 u4Nr; + u32 u4Bw; + u32 u4SpeIdx; + u32 u4TotalMemReq; + u32 u4MemReq20M; + u32 au4MemRow[4]; + u32 au4MemCol[4]; +} STA_REC_BF_UPD_ARGUMENT, *P_STA_REC_BF_UPD_ARGUMENT; + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +int Set_ResetStatCounter_Proc(struct net_device *prNetDev, u8 *prInBuf); +int SetATE(struct net_device *prNetDev, u8 *prInBuf); +int SetATEDa(struct net_device *prNetDev, u8 *prInBuf); +int SetATESa(struct net_device *prNetDev, u8 *prInBuf); +int SetATEChannel(struct net_device *prNetDev, u8 *prInBuf); +int SetATETxPower0(struct net_device *prNetDev, u8 *prInBuf); +int SetATETxGi(struct net_device *prNetDev, u8 *prInBuf); +int SetATETxBw(struct net_device *prNetDev, u8 *prInBuf); +int SetATETxMode(struct net_device *prNetDev, u8 *prInBuf); +int SetATETxLength(struct net_device *prNetDev, u8 *prInBuf); +int SetATETxCount(struct net_device *prNetDev, u8 *prInBuf); +int SetATETxMcs(struct net_device *prNetDev, u8 *prInBuf); +int SetATEIpg(struct net_device *prNetDev, u8 *prInBuf); + +#if CFG_SUPPORT_TX_BF +int Set_TxBfProfileTag_Help(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_InValid(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_PfmuIdx(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_BfType(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_DBW(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_SuMu(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_Mem(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_Matrix(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_SNR(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_SmartAnt(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_SeIdx(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_RmsdThrd(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_McsThrd(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_TimeOut(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_DesiredBW(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_DesiredNc(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTag_DesiredNr(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTagRead(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileTagWrite(struct net_device *prNetDev, u8 *prInBuf); +int Set_StaRecCmmUpdate(struct net_device *prNetDev, u8 *prInBuf); +int Set_StaRecBfUpdate(struct net_device *prNetDev, u8 *prInBuf); + +int Set_DevInfoUpdate(struct net_device *prNetDev, u8 *prInBuf); + +int Set_BssInfoUpdate(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileDataRead(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfileDataWrite(struct net_device *prNetDev, u8 *prInBuf); +int Set_Trigger_Sounding_Proc(struct net_device *prNetDev, u8 *prInBuf); +int Set_Stop_Sounding_Proc(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfTxApply(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfilePnRead(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfProfilePnWrite(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfManualAssoc(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfPfmuMemAlloc(struct net_device *prNetDev, u8 *prInBuf); +int Set_TxBfPfmuMemRelease(struct net_device *prNetDev, u8 *prInBuf); + +#if CFG_SUPPORT_MU_MIMO +int Set_MUGetInitMCS(struct net_device *prNetDev, u8 *prInBuf); +int Set_MUCalInitMCS(struct net_device *prNetDev, u8 *prInBuf); +int Set_MUCalLQ(struct net_device *prNetDev, u8 *prInBuf); +int Set_MUGetLQ(struct net_device *prNetDev, u8 *prInBuf); +int Set_MUSetSNROffset(struct net_device *prNetDev, u8 *prInBuf); +int Set_MUSetZeroNss(struct net_device *prNetDev, u8 *prInBuf); +int Set_MUSetSpeedUpLQ(struct net_device *prNetDev, u8 *prInBuf); +int Set_MUSetMUTable(struct net_device *prNetDev, u8 *prInBuf); +int Set_MUSetGroup(struct net_device *prNetDev, u8 *prInBuf); +int Set_MUGetQD(struct net_device *prNetDev, u8 *prInBuf); +int Set_MUSetEnable(struct net_device *prNetDev, u8 *prInBuf); +int Set_MUSetGID_UP(struct net_device *prNetDev, u8 *prInBuf); +int Set_MUTriggerTx(struct net_device *prNetDev, u8 *prInBuf); +#endif +#endif + +int WriteEfuse(struct net_device *prNetDev, u8 *prInBuf); +int SetTxTargetPower(struct net_device *prNetDev, u8 *prInBuf); + +#if (CFG_SUPPORT_DFS_MASTER == 1) +int SetRddReport(struct net_device *prNetDev, u8 *prInBuf); +int SetByPassCac(struct net_device *prNetDev, u8 *prInBuf); +int SetRadarDetectMode(struct net_device *prNetDev, u8 *prInBuf); +#endif + +int AteCmdSetHandle(struct net_device *prNetDev, u8 *prInBuf, u32 u4InBufLen); +#endif +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_cfg80211.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_cfg80211.h new file mode 100644 index 00000000000000..d5fc3e8c3bb3e2 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_cfg80211.h @@ -0,0 +1,626 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_cfg80211.h + * \brief This file is for Portable Driver linux cfg80211 support. + */ + +#ifndef _GL_CFG80211_H +#define _GL_CFG80211_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include <linux/kernel.h> +#include <linux/netdevice.h> +#include <linux/wireless.h> +#include <linux/ieee80211.h> +#include <net/cfg80211.h> + +#include "gl_os.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#ifdef CONFIG_NL80211_TESTMODE +#define NL80211_DRIVER_TESTMODE_VERSION 2 +#endif + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +#ifdef CONFIG_NL80211_TESTMODE +#if CFG_SUPPORT_NFC_BEAM_PLUS + +typedef struct _NL80211_DRIVER_SET_NFC_PARAMS { + NL80211_DRIVER_TEST_MODE_PARAMS hdr; + u32 NFC_Enable; +} NL80211_DRIVER_SET_NFC_PARAMS, *P_NL80211_DRIVER_SET_NFC_PARAMS; + +#endif + +typedef struct _NL80211_DRIVER_GET_STA_STATISTICS_PARAMS { + NL80211_DRIVER_TEST_MODE_PARAMS hdr; + u32 u4Version; + u32 u4Flag; + u8 aucMacAddr[MAC_ADDR_LEN]; +} NL80211_DRIVER_GET_STA_STATISTICS_PARAMS, +*P_NL80211_DRIVER_GET_STA_STATISTICS_PARAMS; + +typedef enum _ENUM_TESTMODE_STA_STATISTICS_ATTR { + NL80211_TESTMODE_STA_STATISTICS_INVALID = 0, + NL80211_TESTMODE_STA_STATISTICS_VERSION, + NL80211_TESTMODE_STA_STATISTICS_MAC, + NL80211_TESTMODE_STA_STATISTICS_LINK_SCORE, + NL80211_TESTMODE_STA_STATISTICS_FLAG, + + NL80211_TESTMODE_STA_STATISTICS_PER, + NL80211_TESTMODE_STA_STATISTICS_RSSI, + NL80211_TESTMODE_STA_STATISTICS_PHY_MODE, + NL80211_TESTMODE_STA_STATISTICS_TX_RATE, + + NL80211_TESTMODE_STA_STATISTICS_TOTAL_CNT, + NL80211_TESTMODE_STA_STATISTICS_THRESHOLD_CNT, + NL80211_TESTMODE_STA_STATISTICS_AVG_PROCESS_TIME, + + NL80211_TESTMODE_STA_STATISTICS_FAIL_CNT, + NL80211_TESTMODE_STA_STATISTICS_TIMEOUT_CNT, + NL80211_TESTMODE_STA_STATISTICS_AVG_AIR_TIME, + + NL80211_TESTMODE_STA_STATISTICS_TC_EMPTY_CNT_ARRAY, + NL80211_TESTMODE_STA_STATISTICS_TC_QUE_LEN_ARRAY, + + NL80211_TESTMODE_STA_STATISTICS_TC_AVG_QUE_LEN_ARRAY, + NL80211_TESTMODE_STA_STATISTICS_TC_CUR_QUE_LEN_ARRAY, + + NL80211_TESTMODE_STA_STATISTICS_RESERVED_ARRAY, + + NL80211_TESTMODE_STA_STATISTICS_NUM +} ENUM_TESTMODE_STA_STATISTICS_ATTR; +#endif +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/* cfg80211 hooks */ +#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE +int mtk_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, + struct vif_params *params); +#else +int mtk_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); +#endif + +int mtk_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index, + bool pairwise, + const u8 *mac_addr, + struct key_params *params); + +int mtk_cfg80211_get_key(struct wiphy *wiphy, + struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index, + bool pairwise, + const u8 *mac_addr, + void *cookie, + void (*callback)(void *cookie, struct key_params *)); + +int mtk_cfg80211_del_key(struct wiphy *wiphy, + struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index, + bool pairwise, + const u8 *mac_addr); + +int mtk_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index, + bool unicast, + bool multicast); + +int mtk_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *mac, + struct station_info *sinfo); + +int mtk_cfg80211_get_link_statistics(struct wiphy *wiphy, + struct net_device *ndev, + u8 *mac, + struct station_info *sinfo); + +int mtk_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request); +void mtk_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev); + +int mtk_cfg80211_auth(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_auth_request *req); +int mtk_cfg80211_connect(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_connect_params *sme); +int mtk_cfg80211_disconnect(struct wiphy *wiphy, + struct net_device *ndev, + u16 reason_code); +int mtk_cfg80211_deauth(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_deauth_request *req); +int mtk_cfg80211_disassoc(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_disassoc_request *req); + +int mtk_cfg80211_join_ibss(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_ibss_params *params); + +int mtk_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev); + +int mtk_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *ndev, + bool enabled, + int timeout); + +int mtk_cfg80211_set_pmksa(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_pmksa *pmksa); + +int mtk_cfg80211_del_pmksa(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_pmksa *pmksa); + +int mtk_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev); + +int mtk_cfg80211_set_rekey_data(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_gtk_rekey_data *data); + +int mtk_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, + u64 *cookie); + +int mtk_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie); + +int mtk_cfg80211_mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie); + +void mtk_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy, + IN struct wireless_dev *wdev, + IN u16 frame_type, + IN bool reg); + +int mtk_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie); + +#ifdef CONFIG_NL80211_TESTMODE +int mtk_cfg80211_testmode_get_sta_statistics(IN struct wiphy *wiphy, + IN void *data, + IN int len, + IN P_GLUE_INFO_T prGlueInfo); + +int mtk_cfg80211_testmode_get_scan_done(IN struct wiphy *wiphy, + IN void *data, + IN int len, + IN P_GLUE_INFO_T prGlueInfo); + +int mtk_cfg80211_testmode_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + void *data, + int len); + +int mtk_cfg80211_testmode_sw_cmd(IN struct wiphy *wiphy, + IN void *data, + IN int len); + +#if CFG_SUPPORT_NFC_BEAM_PLUS +int mtk_cfg80211_testmode_get_scan_done(IN struct wiphy *wiphy, + IN void *data, + IN int len, + IN P_GLUE_INFO_T prGlueInfo); +#endif +#endif + +int mtk_cfg80211_sched_scan_start(IN struct wiphy *wiphy, + IN struct net_device *ndev, + IN struct cfg80211_sched_scan_request *request); + +int mtk_cfg80211_sched_scan_stop(IN struct wiphy *wiphy, + IN struct net_device *ndev, + IN u64 reqid); + +int mtk_cfg80211_assoc(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_assoc_request *req); + +int mtk_cfg80211_change_station(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *mac, + struct station_parameters *params); + +int mtk_cfg80211_add_station(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *mac, + struct station_parameters *params); + +int mtk_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *ndev, + struct station_del_parameters *params); + +int mtk_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, +#if (CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)) + int link_id, +#endif + u8 action_code, + u8 dialog_token, + u16 status_code, + u32 peer_capability, + bool initiator, + const u8 *buf, + size_t len); + +int mtk_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, + enum nl80211_tdls_operation oper); + +s32 mtk_cfg80211_process_str_cmd(P_GLUE_INFO_T prGlueInfo, u8 *cmd, s32 len); + +void mtk_reg_notify(IN struct wiphy *pWiphy, + IN struct regulatory_request *pRequest); +void cfg80211_regd_set_wiphy(IN struct wiphy *pWiphy); + +void mtk_cfg80211_set_wakeup(struct wiphy *wiphy, bool enabled); + +int mtk_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow); + +int mtk_cfg80211_resume(struct wiphy *wiphy); + +/* cfg80211 wrapper hooks */ +#if CFG_ENABLE_UNIFY_WIPHY + +struct wireless_dev *mtk_cfg_add_iface(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + struct vif_params *params); + +int mtk_cfg_del_iface(struct wiphy *wiphy, + struct wireless_dev *wdev); + +int mtk_cfg_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, + struct vif_params *params); + +#if KERNEL_VERSION(6, 1, 0) <= CFG80211_VERSION_CODE +int mtk_cfg_add_key(struct wiphy *wiphy, + struct net_device *ndev, int link_id, u8 key_index, + bool pairwise, const u8 *mac_addr, + struct key_params *params); +#else +int mtk_cfg_add_key(struct wiphy *wiphy, + struct net_device *ndev, u8 key_index, + bool pairwise, const u8 *mac_addr, + struct key_params *params); +#endif + +#if KERNEL_VERSION(6, 1, 0) <= CFG80211_VERSION_CODE +int mtk_cfg_get_key(struct wiphy *wiphy, + struct net_device *ndev, int link_id, u8 key_index, + bool pairwise, const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, struct key_params *)); +#else +int mtk_cfg_get_key(struct wiphy *wiphy, + struct net_device *ndev, u8 key_index, + bool pairwise, const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, struct key_params *)); +#endif + +#if KERNEL_VERSION(6, 1, 0) <= CFG80211_VERSION_CODE +int mtk_cfg_del_key(struct wiphy *wiphy, + struct net_device *ndev, int link_id, u8 key_index, + bool pairwise, const u8 *mac_addr); +#else +int mtk_cfg_del_key(struct wiphy *wiphy, + struct net_device *ndev, u8 key_index, + bool pairwise, const u8 *mac_addr); +#endif + +#if KERNEL_VERSION(6, 1, 0) <= CFG80211_VERSION_CODE +int mtk_cfg_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, int link_id, + u8 key_index, bool unicast, bool multicast); +#else +int mtk_cfg_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool unicast, bool multicast); +#endif + +#if KERNEL_VERSION(6, 1, 0) <= CFG80211_VERSION_CODE +int mtk_cfg_set_default_mgmt_key(struct wiphy *wiphy, + struct net_device *ndev, int link_id, + u8 key_index); +#else +int mtk_cfg_set_default_mgmt_key(struct wiphy *wiphy, + struct net_device *ndev, u8 key_index); +#endif + +int mtk_cfg_get_station(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *mac, struct station_info *sinfo); + +#if CFG_SUPPORT_TDLS +int mtk_cfg_change_station(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *mac, struct station_parameters *params); + +int mtk_cfg_add_station(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *mac, struct station_parameters *params); + +int mtk_cfg_tdls_oper(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *peer, enum nl80211_tdls_operation oper); + + +int mtk_cfg_tdls_mgmt(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *peer, +#if (CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)) + int link_id, +#endif + u8 action_code, u8 dialog_token, + u16 status_code, + u32 peer_capability, bool initiator, const u8 *buf, + size_t len); + +#endif /* CFG_SUPPORT_TDLS */ + +int mtk_cfg_del_station(struct wiphy *wiphy, + struct net_device *ndev, + struct station_del_parameters *params); + +int mtk_cfg_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request); + +void mtk_cfg_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev); + +int mtk_cfg_sched_scan_start(IN struct wiphy *wiphy, + IN struct net_device *ndev, + IN struct cfg80211_sched_scan_request *request); + +int mtk_cfg_sched_scan_stop(IN struct wiphy *wiphy, + IN struct net_device *ndev, + IN u64 reqid); + +int mtk_cfg_auth(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_auth_request *req); + +int mtk_cfg_connect(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_connect_params *sme); + +int mtk_cfg_disconnect(struct wiphy *wiphy, + struct net_device *ndev, + u16 reason_code); + +int mtk_cfg_join_ibss(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_ibss_params *params); + +int mtk_cfg_leave_ibss(struct wiphy *wiphy, + struct net_device *ndev); + +int mtk_cfg_set_power_mgmt(struct wiphy *wiphy, + struct net_device *ndev, + bool enabled, int timeout); + +int mtk_cfg_set_pmksa(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_pmksa *pmksa); + +int mtk_cfg_del_pmksa(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_pmksa *pmksa); + +int mtk_cfg_flush_pmksa(struct wiphy *wiphy, + struct net_device *ndev); + +#if CONFIG_SUPPORT_GTK_REKEY +int mtk_cfg_set_rekey_data(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_gtk_rekey_data *data); +#endif /* CONFIG_SUPPORT_GTK_REKEY */ + +int mtk_cfg_suspend(struct wiphy *wiphy, + struct cfg80211_wowlan *wow); + +int mtk_cfg_resume(struct wiphy *wiphy); + +int mtk_cfg_assoc(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_assoc_request *req); + +int mtk_cfg_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, + u64 *cookie); + +int mtk_cfg_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, u64 cookie); + +int mtk_cfg_mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie); + +#if KERNEL_VERSION(5, 8, 0) > CFG80211_VERSION_CODE +void mtk_cfg_mgmt_frame_register(struct wiphy *wiphy, + struct wireless_dev *wdev, + u16 frame_type, bool reg); +#else +void mtk_cfg_mgmt_frame_update(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct mgmt_frame_regs *upd); +#endif + +#if (CFG_SUPPORT_DFS_MASTER == 1) +int mtk_cfg_start_radar_detection(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, + unsigned int cac_time_ms +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) + , int link_id +#endif + ); + +int mtk_cfg_channel_switch(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_csa_settings *params); +#endif + +#if (CFG_ENABLE_WIFI_DIRECT_CFG_80211 != 0) +int mtk_cfg_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params); + +int mtk_cfg_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie); + +int mtk_cfg_deauth(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_deauth_request *req); + +int mtk_cfg_disassoc(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_disassoc_request *req); + +int mtk_cfg_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *settings); + +int mtk_cfg_change_beacon(struct wiphy *wiphy, + struct net_device *dev, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0)) + struct cfg80211_beacon_data *info +#else + struct cfg80211_ap_update *info +#endif + ); + +#if KERNEL_VERSION(6, 0, 0) <= CFG80211_VERSION_CODE +int mtk_cfg_stop_ap(struct wiphy *wiphy, + struct net_device *dev, + unsigned int link_id); +#else +int mtk_cfg_stop_ap(struct wiphy *wiphy, + struct net_device *dev); +#endif + +int mtk_cfg_set_wiphy_params(struct wiphy *wiphy, + u32 changed); + +int mtk_cfg_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *dev, +#if KERNEL_VERSION(6, 0, 0) <= CFG80211_VERSION_CODE + unsigned int link_id, +#endif + const u8 *peer, + const struct cfg80211_bitrate_mask *mask); + +int mtk_cfg_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, int mbm); + +int mtk_cfg_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + unsigned int link_id, + int *dbm); + +#endif /* (CFG_ENABLE_WIFI_DIRECT_CFG_80211 != 0) */ +#endif /* CFG_ENABLE_UNIFY_WIPHY */ + +#if CFG_SUPPORT_NFC_BEAM_PLUS +int mtk_cfg80211_testmode_get_scan_done(IN struct wiphy *wiphy, IN void *data, + IN int len, + IN P_GLUE_INFO_T prGlueInfo); +#endif + +enum regd_state regd_state_machine(IN struct regulatory_request *pRequest); +void mtk_apply_custom_regulatory(IN struct wiphy *pWiphy, + IN const struct ieee80211_regdomain *pRegdom); + +u8 mtk_p2p_cfg80211func_channel_sco_switch(IN enum nl80211_channel_type channel_type, IN P_ENUM_CHNL_EXT_T prChnlSco); +u8 mtk_p2p_cfg80211func_channel_format_switch( + IN struct cfg80211_chan_def *channel_def, + IN struct ieee80211_channel *channel, IN P_RF_CHANNEL_INFO_T prRfChnlInfo); + +#if CFG_ENABLE_UNIFY_WIPHY +int mtk_IsP2PNetDevice(P_GLUE_INFO_T prGlueInfo, struct net_device *ndev); +int mtk_init_sta_role(P_ADAPTER_T prAdapter, struct net_device *ndev); +int mtk_uninit_sta_role(P_ADAPTER_T prAdapter, struct net_device *ndev); +int mtk_init_ap_role(P_GLUE_INFO_T prGlueInfo, struct net_device *ndev); +int mtk_uninit_ap_role(P_GLUE_INFO_T prGlueInfo, struct net_device *ndev); +#endif + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_hook_api.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_hook_api.h new file mode 100644 index 00000000000000..97dea344bb004e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_hook_api.h @@ -0,0 +1,287 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_hook_api.h + * \brief This file includes private ioctl support. + */ + +#ifndef _GL_HOOK_API_H +#define _GL_HOOK_API_H +#if CFG_SUPPORT_QA_TOOL +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +s32 MT_ATEStart(struct net_device *prNetDev, u8 *prInBuf); +s32 MT_ICAPStart(struct net_device *prNetDev, u8 *prInBuf); +s32 MT_ATEStop(struct net_device *prNetDev, u8 *prInBuf); +s32 MT_ATEStartTX(struct net_device *prNetDev, u8 *prInBuf); +s32 MT_ATEStopTX(struct net_device *prNetDev, u8 *prInBuf); +s32 MT_ATEStartRX(struct net_device *prNetDev, u8 *prInBuf); +s32 MT_ATEStopRX(struct net_device *prNetDev, u8 *prInBuf); +s32 MT_ATESetChannel(struct net_device *prNetDev, u32 u4SXIdx, u32 u4SetFreq); +s32 MT_ATESetPreamble(struct net_device *prNetDev, u32 u4Mode); +s32 MT_ATESetSystemBW(struct net_device *prNetDev, u32 u4BW); +s32 MT_ATESetTxLength(struct net_device *prNetDev, u32 u4TxLength); +s32 MT_ATESetTxCount(struct net_device *prNetDev, u32 u4TxCount); +s32 MT_ATESetTxIPG(struct net_device *prNetDev, u32 u4TxIPG); +s32 MT_ATESetTxPower0(struct net_device *prNetDev, u32 u4TxPower0); +s32 MT_ATESetPerPacketBW(struct net_device *prNetDev, u32 u4BW); +s32 MT_ATEPrimarySetting(struct net_device *prNetDev, u32 u4PrimaryCh); +s32 MT_ATESetTxGi(struct net_device *prNetDev, u32 u4SetTxGi); +s32 MT_ATESetTxPayLoad(struct net_device *prNetDev, + u32 u4Gen_payload_rule, + u8 ucPayload); +s32 MT_ATESetTxSTBC(struct net_device *prNetDev, u32 u4Stbc); +s32 MT_ATESetTxPath(struct net_device *prNetDev, u32 u4Tx_path); +s32 MT_ATESetTxVhtNss(struct net_device *prNetDev, u32 u4VhtNss); +s32 MT_ATESetRate(struct net_device *prNetDev, u32 u4Rate); +s32 MT_ATESetEncodeMode(struct net_device *prNetDev, u32 u4Ldpc); +s32 MT_ATESetiBFEnable(struct net_device *prNetDev, u32 u4iBF); +s32 MT_ATESeteBFEnable(struct net_device *prNetDev, u32 u4eBF); +s32 MT_ATESetMACAddress(struct net_device *prNetDev, u32 u4Type, u8 ucAddr[]); +s32 MT_ATELogOnOff(struct net_device *prNetDev, + u32 u4Type, + u32 u4On_off, + u32 u4Size); +s32 MT_ATEResetTXRXCounter(struct net_device *prNetDev); +s32 MT_ATESetDBDCBandIndex(struct net_device *prNetDev, u32 u4BandIdx); +s32 MT_ATESetBand(struct net_device *prNetDev, s32 i4Band); +s32 MT_ATESetTxToneType(struct net_device *prNetDev, s32 i4ToneType); +s32 MT_ATESetTxToneBW(struct net_device *prNetDev, s32 i4ToneFreq); +s32 MT_ATESetTxToneDCOffset(struct net_device *prNetDev, + s32 i4DcOffsetI, + s32 i4DcOffsetQ); +s32 MT_ATESetDBDCTxTonePower(struct net_device *prNetDev, + s32 i4AntIndex, + s32 i4RF_Power, + s32 i4Digi_Power); +s32 MT_ATEDBDCTxTone(struct net_device *prNetDev, s32 i4Control); +s32 MT_ATESetMacHeader(struct net_device *prNetDev, + u32 u2FrameCtrl, + u32 u2DurationID, + u32 u4SeqCtrl); +s32 MT_ATE_IRRSetADC(struct net_device *prNetDev, + u32 u4WFIdx, + u32 u4ChFreq, + u32 u4BW, + u32 u4Sx, + u32 u4Band, + u32 u4RunType, + u32 u4FType); +s32 MT_ATE_IRRSetRxGain(struct net_device *prNetDev, + u32 u4PgaLpfg, + u32 u4Lna, + u32 u4Band, + u32 u4WF_inx, + u32 u4Rfdgc); +s32 MT_ATE_IRRSetTTG(struct net_device *prNetDev, + u32 u4TTGPwrIdx, + u32 u4ChFreq, + u32 u4FIToneFreq, + u32 u4Band); +s32 MT_ATE_IRRSetTrunOnTTG(struct net_device *prNetDev, + u32 u4TTGOnOff, + u32 u4Band, + u32 u4WF_inx); +s32 MT_ATE_TMRSetting(struct net_device *prNetDev, + u32 u4Setting, + u32 u4Version, + u32 u4MPThres, + u32 u4MPIter); +s32 MT_ATERDDStart(struct net_device *prNetDev, u8 *prInBuf); +s32 MT_ATERDDStop(struct net_device *prNetDev, u8 *prInBuf); +s32 MT_ATEMPSSetSeqData(struct net_device *prNetDev, + u32 u4TestNum, + u32 *pu4Phy, + u32 u4Band); +s32 MT_ATEMPSSetPayloadLength(struct net_device *prNetDev, + u32 u4TestNum, + u32 *pu4Length, + u32 u4Band); +s32 MT_ATEMPSSetPacketCount(struct net_device *prNetDev, + u32 u4TestNum, + u32 *pu4PktCnt, + u32 u4Band); +s32 MT_ATEMPSSetPowerGain(struct net_device *prNetDev, + u32 u4TestNum, + u32 *pu4PwrGain, + u32 u4Band); +s32 MT_ATEMPSSetNss(struct net_device *prNetDev, + u32 u4TestNum, + u32 *pu4Nss, + u32 u4Band); +s32 MT_ATEMPSSetPerpacketBW(struct net_device *prNetDev, + u32 u4TestNum, + u32 *pu4PerPktBW, + u32 u4Band); + +s32 MT_ATEWriteEfuse(struct net_device *prNetDev, u16 u2Offset, u16 u2Content); +s32 MT_ATESetTxTargetPower(struct net_device *prNetDev, u8 ucTxTargetPower); +#if (CFG_SUPPORT_DFS_MASTER == 1) +s32 MT_ATESetRddReport(struct net_device *prNetDev, u8 ucDbdcIdx); +s32 MT_ATESetRadarDetectMode(struct net_device *prNetDev, u8 ucRadarDetectMode); +#endif + +#if CFG_SUPPORT_TX_BF +s32 TxBfProfileTag_InValid(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, + u8 ucInValid); +s32 TxBfProfileTag_PfmuIdx(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, + u8 ucProfileIdx); +s32 TxBfProfileTag_TxBfType(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, + u8 ucBFType); +s32 TxBfProfileTag_DBW(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, + u8 ucBW); +s32 TxBfProfileTag_SuMu(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, + u8 ucSuMu); +s32 TxBfProfileTag_Mem(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, + u8 *aucMemAddrColIdx, + u8 *aucMemAddrRowIdx); +s32 TxBfProfileTag_Matrix(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, + u8 ucNrow, + u8 ucNcol, + u8 ucNgroup, + u8 ucLM, + u8 ucCodeBook, + u8 ucHtcExist); +s32 TxBfProfileTag_SNR(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, + u8 ucSNR_STS0, + u8 ucSNR_STS1, + u8 ucSNR_STS2, + u8 ucSNR_STS3); +s32 TxBfProfileTag_SmtAnt(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, + u8 ucSmartAnt); +s32 TxBfProfileTag_SeIdx(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, + u8 ucSeIdx); +s32 TxBfProfileTag_RmsdThd(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, + u8 ucRmsdThrd); +s32 TxBfProfileTag_McsThd(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, + u8 *pMCSThLSS, + u8 *pMCSThSSS); +s32 TxBfProfileTag_TimeOut(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, + u8 ucTimeOut); +s32 TxBfProfileTag_DesiredBW(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, + u8 ucDesiredBW); +s32 TxBfProfileTag_DesiredNc(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, + u8 ucDesiredNc); +s32 TxBfProfileTag_DesiredNr(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG2 prPfmuTag2, + u8 ucDesiredNr); +s32 TxBfProfileTagWrite(struct net_device *prNetDev, + P_PFMU_PROFILE_TAG1 prPfmuTag1, + P_PFMU_PROFILE_TAG2 prPfmuTag2, + u8 profileIdx); +s32 TxBfProfileTagRead(struct net_device *prNetDev, u8 PfmuIdx, u8 fgBFer); +s32 TxBfProfileDataRead(struct net_device *prNetDev, + u8 profileIdx, + u8 fgBFer, + u8 subcarrierIdxMsb, + u8 subcarrierIdxLsb); +s32 TxBfProfileDataWrite(struct net_device *prNetDev, + u8 profileIdx, + u16 subcarrierIdx, + u16 au2Phi[6], + u8 aucPsi[6], + u8 aucDSnr[4]); +s32 TxBfProfilePnRead(struct net_device *prNetDev, u8 profileIdx); +s32 TxBfProfilePnWrite(struct net_device *prNetDev, + u8 ucProfileIdx, + u16 u2bw, + u16 au2XSTS[12]); + +s32 TxBfSounding(struct net_device *prNetDev, u8 ucSuMu, /* 0/1/2/3 */ + u8 ucNumSta, /* 00~04 */ + u8 ucSndInterval, /* 00~FF */ + u8 ucWLan0, /* 00~7F */ + u8 ucWLan1, /* 00~7F */ + u8 ucWLan2, /* 00~7F */ + u8 ucWLan3 /* 00~7F */ + ); +s32 TxBfSoundingStop(struct net_device *prNetDev); +s32 TxBfTxApply(struct net_device *prNetDev, + u8 ucWlanId, + u8 fgETxBf, + u8 fgITxBf, + u8 fgMuTxBf); + +s32 TxBfManualAssoc(struct net_device *prNetDev, + u8 aucMac[MAC_ADDR_LEN], + u8 ucType, + u8 ucWtbl, + u8 ucOwnmac, + u8 ucPhyMode, + u8 ucBw, + u8 ucNss, + u8 ucPfmuId, + u8 ucMarate, + u8 ucSpeIdx, + u8 ucRca2, + u8 ucRv); + +s32 TxBfPfmuMemAlloc(struct net_device *prNetDev, u8 ucSuMuMode, u8 ucWlanIdx); + +s32 TxBfPfmuMemRelease(struct net_device *prNetDev, u8 ucWlanId); + +s32 TxBfBssInfoUpdate(struct net_device *prNetDev, u8 ucOwnMacIdx, u8 ucBssIdx, u8 ucBssId[MAC_ADDR_LEN]); + +s32 DevInfoUpdate(struct net_device *prNetDev, + u8 ucOwnMacIdx, + u8 fgBand, + u8 aucMacAddr[MAC_ADDR_LEN]); + +s32 BssInfoUpdate(struct net_device *prNetDev, + u8 u4OwnMacIdx, + u8 u4BssIdx, + u8 u4BssId[MAC_ADDR_LEN]); + +s32 StaRecCmmUpdate(struct net_device *prNetDev, + u8 ucWlanId, + u8 ucBssId, + u8 u4Aid, + u8 aucMacAddr[MAC_ADDR_LEN]); + +s32 StaRecBfUpdate(struct net_device *prNetDev, + STA_REC_BF_UPD_ARGUMENT rStaRecBfUpdArg, + u8 aucMemRow[4], + u8 aucMemCol[4]); +#endif // CFG_SUPPORT_TX_BF +#endif // CFG_SUPPORT_QA_TOOL +#endif // _GL_HOOK_API_H diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_kal.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_kal.h new file mode 100644 index 00000000000000..ec74b66d45fff3 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_kal.h @@ -0,0 +1,1241 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_kal.h + * \brief Declaration of KAL functions - kal*() which is provided by GLUE + * Layer. + * + * Any definitions in this file will be shared among GLUE Layer and internal + * Driver Stack. + */ + +#ifndef _GL_KAL_H +#define _GL_KAL_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "config.h" +#include "gl_typedef.h" +#include "gl_os.h" +#include "gl_wext_priv.h" +#include "link.h" +#include "nic/mac.h" +#include "nic/wlan_def.h" +#include "wlan_lib.h" +#include "wlan_oid.h" + +#include "linux/kallsyms.h" +/*#include <linux/ftrace_event.h>*/ + +#if DBG +extern int allocatedMemSize; +#endif + +extern struct semaphore g_halt_sem; +extern int g_u4HaltFlag; + +extern struct delayed_work sched_workq; +extern struct delayed_work wdev_lock_workq; + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* Define how many concurrent operation networks. */ +#define KAL_BSS_NUM 4 + +#define KAL_AIS_NUM 1 + +#if CFG_DUAL_P2PLIKE_INTERFACE +#define KAL_P2P_NUM 2 +#else +#define KAL_P2P_NUM 1 +#endif + +#define GLUE_FLAG_MAIN_PROCESS \ + (GLUE_FLAG_HALT | GLUE_FLAG_SUB_MOD_MULTICAST | \ + GLUE_FLAG_TX_CMD_DONE | GLUE_FLAG_TXREQ | GLUE_FLAG_TIMEOUT | \ + GLUE_FLAG_FRAME_FILTER | GLUE_FLAG_OID | GLUE_FLAG_RX) + +#define GLUE_FLAG_HIF_PROCESS \ + (GLUE_FLAG_HALT | GLUE_FLAG_INT | GLUE_FLAG_HIF_TX | \ + GLUE_FLAG_HIF_TX_CMD | GLUE_FLAG_HIF_FW_OWN) + +#define GLUE_FLAG_RX_PROCESS (GLUE_FLAG_HALT | GLUE_FLAG_RX_TO_OS) + +#if CFG_SUPPORT_SNIFFER +#define RADIOTAP_FIELD_TSFT BIT(0) +#define RADIOTAP_FIELD_FLAGS BIT(1) +#define RADIOTAP_FIELD_RATE BIT(2) +#define RADIOTAP_FIELD_CHANNEL BIT(3) +#define RADIOTAP_FIELD_ANT_SIGNAL BIT(5) +#define RADIOTAP_FIELD_ANT_NOISE BIT(6) +#define RADIOTAP_FIELD_ANT BIT(11) +#define RADIOTAP_FIELD_MCS BIT(19) +#define RADIOTAP_FIELD_AMPDU BIT(20) +#define RADIOTAP_FIELD_VHT BIT(21) +#define RADIOTAP_FIELD_VENDOR BIT(30) + +#define RADIOTAP_LEN_VHT 48 +#define RADIOTAP_FIELDS_VHT \ + (RADIOTAP_FIELD_TSFT | RADIOTAP_FIELD_FLAGS | RADIOTAP_FIELD_RATE | \ + RADIOTAP_FIELD_CHANNEL | RADIOTAP_FIELD_ANT_SIGNAL | \ + RADIOTAP_FIELD_ANT_NOISE | RADIOTAP_FIELD_ANT | \ + RADIOTAP_FIELD_AMPDU | RADIOTAP_FIELD_VHT | RADIOTAP_FIELD_VENDOR) + +#define RADIOTAP_LEN_HT 36 +#define RADIOTAP_FIELDS_HT \ + (RADIOTAP_FIELD_TSFT | RADIOTAP_FIELD_FLAGS | RADIOTAP_FIELD_RATE | \ + RADIOTAP_FIELD_CHANNEL | RADIOTAP_FIELD_ANT_SIGNAL | \ + RADIOTAP_FIELD_ANT_NOISE | RADIOTAP_FIELD_ANT | RADIOTAP_FIELD_MCS | \ + RADIOTAP_FIELD_AMPDU | RADIOTAP_FIELD_VENDOR) + +#define RADIOTAP_LEN_LEGACY 26 +#define RADIOTAP_FIELDS_LEGACY \ + (RADIOTAP_FIELD_TSFT | RADIOTAP_FIELD_FLAGS | RADIOTAP_FIELD_RATE | \ + RADIOTAP_FIELD_CHANNEL | RADIOTAP_FIELD_ANT_SIGNAL | \ + RADIOTAP_FIELD_ANT_NOISE | RADIOTAP_FIELD_ANT | \ + RADIOTAP_FIELD_VENDOR) +#endif + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef enum _ENUM_SPIN_LOCK_CATEGORY_E { + SPIN_LOCK_FSM = 0, + SPIN_LOCK_TX_PORT_QUE, + SPIN_LOCK_TX_CMD_QUE, + SPIN_LOCK_TX_CMD_DONE_QUE, + SPIN_LOCK_TC_RESOURCE, + SPIN_LOCK_RX_TO_OS_QUE, + SPIN_LOCK_WDEV_LOCK, + + /* FIX ME */ + SPIN_LOCK_RX_QUE, + SPIN_LOCK_RX_FREE_QUE, + SPIN_LOCK_TX_QUE, + SPIN_LOCK_CMD_QUE, + SPIN_LOCK_TX_RESOURCE, + SPIN_LOCK_CMD_RESOURCE, + SPIN_LOCK_QM_TX_QUEUE, + SPIN_LOCK_CMD_PENDING, + SPIN_LOCK_CMD_SEQ_NUM, + SPIN_LOCK_TX_MSDU_INFO_LIST, + SPIN_LOCK_TXING_MGMT_LIST, + SPIN_LOCK_TX_SEQ_NUM, + SPIN_LOCK_TX_COUNT, + SPIN_LOCK_TXS_COUNT, + /* end */ + SPIN_LOCK_TX, + /* TX/RX Direct : BEGIN */ + SPIN_LOCK_TX_DIRECT, + SPIN_LOCK_TX_DESC, + SPIN_LOCK_RX_DIRECT_REORDER, + /* TX/RX Direct : END */ + SPIN_LOCK_IO_REQ, + SPIN_LOCK_INT, + + SPIN_LOCK_MGT_BUF, + SPIN_LOCK_MSG_BUF, + SPIN_LOCK_STA_REC, + + SPIN_LOCK_MAILBOX, + SPIN_LOCK_TIMER, + + SPIN_LOCK_BOW_TABLE, + + SPIN_LOCK_EHPI_BUS, /* only for EHPI */ + SPIN_LOCK_NET_DEV, + SPIN_LOCK_CHIP_RST, +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK + SPIN_LOCK_TX_LB_QUE, + SPIN_LOCK_RX_LB_QUE, +#endif + SPIN_LOCK_NUM +} ENUM_SPIN_LOCK_CATEGORY_E; + +typedef enum _ENUM_MUTEX_CATEGORY_E { + MUTEX_TX_CMD_CLEAR, + MUTEX_TX_DATA_DONE_QUE, + MUTEX_DEL_INF, + MUTEX_DEL_P2P_VIF, + MUTEX_NUM +} ENUM_MUTEX_CATEGORY_E; + +/* event for assoc information update */ +typedef struct _EVENT_ASSOC_INFO { + u8 ucAssocReq; /* 1 for assoc req, 0 for assoc rsp */ + u8 ucReassoc; /* 0 for assoc, 1 for reassoc */ + u16 u2Length; + u8 *pucIe; +} EVENT_ASSOC_INFO, *P_EVENT_ASSOC_INFO; + +typedef enum _ENUM_KAL_NETWORK_TYPE_INDEX_T { + KAL_NETWORK_TYPE_AIS_INDEX = 0, +#if CFG_ENABLE_WIFI_DIRECT + KAL_NETWORK_TYPE_P2P_INDEX, +#endif + + KAL_NETWORK_TYPE_INDEX_NUM +} ENUM_KAL_NETWORK_TYPE_INDEX_T; + +typedef enum _ENUM_KAL_MEM_ALLOCATION_TYPE_E { + PHY_MEM_TYPE, /* physically continuous */ + VIR_MEM_TYPE, /* virtually continuous */ + MEM_TYPE_NUM +} ENUM_KAL_MEM_ALLOCATION_TYPE; + +typedef enum _ENUM_MTK_AGPS_ATTR { + MTK_ATTR_AGPS_INVALID, + MTK_ATTR_AGPS_CMD, + MTK_ATTR_AGPS_DATA, + MTK_ATTR_AGPS_IFINDEX, + MTK_ATTR_AGPS_IFNAME, + MTK_ATTR_AGPS_MAX +} ENUM_MTK_CCX_ATTR; + +typedef enum _ENUM_AGPS_EVENT { + AGPS_EVENT_WLAN_ON, + AGPS_EVENT_WLAN_OFF, + AGPS_EVENT_WLAN_AP_LIST, +} ENUM_CCX_EVENT; +u8 kalIndicateAgpsNotify(P_ADAPTER_T prAdapter, u8 cmd, u8 *data, u16 dataLen); + +#if CFG_SUPPORT_SNIFFER +/* Vendor Namespace + * Bit Number 30 + * Required Alignment 2 bytes + */ +typedef struct _RADIOTAP_FIELD_VENDOR_T { + u8 aucOUI[3]; + u8 ucSubNamespace; + u16 u2DataLen; + u8 ucData; +} __packed RADIOTAP_FIELD_VENDOR_T, *P_RADIOTAP_FIELD_VENDOR_T; + +typedef struct _MONITOR_RADIOTAP_T { + /* radiotap header */ + u8 ucItVersion; /* set to 0 */ + u8 ucItPad; + u16 u2ItLen; /* entire length */ + u32 u4ItPresent; /* fields present */ + + /* TSFT + * Bit Number 0 + * Required Alignment 8 bytes + * Unit microseconds + */ + u64 u8MacTime; + + /* Flags + * Bit Number 1 + */ + u8 ucFlags; + + /* Rate + * Bit Number 2 + * Unit 500 Kbps + */ + u8 ucRate; + + /* Channel + * Bit Number 3 + * Required Alignment 2 bytes + */ + u16 u2ChFrequency; + u16 u2ChFlags; + + /* Antenna signal + * Bit Number 5 + * Unit dBm + */ + u8 ucAntennaSignal; + + /* Antenna noise + * Bit Number 6 + * Unit dBm + */ + u8 ucAntennaNoise; + + /* Antenna + * Bit Number 11 + * Unit antenna index + */ + u8 ucAntenna; + + /* MCS + * Bit Number 19 + * Required Alignment 1 byte + */ + u8 ucMcsKnown; + u8 ucMcsFlags; + u8 ucMcsMcs; + + /* A-MPDU status + * Bit Number 20 + * Required Alignment 4 bytes + */ + u32 u4AmpduRefNum; + u16 u2AmpduFlags; + u8 ucAmpduDelimiterCRC; + u8 ucAmpduReserved; + + /* VHT + * Bit Number 21 + * Required Alignment 2 bytes + */ + u16 u2VhtKnown; + u8 ucVhtFlags; + u8 ucVhtBandwidth; + u8 aucVhtMcsNss[4]; + u8 ucVhtCoding; + u8 ucVhtGroupId; + u16 u2VhtPartialAid; + + /* extension space */ + u8 aucReserve[12]; +} __packed MONITOR_RADIOTAP_T, *P_MONITOR_RADIOTAP_T; +#endif + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Macros of getting current thread id */ +/*----------------------------------------------------------------------------*/ +#define KAL_GET_CURRENT_THREAD_ID() (current->pid) +#define KAL_GET_CURRENT_THREAD_NAME() (current->comm) + +/*----------------------------------------------------------------------------*/ +/* Macros of SPIN LOCK operations for using in Driver Layer */ +/*----------------------------------------------------------------------------*/ +#define KAL_SPIN_LOCK_DECLARATION() unsigned long __ulFlags + +#define KAL_ACQUIRE_SPIN_LOCK(_prAdapter, _rLockCategory) \ + kalAcquireSpinLock(((P_ADAPTER_T)_prAdapter)->prGlueInfo, \ + _rLockCategory, &__ulFlags) + +#define KAL_RELEASE_SPIN_LOCK(_prAdapter, _rLockCategory) \ + kalReleaseSpinLock(((P_ADAPTER_T)_prAdapter)->prGlueInfo, \ + _rLockCategory, __ulFlags) + +/*----------------------------------------------------------------------------*/ +/* Macros of MUTEX operations for using in Driver Layer */ +/*----------------------------------------------------------------------------*/ +#define KAL_ACQUIRE_MUTEX(_prAdapter, _rLockCategory) \ + kalAcquireMutex(((P_ADAPTER_T)_prAdapter)->prGlueInfo, _rLockCategory) + +#define KAL_RELEASE_MUTEX(_prAdapter, _rLockCategory) \ + kalReleaseMutex(((P_ADAPTER_T)_prAdapter)->prGlueInfo, _rLockCategory) + +/*----------------------------------------------------------------------------*/ +/* Macros for accessing Reserved Fields of native packet */ +/*----------------------------------------------------------------------------*/ +#define KAL_GET_PKT_QUEUE_ENTRY(_p) GLUE_GET_PKT_QUEUE_ENTRY(_p) +#define KAL_GET_PKT_DESCRIPTOR(_prQueueEntry) \ + GLUE_GET_PKT_DESCRIPTOR(_prQueueEntry) +#define KAL_GET_PKT_TID(_p) GLUE_GET_PKT_TID(_p) +#define KAL_GET_PKT_IS1X(_p) GLUE_GET_PKT_IS1X(_p) +#define KAL_GET_PKT_HEADER_LEN(_p) GLUE_GET_PKT_HEADER_LEN(_p) +#define KAL_GET_PKT_PAYLOAD_LEN(_p) GLUE_GET_PKT_PAYLOAD_LEN(_p) +#define KAL_GET_PKT_ARRIVAL_TIME(_p) GLUE_GET_PKT_ARRIVAL_TIME(_p) + +/*----------------------------------------------------------------------------*/ +/* Macros for kernel related defines */ +/*----------------------------------------------------------------------------*/ + +/** + * kalCfg80211ToMtkBand - Band translation helper + * + * @band: cfg80211_band + * + * Translates cfg80211 band into internal band definition + */ +#if CFG_SCAN_CHANNEL_SPECIFIED +#define kalCfg80211ToMtkBand(cfg80211_band) \ + (cfg80211_band == NL80211_BAND_2GHZ ? BAND_2G4 : \ + cfg80211_band == NL80211_BAND_5GHZ ? BAND_5G : \ + BAND_NULL) +#endif + +/** + * kalCfg80211ScanDone - abstraction of cfg80211_scan_done + * + * @request: the corresponding scan request (sanity checked by callers!) + * @aborted: set to true if the scan was aborted for any reason, + * userspace will be notified of that + * + * Since linux-4.8.y the 2nd parameter is changed from bool to + * struct cfg80211_scan_info, but we don't use all fields yet. + */ +static inline void kalCfg80211ScanDone(struct cfg80211_scan_request *request, + bool aborted) +{ + struct cfg80211_scan_info info = { .aborted = aborted }; + cfg80211_scan_done(request, &info); +} + +/* Consider on some Android platform, using request_firmware_direct() + * may cause system failed to load firmware. So we still use + * request_firmware(). + */ +#define REQUEST_FIRMWARE(_fw, _name, _dev) request_firmware(_fw, _name, _dev) + +#define RELEASE_FIRMWARE(_fw) \ + do { \ + release_firmware(_fw); \ + _fw = NULL; \ + } while (0) + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Cache memory allocation + * + * \param[in] u4Size Required memory size. + * \param[in] eMemType Memory allocation type + * + * \return Pointer to allocated memory + * or NULL + */ +/*----------------------------------------------------------------------------*/ +#if DBG +#define kalMemAlloc(u4Size, eMemType) \ + ({ \ + void *pvAddr; \ + if (eMemType == PHY_MEM_TYPE) { \ + if (in_interrupt()) \ + pvAddr = kmalloc(u4Size, GFP_ATOMIC); \ + else \ + pvAddr = kmalloc(u4Size, GFP_KERNEL); \ + } else { \ + pvAddr = vmalloc(u4Size); \ + } \ + if (pvAddr) { \ + allocatedMemSize += u4Size; \ + DBGLOG(INIT, INFO, "0x%p(%ld) allocated (%s:%s)\n", \ + pvAddr, (u32)u4Size, __FILE__, __func__); \ + } \ + pvAddr; \ + }) +#else +#define kalMemAlloc(u4Size, eMemType) \ + ({ \ + void *pvAddr; \ + if (eMemType == PHY_MEM_TYPE) { \ + if (in_interrupt()) \ + pvAddr = kmalloc(u4Size, GFP_ATOMIC); \ + else \ + pvAddr = kmalloc(u4Size, GFP_KERNEL); \ + } else { \ + pvAddr = vmalloc(u4Size); \ + } \ + pvAddr; \ + }) +#endif + +#define kalMemZAlloc(u4size, eMemType) \ + ({ \ + void *pvAddr; \ + pvAddr = kalMemAlloc(u4size, eMemType); \ + if (pvAddr) \ + kalMemSet(pvAddr, 0, u4size); \ + pvAddr; \ + }) + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Free allocated cache memory + * + * \param[in] pvAddr Required memory size. + * \param[in] eMemType Memory allocation type + * \param[in] u4Size Allocated memory size. + * + * \return - + */ +/*----------------------------------------------------------------------------*/ +#if DBG +#define kalMemFree(pvAddr, eMemType, u4Size) \ + { \ + if (pvAddr) { \ + allocatedMemSize -= u4Size; \ + DBGLOG(INIT, INFO, "0x%p(%ld) freed (%s:%s)\n", \ + pvAddr, (u32)u4Size, __FILE__, __func__); \ + } \ + if (eMemType == PHY_MEM_TYPE) { \ + kfree(pvAddr); \ + } else { \ + vfree(pvAddr); \ + } \ + } +#else +#define kalMemFree(pvAddr, eMemType, u4Size) \ + { \ + if (eMemType == PHY_MEM_TYPE) { \ + kfree(pvAddr); \ + } else { \ + vfree(pvAddr); \ + } \ + } +#endif + +#define kalUdelay(u4USec) udelay(u4USec) + +#define kalMdelay(u4MSec) mdelay(u4MSec) +#define kalMsleep(u4MSec) msleep(u4MSec) + +/* Copy memory from user space to kernel space */ +#define kalMemCopyFromUser(_pvTo, _pvFrom, _u4N) \ + copy_from_user(_pvTo, _pvFrom, _u4N) + +/* Copy memory from kernel space to user space */ +#define kalMemCopyToUser(_pvTo, _pvFrom, _u4N) \ + copy_to_user(_pvTo, _pvFrom, _u4N) + +/* Copy memory block with specific size */ +#define kalMemCopy(pvDst, pvSrc, u4Size) memcpy(pvDst, pvSrc, u4Size) + +/* Set memory block with specific pattern */ +#define kalMemSet(pvAddr, ucPattern, u4Size) memset(pvAddr, ucPattern, \ + u4Size) + +/* Compare two memory block with specific length. + * Return zero if they are the same. + */ +#define kalMemCmp(pvAddr1, pvAddr2, u4Size) memcmp(pvAddr1, pvAddr2, u4Size) + +/* Zero specific memory block */ +#define kalMemZero(pvAddr, u4Size) memset(pvAddr, 0, u4Size) + +/* Move memory block with specific size */ +#define kalMemMove(pvDst, pvSrc, u4Size) memmove(pvDst, pvSrc, u4Size) + +#define strnicmp(s1, s2, n) strncasecmp(s1, s2, n) + +/* string operation */ +#define kalStrCpy(dest, src) strcpy(dest, src) +#define kalStrnCpy(dest, src, n) strncpy(dest, src, n) +#define kalStrCmp(ct, cs) strcmp(ct, cs) +#define kalStrnCmp(ct, cs, n) strncmp(ct, cs, n) +#define kalStrChr(s, c) strchr(s, c) +#define kalStrrChr(s, c) strrchr(s, c) +#define kalStrnChr(s, n, c) strnchr(s, n, c) +#define kalStrLen(s) strlen(s) +#define kalStrnLen(s, b) strnlen(s, b) + +#define kalkStrtou8(cp, base, resp) kstrtou8(cp, base, resp) +#define kalkStrtou16(cp, base, resp) kstrtou16(cp, base, resp) +#define kalkStrtou32(cp, base, resp) kstrtou32(cp, base, resp) +#define kalkStrtos32(cp, base, resp) kstrtos32(cp, base, resp) +#define kalSnprintf(buf, size, fmt, ...) snprintf(buf, \ + size, \ + fmt, \ + ## __VA_ARGS__) +#define kalScnprintf(buf, size, fmt, ...) \ + scnprintf(buf, size, fmt, ## __VA_ARGS__) +#define kalSprintf(buf, fmt, ...) sprintf(buf, fmt, __VA_ARGS__) + +#define kalStrStr(ct, cs) strstr(ct, cs) +#define kalStrSep(s, ct) strsep(s, ct) +#define kalStrCat(dest, src) strcat(dest, src) +#define kalIsXdigit(c) isxdigit(c) + +/* defined for wince sdio driver only */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Notify OS with SendComplete event of the specific packet. Linux should + * free packets here. + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * \param[in] pvPacket Pointer of Packet Handle + * \param[in] status Status Code for OS upper layer + * + * \return - + */ +/*----------------------------------------------------------------------------*/ +#define kalSendComplete(prGlueInfo, pvPacket, status) \ + kalSendCompleteAndAwakeQueue(prGlueInfo, pvPacket) + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is used to locate the starting address of incoming + * ethernet frame for skb. + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * \param[in] pvPacket Pointer of Packet Handle + * + * \return starting address of ethernet frame buffer. + */ +/*----------------------------------------------------------------------------*/ +#define kalQueryBufferPointer(prGlueInfo, pvPacket) \ + ((u8 *)((struct sk_buff *)pvPacket)->data) + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is used to query the length of valid buffer which is + * accessible during port read/write. + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * \param[in] pvPacket Pointer of Packet Handle + * + * \return starting address of ethernet frame buffer. + */ +/*----------------------------------------------------------------------------*/ +#define kalQueryValidBufferLength(prGlueInfo, pvPacket) \ + ((u32)((struct sk_buff *)pvPacket)->end - \ + (u32)((struct sk_buff *)pvPacket)->data) + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is used to copy the entire frame from skb to the + * destination address in the input parameter. + * + * \param[in] prGlueInfo Pointer of GLUE Data Structure + * \param[in] pvPacket Pointer of Packet Handle + * \param[in] pucDestBuffer Destination Address + * + * \return - + */ +/*----------------------------------------------------------------------------*/ +#define kalCopyFrame(prGlueInfo, pvPacket, pucDestBuffer) \ + do { \ + struct sk_buff *skb = (struct sk_buff *)pvPacket; \ + memcpy(pucDestBuffer, skb->data, skb->len); \ + } while (0) + +#define kalGetTimeTick() jiffies_to_msecs(jiffies) + +#define WLAN_TAG "[wlan]" +#define kalPrint(_Fmt ...) printk(WLAN_TAG _Fmt) + +extern int __printk_ratelimit(const char *func); +#define printk_ratelimit() __printk_ratelimit(__func__) +#define kalPrintRateCtrl() printk_ratelimit() + +#define kalBreakPoint() \ + do { \ + WARN_ON(1); \ + panic("Oops"); \ + } while (0) + +#define PRINTF_ARG(...) __VA_ARGS__ +#define SPRINTF(buf, arg) \ + { \ + buf += sprintf((char *)(buf), PRINTF_ARG arg); \ + } + +#define USEC_TO_SYSTIME(_usec) ((_usec) / USEC_PER_MSEC) +#define MSEC_TO_SYSTIME(_msec) (_msec) + +#define MSEC_TO_JIFFIES(_msec) msecs_to_jiffies(_msec) + +#define KAL_TIME_INTERVAL_DECLARATION() struct timeval __rTs, __rTe +#define KAL_REC_TIME_START() do_gettimeofday(&__rTs) +#define KAL_REC_TIME_END() do_gettimeofday(&__rTe) +#define KAL_GET_TIME_INTERVAL() \ + ((SEC_TO_USEC(__rTe.tv_sec) + __rTe.tv_usec) - \ + (SEC_TO_USEC(__rTs.tv_sec) + __rTs.tv_usec)) +#define KAL_ADD_TIME_INTERVAL(_Interval) \ + { \ + (_Interval) += KAL_GET_TIME_INTERVAL(); \ + } + +#define KAL_GET_HOST_CLOCK() local_clock() + +/*----------------------------------------------------------------------------*/ +/* Macros of wiphy operations for using in Driver Layer */ +/*----------------------------------------------------------------------------*/ +#define WIPHY_PRIV(_wiphy, _priv) \ + (_priv = *((P_GLUE_INFO_T *)wiphy_priv(_wiphy))) + +/*----------------------------------------------------------------------------*/ +/* Macros of show stack operations for using in Driver Layer */ +/*----------------------------------------------------------------------------*/ +#define kal_show_stack(_adapter, _task, _sp) \ + { \ + if (_adapter->chip_info->showTaskStack) { \ + _adapter->chip_info->showTaskStack(_task, _sp); \ + } \ + } + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Routines in gl_kal.c */ +/*----------------------------------------------------------------------------*/ +void kalAcquireSpinLock(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, + OUT unsigned long *plFlags); + +void kalReleaseSpinLock(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_SPIN_LOCK_CATEGORY_E rLockCategory, + IN unsigned long ulFlags); + +void kalUpdateMACAddress(IN P_GLUE_INFO_T prGlueInfo, IN u8 *pucMacAddr); + +void kalAcquireMutex(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_MUTEX_CATEGORY_E rMutexCategory); + +void kalReleaseMutex(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_MUTEX_CATEGORY_E rMutexCategory); + +void kalAcquireWDevMutex(IN struct net_device *pDev); +void kalReleaseWDevMutex(IN struct net_device *pDev); + +void kalPacketFree(IN P_GLUE_INFO_T prGlueInfo, IN void *pvPacket); + +void *kalPacketAlloc(IN P_GLUE_INFO_T prGlueInfo, + IN u32 u4Size, + OUT u8 **ppucData); + +void kalOsTimerInitialize(IN P_GLUE_INFO_T prGlueInfo, IN void *prTimerHandler); + +u8 kalSetTimer(IN P_GLUE_INFO_T prGlueInfo, IN u32 rInterval); + +WLAN_STATUS +kalProcessRxPacket(IN P_GLUE_INFO_T prGlueInfo, + IN void *pvPacket, + IN u8 *pucPacketStart, + IN u32 u4PacketLen, + IN ENUM_CSUM_RESULT_T aeCSUM[]); + +WLAN_STATUS kalRxIndicatePkts(IN P_GLUE_INFO_T prGlueInfo, + IN void *apvPkts[], + IN u8 ucPktNum); + +WLAN_STATUS kalRxIndicateOnePkt(IN P_GLUE_INFO_T prGlueInfo, IN void *pvPkt); + +void kalIndicateStatusAndComplete(IN P_GLUE_INFO_T prGlueInfo, + IN WLAN_STATUS eStatus, + IN void *pvBuf, + IN u32 u4BufLen); + +void kalUpdateReAssocReqInfo(IN P_GLUE_INFO_T prGlueInfo, + IN u8 *pucFrameBody, + IN u32 u4FrameBodyLen, + IN u8 fgReassocRequest); + +void kalUpdateReAssocRspInfo(IN P_GLUE_INFO_T prGlueInfo, + IN u8 *pucFrameBody, + IN u32 u4FrameBodyLen); + +#if CFG_TX_FRAGMENT +u8 kalQueryTxPacketHeader(IN P_GLUE_INFO_T prGlueInfo, + IN void *pvPacket, + OUT u16 *pu2EtherTypeLen, + OUT u8 *pucEthDestAddr); +#endif + +void kalSendCompleteAndAwakeQueue(IN P_GLUE_INFO_T prGlueInfo, + IN void *pvPacket); + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +void kalQueryTxChksumOffloadParam(IN void *pvPacket, OUT u8 *pucFlag); + +void kalUpdateRxCSUMOffloadParam(IN void *pvPacket, + IN ENUM_CSUM_RESULT_T eCSUM[]); +#endif + +u8 kalRetrieveNetworkAddress(IN P_GLUE_INFO_T prGlueInfo, + IN OUT PARAM_MAC_ADDRESS *prMacAddr); + +void kalReadyOnChannel(IN P_GLUE_INFO_T prGlueInfo, + IN u64 u8Cookie, + IN ENUM_BAND_T eBand, + IN ENUM_CHNL_EXT_T eSco, + IN u8 ucChannelNum, + IN u32 u4DurationMs); + +void kalRemainOnChannelExpired(IN P_GLUE_INFO_T prGlueInfo, + IN u64 u8Cookie, + IN ENUM_BAND_T eBand, + IN ENUM_CHNL_EXT_T eSco, + IN u8 ucChannelNum); + +#if CFG_SUPPORT_DFS +void kalIndicateChannelSwitch(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_CHNL_EXT_T eSco, + IN u8 ucChannelNum); +#endif + +void kalIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, + IN u64 u8Cookie, + IN u8 fgIsAck, + IN u8 *pucFrameBuf, + IN u32 u4FrameLen); + +void kalIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, IN P_SW_RFB_T prSwRfb); + +/*----------------------------------------------------------------------------*/ +/* Routines in interface - ehpi/sdio.c */ +/*----------------------------------------------------------------------------*/ +u8 kalDevRegRead(IN P_GLUE_INFO_T prGlueInfo, + IN u32 u4Register, + OUT u32 *pu4Value); +u8 kalDevRegRead_mac(IN P_GLUE_INFO_T prGlueInfo, + IN u32 u4Register, + OUT u32 *pu4Value); + +u8 kalDevRegWrite(P_GLUE_INFO_T prGlueInfo, IN u32 u4Register, IN u32 u4Value); +u8 kalDevRegWrite_mac(P_GLUE_INFO_T prGlueInfo, IN u32 u4Register, + IN u32 u4Value); + +u8 kalDevPortRead(IN P_GLUE_INFO_T prGlueInfo, + IN u16 u2Port, + IN u32 u2Len, + OUT u8 *pucBuf, + IN u32 u2ValidOutBufSize); + +u8 kalDevPortWrite(P_GLUE_INFO_T prGlueInfo, + IN u16 u2Port, + IN u32 u2Len, + IN u8 *pucBuf, + IN u32 u2ValidInBufSize); + +u8 kalDevWriteData(IN P_GLUE_INFO_T prGlueInfo, IN P_MSDU_INFO_T prMsduInfo); +#if CFG_MESON_G12A_PATCH +WLAN_STATUS kalDevWriteCmd(IN P_GLUE_INFO_T prGlueInfo, + IN P_CMD_INFO_T prCmdInfo, + IN u8 ucTC); +#else +u8 kalDevWriteCmd(IN P_GLUE_INFO_T prGlueInfo, + IN P_CMD_INFO_T prCmdInfo, + IN u8 ucTC); +#endif +u8 kalDevKickData(IN P_GLUE_INFO_T prGlueInfo); +void kalDevReadIntStatus(IN P_ADAPTER_T prAdapter, OUT u32 *pu4IntStatus); + +u8 kalDevWriteWithSdioCmd52(IN P_GLUE_INFO_T prGlueInfo, + IN u32 u4Addr, + IN u8 ucData); + +#if CFG_SUPPORT_EXT_CONFIG +u32 kalReadExtCfg(IN P_GLUE_INFO_T prGlueInfo); +#endif + +u8 kalQoSFrameClassifierAndPacketInfo(IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket, + OUT P_TX_PACKET_INFO prTxPktInfo); + +u8 kalGetEthDestAddr(IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket, + OUT u8 *pucEthDestAddr); + +void kalOidComplete(IN P_GLUE_INFO_T prGlueInfo, + IN u8 fgSetQuery, + IN u32 u4SetQueryInfoLen, + IN WLAN_STATUS rOidStatus); + +WLAN_STATUS +kalIoctl(IN P_GLUE_INFO_T prGlueInfo, + IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN void *pvInfoBuf, + IN u32 u4InfoBufLen, + IN u8 fgRead, + IN u8 fgWaitResp, + IN u8 fgCmd, + OUT u32 *pu4QryInfoLen); + +WLAN_STATUS +kalIoctlTimeout(IN P_GLUE_INFO_T prGlueInfo, + IN PFN_OID_HANDLER_FUNC pfnOidHandler, + IN void *pvInfoBuf, + IN u32 u4InfoBufLen, + IN u8 fgRead, + IN u8 fgWaitResp, + IN u8 fgCmd, + IN s32 i4OidTimeout, + OUT u32 *pu4QryInfoLen); + +void kalHandleAssocInfo(IN P_GLUE_INFO_T prGlueInfo, + IN P_EVENT_ASSOC_INFO prAssocInfo); + +#if CFG_ENABLE_FW_DOWNLOAD +WLAN_STATUS kalFirmwareOpen(IN P_GLUE_INFO_T prGlueInfo, IN u8 **apucNameTable); +WLAN_STATUS kalFirmwareClose(IN P_GLUE_INFO_T prGlueInfo); +WLAN_STATUS kalFirmwareLoad(IN P_GLUE_INFO_T prGlueInfo, + OUT void *prBuf, + IN u32 u4Offset, + OUT u32 *pu4Size); +WLAN_STATUS kalFirmwareSize(IN P_GLUE_INFO_T prGlueInfo, OUT u32 *pu4Size); +void kalConstructDefaultFirmwarePrio(P_GLUE_INFO_T prGlueInfo, + u8 **apucNameTable, + u8 **apucName, + u8 *pucNameIdx, + u8 ucMaxNameIdx); +void *kalFirmwareImageMapping(IN P_GLUE_INFO_T prGlueInfo, + OUT void **ppvMapFileBuf, + OUT u32 *pu4FileLength, + IN ENUM_IMG_DL_IDX_T eDlIdx); +void kalFirmwareImageUnmapping(IN P_GLUE_INFO_T prGlueInfo, + IN void *prFwHandle, + IN void *pvMapFileBuf); +#endif + +/*----------------------------------------------------------------------------*/ +/* Card Removal Check */ +/*----------------------------------------------------------------------------*/ +u8 kalIsCardRemoved(IN P_GLUE_INFO_T prGlueInfo); + +/*----------------------------------------------------------------------------*/ +/* TX */ +/*----------------------------------------------------------------------------*/ +void kalFlushPendingTxPackets(IN P_GLUE_INFO_T prGlueInfo); + +/*----------------------------------------------------------------------------*/ +/* Media State Indication */ +/*----------------------------------------------------------------------------*/ +ENUM_PARAM_MEDIA_STATE_T kalGetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo); + +void kalSetMediaStateIndicated(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_PARAM_MEDIA_STATE_T + eParamMediaStateIndicate); + +/*----------------------------------------------------------------------------*/ +/* OID handling */ +/*----------------------------------------------------------------------------*/ +void kalOidCmdClearance(IN P_GLUE_INFO_T prGlueInfo); + +void kalEnqueueCommand(IN P_GLUE_INFO_T prGlueInfo, + IN P_QUE_ENTRY_T prQueueEntry); + +/*----------------------------------------------------------------------------*/ +/* Security Frame Clearance */ +/*----------------------------------------------------------------------------*/ +void kalClearSecurityFrames(IN P_GLUE_INFO_T prGlueInfo); + +void kalClearSecurityFramesByBssIdx(IN P_GLUE_INFO_T prGlueInfo, + IN u8 ucBssIndex); + +void kalSecurityFrameSendComplete(IN P_GLUE_INFO_T prGlueInfo, + IN void *pvPacket, + IN WLAN_STATUS rStatus); + +/*----------------------------------------------------------------------------*/ +/* Management Frame Clearance */ +/*----------------------------------------------------------------------------*/ +void kalClearMgmtFrames(IN P_GLUE_INFO_T prGlueInfo); + +void kalClearMgmtFramesByBssIdx(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucBssIndex); + +u32 kalGetTxPendingFrameCount(IN P_GLUE_INFO_T prGlueInfo); + +u32 kalGetTxPendingCmdCount(IN P_GLUE_INFO_T prGlueInfo); + +void kalClearCommandQueue(IN P_GLUE_INFO_T prGlueInfo, IN u8 fgIsNeedHandler); + +u8 kalSetTimer(IN P_GLUE_INFO_T prGlueInfo, IN u32 u4Interval); + +u8 kalCancelTimer(IN P_GLUE_INFO_T prGlueInfo); + +void kalScanDone(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN WLAN_STATUS status); + +u32 kalRandomNumber(void); + +#if KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE +void kalTimeoutHandler(struct timer_list *timer); +#else +void kalTimeoutHandler(unsigned long arg); +#endif + +void kalSetEvent(P_GLUE_INFO_T pr); + +void kalSetIntEvent(P_GLUE_INFO_T pr); + +void kalSetTxEvent2Hif(P_GLUE_INFO_T pr); + +void kalSetTxEvent2Rx(P_GLUE_INFO_T pr); + +void kalSetTxCmdEvent2Hif(P_GLUE_INFO_T pr); + +/*----------------------------------------------------------------------------*/ +/* NVRAM/Registry Service */ +/*----------------------------------------------------------------------------*/ +u8 kalIsConfigurationExist(IN P_GLUE_INFO_T prGlueInfo); + +P_REG_INFO_T kalGetConfiguration(IN P_GLUE_INFO_T prGlueInfo); + +void kalGetConfigurationVersion(IN P_GLUE_INFO_T prGlueInfo, + OUT u16 *pu2Part1CfgOwnVersion, + OUT u16 *pu2Part1CfgPeerVersion, + OUT u16 *pu2Part2CfgOwnVersion, + OUT u16 *pu2Part2CfgPeerVersion); + +u8 kalCfgDataRead16(IN P_GLUE_INFO_T prGlueInfo, + IN u32 u4Offset, + OUT u16 *pu2Data); + +u8 kalCfgDataWrite16(IN P_GLUE_INFO_T prGlueInfo, IN u32 u4Offset, + IN u16 u2Data); + +/*----------------------------------------------------------------------------*/ +/* WSC Connection */ +/*----------------------------------------------------------------------------*/ +u8 kalWSCGetActiveState(IN P_GLUE_INFO_T prGlueInfo); + +/*----------------------------------------------------------------------------*/ +/* RSSI Updating */ +/*----------------------------------------------------------------------------*/ +void kalUpdateRSSI(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_KAL_NETWORK_TYPE_INDEX_T eNetTypeIdx, + IN s8 cRssi, + IN s8 cLinkQuality); + +/*----------------------------------------------------------------------------*/ +/* I/O Buffer Pre-allocation */ +/*----------------------------------------------------------------------------*/ +u8 kalInitIOBuffer(u8 is_pre_alloc); + +void kalUninitIOBuffer(void); + +void *kalAllocateIOBuffer(IN u32 u4AllocSize); + +void kalReleaseIOBuffer(IN void *pvAddr, IN u32 u4Size); + +void kalGetChannelList(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_BAND_T eSpecificBand, + IN u8 ucMaxChannelNum, + IN u8 *pucNumOfChannel, + IN P_RF_CHANNEL_INFO_T paucChannelList); + +u8 kalIsAPmode(IN P_GLUE_INFO_T prGlueInfo); + +#if CFG_SUPPORT_802_11W +/*----------------------------------------------------------------------------*/ +/* 802.11W */ +/*----------------------------------------------------------------------------*/ +u32 kalGetMfpSetting(IN P_GLUE_INFO_T prGlueInfo); +u8 kalGetRsnIeMfpCap(IN P_GLUE_INFO_T prGlueInfo); +#endif + +/*----------------------------------------------------------------------------*/ +/* file opetation */ +/*----------------------------------------------------------------------------*/ +u32 kalWriteToFile(const u8 *pucPath, u8 fgDoAppend, u8 *pucData, u32 u4Size); + +u32 kalCheckPath(const u8 *pucPath); + +u32 kalTrunkPath(const u8 *pucPath); + +s32 kalReadToFile(const u8 *pucPath, u8 *pucData, u32 u4Size, u32 *pu4ReadSize); + +s32 kalRequestFirmware(const u8 *pucPath, + u8 *pucData, + u32 u4Size, + u32 *pu4ReadSize, + struct device *dev); + +/*----------------------------------------------------------------------------*/ +/* NL80211 */ +/*----------------------------------------------------------------------------*/ +void kalIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, + IN u8 *pucFrameBuf, + IN u32 u4BufLen, + IN u8 ucChannelNum, + IN s32 i4SignalStrength); + +/*----------------------------------------------------------------------------*/ +/* Net device */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS +kalHardStartXmit(struct sk_buff *prSkb, + IN struct net_device *prDev, + P_GLUE_INFO_T prGlueInfo, + u8 ucBssIndex); + +u8 kalIsPairwiseEapolPacket(IN P_NATIVE_PACKET prPacket); + +u8 kalGetIPv4Address(IN struct net_device *prDev, + IN u32 u4MaxNumOfAddr, + OUT u8 *pucIpv4Addrs, + OUT u32 *pu4NumOfIpv4Addr); + +#if IS_ENABLED(CONFIG_IPV6) +u8 kalGetIPv6Address(IN struct net_device *prDev, + IN u32 u4MaxNumOfAddr, + OUT u8 *pucIpv6Addrs, + OUT u32 *pu4NumOfIpv6Addr); +#else +static inline u8 kalGetIPv6Address(IN struct net_device *prDev, + IN u32 u4MaxNumOfAddr, OUT u8 *pucIpv6Addrs, + OUT u32 *pu4NumOfIpv6Addr) +{ + /* Not support IPv6 */ + *pu4NumOfIpv6Addr = 0; + return false; +} +#endif + +void kalSetNetAddressFromInterface(IN P_GLUE_INFO_T prGlueInfo, + IN struct net_device *prDev, + IN u8 fgSet); + +WLAN_STATUS kalResetStats(IN struct net_device *prDev); + +void *kalGetStats(IN struct net_device *prDev); + +void kalResetPacket(IN P_GLUE_INFO_T prGlueInfo, IN P_NATIVE_PACKET prPacket); + +#if CFG_SUPPORT_QA_TOOL +struct file *kalFileOpen(const char *path, int flags, int rights); + +void kalFileClose(struct file *file); + +u32 kalFileRead(struct file *file, + unsigned long long offset, + unsigned char *data, + unsigned int size); +#endif + +#if CFG_SUPPORT_SDIO_READ_WRITE_PATTERN +/*----------------------------------------------------------------------------*/ +/* SDIO Read/Write Pattern Support */ +/*----------------------------------------------------------------------------*/ +u8 kalSetSdioTestPattern(IN P_GLUE_INFO_T prGlueInfo, IN u8 fgEn, IN u8 fgRead); +#endif + +/*----------------------------------------------------------------------------*/ +/* PNO Support */ +/*----------------------------------------------------------------------------*/ +void kalSchedScanResults(IN P_GLUE_INFO_T prGlueInfo); + +void kalSchedScanStopped(IN P_GLUE_INFO_T prGlueInfo); + +void kalWDevLockThread(IN P_GLUE_INFO_T prGlueInfo, + IN struct net_device *pDev, + IN enum ENUM_CFG80211_WDEV_LOCK_FUNC fn, + IN u8 *pFrameBuf, + IN size_t frameLen, + IN struct cfg80211_bss *pBss, + IN s32 uapsd_queues, + const u8 *req_ies, + size_t req_ies_len, + IN u8 fgIsInterruptContext); + +#if CFG_MULTI_ECOVER_SUPPORT + +typedef enum _ENUM_WMTCHIN_TYPE_T { + WMTCHIN_CHIPID = 0x0, + WMTCHIN_HWVER = WMTCHIN_CHIPID + 1, + WMTCHIN_MAPPINGHWVER = WMTCHIN_HWVER + 1, + WMTCHIN_FWVER = WMTCHIN_MAPPINGHWVER + 1, + WMTCHIN_MAX +} ENUM_WMT_CHIPINFO_TYPE_T, +*P_ENUM_WMT_CHIPINFO_TYPE_T; + +u32 mtk_wcn_wmt_ic_info_get(ENUM_WMT_CHIPINFO_TYPE_T type); + +#endif + +void kalSetFwOwnEvent2Hif(P_GLUE_INFO_T pr); +#if CFG_ASSERT_DUMP +/* Core Dump out put file */ +WLAN_STATUS kalOpenCorDumpFile(u8 fgIsN9); +WLAN_STATUS kalWriteCorDumpFile(u8 *pucBuffer, u16 u2Size, u8 fgIsN9); +WLAN_STATUS kalCloseCorDumpFile(u8 fgIsN9); +#endif +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#if CFG_WOW_SUPPORT +void kalWowInit(IN P_GLUE_INFO_T prGlueInfo); +void kalWowProcess(IN P_GLUE_INFO_T prGlueInfo, u8 enable); +#endif + +int main_thread(void *data); +int hif_thread(void *data); +int rx_thread(void *data); + +u64 kalGetBootTime(void); + +int kalMetInitProcfs(IN P_GLUE_INFO_T prGlueInfo); +int kalMetRemoveProcfs(IN P_GLUE_INFO_T prGlueInfo); + +void kalFreeTxMsduWorker(struct work_struct *work); +void kalFreeTxMsdu(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo); + +static inline void kal_skb_reset_mac_len(struct sk_buff *skb) +{ + skb_reset_mac_len(skb); +} + +int kal_sched_set(struct task_struct *p, + int policy, + const struct sched_param *param, + int nice); + +WLAN_STATUS kalUpdateBssChannel(IN P_GLUE_INFO_T prGlueInfo, + IN u8 aucSSID[], + IN u8 ucSsidLength, + IN u8 aucBSSID[], + IN u8 ucChannelNum); + +#if CFG_WOW_SUPPORT +void kalWowCmdEventSetCb(IN P_ADAPTER_T prAdapter, + IN P_CMD_INFO_T prCmdInfo, + IN u8 *pucEventBuf, IN u32 u4EventBufLen); +#endif + +void kalSetNetAddress(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucBssIdx, + IN u8 *pucIPv4Addr, IN u32 u4NumIPv4Addr, + IN u8 *pucIPv6Addr, IN u32 u4NumIPv6Addr); + +u32 kalProcessTxPacket(P_GLUE_INFO_T prGlueInfo, struct sk_buff *prSkb); +void kalProcessTxReq(P_GLUE_INFO_T prGlueInfo, u8 *pfgNeedHwAccess); +u32 kalFileWrite(struct file *file, unsigned long long offset, + unsigned char *data, unsigned int size); +void kalQueryRegistryMacAddr(IN P_GLUE_INFO_T prGlueInfo, + OUT u8 *paucMacAddr); +u8 kalIPv4FrameClassifier(IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket, IN u8 *pucIpHdr, + OUT P_TX_PACKET_INFO prTxPktInfo); + +#if CFG_MET_PACKET_TRACE_SUPPORT +u8 kalMetCheckProfilingPacket(IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket); +#endif + +static inline void kal_eth_hw_addr_set(struct net_device *dev, + const u8 *addr) +{ +#if KERNEL_VERSION(5, 17, 0) <= LINUX_VERSION_CODE + // eth_hw_addr_set(dev, addr); + dev_addr_set(dev, addr); +#else + kalMemCopy(dev->dev_addr, addr, ETH_ALEN); +#endif +} + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_os.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_os.h new file mode 100644 index 00000000000000..42e9ebe007f2bc --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_os.h @@ -0,0 +1,932 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_os.h + * \brief List the external reference to OS for GLUE Layer. + * + * In this file we define the data structure - GLUE_INFO_T to store those + * objects we acquired from OS - e.g. TIMER, SPINLOCK, NET DEVICE ... . And all + * the external reference (header file, extern func() ..) to OS for GLUE Layer + * should also list down here. + */ + +#ifndef _GL_OS_H +#define _GL_OS_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/*------------------------------------------------------------------------------ + * Flags for LINUX(OS) dependent + *------------------------------------------------------------------------------ + */ +#define CFG_MAX_WLAN_DEVICES 1 /* number of wlan card will coexist */ + +#define CFG_MAX_TXQ_NUM 4 /* number of tx queue for support multi-queue h/w */ + +/* 1: Enable use of SPIN LOCK Bottom Half for LINUX */ +/* 0: Disable - use SPIN LOCK IRQ SAVE instead */ +#define CFG_USE_SPIN_LOCK_BOTTOM_HALF 0 + +/* 1: Enable - Drop ethernet packet if it < 14 bytes. + * And pad ethernet packet with dummy 0 if it < 60 bytes. + * 0: Disable + */ +#define CFG_TX_PADDING_SMALL_ETH_PACKET 0 + +#define CFG_TX_STOP_NETIF_QUEUE_THRESHOLD 256 /* packets */ + +#define CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD 512 /* packets */ +#define CFG_TX_START_NETIF_PER_QUEUE_THRESHOLD 128 /* packets */ + +/* WMM Certification Related */ +#define CFG_CERT_WMM_MAX_TX_PENDING 20 +#define CFG_CERT_WMM_MAX_RX_NUM 10 +#define CFG_CERT_WMM_HIGH_STOP_TX_WITH_RX \ + (CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD * 3) +#define CFG_CERT_WMM_HIGH_STOP_TX_WO_RX \ + (CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD * 2) +#define CFG_CERT_WMM_LOW_STOP_TX_WITH_RX \ + (CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD >> 4) +#define CFG_CERT_WMM_LOW_STOP_TX_WO_RX \ + (CFG_TX_STOP_NETIF_PER_QUEUE_THRESHOLD >> 3) + +#define CHIP_NAME "MT6632" + +#define DRV_NAME "[" CHIP_NAME "]: " + +/* for CFG80211 IE buffering mechanism */ +#define CFG_CFG80211_IE_BUF_LEN (512) + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include <linux/version.h> /* constant of kernel version */ + +#include <linux/kernel.h> /* bitops.h */ + +#include <linux/timer.h> /* struct timer_list */ +#include <linux/jiffies.h> /* jiffies */ +#include <linux/delay.h> /* udelay and mdelay macro */ + +#include <linux/irq.h> /* IRQT_FALLING */ + +#include <linux/netdevice.h> /* struct net_device, struct net_device_stats */ +#include <linux/etherdevice.h> /* for eth_type_trans() function */ +#include <linux/wireless.h> /* struct iw_statistics */ +#include <linux/if_arp.h> +#include <linux/inetdevice.h> /* struct in_device */ + +#include <linux/ip.h> /* struct iphdr */ + +#include <linux/string.h> /* for memcpy()/memset() function */ +#include <linux/stddef.h> /* for offsetof() macro */ + +#include <linux/proc_fs.h> /* The proc filesystem constants/structures */ + +#include <linux/rtnetlink.h> /* for rtnl_lock() and rtnl_unlock() */ +#include <linux/kthread.h> /* kthread_should_stop(), kthread_run() */ +#include <linux/uaccess.h> /* for copy_from_user() */ +#include <linux/fs.h> /* for firmware download */ +#include <linux/vmalloc.h> + +#include <linux/kfifo.h> /* for kfifo interface */ +#include <linux/cdev.h> /* for cdev interface */ + +#include <linux/firmware.h> /* for firmware download */ +#include <linux/ctype.h> + +#include <linux/interrupt.h> + +#include <linux/mmc/sdio.h> +#include <linux/mmc/sdio_func.h> + +#include <linux/random.h> + +#include <linux/io.h> /* readw and writew */ + +#if WIRELESS_EXT > 12 +#include <net/iw_handler.h> +#endif + +#ifdef CFG_CFG80211_VERSION +#define CFG80211_VERSION_CODE CFG_CFG80211_VERSION +#else +#define CFG80211_VERSION_CODE LINUX_VERSION_CODE +#endif + +#include "version.h" +#include "config.h" + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +#include <linux/wireless.h> +#include <net/cfg80211.h> +#endif + +#include <linux/module.h> +#include <linux/can/netlink.h> +#include <net/netlink.h> + +#if IS_ENABLED(CONFIG_IPV6) +#include <linux/ipv6.h> +#include <linux/in6.h> +#include <net/if_inet6.h> +#endif + +#include <uapi/linux/nl80211.h> + +#include "gl_typedef.h" +#include "typedef.h" +#include "queue.h" +#include "gl_kal.h" +#include "hif.h" + +#if CFG_SUPPORT_TDLS +#include "tdls.h" +#endif + +#include "debug.h" + +#include "wlan_lib.h" +#include "wlan_oid.h" + +#include <linux/time.h> +#include <linux/capability.h> +#include <linux/skbuff.h> + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0) +#include <linux/sched/clock.h> +#include <uapi/linux/sched/types.h> + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +#include <linux/sched.h> +#include <uapi/linux/sched/types.h> +#endif + +extern u8 fgIsBusAccessFailed; +extern const struct ieee80211_iface_combination *p_mtk_iface_combinations_sta; +extern const s32 mtk_iface_combinations_sta_num; + +#if CFG_ENABLE_UNIFY_WIPHY +extern const struct ieee80211_iface_combination *p_mtk_iface_combinations_p2p; +extern const s32 mtk_iface_combinations_p2p_num; +#endif + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define GLUE_FLAG_HALT BIT(0) +#define GLUE_FLAG_INT BIT(1) +#define GLUE_FLAG_OID BIT(2) +#define GLUE_FLAG_TIMEOUT BIT(3) +#define GLUE_FLAG_TXREQ BIT(4) +#define GLUE_FLAG_SUB_MOD_MULTICAST BIT(7) +#define GLUE_FLAG_FRAME_FILTER BIT(8) +#define GLUE_FLAG_FRAME_FILTER_AIS BIT(9) + +#define GLUE_FLAG_HALT_BIT (0) +#define GLUE_FLAG_INT_BIT (1) +#define GLUE_FLAG_OID_BIT (2) +#define GLUE_FLAG_TIMEOUT_BIT (3) +#define GLUE_FLAG_TXREQ_BIT (4) +#define GLUE_FLAG_SUB_MOD_MULTICAST_BIT (7) +#define GLUE_FLAG_FRAME_FILTER_BIT (8) +#define GLUE_FLAG_FRAME_FILTER_AIS_BIT (9) + +#define GLUE_FLAG_RX BIT(10) +#define GLUE_FLAG_TX_CMD_DONE BIT(11) +#define GLUE_FLAG_HIF_TX BIT(12) +#define GLUE_FLAG_HIF_TX_CMD BIT(13) +#define GLUE_FLAG_RX_TO_OS BIT(14) +#define GLUE_FLAG_HIF_FW_OWN BIT(15) +#define GLUE_FLAG_HIF_PRT_HIF_DBG_INFO BIT(16) + +#define GLUE_FLAG_RX_BIT (10) +#define GLUE_FLAG_TX_CMD_DONE_BIT (11) +#define GLUE_FLAG_HIF_TX_BIT (12) +#define GLUE_FLAG_HIF_TX_CMD_BIT (13) +#define GLUE_FLAG_RX_TO_OS_BIT (14) +#define GLUE_FLAG_HIF_FW_OWN_BIT (15) +#define GLUE_FLAG_HIF_PRT_HIF_DBG_INFO_BIT (16) +#define GLUE_FLAG_ADAPT_RDY BIT(17) + +#define GLUE_FLAG_ADAPT_RDY_BIT (17) + +#define GLUE_BOW_KFIFO_DEPTH (1024) +#define GLUE_BOW_DEVICE_NAME "ampc0" + +#define WAKE_LOCK_RX_TIMEOUT 300 /* ms */ +#define WAKE_LOCK_THREAD_WAKEUP_TIMEOUT 50 /* ms */ + +/* EFUSE Auto Mode Support */ +#define LOAD_EFUSE 0 +#define LOAD_EEPROM_BIN 1 +#define LOAD_AUTO 2 +#define EFUSE_AUTO_CHEK 0x76 + +#if KERNEL_VERSION(4, 12, 0) > CFG80211_VERSION_CODE +#define WLAN_AKM_SUITE_8021X_SUITE_B 0x000FAC0B +#define WLAN_AKM_SUITE_8021X_SUITE_B_192 0x000FAC0C +#endif + +#if KERNEL_VERSION(6, 0, 0) > CFG80211_VERSION_CODE +#if CFG_SUPPORT_OWE +#define WLAN_AKM_SUITE_OWE 0x000FAC12 +#endif +#endif + +#define IW_AUTH_CIPHER_GCMP256 0x00000080 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef struct _GL_WPA_INFO_T { + u32 u4WpaVersion; + u32 u4KeyMgmt; + u32 u4CipherGroup; + u32 u4CipherPairwise; + u32 u4AuthAlg; + u8 fgPrivacyInvoke; +#if CFG_SUPPORT_802_11W + u32 u4CipherGroupMgmt; + u32 u4Mfp; + u8 ucRSNMfpCap; +#endif + u8 ucRsneLen; + u8 aucKek[NL80211_KEK_LEN]; + u8 aucKck[NL80211_KCK_LEN]; + u8 aucReplayCtr[NL80211_REPLAY_CTR_LEN]; +} GL_WPA_INFO_T, *P_GL_WPA_INFO_T; + +#if CFG_SUPPORT_REPLAY_DETECTION +struct SEC_REPLEY_PN_INFO { + u8 auPN[16]; + u8 fgRekey; + u8 fgFirstPkt; +}; +struct SEC_DETECT_REPLAY_INFO { + u8 ucCurKeyId; + u8 ucKeyType; + struct SEC_REPLEY_PN_INFO arReplayPNInfo[4]; + u32 u4KeyLength; + u8 aucKeyMaterial[32]; + u8 fgPairwiseInstalled; + u8 fgKeyRscFresh; +}; +#endif + +typedef enum _ENUM_NET_DEV_IDX_T { + NET_DEV_WLAN_IDX = 0, + NET_DEV_P2P_IDX, + NET_DEV_BOW_IDX, + NET_DEV_NUM +} ENUM_NET_DEV_IDX_T; + +typedef enum _ENUM_RSSI_TRIGGER_TYPE { + ENUM_RSSI_TRIGGER_NONE, + ENUM_RSSI_TRIGGER_GREATER, + ENUM_RSSI_TRIGGER_LESS, + ENUM_RSSI_TRIGGER_TRIGGERED, + ENUM_RSSI_TRIGGER_NUM +} ENUM_RSSI_TRIGGER_TYPE; + +#if CFG_ENABLE_WIFI_DIRECT +typedef enum _ENUM_NET_REG_STATE_T { + ENUM_NET_REG_STATE_UNREGISTERED, + ENUM_NET_REG_STATE_REGISTERING, + ENUM_NET_REG_STATE_REGISTERED, + ENUM_NET_REG_STATE_UNREGISTERING, + ENUM_NET_REG_STATE_NUM +} ENUM_NET_REG_STATE_T; + +typedef enum _ENUM_P2P_REG_STATE_T { + ENUM_P2P_REG_STATE_UNREGISTERED, + ENUM_P2P_REG_STATE_REGISTERING, + ENUM_P2P_REG_STATE_REGISTERED, + ENUM_P2P_REG_STATE_UNREGISTERING, + ENUM_P2P_REG_STATE_NUM +} ENUM_P2P_REG_STATE_T; +#endif + +typedef enum _ENUM_PKT_FLAG_T { + ENUM_PKT_802_11, /* 802.11 or non-802.11 */ + ENUM_PKT_802_3, /* 802.3 or ethernetII */ + ENUM_PKT_1X, /* 1x frame or not */ + ENUM_PKT_PROTECTED_1X, /* protected 1x frame */ + ENUM_PKT_NON_PROTECTED_1X, /* Non protected 1x frame */ + ENUM_PKT_VLAN_EXIST, /* VLAN tag exist */ + ENUM_PKT_DHCP, /* DHCP frame */ + ENUM_PKT_ARP, /* ARP */ +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT + ENUM_PKT_FIRST_DUP, /* The First Duplicate packet */ +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK + ENUM_PKT_LB, /* PKT LB flag */ +#endif +#endif + ENUM_PKT_FLAG_NUM +} ENUM_PKT_FLAG_T; + +typedef struct _GL_IO_REQ_T { + QUE_ENTRY_T rQueEntry; + /* wait_queue_head_t cmdwait_q; */ + u8 fgRead; + u8 fgWaitResp; + P_ADAPTER_T prAdapter; + PFN_OID_HANDLER_FUNC pfnOidHandler; + void *pvInfoBuf; + u32 u4InfoBufLen; + u32 *pu4QryInfoLen; + WLAN_STATUS rStatus; + u32 u4Flag; + u32 u4Timeout; +} GL_IO_REQ_T, *P_GL_IO_REQ_T; + +/* + * type definition of pointer to p2p structure + */ +typedef struct _GL_P2P_INFO_T GL_P2P_INFO_T, *P_GL_P2P_INFO_T; +typedef struct _GL_P2P_DEV_INFO_T GL_P2P_DEV_INFO_T, *P_GL_P2P_DEV_INFO_T; + +struct _GLUE_INFO_T { + /* Device handle */ + struct net_device *prDevHandler; + + /* Device */ + struct device *prDev; + + /* Device Index(index of arWlanDevInfo[]) */ + s32 i4DevIdx; + + /* Device statistics */ + /* struct net_device_stats rNetDevStats; */ + + /* Wireless statistics struct net_device */ + struct iw_statistics rIwStats; + + /* spinlock to sync power save mechanism */ + spinlock_t rSpinLock[SPIN_LOCK_NUM]; + + /* Mutex to protect interruptible section */ + struct mutex arMutex[MUTEX_NUM]; + + /* semaphore for ioctl */ + struct semaphore ioctl_sem; + + u64 u8Cookie; + + volatile unsigned long ulFlag; /* GLUE_FLAG_XXX */ + u32 u4PendFlag; + /* u32 u4TimeoutFlag; */ + u32 u4OidCompleteFlag; + u32 u4ReadyFlag; /* check if card is ready */ + + u32 u4OsMgmtFrameFilter; + + /* Number of pending frames, also used for debuging if any frame is + * missing during the process of unloading Driver. + * + * NOTE(Kevin): In Linux, we also use this variable as the threshold + * for manipulating the netif_stop(wake)_queue() func. + */ + s32 ai4TxPendingFrameNumPerQueue[HW_BSSID_NUM + 1][CFG_MAX_TXQ_NUM]; + s32 i4TxPendingFrameNum; + s32 i4TxPendingSecurityFrameNum; + s32 i4TxPendingCmdNum; + + /* Tx: for NetDev to BSS index mapping */ + NET_INTERFACE_INFO_T arNetInterfaceInfo[HW_BSSID_NUM + 1]; + + /* Rx: for BSS index to NetDev mapping */ + /* P_NET_INTERFACE_INFO_T aprBssIdxToNetInterfaceInfo[HW_BSSID_NUM]; */ + + /* current IO request for kalIoctl */ + GL_IO_REQ_T OidEntry; + + /* registry info */ + REG_INFO_T rRegInfo; + + /* firmware */ + struct firmware *prFw; + + /* Host interface related information */ + /* defined in related hif header file */ + GL_HIF_INFO_T rHifInfo; + + /*! \brief wext wpa related information */ + GL_WPA_INFO_T rWpaInfo; + + /* Pointer to ADAPTER_T - main data structure of internal protocol stack + */ + P_ADAPTER_T prAdapter; + +#if WLAN_INCLUDE_PROC + struct proc_dir_entry *pProcRoot; +#endif + + /* Indicated media state */ + ENUM_PARAM_MEDIA_STATE_T eParamMediaStateIndicated; + + /* Device power state D0~D3 */ + PARAM_DEVICE_POWER_STATE ePowerState; + + struct completion rScanComp; /* indicate scan complete */ + struct completion rHaltComp; /* indicate main thread halt complete */ + struct completion rPendComp; /* indicate main thread halt complete */ + struct completion rHifHaltComp; /* indicate hif_thread halt complete */ + struct completion rRxHaltComp; /* indicate hif_thread halt complete */ + + u32 u4TxThreadPid; + u32 u4RxThreadPid; + u32 u4HifThreadPid; + WLAN_STATUS rPendStatus; + + QUE_T rTxQueue; + + /* OID related */ + QUE_T rCmdQueue; + + wait_queue_head_t waitq; + struct task_struct *main_thread; + + wait_queue_head_t waitq_hif; + struct task_struct *hif_thread; + + wait_queue_head_t waitq_rx; + struct task_struct *rx_thread; + + struct tasklet_struct rRxTask; + struct tasklet_struct rTxCompleteTask; + + struct work_struct rTxMsduFreeWork; + struct delayed_work rRxPktDeAggWork; + + struct timer_list tickfn; + +#if CFG_SUPPORT_EXT_CONFIG + u16 au2ExtCfg[256]; /* NVRAM data buffer */ + u32 u4ExtCfgLength; /* 0 means data is NOT valid */ +#endif + + /* Should be large than the PARAM_WAPI_ASSOC_INFO_T */ + u8 aucWapiAssocInfoIEs[42]; + u16 u2WapiAssocInfoIESz; + +#if CFG_ENABLE_WIFI_DIRECT + P_GL_P2P_DEV_INFO_T prP2PDevInfo; + P_GL_P2P_INFO_T prP2PInfo[KAL_P2P_NUM]; +#if CFG_SUPPORT_P2P_RSSI_QUERY + /* Wireless statistics struct net_device */ + struct iw_statistics rP2pIwStats; +#endif +#endif + u8 fgWpsActive; + u8 aucWSCIE[500]; /*for probe req */ + u16 u2WSCIELen; + u8 aucWSCAssocInfoIE[200]; /*for Assoc req */ + u16 u2WSCAssocInfoIELen; + + /* NVRAM availability */ + u8 fgNvramAvailable; + + u8 fgMcrAccessAllowed; + + /* MAC Address Overridden by IOCTL */ + u8 fgIsMacAddrOverride; + PARAM_MAC_ADDRESS rMacAddrOverride; + + SET_TXPWR_CTRL_T rTxPwr; + + /* for cfg80211 scan done indication */ + struct cfg80211_scan_request *prScanRequest; + + /* for cfg80211 scheduled scan */ + struct cfg80211_sched_scan_request *prSchedScanRequest; + + /* to indicate registered or not */ + u8 fgIsRegistered; + + /* for cfg80211 connected indication */ + u32 u4RspIeLength; + u8 aucRspIe[CFG_CFG80211_IE_BUF_LEN]; + + u32 u4ReqIeLength; + u8 aucReqIe[CFG_CFG80211_IE_BUF_LEN]; + +#if CFG_SUPPORT_SDIO_READ_WRITE_PATTERN + u8 fgEnSdioTestPattern; + u8 fgSdioReadWriteMode; + u8 fgIsSdioTestInitialized; + u8 aucSdioTestBuffer[256]; +#endif + + u8 fgIsInSuspendMode; + +#if CFG_MET_PACKET_TRACE_SUPPORT + u8 fgMetProfilingEn; + u16 u2MetUdpPort; +#endif + +#if CFG_SUPPORT_SNIFFER + u8 fgIsEnableMon; + struct net_device *prMonDevHandler; + struct work_struct monWork; +#endif + + s32 i4RssiCache; + u32 u4LinkSpeedCache; + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT_LOOKBACK + QUE_T rTxLookBackQueue; + QUE_T rRxLookBackQueue; +#endif +}; + +typedef irqreturn_t (*PFN_WLANISR)(int irq, void *dev_id, struct pt_regs *regs); + +typedef void (*PFN_LINUX_TIMER_FUNC)(unsigned long); + +/* generic sub module init/exit handler + * now, we only have one sub module, p2p + */ +#if CFG_ENABLE_WIFI_DIRECT +typedef u8 (*SUB_MODULE_INIT)(P_GLUE_INFO_T prGlueInfo); +typedef u8 (*SUB_MODULE_EXIT)(P_GLUE_INFO_T prGlueInfo); + +typedef struct _SUB_MODULE_HANDLER { + SUB_MODULE_INIT subModInit; + SUB_MODULE_EXIT subModExit; + u8 fgIsInited; +} SUB_MODULE_HANDLER, *P_SUB_MODULE_HANDLER; + +#endif + +#ifdef CONFIG_NL80211_TESTMODE + +enum TestModeCmdType { + TESTMODE_CMD_ID_SW_CMD = 1, + TESTMODE_CMD_ID_WAPI = 2, + TESTMODE_CMD_ID_HS20 = 3, + TESTMODE_CMD_ID_STR_CMD = 102, + NUM_OF_TESTMODE_CMD_ID +}; + +typedef struct _NL80211_DRIVER_TEST_MODE_PARAMS { + u32 index; + u32 buflen; +} NL80211_DRIVER_TEST_MODE_PARAMS, *P_NL80211_DRIVER_TEST_MODE_PARAMS; + +/*SW CMD */ +typedef struct _NL80211_DRIVER_SW_CMD_PARAMS { + NL80211_DRIVER_TEST_MODE_PARAMS hdr; + u8 set; + u32 adr; + u32 data; +} NL80211_DRIVER_SW_CMD_PARAMS, *P_NL80211_DRIVER_SW_CMD_PARAMS; + +struct iw_encode_exts { + __u32 ext_flags; /*!< IW_ENCODE_EXT_**/ + __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ + __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ + /*!< ff:ff:ff:ff:ff:ff for broadcast/multicast + * (group) keys or unicast address for + * individual keys + */ + __u8 addr[MAC_ADDR_LEN]; + __u16 alg; /*!< IW_ENCODE_ALG_**/ + __u16 key_len; + __u8 key[32]; +}; + +/*SET KEY EXT */ +typedef struct _NL80211_DRIVER_SET_KEY_EXTS { + NL80211_DRIVER_TEST_MODE_PARAMS hdr; + u8 key_index; + u8 key_len; + struct iw_encode_exts ext; +} NL80211_DRIVER_SET_KEY_EXTS, *P_NL80211_DRIVER_SET_KEY_EXTS; + +#endif + +typedef struct _NETDEV_PRIVATE_GLUE_INFO { + P_GLUE_INFO_T prGlueInfo; + u8 ucBssIdx; +#if CFG_ENABLE_UNIFY_WIPHY + u8 ucIsP2p; +#endif +} NETDEV_PRIVATE_GLUE_INFO, *P_NETDEV_PRIVATE_GLUE_INFO; + +typedef struct _PACKET_PRIVATE_DATA { + QUE_ENTRY_T rQueEntry; + u16 u2Flag; + u8 ucTid; + u8 ucBssIdx; + + u8 ucHeaderLen; + u16 u2FrameLen; + + u8 ucProfilingFlag; + u32 rArrivalTime; + u16 u2IpId; +} PACKET_PRIVATE_DATA, *P_PACKET_PRIVATE_DATA; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Macros of SPIN LOCK operations for using in Glue Layer */ +/*----------------------------------------------------------------------------*/ +#if CFG_USE_SPIN_LOCK_BOTTOM_HALF +#define GLUE_SPIN_LOCK_DECLARATION() +#define GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, rLockCategory) \ + { \ + if (rLockCategory < SPIN_LOCK_NUM) \ + spin_lock_bh(&(prGlueInfo->rSpinLock[rLockCategory])); \ + } +#define GLUE_RELEASE_SPIN_LOCK(prGlueInfo, rLockCategory) \ + { \ + if (rLockCategory < SPIN_LOCK_NUM) \ + spin_unlock_bh( \ + &(prGlueInfo->rSpinLock[rLockCategory])); \ + } +#else /* !CFG_USE_SPIN_LOCK_BOTTOM_HALF */ +#define GLUE_SPIN_LOCK_DECLARATION() unsigned long __ulFlags = 0 +#define GLUE_ACQUIRE_SPIN_LOCK(prGlueInfo, rLockCategory) \ + { \ + if (rLockCategory < SPIN_LOCK_NUM) \ + spin_lock_irqsave( \ + &(prGlueInfo)->rSpinLock[rLockCategory], \ + __ulFlags); \ + } +#define GLUE_RELEASE_SPIN_LOCK(prGlueInfo, rLockCategory) \ + { \ + if (rLockCategory < SPIN_LOCK_NUM) \ + spin_unlock_irqrestore( \ + &(prGlueInfo->rSpinLock[rLockCategory]), \ + __ulFlags); \ + } +#endif + +/*----------------------------------------------------------------------------*/ +/* Macros for accessing Reserved Fields of native packet */ +/*----------------------------------------------------------------------------*/ + +#define GLUE_GET_PKT_PRIVATE_DATA(_p) \ + ((P_PACKET_PRIVATE_DATA)(&(((struct sk_buff *)(_p))->cb[0]))) + +#define GLUE_GET_PKT_QUEUE_ENTRY(_p) \ + (&(GLUE_GET_PKT_PRIVATE_DATA(_p)->rQueEntry)) + +#define GLUE_GET_PKT_DESCRIPTOR(_prQueueEntry) \ + ((P_NATIVE_PACKET)(((unsigned long)_prQueueEntry) - \ + offsetof(struct sk_buff, cb[0]))) + +#define GLUE_SET_PKT_TID(_p, _tid) \ + (GLUE_GET_PKT_PRIVATE_DATA(_p)->ucTid = (u8)(_tid)) + +#define GLUE_GET_PKT_TID(_p) (GLUE_GET_PKT_PRIVATE_DATA(_p)->ucTid) + +#define GLUE_SET_PKT_FLAG(_p, _flag) \ + (GLUE_GET_PKT_PRIVATE_DATA(_p)->u2Flag |= BIT(_flag)) + +#define GLUE_TEST_PKT_FLAG(_p, _flag) \ + (GLUE_GET_PKT_PRIVATE_DATA(_p)->u2Flag & BIT(_flag)) + +#define GLUE_IS_PKT_FLAG_SET(_p) (GLUE_GET_PKT_PRIVATE_DATA(_p)->u2Flag) + +#define GLUE_SET_PKT_BSS_IDX(_p, _ucBssIndex) \ + (GLUE_GET_PKT_PRIVATE_DATA(_p)->ucBssIdx = (u8)(_ucBssIndex)) + +#define GLUE_GET_PKT_BSS_IDX(_p) (GLUE_GET_PKT_PRIVATE_DATA(_p)->ucBssIdx) + +#define GLUE_SET_PKT_HEADER_LEN(_p, _ucMacHeaderLen) \ + (GLUE_GET_PKT_PRIVATE_DATA(_p)->ucHeaderLen = (u8)(_ucMacHeaderLen)) + +#define GLUE_GET_PKT_HEADER_LEN(_p) (GLUE_GET_PKT_PRIVATE_DATA( \ + _p)->ucHeaderLen) + +#define GLUE_SET_PKT_FRAME_LEN(_p, _u2PayloadLen) \ + (GLUE_GET_PKT_PRIVATE_DATA(_p)->u2FrameLen = (u16)(_u2PayloadLen)) + +#define GLUE_GET_PKT_FRAME_LEN(_p) (GLUE_GET_PKT_PRIVATE_DATA( \ + _p)->u2FrameLen) + +#define GLUE_SET_PKT_ARRIVAL_TIME(_p, _rSysTime) \ + (GLUE_GET_PKT_PRIVATE_DATA(_p)->rArrivalTime = (u32)(_rSysTime)) + +#define GLUE_GET_PKT_ARRIVAL_TIME(_p) \ + (GLUE_GET_PKT_PRIVATE_DATA(_p)->rArrivalTime) + +#define GLUE_SET_PKT_IP_ID(_p, _u2IpId) \ + (GLUE_GET_PKT_PRIVATE_DATA(_p)->u2IpId = (u16)(_u2IpId)) + +#define GLUE_GET_PKT_IP_ID(_p) (GLUE_GET_PKT_PRIVATE_DATA(_p)->u2IpId) + +#define GLUE_SET_PKT_FLAG_PROF_MET(_p) \ + (GLUE_GET_PKT_PRIVATE_DATA(_p)->ucProfilingFlag |= BIT(0)) + +#define GLUE_GET_PKT_IS_PROF_MET(_p) \ + (GLUE_GET_PKT_PRIVATE_DATA(_p)->ucProfilingFlag & BIT(0)) + +#define GLUE_GET_PKT_ETHER_DEST_ADDR(_p) \ + ((u8 *)&(((struct sk_buff *)(_p))->data)) + +/* Check validity of prDev, private data, and pointers */ +#define GLUE_CHK_DEV(prDev) \ + ((prDev && *((P_GLUE_INFO_T *)netdev_priv(prDev))) ? true : false) + +#define GLUE_CHK_PR2(prDev, \ + pr2) ((GLUE_CHK_DEV(prDev) && \ + pr2) ? true : false) + +#define GLUE_CHK_PR3(prDev, pr2, pr3) \ + ((GLUE_CHK_PR2(prDev, pr2) && pr3) ? true : false) + +#define GLUE_CHK_PR4(prDev, pr2, pr3, pr4) \ + ((GLUE_CHK_PR3(prDev, pr2, pr3) && pr4) ? true : false) + +#define GLUE_SET_EVENT(pr) kalSetEvent(pr) + +#define GLUE_INC_REF_CNT(_refCount) atomic_inc((atomic_t *)&(_refCount)) +#define GLUE_DEC_REF_CNT(_refCount) atomic_dec((atomic_t *)&(_refCount)) +#define GLUE_GET_REF_CNT(_refCount) atomic_read((atomic_t *)&(_refCount)) + +#define DbgPrint(...) + +/*----------------------------------------------------------------------------*/ +/* Macros of Data Type Check */ +/*----------------------------------------------------------------------------*/ +/* Kevin: we don't have to call following function to inspect the data + * structure. It will check automatically while at compile time. + */ +static __KAL_INLINE__ void glPacketDataTypeCheck(void) +{ + DATA_STRUCT_INSPECTING_ASSERT(sizeof(PACKET_PRIVATE_DATA) <= + sizeof(((struct sk_buff *)0)->cb)); +} + +static inline u16 mtk_wlan_ndev_select_queue(struct sk_buff *skb) +{ + static u16 ieee8021d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; + + /* cfg80211_classify8021d returns 0~7 */ + skb->priority = cfg80211_classify8021d(skb, NULL); + + return ieee8021d_to_queue[skb->priority]; +} + +#if KERNEL_VERSION(2, 6, 34) > LINUX_VERSION_CODE +#define netdev_for_each_mc_addr(mclist, dev) \ + for (mclist = dev->mc_list; mclist; mclist = mclist->next) +#endif + +#if KERNEL_VERSION(2, 6, 34) > LINUX_VERSION_CODE +#define GET_ADDR(ha) (ha->da_addr) +#else +#define GET_ADDR(ha) (ha->addr) +#endif + +#if KERNEL_VERSION(2, 6, 35) <= LINUX_VERSION_CODE +#define LIST_FOR_EACH_IPV6_ADDR(_prIfa, _ip6_ptr) \ + list_for_each_entry( \ + _prIfa, &((struct inet6_dev *)_ip6_ptr)->addr_list, if_list) +#else +#define LIST_FOR_EACH_IPV6_ADDR(_prIfa, _ip6_ptr) \ + for (_prIfa = ((struct inet6_dev *)_ip6_ptr)->addr_list; _prIfa; \ + _prIfa = _prIfa->if_next) +#endif + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +#if WLAN_INCLUDE_PROC +s32 procCreateFsEntry(P_GLUE_INFO_T prGlueInfo); +s32 procRemoveProcfs(void); + +s32 procInitFs(void); +s32 procUninitProcFs(void); + +s32 procInitProcfs(struct net_device *prDev, char *pucDevName); +#endif + +#if CFG_ENABLE_WIFI_DIRECT +void p2pSetMulticastListWorkQueueWrapper(P_GLUE_INFO_T prGlueInfo); +#endif + +P_GLUE_INFO_T wlanGetGlueInfo(void); + +#if KERNEL_VERSION(5, 2, 0) <= LINUX_VERSION_CODE +u16 wlanSelectQueue(struct net_device *dev, + struct sk_buff *skb, + struct net_device *sb_dev); +#elif KERNEL_VERSION(4, 19, 0) <= LINUX_VERSION_CODE +u16 wlanSelectQueue(struct net_device *dev, + struct sk_buff *skb, + struct net_device *sb_dev, + select_queue_fallback_t fallback); +#else +u16 wlanSelectQueue(struct net_device *dev, + struct sk_buff *skb, + void *accel_priv, + select_queue_fallback_t fallback); +#endif + +void wlanDebugInit(void); + +WLAN_STATUS wlanSetDebugLevel(IN u32 u4DbgIdx, IN u32 u4DbgMask); + +WLAN_STATUS wlanGetDebugLevel(IN u32 u4DbgIdx, OUT u32 *pu4DbgMask); + +void wlanSetSuspendMode(P_GLUE_INFO_T prGlueInfo, u8 fgEnable); + +void wlanGetConfig(P_ADAPTER_T prAdapter); + +WLAN_STATUS wlanExtractBufferBin(P_ADAPTER_T prAdapter); + +struct wireless_dev *wlanGetWirelessDevice(void); +/******************************************************************************* + * E X T E R N A L F U N C T I O N S / V A R I A B L E + ******************************************************************************* + */ + +extern struct net_device *gPrP2pDev[KAL_P2P_NUM]; +extern struct net_device *gPrDev; +extern struct wireless_dev *gprWdev; + +#ifdef CFG_DRIVER_INF_NAME_CHANGE +extern char *gprifnameap; +extern char *gprifnamep2p; +extern char *gprifnamesta; +#endif + +extern void wlanRegisterNotifier(void); +extern void wlanUnregisterNotifier(void); + +extern void wlanRegisterRebootNotifier(void); +extern void wlanUnregisterRebootNotifier(void); + +#if CFG_ENABLE_EARLY_SUSPEND +extern int glRegisterEarlySuspend(struct early_suspend *prDesc, + early_suspend_callback wlanSuspend, + late_resume_callback wlanResume); + +extern int glUnregisterEarlySuspend(struct early_suspend *prDesc); +#endif + +u8 glIsReadClearReg(u32 u4Address); + +#if CFG_MET_PACKET_TRACE_SUPPORT +void kalMetTagPacket(IN P_GLUE_INFO_T prGlueInfo, + IN P_NATIVE_PACKET prPacket, + IN ENUM_TX_PROFILING_TAG_T eTag); + +void kalMetInit(IN P_GLUE_INFO_T prGlueInfo); +#endif + +void wlanUpdateChannelTable(P_GLUE_INFO_T prGlueInfo); + +#if CFG_SUPPORT_SAP_DFS_CHANNEL +void wlanUpdateDfsChannelTable(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucChannel); +#endif + +int set_p2p_mode_handler(struct net_device *netdev, + PARAM_CUSTOM_P2P_SET_STRUCT_T p2pmode); + +#if CFG_ENABLE_UNIFY_WIPHY +const struct net_device_ops *wlanGetNdevOps(void); +#endif + +s32 wlanProbe(struct sdio_func *pvData, void *pvDriverData); +void wlanRemove(void); +WLAN_STATUS wlanDownloadBufferBin(P_ADAPTER_T prAdapter); +void wlanGetParseConfig(P_ADAPTER_T prAdapter); +struct net_device_stats *wlanGetStats(IN struct net_device *prDev); +void wlanMonWorkHandler(struct work_struct *work); +void wlanSchedScanStoppedWorkQueue(struct work_struct *work); +void wlanSchedWDevLockWorkQueue(struct work_struct *work); +int wlanDoIOCTL(struct net_device *prDev, struct ifreq *prIfReq, int i4Cmd); + +#endif /* _GL_OS_H */ diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_p2p_ioctl.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_p2p_ioctl.h new file mode 100644 index 00000000000000..ec20a79b818bef --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_p2p_ioctl.h @@ -0,0 +1,744 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_p2p_ioctl.h + * \brief This file is for custom ioctls for Wi-Fi Direct only + */ + +#ifndef _GL_P2P_IOCTL_H +#define _GL_P2P_IOCTL_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include <linux/kernel.h> +#include <linux/netdevice.h> +#include <linux/wireless.h> +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 +#include <linux/ieee80211.h> +#include <net/cfg80211.h> +#endif + +#include "wlan_oid.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* (WirelessExtension) Private I/O Controls */ +#define IOC_P2P_CFG_DEVICE (SIOCIWFIRSTPRIV + 0) +#define IOC_P2P_PROVISION_COMPLETE (SIOCIWFIRSTPRIV + 2) +#define IOC_P2P_START_STOP_DISCOVERY (SIOCIWFIRSTPRIV + 4) +#define IOC_P2P_DISCOVERY_RESULTS (SIOCIWFIRSTPRIV + 5) +#define IOC_P2P_WSC_BEACON_PROBE_RSP_IE (SIOCIWFIRSTPRIV + 6) +#define IOC_P2P_GO_WSC_IE IOC_P2P_WSC_BEACON_PROBE_RSP_IE +#define IOC_P2P_CONNECT_DISCONNECT (SIOCIWFIRSTPRIV + 8) +#define IOC_P2P_PASSWORD_READY (SIOCIWFIRSTPRIV + 10) +/* #define IOC_P2P_SET_PWR_MGMT_PARAM (SIOCIWFIRSTPRIV+12) */ +#define IOC_P2P_SET_INT (SIOCIWFIRSTPRIV + 12) +#define IOC_P2P_GET_STRUCT (SIOCIWFIRSTPRIV + 13) +#define IOC_P2P_SET_STRUCT (SIOCIWFIRSTPRIV + 14) +#define IOC_P2P_GET_REQ_DEVICE_INFO (SIOCIWFIRSTPRIV + 15) + +#define PRIV_CMD_INT_P2P_SET 0 + +/* IOC_P2P_PROVISION_COMPLETE (iw_point . flags) */ +#define P2P_PROVISIONING_SUCCESS 0 +#define P2P_PROVISIONING_FAIL 1 + +/* IOC_P2P_START_STOP_DISCOVERY (iw_point . flags) */ +#define P2P_STOP_DISCOVERY 0 +#define P2P_START_DISCOVERY 1 + +/* IOC_P2P_CONNECT_DISCONNECT (iw_point . flags) */ +#define P2P_CONNECT 0 +#define P2P_DISCONNECT 1 + +/* IOC_P2P_START_STOP_DISCOVERY (scan_type) */ +#define P2P_SCAN_FULL_AND_FIND 0 +#define P2P_SCAN_FULL 1 +#define P2P_SCAN_SEARCH_AND_LISTEN 2 +#define P2P_LISTEN 3 + +/* IOC_P2P_GET_STRUCT/IOC_P2P_SET_STRUCT */ +#define P2P_SEND_SD_RESPONSE 0 +#define P2P_GET_SD_REQUEST 1 +#define P2P_SEND_SD_REQUEST 2 +#define P2P_GET_SD_RESPONSE 3 +#define P2P_TERMINATE_SD_PHASE 4 + +#define CHN_DIRTY_WEIGHT_UPPERBOUND 4 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/* Wireless Extension: Private I/O Control */ +/*----------------------------------------------------------------------------*/ +typedef struct iw_p2p_cfg_device_type { + void __user *ssid; + u8 ssid_len; + u8 pri_device_type[8]; + u8 snd_device_type[8]; + void __user *device_name; + u8 device_name_len; + u8 intend; + u8 persistence; + u8 sec_mode; + u8 ch; + u8 ch_width; /* 0: 20 Mhz 1:20/40 Mhz auto */ + u8 max_scb; +} IW_P2P_CFG_DEVICE_TYPE, *P_IW_P2P_CFG_DEVICE_TYPE; + +typedef struct iw_p2p_hostapd_param { + u8 cmd; + u8 rsv[3]; + u8 sta_addr[6]; + void __user *data; + u16 len; +} IW_P2P_HOSTAPD_PARAM, *P_IW_P2P_HOSTAPD_PARAM; + +typedef struct iw_p2p_req_device_type { + u8 scan_type; /* 0: Full scan + Find + * 1: Full scan + * 2: Scan (Search +Listen) + * 3: Listen + * other : reserved + */ + u8 pri_device_type[8]; + void __user *probe_req_ie; + u16 probe_req_len; + void __user *probe_rsp_ie; + u16 probe_rsp_len; +} IW_P2P_REQ_DEVICE_TYPE, *P_IW_P2P_REQ_DEVICE_TYPE; + +typedef struct iw_p2p_connect_device { + u8 sta_addr[6]; + u8 p2pRole; /* 0: P2P Device, 1:GC, 2: GO */ + u8 needProvision; /* 0: Don't needed provision, 1: doing the wsc + * provision first */ + u8 authPeer; /* 1: auth peer invitation request */ + u8 intend_config_method; /* Request Peer Device used config method */ +} IW_P2P_CONNECT_DEVICE, *P_IW_P2P_CONNECT_DEVICE; + +typedef struct iw_p2p_password_ready { + u8 active_config_method; + void __user *probe_req_ie; + u16 probe_req_len; + void __user *probe_rsp_ie; + u16 probe_rsp_len; +} IW_P2P_PASSWORD_READY, *P_IW_P2P_PASSWORD_READY; + +typedef struct iw_p2p_device_req { + u8 name[33]; + u32 name_len; + u8 device_addr[6]; + u8 device_type; + s32 config_method; + s32 active_config_method; +} IW_P2P_DEVICE_REQ, *P_IW_P2P_DEVICE_REQ; + +typedef struct iw_p2p_transport_struct { + u32 u4CmdId; + u32 inBufferLength; + u32 outBufferLength; + u8 aucBuffer[16]; +} IW_P2P_TRANSPORT_STRUCT, *P_IW_P2P_TRANSPORT_STRUCT; + +/* For Invitation */ +typedef struct iw_p2p_ioctl_invitation_struct { + u8 aucDeviceID[6]; + u8 aucGroupID[6]; /* BSSID */ + u8 aucSsid[32]; + u32 u4SsidLen; + u8 ucReinvoke; +} IW_P2P_IOCTL_INVITATION_STRUCT, *P_IW_P2P_IOCTL_INVITATION_STRUCT; + +typedef struct iw_p2p_ioctl_abort_invitation { + u8 dev_addr[6]; +} IW_P2P_IOCTL_ABORT_INVITATION, *P_IW_P2P_IOCTL_ABORT_INVITATION; + +typedef struct iw_p2p_ioctl_invitation_indicate { + u8 dev_addr[6]; + u8 group_bssid[6]; + s32 config_method; /* peer device supported config method */ + u8 dev_name[32]; /* for reinvoke */ + u32 name_len; + u8 operating_channel; /* for re-invoke, target operating channel */ + u8 invitation_type; /* invitation or re-invoke */ +} IW_P2P_IOCTL_INVITATION_INDICATE, *P_IW_P2P_IOCTL_INVITATION_INDICATE; + +typedef struct iw_p2p_ioctl_invitation_status { + u32 status_code; +} IW_P2P_IOCTL_INVITATION_STATUS, *P_IW_P2P_IOCTL_INVITATION_STATUS; + +/* For Formation */ +typedef struct iw_p2p_ioctl_start_formation { + u8 dev_addr[6]; /* bssid */ + u8 role; /* 0: P2P Device, 1:GC, 2: GO */ + u8 needProvision; /* 0: Don't needed provision, 1: doing the wsc + * provision first */ + u8 auth; /* 1: auth peer invitation request */ + u8 config_method; /* Request Peer Device used config method */ +} IW_P2P_IOCTL_START_FORMATION, *P_IW_P2P_IOCTL_START_FORMATION; + +/* SET_STRUCT / GET_STRUCT */ +typedef enum _ENUM_P2P_CMD_ID_T { + P2P_CMD_ID_SEND_SD_RESPONSE = 0, /* 0x00 (Set) */ + P2P_CMD_ID_GET_SD_REQUEST, /* 0x01 (Get) */ + P2P_CMD_ID_SEND_SD_REQUEST, /* 0x02 (Set) */ + P2P_CMD_ID_GET_SD_RESPONSE, /* 0x03 (Get) */ + P2P_CMD_ID_TERMINATE_SD_PHASE, /* 0x04 (Set) */ + + P2P_CMD_ID_SEC_CHECK, /* 0x05(Set) */ + + P2P_CMD_ID_INVITATION, /* 0x06 (Set) */ + P2P_CMD_ID_INVITATION_INDICATE, /* 0x07 (Get) */ + P2P_CMD_ID_INVITATION_STATUS, /* 0x08 (Get) */ + P2P_CMD_ID_INVITATION_ABORT, /* 0x09 (Set) */ + P2P_CMD_ID_START_FORMATION, /* 0x0A (Set) */ + P2P_CMD_ID_P2P_VERSION, /* 0x0B (Set/Get) */ + P2P_CMD_ID_GET_CH_LIST = 12, /* 0x0C (Get) */ + P2P_CMD_ID_GET_OP_CH = 14 /* 0x0E (Get) */ +} ENUM_P2P_CMD_ID_T, +*P_ENUM_P2P_CMD_ID_T; + +/* Service Discovery */ +typedef struct iw_p2p_cmd_send_sd_response { + PARAM_MAC_ADDRESS rReceiverAddr; + u8 fgNeedTxDoneIndication; + u8 ucSeqNum; + u16 u2PacketLength; + u8 aucPacketContent[0]; /*native 802.11 */ +} IW_P2P_CMD_SEND_SD_RESPONSE, *P_IW_P2P_CMD_SEND_SD_RESPONSE; + +typedef struct iw_p2p_cmd_get_sd_request { + PARAM_MAC_ADDRESS rTransmitterAddr; + u16 u2PacketLength; + u8 aucPacketContent[0]; /*native 802.11 */ +} IW_P2P_CMD_GET_SD_REQUEST, *P_IW_P2P_CMD_GET_SD_REQUEST; + +typedef struct iw_p2p_cmd_send_service_discovery_request { + PARAM_MAC_ADDRESS rReceiverAddr; + u8 fgNeedTxDoneIndication; + u8 ucSeqNum; + u16 u2PacketLength; + u8 aucPacketContent[0]; /*native 802.11 */ +} IW_P2P_CMD_SEND_SD_REQUEST, *P_IW_P2P_CMD_SEND_SD_REQUEST; + +typedef struct iw_p2p_cmd_get_sd_response { + PARAM_MAC_ADDRESS rTransmitterAddr; + u16 u2PacketLength; + u8 aucPacketContent[0]; /*native 802.11 */ +} IW_P2P_CMD_GET_SD_RESPONSE, *P_IW_P2P_CMD_GET_SD_RESPONSE; + +typedef struct iw_p2p_cmd_terminate_sd_phase { + PARAM_MAC_ADDRESS rPeerAddr; +} IW_P2P_CMD_TERMINATE_SD_PHASE, *P_IW_P2P_CMD_TERMINATE_SD_PHASE; + +typedef struct iw_p2p_version { + u32 u4Version; +} IW_P2P_VERSION, *P_IW_P2P_VERSION; + +/*----------------------------------------------------------------------------*/ +/* NL80211 TEST MODE */ +/*----------------------------------------------------------------------------*/ +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +typedef enum _ENUM_TESTMODE_AVAILABLE_CHAN_ATTR { + __NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_INVALID, + NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_2G_BASE_1, + NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_36, + NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_52, + NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_100, + NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_5G_BASE_149, + __NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_AFTER_LAST, + NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_MAX = + __NL80211_TESTMODE_AVAILABLE_CHAN_ATTR_AFTER_LAST - 1 +} ENUM_TESTMODE_AVAILABLE_CHAN_ATTR; +#endif + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +extern struct ieee80211_supported_band mtk_band_2ghz; +extern struct ieee80211_supported_band mtk_band_5ghz; + +extern const u32 mtk_cipher_suites[5]; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +#if (CFG_ENABLE_WIFI_DIRECT_CFG_80211 != 0) + +#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE +struct wireless_dev *mtk_p2p_cfg80211_add_iface(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + struct vif_params *params); +#else +struct wireless_dev *mtk_p2p_cfg80211_add_iface(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); +#endif + +#if KERNEL_VERSION(4, 12, 0) <= CFG80211_VERSION_CODE +int mtk_p2p_cfg80211_change_iface(IN struct wiphy *wiphy, + IN struct net_device *ndev, + IN enum nl80211_iftype type, + IN struct vif_params *params); +#else +int mtk_p2p_cfg80211_change_iface(IN struct wiphy *wiphy, + IN struct net_device *ndev, + IN enum nl80211_iftype type, + IN u32 *flags, + IN struct vif_params *params); +#endif + +int mtk_p2p_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev); + +int mtk_p2p_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index, + bool pairwise, + const u8 *mac_addr, + struct key_params *params); + +int mtk_p2p_cfg80211_get_key(struct wiphy *wiphy, + struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index, + bool pairwise, + const u8 *mac_addr, + void *cookie, + void (*callback)(void *cookie, + struct key_params *)); + +int mtk_p2p_cfg80211_del_key(struct wiphy *wiphy, + struct net_device *ndev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index, + bool pairwise, + const u8 *mac_addr); + +int mtk_p2p_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *netdev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index, + bool unicast, + bool multicast); + +int mtk_p2p_cfg80211_set_mgmt_key(struct wiphy *wiphy, + struct net_device *dev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + int link_id, +#endif + u8 key_index); + +int mtk_p2p_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *mac, + struct station_info *sinfo); + +int mtk_p2p_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request); + +void mtk_p2p_cfg80211_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev); + +int mtk_p2p_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); + +int mtk_p2p_cfg80211_connect(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_connect_params *sme); + +int mtk_p2p_cfg80211_disconnect(struct wiphy *wiphy, + struct net_device *dev, + u16 reason_code); + +int mtk_p2p_cfg80211_join_ibss(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ibss_params *params); + +int mtk_p2p_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev); + +int mtk_p2p_cfg80211_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, + int mbm); + +int mtk_p2p_cfg80211_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + unsigned int link_id, + int *dbm); + +int mtk_p2p_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, + u64 *cookie); + +int mtk_p2p_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie); + +int mtk_p2p_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool enabled, + int timeout); + +int mtk_p2p_cfg80211_start_radar_detection(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, + unsigned int cac_time_ms +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0) + , int link_id +#endif + ); + +int mtk_p2p_cfg80211_channel_switch(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_csa_settings *params); + +int mtk_p2p_cfg80211_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params); + +int mtk_p2p_cfg80211_auth(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_auth_request *req); + +int mtk_p2p_cfg80211_assoc(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_assoc_request *req); + +int mtk_p2p_cfg80211_deauth(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_deauth_request *req); + +int mtk_p2p_cfg80211_disassoc(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_disassoc_request *req); + +int mtk_p2p_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *settings); + +int mtk_p2p_cfg80211_change_beacon(struct wiphy *wiphy, + struct net_device *dev, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0)) + struct cfg80211_beacon_data *info +#else + struct cfg80211_ap_update *info +#endif + ); + +int mtk_p2p_cfg80211_mgmt_tx(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, + u64 *cookie); + +int mtk_p2p_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + struct station_del_parameters *params); + +int mtk_p2p_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie); + +int mtk_p2p_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + , unsigned int link_id +#endif + ); + +int mtk_p2p_cfg80211_set_channel(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef); + +void mtk_p2p_cfg80211_mgmt_frame_register(IN struct wiphy *wiphy, + struct wireless_dev *wdev, + IN u16 frame_type, + IN bool reg); + +int mtk_p2p_cfg80211_set_bitrate_mask(IN struct wiphy *wiphy, + IN struct net_device *dev, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + unsigned int link_id, +#endif + IN const u8 *peer, + IN const struct cfg80211_bitrate_mask * + mask); + +#ifdef CONFIG_NL80211_TESTMODE +int mtk_p2p_cfg80211_testmode_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + void *data, + int len); + +int mtk_p2p_cfg80211_testmode_p2p_sigma_pre_cmd(IN struct wiphy *wiphy, + IN void *data, + IN int len); + +int mtk_p2p_cfg80211_testmode_p2p_sigma_cmd(IN struct wiphy *wiphy, + IN void *data, + IN int len); + +#if CFG_SUPPORT_WFD +int mtk_p2p_cfg80211_testmode_wfd_update_cmd(IN struct wiphy *wiphy, + IN void *data, + IN int len); +#endif + +int mtk_p2p_cfg80211_testmode_hotspot_block_list_cmd(IN struct wiphy *wiphy, + IN void *data, + IN int len); + +#if CFG_AUTO_CHANNEL_SEL_SUPPORT +int mtk_p2p_cfg80211_testmode_get_best_channel(IN struct wiphy *wiphy, + IN void *data, + IN int len); +#endif + +#endif + +#endif + +/* I/O control handlers */ + +int mtk_p2p_wext_get_priv(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_reconnect(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_set_auth(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_set_key(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_mlme_handler(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_set_powermode(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_get_powermode(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +/* Private Wireless I/O Controls takes use of iw_handler */ +int mtk_p2p_wext_set_local_dev_info(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_set_provision_complete(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_start_stop_discovery(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_discovery_results(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_wsc_ie(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_connect_disconnect(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_password_ready(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_request_dev_info(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_invitation_indicate(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_invitation_status(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_set_pm_param(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_set_ps_profile(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_set_network_address(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_set_int(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +/* Private Wireless I/O Controls for IOC_SET_STRUCT/IOC_GET_STRUCT */ +int mtk_p2p_wext_set_struct(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_get_struct(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +/* IOC_SET_STRUCT/IOC_GET_STRUCT: Service Discovery */ +int mtk_p2p_wext_get_service_discovery_request(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_get_service_discovery_response(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_send_service_discovery_request(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_send_service_discovery_response(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_terminate_service_discovery_phase(IN struct net_device *prDev, + IN struct iw_request_info * + info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +#if CFG_SUPPORT_ANTI_PIRACY +int mtk_p2p_wext_set_sec_check_request(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_get_sec_check_response(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); +#endif + +int mtk_p2p_wext_set_noa_param(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_set_oppps_param(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_set_p2p_version(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +int mtk_p2p_wext_get_p2p_version(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +void mtk_p2p_wext_set_Multicastlist(IN P_GLUE_INFO_T prGlueInfo); + +#if CFG_SUPPORT_P2P_RSSI_QUERY +int mtk_p2p_wext_get_rssi(IN struct net_device *prDev, + IN struct iw_request_info *info, + IN OUT union iwreq_data *wrqu, + IN OUT char *extra); + +struct iw_statistics *mtk_p2p_wext_get_wireless_stats(struct net_device *prDev); + +#endif + +int mtk_p2p_wext_set_txpow(IN struct net_device *prDev, + IN struct iw_request_info *prIwrInfo, + IN OUT union iwreq_data *prTxPow, + IN char *pcExtra); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_p2p_kal.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_p2p_kal.h new file mode 100644 index 00000000000000..bb85a0e5afd588 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_p2p_kal.h @@ -0,0 +1,263 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_p2p_kal.h + * \brief Declaration of KAL functions for Wi-Fi Direct support + * - kal*() which is provided by GLUE Layer. + * + * Any definitions in this file will be shared among GLUE Layer and internal + * Driver Stack. + */ + +#ifndef _GL_P2P_KAL_H +#define _GL_P2P_KAL_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "config.h" +#include "gl_typedef.h" +#include "gl_os.h" +#include "wlan_lib.h" +#include "wlan_oid.h" +#include "wlan_p2p.h" +#include "gl_kal.h" +#include "gl_wext_priv.h" +#include "gl_p2p_ioctl.h" +#include "nic/p2p.h" + +#if DBG +extern int allocatedMemSize; +#endif + +u8 kalP2pFuncGetChannelType(IN ENUM_CHNL_EXT_T rChnlSco, + OUT enum nl80211_channel_type *channel_type); + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/* Service Discovery */ +void kalP2PIndicateSDRequest(IN P_GLUE_INFO_T prGlueInfo, + IN PARAM_MAC_ADDRESS rPeerAddr, + IN u8 ucSeqNum); + +void kalP2PIndicateSDResponse(IN P_GLUE_INFO_T prGlueInfo, + IN PARAM_MAC_ADDRESS rPeerAddr, + IN u8 ucSeqNum); + +void kalP2PIndicateTXDone(IN P_GLUE_INFO_T prGlueInfo, + IN u8 ucSeqNum, + IN u8 ucStatus); + +/*----------------------------------------------------------------------------*/ +/* Wi-Fi Direct handling */ +/*----------------------------------------------------------------------------*/ +/*ENUM_PARAM_MEDIA_STATE_T kalP2PGetState(IN P_GLUE_INFO_T prGlueInfo);*/ + +/*void + * kalP2PSetState(IN P_GLUE_INFO_T prGlueInfo, + * IN ENUM_PARAM_MEDIA_STATE_T eState, IN PARAM_MAC_ADDRESS rPeerAddr, IN + * u8 ucRole); + */ + +void kalP2PUpdateAssocInfo(IN P_GLUE_INFO_T prGlueInfo, + IN u8 *pucFrameBody, + IN u32 u4FrameBodyLen, + IN u8 fgReassocRequest, + IN u8 ucBssIndex); + +/*u32 kalP2PGetFreqInKHz(IN P_GLUE_INFO_T prGlueInfo);*/ + +s32 mtk_Netdev_To_RoleIdx(P_GLUE_INFO_T prGlueInfo, + struct net_device *ndev, + u8 *pucRoleIdx); + +u8 kalP2PGetRole(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIdx); + +void kalP2PSetRole(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRole, IN u8 ucRoleIdx); + +void kalP2PSetCipher(IN P_GLUE_INFO_T prGlueInfo, + IN u32 u4Cipher, + IN u8 ucRoleIdx); + +u8 kalP2PGetCipher(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIdx); + +u8 kalP2PGetWepCipher(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIdx); + +u8 kalP2PGetTkipCipher(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIdx); + +u8 kalP2PGetCcmpCipher(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIdx); + +#if CFG_SUPPORT_SUITB +u8 kalP2PGetGcmp256Cipher(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIdx); +#endif + +void kalP2PSetWscMode(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucWscMode); + +u8 kalP2PGetWscMode(IN P_GLUE_INFO_T prGlueInfo); + +u16 kalP2PCalWSC_IELen(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucType, + IN u8 ucRoleIdx); + +void kalP2PGenWSC_IE(IN P_GLUE_INFO_T prGlueInfo, + IN u8 ucType, + IN u8 *pucBuffer, + IN u8 ucRoleIdx); + +void kalP2PUpdateWSC_IE(IN P_GLUE_INFO_T prGlueInfo, + IN u8 ucType, + IN u8 *pucBuffer, + IN u16 u2BufferLength, + IN u8 ucRoleIdx); + +u8 kalP2PIndicateFound(IN P_GLUE_INFO_T prGlueInfo); + +void kalP2PIndicateConnReq(IN P_GLUE_INFO_T prGlueInfo, + IN u8 *pucDevName, + IN s32 u4NameLength, + IN PARAM_MAC_ADDRESS rPeerAddr, + IN u8 ucDevType, + /* 0: P2P Device / 1: GC / 2: GO */ + IN s32 i4ConfigMethod, + IN s32 i4ActiveConfigMethod); + +/*void kalP2PInvitationStatus(IN P_GLUE_INFO_T prGlueInfo, IN u32 + * u4InvStatus);*/ + +void kalP2PInvitationIndication(IN P_GLUE_INFO_T prGlueInfo, + IN P_P2P_DEVICE_DESC_T prP2pDevDesc, + IN u8 *pucSsid, + IN u8 ucSsidLen, + IN u8 ucOperatingChnl, + IN u8 ucInvitationType, + IN u8 *pucGroupBssid); + +struct net_device *kalP2PGetDevHdlr(P_GLUE_INFO_T prGlueInfo); + +void kalGetChnlList(IN P_GLUE_INFO_T prGlueInfo, + IN ENUM_BAND_T eSpecificBand, + IN u8 ucMaxChannelNum, + IN u8 *pucNumOfChannel, + IN P_RF_CHANNEL_INFO_T paucChannelList); + +#if CFG_SUPPORT_ANTI_PIRACY +void kalP2PIndicateSecCheckRsp(IN P_GLUE_INFO_T prGlueInfo, + IN u8 *pucRsp, + IN u16 u2RspLen); +#endif + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +void kalP2PIndicateChannelReady(IN P_GLUE_INFO_T prGlueInfo, + IN u64 u8SeqNum, + IN u32 u4ChannelNum, + IN ENUM_BAND_T eBand, + IN ENUM_CHNL_EXT_T eSco, + IN u32 u4Duration); + +void kalP2PIndicateScanDone(IN P_GLUE_INFO_T prGlueInfo, + IN u8 ucRoleIndex, + IN u8 fgIsAbort); + +void kalP2PIndicateBssInfo(IN P_GLUE_INFO_T prGlueInfo, + IN u8 *pucFrameBuf, + IN u32 u4BufLen, + IN P_RF_CHANNEL_INFO_T prChannelInfo, + IN s32 i4SignalStrength); + +void kalP2PIndicateRxMgmtFrame(IN P_GLUE_INFO_T prGlueInfo, + IN P_SW_RFB_T prSwRfb, + IN u8 fgIsDevInterface, + IN u8 ucRoleIdx); + +void kalP2PIndicateMgmtTxStatus(IN P_GLUE_INFO_T prGlueInfo, + IN P_MSDU_INFO_T prMsduInfo, + IN u8 fgIsAck); + +void kalP2PIndicateChannelExpired(IN P_GLUE_INFO_T prGlueInfo, + IN u64 u8SeqNum, + IN u32 u4ChannelNum, + IN ENUM_BAND_T eBand, + IN ENUM_CHNL_EXT_T eSco); + +void kalP2PGCIndicateConnectionStatus(IN P_GLUE_INFO_T prGlueInfo, + IN u8 ucRoleIndex, + IN P_P2P_CONNECTION_REQ_INFO_T + prP2pConnInfo, + IN u8 *pucRxIEBuf, + IN u16 u2RxIELen, + IN u16 u2StatusReason, + IN WLAN_STATUS eStatus); + +void kalP2PGOStationUpdate(IN P_GLUE_INFO_T prGlueInfo, + IN u8 ucRoleIndex, + IN P_STA_RECORD_T prCliStaRec, + IN u8 fgIsNew); + +#if (CFG_SUPPORT_DFS_MASTER == 1) +void kalP2PRddDetectUpdate(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIndex); + +void kalP2PCacFinishedUpdate(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucRoleIndex); +#endif + +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER + +u8 kalP2PSetBlackList(IN P_GLUE_INFO_T prGlueInfo, + IN PARAM_MAC_ADDRESS rbssid, + IN u8 fgIsblock, + IN u8 ucRoleIndex); + +u8 kalP2PCmpBlackList(IN P_GLUE_INFO_T prGlueInfo, + IN PARAM_MAC_ADDRESS rbssid, + IN u8 ucRoleIndex); + +void kalP2PSetMaxClients(IN P_GLUE_INFO_T prGlueInfo, + IN u32 u4MaxClient, + IN u8 ucRoleIndex); + +u8 kalP2PMaxClients(IN P_GLUE_INFO_T prGlueInfo, + IN u32 u4NumClient, + IN u8 ucRoleIndex); + +#endif + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_p2p_os.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_p2p_os.h new file mode 100644 index 00000000000000..6d461d96b526d6 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_p2p_os.h @@ -0,0 +1,296 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_p2p_os.h + * \brief List the external reference to OS for p2p GLUE Layer. + * + * In this file we define the data structure - GLUE_INFO_T to store those + * objects we acquired from OS - e.g. TIMER, SPINLOCK, NET DEVICE ... . And all + * the external reference (header file, extern func() ..) to OS for GLUE Layer + * should also list down here. + */ + +#ifndef _GL_P2P_OS_H +#define _GL_P2P_OS_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L V A R I A B L E + ******************************************************************************* + */ + +#if CFG_ENABLE_WIFI_DIRECT && CFG_ENABLE_WIFI_DIRECT_CFG_80211 +extern const struct net_device_ops p2p_netdev_ops; +#endif + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +extern struct net_device *g_P2pPrDev; +extern struct wireless_dev *gprP2pWdev; +extern struct wireless_dev *gprP2pRoleWdev[KAL_P2P_NUM]; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +struct _GL_P2P_INFO_T { + /* P2P Device interface handle */ + /*only first p2p have this devhandler*/ + struct net_device *prDevHandler; + /*struct net_device *prRoleDevHandler;*/ /* TH3 multiple P2P */ + + struct net_device *aprRoleHandler; + + /* Todo : should move to the glueinfo or not*/ + /*u8 ucRoleInterfaceNum;*/ /* TH3 multiple P2P */ + +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + /* cfg80211 */ + struct wireless_dev *prWdev; + /*struct wireless_dev *prRoleWdev[KAL_P2P_NUM];*/ /* TH3 multiple P2P */ + + /*struct cfg80211_scan_request *prScanRequest;*/ /* TH3 multiple P2P */ + + /*u64 u8Cookie;*/ /* TH3 multiple P2P */ + + /* Generation for station list update. */ + s32 i4Generation; + + /*u32 u4OsMgmtFrameFilter;*/ /* TH3 multiple P2P */ +#endif + + /* Device statistics */ + /*struct net_device_stats rNetDevStats;*/ /* TH3 multiple P2P */ + + /* glue layer variables */ + /*move to glueinfo->adapter */ + /* u8 fgIsRegistered; */ + /*u32 u4FreqInKHz;*/ /* TH3 multiple P2P */ /* frequency */ + u8 ucRole; /* 0: P2P Device, 1: Group Client, 2: Group Owner */ + /*u8 ucIntent;*/ /* TH3 multiple P2P */ /* range: 0-15 */ + /*u8 ucScanMode;*/ + /* TH3 multiple P2P */ /* 0: Search & Listen, 1: Scan without probe + * response */ + + /*ENUM_PARAM_MEDIA_STATE_T eState;*/ /* TH3 multiple P2P */ + /*u32 u4PacketFilter;*/ /* TH3 multiple P2P */ + /*PARAM_MAC_ADDRESS aucMCAddrList[MAX_NUM_GROUP_ADDR];*/ /* TH3 multiple + * P2P + */ + + /* connection-requested peer information */ /* TH3 multiple P2P */ + /*u8 aucConnReqDevName[32];*/ /* TH3 multiple P2P */ + /*s32 u4ConnReqNameLength;*/ /* TH3 multiple P2P */ + /*PARAM_MAC_ADDRESS rConnReqPeerAddr;*/ /* TH3 multiple P2P */ + /*PARAM_MAC_ADDRESS rConnReqGroupAddr;*/ + /* TH3 multiple P2P */ /* For invitation group. */ + /*u8 ucConnReqDevType;*/ /* TH3 multiple P2P */ + /*s32 i4ConnReqConfigMethod;*/ /* TH3 multiple P2P */ + /*s32 i4ConnReqActiveConfigMethod;*/ /* TH3 multiple P2P */ + + u32 u4CipherPairwise; + /*u8 ucWSCRunning;*/ /* TH3 multiple P2P */ + + u8 aucWSCIE[4][400]; /* 0 for beacon, 1 for probe req, 2 for probe + * response, 3 for assoc response */ + u16 u2WSCIELen[4]; + +#if CFG_SUPPORT_WFD + u8 aucWFDIE[400]; /* 0 for beacon, 1 for probe req, 2 for probe response + */ + u16 u2WFDIELen; + /* u8 aucVenderIE[1024]; */ /* Save the other IE + * for + * prove resp */ +/* u16 u2VenderIELen; */ +#endif + +#if (CFG_SUPPORT_DFS_MASTER == 1) + struct cfg80211_chan_def *chandef; + u32 cac_time_ms; +#endif + +#if CFG_SUPPORT_HOTSPOT_WPS_MANAGER + /* Hotspot Client Management */ + /* dependent with #define P2P_MAXIMUM_CLIENT_COUNT 10, + * fix me to PARAM_MAC_ADDRESS + * aucblackMACList[P2P_MAXIMUM_CLIENT_COUNT]; + */ + PARAM_MAC_ADDRESS aucblackMACList[10]; + u8 ucMaxClients; +#endif + +#if CFG_SUPPORT_HOTSPOT_OPTIMIZATION + /*u8 fgEnableHotspotOptimization;*/ /* TH3 multiple P2P */ + /*u32 u4PsLevel;*/ /* TH3 multiple P2P */ +#endif + +#if 0 + u8 fgIsNetDevRegistered; +#endif +}; + +struct _GL_P2P_DEV_INFO_T { +#if CFG_ENABLE_WIFI_DIRECT_CFG_80211 + struct cfg80211_scan_request *prScanRequest; +#if (CFG_ENABLE_UNIFY_WIPHY == 0) + struct cfg80211_scan_request rBackupScanRequest; +#endif + u64 u8Cookie; + u32 u4OsMgmtFrameFilter; +#endif + u32 u4PacketFilter; + PARAM_MAC_ADDRESS aucMCAddrList[MAX_NUM_GROUP_ADDR]; + u8 ucWSCRunning; +}; + +#ifdef CONFIG_NL80211_TESTMODE +typedef struct _NL80211_DRIVER_TEST_PRE_PARAMS { + u16 idx_mode; + u16 idx; + u32 value; +} NL80211_DRIVER_TEST_PRE_PARAMS, *P_NL80211_DRIVER_TEST_PRE_PARAMS; + +typedef struct _NL80211_DRIVER_TEST_PARAMS { + u32 index; + u32 buflen; +} NL80211_DRIVER_TEST_PARAMS, *P_NL80211_DRIVER_TEST_PARAMS; + +/* P2P Sigma*/ +typedef struct _NL80211_DRIVER_P2P_SIGMA_PARAMS { + NL80211_DRIVER_TEST_PARAMS hdr; + u32 idx; + u32 value; +} NL80211_DRIVER_P2P_SIGMA_PARAMS, *P_NL80211_DRIVER_P2P_SIGMA_PARAMS; + +/* Hotspot Client Management */ +typedef struct _NL80211_DRIVER_hotspot_block_PARAMS { + NL80211_DRIVER_TEST_PARAMS hdr; + u8 ucblocked; + u8 aucBssid[MAC_ADDR_LEN]; +} NL80211_DRIVER_hotspot_block_PARAMS, *P_NL80211_DRIVER_hotspot_block_PARAMS; + +#if CFG_SUPPORT_WFD +typedef struct _NL80211_DRIVER_WFD_PARAMS { + NL80211_DRIVER_TEST_PARAMS hdr; + u32 WfdCmdType; + u8 WfdEnable; + u8 WfdCoupleSinkStatus; + u8 WfdSessionAvailable; + u8 WfdSigmaMode; + u16 WfdDevInfo; + u16 WfdControlPort; + u16 WfdMaximumTp; + u16 WfdExtendCap; + u8 WfdCoupleSinkAddress[MAC_ADDR_LEN]; + u8 WfdAssociatedBssid[MAC_ADDR_LEN]; + u8 WfdVideoIp[4]; + u8 WfdAudioIp[4]; + u16 WfdVideoPort; + u16 WfdAudioPort; + u32 WfdFlag; + u32 WfdPolicy; + u32 WfdState; + u8 WfdSessionInformationIE[24 * 8]; /* Include Subelement ID, length */ + u16 WfdSessionInformationIELen; + u8 aucReserved1[2]; + u8 aucWfdPrimarySinkMac[MAC_ADDR_LEN]; + u8 aucWfdSecondarySinkMac[MAC_ADDR_LEN]; + u32 WfdAdvanceFlag; + /* Group 1 64 bytes */ + u8 aucWfdLocalIp[4]; + u16 WfdLifetimeAc2; /* Unit is 2 TU */ + u16 WfdLifetimeAc3; /* Unit is 2 TU */ + u16 WfdCounterThreshold; /* Unit is ms */ + u8 aucReserved2[54]; + /* Group 3 64 bytes */ + u8 aucReserved3[64]; + /* Group 3 64 bytes */ + u8 aucReserved4[64]; +} NL80211_DRIVER_WFD_PARAMS, *P_NL80211_DRIVER_WFD_PARAMS; +#endif +#endif + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +u8 p2pRegisterToWlan(P_GLUE_INFO_T prGlueInfo); + +u8 p2pUnregisterToWlan(P_GLUE_INFO_T prGlueInfo); + +u8 p2pLaunch(P_GLUE_INFO_T prGlueInfo); + +u8 p2pRemove(P_GLUE_INFO_T prGlueInfo); + +void p2pSetMode(IN u8 ucAPMode); + +u8 glRegisterP2P(P_GLUE_INFO_T prGlueInfo, + const char *prDevName, + const char *prDevName2, + u8 ucApMode); + + +#if CFG_ENABLE_UNIFY_WIPHY +int glSetupP2P(P_GLUE_INFO_T prGlueInfo, struct wireless_dev *prP2pWdev, + struct net_device *prP2pDev, int u4Idx, u8 fgIsApMode); +#endif +u8 glUnregisterP2P(P_GLUE_INFO_T prGlueInfo, u8 ucIdx); + +u8 p2pNetRegister(P_GLUE_INFO_T prGlueInfo, u8 fgIsRtnlLockAcquired); + +u8 p2pNetUnregister(P_GLUE_INFO_T prGlueInfo, u8 fgIsRtnlLockAcquired); + +#if CFG_ENABLE_UNIFY_WIPHY +u8 p2PAllocInfo(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucIdex); +#endif +u8 p2PFreeInfo(P_GLUE_INFO_T prGlueInfo, u8 ucIdx); + +void p2pSetSuspendMode(P_GLUE_INFO_T prGlueInfo, u8 fgEnable); +u8 glP2pCreateWirelessDevice(P_GLUE_INFO_T prGlueInfo); +void glP2pDestroyWirelessDevice(void); +void p2pUpdateChannelTableByDomain(P_GLUE_INFO_T prGlueInfo); +u8 p2PAllocInfo(IN P_GLUE_INFO_T prGlueInfo, IN u8 ucIdex); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_qa_agent.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_qa_agent.h new file mode 100644 index 00000000000000..e23f8e2a21979f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_qa_agent.h @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_qa_agent.h + * \brief This file includes private ioctl support. + */ + +#ifndef _GL_QA_AGENT_H +#define _GL_QA_AGENT_H +#if CFG_SUPPORT_QA_TOOL +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +#define HQA_CMD_MAGIC_NO 0x18142880 +#define HQA_CHIP_ID_6632 0x6632 +#define HQA_CHIP_ID_7668 0x7668 + +#if CFG_SUPPORT_TX_BF +#define HQA_BF_STR_SIZE 512 +#endif + +#define HQA_RX_STATISTIC_NUM 66 +#define BUFFER_BIN_MODE 0x0 +#define EFUSE_MODE 0x2 + +extern u8 uacEEPROMImage[MAX_EEPROM_BUFFER_SIZE]; + +typedef struct _PARAM_RX_STAT_T { + u32 MAC_FCS_Err; /* b0 */ + u32 MAC_Mdrdy; /* b0 */ + u32 FCSErr_CCK; + u32 FCSErr_OFDM; + u32 CCK_PD; + u32 OFDM_PD; + u32 CCK_SIG_Err; + u32 CCK_SFD_Err; + u32 OFDM_SIG_Err; + u32 OFDM_TAG_Err; + u32 WB_RSSI0; + u32 IB_RSSI0; + u32 WB_RSSI1; + u32 IB_RSSI1; + u32 PhyMdrdyCCK; + u32 PhyMdrdyOFDM; + u32 DriverRxCount; + u32 RCPI0; + u32 RCPI1; + u32 FreqOffsetFromRX; + u32 RSSI0; + u32 RSSI1; /* insert new member here */ + u32 OutOfResource; /* MT7615 begin here */ + u32 LengthMismatchCount_B0; + u32 MAC_FCS_Err1; /* b1 */ + u32 MAC_Mdrdy1; /* b1 */ + u32 FAGCRssiIBR0; + u32 FAGCRssiIBR1; + u32 FAGCRssiIBR2; + u32 FAGCRssiIBR3; + u32 FAGCRssiWBR0; + u32 FAGCRssiWBR1; + u32 FAGCRssiWBR2; + u32 FAGCRssiWBR3; + + u32 InstRssiIBR0; + u32 InstRssiIBR1; + u32 InstRssiIBR2; + u32 InstRssiIBR3; + u32 InstRssiWBR0; + u32 InstRssiWBR1; + u32 InstRssiWBR2; + u32 InstRssiWBR3; + u32 ACIHitLower; + u32 ACIHitUpper; + u32 DriverRxCount1; + u32 RCPI2; + u32 RCPI3; + u32 RSSI2; + u32 RSSI3; + u32 SNR0; + u32 SNR1; + u32 SNR2; + u32 SNR3; + u32 OutOfResource1; + u32 LengthMismatchCount_B1; + u32 CCK_PD_Band1; + u32 OFDM_PD_Band1; + u32 CCK_SIG_Err_Band1; + u32 CCK_SFD_Err_Band1; + u32 OFDM_SIG_Err_Band1; + u32 OFDM_TAG_Err_Band1; + u32 PHY_CCK_MDRDY_Band1; + u32 PHY_OFDM_MDRDY_Band1; + u32 CCK_FCS_Err_Band1; + u32 OFDM_FCS_Err_Band1; + u32 MRURxCount; + u32 SIGMCS; + u32 SINR; + u32 RXVRSSI; + u32 Reserved[184]; + u32 PHY_Mdrdy; + u32 Noise_Floor; + u32 AllLengthMismatchCount_B0; + u32 AllLengthMismatchCount_B1; + u32 AllMacMdrdy0; + u32 AllMacMdrdy1; + u32 AllFCSErr0; + u32 AllFCSErr1; + u32 RXOK0; + u32 RXOK1; + u32 PER0; + u32 PER1; +} PARAM_RX_STAT_T, *P_PARAM_RX_STAT_T; +extern PARAM_RX_STAT_T g_HqaRxStat; + +typedef struct _HQA_CMD_FRAME { + u32 MagicNo; + u16 Type; + u16 Id; + u16 Length; + u16 Sequence; + u8 Data[2000]; +} __packed HQA_CMD_FRAME; + +typedef s32 (*HQA_CMD_HANDLER)(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame); + +typedef struct _HQA_CMD_TABLE { + HQA_CMD_HANDLER *CmdSet; + u32 CmdSetSize; + u32 CmdOffset; +} HQA_CMD_TABLE; + +int HQA_CMDHandler(struct net_device *prNetDev, + IN union iwreq_data *prIwReqData, + HQA_CMD_FRAME *HqaCmdFrame); + +int priv_qa_agent(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN char *pcExtra); + +int priv_set_eeprom_mode(IN u32 u4Mode); +#endif +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_sec.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_sec.h new file mode 100644 index 00000000000000..91081cae012e8f --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_sec.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file p2p_fsm.h + * \brief Declaration of functions and finite state machine for P2P Module. + * + * Declaration of functions and finite state machine for P2P Module. + */ + +#ifndef _GL_SEC_H +#define _GL_SEC_H + +extern void handle_sec_msg_1(unsigned char *msg_in, + int msg_in_len, + unsigned char *msg_out, + int *msg_out_len); +extern void handle_sec_msg_2(unsigned char *msg_in, + int msg_in_len, + unsigned char *msg_out, + int *msg_out_len); +extern void handle_sec_msg_3(unsigned char *msg_in, + int msg_in_len, + unsigned char *msg_out, + int *msg_out_len); +extern void handle_sec_msg_4(unsigned char *msg_in, + int msg_in_len, + unsigned char *msg_out, + int *msg_out_len); +extern void handle_sec_msg_5(unsigned char *msg_in, + int msg_in_len, + unsigned char *msg_out, + int *msg_out_len); +extern void handle_sec_msg_final(unsigned char *msg_in, + int msg_in_len, + unsigned char *msg_out, + int *msg_out_len); + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_typedef.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_typedef.h new file mode 100644 index 00000000000000..3a6762c121975c --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_typedef.h @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_typedef.h + * \brief Definition of basic data type(os dependent). + * + * In this file we define the basic data type. + */ + +#ifndef _GL_TYPEDEF_H +#define _GL_TYPEDEF_H + +#include <linux/mmc/ioctl.h> +#include <linux/mmc/sdio.h> +#include <linux/mmc/sdio_func.h> + +#if CFG_ENABLE_EARLY_SUSPEND +#include <linux/earlysuspend.h> +#endif + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* Define HZ of timer tick for function kalGetTimeTick() */ +#define KAL_HZ (1000) + +#ifndef NULL +#if defined(__cplusplus) +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +#if CFG_ENABLE_EARLY_SUSPEND +typedef void (*early_suspend_callback)(struct early_suspend *h); +typedef void (*late_resume_callback)(struct early_suspend *h); +#endif + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* Type definition of large integer (64bits) union to be comptaible with + * Windows definition, so we won't apply our own coding style to these data + * types. NOTE: LARGE_INTEGER must NOT be floating variable. <TODO>: Check for + * big-endian compatibility. + */ +typedef union _LARGE_INTEGER { + struct { + u32 LowPart; + s32 HighPart; + } u; + s64 QuadPart; +} LARGE_INTEGER, *PLARGE_INTEGER; + +typedef union _ULARGE_INTEGER { + struct { + u32 LowPart; + u32 HighPart; + } u; + u64 QuadPart; +} ULARGE_INTEGER, *PULARGE_INTEGER; + +typedef s32 (*probe_card)(struct sdio_func *pvData, void *pvDriverData); +typedef void (*remove_card)(void); + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define IN /* volatile */ +#define OUT /* volatile */ + +#define __KAL_INLINE__ inline +#define __KAL_ATTRIB_PACKED__ __attribute__((__packed__)) +#define __KAL_ATTRIB_ALIGN_4__ __aligned(4) + +#ifndef BIT +#define BIT(n) ((u32)1UL << (n)) +#endif + +#ifndef BITS +/* bits range: for example BITS(16,23) = 0xFF0000 + * ==> (BIT(m)-1) = 0x0000FFFF ~(BIT(m)-1) => 0xFFFF0000 + * ==> (BIT(n+1)-1) = 0x00FFFFFF + */ +#define BITS(m, n) (~(BIT(m) - 1) & ((BIT(n) - 1) | BIT(n))) +#endif + +/* This macro returns the byte offset of a named field in a known structure + * type. + * _type - structure name, + * _field - field name of the structure + */ +#ifndef OFFSET_OF +#define OFFSET_OF(_type, _field) ((unsigned long)&(((_type *)0)->_field)) +#endif + +/* This macro returns the base address of an instance of a structure + * given the type of the structure and the address of a field within the + * containing structure. + * _addrOfField - address of current field of the structure, + * _type - structure name, + * _field - field name of the structure + */ +#ifndef ENTRY_OF +#define ENTRY_OF(_addrOfField, _type, _field) \ + ((_type *)((s8 *)(_addrOfField) - (s8 *)OFFSET_OF(_type, _field))) +#endif + +/* This macro align the input value to the DW boundary. + * _value - value need to check + */ +#ifndef ALIGN_4 +#define ALIGN_4(_value) (((_value) + 3) & ~3u) +#endif + +/* This macro check the DW alignment of the input value. + * _value - value of address need to check + */ +#ifndef IS_ALIGN_4 +#define IS_ALIGN_4(_value) (((_value) & 0x3) ? false : true) +#endif + +#ifndef IS_NOT_ALIGN_4 +#define IS_NOT_ALIGN_4(_value) (((_value) & 0x3) ? true : false) +#endif + +/* This macro evaluate the input length in unit of Double Word(4 Bytes). + * _value - value in unit of Byte, output will round up to DW boundary. + */ +#ifndef BYTE_TO_DWORD +#define BYTE_TO_DWORD(_value) ((_value + 3) >> 2) +#endif + +/* This macro evaluate the input length in unit of Byte. + * _value - value in unit of DW, output is in unit of Byte. + */ +#ifndef DWORD_TO_BYTE +#define DWORD_TO_BYTE(_value) ((_value) << 2) +#endif + +#define CONST_NTOHS(_x) ntohs(_x) + +#define CONST_HTONS(_x) htons(_x) + +#define NTOHS(_x) ntohs(_x) + +#define HTONS(_x) htons(_x) + +#define NTOHL(_x) ntohl(_x) + +#define HTONL(_x) htonl(_x) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_wext.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_wext.h new file mode 100644 index 00000000000000..29923abd1e5ace --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_wext.h @@ -0,0 +1,316 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_wext.h + * \brief This file is for Portable Driver linux wireless extension support. + */ + +#ifndef _GL_WEXT_H +#define _GL_WEXT_H + +#ifdef WIRELESS_EXT +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +extern void wlanUpdateChannelTable(P_GLUE_INFO_T prGlueInfo); + +/* for IE Searching */ +extern u8 wextSrchDesiredWPAIE(IN u8 *pucIEStart, + IN s32 i4TotalIeLen, + IN u8 ucDesiredElemId, + OUT u8 **ppucDesiredIE); + +#if CFG_SUPPORT_WPS +extern u8 wextSrchDesiredWPSIE(IN u8 *pucIEStart, + IN s32 i4TotalIeLen, + IN u8 ucDesiredElemId, + OUT u8 **ppucDesiredIE); +#endif + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define KILO 1000 +#define RATE_5_5M 11 /* 5.5M */ + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef struct _PARAM_FIXED_IEs { + u8 aucTimestamp[8]; + u16 u2BeaconInterval; + u16 u2Capabilities; +} PARAM_FIXED_IEs; + +typedef struct _PARAM_VARIABLE_IE_T { + u8 ucElementID; + u8 ucLength; + u8 aucData[1]; +} PARAM_VARIABLE_IE_T, *P_PARAM_VARIABLE_IE_T; + +#if WIRELESS_EXT < 18 + +#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses struct iw_mlme */ +/* MLME requests (SIOCSIWMLME / struct iw_mlme) */ +#define IW_MLME_DEAUTH 0 +#define IW_MLME_DISASSOC 1 + +/*! \brief SIOCSIWMLME data */ +struct iw_mlme { + __u16 cmd; /*!< IW_MLME_**/ + __u16 reason_code; + struct sockaddr addr; +}; + +#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */ +#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */ +/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ +#define IW_AUTH_INDEX 0x0FFF +#define IW_AUTH_FLAGS 0xF000 +/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095) + * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the + * parameter that is being set/get to; value will be read/written to + * struct iw_param value field) + */ +#define IW_AUTH_WPA_VERSION 0 +#define IW_AUTH_CIPHER_PAIRWISE 1 +#define IW_AUTH_CIPHER_GROUP 2 +#define IW_AUTH_KEY_MGMT 3 +#define IW_AUTH_TKIP_COUNTERMEASURES 4 +#define IW_AUTH_DROP_UNENCRYPTED 5 +#define IW_AUTH_80211_AUTH_ALG 6 +#define IW_AUTH_WPA_ENABLED 7 +#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 +#define IW_AUTH_ROAMING_CONTROL 9 +#define IW_AUTH_PRIVACY_INVOKED 10 +#if CFG_SUPPORT_802_11W +#define IW_AUTH_MFP 12 + +#define IW_AUTH_MFP_DISABLED 0 /* MFP disabled */ +#define IW_AUTH_MFP_OPTIONAL 1 /* MFP optional */ +#define IW_AUTH_MFP_REQUIRED 2 /* MFP required */ +#endif + +/* IW_AUTH_WPA_VERSION values (bit field) */ +#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 +#define IW_AUTH_WPA_VERSION_WPA 0x00000002 +#define IW_AUTH_WPA_VERSION_WPA2 0x00000004 + +/* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */ +#define IW_AUTH_CIPHER_NONE 0x00000001 +#define IW_AUTH_CIPHER_WEP40 0x00000002 +#define IW_AUTH_CIPHER_TKIP 0x00000004 +#define IW_AUTH_CIPHER_CCMP 0x00000008 +#define IW_AUTH_CIPHER_WEP104 0x00000010 + +/* IW_AUTH_KEY_MGMT values (bit field) */ +#define IW_AUTH_KEY_MGMT_802_1X 1 +#define IW_AUTH_KEY_MGMT_PSK 2 +#define IW_AUTH_KEY_MGMT_WPA_NONE 4 + +/* IW_AUTH_80211_AUTH_ALG values (bit field) */ +#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 +#define IW_AUTH_ALG_SHARED_KEY 0x00000002 +#define IW_AUTH_ALG_LEAP 0x00000004 + +/* IW_AUTH_ROAMING_CONTROL values */ +#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */ +#define IW_AUTH_ROAMING_DISABLE \ + 1 /* user space program used for roaming control */ + +#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */ +#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */ +/* SIOCSIWENCODEEXT definitions */ +#define IW_ENCODE_SEQ_MAX_SIZE 8 +/* struct iw_encode_ext ->alg */ +#define IW_ENCODE_ALG_NONE 0 +#define IW_ENCODE_ALG_WEP 1 +#define IW_ENCODE_ALG_TKIP 2 +#define IW_ENCODE_ALG_CCMP 3 +#if CFG_SUPPORT_802_11W +#define IW_ENCODE_ALG_AES_CMAC 5 +#endif + +/* struct iw_encode_ext ->ext_flags */ +#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 +#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 +#define IW_ENCODE_EXT_GROUP_KEY 0x00000004 +#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008 + +struct iw_encode_ext { + __u32 ext_flags; /*!< IW_ENCODE_EXT_**/ + __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ + __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /*!< LSB first */ + struct sockaddr addr; /*!< ff:ff:ff:ff:ff:ff for broadcast/multicast + * (group) keys or unicast address for + * individual keys + */ + __u16 alg; /*!< IW_ENCODE_ALG_**/ + __u16 key_len; + __u8 key[0]; +}; + +#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */ +#define IW_PMKSA_ADD 1 +#define IW_PMKSA_REMOVE 2 +#define IW_PMKSA_FLUSH 3 + +#define IW_PMKID_LEN 16 + +struct iw_pmksa { + __u32 cmd; /*!< IW_PMKSA_**/ + struct sockaddr bssid; + __u8 pmkid[IW_PMKID_LEN]; +}; + +#define IWEVGENIE \ + 0x8C05 /* Generic IE (WPA, RSN, WMM, ..) \ + * (scan results); This includes id and \ + * length fields. One IWEVGENIE may \ + * contain more than one IE. Scan \ + * results may contain one or more \ + * IWEVGENIE events. \ + */ +#define IWEVMICHAELMICFAILURE \ + 0x8C06 /* Michael MIC failure \ + * (struct iw_michaelmicfailure) \ + */ +#define IWEVASSOCREQIE \ + 0x8C07 /* IEs used in (Re)Association Request. \ + * The data includes id and length \ + * fields and may contain more than one \ + * IE. This event is required in \ + * Managed mode if the driver \ + * generates its own WPA/RSN IE. This \ + * should be sent just before \ + * IWEVREGISTERED event for the \ + * association. \ + */ +#define IWEVASSOCRESPIE \ + 0x8C08 /* IEs used in (Re)Association \ + * Response. The data includes id and \ + * length fields and may contain more \ + * than one IE. This may be sent \ + * between IWEVASSOCREQIE and \ + * IWEVREGISTERED events for the \ + * association. \ + */ +#define IWEVPMKIDCAND \ + 0x8C09 /* PMKID candidate for RSN \ + * pre-authentication \ + * (struct iw_pmkid_cand) \ + */ + +#endif + +#if WIRELESS_EXT < 17 +/* Statistics flags (bitmask in updated) */ +#define IW_QUAL_QUAL_UPDATED 0x1 /* Value was updated since last read */ +#define IW_QUAL_LEVEL_UPDATED 0x2 +#define IW_QUAL_NOISE_UPDATED 0x4 +#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ +#define IW_QUAL_LEVEL_INVALID 0x20 +#define IW_QUAL_NOISE_INVALID 0x40 +#endif + +enum { + IEEE80211_FILTER_TYPE_BEACON = 1 << 0, + IEEE80211_FILTER_TYPE_PROBE_REQ = 1 << 1, + IEEE80211_FILTER_TYPE_PROBE_RESP = 1 << 2, + IEEE80211_FILTER_TYPE_ASSOC_REQ = 1 << 3, + IEEE80211_FILTER_TYPE_ASSOC_RESP = 1 << 4, + IEEE80211_FILTER_TYPE_AUTH = 1 << 5, + IEEE80211_FILTER_TYPE_DEAUTH = 1 << 6, + IEEE80211_FILTER_TYPE_DISASSOC = 1 << 7, + IEEE80211_FILTER_TYPE_ALL = 0xFF /* used to check the valid filter bits + */ +}; + +// #define IW_AUTH_WAPI_ENABLED 0x20 +// #define IW_ENCODE_ALG_SMS4 0x20 + +// #define IW_AUTH_KEY_MGMT_WAPI_PSK 3 +// #define IW_AUTH_KEY_MGMT_WAPI_CERT 4 +#define IW_AUTH_KEY_MGMT_WPS 5 + +#if CFG_SUPPORT_802_11W +#define IW_AUTH_KEY_MGMT_802_1X_SHA256 7 +#define IW_AUTH_KEY_MGMT_PSK_SHA256 8 +#endif + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +extern const struct iw_handler_def wext_handler_def; + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/* wireless extensions' ioctls */ +int wext_support_ioctl(IN struct net_device *prDev, + IN struct ifreq *prIfReq, + IN int i4Cmd); + +int wext_set_rate(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN struct iw_param *prRate, + IN char *pcExtra); + +void wext_indicate_wext_event(IN P_GLUE_INFO_T prGlueInfo, + IN unsigned int u4Cmd, + IN unsigned char *pucData, + IN unsigned int u4DataLen); + +struct iw_statistics *wext_get_wireless_stats(struct net_device *prDev); + +u8 wextSrchDesiredWPAIE(IN u8 *pucIEStart, + IN s32 i4TotalIeLen, + IN u8 ucDesiredElemId, + OUT u8 **ppucDesiredIE); + +#if CFG_SUPPORT_WPS +u8 wextSrchDesiredWPSIE(IN u8 *pucIEStart, + IN s32 i4TotalIeLen, + IN u8 ucDesiredElemId, + OUT u8 **ppucDesiredIE); +#endif + +u8 wextSrchDesiredWAPIIE(IN u8 *pucIEStart, + IN s32 i4TotalIeLen, + OUT u8 **ppucDesiredIE); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_wext_priv.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_wext_priv.h new file mode 100644 index 00000000000000..705008a0305119 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/gl_wext_priv.h @@ -0,0 +1,588 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file gl_wext_priv.h + * \brief This file includes private ioctl support. + */ + +#ifndef _GL_WEXT_PRIV_H +#define _GL_WEXT_PRIV_H +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/* If it is set to 1, iwpriv will support register read/write */ +#define CFG_SUPPORT_PRIV_MCR_RW 1 + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +/* New wireless extensions API - SET/GET convention (even ioctl numbers are + * root only) + */ +#define IOCTL_SET_INT (SIOCIWFIRSTPRIV + 0) +#define IOCTL_GET_INT (SIOCIWFIRSTPRIV + 1) + +#define IOCTL_SET_ADDRESS (SIOCIWFIRSTPRIV + 2) +#define IOCTL_GET_ADDRESS (SIOCIWFIRSTPRIV + 3) +#define IOCTL_SET_STR (SIOCIWFIRSTPRIV + 4) +#define IOCTL_GET_STR (SIOCIWFIRSTPRIV + 5) +#define IOCTL_SET_KEY (SIOCIWFIRSTPRIV + 6) +#define IOCTL_GET_KEY (SIOCIWFIRSTPRIV + 7) +#define IOCTL_SET_STRUCT (SIOCIWFIRSTPRIV + 8) +#define IOCTL_GET_STRUCT (SIOCIWFIRSTPRIV + 9) +#define IOCTL_SET_STRUCT_FOR_EM (SIOCIWFIRSTPRIV + 11) +#define IOCTL_SET_INTS (SIOCIWFIRSTPRIV + 12) +#define IOCTL_GET_INTS (SIOCIWFIRSTPRIV + 13) +#define IOCTL_SET_DRIVER (SIOCIWFIRSTPRIV + 14) +#define IOCTL_GET_DRIVER (SIOCIWFIRSTPRIV + 15) + +#if CFG_SUPPORT_QA_TOOL +#define IOCTL_QA_TOOL_DAEMON (SIOCIWFIRSTPRIV + 16) +#define IOCTL_IWPRIV_ATE (SIOCIWFIRSTPRIV + 17) +#endif + +#define PRIV_CMD_REG_DOMAIN 0 +#define PRIV_CMD_BEACON_PERIOD 1 +#define PRIV_CMD_ADHOC_MODE 2 + +#if CFG_TCP_IP_CHKSUM_OFFLOAD +#define PRIV_CMD_CSUM_OFFLOAD 3 +#endif + +#define PRIV_CMD_ROAMING 4 +#define PRIV_CMD_VOIP_DELAY 5 +#define PRIV_CMD_POWER_MODE 6 + +#define PRIV_CMD_WMM_PS 7 +#define PRIV_CMD_BT_COEXIST 8 +#define PRIV_GPIO2_MODE 9 + +#define PRIV_CUSTOM_SET_PTA 10 +#define PRIV_CUSTOM_CONTINUOUS_POLL 11 +#define PRIV_CUSTOM_SINGLE_ANTENNA 12 +#define PRIV_CUSTOM_BWCS_CMD 13 +#define PRIV_CUSTOM_DISABLE_BEACON_DETECTION 14 /* later */ +#define PRIV_CMD_OID 15 +#define PRIV_SEC_MSG_OID 16 + +#define PRIV_CMD_TEST_MODE 17 +#define PRIV_CMD_TEST_CMD 18 +#define PRIV_CMD_ACCESS_MCR 19 +#define PRIV_CMD_SW_CTRL 20 + +#define PRIV_SEC_CHECK_OID 21 + +#define PRIV_CMD_WSC_PROBE_REQ 22 + +#define PRIV_CMD_P2P_VERSION 23 + +#define PRIV_CMD_GET_CH_LIST 24 + +#define PRIV_CMD_SET_TX_POWER 25 + +#define PRIV_CMD_BAND_CONFIG 26 + +#define PRIV_CMD_DUMP_MEM 27 + +#define PRIV_CMD_P2P_MODE 28 + +#if CFG_SUPPORT_QA_TOOL +#define PRIV_QACMD_SET 29 +#endif + +#define PRIV_CMD_MET_PROFILING 33 + +#if CFG_WOW_SUPPORT +#define PRIV_CMD_SET_WOW_ENABLE 34 +#define PRIV_CMD_SET_WOW_PAR 35 +#endif + +/* 802.3 Objects (Ethernet) */ +#define OID_802_3_CURRENT_ADDRESS 0x01010102 + +/* IEEE 802.11 OIDs */ +#define OID_802_11_SUPPORTED_RATES 0x0D01020E +#define OID_802_11_CONFIGURATION 0x0D010211 + +/* PnP and PM OIDs, NDIS default OIDS */ +#define OID_PNP_SET_POWER 0xFD010101 + +#define OID_CUSTOM_OID_INTERFACE_VERSION 0xFFA0C000 + +/* MT5921 specific OIDs */ +#define OID_CUSTOM_BT_COEXIST_CTRL 0xFFA0C580 +#define OID_CUSTOM_POWER_MANAGEMENT_PROFILE 0xFFA0C581 +#define OID_CUSTOM_PATTERN_CONFIG 0xFFA0C582 +#define OID_CUSTOM_BG_SSID_SEARCH_CONFIG 0xFFA0C583 +#define OID_CUSTOM_VOIP_SETUP 0xFFA0C584 +#define OID_CUSTOM_ADD_TS 0xFFA0C585 +#define OID_CUSTOM_DEL_TS 0xFFA0C586 +#define OID_CUSTOM_SLT 0xFFA0C587 +#define OID_CUSTOM_ROAMING_EN 0xFFA0C588 +#define OID_CUSTOM_WMM_PS_TEST 0xFFA0C589 +#define OID_CUSTOM_COUNTRY_STRING 0xFFA0C58A +#define OID_CUSTOM_MULTI_DOMAIN_CAPABILITY 0xFFA0C58B +#define OID_CUSTOM_GPIO2_MODE 0xFFA0C58C +#define OID_CUSTOM_CONTINUOUS_POLL 0xFFA0C58D +#define OID_CUSTOM_DISABLE_BEACON_DETECTION 0xFFA0C58E + +/* CR1460, WPS privacy bit check disable */ +#define OID_CUSTOM_DISABLE_PRIVACY_CHECK 0xFFA0C600 + +/* Precedent OIDs */ +#define OID_CUSTOM_MCR_RW 0xFFA0C801 +#define OID_CUSTOM_EEPROM_RW 0xFFA0C803 +#define OID_CUSTOM_SW_CTRL 0xFFA0C805 +#define OID_CUSTOM_MEM_DUMP 0xFFA0C807 + +/* RF Test specific OIDs */ +#define OID_CUSTOM_TEST_MODE 0xFFA0C901 +#define OID_CUSTOM_TEST_RX_STATUS 0xFFA0C903 +#define OID_CUSTOM_TEST_TX_STATUS 0xFFA0C905 +#define OID_CUSTOM_ABORT_TEST_MODE 0xFFA0C906 +#define OID_CUSTOM_MTK_WIFI_TEST 0xFFA0C911 +#define OID_CUSTOM_TEST_ICAP_MODE 0xFFA0C913 + +/* BWCS */ +#define OID_CUSTOM_BWCS_CMD 0xFFA0C931 +#define OID_CUSTOM_SINGLE_ANTENNA 0xFFA0C932 +#define OID_CUSTOM_SET_PTA 0xFFA0C933 + +/* NVRAM */ +#define OID_CUSTOM_MTK_NVRAM_RW 0xFFA0C941 +#define OID_CUSTOM_CFG_SRC_TYPE 0xFFA0C942 +#define OID_CUSTOM_EEPROM_TYPE 0xFFA0C943 + +// #define OID_802_11_WAPI_MODE 0xFFA0CA00 +// #define OID_802_11_WAPI_ASSOC_INFO 0xFFA0CA01 +// #define OID_802_11_SET_WAPI_KEY 0xFFA0CA02 + +#if CFG_SUPPORT_WPS2 +#define OID_802_11_WSC_ASSOC_INFO 0xFFA0CB00 +#endif + +/* Define magic key of test mode (Don't change it for future compatibity) */ +#define PRIV_CMD_TEST_MAGIC_KEY 2011 +#define PRIV_CMD_TEST_MAGIC_KEY_ICAP 2013 + +/* CFG_SUPPORT_ADVANCE_CONTROL */ +#define TX_RATE_MODE_CCK 0 +#define TX_RATE_MODE_OFDM 1 +#define TX_RATE_MODE_HTMIX 2 +#define TX_RATE_MODE_HTGF 3 +#define TX_RATE_MODE_VHT 4 +#define MAX_TX_MODE 5 + +#if CFG_SUPPORT_ADVANCE_CONTROL +#define CMD_SW_DBGCTL_ADVCTL_SET_ID 0xa1260000 +#define CMD_SW_DBGCTL_ADVCTL_GET_ID 0xb1260000 +#define CMD_SET_NOISE "SET_NOISE" +#define CMD_GET_NOISE "GET_NOISE" +#define CMD_AFH_RANGE_CONFIG "AFH_RANGE_CONFIG" +#define CMD_PTA_CONFIG "PTA_CONFIG" +#define CMD_PTA_TAG_CONFIG "PTA_TAG_CONFIG" +#define CMD_BA_SIZE_CONFIG "BA_SIZE_CONFIG" +#define CMD_TRAFFIC_REPORT "TRAFFIC_REPORT" +#define CMD_ADMINCTRL_CONFIG "ADMINCTRL" +#define CMD_SET_POP "SET_POP" +#define CMD_GET_POP "GET_POP" +#define CMD_SET_ED "SET_ED" +#define CMD_GET_ED "GET_ED" +#define CMD_SET_PD "SET_PD" +#define CMD_GET_PD "GET_PD" +#define CMD_SET_MAX_RFGAIN "SET_MAX_RFGAIN" +#define CMD_GET_MAX_RFGAIN "GET_MAX_RFGAIN" +#define CMD_NOISE_HISTOGRAM "NOISE_HISTOGRAM" +#define CMD_SET_ADM_CTRL "SET_ADM" +#define CMD_SET_BCN_TH "SET_BCN_TH" +#define CMD_GET_BCN_TH "GET_BCN_TH" +#define CMD_SET_DEWEIGHTING_TH "SET_DEWEIGHTING_TH" +#define CMD_GET_DEWEIGHTING_TH "GET_DEWEIGHTING_TH" +#define CMD_GET_DEWEIGHTING_NOISE "GET_DEWEIGHTING_NOISE" +#define CMD_GET_DEWEIGHTING_WEIGHT "GET_DEWEIGHTING_WEIGHT" +#define CMD_SET_ACT_INTV "SET_ACT_INTV" +#define CMD_SET_1RPD "SET_1RPD" +#define CMD_GET_1RPD "GET_1RPD" +#define CMD_SET_MMPS "SET_MMPS" +#define CMD_GET_MMPS "GET_MMPS" +#define CMD_ENFORCE_POWER_MODE "ENFORCE_POWER_MODE" +#define CMD_GET_POWER_MODE "GET_POWER_MODE" +#if CFG_SUPPORT_802_11K +#define CMD_NEIGHBOR_REQUEST "NEIGHBOR-REQUEST" +#endif +#if CFG_SUPPORT_802_11V_BSS_TRANSITION_MGT +#define CMD_BSS_TRANSITION_QUERY "BSS-TRANSITION-QUERY" +#endif + +#define CMD_GET_1XTX_STATUS "GET_1XTX_STATUS" +#define CMD_TEST_1XTX_STATUS "TEST_1XTX_STATUS" + +#ifdef CFG_SUPPORT_EXT_PTA_DEBUG_COMMAND +#define CMD_EXT_PTA_CONFIG "EXT_PTA_CONFIG" +#endif +#if CFG_RX_SINGLE_CHAIN_SUPPORT +#define CMD_SET_RXC "SET_RXC" +#define CMD_GET_RXC "GET_RXC" +#endif + +#define CMD_GET_BCNTIMEOUT_NUM "GET_BCNTIMEOUT_NUM" +#define CMD_SET_EVERY_TBTT "SET_EVERY_TBTT" +#define CMD_GET_EVERY_TBTT "GET_EVERY_TBTT" + +enum { + CMD_ADVCTL_NOISE_ID = 1, + CMD_ADVCTL_POP_ID, + CMD_ADVCTL_ED_ID, + CMD_ADVCTL_PD_ID, + CMD_ADVCTL_MAX_RFGAIN_ID, + CMD_ADVCTL_ADM_CTRL_ID, + CMD_ADVCTL_BCN_TH_ID = 9, + CMD_ADVCTL_DEWEIGHTING_TH_ID, + CMD_ADVCTL_DEWEIGHTING_NOISE_ID, + CMD_ADVCTL_DEWEIGHTING_WEIGHT_ID, + CMD_ADVCTL_ACT_INTV_ID, + CMD_ADVCTL_1RPD, + CMD_ADVCTL_MMPS, +#if CFG_RX_SINGLE_CHAIN_SUPPORT + CMD_ADVCTL_RXC_ID = 17, +#endif + CMD_ADVCTL_SNR_ID = 18, + CMD_ADVCTL_BCNTIMOUT_NUM_ID = 19, + CMD_ADVCTL_EVERY_TBTT_ID = 20, + CMD_ADVCTL_MAX +}; +#endif + +#define COEX_REF_TABLE_ID_ISO_DETECTION_VALUE 1 +#define COEX_REF_TABLE_ID_COEX_FDD_PARAM 2 +#define COEX_REF_TABLE_ID_COEX_WMT_CONFIG 3 +#define COEX_REF_TABLE_ID_ACTIVE_BSSID 4 +#define COEX_REF_TABLE_ID_COEX_MODE 5 +#define COEX_REF_TABLE_ID_HYBRID_MODE 6 +#define COEX_REF_TABLE_ID_COEX_ISO 7 +#define COEX_REF_TABLE_ID_COEX_CHANNEL_INFO 8 +#define COEX_REF_TABLE_ID_COEX_BT_PROFILE 9 +#define COEX_REF_TABLE_ID_BT_LONGRX_DISABLE_WFTX 10 +#define COEX_REF_TABLE_ID_BT_PORT 11 +#define COEX_REF_TABLE_ID_BTTX_POWER 12 +#define COEX_REF_TABLE_ID_TDD_BAND 13 +#define COEX_REF_TABLE_ID_PER_PKT_STAT 30 +#define COEX_REF_TABLE_ID_PER_PKT_BT_HIT_CNT 31 +#define COEX_REF_TABLE_ID_PER_PKT_RX_PROTECT_CTL 32 +#define COEX_REF_TABLE_ID_PER_PKT_WF_PROTTIME 33 +#define COEX_REF_TABLE_ID_PER_PKT_BT_DURATION 34 +#define COEX_REF_TABLE_ID_BTRX_GAIN_INFO 35 +#define COEX_REF_TABLE_ID_BTTX_PWR_DIST 36 +#define COEX_REF_TABLE_ID_WFRX_GAIN_DIST 37 + +#define IW_PRIV_BUF_SIZE 2000 + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/* NIC BBCR configuration entry structure */ +typedef struct _PRIV_CONFIG_ENTRY { + u8 ucOffset; + u8 ucValue; +} PRIV_CONFIG_ENTRY, *PPRIV_CONFIG_ENTRY; + +typedef WLAN_STATUS (*PFN_OID_HANDLER_FUNC_REQ)(IN void *prAdapter, + IN OUT void *pvBuf, + IN u32 u4BufLen, + OUT u32 *pu4OutInfoLen); + +typedef enum _ENUM_OID_METHOD_T { + ENUM_OID_GLUE_ONLY, + ENUM_OID_GLUE_EXTENSION, + ENUM_OID_DRIVER_CORE +} ENUM_OID_METHOD_T, +*P_ENUM_OID_METHOD_T; + +/* OID set/query processing entry */ +typedef struct _WLAN_REQ_ENTRY { + u32 rOid; /* OID */ + u8 *pucOidName; /* OID name text */ + u8 fgQryBufLenChecking; + u8 fgSetBufLenChecking; + ENUM_OID_METHOD_T eOidMethod; + u32 u4InfoBufLen; + PFN_OID_HANDLER_FUNC_REQ pfOidQueryHandler; /* PFN_OID_HANDLER_FUNC */ + PFN_OID_HANDLER_FUNC_REQ pfOidSetHandler; /* PFN_OID_HANDLER_FUNC */ +} WLAN_REQ_ENTRY, *P_WLAN_REQ_ENTRY; + +typedef struct _NDIS_TRANSPORT_STRUCT { + u32 ndisOidCmd; + u32 inNdisOidlength; + u32 outNdisOidLength; + u8 ndisOidContent[16]; +} NDIS_TRANSPORT_STRUCT, *P_NDIS_TRANSPORT_STRUCT; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +int priv_set_int(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN char *pcExtra); + +int priv_get_int(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN OUT char *pcExtra); + +int priv_set_ints(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN char *pcExtra); + +int priv_get_ints(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN OUT char *pcExtra); + +int priv_set_struct(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN char *pcExtra); + +int priv_get_struct(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN OUT char *pcExtra); + +int priv_set_driver(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN OUT char *pcExtra); + +int priv_support_ioctl(IN struct net_device *prDev, + IN OUT struct ifreq *prReq, + IN int i4Cmd); + +int priv_support_driver_cmd(IN struct net_device *prDev, + IN OUT struct ifreq *prReq, + IN int i4Cmd); + +#ifdef CFG_ANDROID_AOSP_PRIV_CMD +int android_private_support_driver_cmd(IN struct net_device *prDev, + IN OUT struct ifreq *prReq, + IN int i4Cmd); +#endif + +s32 priv_driver_cmds(IN struct net_device *prNetDev, + IN s8 *pcCommand, + IN s32 i4TotalLen); + +int priv_driver_set_cfg(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen); + +#if CFG_SUPPORT_QA_TOOL +int priv_qa_agent(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN char *pcExtra); +int priv_ate_set(IN struct net_device *prNetDev, + IN struct iw_request_info *prIwReqInfo, + IN union iwreq_data *prIwReqData, + IN char *pcExtra); +#endif + +int wext_get_priv(IN struct net_device *prNetDev, OUT struct iw_point *prData); + +int priv_driver_get_chip_config(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_set_ap_start(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_get_linkspeed(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_set_band(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_set_txpower(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +#if CFG_SUPPORT_DBDC_TC6 +int priv_driver_set_csa(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); +#endif + +int priv_driver_set_country(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_get_country(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_set_suspend_mode(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +#if CFG_SUPPORT_SNIFFER +int priv_driver_set_monitor(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); +#endif + +#if CFG_SUPPORT_DBDC +int priv_driver_set_dbdc(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); +#endif + +int priv_driver_set_p2p_ps(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_get_channels(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_get_ap_channels(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +#if (CFG_SUPPORT_DFS_MASTER == 1) +int priv_driver_show_dfs_state(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); +#endif + +int priv_driver_show_dfs_abd123_param(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_show_dfs_help(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_show_dfs_cac_time(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_set_rdd_report(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_clean_dfs_abd123_param(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_set_abd123_detect_mode(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_set_miracast(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +void priv_driver_get_chip_config_16(u8 *pucStartAddr, u32 u4Length, u32 u4Line, + int i4TotalLen, s32 i4BytesWritten, + char *pcCommand); + +void priv_driver_get_chip_config_4(u32 *pu4StartAddr, u32 u4Length, u32 u4Line, + int i4TotalLen, s32 i4BytesWritten, + char *pcCommand); + +int priv_driver_set_drv_mcr(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_set_sw_ctrl(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_set_fixed_rate(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +#ifdef CFG_SUPPORT_MULTICAST_ENHANCEMENT +int priv_driver_set_fixed_mrate(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); +#endif + +int priv_driver_set_dup_mpacket(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_get_dup_mpacket(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_set_mcast_burst(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_get_mcast_burst(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_set_txop(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_get_txop(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_set_11mc_type(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_get_11mc_type(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_set_unicast_burst(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_get_unicast_burst(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_set_unicast_burst_timeout(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_get_unicast_burst_timeout(IN struct net_device *prNetDev, + IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_set_mrm_clinet(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_get_mrm_client(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_set_audio_tos(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_get_audio_tos(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_set_chip_config(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +int priv_driver_get_cfg(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_set_mcr(IN struct net_device *prNetDev, IN char *pcCommand, + IN int i4TotalLen); + +int priv_driver_get_dbg_level(IN struct net_device *prNetDev, + IN char *pcCommand, IN int i4TotalLen); + +u32 batchChannelNum2Freq(u32 u4ChannelNum); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/hif.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/hif.h new file mode 100644 index 00000000000000..f6d3eaa31a02e9 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/hif.h @@ -0,0 +1,297 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "hif.h" + * \brief Functions for the driver to register bus and setup the IRQ + * + * Functions for the driver to register bus and setup the IRQ + */ + +#ifndef _HIF_H +#define _HIF_H + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +#define HIF_SDIO_SUPPORT_GPIO_SLEEP_MODE 0 + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define HIF_NAME "SDIO" + +/* Enable driver timing profiling */ +#define CFG_SDIO_TIMING_PROFILING 0 + +#define SDIO_X86_WORKAROUND_WRITE_MCR 0x00C4 +#define HIF_NUM_OF_QM_RX_PKT_NUM 512 + +#define HIF_TX_INIT_CMD_PORT TX_RING_FWDL_IDX_3 + +#define HIF_IST_LOOP_COUNT 128 +#define HIF_IST_TX_THRESHOLD \ + 32 /* Min msdu count to trigger Tx during INT polling state */ + +#define HIF_TX_MAX_AGG_LENGTH (511 * 512) /* 511 blocks x 512 */ + +#define HIF_RX_MAX_AGG_NUM 16 +/*!< Setting the maximum RX aggregation number 0: no limited (16) */ + +#define HIF_TX_BUFF_COUNT_TC0 8 +#define HIF_TX_BUFF_COUNT_TC1 167 +#define HIF_TX_BUFF_COUNT_TC2 8 +#define HIF_TX_BUFF_COUNT_TC3 8 +#define HIF_TX_BUFF_COUNT_TC4 7 +#define HIF_TX_BUFF_COUNT_TC5 0 + +#define HIF_TX_RESOURCE_CTRL 1 /* enable/disable TX resource control */ + +#define HIF_TX_PAGE_SIZE_IN_POWER_OF_2 11 +#define HIF_TX_PAGE_SIZE 2048 /* in unit of bytes */ + +#define HIF_EXTRA_IO_BUFFER_SIZE \ + (sizeof(ENHANCE_MODE_DATA_STRUCT_T) + \ + HIF_RX_COALESCING_BUF_COUNT * HIF_RX_COALESCING_BUFFER_SIZE) + +#define HIF_CR4_FWDL_SECTION_NUM 2 +#define HIF_IMG_DL_STATUS_PORT_IDX 0 + +#define HIF_RX_ENHANCE_MODE_PAD_LEN 4 + +#define HIF_TX_TERMINATOR_LEN 4 + +#if CFG_SDIO_TX_AGG +#define HIF_TX_COALESCING_BUFFER_SIZE (HIF_TX_MAX_AGG_LENGTH) +#else +#define HIF_TX_COALESCING_BUFFER_SIZE (CFG_TX_MAX_PKT_SIZE) +#endif + +#if CFG_SDIO_RX_AGG +#define HIF_RX_COALESCING_BUFFER_SIZE \ + ((HIF_RX_MAX_AGG_NUM + 1) * CFG_RX_MAX_PKT_SIZE) +#else +#define HIF_RX_COALESCING_BUFFER_SIZE (CFG_RX_MAX_PKT_SIZE) +#endif + +#if CFG_SDIO_RX_AGG_TASKLET +#define HIF_RX_COALESCING_BUF_COUNT 16 +#else +#define HIF_RX_COALESCING_BUF_COUNT 1 +#endif + +/* WHISR device to host (D2H) */ +/* N9 Interrupt Host to stop tx/rx operation (at the moment, HIF tx/rx are + * stopted) */ +#define SER_SDIO_N9_HOST_STOP_TX_RX_OP BIT(8) +/* N9 Interrupt Host to stop tx operation (at the moment, HIF tx are stopted) */ +#define SER_SDIO_N9_HOST_STOP_TX_OP BIT(9) +/* N9 Interrupt Host all modules were reset done (to let host reinit HIF) */ +#define SER_SDIO_N9_HOST_RESET_DONE BIT(10) +/* N9 Interrupt Host System Error Recovery Done */ +#define SER_SDIO_N9_HOST_RECOVERY_DONE BIT(11) + +/* WSICR host to device (H2D) */ +/* Host ACK HIF tx/rx ring stop operatio */ +#define SER_SDIO_HOST_N9_STOP_TX_RX_OP_ACK BIT(19) +/* Host interrupt N9 HIF init done */ +#define SER_SDIO_HOST_N9_RESET_DONE_ACK BIT(20) +/* Host interrupt N9 System Error Recovery done */ +#define SER_SDIO_HOST_N9_RECOVERY_DONE_ACK BIT(21) + +/* HIF SDIO WMM Tx resource flow control */ +#if CFG_TX_WMM_ENHANCE +#define HIF_TX_RSRC_WMM_ENHANCE 1 +#else +#define HIF_TX_RSRC_WMM_ENHANCE 0 +#endif + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +typedef struct _ENHANCE_MODE_DATA_STRUCT_T SDIO_CTRL_T, *P_SDIO_CTRL_T; + +typedef struct _SDIO_STAT_COUNTER_T { + /* Tx data */ + u32 u4DataPortWriteCnt; + u32 u4DataPktWriteCnt; + u32 u4DataPortKickCnt; + + /* Tx command */ + u32 u4CmdPortWriteCnt; + u32 u4CmdPktWriteCnt; + + /* Tx done interrupt */ + u32 u4TxDoneCnt[16]; + u32 u4TxDoneIntCnt[16]; + u32 u4TxDoneIntTotCnt; + u32 u4TxDonePendingPktCnt; + + u32 u4IntReadCnt; + u32 u4IntCnt; + + /* Rx data/cmd*/ + u32 u4PortReadCnt[2]; + u32 u4PktReadCnt[2]; + + u32 u4RxBufUnderFlowCnt; + +#if CFG_SDIO_TIMING_PROFILING + u32 u4TxDataCpTime; + u32 u4TxDataFreeTime; + + u32 u4RxDataCpTime; + u32 u4PortReadTime; + + u32 u4TxDoneIntTime; + u32 u4IntReadTime; +#endif +} SDIO_STAT_COUNTER_T, *P_SDIO_STAT_COUNTER_T; + +typedef struct _SDIO_RX_COALESCING_BUF_T { + QUE_ENTRY_T rQueEntry; + void *pvRxCoalescingBuf; + u32 u4BufSize; + u32 u4PktCount; +} SDIO_RX_COALESCING_BUF_T, *P_SDIO_RX_COALESCING_BUF_T; + +/* host interface's private data structure, which is attached to os glue +** layer info structure. +*/ +typedef struct _GL_HIF_INFO_T { + struct sdio_func *func; + + P_SDIO_CTRL_T prSDIOCtrl; + + u8 fgIntReadClear; + u8 fgMbxReadClear; + QUE_T rFreeQueue; + u8 fgIsPendingInt; + +#if (HIF_TX_RSRC_WMM_ENHANCE == 1) + /*17 = TC_NUM*/ + u32 au4PendingTxDoneCount[17]; +#else + u32 au4PendingTxDoneCount[6]; +#endif + /* Statistic counter */ + SDIO_STAT_COUNTER_T rStatCounter; + + SDIO_RX_COALESCING_BUF_T rRxCoalesingBuf[HIF_RX_COALESCING_BUF_COUNT]; + + QUE_T rRxDeAggQueue; + QUE_T rRxFreeBufQueue; + + struct mutex rRxFreeBufQueMutex; + struct mutex rRxDeAggQueMutex; +} GL_HIF_INFO_T, *P_GL_HIF_INFO_T; + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#if CFG_SDIO_TIMING_PROFILING +#define SDIO_TIME_INTERVAL_DEC() KAL_TIME_INTERVAL_DECLARATION() +#define SDIO_REC_TIME_START() KAL_REC_TIME_START() +#define SDIO_REC_TIME_END() KAL_REC_TIME_END() +#define SDIO_GET_TIME_INTERVAL() KAL_GET_TIME_INTERVAL() +#define SDIO_ADD_TIME_INTERVAL(_Interval) KAL_ADD_TIME_INTERVAL(_Interval) +#else +#define SDIO_TIME_INTERVAL_DEC() +#define SDIO_REC_TIME_START() +#define SDIO_REC_TIME_END() +#define SDIO_GET_TIME_INTERVAL() +#define SDIO_ADD_TIME_INTERVAL(_Interval) +#endif + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +WLAN_STATUS glRegisterBus(probe_card pfProbe, remove_card pfRemove); + +void glUnregisterBus(remove_card pfRemove); + +void glSetHifInfo(P_GLUE_INFO_T prGlueInfo, unsigned long ulCookie); + +void glClearHifInfo(P_GLUE_INFO_T prGlueInfo); + +u8 glBusInit(void *pvData); + +s32 glBusSetIrq(void *pvData, void *pfnIsr, void *pvCookie); + +void glBusFreeIrq(void *pvData, void *pvCookie); + +void glGetDev(void *ctx, struct device **dev); + +void glGetHifDev(P_GL_HIF_INFO_T prHif, struct device **dev); + +u8 glWakeupSdio(P_GLUE_INFO_T prGlueInfo); + +#if !CFG_SDIO_INTR_ENHANCE +void halRxSDIOReceiveRFBs(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS halRxReadBuffer(IN P_ADAPTER_T prAdapter, + IN OUT P_SW_RFB_T prSwRfb); + +#else +void halRxSDIOEnhanceReceiveRFBs(IN P_ADAPTER_T prAdapter); + +WLAN_STATUS halRxEnhanceReadBuffer(IN P_ADAPTER_T prAdapter, + IN u32 u4DataPort, + IN u16 u2RxLength, + IN OUT P_SW_RFB_T prSwRfb); + +void halProcessEnhanceInterruptStatus(IN P_ADAPTER_T prAdapter); + +#endif + +#if CFG_SDIO_RX_AGG +void halRxSDIOAggReceiveRFBs(IN P_ADAPTER_T prAdapter); +#endif + +void halPutMailbox(IN P_ADAPTER_T prAdapter, IN u32 u4MailboxNum, + IN u32 u4Data); +void halGetMailbox(IN P_ADAPTER_T prAdapter, + IN u32 u4MailboxNum, + OUT u32 *pu4Data); +void halDeAggRxPkt(P_ADAPTER_T prAdapter, P_SDIO_RX_COALESCING_BUF_T prRxBuf); +void halPrintMailbox(IN P_ADAPTER_T prAdapter); +void halPollDbgCr(IN P_ADAPTER_T prAdapter, IN u32 u4LoopCount); +u8 halDeAggRxPktProc(P_ADAPTER_T prAdapter, P_SDIO_RX_COALESCING_BUF_T prRxBuf); +void halTxInterruptSanityCheck(IN P_ADAPTER_T prAdapter, IN u16 *au2TxRlsCnt); +void halPrintFirmwareAssertInfo(IN P_ADAPTER_T prAdapter); +u8 halTxCalculateResource(IN P_ADAPTER_T prAdapter, IN u16 *au2TxRlsCnt, + OUT u16 *au2FreeTcResource); +u8 halTxReleaseResource(IN P_ADAPTER_T prAdapter, IN u16 *au2TxRlsCnt); + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/version.h b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/version.h new file mode 100644 index 00000000000000..e32a3ee681946e --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/include/version.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "version.h" + * \brief Driver's version definition + * + */ + +#ifndef _VERSION_H +#define _VERSION_H +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#ifndef NIC_AUTHOR +#define NIC_AUTHOR "NIC_AUTHOR" +#endif +#ifndef NIC_DESC +#define NIC_DESC "NIC_DESC" +#endif + +#ifndef NIC_NAME +#define NIC_NAME "MT6632" +#define NIC_DEVICE_ID "MT6632" +#define NIC_DEVICE_ID_LOW "mt6632" +#endif + +/* NIC driver information */ +#define NIC_VENDOR "MediaTek Inc." +#define NIC_VENDOR_OUI \ + { \ + 0x00, 0x0C, 0xE7 \ + } + +#define NIC_PRODUCT_NAME "MediaTek Inc. Wireless LAN Adapter" +#define NIC_DRIVER_NAME "MediaTek Inc. Wireless LAN Adapter Driver" + +/* Define our driver version */ +#define NIC_DRIVER_MAJOR_VERSION 1 +#define NIC_DRIVER_MINOR_VERSION 1 +#define NIC_DRIVER_SERIAL_VERSION 0 +#define NIC_DRIVER_VERSION \ + (NIC_DRIVER_MAJOR_VERSION, NIC_DRIVER_MINOR_VERSION, \ + NIC_DRIVER_SERIAL_VERSION) + +#define STR(s) #s +#define XSTR(x) STR(x) +#define NDV(v) XSTR(NIC_DRIVER_ ## v ## _VERSION) +#define NDV_STR(a, i, s) NDV(a) "." NDV(i) "." NDV(s) +#define NIC_DRIVER_VERSION_STRING NDV_STR(MAJOR, MINOR, SERIAL) + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +#endif diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/platform.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/platform.c new file mode 100644 index 00000000000000..5f412f88fe8bd0 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/platform.c @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ + +/*! \file "platform.c" + * \brief This file including the protocol layer privacy function. + * + * This file provided the macros and functions library support for the + * protocol layer security setting from wlan_oid.c and for parse.c and + * rsn.c and nic_privacy.c + * + */ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include <linux/version.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/module.h> +#include <linux/fs.h> + +#include <linux/uaccess.h> +#include "precomp.h" +#include "gl_os.h" + +#if CFG_ENABLE_EARLY_SUSPEND +#include <linux/earlysuspend.h> +#endif + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define WIFI_NVRAM_FILE_NAME "/lib/firmware/WIFI" +#define WIFI_NVRAM_CUSTOM_NAME "/data/nvram/APCFG/APRDEB/WIFI_CUSTOM" + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ +static int netdev_event(struct notifier_block *nb, unsigned long notification, + void *ptr) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; + struct net_device *prDev = ifa->ifa_dev->dev; + P_GLUE_INFO_T prGlueInfo = NULL; + + if (prDev == NULL) { + /* DBGLOG(REQ, INFO, ("netdev_event: device is empty.\n")); */ + return NOTIFY_DONE; + } + + if ((strncmp(prDev->name, "p2p", 3) != 0) && + (strncmp(prDev->name, "wlan", 4) != 0)) { + /* DBGLOG(REQ, INFO, ("netdev_event: xxx\n")); */ + return NOTIFY_DONE; + } + + if ((prDev != gPrDev) && (prDev != gPrP2pDev[0]) && + (prDev != gPrP2pDev[1])) { + /* DBGLOG(REQ, INFO, ("netdev_event: device is not mine.\n")); + */ + return NOTIFY_DONE; + } + + prGlueInfo = *((P_GLUE_INFO_T *)netdev_priv(prDev)); + if (prGlueInfo == NULL) { + DBGLOG(REQ, INFO, "netdev_event: prGlueInfo is empty.\n"); + return NOTIFY_DONE; + } + +#if CFG_GARP_KEEPALIVE + // garp keepalive needs IP address update when host is awake +#else + if (prGlueInfo->fgIsInSuspendMode == false) { + /* DBGLOG(REQ, INFO, + * ("netdev_event: PARAM_MEDIA_STATE_DISCONNECTED. (%d)\n", + * prGlueInfo->eParamMediaStateIndicated)); + */ + return NOTIFY_DONE; + } +#endif // CFG_GARP_KEEPALIVE + + kalSetNetAddressFromInterface(prGlueInfo, prDev, true); + + return NOTIFY_DONE; +} + +static struct notifier_block inetaddr_notifier = { + .notifier_call = netdev_event, +}; + +void wlanRegisterNotifier(void) +{ +#if CFG_ENABLE_NET_DEV_NOTIFY + register_inetaddr_notifier(&inetaddr_notifier); +#endif +} + +void wlanUnregisterNotifier(void) +{ +#if CFG_ENABLE_NET_DEV_NOTIFY + unregister_inetaddr_notifier(&inetaddr_notifier); +#endif +} + +#if CFG_ENABLE_EARLY_SUSPEND +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will register platform driver to os + * + * \param[in] wlanSuspend Function pointer to platform suspend function + * \param[in] wlanResume Function pointer to platform resume function + * + * \return The result of registering earlysuspend + */ +/*----------------------------------------------------------------------------*/ + +int glRegisterEarlySuspend(struct early_suspend *prDesc, + early_suspend_callback wlanSuspend, + late_resume_callback wlanResume) +{ + int ret = 0; + + if (wlanSuspend != NULL) { + prDesc->suspend = wlanSuspend; + } else { + DBGLOG(REQ, INFO, + "glRegisterEarlySuspend wlanSuspend ERROR.\n"); + ret = -1; + } + + if (wlanResume != NULL) { + prDesc->resume = wlanResume; + } else { + DBGLOG(REQ, INFO, "glRegisterEarlySuspend wlanResume ERROR.\n"); + ret = -1; + } + + register_early_suspend(prDesc); + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will un-register platform driver to os + * + * \return The result of un-registering earlysuspend + */ +/*----------------------------------------------------------------------------*/ + +int glUnregisterEarlySuspend(struct early_suspend *prDesc) +{ + int ret = 0; + + unregister_early_suspend(prDesc); + + prDesc->suspend = NULL; + prDesc->resume = NULL; + + return ret; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Utility function for reading data from files on NVRAM-FS + * + * \param[in] + * filename + * len + * offset + * \param[out] + * buf + * \return + * actual length of data being read + */ +/*----------------------------------------------------------------------------*/ +static int nvram_read(char *filename, char *buf, ssize_t len, int offset) +{ +#if CFG_SUPPORT_NVRAM + struct file *fd; + int retLen = -1; + loff_t pos = (loff_t) offset; + +#ifdef set_fs + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); +#endif + + fd = filp_open(filename, O_RDONLY, 0); + + if (IS_ERR(fd)) { + DBGLOG(INIT, INFO, "[nvram_read] : failed to open!!\n"); +#ifdef set_fs + set_fs(old_fs); +#endif + return -1; + } + + do { + /*if ((fd->f_op == NULL) || ((fd->f_op->read == NULL) && (fd->f_op->read_iter == NULL))) { + DBGLOG(INIT, INFO, + "[nvram_read] : file can not be read!!\n"); + break; + } + + if (fd->f_pos != offset) { + if (fd->f_op->llseek) { + if (fd->f_op->llseek(fd, offset, 0) != offset) { + DBGLOG(INIT, + INFO, + "[nvram_read] : failed to seek!!\n"); + break; + } + } else { + fd->f_pos = offset; + } + }*/ + + retLen = kernel_read(fd, buf, len, &pos /*&fd->f_pos*/); //fd->f_op->read != NULL ? fd->f_op->read(fd, buf, len, &fd->f_pos) + //: kernel_read(fd, buf, len, &fd->f_pos) ; + } while (false); + + filp_close(fd, NULL); + +#ifdef set_fs + set_fs(old_fs); +#endif + + return retLen; + +#else /* !CFG_SUPPORT_NVRAM */ + return -EIO; + +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Utility function for writing data to files on NVRAM-FS + * + * \param[in] + * filename + * buf + * len + * offset + * \return + * actual length of data being written + */ +/*----------------------------------------------------------------------------*/ +static int nvram_write(char *filename, char *buf, ssize_t len, int offset) +{ +#if CFG_SUPPORT_NVRAM + struct file *fd; + int retLen = -1; + +#ifdef set_fs + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); +#endif + + fd = filp_open(filename, O_WRONLY | O_CREAT, 0644); + + if (IS_ERR(fd)) { + DBGLOG(INIT, INFO, "[nvram_write] : failed to open!!\n"); +#ifdef set_fs + set_fs(old_fs); +#endif + return -1; + } + + do { + if ((fd->f_op == NULL) || (fd->f_op->write == NULL)) { + DBGLOG(INIT, INFO, + "[nvram_write] : file can not be write!!\n"); + break; + } + /* End of if */ + if (fd->f_pos != offset) { + if (fd->f_op->llseek) { + if (fd->f_op->llseek(fd, offset, 0) != offset) { + DBGLOG(INIT, + INFO, + "[nvram_write] : failed to seek!!\n"); + break; + } + } else { + fd->f_pos = offset; + } + } + + retLen = fd->f_op->write(fd, buf, len, &fd->f_pos); + } while (false); + + filp_close(fd, NULL); + +#ifdef set_fs + set_fs(old_fs); +#endif + + return retLen; + +#else /* !CFG_SUPPORT_NVRAMS */ + return -EIO; + +#endif +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief API for reading data on NVRAM + * + * \param[in] + * prGlueInfo + * u4Offset + * \param[out] + * pu2Data + * \return + * true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 kalCfgDataRead16(IN P_GLUE_INFO_T prGlueInfo, IN u32 u4Offset, + OUT u16 *pu2Data) +{ + if (pu2Data == NULL) { + return false; + } + + if (nvram_read(WIFI_NVRAM_FILE_NAME, (char *)pu2Data, + sizeof(unsigned short), + u4Offset) != sizeof(unsigned short)) { + return false; + } else { + return true; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief API for writing data on NVRAM + * + * \param[in] + * prGlueInfo + * u4Offset + * u2Data + * \return + * true + * false + */ +/*----------------------------------------------------------------------------*/ +u8 kalCfgDataWrite16(IN P_GLUE_INFO_T prGlueInfo, u32 u4Offset, u16 u2Data) +{ + if (nvram_write(WIFI_NVRAM_FILE_NAME, (char *)&u2Data, + sizeof(unsigned short), + u4Offset) != sizeof(unsigned short)) { + return false; + } else { + return true; + } +} diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/sdio.c b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/sdio.c new file mode 100644 index 00000000000000..232d50a7676c63 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/sdio/sdio.c @@ -0,0 +1,1421 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2016 MediaTek Inc. + */ +/****************************************************************************** +*[File] sdio.c +*[Version] v1.0 +*[Revision Date] 2010-03-01 +*[Author] +*[Description] +* The program provides SDIO HIF driver +*[Copyright] +* Copyright (C) 2010 MediaTek Incorporation. All Rights Reserved. +******************************************************************************/ + +/******************************************************************************* + * C O M P I L E R F L A G S + ******************************************************************************* + */ + +/******************************************************************************* + * E X T E R N A L R E F E R E N C E S + ******************************************************************************* + */ + +#include "gl_os.h" +#include "precomp.h" + +#include <linux/mmc/card.h> +#include <linux/mmc/host.h> +#include <linux/mmc/sdio.h> +#include <linux/mmc/sdio_func.h> /* sdio_readl(), etc */ +#include <linux/mmc/sdio_ids.h> + +#include <linux/mm.h> +#ifndef CONFIG_X86 +#include <asm/memory.h> +#endif + +#include "reg.h" + +/******************************************************************************* + * C O N S T A N T S + ******************************************************************************* + */ + +#define HIF_SDIO_ERR_TITLE_STR "[" CHIP_NAME \ + "] SDIO Access Error!" +#define HIF_SDIO_ERR_DESC_STR "**SDIO Access Error**\n" + +#define HIF_SDIO_ACCESS_RETRY_LIMIT 3 +#define HIF_SDIO_INTERRUPT_RESPONSE_TIMEOUT (15000) + +/******************************************************************************* + * P R O T O T Y P E S + ******************************************************************************* + */ + +static int mtk_sdio_pm_suspend(struct device *pDev); +static int mtk_sdio_pm_resume(struct device *pDev); + +const struct sdio_device_id mtk_sdio_ids[] = { + { SDIO_DEVICE(0x037a, 0x7608), + .driver_data = (kernel_ulong_t)&driver_data_mt7668 }, + { /* end: all zeroes */ }, +}; + +MODULE_DEVICE_TABLE(sdio, mtk_sdio_ids); + +/******************************************************************************* + * D A T A T Y P E S + ******************************************************************************* + */ + +/******************************************************************************* + * P U B L I C D A T A + ******************************************************************************* + */ + +/******************************************************************************* + * P R I V A T E D A T A + ******************************************************************************* + */ + +static probe_card pfWlanProbe; +static remove_card pfWlanRemove; + +static const struct dev_pm_ops mtk_sdio_pm_ops = { + .suspend = mtk_sdio_pm_suspend, + .resume = mtk_sdio_pm_resume, +}; + +static struct sdio_driver mtk_sdio_driver = { /* Mediatek SDIO Driver */ + .name = "wlan", + .id_table = mtk_sdio_ids, + .probe = NULL, + .remove = NULL, + .drv = { + .owner = THIS_MODULE, + .pm = &mtk_sdio_pm_ops, + } +}; + +/******************************************************************************* + * M A C R O S + ******************************************************************************* + */ + +#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) + +/******************************************************************************* + * F U N C T I O N D E C L A R A T I O N S + ******************************************************************************* + */ + +/******************************************************************************* + * F U N C T I O N S + ******************************************************************************* + */ + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is a SDIO interrupt callback function + * + * \param[in] func pointer to SDIO handle + * + * \return void + */ +/*----------------------------------------------------------------------------*/ +static void mtk_sdio_interrupt(struct sdio_func *func) +{ + P_GLUE_INFO_T prGlueInfo = NULL; + + int ret = 0; + + prGlueInfo = sdio_get_drvdata(func); + /* ASSERT(prGlueInfo); */ + + if (!prGlueInfo) { + return; + } + + if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) { + sdio_writeb(prGlueInfo->rHifInfo.func, WHLPCR_INT_EN_CLR, + MCR_WHLPCR, &ret); + + return; + } + + sdio_writeb(prGlueInfo->rHifInfo.func, WHLPCR_INT_EN_CLR, MCR_WHLPCR, + &ret); + + kalSetIntEvent(prGlueInfo); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function is a SDIO probe function + * + * \param[in] func pointer to SDIO handle + * \param[in] id pointer to SDIO device id table + * + * \return void + */ +/*----------------------------------------------------------------------------*/ +int mtk_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + int ret; + + ASSERT(func); + ASSERT(id); + + sdio_claim_host(func); + ret = sdio_enable_func(func); + sdio_release_host(func); + + if (ret) { + dev_err(&func->dev, "Mediatek MT7668S Probe FAIL [%d]\n", ret); + return ret; + } + + if (pfWlanProbe((void *)func, (void *)id->driver_data) != + WLAN_STATUS_SUCCESS) { + dev_err(&func->dev, "Mediatek MT7668S Probe FAIL\n"); + pfWlanRemove(); + return -1; + } + + return WLAN_STATUS_SUCCESS; +} + +void mtk_sdio_remove(struct sdio_func *func) +{ + ASSERT(func); + + pfWlanRemove(); + + sdio_claim_host(func); + sdio_disable_func(func); + + sdio_release_host(func); +} + +static int mtk_sdio_pm_suspend(struct device *pDev) +{ + int ret = 0, wait = 0; + int pm_caps, set_flag; + const char *func_id; + struct sdio_func *func; + P_GLUE_INFO_T prGlueInfo = NULL; + + DBGLOG(HAL, STATE, "==>\n"); + + func = dev_to_sdio_func(pDev); + prGlueInfo = sdio_get_drvdata(func); + + DBGLOG(REQ, STATE, "Wow:%d, WowEnable:%d, state:%d\n", + prGlueInfo->prAdapter->rWifiVar.ucWow, + prGlueInfo->prAdapter->rWowCtrl.fgWowEnable, + kalGetMediaStateIndicated(prGlueInfo)); + + /* 1) wifi cfg "Wow" is true, 2) wow is enable 3) WIfI connected => + * execute WOW flow */ + if (prGlueInfo->prAdapter->rWifiVar.ucWow && + prGlueInfo->prAdapter->rWowCtrl.fgWowEnable && + (kalGetMediaStateIndicated(prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED)) { + DBGLOG(HAL, STATE, "enter WOW flow\n"); + kalWowProcess(prGlueInfo, true); + } + + prGlueInfo->prAdapter->fgForceFwOwn = true; + + /* Wait for + * 1. The other unfinished ownership handshakes + * 2. FW own back + */ + wait = 0; + while (1) { + if (prGlueInfo->prAdapter->u4PwrCtrlBlockCnt == 0 && + prGlueInfo->prAdapter->fgIsFwOwn == true) { + DBGLOG(HAL, STATE, "************************\n"); + DBGLOG(HAL, STATE, "* Entered SDIO Supsend *\n"); + DBGLOG(HAL, STATE, "************************\n"); + DBGLOG(HAL, INFO, "wait = %d\n\n", wait); + break; + } + + ACQUIRE_POWER_CONTROL_FROM_PM(prGlueInfo->prAdapter); + kalMsleep(5); + RECLAIM_POWER_CONTROL_TO_PM(prGlueInfo->prAdapter, false); + + if (wait > 200) { + DBGLOG(HAL, ERROR, "Timeout !!\n\n"); + return -EAGAIN; + } + wait++; + } + + pm_caps = sdio_get_host_pm_caps(func); + func_id = sdio_func_id(func); + + /* Ask kernel keeping SDIO bus power-on */ + set_flag = MMC_PM_KEEP_POWER; + ret = sdio_set_host_pm_flags(func, set_flag); + if (ret) { + DBGLOG(HAL, ERROR, "set flag %d err %d\n", set_flag, ret); + DBGLOG(HAL, ERROR, "%s: cannot remain alive(0x%X)\n", func_id, + pm_caps); + } + + /* If wow enable, ask kernel accept SDIO IRQ in suspend mode */ + if (prGlueInfo->prAdapter->rWifiVar.ucWow && + prGlueInfo->prAdapter->rWowCtrl.fgWowEnable) { + set_flag = MMC_PM_WAKE_SDIO_IRQ; + ret = sdio_set_host_pm_flags(func, set_flag); + if (ret) { + DBGLOG(HAL, ERROR, "set flag %d err %d\n", set_flag, + ret); + DBGLOG(HAL, ERROR, "%s: cannot sdio wake-irq(0x%X)\n", + func_id, pm_caps); + } + } + + DBGLOG(HAL, STATE, "<==\n"); + return 0; +} + +static int mtk_sdio_pm_resume(struct device *pDev) +{ + struct sdio_func *func; + P_GLUE_INFO_T prGlueInfo = NULL; + + DBGLOG(HAL, STATE, "==>\n"); + + func = dev_to_sdio_func(pDev); + prGlueInfo = sdio_get_drvdata(func); + + DBGLOG(REQ, STATE, "Wow:%d, WowEnable:%d, state:%d\n", + prGlueInfo->prAdapter->rWifiVar.ucWow, + prGlueInfo->prAdapter->rWowCtrl.fgWowEnable, + kalGetMediaStateIndicated(prGlueInfo)); + + prGlueInfo->prAdapter->fgForceFwOwn = false; + + if (prGlueInfo->prAdapter->rWifiVar.ucWow && + prGlueInfo->prAdapter->rWowCtrl.fgWowEnable && + (kalGetMediaStateIndicated(prGlueInfo) == + PARAM_MEDIA_STATE_CONNECTED)) { + DBGLOG(HAL, STATE, "leave WOW flow\n"); + kalWowProcess(prGlueInfo, false); + } + + DBGLOG(HAL, STATE, "<==\n"); + return 0; +} + +static int mtk_sdio_suspend(struct device *pDev, pm_message_t state) +{ + return mtk_sdio_pm_suspend(pDev); +} + +static int mtk_sdio_resume(struct device *pDev) +{ + return mtk_sdio_pm_resume(pDev); +} +#if (CFG_SDIO_ASYNC_IRQ_AUTO_ENABLE == 1) +int mtk_sdio_async_irq_enable(struct sdio_func *func) +{ +#define SDIO_CCCR_IRQ_EXT 0x16 +#define SDIO_IRQ_EXT_SAI BIT(0) +#define SDIO_IRQ_EXT_EAI BIT(1) + unsigned char data = 0; + unsigned int quirks_bak; + int ret; + + /* Read CCCR 0x16 (interrupt extension)*/ + data = sdio_f0_readb(func, SDIO_CCCR_IRQ_EXT, &ret); + if (ret) { + DBGLOG(HAL, ERROR, "CCCR 0x%X read fail (%d).\n", + SDIO_CCCR_IRQ_EXT, ret); + return false; + } + /* Check CCCR capability status */ + if (!(data & SDIO_IRQ_EXT_SAI)) { + /* SAI = 0 */ + DBGLOG(HAL, ERROR, "No Async-IRQ capability.\n"); + return false; + } else if (data & SDIO_IRQ_EXT_EAI) { + /* EAI = 1 */ + DBGLOG(INIT, INFO, "Async-IRQ enabled already.\n"); + return true; + } + + /* Set EAI bit */ + data |= SDIO_IRQ_EXT_EAI; + + /* Enable capability to write CCCR */ + quirks_bak = func->card->quirks; + func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + /* Write CCCR into card */ + sdio_f0_writeb(func, data, SDIO_CCCR_IRQ_EXT, &ret); + if (ret) { + DBGLOG(HAL, ERROR, "CCCR 0x%X write fail (%d).\n", + SDIO_CCCR_IRQ_EXT, ret); + return false; + } + func->card->quirks = quirks_bak; + + data = sdio_f0_readb(func, SDIO_CCCR_IRQ_EXT, &ret); + if (ret || !(data & SDIO_IRQ_EXT_EAI)) { + DBGLOG(HAL, ERROR, "CCCR 0x%X write fail (%d).\n", + SDIO_CCCR_IRQ_EXT, ret); + return false; + } + return true; +} +#endif + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will register sdio bus to the os + * + * \param[in] pfProbe Function pointer to detect card + * \param[in] pfRemove Function pointer to remove card + * + * \return The result of registering sdio bus + */ +/*----------------------------------------------------------------------------*/ +WLAN_STATUS glRegisterBus(probe_card pfProbe, remove_card pfRemove) +{ + int ret = 0; + + ASSERT(pfProbe); + ASSERT(pfRemove); + + pfWlanProbe = pfProbe; + pfWlanRemove = pfRemove; + + mtk_sdio_driver.probe = mtk_sdio_probe; + mtk_sdio_driver.remove = mtk_sdio_remove; + + mtk_sdio_driver.drv.suspend = mtk_sdio_suspend; + mtk_sdio_driver.drv.resume = mtk_sdio_resume; + + ret = (sdio_register_driver(&mtk_sdio_driver) == 0) ? + WLAN_STATUS_SUCCESS : + WLAN_STATUS_FAILURE; + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function will unregister sdio bus to the os + * + * \param[in] pfRemove Function pointer to remove card + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void glUnregisterBus(remove_card pfRemove) +{ + ASSERT(pfRemove); + pfRemove(); + + sdio_unregister_driver(&mtk_sdio_driver); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function stores hif related info, which is initialized before. + * + * \param[in] prGlueInfo Pointer to glue info structure + * \param[in] u4Cookie Pointer to u32 memory base variable for _HIF_HPI + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void glSetHifInfo(P_GLUE_INFO_T prGlueInfo, unsigned long ulCookie) +{ + P_GL_HIF_INFO_T prHif = NULL; + u8 ucIdx; + + prHif = &prGlueInfo->rHifInfo; + + QUEUE_INITIALIZE(&prHif->rFreeQueue); + QUEUE_INITIALIZE(&prHif->rRxDeAggQueue); + QUEUE_INITIALIZE(&prHif->rRxFreeBufQueue); + + prHif->func = (struct sdio_func *)ulCookie; + + sdio_set_drvdata(prHif->func, prGlueInfo); + + SET_NETDEV_DEV(prGlueInfo->prDevHandler, &prHif->func->dev); + + /* Reset statistic counter */ + kalMemZero(&prHif->rStatCounter, sizeof(SDIO_STAT_COUNTER_T)); + + for (ucIdx = TC0_INDEX; ucIdx < TC_NUM; ucIdx++) + prHif->au4PendingTxDoneCount[ucIdx] = 0; + + mutex_init(&prHif->rRxFreeBufQueMutex); + mutex_init(&prHif->rRxDeAggQueMutex); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief This function clears hif related info. + * + * \param[in] prGlueInfo Pointer to glue info structure + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void glClearHifInfo(P_GLUE_INFO_T prGlueInfo) +{ + /* P_GL_HIF_INFO_T prHif = NULL; */ + /* ASSERT(prGlueInfo); */ + /* prHif = &prGlueInfo->rHifInfo; */ +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Initialize bus operation and hif related information, request + * resources. + * + * \param[out] pvData A pointer to HIF-specific data type buffer. + * For eHPI, pvData is a pointer to u32 type and stores a + * mapped base address. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +u8 glBusInit(void *pvData) +{ + int ret = 0; + struct sdio_func *func = NULL; + + ASSERT(pvData); + + func = (struct sdio_func *)pvData; + + sdio_claim_host(func); + +#if (CFG_SDIO_ASYNC_IRQ_AUTO_ENABLE == 1) + ret = mtk_sdio_async_irq_enable(func); + if (ret == false) { + DBGLOG(HAL, ERROR, "Async-IRQ auto-enable fail.\n"); + }else{ + DBGLOG(INIT, INFO, "Async-IRQ is enabled.\n"); + } +#endif + + ret = sdio_set_block_size(func, 512); + sdio_release_host(func); + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Setup bus interrupt operation and interrupt handler for os. + * + * \param[in] pvData A pointer to struct net_device. + * \param[in] pfnIsr A pointer to interrupt handler function. + * \param[in] pvCookie Private data for pfnIsr function. + * + * \retval WLAN_STATUS_SUCCESS if success + * NEGATIVE_VALUE if fail + */ +/*----------------------------------------------------------------------------*/ +s32 glBusSetIrq(void *pvData, void *pfnIsr, void *pvCookie) +{ + int ret = 0; + + struct net_device *prNetDevice = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_GL_HIF_INFO_T prHifInfo = NULL; + + ASSERT(pvData); + if (!pvData) { + return -1; + } + + prNetDevice = (struct net_device *)pvData; + prGlueInfo = (P_GLUE_INFO_T)pvCookie; + ASSERT(prGlueInfo); + if (!prGlueInfo) { + return -1; + } + + prHifInfo = &prGlueInfo->rHifInfo; + + sdio_claim_host(prHifInfo->func); + ret = sdio_claim_irq(prHifInfo->func, mtk_sdio_interrupt); + sdio_release_host(prHifInfo->func); + + prHifInfo->fgIsPendingInt = false; + + return ret; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Stop bus interrupt operation and disable interrupt handling for os. + * + * \param[in] pvData A pointer to struct net_device. + * \param[in] pvCookie Private data for pfnIsr function. + * + * \return (none) + */ +/*----------------------------------------------------------------------------*/ +void glBusFreeIrq(void *pvData, void *pvCookie) +{ + struct net_device *prNetDevice = NULL; + P_GLUE_INFO_T prGlueInfo = NULL; + P_GL_HIF_INFO_T prHifInfo = NULL; + + ASSERT(pvData); + if (!pvData) { + return; + } + prNetDevice = (struct net_device *)pvData; + prGlueInfo = (P_GLUE_INFO_T)pvCookie; + ASSERT(prGlueInfo); + if (!prGlueInfo) { + return; + } + + prHifInfo = &prGlueInfo->rHifInfo; + + sdio_claim_host(prHifInfo->func); + sdio_release_irq(prHifInfo->func); + sdio_release_host(prHifInfo->func); +} + +u8 glIsReadClearReg(u32 u4Address) +{ + switch (u4Address) { + case MCR_WHISR: + case MCR_WASR: + case MCR_D2HRM0R: + case MCR_D2HRM1R: + case MCR_WTQCR0: + case MCR_WTQCR1: + case MCR_WTQCR2: + case MCR_WTQCR3: + case MCR_WTQCR4: + case MCR_WTQCR5: + case MCR_WTQCR6: + case MCR_WTQCR7: + return true; + + default: + return false; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Read a 32-bit device register of SDIO host driver domian + * + * \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. + * \param[in] u4Register Register offset + * \param[in] pu4Value Pointer to variable used to store read value + * + * \retval true operation success + * \retval false operation fail + */ +/*----------------------------------------------------------------------------*/ +u8 kalDevRegRead(IN P_GLUE_INFO_T prGlueInfo, IN u32 u4Register, + OUT u32 *pu4Value) +{ + int ret = 0; + u8 ucRetryCount = 0; + + ASSERT(prGlueInfo); + ASSERT(pu4Value); + + do { + sdio_claim_host(prGlueInfo->rHifInfo.func); + *pu4Value = + sdio_readl(prGlueInfo->rHifInfo.func, u4Register, &ret); + sdio_release_host(prGlueInfo->rHifInfo.func); + + if (ret || ucRetryCount) { + if (glIsReadClearReg(u4Register) && + (ucRetryCount == 0)) { + /* Read Snapshot CR instead */ + u4Register = MCR_WSR; + } + } + + ucRetryCount++; + if (ucRetryCount > HIF_SDIO_ACCESS_RETRY_LIMIT) { + break; + } + } while (ret); + + if (ret) { + DBGLOG(HAL, ERROR, "sdio_readl() reports error: %x retry: %u\n", + ret, ucRetryCount); + } + return (ret) ? false : true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Read a 32-bit device register of chip firmware register domain + * + * \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. + * \param[in] u4Register Register offset + * \param[in] pu4Value Pointer to variable used to store read value + * + * \retval true operation success + * \retval false operation fail + */ +/*----------------------------------------------------------------------------*/ +u8 kalDevRegRead_mac(IN P_GLUE_INFO_T prGlueInfo, IN u32 u4Register, + OUT u32 *pu4Value) +{ + u32 value; + u32 u4Time, u4Current; + + /* progrqm h2d mailbox0 as interested register address */ + kalDevRegWrite(prGlueInfo, MCR_H2DSM0R, u4Register); + + /* set h2d interrupt to notify firmware. bit16 */ + kalDevRegWrite(prGlueInfo, MCR_WSICR, SDIO_MAILBOX_FUNC_READ_REG_IDX); + + /* polling interrupt status asserted. bit16 */ + + /* first, disable interrupt enable for SDIO_MAILBOX_FUNC_READ_REG_IDX */ + kalDevRegRead(prGlueInfo, MCR_WHIER, &value); + kalDevRegWrite(prGlueInfo, MCR_WHIER, + (value & ~SDIO_MAILBOX_FUNC_READ_REG_IDX)); + + u4Time = (u32)kalGetTimeTick(); + + do { + /* check bit16 of WHISR assert for read register response */ + kalDevRegRead(prGlueInfo, MCR_WHISR, &value); + + if (value & SDIO_MAILBOX_FUNC_READ_REG_IDX) { + /* read d2h mailbox0 for interested register address */ + kalDevRegRead(prGlueInfo, MCR_D2HRM0R, &value); + + if (value != u4Register) { + DBGLOG(HAL, + ERROR, + "ERROR! kalDevRegRead_mac():register address mis-match"); + DBGLOG(HAL, + ERROR, + "(u4Register = 0x%08x, reported register = 0x%08x)\n", + u4Register, + value); + return false; + } + + /* read d2h mailbox1 for the value of the register */ + kalDevRegRead(prGlueInfo, MCR_D2HRM1R, &value); + *pu4Value = value; + return true; + } + + /* timeout exceeding check */ + u4Current = (u32)kalGetTimeTick(); + + if (((u4Current > u4Time) && + ((u4Current - u4Time) > + HIF_SDIO_INTERRUPT_RESPONSE_TIMEOUT)) || + (u4Current < u4Time && + ((u4Current + (0xFFFFFFFF - u4Time)) > + HIF_SDIO_INTERRUPT_RESPONSE_TIMEOUT))) { + DBGLOG(HAL, ERROR, + "ERROR: kalDevRegRead_mac(): response timeout\n"); + return false; + } + + /* Response packet is not ready */ + kalUdelay(50); + } while (1); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Write a 32-bit device register of SDIO driver domian + * + * \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. + * \param[in] u4Register Register offset + * \param[in] u4Value Value to be written + * + * \retval true operation success + * \retval false operation fail + */ +/*----------------------------------------------------------------------------*/ +u8 kalDevRegWrite(IN P_GLUE_INFO_T prGlueInfo, IN u32 u4Register, + IN u32 u4Value) +{ + int ret = 0; + u8 ucRetryCount = 0; + + ASSERT(prGlueInfo); + + do { + sdio_claim_host(prGlueInfo->rHifInfo.func); + sdio_writel(prGlueInfo->rHifInfo.func, u4Value, u4Register, + &ret); + sdio_release_host(prGlueInfo->rHifInfo.func); + + ucRetryCount++; + if (ucRetryCount > HIF_SDIO_ACCESS_RETRY_LIMIT) { + break; + } + } while (ret); + + if (ret) { + DBGLOG(HAL, ERROR, + "sdio_writel() reports error: %x retry: %u\n", ret, + ucRetryCount); + } + + return (ret) ? false : true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Write a 32-bit device register of chip firmware register domain + * + * \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. + * \param[in] u4Register Register offset + * \param[in] u4Value Value to be written + * + * \retval true operation success + * \retval false operation fail + */ +/*----------------------------------------------------------------------------*/ +u8 kalDevRegWrite_mac(IN P_GLUE_INFO_T prGlueInfo, IN u32 u4Register, + IN u32 u4Value) +{ + u32 value; + u32 u4Time, u4Current; + + /* progrqm h2d mailbox0 as interested register address */ + kalDevRegWrite(prGlueInfo, MCR_H2DSM0R, u4Register); + + /* progrqm h2d mailbox1 as the value to write */ + kalDevRegWrite(prGlueInfo, MCR_H2DSM1R, u4Value); + + /* set h2d interrupt to notify firmware bit17 */ + kalDevRegWrite(prGlueInfo, MCR_WSICR, SDIO_MAILBOX_FUNC_WRITE_REG_IDX); + + /* polling interrupt status asserted. bit17 */ + + /* first, disable interrupt enable for SDIO_MAILBOX_FUNC_WRITE_REG_IDX + */ + kalDevRegRead(prGlueInfo, MCR_WHIER, &value); + kalDevRegWrite(prGlueInfo, MCR_WHIER, + (value & ~SDIO_MAILBOX_FUNC_WRITE_REG_IDX)); + + u4Time = (u32)kalGetTimeTick(); + + do { + /* check bit17 of WHISR assert for response */ + kalDevRegRead(prGlueInfo, MCR_WHISR, &value); + + if (value & SDIO_MAILBOX_FUNC_WRITE_REG_IDX) { + /* read d2h mailbox0 for interested register address */ + kalDevRegRead(prGlueInfo, MCR_D2HRM0R, &value); + + if (value != u4Register) { + DBGLOG(HAL, + ERROR, + "ERROR! kalDevRegWrite_mac():register address mis-match"); + DBGLOG(HAL, + ERROR, + "(u4Register = 0x%08x, reported register = 0x%08x)\n", + u4Register, + value); + return false; + } + return true; + } + + /* timeout exceeding check */ + u4Current = (u32)kalGetTimeTick(); + + if (((u4Current > u4Time) && + ((u4Current - u4Time) > + HIF_SDIO_INTERRUPT_RESPONSE_TIMEOUT)) || + (u4Current < u4Time && + ((u4Current + (0xFFFFFFFF - u4Time)) > + HIF_SDIO_INTERRUPT_RESPONSE_TIMEOUT))) { + DBGLOG(HAL, ERROR, + "ERROR: kalDevRegWrite_mac(): response timeout\n"); + return false; + } + + /* Response packet is not ready */ + kalUdelay(50); + } while (1); +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Read device I/O port + * + * \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. + * \param[in] u2Port I/O port offset + * \param[in] u2Len Length to be read + * \param[out] pucBuf Pointer to read buffer + * \param[in] u2ValidOutBufSize Length of the buffer valid to be accessed + * + * \retval true operation success + * \retval false operation fail + */ +/*----------------------------------------------------------------------------*/ +u8 kalDevPortRead(IN P_GLUE_INFO_T prGlueInfo, IN u16 u2Port, IN u32 u4Len, + OUT u8 *pucBuf, IN u32 u4ValidOutBufSize) +{ + P_GL_HIF_INFO_T prHifInfo = NULL; + u8 *pucDst = NULL; + int count = u4Len; + int ret = 0; + int bNum = 0; + + struct sdio_func *prSdioFunc = NULL; + + ASSERT(prGlueInfo); + + prHifInfo = &prGlueInfo->rHifInfo; + + ASSERT(pucBuf); + pucDst = pucBuf; + + ASSERT(u4Len <= u4ValidOutBufSize); + if (u4Len > u4ValidOutBufSize) { + DBGLOG(HAL, ERROR, + "kalDevPortRead: invalid len: %d out of bound(%d)\n", + u4Len, u4ValidOutBufSize); + return false; + } + + prSdioFunc = prHifInfo->func; + + ASSERT(prSdioFunc->cur_blksize > 0); + + sdio_claim_host(prSdioFunc); + + /* Split buffer into multiple single block to workaround hifsys */ + while (count >= prSdioFunc->cur_blksize) { + count -= prSdioFunc->cur_blksize; + bNum++; + } + if (count > 0 && bNum > 0) { + bNum++; + } + + if (bNum > 0) { + ret = sdio_readsb(prSdioFunc, pucDst, u2Port, + prSdioFunc->cur_blksize * bNum); + +#ifdef CONFIG_X86 + /* ENE workaround */ + { + int tmp; + + sdio_writel(prSdioFunc, 0x0, + SDIO_X86_WORKAROUND_WRITE_MCR, &tmp); + } +#endif + } else { + ret = sdio_readsb(prSdioFunc, pucDst, u2Port, count); + } + + sdio_release_host(prSdioFunc); + + if (ret) { + DBGLOG(HAL, ERROR, "sdio_readsb() reports error: %x\n", ret); + } + return (ret) ? false : true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Write device I/O port + * + * \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. + * \param[in] u2Port I/O port offset + * \param[in] u2Len Length to be write + * \param[in] pucBuf Pointer to write buffer + * \param[in] u2ValidInBufSize Length of the buffer valid to be accessed + * + * \retval true operation success + * \retval false operation fail + */ +/*----------------------------------------------------------------------------*/ +u8 kalDevPortWrite(IN P_GLUE_INFO_T prGlueInfo, IN u16 u2Port, IN u32 u4Len, + IN u8 *pucBuf, IN u32 u4ValidInBufSize) +{ + P_GL_HIF_INFO_T prHifInfo = NULL; + u8 *pucSrc = NULL; + int count = u4Len; + int ret = 0; + int bNum = 0; + struct sdio_func *prSdioFunc = NULL; + + ASSERT(prGlueInfo); + prHifInfo = &prGlueInfo->rHifInfo; + + ASSERT(pucBuf); + pucSrc = pucBuf; + + ASSERT(u4Len <= u4ValidInBufSize); + + prSdioFunc = prHifInfo->func; + ASSERT(prSdioFunc->cur_blksize > 0); + + sdio_claim_host(prSdioFunc); + + /* Split buffer into multiple single block to workaround hifsys */ + while (count >= prSdioFunc->cur_blksize) { + count -= prSdioFunc->cur_blksize; + bNum++; + } + if (count > 0 && bNum > 0) { + bNum++; + } + + if (bNum > 0) { /* block mode */ + ret = sdio_writesb(prSdioFunc, u2Port, pucSrc, + prSdioFunc->cur_blksize * bNum); + +#ifdef CONFIG_X86 + /* ENE workaround */ + { + int tmp; + sdio_writel(prSdioFunc, 0x0, + SDIO_X86_WORKAROUND_WRITE_MCR, &tmp); + } +#endif + } else { /* byte mode */ + ret = sdio_writesb(prSdioFunc, u2Port, pucSrc, count); + } + + sdio_release_host(prSdioFunc); + + if (ret) { + DBGLOG(HAL, ERROR, "sdio_writesb() reports error: %x\n", ret); + } + return (ret) ? false : true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Read interrupt status from hardware + * + * @param prAdapter pointer to the Adapter handler + * @param the interrupts + * + * @return N/A + * + */ +/*----------------------------------------------------------------------------*/ +void kalDevReadIntStatus(IN P_ADAPTER_T prAdapter, OUT u32 *pu4IntStatus) +{ +#if CFG_SDIO_INTR_ENHANCE + P_SDIO_CTRL_T prSDIOCtrl; + P_SDIO_STAT_COUNTER_T prStatCounter; + + SDIO_TIME_INTERVAL_DEC(); + + DEBUGFUNC("nicSDIOReadIntStatus"); + + ASSERT(prAdapter); + ASSERT(pu4IntStatus); + + prSDIOCtrl = prAdapter->prGlueInfo->rHifInfo.prSDIOCtrl; + ASSERT(prSDIOCtrl); + + prStatCounter = &prAdapter->prGlueInfo->rHifInfo.rStatCounter; + + /* There are pending interrupt to be handled */ + if (prAdapter->prGlueInfo->rHifInfo.fgIsPendingInt) { + prAdapter->prGlueInfo->rHifInfo.fgIsPendingInt = false; + } else { + SDIO_REC_TIME_START(); + HAL_PORT_RD(prAdapter, MCR_WHISR, + sizeof(ENHANCE_MODE_DATA_STRUCT_T), + (u8 *)prSDIOCtrl, + sizeof(ENHANCE_MODE_DATA_STRUCT_T)); + SDIO_REC_TIME_END(); + SDIO_ADD_TIME_INTERVAL(prStatCounter->u4IntReadTime); + prStatCounter->u4IntReadCnt++; + } + + prStatCounter->u4IntCnt++; + + if (kalIsCardRemoved(prAdapter->prGlueInfo) == true || + fgIsBusAccessFailed == true) { + *pu4IntStatus = 0; + return; + } + + halProcessEnhanceInterruptStatus(prAdapter); + + *pu4IntStatus = prSDIOCtrl->u4WHISR; +#else + HAL_MCR_RD(prAdapter, MCR_WHISR, pu4IntStatus); +#endif + + if (*pu4IntStatus & ~(WHIER_DEFAULT | WHIER_FW_OWN_BACK_INT_EN)) { + DBGLOG(INTR, WARN, + "Un-handled HISR %#lx, HISR = %#lx (HIER:0x%lx)\n", + (*pu4IntStatus & ~WHIER_DEFAULT), *pu4IntStatus, + WHIER_DEFAULT); + *pu4IntStatus &= WHIER_DEFAULT; + } +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Write device I/O port in byte with CMD52 + * + * \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. + * \param[in] u4Addr I/O port offset + * \param[in] ucData Single byte of data to be written + * + * \retval true operation success + * \retval false operation fail + */ +/*----------------------------------------------------------------------------*/ +u8 kalDevWriteWithSdioCmd52(IN P_GLUE_INFO_T prGlueInfo, IN u32 u4Addr, + IN u8 ucData) +{ + int ret = 0; + + sdio_claim_host(prGlueInfo->rHifInfo.func); + sdio_writeb(prGlueInfo->rHifInfo.func, ucData, u4Addr, &ret); + sdio_release_host(prGlueInfo->rHifInfo.func); + + if (ret) { + DBGLOG(HAL, ERROR, "sdio_writeb() reports error: %x\n", ret); + } + + return (ret) ? false : true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Write data to device + * + * \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. + * \param[in] prMsduInfo msdu info + * + * \retval true operation success + * \retval false operation fail + */ +/*----------------------------------------------------------------------------*/ +u8 kalDevWriteData(IN P_GLUE_INFO_T prGlueInfo, IN P_MSDU_INFO_T prMsduInfo) +{ + P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; + P_GL_HIF_INFO_T prHifInfo = &prGlueInfo->rHifInfo; + P_TX_CTRL_T prTxCtrl; + u8 *pucOutputBuf = (u8 *)NULL; + u32 u4PaddingLength; + struct sk_buff *skb; + u8 *pucBuf; + u32 u4Length; + u8 ucTC; + + SDIO_TIME_INTERVAL_DEC(); + + skb = (struct sk_buff *)prMsduInfo->prPacket; + pucBuf = skb->data; + u4Length = skb->len; +#if CFG_MESON_G12A_PATCH + if (skb->len > 1500) { + DBGLOG(HAL, ERROR, "skb->len = %d\n", skb->len); + } +#endif + ucTC = prMsduInfo->ucTC; + + prTxCtrl = &prAdapter->rTxCtrl; + pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; + + if (prTxCtrl->u4WrIdx + ALIGN_4(u4Length) > + prAdapter->u4CoalescingBufCachedSize) { + if ((prAdapter->u4CoalescingBufCachedSize - + ALIGN_4(prTxCtrl->u4WrIdx)) >= HIF_TX_TERMINATOR_LEN) { + /* fill with single dword of zero as TX-aggregation + * termination */ + *(u32 *)(&(( + pucOutputBuf)[ALIGN_4( + prTxCtrl-> + u4WrIdx)])) = + 0; + } + + if (HAL_TEST_FLAG(prAdapter, ADAPTER_FLAG_HW_ERR) == false) { + if (kalDevPortWrite( + prGlueInfo, MCR_WTDR1, prTxCtrl->u4WrIdx, + pucOutputBuf, + prAdapter->u4CoalescingBufCachedSize) == + false) { + HAL_SET_FLAG(prAdapter, ADAPTER_FLAG_HW_ERR); + fgIsBusAccessFailed = true; + } + prHifInfo->rStatCounter.u4DataPortWriteCnt++; + } + prTxCtrl->u4WrIdx = 0; + } + + SDIO_REC_TIME_START(); + memcpy(pucOutputBuf + prTxCtrl->u4WrIdx, pucBuf, u4Length); + SDIO_REC_TIME_END(); + SDIO_ADD_TIME_INTERVAL(prHifInfo->rStatCounter.u4TxDataCpTime); + + prTxCtrl->u4WrIdx += u4Length; + + u4PaddingLength = (ALIGN_4(u4Length) - u4Length); + if (u4PaddingLength) { + memset(pucOutputBuf + prTxCtrl->u4WrIdx, 0, u4PaddingLength); + prTxCtrl->u4WrIdx += u4PaddingLength; + } + + SDIO_REC_TIME_START(); + if (!prMsduInfo->pfTxDoneHandler) { + kalFreeTxMsdu(prAdapter, prMsduInfo); + } + SDIO_REC_TIME_END(); + SDIO_ADD_TIME_INTERVAL(prHifInfo->rStatCounter.u4TxDataFreeTime); + + /* Update pending Tx done count */ + prHifInfo->au4PendingTxDoneCount[ucTC]++; + + prHifInfo->rStatCounter.u4DataPktWriteCnt++; + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Kick Tx data to device + * + * \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. + * + * \retval true operation success + * \retval false operation fail + */ +/*----------------------------------------------------------------------------*/ +u8 kalDevKickData(IN P_GLUE_INFO_T prGlueInfo) +{ + P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; + P_GL_HIF_INFO_T prHifInfo = &prGlueInfo->rHifInfo; + P_TX_CTRL_T prTxCtrl; + u8 *pucOutputBuf = (u8 *)NULL; + + prTxCtrl = &prAdapter->rTxCtrl; + pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; + + if (prTxCtrl->u4WrIdx == 0) { + return false; + } + + if ((prAdapter->u4CoalescingBufCachedSize - + ALIGN_4(prTxCtrl->u4WrIdx)) >= HIF_TX_TERMINATOR_LEN) { + /* fill with single dword of zero as TX-aggregation termination + */ + *(u32 *)(&((pucOutputBuf)[ALIGN_4(prTxCtrl->u4WrIdx)])) = 0; + } + + if (HAL_TEST_FLAG(prAdapter, ADAPTER_FLAG_HW_ERR) == false) { + if (kalDevPortWrite(prGlueInfo, MCR_WTDR1, prTxCtrl->u4WrIdx, + pucOutputBuf, + prAdapter->u4CoalescingBufCachedSize) == + false) { + HAL_SET_FLAG(prAdapter, ADAPTER_FLAG_HW_ERR); + fgIsBusAccessFailed = true; + } + prHifInfo->rStatCounter.u4DataPortWriteCnt++; + } + + prTxCtrl->u4WrIdx = 0; + + prHifInfo->rStatCounter.u4DataPortKickCnt++; + + return true; +} + +/*----------------------------------------------------------------------------*/ +/*! + * \brief Write command to device + * + * \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. + * \param[in] u4Addr I/O port offset + * \param[in] ucData Single byte of data to be written + * + * \retval true operation success + * \retval false operation fail + */ +/*----------------------------------------------------------------------------*/ +#if CFG_MESON_G12A_PATCH +WLAN_STATUS kalDevWriteCmd(IN P_GLUE_INFO_T prGlueInfo, + IN P_CMD_INFO_T prCmdInfo, IN u8 ucTC) +#else +u8 kalDevWriteCmd(IN P_GLUE_INFO_T prGlueInfo, IN P_CMD_INFO_T prCmdInfo, + IN u8 ucTC) +#endif +{ + P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; + /* P_GL_HIF_INFO_T prHifInfo = &prGlueInfo->rHifInfo; */ + P_TX_CTRL_T prTxCtrl; + u8 *pucOutputBuf = (u8 *)NULL; + u16 u2OverallBufferLength = 0; + /* WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; */ + + prTxCtrl = &prAdapter->rTxCtrl; + pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; + + if (TFCB_FRAME_PAD_TO_DW(prCmdInfo->u4TxdLen + prCmdInfo->u4TxpLen) > + prAdapter->u4CoalescingBufCachedSize) { + DBGLOG(HAL, ERROR, "Command TX buffer underflow!\n"); +#if CFG_MESON_G12A_PATCH + return WLAN_STATUS_FAILURE; + +#else + return false; + +#endif + } + if (prCmdInfo->u4TxdLen) { + memcpy((pucOutputBuf + u2OverallBufferLength), + prCmdInfo->pucTxd, prCmdInfo->u4TxdLen); + u2OverallBufferLength += prCmdInfo->u4TxdLen; + } + + if (prCmdInfo->u4TxpLen) { + memcpy((pucOutputBuf + u2OverallBufferLength), + prCmdInfo->pucTxp, prCmdInfo->u4TxpLen); + u2OverallBufferLength += prCmdInfo->u4TxpLen; + } + + memset(pucOutputBuf + u2OverallBufferLength, 0, + (TFCB_FRAME_PAD_TO_DW(u2OverallBufferLength) - + u2OverallBufferLength)); + + if ((prAdapter->u4CoalescingBufCachedSize - + ALIGN_4(u2OverallBufferLength)) >= HIF_TX_TERMINATOR_LEN) { + /* fill with single dword of zero as TX-aggregation termination + */ + *(u32 *)(&((pucOutputBuf)[ALIGN_4(u2OverallBufferLength)])) = 0; + } + if (HAL_TEST_FLAG(prAdapter, ADAPTER_FLAG_HW_ERR) == false) { + if (kalDevPortWrite(prGlueInfo, MCR_WTDR1, + TFCB_FRAME_PAD_TO_DW(u2OverallBufferLength), + pucOutputBuf, + prAdapter->u4CoalescingBufCachedSize) == + false) { + HAL_SET_FLAG(prAdapter, ADAPTER_FLAG_HW_ERR); + fgIsBusAccessFailed = true; + } + prGlueInfo->rHifInfo.rStatCounter.u4CmdPortWriteCnt++; + } + + /* Update pending Tx done count */ + prGlueInfo->rHifInfo.au4PendingTxDoneCount[ucTC]++; + + prGlueInfo->rHifInfo.rStatCounter.u4CmdPktWriteCnt++; +#if CFG_MESON_G12A_PATCH + return WLAN_STATUS_SUCCESS; + +#else + return true; + +#endif +} + +void glGetDev(void *ctx, struct device **dev) +{ + *dev = &((struct sdio_func *)ctx)->dev; +} + +void glGetHifDev(P_GL_HIF_INFO_T prHif, struct device **dev) +{ + *dev = &(prHif->func->dev); +} + +u8 glWakeupSdio(P_GLUE_INFO_T prGlueInfo) +{ + u8 fgSuccess = true; + + return fgSuccess; +} + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Check if HIF state is READY for upper layer cfg80211 + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (TRUE: ready, FALSE: not ready) + */ +/*----------------------------------------------------------------------------*/ +bool halIsHifStateReady(IN P_ADAPTER_T prAdapter, u8 *pucState) +{ + if (!prAdapter) { + return false; + } + + if (!prAdapter->prGlueInfo) { + return false; + } + + if (prAdapter->prGlueInfo->u4ReadyFlag == 0) { + return false; + } + + // if (pucState) { + // *pucState = prAdapter->prGlueInfo->rHifInfo.state; + // } + + // if (prAdapter->prGlueInfo->rHifInfo.state != SDIO_STATE_READY) { + // return FALSE; + // } + + return true; +} + + +/*----------------------------------------------------------------------------*/ +/*! + * @brief Check if HIF state is during supend process + * + * @param prAdapter Pointer to the Adapter structure. + * + * @return (TRUE: suspend, reject the caller action. FALSE: not suspend) + */ +/*----------------------------------------------------------------------------*/ +bool halIsHifStateSuspend(IN P_ADAPTER_T prAdapter) +{ + // enum sdio_state state; + + if (!prAdapter) { + return false; + } + + if (!prAdapter->prGlueInfo) { + return false; + } + + // state = prAdapter->prGlueInfo->rHifInfo.state; + + // if (state == SDIO_STATE_SUSPEND) { + // return TRUE; + // } + + return false; +} + diff --git a/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/uncrustify.cfg b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/uncrustify.cfg new file mode 100644 index 00000000000000..c5df1937ded859 --- /dev/null +++ b/drivers/misc/mediatek/connectivity/wlan/core/gen4-mt7668/uncrustify.cfg @@ -0,0 +1,81 @@ +# +# uncrustify config file for the linux kernel +# + +indent_with_tabs = 0 # 1=indent to level only, 2=indent with tabs +input_tab_size = 4 # original tab size +output_tab_size = 4 # new tab size +indent_columns = output_tab_size +code_width = 80 +indent_label = 1 # pos: absolute col, neg: relative column + +align_func_params = false +align_var_def_span = 0 +align_assign_span = 0 +align_struct_init_span = 0 +align_right_cmt_span = 0 +align_on_tabstop = false +indent_paren_nl = false +align_var_def_inline = false +align_right_cmt_at_col = 0 + +# +# inter-symbol newlines +# + +nl_enum_brace = remove # "enum {" vs "enum \n {" +nl_union_brace = remove # "union {" vs "union \n {" +nl_struct_brace = remove # "struct {" vs "struct \n {" +nl_do_brace = remove # "do {" vs "do \n {" +nl_if_brace = remove # "if () {" vs "if () \n {" +nl_for_brace = remove # "for () {" vs "for () \n {" +nl_else_brace = remove # "else {" vs "else \n {" +nl_while_brace = remove # "while () {" vs "while () \n {" +nl_switch_brace = remove # "switch () {" vs "switch () \n {" +nl_brace_while = remove # "} while" vs "} \n while" - cuddle while +nl_brace_else = remove # "} else" vs "} \n else" - cuddle else +nl_fcall_brace = remove # "list_for_each() {" vs "list_for_each()\n{" +nl_fdef_brace = force # "int foo() {" vs "int foo()\n{" + +# +# Source code modifications +# + +mod_paren_on_return = remove # "return 1;" vs "return (1);" +mod_full_brace_if = force # "if (a) a--;" vs "if (a) { a--; }" +mod_full_brace_for = remove # "for () a--;" vs "for () { a--; }" +mod_full_brace_do = remove # "do a--; while ();" vs "do { a--; } while ();" +mod_full_brace_while = remove # "while (a) a--;" vs "while (a) { a--; }" +mod_full_brace_nl = 3 # don't remove if more than 3 newlines + +# +# inter-character spacing options +# + +sp_sizeof_paren = remove # "sizeof (int)" vs "sizeof(int)" +sp_before_sparen = force # "if (" vs "if(" +sp_after_sparen = force # "if () {" vs "if (){" +sp_after_cast = remove # "(int) a" vs "(int)a" +sp_inside_braces = add # "{ 1 }" vs "{1}" +sp_inside_braces_struct = add # "{ 1 }" vs "{1}" +sp_inside_braces_enum = add # "{ 1 }" vs "{1}" +sp_assign = add +sp_arith = add +sp_bool = add +sp_compare = add +sp_assign = add +sp_after_comma = force +sp_func_def_paren = remove # "int foo (){" vs "int foo(){" +sp_func_call_paren = remove # "foo (" vs "foo(" +sp_func_proto_paren = remove # "int foo ();" vs "int foo();" + +# +# Aligning stuff +# + +align_with_tabs = false # use tabs to align +align_enum_equ_span = 4 # '=' in enum definition +align_nl_cont = 1 +sp_before_tr_emb_cmt = force +sp_num_before_tr_emb_cmt = 2 + diff --git a/drivers/misc/mediatek/eemcs/eemcs_ccci.h b/drivers/misc/mediatek/eemcs/eemcs_ccci.h new file mode 100644 index 00000000000000..885faec4898cf7 --- /dev/null +++ b/drivers/misc/mediatek/eemcs/eemcs_ccci.h @@ -0,0 +1,488 @@ +#ifndef __EEMCS_CCCI_H__ +#define __EEMCS_CCCI_H__ +#include <linux/version.h> +#include "eemcs_kal.h" +#include "lte_df_main.h" + +#define BLK_16K (16384) +#define BLK_8K (8192) +#define BLK_4K (4096) +#define BLK_2K (2048) +#define BLK_1K (1024) + +#ifndef CCCI_MTU_3456B +#define MAX_TX_BYTE (0xFFF - 127) +#else +#define MAX_TX_BYTE (3584 - 128) //3456B, skb allocate max size=3.5KB, CCCI header+reserved mem=128B +#endif + +#define MD_IMG_MAX_CNT (7) + +typedef KAL_INT32 (*EEMCS_CCCI_CALLBACK)(struct sk_buff *skb, KAL_UINT32 data); +typedef KAL_INT32 (*EEMCS_CCCI_SWINT_CALLBACK)(KAL_UINT32 swint_status); +typedef KAL_INT32 (*EEMCS_CCCI_WDT_CALLBACK)(void); + +enum +{ + EXPORT_CCCI_H =(1<<0), + TX_PRVLG1 =(1<<1), // tx channel can send data even if modem not boot ready + TX_PRVLG2 =(1<<2), // This logic channel can send data even if modem exception +}; + +typedef struct{ + KAL_UINT8 rx; + KAL_UINT8 tx; + EEMCS_CCCI_CALLBACK rx_cb; + EEMCS_CCCI_CALLBACK tx_cb; /* reserved */ +}ccci_ch_set; + +typedef struct +{ + ccci_ch_set ch; + KAL_UINT32 hif_type; + KAL_UINT32 txq_id; + KAL_UINT32 rxq_id; + KAL_UINT32 rx_flow_ctrl_limit; //>0, enable flow ctl and disable rxq read when rx_cnt>limit; =0, disable flow ctrl + KAL_UINT32 rx_flow_ctrl_thresh;//enable rxq read when rx_cnt<thresh + + KAL_UINT32 tx_mem_size; + KAL_UINT32 tx_mem_cnt; + KAL_UINT32 rx_mem_size; + KAL_UINT32 rx_mem_cnt; + + KAL_UINT32 export_type; //EXPORT_CCCI_H + KAL_UINT32 pri; + KAL_UINT32 flag; + atomic_t reserve_space; //use by blocking I/O +}ccci_port_cfg; + +typedef struct{ + wait_queue_head_t tx_waitq; + atomic_t reserve_space; +}ccci_tx_waitq_t; + +enum HIF_TYPE{ + HIF_CCIF, + HIF_SDIO, + HIF_CLDMA, +}; + +enum PORT_PRI{ + PRI_RT, + PRI_NR, +}; + +enum EXPORT_TYPE{ + EX_T_USER, + EX_T_KERN, + EX_T_BOOT, +}; + +typedef enum{ + TX_Q_MIN, + TX_Q_0 = TX_Q_MIN, + TX_Q_1, + TX_Q_2, + TX_Q_3, + TX_Q_4, + TX_Q_MAX, + RX_Q_MIN = TX_Q_MAX, + RX_Q_0 = RX_Q_MIN, + RX_Q_1, + RX_Q_2, + RX_Q_3, + RX_Q_MAX, + RX_Q_BOOT = RX_Q_MAX, + TR_Q_NUM, + TR_Q_INVALID, +}SDIO_QUEUE_IDX; + +#define SDIO_TX_Q_NUM (TX_Q_MAX - TX_Q_MIN) //TX_Q_NUM +#define SDIO_RX_Q_NUM (RX_Q_MAX - RX_Q_MIN) //RX_Q_NUM +#define SDIO_TXQ(x) (x - TX_Q_0) //CCCI_TXQ_TO_DF +#define SDIO_RXQ(x) (x - RX_Q_0) //CCCI_RXQ_TO_DF + +typedef enum { /* sync with MD */ + CH_CTRL_RX = 0, + CH_CTRL_TX = 1, + CH_SYS_RX = 2, + CH_SYS_TX = 3, + CH_AUD_RX = 4, + CH_AUD_TX = 5, + CH_META_RX = 6, + CH_META_RACK = 7, + CH_META_TX = 8, + CH_META_TACK = 9, + CH_MUX_RX = 10, + CH_MUX_RACK = 11, + CH_MUX_TX = 12, + CH_MUX_TACK = 13, + CH_FS_RX = 14, + CH_FS_TX = 15, + CH_PMIC_RX = 16, + CH_PMIC_TX = 17, + CH_UEM_RX = 18, + CH_UEM_TX = 19, + CH_NET1_RX = 20, + CH_NET1_RX_ACK = 21, + CH_NET1_TX = 22, + CH_NET1_TX_ACK = 23, + CH_NET2_RX = 24, + CH_NET2_RX_ACK = 25, + CH_NET2_TX = 26, + CH_NET2_TX_ACK = 27, + CH_NET3_RX = 28, + CH_NET3_RX_ACK = 29, + CH_NET3_TX = 30, + CH_NET3_TX_ACK = 31, + CH_RPC_RX = 32, + CH_RPC_TX = 33, + CH_IPC_RX = 34, + CH_IPC_RX_ACK = 35, + CH_IPC_TX = 36, + CH_IPC_TX_ACK = 37, + CH_AGPS_RX = 38, + CH_AGPS_RX_ACK = 39, + CH_AGPS_TX = 40, + CH_AGPS_TX_ACK = 41, + CH_MLOG_RX = 42, + CH_MLOG_TX = 43, + /* ch44~49 reserved for ARM7 */ + CH_IT_RX = 50, + CH_IT_TX = 51, + CH_IMSV_UL = 52, + CH_IMSV_DL = 53, + CH_IMSC_UL = 54, + CH_IMSC_DL = 55, + CH_IMSA_UL = 56, + CH_IMSA_DL = 57, + CH_IMSDC_UL = 58, + CH_IMSDC_DL = 59, + CH_NET1_DL_ACK = 64, /* ch for CCMNI0 ACK packet of DL data packet*/ + CH_NET2_DL_ACK = 65, /* ch for CCMNI1 ACK packet of DL data packet */ + CH_NET3_DL_ACK = 66, /* ch for CCMNI2 ACK packet of DL data packet */ + CH_NUM_MAX, + CH_DUMMY = 0xFF, /* ch which drops Tx pkts */ + CCCI_FORCE_RESET_MODEM_CHANNEL = 20090215, +}CCCI_CHANNEL_T; + +enum CCCI_PORT{ + /* CCCI Character Devices, start from 0 */ + START_OF_CCCI_CDEV = 0x00, + START_OF_BOOT_PORT = START_OF_CCCI_CDEV, + CCCI_PORT_CTRL = START_OF_BOOT_PORT,/*PORT=0*/ + END_OF_BOOT_PORT, + START_OF_NORMAL_PORT = END_OF_BOOT_PORT, + CCCI_PORT_SYS = START_OF_NORMAL_PORT,/*PORT=1*/ + CCCI_PORT_AUD, /*PORT=2*/ + CCCI_PORT_META, /*PORT=3*/ + CCCI_PORT_MUX, /*PORT=4*/ + CCCI_PORT_FS, /*PORT=5*/ + CCCI_PORT_PMIC, /*PORT=6*/ + CCCI_PORT_UEM, /*PORT=7*/ + CCCI_PORT_RPC, /*PORT=8*/ + CCCI_PORT_IPC, /*PORT=9*/ + CCCI_PORT_IPC_UART, /*PORT=10*/ + CCCI_PORT_MD_LOG, /*PORT=11*/ + CCCI_PORT_IMS_VIDEO, /*PORT=12*/ + CCCI_PORT_IMS_CTRL, /*PORT=13*/ + CCCI_PORT_IMS_AUDIO, /*PORT=14*/ + CCCI_PORT_IMS_DCTRL, /*PORT=15*/ + CCCI_PORT_MUX_REPORT, /*PORT=16, ioctl only no CCCI ch needed */ + CCCI_PORT_IOCTL, /*PORT=17, ioctl only no CCCI ch needed */ + CCCI_PORT_RILD, /*PORT=18, ioctl only no CCCI ch needed */ + CCCI_PORT_IT, /*PORT=19, ioctl only no CCCI ch needed */ + END_OF_NORMAL_PORT, + END_OF_CCCI_CDEV = END_OF_NORMAL_PORT, + + /* CCCI Network Interface */ + START_OF_CCMNI = END_OF_CCCI_CDEV, + CCCI_PORT_NET1 = START_OF_CCMNI, /*PORT=20*/ + CCCI_PORT_NET2, /*PORT=21*/ + CCCI_PORT_NET3, /*PORT=22*/ + END_OF_CCMNI, + + CCCI_PORT_NUM_MAX = END_OF_CCMNI, +}; + + +typedef struct +{ + union{ + KAL_UINT32 data[2]; + struct { + KAL_UINT32 data0; + KAL_UINT32 data1; + }; + struct { + KAL_UINT32 magic; + KAL_UINT32 id; + }; + }; + KAL_UINT32 channel; + KAL_UINT32 reserved; +} CCCI_BUFF_T; + +typedef struct +{ + unsigned int tx_cnt:12; + unsigned int reserd:17; + unsigned int d_type:3; +}SDIO_H; + +#define CCCI_MAGIC_NUM 0xFFFFFFFF + +/* CCCI/EMCS ioctl messages */ +// CCCI == EEMCS +#define CCCI_IOC_MAGIC 'C' +#define CCCI_IOC_MD_RESET _IO(CCCI_IOC_MAGIC, 0) // mdlogger // META // muxreport +#define CCCI_IOC_GET_MD_STATE _IOR(CCCI_IOC_MAGIC, 1, unsigned int) // audio +#define CCCI_IOC_PCM_BASE_ADDR _IOR(CCCI_IOC_MAGIC, 2, unsigned int) // audio +#define CCCI_IOC_PCM_LEN _IOR(CCCI_IOC_MAGIC, 3, unsigned int) // audio +#define CCCI_IOC_FORCE_MD_ASSERT _IO(CCCI_IOC_MAGIC, 4) // muxreport // mdlogger +#define CCCI_IOC_ALLOC_MD_LOG_MEM _IO(CCCI_IOC_MAGIC, 5) // mdlogger +#define CCCI_IOC_DO_MD_RST _IO(CCCI_IOC_MAGIC, 6) // md_init +#define CCCI_IOC_SEND_RUN_TIME_DATA _IO(CCCI_IOC_MAGIC, 7) // md_init +#define CCCI_IOC_GET_MD_INFO _IOR(CCCI_IOC_MAGIC, 8, unsigned int) // md_init +#define CCCI_IOC_GET_MD_EX_TYPE _IOR(CCCI_IOC_MAGIC, 9, unsigned int) // mdlogger +#define CCCI_IOC_SEND_STOP_MD_REQUEST _IO(CCCI_IOC_MAGIC, 10) // muxreport +#define CCCI_IOC_SEND_START_MD_REQUEST _IO(CCCI_IOC_MAGIC, 11) // muxreport +#define CCCI_IOC_DO_STOP_MD _IO(CCCI_IOC_MAGIC, 12) // md_init +#define CCCI_IOC_DO_START_MD _IO(CCCI_IOC_MAGIC, 13) // md_init +#define CCCI_IOC_ENTER_DEEP_FLIGHT _IO(CCCI_IOC_MAGIC, 14) // RILD // factory +#define CCCI_IOC_LEAVE_DEEP_FLIGHT _IO(CCCI_IOC_MAGIC, 15) // RILD // factory +#define CCCI_IOC_POWER_ON_MD _IO(CCCI_IOC_MAGIC, 16) // md_init +#define CCCI_IOC_POWER_OFF_MD _IO(CCCI_IOC_MAGIC, 17) // md_init +#define CCCI_IOC_POWER_ON_MD_REQUEST _IO(CCCI_IOC_MAGIC, 18) +#define CCCI_IOC_POWER_OFF_MD_REQUEST _IO(CCCI_IOC_MAGIC, 19) +#define CCCI_IOC_SIM_SWITCH _IOW(CCCI_IOC_MAGIC, 20, unsigned int) // RILD // factory +#define CCCI_IOC_SEND_BATTERY_INFO _IO(CCCI_IOC_MAGIC, 21) // md_init +#define CCCI_IOC_SIM_SWITCH_TYPE _IOR(CCCI_IOC_MAGIC, 22, unsigned int) // RILD +#define CCCI_IOC_STORE_SIM_MODE _IOW(CCCI_IOC_MAGIC, 23, unsigned int) // RILD +#define CCCI_IOC_GET_SIM_MODE _IOR(CCCI_IOC_MAGIC, 24, unsigned int) // RILD +#define CCCI_IOC_RELOAD_MD_TYPE _IO(CCCI_IOC_MAGIC, 25) // META // md_init // muxreport +#define CCCI_IOC_GET_SIM_TYPE _IOR(CCCI_IOC_MAGIC, 26, unsigned int) // terservice +#define CCCI_IOC_ENABLE_GET_SIM_TYPE _IOW(CCCI_IOC_MAGIC, 27, unsigned int) // terservice +#define CCCI_IOC_SEND_ICUSB_NOTIFY _IOW(CCCI_IOC_MAGIC, 28, unsigned int) // icusbd +#define CCCI_IOC_SET_MD_IMG_EXIST _IOW(CCCI_IOC_MAGIC, 29, unsigned int) // md_init +#define CCCI_IOC_GET_MD_IMG_EXIST _IOR(CCCI_IOC_MAGIC, 30, unsigned int) +#define CCCI_IOC_GET_MD_TYPE _IOR(CCCI_IOC_MAGIC, 31, unsigned int) // RILD +#define CCCI_IOC_STORE_MD_TYPE _IOW(CCCI_IOC_MAGIC, 32, unsigned int) // RILD +#define CCCI_IOC_GET_MD_TYPE_SAVING _IOR(CCCI_IOC_MAGIC, 33, unsigned int) // META +#define CCCI_IOC_GET_EXT_MD_POST_FIX _IOR(CCCI_IOC_MAGIC, 34, unsigned int) // char[32] emcs_fsd // mdlogger +#define CCCI_IOC_FORCE_FD _IOW(CCCI_IOC_MAGIC, 35, unsigned int) // RILD(6577) +#define CCCI_IOC_AP_ENG_BUILD _IOW(CCCI_IOC_MAGIC, 36, unsigned int) // md_init(6577) +#define CCCI_IOC_GET_MD_MEM_SIZE _IOR(CCCI_IOC_MAGIC, 37, unsigned int) // md_init(6577) +#define CCCI_IOC_GET_CFG_SETTING _IOW(CCCI_IOC_MAGIC, 39, unsigned int) // md_init + +#define CCCI_IOC_GET_MD_PROTOCOL_TYPE _IOR(CCCI_IOC_MAGIC, 42, char[16]) /*metal tool to get modem protocol type: AP_TST or DHL*/ + +// EEMCS only +#define CCCI_IOC_BOOT_MD _IO(CCCI_IOC_MAGIC, 100) /*mdinit*/ +#define CCCI_IOC_GATE_MD _IO(CCCI_IOC_MAGIC, 101) /*nouser*/ +#define CCCI_IOC_ASSERT_MD _IO(CCCI_IOC_MAGIC, 102) /*nouser*/ +#define CCCI_IOC_CHECK_STATE _IOR(CCCI_IOC_MAGIC, 103, unsigned int) /*nouser*/ +#define CCCI_IOC_SET_STATE _IOW(CCCI_IOC_MAGIC, 104, unsigned int) /*nouser*/ +#define CCCI_IOC_GET_MD_BOOT_INFO _IOR(CCCI_IOC_MAGIC, 105, unsigned int) /*mdinit*/ +#define CCCI_IOC_START_BOOT _IO(CCCI_IOC_MAGIC, 106) /*mdinit*/ +#define CCCI_IOC_BOOT_DONE _IO(CCCI_IOC_MAGIC, 107) /*mdinit*/ +#define CCCI_IOC_REBOOT _IO(CCCI_IOC_MAGIC, 108) /*mdinit*/ +#define CCCI_IOC_MD_EXCEPTION _IO(CCCI_IOC_MAGIC, 109) /*nouser*/ +#define CCCI_IOC_MD_EX_REC_OK _IO(CCCI_IOC_MAGIC, 110) /*nouser*/ +#define CCCI_IOC_GET_RUNTIME_DATA _IOR(CCCI_IOC_MAGIC, 111, char[1024]) /*mdinit*/ +#define CCCI_IOC_SET_HEADER _IO(CCCI_IOC_MAGIC, 112) /*UT */ +#define CCCI_IOC_CLR_HEADER _IO(CCCI_IOC_MAGIC, 113) /*UT */ +#define CCCI_IOC_SET_EXCEPTION_DATA _IOW(CCCI_IOC_MAGIC, 114, char[1024]) /*nouser*/ +#define CCCI_IOC_GET_EXCEPTION_LENGTH _IOR(CCCI_IOC_MAGIC, 115, unsigned int) /*nouser*/ +#define CCCI_IOC_SET_BOOT_STATE _IOW(CCCI_IOC_MAGIC, 116, unsigned int) /*boot_IT*/ +#define CCCI_IOC_GET_BOOT_STATE _IOR(CCCI_IOC_MAGIC, 117, unsigned int) /*boot_IT*/ +#define CCCI_IOC_WAIT_RDY_RST _IO(CCCI_IOC_MAGIC, 118) /*mdinit*/ /* For MD reset flow must wait for mux/fsd/mdlogger close port */ +#define CCCI_IOC_DL_TRAFFIC_CONTROL _IOW(CCCI_IOC_MAGIC, 119, unsigned int) /* For MD LOGER to turn on/off downlink traffic */ +#define CCCI_IOC_FLOW_CTRL_SETTING _IOW(CCCI_IOC_MAGIC, 120, unsigned int) /*flow control setting*/ +#define CCCI_IOC_BOOT_UP_TIMEOUT _IOW(CCCI_IOC_MAGIC, 121, unsigned int[2]) /*notify kernel of md boot up timeout*/ +#define CCCI_IOC_SET_BOOT_TO_VAL _IOW(CCCI_IOC_MAGIC, 122, unsigned int) /* Set boot time out value */ + +/******************************************************************************* +* CCCI_ERROR_CODE +********************************************************************************/ + +// CCCI error number region +#define CCCI_ERR_MODULE_INIT_START_ID (0) +#define CCCI_ERR_COMMON_REGION_START_ID (100) +#define CCCI_ERR_CCIF_REGION_START_ID (200) +#define CCCI_ERR_CCCI_REGION_START_ID (300) +#define CCCI_ERR_LOAD_IMG_START_ID (400) + +// CCCI error number +#define CCCI_ERR_MODULE_INIT_OK (CCCI_ERR_MODULE_INIT_START_ID+0) +#define CCCI_ERR_INIT_DEV_NODE_FAIL (CCCI_ERR_MODULE_INIT_START_ID+1) +#define CCCI_ERR_INIT_PLATFORM_FAIL (CCCI_ERR_MODULE_INIT_START_ID+2) +#define CCCI_ERR_MK_DEV_NODE_FAIL (CCCI_ERR_MODULE_INIT_START_ID+3) +#define CCCI_ERR_INIT_LOGIC_LAYER_FAIL (CCCI_ERR_MODULE_INIT_START_ID+4) +#define CCCI_ERR_INIT_MD_CTRL_FAIL (CCCI_ERR_MODULE_INIT_START_ID+5) +#define CCCI_ERR_INIT_CHAR_DEV_FAIL (CCCI_ERR_MODULE_INIT_START_ID+6) +#define CCCI_ERR_INIT_TTY_FAIL (CCCI_ERR_MODULE_INIT_START_ID+7) +#define CCCI_ERR_INIT_IPC_FAIL (CCCI_ERR_MODULE_INIT_START_ID+8) +#define CCCI_ERR_INIT_RPC_FAIL (CCCI_ERR_MODULE_INIT_START_ID+9) +#define CCCI_ERR_INIT_FS_FAIL (CCCI_ERR_MODULE_INIT_START_ID+10) +#define CCCI_ERR_INIT_CCMNI_FAIL (CCCI_ERR_MODULE_INIT_START_ID+11) +#define CCCI_ERR_INIT_VIR_CHAR_FAIL (CCCI_ERR_MODULE_INIT_START_ID+12) +#define CCCI_ERR_INIT_SYSMSG_FAIL (CCCI_ERR_MODULE_INIT_START_ID+13) + +// ---- Common +#define CCCI_ERR_FATAL_ERR (CCCI_ERR_COMMON_REGION_START_ID+0) +#define CCCI_ERR_ASSERT_ERR (CCCI_ERR_COMMON_REGION_START_ID+1) +#define CCCI_ERR_MD_IN_RESET (CCCI_ERR_COMMON_REGION_START_ID+2) +#define CCCI_ERR_RESET_NOT_READY (CCCI_ERR_COMMON_REGION_START_ID+3) +#define CCCI_ERR_GET_MEM_FAIL (CCCI_ERR_COMMON_REGION_START_ID+4) +#define CCCI_ERR_GET_SMEM_SETTING_FAIL (CCCI_ERR_COMMON_REGION_START_ID+5) +#define CCCI_ERR_INVALID_PARAM (CCCI_ERR_COMMON_REGION_START_ID+6) +#define CCCI_ERR_LARGE_THAN_BUF_SIZE (CCCI_ERR_COMMON_REGION_START_ID+7) +#define CCCI_ERR_GET_MEM_LAYOUT_FAIL (CCCI_ERR_COMMON_REGION_START_ID+8) +#define CCCI_ERR_MEM_CHECK_FAIL (CCCI_ERR_COMMON_REGION_START_ID+9) +#define CCCI_IPO_H_RESTORE_FAIL (CCCI_ERR_COMMON_REGION_START_ID+10) + +// ---- CCIF +#define CCCI_ERR_CCIF_NOT_READY (CCCI_ERR_CCIF_REGION_START_ID+0) +#define CCCI_ERR_CCIF_CALL_BACK_HAS_REGISTERED (CCCI_ERR_CCIF_REGION_START_ID+1) +#define CCCI_ERR_CCIF_GET_NULL_POINTER (CCCI_ERR_CCIF_REGION_START_ID+2) +#define CCCI_ERR_CCIF_UN_SUPPORT (CCCI_ERR_CCIF_REGION_START_ID+3) +#define CCCI_ERR_CCIF_NO_PHYSICAL_CHANNEL (CCCI_ERR_CCIF_REGION_START_ID+4) +#define CCCI_ERR_CCIF_INVALID_RUNTIME_LEN (CCCI_ERR_CCIF_REGION_START_ID+5) +#define CCCI_ERR_CCIF_INVALID_MD_SYS_ID (CCCI_ERR_CCIF_REGION_START_ID+6) +#define CCCI_ERR_CCIF_GET_HW_INFO_FAIL (CCCI_ERR_CCIF_REGION_START_ID+9) + +// ---- CCCI +#define CCCI_ERR_INVALID_LOGIC_CHANNEL_ID (CCCI_ERR_CCCI_REGION_START_ID+0) +#define CCCI_ERR_PUSH_RX_DATA_TO_TX_CHANNEL (CCCI_ERR_CCCI_REGION_START_ID+1) +#define CCCI_ERR_REG_CALL_BACK_FOR_TX_CHANNEL (CCCI_ERR_CCCI_REGION_START_ID+2) +#define CCCI_ERR_LOGIC_CH_HAS_REGISTERED (CCCI_ERR_CCCI_REGION_START_ID+3) +#define CCCI_ERR_MD_NOT_READY (CCCI_ERR_CCCI_REGION_START_ID+4) +#define CCCI_ERR_ALLOCATE_MEMORY_FAIL (CCCI_ERR_CCCI_REGION_START_ID+5) +#define CCCI_ERR_CREATE_CCIF_INSTANCE_FAIL (CCCI_ERR_CCCI_REGION_START_ID+6) +#define CCCI_ERR_REPEAT_CHANNEL_ID (CCCI_ERR_CCCI_REGION_START_ID+7) +#define CCCI_ERR_KFIFO_IS_NOT_READY (CCCI_ERR_CCCI_REGION_START_ID+8) +#define CCCI_ERR_GET_NULL_POINTER (CCCI_ERR_CCCI_REGION_START_ID+9) +#define CCCI_ERR_GET_RX_DATA_FROM_TX_CHANNEL (CCCI_ERR_CCCI_REGION_START_ID+10) +#define CCCI_ERR_CHANNEL_NUM_MIS_MATCH (CCCI_ERR_CCCI_REGION_START_ID+11) +#define CCCI_ERR_START_ADDR_NOT_4BYTES_ALIGN (CCCI_ERR_CCCI_REGION_START_ID+12) +#define CCCI_ERR_NOT_DIVISIBLE_BY_4 (CCCI_ERR_CCCI_REGION_START_ID+13) +#define CCCI_ERR_MD_AT_EXCEPTION (CCCI_ERR_CCCI_REGION_START_ID+14) +#define CCCI_ERR_MD_CB_HAS_REGISTER (CCCI_ERR_CCCI_REGION_START_ID+15) + +// ---- Load image error +#define CCCI_ERR_LOAD_IMG_NOMEM (CCCI_ERR_LOAD_IMG_START_ID+0) +#define CCCI_ERR_LOAD_IMG_FILE_OPEN (CCCI_ERR_LOAD_IMG_START_ID+1) +#define CCCI_ERR_LOAD_IMG_FILE_READ (CCCI_ERR_LOAD_IMG_START_ID+2) +#define CCCI_ERR_LOAD_IMG_KERN_READ (CCCI_ERR_LOAD_IMG_START_ID+3) +#define CCCI_ERR_LOAD_IMG_NO_ADDR (CCCI_ERR_LOAD_IMG_START_ID+4) +#define CCCI_ERR_LOAD_IMG_NO_FIRST_BOOT (CCCI_ERR_LOAD_IMG_START_ID+5) +#define CCCI_ERR_LOAD_IMG_LOAD_FIRM (CCCI_ERR_LOAD_IMG_START_ID+6) +#define CCCI_ERR_LOAD_IMG_FIRM_NULL (CCCI_ERR_LOAD_IMG_START_ID+7) +#define CCCI_ERR_LOAD_IMG_CHECK_HEAD (CCCI_ERR_LOAD_IMG_START_ID+8) +#define CCCI_ERR_LOAD_IMG_SIGN_FAIL (CCCI_ERR_LOAD_IMG_START_ID+9) +#define CCCI_ERR_LOAD_IMG_CIPHER_FAIL (CCCI_ERR_LOAD_IMG_START_ID+10) +#define CCCI_ERR_LOAD_IMG_MD_CHECK (CCCI_ERR_LOAD_IMG_START_ID+11) +#define CCCI_ERR_LOAD_IMG_DSP_CHECK (CCCI_ERR_LOAD_IMG_START_ID+12) +#define CCCI_ERR_LOAD_IMG_ABNORAL_SIZE (CCCI_ERR_LOAD_IMG_START_ID+13) + + + +/******************************************************************************* +* A P I s +********************************************************************************/ +KAL_UINT32 ccci_get_port_type(KAL_UINT32 ccci_port_index); +ccci_port_cfg* ccci_get_port_info(KAL_UINT32 ccci_port_index); +KAL_UINT32 ccci_get_port_cflag(KAL_UINT32 ccci_port_index); +void ccci_set_port_type(KAL_UINT32 ccci_port_index, KAL_UINT32 new_flag); + +void eemcs_ccci_turn_off_dlq_by_port(KAL_UINT32 ccci_port_index); +void eemcs_ccci_turn_on_dlq_by_port(KAL_UINT32 ccci_port_index); + +void eemcs_ccci_release_rx_skb(KAL_UINT32 port_idx, KAL_UINT32 cnt, struct sk_buff *skb); +void eemcs_ccci_reset(void); + +KAL_UINT32 eemcs_ccci_register_callback(CCCI_CHANNEL_T chn, EEMCS_CCCI_CALLBACK func_ptr , KAL_UINT32 private_data); +KAL_UINT32 eemcs_ccci_register_swint_callback(EEMCS_CCCI_SWINT_CALLBACK func_ptr); +KAL_UINT32 eemcs_ccci_register_WDT_callback(EEMCS_CCCI_WDT_CALLBACK func_ptr); +KAL_UINT32 eemcs_ccci_unregister_callback(CCCI_CHANNEL_T chn); +KAL_UINT32 eemcs_ccci_unregister_swint_callback(KAL_UINT32 id); +KAL_UINT32 eemcs_ccci_unregister_WDT_callback(void); +KAL_UINT32 eemcs_ccci_UL_write_room_alloc(CCCI_CHANNEL_T chn); +KAL_UINT32 eemcs_ccci_UL_write_room_release(CCCI_CHANNEL_T chn); +KAL_UINT32 eemcs_ccci_UL_write_wait(CCCI_CHANNEL_T chn); +KAL_INT32 eemcs_ccci_UL_write_skb_to_swq(CCCI_CHANNEL_T chn, struct sk_buff *skb); +KAL_UINT32 eemcs_ccci_boot_UL_write_room_check(void); +KAL_INT32 eemcs_ccci_boot_UL_write_skb_to_swq(struct sk_buff *skb); +//inline struct sk_buff* eemcs_ccci_DL_read_skb_from_swq(CCCI_CHANNEL_T chn); +KAL_UINT32 ccci_ch_to_port(KAL_UINT32 ccci_ch_num); +KAL_INT32 eemcs_ccci_mod_init(void); +void eemcs_ccci_exit(void); +int eemcs_cdev_msg(int port_id, unsigned int message, unsigned int reserved); +#ifdef _EEMCS_CCCI_LB_UT +/* UL APIs */ +int ccci_ut_UL_write_skb_to_swq(MTLTE_DF_TX_QUEUE_TYPE qno , struct sk_buff *skb); +int ccci_ut_UL_swq_space(MTLTE_DF_TX_QUEUE_TYPE qno); +int ccci_ut_register_swint_callback(MTLTE_DF_TO_DEV_CALLBACK func_ptr); +int ccci_ut_unregister_swint_callback(void); +int ccci_ut_register_WDT_callback(MTLTE_DF_TO_DEV_CALLBACK func_ptr); +int ccci_ut_unregister_WDT_callback(void); +int ccci_ut_register_tx_callback(MTLTE_DF_TX_QUEUE_TYPE qno, MTLTE_DF_TO_DEV_CALLBACK func_ptr , unsigned int private_data); +/* DL APIs */ +struct sk_buff * ccci_ut_DL_read_skb_from_swq(MTLTE_DF_RX_QUEUE_TYPE qno); +int ccci_ut_DL_pkt_handle_complete(MTLTE_DF_RX_QUEUE_TYPE qno); +int ccci_ut_register_rx_callback(MTLTE_DF_RX_QUEUE_TYPE qno, MTLTE_DF_TO_DEV_CALLBACK func_ptr , unsigned int private_data); +void ccci_ut_unregister_rx_callback(MTLTE_DF_RX_QUEUE_TYPE qno); + +void ccci_ut_expt_q_num_init(KAL_UINT32 nonstop_q, KAL_UINT32 except_q); +int ccci_ut_register_expt_callback(EEMCS_CCCI_EX_IND func_ptr); + +void ccci_ut_init_probe(void); +void ccci_ut_exit(void); + +void ccci_ut_turnoff_DL_port(MTLTE_DF_RX_QUEUE_TYPE qno); +void ccci_ut_turnon_DL_port(MTLTE_DF_RX_QUEUE_TYPE qno); + +/* UT mode */ +#define hif_ul_write_swq ccci_ut_UL_write_skb_to_swq +#define hif_ul_swq_space ccci_ut_UL_swq_space +#define hif_reg_swint_cb ccci_ut_register_swint_callback +#define hif_unreg_swint_cb ccci_ut_unregister_swint_callback +#define hif_reg_WDT_cb ccci_ut_register_WDT_callback +#define hif_unreg_WDT_cb ccci_ut_unregister_WDT_callback +#define hif_dl_read_swq ccci_ut_DL_read_skb_from_swq +#define hif_dl_pkt_handle_complete ccci_ut_DL_pkt_handle_complete +#define hif_reg_rx_cb ccci_ut_register_rx_callback +#define hif_unreg_rx_cb ccci_ut_unregister_rx_callback +#define hif_reg_tx_cb ccci_ut_register_tx_callback +#define hif_unreg_tx_cb ccci_ut_unregister_tx_callback +#define hif_clean_tq_cnt ccci_ut_clean_txq_count +#define hif_except_init ccci_ut_expt_q_num_init +#define hif_reg_expt_cb ccci_ut_register_expt_callback +#define hif_turn_off_dl_q ccci_ut_turnoff_DL_port +#define hif_turn_on_dl_q ccci_ut_turnon_DL_port +#else +void eemcs_ccci_exit(void); + +/* normal mode */ +#define hif_ul_write_swq mtlte_df_UL_write_skb_to_swq +#define hif_ul_swq_space mtlte_df_UL_swq_space +#define hif_reg_swint_cb mtlte_df_register_swint_callback +#define hif_unreg_swint_cb mtlte_df_unregister_swint_callback +#define hif_reg_WDT_cb mtlte_df_register_WDT_callback +#define hif_unreg_WDT_cb mtlte_df_unregister_WDT_callback +#define hif_dl_read_swq mtlte_df_DL_read_skb_from_swq +#define hif_dl_pkt_handle_complete mtlte_df_DL_pkt_handle_complete +#define hif_reg_rx_cb mtlte_df_register_rx_callback +#define hif_unreg_rx_cb mtlte_df_unregister_rx_callback +#define hif_reg_tx_cb mtlte_df_register_tx_callback +#define hif_unreg_tx_cb mtlte_df_unregister_tx_callback +#define hif_clean_tq_cnt mtlte_hif_clean_txq_count +#define hif_except_init mtlte_expt_q_num_init +#define hif_reg_expt_cb mtlte_expt_register_callback +#define hif_turn_off_dl_q mtlte_manual_turnoff_DL_port +#define hif_turn_on_dl_q mtlte_manual_turnon_DL_port +#endif + +#endif // __EEMCS_CCCI_H__ + diff --git a/drivers/misc/mediatek/eemcs/eemcs_cfg.h b/drivers/misc/mediatek/eemcs/eemcs_cfg.h new file mode 100644 index 00000000000000..4aa1e5253bc7bc --- /dev/null +++ b/drivers/misc/mediatek/eemcs/eemcs_cfg.h @@ -0,0 +1,51 @@ +#ifndef __EEMCS_CFG_H__ +#define __EEMCS_CFG_H__ + + +//--------------feature configure--------------// +#define _ECCMNI_SEQ_SUPPORT_ //ADD sequence number in cccih->reserved +#define __ECCMNI_SUPPORT__ +#define __EEMCS_EXPT_SUPPORT__ //exception mode support +#define __EEMCS_XBOOT_SUPPORT__ //Enable/Disable xBoot flow + +#define ENABLE_AEE_MD_EE //disable for bring up +#define ENABLE_MD_WDT_PROCESS //disable for bring up for md not enable wdt at bring up +//#define ENABLE_CONN_COEX_MSG //disable for bring up + + +//--------------feature configure--------------// +#define EE_INIT_TIMER (2*HZ) //sdio exception handshake timeout +#define EE_HS1_TIMER (10*HZ) //sdio exception handshake complete -> AP receive MD_EX msg +#define EE_HS2_TIMER (5*HZ) //AP receive MD_EX msg -> AP receive MD_EX_RECV_OK msg + +#define CCCI_MTU_3456B //ccci user raw data size from (4096-128) to 3456(3.5K-128) +//#define CCCI_SDIO_HEAD //add sdio header for sdio driver saving info, which is included in 128B + +#define MD_EX_LOG_SIZE (512) //size of modem send exception info +#define MD_EX_MEM_SIZE (2*1024) //size of modem exception memory, which is print in AEE +#define MD_EX_BOOT_TRA_START_OFF (0x400) //modem boot up trace start offset in exception memory +#define MD_EX_BOOT_TRA_END_OFF (0x780) //modem boot up trace end offset in exception memory + + +//--------------Debug&UT configure--------------// +//#define _EEMCS_EXCEPTION_UT //Enable exception mode UT +//#define _ECCMNI_LB_UT_ //configure EMCS_NET as UL loopback mode +//#define _EEMCS_CDEV_LB_UT_ //configure EMCS_CHAR as UL loopback mode +//#define _EEMCS_CCCI_LB_UT //configure EMCS_CCCI as UL loopback mode +//#define _EEMCS_FS_UT //Enable FS UT +//#define _EEMCS_RPC_UT //Enable RPC UT + +//Temp disable for testing +//#define _EEMCS_TRACE_SUPPORT //Enable/Disable xBoot flow tracing +//#define _EEMCS_BOOT_UT //Enable/Disable xBoot UT + +#ifdef _EEMCS_CCCI_LB_UT +#ifndef _EEMCS_BOOT_UT +#define _EEMCS_BOOT_UT +#endif +#endif + + +#endif //__EEMCS_CFG_H__ + + diff --git a/drivers/misc/mediatek/eemcs/eemcs_ipc.h b/drivers/misc/mediatek/eemcs/eemcs_ipc.h new file mode 100644 index 00000000000000..51dbb660ac4569 --- /dev/null +++ b/drivers/misc/mediatek/eemcs/eemcs_ipc.h @@ -0,0 +1,173 @@ +/***************************************************************************** + * + * Filename: + * --------- + * eemcs_ipc.h + * + * + * Author: + * ------- + * Anping Wang (mtk05304) + * + ****************************************************************************/ + +#ifndef __EEMCS_IPC_H +#define __EEMCS_IPC_H +#include <asm/ioctl.h> +#include <asm/atomic.h> +#include <linux/skbuff.h> +#include <linux/wait.h> +#include "eemcs_ccci.h" +#include "eemcs_kal.h" + +#define EEMCS_IPC_MAJOR 183 +#define EEMCS_IPC_MINOR_BASE 100 +#define EEMCS_IPC_PORT CCCI_PORT_IPC +#define EEMCS_IPC_NAME "eemcs_ipc" +#define EEMCS_IPCD_MAX_NUM (10) +#define EEMCS_IPC_NAME_LEN (30) +#define CCCI_IPC_MAGIC 'P' +#define CCCI_IPC_RESET_RECV _IO(CCCI_IPC_MAGIC,0) +#define CCCI_IPC_RESET_SEND _IO(CCCI_IPC_MAGIC,1) +#define CCCI_IPC_WAIT_MD_READY _IO(CCCI_IPC_MAGIC,2) +#define CCCI_IPC_KERN_WRITE_TEST _IO(CCCI_IPC_MAGIC,3) + +/* MD <-> AP Msg_id mapping enum */ +typedef enum +{ + IPC_L4C_MSG_ID_BEGIN = 0x80000000, + IPC_L4C_MSG_ID_RANGE = 0x80, + IPC_EL1_MSG_ID_BEGIN = IPC_L4C_MSG_ID_BEGIN + IPC_L4C_MSG_ID_RANGE, + IPC_EL1_MSG_ID_RANGE = 0x20, + +}EEMCS_IPC_MSG_ID_RANGE; + +typedef enum +{ + IPC_L4C_MSG_ID_INVALID = IPC_L4C_MSG_ID_BEGIN, + //------- Include msg_id file------------------ + //#include"mmi_ss_msg_id.h" + //--------------------------------------------- + IPC_L4C_MSG_ID_END, + IPC_EL1_MSG_ID_INVALID = IPC_EL1_MSG_ID_BEGIN, + #include "eemcs_ipc_el1_msg_id.h" + IPC_EL1_MSG_ID_END, +}EEMCS_IPC_MSG_ID_CODE; + + + +/* IPC ILM Struct define */ +typedef unsigned int uint32; +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef struct { + uint8 ref_count; + uint8 lp_reserved; + uint16 msg_len; + uint8 data[0]; +} local_para ; + +typedef struct { + uint16 pdu_len; + uint8 ref_count; + uint8 pb_resvered; + uint16 free_header_space; + uint16 free_tail_space; + uint8 data[0]; +}peer_buff_struct ; + +typedef struct ipc_ilm_struct +{ + uint32 src_mod_id; + uint32 dest_mod_id; + uint32 sap_id; + uint32 msg_id; + local_para *local_para_ptr; + peer_buff_struct *peer_buff_ptr; +} conn_md_ipc_ilm_t; + +/* IPC Device state define*/ +typedef enum _EEMCS_IPC_STATE{ + IPCD_CLOSE = 0, + IPCD_OPEN = 1, + IPCD_KERNEL = 2 +}EEMCS_IPC_STATE; + +/* IPC Node structure define */ +typedef struct _eemcs_ipc_node_t +{ + KAL_CHAR dev_name[32]; + KAL_UINT8 ipc_node_id; + atomic_t dev_state; /*0: close 1:open*/ + /* rx informaiont */ + /* 1. [eemcs_cdev_rx_callback] enqueue rx_skb_list + * 2. [eemcs_cdev_rx_callback] rx_pkt_cnt ++ + * 3. [eemcs_cdev_rx_callback] wake_up rx_waitq + * 4. [emcs_cdev_read] (wait_event_interruptible rx_waitq) + * 5. [emcs_cdev_read] rx_pkt_cnt -- + * 6. [emcs_cdev_read] dequeue rx_skb_list + */ + wait_queue_head_t rx_waitq; + struct sk_buff_head rx_skb_list; + atomic_t rx_pkt_cnt; + atomic_t rx_pkt_drop_cnt; /* happen when user memory is not enough */ + struct fasync_struct *fasync; + /* tx informaiont */ + wait_queue_head_t tx_waitq; + atomic_t tx_pkt_cnt; +}eemcs_ipc_node_t; + + +/* IPC Instance structure define */ +typedef struct _eemcs_ipc_inst_t +{ + struct class *dev_class; /* class_create/class_destroy/device_create/device_destroy */ + struct cdev *eemcs_ipcdev; /* cdev_alloc/cdev_del/cdev_init/cdev_add */ + KAL_UINT8 eemcs_port_id; + ccci_ch_set ccci_ch; + eemcs_ipc_node_t ipc_node[EEMCS_IPCD_MAX_NUM]; + wait_queue_head_t state_waitq; + int md_is_ready; +}eemcs_ipc_inst_t; + +/* IPC MD/AP id map table */ +typedef struct IPC_MSGSVC_TASKMAP_STRUCT +{ + uint32 extq_id; /* IPC universal mapping external queue */ + uint32 task_id; /* IPC processor internal task id */ + +}IPC_MSGSVC_TASKMAP_T; + +#ifdef _EEMCS_IPCD_LB_UT_ +KAL_UINT32 ipcdut_register_callback(CCCI_CHANNEL_T chn, EEMCS_CCCI_CALLBACK func_ptr , KAL_UINT32 private_data) ; +KAL_UINT32 ipcdut_unregister_callback(CCCI_CHANNEL_T chn); +inline KAL_INT32 ipcdut_UL_write_skb_to_swq(CCCI_CHANNEL_T chn, struct sk_buff *skb); +inline KAL_UINT32 ipcdut_UL_write_room_check(CCCI_CHANNEL_T chn); + +#define ccci_ch_register(ch_num,cb,para) ipcdut_register_callback(ch_num,cb,para) +#define ccci_ch_unregister(ch_num) ipcdut_unregister_callback(ch_num) +#define ccci_ch_write_desc_to_q(ch_num,desc_p) ipcdut_UL_write_skb_to_swq(ch_num, desc_p) +#define ccci_ch_write_space_alloc(ch_num) ipcdut_UL_write_room_alloc(ch_num) +//#define ccci_ch_read_desc_from_q(ch_num) cdevut_DL_read_skb_from_swq(ch_num) +#else +#define ccci_ch_register(ch_num,cb,para) eemcs_ccci_register_callback(ch_num,cb,para) +#define ccci_ch_unregister(ch_num) eemcs_ccci_unregister_callback(ch_num) +#define ccci_ch_write_desc_to_q(ch_num,desc_p) eemcs_ccci_UL_write_skb_to_swq(ch_num, desc_p) +#define ccci_ch_write_space_alloc(ch_num) eemcs_ccci_UL_write_room_alloc(ch_num) +#endif + +#ifdef CCCI_SDIO_HEAD +#define CCCI_IPC_HEADER_ROOM (sizeof(SDIO_H)+sizeof(CCCI_BUFF_T)) +#else +#define CCCI_IPC_HEADER_ROOM (sizeof(CCCI_BUFF_T)) +#endif + +//#define ccci_ipc_mem_alloc(sz) dev_alloc_skb(sz) +#define ccci_ipc_mem_alloc(sz, flag) __dev_alloc_skb(sz, flag) + +ssize_t eemcs_ipc_kern_write(conn_md_ipc_ilm_t *in_ilm); +KAL_INT32 eemcs_ipc_mod_init(void); +void eemcs_ipc_exit(void); + +#endif + diff --git a/drivers/misc/mediatek/eemcs/eemcs_ipc_el1_msg_id.h b/drivers/misc/mediatek/eemcs/eemcs_ipc_el1_msg_id.h new file mode 100644 index 00000000000000..75cf8b1dda3b71 --- /dev/null +++ b/drivers/misc/mediatek/eemcs/eemcs_ipc_el1_msg_id.h @@ -0,0 +1,36 @@ +//below are EL1 IPC messages sent from AP +IPC_MSG_ID_EL1_LTE_TX_ALLOW_IND, +IPC_MSG_ID_EL1_WIFIBT_OPER_DEFAULT_PARAM_IND, +IPC_MSG_ID_EL1_WIFIBT_OPER_FREQ_IND, +IPC_MSG_ID_EL1_WIFIBT_FREQ_IDX_TABLE_IND, +IPC_MSG_ID_EL1_WIFIBT_PROFILE_IND, + +//below are EL1 messages sent to AP +IPC_MSG_ID_EL1_LTE_DEFAULT_PARAM_IND, +IPC_MSG_ID_EL1_LTE_OPER_FREQ_PARAM_IND, +IPC_MSG_ID_EL1_WIFI_MAX_PWR_IND, +IPC_MSG_ID_EL1_LTE_TX_IND, +IPC_MSG_ID_EL1_LTE_CONNECTION_STATUS_IND, +IPC_MSG_ID_EL1_PIN_TYPE_IND, +IPC_MSG_ID_EL1_LTE_HW_INTERFACE_IND, +IPC_MSG_ID_EL1_DUMMY13_IND, +IPC_MSG_ID_EL1_DUMMY14_IND, +IPC_MSG_ID_EL1_DUMMY15_IND, +IPC_MSG_ID_EL1_DUMMY16_IND, +IPC_MSG_ID_EL1_DUMMY17_IND, +IPC_MSG_ID_EL1_DUMMY18_IND, +IPC_MSG_ID_EL1_DUMMY19_IND, +IPC_MSG_ID_EL1_DUMMY20_IND, +IPC_MSG_ID_EL1_DUMMY21_IND, +IPC_MSG_ID_EL1_DUMMY22_IND, +IPC_MSG_ID_EL1_DUMMY23_IND, +IPC_MSG_ID_EL1_DUMMY24_IND, +IPC_MSG_ID_EL1_DUMMY25_IND, +IPC_MSG_ID_EL1_DUMMY26_IND, +IPC_MSG_ID_EL1_DUMMY27_IND, +IPC_MSG_ID_EL1_DUMMY28_IND, +IPC_MSG_ID_EL1_DUMMY29_IND, +IPC_MSG_ID_EL1_DUMMY30_IND, +IPC_MSG_ID_MD_CONSYS_VERIFICATION_IND, +IPC_MSG_ID_MD_CONSYS_VERIFICATION_REQ, + diff --git a/drivers/misc/mediatek/eemcs/eemcs_ipc_task_ID.h b/drivers/misc/mediatek/eemcs/eemcs_ipc_task_ID.h new file mode 100644 index 00000000000000..4aeb897900d275 --- /dev/null +++ b/drivers/misc/mediatek/eemcs/eemcs_ipc_task_ID.h @@ -0,0 +1,52 @@ +#ifndef __CCCI_IPC_TASK_ID_H__ +#define __CCCI_IPC_TASK_ID_H__ +// Priority --> Local module ID --> External ID --> Max sent message +// X_IPC_MODULE_CONF(1,M_SSDBG1,0,1) //TASK_ID_1 +// X_IPC_MODULE_CONF(1,AP_SSDBG2,1,1) //TASK_ID_2 +#ifdef __IPC_ID_TABLE +#define X_IPC_MODULE_CONF(a,b,c,d) {c,b}, +#else +#define X_IPC_MODULE_CONF(a,b,c,d) +#endif + + +#define AP_UNIFY_ID_FLAG (1<<31) +#define MD_UNIFY_ID_FLAG (0<<31) + +//---------------------------------------------------------- +#define MD_MOD_L4C 0 +#define MD_MOD_L4C_2 1 +#define MD_MOD_L4C_3 2 +#define MD_MOD_L4C_4 3 +#define MD_MOD_AOMGR 4 +#define MD_MOD_EL1 5 + +#define AP_MOD_AGPS (0 | AP_UNIFY_ID_FLAG) +#define AP_MOD_DHCP (1 | AP_UNIFY_ID_FLAG) +#define AP_MOD_GPS (2 | AP_UNIFY_ID_FLAG) +#define AP_MOD_WMT (3 | AP_UNIFY_ID_FLAG) + +#define AP_IPC_AGPS 0 +#define AP_IPC_DHCP 1 +#define AP_IPC_GPS 2 +#define AP_IPC_WMT 3 + + +//-------------------------------------------------------------------------- +X_IPC_MODULE_CONF(1, MD_MOD_L4C, MD_UNIFY_ID_FLAG|0, 1) +X_IPC_MODULE_CONF(1, MD_MOD_L4C_2, MD_UNIFY_ID_FLAG|1, 1) +X_IPC_MODULE_CONF(1, MD_MOD_L4C_3, MD_UNIFY_ID_FLAG|2, 1) +X_IPC_MODULE_CONF(1, MD_MOD_L4C_4, MD_UNIFY_ID_FLAG|3, 1) +X_IPC_MODULE_CONF(1, MD_MOD_AOMGR, MD_UNIFY_ID_FLAG|4, 1) +X_IPC_MODULE_CONF(1, MD_MOD_EL1, MD_UNIFY_ID_FLAG|5, 1) + +//-------------------------------------------------------------------------- +X_IPC_MODULE_CONF(1, AP_IPC_AGPS, AP_UNIFY_ID_FLAG|0, 1) +X_IPC_MODULE_CONF(1, AP_IPC_DHCP, AP_UNIFY_ID_FLAG|1, 1) +X_IPC_MODULE_CONF(1, AP_IPC_GPS, AP_UNIFY_ID_FLAG|2, 1) +X_IPC_MODULE_CONF(1, AP_IPC_WMT, AP_UNIFY_ID_FLAG|3, 1) + +//------------------------------------------------------------------------- + +#endif + diff --git a/drivers/misc/mediatek/eemcs/eemcs_kal.h b/drivers/misc/mediatek/eemcs/eemcs_kal.h new file mode 100644 index 00000000000000..0e9ae11e7dbcb9 --- /dev/null +++ b/drivers/misc/mediatek/eemcs/eemcs_kal.h @@ -0,0 +1,153 @@ +#ifndef __EEMCS_KAL_H__ +#define __EEMCS_KAL_H__ + +#include <asm/types.h> +#include <linux/delay.h> +#include <linux/skbuff.h> +#include "eemcs_cfg.h" + +/* portable character for multichar character set */ +#define KAL_CHAR s8 +/* portable wide character for unicode character set */ +#define KAL_WCHAR s16 +/* portable 8-bit unsigned integer */ +#define KAL_UINT8 u8 +/* portable 8-bit signed integer */ +#define KAL_INT8 s8 +/* portable 16-bit unsigned integer */ +#define KAL_UINT16 u16 +/* portable 16-bit signed integer */ +#define KAL_INT16 s16 +/* portable 32-bit unsigned integer */ +#define KAL_UINT32 u32 +/* portable 32-bit signed integer */ +#define KAL_INT32 s32 +/* portable 64-bit unsigned integer */ +#define KAL_UINT64 u64 +/* portable 64-bit signed integer */ +#define KAL_INT64 s64 + +#define KAL_SUCCESS (0) +#define KAL_FAIL (-1) + +#define kal_uint8 KAL_UINT8 +#define kal_uint16 KAL_UINT16 +#define kal_uint32 KAL_UINT32 +#define kal_bool KAL_CHAR + + +#define KAL_MUTEX struct mutex +#define KAL_AQUIREMUTEX(_lock_p) mutex_init(_lock_p) +#define KAL_DESTROYMUTEX(_lock_p) mutex_destroy(_lock_p) +#define KAL_MUTEXLOCK(_lock_p) mutex_lock(_lock_p) +#define KAL_MUTEXUNLOCK(_lock_p) mutex_unlock(_lock_p) + +#define KAL_ENQUEUE_PKT(_queue, _pkt) skb_queue_tail(_queue, _pkt) +#define KAL_DEQUEUE_PKT(_queue) skb_dequeue(_queue) +#define KAL_QUEUE_PURGE(_queue) skb_queue_purge(_queue) + +#define KAL_ALLOCATE_PHYSICAL_MEM(_pBuf, _Size) \ +({ \ + int result; \ + \ + _pBuf = kmalloc(_Size, GFP_KERNEL); \ + result = _pBuf == NULL ? -ENOMEM : 0; \ + \ + result; \ +}) + +#define KAL_ALLOCATE_PHYSICAL_DMA_MEM(_pBuf, _Size) \ +({ \ + int result; \ + \ + _pBuf = kmalloc(_Size, GFP_KERNEL | GFP_DMA); \ + result = _pBuf == NULL ? -ENOMEM : 0; \ + \ + result; \ +}) + +#define KAL_ALLOCATE_PHYSICAL_DMA_MEM_NEW(_pBuf, _Size) \ +({ \ + int result; \ + \ + _pBuf = kmalloc(_Size, GFP_ATOMIC); \ + result = _pBuf == NULL ? -ENOMEM : 0; \ + \ + result; \ +}) + + +#define KAL_FREE_PHYSICAL_MEM(_pBuf) kfree(_pBuf) +#define KAL_COPY_MEM(_pDst, _pSrc, _Size) memcpy((void *)(_pDst), (void *)(_pSrc), (_Size)) +#define KAL_ZERO_MEM(_pBuf, _Size) memset((void *)(_pBuf), 0, (_Size)) +#define KAL_COMP_MEM(_pDst, _pSrc, _Size) memcmp((void *)(_pDst), (void *)(_pSrc), (_Size)) + +#define KAL_ALIGN_TO_DWORD(_value) (((_value) + 0x3) & ~0x3) + +#define KAL_SLEEP_USEC(_Usec) usleep_range(_Usec, _Usec+10) +#define KAL_SLEEP_MSEC(_Msec) msleep(_Msec) +#define KAL_SLEEP_SEC(_sec) msleep(_sec * 1000) + +#define KAL_FUNC_NAME __FUNCTION__ + +/* Message verbosity: lower values indicate higher urgency */ +#define DBG_OFF 0 +#define DBG_ERROR 1 +#define DBG_WARN 2 +#define DBG_CRIT 3 +#define DBG_TRACE 4 +#define DBG_INFO 5 +#define DBG_LOUD 6 + +#define KAL_DEBUG_LEVEL DBG_ERROR + +#define KERNEL_DEBUG + +#define LOG_FUNC(a...) printk(KERN_ERR a) + +extern unsigned int lte_kal_debug_level ; + + +#ifdef KERNEL_DEBUG +#define KAL_DBGPRINT(_mod, _level, _fmt) \ +({ \ + if (lte_kal_debug_level >= _level){ \ + LOG_FUNC _fmt; \ + } \ +}) +#define KAL_RAWPRINT(_fmt) \ +({ \ + LOG_FUNC _fmt; \ +}) + +#define KAL_ASSERT(exp) \ +({ \ + if (!(exp)){ \ + panic("[EEMCS/KAL] [ASSERT]%s : %d : %s\r\n", __FILE__, __LINE__,#exp); \ + } \ +}) +#define KAL_DUMP_DWARD_DATA(dword_size, addr) \ +({ \ + KAL_INT32 i ; \ + for (i=0; i<dword_size; i++){ \ + LOG_FUNC("[EEMCS/KAL] [DUMP] 0x%x\t", *((unsigned int)(addr)+i)); \ + } \ +}) +#else +#define KAL_DBGPRINT(_mod, _level, _fmt) +#define KAL_RAWPRINT(_fmt) \ +({ \ + LOG_FUNC _fmt; \ +}) +#define KAL_ASSERT(exp) \ +({ \ + if (!(exp)){ \ + LOG_FUNC("[EEMCS/KAL] [ASSERT]%s : %d : %s\r\n", __FILE__, __LINE__,#exp); \ + } \ +}) +#define KAL_DUMP_DWARD_DATA(size, addr) +#endif + + +#endif + diff --git a/drivers/misc/mediatek/eemcs/lte_df_main.h b/drivers/misc/mediatek/eemcs/lte_df_main.h new file mode 100644 index 00000000000000..b60f01f2885c8a --- /dev/null +++ b/drivers/misc/mediatek/eemcs/lte_df_main.h @@ -0,0 +1,368 @@ +#ifndef __LTE_DF_MAIN_H__ +#define __LTE_DF_MAIN_H__ + +#include <linux/skbuff.h> +#include "eemcs_kal.h" + + +#define DISPATCH_AFTER_ALL_SKB_DONE 1 // Don't turn on these flag at same time + +#define USE_QUE_WORK_DISPATCH_RX 0 // Don't turn on these flag at same time +#define USE_MULTI_QUE_DISPATCH 0 + +#define IMMEDIATE_RELOAD_DL_SKB 1 //move from makefile to solve compile error + +#define FORMAL_DL_FLOW_CONTROL 1 +#define FORMAL_DL_FLOW_CONTROL_TEST 0 + +#define BUFFER_POOL_FOR_EACH_QUE 1 +#define EXPT_HELP_WAKELOCK_FOR_UART 1 + + +//#define DEV_MAX_PKT_SIZE (65536) +//#define DEV_MAX_PKT_SIZE (4096) + +/* Change PKT SIZE to 3584Byte due to AP skb allocate way & page size issue */ +#define DEV_MAX_PKT_SIZE (3584) + +/* TX Q Threshold */ +#define MT_LTE_TX_SWQ_Q0_TH (32) + +#define MT_LTE_TX_SWQ_Q1_TH (32) + +#define MT_LTE_TX_SWQ_Q2_TH (512) // Enalrge to 512 due to network usage + +#define MT_LTE_TX_SWQ_Q3_TH (512) // Enalrge to 512 due to network usage + +#define MT_LTE_TX_SWQ_Q4_TH (512) // Enalrge to 512 due to network usage + +#define MT_LTE_TX_SWQ_Q5_TH (32) + +#define MT_LTE_TX_SWQ_Q6_TH (32) + + +/* RX Q Threshold */ +#define MT_LTE_RX_SWQ_Q0_TH (128) + +#define MT_LTE_RX_SWQ_Q1_TH (256) + +#define MT_LTE_RX_SWQ_Q2_TH (256) + +#define MT_LTE_RX_SWQ_Q3_TH (256) + +/* DL Buffer pool Threshold */ +#define MT_LTE_DL_BUFF_POOL_TH (512) + +typedef enum{ + +/* TX PORT 1 */ + TX_PORT1_Q_MIN = 0 , + TXQ_Q0 = 0 , + TXQ_Q1 = 1 , + TXQ_Q2 = 2 , + TXQ_Q3 = 3 , + TXQ_Q4 = 4 , + TXQ_Q5 = 5 , + TXQ_Q6 = 6 , + TX_PORT1_Q_MAX = 6 , + + TXQ_NUM , + +} MTLTE_DF_TX_QUEUE_TYPE ; + +#define TXQ_PORT1_Q_NUM (1 + TX_PORT1_Q_MAX - TX_PORT1_Q_MIN) // 7 + +typedef enum{ + RXQ_Q0 = 0, + RXQ_Q1 = 1, + RXQ_Q2 = 2 , + RXQ_Q3 = 3 , + RXQ_NUM , +} MTLTE_DF_RX_QUEUE_TYPE ; + +typedef int (*MTLTE_DF_TO_DEV_CALLBACK)(unsigned int data); + +typedef int (*MTLTE_DF_TO_HIF_CALLBACK)(unsigned int data); + +struct mtlte_df_to_hif_callback { + MTLTE_DF_TO_HIF_CALLBACK callback_func ; + unsigned int private_data ; +} ; + +struct mtlte_df_to_dev_callback { + MTLTE_DF_TO_DEV_CALLBACK callback_func ; + unsigned int private_data ; +} ; + +typedef struct { + struct work_struct rxq_dispatch_work; + MTLTE_DF_RX_QUEUE_TYPE rxq_num; +} rxq_dispatch_work_t; + + +struct mtlte_df_core { + + struct mtlte_df_to_dev_callback cb_handle[RXQ_NUM] ; + struct mtlte_df_to_dev_callback tx_cb_handle[TXQ_NUM] ; + MTLTE_DF_TO_DEV_CALLBACK cb_sw_int; + MTLTE_DF_TO_DEV_CALLBACK cb_wd_timeout; + + /* For Down Link path */ +#if BUFFER_POOL_FOR_EACH_QUE + struct sk_buff_head dl_buffer_pool_queue[RXQ_NUM]; + KAL_UINT32 df_skb_alloc_size[RXQ_NUM]; + KAL_UINT32 df_buffer_pool_depth[RXQ_NUM]; +#else + struct sk_buff_head dl_buffer_pool_queue; +#endif + struct workqueue_struct *dl_reload_work_queue; + struct work_struct dl_reload_work; + + struct sk_buff_head dl_recv_wait_queue[RXQ_NUM]; + volatile int dl_pkt_in_use[RXQ_NUM]; + +#if USE_MULTI_QUE_DISPATCH + struct workqueue_struct *rxq_dispatch_work_queue[RXQ_NUM]; + rxq_dispatch_work_t rxq_dispatch_work_param[RXQ_NUM]; +#else + struct workqueue_struct *dl_dispatch_work_queue; + struct work_struct dl_dispatch_work; +#endif + + /* For Up Link path */ + struct sk_buff_head ul_xmit_wait_queue[TXQ_NUM]; + + struct sk_buff_head ul_xmit_free_queue; + + struct mtlte_df_to_hif_callback kick_hif_process ; + + /* For dl_pkt_in_use */ + KAL_MUTEX dl_pkt_lock ; + +#if FORMAL_DL_FLOW_CONTROL + /* for Down Link flow control */ + bool fl_ctrl_enable[RXQ_NUM]; + bool fl_ctrl_free_skb[RXQ_NUM]; + KAL_UINT32 fl_ctrl_limit[RXQ_NUM]; + KAL_UINT32 fl_ctrl_threshold[RXQ_NUM]; + bool fl_ctrl_full[RXQ_NUM]; + atomic_t fl_ctrl_counter[RXQ_NUM]; + KAL_UINT32 fl_ctrl_record[RXQ_NUM]; +#endif + +} ; + + +int mtlte_df_init(void) ; + +int mtlte_df_deinit(void) ; + +int mtlte_df_probe(void) ; + +//int mtlte_df_remove(void) ; + +int mtlte_df_remove_phase1(void) ; +int mtlte_df_remove_phase2(void) ; + + + + + +/****************************************************** +* +* API for HIF Layer +* +******************************************************/ +/****************************************************** +* UL data traffic APIs +******************************************************/ +int mtlte_df_UL_pkt_in_swq(MTLTE_DF_TX_QUEUE_TYPE qno) ; + +void mtlte_df_UL_callback(MTLTE_DF_TX_QUEUE_TYPE qno) ; + +unsigned int mtlte_df_UL_deswq_buf(MTLTE_DF_TX_QUEUE_TYPE qno , void *buf_ptr) ; + +/****************************************************** +* DL data traffic APIs +******************************************************/ +#if BUFFER_POOL_FOR_EACH_QUE +int mtlte_df_DL_pkt_in_buff_pool(MTLTE_DF_TX_QUEUE_TYPE qno); +#else +int mtlte_df_DL_pkt_in_buff_pool(void); +#endif + +void mtlte_df_DL_try_reload_swq(void); + +int mtlte_df_DL_pkt_in_swq(MTLTE_DF_RX_QUEUE_TYPE qno); + +int mtlte_df_DL_enswq_buf(MTLTE_DF_RX_QUEUE_TYPE qno , void *buf, unsigned int len) ; + +void mtlte_df_UL_swq_drop_skb(MTLTE_DF_TX_QUEUE_TYPE qno); + +int mtlte_df_register_df_to_hif_callback(void *func_ptr , unsigned int data) ; + +/****************************************************** +* Software Interrupt related APIs +******************************************************/ +int mtlte_df_swint_handle(unsigned int swint_status); + +#if BUFFER_POOL_FOR_EACH_QUE +void mtlte_df_DL_prepare_skb_for_swq_short(unsigned int target_num, MTLTE_DF_TX_QUEUE_TYPE qno); +#else +void mtlte_df_DL_prepare_skb_for_swq_short(unsigned int target_num); +#endif + +/****************************************************** +* +* API for Upper (Device) Layer +* +******************************************************/ + +/****************************************************** +* UL data traffic APIs +******************************************************/ +int mtlte_df_UL_write_skb_to_swq(MTLTE_DF_TX_QUEUE_TYPE qno , struct sk_buff *skb) ; + +int mtlte_df_UL_swq_space(MTLTE_DF_TX_QUEUE_TYPE qno) ; + +int mtlte_df_register_tx_callback(MTLTE_DF_TX_QUEUE_TYPE qno, MTLTE_DF_TO_DEV_CALLBACK func_ptr , unsigned int private_data) ; + +void mtlte_df_unregister_tx_callback(MTLTE_DF_TX_QUEUE_TYPE qno) ; + +void mtlte_df_UL_SWQ_threshold_set(MTLTE_DF_TX_QUEUE_TYPE qno, unsigned int threshold) ; + + +/****************************************************** +* DL data traffic APIs +******************************************************/ +struct sk_buff * mtlte_df_DL_read_skb_from_swq(MTLTE_DF_RX_QUEUE_TYPE qno) ; + +int mtlte_df_register_rx_callback(MTLTE_DF_RX_QUEUE_TYPE qno, MTLTE_DF_TO_DEV_CALLBACK func_ptr , unsigned int private_data) ; + +void mtlte_df_unregister_rx_callback(MTLTE_DF_RX_QUEUE_TYPE qno) ; + +int mtlte_df_DL_pkt_handle_complete(MTLTE_DF_RX_QUEUE_TYPE qno); + +#if USE_QUE_WORK_DISPATCH_RX + #if USE_MULTI_QUE_DISPATCH +void mtlte_df_DL_try_dispatch_rxque(MTLTE_DF_RX_QUEUE_TYPE qno); + #else +void mtlte_df_DL_try_dispatch_rx(void); + #endif +#endif + +#if DISPATCH_AFTER_ALL_SKB_DONE +void mtlte_df_DL_rx_callback(MTLTE_DF_RX_QUEUE_TYPE qno); +#endif + +#if BUFFER_POOL_FOR_EACH_QUE +void mtlte_df_DL_set_skb_alloc_size_depth(MTLTE_DF_TX_QUEUE_TYPE qno, unsigned int alloc_size, unsigned int pool_depth); +#endif + +/****************************************************** +* Software Interrupt related APIs +******************************************************/ +int mtlte_df_register_swint_callback(MTLTE_DF_TO_DEV_CALLBACK func_ptr); +int mtlte_df_unregister_swint_callback(void); + + + +/****************************************************** +* Other APIs +******************************************************/ + /* NOTICE : Only can be called at end of xboot !!!! */ +int mtlte_hif_clean_txq_count(void); +int sdio_xboot_mb_wr(KAL_UINT32 *pBuffer, KAL_UINT32 len); +int sdio_xboot_mb_rd(KAL_UINT32 *pBuffer, KAL_UINT32 len); + + + +/****************************************************** +* Device Watchdog Timeout related APIs +******************************************************/ +int mtlte_df_register_WDT_callback(MTLTE_DF_TO_DEV_CALLBACK func_ptr); +int mtlte_df_unregister_WDT_callback(void); +int mtlte_df_WDT_handle(int wd_handle_data); +void mtlte_enable_WDT_flow(void); + + +/****************************************************** +* Downlink flow control APIs +******************************************************/ +int mtlte_manual_turnoff_DL_port(MTLTE_DF_RX_QUEUE_TYPE qno); +int mtlte_manual_turnon_DL_port(MTLTE_DF_RX_QUEUE_TYPE qno); + +#if FORMAL_DL_FLOW_CONTROL +void mtlte_df_Init_DL_flow_ctrl(MTLTE_DF_RX_QUEUE_TYPE qno, bool free_skb, unsigned int limit, unsigned int threshold); +void mtlte_df_DL_release_buff (MTLTE_DF_RX_QUEUE_TYPE qno, unsigned int buff_amount, struct sk_buff *skb); + + /* Below is only for internal usage */ +bool mtlte_df_DL_check_fl_ctrl_enable(MTLTE_DF_RX_QUEUE_TYPE qno); +bool mtlte_df_DL_check_fl_ctrl_full(MTLTE_DF_RX_QUEUE_TYPE qno); +int mtlte_df_DL_read_fl_ctrl_record(MTLTE_DF_RX_QUEUE_TYPE qno); +#endif +#if FORMAL_DL_FLOW_CONTROL_TEST +void mtlte_df_DL_fl_ctrl_print_status(MTLTE_DF_RX_QUEUE_TYPE qno); +#endif + +/****************************************************** +* Assertion Dump Flow Related +******************************************************/ + +#define H2D_INT_except_ack (0x1 << 18) +#define H2D_INT_except_clearQ_ack (0x1 << 19) +#define H2D_INT_except_wakelock_ack (0x1 << 20) + +#define D2H_INT_except_init (0x1 << 18) +#define D2H_INT_except_init_done (0x1 << 19) +#define D2H_INT_except_clearQ_done (0x1 << 20) +#define D2H_INT_except_allQ_reset (0x1 << 21) + +#define D2H_INT_xboot_D2HMB (1 << 16) +#define H2D_INT_xboot_H2DMB (1 << 17) + +#define D2H_INT_PLL_START (1 << 22) +#define D2H_INT_PLL_END (1 << 23) + +#define D2H_INT_except_wakelock (1 << 24) + + +#define EX_INIT (0) +#define EX_DHL_DL_RDY (1) +#define EX_INIT_DONE (2) + + +typedef void (*EEMCS_CCCI_EX_IND)(KAL_UINT32 msgid); + +struct mtlte_expt_priv { + + EEMCS_CCCI_EX_IND cb_ccci_expt_int; + + kal_uint32 non_stop_dlq[RXQ_NUM]; + + kal_uint32 except_mode_ulq[TXQ_NUM]; + kal_uint32 except_mode_dlq[RXQ_NUM]; +}; + + +int mtlte_check_excetion_int(unsigned int swint_status); + +int mtlte_expt_reset_inform_hif(void); + +void mtlte_expt_q_num_init(KAL_UINT32 dhldl_q, KAL_UINT32 except_q); + +int mtlte_expt_register_callback(EEMCS_CCCI_EX_IND cb); + +int mtlte_expt_check_expt_q_num(KAL_UINT32 is_DL, KAL_UINT32 q_num); + +int mtlte_expt_init(void); + +int mtlte_expt_probe(void) ; + +int mtlte_expt_remove(void) ; + +int mtlte_expt_deinit(void); + + +#endif + diff --git a/drivers/misc/mediatek/include/mt-plat/aee.h b/drivers/misc/mediatek/include/mt-plat/aee.h new file mode 100644 index 00000000000000..d1cf448dafb21f --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/aee.h @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#if !defined(__AEE_H__) +#define __AEE_H__ + +#include <linux/kernel.h> +#include <linux/sched.h> + +#define AEE_MODULE_NAME_LENGTH 64 +#define AEE_PROCESS_NAME_LENGTH 256 +#define AEE_BACKTRACE_LENGTH 3072 + +typedef enum { + AE_DEFECT_FATAL, + AE_DEFECT_EXCEPTION, + AE_DEFECT_WARNING, + AE_DEFECT_REMINDING, + AE_DEFECT_ATTR_END +} AE_DEFECT_ATTR; + +typedef enum { + AE_KE = 0, /* Fatal Exception */ + AE_HWT, + AE_REBOOT, + AE_NE, + AE_JE, + AE_SWT, + AE_EE, + AE_EXP_ERR_END, + AE_ANR, /* Error or Warning or Defect */ + AE_RESMON, + AE_MODEM_WARNING, + AE_WTF, + AE_WRN_ERR_END, + AE_MANUAL, /* Manual Raise */ + AE_EXP_CLASS_END, + + AE_KERNEL_PROBLEM_REPORT = 1000, + AE_SYSTEM_JAVA_DEFECT, + AE_SYSTEM_NATIVE_DEFECT, + AE_MANUAL_MRDUMP_KEY, +} AE_EXP_CLASS; /* General Program Exception Class */ + +typedef enum { + AEE_REBOOT_MODE_NORMAL = 0, + AEE_REBOOT_MODE_KERNEL_OOPS, + AEE_REBOOT_MODE_KERNEL_PANIC, + AEE_REBOOT_MODE_NESTED_EXCEPTION, + AEE_REBOOT_MODE_WDT, + AEE_REBOOT_MODE_MANUAL_KDUMP, +} AEE_REBOOT_MODE; + +#define AEE_SZ_SYMBOL_L 140 +#define AEE_SZ_SYMBOL_S 80 +struct aee_bt_frame { + __u64 pc; + __u64 lr; + __u32 pad[5]; + char pc_symbol[AEE_SZ_SYMBOL_S]; /* Now we use different symbol length for PC &LR */ + char lr_symbol[AEE_SZ_SYMBOL_L]; +}; + +/* aee_process_info struct should strictly small than ipanic_buffer, now 4KB */ +struct aee_process_info { + char process_path[AEE_PROCESS_NAME_LENGTH]; + char backtrace[AEE_BACKTRACE_LENGTH]; + struct aee_bt_frame ke_frame; +}; + +struct aee_process_bt { + __u32 pid; + __u32 nr_entries; + struct aee_bt_frame *entries; +}; + + +struct aee_thread_reg { + pid_t tid; + struct pt_regs regs; +}; + +struct aee_user_thread_stack { + pid_t tid; + int StackLength; + unsigned char *Userthread_Stack; /*8k stack ,define to char only for match 64bit/32bit*/ +}; + +struct aee_user_thread_maps { + pid_t tid; + int Userthread_mapsLength; + unsigned char *Userthread_maps; /*8k stack ,define to char only for match 64bit/32bit*/ +}; + + + +struct aee_oops { + struct list_head list; + AE_DEFECT_ATTR attr; + AE_EXP_CLASS clazz; + + char module[AEE_MODULE_NAME_LENGTH]; + /* consist with struct aee_process_info */ + char process_path[AEE_PROCESS_NAME_LENGTH]; + char backtrace[AEE_BACKTRACE_LENGTH]; + struct aee_bt_frame ke_frame; + + char *detail; + int detail_len; + + char *console; + int console_len; + + char *android_main; + int android_main_len; + char *android_radio; + int android_radio_len; + char *android_system; + int android_system_len; + + char *userspace_info; + int userspace_info_len; + + char *mmprofile; + int mmprofile_len; + + char *mini_rdump; + int mini_rdump_len; + + + struct aee_user_thread_stack userthread_stack; + struct aee_thread_reg userthread_reg; + struct aee_user_thread_maps userthread_maps; + + int dump_option; +}; + +struct aee_kernel_api { + void (*kernel_reportAPI)(const AE_DEFECT_ATTR attr, const int db_opt, const char *module, + const char *msg); + void (*md_exception)(const char *assert_type, const int *log, int log_size, const int *phy, + int phy_size, const char *detail, const int db_opt); + void (*md32_exception)(const char *assert_type, const int *log, int log_size, + const int *phy, int phy_size, const char *detail, const int db_opt); + void (*combo_exception)(const char *assert_type, const int *log, int log_size, + const int *phy, int phy_size, const char *detail, const int db_opt); + void (*scp_exception)(const char *assert_type, const int *log, int log_size, + const int *phy, int phy_size, const char *detail, const int db_opt); +}; + +void aee_sram_printk(const char *fmt, ...); +int aee_nested_printf(const char *fmt, ...); +void aee_wdt_irq_info(void); +void aee_wdt_fiq_info(void *arg, void *regs, void *svc_sp); +void aee_trigger_kdb(void); +struct aee_oops *aee_oops_create(AE_DEFECT_ATTR attr, AE_EXP_CLASS clazz, const char *module); +void aee_oops_set_backtrace(struct aee_oops *oops, const char *backtrace); +void aee_oops_set_process_path(struct aee_oops *oops, const char *process_path); +void aee_oops_free(struct aee_oops *oops); +/* powerkey press,modules use bits */ +#define AE_WDT_Powerkey_DEVICE_PATH "/dev/kick_powerkey" +#define WDT_SETBY_DEFAULT (0) +#define WDT_SETBY_Backlight (1<<0) +#define WDT_SETBY_Display (1<<1) +#define WDT_SETBY_SF (1<<2) +#define WDT_SETBY_PM (1<<3) +#define WDT_SETBY_WMS_DISABLE_PWK_MONITOR (0xAEEAEE00) +#define WDT_SETBY_WMS_ENABLE_PWK_MONITOR (0xAEEAEE01) +#define WDT_PWK_HANG_FORCE_HWT (0xAEE0FFFF) + +/* QHQ RT Monitor */ +#define AEEIOCTL_RT_MON_Kick _IOR('p', 0x0A, int) +#define AE_WDT_DEVICE_PATH "/dev/RT_Monitor" +/* QHQ RT Monitor end */ + +/* DB dump option bits, set relative bit to 1 to include related file in db */ +#define DB_OPT_DEFAULT (0) +#define DB_OPT_FTRACE (1<<0) +#define DB_OPT_PRINTK_TOO_MUCH (1<<1) +#define DB_OPT_NE_JBT_TRACES (1<<2) +#define DB_OPT_SWT_JBT_TRACES (1<<3) +#define DB_OPT_VM_TRACES (1<<4) +#define DB_OPT_DUMPSYS_ACTIVITY (1<<5) +#define DB_OPT_DUMPSYS_WINDOW (1<<6) +#define DB_OPT_DUMPSYS_GFXINFO (1<<7) +#define DB_OPT_DUMPSYS_SURFACEFLINGER (1<<8) +#define DB_OPT_DISPLAY_HANG_DUMP (1<<9) +#define DB_OPT_LOW_MEMORY_KILLER (1<<10) +#define DB_OPT_PROC_MEM (1<<11) +#define DB_OPT_FS_IO_LOG (1<<12) +#define DB_OPT_PROCESS_COREDUMP (1<<13) +#define DB_OPT_VM_HPROF (1<<14) +#define DB_OPT_PROCMEM (1<<15) +#define DB_OPT_DUMPSYS_INPUT (1<<16) +#define DB_OPT_MMPROFILE_BUFFER (1<<17) +#define DB_OPT_BINDER_INFO (1<<18) +#define DB_OPT_WCN_ISSUE_INFO (1<<19) +#define DB_OPT_DUMMY_DUMP (1<<20) +#define DB_OPT_PID_MEMORY_INFO (1<<21) +#define DB_OPT_VM_OOME_HPROF (1<<22) +#define DB_OPT_PID_SMAPS (1<<23) +#define DB_OPT_PROC_CMDQ_INFO (1<<24) +#define DB_OPT_PROC_USKTRK (1<<25) +#define DB_OPT_SF_RTT_DUMP (1<<26) +#define DB_OPT_PAGETYPE_INFO (1<<27) +#define DB_OPT_DUMPSYS_PROCSTATS (1<<28) +#define DB_OPT_DUMP_DISPLAY (1<<29) +#define DB_OPT_NATIVE_BACKTRACE (1<<30) +#define DB_OPT_AARCH64 (1<<31) + +#define aee_kernel_exception(module, msg...) \ + aee_kernel_exception_api(__FILE__, __LINE__, DB_OPT_DEFAULT, module, msg) +#define aee_kernel_warning(module, msg...) \ + aee_kernel_warning_api(__FILE__, __LINE__, DB_OPT_DEFAULT, module, msg) +#define aee_kernel_reminding(module, msg...) \ + aee_kernel_reminding_api(__FILE__, __LINE__, DB_OPT_DEFAULT, module, msg) +#define aee_kernel_dal_show(msg) \ + aee_kernel_dal_api(__FILE__, __LINE__, msg) + +#define aed_md_exception(log, log_size, phy, phy_size, detail) \ + aed_md_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) +#define aed_md32_exception(log, log_size, phy, phy_size, detail) \ + aed_md32_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) +#define aed_scp_exception(log, log_size, phy, phy_size, detail) \ + aed_scp_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) +#define aed_combo_exception(log, log_size, phy, phy_size, detail) \ + aed_combo_exception_api(log, log_size, phy, phy_size, detail, DB_OPT_DEFAULT) + +void aee_kernel_exception_api(const char *file, const int line, const int db_opt, + const char *module, const char *msg, ...); +void aee_kernel_warning_api(const char *file, const int line, const int db_opt, const char *module, + const char *msg, ...); +void aee_kernel_reminding_api(const char *file, const int line, const int db_opt, + const char *module, const char *msg, ...); +void aee_kernel_dal_api(const char *file, const int line, const char *msg); + +void aed_md_exception_api(const int *log, int log_size, const int *phy, int phy_size, + const char *detail, const int db_opt); +void aed_md32_exception_api(const int *log, int log_size, const int *phy, int phy_size, + const char *detail, const int db_opt); +void aed_scp_exception_api(const int *log, int log_size, const int *phy, int phy_size, + const char *detail, const int db_opt); +void aed_combo_exception_api(const int *log, int log_size, const int *phy, int phy_size, + const char *detail, const int db_opt); + +void aee_kernel_wdt_kick_Powkey_api(const char *module, int msg); +int aee_kernel_wdt_kick_api(int kinterval); +void aee_powerkey_notify_press(unsigned long pressed); +int aee_kernel_Powerkey_is_press(void); + +void ipanic_recursive_ke(struct pt_regs *regs, struct pt_regs *excp_regs, int cpu); + +/* QHQ RT Monitor */ +void aee_kernel_RT_Monitor_api(int lParam); +/* QHQ RT Monitor end */ +void mt_fiq_printf(const char *fmt, ...); +void aee_register_api(struct aee_kernel_api *aee_api); +int aee_in_nested_panic(void); +void aee_stop_nested_panic(struct pt_regs *regs); +void aee_wdt_dump_info(void); +void aee_wdt_printf(const char *fmt, ...); + +void aee_fiq_ipi_cpu_stop(void *arg, void *regs, void *svc_sp); + +#if defined(CONFIG_MTK_AEE_DRAM_CONSOLE) +void aee_dram_console_reserve_memory(void); +#else +static inline void aee_dram_console_reserve_memory(void) +{ +} +#endif + +extern void *aee_excp_regs; /* To store latest exception, in case of stack corruption */ +#endif /* __AEE_H__ */ diff --git a/drivers/misc/mediatek/include/mt-plat/mrdump.h b/drivers/misc/mediatek/include/mt-plat/mrdump.h new file mode 100644 index 00000000000000..b6bdfa2f7617cb --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mrdump.h @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#if !defined(__MRDUMP_H__) +#define __MRDUMP_H__ + +#include <stdarg.h> +#include <linux/elf.h> +#include <linux/elfcore.h> +#include <asm/ptrace.h> +#include <mt-plat/aee.h> + +#ifdef __aarch64__ +#define reg_pc pc +#define reg_lr regs[30] +#define reg_sp sp +#define reg_fp regs[29] +#else +#define reg_pc ARM_pc +#define reg_lr ARM_lr +#define reg_sp ARM_sp +#define reg_ip ARM_ip +#define reg_fp ARM_fp +#endif + +#define MRDUMP_CPU_MAX 16 + +#define MRDUMP_DEV_NULL 0 +#define MRDUMP_DEV_SDCARD 1 +#define MRDUMP_DEV_EMMC 2 + +#define MRDUMP_FS_NULL 0 +#define MRDUMP_FS_VFAT 1 +#define MRDUMP_FS_EXT4 2 + +#define MRDUMP_GO_DUMP "MRDUMP04" + +typedef uint32_t arm32_gregset_t[18]; +typedef uint64_t aarch64_gregset_t[34]; + +struct mrdump_crash_record { + int reboot_mode; + + char msg[128]; + char backtrace[512]; + + uint32_t fault_cpu; + + union { + arm32_gregset_t arm32_regs; + aarch64_gregset_t aarch64_regs; + } cpu_regs[MRDUMP_CPU_MAX]; +}; + +struct mrdump_machdesc { + uint32_t crc; + + uint32_t output_device; + + uint32_t nr_cpus; + + uint64_t page_offset; + uint64_t high_memory; + + uint64_t vmalloc_start; + uint64_t vmalloc_end; + + uint64_t modules_start; + uint64_t modules_end; + + uint64_t phys_offset; + uint64_t master_page_table; + + uint32_t output_fstype; + uint32_t output_lbaooo; +}; + +struct mrdump_control_block { + char sig[8]; + + struct mrdump_machdesc machdesc; + struct mrdump_crash_record crash_record; +}; + +/* NOTE!! any change to this struct should be compatible in aed */ +struct mrdump_mini_reg_desc { + unsigned long reg; /* register value */ + unsigned long kstart; /* start kernel addr of memory dump */ + unsigned long kend; /* end kernel addr of memory dump */ + unsigned long pos; /* next pos to dump */ + int valid; /* 1: valid regiser, 0: invalid regiser */ + int pad; /* reserved */ + loff_t offset; /* offset in buffer */ +}; + +/* it should always be smaller than MRDUMP_MINI_HEADER_SIZE */ +struct mrdump_mini_header { + struct mrdump_mini_reg_desc reg_desc[ELF_NGREG]; +}; + +#define MRDUMP_MINI_NR_SECTION 60 +#define MRDUMP_MINI_SECTION_SIZE (32 * 1024) +#define NT_IPANIC_MISC 4095 +#define MRDUMP_MINI_NR_MISC 20 + +struct mrdump_mini_elf_misc { + unsigned long vaddr; + unsigned long paddr; + unsigned long start; + unsigned long size; +}; + +#define NOTE_NAME_SHORT 12 +#define NOTE_NAME_LONG 20 + +struct mrdump_mini_elf_psinfo { + struct elf_note note; + char name[NOTE_NAME_SHORT]; + struct elf_prpsinfo data; +}; + +struct mrdump_mini_elf_prstatus { + struct elf_note note; + char name[NOTE_NAME_SHORT]; + struct elf_prstatus data; +}; + +struct mrdump_mini_elf_note { + struct elf_note note; + char name[NOTE_NAME_LONG]; + struct mrdump_mini_elf_misc data; +}; + +struct mrdump_mini_elf_header { + struct elfhdr ehdr; + struct elf_phdr phdrs[MRDUMP_MINI_NR_SECTION]; + struct mrdump_mini_elf_psinfo psinfo; + struct mrdump_mini_elf_prstatus prstatus[NR_CPUS + 1]; + struct mrdump_mini_elf_note misc[MRDUMP_MINI_NR_MISC]; +}; + +typedef struct mrdump_rsvmem_block { + phys_addr_t start_addr; + phys_addr_t size; +} mrdump_rsvmem_block_t; + + +#define MRDUMP_MINI_HEADER_SIZE ALIGN(sizeof(struct mrdump_mini_elf_header), PAGE_SIZE) +#define MRDUMP_MINI_DATA_SIZE (MRDUMP_MINI_NR_SECTION * MRDUMP_MINI_SECTION_SIZE) +#define MRDUMP_MINI_BUF_SIZE (MRDUMP_MINI_HEADER_SIZE + MRDUMP_MINI_DATA_SIZE) + +#ifdef CONFIG_MTK_RAM_CONSOLE_DRAM_ADDR +#define MRDUMP_MINI_BUF_PADDR (CONFIG_MTK_RAM_CONSOLE_DRAM_ADDR + 0xf0000) +#else +#define MRDUMP_MINI_BUF_PADDR 0 +#endif + +int mrdump_init(void); +void __mrdump_create_oops_dump(AEE_REBOOT_MODE reboot_mode, struct pt_regs *regs, const char *msg, + ...); +#if defined(CONFIG_MTK_AEE_IPANIC) +void mrdump_rsvmem(void); +#else +static inline void mrdump_rsvmem(void) +{ +} +#endif + +#if defined(CONFIG_MTK_AEE_MRDUMP) +void aee_kdump_reboot(AEE_REBOOT_MODE, const char *msg, ...); +#else +static inline void aee_kdump_reboot(AEE_REBOOT_MODE reboot_mode, const char *msg, ...) +{ +} +#endif + +typedef int (*mrdump_write)(void *buf, int off, int len, int encrypt); +#if defined(CONFIG_MTK_AEE_IPANIC) +int mrdump_mini_create_oops_dump(AEE_REBOOT_MODE reboot_mode, mrdump_write write, + loff_t sd_offset, const char *msg, va_list ap); +void mrdump_mini_reserve_memory(void); +#else +static inline int mrdump_mini_create_oops_dump(AEE_REBOOT_MODE reboot_mode, mrdump_write write, + loff_t sd_offset, const char *msg, va_list ap) +{ + return 0; +} + +static inline void mrdump_mini_reserve_memory(void) +{ +} +#endif + +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h b/drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h new file mode 100644 index 00000000000000..1b60f007d0fdff --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mt7622/include/mach/mtk_thermal.h @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +#ifndef _MT8167_THERMAL_H +#define _MT8167_THERMAL_H + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> + +#include <linux/io.h> +#include <linux/uaccess.h> + +#include "sync_write.h" + +extern void __iomem *thermal_base; +extern void __iomem *auxadc_ts_base; +extern void __iomem *apmixed_base; +extern void __iomem *pericfg_base; +extern int auxadc_ts_phy_base; +extern int apmixed_phy_base; + +#define THERM_CTRL_BASE_2 thermal_base +#define AUXADC_BASE_2 auxadc_ts_base +#define PERICFG_BASE pericfg_base +#define APMIXED_BASE_2 apmixed_base + +#define MT6752_EVB_BUILD_PASS /*Jerry fix build error FIX_ME*/ + +/******************************************************************************* +* AUXADC Register Definition +******************************************************************************/ +/*AUXADC_BASE: 0xF1001000 from Vincent Liang 2014.5.8*/ + +#define AUXADC_CON0_V (AUXADC_BASE_2 + 0x000) /*yes, 0x11003000*/ +#define AUXADC_CON1_V (AUXADC_BASE_2 + 0x004) +#define AUXADC_CON1_SET_V (AUXADC_BASE_2 + 0x008) +#define AUXADC_CON1_CLR_V (AUXADC_BASE_2 + 0x00C) +#define AUXADC_CON2_V (AUXADC_BASE_2 + 0x010) +/*#define AUXADC_CON3_V (AUXADC_BASE_2 + 0x014)*/ +#define AUXADC_DAT0_V (AUXADC_BASE_2 + 0x014) +#define AUXADC_DAT1_V (AUXADC_BASE_2 + 0x018) +#define AUXADC_DAT2_V (AUXADC_BASE_2 + 0x01C) +#define AUXADC_DAT3_V (AUXADC_BASE_2 + 0x020) +#define AUXADC_DAT4_V (AUXADC_BASE_2 + 0x024) +#define AUXADC_DAT5_V (AUXADC_BASE_2 + 0x028) +#define AUXADC_DAT6_V (AUXADC_BASE_2 + 0x02C) +#define AUXADC_DAT7_V (AUXADC_BASE_2 + 0x030) +#define AUXADC_DAT8_V (AUXADC_BASE_2 + 0x034) +#define AUXADC_DAT9_V (AUXADC_BASE_2 + 0x038) +#define AUXADC_DAT10_V (AUXADC_BASE_2 + 0x03C) +#define AUXADC_DAT11_V (AUXADC_BASE_2 + 0x040) +#define AUXADC_MISC_V (AUXADC_BASE_2 + 0x094) + +#define AUXADC_CON0_P (auxadc_ts_phy_base + 0x000) +#define AUXADC_CON1_P (auxadc_ts_phy_base + 0x004) +#define AUXADC_CON1_SET_P (auxadc_ts_phy_base + 0x008) +#define AUXADC_CON1_CLR_P (auxadc_ts_phy_base + 0x00C) +#define AUXADC_CON2_P (auxadc_ts_phy_base + 0x010) +/*#define AUXADC_CON3_P (auxadc_ts_phy_base + 0x014)*/ +#define AUXADC_DAT0_P (auxadc_ts_phy_base + 0x014) +#define AUXADC_DAT1_P (auxadc_ts_phy_base + 0x018) +#define AUXADC_DAT2_P (auxadc_ts_phy_base + 0x01C) +#define AUXADC_DAT3_P (auxadc_ts_phy_base + 0x020) +#define AUXADC_DAT4_P (auxadc_ts_phy_base + 0x024) +#define AUXADC_DAT5_P (auxadc_ts_phy_base + 0x028) +#define AUXADC_DAT6_P (auxadc_ts_phy_base + 0x02C) +#define AUXADC_DAT7_P (auxadc_ts_phy_base + 0x030) +#define AUXADC_DAT8_P (auxadc_ts_phy_base + 0x034) +#define AUXADC_DAT9_P (auxadc_ts_phy_base + 0x038) +#define AUXADC_DAT10_P (auxadc_ts_phy_base + 0x03C) +#define AUXADC_DAT11_P (auxadc_ts_phy_base + 0x040) + +#define AUXADC_MISC_P (auxadc_ts_phy_base + 0x094) + +/******************************************************************************* +* Peripheral Configuration Register Definition +******************************************************************************/ +/*#define PERICFG_BASE (0x10002000)*/ +#define PERI_GLOBALCON_RST0 (pericfg_base + 0x000) /*yes, 0x10002000*/ +/******************************************************************************* + * APMixedSys Configuration Register Definition + ******************************************************************************/ +#define TS_CON0 (APMIXED_BASE_2 + 0x600) /*yes 0x10209000*/ +#define TS_CON1 (APMIXED_BASE_2 + 0x604) +#define TS_CON0_TM (APMIXED_BASE_2 + 0x600) /* yes 0x10209000 */ +#define TS_CON1_TM (APMIXED_BASE_2 + 0x604) +#define TS_CON0_P (apmixed_phy_base + 0x600) +#define TS_CON1_P (apmixed_phy_base + 0x604) + +/******************************************************************************* + * Thermal Controller Register Definition + ******************************************************************************/ +#define TEMPMONCTL0 (THERM_CTRL_BASE_2 + 0x000) /*yes 0x1100B000*/ +#define TEMPMONCTL1 (THERM_CTRL_BASE_2 + 0x004) +#define TEMPMONCTL2 (THERM_CTRL_BASE_2 + 0x008) +#define TEMPMONINT (THERM_CTRL_BASE_2 + 0x00C) +#define TEMPMONINTSTS (THERM_CTRL_BASE_2 + 0x010) +#define TEMPMONIDET0 (THERM_CTRL_BASE_2 + 0x014) +#define TEMPMONIDET1 (THERM_CTRL_BASE_2 + 0x018) +#define TEMPMONIDET2 (THERM_CTRL_BASE_2 + 0x01C) +#define TEMPH2NTHRE (THERM_CTRL_BASE_2 + 0x024) +#define TEMPHTHRE (THERM_CTRL_BASE_2 + 0x028) +#define TEMPCTHRE (THERM_CTRL_BASE_2 + 0x02C) +#define TEMPOFFSETH (THERM_CTRL_BASE_2 + 0x030) +#define TEMPOFFSETL (THERM_CTRL_BASE_2 + 0x034) +#define TEMPMSRCTL0 (THERM_CTRL_BASE_2 + 0x038) +#define TEMPMSRCTL1 (THERM_CTRL_BASE_2 + 0x03C) +#define TEMPAHBPOLL (THERM_CTRL_BASE_2 + 0x040) +#define TEMPAHBTO (THERM_CTRL_BASE_2 + 0x044) +#define TEMPADCPNP0 (THERM_CTRL_BASE_2 + 0x048) +#define TEMPADCPNP1 (THERM_CTRL_BASE_2 + 0x04C) +#define TEMPADCPNP2 (THERM_CTRL_BASE_2 + 0x050) +#define TEMPADCPNP3 (THERM_CTRL_BASE_2 + 0x0B4) + +#define TEMPADCMUX (THERM_CTRL_BASE_2 + 0x054) +#define TEMPADCEXT (THERM_CTRL_BASE_2 + 0x058) +#define TEMPADCEXT1 (THERM_CTRL_BASE_2 + 0x05C) +#define TEMPADCEN (THERM_CTRL_BASE_2 + 0x060) +#define TEMPPNPMUXADDR (THERM_CTRL_BASE_2 + 0x064) +#define TEMPADCMUXADDR (THERM_CTRL_BASE_2 + 0x068) +#define TEMPADCEXTADDR (THERM_CTRL_BASE_2 + 0x06C) +#define TEMPADCEXT1ADDR (THERM_CTRL_BASE_2 + 0x070) +#define TEMPADCENADDR (THERM_CTRL_BASE_2 + 0x074) +#define TEMPADCVALIDADDR (THERM_CTRL_BASE_2 + 0x078) +#define TEMPADCVOLTADDR (THERM_CTRL_BASE_2 + 0x07C) +#define TEMPRDCTRL (THERM_CTRL_BASE_2 + 0x080) +#define TEMPADCVALIDMASK (THERM_CTRL_BASE_2 + 0x084) +#define TEMPADCVOLTAGESHIFT (THERM_CTRL_BASE_2 + 0x088) +#define TEMPADCWRITECTRL (THERM_CTRL_BASE_2 + 0x08C) +#define TEMPMSR0 (THERM_CTRL_BASE_2 + 0x090) +#define TEMPMSR1 (THERM_CTRL_BASE_2 + 0x094) +#define TEMPMSR2 (THERM_CTRL_BASE_2 + 0x098) +#define TEMPMSR3 (THERM_CTRL_BASE_2 + 0x0B8) + +#define TEMPIMMD0 (THERM_CTRL_BASE_2 + 0x0A0) +#define TEMPIMMD1 (THERM_CTRL_BASE_2 + 0x0A4) +#define TEMPIMMD2 (THERM_CTRL_BASE_2 + 0x0A8) +#define TEMPIMMD3 (THERM_CTRL_BASE_2 + 0x0BC) + + +#define TEMPPROTCTL (THERM_CTRL_BASE_2 + 0x0C0) +#define TEMPPROTTA (THERM_CTRL_BASE_2 + 0x0C4) +#define TEMPPROTTB (THERM_CTRL_BASE_2 + 0x0C8) +#define TEMPPROTTC (THERM_CTRL_BASE_2 + 0x0CC) + +#define TEMPSPARE0 (THERM_CTRL_BASE_2 + 0x0F0) +#define TEMPSPARE1 (THERM_CTRL_BASE_2 + 0x0F4) +#define TEMPSPARE2 (THERM_CTRL_BASE_2 + 0x0F8) +#define TEMPSPARE3 (THERM_CTRL_BASE_2 + 0x0FC) + +#define PTPCORESEL (THERM_CTRL_BASE_2 + 0x400) +#define THERMINTST (THERM_CTRL_BASE_2 + 0x404) +#define PTPODINTST (THERM_CTRL_BASE_2 + 0x408) +#define THSTAGE0ST (THERM_CTRL_BASE_2 + 0x40C) +#define THSTAGE1ST (THERM_CTRL_BASE_2 + 0x410) +#define THSTAGE2ST (THERM_CTRL_BASE_2 + 0x414) +#define THAHBST0 (THERM_CTRL_BASE_2 + 0x418) +#define THAHBST1 (THERM_CTRL_BASE_2 + 0x41C) /*Only for DE debug*/ +#define PTPSPARE0 (THERM_CTRL_BASE_2 + 0x420) +#define PTPSPARE1 (THERM_CTRL_BASE_2 + 0x424) +#define PTPSPARE2 (THERM_CTRL_BASE_2 + 0x428) +#define PTPSPARE3 (THERM_CTRL_BASE_2 + 0x42C) +#define THSLPEVEB (THERM_CTRL_BASE_2 + 0x430) + + +#define PTPSPARE0_P (thermal_phy_base + 0x420) +#define PTPSPARE1_P (thermal_phy_base + 0x424) +#define PTPSPARE2_P (thermal_phy_base + 0x428) +#define PTPSPARE3_P (thermal_phy_base + 0x42C) + +/******************************************************************************* + * Thermal Controller Register Mask Definition + ******************************************************************************/ +#define THERMAL_ENABLE_SEN0 0x1 +#define THERMAL_ENABLE_SEN1 0x2 +#define THERMAL_ENABLE_SEN2 0x4 +#define THERMAL_MONCTL0_MASK 0x00000007 + +#define THERMAL_PUNT_MASK 0x00000FFF +#define THERMAL_FSINTVL_MASK 0x03FF0000 +#define THERMAL_SPINTVL_MASK 0x000003FF +#define THERMAL_MON_INT_MASK 0x0007FFFF + +#define THERMAL_MON_CINTSTS0 0x000001 +#define THERMAL_MON_HINTSTS0 0x000002 +#define THERMAL_MON_LOINTSTS0 0x000004 +#define THERMAL_MON_HOINTSTS0 0x000008 +#define THERMAL_MON_NHINTSTS0 0x000010 +#define THERMAL_MON_CINTSTS1 0x000020 +#define THERMAL_MON_HINTSTS1 0x000040 +#define THERMAL_MON_LOINTSTS1 0x000080 +#define THERMAL_MON_HOINTSTS1 0x000100 +#define THERMAL_MON_NHINTSTS1 0x000200 +#define THERMAL_MON_CINTSTS2 0x000400 +#define THERMAL_MON_HINTSTS2 0x000800 +#define THERMAL_MON_LOINTSTS2 0x001000 +#define THERMAL_MON_HOINTSTS2 0x002000 +#define THERMAL_MON_NHINTSTS2 0x004000 +#define THERMAL_MON_TOINTSTS 0x008000 +#define THERMAL_MON_IMMDINTSTS0 0x010000 +#define THERMAL_MON_IMMDINTSTS1 0x020000 +#define THERMAL_MON_IMMDINTSTS2 0x040000 +#define THERMAL_MON_FILTINTSTS0 0x080000 +#define THERMAL_MON_FILTINTSTS1 0x100000 +#define THERMAL_MON_FILTINTSTS2 0x200000 + + +#define THERMAL_tri_SPM_State0 0x20000000 +#define THERMAL_tri_SPM_State1 0x40000000 +#define THERMAL_tri_SPM_State2 0x80000000 + + +#define THERMAL_MSRCTL0_MASK 0x00000007 +#define THERMAL_MSRCTL1_MASK 0x00000038 +#define THERMAL_MSRCTL2_MASK 0x000001C0 + +enum thermal_sensor_name { + THERMAL_SENSOR1 = 0,/*TS_MCU1*/ + THERMAL_SENSOR_NUM +}; + +enum thermal_bank_name { + THERMAL_BANK0 = 0, /*CPU (TS_MCU1) (TS1)*/ + THERMAL_BANK_NUM +}; + +struct TS_SVS { + unsigned int ts_MTS; + unsigned int ts_BTS; +}; + +struct mtk_gpu_power_info { + unsigned int gpufreq_khz; + unsigned int gpufreq_power; +}; + +/* svs driver need this function */ +extern void get_thermal_slope_intercept(struct TS_SVS *ts_info, enum thermal_bank_name ts_bank); + +/* mtk_thermal_platform.c need this */ +extern void set_taklking_flag(bool flag); + +#define THERMAL_WRAP_WR32(val, addr) mt_reg_sync_writel((val), ((void *)addr)) + +enum MTK_THERMAL_SENSOR_CPU_ID_MET { + MTK_THERMAL_SENSOR_TS1 = 0, + MTK_THERMAL_SENSOR_TS2, + MTK_THERMAL_SENSOR_TS3, + MTK_THERMAL_SENSOR_TS4, + MTK_THERMAL_SENSOR_TSABB, + + ATM_CPU_LIMIT, + ATM_GPU_LIMIT, + + MTK_THERMAL_SENSOR_CPU_COUNT +}; + +extern int tscpu_get_cpu_temp_met(enum MTK_THERMAL_SENSOR_CPU_ID_MET id); +extern int mtk_gpufreq_register(struct mtk_gpu_power_info *freqs, int num); + +typedef void (*met_thermalsampler_funcMET)(void); +void mt_thermalsampler_registerCB(met_thermalsampler_funcMET pCB); + +void tscpu_start_thermal(void); +void tscpu_stop_thermal(void); +void tscpu_cancel_thermal_timer(void); +void tscpu_start_thermal_timer(void); +int mtkts_bts_get_hw_temp(void); + +extern int get_immediate_ts1_wrap(void); +extern int get_immediate_ts2_wrap(void); +extern int get_immediate_ts3_wrap(void); + +extern int is_cpu_power_unlimit(void); /* in mtk_ts_cpu.c */ +extern int is_cpu_power_min(void); /* in mtk_ts_cpu.c */ +extern int get_cpu_target_tj(void); +extern int get_cpu_target_offset(void); + +extern int mtktscpu_debug_log; + +#endif + diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h new file mode 100644 index 00000000000000..142a007805b952 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_freqhopping.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2011 MediaTek, Inc. + * + * Author: Holmes Chiou <holmes.chiou@mediatek.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __MT_FREQHOPPING_H__ +#define __MT_FREQHOPPING_H__ + +#define MT_FHPLL_MAX 6 +#define MT_SSC_NR_PREDEFINE_SETTING 10 /* TODO: is 10 a good number ? */ + +#define MEMPLL_SSC 0 +#define MAINPLL_SSC 1 + +#define FHTAG "[FH]" + +#define VERBOSE_DEBUG 0 + +#if VERBOSE_DEBUG +#define FH_MSG(fmt, args...) \ + pr_debug(FHTAG""fmt" <- %s(): L<%d> PID<%s><%d>\n", ##args, __func__, __LINE__, current->comm, current->pid) +#else + +#if 1 /* log level is 6 xlog */ +#define FH_MSG(fmt, args...) pr_debug(fmt, ##args) +#else /* log level is 4 (printk) */ +#define FH_MSG(fmt, args...) printk(FHTAG""fmt"\n", ##args) +#endif + +#endif + +/* not support at mt2701 yet */ +/* DRAMC */ +#define FULLY_VERSION_FHCTL 0 + +enum FH_FH_STATUS { + FH_FH_DISABLE = 0, + FH_FH_ENABLE_SSC, + FH_FH_ENABLE_DFH, + FH_FH_ENABLE_DVFS, +}; + +enum FH_PLL_STATUS { + FH_PLL_DISABLE = 0, + FH_PLL_ENABLE = 1 +}; + +/* TODO: FREQ_MODIFIED should not be here */ +/* FH_PLL_STATUS_FREQ_MODIFIED = 3 */ + + +enum FH_CMD { + FH_CMD_ENABLE = 1, + FH_CMD_DISABLE, + FH_CMD_ENABLE_USR_DEFINED, + FH_CMD_DISABLE_USR_DEFINED, + FH_CMD_INTERNAL_MAX_CMD, +/* TODO: do we need these cmds ? + * FH_CMD_PLL_ENABLE, + * FH_CMD_PLL_DISABLE, + * FH_CMD_EXT_ALL_FULL_RANGE_CMD, + * FH_CMD_EXT_ALL_HALF_RANGE_CMD, + * FH_CMD_EXT_DISABLE_ALL_CMD, + * FH_CMD_EXT_DESIGNATED_PLL_FULL_RANGE_CMD, + * FH_CMD_EXT_DESIGNATED_PLL_AND_SETTING_CMD +*/ +}; + +/* + * enum FH_OPCODE{ + * FH_OPCODE_ENABLE_WITH_ID = 1, + * FH_OPCODE_ENABLE_WITHOUT_ID, + * FH_OPCODE_DISABLE, + * }; +*/ + +enum FH_PLL_ID { + MT658X_FH_MINIMUMM_PLL = 0, + MT658X_FH_ARM_PLL = MT658X_FH_MINIMUMM_PLL, + MT658X_FH_MAIN_PLL = 1, + MT658X_FH_MEM_PLL = 2, + MT658X_FH_MSDC_PLL = 3, + MT658X_FH_MM_PLL = 4, /* MT658X_FH_TVD_PLL = 4, */ + MT658X_FH_VENC_PLL = 5, /* MT658X_FH_LVDS_PLL = 5, */ + /* 8127 FHCTL MB */ + MT658X_FH_TVD_PLL = 6, /* MT658X_FH_TVD_PLL = 6, */ + MT658X_FH_MAXIMUMM_PLL = MT658X_FH_TVD_PLL, + /* 8127 FHCTL ME */ + MT658X_FH_PLL_TOTAL_NUM +}; + +/* keep track the status of each PLL */ +/* TODO: do we need another "uint mode" for Dynamic FH */ +typedef struct { + unsigned int fh_status; + unsigned int pll_status; + unsigned int setting_id; + unsigned int curr_freq; + unsigned int user_defined; +} fh_pll_t; + + +/* Record the owner of enable freq hopping <==TBD */ +struct freqhopping_pll { + union { + int mt_pll[MT_FHPLL_MAX]; + struct { + int mt_arm_fhpll; + int mt_main_fhpll; + int mt_mem_fhpll; + int mt_msdc_fhpll; + int mt_mm_fhpll; + int mt_venc_fhpll; + }; + }; +}; + +struct freqhopping_ssc { + unsigned int freq; + unsigned int dt; + unsigned int df; + unsigned int upbnd; + unsigned int lowbnd; + unsigned int dds; +}; + +struct freqhopping_ioctl { + unsigned int pll_id; + struct freqhopping_ssc ssc_setting; /* used only when user-define */ + int result; +}; + +int freqhopping_config(unsigned int pll_id, unsigned long vco_freq, unsigned int enable); +void mt_freqhopping_init(void); +void mt_freqhopping_pll_init(void); +int mt_h2l_mempll(void); +int mt_l2h_mempll(void); +int mt_h2l_dvfs_mempll(void); +int mt_l2h_dvfs_mempll(void); +int mt_dfs_armpll(unsigned int current_freq, unsigned int target_freq); +int mt_is_support_DFS_mode(void); +void mt_fh_popod_save(void); +void mt_fh_popod_restore(void); +int mt_fh_dram_overclock(int clk); +int mt_fh_get_dramc(void); +unsigned int mt_get_emi_freq(void); + +#endif /* !__MT_FREQHOPPING_H__ */ diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h new file mode 100644 index 00000000000000..0c049db9aa977e --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mt_spm_mtcmos.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> + +#define STA_POWER_DOWN 0 +#define STA_POWER_ON 1 + +/* + * 1. for CPU MTCMOS: CPU0, CPU1, CPU2, CPU3, DBG0, CPU4, CPU5, CPU6, CPU7, DBG1, CPUSYS1 + * 2. call spm_mtcmos_cpu_lock/unlock() before/after any operations + */ +extern int spm_mtcmos_cpu_init(void); +extern void spm_mtcmos_cpu_lock(unsigned long *flags); +extern void spm_mtcmos_cpu_unlock(unsigned long *flags); +extern int spm_mtcmos_ctrl_cpu(unsigned int cpu, int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu0(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu1(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu2(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu3(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu4(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu5(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu6(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpu7(int state, int chkWfiBeforePdn); +extern int spm_mtcmos_ctrl_cpusys0(int state, int chkWfiBeforePdn); +extern bool spm_cpusys0_can_power_down(void); diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h new file mode 100644 index 00000000000000..28176b3cd9af16 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_boot_share_page.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_BOOT_SHARE_PAGE_H__ +#define __MTK_BOOT_SHARE_PAGE_H__ + +#define BOOT_SHARE_BASE (0xC0002000) /* address in linux kernel */ +#define BOOT_SHARE_SIZE (0x1000) /* page size 4K bytes */ + +#define BOOT_SHARE_MAGIC (0x4545544D) /* MTEE */ + +/* Memory map & defines for boot share page */ +/* + * Note: + * 1. BOOT_SHARE_XXXXX_OFST is the address offset related to BOOT_SHARE_BASE + */ +#define BOOT_SHARE_MAGIC1_OFST (0) +#define BOOT_SHARE_MAGIC1_SIZE (4) + +#define BOOT_SHARE_DEV_INFO_OFST (BOOT_SHARE_MAGIC1_OFST+BOOT_SHARE_MAGIC1_SIZE) +#define BOOT_SHARE_DEV_INFO_SIZE (16) + +#define BOOT_SHARE_HOTPLUG_OFST (1008) /* 16 bytes for hotplug/jump-reg */ +#define BOOT_SHARE_HOTPLUG_SIZE (32) + +#define BOOT_SHARE_MAGIC2_OFST (4092) +#define BOOT_SHARE_MAGIC2_SIZE (4) + +#endif /* __MTK_BOOT_SHARE_PAGE_H__ */ diff --git a/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h new file mode 100644 index 00000000000000..eefdaad4aaa5de --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mt8127/include/mach/mtk_thermal.h @@ -0,0 +1,301 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +#ifndef _MT8127_THERMAL_H +#define _MT8127_THERMAL_H + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> + +#include <linux/io.h> +#include <linux/uaccess.h> + +#include "mt-plat/sync_write.h" +#include <linux/types.h> + +/* #include <mach/mt_gpufreq.h> */ +/* #include "../../../../../thermal/mt8127/inc/mt_gpufreq.h" */ + +#if 1 +extern void __iomem *thermal_base; +extern void __iomem *auxadc_ts_base; +extern void __iomem *pericfg_base; +extern void __iomem *apmixed_ts_base; + +extern int mtktscpu_limited_dmips; + +void __attribute__ ((weak)) mt_gpufreq_thermal_protect(unsigned int limited_power) { +} + +unsigned int __attribute__ ((weak)) mt_gpufreq_get_cur_freq(void) { + return 0; +} + +u32 __attribute__ ((weak)) get_devinfo_with_index(u32 index) { + return 0; +} + +extern int IMM_GetOneChannelValue(int dwChannel, int data[4], int *rawdata); +extern int IMM_IsAdcInitReady(void); +extern int PMIC_IMM_GetOneChannelValue(int dwChannel, int deCount, int trimd); +extern int thermal_phy_base; +extern int auxadc_ts_phy_base; +extern int apmixed_phy_base; +extern int pericfg_phy_base; + +/* extern int last_abb_t; */ +/* extern int last_CPU2_t; */ +extern int get_immediate_temp2_wrap(void); +extern void mtkts_dump_cali_info(void); +extern u32 get_devinfo_with_index(u32 index); +extern int bts_cur_temp; + +#define THERM_CTRL_BASE_2 thermal_base +#define AUXADC_BASE_2 auxadc_ts_base +#define PERICFG_BASE_2 pericfg_base +#define APMIXED_BASE_2 apmixed_ts_base +#endif + +/******************************************************************************* + * AUXADC Register Definition + ******************************************************************************/ +#define AUXADC_CON0_V (AUXADC_BASE_2 + 0x000) /* yes, 0x11001000 */ +#define AUXADC_CON1_V (AUXADC_BASE_2 + 0x004) +#define AUXADC_CON1_SET_V (AUXADC_BASE_2 + 0x008) +#define AUXADC_CON1_CLR_V (AUXADC_BASE_2 + 0x00C) +#define AUXADC_CON2_V (AUXADC_BASE_2 + 0x010) +#define AUXADC_DAT0_V (AUXADC_BASE_2 + 0x014) +#define AUXADC_DAT1_V (AUXADC_BASE_2 + 0x018) +#define AUXADC_DAT2_V (AUXADC_BASE_2 + 0x01C) +#define AUXADC_DAT3_V (AUXADC_BASE_2 + 0x020) +#define AUXADC_DAT4_V (AUXADC_BASE_2 + 0x024) +#define AUXADC_DAT5_V (AUXADC_BASE_2 + 0x028) +#define AUXADC_DAT6_V (AUXADC_BASE_2 + 0x02C) +#define AUXADC_DAT7_V (AUXADC_BASE_2 + 0x030) +#define AUXADC_DAT8_V (AUXADC_BASE_2 + 0x034) +#define AUXADC_DAT9_V (AUXADC_BASE_2 + 0x038) +#define AUXADC_DAT10_V (AUXADC_BASE_2 + 0x03C) +#define AUXADC_DAT11_V (AUXADC_BASE_2 + 0x040) +#define AUXADC_MISC_V (AUXADC_BASE_2 + 0x094) +#define AUXADC_CON0_P (auxadc_ts_phy_base + 0x000) +#define AUXADC_CON1_P (auxadc_ts_phy_base + 0x004) +#define AUXADC_CON1_SET_P (auxadc_ts_phy_base + 0x008) +#define AUXADC_CON1_CLR_P (auxadc_ts_phy_base + 0x00C) +#define AUXADC_CON2_P (auxadc_ts_phy_base + 0x010) +#define AUXADC_DAT0_P (auxadc_ts_phy_base + 0x014) +#define AUXADC_DAT1_P (auxadc_ts_phy_base + 0x018) +#define AUXADC_DAT2_P (auxadc_ts_phy_base + 0x01C) +#define AUXADC_DAT3_P (auxadc_ts_phy_base + 0x020) +#define AUXADC_DAT4_P (auxadc_ts_phy_base + 0x024) +#define AUXADC_DAT5_P (auxadc_ts_phy_base + 0x028) +#define AUXADC_DAT6_P (auxadc_ts_phy_base + 0x02C) +#define AUXADC_DAT7_P (auxadc_ts_phy_base + 0x030) +#define AUXADC_DAT8_P (auxadc_ts_phy_base + 0x034) +#define AUXADC_DAT9_P (auxadc_ts_phy_base + 0x038) +#define AUXADC_DAT10_P (auxadc_ts_phy_base + 0x03C) +#define AUXADC_DAT11_P (auxadc_ts_phy_base + 0x040) +#define AUXADC_MISC_P (auxadc_ts_phy_base + 0x094) + +/******************************************************************************* + * Peripheral Configuration Register Definition + ******************************************************************************/ +#define PERI_GLOBALCON_RST0 (PERICFG_BASE_2 + 0x000) /* yes, 0x10003000 */ + +/******************************************************************************* + * APMixedSys Configuration Register Definition + ******************************************************************************/ +#define TS_CON0 (APMIXED_BASE_2 + 0x600) /* yes 0x10209000 */ +#define TS_CON1 (APMIXED_BASE_2 + 0x604) +/******************************************************************************* + * Thermal Controller Register Definition + ******************************************************************************/ +#define TEMPMONCTL0 (THERM_CTRL_BASE_2 + 0x000) /* yes 0x1100B000 */ +#define TEMPMONCTL1 (THERM_CTRL_BASE_2 + 0x004) +#define TEMPMONCTL2 (THERM_CTRL_BASE_2 + 0x008) +#define TEMPMONINT (THERM_CTRL_BASE_2 + 0x00C) +#define TEMPMONINTSTS (THERM_CTRL_BASE_2 + 0x010) +#define TEMPMONIDET0 (THERM_CTRL_BASE_2 + 0x014) +#define TEMPMONIDET1 (THERM_CTRL_BASE_2 + 0x018) +#define TEMPMONIDET2 (THERM_CTRL_BASE_2 + 0x01C) +#define TEMPH2NTHRE (THERM_CTRL_BASE_2 + 0x024) +#define TEMPHTHRE (THERM_CTRL_BASE_2 + 0x028) +#define TEMPCTHRE (THERM_CTRL_BASE_2 + 0x02C) +#define TEMPOFFSETH (THERM_CTRL_BASE_2 + 0x030) +#define TEMPOFFSETL (THERM_CTRL_BASE_2 + 0x034) +#define TEMPMSRCTL0 (THERM_CTRL_BASE_2 + 0x038) +#define TEMPMSRCTL1 (THERM_CTRL_BASE_2 + 0x03C) +#define TEMPAHBPOLL (THERM_CTRL_BASE_2 + 0x040) +#define TEMPAHBTO (THERM_CTRL_BASE_2 + 0x044) +#define TEMPADCPNP0 (THERM_CTRL_BASE_2 + 0x048) +#define TEMPADCPNP1 (THERM_CTRL_BASE_2 + 0x04C) +#define TEMPADCPNP2 (THERM_CTRL_BASE_2 + 0x050) +#define TEMPADCPNP3 (THERM_CTRL_BASE_2 + 0x0B4) + +#define TEMPADCMUX (THERM_CTRL_BASE_2 + 0x054) +#define TEMPADCEXT (THERM_CTRL_BASE_2 + 0x058) +#define TEMPADCEXT1 (THERM_CTRL_BASE_2 + 0x05C) +#define TEMPADCEN (THERM_CTRL_BASE_2 + 0x060) +#define TEMPPNPMUXADDR (THERM_CTRL_BASE_2 + 0x064) +#define TEMPADCMUXADDR (THERM_CTRL_BASE_2 + 0x068) +#define TEMPADCEXTADDR (THERM_CTRL_BASE_2 + 0x06C) +#define TEMPADCEXT1ADDR (THERM_CTRL_BASE_2 + 0x070) +#define TEMPADCENADDR (THERM_CTRL_BASE_2 + 0x074) +#define TEMPADCVALIDADDR (THERM_CTRL_BASE_2 + 0x078) +#define TEMPADCVOLTADDR (THERM_CTRL_BASE_2 + 0x07C) +#define TEMPRDCTRL (THERM_CTRL_BASE_2 + 0x080) +#define TEMPADCVALIDMASK (THERM_CTRL_BASE_2 + 0x084) +#define TEMPADCVOLTAGESHIFT (THERM_CTRL_BASE_2 + 0x088) +#define TEMPADCWRITECTRL (THERM_CTRL_BASE_2 + 0x08C) +#define TEMPMSR0 (THERM_CTRL_BASE_2 + 0x090) +#define TEMPMSR1 (THERM_CTRL_BASE_2 + 0x094) +#define TEMPMSR2 (THERM_CTRL_BASE_2 + 0x098) +#define TEMPMSR3 (THERM_CTRL_BASE_2 + 0x0B8) + +#define TEMPIMMD0 (THERM_CTRL_BASE_2 + 0x0A0) +#define TEMPIMMD1 (THERM_CTRL_BASE_2 + 0x0A4) +#define TEMPIMMD2 (THERM_CTRL_BASE_2 + 0x0A8) + +#define TEMPPROTCTL (THERM_CTRL_BASE_2 + 0x0C0) +#define TEMPPROTTA (THERM_CTRL_BASE_2 + 0x0C4) +#define TEMPPROTTB (THERM_CTRL_BASE_2 + 0x0C8) +#define TEMPPROTTC (THERM_CTRL_BASE_2 + 0x0CC) + +#define TEMPSPARE0 (THERM_CTRL_BASE_2 + 0x0F0) +#define TEMPSPARE1 (THERM_CTRL_BASE_2 + 0x0F4) +#define TEMPSPARE2 (THERM_CTRL_BASE_2 + 0x0F8) +#define TEMPSPARE3 (THERM_CTRL_BASE_2 + 0x0FC) + +#define PTPCORESEL (THERM_CTRL_BASE_2 + 0x400) +#define THERMINTST (THERM_CTRL_BASE_2 + 0x404) +#define PTPODINTST (THERM_CTRL_BASE_2 + 0x408) +#define THSTAGE0ST (THERM_CTRL_BASE_2 + 0x40C) +#define THSTAGE1ST (THERM_CTRL_BASE_2 + 0x410) +#define THSTAGE2ST (THERM_CTRL_BASE_2 + 0x414) +#define THAHBST0 (THERM_CTRL_BASE_2 + 0x418) +#define THAHBST1 (THERM_CTRL_BASE_2 + 0x41C) /* Only for DE debug */ +#define PTPSPARE0 (THERM_CTRL_BASE_2 + 0x420) +#define PTPSPARE1 (THERM_CTRL_BASE_2 + 0x424) +#define PTPSPARE2 (THERM_CTRL_BASE_2 + 0x428) +#define PTPSPARE3 (THERM_CTRL_BASE_2 + 0x42C) +#define THSLPEVEB (THERM_CTRL_BASE_2 + 0x430) + +/******************************************************************************* + * Thermal Controller Register Mask Definition + ******************************************************************************/ +#define THERMAL_ENABLE_SEN0 0x1 +#define THERMAL_ENABLE_SEN1 0x2 +#define THERMAL_ENABLE_SEN2 0x4 +#define THERMAL_MONCTL0_MASK 0x00000007 + +#define THERMAL_PUNT_MASK 0x00000FFF +#define THERMAL_FSINTVL_MASK 0x03FF0000 +#define THERMAL_SPINTVL_MASK 0x000003FF +#define THERMAL_MON_INT_MASK 0x0007FFFF + +#define THERMAL_MON_CINTSTS0 0x000001 +#define THERMAL_MON_HINTSTS0 0x000002 +#define THERMAL_MON_LOINTSTS0 0x000004 +#define THERMAL_MON_HOINTSTS0 0x000008 +#define THERMAL_MON_NHINTSTS0 0x000010 +#define THERMAL_MON_CINTSTS1 0x000020 +#define THERMAL_MON_HINTSTS1 0x000040 +#define THERMAL_MON_LOINTSTS1 0x000080 +#define THERMAL_MON_HOINTSTS1 0x000100 +#define THERMAL_MON_NHINTSTS1 0x000200 +#define THERMAL_MON_CINTSTS2 0x000400 +#define THERMAL_MON_HINTSTS2 0x000800 +#define THERMAL_MON_LOINTSTS2 0x001000 +#define THERMAL_MON_HOINTSTS2 0x002000 +#define THERMAL_MON_NHINTSTS2 0x004000 +#define THERMAL_MON_TOINTSTS 0x008000 +#define THERMAL_MON_IMMDINTSTS0 0x010000 +#define THERMAL_MON_IMMDINTSTS1 0x020000 +#define THERMAL_MON_IMMDINTSTS2 0x040000 +#define THERMAL_MON_FILTINTSTS0 0x080000 +#define THERMAL_MON_FILTINTSTS1 0x100000 +#define THERMAL_MON_FILTINTSTS2 0x200000 + + +#define THERMAL_tri_SPM_State0 0x20000000 +#define THERMAL_tri_SPM_State1 0x40000000 +#define THERMAL_tri_SPM_State2 0x80000000 + + +#define THERMAL_MSRCTL0_MASK 0x00000007 +#define THERMAL_MSRCTL1_MASK 0x00000038 +#define THERMAL_MSRCTL2_MASK 0x000001C0 + +/* extern int thermal_one_shot_handler(int times); */ + +typedef enum { + THERMAL_SENSOR1 = 0, /* TS1 */ + THERMAL_SENSOR_NUM +} thermal_sensor_name; + +struct TS_PTPOD { + unsigned int ts_MTS; + unsigned int ts_BTS; +}; + +extern void get_thermal_slope_intercept(struct TS_PTPOD *ts_info); +extern void set_taklking_flag(bool flag); +extern int tscpu_get_cpu_temp(void); + +/*5 thermal sensors*/ +typedef enum { + MTK_THERMAL_SENSOR_TS1 = 0, + ATM_CPU_LIMIT, + ATM_GPU_LIMIT, + MTK_THERMAL_SENSOR_CPU_COUNT +} MTK_THERMAL_SENSOR_CPU_ID_MET; + +struct mtk_cpu_power_info { + unsigned int cpufreq_khz; + unsigned int cpufreq_ncpu; + unsigned int cpufreq_power; +}; +extern int mtk_cpufreq_register(struct mtk_cpu_power_info *freqs, int num); + +extern int tscpu_get_cpu_temp_met(MTK_THERMAL_SENSOR_CPU_ID_MET id); + + +typedef void (*met_thermalsampler_funcMET) (void); +void mt_thermalsampler_registerCB(met_thermalsampler_funcMET pCB); + +void tscpu_start_thermal(void); +void tscpu_stop_thermal(void); +void tscpu_cancel_thermal_timer(void); +void tscpu_start_thermal_timer(void); +int mtkts_AP_get_hw_temp(void); + +extern int amddulthro_backoff(int level); +/* extern int IMM_GetOneChannelValue(int dwChannel, int data[4], int *rawdata); */ +/* extern int IMM_IsAdcInitReady(void); */ +extern int get_immediate_temp2_wrap(void); +extern void mtkts_dump_cali_info(void); +extern unsigned int read_dram_temperature(void); +extern int mtk_thermal_get_cpu_load_sum(void); + +/********************************** + * Power table struct for thermal + **********************************/ +struct mt_gpufreq_power_table_info { + unsigned int gpufreq_khz; + unsigned int gpufreq_volt; + unsigned int gpufreq_power; +}; + +extern int mtk_gpufreq_register(struct mt_gpufreq_power_table_info *freqs, int num); +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mt8695/include/mach/mtk_thermal.h b/drivers/misc/mediatek/include/mt-plat/mt8695/include/mach/mtk_thermal.h new file mode 100644 index 00000000000000..a7adb61c8ae4f8 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mt8695/include/mach/mtk_thermal.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +#ifndef _MTK_THERMAL_H +#define _MTK_THERMAL_H + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> + +#include <linux/io.h> +#include <linux/uaccess.h> + +#include "sync_write.h" + +extern void __iomem *thermal_base; +extern void __iomem *auxadc_ts_base; +extern void __iomem *apmixed_base; +extern void __iomem *INFRACFG_AO_BASE; +extern void __iomem *pericfg_base; +extern int auxadc_ts_phy_base; +extern int apmixed_phy_base; + +#define THERM_CTRL_BASE_2 thermal_base +#define AUXADC_BASE_2 auxadc_ts_base +#define INFRACFG_AO_BASE_2 INFRACFG_AO_BASE +#define PERICFG_BASE_2 pericfg_base +#define APMIXED_BASE_2 apmixed_base + +#define MT6752_EVB_BUILD_PASS /*Jerry fix build error FIX_ME*/ + +/******************************************************************************* +* AUXADC Register Definition +******************************************************************************/ +/*AUXADC_BASE: 0xF1001000 from Vincent Liang 2014.5.8*/ + +#define AUXADC_CON0_V (AUXADC_BASE_2 + 0x000) /*yes, 0x11003000*/ +#define AUXADC_CON1_V (AUXADC_BASE_2 + 0x004) +#define AUXADC_CON1_SET_V (AUXADC_BASE_2 + 0x008) +#define AUXADC_CON1_CLR_V (AUXADC_BASE_2 + 0x00C) +#define AUXADC_CON2_V (AUXADC_BASE_2 + 0x010) +/*#define AUXADC_CON3_V (AUXADC_BASE_2 + 0x014)*/ +#define AUXADC_DAT0_V (AUXADC_BASE_2 + 0x014) +#define AUXADC_DAT1_V (AUXADC_BASE_2 + 0x018) +#define AUXADC_DAT2_V (AUXADC_BASE_2 + 0x01C) +#define AUXADC_DAT3_V (AUXADC_BASE_2 + 0x020) +#define AUXADC_DAT4_V (AUXADC_BASE_2 + 0x024) +#define AUXADC_DAT5_V (AUXADC_BASE_2 + 0x028) +#define AUXADC_DAT6_V (AUXADC_BASE_2 + 0x02C) +#define AUXADC_DAT7_V (AUXADC_BASE_2 + 0x030) +#define AUXADC_DAT8_V (AUXADC_BASE_2 + 0x034) +#define AUXADC_DAT9_V (AUXADC_BASE_2 + 0x038) +#define AUXADC_DAT10_V (AUXADC_BASE_2 + 0x03C) +#define AUXADC_DAT11_V (AUXADC_BASE_2 + 0x040) +#define AUXADC_MISC_V (AUXADC_BASE_2 + 0x094) + +#define AUXADC_CON0_P (auxadc_ts_phy_base + 0x000) +#define AUXADC_CON1_P (auxadc_ts_phy_base + 0x004) +#define AUXADC_CON1_SET_P (auxadc_ts_phy_base + 0x008) +#define AUXADC_CON1_CLR_P (auxadc_ts_phy_base + 0x00C) +#define AUXADC_CON2_P (auxadc_ts_phy_base + 0x010) +/*#define AUXADC_CON3_P (auxadc_ts_phy_base + 0x014)*/ +#define AUXADC_DAT0_P (auxadc_ts_phy_base + 0x014) +#define AUXADC_DAT1_P (auxadc_ts_phy_base + 0x018) +#define AUXADC_DAT2_P (auxadc_ts_phy_base + 0x01C) +#define AUXADC_DAT3_P (auxadc_ts_phy_base + 0x020) +#define AUXADC_DAT4_P (auxadc_ts_phy_base + 0x024) +#define AUXADC_DAT5_P (auxadc_ts_phy_base + 0x028) +#define AUXADC_DAT6_P (auxadc_ts_phy_base + 0x02C) +#define AUXADC_DAT7_P (auxadc_ts_phy_base + 0x030) +#define AUXADC_DAT8_P (auxadc_ts_phy_base + 0x034) +#define AUXADC_DAT9_P (auxadc_ts_phy_base + 0x038) +#define AUXADC_DAT10_P (auxadc_ts_phy_base + 0x03C) +#define AUXADC_DAT11_P (auxadc_ts_phy_base + 0x040) + +#define AUXADC_MISC_P (auxadc_ts_phy_base + 0x094) + +/******************************************************************************* +* Peripheral Configuration Register Definition +******************************************************************************/ +#define PERI_GLOBALCON_RST0 (PERICFG_BASE_2 + 0x000) + +/* APB Module infracfg_ao*/ +/*#define INFRACFG_AO_BASE (0xF0001000)*/ +#define INFRA_GLOBALCON_RST_0_SET (INFRACFG_AO_BASE_2 + 0x120) /*yes, 0x10001000*/ +#define INFRA_GLOBALCON_RST_0_CLR (INFRACFG_AO_BASE_2 + 0x124) /*yes, 0x10001000*/ +#define INFRA_GLOBALCON_RST_0_STA (INFRACFG_AO_BASE_2 + 0x128) /*yes, 0x10001000*/ +/******************************************************************************* + * APMixedSys Configuration Register Definition + ******************************************************************************/ +/*APMIXED_BASE: 0x1000C000 from KJ 2014.5.8 TODO: FIXME*/ +#define TS_CON0 (APMIXED_BASE_2 + 0x600) /*yes 0x10209000*/ +#define TS_CON1 (APMIXED_BASE_2 + 0x604) +#define TS_CON0_TM (APMIXED_BASE_2 + 0x600) /* yes 0x10209000 */ +#define TS_CON1_TM (APMIXED_BASE_2 + 0x604) +#define TS_CON0_P (apmixed_phy_base + 0x600) +#define TS_CON1_P (apmixed_phy_base + 0x604) + +/******************************************************************************* + * Thermal Controller Register Definition + ******************************************************************************/ +#define TEMPMONCTL0 (THERM_CTRL_BASE_2 + 0x000) /*yes 0xF100B000*/ +#define TEMPMONCTL1 (THERM_CTRL_BASE_2 + 0x004) +#define TEMPMONCTL2 (THERM_CTRL_BASE_2 + 0x008) +#define TEMPMONINT (THERM_CTRL_BASE_2 + 0x00C) +#define TEMPMONINTSTS (THERM_CTRL_BASE_2 + 0x010) +#define TEMPMONIDET0 (THERM_CTRL_BASE_2 + 0x014) +#define TEMPMONIDET1 (THERM_CTRL_BASE_2 + 0x018) +#define TEMPMONIDET2 (THERM_CTRL_BASE_2 + 0x01C) +#define TEMPMONIDET3 (THERM_CTRL_BASE_2 + 0x0B0) +#define TEMPH2NTHRE (THERM_CTRL_BASE_2 + 0x024) +#define TEMPHTHRE (THERM_CTRL_BASE_2 + 0x028) +#define TEMPCTHRE (THERM_CTRL_BASE_2 + 0x02C) +#define TEMPOFFSETH (THERM_CTRL_BASE_2 + 0x030) +#define TEMPOFFSETL (THERM_CTRL_BASE_2 + 0x034) +#define TEMPMSRCTL0 (THERM_CTRL_BASE_2 + 0x038) +#define TEMPMSRCTL1 (THERM_CTRL_BASE_2 + 0x03C) +#define TEMPAHBPOLL (THERM_CTRL_BASE_2 + 0x040) +#define TEMPAHBTO (THERM_CTRL_BASE_2 + 0x044) +#define TEMPADCPNP0 (THERM_CTRL_BASE_2 + 0x048) +#define TEMPADCPNP1 (THERM_CTRL_BASE_2 + 0x04C) +#define TEMPADCPNP2 (THERM_CTRL_BASE_2 + 0x050) +#define TEMPADCPNP3 (THERM_CTRL_BASE_2 + 0x0B4) + +#define TEMPADCMUX (THERM_CTRL_BASE_2 + 0x054) +#define TEMPADCEXT (THERM_CTRL_BASE_2 + 0x058) +#define TEMPADCEXT1 (THERM_CTRL_BASE_2 + 0x05C) +#define TEMPADCEN (THERM_CTRL_BASE_2 + 0x060) +#define TEMPPNPMUXADDR (THERM_CTRL_BASE_2 + 0x064) +#define TEMPADCMUXADDR (THERM_CTRL_BASE_2 + 0x068) +#define TEMPADCEXTADDR (THERM_CTRL_BASE_2 + 0x06C) +#define TEMPADCEXT1ADDR (THERM_CTRL_BASE_2 + 0x070) +#define TEMPADCENADDR (THERM_CTRL_BASE_2 + 0x074) +#define TEMPADCVALIDADDR (THERM_CTRL_BASE_2 + 0x078) +#define TEMPADCVOLTADDR (THERM_CTRL_BASE_2 + 0x07C) +#define TEMPRDCTRL (THERM_CTRL_BASE_2 + 0x080) +#define TEMPADCVALIDMASK (THERM_CTRL_BASE_2 + 0x084) +#define TEMPADCVOLTAGESHIFT (THERM_CTRL_BASE_2 + 0x088) +#define TEMPADCWRITECTRL (THERM_CTRL_BASE_2 + 0x08C) +#define TEMPMSR0 (THERM_CTRL_BASE_2 + 0x090) +#define TEMPMSR1 (THERM_CTRL_BASE_2 + 0x094) +#define TEMPMSR2 (THERM_CTRL_BASE_2 + 0x098) +#define TEMPMSR3 (THERM_CTRL_BASE_2 + 0x0B8) + +#define TEMPIMMD0 (THERM_CTRL_BASE_2 + 0x0A0) +#define TEMPIMMD1 (THERM_CTRL_BASE_2 + 0x0A4) +#define TEMPIMMD2 (THERM_CTRL_BASE_2 + 0x0A8) +#define TEMPIMMD3 (THERM_CTRL_BASE_2 + 0x0BC) + + +#define TEMPPROTCTL (THERM_CTRL_BASE_2 + 0x0C0) +#define TEMPPROTTA (THERM_CTRL_BASE_2 + 0x0C4) +#define TEMPPROTTB (THERM_CTRL_BASE_2 + 0x0C8) +#define TEMPPROTTC (THERM_CTRL_BASE_2 + 0x0CC) + +#define TEMPSPARE0 (THERM_CTRL_BASE_2 + 0x0F0) +#define TEMPSPARE1 (THERM_CTRL_BASE_2 + 0x0F4) +#define TEMPSPARE2 (THERM_CTRL_BASE_2 + 0x0F8) +#define TEMPSPARE3 (THERM_CTRL_BASE_2 + 0x0FC) + +#define PTPCORESEL (THERM_CTRL_BASE_2 + 0xF00) +#define THERMINTST (THERM_CTRL_BASE_2 + 0xF04) +#define PTPODINTST (THERM_CTRL_BASE_2 + 0xF08) +#define THSTAGE0ST (THERM_CTRL_BASE_2 + 0xF0C) +#define THSTAGE1ST (THERM_CTRL_BASE_2 + 0xF10) +#define THSTAGE2ST (THERM_CTRL_BASE_2 + 0xF14) +#define THAHBST0 (THERM_CTRL_BASE_2 + 0xF18) +#define THAHBST1 (THERM_CTRL_BASE_2 + 0xF1C) /*Only for DE debug*/ +#define PTPSPARE0 (THERM_CTRL_BASE_2 + 0xF20) +#define PTPSPARE1 (THERM_CTRL_BASE_2 + 0xF24) +#define PTPSPARE2 (THERM_CTRL_BASE_2 + 0xF28) +#define PTPSPARE3 (THERM_CTRL_BASE_2 + 0xF2C) +#define THSLPEVEB (THERM_CTRL_BASE_2 + 0xF30) + + +#define PTPSPARE0_P (thermal_phy_base + 0xF20) +#define PTPSPARE1_P (thermal_phy_base + 0xF24) +#define PTPSPARE2_P (thermal_phy_base + 0xF28) +#define PTPSPARE3_P (thermal_phy_base + 0xF2C) + +/******************************************************************************* + * Thermal Controller Register Mask Definition + ******************************************************************************/ +#define THERMAL_ENABLE_SEN0 0x1 +#define THERMAL_ENABLE_SEN1 0x2 +#define THERMAL_ENABLE_SEN2 0x4 +#define THERMAL_MONCTL0_MASK 0x00000007 + +#define THERMAL_PUNT_MASK 0x00000FFF +#define THERMAL_FSINTVL_MASK 0x03FF0000 +#define THERMAL_SPINTVL_MASK 0x000003FF +#define THERMAL_MON_INT_MASK 0x0007FFFF + +#define THERMAL_MON_CINTSTS0 0x000001 +#define THERMAL_MON_HINTSTS0 0x000002 +#define THERMAL_MON_LOINTSTS0 0x000004 +#define THERMAL_MON_HOINTSTS0 0x000008 +#define THERMAL_MON_NHINTSTS0 0x000010 +#define THERMAL_MON_CINTSTS1 0x000020 +#define THERMAL_MON_HINTSTS1 0x000040 +#define THERMAL_MON_LOINTSTS1 0x000080 +#define THERMAL_MON_HOINTSTS1 0x000100 +#define THERMAL_MON_NHINTSTS1 0x000200 +#define THERMAL_MON_CINTSTS2 0x000400 +#define THERMAL_MON_HINTSTS2 0x000800 +#define THERMAL_MON_LOINTSTS2 0x001000 +#define THERMAL_MON_HOINTSTS2 0x002000 +#define THERMAL_MON_NHINTSTS2 0x004000 +#define THERMAL_MON_TOINTSTS 0x008000 +#define THERMAL_MON_IMMDINTSTS0 0x010000 +#define THERMAL_MON_IMMDINTSTS1 0x020000 +#define THERMAL_MON_IMMDINTSTS2 0x040000 +#define THERMAL_MON_FILTINTSTS0 0x080000 +#define THERMAL_MON_FILTINTSTS1 0x100000 +#define THERMAL_MON_FILTINTSTS2 0x200000 + + +#define THERMAL_tri_SPM_State0 0x20000000 +#define THERMAL_tri_SPM_State1 0x40000000 +#define THERMAL_tri_SPM_State2 0x80000000 + + +#define THERMAL_MSRCTL0_MASK 0x00000007 +#define THERMAL_MSRCTL1_MASK 0x00000038 +#define THERMAL_MSRCTL2_MASK 0x000001C0 + +enum thermal_sensor_name { + THERMAL_SENSOR1 = 0,/*TS_MCU1*/ + THERMAL_SENSOR2 = 1,/*TS_MCU2*/ + THERMAL_SENSOR3 = 2,/*TS_MCU3*/ + THERMAL_SENSOR_NUM +}; + +enum thermal_bank_name { + THERMAL_BANK0 = 0, /*CPU (TS_MCU1) (TS1)*/ + THERMAL_BANK1 = 1, /*MFG (TS_MCU2) (TS2)*/ + THERMAL_BANK2 = 2, /*GPU (TS_MCU3) (TS3)*/ + THERMAL_BANK_NUM +}; + +struct TS_SVS { + unsigned int ts_MTS; + unsigned int ts_BTS; +}; + +struct mtk_gpu_power_info { + unsigned int gpufreq_khz; + unsigned int gpufreq_power; +}; + +/* ptp driver need this function */ +extern void get_thermal_slope_intercept(struct TS_SVS *ts_info, enum thermal_bank_name ts_bank); + +/* mtk_thermal_platform.c need this */ +extern void set_taklking_flag(bool flag); + +#define THERMAL_WRAP_WR32(val, addr) mt_reg_sync_writel((val), ((void *)addr)) + +#if 1 +/*4 thermal sensors*/ +enum MTK_THERMAL_SENSOR_CPU_ID_MET { + MTK_THERMAL_SENSOR_TS1 = 0, + MTK_THERMAL_SENSOR_TS2, + MTK_THERMAL_SENSOR_TS3, + MTK_THERMAL_SENSOR_TS4, + MTK_THERMAL_SENSOR_TSABB, + + ATM_CPU_LIMIT, + ATM_GPU_LIMIT, + + MTK_THERMAL_SENSOR_CPU_COUNT +}; +#else +/*5 thermal sensors*/ +enum MTK_THERMAL_SENSOR_CPU_ID_MET { + MTK_THERMAL_SENSOR_TS1 = 0, + MTK_THERMAL_SENSOR_TS2, + MTK_THERMAL_SENSOR_TS3, + MTK_THERMAL_SENSOR_TS4, + MTK_THERMAL_SENSOR_TSABB, + + ATM_CPU_LIMIT, + ATM_GPU_LIMIT, + + MTK_THERMAL_SENSOR_CPU_COUNT +}; +#endif + +extern int tscpu_get_cpu_temp_met(enum MTK_THERMAL_SENSOR_CPU_ID_MET id); +extern int mtk_gpufreq_register(struct mtk_gpu_power_info *freqs, int num); + +typedef void (*met_thermalsampler_funcMET)(void); +void mt_thermalsampler_registerCB(met_thermalsampler_funcMET pCB); + +void tscpu_start_thermal(void); +void tscpu_stop_thermal(void); +void tscpu_cancel_thermal_timer(void); +void tscpu_start_thermal_timer(void); +int mtkts_bts_get_hw_temp(void); + +extern int get_immediate_ts1_wrap(void); +extern int get_immediate_ts2_wrap(void); +extern int get_immediate_ts3_wrap(void); + +extern int is_cpu_power_unlimit(void); /* in mtk_ts_cpu.c */ +extern int is_cpu_power_min(void); /* in mtk_ts_cpu.c */ +extern int get_cpu_target_tj(void); +extern int get_cpu_target_offset(void); + +extern int mtktscpu_debug_log; + +#endif + diff --git a/drivers/misc/mediatek/include/mt-plat/mt_sched.h b/drivers/misc/mediatek/include/mt-plat/mt_sched.h new file mode 100644 index 00000000000000..71206f08054829 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mt_sched.h @@ -0,0 +1,34 @@ +/* +* Copyright (C) 2016 MediaTek Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See http://www.gnu.org/licenses/gpl-2.0.html for more details. +*/ + +#ifdef CONFIG_MTK_SCHED_RQAVG_US +/* + * @cpu: cpu id + * @reset: reset the statistic start time after this time query + * @use_maxfreq: caculate cpu loading with max cpu max frequency + * return: cpu loading as percentage (0~100) + */ +extern unsigned int sched_get_percpu_load(int cpu, bool reset, bool use_maxfreq); + +/* + * return: heavy task(loading>90%) number in the system + */ +extern unsigned int sched_get_nr_heavy_task(void); + +/* + * @threshold: heavy task loading threshold (0~1023) + * return: heavy task(loading>threshold) number in the system + */ +extern unsigned int sched_get_nr_heavy_task_by_threshold(unsigned int threshold); +#endif /* CONFIG_MTK_SCHED_RQAVG_US */ + diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_boot.h b/drivers/misc/mediatek/include/mt-plat/mtk_boot.h new file mode 100644 index 00000000000000..760be93b8b94a4 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_boot.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_BOOT_H__ +#define __MTK_BOOT_H__ +#include "mtk_boot_common.h" +#include "mtk_boot_reason.h" + +/*META COM port type*/ +enum meta_com_type { + META_UNKNOWN_COM = 0, + META_UART_COM, + META_USB_COM +}; + +extern enum meta_com_type get_meta_com_type(void); +extern unsigned int get_meta_com_id(void); +extern unsigned int get_meta_uart_port(void); + +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_boot_common.h b/drivers/misc/mediatek/include/mt-plat/mtk_boot_common.h new file mode 100644 index 00000000000000..a43a4e6fcbdffc --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_boot_common.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_BOOT_COMMON_H__ +#define __MTK_BOOT_COMMON_H__ + +/* boot type definitions */ +enum boot_mode_t { + NORMAL_BOOT = 0, + META_BOOT = 1, + RECOVERY_BOOT = 2, + SW_REBOOT = 3, + FACTORY_BOOT = 4, + ADVMETA_BOOT = 5, + ATE_FACTORY_BOOT = 6, + ALARM_BOOT = 7, +#if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING) + KERNEL_POWER_OFF_CHARGING_BOOT = 8, + LOW_POWER_OFF_CHARGING_BOOT = 9, +#endif + DONGLE_BOOT = 10, + UNKNOWN_BOOT +}; + +#define BOOT_DEV_NAME "BOOT" +#define BOOT_SYSFS "boot" +#define BOOT_SYSFS_ATTR "boot_mode" + +extern enum boot_mode_t get_boot_mode(void); +extern bool is_meta_mode(void); +extern bool is_advanced_meta_mode(void); +extern void set_boot_mode(unsigned int bm); + +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_boot_reason.h b/drivers/misc/mediatek/include/mt-plat/mtk_boot_reason.h new file mode 100644 index 00000000000000..9126085d99016f --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_boot_reason.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_BOOT_REASON_H__ +#define __MTK_BOOT_REASON_H__ + +enum boot_reason_t { + BR_POWER_KEY = 0, + BR_USB, + BR_RTC, + BR_WDT, + BR_WDT_BY_PASS_PWK, + BR_TOOL_BY_PASS_PWK, + BR_2SEC_REBOOT, + BR_UNKNOWN +}; + +extern enum boot_reason_t get_boot_reason(void); + +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_devinfo.h b/drivers/misc/mediatek/include/mt-plat/mtk_devinfo.h new file mode 100644 index 00000000000000..c14083e2139840 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_devinfo.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT_DEVINFO_H__ +#define __MT_DEVINFO_H__ + +#include <linux/types.h> + + /***************************************************************************** + * HRID RET CODE DEFINITION + *****************************************************************************/ +#define E_SUCCESS 0x00000000 +#define E_BUF_NOT_ENOUGH 0x10000000 +#define E_BUF_ZERO_OR_NULL 0x20000000 +#define E_BUF_SIZE_ZERO_OR_NULL 0x40000000 + + /***************************************************************************** + * DEVINFO AND HRID APIS + *****************************************************************************/ +extern u32 get_devinfo_with_index(u32 index); +extern u32 devinfo_ready(void); +extern u32 devinfo_get_size(void); +extern u32 get_hrid_size(void); +extern u32 get_hrid(unsigned char *rid, unsigned char *rid_sz); + +#endif /* __MT_DEVINFO_H__ */ + diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_gpu_utility.h b/drivers/misc/mediatek/include/mt-plat/mtk_gpu_utility.h new file mode 100644 index 00000000000000..dbb6b47409d65c --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_gpu_utility.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_GPU_UTILITY_H__ +#define __MTK_GPU_UTILITY_H__ + +#include <linux/types.h> + + #define MTK_GPU_DVFS_TYPE_LIST {\ +MTK_GPU_DVFS_TYPE_ITEM(NONE) \ +MTK_GPU_DVFS_TYPE_ITEM(SMARTBOOST) \ +MTK_GPU_DVFS_TYPE_ITEM(VSYNCBASED) \ +MTK_GPU_DVFS_TYPE_ITEM(FALLBACK) \ +MTK_GPU_DVFS_TYPE_ITEM(TIMERBASED) \ +MTK_GPU_DVFS_TYPE_ITEM(FASTDVFS) \ +MTK_GPU_DVFS_TYPE_ITEM(TOUCHBOOST) \ +MTK_GPU_DVFS_TYPE_ITEM(THERMAL) \ +MTK_GPU_DVFS_TYPE_ITEM(CUSTOMIZATION)} + +typedef enum MTK_GPU_DVFS_TYPE_TAG +#define MTK_GPU_DVFS_TYPE_ITEM(type) MTK_GPU_DVFS_TYPE_##type, +MTK_GPU_DVFS_TYPE_LIST +#undef MTK_GPU_DVFS_TYPE_ITEM +MTK_GPU_DVFS_TYPE; + +/* returning false indicated no implement */ + +/* unit: x bytes */ +bool mtk_get_gpu_memory_usage(unsigned int *pMemUsage); +bool mtk_get_gpu_page_cache(unsigned int *pPageCache); + +/* unit: 0~100 % */ +bool mtk_get_gpu_loading(unsigned int *pLoading); +bool mtk_get_gpu_block(unsigned int *pBlock); +bool mtk_get_gpu_idle(unsigned int *pIlde); +bool mtk_get_gpu_freq(unsigned int *pFreq); + +bool mtk_get_gpu_GP_loading(unsigned int *pLoading); +bool mtk_get_gpu_PP_loading(unsigned int *pLoading); +bool mtk_get_gpu_power_loading(unsigned int *pLoading); + +bool mtk_enable_gpu_dvfs_timer(bool bEnable); +bool mtk_boost_gpu_freq(void); +bool mtk_set_bottom_gpu_freq(unsigned int ui32FreqLevel); + +/* ui32FreqLevel: 0=>lowest freq, count-1=>highest freq */ +bool mtk_custom_get_gpu_freq_level_count(unsigned int *pui32FreqLevelCount); +bool mtk_custom_boost_gpu_freq(unsigned int ui32FreqLevel); +bool mtk_custom_upbound_gpu_freq(unsigned int ui32FreqLevel); +bool mtk_get_custom_boost_gpu_freq(unsigned int *pui32FreqLevel); +bool mtk_get_custom_upbound_gpu_freq(unsigned int *pui32FreqLevel); + +bool mtk_dump_gpu_memory_usage(void); + +bool mtk_get_gpu_dvfs_from(MTK_GPU_DVFS_TYPE *peType, unsigned long *pulFreq); +bool mtk_get_3D_fences_count(int *pi32Count); +bool mtk_get_vsync_based_target_freq(unsigned long *pulFreq); +bool mtk_get_gpu_sub_loading(unsigned int *pLoading); +bool mtk_get_gpu_bottom_freq(unsigned long *pulFreq); +bool mtk_get_gpu_custom_boost_freq(unsigned long *pulFreq); +bool mtk_get_gpu_custom_upbound_freq(unsigned long *pulFreq); +bool mtk_get_vsync_offset_event_status(unsigned int *pui32EventStatus); +bool mtk_get_vsync_offset_debug_status(unsigned int *pui32DebugStatus); + +/* MET */ +bool mtk_enable_gpu_perf_monitor(bool enable); + +/* GPU PMU should be implemented by GPU IP-dep code */ +typedef struct { + int id; + const char *name; + unsigned int value; + int overflow; +} GPU_PMU; +bool mtk_get_gpu_pmu_init(GPU_PMU *pmus, int pmu_size, int *ret_size); +bool mtk_get_gpu_pmu_swapnreset(GPU_PMU *pmus, int pmu_size); + +typedef void (*gpu_power_change_notify_fp)(int power_on); + +bool mtk_register_gpu_power_change(const char *name, gpu_power_change_notify_fp callback); +bool mtk_unregister_gpu_power_change(const char *name); + +/* GPU POWER NOTIFY should be called by GPU only */ +void mtk_notify_gpu_power_change(int power_on); + +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_io.h b/drivers/misc/mediatek/include/mt-plat/mtk_io.h new file mode 100644 index 00000000000000..de17db505d3e5f --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_io.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT_IO_H__ +#define __MT_IO_H__ + +/* only for arm64 */ +#ifdef CONFIG_ARM64 +#define IOMEM(a) ((void __force __iomem *)((a))) +#endif + +#endif /* !__MT_IO_H__ */ + diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_lpae.h b/drivers/misc/mediatek/include/mt-plat/mtk_lpae.h new file mode 100644 index 00000000000000..d679c5a1ce7380 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_lpae.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_LPAE_H__ +#define __MTK_LPAE_H__ +#ifdef CONFIG_MTK_LM_MODE + +#include <mt-plat/mtk_io.h> + +#define INTERAL_MAPPING_OFFSET (0x40000000) +#define INTERAL_MAPPING_LIMIT (INTERAL_MAPPING_OFFSET + 0x80000000) + +#define MT_OVERFLOW_ADDR_START 0x100000000ULL + +unsigned int __attribute__((weak)) enable_4G(void) +{ + return 0; +} + +/* For HW modules which support 33-bit address setting */ +#define CROSS_OVERFLOW_ADDR_TRANSFER(phy_addr, size, ret) \ + do { \ + ret = 0; \ + if (enable_4G()) {\ + if (((phys_addr_t)phy_addr < MT_OVERFLOW_ADDR_START)\ + && (((phys_addr_t)phy_addr + size) >= MT_OVERFLOW_ADDR_START)) \ + ret = MT_OVERFLOW_ADDR_START - phy_addr; \ + } \ + } while (0) \ + +/* For SPM and MD32 only in ROME */ +#define MAPPING_DRAM_ACCESS_ADDR(phy_addr) \ + do { \ + if (enable_4G()) {\ + if (phy_addr >= INTERAL_MAPPING_OFFSET && phy_addr < INTERAL_MAPPING_LIMIT) \ + phy_addr += INTERAL_MAPPING_OFFSET; \ + } \ + } while (0)\ + +#else /* !CONFIG_ARM_LPAE */ + +#define CROSS_OVERFLOW_ADDR_TRANSFER(phy_addr, size, ret) +#define MAPPING_DRAM_ACCESS_ADDR(phy_addr) +#define MT_OVERFLOW_ADDR_START 0 + +static inline unsigned int enable_4G(void) +{ + return 0; +} + +#endif +#endif /*!__MTK_LPAE_H__ */ diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h b/drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h new file mode 100644 index 00000000000000..7baafc4329bfc7 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_mdm_monitor.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MTK_MDM_MONITOR_H +#define _MTK_MDM_MONITOR_H + +struct md_info { + char *attribute; + int value; + char *unit; + int invalid_value; + int index; +}; + +extern +int mtk_mdm_get_md_info(struct md_info **p_inf, int *size); + +extern +int mtk_mdm_start_query(void); + +extern +int mtk_mdm_stop_query(void); + +extern +int mtk_mdm_set_signal_period(int second); + +extern +int mtk_mdm_set_md1_signal_period(int second); + +extern +int mtk_mdm_set_md2_signal_period(int second); +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h b/drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h new file mode 100644 index 00000000000000..8f20f38b75d6ce --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_platform_debug.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_PLATFORM_DEBUG_H__ +#define __MTK_PLATFORM_DEBUG_H__ + +#ifdef CONFIG_MTK_PLAT_SRAM_FLAG +/* plat_sram_flag */ +extern int set_sram_flag_lastpc_valid(void); +extern int set_sram_flag_dfd_valid(void); +extern int set_sram_flag_etb_user(unsigned int etb_id, unsigned int user_id); +#endif + +#ifdef CONFIG_MTK_DFD_INTERNAL_DUMP +extern int dfd_setup(void); +#endif + +#endif /* __MTK_PLATFORM_DEBUG_H__ */ diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h b/drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h new file mode 100644 index 00000000000000..3a94a1bbcd2413 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_ram_console.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MTK_RAM_CONSOLE_H__ +#define __MTK_RAM_CONSOLE_H__ + +#include <linux/console.h> +#include <linux/pstore.h> + +typedef enum { + AEE_FIQ_STEP_FIQ_ISR_BASE = 1, + AEE_FIQ_STEP_WDT_FIQ_INFO = 4, + AEE_FIQ_STEP_WDT_FIQ_STACK, + AEE_FIQ_STEP_WDT_FIQ_LOOP, + AEE_FIQ_STEP_WDT_FIQ_DONE, + AEE_FIQ_STEP_WDT_IRQ_INFO = 8, + AEE_FIQ_STEP_WDT_IRQ_KICK, + AEE_FIQ_STEP_WDT_IRQ_SMP_STOP, + AEE_FIQ_STEP_WDT_IRQ_TIME, + AEE_FIQ_STEP_WDT_IRQ_STACK, + AEE_FIQ_STEP_WDT_IRQ_GIC, + AEE_FIQ_STEP_WDT_IRQ_LOCALTIMER, + AEE_FIQ_STEP_WDT_IRQ_IDLE, + AEE_FIQ_STEP_WDT_IRQ_SCHED, + AEE_FIQ_STEP_WDT_IRQ_DONE, + AEE_FIQ_STEP_KE_WDT_INFO = 20, + AEE_FIQ_STEP_KE_WDT_PERCPU, + AEE_FIQ_STEP_KE_WDT_LOG, + AEE_FIQ_STEP_KE_SCHED_DEBUG, + AEE_FIQ_STEP_KE_EINT_DEBUG, + AEE_FIQ_STEP_KE_WDT_DONE, + AEE_FIQ_STEP_KE_IPANIC_DIE = 32, + AEE_FIQ_STEP_KE_IPANIC_START, + AEE_FIQ_STEP_KE_IPANIC_OOP_HEADER, + AEE_FIQ_STEP_KE_IPANIC_DETAIL, + AEE_FIQ_STEP_KE_IPANIC_CONSOLE, + AEE_FIQ_STEP_KE_IPANIC_USERSPACE, + AEE_FIQ_STEP_KE_IPANIC_ANDROID, + AEE_FIQ_STEP_KE_IPANIC_MMPROFILE, + AEE_FIQ_STEP_KE_IPANIC_HEADER, + AEE_FIQ_STEP_KE_IPANIC_DONE, + AEE_FIQ_STEP_KE_NESTED_PANIC = 64, +} AEE_FIQ_STEP_NUM; + +#ifdef CONFIG_MTK_RAM_CONSOLE +extern int aee_rr_curr_fiq_step(void); +extern void aee_rr_rec_fiq_step(u8 i); +extern void aee_rr_rec_reboot_mode(u8 mode); +extern void aee_rr_rec_kdump_params(void *params); +extern void aee_rr_rec_last_irq_enter(int cpu, int irq, u64 j); +extern void aee_rr_rec_last_irq_exit(int cpu, int irq, u64 j); +extern void aee_rr_rec_last_sched_jiffies(int cpu, u64 j, const char *comm); +extern void aee_sram_fiq_log(const char *msg); +extern void ram_console_write(struct console *console, const char *s, unsigned int count); +extern void aee_sram_fiq_save_bin(const char *buffer, size_t len); +extern void aee_rr_rec_hotplug_footprint(int cpu, u8 fp); +extern void aee_rr_rec_hotplug_cpu_event(u8 val); +extern void aee_rr_rec_hotplug_cb_index(u8 val); +extern void aee_rr_rec_hotplug_cb_fp(unsigned long val); +#ifdef CONFIG_MTK_EMMC_SUPPORT +extern void last_kmsg_store_to_emmc(void); +#endif + +#else +static inline void aee_rr_rec_hotplug_footprint(int cpu, u8 fp) +{ +} +static inline void aee_rr_rec_hotplug_cpu_event(u8 val) +{ +} +static inline void aee_rr_rec_hotplug_cb_index(u8 val) +{ +} +static inline void aee_rr_rec_hotplug_cb_fp(unsigned long val) +{ +} +static inline int aee_rr_curr_fiq_step(void) +{ + return 0; +} + +static inline void aee_rr_rec_fiq_step(u8 i) +{ +} + +static inline unsigned int aee_rr_curr_exp_type(void) +{ + return 0; +} + +static inline void aee_rr_rec_exp_type(unsigned int type) +{ +} + +static inline void aee_rr_rec_reboot_mode(u8 mode) +{ +} + +static inline void aee_rr_rec_kdump_params(void *params) +{ +} + +static inline void aee_rr_rec_last_irq_enter(int cpu, int irq, u64 j) +{ +} + +static inline void aee_rr_rec_last_irq_exit(int cpu, int irq, u64 j) +{ +} + +static inline void aee_rr_rec_last_sched_jiffies(int cpu, u64 j, const char *comm) +{ +} + +static inline void aee_sram_fiq_log(const char *msg) +{ +} + +static inline void ram_console_write(struct console *console, const char *s, unsigned int count) +{ +} + +static inline void aee_sram_fiq_save_bin(unsigned char *buffer, size_t len) +{ +} + +#ifdef CONFIG_MTK_EMMC_SUPPORT +static inline void last_kmsg_store_to_emmc(void) +{ +} +#endif + +#endif /* CONFIG_MTK_RAM_CONSOLE */ + +#ifdef CONFIG_MTK_AEE_IPANIC +extern int ipanic_kmsg_write(unsigned int part, const char *buf, size_t size); +extern int ipanic_kmsg_get_next(int *count, u64 *id, enum pstore_type_id *type, struct timespec *time, + char **buf, struct pstore_info *psi); +#else +static inline int ipanic_kmsg_write(unsigned int part, const char *buf, size_t size) +{ + return 0; +} + +static inline int ipanic_kmsg_get_next(int *count, u64 *id, enum pstore_type_id *type, struct timespec *time, + char **buf, struct pstore_info *psi) +{ + return 0; +} +#endif /* CONFIG_MTK_AEE_IPANIC */ + +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h b/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h new file mode 100644 index 00000000000000..78d4a39c7cd62d --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MTK_RTC_H +#define MTK_RTC_H + +#include <linux/ioctl.h> +#include <linux/rtc.h> +#include <linux/types.h> + +typedef enum { + RTC_GPIO_USER_WIFI = 8, + RTC_GPIO_USER_GPS = 9, + RTC_GPIO_USER_BT = 10, + RTC_GPIO_USER_FM = 11, + RTC_GPIO_USER_PMIC = 12, +} rtc_gpio_user_t; + +#ifdef CONFIG_MTK_RTC + +/* + * NOTE: + * 1. RTC_GPIO always exports 32K enabled by some user even if the phone is powered off + */ + +extern unsigned long rtc_read_hw_time(void); +extern void rtc_gpio_enable_32k(rtc_gpio_user_t user); +extern void rtc_gpio_disable_32k(rtc_gpio_user_t user); +extern bool rtc_gpio_32k_status(void); + +/* for AUDIOPLL (deprecated) */ +extern void rtc_enable_abb_32k(void); +extern void rtc_disable_abb_32k(void); + +/* NOTE: used in Sleep driver to workaround Vrtc-Vore level shifter issue */ +extern void rtc_enable_writeif(void); +extern void rtc_disable_writeif(void); + +extern void rtc_mark_recovery(void); +#if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING) +extern void rtc_mark_kpoc(void); +#endif/*if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING)*/ +extern void rtc_mark_fast(void); +extern u16 rtc_rdwr_uart_bits(u16 *val); +extern void rtc_bbpu_power_down(void); +extern void rtc_read_pwron_alarm(struct rtc_wkalrm *alm); +extern int get_rtc_spare_fg_value(void); +extern int set_rtc_spare_fg_value(int val); +extern void rtc_irq_handler(void); +extern bool crystal_exist_status(void); +extern void mt_power_off(void); +#else/*ifdef CONFIG_MTK_RTC*/ +#define rtc_read_hw_time() ({ 0; }) +#define rtc_gpio_enable_32k(user) do {} while (0) +#define rtc_gpio_disable_32k(user) do {} while (0) +#define rtc_gpio_32k_status() do {} while (0) +#define rtc_enable_abb_32k() do {} while (0) +#define rtc_disable_abb_32k() do {} while (0) +#define rtc_enable_writeif() do {} while (0) +#define rtc_disable_writeif() do {} while (0) +#define rtc_mark_recovery() do {} while (0) +#if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING) +#define rtc_mark_kpoc() do {} while (0) +#endif/*if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING)*/ +#define rtc_mark_fast() do {} while (0) +#define rtc_rdwr_uart_bits(val) ({ 0; }) +#define rtc_bbpu_power_down() do {} while (0) +#define rtc_read_pwron_alarm(alm) do {} while (0) +#define get_rtc_spare_fg_value() ({ 0; }) +#define set_rtc_spare_fg_value(val) ({ 0; }) +#define rtc_irq_handler() do {} while (0) +#define crystal_exist_status() do {} while (0) +__weak void mt_power_off(void); +#endif/*ifdef CONFIG_MTK_RTC*/ +#endif + diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_systimer.h b/drivers/misc/mediatek/include/mt-plat/mtk_systimer.h new file mode 100644 index 00000000000000..34b0528df5506a --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_systimer.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015-2017 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MTK_SYSTIMER_H_ +#define _MTK_SYSTIMER_H_ + +/** + * request_systimer - request one systimer + * @timer_id: output value, timer_id must be globally unique; + * a pointer to a integer where the timer id is to be stored. + * @func: timer interrupt handler which is defined by user + * @data: input parameter for interrupt func + * + * Used to request one systimer for timer interrupt defined by user. + */ +extern int request_systimer(unsigned int *timer_id, + void (*func)(unsigned long), + unsigned long data); + +/** + * free_systimer - release a systimer + * @timer_id: systimer id to free + * + * Used to free one systimer device allocated with request_systimer(). + */ +extern int free_systimer(unsigned int timer_id); + +/** + * systimer_start - start a systimer + * @timer_id: systimer id to use + * @usec: time interval in unit of microseconds + * + * Used to start a systimer with XXX us expired. + * This function may be called from interrupt context. + */ +extern int systimer_start(unsigned int timer_id, unsigned int usec); + +/** + * systimer_stop - stop a systimer + * @timer_id: systimer id to stop + * + * Used to stop a systimer started with systimer_start(). + * This function may be called from interrupt context. + */ +extern int systimer_stop(unsigned int timer_id); + +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h new file mode 100644 index 00000000000000..eac6bc713c985a --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_ext_control.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009 Travis Geiselbrecht + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _MTK_THERMAL_EXT_CONTROL_H +#define _MTK_THERMAL_EXT_CONTROL_H + +#define THERMAL_MD32_IPI_MSG_BASE 0x1F00 +#define THERMAL_AP_IPI_MSG_BASE 0x2F00 + +typedef enum { + THERMAL_AP_IPI_MSG_SET_TZ_THRESHOLD = THERMAL_AP_IPI_MSG_BASE, + THERMAL_AP_IPI_MSG_MD32_START, + + THERMAL_MD32_IPI_MSG_READY = THERMAL_MD32_IPI_MSG_BASE, + THERMAL_MD32_IPI_MSG_MD32_START_ACK, + THERMAL_MD32_IPI_MSG_REACH_THRESHOLD, +} thermal_ipi_msg_id; + +typedef enum { +/* MTK_THERMAL_EXT_SENSOR_CPU = 0, */ + MTK_THERMAL_EXT_SENSOR_ABB = 0, + MTK_THERMAL_EXT_SENSOR_PMIC, + MTK_THERMAL_EXT_SENSOR_BATTERY, + MTK_THERMAL_EXT_SENSOR_COUNT +} MTK_THERMAL_EXT_SENSOR_ID; + +typedef struct { + int id; /* id of this tz */ + int polling_delay; /* polling delay of this tz */ + long high_trip_point; /* high threshold of this tz */ + long low_trip_point; /* low threshold of this tz */ +} thermal_zone_data; + +typedef struct { + int id; /* id of this tz */ + long high_trip_point; /* high threshold of this tz */ + long low_trip_point; /* low threshold of this tz */ + long temperature; /* Current temperature gotten from TS */ +} thermal_zone_status; + +typedef struct { + short id; + union { + thermal_zone_data tz; + thermal_zone_status tz_status; + } data; +} thermal_ipi_msg; + +#endif /* _MTK_THERMAL_EXT_CONTROL_H */ diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h new file mode 100644 index 00000000000000..7903b49dc419c5 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_monitor.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MTK_THERMAL_MONITOR_H +#define _MTK_THERMAL_MONITOR_H + +#include <linux/thermal.h> + +/* + * MTK_THERMAL_WRAPPER_BYPASS = 1 (use original Linux Thermal API) + * MTK_THERMAL_WRAPPER_BYPASS = 0 (use MTK Thermal API Monitor) + */ +#define MTK_THERMAL_WRAPPER_BYPASS 0 + +#if MTK_THERMAL_WRAPPER_BYPASS +/* Original LTF API */ +#define mtk_thermal_zone_device_register thermal_zone_device_register +#define mtk_thermal_zone_device_unregister thermal_zone_device_unregister +#define mtk_thermal_cooling_device_unregister thermal_cooling_device_unregister +#define mtk_thermal_cooling_device_register thermal_cooling_device_register +#define mtk_thermal_zone_bind_cooling_device thermal_zone_bind_cooling_device + +#else + +struct thermal_cooling_device_ops_extra { + int (*set_cur_temp)(struct thermal_cooling_device *, unsigned long); +}; + +extern +struct thermal_zone_device *mtk_thermal_zone_device_register_wrapper +(char *type, int trips, void *devdata, const struct thermal_zone_device_ops *ops, +int tc1, int tc2, int passive_delay, int polling_delay); + +extern +void mtk_thermal_zone_device_unregister_wrapper(struct thermal_zone_device *tz); + +extern +struct thermal_cooling_device *mtk_thermal_cooling_device_register_wrapper +(char *type, void *devdata, const struct thermal_cooling_device_ops *ops); + +extern +struct thermal_cooling_device *mtk_thermal_cooling_device_register_wrapper_extra +(char *type, void *devdata, const struct thermal_cooling_device_ops *ops, +const struct thermal_cooling_device_ops_extra *ops_ext); + +extern +int mtk_thermal_cooling_device_add_exit_point +(struct thermal_cooling_device *cdev, int exit_point); + +extern +void mtk_thermal_cooling_device_unregister_wrapper(struct thermal_cooling_device *cdev); + +extern int mtk_thermal_zone_bind_cooling_device_wrapper +(struct thermal_zone_device *tz, int trip, struct thermal_cooling_device *cdev); + +extern int mtk_thermal_zone_bind_trigger_trip(struct thermal_zone_device *tz, int trip, int mode); +#define mtk_thermal_zone_device_register mtk_thermal_zone_device_register_wrapper +#define mtk_thermal_zone_device_unregister mtk_thermal_zone_device_unregister_wrapper +#define mtk_thermal_cooling_device_unregister mtk_thermal_cooling_device_unregister_wrapper +#define mtk_thermal_cooling_device_register mtk_thermal_cooling_device_register_wrapper +#define mtk_thermal_zone_bind_cooling_device mtk_thermal_zone_bind_cooling_device_wrapper + +#endif + +typedef enum { + MTK_THERMAL_SENSOR_CPU = 0, + MTK_THERMAL_SENSOR_ABB, + MTK_THERMAL_SENSOR_PMIC, + MTK_THERMAL_SENSOR_BATTERY, + MTK_THERMAL_SENSOR_MD1, + MTK_THERMAL_SENSOR_MD2, + MTK_THERMAL_SENSOR_WIFI, + MTK_THERMAL_SENSOR_BATTERY2, + MTK_THERMAL_SENSOR_BUCK, + MTK_THERMAL_SENSOR_AP, + MTK_THERMAL_SENSOR_PCB1, + MTK_THERMAL_SENSOR_PCB2, + MTK_THERMAL_SENSOR_SKIN, + MTK_THERMAL_SENSOR_XTAL, + MTK_THERMAL_SENSOR_MD_PA, + + MTK_THERMAL_SENSOR_COUNT +} MTK_THERMAL_SENSOR_ID; + +extern int mtk_thermal_get_temp(MTK_THERMAL_SENSOR_ID id); +extern struct proc_dir_entry *mtk_thermal_get_proc_drv_therm_dir_entry(void); + +/* This API function is implemented in mediatek/kernel/drivers/leds/leds.c */ +extern int setMaxbrightness(int max_level, int enable); + +extern void machine_power_off(void); +#endif diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h new file mode 100644 index 00000000000000..305574031196a2 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_platform.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MTK_THERMAL_PLATFORM_H +#define _MTK_THERMAL_PLATFORM_H + +#include <linux/thermal.h> +#include <mtk_thermal_typedefs.h> + +extern +int mtk_thermal_get_cpu_info(int *nocores, int **cpufreq, int **cpuloading); + +extern +int mtk_thermal_get_gpu_info(int *nocores, int **gpufreq, int **gpuloading); + +extern +int mtk_thermal_get_batt_info(int *batt_voltage, int *batt_current, int *batt_temp); + +extern +int mtk_thermal_get_extra_info(int *no_extra_attr, + char ***attr_names, int **attr_values, char ***attr_unit); + +extern +int mtk_thermal_force_get_batt_temp(void); + + +enum { + MTK_THERMAL_SCEN_CALL = 0x1 +}; + +extern +unsigned int mtk_thermal_set_user_scenarios(unsigned int mask); + +extern +unsigned int mtk_thermal_clear_user_scenarios(unsigned int mask); + + +#if defined(CONFIG_MTK_SMART_BATTERY) +/* global variable from battery driver... */ +extern kal_bool gFG_Is_Charging; +#endif + +extern int force_get_tbat(void); +#endif /* _MTK_THERMAL_PLATFORM_H */ + + +typedef enum { + TA_DAEMON_CMD_GET_INIT_FLAG = 0, + TA_DAEMON_CMD_SET_DAEMON_PID, + TA_DAEMON_CMD_NOTIFY_DAEMON, + TA_DAEMON_CMD_NOTIFY_DAEMON_CATMINIT, + TA_DAEMON_CMD_SET_TTJ, + TA_DAEMON_CMD_GET_TPCB, + + TA_DAEMON_CMD_TO_KERNEL_NUMBER +} TA_DAEMON_CTRL_CMD_TO_KERNEL; /*must sync userspace/kernel: TA_DAEMON_CTRL_CMD_FROM_USER*/ + +#define TAD_NL_MSG_T_HDR_LEN 12 +#define TAD_NL_MSG_MAX_LEN 2048 + +struct tad_nl_msg_t { + unsigned int tad_cmd; + unsigned int tad_data_len; + unsigned int tad_ret_data_len; + char tad_data[TAD_NL_MSG_MAX_LEN]; +}; + +enum { + TA_CATMPLUS = 1, + TA_CONTINUOUS = 2, + TA_CATMPLUS_TTJ = 3 +}; + + +struct cATM_params_t { + int CATM_ON; + int K_TT; + int K_SUM_TT_LOW; + int K_SUM_TT_HIGH; + int MIN_SUM_TT; + int MAX_SUM_TT; + int MIN_TTJ; + int CATMP_STEADY_TTJ_DELTA; +}; +struct continuetm_params_t { + int STEADY_TARGET_TJ; + int MAX_TARGET_TJ; + int TRIP_TPCB; + int STEADY_TARGET_TPCB; +}; + + +struct CATM_T { + struct cATM_params_t t_catm_par; + struct continuetm_params_t t_continuetm_par; +}; +extern struct CATM_T thermal_atm_t; +int wakeup_ta_algo(int flow_state); +int ta_get_ttj(void); + +extern int mtk_thermal_get_tpcb_target(void); +extern int tsatm_thermal_get_catm_type(void); + + diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h new file mode 100644 index 00000000000000..1c23a9f4a862e5 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_trace.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM thermal + +#if !defined(_MTK_THERMAL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _MTK_THERMAL_TRACE_H + +#include <linux/tracepoint.h> + +TRACE_EVENT(cooling_device_state, + TP_PROTO(int device, unsigned long state), + TP_ARGS(device, state), TP_STRUCT__entry(__field(int, device) + __field(unsigned long, state) + ), + TP_fast_assign(__entry->device = device; + __entry->state = state;), + TP_printk("cooling_device=%d, state=%lu\n", __entry->device, __entry->state) +); + +TRACE_EVENT(thermal_zone_state, + TP_PROTO(int device, int state), + TP_ARGS(device, state), TP_STRUCT__entry(__field(int, device) + __field(int, state) + ), + TP_fast_assign(__entry->device = device; + __entry->state = state;), + TP_printk("thermal_zone=%d, state=%d\n", __entry->device, __entry->state) +); +#endif /* _MTK_THERMAL_TRACE_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE mach/mtk_thermal_trace +#include <trace/define_trace.h> diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h new file mode 100644 index 00000000000000..dfcef3d952fc7f --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_thermal_typedefs.h @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _TYPEDEFS_H +#define _TYPEDEFS_H + +#include <linux/bug.h> + +/* --------------------------------------------------------------------------- */ +/* Basic Type Definitions */ +/* --------------------------------------------------------------------------- */ + +typedef volatile unsigned char *P_kal_uint8; +typedef volatile unsigned short *P_kal_uint16; +typedef volatile unsigned int *P_kal_uint32; + +typedef long LONG; +typedef unsigned char UBYTE; +typedef short SHORT; + +typedef signed char kal_int8; +typedef signed short kal_int16; +typedef signed int kal_int32; +typedef long long kal_int64; +typedef unsigned char kal_uint8; +typedef unsigned short kal_uint16; +typedef unsigned int kal_uint32; +typedef unsigned long long kal_uint64; +typedef char kal_char; + +typedef unsigned int *UINT32P; +typedef volatile unsigned short *UINT16P; +typedef volatile unsigned char *UINT8P; +typedef unsigned char *U8P; + +typedef volatile unsigned char *P_U8; +typedef volatile signed char *P_S8; +typedef volatile unsigned short *P_U16; +typedef volatile signed short *P_S16; +typedef volatile unsigned int *P_U32; +typedef volatile signed int *P_S32; +typedef unsigned long long *P_U64; +typedef signed long long *P_S64; + +typedef unsigned char U8; +typedef signed char S8; +typedef unsigned short U16; +typedef signed short S16; +typedef unsigned int U32; +typedef signed int S32; +typedef unsigned long long U64; +typedef signed long long S64; +/* typedef unsigned char bool; */ + +typedef unsigned char UINT8; +typedef unsigned short UINT16; +typedef unsigned int UINT32; +typedef unsigned short USHORT; +typedef signed char INT8; +typedef signed short INT16; +typedef signed int INT32; +typedef unsigned int DWORD; +typedef void VOID; +typedef unsigned char BYTE; +typedef float FLOAT; + +typedef char *LPCSTR; +typedef short *LPWSTR; + + +/* --------------------------------------------------------------------------- */ +/* Constants */ +/* --------------------------------------------------------------------------- */ + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + +#ifndef NULL +#define NULL (0) +#endif + +/* enum boolean {false, true}; */ +enum { RX, TX, NONE }; + +#ifndef BOOL +typedef unsigned char BOOL; +#endif + +#ifndef BATTERY_BOOL +#define BATTERY_BOOL +typedef enum { + KAL_FALSE = 0, + KAL_TRUE = 1, +} kal_bool; +#endif + +/* --------------------------------------------------------------------------- */ +/* Type Casting */ +/* --------------------------------------------------------------------------- */ + +#define AS_INT32(x) (*(INT32 *)((void *)x)) +#define AS_INT16(x) (*(INT16 *)((void *)x)) +#define AS_INT8(x) (*(INT8 *)((void *)x)) + +#define AS_UINT32(x) (*(UINT32 *)((void *)x)) +#define AS_UINT16(x) (*(UINT16 *)((void *)x)) +#define AS_UINT8(x) (*(UINT8 *)((void *)x)) + + +/* --------------------------------------------------------------------------- */ +/* Register Manipulations */ +/* --------------------------------------------------------------------------- */ + +#define READ_REGISTER_UINT32(reg) \ + (*(volatile UINT32 * const)(reg)) + +#define WRITE_REGISTER_UINT32(reg, val) \ + ((*(volatile UINT32 * const)(reg)) = (val)) + +#define READ_REGISTER_UINT16(reg) \ + ((*(volatile UINT16 * const)(reg))) + +#define WRITE_REGISTER_UINT16(reg, val) \ + ((*(volatile UINT16 * const)(reg)) = (val)) + +#define READ_REGISTER_UINT8(reg) \ + ((*(volatile UINT8 * const)(reg))) + +#define WRITE_REGISTER_UINT8(reg, val) \ + ((*(volatile UINT8 * const)(reg)) = (val)) + +#define INREG8(x) READ_REGISTER_UINT8((UINT8 *)((void *)(x))) +#define OUTREG8(x, y) WRITE_REGISTER_UINT8((UINT8 *)((void *)(x)), (UINT8)(y)) +#define SETREG8(x, y) OUTREG8(x, INREG8(x)|(y)) +#define CLRREG8(x, y) OUTREG8(x, INREG8(x)&~(y)) +#define MASKREG8(x, y, z) OUTREG8(x, (INREG8(x)&~(y))|(z)) + +#define INREG16(x) READ_REGISTER_UINT16((UINT16 *)((void *)(x))) +#define OUTREG16(x, y) WRITE_REGISTER_UINT16((UINT16 *)((void *)(x)), (UINT16)(y)) +#define SETREG16(x, y) OUTREG16(x, INREG16(x)|(y)) +#define CLRREG16(x, y) OUTREG16(x, INREG16(x)&~(y)) +#define MASKREG16(x, y, z) OUTREG16(x, (INREG16(x)&~(y))|(z)) + +#define INREG32(x) READ_REGISTER_UINT32((UINT32 *)((void *)(x))) +#define OUTREG32(x, y) WRITE_REGISTER_UINT32((UINT32 *)((void *)(x)), (UINT32)(y)) +#define SETREG32(x, y) OUTREG32(x, INREG32(x)|(y)) +#define CLRREG32(x, y) OUTREG32(x, INREG32(x)&~(y)) +#define MASKREG32(x, y, z) OUTREG32(x, (INREG32(x)&~(y))|(z)) + + +#define DRV_Reg8(addr) INREG8(addr) +#define DRV_WriteReg8(addr, data) OUTREG8(addr, data) +#define DRV_SetReg8(addr, data) SETREG8(addr, data) +#define DRV_ClrReg8(addr, data) CLRREG8(addr, data) + +#define DRV_Reg16(addr) INREG16(addr) +#define DRV_WriteReg16(addr, data) OUTREG16(addr, data) +#define DRV_SetReg16(addr, data) SETREG16(addr, data) +#define DRV_ClrReg16(addr, data) CLRREG16(addr, data) + +#define DRV_Reg32(addr) INREG32(addr) +#define DRV_WriteReg32(addr, data) OUTREG32(addr, data) +#define DRV_SetReg32(addr, data) SETREG32(addr, data) +#define DRV_ClrReg32(addr, data) CLRREG32(addr, data) + +/* !!! DEPRECATED, WILL BE REMOVED LATER !!! */ +#define DRV_Reg(addr) DRV_Reg16(addr) +#define DRV_WriteReg(addr, data) DRV_WriteReg16(addr, data) +#define DRV_SetReg(addr, data) DRV_SetReg16(addr, data) +#define DRV_ClrReg(addr, data) DRV_ClrReg16(addr, data) + + +/* --------------------------------------------------------------------------- */ +/* Compiler Time Deduction Macros */ +/* --------------------------------------------------------------------------- */ + + + +/* --------------------------------------------------------------------------- */ +/* Assertions */ +/* --------------------------------------------------------------------------- */ + +/* +*#ifndef ASSERT +*#define ASSERT(expr) BUG_ON(!(expr)) +*#endif +* +*#ifndef NOT_IMPLEMENTED +*#define NOT_IMPLEMENTED() BUG_ON(1) +*#endif +*/ +#define STATIC_ASSERT(pred) STATIC_ASSERT_X(pred, __LINE__) +#define STATIC_ASSERT_X(pred, line) STATIC_ASSERT_XX(pred, line) +#define STATIC_ASSERT_XX(pred, line) \ +extern char assertion_failed_at_##line[(pred) ? 1 : -1] + +/* --------------------------------------------------------------------------- */ +/* Resolve Compiler Warnings */ +/* --------------------------------------------------------------------------- */ + +#define NOT_REFERENCED(x) { (x) = (x); } + + +/* --------------------------------------------------------------------------- */ +/* Utilities */ +/* --------------------------------------------------------------------------- */ + +#define MAXIMUM(A, B) (((A) > (B))?(A):(B)) +#define MINIMUM(A, B) (((A) < (B))?(A):(B)) + +#define ARY_SIZE(x) (sizeof((x)) / sizeof((x[0]))) +#define DVT_DELAYMACRO(u4Num) \ +{ \ + UINT32 u4Count = 0; \ + for (u4Count = 0; u4Count < u4Num; u4Count++) \ + ; \ +} \ + +#define A68351B 0 +#define B68351B 1 +#define B68351D 2 +#define B68351E 3 +#define UNKNOWN_IC_VERSION 0xFF + + +#endif /* _TYPEDEFS_H */ diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h b/drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h new file mode 100644 index 00000000000000..bfc9983a0cd42b --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/mtk_wcn_cmb_stub.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/*! \file + * \brief Declaration of library functions + * + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _MTK_WCN_CMB_STUB_H_ +#define _MTK_WCN_CMB_STUB_H_ + +#include <linux/pm.h> + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* Audio GPIO naming style for 73/75/77 */ +/* #define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_0 1 */ +/* Audio GPIO naming style for 89/8135 */ +/* #define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_1 1 */ +/* Audio GPIO naming style for 6592 */ +/* #define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_2 1 */ +/* Audio GPIO naming style for 6595 */ +#define MTK_WCN_CMB_AUD_IO_NAMING_STYLE_3 1 +#define MTK_WCN_CMB_FOR_SDIO_1V_AUTOK 1 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum { + CMB_STUB_AIF_0 = 0, /* 0000: BT_PCM_OFF & FM analog (line in/out) */ + CMB_STUB_AIF_1 = 1, /* 0001: BT_PCM_ON & FM analog (in/out) */ + CMB_STUB_AIF_2 = 2, /* 0010: BT_PCM_OFF & FM digital (I2S) */ + CMB_STUB_AIF_3 = 3, /* 0011: BT_PCM_ON & FM digital (I2S) (invalid in 73evb & 1.2 phone configuration) */ + CMB_STUB_AIF_4 = 4, /* 0100: BT_I2S & FM disable in special projects, e.g. protea*/ + CMB_STUB_AIF_MAX = 5, +} CMB_STUB_AIF_X; + +/*COMBO_CHIP_AUDIO_PIN_CTRL*/ +typedef enum { + CMB_STUB_AIF_CTRL_DIS = 0, + CMB_STUB_AIF_CTRL_EN = 1, + CMB_STUB_AIF_CTRL_MAX = 2, +} CMB_STUB_AIF_CTRL; + +typedef enum { + COMBO_FUNC_TYPE_BT = 0, + COMBO_FUNC_TYPE_FM = 1, + COMBO_FUNC_TYPE_GPS = 2, + COMBO_FUNC_TYPE_WIFI = 3, + COMBO_FUNC_TYPE_WMT = 4, + COMBO_FUNC_TYPE_STP = 5, + COMBO_FUNC_TYPE_NUM = 6 +} COMBO_FUNC_TYPE; + +typedef enum { + COMBO_IF_UART = 0, + COMBO_IF_MSDC = 1, + COMBO_IF_BTIF = 2, + COMBO_IF_MAX, +} COMBO_IF; + +typedef void (*wmt_bgf_eirq_cb) (void); +typedef int (*wmt_aif_ctrl_cb) (CMB_STUB_AIF_X, CMB_STUB_AIF_CTRL); +typedef void (*wmt_func_ctrl_cb) (unsigned int, unsigned int); +typedef signed long (*wmt_thermal_query_cb) (void); +typedef int (*wmt_deep_idle_ctrl_cb) (unsigned int); +typedef int (*wmt_func_do_reset) (unsigned int); + +/* for DVFS driver do 1v autok */ +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK +typedef unsigned int (*wmt_get_drv_status)(unsigned int); +#endif + +typedef void (*msdc_sdio_irq_handler_t) (void *); /* external irq handler */ +typedef void (*pm_callback_t) (pm_message_t state, void *data); + +struct sdio_ops { + void (*sdio_request_eirq)(msdc_sdio_irq_handler_t irq_handler, void *data); + void (*sdio_enable_eirq)(void); + void (*sdio_disable_eirq)(void); + void (*sdio_register_pm)(pm_callback_t pm_cb, void *data); +}; + +typedef struct _CMB_STUB_CB_ { + unsigned int size; /* structure size */ + /*wmt_bgf_eirq_cb bgf_eirq_cb; *//* remove bgf_eirq_cb from stub. handle it in platform */ + wmt_aif_ctrl_cb aif_ctrl_cb; + wmt_func_ctrl_cb func_ctrl_cb; + wmt_thermal_query_cb thermal_query_cb; + wmt_deep_idle_ctrl_cb deep_idle_ctrl_cb; + wmt_func_do_reset wmt_do_reset_cb; +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK + wmt_get_drv_status get_drv_status_cb; +#endif +} CMB_STUB_CB, *P_CMB_STUB_CB; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern struct sdio_ops mt_sdio_ops[4]; + +extern int mtk_wcn_cmb_stub_reg(P_CMB_STUB_CB p_stub_cb); +extern int mtk_wcn_cmb_stub_unreg(void); + +extern int mtk_wcn_cmb_stub_aif_ctrl(CMB_STUB_AIF_X state, CMB_STUB_AIF_CTRL ctrl); + +static inline int mtk_wcn_cmb_stub_audio_ctrl(CMB_STUB_AIF_X state) +{ +/* return mtk_wcn_cmb_stub_aif_ctrl(state, 1); */ + return 0; +} + +extern int mt_combo_plt_enter_deep_idle(COMBO_IF src); +extern int mt_combo_plt_exit_deep_idle(COMBO_IF src); + +/* Use new mtk_wcn_stub APIs instead of old mt_combo ones for kernel to control + * function on/off. + */ +extern void mtk_wcn_cmb_stub_func_ctrl(unsigned int type, unsigned int on); +extern int mtk_wcn_cmb_stub_query_ctrl(void); +extern void mtk_wcn_cmb_stub_clock_fail_dump(void); +extern int board_sdio_ctrl(unsigned int sdio_port_num, unsigned int on); +extern int mtk_wcn_sdio_irq_flag_set(int falg); + +#if MTK_WCN_CMB_FOR_SDIO_1V_AUTOK +extern int mtk_wcn_cmb_stub_1vautok_for_dvfs(void); +#endif + +extern int mtk_wcn_wmt_chipid_query(void); +extern void mtk_wcn_wmt_set_chipid(int chipid); +extern int mtk_wcn_cmb_stub_do_reset(unsigned int type); + +/* mtk_uart_pdn_enable -- request uart port enter/exit deep idle mode, this API is defined in uart driver + * + * @ port - uart port name, Eg: "ttyMT0", "ttyMT1", "ttyMT2" + * @ enable - "1", enable deep idle; "0", disable deep idle + * + * Return 0 if success, else -1 + */ +extern unsigned int mtk_uart_pdn_enable(char *port, int enable); +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _MTK_WCN_CMB_STUB_H_ */ diff --git a/drivers/misc/mediatek/include/mt-plat/rt-regmap.h b/drivers/misc/mediatek/include/mt-plat/rt-regmap.h new file mode 100644 index 00000000000000..9a45e23005cad5 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/rt-regmap.h @@ -0,0 +1,291 @@ +/* drivers/misc/mediatek/include/mt-plat/rt-regmap.h + * Header of Richtek regmap with debugfs Driver + * + * Copyright (C) 2014 Richtek Technology Corp. + * Jeff Chang <jeff_chang@richtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef MISC_MEDIATEK_RT_REGMAP_H +#define MISC_MEDIATEK_RT_REGMAP_H + +#include <linux/debugfs.h> +#include <linux/i2c.h> + +/* #define RT_REGMAP_VERSION "1.1.11_G" */ + +enum rt_access_mode { + RT_1BYTE_MODE = 1, + RT_2BYTE_MODE = 2, + RT_4BYTE_MODE = 4, +}; + +/* start : the start address of group + * end : the end address of group + * mode : access mode (1,2,4 bytes) + */ +struct rt_access_group { + u32 start; + u32 end; + enum rt_access_mode mode; +}; + +/* rt_reg_type + * RT_NORMAL : Write data without mask + * Read from cache + * RT_WBITS : Write data with mask + * Read from cache + * RT_VOLATILE : Write data to chip directly + * Read data from chip + * RT_RESERVE : Reserve registers (Write/Read as RT_NORMAL) + */ + +#define RT_REG_TYPE_MASK (0x03) +#define RT_NORMAL (0x00) +#define RT_WBITS (0x01) +#define RT_VOLATILE (0x02) +#define RT_RESERVE (0x03) + +/* RT_WR_ONCE : write once will check write data and cache data, + * if write data = cache data, data will not be writen. + */ +#define RT_WR_ONCE (0x08) +#define RT_NORMAL_WR_ONCE (RT_NORMAL|RT_WR_ONCE) +#define RT_WBITS_WR_ONCE (RT_WBITS|RT_WR_ONCE) + +enum rt_data_format { + RT_LITTLE_ENDIAN, + RT_BIG_ENDIAN, +}; + +/* rt_regmap_mode + * 0 0 0 0 0 0 0 0 + * | | | | | | + * | | | |__| byte_mode + * | |__| || + * | || Cache_mode + * | Block_mode + * Debug_mode + */ + +#define RT_BYTE_MODE_MASK (0x01) +/* 1 byte for each register*/ +#define RT_SINGLE_BYTE (0 << 0) +/* multi bytes for each regiseter*/ +#define RT_MULTI_BYTE (1 << 0) + +#define RT_CACHE_MODE_MASK (0x06) +/* write to cache and chip synchronously */ +#define RT_CACHE_WR_THROUGH (0 << 1) +/* write to cache and chip asynchronously */ +#define RT_CACHE_WR_BACK (1 << 1) +/* disable cache */ +#define RT_CACHE_DISABLE (2 << 1) + +#define RT_IO_BLK_MODE_MASK (0x18) +/* pass through all write function */ +#define RT_IO_PASS_THROUGH (0 << 3) +/* block all write function */ +#define RT_IO_BLK_ALL (1 << 3) +/* block cache write function */ +#define RT_IO_BLK_CACHE (2 << 3) +/* block chip write function */ +#define RT_IO_BLK_CHIP (3 << 3) + +#define DBG_MODE_MASK (0x20) +/* create general debugfs for register map */ +#define RT_DBG_GENERAL (0 << 5) +/* create node for each regisetr map by register address*/ +#define RT_DBG_SPECIAL (1 << 5) + + +/* struct rt_register + * + * Ricktek register map structure for store mapping data + * @addr: register address. + * @name: register name. + * @size: register byte size. + * @reg_type: register R/W type ( RT_NORMAL, RT_WBITS, RT_VOLATILE, RT_RESERVE) + * @wbit_mask: register writeable bits mask; + * @cache_data: cache data for store cache value. + */ +struct rt_register { + u32 addr; + const char *name; + unsigned int size; + unsigned char reg_type; + unsigned char *wbit_mask; + unsigned char *cache_data; +}; + +/* Declare a rt_register by RT_REG_DECL + * @_addr: regisetr address. + * @_reg_length: register data length. + * @_reg_type: register type (rt_reg_type). + * @_mask: register writealbe mask. + */ +#define RT_REG_DECL(_addr, _reg_length, _reg_type, _mask_...) \ + static unsigned char rt_writable_mask_##_addr[_reg_length] = _mask_;\ + static struct rt_register rt_register_##_addr = { \ + .addr = _addr, \ + .size = _reg_length,\ + .reg_type = _reg_type,\ + .wbit_mask = rt_writable_mask_##_addr,\ + } + +/* Declare a rt_register by RT_NAMED_REG_DECL + * @_name: a name for a rt_register. + */ +#define RT_NAMED_REG_DECL(_addr, _name, _reg_length, _reg_type, _mask_...) \ + static unsigned char rt_writable_mask_##_addr[_reg_length] = _mask_;\ + static struct rt_register rt_register_##_addr = { \ + .addr = _addr, \ + .name = _name, \ + .size = _reg_length,\ + .reg_type = _reg_type,\ + .wbit_mask = rt_writable_mask_##_addr,\ + } + +#define RT_REG(_addr) (&rt_register_##_addr) + +/* rt_regmap_properties + * @name: the name of debug node. + * @aliases: alisis name of rt_regmap_device. + * @register_num: the number of rt_register_map registers. + * @rm: rt_regiseter_map pointer array. + * @group: register map access group. + * @rt_format: default is little endian. + * @rt_regmap_mode: rt_regmap_device mode. + * @io_log_en: enable/disable io log + */ +struct rt_regmap_properties { + const char *name; + const char *aliases; + int register_num; + struct rt_register **rm; + struct rt_access_group *group; + enum rt_data_format rt_format; + unsigned char rt_regmap_mode; + unsigned char io_log_en:1; +}; + +/* A passing struct for rt_regmap_reg_read and rt_regmap_reg_write function + * reg: regmap addr. + * mask: mask for update bits. + * rt_data: register value. + */ +struct rt_reg_data { + u32 reg; + u32 mask; + union { + u32 data_u32; + u16 data_u16; + u8 data_u8; + u8 data[4]; + } rt_data; +}; + +struct rt_regmap_device; + +struct rt_debug_st { + void *info; + int id; +}; + +/* basic chip read/write function */ +struct rt_regmap_fops { + int (*read_device)(void *client, u32 addr, int leng, void *dst); + int (*write_device)(void *client, u32 addr, int leng, const void *src); +}; + +/* with slave address */ +extern struct rt_regmap_device* + rt_regmap_device_register_ex(struct rt_regmap_properties *props, + struct rt_regmap_fops *rops, + struct device *parent, + void *client, int slv_addr, void *drvdata); + +static inline struct rt_regmap_device* + rt_regmap_device_register(struct rt_regmap_properties *props, + struct rt_regmap_fops *rops, + struct device *parent, + struct i2c_client *client, void *drvdata) +{ + return rt_regmap_device_register_ex(props, rops, parent, + client, client->addr, drvdata); +} + +extern void rt_regmap_device_unregister(struct rt_regmap_device *rd); + +extern int rt_regmap_cache_init(struct rt_regmap_device *rd); + +extern int rt_regmap_cache_reload(struct rt_regmap_device *rd); + +extern int rt_regmap_block_write(struct rt_regmap_device *rd, u32 reg, + int bytes, const void *rc); +extern int rt_asyn_regmap_block_write(struct rt_regmap_device *rd, u32 reg, + int bytes, const void *rc); +extern int rt_regmap_block_read(struct rt_regmap_device *rd, u32 reg, + int bytes, void *dst); + +extern int _rt_regmap_reg_read(struct rt_regmap_device *rd, + struct rt_reg_data *rrd); +extern int _rt_regmap_reg_write(struct rt_regmap_device *rd, + struct rt_reg_data *rrd); +extern int _rt_asyn_regmap_reg_write(struct rt_regmap_device *rd, + struct rt_reg_data *rrd); +extern int _rt_regmap_update_bits(struct rt_regmap_device *rd, + struct rt_reg_data *rrd); + +static inline int rt_regmap_reg_read(struct rt_regmap_device *rd, + struct rt_reg_data *rrd, u32 reg) +{ + rrd->reg = reg; + return _rt_regmap_reg_read(rd, rrd); +}; + +static inline int rt_regmap_reg_write(struct rt_regmap_device *rd, + struct rt_reg_data *rrd, u32 reg, const u32 data) +{ + rrd->reg = reg; + rrd->rt_data.data_u32 = data; + return _rt_regmap_reg_write(rd, rrd); +}; + +static inline int rt_asyn_regmap_reg_write(struct rt_regmap_device *rd, + struct rt_reg_data *rrd, u32 reg, const u32 data) +{ + rrd->reg = reg; + rrd->rt_data.data_u32 = data; + return _rt_asyn_regmap_reg_write(rd, rrd); +}; + +static inline int rt_regmap_update_bits(struct rt_regmap_device *rd, + struct rt_reg_data *rrd, u32 reg, u32 mask, u32 data) +{ + rrd->reg = reg; + rrd->mask = mask; + rrd->rt_data.data_u32 = data; + return _rt_regmap_update_bits(rd, rrd); +} + +extern void rt_regmap_cache_backup(struct rt_regmap_device *rd); + +extern void rt_regmap_cache_sync(struct rt_regmap_device *rd); +extern void rt_regmap_cache_write_back(struct rt_regmap_device *rd, u32 reg); + +extern int rt_is_reg_readable(struct rt_regmap_device *rd, u32 reg); +extern int rt_is_reg_volatile(struct rt_regmap_device *rd, u32 reg); +extern int rt_get_regsize(struct rt_regmap_device *rd, u32 reg); +extern void rt_cache_getlasterror(struct rt_regmap_device *rd, char *buf); +extern void rt_cache_clrlasterror(struct rt_regmap_device *rd); + +extern int rt_regmap_add_debugfs(struct rt_regmap_device *rd, const char *name, + umode_t mode, void *data, const struct file_operations *fops); + +#define to_rt_regmap_device(obj) container_of(obj, struct rt_regmap_device, dev) + +#endif /*MISC_MEDIATEK_RT_REGMAP_H*/ diff --git a/drivers/misc/mediatek/include/mt-plat/sync_write.h b/drivers/misc/mediatek/include/mt-plat/sync_write.h new file mode 100644 index 00000000000000..f9e5fe4c23e171 --- /dev/null +++ b/drivers/misc/mediatek/include/mt-plat/sync_write.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MT_SYNC_WRITE_H +#define _MT_SYNC_WRITE_H + +#if defined(__KERNEL__) + +#include <linux/io.h> +#include <asm/cacheflush.h> + +/* + * Define macros. + */ +#define mt_reg_sync_writel(v, a) \ + do { \ + __raw_writel((v), (void __force __iomem *)((a))); \ + mb(); \ + } while (0) + +#define mt_reg_sync_writew(v, a) \ + do { \ + __raw_writew((v), (void __force __iomem *)((a))); \ + mb(); \ + } while (0) + +#define mt_reg_sync_writeb(v, a) \ + do { \ + __raw_writeb((v), (void __force __iomem *)((a))); \ + mb(); \ + } while (0) + +#ifdef CONFIG_64BIT +#define mt_reg_sync_writeq(v, a) \ + do { \ + __raw_writeq((v), (void __force __iomem *)((a))); \ + mb(); \ + } while (0) +#endif + +#else /* __KERNEL__ */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> + +#define mt_reg_sync_writel(v, a) mt65xx_reg_sync_writel(v, a) +#define mt_reg_sync_writew(v, a) mt65xx_reg_sync_writew(v, a) +#define mt_reg_sync_writeb(v, a) mt65xx_reg_sync_writeb(v, a) + +#define mb() \ + { \ + __asm__ __volatile__ ("dsb" : : : "memory"); \ + } + +#define mt65xx_reg_sync_writel(v, a) \ + do { \ + *(volatile unsigned int *)(a) = (v); \ + mb(); \ + } while (0) + +#define mt65xx_reg_sync_writew(v, a) \ + do { \ + *(volatile unsigned short *)(a) = (v); \ + mb(); \ + } while (0) + +#define mt65xx_reg_sync_writeb(v, a) \ + do { \ + *(volatile unsigned char *)(a) = (v); \ + mb(); \ + } while (0) + +#endif /* __KERNEL__ */ + +#endif /* !_MT_SYNC_WRITE_H */ diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 4198f30aac3cab..937e3ed75f7753 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -234,6 +234,7 @@ unsigned long kallsyms_lookup_name(const char *name) return module_kallsyms_lookup_name(name); } +EXPORT_SYMBOL_GPL(kallsyms_lookup_name); /* * Iterate over all symbols in vmlinux. For symbols from modules use diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c index c326de1344fb72..19f7c9e87361f9 100644 --- a/kernel/sched/syscalls.c +++ b/kernel/sched/syscalls.c @@ -794,6 +794,7 @@ int sched_setscheduler(struct task_struct *p, int policy, { return _sched_setscheduler(p, policy, param, true); } +EXPORT_SYMBOL_GPL(sched_setscheduler); int sched_setattr(struct task_struct *p, const struct sched_attr *attr) {